nethack-3.6.0/DEVEL/DOTGIT/TARGET0000664000076400007660000000000512504242744014676 0ustar paxedpaxed.git nethack-3.6.0/DEVEL/Developer.txt0000664000076400007660000002031112620563146015464 0ustar paxedpaxed ___ _ | \ _____ _____| |___ _ __ ___ _ _ | |) / -_) V / -_) / _ \ '_ \/ -_) '_| |___/\___|\_/\___|_\___/ .__/\___|_| |_| $NHDT-Date: 1447180052 2015/11/10 18:27:32 $ Welcome to the NetHack Infrastructure Developer's Guide. This is the info you need if you are developing code for NetHack. (This information is from DevTeam. If you are working with a variant please check for additional documentation for that variant.) For information on building NetHack, see README in the top level directory. For information on playing NetHack, see the Guidebook in the doc directory. DANGER! WORK IN PROGRESS! Known issues marked XXX. CONTENTS 1. email 2. git repositories 3. bug reporting 4. git configuration 5. variable expansion 6. reserved names 7. nhadd/nhcommit ------------------------------------------------------------------------------ 1. email Email to devteam@nethack.org will usually get a response, but it may take a while. Please do not send save files, binary screen grabs, or other large things. ------------------------------------------------------------------------------ 2. git repositories The public NetHack git repository is available (read-only) on SourceForge at: git://git.code.sf.net/p/nethack/NHsource XXX need to discuss what branches are available ------------------------------------------------------------------------------ 3. bug reporting Please use the form at http://www.nethack.org/common/contact.html (or send us an email if that's more appropriate). ------------------------------------------------------------------------------ 4. git configuration NOTE: These instructions assume you are on the default branch ("master"); this _is_ where you want to be for setting things up. This may or may not be the branch you want to use for your changes; see the appropriate project private documentation for more information (if you are working alone we suggest using branch names starting with "LOCAL-"). A. If you have never set up git on this machine before: (This assumes you will only be using git for NetHack. If you are going to use it for other projects as well, think before you type.) Tell git what name (or nicname) and email address to use for you: git config --global user.name "MY NAME" git config --global user.email USER@EXAMPLE.COM You probably want to set up a credential cache. Mac OS X: git config --global credential.helper osxkeychain Windows: git config --global credential.helper store XXX linux B. Specify the prefix for variable substitution: (This assumes you are not a member of DevTeam or any variant's development team. If you are, this may be wrong. Look for more specific documentation. For example, this file uses "MINE" for the substitution prefix - this will almost always be wrong if you are working with someone else.) Decide where you want to put this info; it should NOT be inside the tree you cloned from git. I use ~/nethack/GITADDDIR; for that base, create the needed directories and edit the file: ~/nethack/GITADDDIR/DOTGIT/PRE Put this in it (if your OS is not Unix-like you may need to change the first line): #!/bin/sh git config nethack.substprefix MINE Now make it executable: chmod +x ~/nethack/GITADDDIR/DOTGIT/PRE C. Configure the repository: - cd to the top level of the repository - tell the repository about the directory you created above: git config nethack.gitadddir FULL_PATH_TO_GITADDDIR so for the example above: git config nethack.gitadddir ~/nethack/GITADDDIR - do the automated setup: perl DEVEL/nhgitset.pl If it complains, fix what it complains about. nhgitset.pl accepts the following options: -v verbose -n dry run You can re-run nhgitset.pl as often as needed; occasionally we will update it and ask you to run it again. D. aliases Two aliases are installed by nhgitset.pl: nhadd nhcommit These two commands take the same options as the normal git add and commit commands but perform RCS/CVS-style variable substitution. Note that nothing terrible will happen if you do not use the nh* versions of the commands. Supported substitutions: MINE-Date the commit time and date Experimental substitutions: MINE-Revision CVS style revision number MINE-Branch the current git branch For direct access to the substitution mechanism, use: nhsub See the section "nhadd/nhcommit" for details on those aliases. Run "perldoc DEVEL/hooksdir/nhsub" for details on nhsub. That's it. If you need to do something more when setting up your repository, keep reading. Otherwise, you are done with this section. 1) to run your own hooks in addition to ours: name your hook WHEN-HOOKNAME where WHEN is PRE (run your code before the NetHack hook) POST (run your code after the NetHack hook) and HOOKNAME is the normal git name of the hook. Make sure the hooks are executable (chmod +x ...). Be sure to test carefully since the composition of two bits of code may or may not do what you want. 2) to install other bits on setup: Put additional files in the GITADDDIR tree. Use "DOTGIT" instead of ".git". If a file called PRE, POST, or INSTEAD exists in a subdirectory of GITADDDIR, it is run before the copy, after the copy, or instead of the copy. No copy operation is attempted in the DOTGIT directory; use a script and standard git commands to change the contents as needed. 3) NB: In all namespaces, anything that matches m/^nh/i or m/^nethack/i is reserved. ------------------------------------------------------------------------------ 5. variable expansion A. Introduction We have implemented an RCS/CVS/SVN style variable expansion mechanism. References of either of the formats: $PREFIX-VARNAME$ $PREFIX-VARNAME: VALUE $ will be handled (if enabled). The PREFIX is the value in the git config variable nethack.substprefix. VARNAME is one of: Date Branch (experimental) Revision (experimental) other names will give a warning. B. Enabling variable expansion Variable expansion is controlled by the .gitattributes file. To enable variable expansion: pattern NHSUBST To disable variable expansion: pattern -NHSUBST More information: "git help gitattributes" C. Oddities To trigger variable expansion, you _must_ use "git nhadd" or "git nhcommit" instead of "git add" or "git commit." Nothing terrible will happen if you use the wrong one, but the values will not be updated. Variable expansion modifies the files in the work tree - your editor or IDE may or may not be happy with this. D. Using your own hooks You can use your own hooks - put them in .git/hooks as usual BUT name them as follows: WHEN-HOOKNAME where WHEN is: PRE (execute the code before the NetHack hook) POST (execute the code after the NetHack hook) and HOOKNAME is the normal git name for the hook. Test carefully - interactions between hooks can be nasty. ------------------------------------------------------------------------------ 6. reserved names Anything that matches m/^nh/i or m/^nethack/i is reserved in all namespaces (environment, file names, git config, etc). ------------------------------------------------------------------------------ 7. nhadd/nhcommit nhadd is essentially "git nhsub $*; git add $*" nhcommit is essentially "git nhsub $*; git commit $*" As "git add" and "git commit" have complex arguments, nhsub attempts to do the right thing - or at least something reasonable - for most arguments. If nhadd/nhcommit don't do what you need, run "git nhsub" on its own then add/commit. So when do I need to use what? The object is to get nhsub run right before git takes a snapshot of each file. So for example: - use "git nhcommit " instead of "git commit " - use "git nhadd " instead of "git add " - use either "git commit" or "git nhcommit" (because the snapshot was already taken) - if you use "git nhsub " then you can "git add " or "git commit " For more complex situations, "git nhsub" takes -v and -n flags - see "perldoc DEVEL/hooksdir/nhsub". ------------------------------------------------------------------------------ nethack-3.6.0/DEVEL/code_features.txt0000664000076400007660000001124212536476415016362 0ustar paxedpaxed$NHDT-Date: 1432473678 2015/05/24 13:21:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.2 $ code_features.txt Developer-useful info about code features, assumptions, purpose, rationale, etc. ============================================== FEATURE_NOTICE Alerts for a Release There is a code mechanism for alerting players to a change in behavior over prior versions of the game. Here's how to do it: o Where the change in behavior needs to alert the player, - Add an 'if statement' to invoke the alert behavior if the condition is met, for example if (flags.suppress_alert < FEATURE_NOTICE_VER(3.6.0)) pline("Note: and explain the change here."); - The example above will alert the users for a new feature added in 3.6.0 via a one-liner via pline(), but you could get more elaborate (just make sure it is all done in the 'if' code block.. Once the user finds the alert no longer useful, or becoming annoying, they can set the "suppress_alert" option. - The user can only set the suppress_alert to the current version, not future versions. That restriction is done so that the feature can be used for new things in new releases. - The suppression can be done interactively mid game with the 'O' command, or via OPTIONS=suppress_alert:3.6.0 in the user's config file. ============================================== PREFIXES_IN_USE and NOCWD_ASSUMPTIONS Those provide a storage mechanism for holding the paths to various different types of files. Those paths are stored in the fqn_prefix[] array. They are a mechanism for enabling separation of the different files that NetHack needs. The prefixes are added to the beginning of file names by various routines in files.c immediately prior to opening one of the types of files that the game uses. They aren't about config file options (although config file options would be one way to set non-default values for some of the paths in the fqn_prefix[] array). Obviously the very first path needed (now sysconfdir, previously configdir) isn't viable for setting via config file options, but the game still needs to hunt it down "someplace." When the "someplace" is figured out, that place (path) would be stored in fqn_prefix[SYSCONPREFIX]. How it gets stored in fqn_prefix[SYSCONPREFIX] is up to us as developers. Any of the fqn_prefix[] entries can be set somehow. It could be done in port startup code; in options processing; in config file processing; by translating a system environment variable such as USERPROFILE; whatever you/we want. The point is that NOCWD_ASSUMPTIONS and PREFIXES_IN_USE are there to ensure that there is a place to store that path information. The code to *utilize* the information is already in files.c (see fqname()). There is a fqn_prefix[] entry for holding the path to each of the following: PREFIX NAME 0 HACKPREFIX hackdir 1 LEVELPREFIX leveldir location to create level files 2 SAVEPREFIX savedir location to create/read saved games 3 BONESPREFIX bonesir location to create/read bones 4 DATAPREFIX datadir location to read data.base etc. 5 SCOREPREFIX scoredir location to read/write scorefile 6 LOCKPREFIX lockdir location to create/read lock files 7 SYSCONFPREFIX sysconfdir location to read SYSCF_FILE 8 CONFIGPREFIX configdir location to read user configuration file 9 TROUBLEPREFIX troubledir location to place panic files etc. To recap, they are about enabling "different paths for different things", and separation of: - read-only stuff from read-write stuff. - sysadmin stuff from user-writeable stuff. etc. ============================================== REGULAR EXPRESSIONS There are multiple regular expression libraries supported. Currently, one (and only one) of the following files should be linked into a built: sys/share/cppregex.cpp sys/share/posixregex.c sys/share/pmatchregex.c This provides a way to access different system regular expression libraries, or fall back onto pmatch() if none is available. cppregex.cpp uses the regular expression library in the C++11 standard, and is the default on Windows. posixregex.c uses the POSIX regular expression library, and is the default on POSIX. pmatchregex.c is the fallback. Configuration files written using either of the two true regex engines are compatible with one another, as the regular expressions are both POSIX extended regular expressions. Configuration files written using the fallback engine are incompatible. Additional regular expression implementations can be written. The full interface documentation is in sys/share/posixregex.c =================== NEXT FEATURE ========================== nethack-3.6.0/DEVEL/code_style.txt0000664000076400007660000001305312536476415015706 0ustar paxedpaxedNetHack DevTeam Coding Style ============================ NetHack is written in C, with a little bit of C++ to access platform libraries. This coding style document is concerned primarily with the style used for C source files. We do not have a defined style for C++ files, but C++ should be styled in keeping with C. The code base in C files was, close to the 3.6 release, reformatted using a version of the clang-format tool patched to support K&R-style argument declarations. Due to some incompatibilities, the patch is not publicly available and clang-format is not expected to be regularly used. Developers should do their best to adhere to the coding style to promote legibile, easy-to-edit code. Legibility is paramount, so in some cases, it may be better not to fully adhere to the style guidelines. Recipes for common text editors can be found at the end of this file. Indentation and Spacing ----------------------- The basic indentation is 4 spaces wide. All indentation is done using space characters, not tabs. Lines should be at most 78 characters wide. If a line would be longer than the limit, the line should be wrapped and the wrapped portion should be aligned with the parentheses or brackets containing the wrap. If there is no set of parenthese or brackets, the line should be indented four spaces. Wrapping should normally occur after a comma or before a binary operator, when possible: int index = SomeExcessivelyLongExpression; fcall(arg1, arg2, (cond13 && cond2)); Single blank lines should be used wherever convenient to improve readability. Functions and Control Satements ------------------------------- For a function definition, the return type, declarator, and opening brace should each appear on a line of their own. Arguments are never declared in the function declarator, but are declared, unintended, K&R-style before the opening brace: void foo(i, c) int i; char c; { /* function body */ } Opening braces of control statements appear on the same line as the control statement: if (condition) { /* body */ } Else statements and the while statements of do-while blocks appear on the same line as the closing brace of the if or do statement. Otherwise, closing braces always get a line of their own. if (condition) { /* body */ } else if (condition) { do { /* body */ } while (condition); } else { /* body */ } If a control block has only a single statement, it can appear on a line of its own, with an indent. If the statement is a null statement, then it should be expressed as an empty set block, not with a semicolon, because many compilers will warn if a null statement is used: if (condition) fcall(); if (condition) { } else fcall(); If multiple control blocks are being used in a row, it may be more readable to use braces even for single statements, and they should be used if they improve readability. The following is an example of poor usage: if (condition) { /* long body */ } else if (condition) statement; else { /* very long body */ } Switch statements should have the case labels unindented, and the statements should be indented normally. The default case should occur last unless there's a compelling reason not to, and fallthroughs should be explicitly marked as such with a comment, to avoid Yeenoghu getting the touch of death again: switch (condition) { case FOO: case BAR: fcall(); /* fall-through */ case BAZ: fcall(); break; default: statement; } Variables should never be declared in a condition or a for loop initialization, and if an assignment is used as a condition, it should be wrapped in an additional set of parentheses for clarity: int *p; if ((p = fcall())) { /* body */ } int i; for (i = 1; i < 10; ++i) { /* body */ } Spaces in Expressions --------------------- Spaces should appear around binary operators, after commas, after a C-style cast, and after the keyword in a control statement. They should not appear between a function name and the opening parenthesis of a function call, nor immediately inside a pair of parentheses: foo(i, j, l); if ((boolean) condition) { /* body */ } Vim Configuration ================= For vim, the following settings are encouraged when editing NetHack code, to ensure that indentation is done correctly: set shiftwidth=4 set softtabstop=4 set expandtab set tabstop=4 set shiftround set textwidth=78 set cindent set filetype=c Visual Studio Configuration =========================== In Visual Studio under Tools->Options->Text Editor->C/C++, you can set the following options to obtain desired behavior: [Tabs] Indenting: Smart Tab size: 4 Indent size: 4 Insert Spaces There are a number of other options under [Formatting] that should be checked (Indentation, New Lines, Spacing, and Wrapping), but there are so many entries that reproducing them here is impractical. Fortunately, the options are in plain English, so walking through them with a copy of this Guide handy and making changes as required will suffice. emacs Configuration =================== There are no doubt umpteen different ways to handle this in emacs. Putting the following in ~/.emacs.el is one (defun hook-c () (setq c-set-style "k&r") (setq c-basic-offset 4) (setq indent-tabs-mode nil) (c-set-offset 'knr-argdecl-intro 0)) (add-hook 'c-mode-common-hook 'hook-c) nethack-3.6.0/DEVEL/git_recipes.txt0000664000076400007660000001533312536476415016054 0ustar paxedpaxedGit has a messy learning curve. This file is an attempt to serve as a quick reference for basic tasks while you get up to speed. $NHDT-Date: 1429884051 2015/04/24 14:00:51 $ ------------------------ [*] git checkout [-f] (branch) Switch your local repository to be at the most recent commit of (branch). Including -f will discard changes made in the working directory. [*] git status [-uall | -uno] Shows all changed files in your local repository and also a list of the ones you have staged for commit. Including -uall will also show you all untracked files in all subdirectories. Including -uno will show you _no_ untracked files. [*] git log [-NUM] [*] git log [*] git log [--pretty=one] [*] git log (branch) For a full explanation of all the arguments you can pass to 'log', please see the manual; there are a lot and these are just a few of the common ones. For our purposes, git log will show you all the commits according to criteria you specify: -NUM: The last NUM commits in this branch : all commits between commit1 and commit2 -pretty=one: format output as a single line for each entry (branch): show the commits from (branch) instead of the current one [*] git log --pretty=one --decorate --graph --all (This is best explained by executing and looking at the output.) [*] git add (filename) [*] git nhadd (filename) Adds the changes you've made in (filename) to the pre-commit staging area. (also referred to as the 'index') OR Make a new file be tracked by git. "nhadd" is the preferred syntax and will automatically update the source file headers with the latest date, branch, and version. See Developer.txt for details. [*] git commit [-a] [-m "text"] [*] git nhcommit [-a] [-m "text"] Commits all staged changes (in the index) to this branch in your local repo from your current position. Including -a will 'git add' all eligible files before doing so. Including -m will use "text" as the commit message instead of opening an editor window for you to create one. "nhcommit" is the preferred syntax and will automatically update the source file headers with the latest date, branch, and version. See Developer.txt for details. [*] git push [--all] [-u origin (branch)] Sends all your commits for the current branch to the centralized repo. Including --all will send the commits for _all_ branches. Specifying -u is only needed the first time you push (branch) that you created; it establishes the connection between local and remote for that branch. [*] git reset [--hard] (filename) Without any parameters, unstages the changes for (filename) from the index; does not change the working tree. This is the equivalent of the command git reset --mixed (filename); git reset --soft (filename) has no effect. With --hard, unstages (filename) from the index and reverts (filename) in the working tree to the most recent commit. *** WARNING *** --hard _will_ throw away your changes. [DSR: I'm hesitant about including this command because you can trash stuff with it. But at the same time, for people who are adapting to a commit not also automatically being a send, it's nice for them to know how to undo one in case they do something wrong. thoughts?] [*] git reset [--soft | --mixed | --hard] HEAD~1 *** WARNING *** Never, EVER do this to a commit that you have already pushed; you will be rewriting history on other people's machines and this will generally turn out very poorly. With --soft, undoes the most recent 'git commit' action, but leaves the changes in the index and in the working directory. With --mixed, does everything --soft does but also unstages the changes from the index. If you don't specify one of the three, reset will assume this. With --hard, does everything --mixed does but also reverts the working tree to the prior commit. *** WARNING *** --hard will effectively delete a commit and "lose" the changes. [/end area-of-concern] [*] git fetch [--all] Retrieve commits from the remote repository to your machine. Including --all will get commits for all branches. Does NOT merge them into your local repository. [*] git pull Incorporate any fetched commits for the current branch into your repository and update your position accordingly. This will create a merge commit (noting that you merged a branch into itself). [*] git rebase [no-arguments version ONLY] Incorporate fetched commits for the current branch into your repository, and replay any local commits and changes afterwards on top. Quality picture-pages ASCII art: E---F---G---H (remote changes) / / (branch 'frog') A---B---C---D---E'---F' (your local changes) After 'git fetch' and 'git rebase', it will look like this: --- (remote HEAD) | V (branch 'frog') A---B---C---D---E---F---G---H---E'---F' ^ ^ | | -------- (to be pushed) [*] git branch (branch) Creates a new branch from the current commit you're pointed to. Does not automatically checkout (switch to) the branch. [*] git checkout -b (branch) Creates a new branch from the current commit you're pointed to, and automatically checks out that branch. [*] git branch --list | [--all | -a] | [--remotes | -r] Lists all branches matching . With --all instead, lists all branches (including remotely tracked ones). With --remotes instead, lists only remote branches. [*] git merge (branch) [--no-commit] Merges all the changes from (branch) since it last diverged from a common ancestor into your current branch. With --no-commit, does not automatically create a merge entry in the log but leaves all the merged files in your working directory; to complete the merge you must commit them manually later (likely after you have edited them). This more accurately mimics the merge behavior of svn [and cvs?] [*] git stash [save | apply | list] save: Takes all changes in your working directory and 'stashes' them in a temporary holding area. Convenient if the command you're trying to run won't go unless you have a clean working dir; also convenient to move experimental changes between branches without needing to commit them. apply: Replays the named stash onto your current working directory as though it were a patch. Does not delete the stash from the list. list: Lists all of your stashed code blobs. ======================================= Typical workflows for common activities ======================================= {To be added in near future: DSR 3/15} nethack-3.6.0/DEVEL/hooksdir/.NHgithook.pm.swp0000664000076400007660000004000012504242744017732 0ustar paxedpaxedb0VIM 7.3yzT#]K'kenipolyhymnia.home~keni/nethack/git/test4/NHtest/GIT/hooksdir/NHgithook.pmutf-8 3210#"! Utp$adsreL64uYVU+)( v X B    z h f e Z G E D : ,  n V ) (  u P 7 . v S P N M E 1   pY6%jS&rb+ {U@310&wVF(NM $gitdir =~ s/[\r\n]*$/; $gitdir = `git rev-parse --git-dir`; # and when the above really doesn't work push(@INC, ($0 =~ m!^(.*)$DS!)[0]); # when the above doesn't work push(@INC, $ENV{GIT_DIR}.$PDS."hooks"); # for most hooks } $PDS = '\\'; $DS = quotemeta('\\'); { if ($^O eq "MSWin32") my $PDS = '/'; my $DS = quotemeta('/'); BEGIN {=head1 SYNOPSISNHgithook - common code for NetHack git hooks (and other git bits)=head1 NAME__END__1;} return $self->{EOF}; $self = shift;sub EOF {} } } return undef; $self->{EOF} = 1; } else { return $rv; $self->{NEXT}++; if(length $rv){ my $rv = $self->{DATA}[$self->{NEXT}]; } else{ return @rv; $self->{EOF} = 1; my @rv = @ary[$self->{NEXT}..$#ary]; my @ary = @{$self->{DATA}}[$self->{NEXT}..$lim]; my $lim = $#{$self->{DATA}}; if(wantarray){ return undef if($self->{EOF}); my $self = shift;sub READLINE {} return bless \%fh, $class; $fh{NEXT} = 0; } $fh{DATA} = \@_; } else { $fh{DATA} = @_[0]; if(ref @_[0]){ # XXX yuck my %fh; my $class = shift;sub TIEHANDLE {package NHIO::STDIN;###### ugly mess so we can re-read STDIN###} &trace_start; @saved_argv = @ARGV; %saved_env = %ENV;BEGIN {} } print TRACE " $k => $ENV{$k}\n"; next unless ($k =~ m/(^GIT_)|(^NH)/); foreach my $k (sort keys %ENV){ print TRACE "ENV:\n"; } print TRACE "[$x1] $ARGV[$x]\n"; $x1 = $x+1; for(my $x=0;$x>", $tracefile; my $self = shift; return unless($trace);sub trace_start {} } print TRACE "END $p\n" if($trace); close TOHOOK or die "close $hname: $! $?"; print TOHOOK ; open TOHOOK, "|-", $hname or die "open $hname: $!"; print TRACE "START $p: $hname\n" if($trace); if(-x $hname){ $hname =~ s!^((.*$DS)|())(.*)!$1$p-$4!; my $hname = $0; my($p) = @_;sub do_hook {# PRIVATE} &do_hook("POST");sub POST {} &do_hook("PRE");sub PRE {#}# %ENV = %saved_env;# @ARGV = @saved_argv;# open STDIN, "<", \$saved_input or die "reopen STDIN: $!";#sub restore {# don't need this now} tie *STDIN, 'NHIO::STDIN', $data; untie *STDIN; my $data = @$x{DATA}; my %x = %$x; my $x = tied(*STDIN);sub resetSTDIN{# (the sensitive thing is @foo = )# XXX this needs a re-write (don't tie and untie, just set NEXT=0)} tie *STDIN, 'NHIO::STDIN', @saved_input; } print TRACE "ENDSTDIN\n"; print TRACE $saved_input; print TRACE "STDIN:\n"; if($trace){ @saved_input = ;sub saveSTDIN {our $saved_input;our @saved_argv;our %saved_env;} $DS = quotemeta('\\');{if ($^O eq "MSWin32")my $DS = quotemeta('/');# OS hackerymy $tracefile = "/tmp/nhgitt.$$";my $trace = 0;###### CONFIG###use Cwd;package NHgithook;# NetHack Git Hook Module# NHgithook.pm#adX  $kjWV F r - ,   y x l k 2 1 # "   Kenneth Lorber (keni@his.com)=head1 AUTHORSome features not well tested, especially under Windows.=head1 BUGS NHgithook::POST runs the POST hook, if it exists NHgithook::PRE runs the PRE hook, if it exists NHgithook::saveSTDIN reads STDIN until EOF and saves it=head1 FUNCTIONSmay be useful since multiple processes may be live at the same time.C<$tracefile> specifies the file used for trace output. Note that C<$$>filehandle must be guarded by C<$NHgithook::trace>. Settingand leaves the C filehandle open for additional output; output to thismodule source. Setting C<$trace> enables tracing, logs basic information,Changing the C<$trace> and C<$tracefile> variables requires editing the=head1 SETUPGit hooks and similar Git callouts.Buffers call information so multiple independent actions may be coded for=head1 DESCRIPTION &NHgithook::POST; (core hook code) &NHgithook::PRE; &NHgithook::saveSTDIN; use NHgithook; } push(@INC, $gitdir.$PDS."hooks");nethack-3.6.0/DEVEL/hooksdir/NHadd0000664000076400007660000000102012536476415015525 0ustar paxedpaxed#!/usr/bin/perl # wrapper for nhadd and nhcommit aliases # $NHDT-Date: 1427408239 2015/03/26 22:17:19 $ %ok = map { $_ => 1 } ('add', 'commit'); die "Bad subcommand '$ARGV[0]'" unless $ok{$ARGV[0]}; # we won't fail on a failure, so just system() $rv = system('.git/hooks/nhsub',"--$ARGV[0]",@ARGV[1..$#ARGV]); if($rv){ print "warning: nhsub failed: $rv $!\n"; } if(length $ENV{GIT_PREFIX}){ chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; } exec "git", @ARGV or die "Can't exec git: $!"; nethack-3.6.0/DEVEL/hooksdir/NHgithook.pm0000664000076400007660000001047012504242744017054 0ustar paxedpaxed# # NHgithook.pm # NetHack Git Hook Module # $NHDT-Date$ package NHgithook; use Cwd; ### ### CONFIG ### my $trace = 0; my $tracefile = "/tmp/nhgitt.$$"; # OS hackery my $DS = quotemeta('/'); if ($^O eq "MSWin32") { $DS = quotemeta('\\'); } our %saved_env; our @saved_argv; our $saved_input; sub saveSTDIN { @saved_input = ; if($trace){ print TRACE "STDIN:\n"; print TRACE $saved_input; print TRACE "ENDSTDIN\n"; } tie *STDIN, 'NHIO::STDIN', @saved_input; } # XXX this needs a re-write (don't tie and untie, just set NEXT=0) # (the sensitive thing is @foo = ) sub resetSTDIN{ my $x = tied(*STDIN); my %x = %$x; my $data = @$x{DATA}; untie *STDIN; tie *STDIN, 'NHIO::STDIN', $data; } # don't need this now #sub restore { # open STDIN, "<", \$saved_input or die "reopen STDIN: $!"; # @ARGV = @saved_argv; # %ENV = %saved_env; #} sub PRE { &do_hook("PRE"); } sub POST { &do_hook("POST"); } # PRIVATE sub do_hook { my($p) = @_; my $hname = $0; $hname =~ s!^((.*$DS)|())(.*)!$1$p-$4!; if(-x $hname){ print TRACE "START $p: $hname\n" if($trace); open TOHOOK, "|-", $hname or die "open $hname: $!"; print TOHOOK ; close TOHOOK or die "close $hname: $! $?"; print TRACE "END $p\n" if($trace); } } sub trace_start { return unless($trace); my $self = shift; open TRACE, ">>", $tracefile; print TRACE "START CLIENT PID:$$ ARGV:\n"; print TRACE "CWD: " . cwd() . "\n"; print TRACE "[0] $0\n"; my $x1; for(my $x=0;$x $ENV{$k}\n"; } } BEGIN { %saved_env = %ENV; @saved_argv = @ARGV; &trace_start; } ### ### ugly mess so we can re-read STDIN ### package NHIO::STDIN; sub TIEHANDLE { my $class = shift; my %fh; # XXX yuck if(ref @_[0]){ $fh{DATA} = @_[0]; } else { $fh{DATA} = \@_; } $fh{NEXT} = 0; return bless \%fh, $class; } sub READLINE { my $self = shift; return undef if($self->{EOF}); if(wantarray){ my $lim = $#{$self->{DATA}}; my @ary = @{$self->{DATA}}[$self->{NEXT}..$lim]; my @rv = @ary[$self->{NEXT}..$#ary]; $self->{EOF} = 1; return @rv; } else{ my $rv = $self->{DATA}[$self->{NEXT}]; if(length $rv){ $self->{NEXT}++; return $rv; } else { $self->{EOF} = 1; return undef; } } } sub EOF { $self = shift; return $self->{EOF}; } 1; __END__ =head1 NAME NHgithook - common code for NetHack git hooks (and other git bits) =head1 SYNOPSIS BEGIN { my $DS = quotemeta('/'); my $PDS = '/'; if ($^O eq "MSWin32") { $DS = quotemeta('\\'); $PDS = '\\'; } push(@INC, $ENV{GIT_DIR}.$PDS."hooks"); # for most hooks push(@INC, ($0 =~ m!^(.*)$DS!)[0]); # when the above doesn't work $gitdir = `git rev-parse --git-dir`; # and when the above really doesn't work $gitdir =~ s/[\r\n]*$/; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; &NHgithook::saveSTDIN; &NHgithook::PRE; (core hook code) &NHgithook::POST; =head1 DESCRIPTION Buffers call information so multiple independent actions may be coded for Git hooks and similar Git callouts. =head1 SETUP Changing the C<$trace> and C<$tracefile> variables requires editing the module source. Setting C<$trace> enables tracing, logs basic information, and leaves the C filehandle open for additional output; output to this filehandle must be guarded by C<$NHgithook::trace>. Setting C<$tracefile> specifies the file used for trace output. Note that C<$$> may be useful since multiple processes may be live at the same time. =head1 FUNCTIONS NHgithook::saveSTDIN reads STDIN until EOF and saves it NHgithook::PRE runs the PRE hook, if it exists NHgithook::POST runs the POST hook, if it exists =head1 BUGS Some features not well tested, especially under Windows. =head1 AUTHOR Kenneth Lorber (keni@his.com) nethack-3.6.0/DEVEL/hooksdir/NHsubst0000775000076400007660000002317312536476415016155 0ustar paxedpaxed#!/usr/bin/perl # # NHsubst # $NHDT-Date$ # git merge driver for substitutions (like RCS/CVS) # driver line: .... %O %A %B %L use strict; my $debug = 0; my $rawin = 0; # feed diff to stdin for testing (do NOT set $debug=1) # We want TRACE open so we don't need to test $debug everywhere, but we skip # this first block because it's expensive and dumpfile() hangs with $rawin. my $sink = ($^O eq "MSWin32") ? "NUL" : "/dev/null"; my $dbgfile = ($^O eq "MSWin32") ? "$ENV{TEMP}.$$" : "/tmp/trace.$$"; open TRACE, ">>", $rawin?"/dev/tty":(($debug==0)? $sink : $dbgfile); print TRACE "TEST TRACE\n"; if($debug){ print TRACE "START CLIENT ARGV:\n"; print TRACE "[0] $0\n"; my $x1; for(my $x=0;$x $ENV{$k}\n"; } print TRACE "CWD: " . `pwd`; &dumpfile($ARGV[0], "[0O]"); &dumpfile($ARGV[1], "[1A]"); &dumpfile($ARGV[2], "[2B]"); print TRACE "L=$ARGV[3]\n"; print TRACE "END\n"; } my $mark_len = $ARGV[3]; $mark_len = 3 if($mark_len==0 && $rawin); my $mark_start = '<' x $mark_len; my $mark_middle = '=' x $mark_len; my $mark_end = '>' x $mark_len; my $PREFIX; # pick up the prefix for substitutions in this repo if($rawin){ $PREFIX = "TEST"; } else { $PREFIX = `git config --local --get nethack.substprefix`; chomp($PREFIX); } my @out; my $cntout; if($rawin){ @out = ; } else { #system "git merge-file -p .... > temp my $tags = "-L CURRENT -L ANCESTOR -L OTHER"; # XXX should "CURRENT" be "MINE"? @out = `git merge-file -p $tags $ARGV[1] $ARGV[0] $ARGV[2]`; #NB: we don't check the exit value because it's useless print TRACE "MERGE-FILE START\n".join("",@out)."MERGE-FILE END\n"; } ($cntout,@out) = &edit_merge(@out); if($rawin){ print "COUNT: $cntout\n"; print @out; } else { # spit @out to $ARGV[1] (careful: what about EOL character?) open OUT, ">$ARGV[1]" or die "Can't open $ARGV[1]"; print OUT @out; close OUT; print TRACE "WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n"; &dumpfile($ARGV[1], "READBACK"); } print TRACE "COUNT: $cntout\n"; exit( ($cntout>0) ? 1 : 0); #git merge-file [-L [-L [-L ]]] # [--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=] # [--[no-]diff3] #The `merge.*.driver` variable's value is used to construct a command to run to merge ancestor's # version (%O), current version (%A) and the other branches' version (%B). These three tokens are # replaced with the names of temporary files that hold the contents of these versions when the # command line is built. Additionally, %L will be replaced with the conflict marker size (see # below). # keep failing so we don't need to keep changing the setup while building this script sub dumpfile { my($file, $tag) = @_; print TRACE "FILE $tag START\n"; print TRACE `hexdump -C $file`; print TRACE "FILE END\n"; } sub edit_merge { my(@input) = @_; # $::count is a bit ugly XXX local $::count = 0; # we need the number of conflicts for exit() my @out; local $_; while($_ = shift @input){ if(m/^$mark_start /){ print TRACE "FOUND A CONFLICT\n"; my @conflict; push(@conflict, $_); while($_ = shift @input){ push(@conflict, $_); if(m/^$mark_end /){ last; } } push(@out, &edit_conflict(@conflict)); } else { push(@out, $_); } } print TRACE "RETURN count=$::count\n"; return($::count, @out); } sub edit_conflict { my(@in) = @_; print TRACE "EDIT START: " . scalar(@in)."\n"; if($debug){ foreach my $x (@in){ my $xx = $x; chomp($xx); print TRACE "-$xx-\n"; } } print TRACE "EDIT END INPUT\n"; # one-line change - use as base case to develop the code # ours ARGV[1] top-of-diff # theirs ARGV[2] bottom-of-diff # simple conflict: # [0] <<<<<<< d1 # [1] $$PREFIX-Date: 1 ... # [2] ======= # [3] $$PREFIX-Date: 3 ... # [4] >>>>>>> d3 if(scalar(@in) == 5 && $in[2] =~ m/^$mark_middle/){ my $back = &merge_one_line_maybe($in[1],$in[3]); # (ours, theirs) if(!defined $back){ $::count++; # leave the conflict return @in; } else { return ($back); } # NOTREACHED } else { # XXX LATER # Start at the top of both sections and work downwards. As long as the lines can be merged, # push them out and keep going. If there are lines left, we will still have a conflict but # we can try to make it smaller. Push out the start-conflict marker. Start at the # bottom of both section and work upwards. As long as the lines can be merged, reverse push out # the merged line and keep going. (We know there will be lines left at some point.) Push out # remaining (middle) lines from OURS. Push out mark_middle. Push out remaining middle lines # from THEIRS. Push out end-conflict marker. $::count++; return (@a,$b,@c,$d,@e,$f,@g) # @a # $b = <<< # @c # $d = === # @e # $f = >>> # @g } # not matched - return the unchanged conflict $::count++; return @in; } # XXX This is expensive. Add a quick check for "anything that looks like a subst var" and just # declare the lines unmergeable if it fails. sub merge_one_line_maybe { my($ours, $theirs) = @_; my $more = 1; my $fail = 0; my $out = ''; # TYPES: # 0 no match # 1 unexpanded var # 2 expanded var # 3 non-var text my($ourstype, $theirtype); my($oursvar, $theirvar); my($oursval, $theirval); while($more){ ($ourstype, $theirtype) = (0,0); ($oursvar, $theirvar) = (undef, undef); ($oursvar, $theirvar) = (undef, undef); # unexpanded var if($ours =~ m/\G\$$PREFIX-([A-Z][a-z]+)\$/gc){ $ourstype = 1; $oursvar = $1; } if($theirs =~ m/\G\$$PREFIX-([A-Z][a-z]+)\$/gc){ $theirtype = 1; $theirvar = $1; } # expanded var unless($ourstype){ if($ours =~ m/\G\$$PREFIX-([A-Za-z]+):\s+(.*?)\s\$/gc){ $ourstype = 2; $oursvar = $1; $oursval = $2; } } unless($theirtype){ if($theirs =~ m/\G\$$PREFIX-([A-Za-z]+):\s+(.*?)\s\$/gc){ $theirtype = 2; $theirvar = $1; $theirval = $2; } } # non-var text unless($ourstype){ if($ours =~ m/\G(\$?[^\x24]*)/gc){ $ourstype = 3; $oursval = $1; } } unless($theirtype){ if($theirs =~ m/\G(\$?[^\x24]*)/gc){ $theirtype = 3; $theirval = $1; } } print TRACE "MID: $ourstype/$oursval $theirtype/$theirval\n"; # are we done? if(pos($ours)==length $ours && pos($theirs) == length $theirs){ $more = 0; } if($ourstype == 0 && $theirtype == 0){ die "NHsubst MERGE FAILED - aborted infinite loop\n"; } # now see if ours and their match or can be resolved # text if($ourstype == 3 && $theirtype == 3){ #mismatch is \s vs \s\s - where is this coming from? # HACK - hopefully temporary if($oursval =~ m/^\s+$/ && $theirval =~ m/^\s+$/){ $out .= $oursval; next; } if($oursval eq $theirval){ $out .= $oursval; next; } return undef; } if($ourstype == 3 || $theirtype == 3){ return undef; } # XXX we could do better: on failure of one field, return 2 lines with the fields we _can_ fix # substituted into those lines, leaving only the fail-to-match bits for the user to # deal with. Later. # vars (all 4 cases) if($oursvar ne $theirvar){ return undef; } my $m = merge_one_var_maybe($oursvar, $oursval, $theirval); if(! defined $m){ return undef; } $out .= $m; } return $out; } # return undef if we can't merge the values; $NAME: VALUE $ or $NAME$ (as appropriate) if we can. sub merge_one_var_maybe { my($varname, $oursval, $theirval) = @_; print TRACE "MVM: -$varname-$oursval-$theirval-\n"; my $resolvedas; { no strict; my $fn = "PREFIX::$varname"; if(defined &$fn){ $resolvedas = &$fn($PREFIX,$varname,$oursval, $theirval); } else { $resolvedas = undef; # can't resolve } } if(!defined $resolvedas){ $::count++; # we have an externally visible conflict return undef; } else { return $resolvedas; } # NOTREACHED } package PREFIX; # Resolve the conflict of a single var's 2 values. Return undef to leave the conflict. sub Date { my($PREFIX, $varname, $mine, $theirs) = @_; my $m = ($mine =~ m/(\d+)/)[0]; my $t = ($theirs =~ m/(\d+)/)[0]; return undef unless ($m>0) && ($t>0); return "\$$PREFIX-$varname: " . (($m>$t)?$mine:$theirs) .' $'; } #sub Header { #sub Author { sub Branch { my($PREFIX, $varname, $mine, $theirs) = @_; $mine =~ s/^\s+//; $mine =~ s/\s+$//; $theirs =~ s/^\s+//; $theirs =~ s/\s+$//; return "\$$PREFIX-$varname: $mine \$" if(length $mine); return "\$$PREFIX-$varname: $theirs \$" if(length $theirs); return "\$$PREFIX-$varname\$" if(length $theirs); } sub Revision { my($PREFIX, $varname, $mine, $theirs) = @_; my($m) = ($mine =~ m/1.(\d+)/); my($t) = ($theirs =~ m/1.(\d+)/); if($m > 0 && $t > 0){ my $q = ($m > $t) ? $m : $t; return "\$$PREFIX-$varname: 1.$q \$"; } if($m > 0){ return "\$$PREFIX-$varname: 1.$m \$"; } if($t > 0){ return "\$$PREFIX-$varname: 1.$t \$"; } return "\$$PREFIX-$varname\$"; } __END__ TEST 1: <<< d1 $TEST-Date: 1 $ === $TEST-Date: 3 $ >>> d3 TEST 2: nothing at all TEST 3: <<< d1 a line === one line two lines >>> d3 TEST 4: <<< d1 $TEST-Date: 1 $ yes === $TEST-Date: 1 $ no >>> d3 TEST 5: <<< d1 $TEST-Date: 3 $ yes === $TEST-Date: 1 $ yes >>> d3 TEST 6: <<< d1 $TEST-Date: 3 $ yes$TEST-Date: 4 $ === $TEST-Date: 1 $ yes$TEST-Date: 5 $ >>> d3 TEST 7: <<< d1 $TEST-Branch: mine $ === $TEST-Branch: theirs $ >>> d3 TEST 8: <<< d1 /* NetHack 3.6 objnam.c $TEST-Date$ $TEST-Branch$:$TEST-Revision$ */ === /* NetHack 3.6 objnam.c $TEST-Date: 1426977394 2015/03/21 22:36:34 $ $TEST-Branch: master $:$TEST-Revision: 1.108 $ */ >>> d3 nethack-3.6.0/DEVEL/hooksdir/NHtext0000775000076400007660000000727112504447327015775 0ustar paxedpaxed#!/usr/bin/perl # # NHtext # $NHDT-Date$ # clean/smudge filter for handling substitutions use strict; #my $debug = 0; # save trace to file #my $debug2 = 0; # annotate output when running from command line #my $sink = ($^O eq "MSWin32")? "NUL" :"/dev/null"; #my $dbgfile = ($^O eq "MSWin32") ? "$ENV{TEMP}.$$" : "/tmp/trace.$$"; #open TRACE, ">>", ($debug==0)? $sink : $dbgfile; sub git_config { my($section, $var) = @_; local($_); # Sigh. Without GIT_DIR we have to do it the slow way, and sometimes we don't # have GIT_DIR. if(0 == length($ENV{GIT_DIR})){ my $raw = `git config --local --get $section.$var`; chomp($raw); return $raw } open(CONFIG, "<", "$ENV{GIT_DIR}/config") or die "Missing .git/config: $!"; while(){ m/^\[$section]/ && do { while(){ m/^\s+$var\s+=\s+(.*)/ && do { return $1; }; } }; } die "Missing config var: [$section] $var\n"; } # pick up the prefix for substitutions in this repo my $PREFIX = &git_config('nethack','substprefix'); my $submode = 0; # ok to make non-cleaning changes to file my $mode; if($ARGV[0] eq "--clean"){ $mode = "c"; if(0 == 0+$ENV{NHMODE}){ $submode = 1; # do NOT add extra changes to the file # print TRACE "SKIPPING\n"; } } elsif($ARGV[0] eq "--smudge"){ $mode = "s"; } else { warn "Unknown mode '$ARGV[0]'\n"; exit 1; } # XXX for now, there isn't any - if we get called, we subst. No options for now. # get relevent config info #XXX #git check-attr -a $ARGV[1] # Process stdin to stdout. # For speed we read in the entire file then do the substitutions. local($_) = ''; my $len; while(1){ # On at least some systems we only get 64K. my $len = sysread(STDIN, $_, 999999, length($_)); last if($len == 0); die "read failed: $!" unless defined($len); } # $1 - var and value (including trailing space but not $) # $2 - var # $4 - value or undef # s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\N{DOLLAR SIGN}]+))?)\$/&handlevar($2,$4)/eg; s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+))?)\$/&handlevar($2,$4)/ego; die "write failed: $!" unless defined syswrite(STDOUT, $_); exit 0; sub handlevar { my($var, $val) = @_; # print "HIT '$var' '$val'\n" if($debug2); my $subname = "PREFIX::$var"; if(defined &$subname){ no strict; $val =~ s/\s+$//; $val = &$subname($val,$mode,$submode); } else { warn "No handler for \$$PREFIX-$var\n"; } if(length $val){ return "\$$PREFIX-$var: $val \$"; } else { return "\$$PREFIX-$var\$"; } } package PREFIX; use POSIX qw(strftime); # On push, put in the current date because we changed the file. # On pull, keep the current value so we can see the last change date. sub Date { my($val, $mode, $submode) = @_; if($mode eq "c"){ if($submode==0){ # we add this to make merge easier for now XXX my $now = time; # not %s below - may not be portable # YYYY/MM/DD HH:MM:SS $val = "$now " . strftime("%Y/%m/%d %H:%M:%S", gmtime($now)); } } # if($mode eq "s"){ # } return $val; } #sub Header { #} #sub Author { #} # NB: the standard-ish Revision line isn't enough - you need Branch:Revision - # but we split it into 2 so we can use the standard processing code on Revision # and just slip Branch in. sub Branch { my($val, $mode, $submode) = @_; if($mode eq "c"){ if($submode==0){ $val = `git symbolic-ref -q --short HEAD`; $val =~ s/[\n\r]*$//; $val =~ s/^\*\s*//; $val = "(unknown)" unless($val =~ m/^[[:print:]]+$/); } } # if($mode eq "s"){ # } return $val; } sub Revision { my($val, $mode, $submode) = @_; if($mode eq "c"){ if($submode==0){ my $file = $ARGV[1]; my @val = `git log --follow --oneline $file`; my $ver = 0+$#val; $ver = 0 if($ver < 0); $val = "1.$ver"; } } # if($mode eq "s"){ # } return $val; } nethack-3.6.0/DEVEL/hooksdir/TARGET0000664000076400007660000000001312504242744015525 0ustar paxedpaxed.git/hooks nethack-3.6.0/DEVEL/hooksdir/applypatch-msg0000775000076400007660000000123112504242744017476 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/commit-msg0000775000076400007660000000123112504242744016621 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/nhsub0000664000076400007660000003273612536476415015710 0ustar paxedpaxed#!/usr/bin/perl # nhsub # $NHDT-Date: 1427408239 2015/03/26 22:17:19 $ # Note: was originally called nhdate; the rename is not reflected in the code. use strict; our %opt; #cmd v n f F m (other single char, but we don't care) my $mode; # a c d f (add, commit, date, date -f) if(length $ENV{GIT_PREFIX}){ chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; } #SO how do we know if a file has changed? #(git status: git status --porcelain --ignored -- FILES. #maybe + -z but it's a question of rename operations - probably doesn't # matter, but need to experiment. # key: [dacf] first character of opt{cmd} (f if nhsub -f or add -f) # first 2 chars of "git status --porcelain --ignored" # (see "git help status" for table) # No default. Undef means something unexpected happened. my %codes = ( 'f M'=>1, 'f D'=>1, # [MD] not updated 'a M'=>0, 'a D'=>0, 'd M'=>0, 'd D'=>0, 'c M'=>0, 'c D'=>0, 'dM '=>0, 'dMM'=>1, 'dMD'=>0, 'aM '=>0, 'aMM'=>1, 'aMD'=>0, 'cM '=>0, 'cMM'=>1, 'cMD'=>0, 'fM '=>0, 'fMM'=>1, 'fMD'=>0, # M [ MD] updated in index 'dA '=>1, 'dAM'=>1, 'dAD'=>1, 'aA '=>1, 'aAM'=>1, 'aAD'=>1, 'cA '=>1, 'cAM'=>1, 'cAD'=>1, 'fA '=>1, 'fAM'=>1, 'fAD'=>1, # A [ MD] added to index 'dD '=>0, 'dDM'=>0, 'aD '=>1, 'aDM'=>1, 'cD '=>0, 'cDM'=>0, 'fD '=>1, 'fDM'=>1, # D [ M] deleted from index 'dR '=>0, 'dRM'=>1, 'dRD'=>0, 'aR '=>0, 'aRM'=>1, 'aRD'=>0, 'cR '=>0, 'cRM'=>1, 'cRD'=>0, 'fR '=>0, 'fRM'=>1, 'fRD'=>0, # R [ MD] renamed in index 'dC '=>0, 'dCM'=>1, 'dCD'=>0, 'aC '=>0, 'aCM'=>1, 'aCD'=>0, 'cC '=>0, 'cCM'=>1, 'cCD'=>0, 'fC '=>0, 'fCM'=>1, 'fCD'=>0, # C [ MD] copied in index 'aM '=>1, 'aA '=>1, 'aR '=>1, 'aC '=>1, 'fM '=>1, 'fA '=>1, 'fR '=>1, 'fC '=>1, # [MARC] index and work tree matches 'd M'=>1, 'dMM'=>1, 'dAM'=>1, 'dRM'=>1, 'dCM'=>1, 'a M'=>1, 'aMM'=>1, 'aAM'=>1, 'aRM'=>1, 'aCM'=>1, 'c M'=>1, 'cMM'=>1, 'cAM'=>1, 'cRM'=>1, 'cCM'=>1, 'f M'=>1, 'fMM'=>1, 'fAM'=>1, 'fRM'=>1, 'fCM'=>1, # [ MARC] M work tree changed since index 'd D'=>0, 'dMD'=>0, 'dAD'=>0, 'dRD'=>0, 'dCD'=>0, 'a D'=>0, 'aMD'=>0, 'aAD'=>0, 'aRD'=>0, 'aCD'=>0, 'c D'=>0, 'cMD'=>0, 'cAD'=>0, 'cRD'=>0, 'cCD'=>0, 'f D'=>0, 'fMD'=>0, 'fAD'=>0, 'fRD'=>0, 'fCD'=>0, # [ MARC] D deleted in work tree # ------------------------------------------------- # DD unmerged, both deleted # AU unmerged, added by us # UD unmerged, deleted by them # UA unmerged, added by them # DU unmerged, deleted by us # AA unmerged, both added # UU unmerged, both modified # ------------------------------------------------- 'a??'=>1, 'f??'=>1, # ?? untracked 'd??'=>0, 'c??'=>0, 'f!!'=>1, # !! ignored 'a!!'=>0, 'd!!'=>0, 'c!!'=>0, 'f@@'=>1, # @@ internal ignored 'a@@'=>0, 'd@@'=>0, 'c@@'=>0 ); # OS hackery my $PDS = '/'; if ($^O eq "MSWin32") { $PDS = '\\'; } # various command line options to consider and what the code actually does: #DONE nhcommit with no files should exit(0) #DONE nhadd with no files should exit(0) #DONE commit -a? # add root dir #DONE commit -a + files -> exit(0) #nothing: commit --interactive/--patch #nothing: add -i/--interactive --patch/-p? #nothing: add -u/--update?????? -A/--all/--no-ignore-removal??? #nothing (not quite right): add --no-all --ignore-removal??? #DONE add --refresh #nothing: add -N/--intent-to-add #DONE add -n - exit(0) #DONE add --dry-run - exit 0 #DONE commit --dry-run - exit 0 #DONE?: add foo/\*/x (letting git expand the filenames) my @rawlist0 = &cmdparse(@ARGV); # Use git ls-files to expand command line filepaths with wildcards. # Let's try this for all commands. my @rawlist; foreach my $e (@rawlist0){ if($e =~ m/[?*[\\]/){ my @rv = &lsfiles(undef, $e); push(@rawlist, @rv) if(@rv); if($opt{f}){ my @rv = &lsfiles('-i', $e); push(@rawlist, @rv) if(@rv); } } else { push(@rawlist, $e); } } push(@rawlist,'.') if($#rawlist == -1); # pick up the prefix for substitutions in this repo #TEST my $PREFIX = &git_config('nethack','substprefix'); my $PREFIX = "NHDT"; print "PREFIX: '$PREFIX'\n" if($opt{v}); while(@rawlist){ my $raw = shift @rawlist; if(-f $raw){ &schedule_work($raw); next; } if(-d $raw){ if($raw =~ m!$PDS.git$!o){ print "SKIP $raw\n" if($opt{v}>=2); next; } opendir RDIR,$raw or die "Can't opendir: $raw"; local($_); # needed until perl 5.11.2 while($_ = readdir RDIR){ next if(m/^\.\.?$/); if(m/^\./ && $opt{f}){ print " IGNORE-f: $raw$PDS$_\n" if($opt{v}>=2); next; } push(@rawlist, $raw.$PDS.$_); } closedir RDIR; } # ignore other file types if(! -e $raw){ print "warning: missing file $raw\n"; } } # XXX could batch things up - later sub schedule_work { my($file) = @_; print "CHECK: '$file'\n" if($opt{v}>=2); local($_) = `git status --porcelain --ignored -- $file`; my $key = $mode . join('',(m/^(.)(.)/)); if(length $key == 1){ # Hack. An unmodified, tracked file produces no output from # git status. Treat as another version of 'ignored'. $key .= '@@'; } $key =~ s/-/ /g; # for Keni's locally mod'ed git if(!exists $codes{$key}){ die "I'm lost.\nK='$key' F=$file\nST=$_"; } if($codes{$key}==0){ if($opt{v}>=2){ print " IGNORE: $_" if(length); print " IGNORE: !! $file\n" if(!length); } return; } if($opt{F}){ my $ign = `git check-ignore $file`; if($ign !~ m/^\s*$/){ print " IGNORE-F: $ign" if($opt{v}>=2); return; } } # FALLTHROUGH and continue #print "ACCEPT TEST\n"; # XXXXXXXXXX TEST #return; my $attr = `git check-attr NHSUBST -- $file`; if($attr =~ m/NHSUBST:\s+(.*)/){ # XXX this is a bug in git. What if the value of an attribute is the # string "unset"? Sigh. if(! $opt{F}){ if($1 eq "unset" || $1 eq "unspecified"){ print " NOATTR: $attr" if($opt{v}>=2); return; } } &process_file($file); return; } die "Can't parse check-attr return: $attr\n"; } sub process_file { my($file) = @_; print "DOFIL: $file\n" if($opt{v}>=1); # For speed we read in the entire file then do the substitutions. local($_) = ''; my $len; open INFILE, "<", $file or die "Can't open $file: $!"; while(1){ # On at least some systems we only get 64K. my $len = sysread(INFILE, $_, 999999, length($_)); last if($len == 0); die "read failed: $!" unless defined($len); } close INFILE; local $::current_file = $file; # used under handlevar # $1 - var and value (including trailing space but not $) # $2 - var # $4 - value or undef #s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\N{DOLLAR SIGN}]+))?)\$/&handlevar($2,$4)/eg; my $count = s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+))?)\$/&handlevar($2,$4)/eg; # XXX had o modifier, why? return unless($count>0); return if($opt{n}); my $ofile = $file . ".nht"; open(TOUT, ">", $ofile) or die "Can't open $ofile"; # die "write failed: $!" unless defined syswrite(TOUT, $_); my $offset = 0; my $sent; #print STDERR "L=",length,"\n"; while($offset < length){ $sent = syswrite(TOUT, $_, (length($_) - $offset), $offset); die "write failed: $!" unless defined($sent); #print STDERR "rv=$sent\n"; last if($sent == (length($_) - $offset)); $offset += $sent; #print STDERR "loop: O=$offset\n"; } close TOUT or die "Can't close $ofile"; rename $ofile, $file or die "Can't rename $ofile to $file"; } # XXX docs for --fixup and --squash are wrong in git's synopsis. --file missing # --message --template -t sub cmdparse { my(@in) = @_; # What are we doing? $opt{cmd} = 'date'; # really nhsub if($in[0] eq '--add'){ $opt{cmd} = 'add'; shift @in; } if($in[0] eq '--commit'){ $opt{cmd} = 'commit'; shift @in; } # add: -n -v # commit: --dry-run -v # nhsub: -n -v while($in[0] =~ m/^-/){ local($_) = $in[0]; if($_ eq '--'){ shift @in; last; } if(m/^--/){ if($opt{cmd} eq 'add' && $_ eq '--dry-run'){ exit 0; } if($opt{cmd} eq 'commit' && $_ eq '--dry-run'){ exit 0; } if($opt{cmd} eq 'add' && $_ eq '--refresh'){ exit 0; } shift @in; next; } # XXX this is messy - time for a rewrite? if(m/^-(.*)/){ foreach my $single ( split(//,$1) ){ # don't do -v here from add/commit if($single ne 'v'){ # don't use -m from add/commit if($opt{cmd} eq 'date' || $single ne 'm'){ $opt{$single}++; } } elsif($opt{cmd} eq 'date'){ $opt{$single}++; } if($opt{cmd} eq 'add' && $single eq 'n'){ exit 0; } #need to deal with options that eat a following element (-m, -F etc etc) #add: nothing? #commit: -c -C -F -m # -u mode is optional # -S keyid is optional if($opt{cmd} eq 'commit'){ if($single =~ m/[uS]/){ last; } if($single =~ m/[cCFm]/){ #XXX this will be a mess if the argument is wrong, but can we tell? No. shift @in; last; } } } } shift @in; } ($mode) = ($opt{cmd} =~ m/^(.)/); $mode = 'f' if($opt{cmd} eq 'date' && ($opt{f}||$opt{F})); $mode = 'f' if($opt{cmd} eq 'add' && $opt{f}); if($opt{cmd} eq 'add' && $#in == -1){ exit 0; } if($opt{cmd} eq 'commit' && $#in == -1){ exit 0; } if($opt{cmd} eq 'add' && $opt{a} && $#in != -1){ exit 0; } if($opt{cmd} eq 'add' && $opt{a}){ my $x = `git rev-parse --show-toplevel`; $x =~ s/[\n\r]+$//; push(@in, $x); } return @in; # this is our file list } sub git_config { my($section, $var) = @_; my $raw = `git config --local --get $section.$var`; $raw =~ s/[\r\n]*$//g; return $raw if(length $raw); die "Missing config var: [$section] $var\n"; } sub handlevar { my($var, $val) = @_; # print "HIT '$var' '$val'\n" if($debug2); my $subname = "PREFIX::$var"; if(defined &$subname){ no strict; print " SUBIN: $var '$val'\n" if($opt{v}>=3); $val =~ s/\s+$//; $val = &$subname($val); print " SUBOT: $var '$val'\n" if($opt{v}>=3); } else { warn "No handler for \$$PREFIX-$var\n"; } if(length $val){ return "\$$PREFIX-$var: $val \$"; } else { return "\$$PREFIX-$var\$"; } } sub lsfiles { my ($flags, $ps) = @_; open RV, "-|", "git ls-files $flags '$ps'" or die "Can't ls-files"; my @rv = ; map { s/[\r\n]+$// } @rv; if(!close RV){ return undef if($! == 0); die "close ls-files failed: $!"; } return undef if($#rv == -1); return @rv; } package PREFIX; use POSIX qw(strftime); # On push, put in the current date because we changed the file. # On pull, keep the current value so we can see the last change date. sub Date { my($val) = @_; my $now; if($opt{m}){ my $hash = `git log -1 '--format=format:%H' $::current_file`; #author keni 1429884677 -0400 chomp($now = `git cat-file -p $hash | awk '/author/{print \$4}'`); } else { $now = time; } # YYYY/MM/DD HH:MM:SS $val = "$now " . strftime("%Y/%m/%d %H:%M:%S", gmtime($now)); return $val; } #sub Header { #} #sub Author { #} # NB: the standard-ish Revision line isn't enough - you need Branch:Revision - # but we split it into 2 so we can use the standard processing code on Revision # and just slip Branch in. sub Branch { my($val) = @_; $val = `git symbolic-ref -q --short HEAD`; $val =~ s/[\n\r]*$//; $val =~ s/^\*\s*//; $val = "(unknown)" unless($val =~ m/^[[:print:]]+$/); return $val; } sub Revision { my($val) = @_; my @val = `git log --follow --oneline $::current_file`; my $ver = 0+$#val; $ver = 0 if($ver < 0); $val = "1.$ver"; return $val; } __END__ =head1 NAME C - NetHack git command for substitution variables =head1 SYNOPSIS C =head1 DESCRIPTION C rewrites the specified files by doing variable substitution for variables starting with the prefix specified in the repository's C configuration variable. C is also invoked internally from the implementation of the C and C commands. The program re-writes those files listed on the command line; if the file is actually a directory, the program recurses into that directory tree. Not all files found are re-written; some are ignored and those with no substitution variables are not re-written. Unless changed by the options, files that have not changed are not affected. If no files are listed on the command line, the current directory is checked as if specified as C<.>. Files listed directly on the command line are always checked. The C<.git> directory is never processed. The following command line options are available: =over =item C<-v[v[v]]> Verbose output; may be (usefully) specified up to 3 times. Not available when invoked as part of C or C. =item C<-n> Do not write any files. =item C<-f> Force, version 1: Perform substitution even if the file has not changed, except no dot files are processed unless listed directly on the command line. This prevents accidents with editor temprorary files while recursing. Note that this overloads the C<-f> option of C and C. =item C<-F> Force, version 2: Perform substitution even if the file has not changed, even if the NHSUBST attribute is not set for the file, and only if the file is not ignored by git. Not available when invoked as part of C or C. =item C<-m> Use metadata (C and C) to find the last change date to substitute. Often used with C<-f>. This is useful for cleaning up dates in files that were not updated when last changed. (Do not use C/C after C or the changes will be overwritten with the current date.) =back nethack-3.6.0/DEVEL/hooksdir/post-applypatch0000775000076400007660000000123112504242744017675 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/post-checkout0000775000076400007660000000123112504242744017335 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/post-commit0000775000076400007660000000123112504242744017020 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/post-merge0000775000076400007660000000123112504242744016627 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/post-rewrite0000775000076400007660000000131012504242744017207 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::saveSTDIN; &NHgithook::PRE; &NHgithook::resetSTDIN; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/pre-applypatch0000775000076400007660000000123112504242744017476 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/pre-auto-gc0000775000076400007660000000123112504242744016670 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/pre-commit0000775000076400007660000000123112504242744016621 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/pre-push0000775000076400007660000000131012504242744016306 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::saveSTDIN; &NHgithook::PRE; &NHgithook::resetSTDIN; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/pre-rebase0000775000076400007660000000123112504242744016572 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/hooksdir/prepare-commit-msg0000775000076400007660000000123112504242744020255 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ #STARTUP-START BEGIN { # OS hackery has to be duplicated in each of the hooks :/ # first the directory separator my $DS = quotemeta('/'); my $PDS = '/'; # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). # temporarily removed because inconsistent behavior # if ($^O eq "msys") # { # $/ = "\r\n"; # $\ = "\r\n"; # } if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $PDS = '\\'; } $gitdir = `git rev-parse --git-dir`; chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } use NHgithook; #STARTUP-END &NHgithook::PRE; &NHgithook::POST; exit 0; nethack-3.6.0/DEVEL/nhgitset.pl0000775000076400007660000002046212536476415015202 0ustar paxedpaxed#!/usr/bin/perl # $NHDT-Date$ # value of nethack.setupversion we will end up with when this is done # version 1 is reserved for repos checked out before versioning was added my $version_new = 3; my $version_old = 0; # current version, if any (0 is no entry ergo new repo) use Cwd; use Getopt::Std; # Activestate Perl doesn't include File::Spec. Grr. BEGIN { eval "require File::Spec::Functions"; if($@){ die <import; } exit 1 unless(getopts('nvf')); # TODO: this can probably have better output # OS hackery my $DS = quotemeta('/'); # Directory Separator (for regex) my $DSP = '/'; # ... for printing # Temporarily disabled; there's something weird about msys # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). #if($^O eq "msys"){ # $/ = "\r\n"; # $\ = "\r\n"; # # NB: We don't need to do anything about File::Spec. It doesn't know # # about msys but it defaults to Unix, so we'll be ok. #} if($^O eq "MSWin32"){ $DS = quotemeta('\\'); $DSP = '\\'; } # make sure we're at the top level of a repo if(! -d ".git"){ die "This is not the top level of a git repository.\n"; } my $vtemp = `git config --local --get nethack.setupversion`; chomp($vtemp); if($vtemp > 0){ $version_old = 0+$vtemp; if($version_old != $version_new){ print STDERR "Migrating from setup version $version_old to $version_new\n" if($opt_v); } } # legacy check: if(length $vtemp == 0){ if(`git config --get merge.NHsubst.name` =~ m/^Net/){ $version_old = 1; print STDERR "Migrating to setup version 1\n" if($opt_v); } } my $gitadddir = `git config --get nethack.gitadddir`; chomp($gitadddir); if(length $gitadddir){ if(! -d $gitadddir){ die "nethack.gitadddir has invalid value '$gitadddir'\n"; } } print STDERR "nethack.gitadddir=$gitadddir\n" if($opt_v); # This is (relatively) safe because we know we're at R in R/DEVEL/nhgitset.pl my $srcdir = ($0 =~ m!^(.*)$DS!)[0]; if(! -f catfile($srcdir, 'nhgitset.pl')){ die "I can't find myself in '$srcdir'\n"; } print STDERR "Copying from: $srcdir\n" if($opt_v); if($opt_f || $version_old==0){ print STDERR "Configuring line endings\n" if($opt_v); unlink catfile('.git','index') unless($opt_n); system("git reset") unless($opt_n); system("git config --local core.safecrlf true") unless($opt_n); system("git config --local core.autocrlf false") unless($opt_n); } elsif($version_old <2){ my $xx = `git config --get --local core.safecrlf`; if($xx !~ m/true/){ print STDERR "\nNeed to 'rm .git${DSP}index;git reset'.\n"; print STDERR " When ready to proceed, re-run with -f flag.\n"; exit 2; } } print STDERR "Installing aliases\n" if($opt_v); $addpath = catfile(curdir(),'.git','hooks','NHadd'); &add_alias('nhadd', "!$addpath add"); &add_alias('nhcommit', "!$addpath commit"); my $nhsub = catfile(curdir(),'.git','hooks','nhsub'); &add_alias('nhsub', "!$nhsub"); print STDERR "Installing filter/merge\n" if($opt_v); # XXXX need it in NHadd to find nhsub??? # removed at version 3 #if($^O eq "MSWin32"){ # $cmd = '.git\\\\hooks\\\\NHtext'; #} else { # $cmd = catfile(curdir(),'.git','hooks','NHtext'); #} #&add_config('filter.NHtext.clean', "$cmd --clean %f"); #&add_config('filter.NHtext.smudge', "$cmd --smudge %f"); if($version_old == 1 or $version_old == 2){ print STDERR "Removing filter.NHtext\n" if($opt_v); system('git','config','--unset','filter.NHtext.clean') unless($opt_n); system('git','config','--unset','filter.NHtext.smudge') unless($opt_n); system('git','config','--remove-section','filter.NHtext') unless($opt_n); print STDERR "Removing NHtext\n" if($opt_v); unlink catfile(curdir(),'.git','hooks','NHtext') unless($opt_n); } $cmd = catfile(curdir(),'.git','hooks','NHsubst'); &add_config('merge.NHsubst.name', 'NetHack Keyword Substitution'); &add_config('merge.NHsubst.driver', "$cmd %O %A %B %L"); print STDERR "Running directories\n" if($opt_v); foreach my $dir ( glob("$srcdir$DS*") ){ next unless(-d $dir); my $target = catfile($dir, 'TARGET'); next unless(-f $target); open TARGET, '<', $target or die "$target: $!"; my $targetpath = ; # still have to eat all these line endings under msys, so instead of chomp use this: $targetpath =~ s![\r\n]!!g; close TARGET; print STDERR "Directory $dir -> $targetpath\n" if($opt_v); my $enddir = $dir; $enddir =~ s!.*$DS!!; if(! &process_override($enddir, "INSTEAD")){ &process_override($enddir, "PRE"); my $fnname = "do_dir_$enddir"; if(defined &$fnname){ &$fnname($dir, $targetpath); } &process_override($enddir, "POST"); } } &check_prefix; # for variable substitution if($version_old != $version_new){ print STDERR "Setting version to $version_new\n" if($opt_v); if(! $opt_n){ system("git config nethack.setupversion $version_new"); if($?){ die "Can't set nethack.setupversion $version_new: $?,$!\n"; } } } exit 0; sub process_override { my($srcdir, $plname) = @_; return 0 unless(length $gitadddir); my $plpath = catfile($gitadddir, $srcdir, $plname); #print STDERR " ",catfile($srcdir, $plname),"\n"; # save this for updating docs - list of overrides return 0 unless(-x $plpath); print STDERR "Running $plpath\n" if($opt_v); # current directory is top of target repo unless($opt_n){ system("$plpath $opt_v") and die "Callout $plpath failed: $?\n"; } return 1; } sub add_alias { my($name, $def) = @_; &add_config("alias.$name",$def); } sub add_config { my($name, $val) = @_; system('git', 'config', '--local', $name, $val) unless($opt_n); } sub check_prefix { my $lcl = `git config --local --get nethack.substprefix`; chomp($lcl); if(0==length $lcl){ my $other = `git config --get nethack.substprefix`; chomp($other); if(0==length $other){ print STDERR "ERROR: nethack.substprefix is not set anywhere. Set it and re-run.\n"; exit 2; } else { &add_config('nethack.substprefix', $other); print STDERR "Copying prefix '$other' to local repository.\n" if($opt_v); } $lcl = $other; # for display below } print "\n\nUsing prefix '$lcl' - PLEASE MAKE SURE THIS IS CORRECT\n\n"; } sub do_dir_DOTGIT { if(1){ # We are NOT going to mess with config now. return; } else { my($srcdir, $targetdir) = @_; #warn "do_dir_DOTGIT($srcdir, $targetdir)\n"; my $cname = "$srcdir/config"; if(-e $cname){ print STDERR "Appending to .git/config\n" if($opt_v); open CONFIG, ">>.git/config" or die "open .git/config: $!"; open IN, "<", $cname or die "open $cname: $!"; my @data = ; print CONFIG @data; close IN; close CONFIG; } else { print STDERR " Nothing to add to .git/config\n" if($opt_v); } # XXX are there other files in .git that we might want to handle? # So just in case: for my $file ( glob("$srcdir/*") ){ next if( $file =~ m!.*/TARGET$! ); next if( $file =~ m!.*/config$! ); die "ERROR: no handler for $file\n"; } } } sub do_dir_hooksdir { my($srcdir, $targetdir) = @_; for my $path ( glob("$srcdir$DS*") ){ next if( $path =~ m!.*${DS}TARGET$! ); my $file = $path; $file =~ s!.*$DS!!; $file = catfile($targetdir, $file); next if($opt_n); open IN, "<", $path or die "Can't open $path: $!"; open OUT, ">", "$file" or die "Can't open $file: $!"; while(){ print OUT; } close OUT; close IN; if(! -x $file){ chmod 0755 ,$file; } } } __END__ (can we change the .gitattributes syntax to include a comment character?) maybe [comment] attr.c:parse_attr_line grr - looks like # is the comment character =head1 NAME nhgitset.pl - Setup program for NetHack git repositories =head1 SYNOPSIS cd THE_REPO [git config nethack.gitadddir GITADDDIR] perl SOME_PATH/DEVEL/nhgitset.pl [-v][-n][-f] =head1 DESCRIPTION nhgitset.pl installs NetHack-specific setup after a C (or after changes to the desired configuration, which are installed by re-running nhgitset.pl). The follwing options are available: B<-f> Force. Do not use this unless the program requests it. B<-n> Make no changes. B<-v> Verbose output. =head1 CONFIG nhgitset.pl uses the following non-standard C variables: nethack.gitadddir DOTGIT/INSTEAD DOTGIT/PRE DOTGIT/POST hooksdir/INSTEAD hooksdir/PRE hooksdir/POST nethack.setupversion nethack.substprefix =head1 EXIT STATUS 0 Success. 1 Fail. 2 Intervention required. nethack-3.6.0/Files0000664000076400007660000004305412631241231013123 0ustar paxedpaxedThis is a listing of all files in a full NetHack 3.6 distribution, organized in their standard manner on a UNIX system. It indicates which files are necessary for which versions, so that you can tell which files may be deleted from or not transferred to your system if you wish. .: (files in top directory) Files Porting README dat: (files for all versions) Arch.des Barb.des Caveman.des Healer.des Knight.des Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des Valkyrie.des Wizard.des bigroom.des castle.des cmdhelp data.base dungeon.def endgame.des gehennom.des help hh history knox.des license medusa.des mines.des opthelp oracle.des oracles.txt quest.txt rumors.fal rumors.tru sokoban.des symbols tower.des wizhelp yendor.des tribute bogusmon.txt engrave.txt epitaph.txt doc: (files for all versions) Guidebook.mn Guidebook.tex Guidebook.txt dgn_comp.6 dgn_comp.txt dlb.6 dlb.txt fixes22.0 fixes30.0 fixes31.1 fixes31.2 fixes31.3 fixes32.0 fixes32.1 fixes32.2 fixes32.3 fixes33.0 fixes33.1 fixes34.0 fixes34.1 fixes34.2 fixes34.3 fixes35.0 fixes36.0 lev_comp.6 lev_comp.txt makedefs.6 makedefs.txt nethack.6 nethack.txt recover.6 recover.txt tmac.n window.doc include: (files for all versions) align.h amiconf.h artifact.h artilist.h attrib.h beconf.h botl.h color.h config.h config1.h context.h coord.h decl.h def_os2.h dgn_file.h display.h dlb.h dungeon.h engrave.h extern.h flag.h func_tab.h global.h hack.h lev.h lint.h mail.h mextra.h mfndpos.h micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsym.h ntconf.h obj.h objclass.h os2conf.h patchlevel.h pcconf.h permonst.h prop.h qtext.h quest.h rect.h region.h rm.h skills.h sp_lev.h spell.h sys.h system.h tcap.h timeout.h tosconf.h tradstdc.h trampoli.h trap.h unixconf.h vision.h vmsconf.h wceconf.h winami.h winprocs.h wintype.h you.h youprop.h (file for tty versions) wintty.h (files for X versions) tile2x11.h winX.h xwindow.h xwindowp.h (files for Qt versions) qt_clust.h qt_kde0.h qt_win.h qt_xpms.h qttableview.h (files for Gem versions) bitmfile.h gem_rsc.h load_img.h wingem.h (file for GNOME versions) winGnome.h (files for various Macintosh versions) mac-carbon.h mac-qt.h mac-term.h macconf.h macpopup.h mactty.h macwin.h mttypriv.h src: (files for all versions) allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c options.c pager.c pickup.c pline.c polyself.c potion.c pray.c priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c steal.c steed.c sys.c teleport.c timeout.c topten.c track.c trap.c u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c windows.c wizard.c worm.c worn.c write.c zap.c sys/amiga: (files for Amiga versions - untested for 3.6.0) Build.ami Install.ami Makefile.agc Makefile.ami NetHack.cnf amidos.c amidos.p amifont.uu amifont8.uu amigst.c amii.hlp amimenu.c amirip.c amisnd.c amistack.c amitty.c amiwind.c amiwind.p clipwin.c colorwin.c cvtsnd.c grave16.xpm ifchange mkdmake txt2iff.c winami.c winami.p winchar.c windefs.h winext.h winfuncs.c winkey.c winmenu.c winproto.h winreq.c winstr.c xpm2iff.c sys/atari: (files for Atari version - untested for 3.6.0) Install.tos atarifnt.uue nethack.mnu setup.g tos.c unx2atar.sed sys/be: (files for BeOS version - untested for 3.6.0) README bemain.c sys/mac: (files for Macintosh versions) Files.r Install.mw MacHelp NHDeflts NHrsrc.hqx NHsound.hqx News README carbon.plist dprintf.c maccurs.c macerrs.c macfile.c machelp.hqx macmain.c macmenu.c macsnd.c mactopl.c mactty.c macunix.c macwin.c mgetline.c mmodal.c mrecover.c mrecover.hqx mttymain.c sys/msdos: (files for MSDOS version - untested for 3.6.0) Install.dos Makefile.BC Makefile.GCC Makefile.MSC moveinit.pat msdos.c msdoshlp.txt ovlinit.c pckeys.c pctiles.c pctiles.h pcvideo.h portio.h schema1.BC schema2.BC schema3.MSC SCHEMA35.MSC setup.bat sound.c tile2bin.c video.c vidtxt.c vidvga.c (files for running MSDOS binary under Windows) nhico.uu nhpif.uu sys/os2: (files for OS/2 version - untested for 3.6.0) Install.os2 Makefile.os2 nhpmico.uu os2.c sys/share: (files for MSDOS and OS/2 versions - untested for 3.6.0) Makefile.lib termcap.uu (file for MSDOS, OS/2, NT, Amiga, and Atari versions - untested for 3.6.0) pcmain.c (files for MSDOS, OS/2, NT, and Atari versions - untested for 3.6.0) pcsys.c pcunix.c (file for MSDOS, OS/2, and Atari versions - untested for 3.6.0) NetHack.cnf pctty.c (files for UNIX and Be versions) ioctl.c unixtty.c (file for NT version) nhlan.c (Berkeley random number file, which may be included in any version) random.c (Berkeley uudecode file, which may be used in build process of any version) uudecode.c (file for VMS version) tclib.c (file for MSDOS, OS/2, and VMS versions) termcap (lex/yacc output for special level and dungeon compilers) dgn_comp.h dgn_lex.c dgn_yacc.c lev_comp.h lev_lex.c lev_yacc.c (posix regex for versions that include regex in their C library) posixregex.c (c++ regex code for versions that can build a C++ module and link it in) cppregex.cpp (pmatch regex for other versions) pmatchregex.c sys/share/sounds: (files for Amiga and Macintosh versions) README bell.uu bugle.uu erthdrum.uu firehorn.uu frsthorn.uu lethdrum.uu mgcflute.uu mgcharp.uu toolhorn.uu wdnflute.uu wdnharp.uu sys/unix: (files for UNIX versions) Install.unx Makefile.dat Makefile.doc Makefile.src Makefile.top Makefile.utl README.linux depend.awk mkmkfile.sh nethack.sh NewInstall.unx setup.sh sysconf unixmain.c unixres.c unixunix.c (files for replacement cpp, only needed by some ancient UNIX systems) cpp1.shr cpp2.shr cpp3.shr (file for sound driver for 386 UNIX) snd86unx.shr sys/unix/hints: (files for configuring UNIX NetHack versions) linux linux-chroot linux-x11 macosx macosx10.5 macosx10.7 macosx.sh macosx10.10 unix sys/vms: (files for VMS version) Install.vms Makefile.dat Makefile.doc Makefile.src Makefile.top Makefile.utl install.com lev_lex.h nethack.com oldcrtl.c spec_lev.com sysconf vmsbuild.com vmsfiles.c vmsmail.c vmsmain.c vmsmisc.c vmstty.c vmsunix.c sys/wince: (files for Windows CE and PocketPC - untested for 3.6.0) Install.ce bootstrp.mak celib.c cesetup.bat cesound.c defaults.nh keypad.uu menubar.uu mhaskyn.c mhaskyn.h mhcmd.c mhcmd.h mhcolor.c mhcolor.h mhdlg.c mhdlg.h mhfont.c mhfont.h mhinput.c mhinput.h mhmain.c mhmain.h mhmap.c mhmap.h mhmenu.c mhmenu.h mhmsg.h mhmsgwnd.c mhmsgwnd.h mhrip.c mhrip.h mhstatus.c mhstatus.h mhtext.c mhtext.h mhtxtbuf.c mhtxtbuf.h mswproc.c newres.h nhico.uu resource.h winMS.h winhack.c winhack.rc winhcksp.rc winmain.c sys/wince/ceinc: (header files for Windows CE and PocketPC - untested for 3.6.0) assert.h errno.h fcntl.h sys/wince/ceinc/sys: (sys/stat.h for Windows CE and PocketPC - untested for 3.6.0) stat.h sys/winnt: (files for Windows 7/8.x/10 version) Install.nt Makefile.gcc Makefile.msc console.rc defaults.nh nethack.def nh340key.c nhdefkey.c nhico.uu nhraykey.c nhsetup.bat ntsound.c nttty.c porthelp stubs.c sysconf win32api.h winnt.c util: (files for all versions) dgn_main.c dlb_main.c lev_main.c makedefs.c mdgrep.h mdgrep.pl panic.c recover.c (lex/yacc input for special level and dungeon compilers) dgn_comp.l dgn_comp.y lev_comp.l lev_comp.y win/Qt: (files for the Qt widget library - X11, Windows, Mac OS X, or Qtopia) Info.plist Install.Qt knethack.lnk knh-mini.xpm knh.xpm nhicns.uu nhsplash.xpm qt_clust.cpp qt_win.cpp qttableview.cpp tileedit.cpp tileedit.h qpe-nethack.control win/X11: (files for X versions) Install.X11 NetHack.ad Window.c dialogs.c ibm.bdf nethack.rc nh10.bdf nh32icon nh56icon nh72icon nh_icon.xpm pet_mark.xbm pilemark.xbm rip.xpm tile2x11.c winX.c winmap.c winmenu.c winmesg.c winmisc.c winstat.c wintext.c winval.c win/chain: (files for stacking window systems) wc_chainin.c wc_chainout.c wc_trace.c win/gem: (files for GEM versions - untested for 3.6.0) Install.gem bitmfile.c gem_rsc.uu gem_rso.uu gr_rect.c gr_rect.h load_img.c tile2img.c title.uu wingem.c wingem1.c xpm2img.c win/gnome: (files for GNOME versions - untested for 3.6.0) README gn_xpms.h gnaskstr.c gnaskstr.h gnbind.c gnbind.h gnglyph.c gnglyph.h gnmain.c gnmain.h gnmap.c gnmap.h gnmenu.c gnmenu.h gnmesg.c gnmesg.h gnomeprv.h gnopts.c gnopts.h gnplayer.c gnplayer.h gnsignal.c gnsignal.h gnstatus.c gnstatus.h gntext.c gntext.h gnworn.c gnworn.h gnyesno.c gnyesno.h mapbg.xpm win/macosx: (files for macosx versions) NetHackGuidebook.applescript NetHackRecover.applescript NetHackTerm.applescript recover.pl win/share: (files for versions using optional tiles) gifread.c monsters.txt objects.txt other.txt ppmwrite.c renumtiles.pl thintile.c tile.doc tile.h tile2bmp.c tilemap.c tiletext.c win/tty: (files for tty versions) getline.c termcap.c topl.c wintty.c win/win32: (files for Windows Windows 200x, Windows XP and Windows 7 version) mhaskyn.c mhaskyn.h mhdlg.c mhdlg.h mhfont.c mhfont.h mhinput.c mhinput.h mhmain.c mhmain.h mhmap.c mhmap.h mhmenu.c mhmenu.h mhmsg.h mhmsgwnd.c mhmsgwnd.h mhrip.c mhrip.h mhsplash.c mhsplash.h mhstatus.c mhstatus.h mhtext.c mhtext.h mnsel.uu mnselcnt.uu mnunsel.uu mswproc.c petmark.uu pilemark.uu resource.h rip.uu splash.uu tiles.mak winMS.h winhack.c winhack.rc win/win32/vs2010: (files for Visual Studio 2010 Express Edition builds) dgncomp.vcxproj dgnstuff.vcxproj dlb_main.vcxproj levcomp.vcxproj levstuff.vcxproj makedefs.vcxproj NetHack.sln NetHackW.vcxproj recover.vcxproj tile2bmp.vcxproj tilemap.vcxproj tiles.vcxproj uudecode.vcxproj win/win32/vs2013: (files for Visual Studio 2013 Express Edition builds) dgncomp.vcxproj dgnstuff.vcxproj dlb_main.vcxproj levcomp.vcxproj levstuff.vcxproj makedefs.vcxproj NetHack.sln NetHack.vcxproj NetHackW.vcxproj nhdefkey.vcxproj recover.vcxproj tile2bmp.vcxproj tilemap.vcxproj tiles.vcxproj uudecode.vcxproj This is a list of files produced by auxiliary programs. They can all be regenerated from the files in the distribution. dat: (files generated by makedefs at playground creation time) data dungeon.pdf options oracles quest.dat rumors (file generated by dgn_comp at playground creation time) dungeon (files generated by lev_comp at playground creation time) Arc-fila.lev Arc-filb.lev Arc-goal.lev Arc-loca.lev Arc-strt.lev Bar-fila.lev Bar-filb.lev Bar-goal.lev Bar-loca.lev Bar-strt.lev Cav-fila.lev Cav-filb.lev Cav-goal.lev Cav-loca.lev Cav-strt.lev Hea-fila.lev Hea-filb.lev Hea-goal.lev Hea-loca.lev Hea-strt.lev Kni-fila.lev Kni-filb.lev Kni-goal.lev Kni-loca.lev Kni-strt.lev Mon-fila.lev Mon-filb.lev Mon-goal.lev Mon-loca.lev Mon-strt.lev Pri-fila.lev Pri-filb.lev Pri-goal.lev Pri-loca.lev Pri-strt.lev Ran-fila.lev Ran-filb.lev Ran-goal.lev Ran-loca.lev Ran-strt.lev Rog-fila.lev Rog-filb.lev Rog-goal.lev Rog-loca.lev Rog-strt.lev Sam-fila.lev Sam-filb.lev Sam-goal.lev Sam-loca.lev Sam-strt.lev Tou-fila.lev Tou-filb.lev Tou-goal.lev Tou-loca.lev Tou-strt.lev Val-fila.lev Val-filb.lev Val-goal.lev Val-loca.lev Val-strt.lev Wiz-fila.lev Wiz-filb.lev Wiz-goal.lev Wiz-loca.lev Wiz-strt.lev air.lev asmodeus.lev astral.lev baalz.lev bigrm-1.lev bigrm-2.lev bigrm-3.lev bigrm-4.lev bigrm-5.lev castle.lev earth.lev fakewiz1.lev fakewiz2.lev fire.lev juiblex.lev knox.lev medusa-1.lev medusa-2.lev minefill.lev minend-1.lev minend-2.lev minend-3.lev minetn-1.lev minetn-2.lev minetn-3.lev minetn-4.lev minetn-5.lev minetn-6.lev minetn-7.lev oracle.lev orcus.lev sanctum.lev soko1-1.lev soko1-2.lev soko2-1.lev soko2-2.lev soko3-1.lev soko3-2.lev soko4-1.lev soko4-2.lev tower1.lev tower2.lev tower3.lev valley.lev water.lev wizard1.lev wizard2.lev wizard3.lev (tile files optionally generated for X ports at playground creation time) pet_mark.xbm rip.xpm x11tiles (files generated for Qt interface on Mac OS X) nethack.icns Info.plist (files generated for win32 at compile time) porthelp dlb.lst (files generated for win32 tty at compile time) ttyoptions (files generated for win32 gui at compile time) guioptions include: (files generated by makedefs at compile time) date.h onames.h pm.h vis_tab.h (files generated by yacc (or copied from sys/share) at compile time) dgn_comp.h lev_comp.h (file for tiles support copied from win/share at compile time) tile.h (files for win32 that are moved into include at compile time) win32api.h src: (files generated by makedefs at compile time) monstr.c vis_tab.c (file optionally generated by tilemap at compile time) tile.c (files generated by 'moc' for Qt interface at compile time) qt_kde0.moc qt_win.moc qttableview.moc (files for win32 that are moved into src at compile time) Makefile Makefile.bcc Makefile.gcc sys/winnt: (files generated by uudecode at compile time) nethack.ico util: (files generated by lex and yacc (or copied from sys/share) at compile time) dgn_lex.c dgn_yacc.c lev_lex.c lev_yacc.c (file generated for unix at compile time if various tiles utilities are built) tiletxt.c (files generated for win32 at compile time) uudecode.exe DEVEL: (files for people developing changes to NetHack) code_features.txt code_style.txt Developer.txt git_recipes.txt nhgitset.pl DEVEL/DOTGIT: TARGET DEVEL/hooksdir: applypatch-msg commit-msg NHadd NHgithook.pm nhsub NHsubst NHtext post-applypatch post-checkout post-commit post-merge post-rewrite pre-applypatch pre-auto-gc pre-commit pre-push pre-rebase prepare-commit-msg TARGET .: (files for win32 that are moved into . at compile time) NetHack.dsw NOTE: If your binaries were compiled with the data librarian (DLB) option, your playground will not contain all of the files listed here. All of the files listed as being required for the playground must still have been built by your compiler, but the DLB code will roll them up into another file (or files). nethack-3.6.0/Porting0000664000076400007660000001630512615610375013515 0ustar paxedpaxed NetHack Porting Guidelines v 3.6 1999-11-29 1.0 Introduction This document goes through the steps required to port NetHack to a new machine. The basic steps in porting the program are: 1. Get the code onto your machine. The parts of the current directory setup you definitely need include src (NetHack code shared by all systems), include (include files), util (code for utility programs), and dat (various data files). The documentation in doc is strongly recommended. You already have the files in the top directory since you're reading this one. :-) A full list of the distribution files and their associated OSes may be found in the top-level file "Files". If your machine uses an OS already supported, you need the sys subdirectory for that OS and possibly sys/share. Otherwise, get the closest match (say sys/msdos for single-tasking OSes and sys/unix for multi-user OSes, along with sys/share, if nothing else comes to mind). You may want others for comparison. If your machine uses a windowing system already supported, you need the win subdirectory for that system (or the appropriate sys subdirectory if the windowing system was previously considered restricted to one OS) and possibly win/share. 2. Modify the appropriate include files to customize NetHack to your system. You may need to add a new OS-specific "*conf.h" file (see unixconf.h, pcconf.h, tosconf.h, etc. as examples). 3. If your machine uses a new OS instead of a variant of existing OSes, add a new sys subdirectory. Add, if required, a OS- specific copy of "main.c", "tty.c" and "unix.c". Possibly add an OS-specific library (see "msdos.c" and "tos.c" as examples) to provide functions NetHack wants and your OS lacks. 4. If your machine uses a new windowing system, follow doc/window.doc carefully. Put files implementing these routines in a win or sys subdirectory as appropriate. 5. If your compilation environment isn't close to one already supported, try starting from the UNIX makefiles. Modify the top level makefile and the src makefile as required. Then run an initial compile. You are bound to get some errors. You should be able to fix them in a fairly simple fashion. If things seem to be getting too complex, take a step back, and possibly send us some mail. We might be able to help. 6. Mail all of your fixes to us in a contextual form so that we can easily integrate them into the code. One general rule of thumb exists. Always add code. Don't delete somebody else's code for yours -- it won't work on their machine if you do. Always add your OS specific code inside #ifdef / #else / #endif constructs so that it will be able to be folded back into the original code easily. 2.0 Include Files 2.1 config.h The file "config.h" is a master configuration file that determines the basic features of the game, as well as many of the security options. It is intended that end users configure the game by editing "config.h" and an appropriate "*conf.h" file, so any #defines for individual preferences should be added to those files. OS-specific #defines that are not intended to be changed should also go in "*conf.h"; try to find the most appropriate place for other #defines. The following sections may require modification: - Section 1: OS and window system selection. You may have to put a #define for your OS here. If your OS is yet another UNIX variant, put the #define in unixconf.h instead. An unfortunately large amount of stuff shares this section because the #definitions have to be seen before *conf.h is reached. Don't add to this unless necessary. - Section 2: Global parameters and filenames. These will have to be customized to your system. - Section 3: Type definitions and other compiler behavior. These will have to be matched to your compiler. 2.2 global.h This file defines things specific to NetHack that should not require modification by an end user. For a new port, you may have to add automatic inclusion of another auxiliary config file (*conf.h) which you wrote for your system. 2.3 extern.h If you create any new source modules or new functions in old modules, you must enter the names of the new external references (the functions defined there for external use) in this file. 2.4 system.h This file contains references for all hooks into the OS (via the standard "C" libraries). Depending on what your standard library looks like, you may have to put new entries into this file. 3.0 Source files The first step in getting the game up is to get the "makedefs" program running. This program is used to create configuration-specific files for the game. Once "makedefs" has been built, the rest of the game can be compiled. You may have to create an OS-specific module to handle things you want to use, like a mouse or a ram-disk. The utility compilers "dgn_comp" and "lev_comp" may be a better place to start. They also require "makedefs" but are independent of "nethack". They are usually the last programs made, but since they are much smaller they may be more tractable when first arguing with the include files. These programs create binary data files that "nethack" uses to guide its dungeon creation. 3.1 Makefiles This distribution provides makefiles for several kinds of systems. There are joint makefiles for the various varieties of UNIX, makefiles for MSDOS, a makefile for NT, and so on. You may have to create a new makefile for your specific machine. You may even have to translate some makefiles into a form more congenial to your system. If possible, however, add to one of those provided. 3.2 termcap.c If your system wants to use tty windowing and it doesn't run off of a termcap or terminfo database, you may have to put the appropriate terminal control strings into termcap.c. This has already been done for MSDOS, and these mods can be used as an example. You can also consider using the termcap code from sys/share/tclib.c or sys/share/termcap.uu, especially if your system supports multiple kinds of terminals. 3.3 main.c You may need to create a new "main.c" module. If you do, call it [OS]main.c where the [OS] is replaced with the name of the OS you are porting to. This file contains the mainline module, which reads options from the command line (or wherever) and processes them. It also contains various functions associated with game startup. 3.4 tty.c You may need to create a new "tty.c" module. If you do, call it [OS]tty.c where the [OS] is replaced with the name of the OS you are porting to. This file contains the routines that configure the terminal/console for raw I/O, etc. 3.5 unix.c You may need to create a new "unix.c" module. If you do, call it [OS]unix.c where the [OS] is replaced with the name of the OS you are porting to. This file contains some OS dependencies concerning time and filename creation. An object of the NetHack development project is to get the game working on as many different types of hardware and under as many different operating systems as is practical. Any assistance will be appreciated. nethack-3.6.0/README0000664000076400007660000001702112631241231013011 0ustar paxedpaxed NetHack 3.6.0 -- General information NetHack 3.6 is an enhancement to the dungeon exploration game NetHack. It is a distant descendent of Rogue and Hack, and a direct descendent of NetHack 3.4. In order to avoid confusion with interim development code that was posted online in 2014 by others, there is no NetHack 3.5 release. NetHack 3.6.0 contains some code reorganization, new features, and bugfixes. The file doc/fixes36.0 in the source distribution has a full list of each. The text in there was written for the development team's own use and is provided "as is", so please do not ask us to further explain the entries in that file. Some entries might be considered "spoilers", particularly in the "new features" section. Here are some additional general notes that are not considered spoilers: * Some code paths and long-established game features have been made part of the base build and no longer conditional on compile settings. * Several treasured NetHack community patches, or a variation of them, have been rolled in to the base NetHack source tree, incuding: menucolors, pickup thrown, statue glyphs, dungeon overview, sortloot. - - - - - - - - - - - Please read items (1), (2) and (3) BEFORE doing anything with your new code. 1. Unpack the code in a dedicated new directory. We will refer to that directory as the 'Top' directory. It makes no difference what you call it. 2. Having unpacked, you should have a file called 'Files' in your Top directory. This file contains the list of all the files you now SHOULD have in each directory. Please check the files in each directory against this list to make sure that you have a complete set. This file also contains a list of what files are created during the build process. The names of the directories listed should not be changed unless you are ready to go through the makefiles and the makedefs program and change all the directory references in them. 3. Before you do anything else, please read carefully the file called "license" in the 'dat' subdirectory. It is expected that you comply with the terms of that license, and we are very serious about it. 4. If everything is in order, you can now turn to trying to get the program to compile and run on your particular system. It is worth mentioning that the default configuration is SysV/Sun/Solaris2.x (simply because the code was housed on such a system). The files sys/*/Install.* were written to guide you in configuring the program for your operating system. The files win/*/Install.* are available, where necessary, to help you in configuring the program for particular windowing environments. Reading them, and the man pages, should answer most of your questions. At the time of this release, NetHack 3.6 has been tested to run/compile on: Intel Pentium or better (or clone) running Linux, BSDI, or Windows (7 through 10) Intel 80386 or greater (or clone) boxes running Linux, or BSDI Mac OS X 10.9 OpenVMS (aka VMS) V8.4 on Alpha and on Integrity/Itanium/IA64 Previous versions of NetHack were tested and known to run on the following systems, but it is unknown if they can still build and execute NetHack 3.6: Apple Macintosh running MacOS 7.5 or higher, LinuxPPC, BeOS 4.0 Atari ST/TT/Falcon running TOS (or MultiTOS) with GCC AT&T 3B1 running System V (3.51) AT&T 3B2/600 & 3B2/622 running System V R3.2.1 AT&T 3B2/1000 Model 80 running System V R3.2.2 AT&T 3B4000 running System V AT&T 6386 running System V R3.2 Commodore Amiga running AmigaDOS 3.0 or higher with SAS/C 6.x (but see Makefile.ami about DICE and Manx) Data General AViiON systems running DG/UX DEC Alpha/VMS (aka OpenVMS AXP), running V1.x through V7.1 DEC VAX/VMS, running V4.6 through V7.1 DEC vaxen running BSD, Ultrix Decstations running Ultrix 3.1, 4.x Encore Multimax running UMAX 4.2 Gould NP1 running UTX 3/2 HP 9000s300 running HP-UX HP 9000s700 running HP-UX 9.x, 10.x, 11.x H/PC Pro devices running Windows CE 2.11 and higher. IBM PC/RT and RS/6000 running AIX 3.x IBM PS/2 and AT compatibles running OS/2 - 2.0 and up with GCC emx IBM PS/2 and AT compatibles running OS/2 1.1 - 2.0 (and probably Warp) with Microsoft 6.0, and OS/2 2.0 and up with IBM CSet++ 2.0. Intel 80386 or greater (or clone) running 386BSD Intel 80386 or greater (or clone) boxes running MS-DOS with DPMI. Intel x86 running a version of Windows prior to XP. Mips M2000 running RiscOS 4.1 NeXT running Mach (using BSD configuration) Palm Size PC 1.1 devices running Windows CE 2.11 Pocket PC devices running Windows CE 3.0 and higher Pyramid 9820x running OSx 4.4c SGI Iris running IRIX Stardent Vistra 800 running SysV R4.0 Stride 460 running UniStride 2.1 Sun-3s, -4s, and -386is running SunOS 3.x Sun-3s and -386is running SunOS 4.x Sun SPARC based machine running SunOS 4.x, Solaris 2.x, or Solaris 7 Valid Logic Systems SCALD-System Previous versions, using a cross-compiler hosted on another platform, such as win32, could also build the following from source: Pocket PC devices running Windows CE 3.0 and higher H/PC Pro devices running Windows CE 2.11 and higher Palm Size PC 1.1 devices running Windows CE 2.11 Unless otherwise mentioned, the compiler used was the OS-vendor's C compiler. - - - - - - - - - - - If you have problems building the game, or you find bugs in it, we recommend filing a bug report from our "Contact Us" web page at: http://www.nethack.org/ A public repository of the latest NetHack code that we've made available can be obtained via git here: When sending correspondence, please observe the following: o Please be sure to include your machine type, OS, and patchlevel. o Please avoid sending us binary files (e.g. save files or bones files). If you have found a bug and think that your save file would aid in solving the problem, send us a description in words of the problem, your machine type, your operating system, and the version of NetHack. Tell us that you have a save file, but do not actually send it. You may then be contacted by a member of the development team with the address of a specific person to send the save file to. o Though we make an effort to reply to each bug report, it may take some time before you receive feedback. This is especially true during the period immediately after a new release, when we get the most bug reports. o We don't give hints for playing the game. o Don't bother to ask when the next version will be out or you can expect to receive a stock answer. If you want to submit a patch for the NetHack source code via email directly, you can direct it to this address: nethack-bugs (at) nethack.org If a feature is not accepted you are free, of course, to post the patches to the net yourself and let the marketplace decide their worth. All of this amounts to the following: If you decide to apply a free-lanced patch to your 3.6 code, you are welcome to do so, of course, but we won't be able to provide support or receive bug reports for it. In our own patches, we will assume that your code is synchronized with ours. -- Good luck, and happy Hacking -- nethack-3.6.0/dat/Arch.des0000664000076400007660000003507712536476415014310 0ustar paxedpaxed# NetHack 3.6 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Lord Carnarvon # and receive your quest assignment. # MAZE: "Arc-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ............................................................................ ....................}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}................. ....................}-------------------------------------}................. ....................}|..S......+.................+.......|}................. ....................}-S---------------+----------|.......|}................. ....................}|.|...............|.......+.|.......|}................. ....................}|.|...............---------.---------}................. ....................}|.S.\.............+.................+.................. ....................}|.|...............---------.---------}................. ....................}|.|...............|.......+.|.......|}................. ....................}-S---------------+----------|.......|}................. ....................}|..S......+.................+.......|}................. ....................}-------------------------------------}................. ....................}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}................. ............................................................................ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION: (22,06,23,06),unlit,"ordinary" REGION: (25,06,30,06),unlit,"ordinary" REGION: (32,06,48,06),unlit,"ordinary" REGION: (50,06,56,08),lit,"ordinary" REGION: (40,08,46,08),unlit,"ordinary" REGION: (22,08,22,12),unlit,"ordinary" REGION: (24,08,38,12),unlit,"ordinary" REGION: (48,08,48,08),lit,"ordinary" REGION: (40,10,56,10),lit,"ordinary" REGION: (48,12,48,12),lit,"ordinary" REGION: (40,12,46,12),unlit,"ordinary" REGION: (50,12,56,14),lit,"ordinary" REGION: (22,14,23,14),unlit,"ordinary" REGION: (25,14,30,14),unlit,"ordinary" REGION: (32,14,48,14),unlit,"ordinary" # Stairs STAIR:(55,07),down # Portal arrival point BRANCH:(63,06,63,06),(0,0,0,0) # Doors DOOR:closed,(22,07) DOOR:closed,(38,07) DOOR:locked,(47,08) DOOR:locked,(23,10) DOOR:locked,(39,10) DOOR:locked,(57,10) DOOR:locked,(47,12) DOOR:closed,(22,13) DOOR:closed,(38,13) DOOR:locked,(24,14) DOOR:closed,(31,14) DOOR:locked,(49,14) # Lord Carnarvon MONSTER:('@',"Lord Carnarvon"),(25,10) # The treasure of Lord Carnarvon OBJECT:('(',"chest"),(25,10) # student guards for the audience chamber MONSTER:('@',"student"),(26,09) MONSTER:('@',"student"),(27,09) MONSTER:('@',"student"),(28,09) MONSTER:('@',"student"),(26,10) MONSTER:('@',"student"),(28,10) MONSTER:('@',"student"),(26,11) MONSTER:('@',"student"),(27,11) MONSTER:('@',"student"),(28,11) # city watch guards in the antechambers MONSTER:('@',"watchman"),(50,06) MONSTER:('@',"watchman"),(50,14) # Eels in the moat MONSTER:(';',"giant eel"),(20,10) MONSTER:(';',"giant eel"),(45,04) MONSTER:(';',"giant eel"),(33,16) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'S',(60,09) MONSTER: 'M',(60,10) MONSTER: 'S',(60,11) MONSTER: 'S',(60,12) MONSTER: 'M',(60,13) MONSTER: 'S',(61,10) MONSTER: 'S',(61,11) MONSTER: 'S',(61,12) MONSTER: 'S',(30,03) MONSTER: 'M',(20,17) MONSTER: 'S',(67,02) MONSTER: 'S',(10,19) # # The "locate" level for the quest. # # Here you have to find the Entrance to the Tomb of the Toltec Kings # to go further towards your assigned quest. # MAZE: "Arc-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ........................-------------------------------..................... ........................|....|.S......................|..................... ........................|....|.|.|+------------------.|..................... ........................|....|.|.|.|.........|......|.|..................... ........................|....|.|.|.|.........|......|.|..................... ........................|---+-.|.|.|..---....+......|.|..................... ........................|....|.|.|.---|.|....|......|.|..................... ........................|....S.|.|.+..S.|--S-----S--|.|..................... ........................|....|.|.|.---|.|....|......+.|..................... ........................|---+-.|.|.|..---....|.------.|..................... ........................|....|.|.|.|.........|.|....+.|..................... ........................|....|.|.|.|.........|+|....|-|..................... ........................|....|.|.|------------+------.S..................... ........................|....|.S......................|..................... ........................-------------------------------..................... ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(25,04,28,07),lit,"temple" REGION:(25,09,28,11),unlit,"temple" REGION:(25,13,28,16),lit,"temple" REGION:(30,04,30,16),lit,"ordinary" REGION:(32,04,32,16),unlit,"ordinary" REGION:(33,04,53,04),unlit,"ordinary",unfilled,irregular REGION:(36,10,37,10),unlit,"ordinary" REGION:(39,09,39,11),unlit,"ordinary" REGION:(36,06,42,08),unlit,"ordinary",unfilled,irregular REGION:(36,12,42,14),unlit,"ordinary",unfilled,irregular REGION:(46,06,51,09),unlit,"ordinary" REGION:(46,11,49,11),unlit,"ordinary",unfilled,irregular REGION:(48,13,51,14),unlit,"ordinary" # Doors DOOR:closed,(31,04) DOOR:closed,(28,08) DOOR:locked,(29,10) DOOR:closed,(28,12) DOOR:closed,(31,16) DOOR:locked,(34,05) DOOR:locked,(35,10) DOOR:locked,(38,10) DOOR:closed,(43,10) DOOR:closed,(45,08) DOOR:locked,(46,14) DOOR:locked,(46,15) DOOR:locked,(49,10) DOOR:locked,(52,11) DOOR:closed,(52,13) DOOR:closed,(54,15) # Stairs STAIR:(03,17),up STAIR:(39,10),down # Altars - three types. All are unattended. ALTAR:(26,05),align[0],altar ALTAR:(26,10),align[1],altar ALTAR:(26,15),align[2],altar # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Treasure? ENGRAVING:random,engrave,"X marks the spot." ENGRAVING:random,engrave,"X marks the spot." ENGRAVING:random,engrave,"X marks the spot." ENGRAVING:random,engrave,"X marks the spot." # Random traps TRAP:"spiked pit",(24,02) TRAP:"spiked pit",(37,00) TRAP:"spiked pit",(23,05) TRAP:"spiked pit",(26,19) TRAP:"spiked pit",(55,10) TRAP:"spiked pit",(55,08) TRAP:"pit",(51,01) TRAP:"pit",(23,18) TRAP:"pit",(31,18) TRAP:"pit",(48,19) TRAP:"pit",(55,15) TRAP:"magic",(60,04) TRAP:"statue",(72,07) TRAP:"statue",random TRAP:"statue",random TRAP:"anti magic",(64,12) TRAP:"sleep gas",random TRAP:"sleep gas",random TRAP:"dart",random TRAP:"dart",random TRAP:"dart",random TRAP:"rolling boulder",(32,10) TRAP:"rolling boulder",(40,16) # Random monsters. MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'M',random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:'M',random # # The "goal" level for the quest. # # Here you meet Minion of Huhetotl your nemesis monster. You have to # defeat Minion of Huhetotl in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Arc-goal", ' ' GEOMETRY:center,center MAP --------- |..|.|..| -----------|..S.S..|----------- |.|........|+-|.|-+|........|.| |.S........S..|.|..S........S.| |.|........|..|.|..|........|.| ------------------+------------------ |..|..........|.......|..........|..| |..|..........+.......|..........S..| |..S..........|.......+..........|..| |..|..........|.......|..........|..| ------------------+------------------ |.|........|..|.|..|........|.| |.S........S..|.|..S........S.| |.|........|+-|.|-+|........|.| -----------|..S.S..|----------- |..|.|..| --------- ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(35,02,36,03),unlit,"ordinary" REGION:(40,02,41,03),unlit,"ordinary" REGION:(24,04,24,06),unlit,"ordinary" REGION:(26,04,33,06),lit,"ordinary" REGION:(38,02,38,06),unlit,"ordinary" REGION:(43,04,50,06),lit,"ordinary" REGION:(52,04,52,06),unlit,"ordinary" REGION:(35,05,36,06),unlit,"ordinary" REGION:(40,05,41,06),unlit,"ordinary" REGION:(21,08,22,11),unlit,"ordinary" REGION:(24,08,33,11),lit,"ordinary" REGION:(35,08,41,11),unlit,"ordinary" REGION:(43,08,52,11),lit,"ordinary" REGION:(54,08,55,11),unlit,"ordinary" REGION:(24,13,24,15),unlit,"ordinary" REGION:(26,13,33,15),unlit,"ordinary" REGION:(35,13,36,14),unlit,"ordinary" REGION:(35,16,36,17),unlit,"ordinary" REGION:(38,13,38,17),unlit,"ordinary" REGION:(40,13,41,14),unlit,"ordinary" REGION:(40,16,41,17),unlit,"ordinary" REGION:(43,13,50,15),unlit,"temple" REGION:(52,13,52,15),unlit,"ordinary" # Stairs STAIR:(38,10),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # The altar of Huhetotl. Unattended. ALTAR:(50,14),chaos,altar # Objects OBJECT:('(',"crystal ball"),(50,14),blessed,5,name:"The Orb of Detection" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:"rolling boulder",(46,14) # Random monsters. MONSTER:('&',"Minion of Huhetotl"),(50,14) MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:'S',random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:('M',"human mummy"),random MONSTER:'M',random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # LEVEL: "Arc-fila" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: 'S', random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: 'S', random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: 'S', random } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: 'S', random MONSTER: ('M', "human mummy"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: 'S', random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: 'S', random } RANDOM_CORRIDORS LEVEL: "Arc-filb" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: 'M', random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: 'M', random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: 'M', random } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: 'S', random MONSTER: ('M', "human mummy"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: 'S', random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: 'S', random } RANDOM_CORRIDORS nethack-3.6.0/dat/Barb.des0000664000076400007660000003157712536476415014302 0ustar paxedpaxed# NetHack 3.6 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Pelias, # and receive your quest assignment. # MAZE: "Bar-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ..................................PP........................................ ...................................PP....................................... ...................................PP....................................... ....................................PP...................................... ........--------------......-----....PPP.................................... ........|...S........|......+...|...PPP..................................... ........|----........|......|...|....PP..................................... ........|.\..........+......-----........................................... ........|----........|...............PP..................................... ........|...S........|...-----.......PPP.................................... ........--------------...+...|......PPPPP................................... .........................|...|.......PPP.................................... ...-----......-----......-----........PP.................................... ...|...+......|...+..--+--.............PP................................... ...|...|......|...|..|...|..............PP.................................. ...-----......-----..|...|.............PPPP................................. .....................-----............PP..PP................................ .....................................PP...PP................................ ....................................PP...PP................................. ....................................PP....PP................................ ENDMAP # the forest beyond the river REPLACE_TERRAIN:(37,0,59,19),'.','T', 5% REPLACE_TERRAIN:(60,0,64,19),'.','T', 10% REPLACE_TERRAIN:(65,0,75,19),'.','T', 20% # guarantee a path and free spot for the portal TERRAIN:(randline (37,7),(62,02),7), '.' TERRAIN:(62,02),'.' # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(09,05,11,05),unlit,"ordinary" REGION:(09,07,11,07),lit,"ordinary" REGION:(09,09,11,09),unlit,"ordinary" REGION:(13,05,20,09),lit,"ordinary" REGION:(29,05,31,06),lit,"ordinary" REGION:(26,10,28,11),lit,"ordinary" REGION:(04,13,06,14),lit,"ordinary" REGION:(15,13,17,14),lit,"ordinary" REGION:(22,14,24,15),lit,"ordinary" # Stairs STAIR:(09,09),down # Portal arrival point BRANCH:(62,02,62,02),(0,0,0,0) # Doors DOOR:locked,(12,05) DOOR:locked,(12,09) DOOR:closed,(21,07) DOOR:open,(07,13) DOOR:open,(18,13) DOOR:open,(23,13) DOOR:open,(25,10) DOOR:open,(28,05) # Elder MONSTER:('@',"Pelias"),(10,07) # The treasure of Pelias OBJECT:('(',"chest"),(09,05) # chieftain guards for the audience chamber MONSTER:('@',"chieftain"),(10,05) MONSTER:('@',"chieftain"),(10,09) MONSTER:('@',"chieftain"),(11,05) MONSTER:('@',"chieftain"),(11,09) MONSTER:('@',"chieftain"),(14,05) MONSTER:('@',"chieftain"),(14,09) MONSTER:('@',"chieftain"),(16,05) MONSTER:('@',"chieftain"),(16,09) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # One trap to keep the ogres at bay. TRAP:"spiked pit",(37,07) # Eels in the river MONSTER:(';',"giant eel"),(36,01) MONSTER:(';',"giant eel"),(37,09) MONSTER:(';',"giant eel"),(39,15) # Monsters on siege duty. MONSTER:('O',"ogre"),(40,08),hostile MONSTER:('O',"ogre"),(41,06),hostile MONSTER:('O',"ogre"),(41,07),hostile MONSTER:('O',"ogre"),(41,08),hostile MONSTER:('O',"ogre"),(41,09),hostile MONSTER:('O',"ogre"),(41,10),hostile MONSTER:('O',"ogre"),(42,06),hostile MONSTER:('O',"ogre"),(42,07),hostile MONSTER:('O',"ogre"),(42,08),hostile MONSTER:('O',"ogre"),(42,09),hostile MONSTER:('O',"ogre"),(42,10),hostile # # The "locate" level for the quest. # # Here you have to infiltrate the Duali Oasis to go # further towards your assigned quest. # MAZE: "Bar-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ..........PPP......................................... ...........PP.......................................... ....... ..........PP...........-----..........------------------ .......... ...........PP..........+...|..........|....S...........|.. ............ ..........PPP..........|...|..........|-----...........|... ............. ...........PPP.........-----..........+....+...........|... ............. ..........PPPPPPPPP...................+....+...........S................. ........PPPPPPPPPPPPP.........-----...|-----...........|................ ......PPPPPPPPPPPPPP..P.......+...|...|....S...........| ... .....PPPPPPP......P..PPPP.....|...|...------------------.. ... ....PPPPPPP.........PPPPPP....-----........................ ........ ...PPPPPPP..........PPPPPPP.................................. .......... ....PPPPPPP........PPPPPPP.................................... .......... .....PPPPP........PPPPPPP.........-----........................ ........ ......PPP..PPPPPPPPPPPP...........+...|......................... ..... ..........PPPPPPPPPPP.............|...|......................... .... ..........PPPPPPPPP...............-----......................... . ..............PPP................................................. ...............PP.................................................... ................PPP................................................... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(24,03,26,04),unlit,"ordinary" REGION:(31,08,33,09),unlit,"ordinary" REGION:(35,14,37,15),unlit,"ordinary" REGION:(39,03,54,08),lit,"ordinary" REGION:(56,00,75,08),unlit,"ordinary" REGION:(64,09,75,16),unlit,"ordinary" # Doors DOOR:open,(23,03) DOOR:open,(30,08) DOOR:open,(34,14) DOOR:locked,(38,05) DOOR:locked,(38,06) DOOR:closed,(43,03) DOOR:closed,(43,05) DOOR:closed,(43,06) DOOR:closed,(43,08) DOOR:locked,(55,06) # Stairs STAIR:(05,02),up STAIR:(70,13),down # Objects OBJECT:random,(42,03) OBJECT:random,(42,03) OBJECT:random,(42,03) OBJECT:random,(41,03) OBJECT:random,(41,03) OBJECT:random,(41,03) OBJECT:random,(41,03) OBJECT:random,(41,08) OBJECT:random,(41,08) OBJECT:random,(42,08) OBJECT:random,(42,08) OBJECT:random,(42,08) OBJECT:random,(71,13) OBJECT:random,(71,13) OBJECT:random,(71,13) # Random traps TRAP:"spiked pit",(10,13) TRAP:"spiked pit",(21,07) TRAP:"spiked pit",(67,08) TRAP:"spiked pit",(68,09) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('O',"ogre"),(12,09),hostile MONSTER:('O',"ogre"),(18,11),hostile MONSTER:('O',"ogre"),(45,05),hostile MONSTER:('O',"ogre"),(45,06),hostile MONSTER:('O',"ogre"),(47,05),hostile MONSTER:('O',"ogre"),(46,05),hostile MONSTER:('O',"ogre"),(56,03),hostile MONSTER:('O',"ogre"),(56,04),hostile MONSTER:('O',"ogre"),(56,05),hostile MONSTER:('O',"ogre"),(56,06),hostile MONSTER:('O',"ogre"),(57,03),hostile MONSTER:('O',"ogre"),(57,04),hostile MONSTER:('O',"ogre"),(57,05),hostile MONSTER:('O',"ogre"),(57,06),hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:'O',random,hostile MONSTER:'T',random,hostile MONSTER:('T',"rock troll"),(46,06),hostile MONSTER:('T',"rock troll"),(47,06),hostile MONSTER:('T',"rock troll"),(56,07),hostile MONSTER:('T',"rock troll"),(57,07),hostile MONSTER:('T',"rock troll"),(70,13),hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:'T',random,hostile # # The "goal" level for the quest. # # Here you meet Thoth Amon, your nemesis monster. You have to # defeat Thoth Amon in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Bar-goal", ' ' GEOMETRY:center,center MAP ............. .................. .... ......................... .... ....... .......................... ....... ...... ........................ ....... .. ...................................... .. .. ..................... .. .. .................. .. .. ..S...S.............. ................ .. ........ ... ......... .. ...... .. ... .... .. ... .. ...... ........ .... .. .................. ........ ...... ...... ...................... ...... .. .... .................. ........... .............. ........... ENDMAP # Dungeon Description REGION:(00,00,75,19),unlit,"ordinary" # Secret doors DOOR:locked,(22,09) DOOR:locked,(26,09) # Stairs STAIR:(36,05),up # The altar. Unattended. ALTAR:(63,04),noncoaligned,altar NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:('*',"luckstone"),(63,04),blessed,0,name:"The Heart of Ahriman" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"Thoth Amon"),(63,04),hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:('O',"ogre"),random,hostile MONSTER:'O',random,hostile MONSTER:'O',random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:('T',"rock troll"),random,hostile MONSTER:'T',random,hostile WALLIFY # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Bar-fila" , ' ' INIT_MAP: mines, '.' , '.' , true , true , unlit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: 'O', random, hostile MONSTER: ('T', "rock troll"), random, hostile MAZE: "Bar-filb" , ' ' INIT_MAP: mines, '.' , ' ' , true , true , unlit , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: ('O', "ogre"), random, hostile MONSTER: 'O' , random, hostile MONSTER: ('T', "rock troll"), random, hostile MONSTER: ('T', "rock troll"), random, hostile MONSTER: ('T', "rock troll"), random, hostile MONSTER: 'T' , random, hostile nethack-3.6.0/dat/Caveman.des0000664000076400007660000002650612536476415015002 0ustar paxedpaxed# NetHack 3.6 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Shaman Karnov # and receive your quest assignment. # MAZE: "Cav-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ...... .......................... ... .... ...... ...... .......................... ........ .... ..... ..BB ............................. ......... .... .. .. ...................... ....... .. .... .. .. .................... .. ....... .. ... .. S BB ..... ....... .... .... .. ... . .. ........ .. .. .. ... .. ...... .. ............ .. ... . .... .. ........ .. ........... ... .. .. ............. ................... ..... ..... ............................... ........... .....B................ ... ... ..... . .......... .... . ... .......... ... ... .. ............. .. ................... .... BB .. ......... BB ... .......... .. ... ... ...... ..... B ........ .. .. .... ... .......... .......... ..... ... ..... ........ .. ... . ..... .... .. ... .. ENDMAP # Dungeon Description REGION:(00,00,75,19),unlit,"ordinary" REGION:(13,01,40,05),lit,"temple",unfilled,irregular # The occupied rooms. REGION:(02,01,08,03),lit,"ordinary",unfilled,irregular REGION:(01,11,06,14),lit,"ordinary",unfilled,irregular REGION:(13,08,18,10),lit,"ordinary",unfilled,irregular REGION:(05,17,14,18),lit,"ordinary",unfilled,irregular REGION:(17,16,23,18),lit,"ordinary",unfilled,irregular REGION:(35,16,44,18),lit,"ordinary",unfilled,irregular # Stairs STAIR:(02,03),down # Portal arrival point BRANCH:(71,09,71,09),(0,0,0,0) # Doors DOOR:locked,(19,06) # The temple altar (this will force a priest(ess) to be created) ALTAR:(36,02),coaligned,shrine # Shaman Karnov MONSTER:('@',"Shaman Karnov"),(35,02) # The treasure of Shaman Karnov OBJECT:('(',"chest"),(34,02) # neanderthal guards for the audience chamber MONSTER:('@',"neanderthal"),(20,03) MONSTER:('@',"neanderthal"),(20,02) MONSTER:('@',"neanderthal"),(20,01) MONSTER:('@',"neanderthal"),(21,03) MONSTER:('@',"neanderthal"),(21,02) MONSTER:('@',"neanderthal"),(21,01) MONSTER:('@',"neanderthal"),(22,01) MONSTER:('@',"neanderthal"),(26,09) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:"pit",(47,11) TRAP:"pit",(57,10) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty (in the outer caves). MONSTER: ('h',"bugbear"),(47,02),hostile MONSTER: ('h',"bugbear"),(48,03),hostile MONSTER: ('h',"bugbear"),(49,04),hostile MONSTER: ('h',"bugbear"),(67,03),hostile MONSTER: ('h',"bugbear"),(69,04),hostile MONSTER: ('h',"bugbear"),(51,13),hostile MONSTER: ('h',"bugbear"),(53,14),hostile MONSTER: ('h',"bugbear"),(55,15),hostile MONSTER: ('h',"bugbear"),(63,10),hostile MONSTER: ('h',"bugbear"),(65,09),hostile MONSTER: ('h',"bugbear"),(67,10),hostile MONSTER: ('h',"bugbear"),(69,11),hostile WALLIFY # # The "locate" level for the quest. # # Here you have to find the lair of Tiamat to go # further towards your assigned quest. # MAZE: "Cav-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............. ........... ............... ............. ............. ............... .......... ........... ............. ............... ... ... .................. ... .......... ... .................. ... ............ BBB................... ... .......... ...................... ..... .. .....B........................ .... ............... . ........B.......................... ...... .. .............S.............. .................. .... .. ........... ............... .. ... .................... .... BB................... .. .. .. ............... .. ....... .... ..... .... .. ....... S ............ ....... .. ....... ..... ... .... ....... ..... ...... ....... ENDMAP # Dungeon Description REGION:(00,00,75,19),unlit,"ordinary" REGION:(52,06,73,15),lit,"ordinary",unfilled,irregular # Doors DOOR:locked,(28,11) # Stairs STAIR:(04,03),up STAIR:(73,10),down # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('h',"bugbear"),(02,10),hostile MONSTER:('h',"bugbear"),(03,11),hostile MONSTER:('h',"bugbear"),(04,12),hostile MONSTER:('h',"bugbear"),(02,11),hostile MONSTER:('h',"bugbear"),(16,16),hostile MONSTER:('h',"bugbear"),(17,17),hostile MONSTER:('h',"bugbear"),(18,18),hostile MONSTER:('h',"bugbear"),(19,16),hostile MONSTER:('h',"bugbear"),(30,06),hostile MONSTER:('h',"bugbear"),(31,07),hostile MONSTER:('h',"bugbear"),(32,08),hostile MONSTER:('h',"bugbear"),(33,06),hostile MONSTER:('h',"bugbear"),(34,07),hostile MONSTER:('h',"bugbear"),random,hostile MONSTER:('h',"bugbear"),random,hostile MONSTER:('h',"bugbear"),random,hostile MONSTER:('h',"bugbear"),random,hostile MONSTER:'h',random,hostile MONSTER:'H',random,hostile MONSTER:('H',"hill giant"),(03,12),hostile MONSTER:('H',"hill giant"),(20,17),hostile MONSTER:('H',"hill giant"),(35,08),hostile MONSTER:('H',"hill giant"),random,hostile MONSTER:('H',"hill giant"),random,hostile MONSTER:('H',"hill giant"),random,hostile MONSTER:('H',"hill giant"),random,hostile MONSTER:'H',random,hostile WALLIFY # # The "goal" level for the quest. # # Here you meet Tiamat your nemesis monster. You have to # defeat Tiamat in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Cav-goal", ' ' GEOMETRY:center,center MAP ..................... ....................... ......................... ........................... ............................. ............................... ................................. ................................... ..................................... ....................................... ..................................... ................................... ................................. ............................... ............................. ........................... ......................... ....................... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Stairs STAIR:random,up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:(')',"mace"),(23,10),blessed,0,name:"The Sceptre of Might" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # monsters. MONSTER:('D',"Chromatic Dragon"),(23,10),asleep MONSTER:('F',"shrieker"),(26,13) MONSTER:('F',"shrieker"),(25,8) MONSTER:('F',"shrieker"),(45,11) WALLIFY # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Cav-fila" , ' ' INIT_MAP: mines, '.' , ' ' , true , true , random , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: 'h', random, hostile MONSTER: ('H', "hill giant"), random, hostile MAZE: "Cav-filb" , ' ' INIT_MAP: mines, '.' , ' ' , true , true , random , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: ('h', "bugbear"), random, hostile MONSTER: 'h', random, hostile MONSTER: 'h', random, hostile MONSTER: ('H', "hill giant"), random, hostile MONSTER: ('H', "hill giant"), random, hostile nethack-3.6.0/dat/Healer.des0000664000076400007660000002521312536476415014622 0ustar paxedpaxed# NetHack 3.6 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991, 1993 by M. Stephenson, P. Winner # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Hippocrates # and receive your quest assignment. # MAZE: "Hea-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP PPPP........PPPP.....PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP.P..PPPPP......PPPPPPPP PPP..........PPPP...PPPPP.........................PPPP..PPPPP........PPPPPPP PP............PPPPPPPP..............................PPP...PPPP......PPPPPPPP P.....PPPPPPPPPPPPPPP................................PPPPPPPPPPPPPPPPPPPPPPP PPPP....PPPPPPPPPPPP...................................PPPPP.PPPPPPPPPPPPPPP PPPP........PPPPP.........-----------------------........PP...PPPPPPP.....PP PPP............PPPPP....--|.|......S..........S.|--.....PPPP.PPPPPPP.......P PPPP..........PPPPP.....|.S.|......-----------|S|.|......PPPPPP.PPP.......PP PPPPPP......PPPPPP......|.|.|......|...|......|.|.|.....PPPPPP...PP.......PP PPPPPPPPPPPPPPPPPPP.....+.|.|......S.\.S......|.|.+......PPPPPP.PPPP.......P PPP...PPPPP...PPPP......|.|.|......|...|......|.|.|.......PPPPPPPPPPP.....PP PP.....PPP.....PPP......|.|S|-----------......|.S.|......PPPPPPPPPPPPPPPPPPP PPP..PPPPP...PPPP.......--|.S..........S......|.|--.....PPPPPPPPP....PPPPPPP PPPPPPPPPPPPPPPP..........-----------------------..........PPPPP..........PP PPPPPPPPPPPPPPPPP........................................PPPPPP............P PPP.............PPPP...................................PPP..PPPP..........PP PP...............PPPPP................................PPPP...PPPP........PPP PPP.............PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP....PPPPPP PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP ENDMAP REPLACE_TERRAIN:(01,01,74,18), 'P', '.', 10% # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Stairs STAIR:(37,9),down # Portal arrival point BRANCH:(04,12,04,12),(0,0,0,0) # altar for the Temple ALTAR:(32,09),neutral,altar # Doors DOOR:locked,(24,10) DOOR:closed,(26,08) DOOR:closed,(27,12) DOOR:locked,(28,13) DOOR:closed,(35,07) DOOR:locked,(35,10) DOOR:locked,(39,10) DOOR:closed,(39,13) DOOR:locked,(46,07) DOOR:closed,(47,08) DOOR:closed,(48,12) DOOR:locked,(50,10) # Hippocrates MONSTER:('@',"Hippocrates"),(37,10) # The treasure of Hippocrates OBJECT:('(',"chest"),(37,10) # intern guards for the audience chamber MONSTER:('@',"attendant"),(29,08) MONSTER:('@',"attendant"),(29,09) MONSTER:('@',"attendant"),(29,10) MONSTER:('@',"attendant"),(29,11) MONSTER:('@',"attendant"),(40,09) MONSTER:('@',"attendant"),(40,10) MONSTER:('@',"attendant"),(40,11) MONSTER:('@',"attendant"),(40,13) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: ('r',"rabid rat"),random MONSTER: (';',"giant eel"),random MONSTER: (';',"shark"),random MONSTER: ';', random MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile # # The "locate" level for the quest. # # Here you have to find the Temple of Coeus to go # further towards your assigned quest. # MAZE: "Hea-loca",' ' FLAGS: hardfloor # INIT_MAP: mines, '.' , 'P', true , true , lit , false GEOMETRY:center,center MAP PPPPPPPPPPPPP.......PPPPPPPPPPP PPPPPPPP...............PPPPPPPP PPPP.....-------------...PPPPPP PPPPP....|.S.........|....PPPPP PPP......+.|.........|...PPPPPP PPP......+.|.........|..PPPPPPP PPPP.....|.S.........|..PPPPPPP PPPPP....-------------....PPPPP PPPPPPPP...............PPPPPPPP PPPPPPPPPPP........PPPPPPPPPPPP ENDMAP # Dungeon Description REGION:(00,00,30,09),lit,"ordinary" REGION:(12,03,20,06),lit,"temple" # Doors DOOR:closed,(09,04) DOOR:closed,(09,05) DOOR:locked,(11,03) DOOR:locked,(11,06) # Stairs STAIR:(04,04),up STAIR:(20,06),down # Non diggable walls NON_DIGGABLE:(11,02,21,07) # Altar in the temple. ALTAR:(13,05), chaos, shrine # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:'r',random,hostile MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"kraken"),random MONSTER:(';',"shark"),random MONSTER:(';',"shark"),random MONSTER:';', random,hostile MONSTER:';', random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile # # The "goal" level for the quest. # # Here you meet Cyclops your nemesis monster. You have to # defeat Cyclops in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Hea-goal", 'P' # INIT_MAP: mines, '.' , 'P' , false , true , lit , false GEOMETRY:center,center MAP .P....................................PP. PP.......PPPPPPP....PPPPPPP....PPPP...PP. ...PPPPPPP....PPPPPPP.....PPPPPP..PPP...P ...PP..............................PPP... ..PP..............................PP..... ..PP..............................PPP.... ..PPP..............................PP.... .PPP..............................PPPP... ...PP............................PPP...PP ..PPPP...PPPPP..PPPP...PPPPP.....PP...PP. P....PPPPP...PPPP..PPPPP...PPPPPPP...PP.. PPP..................................PPP. ENDMAP # Dungeon Description REGION:(00,00,40,11),lit,"ordinary" # Stairs STAIR:(39,10),up # Non diggable walls NON_DIGGABLE:(00,00,40,11) # Objects OBJECT:(')',"quarterstaff"),(20,06),blessed,0,name:"The Staff of Aesculapius" OBJECT:('/',"lightning"),(20,06) OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('H',"Cyclops"),(20,06),hostile MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:('r',"rabid rat"),random MONSTER:'r',random,hostile MONSTER:'r',random,hostile MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"shark"),random MONSTER:(';',"shark"),random MONSTER:';',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Hea-fila" , 'P' INIT_MAP: mines, '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('r', "rabid rat"), random MONSTER: 'r', random,hostile MONSTER: 'r', random,hostile MONSTER: (';', "giant eel"), random MONSTER: (';', "giant eel"), random MONSTER: (';', "electric eel"), random MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Hea-filb" , 'P' INIT_MAP: mines, '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('r', "rabid rat"), random MONSTER: ('r', "rabid rat"), random MONSTER: 'r', random,hostile MONSTER: 'r', random,hostile MONSTER: (';', "giant eel"), random MONSTER: (';', "giant eel"), random MONSTER: (';', "giant eel"), random MONSTER: (';', "giant eel"), random MONSTER: (';', "giant eel"), random MONSTER: (';', "electric eel"), random MONSTER: (';', "electric eel"), random MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'D',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile MONSTER: 'S',random,hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random nethack-3.6.0/dat/Knight.des0000664000076400007660000003031012536476415014640 0ustar paxedpaxed# NetHack 3.6 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991,92 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, King Arthur # and receive your quest assignment. # MAZE: "Kni-strt",'.' FLAGS: noteleport,hardfloor # This is a kludge to init the level as a lit field. INIT_MAP: mines, '.' , '.' , false , false , lit , false GEOMETRY:center,center MAP .................................................. .-----......................................-----. .|...|......................................|...|. .--|+-------------------++-------------------+|--. ...|...................+..+...................|... ...|.|-----------------|++|-----------------|.|... ...|.|.................|..|.........|.......|.|... ...|.|...\.............+..+.........|.......|.|... ...|.|.................+..+.........+.......|.|... ...|.|.................|..|.........|.......|.|... ...|.|--------------------------------------|.|... ...|..........................................|... .--|+----------------------------------------+|--. .|...|......................................|...|. .-----......................................-----. .................................................. ENDMAP # Dungeon Description REGION:(00,00,49,15),lit,"ordinary" REGION:(04,04,45,11),unlit,"ordinary" REGION:(06,06,22,09),lit,"throne" , unfilled REGION:(27,06,43,09),lit,"ordinary" # Portal arrival point BRANCH:(20,14,20,14),(0,0,0,0) # Stairs STAIR:(40,7),down # Doors # Outside Doors DOOR:locked,(24,03) DOOR:locked,(25,03) # Inside Doors DOOR:closed,(23,04) DOOR:closed,(26,04) DOOR:locked,(24,05) DOOR:locked,(25,05) DOOR:closed,(23,07) DOOR:closed,(26,07) DOOR:closed,(23,08) DOOR:closed,(26,08) DOOR:closed,(36,08) # Watchroom Doors DOOR:closed,(04,03) DOOR:closed,(45,03) DOOR:closed,(04,12) DOOR:closed,(45,12) # King Arthur MONSTER:('@',"King Arthur"),(09,07) # The treasure of King Arthur OBJECT:('(',"chest"),(09,07) # knight guards for the watchrooms MONSTER:('@',"knight"),(04,02),peaceful MONSTER:('@',"knight"),(04,13),peaceful MONSTER:('@',"knight"),(45,02),peaceful MONSTER:('@',"knight"),(45,13),peaceful # page guards for the audience chamber MONSTER:('@',"page"),(16,06) MONSTER:('@',"page"),(18,06) MONSTER:('@',"page"),(20,06) MONSTER:('@',"page"),(16,09) MONSTER:('@',"page"),(18,09) MONSTER:('@',"page"),(20,09) # Non diggable walls NON_DIGGABLE:(00,00,49,15) # Random traps TRAP:"sleep gas",(24,04) TRAP:"sleep gas",(25,04) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: ('i',"quasit"),(14,00),hostile MONSTER: ('i',"quasit"),(16,00),hostile MONSTER: ('i',"quasit"),(18,00),hostile MONSTER: ('i',"quasit"),(20,00),hostile MONSTER: ('i',"quasit"),(22,00),hostile MONSTER: ('i',"quasit"),(24,00),hostile MONSTER: ('i',"quasit"),(26,00),hostile MONSTER: ('i',"quasit"),(28,00),hostile MONSTER: ('i',"quasit"),(30,00),hostile MONSTER: ('i',"quasit"),(32,00),hostile MONSTER: ('i',"quasit"),(34,00),hostile MONSTER: ('i',"quasit"),(36,00),hostile # # The "locate" level for the quest. # # Here you have to find your way to the Isle of Glass to go # further towards your assigned quest. # MAZE: "Kni-loca",' ' FLAGS: hardfloor INIT_MAP: mines, '.' , 'P' , false , true , lit , false GEOMETRY:center,center MAP xxxxxxxxx......xxxx...........xxxxxxxxxx xxxxxxx.........xxx.............xxxxxxxx xxxx..............................xxxxxx xx.................................xxxxx ....................................xxxx .......................................x ........................................ xx...................................xxx xxxx..............................xxxxxx xxxxxx..........................xxxxxxxx xxxxxxxx.........xx..........xxxxxxxxxxx xxxxxxxxx.......xxxxxx.....xxxxxxxxxxxxx ENDMAP # Dungeon Description # The Isle of Glass is a Tor rising out of the swamps surrounding it. REGION:(00,00,39,11),lit,"ordinary" # The top area of the Tor is a holy site. REGION:(09,02,27,09),lit,"temple" # Stairs STAIR:(38,0),up STAIR:(18,05),down # The altar atop the Tor and its attendant (creating altar makes the priest). ALTAR:(17,05),neutral,shrine # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps # All of the avenues are guarded by magic except for the East. # South TRAP:"magic",(08,11) TRAP:"magic",(09,11) TRAP:"magic",(10,11) TRAP:"magic",(11,11) TRAP:"magic",(12,11) TRAP:"magic",(13,11) TRAP:"magic",(14,11) TRAP:"magic",(15,11) TRAP:"magic",(16,11) TRAP:"magic",(20,11) TRAP:"magic",(21,11) TRAP:"magic",(22,11) TRAP:"magic",(23,11) TRAP:"magic",(24,11) TRAP:"magic",(25,11) TRAP:"magic",(26,11) TRAP:"magic",(27,11) TRAP:"magic",(28,11) # West TRAP:"magic",(00,03) TRAP:"magic",(00,04) TRAP:"magic",(00,05) TRAP:"magic",(00,06) # North TRAP:"magic",(06,00) TRAP:"magic",(07,00) TRAP:"magic",(08,00) TRAP:"magic",(09,00) TRAP:"magic",(10,00) TRAP:"magic",(11,00) TRAP:"magic",(12,00) TRAP:"magic",(13,00) TRAP:"magic",(14,00) TRAP:"magic",(19,00) TRAP:"magic",(20,00) TRAP:"magic",(21,00) TRAP:"magic",(22,00) TRAP:"magic",(23,00) TRAP:"magic",(24,00) TRAP:"magic",(25,00) TRAP:"magic",(26,00) TRAP:"magic",(27,00) TRAP:"magic",(28,00) TRAP:"magic",(29,00) TRAP:"magic",(30,00) TRAP:"magic",(31,00) TRAP:"magic",(32,00) # Even so, there are magic "sinkholes" around. TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random # Random monsters. MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:'i',random,hostile MONSTER:'j',random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:'j',random,hostile # # The "goal" level for the quest. # # Here you meet Ixoth your nemesis monster. You have to # defeat Ixoth in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Kni-goal", ' ' GEOMETRY:center,center MAP ....PPPP..PPP.. .PPPPP...PP.. .......... ................................. ..PPPPP...P.. ........... ................................... ..PPP....... ........... ...................................... ...PPP....... ......... ............... ..................... ........... ............ ............ ...................... ............ ............. ....... ..................... .............................. ......................... ............................... .................................. ............................. .................................... ......... ...................................................... .....PP... ..................................................... .....PPP.... .................................................... ......PPP.... .............. .................................... .......PPP.... ............. ..................................... ........PP... ............ ...................................... ...PPP........ .......... .................................. ..PPPPP........ .......... .............................. ....PPPPP...... ......... .......................... .......PPPP... ENDMAP # Dungeon Description REGION:(00,00,14,19),lit,"ordinary" REGION:(15,00,75,19),unlit,"ordinary" # Stairs STAIR:(03,08),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:('(',"mirror"),(50,06),blessed,0,name:"The Magic Mirror of Merlin" OBJECT:random,(33,01) OBJECT:random,(33,02) OBJECT:random,(33,03) OBJECT:random,(33,04) OBJECT:random,(33,05) OBJECT:random,(34,01) OBJECT:random,(34,02) OBJECT:random,(34,03) OBJECT:random,(34,04) OBJECT:random,(34,05) OBJECT:random,(35,01) OBJECT:random,(35,02) OBJECT:random,(35,03) OBJECT:random,(35,04) OBJECT:random,(35,05) OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:"spiked pit",(13,07) TRAP:"spiked pit",(12,08) TRAP:"spiked pit",(12,09) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('D',"Ixoth"),(50,06),hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:('i',"quasit"),random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:('j',"ochre jelly"),random,hostile MONSTER:'j',random,hostile # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Kni-fila" , '.' INIT_MAP: mines, '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('i', "quasit"), random, hostile MONSTER: ('i', "quasit"), random, hostile MONSTER: ('i', "quasit"), random, hostile MONSTER: ('i', "quasit"), random, hostile MONSTER: 'i', random, hostile MONSTER: ('j', "ochre jelly"), random, hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Kni-filb" , '.' INIT_MAP: mines, '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('i', "quasit"), random, hostile MONSTER: ('i', "quasit"), random, hostile MONSTER: ('i', "quasit"), random, hostile MONSTER: ('i', "quasit"), random, hostile MONSTER: 'i', random, hostile MONSTER: ('j', "ochre jelly"), random, hostile MONSTER: ('j', "ochre jelly"), random, hostile MONSTER: ('j', "ochre jelly"), random, hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random nethack-3.6.0/dat/Monk.des0000664000076400007660000002641612536476415014334 0ustar paxedpaxed# NetHack 3.6 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-2 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, the Grand Master # and receive your quest assignment. # MAZE: "Mon-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ....................------------------------------------.................... ....................|................|.....|.....|.....|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|..|..........|..|.................|.................... ....................|..|..........|..|+---+---+-----+--|.................... ..................---..|..........|......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................---..|..........|......|...|...|.....|.................... ....................|..|..........|..|+-----+---+---+--|.................... ....................|..|..........|..|.................|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|................|.....|.....|.....|.................... ....................------------------------------------.................... ............................................................................ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(24,06,33,13),lit,"temple" REPLACE_TERRAIN:(0,0,10,19),'.','T',10% REPLACE_TERRAIN:(65,0,75,19),'.','T',10% # Portal arrival point TERRAIN:(05,04),'.' BRANCH:(05,04,05,04),(0,0,0,0) # Stairs STAIR:(52,09),down # Doors DOOR:locked,(18,09) DOOR:locked,(18,10) DOOR:closed,(34,09) DOOR:closed,(34,10) DOOR:closed,(40,05) DOOR:closed,(46,05) DOOR:closed,(52,05) DOOR:locked,(38,07) DOOR:closed,(42,07) DOOR:closed,(46,07) DOOR:closed,(52,07) DOOR:locked,(38,12) DOOR:closed,(44,12) DOOR:closed,(48,12) DOOR:closed,(52,12) DOOR:closed,(40,14) DOOR:closed,(46,14) DOOR:closed,(52,14) # Unattended Altar - unaligned due to conflict - player must align it. ALTAR:(28,09),noalign,altar # The Grand Master MONSTER:('@',"Grand Master"),(28,10) # No treasure chest! # guards for the audience chamber MONSTER:('@',"abbot"),(32,07) MONSTER:('@',"abbot"),(32,08) MONSTER:('@',"abbot"),(32,11) MONSTER:('@',"abbot"),(32,12) MONSTER:('@',"abbot"),(33,07) MONSTER:('@',"abbot"),(33,08) MONSTER:('@',"abbot"),(33,11) MONSTER:('@',"abbot"),(33,12) # Non diggable walls NON_DIGGABLE:(18,03,55,16) # Random traps TRAP:"dart",(20,09) TRAP:"dart",(20,10) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: ('E',"earth elemental"),(37,01) MONSTER: ('E',"earth elemental"),(37,18) MONSTER: ('E',"earth elemental"),(03,03) MONSTER: ('E',"earth elemental"),(65,04) MONSTER: ('E',"earth elemental"),(12,11) MONSTER: ('E',"earth elemental"),(60,12) MONSTER: ('E',"earth elemental"),(14,08) MONSTER: ('E',"earth elemental"),(55,00) MONSTER: ('X',"xorn"),(18,18) MONSTER: ('X',"xorn"),(59,10) MONSTER: ('X',"xorn"),(13,09) MONSTER: ('X',"xorn"),(01,17) # # The "locate" level for the quest. # # Here you have to locate the Monastery of the Earth-Lord to # go further towards your assigned quest. # MAZE: "Mon-loca",' ' GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ---------------------------------------------------- -------- ---.................................................- --.....| ---...--------........------........................--- ---...| ---.....- --.......- ----..................---- --.-- ---.....---- --------- --..................-- --..| ---...----- ----.----.....----.....--- --..|| ----..---- -----..--- |...--- |.......--- --...| |...--- ----....--- |.--- |.........-- --...|| |...- ----.....--- ---- |..........---....| |...---- ----......--- | |...|.......-....|| |......----- ---.........- | -----...|............| |..........----- ----...........--- -------......||...........|| |..............-----................--- |............|||..........| |-S----...............................--- |...........|| |.........|| |.....|..............------.............-----..........|| ||........| |.....|.............-- ---.........................|| |.......|| |.....|.............- ---.....................--| ||......| |---S--------.......---- --.................---- |.....|| |...........|..........--------..............----- ||....| |...........|............................----- |....| ------------------------------------------ ------ ENDMAP # Random Monsters $monster = monster: { 'E', 'X' } SHUFFLE: $monster # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random # # The "goal" level for the quest. # # Here you meet Master Kaen, your nemesis monster. You have to # defeat Master Kaen in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Mon-goal", ' ' INIT_MAP: mines, 'L' , '.' , false , false , unlit , false GEOMETRY:center,center MAP xxxxxx..xxxxxx...xxxxxxxxx xxxx......xx......xxxxxxxx xx.xx.............xxxxxxxx x....................xxxxx ......................xxxx ......................xxxx xx........................ xxx......................x xxx................xxxxxxx xxxx.....x.xx.......xxxxxx xxxxx...xxxxxx....xxxxxxxx ENDMAP # Dungeon Description $place = { (14,04),(13,07) } SHUFFLE: $place REGION:(00,00,25,10),unlit,"ordinary" # Stairs STAIR:(20,05),up # Objects OBJECT:('(',"lenses"),$place[0],blessed,0,name:"The Eyes of the Overworld" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"Master Kaen"),$place[0] ALTAR:$place[0],noalign,altar MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('E',"earth elemental"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random MONSTER: ('X',"xorn"),random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "fila" is the upper filler, between the # start and locate levels, and "filb" the lower between the locate # and goal levels. # LEVEL: "Mon-fila" # Random Monsters $monster = monster: { 'E', 'X' } SHUFFLE: $monster # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: 'E', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: 'E', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: ('X', "xorn"), random MONSTER: ('E', "earth elemental"), random } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: 'E', random, hostile MONSTER: ('E', "earth elemental"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: 'X', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: ('E', "earth elemental"), random } RANDOM_CORRIDORS LEVEL: "Mon-filb" # Random Monsters $monster = monster: { 'E', 'X' } SHUFFLE: $monster # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: 'X', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: 'X', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: 'E', random, hostile } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: 'E', random, hostile MONSTER: ('E', "earth elemental"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: 'X', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: ('E', "earth elemental"), random } RANDOM_CORRIDORS nethack-3.6.0/dat/Priest.des0000664000076400007660000002370112536476415014670 0ustar paxedpaxed# NetHack 3.6 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-2 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, High Priest # and receive your quest assignment. # MAZE: "Pri-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ....................------------------------------------.................... ....................|................|.....|.....|.....|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|..|..........|..|.................|.................... ....................|..|..........|..|+---+---+-----+--|.................... ..................---..|..........|......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................---..|..........|......|...|...|.....|.................... ....................|..|..........|..|+-----+---+---+--|.................... ....................|..|..........|..|.................|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|................|.....|.....|.....|.................... ....................------------------------------------.................... ............................................................................ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(24,06,33,13),lit,"temple" REPLACE_TERRAIN:(0,0,10,19),'.','T',10% REPLACE_TERRAIN:(65,0,75,19),'.','T',10% TERRAIN:(05,04),'.' # Portal arrival point BRANCH:(05,04,05,04),(0,0,0,0) # Stairs STAIR:(52,09),down # Doors DOOR:locked,(18,09) DOOR:locked,(18,10) DOOR:closed,(34,09) DOOR:closed,(34,10) DOOR:closed,(40,05) DOOR:closed,(46,05) DOOR:closed,(52,05) DOOR:locked,(38,07) DOOR:closed,(42,07) DOOR:closed,(46,07) DOOR:closed,(52,07) DOOR:locked,(38,12) DOOR:closed,(44,12) DOOR:closed,(48,12) DOOR:closed,(52,12) DOOR:closed,(40,14) DOOR:closed,(46,14) DOOR:closed,(52,14) # Unattended Altar - unaligned due to conflict - player must align it. ALTAR:(28,09),noalign,altar # High Priest MONSTER:('@',"Arch Priest"),(28,10) # The treasure of High Priest OBJECT:('(',"chest"),(27,10) # knight guards for the audience chamber MONSTER:('@',"acolyte"),(32,07) MONSTER:('@',"acolyte"),(32,08) MONSTER:('@',"acolyte"),(32,11) MONSTER:('@',"acolyte"),(32,12) MONSTER:('@',"acolyte"),(33,07) MONSTER:('@',"acolyte"),(33,08) MONSTER:('@',"acolyte"),(33,11) MONSTER:('@',"acolyte"),(33,12) # Non diggable walls NON_DIGGABLE:(18,03,55,16) # Random traps TRAP:"dart",(20,09) TRAP:"dart",(20,10) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: ('Z',"human zombie"),(37,01) MONSTER: ('Z',"human zombie"),(37,18) MONSTER: ('Z',"human zombie"),(03,03) MONSTER: ('Z',"human zombie"),(65,04) MONSTER: ('Z',"human zombie"),(12,11) MONSTER: ('Z',"human zombie"),(60,12) MONSTER: ('Z',"human zombie"),(14,08) MONSTER: ('Z',"human zombie"),(55,00) MONSTER: ('Z',"human zombie"),(18,18) MONSTER: ('Z',"human zombie"),(59,10) MONSTER: ('Z',"human zombie"),(13,09) MONSTER: ('Z',"human zombie"),(01,17) # # The "locate" level for the quest. # # Here you have to locate the Temple of Nalzok to go # further towards your assigned quest. # MAZE: "Pri-loca",' ' FLAGS: hardfloor # This is a kludge to init the level as a lit field. INIT_MAP: mines, '.' , '.' , false , false , lit , false GEOMETRY:center,center MAP ........................................ ........................................ ..........----------+----------......... ..........|........|.|........|......... ..........|........|.|........|......... ..........|----.----.----.----|......... ..........+...................+......... ..........+...................+......... ..........|----.----.----.----|......... ..........|........|.|........|......... ..........|........|.|........|......... ..........----------+----------......... ........................................ ........................................ ENDMAP # Dungeon Description REGION:(00,00,09,13),unlit,"morgue" REGION:(09,00,30,01),unlit,"morgue" REGION:(09,12,30,13),unlit,"morgue" REGION:(31,00,39,13),unlit,"morgue" REGION:(11,03,29,10),lit,"temple",filled,irregular # The altar inside the temple ALTAR:(20,07),noalign,shrine MONSTER:('@',"aligned priest"),(20,07),noalign,hostile # Doors DOOR:locked,(10,06) DOOR:locked,(10,07) DOOR:locked,(20,02) DOOR:locked,(20,11) DOOR:locked,(30,06) DOOR:locked,(30,07) # Stairs # Note: The up stairs are *intentionally* off of the map. STAIR:(43,05),up STAIR:(20,06),down # Non diggable walls NON_DIGGABLE:(10,02,30,13) # Objects (inside the antechambers). OBJECT:random,(14,03) OBJECT:random,(15,03) OBJECT:random,(16,03) OBJECT:random,(14,10) OBJECT:random,(15,10) OBJECT:random,(16,10) OBJECT:random,(17,10) OBJECT:random,(24,03) OBJECT:random,(25,03) OBJECT:random,(26,03) OBJECT:random,(27,03) OBJECT:random,(24,10) OBJECT:random,(25,10) OBJECT:random,(26,10) OBJECT:random,(27,10) # Random traps TRAP:random,(15,04) TRAP:random,(25,04) TRAP:random,(15,09) TRAP:random,(25,09) TRAP:random,random TRAP:random,random # No random monsters - the morgue generation will put them in. # # The "goal" level for the quest. # # Here you meet Nalzok your nemesis monster. You have to # defeat Nalzok in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Pri-goal", ' ' INIT_MAP: mines, 'L' , '.' , false , false , unlit , false GEOMETRY:center,center MAP xxxxxx..xxxxxx...xxxxxxxxx xxxx......xx......xxxxxxxx xx.xx.............xxxxxxxx x....................xxxxx ......................xxxx ......................xxxx xx........................ xxx......................x xxx................xxxxxxx xxxx.....x.xx.......xxxxxx xxxxx...xxxxxx....xxxxxxxx ENDMAP # Dungeon Description $place = { (14,04),(13,07) } SHUFFLE: $place REGION:(00,00,25,10),unlit,"ordinary" # Stairs STAIR:(20,05),up # Objects OBJECT:('[',"helm of brilliance"),$place[0],blessed,0,name:"The Mitre of Holiness" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('&',"Nalzok"),$place[0] MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:'Z',random MONSTER:'Z',random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:('W',"wraith"),random MONSTER:'W',random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # LEVEL: "Pri-fila" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: ('Z', "human zombie"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: ('Z', "human zombie"), random } ROOM: "morgue" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: ('W', "wraith"), random } ROOM: "morgue" , random, random, random, random { OBJECT: random, random TRAP: random, random } RANDOM_CORRIDORS LEVEL: "Pri-filb" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: ('Z', "human zombie"), random MONSTER: ('W', "wraith"), random } ROOM: "morgue" , random, random, random, random { OBJECT: random, random OBJECT: random, random OBJECT: random,random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: ('Z', "human zombie"), random MONSTER: ('W', "wraith"), random } ROOM: "morgue" , random, random, random, random { STAIR: random, down OBJECT: random, random OBJECT: random, random TRAP: random, random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: ('Z', "human zombie"), random MONSTER: ('W', "wraith"), random } ROOM: "morgue" , random, random, random, random { OBJECT: random, random TRAP: random, random } RANDOM_CORRIDORS nethack-3.6.0/dat/Ranger.des0000664000076400007660000002765712536476415014656 0ustar paxedpaxed# NetHack 3.6 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Orion, # and receive your quest assignment. # MAZE: "Ran-strt",'.' FLAGS: noteleport,hardfloor,arboreal INIT_MAP:mines,'.','.',true,true,lit,false REPLACE_TERRAIN:(0,0,76,19),'.', 'T', 5% GEOMETRY:left,center #1234567890123456789012345678901234567890123456789012345678901234567890 MAP xx ................................... x .. .. .. ...............F............... .. . .. .F. .. . . .. .............F............. .. . . . .. .. . . . . .. ....................... .. ... . . . .. .. . ... . .. .|..................... ...... FFF . . ..S.................. ... . .. .|................. .... ... . . . .. .. . . . . . .. ....................... .. . . . . .. .. . . . .. .............F............. .. . . .. .F. .. . .. ...............F............... .. .. .. ................................... x xx ENDMAP # Dungeon Description REGION:(00,00,40,20),lit,"ordinary" # Stairs STAIR:(10,10),down # Portal arrival point; just about anywhere on the right hand side of the map BRANCH:levregion(51,2,77,18),(0,0,40,20) # Orion MONSTER:('@',"Orion"),(20,10) # The treasure of Orion OBJECT:('(',"chest"),(20,10) # Guards for the audience chamber MONSTER:('@',"hunter"),(19,09) MONSTER:('@',"hunter"),(20,09) MONSTER:('@',"hunter"),(21,09) MONSTER:('@',"hunter"),(19,10) MONSTER:('@',"hunter"),(21,10) MONSTER:('@',"hunter"),(19,11) MONSTER:('@',"hunter"),(20,11) MONSTER:('@',"hunter"),(21,11) # Non diggable walls NON_DIGGABLE:(00,00,40,20) # Traps TRAP:"arrow",(30,09) TRAP:"arrow",(30,10) TRAP:"pit",(40,09) TRAP:"spiked pit",random TRAP:"bear",random TRAP:"bear",random # Monsters on siege duty. MONSTER: ('H',"minotaur"),(33,09),hostile,asleep MONSTER: ('C',"forest centaur"),(19,03),hostile MONSTER: ('C',"forest centaur"),(19,04),hostile MONSTER: ('C',"forest centaur"),(19,05),hostile MONSTER: ('C',"forest centaur"),(21,03),hostile MONSTER: ('C',"forest centaur"),(21,04),hostile MONSTER: ('C',"forest centaur"),(21,05),hostile MONSTER: ('C',"forest centaur"),(01,09),hostile MONSTER: ('C',"forest centaur"),(02,09),hostile MONSTER: ('C',"forest centaur"),(03,09),hostile MONSTER: ('C',"forest centaur"),(01,11),hostile MONSTER: ('C',"forest centaur"),(02,11),hostile MONSTER: ('C',"forest centaur"),(03,11),hostile MONSTER: ('C',"forest centaur"),(19,15),hostile MONSTER: ('C',"forest centaur"),(19,16),hostile MONSTER: ('C',"forest centaur"),(19,17),hostile MONSTER: ('C',"forest centaur"),(21,15),hostile MONSTER: ('C',"forest centaur"),(21,16),hostile MONSTER: ('C',"forest centaur"),(21,17),hostile MONSTER: ('C',"plains centaur"),random,hostile MONSTER: ('C',"plains centaur"),random,hostile MONSTER: ('C',"plains centaur"),random,hostile MONSTER: ('C',"plains centaur"),random,hostile MONSTER: ('C',"plains centaur"),random,hostile MONSTER: ('C',"plains centaur"),random,hostile MONSTER: ('s',"scorpion"),random,hostile MONSTER: ('s',"scorpion"),random,hostile # # The "locate" level for the quest. # # Here you have to infiltrate the Cave of the Wumpus to go # further towards your assigned quest. # MAZE: "Ran-loca",' ' FLAGS: hardfloor GEOMETRY:center,center #1234567890123456789012345678901234567890123456789012345678901234567890 MAP ....... ......... ....... ................... ................... .... ....... ....... .... ... ..... . ..... . ..... ... . .......... ..... ........... ..... .......... . . .. ..... .......... ..... .......... ..... .. . . . . ..... . ..... . . . . . ..... ............. ..... . . . . ................ ....... ................ . . . . ..... ....... ..... . . . . . ...... ...... . . . . . ........... ......... ........... . . . . .......... .......... . . . .. ..... . ..... . ..... .. . . .......... ..... ........... ..... .......... . . ..... .......... ..... .......... ..... . . . ..... . ..... . . ... ....... ....... ....... ... .............. ............. .............. ....... ....... ....... ....... ....... ENDMAP # Dungeon Description REGION:(00,00,54,19),lit,"ordinary" # Stairs STAIR:(25,05),up STAIR:(27,18),down # Non diggable walls NON_DIGGABLE:(00,00,54,19) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:"spiked pit",random TRAP:"spiked pit",random TRAP:"teleport",random TRAP:"teleport",random TRAP:"arrow",random TRAP:"arrow",random # Random monsters. MONSTER:('q',"wumpus"),(27,18),hostile,asleep MONSTER:('B',"giant bat"),random,hostile MONSTER:('B',"giant bat"),random,hostile MONSTER:('B',"giant bat"),random,hostile MONSTER:('B',"giant bat"),random,hostile MONSTER:('C',"forest centaur"),random,hostile MONSTER:('C',"forest centaur"),random,hostile MONSTER:('C',"forest centaur"),random,hostile MONSTER:('C',"forest centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('s',"scorpion"),random,hostile MONSTER:('s',"scorpion"),random,hostile MONSTER:('s',"scorpion"),random,hostile MONSTER:('s',"scorpion"),random,hostile MONSTER:'s',random,hostile MONSTER:'s',random,hostile # # The "goal" level for the quest. # # Here you meet Scorpius, your nemesis monster. You have to # defeat Scorpius in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Ran-goal", ' ' GEOMETRY:center,center MAP ... ... .......................................................................... ... + ... . ............ ....... . ....... . . ............................. . ........ .........S.. . . ............ . ...... . . . ....... .. . . ......... . .... + . ... . .. . . S . ......... .S. .S............... . . ... . ... . ......... . . . ........ .....S.+.......+....\....+........+. . . ... ... S ......... .. ..... . . .. ......... .. ...... . . ....... ... + .... .... .......... . . .............. .. . ...... .. ............. . . ............. . .......... ...... . ... + ... .......................................................................... ... ... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Stairs STAIR:(19,10),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:(')',"bow"),(37,10),blessed,0,name:"The Longbow of Diana" OBJECT:('(',"chest"),(37,10) OBJECT:random,(36,09) OBJECT:random,(36,10) OBJECT:random,(36,11) OBJECT:random,(37,09) OBJECT:random,(37,11) OBJECT:random,(38,09) OBJECT:random,(38,10) OBJECT:random,(38,11) OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # doors DOOR:locked,(12,08) DOOR:closed,(22,10) DOOR:locked,(24,10) DOOR:closed,(25,11) DOOR:closed,(32,10) DOOR:closed,(37,03) DOOR:closed,(37,07) DOOR:closed,(37,13) DOOR:closed,(37,16) DOOR:closed,(42,10) DOOR:locked,(46,08) DOOR:closed,(51,10) DOOR:locked,(53,08) DOOR:closed,(65,05) # Random monsters. MONSTER:('s',"Scorpius"),(37,10),hostile MONSTER:('C',"forest centaur"),(36,09),hostile MONSTER:('C',"forest centaur"),(36,10),hostile MONSTER:('C',"forest centaur"),(36,11),hostile MONSTER:('C',"forest centaur"),(37,09),hostile MONSTER:('C',"forest centaur"),(37,11),hostile MONSTER:('C',"forest centaur"),(38,09),hostile MONSTER:('C',"mountain centaur"),(38,10),hostile MONSTER:('C',"mountain centaur"),(38,11),hostile MONSTER:('C',"mountain centaur"),(02,02),hostile MONSTER:('C',"mountain centaur"),(71,02),hostile MONSTER:('C',"mountain centaur"),(02,16),hostile MONSTER:('C',"mountain centaur"),(71,16),hostile MONSTER:('C',"forest centaur"),random,hostile MONSTER:('C',"forest centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:('C',"mountain centaur"),random,hostile MONSTER:'C',random,hostile MONSTER:'C',random,hostile MONSTER:('s',"scorpion"),(03,02),hostile MONSTER:('s',"scorpion"),(72,02),hostile MONSTER:('s',"scorpion"),(03,17),hostile MONSTER:('s',"scorpion"),(72,17),hostile MONSTER:('s',"scorpion"),(41,10),hostile MONSTER:('s',"scorpion"),(33,09),hostile MONSTER:('s',"scorpion"),random,hostile MONSTER:('s',"scorpion"),random,hostile MONSTER:'s',random,hostile WALLIFY # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "fila" is the upper filler, between the # start and locate levels, and "filb" the lower between the locate # and goal levels. # MAZE: "Ran-fila" , ' ' INIT_MAP: mines, '.' , 'T', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('C', "mountain centaur"), random, hostile MONSTER: ('C', "mountain centaur"), random, hostile MONSTER: ('C', "forest centaur"), random, hostile MONSTER: ('C', "forest centaur"), random, hostile MONSTER: ('C', "forest centaur"), random, hostile MONSTER: 'C', random, hostile MONSTER: ('s', "scorpion"), random, hostile MAZE: "Ran-filb" , ' ' INIT_MAP: mines, '.' , ' ', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('C', "mountain centaur"), random, hostile MONSTER: ('C', "mountain centaur"), random, hostile MONSTER: ('C', "mountain centaur"), random, hostile MONSTER: ('C', "mountain centaur"), random, hostile MONSTER: 'C', random, hostile MONSTER: ('s', "scorpion"), random, hostile MONSTER: ('s', "scorpion"), random, hostile nethack-3.6.0/dat/Rogue.des0000664000076400007660000004011212536476415014476 0ustar paxedpaxed# NetHack 3.6 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ # Copyright (c) 1992 by Dean Luick # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Master of Thieves # and receive your quest assignment. # MAZE: "Rog-strt",' ' FLAGS: noteleport, hardfloor, nommap GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ---------------------------------.------------------------------------------ |.....|.||..........|....|......|.|.........|.......+............---.......| |.....|..+..........+....---....S.|...-S-----.-----.|............+.+.......| |.....+.||........---......|....|.|...|.....|.|...|.---.....------.--------| |-----|.-------|..|........------.-----.....|.--..|...-------..............| |.....|........------+------..........+.....|..--S---.........------.-----.. |.....|.------...............-----.}}.--------.|....-------.---....|.+...--| |..-+--.|....|-----.--------.|...|.....+.....|.|....|.....+.+......|.--....| |..|....|....|....+.|......|.|...-----.|.....|.--...|.....|.|......|..|....| |..|.-----S----...|.+....-----...|...|.----..|..|.---....--.---S-----.|----| |..|.|........|...------.|.S.....|...|....-----.+.|......|..|.......|.|....| |---.-------..|...|....|.|.|.....|...----.|...|.|---.....|.|-.......|.---..| ...........|..S...|....---.----S----..|...|...+.|..-------.---+-....|...--+| |---------.---------...|......|....S..|.---...|.|..|...........----.---....| |........|.........|...+.------....|---.---...|.--+-.----.----....|.+...--+| |........|.---+---.|----.--........|......-----......|..|..|.--+-.|.-S-.|..| |........|.|.....|........----------.----.......---.--..|-.|....|.-----.|..| |----....+.|.....----+---............|..|--------.+.|...SS.|....|.......|..| |...--+-----.....|......|.------------............---...||.------+--+----..| |..........S.....|......|.|..........S............|.....||...|.....|....|..| -------------------------.-------------------------------------------------- ENDMAP # Dungeon Description #REGION:(00,00,75,20),lit,"ordinary" $streets = selection: floodfill(0,12) # The down stairs is at one of the 4 "exits". The others are mimics, # mimicing stairwells. $place = { (33,0), (0,12), (25,20), (75,05) } SHUFFLE: $place STAIR:$place[0],down MONSTER:('m',"giant mimic"), $place[1], m_feature "staircase down" MONSTER:('m',"large mimic"), $place[2], m_feature "staircase down" MONSTER:('m',"small mimic"), $place[3], m_feature "staircase down" # Portal arrival point BRANCH:(19,09,19,09),(0,0,0,0) # Doors (secret) #DOOR:locked|closed|open,(xx,yy) DOOR: locked, (32, 2) DOOR: locked, (63, 9) DOOR: locked, (27,10) DOOR: locked, (31,12) DOOR: locked, (35,13) DOOR: locked, (69,15) DOOR: locked, (56,17) DOOR: locked, (57,17) DOOR: locked, (11,19) DOOR: locked, (37,19) DOOR: locked, (39, 2) DOOR: locked, (49, 5) DOOR: locked, (10, 9) DOOR: locked, (14,12) # Doors (regular) DOOR: closed, (52, 1) DOOR: closed, ( 9, 2) DOOR: closed, (20, 2) DOOR: closed, (65, 2) DOOR: closed, (67, 2) DOOR: closed, ( 6, 3) DOOR: closed, (21, 5) DOOR: closed, (38, 5) DOOR: closed, (69, 6) DOOR: closed, ( 4, 7) DOOR: closed, (39, 7) DOOR: closed, (58, 7) DOOR: closed, (60, 7) DOOR: closed, (18, 8) DOOR: closed, (20, 9) DOOR: closed, (48,10) DOOR: closed, (46,12) DOOR: closed, (62,12) DOOR: closed, (74,12) DOOR: closed, (23,14) DOOR: closed, (23,14) DOOR: closed, (50,14) DOOR: closed, (68,14) DOOR: closed, (74,14) DOOR: closed, (14,15) DOOR: closed, (63,15) DOOR: closed, ( 9,17) DOOR: closed, (21,17) DOOR: closed, (50,17) DOOR: closed, ( 6,18) DOOR: closed, (65,18) DOOR: closed, (68,18) # Master of Thieves MONSTER:('@',"Master of Thieves"),(36,11) # The treasure of Master of Thieves OBJECT:('(',"chest"),(36,11) # thug guards, room #1 MONSTER:('@',"thug"),(28,10) MONSTER:('@',"thug"),(29,11) MONSTER:('@',"thug"),(30,09) MONSTER:('@',"thug"),(31,07) # thug guards, room #2 MONSTER:('@',"thug"),(31,13) MONSTER:('@',"thug"),(33,14) MONSTER:('@',"thug"),(30,15) #thug guards, room #3 MONSTER:('@',"thug"),(35,09) MONSTER:('@',"thug"),(36,13) # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # # Monsters to get in the way. # # West exit MONSTER: ('l',"leprechaun"),(01,12),hostile MONSTER: ('n',"water nymph"),(02,12),hostile # North exit MONSTER: ('n',"water nymph"),(33,01),hostile MONSTER: ('l',"leprechaun"),(33,02),hostile # East exit MONSTER: ('n',"water nymph"),(74,05),hostile MONSTER: ('l',"leprechaun"),(74,04),hostile # South exit MONSTER: ('l',"leprechaun"),(25,19),hostile MONSTER: ('n',"water nymph"),(25,18),hostile # Wandering the streets. LOOP [ 4 + 1d3 ] { MONSTER: ('n',"water nymph"),rndcoord($streets),hostile MONSTER: ('l',"leprechaun"),rndcoord($streets),hostile } LOOP [ 7 + 1d3 ] { MONSTER: (':',"chameleon"),rndcoord($streets),hostile } # # The "locate" level for the quest. # # Here you have to find the entrance to the Assassins' Guild to go # further towards your assigned quest. # MAZE: "Rog-loca",' ' GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ---------------------------------------------------- -------- ---.................................................- --.....| ---...--------........-------.......................--- ---...| ---.....- ---......- ---..................---- --.-- ---.....---- -------- --..................-- --..| ---...----- ----.----.....----.....--- --..|| ----..---- -----..--- |...--- |.......--- --...| |...--- ----....--- |.--- |.........-- --...|| |...- ----.....--- ---- |..........---....| |...---- ----......--- | |...|.......-....|| |......----- ---.........- | -----...|............| |..........----- ----...........--- -------......||...........|| |..............-----................--- |............|||..........| |------...............................--- |...........|| |.........|| |.....|..............------.............-----..........|| ||........| |.....|.............-- ---.........................|| |.......|| |.....|.............- ---.....................--| ||......| |-S----------.......---- --.................---- |.....|| |...........|..........--------..............----- ||....| |...........|............................----- |....| ------------------------------------------ ------ ENDMAP # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" # Doors #DOOR:locked|closed|open,(xx,yy) # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Objects OBJECT:('?',"teleportation"),(11,18),cursed,0 OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:'l',random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:'N',random,hostile MONSTER:'N',random,hostile MONSTER:'N',random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile # # The "goal" level for the quest. Teleportation and digging are # disallowed. # # You have to reach The Master Assassin via some means other than # simple searching or digging since there is no path between your # arrival point and his location. # MAZE: "Rog-goal", ' ' FLAGS: noteleport GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ----- -------.......................................|-----------------| |...| -----.....|.......................................|.................| |...----...|.....|.......................................|....---------....| |.---......---..--.................................------------.......|....| |...............|..................................|..|...|...----........-| |.....-----....--.................................|-..--..-|.....----S----| |--S---...|....|.................................|-........-|....|........| |.........---------.............................|-....}}....-|...|...|....| |....|.....S......|............................|-.....}}.....-|..--.------| |-----.....--.....|...........................|-...}}}}}}}}...-|....|.....-- |...........--....------S-----...............|-....}}}}}}}}....-|..........| |............--........|...| |..............--.....}}.}}........----------S- |.............|........|...| |..............|......}}}}}}}}......|...|.....| |S-.---.---.---.---.---|...| ------------...--........}}.}}.....--..---....| |.---.---.---.---.-S-..----- |....|.....|....|-....}}}}}}}}....---..S.|--..| |...|.......|..........|...---....---...S.....|-...}}}}}}}}...-|.S..|...|..| |...|..|....|..........|............|..--..----|-.....}}.....-|..----...-S-- |...|---....----.......|----- ......|...---| |-....}}....-|...|..--.--..| -----.....---.....--.---....--...--------..| |-........-|....|.........| |.............|..........|.............S... |S-------|.....|..-----..| ---------------------------------------- ...... ---------- ---- ENDMAP # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" # Stairs STAIR:levregion(01,00,15,20),(01,18,04,20),up # Doors # Non diggable walls NON_DIGGABLE:(00,00,75,20) # One trap to keep the gnomes at bay. TRAP:"spiked pit",(37,07) # Objects OBJECT:('(',"skeleton key"),(38,10),blessed,0,name:"The Master Key of Thievery" OBJECT:('%',"tin"),(26,12),montype:"chameleon" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"Master Assassin"),(38,10),hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:('l',"leprechaun"),random,hostile MONSTER:'l',random,hostile MONSTER:'l',random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:('N',"guardian naga"),random,hostile MONSTER:'N',random,hostile MONSTER:'N',random,hostile MONSTER:'N',random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER: (':',"chameleon"),random,hostile MONSTER:(';',"shark"),(51,14),hostile MONSTER:(';',"shark"),(53,09),hostile MONSTER:(';',"shark"),(55,15),hostile MONSTER:(';',"shark"),(58,10),hostile # # The "fill" level for the quest. # # This level is used to fill out any levels not occupied by specific # levels as defined above. # LEVEL: "Rog-fila" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: ('l', "leprechaun"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: ('l', "leprechaun"), random, hostile MONSTER: ('N', "guardian naga"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random TRAP: random, random OBJECT: random,random MONSTER: ('n', "water nymph"), random, hostile } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random TRAP: random, random MONSTER: 'l', random, hostile MONSTER: ('N', "guardian naga"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random TRAP: random, random MONSTER: ('l', "leprechaun"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random TRAP: random, random MONSTER: ('l', "leprechaun"), random, hostile MONSTER: ('n', "water nymph"), random, hostile } RANDOM_CORRIDORS # # currently a & b are the same. # LEVEL: "Rog-filb" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: ('l', "leprechaun"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: ('l', "leprechaun"), random, hostile MONSTER: ('N', "guardian naga"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random TRAP: random, random OBJECT: random,random MONSTER: ('n', "water nymph"), random, hostile } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random TRAP: random, random MONSTER: 'l', random, hostile MONSTER: ('N', "guardian naga"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random TRAP: random, random MONSTER: ('l', "leprechaun"), random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random TRAP: random, random MONSTER: ('l', "leprechaun"), random, hostile MONSTER: ('n', "water nymph"), random, hostile } RANDOM_CORRIDORS nethack-3.6.0/dat/Samurai.des0000664000076400007660000003242112536476415015022 0ustar paxedpaxed# NetHack 3.6 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-92 by M. Stephenson, P. Winner # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Lord Sato # and receive your quest assignment. # MAZE: "Sam-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ..............................................................PP............ ...............................................................PP........... ..........---------------------------------------------------...PPP......... ..........|......|.........|...|..............|...|.........|....PPPPP...... ......... |......|.........S...|..............|...S.........|.....PPPP...... ..........|......|.........|---|..............|---|.........|.....PPP....... ..........+......|.........+...-------++-------...+.........|......PP....... ..........+......|.........|......................|.........|......PP....... ......... |......---------------------++--------------------|........PP..... ..........|.................................................|.........PP.... ..........|.................................................|...........PP.. ..........----------------------------------------...-------|............PP. ..........................................|.................|.............PP .............. ................. .........|.................|..............P ............. } ............... } ........|.................|............... .............. ........PP....... .........|.................|............... .....................PPP..................|.................|............... ......................PP..................-------------------............... ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(18,03,26,07),lit,"throne",unfilled # Portal arrival zone BRANCH:(62,12,70,17),(0,0,0,0) # Stairs STAIR:(29,04),down # Doors DOOR:locked,(10,06) DOOR:locked,(10,07) DOOR:closed,(27,04) DOOR:closed,(27,06) DOOR:closed,(38,06) DOOR:locked,(38,08) DOOR:closed,(39,06) DOOR:locked,(39,08) DOOR:closed,(50,04) DOOR:closed,(50,06) # Lord Sato MONSTER:('@',"Lord Sato"),(20,04) # The treasure of Lord Sato OBJECT:('(',"chest"),(20,04) # roshi guards for the audience chamber MONSTER:('@',"roshi"),(18,04) MONSTER:('@',"roshi"),(18,05) MONSTER:('@',"roshi"),(18,06) MONSTER:('@',"roshi"),(18,07) MONSTER:('@',"roshi"),(26,04) MONSTER:('@',"roshi"),(26,05) MONSTER:('@',"roshi"),(26,06) MONSTER:('@',"roshi"),(26,07) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: ('@',"ninja"),(64,00),hostile MONSTER: ('d',"wolf"),(65,01) MONSTER: ('@',"ninja"),(67,02),hostile MONSTER: ('@',"ninja"),(69,05),hostile MONSTER: ('@',"ninja"),(69,06),hostile MONSTER: ('d',"wolf"),(69,07) MONSTER: ('@',"ninja"),(70,06),hostile MONSTER: ('@',"ninja"),(70,07),hostile MONSTER: ('@',"ninja"),(72,01),hostile MONSTER: ('d',"wolf"),(75,09) MONSTER: ('@',"ninja"),(73,05),hostile MONSTER: ('@',"ninja"),(68,02),hostile MONSTER:('E',"stalker"),random # # The "locate" level for the quest. # # Here you have to invade the Shogun's Castle to go # further towards your assigned quest. # MAZE: "Sam-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ........-----..................................................-----........ ........|...|..................................................|...|........ ........|...---..}..--+------------------------------+--..}..---...|........ ........|-|...|.....|...|....|....|....|....|....|.|...|.....|...|-|........ ..........|...-------...|....|....|....|....|....S.|...-------...|.......... ..........|-|.........------+----+-+-------+-+--------.........|-|.......... ............|..--------.|}........................}|.--------..|............ ............|..+........+..........................+........+..|............ ............|..+........+..........................+........+..|............ ............|..--------.|}........................}|.--------..|............ ..........|-|.........--------+-+-------+-+----+------.........|-|.......... ..........|...-------...|.S....|....|....|....|....|...-------...|.......... ........|-|...|.....|...|.|....|....|....|....|....|...|.....|...|-|........ ........|...---..}..--+------------------------------+--..}..---...|........ ........|...|..................................................|...|........ ........-----..................................................-----........ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Doors DOOR:locked,(22,04) DOOR:locked,(22,15) DOOR:locked,(53,04) DOOR:locked,(53,15) DOOR:locked,(49,06) DOOR:locked,(26,13) DOOR:locked,(28,07) DOOR:locked,(30,12) DOOR:locked,(33,07) DOOR:locked,(32,12) DOOR:locked,(35,07) DOOR:locked,(40,12) DOOR:locked,(43,07) DOOR:locked,(42,12) DOOR:locked,(45,07) DOOR:locked,(47,12) DOOR:closed,(15,09) DOOR:closed,(15,10) DOOR:closed,(24,09) DOOR:closed,(24,10) DOOR:closed,(51,09) DOOR:closed,(51,10) DOOR:closed,(60,09) DOOR:closed,(60,10) # Stairs STAIR:(10,10),up STAIR:(25,14),down # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:'*',(25,05) OBJECT:'*',(26,05) OBJECT:'*',(27,05) OBJECT:'*',(28,05) OBJECT:'*',(25,06) OBJECT:'*',(26,06) OBJECT:'*',(27,06) OBJECT:'*',(28,06) # OBJECT:'[',(40,05) OBJECT:'[',(41,05) OBJECT:'[',(42,05) OBJECT:'[',(43,05) OBJECT:'[',(40,06) OBJECT:'[',(41,06) OBJECT:'[',(42,06) OBJECT:'[',(43,06) # OBJECT:')',(27,13) OBJECT:')',(28,13) OBJECT:')',(29,13) OBJECT:')',(30,13) OBJECT:')',(27,14) OBJECT:')',(28,14) OBJECT:')',(29,14) OBJECT:')',(30,14) # OBJECT:'(',(37,13) OBJECT:'(',(38,13) OBJECT:'(',(39,13) OBJECT:'(',(40,13) OBJECT:'(',(37,14) OBJECT:'(',(38,14) OBJECT:'(',(39,14) OBJECT:'(',(40,14) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"ninja"),(15,05),hostile MONSTER:('@',"ninja"),(16,05),hostile MONSTER:('d',"wolf"),(17,05) MONSTER:('d',"wolf"),(18,05) MONSTER:('@',"ninja"),(19,05),hostile MONSTER:('d',"wolf"),(15,14) MONSTER:('d',"wolf"),(16,14) MONSTER:('@',"ninja"),(17,14),hostile MONSTER:('@',"ninja"),(18,14),hostile MONSTER:('d',"wolf"),(56,05) MONSTER:('@',"ninja"),(57,05),hostile MONSTER:('d',"wolf"),(58,05) MONSTER:('d',"wolf"),(59,05) MONSTER:('@',"ninja"),(56,14),hostile MONSTER:('d',"wolf"),(57,14) MONSTER:('@',"ninja"),(58,14),hostile MONSTER:'d',(59,14) MONSTER:('d',"wolf"),(60,14) MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random # "guards" for the central courtyard. MONSTER:('@',"samurai"),(30,05),hostile MONSTER:('@',"samurai"),(31,05),hostile MONSTER:('@',"samurai"),(32,05),hostile MONSTER:('@',"samurai"),(32,14),hostile MONSTER:('@',"samurai"),(33,14),hostile MONSTER:('@',"samurai"),(34,14),hostile # # The "goal" level for the quest. # # Here you meet Takauji, your nemesis monster. You have to # defeat him in combat to gain the artifact you have been # assigned to retrieve. # MAZE: "Sam-goal", ' ' FLAGS: noteleport GEOMETRY:center,center MAP ....................... ......-------------------...... ......----.................----...... ....----.....-------------.....----.... ....--.....----...........----.....--.... ...||....---....---------....---....||... ...|....--....---.......---....--....|... ....|...||...---...--+--...---...||...|.... ....|...|....|....|-...-|....|....|...|.... ....|...|....|....+.....+....|....|...|.... ....|...|....|....|-...-|....|....|...|.... ....|...||...---...--+--...---...||...|.... ...|....--....---.......---....--....|... ...||....---....---------....---....||... ....--.....----...........----.....--.... ....----.....-------------.....----.... ......----.................----...... ......-------------------...... ....................... ENDMAP # Dungeon Description $place = { (02,11),(42,09) } SHUFFLE: $place REGION:(00,00,44,19),unlit,"ordinary" # Doors DOOR:closed,(19,10) DOOR:closed,(22,08) DOOR:closed,(22,12) DOOR:closed,(25,10) # Stairs STAIR:$place[0],up # Holes in the concentric ring walls $place = { (22,14),(30,10),(22, 6),(14,10) } SHUFFLE:$place TERRAIN:$place[0],'.' $place = { (22, 4),(35,10),(22,16),( 9,10) } SHUFFLE:$place TERRAIN:$place[0],'.' $place = { (22, 2),(22,18) } SHUFFLE:$place TERRAIN:$place[0],'.' # Non diggable walls NON_DIGGABLE:(00,00,44,19) # Objects OBJECT:(')',"tsurugi"),(22,10),blessed,0,name:"The Tsurugi of Muramasa" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # TRAP:"board",(22,09) TRAP:"board",(24,10) TRAP:"board",(22,11) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"Ashikaga Takauji"),(22,10) MONSTER:('@',"samurai"),random,hostile MONSTER:('@',"samurai"),random,hostile MONSTER:('@',"samurai"),random,hostile MONSTER:('@',"samurai"),random,hostile MONSTER:('@',"samurai"),random,hostile MONSTER:('@',"ninja"),random,hostile MONSTER:('@',"ninja"),random,hostile MONSTER:('@',"ninja"),random,hostile MONSTER:('@',"ninja"),random,hostile MONSTER:('@',"ninja"),random,hostile MONSTER:('d',"wolf"),random MONSTER:('d',"wolf"),random MONSTER:('d',"wolf"),random MONSTER:('d',"wolf"),random MONSTER:'d',random MONSTER:'d',random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random MONSTER:('E',"stalker"),random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Sam-fila", ' ' INIT_MAP: mines, '.' , 'P', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: 'd', random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('E', "stalker"), random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Sam-filb", ' ' GEOMETRY:center,center MAP ------------- ------------- |...........| |...........| |...-----...|----------------------------------|...-----...| |...| |...|..................................|...| |...| |...-----..........................................-----...| |...........|--S----------------------------S--|...........| ----...--------.|..........................|.--------...---- |...|........+..........................+........|...| |...|........+..........................+........|...| ----...--------.|..........................|.--------...---- |...........|--S----------------------------S--|...........| |...-----..........................................-----...| |...| |...|..................................|...| |...| |...-----...|----------------------------------|...-----...| |...........| |...........| ------------- ------------- ENDMAP REGION:(00,00,59,15),unlit,"ordinary" # Doors DOOR:closed,(16,07) DOOR:closed,(16,08) DOOR:closed,(43,07) DOOR:closed,(43,08) # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: 'd', random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('d', "wolf"), random MONSTER: ('E', "stalker"), random MONSTER: ('E', "stalker"), random MONSTER: ('E', "stalker"), random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random nethack-3.6.0/dat/Tourist.des0000664000076400007660000004054612536476415015101 0ustar paxedpaxed# NetHack 3.6 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991,92 by M. Stephenson, P. Winner # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Twoflower # and receive your quest assignment. # MAZE: "Tou-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP .......}}....---------..-------------------------------------------------... ........}}...|.......|..|.-------------------------------------------...|... .........}}..|.......|..|.|......|......|.............|......|......|...|... ..........}}.|.......|..|.|......+......+.............+......+..\...|...|... ...........}}}..........|.|......|......|.............|......|......|...|... .............}}.........|.|----S-|--S---|S----------S-|---S--|------|...|... ..............}}}.......|...............................................|... ................}}}.....----S------++--S----------S----------S-----------... ..................}}........... .. ................................... ......-------......}}}}........}}}}..}}}}..}}}}..}}}}....................... ......|.....|.......}}}}}}..}}}} .. }}}}..}}}}..}}}..................... ......|.....+...........}}}}}}........................}}}..}}}}..}}}..}}}... ......|.....|...........................................}}}}..}}}..}}}}.}}}} ......-------............................................................... ............................................................................ ...-------......-------..................................................... ...|.....|......|.....|..................................................... ...|.....+......+.....|..................................................... ...|.....|......|.....|..................................................... ...-------......-------..................................................... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(14,01,20,03),unlit,"morgue" REGION:(07,10,11,12),unlit,"ordinary" REGION:(04,16,08,18),unlit,"ordinary" REGION:(17,16,21,18),unlit,"ordinary" REGION:(27,02,32,04),unlit,"ordinary" REGION:(34,02,39,04),unlit,"ordinary" REGION:(41,02,53,04),unlit,"ordinary" REGION:(55,02,60,04),unlit,"ordinary" REGION:(62,02,67,04),lit,"ordinary" # Stairs STAIR:(66,03),down # Portal arrival point BRANCH:(68,14,68,14),(0,0,0,0) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Doors DOOR:locked,(31,05) DOOR:locked,(36,05) DOOR:locked,(41,05) DOOR:locked,(52,05) DOOR:locked,(58,05) DOOR:locked,(28,07) DOOR:locked,(39,07) DOOR:locked,(50,07) DOOR:locked,(61,07) DOOR:closed,(33,03) DOOR:closed,(40,03) DOOR:closed,(54,03) DOOR:closed,(61,03) DOOR:open,(12,11) DOOR:open,(09,17) DOOR:open,(16,17) DOOR:locked,(35,07) DOOR:locked,(36,07) # Monsters on siege duty. MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: ('s',"giant spider"),random MONSTER: 's',random MONSTER: 's',random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: ('C',"forest centaur"),random MONSTER: 'C',random # Twoflower MONSTER:('@',"Twoflower"),(64,03) # The treasure of Twoflower OBJECT:('(',"chest"),(64,03) # guides for the audience chamber MONSTER:('@',"guide"),(29,03) MONSTER:('@',"guide"),(32,04) MONSTER:('@',"guide"),(35,02) MONSTER:('@',"guide"),(38,03) MONSTER:('@',"guide"),(45,03) MONSTER:('@',"guide"),(48,02) MONSTER:('@',"guide"),(49,04) MONSTER:('@',"guide"),(51,03) MONSTER:('@',"guide"),(57,03) MONSTER:('@',"guide"),(62,04) MONSTER:('@',"guide"),(66,04) # path guards MONSTER:('@',"watchman"),(35,08) MONSTER:('@',"watchman"),(36,08) # river monsters MONSTER:(';',"giant eel"),(62,12) MONSTER:(';',"piranha"),(47,10) MONSTER:(';',"piranha"),(29,11) MONSTER:(';',"kraken"),(34,09) MONSTER:(';',"kraken"),(37,09) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # # The "locate" level for the quest. # # Here you have to find the Thieves' Guild Hall to go # further towards your assigned quest. # MAZE: "Tou-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ---------------------------------------------------------------------------- |....|......|..........|......|......|...|....|.....|......|...............| |....|......|.|------|.|......|......|.|.|....|..}..|......|.|----------|..| |....|--+----.|......|.|-S---+|+-----|.|.S....|.....|---+--|.|..........+..| |....|........|......|.|...|.........|.|------|..............|..........|-+| |....+...}}...+......|.|...|.|-----|.|..............|--+----------------|..| |----|........|------|.|---|.|.....|......|-----+-|.|.......|...........|--| |............................|.....|.|--+-|.......|.|.......|...........|..| |----|.....|-------------|...|--+--|.|....|.......|.|-----------+-------|..| |....+.....+.........S...|...........|....|-------|........................| |....|.....|.........|...|.|---------|....|.........|-------|.|----------|.| |....|.....|---------|---|.|......|..+....|-------|.|.......|.+......S.\.|.| |....|.....+.........S...|.|......|..|....|.......|.|.......|.|......|...|.| |-------|..|.........|---|.|+-------------------+-|.|.......+.|----------|.| |.......+..|---------|.........|.........|..........|.......|.|..........|.| |.......|..............|--+--|.|.........|.|----+-----------|.|..........|.| |---------+-|--+-----|-|.....|.|.........|.|........|.|.....+.|..........+.| |...........|........|.S.....|.|----+----|.|--------|.|.....|.|----------|.| |...........|........|.|.....|........................|.....|..............| ---------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" NON_DIGGABLE:(00,00,75,19) # REGION:(01,01,04,05),unlit,"morgue" REGION:(15,03,20,05),lit,"shop" REGION:(62,03,71,04),lit,"shop" REGION:(01,17,11,18),lit,"barracks" REGION:(12,09,20,10),lit,"barracks" REGION:(53,11,59,14),lit,"zoo" REGION:(63,14,72,16),lit,"barracks" REGION:(32,14,40,16),lit,"temple" # REGION:(06,01,11,02),random,"ordinary" REGION:(24,01,29,02),random,"ordinary" REGION:(31,01,36,02),random,"ordinary" REGION:(42,01,45,03),random,"ordinary" REGION:(53,01,58,02),random,"ordinary" REGION:(24,04,26,05),random,"ordinary" REGION:(30,06,34,07),random,"ordinary" REGION:(73,05,74,05),unlit,"ordinary" REGION:(01,09,04,12),random,"ordinary" REGION:(01,14,07,15),random,"ordinary" REGION:(12,12,20,13),random,"ordinary" REGION:(13,17,20,18),random,"ordinary" REGION:(22,09,24,10),random,"ordinary" REGION:(22,12,24,12),random,"ordinary" REGION:(24,16,28,18),random,"ordinary" REGION:(28,11,33,12),random,"ordinary" REGION:(35,11,36,12),lit,"ordinary" REGION:(38,08,41,12),random,"ordinary" REGION:(43,07,49,08),random,"ordinary" REGION:(43,12,49,12),random,"ordinary" REGION:(44,16,51,16),random,"ordinary" REGION:(53,06,59,07),random,"ordinary" REGION:(61,06,71,07),random,"ordinary" REGION:(55,16,59,18),random,"ordinary" REGION:(63,11,68,12),random,"ordinary" REGION:(70,11,72,12),random,"ordinary" # Stairs STAIR:(10,04),up STAIR:(73,05),down # Non diggable walls NON_DIGGABLE:(00,00,75,19) DOOR:closed,(05,05) DOOR:closed,(05,09) DOOR:closed,(08,14) DOOR:closed,(08,03) DOOR:closed,(11,09) DOOR:closed,(11,12) DOOR:closed,(10,16) DOOR:closed,(14,05) DOOR:closed,(15,16) DOOR:locked,(21,09) DOOR:locked,(21,12) DOOR:closed,(23,17) DOOR:closed,(25,03) DOOR:closed,(26,15) DOOR:closed,(29,03) DOOR:closed,(28,13) DOOR:closed,(31,03) DOOR:closed,(32,08) DOOR:closed,(37,11) DOOR:closed,(36,17) DOOR:locked,(41,03) DOOR:closed,(40,07) DOOR:closed,(48,06) DOOR:closed,(48,13) DOOR:closed,(48,15) DOOR:closed,(56,03) DOOR:closed,(55,05) DOOR:closed,(72,03) DOOR:locked,(74,04) DOOR:closed,(64,08) DOOR:closed,(62,11) DOOR:closed,(69,11) DOOR:closed,(60,13) DOOR:closed,(60,16) DOOR:closed,(73,16) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Toilet paper OBJECT:('?',"blank paper"),(71,12) OBJECT:('?',"blank paper"),(71,12) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:'s',random MONSTER:'s',random # # The "goal" level for the quest. # # Here you meet the Master of Thieves your nemesis monster. You have to # defeat the Master of Thieves in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Tou-goal", ' ' GEOMETRY:center,center MAP ---------------------------------------------------------------------------- |.........|.........|..........|..| |.................|........|........|..| |.........|.........|..........|..| |....--------.....|........|........|..| |------S--|--+-----------+------..| |....|......|.....|........|........|..| |.........|.......................| |....|......+.....--+-------------+--..| |.........|.......................| |....|......|..........................| |-S-----S-|......----------.......| |....|......|..........................| |..|..|...|......|........|.......| |....-----------.........----..........| |..+..+...|......|........|.......| |....|.........|.........|}}|..........| |..|..|...|......+........|.......| |....|.........+.........|}}|..........| |..|..|...|......|........|.......S.S....|.........|.........----..........| |---..----|......|........|.......| |....|.........|.......................| |.........+......|+F-+F-+F|.......| |....-----------.......................| |---..----|......|..|..|..|.......| |......................--------------..| |..|..|...|......--F-F--F--.......| |......................+............|..| |..+..+...|.......................| |--.---...-----+-----..|............|..| |--|..----|--+-----------+------..| |.....|...|.........|..|------------|..| |..+..+...|.........|..........|..| |.....|...|.........|..+............|..| |..|..|...|.........|..........|..| |.....|...|.........|..|............|..| ---------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # The Inn REGION:(01,01,09,02),lit,"ordinary" REGION:(01,04,09,05),lit,"barracks" REGION:(01,07,02,10),unlit,"ordinary" REGION:(07,07,09,10),unlit,"ordinary" REGION:(01,14,02,15),unlit,"ordinary" REGION:(07,14,09,15),unlit,"ordinary" REGION:(01,17,02,18),unlit,"ordinary" REGION:(07,17,09,18),unlit,"ordinary" # REGION:(11,01,19,02),unlit,"barracks" REGION:(21,01,30,02),unlit,"ordinary" REGION:(11,17,19,18),unlit,"barracks" REGION:(21,17,30,18),unlit,"ordinary" # Police Station REGION:(18,07,25,11),lit,"ordinary" REGION:(18,13,19,13),unlit,"ordinary" REGION:(21,13,22,13),unlit,"ordinary" REGION:(24,13,25,13),unlit,"ordinary" # The town itself REGION:(42,03,47,06),unlit,"ordinary" REGION:(42,08,50,11),unlit,"ordinary" REGION:(37,16,41,18),unlit,"morgue" REGION:(47,16,55,18),unlit,"ordinary" REGION:(55,01,62,03),unlit,"ordinary" REGION:(64,01,71,03),unlit,"ordinary" REGION:(60,14,71,15),lit,"shop" REGION:(60,17,71,18),lit,"shop" # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Stairs STAIR:(70,08),up # Doors DOOR:locked,(07,03) DOOR:locked,(02,06) DOOR:locked,(08,06) DOOR:closed,(03,08) DOOR:closed,(06,08) DOOR:open,(10,12) DOOR:closed,(03,15) DOOR:closed,(06,15) DOOR:closed,(03,17) DOOR:closed,(06,17) DOOR:closed,(13,03) DOOR:random,(25,03) DOOR:closed,(13,16) DOOR:random,(25,16) DOOR:locked,(17,09) DOOR:locked,(18,12) DOOR:locked,(21,12) DOOR:locked,(24,12) DOOR:locked,(34,10) DOOR:locked,(36,10) DOOR:random,(48,04) DOOR:random,(56,04) DOOR:random,(70,04) DOOR:random,(51,09) DOOR:random,(51,15) DOOR:open,(59,14) DOOR:open,(59,17) # Objects OBJECT:('(',"credit card"),(04,01),blessed,0,name:"The Platinum Yendorian Express Card" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"Master of Thieves"),(04,01),hostile MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:('s',"giant spider"),random MONSTER:'s',random MONSTER:'s',random # ladies of the evening MONSTER:('&',"succubus"),(02,08) MONSTER:('&',"succubus"),(08,08) MONSTER:('&',"incubus"),(02,14) MONSTER:('&',"incubus"),(08,14) MONSTER:('&',"incubus"),(02,17) MONSTER:('&',"incubus"),(08,17) # Police station (with drunken prisoners) MONSTER:('K',"Kop Kaptain"),(24,09),hostile MONSTER:('K',"Kop Lieutenant"),(20,09),hostile MONSTER:('K',"Kop Lieutenant"),(22,11),hostile MONSTER:('K',"Kop Lieutenant"),(22,07),hostile MONSTER:('K',"Keystone Kop"),(19,07),hostile MONSTER:('K',"Keystone Kop"),(19,08),hostile MONSTER:('K',"Keystone Kop"),(22,09),hostile MONSTER:('K',"Keystone Kop"),(24,11),hostile MONSTER:('K',"Keystone Kop"),(19,11),hostile MONSTER:('@',"prisoner"),(19,13) MONSTER:('@',"prisoner"),(21,13) MONSTER:('@',"prisoner"),(24,13) # MONSTER:('@',"watchman"),(33,10),hostile WALLIFY # # The "fill" level for the quest. # # This level is used to fill out any levels not occupied by specific # levels as defined above. # MAZE: "Tou-fila" , ' ' INIT_MAP: mines, '.' , ' ', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('@', "soldier"), random, hostile MONSTER: ('@', "soldier"), random, hostile MONSTER: ('@', "soldier"), random, hostile MONSTER: ('@', "soldier"), random, hostile MONSTER: ('@', "soldier"), random, hostile MONSTER: 'H', random, hostile MONSTER: 'C', random, hostile MAZE: "Tou-filb" , ' ' INIT_MAP: mines, '.' , ' ', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: ('@', "soldier"), random, hostile MONSTER: ('@', "captain"), random, hostile MONSTER: ('@', "captain"), random, hostile MONSTER: 'H', random, hostile MONSTER: 'H', random, hostile MONSTER: 'C', random, hostile MONSTER: 's', random nethack-3.6.0/dat/Valkyrie.des0000664000076400007660000002421612536476415015212 0ustar paxedpaxed# NetHack 3.6 Valkyrie.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-2 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, the Norn, # and receive your quest assignment. # MAZE: "Val-strt",' ' FLAGS: noteleport,hardfloor,icedpools INIT_MAP:solidfill,'I' $pools = selection: random & random & random & random & random & random & random & random & random & random & random & random & random & grow(west, random) & grow(north, random) & grow(random & random) # This works because the random coordinates in $pools are evaluated once, # when the variable is initialized. TERRAIN:grow($pools), 'P' TERRAIN:$pools, 'L' GEOMETRY:center,center MAP xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..{..xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.....xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..xxxxxxxxxxxxxxxxxxx xxxxxxxx.....xxxxxxxxxxxxx|----------------|xxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxx xxxxxxx..xxx...xxxxxxxxxxx|................|xxxxxxxxxx..xxxxxxxxxxxxxxxxxxxx xxxxxx..xxxxxx......xxxxx.|................|.xxxxxxxxx.xxxxxxxxxxxxxxxxxxxxx xxxxx..xxxxxxxxxxxx.......+................+...xxxxxxx.xxxxxxxxxxxxxxxxxxxxx xxxx..xxxxxxxxx.....xxxxx.|................|.x...xxxxx.xxxxxxxxxxxxxxxxxxxxx xxx..xxxxxxxxx..xxxxxxxxxx|................|xxxx.......xxxxxxxxxxxxxxxxxxxxx xxxx..xxxxxxx..xxxxxxxxxxx|----------------|xxxxxxxxxx...xxxxxxxxxxxxxxxxxxx xxxxxx..xxxx..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxxxx xxxxxxx......xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...xxxxxxxxxxxxxxx xxxxxxxxx...xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...x......xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.........xxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.......xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(27,08,42,12),lit,"ordinary" # Portal arrival point BRANCH:(66,17,66,17),(0,0,0,0) # Stairs STAIR:(18,01),down FOUNTAIN:(53,02) # Doors DOOR:locked,(26,10) DOOR:locked,(43,10) # Norn MONSTER:('@',"Norn"),(35,10) # The treasure of the Norn OBJECT:('(',"chest"),(36,10) # valkyrie guards for the audience chamber MONSTER:('@',"warrior"),(27,08) MONSTER:('@',"warrior"),(27,09) MONSTER:('@',"warrior"),(27,11) MONSTER:('@',"warrior"),(27,12) MONSTER:('@',"warrior"),(42,08) MONSTER:('@',"warrior"),(42,09) MONSTER:('@',"warrior"),(42,11) MONSTER:('@',"warrior"),(42,12) # Non diggable walls NON_DIGGABLE:(26,07,43,13) # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random # Monsters on siege duty. MONSTER: ('a',"fire ant"),(04,12) MONSTER: ('a',"fire ant"),(08,08) MONSTER: ('a',"fire ant"),(14,04) MONSTER: ('a',"fire ant"),(17,11) MONSTER: ('a',"fire ant"),(24,10) MONSTER: ('a',"fire ant"),(45,10) MONSTER: ('a',"fire ant"),(54,02) MONSTER: ('a',"fire ant"),(55,07) MONSTER: ('a',"fire ant"),(58,14) MONSTER: ('a',"fire ant"),(63,17) MONSTER: ('H',"fire giant"),(18,01),hostile MONSTER: ('H',"fire giant"),(10,16),hostile # # The "locate" level for the quest. # # Here you have to find the cave of Surtur to go # further towards your assigned quest. # MAZE: "Val-loca",' ' FLAGS: hardfloor,icedpools INIT_MAP: mines, '.', 'I', true, true, lit, false GEOMETRY:center,center MAP PPPPxxxx xxxxPPPPPx PLPxxx xPPLLLPP PPP ....................... PPPLLP xx ............................ PPPP x ............................... xxxx ................................. xx .................................... x ................................... x .................................. x xx .............................. PP xPPP .......................... PLP xPLLP xxPLLP xPPPPxx xxxxPPPP ENDMAP # Dungeon Description REGION:(00,00,39,12),lit,"ordinary" # Stairs STAIR:(48,14),up STAIR:(20,06),down # Non diggable walls NON_DIGGABLE:(00,00,39,12) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:'a',random MONSTER:'H',random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:'H',random,hostile # # The "goal" level for the quest. # # Here you meet Lord Surtur your nemesis monster. You have to # defeat Lord Surtur in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Val-goal", 'L' FLAGS: icedpools INIT_MAP: mines, '.', 'L', true, true, lit, false GEOMETRY:center,center MAP xxxxxx.....................xxxxxxxx xxxxx.......LLLLL.LLLLL......xxxxxx xxxx......LLLLLLLLLLLLLLL......xxxx xxxx.....LLL|---------|LLL.....xxxx xxxx....LL|--.........--|LL.....xxx x......LL|-...LLLLLLL...-|LL.....xx .......LL|...LL.....LL...|LL......x ......LL|-..LL.......LL..-|LL...... ......LL|.................|LL...... ......LL|-..LL.......LL..-|LL...... .......LL|...LL.....LL...|LL....... xx.....LL|-...LLLLLLL...-|LL......x xxx.....LL|--.........--|LL.....xxx xxxx.....LLL|---------|LLL...xxxxxx xxxxx.....LLLLLLLLLLLLLLL...xxxxxxx xxxxxx......LLLLL.LLLLL.....xxxxxxx xxxxxxxxx..................xxxxxxxx ENDMAP # Dungeon Description REGION:(00,00,34,16),lit,"ordinary" # Stairs # Note: The up stairs are *intentionally* off of the map. STAIR:(45,10),up # Non diggable walls NON_DIGGABLE:(00,00,34,16) # Drawbridges DRAWBRIDGE:(17,02),south,random DRAWBRIDGE:(17,14),north,open # Objects OBJECT:('(',"crystal ball"),(17,08),blessed,5,name:"The Orb of Fate" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Traps TRAP:"board",(13,08) TRAP:"board",(21,08) # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"board",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('H',"Lord Surtur"),(17,08) MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:('a',"fire ant"),random MONSTER:'a',random MONSTER:'a',random MONSTER:('H',"fire giant"),(10,06),hostile MONSTER:('H',"fire giant"),(10,07),hostile MONSTER:('H',"fire giant"),(10,08),hostile MONSTER:('H',"fire giant"),(10,09),hostile MONSTER:('H',"fire giant"),(10,10),hostile MONSTER:('H',"fire giant"),(24,06),hostile MONSTER:('H',"fire giant"),(24,07),hostile MONSTER:('H',"fire giant"),(24,08),hostile MONSTER:('H',"fire giant"),(24,09),hostile MONSTER:('H',"fire giant"),(24,10),hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:('H',"fire giant"),random,hostile MONSTER:'H',random,hostile # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Val-fila" , 'I' FLAGS: icedpools INIT_MAP: mines, '.', 'I', true, true, lit, false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('a', "fire ant"), random MONSTER: ('a', "fire ant"), random MONSTER: ('a', "fire ant"), random MONSTER: ('a', "fire ant"), random MONSTER: ('a', "fire ant"), random MONSTER: 'a', random MONSTER: ('H', "fire giant"), random, hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Val-filb" , 'L' FLAGS: icedpools INIT_MAP: mines, '.', 'L', true, true, lit, false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('a', "fire ant"), random MONSTER: ('a', "fire ant"), random MONSTER: ('a', "fire ant"), random MONSTER: 'a', random MONSTER: ('H', "fire giant"), random, hostile MONSTER: ('H', "fire giant"), random, hostile MONSTER: ('H', "fire giant"), random, hostile # TRAP: "fire", random TRAP: "fire", random TRAP: "fire", random TRAP: "fire", random TRAP: "fire", random TRAP: random, random TRAP: random, random nethack-3.6.0/dat/Wizard.des0000664000076400007660000003574512536476415014675 0ustar paxedpaxed# NetHack 3.6 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ # Copyright (c) 1992 by David Cohrs # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Neferet the Green # and receive your quest assignment. # MAZE: "Wiz-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ .....................C....CC.C........................C..................... ..........CCC.....................CCC....................................... ........CC........-----------.......C.C...C...C....C........................ .......C.....---------------------...C..C..C..C............................. ......C..C...------....\....------....C.....C............................... ........C...||....|.........|....||......................................... .......C....||....|.........+....||......................................... .......C...||---+--.........|....|||........................................ ......C....||...............|--S--||........................................ ...........||--+--|++----|---|..|.SS..........C......C...................... ........C..||.....|..|...|...|--|.||..CC..C.....C..........C................ .......C...||.....|..|.--|.|.|....||.................C..C................... .....C......||....|..|.....|.|.--||..C..C..........C...........}}}.......... ......C.C...||....|..-----.|.....||...C.C.C..............C....}}}}}}........ .........C...------........|------....C..C.....C..CC.C......}}}}}}}}}}}..... .........CC..---------------------...C.C..C.....CCCCC.C.......}}}}}}}}...... .........C........-----------..........C.C.......CCC.........}}}}}}}}}...... ..........C.C.........................C............C...........}}}}}........ ......................CCC.C................................................. ENDMAP # first do cloud everywhere REPLACE_TERRAIN:(0,0, 75,19), '.', 'C', 10% # then replace clouds inside the tower back to floor REPLACE_TERRAIN:(13,5, 33,15), 'C', '.', 100% # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(35,00,49,03),unlit,"ordinary" REGION:(43,12,49,16),unlit,"ordinary" REGION:(19,11,33,15),unlit,"ordinary",unfilled,irregular REGION:(30,10,31,10),unlit,"ordinary" # Stairs STAIR:(30,10),down # Portal arrival point TERRAIN:(63,06),'.' BRANCH:(63,06,63,06),(0,0,0,0) # Doors DOOR:closed,(31,09) DOOR:closed,(16,08) DOOR:closed,(28,07) DOOR:locked,(34,10) DOOR:locked,(35,10) DOOR:closed,(15,10) DOOR:locked,(19,10) DOOR:locked,(20,10) # Neferet the Green, the quest leader MONSTER:('@',"Neferet the Green"),(23,05) # The treasure of the quest leader OBJECT:('(',"chest"),(24,05) # apprentice guards for the audience chamber MONSTER:('@',"apprentice"),(30,07) MONSTER:('@',"apprentice"),(24,06) MONSTER:('@',"apprentice"),(15,06) MONSTER:('@',"apprentice"),(15,12) MONSTER:('@',"apprentice"),(26,11) MONSTER:('@',"apprentice"),(27,11) MONSTER:('@',"apprentice"),(19,09) MONSTER:('@',"apprentice"),(20,09) # Eels in the pond MONSTER:(';',"giant eel"),(62,14) MONSTER:(';',"giant eel"),(69,15) MONSTER:(';',"giant eel"),(67,17) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'B',(60,09),hostile MONSTER: 'W',(60,10),hostile MONSTER: 'B',(60,11),hostile MONSTER: 'B',(60,12),hostile MONSTER: 'i',(60,13),hostile MONSTER: 'B',(61,10),hostile MONSTER: 'B',(61,11),hostile MONSTER: 'B',(61,12),hostile MONSTER: 'B',(35,03),hostile MONSTER: 'i',(35,17),hostile MONSTER: 'B',(36,17),hostile MONSTER: 'B',(34,16),hostile MONSTER: 'i',(34,17),hostile MONSTER: 'W',(67,02),hostile MONSTER: 'B',(10,19),hostile # # The "locate" level for the quest. # # Here you have to find the Entrance to the Tower of Darkness to go # further towards your assigned quest. # MAZE: "Wiz-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............. ....................................................... .............. .............}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}....... .............. ..............}.................................}....... .............. ..............}.-------------------------------.}....... ............... .........C....}.|.............................|.}....... ............... ..........C....}.|.---------------------------.|.}....... ............... .........CCC...}.|.|.........................|.|.}....... ................ ....C....CCC...}.|.|.-----------------------.|.|.}....... .......C..C..... .....C....CCC...}.|.|.|......+.......+......|.|.|.}....... .............C..CC.....C....CCC...}.|.|.|......|-------|......|.|.|.}....... ................ ....C....CCC...}.|.|.|......|.......|......|.|.|.}....... ......C..C..... ....C....CCC...}.|.|.|......|-------|......|.|.|.}....... ............C.. ...C....CCC...}.|.|.|......+.......+......|.|.|.}....... ........C...... ....C....CCC...}.|.|.-----------------------.|.|.}....... ....C......C... ........CCC...}.|.|.........................|.|.}....... ......C..C.... .........C....}.|.---------------------------.|.}....... .............. .........C....}.|.............................|.}....... ............. ..............}.-------------------------------.}....... ............. .............}.................................}....... ............. .............}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}....... ............. ....................................................... ENDMAP REPLACE_TERRAIN:(0,0,30,20), '.', 'C', 15% REPLACE_TERRAIN:(68,0,75,20), '.', '}', 25% REPLACE_TERRAIN:(34,1,68,19), '}', '.', 2% # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" REGION:(37,04,65,16),unlit,"ordinary",filled,irregular { ROOMDOOR:true,closed,north|south|west|east,random } REGION:(39,06,63,14),unlit,"ordinary",filled,irregular { ROOMDOOR:true,closed,north|south|west|east,random } REGION:(41,08,46,12),lit,"ordinary",filled,irregular { ROOMDOOR:true,closed,north|south|west,random } REGION:(56,08,61,12),lit,"ordinary",filled,irregular { ROOMDOOR:true,closed,north|south|east,random } REGION:(48,08,54,08),unlit,"ordinary" REGION:(48,12,54,12),unlit,"ordinary" REGION:(48,10,54,10),unlit,"ordinary",filled,irregular { ROOMDOOR:true,closed,north|south|west|east,random } # Doors DOOR:locked,(55,08) DOOR:locked,(55,12) DOOR:locked,(47,08) DOOR:locked,(47,12) # Stairs TERRAIN:(03,17),'.' STAIR:(03,17),up STAIR:(48,10),down # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:"spiked pit",(24,02) TRAP:"spiked pit",(07,10) TRAP:"spiked pit",(23,05) TRAP:"spiked pit",(26,19) TRAP:"spiked pit",(72,02) TRAP:"spiked pit",(72,12) TRAP:"falling rock",(45,16) TRAP:"falling rock",(65,13) TRAP:"falling rock",(55,06) TRAP:"falling rock",(39,11) TRAP:"falling rock",(57,09) TRAP:"magic",random TRAP:"statue",random TRAP:"statue",random TRAP:"polymorph",random TRAP:"anti magic",(53,10) TRAP:"sleep gas",random TRAP:"sleep gas",random TRAP:"dart",random TRAP:"dart",random TRAP:"dart",random # Random monsters. MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:'i',random,hostile # # The "goal" level for the quest. # # Here you meet the Dark One, your nemesis monster. You have to # defeat the Dark One in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Wiz-goal", ' ' GEOMETRY:center,center MAP ------------- ------------- |...........| |...........| -------|...........-------------------...........| |......S...........|..|..|..|..|..|..|...........| |......|...........|..|..|..|..|..|..|...........| |......|...........-F+-F+-F+-F+-F+-F+-...........| --S----|...........S.................+...........| |......|...........-F+-F+-F+-F+-F+-F+-...........| |......|...........|..|..|..|..|..|..|...........| |......|...........|..|..|..|..|..|..|...........| -------|...........-------------------...........| |...........| |...........| ------------- ------------- ENDMAP # Dungeon Description REGION:(13,10,18,12),unlit,"temple" REGION:(13,06,18,08),lit,"ordinary" REGION:(20,04,30,14),unlit,"ordinary" REGION:(32,06,33,07),unlit,"ordinary" REGION:(35,06,36,07),unlit,"ordinary" REGION:(38,06,39,07),unlit,"ordinary" REGION:(41,06,42,07),unlit,"ordinary" REGION:(44,06,45,07),unlit,"ordinary" REGION:(47,06,48,07),unlit,"ordinary" REGION:(32,09,48,09),unlit,"ordinary" REGION:(32,11,33,12),unlit,"ordinary" REGION:(35,11,36,12),unlit,"ordinary" REGION:(38,11,39,12),unlit,"ordinary" REGION:(41,11,42,12),unlit,"ordinary" REGION:(44,11,45,12),unlit,"ordinary" REGION:(47,11,48,12),unlit,"ordinary" REGION:(50,04,60,14),lit,"ordinary" # Doors DOOR:locked,(19,06) DOOR:locked,(14,09) DOOR:locked,(31,09) DOOR:locked,(33,08) DOOR:locked,(36,08) DOOR:locked,(39,08) DOOR:locked,(42,08) DOOR:locked,(45,08) DOOR:locked,(48,08) DOOR:locked,(33,10) DOOR:locked,(36,10) DOOR:locked,(39,10) DOOR:locked,(42,10) DOOR:locked,(45,10) DOOR:locked,(48,10) DOOR:locked,(49,09) # Stairs STAIR:(55,05),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # The altar. This is not a shrine. ALTAR:(16,11),noncoaligned,altar # Objects OBJECT:('"',"amulet of ESP"),(16,11),blessed,0,name:"The Eye of the Aethiopica" OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('@',"Dark One"),(16,11) MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'B',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:'i',random,hostile MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:'i',random,hostile # Captive Monsters in the dungeon MONSTER:('@',"rogue"),(35,06),peaceful,"Pug" MONSTER:('Y',"owlbear"),(47,06),peaceful,asleep MONSTER:('@',"wizard"),(32,11),peaceful,asleep,"Newt" MONSTER:('@',"Grey-elf"),(44,11),peaceful MONSTER:('H',"hill giant"),(47,11),peaceful,asleep MONSTER:('G',"gnomish wizard"),(38,06),peaceful MONSTER:('@',"prisoner"),(35,11),peaceful MONSTER:('@',"prisoner"),(41,11),peaceful,asleep # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # LEVEL: "Wiz-fila" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: 'i', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: 'i', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: ('B', "vampire bat"), random MONSTER: ('B', "vampire bat"), random } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: 'i', random, hostile MONSTER: ('B', "vampire bat"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: 'i', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: ('B', "vampire bat"), random } RANDOM_CORRIDORS LEVEL: "Wiz-filb" # ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random MONSTER: 'X', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random,random MONSTER: 'i', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random OBJECT: random,random MONSTER: 'X', random, hostile } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: 'i', random, hostile MONSTER: ('B', "vampire bat"), random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random TRAP: random, random MONSTER: 'i', random, hostile } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: ('B', "vampire bat"), random } RANDOM_CORRIDORS nethack-3.6.0/dat/bigroom.des0000664000076400007660000005707612536476415015074 0ustar paxedpaxed# NetHack 3.6 bigroom.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1990 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # These are the bigroom levels: # MAZE:"bigrm-1",' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| --------------------------------------------------------------------------- ENDMAP $terrains = TERRAIN:{'-', 'F', 'L', 'T', 'C'} SHUFFLE:$terrains [50%]: SWITCH [ 4 ] { CASE 0: TERRAIN:line (10,8),(65, 8), $terrains[0] BREAK CASE 1: TERRAIN:line (15,4),(15, 13), $terrains[0] TERRAIN:line (59,4),(59, 13), $terrains[0] BREAK CASE 2: TERRAIN:line (10,8),(38, 8), $terrains[0] TERRAIN:line (37,8),(65, 8), $terrains[0] TERRAIN:line (37,3),(37, 8), $terrains[0] TERRAIN:line (37,8),(37,14), $terrains[0] BREAK CASE 3: TERRAIN:rect (4,4,70,13), $terrains[0] TERRAIN:line (25, 4),(50, 4), '.' TERRAIN:line (25,13),(50,13), '.' BREAK DEFAULT: } # Dungeon Description REGION:(01,01,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random # Here, just play with the lighting... MAZE:"bigrm-2",' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| --------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(01,01,23,06),lit,"ordinary" REGION:(01,07,23,10),unlit,"ordinary" REGION:(01,11,23,16),lit,"ordinary" REGION:(24,01,50,06),unlit,"ordinary" REGION:(24,07,50,10),lit,"ordinary" REGION:(24,11,50,16),unlit,"ordinary" REGION:(51,01,73,06),lit,"ordinary" REGION:(51,07,73,10),unlit,"ordinary" REGION:(51,11,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random # Now, let's get fancy... MAZE:"bigrm-3",' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| |.........................................................................| |.........................................................................| |.........................................................................| |..............---.......................................---..............| |...............|.........................................|...............| |.....|.|.|.|.|---|.|.|.|.|...................|.|.|.|.|.|---|.|.|.|.|.....| |.....|-------- --------|...................|---------- --------|.....| |.....|.|.|.|.|---|.|.|.|.|...................|.|.|.|.|.|---|.|.|.|.|.....| |...............|.........................................|...............| |..............---.......................................---..............| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| --------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(01,01,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,(01,01) MONSTER:random,(13,01) MONSTER:random,(25,01) MONSTER:random,(37,01) MONSTER:random,(49,01) MONSTER:random,(61,01) MONSTER:random,(73,01) MONSTER:random,(07,07) MONSTER:random,(13,07) MONSTER:random,(25,07) MONSTER:random,(37,07) MONSTER:random,(49,07) MONSTER:random,(61,07) MONSTER:random,(67,07) MONSTER:random,(07,09) MONSTER:random,(13,09) MONSTER:random,(25,09) MONSTER:random,(37,09) MONSTER:random,(49,09) MONSTER:random,(61,09) MONSTER:random,(67,09) MONSTER:random,(01,16) MONSTER:random,(13,16) MONSTER:random,(25,16) MONSTER:random,(37,16) MONSTER:random,(49,16) MONSTER:random,(61,16) MONSTER:random,(73,16) MAZE:"bigrm-4",' ' GEOMETRY:center,center MAP ----------- ----------- |.........| |.........| |.........|-----------| |-----------|.........| |-|...................|----------| |----------|...................|-| -|.............................|-------|.............................|- -|.................................................................|- -|...............................................................|- -|.............................................................|- -|...........................................................|- -|...........................................................|- -|.............................................................|- -|...............................................................|- -|.................................................................|- -|.............................|-------|.............................|- |-|...................|----------| |----------|...................|-| |.........|-----------| |-----------|.........| |.........| |.........| ----------- ----------- ENDMAP # Dungeon Description REGION:(01,01,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Fountains FOUNTAIN:(05,02) FOUNTAIN:(05,15) FOUNTAIN:(69,02) FOUNTAIN:(69,15) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random # Try an oval room... MAZE:"bigrm-5",' ' GEOMETRY:center,center MAP ------------------ ---------................--------- -------................................------- ------............................................------ ----......................................................---- ---............................................................--- ---................................................................--- ---....................................................................--- |........................................................................| |........................................................................| |........................................................................| ---....................................................................--- ---................................................................--- ---............................................................--- ----......................................................---- ------............................................------ -------................................------- ---------................--------- ------------------ ENDMAP # Dungeon Description REGION:(00,00,72,18),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,72,18) # Objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random # The Four Circles LEVEL:"bigrm-6" FLAGS:mazelevel INIT_MAP:solidfill,' ' GEOMETRY:center,center MAP --------- --------- --------- --------- ---.......--- ---.......--- ---.......--- ---.......--- --...........-- --...........-- --...........-- --...........-- --.............-- --.............-- --.............-- --.............-- -...............- -...............- -...............- -...............- |-...............---...............---...............---...............-- |.................-.................-.................-.................| |........T.................T.................T.................T........| |.......................................................................| |......T.{.....................................................{.T......| |.......................................................................| |........T.................T.................T.................T........| |.................-.................-.................-.................| --...............---...............---...............---...............-- -...............- -...............- -...............- -...............- --.............-- --.............-- --.............-- --.............-- --...........-- --...........-- --...........-- --...........-- ---.......--- ---.......--- ---.......--- ---.......--- --------- --------- --------- --------- ENDMAP REGION:(01,01,72,17),lit,"ordinary" STAIR:random,up STAIR:random,down NON_DIGGABLE:(00,00,72,18) LOOP [15] { OBJECT:random,random } LOOP [6] { TRAP:random,random } LOOP [28] { MONSTER:random,random } # Let's tilt it a bit LEVEL:"bigrm-7" FLAGS:mazelevel INIT_MAP:solidfill,' ' GEOMETRY:center,center MAP ----- ---------...--- ---------.........L...--- ---------.......................--- ---------.................................--- ---------...........................................--- ---------.....................................................--- |--------...............................................................--| |.........................................................................| |.L.....................................................................L.| |.........................................................................| |--...............................................................--------| ---.....................................................--------- ---...........................................--------- ---.................................--------- ---.......................--------- ---...L.........--------- ---...--------- ----- ENDMAP $terrain = terrain:{ 'L', 'T', '{', '.' } SHUFFLE:$terrain REPLACE_TERRAIN:(00,00,74,18),'L',$terrain[0],100% REGION:(01,01,73,17),lit,"ordinary" STAIR:random,up STAIR:random,down NON_DIGGABLE:(00,00,74,18) LOOP [15] { OBJECT:random,random } LOOP [6] { TRAP:random,random } LOOP [28] { MONSTER:random,random } # Slanted LEVEL:"bigrm-8" FLAGS:mazelevel INIT_MAP:solidfill,' ' GEOMETRY:center,center MAP ---------------------------------------------- |............................................--- --.............................................--- ---......................................FF.....--- ---...................................FF........--- ---................................FF...........--- ---.............................FF..............--- ---..........................FF.................--- ---.......................FF....................--- ---....................FF.......................--- ---.................FF..........................--- ---..............FF.............................--- ---...........FF................................---- ---........FF...................................--- ---.....FF......................................--- ---.............................................-- ---............................................| ---------------------------------------------- ENDMAP IF [40%] { $terrain = TERRAIN:{ 'L', '}', 'T', '.', '-', 'C' } SHUFFLE:$terrain REPLACE_TERRAIN:(0,0,74,17),'F', $terrain[0], 100% } REGION:(01,01,73,16),lit,"ordinary" STAIR:random,up STAIR:random,down NON_DIGGABLE:(00,00,74,17) LOOP [15] { OBJECT:random,random } LOOP [6] { TRAP:random,random } LOOP [28] { MONSTER:random,random } # The Eye LEVEL:"bigrm-9" FLAGS:mazelevel GEOMETRY:center,center MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}................}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}................................}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}............................................}}}}}}}}}}}}}}} }}}}}}}}}}......................................................}}}}}}}}}} }}}}}}}............................................................}}}}}}} }}}}}.......................LLLLLLLLLLLLLLLLLL.......................}}}}} }}}....................LLLLLLLLLLLLLLLLLLLLLLLLLLL.....................}}} }....................LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL....................} }....................LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL....................} }....................LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL....................} }}}....................LLLLLLLLLLLLLLLLLLLLLLLLLLL.....................}}} }}}}}.......................LLLLLLLLLLLLLLLLLL.......................}}}}} }}}}}}}............................................................}}}}}}} }}}}}}}}}}......................................................}}}}}}}}}} }}}}}}}}}}}}}}}............................................}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}................................}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}................}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP # Unlit, except 3 mapgrids around the "pupil" REGION:(00,00,73,18),unlit,"ordinary" REGION:(26,04,47,14),lit,"ordinary" REGION:(21,05,51,13),lit,"ordinary" REGION:(19,06,54,12),lit,"ordinary" STAIR:random,up STAIR:random,down LOOP [15] { OBJECT:random,random } LOOP [6] { TRAP:random,random } LOOP [28] { MONSTER:random,random } # Fog Maze LEVEL:"bigrm-10" FLAGS:mazelevel GEOMETRY:center,center MAP ....................................................................... ....................................................................... ....................................................................... ....................................................................... ...C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C... ...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC... ...C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C... ...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC... ...C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C... ...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC... ...C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C... ...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC... ...C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C... ...CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC... ...C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C C... ....................................................................... ....................................................................... ....................................................................... ....................................................................... ENDMAP IF [33%] { # occasionally it's not a fog maze $terrain = TERRAIN:{ 'L', '}', 'T', '-', 'F' } SHUFFLE:$terrain # break it up a bit REPLACE_TERRAIN:(0,0,70,18),'C', '.', 5% REPLACE_TERRAIN:(0,0,70,18),'C', $terrain[0], 100% } REGION:(00,00,70,18),lit,"ordinary" # when falling down on this level, never end up in the fog maze TELEPORT_REGION:(00,00,70,18),(02,03,68,15),down LOOP [15] { OBJECT:random,random } LOOP [6] { TRAP:random,random } LOOP [28] { MONSTER:random,random } MAZEWALK:(4, 2), south # Stairs up, not in the fog maze STAIR:(00,00,70,18),(02,03,68,15),up STAIR:random,down nethack-3.6.0/dat/bogusmon.txt0000664000076400007660000001320512624601020015271 0ustar paxedpaxed# Hallucinatory monsters # # # prefix codes: # dash - female, personal name # underscore _ female, general name # plus + male, personal name # vertical bar | male, general name # equals = gender not specified, personal name # misc. jumbo shrimp giant pigmy gnu killer penguin giant cockroach giant slug maggot pterodactyl tyrannosaurus rex basilisk beholder nightmare efreeti marid rot grub bookworm master lichen shadow hologram jester attorney sleazoid killer tomato amazon robot battlemech rhinovirus harpy lion-dog rat-ant Y2K bug angry mariachi arch-pedant bluebird of happiness cardboard golem duct tape golem diagonally moving grid bug evil overlord newsgroup troll ninja pirate zombie robot octarine dragon gonzo journalist lag monster loan shark possessed waffle iron poultrygeist stuffed raccoon puppet viking wee green blobbie wereplatypus hag of bolding blancmange raging nerd spelling bee land octopus frog prince pigasus _Semigorgon conventioneer large microbat small megabat uberhulk tofurkey +Dudley # Quendor (Zork, &c.) grue Christmas-tree monster luck sucker paskald brogmoid dornbeast # Moria Ancient Multi-Hued Dragon +Evil Iggy # Rogue V5 http://rogue.rogueforge.net/vade-mecum/ rattlesnake ice monster phantom quagga aquator griffin emu kestrel xeroc venus flytrap # Wizardry creeping coins # Greek legend hydra siren # Monty Python killer bunny # The Princess Bride rodent of unusual size # Wallace & Gromit were-rabbit # "Only you can prevent forest fires! +Smokey Bear # Discworld Luggage # Lord of the Rings Ent # Xanth tangle tree nickelpede wiggle # Lewis Carroll white rabbit snark # Dr. Dolittle pushmi-pullyu # The Smurfs smurf # Star Trek tribble Klingon Borg # Star Wars Ewok # Tonari no Totoro Totoro # Nausicaa ohmu # Sailor Moon youma # Pokemon (Meowth) nyaasu # monster movies -Godzilla +King Kong # old L of SH earthquake beast # Robotech Invid # The Terminator Terminator # Bubblegum Crisis boomer # Dr. Who ("Exterminate!") Dalek # HGttG microscopic space fleet Ravenous Bugblatter Beast of Traal # TMNT teenage mutant ninja turtle # Usagi Yojimbo samurai rabbit # Cerebus aardvark # Little Shop of Horrors =Audrey II # 50's rock 'n' roll witch doctor one-eyed one-horned flying purple people eater # saccharine kiddy TV +Barney the dinosaur # Angband +Morgoth # Babylon 5 Vorlon # King Arthur questing beast # Movie Predator # common pest mother-in-law # Actual creatures praying mantis beluga whale chicken coelacanth star-nosed mole lungfish slow loris sea cucumber tapeworm liger velociraptor corpulent porpoise quokka potoo # european cryptids wolpertinger elwedritsche skvader +Nessie tatzelwurm dahu # fictitious beasts dropbear wild haggis jackalope flying pig hippocampus hippogriff kelpie catoblepas phoenix amphisbaena # Unusually animate body parts bouncing eye floating nose wandering eye # Computerese buffer overflow dangling pointer walking disk drive floating point regex engine netsplit wiki peer COBOL # bugs bohrbug mandelbug schroedinbug heisenbug # DooM cacodemon scrag # MST3K +Crow T. Robot # Items and stuff chess pawn chocolate pudding ooblecks terracotta warrior hearse roomba miniature blimp dust speck # DnD monster gazebo # SciFi elements gray goo magnetic monopole first category perpetual motion device # Ultima +Lord British # They Might Be Giants particle man # Robot Finds Kitten kitten prospecting robot # Typography guillemet solidus obelus dingbat bold face boustrophedon ligature rebus # Their actual character apostrophe golem voluptuous ampersand # Web comics and animation +Bob the angry flower +Strong Bad +Magical Trevor # KoL one-winged dewinged stab-bat # deities Invisible Pink Unicorn Flying Spaghetti Monster # Monkey Island three-headed monkey +El Pollo Diablo # modern folklore little green man # Portal weighted Companion Cube # /b/ /b/tard # South Park manbearpig # internet memes bonsai-kitten tie-thulu +Domo-kun looooooooooooong cat nyan cat # the Internet is made for cat pix ceiling cat basement cat monorail cat # POWDER tridude # Radomir Dopieralski orcus cosmicus # Angband yeek quylthulg Greater Hell Beast # Souljazz +Vendor of Yizard # Dungeon Crawl Stone Soup +Sigmund lernaean hydra +Ijyb +Gloorx Vloq +Blork the orc # Wil Wheaton, John Scalzi unicorn pegasus kitten # Minecraft enderman # Pun wight supremacist # Starcraft 2 zergling # Feelings existential angst figment of your imagination flash of insight # Fish ghoti # Roald Dahl vermicious knid # Carcassonne meeple # The Wombles womble # Fraggle Rock fraggle # Spoonerism mock role # Truly scary things clown mime peddler haggler # soundex and typos of monsters gloating eye flush golem martyr orc mortar orc acid blog acute blob aria elemental aliasing priest aligned parasite aligned parquet aligned proctor baby balky dragon baby blues dragon baby caricature baby crochet baby grainy dragon baby bong worm baby long word baby parable worm barfed devil beer wight boor wight brawny mold rave spider clue golem bust vortex errata elemental elastic eel electrocardiogram eel fir elemental tire elemental flamingo sphere fallacy golem frizzed centaur forest centerfold fierceness sphere frosted giant geriatric snake gnat ant giant bath grant beetle grind bug giant mango glossy golem gnome laureate gnome dummy gooier ooze green slide guardian nacho hell hound pun high purist hairnet devil ice trowel killer beet feather golem lounge worm mountain lymph pager golem pie fiend prophylactic worm sock mole rogue piercer seesawing sphere simile mimic moldier ant stain vortex scone giant umbrella hulk vampire mace verbal jabberwock water lemon water melon winged grizzly yellow wight nethack-3.6.0/dat/castle.des0000664000076400007660000001661612536476415014704 0ustar paxedpaxed# NetHack 3.6 castle.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ # Copyright (c) 1989 by Jean-Christophe Collet # NetHack may be freely redistributed. See license for details. # # This is the stronghold level : # there are several ways to enter it : # - opening the drawbridge (wand of opening, knock spell, playing # the appropriate tune) # # - enter via the back entry (this suppose a ring of levitation, boots # of water walking, etc.) # # Note : If you don't play the right tune, you get indications like in the # MasterMind game... # # To motivate the player : there are 4 storerooms (armors, weapons, food and # gems) and a wand of wishing in one of the 4 towers... MAZE:"castle",random FLAGS: noteleport GEOMETRY:center,center MAP }}}}}}}}}.............................................}}}}}}}}} }-------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------} }|.....|-----------------------------------------------|.....|} }|.....+...............................................+.....|} }-------------------------------+-----------------------------} }}}}}}|........|..........+...........|.......S.S.......|}}}}}} .....}|........|..........|...........|.......|.|.......|}..... .....}|........------------...........---------S---------}..... .....}|...{....+..........+.........\.S.................+...... .....}|........------------...........---------S---------}..... .....}|........|..........|...........|.......|.|.......|}..... }}}}}}|........|..........+...........|.......S.S.......|}}}}}} }-------------------------------+-----------------------------} }|.....+...............................................+.....|} }|.....|-----------------------------------------------|.....|} }-------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------} }}}}}}}}}.............................................}}}}}}}}} ENDMAP # Random registers initialisation $object = object: { '[',')','*','%' } SHUFFLE: $object $place = { (04,02),(58,02),(04,14),(58,14) } SHUFFLE: $place $monster = monster: { 'L','N','E','H','M','O','R','T','X','Z' } SHUFFLE: $monster TELEPORT_REGION:levregion(01,00,10,20),(1,1,61,15),down TELEPORT_REGION:levregion(69,00,79,20),(1,1,61,15),up STAIR:levregion(01,00,10,20),(0,0,62,16),up FOUNTAIN:(10,08) # Doors DOOR:closed,(07,03) DOOR:closed,(55,03) DOOR:locked,(32,04) DOOR:locked,(26,05) DOOR:locked,(46,05) DOOR:locked,(48,05) DOOR:locked,(47,07) DOOR:closed,(15,08) DOOR:closed,(26,08) DOOR:locked,(38,08) DOOR:locked,(56,08) DOOR:locked,(47,09) DOOR:locked,(26,11) DOOR:locked,(46,11) DOOR:locked,(48,11) DOOR:locked,(32,12) DOOR:closed,(07,13) DOOR:closed,(55,13) # The drawbridge DRAWBRIDGE:(05,08),east,closed # Storeroom number 1 OBJECT:$object[0],(39,05) OBJECT:$object[0],(40,05) OBJECT:$object[0],(41,05) OBJECT:$object[0],(42,05) OBJECT:$object[0],(43,05) OBJECT:$object[0],(44,05) OBJECT:$object[0],(45,05) OBJECT:$object[0],(39,06) OBJECT:$object[0],(40,06) OBJECT:$object[0],(41,06) OBJECT:$object[0],(42,06) OBJECT:$object[0],(43,06) OBJECT:$object[0],(44,06) OBJECT:$object[0],(45,06) # Storeroom number 2 OBJECT:$object[1],(49,05) OBJECT:$object[1],(50,05) OBJECT:$object[1],(51,05) OBJECT:$object[1],(52,05) OBJECT:$object[1],(53,05) OBJECT:$object[1],(54,05) OBJECT:$object[1],(55,05) OBJECT:$object[1],(49,06) OBJECT:$object[1],(50,06) OBJECT:$object[1],(51,06) OBJECT:$object[1],(52,06) OBJECT:$object[1],(53,06) OBJECT:$object[1],(54,06) OBJECT:$object[1],(55,06) # Storeroom number 3 OBJECT:$object[2],(39,10) OBJECT:$object[2],(40,10) OBJECT:$object[2],(41,10) OBJECT:$object[2],(42,10) OBJECT:$object[2],(43,10) OBJECT:$object[2],(44,10) OBJECT:$object[2],(45,10) OBJECT:$object[2],(39,11) OBJECT:$object[2],(40,11) OBJECT:$object[2],(41,11) OBJECT:$object[2],(42,11) OBJECT:$object[2],(43,11) OBJECT:$object[2],(44,11) OBJECT:$object[2],(45,11) # Storeroom number 4 OBJECT:$object[3],(49,10) OBJECT:$object[3],(50,10) OBJECT:$object[3],(51,10) OBJECT:$object[3],(52,10) OBJECT:$object[3],(53,10) OBJECT:$object[3],(54,10) OBJECT:$object[3],(55,10) OBJECT:$object[3],(49,11) OBJECT:$object[3],(50,11) OBJECT:$object[3],(51,11) OBJECT:$object[3],(52,11) OBJECT:$object[3],(53,11) OBJECT:$object[3],(54,11) OBJECT:$object[3],(55,11) # THE WAND OF WISHING in 1 of the 4 towers CONTAINER:('(',"chest"),not_trapped,$place[0] { OBJECT:('/',"wishing") } # Prevent monsters from eating it. (@'s never eat objects) ENGRAVING:$place[0],burn,"Elbereth" OBJECT:('?',"scare monster"),$place[0],cursed # The treasure of the lord OBJECT:('(',"chest"),(37,08) # Traps TRAP:"trap door",(40,08) TRAP:"trap door",(44,08) TRAP:"trap door",(48,08) TRAP:"trap door",(52,08) TRAP:"trap door",(55,08) # Soldiers guarding the entry hall MONSTER:('@',"soldier"),(08,06) MONSTER:('@',"soldier"),(09,05) MONSTER:('@',"soldier"),(11,05) MONSTER:('@',"soldier"),(12,06) MONSTER:('@',"soldier"),(08,10) MONSTER:('@',"soldier"),(09,11) MONSTER:('@',"soldier"),(11,11) MONSTER:('@',"soldier"),(12,10) MONSTER:('@',"lieutenant"),(09,08) # Soldiers guarding the towers MONSTER:('@',"soldier"),(03,02) MONSTER:('@',"soldier"),(05,02) MONSTER:('@',"soldier"),(57,02) MONSTER:('@',"soldier"),(59,02) MONSTER:('@',"soldier"),(03,14) MONSTER:('@',"soldier"),(05,14) MONSTER:('@',"soldier"),(57,14) MONSTER:('@',"soldier"),(59,14) # The four dragons that are guarding the storerooms MONSTER:'D',(47,05) MONSTER:'D',(47,06) MONSTER:'D',(47,10) MONSTER:'D',(47,11) # Sea monsters in the moat MONSTER:(';',"giant eel"),(05,07) MONSTER:(';',"giant eel"),(05,09) MONSTER:(';',"giant eel"),(57,07) MONSTER:(';',"giant eel"),(57,09) MONSTER:(';',"shark"),(05,00) MONSTER:(';',"shark"),(05,16) MONSTER:(';',"shark"),(57,00) MONSTER:(';',"shark"),(57,16) # The throne room and the court monsters MONSTER:$monster[0],(27,05) MONSTER:$monster[1],(30,05) MONSTER:$monster[2],(33,05) MONSTER:$monster[3],(36,05) MONSTER:$monster[4],(28,06) MONSTER:$monster[5],(31,06) MONSTER:$monster[6],(34,06) MONSTER:$monster[7],(37,06) MONSTER:$monster[8],(27,07) MONSTER:$monster[9],(30,07) MONSTER:$monster[0],(33,07) MONSTER:$monster[1],(36,07) MONSTER:$monster[2],(28,08) MONSTER:$monster[3],(31,08) MONSTER:$monster[4],(34,08) MONSTER:$monster[5],(27,09) MONSTER:$monster[6],(30,09) MONSTER:$monster[7],(33,09) MONSTER:$monster[8],(36,09) MONSTER:$monster[9],(28,10) MONSTER:$monster[0],(31,10) MONSTER:$monster[1],(34,10) MONSTER:$monster[2],(37,10) MONSTER:$monster[3],(27,11) MONSTER:$monster[4],(30,11) MONSTER:$monster[5],(33,11) MONSTER:$monster[6],(36,11) # MazeWalks MAZEWALK:(00,10),west MAZEWALK:(62,06),east # Non diggable walls NON_DIGGABLE:(00,00,62,16) # Subrooms: # Entire castle area REGION:(00,00,62,16),unlit,"ordinary" # Courtyards REGION:(00,05,05,11),lit,"ordinary" REGION:(57,05,62,11),lit,"ordinary" # Throne room REGION:(27,05,37,11),lit,"throne",unfilled # Antechamber REGION:(07,05,14,11),lit,"ordinary" # Storerooms REGION:(39,05,45,06),lit,"ordinary" REGION:(39,10,45,11),lit,"ordinary" REGION:(49,05,55,06),lit,"ordinary" REGION:(49,10,55,11),lit,"ordinary" # Corners REGION:(02,02,06,03),lit,"ordinary" REGION:(56,02,60,03),lit,"ordinary" REGION:(02,13,06,14),lit,"ordinary" REGION:(56,13,60,14),lit,"ordinary" # Barracks REGION:(16,05,25,06),lit,"barracks" REGION:(16,10,25,11),lit,"barracks" # Hallways REGION:(08,03,54,03),unlit,"ordinary" REGION:(08,13,54,13),unlit,"ordinary" REGION:(16,08,25,08),unlit,"ordinary" REGION:(39,08,55,08),unlit,"ordinary" # Storeroom alcoves REGION:(47,05,47,06),unlit,"ordinary" REGION:(47,10,47,11),unlit,"ordinary" nethack-3.6.0/dat/cmdhelp0000664000076400007660000001266712627501605014264 0ustar paxedpaxed^ Show the type of a trap ^[ Cancel command ^A Redo the previous command ^C Quit the game ^D Kick something (usually a door, chest, or box) ^E Search a room (available in debug mode only) ^F Map the level (available in debug mode only) ^G Create a monster (available in debug mode only) ^I Identify all items (available in debug mode only) ^O Show location of special levels (available in debug mode only) ^P Toggle through previously displayed game messages ^R Redraw screen ^T Teleport around level ^V Teleport between levels (available in debug mode only) ^W Wish (available in debug mode only) ^X Show your attributes (shows more in debug or explore mode) ^Z Suspend game (only if defined) a Apply (use) a tool A Remove all armor b Go southwest 1 space B Go southwest until you are on top of something ^B Go southwest until you are near something c Close a door C Call (name) a monster, an individual object, or a type of object d Drop an item D Drop specific item types e Eat something E Engrave writing on the floor f Fire ammunition from quiver F Followed by direction, fight a monster (even if you don't sense it) g Followed by direction, move until you are near something G Followed by direction, same as control-direction h Go west 1 space (if number_pad is on, display help message) H Go west until you are on top of something ^H Go west until you are near something i Show your inventory I Inventory specific item types j Go south 1 space (or if number_pad is on, jump to another location) J Go south until you are on top of something ^J Go south until you are near something k Go north 1 space (or if number_pad is on, kick something) K Go north until you are on top of something ^K Go north until you are near something l Go east 1 space (or if number_pad is on, loot a box on the floor) L Go east until you are on top of something ^L Go east until you are near something m Followed by direction, move without picking anything up or fighting M Followed by direction, move a distance without picking anything up n Go southeast 1 space N Go southeast until you are on something (if number_pad is on, name) ^N Go southeast until you are near something o Open a door O Show option settings, possibly change them p Pay your shopping bill P Put on an accessory (ring, amulet, etc) q Quaff (drink) something (potion, water, etc) Q Select ammunition for quiver r Read a scroll or spellbook R Remove an accessory (ring, amulet, etc) s Search for traps and secret doors S Save the game t Throw something T Take off one piece of armor u Go northeast 1 space (or if number_pad is on, untrap something) U Go northeast until you are on top of something ^U Go northeast until you are near something v Show version V Show long version and game history w Wield (put in use) a weapon W Wear a piece of armor x Swap wielded and secondary weapons X Toggle two-weapon combat y Go northwest 1 space Y Go northwest until you are on top of something ^Y Go northwest until you are near something z Zap a wand Z Zap (cast) a spell < Go up a staircase > Go down a staircase / Show what type of thing a symbol corresponds to ? Give a help message & Tell what a command does ! Do a shell escape (only if defined) \ Show what object types have been discovered ` Show discovered types for one class of objects _ Travel via a shortest-path algorithm to a point on the map . Rest one move while doing nothing Rest one move while doing nothing (if rest_on_space option is on) : Look at what is on the floor ; Show what type of thing a map symbol on the level corresponds to , Pick up things at the current location @ Toggle the pickup option on/off ) Show the weapon currently wielded [ Show the armor currently worn = Show the ring(s) currently worn " Show the amulet currently worn ( Show the tools currently in use * Show all equipment in use (combination of the ),[,=,",( commands) $ Count your gold + List known spells # Perform an extended command M-? Display extended command help (if the platform allows this) M-2 Toggle two-weapon combat (unless number_pad is enabled) M-a Adjust inventory letters M-A Annotate: supply a name for the current dungeon level M-c Talk to someone M-C Conduct: list voluntary challenges you have maintained M-d Dip an object into something M-e Advance or check weapons skills M-f Force a lock M-i Invoke an object's special powers M-j Jump to another location M-l Loot a box on the floor M-m Use a monster's special ability M-n Name a monster, an individual object, or a type of object M-o Offer a sacrifice to the gods M-O Overview: show a summary of the explored dungeon M-p Pray to the gods for help M-q Quit M-r Rub a lamp M-R Ride: mount or dismount a saddled steed M-s Sit down M-t Turn undead M-T Tip: empty a container M-u Untrap something (trap, door, or chest) M-v Print compile time options for this version of NetHack M-w Wipe off your face nethack-3.6.0/dat/data.base0000664000076400007660000077172112617727657014515 0ustar paxedpaxed# NetHack 3.6 data.base $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Copyright (c) 1994, 1995, 1996 by the NetHack Development Team # Copyright (c) 1994 by Boudewijn Wayers # NetHack may be freely redistributed. See license for details. # # This is the source file for the "data" file generated by `makedefs -d'. # A line starting with a # is a comment and is ignored by makedefs. # Any other line not starting with whitespace is a creature or an item. # # Each entry should be comprised of: # the thing/person being described on a line by itself, in lowercase; # on each succeeding line a description. # # If the first character of a key field is "~", then anything which matches # the rest of that key will be treated as if it did not match any of the # following keys for that entry. For instance, `~orc ??m*' preceding `orc*' # prevents "orc mummy" and "orc zombie" from matching. # abbot For it had been long apparent to Count Landulf that nothing could be done with his seventh son Thomas, except to make him an Abbot or something of that kind. Born in 1226, he had from childhood a mysterious objection to becoming a predatory eagle, or even to taking an ordinary interest in falconry or tilting or any other gentlemanly pursuits. He was a large and heavy and quiet boy, and phenomenally silent, scarcely opening his mouth except to say suddenly to his schoolmaster in an explosive manner, "What is God?" The answer is not recorded but it is probable that the asker went on worrying out answers for himself. [ The Runaway Abbot, by G. K. Chesterton ] # takes "suit or piece of armor" when specifying '[' ac armor* armour* suit or piece of armor "The last spot on the school jousting team came down to another boy and me. He was poor, and his only armor was a blanket his mother had made him from her hair. I, on the other hand, had a brand new suit of chain mail. Just before our joust, I asked him what he'd do if he made the team. (I was hoping to be more popular with the ladies.) He said he would be able to save the town from dragons and be able to afford some water for his 20 brothers and sisters. Well, a sense of compassion came over me. I insisted we swap armor. He was forced to accept, as it would have been an insult not to do so. On the battlefield, we charged at each other and we both connected with our lances. Lying there on the mud mortally wounded, I learned what true armor class was that day." [ When Help Collides, by J. D. Berry ] aclys aklys A short studded or spiked club attached to a cord allowing it to be drawn back to the wielder after having been thrown. It should not be confused with the atlatl, which is a device used to throw spears for longer distances. ~agate ring agate* Translucent, cryptocrystalline variety of quartz and a subvariety of chalcedony. Agates are identical in chemical structure to jasper, flint, chert, petrified wood, and tiger's-eye, and are often found in association with opal. The colorful, banded rocks are used as a semiprecious gemstone and in the manufacture of grinding equipment. An agate's banding forms as silica from solution is slowly deposited into cavities and veins in older rock. [ The Columbia Encyclopedia, Sixth Edition ] aleax Said to be a doppelganger sent to inflict divine punishment for alignment violations. *altar offer* sacrific* Altars are of three types: 1. In Temples. These are for Sacrifices [...]. The stone top will have grooves for blood, and the whole will be covered with _dry brown stains of a troubling kind_ from former Sacrifices. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] To every man upon this earth Death cometh soon or late; And how can man die better Than facing fearful odds For the ashes of his fathers And the temples of his gods? [ Lays of Ancient Rome, by Thomas B. Macaulay ] amaterasu omikami The Shinto sun goddess, Amaterasu Omikami is the central figure of Shintoism and the ancestral deity of the imperial house. One of the daughters of the primordial god Izanagi and said to be his favourite offspring, she was born from his left eye. [ Encyclopedia of Gods, by Michael Jordan ] amber* "Tree sap," Wu explained, "often flows over insects and traps them. The insects are then perfectly preserved within the fossil. One finds all kinds of insects in amber - including biting insects that have sucked blood from larger animals." [ Jurassic Park, by Michael Crichton ] *amnesia maud Get thee hence, nor come again, Mix not memory with doubt, Pass, thou deathlike type of pain, Pass and cease to move about! 'Tis the blot upon the brain That will show itself without. ... For, Maud, so tender and true, As long as my life endures I feel I shall owe you a debt, That I never can hope to pay; And if ever I should forget That I owe this debt to you And for your sweet sake to yours; O then, what then shall I say? - If ever I should forget, May God make me more wretched Than ever I have been yet! [ Maud, And Other Poems by Alfred, Lord Tennyson ] ~amulet of yendor ~amulet of restful sleep *amulet amulet of * amulet versus * "The complete Amulet can keep off all the things that make people unhappy -- jealousy, bad temper, pride, disagreeableness, greediness, selfishness, laziness. Evil spirits, people called them when the Amulet was made. Don't you think it would be nice to have it?" "Very," said the children, quite without enthusiasm. "And it can give you strength and courage." "That's better," said Cyril. "And virtue." "I suppose it's nice to have that," said Jane, but not with much interest. "And it can give you your heart's desire." "Now you're talking," said Robert. [ The Story of the Amulet, by Edith Nesbit ] amulet of yendor This mysterious talisman is the object of your quest. It is said to possess powers which mere mortals can scarcely comprehend, let alone utilize. The gods will grant the gift of immortality to the adventurer who can deliver it from the depths of Moloch's Sanctum and offer it on the appropriate high altar on the Astral Plane. angel* He answered and said unto them, he that soweth the good seed is the Son of man; the field is the world, and the good seed are the children of the kingdom; but the weeds are the children of the wicked one; the enemy that sowed them is the devil; the harvest is the end of the world; and the reapers are the angels. As therefore the weeds are gathered and burned in the fire; so shall it be in the end of this world. [...] So shall it be at the end of the world; the angels shall come forth, and sever the wicked from among the just, and shall cast them into the furnace of fire; there shall be wailing and gnashing of teeth. [ The Gospel According to Matthew, 13:37-42, 49-50 ] angry god* Cold wind blows. The gods look down in anger on this poor child. Why so unforgiving? And why so cold? [ Bridge of Sighs, by Robin Trower ] anhur An Egyptian god of war and a great hunter, few gods can match his fury. Unlike many gods of war, he is a force for good. The wrath of Anhur is slow to come, but it is inescapable once earned. Anhur is a mighty figure with four arms. He is often seen with a powerful lance that requires both of his right arms to wield and which is tipped with a fragment of the sun. He is married to Mehut, a lion-headed goddess. ankh-morpork The twin city of Ankh-Morpork, foremost of all the cities bounding the Circle Sea, was as a matter of course the home of a large number of gangs, thieves' guilds, syndicates and similar organisations. This was one of the reasons for its wealth. Most of the humbler folk on the widdershin side of the river, in Morpork's mazy alleys, supplemented their meagre incomes by filling some small role for one or other of the competing gangs. [ The Colour of Magic, by Terry Pratchett ] anshar A primordial Babylonian-Akkadian deity, Anshar is mentioned in the Babylonian creation epic _Enuma Elish_ as one of a pair of offspring (with Kishar) of Lahmu and Lahamu. Anshar is linked with heaven while Kishar is identified with earth. [ Encyclopedia of Gods, by Michael Jordan ] ant * ant This giant variety of the ordinary ant will fight just as fiercely as its small, distant cousin. Various varieties exist, and they are known and feared for their relentless persecution of their victims. anu Anu was the Babylonian god of the heavens, the monarch of the north star. He was the oldest of the Babylonian gods, the father of all gods, and the ruler of heaven and destiny. Anu features strongly in the _atiku_ festival in Babylon, Uruk and other cities. # takes "apelike creature" when specifying 'Y' ape apelike creature * ape The most highly evolved of all the primates, as shown by all their anatomical characters and particularly the development of the brain. Both arboreal and terrestrial, the apes have the forelimbs much better developed than the hind limbs. Tail entirely absent. Growth is slow and sexual maturity reached at quite an advanced age. [ A Field Guide to the Larger Mammals of Africa by Dorst ] Aldo the gorilla had a plan. It was a good plan. It was right. He knew it. He smacked his lips in anticipation as he thought of it. Yes. Apes should be strong. Apes should be masters. Apes should be proud. Apes should make the Earth shake when they walked. Apes should _rule_ the Earth. [ Battle for the Planet of the Apes, by David Gerrold ] apple NEWTONIAN, adj. Pertaining to a philosophy of the universe invented by Newton, who discovered that an apple will fall to the ground, but was unable to say why. His successors and disciples have advanced so far as to be able to say when. [ The Devil's Dictionary, by Ambrose Bierce ] archeolog* * archeologist Archeology is the search for fact, not truth. [...] So forget any ideas you've got about lost cities, exotic travel, and digging up the world. We do not follow maps to buried treasure, and X never, ever, marks the spot. [ Indiana Jones and the Last Crusade ] "I cannot be having with archeological excavations, myself," I said. "The fellows who dig them only ever find tiny walls and a few bits of broken pottery, and then they get all excited and swear that they have just made the most important discovery of the century, the ruins of a mile-high gold-covered temple to Frogmore the God of Bike-Saddle Fixtures or some such." "I think you will find," said Mr Rune, "that they do this in order to secure further government funding for their diggings and so remain in employment." "That is a rather cynical view," I said. [ the brightonomicon, by Robert Rankin ] # [title & author: same situation as with "bad luck" entry] archon Archons are the predominant inhabitants of the heavens. However unusual their appearance, they are not generally evil. They are beings at peace with themselves and their surroundings. arioch Arioch, the patron demon of Elric's ancestors; one of the most powerful of all the Dukes of Hell, who was called Knight of the Swords, Lord of the Seven Darks, Lord of the Higher Hell and many more names besides. [ Elric of Melnibone, by Michael Moorcock ] *arrow I shot an arrow into the air, It fell to earth, I knew not where; For, so swiftly it flew, the sight Could not follow it in its flight. I breathed a song into the air, It fell to earth, I knew not where; For who has sight so keen and strong That it can follow the flight of song? Long, long afterward, in an oak I found the arrow still unbroke; And the song, from beginning to end, I found again in the heart of a friend. [ The Arrow and the Song, by Henry Wadsworth Longfellow ] ashikaga takauji Ashikaga Takauji was a daimyo of the Minamoto clan who joined forces with the Go-Daigo to defeat the Hojo armies. Later when Go-Daigo attempted to reduce the powers of the samurai clans he rebelled against him. He defeated Go- Daigo and established the emperor Komyo on the throne. Go-Daigo eventually escaped and established another government in the town of Yoshino. This period of dual governments was known as the Nambokucho. [ Samurai - The Story of a Warrior Tradition, by Cook ] asmodeus It is said that Asmodeus is the overlord over all of hell. His appearance, unlike many other demons and devils, is human apart from his horns and tail. He can freeze flesh with a touch. [] The evil demon who appears in the Apocryphal book of _Tobit_ and is derived from the Persian _Aeshma_. In _Tobit_ Asmodeus falls in love with Sara, daughter of Raguel, and causes the death of seven husbands in succession, each on his bridal night. He was finally driven from Egypt through a charm made by Tobias of the heart and liver of a fish burned on perfumed ashes, as described by Milton in _Paradise Lost_ (IV, 167-71). Hence Asmodeus often figures as the spirit of matrimonial jealousy or unhappiness. [ Brewer's Concise Dictionary of Phrase and Fable ] athame The consecrated ritual knife of a Wiccan initiate (one of four basic tools, together with the wand, chalice and pentacle). Traditionally, the athame is a double-edged, black-handled, cross-hilted dagger of between six and eighteen inches length. athen* Athene was the offspring of Zeus, and without a mother. She sprang forth from his head completely armed. Her favourite bird was the owl, and the plant sacred to her is the olive. [ Bulfinch's Mythology, by Thomas Bulfinch ] axe "For ev'ry silver ringing blow, Cities and palaces shall grow!" "Bite deep and wide, O Axe, the tree, Tell wider prophecies to me." "When rust hath gnaw'd me deep and red, A nation strong shall lift his head. "His crown the very Heav'ns shall smite, Aeons shall build him in his might." "Bite deep and wide, O Axe, the tree; Bright Seer, help on thy prophecy!" [ Malcolm's Katie, by Isabella Valancey Crawford ] axolotl A mundane salamander, harmless. bag bag of * sack "Now, this third handkerchief," Mein Herr proceeded, "has also four edges, which you can trace continuously round and round: all you need do is to join its four edges to the four edges of the opening. The Purse is then complete, and its outer surface--" "I see!" Lady Muriel eagerly interrupted. "Its outer surface will be continuous with its inner surface! But it will take time. I'll sew it up after tea." She laid aside the bag, and resumed her cup of tea. "But why do you call it Fortunatus's Purse, Mein Herr?" The dear old man beamed upon her, with a jolly smile, looking more exactly like the Professor than ever. "Don't you see, my child--I should say Miladi? Whatever is inside that Purse, is outside it; and whatever is outside it, is inside it. So you have all the wealth of the world in that leetle Purse!" [ Sylvie and Bruno Concluded, by Lewis Carroll ] b*lzebub The "lord of the flies" is a translation of the Hebrew Ba'alzevuv (Beelzebub in Greek). It has been suggested that it was a mistranslation of a mistransliterated word which gave us this pungent and suggestive name of the Devil, a devil whose name suggests that he is devoted to decay, destruction, demoralization, hysteria and panic... [ Notes on _Lord of the Flies_, by E. L. Epstein ] balrog ... It came to the edge of the fire and the light faded as if a cloud had bent over it. Then with a rush it leaped the fissure. The flames roared up to greet it, and wreathed about it; and a black smoke swirled in the air. Its streaming mane kindled, and blazed behind it. In its right hand was a blade like a stabbing tongue of fire; in its left it held a whip of many thongs. 'Ai, ai!' wailed Legolas. 'A Balrog! A Balrog is come!' [ The Fellowship of the Ring, by J.R.R. Tolkien ] baluchitherium titanothere Extinct rhinos include a variety of forms, the most spectacular being _Baluchitherium_ from the Oligocene of Asia, which is the largest known land mammal. Its body, 18 feet high at the shoulder and carried on massive limbs, allowed the 4-foot-long head to browse on the higher branches of trees. Though not as enormous, the titanotheres of the early Tertiary were also large perissodactyls, _Brontotherium_ of the Oligocene being 8 feet high at the shoulder. [ Prehistoric Animals, by Barry Cox ] banana He took another step and she cocked her right wrist in viciously. She heard the spring click. Weight slapped into her hand. "Here!" she shrieked hysterically, and brought her arm up in a hard sweep, meaning to gut him, leaving him to blunder around the room with his intestines hanging out in steaming loops. Instead he roared laughter, hands on his hips, flaming face cocked back, squeezing and contorting with great good humor. "Oh, my dear!" he cried, and went off into another gale of laughter. She looked stupidly down at her hand. It held a firm yellow banana with a blue and white Chiquita sticker on it. She dropped it, horrified, to the carpet, where it became a sickly yellow grin, miming Flagg's own. "You'll tell," he whispered. "Oh yes indeed you will." And Dayna knew he was right. [ The Stand, by Stephen King ] banshee In Irish folklore and that of the Western Highlands of Scotland, a female fairy who announces her presence by shrieking and wailing under the windows of a house when one of its occupants is awaiting death. The word is a phonetic spelling of the Irish _beansidhe_, a woman of the fairies. [ Brewer's Concise Dictionary of Phrase and Fable ] barbarian * barbarian They dressed alike -- in buckskin boots, leathern breeks and deerskin shirts, with broad girdles that held axes and short swords; and they were all gaunt and scarred and hard-eyed; sinewy and taciturn. They were wild men, of a sort, yet there was still a wide gulf between them and the Cimmerian. They were sons of civilization, reverted to a semi-barbarism. He was a barbarian of a thousand generations of barbarians. They had acquired stealth and craft, but he had been born to these things. He excelled them even in lithe economy of motion. They were wolves, but he was a tiger. [ Conan - The Warrior, by Robert E. Howard ] barbed devil Barbed devils lack any real special abilities, though they are quite difficult to kill. # takes "bat or bird" when specifying 'B' ~combat ~wombat *bat bat or bird A bat, flitting in the darkness outside, took the wrong turn as it made its nightly rounds and came in through the window which had been left healthfully open. It then proceeded to circle the room in the aimless fat-headed fashion habitual with bats, who are notoriously among the less intellectually gifted of God's creatures. Show me a bat, says the old proverb, and I will show you something that ought to be in some kind of a home. [ A Pelican at Blandings, by P. G. Wodehouse ] bear*trap Probably most commonly associated with trapping, the leghold trap is a rather simple mechanical trap. It is made up of two jaws, a spring of some sort, and a trigger in the middle. When the animal steps on the trigger the trap closes around the leg, holding the animal in place. Usually some kind of lure is used to position the animal, or the trap is set on an animal trail. Traditionally, leghold traps had tightly closing "teeth" to make sure the animal stayed in place. The teeth also made sure the animal could not move the leg in the trap and ruin their fur. However, this resulted in many animals gnawing off legs in order to escape. More modern traps have a gap called an "offset jaw" and work more like a handcuff. They grip above the paw, making sure the animal cannot pull out but does not destroy the leg. This also allows the trapper to release unwanted catches. [ Wikipedia, the free encyclopedia ] *bee This giant variety of its useful normal cousin normally appears in small groups, looking for raw material to produce the royal jelly needed to feed their queen. On rare occasions, one may stumble upon a bee-hive, in which the queen bee is being well provided for, and guarded against intruders. *beetle [ The Creator ] has an inordinate fondness for beetles. [ attributed to biologist J.B.S. Haldane ] The common name for the insects with wings shaped like shields (_Coleoptera_), one of the ten sub-species into which the insects are divided. They are characterized by the shields (the front pair of wings) under which the back wings are folded. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] bell of opening "A bell, book and candle job." The Bursar sighed. "We tried that, Archchancellor." The Archchancellor leaned towards him. "Eh?" he said. "I _said_, we tried that Archchancellor," said the Bursar loudly, directing his voice at the old man's ear. "After dinner, you remember? We used Humptemper's _Names of the Ants_ and rang Old Tom."* "Did we, indeed. Worked, did it?" "_No_, Archchancellor." * Old Tom was the single cracked bronze bell in the University bell tower. [ Eric, by Terry Pratchett ] blindfold The blindfolding was performed by binding a piece of the yellowish linen whereof those of the Amahagger who condescended to wear anything in particular made their dresses tightly round the eyes. This linen I afterwards discovered was taken from the tombs, and was not, as I had first supposed, of native manufacture. The bandage was then knotted at the back of the head, and finally brought down again and the ends bound under the chin to prevent its slipping. Ustane was, by the way, also blindfolded, I do not know why, unless it was from fear that she should impart the secrets of the route to us. [ She, by H. Rider Haggard ] blind io On this particular day Blind Io, by dint of constant vigilance the chief of the gods, sat with his chin on his hand and looked at the gaming board on the red marble table in front of him. Blind Io had got his name because, where his eye sockets should have been, there were nothing but two areas of blank skin. His eyes, of which he had an impressively large number, led a semi-independent life of their own. Several were currently hovering above the table. [ The Colour of Magic, by Terry Pratchett ] * blob ooze * ooze *pudding * slime These giant amoeboid creatures look like nothing more than puddles of slime, but they both live and move, feeding on metal or wood as well as the occasional dungeon explorer to supplement their diet. But we were not on a station platform. We were on the track ahead as the nightmare, plastic column of fetid black iridescence oozed tightly onward through its fifteen-foot sinus, gathering unholy speed and driving before it a spiral, re-thickening cloud of the pallid abyss vapor. It was a terrible, indescribable thing vaster than any subway train -- a shapeless congeries of protoplasmic bubbles, faintly self-luminous, and with myriads of temporary eyes forming and unforming as pustules of greenish light all over the tunnel-filling front that bore down upon us, crushing the frantic penguins and slithering over the glistening floor that it and its kind had swept so evilly free of all litter. [ At the Mountains of Madness, by H.P. Lovecraft ] blue jelly I'd planned how to prevent the lock from sealing behind me; it required a temporary sacrifice, not cleverness. I used the door itself to help me cut off a portion of my body, after shunting all memory from the piece to be abandoned. The piece, looking inexpressibly dear and forlorn for a bit of blue jelly, would force open the outer door until I returned and rejoined it. [ Beholder's Eye, by Julie E. Czerneda ] bone devil Bone devils attack with weapons and with a great hooked tail which causes a loss of strength to those they sting. book of the dead candelabrum* *candle Faustus: Come on Mephistopheles. What shall we do? Mephistopheles: Nay, I know not. We shall be cursed with bell, book, and candle. Faustus: How? Bell, book, and candle, candle, book, and bell, Forward and backward, to curse Faustus to hell. Anon you shall hear a hog grunt, a calf bleat, and an ass bray, Because it is Saint Peter's holy day. (Enter all the Friars to sing the dirge) [ Doctor Faustus and Other Plays, by Christopher Marlowe ] boomerang Rincewind pulled himself up and thought about reaching for his stick. And then he thought again. The man had a couple of spears stuck in the ground, and people here were good at spears, because if you didn't get efficient at hitting the things that moved fast you had to eat the things that moved slowly. He was also holding a boomerang, and it wasn't one of those toy ones that came back. This was one of the big, heavy, gently curved sort that didn't come back because it was sticking in something's ribcage. You could laugh at the idea of wooden weapons until you saw the kind of wood that grew here. [ The Last Continent, by Terry Pratchett ] ~*jack*boot* *boot* In Fantasyland these are remarkable in that they seldom or never wear out and are suitable for riding or walking in without the need of Socks. Boots never pinch, rub, or get stones in them; nor do nails stick upwards into the feet from the soles. They are customarily mid-calf length or knee-high, slip on and off easily and never smell of feet. Unfortunately, the formula for making this splendid footwear is a closely guarded secret, possibly derived from nonhumans (see Dwarfs, Elves, and Gnomes). [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] *booze potion of sleeping On waking, he found himself on the green knoll whence he had first seen the old man of the glen. He rubbed his eyes -- it was a bright sunny morning. The birds were hopping and twittering among the bushes, and the eagle was wheeling aloft, and breasting the pure mountain breeze. "Surely," thought Rip, "I have not slept here all night." He recalled the occurrences before he fell asleep. The strange man with a keg of liquor -- the mountain ravine -- the wild retreat among the rocks -- the woe-begone party at ninepins -- the flagon -- "Oh! that flagon! that wicked flagon!" thought Rip -- "what excuse shall I make to Dame Van Winkle!" [ Rip Van Winkle, a Posthumous Writing of Diedrich Knickerbocker, by Washington Irving ] boulder I worked the lever well under, and stretched my back; the end of the stone rose up, and I kicked the fulcrum under. Then, when I was going to bear down, I remembered there was something to get out from below; when I let go of the lever, the stone would fall again. I sat down to think, on the root of the oak tree; and, seeing it stand about the ground, I saw my way. It was lucky I had brought a longer lever. It would just reach to wedge under the oak root. Bearing it down so far would have been easy for a heavy man, but was a hard fight for me. But this time I meant to do it if it killed me, because I knew it could be done. Twice I got it nearly there, and twice the weight bore it up again; but when I flung myself on it the third time, I heard in my ears the sea-sound of Poseidon. Then I knew this time I would do it; and so I did. [ The King Must Die, by Mary Renault ] ~*longbow of diana bow * bow "Stand to it, my hearts of gold," said the old bowman as he passed from knot to knot. "By my hilt! we are in luck this journey. Bear in mind the old saying of the Company." "What is that, Aylward?" cried several, leaning on their bows and laughing at him. "'Tis the master-bowyer's rede: 'Every bow well bent. Every shaft well sent. Every stave well nocked. Every string well locked.' There, with that jingle in his head, a bracer on his left hand, a shooting glove on his right, and a farthing's-worth of wax in his girdle, what more doth a bowman need?" "It would not be amiss," said Hordle John, "if under his girdle he had four farthings'-worth of wine." [ The White Company, by Sir Arthur Conan Doyle ] brigit Brigit (Brigid, Bride, Banfile), which means the Exalted One, was the Celtic (continental European and Irish) fertility goddess. She was originally celebrated on February first in the festival of Imbolc, which coincided with the beginning of lactation in ewes and was regarded in Scotland as the date on which Brigit deposed the blue-faced hag of winter. The Christian calendar adopted the same date for the Feast of St. Brigit. There is no record that a Christian saint ever actually existed, but in Irish mythology she became the midwife to the Virgin Mary. [ Encyclopedia of Gods, by Michael Jordan ] ~stormbringer *broadsword Bring me my broadsword And clear understanding. Bring me my cross of gold, As a talisman. [ "Broadsword" (refrain) by Ian Anderson ] bugbear Bugbears are relatives of goblins, although they tend to be larger and more hairy. They are aggressive carnivores and sometimes kill just for the treasure their victims may be carrying. bugle 'I read you by your bugle horn And by your palfrey good, I read you for a Ranger sworn To keep the King's green-wood.' 'A Ranger, Lady, winds his horn, And 'tis at peep of light; His blast is heard at merry morn, And mine at dead of night.' [ Brignall Banks, by Sir Walter Scott ] bullwhip "Good," he said and, unbelievably, smiled at me, a smirk like a round of rotted cheese. "What did your keeper use on you? A bullwhip?" [ Melusine, by Sarah Monette ] *camaxtli A classical Mesoamerican Aztec god, also known as Mixcoatl- Camaxtli (the Cloud Serpent), Camaxtli is the god of war. He is also a deity of hunting and fire who received human sacrifice of captured prisoners. According to tradition, the sun god Tezcatlipoca transformed himself into Mixcoatl-Camaxtli to make fire by twirling the sacred fire sticks. [ Encyclopedia of Gods, by Michael Jordan ] camelot* The seat of Arthur's power in medieval romance. The name is of unknown origin and refers to the castle but also includes the surrounding town. ... Camelot appears, most significantly, as a personal capital as opposed to a permanent or national one. It is Arthur's and Arthur's alone. There are no previous lords and Arthur's successor, Constantine, does not take up residence there. Camelot is actually said to have been demolished after Arthur and Lancelot were gone by Mark. Fazio degli Uberti, the Italian poet, claims to have seen the ruins in the 14th century. [ Encyclopedia Mythica, ed. M.F. Lindemans ] candy bar Only once a year, on his birthday, did Charlie Bucket ever get to taste a bit of chocolate. The whole family saved up their money for that special occasion, and when the great day arrived, Charlie was always presented with one small chocolate bar to eat all by himself. And each time he received it, on those marvelous birthday mornings, he would place it carefully in a small wooden box that he owned, and treasure it as though it were a bar of solid gold; and for the next few days, he would allow himself only to look at it, but never to touch it. Then at last, when he could stand it no longer, he would peel back a tiny bit of the paper wrapping at one corner to expose a tiny bit of chocolate, and then he would take a tiny nibble - just enough to allow the lovely sweet taste to spread out slowly over his tongue. The next day, he would take another tiny nibble, and so on, and so on. And in this way, Charlie would make his ten-cent bar of birthday chocolate last him for more than a month. [ Charlie and the Chocolate Factory, by Roald Dahl ] carrot In World War II, Britain's air ministry spread the word that a diet of these vegetables helped pilots see Nazi bombers attacking at night. That was a lie intended to cover the real matter of what was underpinning the Royal Air Force's successes: Airborne Interception Radar, also known as AI. ... British Intelligence didn't want the Germans to find out about the superior new technology helping protect the nation, so they created a rumor to afford a somewhat plausible-sounding explanation for the sudden increase in bombers being shot down. ... The disinformation was so persuasive that the English public took to eating carrots to help them find their way during the blackouts. [ Urban Legends Reference Pages ] s*d*g*r* cat Imagine a sealed container, so perfectly constructed that no physical influence can pass either inwards or outwards across its walls. Imagine that inside the container is a cat, and also a device that can be triggered by some quantum event. If that event takes place, then the device smashes a phial containing cyanide and the cat is killed. If the event does not take place, the cat lives on. In Schroedinger's original version, the quantum event was the decay of a radioactive atom. ... To the outside observer, the cat is indeed in a linear combination of being alive and dead, and only when the container is finally opened would the cat's state vector collapse into one or the other. On the other hand, to a (suitably protected) observer inside the container, the cat's state-vector would have collapsed much earlier, and the outside observer's linear combination has no relevance. [ The Emperor's New Mind, by Roger Penrose ] # takes "cat or other feline" when specifying 'f' *cat *feline kitten Well-known quadruped domestic animal from the family of predatory felines (_Felis ochreata domestica_), with a thick, soft pelt; often kept as a pet. Various folklores have the cat associated with magic and the gods of ancient Egypt. So Ulthar went to sleep in vain anger; and when the people awakened at dawn - behold! Every cat was back at his accustomed hearth! Large and small, black, grey, striped, yellow and white, none was missing. Very sleek and fat did the cats appear, and sonorous with purring content. [ The Cats of Ulthar, by H.P. Lovecraft ] # this one doesn't work very well for dwarven and gnomish cavemen cave*man human cave*man Now it was light enough to leave. Moon-Watcher picked up the shriveled corpse and dragged it after him as he bent under the low overhang of the cave. Once outside, he threw the body over his shoulder and stood upright - the only animal in all this world able to do so. Among his kind, Moon-Watcher was almost a giant. He was nearly five feet high, and though badly undernourished weighed over a hundred pounds. His hairy, muscular body was halfway between ape and man, but his head was already much nearer to man than ape. The forehead was low, and there were ridges over the eye sockets, yet he unmistakably held in his genes the promise of humanity. [ 2001: A Space Odyssey, by Arthur C. Clarke ] dwar* cave*man gnom* cave*man 'Twas in a land unkempt of life's red dawn; Where in his sanded cave he dwelt alone; Sleeping by day, or sometimes worked upon His flint-head arrows and his knives of stone; By night stole forth and slew the savage boar, So that he loomed a hunter of loud fame, And many a skin of wolf and wild-cat wore, And counted many a flint-head to his name; Wherefore he walked the envy of the band, Hated and feared, but matchless in his skill. Till lo! one night deep in that shaggy land, He tracked a yearling bear and made his kill; Then over-worn he rested by a stream, And sank into a sleep too deep for dream. [ The Dreamer, by Robert Service ] *centaur Of all the monsters put together by the Greek imagination the Centaurs (Kentauroi) constituted a class in themselves. Despite a strong streak of sensuality, in their make-up, their normal behaviour was moral, and they took a kindly thought of man's welfare. The attempted outrage of Nessos on Deianeira, and that of the whole tribe of Centaurs on the Lapith women, are more than offset by the hospitality of Pholos and by the wisdom of Cheiron, physician, prophet, lyrist, and the instructor of Achilles. Further, the Centaurs were peculiar in that their nature, which united the body of a horse with the trunk and head of a man, involved an unthinkable duplication of vital organs and important members. So grotesque a combination seems almost un-Greek. These strange creatures were said to live in the caves and clefts of the mountains, myths associating them especially with the hills of Thessaly and the range of Erymanthos. [ Mythology of all races, Vol. 1, pp. 270-271 ] centipede I observed here, what I had often seen before, that certain districts abound in centipedes. Here they have light reddish bodies and blue legs; great myriapedes are seen crawling every where. Although they do no harm, they excite in man a feeling of loathing. Perhaps our appearance produces a similar feeling in the elephant and other large animals. Where they have been much disturbed, they certainly look upon us with great distrust, as the horrid biped that ruins their peace. [ Travels and Researches in South Africa, by Dr. David Livingstone ] cerberus kerberos Cerberus, (or Kerberos in Greek), was the three-headed dog that guarded the Gates of Hell. He allowed any dead to enter, and likewise prevented them all from ever leaving. He was bested only twice: once when Orpheus put him to sleep by playing bewitching music on his lyre, and the other time when Hercules confronted him and took him to the world of the living (as his twelfth and last labor). chameleon A small lizard perched on a brown stone. Feeling threatened by the approach of human beings along the path, it metamorphosed into a stingray beetle, then into a stench-puffer, then into a fiery salamander. Bink smiled. These conversions weren't real. It had assumed the forms of obnoxious little monsters, but not their essence. It could not sting, stink or burn. It was a chameleon, using its magic to mimic creatures of genuine threat. Yet as it shifted into the form of a basilisk it glared at him with such ferocity that Bink's mirth abated. If its malice could strike him, he would be horribly dead. [ A Spell for Chameleon, by Piers Anthony ] charo*n When an ancient Greek died, his soul went to the nether world: the Hades. To reach the nether world, the souls had to cross the river Styx, the river that separated the living from the dead. The Styx could be crossed by ferry, whose shabby ferry- man, advanced in age, was called Charon. The deceased's next- of-kin would place a coin under his tongue, to pay the ferry- man. chest large box Dantes rapidly cleared away the earth around the chest. Soon the center lock appeared, then the handles at each end, all delicately wrought in the manner of that period when art made precious even the basest of metals. He took the chest by the two handles and tried to lift it, but it was impossible. He tried to open it; it was locked. He inserted the sharp end of his pickaxe between the chest and the lid and pushed down on the handle. The lid creaked, then flew open. Dantes was seized with a sort of giddy fever. He cocked his gun and placed it beside him. Then he closed his eyes like a child, opened them and stood dumbfounded. The chest was divided into three compartments. In the first were shining gold coins. In the second, unpolished gold ingots packed in orderly stacks. From the third compartment, which was half full, Dantes picked up handfuls of diamonds, pearls and rubies. As they fell through his fingers in a glittering cascade, they gave forth the sound of hail beating against the windowpanes. [ The Count of Monte Cristo, by Alexandre Dumas ] chih*sung*tzu A character in Chinese mythology noted for bringing about the end of a terrible drought which threatened the survival of the people. He achieved this by means of sprinkling the earth with water from a bowl, using the branch of a tree to do so. He became the heavenly controller of the rain, and lived with other celestial beings in their paradise on Mount Kunlun. [ The Illustrated Who's Who In Mythology, by Michael Senior ] chromatic dragon tiamat Tiamat is said to be the mother of evil dragonkind. She is extremely vain. citrine* A pale yellow variety of crystalline quartz resembling topaz. ~elven cloak ~oilskin cloak *cloak* Cloaks are the universal outer garb of everyone who is not a Barbarian. It is hard to see why. They are open in front and require you at most times to use one hand to hold them shut. On horseback they leave the shirt-sleeved arms and most of the torso exposed to wind and Weather. The OMTs [ Official Management Terms ] for Cloaks well express their difficulties. They are constantly _swirling and dripping_ and becoming _heavy with water_ in rainy Weather, _entangling with trees_ or _swords_, or needing to be _pulled close around her/his shivering body_. This seems to suggest they are less than practical for anyone on an arduous Tour. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] cloud* I wandered lonely as a cloud That floats on high o'er vales and hills, When all at once I saw a crowd, A host, of golden daffodils; Beside the lake, beneath the trees, Fluttering and dancing in the breeze. [ I Wandered Lonely as a Cloud, by William Wordsworth ] cobra Darzee and his wife only cowered down in the nest without answering, for from the thick grass at the foot of the bush there came a low hiss -- a horrid cold sound that made Rikki-tikki jump back two clear feet. Then inch by inch out of the grass rose up the head and spread hood of Nag, the big black cobra, and he was five feet long from tongue to tail. When he had lifted one-third of himself clear of the ground, he stayed balancing to and fro exactly as a dandelion-tuft balances in the wind, and he looked at Rikki-tikki with the wicked snake's eyes that never change their expression, whatever the snake may be thinking of. 'Who is Nag?' said he. '_I_ am Nag. The great God Brahm put his mark upon all our people, when the first cobra spread his hood to keep the sun off Brahm as he slept. Look, and be afraid!' [ Rikki-tikki-tavi, by Rudyard Kipling ] c*ckatrice Once in a great while, when the positions of the stars are just right, a seven-year-old rooster will lay an egg. Then, along will come a snake, to coil around the egg, or a toad, to squat upon the egg, keeping it warm and helping it to hatch. When it hatches, out comes a creature called basilisk, or cockatrice, the most deadly of all creatures. A single glance from its yellow, piercing toad's eyes will kill both man and beast. Its power of destruction is said to be so great that sometimes simply to hear its hiss can prove fatal. Its breath is so venomous that it causes all vegetation to wither. There is, however, one creature which can withstand the basilisk's deadly gaze, and this is the weasel. No one knows why this is so, but although the fierce weasel can slay the basilisk, it will itself be killed in the struggle. Perhaps the weasel knows the basilisk's fatal weakness: if it ever sees its own reflection in a mirror it will perish instantly. But even a dead basilisk is dangerous, for it is said that merely touching its lifeless body can cause a person to sicken and die. [ Mythical Beasts by Deirdre Headon (The Leprechaun Library) and other sources ] *coin ~creeping coins *coins zorkmid* The coin bears the likeness of Belwit the Flat, along with the inscriptions, "One Zorkmid," and "699 GUE [ Great Underground Empire ]." On the other side, the coin depicts Egreth Castle, and says "In Frobs We Trust" in several languages. [ Zork Zero, by Infocom ] # not "stethoscope" combat fight fracas melee spat squabble tiff [Scene: Mr. Moon and Gilbert enter tavern and discover many corpses strewn about the place; Blind Pew is sole survivor.] Blind Pew: Evening. Sounded as though there has been a bit of a squabble. Mr. Moon: Squabble? They're all dead. Blind Pew: Oh. Must have been more of a tiff then. [ Yellowbeard, directed by Mel Damski, screenplay by Graham Chapman, Peter Cook, Bernard McKenna ] cope * cope The cope is a liturgical vestment which may be worn by any rank of the clergy. Copes are made in all liturgical colours, and are like a very long mantle or cloak, fastened at the breast by a clasp. [ Wikipedia, the free encyclopedia ] cornuthaum He was dressed in a flowing gown with fur tippets which had the signs of the zodiac embroidered over it, with various cabalistic signs, such as triangles with eyes in them, queer crosses, leaves of trees, bones of birds and animals, and a planetarium whose stars shone like bits of looking-glass with the sun on them. He had a pointed hat like a dunce's cap, or like the headgear worn by ladies of that time, except that the ladies were accustomed to have a bit of veil floating from the top of it. [ The Once and Future King, by T.H. White ] "A wizard!" Dooley exclaimed, astounded. "At your service, sirs," said the wizard. "How perceptive of you to notice. I suppose my hat rather gives me away. Something of a beacon, I don't doubt." His hat was pretty much that, tall and cone-shaped with stars and crescent moons all over it. All in all, it couldn't have been more wizardish. [ The Elfin Ship, James P. Blaylock ] couatl A mythical feathered serpent. The couatl are very rare. coyote This carnivore is known for its voracious appetite and inflated view of its own intelligence. cram* If you want to know what cram is, I can only say that I don't know the recipe; but it is biscuitish, keeps good indefinitely, is supposed to be sustaining, and is certainly not entertaining, being in fact very uninteresting except as a chewing exercise. It was made by the Lake-men for long journeys. [ The Hobbit, by J.R.R. Tolkien ] cream pie Gregor stared at the pastry tray, and sighed. "I suppose it would disturb the guards if I tried to shove a cream torte up your nose." "Deeply. You should have done it when we were eight and twelve, you could have gotten away with it then. The cream pie of justice flies one way," Miles snickered. [ The Vor Game, by Lois McMaster Bujold ] *crocodile A big animal with the appearance of a lizard, constituting an order of the reptiles (_Loricata_ or _Crocodylia_), the crocodile is a large, dangerous predator native to tropical and subtropical climes. It spends most of its time in large bodies of water. [] How doth the little crocodile Improve his shining tail, And pour the waters of the Nile On every golden scale! How cheerfully he seems to grin How neatly spreads his claws, And welcomes little fishes in, With gently smiling jaws! [ How Doth The Little Crocodile, by Lewis Carroll ] croesus kroisos creosote Croesus (in Greek: Kroisos), the wealthy last king of Lydia; his empire was destroyed when he attacked Cyrus in 549, after the Oracle of Delphi (q.v.) had told him: "if you attack the Persians, you will destroy a mighty empire". Herodotus relates of his legendary conversation with Solon of Athens, who impressed upon him that being rich does not imply being happy and that no one should be considered fortunate before his death. crom Warily Conan scanned his surroundings, all of his senses alert for signs of possible danger. Off in the distance, he could see the familiar shapes of the Camp of the Duali tribe. Suddenly, the hairs on his neck stand on end as he detects the aura of evil magic in the air. Without thought, he readies his weapon, and mutters under his breath: "By Crom, there will be blood spilt today." [ Conan the Avenger by Robert E. Howard, Bjorn Nyberg, and L. Sprague de Camp ] crossbow* "God save thee, ancient Mariner! From the fiends, that plague thee thus! - Why look'st thou so?" - With my cross-bow I shot the Albatross. [ The Rime of the Ancient Mariner, by Samuel Taylor Coleridge ] crystal ball You look into one of these and see _vapours swirling like clouds_. These shortly clear away to show a sort of video without sound of something that is going to happen to you soon. It is seldom good news. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] curse* Curses are longstanding ill-wishings which, in Fantasyland, often manifest as semisentient. They have to be broken or dispelled. The method varies according to the type and origin of the Curse: [...] 4. Curses on Rings and Swords. You have problems. Rings have to be returned whence they came, preferably at over a thousand degrees Fahrenheit, and the Curse means you won't want to do this. Swords usually resist all attempts to raise their Curses. Your best source is to hide the Sword or give it to someone you dislike. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] cwn*n A pack of snow-white, red-eared spectral hounds which sometimes took part in the kidnappings and raids the inhabitants of the underworld sometimes make on this world (the Wild Hunt). They are associated in Wales with the sounds of migrating wild geese, and are said to be leading the souls of the damned to hell. The phantom chase is usually heard or seen in midwinter and is accompanied by a howling wind. [ Encyclopedia Mythica, ed. M.F. Lindemans ] cyclops And after he had milked his cattle swiftly, he again took hold of two of my men and had them as his supper. Then I went, with a tub of red wine, to stand before the Cyclops, saying: "A drop of wine after all this human meat, so you can taste the delicious wine that is stored in our ship, Cyclops." He took the tub and emptied it. He appreciated the priceless wine that much that he promptly asked me for a second tub. "Give it", he said, "and give me your name as well". ... Thrice I filled the tub, and after the wine had clouded his mind, I said to him, in a tone as sweet as honey: "You have asked my name, Cyclops? Well, my name is very well known. I'll give it to you, if you give me the gift you promised me as a guest. My name is Nobody. All call me thus: my father and my mother and my friends." Ruthlessly he answered to this: "Nobody, I will eat you last of all; your host of friends will completely precede you. That will be my present to you, my friend." And after these words he fell down backwards, restrained by the all-restrainer Hupnos. His monstrous neck slid into the dust; the red wine squirted from his throat; the drunk vomited lumps of human flesh. [ The Odyssey, (chapter Epsilon), by Homer ] ~sting *dagger Is this a dagger which I see before me, The handle toward my hand? Come, let me clutch thee. I have thee not, and yet I see thee still. Art thou not, fatal vision, sensible To feeling as to sight? or art thou but A dagger of the mind, a false creation, Proceeding from the heat-oppressed brain? I see thee yet, in form as palpable As this which now I draw. [ Macbeth, by William Shakespeare ] dark one ... But he ruled rather by force and fear, if they might avail; and those who perceived his shadow spreading over the world called him the Dark Lord and named him the Enemy; and he gathered again under his government all the evil things of the days of Morgoth that remained on earth or beneath it, and the Orcs were at his command and multiplied like flies. Thus the Black Years began ... [ The Silmarillion, by J.R.R. Tolkien ] # includes "dart trap" dart* Darts are missile weapons, designed to fly such that a sharp, often weighted point will strike first. They can be distinguished from javelins by fletching (i.e., feathers on the tail) and a shaft that is shorter and/or more flexible, and from arrows by the fact that they are not of the right length to use with a normal bow. [ Wikipedia, the free encyclopedia ] Against my foe I hurled a murderous dart. He caught it in his hand -- I heard him laugh -- I saw the thing that should have pierced his heart Turn to a golden staff. [ Gifts, by Mary Coleridge ] demogorgon A terrible deity, whose very name was capable of producing the most horrible effects. He is first mentioned by the 4th-century Christian writer, Lactantius, who in doing so broke with the superstition that the very reference to Demogorgon by name brought death and disaster. [ Brewer's Concise Dictionary of Phrase and Fable ] Demogorgon, the prince of demons, wallows in filth and can spread a quickly fatal illness to his victims while rending them. He is a mighty spellcaster, and he can drain the life of mortals with a touch of his tail. # takes "major demon" when specifying '&' demon major demon It is often very hard to discover what any given Demon looks like, apart from a general impression of large size, huge fangs, staring eyes, many limbs, and an odd color; but all accounts agree that Demons are very powerful, very Magic (in a nonhuman manner), and made of some substance that can squeeze through a keyhole yet not be pierced with a Sword. This makes them difficult to deal with, even on the rare occasions when they are friendly. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] diamond The hardest known mineral (with a hardness of 10 on Mohs' scale). It is an allotropic form of pure carbon that has crystallized in the cubic system, usually as octahedra or cubes, under great pressure. [ A Concise Dictionary of Physics ] The diamond, _adamas_ or _dyamas_, is a transparent stone, like crystal, but having the colour of polished iron, but it cannot be destroyed by iron, fire or any other means, unless it is placed in the hot blood of a goat; with sharp pieces of diamond other stones are engraved and polished. It is no greater than a small nut. There are six kinds, however Adamant attracts metal; it expels venom; it produces amber (and is efficacious against empty fears and for those resisting spells). It is found in India, in Greece and in Cyprus, where magicians make use of it. It gives you courage; it averts apparitions; it removes anger and quarrels; it heals the mad; it defends you from your enemies. It should be set in gold or silver and worn on the left arm. It is likewise found in Arabia. [ The Aberdeen Bestiary, translated by Colin McLaren ] dilithium* The most famous and the first to be named of the imaginary "minerals" of Star Trek is dilithium. ... Because of this mineral's central role in the storyline, a whole mythology surrounds it. It is, however, a naturally occurring substance within the mythology, as there are various episodes that make reference to the mining of dilithium deposits. ... This name itself is imaginary and gives no real information on the structure or make-up of this substance other than that this version of the name implies a lithium and iron-bearing aluminosilicate of some sort. That said, the real mineral that most closely matches the descriptive elements of this name is ferroholmquistite which is a dilithium triferrodiallosilicate. If one goes on the premise that nature follows certain general norms, then one could extrapolate that dilithium might have a similar number of silicon atoms in its structure. Keeping seven (i.e. hepto) ferrous irons and balancing the oxygens would give a theoretical formula of Li2Fe7Al2Si8O27. A mineral with this composition could theoretically exist, although it is doubtful that it would possess the more fantastic properties ascribed to dilithium. [ The Mineralogy of Star Trek, by Jeffrey de Fourestier ] dingo A wolflike wild dog, Canis dingo, of Australia, having a reddish- or yellowish-brown coat, believed to have been introduced by the aborigines. [Webster's Encyclopedic Unabridged Dictionary of the English Language] disenchanter Ask not, what your magic can do to it. Ask what it can do to your magic. dispater The Roman ruler of the underworld and fortune, similar to the Greek Hades. Every hundred years, the Ludi Tarentini were celebrated in his honor. The Gauls regarded Dis Pater as their ancestor. The name is a contraction of the Latin Dives, "the wealthy", Dives Pater, "the wealthy father", or "Fater Wealth". It refers to the wealth of precious stone below the earth. [ Encyclopedia Mythica, ed. M.F. Lindemans ] djinn* The djinn are genies from the elemental plane of Air. There, among their kind, they have their own societies. They are sometimes encountered on earth and may even be summoned here to perform some service for powerful wizards. The wizards often leave them about for later service, safely tucked away in a flask or lamp. Once in a while, such a tool is found by a lucky rogue, and some djinn are known to be so grateful when released that they might grant their rescuer a wish. # takes "dog or other canine" when specifying 'd' ~hachi ~slasher ~sirius *dog pup* *canine A domestic animal, the _tame dog_ (_Canis familiaris_), of which numerous breeds exist. The male is called a dog, while the female is called a bitch. Because of its known loyalty to man and gentleness with children, it is the world's most popular domestic animal. It can easily be trained to perform various tasks. # typing "spellbook or a closed door" shouldn't yield this entry ~trap*door ~*spellbook* *door doorway Through me you pass into the city of woe: Through me you pass into eternal pain: Through me among the people lost for aye. Justice the founder of my fabric mov'd: To rear me was the task of power divine, Supremest wisdom, and primeval love. Before me things create were none, save things Eternal, and eternal I endure. All hope abandon ye who enter here. [ The Inferno, from The Divine Comedy of Dante Alighieri, translated by H.F. Cary ] doppelganger "Then we can only give thanks that this is Antarctica, where there is not one, single, solitary, living thing for it to imitate, except these animals in camp." "Us," Blair giggled. "It can imitate us. Dogs can't make four hundred miles to the sea; there's no food. There aren't any skua gulls to imitate at this season. There aren't any penguins this far inland. There's nothing that can reach the sea from this point - except us. We've got brains. We can do it. Don't you see - it's got to imitate us - it's got to be one of us - that's the only way it can fly an airplane - fly a plane for two hours, and rule - be - all Earth's inhabitants. A world for the taking - if it imitates us! [ Who Goes There?, by John W. Campbell ] Xander: Let go! I have to kill the demon bot! Xander Double (grabbing the gun): Anya, get out of the way. Buffy: Xander! Xander Double: That's all right, Buffy. I have him. Xander: No, Buffy, I'm me. Help me! Anya: My gun, he's got my gun. Riley: You own a gun? Buffy: Xander, gun holding Xander, give it to me. Anya: Buffy, which one's real? Xander: I am. Xander Double: No, _I_ am. [ Buffy the Vampire Slayer, Episode 5.03, "The Replacement" ] *dragon *xoth In the West the dragon was the natural enemy of man. Although preferring to live in bleak and desolate regions, whenever it was seen among men it left in its wake a trail of destruction and disease. Yet any attempt to slay this beast was a perilous undertaking. For the dragon's assailant had to contend not only with clouds of sulphurous fumes pouring from its fire breathing nostrils, but also with the thrashings of its tail, the most deadly part of its serpent-like body. [ Mythical Beasts by Deirdre Headon (The Leprechaun Library) ] "One whom the dragons will speak with," he said, "that is a dragonlord, or at least that is the center of the matter. It's not a trick of mastering the dragons, as most people think. Dragons have no masters. The question is always the same, with a dragon: will he talk to you or will he eat you? If you can count upon his doing the former, and not doing the latter, why then you're a dragonlord." [ The Tombs of Atuan, by Ursula K. Le Guin ] *dragon*scale* Stephen had argued, and the expert armorer had grudgingly admitted, that dragonscale shield or armor, provided it proved feasible to make at all, ought to offer some real, practical advantages over any metal breastplate or shield -- gram for gram of weight, such a defense would probably be a lot tougher and more protective than any human smiths could make of steel. [ The Last Book of Swords: Shieldbreaker's Story, by Fred Saberhagen ] *drum* Many travelers have seen the drums of the great apes, and some have heard the sounds of their beating and the noise of the wild, weird revelry of these first lords of the jungle, but Tarzan, Lord Greystoke, is, doubtless, the only human being who ever joined in the fierce, mad, intoxicating revel of the Dum-Dum. [ Tarzan of the Apes, by Edgar Rice Burroughs ] dunce* A dunce cap, also variously known as a dunce hat, dunce's cap, or dunce's hat, is a tall conical hat. In popular culture, it is typically made of paper and often marked with a D, and given to schoolchildren to wear as punishment for being stupid or lazy. While this is now a rare practice, it is frequently depicted in popular culture such as children's cartoons. [ Wikipedia, the free encyclopedia ] dungeon* At once as far as Angels kenn he views The dismal Situation waste and wilde, A Dungeon horrible, on all sides round As one great Furnace flam'd, yet from those flames No light, but rather darkness visible Serv'd only to discover sights of woe, Regions of sorrow, doleful shades, where peace And rest can never dwell, hope never comes That comes to all; but torture without end Still urges, and a fiery Deluge, fed With ever-burning Sulphur unconsum'd: Such place Eternal Justice had prepar'd For those rebellious, here their Prison ordain'd In utter darkness, and their portion set As far remov'd from God and light of Heav'n As from the Center thrice to th' utmost Pole. [ Paradise Lost, by John Milton ] ~dwarf ??m* #~dwar* cave*man dwarf* Dwarfs have faces like men (ugly men, with wrinkled, leathery skins), but are generally either flat-footed, duck-footed, or have feet pointing backwards. They are of the earth, earthy, living in the darkest of caverns and venturing forth only with the cloaks by which they can make themselves invisible, and others disguised as toads. Miners often come across them, and sometimes establish reasonably close relations with them. ... The miners of Cornwall were always delighted to hear a bucca busily mining away, for all dwarfs have an infallible nose for precious metals. Among other things, dwarfs are rightly valued for their skill as blacksmiths and jewellers: they made Odin his famous spear Gungnir, and Thor his hammer; for Freya they designed a magnificent necklace, and for Frey a golden boar. And in their spare time they are excellent bakers. Ironically, despite their odd feet, they are particularly fond of dancing. They can also see into the future, and consequently are excellent meteorologists. They can be free with presents to people they like, and a dwarvish gift is likely to turn to gold in the hand. But on the whole they are a snappish lot. [ The Immortals, by Derek and Julia Parker ] earendil elwing In after days, when because of the triumph of Morgoth Elves and Men became estranged, as he most wished, those of the Elven-race that lived still in Middle-earth waned and faded, and Men usurped the sunlight. Then the Quendi wandered in the lonely places of the great lands and the isles, and took to the moonlight and the starlight, and to the woods and the caves, becoming as shadows and memories, save those who ever and anon set sail into the West and vanished from Middle-earth. But in the dawn of years Elves and Men were allies and held themselves akin, and there were some among Men that learned the wisdom of the Eldar, and became great and valiant among the captains of the Noldor. And in the glory and beauty of the Elves, and in their fate, full share had the offspring of elf and mortal, Earendil, and Elwing, and Elrond their child. [ The Silmarillion, by J.R.R. Tolkien ] eel giant eel The behaviour of eels in fresh water extends the air of mystery surrounding them. They move freely into muddy, silty bottoms of lakes, lying buried in the daylight hours in summer. [...] Eels are voracious carnivores, feeding mainly at night and consuming a wide variety of fishes and invertebrate creatures. Contrary to earlier thinking, eels seek living rather than dead creatures and are not habitual eaters of carrion. [ Freshwater Fishes of Canada, by Scott and Crossman ] egg But I asked why not keep it and let the hen sit on it till it hatched, and then we could see what would come out of it. "Nothing good, I'm certain of that," Mom said. "It would probably be something horrible. But just remember, if it's a crocodile or a dragon or something like that, I won't have it in my house for one minute." [ The Enormous Egg, by Oliver Butterworth ] elbereth ... Even as they stepped over the threshold a single clear voice rose in song. A Elbereth Gilthoniel, silivren penna miriel o menel aglar elenath! Na-chaered palan-diriel o galadhremmin ennorath, Fanuilos, le linnathon nef aear, si nef aearon! Frodo halted for a moment, looking back. Elrond was in his chair and the fire was on his face like summer-light upon the trees. Near him sat the Lady Arwen. [...] He stood still enchanted, while the sweet syllables of the elvish song fell like clear jewels of blended word and melody. "It is a song to Elbereth," said Bilbo. "They will sing that, and other songs of the Blessed Realm, many times tonight. Come on!" [ The Fellowship of the Ring, by J.R.R. Tolkien ] electric eel South-American fish (_Gymnotus electricus_), living in fresh water. Shaped like a serpent, it can grow up to 2 metres. This eel is known for its electrical organ which enables it to paralyse creatures up to the size of a horse. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] *elemental Elementals are manifestations of the basic nature of the universe. There are four known forms of elementals: air, fire, water, and earth. Some mystics have postulated the necessity for a fifth type, the spirit elemental, but none have ever been encountered, at least on this plane of existence. ~human or elf* ~elf ??m* *elf* elvenking The Elves sat round the fire upon the grass or upon the sawn rings of old trunks. Some went to and fro bearing cups and pouring drinks; others brought food on heaped plates and dishes. "This is poor fare," they said to the hobbits; "for we are lodging in the greenwood far from our halls. If ever you are our guests at home, we will treat you better." "It seems to me good enough for a birthday-party," said Frodo. Pippin afterwards recalled little of either food or drink, for his mind was filled with the light upon the elf-faces, and the sound of voices so various and so beautiful that he felt in a waking dream. [...] Sam could never describe in words, nor picture clearly to himself, what he felt or thought that night, though it remained in his memory as one of the chief events of his life. The nearest he ever got was to say: "Well, sir, if I could grow apples like that, I would call myself a gardener. But it was the singing that went to my heart, if you know what I mean." [ The Fellowship of the Ring, by J.R.R. Tolkien ] elven cloak The Elves next unwrapped and gave to each of the Company the clothes they had brought. For each they had provided a hood and cloak, made according to his size, of the light but warm silken stuff that the Galadrim wove. It was hard to say of what colour they were: grey with the hue of twilight under the trees they seemed to be; and yet if they were moved, or set in another light, they were green as shadowed leaves, or brown as fallow fields by night, dusk-silver as water under the stars. [ The Fellowship of the Ring, by J.R.R. Tolkien ] emerald 'Put off that mask of burning gold With emerald eyes.' 'O no, my dear, you make so bold To find if hearts be wild and wise, And yet not cold.' 'I would but find what's there to find, Love or deceit.' 'It was the mask engaged your mind, And after set your heart to beat, Not what's behind.' 'But lest you are my enemy, I must enquire.' 'O no, my dear, let all that be; What matter, so there is but fire In you, in me?' [ The Mask, by W.B. Yeats ] engrav* A.S* Presently we reached a place where the beach narrowed; the sea almost came up to the foot of the cliffs, leaving a passage no wider than a couple of yards. Between two projecting rocks we caught sight of the entrance to a dark tunnel. There, on a slab of granite, appeared two mysterious letters, half eaten away by time -- the two initials of the bold, adventurous traveller: A.S. 'A.S.,' cried my uncle. 'Arne Saknussemm! Arne Saknussemm again!' [...] at the sight of those two letters, carved there three hundred years before, I stood in utter stupefaction. Not only was the signature of the learned alchemist legible on the rock, but I held in my hand the dagger which had traced it. Without showing the most appalling bad faith, I could no longer doubt the existence of the traveller and the reality of his journey. [ Journey to the Centre of the Earth, by Jules Verne, translated by Robert Baldick ] *epidaurus The asclepieion at Epidaurus was the most celebrated healing center of the Classical world, the place where ill people went in the hope of being cured. To find out the right cure for their ailments, they spent a night in the enkoimitiria, a big sleeping hall. In their dreams, the god himself (Asclepius) would advise them what they had to do to regain their health. There are also mineral springs in the vicinity which may have been used in healing. [ Wikipedia, the free encyclopedia ] erinys erinyes These female-seeming devils named after the Furies of mythology attack hand to hand and poison their unwary victims as well. ettin The two-headed giant, or ettin, is a vicious and unpredictable hunter that stalks by night and eats any meat it can catch. excalibur At first only its tip was visible, but then it rose, straight, proud, all that was noble and great and wondrous. The tip of the blade pointed toward the moon, as if it would cleave it in two. The blade itself gleamed like a beacon in the night. There was no light source for the sword to be reflecting from, for the moon had darted behind a cloud in fear. The sword was glowing from the intensity of its strength and power and knowledge that it was justice incarnate, and that after a slumber of uncounted years its time had again come. After the blade broke the surface, the hilt was visible, and holding the sword was a single strong, yet feminine hand, wearing several rings that bore jewels sparkling with the blue-green color of the ocean. [ Knight Life, by Peter David ] expensive camera There was a time when Rincewind had quite liked the iconoscope. He believed, against all experience, that the world was fundamentally understandable, and that if he could only equip himself with the right mental toolbox he could take the back off and see how it worked. He was, of course, dead wrong. The iconoscope didn't take pictures by letting light fall onto specially treated paper, as he had surmised, but by the far simpler method of imprisoning a small demon with a good eye for colour and a speedy hand with a paintbrush. He had been very upset to find that out. [ The Light Fantastic, by Terry Pratchett ] eye of the aethiopica This is a powerful amulet of ESP. In addition to its standard powers, it regenerates the energy of anyone who carries it, allowing them to cast spells more often. It also reduces any spell damage to the person who carries it by half, and protects from magic missiles. Finally, when invoked it has the power to instantly open a portal to any other area of the dungeon, allowing its invoker to travel quickly between areas. eyes of the overworld ... and finally there is "the Eyes of the Overworld". This obscure artifact pushes the wearer's view sense into the "overworld" -- another name for a segment of the Astral Plane. Usually, there is nothing to be seen. However, the wearer is also able to look back and see the area around herself, much like looking on a map. Why anyone would want to ... fedora Some hats can only be worn if you're willing to be jaunty, to set them at an angle and to walk beneath them with a spring in your stride as if you're only a step away from dancing. They demand a lot of you. [ Anansi Boys, by Neil Gaiman ] figurine* Then it appeared in Paris at just about the time that Paris was full of Carlists who had to get out of Spain. One of them must have brought it with him, but, whoever he was, it's likely he knew nothing about its real value. It had been -- no doubt as a precaution during the Carlist trouble in Spain -- painted or enameled over to look like nothing more than a fairly interesting black statuette. And in that disguise, sir, it was, you might say, kicked around Paris for seventy years by private owners and dealers too stupid to see what it was under the skin. [ The Maltese Falcon, by Dashiell Hammett ] fire trap 'Let him be for a while,' said Cohen. 'I reckon the fish disagreed with him.' 'Don't see why,' said Truckle. 'I pulled him out before it'd hardly chewed him. And he must've dried out nicely in that corridor. You know, the one where the flames shot up out of the floor unexpectedly.' 'I reckon our bard wasn't expecting flames to shoot out of the floor unexpectedly,' said Cohen. Truckle shrugged theatrically. '_Well_, if you're not going to expect unexpected flames, what's the point of going _anywhere_?' [ The Last Hero, by Terry Pratchett ] f* brand One of a pair of legendary swords that possess the powers of elemental flame and ice, and will grant these to whoever is fortunate enough to wield them. flesh golem With an anxiety that almost amounted to agony, I collected the instruments of life around me, that I might infuse a spark of being into the lifeless thing that lay at my feet. It was already one in the morning; the rain pattered dismally against the panes, and my candle was nearly burnt out, when, by the glimmer of the half-extinguished light, I saw the dull yellow eye of the creature open; it breathed hard, and a convulsive motion agitated its limbs. How can I describe my emotions at this catastrophe, or how delineate the wretch whom with such infinite pains and care I had endeavoured to form? His limbs were in proportion, and I had selected his features as beautiful. Beautiful!--Great God! His yellow skin scarcely covered the work of muscles and arteries beneath; his hair was of a lustrous black, and flowing; his teeth of a pearly whiteness; but these luxuriances only formed a more horrid contrast with his watery eyes, that seemed almost of the same colour as the dun white sockets in which they were set, his shrivelled complexion and straight black lips. [ Frankenstein, by Mary Wollstonecraft Shelley ] flint* An emerald is as green as grass; A ruby red as blood; A sapphire shines as blue as heaven; A flint lies in the mud. A diamond is a brilliant stone, To catch the world's desire; An opal holds a fiery spark; But a flint holds fire. [ Precious Stones, by Christina Giorgina Rossetti ] floating eye Floating eyes, not surprisingly, are large, floating eyeballs which drift about the dungeon. Though not dangerous in and of themselves, their power to paralyse those who gaze at their large eye in combat is widely feared. Many are the tales of those who struck a floating eye, were paralysed by its mystic powers, and then nibbled to death by some other creature that lurked around nearby. *flute With this thou canst do mighty deeds And change men's passions for thy needs: A man's despair with joy allay, Turn bachelors old to lovers gay. [ The Magic Flute, by Wolfgang Amadeus Mozart ] # also takes fog/vapor cloud fog* cloud The fog comes on little cat feet. It sits looking over harbor and city on silent haunches and then moves on. [ Fog, by Carl Sandburg ] # includes "food detection" and "detect food", which might not be the best *food* The little girl stood on tip-toe and picked one of the nicest and biggest lunch-boxes, and then she sat down upon the ground and eagerly opened it. Inside she found, nicely wrapped in white papers, a ham sandwich, a piece of sponge-cake, a pickle, a slice of new cheese and an apple. Each thing had a separate stem, and so had to be picked off the side of the box; but Dorothy found them all to be delicious, and she ate every bit of luncheon in the box before she had finished. [ Ozma of Oz, by L. Frank Baum ] fountain Rest! This little Fountain runs Thus for aye: -- It never stays For the look of summer suns, Nor the cold of winter days. Whose'er shall wander near, When the Syrian heat is worst, Let him hither come, nor fear Lest he may not slake his thirst: He will find this little river Running still, as bright as ever. Let him drink, and onward hie, Bearing but in thought, that I, Erotas, bade the Naiad fall, And thank the great god Pan for all! [ For a Fountain, by Bryan Waller Procter ] fox One hot summer's day a Fox was strolling through an orchard till he came to a bunch of Grapes just ripening on a vine which had been trained over a lofty branch. "Just the thing to quench my thirst," quoth he. Drawing back a few paces, he took a run and a jump, and just missed the bunch. Turning round again with a One, Two, Three, he jumped up, but with no greater success. Again and again he tried after the tempting morsel, but at last had to give it up, and walked away with his nose in the air, saying: "I am sure they are sour." [ Aesop's Fables ] *fung* Fungi, division of simple plants that lack chlorophyll, true stems, roots, and leaves. Unlike algae, fungi cannot photosynthesize, and live as parasites or saprophytes. The division comprises the slime molds and true fungi. True fungi are multicellular (with the exception of yeasts); the body of most true fungi consists of slender cottony filaments, or hyphae. All fungi are capable of asexual reproduction by cell division, budding, fragmentation, or spores. Those that reproduce sexually alternate a sexual generation (gametophyte) with a spore-producing one. The four classes of true fungi are the algaelike fungi (e.g., black bread mold and downy mildew), sac fungi (e.g., yeasts, powdery mildews, truffles, and blue and green molds such as Penicillium), basidium fungi (e.g., mushrooms and puffballs) and imperfect fungi (e.g., species that cause athlete's foot and ringworm). Fungi help decompose organic matter (important in soil renewal); are valuable as a source of antibiotics, vitamins, and various chemicals; and for their role in fermentation, e.g., in bread and alcoholic beverage production. [ The Concise Columbia Encyclopedia ] *gargoyle And so it came to pass that while Man ruled on Earth, the gargoyles waited, lurking, hidden from the light. Reborn every 600 years in Man's reckoning of time, the gargoyles joined battle against Man to gain dominion over the Earth. In each coming, the gargoyles were nearly destroyed by Men who flourished in greater numbers. Now it has been so many hundreds of years that it seems the ancient statues and paintings of gargoyles are just products of Man's imagination. In this year, with Man's thoughts turned toward the many ills he has brought among himself, Man has forgotten his most ancient adversary, the gargoyles. [ Excerpt from the opening narration to the movie _Gargoyles_, written by Stephen and Elinor Karpf ] *garlic 1 November - All day long we have travelled, and at a good speed. The horses seem to know that they are being kindly treated, for they go willingly their full stage at best speed. We have now had so many changes and find the same thing so constantly that we are encouraged to think that the journey will be an easy one. Dr. Van Helsing is laconic, he tells the farmers that he is hurrying to Bistritz, and pays them well to make the exchange of horses. We get hot soup, or coffee, or tea, and off we go. It is a lovely country. Full of beauties of all imaginable kinds, and the people are brave, and strong, and simple, and seem full of nice qualities. They are very, very superstitious. In the first house where we stopped, when the woman who served us saw the scar on my forehead, she crossed herself and put out two fingers towards me, to keep off the evil eye. I believe they went to the trouble of putting an extra amount of garlic into our food, and I can't abide garlic. Ever since then I have taken care not to take off my hat or veil, and so have escaped their suspicions. [ Dracula, by Bram Stoker ] # gas spore -- see *spore gehenn* *h?nnom hell "Place of Torment." The Valley of Hinnom, south-west of Jerusalem, where Solomon, king of Israel, built "a high place", or place of worship, for the gods Chemosh and Moloch. The valley came to be regarded as a place of abomination because some of the Israelites sacrificed their children to Moloch there. In a later period it was made a refuse dump and perpetual fires were maintained there to prevent pestilence. Thus, in the New Testament, Gehenna became synonymous with hell. [ Encyclopedia Mythica, ed. M.F. Lindemans ] gelatinous cube Despite its popularity (or perhaps because of it), the gelatinous cube is also widely known as one of the sillier role-playing monsters. It is something of a commentary on the ubiquity of treasure-laden dungeons in the Dungeons & Dragons universe, as the cube is a creature specifically adapted to a dungeon ecosystem. 10 feet to the side, it travels through standard 10-foot by 10-foot dungeon corridors, cleaning up debris and redistributing treasure by excreting indigestible metal items. [ Wikipedia, the free encyclopedia ] *gem gem or rock The difference between false memories and true ones is the same as for jewels: it is always the false ones that look the most real, the most brilliant. [ Salvador Dali ] geryon Forthwith that image vile of fraud appear'd, His head and upper part expos'd on land, But laid not on the shore his bestial train. His face the semblance of a just man's wore, So kind and gracious was its outward cheer; The rest was serpent all: two shaggy claws Reach'd to the armpits, and the back and breast, And either side, were painted o'er with nodes And orbits. Colours variegated more Nor Turks nor Tartars e'er on cloth of state With interchangeable embroidery wove, Nor spread Arachne o'er her curious loom. As ofttimes a light skiff, moor'd to the shore, Stands part in water, part upon the land; Or, as where dwells the greedy German boor, The beaver settles watching for his prey; So on the rim, that fenc'd the sand with rock, Sat perch'd the fiend of evil. In the void Glancing, his tail upturn'd its venomous fork, With sting like scorpion's arm'd. Then thus my guide: "Now need our way must turn few steps apart, Far as to that ill beast, who couches there." [ The Inferno, from The Divine Comedy of Dante Alighieri, translated by H.F. Cary ] *ghost valley of *dea* And now the souls of the dead who had gone below came swarming up from Erebus -- fresh brides, unmarried youths, old men with life's long suffering behind them, tender young girls still nursing this first anguish in their hearts, and a great throng of warriors killed in battle, their spear-wounds gaping yet and all their armour stained with blood. From this multitude of souls, as they fluttered to and fro by the trench, there came a moaning that was horrible to hear. Panic drained the blood from my cheeks. [ The Odyssey, (chapter Lambda), by Homer ] ghoul The forces of the gloom know each other, and are strangely balanced by each other. Teeth and claws fear what they cannot grasp. Blood-drinking bestiality, voracious appetites, hunger in search of prey, the armed instincts of nails and jaws which have for source and aim the belly, glare and smell out uneasily the impassive spectral forms straying beneath a shroud, erect in its vague and shuddering robe, and which seem to them to live with a dead and terrible life. These brutalities, which are only matter, entertain a confused fear of having to deal with the immense obscurity condensed into an unknown being. A black figure barring the way stops the wild beast short. That which emerges from the cemetery intimidates and disconcerts that which emerges from the cave; the ferocious fear the sinister; wolves recoil when they encounter a ghoul. [ Les Miserables, by Victor Hugo ] *giant giant humanoid Giants have always walked the earth, though they are rare in these times. They range in size from little over nine feet to a towering twenty feet or more. The larger ones use huge boulders as weapons, hurling them over large distances. All types of giants share a love for men - roasted, boiled, or fried. Their table manners are legendary. # note: "gnomish wizard" is a monster ~gnome ??m* #~gnom* cave*man gnome* gnomish wizard ... And then a gnome came by, carrying a bundle, an old fellow three times as large as an imp and wearing clothes of a sort, especially a hat. And he was clearly just as frightened as the imps though he could not go so fast. Ramon Alonzo saw that there must be some great trouble that was vexing magical things; and, since gnomes speak the language of men, and will answer if spoken to gently, he raised his hat, and asked of the gnome his name. The gnome did not stop his hasty shuffle a moment as he answered 'Alaraba' and grabbed the rim of his hat but forgot to doff it. 'What is the trouble, Alaraba?' said Ramon Alonzo. 'White magic. Run!' said the gnome .. [ The Charwoman's Shadow, by Lord Dunsany ] "Muggles have garden gnomes, too, you know," Harry told Ron as they crossed the lawn. "Yeah, I've seen those things they think are gnomes," said Ron, bent double with his head in a peony bush, "like fat little Santa Clauses with fishing rods..." There was a violent scuffling noise, the peony bush shuddered, and Ron straightened up. "This is a gnome," he said grimly. "Geroff me! Gerroff me!" squealed the gnome. It was certainly nothing like Santa Claus. It was small and leathery looking, with a large, knobby, bald head exactly like a potato. Ron held it at arm's length as it kicked out at him with its horny little feet; he grasped it around the ankles and turned it upside down. [ Harry Potter and the Chamber of Secrets, by J. K. Rowling ] goblin Now goblins are cruel, wicked, and bad-hearted. They make no beautiful things, but they make many clever ones. They can tunnel and mine as well as any but the most skilled dwarves, when they take the trouble, though they are usually untidy and dirty. Hammers, axes, swords, daggers, pickaxes, tongs, and also instruments of torture, they make very well, or get other people to make to their design, prisoners and slaves that have to work till they die for want of air and light. [ The Hobbit, by J.R.R. Tolkien ] god goddess Goddesses and Gods operate in ones, threesomes, or whole pantheons of nine or more (see Religion). Most of them claim to have made the world, and this is indeed a likely claim in the case of threesomes or pantheons: Fantasyland does have the air of having been made by a committee. But all Goddesses and Gods, whether they say they made the world or not, have very detailed short-term plans for it which they are determined to carry out. Consequently they tend to push people into the required actions by the use of coincidence or Prophecy, or just by narrowing down your available choices of what to do next: if a deity is pushing you, things will go miserably badly until there is only one choice left to you. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] gold gold piece A metal of characteristic yellow colour, the most precious metal used as a common commercial medium of exchange. Symbol, Au; at. no. 79; at. wt. 197.2. It is the most malleable and ductile of all metals, and very heavy (sp. gr., 19.3). It is quite unalterable by heat, moisture, and most corrosive agents, and therefore well suited for its use in coin and jewelry. [ Webster's New International Dictionary of the English Language, Second Edition ] gold golem The bellows he set away from the fire, and gathered all the tools wherewith he wrought into a silver chest; and with a sponge wiped he his face and his two hands withal, and his mighty neck and shaggy breast, and put upon him a tunic, and grasped a stout staff, and went forth halting; but there moved swiftly to support their lord handmaidens wrought of gold in the semblance of living maids. In them is understanding in their hearts, and in them speech and strength, and they know cunning handiwork by gift of the immortal gods. [ The Iliad, by Homer ] ~flesh golem ~gold golem ~straw golem ~wood golem *golem "The original story harks back, so they say, to the sixteenth century. Using long-lost formulas from the Kabbala, a rabbi is said to have made an artificial man -- the so-called Golem -- to help ring the bells in the Synagogue and for all kinds of other menial work. "But he hadn't made a full man, and it was animated by some sort of vegetable half-life. What life it had, too, so the story runs, was only derived from the magic charm placed behind its teeth each day, that drew down to itself what was known as the `free sidereal strength of the universe.' "One evening, before evening prayers, the rabbi forgot to take the charm out of the Golem's mouth, and it fell into a frenzy. It raged through the dark streets, smashing everything in its path, until the rabbi caught up with it, removed the charm, and destroyed it. Then the Golem collapsed, lifeless. All that was left of it was a small clay image, which you can still see in the Old Synagogue." ... [ The Golem, by Gustav Meyrink ] grave "Who'd care to dig 'em," said the old, old man, "Those six feet marked in chalk? Much I talk, more I walk; Time I were buried," said the old, old man. [ Three Songs to the Same Tune, by W.B. Yeats ] grayswandir Why had I been wearing Grayswandir? Would another weapon have affected a Logrus-ghost as strongly? Had it really been my father, then, who had brought me here? And had he felt I might need the extra edge his weapon could provide? I wanted to think so, to believe that he had been more than a Pattern-ghost. [ Knight of Shadows, by Roger Zelazny ] *grease ANOINT, v.t. To grease a king or other great functionary already sufficiently slippery. [ The Devil's Dictionary, by Ambrose Bierce ] gremlin The gremlin is a highly intelligent and completely evil creature. It lives to torment other creatures and will go to great lengths to inflict pain or cause injury. [] Suddenly, Wilson thought about war, about the newspaper stories which recounted the alleged existence of creatures in the sky who plagued the Allied pilots in their duties. They called them gremlins, he remembered. Were there, actually, such beings? Did they, truly, exist up here, never falling, riding on the wind, apparently of bulk and weight, yet impervious to gravity? He was thinking that when the man appeared again. [ Nightmare at 20,000 Feet, by Richard Matheson ] grid bug These electronically based creatures are not native to this universe. They appear to come from a world whose laws of motion are radically different from ours. [] Tron looked to his mate and pilot. "I'm going to check on the beam connection, Yori. You two can keep a watch out for grid bugs." Tron paced forward along the slender catwalk that still seemed awfully insubstantial to Flynn, though he knew it to be amazingly sturdy. He gazed after Tron, asking himself what in the world a grid bug was, and hoping that the beam connection -- to which he'd given no thought whatsoever until this moment -- was healthy and sound." [ Tron, novel by Brian Daley, story by Steven Lisberger ] gunyoki The samurai's last meal before battle. It was usually made up of cooked chestnuts, dried seaweed, and sake. hachi Hachi was a dog that went with his master, a professor, to the Shibuya train station every morning. In the afternoon, when his master was to return from work Hachi would be there waiting. One day his master died at the office, and did not return. For over ten years Hachi returned to the station every afternoon to wait for his master. When Hachi died a statue was erected on the station platform in his honor. It is said to bring you luck if you touch his statue. *harp A triangular stringed instrument, often Magic. Even when not Magic, a Harp is surprisingly portable and tough and can be carried everywhere on the back of the Bard or Harper in all weathers. A Harp seldom goes out of tune and never warps. Its strings break only in very rare instances, usually because the Harper is sulking or crossed in love. This is just as well as no one seems to make or sell spare strings. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] After breakfast was over, the ogre called out: "Wife, wife, bring me my golden harp." So she brought it and put it on the table before him. Then he said: "Sing!" and the golden harp sang most beautifully. And it went on singing till the ogre fell asleep, and commenced to snore like thunder. Then Jack lifted up the copper-lid very quietly and got down like a mouse and crept on hands and knees till he came to the table, when up he crawled, caught hold of the golden harp and dashed with it towards the door. But the harp called out quite loud: "Master! Master!" and the ogre woke up just in time to see Jack running off with his harp. [ Jack and the Beanstalk, from English Fairy Tales, by Joseph Jacobs ] hawaiian*shirt 'One of the things he can't do, he can't ride a horse,' he said. Then he stiffened as if sandbagged by a sudden recollection, gave a small yelp of terror and dashed into the gloom. When he returned, the being called Twoflower was hanging limply over his shoulder. It was small and skinny, and dressed very oddly in a pair of knee-length britches and a shirt in such a violent and vivid conflict of colours that the Weasel's fastidious eye was offended even in the half-light. [ The Colour of Magic, by Terry Pratchett ] healer * healer attendant doctor physician I swear by Apollo the physician, and Aesculapius, and Health, and All-heal, and all the gods and goddesses, that, according to my ability and judgment, I will keep this Oath and this stipulation -- to reckon him who taught me this Art equally dear to me as my parents, to share my substance with him, and relieve his necessities if required; to look upon his offspring in the same footing as my own brothers, and to teach them this art, if they shall wish to learn it, without fee or stipulation; and that by precept, lecture, and every other mode of instruction, I will impart a knowledge of the Art to my own sons, and those of my teachers, and to disciples bound by a stipulation and oath according to the law of medicine, but to none others. I will follow that system of regimen which, according to my ability and judgment, I consider for the benefit of my patients, and abstain from whatever is deleterious and mischievous. [...] [ Hippocrates' Oath, translated by Francis Adams ] PHYSICIAN, n. One upon whom we set our hopes when ill and our dogs when well. [ The Devil's Dictionary, by Ambrose Bierce ] heart of ahriman The other three drew in their breath sharply, and the dark, powerful man who stood at the head of the sarcophagus whispered: "The Heart of Ahriman!" The other lifted a quick hand for silence. Somewhere a dog began howling dolefully, and a stealthy step padded outside the barred and bolted door. ... But none looked aside from the mummy case over which the man in the ermine-trimmed robe was now moving the great flaming jewel, while he muttered an incantation that was old when Atlantis sank. The glare of the gem dazzled their eyes, so that they could not be sure what they saw; but with a splintering crash, the carven lid of the sarcophagus burst outward as if from some irresistible pressure applied from within and the four men, bending eagerly forward, saw the occupant -- a huddled, withered, wizened shape, with dried brown limbs like dead wood showing through moldering bandages. "Bring that thing back?" muttered the small dark man who stood on the right, with a short, sardonic laugh. "It is ready to crumble at a touch. We are fools ---" [ Conan The Conqueror, by Robert E. Howard ] hell hound* But suddenly they started forward in a rigid, fixed stare, and his lips parted in amazement. At the same instant Lestrade gave a yell of terror and threw himself face downward upon the ground. I sprang to my feet, my inert hand grasping my pistol, my mind paralyzed by the dreadful shape which had sprung out upon us from the shadows of the fog. A hound it was, an enormous coal-black hound, but not such a hound as mortal eyes have ever seen. Fire burst from its open mouth, its eyes glowed with a smouldering glare, its muzzle and hackles and dewlap were outlined in flickering flame. Never in the delirious dream of a disordered brain could anything more savage, more appalling, more hellish be conceived than that dark form and savage face which broke upon us out of the wall of fog. [ The Hound of the Baskervilles, by Sir Arthur Conan Doyle. ] hermes Messenger and herald of the Olympians. Being required to do a great deal of travelling and speaking in public, he became the god of eloquence, travellers, merchants, and thieves. He was one of the most energetic of the Greek gods, a Machiavellian character full of trickery and sexual vigour. Like other Greek gods, he is endowed with not-inconsiderable sexual prowess which he directs towards countryside nymphs. He is a god of boundaries, guardian of graves and patron deity of shepherds. He is usually depicted as a handsome young man wearing winged golden sandals and holding a magical herald's staff consisting of intertwined serpents, the kerykeion. He is reputedly the only being able to find his way to the underworld ferry of Charon and back again. He is said to have invented, among other things, the lyre, Pan's Pipes, numbers, the alphabet, weights and measures, and sacrificing. hezrou "Hezrou" is the common name for the type II demon. It is among the weaker of demons, but still quite formidable. hippocrates Greek physician, recognized as the father of medicine. He is believed to have been born on the island of Cos, to have studied under his father, a physician, to have traveled for some time, perhaps studying in Athens, and to have then returned to practice, teach, and write at Cos. The Hippocratic or Coan school that formed around him was of enormous importance in separating medicine from superstition and philosophic speculation, placing it on a strictly scientific plane based on objective observation and critical deductive reasoning. [ The Columbia Encyclopedia, Sixth Edition ] hobbit Hobbits are an unobtrusive but very ancient people, more numerous formerly than they are today; for they love peace and quiet and good tilled earth: a well-ordered and well- farmed countryside was their favourite haunt. They do not and did not understand or like machines more complicated than a forge-bellows, a water-mill, or a handloom, although they were skillful with tools. Even in ancient days they were, as a rule, shy of "the Big Folk", as they call us, and now they avoid us with dismay and are becoming hard to find. [ The Fellowship of the Ring, by J.R.R. Tolkien ] hobgoblin Hobgoblin. Used by the Puritans and in later times for wicked goblin spirits, as in Bunyan's "Hobgoblin nor foul friend", but its more correct use is for the friendly spirits of the brownie type. In "A midsummer night's dream" a fairy says to Shakespeare's Puck: Those that Hobgoblin call you, and sweet Puck, You do their work, and they shall have good luck: Are you not he? and obviously Puck would not wish to be called a hobgoblin if that was an ill-omened word. Hobgoblins are on the whole, good-humoured and ready to be helpful, but fond of practical joking, and like most of the fairies rather nasty people to annoy. Boggarts hover on the verge of hobgoblindom. Bogles are just over the edge. One Hob mentioned by Henderson, was Hob Headless who haunted the road between Hurworth and Neasham, but could not cross the little river Kent, which flowed into the Tess. He was exorcised and laid under a large stone by the roadside for ninety-nine years and a day. If anyone was so unwary as to sit on that stone, he would be unable to quit it for ever. The ninety-nine years is nearly up, so trouble may soon be heard of on the road between Hurworth and Neasham. [ A Dictionary of Fairies, by Katharine Briggs ] holy water "We want a word with you," said Ligur (in a tone of voice intended to imply that "word" was synonymous with "horrifically painful eternity"), and the squat demon pushed open the office door. The bucket teetered, then fell neatly on Ligur's head. Drop a lump of sodium in water. Watch it flame and burn and spin around crazily, flaring and sputtering. This was like that, just nastier. The demon peeled and flared and flickered. Oily brown smoke oozed from it, and it screamed and it screamed and it screamed. Then it crumpled, folded in on itself, and what was left lay glistening on the burnt and blackened circle of carpet, looking like a handful of mashed slugs. "Hi," said Crowley to Hastur, who had been walking behind Ligur, and had unfortunately not been so much as splashed. There are some things that are unthinkable; there are some depths that not even demons would believe other demons would stoop to. ". . . Holy water. You bastard," said Hastur. "You complete _bastard_. He hadn't never done nothing to _you_." "Yet," corrected Crowley. [ Good Omens, by Neil Gaiman and Terry Pratchett ] hom*nculus A homunculus is a creature summoned by a mage to perform some particular task. They are particularly good at spying. They are smallish creatures, but very agile. They can put their victims to sleep with a venomous bite, but due to their size, the effect does not last long on humans. "Tothapis cut him off. 'Be still and hearken. You will travel aboard the sacred wingboat. Of it you may not have heard; but it will bear you thither in a night and a day and a night. With you will go a homunculus that can relay your words to me, and mine to you, across the leagues between at the speed of thought.'" [ Conan the Rebel, by Poul Anderson ] # also gets 'pruning hook' aka guisarme *hook But as for Queequeg -- why, Queequeg sat there among them -- at the head of the table, too, it so chanced; as cool as an icicle. To be sure I cannot say much for his breeding. His greatest admirer could not have cordially justified his bringing his harpoon into breakfast with him, and using it there without ceremony; reaching over the table with it, to the imminent jeopardy of many heads, and grappling the beefsteaks towards him. [ Moby Dick, by Herman Melville ] ~unicorn horn *horn Roland hath set the Olifant to his mouth, He grasps it well, and with great virtue sounds. High are those peaks, afar it rings and loud, Thirty great leagues they hear its echoes mount. So Charles heard, and all his comrades round; Then said that King: "Battle they do, our counts!" And Guenelun answered, contrarious: "That were a lie, in any other mouth." [ The Song of Roland ] horn of plenty cornucopia The infant Zeus was fed with goat's milk by Amalthea, daughter of Melisseus, King of Crete. Zeus, in gratitude, broke off one of the goat's horns, and gave it to Amalthea, promising that the possessor should always have in abundance everything desired. [ Brewer's Concise Dictionary of Phrase and Fable ] When Amalthea's horn O'er hill and dale the rose-crowned flora pours, And scatters corn and wine, and fruits and flowers. [ Os Lusiadas, by Luis Vaz de Camoes ] horned devil Horned devils lack any real special abilities, though they are quite difficult to kill. ~horsem* *horse King Richard III: A horse! a horse! my kingdom for a horse! Catesby: Withdraw, my lord; I'll help you to a horse. King Richard III: Slave, I have set my life upon a cast, And I will stand the hazard of the die: I think there be six Richmonds in the field; Five have I slain to-day instead of him. A horse! a horse! my kingdom for a horse! [ King Richard III, by William Shakespeare ] *horsem* rider* death famine pestilence war hunger [Pestilence:] And I saw when the Lamb opened one of the seals, and I heard, as it were the noise of thunder, one of the four beasts saying, Come and see. And I saw, and behold a white horse: and he that sat on him had a bow; and a crown was given unto him: and he went forth conquering, and to conquer. [War:] And when he had opened the second seal, I heard the second beast say, Come and see. And there went out another horse that was red: and power was given to him that sat thereon to take peace from the earth, and that they should kill one another: and there was given unto him a great sword. [Famine:] And when he had opened the third seal, I heard the third beast say, Come and see. And I beheld, and lo a black horse; and he that sat on him had a pair of balances in his hand. And I heard a voice in the midst of the four beasts say, A measure of wheat for a penny, and three measures of barley for a penny; and see thou hurt not the oil and the wine. [Death:] And when he had opened the fourth seal, I heard the voice of the fourth beast say, Come and see. And I looked, and behold a pale horse: and his name that sat on him was Death, and Hell followed with him. And power was given unto them over the fourth part of the earth, to kill with sword, and with hunger, and with death, and with the beasts of the earth. [ Revelations of John, 6:1-8 ] huan*ti The first of five mythical Chinese emperors, Huan Ti is known as the yellow emperor. He rules the _moving_ heavens, as opposed to the _dark_ heavens. He is an inventor, said to have given mankind among other things, the wheel, armour, and the compass. He is the god of fortune telling and war. hu*h*eto*l minion of huhetotl Huehuetotl, or Huhetotl, which means Old God, was the Aztec (classical Mesoamerican) god of fire. He is generally associated with paternalism and one of the group classed as the Xiuhtecuhtli complex. He is known to send his minions to wreak havoc upon ordinary humans. [ after the Encyclopedia of Gods, by Michael Jordan ] humanoid Humanoids are all approximately the size of a human, and may be mistaken for one at a distance. They are usually of a tribal nature, and will fiercely defend their lairs. Usually hostile, they may even band together to raid and pillage human settlements. # takes "human or elf or you" when specifying '@' as a dwarf, gnome, or orc human chieftain guard ninja nurse ronin student warrior *watch* human or elf* These strange creatures live mostly on the surface of the earth, gathering together in societies of various forms, but occasionally a stray will descend into the depths and commit mayhem among the dungeon residents who, naturally, often resent the intrusion of such beasts. They are capable of using weapons and magic, and it is even rumored that the Wizard of Yendor is a member of this species. hunter What of the hunting, hunter bold? Brother, the watch was long and cold. What of the quarry ye went to kill? Brother, he crops in the jungle still. Where is the power that made your pride? Brother, it ebbs from my flank and side. Where is the haste that ye hurry by? Brother, I go to my lair to die. [ The Jungle Book, by Rudyard Kipling ] ice devil Ice devils are large semi-insectoid creatures, who are equally at home in the fires of Hell and the cold of Limbo, and who can cause the traveller to feel the latter with just a touch of their tail. idefix Another clever translation [of the _Asterix_ character names] is that of Idefix. An _idee fixe_ is a "fixed idea", i.e. an obsession, a dogma. The translation, Dogmatix, manages to conserve the "fixed idea" meaning and also include the syllable dog -- perfect, given that the character is a dog who has very strong views on the environment (he howls whenever he sees an uprooted tree). [ Wikipedia, the free encyclopedia ] # takes "imp or minor demon" when specifying 'i' imp imp or minor demon ... imps ... little creatures of two feet high that could gambol and jump prodigiously; ... [ The Charwoman's Shadow, by Lord Dunsany ] An 'imp' is an off-shoot or cutting. Thus an 'ymp tree' was a grafted tree, or one grown from a cutting, not from seed. 'Imp' properly means a small devil, an off-shoot of Satan, but the distinction between goblins or bogles and imps from hell is hard to make, and many in the Celtic countries as well as the English Puritans regarded all fairies as devils. The fairies of tradition often hover uneasily between the ghostly and the diabolic state. [ A Dictionary of Fairies, by Katharine Briggs ] incubus succubus The incubus and succubus are male and female versions of the same demon, one who lies with a human for its own purposes, usually to the detriment of the mortals who are unwise in their dealings with them. *insect *insects A minute invertebrate animal; one of the class _Insecta_. The true insects or hexapods have the body divided into a head, a thorax of 3 segments, each of which bears a pair of legs, and an abdomen of 7 to 11 segments, and in development usually pass through a metamorphosis. There are usually 2 pairs of wings, sometimes one pair or none. [ Webster's Comprehensive International Dictionary of the English Language ] Else, if thou refuse to let my people go, behold, to morrow will I bring the locusts into thy coast: And they shall cover the face of the earth, that one cannot be able to see the earth: and they shall eat the residue of that which is escaped, which remaineth unto you from the hail, and shall eat every tree which groweth for you out of the field: And they shall fill thy houses, and the houses of all thy servants, and the houses of all the Egyptians; which neither thy fathers, nor thy fathers' fathers have seen, since the day that they were upon the earth unto this day. And he turned himself, and went out from Pharaoh. [ Exodus, 10:4-6 ] *iron ball *iron chain "You are fettered, " said Scrooge, trembling. "Tell me why?" "I wear the chain I forged in life," replied the Ghost. "I made it link by link, and yard by yard; I girded it on of my own free will, and of my own free will I wore it. Is its pattern strange to you?" Scrooge trembled more and more. "Or would you know," pursued the Ghost, "the weight and length of the strong coil you bear yourself? It was full as heavy and as long as this, seven Christmas Eves ago. You have laboured on it, since. It is a ponderous chain!" [ A Christmas Carol, by Charles Dickens ] iron bars Stone walls do not a prison make, Nor iron bars a cage; Minds innocent and quiet take That for an hermitage; If I have freedom in my love, And in my soul am free, Angels alone that soar above Enjoy such liberty. [ To Althea from Prison, by Richard Lovelace ] ishtar Ishtar (the star of heaven) is the Mesopotamian goddess of fertility and war. She is usually depicted with wings and weapon cases at her shoulders, carrying a ceremonial double- headed mace-scimitar embellished with lion heads, frequently being accompanied by a lion. She is symbolized by an eight- pointed star. [ Encyclopedia of Gods, by Michael Jordan ] issek Now Issek of the Jug, whom Fafhrd chose to serve, was once of the most lowly and unsuccessful of the gods, godlets rather, in Lankhmar. He had dwelt there for about thirteen years, during which time he had traveled only two squares up the Street of the Gods and was now back again, ready for oblivion. He is not to be confused with Issek the Armless, Issek of the Burnt Legs, Flayed Issek, or any other of the numerous and colorfully mutilated divinities of that name. Indeed, his unpopularity may have been due in part to the fact that the manner of his death -- racking -- was not deemed particularly spectacular. ... However, after Fafhrd became his acolyte, things somehow began to change. [ Swords In The Mist, by Fritz Leiber ] izchak The shopkeeper of the lighting shop in the town level of the gnomish mines is a tribute to Izchak Miller, a founding member of the NetHack development team and a personal friend of a large number of us. Izchak contributed greatly to the game, coding a large amount of the shopkeep logic (hence the nature of the tribute) as well as a good part of the alignment system, the prayer code and the rewrite of "hell" in the 3.1 release. Izchak was a professor of Philosophy, who taught at many respected institutions, including MIT and Stanford, and who also worked, for a period of time, at Xerox PARC. Izchak was the first "librarian" of the NetHack project, and was a founding member of the DevTeam, joining in 1986 while he was working at the University of Pennsylvania (hence our former mailing list address). Until the 3.1.3 release, Izchak carefully kept all of the code synchronized and arbitrated disputes between members of the development teams. Izchak Miller passed away at the age of 58, in the early morning hours of April 1, 1994 from complications due to cancer. We then dedicated NetHack 3.2 in his memory. [ Mike Stephenson, for the NetHack DevTeam ] jabberwock vorpal* "Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!" He took his vorpal sword in hand; Long time the manxome foe he sought -- So rested he by the Tumtum tree, And stood awhile in thought. And, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back. [ Jabberwocky, by Lewis Carroll ] jacinth* Sweet in the rough weather The voice of the turtle-dove 'Beautiful altogether Is my Love. His Hands are open spread for love And full of jacinth stones As the apple-tree among trees of the grove Is He among the sons.' [ The Beloved, by May Probyn ] jackal In Asiatic folktale, jackal provides for the lion; he scares up game, which the lion kills and eats, and receives what is left as reward. In stories from northern India he is sometimes termed "minister to the king," i.e. to the lion. From the legend that he does not kill his own food has arisen the legend of his cowardice. Jackal's heart must never be eaten, for instance, in the belief of peoples indigenous to the regions where the jackal abounds. ... In Hausa Negro folktale Jackal plays the role of sagacious judge and is called "O Learned One of the Forest." The Bushmen say that Jackal goes around behaving the way he does "because he is Jackal". [ Funk & Wagnalls Standard Dictionary of Folklore ] *jack*boot* A large boot extending over the knee, acting as protective armour for the leg, worn by troopers in the 17th and 18th centuries and later. It is still the type of boot worn by the Household Cavalry and was adopted by fishermen and others before the advent of gum boots. Figuratively, _to be under the jack-boot_ is to be controlled by a brutal military regime. [ Brewer's Concise Dictionary of Phrase and Fable ] jade* Nothing grew among the ruins of the city. The streets were broken and the walls of the houses had fallen, but there were no weeds flowering in the cracks and it seemed that the city had but recently been brought down by an earthquake. Only one thing still stood intact, towering over the ruins. It was a gigantic statue of white, gray and green jade - the statue of a naked youth with a face of almost feminine beauty that turned sightless eyes toward the north. "The eyes!" Duke Avan Astran said. "They're gone!" [ The Jade Man's Eyes, by Michael Moorcock ] jaguar Large, flesh-eating animal of the cat family, of Central and South America. This feline predator (_Panthera onca_) is sometimes incorrectly called a panther. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] jellyfish I do not care to share the seas With jellyfishes such as these; Particularly Portuguese. [ Lines on Meeting a Portuguese Man-o'-war while Bathing, by Michael Flanders ] juiblex jubilex Little is known about the Faceless Lord, even the correct spelling of his name. He does not have a physical form as we know it, and those who have peered into his realm claim he is a slime-like creature who swallows other creatures alive, spits acidic secretions, and causes disease in his victims which can be almost instantly fatal. k?ration The K ration was the [ Quartermaster Subsistence Research and Development Laboratory's ] answer to the demand for an individual, easy-to-carry ration that could be used in assault and combat operations. It was noted for compactness and superior packaging and was acknowledged as the ration that provided the greatest variety of nutritionally balanced components within the smallest space. [ Special Rations for the Armed Forces, 1946-53, by Franz A. Koehler ] kabuto The kabuto is the helmet worn by the samurai. It was characterized by a prominent beaked front which jutted out over the brow to protect the wearer's face; a feature that gives rise to their modern Japanese name of 'shokaku tsuki kabuto' (battering-ram helmet). Their main constructional element was an oval plate, the shokaku bo, slightly domed for the head with a narrow prolongation in front that curved forwards and downwards where it developed a pronounced central fold. Two horizontal strips encircling the head were riveted to this frontal strip: the lower one, the koshimaki (hip wrap), formed the lower edge of the helmet bowl; the other, the do maki (body wrap), was set at about the level of the temples. Filling the gaps between these strips and the shokaku bo were small plates, sometimes triangular but more commonly rectangular in shape. Because the front projected so far from the head, the triangular gap beneath was filled by a small plate, the shoshaku tei ita, whose rear edge bent downwards into a flange that rested against the forehead. [ Arms & Armour of the Samurai, by Bottomley & Hopson ] katana The katana is a long, single-edged samurai sword with a slightly curved blade. Its long handle is designed to allow it to be wielded with either one or two hands. kelp* *frond I noticed that all the plants were attached to the soil by an almost imperceptible bond. Devoid of roots, they seemed not to require any nourishment from sand, soil, or pebble. All they required was a point of support -- nothing else. These plants are self-propagated, and their existence depends entirely on the water that supports and nourishes them. Most of them do not sprout leaves, but sprout blades of various whimsical shapes, and their colors are limited to pink, carmine, green, olive, fawn, and brown. I had the opportunity to observe once more -- not the dried specimens I had studied on the _Nautilus_ -- but the fresh, living specimens in their native setting. [ 20,000 Leagues Under the Sea, by Jules Verne ] ki-rin The ki-rin is a strange-looking flying creature. It has scales, a mane like a lion, a tail, hooves, and a horn. It is brightly colored, and can usually be found flying in the sky looking for good deeds to reward. king arthur *arthur Ector took both his sons to the church before which the anvil had been placed. There, standing before the anvil, he commanded Kay: "Put the sword back into the steel if you really think the throne is yours!" But the sword glanced off the steel. "Now it is your turn", Ector said facing Arthur. The young man lifted the sword and thrust with both arms; the blade whizzed through the air with a flash and drilled the metal as if it were mere butter. Ector and Kay dropped to their knees before Arthur. "Why, father and brother, do you bow before me?", Arthur asked with wonder in his voice. "Because now I know for sure that you are the king, not only by birth but also by law", Ector said. "You are no son of mine nor are you Kay's brother. Immediately after your birth, Merlin the Wise brought you to me to be raised safely. And though it was me that named you Arthur when you were baptized, you are really the son of brave king Uther Pendragon and queen Igraine..." And after these words, the lord rose and went to see the arch- bishop to impart to him what had passed. [ Van Gouden Tijden Zingen de Harpen, by Vladimir Hulpach, Emanuel Frynta, and Vackav Cibula ] knife stiletto Possibly perceiving an expression of dubiosity on their faces, the globetrotter went on adhering to his adventures. -- And I seen a man killed in Trieste by an Italian chap. Knife in his back. Knife like that. Whilst speaking he produced a dangerous looking clasp knife, quite in keeping with his character, and held it in the striking position. -- In a knockingshop it was count of a tryon between two smugglers. Fellow hid behind a door, come up behind him. Like that. Prepare to meet your God, says he. Chuck! It went into his back up to the butt. [ Ulysses, by James Joyce ] knight * knight Here lies the noble fearless knight, Whose valour rose to such a height; When Death at last had struck him down, His was the victory and renown. He reck'd the world of little prize, And was a bugbear in men's eyes; But had the fortune in his age To live a fool and die a sage. [ Don Quixote of La Mancha, by Miquel de Cervantes Saavedra ] ~kobold ??m* *kobold* The race of kobolds are reputed to be an artificial creation of a master wizard (demi-god?). They are about 3' tall with a vaguely dog-like face. They bear a violent dislike of the Elven race, and will go out of their way to cause trouble for Elves at any time. *kop* The Kops are a brilliant concept. To take a gaggle of inept policemen and display them over and over again in a series of riotously funny physical punishments plays equally well to the peanut gallery and the expensive box seats. People hate cops. Even people who have never had anything to do with cops hate them. Of course, we count on them to keep order and to protect us when we need protecting, and we love them on television shows in which they have nerves of steel and hearts of gold, but in the abstract, as a nation, collectively we hate them. They are too much like high school principals. We're very happy to see their pants fall down, and they look good to us with pie on their faces. The Keystone Kops turn up--and they get punished for it, as they crash into each other, fall down, and suffer indignity after indignity. Here is pure movie satisfaction. The Kops are very skillfully presented. The comic originality and timing in one of their chase scenes requires imagination to think up, talent to execute, understanding of the medium, and, of course, raw courage to perform. The Kops are madmen presented as incompetents, and they're madmen rushing around in modern machines. What's more, the machines they were operating in their routines were newly invented and not yet experienced by the average moviegoer. (In the early days of automobiles, it was reported that there were only two cars registered in all of Kansas City, and they ran into each other. There is both poetry and philosophy in this fact, but most of all, there is humor. Sennett got the humor.) [ Silent Stars, by Jeanine Basinger ] kos "I am not a coward!" he cried. "I'll dare Thieves' House and fetch you Krovas' head and toss it with blood a-drip at Vlana's feet. I swear that, witness me, Kos the god of dooms, by the brown bones of Nalgron my father and by his sword Graywand here at my side!" [ Swords and Deviltry, by Fritz Leiber ] koto A Japanese harp. kraken Out from the water a long sinuous tentacle had crawled; it was pale-green and luminous and wet. Its fingered end had hold of Frodo's foot, and was dragging him into the water. Sam on his knees was now slashing at it with a knife. The arm let go of Frodo, and Sam pulled him away, crying out for help. Twenty other arms came rippling out. The dark water boiled, and there was a hideous stench. [ The Fellowship of the Ring, by J.R.R. Tolkien ] *lady offler Blind Io took up the dice-box, which was a skull whose various orifices had been stoppered with rubies, and with several of his eyes on the Lady he rolled three fives. She smiled. This was the nature of the Lady's eyes: they were bright green, lacking iris or pupil, and they glowed from within. The room was silent as she scrabbled in her box of pieces and, from the very bottom, produced a couple that she set down on the board with two decisive clicks. The rest of the players, as one God, craned forward to peer at them. "A wenegade wiffard and fome fort of clerk," said Offler the Crocodile God, hindered as usual by his tusks. "Well, weally!" With one claw he pushed a pile of bone-white tokens into the centre of the table. The Lady nodded slightly. She picked up the dice-cup and held it as steady as a rock, yet all the Gods could hear the three cubes rattling about inside. And then she sent them bouncing across the table. A six. A three. A five. Something was happening to the five, however. Battered by the chance collision of several billion molecules, the die flipped onto a point, spun gently and came down a seven. Blind Io picked up the cube and counted the sides. "Come _on_," he said wearily, "Play fair." [ The Colour of Magic, by Terry Pratchett ] *lamp When he came to himself he told his mother what had passed, and showed her the lamp and the fruits he had gathered in the garden, which were in reality precious stones. He then asked for some food. "Alas! child," she said, "I have nothing in the house, but I have spun a little cotton and will go and sell it." Aladdin bade her keep her cotton, for he would sell the lamp instead. As it was very dirty she began to rub it, that it might fetch a higher price. Instantly a hideous genie appeared, and asked what she would have. She fainted away, but Aladdin, snatching the lamp, said boldly: "Fetch me something to eat!" [ Aladdin, from The Arabian Nights, by Andrew Lang ] lance With this the wind increased, and the mill sails began to turn about; which Don Quixote espying, said, 'Although thou movest more arms than the giant Briareus thou shalt stoop to me.' And, after saying this, and commending himself most devoutly to his Lady Dulcinea, desiring her to succor him in that trance, covering himself well with his buckler, and setting his lance on his rest, he spurred on Rozinante, and encountered with the first mill that was before him, and, striking his lance into the sail, the wind swung it about with such fury, that it broke his lance into shivers, carrying him and his horse after it, and finally tumbled him a good way off from it on the field in evil plight. [ Don Quixote of La Mancha, by Miquel de Cervantes Saavedra ] land mine Your heart is intact, your brain is not badly damaged, but the rest of your injuries are comparable to stepping on a land mine. You'd never walk again, and you'd be in great pain. You would come to wish you had not survived. [ Steel Beach, by John Varley ] *lantern While pretending to be a fancy safety lamp, it is in fact battery powered. A discreet little switch is marked "on/off" in elaborate lettering. [ Adventure 770, by Mike Arnautov ] lava * lava You are on the edge of a breath-taking view. Far below you is an active volcano, from which great gouts of molten lava come surging out, cascading back down into the depths. The glowing rock fills the farthest reaches of the cavern with a blood-red glare, giving everything an eerie, macabre appearance. The air is filled with flickering sparks of ash and a heavy smell of brimstone. The walls are hot to the touch, and the thundering of the volcano drowns out all other sounds. Embedded in the jagged roof far overhead are myriad twisted formations composed of pure white alabaster, which scatter the murky light into sinister apparitions upon the walls. To one side is a deep gorge, filled with a bizarre chaos of tortured rock which seems to have been crafted by the devil himself. An immense river of fire crashes out from the depths of the volcano, burns its way through the gorge, and plummets into a bottomless pit far off to your left. To the right, an immense geyser of blistering steam erupts continuously from a barren island in the center of a sulfurous lake, which bubbles ominously. The far right wall is aflame with an incandescence of its own, which lends an additional infernal splendor to the already hellish scene. A dark, forboding passage exits to the south. [ Adventure, by Will Crowther and Doug Woods. ] leash They had splendid heads, fine shoulders, strong legs, and straight tails. The spots on their bodies were jet-black and mostly the size of a two-shilling piece; they had smaller spots on their heads, legs, and tails. Their noses and eye- rims were black. Missis had a most winning expression. Pongo, though a dog born to command, had a twinkle in his eye. They walked side by side with great dignity, only putting the Dearlys on the leash to lead them over crossings. [ The Hundred and One Dalmatians, by Dodie Smith ] lembas* In the morning, as they were beginning to pack their slender goods, Elves that could speak their tongue came to them and brought them many gifts of food and clothing for their journey. The food was mostly in the form of very thin cakes, made of a meal that was baked a light brown on the outside, and inside was the colour of cream. Gimli took up one of the cakes and looked at it with a doubtful eye. 'Cram,' he said under his breath, as he broke off a crisp corner and nibbled at it. His expression quickly changed, and he ate all the rest of the cake with relish. 'No more, no more!' cried the Elves laughing. 'You have eaten enough already for a long day's march.' 'I thought it was only a kind of cram, such as the Dalemen make for journeys in the wild,' said the Dwarf. 'So it is,' they answered. 'But we call it lembas or waybread, and it is more strengthening than any foods made by Men, and it is more pleasant than cram, by all accounts.' [ The Fellowship of the Ring, by J.R.R. Tolkien ] lemure larvae The Larvae (Lemures) are Roman spirits of deceased family members. These malignant spirits dwell throughout the house and frighten the inhabitants. People tried to reconcile or avert the Larvae with strange ceremonies which took place on May 9, 11, and 13; this was called the "Feast of the Lemures". The master of the house usually performed these ceremonies, either by offering black beans to the spirits or chasing them away by making a lot of noise. Their counterparts are the Lares, friendly and beneficent house spirits. [ Encyclopedia Mythica, ed. M.F. Lindemans ] leocrotta leu*otta ... the leucrocotta, a wild beast of extraordinary swiftness, the size of the wild ass, with the legs of a Stag, the neck, tail, and breast of a lion, the head of a badger, a cloven hoof, the mouth slit up as far as the ears, and one continuous bone instead of teeth; it is said, too, that this animal can imitate the human voice. [ Curious Creatures in Zoology, by John Ashton ] leprechaun The Irish Leprechaun is the Faeries' shoemaker and is known under various names in different parts of Ireland: Cluricaune in Cork, Lurican in Kerry, Lurikeen in Kildare and Lurigadaun in Tipperary. Although he works for the Faeries, the Leprechaun is not of the same species. He is small, has dark skin and wears strange clothes. His nature has something of the manic-depressive about it: first he is quite happy, whistling merrily as he nails a sole on to a shoe; a few minutes later, he is sullen and morose, drunk on his home-made heather ale. The Leprechaun's two great loves are tobacco and whiskey, and he is a first-rate con-man, impossible to out-fox. No one, no matter how clever, has ever managed to cheat him out of his hidden pot of gold or his magic shilling. At the last minute he always thinks of some way to divert his captor's attention and vanishes in the twinkling of an eye. [ A Field Guide to the Little People by Nancy Arrowsmith & George Moorse ] *lich But on its heels ere the sunset faded, there came a second apparition, striding with incredible strides and halting when it loomed almost upon me in the red twilight-the monstrous mummy of some ancient king still crowned with untarnished gold but turning to my gaze a visage that more than time or the worm had wasted. Broken swathings flapped about the skeleton legs, and above the crown that was set with sapphires and orange rubies, a black something swayed and nodded horribly; but, for an instant, I did not dream what it was. Then, in its middle, two oblique and scarlet eyes opened and glowed like hellish coals, and two ophidian fangs glittered in an ape-like mouth. A squat, furless, shapeless head on a neck of disproportionate extent leaned unspeakably down and whispered in the mummy's ear. Then, with one stride, the titanic lich took half the distance between us, and from out the folds of the tattered sere-cloth a gaunt arm arose, and fleshless, taloned fingers laden with glowering gems, reached out and fumbled for my throat . . . [ The Abominations of Yondo, by Clark Ashton Smith ] lichen The chamber was of unhewn rock, round, as near as might be, eighteen or twenty feet across, and gay with rich variety of fern and moss and lichen. The fern was in its winter still, or coiling for the spring-tide; but moss was in abundant life, some feathering, and some gobleted, and some with fringe of red to it. [ Lorna Doone, by R.D. Blackmore ] # takes "light" when specifying 'y' ~* of light * light light Strange creatures formed from energy rather than matter, lights are given to self-destructive behavior when battling foes. gecko iguana lizard Lizards, snakes and the burrowing amphisbaenids make up the order Squamata, meaning the scaly ones. The elongate, slim, long-tailed bodies of lizards have become modified to enable them to live in a wide range of habitats. Lizards can be expert burrowers, runners, swimmers and climbers, and a few can manage crude, short-distance gliding on rib-supported "wings". Most are carnivores, feeding on invertebrate and small vertebrate prey, but others feed on vegetation. [ Macmillan Illustrated Animal Encyclopedia ] loki Loki, or Lopt, is described in Snorri's _Edda_ as being "pleasing and handsome in appearance, evil in character, and very capricious in behaviour". He is the son of the giant Farbauti and of Laufey. Loki is the Norse god of cunning, evil, thieves, and fire. He hated the other gods and wanted to ruin them and overthrow the universe. He committed many murders. As a thief, he stole Freyja's necklace, Thor's belt and gauntlets of power, and the apples of youth. Able to shapechange at will, he is said to have impersonated at various times a mare, flea, fly, falcon, seal, and an old crone. As a mare he gave birth to Odin's horse Sleipnir. He also allegedly sired the serpent Midgard, the mistress of the netherworld, Hel, and the wolf Fenrir, who will devour the sun at Ragnarok. *longbow of diana This legendary bow grants ESP when carried and can reflect magical attacks when wielded. When invoked it provides a supply of arrows. # long worm -- see "worm" looking glass mirror But as Snow White grew, she became more and more beautiful, and by the time she was seven years old she was as beautiful as the day and more beautiful than the queen herself. One day when the queen said to her mirror: "Mirror, Mirror, here I stand. Who is the fairest in the land?" - the mirror replied: "You, O Queen, are the fairest here, But Snow White is a thousand times more fair." [ Snow White, by Jakob and Wilhelm Grimm ] lord carnarvon Lord Carnarvon was a personality who could have been produced nowhere but in England, a mixture of sportsman and collector, gentleman and world traveler, a realist in action and a romantic in feeling. ... In 1903 he went for the first time to Egypt in search of a mild climate and while there visited the excavation sites of several archaeological expeditions. ... In 1906 he began his own excavations. [ Gods, Graves, and Scholars, by C. W. Ceram ] lord sato Lord Sato was the family head of the Taro Clan, and a mighty daimyo. He is a loyal servant of the Emperor, and will do everything in his power to further the imperial cause. lord surt* Yet first was the world in the southern region, which was named Muspell; it is light and hot; that region is glowing and burning, and impassable to such as are outlanders and have not their holdings there. He who sits there at the land's-end, to defend the land, is called Surtr; he brandishes a flaming sword, and at the end of the world he shall go forth and harry, and overcome all the gods, and burn all the world with fire. [ The Prose Edda, by Snorri Sturluson ] # if a quote for good luck gets added, make this one exclusively bad luck luck bad luck "[...] We'll succeed and you'll get all the fortune you came seeking." Jack shook his head dismally. "You'll be better off without me," he said. "I'm nothing but bad luck. It's because I'm cursed. A farmer I met on the way to the city cursed me. He said, 'I curse you Jack. May you never know wealth. May all that you wish for be denied you.'" "What a horrid man," said Eddie. "Why did he curse you like that?" Jack shrugged [...]. "Bad grace, I suppose. Just because I shot off his ear and made him jump into a pit full of spikes." [ the hollow chocolate bunnies of the apocalypse, by Robert Rankin ] # [no relation... both cover and title page list # this book's title in all lower case] lug* Lugh, or Lug, was the sun god of the Irish Celts. One of his weapons was a rod-sling which worshippers sometimes saw in the sky as a rainbow. As a tribal god, he was particularly skilled in the use of his massive, invincible spear, which fought on its own accord. One of his epithets is _lamfhada_ (of the long arm). He was a young and apparently more attractive deity than Dagda, the father of the gods. Being able to shapeshift, his name translates as lynx. lurker* These dungeon scavengers are very adept at blending into the surrounding walls and ceilings of the dungeon due to the stone-like coloring of their skin. lycanthrope were* human were* *were In 1573, the Parliament of Dole published a decree, permitting the inhabitants of the Franche-Comte to pursue and kill a were-wolf or loup-garou, which infested that province, "notwithstanding the existing laws concerning the chase." The people were empowered to "assemble with javelins, halberds, pikes, arquebuses and clubs, to hunt and pursue the said were-wolf in all places where they could find it, and to take, burn, and kill it, without incurring any fine or other penalty." The hunt seems to have been successful, if we may judge from the fact that the same tribunal in the following year condemned to be burned a man named Giles Garnier, who ran on all fours in the forest and fields and devoured little children, "even on Friday." The poor lycanthrope, it appears, had as slight respect for ecclesiastical feasts as the French pig, which was not restrained by any feeling of piety from eating infants on a fast day. [ The History of Vampires, by Dudley Wright ] lynx To dream of seeing a lynx, enemies are undermining your business and disrupting your home affairs. For a woman, this dream indicates that she has a wary woman rivaling her in the affections of her lover. If she kills the lynx, she will overcome her rival. [ 10,000 Dreams Interpreted, by Gustavus Hindman Miller ] ~*sceptre of might mace sceptre Originally a club armed with iron, and used in war; now a staff of office pertaining to certain dignitaries, as the Speaker of the House of Commons, Lord Mayors, Mayors etc. Both sword and mace are symbols of dignity, suited to the times when men went about in armour, and sovereigns needed champions to vindicate their rights. [ Brewer's Concise Dictionary of Phrase and Fable ] magic marker The pen is mightier than the sword. [ Richelieu, by Edward Bulwer-Lytton ] magic mirror of merlin [...] In Dehenbarth (that now South Wales is hight, What time King Ryence reigned, and dealed right) The great magician Merlin had devised, By his deep science, and hell-dreaded might, A looking-glass, right wondrously aguised, Whose virtues through the wide world soon were solemnized. It virtue had to show in perfect sight Whatever thing was in the world contained, Betwixt the lowest earth and heaven's height, So that it to the looker appertained; Whatever foe had wrought, or friend had fained, Therein discovered was, nor aught might pass, Nor aught in secret from the same remained; # we'll leave out the part about it being a crystal ball... # For-thy it round and hollow shaped was, # Like the world itself, and seemed a world of glass. [ The Faerie Queene, by Edmund Spencer ] magicbane A highly enchanted athame said to hold the power to channel and direct magical energy. mail d*emon It is rumoured that these strange creatures can be harmed by domesticated canines only. ma*annan* Normally called Manannan, Ler's son was the patron of merchants and sailors. Manannan had a sword which never failed to slay, a boat which propelled itself wherever its owner wished, a horse which was swifter than the wind, and magic armour which no sword could pierce. He later became god of the sea, beneath which he lived in Tir na nOc, the underworld. manes Manes or Di Manes ("good ones") is the euphemistic description of the souls of the deceased, worshipped as divinities. The formula D.M. (= Dis Manibus; "dedicated to the Manes-gods") can often be found on tombstones. Manes also means metaphorically 'underworld' or 'realm of death'. Festivals in honor of the dead were the Parentalia and the Feralia, celebrated in February. [ Encyclopedia Mythica, ed. M.F. Lindemans ] The gnats of the dungeon, these swarming monsters are rarely seen alone. marduk First insisting on recognition as supreme commander, Marduk defeated the Dragon, cut her body in two, and from it created heaven and earth, peopling the world with human beings who not unnaturally showed intense gratitude for their lives. The gods were also properly grateful, invested him with many titles, and eventually permitted themselves to be embodied in him, so that he became supreme god, plotting the whole course of known life from the paths of the planets to the daily events in the lives of men. [ The Immortals, by Derek and Julia Parker ] marilith The marilith has a torso shaped like that of a human female, and the lower body of a great snake. It has multiple arms, and can freely attack with all of them. Since it is intelligent enough to use weapons, this means it can cause great damage. mars The god of war, and one of the most prominent and worshipped gods. In early Roman history he was a god of spring, growth in nature, and fertility, and the protector of cattle. Mars is also mentioned as a chthonic god (earth-god) and this could explain why he became a god of death and finally a god of war. He is the son of Jupiter and Juno. [ Encyclopedia Mythica, ed. M.F. Lindemans ] master assassin He strolled down the stairs, followed by a number of assassins. When he was directly in front of Ymor he said: "I've come for the tourist." ... "One step more and you'll leave here with fewer eyeballs than you came with," said the thiefmaster. "So sit down and have a drink, Zlorf, and let's talk about this sensibly. _I_ thought we had an agreement. You don't rob -- I don't kill. Not for payment, that is," he added after a pause. Zlorf took the proffered beer. "So?" he said. "I'll kill him. Then you rob him. Is he that funny looking one over there?" "Yes." Zlorf stared at Twoflower, who grinned at him. He shrugged. He seldom wasted time wondering why people wanted other people dead. It was just a living. "Who is your client, may I ask?" said Ymor. Zlorf held up a hand. "Please!" he protested. "Professional etiquette." [ The Colour of Magic, by Terry Pratchett ] master key of thievery This skeleton key was fashioned in ages past and imbued with a powerful magic which allows it to open any lock. When carried, it grants its owner warning, teleport control, and reduces all physical damage by half. Finally, when invoked, it has the ability to disarm any trap. master of thieves There was a flutter of wings at the window. Ymor shifted his bulk out of the chair and crossed the room, coming back with a large raven. After he'd unfastened the message capsule from its leg it flew up to join its fellows lurking among the rafters. Withel regarded it without love. Ymor's ravens were notoriously loyal to their master, to the extent that Withel's one attempt to promote himself to the rank of greatest thief in Ankh-Morpork had cost their master's right hand man his left eye. But not his life, however. Ymor never grudged a man his ambitions. [ The Colour of Magic, by Terry Pratchett ] mastodon Any large, elephantlike mammal of the genera Mammut, Mastodon, etc., from the Oligocene and Pleistocene epochs, having conical projections on the molar teeth. [ Webster's Encyclopedic Unabridged Dictionary of the English Language ] *mattock A mattock is an agricultural tool similar to a mining pick. It is distinguished by the head terminating in a broader blade rather than a narrow spike, which makes it particularly suitable for breaking up moderately hard ground. ... During the Middle Ages of Europe, the mattock served as an improvised shafted weapon for the poorer classes. [ Wikipedia, the free encyclopedia ] meat* huge chunk of meat Some hae meat and canna eat, And some would eat that want it; But we hae meat, and we can eat, Sae let the Lord be thankit. [ Grace Before Meat, by Robert Burns ] medusa perseus Medusa, one of the three Gorgons or Graeae, is the only one of her sisters to have assumed mortal form and inhabited the dungeon world. When Perseus was grown up Polydectes sent him to attempt the conquest of Medusa, a terrible monster who had laid waste the country. She was once a beautiful maiden whose hair was her chief glory, but as she dared to vie in beauty with Minerva, the goddess deprived her of her charms and changed her beautiful ringlets into hissing serpents. She became a cruel monster of so frightful an aspect that no living thing could behold her without being turned into stone. All around the cavern where she dwelt might be seen the stony figures of men and animals which had chanced to catch a glimpse of her and had been petrified with the sight. Perseus, favoured by Minerva and Mercury, the former of whom lent him her shield and the latter his winged shoes, approached Medusa while she slept and taking care not to look directly at her, but guided by her image reflected in the bright shield which he bore, he cut off her head and gave it to Minerva, who fixed it in the middle of her Aegis. [ Bulfinch's Mythology, by Thomas Bulfinch ] melon "What is it, Umbopa, son of a fool?" I shouted in Zulu. "It is food and water, Macumazahn," and again he waved the green thing. Then I saw what he had got. It was a melon. We had hit upon a patch of wild melons, thousands of them, and dead ripe. "Melons!" I yelled to Good, who was next me; and in another second he had his false teeth fixed in one. I think we ate about six each before we had done, and, poor fruit as they were, I doubt if I ever thought anything nicer. [ King Solomon's Mines, by H. Rider Haggard ] mercury Roman god of commerce, trade and travellers. He is commonly depicted carrying a caduceus (a staff with two snakes intertwining around it) and a purse. *mimic The ancestors of the modern day chameleon, these creatures can assume the form of anything in their surroundings. They may assume the shape of objects or dungeon features. Unlike the chameleon though, which assumes the shape of another creature and goes in hunt of food, the mimic waits patiently for its meals to come in search of it. *mind flayer This creature has a humanoid body, tentacles around its covered mouth, and three long fingers on each hand. Mind flayers are telepathic, and love to devour intelligent beings, especially humans. If they hit their victim with a tentacle, the mind flayer will slowly drain it of all intelligence, eventually killing its victim. mine* gnomish mines Made by Dwarfs. The Rule here is that the Mine is either long deserted or at most is inhabited by a few survivors who will make confused claims to have been driven out/decimated by humans/ other Dwarfs/Minions of the Dark Lord. Inhabited or not, this Mine will be very complex, with many levels of galleries, beautifully carved and engineered. What was being mined here is not always evident, but at least some of the time it will appear to have been Jewels, since it is customary to find unwanted emeralds, etc., still embedded in the rock of the walls. Metal will also be present, but only when made up into armor and weapons (_wondrous_). [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] minotaur The Minotaur was a monster, half bull, half human, the offspring of Minos' wife Pasiphae and a wonderfully beautiful bull. ... When the Minotaur was born Minos did not kill him. He had Daedalus, a great architect and inventor, construct a place of confinement for him from which escape was impossible. Daedalus built the Labyrinth, famous throughout the world. Once inside, one would go endlessly along its twisting paths without ever finding the exit. [ Mythology, by Edith Hamilton ] mit*ra* Originating in India (Mitra), Mithra is a god of light who was translated into the attendant of the god Ahura Mazda in the light religion of Persia; from this he was adopted as the Roman deity Mithras. He is not generally regarded as a sky god but a personification of the fertilizing power of warm, light air. According to the _Avesta_, he possesses 10,000 eyes and ears and rides in a chariot drawn by white horses. Mithra, according to Zarathustra, is concerned with the endless battle between light and dark forces: he represents truth. He is responsible for the keeping of oaths and contracts. He is attributed with the creation of both plants and animals. His chief adversary is Ahriman, the power of darkness. [ The Encyclopaedia of Myths and Legends of All Nations, by Herbert Spencer Robinson and Knox Wilson ] *mithril* _Mithril_! All folk desired it. It could be beaten like copper, and polished like glass; and the Dwarves could make of it a metal, light and yet harder than tempered steel. Its beauty was like to that of common silver, but the beauty of _mithril_ did not tarnish or grow dim. [ The Fellowship of the Ring, by J.R.R. Tolkien ] *mitre of holiness This helm of brilliance performs all of the normal functions of a helm of brilliance, but also has the ability to protect anyone who carries it from fire. When invoked, it boosts the energy of the invoker, allowing them to cast more spells. mjollnir Forged by the dwarves Eitri and Brokk, in response to Loki's challenge, Mjollnir is an indestructible war hammer. It has two magical properties: when thrown it always returned to Thor's hand; and it could be made to shrink in size until it could fit inside Thor's shirt. Its only flaw is that it has a short handle. The other gods judged Mjollnir the winner of the contest because, of all the treasures created, it alone had the power to protect them from the giants. As the legends surrounding Mjollnir grew, it began to take on the quality of "vigja", or consecration. Thor used it to consecrate births, weddings, and even to raise his goats from the dead. In the Norse mythologies Mjollnir is considered to represent Thor's governance over the entire cycle of life - fertility, birth, destruction, and resurrection. mog Mog is known as the Spider God. Mog resembles a four-limbed spider with a handsome, if not entirely human, face. ~slime mold *mold Mold, multicellular organism of the division Fungi, typified by plant bodies composed of a network of cottony filaments. The colors of molds are due to spores borne on the filaments. Most molds are saprophytes. Some species (e.g., penicillium) are used in making cheese and antibiotics. [ The Concise Columbia Encyclopedia ] mol?ch And the Lord spake unto Moses, saying, Again, thou shalt say to the children of Israel, Whosoever he be of the children of Israel, or of the strangers that sojourn in Israel, that giveth any of his seed unto Molech; he shall surely be put to death: the people of the land shall stone him with stones. And I will set my face against that man, and will cut him off from among his people; because he hath given of his seed unto Molech, to defile my sanctuary, and to profane my holy name. And if the people of the land do any ways hide their eyes from the man, when he giveth of his seed unto Molech, and kill him not: Then I will set my face against that man, and against his family, and will cut him off, and all that go a whoring after him, to commit whoredom with Molech, from among their people. [ Leviticus 20:1-5 ] monk * monk grand master master kaen One day, an army general invited the Buddhist monk I-Hsiu (literally, "One Rest") to his military head office for a dinner. I-Hsiu was not accustomed to wearing luxurious clothings and so he just put on an old ordinary casual robe to go to the military base. To him, "form is void". As he approached the base, two soldiers appeared before him and shouted, "Where does this beggar came from? Identify yourself! You do not have permission to be around here!" "My name is I-Hsiu Dharma Master. I am invited by your general for a supper." The two soldiers examined the monk closely and said, "You liar. How come my general invites such a shabby monk to dinner? He invites the very solemn venerable I-Hsiu to our base for a great ceremony today, not you. Now, get out!" I-Hsiu was unable to convince the soldiers that he was indeed the invited guest, so he returned to the temple and changed to a very formal solemn ceremonial robe for the dinner. And as he returned to the military base, the soldiers observed that he was such a great Buddhist monk, let him in with honour. At the dinner, I-Hsiu sat in front of the table full of food but, instead of putting the food into his mouth, he picked up the food with his chopsticks and put it into his sleeves. The general was curious, and whispered to him, "This is very embarrassing. Do you want to take some food back to the temple? I will order the cook to prepare some take out orders for you." "No" replied the monk. "When I came here, I was not allowed into the base by your soldiers until I wear this ceremonial robe. You do not invite me for a dinner. You invite my robe. Therefore, my robe is eating the food, not me." [ Dining with a General - a Zen Buddhism Koan, translation by Yiu-man Chan ] monkey "Listen, man-cub," said the Bear, and his voice rumbled like thunder on a hot night. "I have taught thee all the Law of the Jungle for all the peoples of the jungle--except the Monkey-Folk who live in the trees. They have no law. They are outcasts. They have no speech of their own, but use the stolen words which they overhear when they listen, and peep, and wait up above in the branches. Their way is not our way. They are without leaders. They have no remembrance. They boast and chatter and pretend that they are a great people about to do great affairs in the jungle, but the falling of a nut turns their minds to laughter and all is forgotten. We of the jungle have no dealings with them. We do not drink where the monkeys drink; we do not go where the monkeys go; we do not hunt where they hunt; we do not die where they die...." [ The Jungle Book, by Rudyard Kipling ] morning star The morning star was a medieval weapon resembling a mace, but with a large spike on the end and smaller spikes around the circumference. It was also known as the goedendag (from the Dutch word for "good day") and the holy water sprinkler (from its resemblance to the aspergillum sometimes used in the Catholic Mass). It was used by both cavalry and infantry; the horseman's weapon typically had a shorter haft than the footman's, which might be up to six feet long. It came into use in the beginning of the 14th century. The name "morning star" is often erroneously applied to the military flail (also known as the therscol), a similar weapon, but with the head attached by a short chain. [ Dictionary of Medieval Knighthood and Chivalry, by Bradford Broughton ] mumak* ... the Mumak of Harad was indeed a beast of vast bulk, and the like of him does not walk now in Middle-Earth; his kin that live still in latter days are but memories of his girth and majesty. On he came, ... his great legs like trees, enormous sail-like ears spread out, long snout upraised like a huge serpent about to strike, his small red eyes raging. His upturned hornlike tusks ... dripped with blood. [ The Two Towers, by J.R.R. Tolkien ] *mummy But for an account of the manner in which the body was bandaged, and a list of the unguents and other materials employed in the process, and the words of power which were spoken as each bandage was laid in its place, we must have recourse to a very interesting papyrus which has been edited and translated by M. Maspero under the title of Le Rituel de l'Embaumement. ... Everything that could be done to preserve the body was now done, and every member of it was, by means of the words of power which changed perishable substances into imperishable, protected to all eternity; when the final covering of purple or white linen had been fastened upon it, the body was ready for the tomb. [ Egyptian Magic, by E.A. Wallis Budge ] mummy wrapping He held a white cloth -- it was a serviette he had brought with him -- over the lower part of his face, so that his mouth and jaws were completely hidden, and that was the reason for his muffled voice. But it was not that which startled Mrs. Hall. It was the fact that all his forehead above his blue glasses was covered by a white bandage, and that another covered his ears, leaving not a scrap of his face exposed excepting only his pink, peaked nose. It was bright, pink, and shiny just as it had been at first. He wore a dark-brown velvet jacket with a high, black, linen- lined collar turned up about his neck. The thick black hair, escaping as it could below and between the cross bandages, project in curious tails and horns, giving him the strangest appearance conceivable. [ The Invisible Man, by H.G. Wells ] *naga* *naja* The naga is a mystical creature with the body of a snake and the head of a man or woman. They will fiercely protect the territory they consider their own. Some nagas can be forced to serve as guardians by a spellcaster of great power. naginata A Japanese pole-arm, fitted with a curved single-edged blade. The blades ranged in length from two to four feet, mounted on shafts about four to five feet long. The naginata were cut with a series of short grooves near to the tang, above which the back edge was thinned, but not sharpened, so that the greater part of the blade was a flattened diamond shape in section. Seen in profile, the curve is slight or non- existent near the tang, becoming more pronounced towards the point. [] "With his naginata he killed five, but with the sixth it snapped asunder in the midst and, flinging it away, he drew his sword, wielding it in the zigzag style, the interlacing, cross, reversed dragonfly, waterwheel, and eight-sides-at- once styles of fencing and cutting down eight men; but as he brought down the ninth with a mighty blow on the helmet, the blade snapped at the hilt." [ Story of Tsutsui no Jomio Meishu from Tales of Heike ] nalfeshnee Not only do these demons do physical damage with their claws and bite, but they are capable of using magic as well. nalzok Nalzok is Moloch's cunning and unfailingly loyal battle lieutenant, to whom he trusts the command of warfare when he does not wish to exercise it himself. Nalzok is a major demon, known to command the undead. He is hungry for power, and secretly covets Moloch's position. Moloch doesn't trust him, but, trusting his own power enough, chooses to allow Nalzok his position because he is useful. neanderthal* 1. Valley between Duesseldorf and Elberfeld in Germany, where an ancient skull of a prehistoric ancestor to modern man was found. 2. Human(oid) of the race mentioned above. neferet neferet the green Neferet the Green holds office in her hidden tower, only reachable by magical means, where she teaches her apprentices the enigmatic skills of occultism. Despite her many years, she continues to investigate new spells, especially those involving translocation. It is further rumored that when she was an apprentice herself, she accidentally turned her skin green, and has kept it that way ever since. newt (kinds of) small animal, like a lizard, which spends most of its time in the water. [ Oxford's Student's Dictionary of Current English ] "Fillet of a fenny snake, In the cauldron boil and bake; Eye of newt and toe of frog, Wool of bat and tongue of dog, Adder's fork and blind-worm's sting, Lizard's leg and howlet's wing, For a charm of powerful trouble, Like a hell-broth boil and bubble." [ Macbeth, by William Shakespeare ] ninja-to A Japanese broadsword. *norn The Norns were the three Norse Fates, or the goddesses of fate. Female giants, they brought the wonderful Golden Age to an end. They cast lots over the cradle of every child that was born, and placed gifts in the cradle. Their names were Urda, Verdandi, and Skuld, representing the past, the present, and the future. Urda and Verdandi were kindly disposed, but Skuld was cruel and savage. Their tasks were to sew the web of fate, to water the sacred ash, Yggdrasil, and to keep it in good condition by placing fresh earth around it daily. In her fury, Skuld often spoiled the work of her sisters by tearing the web to shreds. [ The Encyclopedia of Myths and Legends of All Nations by Herbert Spencer Robinson and Knox Wilson ] nunchaku A nunchaku is two sections of wood (or metal in modern incarnations) connected by a cord or chain. There is much controversy over its origins; some say it was originally a Chinese weapon, others say it evolved from a threshing flail; one theory purports that it was developed from a horse's bit. Chinese nunchaku tend to be rounded, whereas Japanese are octagonal, and they were originally linked by horse hair. There are many variations on the nunchaku, ranging from the three sectional staff (san-setsu-kon nunchaku), to smaller multi-section nunchaku. The nunchaku was popularized by Bruce Lee in a number of films, made in both Hollywood and Hong Kong. [ Wikipedia, the free encyclopedia ] *nymph naiad A female creature from Roman and Greek mythology, the nymph occupied rivers, forests, ponds, etc. A nymph's beauty is beyond words: an ever-young woman with sleek figure and long, thick hair, radiant skin and perfect teeth, full lips and gentle eyes. A nymph's scent is delightful, and her long robe glows, hemmed with golden threads and embroidered with rainbow hues of unearthly magnificence. A nymph's demeanour is graceful and charming, her mind quick and witty. [] Theseus felt her voice pulling him down into fathoms of sleep. The song was the skeleton of his dream, and the dream was full of terror. Demon girls were after him, and a bull- man was goring him. Everywhere there was blood. There was pain. There was fear. But his head was in the nymph's lap and her musk was about him, her voice weaving the dream. He knew then that she had been sent to tell him of something dreadful that was to happen to him later. Her song was a warning. But she had brought him a new kind of joy, one that made him see everything differently. The boy, who was to become a hero, suddenly knew then what most heroes learn later -- and some too late -- that joy blots suffering and that the road to nymphs is beset by monsters. [ The Minotaur, by Bernard Evslin ] obsidian* A volcanic glass, homogeneous in texture and having a low water content, with a vitreous luster and a conchoidal fracture. The color is commonly black, but may be some shade of red or brown, and cut sections sometimes appear to be green. Like other volcanic glasses, obsidian is a lava that has cooled too quickly for the contained minerals to crystallize. In chemical composition it is rich in silica and similar to granite. It is favored by primitive peoples for knives, arrowheads, spearheads, and other weapons and tools. [ The Columbia Encyclopedia, Sixth Edition ] odin Also called Sigtyr (god of Victory), Val-father (father of the slain), One-Eyed, Hanga-god (god of the hanged), Farma- god (god of cargoes), Hapta-god (god of prisoners), and Othin. He is the prime god of the Norsemen: god of war and victory, wisdom and prophecy, poetry, the dead, air and wind, hospitality, and magic. As the god of war and victory, Odin is ruler of the Valkyries, warrior-maidens who lived in the halls of Valhalla in Asgard, the hall of dead heroes where he held his court. These chosen ones will defend the realm of the gods against the Frost Giants on the final day of reckoning, Ragnarok. As god of the wind, Odin rides through the air on his eight- footed horse, Sleipnir, wielding Gungner, his spear, normally accompanied by his ravens, Hugin and Munin, who he would also use as his spies. As a god of hospitality, he enjoys visiting the earth in disguise to see how people were behaving and to see how they would treat him, not knowing who he was. Odin is usually represented as a one-eyed wise old man with a long white beard and a wide-brimmed hat (he gave one of his eyes to Mimir, the guardian of the well of wisdom in Hel, in exchange for a draught of knowledge). ogre* Anyone who has met a gluttonous, nude, angry ogre, will not easily forget this encounter -- if he survives it at all. Both male and female ogres can easily grow as tall as three metres. Build and facial expressions would remind one of a Neanderthal. Its small, pointy, keen teeth are striking. Since ogres avoid direct sunlight, their ragged, unfurry skin is as white as a sheet. They enjoy coating their body with lard and usually wear nothing but a loin-cloth. An elf would smell its rancid stench at ten metres distance. Ogres are solitary creatures: very rarely one may encounter a female with two or three young. They are the only real carnivores among the humanoids, and its favourite meal is -- not surprisingly -- human flesh. They sometimes ally with orcs or goblins, but only when they anticipate a good meaty meal. [ het Boek van de Regels; Het Oog des Meesters ] oilskin cloak During our watches below we overhauled our clothes, and made and mended everything for bad weather. Each of us had made for himself a suit of oil-cloth or tarpaulin, and these we got out, and gave thorough coatings of oil or tar, and hung upon the stays to dry. Our stout boots, too, we covered over with a thick mixture of melted grease and tar. Thus we took advantage of the warm sun and fine weather of the Pacific to prepare for its other face. [ Two Years Before the Mast, by Richard Henry Dana ] oilskin sack Summer passed all too quickly. On the last day of camp, Mr. Brickle called his counselors together and paid them what he owed them. Louis received one hundred dollars - the first money he had ever earned. He had no wallet and no pockets, so Mr. Brickle placed the money in a waterproof bag that had a drawstring. He hung this moneybag around Louis' neck, along with the trumpet, the slate, the chalk pencil, and the lifesaving medal. [ The Trumpet of the Swan, by E.B. White ] olog-hai But at the end of the Third Age a troll-race not before seen appeared in southern Mirkwood and in the mountain borders of Mordor. Olog-hai they were called in the Black Speech. That Sauron bred them none doubted, though from what stock was not known. Some held that they were not Trolls but giant Orcs; but the Olog-hai were in fashion of body and mind quite unlike even the largest of Orc-kind, whom they far surpassed in size and power. Trolls they were, but filled with the evil will of their master: a fell race, strong, agile, fierce and cunning, but harder than stone. Unlike the older race of the Twilight they could endure the Sun.... They spoke little, and the only tongue they knew was the Black Speech of Barad-dur. [ The Return of the King, by J.R.R. Tolkien ] oracle delphi p*thia Delphi under towering Parnassus, where Apollo's oracle was, plays an important part in mythology. Castalia was its sacred spring; Cephissus its river. It was held to be the center of the world, so many pilgrims came to it, from foreign countries as well as Greece. No other shrine rivaled it. The answers to the questions asked by the anxious seekers for Truth were delivered by a priestess who went into a trance before she spoke. [ Mythology, by Edith Hamilton ] orange pear What was the fruit like? Unfortunately, no one can describe a taste. All I can say is that, compared with those fruits, the freshest grapefruit you've ever eaten was dull, and the juiciest orange was dry, and the most melting pear was hard and woody, and the sweetest wild strawberry was sour. And there were no seeds or stones, and no wasps. If you had once eaten that fruit, all the nicest things in this world would taste like medicines after it. But I can't describe it. You can't find out what it is like unless you can get to that country and taste it for yourself. [ The Last Battle, by C.S. Lewis ] *orb of detection This Orb is a crystal ball of exceptional powers. When carried, it grants ESP, limits damage done by spells, and protects the carrier from magic missiles. When invoked it allows the carrier to become invisible. *orb of fate Some say that Odin himself created this ancient crystal ball, although others argue that Loki created it and forged Odin's signature on the bottom. In any case, it is a powerful artifact. Anyone who carries it is granted the gift of warning, and damage, both spell and physical, is partially absorbed by the orb itself. When invoked it has the power to teleport the invoker between levels. goblin king orcrist The Great Goblin gave a truly awful howl of rage when he looked at it, and all his soldiers gnashed their teeth, clashed their shields, and stamped. They knew the sword at once. It had killed hundreds of goblins in its time, when the fair elves of Gondolin hunted them in the hills or did battle before their walls. They had called it Orcrist, Goblin-cleaver, but the goblins called it simply Biter. They hated it and hated worse any one that carried it. [ The Hobbit, by J.R.R. Tolkien ] orcus Orcus, Prince of the Undead, has a ram's head and a poison stinger. He is most feared, though, for his powerful magic abilities. His wand causes death to those he chooses. ~orc ??m* ~orcish barbarian ~orcish ranger ~orcish rogue ~orcish wizard orc* * orc uruk*hai Orcs, bipeds with a humanoid appearance, are related to the goblins, but much bigger and more dangerous. The average orc is only moderately intelligent, has broad, muscled shoulders, a short neck, a sloping forehead and a thick, dark fur. Their lower eye-teeth are pointing forward, like a boar's. Female orcs are more lightly built and bare-chested. Not needing any clothing, they do like to dress in variegated apparels. Suspicious by nature, orcs live in tribes or hordes. They tend to live underground as well as above ground (but they dislike sunlight). Orcs can use all weapons, tools and armours that are used by men. Since they don't have the talent to fashion these themselves, they are constantly hunting for them. There is nothing a horde of orcs cannot use. [ het Boek van de Regels; Het Oog des Meesters ] orion sirius Orion was the son of Neptune. He was a handsome giant and a mighty hunter. His father gave him the power of wading through the depths of the sea, or, as others say, of walking on its surface. He dwelt as a hunter with Diana (Artemis), with whom he was a favourite, and it is even said she was about to marry him. Her brother was highly displeased and often chid her, but to no purpose. One day, observing Orion wading through the sea with his head just above the water, Apollo pointed it out to his sister and maintained that she could not hit that black thing on the sea. The archer-goddess discharged a shaft with fatal aim. The waves rolled the dead body of Orion to the land, and bewailing her fatal error with many tears, Diana placed him among the stars, where he appears as a giant, with a girdle, sword, lion's skin, and club. Sirius, his dog, follows him, and the Pleiads fly before him. [ Bulfinch's Mythology, by Thomas Bulfinch ] osaku The osaku is a small tool for picking locks. owlbear Owlbears are probably the crossbreed creation of a demented wizard; given the lethal nature of this creation, it is quite likely the wizard who created them is no longer alive. As the name might already suggest, owlbears are a cross between a giant owl and a bear. They are covered with fur and feathers. page A male servant or attendant; specifically, in chivalry, a lad or young man in training for knighthood, or a youth of gentle parentage attending a royal or princely personage. [ Webster's Comprehensive International Dictionary of the English Language ] *pall _Pallium._ The Roman name for a square woollen cloak worn by men in ancient Greece, especially by philosophers and courtesans, corresponding to the Roman toga. Hence the Greeks called themselves _gens palliata,_ and the Romans called themselves _gens togata._ [ Brewer's Concise Dictionary of Phrase and Fable ] panther And lo! almost where the ascent began, A panther light and swift exceedingly, Which with a spotted skin was covered o'er! And never moved she from before my face, Nay, rather did impede so much my way, That many times I to return had turned. [ Dante's Inferno, as translated by Henry Wadsworth Longfellow ] *paper Some players, who unconsciously perceive Paper as weak or a sign of surrender, will shy away from using it entirely or drop it from their game when they are falling behind. On the other hand, Paper also connects with a player's perceptions about writing. There is a quiet power in the printed word. It has the ability to lay off thousands of employees, declare war against nations, spread scandal or confess love. Paper, in short, has power over masses. The fate of the entire world is determined by print. As such, some players perceive Paper as a subtle attack, the victory of modern culture over barbarism. Such players may use Paper to assert their superiority and dignity. [ The Official Rock Paper Scissors Strategy Guide, by Douglas and Graham Walker ] pelias Conan cried out sharply and recoiled, thrusting his companion back. Before them rose the great shimmering white form of Satha, an ageless hate in its eyes. Conan tensed himself for one mad berserker onslaught -- to thrust the glowing faggot into that fiendish countenance and throw his life into the ripping sword- stroke. But the snake was not looking at him. It was glaring over his shoulder at the man called Pelias, who stood with his arms folded, smiling. And in the great, cold, yellow eyes slowly the hate died out in a glitter of pure fear -- the only time Conan ever saw such an expression in a reptile's eyes. With a swirling rush like the sweep of a strong wind, the great snake was gone. "What did he see to frighten him?" asked Conan, eyeing his companion uneasily. "The scaled people see what escapes the mortal eye," answered Pelias cryptically. "You see my fleshy guise, he saw my naked soul." [ Conan the Usurper, by Robert E. Howard and L. Sprague de Camp ] pick*ax* broad pick The mine is full of holes; With the wound of pickaxes. But look at the goldsmith's store. There, there is gold everywhere. [ Divan-i Kebir Meter 2, by Mevlana Celaleddin Rumi ] *piercer Ye Piercer doth look like unto a stalactyte, and hangeth from the roofs of caves and caverns. Unto the height of a man, and thicker than a man's thigh do they grow, and in groups do they hang. If a creature doth pass beneath them, they will by its heat and noise perceive it, and fall upon it to kill and devour it, though in any other way they move but exceeding slow. [ the Bestiary of Xygag ] piranha They live in "schools." Many times they will wait for prey to come to the shallow water of the river. Then the large group of piranhas will attack. These large groups are able to kill large animals... Their lower teeth fit perfectly into the spaces of their upper teeth, creating a tremendous vice-like bite... Piranhas are attracted to any disturbance in the water. [ http://www.animalsoftherainforest.com ] pit spiked pit Amid the thought of the fiery destruction that impended, the idea of the coolness of the well came over my soul like balm. I rushed to its deadly brink. I threw my straining vision below. The glare from the enkindled roof illumined its inmost recesses. Yet, for a wild moment, did my spirit refuse to comprehend the meaning of what I saw. At length it forced -- it wrestled its way into my soul -- it burned itself in upon my shuddering reason. Oh! for a voice to speak! -- oh! horror! -- oh! any horror but this! [ The Pit and the Pendulum, by Edgar Allan Poe ] pit fiend Pit fiends are among the more powerful of devils, capable of attacking twice with weapons as well as grabbing and crushing the life out of those unwary enough to enter their domains. platinum yendorian express card This is an ancient artifact made of an unknown material. It is rectangular in shape, very thin, and inscribed with unreadable ancient runes. When carried, it grants the one who carries it ESP, and reduces all spell induced damage done to the carrier by half. It also protects from magic missile attacks. Finally, its power is such that when invoked, it can charge other objects. # playing style, rather vague topic but these quotes are too apt to pass up player play* style user Be bold, be bold, but not too bold. Or else your life's blood, shall run cold. [ The White Road, by Neil Gaiman ] People think I'm crazy to worry all the time; If you paid attention, you'd be worried too. You better pay attention, or this world we love so much Might just kill you. [ It's a Jungle Out There, by Randy Newman ] # [ theme song from "Monk" ] pony Hey! now! Come hoy now! Whither do you wander? Up, down, near or far, here, there or yonder? Sharp-ears, Wise-nose, Swish-tail and Bumpkin, White-socks my little lad, and old Fatty Lumpkin! [...] Tom called them one by one and they climbed over the brow and stood in a line. Then Tom bowed to the hobbits. "Here are your ponies, now!" he said. "They've more sense (in some ways) than you wandering hobbits have -- more sense in their noses. For they sniff danger ahead which you walk right into; and if they run to save themselves, then they run the right way." [ The Fellowship of the Ring, by J.R.R. Tolkien ] *portal Portals can be Mirrors, Pictures, Standing Stones, Stone Circles, Windows, and special gates set up for the purpose. You will travel through them both to distant parts of the continent and to and from our own world. The precise manner of their working is a Management secret. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] poseido*n Poseido(o)n, lord of the seas and father of rivers and fountains, was the son of Chronos and Rhea, brother of Zeus, Hades, Hera, Hestia and Demeter. His rank of ruler of the waves he received by lot at the Council Meeting of the Gods, at which Zeus took the upper world for himself and gave dominion over the lower world to Hades. Poseidon is associated in many ways with horses and thus is the god of horses. He taught men how to ride and manage the animal he invented and is looked upon as the originator and guardian deity of horse races. His symbol is the familiar trident or three-pronged spear with which he can split rocks, cause or quell storms, and shake the earth, a power which makes him the god of earthquakes as well. Physically, he is shown as a strong and powerful ruler, every inch a king. [ The Encyclopedia of Myths and Legends of All Nations, by Herbert Robinson and Knox Wilson ] ~*sleeping ~*booze *potion* POTABLE, n. Suitable for drinking. Water is said to be potable; indeed, some declare it our natural beverage, although even they find it palatable only when suffering from the recurrent disorder known as thirst, for which it is a medicine. Upon nothing has so great and diligent ingenuity been brought to bear in all ages and in all countries, except the most uncivilized, as upon the invention of substitutes for water. To hold that this general aversion to that liquid has no basis in the preservative instinct of the race is to be unscientific -- and without science we are as the snakes and toads. [ The Devil's Dictionary, by Ambrose Bierce ] Jack Burton: What's in the flask, Egg? Magic potion? Egg Shen: Yeah. Jack: I thought so, good. What do we do? Drink it? Egg: Yeah. Jack: Good, I thought so. [later] Jack: This does what again, exactly? Egg: Huge buzz! [drinks] Oh good! See things no one else can see, do things no one else can do. [ Big Trouble in Little China, directed by John Carpenter, written by Gary Goldman & David Z. Weinstein, adaptation by W. D. Richter ] pray* Whatever a man prays for, he prays for a miracle. Every prayer reduces itself to this: Great God, grant that twice two be not four. [ Fathers and Sons, by Ivan Turgenev ] priest* * priest* acolyte [...] For the two priests were talking exactly like priests, piously, with learning and leisure, about the most aerial enigmas of theology. The little Essex priest spoke the more simply, with his round face turned to the strengthening stars; the other talked with his head bowed, as if he were not even worthy to look at them. But no more innocently clerical conversation could have been heard in any white Italian cloister or black Spanish cathedral. The first he heard was the tail of one of Father Brown's sentences, which ended: "... what they really meant in the Middle Ages by the heavens being incorruptible." The taller priest nodded his bowed head and said: "Ah, yes, these modern infidels appeal to their reason; but who can look at those millions of worlds and not feel that there may well be wonderful universes above us where reason is utterly unreasonable?" [ The Innocence of Father Brown, by G.K. Chesterton ] prisoner Where am I? In the Village. What do you want? Information. Whose side are you on? That would be telling. We want information ... information ... You won't get it. By hook or by crook, we will. Who are you? The new Number 2. Who is Number 1? You are Number 6. I am not a number! I am a free man! [ The Prisoner, by Patrick McGoohan ] ptah Known under various names (Nu, Neph, Cenubis, Amen-Kneph, Khery-Bakef), Ptah is the creator god and god of craftsmen. He is usually depicted as wearing a closely fitting robe with only his hands free. His most distinctive features are the invariable skull-cap exposing only his face and ears, and the _was_ or rod of domination which he holds, consisting of a staff surmounted by the _ankh_ symbol of life. He is otherwise symbolized by his sacred animal, the bull. *purple worm A gargantuan version of the harmless rain-worm, the purple worm poses a huge threat to the ordinary adventurer. It is known to swallow whole and digest its victims within only a few minutes. These worms are always on guard, sensitive to the most minute vibrations in the earth, but may also be awakened by a remote shriek. pyrolisk At first glance around the corner, I thought it was another cockatrice. I had encountered the wretched creatures two or three times since leaving the open area. I quickly ducked my head back and considered what to do next. My heart had begun to thump audibly as I patted my pack to make sure I still had the dead lizards at close reach. A check of my attire showed no obvious holes or damage. I had to keep moving. One deep breath, and a count of three, two, one, and around the corner I bolted. But it was no cockatrice! I felt a sudden intense searing of the skin around my face, and flames began to leap from my pack. I tossed it to the ground, and quickly retreated back, around that corner, desperately striving to get out of its sight. python A monstrous serpent in Greek mythology, and the child of Gaia, the goddess earth. It was produced from the slime and mud that was left on the earth by the great flood of Deucalion. It lived in a cave and guarded the oracle of Delphi on mount Parnassus. No man dared to approach the beast and the people asked Apollo for help. He came down from Mount Olympus with his silver bow and golden arrows. With using only one arrow he killed the serpent and claimed the oracle for himself. ... The old name of Delphi, Pytho, refers to the serpent. [ Encyclopedia Mythica, ed. M.F. Lindemans ] quadruped The woodlands and other regions are inhabited by multitudes of four-legged creatures which cannot be simply classified. They might not have fiery breath or deadly stings, but adventurers have nevertheless met their end numerous times due to the claws, hooves, or bites of such animals. quantum mechanic These creatures are not native to this universe; they seem to have strangely derived powers, and unknown motives. [] _Uncertainty Principle_ The principle that it is not possible to know with unlimited accuracy both the position and momentum of a particle. ... An explanation of the uncertainty is that in order to locate a particle exactly, an observer must be able to bounce off it a photon of radiation; this act of location itself alters the position of the particle in an unpredictable way. To locate the position accurately, photons of short wavelength would have to be used. The high momentum of such photons would cause a large effect on the position. On the other hand, using photons of lower momenta would have less effect on the particle's position, but would be less accurate because of the lower wavelength. [ A Concise Dictionary of Physics ] quasit Quasits are small, evil creatures, related to imps. Their talons release a very toxic poison when used in an attack. *quest Many, possibly most, Tours are organized as a Quest. This is like a large-scale treasure hunt, with clues scattered all over the continent, a few false leads, Mystical Masters as game-show hosts, and the Dark Lord and the Terrain to make the Quest interestingly difficult. [...] In order to be assured of your future custom, the Management has a further Rule: Tourists, far from being rewarded for achieving their Quest Object, must then go on to conquer the Dark Lord or set about Saving the World, or both. And why not? By then you will have had a lot of practice in that sort of thing and, besides, the Quest Object is usually designed to help you do it. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] quetzalcoatl One of the principal Aztec-Toltec gods was the great and wise Quetzalcoatl, who was called Kukumatz in Guatemala, and Kukulcan in Yucatan. His image, the plumed serpent, is found on both the oldest and the most recent Indian edifices. ... The legend tells how the Indian deity Quetzalcoatl came from the "Land of the Rising Sun". He wore a long white robe and had a beard; he taught the people crafts and customs and laid down wise laws. He created an empire in which the ears of corn were as long as men are tall, and caused bolls of colored cotton to grow on cotton plants. But for some reason or other he had to leave his empire. ... But all the legends of Quetzalcoatl unanimously agree that he promised to come again. [ Gods, Graves, and Scholars, by C. W. Ceram ] quit* Maltar: [...] I remembered a little saying I learned my first day at the academy. Natalie: Yeah, yeah, I know. Winners never quit and quitters never win. Maltar: What? No! Winners never quit and quitters should be cast into the Flaming Pit of Death. [ Snow Day, directed by Chris Koch, written by Will McRobb and Chris Viscardi ] raijin raiden The Japanese god of thunder (rai) and lightning (den). He prevented the Mongols from invading Japan in 1274. Sitting on a cloud he sent forth a shower of lightning arrows upon the invading fleet. Only three men escaped. Raiden is portrayed as a red demon with sharp claws, carrying a large drum. He is fond of eating human navels. The only protection against him is to hide under a mosquito net. [ Encyclopedia Mythica, ed. M.F. Lindemans ] ranger * ranger "Lonely men are we, Rangers of the wild, hunters -- but hunters ever of the servants of the Enemy; for they are found in many places, not in Mordor only. If Gondor, Boromir, has been a stalwart tower, we have played another part. Many evil things there are that your strong walls and bright swords do not stay. You know little of the lands beyond your bounds. Peace and freedom, do you say? The North would have known them little but for us. Fear would have destroyed them. But when dark things come from the houseless hills, or creep from sunless woods, they fly from us. What roads would any dare to tread, what safety would there be in quiet lands, or in the homes of simple men at night, if the Dunedain were asleep, or were all gone into the grave?" [ The Fellowship of the Ring, by J.R.R. Tolkien ] rat * rat Rats are long-tailed rodents. They are aggressive, omnivorous, and adaptable, often carrying diseases. [] "The rat," said O'Brien, still addressing his invisible audience, "although a rodent, is carnivorous. You are aware of that. You will have heard of the things that happen in the poor quarters of this town. In some streets a woman dare not leave her baby alone in the house, even for five minutes. The rats are certain to attack it. Within quite a small time they will strip it to the bones. They also attack sick or dying people. They show astonishing intelligence in knowing when a human being is helpless." [ 1984, by George Orwell ] raven But the raven, sitting lonely on the placid bust, spoke only That one word, as if his soul in that one word he did outpour. Nothing further then he uttered -- not a feather then he fluttered-- Till I scarcely more than muttered, 'other friends have flown before-- On the morrow *he* will leave me, as my hopes have flown before.' Then the bird said, 'Nevermore.' [ The Raven, by Edgar Allan Poe ] ~*invisibility ring * ring ring of * Three Rings for the Elven-kings under the sky, Seven for the Dwarf-lords in their halls of stone, Nine for Mortal Men doomed to die, One for the Dark Lord on his dark throne, In the Land of Mordor where the Shadows lie. One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them In the Land of Mordor where the Shadows lie. [ The Fellowship of the Ring, by J.R.R. Tolkien ] ring of invisibility "When time came for the shepherds to hold their customary assembly in order to prepare their monthly report to the king about the state of the flocks, he came too, wearing this ring. While he was sitting with the others, it chanced that he moved the collet of the ring around toward himself into the inside of his hand; having done this, he disappeared from the sight of those who were sitting beside him, and they discussed of him as of someone who had left. And he wondered and once again feeling for the ring, he turned the collet outwards and, by turning it, reappeared. Reflecting upon this, he put the ring to the test to see if it indeed had such power, and he came to this conclusion that, by turning the collet inwards, he became invisible, outwards, visible. Having perceived this, he at once managed for himself to become one of the envoys to the king; upon arrival, having seduced his wife, with her help, he laid a hand on the king, murdered him and took hold of the leadership." [ The Republic, by Plato, translated by James Adam ] robe Robes are the only garments, apart from Shirts, ever to have sleeves. They have three uses: 1. As the official uniform of Priests, Priestesses, Monks, Nuns (see Nunnery), and Wizards. The OMT [ Official Management Term ] prescribed for the Robes of Priests and Nuns is that they _fall in severe folds_; of Priestesses that they _float_; and of Wizards that they _swirl_. You can thus see who you are dealing with. 2. For Kings. The OMT here is _falling in stately folds_. 3. As the garb of Desert Nomads. [...] [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] rock Bilbo saw that the moment had come when he must do something. He could not get up at the brutes and he had nothing to shoot with; but looking about he saw that in this place there were many stones lying in what appeared to be a now dry little watercourse. Bilbo was a pretty fair shot with a stone, and it did not take him long to find a nice smooth egg-shaped one that fitted his hand cosily. As a boy he used to practise throwing stones at things, until rabbits and squirrels, and even birds, got out of his way as quick as lightning if they saw him stoop; and even grownup he had still spent a deal of his time at quoits, dart-throwing, shooting at the wand, bowls, ninepins and other quiet games of the aiming and throwing sort - indeed he could do lots of things, besides blowing smoke-rings, asking riddles and cooking, that I haven't time to tell you about. There is no time now. While he was picking up stones, the spider had reached Bombur, and soon he would have been dead. At that moment Bilbo threw. The stone struck the spider plunk on the head, and it dropped senseless off the tree, flop to the ground, with all its legs curled up. [ The Hobbit, by J.R.R. Tolkien ] rock mole A rock mole is a member of the rodent family. They get their name from their ability to tunnel through rock in the same fashion that a mole tunnels through earth. They are known to eat anything they come across in their diggings, although it is still unknown how they convert some of these things into something of nutritional value. rodent* A gnawing mammal (order _Rodentia_) having in each jaw two (rarely four) incisors, growing continually from persistent pulps, and no canine teeth, as a squirrel, beaver, or rat. [ Webster's Comprehensive International Dictionary of the English Language ] rogue * rogue I understand the business, I hear it: to have an open ear, a quick eye, and a nimble hand, is necessary for a cut-purse; a good nose is requisite also, to smell out work for the other senses. I see this is the time that the unjust man doth thrive. ... The prince himself is about a piece of iniquity, stealing away from his father with his clog at his heels: if I thought it were a piece of honesty to acquaint the king withal, I would not do't: I hold it the more knavery to conceal it; and therein am I constant to my profession. [ Autolycus the Rogue, from The Winter's Tale by William Shakespeare ] roshi Roshi is a Japanese word, common in Zen Buddhism, meaning "old" (ro) and "teacher" (shi). Roshi can be used as a term of respect, as in the Rinzai school; as a simple reference to actual age, as in the Soto school; or it can mean a teacher who has transmitted knowledge to, and thus "given birth" to, a new teacher. [ Wikipedia, the free encyclopedia ] rothe The rothe (pronounced roth-AY) is a musk ox-like creature with an aversion to light. It prefers to live underground near lichen and moss. *royal jelly "'Royal Jelly,'" he read aloud, "'must be a substance of tremendous nourishing power, for on this diet alone, the honey-bee larva increases in weight fifteen hundred times in five days!'" "How much?" "Fifteen hundred times, Mabel. And you know what that means if you put it in terms of a human being? It means," he said, lowering his voice, leaning forward, fixing her with those small pale eyes, "it means that in five days a baby weighing seven and a half pounds to start off with would increase in weight to five tons!" [ Royal Jelly, by Roald Dahl ] ruby sapphire _Corundum._ Mineral, aluminum oxide, Al2O3. The clear varieties are used as gems and the opaque as abrasive materials. Corundum occurs in crystals of the hexagonal system and in masses. It is transparent to opaque and has a vitreous to adamantine luster. ... The chief corundum gems are the ruby (red) and the sapphire (blue). [ The Columbia Encyclopedia, Sixth Edition ] rust monster These strange creatures live on a diet of metals. They can turn a suit of armour into so much useless rusted scrap in no time at all. # takes "rust monster or disenchanter" when specifying 'R' rust monster or disenchanter These ground-dwelling monsters are known to make short work out of degrading adventurers' combat equipment. *saber *sabre Flashed all their sabres bare, Flashed as they turned in air, Sab'ring the gunners there, Charging an army, while All the world wondered: Plunged in the battery smoke, Right through the line they broke; Cossack and Russian Reeled from the sabre-stroke Shattered and sundered. Then they rode back, but not-- Not the six hundred. [ The Charge of the Light Brigade, by Alfred, Lord Tennyson ] saddle The horseman serves the horse, The neat-herd serves the neat, The merchant serves the purse, The eater serves his meat; 'Tis the day of the chattel, Web to weave, and corn to grind, Things are in the saddle, And ride mankind. [ Ode, by Ralph Waldo Emerson ] sake Japanese rice wine. salamander For hundreds of years, many people believed that salamanders were magical. In England in the Middle Ages, people thought that fire created salamanders. When they set fire to damp logs, dozens of the slimy creatures scurried out. The word salamander, in fact, comes from a Greek word meaning "fire animal". [ Salamanders, by Cherie Winner ] samurai * samurai By that time, Narahara had already slipped his arm from the sleeve of his outer robe, drew out his two-and-a-half-foot Fujiwara Tadahiro sword, and, brandishing it over his head, began barreling toward the foreigners. In less than a minute, he had charged upon them and cut one of them through the torso. The man fled, clutching his bulging guts, finally to fall from his horse at the foot of a pine tree about a thousand yards away. Kaeda Takeji finished him off. The other two Englishmen were severely wounded as they tried to flee. Only the woman managed to escape virtually unscathed. [ The Fox-horse, from Drunk as a Lord, by Ryotaro Shiba ] sandestin Ildefonse left the terrace and almost immediately sounds of contention came from the direction of the work-room. Ildefonse presently returned to the terrace, followed by Osherl and a second sandestin using the guise of a gaunt blue bird-like creature, some six feet in height. Ildefonse spoke in scathing tones: "Behold these two creatures! They can roam the chronoplex as easily as you or I can walk around the table; yet neither has the wit to announce his presence upon arrival. I found Osherl asleep in his fulgurite and Sarsem perched in the rafters." [...] "No matter," said Rhialto. "He has brought Sarsem, and this was his requirement. In the main, Osherl, you have done well!" "And my indenture point?" "Much depends upon Sarsem's testimony. Sarsem, will you sit?" "In this guise, I find it more convenient to stand." "Then why not alter to human form and join us in comfort at the table?" "That is a good idea." Sarsem became a naked young epicene in an integument of lavender scales with puffs of purple hair like pom-poms growing down his back. He seated himself at the table but declined refreshment. "This human semblance, though typical, is after all, only a guise. If I were to put such things inside myself, I might well become uneasy." [ Rhialto the Marvellous, by Jack Vance ] sasquatch The name _Sasquatch_ doesn't really become important in Canada until the 1930s, when it appeared in the works of J. W. Burns, a British Columbian writer who used a great deal of Indian lore in his stories. Burn's Sasquatch was a giant Indian who lived in the wilderness. He was hairy only in the sense that he had long hair on his head, and while this Sasquatch lived a wild and primitive life, he was fully human. Burns's character proved to be quite popular. There was a Sasquatch Inn near the town of Harrison, British Columbia, and Harrison even had a local celebration called "Sasquatch Days." The celebration which had been dormant for years was revived as part of British Columbia's centennial, and one of the events was to be a Sasquatch hunt. The hunt never took place, perhaps it was never supposed to, but the publicity about it did bring out a number of people who said they had encountered a Sasquatch -- not Burns's giant Indian, but the hairy apelike creature that we have all come to know. [ The Encyclopedia of Monsters, by Daniel Cohen ] scalpel A scalpel is a very sharp knife used for surgery ... Merely touching a medical scalpel with bare hands to test it will cut through the skin. ... Medical scalpel blades are gradually curved for greater precision when cutting through tissue. [ Wikipedia, the free encyclopedia ] *sceptre of might This mace was created aeons ago in some unknown cave, and has been passed down from generation to generation of cave dwellers. It is a very mighty mace indeed, and in addition will protect anyone who carries it from magic missile attacks. When invoked, it causes conflict in the area around it. scimitar Oh, how handsome, how noble was the Vizier Ali Tebelin, my father, as he stood there in the midst of the shot, his scimitar in his hand, his face black with powder! How his enemies fled before him! [ The Count of Monte Cristo, by Alexandre Dumas ] scorpio* A sub-species of the spider (_Scorpionidae_), the scorpion distinguishes itself from them by having a lower body that ends in a long, jointed tail tapering to a poisonous stinger. They have eight legs and pincers. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] scorpius Since early times, the Scorpion has represented death, darkness, and evil. Scorpius is the reputed slayer of Orion the Hunter. [...] The gods put both scorpion and hunter among the stars, but on opposite sides of the sky so they would never fight again. As Scorpius rises in the east, Orion sets in the west. [ 365 Starry Nights, by Chet Raymo ] *scroll scroll * And I was gazing on the surges prone, With many a scalding tear and many a groan, When at my feet emerg'd an old man's hand, Grasping this scroll, and this same slender wand. I knelt with pain--reached out my hand--had grasp'd Those treasures--touch'd the knuckles--they unclasp'd-- I caught a finger: but the downward weight O'erpowered me--it sank. Then 'gan abate The storm, and through chill aguish gloom outburst The comfortable sun. I was athirst To search the book, and in the warming air Parted its dripping leaves with eager care. Strange matters did it treat of, and drew on My soul page after page, till well-nigh won Into forgetfulness; when, stupefied, I read these words, and read again, and tried My eyes against the heavens, and read again. [ Endymion, by John Keats ] set seth The ancient Egyptian god of chaos (Set), the embodiment of hostility and even of outright evil. He is also a god of war, deserts, storms, and foreign lands. ... In the Book of the Dead, Seth is called "Lord of the Northern Sky" and is held responsible for storms and cloudy weather. ... Seth was portrayed as a man with the head of undeterminable origin, although some see in it the head of an aardvark. He had a curved snout, erect square-tipped ears and a long forked tail. He was sometimes entirely in animal form with the body similar to that of a greyhound. Animals sacred to this god were the dog, the jackal, the gazelle, the donkey, the crocodile, the hippopotamus, and the pig. [ Encyclopedia Mythica, ed. M.F. Lindemans ] shad* Shades are undead creatures. They differ from zombies in that a zombie is an undead animation of a corpse, while a shade is an undead creature magically created by the use of black magic. shaman karnov Making his quarters in the Caves of the Ancestors, Shaman Karnov unceasingly tries to shield his neanderthal people from Tiamat's minions' harassments. shan*lai*ching The Chinese god of Mountains and Seas, also the name of an old book (also Shan Hai Tjing), the book of mountains and seas - which deals with the monster Kung Kung trying to seize power from Yao, the fourth emperor. [ Spectrum Atlas van de Mythologie ] shark As the shark moved, its dark top reflected virtually no light. The denticles on its skin muted the whoosh of its movements as the shark rose, driven by the power of the great tail sweeping from side to side, like a scythe. The fish exploded upward. Charles Bruder felt a slight vacuum tug in the motion of the sea, noted it as a passing current, the pull of a wave, the tickle of undertow. He could not have heard the faint sucking rush of water not far beneath him. He couldn't have seen or heard what was hurtling from the murk at astonishing speed, jaws unhinging, widening, for the enormous first bite. It was the classic attack that no other creature in nature could make -- a bomb from the depths. [ Close to Shore, by Michael Capuzzo ] shito A Japanese stabbing knife. shopkeeper There have been three general theories put forward to explain the phenomenon of the wandering shops or, as they are generically known, _tabernae vagantes._ The first postulates that many thousands of years ago there evolved somewhere in the multiverse a race whose single talent was to buy cheap and sell dear. Soon they controlled a vast galactic empire or, as they put it, Emporium, and the more advanced members of the species found a way to equip their very shops with unique propulsion units that could break the dark walls of space itself and open up vast new markets. And long after the worlds of the Emporium perished in the heat death of their particular universe, after one last defiant fire sale, the wandering starshops still ply their trade, eating their way through the pages of spacetime like a worm through a three- volume novel. The second is that they are the creation of a sympathetic Fate, charged with the role of supplying exactly the right thing at the right time. The third is that they are simply a very clever way of getting around the various Sunday Closing acts. All these theories, diverse as they are, have two things in common. They explain the observed facts, and they are completely and utterly wrong. [ The Light Fantastic, by Terry Pratchett ] shrieker With a single, savage thrust of her spear, the warrior-woman impaled the fungus, silencing it. However, it was too late: the alarm had been raised[...] Suddenly, a large, dark shape rose from the abyss before them, its fetid bulk looming overhead... The monster was some kind of great dark worm, but that was about all they were sure of. [ The Adventurers, Epic IV, by Thomas A. Miller ] throwing star shuriken You know, that's what I hate most about fighting against magic: you never know what they're trying to do to you until it hits. The sorceress knew what hit her, however. Two of the shuriken got past whatever defenses she had. One caught her just below the throat, the other in the middle of her chest. It wouldn't kill her, but she wouldn't be fighting anyone for a while. [ Jhereg, by Steven Brust ] skeleton A skeleton is a magically animated undead creature. Unlike shades, only a humanoid creature can be used to create a skeleton. No one knows why this is true, but it has become an accepted fact amongst the practitioners of the black arts. slasher "That dog belonged to a settler who tried to build his cabin on the bank of the river a few miles south of the fort," grunted Conan. ... "We took him to the fort and dressed his wounds, but after he recovered he took to the woods and turned wild. -- What now, Slasher, are you hunting the men who killed your master?" ... "Let him come," muttered Conan. "He can smell the devils before we can see them." ... Slasher cleared the timbers with a bound and leaped into the bushes. They were violently shaken and then the dog slunk back to Balthus' side, his jaws crimson. ... "He was a man," said Conan. "I drink to his shade, and to the shade of the dog, who knew no fear." He quaffed part of the wine, then emptied the rest upon the floor, with a curious heathen gesture, and smashed the goblet. "The heads of ten Picts shall pay for this, and seven heads for the dog, who was a better warrior than many a man." [ Conan The Warrior, by Robert E Howard ] *sleep Sleep is a death; oh, make me try By sleeping, what it is to die, And as gently lay my head On my grave, as now my bed. [ Religio Medici, by Sir Thomas Browne ] slime mold Science fiction did not invent the slime molds, but it has borrowed from them in using the idea of sheets of liquid, flowing cytoplasm engulfing and dissolving every living thing they touch. What fiction can only imagine, nature has produced, and only their small size and dependence on coolness, moisture, and darkness has kept the slime molds from ordinary observation, for they are common enough. [ Encyclopaedia Britannica, 1977 ] sling And it came to pass, when the Philistine arose, and came and drew nigh to meet David, that David hasted, and ran toward the army to meet the Philistine. And David put his hand in his bag, and took thence a stone, and slang it, and smote the Philistine in his forehead, that the stone sunk into his forehead; and he fell upon his face to the earth. So David prevailed over the Philistine with a sling and with a stone, and smote the Philistine, and slew him; but there was no sword in the hand of David. [ 1 Samuel 17:48-50 ] *snake serpent water moccasin pit viper Now the serpent was more subtle than any beast of the field which the Lord God had made. And he said unto the woman, Yea, hath God said, Ye shall not eat of every tree of the garden? And the woman said unto the serpent, We may eat of the fruit of the trees of the garden: but of the fruit of the tree which is in the midst of the garden, God hath said, Ye shall not eat of it, neither shall ye touch it, lest ye die. And the serpent said unto the woman, Ye shall not surely die: for God doth know that in the day ye eat thereof, then your eyes shall be opened, and ye shall be as gods, knowing good and evil. And when the woman saw that the tree was good for food, and that it was pleasant to the eyes, and a tree to be desired to make one wise, she took of the fruit thereof, and did eat, and gave also unto her husband with her; and he did eat. And the Lord God said unto the woman, What is this that thou hast done? And the woman said, The serpent beguiled me, and I did eat. And the Lord God said unto the serpent, Because thou hast done this, thou art cursed above all cattle, and above every beast of the field; upon thy belly shalt thou go, and dust shalt thou eat all the days of thy life: And I will put enmity between thee and the woman, and between thy seed and her seed; it shall bruise thy head, and thou shalt bruise his heel. [ Genesis 3:1-6,13-15 ] snickersnee Ah, never shall I forget the cry, or the shriek that shrieked he, As I gnashed my teeth, and from my sheath I drew my Snickersnee! --Koko, Lord high executioner of Titipu [ The Mikado, by Sir W.S. Gilbert ] sokoban Sokoban (Japanese for "warehouse keeper") is a transport puzzle in which the player pushes boxes around a maze, viewed from above, and tries to put them in designated locations. Only one box may be pushed at a time, not two, and boxes cannot be pulled. As the puzzle would be extremely difficult to create physically, it is usually implemented as a video game. Sokoban was created in 1982 by Hiroyuki Imabayashi, and was published by Thinking Rabbit, a software house based in Takarazuka, Japan. Thinking Rabbit also released three sequels: Boxxle, Sokoban Perfect and Sokoban Revenge. [ Wikipedia, the free encyclopedia ] *soldier sergeant lieutenant captain The soldiers of Yendor are well-trained in the art of war, many trained by the Wizard himself. Some say the soldiers are explorers who were unfortunate enough to be captured, and put under the Wizard's spell. Those who have survived encounters with soldiers say they travel together in platoons, and are fierce fighters. Because of the load of their combat gear, however, one can usually run away from them, and doing so is considered a wise thing. *spear javelin - they come together with great random, and a spear is brast, and one party brake his shield and the other one goes down, horse and man, over his horse-tail and brake his neck, and then the next candidate comes randoming in, and brast his spear, and the other man brast his shield, and down he goes, horse and man, over his horse-tail, and brake his neck, and then there's another elected, and another and another and still another, till the material is all used up; and when you come to figure up results, you can't tell one fight from another, nor who whipped; and as a picture of living, raging, roaring battle, sho! why it's pale and noiseless - just ghosts scuffling in a fog. Dear me, what would this barren vocabulary get out of the mightiest spectacle? - the burning of Rome in Nero's time, for instance? Why, it would merely say 'Town burned down; no insurance; boy brast a window, fireman brake his neck!' Why, that ain't a picture! [ A Connecticut Yankee in King Arthur's Court, by Mark Twain ] *spellbook* The Book of Three lay closed on the table. Taran had never been allowed to read the volume for himself; now he was sure it held more than Dallben chose to tell him. In the sun- filled room, with Dallben still meditating and showing no sign of stopping, Taran rose and moved through the shimmering beams. From the forest came the monotonous tick of a beetle. His hands reached for the cover. Taran gasped in pain and snatched them away. They smarted as if each of his fingers had been stung by hornets. He jumped back, stumbled against the bench, and dropped to the floor, where he put his fingers woefully into his mouth. Dallben's eyes blinked open. He peered at Taran and yawned slowly. "You had better see Coll about a lotion for those hands," he advised. "Otherwise, I shouldn't be surprised if they blistered." [ The Book of Three, by Lloyd Alexander ] *spider Eight legged creature capable of spinning webs to trap prey. [] "You mean you eat flies?" gasped Wilbur. "Certainly. Flies, bugs, grasshoppers, choice beetles, moths, butterflies, tasty cockroaches, gnats, midges, daddy longlegs, centipedes, mosquitoes, crickets - anything that is careless enough to get caught in my web. I have to live, don't I?" "Why, yes, of course," said Wilbur. [ Charlotte's Web, by E.B. White ] *spore *sphere The attack by those who want to die -- this is the attack against which you cannot prepare a perfect defense. --Human aphorism [ The Dosadi Experiment, by Frank Herbert ] squeaky board A floorboard creaked. Galder had spent many hours tuning them, always a wise precaution with an ambitious assistant who walked like a cat. D flat. That meant he was just to the right of the door. "Ah, Trymon," he said, without turning, and noted with some satisfaction the faint indrawing of breath behind him. "Good of you to come. Shut the door, will you?" [ The Light Fantastic, by Terry Pratchett ] ~*aesculapius *staff So they stood, each in his place, neither moving a finger's breadth back, for one good hour, and many blows were given and received by each in that time, till here and there were sore bones and bumps, yet neither thought of crying "Enough," or seemed likely to fall from off the bridge. Now and then they stopped to rest, and each thought that he never had seen in all his life before such a hand at quarterstaff. At last Robin gave the stranger a blow upon the ribs that made his jacket smoke like a damp straw thatch in the sun. So shrewd was the stroke that the stranger came within a hair's breadth of falling off the bridge; but he regained himself right quickly, and, by a dexterous blow, gave Robin a crack on the crown that caused the blood to flow. Then Robin grew mad with anger, and smote with all his might at the other; but the stranger warded the blow, and once again thwacked Robin, and this time so fairly that he fell heels over head into the water, as the queen pin falls in a game of bowls. [ The Merry Adventures of Robin Hood, by Howard Pyle ] *staff of aesculapius This staff is considered sacred to all healers, as it truly holds the powers of life and death. When wielded, it protects its user from all life draining attacks, and additionally gives the wielder the power of regeneration. When invoked it performs healing magic. stair* Up he went -- very quickly at first -- then more slowly -- then in a little while even more slowly than that -- and finally, after many minutes of climbing up the endless stairway, one weary foot was barely able to follow the other. Milo suddenly realized that with all his effort he was no closer to the top than when he began, and not a great deal further from the bottom. But he struggled on for a while longer, until at last, completely exhausted, he collapsed onto one of the steps. "I should have known it," he mumbled, resting his tired legs and filling his lungs with air. "This is just like the line that goes on forever, and I'll never get there." "You wouldn't like it much anyway," someone replied gently. "Infinity is a dreadfully poor place. They can never manage to make ends meet." [ The Phantom Tollbooth, by Norton Juster ] Dr. Ray Stantz: Hey, where do those stairs go? Dr. Peter Venkman: They go up. [ Ghostbusters, directed by Ivan Reitman, written by Dan Ackroyd and Harold Ramis ] ~statue trap statue* Then at last he began to wonder why the lion was standing so still - for it hadn't moved one inch since he first set eyes on it. Edmund now ventured a little nearer, still keeping in the shadow of the arch as much as he could. He now saw from the way the lion was standing that it couldn't have been looking at him at all. ("But supposing it turns its head?" thought Edmund.) In fact it was staring at something else - namely a little dwarf who stood with his back to it about four feet away. "Aha!" thought Edmund. "When it springs at the dwarf then will be my chance to escape." But still the lion never moved, nor did the dwarf. And now at last Edmund remembered what the others had said about the White Witch turning people into stone. Perhaps this was only a stone lion. And as soon as he had thought of that he noticed that the lion's back and the top of its head were covered with snow. Of course it must be only a statue! [ The Lion, the Witch and the Wardrobe by C.S. Lewis ] sting There was the usual dim grey light of the forest-day about him when he came to his senses. The spider lay dead beside him, and his sword-blade was stained black. Somehow the killing of the giant spider, all alone and by himself in the dark without the help of the wizard or the dwarves or of anyone else, made a great difference to Mr. Baggins. He felt a different person, and much fiercer and bolder in spite of an empty stomach, as he wiped his sword on the grass and put it back into its sheath. "I will give you a name," he said to it, "and I shall call you Sting." [ The Hobbit, by J.R.R. Tolkien ] stormbringer There were sounds in the distance, incongruent with the sounds of even this nameless, timeless sea: thin sounds, agonized and terrible, for all that they remained remote - yet the ship followed them, as if drawn by them; they grew louder - pain and despair were there, but terror was predominant. Elric had heard such sounds echoing from his cousin Yyrkoon's sardonically named 'Pleasure Chambers' in the days before he had fled the responsibilities of ruling all that remained of the old Melnibonean Empire. These were the voices of men whose very souls were under siege; men to whom death meant not mere extinction, but a continuation of existence, forever in thrall to some cruel and supernatural master. He had heard men cry so when his salvation and his nemesis, his great black battle-blade Stormbringer, drank their souls. [ The Lands Beyond the World, by Michael Moorcock ] *strange object He walked for some time through a long narrow corridor without finding any one and was just going to call out, when suddenly in a dark corner between an old cupboard and the door he caught sight of a strange object which seemed to be alive. [ Crime and Punishment, by Fyodor Dostoevsky ] straw golem Dorothy leaned her chin upon her hand and gazed thoughtfully at the Scarecrow. Its head was a small sack stuffed with straw, with eyes, nose, and mouth painted on it to represent a face. An old, pointed blue hat, that had belonged to some Munchkin, was perched on his head, and the rest of the figure was a blue suit of clothes, worn and faded, which had also been stuffed with straw. On the feet were some old boots with blue tops, such as every man wore in this country, and the figure was raised above the stalks of corn by means of the pole stuck up its back. [ The Wonderful Wizard of Oz, by L. Frank Baum ] susano*o The Shinto chthonic and weather god and brother of the sun goddess Amaterasu, he was born from the nose of the primordial creator god Izanagi and represents the physical, material world. He has been expelled from heaven and taken up residence on earth. [ Encyclopedia of Gods, by Michael Jordan ] tanko Samurai plate armor of the Yamato period (AD 300 - 710). tengu The tengu was the most troublesome creature of Japanese legend. Part bird and part man, with red beak for a nose and flashing eyes, the tengu was notorious for stirring up feuds and prolonging enmity between families. Indeed, the belligerent tengu were supposed to have been man's first instructors in the use of arms. [ Mythical Beasts, by Deirdre Headon (The Leprechaun Library) ] thoth The Egyptian god of the moon and wisdom, Thoth is the patron deity of scribes and of knowledge, including scientific, medical and mathematical writing, and is said to have given mankind the art of hieroglyphic writing. He is important as a mediator and counsellor amongst the gods and is the scribe of the Heliopolis Ennead pantheon. According to mythology, he was born from the head of the god Seth. He may be depicted in human form with the head of an ibis, wholly as an ibis, or as a seated baboon sometimes with its torso covered in feathers. His attributes include a crown which consists of a crescent moon surmounted by a moon disc. Thoth is generally regarded as a benign deity. He is also scrupulously fair and is responsible not only for entering in the record the souls who pass to afterlife, but of adjudicating in the Hall of the Two Truths. The Pyramid Texts reveal a violent side of his nature by which he decapitates the adversaries of truth and wrenches out their hearts. [ Encyclopedia of Gods, by Michael Jordan ] thoth*amon Men say that he [Thutothmes] has opposed Thoth-Amon, who is master of all priests of Set, and dwells in Luxor, and that Thutothmes seeks hidden power [The Heart of Ahriman] to overthrow the Great One. [ Conan the Conqueror, by Robert E. Howard ] *throne Methought I saw the footsteps of a throne Which mists and vapours from mine eyes did shroud-- Nor view of who might sit thereon allowed; But all the steps and ground about were strown With sights the ruefullest that flesh and bone Ever put on; a miserable crowd, Sick, hale, old, young, who cried before that cloud, "Thou art our king, O Death! to thee we groan." Those steps I clomb; the mists before me gave Smooth way; and I beheld the face of one Sleeping alone within a mossy cave, With her face up to heaven; that seemed to have Pleasing remembrance of a thought foregone; A lovely Beauty in a summer grave! [ Sonnet, by William Wordsworth ] thug A worshipper of Kali, who practised _thuggee_, the strangling of human victims in the name of the religion. Robbery of the victim provided the means of livelihood. They were also called _Phansigars_ (Noose operators) from the method employed. Vigorous suppression was begun by Lord William Bentinck in 1828, but the fraternity did not become completely extinct for another 50 years or so. In common parlance the word is used for any violent "tough". [ Brewer's Concise Dictionary of Phrase and Fable ] tiger 1. A well-known tropical predator (_Felis tigris_): a feline. It has a yellowish skin with darker spots or stripes. 2. Figurative: _a paper tiger_, something that is meant to scare, but has no really scaring effect whatsoever, (after a statement by Mao Ze Dong, August 1946). [ Van Dale's Groot Woordenboek der Nederlandse Taal ] Tyger! Tyger! burning bright In the forests of the night, What immortal hand or eye Could frame thy fearful symmetry? [ The Tyger, by William Blake ] tin tin of * tinning kit "You know salmon, Sarge," said Nobby. "It is a fish of which I am aware, yes." "You know they sell kind of slices of it in tins..." "So I am given to understand, yes." "Weell...how come all the tins are the same size? Salmon gets thinner at both ends." "Interesting point, Nobby. I think-" [ Soul Music, by Terry Pratchett ] tin opener Less than thirty Cat tribes now survived, roaming the cargo decks on their hind legs in a desperate search for food. But the food had gone. The supplies were finished. Weak and ailing, they prayed at the supply hold's silver mountains: huge towering acres of metal rocks which, in their pagan way, the mutant Cats believed watched over them. Amid the wailing and the screeching one Cat stood up and held aloft the sacred icon. The icon which had been passed down as holy, and one day would make its use known. It was a piece of V-shaped metal with a revolving handle on its head. He took down a silver rock from the silver mountain, while the other Cats cowered and screamed at the blasphemy. He placed the icon on the rim of the rock, and turned the handle. And the handle turned. And the rock opened. And inside the rock was Alphabetti spaghetti in tomato sauce. [ Red Dwarf, by Rob Grant and Doug Naylor ] titan Gaea, mother earth, arose from the Chaos and gave birth to Uranus, heaven, who became her consort. Uranus hated all their children, because he feared they might challenge his own authority. Those children, the Titans, the Gigantes, and the Cyclops, were banished to the nether world. Their enraged mother eventually released the youngest titan, Chronos (time), and encouraged him to castrate his father and rule in his place. Later, he too was challenged by his own son, Zeus, and he and his fellow titans were ousted from Mount Olympus. [ Greek Mythology, by Richard Patrick ] topaz Aluminum silicate mineral with either hydroxyl radicals or fluorine, Al2SiO4(F,OH)2, used as a gem. It is commonly colorless or some shade of pale yellow to wine-yellow; ... The stone is transparent with a vitreous luster. It has perfect cleavage on the basal pinacoid, but it is nevertheless hard and durable. The brilliant cut is commonly used. Topaz crystals, which are of the orthorhombic system, occur in highly acid igneous rocks, e.g., granites and rhyolites, and in metamorphic rocks, e.g., gneisses and schists. [ The Columbia Encyclopedia, Sixth Edition ] touch*stone "Gold is tried by a touchstone, men by gold." [ Chilon (c. 560 BC) ] tourist * tourist The road from Ankh-Morpork to Chrim is high, white and winding, a thirty-league stretch of potholes and half-buried rocks that spirals around mountains and dips into cool green valleys of citrus trees, crosses liana-webbed gorges on creaking rope bridges and is generally more picturesque than useful. Picturesque. That was a new word to Rincewind the wizard (BMgc, Unseen University [failed]). It was one of a number he had picked up since leaving the charred ruins of Ankh-Morpork. Quaint was another one. Picturesque meant -- he decided after careful observation of the scenery that inspired Twoflower to use the word -- that the landscape was horribly precipitous. Quaint, when used to describe the occasional village through which they passed, meant fever- ridden and tumbledown. Twoflower was a tourist, the first ever seen on the discworld. Tourist, Rincewind had decided, meant "idiot". [ The Colour of Magic, by Terry Pratchett ] towel The Hitchhiker's Guide to the Galaxy has a few things to say on the subject of towels. A towel, it says, is about the most massively useful thing an interstellar hitchhiker can have. Partly it has great practical value. You can wrap it around you for warmth as you bound across the cold moons of Jaglan Beta; you can lie on it on the brilliant marble-sanded beaches of Santraginus V, inhaling the heady sea vapors; you can sleep under it beneath the stars which shine so redly on the desert world of Kakrafoon; use it to sail a miniraft down the slow heavy River Moth; wet it for use in hand-to-hand combat; wrap it round your head to ward off noxious fumes or avoid the gaze of the Ravenous Bugblatter Beast of Traal (a mind-bogglingly stupid animal, it assumes that if you can't see it, it can't see you - daft as a brush, but very very ravenous); you can wave your towel in emergencies as a distress signal, and of course dry yourself off with it if it still seems to be clean enough. [ The Hitchhiker's Guide to the Galaxy, by Douglas Adams ] *tower *tower of darkness Towers (_brooding_, _dark_) stand alone in Waste Areas and almost always belong to Wizards. All are several stories high, round, doorless, virtually windowless, and composed of smooth blocks of masonry that make them very hard to climb. [...] You will have to go to a Tower and then break into it at some point towards the end of your Tour. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] trap*door I knew my Erik too well to feel at all comfortable on jumping into his house. I knew what he had made of a certain palace at Mazenderan. From being the most honest building conceivable, he soon turned it into a house of the very devil, where you could not utter a word but it was overheard or repeated by an echo. With his trap-doors the monster was responsible for endless tragedies of all kinds. [ The Phantom of the Opera, by Gaston Leroux ] # takes "trapper or lurker above" when specifying 't' trapper trapper or lurker above The trapper is a creature which has evolved a chameleon-like ability to blend into the dungeon surroundings. It captures its prey by remaining very still and blending into the surrounding dungeon features, until an unsuspecting creature passes by. It wraps itself around its prey and digests it. tree I think that I shall never see A poem lovely as a tree. A tree whose hungry mouth is prest Against the earth's sweet flowing breast; A tree that looks at God all day, And lifts her leafy arms to pray; A tree that may in Summer wear A nest of robins in her hair; Upon whose bosom snow has lain; Who intimately lives with rain. Poems are made by fools like me, But only God can make a tree. [ Trees, by Joyce Kilmer ] tripe tripe ration If you start from scratch, cooking tripe is a long-drawn-out affair. Fresh whole tripe calls for a minimum of 12 hours of cooking, some time-honored recipes demanding as much as 24. To prepare fresh tripe, trim if necessary. Wash it thoroughly, soaking overnight, and blanch, for 1/2 hour in salted water. Wash well again, drain and cut for cooking. When cooked, the texture of tripe should be like that of soft gristle. More often, alas, because the heat has not been kept low enough, it has the consistency of wet shoe leather. [ Joy of Cooking, by I Rombauer and M Becker ] *troll The troll shambled closer. He was perhaps eight feet tall, perhaps more. His forward stoop, with arms dangling past thick claw-footed legs to the ground, made it hard to tell. The hairless green skin moved upon his body. His head was a gash of a mouth, a yard-long nose, and two eyes which drank the feeble torchlight and never gave back a gleam. [...] Like a huge green spider, the troll's severed hand ran on its fingers. Across the mounded floor, up onto a log with one taloned forefinger to hook it over the bark, down again it scrambled, until it found the cut wrist. And there it grew fast. The troll's smashed head seethed and knit together. He clambered back on his feet and grinned at them. The waning faggot cast red light over his fangs. [ Three Hearts and Three Lions, by Poul Anderson ] *tsurugi of muramasa This most ancient of swords has been passed down through the leadership of the Samurai legions for hundreds of years. It is said to grant luck to its wielder, but its main power is terrible to behold. It has the capability to cut in half any creature it is wielded against, instantly killing them. ~*muramasa tsurugi The tsurugi, also known as the long samurai sword, is an extremely sharp, two-handed blade favored by the samurai. It is made of hardened steel, and is manufactured using a special process, causing it to never rust. The tsurugi is rumored to be so sharp that it can occasionally cut opponents in half! ~*spellbook turquoise* TUBAL: There came divers of Antonio's creditors in my company to Venice that swear he cannot choose but break. SHYLOCK: I am very glad of it; I'll plague him, I'll torture him; I am glad of it. TUBAL: One of them showed me a ring that he had of your daughter for a monkey. SHYLOCK: Out upon her! Thou torturest me, Tubal. It was my turquoise; I had it of Leah when I was a bachelor; I would not have given it for a wilderness of monkeys. [ The Merchant of Venice, by William Shakespeare ] twoflower guide "Rincewind!" Twoflower sprang off the bed. The wizard jumped back, wrenching his features into a smile. "My dear chap, right on time! We'll just have lunch, and then I'm sure you've got a wonderful programme lined up for this afternoon!" "Er --" "That's great!" Rincewind took a deep breath. "Look," he said desperately, "let's eat somewhere else. There's been a bit of a fight down below." "A tavern brawl? Why didn't you wake me up?" "Well, you see, I - _what_?" "I thought I made myself clear this morning, Rincewind. I want to see genuine Morporkian life - the slave market, the Whore Pits, the Temple of Small Gods, the Beggar's Guild... and a genuine tavern brawl." A faint note of suspicion entered Twoflower's voice. "You _do_ have them, don't you? You know, people swinging on chandeliers, swordfights over the table, the sort of thing Hrun the Barbarian and the Weasel are always getting involved in. You know -- _excitement_." [ The Colour of Magic, by Terry Pratchett ] tyr Yet remains that one of the Aesir who is called Tyr: he is most daring, and best in stoutness of heart, and he has much authority over victory in battle; it is good for men of valor to invoke him. It is a proverb, that he is Tyr-valiant, who surpasses other men and does not waver. He is wise, so that it is also said, that he that is wisest is Tyr-prudent. This is one token of his daring: when the Aesir enticed Fenris-Wolf to take upon him the fetter Gleipnir, the wolf did not believe them, that they would loose him, until they laid Tyr's hand into his mouth as a pledge. But when the Aesir would not loose him, then he bit off the hand at the place now called 'the wolf's joint;' and Tyr is one- handed, and is not called a reconciler of men. [ The Prose Edda, by Snorri Sturluson ] *hulk Umber hulks are powerful subterranean predators whose iron-like claws allow them to burrow through solid stone in search of prey. They are tremendously strong; muscles bulge beneath their thick, scaly hides and their powerful arms and legs all end in great claws. *unicorn unicorn horn Men have always sought the elusive unicorn, for the single twisted horn which projected from its forehead was thought to be a powerful talisman. It was said that the unicorn had simply to dip the tip of its horn in a muddy pool for the water to become pure. Men also believed that to drink from this horn was a protection against all sickness, and that if the horn was ground to a powder it would act as an antidote to all poisons. Less than 200 years ago in France, the horn of a unicorn was used in a ceremony to test the royal food for poison. Although only the size of a small horse, the unicorn is a very fierce beast, capable of killing an elephant with a single thrust from its horn. Its fleetness of foot also makes this solitary creature difficult to capture. However, it can be tamed and captured by a maiden. Made gentle by the sight of a virgin, the unicorn can be lured to lay its head in her lap, and in this docile mood, the maiden may secure it with a golden rope. [ Mythical Beasts, by Deirdre Headon (The Leprechaun Library) ] Martin took a small sip of beer. "Almost ready," he said. "You hold your beer awfully well." Tlingel laughed. "A unicorn's horn is a detoxicant. Its possession is a universal remedy. I wait until I reach the warm glow stage, then I use my horn to burn off any excess and keep me right there." [ Unicorn Variations, by Roger Zelazny ] valkyrie * valkyrie The Valkyries were the thirteen choosers of the slain, the beautiful warrior-maids of Odin who rode through the air and over the sea. They watched the progress of the battle and selected the heroes who were to fall fighting. After they were dead, the maidens rewarded the heroes by kissing them and then led their souls to Valhalla, where the warriors lived happily in an ideal existence, drinking and eating without restraint and fighting over again the battles in which they died and in which they had won their deathless fame. [ The Encyclopaedia of Myths and Legends of All Nations, by Herbert Robinson and Knox Wilson ] vampire ~vampire bat vampire lord The Oxford English Dictionary is quite unequivocal: _vampire_ - "a preternatural being of a malignant nature (in the original and usual form of the belief, a reanimated corpse), supposed to seek nourishment, or do harm, by sucking the blood of sleeping persons. ..." venus Venus, the goddess of love and beauty, was the daughter of Jupiter and Dione. Others say that Venus sprang from the foam of the sea. The zephyr wafted her along the waves to the Isle of Cyprus, where she was received and attired by the Seasons, and then led to the assembly of the gods. All were charmed with her beauty, and each one demanded her for his wife. Jupiter gave her to Vulcan, in gratitude for the service he had rendered in forging thunderbolts. So the most beautiful of the goddesses became the wife of the most ill-favoured of gods. [ Bulfinch's Mythology, by Thomas Bulfinch ] vlad* Vlad Dracula the Impaler was a 15th-Century monarch of the Birgau region of the Carpathian Mountains, in what is now Romania. In Romanian history he is best known for two things. One was his skilled handling of the Ottoman Turks, which kept them from making further inroads into Christian Europe. The other was the ruthless manner in which he ran his fiefdom. He dealt with perceived challengers to his rule by impaling them upright on wooden stakes. Visiting dignitaries who failed to doff their hats had them nailed to their head. *vortex vortices Swirling clouds of pure elemental energies, the vortices are thought to be related to the larger elementals. Though the vortices do no damage when touched, they are noted for being able to envelop unwary travellers. The hapless fool thus swallowed by a vortex will soon perish from exposure to the element the vortex is composed of. vrock The vrock is one of the weaker forms of demon. It resembles a cross between a human being and a vulture and does physical damage by biting and by using the claws on both its arms and feet. wakizashi A wakizashi was used as a samurai's weapon when the katana was unavailable. When entering a building, a samurai would leave his katana on a rack near the entrance. However, the wakizashi would be worn at all times, and therefore, it made a sidearm for the samurai (similar to a soldier's use of a pistol). The samurai would have worn it from the time they awoke to the time they went to sleep. In earlier periods, and especially during times of civil wars, a tanto was worn in place of a wakizashi. [ Wikipedia, the free encyclopedia ] # takes "wand or a wall" when specifying '/' ~*sleep wand * *wand 'Saruman!' he cried, and his voice grew in power and authority. 'Behold, I am not Gandalf the Grey, whom you betrayed. I am Gandalf the White, who has returned from death. You have no colour now, and I cast you from the order and from the Council.' He raised his hand, and spoke slowly in a clear cold voice. 'Saruman, your staff is broken.' There was a crack, and the staff split asunder in Saruman's hand, and the head of it fell down at Gandalf's feet. 'Go!' said Gandalf. With a cry Saruman fell back and crawled away. [ The Two Towers, by J.R.R. Tolkien ] warg Suddenly Aragorn leapt to his feet. "How the wind howls!" he cried. "It is howling with wolf-voices. The Wargs have come west of the Mountains!" "Need we wait until morning then?" said Gandalf. "It is as I said. The hunt is up! Even if we live to see the dawn, who now will wish to journey south by night with the wild wolves on his trail?" "How far is Moria?" asked Boromir. "There was a door south-west of Caradhras, some fifteen miles as the crow flies, and maybe twenty as the wolf runs," answered Gandalf grimly. "Then let us start as soon as it is light tomorrow, if we can," said Boromir. "The wolf that one hears is worse than the orc that one fears." "True!" said Aragorn, loosening his sword in its sheath. "But where the warg howls, there also the orc prowls." [ The Fellowship of the Ring, by J.R.R. Tolkien ] ~mjollnir war*hammer They had come together at the ford of the Trident while the battle crashed around them, Robert with his warhammer and his great antlered helm, the Targaryen prince armored all in black. On his breastplate was the three-headed dragon of his House, wrought all in rubies that flashed like fire in the sunlight. The waters of the Trident ran red around the hooves of their destriers as they circled and clashed, again and again, until at last a crushing blow from Robert's hammer stove in the dragon and the chest behind it. When Ned had finally come on the scene, Rhaegar lay dead in the stream, while men of both armies scrambled in the swirling waters for rubies knocked free of his armor. [ A Game of Thrones, by George R.R. Martin ] water Day after day, day after day, We stuck, nor breath nor motion; As idle as a painted ship Upon a painted ocean. Water, water, everywhere, And all the boards did shrink; Water, water, everywhere Nor any drop to drink. [ The Rime of the Ancient Mariner, by Samuel Taylor Coleridge ] water demon [ The monkey king ] walked along the bank, around the pond. He examined the footprints of the animals that had gone into the water, and saw that none came out again! So he realized this pond must be possessed by a water demon. He said to the 80,000 monkeys, "This pond is possessed by a water demon. Do not let anybody go into it." After a little while, the water demon saw that none of the monkeys went into the water to drink. So he rose out of the middle of the pond, taking the shape of a frightening monster. He had a big blue belly, a white face with bulging green eyes, and red claws and feet. He said, "Why are you just sitting around? Come into the pond and drink at once!" The monkey king said to the horrible monster, "Are you the water demon who owns this pond?" "Yes, I am," said he. "Do you eat whoever goes into the water?" asked the king. "Yes, I do," he answered, "including even birds. I eat them all. And when you are forced by your thirst to come into the pond and drink, I will enjoy eating you, the biggest monkey, most of all!" He grinned, and saliva dripped down his hairy chin. [ Buddhist Tales for Young and Old, Vol. 1 ] weapon A weapon is a device for making your enemy change his mind. [ The Vor Game, by Lois McMaster Bujold ] web Oh what a tangled web we weave, When first we practise to deceive! [ Marmion, by Sir Walter Scott ] whistle There were legends both on the front and on the back of the whistle. The one read thus: FLA FUR BIS FLE The other: QUIS EST ISTE QUI VENIT 'I ought to be able to make it out,' he thought; 'but I suppose I am a little rusty in my Latin. When I come to think of it, I don't believe I even know the word for a whistle. The long one does seem simple enough. It ought to mean, "Who is this who is coming?" Well, the best way to find out is evidently to whistle for him.' [Ghost Stories of an Antiquary, by Montague Rhodes James 'Oh, Whistle, and I'll Come to You My Lad'] # werecritter -- see "lycanthrope" *wight When he came to himself again, for a moment he could recall nothing except a sense of dread. Then suddenly he knew that he was imprisoned, caught hopelessly; he was in a barrow. A Barrow-wight had taken him, and he was probably already under the dreadful spells of the Barrow-wights about which whispered tales spoke. He dared not move, but lay as he found himself: flat on his back upon a cold stone with his hands on his breast. [ The Fellowship of the Ring, by J.R.R. Tolkien ] # note: need to convert player character "gnomish wizard" into just "wizard" # in the lookup code to avoid conflict with the monster of that same name ~gnomish wizard wizard * wizard apprentice Ebenezum walked before me along the closest thing we could find to a path in these overgrown woods. Every few paces he would pause, so that I, burdened with a pack stuffed with arcane and heavy paraphernalia, could catch up with his wizardly strides. He, as usual, carried nothing, preferring, as he often said, to keep his hands free for quick conjuring and his mind free for the thoughts of a mage. [ A Dealing with Demons, by Craig Shaw Gardner ] wizard of yendor No one knows how old this mighty wizard is, or from whence he came. It is known that, having lived a span far greater than any normal man's, he grew weary of lesser mortals; and so, spurning all human company, he forsook the dwellings of men and went to live in the depths of the Earth. He took with him a dreadful artifact, the Book of the Dead, which is said to hold great power indeed. Many have sought to find the wizard and his treasure, but none have found him and lived to tell the tale. Woe be to the incautious adventurer who disturbs this mighty sorcerer! wolf *wolf *wolf cub The ancestors of the modern day domestic dog, wolves are powerful muscular animals with bushy tails. Intelligent, social animals, wolves live in family groups or packs made up of multiple family units. These packs cooperate in hunting down prey. *wolfsbane 1. Any of various, usually poisonous perennial herbs of the genus Aconitum, having tuberous roots, palmately lobed leaves, blue or white flowers with large hoodlike upper sepals, and an aggregate of follicles. 2. The dried leaves and roots of some of these plants, which yield a poisonous alkaloid that was formerly used medicinally. In both senses also called monkshood. [ The American Heritage Dictionary of the English Language, Fourth Edition. ] wood golem Come, old broomstick, you are needed, Take these rags and wrap them round you! Long my orders you have heeded, By my wishes now I've bound you. Have two legs and stand, And a head for you. Run, and in your hand Hold a bucket too. ... See him, toward the shore he's racing There, he's at the stream already, Back like lightning he is chasing, Pouring water fast and steady. Once again he hastens! How the water spills, How the water basins Brimming full he fills! [ The Sorcerer's Apprentice, by Johann Wolfgang von Goethe, translation by Edwin Zeydel ] woodchuck The Usenet Oracle requires an answer to this question! > How much wood could a woodchuck chuck if a woodchuck could > chuck wood? "Oh, heck! I'll handle *this* one!" The Oracle spun the terminal back toward himself, unlocked the ZOT-guard lock, and slid the glass guard away from the ZOT key. "Ummmm....could you turn around for a minute? ZOTs are too graphic for the uninitiated. Even *I* get a little squeamish sometimes..." The neophyte turned around, and heard the Oracle slam his finger on a computer key, followed by a loud ZZZZOTTTTT and the smell of ozone. [ Excerpted from Internet Oracularity 576.6 ] *worm long worm tail worm tooth crysknife [The crysknife] is manufactured in two forms from teeth taken from dead sandworms. The two forms are "fixed" and "unfixed". An unfixed knife requires proximity to a human body's electrical field to prevent disintegration. Fixed knives are treated for storage. All are about 20 centimeters long. [ Dune, by Frank Herbert ] wraith nazgul Immediately, though everything else remained as before, dim and dark, the shapes became terribly clear. He was able to see beneath their black wrappings. There were five tall figures: two standing on the lip of the dell, three advancing. In their white faces burned keen and merciless eyes; under their mantles were long grey robes; upon their grey hairs were helms of silver; in their haggard hands were swords of steel. Their eyes fell on him and pierced him, as they rushed towards him. Desperate, he drew his own sword, and it seemed to him that it flickered red, as if it was a firebrand. Two of the figures halted. The third was taller than the others: his hair was long and gleaming and on his helm was a crown. In one hand he held a long sword, and in the other a knife; both the knife and the hand that held it glowed with a pale light. He sprang forward and bore down on Frodo. [ The Fellowship of the Ring, by J.R.R. Tolkien ] *wumpus The Wumpus, by the way, is not bothered by the hazards since he has sucker feet and is too big for a bat to lift. If you try to shoot him and miss, there's also a chance that he'll up and move himself into another cave, though by nature the Wumpus is a sedentary creature. [ wump (6) -- "Hunt the Wumpus" ] _Wumpus yobgregorii_, in the flesh... Later, all you will be able to remember are its eyes. They are rich mud-brown, and they hold your own without effort. [ Hunter, In Darkness, by Andrew Plotkin ] xan They sent their friend the mosquito [xan] ahead of them to find out what lay ahead. "Since you are the one who sucks the blood of men walking along paths," they told the mosquito, "go and sting the men of Xibalba." The mosquito flew down the dark road to the Underworld. Entering the house of the Lords of Death, he stung the first person that he saw... The mosquito stung this man as well, and when he yelled, the man next to him asked, "Gathered Blood, what's wrong?" So he flew along the row stinging all the seated men until he knew the names of all twelve. [ Popul Vuh, as translated by Ralph Nelson ] xorn A distant cousin of the earth elemental, the xorn has the ability to shift the cells of its body around in such a way that it becomes porous to inert material. This gives it the ability to pass through any obstacle that might be between it and its next meal. ya The arrow of choice of the samurai, ya are made of very straight bamboo, and are tipped with hardened steel. yeenoghu Yeenoghu, the demon lord of gnolls, still exists although all his followers have been wiped off the face of the earth. He casts magic projectiles at those close to him, and a mere gaze into his piercing eyes may hopelessly confuse the battle-weary adventurer. yeti The Abominable Snowman, or yeti, is one of the truly great unknown animals of the twentieth century. It is a large hairy biped that lives in the Himalayan region of Asia ... The story of the Abominable Snowman is filled with mysteries great and small, and one of the most difficult of all is how it got that awful name. The creature is neither particularly abominable, nor does it necessarily live in the snows. _Yeti_ is a Tibetan word which may apply either to a real, but unknown animal of the Himalayas, or to a mountain spirit or demon -- no one is quite sure which. And after nearly half a century in which Westerners have trampled around looking for the yeti, and asking all sorts of questions, the original native traditions concerning the creature have become even more muddled and confused. [ The Encyclopedia of Monsters, by Daniel Cohen ] *yugake Japanese leather archery gloves. Gloves made for use while practicing had thumbs reinforced with horn. Those worn into battle had thumbs reinforced with a double layer of leather. yumi The samurai is highly trained with a special type of bow, the yumi. Like the ya, the yumi is made of bamboo. With the yumi-ya, the bow and arrow, the samurai is an extremely accurate and deadly warrior. *zombi* The zombi... is a soulless human corpse, still dead, but taken from the grave and endowed by sorcery with a mechanical semblance of life, -- it is a dead body which is made to walk and act and move as if it were alive. [ W. B. Seabrook ] zruty The zruty are wild and gigantic beings, living in the wildernesses of the Tatra mountains. nethack-3.6.0/dat/dungeon.def0000664000076400007660000001031512536476415015041 0ustar paxedpaxed# NetHack 3.6 dungeon.def $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) 1990-95 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The dungeon description file for the "standard" 3.1 NetHack. # # Note: The order of the definition of dungeons in this file # reflects in their order of creation in the real dungeon. # The "Main" branch must *always* be first. # Also note that the order of the dungeons in this file # determines the order in which branch levels are assigned. # If two dungeons have overlapping ranges for their entry # points, then you should list the dungeon with the _least_ # number of choices for its branch level _first_. # DUNGEON: "The Dungeons of Doom" "D" (25, 5) ALIGNMENT: unaligned BRANCH: "The Gnomish Mines" @ (2, 3) LEVEL: "rogue" "R" @ (15, 4) LEVELDESC: roguelike LEVEL: "oracle" "O" @ (5, 5) LEVALIGN: neutral CHAINBRANCH: "Sokoban" "oracle" + (1, 0) up RNDLEVEL: "bigrm" "B" @ (10, 3) 40 10 CHAINBRANCH: "The Quest" "oracle" + (6, 2) portal BRANCH: "Fort Ludios" @ (18, 4) portal RNDLEVEL: "medusa" "none" @ (-5, 4) 4 LEVALIGN: chaotic LEVEL: "castle" "none" @ (-1, 0) CHAINBRANCH: "Gehennom" "castle" + (0, 0) no_down BRANCH: "The Elemental Planes" @ (1, 0) no_down up # # Gehennom # # Now re-worked for 3.1, hell is hopefully going to be a little # less boring. Also, in 3.1, the tower is not considered as a # part of hell, but is set up as a separate dungeon. # # Gehennom is no longer considered "hellish" as a complete dungeon. # That is, fire resistance is no longer a condition for survival in # it. However, Gehennom, and the special levels in it in particular, # is abundant with fire traps. As a result, fire resistance is still # a prudent survival strategy in Gehennom. # # Note: Gehennom *must* be the second dungeon defined so that # monsters can properly migrate here under certain # circumstances. # DUNGEON: "Gehennom" "G" (20, 5) DESCRIPTION: mazelike DESCRIPTION: hellish ALIGNMENT: noalign BRANCH: "Vlad's Tower" @ (9, 5) up LEVEL: "valley" "V" @ (1, 0) LEVEL: "sanctum" "none" @ (-1, 0) LEVEL: "juiblex" "J" @ (4, 4) LEVEL: "baalz" "B" @ (6, 4) LEVEL: "asmodeus" "A" @ (2, 6) LEVEL: "wizard1" "none" @ (11, 6) CHAINLEVEL: "wizard2" "X" "wizard1" + (1, 0) CHAINLEVEL: "wizard3" "Y" "wizard1" + (2, 0) LEVEL: "orcus" "O" @ (10, 6) LEVEL: "fakewiz1" "F" @ (-6,4) LEVEL: "fakewiz2" "G" @ (-6,4) # # The Mines of the Gnomes of Zurich. # DUNGEON: "The Gnomish Mines" "M" (8, 2) ALIGNMENT: lawful DESCRIPTION: mazelike RNDLEVEL: "minetn" "T" @ (3, 2) 7 LEVELDESC: town RNDLEVEL: "minend" "E" @ (-1, 0) 3 # # The Questdungeon # # This is a proto-dungeon. The level file names will be prepended with # three letter role abbreviation during initialization, replacing "x". # A special "x-fill" level must be defined in the levels description # file. It will be used for all levels not defined explicitly below. # DUNGEON: "The Quest" "Q" (5, 2) LEVEL: "x-strt" "none" @ (1, 1) LEVEL: "x-loca" "L" @ (3, 1) LEVEL: "x-goal" "none" @ (-1, 0) # # Sokoban # DUNGEON: "Sokoban" "none" (4, 0) DESCRIPTION: mazelike ALIGNMENT: neutral ENTRY: -1 RNDLEVEL: "soko1" "none" @ (1, 0) 2 RNDLEVEL: "soko2" "none" @ (2, 0) 2 RNDLEVEL: "soko3" "none" @ (3, 0) 2 RNDLEVEL: "soko4" "none" @ (4, 0) 2 # # The Central Vault of Croesus. # DUNGEON: "Fort Ludios" "K" (1, 0) DESCRIPTION: mazelike ALIGNMENT: unaligned LEVEL: "knox" "K" @ (-1, 0) # # Vlad's Tower # # It has been removed from Gehennom, and it is surrounded by stone. # Must not allow bones files for its top level. # DUNGEON: "Vlad's Tower" "T" (3, 0) PROTOFILE: "tower" DESCRIPTION: mazelike ALIGNMENT: chaotic ENTRY: -1 LEVEL: "tower1" "none" @ (1, 0) # # The Endgame levels # # Enter on 2nd level from bottom; 1st (from bottom) is a # placeholder for surface level, and should be unreachable. # [Note: the name "dummy" is checked for in init_dungeons().] # DUNGEON: "The Elemental Planes" "E" (6, 0) DESCRIPTION: mazelike ALIGNMENT: unaligned ENTRY: -2 LEVEL: "astral" "none" @ (1, 0) LEVEL: "water" "none" @ (2, 0) LEVEL: "fire" "none" @ (3, 0) LEVEL: "air" "none" @ (4, 0) LEVEL: "earth" "none" @ (5, 0) LEVEL: "dummy" "none" @ (6, 0) nethack-3.6.0/dat/endgame.des0000664000076400007660000006235012536476415015025 0ustar paxedpaxed# NetHack 3.6 endgame.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, # and Timo Hakulinen # NetHack may be freely redistributed. See license for details. # # These are the ENDGAME levels: earth, air, fire, water, and astral. # The top-most level, the Astral Level, has 3 temples and shrines. # Players are supposed to sacrifice the Amulet of Yendor on the appropriate # shrine. MAZE:"earth",' ' FLAGS: noteleport,hardfloor,shortsighted MESSAGE: "Well done, mortal!" MESSAGE: "But now thou must face the final Test..." MESSAGE: "Prove thyself worthy or perish!" GEOMETRY:center,center # The player lands, upon arrival, in the # lower-right cavern. The location of the # portal to the next level is randomly chosen. # This map has no visible outer boundary, and # is mostly diggable "rock". MAP ... .... .. ..... ... .. .... .... ... .... ... .... ... . .. .. ....... . .. .. ... . . .. . ... .. .. . .. . .. ... . ... ... .. ... .. .... .. .. ... .. ..... ... ... .... .. ENDMAP REPLACE_TERRAIN:(0,0,75,19), ' ', ('.', unlit), 5% # Since there are no stairs, this forces the hero's initial placement TELEPORT_REGION:(69,16,69,16),(0,0,0,0) PORTAL:(0,0,75,19),(65,13,75,19),"air" # Some helpful monsters. Making sure a # pick axe and at least one wand of digging # are available. MONSTER:('@',"Elvenking"),(67,16) MONSTER:('H',"minotaur"),(67,14) # An assortment of earth-appropriate nasties # in each cavern. MONSTER:('E',"earth elemental"),(52,13),hostile MONSTER:('E',"earth elemental"),(53,13),hostile MONSTER:('T',"rock troll"),(53,12) MONSTER:('H',"stone giant"),(54,12) # MONSTER:('S',"pit viper"),(70,05) MONSTER:('&',"barbed devil"),(69,06) MONSTER:('H',"stone giant"),(69,08) MONSTER:(''',"stone golem"),(71,08) MONSTER:('&',"pit fiend"),(70,09) MONSTER:('E',"earth elemental"),(70,08),hostile # MONSTER:('E',"earth elemental"),(60,03),hostile MONSTER:('H',"stone giant"),(61,04) MONSTER:('E',"earth elemental"),(62,04),hostile MONSTER:('E',"earth elemental"),(61,05),hostile MONSTER:('s',"scorpion"),(62,05) MONSTER:('p',"rock piercer"),(63,05) # MONSTER:('U',"umber hulk"),(40,05) MONSTER:('v',"dust vortex"),(42,05) MONSTER:('T',"rock troll"),(38,06) MONSTER:('E',"earth elemental"),(39,06),hostile MONSTER:('E',"earth elemental"),(41,06),hostile MONSTER:('E',"earth elemental"),(38,07),hostile MONSTER:('H',"stone giant"),(39,07) MONSTER:('E',"earth elemental"),(43,07),hostile MONSTER:(''',"stone golem"),(37,08) MONSTER:('S',"pit viper"),(43,08) MONSTER:('S',"pit viper"),(43,09) MONSTER:('T',"rock troll"),(44,10) # MONSTER:('E',"earth elemental"),(02,01),hostile MONSTER:('E',"earth elemental"),(03,01),hostile MONSTER:(''',"stone golem"),(01,02) MONSTER:('E',"earth elemental"),(02,02),hostile MONSTER:('T',"rock troll"),(04,03) MONSTER:('T',"rock troll"),(03,03) MONSTER:('&',"pit fiend"),(03,04) MONSTER:('E',"earth elemental"),(04,05),hostile MONSTER:('S',"pit viper"),(05,06) # MONSTER:('E',"earth elemental"),(21,02),hostile MONSTER:('E',"earth elemental"),(21,03),hostile MONSTER:('H',"minotaur"),(21,04) MONSTER:('E',"earth elemental"),(21,05),hostile MONSTER:('T',"rock troll"),(22,05) MONSTER:('E',"earth elemental"),(22,06),hostile MONSTER:('E',"earth elemental"),(23,06),hostile # MONSTER:('S',"pit viper"),(14,08) MONSTER:('&',"barbed devil"),(14,09) MONSTER:('E',"earth elemental"),(13,10),hostile MONSTER:('T',"rock troll"),(12,11) MONSTER:('E',"earth elemental"),(14,12),hostile MONSTER:('E',"earth elemental"),(15,13),hostile MONSTER:('H',"stone giant"),(17,13) MONSTER:(''',"stone golem"),(18,13) MONSTER:('&',"pit fiend"),(18,12) MONSTER:('E',"earth elemental"),(18,11),hostile MONSTER:('E',"earth elemental"),(18,10),hostile # MONSTER:('&',"barbed devil"),(02,16) MONSTER:('E',"earth elemental"),(03,16),hostile MONSTER:('T',"rock troll"),(02,17) MONSTER:('E',"earth elemental"),(04,17),hostile MONSTER:('E',"earth elemental"),(04,18),hostile OBJECT:('`',"boulder"),random MAZE:"air",' ' FLAGS: noteleport,hardfloor,shortsighted # The following messages are somewhat obtuse, to make then # equally meaningful if the player can see or not. MESSAGE: "What a strange feeling!" MESSAGE: "You notice that there is no gravity here." GEOMETRY:center,center # The player lands, upon arrival, in the # lower-left area. The location of the # portal to the next level is randomly chosen. # This map has no visible outer boundary, and # is all "air". MAP AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ENDMAP # Use up and down regions to partition the level into three parts; # teleportation can't cross from one part into another. # The up region is where you'll arrive after activating the portal from # the preceding level; the exit portal is placed inside the down region. TELEPORT_REGION:levregion(01,00,24,20),levregion(25,00,79,20),up TELEPORT_REGION:levregion(56,00,79,20),levregion(01,00,55,20),down PORTAL:levregion(57,01,78,19),(0,0,0,0),"fire" REGION:(00,00,75,19),lit,"ordinary" MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('E',"air elemental"),random,hostile MONSTER:('e',"floating eye"),random,hostile MONSTER:('e',"floating eye"),random,hostile MONSTER:('e',"floating eye"),random,hostile MONSTER:('y',"yellow light"),random,hostile MONSTER:('y',"yellow light"),random,hostile MONSTER:('y',"yellow light"),random,hostile MONSTER:('A',"couatl"),random MONSTER:'D',random MONSTER:'D',random MONSTER:'D',random MONSTER:'D',random MONSTER:'D',random MONSTER:'E',random MONSTER:'E',random MONSTER:'E',random MONSTER:'J',random MONSTER:'J',random MONSTER:('&',"djinni"),random,hostile MONSTER:('&',"djinni"),random,hostile MONSTER:('&',"djinni"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"fog cloud"),random,hostile MONSTER:('v',"energy vortex"),random,hostile MONSTER:('v',"energy vortex"),random,hostile MONSTER:('v',"energy vortex"),random,hostile MONSTER:('v',"energy vortex"),random,hostile MONSTER:('v',"energy vortex"),random,hostile MONSTER:('v',"steam vortex"),random,hostile MONSTER:('v',"steam vortex"),random,hostile MONSTER:('v',"steam vortex"),random,hostile MONSTER:('v',"steam vortex"),random,hostile MONSTER:('v',"steam vortex"),random,hostile MAZE:"fire",' ' FLAGS: noteleport,hardfloor,shortsighted GEOMETRY:center,center # The player lands, upon arrival, in the # lower-right. The location of the # portal to the next level is randomly chosen. # This map has no visible outer boundary, and # is mostly open area, with lava lakes and bunches of fire traps. MAP ............................................................................ ....LLLLLLLL............L.......................LLL......................... ...LL...................L......................LLLL................LL....... ...L.............LLLL...LL....LL...............LLLLL.............LLL........ .LLLL..............LL....L.....LLL..............LLLL..............LLLL...... ..........LLLL...LLLL...LLL....LLL......L........LLLL....LL........LLL...... ........LLLLLLL...LL.....L......L......LL.........LL......LL........LL...L.. ........LL..LLL..LL......LL......LLLL..L.........LL......LLL............LL.. ....L..LL....LLLLL.................LLLLLLL.......L......LL............LLLLLL ....L..L.....LL.LLLL.......L............L........LLLLL.LL......LL.........LL ....LL........L...LL......LL.............LLL.....L...LLL.......LLL.........L .....LLLLLL........L.......LLL.............L....LL...L.LLL......LLLLLLL..... ..........LLLL............LL.L.............L....L...LL.........LLL..LLL..... ...........................LLLLL...........LL...L...L........LLLL..LLLLLL... .....LLLL.............LL....LL.......LLL...LL.......L..LLL....LLLLLLL....... .......LLL.........LLLLLLLLLLL......LLLLL...L...........LL...LL...LL........ .........LL.......LL.........LL.......LLL....L..LLL....LL.........LL........ ..........LLLLLLLLL...........LL....LLL.......LLLLL.....LL........LL........ .................L.............LLLLLL............LL...LLLL.........LL....... .................................LL....................LL................... ENDMAP TELEPORT_REGION:(69,16,69,16),(0,0,0,0) PORTAL:(0,0,75,19),(65,13,75,19),"water" TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random # An assortment of fire-appropriate nasties MONSTER:('D',"red dragon"),random MONSTER:('&',"balrog"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile MONSTER:('v',"fire vortex"),random MONSTER:('d',"hell hound"),random # MONSTER:('H',"fire giant"),random MONSTER:('&',"barbed devil"),random MONSTER:('d',"hell hound"),random MONSTER:(''',"stone golem"),random MONSTER:('&',"pit fiend"),random MONSTER:('E',"fire elemental"),random,hostile # MONSTER:('E',"fire elemental"),random,hostile MONSTER:('d',"hell hound"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile MONSTER:('s',"scorpion"),random MONSTER:('H',"fire giant"),random # MONSTER:('d',"hell hound"),random MONSTER:('v',"dust vortex"),random MONSTER:('v',"fire vortex"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile MONSTER:('d',"hell hound"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:(''',"stone golem"),random MONSTER:('S',"pit viper"),random MONSTER:('S',"pit viper"),random MONSTER:('v',"fire vortex"),random # MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile MONSTER:('H',"fire giant"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('v',"fire vortex"),random MONSTER:('v',"fire vortex"),random MONSTER:('&',"pit fiend"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('S',"pit viper"),random # MONSTER:(':',"salamander"),random,hostile MONSTER:(':',"salamander"),random,hostile MONSTER:('H',"minotaur"),random MONSTER:(':',"salamander"),random,hostile MONSTER:('v',"steam vortex"),random MONSTER:(':',"salamander"),random,hostile MONSTER:(':',"salamander"),random,hostile # MONSTER:('H',"fire giant"),random MONSTER:('&',"barbed devil"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('v',"fire vortex"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile MONSTER:('d',"hell hound"),random MONSTER:('H',"fire giant"),random MONSTER:('&',"pit fiend"),random MONSTER:('E',"fire elemental"),random,hostile MONSTER:('E',"fire elemental"),random,hostile # MONSTER:('&',"barbed devil"),random MONSTER:(':',"salamander"),random,hostile MONSTER:('v',"steam vortex"),random MONSTER:(':',"salamander"),random,hostile MONSTER:(':',"salamander"),random,hostile OBJECT:('`',"boulder"),random OBJECT:('`',"boulder"),random OBJECT:('`',"boulder"),random OBJECT:('`',"boulder"),random OBJECT:('`',"boulder"),random MAZE:"water",' ' FLAGS: noteleport,hardfloor,shortsighted MESSAGE: "You find yourself suspended in an air bubble surrounded by water." GEOMETRY:center,center # The player lands upon arrival to an air bubble # within the leftmost third of the level. The # portal to the next level is randomly located in an air # bubble within the rightmost third of the level. # Bubbles are generated by special code in mkmaze.c for now. MAP WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ENDMAP TELEPORT_REGION:(0,0,25,19),(0,0,0,0) PORTAL:(51,0,75,19),(0,0,0,0),"astral" # A fisherman's dream... MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"electric eel"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"kraken"),random MONSTER:(';',"shark"),random MONSTER:(';',"shark"),random MONSTER:(';',"shark"),random MONSTER:(';',"shark"),random MONSTER:(';',"piranha"),random MONSTER:(';',"piranha"),random MONSTER:(';',"piranha"),random MONSTER:(';',"piranha"),random MONSTER:(';',"jellyfish"),random MONSTER:(';',"jellyfish"),random MONSTER:(';',"jellyfish"),random MONSTER:(';',"jellyfish"),random MONSTER:';',random MONSTER:';',random MONSTER:';',random MONSTER:';',random # These guys feel like home here MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MONSTER:('E',"water elemental"),random,hostile MAZE:"astral",' ' FLAGS: noteleport,hardfloor,nommap,shortsighted,solidify MESSAGE: "You arrive on the Astral Plane!" MESSAGE: "Here the High Temple of %d is located." MESSAGE: "You sense alarm, hostility, and excitement in the air!" GEOMETRY:center,center MAP --------------- |.............| |..---------..| |..|.......|..| --------------- |..|.......|..| --------------- |.............| |..|.......|..| |.............| |..---------..-| |-------| |..|.......|..| |-------| |-..---------..| |..|.......|...-| |-.......-| |..|.......|..| |-.......-| |-...|.......|..| |..|.......|....-|-.........-||..----+----..||-.........-|-....|.......|..| |..|.......+.....+...........||.............||...........+.....+.......|..| |..|.......|....-|-.........-|--|.........|--|-.........-|-....|.......|..| |..|.......|...-| |-.......-| -|---+---|- |-.......-| |-...|.......|..| |..---------..-| |---+---| |-.......-| |---+---| |-..---------..| |.............| |...|-----|-.........-|-----|...| |.............| --------------- |.........|...........|.........| --------------- -------...|-.........-|...------- |....|-.......-|....| ---...|---+---|...--- |...............| ----------------- ENDMAP IF [75%] { TERRAIN:fillrect (17,14, 30,18),'.' TERRAIN:fillrect (44,14, 57,18),'.' WALLIFY $hall = selection:floodfill(37,18) LOOP [6 + 3d4] { MONSTER:('A',"Angel"),rndcoord($hall),noalign,hostile [50%]: MONSTER:random,rndcoord($hall),hostile } } # Rider locations $place = { (23,9),(37,14),(51,9) } SHUFFLE: $place # Where the player will land on arrival TELEPORT_REGION:(29,15,45,15),(30,15,44,15) # Lit courts REGION:(01,05,16,14),lit,"ordinary",filled,irregular REGION:(31,01,44,10),lit,"ordinary",filled,irregular REGION:(61,05,74,14),lit,"ordinary",filled,irregular # A Sanctum for each alignment # The shrines' alignments are shuffled for # each game REGION:(04,07,10,11),lit,"temple" REGION:(34,03,40,07),lit,"temple" REGION:(64,07,70,11),lit,"temple" ALTAR:(07,09),align[0],sanctum ALTAR:(37,05),align[1],sanctum ALTAR:(67,09),align[2],sanctum # Doors DOOR:closed,(11,09) DOOR:closed,(17,09) DOOR:locked,(23,12) DOOR:locked,(37,08) DOOR:closed,(37,11) DOOR:closed,(37,17) DOOR:locked,(51,12) DOOR:locked,(57,09) DOOR:closed,(63,09) # Non diggable and phazeable everywhere NON_DIGGABLE:(00,00,74,19) NON_PASSWALL:(00,00,74,19) # Moloch's horde # West round room MONSTER:('@',"aligned priest"),(18,09),noalign,hostile MONSTER:('@',"aligned priest"),(19,08),noalign,hostile MONSTER:('@',"aligned priest"),(19,09),noalign,hostile MONSTER:('@',"aligned priest"),(19,10),noalign,hostile MONSTER:('A',"Angel"),(20,09),noalign,hostile MONSTER:('A',"Angel"),(20,10),noalign,hostile MONSTER:('&',"Pestilence"),$place[0],hostile # South-central round room MONSTER:('@',"aligned priest"),(36,12),noalign,hostile MONSTER:('@',"aligned priest"),(37,12),noalign,hostile MONSTER:('@',"aligned priest"),(38,12),noalign,hostile MONSTER:('@',"aligned priest"),(36,13),noalign,hostile MONSTER:('A',"Angel"),(38,13),noalign,hostile MONSTER:('A',"Angel"),(37,13),noalign,hostile MONSTER:('&',"Death"),$place[1],hostile # East round room MONSTER:('@',"aligned priest"),(56,09),noalign,hostile MONSTER:('@',"aligned priest"),(55,08),noalign,hostile MONSTER:('@',"aligned priest"),(55,09),noalign,hostile MONSTER:('@',"aligned priest"),(55,10),noalign,hostile MONSTER:('A',"Angel"),(54,09),noalign,hostile MONSTER:('A',"Angel"),(54,10),noalign,hostile MONSTER:('&',"Famine"),$place[2],hostile # # The aligned horde # # We do not know in advance the alignment of the # player. The mpeaceful bit will need resetting # when the level is created. The setting here is # but a place holder. # # West court MONSTER:('@',"aligned priest"),(12,07),chaos,hostile MONSTER:('@',"aligned priest"),(13,07),chaos,peaceful MONSTER:('@',"aligned priest"),(14,07),law,hostile MONSTER:('@',"aligned priest"),(12,11),law,peaceful MONSTER:('@',"aligned priest"),(13,11),neutral,hostile MONSTER:('@',"aligned priest"),(14,11),neutral,peaceful MONSTER:('A',"Angel"),(11,05),chaos,hostile MONSTER:('A',"Angel"),(12,05),chaos,peaceful MONSTER:('A',"Angel"),(13,05),law,hostile MONSTER:('A',"Angel"),(11,13),law,peaceful MONSTER:('A',"Angel"),(12,13),neutral,hostile MONSTER:('A',"Angel"),(13,13),neutral,peaceful # Central court MONSTER:('@',"aligned priest"),(32,09),chaos,hostile MONSTER:('@',"aligned priest"),(33,09),chaos,peaceful MONSTER:('@',"aligned priest"),(34,09),law,hostile MONSTER:('@',"aligned priest"),(40,09),law,peaceful MONSTER:('@',"aligned priest"),(41,09),neutral,hostile MONSTER:('@',"aligned priest"),(42,09),neutral,peaceful MONSTER:('A',"Angel"),(31,08),chaos,hostile MONSTER:('A',"Angel"),(32,08),chaos,peaceful MONSTER:('A',"Angel"),(31,09),law,hostile MONSTER:('A',"Angel"),(42,08),law,peaceful MONSTER:('A',"Angel"),(43,08),neutral,hostile MONSTER:('A',"Angel"),(43,09),neutral,peaceful # East court MONSTER:('@',"aligned priest"),(60,07),chaos,hostile MONSTER:('@',"aligned priest"),(61,07),chaos,peaceful MONSTER:('@',"aligned priest"),(62,07),law,hostile MONSTER:('@',"aligned priest"),(60,11),law,peaceful MONSTER:('@',"aligned priest"),(61,11),neutral,hostile MONSTER:('@',"aligned priest"),(62,11),neutral,peaceful MONSTER:('A',"Angel"),(61,05),chaos,hostile MONSTER:('A',"Angel"),(62,05),chaos,peaceful MONSTER:('A',"Angel"),(63,05),law,hostile MONSTER:('A',"Angel"),(61,13),law,peaceful MONSTER:('A',"Angel"),(62,13),neutral,hostile MONSTER:('A',"Angel"),(63,13),neutral,peaceful # # Assorted nasties MONSTER:'L',random,hostile MONSTER:'L',random,hostile MONSTER:'L',random,hostile MONSTER:'V',random,hostile MONSTER:'V',random,hostile MONSTER:'V',random,hostile MONSTER:'D',random,hostile MONSTER:'D',random,hostile MONSTER:'D',random,hostile nethack-3.6.0/dat/engrave.txt0000664000076400007660000000326712615363064015113 0ustar paxedpaxed# Random engravings on the floor # Elbereth # trap engravings Vlad was here ad aerarium # take-offs and other famous engravings Owlbreath Galadriel Kilroy was here # Journey to the Center of the Earth A.S. -> <- A.S. # Adventure You won't get it up the steps # Inferno Lasciate ogni speranza o voi ch'entrate. # Prisoner Well Come # So Long... We apologize for the inconvenience. # Thriller See you next Wednesday # Smokey Stover notary sojak For a good time call 8?7-5309 # Various zoos around the world Please don't feed the animals. # A palindrome Madam, in Eden, I'm Adam. # Siskel & Ebert Two thumbs up! # The First C Program Hello, World! ^?MAIL # AOL You've got mail! ^. # Clueless As if! # 200x incarnation of Dr.Who BAD WOLF # Gang tag Arooo! Werewolves of Yendor! # Strategy and pun Dig for Victory here # Pompeii Gaius Julius Primigenius was here. Why are you late? # Helpful guiding Don't go this way Go left ---> <--- Go right X marks the spot X <--- You are here. Here be dragons Save now, and do your homework! There was a hole here. It's gone now. The Vibrating Square This is a pit! This is not the dungeon you are looking for. Watch out, there's a gnome with a wand of death behind that door! # Misc fun This square deliberately left blank. # Viking graffiti Haermund Hardaxe carved these runes # Advertising Need a light? Come visit the Minetown branch of Izchak's Lighting Store! Snakes on the Astral Plane - Soon in a dungeon near you You are the one millionth visitor to this place! Please wait 200 turns for your wand of wishing. # DnD Warning, Exploding runes! # "Whispers Underground" Ben Aaronovitch If you can read these words then you are not only a nerd but probably dead. nethack-3.6.0/dat/epitaph.txt0000664000076400007660000003342412545422255015114 0ustar paxedpaxed# Epitaphs for random headstones # # Rest in peace R.I.P. Rest In Pieces Note -- there are NO valuable items in this grave 1994-1995. The Longest-Lived Hacker Ever The Grave of the Unknown Hacker We weren't sure who this was, but we buried him here anyway Sparky -- he was a very good dog Beware of Electric Third Rail Made in Taiwan Og friend. Og good dude. Og died. Og now food. Beetlejuice Beetlejuice Beetlejuice Look out below! Please don't dig me up. I'm perfectly happy down here. -- Resident Postman, please note forwarding address: Gehennom, Asmodeus's Fortress, fifth lemure on the left Mary had a little lamb/Its fleece was white as snow/When Mary was in trouble/The lamb was first to go Be careful, or this could happen to you! Soon you'll join this fellow in hell! -- the Wizard of Yendor Caution! This grave contains toxic waste Sum quod eris Here lies an Atheist, all dressed up and no place to go Here lies Ezekiel, age 102. The good die young. Here lies my wife: Here let her lie! Now she's at rest and so am I. Here lies Johnny Yeast. Pardon me for not rising. He always lied while on the earth and now he's lying in it I made an ash of myself Soon ripe. Soon rotten. Soon gone. But not forgotten. Here lies the body of Jonathan Blake. Stepped on the gas instead of the brake. Go away! Alas fair Death, 'twas missed in life - some peace and quiet from my wife Applaud, my friends, the comedy is finished. At last... a nice long sleep. Audi Partem Alteram Basil, assaulted by bears Burninated Confusion will be my epitaph Do not open until Christmas Don't be daft, they couldn't hit an elephant at this dist- Don't forget to stop and smell the roses Don't let this happen to you! Dulce et decorum est pro patria mori Et in Arcadia ego Fatty and skinny went to bed. Fatty rolled over and skinny was dead. Skinny Smith 1983-2000. Finally I am becoming stupider no more Follow me to hell ...for famous men have the whole earth as their memorial Game over, man. Game over. Go away! I'm trying to take a nap in here! Bloody adventurers... Gone fishin' Good night, sweet prince: And flights of angels sing thee to thy rest! Go Team Ant! He farmed his way here Here lies a programmer. Killed by a fatal error. Here lies Bob - decided to try an acid blob Here lies Dudley, killed by another %&#@#& newt. Here lies Gregg, choked on an egg Here lies Lies. It's True. Here lies The Lady's maid, died of a Vorpal Blade Here lies the left foot of Jack, killed by a land mine. Let us know if you find any more of him He waited too long I'd rather be sailing If a man's deeds do not outlive him, of what value is a mark in stone? I'm gonna make it! I took both pills! I will survive! Killed by a black dragon -- This grave is empty Let me out of here! Lookin' good, Medusa. Mrs. Smith, choked on an apple. She left behind grieving husband, daughter, and granddaughter. Nobody believed her when she said her feet were killing her No! I don't want to see my damn conduct! One corpse, sans head On the whole, I'd rather be in Minetown On vacation Oops. Out to Lunch SOLD Someone set us up the bomb! Take my stuff, I don't need it anymore Taking a year dead for tax reasons The reports of my demise are completely accurate (This space for sale) This was actually just a pit, but since there was a corpse, we filled it This way to the crypt Tu quoque, Brute? VACANCY Welcome! Wish you were here! Yea, it got me too You should see the other guy ...and they made me engrave my own headstone too! ...but the blood has stopped pumping and I am left to decay... A masochist is never satisfied. Ach, 'twas a wee monster in the loch Adapt. Enjoy. Survive. Adventure, hah! Excitement, hah! After all, what are friends for... After this, nothing will shock me After three days, fish and guests stink Age and treachery will always overcome youth and skill Ageing is not so bad. The real killer is when you stop. Ain't I a stinker? Algernon All else failed... All hail RNG All right, we'll call it a draw! All's well that end well Alone at last! Always attack a floating eye from behind! Am I having fun yet? And I can still crawl, I'm not dead yet! And all I wanted was a free lunch And all of the signs were right there on your face And don't give me that innocent look either! And everyone died. Boo hoo hoo. And here I go again... And nobody cares until somebody famous dies... And so it ends? And so... it begins. And sometimes the bear eats you. And then 'e nailed me 'ead to the floor! And they said it couldn't be done! And what do I look like? The living? And yes, it was ALL his fault! And you said it was pretty here... Another lost soul Any day above ground is a good day! Any more of this and I'll die of a stroke before I'm 30. Anybody seen my head? Anyone for deathmatch? Anything for a change. Anything that kills you makes you ... well, dead Anything worth doing is worth overdoing. Are unicorns supposedly peaceful if you're a virgin? Hah! Are we all being disintegrated, or is it just me? At least I'm good at something Attempted suicide Auri sacra fames Auribus teneo lupum Be prepared Beauty survives Been Here. Now Gone. Had a Good Time. Been through Hell, eh? What did you bring me? Beg your pardon, didn't recognize you, I've changed a lot. Being dead builds character Beloved daughter, a treasure, buried here. Best friends come and go.... Mine just die. Better be dead than a fat slave Better luck next time Beware of Discordians bearing answers Beware the ... Bloody Hell... Bloody barbarians! Blown upward out of sight: He sought the leak by candlelight Brains... Brains... Fresh human brains... Buried the cat. Took an hour. Damn thing kept fighting. But I disarmed the trap! CONNECT 1964 - NO CARRIER 1994 Call me if you need my phone number! Can YOU fly? Can you believe that thing is STILL moving? Can you come up with some better ending for this? Can you feel anything when I do this? Can you give me mouth to mouth, you just took my breath away. Can't I just have a LITTLE peril? Can't eat, can't sleep, had to bury the husband here. Can't you hit me?! Chaos, panic and disorder. My work here is done. Check enclosed. Check this out! It's my brain! Chivalry is only reasonably dead Coffin for sale. Lifetime guarantee. Come Monday, I'll be all right. Come and see the violence inherent in the system Come back here! I'll bite your bloody knees off! Commodore Business Machines, Inc. Died for our sins. Complain to one who can help you Confess my sins to god? Which one? Confusion will be my epitaph Cooties? Ain't no cooties on me! Could somebody get this noose off me? Could you check again? My name MUST be there. Could you please take a breath mint? Couldn't I be sedated for this? Courage is looking at your setbacks with serenity Cover me, I'm going in! Crash course in brain surgery Cross my fingers for me. Curse god and die Cut to fit De'Ath Dead Again? Pardon me for not getting it right the first time! Dead and loving every moment! Dear wife of mine. Died of a broken heart, after I took it out of her. Don't tread on me! Dragon? What dragon? Drawn and quartered Either I'm dead or my watch has stopped. Eliza -- Was I really alive, or did I just think I was? Elvis Enter not into the path of the wicked Eris? I don't need Eris Eternal Damnation, Come and stay a long while! Even The Dead pay taxes (and they aren't Grateful). Even a tomb stone will say good things when you're down! Ever notice that live is evil backwards? Every day is starting to look like Monday Every day, in every way, I am getting better and better. Every survival kit should include a sense of humor Evil I did dwell; lewd did I live Ex post fucto Excellent day to have a rotten day. Excuse me for not standing up. Experience isn't everything. First, you've got to survive. First shalt thou pull out the Holy Pin For a Breath, I Tarry... For recreational use only. For sale: One soul, slightly used. Asking for 3 wishes. For some moments in life, there are no words. Forget Disney World, I'm going to Hell! Forget about the dog, Beware of my wife. Funeral - Real fun. Gawd, it's depressing in here, isn't it? Genuine Exploding Gravestone. (c)Acme Gravestones Inc. Get back here! I'm not finished yet... Go ahead, I dare you to! Go ahead, it's either you or him. Goldilocks -- This casket is just right Gone But Not Forgotten Gone Underground For Good Gone away owin' more than he could pay. Gone, but not forgiven Got a life. Didn't know what to do with it. Grave? But I was cremated! Greetings from Hell - Wish you were here. HELP! It's dark in here.... Oh, my eyes are closed - sorry Ha! I NEVER pay income tax! Have you come to raise the dead? Having a good time can be deadly. Having a great time. Where am I exactly?? He died of the flux. He died today.... May we rest in peace! He got the upside, I got the downside. He lost his face when he was beheaded. He missed me first. He's not dead, he just smells that way. Help! I've fallen and I can't get up! Help, I can't wake up! Here lies Pinocchio Here lies the body of John Round. Lost at sea and never found. Here there be dragons Hey, I didn't write this stuff! Hodie mihi, cras tibi Hold my calls Home Sweet Hell Humpty Dumpty, a Bad Egg. He was pushed off the wall. I KNEW this would happen if I lived long enough. I TOLD you I was sick! I ain't broke but I am badly bent. I ain't old. I'm chronologically advantaged. I am NOT a vampire. I just like to bite..nibble, really! I am here. Wish you were fine. I am not dead yet, but watch for further reports. I believe them bones are me. I broke his brain. I can feel it. My mind. It's going. I can feel it. I can't go to Hell. They're afraid I'm gonna take over! I can't go to hell, they don't want me. I didn't believe in reincarnation the last time, either. I didn't mean it when I said 'Bite me' I died laughing I disbelieved in reincarnation in my last life, too. I hacked myself to death I have all the time in the world I knew I'd find a use for this gravestone! I know my mind. And it's around here someplace. I lied! I'll never be alright! I like it better in the dark. I like to be here when I can. I may rise but I refuse to shine. I never get any either. I said hit HIM with the fireball, not me! I told you I would never say goodbye. I used to be amusing. Now I'm just disgusting. I used up all my sick days, so now I'm calling in dead. I was killed by I was somebody. Who, is no business of yours. I will not go quietly. I'd give you a piece of my mind... but I can't find it. I'd rather be breathing I'll be back! I'll be mellow when I'm dead. For now, let's PARTY! I'm doing this only for tax purposes. I'm not afraid of Death! What's he gonna do? Kill me? I'm not getting enough money, so I'm not going to engrave anything useful here. I'm not saying anything. I'm weeth stupeed ---> If you thought you had problems... Ignorance kills daily. Ignore me... I'm just here for my looks! Ilene Toofar -- Fell off a cliff Is that all? Is there life before Death? Is this a joke, or a grave matter? It happens sometimes. People just explode. It must be Thursday. I never could get the hang of Thursdays. It wasn't a fair fight It wasn't so easy. It's Loot, Pillage and THEN Burn... Just doing my job here Killed by diarrhea of mouth and constipation of brain. Let her RIP Let it be; I am dead. Let's play Hide the Corpse Life is NOT a dream Madge Ination -- It wasn't all in my head Meet me in Heaven Move on, there's nothing to see here. Mr. Flintstone -- Yabba-dabba-done My heart is not in this No one ever died from it No, you want room 12A, next door. Nope. No trap on that chest. I swear. Not again! Not every soil can bear all things Now I have a life Now I lay thee down to sleep... wanna join me? OK, here is a question: Where ARE your tanlines? Obesa Cantavit Oh! An untimely death. Oh, by the way, how was my funeral? "Oh, honey... I missed you!" she said, and fired again. Ok, so the light does go off. Now let me out of here. One stone brain Ooh! Somebody STOP me! Oops! Out for the night. Leave a message. Ow! Do that again! Pardon my dust. Part of me still works. Please, not in front of those orcs! Prepare to meet me in Heaven R2D2 -- Rest, Tin Piece Relax. Nothing ever happens on the first level. Res omnia mea culpa est Rest In Pieces Rest, rest, perturbed spirit. Rip Torn She always said her feet were killing her but nobody believed her. She died of a chest cold. So let it be written, so let it be done! So then I says, How do I know you're the real angel of death? Some patients insist on dying. Some people have it dead easy, don't they? Some things are better left buried. Sure, trust me, I'm a lawyer... Thank God I wore my corset, because I think my sides have split. That is all The Gods DO have a sense of humor: I'm living proof! The frog's dead. He Kermitted suicide. This dungeon is a pushover This elevator doesn't go to Heaven This gravestone is shareware. To register, please send me 10 zorkmids This gravestone provided by The Yendorian Grave Services Inc. This is not an important part of my life. This one's on me. This side up Tim Burr -- Smashed by a tree Tone it down a bit, I'm trying to get some rest here. Virtually Alive We Will Meet Again. Weep not, he is at rest Welcome to Dante's. What level please? Well, at least they listened to my sermon... Went to be an angel. What are you doing over there? What are you smiling at? What can you say, Death's got appeal...! What health care? What pit? When the gods want to punish you, they answer your prayers. Where e'er you be let your wind go free. Keeping it in was the death of me! Where's my refund? Will let you know for sure in a day or two... Wizards are wimps Worms at work, do not disturb! Would you mind moving a bit? I'm short of breath down here. Would you quit being evil over my shoulder? Ya really had me going baby, but now I'm gone. Yes Dear, just a few more minutes... You said it wasn't poisonous! You set my heart aflame. You gave me heartburn. nethack-3.6.0/dat/gehennom.des0000664000076400007660000005056012536476415015225 0ustar paxedpaxed# NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992 by M. Stephenson and Izchak Miller # NetHack may be freely redistributed. See license for details. # MAZE: "valley", ' ' FLAGS: noteleport,hardfloor,nommap GEOMETRY:center,center MAP ---------------------------------------------------------------------------- |...S.|..|.....| |.....-| |................| |...............| |...| |---|.|.--.---.| |......--- ----..........-----.-----....---........---.-.| | |.|.|..| |.| --........| |.............| |.......---| |-...........--| | |...S..| |.| |.......-----.......------| |--------..---......------- | |----------- |.| |-......| |....|...-- |...-----................---- | |.....S....---.| |.......| |....|...| |..............----------- | |.....|.|......| |.....--- |......--- |....---.......| | |.....|.|------| |....-- --....-- |-------- ----....--------------- | |.....|--......---BBB-| |...-- |.......| |..................| | |..........||........-| --...| |.......| |...||.............| | |.....|...-||-........------....| |.......---- |...||.............-- | |.....|--......---...........--------..........| |.......---------...-- | |.....| |------| |--.......--| |..B......----- -----....| |.| |....--- | |.....| |......--| ------..| |----..B......| |.--------.-- |-.....---| |------ |........| |.|....| |.....----BBBB---------...........---.........| | |........| |...|..| |.....| |-.............--------...........---| | --.....-----------.| |....-----.....---------- |.........---- | | |..|..B...........| |.|..........|.| |.|........| | ---------------------------------------------------------------------------- ENDMAP # Make the path somewhat unpredictable # If you get "lucky", you may have to go through all three graveyards. IF [50%] { TERRAIN:line (50,8),(53,8), '-' TERRAIN:line (40,8),(43,8), 'B' } IF [50%] { TERRAIN:(27,12),'|' TERRAIN:line (27,3),(29,3), 'B' TERRAIN:(28,2), '-' } IF [50%] { TERRAIN:line (16,10),(16,11),'|' TERRAIN:line (9,13),(14,13), 'B' } # Dungeon Description # The shrine to Moloch. REGION:(01,06,05,14),lit,"temple" # The Morgues REGION:(19,01,24,08),unlit,"morgue",filled,irregular REGION:(09,14,16,18),unlit,"morgue",filled,irregular REGION:(37,09,43,14),unlit,"morgue",filled,irregular # Stairs STAIR:(01,01),down # Branch location BRANCH:(66,17,66,17),(0,0,0,0) TELEPORT_REGION:(58,09,72,18),(0,0,0,0),down # Secret Doors DOOR:locked,(04,01) DOOR:locked,(08,04) DOOR:locked,(06,06) # The altar of Moloch. ALTAR:(03,10),noalign,shrine # Non diggable walls - everywhere! NON_DIGGABLE:(00,00,75,19) # Objects # **LOTS** of dead bodies (all human). # note: no priest(esse)s or monks - maybe Moloch has a *special* # fate reserved for members of *those* classes. # OBJECT:('%',"corpse"),random,montype:"archeologist" OBJECT:('%',"corpse"),random,montype:"archeologist" OBJECT:('%',"corpse"),random,montype:"barbarian" OBJECT:('%',"corpse"),random,montype:"barbarian" OBJECT:('%',"corpse"),random,montype:"caveman" OBJECT:('%',"corpse"),random,montype:"cavewoman" OBJECT:('%',"corpse"),random,montype:"healer" OBJECT:('%',"corpse"),random,montype:"healer" OBJECT:('%',"corpse"),random,montype:"knight" OBJECT:('%',"corpse"),random,montype:"knight" OBJECT:('%',"corpse"),random,montype:"ranger" OBJECT:('%',"corpse"),random,montype:"ranger" OBJECT:('%',"corpse"),random,montype:"rogue" OBJECT:('%',"corpse"),random,montype:"rogue" OBJECT:('%',"corpse"),random,montype:"samurai" OBJECT:('%',"corpse"),random,montype:"samurai" OBJECT:('%',"corpse"),random,montype:"tourist" OBJECT:('%',"corpse"),random,montype:"tourist" OBJECT:('%',"corpse"),random,montype:"valkyrie" OBJECT:('%',"corpse"),random,montype:"valkyrie" OBJECT:('%',"corpse"),random,montype:"wizard" OBJECT:('%',"corpse"),random,montype:"wizard" # # Some random weapons and armor. # OBJECT:'[',random OBJECT:'[',random OBJECT:'[',random OBJECT:'[',random OBJECT:')',random OBJECT:')',random OBJECT:')',random OBJECT:')',random # # Some random loot. # OBJECT:('*',"ruby"),random OBJECT:'*',random OBJECT:'*',random OBJECT:'!',random OBJECT:'!',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random OBJECT:'/',random OBJECT:'/',random OBJECT:'=',random OBJECT:'=',random OBJECT:'+',random OBJECT:'+',random OBJECT:'(',random OBJECT:'(',random OBJECT:'(',random # (Not so) Random traps. TRAP:"spiked pit", (05,02) TRAP:"spiked pit", (14,05) TRAP:"sleep gas", (03,01) TRAP:"board", (21,12) TRAP:"board", random TRAP:"dart", (60,01) TRAP:"dart", (26,17) TRAP:"anti magic", random TRAP:"anti magic", random TRAP:"magic", random TRAP:"magic", random # Random monsters. # The ghosts. MONSTER:(' ',"ghost"),random MONSTER:(' ',"ghost"),random MONSTER:(' ',"ghost"),random MONSTER:(' ',"ghost"),random MONSTER:(' ',"ghost"),random MONSTER:(' ',"ghost"),random # Add a few bats for atmosphere. MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random MONSTER:('B',"vampire bat"),random # And a lich for good measure. MONSTER:'L',random # Some undead nasties for good measure MONSTER:'V',random MONSTER:'V',random MONSTER:'V',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'M',random MONSTER:'M',random MONSTER:'M',random MONSTER:'M',random # # The Juiblex level # MAZE:"juiblex",' ' FLAGS:noteleport,shortsighted INIT_MAP:mines,'.','}',true,true,unlit,false # guarantee at least one open spot to ensure successful stair placement GEOMETRY:left,bottom MAP xxxxxxxx xx...xxx xxx...xx xxxx.xxx xxxxxxxx ENDMAP OBJECT:('`',"boulder"),random GEOMETRY:right,top MAP xxxxxxxx xxxx.xxx xxx...xx xx...xxx xxxxxxxx ENDMAP OBJECT:('`',"boulder"),random # lair GEOMETRY:center,center MAP xx}}}}}x}}}}}x}}}}}x}}}}}x}}}}}x}}}}}x}}}}}x}}}}}xx x}}}.}}}}}..}}}..}}}}}..}}}..}}}}}..}}}..}}}}}.}}}x }}}...}}..}}.}.}}.}}.}}}...}}}.}}}..}}}..}}}}...}}} x}}}.}}.}}}.}}.}}.}}...}}.}}.....}}.....}....}.}}}x xx}}}..}}}.}}.}}.}}..}}.....}}.}}}.}}.}}}}}}}}}}}xx x}}}..}}}}}.}}.}}.}}...}}}}}.....}}.}}}}}}.....}}}x }}}..}}...}}..}}.}}}.}}}...}}}.}}}.}.}}}}..P.P..}}} }}.}}}}...}}}}}.}...}}}..P..}}}.}.}}}.}}}}.....}}}} }.}}}}.}}.}..}.}}}}}}}..P.P..}}}.}}}.}}..}}...}}}}x x}}}}.}}}}....}}}}}.}}}..P..}}}.}}}}.}}..}}...}}}.} }}}}..}}.}}..}}}}...}}}}...}}}.}}}}}.}}}}.}}}}}}.}} }}}...}}...}}}..}}}}}}}}}}}}.....}}}}.}}...}..}.}}} x}}}..}}.}}}}....}}..}}}..}}.....}}}}.}}}.}....}}}x xx}}}.}}}}..}}..}}..}}..}}..}}.}}}..}.}..}}}..}}}xx x}}}.}}}}....}}}}..}}....}}}}}}}...}}}....}}}}.}}}x }}}...}}}....}}}..}}}....}}}..}}...}}}....}}}...}}} x}}}.}}}}}..}}}..}}}}}..}}}..}}}}}..}}}..}}}}}.}}}x xx}}}}}x}}}}}x}}}}}x}}}}}x}}}}}x}}}}}x}}}}}x}}}}}xx ENDMAP # Random registers $monster = monster: { 'j','b','P','F' } SHUFFLE: $monster $place = { (04,02),(46,02),(04,15),(46,15) } SHUFFLE: $place # Dungeon description REGION:(00,00,50,17),unlit,"swamp" MAZEWALK:(00,09),west MAZEWALK:(50,08),east STAIR:levregion(01,00,11,20),(0,0,50,17),down STAIR:levregion(69,00,79,20),(0,0,50,17),up BRANCH:levregion(01,00,11,20),(0,0,50,17) TELEPORT_REGION:levregion(01,00,11,20),(0,0,50,17),up TELEPORT_REGION:levregion(69,00,79,20),(0,0,50,17),down FOUNTAIN:$place[0] MONSTER:('m',"giant mimic"),$place[1],m_feature "fountain" MONSTER:('m',"giant mimic"),$place[2],m_feature "fountain" MONSTER:('m',"giant mimic"),$place[3],m_feature "fountain" # The demon of the swamp MONSTER:('&',"Juiblex"),(25,08) # And a couple demons MONSTER:('i',"lemure"),(43,08) MONSTER:('i',"lemure"),(44,08) MONSTER:('i',"lemure"),(45,08) # Some liquids and gems OBJECT:'*',(43,06) OBJECT:'*',(45,06) OBJECT:'!',(43,09) OBJECT:'!',(44,09) OBJECT:'!',(45,09) # And lots of blobby monsters MONSTER:$monster[0],(25,06) MONSTER:$monster[1],(24,07) MONSTER:$monster[2],(26,07) MONSTER:$monster[3],(23,08) MONSTER:$monster[3],(27,08) MONSTER:$monster[2],(24,09) MONSTER:$monster[1],(26,09) MONSTER:$monster[0],(25,10) MONSTER:'j',random MONSTER:'j',random MONSTER:'j',random MONSTER:'j',random MONSTER:'P',random MONSTER:'P',random MONSTER:'P',random MONSTER:'P',random MONSTER:'b',random MONSTER:'b',random MONSTER:'b',random MONSTER:'F',random MONSTER:'F',random MONSTER:'F',random MONSTER:'m',random MONSTER:'m',random MONSTER:(';',"jellyfish"),random MONSTER:(';',"jellyfish"),random # Some random objects OBJECT:'!',random OBJECT:'!',random OBJECT:'!',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:('`',"boulder"),random # Some traps TRAP:"sleep gas",random TRAP:"sleep gas",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"magic",random TRAP:"magic",random # # The Orcus Level # MAZE:"orcus",random FLAGS: noteleport,shortsighted GEOMETRY:right,center # A ghost town MAP .|....|....|....|..............|....|........ .|....|....|....|..............|....|........ .|....|....|....|--...-+-------|............. .|....|....|....|..............+............. .|.........|....|..............|....|........ .--+-...-+----+--....-------...--------.-+--- .....................|.....|................. .....................|.....|................. .--+----....-+---....|.....|...----------+--- .|....|....|....|....---+---...|......|...... .|.........|....|..............|......|...... .----...---------.....-----....+......|...... .|........................|....|......|...... .----------+-...--+--|....|....----------+--- .|....|..............|....+....|............. .|....+.......|......|....|....|............. .|....|.......|......|....|....|............. ENDMAP MAZEWALK:(00,06),west # Entire main area REGION:(01,00,44,16),unlit,"ordinary" STAIR:(33,15),down STAIR:levregion(01,00,12,20),levregion(20,01,70,20),up BRANCH:levregion(01,00,12,20),levregion(20,01,70,20) TELEPORT_REGION:levregion(01,00,12,20),levregion(20,01,70,20) # Wall "ruins" OBJECT:('`',"boulder"),(19,02) OBJECT:('`',"boulder"),(20,02) OBJECT:('`',"boulder"),(21,02) OBJECT:('`',"boulder"),(36,02) OBJECT:('`',"boulder"),(36,03) OBJECT:('`',"boulder"),(06,04) OBJECT:('`',"boulder"),(05,05) OBJECT:('`',"boulder"),(06,05) OBJECT:('`',"boulder"),(07,05) OBJECT:('`',"boulder"),(39,05) OBJECT:('`',"boulder"),(08,08) OBJECT:('`',"boulder"),(09,08) OBJECT:('`',"boulder"),(10,08) OBJECT:('`',"boulder"),(11,08) OBJECT:('`',"boulder"),(06,10) OBJECT:('`',"boulder"),(05,11) OBJECT:('`',"boulder"),(06,11) OBJECT:('`',"boulder"),(07,11) OBJECT:('`',"boulder"),(21,11) OBJECT:('`',"boulder"),(21,12) OBJECT:('`',"boulder"),(13,13) OBJECT:('`',"boulder"),(14,13) OBJECT:('`',"boulder"),(15,13) OBJECT:('`',"boulder"),(14,14) # Doors DOOR:closed,(23,02) DOOR:open,(31,03) DOOR:nodoor,(03,05) DOOR:closed,(09,05) DOOR:closed,(14,05) DOOR:closed,(41,05) DOOR:open,(03,08) DOOR:nodoor,(13,08) DOOR:open,(41,08) DOOR:closed,(24,09) DOOR:closed,(31,11) DOOR:open,(11,13) DOOR:closed,(18,13) DOOR:closed,(41,13) DOOR:open,(26,14) DOOR:closed,(06,15) # Special rooms ALTAR:(24,07),noalign,sanctum REGION:(22,12,25,16),unlit,"morgue" REGION:(32,09,37,12),lit,"shop" REGION:(12,00,15,04),lit,"shop" # Some traps. TRAP:"spiked pit", random TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"fire", random TRAP:"fire", random TRAP:"magic", random TRAP:"magic", random # Some random objects OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # The resident nasty MONSTER:('&',"Orcus"),(33,15) # And its preferred companions MONSTER:('Z',"human zombie"),(32,15) MONSTER:(' ',"shade"),(32,14) MONSTER:(' ',"shade"),(32,16) MONSTER:('V',"vampire"),(35,16) MONSTER:('V',"vampire"),(35,14) MONSTER:('V',"vampire lord"),(36,14) MONSTER:('V',"vampire lord"),(36,15) # Randomly placed companions MONSTER:('Z',"skeleton"),random MONSTER:('Z',"skeleton"),random MONSTER:('Z',"skeleton"),random MONSTER:('Z',"skeleton"),random MONSTER:('Z',"skeleton"),random MONSTER:(' ',"shade"),random MONSTER:(' ',"shade"),random MONSTER:(' ',"shade"),random MONSTER:(' ',"shade"),random MONSTER:('Z',"giant zombie"),random MONSTER:('Z',"giant zombie"),random MONSTER:('Z',"giant zombie"),random MONSTER:('Z',"ettin zombie"),random MONSTER:('Z',"ettin zombie"),random MONSTER:('Z',"ettin zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('Z',"human zombie"),random MONSTER:('V',"vampire"),random MONSTER:('V',"vampire"),random MONSTER:('V',"vampire"),random MONSTER:('V',"vampire lord"),random MONSTER:('V',"vampire lord"),random # A few more for the party MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random # # The Asmodeus Level # MAZE:"asmodeus",random FLAGS: noteleport # First part GEOMETRY:half-left,center MAP --------------------- |.............|.....| |.............S.....| |---+------------...| |.....|.........|-+-- |..---|.........|.... |..|..S.........|.... |..|..|.........|.... |..|..|.........|-+-- |..|..-----------...| |..S..........|.....| --------------------- ENDMAP STAIR:levregion(01,00,6,20),levregion(6,1,70,16),up BRANCH:levregion(01,00,6,20),levregion(6,1,70,16) TELEPORT_REGION:levregion(01,00,6,20),levregion(6,1,70,16) # Doors DOOR:closed,(04,03) DOOR:locked,(18,04) DOOR:closed,(18,08) # STAIR:(13,07),down # Non diggable walls NON_DIGGABLE:(00,00,20,11) # Entire main area REGION:(01,01,20,10),unlit,"ordinary" # The fellow in residence MONSTER:('&',"Asmodeus"),(12,07) # Some random weapons and armor. OBJECT:'[',random OBJECT:'[',random OBJECT:')',random OBJECT:')',random OBJECT:'*',random OBJECT:'!',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random # Some traps. TRAP:"spiked pit", (05,02) TRAP:"fire", (08,06) TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random TRAP:"magic", random # Random monsters. MONSTER:(' ',"ghost"),(11,07) MONSTER:('&',"horned devil"),(10,05) MONSTER:'L',random # Some Vampires for good measure MONSTER:'V',random MONSTER:'V',random MONSTER:'V',random # Second part GEOMETRY:half-right,center MAP --------------------------------- ................................| ................................+ ................................| --------------------------------- ENDMAP MAZEWALK:(32,02),east # Non diggable walls NON_DIGGABLE:(00,00,32,04) DOOR:closed,(32,02) MONSTER:'&',random MONSTER:'&',random MONSTER:'&',random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random # # The Baalzebub level # MAZE:"baalz",' ' FLAGS: noteleport,corrmaze GEOMETRY:right,center MAP ------------------------------------------------- | --- ---- | ---- | ------------ | | ------ | --------|..........|--- | |....| -------|...........-------------- ---....|--|..................S............|---- ....--....S..----------------|............S...| ---....|--|..................|............|---- | |....| -------|...........-----S-------- | ------ | --------|..........|--- | ---- | ------------ | | --- ---- ------------------------------------------------- ENDMAP STAIR:levregion(01,00,15,20),levregion(15,1,70,16),up BRANCH:levregion(01,00,15,20),levregion(15,1,70,16) TELEPORT_REGION:levregion(01,00,15,20),levregion(15,1,70,16) NON_DIGGABLE:(00,00,46,12) MAZEWALK:(00,06),west STAIR:(44,06),down # The fellow in residence MONSTER:('&',"Baalzebub"),(35,06) # Some random weapons and armor. OBJECT:'[',random OBJECT:'[',random OBJECT:')',random OBJECT:')',random OBJECT:'*',random OBJECT:'!',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random # Some traps. TRAP:"spiked pit", random TRAP:"fire", random TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random TRAP:"magic", random # Random monsters. MONSTER:(' ',"ghost"),(37,07) MONSTER:('&',"horned devil"),(32,05) MONSTER:('&',"barbed devil"),(38,07) MONSTER:'L',random # Some Vampires for good measure MONSTER:'V',random MONSTER:'V',random MONSTER:'V',random # # The Sanctum Level # MAZE:"sanctum", ' ' FLAGS: noteleport,hardfloor,nommap # This is outside the main map, below, so we must do it before adding # that map and anchoring coordinates to it. This extends the invisible # barrier up to the top row, which falls outside the drawn map. NON_PASSWALL:(39,00,41,00) GEOMETRY:center,center MAP ---------------------------------------------------------------------------- | -------------- | | |............| ------- | | -------............----- |.....| | | |......................| --.....| --------- | | ----......................---------|......---- |.......| | | |........---------..........|......+.........| ------+---..| | | ---........|.......|..........--S----|.........| |........|..| | | |..........|.......|.............| |.........-------..---------- | | |..........|.......|..........---- |..........|....|..|......| | | |..........|.......|..........| --.......----+---S---S--..| | | |..........---------..........| |.......|.............|..| | | ---...........................| -----+-------S---------S--- | | |...........................| |...| |......| |....|-- | | ----.....................---- |...---....--- ---......| | | |.....................| |..........| |.....---- | | -------...........----- --...------- |.....| | | |...........| |...| |.....| | | ------------- ----- ------- | ---------------------------------------------------------------------------- ENDMAP REGION:(15,07,21,10),lit,"temple" ALTAR:(18,08),noalign,sanctum REGION:(41,06,48,11),unlit,"morgue",filled,irregular # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Invisible barrier separating the left & right halves of the level NON_PASSWALL:(37,00,39,19) # Doors DOOR:closed,(40,06) DOOR:locked,(62,06) DOOR:closed,(46,12) DOOR:closed,(53,10) # Surround the temple with fire TRAP:"fire",(13,05) TRAP:"fire",(14,05) TRAP:"fire",(15,05) TRAP:"fire",(16,05) TRAP:"fire",(17,05) TRAP:"fire",(18,05) TRAP:"fire",(19,05) TRAP:"fire",(20,05) TRAP:"fire",(21,05) TRAP:"fire",(22,05) TRAP:"fire",(23,05) TRAP:"fire",(13,12) TRAP:"fire",(14,12) TRAP:"fire",(15,12) TRAP:"fire",(16,12) TRAP:"fire",(17,12) TRAP:"fire",(18,12) TRAP:"fire",(19,12) TRAP:"fire",(20,12) TRAP:"fire",(21,12) TRAP:"fire",(22,12) TRAP:"fire",(23,12) TRAP:"fire",(13,06) TRAP:"fire",(13,07) TRAP:"fire",(13,08) TRAP:"fire",(13,09) TRAP:"fire",(13,10) TRAP:"fire",(13,11) TRAP:"fire",(23,06) TRAP:"fire",(23,07) TRAP:"fire",(23,08) TRAP:"fire",(23,09) TRAP:"fire",(23,10) TRAP:"fire",(23,11) # Some traps. TRAP:"spiked pit", random TRAP:"fire", random TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random # Some random objects OBJECT:'[',random OBJECT:'[',random OBJECT:'[',random OBJECT:'[',random OBJECT:')',random OBJECT:')',random OBJECT:'*',random OBJECT:'!',random OBJECT:'!',random OBJECT:'!',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random # Some monsters. MONSTER:('&',"horned devil"),(14,12),hostile MONSTER:('&',"barbed devil"),(18,08),hostile MONSTER:('&',"erinys"),(10,04),hostile MONSTER:('&',"marilith"),(07,09),hostile MONSTER:('&',"nalfeshnee"),(27,08),hostile # Moloch's horde MONSTER:('@',"aligned priest"),(20,03),noalign,hostile MONSTER:('@',"aligned priest"),(15,04),noalign,hostile MONSTER:('@',"aligned priest"),(11,05),noalign,hostile MONSTER:('@',"aligned priest"),(11,07),noalign,hostile MONSTER:('@',"aligned priest"),(11,09),noalign,hostile MONSTER:('@',"aligned priest"),(11,12),noalign,hostile MONSTER:('@',"aligned priest"),(15,13),noalign,hostile MONSTER:('@',"aligned priest"),(17,13),noalign,hostile MONSTER:('@',"aligned priest"),(21,13),noalign,hostile # A few nasties MONSTER:'L',random MONSTER:'L',random MONSTER:'V',random MONSTER:'V',random MONSTER:'V',random STAIR:(63,15),up # Teleporting to this level is allowed after the invocation creates its # entrance. Force arrival in that case to be on rightmost third of level. TELEPORT_REGION:levregion(54,1,79,18),(0,0,0,0),down nethack-3.6.0/dat/help0000664000076400007660000002561412615625541013577 0ustar paxedpaxed Welcome to NetHack! ( description of version 3.6 ) NetHack is a Dungeons and Dragons like game where you (the adventurer) descend into the depths of the dungeon in search of the Amulet of Yendor, reputed to be hidden somewhere below the twentieth level. You begin your adventure with a pet that can help you in many ways, and can be trained to do all sorts of things. On the way you will find useful (or useless) items, quite possibly with magic properties, and assorted monsters. You can attack a monster by trying to move onto the space a monster is on (but often it is much wiser to leave it alone). Unlike most adventure games, which give you a verbal description of your location, NetHack gives you a visual image of the dungeon level you are on. NetHack uses the following symbols: - and | The walls of a room, possibly also open doors or a grave. . The floor of a room or a doorway. # A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. > Stairs down: a way to the next level. < Stairs up: a way to the previous level. @ You (usually), or another human. ) A weapon of some sort. [ A suit or piece of armor. % Something edible (not necessarily healthy). / A wand. = A ring. ? A scroll. ! A potion. ( Some other useful object (pick-axe, key, lamp...) $ A pile of gold. * A gem or rock (possibly valuable, possibly worthless). + A closed door, or a spellbook containing a spell you can learn. ^ A trap (once you detect it). " An amulet, or a spider web. 0 An iron ball. _ An altar, or an iron chain. { A fountain. } A pool of water or moat or a pool of lava. \ An opulent throne. ` A boulder or statue. A to Z, a to z, and several others: Monsters. I Invisible or unseen monster's last known location You can find out what a symbol represents by typing '/' and following the directions to move the cursor to the symbol in question. For instance, a 'd' may turn out to be a dog. y k u 7 8 9 Move commands: \|/ \|/ yuhjklbn: go one step in specified direction h-.-l 4-.-6 YUHJKLBN: go in specified direction until you /|\ /|\ hit a wall or run into something b j n 1 2 3 g: run in direction until something numberpad interesting is seen G, same, except a branching corridor isn't < up ^: considered interesting (the ^ in this case means the Control key, not a caret) > down m: move without picking up objects F: fight even if you don't sense a monster If the number_pad option is set, the number keys move instead. Depending on the platform, Shift number (on the numberpad), Meta number, or Alt number will invoke the YUHJKLBN commands. Control may or may not work when number_pad is enabled, depending on the platform's capabilities. Digit '5' acts as 'G' prefix, unless number_pad is set to 2 in which case it acts as 'g' instead. If number_pad is set to 3, the roles of 1,2,3 and 7,8,9 are reversed; when set to 4, behaves same as 3 combined with 2. If number_pad is set to -1, alphabetic movement commands are used but 'y' and 'z' are swapped. Commands: NetHack knows the following commands: ? Help menu. / Tell what a symbol represents. You may choose to specify a location or give a symbol argument. & Tell what a command does. < Go up a staircase (if you are standing on it). > Go down a staircase (if you are standing on it). . Rest, do nothing for one turn. _ Travel via a shortest-path algorithm to a point on the map. a Apply (use) a tool (pick-axe, key, lamp...). A Remove all armor. ^A Redo the previous command. c Close a door. C Call (name) monster, individual object, or type of object. d Drop something. d7a: drop seven items of object a. D Drop multiple items. This command is implemented in two different ways. One way is: "D" displays a list of all of your items, from which you can pick and choose what to drop. A "+" next to an item means that it will be dropped, a "-" means that it will not be dropped. Toggle an item to be selected/deselected by typing the letter adjacent to its description. Select all items with "+", deselect all items with "=". The moves you from one page of the listing to the next. The other way is: "D" will ask the question "What kinds of things do you want to drop? [!%= au]". You should type zero or more object symbols possibly followed by 'a' and/or 'u'. Da - drop all objects, without asking for confirmation. Du - drop only unpaid objects (when in a shop). D%u - drop only unpaid food. ^D Kick (for doors, usually). e Eat food. E Engrave a message on the floor. E- - write in the dust with your fingers. f Fire ammunition from quiver. F Followed by direction, fight a monster (even if you don't sense it). i Display your inventory. I Display selected parts of your inventory, as in I* - list all gems in inventory. Iu - list all unpaid items. Ix - list all used up items that are on your shopping bill. I$ - count your money. o Open a door. O Review current options and possibly change them. A menu displaying the option settings will be displayed and most can be changed by simply selecting their entry. Options are usually set before the game with a NETHACKOPTIONS environment variable, or via a config file (defaults.nh, NetHack Defaults, nethack.cnf, .nethackrc, etc.), not with the 'O' command. p Pay your shopping bill. P Put on an accessory (ring, amulet, etc). ^P Repeat last message (subsequent ^P's repeat earlier messages). The behavior can be varied via the msg_window option. q Drink (quaff) something (potion, water, etc). Q Select ammunition for quiver. r Read a scroll or spellbook. R Remove an accessory (ring, amulet, etc). ^R Redraw the screen. s Search for secret doors and traps around you. S Save the game. t Throw an object or shoot a projectile. T Take off armor. ^T Teleport, if you are able. v Displays the version number. V Display a longer identification of the version, including the history of the game. w Wield weapon. w- means wield nothing, use bare hands. W Wear armor. x Swap wielded and secondary weapons. X Toggle two-weapon combat. ^X Show your attributes. z Zap a wand. (Use y instead of z if number_pad is -1.) Z Cast a spell. (Use Y instead of Z if number_pad is -1.) ^Z Suspend the game. (^Y instead of ^Z if number_pad is -1.) : Look at what is here. ; Look at what is somewhere else. , Pick up some things. @ Toggle the pickup option. ^ Ask for the type of a trap you found earlier. ) Tell what weapon you are wielding. [ Tell what armor you are wearing. = Tell what rings you are wearing. " Tell what amulet you are wearing. ( Tell what tools you are using. * Tell what equipment you are using; combines the preceding five. $ Count your gold pieces. + List the spells you know; also rearrange them if desired. \ Show what types of objects have been discovered. ` Show discovered types for one class of objects. ! Escape to a shell, if supported in your version and OS. # Introduces one of the "extended" commands. To get a list of the commands you can use with "#" type "#?". The extended commands you can use depends upon what options the game was compiled with, along with your class and what type of monster you most closely resemble at a given moment. If your keyboard has a meta key (which, when pressed in combination with another key, modifies it by setting the 'meta' (8th, or 'high') bit), these extended commands can be invoked by meta-ing the first letter of the command. An alt key may have a similar effect. If the "number_pad" option is on, some additional letter commands are available: h displays the help menu, like '?' j Jump to another location. k Kick (for doors, usually). l Loot a box on the floor. n followed by number of times to repeat the next command. N Name a monster, an individual object, or a type of object. u Untrap a trapped object or door. You can put a number before a command to repeat it that many times, as in "40." or "20s.". If you have the number_pad option set, you must type 'n' to prefix the count, as in "n40." or "n20s". Some information is displayed on the bottom line or perhaps in a box, depending on the platform you are using. You see your attributes, your alignment, what dungeon level you are on, how many hit points you have now (and will have when fully recovered), what your armor class is (the lower the better), your experience level, and the state of your stomach. Optionally, you may or may not see other information such as spell points, how much gold you have, etc. Have Fun, and Happy Hacking! nethack-3.6.0/dat/hh0000664000076400007660000001415212504447327013242 0ustar paxedpaxedy k u 7 8 9 Move commands: \|/ \|/ yuhjklbn: go one step in specified direction h-.-l 4-.-6 YUHJKLBN: go in specified direction until you /|\ /|\ hit a wall or run into something b j n 1 2 3 g: run in direction until something numberpad interesting is seen G, same, except a branching corridor isn't < up ^: considered interesting (the ^ in this case means the Control key, not a caret) > down m: move without picking up objects/fighting F: fight even if you don't sense a monster If the number_pad option is set, the number keys move instead. Depending on the platform, Shift number (on the numberpad), Meta number, or Alt number will invoke the YUHJKLBN commands. Control may or may not work when number_pad is enabled, depending on the platform's capabilities. Digit '5' acts as 'G' prefix, unless number_pad is set to 2 in which case it acts as 'g' instead. If number_pad is set to 3, the roles of 1,2,3 and 7,8,9 are reversed; when set to 4, behaves same as 3 combined with 2. If number_pad is set to -1, alphabetic movement commands are used but 'y' and 'z' are swapped. General commands: ? help display one of several informative texts #quit quit end the game without saving current game S save save the game (to be continued later) and exit ! sh escape to some SHELL (if allowed) ^Z suspend suspend the game (independent of your current suspend char) O options set options / whatis tell what a map symbol represents \ known display list of what's been discovered v version display version number V history display game history ^A again redo the previous command (^A denotes the keystroke CTRL-A) ^R redraw redraw the screen ^P prevmsg repeat previous message (subsequent ^P's repeat earlier ones) # introduces an extended command (#? for a list of them) Game commands: ^D kick kick (a door, or something else) ^T 'port teleport (if you can) ^X show show your attributes a apply apply or use a tool (pick-axe, key, camera, etc.) A armor take off all armor c close close a door C call name a monster, an individual object, or a type of object d drop drop an object. d7a: drop seven items of object 'a' D Drop drop selected types of objects e eat eat something E engrave write a message in the dust on the floor (E- use fingers) f fire fire ammunition from quiver F fight followed by direction, fight a monster i invent list your inventory (all objects you are carrying) I Invent list selected parts of your inventory Iu: list unpaid objects Ix: list unpaid but used up items I$: count your money o open open a door p pay pay your bill (in a shop) P puton put on an accessory (ring, amulet, etc) q quaff drink something (potion, water, etc) Q quiver select ammunition for quiver r read read a scroll or spellbook R remove remove an accessory (ring, amulet, etc) s search search for secret doors, hidden traps and monsters t throw throw or shoot a weapon T takeoff take off some armor w wield wield a weapon (w- wield nothing) W wear put on some armor x xchange swap wielded and secondary weapons X twoweapon toggle two-weapon combat z zap zap a wand (use y instead of z if number_pad is -1) Z Zap cast a spell (use Y instead of Z if number_pad is -1) < up go up the stairs > down go down the stairs ^ trap_id identify a previously found trap ),[,=,",( ask for current items of specified symbol in use * ask for combination of ),[,=,",( all at once $ gold count your gold + spells list the spells you know; also rearrange them if desired ` classkn display known items for one class of objects _ travel move via a shortest-path algorithm to a point on the map . rest wait a moment , pickup pick up all you can carry @ toggle "pickup" (auto pickup) option on and off : look look at what is here ; farlook look at what is somewhere else by selecting a map symbol Keyboards that have a meta key can also use these extended commands via the meta modifier instead of the # prefix: M-? display extended command help (if the platform allows this) M-2 twoweapon toggle two-weapon combat (unless number_pad is enabled) M-a adjust adjust inventory letters M-c chat talk to someone M-d dip dip an object into something M-e enhance advance or check weapon and spell skills M-f force force a lock M-i invoke invoke an object's special powers M-j jump jump to another location M-l loot loot a box on the floor M-m monster use a monster's special ability M-n name name a monster, an individual object, or a type of object M-o offer offer a sacrifice to the gods M-p pray pray to the gods for help M-q quit stop playing M-r rub rub a lamp or a stone M-s sit sit down M-t turn turn undead M-u untrap untrap something M-v version print compile time options for this version M-w wipe wipe off your face If the "number_pad" option is on, these additional variants are available: n followed by number of times to repeat the next command h help display one of several informative texts, like '?' j jump jump to another location k kick kick something (usually a door) l loot loot a box on the floor N name name an item or type of object u untrap untrap something (usually a trapped object) nethack-3.6.0/dat/history0000664000076400007660000003353312620344570014343 0ustar paxedpaxedNetHack History file for release 3.6 Behold, mortal, the origins of NetHack... Jay Fenlason wrote the original Hack with help from Kenny Woodland, Mike Thome, and Jon Payne. Andries Brouwer did a major re-write, transforming Hack into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for UNIX(tm) machines to the Usenet. Don G. Kneller ported Hack 1.0.3 to Microsoft(tm) C and MS-DOS(tm), producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6; note that these are old Hack version numbers, not contemporary NetHack ones). R. Black ported PC HACK 3.51 to Lattice(tm) C and the Atari 520/1040ST, producing ST Hack 1.03. Mike Stephenson merged these various versions back together, incorporating many of the added features, and produced NetHack version 1.4 in 1987. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Later, Mike coordinated a major rewrite of the game, heading a team which included Ken Arromdee, Jean-Christophe Collet, Steve Creps, Eric Hendrickson, Izchak Miller, Eric S. Raymond, John Rupley, Mike Threepoint, and Janet Walz, to produce NetHack 3.0c. The same group subsequently released ten patch- level revisions and updates of 3.0. NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by Timo Hakulinen, and to VMS by David Gentzel. The three of them and Kevin Darcy later joined the main development team to produce subsequent revisions of 3.0. Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm Meluch, Stephen Spackman and Pierre Martineau designed overlay code for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. Headed by Mike Stephenson and coordinated by Izchak Miller and Janet Walz, the development team which now included Ken Arromdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, and Eric Smith undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced NetHack 3.1. Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga. Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC. Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke, and Andy Swanson developed NetHack 3.1 for the Macintosh, porting it for MPW. Building on their development, Barton House added a Think C port. Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua Delahunty, is responsible for the VMS version of NetHack 3.1. Michael Allison ported NetHack 3.1 to Windows NT. Dean Luick, with help from David Cohrs, developed NetHack 3.1 for X11. Warwick Allison wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. The 3.2 development team, comprised of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2 in April of 1996. Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team remained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, Dr. Izchak Miller, passed away. That release of the game was dedicated to him by the development and porting teams. Version 3.2 proved to be more stable than previous versions. Many bugs were fixed, abuses eliminated, and game features tuned for better game play. During the lifespan of NetHack 3.1 and 3.2, several enthusiasts of the game added their own modifications to the game and made these "variants" publicly available: Tom Proudfoot and Yuval Oren created NetHack++, which was quickly renamed NetHack--. Working independently, Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and Warwick Allison improved the spellcasting system with the Wizard Patch. Warwick Allison also ported NetHack to use the Qt interface. Warren Cheung combined SLASH with the Wizard Patch to produce Slash'em, and with the help of Kevin Hugo, added more features. Kevin later joined the DevTeam and incorporated the best of these ideas in NetHack 3.3. The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. The 3.3 development team, consisting of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in preference to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. The 3.4 development team initially consisted of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul Winner, with Warwick Allison joining just before the release of NetHack 3.4.0 in March 2002. As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that NetHack runs on: Pat Rankin maintained 3.4 for VMS. Michael Allison maintained NetHack 3.4 for the MS-DOS platform. Paul Winner and Yitzhak Sapir provided encouragement. Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced the Macintosh port of 3.4. Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows platform. Alex Kompel contributed a new graphical interface for the Windows port. Alex Kompel also contributed a Windows CE port for 3.4.1. Ron Van Iwaarden maintained 3.4 for OS/2. Janne Salmijarvi and Teemu Suikki maintained and enhanced the Amiga port of 3.5 after Janne Salmijarvi resurrected it for 3.3.1. Christian `Marvin' Bressler maintained 3.5 for the Atari after he resurrected it for 3.3.1. The release of NetHack 3.4.3 in December 2003 marked the beginning of a long release hiatus. 3.4.3 proved to be a remarkably stable version that provided continued enjoyment by the community for more than a decade. The devteam slowly and quietly continued to work on the game behind the scenes during the tenure of 3.4.3. It was during that same period that several new variants emerged within the NetHack community. Notably sporkhack by Derek S. Ray, unnethack by Patric Mueller, nitrohack and its successors originally by Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. Some of those variants continue to be developed, maintained, and enjoyed by the community to this day. In September 2014, an interim snapshot of the code under development was released publicly by other parties. Since that code was a work-in-progress and had not gone through a period of debugging, it was decided that the version numbers present on that code snapshot would be retired and never used in an official NetHack release. An announcement was posted on the devteam's official nethack.org website to that effect, stating that there would never be a 3.4.4, 3.5, or 3.5.0 official release version. In January 2015, preparation began for the release of NetHack 3.6. At the beginning of development for what would eventually get released as 3.6.0, the development team consisted of Michael Allison, Warwick Allison, Ken Arromdee, David Cohrs, Jessie Collet, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul Winner. Leading up to the release of 3.6.0 in early 2015, new members Sean Hunt, Pasi Kallinen, and Derek S. Ray joined the NetHack development team. In January 2015, preparation began for the release of NetHack 3.6. The 3.6 version merges work done by the development team since the previous release with some of the beloved community patches. Many bugs were fixed and some code was restructured. The development team, as well as Steve VanDevender and Kevin Smolkowski ensured that NetHack 3.6.0 continued to operate on various Unix flavors as well as maintaining the X11 interface. Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained the port of NetHack 3.6.0 for Mac. Michael Allison, Derek S. Ray, Yitzhak Sapir, Alex Kompel, Dion Nicolaas, and David Cohrs maintained the port of NetHack 3.6.0 for Microsoft Windows. Pat Rankin attempted to keep the VMS port running for NetHack 3.6.0, hindered by limited access. Kevin Smolkowski has updated and tested it for the most recent version of OpenVMS (V8.4 as of this writing) on Alpha and Integrity (aka Itanium aka IA64) but not VAX. This version of the game is special in a particular way. Near the end of the development of 3.6, one of the significant inspirations for many of the humorous and fun features found in the game, author Terry Pratchett, passed away. This version of the game includes a tribute to him. An official NetHack web site continues to be maintained by Ken Lorber at http://www.nethack.org/. -- SHOUT-OUTS The devteam would like to give a special "shout-out" to thank the generous people primarily responsible for the public NetHack servers available for playing the game at nethack.alt.org and devnull.net. In addition to providing a way for the public to play a game of NetHack from almost anywhere, they have hosted annual NetHack tournaments for many, many years. On behalf of the NetHack community, thank you very much to M. Drew Streib, Pasi Kallinen and Robin Bandy. - - - - - - - - - - From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: Adam Aronow Janet Walz Nathan Eady Alex Kompel Janne Salmijarvi Norm Meluch Andreas Dorn Jean-Christophe Collet Olaf Seibert Andy Church Jeff Bailey Pasi Kallinen Andy Swanson Jochen Erwied Pat Rankin Ari Huttunen John Kallen Paul Winner Barton House John Rupley Pierre Martineau Benson I. Margulies John S. Bien Ralf Brown Bill Dyer Johnny Lee Ray Chason Boudewijn Waijers Jon W{tte Richard Addison Bruce Cox Jonathan Handler Richard Beigel Bruce Holloway Joshua Delahunty Richard P. Hughey Bruce Mewborne Keizo Yamamoto Rob Menke Carl Schelin Ken Arnold Robin Bandy Chris Russo Ken Arromdee Robin Johnson David Cohrs Ken Lorber Roderick Schertler David Damerell Ken Washikita Roland McGrath David Gentzel Kevin Darcy Ron Van Iwaarden David Hairston Kevin Hugo Ronnen Miller Dean Luick Kevin Sitze Ross Brown Del Lamb Kevin Smolkowski Sascha Wostmann Derek S. Ray Kevin Sweet Scott Bigham Deron Meranda Lars Huttar Scott R. Turner Dion Nicolaas Leon Arnott Sean Hunt Dylan O'Donnell M. Drew Streib Stephen Spackman Eric Backus Malcolm Ryan Stefan Thielscher Eric Hendrickson Mark Gooderum Stephen White Eric R. Smith Mark Modrall Steve Creps Eric S. Raymond Marvin Bressler Steve Linhart Erik Andersen Matthew Day Steve VanDevender Frederick Roeber Merlyn LeRoy Teemu Suikki Gil Neiger Michael Allison Tim Lennan Greg Laskin Michael Feir Timo Hakulinen Greg Olson Michael Hamel Tom Almy Gregg Wonderly Michael Sokolov Tom West Hao-yang Wang Mike Engber Warren Cheung Helge Hafting Mike Gallop Warwick Allison Irina Rempt-Drijfhout Mike Passaretti Yitzhak Sapir Izchak Miller Mike Stephenson J. Ali Harlow Mikko Juola nethack-3.6.0/dat/knox.des0000664000076400007660000001026612536476415014403 0ustar paxedpaxed# NetHack 3.6 knox.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992 by Izchak Miller # NetHack may be freely redistributed. See license for details. # MAZE:"knox",' ' FLAGS: noteleport GEOMETRY:center,center MAP ---------------------------------------------------------------------------- | |........|...............................................................| | |........|.................................................------------..| | -------+--.................................................|..........|..| | |........}}}}}}}....................}}}}}}}..........|..........|..| | |........}-----}....................}-----}..........--+--+--...|..| | ---........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..| | |..........}---S------------------------S---}.................|...|..| | |..........}}}|...............|..........|}}}.................+...|..| | -------..........}|...............S..........|}...................|...|..| | |.....|..........}|...............|......\...S}...................|...|..| | |.....+........}}}|...............|..........|}}}.................+...|..| | |.....|........}---S------------------------S---}.................|...|..| | |.....|........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..| | |..-S----......}-----}....................}-----}..........--+--+--...|..| | |..|....|......}}}}}}}....................}}}}}}}..........|..........|..| | |..|....|..................................................|..........|..| | -----------................................................------------..| | |..............................................................| ---------------------------------------------------------------------------- ENDMAP # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Portal arrival point BRANCH:(08,16,08,16),(0,0,0,0) # accessible via ^V in wizard mode; arrive near the portal TELEPORT_REGION:(06,16,09,17),(0,0,0,0),up TELEPORT_REGION:(06,16,09,17),(0,0,0,0),down # Throne room, with Croesus on the throne REGION:(37,08,46,11),lit,"throne" MONSTER:('@',"Croesus"),(43,10),hostile # The Vault # Using unfilled morgue for # identification in mkmaze.c REGION:(21,08,35,11),lit,"morgue",unfilled # Corner towers REGION:(19,06,21,06),lit,"ordinary" REGION:(46,06,48,06),lit,"ordinary" REGION:(19,13,21,13),lit,"ordinary" REGION:(46,13,48,13),lit,"ordinary" # A welcoming committee REGION:(03,10,07,13),lit,"zoo",filled,irregular # arrival chamber; needs to be a real room to control migrating monsters, # and `unfilled' is a kludge to force an ordinary room to remain a room REGION:(06,15,09,16),unlit,"ordinary",unfilled # Barracks REGION:(62,03,71,04),lit,"barracks",filled,irregular # Doors DOOR:closed,(06,14) DOOR:closed,(09,03) DOOR:open,(63,05) DOOR:open,(66,05) DOOR:open,(68,08) DOOR:locked,(08,11) DOOR:open,(68,11) DOOR:closed,(63,14) DOOR:closed,(66,14) # Soldiers guarding the fort MONSTER:('@',"soldier"),(12,14) MONSTER:('@',"soldier"),(12,13) MONSTER:('@',"soldier"),(11,10) MONSTER:('@',"soldier"),(13,02) MONSTER:('@',"soldier"),(14,03) MONSTER:('@',"soldier"),(20,02) MONSTER:('@',"soldier"),(30,02) MONSTER:('@',"soldier"),(40,02) MONSTER:('@',"soldier"),(30,16) MONSTER:('@',"soldier"),(32,16) MONSTER:('@',"soldier"),(40,16) MONSTER:('@',"soldier"),(54,16) MONSTER:('@',"soldier"),(54,14) MONSTER:('@',"soldier"),(54,13) MONSTER:('@',"soldier"),(57,10) MONSTER:('@',"soldier"),(57,09) MONSTER:('@',"lieutenant"),(15,08) # Four dragons guarding each side MONSTER:'D',(18,09) MONSTER:'D',(49,10) MONSTER:'D',(33,05) MONSTER:'D',(33,14) # Eels in the moat MONSTER:(';',"giant eel"),(17,08) MONSTER:(';',"giant eel"),(17,11) MONSTER:(';',"giant eel"),(48,08) MONSTER:(';',"giant eel"),(48,11) # The corner rooms treasures OBJECT:('*',"diamond"),(19,06) OBJECT:('*',"diamond"),(20,06) OBJECT:('*',"diamond"),(21,06) OBJECT:('*',"emerald"),(19,13) OBJECT:('*',"emerald"),(20,13) OBJECT:('*',"emerald"),(21,13) OBJECT:('*',"ruby"),(46,06) OBJECT:('*',"ruby"),(47,06) OBJECT:('*',"ruby"),(48,06) OBJECT:('*',"amethyst"),(46,13) OBJECT:('*',"amethyst"),(47,13) OBJECT:('*',"amethyst"),(48,13) nethack-3.6.0/dat/license0000664000076400007660000001141312467321052014254 0ustar paxedpaxed NETHACK GENERAL PUBLIC LICENSE (Copyright 1989 M. Stephenson) (Based on the BISON general public license, copyright 1988 Richard M. Stallman) Everyone is permitted to copy and distribute verbatim copies of this license, but changing it is not allowed. You can also use this wording to make the terms for other programs. The license agreements of most software companies keep you at the mercy of those companies. By contrast, our general public license is intended to give everyone the right to share NetHack. To make sure that you get the rights we want you to have, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. Hence this license agreement. Specifically, we want to make sure that you have the right to give away copies of NetHack, that you receive source code or else can get it if you want it, that you can change NetHack or use pieces of it in new free programs, and that you know you can do these things. To make sure that everyone has such rights, we have to forbid you to deprive anyone else of these rights. For example, if you distribute copies of NetHack, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. Also, for our own protection, we must make certain that everyone finds out that there is no warranty for NetHack. If NetHack is modified by someone else and passed on, we want its recipients to know that what they have is not what we distributed. Therefore we (Mike Stephenson and other holders of NetHack copyrights) make the following terms which say what you must do to be allowed to distribute or change NetHack. COPYING POLICIES 1. You may copy and distribute verbatim copies of NetHack source code as you receive it, in any medium, provided that you keep intact the notices on all files that refer to copyrights, to this License Agreement, and to the absence of any warranty; and give any other recipients of the NetHack program a copy of this License Agreement along with the program. 2. You may modify your copy or copies of NetHack or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above (including distributing this License Agreement), provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains or is a derivative of NetHack or any part thereof, to be licensed at no charge to all third parties on terms identical to those contained in this License Agreement (except that you may choose to grant more extensive warranty protection to some or all third parties, at your option) c) You may charge a distribution fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 3. You may copy and distribute NetHack (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with full information as to how to obtain the complete machine-readable source code from an appropriate archive site. (This alternative is allowed only for noncommercial distribution.) For these purposes, complete source code means either the full source distribution as originally released over Usenet or updated copies of the files in this distribution used to create the object code or executable. 4. You may not copy, sublicense, distribute or transfer NetHack except as expressly provided under this License Agreement. Any attempt otherwise to copy, sublicense, distribute or transfer NetHack is void and your rights to use the program under this License agreement shall be automatically terminated. However, parties who have received computer software programs from you with this License Agreement will not have their licenses terminated so long as such parties remain in full compliance. Stated plainly: You are permitted to modify NetHack, or otherwise use parts of NetHack, provided that you comply with the conditions specified above; in particular, your modified NetHack or program containing parts of NetHack must remain freely available as provided in this License Agreement. In other words, go ahead and share NetHack, but don't try to stop anyone else from sharing it farther. nethack-3.6.0/dat/medusa.des0000664000076400007660000003614012536476415014701 0ustar paxedpaxed# NetHack 3.6 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1990, 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # These are the Medusa's levels : # MAZE:"medusa-1",' ' FLAGS: noteleport GEOMETRY:center,center MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}.}}}}}..}}}}}......}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}....}}}...}}}}} }...}}.....}}}}}....}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}...............} }....}}}}}}}}}}....}}}..}}}}}}}}}}}.......}}}}}}}}}}}}}}}}..}}.....}}}...}} }....}}}}}}}}.....}}}}..}}}}}}.................}}}}}}}}}}}.}}}}.....}}...}} }....}}}}}}}}}}}}.}}}}.}}}}}}.-----------------.}}}}}}}}}}}}}}}}}.........} }....}}}}}}}}}}}}}}}}}}.}}}...|...............S...}}}}}}}}}}}}}}}}}}}....}} }.....}.}}....}}}}}}}}}.}}....--------+--------....}}}}}}..}}}}}}}}}}}...}} }......}}}}..}}}}}}}}}}}}}........|.......|........}}}}}....}}}}}}}}}}}}}}} }.....}}}}}}}}}}}}}}}}}}}}........|.......|........}}}}}...}}}}}}}}}.}}}}}} }.....}}}}}}}}}}}}}}}}}}}}....--------+--------....}}}}}}.}.}}}}}}}}}}}}}}} }......}}}}}}}}}}}}}}}}}}}}...S...............|...}}}}}}}}}}}}}}}}}.}}}}}}} }.......}}}}}}}..}}}}}}}}}}}}.-----------------.}}}}}}}}}}}}}}}}}....}}}}}} }........}}.}}....}}}}}}}}}}}}.................}}}}}..}}}}}}}}}.......}}}}} }.......}}}}}}}......}}}}}}}}}}}}}}.......}}}}}}}}}.....}}}}}}...}}..}}}}}} }.....}}}}}}}}}}}.....}}}}}}}}}}}}}}}}}}}}}}.}}}}}}}..}}}}}}}}}}....}}}}}}} }}..}}}}}}}}}}}}}....}}}}}}}}}}}}}}}}}}}}}}...}}..}}}}}}}.}}.}}}}..}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP # Dungeon Description # (must maintain one room definition; `unfilled' forces its room to be kept) REGION:(00,00,74,19),lit,"ordinary" REGION:(31,07,45,07),unlit,"ordinary" REGION:(35,09,41,10),unlit,"ordinary",unfilled REGION:(31,12,45,12),unlit,"ordinary" # Teleport: down to up stairs island, up to Medusa's island TELEPORT_REGION:(01,01,05,17),(0,0,0,0),down TELEPORT_REGION:(26,04,50,15),(0,0,0,0),up # Stairs STAIR:(05,14),up STAIR:(36,10),down # Doors DOOR:closed,(46,07) DOOR:locked,(38,08) DOOR:locked,(38,11) DOOR:closed,(30,12) # Branch, not allowed inside Medusa's building. BRANCH:levregion(01,00,79,20),(30,06,46,13) # Non diggable walls NON_DIGGABLE:(30,06,46,13) # Objects CONTAINER:('`',"statue"),(36,10),uncursed,montype:"knight",3,name:"Perseus" { [75%]: OBJECT:('[',"shield of reflection"),cursed,+0 [25%]: OBJECT:('[',"levitation boots"),+0 [50%]: OBJECT:(')',"scimitar"),blessed,+2 [50%]: OBJECT:('(',"sack") } # These aren't really containers, but specifying CONTAINER forces them to be # empty, since CONTAINERs contain only what is explicitly specified. CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:"board",(38,07) TRAP:"board",(38,12) # Random monsters MONSTER:('@',"Medusa"),(36,10),asleep MONSTER:(';',"giant eel"),(11,06) MONSTER:(';',"giant eel"),(23,13) MONSTER:(';',"giant eel"),(29,02) MONSTER:(';',"jellyfish"),(02,02) MONSTER:(';',"jellyfish"),(00,08) MONSTER:(';',"jellyfish"),(04,18) MONSTER:('T',"water troll"),(51,03) MONSTER:('T',"water troll"),(64,11) MONSTER:'S',(38,07) MONSTER:'S',(38,12) MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MAZE:"medusa-2",' ' FLAGS: noteleport GEOMETRY:center,center MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------}}}}}}}}--------------} }|....|}}}}}}}}}..}.}}..}}}}}}}}}}}}}..}}}}}}-.....--}}}}}}}|............|} }|....|.}}}}}}}}}}}.}...}}..}}}}}}}}}}}}}}}}}---......}}}}}.|............|} }S....|.}}}}}}---}}}}}}}}}}}}}}}}}}}}}}}}}}---...|..-}}}}}}.S..----------|} }|....|.}}}}}}-...}}}}}}}}}.}}...}.}}}}.}}}......----}}}}}}.|............|} }|....|.}}}}}}-....--}}}}}}}}}}}}}}}}}}}}}}----...--}}}}}}}.|..--------+-|} }|....|.}}}}}}}......}}}}...}}}}}}.}}}}}}}}}}}---..---}}}}}.|..|..S...|..|} }|....|.}}}}}}-....-}}}}}}}------}}}}}}}}}}}}}}-...|.-}}}}}.|..|..|...|..|} }|....|.}}}}}}}}}---}}}}}}}........}}}}}}}}}}---.|....}}}}}.|..|..|...|..|} }|....|.}}}}}}}}}}}}}}}}}}-....|...-}}}}}}}}--...----.}}}}}.|..|..|...|..|} }|....|.}}}}}}..}}}}}}}}}}---..--------}}}}}-..---}}}}}}}}}.|..|..-------|} }|...}|...}}}.}}}}}}...}}}}}--..........}}}}..--}}}}}}}}}}}.|..|.........|} }|...}S...}}.}}}}}}}}}}}}}}}-..--------}}}}}}}}}}}}}}...}}}.|..--------..S} }|...}|...}}}}}}}..}}}}}}----..|....-}}}}}}}}}}}}}}}}}..}}}.|............|} }|....|}}}}}....}}}}..}}.-.......----}}......}}}}}}.......}}|............|} }------}}}}}}}}}}}}}}}}}}---------}}}}}}}}}}}}}}}}}}}}}}}}}}--------------} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP # Dungeon Description REGION:(00,00,74,19),lit,"ordinary" REGION:(02,03,05,16),unlit,"ordinary" REGION:(61,03,72,16),unlit,"ordinary",unfilled,irregular REGION:(71,08,72,11),unlit,"ordinary" REGION:(67,08,69,11),lit,"ordinary" # Teleport: down to up stairs island, up to Medusa's island TELEPORT_REGION:(02,03,05,16),(0,0,0,0),down TELEPORT_REGION:(61,03,72,16),(0,0,0,0),up # Stairs STAIR:(04,09),up STAIR:(68,10),down # Doors DOOR:locked,(71,07) # Branch, not allowed on Medusa's island. BRANCH:levregion(01,00,79,20),(59,01,73,17) # Non diggable walls NON_DIGGABLE:(01,02,06,17) NON_DIGGABLE:(60,02,73,17) # Objects CONTAINER:('`',"statue"),(68,10),uncursed,montype:"knight",3,name:"Perseus" { [25%]: OBJECT:('[',"shield of reflection"),cursed,+0 [75%]: OBJECT:('[',"levitation boots"),+0 [50%]: OBJECT:(')',"scimitar"),blessed,+2 [50%]: OBJECT:('(',"sack") } CONTAINER:('`',"statue"),(64,08) { } CONTAINER:('`',"statue"),(65,08) { } CONTAINER:('`',"statue"),(64,09) { } CONTAINER:('`',"statue"),(65,09) { } CONTAINER:('`',"statue"),(64,10) { } CONTAINER:('`',"statue"),(65,10) { } CONTAINER:('`',"statue"),(64,11) { } CONTAINER:('`',"statue"),(65,11) { } OBJECT:('`',"boulder"),(04,04) OBJECT:'/',(52,09) OBJECT:('`',"boulder"),(52,09) OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Traps TRAP:"magic",(03,12) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters. MONSTER:('@',"Medusa"),(68,10),asleep MONSTER:('g',"gremlin"),(02,14) MONSTER:('H',"titan"),(02,05) MONSTER:(';',"electric eel"),(10,13) MONSTER:(';',"electric eel"),(11,13) MONSTER:(';',"electric eel"),(10,14) MONSTER:(';',"electric eel"),(11,14) MONSTER:(';',"electric eel"),(10,15) MONSTER:(';',"electric eel"),(11,15) MONSTER:(';',"jellyfish"),(01,01) MONSTER:(';',"jellyfish"),(00,08) MONSTER:(';',"jellyfish"),(04,19) MONSTER:(''',"stone golem"),(64,08),asleep MONSTER:(''',"stone golem"),(65,08),asleep MONSTER:(''',"stone golem"),(64,09),asleep MONSTER:(''',"stone golem"),(65,09),asleep MONSTER:('S',"cobra"),(64,10),asleep MONSTER:('S',"cobra"),(65,10),asleep MONSTER:'A',(72,08) MONSTER:('y',"yellow light"),(72,11),asleep MONSTER:random,(17,07) MONSTER:random,(28,11) MONSTER:random,(32,13) MONSTER:random,(49,09) MONSTER:random,(48,07) MONSTER:random,(65,03) MONSTER:random,(70,04) MONSTER:random,(70,15) MONSTER:random,(65,16) MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random LEVEL:"medusa-3" FLAGS: noteleport,mazelevel INIT_MAP:solidfill,' ' GEOMETRY:center,center # # Here you disturb ravens nesting in the trees. # MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}.}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}.}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}T..T.}}}}}}}}}}}}}}}}}}}}..}}}}}}}}.}}}...}}}}}}}.}}}}}......}}}}}}} }}}}}}.......T.}}}}}}}}}}}..}}}}..T.}}}}}}...T...T..}}...T..}}..-----..}}}}} }}}...-----....}}}}}}}}}}.T..}}}}}...}}}}}.....T..}}}}}......T..|...|.T..}}} }}}.T.|...|...T.}}}}}}}.T......}}}}..T..}}.}}}.}}...}}}}}.T.....+...|...}}}} }}}}..|...|.}}.}}}}}.....}}}T.}}}}.....}}}}}}.T}}}}}}}}}}}}}..T.|...|.}}}}}} }}}}}.|...|.}}}}}}..T..}}}}}}}}}}}}}T.}}}}}}}}..}}}}}}}}}}}.....-----.}}}}}} }}}}}.--+--..}}}}}}...}}}}}}}}}}}}}}}}}}}T.}}}}}}}}}}}}}}}}.T.}........}}}}} }}}}}.......}}}}}}..}}}}}}}}}.}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}.}}}.}}.T.}}}}}} }}.T...T...}}}}T}}}}}}}}}}}....}}}}}}}}}}T}}}}}.T}}...}}}}}}}}}}}}}}...}}}}} }}}...T}}}}}}}..}}}}}}}}}}}.T...}}}}}}}}.T.}.T.....T....}}}}}}}}}}}}}.}}}}}} }}}}}}}}}}}}}}}....}}}}}}}...}}.}}}}}}}}}}............T..}}}}}.T.}}}}}}}}}}} }}}}}}}}}}}}}}}}..T..}}}}}}}}}}}}}}..}}}}}..------+--...T.}}}....}}}}}}}}}}} }}}}.}..}}}}}}}.T.....}}}}}}}}}}}..T.}}}}.T.|...|...|....}}}}}.}}}}}...}}}}} }}}.T.}...}..}}}}T.T.}}}}}}.}}}}}}}....}}...|...+...|.}}}}}}}}}}}}}..T...}}} }}}}..}}}.....}}...}}}}}}}...}}}}}}}}}}}}}T.|...|...|}}}}}}}}}}}....T..}}}}} }}}}}..}}}.T..}}}.}}}}}}}}.T..}}}}}}}}}}}}}}---S-----}}}}}}}}}}}}}....}}}}}} }}}}}}}}}}}..}}}}}}}}}}}}}}}.}}}}}}}}}}}}}}}}}T..T}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP $place = { (08,06),(66,05),(46,15) } SHUFFLE: $place REGION:(00,00,74,19),lit,"ordinary" REGION:(49,14,51,16),random,"ordinary",unfilled REGION:(07,05,09,07),unlit,"ordinary" REGION:(65,04,67,06),unlit,"ordinary" REGION:(45,14,47,16),unlit,"ordinary" # Non diggable walls # 4th room has diggable walls as Medusa is never placed there NON_DIGGABLE:(06,04,10,08) NON_DIGGABLE:(64,03,68,07) NON_DIGGABLE:(44,13,48,17) # All places are accessible also with jumping, so don't bother # restricting the placement when teleporting from levels below this. TELEPORT_REGION:(33,02,38,07),(0,0,0,0),down STAIR:(32,01,39,07),(0,0,0,0),up STAIR:$place[0],down DOOR:locked,(08,08) DOOR:locked,(64,05) DOOR:random,(50,13) DOOR:locked,(48,15) # FOUNTAIN:$place[1] # CONTAINER:('`',"statue"),$place[2],uncursed,montype:"knight",3,name:"Perseus" { [75%]: OBJECT: ('[',"shield of reflection"),cursed,+0 [25%]: OBJECT: ('[',"levitation boots"),+0 [50%]: OBJECT: (')',"scimitar"),blessed,+2 [50%]: OBJECT: ('(',"sack") } # CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } LOOP [8] { OBJECT:random,random } OBJECT:('?',"blank paper"),(48,18) OBJECT:('?',"blank paper"),(48,18) # TRAP:"rust",random TRAP:"rust",random TRAP:"board",random TRAP:"board",random TRAP:random,random # MONSTER:('@',"Medusa"),$place[0] MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"jellyfish"),random MONSTER:(';',"jellyfish"),random MONSTER:('n',"wood nymph"),random MONSTER:('n',"wood nymph"),random MONSTER:('n',"water nymph"),random MONSTER:('n',"water nymph"),random LOOP [30] { MONSTER:('B',"raven"),random,hostile } LEVEL:"medusa-4" FLAGS: noteleport,mazelevel INIT_MAP:solidfill,' ' GEOMETRY:center,center # # Here the Medusa rules some slithery monsters from her 'palace', with # a yellow dragon nesting in the backyard. # MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}........}}}}}}}}}}}}}}}}}}}}}}}..}}}.....}}}}}}}}}}}----|}}}}} }}}}}}..----------F-.....}}}}}}}}}}}}}}}}..---...}}}}....T.}}}}}}}....|}}}}} }}}.....|...F......S}}}}....}}}}}}}...}}.....|}}.}}}}}}}......}}}}|......}}} }}}.....+...|..{...|}}}}}}}}}}}}.....}}}}|...|}}}}}}}}}}}.}}}}}}}}----.}}}}} }}......|...|......|}}}}}}}}}......}}}}}}|.......}}}}}}}}}}}}}..}}}}}...}}}} }}|-+--F|-+--....|F|-|}}}}}....}}}....}}}-----}}.....}}}}}}}......}}}}.}}}}} }}|...}}|...|....|}}}|}}}}}}}..}}}}}}}}}}}}}}}}}}}}....}}}}}}}}....T.}}}}}}} }}|...}}F...+....F}}}}}}}..}}}}}}}}}}}}}}...}}}}}}}}}}}}}}}}}}}}}}....}}..}} }}|...}}|...|....|}}}|}....}}}}}}....}}}...}}}}}...}}}}}}}}}}}}}}}}}.....}}} }}--+--F|-+--....-F|-|....}}}}}}}}}}.T...}}}}....---}}}}}}}}}}}}}}}}}}}}}}}} }}......|...|......|}}}}}.}}}}}}}}}....}}}}}}}.....|}}}}}}}}}.}}}}}}}}}}}}}} }}}}....+...|..{...|.}}}}}}}}}}}}}}}}}}}}}}}}}}.|..|}}}}}}}......}}}}...}}}} }}}}}}..|...F......|...}}}}}}}}}}..---}}}}}}}}}}--.-}}}}}....}}}}}}....}}}}} }}}}}}}}-----S----F|....}}}}}}}}}|...|}}}}}}}}}}}}...}}}}}}...}}}}}}..}}}}}} }}}}}}}}}..............T...}}}}}.|.......}}}}}}}}}}}}}}..}...}.}}}}....}}}}} }}}}}}}}}}....}}}}...}...}}}}}.......|.}}}}}}}}}}}}}}.......}}}}}}}}}...}}}} }}}}}}}}}}..}}}}}}}}}}.}}}}}}}}}}-..--.}}}}}}}}..}}}}}}..T...}}}..}}}}}}}}}} }}}}}}}}}...}}}}}}}}}}}}}}}}}}}}}}}...}}}}}}}....}}}}}}}.}}}..}}}...}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}.}}}}}}....}}}}}}}}}}}}}}}}}}}...}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP # $place = { (04,08),(10,04),(10,08),(10,12) } SHUFFLE: $place # REGION:(00,00,74,19),lit,"ordinary" REGION:(13,03,18,13),lit,"ordinary",unfilled # TELEPORT_REGION:(64,01,74,17),(0,0,0,0),down TELEPORT_REGION:(02,02,18,13),(0,0,0,0),up # STAIR:(67,01,74,20),(0,0,0,0),up STAIR:$place[0],down # DOOR:locked,(04,06) DOOR:locked,(04,10) DOOR:locked,(08,04) DOOR:locked,(08,12) DOOR:locked,(10,06) DOOR:locked,(10,10) DOOR:locked,(12,08) # BRANCH:levregion(27,00,79,20),(0,0,0,0) # NON_DIGGABLE:(01,01,22,14) # OBJECT:('(',"crystal ball"),(07,08) # CONTAINER:('`',"statue"),$place[1],uncursed,montype:"knight",3,name:"Perseus" { [75%]: OBJECT: ('[',"shield of reflection"),cursed,+0 [25%]: OBJECT: ('[',"levitation boots"),+0 [50%]: OBJECT: (')',"scimitar"),blessed,+2 [50%]: OBJECT: ('(',"sack") } # CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } CONTAINER:('`',"statue"),random { } LOOP [8] { OBJECT:random,random } # LOOP [7] { TRAP:random,random } # MONSTER:('@',"Medusa"),$place[0] MONSTER:(';',"kraken"),(07,07) # # the nesting dragon MONSTER:('D',"yellow dragon"), (05,04), asleep [50%]: MONSTER: ('D',"baby yellow dragon"), (04,04), asleep [25%]: MONSTER: ('D',"baby yellow dragon"), (04,05), asleep OBJECT:('%',"egg"), (05,04), montype:"yellow dragon" [50%]: OBJECT: ('%',"egg"), (05,04), montype:"yellow dragon" [25%]: OBJECT: ('%',"egg"), (05,04), montype:"yellow dragon" # MONSTER:(';',"giant eel"),random MONSTER:(';',"giant eel"),random MONSTER:(';',"jellyfish"),random MONSTER:(';',"jellyfish"),random LOOP [14] { MONSTER:'S',random } LOOP [4] { MONSTER:('N',"black naga hatchling"), random MONSTER:('N',"black naga"), random } nethack-3.6.0/dat/mines.des0000664000076400007660000010151712621207145014522 0ustar paxedpaxed# NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ # Copyright (c) 1989-95 by Jean-Christophe Collet # Copyright (c) 1991-95 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "fill" level for the mines. # # This level is used to fill out any levels not occupied by # specific levels as defined below. # MAZE: "minefill" , ' ' INIT_MAP: mines, '.' , ' ' , true , true , random , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: '*', random OBJECT: '*', random OBJECT: '*', random OBJECT: '(', random OBJECT: random, random OBJECT: random, random OBJECT: random, random # MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome lord"), random MONSTER: ('h', "dwarf"), random MONSTER: ('h', "dwarf"), random MONSTER: 'G', random MONSTER: 'G', random MONSTER: 'h', random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # A tragic accident has occurred in Frontier Town.... # # Minetown variant 1 # Orcish Town - a variant of Frontier Town that has been # overrun by orcs. Note the barricades (iron bars). # LEVEL: "minetn-1" FLAGS:mazelevel INIT_MAP:mines,'.',' ',true,true,random,true GEOMETRY:center,center MAP ..................................... .----------------F------------------. .|.................................|. .|.-------------......------------.|. .|.|...|...|...|......|..|...|...|.|. .F.|...|...|...|......|..|...|...|.|. .|.|...|...|...|......|..|...|...|.F. .|.|...|...|----......------------.|. .|.---------.......................|. .|.................................|. .|.---------.....--...--...........|. .|.|...|...|----.|.....|.---------.|. .|.|...|...|...|.|.....|.|..|....|.|. .|.|...|...|...|.|.....|.|..|....|.|. .|.|...|...|...|.|.....|.|..|....|.|. .|.-------------.-------.---------.|. .|.................................F. .-----------F------------F----------. ..................................... ENDMAP # Don't let the player fall into his likely death TELEPORT_REGION:levregion(01,01,20,19),levregion(20,00,70,19) REGION:(00,00,36,16),lit,"ordinary" STAIR:levregion(01,03,20,19),(00,00,36,15),up STAIR:levregion(61,03,75,19),(00,00,36,15),down # shame we can't make polluted fountains FOUNTAIN:(16,09) FOUNTAIN:(25,09) # the altar's defiled; useful for BUC but never coaligned ALTAR:(20,13),noalign,shrine # set up the shop doors; could be broken down DOOR:random,(5,8) DOOR:random,(9,8) DOOR:random,(13,7) DOOR:random,(22,5) DOOR:random,(27,7) DOOR:random,(31,7) DOOR:random,(5,10) DOOR:random,(9,10) DOOR:random,(15,13) DOOR:random,(25,13) DOOR:random,(31,11) # knock a few holes in the shop interior walls REPLACE_TERRAIN:(07,04,11,06),'|','.',18% REPLACE_TERRAIN:(25,04,29,06),'|','.',18% REPLACE_TERRAIN:(07,12,11,14),'|','.',18% REPLACE_TERRAIN:(28,12,28,14),'|','.',33% # One spot each in most shops... $place = { (05,04),(09,05),(13,04),(26,04),(31,05),(30,14),(05,14),(10,13),(26,14),(27,13) } SHUFFLE:$place # scatter some bodies OBJECT:('%',"corpse"),(20,12),montype:"aligned priest" OBJECT:('%',"corpse"),$place[0],montype:"shopkeeper" OBJECT:('%',"corpse"),$place[1],montype:"shopkeeper" OBJECT:('%',"corpse"),$place[2],montype:"shopkeeper" OBJECT:('%',"corpse"),$place[3],montype:"shopkeeper" OBJECT:('%',"corpse"),$place[4],montype:"shopkeeper" OBJECT:('%',"corpse"),random,montype:"watchman" OBJECT:('%',"corpse"),random,montype:"watchman" OBJECT:('%',"corpse"),random,montype:"watchman" OBJECT:('%',"corpse"),random,montype:"watchman" OBJECT:('%',"corpse"),random,montype:"watch captain" # Rubble! LOOP [9 + 2d5] { [90%]: OBJECT:('`',"boulder"),random OBJECT:('*',"rock"),random } # Guarantee 7 candles since we won't have Izchak available OBJECT:('(',"wax candle"),$place[0],quantity:1d2 OBJECT:('(',"wax candle"),$place[1],quantity:2d2 OBJECT:('(',"wax candle"),$place[2],quantity:1d2 OBJECT:('(',"tallow candle"),$place[3],quantity:1d3 OBJECT:('(',"tallow candle"),$place[2],quantity:1d2 OBJECT:('(',"tallow candle"),$place[0],quantity:1d2 # go ahead and leave a lamp next to one corpse to be suggestive # and some empty wands... OBJECT:('(',"oil lamp"),$place[2] OBJECT:('/',"striking"),$place[1],uncursed,0 OBJECT:('/',"striking"),$place[3],uncursed,0 OBJECT:('/',"striking"),$place[4],uncursed,0 OBJECT:('/',"magic missile"),$place[4],uncursed,0 OBJECT:('/',"magic missile"),$place[0],uncursed,0 # the Orcish Army $inside = selection: floodfill(18,8) $near_temple = selection: filter(fillrect(17,8, 23,14), $inside) LOOP [5 + 1d10] { IF [50%] { MONSTER: ('o', "orc-captain"), rndcoord($inside), hostile } ELSE { IF [80%] { MONSTER: ('o', "Uruk-hai"), rndcoord($inside), hostile } ELSE { MONSTER: ('o', "Mordor orc"), rndcoord($inside), hostile } } } # shamans can be hanging out in/near the temple LOOP [2d3] { MONSTER: ('o', "orc shaman"), rndcoord($near_temple), hostile } # these are not such a big deal # to run into outside the bars LOOP [9 + 2d5] { IF [90%] { MONSTER: ('o', "hill orc"), random, hostile } ELSE { MONSTER: ('o', "goblin"), random, hostile } } # Hack to force full-level wallification NOMAP WALLIFY # Minetown variant 2 # "Town Square" # LEVEL: "minetn-2" ROOM: "ordinary" , lit, (3,3), (center,center), (31,15) { FOUNTAIN: (17, 5) FOUNTAIN: (13, 8) [75%]: SUBROOM: "ordinary", random, (2,0), (2,2) { ROOMDOOR: false, closed, west, random } [75%]: SUBROOM: "ordinary", unlit, (5,0), (2,2) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", random, (8,0), (2,2) { ROOMDOOR: false, closed, east, random } [75%]: SUBROOM: "ordinary", lit, (16,0), (2,2) { ROOMDOOR: false, closed, west, random } [75%]: SUBROOM: "ordinary", unlit, (19,0), (2,2) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", random, (22,0), (2,2) { ROOMDOOR: false, locked, south, random MONSTER: ('G', "gnome"), random } [75%]: SUBROOM: "ordinary", unlit, (25,0), (2,2) { ROOMDOOR: false, closed, east, random } [75%]: SUBROOM: "ordinary", lit, (2,5), (2,2) { ROOMDOOR: false, closed, north, random } [75%]: SUBROOM: "ordinary", lit, (5,5), (2,2) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", random, (8,5), (2,2) { ROOMDOOR: false, locked, north, random MONSTER: ('G', "gnome"), random } SUBROOM: "shop" [90%] , lit, (2,10), (4,3) { ROOMDOOR: false, closed, west, random } SUBROOM: "tool shop" [90%], lit, (23,10), (4,3) { ROOMDOOR: false, closed, east, random } SUBROOM: "food shop" [90%], lit, (24,5), (3,4) { ROOMDOOR: false, closed, north, random } SUBROOM: "candle shop", lit, (11,10), (4,3) { ROOMDOOR: false, closed, east, random } [75%]: SUBROOM: "ordinary", unlit, (7,10), (3,3) { ROOMDOOR: false, locked, north, random MONSTER: ('G', "gnome"), random } SUBROOM: "temple", lit, (19,5), (4,4) { ROOMDOOR: false, closed, north, random ALTAR:(02,02),align[0],shrine MONSTER: ('G', "gnomish wizard"), random MONSTER: ('G', "gnomish wizard"), random } [75%]: SUBROOM: "ordinary", lit, (18,10), (4,3) { ROOMDOOR: false, locked, west, random MONSTER: ('G', "gnome lord"), random } # The Town Watch MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful } ROOM: "ordinary" , random, random, random, random { STAIR: random, up } ROOM: "ordinary" , random, random, random, random { STAIR: random, down TRAP: random, random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random } ROOM: "ordinary" , random, random, random, random { MONSTER: ('h', "dwarf"), random } ROOM: "ordinary" , random, random, random, random { TRAP: random, random MONSTER: ('G', "gnome"), random } RANDOM_CORRIDORS # Minetown variant 3 by Kelly Bailey # "Alley Town" # LEVEL: "minetn-3" ROOM: "ordinary",lit,(3,3),(center,center),(31,15) { FOUNTAIN:(01,06) FOUNTAIN:(29,13) SUBROOM:"ordinary",random,(2,2),(2,2) { ROOMDOOR: false,closed,south,random } SUBROOM:"tool shop" [30%], lit,(5,3),(2,3) { ROOMDOOR: false,closed,south,random } SUBROOM:"ordinary",random,(2,10),(2,3) { ROOMDOOR: false, locked, north, random MONSTER: 'G',random } SUBROOM:"ordinary",random,(5,9),(2,2) { ROOMDOOR: false,closed,north,random } SUBROOM:"temple",lit,(10,2),(3,4) { ROOMDOOR: false,closed,east,random ALTAR:(1,1),align[0],shrine MONSTER: ('G', "gnomish wizard"), random MONSTER: ('G', "gnomish wizard"), random } SUBROOM:"ordinary",random,(11,7),(2,2) { ROOMDOOR: false,closed,west,random } SUBROOM:"shop",lit,(10,10),(3,3) { ROOMDOOR:false,closed,west,random } SUBROOM:"ordinary",random,(14,8),(2,2) { ROOMDOOR:false,locked,north,random MONSTER: 'G',random } SUBROOM:"ordinary",random,(14,11),(2,2) { ROOMDOOR:false,closed,south,random } SUBROOM:"tool shop" [40%],lit,(17,10),(3,3) { ROOMDOOR:false,closed,north,random } SUBROOM:"ordinary",random,(21,11),(2,2) { ROOMDOOR:false,locked,east,random MONSTER:'G',random } SUBROOM:"food shop" [90%],lit,(26,8),(3,2) { ROOMDOOR:false,closed,west,random } SUBROOM:"ordinary",random,(16,2),(2,2) { ROOMDOOR:false,closed,west,random } SUBROOM:"ordinary",random,(19,2),(2,2) { ROOMDOOR:false,closed,north,random } SUBROOM:"wand shop" [30%],lit,(19,5),(3,2) { ROOMDOOR:false,closed,west,random } SUBROOM: "candle shop",lit,(25,2),(3,3) { ROOMDOOR:false,closed,south,random } MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful } ROOM: "ordinary", random, random, random, random { STAIR: random, up } ROOM: "ordinary" , random, random, random, random { STAIR: random, down TRAP: random, random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random } ROOM: "ordinary" , random, random, random, random { MONSTER: ('h', "dwarf"), random } ROOM: "ordinary" , random, random, random, random { TRAP: random, random MONSTER: ('G', "gnome"), random } RANDOM_CORRIDORS # Minetown variant 4 by Kelly Bailey # "College Town" # LEVEL: "minetn-4" ROOM: "ordinary",lit,(3,3),(center,center),(30,15) { FOUNTAIN:(08,07) FOUNTAIN:(18,07) SUBROOM:"book shop",lit,(4,2),(3,3) { ROOMDOOR: false,closed,south,random } SUBROOM:"ordinary",random,(8,2),(2,2) { ROOMDOOR: false,closed,south,random } SUBROOM:"temple",lit,(11,3),(5,4) { ROOMDOOR: false,closed,south,random ALTAR:(2,1),align[0],shrine MONSTER: ('G', "gnomish wizard"), random MONSTER: ('G', "gnomish wizard"), random } SUBROOM:"ordinary",random,(19,2),(2,2) { ROOMDOOR: false,closed,south,random MONSTER: 'G', random } SUBROOM:"candle shop",lit,(22,2),(3,3) { ROOMDOOR:false,closed,south,random } SUBROOM:"ordinary",random,(26,2),(2,2) { ROOMDOOR:false,locked,east,random MONSTER: 'G',random } SUBROOM:"tool shop" [90%],lit,(4,10),(3,3) { ROOMDOOR:false,closed,north,random } SUBROOM:"ordinary",random,(8,11),(2,2) { ROOMDOOR:false,locked,south,random MONSTER: ('k',"kobold shaman"),random MONSTER: ('k',"kobold shaman"),random MONSTER: ('f',"kitten"),random MONSTER: 'f',random } SUBROOM:"food shop" [90%],lit,(11,11),(3,2) { ROOMDOOR:false,closed,east,random } SUBROOM:"ordinary",random,(17,11),(2,2) { ROOMDOOR:false,closed,west,random } SUBROOM:"ordinary",random,(20,10),(2,2) { ROOMDOOR:false,locked,north,random MONSTER:'G',random } SUBROOM:"shop" [90%],lit,(23,10),(3,3) { ROOMDOOR:false,closed,north,random } MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful } ROOM: "ordinary" , random, random, random, random { STAIR: random, up } ROOM: "ordinary" , random, random, random, random { STAIR: random, down TRAP: random, random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random } ROOM: "ordinary" , random, random, random, random { MONSTER: ('h', "dwarf"), random } ROOM: "ordinary" , random, random, random, random { TRAP: random, random MONSTER: ('G', "gnome"), random } RANDOM_CORRIDORS # "Grotto Town" by Kelly Bailey # MAZE: "minetn-5",' ' GEOMETRY:center,center MAP ----- --------- |...--- ------.......-- ------- --------------- |.....----.........--..| |.....| ------- |.............| --..-....-.----------..| |.....| |.....| --+---+--.----+- --.--.....---- ---- |.....| ------ --....---- |..-...--.-.+..| ---.........---- ----- ---+--- |..+.| ---..-..----..---+-..---..| ----.-....|..----...-- |.| |..|.| ---+-.....-+--........--+- -----..|....-.....---- |.| |..|.------......--................| ------ |..|.............---.-- ----.+..|-.......--..--------+--..-- |....| --......---...........----- |.|..|-...{....---|.........|..-- |....| |........-...-...........----.|..|--.......| |.........|...| ---+--------....-------...---......--.-------....---- -----------...| ------.---...--...--..-..--...-..---...|.--..-...-....------- |.......-- |..|-.........-..---..-..---.....--....|........---...-|....| |.------- |..+...............-+---+-----..--..........--....--...+....| |.|...S. -----.....{....----...............-...........--...-...-|....| |.|...| |..............-- --+--.---------.........--..-........------- |.--+------- -+-----.........| |...|.|....| --.......------...|....---------.....|....| |...| --..------- |...|.+....| ---...--- --..|...--......-...{..+..-+| |...| ---- ------|....| ----- -----.....----........|..|.| ----- ------ ------- --------------- ENDMAP IF [75%] { IF [50%] { TERRAIN:line (25,8),(25,9), '|' } ELSE { TERRAIN:line (16,13),(17,13), '-' } } IF [75%] { IF [50%] { TERRAIN:line (36,10),(36,11), '|' } ELSE { TERRAIN:line (32,15),(33,15), '-' } } IF [50%] { TERRAIN:fillrect (21,4,22,5), '.' TERRAIN:line (14,9),(14,10), '|' } IF [50%] { TERRAIN:(46,13), '|' TERRAIN:line (43,5),(47,5), '-' TERRAIN:line (42,6),(46,6), '.' TERRAIN:line (46,7),(47,7), '.' } [50%]: TERRAIN:fillrect (69,11,71,11), '-' STAIR:(01,01),up STAIR:(46,03),down FOUNTAIN:(50,09) FOUNTAIN:(10,15) FOUNTAIN:(66,18) REGION:(00,00,74,20),unlit,"ordinary" REGION:(09,13,11,17),lit,"ordinary" REGION:(08,14,12,16),lit,"ordinary" REGION:(49,07,51,11),lit,"ordinary" REGION:(48,08,52,10),lit,"ordinary" REGION:(64,17,68,19),lit,"ordinary" REGION:(37,13,39,17),lit,"ordinary" REGION:(36,14,40,17),lit,"ordinary" REGION:(59,02,72,10),lit,"ordinary" MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome lord"), random MONSTER: ('G', "gnome lord"), random MONSTER: ('h', "dwarf"), random MONSTER: ('h', "dwarf"), random MONSTER: ('h', "dwarf"), random # The shops REGION:(25,17,28,19),lit,"candle shop" DOOR:closed,(24,18) REGION:(59,9,67,10),lit,"shop" DOOR:closed,(66,08) REGION:(57,13,60,15),lit,"tool shop" DOOR:closed,(56,14) REGION:(05,09,08,10),lit,"food shop" DOOR:closed,(07,11) # Gnome homes DOOR:closed,(04,14) DOOR:locked,(01,17) MONSTER: ('G', "gnomish wizard"), (02,19) DOOR:locked,(20,16) MONSTER: 'G', (20,18) DOOR:random,(21,14) DOOR:random,(25,14) DOOR:random,(42,08) DOOR:locked,(40,05) MONSTER: 'G', (38,07) DOOR:random,(59,03) DOOR:random,(58,06) DOOR:random,(63,03) DOOR:random,(63,05) DOOR:locked,(71,03) DOOR:locked,(71,06) DOOR:closed,(69,04) DOOR:closed,(67,16) MONSTER: ('G', "gnomish wizard"), (67,14) OBJECT: '=', (70,14) DOOR:locked,(69,18) MONSTER: ('G', "gnome lord"), (71,19) DOOR:locked,(73,18) OBJECT: ('(', "chest"), (73,19) DOOR:locked,(50,06) OBJECT: '(', (50,03) OBJECT: ('`', "statue"), (38,15), montype:"gnome king", 1 # Temple REGION:(29,02,33,04),lit,"temple" DOOR:closed,(31,05) ALTAR:(31,03),align[0],shrine # "Bustling Town" by Kelly Bailey # MAZE: "minetn-6",' ' FLAGS: inaccessibles INIT_MAP:mines,'.','-',true,true,lit,true GEOMETRY:center,top MAP .-----................----------------.- .|...|................|...|..|...|...|.. .|...+..--+--.........|...|..|...|...|.. .|...|..|...|..-----..|...|..|-+---+--.. .-----..|...|--|...|..--+---+-.........| ........|...|..|...+.............-----.. ........-----..|...|......--+-...|...|.. .----...|...|+------..{...|..|...+...|.. .|..+...|...|.............|..|...|...|.. .|..|...|...|-+-.....---+-------------.| .----...--+--..|..-+-|.................. ...|........|..|..|..|----....---------. ...|..T.....----..|..|...+....|......|-. ...|-....{........|..|...|....+......|-. ...--..-....T.....--------....|......|-. .......--.....................---------- ENDMAP REGION:(00,00,38,15),lit,"ordinary" STAIR:levregion(01,03,20,19),(0,0,39,15),up STAIR:levregion(61,03,75,19),(0,0,39,15),down FOUNTAIN:(22,07) FOUNTAIN:(09,13) REGION:(13,5,14,6),unlit,"ordinary" REGION:(9,7,11,9),lit,"candle shop" REGION:(16,4,18,6),lit,"tool shop" REGION:(23,1,25,3),lit,"shop" REGION:(22,12,24,13),lit,"food shop" REGION:(31,12,36,14),lit,"temple" ALTAR:(35,13),align[0],shrine DOOR:closed,(5,2) DOOR:locked,(4,8) DOOR:closed,(10,2) DOOR:closed,(10,10) DOOR:locked,(13,7) DOOR:locked,(14,9) DOOR:closed,(19,5) DOOR:closed,(19,10) DOOR:closed,(24,4) DOOR:closed,(24,9) DOOR:closed,(25,12) DOOR:closed,(28,4) DOOR:locked,(28,6) DOOR:closed,(30,13) DOOR:closed,(31,3) DOOR:closed,(35,3) DOOR:closed,(33,7) MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), (14,6) MONSTER: ('G', "gnome lord"), (14,5) MONSTER: ('G', "gnome"), (27,8) MONSTER: ('G', "gnome lord"), random MONSTER: ('G', "gnome lord"), random MONSTER: ('h', "dwarf"), random MONSTER: ('h', "dwarf"), random MONSTER: ('h', "dwarf"), random MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful # "Bazaar Town" by Kelly Bailey # LEVEL: "minetn-7" ROOM: "ordinary" , lit, (3,3), (center,center), (30,15) { FOUNTAIN: (12, 07) FOUNTAIN: (11, 13) [75%]: SUBROOM: "ordinary", random, (2,2), (4,2) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", random, (7,2), (2,2) { ROOMDOOR: false, closed, north, random } [75%]: SUBROOM: "ordinary", random, (7,5), (2,2) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", lit, (10,2), (3,4) { MONSTER:('G',"gnome"),random MONSTER:('Y',"monkey"),random MONSTER:('Y',"monkey"),random MONSTER:('Y',"monkey"),random ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", random, (14,2), (4,2) { ROOMDOOR: false, closed, south, 0 MONSTER: 'n', random } [75%]: SUBROOM: "ordinary", random, (16,5), (2,2) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", unlit, (19,2), (2,2) { ROOMDOOR: false, locked, east, random MONSTER: ('G',"gnome king"),random } SUBROOM: "food shop" [50%], lit, (19,5), (2,3) { ROOMDOOR: false, closed, south, random } [75%]: SUBROOM: "ordinary", random, (2,7), (2,2) { ROOMDOOR: false, closed, east, random } SUBROOM: "tool shop" [50%], lit, (2,10), (2,3) { ROOMDOOR: false, closed, south, random } SUBROOM: "candle shop", lit, (5,10),(3,3) { ROOMDOOR: false, closed, north, random } [75%]: SUBROOM: "ordinary", random, (11,10), (2,2) { ROOMDOOR: false, locked, west, random MONSTER: 'G',random } SUBROOM: "shop" [60%], lit, (14,10), (2,3) { ROOMDOOR: false, closed, north, random } [75%]: SUBROOM: "ordinary", random, (17,11), (4,2) { ROOMDOOR: false, closed, north, random } [75%]: SUBROOM: "ordinary", random, (22,11), (2,2) { ROOMDOOR: false, closed, south, random SINK: (00,00) } SUBROOM: "food shop" [50%], lit, (25,11), (3,2) { ROOMDOOR: false, closed, east, random } SUBROOM: "tool shop" [30%], lit, (25,2), (3,3) { ROOMDOOR: false, closed, west, random } SUBROOM: "temple", lit, (24,6), (4,4) { ROOMDOOR: false, closed, west, random ALTAR:(02,01),align[0],shrine MONSTER: ('G', "gnomish wizard"), random MONSTER: ('G', "gnomish wizard"), random } MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watchman"), random, peaceful MONSTER: ('@', "watch captain"), random, peaceful MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome lord"),random MONSTER:('Y',"monkey"),random MONSTER:('Y',"monkey"),random } ROOM: "ordinary" , random, random, random, random { STAIR: random, up } ROOM: "ordinary" , random, random, random, random { STAIR: random, down TRAP: random, random MONSTER: ('G', "gnome"), random MONSTER: ('G', "gnome"), random } ROOM: "ordinary" , random, random, random, random { MONSTER: ('h', "dwarf"), random } ROOM: "ordinary" , random, random, random, random { TRAP: random, random MONSTER: ('G', "gnome"), random } RANDOM_CORRIDORS # Mine end level variant 1 # "Mimic of the Mines" # MAZE: "minend-1", ' ' GEOMETRY:center,center #1234567890123456789012345678901234567890123456789012345678901234567890 MAP ------------------------------------------------------------------ ------ | |.......| |.......-...| |.....|. | | --------- ----.......-------...........| ---...-S- | | |.......| |..........................-S- --.......| | | |......------- ---........................|. |.......-- | | |..--........-----..........................|. -.-..---- | | --..--.-----........-.....................--- --..-- | | --..--..| -----------..................---.----------..-- | | |...--.| |..S...S..............---................-- | | ----..----- ------------........--- ------------...--- | | |.........-- ---------- ---...-- ----- | | --.....---..-- -------- --...---...-- | | ----..-..-- --..--------------------- --......-- ---........| | |--....----- --..-..................--- |........| |.......-- | |.......| --......................S.. --......-- ---..---- | |--.--.-- ----.................--- ------..------...-- | | |....S.. |...............-..| ..S...........| | -------- -------------------- ------------------------ ENDMAP # Dungeon Description $place = { (08,16),(13,07),(21,08),(41,14),(50,04),(50,16),(66,01) } SHUFFLE: $place REGION:(26,01,32,01),unlit,"ordinary",filled,irregular REGION:(20,08,21,08),unlit,"ordinary" REGION:(23,08,25,08),unlit,"ordinary" # Secret doors DOOR:locked,(07,16) DOOR:locked,(22,08) DOOR:locked,(26,08) DOOR:locked,(40,14) DOOR:locked,(50,03) DOOR:locked,(51,16) DOOR:locked,(66,02) # Stairs STAIR:(36,04),up # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Niches # Note: $place[6] empty OBJECT:('*',"diamond"),$place[0] OBJECT:('*',"emerald"),$place[0] OBJECT:('*',"worthless piece of violet glass"),$place[0] MONSTER:'m',$place[0], m_object "luckstone" OBJECT:('*',"worthless piece of white glass"),$place[1] OBJECT:('*',"emerald"),$place[1] OBJECT:('*',"amethyst"),$place[1] MONSTER:'m',$place[1], m_object "loadstone" OBJECT:('*',"diamond"),$place[2] OBJECT:('*',"worthless piece of green glass"),$place[2] OBJECT:('*',"amethyst"),$place[2] MONSTER:'m',$place[2], m_object "flint" OBJECT:('*',"worthless piece of white glass"),$place[3] OBJECT:('*',"emerald"),$place[3] OBJECT:('*',"worthless piece of violet glass"),$place[3] MONSTER:'m',$place[3], m_object "touchstone" OBJECT:('*',"worthless piece of red glass"),$place[4] OBJECT:('*',"ruby"),$place[4] OBJECT:('*',"loadstone"),$place[4] OBJECT:('*',"ruby"),$place[5] OBJECT:('*',"worthless piece of red glass"),$place[5] OBJECT:('*',"luckstone"),$place[5] # Random objects OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'(',random OBJECT:'(',random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters MONSTER:('G',"gnome king"),random MONSTER:('G',"gnome lord"),random MONSTER:('G',"gnome lord"),random MONSTER:('G',"gnome lord"),random MONSTER:('G',"gnomish wizard"),random MONSTER:('G',"gnomish wizard"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('h',"hobbit"),random MONSTER:('h',"hobbit"),random MONSTER:('h',"dwarf"),random MONSTER:('h',"dwarf"),random MONSTER:('h',"dwarf"),random MONSTER:'h',random # Mine end level variant 2 # "Gnome King's Wine Cellar" # MAZE: "minend-2", ' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |...................................................| | |.|---------S--.--|...|--------------------------|..| | |.||---| |.||-| |...|..........................|..| | |.||...| |-|.|.|---...|.............................| .. | |.||...|-|.....|....|-|..........................|..|. .. | |.||.....|-S|..|....|............................|..|.. | |.||--|..|..|..|-|..|----------------------------|..|-. | |.| |..|..|....|..................................|... | |.| |..|..|----|..-----------------------------|..|.... | |.|---|..|--|.......|----------------------------|..|..... | |...........|----.--|......................| |..|....... | |-----------|...|.| |------------------|.|.|-----|..|.....|.. | |-----------|.{.|.|--------------------|.|..........|.....|.... | |...............|.S......................|-------------..-----... | |.--------------|.|--------------------|.|......................... | |.................| |.....................|........ | --------------------------------------------------------------------------- ENDMAP IF [50%] { TERRAIN:(55,14),'-' TERRAIN:(56,14),'-' TERRAIN:(61,15),'|' TERRAIN:(52,5), 'S' DOOR:locked, (52,5) } IF [50%] { TERRAIN:(18,1), '|' TERRAIN:rect (7,12, 8,13), '.' } IF [50%] { TERRAIN:(49,4), '|' TERRAIN:(21,5), '.' } IF [50%] { IF [50%] { TERRAIN:(22,1), '|' } ELSE { TERRAIN:(50,7), '-' TERRAIN:(51,7), '-' } } # Dungeon Description FOUNTAIN:(14,13) REGION:(23,03,48,06),lit,"ordinary" REGION:(21,06,22,06),lit,"ordinary" REGION:(14,04,14,04),unlit,"ordinary" REGION:(10,05,14,08),unlit,"ordinary" REGION:(10,09,11,09),unlit,"ordinary" REGION:(15,08,16,08),unlit,"ordinary" # Secret doors DOOR:locked,(12,02) DOOR:locked,(11,06) # Stairs STAIR:(36,04),up # Non diggable walls NON_DIGGABLE:(00,00,52,17) NON_DIGGABLE:(53,00,74,00) NON_DIGGABLE:(53,17,74,17) NON_DIGGABLE:(74,01,74,16) NON_DIGGABLE:(53,07,55,07) NON_DIGGABLE:(53,14,61,14) # The Gnome King's wine cellar. # the Trespassers sign is a long-running joke ENGRAVING:(12,03),engrave,"You are now entering the Gnome King's wine cellar." ENGRAVING:(12,04),engrave,"Trespassers will be persecuted!" OBJECT:('!',"booze"),(10,07) OBJECT:('!',"booze"),(10,07) OBJECT:'!',(10,07) OBJECT:('!',"booze"),(10,08) OBJECT:('!',"booze"),(10,08) OBJECT:'!',(10,08) OBJECT:('!',"booze"),(10,09) OBJECT:('!',"booze"),(10,09) OBJECT:('!',"object detection"),(10,09) # Objects # The Treasure chamber... OBJECT:('*',"diamond"),(69,04) OBJECT:'*',(69,04) OBJECT:('*',"diamond"),(69,04) OBJECT:'*',(69,04) OBJECT:('*',"emerald"),(70,04) OBJECT:'*',(70,04) OBJECT:('*',"emerald"),(70,04) OBJECT:'*',(70,04) OBJECT:('*',"emerald"),(69,05) OBJECT:'*',(69,05) OBJECT:('*',"ruby"),(69,05) OBJECT:'*',(69,05) OBJECT:('*',"ruby"),(70,05) OBJECT:('*',"amethyst"),(70,05) OBJECT:'*',(70,05) OBJECT:('*',"amethyst"),(70,05) OBJECT:('*',"luckstone"),(70,05) # Scattered gems... OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'*',random OBJECT:'(',random OBJECT:'(',random OBJECT:random,random OBJECT:random,random OBJECT:random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:('G',"gnome king"),random MONSTER:('G',"gnome lord"),random MONSTER:('G',"gnome lord"),random MONSTER:('G',"gnome lord"),random MONSTER:('G',"gnomish wizard"),random MONSTER:('G',"gnomish wizard"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('G',"gnome"),random MONSTER:('h',"hobbit"),random MONSTER:('h',"hobbit"),random MONSTER:('h',"dwarf"),random MONSTER:('h',"dwarf"),random MONSTER:('h',"dwarf"),random MONSTER:'h',random # "Catacombs" by Kelly Bailey # Relies on some very specific behavior of MAZEWALK. # MAZE:"minend-3",'-' FLAGS:nommap GEOMETRY:center,bottom MAP - - - - - - - - - - -- -- - - . - - - - - - - - - -- - - -- - - - - . - - | ------...---------.-----------...-----.-------.------- ----------------| - - - - - - - - - - - . - - - . - - - - - - - - - - -- - -- - . - - - - - | ------------.---------...-------------------------.--- ------------------| - - - - - - - - - - . . - - --- - . - - - - - - - - -- -- - - - - |.....| | --.---------------.......------------------------------- ----------|.....S-| - - - - |.. ..| - ....... . - - - - |.........| - - - --- - - - - |.....| | ----.----|.....|------.......--------|.........|--------------.------------| - - - - |..{..| - - -.... . --- - -.S.........S - - - - - - - - - - - - - | ---------|.....|--.---...------------|.........|---------------------------| - - - - |.. ..| - - - . - - - - - - |.........| - --- . - - - - - - - - - | ----------------------...-------.---------------------...------------------| ---..| - - - - - - - - . --- - - - - - - - - - - - - - . - - --- - - --- - | -.S..|----.-------.------- ---------.-----------------...----- -----.------- ---..| - - - - - - - -- - - -- . - - - - - . - - - . - . - - -- -- - - - -- -.S..|--------.---.--- -...---------------...{.--------- --------- --|. - - - - - - - -- - - - -- . - - - --- - - - . . - - - - -- - - - - - - ENDMAP $place = { (1,15),(68,6),(1,13) } SHUFFLE: $place NON_DIGGABLE:(67,3,73,7) NON_DIGGABLE:(0,12,2,16) FOUNTAIN:(12,08) FOUNTAIN:(51,15) REGION:(0,0,75,16),unlit,"ordinary" REGION:(38,6,46,10),lit,"ordinary" DOOR:closed,(37,8) DOOR:closed,(47,8) DOOR:closed,(73,5) DOOR:closed,(2,15) MAZEWALK:(36,8),west STAIR:(42,8),up WALLIFY # Objects OBJECT:('*',"diamond"),random OBJECT:'*',random OBJECT:('*',"diamond"),random OBJECT:'*',random OBJECT:('*',"emerald"),random OBJECT:'*',random OBJECT:('*',"emerald"),random OBJECT:'*',random OBJECT:('*',"emerald"),random OBJECT:'*',random OBJECT:('*',"ruby"),random OBJECT:'*',random OBJECT:('*',"ruby"),random OBJECT:('*',"amethyst"),random OBJECT:'*',random OBJECT:('*',"amethyst"),random OBJECT:('*',"luckstone"),$place[0] OBJECT:('*',"flint"),$place[1] OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random OBJECT:'?',random OBJECT:'+',random OBJECT:'+',random OBJECT:'+',random OBJECT:'+',random OBJECT:random,random OBJECT:random,random OBJECT:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # One-time annoyance factor TRAP:"level teleport",$place[0] TRAP:"level teleport",$place[1] MONSTER:'M',random MONSTER:'M',random MONSTER:'M',random MONSTER:'M',random MONSTER:'M',random MONSTER:('M',"ettin mummy"),random MONSTER:'V',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'Z',random MONSTER:'V',random MONSTER:'e',random MONSTER:'e',random MONSTER:'e',random MONSTER:'e',random # end mines.des nethack-3.6.0/dat/opthelp0000664000076400007660000003670412536476415014332 0ustar paxedpaxedBoolean options not under specific compile flags (with default values in []): (You can learn which options exist in your version by checking your current option setting, which is reached via the 'O' cmd.) autodig dig if moving and wielding digging tool [FALSE] autoopen walking into a door attempts to open it [TRUE] autopickup automatically pick up objects you move over [TRUE] autoquiver when firing with an empty quiver, select some suitable inventory weapon to fill the quiver [FALSE] BIOS allow the use of IBM ROM BIOS calls [FALSE] cmdassist give help for errors on direction & other commands [TRUE] confirm ask before hitting tame or peaceful monsters [TRUE] DECgraphics use DEC/VT line-drawing characters for the dungeon [FALSE] eight_bit_tty send 8-bit characters straight to terminal [FALSE] extmenu use a menu for selecting extended commands (#) [FALSE] fixinv try to retain the same letter for the same object [TRUE] help print all available info when using the / command [TRUE] IBMgraphics use IBM extended characters for the dungeon [FALSE] ignintr ignore interrupt signal, including breaks [FALSE] implicit_uncursed omit "uncursed" from inventory, if possible [TRUE] legacy print introductory message [TRUE] lit_corridor show a dark corridor as lit if in sight [FALSE] lootabc use a/b/c rather than o/i/b when looting [FALSE] mail enable the mail daemon [TRUE] null allow nulls to be sent to your terminal [TRUE] try turning this option off (forcing NetHack to use its own delay code) if moving objects seem to teleport across rooms perm_invent keep inventory in a permanent window [FALSE] pickup_thrown override pickup_types for thrown objects [TRUE] pushweapon when wielding a new weapon, put your previously wielded weapon into the secondary weapon slot [FALSE] rawio allow the use of raw I/O [FALSE] rest_on_space count the space bar as a rest character [FALSE] safe_pet prevent you from (knowingly) attacking your pet(s) [TRUE] showexp display your accumulated experience points [FALSE] showrace show yourself by your race rather than by role [FALSE] silent don't use your terminal's bell sound [TRUE] sortpack group similar kinds of objects in inventory [TRUE] sound enable messages about what your character hears [TRUE] (note: this has nothing to do with your computer's audio capabilities, and the game resets it periodically) sparkle display sparkly effect for resisted magical [TRUE] attacks (e.g. fire attack on fire-resistant monster) standout use standout mode for --More-- on messages [FALSE] time display elapsed game time, in moves [FALSE] tombstone print tombstone when you die [TRUE] toptenwin print topten in a window rather than stdout [FALSE] travel enable the command to travel to a map location via [TRUE] a shortest-path algorithm, usually invoked by '_'. use_darkgray use bold black instead of blue for black glyphs. [TRUE] use_inverse display detected monsters in highlighted manner [FALSE] verbose print more commentary during the game [TRUE] There are further boolean options controlled by compilation flags. Boolean option if INSURANCE was set at compile time: checkpoint save game state after each level change, for possible [TRUE] recovery after program crash Boolean option if NEWS was set at compile time: news print any news from game administrator on startup [TRUE] Boolean option if MFLOPPY was set at compile time: checkspace check free disk space before writing files to disk [TRUE] Boolean option if SCORE_ON_BOTL was set at compile time: showscore display your approximate accumulated score [FALSE] Boolean options if TEXTCOLOR was set at compile time: color use different colors for objects on screen [TRUE for micros] hilite_pet display pets in a highlighted manner [FALSE] Boolean option if TIMED_DELAY was set at compile time (tty interface only): timed_delay on unix and VMS, use a timer instead of sending extra screen output when attempting to pause for display effect. on MSDOS without the termcap lib, whether or not to pause for visual effect. [TRUE] Boolean option for Amiga, or for others if ALTMETA was set at compile time: altmeta For Amiga, treat Alt+key as Meta+key. [TRUE] altmeta For unix and VMS, treat two character sequence "ESC c" as M-c (Meta+c, 8th bit set) when nethack obtains a command from player's keyboard. [FALSE] Boolean option if USE_TILES was set at compile time (MSDOS protected mode only): preload_tiles control whether tiles get pre-loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. [TRUE] Any Boolean option can be negated by prefixing it with a '!' or 'no'. Compound options are written as option_name:option_value. Compound options which can be set during the game are: boulder override the default boulder symbol with another default: [`] disclose the types of information you want offered at the end of the game [ni na nv ng nc no] fruit the name of a fruit you enjoy eating [slime mold] (basically a whimsy which NetHack uses from time to time). menustyle user interface for selection of multiple objects: Traditional -- prompt for classes of interest, then prompt item-by-item for those classes; Combination -- prompt for classes of interest, then use a menu for choosing items; Full -- menu for classes of interest, then item menu; Partial -- skip class filtering, use menu of all items; only the first letter ('T','C','P','F') matters; 'N' (None) is a synonym for 'T', as is boolean style negation [Full] number_pad alphabetic versus numeric control over movement: 0 -- traditional hjkl + yubn movement (default); 1 -- digits control movement, for use with numeric keypad; 2 -- same as 1, but '5' works as 'g' prefix rather than 'G'; 3 -- numeric for phone keypad (1,2,3 above, 7,8,9 below); 4 -- phone keypad (3) combined with MSDOS compatibility (2); -1 -- alphabetic movement but 'z' swapped with 'y'. [0] packorder a list of default symbols for kinds of objects that gives the order in which your pack will be displayed [")[%?+!=/(*`0_] (If you specify only some kinds of items, the others from the default order will be appended to the end.) paranoid_confirmation space separated list of situations where alternate prompting is desired [paranoid_confirmation:pray] Confirm -- when requiring yes, also require no to reject quit -- yes vs y to confirm quitting or to enter explore mode die -- yes vs y to confirm dying (for explore or debug mode) bones -- yes vs y to confirm saving bones data in debug mode attack -- yes vs y to confirm attacking a peaceful monster pray -- y to confirm an attempt to pray; on by default Remove -- always pick from inventory for 'R' and 'T' even when wearing just one applicable item to remove or take off pickup_burden when you pick up an item that exceeds this encumberance level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. [S] pickup_types a list of default symbols for kinds of objects to autopickup when that option is on [all] pile_limit for feedback when walking across floor objects, threshold at which "there are many objects here" is displayed instead of listing the objects. (0 means "always list objects.") [5] runmode controls how often the map window is updated when performing multi-step movement (various running modes or travel command): teleport -- don't update map until movement stops; run -- periodically update map (interval is seven steps); walk -- update map after every step; crawl -- like walk, but delay after making each step. (This only affects screen display, not actual movement.) [run] scores the parts of the score list you wish to see when the game ends You choose a combination of top scores, scores around the top scores, and all of your own scores. [!own/3 top/2 around] suppress_alert disable various version-specific warnings about changes in game play or the user interface, such as notification given for the 'Q' command that quitting is now done via #quit (e.g., use suppress_alert:3.3.1 to stop that and any other notifications added in that version or earlier) default: [(none)] Compound options which may be set only on startup are: align Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. [RANDOM] catname the name of your first cat [NONE] dogname the name of your first dog [NONE] dungeon a list of symbols to be used in place of the default ones for drawing the dungeon. The symbols are subjected to a fair amount of processing, so that you can use C-style escapes such as \n or \081 as well as indicate control characters by ^x or meta characters by \Mx. As usual, \ can force the next character to be taken literally. Since many of the default symbols are overloaded, they are given here by name instead of symbol, with some added notes: stone (solid rock, normally ' ') vwall hwall tlcorn trcorn blcorn brcorn (room boundaries) crwall tuwall tdwall tlwall trwall (wallified maze characters) nodoor vodoor hodoor (no, vertical, horizontal open door) vcdoor hcdoor (vertical, horizontal closed door) ironbars tree room darkcorr litcorr upstair dnstair upladder dnladder altar grave throne sink fountain pool ice lava vodbridge hodbridge (vertical, horizontal open drawbridge) vcdbridge hcdbridge (vertical, horizontal closed drawbridge) air cloud water default: \ |--------||.-|++##.##<><>_\\#{}.}..##\ #} effects like dungeon, but for special effects symbols vbeam hbeam lslant rslant (generic zap beams) digbeam flashbeam (special beams for digging and cameras) boomleft boomright (boomerangs) ss1 ss2 ss3 ss4 (shielding sequence) sw_topl, sw_topm, sw_topr, (swallow, top row) sw_midl, sw_midr, (swallow, middle row [no center]) sw_botl, sw_botm, sw_botr (swallow, bottom row) extl extm extr (explosion matrix top row) exml exmm exmr (explosion matrix middle row) exbl exbm exbr (explosion matrix bottom row) default: |-\\/*!)(0#@*/-\\||\\-//-\\|\ |\\-/ gender Your starting gender (gender:male or gender:female). You may specify just the first letter. Although you can still denote your gender using the "male" and "female" options, the "gender" option will take precedence. [RANDOM] horsename the name of your first horse [NONE] menu_* create single character accelerators for menu commands. Below is a list of all commands. Each is followed by a list of window- ports that implement them: 'x' is X11, 't' is tty, 'g' is Gem, 'a' is Amiga. menu_deselect_all deselect all items in a menu [-](gxta) menu_deselect_page deselect all items on this menu page [\](gta) menu_first_page jump to the first page in a menu [^](gta) menu_invert_all invert all items in a menu [@](gxta) menu_invert_page invert all items on this menu page [~](gta) menu_last_page jump to the last page in a menu [|](gta) menu_next_page goto the next menu page [>](gta) menu_previous_page goto the previous menu page [<](gta) menu_search search for a menu item [:](gxta) menu_select_all select all items in a menu [.](gxta) menu_select_page select all items on this menu page [,](gta) monsters like dungeon, but for monster symbols default: abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ@\ \\&;:~] msghistory number of top line messages to save [20] name the name of your character [obtained by asking the system or the player] objects like dungeon, but for object symbols default: ])[="(%!?+/$*`0_. pettype your preferred type of pet (cat or dog), if your character class uses both types; or none for no pet [RANDOM] playmode normal play or non-scoring explore mode or debug mode [normal] race Your starting race (e.g., race:Human, race:Elf). [RANDOM] role Your starting role (e.g., role:Barbarian, role:Valk). Although you can specify just the first letter(s), it will choose only the first role it finds that matches; thus, it is recommended that you spell out as much of the role name as possible. You can also still denote your role by appending it to the "name" option (e.g., name:Vic-V), but the "role" option will take precedence. [RANDOM] traps like dungeon, but for trap symbols arrow_trap dart_trap falling_rock_trap squeaky_board bear_trap land_mine rolling_boulder_trap sleeping_gas_trap rust_trap fire_trap pit spiked_pit hole trap_door teleportation_trap level_teleporter magic_portal web statue_trap magic_trap anti_magic_trap polymorph_trap default: ^^^^^^^^^^^^^^^^^"^^^^ windowtype windowing system to be used [depends on operating system] Compound option if TTY_GRAPHICS was set at compile time: msg_window the type of message window to use: single -- One message at a time full -- Full window with all saved top line messages reverse -- Same as full, but messages printed most-recent-first combination -- Two single messages, then as full default: single Some sample options lists are: !autopickup,!tombstone,name:Gandalf,scores:own/3 top/2 around female,nonews,dogname:Rover,dungeon: |--------||.-|++.##<><>_\\#{}.}..## #} rest_on_space,!verbose,menustyle:traditional nethack-3.6.0/dat/oracle.des0000664000076400007660000000305712536476415014671 0ustar paxedpaxed# NetHack 3.6 oracle.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # NetHack may be freely redistributed. See license for details. # # Oracle level # LEVEL: "oracle" ROOM: "ordinary" , lit, (3,3), (center,center), (11,9) { OBJECT:('`',"statue"),(0,0),montype:'C',1 OBJECT:('`',"statue"),(0,8),montype:'C',1 OBJECT:('`',"statue"),(10,0),montype:'C',1 OBJECT:('`',"statue"),(10,8),montype:'C',1 OBJECT:('`',"statue"),(5,1),montype:'C',1 OBJECT:('`',"statue"),(5,7),montype:'C',1 OBJECT:('`',"statue"),(2,4),montype:'C',1 OBJECT:('`',"statue"),(8,4),montype:'C',1 SUBROOM: "delphi" , lit , (4,3) , (3,3) { FOUNTAIN: (0, 1) FOUNTAIN: (1, 0) FOUNTAIN: (1, 2) FOUNTAIN: (2, 1) MONSTER: ('@', "Oracle"), (1,1) ROOMDOOR: false , nodoor , random, random } MONSTER: random, random MONSTER: random, random } ROOM: "ordinary" , random, random, random, random { STAIR: random, up OBJECT: random,random } ROOM: "ordinary" , random, random, random, random { STAIR: random, down OBJECT: random, random TRAP: random, random MONSTER: random, random MONSTER: random, random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random OBJECT: random, random MONSTER: random, random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: random, random } ROOM: "ordinary" , random, random, random, random { OBJECT: random, random TRAP: random, random MONSTER: random, random } RANDOM_CORRIDORS nethack-3.6.0/dat/oracles.txt0000664000076400007660000001274512504447327015117 0ustar paxedpaxed----- If thy wand hath run out of charges, thou mayst zap it again and again; though naught will happen at first, verily, thy persistence shall be rewarded, as one last charge may yet be wrested from it! ----- Though the shopkeepers be wary, thieves have nevertheless stolen much by using their digging wands to hasten exits through the pavement. ----- If thou hast had trouble with rust on thine armor or weapons, thou shouldst know that thou canst prevent this by, while in a confused state, reading the magical parchments which normally are used to cause their enchantment. Unguents of lubrication may provide similar protection, albeit of a transitory nature. ----- Behold the cockatrice, whose diminutive stature belies its hidden might. The cockatrice can petrify any ordinary being it contacts--save those wise adventurers who eat a dead lizard or blob of acid when they feel themselves slowly turning to stone. ----- While some wayfarers rely on scrounging finished armour in the dungeon, the resourceful know the mystical means by which mail may be fashioned out of scales from a dragon's hide. ----- It is customarily known among travelers that extra-healing draughts may clear thy senses when thou art addled by delusory visions. But never forget, the lowly potion which makes one sick may be used for the same purpose. ----- While the consumption of lizard flesh or water beloved of the gods may clear the muddled head, the application of the horn of a creature of utmost purity can alleviate many other afflictions as well. ----- If thou wouldst travel quickly between distant locations, thou must be able to control thy teleports, and in a confused state misread the scroll which usually teleports thyself locally. Daring adventurers have also performed the same feat sans need for scrolls or potions by stepping into a particular ambuscade. ----- Almost all adventurers who come this way hope to pass the dread Medusa. To do this, the best advice is to keep thine eyes blindfolded and to cause the creature to espy its own reflection in a mirror. ----- And where it is written "ad aerarium", diligent searching will often reveal the way to a trap which sends one to the Magic Memory Vault, where the riches of Croesus are stored; however, escaping from the vault with its gold is much harder than getting in. ----- It is well known that wily shopkeepers raise their prices whene'er they espy the garish apparel of the approaching tourist or the countenance of a disfavored patron. They favor the gentle of manner and the fair of face. The boor may expect unprofitable transactions. ----- The cliche of the kitchen sink swallowing any unfortunate rings that contact its pernicious surface reflecteth greater truth than many homilies, yet even so, few have developed the skill to identify enchanted rings by the transfigurations effected upon the voracious device's frame. ----- The meat of enchanted creatures ofttimes conveyeth magical properties unto the consumer. A fresh corpse of floating eye doth fetch a high price among wizards for its utility in conferring Telepathy, by which the sightless may locate surrounding minds. ----- The detection of blessings and curses is in the domain of the gods. They will make this information available to mortals who request it at their places of worship, or elsewhere for those mortals who devote themselves to the service of the gods. ----- At times, the gods may favor worthy supplicants with named blades whose powers echo throughout legend. Learned wayfarers can reproduce blades of elven lineage, hated of the orcs, without the need for such intervention. ----- There are many stories of a mighty amulet, the origins of which are said to be ancient Yendor. This amulet doth have awesome power, and the gods desire it greatly. Mortals mayst tap only portions of its terrible abilities. The stories tell of mortals seeing what their eyes cannot see and seeking places of magical transportation, while having this amulet in their possession. Others say a mortal must wear the amulet to obtain these powers. But verily, such power comes at great cost, to preserve the balance. ----- It is said that thou mayst gain entry to Moloch's sanctuary, if thou darest, from a place where the ground vibrateth in the deepest depths of Gehennom. Thou needs must have the aid of three magical items. The pure sound of a silver bell shall announce thee. The terrible runes, read from Moloch's book, shall cause the earth to tremble mightily. The light of an enchanted candelabrum shall show thee the way. ----- In the deepest recesses of the Dungeons of Doom, guarding access to the nether regions, there standeth a castle, wherein lieth a wand of wishes. If thou wouldst gain entry, bear with thee an instrument of music, for the pontlevis may be charmed down with the proper melody. What notes comprise it only the gods know, but a musical mastermind may yet succeed by witful improvisation. However, the less perspicacious are not without recourse, should they be prepared to circumambulate the castle to the postern. ----- The gods are said to be pleased when offerings are given to the priests who attend their temples, and they may grant various favors to those who do so. But beware! To be young and frugal is better than to be old and miserly. ----- The name of Elbereth may strike fear into the hearts of thine enemies, if thou dost write it upon the ground at thy feet. If thou maintainest the utmost calm, thy safety will be aided greatly, but beware lest thy clumsy feet scuff the inscription, cancelling its potence. ----- nethack-3.6.0/dat/quest.txt0000664000076400007660000032736112625765105014634 0ustar paxedpaxed# NetHack 3.6 quest.txt $NHDT-Date: 1448540693 2015/11/26 12:24:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The quest text file for NetHack 3.4 # # These are the "standard" message numbers from qtext.h. All class # dialogue must have at least these entries. # # QT_FIRSTTIME 1 # QT_NEXTTIME 2 # QT_OTHERTIME 3 # # QT_GUARDTALK 5 /* 5 random things guards say before quest */ # QT_GUARDTALK2 10 /* 5 random things guards say after quest */ # # QT_FIRSTLEADER 15 # QT_NEXTLEADER 16 # QT_OTHERLEADER 17 # QT_LASTLEADER 18 # QT_BADLEVEL 19 # QT_BADALIGN 20 # QT_ASSIGNQUEST 21 # # QT_ENCOURAGE 25 /* 1-10 random encouragement messages */ # # QT_FIRSTLOCATE 35 # QT_NEXTLOCATE 36 # # QT_FIRSTACQUIRE 40 # QT_NEXTACQUIRE 41 # # QT_FIRSTNEMESIS 50 # QT_NEXTNEMESIS 51 # QT_OTHERNEMESIS 52 # QT_NEMWANTSIT 53 /* you somehow got the artifact */ # # QT_DISCOURAGE 60 /* 1-10 random maledictive messages */ # # QT_GOTIT 70 # # QT_KILLEDNEM 80 # QT_OFFEREDIT 81 # QT_OFFEREDIT2 82 /* if you throw artifact to leader after #81 */ # # QT_POSTHANKS 90 # QT_HASAMULET 91 # # # Archeologist # %Cc Arc 00001 You are suddenly in familiar surroundings. The buildings in the distance seem to be those of your old alma mater, but something is wrong. It feels as if there has been a riot recently, or %H has been under siege. All of the windows are boarded up, and there are objects scattered around the entrance. Strange forbidding shapes seem to be moving in the distance. %E [You arrive at %H, but all is not well.] %Cp Arc 00002 Once again, you are back at %H. %E %Cp Arc 00003 You are back at %H. You have an odd feeling this may be the last time you ever come here. %E %Cp Arc 00005 "Did you see Lash LaRue in 'Song of Old Wyoming' the other night?" %E %Cp Arc 00006 "Hey man, got any potions of hallucination for sale?" %E %Cp Arc 00007 "Did you see the artifact %l brought back from the last dig?" %E %Cp Arc 00008 "So what species do *you* think we evolved from?" %E %Cp Arc 00009 "So you're %ls prize pupil! I don't know what he sees in you." %E %Cp Arc 00010 "Did you see Lash LaRue in 'Song of Old Wyoming' the other night?" %E %Cp Arc 00011 "Hey man, got any potions of hallucination for sale?" %E %Cp Arc 00012 "I guess you are guaranteed to make full professor now." %E %Cp Arc 00013 "So, what was worse, %n or your entrance exams?" %E %Cp Arc 00014 "%oC is impressive, but nothing like the bones I dug up!" %E %Cc Arc 00015 "Finally you have returned, %p. You were always my most promising student. Allow me to see if you are ready for the most difficult task of your career." %E ["You have returned, %p, to a difficult task."] %Cp Arc 00016 "Again, %p, you stand before me. Let me see if you have gained experience in the interim." %E %Cp Arc 00017 "Once more, %p, you have returned from the field. Are you finally ready for the task that must be accomplished?" %E %Cc Arc 00018 "%p, you have failed us. All of my careful training has been in vain. Begone! Your tenure at this college has been revoked! "You are a disgrace to the profession!" %E ["%pC, you have failed us. Begone!"] %Cc Arc 00019 "%p, you are yet too inexperienced to undertake such a demanding quest. A mere %r could not possibly face the rigors demanded and survive. Go forth, and come here again when your adventures have further taught you." %E [%pC, a mere %r is too inexperienced.] %Cc Arc 00020 "%pC! I've heard that you've been using sloppy techniques. Your results lately can hardly be called suitable for %ra! "How could you have strayed from the %a path? Go from here, and come back only when you have purified yourself." %E ["%pC, you have strayed from the %a path. Purify yourself!"] %Cc Arc 00021 "Grave times have befallen the college, for %na has stolen %o. Without it, the board of directors of the university will soon have no choice but to revoke our research grants. "You must locate the entrance to %i. Within it, you will find %n. "You must then defeat %n and return %o to me. "Only in this way will we be able to prevent the budget cuts that could close this college. "May the wisdom of %d be your guide." %E [%nC has stolen %o. Locate %i, defeat %ni, and return %O.] %Cp Arc 00025 "Beware, for %n is powerful and cunning." %E %Cp Arc 00026 "To locate the entrance to %i, you must pass many traps." %E %Cp Arc 00027 "A %nt may be vulnerable to attacks by magical cold." %E %Cp Arc 00028 "Call upon %d when you encounter %n." %E %Cp Arc 00029 "You must destroy %n. It will pursue you otherwise." %E %Cp Arc 00030 "%oC is a mighty talisman. With it you can destroy %n." %E %Cp Arc 00031 "Go forth with the blessings of %d." %E %Cp Arc 00032 "I will have my %gP watch for your return." %E %Cp Arc 00033 "Remember not to stray from the true %a path." %E %Cp Arc 00034 "You may be able to sense %o when you are near." %E %Cc Arc 00035 A plain opens before you. Beyond the plain lies a foreboding edifice. You have the feeling that you will soon find the entrance to %i. %E [This foreboding edifice must hide the entrance to %i.] %Cp Arc 00036 Once again, you are near the entrance to %i. %E %Cc Arc 00040 A strange feeling washes over you, and you think back to things you learned during the many lectures of %l. You realize the feeling must be the presence of %o. %E [This strange feeling must be the presence of %o.] %Cp Arc 00041 The familiar presence of %o is in the ether. %E %Cc Arc 00050 "So, %p, you think that you can succeed in recovering %o, when your teacher, %l, has already failed. "Come, try your best! I shall destroy you, and gnaw on your bones." %E ["Come, %p, I shall destroy you!"] %Cc Arc 00051 "Again you try to best me, eh %p? Well, you shall fail again. "You shall never recover %o. "I shall bear your soul to the Plane of Origins for my master's pleasure." %E ["Again you try to best me, %p? You shall never recover %o."] %Cp Arc 00052 "You persist yet %p! Good. Now, you shall die!" %E %Cp Arc 00053 "I shall have %o from you, %p, then feast upon your entrails!" %E %Cp Arc 00060 "Try your best, %p. You cannot defeat me." %E %Cp Arc 00061 "I shall rend the flesh from your body whilst you still breathe!" %E %Cp Arc 00062 "First you, %p, then I shall destroy your mentor, %l." %E %Cp Arc 00063 "Tiring yet, %p? I draw my power from my master and cannot falter!" %E %Cp Arc 00064 "I shall rend thy soul from thy body and consume it!" %E %Cp Arc 00065 "You are far too %a -- it weakens you. You shall die in this place." %E %Cp Arc 00066 "%d has forsaken you! You are lost now!" %E %Cp Arc 00067 "A mere %r cannot hope to defeat me!" %E %Cp Arc 00068 "If you are the best %l can send, I have nothing to fear." %E %Cp Arc 00069 "Die %c! I shall exhibit your carcass as a trophy." %E %Cc Arc 00070 The power of %o flows through your body! You feel as if you could now take on the Wizard of Yendor himself and win, but you know you must return %o to %l. %E [The power of %o flows through your body! You must return it to %l.] %Cp Arc 00080 The body of %n dissipates in a cloud of noxious fumes. %E %Cc Arc 00081 %lC touches %o briefly, gazes into it, then smiles at you and says: "Well done, %p. You have defeated %n and recovered %o. But I fear that it shall never be safe here. Please take %o with you. You, %p, can guard it now far better than I. May the blessings of %d follow you and guard you." %E [%lC instructs you to guard %o from now on.] # assumes Orb of Detection (glass object) %Cc Arc 00082 "Careful, %p! %oC might break, and that would be a tragic loss. You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E ["Resume your search for the Amulet beyond the magic portal to %Z."] %Cc Arc 00090 "Welcome back, %p. Have you progressed with your quest to regain the Amulet of Yendor for %d?" %E ["Have you progressed with your quest to regain the Amulet of Yendor for %d?"] %Cc Arc 00091 "Congratulations, %p. I wondered if anyone could prevail against the Wizard and the minions of Moloch. Now, you must embark on one final adventure. "Take the Amulet, and find your way onto the Astral Plane. There you must find the altar of %d and sacrifice the Amulet on that altar to fulfill your destiny. "Remember, your path now should always be upwards." %E [Take the Amulet to the Astral Plane and sacrifice it at the altar of %d.] # # Barbarian # %Cc Bar 00001 Warily you scan your surroundings, all of your senses alert for signs of possible danger. Off in the distance, you can %x the familiar shapes of %H. But why, you think, should %l be there? Suddenly, the hairs on your neck stand on end as you detect the aura of evil magic in the air. Without thought, you ready your weapon, and mutter under your breath: "By %d, there will be blood spilt today." %E [You reach the vicinity of %H, but sense evil magic nearby.] %Cp Bar 00002 Once again, you near %H. You know that %l will be waiting. %E %Cp Bar 00003 Again, and you think possibly for the last time, you approach %H. %E %Cp Bar 00005 "The battles here have been good -- our enemies' blood soaks the soil!" %E %Cp Bar 00006 "Remember that glory is crushing your enemies beneath your feet!" %E %Cp Bar 00007 "There has been little treasure to loot, since the horde arrived." %E %Cp Bar 00008 "The horde is mighty in numbers, but they have little courage." %E %Cp Bar 00009 "%lC is a strange one, but he has helped defend us." %E %Cp Bar 00010 "The battles here have been good -- our enemies' blood soaks the soil!" %E %Cp Bar 00011 "Remember that glory is crushing your enemies beneath your feet!" %E %Cp Bar 00012 "Times will be good again, now that the horde is vanquished." %E %Cp Bar 00013 "You have brought our clan much honor in defeating %n." %E %Cp Bar 00014 "You will be a worthy successor to %l." %E %Cc Bar 00015 "Ah, %p. You have returned at last. The world is in dire need of your help. There is a great quest you must undertake. "But first, I must see if you are ready to take on such a challenge." %E ["At last you have returned. There is a great quest you must undertake."] %Cp Bar 00016 "%p, you are back. Are you ready now for the challenge?" %E %Cp Bar 00017 "Again, you stand before me, %p. Surely you have prepared yourself." %E %Cc Bar 00018 "Pah! You have betrayed the gods, %p. You will never attain the glory which you aspire to. Your failure to follow the true path has closed this future to you. "I will protect these people as best I can, but soon %n will overcome me and destroy all who once called you %s. Now begone!" %E ["You have betrayed %d; soon %n will destroy us. Begone!"] %Cc Bar 00019 "%p, I fear that you are as yet too inexperienced to face %n. Only %Ra with the help of %d could ever hope to defeat %ni." %E ["You are too inexperienced. Come back when you are %Ra."] %Cc Bar 00020 "%pC! You have wandered from the path of the %a! If you attempt to overcome %n in this state, he will surely enslave your soul. Your only hope, and ours, lies in your purification. Go forth, and return when you feel ready." %E ["You have wandered from the path of the %a. Come back when you have atoned."] %Cc Bar 00021 "The world is in great need of your assistance, %p. "About six months ago, I learned that a mysterious sorcerer, known as %n, had begun to gather a large group of cutthroats and brigands about %ni. "At about the same time, these people you once rode with `liberated' a potent magical talisman, %o, from a Turanian caravan. "%nC and %nj Black Horde swept down upon %i and defeated the people there, driving them out into the desert. He has taken %o, and seeks to bend it to %nj will. I detected the subtle changes in the currents of fate, and joined these people. Then I sent forth a summons for you. "If %n can bend %o to %nj will, he will become almost indestructible. He will then be able to enslave the minds of men across the world. You are the only hope. The gods smile upon you, and with %d behind you, you alone can defeat %n. "You must go to %i. From there, you can track down %n, defeat %ni, and return %o to us. Only then will the world be safe." %E ["Find %n, defeat %ni, and return %o to us."] %Cp Bar 00025 "%nC is strong in the dark arts, but not immune to cold steel." %E %Cp Bar 00026 "Remember that %n is a great sorcerer. He lived in the time of Atlantis." %E %Cp Bar 00027 "If you fail, %p, I will not be able to protect these people long." %E %Cp Bar 00028 "To enter %i, you must be very stealthy. The horde will be on guard." %E %Cp Bar 00029 "Call upon %d in your time of need." %E %Cp Bar 00030 "May %d protect you, and guide your steps." %E %Cp Bar 00031 "If you can lay hands upon %o, carry it for good fortune." %E %Cp Bar 00032 "I cannot stand against %ns sorcery. But %d will help you." %E %Cp Bar 00033 "Do not fear %n. I know you can defeat %ni." %E %Cp Bar 00034 "You have a great road to travel, %p, but only after you defeat %n." %E %Cc Bar 00035 The scent of water comes to you in the desert breeze. You know that you have located %i. %E [You have located %i.] %Cp Bar 00036 Yet again you have a chance to infiltrate %i. %E %Cc Bar 00040 The hairs on the nape of your neck lift as you sense an energy in the very air around you. You fight down a primordial panic that seeks to make you turn and run. This is surely the lair of %n. %E [This is surely the lair of %n.] %Cp Bar 00041 Yet again you feel the air around you heavy with malevolent magical energy. %E %Cc Bar 00050 "So. This is what that second rate sorcerer %l sends to do %lj bidding. I have slain many before you. You shall give me little sport. "Prepare to die, %c." %E [%nC boasts that %nh has slain many. "Prepare to die, %c."] %Cp Bar 00051 "I have wasted too much time on you already. Now, you shall die." %E %Cp Bar 00052 "You return yet again, %c! Are you prepared for death now?" %E %Cp Bar 00053 "I shall have %o back, you pitiful excuse for %ca. And your life as well." %E %Cp Bar 00060 "My pets will dine on your carcass tonight!" %E %Cp Bar 00061 "You are a sorry excuse for %ra." %E %Cp Bar 00062 "Run while you can, %c. My next spell will be your last." %E %Cp Bar 00063 "I shall use your very skin to bind my next grimoire." %E %Cp Bar 00064 "%d cannot protect you now. Here, you die." %E %Cp Bar 00065 "Your %a nature makes you weak. You cannot defeat me." %E %Cp Bar 00066 "Come, %c. I shall kill you, then unleash the horde on your tribe." %E %Cp Bar 00067 "Once you are dead, my horde shall finish off %l, and your tribe." %E %Cp Bar 00068 "Fight, %c, or are you afraid of the mighty %n?" %E %Cp Bar 00069 "You have failed, %c. Now, my victory is complete." %E %Cc Bar 00070 As you pick up %o, you feel the power of it flowing through your hands. It seems to be in two or more places at once, even though you are holding it. %E [You feel the power of %o flowing through your hands.] %Cc Bar 00080 %nC falls to the ground, and utters a last curse at you. Then %nj body fades slowly, seemingly dispersing into the air around you. You slowly become aware that the overpowering aura of magic in the air has begun to fade. %E [%nC curses you, but you feel the overpowering aura of magic fading.] %Cc Bar 00081 When %l sees %o, he smiles, and says: Well done, %p. You have saved the world from certain doom. What, now, should be done with %o? These people, brave as they are, cannot hope to guard it from other sorcerers who will detect it, as surely as %n did. Take %o with you, %p. It will guard you in your adventures, and you can best guard it. You embark on a quest far greater than you realize. Remember me, %p, and return when you have triumphed. I will tell you then of what you must do. You will understand when the time comes. %E [%lC tells you to guard %o, and to return when you have triumphed.] %Cc Bar 00082 %l gazes reverently at %o, then back at you. "You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal which brought you here." %E ["You keep %o. Return to %Z to search for the Amulet."] %Cp Bar 00090 "Tell us, %p, have you fared well on your great quest?" %E %Cc Bar 00091 "This is wondrous, %p. I feared that you could not possibly succeed in your quest, but here you are in possession of the Amulet of Yendor! "I have studied the texts of the magi constantly since you left. In the Book of Skelos, I found this: %d will cause a child to be sent into the world. This child is to be made strong by trial of battle and magic, for %d has willed it so. It is said that the child of %d will recover the Amulet of Yendor that was stolen from the Creator at the beginning of time. "As you now possess the amulet, %p, I suspect that the Book speaks of you. The child of %d will take the Amulet, and travel to the Astral Plane, where the Great Temple of %d is to be found. The Amulet will be sacrificed to %d, there on %dJ altar. Then the child will stand by %d as champion of all %cP for eternity. "This is all I know, %p. I hope it will help you." %E ["Take the Amulet to the altar of %d on the Astral Plane and offer it."] # # Cave(wo)man # %Cc Cav 00001 You descend through a barely familiar stairwell that you remember %l showing you when you embarked upon your vision quest. You arrive back at %H, but something seems wrong here. The usual smoke and glowing light of the fires of the outer caves are absent, and an uneasy quiet fills the damp air. %E [You arrive back at %H, but something is wrong here.] %Cp Cav 00002 Once again, you arrive back at %H. %E %Cp Cav 00003 For some reason, you think that this may be the last time you will enter %H. %E %Cp Cav 00005 "We have not been able to gather as much food since the Giants sealed off our access to the outer world." %E %Cp Cav 00006 "Since %n sent her minions, we have been constantly fighting." %E %Cp Cav 00007 "I have heard your vision quest was successful. Is this so?" %E %Cp Cav 00008 "So, tell me, %p, how have you fared?" %E %Cp Cav 00009 "%lC grows old. We know not who will guide us after he ascends." %E %Cp Cav 00010 "The rains have returned and the land grows lush again." %E %Cp Cav 00011 "Peace has returned, give thanks to %d!" %E %Cp Cav 00012 "Welcome back! Did you find %o?" %E %Cp Cav 00013 "So, %p, tell us the story of your fight with %n." %E %Cp Cav 00014 "%lC grows old. Perhaps you will guide us after he ascends." %E %Cc Cav 00015 "You have returned from your vision quest, %p. Thank %d. "We are in dire need of your help, my %S. "But first, I must see if you are yet capable of the quest I would ask you to undertake." %E ["You have returned. We are in dire need of your help."] %Cp Cav 00016 "Again, you return to us, %p. Let me see if you are ready now." %E %Cp Cav 00017 "Ah, %p. Are you finally ready?" %E %Cc Cav 00018 "%pC! You have sealed our fate. You seem unable to reform yourself, so I must select another to take your place. "Begone from %H! You have betrayed us by choosing the path of the %C over the true path of the %L. "You no longer live in our eyes." %E ["You have betrayed the %L. Begone!"] %Cc Cav 00019 "Alas, %p, you are as yet too inexperienced to embark upon such a difficult quest as that I propose to give you. "%rA could not possibly survive the rigors demanded to find %i, never mind to confront %n herself. "Adventure some more, and you will learn the skills you will require. %d decrees it." %E ["%rA is too inexperienced. Come back when you have progressed."] %Cc Cav 00020 "%pC! You have deviated from my teachings. You no longer follow the path of the %a as you should. I banish you from these caves, to go forth and purify yourself. Then, you might be able to accomplish this quest." %E ["You no longer follow the path of the %a. Go, and purify yourself."] %Cc Cav 00021 "You are indeed ready now, %p. I shall tell you a tale of great suffering among your people: "Shortly after you left on your vision quest, the caves were invaded by the creatures sent against us by %n. "She, herself, could not attack us due to her great size, but her minions have harassed us ever since. In the first attacks, many died, and the minions of %n managed to steal %o. They took it to %i and there, none of our %g warriors have been able to go. "You must find %i, and within it wrest %o from %n. She guards it as jealously as she guards all treasures she attains. But with it, we can make our caves safe once more. "Please, %p, recover %o for us, and return it here." %E [Find and defeat %n, recover %o, and return with it.] %Cp Cav 00025 "%nC is immune to her own breath weapons. You should use magic upon her that she does not use herself." %E %Cp Cav 00026 "When you encounter %n, call upon %d for assistance." %E %Cp Cav 00027 "There will be nowhere to hide inside %ns inner sanctum." %E %Cp Cav 00028 "Your best chance with %n will be to keep moving." %E %Cp Cav 00029 "Do not be distracted by the great treasures in %ns lair. Concentrate on %o." %E %Cp Cav 00030 "%oC is the only object that %n truly fears." %E %Cp Cav 00031 "Do not be fooled by %ns size. She is fast, and it is rumored that she uses magic." %E %Cp Cav 00032 "I would send a party of %gP with you, but we will need all of our strength to defend ourselves." %E %Cp Cav 00033 "Remember, be %a at all times. This is your strength." %E %Cp Cav 00034 "If only we had an amulet of reflection, this would not have happened." %E %Cc Cav 00035 You %x many large claw marks on the ground. The tunnels ahead of you are larger than most of those in any cave complex you have ever been in before. Your nose detects the smell of carrion from within, and bones litter the sides of the tunnels. %E [You %x many large claw marks, smell carrion, and notice bones.] %Cp Cav 00036 Once again, you approach %i. %E %Cc Cav 00040 You find yourself in a large cavern, with neatly polished walls, that nevertheless show signs of being scorched by fire. Bones litter the floor, and there are objects scattered everywhere. The air is close with the stench of sulphurous fumes. %nC is clearly visible, but %nh seems to be asleep. %E [You enter a large cavern. %nC is present.] %Cp Cav 00041 Once again, you find yourself in the lair of %n. %E %Cc Cav 00050 "So, follower of %l, you seek to invade the lair of %n. Only my meals are allowed down here. Prepare to be eaten!" %E [%nC threatens to eat you.] %Cp Cav 00051 "So, again you face me, %c. No one has ever before escaped me. Now I shall kill you." %E %Cp Cav 00052 "You are getting annoying, %c. Prepare to die." %E %Cp Cav 00053 "I'll have %o from you, %c. You shall die." %E %Cp Cav 00060 "You are weak, %c. No challenge for the Mother of all Dragons." %E %Cp Cav 00061 "I grow hungry, %r. You look like a nice appetizer!" %E %Cp Cav 00062 "Join me for lunch? You're the main course, %c." %E %Cp Cav 00063 "With %o, I am invincible! You cannot succeed." %E %Cp Cav 00064 "Your mentor, %l has failed. You are nothing to fear." %E %Cp Cav 00065 "You shall die here, %c. %rA cannot hope to defeat me." %E %Cp Cav 00066 "You, a mere %r challenge the might of %n? Hah!" %E %Cp Cav 00067 "I am the Mother of all Dragons! You cannot hope to defeat me." %E %Cp Cav 00068 "My claws are sharp now. I shall rip you to shreds!" %E %Cp Cav 00069 "%d has deserted you, %c. This is my domain." %E %Cc Cav 00070 As you pick up %o it seems heavy at first, but as you hold it strength flows into your arms. You suddenly feel full of power, as if nothing could possibly stand in your path. %E [%oC fills you with a feeling of power.] %Cp Cav 00080 %nC sinks to the ground, her heads flailing about. As she dies, a cloud of noxious fumes billows about her. %E %Cc Cav 00081 %lC glimpses %o in your possession. He smiles and says: You have done it! We are saved. But I fear that %o will always be a target for %C forces who will want it for their own. To prevent further trouble, I would like you, %p, to take %o away with you. It will help you as you quest for the Amulet of Yendor. %E ["Take %o with you. It will help in your quest for the Amulet of Yendor."] %Cc Cav 00082 %l grasps %o proudly for a moment, then looks at you. "You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal which brought you here." %E ["You are the keeper of %o now. Return to %Z to search for the Amulet.] %Cp Cav 00090 "%pC! Welcome back. How goes your quest to recover the Amulet for %d?" %E %Cc Cav 00091 "You have been successful, I see, %p. "Now that the Amulet of Yendor is yours, here is what you must do: "Journey upwards to the open air. The Amulet you carry will then take you into the Astral Planes, where the Great Temple of %d casts its influence throughout our world. "Sacrifice the Amulet on the altar. Thus shall %d become supreme!" %E ["Take the Amulet to the altar of %d on the Astral Plane and offer it."] # # Healer # %Cc Hea 00001 What sorcery has brought you back to %H? The smell of fresh funeral pyres tells you that something is amiss with the healing powers that used to practice here. No rhizotomists are tending the materia medica gardens, and where are the common folk who used to come for the cures? You know that you must quickly make your way to the collegium, and %ls iatreion, and find out what has happened in your absence. %E [You arrive back at %H and must find %l.] %Cp Hea 00002 After your last experience you expected to be here, but you certainly did not expect to see things so much worse. This time you must succeed. %E %Cp Hea 00003 Again, you %x %H in the distance. The smell of death and disease permeates the air. You do not have to be %Ra to know that %n is on the verge of victory. %E %Cp Hea 00005 "Did you read that new treatise on the therapeutic use of leeches?" %E %Cp Hea 00006 "Paint a red caduceus on your shield and monsters won't hit you." %E %Cp Hea 00007 "I passed handwriting so they are demoting me a rank." %E %Cp Hea 00008 "I've heard that even %l has not been able to cure Chiron." %E %Cp Hea 00009 "We think %n has used %nj alchemists, and %o, to unleash a new disease we call 'the cold' on Gehennom." %E %Cp Hea 00010 "Did you read that new treatise on the therapeutic use of leeches?" %E %Cp Hea 00011 "Paint a red caduceus on your shield and monsters won't hit you." %E %Cp Hea 00012 "How are you feeling? Perhaps a good bleeding will improve your spirits." %E %Cp Hea 00013 "Have you heard the absurd new theory that diseases are caused by microscopic organisms, and not ill humors?" %E %Cp Hea 00014 "I see that you bring %o, now you can cure this plague!" %E %Cc Hea 00015 Feebly, %l raises %lj head to look at you. "It is good to see you again, %p. I see the concern in your eyes, but do not worry for me. I am not ready for Hades yet. We have exhausted much of our healing powers holding off %n. I need your fresh strength to carry on our work. "Come closer and let me lay hands on you, and determine if you have the skills necessary to accomplish this mission." %E [%l is weak from the struggle with %n. %lH wants to examine you.] %Cp Hea 00016 "Again you return to me, %p. I sense that each trip back the pleurisy and maladies of our land begin to infect you. Let us hope and pray to %d that you become ready for your task before you fall victim to the bad humors." %E %Cp Hea 00017 "Chiron has fallen, Hermes has fallen, what else must I tell you to impress upon you the importance of your mission! I hope that you have come prepared this time." %E %Cc Hea 00018 "You have failed us, %p. You are a quack! A charlatan! "Hades will be happy to hear that you are once again practicing your arts on the unsuspecting." %E [You are a failure as a healer.] %Cc Hea 00019 "Alas, %p, you are yet too inexperienced to deal with the rigors of such a task. You must be able to draw on the knowledge of botany, vetenary, and alchemy before I can send you on this quest with good conscience. "Return when you wear %Ra's caduceus." %E [You are too inexperienced. Return when you are %Ra.] %Cc Hea 00020 "You have learned much of the remedies that benefit, but you must also know which physic for which ail. That is why %ds teachings are a part of your training. "Return to us when you have healed thyself." %E [Return when you are more %a.] %Cc Hea 00021 For the first time, you sense a smile on %ls face. "You have indeed learned as much as we can teach you in preparation for this task. Let me tell you what I know of the symptoms and hope that you can provide a cure. "A short while ago, the dreaded %nt was fooled by the gods into thinking that %nh could use %o to find a cure for old age. Think of it, eternal youth! But %nj good health is accomplished by drawing the health from those around %ni. "He has exhausted %nj own supply of healthy people and now %nh seeks to extend %nj influence into our world. You must recover from %ni %o and break the spell. "You must travel into the swamps to %i, and from there follow the trail to %ns island lair. Be careful." %E [Travel to %i on your way to recover %o from %n.] %Cp Hea 00025 "Remember, %p, to always wash your hands before operating." %E %Cp Hea 00026 "%nC has no real magic of %nj own. To this %nh is vulnerable." %E %Cp Hea 00027 "If you have been true to %d, you can draw on the power of %o." %E %Cp Hea 00028 "Bring with you antidotes for poisons." %E %Cp Hea 00029 "Remember this, %n can twist the powers of %o to hurt instead of heal." %E %Cp Hea 00030 "I have sent for Chiron, but I am afraid he will come too late." %E %Cp Hea 00031 "Maybe when you return the snakes will once again begin to shed." %E %Cp Hea 00032 "The plague grows worse as we speak. Hurry, %p!" %E %Cp Hea 00033 "Many times %n has caused trouble in these lands. It is time that %nh was eradicated like the diseases %nh has caused." %E %Cp Hea 00034 "With but one eye, %n should be easy to blind. Remember this." %E %Cc Hea 00035 You stand before the entrance to %i. Strange scratching noises come from within the building. The swampy ground around you seems to stink with disease. %E [You have reached %i but all is not well.] %Cp Hea 00036 Once again you stand at the entrance to %i. %E %Cc Hea 00040 You stand within sight of the infamous Isle of %n. Even the words of %l had not prepared you for this. Steeling yourself against the wails of the ill that pierce your ears, you hurry on your task. Maybe with %o you can heal them on your return, but not now. %E [You have reached the lair of %n. Take %o away from %ni.] %Cp Hea 00041 Once again, you %x the Isle of %n in the distance. %E %Cc Hea 00050 "They have made a mistake in sending you, %p. "When I add your youth to mine, it will just make it easier for me to defeat %l." %E ["I will take your life, then defeat %l."] %Cp Hea 00051 "Unlike your patients, you seem to keep coming back, %p!" %E %Cp Hea 00052 "Which would you like, %p? Boils, pleurisy, convulsions?" %E %Cp Hea 00053 "I'll have %o back from you, %r. You are not going to live to escape this place." %E %Cp Hea 00060 "They might as well give scalpels to wizards as to let you try to use %o!" %E %Cp Hea 00061 "If I could strike %l, surrounded by %lj %gP, imagine what I can do to you here by yourself." %E %Cp Hea 00062 "I will put my %Rp to work making a physic out of your ashes." %E %Cp Hea 00063 "As we speak, Hades gathers your patients to join you." %E %Cp Hea 00064 "After I'm done with you, I'll destroy %l as well." %E %Cp Hea 00065 "You will have to kill me if you ever hope to leave this place." %E %Cp Hea 00066 "I will impale your head on my caduceus for all to see." %E %Cp Hea 00067 "There is no materia medica in your sack which will cure you of me!" %E %Cp Hea 00068 "Do not fight too hard, I want your soul strong, not weakened!" %E %Cp Hea 00069 "You should have stopped studying at vetenary." %E %Cc Hea 00070 As you pick up %o, you feel its healing begin to warm your soul. You curse Zeus for taking it from its rightful owner, but at least you hope that %l can put it to good use once again. %E [You feel the healing power of %o and should return it to %l.] %Cc Hea 00080 The battered body of %n slumps to the ground and gasps out one last curse: "You have defeated me, %p, but I shall have my revenge. How, I shall not say, but this curse shall be like a cancer on you." With that %n dies. %E [%nC curses you as %nh dies.] %Cc Hea 00081 As soon as %l sees %o %lh summons %lj %gP. Gently, %l reaches out and touches %o. He instructs each of the assembled to do the same. When everyone has finished %lh speaks to you. "Now that we have been replenished we can defeat this plague. You must take %o with you and replenish the worlds you have been called upon to travel next. I wish you could ride Chiron to the end of your journey, but I need him to help me spread the cure. Go now and continue your journey." %E [%l touches %o and tells %lj %gP to do so too, then tells you to take it with you.] %Cc Hea 00082 %l cautiously handles %o while watching you. "You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal which brought you here." %E [%l tells you to keep %o and return to %Z to search for the Amulet.] %Cp Hea 00090 "You have again returned to us, %p. We have done well in your absence, yes? How fare you upon your quest for the Amulet?" %E %Cc Hea 00091 "Ah, you have recovered the Amulet, %p. Well done! "Now, you should know that you must travel through the Elemental Planes to the Astral, and there return the Amulet to %d. Go forth and may our prayers be as a wind upon your back." %E ["You have recovered the Amulet. Travel to the Astral Plane and return it to %d."] # # Knight # %Cc Kni 00001 You materialize in the shadows of %H. Immediately, you notice that something is wrong. The fields around the castle are trampled and withered, as if some great battle has been recently fought. Exploring further, you %x long gouges in the walls of %H. You know of only one creature that makes those kinds of marks... %E [Signs of battle include long gouges in the walls of %H.] %Cp Kni 00002 Once again you stand in the shadows of %H. %E %Cp Kni 00003 Again, you stand before %H. You vaguely sense that this may be the last time you stand before %l. %E %Cp Kni 00005 "Hail, %p! Verily, thou lookest well." %E %Cp Kni 00006 "There is word, %p, that %n hath been sighted in the fens near %i." %E %Cp Kni 00007 "Thou art our only hope now, %p." %E %Cp Kni 00008 "Verily, %l could have no better champion, %p." %E %Cp Kni 00009 "Many brave %cP died when %n attacked." %E %Cp Kni 00010 "Hail, %p! Verily, thou lookest well." %E %Cp Kni 00011 "So, %p, didst thou find %n in the fens near %i?" %E %Cp Kni 00012 "Worthy %p, hast thou proven thy right purpose on the body of %n?" %E %Cp Kni 00013 "Verily, %l could have no better champion, %p." %E %Cp Kni 00014 "Hast thou indeed recovered %o?" %E %Cc Kni 00015 "Ah, %p. We see thou hast received Our summons. We are in dire need of thy prowess. But first, We must needs decide if thou art ready for this great undertaking." %E [%lC checks whether you are ready for a great undertaking.] %Cp Kni 00016 "Welcome again, %p. We hope thou art ready now." %E %Cp Kni 00017 "Once again, thou standest before Us, %p. Art thou ready now?" %E %Cc Kni 00018 "Thou disgracest this noble court with thine impure presence. We have been lenient with thee, but no more. Thy name shall be spoken no more. We hereby strip thee of thy title, thy lands, and thy standing as %ca. Begone from Our sight!" %E [You are a disgrace as %ca.] %Cc Kni 00019 "Verily, %p, thou hast done well. That thou hast survived thus far is a credit to thy valor, but thou art yet unprepared for the demands required as Our Champion. %rA, no matter how pure, could never hope to defeat the foul %n. "Journey forth from this place, and hone thy skills. Return to Our presence when thou hast attained the noble title of %R." %E [You are not prepared to face %n. Return when you are %Ra.] %Cc Kni 00020 "Thou dishonourest Us, %p! Thou hast strayed from the path of chivalry! Go from Our presence and do penance. Only when thou art again pure mayst thou return hence." %E [Go and do penance. Return when you are truly %a.] %Cc Kni 00021 "Ah, %p. Thou art truly ready, as no %c before thee hath been. Hear now Our words: "As thou noticed as thou approached %H, a great battle hath been fought recently in these fields. Know thou that Merlin himself came to aid Us here as We battled the foul %n. In the midst of that battle, %n struck Merlin a great blow, felling him. Then, as Our forces were pressed back, %n stole %o. "We eventually turned the tide, but lost many %cP in doing so. Merlin was taken off by his apprentice, but hath not recovered. We have been told that so long as %n possesseth %o, Merlin will not regain his health. "We hereby charge thee with this most important of duties: "Go forth from this place, to the fens, and there thou wilt find %i. From there, thou must track down %n. Destroy the beast, and return to Us %o. Only then can We restore Merlin to health." %E [Pass through %i to reach %n. Destroy %ni and return with %o.] %Cp Kni 00025 "Remember, %p, follow always the path of %d." %E %Cp Kni 00026 "Though %n is verily a mighty foe, We have confidence in thy victory." %E %Cp Kni 00027 "Beware, for %n hath surrounded %niself with hordes of foul creatures." %E %Cp Kni 00028 "Great treasure, 'tis said, is hoarded in the lair of %n." %E %Cp Kni 00029 "If thou possessest %o, %p, %ns magic shall therewith be thwarted." %E %Cp Kni 00030 "The gates of %i are guarded by forces unseen, %p. Go carefully." %E %Cp Kni 00031 "Return %o to Us quickly, %p." %E %Cp Kni 00032 "Destroy %n, %p, else %H shall surely fall." %E %Cp Kni 00033 "Call upon %d when thou art in need." %E %Cp Kni 00034 "To find %i, thou must keep thy heart pure." %E %Cc Kni 00035 You stand at the foot of %i. Atop, you can %x a shrine. Strange energies seem to be focused here, and the hair on the back of your neck stands on end. %E [You have reached %i and can %x a shrine.] %Cp Kni 00036 Again, you stand at the foot of %i. %E %Cc Kni 00040 As you exit the swamps, you %x before you a huge, gaping hole in the side of a hill. From within, you smell the foul stench of carrion. The pools on either side of the entrance are fouled with blood, and pieces of rusted metal and broken weapons show above the surface. %E [You %x the entrance to a cavern inside a hill.] %Cp Kni 00041 Again, you stand at the entrance to %ns lair. %E %Cc Kni 00050 "Hah! Another puny %c seeks death. I shall dine well tonight, then tomorrow, %H shall fall!" %E [%nC taunts you and issues a threat against %H.] %Cp Kni 00051 "Again, thou challengest me, %r? So be it. Thou wilt die here." %E %Cp Kni 00052 "Thou art truly foolish, %r. I shall dispatch thee anon." %E %Cp Kni 00053 "So, thou darest touch MY property! I shall have that bauble back, puny %r. Thou wilt die in agony!" %E %Cp Kni 00060 "A mere %r can never withstand me!" %E %Cp Kni 00061 "I shall kill thee now, and feast!" %E %Cp Kni 00062 "Puny %c. What manner of death dost thou wish?" %E %Cp Kni 00063 "First thee, %p, then I shall feast upon %l." %E %Cp Kni 00064 "Hah! Thou hast failed, %r. Now thou shalt die." %E %Cp Kni 00065 "Die, %c. Thou art as nothing against my might." %E %Cp Kni 00066 "I shall suck the marrow from thy bones, %c." %E %Cp Kni 00067 "Let's see... Baked? No. Fried? Nay. Broiled? Yea verily, that is the way I like my %c for dinner." %E %Cp Kni 00068 "Thy strength waneth, %p. The time of thy death draweth near." %E %Cp Kni 00069 "Call upon thy precious %d, %p. It shall not avail thee." %E %Cc Kni 00070 As you pick up %o, you feel its protective fields form around your body. You also feel a faint stirring in your mind, as if you are in two places at once, and in the second, you are waking from a long sleep. %E [You feel the magic of %o.] %Cc Kni 00080 As %n sinks to the ground, blood gushing from %nj open mouth, %nh defiantly curses you and %l: "Thou hast not won yet, %r. By the gods, I shall return and dog thy steps to the grave!" %nJ tail flailing madly, %n tries to crawl towards you, but slumps to the ground and dies in a pool of %nj own blood. %E [%nC curses you as %nh dies.] %Cc Kni 00081 As you approach %l, %lh beams at you and says: "Well done! Thou art truly the Champion of %H. We have received word that Merlin is recovering, and shall soon rejoin Us. "He hath instructed Us that thou art now to be the guardian of %o. He feeleth that thou mayst have need of its powers in thine adventures. It is Our wish that thou keepest %o with thee as thou searchest for the fabled Amulet of Yendor." %E [%oC is yours now. It will aid in your search for the Amulet.] # assumes Magic Mirror of Merlin (glass object) %Cc Kni 00082 "Careful, %p! %oC might break, and that would be a tragic loss. Thou art its keeper now, and the time hath come to resume thy search for the Amulet. %Z await thy return through the magic portal that brought thee here." %E [You are the keeper of %o. Return to %Z and find the Amulet.] %Cp Kni 00090 "Well met, %p. How goeth thy search for the Amulet of Yendor?" %E %Cc Kni 00091 "Thou hast succeeded, We see, %p! Now thou art commanded to take the Amulet to be sacrificed to %d in the Plane of the Astral. "Merlin hath counseled Us that thou must travel always upwards through the Planes of the Elements, to achieve this goal. "Go with %d, %p." %E [Take the Amulet to the Astral Plane and deliver it to %d.] # # Monk # # The quest artifact is "The Eyes of the Overworld", hence needs # to be treated as plural by messages which use %o. # %Cc Mon 00001 You find yourself standing in sight of %H. Something is obviously wrong here. Strange shapes lumber around outside %H! You realize that the %l needs your assistance! %E [You have reached %H but something is wrong. %lC needs your aid.] %Cp Mon 00002 Once again, you stand before %H. %E %Cp Mon 00003 Again you face %H. Your intuition hints that this may be the final time you come here. %E %Cp Mon 00005 "Greetings, honorable %r. It is good to see you." %E %Cp Mon 00006 "Ah, %p! Surely you can help us in our hour of need." %E %Cp Mon 00007 "Greetings, %s. %lC has great need of your help." %E %Cp Mon 00008 "Alas, it seems as if even %d has deserted us." %E %Cp Mon 00009 "May %d be with you, %s." %E %Cp Mon 00010 "Greetings, honorable %r. It is good to see you again." %E %Cp Mon 00011 "Ah, %p! Our deepest gratitude for all of your help." %E %Cp Mon 00012 "Greetings, %s. Perhaps you will take some time to meditate with us?" %E %Cp Mon 00013 "With this test behind you, may %d bring you enlightenment." %E %Cp Mon 00014 "May %d be with you, %s." %E %Cc Mon 00015 "Ah, %p, my %S. You have returned to us at last. A great blow has befallen our order; perhaps you can help us. First, however, I must determine if you are prepared for this great challenge." %E [%lC checks whether you are ready for the great challenge.] %Cp Mon 00016 "Again, my %S, you stand before me. Are you ready now to help us?" %E %Cp Mon 00017 "Once more, %p, you stand within the sanctum. Are you ready now?" %E %Cc Mon 00018 "You are a heretic, %p! How can you, %ra, deviate so from the teachings of %d? Begone from this temple. You are no longer %sa to this order. We will pray to %d for other assistance, as you have failed us utterly." %E [You are a heretic and have failed utterly.] %Cc Mon 00019 "Alas, %p, it is not yet to be. A mere %r could never withstand the might of %n. Go forth, again into the world, and return when you have attained the post of %R." %E [You are not ready to face %n. Come back when you are %Ra.] %Cc Mon 00020 "This is terrible, %p. You have deviated from the true path! You know that %d requires the most strident devotion of this order. The %shood must stand for utmost piety. "Go from here, atone for your sins against %d. Return only when you have purified yourself." %E [You must atone. Come back when you are worthy of %d.] %Cc Mon 00021 "Yes, %p. You are truly ready now. Attend to me and I shall tell you of what has transpired: "During one of the Great Meditations a short time ago, %n and a legion of elementals invaded %H. Many %gP were killed, including the one bearing %o. Now, there are barely enough %gP left to keep the elementals at bay. "We need you to find %i, then, from there, travel to %ns lair. If you can manage to defeat %n and return %o here, we can then drive off the legions of elementals that slay our students. "Go with %d as your guide, %p." %E [Find %i, then continue to %ns lair. Defeat %ni and return with %o.] %Cp Mon 00025 "You can prevail, if you rely on %d." %E %Cp Mon 00026 "Remember that %n has great magic at his command." %E %Cp Mon 00027 "Be pure, my %S." %E %Cp Mon 00028 "Beware, %i is surrounded by hordes of earth elementals." %E %Cp Mon 00029 "Remember your studies, and you will prevail!" %E %Cp Mon 00030 "Acquire and wear %o if you can. They will aid you against %n." %E %Cp Mon 00031 "Call upon %d when your need is greatest. You will be answered." %E %Cp Mon 00032 "Remember to use the elementals' strength against them!" %E %Cp Mon 00033 "Do not lose faith, %p. If you do so, %n will grow stronger." %E %Cp Mon 00034 "Wear %o. They will assist you in your efforts." %E %Cc Mon 00035 You remember the descriptions of %i, given to you by the %l. It is ahead that you will find %n's trail. %E [You have reached %i. %nC lurks further ahead.] %Cp Mon 00036 Again, you stand before %i. %E %Cc Mon 00040 The stench of brimstone is all about you, and the elementals close in from all sides! Ahead, there is a small clearing amidst the bubbling pits of lava... %E [You are surrounded by brimstone, lava, and elementals.] %Cp Mon 00041 Again, you have invaded %ns domain. %E %Cc Mon 00050 "Ah, so %l has sent another %g to retrieve %o. "No, I see you are no %g. Perhaps I shall have some fun today after all. Prepare to die, %r! You shall never regain %o." %E [You are no %g. You shall never regain %o.] %Cp Mon 00051 "So, %r. Again you challenge me." %E %Cp Mon 00052 "Die now, %r. %d has no power here to aid you." %E %Cp Mon 00053 "You shall die, %r, and I will have %o back." %E %Cp Mon 00060 "Submit to my will, %c, and I shall spare you." %E %Cp Mon 00061 "Your puny powers are no match for me, %c." %E %Cp Mon 00062 "I shall have you turned into a zombie for my pleasure!" %E %Cp Mon 00063 "Despair now, %r. %d cannot help you." %E %Cp Mon 00064 "I shall feast upon your soul for many days, %c." %E %Cp Mon 00065 "Your death will be slow and painful. That I promise!" %E %Cp Mon 00066 "You cannot defeat %n, you fool. I shall kill you now." %E %Cp Mon 00067 "Your precious %lt will be my next victim." %E %Cp Mon 00068 "I feel your powers failing you, %r. You shall die now." %E %Cp Mon 00069 "With %o, nothing can stand in my way." %E %Cc Mon 00070 As you pick up %o, you feel the essence of %d fill your soul. You know now why %n stole %oi from %H, for with %oi, %ca of %d could easily defeat his plans. You sense a message from %d. Though not verbal, you get the impression that you must return to %l as soon as possible. %E [You feel the essence of %d and realize that you should take %o to %l.] %Cc Mon 00080 %nC gasps: "You have only defeated this mortal body. Know this: my spirit is strong. I shall return and reclaim what is mine!" With that, %n expires. %E [As %n dies, %nh threatens to return.] %Cc Mon 00081 "You have returned, %p. And with %o, I see. Congratulations. "I have been in meditation, and have received direction from a minion of %d. %d commands that you retain %o. With %oi, you must recover the Amulet of Yendor. "Go forth, and let %d guide your steps." %E [Keep %o. %oH will help you recover the Amulet of Yendor.] %Cc Mon 00082 %lC studies %o for a moment, then returns his gaze to you. "%oC must remain with you. Use %oi as you resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E [Keep %o and return to %Z to search for the Amulet.] %Cp Mon 00090 "Welcome back, %p. How is your quest for the Amulet going?" %E %Cc Mon 00091 "You have prevailed, %p! %d is surely with you. Now, you must take the Amulet, and sacrifice it on %ds altar on the Astral Plane. I suspect that I shall never see you again in this life, but I hope to at %ds feet." %E [Take the Amulet to the Astral Plane and deliver it to %d.] # # Priest # %Cc Pri 00001 You find yourself standing in sight of %H. Something is obviously wrong here. The doors to %H, which usually stand open, are closed. Strange human shapes shamble around outside. You realize that %l needs your assistance! %E [You are at %H; the doors are closed. %lC needs your help!] %Cp Pri 00002 Once again, you stand before %H. %E %Cp Pri 00003 Again you face %H. Your intuition hints that this may be the final time you come here. %E %Cp Pri 00005 "Greetings, honored %r. It is good to see you." %E %Cp Pri 00006 "Ah, %p! Surely you can help us in our hour of need." %E %Cp Pri 00007 "Greetings, %s. %lC has great need of your help." %E %Cp Pri 00008 "Alas, it seems as if even %d has deserted us." %E %Cp Pri 00009 "May %d be with you, %s." %E %Cp Pri 00010 "Greetings, %r. It is good to see you again." %E %Cp Pri 00011 "Ah, %p! Our deepest gratitude for all of your help." %E %Cp Pri 00012 "Welcome back, %s! With %o, no undead can stand against us." %E %Cp Pri 00013 "Praise be to %d, for delivering us from %n." %E %Cp Pri 00014 "May %d be with you, %s." %E %Cc Pri 00015 "Ah, %p, my %S. You have returned to us at last. A great blow has befallen our order; perhaps you can help us. First, however, I must determine if you are prepared for this great challenge." %E [You have returned and we need your help. Are you ready?] %Cp Pri 00016 "Again, my %S, you stand before me. Are you ready now to help us?" %E %Cp Pri 00017 "Once more, %p, you stand within the sanctum. Are you ready now?" %E %Cc Pri 00018 "You are a heretic, %p! How can you, %ra, deviate so from the teachings of %d? Begone from this temple. You are no longer %sa to this order. We will pray to %d for other assistance, as you have failed us utterly." %E [You are a heretic who has deviated from the teachings of %d.] %Cc Pri 00019 "Alas, %p, it is not yet to be. A mere %r could never withstand the might of %n. Go forth, again into the world, and return when you have attained the post of %R." %E [%rA cannot withstand %n. Come back when you are %Ra.] %Cc Pri 00020 "This is terrible, %p. You have deviated from the true path! You know that %d requires the most strident devotion of this order. The %shood must stand for utmost piety. "Go from here, atone for your sins against %d. Return only when you have purified yourself." %E [You have deviated from the path. Return when you have purified yourself.] %Cc Pri 00021 "Yes, %p. You are truly ready now. Attend to me and I shall tell you of what has transpired: "At one of the Great Festivals a short time ago, %n and a legion of undead invaded %H. Many %gP were killed, including the one carrying %o. "As a final act of vengefulness, %n desecrated the altar here. Without it, we could not mount a counter-attack. Now, there are barely enough %gP left to keep the undead at bay. "We need you to find %i, then, from there, travel to %ns lair. If you can manage to defeat %n and return %o here, we can then drive off the legions of undead that befoul the land. "Go with %d as your guide, %p." %E [%nC invaded %H and captured %o. Defeat %ni and retrive %oh.] %Cp Pri 00025 "You can prevail, if you rely on %d." %E %Cp Pri 00026 "Remember that %n has great magic at his command." %E %Cp Pri 00027 "Be pure, my %S." %E %Cp Pri 00028 "Beware, %i is surrounded by a great graveyard." %E %Cp Pri 00029 "You may be able to affect %n with magical cold." %E %Cp Pri 00030 "Acquire and wear %o if you can. It will aid you against %n." %E %Cp Pri 00031 "Call upon %d when your need is greatest. You will be answered." %E %Cp Pri 00032 "The undead legions are weakest during the daylight hours." %E %Cp Pri 00033 "Do not lose faith, %p. If you do so, %n will grow stronger." %E %Cp Pri 00034 "Wear %o. It will assist you against the undead." %E %Cc Pri 00035 You stand facing a large graveyard. The sky above is filled with clouds that seem to get thicker closer to the center. You sense the presence of undead in larger numbers than you have ever encountered before. You remember the descriptions of %i, given to you by %l. It is ahead that you will find %ns trail. %E [You have found %i. The trail to %n lies ahead.] %Cp Pri 00036 Again, you stand before %i. %E %Cc Pri 00040 The stench of brimstone is all about you, and the shrieks and moans of tortured souls assault your psyche. Ahead, there is a small clearing amidst the bubbling pits of lava... %E [The stench of brimstone surrounds you, the shrieks and moans are endless.] %Cp Pri 00041 Again, you have invaded %ns domain. %E %Cc Pri 00050 "Ah, so %l has sent another %gC to retrieve %o. "No, I see you are no %gC. Perhaps I shall have some fun today after all. Prepare to die, %r! You shall never regain %o." %E [%lC has sent you, but you are no %gC. I shall destroy you.] %Cp Pri 00051 "So, %r. Again you challenge me." %E %Cp Pri 00052 "Die now, %r. %d has no power here to aid you." %E %Cp Pri 00053 "You shall die, %r, and I will have %o back." %E %Cp Pri 00060 "Submit to my will, %c, and I shall spare you." %E %Cp Pri 00061 "Your puny powers are no match for me, %c." %E %Cp Pri 00062 "I shall have you turned into a zombie for my pleasure!" %E %Cp Pri 00063 "Despair now, %r. %d cannot help you." %E %Cp Pri 00064 "I shall feast upon your soul for many days, %c." %E %Cp Pri 00065 "Your death will be slow and painful. That I promise!" %E %Cp Pri 00066 "You cannot defeat %n, you fool. I shall kill you now." %E %Cp Pri 00067 "Your precious %lt will be my next victim." %E %Cp Pri 00068 "I feel your powers failing you, %r. You shall die now." %E %Cp Pri 00069 "With %o, nothing can stand in my way." %E %Cc Pri 00070 As you pick up %o, you feel the essence of %d fill your soul. You know now why %n stole it from %H, for with it, %ca of %d could easily defeat his plans. You sense a message from %d. Though not verbal, you get the impression that you must return to %l as soon as possible. %E [You feel %d as you pick up %o; return %oh to %l.] %Cc Pri 00080 You feel a wrenching shift in the ether as %ns body dissolves into a cloud of noxious gas. Suddenly, a voice booms out: "Thou hast defeated the least of my minions, %r. Know now that Moloch is aware of thy presence. As for thee, %n, I shall deal with thy failure at my leisure." You then hear the voice of %n, screaming in terror... %E [%nC dies. Moloch is aware of you and angry at %n.] %Cc Pri 00081 "You have returned, %p. And with %o, I see. Congratulations. "I have been in meditation, and have received direction from a minion of %d. %d commands that you retain %o. With it, you must recover the Amulet of Yendor. "Go forth, and let %d guide your steps." %E [Congraulations, %p. Keep %o; go and recover the Amulet.] %Cc Pri 00082 %lC reiterates that %o is yours now. "The time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E [%oC is yours now. Return to %Z and find the Amulet.] %Cp Pri 00090 "Welcome back, %p. How is your quest for the Amulet going?" %E %Cc Pri 00091 "You have prevailed, %p! %d is surely with you. Now, you must take the amulet, and sacrifice it on %ds altar on the Astral Plane. I suspect that I shall never see you again in this life, but I hope to at %ds feet." %E [Take the Amulet to the Astral Plane and offer it on %ds altar.] # # Ranger # # [Ran 00001: what if centaurs have been genocided?] %Cc Ran 00001 You arrive in familiar surroundings. In the distance, you %x the ancient forest grove, the place of worship to %d. Something is wrong, though. Surrounding the grove are centaurs! And they've noticed you! %E [The ancient forest grove is surrounded by centaurs.] %Cp Ran 00002 Once again, you stand before %H. %E %Cp Ran 00003 You have the oddest feeling that this may be the last time you are to enter %H. %E %Cp Ran 00005 "%pC! I have not seen you in many moons. How do you fare?" %E %Cp Ran 00006 "%nC continues to threaten the grove. But we hold fast." %E %Cp Ran 00007 "%lC is growing weak. The magic required to defend the grove drains us." %E %Cp Ran 00008 "Remember %i is hard to enter. Beware the distraction of leatherwings." %E %Cp Ran 00009 "We must regain %o. Without it we will be overrun." %E %Cp Ran 00010 "%pC! I have not seen you in many moons. How do you fare?" %E %Cp Ran 00011 "Birdsong has returned to the grove, surely this means you have defeated %n." %E %Cp Ran 00012 "%lC seems to have regained some of his strength." %E %Cp Ran 00013 "So, tell us how you entered %i, in case some new evil arises there." %E %Cp Ran 00014 "Is that truly %o that I see you carrying?" %E %Cc Ran 00015 "%pC! You have returned! Thank %d. "We have great need of you. But first, I must see if you have the required abilities to take on this responsibility." %E [You have returned, %p. We need your help. Are you ready?] %Cp Ran 00016 "Once again, %p, you stand in our midst. Are you ready now?" %E %Cp Ran 00017 "Ah, you are here again, %p. Allow me to determine your readiness..." %E %Cc Ran 00018 "%pC! You have doomed us all. You fairly radiate %L influences and weaken the power we have raised in this grove as a result! "Begone! We renounce your %shood with us! You are an outcast now!" %E [You are not sufficiently %a. We renounce your %shood.] %Cc Ran 00019 "%p, you are yet too inexperienced to withstand the demands of that which we need you to do. %RA might just be able to do this thing. "Return to us when you have learned more, my %S." %E [You are too inexperienced. Come back when you are %Ra.] %Cc Ran 00020 "You have strayed, %p! You know that %d requires that we maintain a pure devotion to things %a! "You must go from us. Return when you have purified yourself." %E [You are not sufficiently %a. Come back when you have purified yourself.] %Cc Ran 00021 "You are indeed ready, %p. I shall tell you what has transpired, and why we so desperately need your help: "A short time ago, the mountain centaurs to the east invaded and enslaved the plains centaurs in this area. The local leader is now only a figurehead, and serves %n. "During our last gathering of worship here, we were beset by hordes of hostile centaurs, as you witnessed. In the first onslaught a group, headed by %n %niself, managed to breach the grove and steal %o. "Since then, we have been besieged. We do not know how much longer we will be able to maintain our magical barriers. "If we are to survive, you, %p, must infiltrate %i. There, you will find a pathway down, to the underground cavern of %n. He has always coveted %o, and will surely keep it. "Recover %o for us, %p! Only then will %d be safe." %E [%nC has stolen %o. Infiltrate %i and retrieve %oh for us.] %Cp Ran 00025 "It is rumored that the Forest and Mountain Centaurs have resolved their ancient feud and now band together against us." %E %Cp Ran 00026 "%nC is strong, and very smart." %E %Cp Ran 00027 "Use %o, when you find it. It will help you survive to reach us." %E %Cp Ran 00028 "Remember, let %d be your guide." %E %Cp Ran 00029 "Call upon %d when you face %n. The very act of doing so will infuriate him, and give you advantage." %E %Cp Ran 00030 "%n and his kind have always hated us." %E %Cp Ran 00031 "We cannot hold the grove much longer, %p. Hurry!" %E %Cp Ran 00032 "To infiltrate %i, you must be very stealthy." %E %Cp Ran 00033 "Remember that %n is a braggart. Trust not what he says." %E %Cp Ran 00034 "You can triumph, %p, if you trust in %d." %E %Cc Ran 00035 This must be %i. You are in a cave built of many different rooms, all interconnected by tunnels. Your quest is to find and shoot the evil wumpus that resides elsewhere in the cave without running into any bottomless pits or using up your limited supply of arrows. Good luck. You are in room 9 of the cave. There are tunnels to rooms 5, 8, and 10. *rustle* *rustle* (must be bats nearby.) *sniff* (I can smell the evil wumpus nearby!) %E [This is %i. There are bats nearby. Beware the wumpus!] %Cc Ran 00036 Once again, you descend into %i. *whoosh* (I feel a draft from some pits.) *rustle* *rustle* (must be bats nearby.) %E [You are in %i. There are pits. There are bats nearby.] # [Ran 00040: 'hear a sound' but hero might be deaf.] %Cc Ran 00040 You descend into a weird place, in which roughly cut cave-like walls join with smooth, finished ones, as if someone was in the midst of finishing off the construction of a subterranean complex. Off in the distance, you hear a sound like the clattering of many hooves on rock. %E [You descend into a subterranean complex. Hooves clatter in the distance.] %Cp Ran 00041 Once again, you enter the distorted castle of %n. %E %Cc Ran 00050 "So, %c. %lC has sent you to recover %o. "Well, I shall keep that bauble. It pleases me. You, %c, shall die." %E [You have come to recover %o, but I shall keep %oh and you shall die.] %Cp Ran 00051 "Back again, eh? Well, a mere %r is no threat to me! Die, %c!" %E %Cp Ran 00052 "You haven't learned your lesson, %c. You can't kill me! You shall die now." %E %Cp Ran 00053 "I shall have %o from you, %r. Then I shall kill you." %E %Cp Ran 00060 "Your %d is nothing, %c. You are mine now!" %E %Cp Ran 00061 "Run away little %c! You can never hope to defeat %n!" %E %Cp Ran 00062 "My servants will rip you to shreds!" %E %Cp Ran 00063 "I shall display your head as a trophy. What do you think about that wall?" %E %Cp Ran 00064 "I shall break your %ls grove, and destroy all the %gP!" %E %Cp Ran 00065 "%d has abandoned you, %c. You are doomed." %E %Cp Ran 00066 "%rA? %lC sends a mere %r against me? Hah!" %E %Cp Ran 00067 "%lC has failed, %c. %oC will never leave here." %E %Cp Ran 00068 "You really think you can defeat me, eh %c? You are wrong!" %E %Cp Ran 00069 "You weaken, %c. I shall kill you now." %E %Cc Ran 00070 As you pick up %o, it seems to glow, and a warmth fills you completely. You realize that its power is what has protected your %sp against their enemies for so long. You must now return it to %l without delay -- their lives depend on your speed. %E [You pick up %o and feel power. It's time to return %oh to %l.] %Cc Ran 00080 %nC collapses to the ground, cursing you and %l, then says: "You have defeated me, %r! But I curse you one final time, with my dying breath! You shall die before you leave my castle!" %E [%nC curses you as %nh dies.] %Cc Ran 00081 "%pC! You have succeeded! I feared it was not possible! "You have returned with %o! "I fear, now, that the Centaurs will regroup and plot yet another raid. This will take some time, but if you can recover the Amulet of Yendor for %d before that happens, we will be eternally safe. "Take %o with you. It will aid in your quest for the Amulet." %E [You have succeeded. Take %o with you as you go to find the Amulet.] # assumes The Longbow of Diana %Cc Ran 00082 %l flexs %o reverently. "With this wondrous bow, one need never run out of arrows. You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E [You are the keeper of %o now. Go and find the Amulet.] %Cp Ran 00090 "Welcome, %p. How have you fared on your quest for the Amulet of Yendor?" %E %Cc Ran 00091 "You have it! You have recovered the Amulet of Yendor! Now attend to me, %p, and I will tell you what must be done: "The Amulet has within it magic, the capability to transport you to the Astral Plane, where the primary circle of %d resides. "To activate this magic, you must travel upwards as far as you can. When you reach the temple, sacrifice the Amulet to %d. "Thus will you fulfill your destiny." %E [You have the Amulet! Take it to the Astral Plane and offer it to %d.] # # Rogue (with apologies to all Norsk speakers -dean) # %Cc Rog 00001 Unexpectedly, you find yourself back in Ransmannsby, where you trained to be a thief. Quickly you make the guild sign, hoping that you AND word of your arrival reach %ls den. %E [You are in Ransmannsby, where you trained. Find %l.] %Cp Rog 00002 Once again, you find yourself back in Ransmannsby. Fond memories are replaced by fear, knowing that %l is waiting for you. %E %Cp Rog 00003 You rub your hands through your hair, hoping that the little ones on the back of your neck stay down, and prepare yourself for your meeting with %l. %E %Cp Rog 00005 "I hear that Lady Tyvefelle's household is lightly guarded." %E %Cp Rog 00006 "You're back? Even the Twain don't come back anymore." %E %Cp Rog 00007 "Can you spare an old cutpurse a zorkmid for some grog?" %E %Cp Rog 00008 "Fritz tried to join the other side, and now he's hell-hound chow." %E %Cp Rog 00009 "Be careful what you steal, I hear the boss has perfected turning rocks into worthless pieces of glass." %E %Cp Rog 00010 "I was sure wrong about Lady Tyvefelle's house; I barely got away with my life and lost my lock pick in the process." %E %Cp Rog 00011 "You're back? Even the Twain don't come back anymore." %E %Cp Rog 00012 "Can you spare an old cutpurse a zorkmid for some grog?" %E %Cp Rog 00013 "Fritz tried to join the other side, and now he's hell-hound chow." %E %Cp Rog 00014 "Be careful what you steal, I hear the boss has perfected turning rocks into worthless pieces of glass." %E %Cc Rog 00015 "Well, look who it is boys -- %p has come home. You seem to have fallen behind in your dues. I should kill you as an example to these other worthless cutpurses, but I have a better plan. If you are ready maybe you could work off your back dues by performing a little job for me. Let us just see if you are ready..." %E [You owe back dues to your guild. You can pay them off if you're up to the job.] %Cc Rog 00016 "Well, I didn't expect to see you back. It shows that you are either stupid, or you are finally ready to accept my offer. Let us hope for your sake it isn't stupidity that brings you back." %E [Are you stupid or are you ready?] %Cp Rog 00017 "Did you perhaps mistake me for some other %lt? You must think me as stupid as your behavior. I warn you not to try my patience." %E %Cc Rog 00018 "Well %gp, it looks like our friend has forgotten who is the boss around here. Our friend seems to think that %rp have been put in charge. Wrong. DEAD WRONG!" Your sudden shift in surroundings prevents you from hearing the end of %ls curse. %E [You must go.] %Cc Rog 00019 "In the time that you've been gone you've only been able to master the arts of %ra? I've trained ten times again as many %Rp in that time. Maybe I should send one of them, no? Where would that leave you, %p? Oh yeah, I remember, I was going to kill you!" %E [%rA is not adequately trained to handle this job.] %Cc Rog 00020 "Maybe I should chain you to my perch here for a while. Perhaps watching real %a men at work will bring some sense back to you. I don't think I could stand the sight of you for that long though. Come back when you can be trusted to act properly." %E [Come back when you are really %a.] %Cc Rog 00021 "Will everyone not going to retrieve %o from that jerk, %n, take one step backwards. Good choice, %p, because I was going to send you anyway. My other %gp are too valuable to me. "Here's the deal. I want %o, %n has %o. You are going to get %o and bring it back to me. So simple an assignment even you can understand it." %E [Get %o from %n and bring it to %l.] %Cp Rog 00025 "You don't seem to understand, %o isn't here so neither should you be!" %E %Cp Rog 00026 "May %d curse you with lead fingers. Get going!" %E %Cp Rog 00027 "We don't have all year. GET GOING!" %E %Cp Rog 00028 "How would you like a scar necklace? I'm just the jeweler to do it!" %E %Cp Rog 00029 "Lazy S.O.B. Maybe I should call up someone else..." %E %Cp Rog 00030 "Maybe I should open your skull and see if my instructions are inside?" %E %Cp Rog 00031 "This is not a task you can complete in the afterlife, you know." %E %Cp Rog 00032 "Inside every living person is a dead person trying to get out, and I have your key!" %E %Cp Rog 00033 "We're almost out of hell-hound chow, so why don't you just get moving!" %E %Cp Rog 00034 "You know, %o isn't going to come when you whistle. You must get it yourself." %E %Cp Rog 00035 Those damn little hairs tell you that you are nearer to %o. %E %Cp Rog 00036 Not wanting to face %l without having stolen %o, you continue. %E %Cc Rog 00040 You feel a great swelling up of courage, sensing the presence of %o. Or is it fear? %E [You sense %o.] %Cp Rog 00041 The hairs on the back of your neck whisper -- it's fear. %E %Cp Rog 00050 "Ah! You must be %ls ... er, `hero'. A pleasure to meet you." %E %Cp Rog 00051 "We meet again. Please reconsider your actions." %E %Cc Rog 00052 "Surely, %p, you have learned that you cannot trust any bargains that %l has made. I can show you how to continue on your quest without having to run into him again." %E [You cannot trust %l.] %Cc Rog 00053 "Please, think for a moment about what you are doing. Do you truly believe that %d would want %l to have %o?" %E [%lC should not have %o.] %Cp Rog 00060 "May I suggest a compromise. Are you interested in gold or gems?" %E %Cp Rog 00061 "Please don't force me to kill you." %E %Cp Rog 00062 "Grim times are upon us all. Will you not see reason?" %E %Cp Rog 00063 "I knew %l, and you're no %lt, thankfully." %E %Cp Rog 00064 "It is a shame that we are not meeting under more pleasant circumstances." %E %Cp Rog 00065 "I was once like you are now, %p. Believe in me -- our way is better." %E %Cp Rog 00066 "Stay with me, and I will make you %os guardian." %E %Cp Rog 00067 "When you return, with or without %o, %l will have you killed." %E %Cp Rog 00068 "Do not be fooled; I am prepared to kill to defend %o." %E %Cp Rog 00069 "I can reunite you with the Twain. Oh, the stories you can swap." %E %Cc Rog 00070 As you pick up %o, the hairs on the back of your neck fall out. At once you realize why %n was willing to die to keep it out of %ls hands. Somehow you know that you must do likewise. %E [You pick up %o and know that %l should not have it.] %Cc Rog 00080 "I know what you are thinking, %p. It is not too late for you to use %o wisely. For the sake of your guild %sp, do what is right." You sit and wait for death to come for %n, and then you brace yourself for your next meeting with %l! %E [Before dying, %n tells you to use the %o wisely.] %Cc Rog 00081 "Well, I'll be damned. You got it. I am proud of you, a fine %r you've turned out to be. "While you were gone I got to thinking, you and %o together could bring me more treasure than either of you apart, so why don't you take it with you. All I ask is a cut of whatever loot you come by. That is a better deal than I offered %n. "But, you see what happened to %n when he refused. Don't make me find another to send after you this time." %E [Take %o with you and go.] # assumes Master Key of Thievery (small object) %Cc Rog 00082 %lC seems tempted to swap %o for the mundane one you detect in his pocket, but noticing your alertness, evidently chickens out. "Go filch the Amulet before someone else beats you to it. %Z are back the way you came, through the magic portal." %E [Take %o and acquire the Amulet.] %Cc Rog 00090 "Quite the little thief, aren't we, %p. Can I interest you in a swap for %o? Look around, anything in the keep is yours for the asking." %E [How about trading %o for something?] %Cc Rog 00091 "I see that with your abilities, and my brains, we could rule this world. "All that we would need to be all-powerful is for you to take that little trinket you've got there up to the Astral Plane. From there, %d will show you what to do with it. Once that's done, we will be invincible!" %E [Take the Amulet to the Astral Plane and find %ds temple.] # # Samurai # %Cc Sam 00001 Even before your senses adjust, you recognize the kami of %H. You %x the standard of your teki, %n, flying above the town. How could such a thing have happened? Why are ninja wandering freely; where are the samurai of your daimyo, %l? You quickly say a prayer to Izanagi and Izanami and walk towards town. %E [The banner of %n flies above town. What has happened to %l?] %Cp Sam 00002 Once again, you are back at %H. %E %Cc Sam 00003 You are back at %H. Instantly you sense a subtle change in your karma. You seem to know that if you do not succeed in your quest, %n will have destroyed the kami of %H before you return again. %E [%HC is threatened by %n.] %Cp Sam 00005 "To succeed, you must walk like a butterfly on the wind." %E %Cp Sam 00006 "Ikaga desu ka?" %E %Cp Sam 00007 "I fear for The Land of The Gods." %E %Cp Sam 00008 "%nC has hired the Ninja -- be careful." %E %Cp Sam 00009 "If %o is not returned, we will all be ronin." %E %Cp Sam 00010 "Come, join us in celebrating with some sake." %E %Cp Sam 00011 "Ikaga desu ka?" %E %Cp Sam 00012 "You have brought our clan and %l much honor." %E %Cp Sam 00013 "Please %r, sit for a while and tell us how you overcame the Ninja." %E %Cp Sam 00014 "%lC still lives! You have saved us from becoming ronin." %E %Cc Sam 00015 "Ah, %p-san, it is good to see you again. I need someone who can lead my samurai against %n. If you are ready, you will be that person." %E [%lC needs someone to lead %lj samurai against %n. Are you ready?] %Cp Sam 00016 "Once again, %p-san, you kneel before me. Are you yet capable of being my vassal?" %E # [Sam 00017: This summary is definitely a poor one.] %Cc Sam 00017 "You begin to test my matsu, %p-san. If you cannot determine what I want in a samurai, how can I rely on you to figure out what I need from a samurai?" %E [Are you truely a samurai?] %Cc Sam 00018 "You are no longer my samurai, %p. "Hara-kiri is denied. You are ordered to shave your head and then to become a monk. Your fief and family are forfeit. Wakarimasu ka?" %E [Leave and do not come back.] %Cc Sam 00019 "%p-san, you have learned well and honored your family. I require the skills of %Ra in order to defeat %n. Go and seek out teachers. Learn what they have learned. When you are ready, return to me." %E ["I require %Ra to defeat %n. Return when you are ready."] %Cc Sam 00020 "%p-san, you would do better to join the kyokaku. "You have skills, but until you can call upon the bushido to know when and how to use them you are not samurai. When you can think %a and act %a then return." %E [When you can think %a and act %a then return.] %Cc Sam 00021 "Domo %p-san, indeed you are ready. I can now tell you what it is that I require of you. "The daimyo, %n, has betrayed us. He has stolen from us %o and taken it to his donjon deep within %i. "If I cannot show the emperor %o when he comes for the festival he will know that I have failed in my duty, and request that I commit seppuku. "You must gain entrance to %i and retrieve the emperor's property. Be quick! The emperor will be here for the cha-no-you in 5 sticks. "Wakarimasu ka?" %E [You must enter %i, then regain %o from %n.] %Cp Sam 00025 "To defeat %n you must overcome the seven emotions: hate, adoration, joy, anxiety, anger, grief, and fear." %E %Cp Sam 00026 "Remember your honor is my honor, you perform in my name." %E %Cp Sam 00027 "I will go to the temple and burn incense for your safe return." %E %Cp Sam 00028 "Sayonara." %E %Cp Sam 00029 "There can be honor in defeat, but no gain." %E %Cp Sam 00030 "Your kami must be strong in order to succeed." %E %Cp Sam 00031 "You are indeed a worthy %R, but now you must be a worthy samurai." %E %Cp Sam 00032 "If you fail, %n will be like a tai-fun on the land." %E %Cp Sam 00033 "If you are truly %a, %d will listen." %E %Cp Sam 00034 "Sharpen your swords and your wits for the task before you." %E %Cp Sam 00035 You instinctively reach for your swords. You do not recognize the lay of this land, but you know that your teki are everywhere. %E %Cp Sam 00036 Thankful that your %sp at %H cannot see your fear, you prepare again to advance. %E %Cc Sam 00040 In your mind, you hear the taunts of %n. You become like the rice plant and bend to the ground, offering a prayer to %d. But when the wind has passed, you stand proudly again. Putting your kami in the hands of fate, you advance. %E [You feel the taunts %n, but after offering a prayer to %d, you proceed.] %Cp Sam 00041 As you arrive once again at the home of %n, your thoughts turn only to %o. %E %Cp Sam 00050 "Ah, so it is to be you, %p-san. I offer you seppuku. I will be your second if you wish." %E %Cp Sam 00051 "I have offered you the honorable exit. Now I will have your head to send unwashed to %l." %E %Cp Sam 00052 "After I have dispatched you, I will curse your kami." %E %Cp Sam 00053 "You have fought my samurai; surely you must know that you will not be able to take %o back to %H." %E %Cp Sam 00060 "Ahh, I finally meet the daimyo of the kyokaku!" %E %Cp Sam 00061 "There is no honor for me in your death." %E %Cp Sam 00062 "You know that I cannot resash my swords until they have killed." %E %Cp Sam 00063 "Your presence only compounds the dishonor of %l in not coming %liself." %E %Cp Sam 00064 "I will make tea with your hair and serve it to %l." %E %Cp Sam 00065 "Your fear shows in your eyes, coward!" %E %Cp Sam 00066 "I have not heard of you, %p-san; has your life been that unworthy?" %E %Cp Sam 00067 "If you will not obey me, you will die." %E %Cp Sam 00068 "Kneel now and make the two cuts of honor. I will tell your %sp of your honorable death." %E %Cp Sam 00069 "Your master was a poor teacher. You will pay for his mistakes in your teaching." %E %Cc Sam 00070 As you pick up %o, you feel the strength of its karma. You realize at once why so many good samurai had to die to defend it. You are humbled knowing that you hold one of the artifacts of the sun goddess. %E [You feel the power of %o and are humbled.] %Cc Sam 00080 Your healing skills tell you that %ns wounds are mortal. You know that the bushido tells you to finish him and let his kami die with honor, but the thought of so many samurai dead due to this man's dishonor prevents you from giving the final blow. You order that his unwashed head be given to the crows and his body thrown into the sea. %E [%nC dies without honor.] %Cc Sam 00081 As you bow before %l, he welcomes you: "You have brought your family great honor, %p-sama. "While you have been gone the emperor's advisors have discovered in the ancient texts that the karma of the samurai who seeks to recover the Amulet and the karma of %o are joined as the seasons join to make a year. "Because you have shown such fidelity, the emperor requests that you take leave of other obligations and continue on the road that fate has set your feet upon. I would consider it an honor if you would allow me to watch your household until you return with the Amulet." With that, %l bows, and places his sword atop %o. %E [The emperor wants you to take %o and recover the Amulet.] %Cc Sam 00082 %l holds %o tightly for a moment, then returns his gaze to you. "The time is ripe to recover the Amulet. Return to %Z through the magic portal that transported you here so that you may achieve the destiny which awaits you." %E [Take %o, return to %Z, and recover the Amulet.] %Cp Sam 00090 %lC bows. "%p-sama, tell us of your search for the Amulet." %E # [Sam 00091: most other roles give more explicit directions for the # feedback here, so this summary does that too.] %Cc Sam 00091 "Ah, %p-sama. You have wasted your efforts returning home. Now that you are in possession of the Amulet, you are honor-bound to finish the quest you have undertaken. There will be plenty of time for saki and stories when you have finished. "Go now, and may our prayers be a wind at your back." %E [Take the Amulet to the Astral Plane to finish your task.] # # Tourist # %Cc Tou 00001 You breathe a sigh of relief as you find yourself back in the familiar surroundings of %H. You quickly notice that things do not appear the way they did when you left. The town is dark and quiet. There are no sounds coming from behind the town walls, and no campfires burning in the fields. As a matter of fact, you do not %x any movement in the fields at all, and the crops seem as though they have been untended for many weeks. %E [You find yourself back at %H, but the quiet is ominous.] %Cp Tou 00002 Once again, you are back at %H. %E %Cp Tou 00003 You are back at %H. Things appear to have become so bad that you fear that soon %H will not be here to return to. %E %Cp Tou 00005 "Gehennom on 5 zorkmids a day -- more like 500 a day if you ask me." %E %Cp Tou 00006 "Do you know where I could find some nice postcards of The Gnomish Mines?" %E %Cp Tou 00007 "Have you tried the weird toilets?" %E %Cp Tou 00008 "Don't stay at the Inn, I hear the food is terrible and it has rats." %E %Cp Tou 00009 "They told me that this was the off season!" %E %Cp Tou 00010 "Gehennom on 5 zorkmids a day -- more like 500 a day if you ask me." %E %Cp Tou 00011 "Do you know where I could find some nice postcards of The Gnomish Mines?" %E %Cp Tou 00012 "Have you tried the weird toilets?" %E %Cp Tou 00013 "If you stick around, I'll show you the pictures from my latest trip." %E %Cp Tou 00014 "Did you bring me back any souvenirs?" %E %Cc Tou 00015 "Is it really you, %p! I had given up hope for your return. As you can %x, we are desperately in need of your talents. Someone must defeat %n if our town is to become what it once was. "Let me see if you are ready to be that someone." %E [Someone must defeat %n. Are your ready?] %Cp Tou 00016 "Things are getting worse, %p. I hope that this time you are ready." %E %Cp Tou 00017 "I hope that for the sake of %H you have prepared yourself this time." %E %Cc Tou 00018 "It is too late, %p. You are not even worthy to die amongst us. Leave %H and never return." %E [Leave %H and never return.] %Cc Tou 00019 "There is still too much that you have to learn before you can undertake the next step. Return to us as a proven %R, and perhaps then you will be ready. "Go back now, and may the teachings of %d serve you well." %E [Return when you are %Ra.] %Cc Tou 00020 "It would be an affront to %d to have one not true to the %a path undertake her bidding. "You must not return to us until you have purified yourself of these bad influences on your actions. Remember, only by following the %a path can you hope to overcome the obstacles you will face." %E [You are not sufficiently %a. Return when you are.] %Cc Tou 00021 "You have indeed proven yourself a worthy %c, %p. "But now your kinfolk and I must ask you to put aside your travels and help us in our time of need. After you left us we elected a new mayor, %n. He proved to be a most heinous and vile creature. "Soon after taking office he absconded with %o and fled town, leaving behind his henchmen to rule over us. In order for us to regain control of our town, you must enter %i and recover %o. "Do not be distracted on your quest. If you do not return quickly I fear that all will be lost. Let us both pray now that %d will guide you and keep you safe." %E [Enter %i and recover %o from %n.] %Cp Tou 00025 "Do not be fooled by the false promises of %n." %E %Cp Tou 00026 "To enter %i you must pass many traps." %E %Cp Tou 00027 "If you do not return with %o, your quest will be in vain." %E %Cp Tou 00028 "Do not be afraid to call upon %d if you truly need help." %E %Cp Tou 00029 "If you do not destroy %n, he will follow you back here!" %E %Cp Tou 00030 "Take %o from %n and you may be able to defeat him." %E %Cp Tou 00031 "You must hurry, %p!" %E %Cp Tou 00032 "You are like %Sa to me, %p. Do not let me down." %E %Cp Tou 00033 "If you are %a at all times you may succeed, %p." %E %Cp Tou 00034 "Let all who meet you on your journey know that you are on an quest for %l and grant safe passage." %E %Cc Tou 00035 Only your faith in %d keeps you from trembling. You %x the handiwork of %ns henchlings everywhere. %E [You %x the handiwork of %ns henchlings.] %Cp Tou 00036 You know that this time you must find and destroy %n. %E %Cp Tou 00040 You sense the presence of %o. %E %Cp Tou 00041 You gain confidence, knowing that you may soon be united with %o. %E %Cc Tou 00050 "So, %p, %l thinks that you can wrest %o from me! "It only proves how desperate he has become that he sends %ra to try and defeat me. When this day is over, I will have you enslaved in the mines where you will rue the day that you ever entered %i." %E [%rA will not defeat me.] %Cp Tou 00051 "I let you live the last time because it gave me pleasure. This time I will destroy you, %p." %E %Cc Tou 00052 "These meetings come to bore me. You disturb my workings with %o. "If you do not run away now, I will inflict so much suffering on you that %l will feel guilty for ever having sent his %S to me!" %E [Run away or you will suffer severely.] %Cc Tou 00053 "You fool. You do not know how to call upon the powers of %o. "Return it to me and I will teach you how to use it, and together we will rule %H. But do so now, as my patience grows thin." %E ["Return %o to me and we will rule %H."] %Cp Tou 00060 "I defeated %l and I will defeat you, %p." %E %Cp Tou 00061 "Where is %d now! You must realize no one can help you here." %E %Cp Tou 00062 "Beg for mercy now and I may be lenient on you." %E %Cp Tou 00063 "If you were not so %a, you might have stood a chance." %E %Cp Tou 00064 "Vengeance is mine at last, %p." %E %Cp Tou 00065 "I only wish that %l had a more worthy %r to send against me." %E %Cp Tou 00066 "With %o in my possession you cannot hope to defeat me." %E %Cp Tou 00067 "%nC has never been defeated, NEVER!" %E %Cp Tou 00068 "Are you truly the best %H has to send against me? I pity %l." %E %Cp Tou 00069 "How do you spell %p? I want to ensure the marker on your grave is correct as a warning to your %sp." %E %Cc Tou 00070 As you pick up %o, you feel a great weight has been lifted from your shoulders. Your only thoughts are to quickly return to %H and find %l. %E [You pick up %o and feel relief. Return it to %l.] %Cc Tou 00080 You turn in the direction of %n. As his earthly body begins to vanish before your eyes, you hear him curse: "You shall never be rid of me, %p! I will find you where ever you go and regain what is rightly mine." %E [%nC curses at you as %nh dies.] %Cc Tou 00081 As %l detects the presence of %o, he almost smiles for the first time in many a full moon. As he looks up from %o he says: "You have recovered %o. You are its owner now, but not its master. Let it work with you as you continue your journey. With its help, and %d to guide you on the %a path, you may yet recover the Amulet of Yendor." %E [Take %o and with %ds guidance, recover the Amulet.] %Cc Tou 00082 "%oC is yours now. %Z await your return through the magic portal that brought you here." %E [Keep %o and return to %Z through the portal.] %Cp Tou 00090 "I could not be more proud than if you were my own %S, %p! Tell me of your adventures in quest of the Amulet of Yendor." %E # [Tou 00091: like Sam 00091, the directions about what to do next are # missing, so make the summary be a little bit more explicit.] %Cc Tou 00091 "Stand back and let me look at you, %p. Now that you have recovered the Amulet of Yendor, I'm afraid living out your days in %H would seem pretty tame. "You have come too far to stop now, for there are still more tasks that our oral history foretells for you. Forever more, though, your name shall be spoken by the %gP with awe. You are truly an inspiration to your %sp!" %E [You have the Amulet. Take it to the Astral Plane to finish your task.] # # Valkyrie # %Cc Val 00001 You materialize at the base of a snowy hill. Atop the hill sits a place you know well, %H. You immediately realize that something here is very wrong! In places, the snow and ice have been melted into steaming pools of water. Fumaroles and pools of bubbling lava surround the hill. The stench of sulphur is carried through the air, and you %x creatures that should not be able to live in this environment moving towards you. %E [You arrive below %H. Something is wrong; there is lava present.] %Cp Val 00002 Once again, you are near the abode of %l. %E %Cp Val 00003 Again you materialize near %ls abode. You have a nagging feeling that this may be the last time you come here. %E %Cp Val 00005 "Hail, and well met, brave %c." %E %Cp Val 00006 "May %d guide your steps, %p." %E %Cp Val 00007 "%lC weakens. Without %o, her foresight is dim." %E %Cp Val 00008 "You must hurry, %p, else Ragnarok may well come." %E %Cp Val 00009 "I would deal with this foul %n myself, but %d forbids it." %E %Cp Val 00010 "Hail, and well met, brave %c." %E %Cp Val 00011 "May %d guide your steps, %p." %E %Cp Val 00012 "%lC told us you had succeeded!" %E %Cp Val 00013 "You recovered %o just in time, %p." %E %Cp Val 00014 "Hail %d, for delivering %o back to us." %E %Cc Val 00015 "Ah, %p, my %S. You have returned to %H at last. We are in dire need of your aid, but I must determine if you are yet ready for such an undertaking. "Let me read your fate..." %E [We need your aid. Are you ready?] %Cp Val 00016 "Let me read the future for you now, %p, perhaps you have managed to change it enough..." %E %Cp Val 00017 "Again, I shall read your fate, my %S. Let us both hope that you have made changes to become ready for this task..." %E %Cc Val 00018 "No, %p. Your fate is sealed. I must cast about for another champion. Begone from my presence, and never return. Know this, that you shall never succeed in this life, and Valhalla is denied to you." %E ["Begone from my presence and never return."] %Cc Val 00019 "I see you and %n fighting, %p. But you are not prepared and shall die at %ns hand if you proceed. No. This will not do. Go back out into the world, and grow more experienced at the ways of war. Only when you have returned %Ra will you be able to defeat %n." %E [Come back when you are %Ra.] %Cc Val 00020 "NO! This is terrible. I see you becoming an ally of %n, and leading his armies in the final great battles. This must not come to pass! You have strayed from the %a path. You must purge yourself, and return here only when you have regained a state of purity." %E [You have strayed from the %a path. Return after you purify yourself.] %Cc Val 00021 "It is not clear, %p, for my sight is limited without our relic. But it is now likely that you can defeat %n, and recover %o. "A short time ago, %n and his minions attacked this place. They opened the huge volcanic vents you %x about the hill, and attacked. I knew that this was to come to pass, and had asked %d for a group of %gP to help defend this place. The few you %x here are the mightiest of Valhalla's own, and are all that are left of one hundred %d sent. "Despite the great and glorious battle we fought, %n managed at last to steal %o. This has upset the balance of the universe, and unless %oh is returned into my care, %n may start Ragnarok. "You must find the entrance to %i. Travel downward from there and you will find %ns lair. Defeat him and return %o to me." %E [Find %i; defeat %n; return with %o.] %Cp Val 00025 "Go with the blessings of %d." %E %Cp Val 00026 "Call upon %d when you are in need." %E %Cp Val 00027 "Use %o if you can. It will protect you." %E %Cp Val 00028 "Magical cold is very effective against %n." %E %Cp Val 00029 "To face %n, you will need to be immune to fire." %E %Cp Val 00030 "May %d strengthen your sword-arm." %E %Cp Val 00031 "Trust in %d. He will not desert you." %E %Cp Val 00032 "It becomes more likely that Ragnarok will come with every passing moment. You must hurry, %p." %E %Cp Val 00033 "If %n can master %o, he will be powerful enough to face %d far earlier than is fated. This must not be!" %E %Cp Val 00034 "Remember your training, %p. You can succeed." %E %Cc Val 00035 The ice and snow gives way to a valley floor. You %x ahead of you a huge round hill surrounded by pools of lava. This then is the entrance to %i. It looks like you're not going to get in without a fight though. %E [This is the entrace to %i.] %Cp Val 00036 Once again, you stand before the entrance to %i. %E %Cc Val 00040 Through clouds of sulphurous gasses, you %x a rock palisade surrounded with a moat of bubbling lava. You remember the description from something that %l said. This is the lair of %n. %E [This is the lair of %n.] %Cp Val 00041 Once again, you stand in sight of %ns lair. %E %Cc Val 00050 "So! %lC has finally sent %ca to challenge me! "I thought that mastering %o would enable me to challenge %d, but it has shown me that first I must kill you! So come, little %s. Once I defeat you, I can at last begin the final battle with %d." %E ["%oC has shown me that I must kill you."] %Cp Val 00051 "Again you challenge me, %r. Good. I will kill you now." %E %Cp Val 00052 "Have you not learned yet? You cannot defeat %n!" %E %Cp Val 00053 "I will kill you, %c, and wrest %o from your mangled hands." %E %Cp Val 00060 "I am your death, %c." %E %Cp Val 00061 "You cannot prevail, %r. I have foreseen your every move." %E %Cp Val 00062 "With you out of the way, Valhalla will be mine for the taking." %E %Cp Val 00063 "I killed scores of %ds best when I took %o. Do you really think that one %c can stand against me?" %E %Cp Val 00064 "Who bears the souls of %cP to Valhalla, %r?" %E %Cp Val 00065 "No, %d cannot help you here." %E %Cp Val 00066 "Some instrument of %d you are, %p. You are a weakling!" %E %Cp Val 00067 "Never have I seen %ca so clumsy in battle." %E %Cp Val 00068 "You die now, little %s." %E %Cp Val 00069 "Your body I destroy now, your soul when my hordes overrun Valhalla!" %E %Cc Val 00070 As you pick up %o, your mind is suddenly filled with images, and you perceive all of the possibilities of each potential choice you could make. As you begin to control and channel your thoughts, you realize that you must return %o to %l immediately. %E [You must return %o to %l.] %Cc Val 00080 A look of surprise and horror appears on %ns face. "No!!! %o has lied to me! I have been misled!" Suddenly, %n grasps his head and screams in agony, then dies. %E [%nC dies.] %Cc Val 00081 As you approach, %l rises and touches %o. "You may take %o with you, %p. I have removed from it the power to foretell the future, for that power no mortal should have. Its other abilities, however, you have at your disposal. "You must now begin in %ds name to search for the Amulet of Yendor. May your steps be guided by %d, my %S." %E [Take %o. Search for the Amulet.] # assumes Orb of Fate (glass object) %Cc Val 00082 "Careful, %p! %oC might break, and that would be a tragic loss. You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E [You are %os keeper now. Return through the portal and find the Amulet.] %Cp Val 00090 "Greetings, %p. I have not been able to pay as much attention to your search for the Amulet as I have wished. How do you fare?" %E %Cc Val 00091 "Excellent, %p. I see you have recovered the Amulet! "You must take the Amulet to the Great Temple of %d, on the Astral Plane. There you must offer the Amulet to %d. "Go now, my %S. I cannot tell you your fate, as the power of the Amulet interferes with mine. I hope for your success." %E [Take the Amulet to %ds temple on the Astral Plane and offer it.] # # Wizard # %Cc Wiz 00001 You are suddenly in familiar surroundings. You notice what appears to be a large, squat stone structure nearby. Wait! That looks like the tower of your former teacher, %l. However, things are not the same as when you were last here. Mists and areas of unexplained darkness surround the tower. There is movement in the shadows. Your teacher would never allow such unaesthetic forms to surround the tower... unless something were dreadfully wrong! %E [You have arrived at %ls tower but something is very wrong.] %Cp Wiz 00002 Once again, you are back at %H. %E %Cp Wiz 00003 You are back at %H. You have an odd feeling this may be the last time you ever come here. %E %Cp Wiz 00005 "Would you happen to have some eye of newt in that overstuffed pack, %s?" %E %Cp Wiz 00006 "Ah, the spell to create the magic portal worked. Outstanding!" %E %Cp Wiz 00007 "Hurry! %lC may not survive that casting of the portal spell!" %E %Cp Wiz 00008 "The spells of %n were just too powerful for us to withstand." %E %Cp Wiz 00009 "I, too, will venture into the world, because %n is but one of many evils to be vanquished." %E %Cp Wiz 00010 "I have some eye of newt to trade, do you have a spare blind-worm's sting?" %E %Cp Wiz 00011 "The magic portal now seems like it will remain stable for quite some time." %E %Cp Wiz 00012 "Have you noticed how much stronger %l is since %o was recovered?" %E %Cp Wiz 00013 "Thank %d! We weren't positive you would defeat %n." %E %Cp Wiz 00014 "I, too, will venture into the world, because %n was but one of many evils to be vanquished." %E %Cc Wiz 00015 "Come closer, %p, for my voice falters in my old age. Yes, I see that you have come a long way since you went out into the world, leaving the safe confines of this tower. However, I must first determine if you have all of the skills required to take on the task I require of you." %E [You have come a long way, but are you ready for the task I require?] %Cp Wiz 00016 "Well, %p, you have returned. Perhaps you are now ready..." %E %Cp Wiz 00017 "This is getting tedious, %p, but perseverance is a sign of a true mage. I certainly hope that you are truly ready this time!" %E %Cc Wiz 00018 "You fool, %p! Why did I waste all of those years teaching you the esoteric arts? Get out of here! I shall find another." %E ["Get out of here!"] %Cc Wiz 00019 "Alas, %p, you have not yet shown your proficiency as a worthy spellcaster. As %ra, you would surely be overcome in the challenge ahead. Go, now, expand your horizons, and return when you have attained renown as %Ra." %E [Go; return when you are %Ra.] %Cc Wiz 00020 "You amaze me, %p! How many times did I tell you that the way of a mage is an exacting one. One must use the world with care, lest one leave it in ruins and simplify the task of %n. "You must go back and show your worthiness. Do not return until you are truly ready for this quest. May %d guide you in this task." %E [Go; come back when you are worthy of %d.] %Cc Wiz 00021 "Yes, %p, you truly are ready for this dire task. Listen, carefully, for what I tell you now will be of vital importance. "Since you left us to hone your skills in the world, we unexpectedly came under attack by the forces of %n. As you know, we thought %n had perished at the end of the last age, but, alas, this was not the case. "%nC sent an army of abominations against us. Among them was a minion, mindless and ensorcelled, and thus, in the confusion, it was able to penetrate our defenses. Alas, this creature has stolen %o and I fear has delivered %oh to %n. "Over the years, I had woven most of my power into this amulet, and thus, without it, I have but a shadow of my former power, and I fear that I shall soon perish. "You must travel to %i, and within its dungeons, find and overcome %n, and return %o to me. "Go now, with %d, and complete this quest before it is too late." %E [Travel to %i; overcome %n; return with %o.] %Cp Wiz 00025 "Beware, for %n is immune to most magical attacks." %E %Cp Wiz 00026 "To enter %i you must pass many traps." %E %Cp Wiz 00027 "%nC may be vulnerable to physical attacks." %E %Cp Wiz 00028 "%d will come to your aid when you call." %E %Cp Wiz 00029 "You must utterly destroy %n. He will pursue you otherwise." %E %Cp Wiz 00030 "%oC is a mighty artifact. With it you can destroy %n." %E %Cp Wiz 00031 "Go forth with the blessings of %d." %E %Cp Wiz 00032 "I will have my %gP watch for your return." %E %Cp Wiz 00033 "Feel free to take any items in that chest that might aid you." %E %Cp Wiz 00034 "You will know when %o is near. Proceed with care!" %E %Cp Wiz 00035 Wisps of fog swirl nearby. You feel that %ns lair is close. %E %Cp Wiz 00036 You believe that you may once again invade %i. %E %Cp Wiz 00040 You feel your mentor's presence; perhaps %o is nearby. %E %Cp Wiz 00041 The aura of %o tingles at the edge of your perception. %E %Cc Wiz 00050 "Ah, I recognize you, %p. So, %l has sent you to steal %o from me, hmmm? Well, %lh is a fool to send such a mental weakling against me. "Your destruction, however, should make for good sport. In the end, you shall beg me to kill you!" %E ["Your destruction should make for good sport."] %Cc Wiz 00051 "How nice of you to return, %p! I enjoyed our last meeting. Are you still hungry for more pain? "Come! Your soul, like %o, shall soon be mine to command." %E ["Your soul shall soon be mine to command."] %Cp Wiz 00052 "I'm sure that your perseverance shall be the subject of innumerable ballads, but you shall not be around to hear them, I fear!" %E %Cp Wiz 00053 "Thief! %oC belongs to me, now. I shall feed your living flesh to my minions." %E %Cp Wiz 00060 "Your puny powers are no match for me, fool!" %E %Cp Wiz 00061 "When you are defeated, your torment will last for a thousand years." %E %Cp Wiz 00062 "After your downfall, %p, I shall devour %l for dessert!" %E %Cp Wiz 00063 "Are you ready yet to beg for mercy? I could be lenient..." %E %Cp Wiz 00064 "Your soul shall join the enslaved multitude I command!" %E %Cp Wiz 00065 "Your lack of will is evident, and you shall die as a result." %E %Cp Wiz 00066 "Your faith in %d is for naught! Come, submit to me now!" %E %Cp Wiz 00067 "A mere %r is nothing compared to my skill!" %E %Cp Wiz 00068 "So, you are the best hope of %l? How droll." %E %Cp Wiz 00069 "Feel my power, %c! My victory is imminent!" %E %Cc Wiz 00070 As you touch %o, its comforting power infuses you with new energy. You feel as if you can detect others' thoughts flowing through it. Although you yearn to wear %o and attack the Wizard of Yendor, you know you must return it to its rightful owner, %l. %E [You feel %os power and know you should return %oh to %l.] %Cc Wiz 00080 %nC, whose body begins to shrivel up, croaks out: "I shall haunt your progress until the end of time. A thousand curses on you and %l." Then, the body bursts into a cloud of choking dust, and blows away. %E [%nC curses you as %nh dies.] %Cc Wiz 00081 %lC notices %o in your possession, beams at you and says: "I knew you could defeat %n and retrieve %o. We shall never forget this brave service. "Take %oh with you in your quest for the Amulet of Yendor. I can sense that it has attuned %oiself to you already. "May %d guide you in your quest, and keep you from harm." %E [Take %o with you in your quest for the Amulet.] %Cc Wiz 00082 "You are the keeper of %o now. It is time to recover the /other/ Amulet. %Z await your return through the magic portal which brought you here." %E [Keep %o, return through the portal to %Z; find the other Amulet.] %Cp Wiz 00090 "Come near, my %S, and share your adventures with me. So, have you succeeded in your quest for the Amulet of Yendor?" %E %Cc Wiz 00091 "Congratulations, %p. I always knew that if anyone could succeed in defeating the Wizard of Yendor and his minions, it would be you. "Go now, and take the Amulet to the Astral Plane. Once there, present the Amulet on the altar of %d. Along the way you shall pass through the four Elemental Planes. These planes are like nothing you have ever experienced before, so be prepared! "For this you were born, %s! I am very proud of you." %E [Take the Amulet to %ds altar on the Astral Plane.] # # General # %Cc - 00001 It is written in the Book of %d: After the Creation, the cruel god Moloch rebelled against the authority of Marduk the Creator. Moloch stole from Marduk the most powerful of all the artifacts of the gods, the Amulet of Yendor, and he hid it in the dark cavities of Gehennom, the Under World, where he now lurks, and bides his time. Your %G %d seeks to possess the Amulet, and with it to gain deserved ascendance over the other gods. You, a newly trained %r, have been heralded from birth as the instrument of %d. You are destined to recover the Amulet for your deity, or die in the attempt. Your hour of destiny has come. For the sake of us all: Go bravely with %d! %E [%dC has chosen you to recover the Amulet of Yendor for %dI.] %Cp - 00002 You receive a faint telepathic message from %l: Your help is urgently needed at %H! Look for a ...ic transporter. You couldn't quite make out that last message. %E %Cp - 00003 You again sense %l pleading for help. %E %Cp - 00004 You again sense %l demanding your attendance. %E # Completed the quest by returning with artifact, but not carrying # the Bell of Opening; quest leader lets you know that it is needed. #[ Should this be role-specific so that each leader has variant text? ] %Cp - 00005 "The silver bell which was hoarded by %n will be essential in locating the Amulet of Yendor." %E # # Angelic maledictions. # %Cp - 00010 "Repent, and thou shalt be saved!" %E %Cp - 00011 "Thou shalt pay for thine insolence!" %E %Cp - 00012 "Very soon, my child, thou shalt meet thy maker." %E %Cp - 00013 "The great %D has sent me to make you pay for your sins!" %E %Cp - 00014 "The wrath of %D is now upon you!" %E %Cp - 00015 "Thy life belongs to %D now!" %E %Cp - 00016 "Dost thou wish to receive thy final blessing?" %E %Cp - 00017 "Thou art but a godless void." %E %Cp - 00018 "Thou art not worthy to seek the Amulet." %E %Cp - 00019 "No one expects the Spanish Inquisition!" %E # # Demonic maledictions. # %Cp - 00030 "I first mistook thee for a statue, when I regarded thy head of stone." %E %Cp - 00031 "Come here often?" %E %Cp - 00032 "Doth pain excite thee? Wouldst thou prefer the whip?" %E %Cp - 00033 "Thinkest thou it shall tickle as I rip out thy lungs?" %E %Cp - 00034 "Eat slime and die!" %E %Cp - 00035 "Go ahead, fetch thy mama! I shall wait." %E %Cp - 00036 "Go play leapfrog with a herd of unicorns!" %E %Cp - 00037 "Hast thou been drinking, or art thou always so clumsy?" %E %Cp - 00038 "This time I shall let thee off with a spanking, but let it not happen again." %E %Cp - 00039 "I've met smarter (and prettier) acid blobs." %E %Cp - 00040 "Look! Thy bootlace is undone!" %E %Cp - 00041 "Mercy! Dost thou wish me to die of laughter?" %E %Cp - 00042 "Run away! Live to flee another day!" %E %Cp - 00043 "Thou hadst best fight better than thou canst dress!" %E %Cp - 00044 "Twixt thy cousin and thee, Medusa is the prettier." %E %Cp - 00045 "Methinks thou wert unnaturally stirred by yon corpse back there, eh, varlet?" %E %Cp - 00046 "Up thy nose with a rubber hose!" %E %Cp - 00047 "Verily, thy corpse could not smell worse!" %E %Cp - 00048 "Wait! I shall polymorph into a grid bug to give thee a fighting chance!" %E %Cp - 00049 "Why search for the Amulet? Thou wouldst but lose it, cretin." %E # # Banishment message (for converted hero) # %Cc - 00060 "You have betrayed all those who hold allegiance to %d, as you once did. My allegiance to %d holds fast and I cannot condone or accept what you have done. Leave this place. You shall never set foot at %H again. That which you seek is now lost forever, for without the Bell of Opening, you will never be able to enter the place where he who has the Amulet resides. Go now! You are banished from this place. %E [You are banished from %H for betraying your allegiance to %d.] # # TEST PATTERN # %Cc - 00099 %p: return(plname); %c: return(pl_character); %r: return((char *)rank_of(u.ulevel)); %R: return((char *)rank_of(MIN_QUEST_LEVEL)); %s: return((flags.female) ? "sister" : "brother" ); %S: return((flags.female) ? "daughter" : "son" ); %l: return((char *)ldrname()); %i: return(intermed()); %o: return(artiname()); %O: return(shortened(artiname())); %n: return((char *)neminame()); %g: return((char *)guardname()); %G: return((char *)align_gtitle(u.ualignbase[1])); %H: return((char *)homebase()); %a: return(Alignnam(u.ualignbase[1])); %A: return(Alignnam(u.ualign.type)); %d: return((char *)align_gname(u.ualignbase[1])); %D: return((char *)align_gname(A_LAWFUL)); %C: return("chaotic"); %N: return("neutral"); %L: return("lawful"); %x: return((Blind) ? "sense" : "see"); %Z: return("The Dungeons of Doom"); %%: return(percent_sign); a suffix: return an(root); A suffix: return An(root); C suffix: return capitalized(root); h suffix: return pronoun(he_or_she, mon_of(root)); /* for %l,%n,%d,%o */ H suffix: return capitalized(pronoun(he_or_she, mon_of(root))); i suffix: return pronoun(him_or_her, mon_of(root)); I suffix: return capitalized(pronoun(him_or_her, mon_of(root))); j suffix: return pronoun(his_or_her, mon_of(root)); J suffix: return capitalized(pronoun(his_or_her, mon_of(root))); p suffix: return makeplural(root); P suffix: return makeplural(capitalized(root)); s suffix: return s_suffix(root); S suffix: return s_suffix(capitalized(root)); t suffix: return strip_the_prefix(root); %E nethack-3.6.0/dat/rumors.fal0000664000076400007660000005407712467321052014737 0ustar paxedpaxed"So when I die, the first thing I will see in heaven is a score list?" 1st Law of Hacking: leaving is much more difficult than entering. 2nd Law of Hacking: first in, first out. 3rd Law of Hacking: the last blow counts most. 4th Law of Hacking: you will find the exit at the entrance. A chameleon imitating a mail daemon often delivers scrolls of fire. A cockatrice corpse is guaranteed to be untainted! A dead cockatrice is just a dead lizard. A dragon is just a snake that ate a scroll of fire. A fading corridor enlightens your insight. A glowing potion is too hot to drink. A good amulet may protect you against guards. A lizard corpse is a good thing to turn undead. A long worm can be defined recursively. So how should you attack it? A monstrous mind is a toy forever. A nymph will be very pleased if you call her by her real name: Lorelei. A ring of dungeon master control is a great find. A ring of extra ring finger is useless if not enchanted. A rope may form a trail in a maze. A staff may recharge if you drop it for awhile. A visit to the Zoo is very educational; you meet interesting animals. A wand of deaf is a more dangerous weapon than a wand of sheep. A wand of vibration might bring the whole cave crashing about your ears. A winner never quits. A quitter never wins. A wish? Okay, make me a fortune cookie! Afraid of mimics? Try to wear a ring of true seeing. All monsters are created evil, but some are more evil than others. Always attack a floating eye from behind! An elven cloak is always the height of fashion. Any small object that is accidentally dropped will hide under a larger object. Archeologists find more bones piles. Austin Powers says: My Mojo is back! Yeah, baby! Balrogs do not appear above level 20. Banana peels work especially well against Keystone Kops. Be careful when eating bananas. Monsters might slip on the peels. Better leave the dungeon; otherwise you might get hurt badly. Beware of the potion of nitroglycerin -- it's not for the weak of heart. Beware: there's always a chance that your wand explodes as you try to zap it! Beyond the 23rd level lies a happy retirement in a room of your own. Changing your suit without dropping your sword? You must be kidding! Close the door! You're letting the heat out! Cockatrices might turn themselves to stone faced with a mirror. Consumption of home-made food is strictly forbidden in this dungeon. Dark room? Your chance to develop your photographs! Dark rooms are not *completely* dark: just wait and let your eyes adjust... David London sez, "Hey guys, *WIELD* a lizard corpse against a cockatrice!" Death is just life's way of telling you you've been fired. Demi-gods don't need any help from the gods. Demons *HATE* Priests and Priestesses. Didn't you forget to pay? Didn't your mother tell you not to eat food off the floor? Direct a direct hit on your direct opponent, directing in the right direction. Do you want to make more money? Sure, we all do! Join the Fort Ludios guard! Does your boss know what you're doing right now? Don't bother wishing for things. You'll probably find one on the next level. Don't eat too much: you might start hiccoughing! Don't play NetHack at your work; your boss might hit you! Don't tell a soul you found a secret door, otherwise it isn't a secret anymore. Drinking potions of booze may land you in jail if you are under 21. Drop your vanity and get rid of your jewels! Pickpockets about! Eat 10 cloves of garlic and keep all humans at a two-square distance. Eels hide under mud. Use a unicorn to clear the water and make them visible. Elf has extra speed. Engrave your wishes with a wand of wishing. Eventually you will come to admire the swift elegance of a retreating nymph. Ever heard hissing outside? I *knew* you hadn't! Ever lifted a dragon corpse? Ever seen a leocrotta dancing the tengu? Ever seen your weapon glow plaid? Ever tamed a shopkeeper? Ever tried digging through a Vault Guard? Ever tried enchanting a rope? Floating eyes can't stand Hawaiian shirts. For any remedy there is a misery. Giant bats turn into giant vampires. Good day for overcoming obstacles. Try a steeplechase. Half Moon tonight. (At least it's better than no Moon at all.) Help! I'm being held prisoner in a fortune cookie factory! Housecats have nine lives, kittens only one. How long can you tread water? Hungry? There is an abundance of food on the next level. I guess you've never hit a mail daemon with the Amulet of Yendor... If you are the shopkeeper, you can take things for free. If you ask really nicely, the Wizard will give you the Amulet. If you can't learn to do it well, learn to enjoy doing it badly. If you thought the Wizard was bad, just wait till you meet the Warlord! If you turn blind, don't expect your dog to be turned into a seeing-eye dog. If you want to feel great, you must eat something real big. If you want to float, you'd better eat a floating eye. If your ghost kills a player, it increases your score. Increase mindpower: Tame your own ghost! It furthers one to see the great man. It's easy to overlook a monster in a wood. Just below any trap door there may be another one. Just keep falling! Katanas are very sharp; watch you don't cut yourself. Keep a clear mind: quaff clear potions. Kicking the terminal doesn't hurt the monsters. Killer bees keep appearing till you kill their queen. Killer bunnies can be tamed with carrots only. Latest news? Put `rec.games.roguelike.nethack' in your .newsrc! Learn how to spell. Play NetHack! Leprechauns hide their gold in a secret room. Let your fingers do the walking on the yulkjhnb keys. Let's face it: this time you're not going to win. Let's have a party, drink a lot of booze. Liquor sellers do not drink; they hate to see you twice. Lunar eclipse tonight. May as well quit now! Meeting your own ghost decreases your luck considerably! Money to invest? Take it to the local branch of the Magic Memory Vault! Monsters come from nowhere to hit you everywhere. Monsters sleep because you are boring, not because they ever get tired. Most monsters prefer minced meat. That's why they are hitting you! Most of the bugs in NetHack are on the floor. Much ado Nothing Happens. Multi-player NetHack is a myth. NetHack is addictive. Too late, you're already hooked. Never ask a shopkeeper for a price list. Never burn a tree, unless you like getting whacked with a +5 shovel. Never eat with glowing hands! Never mind the monsters hitting you: they just replace the charwomen. Never play leapfrog with a unicorn. Never step on a cursed engraving. Never swim with a camera: there's nothing to take pictures of. Never teach your pet rust monster to fetch. Never trust a random generator in magic fields. Never use a wand of death. No level contains two shops. The maze is no level. So... No part of this fortune may be reproduced, stored in a retrieval system, ... Not all rumors are as misleading as this one. Nymphs and nurses like beautiful rings. Nymphs are blondes. Are you a gentleman? Offering a unicorn a worthless piece of glass might prove to be fatal! Old hackers never die: young ones do. One has to leave shops before closing time. One homunculus a day keeps the doctor away. One level further down somebody is getting killed, right now. Only a wizard can use a magic whistle. Only adventurers of evil alignment think of killing their dog. Only chaotic evils kill sleeping monsters. Only real trappers escape traps. Only real wizards can write scrolls. Operation OVERKILL has started now. Ouch. I hate when that happens. PLEASE ignore previous rumor. Polymorph into an ettin; meet your opponents face to face to face. Praying will frighten demons. Row (3x) that boat gently down the stream, Charon (4x), death is but a dream. Running is good for your legs. Screw up your courage! You've screwed up everything else. Seepage? Leaky pipes? Rising damp? Summon the plumber! Segmentation fault (core dumped). Shopkeepers are insured by Croesus himself! Shopkeepers sometimes die from old age. Some mazes (especially small ones) have no solutions, says man 6 maze. Some questions the Sphynx asks just *don't* have any answers. Sometimes "mu" is the answer. Sorry, no fortune this time. Better luck next cookie! Spare your scrolls of make-edible until it's really necessary! Stormbringer doesn't steal souls. People steal souls. Suddenly, the dungeon will collapse... Taming a mail daemon may cause a system security violation. The crowd was so tough, the Stooges won't play the Dungeon anymore, nyuk nyuk. The leprechauns hide their treasure in a small hidden room. The longer the wand the better. The magic word is "XYZZY". The meek shall inherit your bones files. The mines are dark and deep, and I have levels to go before I sleep. The use of dynamite is dangerous. There are no worms in the UNIX version. There is a trap on this level! They say that Demogorgon, Asmodeus, Orcus, Yeenoghu & Juiblex is no law firm. They say that Geryon has an evil twin, beware! They say that Medusa would make a terrible pet. They say that NetHack bugs are Seldon planned. They say that NetHack comes in 256 flavors. They say that NetHack is just a computer game. They say that NetHack is more than just a computer game. They say that NetHack is never what it used to be. They say that a baby dragon is too small to hurt or help you. They say that a black pudding is simply a brown pudding gone bad. They say that a black sheep has 3 bags full of wool. They say that a blank scroll is like a blank check. They say that a cat named Morris has nine lives. They say that a desperate shopper might pay any price in a shop. They say that a diamond dog is everybody's best friend. They say that a dwarf lord can carry a pick-axe because his armor is light. They say that a floating eye can defeat Medusa. They say that a fortune only has 1 line and you can't read between it. They say that a fortune only has 1 line, but you can read between it. They say that a fountain looks nothing like a regularly erupting geyser. They say that a gold doubloon is worth more than its weight in gold. They say that a grid bug won't pay a shopkeeper for zapping you in a shop. They say that a gypsy could tell your fortune for a price. They say that a hacker named Alice once level teleported by using a mirror. They say that a hacker named David once slew a giant with a sling and a rock. They say that a hacker named Dorothy once rode a fog cloud to Oz. They say that a hacker named Mary once lost a white sheep in the mazes. They say that a helm of brilliance is not to be taken lightly. They say that a hot dog and a hell hound are the same thing. They say that a lamp named Aladdin's Lamp contains a djinni with 3 wishes. They say that a large dog named Lassie will lead you to the amulet. They say that a long sword is not a light sword. They say that a manes won't mince words with you. They say that a mind is a terrible thing to waste. They say that a plain nymph will only wear a wire ring in one ear. They say that a plumed hat could be a previously used crested helmet. They say that a potion of oil is difficult to grasp. They say that a potion of yogurt is a cancelled potion of sickness. They say that a purple worm is not a baby purple dragon. They say that a quivering blob tastes different than a gelatinous cube. They say that a runed broadsword named Stormbringer attracts vortices. They say that a scroll of summoning has other names. They say that a shaman can bestow blessings but usually doesn't. They say that a shaman will bless you for an eye of newt and wing of bat. They say that a shimmering gold shield is not a polished silver shield. They say that a spear will hit a neo-otyugh. (Do YOU know what that is?) They say that a spotted dragon is the ultimate shape changer. They say that a stethoscope is no good if you can only hear your heartbeat. They say that a succubus named Suzy will sometimes warn you of danger. They say that a wand of cancellation is not like a wand of polymorph. They say that a wood golem named Pinocchio would be easy to control. They say that after killing a dragon it's time for a change of scenery. They say that an amulet of strangulation is worse than ring around the collar. They say that an attic is the best place to hide your toys. They say that an axe named Cleaver once belonged to a hacker named Beaver. They say that an eye of newt and a wing of bat are double the trouble. They say that an incubus named Izzy sometimes makes women feel sensitive. They say that an opulent throne room is rarely a place to wish you'd be in. They say that an unlucky hacker once had a nose bleed at an altar and died. They say that and they say this but they never say never, never! They say that any quantum mechanic knows that speed kills. They say that applying a unicorn horn means you've missed the point. They say that blue stones are radioactive, beware. They say that building a dungeon is a team effort. They say that chaotic characters never get a kick out of altars. They say that collapsing a dungeon often creates a panic. They say that counting your eggs before they hatch shows that you care. They say that dipping a bag of tricks in a fountain won't make it an icebox. They say that dipping an eel and brown mold in hot water makes bouillabaisse. They say that donating a doubloon is extremely pious charity. They say that dungeoneers prefer dark chocolate. They say that eating royal jelly attracts grizzly owlbears. They say that eggs, pancakes and juice are just a mundane breakfast. They say that everyone knows why Medusa stands alone in the dark. They say that everyone wanted rec.games.hack to undergo a name change. They say that finding a winning strategy is a deliberate move on your part. They say that finding worthless glass is worth something. They say that fortune cookies are food for thought. They say that gold is only wasted on a pet dragon. They say that good things come to those that wait. They say that greased objects will slip out of monsters' hands. They say that if you can't spell then you'll wish you had a spellbook. They say that if you live by the sword, you'll die by the sword. They say that if you play like a monster you'll have a better game. They say that if you sleep with a demon you might awake with a headache. They say that if you step on a crack you could break your mother's back. They say that if you're invisible you can still be heard! They say that if you're lucky you can feel the runes on a scroll. They say that in the big picture gold is only small change. They say that in the dungeon it's not what you know that really matters. They say that in the dungeon moon rocks are really dilithium crystals. They say that in the dungeon the boorish customer is never right. They say that in the dungeon you don't need a watch to tell time. They say that in the dungeon you need something old, new, burrowed and blue. They say that in the dungeon you should always count your blessings. They say that iron golem plate mail isn't worth wishing for. They say that it takes four quarterstaffs to make one staff. They say that it's not over till the fat ladies sing. They say that it's not over till the fat lady shouts `Off with its head'. They say that kicking a heavy statue is really a dumb move. They say that kicking a valuable gem doesn't seem to make sense. They say that leprechauns know Latin and you should too. They say that minotaurs get lost outside of the mazes. They say that most trolls are born again. They say that naming your cat Garfield will make you more attractive. They say that no one knows everything about everything in the dungeon. They say that no one plays NetHack just for the fun of it. They say that no one really subscribes to rec.games.roguelike.nethack. They say that no one will admit to starting a rumor. They say that nurses sometimes carry scalpels and never use them. They say that once you've met one wizard you've met them all. They say that one troll is worth 10,000 newts. They say that only David can find the zoo! They say that only angels play their harps for their pets. They say that only big spenders carry gold. They say that orc shamans are healthy, wealthy and wise. They say that playing NetHack is like walking into a death trap. They say that problem breathing is best treated by a proper diet. They say that quaffing many potions of levitation can give you a headache. They say that queen bees get that way by eating royal jelly. They say that reading a scare monster scroll is the same as saying Elbereth. They say that real hackers always are controlled. They say that real hackers never sleep. They say that shopkeepers are insured by Croesus himself! They say that shopkeepers never carry more than 20 gold pieces, at night. They say that shopkeepers never sell blessed potions of invisibility. They say that soldiers wear kid gloves and silly helmets. They say that some Kops are on the take. They say that some guards' palms can be greased. They say that some monsters may kiss your boots to stop your drum playing. They say that sometimes you can be the hit of the party when playing a horn. They say that the NetHack gods generally welcome your sacrifices. They say that the Three Rings are named Vilya, Nenya and Narya. They say that the Wizard of Yendor has a death wish. They say that the `hair of the dog' is sometimes an effective remedy. They say that the best time to save your game is now before it's too late. They say that the biggest obstacle in NetHack is your mind. They say that the gods are angry when they hit you with objects. They say that the priesthood are specially favored by the gods. They say that the way to make a unicorn happy is to give it what it wants. They say that there are no black or white stones, only gray. They say that there are no skeletons hence there are no skeleton keys. They say that there is a clever rogue in every hacker just dying to escape. They say that there is no such thing as free advice. They say that there is only one way to win at NetHack. They say that there once was a fearsome chaotic samurai named Luk No. They say that there was a time when cursed holy water wasn't water. They say that there's no point in crying over a gray ooze. They say that there's only hope left after you've opened Pandora's box. They say that trap doors should always be marked `Caution: Trap Door'. They say that using an amulet of change isn't a difficult operation. They say that water walking boots are better if you are fast like Hermes. They say that when you wear a circular amulet you might resemble a troll. They say that when you're hungry you can get a pizza in 30 moves or it's free. They say that when your god is angry you should try another one. They say that wielding a unicorn horn takes strength. They say that with speed boots you never worry about hit and run accidents. They say that you can defeat a killer bee with a unicorn horn. They say that you can only cross the River Styx in Charon's boat. They say that you can only kill a lich once and then you'd better be careful. They say that you can only wish for things you've already had. They say that you can train a cat by talking gently to it. They say that you can train a dog by talking firmly to it. They say that you can trust your gold with the king. They say that you can't wipe your greasy bare hands on a blank scroll. They say that you cannot trust scrolls of rumor. They say that you could fall head over heels for an energy vortex. They say that you need a key in order to open locked doors. They say that you need a mirror to notice a mimic in an antique shop. They say that you really can use a pick-axe unless you really can't. They say that you should always store your tools in the cellar. They say that you should be careful while climbing the ladder to success. They say that you should call your armor `rustproof'. They say that you should name your dog Spuds to have a cool pet. They say that you should name your weapon after your first monster kill. They say that you should never introduce a rope golem to a succubus. They say that you should never sleep near invisible ring wraiths. They say that you should never try to leave the dungeon with a bag of gems. They say that you should remove your armor before sitting on a throne. This fortune cookie is copy protected. This fortune cookie is the property of Fortune Cookies, Inc. This release contains 10% recycled material. Time stands still as the succubus changes her calendar to January 1, 2000. Tired? Try a scroll of charging on yourself. To achieve the next higher rating, you need 3 more points. To reach heaven, escape the dungeon while wearing a ring of levitation. Tourists wear shirts loud enough to wake the dead. Try calling your katana Moulinette. Ulch! That meat was painted! Unfortunately, this message was left intentionally blank. Using a morning star in the evening has no effect. Waltz, dumb nymph, for quick jigs vex. Want a hint? Zap a wand of make invisible on your weapon! Want to ascend in a hurry? Apply at Gizmonic Institute. Wanted: shopkeepers. Send a scroll of mail to Mage of Yendor/Level 35/Dungeon. Warning: fortune reading can be hazardous to your health. We have new ways of detecting treachery... Wet towels make great weapons! What a pity, you cannot read it! Whatever can go wrong, will go wrong. When a piercer drops in on you, you will be tempted to hit the ceiling! When in a maze follow the right wall and you will never get lost. When you have a key, you don't have to wait for the guard. Why are you wasting time reading fortunes? Wish for a master key and open the Magic Memory Vault! Wizard expects every monster to do its duty. Wow! You could've had a potion of fruit juice! Yet Another Silly Message (YASM). You are destined to be misled by a fortune. You can get a genuine Amulet of Yendor by doing the following: --More-- You can make holy water by boiling the hell out of it. You can protect yourself from black dragons by doing the following: --More-- You can't get by the snake. You choke on the fortune cookie. --More-- You feel like someone is pulling your leg. You have to outwit the Sphynx or pay her. You hear the fortune cookie's hissing! You may get rich selling letters, but beware of being blackmailed! You offend Shai-Hulud by sheathing your crysknife without having drawn blood. You swallowed the fortune! You want to regain strength? Two levels ahead is a guesthouse! You will encounter a tall, dark, and gruesome creature... nethack-3.6.0/dat/rumors.tru0000664000076400007660000005015712605665747015022 0ustar paxedpaxedA blindfold can be very useful if you're telepathic. A candelabrum affixed with seven candles shows the way with a magical light. A cream pie has two uses: food... and entertainment. A crystal plate mail will not rust. A katana might slice a worm in two. A magic vomit pump could be useful for gourmands. A nymph knows how to unlock chains. A potion of blindness lets you see invisible things. A priest can get the gods to listen easily. A priestess and a virgin you might be, but that unicorn won't care. A ring of conflict is a bad thing if there is a nurse in the room. A short sword is not as good as a long sword. A succubus will go farther than a nymph. A wand can exorcize a past explorer's ghost. Acid blobs should be attacked bare-handed. Affairs with nymphs are often very expensive. Afraid of nymphs? Wear a ring of adornment. Afraid of your valuables being stolen? Carry more junk! Always be aware of the phase of the moon! Always sweep the floor before engraving important messages. Amulets of Yendor are hard to make. Even for a wand of wishing. An elven cloak protects against magic. An umber hulk can be a confusing sight. As Crom is my witness, I'll never go hungry again! Asking about monsters may be very useful. Attack long worms from the rear -- that is so much safer! Attacking an eel where there is none is usually a fatal mistake! Bandaging wounds helps keep up appearances. Bashing monsters with a bow is not such a good idea. Be careful! The Wizard may plan an ambush! Be nice to a nurse: Put away your weapon and take off your clothes. Being digested is a painfully slow process. Blank scrolls make more interesting reading. Blind? Catch a floating eye! Booksellers never read scrolls; they might get carried away. Chemistry 101: Never pour water into acid. Concise conquest: Control, confuse, conjure, condemn. Conserve energy, turn off the lights. Digging up a grave could be a bad idea... Dilithium crystals are rare indeed. Dogs are attracted by the smell of tripe. Dogs are superstitious; they never step on cursed items. Dogs of ghosts aren't angry, just hungry. Don't forget! Large dogs are MUCH harder to kill than little dogs. Don't lash out at people while blinded. Don't mess with shopkeepers, or you'll get the Guild after you. Dragons never whip their children; they wouldn't feel it! Eat your carrots. They're good for your eyes. Eating a freezing sphere is like eating a yeti. Eating a killer bee is like eating a scorpion. Eating a tengu is like eating a nymph. Eating a wraith is a rewarding experience! Eating unpaid leprechauns may be advantageous. Elbereth has quite a reputation around these parts. Elf corpses are incompatible with the sandman, and at times the gods as well. Elven cloaks cannot rust. Elves can help you feel less tired. Even evil players have a guardian angel. Ever fought with an enchanted tooth? Ever tried reading while confused? Ever tried to put a troll into a large box? Ever wondered why one would want to dip something in a potion? Expensive cameras have penetrating flash lights. Extra staircases lead to extra levels. Fiery letters might deter monsters. For a good time engrave `Elbereth'. Gems are too precious to be thrown away carelessly. Getting hungry? Stop wearing rings! Getting too warm? Take off that Amulet of Yendor and stay away from the exit! Gods expect the best from their priesthood. Gods look down their noses at demigods. Gods love cats and dogs. Got a question? Try rec.games.roguelike.nethack. Grave robbers sometimes get rich. Guy Montag keeps his scrolls in a bag. Handle your flasks carefully -- there might be a ghost inside! Holy water has many uses. Horses trust their riders, even when not so deserved. Hunger is a confusing experience for a dog! I once knew a hacker who ate too fast and choked to death. I smell a maze of twisty little passages. I wish I never wished a wand of wishing. (Wishful thinking.) I wouldn't advise playing catch with a giant. I'm watching you. -- The Wizard of Yendor Ice boxes keep your food fresh. If you are being punished, it's done with a deadly weapon. If you kill the Wizard, you get promoted to demi-god. If you need a wand of digging, kindly ask the minotaur. If you want to hit, use a dagger. If you want to rob a shop, train your dog. If you're lost, try buying a map next time you're in a shop. Inside a shop you better take a look at the price tags before buying anything. It is bad manners to use a wand in a shop. It is dangerous to visit a graveyard at midnight. It is not always a good idea to whistle for your dog. It is rumored that the Wizard has hired some help. It is the letter 'c' and not 'e' that changes status to statue. It might be a good idea to offer the unicorn a ruby. It would be peculiarly sad were your dog turned to stone. It's a `d' eats `d' world. Just because it says READ ME doesn't mean you should. Keep your armors away from rust. Keep your weaponry away from acids. Kill a unicorn of your color and you kill your luck. Leather is waterproof. Ever see a cow with an umbrella? Leprechauns are the most skilled cutpurses in this dungeon. Lizard corpses protect against cockatrices. Money lost, little lost; honor lost, much lost; pluck lost, all lost. Most monsters can't swim. Music hath charms to affect the stubborn drawbridge. Music hath charms to soothe the savage beast. Never attack a guard. Never ride a long worm. Never use your best weapon to engrave a curse. No easy fighting with a heavy load! Not all boots were made for walking. Nurses are trained to touch naked persons: they don't harm them. Nymphs can unlink more than your chain mail. Once your little dog will be a big dog, and you will be proud of it. Only female monsters can lay eggs. Opening a tin is difficult, especially when you attempt it bare handed! Orcs and killer bees share their lifestyle. Orcs do not procreate in dark rooms. Plain nymphs are harmless. Playing AD&D may be helpful. Playing Gauntlet might be enlightening in some situations. Playing billiards pays when you are in a shop. Polymorphing a shopkeeper might make you safer. Polymorphing your dog probably makes you safer. Potions don't usually mix, but sometimes... Psst! It's done with mirrors! Put on a ring of teleportation: it will take you away from onslaught. Rays aren't boomerangs, of course, but still... Read the manual before entering the cave -- you might get killed otherwise. Reading Herbert might be enlightening in one case. Reading Tolkien might help you. Reading scrolls after drinking booze can give confusing results. Riding a dragon can be an uplifting experience. Rust monsters love water. There are potions they hate, however. Sacks protect contents from temperatures up to 452 degrees fahrenheit. Scrolls fading? It's not the heat, it's the humidity. Shopkeepers accept credit cards, as long as you pay cash. Shopkeepers can spot a tourist a mile away with those Hawaiian shirts. Shopkeepers can't tell identical twins apart. Shopkeepers don't read, so what use is engraving in a shop? Shopkeepers have incredible patience. Shopkeepers might raise their prices for tourists. Shopkeepers value money more than revenge. Some monsters can be tamed. I once saw a hacker with a tame dragon! Someone once said that what goes up < might come down >. Someone's been spiking the pits! Sometimes monsters are more likely to fight each other than attack you. Spinach, carrot, and jelly -- a meal fit for a nurse! Tainted meat is even more sickening than poison! Telepathy is just a trick: once you know how to do it, it's easy. The Leprechaun Gold Tru$t is no division of the Magic Memory Vault. The Wizard finds death to be quite an experience. The best equipment for your work is, of course, the most expensive. The gods don't appreciate pesky priesthood. The gods will get angry if you kill your dog. The magic marker is mightier than the sword. The moon is not the only heavenly body to influence this game. The orc swings his orcish broadsword named Elfrist at you. You die... The secret of wands of Nothing Happens: try again! There has always been something mystical about mirrors. There is a Mastermind deep in the dungeon. There is a big treasure hidden in the zoo! There is more magic in this cave than meets the eye. There is no harm in praising a large dog. There is nothing like eating a mimic. There once was a Knight named Lancelot who liked to ride with his lance a lot. They say a gelatinous cube can paralyze you... They say that Juiblex is afraid of a wand of digging. They say that Medusa would like to put you on a pedestal. They say that Vlad lives!!! ... in the mazes. They say that `Elbereth' is often written about. They say that a bag of holding can't hold everything. They say that a blessed tin of quasit meat is a quick meal. They say that a cat avoids traps. They say that a cave spider will occasionally eat cave spider eggs. They say that a clever wizard can have stats: 18/** 24 18 24 24 24. They say that a clove of garlic makes a good talisman if handled right. They say that a cursed scroll of teleportation could land you in trouble. They say that a diamond is another kind of luck stone. They say that a dog can be trained to fetch objects. They say that a gelatinous cube makes a healthy breakfast. They say that a giant gets strong by eating right, try it! They say that a grid bug won't hit you when you cross it. They say that a lembas wafer is a very light snack. They say that a loadstone has a strange attraction and is not bad luck. They say that a lock pick by any other name is still a lock pick. They say that a lucky amulet will block poisoned arrows. They say that a mirror will freeze a floating eye but you can still see it. They say that a neutral character might get Giantslayer. They say that a polymorph trap is magic and magic protection prevents it. They say that a potion of healing can cancel a potion of sickness. They say that a potion of monster detection sometimes works both ways. They say that a sink looks different from high above the floor. They say that a summoned demon could improve your game. They say that a tin of wraith meat is a rare dining experience. They say that a unicorn might bring you luck. They say that a wand of cancellation is like a wand of polymorph. They say that a wand of locking can close more than just doors. They say that a wand of polymorph can change your game. They say that a wizard is even more powerful the second time around. They say that a xorn knows of no obstacles when pursuing you. They say that abusing a credit card could shock you sooner or later. They say that amulets, like most things, can be deadly or life saving. They say that an altar can identify blessings. They say that an ooze will bite your boots and a rockmole will eat them. They say that an unlucky hacker was once killed by an exploding tin. They say that antique dealers are always interested in precious stones. They say that bandaging one's wounds helps to keep up one's appearance. They say that booze can be diluted but not cancelled. They say that by listening carefully, you can hear a secret door! They say that calculating your donations lets you choose your blessings. They say that carrots and carrot juice may improve your vision. They say that cave spiders are not considered expensive health food. They say that demigods must leave behind their prized earthly possessions. They say that disturbing a djinni can be a costly mistake. They say that dragon scales can be quite enchanting. They say that dropping coins into a fountain will not grant you a wish. They say that dwarves lawfully mind their own business. They say that eating a bat corpse will make you batty, for a while. They say that eating a cram ration is a smart move. They say that eating blue jelly is cool if you don't fight the feeling. They say that escaping a dungeon is only the beginning of the end. They say that feeling an unexpected draft of air is sort of a breakthrough. They say that finding a cursed gray stone is always bad luck. They say that gaining a level is an experience that can raise your sights. They say that garter snake meat rarely tastes good but it's still healthy. They say that gauntlets of dexterity have a hidden enchanted touch. They say that going to heaven is just another way of escaping the dungeon. They say that golden nagas are law-abiding denizens as long as you are too. They say that gremlins can make you feel cooler than you are now. They say that grid bugs only exist in a strictly Cartesian sense. They say that hackers often feel jumpy about eating nymphs. They say that having polymorph control won't shock you. They say that if it's hard getting your food down another bite could kill. They say that if you don't wear glasses why bother with carrots? They say that if you notice a loose board beneath you, don't step on it. They say that if you start at the bottom the only place to go is up. They say that if you teleport to heaven you're presumed to be dead already. They say that in a shop you can be charged for old charges. They say that in lighter moments you could think of ways to pass a stone. They say that in the dungeon breaking a mirror can be seven years bad luck. They say that in the dungeon you don't usually have any luck at all. They say that in time a blessed luckstone can make your god happy. They say that it is easier to kill the Wizard than to make him stand still. They say that it only takes 1 zorkmid to meet the Kops. They say that it's a blast when you mix the right potions together. They say that it's not blind luck if you catch a glimpse of Medusa. They say that killing a shopkeeper brings bad luck. They say that monsters never step on a scare monster scroll. They say that most monsters find flute recitals extremely boring. They say that mummy corpses are not well preserved. They say that naturally a wand of wishing would be heavily guarded. They say that no one notices the junk underneath a boulder. They say that nobody expects a unicorn horn to rust. They say that nobody knows if an explorer can live forever. Do you? They say that nothing can change the fact that some potions contain a djinni. They say that nothing can change the fact that some potions contain a ghost. They say that nymphs always fall for rock'n'roll, try it! They say that once an Olog-Hai is canned it never shows its face again. They say that once upon a time xans would never scratch your boots. They say that only an experienced wizard can do the tengu shuffle. They say that only chaotics can kill shopkeepers and get away with it. They say that only female monsters can lay eggs. They say that playing a horn really bad is really good. They say that prayer at an altar can sometimes make the water there holy. They say that rubbing a glowing potion does not make it a magic lamp. They say that scalpels become dull because they're not athames. They say that shopkeepers don't like pick-axes. They say that shopkeepers don't mind you bringing your pets in the shop. They say that shopkeepers don't usually mind if you sneak into a shop. They say that shopkeepers often have a large amount of money in their purses. They say that shopkeepers often remember things that you might forget. They say that sinks and armor don't mix, take your cloak off now! They say that sinks run hot and cold and many flavors in between. They say that snake charmers aren't charismatic, just musical. They say that soldiers are always prepared and usually protected. They say that some eggs could hatch in your pack, lucky or not. They say that some fire ants will make you a hot meal. They say that some horns play hot music and others are too cool for words. They say that some humanoids are nonetheless quite human. They say that some shopkeepers consider gems to be family heirlooms. They say that some shopkeepers recognize gems but they won't tell you. They say that some stones are much much heavier than others. They say that some yetis are full of hot air. They say that something very special would be in a well-protected place. They say that speed boots aren't fast enough to let you walk on water. They say that teleport traps are the devil's work. They say that tengu don't wear rings, why should you? They say that tengu never steal gold although they would be good at it. They say that that which was stolen once can be stolen again, ask any nymph. They say that the Delphic Oracle knows that lizard corpses aren't confusing. They say that the Hand of Elbereth can hold up your prayers. They say that the Leprechaun King is rich as Croesus. They say that the Wizard of Yendor is schizophrenic and suicidal. They say that the experienced character knows how to convert an altar. They say that the gods are happy when they drop objects at your feet. They say that the idea of invisible Nazguls has a certain ring to it. They say that the lady of the lake now lives in a fountain somewhere. They say that the local shopkeeper frowns upon the rude tourist. They say that the only door to the vampire's tower is on its lowest level. They say that the only good djinni is a grateful djinni. They say that the thing about genocide is that it works both ways. They say that the unicorn horn rule is if it ain't broke then don't fix it. They say that the view from a fog cloud is really very moving. They say that the walls in shops are made of extra hard material. They say that there are at least 15 ways to lose a pair of levitation boots. They say that throwing glass gems is the same as throwing rocks. They say that trespassing a boulder is probably beneath you. They say that unicorns are fond of precious gems. They say that what goes down the drain might come back up. They say that wielded, a long sword named Fire Brand makes you feel cooler. They say that wielded, a long sword named Frost Brand makes you hot stuff. They say that wiping its face is impossible for a floating eye. They say that with a floating eye you could see in the dark. They say that you are lucky if you can get a unicorn to catch a ruby. They say that you are what you eat. They say that you can find named weapons at an altar if you're lucky. They say that you can safely touch cockatrice eggs but why bother? They say that you can't break an amulet of reflection. They say that you don't always get what you wish for. They say that you should always be prepared for a final challenge. They say that you should ask a dwarf to let you into a locked shop. They say that you should pray for divine inspiration. They say that you should religiously give your gold away. They say that you will never get healthy by eating geckos. They say that zapping yourself with a wand of undead turning is stupid. They say the Wizard's castle is booby-trapped! They say the gods get angry if you kill your dog. They say the gods get angry if you pray too much. They say there is a powerful magic item hidden in a castle deep down! Those who wield a cockatrice corpse have a rocky road ahead of them. Throwing food at a wild dog might tame him. To a full belly all food is bad. Trolls are described as rubbery: they keep bouncing back. Try the fall-back end-run play against ghosts. Try using your magic marker on wet scrolls. Two wrongs don't make a right, but three lefts do. Unicorn horns can cleanse things other than yourself. Valkyries come from the north, and have commensurate abilities. Vampires hate garlic. Vault guards never disturb their Lords. Vegetarians enjoy lichen and seaweed. Visitors are requested not to apply genocide to shopkeepers. Watch out, the Wizard might come back. Water traps have no effect on dragons. What is a cockatrice going to eat when it gets hungry? Who needs an apron if they're made of glass? Why do you suppose they call them MAGIC markers? Why do you think they call them mercenaries? Why would anybody in his sane mind engrave "Elbereth"? Wishing too much may bring you too little. You can't bribe soldier ants. You can't leave a shop through the back door: there isn't one! You may discover a fine spirit inside a potion bottle. You may want to dip into a potion of bottled blessings. You might be able to bribe a demon lord. You might trick a shopkeeper if you're invisible. You should certainly learn about quantum mechanics. You won't always get a second chance, even with life saving. You're going into the morgue at midnight??? Your dog knows what to eat; maybe you should take lessons. Zap yourself and see what happens... Zapping a wand of undead turning might bring your dog back to life. nethack-3.6.0/dat/sokoban.des0000664000076400007660000003434112536476415015060 0ustar paxedpaxed# NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) 1998-1999 by Kevin Hugo # NetHack may be freely redistributed. See license for details. # # In case you haven't played the game Sokoban, you'll learn # quickly. This branch isn't particularly difficult, just time # consuming. Some players may wish to skip this branch. # # The following actions are currently permitted without penalty: # Carrying or throwing a boulder already in inventory # (player or nonplayer). # Teleporting boulders. # Digging in the floor. # The following actions are permitted, but with a luck penalty: # Breaking boulders. # Stone-to-fleshing boulders. # Creating new boulders (e.g., with a scroll of earth). # Jumping. # Being pulled by a thrown iron ball. # Hurtling through the air from Newton's 3rd law. # Squeezing past boulders when naked or as a giant. # These actions are not permitted: # Moving diagonally between two boulders and/or walls. # Pushing a boulder diagonally. # Picking up boulders (player or nonplayer). # Digging or walking through walls. # Teleporting within levels or between levels of this branch. # Using cursed potions of gain level. # Escaping a pit/hole (e.g., by flying, levitation, or # passing a dexterity check). # Bones files are not permitted. ### Bottom (first) level of Sokoban ### MAZE:"soko4-1",' ' FLAGS:noteleport,hardfloor,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ------ ----- |....| |...| |....----...| |...........| |..|-|.|-|..| ---------|.--- |......|.....| |..----|.....| --.| |.....| |.|---|.....| |...........| |..|--------- ---- ENDMAP BRANCH:(06,04,06,04),(0,0,0,0) STAIR:(06,06),up REGION:(00,00,13,12),lit,"ordinary" NON_DIGGABLE:(00,00,13,12) NON_PASSWALL:(00,00,13,12) # Boulders OBJECT:('`',"boulder"),(02,02) OBJECT:('`',"boulder"),(02,03) # OBJECT:('`',"boulder"),(10,02) OBJECT:('`',"boulder"),(09,03) OBJECT:('`',"boulder"),(10,04) # OBJECT:('`',"boulder"),(08,07) OBJECT:('`',"boulder"),(09,08) OBJECT:('`',"boulder"),(09,09) OBJECT:('`',"boulder"),(08,10) OBJECT:('`',"boulder"),(10,10) # Traps TRAP:"pit",(03,06) TRAP:"pit",(04,06) TRAP:"pit",(05,06) TRAP:"pit",(02,08) TRAP:"pit",(02,09) TRAP:"pit",(04,10) TRAP:"pit",(05,10) TRAP:"pit",(06,10) TRAP:"pit",(07,10) # A little help OBJECT:('?',"earth"),(02,11) OBJECT:('?',"earth"),(03,11) # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random MAZE:"soko4-2",' ' FLAGS:noteleport,hardfloor,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------- ------ |.|....|-|....| |.|-..........| |.||....|.....| |.||....|.....| |.|-----|.----- |.| |......| |.-----|......| |.............| |..|---|......| ---- -------- ENDMAP BRANCH:(03,01,03,01),(0,0,0,0) STAIR:(01,01),up REGION:(00,00,14,10),lit,"ordinary" NON_DIGGABLE:(00,00,14,10) NON_PASSWALL:(00,00,14,10) # Boulders OBJECT:('`',"boulder"),(05,02) OBJECT:('`',"boulder"),(06,02) OBJECT:('`',"boulder"),(06,03) OBJECT:('`',"boulder"),(07,03) # OBJECT:('`',"boulder"),(09,05) OBJECT:('`',"boulder"),(10,03) OBJECT:('`',"boulder"),(11,02) OBJECT:('`',"boulder"),(12,03) # OBJECT:('`',"boulder"),(07,08) OBJECT:('`',"boulder"),(08,08) OBJECT:('`',"boulder"),(09,08) OBJECT:('`',"boulder"),(10,08) # Traps TRAP:"pit",(01,02) TRAP:"pit",(01,03) TRAP:"pit",(01,04) TRAP:"pit",(01,05) TRAP:"pit",(01,06) TRAP:"pit",(01,07) TRAP:"pit",(03,08) TRAP:"pit",(04,08) TRAP:"pit",(05,08) TRAP:"pit",(06,08) # A little help OBJECT:('?',"earth"),(01,09) OBJECT:('?',"earth"),(02,09) # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random ### Second level ### MAZE:"soko3-1",' ' FLAGS:noteleport,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ----------- ----------- |....|....|-- |.........| |....|......| |.........| |.........|-- |.........| |....|....| |.........| |-.--------- |.........| |....|.....| |.........| |....|.....| |.........| |..........| |.........| |....|.....|---------------+| |....|......................| ----------------------------- ENDMAP STAIR:(11,02),down STAIR:(23,04),up DOOR:locked,(27,09) REGION:(00,00,28,11),lit,"ordinary" NON_DIGGABLE:(00,00,28,11) NON_PASSWALL:(00,00,28,11) # Boulders OBJECT:('`',"boulder"),(03,02) OBJECT:('`',"boulder"),(04,02) # OBJECT:('`',"boulder"),(06,02) OBJECT:('`',"boulder"),(06,03) OBJECT:('`',"boulder"),(07,02) # OBJECT:('`',"boulder"),(03,06) OBJECT:('`',"boulder"),(02,07) OBJECT:('`',"boulder"),(03,07) OBJECT:('`',"boulder"),(03,08) OBJECT:('`',"boulder"),(02,09) OBJECT:('`',"boulder"),(03,09) OBJECT:('`',"boulder"),(04,09) # OBJECT:('`',"boulder"),(06,07) OBJECT:('`',"boulder"),(06,09) OBJECT:('`',"boulder"),(08,07) OBJECT:('`',"boulder"),(08,10) OBJECT:('`',"boulder"),(09,08) OBJECT:('`',"boulder"),(09,09) OBJECT:('`',"boulder"),(10,07) OBJECT:('`',"boulder"),(10,10) # Traps TRAP:"hole",(12,10) TRAP:"hole",(13,10) TRAP:"hole",(14,10) TRAP:"hole",(15,10) TRAP:"hole",(16,10) TRAP:"hole",(17,10) TRAP:"hole",(18,10) TRAP:"hole",(19,10) TRAP:"hole",(20,10) TRAP:"hole",(21,10) TRAP:"hole",(22,10) TRAP:"hole",(23,10) TRAP:"hole",(24,10) TRAP:"hole",(25,10) TRAP:"hole",(26,10) # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random MAZE:"soko3-2",' ' FLAGS:noteleport,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ---- ----------- -|..|------- |.........| |..........| |.........| |..-----.-.| |.........| |..|...|...| |.........| |.........-| |.........| |.......|..| |.........| |.----..--.| |.........| |........|.-- |.........| |.---.-.....------------+| |...|...-................| |.........---------------- ----|..|..| ------- ENDMAP STAIR:(03,01),down STAIR:(20,04),up DOOR:locked,(24,09) REGION:(00,00,25,13),lit,"ordinary" NON_DIGGABLE:(00,00,25,13) NON_PASSWALL:(00,00,25,13) # Boulders OBJECT:('`',"boulder"),(02,03) OBJECT:('`',"boulder"),(08,03) OBJECT:('`',"boulder"),(09,04) OBJECT:('`',"boulder"),(02,05) OBJECT:('`',"boulder"),(04,05) OBJECT:('`',"boulder"),(09,05) OBJECT:('`',"boulder"),(02,06) OBJECT:('`',"boulder"),(05,06) OBJECT:('`',"boulder"),(06,07) OBJECT:('`',"boulder"),(03,08) OBJECT:('`',"boulder"),(07,08) OBJECT:('`',"boulder"),(05,09) OBJECT:('`',"boulder"),(10,09) OBJECT:('`',"boulder"),(07,10) OBJECT:('`',"boulder"),(10,10) OBJECT:('`',"boulder"),(03,11) # Traps TRAP:"hole",(12,10) TRAP:"hole",(13,10) TRAP:"hole",(14,10) TRAP:"hole",(15,10) TRAP:"hole",(16,10) TRAP:"hole",(17,10) TRAP:"hole",(18,10) TRAP:"hole",(19,10) TRAP:"hole",(20,10) TRAP:"hole",(21,10) TRAP:"hole",(22,10) TRAP:"hole",(23,10) # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random ### Third level ### MAZE:"soko2-1",' ' FLAGS:noteleport,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------------------- |........|...|.....| |.....-..|.-.|.....| |..|.....|...|.....| |-.|..-..|.-.|.....| |...--.......|.....| |...|...-...-|.....| |...|..|...--|.....| |-..|..|----------+| |..................| |...|..|------------ -------- ENDMAP STAIR:(06,10),down STAIR:(16,04),up DOOR:locked,(18,08) REGION:(00,00,19,11),lit,"ordinary" NON_DIGGABLE:(00,00,19,11) NON_PASSWALL:(00,00,19,11) # Boulders OBJECT:('`',"boulder"),(02,02) OBJECT:('`',"boulder"),(03,02) # OBJECT:('`',"boulder"),(05,03) OBJECT:('`',"boulder"),(07,03) OBJECT:('`',"boulder"),(07,02) OBJECT:('`',"boulder"),(08,02) # OBJECT:('`',"boulder"),(10,03) OBJECT:('`',"boulder"),(11,03) # OBJECT:('`',"boulder"),(02,07) OBJECT:('`',"boulder"),(02,08) OBJECT:('`',"boulder"),(03,09) # OBJECT:('`',"boulder"),(05,07) OBJECT:('`',"boulder"),(06,06) # Traps TRAP:"hole",(08,09) TRAP:"hole",(09,09) TRAP:"hole",(10,09) TRAP:"hole",(11,09) TRAP:"hole",(12,09) TRAP:"hole",(13,09) TRAP:"hole",(14,09) TRAP:"hole",(15,09) TRAP:"hole",(16,09) TRAP:"hole",(17,09) # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random MAZE:"soko2-2",' ' FLAGS:noteleport,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------- --|.|....| |........|---------- |.-...-..|.|.......| |...-......|.......| |.-....|...|.......| |....-.--.-|.......| |..........|.......| |.--...|...|.......| |....-.|---|.......| --|....|----------+| |................| ------------------ ENDMAP STAIR:(06,11),down STAIR:(15,06),up DOOR:locked,(18,10) REGION:(00,00,19,12),lit,"ordinary" NON_DIGGABLE:(00,00,19,12) NON_PASSWALL:(00,00,19,12) # Boulders OBJECT:('`',"boulder"),(04,02) OBJECT:('`',"boulder"),(04,03) OBJECT:('`',"boulder"),(05,03) OBJECT:('`',"boulder"),(07,03) OBJECT:('`',"boulder"),(08,03) OBJECT:('`',"boulder"),(02,04) OBJECT:('`',"boulder"),(03,04) OBJECT:('`',"boulder"),(05,05) OBJECT:('`',"boulder"),(06,06) OBJECT:('`',"boulder"),(09,06) OBJECT:('`',"boulder"),(03,07) OBJECT:('`',"boulder"),(04,07) OBJECT:('`',"boulder"),(07,07) OBJECT:('`',"boulder"),(06,09) OBJECT:('`',"boulder"),(05,10) OBJECT:('`',"boulder"),(05,11) # Traps TRAP:"hole",(07,11) TRAP:"hole",(08,11) TRAP:"hole",(09,11) TRAP:"hole",(10,11) TRAP:"hole",(11,11) TRAP:"hole",(12,11) TRAP:"hole",(13,11) TRAP:"hole",(14,11) TRAP:"hole",(15,11) TRAP:"hole",(16,11) TRAP:"hole",(17,11) # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random ### Top (last) level of Sokoban ### MAZE:"soko1-1",' ' FLAGS:noteleport,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------------------------- |........................| |.......|---------------.| -------.------ |.| |...........| |.| |...........| |.| --------.----- |.| |............| |.| |............| |.| -----.-------- ------|.| |..........| --|.....|.| |..........| |.+.....|.| |.........|- |-|.....|.| -------.---- |.+.....+.| |........| |-|.....|-- |........| |.+.....| |...|----- --|.....| ----- ------- ENDMAP $place = { (16,11),(16,13),(16,15) } SHUFFLE: $place STAIR:(01,01),down REGION:(00,00,25,17),lit,"ordinary" NON_DIGGABLE:(00,00,25,17) NON_PASSWALL:(00,00,25,17) # Boulders OBJECT:('`',"boulder"),(03,05) OBJECT:('`',"boulder"),(05,05) OBJECT:('`',"boulder"),(07,05) OBJECT:('`',"boulder"),(09,05) OBJECT:('`',"boulder"),(11,05) # OBJECT:('`',"boulder"),(04,07) OBJECT:('`',"boulder"),(04,08) OBJECT:('`',"boulder"),(06,07) OBJECT:('`',"boulder"),(09,07) OBJECT:('`',"boulder"),(11,07) # OBJECT:('`',"boulder"),(03,12) OBJECT:('`',"boulder"),(04,10) OBJECT:('`',"boulder"),(05,12) OBJECT:('`',"boulder"),(06,10) OBJECT:('`',"boulder"),(07,11) OBJECT:('`',"boulder"),(08,10) OBJECT:('`',"boulder"),(09,12) # OBJECT:('`',"boulder"),(03,14) # Traps TRAP:"hole",(08,01) TRAP:"hole",(09,01) TRAP:"hole",(10,01) TRAP:"hole",(11,01) TRAP:"hole",(12,01) TRAP:"hole",(13,01) TRAP:"hole",(14,01) TRAP:"hole",(15,01) TRAP:"hole",(16,01) TRAP:"hole",(17,01) TRAP:"hole",(18,01) TRAP:"hole",(19,01) TRAP:"hole",(20,01) TRAP:"hole",(21,01) TRAP:"hole",(22,01) TRAP:"hole",(23,01) MONSTER:('m',"giant mimic"), random, m_object "boulder" MONSTER:('m',"giant mimic"), random, m_object "boulder" # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random # Rewards DOOR:locked,(23,13) DOOR:closed,(17,11) DOOR:closed,(17,13) DOOR:closed,(17,15) REGION:(18,10,22,16),lit,"zoo",filled,irregular IF [50%] { OBJECT:('(',"bag of holding"),$place[0] } ELSE { OBJECT:('"',"amulet of reflection"),$place[0] } ENGRAVING:$place[0],burn,"Elbereth" OBJECT:('?', "scare monster"),$place[0],cursed MAZE:"soko1-2",' ' FLAGS:noteleport,premapped,solidify GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ------------------------ |......................| |..-------------------.| ----.| ----- |.| |..|.-- --...| |.| |.....|--|....| |.| |.....|..|....| |.| --....|......-- |.| |.......|...| ------|.| |....|..|...| --|.....|.| |....|--|...| |.+.....|.| |.......|..-- |-|.....|.| ----....|.-- |.+.....+.| ---.--.| |-|.....|-- |.....| |.+.....| |..|..| --|.....| ------- ------- ENDMAP $place = { (16,10),(16,12),(16,14) } SHUFFLE: $place STAIR:(06,15),down REGION:(00,00,25,16),lit,"ordinary" NON_DIGGABLE:(00,00,25,16) NON_PASSWALL:(00,00,25,16) # Boulders OBJECT:('`',"boulder"),(04,04) OBJECT:('`',"boulder"),(02,06) OBJECT:('`',"boulder"),(03,06) OBJECT:('`',"boulder"),(04,07) OBJECT:('`',"boulder"),(05,07) OBJECT:('`',"boulder"),(02,08) OBJECT:('`',"boulder"),(05,08) OBJECT:('`',"boulder"),(03,09) OBJECT:('`',"boulder"),(04,09) OBJECT:('`',"boulder"),(03,10) OBJECT:('`',"boulder"),(05,10) OBJECT:('`',"boulder"),(06,12) # OBJECT:('`',"boulder"),(07,14) # OBJECT:('`',"boulder"),(11,05) OBJECT:('`',"boulder"),(12,06) OBJECT:('`',"boulder"),(10,07) OBJECT:('`',"boulder"),(11,07) OBJECT:('`',"boulder"),(10,08) OBJECT:('`',"boulder"),(12,09) OBJECT:('`',"boulder"),(11,10) # Traps TRAP:"hole",(05,01) TRAP:"hole",(06,01) TRAP:"hole",(07,01) TRAP:"hole",(08,01) TRAP:"hole",(09,01) TRAP:"hole",(10,01) TRAP:"hole",(11,01) TRAP:"hole",(12,01) TRAP:"hole",(13,01) TRAP:"hole",(14,01) TRAP:"hole",(15,01) TRAP:"hole",(16,01) TRAP:"hole",(17,01) TRAP:"hole",(18,01) TRAP:"hole",(19,01) TRAP:"hole",(20,01) TRAP:"hole",(21,01) TRAP:"hole",(22,01) MONSTER:('m',"giant mimic"), random, m_object "boulder" MONSTER:('m',"giant mimic"), random, m_object "boulder" # Random objects OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'%',random OBJECT:'=',random OBJECT:'/',random # Rewards DOOR:locked,(23,12) DOOR:closed,(17,10) DOOR:closed,(17,12) DOOR:closed,(17,14) REGION:(18,09,22,15),lit,"zoo",filled,irregular IF [50%] { OBJECT:('(',"bag of holding"),$place[0] } ELSE { OBJECT:('"',"amulet of reflection"),$place[0] } ENGRAVING:$place[0],burn,"Elbereth" OBJECT:('?', "scare monster"),$place[0],cursed nethack-3.6.0/dat/symbols0000664000076400007660000002353712541713002014325 0ustar paxedpaxed# Symbol sets for use in NetHack's text-based display. # # IBMgraphics works by specifying special characters which reside # outside the range of normal printable characters. It has subsets # for use where the internal code page is different than the one # used by US ASCII (437) and has some different special characters. # # DECgraphics works by switching back and forth between two fonts, # where the alternate one substitutes special characters in place # of ordinary printable characters in the lowercase letter range. # NetHack encodes the request to use the alternate font here by # having the high bit set (in hexadecimal, \x80 is combined with # a character code between \x60 and \x7f). start: DECgraphics Handling: DEC S_vwall: \xf8 # meta-x, vertical rule S_hwall: \xf1 # meta-q, horizontal rule S_tlcorn: \xec # meta-l, top left corner S_trcorn: \xeb # meta-k, top right corner S_blcorn: \xed # meta-m, bottom left S_brcorn: \xea # meta-j, bottom right S_crwall: \xee # meta-n, cross S_tuwall: \xf6 # meta-v, T up S_tdwall: \xf7 # meta-w, T down S_tlwall: \xf5 # meta-u, T left S_trwall: \xf4 # meta-t, T right S_ndoor: \xfe # meta-~, centered dot S_vodoor: \xe1 # meta-a, solid block S_hodoor: \xe1 # meta-a, solid block S_bars: \xfb # meta-{, small pi S_tree: \xe7 # meta-g, plus-or-minus S_room: \xfe # meta-~, centered dot S_upladder: \xf9 # meta-y, greater-than-or-equals S_dnladder: \xfa # meta-z, less-than-or-equals S_pool: \xe0 # meta-\, diamond S_ice: \xfe # meta-~, centered dot S_lava: \xe0 # meta-\, diamond S_vodbridge: \xfe # meta-~, centered dot S_hodbridge: \xfe # meta-~, centered dot S_water: \xe0 # meta-\, diamond S_vbeam: \xf8 # meta-x, vertical rule S_hbeam: \xf1 # meta-q, horizontal rule S_sw_tc: \xef # meta-o, high horizontal line S_sw_ml: \xf8 # meta-x, vertical rule S_sw_mr: \xf8 # meta-x, vertical rule S_sw_bc: \xf3 # meta-s, low horizontal line S_explode2: \xef # meta-o, high horizontal line S_explode4: \xf8 # meta-x, vertical rule S_explode6: \xf8 # meta-x, vertical rule S_explode8: \xf3 # meta-s, low horizontal line finish start: IBMgraphics Handling: IBM S_vwall: \xb3 # meta-3, vertical rule S_hwall: \xc4 # meta-D, horizontal rule S_tlcorn: \xda # meta-Z, top left corner S_trcorn: \xbf # meta-?, top right corner S_blcorn: \xc0 # meta-@, bottom left S_brcorn: \xd9 # meta-Y, bottom right S_crwall: \xc5 # meta-E, cross S_tuwall: \xc1 # meta-A, T up S_tdwall: \xc2 # meta-B, T down S_tlwall: \xb4 # meta-4, T left S_trwall: \xc3 # meta-C, T right S_ndoor: \xfa # meta-z, centered dot S_vodoor: \xfe # meta-~, small centered square S_hodoor: \xfe # meta-~, small centered square S_bars: \xf0 # equivalence symbol S_tree: \xf1 # plus or minus symbol S_room: \xfa # meta-z, centered dot S_corr: \xb0 # meta-0, light shading S_litcorr: \xb1 # meta-1, medium shading S_fountain: \xf4 # meta-t, integral top half S_pool: \xf7 # meta-w, approx. equals S_ice: \xfa # meta-z, centered dot S_lava: \xf7 # meta-w, approx. equals S_vodbridge: \xfa # meta-z, centered dot S_hodbridge: \xfa # meta-z, centered dot S_water: \xf7 # meta-w, approx. equals S_vbeam: \xb3 # meta-3, vertical rule S_hbeam: \xc4 # meta-D, horizontal rule S_sw_ml: \xb3 # meta-3, vertical rule S_sw_mr: \xb3 # meta-3, vertical rule S_explode4: \xb3 # meta-3, vertical rule S_explode6: \xb3 # meta-3, vertical rule finish start: IBMGraphics_1 Handling: IBM S_vwall: \xb3 # meta-3, vertical rule S_hwall: \xc4 # meta-D, horizontal rule S_tlcorn: \xda # meta-Z, top left corner S_trcorn: \xbf # meta-?, top right corner S_blcorn: \xc0 # meta-@, bottom left S_brcorn: \xd9 # meta-Y, bottom right S_crwall: \xc5 # meta-E, cross S_tuwall: \xc1 # meta-A, T up S_tdwall: \xc2 # meta-B, T down S_tlwall: \xb4 # meta-4, T left S_trwall: \xc3 # meta-C, T right S_vbeam: \xb3 # meta-3, vertical rule S_hbeam: \xc4 # meta-D, horizontal rule S_sw_ml: \xb3 # meta-3, vertical rule S_sw_mr: \xb3 # meta-3, vertical rule S_explode4: \xb3 # meta-3, vertical rule S_explode6: \xb3 # meta-3, vertical rule finish start: IBMGraphics_2 Handling: IBM S_vwall: \xb3 # meta-3, vertical rule S_hwall: \xc4 # meta-D, horizontal rule S_tlcorn: \xda # meta-Z, top left corner S_trcorn: \xbf # meta-?, top right corner S_blcorn: \xc0 # meta-@, bottom left S_brcorn: \xd9 # meta-Y, bottom right S_crwall: \xc5 # meta-E, cross S_tuwall: \xc1 # meta-A, T up S_tdwall: \xc2 # meta-B, T down S_tlwall: \xb4 # meta-4, T left S_trwall: \xc3 # meta-C, T right S_vodoor: \xfe # meta-~, small centered square S_hodoor: \xfe # meta-~, small centered square S_corr: \xb0 # meta-0, light shading S_litcorr: \xb1 # meta-1, medium shading S_vbeam: \xb3 # meta-3, vertical rule S_hbeam: \xc4 # meta-D, horizontal rule S_sw_ml: \xb3 # meta-3, vertical rule S_sw_mr: \xb3 # meta-3, vertical rule S_explode4: \xb3 # meta-3, vertical rule S_explode6: \xb3 # meta-3, vertical rule finish start: MACgraphics Handling: MAC S_vwall: \xba S_hwall: \xcd S_tlcorn: \xc9 S_trcorn: \xbb S_blcorn: \xc8 S_brcorn: \xbc S_crwall: \xce S_tuwall: \xca S_tdwall: \xcb S_tlwall: \xb9 S_trwall: \xcc S_ndoor: \xb0 S_vodoor: \xee S_hodoor: \xee S_vcdoor: \xef S_hcdoor: \xef S_bars: \xf0 # equivalency symbol S_tree: \xf1 # plus-or-minus S_corr: \xb0 S_grave: \xef # same as open door S_pool: \xe0 finish start: RogueIBM Handling: IBM Restrictions: rogue S_weapon: \x29 S_amulet: \x2c S_food: \x3a S_potion: \xad S_scroll: \x3f S_book: \x2b S_wand: \xe7 S_vwall: \xba # all walls now use S_hwall: \xcd # double line graphics S_tlcorn: \xc9 S_trcorn: \xbb S_blcorn: \xc8 S_brcorn: \xbc S_crwall: \xce S_tuwall: \xca S_tdwall: \xcb S_tlwall: \xb9 S_trwall: \xcc S_ndoor: \xce S_vodoor: \xce S_hodoor: \xce S_room: \xfa # centered dot S_corr: \xb1 S_litcorr: \xb2 S_upstair: \xf0 # Greek Xi S_dnstair: \xf0 finish start: RogueEpyx Description: Rogue level color symbol set like Epyx Rogue Restrictions: rogue Handling: IBM Color: Yes S_weapon: \x18 # up arrow S_armor: \x0a # Vert rect with o S_ring: \x09 # circle with arrow S_amulet: \x0c # "female" symbol S_food: \x05 # club (as in cards) S_potion: \xad # upside down '!' S_scroll: \x0e # musical note S_wand: \xe7 # greek tau S_coin: \x0f # yes it's the same as gems S_gem: \x0f # fancy '*' S_rock: \x60 S_ball: \x30 S_chain: \x5f S_venom: \x2e S_vwall: \xba # all walls now use S_hwall: \xcd # double line graphics S_tlcorn: \xc9 S_trcorn: \xbb S_blcorn: \xc8 S_brcorn: \xbc S_crwall: \xce S_tuwall: \xca S_tdwall: \xcb S_tlwall: \xb9 S_trwall: \xcc S_ndoor: \xce S_vodoor: \xce S_hodoor: \xce S_room: \xfa # centered dot S_corr: \xb1 S_litcorr: \xb2 S_upstair: \xf0 # Greek Xi S_dnstair: \xf0 S_arrow_trap: \x04 # diamond (cards) S_dart_trap: \x04 S_falling_rock_trap: \x04 S_squeaky_board: \x04 S_bear_trap: \x04 S_land_mine: \x04 S_rolling_boulder_trap: \x04 S_sleeping_gas_trap: \x04 S_rust_trap: \x04 S_fire_trap: \x04 S_pit: \x04 S_spiked_pit: \x04 S_hole: \x04 S_trap_door: \x04 S_teleportation_trap: \x04 S_level_teleporter: \x04 S_magic_portal: \x04 S_web: \x04 S_statue_trap: \x04 S_magic_trap: \x04 S_anti_magic_trap: \x04 S_polymorph_trap: \x04 S_weapon: \x18 S_armor: \x5b S_ring: \x3d S_amulet: \xc S_tool: \x28 S_food: \x5 S_potion: \xad S_scroll: \xe S_book: \x2b S_wand: \xe7 S_coin: \xf S_gem: \xf S_rock: \x60 S_ball: \x30 S_chain: \x5f S_venom: \x2e S_human: \x01 finish start: RogueWindows Restrictions: rogue Handling: IBM S_weapon: \x29 S_amulet: \x2c S_food: \x3a S_potion: \xad S_scroll: \x3f S_book: \x2b S_wand: \xe7 S_vwall: \xba # all walls now use S_hwall: \xcd # double line graphics S_tlcorn: \xc9 S_trcorn: \xbb S_blcorn: \xc8 S_brcorn: \xbc S_crwall: \xce S_tuwall: \xca S_tdwall: \xcb S_tlwall: \xb9 S_trwall: \xcc S_ndoor: \xce S_vodoor: \xce S_hodoor: \xce S_room: \xfa # centered dot S_corr: \xb1 S_litcorr: \xb2 S_upstair: \xf0 # Greek Xi S_dnstair: \xf0 finish # Recommended symset for blind players # courtesy Michael Feir start: NHAccess Description: Recommended for blind players S_stone: \032 S_vwall: \124 S_hwall: \045 S_tlcorn: \124 S_trcorn: \124 S_blcorn: \124 S_brcorn: \124 S_crwall: \045 S_tuwall: \045 S_tdwall: \045 S_tlwall: \124 S_trwall: \124 S_ndoor: \046 S_vodoor: \045 S_hodoor: \124 S_vcdoor: \043 S_hcdoor: \043 S_bars: \046 S_tree: \035 S_room: \035 S_corr: \060 S_litcorr: \062 S_upstair: \060 S_dnstair: \062 S_upladder: \095 S_dnladder: \092 S_altar: \035 S_grave: \126 S_throne: \126 S_sink: \126 S_fountain: \126 S_pool: \042 S_ice: \042 S_lava: \035 S_vodbridge: \035 S_hodbridge: \032 S_vcdbridge: \035 S_hcdbridge: \126 S_arrow_trap: \094 S_dart_trap: \094 S_falling_rock_trap: \094 S_squeaky_board: \094 S_bear_trap: \094 S_land_mine: \094 S_rolling_boulder_trap: \094 S_sleeping_gas_trap: \094 S_rust_trap: \094 S_fire_trap: \094 S_pit: \094 S_spiked_pit: \094 S_hole: \094 S_trap_door: \094 S_teleportation_trap: \094 S_level_teleporter: \094 S_magic_portal: \094 S_web: \094 S_statue_trap: \094 S_magic_trap: \094 S_anti_magic_trap: \094 S_polymorph_trap: \094 S_vbeam: \124 S_hbeam: \095 S_lslant: \092 S_rslant: \047 S_digbeam: \042 S_flashbeam: \033 S_boomleft: \041 S_boomright: \040 S_ss1: \048 S_ss2: \035 S_ss3: \064 S_ss4: \042 S_sw_tl: \047 S_sw_tc: \045 S_sw_tr: \092 S_sw_ml: \058 S_sw_mr: \058 S_sw_bl: \092 S_sw_bc: \045 S_sw_br: \047 S_explode1: \047 S_explode2: \045 S_explode3: \092 S_explode4: \058 S_explode5: \032 S_explode6: \058 S_explode7: \092 S_explode8: \045 S_explode9: \047 finish nethack-3.6.0/dat/tower.des0000644000076400007660000000707512537232204014551 0ustar paxedpaxed# NetHack 3.6 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # Copyright (c) 1989 by Jean-Christophe Collet # NetHack may be freely redistributed. See license for details. # # Upper stage of Vlad's tower MAZE:"tower1",' ' FLAGS: noteleport,hardfloor,solidify GEOMETRY:half-left,center MAP --- --- --- |.| |.| |.| ---S---S---S--- |.......+.+...| ---+-----.----- |...\.|.+.| ---+-----.----- |.......+.+...| ---S---S---S--- |.| |.| |.| --- --- --- ENDMAP $niches = { (03,01), (03,09), (07,01), (07,09), (11,01), (11,09) } SHUFFLE: $niches LADDER:(11,05),down # The lord and his court MONSTER:('V',"Vlad the Impaler"),(06,05) MONSTER:'V',$niches[0] MONSTER:'V',$niches[1] MONSTER:'V',$niches[2] MONSTER:'V',$niches[3] MONSTER:'V',$niches[4] MONSTER:'V',$niches[5] # The doors DOOR:closed,(08,03) DOOR:closed,(10,03) DOOR:closed,(03,04) DOOR:locked,(10,05) DOOR:locked,(08,07) DOOR:locked,(10,07) DOOR:closed,(03,06) # treasures OBJECT:('(',"chest"),(07,05) OBJECT:('(',"chest"),$niches[0] OBJECT:('(',"chest"),$niches[1] OBJECT:('(',"chest"),$niches[2] OBJECT:('(',"chest"),$niches[3] CONTAINER:('(',"chest"),$niches[4] { OBJECT:('(', "wax candle"), quantity:4d2 } CONTAINER:('(',"chest"),$niches[5] { OBJECT:('(', "tallow candle"), quantity:4d2 } # We have to protect the tower against outside attacks NON_DIGGABLE:(00,00,14,10) # Intermediate stage of Vlad's tower MAZE:"tower2",' ' FLAGS: noteleport,hardfloor,solidify GEOMETRY:half-left,center MAP --- --- --- |.| |.| |.| ---S---S---S--- |.S.........S.| ---.------+---- |......|..| --------.------ |.S......+..S.| ---S---S---S--- |.| |.| |.| --- --- --- ENDMAP # Random places are the 10 niches $place = { (03,01),(07,01),(11,01),(01,03),(13,03), (01,07),(13,07),(03,09),(07,09),(11,09) } SHUFFLE: $place LADDER:(11,05),up LADDER:(03,07),down DOOR:locked,(10,04) DOOR:locked,(09,07) MONSTER:'&',$place[0] MONSTER:'&',$place[1] MONSTER:('d',"hell hound pup"),$place[2] MONSTER:('d',"hell hound pup"),$place[3] MONSTER:('d',"winter wolf"),$place[4] CONTAINER:('(',"chest"),$place[5] { OBJECT:('"',"amulet of life saving") } CONTAINER:('(',"chest"),$place[6] { OBJECT:('"',"amulet of strangulation") } OBJECT:('[',"water walking boots"),$place[7] OBJECT:('[',"crystal plate mail"),$place[8] OBJECT:('+',"invisibility"),$place[9] # Walls in the tower are non diggable NON_DIGGABLE:(00,00,14,10) # Bottom most stage of Vlad's tower MAZE:"tower3",' ' FLAGS: noteleport,hardfloor,solidify GEOMETRY:half-left,center MAP --- --- --- |.| |.| |.| ---S---S---S--- |.S.........S.| -----.........----- |...|.........+...| |.---.........---.| |.|.S.........S.|.| |.---S---S---S---.| |...|.|.|.|.|.|...| ---.---.---.---.--- |.............| --------------- ENDMAP # Random places are the 10 niches $place = { (05,01),(09,01),(13,01),(03,03),(15,03), (03,07),(15,07),(05,09),(09,09),(13,09) } SHUFFLE: $place BRANCH:(02,05,02,05),(00,00,00,00) LADDER:(05,07),up # Entry door is, of course, locked DOOR:locked,(14,05) # Let's put a dragon behind the door, just for the fun... MONSTER:'D',(13,05) MONSTER:random,(12,04) MONSTER:random,(12,06) MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random MONSTER:random,random OBJECT:(')',"long sword"),$place[0] TRAP:random,$place[0] OBJECT:('(',"lock pick"),$place[1] TRAP:random,$place[1] OBJECT:('[',"elven cloak"),$place[2] TRAP:random,$place[2] OBJECT:('(',"blindfold"),$place[3] TRAP:random,$place[3] # Walls in the tower are non diggable NON_DIGGABLE:(00,00,18,12) nethack-3.6.0/dat/tribute0000664000076400007660000062104212627041424014315 0ustar paxedpaxed# NetHack 3.6.0 tribute to: # # Sir Terence David John "Terry" Pratchett # April 28, 1948 - March 12, 2015 # ("or until the ripples he caused in the world die away...") # # %section books # # # %title The Colour of Magic (2) %passage 1 It has been remarked before that those who are sensitive to radiation in the far octarine - the eighth colour, the pigment of the Imagination - can see things that others cannot. Thus it was that Rincewind, hurrying through the crowded, flare-lit, evening bazarrs of Morpork with the Luggage trundling behind him, jostled a tall figure, turned to deliver a few suitable curses, and beheld Death. It had to be Death. No-one else went around with empty eye sockets and, of course, the scythe over one shoulder was another clue. [The Colour of Magic, by Terry Pratchett] %e passage 1 %passage 2 As he was drawn towards the Eye the terror-struck Rincewind raised the box protectively, and at the same time heard the picture imp say, 'They're about ripe now, can't hold them any longer. Every-one smile, please.' There was a - - flash of light so white and so bright - - it didn't seem like light at all. Bel-Shamharoth screamed, a sound that started in the far ultrasonic and finished somewhere in Rincewind's bowels. The tentacles went momentarily as stiff as rods, hurling their various cargos around the room, before bunching up protectively in front of the abused Eye. The whole mass dropped into the pit and a moment later the big slab was snatched up by several dozen tentacles and slammed into place, leaving a number of thrashing limbs trapped around the edge. [The Colour of Magic, by Terry Pratchett] %e passage 2 %e title # # # %title The Light Fantastic (2) %passage 1 'Cohen is my name, boy' Belthan's hands stopped moving. 'Cohen?' she said, 'Cohen the Barbarian?' 'The very shame.' 'Hang on, hang on,' said Rincewind, 'Cohen's a great big chap, neck like a bull, got chest muscles like a sack of footballs. I mean, he's the Disc's greatest warrior, a legend in his own lifetime. I remember my grandad telling me he saw him ... my grandad telling me he ... my grandad ...' He faltered under the gimlit gaze. 'Oh,' he said, 'Oh. Of course, Sorry.' 'Yesh,' said Cohen, and sighed, 'Thatsh right boy, I'm a lifetime in my own legend.' [The Light Fantastic, by Terry Pratchett] %e passage 1 %passage 2 Death sat at one side of a black baize table in the entre of the room, arguing with Famine, War and Pestilence. Twoflower was the only one to look up and notice Rincewind. 'Hey, how did you get here?' he said. 'Well, some say that the creator took a handful - oh, I see, well, it's hard to explain but I -' 'Have you got the Luggage?' The wooden box pushed past Rincewind and settled down in front of its owner, who opened its lid and rummaged around inside until he came up with a small, leatherbound book which he handed to War, who was hammering the table with a mailed fist. 'It's "Nosehinger on the Laws of Contract",' he said. 'It's quite good, there's a lot in it about double finessing and how to -' Death snatched the book with a bony hand and flipped through the pages, quite oblivious to the presence of the two men. 'RIGHT,' he said, 'PESTILENCE, OPEN ANOTHER PACK OF CARDS. I'M GOING TO GET TO THE BOTTOM OF THIS IF IT KILLS ME. FIGURATIVELY SPEAKING OF COURSE.' [The Light Fantastic, by Terry Pratchett] %e passage 2 %e title # # # %title Equal Rites (3) %passage 1 ...it is well known that a vital ingredient of success is not knowing that what you're attempting can't be done. [Equal Rites, by Terry Pratchett] %e passage %passage 2 Million-to-one chances...crop up nine times out of ten. [Equal Rites, by Terry Pratchett] %e passage %passage 3 Animal minds are simple, and therefore sharp. Animals never spend time dividing experience into little bits and speculating about all the bits they've missed. The whole panoply of the universe has been neatly expressed to them as things to (a) mate with, (b) eat, (c) run away from, and (d) rocks. This frees the mind from unnecessary thoughts and gives it a cutting edge where it matters. Your normal animal, in fact, never tries to walk and chew gum at the same time. The average human, on the other hand, thinks about all sorts of things around the clock, on all sorts of levels, with interruptions from dozens of biological calendars and timepieces. There's thoughts about to be said, and private thoughts, and real thoughts, and thoughts about thoughts, and a whole gamut of subconscious thoughts. To a telepath the human head is a din. It is a railway terminus with all the Tannoys talking at once. It is a complete FM waveband- and some of those stations aren't reputable, they're outlawed pirates on forbidden seas who play late-night records with limbic lyrics. [Equal Rites, by Terry Pratchett] %e passage %e title # # # %title Mort (1) %passage 1 Ankh-Morpork had dallied with many forms of government and hand ended up with that form of democracy known as One Man, One Vote. The Patrician was the Man; he had the Vote. [Mort, by Terry Pratchett] %e passage %e title # # # %title Sourcery (2) %passage 1 And what would humans be without love? RARE, said Death. [Sourcery, by Terry Pratchett] %e passage %passage 2 They suffered from the terrible delusion that something could be done. They seemed prepared to make the world the way they wanted it or die in the attempt, and the trouble with dying in the attempt was that you died in the attempt. [Sourcery, by Terry Pratchett] %e passage %e title # # # %title Wyrd Sisters (2) %passage 1 Destiny is important, see, but people go wrong when they think it controls them. It's the other way around. [Wyrd Sisters, by Terry Pratchett] %e passage %passage 2 #submitted by Boudewijn Verence tried to avoid walking through walls. A man had his dignity. He became aware that he was being watched. He turned his head. There was a cat sitting in the doorway, subjecting him to a slow blink. It was a mottled grey and extremely fat... No. It was extremely /big/. It was covered with so much scar tissue that it looked like a fist with fur on it. Its ears were a couple of perforated stubs, its eyes two yellow slits of easy-going malevolence, its tail a twitching series of question marks as it stared at him. Greebo had heard that Lady Felmet had a small white female cat and had strolled up to pay his respects. Verence had never seen an animal with so much built-in villainy. He didn't resist as it waddled across the floor and dried to rub itself against his legs, purring like a waterfall. 'Well, well,' said the king, vaguely. He reached down and made an effort to scratch it behind the two ragged bits on top of its head. It was a relief to find someone else besides another ghost who could see him, and Greebo, he couldn't help feeling, was a distinctly unusual cat. Most of the castle cats were either pampered pets or flat-eared kitchen and stable habitues who generally resembled the very rodents they lived on. This cat, on the other hand, was its own animal. All cats give that impression, of course, but instead of the mindless animal self-absorption that passes for secret wisdom in the creatures, Greebo radiated genuime intelligence. He also radiated a smell that would have knocked over a wall and caused sinus trouble in a dead fox. [Wyrd Sisters, by Terry Pratchett] %e passage %e title # # # %title Pyramids (2) %passage 1 The trouble with life was that you didn't get a chance to practice before doing it for real. [Pyramids, by Terry Pratchett] %e passage %passage 2 Mere animals couldn't possibly manage to act like this. You need to be a human being to be really stupid. [Pyramids, by Terry Pratchett] %e passage %e title # # # %title Guards! Guards! (2) %passage 1 Never build a dungeon you wouldn't be happy to spend the night in yourself. The world would be a happier place if more people remembered that. [Guards! Guards!, by Terry Pratchett] %e passage %passage 2 These weren't encouraged in the city, since the heft and throw of a longbow's arrow could send it through an innocent bystander a hundred yards away instead of the innocent bystander at whom it was aimed. [Guards! Guards!, by Terry Pratchett] %e passage %e title # # # %title Eric (2) %passage 1 No enemies had ever taken Ankh-Morpork. Well, /technically/ they had, quite often; the city welcomed free-spending barbarian invaders, but somehow the puzzled raiders always found, after a few days, that they didn't own their own horses any more, and within a couple of months they were just another minority group with its own graffiti and food shops. [Eric, by Terry Pratchett] %e passage %passage 2 Rincewind looked down at the broad steps they were climbing. They were something of a novelty; each one was built out of large stone letters. The one he was just stepping on to, for example, read: I Meant It For The Best. The next one was: I Thought You'd Like It. Eric was standing on: For The Sake Of The Children. 'Weird, isn't it?' he said. 'Why do it like this?' 'I think they're meant to be good intentions,' said Rincewind. This was a road to hell, and demons were, after all, traditionalists. [Eric, by Terry Pratchett] %e passage %e title # # # %title Moving Pictures (4) %passage 1 This is space. It's sometimes called the final frontier. (Except that of course you can't have a /final/ frontier, because there'd be nothing for it to be a frontier /to/, but as frontiers go, it's pretty penultimate...) [Moving Pictures, by Terry Pratchett] %e passage %passage 2 By and large, the only skill the alchemists of Ankh-Morpork had discovered so far was the ability to turn gold into less gold. [Moving Pictures, by Terry Pratchett] %e passage %passage 3 There was a dog sitting by his feet. It was small, bow-legged and wiry, and basically grey but with patches of brown, white, and black in outlying areas... It looked up slowly, and said 'Woof?' Victor poked an exploratory finger in his ear. It must have been a trick of an echo, or something. It wasn't that the dog had gone 'woof!', although that was practically unique in itself; most dogs in the universe /never/ went 'woof!', they had complicated barks like 'whuuugh!' and 'hwhoouf!'. No, it was that it hadn't in fact /barked/ at all. It had /said/ 'woof'. 'Could have bin worse, mister. I could have said "miaow".' [Moving Pictures, by Terry Pratchett] %e passage %passage 4 ''Twas beauty killed the beast,' said the Dean, who liked to say things like that. 'No it wasn't,' said the Chair. 'It was it splatting into the ground like that.' [Moving Pictures, by Terry Pratchett] %e passage %e title # # # %title Reaper Man (4) %passage 1 No one is actually dead until the ripples they cause in the world die away... [Reaper Man, by Terry Pratchett] %e passage %passage 2 Five exclamation marks, the sure sign of an insane mind. [Reaper Man, by Terry Pratchett] %e passage %passage 3 Light thinks it travels faster than anything but it is wrong. No matter how fast light travels, it finds the darkness has always got there first, and is waiting for it. [Reaper Man, by Terry Pratchett] %e passage %passage 4 "That's not fair, you know. If we knew when we were going to die, people would lead better lives." IF PEOPLE KNEW WHEN THEY WERE GOING TO DIE, I THINK THEY PROBABLY WOULDN'T LIVE AT ALL. [Reaper Man, by Terry Pratchett] %e passage %e title # # # %title Witches Abroad (1) %passage 1 Vampires have risen from the dead, the grave and the crypt, but have never managed it from the cat. [Witches Abroad, by Terry Pratchett] %e passage %e title # # # %title Small Gods (12) %passage 1 He says gods like to see an atheist around. Gives them something to aim at. [Small Gods, by Terry Pratchett] %e passage %passage 2 Pets are always a great help in times of stress. And in times of starvation too, o'course. [Small Gods, by Terry Pratchett] %e passage # p. 3 (Harper Torch edition) %passage 3 So history has its caretakers. They live ... well, in the nature of things they live wherever they are sent, but their /spiritual/ home is in a hidden valley in the high Ramtops of the Discworld, where the books of history are kept. These aren't books in which the events of the past are pinned like so many butterflies to a cork. These are the books from which history in derived. There are more than twenty thousand of them, each one is ten feet high, bound in lead, and the letters are so small that they have to be read with a magnifying glass. When people say "It is written ..." it is written /here/. There are fewer metaphors than people think. Every month the abbot and two senior monks go into the cave where the books are kept. It used to be the duty of the abbot alone, but two other reliable monks were included after the unfortunate case of the 59th Abbot, who made a million dollars in small bets before his fellow monks caught up with him. Besides, it's dangerous to go in alone. The sheer concentratedness of History, sleeting past soundlessly out into the world, can be overwhelming. Time is a drug. Too much of it kills you. [Small Gods, by Terry Pratchett] %e passage # pp. 4-5 %passage 4 It was the Year of the Notional Serpent, or two hundred years after the Declaration of the Prophet Abbys. Which meant that the time of the 8th Prophet was imminent. That was the reliable thing about the Church of the Great God Om. It had very punctual prophets. You could set your calendar by them, if you had one big enough. And, as is generally the case around the time a prophet is expected, the Church redoubled its efforts to be holy. This was very much like the bustle you get in any large concern when the auditors are expected, but tended towards taking people suspected of being less holy and putting them to death in a hundred ingenious ways. This is considered a reliable barometer of the state of one's piety in most of the really popular religions. There's a tendency to declare that there is more backsliding around than in the national toboggan championships, that heresy must be torn out root and branch, and even arm and leg and eye and tongue, and that it's time to wipe the slate clean. Blood is generally considered very efficient for this purpose. [Small Gods, by Terry Pratchett] %e passage # p. 60 ("he" is a tortoise, unnoticed among a large crowd of people) %passage 5 He walked off slowly, keeping close to the wall to avoid the feet. He had no alternative to walking slowly in any case, but now he was walking slowly because he was thinking. Most gods find it hard to walk and think at the same time. [Small Gods, by Terry Pratchett] %e passage # p. 60 (same page as preceding passage) %passage 6 There were all sorts of ways to petition the Great God, but they depended largely on how much you could afford, which was right and proper and exactly how things should be. After all, those who had achieved success in the world clearly had done it with the approval of the Great God, because it was impossible to believe that they had managed it with His /disapproval/. In the same way, the Quisition could act without possibility of flaw. Suspicion was proof. How could it be anything else? The Great God would not have seen fit to put the suspicion in the minds of His exquisitors unless it was /right/ that it should be there. Life could be very simple, if you believed in the Great God Om. And sometimes quite short, too. [Small Gods, by Terry Pratchett] %e passage # p. 92 ([sic] first paragraph ought to have fourth '.' to end sentence) %passage 7 The memory stole over him: a desert is what you think it is. And now, you can think clearly ... There were no lies here. All fancies fled away. That's what happened in all deserts. It was just you, and what you believed. What have I always believed? That on the whole, and by and large, if a man lived properly, not according to what any priests said, but according to what seemed decent and honest /inside/, then it would, in the end, more or less, turn out all right. You couldn't get that on a banner. But the desert looked better already. [Small Gods, by Terry Pratchett] %e passage # p. 114 %passage 8 Vorbis had a cabin somewhere near the bilges, where the air was as thick as thin soup. Brutha knocked. "Enter."(1) (1) Words are the litmus paper of the mind. If you find yourself in the power of someone who will use the word "commence" in cold blood, go somewhere else very quickly. But if they say "Enter," don't stop to pack. [Small Gods, by Terry Pratchett] %e passage # p. 141 (at the end, Xeno is almost certainly agreeing with Ibid, but # he /might/ be answering Brutha's last question) %passage 9 "Are you all philosophers?" said Brutha. The one called Xeno stepped forward, adjusting the hang of his toga. "That's right," he said. "We're philosophers. We think, therefore we am." "Are," said the luckless paradox manufacturer automatically. Xeno spun around. "I've just about had it up to /here/ with you, Ibid!" he roared. He turned back to Brutha. "We /are/, therefore we am," he said confidently. "That's it." Several of the philosophers looked at one another with interest. "That's actually quite interesting," one said. "The evidence of our existence is the /fact/ of our existence, is that what you're saying?" "Shut up," said Xeno, without looking around. "Have you been fighting?" said Brutha. The assembled philosophers assumed various expressions of shock and horror. "Fighting? Us? We're /philosophers/," said Ibid, shocked. "My word, yes," said Xeno. [Small Gods, by Terry Pratchett] %e passage # p. 151 %passage 10 All over the world there were rulers with titles like the Exalted, the Supreme, and Lord High Something or Other. Only in one small country was the ruler elected by the people, who could remove him whenever they wanted--and they called him the Tyrant. The Ephebians believed that every man should have the vote.(1) Every five years someone was elected to be Tyrant, provided he could prove that he was honest, intelligent, sensible, and trustworthy. Immediately after he was elected, of course, it was obvious to everyone that he was a criminal madman and totally out of touch with the view of the ordinary philosopher in the street looking for a towel. And then five years later they elected another one just like him, and really it was amazing how intelligent people kept on making the same mistakes. (1) Provided that we wasn't poor, foreign, nor disqualified by reason of being mad, frivolous, or a woman. [Small Gods, by Terry Pratchett] %e passage # p. 239 %passage 11 "I still don't see how one god can be a hundred different thunder gods. They all look different ..." "False noses." "What?" "And different voices. I happen to know Io's got seventy different hammers. Not common knowledge, that. And it's just the same with mother goddesses. There's only one of 'em. She just got a lot of wigs and of course it's amazing what you can do with a padded bra." [Small Gods, by Terry Pratchett] %e passage # p. 265 %passage 12 An hour later the lion, who was limping after Brutha, also arrived at the grave. It had lived in the desert for sixteen years, and the reason it had lived so long was that it had not died, and it had not died because it never wasted handy protein. It dug. Humans have always wasted handy protein ever since they started wondering who had lived in it. But, on the whole, there are worse places to be buried than inside a lion. [Small Gods, by Terry Pratchett] %e passage %e title # # # %title Lords and Ladies (12) # p. 122 (Harper Torch edition) %passage 1 Elves are wonderful. They provoke wonder. Elves are marvellous. They cause marvels. Elves are fantastic. They create fantasies. Elves are glamorous. They project glamour. Elves are enchanting. They weave enchantment. Elves are terrific. They beget terror. The thing about words is that meanings can twist just like a snake, and if you want to find snakes look for them behind words that have changed their meaning. No one ever said elves are nice. Elves are bad. [Lords and Ladies, by Terry Pratchett] %e passage # p. 32 %passage 2 "Hope she does all right as queen," said Nanny. "We taught her everything she knows," said Granny Weatherwax. "Yeah," said Nanny Ogg, as they disappeared into the bracken. "D'you think... maybe... ?" "What?" "D'you think maybe we ought to have taught her everything /we/ know?" [Lords and Ladies, by Terry Pratchett] %e passage # p. 36 %passage 3 It was very hard, being a reader in Invisible Writings.(1) (1) The study of invisible writings was a new discipline made available by the discovery of the bi-directional nature of Library-Space. The thaumic mathematics are complex, but boil down to the fact that all books, everywhere, affect all other books. This is obvious: books inspire other books written in the future, and cite books written in the past. But the General Theory(2) of L-Space suggests that, in that case, the contents of books /as yet unwritten/ can be deduced from books now in existence. (2) There's a Special Theory as well, but no one bothers with it much because it's self-evidently a load of marsh gas. [Lords and Ladies, by Terry Pratchett] %e passage # p. 51 %passage 4 "Don't hold with schools," said Granny Weatherwax. "They get in the way of education. All them books. Books? What good are they? There's too much reading these days. We never had time to read when we was young, I know that." [Lords and Ladies, by Terry Pratchett] %e passage # pp. 79-80 %passage 5 The highwayman stepped over the groaning body of the driver and marched toward the door of the coach, dragging his stepladder behind him. He opened the door. "Your money or, I'm sorry to say, your--" A blast of octarine fire blew his hat off. The dwarf's expression did not change. "I wonder if I might be allowed to rephrase my demands?" Ridcully looked the elegantly dressed stranger up and down, or rather down and further down. "You don't look like a dwarf," he said, "apart from the height, that is." "Don't look like a dwarf apart from the height?" I mean, the helmet and iron boots department is among those you are lacking in," said Ridcully. [Lords and Ladies, by Terry Pratchett] %e passage # p. 95 %passage 6 What is magic? There is the wizards' explanation, which comes in two forms, depending on the age of the wizard. Older wizards talk about candles, circles, planets, stars, bananas, chants, runes, and the importance of having at least four good meals every day. Younger wizards, particularly the pale ones who spend most of their time in the High Energy Magic building,(1) chatter at length about fluxes in the morphic nature of the universe, the essentially impermanent quality of even the most apparently rigid time-space framework, the impossibility of reality, and so on: what this means is that they have got hold of something hot and are gabbling the physics as they go along. (1) It was here that the thaum, hitherto believed to be the smallest possible particle of magic, was successfully demonstrated to made up of /resons/(2) or reality fragments. Currently research indicates that each reson is itself made up of a combination of at least five "flavors," known as "up," "down," "sideways," "sex appeal," and "peppermint." (2) Lit: "Thing-ies." [Lords and Ladies, by Terry Pratchett] %e passage # p. 107 %passage 7 What is magic? Then there is the witches' explanation, which comes in two forms, depending on the age of the witch. Older witches hardly put words to it at all, but may suspect in their hearts that the universe really doesn't know what the hell is going on and consists of a zillion trillion billion possibilities, and could become any of them if a trained mind rigid with quantum certainty was inserted in the crack and /twisted/; that, if you really had to make someone's hat explode, all you needed to do was /twist/ into the universe where a large number of hat molecules all decide at the same time to bounce off in different directions. Younger witches, on the other hand, talk about it all the time and believe it involves crystals, mystic forces, and dancing about without yer drawers on. Everyone may to right, all at the same time. That's the thing about quantum. [Lords and Ladies, by Terry Pratchett] %e passage # p. 114; 'colorful' & 'humor' are spelled the American way, 'or' not 'our' %passage 8 He knocked on the coach door. The window slid down. "I wouldn't like you to think of this as a robbery," he said. "I'd like you to think of it more as a colorful anecdote you might enjoy telling your grandchildren about." A voice from within said, "That's him! He stole my horse!" A wizard's staff poked out. The chieftain saw the knob on the end. "Now then," he said pleasantly. "I know the rules. Wizards aren't allowed to use magic against civilians except in genuine life-threatening situa--" There was a burst of octarine light. "Actually, it's not a rule," said Ridcully. "It's more a guideline." He turned to Ponder Stibbons. "Interestin' use of Stacklady's Morphic Resonator here, I hoped you noticed." Ponder lookd down. The chieftain had been turned into a pumpkin, although, in accordance with the rules of universal humor, he still had his hat on. [Lords and Ladies, by Terry Pratchett] %e passage # p. 149 (second half of a paragraph) %passage 9 Things had to balance. You couldn't set out to be a good witch or a bad witch. It never worked for long. All you could try to be was a /witch/, as hard as you could. [Lords and Ladies, by Terry Pratchett] %e passage # p. 162 (mid-paragraph) %passage 10 "I'm the head wizard now. I've only got to give an order and a thousand wizards will... uh... disobey, come to think of it, or say 'What?', or start to argue. But they have to take notice. "I've been to that University a few times," said Granny. "A bunch of fat old men in beards." "That's right! That's /them/!" [Lords and Ladies, by Terry Pratchett] %e passage # p. 190 %passage 11 The window was no escape this time. There was the bed to hide under, and that'd work for all of two seconds, wouldn't it? Her eye was drawn by some kind of horrible magic back to the room's garderobe, lurking behind its curtain. Margrat lifted the lid. The shaft was definitely wide enough to admit a body. Garderobes were notorious in that respect. Several unpopular kings met their end, as it were, in the garderobe, at the hands of an assassin with good climbing ability, a spear, and a fundamental approach to politics. [Lords and Ladies, by Terry Pratchett] %e passage # p. 191 ('a' historian, not 'an'; 'Ynci' is correct) %passage 12 Some shape, some trick of moonlight, some expression on a painted face somehow cut through her terror and caught her eye. That was a portrait she'd never seen before. She'd never walked down this far. The idiot vapidity of the assembled queens had depressed her. But this one... Ths one, somehow, reached out to her. She stopped. It couldn't have been done from life. In the days of /this/ queen, the only paint known locally was a sort of blue, and generally used on the body. But a few generations ago King Lully I had been a bit of a historian and a romantic. He'd researched what was known of the early days of Lancre, and where actual evidence had been a bit sparse he had, in the best traditions of the keen ethnic historian, inferred from revealed self-evident wisdom(1) and extrapolated from associated sources(2). He'd commissioned the portrait of Queen Ynci the Short-Tempered, one of the founders of the kingdom. (1) Made it up. (2) Had read a lot of stuff that other people had made up, too. [Lords and Ladies, by Terry Pratchett] %e passage %e title # # # %title Men at Arms (14) %passage 1 The maze was so small that people got lost looking for it. [Men at Arms, by Terry Pratchett] %e passage # pp. 6-7 (Harper Torch edition) %passage 2 Ankh-Morpork had a king again. And this was /right/. And it was /fate/ that let Edward recognize this /just/ when he'd got his Plan. And it was /right/ that it was /Fate/, and the city would be /Saved/ from its ignoble present by its /glorius/ past. He had the /Means/, and he had the /end/. And so on ... Edward's thoughts often ran like this. He could think in /italics/. Such people need watching. Preferably from a safe distance. [Men at Arms, by Terry Pratchett] %e passage # pp. 76-77 %passage 3 There were such things as dwarf gods. Dwarfs were not a naturally religious species, but in a world where pit props could crack without warning and pockets of fire damp could suddenly explode they'd seen the need for gods as the sort of supernatural equivalent of a hard hat. Besides, when you hit your thumb with an eight-pound hammer it's nice to be able to blaspheme. It takes a very special and strong-minded kind of atheist to jump up and down with their hand clasped under their other armpit and shout, "Oh, random fluctuations-in-the-space-time- continuum!" or "Aaargh, primitive-and-outmoded-concept on a crutch!" [Men at Arms, by Terry Pratchett] %e passage # p. 119 (perhaps a bit subtle; it would be clearer if 'they' was italicized) %passage 4 "It's an ancient tradition," said Carrot. "I thought dwarfs didn't believe in devils and demons and stuff like that." "That's true, but ... we're not sure if they know." "Oh." [Men at Arms, by Terry Pratchett] %e passage # pp. 168-169 (treacle == molasses) %passage 5 "I'd like a couple of eggs," said Vimes, "with the yolks real hard but the whites so runny that they drip like treacle. And I want bacon, that special bacon all covered with bony nodules and dangling bits of fat. And a slice of fried bread. The kind that makes your arteries go clang just by looking at it." "Tough order," said Harga. "You managed it yesterday. And give me some more coffee. Black as midnight on a moonless night." Harga looked surprised. That wasn't like Vimes. "How black's that, then?" he said. "Oh pretty damn black, I should think." "Not necessarily." "What?" "You get more stars on a moonless night. Stands to reason. They show up more. It can be quite bright on a moonless night." Vimes sighed. "An /overcast/ moonless night?" he said. Harga looked carefully at his coffee pot. "Cumulous or cirro-nimbus?" "I'm sorry. What did you say?" "You gets city lights reflected off cumulous, because it's low lying, see. Mind you, you can get high-altitude scatter off the ice crystals in--" "A moonless night," said Vimes, in a hollow voice, "that is as black as that coffee." "Right!" "And a doughnut." Vimes grabbed Harga's stained vest and pulled him until they were nose to nose. "A doughnut as doughnutty as a doughnut made of flour, water, one large egg, sugar, a pinch of yeast, cinnamon to taste and a jam, jelly, or rat filling depending on national or species preference, OK? Not as doughnutty as something in any way metaphorical. Just a doughnut. One doughnut." "A doughnut." "Yes." "You only had to say." Harge brushed off his vest, gave Vimes a hurt look, and went back into the kitchen. [Men at Arms, by Terry Pratchett] %e passage # p. 174 (clumsy wording; 'they' in 2nd sentence != 'they' in 1st sentence) %passage 6 Why had they chased someone halfway across the city? Because they'd run away. /No one/ ran away from the Watch. Thieves just flashed their licenses. Unlicensed thieves had nothing to fear from the Watch, since they'd saved up all their fear for the Thieves' Guild. Assassins always obeyed the letter of the law. And honest men didn't run away from the Watch.(1) Running away from the Watch was downright suspicious. (1) The axiom "Honest men have nothing to fear from the police" is currently under review by the Axioms Appeal Board. [Men at Arms, by Terry Pratchett] %e passage # pp. 176-177 ("this [sic; no 'is'] the pork futures warehouse") %passage 7 "Oh, my," said Detritus. "I think this the pork futures warehouse in Morpork Road." "What?" "Used to work here," said the troll. "Used to work everywhere. Go away, you stupid troll, you too thick," he added, gloomily. "Is there any way out?" "The main door is in Morpork Street. But no one comes in here for months. Till pork exists."(1) Cuddy shivered. (1) Probably no other world in the multiverse has warehouses for things which only exist /in potentia/, but the pork futures warehouse in Ankh- Morpork is a product of the Patrician's rules about baseless metaphors, the literal-mindedness of citizens who assume that everything must exist somewhere, and the general thinness of the fabric of reality around Ankh, which is so thin that it's as thin as a very thin thing. The net result is that trading in pork futures--in pork /that doesn't exist yet/--led to the building of the warehouse to store it until it does. The extremely low temperatures are caused by the imbalance in the temporal energy flow. At least, that's what the wizards in the High Energy Magic building say. And they've got proper pointy hats and letters after their name, so they know what they're talking about. [Men at Arms, by Terry Pratchett] %e passage # p. 212 %passage 8 Black mud, more or less dry, made a path at the bottom of the tunnel. There was slime on the walls, too, indicating that at some point in the recent past the tunnel had been full of water. Here and there huge patches of fungi, luminous with decay, cast a faint glow over the ancient stonework.(1) (1) It didn't need to. Cuddy, belonging to a race that worked underground for preference, and Detritus, a member of a race notoriously nocturnal, had excellent vision in the dark. But mysterious caves and tunnels always have luminous fungi, strangely bright crystals or at a pinch merely an eldritch glow in the air, just in case a human hero comes in and needs to see in the dark. Strange but true. [Men at Arms, by Terry Pratchett] %e passage # p. 218 %passage 9 "He's bound to have done /something/," Noddy repeated. In this he was echoing the Patrician's view of crime and punishment. If there was a crime, there should be punishment. If the specific criminal should be involved in the punishment process then this was a happy accident, but if not then any criminal would do, and since everyone was undoubtedly guilty of something, the net result was that, /in general terms/, justice was done. [Men at Arms, by Terry Pratchett] %e passage # p. 226 %passage 10 The librarian considered matters for a while. So ... a dwarf and a troll. He preferred both species to humans. For one thing, neither of them were great readers. The Librarian was, of course, very much in favor of reading in general, but readers in particular got on his nerves. There was something, well, /sacrilegious/ about the way they kept taking books off the shelves and wearing out the words by reading them. He liked people who loved and respected books, and the best way to do that, in the Librarian's opinion, was to leave them on the shelves where Nature intended them to be. [Men at Arms, by Terry Pratchett] %e passage # p. 253 %passage 11 Sometimes it's better to light a flamethrower than curse the darkness. [Men at Arms, by Terry Pratchett] %e passage # p. 265 (fyi, they're decorated chicken eggs) %passage 12 "All those little heads ... " They stretched away in the candlelight, shelf on shelf of them, tiny little clown faces--as if a tribe of headhunters had suddenly developed a sophisicated sense of humor and a desire to make the world a better place. [Men at Arms, by Terry Pratchett] %e passage # pp. 300-301 %passage 13 "You know what I mean!" "Can't say I do. Can't say I do. Clothing has never been what you might call a thingy of dog wossname." Gaspode scratched his ear. "Two meta- syntactic variables there. Sorry." [Men at Arms, by Terry Pratchett] %e passage # p. 320 %passage 14 "Hahaha, a nice day for it!" leered the Bursar. "Oh dear," said Ridcully, "he's off again. Can't understand the man. Anyone got the dried frog pills?" It was a complete mystery to Mustrum Ridcully, a man designed by nature to live outdoors and happily slaughter anything that coughed in the bushes, why the Bursar (a man designed by Nature to sit in a small room somewhere, adding up figures) was so nervous. He'd tried all sorts of things to, as he put it, buck him up. These included practical jokes, surprise early morning runs, and leaping out at him from behind doors while wearing Willie the Vampire masks in order, he said, to take him out of himself. [Men at Arms, by Terry Pratchett] %e passage %e title # # # %title Soul Music (11) %passage 1 But this didn't feel like magic. It felt a lot older than that. It felt like music. [Soul Music, by Terry Pratchett] %e passage %passage 2 "Yes," said the skull. "Quit while you're a head, that's what I say." [Soul Music, by Terry Pratchett] %e passage # p.2 (Harper Torch edition) %passage 3 But if it is true that the act of observing changes the thing which is observed,(1) it's even more true that it changes the observer. (1) Because of Quantum. [Soul Music, by Terry Pratchett] %e passage # p.8 %passage 4 It is said that whomsoever the gods wish to destroy, they first make mad. In fact, whomsoever the gods wish to destroy, they first hand the equivalent of a stick with a fizzing fuse and Acme Dynamite Company written on the side. It's more interesting, and doesn't take so long. [Soul Music, by Terry Pratchett] %e passage # pp. 63-64 %passage 5 Then the skull said: "Kids today, eh?" "I blame education," said the raven. "A lot of knowledge is a dangerous thing," said the skull. "A lot more dangerous than just a little. I always used to say that, when I was alive." "When was that, exactly?" "Can't remember. I think I was pretty knowledgeable. Probably a teacher or philosopher, something of that kidney. And now I'm on a bench with a bird crapping on my head." "Very allegorical," said the raven. [Soul Music, by Terry Pratchett] %e passage # p. 87 (Stabbing: "in the" both capitalized; "and" not so) %passage 6 The Mended Drum had traditionally gone in for, well, traditional pub games, such as dominoes, darts, and Stabbing People In The Back and Taking All Their Money. The new owner had decided to go up-market. This was the only available direction. [Soul Music, by Terry Pratchett] %e passage # pp. 125-126 ("him"==Librarian; # Leonard of Quirm==Discworld analog of Leonardo da Vinci) %passage 7 The Library didn't only contain magical books, the ones which are chained to their shelves and are very dangerous. It also contained perfectly ordinary books, printed on commonplace paper in mundane ink. It would be a mistake to think that they weren't also dangerous, just because reading them didn't make fireworks go off in the sky. Reading them sometimes did the more dangerous trick of making fireworks go off in the privacy of the reader's brain. For example, the big volume open in front of him contained some of the collected drawings of Leonard of Quirm, skilled artist and certified genious, with a mind that wandered so much it came back with souvenirs. Leonard's books were full of sketches--of kittens, of the way water flows, of the wives of influential Ankh-Morporkian merchants whose portraits had provided his means of making a living. But Leonard had been a genius and was deeply sensitive to the wonders of the world, so the margins were full of detailed doodles of whatever was on this mind at the moment--vast water-powered engines for bringing down city walls on the heads of the enemy, new types of siege guns for pumping flaming oil over the enemy, gunpowder rockets that showered the enemy with burning phosphorous, and other manufactures of the Age of Reason. And there had been something else. The Librarian had noticed it in passing once before, and had been slightly puzzled by it. It seemed out of place.(1) (1) And didn't appear to do anything to the enemy /at all/. [Soul Music, by Terry Pratchett] %e passage # p. 152 (much of the story concerns "Music With Rocks In") %passage 8 Some religions say that the universe was started with a word, a song, a dance, a piece of music. The Listening Monks of the Ramtops have trained their hearing until they can tell the value of a playing card by listening to it, and have made it their task to listen intently to the subtle sounds of the universe to piece together, from the fossile echoes, the very first noises. There was certainly, they say, a very strange noise at the beginning of everything. But the keenest ears (the ones who win most at poker), who listen to the frozen echoes in the ammonites and amber, swear they can detect some tiny sounds before that. It sounded, they say, like someone counting: One, Two, Three, Four. The very best one, who listened to basalt, said he thought he could make out, very faintly, some numbers that came even earlier. When they asked him what it was, he said: "It sounds like One, Two." [Soul Music, by Terry Pratchett] %e passage # p. 227 %passage 9 The Death of Rats put his nose in his paws. It was a lot easier with rats.(1) (1) Rats had featured largely in the history of Ankh-Morpork. Shortly before the Patrician came to power there was a terrible plague of rats. The city council countered it by offering twenty pence for every rat tail. This did, for a week or two, reduce the number of rats--and then people were suddenly queueing up with tails, the city treasury was being drained, and no one seemed to be doing much work. And there /still/ seemed to be a lot of rats around. Lord Vetinari had listened carefully while the problem was explained, and had solved the thing with one memorable phrase which said a lot about him, about the folly of bounty offers, and about the natural instinct of Ankh-Morporkians in any situtation involving money: "Tax the rat farms." [Soul Music, by Terry Pratchett] %e passage # pp. 313-314 (Drongo and Big Mad Adrian are students) %passage 10 The Archchancellor polished this staff as he walked along. It was a particularly good one, six feet long and quite magical. Not that he used magic very much. In his experience, anything that couldn't be disposed of with a couple of whacks from six feet of oak was probably immune to magic as well. "Don't you think we should have brought the senior wizards, sir?" said Ponder, struggling to keep up. "I'm afraid that taking them along in their present state of mind would only make what happens"--Ridcully sought for a useful phrase, and settled for--"happen worse. I've insisted they stay in college." "How about Drongo and the others?" said Ponder hopefully. "Would they be any good in the event of a thaumaturgical dimension rip of enormous proportions?" said Ridcully. "I remember poor Mr. Hong. One minute he was dishing up an order of double cod and mushy peas, the next ..." "Kaboom?" said Ponder. "Kaboom?" said Ridcully, forcing his way up the crowded street. "Not that I heard tell. More like 'Aaaaerrrr-scream-gristle- gristle-gristle- crack' and a shower of fried food. Big Mad Adrian and his friends any good when the chips are down?" "Um. Probably not, Archchancellor." "Correct. People shout and run about. That never did any good. A pocket full of decent spells and a well-charged staff will get you out of trouble nine times out of ten." "Nine times out of ten?" "Correct." "How many times have you had to rely on them, sir?" "Well ... there was Mr. Hong ... that business with the thing in the Bursar's wardrobe ... that dragon, you remember ..." Ridcully's lips moved silently as he counted on his fingers. "Nine times, so far." "It worked every time, sir?" "Absolutely! So there's no need to worry. Gangway! Wizard comin' through." [Soul Music, by Terry Pratchett] %e passage # p. 339 %passage 11 The wizards went rigid as the howl rang through the building. It was slightly animal but also mineral, metallic, edged like a saw. Eventually the Lecturer in Recent Runes said, "Of course, just because we've heard a spine-chilling blood-curdling scream of the sort to make your very marrow freeze in your bones doesn't automatically mean there's anything wrong." The wizards looked out into the corridor. "It came from downstairs somewhere," said the Chair of Indefinite Studies, heading for the staircase. "So why are you going /upstairs/?" "Because I'm not daft!" "But it might be some terrible emanation!" "You don't say?" said the Chair, still accelerating. "All right, please yourself. That's the students floor up there." "Ah, Er--" The Chair came down slowly, occasionally glancing fearfully up the stairs. [Soul Music, by Terry Pratchett] %e passage %e title # # # %title Interesting Times (10) # p.1 (footnote) %passage 1 Whatever happens, they say afterwards, it must have been fate. People are always a little confused about this, as they are in the case of miracles. When someone is saved from certain death by a strange concatenation of circumstances, they say that's a miracle. But of course if someone is killed by a freak chain of events--the oil spilled just there, the safety fence broken just there--that must also be a miracle. Just because it's not nice doesn't mean it's not miraculous. [Interesting Times, by Terry Pratchett] %e passage # p. 18 %passage 2 "Oh, no," said the Lecturer in Recent Runes, pushing his chair back. "Not that. That's meddling with things you don't understand." "Well, we /are/ wizards," said Ridcully. "We're supposed to meddle with things we don't understand. If we hung around waitin' till we understood things we'd never get anything done." [Interesting Times, by Terry Pratchett] %e passage # p. 4 %passage 3 According to the philosopher Ly Tin Wheedle, chaos is found in greatest abundance wherever order is being sought. It always defeats order, because it is better organized. [Interesting Times, by Terry Pratchett] %e passage # p. 14 %passage 4 Many things went on at Unseen University and, regretably, teaching had to be one of them. The faculty had long ago confronted this fact and had perfected various devices for avoiding it. But this was perfectly all right because, to be fair, so had the students. The system worked quite well and, as happens in such cases, had taken on the status of a tradition. Lectures clearly took place, because they were down there on the timetable in black and white. The fact that no one attended was an irrelevant detail. It was occasionally maintained that this meant that the lectures did not in fact happen at all, but no one ever attended them to find out if this was true. Anyway, it was argued (by the Reader in Woolly Thinking(1)) that lectures had taken place /in essence/, so that was all right, too. And therefore education at the University mostly worked by the age-old method of putting a lot of young people in the vicinty of a lot of books and hoping that something would pass from one to the other, while the actual young people put themselves in the vicinity of inns and taverns for exactly the same reason. (1) Which is like Fuzzy Logic, only less so. [Interesting Times, by Terry Pratchett] %e passage # p. 20 (speaker is Archchancellor Ridcully; sad, hopless person is Rincewind) %passage 5 "Wizzard?" he said. "What kind of sad, hopeless person needs to write WIZZARD on their hat?" [Interesting Times, by Terry Pratchett] %e passage # p. 113 %passage 6 Self-doubt was something not regularly entertained within the Cohen cranium. When you're trying to carry a struggling temple maiden and a sack of looted temple goods in one hand and fight off half a dozen angry priests with the other there is little time for reflection. Natural selection saw to it that professional heroes who at a crucial moment tended to ask themselves questions like "What is the purpose of life?" very quickly lacked both. [Interesting Times, by Terry Pratchett] %e passage # p. 113 (same page as previous passage...) %passage 7 Cohen's father had taken him to a mountain top, when he was no more than a lad, and explained to him the hero's creed and told him that there was no greater joy than to die in battle. Cohen had seen the flaw in this straight away, and a lifetime's experience had reinforced his belief that in fact a greater joy was to kill the /other/ bugger in battle and end up sitting on a heap of gold higher than your horse. It was an observation that had served him well. [Interesting Times, by Terry Pratchett] %e passage # p. 144 %passage 8 "'Dang'?" he said. "Wassat mean? And what's this 'darn' and 'heck'?" "They are ... /civilised/ swearwords." said Mr. Saveloy. "Well, you can take 'em and--" "Ah?" said Mr. Saveloy, raising a cautionary finger. "You can shove them up--" "Ah?" "You can--" "Ah?" Truckle shut his eyes and clenched his fists. "Darn it all to heck!" he shouted. "Good," said Mr. Saveloy. "That's much better." [Interesting Times, by Terry Pratchett] %e passage # p. 219 (sic: "Dedd") %passage 9 The taxman was warming to his new job. He'd worked out that although the Horde, as individuals, had acquired mountains of cash in their careers as barbarian heroes they'd lost almost all of it engaging in the other activities (he mentally catalogued these as Public Relations) necessary to the profession, and therefore were entitled to quite a considerable rebate. The fact that they were registered with no revenue collecting authority /anywhere/(1) was entirely a secondary point. It was the principle that counted. And the interest, too, of course. (1) Except on posters with legends like "Wanted--Dedd". [Interesting Times, by Terry Pratchett] %e passage # p. 297 %passage 10 "What do we do now?" said Mr. Saveloy. "Do we do a battle chant or something?" "We just wait," said Cohen. "There's a lot of waiting in warfare," said Boy Willie. "Ah, yes," said Mr. Saveloy. "I've heard people say that. They say there's long periods of boredom followed by short periods of excitement." "Not really," said Cohen. "It's more like short periods of waiting followed by long periods of being dead." [Interesting Times, by Terry Pratchett] %e passage %e title # # # %title Maskerade (9) # pp. 81-82, continued on pp. 87-89 (Harper Torch edition; apparently # transcribed from some other edition based on quote marks used; # a great number of very short paragraphs--it stretches a long way # when using a blank line to separate one paragraph from another; # one omitted bit is that after Granny shuffles the deck of cards # and deals two poker hands, Death swaps them, suggesting that # he suspected her of cheating; initial transcription left off # the most interesting bit, Death's wink at the end) %passage 1 'Maybe you could ... help us?' 'What's wrong?' 'It's my boy ...' Granny opened the door farther and saw the woman standing behind Mr. Slot. One look at her face was enough. There was a bundle in her arms. Granny stepped back. 'Bring him in and let me have a look at him.' She took the baby from the woman, sat down on the room's one chair, and pulled back the blanket. Nanny Ogg peered over her shoulder. 'Hmm,' said Granny, after a while. She glanced at Nanny, who gave an almost imperceptible shake of her head. 'There's a curse on this house, that's what it is,' said Slot. 'My best cow's been taken mortally sick, too.' 'Oh? You have a cowshed?' said Granny. 'Very good place for a sickroom, a cowshed. It's the warmth. You better show me where it is.' 'You want to take the boy down there?' 'Right now.' [...] 'How many have you come for?' ONE. 'The cow?' Death shook his head. 'It could /be/ the cow.' NO. THAT WOULD BE CHANGING HISTORY. 'History is about things changing.' NO. Granny sat back. 'Then I challenge you to a game. That's traditional. That's /allowed/.' Death was silent for a moment. THIS IS TRUE. 'Good.' CHALLENGING ME BY MEANS OF A GAME IS ALLOWABLE. "Yes." HOWEVER ... YOU UNDERSTAND THAT TO WIN ALL YOU MUST GAMBLE ALL? 'Double or quits? Yes, I know.' BUT NOT CHESS. 'Can't abide chess.' OR CRIPPLE MR. ONION. I'VE NEVER BEEN ABLE TO UNDERSTAND THE RULES. 'Very well. How about one hand of poker? Five cards each, no draws? Sudden death, as they say.' Death thought about this, too. YOU KNOW THIS FAMILY? 'No.' THEN WHY? 'Are we talking or are we playing?' OH, VERY WELL. [...] Granny looked at her cards, and threw them down. FOUR QUEENS. HMM. THAT /IS/ VERY HIGH. Death looked down at his cards, and then up into Granny's steady, blue-eyed gaze. Neither moved for some time. Then Death laid the hand on the table. I LOSE, he said. ALL I HAVE IS FOUR ONES. He looked back into Granny's eyes for a moment. There was a blue glow in the depth of his eye-sockets. Maybe, for the merest fraction of a second, barely noticeable even to the closest observation, one winked off. [Maskerade, by Terry Pratchett] %e passage # p. 67 (Harper Torch edition; as above, transcribed from some other edition) %passage 2 The letter inside was on a sheet of the Opera House's own note paper. In neat, copperplate writing, it said: Ahahahahaha! Ahahahaha! Aahahaha! BEWARE!!!!! Yrs sincerely The Opera Ghost 'What sort of person,' said Salzella patiently, 'sits down and /writes/ a maniacal laugh? And all those exclamation marks, you notice? Five? A sure sign of someone who wears his underpants on his head. Opera can do that to a man.' [Maskerade, by Terry Pratchett] %e passage # pp. 30-31 (Harper Torch edition) %passage 3 Agnes had woken up one morning with the horrible realization that she'd been saddled with a lovely personality. It was as simple as that. Oh, and very good hair. It wasn't so much the personality, it was the "but" people always added when they talked about it. /But she's got a lovely personality/, they said. It was the lack of choice that rankled. No one had asked her, before she was born, whether she wanted a lovely personality or whether she'd prefer, say, a miserable personality but a body that could take size nine in dresses. Instead, people would take pains to tell her that beauty was only skin-deep, as if a man ever fell for an attractive pair of kidneys. [Maskerade, by Terry Pratchett] %e passage # p. 258 %passage 4 'And what can I get you, officers?' she said. 'Officers? Us?' said the Count de Nobbes. 'What makes you think we're watchmen?' 'He's got a helmet on,' Nanny pointed out. 'Also, he's got his badge pinned to his coat.' 'I /told/ you to put it away!' Nobby hissed. He looked at Nanny and smiled uneasily. 'Milit'ry chic,' he said. 'It's just a fashion accessory. Actually, we are gentlemen of means and have nothing to do with the city Watch whatsoever.' 'Well, /gentlemen/, would you like some wine?' 'Not while we on duty, t'anks,' said the troll. [Maskerade, by Terry Pratchett] %e passage # p. 27 (Harper Torch edition) %passage 5 Lancre had always bred strong, capable women. A Lancre farmer needed a wife who'd think nothing of beating a wolf to death with her apron when she went out to get some firewood. And, while kissing initially seemed to have more charms than cookery, a stolid Lancre lad looking for a bride would bear in mind his father's advice that kisses eventually lost their fire but cookery tended to get even better over the years, and direct his courting to those families that clearly showed a tradition of enjoying their food. [Maskerade, by Terry Pratchett] %e passage # p. 28 %passage 6 Music and magic had a lot in common. They were only two letters apart, for one thing. And you couldn't do both. [Maskerade, by Terry Pratchett] %e passage # p. 31 %passage 7 She'd caught herself saying "poot!" and "dang!" when she wanted to swear, and using pink writing paper. She'd got a reputation for being calm and capable in a crisis. Next thing she knew she'd be making shortbread and apple pies as good as her mother's, and then there'd be no hope for her. So she'd introduced Perdita. She'd heard somewhere that inside every fat woman was a thin woman trying to get out,(1) so she'd named her Perdita. She was a good repository for all those thoughts that Agnes couldn't think on account of her wonderful personality. Perdita would use black writing paper if she could get away with it, and would be beautifully pale instead of embarassingly flushed. Perdita wanted to be an interestingly lost soul in plum-colored lipstick. Just occasionally, though, Agnes thought Perdita was as dumb as she was. (1) Or, at least, dying for chocolate. [Maskerade, by Terry Pratchett] %e passage # p. 197 (dress shop proprietor has just sold an expensive dress to Granny) %passage 8 She looked down at the money in her hand. She knew about old money, which was somehow hallowed by the fact that people had hung on to it for years, and she knew about new money, which seemed to be being made by all these upstarts that were flooding into the city these days. But under her powdered bosom she was an Ankh-Morpork shopkeeper, and knew that the best kind of money was the sort that was in her hand rather than someone else's. The best kind of money was mine, not yours. Besides, she was also enough of a snob to confuse rudeness with good breeding. In the same way that the really rich can never be mad (they're eccentric), so they can also never be rude (they're outspoken and forthright). [Maskerade, by Terry Pratchett] %e passage # pp. 288-289 %passage 9 Detritus reached down and picked up an eye patch. "What d'you think, then?" said Nobby scornfully. "You think he turned into a bat and flew away?" "Ha! I do not t'ink that 'cos it is in ... consist ... ent with modern policing," said Detritus. "Well, /I/ think," said Nobby, "that when you have ruled out the impossible, what is left, however improbable, ain't worth hanging around on a cold night wonderin' about when you could be getting on the outside of a big drink. Come on. I want to try a leg of the elephant that bit me." "Was dat irony?" "That was metaphor." [Maskerade, by Terry Pratchett] %e passage %e title # # # %title Feet of Clay (14) %passage 1 Rumour is information distilled so finely that it can filter through anything. It does not need doors and windows -- sometimes it does not need people. It can exist free and wild, running from ear to ear without ever touching lips. [Feet of Clay, by Terry Pratchett] %e passage # p. 337 (Harper Torch edition) %passage 2 It was hard enough to kill a vampire. You could stake them down and turn them into dust and ten years later someone drops a drop of blood in the wrong place and /guess who's back/? They returned more times than raw broccoli. [Feet of Clay, by Terry Pratchett] %e passage # p. 4 %passage 3 People look down on stuff like geography and meteorology, and not only because they're standing on one and being soaked by the other. They don't look quite like real science.(1) But geography is only physics slowed down and with a few trees stuck on it, and meteorology is full of excitingly fashionable chaos and complexity. And summer isn't a time. It's a place as well. Summer is a moving creature and likes to go south for the winter. (1) That is to say, the sort you can use to give something three extra legs and then blow it up. [Feet of Clay, by Terry Pratchett] %e passage # p. 19 %passage 4 Upstairs, Vimes pushed open his office door carefully. The Assassins' Guild played to rules. You could say that about the bastards. It was terribly bad form to kill a bystander. Apart from anything else, you wouldn't get paid. So traps in his office were out of the question, because too many people were in and out of it every day. Even so, it paid to be careful. Vimes /was/ good at making the kind of rich enemies who could afford to employ assassins. The assassins had to be lucky only once, but Vimes had to be lucky all the time. [Feet of Clay, by Terry Pratchett] %e passage # p. 86 (passage continues, actually finding an image in dead man's eyes) %passage 5 "Er ... have you ever heard the story about dead men's eyes, sir?" "Assume I haven't had a literary education, Littlebottom." "Well ... they say ..." "/Who/ say?" "/They/, sir. You know, /they/." "The same people who're the 'everyone' in 'everyone knows'? The people who live in 'the community'?" "Yes, sir. I suppose so, sir." Vimes waved a hand. "Oh, /them/. Well, go on." "They say that the last thing a man sees stays imprinted in his eyes, sir." "Oh, /that/. That's just an old story." [Feet of Clay, by Terry Pratchett] %e passage # pp. 127-128 %passage 6 Everyone in the city looked after themselves. That's what the guilds were for. People banded together against other people. The guild looked after you from the cradle to the grave or, in the case of the Assassins, to other people's graves. They even maintained the law, or at least they had done, after a fashion. Thieving without a license was punishable by death for the first offense.(1) The Thieves' Guild saw to that. The arrangement sounded unreal, but it worked. It worked like a machine. That was fine except for the occasional people who got caught in the wheels. (1) The Ankh-Morpork view of crime and punishment was that the penalty for the first offence should prevent the possibility of a second offense. [Feet of Clay, by Terry Pratchett] %e passage # p. 129, continued pp. 132-133 %passage 7 Vimes struggled to his feet, shook his head, and set off after it. No thought was involved. It is the ancient instinct of terriers and policemen to chase anything that runs away. [...] Vimes pounded through the fog after the fleeing figure. It wasn't quite so fast as him, despite the twinges in his legs and one or two warning stabs from his left knee, but whenever he came close to it some muffled pedestrian got in the way, or a cart pulled out from a cross street.(1) (1) This always happens in any police chase /anywhere/. A heavily laden lorry will /always/ pull out of a side alley in front of the pursuit. If vehicles aren't involved, then it'll be a man with a rack of garments. Or two men with a large sheet of glass. There's probably some kind of secret society behind all this. [Feet of Clay, by Terry Pratchett] %e passage # p. 165 %passage 8 Ron had a small grayish-brown, torn-eared terrier on the end of a string, although in truth it would be hard for an observer to know exactly who was leading whom and who, when push came to shove, would be the one to fold at the knees if the other shouted "Sit!" Because, although trained canines as aids for those bereft of sight, and even of hearing, have frequently been used throughout the universe, Foul Ole Ron was the first person ever to own a Thinking-Brain Dog. [Feet of Clay, by Terry Pratchett] %e passage # pp. 173-174 %passage 9 Samuel Vimes dreamed about Clues. He had a jaundiced view of Clues. He instinctively distrusted them. They got in the way. And he distrusted the kind of person who'd take one look at another man and say in a lordly voice to his companion, "Ah, my dear sir. I can tell you nothing except that he is a left-handed stonemason who has spent some years in the merchant navy and has recently fallen on hard times," and then unroll a lot of supercilious commentary about calluses and stance and the state of a man's boots, when /exactly the same/ comments could apply to a man who was wearing his old clothes because he'd been doing a spot of home bricklaying for a new barbecue pit, and had been tatooed once when he was drunk and seventeen(1) and in fact got seasick on a wet pavement. What arrogance! What an insult to the rich and chaotic variety of the human experience. It was the same with more static evidence. The footprints in the flowerbed were probably /in the real world/ left by the window-cleaner. The scream in the night was quite likely a man getting out of bed and stepping sharply on an upturned hairbrush. The real world was far too /real/ to leave neat little hints. It was full of too many things. It wasn't by eliminating the impossible that you got at the truth, however improbable; it was by the much harder process of eliminating the possibilities. You worked away, patiently asking questions and looking hard at things. You walked and talked, and in your heart you just hoped like hell that some bugger's nerve'd crack and he'd give himself up. (1) These terms are often synonymous. [Feet of Clay, by Terry Pratchett] %e passage # p. 188 %passage 10 "Life has certainly been more reliable under Vetinari," said Mr. Potts of the Bakers' Guild. "He does have all the street-theater players and mime artists thrown into the scorpion pit," said Mr. Boggis of the Thieves' Guild. "True. But let's not forget that he has his bad points too. [...]" [Feet of Clay, by Terry Pratchett] %e passage # p. 198 %passage 11 What a mess the world was in, Vimes reflected. Constable Visit had told him the meek would inherit it, and what had the poor devils done to deserve /that/? [Feet of Clay, by Terry Pratchett] %e passage # p. 295 %passage 12 Rogers the bulls were angry and bewildered, which counts as the basic state of mind for full grown bulls.(1) (1) Because of the huge obtrusive mass of his forehead, Rogers the bulls' view of the universe was from two eyes each with their own non-overlapping hemispherical view of the world. Since there were two separate visions, Rogers had reasoned, that meant there must be two bulls (bulls not having been bred for much deductive reasoning). Most bulls believe this, which is why they always keep turning their head this way and that when they look at you. They do this because both of them want to see. [Feet of Clay, by Terry Pratchett] %e passage # p. 312 ('meaning' line capitalizes every word, including 'A','For','To') %passage 13 "It's the most menacing dwarf battle-cry there is! Once it's been shouted /someone/ has to be killed!" "What's it mean?" "Today Is A Good Day For Someone Else To Die!" [Feet of Clay, by Terry Pratchett] %e passage # p. 347 (Colon is addressing Dorfl, a golem who is joining the Watch) %passage 14 "Y'know," said Colon, "if it doesn't work out, you could always get a job making fortune cookies." "Funny thing, that," said Nobby. "You never get bad fortunes in cookies, ever noticed that? They never say stuff like: 'Oh dear, things are going to be /really/ bad.' I mean, they're never /misfortune/ cookies." Vimes lit a cigar and shook the match to put it out. "That, Corporal, is because of one of the fundamental driving forces of the universe." "What? Like, people who read fortune cookies are the lucky ones?" said Nobby. "No. Because people who /sell/ fortune cookies want to go on selling them. [...]" [Feet of Clay, by Terry Pratchett] %e passage %e title # # # %title Hogfather (10) # p. 1 (Harper Torch edition) %passage 1 Everything starts somewhere, though many physicists disagree. But people have always been dimly aware of the problem with the start of things. They wonder how the snowplow driver gets to work, or how the makers of dictionaries look up the spelling of words. Yet there is the constant desire to find some point in the twisting, knotting, raveling nets of space-time on which a metaphorical finger can be put to indicate that here, /here/, is the point where it all began ... /Something/ began when the Guild of Assassins enrolled Mister Teatime, who saw things differently from other people, and one of the ways that he saw things differently from other people was in seeing other people as things (later, Lord Downey of the Guild said, "We took pity on him because he'd lost both parents at an early age. I think that, on reflection, we should have wondered a bit more about that.") [Hogfather, by Terry Pratchett] %e passage # pp. 28-29 %passage 2 If asked to describe what they did for a living, the five men around the table would have said something like "This and that" or "The best I can," although in Banjo's case he'd probably have said "Dur?" They were, by the standards of an uncaring society, criminals, although they wouldn't have thought of themselves as such and couldn't even /spell/ words like "nefarious." What they generally did was move things around. Sometimes the things were on the wrong side of a steel door, or in the wrong house. Sometimes the things were in fact people who were far too unimportant to trouble the Assassins' Guild with, but who were nevertheless inconveniently positioned where they were and would be much better located on, for example, a sea bed somewhere.(1) None of the five belonged to any formal guild and they generally found their clients among those people who, for their own dark reasons, didn't want to put the guilds to any trouble, sometimes because they were guild members themselves. They had plenty of work. There was always something that needed transferring from A to B or, of course, to the bottom of the C. (1) Chickenwire had got his name from his own individual contribution to the science of this very specialized "concrete overshoe" form of waste disposal. An unfortunate drawback of the process was the tendency for bits of the client to eventually detach and float to the surface, causing much comment among the general poplation. Enough chicken wire, he pointed out, would solve that, while also allowing the ingress of crabs and fish going about their vital recycling activities. [Hogfather, by Terry Pratchett] %e passage # pp. 109-110 %passage 3 Although it was Hogswatch the University buildings were bustling. Wizards didn't go to bed early in any case,(1) and of course there was the Hogswatchnight Feast to look forward to at midnight. It would give some idea of the scale of the Hogswatchnight Feast that a light snack at UU consisted of three or four courses, not counting the cheese and nuts. Some of the wizards had been practicing for weeks. The Dean in particular could now lift a twenty-pound turkey on one fork. Having to wait until midnight merely put a healthy edge on appetites already professionally honed. (1) Often they lived to a time scale to suit themselves. Many of the senior ones, of course, lived entirely in the past, but several were like the Professor of Anthropics, who had invented an entire temporal system based on the belief that all the other ones were a mere illusion. Many people are aware of the Weak and Strong Anthropic Principles. The Weak One says, basically, that it was jolly amazing of the universe to be constructed in such a way that humans could evolve to a point where they could make a living in, for example, universities, while the Strong One says that, on the contrary, the whole point of the universe was that humans should not only work in universities, but also write for huge sums books with words like "Cosmic" and "Chaos" in the titles.(2) The UU Professor of Anthropics had developed the Special and Inevitable Anthropic Principle, which was that the entire reason for the existence of the universe was the eventual evolution of the UU Professor of Anthropics. But this was only a formal statement of the theory which absolutely everyone, with only some minor details of a "Fill in name here" nature, secretly believes to be true. (2) And they are correct. The universe clearly operates for the benefit of humanity. This can be readily seen by the convenient way the sun comes up in the morning, when people are ready to start the day. [Hogfather, by Terry Pratchett] %e passage # pp. 112-113 (we end this passage mid-paragraph...) %passage 4 "Watch this, sir," said Ponder. "All right, Adrian, initialize the GBL." "How do you do that, then?" said Ridcully, behind him. "It ... it means pull the great big lever," Ponder said, reluctantly. "Ah. Takes less time to say." Ponder sighed. "Yes, that's right, Archchancellor." He nodded to one of the students, who pulled a large red lever marked "Do Not Pull." Gears spun, somewhere inside Hex. Little trapdoors opened in the ant farms and millions of ants began to scurry along the networks of glass tubing. Ponder tapped at the huge wooden keyboard. "Beats me how you fellows remember how to do all this stuff," said Ridcully, still watching him with what Ponder considered to be amused interest. "Oh, it's largely intuitive, Archchancellor," said Ponder. "Obviously you have to spend a lot of time learning it first, though. [...]" [Hogfather, by Terry Pratchett] %e passage # pp. 139-140 %passage 5 "Tell me, Senior Wrangler, we never invited any /women/ to the Hogswatchnight Feast, did we?" "Of course not, Archchancellor," said the Senior Wrangler. He looked up in the dust-covered rafters, wondering what had caught the Archchancellor's eye. "Good heavens, no. They'd spoil everything. I've always said so." "And all the maids have got the evening off until midnight?." "A very generous custom, I've always said," said the Senior Wrangler, feeling his neck crick. "So why, every year, do we hang a damn great bunch of mistletoe up there?" The Senior Wrangler turned in a circle, still looking upward. "Well, er ... it's well, it's ... it's symbolic, Archchancellor." "Ah?" The Senior Wrangler felt that something more was expected. He groped around in the dusty attics of his education. "Of ... the leaves, d'y'see ... they're symbolic of ... of green, d'y'see, whereas the berries, in fact, yes, the berries symbolize ... symbolize white. Yes. White and green. Very ... symbolic." He waited. He was not, unfortunately, disappointed. "What of?" The Senior Wrangler coughed. "I'm not sure there /has/ to be an /of/," he said. "Ah? So," said the Archchancellor thoughtfully, "it could be said that the white and green symbolize a small parasitic plant?" "Yes, indeed," said the Senior Wrangler. "So mistletoe, in fact, symbolizes mistletoe?" "Exactly, Archchancellor," said the Senior Wrangler, who was now just hanging on. "Funny thing, that," said Ridcully, in the same thoughful tone of voice. "That statement is either so deep it would take a lifetime to fully comprehend every particle of its meaning, or it is a load of absolute tosh. Which is it, I wonder?" "It could be both," said the Senior Wrangler desperately. "And /that/ comment," said Ridcully, "is either very perceptive or very trite." "It could be bo--" "Don't push it, Senior Wrangler." [Hogfather, by Terry Pratchett] %e passage # p. 170 ([sic], sentence at end of paragraph should have fourth period) %passage 6 What Ponder was worried about was the fear that he was simply engaged in a cargo cult. He'd read about them. Ignorant(1) and credulous(2) people, whose island might once have been visited by some itinerant merchant vessel that traded pearls and coconuts for such fruits of civilization as glass beads, mirrors, axes, and sexual diseases, would later make big model ships out of bamboo in the hope of once again attracting this magical cargo. Of course, they were far too ignorant and credulous to know that just because you built the shape you didn't get the substance ... (1) Ignorant: the state of not knowing what a pronoun is, or how to find the square root of 27.4, and merely knowing childish and useless things like which of the seventy almost identical-looking species of the purple sea snake are the deadly ones, how to treat the poisonous pith of the Sago-sago tree to make a nourishing gruel, how to foretell the weather by the movements of the tree-climbing Burglar Crab, how to navigate across a thousand miles of featureless ocean by means of a piece of string and a small clay model of your grandfather, how to get essential vitamins from the liver of the ferocious Ice Bear, and other such trivial matters. It's a strange thing that when everyone becomes educated, everyone knows about the pronoun but no one knows about the Sago-sago. (2) Credulous: having views about the world, the universe and humanity's place in it that are shared only by very unsophisticated people and the most intelligent and advanced mathematicians and physicists. [Hogfather, by Terry Pratchett] %e passage # p. 244 (mantelpiece: it's dark and Ponder is checking whether the Hogfather # [Discworld analog of Santa Claus/Father Christmas] has been there # and left presents in the stocking the Librarian has hung) %passage 7 There was silence again, and then a clang. The Librarian grunted in his sleep. "What are you doing?" "I just knocked over the coal shovel." "Why are feeling around on the mantelpiece?" Oh, just ... you know, just ... just looking. A little ... experiment. After all, you never know." "You never know what?" "Just ... never know, you know." "/Sometimes/ you know," said Ridcully. "I think I know quite a lot that I didn't used to know. It's amazing what you /do/ end up knowing, I sometimes think. I often wonder what new stuff I'll know." "Well, you never know." "That's a fact." [Hogfather, by Terry Pratchett] %e passage # p. 330 %passage 8 IT GETS UNDER YOUR SKIN, LIFE, said Death, stepping forward. SPEAKING METAPHORICALLY, OF COURSE. IT'S A HABIT THAT'S HARD TO GIVE UP. ONE PUFF OF BREATH IS NEVER ENOUGH. YOU'LL FIND YOU WANT TO TAKE ANOTHER. [Hogfather, by Terry Pratchett] %e passage # p. 336 %passage 9 HUMANS NEED FANTASY TO BE HUMAN. TO BE THE PLACE WHERE THE FALLING ANGEL MEETS THE RISING APE. "Tooth Fairies? Hogfathers? Little--" YES. AS PRACTICE. YOU HAVE TO START OUT LEARNING TO BELIEVE THE /LITTLE/ LIES. "So we can believe the big ones?" YES. JUSTICE. MERCY. DUTY. THAT SORT OF THING. [Hogfather, by Terry Pratchett] %e passage # p. 343 (Mr. Teatime [pronounced Teh-ah-tim-eh] has just been thwarted in # his elabrate plot to lure and then kill Death) %passage 10 "What did he do it all for?" said Susan. "I mean, why? Money? Power?" SOME PEOPLE WILL DO ANYTHING FOR THE SHEER FASCINATION OF DOING IT, said Death. OR THE FAME. OR BECAUSE THEY SHOULDN'T. [Hogfather, by Terry Pratchett] %e passage %e title # # # %title Jingo (12) %passage 1 It was so much easier to blame it on Them. It was bleakly depressing to think that They were Us. If it was Them, then nothing was anyone's fault. If it was us, what did that make Me? After all, I'm one of Us. I must be. I've certainly never thought of myself as one of Them. No one ever thinks of themselves as one of Them. We're always one of Us. It's Them that do the bad things. [Jingo, by Terry Pratchett] %e passage # pp. 23-25 (Harper Torch edition) [transcribed from some other edition] %passage 2 There was a general shifting of position and a group clearing of throats. 'What about mercenaries?' said Boggis. 'The problem with mercenaries', said the Patrician, 'is that they need to be paid to start fighting. And, unless you are very lucky, you end up paying them even more to stop--' Selachii thumped the table. 'Very well, then, by jingo!' he snarled. 'Alone!' 'We could certainly do with one,' said Lord Vetinari. 'We need the money. I was about to say that we cannot /afford/ mercenaries.' 'How can this be?' said Lord Downey. Don't we pay our taxes?' 'Ah, I thought we might come to that,' said Lord Vetinari. He raised his hand and, on cue again, his clerk placed a piece of paper in it. 'Let me see now ... ah yes. Guild of Assassins ... Gross earnings in the last year: AM$13,207,048. Taxes paid in the last year: forty-seven dollars, twenty-two pence and what on examination turned out to be a Hershebian half-/dong/, worth one eighth of a penny.' 'That's all perfectly legal! The Guild of Accountants--' 'Ah yes. Guild of Accountants: gross earnings AM$7,999,011. Taxes paid: nil. But, ah yes, I see they applied for a rebate of AM$200,000.' 'And what we received, I may say, included a Hershebian half-/dong/,' said Mr Frostrip of the Guild of Accountants. 'What goes around comes around,' said Vetinari calmly. He tossed the paper aside. 'Taxation, gentlemen, is very much like dairy farming. The task is to extract the maximum amount of milk with the minimum of moo. And I am afraid to say that these days all I get is moo.' 'Are you telling us that Ankh-Morpork is /bankrupt/?' said Downey. 'Of course. While, at the same time, full of rich people. I trust they have been spending their good fortune on swords.' 'And you have /allowed/ this wholesale tax avoidance?' said Lord Selachii. 'Oh, the taxes haven't been avoided,' said Lord Vetinari. 'Or even evaded. They just haven't been paid.' 'That is a disgusting state of affairs!' The Patrician raised his eyebrows. 'Commander Vines?' 'Yes, sir?' 'Would you be so good as to assemble a squad of your most experienced men, liaise with the tax gatherers and obtain the accumulated back taxes, please? My clerk here will give you a list of the prime defaulters.' 'Right, sir. And if they resist, sir?' said Vimes, smiling nastily. 'Oh, how can they resist, commander? This is the will of our civic leaders.' He took the paper his clerk proferred. 'Let me see, now. Top of the list--' Lord Selachii coughed hurriedly. 'Far too late for that sort of nonsense now,' he said. 'Water under the bridge,' said Lord Downey. 'Dead and buried,' said Mr Slant. 'I paid mine,' said Vimes. [Jingo, by Terry Pratchett] %e passage # p. 7 (Harper Torch edition) %passage 3 As every student of exploration knows, the prize goes not to the explorer who first sets foot upon the virgin soil but to the one who gets that foot home first. If it is still attached to his leg, this is a bonus. [Jingo, by Terry Pratchett] %e passage # p. 34 %passage 4 Sergeant Colon had had a broad education. He'd been to the School of My Dad Always Said, the College of It Stands to Reason, and was now a post- graduate student at the University of What Some Bloke In the Pub Told Me. [Jingo, by Terry Pratchett] %e passage # pp. 43-44 %passage 5 "Hey, that's Reg Shoe! He's a zombie. He falls to bits all the time!" "Very big man in undead community, sir," said Carrott. "How come /he/ joined?" "He came round last week to complain about the Watch harassing some bogeymen, sir. He was very, er, vehement, sir. So I persuaded him that what the Watch needed was some expertise, so he joined up, sir." "No more complaints?" "Twice as many, sir. All from undead, sir, and all against Mr. Shoe. Funny That." [Jingo, by Terry Pratchett] %e passage # pp. 78-79 %passage 6 Perhaps it was because he was tired, or just because he was trying to shut out the world, but Vimes found himself slowing down into the traditional Watchman's walk and the traditional idling thought process. It was an almost Pavlovian response.(1) The legs swung, the feet moved, the mind began to work in a certain way. It wasn't a dream state, exactly. It was just that the ears, nose and eyeballs wired themselves straight into the ancient "suspicious bastard" node of his brain, leaving his higher brain center free to freewheel. (1) A term invented by the wizard Denephew Boot,(2) who had found that by a system of rewards and punishments he could train a dog, at the ringing of a bell, to immediately eat a strawberry meringue. (2) His parents, who were uncomplicated country people, had wanted a girl. They were expecting to call her Denise. [Jingo, by Terry Pratchett] %e passage # pp. 92-93 %passage 7 "What was it, Leonard?" "An experimental device for turning chemical energy into rotary motion," said Leonard. "The problem, you see, is getting the little pellets of black powder into the combustion chamber at exactly the right speed and one at a time. If two ignite together, well, what he have is the /external/ combustion engine." "And, er, what would be the purpose of it?" said the Patrician. "I believe it could replace the horse," Leonard said proudly. They looked at the stricken thing. "One of the advantages of horses that people often point out," said Vetinari, after some thought, "is that they very seldom explode. Almost never, in my experience, apart from that unfortunate occurrence in the hot summer a few years ago." With fastidious fingers he pulled something out of the mess. It was a pair of cubes, made out of some soft white fur and linked together by a piece of string. There were dots on them. "Dice?" he said. Leonard smiled in an embarrassed fashion. "Yes. I can't think why I thought they'd help it go better. It was just, well, an idea. You know how it is." [Jingo, by Terry Pratchett] %e passage # p. 98 (1st "He": Leonard; 2nd "He": Vetinari; last "He": Leonard again) %passage 8 He was as easily distracted as a kitten. All that business with the flying machine, for example. Giant bat wings hung from the ceiling even now. The Patrician had been more than happy to let him waste his time on that idea, because it was obvious to anyone that no human being would ever be able to flap the wings hard enough. He needn't have worried. Leonard was his own distraction. He had ended up spending ages designing a special tray so that people could eat their meals in the air. [Jingo, by Terry Pratchett] %e passage # p. 155 %passage 9 She held the lamp higher. Ramkins looked down their noses at her from their frames, through the brown varnish of the centuries. Portraits were another thing that had been collected out of unregarded habit. Most of them were men. They were invariably in armor and always on horseback. And every single one of them had fought the sworn enemies of Ankh-Morpork. In recent times this had been quite difficult and her grandfather, for example, had to lead an expedition all the way to Howondaland in order to find some sworn enemies, although there was an adequate supply and a lot of swearing by the time he left. Earlier, of course, it had been a lot easier. Ramkin regiments had fought the city's enemies all over the Sto Plains and had inflicted heroic casualties, quite often on people in the opposing armies.(1) (1) It is a long-cherished tradition among a certain type of military thinker that huge casualties are the main thing. If they are on the other side then this is a valuable bonus. [Jingo, by Terry Pratchett] %e passage # pp. 180-181 (the same gag was used in the 1968 movie "Support Your Local # Sheriff", with a dented badge rather than a book) %passage 10 He rummaged in a pocket and produced a very small book, which he held up for inspection. "This belonged to my great-grandad," he said. "He was in the scrap we had against Pseudopolis and my great-gran gave him this book of prayers for soldiers, 'cos you need all the prayers you can get, believe you me, and he stuck it in the top pocket of his jerkin, 'cause he couldn't afford armor, and next day in battle--whoosh, this arrow came out of nowhere, wham, straight into this book and it went all the way through to the last page before stopping, look. You can see the hole." "Pretty miraculous," Carrot agreed. "Yeah, it was, I s'pose," said the sergeant. He looked ruefully at the battered volume. "Shame about the other seventeen arrows, really." [Jingo, by Terry Pratchett] %e passage # p. 218 %passage 11 "Er ... what is this thing called?" said Colon, as he followed the Patrician up the ladder. "Well, because it is /submersed/ in a /marine/ environment, I've always called it the Going-Under-the-Water-Safely Device," said Leonard, behind him.(1) "But usually I just think of it as the boat." (1) Thinking up good names was, oddly enough, was one area where Leonard of Quirm's genious tended to give up. [Jingo, by Terry Pratchett] %e passage # p. 274 (passage starts mid-paragraph) %passage 12 "[...] I mean, what're our long-term objectives?" "Cooking meals and keeping warm?" said Les hopefully. "Well, /initially/," said Jackson. "That's obvious. But you know what they say, lad. 'Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.' See my point?" "I don't think that's actually what the saying is--" [Jingo, by Terry Pratchett] %e passage %e title # # # %title The Last Continent (10) # p. 260 (Harper Torch edition) %passage 1 "Is it true that your life passes before your eyes before you die?" YES. "Ghastly thought, really." Rincewind shuddered. "Oh, /gods/, I've just had another one. Suppose I /am/ just about to die and /this/ is my whole life passing in front of my eyes?" I THINK PERHAPS YOU DO NOT UNDERSTAND. PEOPLE'S WHOLE LIVES /DO/ PASS IN FRONT OF THEIR EYES BEFORE THEY DIE. THE PROCESS IS CALLED "LIVING". [...] [The Last Continent, by Terry Pratchett] %e passage %passage 2 "When You're Up to Your Ass in Alligators, Today Is the First Day of the Rest of Your Life." [The Last Continent, by Terry Pratchett] %e passage # p.3 (Harper Torch edition) %passage 3 All tribal myths are true, for a given value of "true." [The Last Continent, by Terry Pratchett] %e passage # pp. 13-14 %passage 4 Ponder /knew/ he should never have let Ridcully look at the invisible writings. Wasn't it a basic principle never to let your employer know what it is that you actually /do/ all day? But no matter what precautions you took, sooner or later the boss was bound to come in and poke around and say things like, "Is this where you work, then?" and "I thought I sent a memo out about people bringing in potted plants," and "What d'you call that thing with the keyboard?" [The Last Continent, by Terry Pratchett] %e passage # p. 21 (passage begins mid-paragraph) %passage 5 [...] Any true wizard, faced with a sign like "Do not open this door. Really. We mean it. We're not kidding. Opening this door will mean the end of the universe," would /automatically/ open the door in order to see what all the fuss was about. This made signs a waste of time, but at least it meant that when you handed what was left of the wizard to his grieving relatives you could say, as they grasped the jar, "We /told/ him not to." [The Last Continent, by Terry Pratchett] %e passage # p. 22 (the books are acting up while the Librarian is incapacitated and # now it's unsafe to go into the library) %passage 6 "But we're a university! We /have/ to have a library!" said Ridcully. "It adds /tone/. What sort of people would we be if we didn't go into the Library?" "Students," said the Senior Wrangler morosely. "Hah, I remember when I was a student," said the Lecturer in Recent Runes. "Old 'Bogeyboy' Swallett took us on an expedition to find the Lost Reading Room. Three weeks we were wandering around. We had to eat our own boots." "Did you find it?" said the Dean. "No, but we found the remains of the previous year's expedition." "What did you do?" "We ate their boots, too." [The Last Continent, by Terry Pratchett] %e passage # pp. 45-46 %passage 7 Death had taken to keeping Rincewind's lifetimer on a special shelf in his study, in much the way that a zoologist would want to keep an eye on a particularly intriguing specimen. The lifetimers of most people were the classic shape that Death thought was right and proper for the task. They appeared to be large eggtimers, although, since the sands they measured were the living seconds of someone's life, all the eggs were in one basket. Rincewind's hourglass looked like something created by a glassblower who'd had hiccups in a time machine. According to the amount of actual sand it contained--and Death was pretty good at making this kind of estimate--he should have died long ago. But strange curves and bends and extrusions of glass had developed over the years, and quite often the sand was flowing backwards, or diagonally. Clearly, Rincewind had been hit by so much magic, had been thrust reluctantly through time and space so often that he'd nearly bumped into himself coming the other way, that the precise end of his life was now as hard to find as the starting point on a roll of really sticky transparent tape. Death was familiar with the concept of the eternal, ever-renewed hero, the champion with a thousand faces. He'd refrained from commenting. He met heroes frequently, generally surrounded by, and this was important, the dead bodies of /very nearly/ all of their enemies and saying, "Vot the hell shust happened?" Whether there was some arrangement that allowed them to come back again afterwards was not something he would be drawn on. But he pondered whether, if this creature /did/ exist, it was somehow balanced by the eternal coward. The hero with a thousand retreating backs, perhaps. Many cultures had a legend of an undying hero who would one day rise again, so perhaps the balance of nature called for one who wouldn't. Whatever the ultimate truth of the matter, the fact now was that Death did not have the slightest idea of when Rincewind was going to die. This was very vexing to a creature who prided himself on his punctuality. [The Last Continent, by Terry Pratchett] %e passage # p. 61 %passage 8 A black and white bird appeared, and perched on his head. "You know what to do," said the old man. "Him? What a wonga," said the bird. "I've been lookin' at him. He's not even heroic. He's just in the right place at the right time." The old man indicated that this was maybe the definition of a hero. "All right, but why not go and get the thing yerself?" said the bird. "You've gotta have heroes," said the old man. "And I suppose I'll have to help," said the bird. It sniffed, which is quite hard to do through a beak. "Yep. Off you go." The bird shrugged, which /is/ easy to do if you have wings, and flew down off the old man's head. It didn't land on the rock but flew into it; for a moment there was a drawing of a bird, and then if faded. Creators aren't gods. They make places, which is quite hard. It's men that make gods. This explains a lot. The old man sat down and waited. [The Last Continent, by Terry Pratchett] %e passage # p. 186 %passage 9 She had a very straightforward view of foreign parts, or at least those more distant than her sister's house in Quirm where she spent a week's holiday every year. They were inhabited by people who were more to be pitied than blamed because, really, they were like children.(1) And they acted like savages.(2) (1) That is to say, she secretly considered them to be vicious, selfish and untrustworthy. (2) Again, when people like Mrs. Whitlow use this term they are not, for some inexplicable reason, trying to suggest that the subjects have a rich oral tradition, a complex system of tribal rights and a deep respect for the spirits of their ancestors. They are implying the kind of behavior more generally associated, oddly enough, with people wearing a full suit of clothes, often with the same sort of insignia. [The Last Continent, by Terry Pratchett] %e passage # p. 187 (last paragraph truncated) %passage 10 "I suppose he wouldn't have done anything stupid, would he?" he said. "Archchancellor, Ponder Stibbons is a fully trained wizard!" said the Dean. "Thank you for that very concise and definite answer, Dean," said Ridcully. [The Last Continent, by Terry Pratchett] %e passage %e title # # # %title Carpe Jugulum (8) # p. 10 (Harper Torch edition) %passage 1 Agnes tended to obey rules. Perdita didn't. Perdita thought that not obeying rules was somehow cool. Agnes thought that rules like "Don't fall into this huge pit of spikes" were there for a purpose. [...] [Carpe Jugulum, by Terry Pratchett] %e passage # p. 2 (example of the silliness and incomprehensability of the # Nac mac Feegle [aka pictsies, pict + pixie]; fortunately their # speech doesn't constitute much of the book's dialogue) %passage 2 "Nac mac Feegle!" "Ach, stickit yer trakkans!" "Gie you sich a kickin'!" "Bigjobs!" "Dere c'n onlie be whin t'ousand!" "Nac mac Feegle wha hae!" "Wha hae yersel, ya boggin!" [Carpe Jugulum, by Terry Pratchett] %e passage # p. 28 (from a discussion about whether Omnian priests still burn witches) %passage 3 "Hah! The leopard does not change his shorts, my girl!" [Carpe Jugulum, by Terry Pratchett] %e passage # p. 133 %passage 4 Things were not what they seemed. But then, as Granny always said, they never were. [Carpe Jugulum, by Terry Pratchett] %e passage # pp. 254-255 ("verra comp-lic-ated" is accurate) %passage 5 "How can I ever repay you?" he said. The pixie's eyes gleamed happily. "Oh, there's a wee bitty thing the Carlin' Ogg said you could be givin' us, hardly important at all," he said. "Anything," said Verence. A couple of pixies came up staggering under a rolled-up parchment, which was unfolded in front of Verence. The old pixie was suddenly holding a quill pen. "It's called a signature," he said, as Verence stared at the tiny handwriting. "An' make sure ye initial all the sub-clauses and codicils. We of the Nac mac Feegle are a simple folk," he added, "but we write verra comp-lic-ated documents." [Carpe Jugulum, by Terry Pratchett] %e passage # p. 326 (Igor's lisp of "th" for "s" makes this /look/ intentionally archaic # although it wouldn't be pronounced that way) %passage 6 "What goeth around, cometh around," said Igor. [Carpe Jugulum, by Terry Pratchett] %e passage # p. 336-337 (the plot is driven by the actions of a family of vampyres # who do mostly cooperate with each other) %passage 7 Vampires are not naturally cooperative creatures. It's not in their nature. Every other vampire is a rival for the next meal. In fact, the ideal situation for a vampire is a world in which every other vampire has been killed off and no one seriously believes in vampires anymore. They are by nature as cooperative as sharks. Vampyres are just the same, the only real difference being that they can't spell properly. [Carpe Jugulum, by Terry Pratchett] %e passage # p. 338 %passage 8 "Be resolute, my dear," said the Count. "Remember--that which does not kill us can only make us stronger." "And that which /does/ kill us leaves us /dead/!" snarled Lacrimosa. "You saw what happened to the others! /You/ got your fingers burned!." [Carpe Jugulum, by Terry Pratchett] %e passage %e title # # # %title The Fifth Elephant (9) %passage 1 You did something because it had always been done, and the explanation was "but we've always done it this way." A million dead people can't have been wrong, can they? [The Fifth Elephant, by Terry Pratchett] %e passage # p. 233 (Harper Torch edition) [this is a footnote] %passage 2 He'd noticed that sex bore some resemblance to cookery: It facinated people, they sometimes bought books full of complicated recipes and interesting pictures, and sometimes when they were really hungry they created vast banquets in their imagination--but at the end of the day they'd settle quite happily for egg and chips, if it was well done and maybe had a slice of tomato. [The Fifth Elephant, by Terry Pratchett] %e passage # pp. 80-81 (Harper Torch edition) [the pigeon is trained to carry messages] %passage 3 Constable Shoe saluted, but a litle testily. He'd been waiting rather a long time. "Afternoon, Sergeant--" "That's Captain," said Captain Colon. "See the pip on my shoulder, Reg?" Reg looked closely. "I thought it was bird doings, Sarge." "That's Captain," said Colon Automatically. "It's only chalk now because I ain't got time to get it done properly," he said, "so don't be cheeky." [...] A pigeon chose that diplomatic moment to flutter into the factory and land on Colon's shoulder, where it promoted him. [...] [The Fifth Elephant, by Terry Pratchett] %e passage # p. 187 %passage 4 The wheels clattered over the wood of a drawbridge. As castles went, this looked as though it could be taken by a small squad of not very efficient soldiers. Its builder had not been thinking about fortifications. He'd been influenced by fairy tales and possibly by some of the more ornamental sorts of cake. It was a castle for looking at. For defense, putting a blanket over your head might be marginally safer. The coach stopped in the courtyard. [...] [The Fifth Elephant, by Terry Pratchett] %e passage # p. 229 %passage 5 "What a mess," he said. "Locked-room mysteries are even worse when they leave the room unlocked." [The Fifth Elephant, by Terry Pratchett] %e passage # p. 246 ([sic] 'rules for which he termed "the art..."' seems like it # ought to have been 'rules for _what_ he termed "the art..."') %passage 6 He punched the dwarf in the stomach. This was no time to play by the Marquis of Fantailler rules.(1) (1) The Marquis of Fantailler got into many fights in his youth, most of them as a result of being known as the Marquis of Fantailler, and wrote a set of rules for which he termed "the noble art of fisticuffs" which mostly consisted of a list of places where people weren't allowed to hit him. Many people were impressed with his work and later stood with noble chest outthrust and fists balled in a spirit of manly aggression against people who hadn't read the Marquis's book but /did/ know how to knock people senseless with a chair. The last words of a surprisingly large number of people were "Stuff the bloody Marquis of Fantailler--" [The Fifth Elephant, by Terry Pratchett] %e passage # p. 251 %passage 7 Vimes shivered. He hadn't realized how warm it had been underground. Or what time it was. There was a dim, a very dim light. Was this just after sunset? What it almost dawn? The flakes were piling up on his damp clothes, driven by the wind. Freedom could get you killed. Shelter ... that was /essential/. The time of day and a precise location were of no use to the dead. They always knew what time it was and where they were. [The Fifth Elephant, by Terry Pratchett] %e passage # p. 267 %passage 8 GOOD MORNING. Vimes blinked. A tall dark-robed figure was now sitting in the boat. "Are you Death?" IT'S THE SCYTHE, ISN'T IT. PEOPLE ALWAYS NOTICE THE SCYTHE. "I'm going to die?" POSSIBLY. "/Possibly/? You turn up when people are /possibly/ going to die?" OH YES. IT'S QUITE THE NEW THING. IT'S BECAUSE OF THE UNCERTAINTY PRINCIPLE. "What's that?" I'M NOT SURE. [The Fifth Elephant, by Terry Pratchett] %e passage # p. 288 [sic: missing 4th '.' at end] %passage 9 "Are you in charge of the Watch here?" "No. That's the job of the Burgermaster." "And who gives him /his/ orders?" "Everyone," said Tantony bitterly. Vimes nodded. Been there, he thought. Been there, done that, bought the dublet... [The Fifth Elephant, by Terry Pratchett] %e passage %e title # # # %title The Truth (8) %passage 1 There are, it has been said, two types of people in the world. There are those who, when presented with a glass that is exactly half full, say: this glass is half full. And then there are those who say: this glass is half empty. The world belongs, however, to those who can look at the glass and say: What's up with this glass? Excuse me? Excuse me? This is my glass? I don't think so. My glass was full! And it was a bigger glass! Who's been pinching my beer? [The Truth, by Terry Pratchett] %e passage 1 %passage 2 The world is made up of four elements: Earth, Air, Fire and Water. This is a fact well known even to Corporal Nobbs. It's also wrong. There's a fifth element, and generally it's called Surprise. [The Truth, by Terry Pratchett] %e passage 2 # pp. 1-2 (Harper Torch edition) %passage 3 The rumor spread through the city like wildfire (which had quite often spread through Ankh-Morpork since its citizens had learned the words "fire insurance"). /The dwarfs can turn lead into gold.../ [...] It reached the pointy ears of the dwarfs. "Can we?" "Damned if I know. /I/ can't." "Yeah, but if you could, you wouldn't say. /I/ wouldn't say, if /I/ could. "Can you?" "No." "/Ah-ha!/" [The Truth, by Terry Pratchett] %e passage # p. 10 ('mucky' is accurate) %passage 4 It would seem quite impossible, on such a mucky night, that there could have been anyone to witness this scene. But there was. The universe requires everything to be observed, lest it cease to exist. [The Truth, by Terry Pratchett] %e passage # p. 19 %passage 5 Very occasionally, a frog was removed from the vivarium and put into a rather smaller jar where it briefly became a very happy frog indeed, and then went to sleep and woke up in that great big jungle in the sky. And thus the university got the active ingredient that it made up into pills and fed to the Bursar, to keep him sane. At least, /apparently/ sane, because nothing was that simple at good old UU. In fact he was incurably insane and hallucinated more or less continually, but by a remarkable stroke of lateral thinking his fellow wizards had reasoned, in that case, that the whole business could be sorted out if only they could find a formula that caused him to /hallucinate that he was completely sane/.(1) This had worked well. [...] (1) This is a very common hallucination, shared by most people. [The Truth, by Terry Pratchett] %e passage # pp. 107-108 ('zis', 'zat', 'vhich', 'Latation' are all accurate) %passage 6 "Er ... why do you need to work in a darkroom, though?" he said. "The imps don't need it, do they?" "Ah, zis is for my experiment," said Otto proudly. "You know zat another term for an iconographer would be 'photographer'? From the old word 'photus' in Latation, vhich means--" "To prance around like an idiot ordering everyone about as if you owned the place," said William. "Ah, you know it!" [The Truth, by Terry Pratchett] %e passage # p. 100 %passage 7 "Vy are ve stoppink?" said Otto. "That's Sergeant Detritus on the gate," said William. "Ah. A troll. Very stupid," opined Otto. "But hard to fool. I'm afraid we shall have to try the truth." "Vy vill that vork?" "He's a policeman. The truth usually confuses them. They don't often hear it." [The Truth, by Terry Pratchett] %e passage # p. 290 %passage 8 Mr. Tulip raised a trembling hand. "Is this the bit where my whole life passes in front of my eyes?" he said. NO, THAT WAS THE BIT JUST NOW. "Which bit?" THE BIT, said Death, BETWEEN YOU BEING BORN AND YOU DYING. NO, THIS... MR. TULIP, THIS IS YOUR WHOLE LIFE AS IT PASSED BEFORE /OTHER PEOPLE'S/ EYES... [The Truth, by Terry Pratchett] %e passage %e title # # # %title Thief of Time (8) %passage 1 "No running with scythes!" [Thief of Time, by Terry Pratchett] %e passage # p. 24 (Harper Torch edition) %passage 2 Silver stars weren't awarded frequently, and gold starts happened less than once a fortnight, and were vied for accordingly. Right now, Miss Susan selected a silver star. Pretty soon Vincent the Keen would have a galaxy of his very own. To give him his due, he was quite disinterested in which kind of star he got. Quantity, that was what he liked. Miss Susan had privately marked him down as Boy Most Likely To Be Killed One Day By His Wife. [Thief of Time, by Terry Pratchett] %e passage # p. 53 ('... with the chorus:', '"Do not act...' are separate paragraphs; # 'challanger' has been cowed after finding out that the little old # man he challanged--for entering the dojo--is actually Lu-Tze) %passage 3 As Lobsang followed the ambling Lu-Tze, he heard the dojo master, who like all teachers never missed an opportunity to drive home a lesson, say: "Dojo! What is Rule One?" Even the cowering challanger mumbled along with the chorus: "Do not act incautiously when confronting a little bald wrinkly smiling man!" [Thief of Time, by Terry Pratchett] %e passage # p. 74-75 (the novices didn't know that the little old man known as Sweeper # is actually Lu-Tze; see passage 3 regarding Rule One) %passage 4 One day a group of senior novices, for mischief, kicked over the little shrine that Lu-Tze kept beside his sleeping mat. Next morning, no sweepers turned up for work. They stayed in their huts with the doors barred. After making inquiries, the abbot, who at that time was fifty years old again, summoned the three novices to his room. There were three brooms leaning against the wall. He spoke as follows: "You know that the dreadful Battle of Five Cities did not happen because the messenger got there in time?" They did. You learned this early in your studies. And they bowed nervously, because this was the abbot, after all. "And you know then that when the messenger's horse threw a shoe he espied a man trudging beside the road carrying a small portable forge and pushing an anvil on a barrow?" They knew. "And you know that man was Lu-tze?" They did. "Surely you know that Janda Trapp, Grand Master of /Oki-doki/, /Toro-fu/, and /Chang-fu/, has only ever yielded to one man?" They knew. "And you know that man is Lu-Tze?" They did. "You know the little shrine you kicked over last night?" They knew. "You know it had an owner?" There was silence. Then the brightest of the novices looked up at the abbot in horror, swallowed, picked up one of the three brooms, and walked out of the room. The other two were slower of brain and had to follow the story all the way through to the end. Then one of them said, "But it was only a sweeper's shrine!" "You will take up the brooms and sweep," said the abbot, "and you will sweep every day, and you will sweep until the day you find Lu-Tze and dare to say 'Sweeper, it was I who knocked over and scattered your shrine and now I will in humility accompany you to the dojo on the Tenth Djim, in order to learn the Right Way.' Only then, if you are still able, may you resume your studies here. Understood?"(1) Older monks sometimes complained, but someone would always say: "Remember that Lu-Tze's Way is not our Way. Remember he learned everything by sweeping unheeded while students were being educated. Remember, he has been everywhere and done many things. Perhaps he is a little... strange, but remember he walked into a citadel full of armed men and traps and nevertheless saw to it that the Pash of Muntab choked innocently on a fish bone. No monk is better than Lu-Tze at finding the Time and the Place." Some, who did not know, would say: "What is this Way that gives him so much power?" And they were told: "It is the Way of Mrs. Marietta Cosmopolite, 3 Quirm Street, Ankh-Morpork, Rooms To Rent Very Reasonable. No, we don't understand it, either. Some subsendential rubbish, apparently." (1) And the story continues: The novice who had protested that it was only the shrine of a sweeper ran away from the temple; the student who said nothing remained a sweeper for the rest of his life; and the student who has seen the inevitable shape of the story went, after much agonizing and several months of meticulous sweeping, to Lu-Tze and knelt and asked to be shown the Right Way. Whereupon the sweeper took him to the dojo of the Tenth Djim, with its terrible multibladed fighting machines and its fearsome serrated weapons such as the /clong-clong/ and the /uppsi/. The story runs that the sweeper then opened a cupboard at the back of the dojo and produced a broom and spake thusly: "One hand /here/ and the other /here/, understand? People never get it right. Use good, even strokes and let the broom do most of the work. Never try to sweep up a big pile, you'll end up sweeping every bit of dust twice. Use your dustpan wisely, and remember: a small brush for the corners." [Thief of Time, by Terry Pratchett] %e passage # p. 102 ('coming here': to the remote mountains where the monks live) %passage 5 "But did not Wen say that if the truth is anywhere, it is everywhere?" said Lobsang. "Well done. I see you learned /something/, at least. But one day it seemed to me that everyone else had decided that wisdom can only be found a long way off. So I went to Ankh-Morpork. They were all coming here, so it seemed only fair. "Seeking /enlightenment/?" "No. The wise man does not seek enlightenment, he waits for it. So while I was waiting, it occurred to me that seeking perplexity might be more fun," said Lu-Tze. "After all, enlightenment begins where perplexity ends. And I found perplexity. And a kind of enlightenment, too. I had not been there for five minutes, for example, when some men in an alley tried to enlighten me of what little I possessed, giving me a valuable lesson in the ridiculousness of material things." [Thief of Time, by Terry Pratchett] %e passage # p. 286 (food in general, and chocolate in particular, has proven to be an # effective 'weapon' against Auditors who've taken on human form) %passage 6 "Let's get up into Zephyr Street," said Susan. "What is there for us?" "Wienrich and Boettcher." "Who are they?" "I think the original Herr Wienrich and Frau Boettcher died a long time ago. But the shop still does very good business," said Susan, darting across the street. "We need ammunition." Lady LeJean caught up. "Oh. They make chocolate?" she said. "Does a bear poo in the woods?" said Susan and realized her mistake right away.(1) Too late. Lady LeJean looked thoughtful for a moment. "Yes," she said at last. "Yes, I believe that most varieties do, indeed, excrete, as you suggest, at least in the temperate zones, but there are several that--" "I mean to say that, yes, they make chocolate," said Susan. (1) Teaching small children for any length of time can do this to a vocabulary. [Thief of Time, by Terry Pratchett] %e passage # p. 308 %passage 7 Kaos listened to history. There were new words. Wizards and philosophers had found Chaos, which is Kaos with his hair combed and a tie on, and had found in the epitome of disorder a new order undreamed of. /There are different kinds of rules./ /From the simple comes the complex, and from the complex comes a different/ /kind of simplicity. Chaos is order in a mask.../ Chaos. Not dark, ancient Kaos, left behind by the evolving universe, but new, shiny Chaos, dancing in the heart of everything. The idea was strangely attractive. And it was a reason to go on living. [Thief of Time, by Terry Pratchett] %e passage # p. 355 (starts mid-paragraph, with a clause about eating in class omitted) %passage 8 [...] Susan [...] took the view that, if there were rules, they applied to everyone, even her. Otherwise they were merely tyranny. But rules were there to make you think before you broke them. [Thief of Time, by Terry Pratchett] %e passage %e title # # # The Last Hero has never been released in the U.S. (or anywhere?) as a # conventional mass market paperback. The large (roughly 10" by 12") # trade paperback contains many full page color illustrations and most # text pages include decorations of varying degrees of elaborateness. # The actual text is probably only novella length. # %title The Last Hero (7) # p. 41 (EOS edition) %passage 1 Too many people, when listing all the perils to be found in the search for lost treasure or ancient wisdom, had forgotten to put at the top of the list 'the man who arrived just before you'. [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage # p. 5 # second paragraph is a bit "on the nose" but is too good to leave out %passage 2 The reason for the story was a mix of many things. There was humanity's desire to do forebidden deeds merely because they were forbidden. There was its desire to find new horizons and kill the people who live beyond them. There were the mysterious scrolls. There was the cucumber. But mostly there was the knowledge that one day, it would all be over. 'Ah, well, life goes on,' people say when someone dies. But from the point of view of the person who has just died, it doesn't. It's the universe that goes on. Just as the deceased was getting the hang of everything it's all whisked away, by illness or accident or, in one case, a cucumber. Why this has to be is one of the imponderables of life, in the face of which people either start to pray... or become really, really angry. [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage # p. 19 %passage 3 'And they're /heroes/,' said Mr Betteridge of the Guild of Historians. 'And that means, exactly?' said the Patrician, sighing. 'They're good at doing what they want to do.' 'But they are also, as I understand it, very old men.' 'Very old /heroes/,' the historian corrected him. 'That just means they've had a lot of /experience/ in doing what they want to do. Lord Vetinari sighed again. He did not like to live in a world of heroes. You had civilisation, such as it was, and you had heroes. [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage # p. 25 %passage 4 They were, all of them, old men. Their background conversation was a litany of complaints about feet, stomachs and backs. They moved slowly. But they had a /look/ about them. It was in their eyes. Their eyes said that wherever it was, they had been there. Whatever it was, they had done it, sometimes more than once. But they would never, ever, /buy/ the T-shirt. And they /did/ know the meaning of the word 'fear'. It was something that happened to other people. [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage # p. 97 %passage 5 Captain Carrot saluted. 'Force is always the last resort, sir,' he said. 'I believe for Cohen it's the first choice,' said Lord Vetinari. 'He's not too bad if you don't come up behind him suddenly,' said Rincewind. 'Ah, there is the voice of our mission specialist,' said the Patrician. 'I just hope-- What is that on your badge, Captain Carrot?' 'Mission motto, sir,' said Carrot cheerfully. '/Morituri Nolumus Mori/. Rincewind suggested it.' 'I imagine he did,' said Lord Vetinari, observing the wizard coldly. 'And would you care to give us a colloquial translation, Mr Rincewind?' 'Er...' Rincewind hesitated, but there really was no escape. 'Er... roughly speaking, it means, "We who are about to die don't want to", sir.' [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage # p. 125 (near top, then continued half way down) %passage 6 'A good wizard, Rincewind,' said the Chair of Indefinite Studies. 'Not particularly bright, but, frankly, I've never been quite happy with intelligence. An overrated talent, in my humble opinion.' Ponder's ears went red. [...] 'Mr Stibbons was right, was he?' said Ridcully, staring at Ponder. 'How did you work that out so /exactly/, Mr Stibbons?' 'I, er...' Ponder felt the eyes of the wizards on him. 'I--' He stopped. 'It was a lucky guess, sir.' The wizards relaxed. They were extremely uneasy with cleverness, but lucky guessing was what being a wizard was all about. [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage # p. 146 %passage 7 Evil Harry looked down and shuffled his feet, his face a battle between pride and relief. 'Good of you to say that, lads,' he mumbled. 'I mean, you know, if it was up to me I wouldn't do this to yer, but I got a reputation to--' 'I said we /understand/,' said Cohen. 'It's just like with us. You see a big hairy thing galloping towards you, you don't stop to think: Is this a rare species on the point of extinction? No, you hack its head off. 'Cos that's heroing, am I right? An' /you/ see someone, you betray 'em, quick as a wink. 'Cos that's villaining.' [The Last Hero, written by Terry Pratchett, illustrated by Paul Kidby] %e passage %e title # # # %title The Amazing Maurice and his Educated Rodents (1) %passage 1 The important thing about adventures, thought Mr Bunnsy, was that they shouldn't be so long as to make you miss mealtimes. [The Amazing Maurice and his Educated Rodents, by Terry Pratchett] %e passage %e title # # # %title Night Watch (7) %passage 1 When Mister Safety Catch Is Not On, Mister Crossbow Is Not Your Friend. [Night Watch, by Terry Pratchett] %e passage # pp. 2-4 (Harper Torch edition; omitted section describes how the student # assassin, who has fallen off a booby-trapped shed roof into a # cesspit, is on an assignment to try to get into position to # target Vimes but not actually attack or try to kill him) %passage 2 "You're a bit young to be sent on this contract, aren't you?" said Vimes. "Not a contract, sir," said Jocasta, still paddling. "Come now, Miss Wiggs. The price on my head is at least--" "The Guild council put it in abeyance, sir," said the patient swimmer. "You're off the register. They're not accepting contracts on you at present." [...] "And quite a few of the traps drop you into something deadly," said Vimes. "Lucky for me that I fell into this one, eh, sir?" "Oh, that one's deadly too," said Vimes. "/Eventually/ deadly." He sighed. He really wanted to discourage this sort of thing but... they'd put him off the register? It wasn't that he'd /liked/ being shot at by hooded figures in the temporary employ of his many and varied enemies, but he'd always looked at it as some kind of vote of confidence. It showed that he was annoying the rich and arrogant people who ought to be annoyed. Besides, the Assassin's Guild was easy to outwit. They had strict rules, which they followed quite honorably, and this was fine by Vimes, who, in certain practical matters, had no rules whatever. Off the register, eh? The only other person not on it anymore, it was rumored, was Lord Vetinari, the Patrician. The Assassins understood the political game in the city better than anyone, and if they took you off the register it was because they felt that your departure would not only spoil the game but also smash the board. [Night Watch, by Terry Pratchett] %e passage # p. 12 (some trainee Watchmen have been taught a marching/running song by # Sergeant Detritus, a troll; trolls count "one, two, many, lots" # and evidently can't go any higher) %passage 3 "/Now we sing dis stupid song!/ /Sing it as we run along!/ /Why we sing dis we don't know!/ /We can't make der words rhyme prop'ly!/" "Sound off!" "/One! Two!/" "Sound off!" "/Many! Lots!/" "Sound off!" "/Er... what?/" [Night Watch, by Terry Pratchett] %e passage # p. 137 %passage 4 Everyone was guilty of something. Vimes knew that. Every copper knew it. That was how you maintained your authority--everyone, talking to a copper, was secretly afraid you could see their guilty secret written on their forehead. You couldn't, of course. But neither were you supposed to drag someone off the street and smash their fingers with a hammer until they told you what it was. [Night Watch, by Terry Pratchett] %e passage # p. 138 (passage starts mid-paragraph) %passage 5 [...] Doctor Lawn was wearing a face mask and holding a pair of very long tweezers in his hand. "Yes?" "I'm going out," said Vimes. "Trouble?" "Not too bad. Slidey Harris was unlucky at cards last night, that's all. Played the ace of hearts." "That's an unlucky card?" "It is if Big Tony knows he didn't deal it to you. But I'll soon have it removed. [...]" [Night Watch, by Terry Pratchett] %e passage # p. 141 ('it' is a piece of paper concealed inside one of CMOT Dibbler's # "meat" pies, partly eaten by Vimes but intended for someone else) %passage 6 He unfolded it. In smudged pencil, but still readable, it read: /Morphic Street, 9 o'clock tonight. Password: Swordfish/. Swordfish? Every password was "swordfish"! Whenever anyone tried to think of a word that no one would ever guess, they /always/ chose "swordfish." It was just one of those strange quirks of the human mind. [Night Watch, by Terry Pratchett] %e passage # p. 345 (text actually has "worth more *that* AM$10,000"--obviously a typo) %passage 7 There were rules. When you had a Guild of Assassins, there had to be rules that everyone knew and that were never, ever broken.(1) An Assassin, a real Assassin, had to look like one--black clothes, hood, boots, and all. If they could wear any clothes, any disguise, then what could anyone do but spend all day sitting in a small room with a loaded crossbow pointed at the door? And they couldn't kill a man incapable of defending himself (although a man worth more than AM$10,000 a year was considered automatically capable of defending himself or at least of employing people who were). And they had to give the target a chance. (1) Sometimes, admittedly, for a given value of "never." [Night Watch, by Terry Pratchett] %e passage %e title # # # %title The Wee Free Men (9) # p. 100 (HarperTempest edition; quin==queen; # this rallying cry occurs multiple times; p. 167 has "/Nae quin! # Nae king! Nae laird! Nae master! We willna be fooled again!/", # p. 193 has same except that King and Quin are reversed and # capitalized, p. 287 has "/Nae Quin! Nae Laird! Wee Fee Men!/") %passage 1 "Nac Mac Feegle! The Wee Free Men! Nae king! Nae quin! Nae laird! Nae master! /We willna be fooled again!/" [The Wee Free Men, by Terry Pratchett] %e passage # pp. 18-19 (unlike in Lancre and its surrounding Ramtop mountains, witches # are unwelcome in the Chalk; the first paragraph continues with # mention of things Miss Tick doesn't carry, then things she does, # ending with 'and, of course, a lucky charm.') %passage 2 Miss Tick did not look like a witch. Most witches don't, at least the ones who wander from place to place. Looking like a witch can be dangerous when you walk among the uneducated. [...] Everyone in the country carried lucky charms, and Miss Tick had worked out that if you didn't have one, people would suspect that you /were/ a witch. You had to be a bit cunning to be a witch. Miss Tick did have a pointy hat, but it was a stealth hat and pointed only when she wanted it to. The one thing in her bag that might have made anyone suspicious was a very small, grubby booklet entitled /An Introduction to Escapology, by the Great Williamson/. If one of the risks of your job is being thrown into a pond with your hands tied together, then the ability to swim thirty yards underwater, fully clothed, plus the ability to lurk under the weeds breathing air through a hollow reed, count as nothing if you aren't also /amazingly/ good at knots. [The Wee Free Men, by Terry Pratchett] %e passage # pp. 29-30 ('pune' is accurate; a mispronunciation of 'pun', as indicated # by the footnote; one wonders how a nine year old farm girl knows # how to pronounce 'mystique'...) %passage 3 "My name," she said at last, "is Miss Tick. And I /am/ a witch. It's a good name for a witch, of course." "You mean blood-sucking parasite?" said Tiffany, wrinkling her forehead. "I'm sorry," said Miss Tick, coldly. "Ticks," said Tiffany. "Sheep get them. But if you use turpentine--" "I /meant/ that it /sounds/ like 'mystic,'" said Miss Tick. "Oh, you mean a pune, or play on words," said Tiffany.(1) "In that case it would be even better if you were Miss /Teak/, a dense foreign wood, because that would sound like 'mystique,' or you could be Miss Take, which would--" "I can see we're going to get on like a house on fire," said Miss Tick. "There may be no survivors." (1) Tiffany had read lots of words in the dictionary that she'd never heard spoken, so she had to guess at how they were pronounced. [The Wee Free Men, by Terry Pratchett] %e passage # pp. 64-65 %passage 4 There was a lot of mist around, but a few stars were visible overhead and there was a gibbous moon in the sky. Tiffany knew it was gibbous because she'd read in the Almanack that /gibbous/ means what the moon looked like when it was just a bit fatter than half full, and so she made a point of paying attention to it around those times just so that she could say to herself, "Ah, I see the moon's very gibbous tonight." It's possible that this tells you more about Tiffany than she would want you to know. [The Wee Free Men, by Terry Pratchett] %e passage # p. 159 (bigjob: pictsie term for human; 'heid', 'dinna', 'canna', 'noo', # 'aroound', and 'Tiffan' are accurate) %passage 5 "[...] Ye have the First Sight and the Second Thoughts, just like yer Granny. That's rare in a bigjob." "Don't you mean Second Sight?" Tiffany asked. "Like people who can see ghosts and stuff?" "Ach, no. That's typical bigjob thinking. /First Sight/ is when you can see what's really there, not what your heid tells you /ought/ to be there. Ye saw Jenny, ye saw the horseman, ye saw them as real thingies. Second sight is dull sight, it's seeing only what you expect to see. Most bigjobs ha' that. Listen to me, because I'm fadin' noo and there's a lot you dinna ken. Ye think this is the whole world? That is a good thought for sheep and mortals who dinna open their eyes. Because in truth there are more worlds than stars in the sky. Understand? They are everywhere, big and small, close as your skin. They are /everywhere/. Some ye can see an' some ye canna, but there are doors, Tiffan. They might be a hill or a tree or a stone or a turn in the road, or they might e'en be a thought in yer heid, but they are there, all aroound ye. You'll have to learn to see 'em, because you walk among them and dinna know it. And some of them... is poisonous." [The Wee Free Men, by Terry Pratchett] %e passage # p. 193 (source text is all italics here; passage continues with the speakers # getting in synch and shouting the cry from passage 1) %passage 6 "They can tak' oour lives but they canna tak' oour troousers!" "Ye'll tak' the high road an' I'll tak' yer wallet!" "There can only be one t'ousand!" "Ach, stick it up yer trakkans!" [The Wee Free Men, by Terry Pratchett] %e passage # p. 227 (also all italics; end of a reminiscence of Granny Aching by Tiffany) %passage 7 "Them as can do has to do for them as can't. And someone has to speak up for them as has no voices." [The Wee Free Men, by Terry Pratchett] %e passage # p. 287 (like passage 6, this ties back to passage 1; the cry there is # one of the things Tiffany hears) %passage 8 Tiffany might have been the only person, in all the worlds that there are, to be happy to hear the sound of the Nac Mac Feegle. They poured out of the smashed nut. Some were still wearing bow ties. Some were back in their kilts. But they were all in a fighting mood and, to save time, were fighting with one another to get up to speed. [The Wee Free Men, by Terry Pratchett] %e passage # pp. 313-314 (passage starts mid-paragraph; 'mebbe' and 'oour' are accurate) %passage 9 "[...] Can you bring Wentworth?" "Aye." "And you won't get lost or--or drunk or anything?" Rob Anybody looked offended. "We ne'er get lost!" he said. "We always ken where we are! It's just sometimes mebbe we aren't sure where everything else is, but it's no' our fault if /everything else/ gets lost! The Nac Mac Feegle never get lost!" "What about drunk?" said Tiffany, dragging Roland toward the lighthouse. "We've ne'er been lost in oour lives! Is that no' the case, lads?" said Rob Anybody. There was a murmur of resentful agreement. "The words /lost/ and /Nac Mac Feegle/ shouldna turn up in the same sentence!" "And drunk?" said Tiffany again, laying Roland down on the beach. "Gettin' lost is something that happens to other people!" declared Rob Anybody. "I want to make that point perfectly clear!" [The Wee Free Men, by Terry Pratchett] %e passage %e title # # # %title Monstrous Regiment (8) %passage 1 'How can you protect yourself by carrying a sword if you don't know how to use it?' 'Not me, sir. Other people. They see the sword and don't attack me,' said Maladict patiently. 'Yes, but if they did, lad, you wouldn't be any good with it,' said the sergeant. 'No, sir. I'd probably settle for just ripping their heads off, sir. That's what I mean by protection, sir. Theirs, not mine. And I'd get hell from the League if I did that, sir.' [Monstrous Regiment, by Terry Pratchett] %e passage # p. 6 (Harper Torch edition) %passage 2 /There was always a war./ Usually they were border disputes, the national equivalent of complaining that the neighbor was letting their hedge grow too long. Sometimes they were bigger. Borogravia was a peace-loving country in the midst of treacherous, devious, warlike enemies. They had to be treacherous, devious, and warlike, otherwise we wouldn't be fighting them, eh? There was always a war. [Monstrous Regiment, by Terry Pratchett] %e passage # pp. 115-116 (plural 'forests' is odd but accurate [1st sentence]; # so is 'knew' which ought to be 'known' [4th paragraph]; # 9 '0's and 7 '0's are accurate too) %passage 3 A pigeon rose over the forests, banked slightly, and headed straight for the valley of the Kneck. Even from here, the black stone bulk of the Keep was visible, rising above the sea of trees. The pigeon sped on, one spark of purpose in the fresh new morning-- --and squawked as darkness dropped from the sky, gripping it in talons of steel. Buzzard and pigeon tumbled for a moment, and then the buzzard gained a little height and flapped onwards. The pigeon thought: 000000000. But had it been more capable of coherent thought, and knew something about how birds of prey caught pigeons,(1) it might have wondered why it was being gripped so... kindly. It was being held, not squeezed. As it was, all it could think was 0000000! (1) And allowing for the fact that all pigeons who knew how birds of prey catch pigeons are dead, and therefore capable of slightly less thought than a living pigeon. [Monstrous Regiment, by Terry Pratchett] %e passage # p. 131 %passage 4 "All the food's been taken but there's carrots and parsnips in a little garden down the hill a bit," Shufti said as they walked away. "It'd be s-stealing from the dead," said Wazzer. "Well, if they object they can hold on, can't they?" said Shufti. "They're underground already!" [Monstrous Regiment, by Terry Pratchett] %e passage # p. 160 %passage 5 "And there you have it, Sergeant Towering," said the lieutenant, turning to the prisoner. "Of course, we all know there is some atrocious behavior in times of war, but it is not the sort of thing we would expect of a royal prince.(1) If we are to be pursued because a gallant young soldier prevented matters from becoming even more disgusting, then so be it." (1) Lieutenant Blouse read only the more technical history books. [Monstrous Regiment, by Terry Pratchett] %e passage # p. 176 (fire: almost certainly to make tea) %passage 6 There are three things a soldier wants to do when there's a respite on the road. One involves lighting a cigarette, one involves lighting a fire, and the other involves no flames at all but does, generally, require a tree.(1) (1) Technically, a tree is not required, but seems to be insisted upon for reasons of style. [Monstrous Regiment, by Terry Pratchett] %e passage # p. 179 ('humor': American spelling is accurate) %passage 7 Maladict dropped his crossbow, which fired straight up into the air,(1) and sat down with his head in his hands. (1) And failed to hit anything, especially a duck. This is so unusual in situations like this that it must be reported under the new humor regulations. If it had hit a duck, which quacked and landed on somebody's head, this would, of course, have been very droll and would certainly have been reported. Instead, the arrow drifted in the breeze a little on the way and landed in an oak tree some thirty feet away, where it missed a squirrel. [Monstrous Regiment, by Terry Pratchett] %e passage # p. 284 (soldiers disguised as washerwomen in order to sneak into an # enemy-controlled castle have been put to work doing the laundry) %passage 8 "Look at this, will you?" said Shufti, waving a sodden pair of men's long pants at her. "They keep putting the colors in with the whites." "Well, so what? These are /enemy/ long johns," said Polly. "Yes, but there's such a thing as doing it properly! Look, they put in this red pair and all the others are going pink." "And? I used to love pink when I was about seven."(1) "But pale pink? On a man?" Polly looked at the next tub for a moment and patted Shufti on the shoulder. "Yes. It is /very/ pale, isn't it? You'd better find a couple more red items," she said. "But that'll make it even worse--" Shufti began. "That was an /order/, soldier," Polly whispered in her ear. "And add some starch." "How much?" "All you can find." (1) It is an established fact that, despite everything society can do, girls of seven are magnetically attracted to the color pink. [Monstrous Regiment, by Terry Pratchett] %e passage %e title # # # %title A Hat Full of Sky (11) # p. 405 (HarperTempest edition) %passage 1 Why do you go away? So that you can come back. So that you can see the place you came from with new eyes and extra colors. And the people there see you differently, too. Coming back to where you started is not the same as never leaving. [A Hat Full of Sky, by Terry Pratchett] %e passage # pp. 11-12 %passage 2 Miss Tick was a sort of witch finder. That seemed to be how witchcraft worked. Some witches kept a magical lookout for girls who showed promise, and found them an older witch to help them along. They didn't teach you how to do it. They taught you how to know what you were doing. Witches were a bit like cats. They didn't much like one another's company, but they /did/ like to know where all the other witches were, just in case they needed them. And what you might need them for was to tell you, as a friend, that you were beginning to cackle. [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 31 %passage 3 "Oh," said Miss Tick. But because she was a teacher as well as a witch, and probably couldn't help herself, she added, "The funny thing is, of course, that officially there is no such thing as a white horse. They're called gray."(1) (1) She had to say that because she was a witch and a teacher, and that's a terrible combination. They want things to be /right/. They like things to be /correct/. If you want to upset a witch, you don't have to mess around with charms and spells--you just have to put her in a room with a picture that's hung slightly crooked and watch her squirm. [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 51 %passage 4 "Oh," she said. "It's like cat's cradle." "You've played that, have you?" said Miss Tick vaguely, still concentrating. "I can do all the common shapes," said Tiffany. "The Jewels and the Cradle and the House and the Flock and the Three Old Ladies, One With a Squint, Carrying the Bucket of Fish to Market When They Meet the Donkey, although you need two people for that one, and I only ever did it once, and Betsy Tupper scratched her nose at the wrong moment and I had to get some scissors to to cut her loose..." [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 106 (passage starts mid-paragraph; 'doon' is accurate) %passage 5 "[...] It's a bad case o' the thinkin' he's caught, missus. When a man starts messin' wi' the readin' and the writin', then he'll come doon with a dose o' the thinkin' soon enough. I'll fetch some o' the lads and we'll hold his head under water until he stops doin' it--'tis the only cure. It can kill a man, the thinkin'." [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 107 ('braked', 'Polis'men', 'dinna' all accurate) %passage 6 "I never braked my word yet," said Rob. "Except to Polis'men and other o' that kidney, ye ken, and they dinna count." [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 111 (passage starts mid-paragraph; 'land o' the living': the Nac Mac # Feegle believe that they're dead and are on Discworld because it # is heaven, also that if they die on Discworld they'll be reborn # on their "real world"; 'big wee hag': Tiffany, apprentice witch # [big: she's human, wee: she's still a child, hag: she's a witch]) %passage 7 "[...] Now lads, ye ken all about hivers. They cannae be killed! But 'tis oor duty to save the big wee hag, so this is, like, a sooey-side mission and ye'll probably all end up back in the land o' the living doin' a borin' wee job. So... I'm askin' for volunteers!" Every Feegle over the age of four automatically put his hand up. "Oh, come /on/," said Rob. "You canna /all/ come! Look, I'll tak'... Daft Wullie, Big Yan, and you... Awf'ly Wee Billy Bigchin. An' I'm takin' no weans, so if yez under three inches high, ye're not comin'! Except for ye, o' course, Awf'ly Wee Billy. As for the rest of youse, we'll settle this the traditional Feegle way. I'll tak' the last fifty men still standing!" He beckoned the chosen three to a place in the corner of the mound while the rest of the crowd squared up cheerfully. A Feegle liked to face enormous odds all by himself, because it meant you didn't have to look where you were hitting. [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 114 (passage starts mid-paragraph) %passage 8 [...] It was a mad, desperate plan, which was very dangerous and risky and would require tremendous strength and bravery to make it work. Put like that, they agreed to it instantly. [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 225 (last paragraph continues--they didn't understand the contents # since most pictsies can't read) %passage 9 "Oh, aye?" he said. "We looked at her diary loads o' times. Nae harm done." "You /looked/ at her /diary/?" said Miss Level, horrified. "Why?" Really, she though later, she should have expected the answer. "Cuz it wuz locked," said Daft Wullie. "If she didna want anyone tae look at it, why'd she keep it at the back o' her sock drawer? [...]" [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 240 (passage starts mid-paragraph; 'frannit' is accurate) %passage 10 "[...] All we need tae do is frannit a wheelstone on it and it'll tak' us right where she is."(1) (1) If anyone knew what this meant, they'd know a lot more about the Nac Mac Feegle's way of traveling. [A Hat Full of Sky, by Terry Pratchett] %e passage # p. 351 (the hiver's dialog is telepathic--internal would be more # accurate--and occurs in italics without quote marks) %passage 11 Tiffany took a deep breath. This was about words, and she knew about words. "Here is a story to believe," she said. "Once we were blobs in the sea, and then fishes, and then lizards and rats, and then monkeys, and hundreds of things in between. This hand was once a fin, this hand once had claws! In my human mouth I have the pointy teeth of a wolf and the chisel teeth of a rabbit and the grinding teeth of a cow! Our blood is as salty as the sea we used to live in! When we're frightened, the hair on our skin stands up, just like it did when we had fur. We /are/ history! Everything we've ever been on the way to becoming us, we still are. Would you like to hear the rest of the story?" /Tell us/, said the hiver. "I'm made up of the memories of my parents and grandparents, all my ancestors. They're in the way I look, in the color of my hair. And I'm made up of everyone I've ever met who's changed the way I think. So who is 'me'?" [A Hat Full of Sky, by Terry Pratchett] %e passage %e title # # # %title Going Postal (13) %passage 1 What was magic, after all, but something that happened at the snap of a finger? Where was the magic in that? It was mumbled words and weird drawings in old books and in the wrong hands it was dangerous as hell, but not one half as dangerous as it could be in the right hands. [Going Postal, by Terry Pratchett] %e passage # p. 5 (Harper Torch edition) %passage 2 They say that the prospect of being hanged in the morning concentrates a man's mind wonderfully; unfortunately, what the mind inevitably concentrates on is that, in the morning, it will be in a body that is going to be hanged. [Going Postal, by Terry Pratchett] %e passage # p. 18 %passage 3 There is a saying, "You can't fool an honest man," which is much quoted by people who make a profitable living by fooling honest men. Moist never tried it, knowingly anyway. If you did fool an honest man, he tended to complain to the local Watch, and these days they were harder to buy off. Fooling dishonest men was a lot safer, and somehow, more sporting. And, of course, there were so many more of them. You hardly had to aim. [Going Postal, by Terry Pratchett] %e passage # p. 47 (passage starts mid-paragraph; # italics because it's Moist von Lipwig's internal monolog) %passage 4 /What kind of man would put a known criminal in charge of a major branch of government? Apart from, say, the average voter./ [Going Postal, by Terry Pratchett] %e passage # p. 137 %passage 5 Now he could see the mysterious order clearly. They were robed, of course, because you couldn't have a secret order without robes. They had pushed the hoods back now, and each man(1) was wearing a peaked cap with a bird skeleton wired to it. (1) Women are always significantly underrepresented in secret orders. [Going Postal, by Terry Pratchett] %e passage # p. 184 ('Tubso' and 'Bissonomy' are accurate) %passage 6 Just below the dome, staring down from their niches, were statues of the Virtues: Patience, Chastity, Silence, Charity, Hope, Tubso, Bissonomy,(1) and Fortitude. (1) Many cultures practice neither of these in the hustle and bustle of the modern world, because no one can remember what they are. [Going Postal, by Terry Pratchett] %e passage # pp. 249-250 (Moist and Miss Dearheart are in a fancy restaurant) %passage 7 She froze, staring over his shoulder. He saw her right hand scrabble frantically among the cutlery and grab a knife. "That bastard has just walked into the place!" she hissed. "Reacher Gilt! I'll just kill him and join you for the pudding..." "You can't do that!" hissed Moist. "Oh? Why not?" "You're using the wrong knife! That's for the fish! You'll get into trouble!" She glared at him, but her hand relaxed, and something like a smile appeared on her face. "They don't have a knife for stabbing rich, murdering bastards?" she said. "They bring it to the table when you order one," said Moist urgently. "Look, this isn't the Drum, they don't just throw the body into the river! They'll call the Watch! Get a grip. Not on a knife! And get ready to run." "Why?" "Because I forged his signature on Grand Trunk notepaper to get us in here, that's why." [Going Postal, by Terry Pratchett] %e passage # pp 260-261 (Mr. Groat: elderly postal employee recently attacked in # the palacial but severely dilapidated post office; # "his imagination": Moist's; "him": Mr. Groat; "he": Moist) %passage 8 The vision of Mr. Groat's chest kept bumping insistently against his imagination. It looked as though something with claws had taken a swipe at him, and only the thick uniform coat prevented him from being opened like a clam. But that didn't sound like a vampire. They weren't messy like that. It was a waste of good food. Nevertheless, he picked up a piece of smashed chair. It had splintered nicely. And the nice thing about a stake through the heart was that it also worked on non-vampires. [Going Postal, by Terry Pratchett] %e passage # p. 262 (Stanley, a young postal employee who collects pins, recently # fought off /something/ using a bag of pins as a weapon) # [this passage doesn't have a very satisfactory ending...] %passage 9 You probably couldn't /kill/ a vampire with pins... And after a thought like that is when you realize that however hard you try to look behind you, there's a behind you, behind you, where you aren't looking. Moist flung his back to the cold stone wall where he slithered along it until he ran out of wall and acquired a doorframe. [Going Postal, by Terry Pratchett] %e passage #p. 278 ('thoughted' and 'thoughting' are accurate) %passage 10 "Oh, Mr. Lipwig!" It is not often that a wailing woman rushes into a room and throws herself at a man. It had never happened to Moist before. Now it happened, and it seemed such a waste that the woman was Miss Maccalariat. She tottered forward and clung to the startled Moist, tears streaming down her face. "Oh, Mr. Lipwig!" she wailed. "Oh, Mr. Lipwig!" Moist reeled under her weight. She was dragging at his collar so hard that he was likely to end up on the floor, and the thought of being found on the floor with Miss Maccalariat was--well, a thought that just couldn't be thoughted. The head would explode before thoughting it. [Going Postal, by Terry Pratchett] %e passage #p. 315 %passage 11 Always remember that the crowd that applauds your coronation is the same crowd that will applaud your beheading. People like a show. [Going Postal, by Terry Pratchett] %e passage # p. 326 (homage to "To Have and Have Not"; Lauren Bacall's character says # to Humphrey Bogart's character, "You know how to whistle, don't # you Steve? Just put your lips together and--blow." # Miss Dearheart's slight pause seems better placed...) %passage 12 Miss Dearheart stubbed out her cigarette. "Go up there tonight, Mr. Lipwig. Get yourself a little bit closer to heaven. And then get down on your knees and pray. You know how to pray, don't you? You just put your hands together--and hope." [Going Postal, by Terry Pratchett] %e passage # p. 333 ('crackers' have been sending and receiving clandestine clacks # messages without owners/operators of the clacks network noticing) %passage 13 It was a little like stealing. It was exactly like stealing. It was, in fact, stealing. But there was no law against it, because no one knew the crime existed, so is it really stealing if what's stolen isn't missed? And is it stealing if you're stealing from thieves? Anyway, all property is theft, except mine. [Going Postal, by Terry Pratchett] %e passage %e title # # # %title Thud! (7) # p. 39 (Harper Torch edition; passage starts mid-paragraph; speaker is Nobby) %passage 1 "Why mess about with a cunning plan when a simple one will do?" [Thud!, by Terry Pratchett] %e passage # pp. 334-336 (originally transcribed from some other edition) %passage 2 He wanted to sleep. He'd never felt this tired before. Vimes slumped to his knees, and then fell sideways on to the sand. When he forced his eyes open, he saw pale stars above him, and had, once again, the sensation that there was someone else present. He turned his head, wincing at the stab of pain, and saw a small but brightly lit folding chair on the sand. A robed figure was reclining in it, reading a book. A scythe was stuck in the sand beside it. A white, skeletal hand turned a page. 'You'll be Death, then?' said Vimes, after a while. AH, MISTER VIMES, ASTUTE AS EVER. GOT IT IN ONE, said Death, shutting the book on his finger to keep the place. 'I've seen you before.' I HAVE WALKED WITH YOU MANY TIMES, MISTER VIMES. 'And this is /it/, is it?' HAS IT NEVER STRUCK YOU THAT THE CONCEPT OF A WRITTEN NARRATIVE IS SOMEWHAT STRANGE? said Death. Vimes could tell when people were trying to avoid something they really didn't want to say, and it was happening here. 'Is it?' he insisted. 'Is this it? This time I die?' COULD BE. 'Could be? What sort of answer is that?' said Vimes. A VERY ACCURATE ONE. YOU SEE, YOU ARE HAVING A NEAR-DEATH EXPERIENCE, WHICH INESCAPABLY MEANS THAT I MUST UNDERGO A NEAR-/VIMES/ EXPERIENCE. DON'T MIND ME. CARRY ON WITH WHATEVER YOU WERE DOING. I HAVE A BOOK. Vimes rolled over on to his stomach, gritted his teeth, and pushed himself on to his hands and knees again. He managed a few yards before slumping back down. He heard the sound of a chair being moved. 'Shouldn't you be somewhere else?' he said. I AM, said Death, sitting down again. 'But you're here!' AS WELL. Death turned a page and, for a person without breath, managed a pretty good sigh. IT APPEARS THAT THE BUTLER DID IT. 'Did what?' IT IS A MADE-UP STORY. VERY STRANGE. ALL ONE NEEDS TO DO IS TURN TO THE LAST PAGE AND THE ANSWER IS THERE. WHAT, THEREFORE, IS THE POINT OF DELIBERATEDLY NOT KNOWING? It sounded like gibberish to Vimes, so he ignored it. Some of the aches had gone, although his head still hammered. There was an empty feeling everywhere. He just wanted to sleep. [Thud!, by Terry Pratchett] %e passage # pp. 225-226 %passage 3 And I'm going home, Vimes repeated to himself. Everyone wants something from Vimes, even though I'm not the sharpest knife in the drawer. Hell, I'm probably a spoon. Well I'm going to be Vimes, and Vimes reads /Where's My Cow?/ to Young Sam at six o'clock. With the noises done right. [Thud!, by Terry Pratchett] %e passage # pp. 261-262 %passage 4 Fred Colon peered through the bars. He was, on the whole, a pretty good jailer; he always had a pot of tea on the go, he was, as a general rule, amiably disposed to most people, he was too slow to be easily fooled, and he kept the cell keys in a box in the bottom drawer of his desk, a long way out of reach of any stick, hand, dog, cunningly thrown belt, or trained Klatchian monkey spider.(1) (1) Making Fred Colon possibly unique in the annals of jail history. [Thud!, by Terry Pratchett] %e passage # p. 287 (American spelling of 'theater' is accurate [Harper Torch edition]) %passage 5 Brushing aside cobwebs with one hand and holding up a lantern with the other, Sybil led the way past boxes of MEN'S BOOTS, VARIOUS; RISIBLE PUPPETS, STRING & GLOVE; MODEL THEATER AND SCENERY. Maybe that was the reason for their wealth: they bought things that were built to last, and now they seldom had to buy anything at all. Except food, of course, and even then Vimes would not have been surprised to see boxes labeled APPLE CORES, VARIOUS, or LEFTOVERS, NEED EATING UP.(1) (1) That was a phrase of Sybil's that got to him. She'd announce at lunch, "we must have the pork tonight, it needs eating up." Vimes never had an actual problem with this, because he'd been raised to eat what was put in front of him, and do it quickly, too, before someone else snatched it away. He was just puzzled at the suggestion that he was there to do the food a favor. [Thud!, by Terry Pratchett] %e passage # pp. 296-297 %passage 6 "Tell me Drumknott, are you a betting man at all?" "I have been know to have the occasional 'little flutter,' sir." "Given, then, a contest between an invisible and very powerful quasidemonic /thing/ of pure vengence on the one hand, and the commander on the other, where would you wager, say... one dollar?" "I wouldn't, sir. That looks like one that would go to the judges." "Yes," said Vetinari, staring thoughtfully at the closed door. "Yes, /indeed/." [Thud!, by Terry Pratchett] %e passage # p. 351 ('teeth-aching' probably ought to have been 'teeth-achingly') %passage 7 Vimes reached up and took a mug of water from Angua. It was teeth-aching cold and the best drink he'd ever tasted. And his mind worked fast, flying in emergency supplies of common sense, as human minds do, to construct a huge anchor in sanity and prove that what happened hadn't really happened and, if it had happened, hadn't happened very much. It was all mystic, that's what it was. Oh, it /might/ all be true, but how could you ever tell? You had to stick to the things you can see. And you had to keep reminding yourself of that, too. Yeah, that was it. What had really happened, eh? A few signs? Well, anything can look like you want it to, if you're worried and confused enough, yes? A sheep can look like a cow, right? Ha! [Thud!, by Terry Pratchett] %e passage %e title # # # %title Wintersmith (16) # p. 82 (HarperTeen edition--presumably HarperTempest suffered a name change) %passage 1 That's Third Thoughts for you. When a huge rock is going to land on your head, they're the thoughts that think: Is that an igneous rock, such as granite, or is it sandstone? [Wintersmith, by Terry Pratchett] %e passage p. 113 %passage 2 They say that there can never be two snowflakes that are exactly alike, but has anyone checked lately? [Wintersmith, by Terry Pratchett] %e passage # pp. 32-33 %passage 3 All witches are a bit odd. Tiffany had got used to odd, so that odd seemed quite normal. There was Miss Level, for example, who had two bodies, although one of them was imaginery. Mistress Pullunder, who bred pedigreed earthworms and gave them all names... well, she was hardly odd at all, just a bit peculiar, and anyway earthworms were quite interesting in a basically uninterestng kind of way. And there had been Old Mother Dismass, who suffered from bouts of temporal confusion, which can be quite strange when it happens to a witch; her mouth never moved in time with her words, and sometimes her footsteps came down the stairs ten minutes before she did. But when it came to odd, Miss Treason didn't just take the cake, but a packet of biscuits too, with sprinkles on the top, and also a candle. [Wintersmith, by Terry Pratchett] %e passage # p. 34 ('villages': plural is accurate; 'clonk-clank' is rendered bold) %passage 4 Then there was her clock. It was heavy and made of rusty iron by someone who was more blacksmith than watchmaker, which was why it went *clonk-clank* instead of /tick-tock/. She wore it on her belt and could tell the time by feeling the stubby little hands. There was a story in the villages that the clock was Miss Treason's heart, which she'd used ever since her first heart died. But there were lots of stories about Miss Treason. [Wintersmith, by Terry Pratchett] %e passage # p. 40 (Boffo) %passage 5 First Sight and Second Thoughts, that's what a witch had to rely on: First Sight to see what's really there, and Second Thoughts to watch the First Thoughts to check that they were thinking right. Then there were the Third Thoughts, which Tiffany had never heard discussed and therefore kept quiet about; they were odd, seemed to think for themselves, and didn't turn up very often. And they were telling her that there was more to Miss Treason than met the eye. [Wintersmith, by Terry Pratchett] %e passage # p. 53-54 (in Carpe Jugulum, most of the lore [for humans] about how to kill # vampires had been written by long-lived/long-not-defunct vampires # [meaning that it was deliberately full of inaccuracies...]) %passage 6 It was in fact Miss Tick who had written /Witch Hunting for Dumb People/, and she made sure that copies of it found their way into those areas where people still believed that witches should be burned or drowned. Since the only witch ever likely to pass through these days was Miss Tick herself, it meant that if things did go wrong, she'd get a good night's sleep and a decent meal before being thrown into the water. The water was no problem at all for Miss Tick, who had been to the Quirm College for Young Ladies, where you had to have an icy dip every morning to build Moral Fiber. And a No. 1 Bosun's knot was very easy to undo with your teeth, even underwater. [Wintersmith, by Terry Pratchett] %e passage # p. 55-56 %passage 7 Working quickly, she emptied her pockets and started a shamble. Shambles worked. That was about all you could say about them for certain. You made them out of some string and a couple of sticks and anything you had in your pocket at the time. They were a witch's equivalent of those knives with fifteen blades and three screwdrivers and a tiny magnifying glass and a thing for extracting earwax from chickens. You couldn't even say precisely what they did, although Miss Tick thought that they were a way of finding out what things the hidden bits of your own mind already knew. You had to make a shamble from scratch every time, and only from things in your pockets. There was no harm in having interesting things in your pockets, though, just in case. [Wintersmith, by Terry Pratchett] %e passage # p. 69 %passage 8 A witch didn't do things because they seemed like a good idea at the time! That was practically cackling! You had to deal every day with people who were foolish and lazy and untruthful and downright unpleasant, and you could certainly end up thinking that the world would be considerably improved if you gave them a slap. But you didn't because, as Miss Tick had once explained: a) it would make the world a better place for only a very short period of time; b) it would then make the world a slightly worse place; and c) you're not supposed to be as stupid as they are. [Wintersmith, by Terry Pratchett] %e passage # p. 106 (Rob Anybody is married to their kelda, ruler of the clan; # passage continues with three or so pages about Explaining # [focusing on the reactions of the recipient of the explanation: # Pursin' o' the Lips; Foldin' o' the Arms; Tappin' o' the Feets; # and also the reactions of the listening Feegles as they hear # about them] but would end up on the long side if included here) %passage 9 "Aye, but the boy willna be interested in marryin'," said Slightly Mad Angus. "He might be one day," said Billy Bigchin, who'd made a hobby of watching humans. "Most bigjob men get married." "They do?" said a Feegle in astonishment. "Oh, aye." "They want tae get married?" "A lot o' them do, aye," said Billy. "So there's nae more drinkin', and stealin', and fightin'?" "Hey, ah'm still allowed some drinkin' and stealin' and fightin'!" said Rob Anybody. "Aye, Rob, but we canna help noticin' ye also have tae do the Explainin', too." said Daft Wullie. There was a general nodding from the crowd. To Feegles, Explaining was a dark art. It was just so /hard/. [Wintersmith, by Terry Pratchett] %e passage # p. 126-127 (passage starts mid-paragraph; # witches know in advance when they're going to die) %passage 10 "[...] We shall hold the funeral tomorrow afternoon." "Sorry? You mean /before/ you die?" said Tiffany. "Why, of course! I don't see why I shouldn't have some fun!" "Good thinkin'!" said Rob Anybody. "That's the kind o' sensible detail people usually fails tae consider." "We call it a going-away party," said Miss Treason. "Just for witches, of course. Other people tend to get a bit nervous--I can't think why. And on the bright side, we've got that splendid ham that Mr. Armbinder gave us last week for settling the ownership of the chestnut tree, and I'd love to try it." [Wintersmith, by Terry Pratchett] %e passage # p. 129 %passage 11 Some people think that "coven" is a word for a group of witches, and it's true that's what the dictionary says. But the real word for a group of witches is an "argument." [Wintersmith, by Terry Pratchett] %e passage # p. 174-175 (passage starts mid-paragraph; last paragraph continues, but # changes topic so abruptly Tiffany gasps; 'rumbustious' is accurate) %passage 12 "[...] And now I shall tell you something vitally important. It is the secret of my long life." Ah, thought Tiffany, and she leaned forward. "The important thing," said Miss Treason, "is to stay the passage of the wind. You should avoid rumbustious fruits and vegetables. Beans are the worst, take it from me." "I don't think I understand--" Tiffany began. "Try not to fart, in a nutshell." "In a nutshell, I imagine it would be pretty unpleasant!" said Tiffany nervously. She couldn't believe she was being told this. "This is no joking matter," said Miss Treason. "The human body has only so much air in it. You have to make it last. One plate of beans can take a year off your life. I have avoided rumbustiousness all my days. I am an old person and that means what I say is wisdom!" She gave the bewildered Tiffany a stern look. "Do you understand, child?" Tiffany's mind raced. Everything is a test! "No," she said. "I'm not a child and that's nonsense, not wisdom!" The stern look cracked into a smile. "Yes," said Miss Treason. "Total gibberish. But you've got to admit it's a corker, all the same, right? You definitely believed it, just for a moment? The villagers did last year. You should have seen the way they walked about for a few weeks! The strained looks on their faces quite cheered me up! [...]" [Wintersmith, by Terry Pratchett] %e passage # p. 185 (Miss Treason tells people she's 113, but she's actually /only/ 111) %passage 13 MISS EUMENIDES TREASON, AGED ONE HUNDRED AND ELEVEN? Tiffany heard the voice inside her head. It didn't seem to have come through her ears. And she'd heard it before, making her quite unusual. Most people hear the voice of Death only once. [Wintersmith, by Terry Pratchett] %e passage # p. 229 %passage 14 Tiffany had looked up "strumpet" in the Unexpurgated Dictionary, and found it meant "a woman who is no better than she should be" and "a lady of easy virtue." This, she decided after some working out, meant that Mrs. Gytha Ogg, known as Nanny, was a very respectable person. She found virtue easy, for one thing. And if she was no better than she should be, she was just as good as she ought to be. [Wintersmith, by Terry Pratchett] %e passage # p. 360-361 ('wurds' is accurate) %passage 15 "An heroic effect, Mr. Anybody," said Granny. "The first thing a hero must conquer is his fear, and when it comes to fightin', the Nac Mac Feegle don't know the meanin' of the word." "Aye, true enough," Rob grunted. "We dinna ken the meanin' o' thousands o' wurds!" [Wintersmith, by Terry Pratchett] %e passage # p. 398-399 ("Chumsfanleigh" is pronounced "Chuffley") %passage 16 At the back of the Feegles' chalk pit, more chalk had been carved out of the wall to make a tunnel about five feet high and perhaps as long. In front of it stood Roland de Chumsfanleigh (it wasn't his fault). His ancestors had been knights, and they had come to own the Chalk by killing the kings who thought they did. Swords, that's what it had all been about. Swords and cutting off heads. That was how you got land in the old days, and then the rules were changed so that you didn't need a sword to own land anymore, you just needed the right piece of paper. But his ancestors had still hung on to their swords, just in case people thought that the whole thing with the bits of paper had been unfair, it being a fact that you can't please everybody. He'd always wanted to be good with a sword, and it had come as a shock to find that they were so /heavy/. He was great at air sword. In front of a mirror he could fence against his reflection and win nearly all the time. Real swords didn't allow that. You tried to swing them and they ended up swinging you. He'd realized that maybe he was more cut out for bits of paper. Besides, he needed glasses, which could be a bit tricky under a helmet, especially if someone was hitting /you/ with a sword. [Wintersmith, by Terry Pratchett] %e passage %e title # # # %title Making Money (17) # p. 187 (Harper edition -- what's become of Harper Torch?) %passage 1 "I'm an Igor, thur. We don't athk quethtionth." "Really? Why not?" "I don't know, thur. I didn't athk." [Making Money, by Terry Pratchett] %e passage # p. 177 (originally transcribed from some other edition; Harper edition # uses American spelling for "armor") # [some off-duty Watchmen moonlight as bank security guards] %passage 2 The Watch armor he'd lifted from the bank's locker room fitted like a glove. He'd have preferred it to fit like a helmet and breastplate. But, in truth, it probably didn't look any better on its owner, currently swanking along the corridors in the bank's own shiny but impractical armor. It was common knowledge that the Watch's approach to uniforms was one-size- doesn't-exactly-fit-anybody, and that Commander Vimes disapproved of armor that didn't have that kicked-by-trolls look. He liked armor to state clearly that it had been doing its job. [Making Money, by Terry Pratchett] %e passage # pp. 108 (passage starts mid-paragraph) %passage 3 "[...] The world is full of things worth more than gold. But we dig the damn stuff up and then bury it in a different hole. Where's the sense in that? What are we, magpies? Good heavens, /potatoes/ are worth more than gold!" "Surely not!" "If you were shipwrecked on a desert island, what would you prefer, a bag of potatoes or a bag of gold?" "Yes, but a desert island isn't Ankh-Morpork!" "And that proves gold is only valuable because we agree it is, right? It's just a dream. But a potato is always worth a potato, anywhere. Add a knob of butter and a pinch of salt and you've got a meal, /anywhere/. Bury gold in the ground and you'll be worrying about thieves forever. Bury a potato and in due season you could be looking at a dividend of a thousand per cent." [Making Money, by Terry Pratchett] %e passage # pp. 22-24 (Albert Spangler is one of Moist Lipwig's aliases; # 'dyslectic' is accurate) %passage 4 "Let us talk about angels," said Lord Vetinari. "Oh yes, I know that one," said Moist bitterly. "I've heard that one. That's the one you got me with after I was hanged--" Vetinari raised an eyebrow. "Only mostly hanged, I think you'll find. To within an inch of your life." "Whatever! I was hanged! And the worst part of that was finding out I only got two paragraphs in the /Tanty Bugle/!(1) Two paragraphs, may I say, for a life of ingenious, inventive, and strictly nonviolent crime? I could have been an example to the youngsters! Page one got hogged by the Dyslectic Alphabet Killer, and he only maanaged A and W!" "I confess the editor does appear to believe that it is not a proper crime unless someone is found in three alleys at once, but that is the price of a free press. And it suits us both, does it not, that Albert Spangler's passage from this world was... unmemorable?" "Yes, but I wasn't expecting an afterlife like this! I have to do what I'm told for the rest of my life?" "Correction, your new life. That is a crude summary, yes," said Vetinari. "Let me rephrase things, however. Ahead of you, Mr. Lipwig, is a life of respectable quiet contentment, of civic dignity, and, of course, in the fullness of time, a pension. Not to mention, of course, the proud gold-ish chain." Moist winced at this. "And if I /don't/ do what you say?" "Hmm? Oh, you misunderstand me, Mr. Lipwig. That is what will happen to you if you decline my offer. If you accept it, you will survive on your wits against powerful and dangerous enemies, with every day presenting fresh challanges. Someone may even try to kill you." "What? Why?" "You annoy people. A hat goes with the job, incidentally." (1) A periodical published throughout the Plains, noted for its coverage of murder (preferably 'orrible) trials, prison escapes, and the world that in general is surrounded by a chalk outline. Very popular. [Making Money, by Terry Pratchett] %e passage #p. 71 %passage 5 When he got back to the Post Office, Moist looked up the Lavish family in /Whom's Whom/. They were indeed what was known of as "old money," which meant that it had been made so long ago that the black deeds which had originally filled the coffers were now historically irrelevant. Funny, that: a brigand for a father was something you kept quiet about, but a slave-taking pirate for a great-great-great-grandfather was something to boast of over the port. Time turned the evil bastards into rogues, and /rogue/ was a word with a twinkle in its eye and nothing to be ashamed of. [Making Money, by Terry Pratchett] %e passage # p. 72 ('clacks' is a communication system, here analogous to a telegraph) %passage 6 He spotted the flimsy pink clacks among the other stuff and tugged it out quickly. It was from Spike! He read: SUCCESS. RETURNING DAY AFTER TOMMOROW. ALL WILL BE REVEALED. S. Moist put it down carefully. Obviously she'd missed him terribly and was desperate to see him again, but she was stingy about spending Golem Trust money. Also, she'd probably run out of cigarettes. Moist drummed his fingers on the desk. A year ago he'd asked Adora Belle Dearheart to be his wife, and she'd explained that, in fact, he was going to be her husband. It was going to be... well, it was going to be sometime in the near future, when Mrs. Dearheart finally lost patience with her daughter's busy schedule and arranged the wedding herself. But he was a nearly married man, however you looked at it. And nearly married men didn't get mixed up with the Lavish family. A nearly married man was steadfast and dependable and always ready to hand his nearly wife an ashtray. He had to be there for his oneday children, and make sure they slept in a well-ventilated nursery. [Making Money, by Terry Pratchett] %e passage # p. 79 (passage starts mid-paragraph; departed Mrs. Lavish is a bank owner) %passage 7 "[...] Now what, Mr. Death?" NOW? said Death. NOW, YOU COULD SAY, COMES... THE AUDIT. "Oh. There is one, is there? Well, I'm not ashamed." THAT COUNTS. [Making Money, by Terry Pratchett] %e passage # pp. 183-184 (American spelling of 'gray' is accurate) %passage 8 Moist lit the lamp and walked over to the battered wreckage of his wardrobe. Once again he selected the tatty gray suit. It had sentimental value; he had been hanged in it. And it was an unmemorable suit for an unmemorable man, with the additional advantage, unlike black, of not showing up in the dark.(1) [...] (1) Every assassin knew that real black often stood out in the dark, because the night in the city is usually never full black, and that gray or green merge much better. But they wore black anyway, because style trumps utility every time. [Making Money, by Terry Pratchett] %e passage # p. 218 (the Cabinet of Curiosity) %passage 9 "All right, then," said Moist, "/what does it do/?" "We don't know." "How does it work?" "We don't know." "Where did it come from?" "We don't know." "Well, that seems to be all," said Moist sarcastically. "Oh no, one last one: what is it? And let me tell you, I'm agog." "That may be the wrong sort of question to ask," said Ponder, shaking his head. "Technically it appears to be a classic Bag of Holding but with /n/ mouths, where /n/ is the number of items in an eleven-dimensional universe, which are not currently alive, not pink, and can fit in a cubical drawer 14.14 inches on a side, divided by P." "What's P?" "That may be the wrong sort of question." [Making Money, by Terry Pratchett] %e passage # p. 225 (passage starts mid-paragraph) %passage 10 "[...] I'll talk to Dr. Hicks. He's the head of the Department of Postmortem Communications." "Postmortem Com..." Moist began. "Isn't that the same as necroman--" "I said the /Department of Postmortem Communications/," said Ponder very firmly. [...] [Making Money, by Terry Pratchett] %e passage # p. 247 (it's a spirit summoned by Dr. Hicks that is describing the art/risk) %passage 11 "Necromancy is a fine art?" said Moist. "None finer, young man. Get things just a tiny bit wrong and the spirits of the vengeful dead may enter your head via your ears and blow your brains out down your nose." The eyes of Moist and Adora Belle focused on Dr. Hicks like those of an archer on his target. He waved his hands frantically and mouthed, "Not very often!" [Making Money, by Terry Pratchett] %e passage # p. 269 %passage 12 "If you can't stand the heat, get off the pot, that's what I always say," said a senior clerk, and there was a general murmur of agreement. [Making Money, by Terry Pratchett] %e passage # p. 264 (passage starts mid-paragraph) %passage 13 [...] if the fundamental occult maxim "as above, so below" was true, then so was "as below, so above"... [Making Money, by Terry Pratchett] %e passage # p. 280 %passage 14 "In the Old Country we have a thaying," Igor volunteered. "A what?" "A thaying. We thay, 'if you don't want the monthter you don't pull the lever.'" "You don't think I've gone mad, do you, Igor?" "Many great men have been conthidered mad, Mr. Hubert. Even Dr. Hanth Forvord wath called mad. But I put it to you: could a madman have created a revolutionary living-brain extractor?" [Making Money, by Terry Pratchett] %e passage # p. 302 %passage 15 There was a saying: "Old necromancers never die." When he told them this, people would say "... and?" and Hicks would have to reply, "That's all of it, I'm afraid. Just 'Old necromancers never die.'" [Making Money, by Terry Pratchett] %e passage # p. 336 (passage starts mid-paragraph) %passage 16 [...] What the iron maiden was to stupid tyrants, the committee was to Lord Vetinari; it was only slightly more expensive,(1) far less messy, considerably more efficient, and, best of all, you had to /force/ people to climb inside the iron maiden. (1) The only real expense was tea and biscuits halfway through, which seldom happened with the iron maiden. [Making Money, by Terry Pratchett] %e passage # p. 361 (Mr. Slant is a zombie) %passage 17 "Mrs. Lavish, a lady many of us were privileged to know, recently confided in me that she was dying," said Vetinari. "She asked me for advice on the future of the bank, given that her obvious heirs were, in her words, 'as nasty a bunch of weasels as you could ever hope not to meet--'" All thirty-one of the Lavish lawyers stood up and spoke at once, incuring a total cost to clients of $AM119.28p. Mr. Slant glared at them. Mr. Slant did not, despite what had been said, have the respect of Ankh- Morpork's legal profession. He commanded its fear. Death had not diminished his encyclopedic memory, his guile, his talent for corkscrew reasoning, and the vitriol of his stare. Do not cross me this day, it advised the lawyers. Do not cross me, for if you do I will have the flesh from your very bones and the marrow therein. You know those leather-bound tomes you have on the wall behind your desks to impress your clients? I have read them all, and wrote half of them. Do not try me. I am not in a good mood. One by one, they sat down.(1) (1) Total cost, including time and disbursements: $AM253.16p. [Making Money, by Terry Pratchett] %e passage %e title # # # %title Unseen Academicals (12) # p. 68 (Harper edition) %passage 1 Be one of the crowd? It went against everything a wizard stood for, and a wizard would not stand for anything if he could sit down for it, but even sitting down, you had to stand out. [Unseen Academicals, by Terry Pratchett] %e passage # p. 1 (footnote, so "(1)" ought to be "(2)", but somebody would complain...) %passage 2 Technically, the city of Ankh-Morpork is a Tyranny, which is not always the same thing as a monarchy, and in fact even the post of Tyrant has been somewhat redefined by the incumbent, Lord Vetinari, as the only form of democracy that works. Everyone is entitled to vote, unless disqualified by reason of age or not being Lord Vetinari. And yet it does work. This has annoyed a number of people who feel, somehow, that it should not work, and who want a monarch instead, thus replacing a man who has achieved his position by cunning, a deep understanding of the realities of the human psyche, breathtaking diplomancy, a certain prowess with the stiletto dagger, and, all agree, a mind like a finely balanced circular saw, with a man who has got there by being born.(1) However, the crown has hung on anyway, as crowns do--on the Post Office and the Royal Bank and the Mint and, not least, in the sprawling, brawling, squalling consciousness of the city itself. Lots of things live in that darkness. There are all kinds of darkness, and all kinds of things can be found in them, imprisoned, banished, lost or hidden. Sometimes they escape. Sometimes they simply fall out. Sometimes they just can't take it any more. (1) A third proposition, that the city be governed by a choice of respectable members of the community who would promise not to give themselves airs or betray the public trust at every turn, was instantly the subject of music hall jokes all over the city. [Unseen Academicals, by Terry Pratchett] %e passage # p. 16 %passage 3 A wizard could do what he liked in his own study, and in the old days that had largely meant smoking anything he fancied and farting hugely without apologizing. These days it meant building out into a congruent set of dimensions. Even the Archchancellor was doing it, which made it hard for Ponder to protest: he had half a mile of trout stream in his bathroom, and claimed that messin' about in his study was what kept a wizard out of mischief. And, as everyone knew, it did. It generally got him into trouble instead. [Unseen Academicals, by Terry Pratchett] %e passage # p. 18 (Ridcully is furious at the former Dean, who left UU to become a # rival [Arch-]Chancellor at Brazeneck University in Pseudopolis) %passage 4 "Remuneration? Since when did a wizard work for wages? We are pure academics, Mister Stibbons! We do not care for mere money!" Unfortunately, Ponder was a clear logical thinker who, in times of mental confusion, fell back on reason and honesty, which, when dealing with an angry Archchancellor, were, to use the proper academic term, unhelpful. And he neglected to think strategically, always a mistake when talking to fellow academics, and as a result made the mistake of employing, as at this point, common sense. "That's because we never actually pay for anything very much," he said, "and if anyone needs any petty cash they just help themselves from the big jar--" "We are part of the very fabric of the university, Mister Stibbons! We take only what we require! We do not seek wealth! And most certainly we do not accept a 'post of vital importance which includes an attractive package of remuneration,' whatever the hells that means, 'and other benefits including a generous pension!' A pension, mark you! When has a wizard ever retired?" [Unseen Academicals, by Terry Pratchett] %e passage # p. 19 (She: plump Glenda; Her: fashion-model-to-be Juliet) %passage 5 She was, in fact, quite a pleasant looking girl, even if her bosom had clearly been intended for a girl two feet taller; but she was not Her.(1) (1) The Egregious Professor of Grammar and Usage would have corrected this to "she was not she," which would have caused the Professor of Logic to spit out his drink. [Unseen Academicals, by Terry Pratchett] %e passage # p. 48 (He: Nutt, a key element of the story who doesn't figure in any # of the other selected passages...) %passage 6 He'd tried wandering around the other cellars, but there was nothing much happening at night, and people gave him funny looks. Ladyship did not rule here. But wizards are a messy lot and nobody tidied up much and lived to tell the tale, so all sorts of old storerooms and junk-filled workshops became his for the use of. And there was so much for a lad with keen night vision to find. He had already seen some luminous spoon ants carrying a fork, and, to his surprise, the forgotten mazes were home to that very rare indoorovore, the Uncommon Sock Eater. There were some things living up in the pipes, too, which periodically murmured "Awk! Awk!" Who knew what strange monsters made there home here? [Unseen Academicals, by Terry Pratchett] %e passage # p. 58 %passage 7 Truth is female, since truth is beauty rather than handsomeness; this, Ridcully reflected as the Council grumbled in, would certainly explain the saying that a lie could run around the world before Truth got its, correction, /her/ boots on, and since she would have to choose which pair--the idea that any woman in the position to choose would have just one pair of boots being beyond rational belief. Indeed, as a goddess she would have lots of shoes, and thus many choices: comfy shoes for home truths, hobnail boots for unpleasant truths, simple clogs for universal truths and possibly some kind of slipper for self-evident truth. More important right now was what kind of truth he was going to have to impart to his colleagues, and he decided not on the whole truth, but instead on nothing but the truth, which dispensed with the need for honesty. [Unseen Academicals, by Terry Pratchett] %e passage # p. 166 (see "the wrong sort of question" passage from /Making Money/ # for a description of the Cabinet; items removed from it have to # be returned within 14:14 hours or they're drawn back magically; # student in question had removed a sandwich and then eaten it) %passage 8 "Yes, sir?" said Ponder wearily. "Promote him. Whatever level he is, move him up one." "I think that'll send the wrong kind of signal," Ponder tried. "On the contrary, Mister Stibbons. It will send exactly the right kind of message to the student body." "But he disobeyed an express order, may I point out?" "That's right. He showed independent thinking and a certain amount of pluck, and in the course of so doing added valuable data to our understanding of the Cabinet." "But he might have destroyed the whole university, sir." "Right, in which case he would have been vigorously disciplined, if we'd been able to find anything left of him. But he didn't and he was lucky and we need lucky wizards. Promote him, on the direct order of me, not pp'd at all. Incidentally, how loud were his screams?" [Unseen Academicals, by Terry Pratchett] %e passage # p. 192-193 ('pants': underpants; 'football': soccer ;-) %passage 9 "You will arrange yourself into two teams, set up goals, and strive to win! No man will leave the field of play unless injured! The hands are not to be used, is that clear? Any questions?" A hand went up. Ridcully sought the attached face. "Ah, Rincewind," he said, and, because he was not a determinedly unpleasant man, amended this to, "Professor Rincewind, of course." "I would like permission to fetch a note from my mother, sir." Ridcully sighed. "Rincewind, you once informed me, to my everlasting puzzlement, that you never knew your mother because she ran away before you were born. Distinctly remember writing it down in my diary. Would you like another try?" "Permission to go and find my mother?" Ridcully hesitated. The Professor of Cruel and Unusual Geography had no students and no real duties other than to stay out of trouble. Although Ridcully would never admit it, it was against all reason an emeritus position. Rincewind was a coward and an unwitting clown, but he had several times saved the world in slightly puzzling circumstances. He was a luck sink, the Archchancellor decided, doomed to being a lightning rod for the fates so that everyone else didn't have to. Such a person was worth all his meals and laundry (including an above-average level of soiled pants) and a bucket of coal every day even if he was, in Ridcully's opinion, a bit of a whiner. However, he was fast, and therefore useful. "Look," said Rincewind, "a mysterious urn turns up and suddenly it's all about football. That bodes. It means that something bad is going to happen." "Come now, it could be something wonderful," Ridcully protested. Rincewind appeared to give this due consideration. "Could be wonderful, will be dreadful. Sorry, that's how it goes." "This is Unseen University, Rincewind. What is there to fear?" Ridcully said. "Apart from me, of course. Good heavens, this is a sport." He raised his voice. "Arrange yourselves into two teams and play football!" [Unseen Academicals, by Terry Pratchett] %e passage # p. 268 (passage starts mid-paragraph; Glenda is cleaning UU's Night Kitchen) %passage 10 [...] If you wanted a job done properly, you had to do it yourself. Juliet's verison of cleanliness was next to godliness, which was to say it was erratic, past all understanding and seldom seen. [Unseen Academicals, by Terry Pratchett] %e passage # pp. 358-359 %passage 11 "Well, big day, lads!" said Ridcully. "Looks like there's going to be a nice day for it as well. They're all over there waiting for us to give them a show. I want you to approach this in the best traditions of Unseen University sportsmanship, which is to cheat whenever you are unobserved, though I fear that the chance of anyone being unobserved today is remote. But in any case, I want you to give it one hundred and ten percent." "Excuse me, Archchancellor," said Ponder Stibbons. "I understand the sense of what you are saying, but there is only one hundred percent." "Well, they could give it one hundred and ten percent if they tried harder," said Ridcully. "Well, yes and no, sir. But, in fact, that would mean that you had just made the one hundred percent bigger while it would still be one hundred percent. Besides, there is only so fast a man can run, only so high a man can jump. I just wanted to make the point." "Good point, well made," said Ridcully, dismissing it instantly. [...] [Unseen Academicals, by Terry Pratchett] %e passage # p. 363 (more lyrics occur later on; they're generally about using # economics to conquer any opposition) %passage 12 The singing of the National Anthem was always a ragged affair, the good people of Ankh-Morpork feeling that it was unpatriotic to sing songs about how patriotic you were, taking the view that someone singing a song about how patriotic they were was either up to something or a Head of State.(1) An additional problem today lay in the acoustics of the arena, which were rather too good, coupled with the fact that the speed of sound at one end of the stadium was slightly offbeat compared with the other end, a drawback exacerbated when both sides tried to recover the gap. These acoustical anomalies did not count for much if you were standing next to Mustrum Ridcully, as the Archchancellor was one of those gentleman who will sing it beautifully, correctly enunciated and very, very loudly. "'When dragons belch and hippos flee, my thoughts, Ankh-Morpork, are of thee.'" he began. (1) i.e., up to something. [Unseen Academicals, by Terry Pratchett] %e passage %e title # # # %title I Shall Wear Midnight (13) # p. 447 (Harper edition; this passage is a quote from the "Authur's Note", # three extra pages after the conclusion of the story; there is a # similar, slightly shorter version of this in the text on p. 236, # where it's preceded by "The past needs to be remembered." but # lacks the final 'going wrong' sentence) %passage 1 It is important that we know where we come from, because if you do not know where you come from, then you don't know where you are, and if you don't know where you are, you don't know where you're going. And if you don't know where you're going, you're probably going wrong. [I Shall Wear Midnight, by Terry Pratchett] %e passage # pp. 429-430 (passage starts mid-paragraph and ends mid-paragraph) %passage 2 "[...] There have been times, lately, when I dearly wished that I could change the past. Well, I can't, but I can change the present, so that when it becomes the past it will turn out to be a past worth having. [...]" [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 2 (passage starts mid-paragraph; scene is a village fair) %passage 3 [...] And so here, [...], you heard the permanent scream of, well, everyone. It was called having fun. The only people not making any noise were the thieves and pickpockets, who went about their business with commendable silence, and they didn't come near Tiffany; who would pick a witch's pocket? You would be lucky to get all your fingers back. At least, that's what they feared, and a sensible witch would encourage them in this fear. [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 61 %passage 4 /The hare runs into the fire./ Had she seen that written down anywhere? Had she heard it as part of a song? A nursery rhyme? What had the hare got to do with anything? But she was a witch, after all, and there was a job to do. Mysterious omens could wait. Witches knew that mysterious omens were around all the time. The world was always very nearly drowning in mysterious omens. You just had to pick the one that was convenient. [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 64 %passage 5 That was the thing about thoughts. They thought themselves, and then dropped into your head in the hope that you would think so too. You had to slap them down, thoughts like that; they would take a witch over if she let them. And then it would all break down, and nothing would be left but the cackling. [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 65 (passage starts mid-paragraph) %passage 6 "[...] It just so happens that I was passing by, ye ken, and not following ye at all. One of them coincidences." "There have been a lot of those coincidences lately," said Tiffany. "Aye," said Rob, grinning, "it must be another coincidence." [I Shall Wear Midnight, by Terry Pratchett] %e passage # pp. 179-180 %passage 7 Tiffany cleared her throat. "Well," she said, "I suppose Rob Anybody would tell you that there are times when promises should be kept and times when promises should be broken, and it takes a Feegle to know the difference." Mrs. Proust grinned hugely. "You could almost be from the city, Miss Tiffany Aching." [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 183 (Wee Mad Arthur is a member of the Ankh-Morpork Watch; he was a # foundling raised by gnomes and didn't know he was a Feegle until # he met with the ones accompanying Tiffany) %passage 8 Despite himself, Wee Mad Arthur was grinning. "Have you boys got no shame?" Rob Anybody matched him grin for grin. "I couldna say," he replied, "but if we have, it probably belonged tae somebody else." [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 219 (footnote) %passage 9 There is a lot of folklore about equestrian statues, especially the ones with riders on them. There is said to be a code in the number and placement of the horse's hooves: If one of the horse's hooves is in the air, the rider was wounded in battle; two legs in the air means that the rider was killed in battle; three legs in the air indicates that the rider got lost on the way to the battle; and four legs in the air means that the sculptor was very, very clever. Five legs in the air means that there's probably at least one other horse standing behind the one you're looking at; and the rider lying on the ground with his horse lying on top of him with all four legs in the air means that the rider was either a very incompetent horseman or owned a very bad-tempered horse. [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 318 (passage starts mid-paragraph and ends mid-paragraph) %passage 10 [...] "Knowledge is power, power is energy, energy is matter, matter is mass, and mass changes time and space." [...] [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 362 (passage starts mid-paragraph; speaker is Preston, a castle guard; # quote is a parody of J.R.R.Tolkien's "Do not meddle in the affairs # of wizards, for they are subtle, and quick to anger.") %passage 11 [...] "My granny said, 'Don't meddle in the affairs of witches because they clout you around the ear.'" [I Shall Wear Midnight, by Terry Pratchett] %e passage # pp. 386-387 (Tiffany is trying to rescue some witches from a castle roof) %passage 12 Tiffany crawled a little farther, well aware of the sheer drop an inch away from her hand. "Preston has gone to fetch a rope. Do you have a broomstick?" "A sheep crashed into it," said Mrs. Proust. Tiffany could just make her out now. "You crashed into a sheep in /the air/?" "Maybe it was a cow, or something. What are those things that go /snuffle snuffle/?" "You ran into a flying hedgehog?" "No, as it happened. We were down low, looking for a bush for Mrs. Happenstance." There was a sigh in the gloom. "It's because of her trouble, poor soul. We've stopped at a lot of bushes on the way here, believe me! And do you know what? Inside every single one of them is something that stings, bites, kicks, screams, howls, squelches, farts enormously, goes all spiky, tries to knock you over, or does an enormous pile of poo! Haven't you people up here ever heard of porcelain?" Tiffany was taken aback. "Well, yes, but not in the fields!" "They would be all the better for it," said Mrs. Proust. "I've ruined a decent pair of boots, I have." [I Shall Wear Midnight, by Terry Pratchett] %e passage # p. 442 (passage starts mid-paragraph; see /The Wee Free Men/; # 'underrr' and 'ag-rreeeed' are accurate; 'arr-angement' is # hyphenated to span lines--it's just a guess that it would have # been hyphenated anyway) %passage 13 "Nae king, nae quin, nae laird! One baron--and underrr mutually ag-rreeeed arr-angement, ye ken!" [I Shall Wear Midnight, by Terry Pratchett] %e passage %e title # # # %title Snuff (2) %passage 1 They were crude weapons, to be sure, but a flint axe hitting your head does not need a degree in physics. [Snuff, by Terry Pratchett] %e passage %passage 2 It is a strange thing to find yourself doing something you have apparently always wanted to do, when in fact up until that moment you had never known that you always wanted to do it... [Snuff, by Terry Pratchett] %e passage %e title # # # %title Raising Steam (8) %passage 1 Yesterday you never thought about it and after today you don't know what you would do without it. That was what the technology was doing. It was your slave but, in a sense, it might be the other way round. [Raising Steam, by Terry Pratchett] %e passage %passage 2 If you take enough precautions, you never need to take precautions. [Raising Steam, by Terry Pratchett] %e passage # p. 57 (Anchor Books edition) %passage 3 Rhys Rhysson, Low King of the dwarfs, was a dwarf of keen intelligence, but he sometimes wondered why someone with that intelligence would go into dwarfish politics, let alone be King of the Dwarfs. Lord Vetinari had it so easy he must hardly know he was born! The King thought that humans were, well, reasonably sensible, whereas there was an old dwarf proverb which, translated, said, "Any three dwarfs having a sensible conversation will always end up having four points of view." [Raising Steam, by Terry Pratchett] %e passage # p. 64 %passage 4 Curious, the Patrician thought, as Drumknott hurried away to dispatch a clacks to the editor of the /Times/, that people in Ankh-Morpork professed not to like change while at the same time fixating on every new entertainment and diversion that came their way. There was nothing the mob liked better than novelty. Lord Vetinari sighed again. Did they actually think? These days /everybody/ used the clacks, even little old ladies who used it to send him clacks messages complaining about all these newfangled ideas, totally missing the irony. And in this doleful mood he ventured to wonder if they ever thought back to when things were just old-fangled or not fangled at all as against the modern day when fangled had reached its apogee. Fangling was indeed, he thought, here to stay. Then he wondered: had anyone ever thought of themselves as a fangler? [Raising Steam, by Terry Pratchett] %e passage # p. 175 (third paragraph has a final sentence, but it's about 'grags' # which wouldn't make any sense here where's no context about them) %passage 5 "Mister Lipwig, you know what they say about dwarfs?" Moist looked blank. "Very small people?" "'Two dwarfs is an argument, three dwarfs is a war,' Mister Lipwig. It's squabble, squabble, squabble. It's built into their culture. [...]" [Raising Steam, by Terry Pratchett] %e passage # p. 233 (second paragraph of a footnote) %passage 6 There clearly has been magic at work in the Netherglades and its future as the pharmacopoeia of the world is being tested by Professor Rincewind of Unseen University. A dispatch from him reveals that the juice pressed from a certain little yellow flower induces certainty in the patient for up to fifteen minutes. About what they are certain they cannot specify, but the patient is, in that short time, completely certain about /everything/. And further research has found that a floating water hyacinth yields in its juices total /un/certainty about anything for half a hour. Philosophers are excited about the uses for these potions, and the search continues for a plant that combines the qualities of both, thereby being of great use to theologians. [Raising Steam, by Terry Pratchett] %e passage # p. 288 %passage 7 The town of Big Cabbage, theoretically the last place any sensible person would want to visit, was nevertheless popular throughout the summer because of the attractions of Brassica World and the Cabbage Research Institute, whose students were the first to get a cabbage to a height of five hundred yards propelled entirely by its own juices. Nobody asked why they felt it was necessary to do this, but that was science for you, and, of course, students. [Raising Steam, by Terry Pratchett] %e passage # pp. 363-364 ("Of the Wheel the Spoke" is the goblin's formal name; perhaps # a new name chosen or given after inventing the bicycle?) %passage 8 A few weeks later, Drumknott persuaded Lord Vetinari to accompany him to the area behind the palace where a jungle of drain pipes emptied and several mismatched sheds, washhouses, and lean-tos housed some of the necessary functions without which a modern palace could not operate.(1) There was a young goblin waiting there, rather nervous, clasping what looked like two wheels held together by not very much. The wheels were spinning. Durmknott cleared his throat. "Show his lordship your new invention, Mister Of the Wheel the Spoke." (1) Frankly most palaces are just like this. Their backsides do not bear looking at. [Raising Steam, by Terry Pratchett] %e passage %e title %title The Shepherd's Crown (1) %passage 1 'It's an inconvenience, true enough, and I don't like it at all, but I know that you do it for everyone, Mister Death. Is there any other way?' NO, THERE ISN'T, I'M AFRAID. WE ARE ALL FLOATING IN THE WINDS OF TIME. BUT YOUR CANDLE, MISTRESS WEATHERWAX, WILL FLICKER FOR SOME TIME BEFORE IT GOES OUT -- A LITTLE REWARD FOR A LIFE WELL LIVED. FOR I CAN SEE THE BALANCE AND YOU HAVE LEFT THE WORLD MUCH BETTER THAN YOU FOUND IT, AND IF YOU ASK ME, said Death, NOBODY COULD DO ANY BETTER THAN THAT. . . [The Shepherd's Crown, by Terry Pratchett] %e passage %e title %e section #----------------------------------------------------- # Used for interaction with Death. # %section Death %title Death Quotes (10) %passage 1 WHERE THE FIRST PRIMAL CELL WAS, THERE WAS I ALSO. WHERE MAN IS, THERE AM I. WHEN THE LAST LIFE CRAWLS UNDER FREEZING STARS, THERE WILL I BE. %e passage # Feet of Clay, p. 17 (Harper Torch edition) %passage 2 I AM DEATH, NOT TAXES. /I/ TURN UP ONLY ONCE. %e passage # Men at Arms, p. 27 (Harper Torch edition) %passage 3 THINK OF IT MORE AS BEING ... DIMENSIONALLY DISADVANTAGED. %e passage # Soul Music, p. 146 (Harper Torch edition; we omit "said Death," after comma) %passage 4 I MAY HAVE ALLOWED MYSELF SOME FLICKER OF EMOTION IN THE RECENT PAST, BUT I CAN GIVE IT UP ANY TIME I LIKE. %e passage %passage 5 # Not a direct quote, but a reference to Thief of Time and the fact that # the player is War HAVE YOU SPOKEN TO RONNIE LATELY? %e passage # Raising Steam, p. 180 (Anchor Books edition) %passage 6 PLEASE DO NOT PANIC. YOU ARE MERELY DEAD. %e passage # Small Gods, p. 90 (Harper Torch edition) %passage 7 THERE IS A LITTLE CONFUSION AT FIRST. IT IS ONLY TO BE EXPECTED. %e passage # Hogfather, p. 343 (Harper Torch edition; Death "lives" outside of normal # time and space) %passage 8 THERE IS ALWAYS TIME FOR ANOTHER LAST MINUTE. # Wintersmith, p. 187 (HarperTeen edition; dying Miss Treason takes a ham # [too silly?] sandwich with her to the grave, and it accompanies # her to the afterlife, but its condiments don't) %passage 9 MUSTARD IS ALWAYS TRICKY. %passage 10 PICKLES OF ALL SORTS DON'T SEEM TO MAKE IT. I'M SORRY. %e title %e section nethack-3.6.0/dat/wizhelp0000664000076400007660000000122712504242744014320 0ustar paxedpaxedDebug-Mode Quick Reference: ^E == detect secret doors and traps. ^F == do magic mapping. ^G == create monster. ^I == identify items in pack. ^O == tell locations of special levels. ^T == do intra-level teleport. ^V == do trans-level teleport. ^W == make wish. ^X == show attributes including intrinsic attributes. #levelchange == change experience level #lightsources == show mobile light sources #monpolycontrol == control monster polymorphs #panic == panic test #polyself == polymorph self #seenv == show seen vectors #stats == show memory statistics #timeout == look at timeout queue #vision == show vision array #wmode == show wall modes nethack-3.6.0/dat/yendor.des0000664000076400007660000001636212536476415014727 0ustar paxedpaxed# NetHack 3.6 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992 by M. Stephenson and Izchak Miller # NetHack may be freely redistributed. See license for details. # # The top (real) wizard level. # Keeping the Moat for old-time's sake MAZE:"wizard1",random FLAGS:noteleport,hardfloor GEOMETRY:center,center MAP ----------------------------. |.......|..|.........|.....|. |.......S..|.}}}}}}}.|.....|. |..--S--|..|.}}---}}.|---S-|. |..|....|..|.}--.--}.|..|..|. |..|....|..|.}|...|}.|..|..|. |..--------|.}--.--}.|..|..|. |..|.......|.}}---}}.|..|..|. |..S.......|.}}}}}}}.|..|..|. |..|.......|.........|..|..|. |..|.......|-----------S-S-|. |..|.......S...............|. ----------------------------. ENDMAP STAIR:levregion(01,00,79,20),(0,0,28,12),up STAIR:levregion(01,00,79,20),(0,0,28,12),down BRANCH:levregion(01,00,79,20),(0,0,28,12) TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12) # Make it a morgue for rm id in mkmaze.c # for the purpose of random sdoor placement REGION:(12,01,20,09),unlit,"morgue",unfilled # another region to constrain monster arrival REGION:(01,01,10,11),unlit,"ordinary",unfilled MAZEWALK:(28,05),east LADDER:(06,05),down # Non diggable walls # Walls inside the moat stay diggable NON_DIGGABLE:(00,00,11,12) NON_DIGGABLE:(11,00,21,00) NON_DIGGABLE:(11,10,27,12) NON_DIGGABLE:(21,00,27,10) # Non passable walls NON_PASSWALL:(00,00,11,12) NON_PASSWALL:(11,00,21,00) NON_PASSWALL:(11,10,27,12) NON_PASSWALL:(21,00,27,10) # The wizard and his guards MONSTER:('@',"Wizard of Yendor"),(16,05),asleep MONSTER:('d',"hell hound"),(15,05) MONSTER:('V',"vampire lord"),(17,05) # The local treasure OBJECT:('+',"Book of the Dead"),(16,05) # Surrounding terror MONSTER:(';',"kraken"),(14,02) MONSTER:(';',"giant eel"),(17,02) MONSTER:(';',"kraken"),(13,04) MONSTER:(';',"giant eel"),(13,06) MONSTER:(';',"kraken"),(19,04) MONSTER:(';',"giant eel"),(19,06) MONSTER:(';',"kraken"),(15,08) MONSTER:(';',"giant eel"),(17,08) MONSTER:(';',"piranha"),(15,02) MONSTER:(';',"piranha"),(19,08) # Random monsters MONSTER:'D',random MONSTER:'H',random MONSTER:'&',random MONSTER:'&',random MONSTER:'&',random MONSTER:'&',random # And to make things a little harder. TRAP:"board",(16,04) TRAP:"board",(16,06) TRAP:"board",(15,05) TRAP:"board",(17,05) # Random traps. TRAP:"spiked pit",random TRAP:"sleep gas",random TRAP:"anti magic",random TRAP:"magic",random # Some random loot. OBJECT:('*',"ruby"),random OBJECT:'!',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'+',random OBJECT:'+',random OBJECT:'+',random # The middle wizard level. MAZE:"wizard2",random FLAGS:noteleport,hardfloor GEOMETRY:center,center MAP ----------------------------. |.....|.S....|.............|. |.....|.-------S--------S--|. |.....|.|.........|........|. |..-S--S|.........|........|. |..|....|.........|------S-|. |..|....|.........|.....|..|. |-S-----|.........|.....|..|. |.......|.........|S--S--..|. |.......|.........|.|......|. |-----S----S-------.|......|. |............|....S.|......|. ----------------------------. ENDMAP STAIR:levregion(01,00,79,20),(0,0,28,12),up STAIR:levregion(01,00,79,20),(0,0,28,12),down BRANCH:levregion(01,00,79,20),(0,0,28,12) TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12) # entire tower in a region, constrains monster migration REGION:(01,01,26,11),unlit,"ordinary",unfilled REGION:(09,03,17,09),unlit,"zoo" DOOR:closed,(15,02) DOOR:closed,(11,10) MAZEWALK:(28,05),east LADDER:(12,01),up LADDER:(14,11),down # Non diggable walls everywhere NON_DIGGABLE:(00,00,27,12) # NON_PASSWALL:(00,00,06,12) NON_PASSWALL:(06,00,27,02) NON_PASSWALL:(16,02,27,12) NON_PASSWALL:(06,12,16,12) # Random traps. TRAP:"spiked pit",random TRAP:"sleep gas",random TRAP:"anti magic",random TRAP:"magic",random # Some random loot. OBJECT:'!',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'+',random # treasures OBJECT:'"',(04,06) # The bottom wizard level. # Memorialize the fakewiz setup. MAZE:"wizard3",random FLAGS:noteleport,hardfloor GEOMETRY:center,center MAP ----------------------------. |..|............S..........|. |..|..------------------S--|. |..|..|.........|..........|. |..S..|.}}}}}}}.|..........|. |..|..|.}}---}}.|-S--------|. |..|..|.}--.--}.|..|.......|. |..|..|.}|...|}.|..|.......|. |..---|.}--.--}.|..|.......|. |.....|.}}---}}.|..|.......|. |.....S.}}}}}}}.|..|.......|. |.....|.........|..|.......|. ----------------------------. ENDMAP STAIR:levregion(01,00,79,20),(0,0,28,12),up STAIR:levregion(01,00,79,20),(0,0,28,12),down BRANCH:levregion(01,00,79,20),(0,0,28,12) TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12) PORTAL:(25,11,25,11),(0,0,0,0),"fakewiz1" MAZEWALK:(28,09),east REGION:(07,03,15,11),unlit,"morgue",unfilled REGION:(17,06,18,11),unlit,"beehive" # make the entry chamber a real room; it affects monster arrival; # `unfilled' is a kludge to force an ordinary room to remain a room REGION:(20,06,26,11),unlit,"ordinary",unfilled { ROOMDOOR:true, closed, north|west, random } DOOR:closed,(18,05) LADDER:(11,07),up # Non diggable walls # Walls inside the moat stay diggable NON_DIGGABLE:(00,00,06,12) NON_DIGGABLE:(06,00,27,02) NON_DIGGABLE:(16,02,27,12) NON_DIGGABLE:(06,12,16,12) # NON_PASSWALL:(00,00,06,12) NON_PASSWALL:(06,00,27,02) NON_PASSWALL:(16,02,27,12) NON_PASSWALL:(06,12,16,12) # MONSTER:'L',(10,07) MONSTER:('V',"vampire lord"),(12,07) # Some surrounding horrors MONSTER:(';',"kraken"),(08,05) MONSTER:(';',"giant eel"),(08,08) MONSTER:(';',"kraken"),(14,05) MONSTER:(';',"giant eel"),(14,08) # Other monsters MONSTER:'L',random MONSTER:'D',random MONSTER:'D',(26,09) MONSTER:'&',random MONSTER:'&',random MONSTER:'&',random # And to make things a little harder. TRAP:"board",(10,07) TRAP:"board",(12,07) TRAP:"board",(11,06) TRAP:"board",(11,08) # Some loot OBJECT:')',random OBJECT:'!',random OBJECT:'?',random OBJECT:'?',random OBJECT:'(',random # treasures OBJECT:'"',(11,07) # The former decoy wizard levels. # There are two of these, and we need to # distinguish between them for the portal. MAZE:"fakewiz1",random GEOMETRY:center,center MAP ......... .}}}}}}}. .}}---}}. .}--.--}. .}|...|}. .}--.--}. .}}---}}. .}}}}}}}. ENDMAP STAIR:levregion(01,00,79,20),(0,0,8,7),up STAIR:levregion(01,00,79,20),(0,0,8,7),down BRANCH:levregion(01,00,79,20),(0,0,8,7) TELEPORT_REGION:levregion(01,00,79,20),(2,2,6,6) PORTAL:(4,4,4,4),(0,0,0,0),"wizard3" MAZEWALK:(08,05),east REGION:(04,03,06,06),unlit,"ordinary",unfilled,irregular MONSTER:'L',(04,04) MONSTER:('V',"vampire lord"),(03,04) MONSTER:(';',"kraken"),(06,06) # And to make things a little harder. TRAP:"board",(04,03) TRAP:"board",(04,05) TRAP:"board",(03,04) TRAP:"board",(05,04) MAZE:"fakewiz2",random GEOMETRY:center,center MAP ......... .}}}}}}}. .}}---}}. .}--.--}. .}|...|}. .}--.--}. .}}---}}. .}}}}}}}. ENDMAP STAIR:levregion(01,00,79,20),(0,0,8,7),up STAIR:levregion(01,00,79,20),(0,0,8,7),down BRANCH:levregion(01,00,79,20),(0,0,8,7) TELEPORT_REGION:levregion(01,00,79,20),(2,2,6,6) MAZEWALK:(08,05),east REGION:(04,03,06,06),unlit,"ordinary",unfilled,irregular MONSTER:'L',(04,04) MONSTER:('V',"vampire lord"),(03,04) MONSTER:(';',"kraken"),(06,06) # And to make things a little harder. TRAP:"board",(04,03) TRAP:"board",(04,05) TRAP:"board",(03,04) TRAP:"board",(05,04) # treasures OBJECT:'"',(04,04) nethack-3.6.0/doc/Guidebook.mn0000664000076400007660000043426012631206535015162 0ustar paxedpaxed.\" $NHDT-Branch: master $:$NHDT-Revision: 1.188 $ $NHDT-Date: 1449420465 2015/12/06 16:47:45 $ .ds h0 "NetHack Guidebook .ds h1 .ds h2 % .ds vr "NetHack 3.6 .ds f0 "\*(vr .ds f1 .ds f2 "December 7, 2015 .\" labeled paragraph start (should be part of tmac.n, but I don't want to .\" make changes to that file) .\" .PS word .\" set the width for the label column .\" .PL word .\" label for the entry .\" .PE .\" clean up .de PS .nr PY \\w'\\$1\ -\ 'u \" width of label plus " - " .nr PX \\w'\ -\ 'u \" width of " - " .sn \\n(pdu \" tmac.n: inter-paragraph space .in +\\n(PYu \" additional indent past label (etc) .si \" tmac.n: start indented section .. .\" labeled paragraph label (and first line) .de PL .br \\h'|-\\n(PYu'\\$1\\h'|-\\n(PXu'\ -\ \\c \" back up, output the label, then . \" skip to width-of(" - ") before the . \" normal indentation, output the " - " . \" then attach the next line (the . \" text) without stopping (\c: nroff . \" section 4.2) .. .\"labeled paragraph end .de PE .ei \" tmac.n: end indented section .in -\\n(PYu \" undo indent past label (etc) .sn \\n(pdu \" tmac.n: inter-paragraph space .. .\" end of labeled paragrah .\" .\" aligned single character key with SHORT definition (if it overflows one .\" line, all bets are off) .\" Usage: .\" .CC k "definition here" .nr CZ \w'\fBW' \" width of the key character column .nr CW \n(CZ/2 \" half the width of the key character column .de CC .nr CX \\w'\\fB\\$1'u/2 \" half the width of the key character .nr CY \\n(CWu-\\n(CXu \" difference between the two half widths .\" output: move right CR units, print the key letter, move right to .\" the full width of the column, print " - " and the definition \\h'|\\n(CYu'\\fB\\$1\\fP\\h'|\\n(CZu'\ -\ \\$2 .. .mt A Guide to the Mazes of Menace (Guidebook for NetHack) .au Original version - Eric S. Raymond (Edited and expanded for 3.6 by Mike Stephenson and others) .hu Preface - Version 3.6 .pg This version of the game is special in a particular way. Near the end of the development of 3.6, one of the significant inspirations for many of the humorous and fun features found in the game, author \fITerry Pratchett\fP, passed away. We have dedicated this version of the game in his memory. .hn 1 Introduction .pg Recently, you have begun to find yourself unfulfilled and distant in your daily occupation. Strange dreams of prospecting, stealing, crusading, and combat have haunted you in your sleep for many months, but you aren't sure of the reason. You wonder whether you have in fact been having those dreams all your life, and somehow managed to forget about them until now. Some nights you awaken suddenly and cry out, terrified at the vivid recollection of the strange and powerful creatures that seem to be lurking behind every corner of the dungeon in your dream. Could these details haunting your dreams be real? As each night passes, you feel the desire to enter the mysterious caverns near the ruins grow stronger. Each morning, however, you quickly put the idea out of your head as you recall the tales of those who entered the caverns before you and did not return. Eventually you can resist the yearning to seek out the fantastic place in your dreams no longer. After all, when other adventurers came back this way after spending time in the caverns, they usually seemed better off than when they passed through the first time. And who was to say that all of those who did not return had not just kept going? .pg Asking around, you hear about a bauble, called the Amulet of Yendor by some, which, if you can find it, will bring you great wealth. One legend you were told even mentioned that the one who finds the amulet will be granted immortality by the gods. The amulet is rumored to be somewhere beyond the Valley of Gehennom, deep within the Mazes of Menace. Upon hearing the legends, you immediately realize that there is some profound and undiscovered reason that you are to descend into the caverns and seek out that amulet of which they spoke. Even if the rumors of the amulet's powers are untrue, you decide that you should at least be able to sell the tales of your adventures to the local minstrels for a tidy sum, especially if you encounter any of the terrifying and magical creatures of your dreams along the way. You spend one last night fortifying yourself at the local inn, becoming more and more depressed as you watch the odds of your success being posted on the inn's walls getting lower and lower. .pg In the morning you awake, collect your belongings, and set off for the dungeon. After several days of uneventful travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morning, you gather your gear, eat what may be your last meal outside, and enter the dungeon... .hn 1 What is going on here? .pg You have just begun a game of NetHack. Your goal is to grab as much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. .pg Your abilities and strengths for dealing with the hazards of adventure will vary with your background and training: .pg \fIArcheologists\fP understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start equipped with the tools for a proper scientific expedition. .pg \fIBarbarians\fP are warriors out of the hinterland, hardened to battle. They begin their quests with naught but uncommon strength, a trusty hauberk, and a great two-handed sword. .pg \fICavemen\fP and \fICavewomen\fP start with exceptional strength but, unfortunately, with neolithic weapons. .pg \fIHealers\fP are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anesthetize, and neutralize poisons; and with their instruments, they can divine a being's state of health or sickness. Their medical practice earns them quite reasonable amounts of money, with which they enter the dungeon. .pg \fIKnights\fP are distinguished from the common skirmisher by their devotion to the ideals of chivalry and by the surpassing excellence of their armor. .pg \fIMonks\fP are ascetics, who by rigorous practice of physical and mental disciplines have become capable of fighting as effectively without weapons as with. They wear no armor but make up for it with increased mobility. .pg \fIPriests\fP and \fIPriestesses\fP are clerics militant, crusaders advancing the cause of righteousness with arms, armor, and arts thaumaturgic. Their ability to commune with deities via prayer occasionally extricates them from peril, but can also put them in it. .pg \fIRangers\fP are most at home in the woods, and some say slightly out of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. .pg \fIRogues\fP are agile and stealthy thieves, with knowledge of locks, traps, and poisons. Their advantage lies in surprise, which they employ to great advantage. .pg \fISamurai\fP are the elite warriors of feudal Nippon. They are lightly armored and quick, and wear the \fIdai-sho\fP, two swords of the deadliest keenness. .pg \fITourists\fP start out with lots of gold (suitable for shopping with), a credit card, lots of food, some maps, and an expensive camera. Most monsters don't like being photographed. .pg \fIValkyries\fP are hardy warrior women. Their upbringing in the harsh Northlands makes them strong, inures them to extremes of cold, and instills in them stealth and cunning. .pg \fIWizards\fP start out with a knowledge of magic, a selection of magical items, and a particular affinity for dweomercraft. Although seemingly weak and easy to overcome at first sight, an experienced Wizard is a deadly foe. .pg You may also choose the race of your character: .pg \fIDwarves\fP are smaller than humans or elves, but are stocky and solid individuals. Dwarves' most notable trait is their great expertise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. .pg \fIElves\fP are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. .pg \fIGnomes\fP are smaller than but generally similar to dwarves. Gnomes are known to be expert miners, and it is known that a secret underground mine complex built by this race exists within the Mazes of Menace, filled with both riches and danger. .pg \fIHumans\fP are by far the most common race of the surface world, and are thus the norm to which other races are often compared. Although they have no special abilities, they can succeed in any role. .pg \fIOrcs\fP are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves with a passion unequalled, and will go out of their way to kill one at any opportunity. The armor and weapons fashioned by the Orcs are typically of inferior quality. .hn 1 What do all those things on the screen mean? .pg On the screen is kept a map of where you have been and what you have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. .pg When NetHack's ancestor \fIrogue\fP first appeared, its screen orientation was almost unique among computer fantasy games. Since then, screen orientation has become the norm rather than the exception; NetHack continues this fine tradition. Unlike text adventure games that accept commands in pseudo-English sentences and explain the results in words, NetHack commands are all one or two keystrokes and the results are displayed graphically on the screen. A minimum screen size of 24 lines by 80 columns is recommended; if the screen is larger, only a 21x80 section will be used for the map. .pg NetHack can even be played by blind players, with the assistance of Braille readers or speech synthesisers. Instructions for configuring NetHack for the blind are included later in this document. .pg NetHack generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game despite having won several times. .pg NetHack offers a variety of display options. The options available to you will vary from port to port, depending on the capabilities of your hardware and software, and whether various compile-time options were enabled when your executable was created. The three possible display options are: a monochrome character interface, a color character interface, and a graphical interface using small pictures called tiles. The two character interfaces allow fonts with other characters to be substituted, but the default assignments use standard ASCII characters to represent everything. There is no difference between the various display options with respect to game play. Because we cannot reproduce the tiles or colors in the Guidebook, and because it is common to all ports, we will use the default ASCII characters from the monochrome character display when referring to things you might see on the screen during your game. .pg In order to understand what is going on in NetHack, first you must understand what NetHack is doing with the screen. The NetHack screen replaces the ``You see ...'' descriptions of text adventure games. Figure 1 is a sample of what a NetHack screen might look like. The way the screen looks for you depends on your platform. .TS S center tab(~); a. _ The bat bites! ------ |....| ---------- |.<..|####...@...$.| |....-# |...B....+ |....| |.d......| ------ -------|-- Player the Rambler St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15 Neutral Dlvl:1 $:0 HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak _ .TE .ce 1 Figure 1 .hn 2 The status lines (bottom) .pg The bottom two lines of the screen contain several cryptic pieces of information describing your current status. If either status line becomes longer than the width of the screen, you might not see all of it. Here are explanations of what the various status items mean (though your configuration may not have all the status items listed below): .lp "Rank " Your character's name and professional ranking (based on the experience level, see below). .lp Strength A measure of your character's strength; one of your six basic attributes. A human character's attributes can range from 3 to 18 inclusive; non-humans may exceed these limits (occasionally you may get super-strengths of the form 18/xx, and magic can also cause attributes to exceed the normal limits). The higher your strength, the stronger you are. Strength affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. .lp Dexterity Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. .lp Constitution Constitution affects your ability to recover from injuries and other strains on your stamina. .lp Intelligence Intelligence affects your ability to cast spells and read spellbooks. .lp Wisdom Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. .lp Charisma Charisma affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you. .lp Alignment \fBLawful\fP, \fBNeutral\fP, or \fBChaotic\fP. Often, Lawful is taken as good and Chaotic as evil, but legal and ethical do not always coincide. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive, while those of an opposing alignment are more likely to be seriously offended at your presence. .lp "Dungeon Level How deep you are in the dungeon. You start at level one and the number increases as you go deeper into the dungeon. Some levels are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be somewhere beneath the twentieth level. .lp "Gold " The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. .lp "Hit Points Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in a fight, the lower they get. You can regain hit points by resting, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. .lp Power Spell points. This tells you how much mystic energy (\fImana\fP) you have available for spell casting. Again, resting will regenerate the amount available. .lp "Armor Class A measure of how effectively your armor stops blows from unfriendly creatures. The lower this number is, the more effective the armor; it is quite possible to have negative armor class. .lp Experience Your current experience level and experience points. As you adventure, you gain experience points. At certain experience point totals, you gain an experience level. The more experienced you are, the better you fight and withstand magical attacks. Many dungeons show only your experience level here. .lp "Time " The number of turns elapsed so far, displayed if you have the .op time option set. .lp "Hunger status Your current hunger status, ranging from \fBSatiated\fP down to \fBFainting\fP. If your hunger status is normal, it is not displayed. .pg Additional status flags may appear after the hunger status: \fBConf\fP when you're confused, \fBFoodPois\fP or \fBIll\fP when sick, \fBBlind\fP when you can't see, \fBStun\fP when stunned, and \fBHallu\fP when hallucinating. .hn 2 The message line (top) .pg The top line of the screen is reserved for messages that describe things that are impossible to represent visually. If you see a ``\fB--More--\fP'' on the top line, this means that NetHack has another message to display on the screen, but it wants to make certain that you've read the one that is there first. To read the next message, just press the space bar. .pg To change how and what messages are shown on the message line, see ``Configuring Message Types`` and the .op verbose option. .hn 2 The map (rest of the screen) .pg The rest of the screen is the map of the level as you have explored it so far. Each symbol on the screen represents something. You can set various graphics options to change some of the symbols the game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: .lp "- and | The walls of a room, or an open door. Or a grave (|). .lp . The floor of a room, ice, or a doorless doorway. .lp # A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. .lp > Stairs down: a way to the next level. .lp < Stairs up: a way to the previous level. .lp + A closed door, or a spellbook containing a spell you may be able to learn. .lp @ Your character or a human. .lp $ A pile of gold. .lp ^ A trap (once you have detected it). .lp ) A weapon. .lp [ A suit or piece of armor. .lp % Something edible (not necessarily healthy). .lp ? A scroll. .lp / A wand. .lp = A ring. .lp ! A potion. .lp ( A useful item (pick-axe, key, lamp...). .lp """ An amulet or a spider web. .lp * A gem or rock (possibly valuable, possibly worthless). .lp ` A boulder or statue. .lp 0 An iron ball. .lp _ An altar, or an iron chain. .lp { A fountain. .lp } A pool of water or moat or a pool of lava. .lp "\e An opulent throne. .lp "a-zA-Z and other symbols Letters and certain other symbols represent the various inhabitants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. .lp I This marks the last known location of an invisible or otherwise unseen monster. Note that the monster could have moved. The 'F' and 'm' commands may be useful here. .pg You need not memorize all these symbols; you can ask the game what any symbol represents with the `/' command (see the next section for more info). .hn 1 Commands .pg Commands are initiated by typing one or two characters. Some commands, like ``search'', do not require that any more information be collected by NetHack. Other commands might require additional information, for example a direction, or an object to be used. For those commands that require additional information, NetHack will present you with either a menu of choices or with a command line prompt requesting information. Which you are presented with will depend chiefly on how you have set the .op menustyle option. .pg For example, a common question, in the form ``What do you want to use?\ [a-zA-Z\ ?*]'', asks you to choose an object you are carrying. Here, ``a-zA-Z'' are the inventory letters of your possible choices. Typing `?' gives you an inventory list of these items, so you can see what each letter refers to. In this example, there is also a `*' indicating that you may choose an object not on the list, if you wanted to use something unexpected. Typing a `*' lists your entire inventory, so you can see the inventory letters of every object you're carrying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the ESC key to abort the command. .pg You can put a number before some commands to repeat them that many times; for example, ``10s'' will search ten times. If you have the .op number_pad option set, you must type `n' to prefix a count, so the example above would be typed ``n10s'' instead. Commands for which counts make no sense ignore them. In addition, movement commands can be prefixed for greater control (see below). To cancel a count or a prefix, press the ESC key. .pg The list of commands is rather long, but it can be read at any time during the game through the `?' command, which accesses a menu of helpful texts. Here are the commands for your reference: .lp ? Help menu: display one of several help texts available. .lp / Tell what a symbol represents. You may choose to specify a location or type a symbol (or even a whole word) to explain. Specifying a location is done by moving the cursor to a particular spot on the map and then pressing one of `.', `,', `;', or `:'. `.' will explain the symbol at the chosen location, conditionally check for ``More info?'' depending upon whether the .op help option is on, and then you will be asked to pick another location; `,' will explain the symbol but skip any additional information; `;' will skip additional info and also not bother asking you to choose another location to examine; `:' will show additional info, if any, without asking for confirmation. When picking a location, pressing the ESC key will terminate this command, or pressing `?' will give a brief reminder about how it works. .pg Specifying a name rather than a location always gives any additional information available about that name. .lp & Tell what a command does. .lp < Go up to the previous level (if you are on a staircase or ladder). .lp > Go down to the next level (if you are on a staircase or ladder). .lp [yuhjklbn] Go one step in the direction indicated (see Figure 2). If you sense or remember a monster there, you will fight the monster instead. Only these one-step movement commands cause you to fight monsters; the others (below) are ``safe.'' .sd .TS S center; c c. y k u 7 8 9 \e | / \e | / h- . -l 4- . -6 / | \e / | \e b j n 1 2 3 (if \fBnumber_pad\fP is set) .TE .ed .ce 1 Figure 2 .lp [YUHJKLBN] Go in that direction until you hit a wall or run into something. .lp m[yuhjklbn] Prefix: move without picking up objects or fighting (even if you remember a monster there) .lp F[yuhjklbn] Prefix: fight a monster (even if you only guess one is there) .lp M[yuhjklbn] Prefix: move far, no pickup. .lp "g[yuhjklbn] Prefix: move until something interesting is found. .lp "G[yuhjklbn] or [yuhjklbn] Prefix: same as `g', but forking of corridors is not considered interesting. .lp _ Travel to a map location via a shortest-path algorithm. .lp "" The shortest path is computed over map locations the hero knows about (e.g. seen or previously traversed). If there is no known path, a guess is made instead. Stops on most of the same conditions as the `G' command, but without picking up objects, similar to the `M' command. For ports with mouse support, the command is also invoked when a mouse-click takes place on a location other than the current position. .lp . Rest, do nothing for one turn. .lp a Apply (use) a tool (pick-axe, key, lamp...). .lp A Remove one or more worn items, such as armor. .lp "" Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. .lp ^A Redo the previous command. .lp c Close a door. .lp C Call (name) a monster, an individual object, or a type of object. .lp "" Same as extended command ``#name''. .lp ^C Panic button. Quit the game. .lp d Drop something. .lp "" Ex. ``d7a'' means drop seven items of object \fIa\fP. .lp D Drop several things. .lp "" In answer to the question .lp "" ``What kinds of things do you want to drop? [!%= BUCXaium]'' .lp "" you should type zero or more object symbols possibly followed by `a' and/or `i' and/or `u' and/or `m'. In addition, one or more of the blessed/uncursed/cursed groups may be typed. .sd .si DB - drop all objects known to be blessed. DU - drop all objects known to be uncursed. DC - drop all objects known to be cursed. DX - drop all objects of unknown B/U/C status. Da - drop all objects, without asking for confirmation. Di - examine your inventory before dropping anything. Du - drop only unpaid objects (when in a shop). Dm - use a menu to pick which object(s) to drop. D%u - drop only unpaid food. .ei .ed .lp ^D Kick something (usually a door). .lp e Eat food. .\" Make sure Elbereth is not hyphenated below, the exact spelling matters .hw Elbereth .lp E Engrave a message on the floor. .sd .si E- - write in the dust with your fingers. .ei .ed .lp "" Engraving the word ``Elbereth'' will cause most monsters to not attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. (This feature may be compiled out of the game, so your version might not have it.) .lp f Fire one of the objects placed in your quiver (or quiver sack, or that you have at the ready). You may select ammunition with a previous `Q' command, or let the computer pick something appropriate if .op autoquiver is true. .lp i List your inventory (everything you're carrying). .lp I List selected parts of your inventory, usually be specifying the character for a particular set of objects, like `[' for armor or `!' for potions. .sd .si I* - list all gems in inventory; Iu - list all unpaid items; Ix - list all used up items that are on your shopping bill; IB - list all items known to be blessed; IU - list all items known to be uncursed; IC - list all items known to be cursed; IX - list all items whose bless/curse status is known; I$ - count your money. .ei .ed .lp o Open a door. .lp O Set options. .lp "" A menu showing the current option values will be displayed. You can change most values simply by selecting the menu entry for the given option (ie, by typing its letter or clicking upon it, depending on your user interface). For the non-boolean choices, a further menu or prompt will appear once you've closed this menu. The available options are listed later in this Guidebook. Options are usually set before the game rather than with the `O' command; see the section on options below. .lp p Pay your shopping bill. .lp P Put on an accessory (ring, amulet, or blindfold). .lp "" This command may also be used to wear armor. The prompt for which inventory item to use will only list accessories, but choosing an unlisted item of armor will attempt to wear it. (See the `W' command below. It lists armor as the inventory choices but will accept an accessory and attempt to put that on.) .lp ^P Repeat previous message. .lp "" Subsequent ^P's repeat earlier messages. The behavior can be varied via the .op msg_window option. .lp q Quaff (drink) something (potion, water, etc). .lp Q Select an object for your quiver, quiver sack, or just generally at the ready (only one of these is available at a time). You can then throw this (or one of these) using the `f' command. .lp "" (In versions prior to 3.3 this was the command to quit the game, which has been moved to ``#quit''.) .lp r Read a scroll or spellbook. .lp R Remove a worn accessory (ring, amulet, or blindfold). .lp "" If you're wearing more than one, you'll be prompted for which one to remove. When you're only wearing one, then by default it will be removed without asking, but you can set the .op paranoid_confirmation option to require a prompt. .lp "" This command may also be used to take off armor. The prompt for which inventory item to remove only lists worn accessories, but an item of worn armor can be chosen. (See the `T' command below. It lists armor as the inventory choices but will accept an accessory and attempt to remove it.) .lp ^R Redraw the screen. .lp s Search for secret doors and traps around you. It usually takes several tries to find something. .lp S Save (and suspend) the game. The game will be restored automatically the next time you play. .lp t Throw an object or shoot a projectile. .lp T Take off armor. .lp "" If you're wearing more than one piece, you'll be prompted for which one to take off. (Note that this treats a cloak covering a suit and/or a shirt, or a suit covering a shirt, as if the underlying items weren't there.) When you're only wearing one, then by default it will be taken off without asking, but you can set the .op paranoid_confirmation option to require a prompt. .lp "" This command may also be used to remove accessories. The prompt for which inventory item to take off only lists worn armor, but a worn accessory can be chosen. (See the `R' command above. It lists accessories as the inventory choices but will accept an item of armor and attempt to take it off.) .lp ^T Teleport, if you have the ability. .lp v Display version number. .lp V Display the game history. .lp w Wield weapon. .sd .si w- - wield nothing, use your bare hands. .ei .ed Some characters can wield two weapons at once; use the `X' command (or the ``#twoweapon'' extended command) to do so. .lp W Wear armor. .lp "" This command may also be used to put on an accessory (ring, amulet, or blindfold). The prompt for which inventory item to use will only list armor, but choosing an unlisted accessory will attempt to put it on. (See the `P' command above. It lists accessories as the inventory choices but will accept an item of armor and attempt to wear it.) .lp x Exchange your wielded weapon with the item in your alternate weapon slot. .lp "" The latter is used as your secondary weapon when engaging in two-weapon combat. Note that if one of these slots is empty, the exchange still takes place. .lp X Toggle two-weapon combat, if your character can do it. Also available via the ``#twoweapon'' extended command. .lp "" (In versions prior to 3.6 this was the command to switch from normal play to "explore mode", also known as "discovery mode", which has now been moved to ``#explore''.) .lp ^X Display basic information about your character. .lp "" Displays name, role, race, gender (unless role name makes that redundant, such as \fICaveman\fP or \fIPriestess\fP), and alignment, along with your patron deity and his or her opposition. It also shows most of the various items of information from the status line(s) in a less terse form, including several additional things which don't appear in the normal status display due to space considerations. .lp z Zap a wand. .sd .si z. - to aim at yourself, use `.' for the direction. .ei .ed .lp Z Zap (cast) a spell. .sd .si Z. - to cast at yourself, use `.' for the direction. .ei .ed .lp ^Z Suspend the game .ux " versions with job control only)." ( .lp : Look at what is here. .lp ; Show what type of thing a visible symbol corresponds to. .lp , Pick up some things from the floor beneath you. .lp "" May be preceded by `m' to force a selection menu. .lp @ Toggle the .op autopickup option on and off. .lp ^ Ask for the type of a trap you found earlier. .lp ) Tell what weapon you are wielding. .lp [ Tell what armor you are wearing. .lp = Tell what rings you are wearing. .lp """ Tell what amulet you are wearing. .lp ( Tell what tools you are using. .lp * Tell what equipment you are using. .lp "" Combines the preceding five type-specific commands into one. .lp $ Count your gold pieces. .lp + List the spells you know. .lp "" Using this command, you can also rearrange the order in which your spells are listed, either by sorting the entire list or by picking one spell from the menu then picking another to swap places with it. Swapping pairs of spells changes their casting letters, so the change lasts after the current `+' command finishes. Sorting the whole list is temporary. To make the most recent sort order persist beyond the current `+' command, choose the sort option again and then pick "reassign casting letters". (Any spells learned after that will be added to the end of the list rather than be inserted into the sorted ordering.) .lp "\e Show what types of objects have been discovered. .lp ` Show discovered types for one class of objects. .lp ! Escape to a shell. .lp # Perform an extended command. .lp "" As you can see, the authors of NetHack used up all the letters, so this is a way to introduce the less frequently used commands. What extended commands are available depends on what features the game was compiled with. .lp #adjust Adjust inventory letters (most useful when the .op fixinv option is ``on''). .lp "" This command allows you to move an item from one particular inventory slot to another so that it has a letter which is more meaningful for you or that it will appear in a particular location when inventory listings are displayed. ``#adjust'' can also be used to split a stack of objects; when choosing the item to adjust, enter a count prior to its letter. .lp #annotate Allows you to specify one line of text to associate with the current dungeon level. All levels with annotations are displayed by the ``#overview'' command. .lp #chat Talk to someone. .lp #conduct List voluntary challenges you have maintained. .lp "" See the section below entitled ``Conduct'' for details. .lp "#dip " Dip an object into something. .lp #enhance Advance or check weapon and spell skills. .lp #force Force a lock. .lp #invoke Invoke an object's special powers. .lp #jump Jump to another location. .lp #loot Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. .lp #monster Use a monster's special ability (when polymorphed into monster form). .lp #name Name a monster, an individual object, or a type of object. Same as `C'. .lp #offer Offer a sacrifice to the gods. .lp "" You'll need to find an altar to have any chance at success. Corpses of recently killed monsters are the fodder of choice. .lp #overview Display information you've discovered about the dungeon. Any visited level (unless forgotten due to amnesia) with an annotation is included, and many things (altars, thrones, fountains, and so on; extra stairs leading to another dungeon branch) trigger an automatic annotation. If dungeon overview is chosen during end-of-game disclosure, every visited level will be included regardless of annotations. .lp #pray Pray to the gods for help. .lp "" Praying too soon after receiving prior help is a bad idea. (Hint: entering the dungeon alive is treated as having received help. You probably shouldn't start off a new game by praying right away.) Since using this command by accident can cause trouble, there is an option to make you confirm your intent before praying. It is enabled by default, and you can reset the .op paranoid_confirmation option to disable it. .lp #quit Quit the program without saving your game. .lp "" Since using this command by accident would throw away the current game, you are asked to confirm your intent before quitting. By default a response of 'y' acknowledges that intent. You can set the .op paranoid_confirmation option to require a response of "yes" instead. .lp #ride Ride (or stop riding) a saddled creature. .lp "#rub " Rub a lamp or a stone. .lp "#sit " Sit down. .lp #terrain Show bare map without displaying monsters, objects, or traps. .lp "#tip " Tip over a container (bag or box) to pour out its contents. .lp #turn Turn undead. .lp #twoweapon Toggle two-weapon combat on or off. .lp "" Note that you must use suitable weapons for this type of combat, or it will be automatically turned off. .lp #untrap Untrap something (trap, door, or chest). .lp "" In some circumstances it can also be used to rescue trapped monsters. .lp #version Print compile time options for this version of NetHack. .lp #wipe Wipe off your face. .lp "#? " Help menu: get the list of available extended commands. .pg If your keyboard has a meta key (which, when pressed in combination with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. In \fINT\fP, \fIOS/2\fP, \fIPC\fP and \fIST\fP \fINetHack\fP, the `Alt' key can be used in this fashion; on the \fIAmiga\fP, set the .op altmeta option to get this behavior. On other systems, if typing `Alt' plus another key transmits a two character sequence consisting of an \fBEscape\fP followed by the other key, you may set the .op altmeta option to have nethack combine them into meta+key. .lp M-? #? (not supported by all platforms) .lp M-2 #twoweapon (unless the number_pad option is enabled) .lp M-a #adjust .lp M-A #annotate .lp M-c #chat .lp M-C #conduct .lp M-d #dip .lp M-e #enhance .lp M-f #force .lp M-i #invoke .lp M-j #jump .lp M-l #loot .lp M-m #monster .lp M-n #name .lp M-o #offer .lp M-O #overview .lp M-p #pray .lp M-q #quit .lp M-r #rub .lp M-R #ride .lp M-s #sit .lp M-t #turn .lp M-T #tip .lp M-u #untrap .lp M-v #version .lp M-w #wipe .pg If the .op number_pad option is on, some additional letter commands are available: .lp h Help menu: display one of several help texts available, like ``?''. .lp j Jump to another location. Same as ``#jump'' or ``M-j''. .lp k Kick something (usually a door). Same as `^D'. .lp l Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. Same as ``#loot'' or ``M-l''. .lp N Name a monster, an individual object, or a type of object. Same as ``#name'' (or ``M-n'') which is the same as the `C' command. .lp u Untrap a trap, door, or chest. Same as ``#untrap'' or ``M-u''. .hn 1 Rooms and corridors .pg Rooms and corridors in the dungeon are either lit or dark. Any lit areas within your line of sight will be displayed; dark areas are only displayed if they are within one space of you. Walls and corridors remain on the map as you explore them. .pg Secret corridors are hidden. You can find them with the `s' (search) command. .hn 2 Doorways .pg Doorways connect rooms and corridors. Some doorways have no doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use the `o' (open) command; to close it again, use the `c' (close) command. .pg You can get through a locked door by using a tool to pick the lock with the `a' (apply) command, or by kicking it open with the `^D' (kick) command. .pg Open doors cannot be entered diagonally; you must approach them straight on, horizontally or vertically. Doorways without doors are not restricted in this fashion. .pg Doors can be useful for shutting out monsters. Most monsters cannot open doors, although a few don't need to (ex. ghosts can walk through doors). .pg Secret doors are hidden. You can find them with the `s' (search) command. Once found they are in all ways equivalent to normal doors. .hn 2 Traps (`^') .pg There are traps throughout the dungeon to snare the unwary delver. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out. Traps don't appear on your map until you see one triggered by moving onto it, see something fall into it, or you discover it with the `s' (search) command. Monsters can fall prey to traps, too, which can be a very useful defensive strategy. .pg There is a special pre-mapped branch of the dungeon based on the classic computer game ``Sokoban.'' The goal is to push the boulders into the pits or holes. With careful foresight, it is possible to complete all of the levels according to the traditional rules of Sokoban. Some allowances are permitted in case the player gets stuck; however, they will lower your luck. .hn 2 Stairs (`<', `>') .pg In general, each level in the dungeon will have a staircase going up (`<') to the previous level and another going down (`>') to the next level. There are some exceptions though. For instance, fairly early in the dungeon you will find a level with two down staircases, one continuing into the dungeon and the other branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so after exploring them (if you choose to do so), you'll need to climb back up to the main dungeon. .pg When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be deactivated and stored in a file on disk. If you're moving to a previously visited level, it will be loaded from its file on disk and reactivated. If you're moving to a level which has not yet been visited, it will be created (from scratch for most random levels, from a template for some ``special'' levels, or loaded from the remains of an earlier game for a ``bones'' level as briefly described below). Monsters are only active on the current level; those on other levels are essentially placed into stasis. .pg Ordinarily when you climb a set of stairs, you will arrive on the corresponding staircase at your destination. However, pets (see below) and some other monsters will follow along if they're close enough when you travel up or down stairs, and occasionally one of these creatures will displace you during the climb. When that occurs, the pet or other monster will arrive on the staircase and you will end up nearby. .hn 2 Ladders (`<', `>') .pg Ladders serve the same purpose as staircases, and the two types of inter-level connections are nearly indistinguishable during game play. .hn 2 Shops and shopping .pg Occasionally you will run across a room with a shopkeeper near the door and many items lying on the floor. You can buy items by picking them up and then using the `p' command. You can inquire about the price of an item prior to picking it up by using the ``#chat'' command while standing on it. Using an item prior to paying for it will incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. .pg You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shopkeeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by the shop). .pg If you drop something in a shop by accident, the shopkeeper will usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. .pg Shopkeepers sometimes run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you happen to find a "credit card" in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) .pg The `$' command, which reports the amount of gold you are carrying (in inventory, not inside bags or boxes), will also show current shop debt or credit, if any. The `Iu' command lists unpaid items (those which still belong to the shop) if you are carrying any. The `Ix' command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. .hn 3 Shop idiosyncracies .pg Several aspects of shop behavior might be unexpected. .\" note: using * instead of \(bu is better for plain text output .lp * 2 The price of a given item can vary due to a variety of factors. .lp * 2 A shopkeeper treats the spot immediately inside the door as if it were outside the shop. .lp * 2 While the shopkeeper watches you like a hawk, he will generally ignore any other customers. .lp * 2 If a shop is "closed for inventory", it will not open of its own accord. .lp * 2 Shops do not get restocked with new items, regardless of inventory depletion. .hn 1 Monsters .pg Monsters you cannot see are not displayed on the screen. Beware! You may suddenly come upon one in a dark place. Some magic items can help you locate them before they locate you (which some monsters can do very well). .pg The commands `/' and `;' may be used to obtain information about those monsters who are displayed on the screen. The command ``#name'', or its synonym `C', allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple monsters are present. Assigning a name which is just a space will remove any prior name. .pg The extended command ``#chat'' can be used to interact with an adjacent monster. There is no actual dialog (in other words, you don't get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. .hn 2 Fighting .pg If you see a monster and you wish to fight it, just attempt to walk into it. Many monsters you find will mind their own business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. .pg In most circumstances, if you attempt to attack a peaceful monster by moving into its location, you'll be asked to confirm your intent. By default an answer of 'y' acknowledges that intent, which can be error prone if you're using 'y' to move. You can set the .op paranoid_confirmation option to require a response of "yes" instead. .pg If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a monster that you can see; of course, if the monster has moved, you will attack empty air. If you guess that the monster has moved and you don't wish to fight, you can use the `m' command to move without fighting; likewise, if you don't remember a monster but want to try fighting anyway, you can use the `F' command. .hn 2 Your pet .pg You start the game with a little dog (`d'), cat (`f'), or pony (`u'), which follows you about the dungeon and fights monsters with you. Like you, your pet needs food to survive. It usually feeds itself on fresh carrion and other meats. If you're worried about it or want to train it, you can feed it, too, by throwing it food. A properly trained pet can be very useful under certain circumstances. .pg Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, your pet may even be better at killing things than you, which makes pets useful for low-level characters. .pg Your pet will follow you up and down staircases if it is next to you when you move. Otherwise your pet will be stranded and may become wild. Similarly, when you trigger certain types of traps which alter your location (for instance, a trap door which drops you to a lower dungeon level), any adjacent pet will accompany you and any non-adjacent pet will be left behind. Your pet may trigger such traps itself; you will not be carried along with it even if adjacent at the time. .hn 2 Steeds .pg Some types of creatures in the dungeon can actually be ridden if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in order to forge the alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the `#ride' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. .pg Riding skill is managed by the `#enhance' command. See the section on Weapon proficiency for more information about that. .hn 2 Bones levels .pg You may encounter the shades and corpses of other adventurers (or even former incarnations of yourself!) and their personal effects. Ghosts are hard to kill, but easy to avoid, since they're slow and do little damage. You can plunder the deceased adventurer's possessions; however, they are likely to be cursed. Beware of whatever killed the former player; it is probably still lurking around, gloating over its last victory. .hn 1 Objects .pg When you find something in the dungeon, it is common to want to pick it up. In NetHack, this is accomplished automatically by walking over the object (unless you turn off the .op autopickup option (see below), or move with the `m' prefix (see above)), or manually by using the `,' command. .pg If you're carrying too many items, NetHack will tell you so and you won't be able to pick up anything more. Otherwise, it will add the object(s) to your pack and tell you what you just picked up. .pg As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry depends on your strength and your constitution. The stronger you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are carrying around with you through the dungeon will encumber you. Your reactions will get slower and you'll burn calories faster, requiring food more frequently to cope with it. Eventually, you'll be so overloaded that you'll either have to discard some of what you're carrying or collapse under its weight. .pg NetHack will tell you how badly you have loaded yourself. The symbols `Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are displayed on the bottom line display to indicate your condition. .pg When you pick up an object, it is assigned an inventory letter. Many commands that operate on objects must ask you to find out which object you want to use. When NetHack asks you to choose a particular object you are carrying, you are usually presented with a list of inventory letters to choose from (see Commands, above). .pg Some objects, such as weapons, are easily differentiated. Others, like scrolls and potions, are given descriptions which vary according to type. During a game, any two objects with the same description are the same type. However, the descriptions will vary from game to game. .pg When you use one of these objects, if its effect is obvious, NetHack will remember what it is for you. If its effect isn't extremely obvious, you will be asked what you want to call this type of object so you will recognize it later. You can also use the ``#name'' command, or its synonym `C', for the same purpose at any time, to name all objects of a particular type or just an individual object. When you use ``#name'' on an object which has already been named, specifying a space as the value will remove the prior name instead of assigning a new one. .hn 2 Curses and Blessings .pg Any object that you find may be cursed, even if the object is otherwise helpful. The most common effect of a curse is being stuck with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is not removable by ordinary means. In addition, cursed arms and armor usually, but not always, bear negative enchantments that make them less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. .pg Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For example, a blessed weapon will do more damage against demons. .pg Objects which are neither cursed nor blessed are referred to as uncursed. They could just as easily have been described as unblessed, but the uncursed designation is what you will see within the game. A ``glass half full versus glass half empty'' situation; make of that what you will. .pg There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate sensitivity to this property in any object, so they can more easily avoid cursed objects than other character roles. .pg An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. In some cases ``uncursed'' will be omitted as being redundant when enough other information is displayed. The .op implicit_uncursed option can be used to control this; toggle it off to have ``uncursed'' be displayed even when that can be deduced from other attributes. .hn 2 Weapons (`)') .pg Given a chance, most monsters in the Mazes of Menace will gratuitously try to kill you. You need weapons for self-defense (killing them first). Without a weapon, you do only 1-2 hit points of damage (plus bonuses, if any). Monk characters are an exception; they normally do much more damage with bare hands than they do with weapons. .pg There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings hurl rocks and (other) stones (like gems). .pg Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be either positive or negative) that adds to your chance to hit and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically identified somehow. Most weapons are subject to some type of damage like rust. Such ``erosion'' damage can be repaired. .pg The chance that an attack will successfully hit a monster, and the amount of damage such a hit will do, depends upon many factors. Among them are: type of weapon, quality of weapon (enchantment and/or erosion), experience level, strength, dexterity, encumbrance, and proficiency (see below). The monster's armor class - a general defense rating, not necessarily due to wearing of armor - is a factor too; also, some monsters are particularly vulnerable to certain types of weapons. .pg Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon ready to use by setting things up with the `x' command, which exchanges your primary (the one being wielded) and alternate weapons. And if you have proficiency in the ``two weapon combat'' skill, you may wield both weapons simultaneously as primary and secondary; use the `#twoweapon' extended command to engage or disengage that. Only some types of characters (barbarians, for instance) have the necessary skill available. Even with that skill, using two weapons at once incurs a penalty in the chance to hit your target compared to using just one weapon at a time. .pg There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `-', or else use the `A' command which allows you to unwield the current weapon in addition to taking off other worn items. .pg Those of you in the audience who are AD&D players, be aware that each weapon which existed in AD&D does roughly the same damage to monsters in NetHack. Some of the more obscure weapons (such as the \fIaklys\fP, \fIlucern hammer\fP, and \fIbec-de-corbin\fP) are defined in an appendix to \fIUnearthed Arcana\fP, an AD&D supplement. .pg The commands to use weapons are `w' (wield), `t' (throw), `f' (fire, an alternative way of throwing), `Q' (quiver), `x' (exchange), `#twoweapon', and `#enhance' (see below). .hn 3 Throwing and shooting .pg You can throw just about anything via the `t' command. It will prompt for the item to throw; picking `?' will list things in your inventory which are considered likely to be thrown, or picking `*' will list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown depends mainly on the type of object and your strength. Arrows can be thrown by hand, but can be thrown much farther and will be more likely to hit when thrown while you are wielding a bow. .pg You can simplify the throwing operation by using the `Q' command to select your preferred ``missile'', then using the `f' command to throw it. You'll be prompted for a direction as above, but you don't have to specify which item to throw each time you use `f'. There is also an option, .op autoquiver, which has NetHack choose another item to automatically fill your quiver (or quiver sack, or have at the ready) when the inventory slot used for `Q' runs out. .pg Some characters have the ability to fire a volley of multiple items in a single turn. Knowing how to load several rounds of ammunition at once -- or hold several missiles in your hand -- and still hit a target is not an easy task. Rangers are among those who are adept at this task, as are those with a high level of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one to shoot bolts, or in sling skill if you're wielding one to shoot stones). The number of items that the character has a chance to fire varies from turn to turn. You can explicitly limit the number of shots by using a numeric prefix before the `t' or `f' command. For example, ``2f'' (or ``n2f'' if using .op number_pad mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify a larger number than would have been shot (``4f'' in this example), you'll just end up shooting the same number (3, here) as if no limit had been specified. Once the volley is in motion, all of the items will travel in the same direction; if the first ones kill a monster, the others can still continue beyond that spot. .hn 3 Weapon proficiency .pg You will have varying degrees of skill in the weapons available. Weapon proficiency, or weapon skills, affect how well you can use particular types of weapons, and you'll be able to improve your skills as you progress through a game, depending on your role, your experience level, and use of the weapons. .pg For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. .pg The `#enhance' extended command is used to review current weapons proficiency (also spell proficiency) and to choose which skill(s) to improve when you've used one or more skills enough to become eligible to do so. The skill rankings are ``none'' (sometimes also referred to as ``restricted'', because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'', and ``expert''. Restricted skills simply will not appear in the list shown by `#enhance'. (Divine intervention might unrestrict a particular skill, in which case it will start at unskilled and be limited to basic.) Some characters can enhance their barehanded combat or martial arts skill beyond expert to ``master'' or ``grand master''. .pg Use of a weapon in which you're restricted or unskilled will incur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is higher. A successful hit has a chance to boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, you'll be told that you feel more confident in your skills. At that point you can use `#enhance' to increase one or more skills. Such skills are not increased automatically because there is a limit to your total overall skills, so you need to actively choose which skills to enhance and which to ignore. .hn 3 Two-Weapon combat .pg Some characters can use two weapons at once. Setting things up to do so can seem cumbersome but becomes second nature with use. To wield two weapons, you need to use the ``#twoweapon'' command. But first you need to have a weapon in each hand. (Note that your two weapons are not fully equal; the one in the hand you normally wield with is considered primary and the other one is considered secondary. The most noticeable difference is after you stop--or before you begin, for that matter--wielding two weapons at once. The primary is your wielded weapon and the secondary is just an item in your inventory that's been designated as alternate weapon.) .pg If your primary weapon is wielded but your off hand is empty or has the wrong weapon, use the sequence 'x', 'w', 'x' to first swap your primary into your off hand, wield whatever you want as secondary weapon, then swap them both back into the intended hands. If your secondary or alternate weapon is correct but your primary one is not, simply use 'w' to wield the primary. Lastly, if neither hand holds the correct weapon, use 'w', 'x', 'w' to first wield the intended secondary, swap it to off hand, and then wield the primary. .pg The whole process can be simplified via use of the .op pushweapon option. When it is enabled, then using 'w' to wield something causes the currently wielded weapon to become your alternate weapon. So the sequence 'w', 'w' can be used to first wield the weapon you intend to be secondary, and then wield the one you want as primary which will push the first into secondary position. .pg When in two-weapon combat mode, using the ``#twoweapon'' command toggles back to single-weapon mode. Throwing or dropping either of the weapons or having one of them be stolen or destroyed will also make you revert to single-weapon combat. .hn 2 Armor (`[') .pg Lots of unfriendly things lurk about; you need armor to protect yourself from their blows. Some types of armor offer better protection than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD&D, with 10 being the equivalent of no armor, and lower numbers meaning better armor. Each suit of armor which exists in AD&D gives the same protection in NetHack. Here is an (incomplete) list of the armor classes provided by various suits of armor: .TS S center; a n. dragon scale mail 1 plate mail 3 crystal plate mail 3 bronze plate mail 4 splint mail 4 banded mail 4 dwarvish mithril-coat 4 elven mithril-coat 5 chain mail 5 orcish chain mail 6 scale mail 6 studded leather armor 7 ring mail 7 orcish ring mail 8 leather armor 8 leather jacket 9 no armor 10 .TE .pg You can also wear other pieces of armor (ex. helmets, boots, shields, cloaks) to lower your armor class even further, but you can only wear one item of each category (one suit of armor, one cloak, one helmet, one shield, and so on) at a time. .pg If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its ``plus'' (or minus) will subtract from your armor class. For example, a +1 chain mail would give you better protection than normal chain mail, lowering your armor class one unit further to 4. When you put on a piece of armor, you immediately find out the armor class and any ``plusses'' it provides. Cursed pieces of armor usually have negative enchantments (minuses) in addition to being unremovable. .pg Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may inhibit spell casting. .pg The commands to use armor are `W' (wear) and `T' (take off). The `A' command can also be used to take off armor as well as other worn items. .hn 2 Food (`%') .pg Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins (``cans'') will usually stay fresh, but ice boxes are heavy, and tins take a while to open. .pg When you kill monsters, they usually leave corpses which are also ``food.'' Many, but not all, of these are edible; some also give you special powers when you eat them. A good rule of thumb is ``you are what you eat.'' .pg Some character roles and some monsters are vegetarian. Vegetarian monsters will typically never eat animal corpses, while vegetarian players can, but with some rather unpleasant side-effects. .pg You can name one food item after something you like to eat with the .op fruit option. .pg The command to eat food is `e'. .hn 2 Scrolls (`?') .pg Scrolls are labeled with various titles, probably chosen by ancient wizards for their amusement value (ex. ``READ ME,'' or ``THANX MAUD'' backwards). Scrolls disappear after you read them (except for blank ones, without magic spells on them). .pg One of the most useful of these is the \fIscroll of identify\fP, which can be used to determine what another object is, whether it is cursed or blessed, and how many uses it has left. Some objects of subtle enchantment are difficult to identify without these. .pg A mail daemon may run up and deliver mail to you as a \fIscroll of mail\fP (on versions compiled with this feature). To use this feature on versions where NetHack mail delivery is triggered by electronic mail appearing in your system mailbox, you must let NetHack know where to look for new mail by setting the ``MAIL'' environment variable to the file name of your mailbox. You may also want to set the ``MAILREADER'' environment variable to the file name of your favorite reader, so NetHack can shell to it when you read the scroll. On versions of NetHack where mail is randomly generated internal to the game, these environment variables are ignored. You can disable the mail daemon by turning off the .op mail option. .pg The command to read a scroll is `r'. .hn 2 Potions (`!') .pg Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. .pg Clear potions are potions of water. Sometimes these are blessed or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`t') at them. It is also sometimes very useful to dip (``#dip'') an object into a potion. .pg The command to drink a potion is `q' (quaff). .hn 2 Wands (`/') .pg Magic wands usually have multiple magical charges. Some wands are directional\(emyou must give a direction in which to zap them. You can also zap them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other wands are nondirectional\(emthey don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. .pg When the number of charges left in a wand becomes zero, attempts to use the wand will usually result in nothing happening. Occasionally, however, it may be possible to squeeze the last few mana points from an otherwise spent wand, destroying it in the process. A wand may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time the wand is recharged. .pg In a truly desperate situation, when your back is up against the wall, you might decide to go for broke and break your wand. This is not for the faint of heart. Doing so will almost certainly cause a catastrophic release of magical energies. .pg When you have fully identified a particular wand, inventory display will include additional information in parentheses: the number of times it has been recharged followed by a colon and then by its current number of charges. A current charge count of -1 is a special case indicating that the wand has been cancelled. .pg The command to use a wand is `z' (zap). To break one, use the `a' (apply) command. .hn 2 Rings (`=') .pg Rings are very useful items, since they are relatively permanent magic, unlike the usually fleeting effects of potions, scrolls, and wands. .pg Putting on a ring activates its magic. You can wear only two rings, one on each ring finger. .pg Most rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. .pg The commands to use rings are `P' (put on) and `R' (remove). .hn 2 Spellbooks (`+') .pg Spellbooks are tomes of mighty magic. When studied with the `r' (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable) \(em unless the attempt backfires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! .pg A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. .pg Casting a spell calls forth magical energies and focuses them with your naked mind. Some of the magical energy released comes from within you, and casting several spells in a row may tire you. Casting of spells also requires practice. With practice, your skill in each category of spell casting will improve. Over time, however, your memory of each spell will dim, and you will need to relearn it. .pg Some spells are directional\(emyou must give a direction in which to cast them. You can also cast them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other spells are nondirectional\(emthey don't require a direction. .pg Just as weapons are divided into groups in which a character can become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises its skill group; using the `#enhance' command to advance a sufficiently exercised skill will affect all spells within the group. Advanced skill may increase the potency of spells, reduce their risk of failure during casting attempts, and improve the accuracy of the estimate for how much longer they will be retained in your memory. Skill slots are shared with weapons skills. (See also the section on ``Weapon proficiency''.) .pg Casting a spell also requires flexible movement, and wearing various types of armor may interfere with that. .pg The command to read a spellbook is the same as for scrolls, `r' (read). The `+' command lists each spell you know along with its level, skill category, chance of failure when casting, and an estimate of how strongly it is remembered. The `Z' (cast) command casts a spell. .hn 2 Tools (`(') .pg Tools are miscellaneous objects with various purposes. Some tools have a limited number of uses, akin to wand charges. For example, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. .pg The command to use tools is `a' (apply). .hn 3 Containers .pg You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the ``#loot'' extended command when you are standing on top of it (that is, on the same floor spot), or with the `a' (apply) command when you are carrying it. However, chests are often locked, and are in any case unwieldy objects. You must set one down before unlocking it by using a key or lock-picking tool with the `a' (apply) command, by kicking it with the `^D' command, or by using a weapon to force the lock with the ``#force'' extended command. .pg Some chests are trapped, causing nasty things to happen when you unlock or open them. You can check for and try to deactivate traps with the ``#untrap'' extended command. .hn 2 Amulets (`"') .pg Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some beneficial, some harmful, which are activated by putting them on. .pg Only one amulet may be worn at a time, around your neck. .pg The commands to use amulets are the same as for rings, `P' (put on) and `R' (remove). .hn 2 Gems (`*') .pg Some gems are valuable, and can be sold for a lot of gold. They are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. .pg Other small rocks are also categorized as gems, but they are much less valuable. All rocks, however, can be used as projectile weapons (if you have a sling). In the most desperate of cases, you can still throw them by hand. .hn 2 Large rocks (`\`') .pg Statues and boulders are not particularly useful, and are generally heavy. It is rumored that some statues are not what they seem. .pg Very large humanoids (giants and their ilk) have been known to use boulders as weapons. .hn 2 Gold (`$') .pg Gold adds to your score, and you can buy things in shops with it. There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). .hn 1 Conduct .pg As if winning NetHack were not difficult enough, certain players seek to challenge themselves by imposing restrictions on the way they play the game. The game automatically tracks some of these challenges, which can be checked at any time with the #conduct command or at the end of the game. When you perform an action which breaks a challenge, it will no longer be listed. This gives players extra ``bragging rights'' for winning the game with these challenges. Note that it is perfectly acceptable to win the game without resorting to these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. .pg Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures can survive long periods of time without food, there is a physiological need for water; thus there is no restriction on drinking beverages, even if they provide some minor food benefits. Calling upon your god for help with starvation does not violate any food challenges either. .pg A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and vegetables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are also considered to be vegetable matter. Certain human food is prepared without animal products; namely, lembas wafers, cram rations, food rations (gunyoki), K-rations, and C-rations. Metal or another normally indigestible material eaten while polymorphed into a creature that can digest it is also considered vegan food. Note however that eating such items still counts against foodless conduct. .pg Vegetarians do not eat animals; however, they are less selective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than the black puddings, eggs and food made from eggs (fortune cookies and pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. .pg Eating any kind of meat violates the vegetarian, vegan, and foodless conducts. This includes tripe rations, the corpses or tins of any monsters not mentioned above, and the various other chunks of meat found in the dungeon. Swallowing and digesting a monster while polymorphed is treated as if you ate the creature's corpse. Eating leather, dragon hide, or bone items while polymorphed into a creature that can digest it, or eating monster brains while polymorphed into a mind flayer, is considered eating an animal, although wax is only an animal byproduct. .pg Regardless of conduct, there will be some items which are indigestible, and others which are hazardous to eat. Using a swallow-and-digest attack against a monster is equivalent to eating the monster's corpse. Please note that the term ``vegan'' is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, coral), but the game will not keep track of this for you. Also note that ``milky'' potions may be a translucent white, but they do not contain milk, so they are compatible with a vegan diet. Slime molds or player-defined ``fruits'', although they could be anything from ``cherries'' to ``pork chops'', are also assumed to be vegan. .pg An atheist is one who rejects religion. This means that you cannot #pray, #offer sacrifices to any god, #turn undead, or #chat with a priest. Particularly selective readers may argue that playing Monk or Priest characters should violate this conduct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also not penalized for being spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. .pg Most players fight with a wielded weapon (or tool intended to be wielded as a weapon). Another challenge is to win the game without using such a wielded weapon. You are still permitted to throw, fire, and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. .pg In NetHack, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to gain experience by other means. .pg An illiterate character cannot read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writing a scroll; or making an engraving of anything other than a single ``x'' (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is assumed to be learned from your teachers prior to the start of the game and isn't counted. .pg There are several other challenges tracked by the game. It is possible to eliminate one or more species of monsters by genocide; playing without this feature is considered a challenge. When the game offers you an opportunity to genocide monsters, you may respond with the monster type ``none'' if you want to decline. You can change the form of an item into another item of the same type (``polypiling'') or the form of your own body into another creature (``polyself'') by wand, spell, or potion of polymorph; avoiding these effects are each considered challenges. Polymorphing monsters, including pets, does not break either of these challenges. Finally, you may sometimes receive wishes; a game without an attempt to wish for any items is a challenge, as is a game without wishing for an artifact (even if the artifact immediately disappears). When the game offers you an opportunity to make a wish for an item, you may choose ``nothing'' if you want to decline. .hn 1 Options .pg Due to variations in personal tastes and conceptions of how NetHack should do things, there are options you can set to change how NetHack behaves. .hn 2 Setting the options .pg Options may be set in a number of ways. Within the game, the `O' command allows you to view all options and change most of them. You can also set options automatically by placing them in the NETHACKOPTIONS environment variable or in a configuration file. Some versions of NetHack also have front-end programs that allow you to set options before starting the game or a global configuration for system administrators. .hn 2 Using the NETHACKOPTIONS environment variable .pg The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, and turn it off by typing a `!' or ``no'' before the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the string. The value is terminated by the next comma or the end of string. .pg For example, to set up an environment variable so that ``autoquiver'' is on, ``autopickup'' is off, the name is set to ``Blue Meanie'', and the fruit is set to ``papaya'', you would enter the command .sd % \fBsetenv NETHACKOPTIONS "autoquiver,\e!autopickup,name:Blue Meanie,fruit:papaya"\fP .ed in \fIcsh\fP (note the need to escape the ! since it's special to the shell), or .sd $ \fBNETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya"\fP $ \fBexport NETHACKOPTIONS\fP .ed in \fIsh\fP or \fIksh\fP. .hn 2 Using a configuration file .pg Any line in the configuration file starting with `#' is treated as a comment. Any line in the configuration file starting with ``OPTIONS='' may be filled out with options in the same syntax as in NETHACKOPTIONS. Any line starting with ``SYMBOLS='' is taken as defining the corresponding symbol in a different syntax, a sequence of decimal numbers giving the character position in the current font to be used in displaying each entry. Such a sequence can be continued to multiple lines by putting a `\e' at the end of each line to be continued. .pg Any line starting with ``AUTOPICKUP_EXCEPTION='' is taken as defining an exception to the .op pickup_types option. There is a section of this Guidebook that discusses that. .pg The default name of the configuration file varies on different operating systems, but NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `@'). .hn 2 Customization options .pg Here are explanations of what the various options do. Character strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. .pg Some options are persistent, and are saved and reloaded along with the game. Changing a persistent option in the configuration file applies only to new games. .lp acoustics Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio capabilities. Persistent. .lp align Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. The default is to randomly pick an appropriate alignment. If you prefix a `!' or ``no'' to the value, you can exclude that alignment from being picked randomly. Cannot be set with the `O' command. Persistent. .lp autodig Automatically dig if you are wielding a digging tool and moving into a place that can be dug (default false). Persistent. .lp autoopen Walking into a door attempts to open it (default true). Persistent. .lp "autopickup " Automatically pick up things onto which you move (default on). Persistent. See .op pickup_types to refine the behavior. .lp "autoquiver " This option controls what happens when you attempt the `f' (fire) command with an empty quiver (or quiver sack or have nothing at the ready). When true, the computer will fill your quiver or quiver sack or make ready some suitable weapon. Note that it will not take into account the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver or quiver sack or make ready with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is executed instead. Persistent. (default false) .lp blind Start the character permanently blind. Persistent. (default false) .lp bones Allow saving and loading bones files. Persistent. (default true) .lp boulder Set the character used to display boulders (default is rock class symbol). .lp catname Name your starting cat (ex. ``catname:Morris''). Cannot be set with the `O' command. .lp character Pick your type of character (ex. ``character:Monk''); synonym for ``role''. See ``name'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; the string ``random'' is an exception. .lp checkpoint Save game state after each level change, for possible recovery after program crash (default on). Persistent. .lp checkspace Check free disk space before writing files to disk (default on). You may have to turn this off if you have more than 2 GB free space on the partition used for your save and level files. Only applies when MFLOPPY was defined during compilation. .lp clicklook Allows looking at things on the screen by navigating the mouse over them and clicking the right mouse button (default off). .lp cmdassist Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). .lp "confirm " Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). Persistent. .lp dark_room Show out-of-sight areas of lit rooms (default off). Persistent. .lp disclose Controls what information the program reveals when the game ends. Value is a space separated list of prompting/category pairs (default is `\fBni na nv ng nc no\fP', prompt with default response of `\fBn\fP' for each candidate). Persistent. The possibilities are: .sd .si .CC i "disclose your inventory;" .CC a "disclose your attributes;" .CC v "summarize monsters that have been vanquished;" .CC g "list monster species that have been genocided;" .CC c "display your conduct;" .CC o "display dungeon overview." .ei .ed Each disclosure possibility can optionally be preceded by a prefix which lets you refine how it behaves. Here are the valid prefixes: .sd .si .CC y "prompt you and default to yes on the prompt;" .CC n "prompt you and default to no on the prompt;" .CC + "disclose it without prompting;" .CC - "do not disclose it and do not prompt." .ei .ed Omitted categories are implicitly added with `n' prefix. Specified categories with omitted prefix implicitly use `+' prefix. Order of the disclosure categories does not matter, program display for end-of-game disclosure follows a set sequence. .lp "" (ex. ``disclose:yi na +v -g o'') The example sets \fBinventory\fP to \fIprompt\fP and default to \fIyes\fP, \fBattributes\fP to \fIprompt\fP and default to \fIno\fP, \fBvanquished\fP to \fIdisclose without prompting\fP, \fBgenocided\fP to \fInot disclose\fP and \fInot prompt\fP, \fBconduct\fP to implicitly \fIprompt\fP and default to \fIno\fP, and \fBoverview\fP to \fIdisclose without prompting\fP. .lp "" Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. And the dungeon overview shows all levels you had visited but does not reveal things about them that you hadn't discovered. .lp dogname Name your starting dog (ex. ``dogname:Fang''). Cannot be set with the `O' command. .lp extmenu Changes the extended commands interface to pop-up a menu of available commands. It is keystroke compatible with the traditional interface except that it does not require that you hit Enter. It is implemented only by the tty port (default off), when the game has been compiled to support tty graphics. .lp female An obsolete synonym for ``gender:female''. Cannot be set with the `O' command. .lp fixinv An object's inventory letter sticks to it when it's dropped (default on). If this is off, dropping an object shifts all the remaining inventory letters. Persistent. .lp "fruit " Name a fruit after something you enjoy eating (ex. ``fruit:mango'') (default ``slime mold''). Basically a nostalgic whimsy that NetHack uses from time to time. You should set this to something you find more appetizing than slime mold. Apples, oranges, pears, bananas, and melons already exist in NetHack, so don't use those. .lp gender Your starting gender (gender:male or gender:female). You may specify just the first letter. Although you can still denote your gender using the ``male'' and ``female'' options, the ``gender'' option will take precedence. The default is to randomly pick an appropriate gender. If you prefix a `!' or ``no'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `O' command. Persistent. .lp "help " If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turning help off makes just looking at things faster, since you aren't interrupted with the ``More info?'' prompt, but it also means that you might miss some interesting and/or important information. Persistent. .lp hilite_pet Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. .lp hilite_pile Visually distinguish piles of objects from individual objects (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a small plus-symbol beside the object on the top of the pile. .lp horsename Name your starting horse (ex. ``horsename:Trigger''). Cannot be set with the `O' command. .lp ignintr Ignore interrupt signals, including breaks (default off). Persistent. .lp implicit_uncursed Omit "uncursed" from inventory lists, if possible (default on). .lp legacy Display an introductory message when starting the game (default on). Persistent. .lp lit_corridor Show corridor squares seen by night vision or a light source held by your character as lit (default off). Persistent. .lp lootabc Use the old `a', `b', and `c' keyboard shortcuts when looting, rather than the mnemonics `o', `i', and `b' (default off). Persistent. .lp "mail " Enable mail delivery during the game (default on). Persistent. .lp "male " An obsolete synonym for ``gender:male''. Cannot be set with the `O' command. .lp mention_walls Give feedback when walking against a wall (default off). .lp menucolors Enable coloring menu lines (default off). See ``Configuring Menu Colors'' on how to configure the colors. .lp menustyle Controls the interface used when you need to choose various objects (in response to the Drop command, for instance). The value specified should be the first letter of one of the following: traditional, combination, full, or partial. Traditional was the only interface available for early versions; it consists of a prompt for object class characters, followed by an object-by-object prompt for all items matching the selected object class(es). Combination starts with a prompt for object class(es) of interest, but then displays a menu of matching objects rather than prompting one-by-one. Full displays a menu of object classes rather than a character prompt, and then a menu of matching objects for selection. Partial skips the object class filtering and immediately displays a menu of all objects. Persistent. .lp menu_deselect_all Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '-'. .lp menu_deselect_page Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default '\e'. .lp menu_first_page Menu character accelerator to jump to the first page in a menu. Implemented by the Amiga, Gem and tty ports. Default '^'. .lp menu_headings Controls how the headings in a menu are highlighted. Values are 'none', 'bold', 'dim', 'underline', 'blink', or 'inverse'. Not all ports can actually display all types. .lp menu_invert_all Menu character accelerator to invert all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '@'. .lp menu_invert_page Menu character accelerator to invert all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default '~'. .lp menu_last_page Menu character accelerator to jump to the last page in a menu. Implemented by the Amiga, Gem and tty ports. Default '|'. .lp menu_next_page Menu character accelerator to goto the next menu page. Implemented by the Amiga, Gem and tty ports. Default '>'. .lp menu_objsyms Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). .lp menu_previous_page Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. Default '<'. .lp menu_search Menu character accelerator to search for a menu item. Implemented by the Amiga, Gem, X11 and tty ports. Default ':'. .lp menu_select_all Menu character accelerator to select all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '.'. .lp menu_select_page Menu character accelerator to select all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default ','. .lp msghistory The number of top line messages to save (and recall with ^P) (default 20). Cannot be set with the `O' command. .lp msg_window Allows you to change the way recalled messages are displayed. (It is currently implemented for tty only.) The possible values are: .sd .si .CC s "single message (default; only choice prior to 3.4.0);" .CC c "combination, two messages as `single', then as `full';" .CC f "full window, oldest message first;" .CC r "full window reversed, newest message first." .ei .ed For backward compatibility, no value needs to be specified (which defaults to `full'), or it can be negated (which defaults to `single'). .lp "name " Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of .op "-A -B -C -H -K -M -P -Ra -Ro -S -T -V -W" ). If .op "-@" is used for the role, then a random one will be automatically chosen. Cannot be set with the `O' command. .lp "news " Read the NetHack news file, if present (default on). Since the news is shown at the beginning of the game, there's no point in setting this with the `O' command. .lp nudist Start the character with no armor (default false). Persistent. .lp "null " Send padding nulls to the terminal (default on). Persistent. .lp number_pad Use digit keys instead of letters to move (default 0 or off). Valid settings are: .PS -1 .PL "\ 0" move by letters; `yuhjklbn' .PL "\ 1" move by numbers; digit `5' acts as `G' movement prefix .PL "\ 2" like 1 but `5' works as `g' prefix instead of as `G' .PL "\ 3" by numbers using phone key layout; 123 above, 789 below .PL "\ 4" combines 3 with 2; phone layout plus MSDOS compatibility .PL "-1" by letters but use `z' to go northwest, `y' to zap wands .PE For backward compatibility, omitting a value is the same as specifying 1 and negating .op number_pad is the same as specifying 0. (Settings 2 and 4 are for compatibility with MSDOS or old PC Hack; in addition to the different behavior for `5', `Alt-5' acts as `G' and `Alt-0' acts as `I'. Setting -1 is to accommodate some German keyboards which have the location of the `y' and `z' keys swapped.) When moving by numbers, to enter a count prefix for those commands which accept one (such as ``12s'' to search twelve times), precede it with the letter `n' (``n12s''). .lp packorder Specify the order to list object types in (default ``")[%?+!=/(*`0_''). The value of this option should be a string containing the symbols for the various object types. Any omitted types are filled in at the end from the previous order. .lp paranoid_confirmation A space separated list of specific situations where alternate prompting is desired. The default is paranoid_confirmation:pray. .PS Confirm .PL Confirm for any prompts which are set to require "yes" rather than 'y', also require "no" to reject instead of accepting any non-yes response as no .PL quit require "yes" rather than 'y' to confirm quitting the game or switching into non-scoring explore mode; .PL die require "yes" rather than 'y' to confirm dying (not useful in normal play; applies to explore mode); .PL bones require "yes" rather than 'y' to confirm saving bones data when dying in debug mode; .PL attack require "yes" rather than 'y' to confirm attacking a peaceful monster; .PL pray require 'y' to confirm an attempt to pray rather than immediately praying; on by default; .PL wand require "yes" rather than 'y' to confirm breaking a wand; .PL Remove require selection from inventory for 'R' and 'T' commands even when wearing just one applicable item. .PE By default, the pray choice is enabled, the others disabled. To disable it without setting any of the other choices, use ``paranoid_confirmation:none''. To keep it enabled while setting any of the others, include it in the list, such as ``paranoid_confirmation:attack pray Remove''. .lp perm_invent If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. Persistent. .lp pettype Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. Possible values are ``cat'', ``dog'', ``horse'', and ``none''. If the choice is not allowed for the role you are currently playing, it will be silently ignored. For example, ``horse'' will only be honored when playing a knight. Cannot be set with the `O' command. .lp pickup_burden When you pick up an item that would exceed this encumbrance level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default `S'). Persistent. .lp pickup_thrown If this option is on and .op autopickup is also on, try to pick up things that you threw, even if they aren't in .op pickup_types or match an autopickup exception. Default is on. Persistent. .lp pickup_types Specify the object types to be picked up when .op autopickup is on. Default is all types. You can use .op autopickup_exception configuration file lines to further refine .op autopickup behavior. Persistent. .lp pile_limit When walking across a pile of objects on the floor, threshold at which the message "there are few/several/many objects here" is given instead of showing a popup list of those objects. A value of 0 means "no limit" (always list the objects); a value of 1 effectively means "never show the objects" since the pile size will always be at least that big; default value is 5. Persistent. .lp playmode Values are `normal', `explore', or `debug'. Allows selection of explore mode (also known as discovery mode) or debug mode (also known as wizard mode) instead of normal play. Debug mode might only be allowed for someone logged in under a particular user name (on multi-user systems) or specifying a particular character name (on single-user systems) or it might be disabled entirely. Requesting it when not allowed or not possible results in explore mode instead. Default is normal play. .lp pushweapon Using the `w' (wield) command when already wielding something pushes the old item into your alternate weapon slot (default off). Likewise for the `a' (apply) command if it causes the applied item to become wielded. Persistent. .lp "race " Selects your race (for example, ``race:human''). Default is random. If you prefix a `!' or ``no'' to the value, you can exclude that race from being picked randomly. Cannot be set with the `O' command. Persistent. .lp rest_on_space Make the space bar a synonym for the `.' (rest) command (default off). Persistent. .lp "role " Pick your type of character (ex. ``role:Samurai''); synonym for ``character''. See ``name'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; `r' is an exception with ``Rogue'', ``Ranger'', and ``random'' values. If you prefix a `!' or ``no'' to the value, you can exclude that role from being picked randomly. Persistent. .lp roguesymset This option may be used to select one of the named symbol sets found within ``symbols'' to alter the symbols displayed on the screen on the rogue level. .lp rlecomp When writing out a save file, perform run length compression of the map. Not all ports support run length compression. It has no effect on reading an existing save file. .lp runmode Controls the amount of screen updating for the map window when engaged in multi-turn movement (running via shift+direction or control+direction and so forth, or via the travel command or mouse click). The possible values are: .PS teleport .PL teleport update the map after movement has finished; .PL run update the map after every seven or so steps; .PL walk update the map after each step; .PL crawl like walk, but pause briefly after each step. .PE This option only affects the game's screen display, not the actual results of moving. The default is `run'; versions prior to 3.4.1 used `teleport' only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. Persistent. .lp safe_pet Prevent you from (knowingly) attacking your pets (default on). Persistent. .lp scores Control what parts of the score list you are shown at the end (ex. ``scores:5 top scores/4 around my score/own scores''). Only the first letter of each category (`t', `a', or `o') is necessary. Persistent. .lp showexp Show your accumulated experience points on bottom line (default off). Persistent. .lp showrace Display yourself as the glyph for your race, rather than the glyph for your role (default off). Note that this setting affects only the appearance of the display, not the way the game treats you. Persistent. .lp showscore Show your approximate accumulated score on bottom line (default off). Persistent. .lp "silent " Suppress terminal beeps (default on). Persistent. .lp sortloot Controls the sorting behavior of the pickup lists for inventory and #loot commands and some others. Persistent. The possible values are: .PS full .PL full always sort the lists; .PL loot only sort the lists that don't use inventory letters, like with the #loot and pickup commands; .PL none show lists the traditional way without sorting. .PE .lp sortpack Sort the pack contents by type when displaying inventory (default on). Persistent. .lp sparkle Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). Persistent. .lp standout Boldface monsters and ``\fB--More--\fP'' (default off). Persistent. .lp statushilites Enable coloring of status fields (default off). See ``Configuring Status Hilites'' for futher information. .lp suppress_alert This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior versions (ex. ``suppress_alert:3.3.1''). .lp symset This option may be used to select one of the named symbol sets found within ``symbols'' to alter the symbols displayed on the screen. .lp "time " Show the elapsed game time in turns on bottom line (default off). Persistent. .lp timed_delay When pausing momentarily for display effect, such as with explosions and moving objects, use a timer rather than sending extra characters to the screen. (Applies to ``tty'' interface only; ``X11'' interface always uses a timer based delay. The default is on if configured into the program.) Persistent. .lp tombstone Draw a tombstone graphic upon your death (default on). Persistent. .lp toptenwin Put the ending display in a NetHack window instead of on stdout (default off). Setting this option makes the score list visible when a windowing version of NetHack is started without a parent window, but it no longer leaves the score list around after game end on a terminal or emulating window. .lp travel Allow the travel command (default on). Turning this option off will prevent the game from attempting unintended moves if you make inadvertent mouse clicks on the map window. Persistent. .lp verbose Provide more commentary during the game (default on). Persistent. .lp windowtype Select which windowing system to use, such as ``tty'' or ``X11'' (default depends on version). Cannot be set with the `O' command. .lp zerocomp When writing out a save file, perform zero-comp compression of the contents. Not all ports support zero-comp compression. It has no effect on reading an existing save file. .hn 2 Window Port Customization options .pg Here are explanations of the various options that are used to customize and change the characteristics of the windowtype that you have chosen. Character strings that are too long may be truncated. Not all window ports will adjust for all settings listed here. You can safely add any of these options to your config file, and if the window port is capable of adjusting to suit your preferences, it will attempt to do so. If it can't it will silently ignore it. You can find out if an option is supported by the window port that you are currently using by checking to see if it shows up in the Options list. Some options are dynamic and can be specified during the game with the `O' command. .lp align_message Where to align or place the message window (top, bottom, left, or right) .lp align_status Where to align or place the status window (top, bottom, left, or right). .lp ascii_map NetHack should display an ascii character map if it can. .lp color NetHack should display color if it can for different monsters, objects, and dungeon features .lp eight_bit_tty NetHack should pass eight-bit character values (for example, specified with the .op traps option) straight through to your terminal (default off). .lp font_map NetHack should use a font by the chosen name for the map window. .lp font_menu NetHack should use a font by the chosen name for menu windows. .lp font_message NetHack should use a font by the chosen name for the message window. .lp font_status NetHack should use a font by the chosen name for the status window. .lp font_text NetHack should use a font by the chosen name for text windows. .lp font_size_map NetHack should use this size font for the map window. .lp font_size_menu NetHack should use this size font for menu windows. .lp font_size_message NetHack should use this size font for the message window. .lp font_size_status NetHack should use this size font for the status window. .lp font_size_text NetHack should use this size font for text windows. .lp fullscreen NetHack should try and display on the entire screen rather than in a window. .lp large_font NetHack should use a large font. .lp map_mode NetHack should display the map in the manner specified. .lp mouse_support Allow use of the mouse for input and travel. .lp player_selection NetHack should pop up dialog boxes, or use prompts for character selection. .lp popup_dialog NetHack should pop up dialog boxes for input. .lp preload_tiles NetHack should preload tiles into memory. For example, in the protected mode MSDOS version, control whether tiles get pre-loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. (default on). Cannot be set with the `O' command. .lp scroll_amount NetHack should scroll the display by this number of cells when the hero reaches the scroll_margin. .lp scroll_margin NetHack should scroll the display when the hero or cursor is this number of cells away from the edge of the window. .lp selectsaved NetHack should display a menu of existing saved games for the player to choose from at game startup, if it can. Not all ports support this option. .lp softkeyboard Display an onscreen keyboard. Handhelds are most likely to support this option. .lp splash_screen NetHack should display an opening splash screen when it starts up (default yes). .lp tiled_map NetHack should display a tiled map if it can. .lp tile_file Specify the name of an alternative tile file to override the default. .lp tile_height Specify the preferred height of each tile in a tile capable port. .lp tile_width Specify the preferred width of each tile in a tile capable port .lp use_darkgray Use bold black instead of blue for black glyphs (TTY only). .lp use_inverse NetHack should display inverse when the game specifies it. .lp vary_msgcount NetHack should display this number of messages at a time in the message window. .lp windowcolors NetHack should display windows with the specified foreground/background colors if it can. .lp wraptext NetHack port should wrap long lines of text if they don't fit in the visible area of the window. .hn 2 Platform-specific Customization options .pg Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. .lp altkeyhandler Select an alternate keystroke handler dll to load (Win32 tty NetHack only). The name of the handler is specified without the .dll extension and without any path information. Cannot be set with the `O' command. .lp altmeta On Amiga, this option controls whether typing `Alt' plus another key functions as a meta-shift for that key (default on). .lp altmeta On other (non-Amiga) systems where this option is available, it can be set to tell nethack to convert a two character sequence beginning with ESC into a meta-shifted version of the second character (default off). .lp "" This conversion is only done for commands, not for other input prompts. Note that typing one or more digits as a count prefix prior to a command--preceded by \fBn\fP if the .op number_pad option is set--is also subject to this conversion, so attempting to abort the count by typing ESC will leave nethack waiting for another character to complete the two character sequence. Type a second ESC to finish cancelling such a count. At other prompts a single ESC suffices. .lp "BIOS " Use BIOS calls to update the screen display quickly and to read the keyboard (allowing the use of arrow keys to move) on machines with an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack only). .lp flush (default off, AMIGA NetHack only). .lp "MACgraphics" (default on, Mac NetHack only). .lp page_wait (default on, Mac NetHack only). .lp "rawio " Force raw (non-cbreak) mode for faster output and more bulletproof input (MS-DOS sometimes treats `^P' as a printer toggle without it) (default off, OS/2, PC, and ST NetHack only). Note: DEC Rainbows hang if this is turned on. Cannot be set with the `O' command. .lp soundcard (default on, PC NetHack only). Cannot be set with the `O' command. .lp subkeyvalue (Win32 tty NetHack only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate for international keyboard issues. OPTIONS=subkeyvalue:171/92 will return 92 to NetHack, if 171 was originally going to be returned. You can use multiple subkeyvalue statements in the config file if needed. Cannot be set with the `O' command. .lp video Set the video mode used (PC NetHack only). Values are `autodetect', `default', or `vga'. Setting `vga' (or `autodetect' with vga hardware present) will cause the game to display tiles. Cannot be set with the `O' command. .lp videocolors Set the color palette for PC systems using NO_TERMS (default 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only). The order of colors is red, green, brown, blue, magenta, cyan, bright.white, bright.red, bright.green, yellow, bright.blue, bright.magenta, and bright.cyan. Cannot be set with the `O' command. .lp videoshades Set the intensity level of the three gray scales available (default dark normal light, PC NetHack only). If the game display is difficult to read, try adjusting these scales; if this does not correct the problem, try !color. Cannot be set with the `O' command. .hn 2 Regular Expressions .pg Regular expressions are normally POSIX extended regular expressions. It is possible to compile NetHack without regular expression support on a platform where there is no regular expression library. While this is not true of any modern platform, if your NetHack was built this way, patterns are instead glob patterns. .hn 2 Configuring Autopickup Exceptions .pg You can further refine the behavior of the .op autopickup option beyond what is available through the .op pickup_types option. .pg By placing .op autopickup_exception lines in your configuration file, you can define patterns to be checked when the game is about to autopickup something. .lp autopickup_exception Sets an exception to the .op pickup_types option. The .op autopickup_exception option should be followed by a regular expression to be used as a pattern to match against the singular form of the description of an object at your location. .lp "" In addition, some characters are treated specially if they occur as the first character in the pattern, specifically: .sd .si .CC < "always pickup an object that matches rest of pattern;" .CC > "never pickup an object that matches rest of pattern." .ei .ed A `never pickup' rule takes precedence over an `always pickup' rule if both match. .lp "" Exceptions can be set with the `\fBO\fP' command, but ones set that way will not be preserved across saves and restores. .\" end of ``.lp autopickup_exception'' entry; continue enclosing page... .\" use .lp "text" to make an unindented paragraph ("text" should be short) .lp "Here are some examples:" .sd .si autopickup_exception="<*arrow" autopickup_exception=">*corpse" autopickup_exception=">* cursed*" .ei .ed .\" (this paragraph would look better unindented but can't use .lp hack...) .pg The first example above will result in autopickup of any type of arrow. The second example results in the exclusion of any corpse from autopickup. The last example results in the exclusion of items known to be cursed from autopickup. .hn 2 Configuring Message Types .pg You can change the way the messages are shown in the message area, when the message matches a user-defined pattern. .pg In general, the config file entries to configure the message types look like this: .si MSGTYPE=type "pattern" .ei .PS "message type" .PL type how the message should be shown; .PL pattern the pattern to match. .PE .lp "" The pattern should be a regular expression. .lp "" Allowed types are: .sd .si show - show message normally. hide - never show the message. stop - wait for user with more-prompt. norep - show the message once, but not again if no other message is shown in between. .ei .ed .lp "" Here's an example of message types using NetHack's internal pattern matching facility: .sd .si MSGTYPE=stop "You feel hungry." MSGTYPE=hide "You displaced *." .ei .ed specifies that whenever a message "You feel hungry" is shown, the user is prompted with more-prompt, and a message matching "You displaced ." is not shown at all. .lp "" The order of the defined MSGTYPE-lines is important; the last matching rule is used. Put the general case first, exceptions below them. .hn 2 Configuring Menu Colors .pg Some platforms allow you to define colors used in menu lines when the line matches a user-defined pattern. At this time the tty, win32tty and win32gui support this. .pg In general, the config file entries to configure the menu color mappings look like this: .si .lp MENUCOLOR="pattern"=color&attribute .ei .PS "menu color" .PL pattern the pattern to match; .PL color the color to use for lines matching the pattern; .PL attribute the attribute to use for lines matching the pattern. The attribute is optional, and if left out, you must also leave out the preceding ampersand. If no attribute is defined, no attribute is used. .PE .lp "" The pattern should be a regular expression. .lp "" Allowed colors are black, red, green, brown, blue, magenta, cyan, gray, orange, lightgreen, yellow, lightblue, lightmagenta, lightcyan, and white. .lp "" Allowed attributes are none, bold, dim, underline, blink, and inverse. Note that the platform used may interpret the attributes any way it wants. .lp "" Here's an example of menu colors using NetHack's internal pattern matching facility: .sd .si MENUCOLOR="* blessed *"=green MENUCOLOR="* cursed *"=red MENUCOLOR="* cursed *(being worn)"=red&underline .ei .ed specifies that any menu line with " blessed " contained in it will be shown in green color, lines with " cursed " will be shown in red, and lines with " cursed " followed by "(being worn)" on the same line will be shown in red color and underlined. You can have multiple MENUCOLOR entries in your config file, and the last MENUCOLOR-line in your config file that matches a menu line will be used for the line. .pg Note that if you intend to have one or more color specifications match " uncursed ", you will probably want to turn the .op implicit_uncursed option off so that all items known to be uncursed are actually displayed with the ``uncursed'' description. .hn 2 Configuring User Sounds .pg Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. .pg The following config file entries are relevant to mapping user sounds to messages: .lp SOUNDDIR The directory that houses the sound files to be played. .lp SOUND An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: .PS "sound file" .PL MESG message window mapping (the only one supported in 3.6); .PL pattern the pattern to match; .PL "sound file" the sound file to play; .PL volume the volume to be set while playing the sound file. .PE .lp "" The pattern should be a POSIX extended regular expression. .pg .hn 2 Configuring Status Hilites .pg Your copy of NetHack may have been compiled with support for ``Status Hilites''. If so, you can customize your game display by setting thresholds to change the color or appearance of fields in the status display. .pg For example, the following line in your config file will cause the hitpoints field to display in the color red if your hitpoints drop to or below a threshold of 30%: .si .lp "OPTION=hilite_status: hitpoints/30%/red/normal" .ei .pg For another example, the following line in your config file will cause wisdom to be displayed red if it drops and green if it rises. .si .lp "OPTION=hilite_status: wisdom/updown/red/green" .ei .pg You can adjust the display of the following status fields: .TS S center; c c c. .\"TABLE_START title strength dexterity constitution intelligence wisdom charisma alignment score carrying-capacity gold power power-max experience-level armor-class HD time hunger hitpoints hitpoints-max dungeon-level experience condition .\"TABLE_END Do not delete this line. .TE .lp "" Allowed colors are black, red, green, brown, blue, magenta, cyan, gray, orange, lightgreen, yellow, lightblue, lightmagenta, lightcyan, and white. .lp "" Allowed attributes are bold, inverse, normal. Note that the platform used may interpret the attributes any way it wants. .lp "" Behaviours can occur based on percentage thresholds, updown, or absolute values. The in-game options menu can help you determine the correct syntax for a config file. .lp "" The whole feature can be disabled by setting option statushilites off. .pg .hn 2 Modifying NetHack Symbols .pg NetHack can load entire symbol sets from the symbol file. .pg The options that are used to select a particular symbol set from the symbol file are: .lp symset Set the name of the symbol set that you want to load. .lp roguesymset Set the name of the symbol set that you want to load for display on the rogue level. .pg You can also override one or more symbols using the SYMBOLS config file option. Symbols are specified as name:value pairs. Note that NetHack escape-processes the value string in conventional C fashion. This means that \e is a prefix to take the following character literally. Thus \e needs to be represented as \e\e. The special escape form \em switches on the meta bit in the symbol value, and the \e^ prefix causes the following character to be treated as a control character. .pg .TS S center; c s s c1 l1 l. .\"TABLE_START NetHack Symbols Default Symbol Name Description \_ \_ \_ S_air (air) \&_ S_altar (altar) " S_amulet (amulet) A S_angel (angelic being) a S_ant (ant or other insect) ^ S_anti_magic_trap (anti-magic field) [ S_armor (suit or piece of armor) [ S_armour (suit or piece of armor) ^ S_arrow_trap (arrow trap) 0 S_ball (iron ball) # S_bars (iron bars) B S_bat (bat or bird) ^ S_bear_trap (bear trap) - S_blcorn (bottom left corner) b S_blob (blob) + S_book (spellbook) ) S_boomleft (boomerang open left) ( S_boomright (boomerang open right) ` S_boulder (boulder) - S_brcorn (bottom right corner) C S_centaur (centaur) \&_ S_chain (iron chain) # S_cloud (cloud) c S_cockatrice (cockatrice) $ S_coin (pile of coins) # S_corr (corridor) - S_crwall (wall) ^ S_dart_trap (dart trap) & S_demon (major demon) * S_digbeam (dig beam) > S_dnladder (ladder down) > S_dnstair (staircase down) d S_dog (dog or other canine) D S_dragon (dragon) ; S_eel (sea monster) E S_elemental (elemental) / S_explode1 (explosion top left) - S_explode2 (explosion top center) `\e' S_explode3 (explosion top right) | S_explode4 (explosion middle left) S_explode5 (explosion middle center) | S_explode6 (explosion middle right) `\e' S_explode7 (explosion bottom left) - S_explode8 (explosion bottom center) / S_explode9 (explosion bottom right) e S_eye (eye or sphere) ^ S_falling_rock_trap (falling rock trap) f S_feline (cat or other feline) ^ S_fire_trap (fire trap) ! S_flashbeam (flash beam) % S_food (piece of food) { S_fountain (fountain) F S_fungus (fungus or mold) * S_gem (gem or rock) S_ghost (ghost) H S_giant (giant humanoid) G S_gnome (gnome) ' S_golem (golem) | S_grave (grave) g S_gremlin (gremlin) - S_hbeam (wall) # S_hcdbridge (horizontal raised drawbridge) + S_hcdoor (closed door) . S_hodbridge (horizontal lowered drawbridge) | S_hodoor (open door) ^ S_hole (hole) @ S_human (human or elf) h S_humanoid (humanoid) - S_hwall (horizontal wall) . S_ice (ice) i S_imp (imp or minor demon) J S_jabberwock (jabberwock) j S_jelly (jelly) k S_kobold (kobold) K S_kop (Keystone Kop) ^ S_land_mine (land mine) } S_lava (molten lava) l S_leprechaun (leprechaun) ^ S_level_teleporter (level teleporter) L S_lich (lich) y S_light (light) # S_litcorr (lit corridor) : S_lizard (lizard) `\e' S_lslant (wall) ^ S_magic_portal (magic portal) ^ S_magic_trap (magic trap) m S_mimic (mimic) ] S_mimic_def (mimic) M S_mummy (mummy) N S_naga (naga) . S_ndoor (doorway) n S_nymph (nymph) O S_ogre (ogre) o S_orc (orc) p S_piercer (piercer) ^ S_pit (pit) # S_poisoncloud (poison cloud) ^ S_polymorph_trap (polymorph trap) } S_pool (water) ! S_potion (potion) P S_pudding (pudding or ooze) q S_quadruped (quadruped) Q S_quantmech (quantum mechanic) \&= S_ring (ring) ` S_rock (boulder or statue) r S_rodent (rodent) ^ S_rolling_boulder_trap (rolling boulder trap) . S_room (floor of a room) / S_rslant (wall) ^ S_rust_trap (rust trap) R S_rustmonst (rust monster or disenchanter) ? S_scroll (scroll) # S_sink (sink) ^ S_sleeping_gas_trap (sleeping gas trap) S S_snake (snake) s S_spider (arachnid or centipede) ^ S_spiked_pit (spiked pit) ^ S_squeaky_board (squeaky board) 0 S_ss1 (magic shield 1 of 4) # S_ss2 (magic shield 2 of 4) @ S_ss3 (magic shield 3 of 4) * S_ss4 (magic shield 4 of 4) ^ S_statue_trap (statue trap) S_stone (dark part of a room) - S_sw_bc (swallow bottom center) `\e' S_sw_bl (swallow bottom left) / S_sw_br (swallow bottom right) | S_sw_ml (swallow middle left) | S_sw_mr (swallow middle right) - S_sw_tc (swallow top center) / S_sw_tl (swallow top left) `\e' S_sw_tr (swallow top right) - S_tdwall (wall) ^ S_teleportation_trap (teleportation trap) \ S_throne (opulent throne) - S_tlcorn (top left corner) | S_tlwall (wall) ( S_tool (useful item (pick-axe\, key\, lamp...)) ^ S_trap_door (trap door) t S_trapper (trapper or lurker above) - S_trcorn (top right corner) # S_tree (tree) T S_troll (troll) | S_trwall (wall) - S_tuwall (wall) U S_umber (umber hulk) u S_unicorn (unicorn or horse) < S_upladder (ladder up) < S_upstair (staircase up) V S_vampire (vampire) | S_vbeam (wall) # S_vcdbridge (vertical raised drawbridge) + S_vcdoor (closed door) . S_venom (splash of venom) ^ S_vibrating_square (vibrating square) . S_vodbridge (vertical lowered drawbridge) - S_vodoor (open door) v S_vortex (vortex) | S_vwall (vertical wall) / S_wand (wand) } S_water (water) ) S_weapon (weapon) " S_web (web) w S_worm (worm) ~ S_worm_tail (long worm tail) W S_wraith (wraith) x S_xan (xan or other mythical/fantastic insect) X S_xorn (xorn) Y S_yeti (apelike creature) Z S_zombie (zombie) z S_zruty (zruty) .\"TABLE_END Do not delete this line. .TE .pg .hn 2 Configuring NetHack for Play by the Blind .pg NetHack can be set up to use only standard ASCII characters for making maps of the dungeons. This makes the MS-DOS versions of NetHack completely accessible to the blind who use speech and/or Braille access technologies. Players will require a good working knowledge of their screen-reader's review features, and will have to know how to navigate horizontally and vertically character by character. They will also find the search capabilities of their screen-readers to be quite valuable. Be certain to examine this Guidebook before playing so you have an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your character since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. .pg While it is not difficult for experienced users to edit the \fBdefaults.nh\fP file to accomplish this, novices may find this task somewhat daunting. Included within the ``symbols'' file of all official distributions of NetHack is a symset called \fBNHAccess\fP. Selecting that symset in your configuration file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings via \fBSYMBOLS=\fP in your configuration file to better suit your preferences. The most crucial settings to make the game accessible are: .pg .lp symset:NHAccess Load a symbol set appropriate for use by blind players. .lp roguesymset:NHAccess Load a symbol set for the rogue level that is appropriate for use by blind players. .lp menustyle:traditional This will assist in the interface to speech synthesizers. .lp number_pad A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number_pad option and use the traditional Rogue-like commands. .hn 2 Global Configuration for System Administrators .pg If NetHack is compiled with the SYSCF option, a system administrator should set up a global configuration; this is a file in the same format as the traditional per-user configuration file (see above). This file should be named sysconf and placed in the same directory as the other NetHack support files. The options recognized in this file are listed below. Any option not set uses a compiled-in default (which may not be appropriate for your system). .pg .lp WIZARDS A space-separated list of user names who are allowed to play in wizard mode (the debugging mode, not the magic-using role). A value of a single asterisk (*) allows anyone to start a game in wizard mode. .lp SHELLERS A list of users who are allowed to use the shell escape command (!). The syntax is the same as WIZARDS. .lp EXPLORERS A list of users who are allowed to use the explore mode. The syntax is the same as WIZARDS. .lp MAXPLAYERS Limit the maximum number of games that can be running at the same time. .lp SUPPORT A string explaining how to get local support (no default value). .lp RECOVER A string explaining how to recover a game on this system (no default value). .lp SEDUCE 0 or 1 to disable or enable, respectively, the SEDUCE option (see the source for details on this function). .lp CHECK_SAVE_UID 0 or 1 to disable or enable, respectively, the UID checking for savefiles. .pg The following options affect the score file: .pg .lp PERSMAX Maximum number of entries for one person. .lp ENTRYMAX Maximum number of entries in the score file. .lp POINTSMIN Minimum number of points to get an entry in the score file. .lp PERS_IS_UID 0 or 1 to use user names or numeric userids, respectively, to identify unique people for the score file. .lp MAX_STATUENAME_RANK Maximum number of score file entries to use for random statue names (default is 10). .hn 1 Scoring .pg NetHack maintains a list of the top scores or scorers on your machine, depending on how it is set up. In the latter case, each account on the machine can post only one non-winning score on this list. If you score higher than someone else on this list, or better your previous score, you will be inserted in the proper place under your current name. How many scores are kept can also be set up when NetHack is compiled. .pg Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will only hear about 90% of your gold when your corpse is discovered (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. .pg If you just want to see what the current top players/games list is, you can type \fBnethack -s all\fP on most versions. .hn 1 Explore mode .pg NetHack is an intricate and difficult game. Novices might falter in fear, aware of their ignorance of the means to survive. Well, fear not. Your dungeon comes equipped with an ``explore'' or ``discovery'' mode that enables you to keep old save files and cheat death, at the paltry cost of not getting on the high score list. .pg There are two ways of enabling explore mode. One is to start the game with the .op -X command-line switch or with the .op playmode:explore option. The other is to issue the ``#exploremode'' extended command while already playing the game. Starting a new game in explore mode provides your character with a wand of wishing in initial inventory; switching during play does not. The other benefits of explore mode are left for the trepid reader to discover. .pg .hn 2 Debug mode .pg Debug mode, also known as wizard mode, is undocumented aside from this brief description. It is intended for tracking down problems within the program rather than to provide god-like powers to your character, and players who attempt debugging are expected to figure out how to use it themselves. It is initiated by starting the game with the .op -D command-line switch or with the .op playmode:debug option. .pg For some systems, the player must be logged in under a particular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the Wizard role). And on any system, the program might have been configured to omit debug mode entirely. Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. .hn Credits .pg The original \fIhack\fP game was modeled on the Berkeley .ux \fIrogue\fP game. Large portions of this paper were shamelessly cribbed from \fIA Guide to the Dungeons of Doom\fP, by Michael C. Toy and Kenneth C. R. C. Arnold. Small portions were adapted from \fIFurther Exploration of the Dungeons of Doom\fP, by Ken Arromdee. .pg NetHack is the product of literally dozens of people's work. Main events in the course of the game development are described below: .pg \fBJay Fenlason\fP wrote the original Hack, with help from \fBKenny Woodland\fP, \fBMike Thome\fP and \fBJon Payne\fP. .pg \fBAndries Brouwer\fP did a major re-write, transforming Hack into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for .ux machines to the Usenet. .pg \fBDon G. Kneller\fP ported Hack 1.0.3 to Microsoft C and MS-DOS, producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6). .pg \fBR. Black\fP ported PC HACK 3.51 to Lattice C and the Atari 520/1040ST, producing ST Hack 1.03. .pg \fBMike Stephenson\fP merged these various versions back together, incorporating many of the added features, and produced NetHack 1.4. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. .pg Later, Mike coordinated a major rewrite of the game, heading a team which included \fBKen Arromdee\fP, \fBJean-Christophe Collet\fP, \fBSteve Creps\fP, \fBEric Hendrickson\fP, \fBIzchak Miller\fP, \fBJohn Rupley\fP, \fBMike Threepoint\fP, and \fBJanet Walz\fP, to produce NetHack 3.0c. .pg NetHack 3.0 was ported to the Atari by \fBEric R. Smith\fP, to OS/2 by \fBTimo Hakulinen\fP, and to VMS by \fBDavid Gentzel\fP. The three of them and \fBKevin Darcy\fP later joined the main development team to produce subsequent revisions of 3.0. .pg \fBOlaf Seibert\fP ported NetHack 2.3 and 3.0 to the Amiga. \fBNorm Meluch\fP, \fBStephen Spackman\fP and \fBPierre Martineau\fP designed overlay code for PC NetHack 3.0. \fBJohnny Lee\fP ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. .pg Headed by \fBMike Stephenson\fP and coordinated by \fBIzchak Miller\fP and \fBJanet Walz\fP, the development team which now included \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJean-Christophe Collet\fP, \fBKevin Darcy\fP, \fBMatt Day\fP, \fBTimo Hakulinen\fP, \fBSteve Linhart\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Raymond\fP, and \fBEric Smith\fP undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced NetHack 3.1. .pg \fBKen Lorber\fP, \fBGregg Wonderly\fP and \fBGreg Olson\fP, with help from \fBRichard Addison\fP, \fBMike Passaretti\fP, and \fBOlaf Seibert\fP, developed NetHack 3.1 for the Amiga. .pg \fBNorm Meluch\fP and \fBKevin Smolkowski\fP, with help from \fBCarl Schelin\fP, \fBStephen Spackman\fP, \fBSteve VanDevender\fP, and \fBPaul Winner\fP, ported NetHack 3.1 to the PC. .pg \fBJon W{tte\fP and \fBHao-yang Wang\fP, with help from \fBRoss Brown\fP, \fBMike Engber\fP, \fBDavid Hairston\fP, \fBMichael Hamel\fP, \fBJonathan Handler\fP, \fBJohnny Lee\fP, \fBTim Lennan\fP, \fBRob Menke\fP, and \fBAndy Swanson\fP, developed NetHack 3.1 for the Macintosh, porting it for MPW. Building on their development, \fBBarton House\fP added a Think C port. .pg \fBTimo Hakulinen\fP ported NetHack 3.1 to OS/2. \fBEric Smith\fP ported NetHack 3.1 to the Atari. \fBPat Rankin\fP, with help from \fBJoshua Delahunty\fP, was responsible for the VMS version of NetHack 3.1. \fBMichael Allison\fP ported NetHack 3.1 to Windows NT. .pg \fBDean Luick\fP, with help from \fBDavid Cohrs\fP, developed NetHack 3.1 for X11. \fBWarwick Allison\fP wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. .pg The 3.2 development team, comprised of \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBSteve Creps\fP, \fBKevin Darcy\fP, \fBTimo Hakulinen\fP, \fBSteve Linhart\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Smith\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP, released version 3.2 in April of 1996. .pg Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team remained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, \fBDr. Izchak Miller\fP, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. .pg During the lifespan of NetHack 3.1 and 3.2, several enthusiasts of the game added their own modifications to the game and made these ``variants'' publicly available: .pg \fBTom Proudfoot\fP and \fBYuval Oren\fP created NetHack++, which was quickly renamed NetHack--. Working independently, \fBStephen White\fP wrote NetHack Plus. \fBTom Proudfoot\fP later merged NetHack Plus and his own NetHack-- to produce SLASH. \fBLarry Stewart-Zerba\fP and \fBWarwick Allison\fP improved the spell casting system with the Wizard Patch. \fBWarwick Allison\fP also ported NetHack to use the Qt interface. .pg \fBWarren Cheung\fP combined SLASH with the Wizard Patch to produce Slash'em, and with the help of \fBKevin Hugo\fP, added more features. Kevin later joined the DevTeam and incorporated the best of these ideas in NetHack 3.3. .pg The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. .pg The 3.3 development team, consisting of \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBSteve Creps\fP, \fBKevin Darcy\fP, \fBTimo Hakulinen\fP, \fBKevin Hugo\fP, \fBSteve Linhart\fP, \fBKen Lorber\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Smith\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. .pg Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in preference to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. .pg The 3.4 development team initially consisted of \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBKevin Hugo\fP, \fBKen Lorber\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP, with \fB Warwick Allison\fP joining just before the release of NetHack 3.4.0 in March 2002. .pg As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that NetHack runs on: .pg \fBPat Rankin\fP maintained 3.4 for VMS. .pg \fBMichael Allison\fP maintained NetHack 3.4 for the MS-DOS platform. \fBPaul Winner\fP and \fBYitzhak Sapir\fP provided encouragement. .pg \fBDean Luick\fP, \fBMark Modrall\fP, and \fBKevin Hugo\fP maintained and enhanced the Macintosh port of 3.4. .pg \fBMichael Allison\fP, \fBDavid Cohrs\fP, \fBAlex Kompel\fP, \fBDion Nicolaas\fP, and \fBYitzhak Sapir\fP maintained and enhanced 3.4 for the Microsoft Windows platform. \fBAlex Kompel\fP contributed a new graphical interface for the Windows port. \fBAlex Kompel\fP also contributed a Windows CE port for 3.4.1. .pg \fBRon Van Iwaarden\fP was the sole maintainer of NetHack for OS/2 the past several releases. Unfortunately Ron's last OS/2 machine stopped working in early 2006. A great many thanks to Ron for keeping NetHack alive on OS/2 all these years. .pg \fBJanne Salmijarvi\fP and \fBTeemu Suikki\fP maintained and enhanced the Amiga port of 3.4 after \fBJanne Salmijarvi\fP resurrected it for 3.3.1. .pg \fBChristian ``Marvin'' Bressler\fP maintained 3.4 for the Atari after he resurrected it for 3.3.1. .pg The release of NetHack 3.4.3 in December 2003 marked the beginning of a long release hiatus. 3.4.3 proved to be a remarkably stable version that provided continued enjoyment by the community for more than a decade. The devteam slowly and quietly continued to work on the game behind the scenes during the tenure of 3.4.3. It was during that same period that several new variants emerged within the NetHack community. Notably sporkhack by \fBDerek S. Ray\fP, unnethack by \fBPatric Mueller\fP, nitrohack and its successors originally by \fBDaniel Thaler\fP and then by \fBAlex Smith\fP, and Dynahack by \fBTung Nguyen\fP. Some of those variants continue to be developed, maintained, and enjoyed by the community to this day. .pg At the beginning of development for what would eventually get released as 3.6.0, the development team consisted of \fBWarwick Allison\fP, \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBKen Lorber\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP. Leading up to the release of 3.6.0 in early 2015, new members \fBSean Hunt\fP, \fBPasi Kallinen\fP, and \fBDerek S. Ray\fP joined the NetHack development team. .pg In September 2014, an interim snapshot of the code under development was released publicly by other parties. Since that code was a work-in-progress and had not gone through the process of debugging it as a suitable release, it was decided that the version numbers present on that code snapshot would be retired and never used in an official NetHack release. An announcement was posted on the devteam's official nethack.org website to that effect, stating that there would never be a 3.4.4, 3.5, or 3.5.0 official release version. .pg In November 2014, preparation began for the release of NetHack 3.6. The 3.6 version merges work done by the development team since the previous release with some of the beloved community patches. Many bugs were fixed and a large amount of code was restructured. .pg \fBThe development team, as well as \fBSteve VanDevender\fP and \fBKevin Smolkowski\fP ensured that NetHack 3.6.0 continued to operate on various Unix flavors and maintained the X11 interface. .pg \fBKen Lorber\fP, \fBHaoyang Wang\fP, \fBPat Rankin\fP, and \fBDean Luick\fP maintained the port of NetHack 3.6.0 for Mac. .pg \fBMichael Allison\fP, \fBDerek S. Ray\fP, \fBYitzhak Sapir\fP, \fBAlex Kompel\fP, and \fBDion Nicolaas\fP maintained the port of NetHack 3.6.0 for Microsoft Windows. .pg The official NetHack web site is maintained by \fBKen Lorber\fP at http://www.nethack.org/. .pg SHOUT-OUTS .pg The devteam would like to give a special "shout-out" to thank the generous people primarily responsible for the public NetHack servers available for playing the game at nethack.alt.org and devnull.net. In addition to providing a way for the public to play a game of NetHack from almost anywhere, they have hosted annual NetHack tournaments for many, many years. .pg On behalf of the NetHack community, thank you very much to \fBM. Drew Streib\fP, \fBPasi Kallinen\fP and \fBRobin Bandy\fP. .pg - - - - - - - - - - .pg From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: .TS S center; c c c. .\"TABLE_START Adam Aronow Janet Walz Nathan Eady Alex Kompel Janne Salmijarvi Norm Meluch Andreas Dorn Jean-Christophe Collet Olaf Seibert Andy Church Jeff Bailey Pasi Kallinen Andy Swanson Jochen Erwied Pat Rankin Ari Huttunen John Kallen Paul Winner Barton House John Rupley Pierre Martineau Benson I. Margulies John S. Bien Ralf Brown Bill Dyer Johnny Lee Ray Chason Boudewijn Waijers Jon W{tte Richard Addison Bruce Cox Jonathan Handler Richard Beigel Bruce Holloway Joshua Delahunty Richard P. Hughey Bruce Mewborne Keizo Yamamoto Rob Menke Carl Schelin Ken Arnold Robin Bandy Chris Russo Ken Arromdee Robin Johnson David Cohrs Ken Lorber Roderick Schertler David Damerell Ken Washikita Roland McGrath David Gentzel Kevin Darcy Ron Van Iwaarden David Hairston Kevin Hugo Ronnen Miller Dean Luick Kevin Sitze Ross Brown Del Lamb Kevin Smolkowski Sascha Wostmann Derek S. Ray Kevin Sweet Scott Bigham Deron Meranda Lars Huttar Scott R. Turner Dion Nicolaas Leon Arnott Sean Hunt Dylan O'Donnell M. Drew Streib Stephen Spackman Eric Backus Malcolm Ryan Stefan Thielscher Eric Hendrickson Mark Gooderum Stephen White Eric R. Smith Mark Modrall Steve Creps Eric S. Raymond Marvin Bressler Steve Linhart Erik Andersen Matthew Day Steve VanDevender Frederick Roeber Merlyn LeRoy Teemu Suikki Gil Neiger Michael Allison Tim Lennan Greg Laskin Michael Feir Timo Hakulinen Greg Olson Michael Hamel Tom Almy Gregg Wonderly Michael Sokolov Tom West Hao-yang Wang Mike Engber Warren Cheung Helge Hafting Mike Gallop Warwick Allison Irina Rempt-Drijfhout Mike Passaretti Yitzhak Sapir Izchak Miller Mike Stephenson J. Ali Harlow Mikko Juola .\"TABLE_END Do not delete this line. .TE .\"Microsoft and MS-DOS are registered trademarks of Microsoft Corporation. .\"Lattice is a trademark of Lattice, Inc. .\"Atari and 1040ST are trademarks of Atari, Inc. .\"AMIGA is a trademark of Commodore-Amiga, Inc. .sm "Brand and product names are trademarks or registered trademarks \ of their respective holders." nethack-3.6.0/doc/Guidebook.tex0000664000076400007660000050237112631206535015347 0ustar paxedpaxed\documentstyle[titlepage,longtable]{article} % NetHack 3.6 Guidebook.tex $NHDT-Date: 1431192762 2015/05/09 17:32:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.60 $ */ %+% we're still limping along in LaTeX 2.09 compatibility mode %-%\documentclass{article} %-%\usepackage{hyperref} % before longtable %-%% if hyperref isn't available, we can get by with this instead %-%%\RequirePackage[errorshow]{tracefnt} \DeclareSymbolFont{typewriter}{OT1}{cmtt}{m}{n} %-%\usepackage{longtable} \textheight 220mm \textwidth 160mm \oddsidemargin 0mm \evensidemargin 0mm \topmargin 0mm \newcommand{\nd}{\noindent} \newcommand{\tb}[1]{\tt #1 \hfill} \newcommand{\bb}[1]{\bf #1 \hfill} \newcommand{\ib}[1]{\it #1 \hfill} \newcommand{\blist}[1] {\begin{list}{$\bullet$} {\leftmargin 30mm \topsep 2mm \partopsep 0mm \parsep 0mm \itemsep 1mm \labelwidth 28mm \labelsep 2mm #1}} \newcommand{\elist}{\end{list}} % this will make \tt underscores look better, but requires that % math subscripts will never be used in this document \catcode`\_=12 \begin{document} % % input file: guidebook.mn % %.ds h0 " %.ds h1 %.ds h2 \% %.ds f0 " %.mt \title{\LARGE A Guide to the Mazes of Menace:\\ \Large Guidebook for {\it NetHack\/}} %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.6 by Mike Stephenson and others)} \date{December 7, 2015} \maketitle %.hn 1 \section{Preface - Version 3.6} %.pg This version of the game is special in a particular way. Near the end of the development of 3.6, one of the significant inspirations for many of the humorous and fun features found in the game, author {\it Terry Pratchett}, passed away. We have dedicated this version of the game in his memory. %.pg %.hn 1 \section{Introduction} %.pg Recently, you have begun to find yourself unfulfilled and distant in your daily occupation. Strange dreams of prospecting, stealing, crusading, and combat have haunted you in your sleep for many months, but you aren't sure of the reason. You wonder whether you have in fact been having those dreams all your life, and somehow managed to forget about them until now. Some nights you awaken suddenly and cry out, terrified at the vivid recollection of the strange and powerful creatures that seem to be lurking behind every corner of the dungeon in your dream. Could these details haunting your dreams be real? As each night passes, you feel the desire to enter the mysterious caverns near the ruins grow stronger. Each morning, however, you quickly put the idea out of your head as you recall the tales of those who entered the caverns before you and did not return. Eventually you can resist the yearning to seek out the fantastic place in your dreams no longer. After all, when other adventurers came back this way after spending time in the caverns, they usually seemed better off than when they passed through the first time. And who was to say that all of those who did not return had not just kept going? %.pg Asking around, you hear about a bauble, called the Amulet of Yendor by some, which, if you can find it, will bring you great wealth. One legend you were told even mentioned that the one who finds the amulet will be granted immortality by the gods. The amulet is rumored to be somewhere beyond the Valley of Gehennom, deep within the Mazes of Menace. Upon hearing the legends, you immediately realize that there is some profound and undiscovered reason that you are to descend into the caverns and seek out that amulet of which they spoke. Even if the rumors of the amulet's powers are untrue, you decide that you should at least be able to sell the tales of your adventures to the local minstrels for a tidy sum, especially if you encounter any of the terrifying and magical creatures of your dreams along the way. You spend one last night fortifying yourself at the local inn, becoming more and more depressed as you watch the odds of your success being posted on the inn's walls getting lower and lower. %.pg \nd In the morning you awake, collect your belongings, and set off for the dungeon. After several days of uneventful travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morning, you gather your gear, eat what may be your last meal outside, and enter the dungeon\ldots %.hn 1 \section{What is going on here?} %.pg You have just begun a game of {\it NetHack}. Your goal is to grab as much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. %.pg Your abilities and strengths for dealing with the hazards of adventure will vary with your background and training: %.pg % \blist{} \item[\bb{Archeologists}]% understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start equipped with the tools for a proper scientific expedition. %.pg % \item[\bb{Barbarians}]% are warriors out of the hinterland, hardened to battle. They begin their quests with naught but uncommon strength, a trusty hauberk, and a great two-handed sword. %.pg % \item[\bb{Cavemen {\rm and} Cavewomen}] start with exceptional strength, but unfortunately, neolithic weapons. %.pg % \item[\bb{Healers}]% are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anesthetize, and neutralize poisons; and with their instruments, they can divine a being's state of health or sickness. Their medical practice earns them quite reasonable amounts of money, with which they enter the dungeon. %.pg % \item[\bb{Knights}]% are distinguished from the common skirmisher by their devotion to the ideals of chivalry and by the surpassing excellence of their armor. %.pg % \item[\bb{Monks}]% are ascetics, who by rigorous practice of physical and mental disciplines have become capable of fighting as effectively without weapons as with. They wear no armor but make up for it with increased mobility. %.pg % \item[\bb{Priests {\rm and} Priestesses}]% are clerics militant, crusaders advancing the cause of righteousness with arms, armor, and arts thaumaturgic. Their ability to commune with deities via prayer occasionally extricates them from peril, but can also put them in it. %.pg % \item[\bb{Rangers}]% are most at home in the woods, and some say slightly out of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. %.pg % \item[\bb{Rogues}]% are agile and stealthy thieves, with knowledge of locks, traps, and poisons. Their advantage lies in surprise, which they employ to great advantage. %.pg % \item[\bb{Samurai}]% are the elite warriors of feudal Nippon. They are lightly armored and quick, and wear the % {\it dai-sho}, two swords of the deadliest keenness. %.pg % \item[\bb{Tourists}]% start out with lots of gold (suitable for shopping with), a credit card, lots of food, some maps, and an expensive camera. Most monsters don't like being photographed. %.pg % \item[\bb{Valkyries}]% are hardy warrior women. Their upbringing in the harsh Northlands makes them strong, inures them to extremes of cold, and instills in them stealth and cunning. %.pg % \item[\bb{Wizards}]% start out with a knowledge of magic, a selection of magical items, and a particular affinity for dweomercraft. Although seemingly weak and easy to overcome at first sight, an experienced Wizard is a deadly foe. \elist %.pg You may also choose the race of your character: %.pg % \blist{} \item[\bb{Dwarves}]% are smaller than humans or elves, but are stocky and solid individuals. Dwarves' most notable trait is their great expertise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. %.pg % \item[\bb{Elves}]% are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. %.pg % \item[\bb{Gnomes}]% are smaller than but generally similar to dwarves. Gnomes are known to be expert miners, and it is known that a secret underground mine complex built by this race exists within the Mazes of Menace, filled with both riches and danger. %.pg % \item[\bb{Humans}]% are by far the most common race of the surface world, and are thus the norm to which other races are often compared. Although they have no special abilities, they can succeed in any role. %.pg % \item[\bb{Orcs}]% are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves with a passion unequalled, and will go out of their way to kill one at any opportunity. The armor and weapons fashioned by the Orcs are typically of inferior quality. \elist %.hn 1 \section{What do all those things on the screen mean?} %.pg On the screen is kept a map of where you have been and what you have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. %.pg When {\it NetHack\/}'s ancestor {\it rogue\/} first appeared, its screen orientation was almost unique among computer fantasy games. Since then, screen orientation has become the norm rather than the exception; {\it NetHack\/} continues this fine tradition. Unlike text adventure games that accept commands in pseudo-English sentences and explain the results in words, {\it NetHack\/} commands are all one or two keystrokes and the results are displayed graphically on the screen. A minimum screen size of 24 lines by 80 columns is recommended; if the screen is larger, only a $21\times80$ section will be used for the map. %.pg {\it NetHack\/} can even be played by blind players, with the assistance of Braille readers or speech synthesisers. Instructions for configuring {\it NetHack\/} for the blind are included later in this document. %.pg {\it NetHack\/} generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game despite having won several times. %.pg {\it NetHack\/} offers a variety of display options. The options available to you will vary from port to port, depending on the capabilities of your hardware and software, and whether various compile-time options were enabled when your executable was created. The three possible display options are: a monochrome character interface, a color character interface, and a graphical interface using small pictures called tiles. The two character interfaces allow fonts with other characters to be substituted, but the default assignments use standard ASCII characters to represent everything. There is no difference between the various display options with respect to game play. Because we cannot reproduce the tiles or colors in the Guidebook, and because it is common to all ports, we will use the default ASCII characters from the monochrome character display when referring to things you might see on the screen during your game. %.pg In order to understand what is going on in {\it NetHack}, first you must understand what {\it NetHack\/} is doing with the screen. The {\it NetHack\/} screen replaces the ``You see \ldots'' descriptions of text adventure games. Figure 1 is a sample of what a {\it NetHack\/} screen might look like. The way the screen looks for you depends on your platform. \vbox{ \begin{verbatim} The bat bites! ------ |....| ---------- |.<..|####...@...$.| |....-# |...B....+ |....| |.d......| ------ -------|-- Player the Rambler St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15 Neutral Dlvl:1 $:0 HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak \end{verbatim} \begin{center} Figure 1 \end{center} } %.hn 2 \subsection*{The status lines (bottom)} %.pg The bottom two lines of the screen contain several cryptic pieces of information describing your current status. If either status line becomes longer than the width of the screen, you might not see all of it. Here are explanations of what the various status items mean (though your configuration may not have all the status items listed below): %.lp \blist{} \item[\bb{Rank}] Your character's name and professional ranking (based on the experience level, see below). %.lp \item[\bb{Strength}] A measure of your character's strength; one of your six basic attributes. A human character's attributes can range from 3 to 18 inclusive; non-humans may exceed these limits (occasionally you may get super-strengths of the form 18/xx, and magic can also cause attributes to exceed the normal limits). The higher your strength, the stronger you are. Strength affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. %.lp \item[\bb{Dexterity}] Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. %.lp \item[\bb{Constitution}] Constitution affects your ability to recover from injuries and other strains on your stamina. %.lp \item[\bb{Intelligence}] Intelligence affects your ability to cast spells and read spellbooks. %.lp \item[\bb{Wisdom}] Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. %.lp \item[\bb{Charisma}] Charisma affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you. %.lp \item[\bb{Alignment}] % {\it Lawful}, {\it Neutral\/} or {\it Chaotic}. Often, Lawful is taken as good and Chaotic is evil, but legal and ethical do not always coincide. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive, while those of an opposing alignment are more likely to be seriously offended at your presence. %.lp \item[\bb{Dungeon Level}] How deep you are in the dungeon. You start at level one and the number increases as you go deeper into the dungeon. Some levels are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be somewhere beneath the twentieth level. %.lp \item[\bb{Gold}] The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. %.lp \item[\bb{Hit Points}] Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in a fight, the lower they get. You can regain hit points by resting, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. %.lp \item[\bb{Power}] Spell points. This tells you how much mystic energy ({\it mana\/}) you have available for spell casting. Again, resting will regenerate the amount available. %.lp \item[\bb{Armor Class}] A measure of how effectively your armor stops blows from unfriendly creatures. The lower this number is, the more effective the armor; it is quite possible to have negative armor class. %.lp \item[\bb{Experience}] Your current experience level and experience points. As you adventure, you gain experience points. At certain experience point totals, you gain an experience level. The more experienced you are, the better you fight and withstand magical attacks. Many dungeons show only your experience level here. %.lp \item[\bb{Time}] The number of turns elapsed so far, displayed if you have the {\it time\/} option set. %.lp \item[\bb{Hunger Status}] Your current hunger status, ranging from % {\it Satiated\/} down to {\it Fainting}. If your hunger status is normal, it is not displayed. %.pg Additional status flags may appear after the hunger status: {\it Conf\/} when you're confused, {\it FoodPois\/} or {\it Ill\/} when sick, {\it Blind\/} when you can't see, {\it Stun\/} when stunned, and {\it Hallu\/} when hallucinating. \elist %.hn 2 \subsection*{The message line (top)} %.pg The top line of the screen is reserved for messages that describe things that are impossible to represent visually. If you see a ``{\tt --More--}'' on the top line, this means that {\it NetHack\/} has another message to display on the screen, but it wants to make certain that you've read the one that is there first. To read the next message, just press the space bar. %.pg To change how and what messages are shown on the message line, see ``{\it Configuring Message Types\/}`` and the {\it verbose\/} option. %.hn 2 \subsection*{The map (rest of the screen)} %.pg The rest of the screen is the map of the level as you have explored it so far. Each symbol on the screen represents something. You can set various graphics options to change some of the symbols the game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: \blist{} %.lp \item[\tb{- {\rm and} |}] The walls of a room, or an open door. Or a grave ({\tt |}). %.lp \item[\tb{.}] The floor of a room, ice, or a doorless doorway. %.lp \item[\tb{\#}] A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. %.lp \item[\tb{>}] Stairs down: a way to the next level. %.lp \item[\tb{<}] Stairs up: a way to the previous level. %.lp \item[\tb{+}] A closed door, or a spellbook containing a spell you may be able to learn. %.lp \item[\tb{@}] Your character or a human. %.lp \item[\tb{\$}] A pile of gold. %.lp \item[\tb{\^}] A trap (once you have detected it). %.lp \item[\tb{)}] A weapon. %.lp \item[\tb{[}] A suit or piece of armor. %.lp \item[\tb{\%}] Something edible (not necessarily healthy). %.lp \item[\tb{?}] A scroll. %.lp \item[\tb{/}] A wand. %.lp \item[\tb{=}] A ring. %.lp \item[\tb{!}] A potion. %.lp \item[\tb{(}] A useful item (pick-axe, key, lamp \ldots). %.lp \item[\tb{"}] An amulet or a spider web. %.lp \item[\tb{*}] A gem or rock (possibly valuable, possibly worthless). %.lp \item[\tb{\`}] A boulder or statue. %.lp \item[\tb{0}] An iron ball. %.lp \item[\tb{_}] An altar, or an iron chain. %.lp \item[\tb{\{}] A fountain. %.lp \item[\tb{\}}] A pool of water or moat or a pool of lava. %.lp \item[\tb{$\backslash$}] An opulent throne. %.lp \item[\tb{a-zA-Z {\rm \& other symbols}}] Letters and certain other symbols represent the various inhabitants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. %.lp \item[\tb{I}] This marks the last known location of an invisible or otherwise unseen monster. Note that the monster could have moved. The `F' and `m' commands may be useful here. \elist %.pg You need not memorize all these symbols; you can ask the game what any symbol represents with the `{\tt /}' command (see the next section for more info). %.hn 1 \section{Commands} %.pg Commands are initiated by typing one or two characters. Some commands, like ``{\tt search}'', do not require that any more information be collected by {\it NetHack\/}. Other commands might require additional information, for example a direction, or an object to be used. For those commands that require additional information, {\it NetHack\/} will present you with either a menu of choices, or with a command line prompt requesting information. Which you are presented with will depend chiefly on how you have set the `{\it menustyle\/}' option. %.pg For example, a common question in the form ``{\tt What do you want to use? [a-zA-Z\ ?*]}'', asks you to choose an object you are carrying. Here, ``{\tt a-zA-Z}'' are the inventory letters of your possible choices. Typing `{\tt ?}' gives you an inventory list of these items, so you can see what each letter refers to. In this example, there is also a `{\tt *}' indicating that you may choose an object not on the list, if you wanted to use something unexpected. Typing a `{\tt *}' lists your entire inventory, so you can see the inventory letters of every object you're carrying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the `ESC' key to abort the command. %.pg You can put a number before some commands to repeat them that many times; for example, ``{\tt 10s}'' will search ten times. If you have the {\it number\verb+_+pad\/} option set, you must type `{\tt n}' to prefix a count, so the example above would be typed ``{\tt n10s}'' instead. Commands for which counts make no sense ignore them. In addition, movement commands can be prefixed for greater control (see below). To cancel a count or a prefix, press the `ESC' key. %.pg The list of commands is rather long, but it can be read at any time during the game through the `{\tt ?}' command, which accesses a menu of helpful texts. Here are the commands for your reference: \blist{} %.lp \item[\tb{?}] Help menu: display one of several help texts available. %.lp \item[\tb{/}] Tell what a symbol represents. You may choose to specify a location or type a symbol (or even a whole word) to explain. Specifying a location is done by moving the cursor to a particular spot on the map and then pressing one of `{\tt .}', `{\tt ,}', `{\tt ;}', or `{\tt :}'. `{\tt .}' will explain the symbol at the chosen location, conditionally check for ``{\tt More info?}'' depending upon whether the {\it help\/} option is on, and then you will be asked to pick another location; `{\tt ,}' will explain the symbol but skip any additional information; `{\tt ;}' will skip additional info and also not bother asking you to choose another location to examine; `{\tt :}' will show additional info, if any, without asking for confirmation. When picking a location, pressing the {\tt ESC} key will terminate this command, or pressing `{\tt ?}' will give a brief reminder about how it works. %.pg Specifying a name rather than a location always gives any additional information available about that name. %.lp \item[\tb{\&}] Tell what a command does. %.lp \item[\tb{<}] Go up to the previous level (if you are on a staircase or ladder). %.lp \item[\tb{>}] Go down to the next level (if you are on a staircase or ladder). %.lp \item[\tb{[yuhjklbn]}] Go one step in the direction indicated (see Figure 2). If you sense or remember a monster there, you will fight the monster instead. Only these one-step movement commands cause you to fight monsters; the others (below) are ``safe.'' %.sd \begin{center} \begin{tabular}{cc} \verb+ y k u + & \verb+ 7 8 9 +\\ \verb+ \ | / + & \verb+ \ | / +\\ \verb+ h- . -l + & \verb+ 4- . -6 +\\ \verb+ / | \ + & \verb+ / | \ +\\ \verb+ b j n + & \verb+ 1 2 3 +\\ & (if {\it number\verb+_+pad\/} set) \end{tabular} \end{center} %.ed \begin{center} Figure 2 \end{center} %.lp \item[\tb{[YUHJKLBN]}] Go in that direction until you hit a wall or run into something. %.lp \item[\tb{m[yuhjklbn]}] Prefix: move without picking up objects or fighting (even if you remember a monster there) %.lp \item[\tb{F[yuhjklbn]}] Prefix: fight a monster (even if you only guess one is there) %.lp \item[\tb{M[yuhjklbn]}] Prefix: Move far, no pickup. %.lp \item[\tb{g[yuhjklbn]}] Prefix: Move until something interesting is found. %.lp \item[\tb{G[yuhjklbn] {\rm or} [yuhjklbn]}] Prefix: Same as `{\tt g}', but forking of corridors is not considered interesting. %.lp \item[\tb{_}] Travel to a map location via a shortest-path algorithm.\\ %.lp "" The shortest path is computed over map locations the hero knows about (e.g. seen or previously traversed). If there is no known path, a guess is made instead. Stops on most of the same conditions as the `G' command, but without picking up objects, similar to the `M' command. For ports with mouse support, the command is also invoked when a mouse-click takes place on a location other than the current position. %.lp \item[\tb{.}] Rest, do nothing for one turn. %.lp \item[\tb{a}] Apply (use) a tool (pick-axe, key, lamp \ldots). %.lp \item[\tb{A}] Remove one or more worn items, such as armor.\\ %.lp "" Use `{\tt T}' (take off) to take off only one piece of armor or `{\tt R}' (remove) to take off only one accessory. %.lp \item[\tb{\^{}A}] Redo the previous command. %.lp \item[\tb{c}] Close a door. %.lp \item[\tb{C}] Call (name) a monster, an individual object, or an object type.\\ %.lp "" Same as extended command ``{\tt \#name}''. %.lp \item[\tb{\^{}C}] Panic button. Quit the game. %.lp \item[\tb{d}] Drop something.\\ {\tt d7a} --- drop seven items of object {\it a}. %.lp \item[\tb{D}] Drop several things.\\ %.lp "" In answer to the question\\ ``{\tt What kinds of things do you want to drop? [!\%= BUCXaium]}''\\ you should type zero or more object symbols possibly followed by `{\tt a}' and/or `{\tt i}' and/or `{\tt u}' and/or `{\tt m}'. In addition, one or more of the bless\-ed/\-un\-curs\-ed/\-curs\-ed groups may be typed.\\ %.sd %.si {\tt DB} --- drop all objects known to be blessed.\\ {\tt DU} --- drop all objects known to be uncursed.\\ {\tt DC} --- drop all objects known to be cursed.\\ {\tt DX} --- drop all objects of unknown B/U/C status.\\ {\tt Da} --- drop all objects, without asking for confirmation.\\ {\tt Di} --- examine your inventory before dropping anything.\\ {\tt Du} --- drop only unpaid objects (when in a shop).\\ {\tt Dm} --- use a menu to pick which object(s) to drop.\\ {\tt D\%u} --- drop only unpaid food. %.ei %.ed %.lp \item[\tb{\^{}D}] Kick something (usually a door). %.lp \item[\tb{e}] Eat food. %.lp % Make sure Elbereth is not hyphenated below, the exact spelling matters. % (Only specified here to parallel Guidebook.mn; use of \tt font implicity % prevents automatic hyphenation in TeX and LaTeX.) \hyphenation{Elbereth} %override the deduced syllable breaks \item[\tb{E}] Engrave a message on the floor.\\ %.sd %.si {\tt E-} --- write in the dust with your fingers.\\ %.ei %.ed %.lp "" Engraving the word ``{\tt Elbereth}'' will cause most monsters to not attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. (This feature may be compiled out of the game, so your version might not have it.) %.lp \item[\tb{f}] Fire one of the objects placed in your quiver (or quiver sack, or that you have at the ready). You may select ammunition with a previous `{\tt Q}' command, or let the computer pick something appropriate if {\it autoquiver\/} is true. %.lp \item[\tb{i}] List your inventory (everything you're carrying). %.lp \item[\tb{I}] List selected parts of your inventory, usually be specifying the character for a particular set of objects, like `{\tt [}' for armor or `{\tt !}' for potions.\\ %.sd %.si {\tt I*} --- list all gems in inventory;\\ {\tt Iu} --- list all unpaid items;\\ {\tt Ix} --- list all used up items that are on your shopping bill;\\ {\tt IB} --- list all items known to be blessed;\\ {\tt IU} --- list all items known to be uncursed;\\ {\tt IC} --- list all items known to be cursed;\\ {\tt IX} --- list all items whose bless/curse status is unknown;\\ {\tt I\$} --- count your money. %.ei %.ed %.lp \item[\tb{o}] Open a door. %.lp \item[\tb{O}] Set options.\\ %.lp "" A menu showing the current option values will be displayed. You can change most values simply by selecting the menu entry for the given option (ie, by typing its letter or clicking upon it, depending on your user interface). For the non-boolean choices, a further menu or prompt will appear once you've closed this menu. The available options are listed later in this Guidebook. Options are usually set before the game rather than with the `{\tt O}' command; see the section on options below. %.lp \item[\tb{p}] Pay your shopping bill. %.lp \item[\tb{P}] Put on an accessory (ring, amulet, blindfold).\\ %.lp "" This command may also be used to wear armor. The prompt for which inventory item to use will only list accessories, but choosing an unlisted item of armor will attempt to wear it. (See the `{\tt W}' command below. It lists armor as the inventory choices but will accept an accessory and attempt to put that on.) %.lp \item[\tb{\^{}P}] Repeat previous message.\\ %.lp "" Subsequent {\tt \^{}P}'s repeat earlier messages. The behavior can be varied via the {\it msg\verb+_+window} option. %.lp \item[\tb{q}] Quaff (drink) something (potion, water, etc). %.lp \item[\tb{Q}] Select an object for your quiver, quiver sack, or just generally at the ready (only one of these is available at a time). You can then throw this (or one of these) using the `f' command.\\ %.lp "" (In versions prior to 3.3 this was the command to quit the game, which has been moved to ``{\tt \#quit}''.) %.lp \item[\tb{r}] Read a scroll or spellbook. %.lp \item[\tb{R}] Remove a worn accessory (ring, amulet, or blindfold).\\ %.lp "" If you're wearing more than one, you'll be prompted for which one to remove. When you're only wearing one, then by default it will be removed without asking, but you can set the {\it paranoid\verb+_+confirmation\/} option to require a prompt.\\ %.lp "" This command may also be used to take off armor. The prompt for which inventory item to remove only lists worn accessories, but an item of worn armor can be chosen. (See the `{\tt T}' command below. It lists armor as the inventory choices but will accept an accessory and attempt to remove it.) %.lp \item[\tb{\^{}R}] Redraw the screen. %.lp \item[\tb{s}] Search for secret doors and traps around you. It usually takes several tries to find something. %.lp \item[\tb{S}] Save (and suspend) the game. The game will be restored automatically the next time you play. %.lp \item[\tb{t}] Throw an object or shoot a projectile. %.lp \item[\tb{T}] Take off armor.\\ %.lp "" If you're wearing more than one piece, you'll be prompted for which one to take off. (Note that this treats a cloak covering a suit and/or a shirt, or a suit covering a shirt, as if the underlying items weren't there.) When you're only wearing one, then by default it will be taken off without asking, but you can set the {\it paranoid\verb+_+confirmation\/} option to require a prompt.\\ %.lp "" This command may also be used to remove accessories. The prompt for which inventory item to take off only lists worn armor, but a worn accessory can be chosen. (See the `{\tt R}' command above. It lists accessories as the inventory choices but will accept an item of armor and attempt to take it off.) %.lp \item[\tb{\^{}T}] Teleport, if you have the ability. %.lp \item[\tb{v}] Display version number. %.lp \item[\tb{V}] Display the game history. %.lp \item[\tb{w}] Wield weapon.\\ %.sd %.si {\tt w-} --- wield nothing, use your bare hands.\\ %.ei %.ed Some characters can wield two weapons at once; use the `{\tt X}' command (or the ``{\tt \#twoweapon}'' extended command) to do so. %.lp \item[\tb{W}] Wear armor.\\ %.lp "" This command may also be used to put on an accessory (ring, amulet, or blindfold). The prompt for which inventory item to use will only list armor, but choosing an unlisted accessory will attempt to put it on. (See the `{\tt P}' command above. It lists accessories as the inventory choices but will accept an item of armor and attempt to wear it.) %.lp \item[\tb{x}] Exchange your wielded weapon with the item in your alternate weapon slot.\\ %.lp "" The latter is used as your secondary weapon when engaging in two-weapon combat. Note that if one of these slots is empty, the exchange still takes place. %.lp \item[\tb{X}] Toggle two-weapon combat, if your character can do it. Also available via the ``{\tt \#twoweapon}'' extended command.\\ +.lp "" +(In versions prior to 3.6 this was the command to switch from normal +play to ``explore mode'', also known as ``discovery mode'', which has now +been moved to ``{\tt \#explore}''.) %.lp \item[\tb{\^{}X}] Display basic information about your character.\\ %.lp "" Displays name, role, race, gender (unless role name makes that redundant, such as {\tt Caveman} or {\tt Priestess}), and alignment, along with your patron deity and his or her opposition. It also shows most of the various items of information from the status line(s) in a less terse form, including several additional things which don't appear in the normal status display due to space considerations. %.lp \item[\tb{z}] Zap a wand.\\ %.sd %.si {\tt z.} --- to aim at yourself, use `{\tt .}' for the direction. %.ei %.ed %.lp \item[\tb{Z}] Zap (cast) a spell.\\ %.sd %.si {\tt Z.} --- to aim at yourself, use `{\tt .}' for the direction. %.ei %.ed %.lp \item[\tb{\^{}Z}] Suspend the game (UNIX versions with job control only). %.lp \item[\tb{:}] Look at what is here. %.lp \item[\tb{;}] Show what type of thing a visible symbol corresponds to. %.lp \item[\tb{,}] Pick up some things.\\ %.lp "" May be preceded by `{\tt m}' to force a selection menu. %.lp \item[\tb{@}] Toggle the {\it autopickup\/} option on and off. %.lp \item[\tb{\^{}}] Ask for the type of a trap you found earlier. %.lp \item[\tb{)}] Tell what weapon you are wielding. %.lp \item[\tb{[}] Tell what armor you are wearing. %.lp \item[\tb{=}] Tell what rings you are wearing. %.lp \item[\tb{"}] Tell what amulet you are wearing. %.lp \item[\tb{(}] Tell what tools you are using. %.lp \item[\tb{*}] Tell what equipment you are using.\\ %.lp "" Combines the preceding five type-specific commands into one. %.lp \item[\tb{\$}] Count your gold pieces. %.lp \item[\tb{+}] List the spells you know.\\ %.lp "" Using this command, you can also rearrange the order in which your spells are listed, either by sorting the entire list or by picking one spell from the menu then picking another to swap places with it. Swapping pairs of spells changes their casting letters, so the change lasts after the current `{\tt +}' command finishes. Sorting the whole list is temporary. To make the most recent sort order persist beyond the current `{\tt +}' command, choose the sort option again and then pick ``reassign casting letters''. (Any spells learned after that will be added to the end of the list rather than be inserted into the sorted ordering.) %.lp \item[\tb{$\backslash$}] Show what types of objects have been discovered. %.lp \item[\tb{\`}] Show discovered types for one class of objects. %.lp \item[\tb{!}] Escape to a shell. %.lp \item[\tb{\#}] Perform an extended command.\\ %.lp "" As you can see, the authors of {\it NetHack\/} used up all the letters, so this is a way to introduce the less frequently used commands. What extended commands are available depends on what features the game was compiled with. %.lp \item[\tb{\#adjust}] Adjust inventory letters (most useful when the {\it fixinv\/} option is ``on'').\\ %.lp "" This command allows you to move an item from one particular inventory slot to another so that it has a letter which is more meaningful for you or that it will appear in a particular location when inventory listings are displayed. ``{\tt \#adjust}'' can also be used to split a stack of objects; when choosing the item to adjust, enter a count prior to its letter. %.lp \item[\tb{\#annotate}] Allows you to specify one line of text to associate with the current dungeon level. All levels with annotations are displayed by the ``{\tt \#overview}'' command. %.lp \item[\tb{\#chat}] Talk to someone. %.lp \item[\tb{\#conduct}] List voluntary challenges you have maintained.\\ %.lp "" See the section below entitled ``Conduct'' for details. %.lp \item[\tb{\#dip}] Dip an object into something. %.lp \item[\tb{\#enhance}] Advance or check weapon and spell skills. %.lp \item[\tb{\#force}] Force a lock. %.lp \item[\tb{\#invoke}] Invoke an object's special powers. %.lp \item[\tb{\#jump}] Jump to another location. %.lp \item[\tb{\#loot}] Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. %.lp \item[\tb{\#monster}] Use a monster's special ability (when polymorphed into monster form). %.lp \item[\tb{\#name}] Name a monster, an individual object, or a type of object. Same as `{\tt C}'. %.lp \item[\tb{\#offer}] Offer a sacrifice to the gods.\\ %.lp "" You'll need to find an altar to have any chance at success. Corpses of recently killed monsters are the fodder of choice. %.lp \item[\tb{\#overview}] Display information you've discovered about the dungeon. Any visited level (unless forgotten due to amnesia) with an annotation is included, and many things (altars, thrones, fountains, and so on; extra stairs leading to another dungeon branch) trigger an automatic annotation. If dungeon overview is chosen during end-of-game disclosure, every visited level will be included regardless of annotations. %.lp \item[\tb{\#pray}] Pray to the gods for help.\\ %.lp "" Praying too soon after receiving prior help is a bad idea. (Hint: entering the dungeon alive is treated as having received help. You probably shouldn't start off a new game by praying right away.) Since using this command by accident can cause trouble, there is an option to make you confirm your intent before praying. It is enabled by default, and you can reset the {\it paranoid\verb+_+confirmation\/} option to disable it. %.lp \item[\tb{\#quit}] Quit the program without saving your game.\\ %.lp "" Since using this command by accident would throw away the current game, you are asked to confirm your intent before quitting. By default a response of `{\tt y}' acknowledges that intent. You can set the {\it paranoid\verb+_+confirmation\/} option to require a response of ``{\tt yes}'' instead. %.lp \item[\tb{\#ride}] Ride (or stop riding) a saddled creature. %.lp \item[\tb{\#rub}] Rub a lamp or a stone. %.lp \item[\tb{\#sit}] Sit down. %.lp \item[\tb{\#terrain}] Show bare map without displaying monsters, objects, or traps. \item[\tb{\#tip}] Tip over a container (bag or box) to pour out its contents. %.lp \item[\tb{\#turn}] Turn undead. %.lp \item[\tb{\#twoweapon}] Toggle two-weapon combat on or off.\\ %.lp "" Note that you must use suitable weapons for this type of combat, or it will be automatically turned off. %.lp \item[\tb{\#untrap}] Untrap something (trap, door, or chest).\\ %.lp "" In some circumstancs it can also be used to rescue trapped monsters. %.lp \item[\tb{\#version}] Print compile time options for this version of {\it NetHack}. %.lp \item[\tb{\#wipe}] Wipe off your face. %.lp \item[\tb{\#?}] Help menu: get the list of available extended commands. \elist %.pg \nd If your keyboard has a meta key (which, when pressed in combination with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. In {\it NT, OS/2, PC\/ {\rm and} ST NetHack}, the `Alt' key can be used in this fashion; on the {\it Amiga\/}, set the {\it altmeta\/} option to get this behavior. On other systems, if typing `Alt' plus another key transmits a two character sequence consisting of an {\tt Escape} followed by the other key, you may set the {\it altmeta\/} option to have nethack combine them into meta\+key. \blist{} %.lp \item[\tb{M-?}] {\tt\#?} (not supported by all platforms) %.lp \item[\tb{M-2}] {\tt\#twoweapon} (unless the {\it number\verb+_+pad\/} option is enabled) %.lp \item[\tb{M-a}] {\tt\#adjust} %.lp \item[\tb{M-A}] {\tt\#annotate} %.lp \item[\tb{M-c}] {\tt\#chat} %.lp \item[\tb{M-C}] {\tt\#conduct} %.lp \item[\tb{M-d}] {\tt\#dip} %.lp \item[\tb{M-e}] {\tt\#enhance} %.lp \item[\tb{M-f}] {\tt\#force} %.lp \item[\tb{M-i}] {\tt\#invoke} %.lp \item[\tb{M-j}] {\tt\#jump} %.lp \item[\tb{M-l}] {\tt\#loot} %.lp \item[\tb{M-m}] {\tt\#monster} %.lp \item[\tb{M-n}] {\tt\#name} %.lp \item[\tb{M-o}] {\tt\#offer} %.lp \item[\tb{M-O}] {\tt\#overview} %.lp \item[\tb{M-p}] {\tt\#pray} %.Ip \item[\tb{M-q}] {\tt\#quit} %.lp \item[\tb{M-r}] {\tt\#rub} %.lp \item[\tb{M-R}] {\tt\#ride} %.lp \item[\tb{M-s}] {\tt\#sit} %.lp \item[\tb{M-t}] {\tt\#turn} %.lp \item[\tb{M-T}] {\tt\#tip} %.lp \item[\tb{M-u}] {\tt\#untrap} %.lp \item[\tb{M-v}] {\tt\#version} %.lp \item[\tb{M-w}] {\tt\#wipe} \elist %.pg \nd If the {\it number\verb+_+pad\/} option is on, some additional letter commands are available: \blist{} %.lp \item[\tb{h}] Help menu: display one of several help texts available, like ``{\tt ?}''. %.lp \item[\tb{j}] Jump to another location. Same as ``{\tt \#jump}'' or ``{\tt M-j}''. %.lp \item[\tb{k}] Kick something (usually a door). Same as `{\tt \^{}D}'. %.lp \item[\tb{l}] Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. Same as ``{\tt \#loot}'' or ``{\tt M-l}''. %.lp \item[\tb{N}] Name an object or type of object. Same as ``{\tt \#name}'' or ``{\tt M-n}''. Name a monster, an individual object, or a type of object. Same as ``{\tt \#name}'' (or ``{\tt M-n}'') which is the same as the `{\tt C}' command. %.lp \item[\tb{u}] Untrap a trap, door, or chest. Same as ``{\tt \#untrap}'' or ``{\tt M-u}''. \elist %.hn 1 \section{Rooms and corridors} %.pg Rooms and corridors in the dungeon are either lit or dark. Any lit areas within your line of sight will be displayed; dark areas are only displayed if they are within one space of you. Walls and corridors remain on the map as you explore them. %.pg Secret corridors are hidden. You can find them with the `{\tt s}' (search) command. %.hn 2 \subsection*{Doorways} %.pg Doorways connect rooms and corridors. Some doorways have no doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use the `{\tt o}' (open) command; to close it again, use the `{\tt c}' (close) command. %.pg You can get through a locked door by using a tool to pick the lock with the `{\tt a}' (apply) command, or by kicking it open with the `{\tt \^{}D}' (kick) command. %.pg Open doors cannot be entered diagonally; you must approach them straight on, horizontally or vertically. Doorways without doors are not restricted in this fashion. %.pg Doors can be useful for shutting out monsters. Most monsters cannot open doors, although a few don't need to (ex.\ ghosts can walk through doors). %.pg Secret doors are hidden. You can find them with the `{\tt s}' (search) command. Once found they are in all ways equivalent to normal doors. %.hn 2 \subsection*{Traps (`{\tt \^{}}')} %.pg There are traps throughout the dungeon to snare the unwary delver. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out. Traps don't appear on your map until you see one triggered by moving onto it, see something fall into it, or you discover it with the `{\tt s}' (search) command. Monsters can fall prey to traps, too, which can be a very useful defensive strategy. %.pg There is a special pre-mapped branch of the dungeon based on the classic computer game ``{\tt Sokoban}.'' The goal is to push the boulders into the pits or holes. With careful foresight, it is possible to complete all of the levels according to the traditional rules of Sokoban. Some allowances are permitted in case the player gets stuck; however, they will lower your luck. \subsection*{Stairs (`{\tt <}', `{\tt >}')} %.pg In general, each level in the dungeon will have a staircase going up (`{\tt <}') to the previous level and another going down (`{\tt >}') to the next level. There are some exceptions though. For instance, fairly early in the dungeon you will find a level with two down staircases, one continuing into the dungeon and the other branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so after exploring them (if you choose to do so), you'll need to climb back up to the main dungeon. %.pg When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be deactivated and stored in a file on disk. If you're moving to a previously visited level, it will be loaded from its file on disk and reactivated. If you're moving to a level which has not yet been visited, it will be created (from scratch for most random levels, from a template for some ``special'' levels, or loaded from the remains of an earlier game for a ``bones'' level as briefly described below). Monsters are only active on the current level; those on other levels are essentially placed into stasis. %.pg Ordinarily when you climb a set of stairs, you will arrive on the corresponding staircase at your destination. However, pets (see below) and some other monsters will follow along if they're close enough when you travel up or down stairs, and occasionally one of these creatures will displace you during the climb. When that occurs, the pet or other monster will arrive on the staircase and you will end up nearby. \subsection*{Ladders (`{\tt <}', `{\tt >}')} %.pg Ladders serve the same purpose as staircases, and the two types of inter-level connections are nearly indistinguishable during game play. %.hn 2 \subsection*{Shops and shopping} %.pg Occasionally you will run across a room with a shopkeeper near the door and many items lying on the floor. You can buy items by picking them up and then using the `{\tt p}' command. You can inquire about the price of an item prior to picking it up by using the ``{\tt \#chat}'' command while standing on it. Using an item prior to paying for it will incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. %.pg You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shopkeeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by the shop). %.pg If you drop something in a shop by accident, the shopkeeper will usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. %.pg Shopkeepers sometimes run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you happen to find a ``credit card'' in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) %.pg The {\tt \$} command, which reports the amount of gold you are carrying (in inventory, not inside bags or boxes), will also show current shop debt or credit, if any. The {\tt Iu} command lists unpaid items (those which still belong to the shop) if you are carrying any. The {\tt Ix} command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. %.hn 3 \subsubsection*{Shop idiosyncracies} %.pg Several aspects of shop behavior might be unexpected. \begin{itemize} % note: a bullet is the default item label so we could omit [$\bullet$] here %.lp \(bu 2 \item[$\bullet$] The price of a given item can vary due to a variety of factors. %.lp \(bu 2 \item[$\bullet$] A shopkeeper treats the spot immediately inside the door as if it were outside the shop. %.lp \(bu 2 \item[$\bullet$] While the shopkeeper watches you like a hawk, he will generally ignore any other customers. %.lp \(bu 2 \item[$\bullet$] If a shop is ``closed for inventory'', it will not open of its own accord. %.lp \(bu 2 \item[$\bullet$] Shops do not get restocked with new items, regardless of inventory depletion. \end{itemize} %.hn 1 \section{Monsters} %.pg Monsters you cannot see are not displayed on the screen. Beware! You may suddenly come upon one in a dark place. Some magic items can help you locate them before they locate you (which some monsters can do very well). %.pg The commands `{\tt /}' and `{\tt ;}' may be used to obtain information about those monsters who are displayed on the screen. The command ``{\tt \#name}'', or its synonym `{\tt C}', allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple monsters are present. Assigning a name which is just a space will remove any prior name. %.pg The extended command ``{\tt \#chat}'' can be used to interact with an adjacent monster. There is no actual dialog (in other words, you don't get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. %.hn 2 \subsection*{Fighting} %.pg If you see a monster and you wish to fight it, just attempt to walk into it. Many monsters you find will mind their own business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. %.pg In most circumstances, if you attempt to attack a peaceful monster by moving into its location, you'll be asked to confirm your intent. By default an answer of `{\tt y}' acknowledges that intent, which can be error prone if you're using `{\tt y}' to move. You can set the {\it paranoid\verb+_+confirmation\/} option to require a response of ``{\tt yes}'' instead. %.pg If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a monster that you can see; of course, if the monster has moved, you will attack empty air. If you guess that the monster has moved and you don't wish to fight, you can use the `m' command to move without fighting; likewise, if you don't remember a monster but want to try fighting anyway, you can use the `F' command. %.hn 2 \subsection*{Your pet} %.pg You start the game with a little dog (`{\tt d}'), cat (`{\tt f}'), or pony (`{\tt u}'), which follows you about the dungeon and fights monsters with you. Like you, your pet needs food to survive. It usually feeds itself on fresh carrion and other meats. If you're worried about it or want to train it, you can feed it, too, by throwing it food. A properly trained pet can be very useful under certain circumstances. %.pg Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, your pet may even be better at killing things than you, which makes pets useful for low-level characters. %.pg Your pet will follow you up and down staircases if it is next to you when you move. Otherwise your pet will be stranded and may become wild. Similarly, when you trigger certain types of traps which alter your location (for instance, a trap door which drops you to a lower dungeon level), any adjacent pet will accompany you and any non-adjacent pet will be left behind. Your pet may trigger such traps itself; you will not be carried along with it even if adjacent at the time. %.hn 2 \subsection*{Steeds} %.pg Some types of creatures in the dungeon can actually be ridden if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in order to forge the alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the `{\tt \#ride}' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. %.pg Riding skill is managed by the `{\tt \#enhance}' command. See the section on Weapon proficiency for more information about that. %.hn 2 \subsection*{Bones levels} %.pg You may encounter the shades and corpses of other adventurers (or even former incarnations of yourself!) and their personal effects. Ghosts are hard to kill, but easy to avoid, since they're slow and do little damage. You can plunder the deceased adventurer's possessions; however, they are likely to be cursed. Beware of whatever killed the former player; it is probably still lurking around, gloating over its last victory. %.hn 1 \section{Objects} %.pg When you find something in the dungeon, it is common to want to pick it up. In {\it NetHack}, this is accomplished automatically by walking over the object (unless you turn off the {\it autopickup\/} option (see below), or move with the `{\tt m}' prefix (see above)), or manually by using the `{\tt ,}' command. %.pg If you're carrying too many items, {\it NetHack\/} will tell you so and you won't be able to pick up anything more. Otherwise, it will add the object(s) to your pack and tell you what you just picked up. %.pg As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry depends on your strength and your constitution. The stronger you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are carrying around with you through the dungeon will encumber you. Your reactions will get slower and you'll burn calories faster, requiring food more frequently to cope with it. Eventually, you'll be so overloaded that you'll either have to discard some of what you're carrying or collapse under its weight. %.pg NetHack will tell you how badly you have loaded yourself. The symbols `Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are displayed on the bottom line display to indicate your condition. %.pg When you pick up an object, it is assigned an inventory letter. Many commands that operate on objects must ask you to find out which object you want to use. When {\it NetHack\/} asks you to choose a particular object you are carrying, you are usually presented with a list of inventory letters to choose from (see Commands, above). %.pg Some objects, such as weapons, are easily differentiated. Others, like scrolls and potions, are given descriptions which vary according to type. During a game, any two objects with the same description are the same type. However, the descriptions will vary from game to game. %.pg When you use one of these objects, if its effect is obvious, {\it NetHack\/} will remember what it is for you. If its effect isn't extremely obvious, you will be asked what you want to call this type of object so you will recognize it later. You can also use the ``{\tt \#name}'' command, or its synonym `{\tt C}', for the same purpose at any time, to name all objects of a particular type or just an individual object. When you use ``{\tt \#name}'' on an object which has already been named, specifying a space as the value will remove the prior name instead of assigning a new one. %.hn 2 \subsection*{Curses and Blessings} %.pg Any object that you find may be cursed, even if the object is otherwise helpful. The most common effect of a curse is being stuck with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is not removable by ordinary means. In addition, cursed arms and armor usually, but not always, bear negative enchantments that make them less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. %.pg Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For example, a blessed weapon will do more damage against demons. %.pg Objects which are neither cursed nor blessed are referred to as uncursed. They could just as easily have been described as unblessed, but the uncursed designation is what you will see within the game. A ``glass half full versus glass half empty'' situation; make of that what you will. %.pg There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate sensitivity to this property in any object, so they can more easily avoid cursed objects than other character roles. %.pg An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. In some cases ``uncursed'' will be omitted as being redundant when enough other information is displayed. The {\it implicit\verb+_+uncursed\/} option can be used to control this; toggle it off to have ``uncursed'' be displayed even when that can be deduced from other attributes. %.hn 2 \subsection*{Weapons (`{\tt )}')} %.pg Given a chance, most monsters in the Mazes of Menace will gratuitously try to kill you. You need weapons for self-defense (killing them first). Without a weapon, you do only 1--2 hit points of damage (plus bonuses, if any). Monk characters are an exception; they normally do much more damage with bare hands than they do with weapons. %.pg There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings hurl rocks and (other) stones (like gems). %.pg Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be either positive or negative) that adds to your chance to hit and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically identified somehow. Most weapons are subject to some type of damage like rust. Such ``erosion'' damage can be repaired. %.pg The chance that an attack will successfully hit a monster, and the amount of damage such a hit will do, depends upon many factors. Among them are: type of weapon, quality of weapon (enchantment and/or erosion), experience level, strength, dexterity, encumbrance, and proficiency (see below). The monster's armor class---a general defense rating, not necessarily due to wearing of armor---is a factor too; also, some monsters are particularly vulnerable to certain types of weapons. %.pg Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon ready to use by setting things up with the `{\tt x}' command, which exchanges your primary (the one being wielded) and alternate weapons. And if you have proficiency in the ``two weapon combat'' skill, you may wield both weapons simultaneously as primary and secondary; use the `{\tt \#twoweapon}' extended command to engage or disengage that. Only some types of characters (barbarians, for instance) have the necessary skill available. Even with that skill, using two weapons at once incurs a penalty in the chance to hit your target compared to using just one weapon at a time. %.pg There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `{\tt -}', or else use the `{\tt A}' command which allows you to unwield the current weapon in addition to taking off other worn items. %.pg Those of you in the audience who are AD\&D players, be aware that each weapon which existed in AD\&D does roughly the same damage to monsters in {\it NetHack}. Some of the more obscure weapons (such as the % {\it aklys}, {\it lucern hammer}, and {\it bec-de-corbin\/}) are defined in an appendix to {\it Unearthed Arcana}, an AD\&D supplement. %.pg The commands to use weapons are `{\tt w}' (wield), `{\tt t}' (throw), `{\tt f}' (fire, an alternative way of throwing), `{\tt Q}' (quiver), `{\tt x}' (exchange), `{\tt \#twoweapon}', and `{\tt \#enhance}' (see below). %.hn 3 \subsection*{Throwing and shooting} %.pg You can throw just about anything via the `{\tt t}' command. It will prompt for the item to throw; picking `{\tt ?}' will list things in your inventory which are considered likely to be thrown, or picking `{\tt *}' will list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown depends mainly on the type of object and your strength. Arrows can be thrown by hand, but can be thrown much farther and will be more likely to hit when thrown while you are wielding a bow. %.pg You can simplify the throwing operation by using the `{\tt Q}' command to select your preferred ``missile'', then using the `{\tt f}' command to throw it. You'll be prompted for a direction as above, but you don't have to specify which item to throw each time you use `{\tt f}'. There is also an option, {\it autoquiver}, which has {\it NetHack\/} choose another item to automatically fill your quiver (or quiver sack, or have at the ready) when the inventory slot used for `{\tt Q}' runs out. %.pg Some characters have the ability to fire a volley of multiple items in a single turn. Knowing how to load several rounds of ammunition at once---or hold several missiles in your hand---and still hit a target is not an easy task. Rangers are among those who are adept at this task, as are those with a high level of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one to shoot bolts, or in sling skill if you're wielding one to shoot stones). The number of items that the character has a chance to fire varies from turn to turn. You can explicitly limit the number of shots by using a numeric prefix before the `{\tt t}' or `{\tt f}' command. For example, ``{\tt 2f}'' (or ``{\tt n2f}'' if using {\it number\verb+_+pad\/} mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify a larger number than would have been shot (``{\tt 4f}'' in this example), you'll just end up shooting the same number (3, here) as if no limit had been specified. Once the volley is in motion, all of the items will travel in the same direction; if the first ones kill a monster, the others can still continue beyond that spot. %.hn 3 \subsection*{Weapon proficiency} %.pg You will have varying degrees of skill in the weapons available. Weapon proficiency, or weapon skills, affect how well you can use particular types of weapons, and you'll be able to improve your skills as you progress through a game, depending on your role, your experience level, and use of the weapons. %.pg For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. %.pg The `{\tt \#enhance}' extended command is used to review current weapons proficiency (also spell proficiency) and to choose which skill(s) to improve when you've used one or more skills enough to become eligible to do so. The skill rankings are ``none'' (sometimes also referred to as ``restricted'', because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'', and ``expert''. Restricted skills simply will not appear in the list shown by `{\tt \#enhance}'. (Divine intervention might unrestrict a particular skill, in which case it will start at unskilled and be limited to basic.) Some characters can enhance their barehanded combat or martial arts skill beyond expert to ``master'' or ``grand master''. %.pg Use of a weapon in which you're restricted or unskilled will incur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is higher. A successful hit has a chance to boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, you'll be told that you feel more confident in your skills. At that point you can use `{\tt \#enhance}' to increase one or more skills. Such skills are not increased automatically because there is a limit to your total overall skills, so you need to actively choose which skills to enhance and which to ignore. %.hn 3 \subsection*{Two-Weapon combat} %.pg Some characters can use two weapons at once. Setting things up to do so can seem cumbersome but becomes second nature with use. To wield two weapons, you need to use the ``{\tt \#twoweapon}'' command. But first you need to have a weapon in each hand. (Note that your two weapons are not fully equal; the one in the hand you normally wield with is considered primary and the other one is considered secondary. The most noticeable difference is after you stop--or before you begin, for that matter--wielding two weapons at once. The primary is your wielded weapon and the secondary is just an item in your inventory that's been designated as alternate weapon.) %.pg If your primary weapon is wielded but your off hand is empty or has the wrong weapon, use the sequence `{\tt x}', `{\tt w}', `{\tt x}' to first swap your primary into your off hand, wield whatever you want as secondary weapon, then swap them both back into the intended hands. If your secondary or alternate weapon is correct but your primary one is not, simply use `{\tt w}' to wield the primary. Lastly, if neither hand holds the correct weapon, use `{\tt w}', `{\tt x}', `{\tt w}' to first wield the intended secondary, swap it to off hand, and then wield the primary. %.pg The whole process can be simplified via use of the {\it pushweapon\/} option. When it is enabled, then using `{\tt w}' to wield something causes the currently wielded weapon to become your alternate weapon. So the sequence `{\tt w}', `{\tt w}' can be used to first wield the weapon you intend to be secondary, and then wield the one you want as primary which will push the first into secondary position. %.pg When in two-weapon combat mode, using the ``{\tt \#twoweapon}'' command toggles back to single-weapon mode. Throwing or dropping either of the weapons or having one of them be stolen or destroyed will also make you revert to single-weapon combat. %.hn 2 \subsection*{Armor (`{\tt [}')} %.pg Lots of unfriendly things lurk about; you need armor to protect yourself from their blows. Some types of armor offer better protection than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD\&D, with 10 being the equivalent of no armor, and lower numbers meaning better armor. Each suit of armor which exists in AD\&D gives the same protection in {\it NetHack}. Here is an (incomplete) list of the armor classes provided by various suits of armor: \begin{center} \begin{tabular}{lllll} dragon scale mail & 1 & \makebox[20mm]{} & plate mail & 3\\ crystal plate mail & 3 & & bronze plate mail & 4\\ splint mail & 4 & & banded mail & 4\\ dwarvish mithril-coat & 4 & & elven mithril-coat & 5\\ chain mail & 5 & & orcish chain mail & 6\\ scale mail & 6 & & studded leather armor & 7\\ ring mail & 7 & & orcish ring mail & 8\\ leather armor & 8 & & leather jacket & 9\\ no armor & 10 \end{tabular} \end{center} %.pg \nd You can also wear other pieces of armor (ex.\ helmets, boots, shields, cloaks) to lower your armor class even further, but you can only wear one item of each category (one suit of armor, one cloak, one helmet, one shield, and so on) at a time. %.pg If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its ``plus'' (or minus) will subtract from your armor class. For example, a +1 chain mail would give you better protection than normal chain mail, lowering your armor class one unit further to 4. When you put on a piece of armor, you immediately find out the armor class and any ``plusses'' it provides. Cursed pieces of armor usually have negative enchantments (minuses) in addition to being unremovable. %.pg Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may inhibit spell casting. %.pg The commands to use armor are `{\tt W}' (wear) and `{\tt T}' (take off). The `{\tt A}' command can also be used to take off armor as well as other worn items. %.hn 2 \subsection*{Food (`{\tt \%}')} %.pg Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins (``cans'') will usually stay fresh, but ice boxes are heavy, and tins take a while to open. %.pg When you kill monsters, they usually leave corpses which are also ``food.'' Many, but not all, of these are edible; some also give you special powers when you eat them. A good rule of thumb is ``you are what you eat.'' %.pg Some character roles and some monsters are vegetarian. Vegetarian monsters will typically never eat animal corpses, while vegetarian players can, but with some rather unpleasant side-effects. %.pg You can name one food item after something you like to eat with the {\it fruit\/} option. %.pg The command to eat food is `{\tt e}'. %.hn 2 \subsection*{Scrolls (`{\tt ?}')} %.pg Scrolls are labeled with various titles, probably chosen by ancient wizards for their amusement value (ex.\ ``READ ME,'' or ``THANX MAUD'' backwards). Scrolls disappear after you read them (except for blank ones, without magic spells on them). %.pg One of the most useful of these is the % {\it scroll of identify}, which can be used to determine what another object is, whether it is cursed or blessed, and how many uses it has left. Some objects of subtle enchantment are difficult to identify without these. %.pg A mail daemon may run up and deliver mail to you as a % {\it scroll of mail} (on versions compiled with this feature). To use this feature on versions where {\it NetHack\/} mail delivery is triggered by electronic mail appearing in your system mailbox, you must let {\it NetHack\/} know where to look for new mail by setting the ``MAIL'' environment variable to the file name of your mailbox. You may also want to set the ``MAILREADER'' environment variable to the file name of your favorite reader, so {\it NetHack\/} can shell to it when you read the scroll. On versions of {\it NetHack\/} where mail is randomly generated internal to the game, these environment variables are ignored. You can disable the mail daemon by turning off the {\it mail\/} option. %.pg The command to read a scroll is `{\tt r}'. %.hn 2 \subsection*{Potions (`{\tt !}')} %.pg Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. %.pg Clear potions are potions of water. Sometimes these are blessed or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`{\tt t}') at them. It is also sometimes very useful to dip (``{\tt \#dip}'') an object into a potion. %.pg The command to drink a potion is `{\tt q}' (quaff). %.hn 2 \subsection*{Wands (`{\tt /}')} %.pg Magic wands usually have multiple magical charges. Some wands are directional---you must give a direction in which to zap them. You can also zap them at yourself (just give a `{\tt .}' or `{\tt s}' for the direction). Be warned, however, for this is often unwise. Other wands are nondirectional---they don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. %.pg When the number of charges left in a wand becomes zero, attempts to use the wand will usually result in nothing happening. Occasionally, however, it may be possible to squeeze the last few mana points from an otherwise spent wand, destroying it in the process. A wand may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time the wand is recharged. %.pg In a truly desperate situation, when your back is up against the wall, you might decide to go for broke and break your wand. This is not for the faint of heart. Doing so will almost certainly cause a catastrophic release of magical energies. %.pg When you have fully identified a particular wand, inventory display will include additional information in parentheses: the number of times it has been recharged followed by a colon and then by its current number of charges. A current charge count of {\tt -1} is a special case indicating that the wand has been cancelled. %.pg The command to use a wand is `{\tt z}' (zap). To break one, use the `{\tt a}' (apply) command. %.hn 2 \subsection*{Rings (`{\tt =}')} %.pg Rings are very useful items, since they are relatively permanent magic, unlike the usually fleeting effects of potions, scrolls, and wands. %.pg Putting on a ring activates its magic. You can wear only two rings, one on each ring finger. %.pg Most rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. %.pg The commands to use rings are `{\tt P}' (put on) and `{\tt R}' (remove). %.hn 2 \subsection*{Spellbooks (`{\tt +}')} %.pg Spellbooks are tomes of mighty magic. When studied with the `{\tt r}' (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable) --- unless the attempt backfires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! %.pg A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. %.pg Casting a spell calls forth magical energies and focuses them with your naked mind. Some of the magical energy released comes from within you, and casting several spells in a row may tire you. Casting of spells also requires practice. With practice, your skill in each category of spell casting will improve. Over time, however, your memory of each spell will dim, and you will need to relearn it. %.pg Some spells are directional---you must give a direction in which to cast them. You can also cast them at yourself (just give a `{\tt .}' or `{\tt s}' for the direction). Be warned, however, for this is often unwise. Other spells are nondirectional---they don't require a direction. %.pg Just as weapons are divided into groups in which a character can become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises its skill group; using the `{\tt \#enhance}' command to advance a sufficiently exercised skill will affect all spells within the group. Advanced skill may increase the potency of spells, reduce their risk of failure during casting attempts, and improve the accuracy of the estimate for how much longer they will be retained in your memory. Skill slots are shared with weapons skills. (See also the section on ``Weapon proficiency''.) %.pg Casting a spell also requires flexible movement, and wearing various types of armor may interfere with that. %.pg The command to read a spellbook is the same as for scrolls, `{\tt r}' (read). The `{\tt +}' command lists each spell you know along with its level, skill category, chance of failure when casting, and an estimate of how strongly it is remembered. The `{\tt Z}' (cast) command casts a spell. %.hn 2 \subsection*{Tools (`{\tt (}')} %.pg Tools are miscellaneous objects with various purposes. Some tools have a limited number of uses, akin to wand charges. For example, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. %.pg The command to use tools is `{\tt a}' (apply). %.hn 3 \subsection*{Containers} %.pg You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the ``{\tt \#loot}'' extended command when you are standing on top of it (that is, on the same floor spot), or with the `{\tt a}' (apply) command when you are carrying it. However, chests are often locked, and are in any case unwieldy objects. You must set one down before unlocking it by using a key or lock-picking tool with the `{\tt a}' (apply) command, by kicking it with the `{\tt \^{}D}' command, or by using a weapon to force the lock with the ``{\tt \#force}'' extended command. %.pg Some chests are trapped, causing nasty things to happen when you unlock or open them. You can check for and try to deactivate traps with the ``{\tt \#untrap}'' extended command. %.hn 2 \subsection*{Amulets (`{\tt "}')} %.pg Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some beneficial, some harmful, which are activated by putting them on. %.pg Only one amulet may be worn at a time, around your neck. %.pg The commands to use amulets are the same as for rings, `{\tt P}' (put on) and `{\tt R}' (remove). %.hn 2 \subsection*{Gems (`{\tt *}')} %.pg Some gems are valuable, and can be sold for a lot of gold. They are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. %.pg Other small rocks are also categorized as gems, but they are much less valuable. All rocks, however, can be used as projectile weapons (if you have a sling). In the most desperate of cases, you can still throw them by hand. %.hn 2 \subsection*{Large rocks (`{\tt `}')} %.pg Statues and boulders are not particularly useful, and are generally heavy. It is rumored that some statues are not what they seem. %.pg Very large humanoids (giants and their ilk) have been known to use boulders as weapons. %.hn 2 \subsection*{Gold (`{\tt \$}')} %.pg Gold adds to your score, and you can buy things in shops with it. There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). %.hn 1 \section{Conduct} %.pg As if winning {\it NetHack\/} were not difficult enough, certain players seek to challenge themselves by imposing restrictions on the way they play the game. The game automatically tracks some of these challenges, which can be checked at any time with the {\tt \#conduct} command or at the end of the game. When you perform an action which breaks a challenge, it will no longer be listed. This gives players extra ``bragging rights'' for winning the game with these challenges. Note that it is perfectly acceptable to win the game without resorting to these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. %.pg Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures can survive long periods of time without food, there is a physiological need for water; thus there is no restriction on drinking beverages, even if they provide some minor food benefits. Calling upon your god for help with starvation does not violate any food challenges either. %.pg A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and vegetables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are also considered to be vegetable matter. Certain human food is prepared without animal products; namely, lembas wafers, cram rations, food rations (gunyoki), K-rations, and C-rations. Metal or another normally indigestible material eaten while polymorphed into a creature that can digest it is also considered vegan food. Note however that eating such items still counts against foodless conduct. %.pg Vegetarians do not eat animals; however, they are less selective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than the black puddings, eggs and food made from eggs (fortune cookies and pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. %.pg Eating any kind of meat violates the vegetarian, vegan, and foodless conducts. This includes tripe rations, the corpses or tins of any monsters not mentioned above, and the various other chunks of meat found in the dungeon. Swallowing and digesting a monster while polymorphed is treated as if you ate the creature's corpse. Eating leather, dragon hide, or bone items while polymorphed into a creature that can digest it, or eating monster brains while polymorphed into a mind flayer, is considered eating an animal, although wax is only an animal byproduct. %.pg Regardless of conduct, there will be some items which are indigestible, and others which are hazardous to eat. Using a swallow-and-digest attack against a monster is equivalent to eating the monster's corpse. Please note that the term ``vegan'' is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, coral), but the game will not keep track of this for you. Also note that ``milky'' potions may be a translucent white, but they do not contain milk, so they are compatible with a vegan diet. Slime molds or player-defined ``fruits'', although they could be anything from ``cherries'' to ``pork chops'', are also assumed to be vegan. %.pg An atheist is one who rejects religion. This means that you cannot {\tt \#pray}, {\tt \#offer} sacrifices to any god, {\tt \#turn} undead, or {\tt \#chat} with a priest. Particularly selective readers may argue that playing Monk or Priest characters should violate this conduct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also not penalized for being spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. %.pg Most players fight with a wielded weapon (or tool intended to be wielded as a weapon). Another challenge is to win the game without using such a wielded weapon. You are still permitted to throw, fire, and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. %.pg In {\it NetHack\/}, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to gain experience by other means. %.pg An illiterate character cannot read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writing a scroll; or making an engraving of anything other than a single ``x'' (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is assumed to be learned from your teachers prior to the start of the game and isn't counted. %.pg There are several other challenges tracked by the game. It is possible to eliminate one or more species of monsters by genocide; playing without this feature is considered a challenge. When the game offers you an opportunity to genocide monsters, you may respond with the monster type ``none'' if you want to decline. You can change the form of an item into another item of the same type (``polypiling'') or the form of your own body into another creature (``polyself'') by wand, spell, or potion of polymorph; avoiding these effects are each considered challenges. Polymorphing monsters, including pets, does not break either of these challenges. Finally, you may sometimes receive wishes; a game without an attempt to wish for any items is a challenge, as is a game without wishing for an artifact (even if the artifact immediately disappears). When the game offers you an opportunity to make a wish for an item, you may choose ``nothing'' if you want to decline. %.hn 1 \section{Options} %.pg Due to variations in personal tastes and conceptions of how {\it NetHack\/} should do things, there are options you can set to change how {\it NetHack\/} behaves. %.hn 2 \subsection*{Setting the options} %.pg Options may be set in a number of ways. Within the game, the `{\tt O}' command allows you to view all options and change most of them. You can also set options automatically by placing them in the ``NETHACKOPTIONS'' environment variable or in a configuration file. Some versions of {\it NetHack\/} also have front-end programs that allow you to set options before starting the game or a global configuration for system administrators. %.hn 2 \subsection*{Using the NETHACKOPTIONS environment variable} %.pg The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, and turn it off by typing a `{\tt !}' or ``{\tt no}'' before the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the string. The value is terminated by the next comma or the end of string. %.pg For example, to set up an environment variable so that {\it autoquiver\/} is on, {\it autopickup\/} is off, the {\it name\/} is set to ``Blue Meanie'', and the {\it fruit\/} is set to ``papaya'', you would enter the command %.sd \begin{verbatim} setenv NETHACKOPTIONS "autoquiver,\!autopickup,name:Blue Meanie,fruit:papaya" \end{verbatim} %.ed \nd in {\it csh} (note the need to escape the ! since it's special to the shell), or %.sd \begin{verbatim} NETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya" export NETHACKOPTIONS \end{verbatim} %.ed \nd in {\it sh\/} or {\it ksh}. %.hn 2 \subsection*{Using a configuration file} %.pg Any line in the configuration file starting with `{\tt \#}' is treated as a comment. Any line in the configuration file starting with ``{\tt OPTIONS=}'' may be filled out with options in the same syntax as in NETHACKOPTIONS. Any line starting with ``{\tt SYMBOLS=}'' is taken as defining the corresponding {\it symbol} in a different syntax, a sequence of decimal numbers giving the character position in the current font to be used in displaying each entry. Such a sequence can be continued to multiple lines by putting a `{\tt \verb+\+}' at the end of each line to be continued. %.pg Any line starting with ``{\tt AUTOPICKUP\verb+_+EXCEPTION=}'' is taken as defining an exception to the ``{\tt pickup\verb+_+types}'' option. There is a section of this Guidebook that discusses that. %.pg The default name of the configuration file varies on different operating systems, but NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `{\tt @}'). %.hn 2 \subsection*{Customization options} %.pg Here are explanations of what the various options do. Character strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. %.pg Some options are persistent, and are saved and reloaded along with the game. Changing a persistent option in the configuration file applies only to new games. \blist{} %.lp \item[\ib{acoustics}] Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio capabilities. Persistent. %.lp \item[\ib{align}] Your starting alignment ({\tt align:lawful}, {\tt align:neutral}, or {\tt align:chaotic}). You may specify just the first letter. The default is to randomly pick an appropriate alignment. If you prefix `{\tt !}' or ``{\tt no}'' to the value, you can exclude that alignment from being picked randomly. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{autodig}] Automatically dig if you are wielding a digging tool and moving into a place that can be dug (default false). Persistent. %.lp \item[\ib{autoopen}] Walking into a door attempts to open it (default true). Persistent. %.lp \item[\ib{autopickup}] Automatically pick up things onto which you move (default on). Persistent. See ``{\it pickup\verb+_+types\/}'' to refine the behavior. %.lp \item[\ib{autoquiver}] This option controls what happens when you attempt the `f' (fire) command with an empty quiver (or quiver sack or have nothing at the ready). When true, the computer will fill your quiver or quiver sack or make ready some suitable weapon. Note that it will not take into account the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver or quiver sack or make ready with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is executed instead. Persistent. (default false) %.lp \item[\ib{blind}] Start the character permanently blind. Persistent. (default false) %.lp \item[\ib{bones}] Allow saving and loading bones files. Persistent. (default true) %.lp \item[\ib{boulder}] Set the character used to display boulders (default is rock class symbol). %.lp \item[\ib{catname}] Name your starting cat (ex.\ ``{\tt catname:Morris}''). Cannot be set with the `{\tt O}' command. %.lp character \item[\ib{character}] Pick your type of character (ex.\ ``{\tt character:Monk}''); synonym for ``{\it role\/}''. See ``{\it name\/}'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; the string ``{\tt random}'' is an exception. %.lp \item[\ib{checkpoint}] Save game state after each level change, for possible recovery after program crash (default on). Persistent. %.lp \item[\ib{checkspace}] Check free disk space before writing files to disk (default on). You may have to turn this off if you have more than 2 GB free space on the partition used for your save and level files. Only applies when MFLOPPY was defined during compilation. %.lp \item[\ib{clicklook}] Allows looking at things on the screen by navigating the mouse over them and clicking the right mouse button (default off). %.lp \item[\ib{cmdassist}] Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). %.lp \item[\ib{confirm}] Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). Persistent. %.lp %.lp \item[\ib{dark\verb+_+room}] Show out-of-sight areas of lit rooms (default off). Persistent. \item[\ib{disclose}] Controls what information the program reveals when the game ends. Value is a space separated list of prompting/category pairs (default is `{\tt ni na nv ng nc no}', prompt with default response of `{\tt n}' for each candidate). Persistent. The possibilities are: %.sd %.si {\tt i} --- disclose your inventory;\\ {\tt a} --- disclose your attributes;\\ {\tt v} --- summarize monsters that have been vanquished;\\ {\tt g} --- list monster species that have been genocided;\\ {\tt c} --- display your conduct;\\ {\tt o} --- display dungeon overview. %.ei %.ed Each disclosure possibility can optionally be preceded by a prefix which lets you refine how it behaves. Here are the valid prefixes: %.sd %.si {\tt y} --- prompt you and default to yes on the prompt;\\ {\tt n} --- prompt you and default to no on the prompt;\\ {\tt +} --- disclose it without prompting;\\ {\tt -} --- do not disclose it and do not prompt. %.ei %.ed %.lp "" (ex.\ ``{\tt disclose:yi na +v -g o}'') The example sets {\tt inventory} to {\it prompt\/} and default to {\it yes\/}, {\tt attributes} to {\it prompt\/} and default to {\it no\/}, {\tt vanquished} to {\it disclose without prompting\/}, {\tt genocided} to {\it not disclose\/} and {\it not prompt\/}, {\tt conduct} to implicitly {\it prompt\/} and default to {\it no\/}, {\tt overview} to {\it disclose without prompting\/}. %.lp "" Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. And the dungeon overview shows all levels you had visited but does not reveal things about them that you hadn't discovered. %.lp \item[\ib{dogname}] Name your starting dog (ex.\ ``{\tt dogname:Fang}''). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{extmenu}] Changes the extended commands interface to pop-up a menu of available commands. It is keystroke compatible with the traditional interface except that it does not require that you hit Enter. It is implemented only by the tty port (default off), when the game has been compiled to support tty graphics. %.lp \item[\ib{female}] An obsolete synonym for ``{\tt gender:female}''. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{fixinv}] An object's inventory letter sticks to it when it's dropped (default on). If this is off, dropping an object shifts all the remaining inventory letters. Persistent. %.lp \item[\ib{fruit}] Name a fruit after something you enjoy eating (ex.\ ``{\tt fruit:mango}'') (default ``{\tt slime mold}''). Basically a nostalgic whimsy that {\it NetHack\/} uses from time to time. You should set this to something you find more appetizing than slime mold. Apples, oranges, pears, bananas, and melons already exist in {\it NetHack}, so don't use those. %.Ip \item[\ib{gender}] Your starting gender ({\tt gender:male} or {\tt gender:female}). You may specify just the first letter. Although you can still denote your gender using the ``{\tt male}'' and ``{\tt female}'' options, the ``{\tt gender}'' option will take precedence. The default is to randomly pick an appropriate gender. If you prefix `{\tt !}' or ``{\tt no}'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{help}] If more information is available for an object looked at with the `{\tt /}' command, ask if you want to see it (default on). Turning help off makes just looking at things faster, since you aren't interrupted with the ``{\tt More info?}'' prompt, but it also means that you might miss some interesting and/or important information. Persistent. %.lp \item[\ib{hilite\verb+_+pet}] Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. %.lp \item[\ib{hilite\verb+_+pile}] Visually distinguish piles of objects from individual objects (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a small plus-symbol beside the object on the top of the pile. %.lp \item[\ib{horsename}] Name your starting horse (ex.\ ``{\tt horsename:Trigger}''). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{ignintr}] Ignore interrupt signals, including breaks (default off). Persistent. %.lp \item[\ib{implicit\verb+_+uncursed}] Omit ``uncursed'' from inventory lists, if possible (default on). %.lp \item[\ib{legacy}] Display an introductory message when starting the game (default on). Persistent. %.lp \item[\ib{lit\verb+_+corridor}] Show corridor squares seen by night vision or a light source held by your character as lit (default off). Persistent. %.lp \item[\ib{lootabc}] Use the old `{\tt a}', `{\tt b}', and `{\tt c}' keyboard shortcuts when looting, rather than the mnemonics `{\tt o}', `{\tt i}', and `{\tt b}' (default off). Persistent. %.lp \item[\ib{mail}] Enable mail delivery during the game (default on). Persistent. %.lp \item[\ib{male}] An obsolete synonym for ``{\tt gender:male}''. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{mention\verb+_+walls}] Give feedback when walking against a wall (default off). %.lp \item[\ib{menucolors}] Enable coloring menu lines (default off). See ``{\it Configuring Menu Colors\/}'' on how to configure the colors. %.lp \item[\ib{menustyle}] Controls the interface used when you need to choose various objects (in response to the Drop command, for instance). The value specified should be the first letter of one of the following: traditional, combination, full, or partial. Traditional was the only interface available for early versions; it consists of a prompt for object class characters, followed by an object-by-object prompt for all items matching the selected object class(es). Combination starts with a prompt for object class(es) of interest, but then displays a menu of matching objects rather than prompting one-by-one. Full displays a menu of object classes rather than a character prompt, and then a menu of matching objects for selection. Partial skips the object class filtering and immediately displays a menu of all objects. Persistent. \item[\ib{menu\verb+_+deselect\verb+_+all}] Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `-'. \item[\ib{menu\verb+_+deselect\verb+_+page}] Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+\+'. \item[\ib{menu\verb+_+first\verb+_+page}] Menu character accelerator to jump to the first page in a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+^+'. \item[\ib{menu\verb+_+headings}] Controls how the headings in a menu are highlighted. Values are ``{\tt none}'', ``{\tt bold}'', ``{\tt dim}'', ``{\tt underline}'', ``{\tt blink}'', or ``{\tt inverse}''. Not all ports can actually display all types. \item[\ib{menu\verb+_+invert\verb+_+all}] Menu character accelerator to invert all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `@'. \item[\ib{menu\verb+_+invert\verb+_+page}] Menu character accelerator to invert all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+~+'. \item[\ib{menu\verb+_+last\verb+_+page}] Menu character accelerator to jump to the last page in a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+|+'. \item[\ib{menu\verb+_+next\verb+_+page}] Menu character accelerator to goto the next menu page. Implemented by the Amiga, Gem and tty ports. Default `\verb+>+'. \item[\ib{menu\verb+_+objsyms}] Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). \item[\ib{menu\verb+_+previous\verb+_+page}] Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. Default `\verb+<+'. \item[\ib{menu\verb+_+search}] Menu character accelerator to search for a menu item. Implemented by the Amiga, Gem, X11 and tty ports. Default `:'. \item[\ib{menu\verb+_+select\verb+_+all}] Menu character accelerator to select all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `.'. \item[\ib{menu\verb+_+select\verb+_+page}] Menu character accelerator to select all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default `,'. %.lp \item[\ib{msghistory}] The number of top line messages to save (and recall with `{\tt \^{}P}') (default 20). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{msg\verb+_+window}] Allows you to change the way recalled messages are displayed. (It is currently implemented for tty only.) The possible values are: %.sd %.si {\tt s} --- single message (default; only choice prior to 3.4.0);\\ {\tt c} --- combination, two messages as {\it single\/}, then as {\it full\/};\\ {\tt f} --- full window, oldest message first;\\ {\tt r} --- full window reversed, newest message first. %.ei %.ed For backward compatibility, no value needs to be specified (which defaults to {\it full\/}), or it can be negated (which defaults to {\it single\/}). %.lp \item[\ib{name}] Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of ``{\tt -A -B -C -H -K -M -P -Ra -Ro -S -T -V -W}''). If ``{\tt -@}'' is used for the role, then a random one will be automatically chosen. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{news}] Read the {\it NetHack\/} news file, if present (default on). Since the news is shown at the beginning of the game, there's no point in setting this with the `{\tt O}' command. %.lp \item[\ib{nudist}] Start the character with no armor (default false). Persistent. %.lp \item[\ib{null}] Send padding nulls to the terminal (default on). Persistent. %.lp \item[\ib{number\verb+_+pad}] Use digit keys instead of letters to move (default 0 or off).\\ Valid settings are: %.sd %.si \newlength{\mwidth} \settowidth{\mwidth}{\tt -0} \newcommand{\numbox}[1]{\makebox[\mwidth][r]{{\tt #1}}} \numbox{0} --- move by letters; `{\tt yuhjklbn}'\\ \numbox{1} --- move by numbers; digit `{\tt 5}' acts as `{\tt G}' movement prefix\\ \numbox{2} --- like {\tt 1} but `{\tt 5}' works as `{\tt g}' prefix instead of as `{\tt G}'\\ \numbox{3} --- by numbers using phone key layout; {\tt 123} above, {\tt 789} below\\ \numbox{4} --- combines {\tt 3} with {\tt 2}; phone layout plus MSDOS compatibility\\ \numbox{-1} --- by letters but use `{\tt z}' to go northwest, `{\tt y}' to zap wands %.ei %.ed For backward compatibility, omitting a value is the same as specifying {\tt 1} and negating {\it number\verb+_+pad\/} is the same as specifying {\tt 0}. (Settings {\tt 2} and {\tt 4} are for compatibility with MSDOS or old PC Hack; in addition to the different behavior for `{\tt 5}', `{\tt Alt-5}' acts as `{\tt G}' and `{\tt Alt-0}' acts as `{\tt I}'. Setting {\tt -1} is to accommodate some German keyboards which have the location of the `{\tt y}' and `{\tt z}' keys swapped.) When moving by numbers, to enter a count prefix for those commands which accept one (such as ``{\tt 12s}'' to search twelve times), precede it with the letter `{\tt n}' (``{\tt n12s}''). %.lp \item[\ib{packorder}] Specify the order to list object types in (default ``\verb&")[%?+!=/(*`0_&''). The value of this option should be a string containing the symbols for the various object types. Any omitted types are filled in at the end from the previous order. %.lp \item[\ib{paranoid\verb+_+confirmation}] A space separated list of specific situations where alternate prompting is desired. The default is ``{\it paranoid\verb+_+confirmation:pray}''. %.sd %.si \newlength{\pcwidth} \settowidth{\pcwidth}{\tt Confirm} \addtolength{\pcwidth}{\labelsep} \blist{\leftmargin \pcwidth \topsep 1mm \itemsep 0mm} \item[{\tt Confirm}] for any prompts which are set to require ``yes'' rather than `y', also require ``no'' to reject instead of accepting any non-yes response as no; \item[{\tt quit~~~}] require ``{\tt yes}'' rather than `{\tt y}' to confirm quitting the game or switching into non-scoring explore mode; \item[{\tt die~~~~}] require ``{\tt yes}'' rather than `{\tt y}' to confirm dying (not useful in normal play; applies to explore mode); \item[{\tt bones~~}] require ``{\tt yes}'' rather than `{\tt y}' to confirm saving bones data when dying in debug mode \item[{\tt attack~}] require ``{\tt yes}'' rather than `{\tt y}' to confirm attacking a peaceful monster; \item[{\tt pray~~~}] require `{\tt y}' to confirm an attempt to pray rather than immediately praying; on by default; \item[{\tt wand}] require ``{\tt yes}'' rather than `{\tt y}' to confirm breaking a wand; \item[{\tt Remove~}] require selection from inventory for `{\tt R}' and `{\tt T}' commands even when wearing just one applicable item. \elist %.ei %.ed By default, the pray choice is enabled, the others disabled. To disable it without setting any of the other choices, use ``{\it paranoid\verb+_+confirmation:none}''. To keep it enabled while setting others, include it in the list, such as ``{\it par\-a\-noid\verb+_+con\-fir\-ma\-tion:attack~pray~Remove}''. %.lp \item[\ib{perm\verb+_+invent}] If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. Persistent. %.lp \item[\ib{pettype}] Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. Possible values are ``{\tt cat}'', ``{\tt dog}'', ``{\tt horse}'' and ``{\tt none}''. If the choice is not allowed for the role you are currently playing, it will be silently ignored. For example, ``{\tt horse}'' will only be honored when playing a knight. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{pickup\verb+_+burden}] When you pick up an item that would exceed this encumbrance level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default `S'). Persistent. %.lp \item[\ib{pickup\verb+_+thrown}] If this option is on and ``{\it autopickup\/}'' is also on, try to pick up things that you threw, even if they aren't in ``{\it pickup\verb+_+types\/}'' or match an autopickup exception. Default is on. Persistent. %.lp \item[\ib{pickup\verb+_+types}] Specify the object types to be picked up when ``{\it autopickup\/}'' is on. Default is all types. You can use ``{\it autopickup\verb+_+exception\/}'' configuration file lines to further refine ``{\it autopickup\/}'' behavior. Persistent. %.lp \item[\ib{pile\verb+_+limit}] When walking across a pile of objects on the floor, threshold at which the message ``there are few/several/many objects here'' is given instead of showing a popup list of those objects. A value of 0 means ``no limit'' (always list the objects); a value of 1 effectively means ``never show the objects'' since the pile size will always be at least that big; default value is 5. Persistent. %.lp \item[\ib{playmode}] Values are {\it normal\/}, {\it explore\/}, or {\it debug\/}. Allows selection of explore mode (also known as discovery mode) or debug mode (also known as wizard mode) instead of normal play. Debug mode might only be allowed for someone logged in under a particular user name (on multi-user systems) or specifying a particular character name (on single-user systems) or it might be disabled entirely. Requesting it when not allowed or not possible results in explore mode instead. Default is normal play. %.lp \item[\ib{pushweapon}] Using the `w' (wield) command when already wielding something pushes the old item into your alternate weapon slot (default off). Likewise for the `a' (apply) command if it causes the applied item to become wielded. Persistent. %.Ip \item[\ib{race}] Selects your race (for example, ``{\tt race:human}''). Default is random. If you prefix `{\tt !}' or ``{\tt no}'' to the value, you can exclude that race from being picked randomly. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{rest\verb+_+on\verb+_+space}] Make the space bar a synonym for the `{\tt .}' (rest) command (default off). Persistent. %.lp \item[\ib{role}] Pick your type of character (ex.\ ``{\tt role:Samurai}''); synonym for ``{\it character\/}''. See ``{\it name\/}'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; `r' is an exception with ``{\tt Rogue}'', {\tt Ranger}'', and ``{\tt random}'' values. If you prefix `{\tt !}' or ``{\tt no}'' to the value, you can exclude that role from being picked randomly. Persistent. %.lp \item[\ib{roguesymset}] This option may be used to select one of the named symbol sets found within {\tt symbols} to alter the symbols displayed on the screen on the rogue level. %.lp \item[\ib{rlecomp}] When writing out a save file, perform run length compression of the map. Not all ports support run length compression. It has no effect on reading an existing save file. %.lp \item[\ib{runmode}] Controls the amount of screen updating for the map window when engaged in multi-turn movement (running via {\tt shift}+direction or {\tt control}+direction and so forth, or via the travel command or mouse click). The possible values are: %.sd %.si {\tt teleport} --- update the map after movement has finished;\\ {\tt run} --- update the map after every seven or so steps;\\ {\tt walk} --- update the map after each step;\\ {\tt crawl} --- like {\it walk\/}, but pause briefly after each step. %.ei %.ed This option only affects the game's screen display, not the actual results of moving. The default is {\it run\/}; versions prior to 3.4.1 used {\it teleport\/} only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. Persistent. %.lp \item[\ib{safe\verb+_+pet}] Prevent you from (knowingly) attacking your pets (default on). Persistent. %.lp \item[\ib{scores}] Control what parts of the score list you are shown at the end (ex.\ ``{\tt scores:5top scores/4around my score/own scores}''). Only the first letter of each category (`{\tt t}', `{\tt a}' or `{\tt o}') is necessary. Persistent. %.lp \item[\ib{showexp}] Show your accumulated experience points on bottom line (default off). Persistent. %.lp \item[\ib{showrace}] Display yourself as the glyph for your race, rather than the glyph for your role (default off). Note that this setting affects only the appearance of the display, not the way the game treats you. Persistent. %.lp \item[\ib{showscore}] Show your approximate accumulated score on bottom line (default off). Persistent. %.lp \item[\ib{silent}] Suppress terminal beeps (default on). Persistent. %.lp \item[\ib{sortloot}] Controls the sorting behavior of pickup lists for inventory and \#loot commands and some others. Persistent. The possible values are: %.sd %.si {\tt full} --- always sort the lists;\\ {\tt loot} --- only sort the lists that don't use inventory letters, like with the \#loot and pickup commands;\\ {\tt none} --- show lists the traditional way without sorting. %.ei %.ed %.lp \item[\ib{sortpack}] Sort the pack contents by type when displaying inventory (default on). Persistent. %.lp \item[\ib{sparkle}] Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). Persistent. %.lp \item[\ib{standout}] Boldface monsters and ``{\tt --More--}'' (default off). Persistent. %.lp \item[\ib{statushilites}] Enable coloring of status fields (default off). See ``{\it Configuring Status Hilites\/}'' for further information. %.lp \item[\ib{suppress\verb+_+alert}] This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior versions (ex.\ ``{\tt suppress\verb+_+alert:3.3.1}'') %.lp \item[\ib{symset}] This option may be used to select one of the named symbol sets found within {\tt symbols} to alter the symbols displayed on the screen. %.lp \item[\ib{time}] Show the elapsed game time in turns on bottom line (default off). Persistent. %.lp \item[\ib{timed\verb+_+delay}] When pausing momentarily for display effect, such as with explosions and moving objects, use a timer rather than sending extra characters to the screen. (Applies to ``tty'' interface only; ``X11'' interface always uses a timer based delay. The default is on if configured into the program.) Persistent. %.lp \item[\ib{tombstone}] Draw a tombstone graphic upon your death (default on). Persistent. %.lp \item[\ib{toptenwin}] Put the ending display in a NetHack window instead of on stdout (default off). Setting this option makes the score list visible when a windowing version of NetHack is started without a parent window, but it no longer leaves the score list around after game end on a terminal or emulating window. %.lp \item[\ib{travel}] Allow the travel command (default on). Turning this option off will prevent the game from attempting unintended moves if you make inadvertent mouse clicks on the map window. Persistent. %.lp \item[\ib{verbose}] Provide more commentary during the game (default on). Persistent. %.lp \item[\ib{windowtype}] Select which windowing system to use, such as ``{\tt tty}'' or ``{\tt X11}'' (default depends on version). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{zerocomp}] When writing out a save file, perform zero-comp compression of the contents. Not all ports support zero-comp compression. It has no effect on reading an existing save file. \elist %.hn 2 \subsection*{Window Port Customization options} %.pg Here are explanations of the various options that are used to customize and change the characteristics of the windowtype that you have chosen. Character strings that are too long may be truncated. Not all window ports will adjust for all settings listed here. You can safely add any of these options to your config file, and if the window port is capable of adjusting to suit your preferences, it will attempt to do so. If it can't it will silently ignore it. You can find out if an option is supported by the window port that you are currently using by checking to see if it shows up in the Options list. Some options are dynamic and can be specified during the game with the `{\tt O}' command. \blist{} %.lp \item[\ib{align\verb+_+message}] Where to align or place the message window (top, bottom, left, or right) %.lp \item[\ib{align\verb+_+status}] Where to align or place the status window (top, bottom, left, or right). %.lp \item[\ib{ascii\verb+_+map}] NetHack should display an ascii map if it can. %.lp \item[\ib{color}] NetHack should display color if it can for different monsters, objects, and dungeon features %.lp \item[\ib{eight\verb+_+bit\verb+_+tty}] Pass eight-bit character values (for example, specified with the {\it traps \/} option) straight through to your terminal (default off). %.lp \item[\ib{font\verb+_+map}] NetHack should use a font by the chosen name for the map window. %.lp \item[\ib{font\verb+_+menu}] NetHack should use a font by the chosen name for menu windows. %.lp \item[\ib{font\verb+_+message}] NetHack should use a font by the chosen name for the message window. %.lp \item[\ib{font\verb+_+status}] NetHack should use a font by the chosen name for the status window. %.lp \item[\ib{font\verb+_+text}] NetHack should use a font by the chosen name for text windows. %.lp \item[\ib{font\verb+_+size\verb+_+map}] NetHack should use this size font for the map window. %.lp \item[\ib{font\verb+_+size\verb+_+menu}] NetHack should use this size font for menu windows. %.lp \item[\ib{font\verb+_+size\verb+_+message}] NetHack should use this size font for the message window. %.lp \item[\ib{font\verb+_+size\verb+_+status}] NetHack should use this size font for the status window. %.lp \item[\ib{font\verb+_+size\verb+_+text}] NetHack should use this size font for text windows. %.lp \item[\ib{fullscreen}] NetHack should try and display on the entire screen rather than in a window. %.lp \item[\ib{large\verb+_+font}] NetHack should use a large font. %.lp \item[\ib{map\verb+_+mode}] NetHack should display the map in the manner specified. %.lp \item[\ib{mouse\verb+_+support}] Allow use of the mouse for input and travel. %.lp \item[\ib{player\verb+_+selection}] NetHack should pop up dialog boxes or use prompts for character selection. %.lp \item[\ib{popup\verb+_+dialog}] NetHack should pop up dialog boxes for input. %.lp \item[\ib{preload\verb+_+tiles}] NetHack should preload tiles into memory. For example, in the protected mode MSDOS version, control whether tiles get pre-loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. (default on). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{scroll\verb+_+amount}] NetHack should scroll the display by this number of cells when the hero reaches the scroll\verb+_+margin. %.lp \item[\ib{scroll\verb+_+margin}] NetHack should scroll the display when the hero or cursor is this number of cells away from the edge of the window. %.lp \item[\ib{selectsaved}] NetHack should display a menu of existing saved games for the player to choose from at game startup, if it can. Not all ports support this option. %.lp \item[\ib{softkeyboard}] Display an onscreen keyboard. Handhelds are most likely to support this option. %.lp \item[\ib{splash\verb+_+screen}] NetHack should display an opening splash screen when it starts up (default yes). %.lp \item[\ib{tiled\verb+_+map}] NetHack should display a tiled map if it can. %.lp \item[\ib{tile\verb+_+file}] Specify the name of an alternative tile file to override the default. %.lp \item[\ib{tile\verb+_+height}] Specify the preferred height of each tile in a tile capable port. %.lp \item[\ib{tile\verb+_+width}] Specify the preferred width of each tile in a tile capable port %.lp \item[\ib{use\verb+_+darkgray}] Use bold black instead of blue for black glyphs (TTY only). %.lp \item[\ib{use\verb+_+inverse}] NetHack should display inverse when the game specifies it. %.lp \item[\ib{vary\verb+_+msgcount}] NetHack should display this number of messages at a time in the message window. %.lp \item[\ib{windowcolors}] NetHack should display windows with the specified foreground/background colors if it can. %.lp \item[\ib{wraptext}] NetHack port should wrap long lines of text if they don't fit in the visible area of the window. \elist %.hn 2 \subsection*{Platform-specific Customization options} %.pg Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. \blist{} %.lp \item[\ib{altkeyhandler}] Select an alternate keystroke handler dll to load ({\it Win32 tty\/ NetHack\/} only). The name of the handler is specified without the .dll extension and without any path information. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{altmeta}] On Amiga, this option controls whether typing ``Alt'' plus another key functions as a meta-shift for that key (default on). %.lp \item[\ib{altmeta}] On other (non-Amiga) systems where this option is available, it can be set to tell nethack to convert a two character sequence beginning with ESC into a meta-shifted version of the second character (default off). %.lp "" This conversion is only done for commands, not for other input prompts. Note that typing one or more digits as a count prefix prior to a command---preceded by {\tt n} if the {\it number\verb+_+pad\/} option is set---is also subject to this conversion, so attempting to abort the count by typing ESC will leave nethack waiting for another character to complete the two character sequence. Type a second ESC to finish cancelling such a count. At other prompts a single ESC suffices. %.lp \item[\ib{BIOS}] Use BIOS calls to update the screen display quickly and to read the keyboard (allowing the use of arrow keys to move) on machines with an IBM PC compatible BIOS ROM (default off, {\it OS/2, PC\/ {\rm and} ST NetHack\/} only). %.lp \item[\ib{flush}] (default off, {\it Amiga NetHack \/} only). %.lp \item[\ib{Macgraphics}] (default on, {\it Mac NetHack \/} only). %.lp \item[\ib{page\verb+_+wait}] (default off, {\it Mac NetHack \/} only). %.lp \item[\ib{rawio}] Force raw (non-cbreak) mode for faster output and more bulletproof input (MS-DOS sometimes treats `{\tt \^{}P}' as a printer toggle without it) (default off, {\it OS/2, PC\/ {\rm and} ST NetHack\/} only). Note: DEC Rainbows hang if this is turned on. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{soundcard}] (default off, {\it PC NetHack \/} only). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{subkeyvalue}] ({\it Win32 tty NetHack \/} only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate for international keyboard issues. OPTIONS=subkeyvalue:171/92 will return 92 to NetHack, if 171 was originally going to be returned. You can use multiple subkeyvalue statements in the config file if needed. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{video}] Set the video mode used ({\it PC\/ NetHack\/} only). Values are {\it autodetect\/}, {\it default\/}, or {\it vga\/}. Setting {\it vga\/} (or {\it autodetect\/} with vga hardware present) will cause the game to display tiles. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{videocolors}] \begin{sloppypar} Set the color palette for PC systems using NO\verb+_+TERMS (default 4-2-6-1-5-3-15-12-10-14-9-13-11, {\it PC\/ NetHack\/} only). The order of colors is red, green, brown, blue, magenta, cyan, bright.white, bright.red, bright.green, yellow, bright.blue, bright.magenta, and bright.cyan. Cannot be set with the `{\tt O}' command. \end{sloppypar} %.lp \item[\ib{videoshades}] Set the intensity level of the three gray scales available (default dark normal light, {\it PC\/ NetHack\/} only). If the game display is difficult to read, try adjusting these scales; if this does not correct the problem, try {\tt !color}. Cannot be set with the `{\tt O}' command. \elist %.nh 2 \subsection*{Regular Expressions} %.pg Regular expressions are normally POSIX extended regular expressions. It is possible to compile NetHack without regular expression support on a platform where there is no regular expression library. While this is not true of any modern platform, if your NetHack was built this way, patterns are instead glob patterns. %.hn 2 \subsection*{Configuring Autopickup Exceptions} %.pg You can further refine the behavior of the ``{\tt autopickup}'' option beyond what is available through the ``{\tt pickup\verb+_+types}'' option. %.pg By placing ``{\tt autopickup\verb+_+exception}'' lines in your configuration file, you can define patterns to be checked when the game is about to autopickup something. \blist{} %.lp \item[\ib{autopickup\verb+_+exception}] Sets an exception to the `{\it pickup\verb+_+types}' option. The {\it autopickup\verb+_+exception\/} option should be followed by a regular expression to be used as a pattern to match against the singular form of the description of an object at your location. In addition, some characters are treated specially if they occur as the first character in the pattern, specifically: %.sd %.si {\tt <} --- always pickup an object that matches rest of pattern;\\ {\tt >} --- never pickup an object that matches rest of pattern. %.ei %.ed A `never pickup' rule takes precedence over an `always pickup' rule if both match. %.lp "" Exceptions can be set with the `{\tt O}' command, but ones set that way will not be preserved across saves and restores. \elist %.lp "Here are some examples:" Here are some examples: \begin{verbatim} autopickup_exception="<*arrow" autopickup_exception=">*corpse" autopickup_exception=">* cursed*" \end{verbatim} %.pg The first example above will result in autopickup of any type of arrow. The second example results in the exclusion of any corpse from autopickup. The last example results in the exclusion of items known to be cursed from autopickup. %.lp %.hn 2 \subsection*{Configuring Message Types} %.pg You can change the way the messages are shown in the message area, when the message matches a user-defined pattern. %.pg In general, the config file entries to configure the message types look like this: \begin{verbatim} MSGTYPE=type "pattern" \end{verbatim} \blist{} %.lp \item[\ib{type}] how the message should be shown: %.sd %.si \\ {\tt show} --- show message normally.\\ {\tt hide} --- never show the message.\\ {\tt stop} --- wait for user with more-prompt.\\ {\tt norep} --- show the message once, but not again if no other message is shown in between. %.ei %.ed %.lp \item[\ib{pattern}] the pattern to match. The pattern should be a regular expression. \elist %.lp "" Here's an example of message types using NetHack's internal pattern matching facility: \begin{verbatim} MSGTYPE=stop "You feel hungry." MSGTYPE=hide "You displaced *." \end{verbatim} specifies that whenever a message ``You feel hungry'' is shown, the user is prompted with more-prompt, and a message matching ``You displaced \verb+<+something\verb+>+'' is not shown at all. %.lp The order of the defined MSGTYPE-lines is important; the last matching rule is used. Put the general case first, exceptions below them. %.pg %.lp %.hn 2 \subsection*{Configuring Menu Colors} %.pg Some platforms allow you to define colors used in menu lines when the line matches a user-defined pattern. At this time the tty, win32tty and win32gui support this. %.pg In general, the config file entries to configure the menu color mappings look like this: \begin{verbatim} MENUCOLOR="pattern"=color&attribute \end{verbatim} \blist{} %.lp \item[\ib{pattern}] the pattern to match; %.lp \item[\ib{color}] the color to use for lines matching the pattern; %.lp \item[\ib{attribute}] the attribute to use for lines matching the pattern. The attribute is optional, and if left out, you must also leave out the preceding ampersand. If no attribute is defined, no attribute is used. \elist %.lp "" The pattern should be a regular expression. %.lp "" Allowed colors are {\it black}, {\it red}, {\it green}, {\it brown}, {\it blue}, {\it magenta}, {\it cyan}, {\it gray}, {\it orange}, {\it lightgreen}, {\it yellow}, {\it lightblue}, {\it lightmagenta}, {\it lightcyan}, and {\it white}. %.lp "" Allowed attributes are {\it none}, {\it bold}, {\it dim}, {\it underline}, {\it blink}, and {\it inverse}. Note that the platform used may interpret the attributes any way it wants. %.lp "" Here's an example of menu colors using NetHack's internal pattern matching facility: \begin{verbatim} MENUCOLOR="* blessed *"=green MENUCOLOR="* cursed *"=red MENUCOLOR="* cursed *(being worn)"=red&underline \end{verbatim} specifies that any menu line with " blessed " contained in it will be shown in green color, lines with " cursed " will be shown in red, and lines with " cursed " followed by "(being worn)" on the same line will be shown in red color and underlined. You can have multiple MENUCOLOR entries in your config file, and the last MENUCOLOR-line in your config file that matches a menu line will be used for the line. %.pg Note that if you intend to have one or more color specifications match " uncursed ", you will probably want to turn the {\it implicit\verb+_+uncursed\/} option off so that all items known to be uncursed are actually displayed with the ``uncursed'' description. %.lp %.hn 2 \subsection*{Configuring User Sounds} %.pg Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. %.pg The following config file entries are relevant to mapping user sounds to messages: \blist{} %.lp \item[\ib{SOUNDDIR}] The directory that houses the sound files to be played. %.lp \item[\ib{SOUND}] An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: %.sd %.si {\tt MESG } --- message window mapping (the only one supported in 3.6);\\ {\tt pattern } --- the pattern to match;\\ {\tt sound file} --- the sound file to play;\\ {\tt volume } --- the volume to be set while playing the sound file. %.ei %.ed \elist %.lp "" The pattern should be a regular expression. %.lp %.hn 2 \subsection*{Configuring Status Hilites} %.pg Your copy of NetHack may have been compiled with support for {\it Status Hilites}. If so, you can customize your game display by setting thresholds to change the color or appearance of fields in the status display. For example, the following line in your config file will cause the hitpoints field to display in the color red if your hitpoints drop to or below a threshold of 30%: \begin{verbatim} OPTION=hilite_status: hitpoints/30%/red/normal \end{verbatim} %.pg For another example, the following line in your config file will cause wisdom to be displayed red if it drops and green if it rises. \begin{verbatim} OPTION=hilite_status: wisdom/updown/red/green \end{verbatim} You can adjust the display of the following status fields: %.sd \begin{center} \begin{tabular}{lll} %TABLE_START title & strength & dexterity\\ constitution & intelligence & wisdom\\ charisma & alignment & score\\ carrying-capacity & gold & power\\ power-max & experience-level & armor-class\\ HD & time & hunger\\ hitpoints & hitpoints-max & dungeon-level\\ experience & condition\\ %TABLE_END Do not delete this line. \end{tabular} \end{center} %.ed %.lp "" Allowed colors are {\it black}, {\it red}, {\it green}, {\it brown}, {\it blue}, {\it magenta}, {\it cyan}, {\it gray}, {\it orange}, {\it lightgreen}, {\it yellow}, {\it lightblue}, {\it lightmagenta}, {\it lightcyan}, and {\it white}. %.lp "" Behaviours can occur based on percentage thresholds, updown, or absolute values. The in-game options menu can help you determine the correct syntax for a config file. %.lp "" The whole feature can be disable by setting option {\it statushilites} off. %.lp %.hn 2 \subsection*{Modifying NetHack Symbols} %.pg NetHack can load entire symbol sets from the symbol file. %.pg The options that are used to select a particular symbol set from the symbol file are: \blist{} %.lp \item[\ib{symset}] Set the name of the symbol set that you want to load. {\it symbols\/}. %.lp \item[\ib{roguesymset}] Set the name of the symbol set that you want to load for display on the rogue level. \elist You can also override one or more symbols using the {\it SYMBOLS\/} config file option. Symbols are specified as {\it name:value\/} pairs. Note that {\it NetHack\/} escape-processes the {\it value\/} string in conventional C fashion. This means that `\verb+\+' is a prefix to take the following character literally. Thus `\verb+\+' needs to be represented as `\verb+\\+'. The special escape form `\verb+\m+' switches on the meta bit in the symbol value, and the `{\tt \^{}}' prefix causes the following character to be treated as a control character. { \small \begin{longtable}{lll} \caption[]{NetHack Symbols}\\ Default & Symbol Name & Description\\ \hline \hline \endhead \verb@ @ & S\verb+_+air & (air)\\ \verb@_@ & S\verb+_+altar & (altar)\\ \verb@"@ & S\verb+_+amulet & (amulet)\\ \verb@A@ & S\verb+_+angel & (angelic being)\\ \verb@a@ & S\verb+_+ant & (ant or other insect)\\ \verb@^@ & S\verb+_+anti\verb+_+magic\verb+_+trap & (anti-magic field)\\ \verb@[@ & S\verb+_+armor & (suit or piece of armor)\\ \verb@[@ & S\verb+_+armour & (suit or piece of armor)\\ \verb@^@ & S\verb+_+arrow\verb+_+trap & (arrow trap)\\ \verb@0@ & S\verb+_+ball & (iron ball)\\ \verb@#@ & S\verb+_+bars & (iron bars)\\ \verb@B@ & S\verb+_+bat & (bat or bird)\\ \verb@^@ & S\verb+_+bear\verb+_+trap & (bear trap)\\ \verb@-@ & S\verb+_+blcorn & (bottom left corner)\\ \verb@b@ & S\verb+_+blob & (blob)\\ \verb@+@ & S\verb+_+book & (spellbook)\\ \verb@)@ & S\verb+_+boomleft & (boomerang open left)\\ \verb@(@ & S\verb+_+boomright & (boomerang open right)\\ \verb@`@ & S\verb+_+boulder & (boulder)\\ \verb@-@ & S\verb+_+brcorn & (bottom right corner)\\ \verb@C@ & S\verb+_+centaur & (centaur)\\ \verb@_@ & S\verb+_+chain & (iron chain)\\ \verb@#@ & S\verb+_+cloud & (cloud)\\ \verb@c@ & S\verb+_+cockatrice & (cockatrice)\\ \verb@$@ & S\verb+_+coin & (pile of coins)\\ \verb@#@ & S\verb+_+corr & (corridor)\\ \verb@-@ & S\verb+_+crwall & (wall)\\ \verb@^@ & S\verb+_+dart\verb+_+trap & (dart trap)\\ \verb@&@ & S\verb+_+demon & (major demon)\\ \verb@*@ & S\verb+_+digbeam & (dig beam)\\ \verb@>@ & S\verb+_+dnladder & (ladder down)\\ \verb@>@ & S\verb+_+dnstair & (staircase down)\\ \verb@d@ & S\verb+_+dog & (dog or other canine)\\ \verb@D@ & S\verb+_+dragon & (dragon)\\ \verb@;@ & S\verb+_+eel & (sea monster)\\ \verb@E@ & S\verb+_+elemental & (elemental)\\ \verb@/@ & S\verb+_+explode1 & (explosion top left)\\ \verb@-@ & S\verb+_+explode2 & (explosion top center)\\ \verb@\@ & S\verb+_+explode3 & (explosion top right)\\ \verb@|@ & S\verb+_+explode4 & (explosion middle left)\\ \verb@ @ & S\verb+_+explode5 & (explosion middle center)\\ \verb@|@ & S\verb+_+explode6 & (explosion middle right)\\ \verb@\@ & S\verb+_+explode7 & (explosion bottom left)\\ \verb@-@ & S\verb+_+explode8 & (explosion bottom center)\\ \verb@/@ & S\verb+_+explode9 & (explosion bottom right)\\ \verb@e@ & S\verb+_+eye & (eye or sphere)\\ \verb@^@ & S\verb+_+falling\verb+_+rock\verb+_+trap & (falling rock trap)\\ \verb@f@ & S\verb+_+feline & (cat or other feline)\\ \verb@^@ & S\verb+_+fire\verb+_+trap & (fire trap)\\ \verb@!@ & S\verb+_+flashbeam & (flash beam)\\ \verb@%@ & S\verb+_+food & (piece of food)\\ \verb@{@ & S\verb+_+fountain & (fountain)\\ \verb@F@ & S\verb+_+fungus & (fungus or mold)\\ \verb@*@ & S\verb+_+gem & (gem or rock)\\ \verb@ @ & S\verb+_+ghost & (ghost)\\ \verb@H@ & S\verb+_+giant & (giant humanoid)\\ \verb@G@ & S\verb+_+gnome & (gnome)\\ \verb@'@ & S\verb+_+golem & (golem)\\ \verb@|@ & S\verb+_+grave & (grave)\\ \verb@g@ & S\verb+_+gremlin & (gremlin)\\ \verb@-@ & S\verb+_+hbeam & (wall)\\ \verb@#@ & S\verb+_+hcdbridge & (horizontal raised drawbridge)\\ \verb@+@ & S\verb+_+hcdoor & (closed door)\\ \verb@.@ & S\verb+_+hodbridge & (horizontal lowered drawbridge)\\ \verb@|@ & S\verb+_+hodoor & (open door)\\ \verb@^@ & S\verb+_+hole & (hole)\\ \verb~@~ & S\verb+_+human & (human or elf)\\ \verb@h@ & S\verb+_+humanoid & (humanoid)\\ \verb@-@ & S\verb+_+hwall & (horizontal wall)\\ \verb@.@ & S\verb+_+ice & (ice)\\ \verb@i@ & S\verb+_+imp & (imp or minor demon)\\ \verb@J@ & S\verb+_+jabberwock & (jabberwock)\\ \verb@j@ & S\verb+_+jelly & (jelly)\\ \verb@k@ & S\verb+_+kobold & (kobold)\\ \verb@K@ & S\verb+_+kop & (Keystone Kop)\\ \verb@^@ & S\verb+_+land\verb+_+mine & (land mine)\\ \verb@}@ & S\verb+_+lava & (molten lava)\\ \verb@l@ & S\verb+_+leprechaun & (leprechaun)\\ \verb@^@ & S\verb+_+level\verb+_+teleporter & (level teleporter)\\ \verb@L@ & S\verb+_+lich & (lich)\\ \verb@y@ & S\verb+_+light & (light)\\ \verb@#@ & S\verb+_+litcorr & (lit corridor)\\ \verb@:@ & S\verb+_+lizard & (lizard)\\ \verb@\@ & S\verb+_+lslant & (wall)\\ \verb@^@ & S\verb+_+magic\verb+_+portal & (magic portal)\\ \verb@^@ & S\verb+_+magic\verb+_+trap & (magic trap)\\ \verb@m@ & S\verb+_+mimic & (mimic)\\ \verb@]@ & S\verb+_+mimic\verb+_+def & (mimic)\\ \verb@M@ & S\verb+_+mummy & (mummy)\\ \verb@N@ & S\verb+_+naga & (naga)\\ \verb@.@ & S\verb+_+ndoor & (doorway)\\ \verb@n@ & S\verb+_+nymph & (nymph)\\ \verb@O@ & S\verb+_+ogre & (ogre)\\ \verb@o@ & S\verb+_+orc & (orc)\\ \verb@p@ & S\verb+_+piercer & (piercer)\\ \verb@^@ & S\verb+_+pit & (pit)\\ \verb@#@ & S\verb+_+poisoncloud & (poison cloud)\\ \verb@^@ & S\verb+_+polymorph\verb+_+trap & (polymorph trap)\\ \verb@}@ & S\verb+_+pool & (water)\\ \verb@!@ & S\verb+_+potion & (potion)\\ \verb@P@ & S\verb+_+pudding & (pudding or ooze)\\ \verb@q@ & S\verb+_+quadruped & (quadruped)\\ \verb@Q@ & S\verb+_+quantmech & (quantum mechanic)\\ \verb@=@ & S\verb+_+ring & (ring)\\ \verb@`@ & S\verb+_+rock & (boulder or statue)\\ \verb@r@ & S\verb+_+rodent & (rodent)\\ \verb@^@ & S\verb+_+rolling\verb+_+boulder\verb+_+trap & (rolling boulder trap)\\ \verb@.@ & S\verb+_+room & (floor of a room)\\ \verb@/@ & S\verb+_+rslant & (wall)\\ \verb@^@ & S\verb+_+rust\verb+_+trap & (rust trap)\\ \verb@R@ & S\verb+_+rustmonst & (rust monster or disenchanter)\\ \verb@?@ & S\verb+_+scroll & (scroll)\\ \verb@#@ & S\verb+_+sink & (sink)\\ \verb@^@ & S\verb+_+sleeping\verb+_+gas\verb+_+trap & (sleeping gas trap)\\ \verb@S@ & S\verb+_+snake & (snake)\\ \verb@s@ & S\verb+_+spider & (arachnid or centipede)\\ \verb@^@ & S\verb+_+spiked\verb+_+pit & (spiked pit)\\ \verb@^@ & S\verb+_+squeaky\verb+_+board & (squeaky board)\\ \verb@0@ & S\verb+_+ss1 & (magic shield 1 of 4)\\ \verb@#@ & S\verb+_+ss2 & (magic shield 2 of 4)\\ \verb+@+ & S\verb+_+ss3 & (magic shield 3 of 4)\\ \verb@*@ & S\verb+_+ss4 & (magic shield 4 of 4)\\ \verb@^@ & S\verb+_+statue\verb+_+trap & (statue trap)\\ \verb@ @ & S\verb+_+stone & (dark part of a room)\\ \verb@-@ & S\verb+_+sw\verb+_+bc & (swallow bottom center)\\ \verb@\@ & S\verb+_+sw\verb+_+bl & (swallow bottom left)\\ \verb@/@ & S\verb+_+sw\verb+_+br & (swallow bottom right )\\ \verb@|@ & S\verb+_+sw\verb+_+ml & (swallow middle left)\\ \verb@|@ & S\verb+_+sw\verb+_+mr & (swallow middle right)\\ \verb@-@ & S\verb+_+sw\verb+_+tc & (swallow top center)\\ \verb@/@ & S\verb+_+sw\verb+_+tl & (swallow top left)\\ \verb@\@ & S\verb+_+sw\verb+_+tr & (swallow top right)\\ \verb@-@ & S\verb+_+tdwall & (wall)\\ \verb@^@ & S\verb+_+teleportation\verb+_+trap & (teleportation trap)\\ \verb@\@ & S\verb+_+throne & (opulent throne)\\ \verb@-@ & S\verb+_+tlcorn & (top left corner)\\ \verb@|@ & S\verb+_+tlwall & (wall)\\ \verb@(@ & S\verb+_+tool & (useful item (pick-axe\, key\, lamp...))\\ \verb@^@ & S\verb+_+trap\verb+_+door & (trap door)\\ \verb@t@ & S\verb+_+trapper & (trapper or lurker above)\\ \verb@-@ & S\verb+_+trcorn & (top right corner)\\ \verb@#@ & S\verb+_+tree & (tree)\\ \verb@T@ & S\verb+_+troll & (troll)\\ \verb@|@ & S\verb+_+trwall & (wall)\\ \verb@-@ & S\verb+_+tuwall & (wall)\\ \verb@U@ & S\verb+_+umber & (umber hulk)\\ \verb@u@ & S\verb+_+unicorn & (unicorn or horse)\\ \verb@<@ & S\verb+_+upladder & (ladder up)\\ \verb@<@ & S\verb+_+upstair & (staircase up)\\ \verb@V@ & S\verb+_+vampire & (vampire)\\ \verb@|@ & S\verb+_+vbeam & (wall)\\ \verb@#@ & S\verb+_+vcdbridge & (vertical raised drawbridge)\\ \verb@+@ & S\verb+_+vcdoor & (closed door)\\ \verb@.@ & S\verb+_+venom & (splash of venom)\\ \verb@^@ & S\verb+_+vibrating\verb+_+square & (vibrating square)\\ \verb@.@ & S\verb+_+vodbridge & (vertical lowered drawbridge)\\ \verb@-@ & S\verb+_+vodoor & (open door)\\ \verb@v@ & S\verb+_+vortex & (vortex)\\ \verb@|@ & S\verb+_+vwall & (vertical wall)\\ \verb@/@ & S\verb+_+wand & (wand)\\ \verb@}@ & S\verb+_+water & (water)\\ \verb@)@ & S\verb+_+weapon & (weapon)\\ \verb@"@ & S\verb+_+web & (web)\\ \verb@w@ & S\verb+_+worm & (worm)\\ \verb@~@ & S\verb+_+worm\verb+_+tail & (long worm tail)\\ \verb@W@ & S\verb+_+wraith & (wraith)\\ \verb@x@ & S\verb+_+xan & (xan or other mythical/fantastic insect)\\ \verb@X@ & S\verb+_+xorn & (xorn)\\ \verb@Y@ & S\verb+_+yeti & (apelike creature)\\ \verb@Z@ & S\verb+_+zombie & (zombie)\\ \verb@z@ & S\verb+_+zruty & (zruty) \end{longtable}% } %.lp %.hn 2 \subsection*{Configuring NetHack for Play by the Blind} %.pg NetHack can be set up to use only standard ASCII characters for making maps of the dungeons. This makes the MS-DOS versions of NetHack completely accessible to the blind who use speech and/or Braille access technologies. Players will require a good working knowledge of their screen-reader's review features, and will have to know how to navigate horizontally and vertically character by character. They will also find the search capabilities of their screen-readers to be quite valuable. Be certain to examine this Guidebook before playing so you have an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your character since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. %.pg While it is not difficult for experienced users to edit the {\it defaults.nh\/} file to accomplish this, novices may find this task somewhat daunting. Included within the symbol file of all official distributions of NetHack is a symset called {\it NHAccess\/}. Selecting that symset in your configuration file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings via {\it SYMBOLS=\/} in your configuration file to better suit your preferences. The most crucial settings to make the game accessible are: %.pg \blist{} %.lp \item[\ib{symset:NHAccess}] Load a symbol set appropriate for use by blind players. %.lp \item[\ib{roguesymset:NHAccess}] Load a symbol set for the rogue level that is appropriate for use by blind players. %.lp \item[\ib{menustyle:traditional}] This will assist in the interface to speech synthesizers. %.lp \item[\ib{number\verb+_+pad}] A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number\verb+_+pad option and use the traditional Rogue-like commands. \elist %.hn2 \subsection*{Global Configuration for System Administrators} %.pg If NetHack is compiled with the SYSCF option, a system administrator should set up a global configuration; this is a file in the same format as the traditional per-user configuration file (see above). This file should be named sysconf and placed in the same directory as the other NetHack support files. The options recognized in this file are listed below. Any option not set uses a compiled-in default (which may not be appropriate for your system). %.pg \blist{} %.lp \item[\ib{WIZARDS}] A space-separated list of user name who are allowed to play in wizard mode (the debugging mode, not the magic-useing role). A value of a single asterisk (*) allows anyone to start a game in wizard mode. %.lp \item[\ib{SHELLERS}] A list of users who are allowed to use the shell escape command (!). The syntax is the same as WIZARDS. %.lp \item[\ib{EXPLORERS}] A list of users who are allowed to use the explore mode. The syntax is the same as WIZARDS. %.lp \item[\ib{MAXPLAYERS}] Limit the maximum number of games taht can be running at the same time. %.lp \item[\ib{SUPPORT}] A string explainign how to get local support (no default value). %.lp \item[\ib{RECOVER}] A string explaining how to recover a game on this system (no default value). %.lp \item[\ib{SEDUCE}] 0 or 1 to disable or enable, respectively, the SEDUCE option (see the source) for details on this function. %.lp \item[\ib{CHECK\verb+_+SAVE\verb+_+UID}] 0 or 1 to disable or enable, respectively, the UID checking for savefiles. \elist %.pg The following options affect the score file: \blist {} %.pg %.lp \item[\ib{PERSMAX}] Maximum number of entries for one person %.lp \item[\ib{ENTRYMAX}] Maximum number of entries in the score file %.lp \item[\ib{POINTSMIN}] Minimum number of points to get an entry in the score file. %.lp \item[\ib{PERS\verb+_+IS\verb+_+UID}] 0 or 1 to use user names or numeric userids, respectively, to identify unique people for the score file \elist %.hn 1 \section{Scoring} %.pg {\it NetHack\/} maintains a list of the top scores or scorers on your machine, depending on how it is set up. In the latter case, each account on the machine can post only one non-winning score on this list. If you score higher than someone else on this list, or better your previous score, you will be inserted in the proper place under your current name. How many scores are kept can also be set up when {\it NetHack\/} is compiled. %.pg Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will only hear about 90\,\% of your gold when your corpse is discovered (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. %.pg If you just want to see what the current top players/games list is, you can type \begin{verbatim} nethack -s all \end{verbatim} on most versions. %.hn 1 \section{Explore mode} %.pg {\it NetHack\/} is an intricate and difficult game. Novices might falter in fear, aware of their ignorance of the means to survive. Well, fear not. Your dungeon comes equipped with an ``explore'' or ``discovery'' mode that enables you to keep old save files and cheat death, at the paltry cost of not getting on the high score list. %.pg There are two ways of enabling explore mode. One is to start the game with the {\tt -X} command-line switch or with the {\it playmode:explore\/} option. The other is to issue the `{\tt \#exploremode}' extended command while already playing the game. Starting a new game in explore mode provides your character with a wand of wishing in initial inventory; switching during play does not. The other benefits of explore mode are left for the trepid reader to discover. %.pg %.hn 2 \subsection*{Debug mode} %.pg Debug mode, also known as wizard mode, is undocumented aside from this brief description. It is intended for tracking down problems within the program rather than to provide god-like powers to your character, and players who attempt debugging are expected to figure out how to use it themselves. It is initiated by starting the game with the {\tt -D} command-line switch or with the {\it playmode:debug\/} option. %.pg For some systems, the player must be logged in under a particular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the {\it Wizard\/} role). And on any system, the program might have been configured to omit debug mode entirely. Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. %.hn \section{Credits} %.pg The original % {\it hack\/} game was modeled on the Berkeley %.ux UNIX {\it rogue\/} game. Large portions of this paper were shamelessly cribbed from % {\it A Guide to the Dungeons of Doom}, by Michael C. Toy and Kenneth C. R. C. Arnold. Small portions were adapted from {\it Further Exploration of the Dungeons of Doom}, by Ken Arromdee. %.pg {\it NetHack\/} is the product of literally dozens of people's work. Main events in the course of the game development are described below: %.pg \bigskip \nd {\it Jay Fenlason\/} wrote the original {\it Hack\/} with help from {\it Kenny Woodland}, {\it Mike Thome}, and {\it Jon Payne}. %.pg \medskip \nd {\it Andries Brouwer\/} did a major re-write, transforming {\it Hack\/} into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for UNIX machines to the Usenet. %.pg \medskip \nd {\it Don G. Kneller\/} ported {\it Hack\/} 1.0.3 to Microsoft C and MS-DOS, producing {\it PC Hack\/} 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6). %.pg \medskip \nd {\it R. Black\/} ported {\it PC Hack\/} 3.51 to Lattice C and the Atari 520/1040ST, producing {\it ST Hack\/} 1.03. %.pg \medskip \nd {\it Mike Stephenson\/} merged these various versions back together, incorporating many of the added features, and produced {\it NetHack\/} version 1.4. He then coordinated a cast of thousands in enhancing and debugging {\it NetHack\/} 1.4 and released {\it NetHack\/} versions 2.2 and 2.3. %.pg \medskip \nd Later, Mike coordinated a major rewrite of the game, heading a team which included {\it Ken Arromdee}, {\it Jean-Christophe Collet}, {\it Steve Creps}, {\it Eric Hendrickson}, {\it Izchak Miller}, {\it Eric S. Raymond}, {\it John Rupley}, {\it Mike Threepoint}, and {\it Janet Walz}, to produce {\it NetHack\/} 3.0c. %.pg \medskip \nd {\it NetHack\/} 3.0 was ported to the Atari by {\it Eric R. Smith}, to OS/2 by {\it Timo Hakulinen}, and to VMS by {\it David Gentzel}. The three of them and {\it Kevin Darcy\/} later joined the main development team to produce subsequent revisions of 3.0. %.pg \medskip \nd {\it Olaf Seibert\/} ported {\it NetHack\/} 2.3 and 3.0 to the Amiga. {\it Norm Meluch}, {\it Stephen Spackman\/} and {\it Pierre Martineau\/} designed overlay code for {\it PC NetHack\/} 3.0. {\it Johnny Lee\/} ported {\it NetHack\/} 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. %.pg \medskip \nd Headed by {\it Mike Stephenson\/} and coordinated by {\it Izchak Miller\/} and {\it Janet Walz}, the development team which now included {\it Ken Arromdee}, {\it David Cohrs}, {\it Jean-Christophe Collet}, {\it Kevin Darcy}, {\it Matt Day}, {\it Timo Hakulinen}, {\it Steve Linhart}, {\it Dean Luick}, {\it Pat Rankin}, {\it Eric Raymond}, and {\it Eric Smith\/} undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced {\it NetHack\/} 3.1. %.pg \medskip \nd {\it Ken Lorber}, {\it Gregg Wonderly\/} and {\it Greg Olson}, with help from {\it Richard Addison}, {\it Mike Passaretti}, and {\it Olaf Seibert}, developed {\it NetHack\/} 3.1 for the Amiga. %.pg \medskip \nd {\it Norm Meluch\/} and {\it Kevin Smolkowski}, with help from {\it Carl Schelin}, {\it Stephen Spackman}, {\it Steve VanDevender}, and {\it Paul Winner}, ported {\it NetHack\/} 3.1 to the PC. %.pg \medskip \nd {\it Jon W\{tte} and {\it Hao-yang Wang}, with help from {\it Ross Brown}, {\it Mike Engber}, {\it David Hairston}, {\it Michael Hamel}, {\it Jonathan Handler}, {\it Johnny Lee}, {\it Tim Lennan}, {\it Rob Menke}, and {\it Andy Swanson}, developed {\it NetHack\/} 3.1 for the Macintosh, porting it for MPW. Building on their development, {\it Barton House} added a Think C port. %.pg \medskip \nd {\it Timo Hakulinen\/} ported {\it NetHack\/} 3.1 to OS/2. {\it Eric Smith\/} ported {\it NetHack\/} 3.1 to the Atari. {\it Pat Rankin}, with help from {\it Joshua Delahunty}, was responsible for the VMS version of {\it NetHack\/} 3.1. {\it Michael Allison} ported {\it NetHack\/} 3.1 to Windows NT. %.pg \medskip \nd {\it Dean Luick}, with help from {\it David Cohrs}, developed {\it NetHack\/} 3.1 for X11. {\it Warwick Allison} wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. %.pg \medskip \nd The 3.2 development team, comprised of {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Steve Creps}, {\it Kevin Darcy}, {\it Timo Hakulinen}, {\it Steve Linhart}, {\it Dean Luick}, {\it Pat Rankin}, {\it Eric Smith}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}, released version 3.2 in April of 1996. %.pg \medskip \nd Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team remained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, {\it Dr. Izchak Miller}, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. %.pg \medskip During the lifespan of {\it NetHack\/} 3.1 and 3.2, several enthusiasts of the game added their own modifications to the game and made these ``variants'' publicly available: %.pg \medskip {\it Tom Proudfoot} and {\it Yuval Oren} created {\it NetHack++}, which was quickly renamed {\it NetHack$--$}. Working independently, {\it Stephen White} wrote {\it NetHack Plus}. {\it Tom Proudfoot} later merged {\it NetHack Plus} and his own {\it NetHack$--$} to produce {\it SLASH}. {\it Larry Stewart-Zerba} and {\it Warwick Allison} improved the spell casting system with the Wizard Patch. {\it Warwick Allison} also ported NetHack to use the Qt interface. %.pg \medskip {\it Warren Cheung} combined {\it SLASH} with the Wizard Patch to produce {\it Slash'em\/}, and with the help of {\it Kevin Hugo}, added more features. Kevin later joined the DevTeam and incorporated the best of these ideas into NetHack 3.3. %.pg \medskip The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. %.pg \medskip The 3.3 development team, consisting of {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Steve Creps}, {\it Kevin Darcy}, {\it Timo Hakulinen}, {\it Kevin Hugo}, {\it Steve Linhart}, {\it Ken Lorber}, {\it Dean Luick}, {\it Pat Rankin}, {\it Eric Smith}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. %.pg \medskip Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in preference to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. %.pg \medskip The 3.4 development team initially consisted of {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Kevin Hugo}, {\it Ken Lorber}, {\it Dean Luick}, {\it Pat Rankin}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}, with {\it Warwick Allison} joining just before the release of NetHack 3.4.0 in March 2002. %.pg \medskip As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that {\it NetHack\/} runs on: %.pg \medskip \nd{\it Pat Rankin} maintained 3.4 for VMS. %.pg \medskip \nd {\it Michael Allison} maintained NetHack 3.4 for the MS-DOS platform. {\it Paul Winner} and {\it Yitzhak Sapir} provided encouragement. %.pg \medskip \nd {\it Dean Luick}, {\it Mark Modrall}, and {\it Kevin Hugo} maintained and enhanced the Macintosh port of 3.4. %.pg \medskip \nd {\it Michael Allison}, {\it David Cohrs}, {\it Alex Kompel}, {\it Dion Nicolaas}, and {\it Yitzhak Sapir} maintained and enhanced 3.4 for the Microsoft Windows platform. {\it Alex Kompel} contributed a new graphical interface for the Windows port. {\it Alex Kompel} also contributed a Windows CE port for 3.4.1. %.pg \medskip \nd {\it Ron Van Iwaarden} was the sole maintainer of NetHack for OS/2 the past several releases. Unfortunately Ron's last OS/2 machine stopped working in early 2006. A great many thanks to Ron for keeping NetHack alive on OS/2 all these years. %.pg \medskip \nd {\it Janne Salmij\"{a}rvi} and {\it Teemu Suikki} maintained and enhanced the Amiga port of 3.4 after {\it Janne Salmij\"{a}rvi} resurrected it for 3.3.1. %.pg \medskip \nd {\it Christian ``Marvin'' Bressler} maintained 3.4 for the Atari after he resurrected it for 3.3.1. %.pg \medskip The release of NetHack 3.4.3 in December 2003 marked the beginning of a long release hiatus. 3.4.3 proved to be a remarkably stable version that provided continued enjoyment by the community for more than a decade. The devteam slowly and quietly continued to work on the game behind the scenes during the tenure of 3.4.3. It was during that same period that several new variants emerged within the NetHack community. Notably sporkhack by Derek S. Ray, unnethack by Patric Mueller, nitrohack and its successors originally by Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. Some of those variants continue to be developed, maintained, and enjoyed by the community to this day. %.pg \medskip At the beginning of development for what would eventually get released as 3.6.0, the development team consisted of {\it Warwick Allison}, {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Ken Lorber}, {\it Dean Luick}, {\it Pat Rankin}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}. Leading up to the release of 3.6.0 in early 2015, new members {\it Sean Hunt}, {\it Pasi Kallinen}, and {\it Derek S. Ray} joined the NetHack development team. %.pg \medskip In September 2014, an interim snapshot of the code under development was released publicly by other parties. Since that code was a work-in-progress and had not gone through the process of debugging it as a suitable release, it was decided that the version numbers present on that code snapshot would be retired and never used in an official NetHack release. An announcement was posted on the devteam's official nethack.org website to that effect, stating that there would never be a 3.4.4, 3.5, or 3.5.0 official release version. %.pg \medskip In November 2014, preparation began for the release of NetHack 3.6. The 3.6 version merges work done by the development team since the previous release with some of the beloved community patches. Many bugs were fixed and a large amount of code was restructured. %.pg \medskip The development team, as well as {\it Steve VanDevender} and {\it Kevin Smolkowski} ensured that NetHack 3.6.0 continued to operate on various Unix flavors and maintained the X11 interface. %.pg {\it Ken Lorber}, {\it Haoyang Wang}, {\it Pat Rankin}, and {\it Dean Luick} maintained the port of NetHack 3.6.0 for Mac. %.pg \medskip {\it Michael Allison}, {\it Derek S. Ray}, {\it Yitzhak Sapir}, {\it Alex Kompel}, and {\it Dion Nicolaas} maintained the port of NetHack 3.6.0 for Microsoft Windows. %.pg \medskip \nd The official NetHack web site is maintained by {\it Ken Lorber} at {\catcode`\#=11 \special{html:}} http:{\tt /}{\tt /}www.nethack.org{\tt /}. {\catcode`\#=11 \special{html:}} %.pg %.hn 2 \subsection*{Shout Outs} \nd The devteam would like to give a special "shout-out" to thank the generous people primarily responsible for the public NetHack servers available for playing the game at nethack.alt.org and devnull.net. In addition to providing a way for the public to play a game of NetHack from almost anywhere, they have hosted annual NetHack tournaments for many, many years. %.pg \nd On behalf of the NetHack community, thank you very much to {\it M. Drew Streib}, {\it Pasi Kallinen} and {\it Robin Bandy}. \clearpage %.hn \section*{Dungeoneers} %.pg \nd From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: %.sd \begin{center} \begin{tabular}{llll} %TABLE_START Adam Aronow & Frederick Roeber & Kevin Smolkowski & Richard Beigel\\ Alex Kompel & Gil Neiger & Kevin Sweet & Richard P. Hughey\\ Andreas Dorn & Greg Laskin & Lars Huttar & Rob Menke\\ Andy Church & Greg Olson & Leon Arnott & Robin Bandy\\ Andy Swanson & Gregg Wonderly & M. Drew Streib & Robin Johnson\\ Ari Huttunen & Hao-yang Wang & Malcolm Ryan & Roderick Schertler\\ Barton House & Helge Hafting & Mark Gooderum & Roland McGrath\\ Benson I. Margulies & Irina Rempt-Drijfhout & Mark Modrall & Ron Van Iwaarden\\ Bill Dyer & Izchak Miller & Marvin Bressler & Ronnen Miller\\ Boudewijn Waijers & J. Ali Harlow & Matthew Day & Ross Brown\\ Bruce Cox & Janet Walz & Merlyn LeRoy & Sascha Wostmann\\ Bruce Holloway & Janne Salmij\"{a}rvi & Michael Allison & Scott Bigham\\ Bruce Mewborne & Jean-Christophe Collet & Michael Feir & Scott R. Turner\\ Carl Schelin & Jeff Bailey & Michael Hamel & Sean Hunt\\ Chris Russo & Jochen Erwied & Michael Sokolov & Stephen Spackman\\ David Cohrs & John Kallen & Mike Engber & Stefan Thielscher\\ David Damerell & John Rupley & Mike Gallop & Stephen White\\ David Gentzel & John S. Bien & Mike Passaretti & Steve Creps\\ David Hairston & Johnny Lee & Mike Stephenson & Steve Linhart\\ Dean Luick & Jon W\{tte & Mikko Juola & Steve VanDevender\\ Del Lamb & Jonathan Handler & Nathan Eady & Teemu Suikki\\ Derek S. Ray & Joshua Delahunty & Norm Meluch & Tim Lennan\\ Deron Meranda & Keizo Yamamoto & Olaf Seibert & Timo Hakulinen\\ Dion Nicolaas & Ken Arnold & Pasi Kallinen & Tom Almy\\ Dylan O'Donnell & Ken Arromdee & Pat Rankin & Tom West\\ Eric Backus & Ken Lorber & Paul Winner & Warren Cheung\\ Eric Hendrickson & Ken Washikita & Pierre Martineau & Warwick Allison\\ Eric R. Smith & Kevin Darcy & Ralf Brown & Yitzhak Sapir\\ Eric S. Raymond & Kevin Hugo & Ray Chason\\ Erik Andersen & Kevin Sitze & Richard Addison %TABLE_END Do not delete this line. \end{tabular} \end{center} %.ed \clearpage %\vfill %\begin{flushleft} %\small %Microsoft and MS-DOS are registered trademarks of Microsoft Corporation.\\ %%%Don't need next line if a UNIX macro automatically inserts footnotes. %UNIX is a registered trademark of AT\&T.\\ %Lattice is a trademark of Lattice, Inc.\\ %Atari and 1040ST are trademarks of Atari, Inc.\\ %AMIGA is a trademark of Commodore-Amiga, Inc.\\ %%.sm %Brand and product names are trademarks or registered trademarks %of their respective holders. %\end{flushleft} \end{document} nethack-3.6.0/doc/Guidebook.txt0000664000076400007660000056776312631206535015406 0ustar paxedpaxed A Guide to the Mazes of Menace (Guidebook for NetHack) Original version - Eric S. Raymond (Edited and expanded for 3.6 by Mike Stephenson and others) Preface - Version 3.6 This version of the game is special in a particular way. Near the end of the development of 3.6, one of the significant inspirations for many of the humorous and fun features found in the game, author Terry Pratchett, passed away. We have dedicated this version of the game in his memory. 1. Introduction Recently, you have begun to find yourself unfulfilled and distant in your daily occupation. Strange dreams of prospecting, stealing, crusading, and combat have haunted you in your sleep for many months, but you aren't sure of the reason. You wonder whether you have in fact been having those dreams all your life, and somehow managed to forget about them until now. Some nights you awaken suddenly and cry out, terrified at the vivid recollec- tion of the strange and powerful creatures that seem to be lurk- ing behind every corner of the dungeon in your dream. Could these details haunting your dreams be real? As each night pass- es, you feel the desire to enter the mysterious caverns near the ruins grow stronger. Each morning, however, you quickly put the idea out of your head as you recall the tales of those who en- tered the caverns before you and did not return. Eventually you can resist the yearning to seek out the fantastic place in your dreams no longer. After all, when other adventurers came back this way after spending time in the caverns, they usually seemed better off than when they passed through the first time. And who was to say that all of those who did not return had not just kept going? Asking around, you hear about a bauble, called the Amulet of Yendor by some, which, if you can find it, will bring you great wealth. One legend you were told even mentioned that the one who finds the amulet will be granted immortality by the gods. The amulet is rumored to be somewhere beyond the Valley of Gehennom, deep within the Mazes of Menace. Upon hearing the legends, you immediately realize that there is some profound and undiscovered reason that you are to descend into the caverns and seek out that amulet of which they spoke. Even if the rumors of the amulet's NetHack Guidebook 1 NetHack Guidebook 2 powers are untrue, you decide that you should at least be able to sell the tales of your adventures to the local minstrels for a tidy sum, especially if you encounter any of the terrifying and magical creatures of your dreams along the way. You spend one last night fortifying yourself at the local inn, becoming more and more depressed as you watch the odds of your success being posted on the inn's walls getting lower and lower. In the morning you awake, collect your belongings, and set off for the dungeon. After several days of uneventful travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morn- ing, you gather your gear, eat what may be your last meal out- side, and enter the dungeon... 2. What is going on here? You have just begun a game of NetHack. Your goal is to grab as much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. Your abilities and strengths for dealing with the hazards of adventure will vary with your background and training: Archeologists understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start equipped with the tools for a proper scientific expedition. Barbarians are warriors out of the hinterland, hardened to battle. They begin their quests with naught but uncommon strength, a trusty hauberk, and a great two-handed sword. Cavemen and Cavewomen start with exceptional strength but, unfortunately, with neolithic weapons. Healers are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anes- thetize, and neutralize poisons; and with their instruments, they can divine a being's state of health or sickness. Their medical practice earns them quite reasonable amounts of money, with which they enter the dungeon. Knights are distinguished from the common skirmisher by their devotion to the ideals of chivalry and by the surpassing excellence of their armor. Monks are ascetics, who by rigorous practice of physical and mental disciplines have become capable of fighting as effectively without weapons as with. They wear no armor but make up for it with increased mobility. NetHack 3.6 December 7, 2015 NetHack Guidebook 3 Priests and Priestesses are clerics militant, crusaders ad- vancing the cause of righteousness with arms, armor, and arts thaumaturgic. Their ability to commune with deities via prayer occasionally extricates them from peril, but can also put them in it. Rangers are most at home in the woods, and some say slightly out of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. Rogues are agile and stealthy thieves, with knowledge of locks, traps, and poisons. Their advantage lies in surprise, which they employ to great advantage. Samurai are the elite warriors of feudal Nippon. They are lightly armored and quick, and wear the dai-sho, two swords of the deadliest keenness. Tourists start out with lots of gold (suitable for shopping with), a credit card, lots of food, some maps, and an expensive camera. Most monsters don't like being photographed. Valkyries are hardy warrior women. Their upbringing in the harsh Northlands makes them strong, inures them to extremes of cold, and instills in them stealth and cunning. Wizards start out with a knowledge of magic, a selection of magical items, and a particular affinity for dweomercraft. Al- though seemingly weak and easy to overcome at first sight, an ex- perienced Wizard is a deadly foe. You may also choose the race of your character: Dwarves are smaller than humans or elves, but are stocky and solid individuals. Dwarves' most notable trait is their great expertise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. Elves are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. Gnomes are smaller than but generally similar to dwarves. Gnomes are known to be expert miners, and it is known that a se- cret underground mine complex built by this race exists within the Mazes of Menace, filled with both riches and danger. Humans are by far the most common race of the surface world, and are thus the norm to which other races are often compared. Although they have no special abilities, they can succeed in any role. Orcs are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves NetHack 3.6 December 7, 2015 NetHack Guidebook 4 with a passion unequalled, and will go out of their way to kill one at any opportunity. The armor and weapons fashioned by the Orcs are typically of inferior quality. 3. What do all those things on the screen mean? On the screen is kept a map of where you have been and what you have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. When NetHack's ancestor rogue first appeared, its screen orientation was almost unique among computer fantasy games. Since then, screen orientation has become the norm rather than the exception; NetHack continues this fine tradition. Unlike text adventure games that accept commands in pseudo-English sen- tences and explain the results in words, NetHack commands are all one or two keystrokes and the results are displayed graphically on the screen. A minimum screen size of 24 lines by 80 columns is recommended; if the screen is larger, only a 21x80 section will be used for the map. NetHack can even be played by blind players, with the assis- tance of Braille readers or speech synthesisers. Instructions for configuring NetHack for the blind are included later in this document. NetHack generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game de- spite having won several times. NetHack offers a variety of display options. The options available to you will vary from port to port, depending on the capabilities of your hardware and software, and whether various compile-time options were enabled when your executable was creat- ed. The three possible display options are: a monochrome charac- ter interface, a color character interface, and a graphical in- terface using small pictures called tiles. The two character in- terfaces allow fonts with other characters to be substituted, but the default assignments use standard ASCII characters to repre- sent everything. There is no difference between the various dis- play options with respect to game play. Because we cannot repro- duce the tiles or colors in the Guidebook, and because it is com- mon to all ports, we will use the default ASCII characters from the monochrome character display when referring to things you might see on the screen during your game. In order to understand what is going on in NetHack, first you must understand what NetHack is doing with the screen. The NetHack screen replaces the ``You see ...'' descriptions of text adventure games. Figure 1 is a sample of what a NetHack screen might look like. The way the screen looks for you depends on your platform. NetHack 3.6 December 7, 2015 NetHack Guidebook 5 -------------------------------------------------------------------- The bat bites! ------ |....| ---------- |.<..|####...@...$.| |....-# |...B....+ |....| |.d......| ------ -------|-- Player the Rambler St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15 Neutral Dlvl:1 $:0 HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak -------------------------------------------------------------------- Figure 1 3.1. The status lines (bottom) The bottom two lines of the screen contain several cryptic pieces of information describing your current status. If either status line becomes longer than the width of the screen, you might not see all of it. Here are explanations of what the vari- ous status items mean (though your configuration may not have all the status items listed below): Rank Your character's name and professional ranking (based on the experience level, see below). Strength A measure of your character's strength; one of your six ba- sic attributes. A human character's attributes can range from 3 to 18 inclusive; non-humans may exceed these limits (occasionally you may get super-strengths of the form 18/xx, and magic can also cause attributes to exceed the normal limits). The higher your strength, the stronger you are. Strength affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. Dexterity Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. Constitution Constitution affects your ability to recover from injuries and other strains on your stamina. Intelligence Intelligence affects your ability to cast spells and read NetHack 3.6 December 7, 2015 NetHack Guidebook 6 spellbooks. Wisdom Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. Charisma Charisma affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you. Alignment Lawful, Neutral, or Chaotic. Often, Lawful is taken as good and Chaotic as evil, but legal and ethical do not always co- incide. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive, while those of an opposing alignment are more likely to be seriously offended at your presence. Dungeon Level How deep you are in the dungeon. You start at level one and the number increases as you go deeper into the dungeon. Some levels are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be some- where beneath the twentieth level. Gold The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. Hit Points Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in a fight, the lower they get. You can regain hit points by resting, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. Power Spell points. This tells you how much mystic energy (mana) you have available for spell casting. Again, resting will regenerate the amount available. Armor Class A measure of how effectively your armor stops blows from un- friendly creatures. The lower this number is, the more ef- fective the armor; it is quite possible to have negative ar- mor class. Experience Your current experience level and experience points. As you adventure, you gain experience points. At certain experi- ence point totals, you gain an experience level. The more experienced you are, the better you fight and withstand mag- ical attacks. Many dungeons show only your experience level NetHack 3.6 December 7, 2015 NetHack Guidebook 7 here. Time The number of turns elapsed so far, displayed if you have the time option set. Hunger status Your current hunger status, ranging from Satiated down to Fainting. If your hunger status is normal, it is not dis- played. Additional status flags may appear after the hunger status: Conf when you're confused, FoodPois or Ill when sick, Blind when you can't see, Stun when stunned, and Hallu when hallucinating. 3.2. The message line (top) The top line of the screen is reserved for messages that de- scribe things that are impossible to represent visually. If you see a ``--More--'' on the top line, this means that NetHack has another message to display on the screen, but it wants to make certain that you've read the one that is there first. To read the next message, just press the space bar. To change how and what messages are shown on the message line, see ``Configuring Message Types`` and the verbose option. 3.3. The map (rest of the screen) The rest of the screen is the map of the level as you have explored it so far. Each symbol on the screen represents some- thing. You can set various graphics options to change some of the symbols the game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: - and | The walls of a room, or an open door. Or a grave (|). . The floor of a room, ice, or a doorless doorway. # A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. > Stairs down: a way to the next level. < Stairs up: a way to the previous level. + A closed door, or a spellbook containing a spell you may be able to learn. @ Your character or a human. $ A pile of gold. NetHack 3.6 December 7, 2015 NetHack Guidebook 8 ^ A trap (once you have detected it). ) A weapon. [ A suit or piece of armor. % Something edible (not necessarily healthy). ? A scroll. / A wand. = A ring. ! A potion. ( A useful item (pick-axe, key, lamp...). " An amulet or a spider web. * A gem or rock (possibly valuable, possibly worthless). ` A boulder or statue. 0 An iron ball. _ An altar, or an iron chain. { A fountain. } A pool of water or moat or a pool of lava. \ An opulent throne. a-zA-Z and other symbols Letters and certain other symbols represent the various in- habitants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. I This marks the last known location of an invisible or other- wise unseen monster. Note that the monster could have moved. The 'F' and 'm' commands may be useful here. You need not memorize all these symbols; you can ask the game what any symbol represents with the `/' command (see the next section for more info). 4. Commands Commands are initiated by typing one or two characters. Some commands, like ``search'', do not require that any more in- formation be collected by NetHack. Other commands might require additional information, for example a direction, or an object to NetHack 3.6 December 7, 2015 NetHack Guidebook 9 be used. For those commands that require additional information, NetHack will present you with either a menu of choices or with a command line prompt requesting information. Which you are pre- sented with will depend chiefly on how you have set the menustyle option. For example, a common question, in the form ``What do you want to use? [a-zA-Z ?*]'', asks you to choose an object you are carrying. Here, ``a-zA-Z'' are the inventory letters of your possible choices. Typing `?' gives you an inventory list of these items, so you can see what each letter refers to. In this example, there is also a `*' indicating that you may choose an object not on the list, if you wanted to use something unexpect- ed. Typing a `*' lists your entire inventory, so you can see the inventory letters of every object you're carrying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the ESC key to abort the command. You can put a number before some commands to repeat them that many times; for example, ``10s'' will search ten times. If you have the number_pad option set, you must type `n' to prefix a count, so the example above would be typed ``n10s'' instead. Commands for which counts make no sense ignore them. In addi- tion, movement commands can be prefixed for greater control (see below). To cancel a count or a prefix, press the ESC key. The list of commands is rather long, but it can be read at any time during the game through the `?' command, which accesses a menu of helpful texts. Here are the commands for your refer- ence: ? Help menu: display one of several help texts available. / Tell what a symbol represents. You may choose to specify a location or type a symbol (or even a whole word) to explain. Specifying a location is done by moving the cursor to a par- ticular spot on the map and then pressing one of `.', `,', `;', or `:'. `.' will explain the symbol at the chosen lo- cation, conditionally check for ``More info?'' depending up- on whether the help option is on, and then you will be asked to pick another location; `,' will explain the symbol but skip any additional information; `;' will skip additional info and also not bother asking you to choose another loca- tion to examine; `:' will show additional info, if any, without asking for confirmation. When picking a location, pressing the ESC key will terminate this command, or press- ing `?' will give a brief reminder about how it works. Specifying a name rather than a location always gives any additional information available about that name. & Tell what a command does. NetHack 3.6 December 7, 2015 NetHack Guidebook 10 < Go up to the previous level (if you are on a staircase or ladder). > Go down to the next level (if you are on a staircase or lad- der). [yuhjklbn] Go one step in the direction indicated (see Figure 2). If you sense or remember a monster there, you will fight the monster instead. Only these one-step movement commands cause you to fight monsters; the others (below) are ``safe.'' y k u 7 8 9 \ | / \ | / h- . -l 4- . -6 / | \ / | \ b j n 1 2 3 (if number_pad is set) Figure 2 [YUHJKLBN] Go in that direction until you hit a wall or run into some- thing. m[yuhjklbn] Prefix: move without picking up objects or fighting (even if you remember a monster there) F[yuhjklbn] Prefix: fight a monster (even if you only guess one is there) M[yuhjklbn] Prefix: move far, no pickup. g[yuhjklbn] Prefix: move until something interesting is found. G[yuhjklbn] or [yuhjklbn] Prefix: same as `g', but forking of corridors is not con- sidered interesting. _ Travel to a map location via a shortest-path algorithm. The shortest path is computed over map locations the hero knows about (e.g. seen or previously traversed). If there is no known path, a guess is made instead. Stops on most of the same conditions as the `G' command, but without picking up objects, similar to the `M' command. For ports with mouse support, the command is also invoked when a mouse- click takes place on a location other than the current NetHack 3.6 December 7, 2015 NetHack Guidebook 11 position. . Rest, do nothing for one turn. a Apply (use) a tool (pick-axe, key, lamp...). A Remove one or more worn items, such as armor. Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. ^A Redo the previous command. c Close a door. C Call (name) a monster, an individual object, or a type of object. Same as extended command ``#name''. ^C Panic button. Quit the game. d Drop something. Ex. ``d7a'' means drop seven items of object a. D Drop several things. In answer to the question ``What kinds of things do you want to drop? [!%= BUCXaium]'' you should type zero or more object symbols possibly fol- lowed by `a' and/or `i' and/or `u' and/or `m'. In addition, one or more of the blessed/uncursed/cursed groups may be typed. DB - drop all objects known to be blessed. DU - drop all objects known to be uncursed. DC - drop all objects known to be cursed. DX - drop all objects of unknown B/U/C status. Da - drop all objects, without asking for confirmation. Di - examine your inventory before dropping anything. Du - drop only unpaid objects (when in a shop). Dm - use a menu to pick which object(s) to drop. D%u - drop only unpaid food. ^D Kick something (usually a door). e Eat food. E Engrave a message on the floor. E- - write in the dust with your fingers. NetHack 3.6 December 7, 2015 NetHack Guidebook 12 Engraving the word ``Elbereth'' will cause most monsters to not attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. (This feature may be compiled out of the game, so your ver- sion might not have it.) f Fire one of the objects placed in your quiver (or quiver sack, or that you have at the ready). You may select ammu- nition with a previous `Q' command, or let the computer pick something appropriate if autoquiver is true. i List your inventory (everything you're carrying). I List selected parts of your inventory, usually be specifying the character for a particular set of objects, like `[' for armor or `!' for potions. I* - list all gems in inventory; Iu - list all unpaid items; Ix - list all used up items that are on your shopping bill; IB - list all items known to be blessed; IU - list all items known to be uncursed; IC - list all items known to be cursed; IX - list all items whose bless/curse status is known; I$ - count your money. o Open a door. O Set options. A menu showing the current option values will be displayed. You can change most values simply by selecting the menu en- try for the given option (ie, by typing its letter or click- ing upon it, depending on your user interface). For the non-boolean choices, a further menu or prompt will appear once you've closed this menu. The available options are listed later in this Guidebook. Options are usually set be- fore the game rather than with the `O' command; see the sec- tion on options below. p Pay your shopping bill. P Put on an accessory (ring, amulet, or blindfold). This command may also be used to wear armor. The prompt for which inventory item to use will only list accessories, but choosing an unlisted item of armor will attempt to wear it. (See the `W' command below. It lists armor as the inventory choices but will accept an accessory and attempt to put that on.) ^P Repeat previous message. NetHack 3.6 December 7, 2015 NetHack Guidebook 13 Subsequent ^P's repeat earlier messages. The behavior can be varied via the msg_window option. q Quaff (drink) something (potion, water, etc). Q Select an object for your quiver, quiver sack, or just gen- erally at the ready (only one of these is available at a time). You can then throw this (or one of these) using the `f' command. (In versions prior to 3.3 this was the command to quit the game, which has been moved to ``#quit''.) r Read a scroll or spellbook. R Remove a worn accessory (ring, amulet, or blindfold). If you're wearing more than one, you'll be prompted for which one to remove. When you're only wearing one, then by default it will be removed without asking, but you can set the paranoid_confirmation option to require a prompt. This command may also be used to take off armor. The prompt for which inventory item to remove only lists worn acces- sories, but an item of worn armor can be chosen. (See the `T' command below. It lists armor as the inventory choices but will accept an accessory and attempt to remove it.) ^R Redraw the screen. s Search for secret doors and traps around you. It usually takes several tries to find something. S Save (and suspend) the game. The game will be restored au- tomatically the next time you play. t Throw an object or shoot a projectile. T Take off armor. If you're wearing more than one piece, you'll be prompted for which one to take off. (Note that this treats a cloak covering a suit and/or a shirt, or a suit covering a shirt, as if the underlying items weren't there.) When you're only wearing one, then by default it will be taken off without asking, but you can set the paranoid_confirmation option to require a prompt. This command may also be used to remove accessories. The prompt for which inventory item to take off only lists worn armor, but a worn accessory can be chosen. (See the `R' command above. It lists accessories as the inventory choic- es but will accept an item of armor and attempt to take it off.) NetHack 3.6 December 7, 2015 NetHack Guidebook 14 ^T Teleport, if you have the ability. v Display version number. V Display the game history. w Wield weapon. w- - wield nothing, use your bare hands. Some characters can wield two weapons at once; use the `X' command (or the ``#twoweapon'' extended command) to do so. W Wear armor. This command may also be used to put on an accessory (ring, amulet, or blindfold). The prompt for which inventory item to use will only list armor, but choosing an unlisted acces- sory will attempt to put it on. (See the `P' command above. It lists accessories as the inventory choices but will ac- cept an item of armor and attempt to wear it.) x Exchange your wielded weapon with the item in your alternate weapon slot. The latter is used as your secondary weapon when engaging in two-weapon combat. Note that if one of these slots is emp- ty, the exchange still takes place. X Toggle two-weapon combat, if your character can do it. Also available via the ``#twoweapon'' extended command. (In versions prior to 3.6 this was the command to switch from normal play to "explore mode", also known as "discovery mode", which has now been moved to ``#explore''.) ^X Display basic information about your character. Displays name, role, race, gender (unless role name makes that redundant, such as Caveman or Priestess), and align- ment, along with your patron deity and his or her opposi- tion. It also shows most of the various items of informa- tion from the status line(s) in a less terse form, including several additional things which don't appear in the normal status display due to space considerations. z Zap a wand. z. - to aim at yourself, use `.' for the direction. Z Zap (cast) a spell. Z. - to cast at yourself, use `.' for the direction. NetHack 3.6 December 7, 2015 NetHack Guidebook 15 ^Z Suspend the game (UNIX(R) versions with job control only). : Look at what is here. ; Show what type of thing a visible symbol corresponds to. , Pick up some things from the floor beneath you. May be preceded by `m' to force a selection menu. @ Toggle the autopickup option on and off. ^ Ask for the type of a trap you found earlier. ) Tell what weapon you are wielding. [ Tell what armor you are wearing. = Tell what rings you are wearing. " Tell what amulet you are wearing. ( Tell what tools you are using. * Tell what equipment you are using. Combines the preceding five type-specific commands into one. $ Count your gold pieces. + List the spells you know. Using this command, you can also rearrange the order in which your spells are listed, either by sorting the entire list or by picking one spell from the menu then picking an- other to swap places with it. Swapping pairs of spells changes their casting letters, so the change lasts after the current `+' command finishes. Sorting the whole list is temporary. To make the most recent sort order persist be- yond the current `+' command, choose the sort option again and then pick "reassign casting letters". (Any spells learned after that will be added to the end of the list rather than be inserted into the sorted ordering.) \ Show what types of objects have been discovered. ` Show discovered types for one class of objects. ! Escape to a shell. __________ (R)UNIX is a registered trademark of AT&T. NetHack 3.6 December 7, 2015 NetHack Guidebook 16 # Perform an extended command. As you can see, the authors of NetHack used up all the let- ters, so this is a way to introduce the less frequently used commands. What extended commands are available depends on what features the game was compiled with. #adjust Adjust inventory letters (most useful when the fixinv option is ``on''). This command allows you to move an item from one particular inventory slot to another so that it has a letter which is more meaningful for you or that it will appear in a particu- lar location when inventory listings are displayed. ``#ad- just'' can also be used to split a stack of objects; when choosing the item to adjust, enter a count prior to its let- ter. #annotate Allows you to specify one line of text to associate with the current dungeon level. All levels with annotations are dis- played by the ``#overview'' command. #chat Talk to someone. #conduct List voluntary challenges you have maintained. See the section below entitled ``Conduct'' for details. #dip Dip an object into something. #enhance Advance or check weapon and spell skills. #force Force a lock. #invoke Invoke an object's special powers. #jump Jump to another location. #loot Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. #monster Use a monster's special ability (when polymorphed into mon- ster form). NetHack 3.6 December 7, 2015 NetHack Guidebook 17 #name Name a monster, an individual object, or a type of object. Same as `C'. #offer Offer a sacrifice to the gods. You'll need to find an altar to have any chance at success. Corpses of recently killed monsters are the fodder of choice. #overview Display information you've discovered about the dungeon. Any visited level (unless forgotten due to amnesia) with an annotation is included, and many things (altars, thrones, fountains, and so on; extra stairs leading to another dun- geon branch) trigger an automatic annotation. If dungeon overview is chosen during end-of-game disclosure, every vis- ited level will be included regardless of annotations. #pray Pray to the gods for help. Praying too soon after receiving prior help is a bad idea. (Hint: entering the dungeon alive is treated as having re- ceived help. You probably shouldn't start off a new game by praying right away.) Since using this command by accident can cause trouble, there is an option to make you confirm your intent before praying. It is enabled by default, and you can reset the paranoid_confirmation option to disable it. #quit Quit the program without saving your game. Since using this command by accident would throw away the current game, you are asked to confirm your intent before quitting. By default a response of 'y' acknowledges that intent. You can set the paranoid_confirmation option to re- quire a response of "yes" instead. #ride Ride (or stop riding) a saddled creature. #rub Rub a lamp or a stone. #sit Sit down. #terrain Show bare map without displaying monsters, objects, or traps. NetHack 3.6 December 7, 2015 NetHack Guidebook 18 #tip Tip over a container (bag or box) to pour out its contents. #turn Turn undead. #twoweapon Toggle two-weapon combat on or off. Note that you must use suitable weapons for this type of combat, or it will be automatically turned off. #untrap Untrap something (trap, door, or chest). In some circumstances it can also be used to rescue trapped monsters. #version Print compile time options for this version of NetHack. #wipe Wipe off your face. #? Help menu: get the list of available extended commands. If your keyboard has a meta key (which, when pressed in com- bination with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. In NT, OS/2, PC and ST NetHack, the `Alt' key can be used in this fashion; on the Amiga, set the altmeta option to get this behavior. On other systems, if typing `Alt' plus another key transmits a two character se- quence consisting of an Escape followed by the other key, you may set the altmeta option to have nethack combine them into meta+key. M-? #? (not supported by all platforms) M-2 #twoweapon (unless the number_pad option is enabled) M-a #adjust M-A #annotate M-c #chat M-C #conduct M-d #dip M-e #enhance NetHack 3.6 December 7, 2015 NetHack Guidebook 19 M-f #force M-i #invoke M-j #jump M-l #loot M-m #monster M-n #name M-o #offer M-O #overview M-p #pray M-q #quit M-r #rub M-R #ride M-s #sit M-t #turn M-T #tip M-u #untrap M-v #version M-w #wipe If the number_pad option is on, some additional letter com- mands are available: h Help menu: display one of several help texts available, like ``?''. j Jump to another location. Same as ``#jump'' or ``M-j''. k Kick something (usually a door). Same as `^D'. l Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. Same as ``#loot'' or ``M-l''. N Name a monster, an individual object, or a type of object. Same as ``#name'' (or ``M-n'') which is the same as the `C' command. NetHack 3.6 December 7, 2015 NetHack Guidebook 20 u Untrap a trap, door, or chest. Same as ``#untrap'' or ``M- u''. 5. Rooms and corridors Rooms and corridors in the dungeon are either lit or dark. Any lit areas within your line of sight will be displayed; dark areas are only displayed if they are within one space of you. Walls and corridors remain on the map as you explore them. Secret corridors are hidden. You can find them with the `s' (search) command. 5.1. Doorways Doorways connect rooms and corridors. Some doorways have no doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use the `o' (open) command; to close it again, use the `c' (close) command. You can get through a locked door by using a tool to pick the lock with the `a' (apply) command, or by kicking it open with the `^D' (kick) command. Open doors cannot be entered diagonally; you must approach them straight on, horizontally or vertically. Doorways without doors are not restricted in this fashion. Doors can be useful for shutting out monsters. Most mon- sters cannot open doors, although a few don't need to (ex. ghosts can walk through doors). Secret doors are hidden. You can find them with the `s' (search) command. Once found they are in all ways equivalent to normal doors. 5.2. Traps (`^') There are traps throughout the dungeon to snare the unwary delver. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out. Traps don't appear on your map until you see one triggered by moving onto it, see some- thing fall into it, or you discover it with the `s' (search) com- mand. Monsters can fall prey to traps, too, which can be a very useful defensive strategy. There is a special pre-mapped branch of the dungeon based on the classic computer game ``Sokoban.'' The goal is to push the boulders into the pits or holes. With careful foresight, it is possible to complete all of the levels according to the tradi- tional rules of Sokoban. Some allowances are permitted in case the player gets stuck; however, they will lower your luck. NetHack 3.6 December 7, 2015 NetHack Guidebook 21 5.3. Stairs (`<', `>') In general, each level in the dungeon will have a staircase going up (`<') to the previous level and another going down (`>') to the next level. There are some exceptions though. For in- stance, fairly early in the dungeon you will find a level with two down staircases, one continuing into the dungeon and the oth- er branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so after exploring them (if you choose to do so), you'll need to climb back up to the main dun- geon. When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be de- activated and stored in a file on disk. If you're moving to a previously visited level, it will be loaded from its file on disk and reactivated. If you're moving to a level which has not yet been visited, it will be created (from scratch for most random levels, from a template for some ``special'' levels, or loaded from the remains of an earlier game for a ``bones'' level as briefly described below). Monsters are only active on the cur- rent level; those on other levels are essentially placed into stasis. Ordinarily when you climb a set of stairs, you will arrive on the corresponding staircase at your destination. However, pets (see below) and some other monsters will follow along if they're close enough when you travel up or down stairs, and occa- sionally one of these creatures will displace you during the climb. When that occurs, the pet or other monster will arrive on the staircase and you will end up nearby. 5.4. Ladders (`<', `>') Ladders serve the same purpose as staircases, and the two types of inter-level connections are nearly indistinguishable during game play. 5.5. Shops and shopping Occasionally you will run across a room with a shopkeeper near the door and many items lying on the floor. You can buy items by picking them up and then using the `p' command. You can inquire about the price of an item prior to picking it up by us- ing the ``#chat'' command while standing on it. Using an item prior to paying for it will incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shopkeeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by NetHack 3.6 December 7, 2015 NetHack Guidebook 22 the shop). If you drop something in a shop by accident, the shopkeeper will usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. Shopkeepers sometimes run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you happen to find a "credit card" in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) The `$' command, which reports the amount of gold you are carrying (in inventory, not inside bags or boxes), will also show current shop debt or credit, if any. The `Iu' command lists un- paid items (those which still belong to the shop) if you are car- rying any. The `Ix' command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. 5.5.1. Shop idiosyncracies Several aspects of shop behavior might be unexpected. * The price of a given item can vary due to a variety of factors. * A shopkeeper treats the spot immediately inside the door as if it were outside the shop. * While the shopkeeper watches you like a hawk, he will generally ignore any other customers. * If a shop is "closed for inventory", it will not open of its own accord. * Shops do not get restocked with new items, regardless of inven- tory depletion. 6. Monsters Monsters you cannot see are not displayed on the screen. Beware! You may suddenly come upon one in a dark place. Some magic items can help you locate them before they locate you (which some monsters can do very well). The commands `/' and `;' may be used to obtain information about those monsters who are displayed on the screen. The com- mand ``#name'', or its synonym `C', allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple monsters are present. Assigning a name which is just a space will remove any prior name. NetHack 3.6 December 7, 2015 NetHack Guidebook 23 The extended command ``#chat'' can be used to interact with an adjacent monster. There is no actual dialog (in other words, you don't get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. 6.1. Fighting If you see a monster and you wish to fight it, just attempt to walk into it. Many monsters you find will mind their own business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. In most circumstances, if you attempt to attack a peaceful monster by moving into its location, you'll be asked to confirm your intent. By default an answer of 'y' acknowledges that in- tent, which can be error prone if you're using 'y' to move. You can set the paranoid_confirmation option to require a response of "yes" instead. If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a monster that you can see; of course, if the mon- ster has moved, you will attack empty air. If you guess that the monster has moved and you don't wish to fight, you can use the `m' command to move without fighting; likewise, if you don't re- member a monster but want to try fighting anyway, you can use the `F' command. 6.2. Your pet You start the game with a little dog (`d'), cat (`f'), or pony (`u'), which follows you about the dungeon and fights mon- sters with you. Like you, your pet needs food to survive. It usually feeds itself on fresh carrion and other meats. If you're worried about it or want to train it, you can feed it, too, by throwing it food. A properly trained pet can be very useful un- der certain circumstances. Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, your pet may even be better at killing things than you, which makes pets useful for low-level characters. Your pet will follow you up and down staircases if it is next to you when you move. Otherwise your pet will be stranded and may become wild. Similarly, when you trigger certain types of traps which alter your location (for instance, a trap door which drops you to a lower dungeon level), any adjacent pet will accompany you and any non-adjacent pet will be left behind. Your pet may trigger such traps itself; you will not be carried along with it even if adjacent at the time. NetHack 3.6 December 7, 2015 NetHack Guidebook 24 6.3. Steeds Some types of creatures in the dungeon can actually be rid- den if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in or- der to forge the alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the `#ride' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. Riding skill is managed by the `#enhance' command. See the section on Weapon proficiency for more information about that. 6.4. Bones levels You may encounter the shades and corpses of other adventur- ers (or even former incarnations of yourself!) and their personal effects. Ghosts are hard to kill, but easy to avoid, since they're slow and do little damage. You can plunder the deceased adventurer's possessions; however, they are likely to be cursed. Beware of whatever killed the former player; it is probably still lurking around, gloating over its last victory. 7. Objects When you find something in the dungeon, it is common to want to pick it up. In NetHack, this is accomplished automatically by walking over the object (unless you turn off the autopickup op- tion (see below), or move with the `m' prefix (see above)), or manually by using the `,' command. If you're carrying too many items, NetHack will tell you so and you won't be able to pick up anything more. Otherwise, it will add the object(s) to your pack and tell you what you just picked up. As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry de- pends on your strength and your constitution. The stronger you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are car- rying around with you through the dungeon will encumber you. Your reactions will get slower and you'll burn calories faster, requiring food more frequently to cope with it. Eventually, you'll be so overloaded that you'll either have to discard some of what you're carrying or collapse under its weight. NetHack will tell you how badly you have loaded yourself. The symbols `Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are displayed on the bottom line display to indicate your condition. NetHack 3.6 December 7, 2015 NetHack Guidebook 25 When you pick up an object, it is assigned an inventory let- ter. Many commands that operate on objects must ask you to find out which object you want to use. When NetHack asks you to choose a particular object you are carrying, you are usually pre- sented with a list of inventory letters to choose from (see Com- mands, above). Some objects, such as weapons, are easily differentiated. Others, like scrolls and potions, are given descriptions which vary according to type. During a game, any two objects with the same description are the same type. However, the descriptions will vary from game to game. When you use one of these objects, if its effect is obvious, NetHack will remember what it is for you. If its effect isn't extremely obvious, you will be asked what you want to call this type of object so you will recognize it later. You can also use the ``#name'' command, or its synonym `C', for the same purpose at any time, to name all objects of a particular type or just an individual object. When you use ``#name'' on an object which has already been named, specifying a space as the value will remove the prior name instead of assigning a new one. 7.1. Curses and Blessings Any object that you find may be cursed, even if the object is otherwise helpful. The most common effect of a curse is being stuck with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is not removable by ordinary means. In addition, cursed arms and armor usually, but not always, bear negative en- chantments that make them less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For ex- ample, a blessed weapon will do more damage against demons. Objects which are neither cursed nor blessed are referred to as uncursed. They could just as easily have been described as unblessed, but the uncursed designation is what you will see within the game. A ``glass half full versus glass half empty'' situation; make of that what you will. There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate sensitivity to this property in any object, so they can more easily avoid cursed objects than other character roles. An item with unknown status will be reported in your inven- tory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word NetHack 3.6 December 7, 2015 NetHack Guidebook 26 ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. In some cases ``uncursed'' will be omitted as being redun- dant when enough other information is displayed. The implic- it_uncursed option can be used to control this; toggle it off to have ``uncursed'' be displayed even when that can be deduced from other attributes. 7.2. Weapons (`)') Given a chance, most monsters in the Mazes of Menace will gratuitously try to kill you. You need weapons for self-defense (killing them first). Without a weapon, you do only 1-2 hit points of damage (plus bonuses, if any). Monk characters are an exception; they normally do much more damage with bare hands than they do with weapons. There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot cross- bow bolts. Slings hurl rocks and (other) stones (like gems). Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be either positive or negative) that adds to your chance to hit and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically iden- tified somehow. Most weapons are subject to some type of damage like rust. Such ``erosion'' damage can be repaired. The chance that an attack will successfully hit a monster, and the amount of damage such a hit will do, depends upon many factors. Among them are: type of weapon, quality of weapon (en- chantment and/or erosion), experience level, strength, dexterity, encumbrance, and proficiency (see below). The monster's armor class - a general defense rating, not necessarily due to wearing of armor - is a factor too; also, some monsters are particularly vulnerable to certain types of weapons. Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon ready to use by setting things up with the `x' command, which exchanges your primary (the one being wielded) and alternate weapons. And if you have proficiency in the ``two weapon combat'' skill, you may wield both weapons si- multaneously as primary and secondary; use the `#twoweapon' ex- tended command to engage or disengage that. Only some types of characters (barbarians, for instance) have the necessary skill available. Even with that skill, using two weapons at once in- curs a penalty in the chance to hit your target compared to using just one weapon at a time. NetHack 3.6 December 7, 2015 NetHack Guidebook 27 There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `-', or else use the `A' com- mand which allows you to unwield the current weapon in addition to taking off other worn items. Those of you in the audience who are AD&D players, be aware that each weapon which existed in AD&D does roughly the same dam- age to monsters in NetHack. Some of the more obscure weapons (such as the aklys, lucern hammer, and bec-de-corbin) are defined in an appendix to Unearthed Arcana, an AD&D supplement. The commands to use weapons are `w' (wield), `t' (throw), `f' (fire, an alternative way of throwing), `Q' (quiver), `x' (exchange), `#twoweapon', and `#enhance' (see below). 7.2.1. Throwing and shooting You can throw just about anything via the `t' command. It will prompt for the item to throw; picking `?' will list things in your inventory which are considered likely to be thrown, or picking `*' will list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown de- pends mainly on the type of object and your strength. Arrows can be thrown by hand, but can be thrown much farther and will be more likely to hit when thrown while you are wielding a bow. You can simplify the throwing operation by using the `Q' command to select your preferred ``missile'', then using the `f' command to throw it. You'll be prompted for a direction as above, but you don't have to specify which item to throw each time you use `f'. There is also an option, autoquiver, which has NetHack choose another item to automatically fill your quiver (or quiver sack, or have at the ready) when the inventory slot used for `Q' runs out. Some characters have the ability to fire a volley of multi- ple items in a single turn. Knowing how to load several rounds of ammunition at once -- or hold several missiles in your hand -- and still hit a target is not an easy task. Rangers are among those who are adept at this task, as are those with a high level of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one to shoot bolts, or in sling skill if you're wielding one to shoot stones). The number of items that the character has a chance to fire varies from turn to turn. You can explicitly limit the number of shots by using a numeric prefix before the `t' or `f' command. For example, ``2f'' (or ``n2f'' if using number_pad mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify a larger number than would have been shot (``4f'' in this example), you'll just end up shooting the same number (3, here) as if no limit had been speci- fied. Once the volley is in motion, all of the items will travel in the same direction; if the first ones kill a monster, the NetHack 3.6 December 7, 2015 NetHack Guidebook 28 others can still continue beyond that spot. 7.2.2. Weapon proficiency You will have varying degrees of skill in the weapons avail- able. Weapon proficiency, or weapon skills, affect how well you can use particular types of weapons, and you'll be able to im- prove your skills as you progress through a game, depending on your role, your experience level, and use of the weapons. For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. The `#enhance' extended command is used to review current weapons proficiency (also spell proficiency) and to choose which skill(s) to improve when you've used one or more skills enough to become eligible to do so. The skill rankings are ``none'' (some- times also referred to as ``restricted'', because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'', and ``expert''. Restricted skills simply will not appear in the list shown by `#enhance'. (Divine intervention might unrestrict a particular skill, in which case it will start at unskilled and be limited to basic.) Some characters can enhance their barehanded combat or martial arts skill beyond expert to ``master'' or ``grand master''. Use of a weapon in which you're restricted or unskilled will incur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is higher. A successful hit has a chance to boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, you'll be told that you feel more confident in your skills. At that point you can use `#enhance' to increase one or more skills. Such skills are not increased automatically because there is a limit to your to- tal overall skills, so you need to actively choose which skills to enhance and which to ignore. 7.2.3. Two-Weapon combat Some characters can use two weapons at once. Setting things up to do so can seem cumbersome but becomes second nature with use. To wield two weapons, you need to use the ``#twoweapon'' command. But first you need to have a weapon in each hand. (Note that your two weapons are not fully equal; the one in the hand you normally wield with is considered primary and the other one is considered secondary. The most noticeable difference is NetHack 3.6 December 7, 2015 NetHack Guidebook 29 after you stop--or before you begin, for that matter--wielding two weapons at once. The primary is your wielded weapon and the secondary is just an item in your inventory that's been designat- ed as alternate weapon.) If your primary weapon is wielded but your off hand is empty or has the wrong weapon, use the sequence 'x', 'w', 'x' to first swap your primary into your off hand, wield whatever you want as secondary weapon, then swap them both back into the intended hands. If your secondary or alternate weapon is correct but your primary one is not, simply use 'w' to wield the primary. Lastly, if neither hand holds the correct weapon, use 'w', 'x', 'w' to first wield the intended secondary, swap it to off hand, and then wield the primary. The whole process can be simplified via use of the push- weapon option. When it is enabled, then using 'w' to wield some- thing causes the currently wielded weapon to become your alter- nate weapon. So the sequence 'w', 'w' can be used to first wield the weapon you intend to be secondary, and then wield the one you want as primary which will push the first into secondary posi- tion. When in two-weapon combat mode, using the ``#twoweapon'' command toggles back to single-weapon mode. Throwing or dropping either of the weapons or having one of them be stolen or de- stroyed will also make you revert to single-weapon combat. 7.3. Armor (`[') Lots of unfriendly things lurk about; you need armor to pro- tect yourself from their blows. Some types of armor offer better protection than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD&D, with 10 be- ing the equivalent of no armor, and lower numbers meaning better armor. Each suit of armor which exists in AD&D gives the same protection in NetHack. Here is an (incomplete) list of the armor classes provided by various suits of armor: dragon scale mail 1 plate mail 3 crystal plate mail 3 bronze plate mail 4 splint mail 4 banded mail 4 dwarvish mithril-coat 4 elven mithril-coat 5 chain mail 5 orcish chain mail 6 scale mail 6 studded leather armor 7 ring mail 7 orcish ring mail 8 NetHack 3.6 December 7, 2015 NetHack Guidebook 30 leather armor 8 leather jacket 9 no armor 10 You can also wear other pieces of armor (ex. helmets, boots, shields, cloaks) to lower your armor class even further, but you can only wear one item of each category (one suit of armor, one cloak, one helmet, one shield, and so on) at a time. If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its ``plus'' (or minus) will subtract from your armor class. For example, a +1 chain mail would give you better protection than normal chain mail, lowering your armor class one unit further to 4. When you put on a piece of armor, you immediately find out the armor class and any ``plusses'' it provides. Cursed pieces of armor usually have negative enchantments (minuses) in addition to being unremovable. Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may in- hibit spell casting. The commands to use armor are `W' (wear) and `T' (take off). The `A' command can also be used to take off armor as well as other worn items. 7.4. Food (`%') Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins (``cans'') will usu- ally stay fresh, but ice boxes are heavy, and tins take a while to open. When you kill monsters, they usually leave corpses which are also ``food.'' Many, but not all, of these are edible; some also give you special powers when you eat them. A good rule of thumb is ``you are what you eat.'' Some character roles and some monsters are vegetarian. Veg- etarian monsters will typically never eat animal corpses, while vegetarian players can, but with some rather unpleasant side-ef- fects. You can name one food item after something you like to eat with the fruit option. The command to eat food is `e'. 7.5. Scrolls (`?') Scrolls are labeled with various titles, probably chosen by ancient wizards for their amusement value (ex. ``READ ME,'' or NetHack 3.6 December 7, 2015 NetHack Guidebook 31 ``THANX MAUD'' backwards). Scrolls disappear after you read them (except for blank ones, without magic spells on them). One of the most useful of these is the scroll of identify, which can be used to determine what another object is, whether it is cursed or blessed, and how many uses it has left. Some ob- jects of subtle enchantment are difficult to identify without these. A mail daemon may run up and deliver mail to you as a scroll of mail (on versions compiled with this feature). To use this feature on versions where NetHack mail delivery is triggered by electronic mail appearing in your system mailbox, you must let NetHack know where to look for new mail by setting the ``MAIL'' environment variable to the file name of your mailbox. You may also want to set the ``MAILREADER'' environment variable to the file name of your favorite reader, so NetHack can shell to it when you read the scroll. On versions of NetHack where mail is randomly generated internal to the game, these environment vari- ables are ignored. You can disable the mail daemon by turning off the mail option. The command to read a scroll is `r'. 7.6. Potions (`!') Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. Clear potions are potions of water. Sometimes these are blessed or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`t') at them. It is also sometimes very useful to dip (``#dip'') an object into a potion. The command to drink a potion is `q' (quaff). 7.7. Wands (`/') Magic wands usually have multiple magical charges. Some wands are directional--you must give a direction in which to zap them. You can also zap them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other wands are nondirectional--they don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. When the number of charges left in a wand becomes zero, at- tempts to use the wand will usually result in nothing happening. Occasionally, however, it may be possible to squeeze the last few mana points from an otherwise spent wand, destroying it in the process. A wand may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time NetHack 3.6 December 7, 2015 NetHack Guidebook 32 the wand is recharged. In a truly desperate situation, when your back is up against the wall, you might decide to go for broke and break your wand. This is not for the faint of heart. Doing so will almost cer- tainly cause a catastrophic release of magical energies. When you have fully identified a particular wand, inventory display will include additional information in parentheses: the number of times it has been recharged followed by a colon and then by its current number of charges. A current charge count of -1 is a special case indicating that the wand has been cancelled. The command to use a wand is `z' (zap). To break one, use the `a' (apply) command. 7.8. Rings (`=') Rings are very useful items, since they are relatively per- manent magic, unlike the usually fleeting effects of potions, scrolls, and wands. Putting on a ring activates its magic. You can wear only two rings, one on each ring finger. Most rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. The commands to use rings are `P' (put on) and `R' (remove). 7.9. Spellbooks (`+') Spellbooks are tomes of mighty magic. When studied with the `r' (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable) -- unless the attempt backfires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. Casting a spell calls forth magical energies and focuses them with your naked mind. Some of the magical energy released comes from within you, and casting several spells in a row may tire you. Casting of spells also requires practice. With prac- tice, your skill in each category of spell casting will improve. Over time, however, your memory of each spell will dim, and you will need to relearn it. NetHack 3.6 December 7, 2015 NetHack Guidebook 33 Some spells are directional--you must give a direction in which to cast them. You can also cast them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other spells are nondirectional--they don't require a direction. Just as weapons are divided into groups in which a character can become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises its skill group; using the `#enhance' command to advance a sufficiently exercised skill will affect all spells within the group. Advanced skill may increase the potency of spells, reduce their risk of failure during casting attempts, and improve the accuracy of the estimate for how much longer they will be retained in your memory. Skill slots are shared with weapons skills. (See also the section on ``Weapon proficiency''.) Casting a spell also requires flexible movement, and wearing various types of armor may interfere with that. The command to read a spellbook is the same as for scrolls, `r' (read). The `+' command lists each spell you know along with its level, skill category, chance of failure when casting, and an estimate of how strongly it is remembered. The `Z' (cast) com- mand casts a spell. 7.10. Tools (`(') Tools are miscellaneous objects with various purposes. Some tools have a limited number of uses, akin to wand charges. For example, lamps burn out after a while. Other tools are contain- ers, which objects can be placed into or taken out of. The command to use tools is `a' (apply). 7.10.1. Containers You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the ``#loot'' extended command when you are standing on top of it (that is, on the same floor spot), or with the `a' (apply) command when you are carry- ing it. However, chests are often locked, and are in any case unwieldy objects. You must set one down before unlocking it by using a key or lock-picking tool with the `a' (apply) command, by kicking it with the `^D' command, or by using a weapon to force the lock with the ``#force'' extended command. Some chests are trapped, causing nasty things to happen when you unlock or open them. You can check for and try to deactivate traps with the ``#untrap'' extended command. NetHack 3.6 December 7, 2015 NetHack Guidebook 34 7.11. Amulets (`"') Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some benefi- cial, some harmful, which are activated by putting them on. Only one amulet may be worn at a time, around your neck. The commands to use amulets are the same as for rings, `P' (put on) and `R' (remove). 7.12. Gems (`*') Some gems are valuable, and can be sold for a lot of gold. They are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. Other small rocks are also categorized as gems, but they are much less valuable. All rocks, however, can be used as projec- tile weapons (if you have a sling). In the most desperate of cases, you can still throw them by hand. 7.13. Large rocks (``') Statues and boulders are not particularly useful, and are generally heavy. It is rumored that some statues are not what they seem. Very large humanoids (giants and their ilk) have been known to use boulders as weapons. 7.14. Gold (`$') Gold adds to your score, and you can buy things in shops with it. There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). 8. Conduct As if winning NetHack were not difficult enough, certain players seek to challenge themselves by imposing restrictions on the way they play the game. The game automatically tracks some of these challenges, which can be checked at any time with the #conduct command or at the end of the game. When you perform an action which breaks a challenge, it will no longer be listed. This gives players extra ``bragging rights'' for winning the game with these challenges. Note that it is perfectly acceptable to win the game without resorting to these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. NetHack 3.6 December 7, 2015 NetHack Guidebook 35 Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures can survive long periods of time without food, there is a physiological need for water; thus there is no restriction on drinking beverages, even if they provide some minor food bene- fits. Calling upon your god for help with starvation does not violate any food challenges either. A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and veg- etables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are also considered to be vegetable matter. Certain human food is prepared without animal products; namely, lembas wafers, cram rations, food rations (gunyoki), K-rations, and C- rations. Metal or another normally indigestible material eaten while polymorphed into a creature that can digest it is also con- sidered vegan food. Note however that eating such items still counts against foodless conduct. Vegetarians do not eat animals; however, they are less se- lective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than the black puddings, eggs and food made from eggs (fortune cookies and pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. Eating any kind of meat violates the vegetarian, vegan, and foodless conducts. This includes tripe rations, the corpses or tins of any monsters not mentioned above, and the various other chunks of meat found in the dungeon. Swallowing and digesting a monster while polymorphed is treated as if you ate the creature's corpse. Eating leather, dragon hide, or bone items while poly- morphed into a creature that can digest it, or eating monster brains while polymorphed into a mind flayer, is considered eating an animal, although wax is only an animal byproduct. Regardless of conduct, there will be some items which are indigestible, and others which are hazardous to eat. Using a swallow-and-digest attack against a monster is equivalent to eat- ing the monster's corpse. Please note that the term ``vegan'' is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, coral), but the game will not keep track of this for you. Also note that ``milky'' potions may be a translucent white, but they do not contain milk, so they are compatible with a vegan diet. Slime molds or player-defined ``fruits'', although they could be anything from ``cherries'' to ``pork chops'', are also assumed to be vegan. An atheist is one who rejects religion. This means that you cannot #pray, #offer sacrifices to any god, #turn undead, or #chat with a priest. Particularly selective readers may argue that playing Monk or Priest characters should violate this NetHack 3.6 December 7, 2015 NetHack Guidebook 36 conduct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also not penalized for being spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. Most players fight with a wielded weapon (or tool intended to be wielded as a weapon). Another challenge is to win the game without using such a wielded weapon. You are still permitted to throw, fire, and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. In NetHack, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to gain experience by other means. An illiterate character cannot read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writing a scroll; or making an engraving of anything other than a single ``x'' (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is assumed to be learned from your teachers prior to the start of the game and isn't counted. There are several other challenges tracked by the game. It is possible to eliminate one or more species of monsters by geno- cide; playing without this feature is considered a challenge. When the game offers you an opportunity to genocide monsters, you may respond with the monster type ``none'' if you want to de- cline. You can change the form of an item into another item of the same type (``polypiling'') or the form of your own body into another creature (``polyself'') by wand, spell, or potion of polymorph; avoiding these effects are each considered challenges. Polymorphing monsters, including pets, does not break either of these challenges. Finally, you may sometimes receive wishes; a game without an attempt to wish for any items is a challenge, as is a game without wishing for an artifact (even if the artifact immediately disappears). When the game offers you an opportunity to make a wish for an item, you may choose ``nothing'' if you want to decline. 9. Options Due to variations in personal tastes and conceptions of how NetHack should do things, there are options you can set to change how NetHack behaves. NetHack 3.6 December 7, 2015 NetHack Guidebook 37 9.1. Setting the options Options may be set in a number of ways. Within the game, the `O' command allows you to view all options and change most of them. You can also set options automatically by placing them in the NETHACKOPTIONS environment variable or in a configuration file. Some versions of NetHack also have front-end programs that allow you to set options before starting the game or a global configuration for system administrators. 9.2. Using the NETHACKOPTIONS environment variable The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, and turn it off by typing a `!' or ``no'' be- fore the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the string. The value is ter- minated by the next comma or the end of string. For example, to set up an environment variable so that ``au- toquiver'' is on, ``autopickup'' is off, the name is set to ``Blue Meanie'', and the fruit is set to ``papaya'', you would enter the command % setenv NETHACKOPTIONS "autoquiver,\!autopickup,name:Blue Meanie,fruit:papaya" in csh (note the need to escape the ! since it's special to the shell), or $ NETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya" $ export NETHACKOPTIONS in sh or ksh. 9.3. Using a configuration file Any line in the configuration file starting with `#' is treated as a comment. Any line in the configuration file start- ing with ``OPTIONS='' may be filled out with options in the same syntax as in NETHACKOPTIONS. Any line starting with ``SYMBOLS='' is taken as defining the corresponding symbol in a different syn- tax, a sequence of decimal numbers giving the character position in the current font to be used in displaying each entry. Such a sequence can be continued to multiple lines by putting a `\' at the end of each line to be continued. Any line starting with ``AUTOPICKUP_EXCEPTION='' is taken as defining an exception to the pickup_types option. There is a section of this Guidebook that discusses that. The default name of the configuration file varies on differ- ent operating systems, but NETHACKOPTIONS can also be set to the NetHack 3.6 December 7, 2015 NetHack Guidebook 38 full name of a file you want to use (possibly preceded by an `@'). 9.4. Customization options Here are explanations of what the various options do. Char- acter strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. Some options are persistent, and are saved and reloaded along with the game. Changing a persistent option in the config- uration file applies only to new games. acoustics Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio ca- pabilities. Persistent. align Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. The default is to randomly pick an appropriate alignment. If you prefix a `!' or ``no'' to the value, you can exclude that alignment from being picked randomly. Cannot be set with the `O' command. Persistent. autodig Automatically dig if you are wielding a digging tool and moving into a place that can be dug (default false). Persistent. autoopen Walking into a door attempts to open it (default true). Persis- tent. autopickup Automatically pick up things onto which you move (default on). Persistent. See pickup_types to refine the behavior. autoquiver This option controls what happens when you attempt the `f' (fire) command with an empty quiver (or quiver sack or have nothing at the ready). When true, the computer will fill your quiver or quiver sack or make ready some suitable weapon. Note that it will not take into account the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver or quiver sack or make ready with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is executed instead. Persis- tent. (default false) blind Start the character permanently blind. Persistent. (default false) NetHack 3.6 December 7, 2015 NetHack Guidebook 39 bones Allow saving and loading bones files. Persistent. (default true) boulder Set the character used to display boulders (default is rock class symbol). catname Name your starting cat (ex. ``catname:Morris''). Cannot be set with the `O' command. character Pick your type of character (ex. ``character:Monk''); synonym for ``role''. See ``name'' for an alternate method of specify- ing your role. Normally only the first letter of the value is examined; the string ``random'' is an exception. checkpoint Save game state after each level change, for possible recovery after program crash (default on). Persistent. checkspace Check free disk space before writing files to disk (default on). You may have to turn this off if you have more than 2 GB free space on the partition used for your save and level files. Only applies when MFLOPPY was defined during compilation. clicklook Allows looking at things on the screen by navigating the mouse over them and clicking the right mouse button (default off). cmdassist Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). confirm Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). Persistent. dark_room Show out-of-sight areas of lit rooms (default off). Persis- tent. disclose Controls what information the program reveals when the game ends. Value is a space separated list of prompting/category pairs (default is `ni na nv ng nc no', prompt with default re- sponse of `n' for each candidate). Persistent. The possibili- ties are: NetHack 3.6 December 7, 2015 NetHack Guidebook 40 i - disclose your inventory; a - disclose your attributes; v - summarize monsters that have been vanquished; g - list monster species that have been genocided; c - display your conduct; o - display dungeon overview. Each disclosure possibility can optionally be preceded by a prefix which lets you refine how it behaves. Here are the valid prefixes: y - prompt you and default to yes on the prompt; n - prompt you and default to no on the prompt; + - disclose it without prompting; - - do not disclose it and do not prompt. Omitted categories are implicitly added with `n' prefix. Spec- ified categories with omitted prefix implicitly use `+' prefix. Order of the disclosure categories does not matter, program display for end-of-game disclosure follows a set sequence. (ex. ``disclose:yi na +v -g o'') The example sets inventory to prompt and default to yes, attributes to prompt and default to no, vanquished to disclose without prompting, genocided to not disclose and not prompt, conduct to implicitly prompt and de- fault to no, and overview to disclose without prompting. Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. And the dun- geon overview shows all levels you had visited but does not re- veal things about them that you hadn't discovered. dogname Name your starting dog (ex. ``dogname:Fang''). Cannot be set with the `O' command. extmenu Changes the extended commands interface to pop-up a menu of available commands. It is keystroke compatible with the tradi- tional interface except that it does not require that you hit Enter. It is implemented only by the tty port (default off), when the game has been compiled to support tty graphics. female An obsolete synonym for ``gender:female''. Cannot be set with the `O' command. fixinv An object's inventory letter sticks to it when it's dropped (default on). If this is off, dropping an object shifts all the remaining inventory letters. Persistent. fruit Name a fruit after something you enjoy eating (ex. NetHack 3.6 December 7, 2015 NetHack Guidebook 41 ``fruit:mango'') (default ``slime mold''). Basically a nostal- gic whimsy that NetHack uses from time to time. You should set this to something you find more appetizing than slime mold. Apples, oranges, pears, bananas, and melons already exist in NetHack, so don't use those. gender Your starting gender (gender:male or gender:female). You may specify just the first letter. Although you can still denote your gender using the ``male'' and ``female'' options, the ``gender'' option will take precedence. The default is to ran- domly pick an appropriate gender. If you prefix a `!' or ``no'' to the value, you can exclude that gender from being picked randomly. Cannot be set with the `O' command. Persis- tent. help If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turn- ing help off makes just looking at things faster, since you aren't interrupted with the ``More info?'' prompt, but it also means that you might miss some interesting and/or important in- formation. Persistent. hilite_pet Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. hilite_pile Visually distinguish piles of objects from individual objects (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a small plus-symbol beside the object on the top of the pile. horsename Name your starting horse (ex. ``horsename:Trigger''). Cannot be set with the `O' command. ignintr Ignore interrupt signals, including breaks (default off). Per- sistent. implicit_uncursed Omit "uncursed" from inventory lists, if possible (default on). legacy Display an introductory message when starting the game (default on). Persistent. NetHack 3.6 December 7, 2015 NetHack Guidebook 42 lit_corridor Show corridor squares seen by night vision or a light source held by your character as lit (default off). Persistent. lootabc Use the old `a', `b', and `c' keyboard shortcuts when looting, rather than the mnemonics `o', `i', and `b' (default off). Persistent. mail Enable mail delivery during the game (default on). Persistent. male An obsolete synonym for ``gender:male''. Cannot be set with the `O' command. mention_walls Give feedback when walking against a wall (default off). menucolors Enable coloring menu lines (default off). See ``Configuring Menu Colors'' on how to configure the colors. menustyle Controls the interface used when you need to choose various ob- jects (in response to the Drop command, for instance). The value specified should be the first letter of one of the fol- lowing: traditional, combination, full, or partial. Tradi- tional was the only interface available for early versions; it consists of a prompt for object class characters, followed by an object-by-object prompt for all items matching the selected object class(es). Combination starts with a prompt for object class(es) of interest, but then displays a menu of matching ob- jects rather than prompting one-by-one. Full displays a menu of object classes rather than a character prompt, and then a menu of matching objects for selection. Partial skips the ob- ject class filtering and immediately displays a menu of all ob- jects. Persistent. menu_deselect_all Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '-'. menu_deselect_page Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. De- fault '\'. menu_first_page Menu character accelerator to jump to the first page in a menu. Implemented by the Amiga, Gem and tty ports. Default '^'. menu_headings Controls how the headings in a menu are highlighted. Values NetHack 3.6 December 7, 2015 NetHack Guidebook 43 are 'none', 'bold', 'dim', 'underline', 'blink', or 'inverse'. Not all ports can actually display all types. menu_invert_all Menu character accelerator to invert all items in a menu. Im- plemented by the Amiga, Gem, X11 and tty ports. Default '@'. menu_invert_page Menu character accelerator to invert all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default '~'. menu_last_page Menu character accelerator to jump to the last page in a menu. Implemented by the Amiga, Gem and tty ports. Default '|'. menu_next_page Menu character accelerator to goto the next menu page. Imple- mented by the Amiga, Gem and tty ports. Default '>'. menu_objsyms Show object symbols in menu headings in menus where the object symbols act as menu accelerators (default off). menu_previous_page Menu character accelerator to goto the previous menu page. Im- plemented by the Amiga, Gem and tty ports. Default '<'. menu_search Menu character accelerator to search for a menu item. Imple- mented by the Amiga, Gem, X11 and tty ports. Default ':'. menu_select_all Menu character accelerator to select all items in a menu. Im- plemented by the Amiga, Gem, X11 and tty ports. Default '.'. menu_select_page Menu character accelerator to select all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default ','. msghistory The number of top line messages to save (and recall with ^P) (default 20). Cannot be set with the `O' command. msg_window Allows you to change the way recalled messages are displayed. (It is currently implemented for tty only.) The possible val- ues are: s - single message (default; only choice prior to 3.4.0); c - combination, two messages as `single', then as `full'; f - full window, oldest message first; r - full window reversed, newest message first. NetHack 3.6 December 7, 2015 NetHack Guidebook 44 For backward compatibility, no value needs to be specified (which defaults to `full'), or it can be negated (which defaults to `single'). name Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of -A -B -C -H -K -M -P -Ra -Ro -S -T -V -W). If -@ is used for the role, then a random one will be automatically chosen. Cannot be set with the `O' command. news Read the NetHack news file, if present (default on). Since the news is shown at the beginning of the game, there's no point in setting this with the `O' command. nudist Start the character with no armor (default false). Persistent. null Send padding nulls to the terminal (default on). Persistent. number_pad Use digit keys instead of letters to move (default 0 or off). Valid settings are: 0 - move by letters; `yuhjklbn' 1 - move by numbers; digit `5' acts as `G' movement prefix 2 - like 1 but `5' works as `g' prefix instead of as `G' 3 - by numbers using phone key layout; 123 above, 789 below 4 - combines 3 with 2; phone layout plus MSDOS compatibility -1 - by letters but use `z' to go northwest, `y' to zap wands For backward compatibility, omitting a value is the same as specifying 1 and negating number_pad is the same as specifying 0. (Settings 2 and 4 are for compatibility with MSDOS or old PC Hack; in addition to the different behavior for `5', `Alt-5' acts as `G' and `Alt-0' acts as `I'. Setting -1 is to accommo- date some German keyboards which have the location of the `y' and `z' keys swapped.) When moving by numbers, to enter a count prefix for those commands which accept one (such as ``12s'' to search twelve times), precede it with the letter `n' (``n12s''). packorder Specify the order to list object types in (default ``")[%?+!=/(*`0_''). The value of this option should be a string containing the symbols for the various object types. Any omitted types are filled in at the end from the previous order. paranoid_confirmation A space separated list of specific situations where alternate NetHack 3.6 December 7, 2015 NetHack Guidebook 45 prompting is desired. The default is paranoid_confirma- tion:pray. Confirm - for any prompts which are set to require "yes" rather than 'y', also require "no" to reject instead of ac- cepting any non-yes response as no quit - require "yes" rather than 'y' to confirm quitting the game or switching into non-scoring explore mode; die - require "yes" rather than 'y' to confirm dying (not useful in normal play; applies to explore mode); bones - require "yes" rather than 'y' to confirm saving bones data when dying in debug mode; attack - require "yes" rather than 'y' to confirm attacking a peaceful monster; pray - require 'y' to confirm an attempt to pray rather than immediately praying; on by default; wand - require "yes" rather than 'y' to confirm breaking a wand; Remove - require selection from inventory for 'R' and 'T' com- mands even when wearing just one applicable item. By default, the pray choice is enabled, the others disabled. To disable it without setting any of the other choices, use ``paranoid_confirmation:none''. To keep it enabled while set- ting any of the others, include it in the list, such as ``para- noid_confirmation:attack pray Remove''. perm_invent If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that im- plement this feature. Persistent. pettype Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. Possible values are ``cat'', ``dog'', ``horse'', and ``none''. If the choice is not allowed for the role you are currently playing, it will be silently ig- nored. For example, ``horse'' will only be honored when play- ing a knight. Cannot be set with the `O' command. pickup_burden When you pick up an item that would exceed this encumbrance level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default `S'). Persistent. pickup_thrown If this option is on and autopickup is also on, try to pick up things that you threw, even if they aren't in pickup_types or match an autopickup exception. Default is on. Persistent. pickup_types Specify the object types to be picked up when autopickup is on. NetHack 3.6 December 7, 2015 NetHack Guidebook 46 Default is all types. You can use autopickup_exception config- uration file lines to further refine autopickup behavior. Per- sistent. pile_limit When walking across a pile of objects on the floor, threshold at which the message "there are few/several/many objects here" is given instead of showing a popup list of those objects. A value of 0 means "no limit" (always list the objects); a value of 1 effectively means "never show the objects" since the pile size will always be at least that big; default value is 5. Persistent. playmode Values are `normal', `explore', or `debug'. Allows selection of explore mode (also known as discovery mode) or debug mode (also known as wizard mode) instead of normal play. Debug mode might only be allowed for someone logged in under a particular user name (on multi-user systems) or specifying a particular character name (on single-user systems) or it might be disabled entirely. Requesting it when not allowed or not possible re- sults in explore mode instead. Default is normal play. pushweapon Using the `w' (wield) command when already wielding something pushes the old item into your alternate weapon slot (default off). Likewise for the `a' (apply) command if it causes the applied item to become wielded. Persistent. race Selects your race (for example, ``race:human''). Default is random. If you prefix a `!' or ``no'' to the value, you can exclude that race from being picked randomly. Cannot be set with the `O' command. Persistent. rest_on_space Make the space bar a synonym for the `.' (rest) command (de- fault off). Persistent. role Pick your type of character (ex. ``role:Samurai''); synonym for ``character''. See ``name'' for an alternate method of speci- fying your role. Normally only the first letter of the value is examined; `r' is an exception with ``Rogue'', ``Ranger'', and ``random'' values. If you prefix a `!' or ``no'' to the value, you can exclude that role from being picked randomly. Persistent. roguesymset This option may be used to select one of the named symbol sets found within ``symbols'' to alter the symbols displayed on the screen on the rogue level. NetHack 3.6 December 7, 2015 NetHack Guidebook 47 rlecomp When writing out a save file, perform run length compression of the map. Not all ports support run length compression. It has no effect on reading an existing save file. runmode Controls the amount of screen updating for the map window when engaged in multi-turn movement (running via shift+direction or control+direction and so forth, or via the travel command or mouse click). The possible values are: teleport - update the map after movement has finished; run - update the map after every seven or so steps; walk - update the map after each step; crawl - like walk, but pause briefly after each step. This option only affects the game's screen display, not the ac- tual results of moving. The default is `run'; versions prior to 3.4.1 used `teleport' only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. Persistent. safe_pet Prevent you from (knowingly) attacking your pets (default on). Persistent. scores Control what parts of the score list you are shown at the end (ex. ``scores:5 top scores/4 around my score/own scores''). Only the first letter of each category (`t', `a', or `o') is necessary. Persistent. showexp Show your accumulated experience points on bottom line (default off). Persistent. showrace Display yourself as the glyph for your race, rather than the glyph for your role (default off). Note that this setting af- fects only the appearance of the display, not the way the game treats you. Persistent. showscore Show your approximate accumulated score on bottom line (default off). Persistent. silent Suppress terminal beeps (default on). Persistent. sortloot Controls the sorting behavior of the pickup lists for inventory and #loot commands and some others. Persistent. The possible values are: NetHack 3.6 December 7, 2015 NetHack Guidebook 48 full - always sort the lists; loot - only sort the lists that don't use inventory letters, like with the #loot and pickup commands; none - show lists the traditional way without sorting. sortpack Sort the pack contents by type when displaying inventory (de- fault on). Persistent. sparkle Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). Per- sistent. standout Boldface monsters and ``--More--'' (default off). Persistent. statushilites Enable coloring of status fields (default off). See ``Config- uring Status Hilites'' for futher information. suppress_alert This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior versions (ex. ``suppress_alert:3.3.1''). symset This option may be used to select one of the named symbol sets found within ``symbols'' to alter the symbols displayed on the screen. time Show the elapsed game time in turns on bottom line (default off). Persistent. timed_delay When pausing momentarily for display effect, such as with ex- plosions and moving objects, use a timer rather than sending extra characters to the screen. (Applies to ``tty'' interface only; ``X11'' interface always uses a timer based delay. The default is on if configured into the program.) Persistent. tombstone Draw a tombstone graphic upon your death (default on). Persis- tent. toptenwin Put the ending display in a NetHack window instead of on stdout (default off). Setting this option makes the score list visi- ble when a windowing version of NetHack is started without a parent window, but it no longer leaves the score list around after game end on a terminal or emulating window. NetHack 3.6 December 7, 2015 NetHack Guidebook 49 travel Allow the travel command (default on). Turning this option off will prevent the game from attempting unintended moves if you make inadvertent mouse clicks on the map window. Persistent. verbose Provide more commentary during the game (default on). Persis- tent. windowtype Select which windowing system to use, such as ``tty'' or ``X11'' (default depends on version). Cannot be set with the `O' command. zerocomp When writing out a save file, perform zero-comp compression of the contents. Not all ports support zero-comp compression. It has no effect on reading an existing save file. 9.5. Window Port Customization options Here are explanations of the various options that are used to customize and change the characteristics of the windowtype that you have chosen. Character strings that are too long may be truncated. Not all window ports will adjust for all settings listed here. You can safely add any of these options to your config file, and if the window port is capable of adjusting to suit your preferences, it will attempt to do so. If it can't it will silently ignore it. You can find out if an option is sup- ported by the window port that you are currently using by check- ing to see if it shows up in the Options list. Some options are dynamic and can be specified during the game with the `O' com- mand. align_message Where to align or place the message window (top, bottom, left, or right) align_status Where to align or place the status window (top, bottom, left, or right). ascii_map NetHack should display an ascii character map if it can. color NetHack should display color if it can for different monsters, objects, and dungeon features eight_bit_tty NetHack should pass eight-bit character values (for example, specified with the traps option) straight through to your ter- minal (default off). NetHack 3.6 December 7, 2015 NetHack Guidebook 50 font_map NetHack should use a font by the chosen name for the map win- dow. font_menu NetHack should use a font by the chosen name for menu windows. font_message NetHack should use a font by the chosen name for the message window. font_status NetHack should use a font by the chosen name for the status window. font_text NetHack should use a font by the chosen name for text windows. font_size_map NetHack should use this size font for the map window. font_size_menu NetHack should use this size font for menu windows. font_size_message NetHack should use this size font for the message window. font_size_status NetHack should use this size font for the status window. font_size_text NetHack should use this size font for text windows. fullscreen NetHack should try and display on the entire screen rather than in a window. large_font NetHack should use a large font. map_mode NetHack should display the map in the manner specified. mouse_support Allow use of the mouse for input and travel. player_selection NetHack should pop up dialog boxes, or use prompts for charac- ter selection. popup_dialog NetHack should pop up dialog boxes for input. NetHack 3.6 December 7, 2015 NetHack Guidebook 51 preload_tiles NetHack should preload tiles into memory. For example, in the protected mode MSDOS version, control whether tiles get pre- loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. (de- fault on). Cannot be set with the `O' command. scroll_amount NetHack should scroll the display by this number of cells when the hero reaches the scroll_margin. scroll_margin NetHack should scroll the display when the hero or cursor is this number of cells away from the edge of the window. selectsaved NetHack should display a menu of existing saved games for the player to choose from at game startup, if it can. Not all ports support this option. softkeyboard Display an onscreen keyboard. Handhelds are most likely to support this option. splash_screen NetHack should display an opening splash screen when it starts up (default yes). tiled_map NetHack should display a tiled map if it can. tile_file Specify the name of an alternative tile file to override the default. tile_height Specify the preferred height of each tile in a tile capable port. tile_width Specify the preferred width of each tile in a tile capable port use_darkgray Use bold black instead of blue for black glyphs (TTY only). use_inverse NetHack should display inverse when the game specifies it. vary_msgcount NetHack should display this number of messages at a time in the message window. windowcolors NetHack should display windows with the specified NetHack 3.6 December 7, 2015 NetHack Guidebook 52 foreground/background colors if it can. wraptext NetHack port should wrap long lines of text if they don't fit in the visible area of the window. 9.6. Platform-specific Customization options Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. altkeyhandler Select an alternate keystroke handler dll to load (Win32 tty NetHack only). The name of the handler is specified without the .dll extension and without any path information. Cannot be set with the `O' command. altmeta On Amiga, this option controls whether typing `Alt' plus anoth- er key functions as a meta-shift for that key (default on). altmeta On other (non-Amiga) systems where this option is available, it can be set to tell nethack to convert a two character sequence beginning with ESC into a meta-shifted version of the second character (default off). This conversion is only done for commands, not for other input prompts. Note that typing one or more digits as a count prefix prior to a command--preceded by n if the number_pad option is set--is also subject to this conversion, so attempting to abort the count by typing ESC will leave nethack waiting for another character to complete the two character sequence. Type a sec- ond ESC to finish cancelling such a count. At other prompts a single ESC suffices. BIOS Use BIOS calls to update the screen display quickly and to read the keyboard (allowing the use of arrow keys to move) on ma- chines with an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack only). flush (default off, AMIGA NetHack only). MACgraphics (default on, Mac NetHack only). page_wait (default on, Mac NetHack only). rawio Force raw (non-cbreak) mode for faster output and more bullet- proof input (MS-DOS sometimes treats `^P' as a printer toggle NetHack 3.6 December 7, 2015 NetHack Guidebook 53 without it) (default off, OS/2, PC, and ST NetHack only). Note: DEC Rainbows hang if this is turned on. Cannot be set with the `O' command. soundcard (default on, PC NetHack only). Cannot be set with the `O' com- mand. subkeyvalue (Win32 tty NetHack only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate for international keyboard issues. OPTIONS=subkey- value:171/92 will return 92 to NetHack, if 171 was originally going to be returned. You can use multiple subkeyvalue state- ments in the config file if needed. Cannot be set with the `O' command. video Set the video mode used (PC NetHack only). Values are `autode- tect', `default', or `vga'. Setting `vga' (or `autodetect' with vga hardware present) will cause the game to display tiles. Cannot be set with the `O' command. videocolors Set the color palette for PC systems using NO_TERMS (default 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only). The order of colors is red, green, brown, blue, magenta, cyan, bright.white, bright.red, bright.green, yellow, bright.blue, bright.magenta, and bright.cyan. Cannot be set with the `O' command. videoshades Set the intensity level of the three gray scales available (de- fault dark normal light, PC NetHack only). If the game display is difficult to read, try adjusting these scales; if this does not correct the problem, try !color. Cannot be set with the `O' command. 9.7. Regular Expressions Regular expressions are normally POSIX extended regular ex- pressions. It is possible to compile NetHack without regular ex- pression support on a platform where there is no regular expres- sion library. While this is not true of any modern platform, if your NetHack was built this way, patterns are instead glob pat- terns. 9.8. Configuring Autopickup Exceptions You can further refine the behavior of the autopickup option beyond what is available through the pickup_types option. By placing autopickup_exception lines in your configuration file, you can define patterns to be checked when the game is NetHack 3.6 December 7, 2015 NetHack Guidebook 54 about to autopickup something. autopickup_exception Sets an exception to the pickup_types option. The autopick- up_exception option should be followed by a regular expression to be used as a pattern to match against the singular form of the description of an object at your location. In addition, some characters are treated specially if they oc- cur as the first character in the pattern, specifically: < - always pickup an object that matches rest of pattern; > - never pickup an object that matches rest of pattern. A `never pickup' rule takes precedence over an `always pickup' rule if both match. Exceptions can be set with the `O' command, but ones set that way will not be preserved across saves and restores. Here are some examples: autopickup_exception="<*arrow" autopickup_exception=">*corpse" autopickup_exception=">* cursed*" The first example above will result in autopickup of any type of arrow. The second example results in the exclusion of any corpse from autopickup. The last example results in the ex- clusion of items known to be cursed from autopickup. 9.9. Configuring Message Types You can change the way the messages are shown in the message area, when the message matches a user-defined pattern. In general, the config file entries to configure the message types look like this: MSGTYPE=type "pattern" type - how the message should be shown; pattern - the pattern to match. The pattern should be a regular expression. Allowed types are: show - show message normally. hide - never show the message. stop - wait for user with more-prompt. norep - show the message once, but not again if no other message is shown in between. Here's an example of message types using NetHack's internal pattern matching facility: NetHack 3.6 December 7, 2015 NetHack Guidebook 55 MSGTYPE=stop "You feel hungry." MSGTYPE=hide "You displaced *." specifies that whenever a message "You feel hungry" is shown, the user is prompted with more-prompt, and a message matching "You displaced ." is not shown at all. The order of the defined MSGTYPE-lines is important; the last matching rule is used. Put the general case first, exceptions below them. 9.10. Configuring Menu Colors Some platforms allow you to define colors used in menu lines when the line matches a user-defined pattern. At this time the tty, win32tty and win32gui support this. In general, the config file entries to configure the menu color mappings look like this: MENUCOLOR="pattern"=color&attribute pattern - the pattern to match; color - the color to use for lines matching the pat- tern; attribute - the attribute to use for lines matching the pattern. The attribute is optional, and if left out, you must also leave out the preced- ing ampersand. If no attribute is defined, no attribute is used. The pattern should be a regular expression. Allowed colors are black, red, green, brown, blue, magenta, cyan, gray, orange, lightgreen, yellow, lightblue, lightmagen- ta, lightcyan, and white. Allowed attributes are none, bold, dim, underline, blink, and inverse. Note that the platform used may interpret the at- tributes any way it wants. Here's an example of menu colors using NetHack's internal pat- tern matching facility: MENUCOLOR="* blessed *"=green MENUCOLOR="* cursed *"=red MENUCOLOR="* cursed *(being worn)"=red&underline specifies that any menu line with " blessed " contained in it will be shown in green color, lines with " cursed " will be shown in red, and lines with " cursed " followed by "(being worn)" on the same line will be shown in red color and under- lined. You can have multiple MENUCOLOR entries in your config file, and the last MENUCOLOR-line in your config file that NetHack 3.6 December 7, 2015 NetHack Guidebook 56 matches a menu line will be used for the line. Note that if you intend to have one or more color specifica- tions match " uncursed ", you will probably want to turn the im- plicit_uncursed option off so that all items known to be uncursed are actually displayed with the ``uncursed'' description. 9.11. Configuring User Sounds Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. The following config file entries are relevant to mapping user sounds to messages: SOUNDDIR The directory that houses the sound files to be played. SOUND An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: MESG - message window mapping (the only one supported in 3.6); pattern - the pattern to match; sound file - the sound file to play; volume - the volume to be set while playing the sound file. The pattern should be a POSIX extended regular expression. 9.12. Configuring Status Hilites Your copy of NetHack may have been compiled with support for ``Status Hilites''. If so, you can customize your game display by setting thresholds to change the color or appearance of fields in the status display. For example, the following line in your config file will cause the hitpoints field to display in the color red if your hitpoints drop to or below a threshold of 30%: OPTION=hilite_status: hitpoints/30%/red/normal For another example, the following line in your config file will cause wisdom to be displayed red if it drops and green if it rises. OPTION=hilite_status: wisdom/updown/red/green You can adjust the display of the following status fields: NetHack 3.6 December 7, 2015 NetHack Guidebook 57 title strength dexterity constitution intelligence wisdom charisma alignment score carrying-capacity gold power power-max experience-level armor-class HD time hunger hitpoints hitpoints-max dungeon-level experience condition Allowed colors are black, red, green, brown, blue, magenta, cyan, gray, orange, lightgreen, yellow, lightblue, lightmagen- ta, lightcyan, and white. Allowed attributes are bold, inverse, normal. Note that the platform used may interpret the attributes any way it wants. Behaviours can occur based on percentage thresholds, updown, or absolute values. The in-game options menu can help you deter- mine the correct syntax for a config file. The whole feature can be disabled by setting option sta- tushilites off. 9.13. Modifying NetHack Symbols NetHack can load entire symbol sets from the symbol file. The options that are used to select a particular symbol set from the symbol file are: symset Set the name of the symbol set that you want to load. roguesymset Set the name of the symbol set that you want to load for dis- play on the rogue level. You can also override one or more symbols using the SYMBOLS config file option. Symbols are specified as name:value pairs. Note that NetHack escape-processes the value string in conven- tional C fashion. This means that \ is a prefix to take the fol- lowing character literally. Thus \ needs to be represented as \\. The special escape form \m switches on the meta bit in the symbol value, and the \^ prefix causes the following character to be treated as a control character. NetHack Symbols Default Symbol Name Description ------------------------------------------------------------------------ S_air (air) _ S_altar (altar) " S_amulet (amulet) A S_angel (angelic being) NetHack 3.6 December 7, 2015 NetHack Guidebook 58 a S_ant (ant or other insect) ^ S_anti_magic_trap (anti-magic field) [ S_armor (suit or piece of armor) [ S_armour (suit or piece of armor) ^ S_arrow_trap (arrow trap) 0 S_ball (iron ball) # S_bars (iron bars) B S_bat (bat or bird) ^ S_bear_trap (bear trap) - S_blcorn (bottom left corner) b S_blob (blob) + S_book (spellbook) ) S_boomleft (boomerang open left) ( S_boomright (boomerang open right) ` S_boulder (boulder) - S_brcorn (bottom right corner) C S_centaur (centaur) _ S_chain (iron chain) # S_cloud (cloud) c S_cockatrice (cockatrice) $ S_coin (pile of coins) # S_corr (corridor) - S_crwall (wall) ^ S_dart_trap (dart trap) & S_demon (major demon) * S_digbeam (dig beam) > S_dnladder (ladder down) > S_dnstair (staircase down) d S_dog (dog or other canine) D S_dragon (dragon) ; S_eel (sea monster) E S_elemental (elemental) / S_explode1 (explosion top left) - S_explode2 (explosion top center) `\' S_explode3 (explosion top right) | S_explode4 (explosion middle left) S_explode5 (explosion middle center) | S_explode6 (explosion middle right) `\' S_explode7 (explosion bottom left) - S_explode8 (explosion bottom center) / S_explode9 (explosion bottom right) e S_eye (eye or sphere) ^ S_falling_rock_trap (falling rock trap) f S_feline (cat or other feline) ^ S_fire_trap (fire trap) ! S_flashbeam (flash beam) % S_food (piece of food) { S_fountain (fountain) F S_fungus (fungus or mold) * S_gem (gem or rock) S_ghost (ghost) H S_giant (giant humanoid) G S_gnome (gnome) NetHack 3.6 December 7, 2015 NetHack Guidebook 59 ' S_golem (golem) | S_grave (grave) g S_gremlin (gremlin) - S_hbeam (wall) # S_hcdbridge (horizontal raised drawbridge) + S_hcdoor (closed door) | S_hodoor (open door) ^ S_hole (hole) @ S_human (human or elf) h S_humanoid (humanoid) - S_hwall (horizontal wall) i S_imp (imp or minor demon) J S_jabberwock (jabberwock) j S_jelly (jelly) k S_kobold (kobold) K S_kop (Keystone Kop) ^ S_land_mine (land mine) } S_lava (molten lava) l S_leprechaun (leprechaun) ^ S_level_teleporter (level teleporter) L S_lich (lich) y S_light (light) # S_litcorr (lit corridor) : S_lizard (lizard) `\' S_lslant (wall) ^ S_magic_portal (magic portal) ^ S_magic_trap (magic trap) m S_mimic (mimic) ] S_mimic_def (mimic) M S_mummy (mummy) N S_naga (naga) n S_nymph (nymph) O S_ogre (ogre) o S_orc (orc) p S_piercer (piercer) ^ S_pit (pit) # S_poisoncloud (poison cloud) ^ S_polymorph_trap (polymorph trap) } S_pool (water) ! S_potion (potion) P S_pudding (pudding or ooze) q S_quadruped (quadruped) Q S_quantmech (quantum mechanic) = S_ring (ring) ` S_rock (boulder or statue) r S_rodent (rodent) ^ S_rolling_boulder_trap (rolling boulder trap) / S_rslant (wall) ^ S_rust_trap (rust trap) R S_rustmonst (rust monster or disenchanter) ? S_scroll (scroll) # S_sink (sink) ^ S_sleeping_gas_trap (sleeping gas trap) NetHack 3.6 December 7, 2015 NetHack Guidebook 60 S S_snake (snake) s S_spider (arachnid or centipede) ^ S_spiked_pit (spiked pit) ^ S_squeaky_board (squeaky board) 0 S_ss1 (magic shield 1 of 4) # S_ss2 (magic shield 2 of 4) @ S_ss3 (magic shield 3 of 4) * S_ss4 (magic shield 4 of 4) ^ S_statue_trap (statue trap) S_stone (dark part of a room) - S_sw_bc (swallow bottom center) `\' S_sw_bl (swallow bottom left) / S_sw_br (swallow bottom right) | S_sw_ml (swallow middle left) | S_sw_mr (swallow middle right) - S_sw_tc (swallow top center) / S_sw_tl (swallow top left) `\' S_sw_tr (swallow top right) - S_tdwall (wall) ^ S_teleportation_trap (teleportation trap) S_throne (opulent throne) - S_tlcorn (top left corner) | S_tlwall (wall) ( S_tool (useful item (pick-axe key lamp...)) ^ S_trap_door (trap door) t S_trapper (trapper or lurker above) - S_trcorn (top right corner) # S_tree (tree) T S_troll (troll) | S_trwall (wall) - S_tuwall (wall) U S_umber (umber hulk) u S_unicorn (unicorn or horse) < S_upladder (ladder up) < S_upstair (staircase up) V S_vampire (vampire) | S_vbeam (wall) # S_vcdbridge (vertical raised drawbridge) + S_vcdoor (closed door) ^ S_vibrating_square (vibrating square) - S_vodoor (open door) v S_vortex (vortex) | S_vwall (vertical wall) / S_wand (wand) } S_water (water) ) S_weapon (weapon) " S_web (web) w S_worm (worm) ~ S_worm_tail (long worm tail) W S_wraith (wraith) x S_xan (xan or other mythical/fantastic insect) X S_xorn (xorn) Y S_yeti (apelike creature) NetHack 3.6 December 7, 2015 NetHack Guidebook 61 Z S_zombie (zombie) z S_zruty (zruty) 9.14. Configuring NetHack for Play by the Blind NetHack can be set up to use only standard ASCII characters for making maps of the dungeons. This makes the MS-DOS versions of NetHack completely accessible to the blind who use speech and/or Braille access technologies. Players will require a good working knowledge of their screen-reader's review features, and will have to know how to navigate horizontally and vertically character by character. They will also find the search capabili- ties of their screen-readers to be quite valuable. Be certain to examine this Guidebook before playing so you have an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your charac- ter since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. While it is not difficult for experienced users to edit the defaults.nh file to accomplish this, novices may find this task somewhat daunting. Included within the ``symbols'' file of all official distributions of NetHack is a symset called NHAccess. Selecting that symset in your configuration file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings via SYMBOLS= in your configuration file to better suit your preferences. The most crucial settings to make the game accessible are: symset:NHAccess Load a symbol set appropriate for use by blind players. roguesymset:NHAccess Load a symbol set for the rogue level that is appropriate for use by blind players. menustyle:traditional This will assist in the interface to speech synthesizers. number_pad A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number_pad option and use the traditional Rogue-like commands. 9.15. Global Configuration for System Administrators If NetHack is compiled with the SYSCF option, a system ad- ministrator should set up a global configuration; this is a file in the same format as the traditional per-user configuration file NetHack 3.6 December 7, 2015 NetHack Guidebook 62 (see above). This file should be named sysconf and placed in the same directory as the other NetHack support files. The options recognized in this file are listed below. Any option not set us- es a compiled-in default (which may not be appropriate for your system). WIZARDS A space-separated list of user names who are allowed to play in wizard mode (the debugging mode, not the magic-using role). A value of a single asterisk (*) allows anyone to start a game in wizard mode. SHELLERS A list of users who are allowed to use the shell es- cape command (!). The syntax is the same as WIZARDS. EXPLORERS A list of users who are allowed to use the explore mode. The syntax is the same as WIZARDS. MAXPLAYERS Limit the maximum number of games that can be run- ning at the same time. SUPPORT A string explaining how to get local support (no de- fault value). RECOVER A string explaining how to recover a game on this sys- tem (no default value). SEDUCE 0 or 1 to disable or enable, respectively, the SEDUCE option (see the source for details on this function). CHECK_SAVE_UID 0 or 1 to disable or enable, respectively, the UID checking for savefiles. The following options affect the score file: PERSMAX Maximum number of entries for one person. ENTRYMAX Maximum number of entries in the score file. POINTSMIN Minimum number of points to get an entry in the score file. PERS_IS_UID 0 or 1 to use user names or numeric userids, re- spectively, to identify unique people for the score file. MAX_STATUENAME_RANK Maximum number of score file entries to use for random statue names (default is 10). 10. Scoring NetHack maintains a list of the top scores or scorers on your machine, depending on how it is set up. In the latter case, each account on the machine can post only one non-winning score on this list. If you score higher than someone else on this list, or better your previous score, you will be inserted in the NetHack 3.6 December 7, 2015 NetHack Guidebook 63 proper place under your current name. How many scores are kept can also be set up when NetHack is compiled. Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will only hear about 90% of your gold when your corpse is discovered (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. If you just want to see what the current top players/games list is, you can type nethack -s all on most versions. 11. Explore mode NetHack is an intricate and difficult game. Novices might falter in fear, aware of their ignorance of the means to survive. Well, fear not. Your dungeon comes equipped with an ``explore'' or ``discovery'' mode that enables you to keep old save files and cheat death, at the paltry cost of not getting on the high score list. There are two ways of enabling explore mode. One is to start the game with the -X command-line switch or with the play- mode:explore option. The other is to issue the ``#exploremode'' extended command while already playing the game. Starting a new game in explore mode provides your character with a wand of wish- ing in initial inventory; switching during play does not. The other benefits of explore mode are left for the trepid reader to discover. 11.1. Debug mode Debug mode, also known as wizard mode, is undocumented aside from this brief description. It is intended for tracking down problems within the program rather than to provide god-like pow- ers to your character, and players who attempt debugging are ex- pected to figure out how to use it themselves. It is initiated by starting the game with the -D command-line switch or with the playmode:debug option. For some systems, the player must be logged in under a par- ticular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the Wizard role). And on any system, the program might have been configured to omit debug mode entirely. Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. NetHack 3.6 December 7, 2015 NetHack Guidebook 64 12. Credits The original hack game was modeled on the Berkeley UNIX rogue game. Large portions of this paper were shamelessly cribbed from A Guide to the Dungeons of Doom, by Michael C. Toy and Kenneth C. R. C. Arnold. Small portions were adapted from Further Exploration of the Dungeons of Doom, by Ken Arromdee. NetHack is the product of literally dozens of people's work. Main events in the course of the game development are described below: Jay Fenlason wrote the original Hack, with help from Kenny Woodland, Mike Thome and Jon Payne. Andries Brouwer did a major re-write, transforming Hack into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for UNIX machines to the Usenet. Don G. Kneller ported Hack 1.0.3 to Microsoft C and MS-DOS, producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more ver- sions (3.0, 3.2, 3.51, and 3.6). R. Black ported PC HACK 3.51 to Lattice C and the Atari 520/1040ST, producing ST Hack 1.03. Mike Stephenson merged these various versions back together, incorporating many of the added features, and produced NetHack 1.4. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Later, Mike coordinated a major rewrite of the game, heading a team which included Ken Arromdee, Jean-Christophe Collet, Steve Creps, Eric Hendrickson, Izchak Miller, John Rupley, Mike Threep- oint, and Janet Walz, to produce NetHack 3.0c. NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by Timo Hakulinen, and to VMS by David Gentzel. The three of them and Kevin Darcy later joined the main development team to produce subsequent revisions of 3.0. Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm Meluch, Stephen Spackman and Pierre Martineau designed overlay code for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. Headed by Mike Stephenson and coordinated by Izchak Miller and Janet Walz, the development team which now included Ken Ar- romdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric NetHack 3.6 December 7, 2015 NetHack Guidebook 65 Raymond, and Eric Smith undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced NetHack 3.1. Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga. Norm Meluch and Kevin Smolkowski, with help from Carl Sche- lin, Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC. Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke, and Andy Swanson, developed NetHack 3.1 for the Macintosh, porting it for MPW. Building on their de- velopment, Barton House added a Think C port. Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith port- ed NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua Delahunty, was responsible for the VMS version of NetHack 3.1. Michael Allison ported NetHack 3.1 to Windows NT. Dean Luick, with help from David Cohrs, developed NetHack 3.1 for X11. Warwick Allison wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. The 3.2 development team, comprised of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2 in April of 1996. Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team re- mained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, Dr. Izchak Miller, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. During the lifespan of NetHack 3.1 and 3.2, several enthusi- asts of the game added their own modifications to the game and made these ``variants'' publicly available: Tom Proudfoot and Yuval Oren created NetHack++, which was quickly renamed NetHack--. Working independently, Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and War- wick Allison improved the spell casting system with the Wizard NetHack 3.6 December 7, 2015 NetHack Guidebook 66 Patch. Warwick Allison also ported NetHack to use the Qt inter- face. Warren Cheung combined SLASH with the Wizard Patch to pro- duce Slash'em, and with the help of Kevin Hugo, added more fea- tures. Kevin later joined the DevTeam and incorporated the best of these ideas in NetHack 3.3. The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. The 3.3 development team, consisting of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in pref- erence to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbar- ians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. The 3.4 development team initially consisted of Michael Al- lison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul Winner, with Warwick Allison joining just before the re- lease of NetHack 3.4.0 in March 2002. As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that NetHack runs on: Pat Rankin maintained 3.4 for VMS. Michael Allison maintained NetHack 3.4 for the MS-DOS plat- form. Paul Winner and Yitzhak Sapir provided encouragement. Dean Luick, Mark Modrall, and Kevin Hugo maintained and en- hanced the Macintosh port of 3.4. Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows platform. Alex Kompel contributed a new graphical inter- face for the Windows port. Alex Kompel also contributed a NetHack 3.6 December 7, 2015 NetHack Guidebook 67 Windows CE port for 3.4.1. Ron Van Iwaarden was the sole maintainer of NetHack for OS/2 the past several releases. Unfortunately Ron's last OS/2 machine stopped working in early 2006. A great many thanks to Ron for keeping NetHack alive on OS/2 all these years. Janne Salmijarvi and Teemu Suikki maintained and enhanced the Amiga port of 3.4 after Janne Salmijarvi resurrected it for 3.3.1. Christian ``Marvin'' Bressler maintained 3.4 for the Atari after he resurrected it for 3.3.1. The release of NetHack 3.4.3 in December 2003 marked the be- ginning of a long release hiatus. 3.4.3 proved to be a remarkably stable version that provided continued enjoyment by the community for more than a decade. The devteam slowly and quietly continued to work on the game behind the scenes during the tenure of 3.4.3. It was during that same period that several new variants emerged within the NetHack community. Notably sporkhack by Derek S. Ray, unnethack by Patric Mueller, nitrohack and its successors origi- nally by Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. Some of those variants continue to be developed, maintained, and enjoyed by the community to this day. At the beginning of development for what would eventually get released as 3.6.0, the development team consisted of Warwick Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie Col- let, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul Winner. Leading up to the release of 3.6.0 in early 2015, new members Sean Hunt, Pasi Kallinen, and Derek S. Ray joined the NetHack development team. In September 2014, an interim snapshot of the code under de- velopment was released publicly by other parties. Since that code was a work-in-progress and had not gone through the process of debugging it as a suitable release, it was decided that the ver- sion numbers present on that code snapshot would be retired and never used in an official NetHack release. An announcement was posted on the devteam's official nethack.org website to that ef- fect, stating that there would never be a 3.4.4, 3.5, or 3.5.0 official release version. In November 2014, preparation began for the release of NetHack 3.6. The 3.6 version merges work done by the development team since the previous release with some of the beloved communi- ty patches. Many bugs were fixed and a large amount of code was restructured. The development team, as well as Steve VanDevender and Kevin Smolkowski ensured that NetHack 3.6.0 continued to operate on various Unix flavors and maintained the X11 interface. NetHack 3.6 December 7, 2015 NetHack Guidebook 68 Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick main- tained the port of NetHack 3.6.0 for Mac. Michael Allison, Derek S. Ray, Yitzhak Sapir, Alex Kompel, and Dion Nicolaas maintained the port of NetHack 3.6.0 for Mi- crosoft Windows. The official NetHack web site is maintained by Ken Lorber at http://www.nethack.org/. SHOUT-OUTS The devteam would like to give a special "shout-out" to thank the generous people primarily responsible for the public NetHack servers available for playing the game at nethack.alt.org and devnull.net. In addition to providing a way for the public to play a game of NetHack from almost anywhere, they have hosted an- nual NetHack tournaments for many, many years. On behalf of the NetHack community, thank you very much to M. Drew Streib, Pasi Kallinen and Robin Bandy. - - - - - - - - - - From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: Adam Aronow Janet Walz Nathan Eady Alex Kompel Janne Salmijarvi Norm Meluch Andreas Dorn Jean-Christophe Collet Olaf Seibert Andy Church Jeff Bailey Pasi Kallinen Andy Swanson Jochen Erwied Pat Rankin Ari Huttunen John Kallen Paul Winner Barton House John Rupley Pierre Martineau Benson I. Margulies John S. Bien Ralf Brown Bill Dyer Johnny Lee Ray Chason Boudewijn Waijers Jon W{tte Richard Addison Bruce Cox Jonathan Handler Richard Beigel Bruce Holloway Joshua Delahunty Richard P. Hughey Bruce Mewborne Keizo Yamamoto Rob Menke Carl Schelin Ken Arnold Robin Bandy Chris Russo Ken Arromdee Robin Johnson David Cohrs Ken Lorber Roderick Schertler David Damerell Ken Washikita Roland McGrath David Gentzel Kevin Darcy Ron Van Iwaarden David Hairston Kevin Hugo Ronnen Miller Dean Luick Kevin Sitze Ross Brown Del Lamb Kevin Smolkowski Sascha Wostmann Derek S. Ray Kevin Sweet Scott Bigham Deron Meranda Lars Huttar Scott R. Turner NetHack 3.6 December 7, 2015 NetHack Guidebook 69 Dion Nicolaas Leon Arnott Sean Hunt Dylan O'Donnell M. Drew Streib Stephen Spackman Eric Backus Malcolm Ryan Stefan Thielscher Eric Hendrickson Mark Gooderum Stephen White Eric R. Smith Mark Modrall Steve Creps Eric S. Raymond Marvin Bressler Steve Linhart Erik Andersen Matthew Day Steve VanDevender Frederick Roeber Merlyn LeRoy Teemu Suikki Gil Neiger Michael Allison Tim Lennan Greg Laskin Michael Feir Timo Hakulinen Greg Olson Michael Hamel Tom Almy Gregg Wonderly Michael Sokolov Tom West Hao-yang Wang Mike Engber Warren Cheung Helge Hafting Mike Gallop Warwick Allison Irina Rempt-Drijfhout Mike Passaretti Yitzhak Sapir Izchak Miller Mike Stephenson J. Ali Harlow Mikko Juola Brand and product names are trademarks or registered trademarks of their respective holders. NetHack 3.6 December 7, 2015 nethack-3.6.0/doc/dgn_comp.60000664000076400007660000001614312536476415014601 0ustar paxedpaxed.TH DGN_COMP 6 "12 Dec 1995" .\" NetHack 3.6 dgn_comp.6 $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ .UC 4 .SH NAME dgn_comp \- NetHack dungeon compiler .SH SYNOPSIS .B dgn_comp [ .I file ] .PP If no arguments are given, it reads standard input. .SH DESCRIPTION .PP .I Dgn_comp is a dungeon compiler for NetHack version 3.2 and higher. It takes a description file as an argument and produces a dungeon "script" that is to be loaded by NetHack at runtime. .PP The purpose of this tool is to provide NetHack administrators and implementors with a convenient way to create a custom dungeon for the game, without having to recompile the entire world. .SH GRAMMAR .PP DUNGEON: .B name .B bonesmarker ( .B base , .B rand ) [ .B %age ] .PP where .B name is the dungeon name, .B bonesmarker is a letter for marking bones files, ( .B base , .B rand ) is the number of levels, and .B %age is its percentage chance of being generated (if absent, 100% chance). DESCRIPTION: .B tag .PP where .B tag is currently one of .BR HELLISH , .BR MAZELIKE , or .BR ROGUELIKE . ALIGNMENT | LEVALIGN: [ .B lawful | .B neutral | .B chaotic | .B unaligned ] .PP gives the alignment of the dungeon/level (default is unaligned). ENTRY: .B level .PP the dungeon entry point. The dungeon connection attaches at this level of the given dungeon. If the value of .B level is negative, the entry level is calculated from the bottom of the dungeon, with -1 being the last level. If this line is not present in a dungeon description, the entry level defaults to 1. PROTOFILE: .B name .PP the prototypical name for dungeon level files in this dungeon. For example, the PROTOFILE name for the dungeon .I Vlad's Tower is .IR tower . LEVEL: .B name .B bonesmarker @ ( .B base , .B rand ) [ .B %age ] .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, ( .B base , .B rand ) is the location and .B %age is the generation percentage, as above. RNDLEVEL: .B name .B bonesmarker @ ( .B base , .B rand ) [ .B %age ] .B rndlevs .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, ( .B base , .B rand ) is the location, .B %age is the generation percentage, as above, and .B rndlevs is the number of similar levels available to choose from. CHAINLEVEL: .B name .B bonesmarker .B prev_name + ( .B base , .B rand ) [ .B %age ] .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, .B prev_name is the name of a level defined previously, ( .B base , .B rand ) is the .I offset from the level being chained from, and .B %age is the generation percentage. RNDCHAINLEVEL: .B name .B bonesmarker .B prev_name + ( .B base , .B rand ) [ .B %age ] .B rndlevs .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, .B prev_name is the name of a level defined previously, ( .B base , .B rand ) is the .I offset from the level being chained from, .B %age is the generation percentage, and .B rndlevs is the number of similar levels available to choose from. LEVELDESC: .B type .PP where .B type is the level type, (see DESCRIPTION, above). The .B type is used to override any pre-set value used to describe the entire dungeon, for this level only. BRANCH: .B name @ ( .B base , .B rand ) [ .B stair | .B no_up | .B no_down | .B portal ] [ .B up | .B down ] .PP where .B name is the name of the dungeon to branch to, and ( .B base , .B rand ) is the location of the branch. The last two optional arguments are the branch type and branch direction. The type of a branch can be a two-way stair connection, a one-way stair connection, or a magic portal. A one-way stair is described by the types .B no_up and .B no_down which specify which stair direction is missing. The default branch type is .BR stair . The direction for a stair can be either up or down; direction is not applicable to portals. The default direction is .BR down . CHAINBRANCH: .B name .B prev_name + ( .B base , .B rand ) [ .B stair | .B no_up | .B no_down | .B portal ] [ .B up | .B down ] .PP where .B name is the name of the dungeon to branch to, .B prev_name is the name of a previously defined .B level and ( .B base , .B rand ) is the .I offset from the level being chained from. The optional branch type and direction are the same as described above. .SH GENERIC RULES .PP Each dungeon must have a unique .B bonesmarker , and each special level must have a .B bonesmarker unique within its dungeon (letters may be reused in different dungeons). If the .B bonesmarker has the special value "none", no bones files will be created for that level or dungeon. .PP The value .B base may be in the range of 1 to .B MAXLEVEL (as defined in .I global.h ). .PP The value .B rand may be in the range of -1 to .BR MAXLEVEL . .PP If .B rand is -1 it will be replaced with the value (num_dunlevs(dungeon) - base) during the load process (ie. from here to the end of the dungeon). .PP If .B rand is 0 the level is located absolutely at .BR base . .PP Branches don't have a probability. Dungeons do. If a dungeon fails to be generated during load, all its levels and branches are skipped. .PP No level or branch may be chained from a level with a percentage generation probability. This is to prevent non-resolution during the load. In addition, no branch may be made from a dungeon with a percentage generation probability for the same reason. .PP As a general rule using the dungeon compiler: .PP If a dungeon has a .B protofile name associated with it .RI ( eg. .BR tower ) that file will be used. .PP If a special level is present, it will override the above rule and the appropriate file will be loaded. .PP If neither of the above are present, the standard generator will take over and make a "normal" level. .PP A level alignment, if present, will override the alignment of the dungeon that it exists within. .SH EXAMPLE .PP Here is the current syntax of the dungeon compiler's "language": .LP .nf .ta +8n +8n +8n # # The dungeon description file for the "standard" original # 3.0 NetHack. # DUNGEON: "The Dungeons of Doom" "D" (25, 5) LEVEL: "rogue" "none" @ (15, 4) LEVEL: "oracle" "none" @ (5, 7) LEVEL: "bigroom" "B" @ (12, 3) 15 LEVEL: "medusa" "none" @ (20, 5) CHAINLEVEL: "castle" "medusa" + (1, 4) CHAINBRANCH: "Hell" "castle" + (0, 0) no_down BRANCH: "The Astral Plane" @ (1, 0) no_down up DUNGEON: "Hell" "H" (25, 5) DESCRIPTION: mazelike DESCRIPTION: hellish BRANCH: "Vlad's Tower" @ (13, 5) up LEVEL: "wizard" "none" @ (15, 10) LEVEL: "fakewiz" "A" @ (5, 5) LEVEL: "fakewiz" "B" @ (10, 5) LEVEL: "fakewiz" "C" @ (15, 5) LEVEL: "fakewiz" "D" @ (20, 5) LEVEL: "fakewiz" "E" @ (25, 5) DUNGEON: "Vlad's Tower" "T" (3, 0) PROTOFILE: "tower" DESCRIPTION: mazelike ENTRY: -1 DUNGEON: "The Astral Plane" "A" (1, 0) DESCRIPTION: mazelike PROTOFILE: "endgame" .fi .PP .I NOTES: .br Lines beginning with '#' are considered comments. .br A special level must be explicitly aligned. The alignment of the dungeon it is in only applies to non-special levels within that dungeon. .SH AUTHOR .PP M. Stephenson (from the level compiler by Jean-Christophe Collet). .SH "SEE ALSO" .PP lev_comp(6), nethack(6) .SH BUGS .PP Probably infinite. nethack-3.6.0/doc/dgn_comp.txt0000664000076400007660000002045412467321052015240 0ustar paxedpaxed DGN_COMP(6) 1995 DGN_COMP(6) NAME dgn_comp - NetHack dungeon compiler SYNOPSIS dgn_comp [ file ] If no arguments are given, it reads standard input. DESCRIPTION Dgn_comp is a dungeon compiler for NetHack version 3.2 and higher. It takes a description file as an argument and pro- duces a dungeon "script" that is to be loaded by NetHack at runtime. The purpose of this tool is to provide NetHack administra- tors and implementors with a convenient way to create a cus- tom dungeon for the game, without having to recompile the entire world. GRAMMAR DUNGEON: name bonesmarker ( base , rand ) [ %age ] where name is the dungeon name, bonesmarker is a letter for marking bones files, ( base , rand ) is the number of lev- els, and %age is its percentage chance of being generated (if absent, 100% chance). DESCRIPTION: tag where tag is currently one of HELLISH, MAZELIKE, or ROGUE- LIKE. ALIGNMENT | LEVALIGN: [ lawful | neutral | chaotic | unaligned ] gives the alignment of the dungeon/level (default is unaligned). ENTRY: level the dungeon entry point. The dungeon connection attaches at this level of the given dungeon. If the value of level is negative, the entry level is calculated from the bottom of the dungeon, with -1 being the last level. If this line is not present in a dungeon description, the entry level defaults to 1. PROTOFILE: name the prototypical name for dungeon level files in this dungeon. For example, the PROTOFILE name for the dungeon Vlad's Tower is tower. Dec Last change: 12 1 DGN_COMP(6) 1995 DGN_COMP(6) LEVEL: name bonesmarker @ ( base , rand ) [ %age ] where name is the level name, bonesmarker is a letter for marking bones files, ( base , rand ) is the location and %age is the generation percentage, as above. RNDLEVEL: name bonesmarker @ ( base , rand ) [ %age ] rndlevs where name is the level name, bonesmarker is a letter for marking bones files, ( base , rand ) is the location, %age is the generation percentage, as above, and rndlevs is the number of similar levels available to choose from. CHAINLEVEL: name bonesmarker prev_name + ( base , rand ) [ %age ] where name is the level name, bonesmarker is a letter for marking bones files, prev_name is the name of a level defined previously, ( base , rand ) is the offset from the level being chained from, and %age is the generation percen- tage. RNDCHAINLEVEL: name bonesmarker prev_name + ( base , rand ) [ %age ] rndlevs where name is the level name, bonesmarker is a letter for marking bones files, prev_name is the name of a level defined previously, ( base , rand ) is the offset from the level being chained from, %age is the generation percentage, and rndlevs is the number of similar levels available to choose from. LEVELDESC: type where type is the level type, (see DESCRIPTION, above). The type is used to override any pre-set value used to describe the entire dungeon, for this level only. BRANCH: name @ ( base , rand ) [ stair | no_up | no_down | portal ] [ up | down ] where name is the name of the dungeon to branch to, and ( base , rand ) is the location of the branch. The last two optional arguments are the branch type and branch direction. The type of a branch can be a two-way stair connection, a one-way stair connection, or a magic portal. A one-way stair is described by the types no_up and no_down which specify which stair direction is missing. The default branch type is stair. The direction for a stair can be either up or down; direction is not applicable to portals. The default direction is down. Dec Last change: 12 2 DGN_COMP(6) 1995 DGN_COMP(6) CHAINBRANCH: name prev_name + ( base , rand ) [ stair | no_up | no_down | portal ] [ up | down ] where name is the name of the dungeon to branch to, prev_name is the name of a previously defined level and ( base , rand ) is the offset from the level being chained from. The optional branch type and direction are the same as described above. GENERIC RULES Each dungeon must have a unique bonesmarker , and each spe- cial level must have a bonesmarker unique within its dungeon (letters may be reused in different dungeons). If the bonesmarker has the special value "none", no bones files will be created for that level or dungeon. The value base may be in the range of 1 to MAXLEVEL (as defined in global.h ). The value rand may be in the range of -1 to MAXLEVEL. If rand is -1 it will be replaced with the value (num_dunlevs(dungeon) - base) during the load process (ie. from here to the end of the dungeon). If rand is 0 the level is located absolutely at base. Branches don't have a probability. Dungeons do. If a dungeon fails to be generated during load, all its levels and branches are skipped. No level or branch may be chained from a level with a per- centage generation probability. This is to prevent non- resolution during the load. In addition, no branch may be made from a dungeon with a percentage generation probability for the same reason. As a general rule using the dungeon compiler: If a dungeon has a protofile name associated with it (eg. tower) that file will be used. If a special level is present, it will override the above rule and the appropriate file will be loaded. If neither of the above are present, the standard generator will take over and make a "normal" level. A level alignment, if present, will override the alignment of the dungeon that it exists within. Dec Last change: 12 3 DGN_COMP(6) 1995 DGN_COMP(6) EXAMPLE Here is the current syntax of the dungeon compiler's "language": # # The dungeon description file for the "standard" original # 3.0 NetHack. # DUNGEON: "The Dungeons of Doom" "D" (25, 5) LEVEL: "rogue" "none" @ (15, 4) LEVEL: "oracle" "none" @ (5, 7) LEVEL: "bigroom" "B" @ (12, 3) 15 LEVEL: "medusa" "none" @ (20, 5) CHAINLEVEL: "castle" "medusa" + (1, 4) CHAINBRANCH: "Hell" "castle" + (0, 0) no_down BRANCH: "The Astral Plane" @ (1, 0) no_down up DUNGEON: "Hell" "H" (25, 5) DESCRIPTION: mazelike DESCRIPTION: hellish BRANCH: "Vlad's Tower" @ (13, 5) up LEVEL: "wizard" "none" @ (15, 10) LEVEL: "fakewiz" "A" @ (5, 5) LEVEL: "fakewiz" "B" @ (10, 5) LEVEL: "fakewiz" "C" @ (15, 5) LEVEL: "fakewiz" "D" @ (20, 5) LEVEL: "fakewiz" "E" @ (25, 5) DUNGEON: "Vlad's Tower" "T" (3, 0) PROTOFILE: "tower" DESCRIPTION: mazelike ENTRY: -1 DUNGEON: "The Astral Plane" "A" (1, 0) DESCRIPTION: mazelike PROTOFILE: "endgame" NOTES: Lines beginning with '#' are considered comments. A special level must be explicitly aligned. The alignment of the dungeon it is in only applies to non-special levels within that dungeon. AUTHOR M. Stephenson (from the level compiler by Jean-Christophe Collet). SEE ALSO lev_comp(6), nethack(6) Dec Last change: 12 4 DGN_COMP(6) 1995 DGN_COMP(6) BUGS Probably infinite. Dec Last change: 12 5 nethack-3.6.0/doc/dlb.60000664000076400007660000000423012536476415013546 0ustar paxedpaxed.TH DLB 6 "28 Oct 1993" .\" NetHack 3.6 dlb.6 $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ .UC 4 .SH NAME dlb \- NetHack data librarian .SH SYNOPSIS .B dlb { .B xct } [ .B vfIC ] arguments... [ .B files... ] .SH DESCRIPTION .PP .I Dlb is a file archiving tool in the spirit (and tradition) of tar for NetHack version 3.1 and higher. It is used to maintain the archive files from which NetHack reads special level files and other read-only information. Note that like tar the command and option specifiers are specified as a continuous string and are followed by any arguments required in the same order as the option specifiers. .PP ^?ALLDOCS This facility is optional and may be excluded during NetHack configuration. ^: ^?DLB This facility is optional but is included in this NetHack configuration. ^: This facility is optional and was excluded from this NetHack configuration. ^. ^. .SH COMMANDS The .B x command causes .I dlb to extract the contents of the archive into the current directory. .PP The .B c command causes .I dlb to create a new archive from files in the current directory. .PP The .B t command lists the files in the archive. .SH OPTIONS AND ARGUMENTS .DT .ta \w'f archive\ \ \ 'u v verbose output .br .sp 1 f archive specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). .br .sp 1 I lfile specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. .br .sp 1 C dir change directory. Changes directory before trying to read any files (including the archive and the lfile). .br .SH EXAMPLES Create the default archive from the default file list: .br dlb c .sp 1 List the contents of the archive 'foo': .br dlb tf foo .SH AUTHOR .PP Kenneth Lorber .SH "SEE ALSO" .PP nethack(6), tar(1) .SH BUGS .PP Not a good tar emulation; - does not mean stdin or stdout. Should include an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. nethack-3.6.0/doc/dlb.txt0000664000076400007660000000440212467321052014206 0ustar paxedpaxed DLB(6) 1993 DLB(6) NAME dlb - NetHack data librarian SYNOPSIS dlb { xct } [ vfIC ] arguments... [ files... ] DESCRIPTION Dlb is a file archiving tool in the spirit (and tradition) of tar for NetHack version 3.1 and higher. It is used to maintain the archive files from which NetHack reads special level files and other read-only information. Note that like tar the command and option specifiers are specified as a continuous string and are followed by any arguments required in the same order as the option specifiers. This facility is optional and may be excluded during NetHack configuration. COMMANDS The x command causes dlb to extract the contents of the archive into the current directory. The c command causes dlb to create a new archive from files in the current directory. The t command lists the files in the archive. OPTIONS AND ARGUMENTS v verbose output f archive specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). I lfile specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. C dir change directory. Changes directory before try- ing to read any files (including the archive and the lfile). EXAMPLES Create the default archive from the default file list: dlb c List the contents of the archive 'foo': dlb tf foo AUTHOR Kenneth Lorber Oct Last change: 28 1 DLB(6) 1993 DLB(6) SEE ALSO nethack(6), tar(1) BUGS Not a good tar emulation; - does not mean stdin or stdout. Should include an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. Oct Last change: 28 2 nethack-3.6.0/doc/fixes22.00000664000076400007660000003456012467321052014257 0ustar paxedpaxed NetHack Fixes List Revision 2.2 Fixes and Modified Features --------------------------- Guidebook.mn New file "Guide to the Mazes of Menace". By Eric Raymond. Guidebook A file for preparation using the "mn" macros supplied with the 2.11 news release, as well as an ascii version of the same. NetHack.cnf Sample configuration file for the PC. (creps@silver) Makefiles Corrected problem in which the linking was done on build and (unix/xenix) on install. (Contributed by Janet Walz - walz@mimsy) Makefile.att Added a makefile for the AT&T Unix PC using shared libraries. (Contributed by ahby@umn-cs) Makefile.pc Streamlined compilation of main.o, tty.o, and unix.o Makefile.tcc (Contributed by polder@cs.vu.nl). data.base deletion of duplicate lines and spelling fixes. (sweet@scubed) invent.c REDO problem with "What do you want to..." text fixed. down stairway identification fixed. Alloc "buf" to allow for variable length HI/HE. (tom@uw-warp) engrave.c Correction to "feel" code. (mike@genat) Corrected switch for message determination. (patrickm@hpisof0) BURN'ed engravings made un-erasable again. (kyrimis@princeton) pri.c Added colour highliting functions (sweet@scubed) prisym.c changed "symbol.room" to "ROOM_SYM" (one I missed) (Ralf.Brown@b.gp.cs.cmu.edu) Changed "dirlet()" to return an int. (maartenj@cs.vu.nl) msdos.c Changed "symbol" to "showsyms" (Ralf.Brown@b.gp.cs.cmu.edu) Fixed up REDO & IBMBIOS stuff. (Kevin Sweet - sweet@scubed) do.c Dropping gold asked for only when gold posessed. (walz@mimsy) Potential unsigned value problem fixed (u.ucreamed) Added leash dropping code. (maartenj@cs.vu.nl) Blind modifications for blindfolding. (eric@snark) Value wrap fixed for u.ucreamed fight.c Dog's name now used in hitting avoidence message. (walz@mimsy) Variable initialization fixed w.r.t. #ifdef / #else. (Reported by Erwin Unruh - unruh@infbs) Added giant rats and kobolds back into code. (sweet@scubed) spell.c Potential unsigned value problem fixed (u.ulevel). Typos corrected. (Tom May - tom@uw-warp) Blind modifications for blindfolding. (eric@snark) shk.c "inshop" crash bug corrected (many sources). extern declaration of carrying() moved to avoid a Turbo-C type mismatch msg. (Ralf.Brown@b.gp.cs.cmu.edu) Added new "online()" which executes faster. (tom@uw-warp) Blind modifications for blindfolding. (eric@snark) Added item pricing shopkeeper talk. (Idea from a hacked up 1.0.1 source sent in by michael@stb) Cleaned up Kops code. (sweet@scubed) mhitu.c Argument mismatches fixed. (walz@mimsy) Scorpion/spider mixup fix. (William LeFebvre - phil@rice.edu) Blind modifications for blindfolding. (eric@snark) potion.c Argument mismatch fixed. (walz@mimsy) Blind modifications for blindfolding. (eric@snark) Poison handling made more dependant on poison resistance. (From an idea by Steve Creps - creps@silver) mklev.c Fixed up installation of vamp traps. (sweet@scubed) makemon.c Monster creation location bug fixed. (walz@mimsy) Monster creation crash fixed. (many sources) Monster posessions bug fixed. (S. Wrammerfors stewr@obelix) Added giant rats and kobolds back into code. (sweet@scubed) hack.c "Elbereth" effectiveness increased under "HARD" option to be reasonable. (walz@mimsy) Declaration of "register struct monst *m_at()" fixed. (many) Typo fixed. (tom@uw-warp) Fixed scroll of scare monster pickup problems (and giveaway) (polder@cs.vu.nl) Documentation modifications for blindfolding. (eric@snark) ioctl.c ioctl call for SET changed to function properly under unixtty.c Sys V R3 mods. (tom@uw-warp) decl.c in_doagain initialized. (many sources) wield.c Ability to remove cursed weapons w. w- removed. (many sources) options.c Major rewrite of options help. Now uses pager. (mike@genat) Rewrote GRAPHICS setup. (maartenj@cs.vu.nl) Allowed reassignment of inventory order #ifdef DGK (polder@cs.vu.nl) pray.c Fixed mk_obj of spellbook under all conditions to make book if "SPELLS" defined, and scroll otherwise. (unruh@infbs) Fixed typo in "gods angry" text. (tom@uw-warp) Fixed blessing code. (Simon Brown - simon@its63b) Blind modifications for blindfolding. (eric@snark) zap.c Potion of invis. breakage message improved. (unruh@infbs) Added WAN_PROBING to "zapyourself". Changed "dirlet()" to return an int. (maartenj@cs.vu.nl) Fixed cancellation code to work properly on wands (spe set to -1 instead of 0) this means no infinite wands of wishing. (Ron Wessels - ron@utcsri) Fixed bug in "buzz()" causing crash when destroying a trapper from inside with a wand/spell. (mike@genat) Added fcn to destroy wands with zero charges. (sweet@scubed) pcmain.c Added a routine to zero out the fileinfo array in order to prevent crashes on level change. (ralf@b.gp.cs.cmu.edu) Added chdir to HACKDIR before looking for .CNF file. Added call "uptodate(savefile)". (polder@cs.vu.nl) pager.c changed "cornline()" to use xputs for HI/HE. (tom@uw-warp) added choice for dowhatis() to allow letter or cursor object selection. (polder@cs.vu.nl) cmd.c Added ^W (wish) and ^I (ident-all) commands for WIZARD-mode. (Paul Polderman - polder@cs.vu.nl) Added "Z" as alternate to "# cast" (Eric Raymond - eric@snark) u_init.c Expanded a tab which didn't show in raw mode. Changed trobj.trotyp to "unsigned short" to avoid >255 problems. (Maarten Jan Huisjes - maartenj@cs.vu.nl) Removed wand of wishing from WIZARD's inventory (due to the above cmd additions). (polder@cs.vu.nl) Fixed declaration of leash. (simon@its63b) Beefed up Wizard class. Added Wakizashi for Samurai. Added holy water for Priest(ess)es. Modifications to provide blindfolds. (eric@snark) end.c changed inventory identification on death to list form. (polder@cs.vu.nl) added hallucination effects to done_in_by() added posession of amulet flag for scoreboard (sweet@scubed) wizard.c corrected "nasties" decl. (maartenj@cs.vu.nl) Blind modifications for blindfolding. (eric@snark) do_wear.c Prot. from shape changers logic fixed. (maartenj@cs.vu.nl) lev.c Prot. from shape changers logic fixed. (maartenj@cs.vu.nl) mon.c Inserted cast to fix compiler warning. (maartenj@cs.vu.nl) Nymphs now leave potions of object detection when killed. Kops now don't leave treasure behind. (sweet@scubed) topl.c Changed size of "toplines" to avoid overflow in "parseoptions" when help is asked for. (probably n/a) (maartenj@cs.vu.nl) topten.c Added longer death descriptions, including name of shopkeeper who killed character. (many sources) termcap.c Changed allocation of HI/HO for copying SI/SO to allow room for null. (maartenj@cs.vu.nl) Added PCHack 3.61 termcap stuff. Added colour highliting code. (sweet@scubed) version.c Expanded a tab for rawmode io. (maartenj@cs.vu.nl) objnam.c Allow the WIZARD to wish for really excessive objects. (polder@cs.vu.nl) makedefs.c Added "freopen" which works (MSC 4.0 drops first couple of lines). Solves missing #define AMULET... problem. (Nathan Glasser - nathan@mit-eddie) rnd.c Changed around random number generation: BSD uses "random()". (Paul Eggert - eggert@grand) SYSV uses "lrand48()". (mike@genat from above) eat.c Changed "choke()" code to waste food rather than choke on it #ifndef HARD. (Allan Pratt - apratt@atari) Blind modifications for blindfolding. (eric@snark) objects.h added blindfold object (tool). (eric@snark) you.h changed Blind/BLIND to Blinded/Blinded added Blindfolded/BLINDFOLDED redefined Blind in terms of above parameters. (eric@snark) apply.c added blindfold code. (eric@snark) timeout.c Blind modifications for blindfolding. (eric@snark) sit.c Blind modifications for blindfolding. (eric@snark) trap.c Blind modifications for blindfolding. (eric@snark) Level teleportation to hell fixed so that it will not do so unless character has Fire_resistance. (many sources) Added polymorph trap. (many sources) monmove.c added check on presence of "fobj" before atl() call to avoid potential segmentation problem with ROCKMOLE. (Reported by Doug Rudoff - doug@wiley) various files Fixed typos. Also converted British English words to American English for uniformity. (Original list of typos submitted by Steve Creps - creps@silver) New Features ------------ 1) New flags in "config.h" (some of these were included in 1.4f): COM_COMPL Command line completion by John S. Bien GRAPHICS Funky screen character support (Eric S. Raymond) HACKOPTIONS Support DGK-style HACKOPTIONS processing (ESR) RPH Various hacks by Richard P. Hughey KJSMODS Various changes made by Kevin Sweet BVH Additions by Bruce Holloway In addition, in an MSDOS enviornment, when GRAPHICS is defined: MSDOSCOLOR Colour highlighting of monsters, etc. Of the above, I haven't tested HACKOPTIONS and MSDOSCOLOR. If you find bugs in these, send me the reports. 2) New objects: blindfold - allows you to avoid the gaze of a Floating Eye and to use your telepathy on command if you have it. mirror - scares monsters if you use it on them (and other uses). ring of polymorph - (usually cursed) forces random polymorphs. ring of polymorph control - prevents system shock and allows choice of creature to polymorph into. 3) New Files: - A new set of documentation, the "Guidebook to the Mazes of Menace" has been supplied by Eric S. Raymond. The guidebook is written for nroff using the "mn" macro set supplied with Bnews 2.11 or greater. Since not everyone has these macros, I have run the guidebook through nroff, and supplied it in flat ascii format as well. [Moderator's note: because of past problems, I ran the formatted version through "col -b" before passing it on to remove ^H's, etc. -br] - A copy of "HACK.CNF" which has been renamed "NetHack.cnf" was supplied by Steve Creps. The file decl.c has been updated to reflect this change. - A new "Makefile" for the AT&T Unix machines has been added. - I was hoping to get documentation on "NANSI.SYS" as well, but got no responses to the mail I sent the author, direct and via Bill Randle at tekred. As per usual, I will gladly publish any relevant documentation I get. 4) Major game changes: - Shop generation has been significantly changed. A new structure has been introduced which allows shops (except the "general" type) to have up to three different types of object inside. There is also a new "distribution pattern" parameter which tells the generation code how to lay out the shop (this is preliminary to the addition of two new types of shop, the temple and barracks - more on this later). - Shopkeepers will now tell you how much they expect for each object you pick up. This gives you the ability to haggle with the merchant in question by dropping and picking up objects until you are more or less satisfied with the price. I have re-written "getprice()" in shk.c in an attempt to make sure that you cannot actually sell any particular object for more than the shopkeeper will charge for it. - Another change to shopkeepers has them potentially getting angry if you stay beside them after not paying your bill. Each they time they ask you to pay up, there is a chance they will decide they don't like people who don't pay... - A new monster, the hydra, has been added (as you have probably seen on the net). I haven't had much chance to test out this feature of the game. Mirrors have also been added, and seem to work quite well. - Changes have been made to the object ocurrence chances in objects.h, so that the relatively rare tools, etc. have at least a 1% chance of showing up. - Throwing and zapping code has been modified so that there is a chance that said can be done through a doorway. Bolts can still bounce however... - The infamous and dreaded makemon() bug has been eliminated. In addition to this, "r"ats and "K"obolds have been added back into the game. "K"ops no longer leave treasure (just what they were carrying, plus maybe a club or whistle). - Two new "super"swords have been added. They are the katana named "Snickersnee" which is +5 on damage (due to sharpness), and the long sword "Excalibur" which is +rnd(10) to hit, +5 on damage, and has a couple of other features I won't go into right now. The only way for a character to get "Excalibur" is as a gift from someone. You cannot write the word "Excalibur" on things for some reason... - There have been two additions to disallow infinite wand charges. First of all, wands with less than zero charges will automatically turn to dust (thanks to Kevin Sweet). Next, a wand of cancellation will set the number of charges in the wand to -1, which will make it forever useless, (thanks to Ron Wessels). 5) Minor game changes: - The fountain code has been tightened slightly so you can no longer dip objects into a fountain or drink from one while you are floating in mid-air due to levitation. - Teleporting to hell via a teleportation trap will no longer occur if the character does not have fire resistance. I found this just too arbitrary a way to die (and so did several other people who com- plained about it). - A new trap, the "polymorph" trap has been added by Richard Hughey. It's inclusion is dependant on having "KAA" defined. - In wizard mode, the wizard player has infinite wishes, and the ability to instantly identify everything (s)he is carrying. The wizard player is also no longer limited by the standard multiple / bonus res- trictions on objects wished for. - Random number generation has been changed around to make it (I hope) more unpredictable. - A large number of typos have been fixed, and all of the British spellings converted to American. I would like to see a shell script to allow conversion back (or something like that) in the future. - I have done a "make depend" for the makefiles to reflect a slight restructuring in the order of inclusion of header files. 6) Future additions: - Steve Creps is working on "barracks" and "soldier" code which is now ready for addition. I have added the "soldier" side into the game, but haven't really tested it. Steve will be adding the "barracks" section in and sending me the resulting patches. There will be a minor (read patch) release as soon as he can get the code integrated into this release and sent up here to me. - There are also several other new room projects in the works which should be able to be included in that minor release, along with any bug reports that are made in the interim. nethack-3.6.0/doc/fixes30.00000664000076400007660000002127612536476415014271 0ustar paxedpaxed$NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ [This is a partial list supplied by Ken Arromdee long after the fact] General Fixes and Modified Features ----------------------------------- dropping a weapon, then picking it up while blind causes it to become unidentified but it remains that way after your vision returns when blind and feeling the floor, the objects then on the floor should have their characteristics become unknown zapping a wand of probing at yourself works, however using a stethoscope on yourself does not trolls that come back to life don't retain their names if you look at what is on the ground and there is more than a screenful, quantities are not printed (i.e. "food rations") if pickup was off and you moved onto a spot with both engraving and objects, you got told what the engraving was twice if a Keystone Kop threw a pie and the pie hit a shopkeeper, the shopkeeper became angry "two handed sword" is spelled with and without a hyphen in various places trying to descend stairs while levitating gives a message where "You're" is misspelled as "Your" the 'V' command gives a history that is not quite correct; it wasn't Ken Arromdee that merged PC Hack and Unix Hack; rather, PC Hack was derived from Unix Hack by Don Kneller. It was (I think) Mike Stephenson who merged the many Hack versions. the uranium wand gets described as "an" uranium wand potions which have been both called and identified have the called instead of the identified name printed out status line at the bottom of the screen is formatted strangely for the first 10 moves; after 10 moves it becomes normal if you polymorph yourself into a rockmole, you are unable to dig through rock a stethoscope or wand of probing, used on a monster, printed out a format with spaces in it (such as %-3d instead of %d) causing such messages to be longer than necessary the number printed out for damage by stethoscope or wand of probing is completely incorrect sometimes your dog would turn into a bat (retaining the same name and tameness) when saving and restoring,going down and back up and in bones levels ghosts on bones levels are replaced by little dogs if you are polymorphed and drink a potion of healing which raises your maximum monster hit points, your current hit points only are raised, so you may have (for instance) 37 out of 36 hit points when you pick up something from a shop, the message is something like "For you, kind sir, only 5 for this " on systems where pointer is not the same size as integer removing a leash from a dog produces garbage, and also can sometimes crash the game when the Wizard is mentioned, you get garbage if you tame a wild dog, and then try to hit it, the safe-attack routine says "You stop to avoid hitting .", or sometimes garbage when you are invisible but can see invisible, drinking at a fountain which dries up causes your symbol to be erased from the screen. pushing an enormous rock onto a teleport trap deletes it instead of teleporting it sometimes returning to human form from a polymorph would leave you with only 1 current hit point left sometimes polymorphing would leave you with an 18/** strength if you used a stethoscope on a wall and a creature moved into the revealed door before you did, when creature moved off, the door was replaced by a wall symbol again, until you walked through it playing a game with fountain symbols set to one character, and restoring it using a configuration file having them set to a different character, leaves the fountain symbols as the old character problem with food poisoning and blindness where you could end up permanently blind, not even reversible by healing etc. you could not wish for a C-ration or K-ration due to lowercase conversion zapping a wand of death at yourself, and the death touch of a demon prince, killed you even if you were polymorphed into an undead, but bouncing death rays didn't if you threw an object in a shop, it landed on the floor still unpaid zapping a wand of cancellation at yourself turned all your objects to -1 instead of +0; -1 was only needed for wands (since cancelling wands to +0 allowed a sneaky way of getting infinite wishes) #remove command is incorrectly described as removing a cursed object, but it actually removes only iron balls at least some messages given for special abilities when you are polymorphed printed out the monster type even if you were blind wishing for a scroll of mail, with MAIL undefined, is permitted but reading the scroll gave an "impossible" error message; change it to read: "This seems to be junk mail directed to the finder of the Eye of Larn." if you were blind, effects of scrolls, et al, still said things such as "Your mace glows green for a moment," "Your left ring glows white" the message "The xan pricks your ___ leg" still mentions the type of monster (xan) when you are blind polymorphing could change your gender, but when the game ended you were still described as a "Cave-man" or "Priest" instead of "Cave-woman" or "Priestess" if you got rocks by using a pick-axe on an enormous rock, the rocks started out blessed if you escaped from a shop by throwing your iron ball to the exit, the ball would stay unpaid any object thrown in a shop stayed unpaid, and you had to pick the object up again and then drop it for it to become paid if you were invisible but could see invisible, when you drank from a fountain that dried up, your symbol got erased from the screen several times colors were mentioned (i.e. black glows when you pray too much) but the colors weren't always changed for hallucination if punished and your chain and 1 other object is on the floor, you get asked if you want to pick up a specific type of object, and the chain is given as one of the possible objects if you polymorph into a "new man", your energy points never change trolls, when killed, can leave bodies or objects, but they should always leave bodies so they can regenerate back to life, whether or not they left objects demon prince demanding bribe gets randomly relocated instead of being placed next to you if you polymorph another tool into a magic marker, the marker always starts out dried out hallucination has the problem that if you do something which takes no time, the monsters still change if you tried drinking at a fountain while levitating, you got asked if you wanted to drink, and then you weren't allowed to do it, and the fountain could still dry up if you were fire resistant and a magic trap produced a tower of flame, you also get a second message (a shiver...) when restoring a game, if there was an error, your saved game still vanishd for some errors pets were always referred to as "him" in the leash code stethoscope in the up or down direction while swallowed referred to "floor" and "ceiling" instead of to the monster that swallowed you if you could not save a game, the screen cleared and you were told to "Continue or Quit", but if you typed C, the game thought you just gave it a Call command you could get told "that spellbook was a mimic" even if mimic was on a wall if you were turning to stone and you polymorphed yourself into a 'c', you still died from the stoning if you interrupted the program before it finished loading a saved game, you were asked if you want your possessions identified "ctmp" was mistakenly used in MHITU.C when being hit by a rust monster rusting your helmet but it should have been "!mtmp->mcan" Platform- and/or Interface-Specific Fixes ----------------------------------------- PC: often the same character class, and same player name, will end up getting 2 scores on the high score list PC: if your name contained a period and you were playing on a PC, you would have problems saving games since your save-file name still contained 2 periods and would thus be illegal; change periods to underscores when figuring out what the save file should be called PC: if you polymorphed into a "new man", and changed your name, when you saved your game the game was still saved under a filename derived from your old name, and to restore that game you had to specify your old name General New Features -------------------- when polymorphed into a giant you are now able to pick up and throw rocks by giving infinite carrying capacity give the Healer a pair of gloves (the most logical piece of armor for a physician to start out with) give the Healer a lot of money to start with (doctors are supposedly rich, you see) have the Healer start out with the healing, cure blindness spells already known create a "trial mode", similar to Wizard Mode where you get a wand of wishing with charges and you can't get on the high score list if you are standing on a trapdoor and you type a '>' symbol, print "You jump down the hole." and go down to the next level nethack-3.6.0/doc/fixes31.10000664000076400007660000001357512467321052014263 0ustar paxedpaxedMakefile.utl vs. GNU make (*_lex.o needs explicit *_lex.c dependency) defining MAKE in more makefiles (symptom is "sh: makedefs: not found") finding test in makefiles (needs shell meta-char, >/dev/null or || exit 1) splitter hunk sizes with SAS 6.x (wouldn't fit on floppy) OpenWindows 2.x documentation (?) ',' and ';' in help files, including Guidebook Guidebook date (nroff and pre-processed versions) VMS options syntax (config file description omitted "OPTIONS=" requirement) phase of moon for Mac and MSDOS ports -- revert to old, portable phase of moon code polymorphing into bees (divide by zero core dump, reported as floating point error on Sparcs) monster throwing boulder into pool could free object twice candle burn-out accessing free'd object while traversing list (Mac core dump) inappropriate candle merging (lit with unlit) several levelflags (fountains, etc.) not being handled on special levels subrooms[] not initialized coredump on messed DEFAULT_WIN_SYS deleting lock.0 files on early quit number_pad/mouse coexistence jumping onto doors or boulders tombstone gold neglected gold in containers, although score was correct initial gold record neglected gold in containers reeling monsters leaving ghosts (missing newsym) display getobj prompt for non-REDO packorder option parsing inconsisent option parsing with IBM vs. IBMg, etc. throwing Mjollnir at adjacent hard things causes panic/core dump throwing at ghosts in walls left objects stuck in walls throwing unpaid objects in shops (donated to player by shk) Shopkeeper administration out of order (buying group of used up items) pricing chains, uball, or other nocharge objects, when they couldn't be sold knocking uball down a hole by dropping another object caused crash kicking monsters while levitating (core dump if monster "reels" or killed) kicking empty space while levitating could give free move (recoil) panic when nurse is fixing your damage and disappears core dump 'D'ropping everything with gold but no inventory (null pointer access) core dump using getpos() "move to feature" response when map shows something covering furniture (displayed glyph leads to invalid subscript use) deity gender reference in opening legacy message makeplural() said "poisoned yas" instead of "poisoned ya" zapping on entry to water left trails allow level teleports to be cancelled excess choking when eating corpses funny death message (or coredump) when you choke on a tin of spinach after partially eating something else Magicbane expulsion confused cutworm() charging for several overlooked items (mainly magical instruments) taming a sticking monster (e.g mimic) wouldn't set you free panic when tinning while standing on stairs with a full pack and object drops zapping down into ice with wand of digging (core dump) rust monsters wouldn't ever hurt armor, even non-rustproof armor. conversely, unrustable things rusted. mysterious rust damage on damp levels (improper object chain traversal when any item landed in pool after being thrown or dropped) very eroded nonrustable/corrodable/flammable objects displayed as "very +0..." map window wasn't being initialized correctly, causing some 'a'filled screens using magic marker with full pack leaves you with an item in the '#' slot spellbook merging caused multiple books to fade away when you re-read them enough times Master of Thieves in Tourist quest not created with Bell of Opening, making game virtually un-winnable could wish for quest items If an eel managed to drown you, it would say "Drowned by a drowning" stop making bones from non-branch portal levels reading blank scrolls exercised wisdom inverted use of crystal ball "vision in unclear" feedback message special room entry messages (shop welcome) given before level change map update limbless blobs like gelatinous cubes could not pick up The level compiler missed first level flag if more than one was specified. The level compiler accumulated level flags when compiling multiple files. make the 32-bit monster flags fields unsigned long rather than just long mksobj() created gold a factor of 10 too light indefinite articles in quest text Alt-n didn't execute #name on some ports, made Alt-? do #? correct tense and grammar of various messages obsolete oracle about using mirror to locate Wizard & Medusa removed Nurses would zap you with wands, et al, instead of healing you Shopkeepers residence was sometimes wrong on bones level, esp. in the minetown Some zaps, esp. by monsters, at the map edge could cause core dumps panic relmon bug possible when #turn'ing multiple monsters at once it wasn't possible to get underwater when polymorphed to a swimmer total digestion wasn't working lycanthropy could change sex interrupting dosinkring() allowed free ring identification killing some hostile humans (like Croesus and priests) lost telepathy, etc. tty specific: long input lines and improved interrupt handling X11: NetHack.ad: "*map*grey" should be "*map*gray" X11: NetHack.ad: remove excess quotes HPs and X (SYSV conflict caused by X11 headers) Handle WM_DELETE_WINDOW protocol in X11 window-port. X11 popups are now positioned so that the cursor is bottom center. Both X11 fonts now have a pool symbol that coveres the whole rectangle. X11_getlin will now allow empty strings to be returned. X11: implement score in the status window. X11: make displaying experience optional. X11: position getline and yn popups center,bottom instead of center,center. X11: autofocus mode made more reliable at program startup X11: number of objects removed from containers could wrap negative X11: allow translation tables X11: initial window would "sweep" shut and reopen micros: save and restore progress reports weren't appearing during save and restore (they would appear immediately afterwards) also error messages from dots aimed off right edge of screen Atari: colors were not properly set in medium resolution Atari: terminal size was set incorrectly after a ^Z OS/2: HPFS support was incomplete nethack-3.6.0/doc/fixes31.20000664000076400007660000001306012467321052014251 0ustar paxedpaxedrevived barbarians didn't gain levels from potions pets wouldn't keep their armor or weapons (blessed figurine of Archon) avoid "rot" v. "burn" damage for organics identify +/- known rings/armor as "uncursed" loop through identification as long as additional "charges" are available successive disease attacks made you less sick, also make nurses cure sickness NO_MAILREADER non-mail daemon message fix make fortune cookies, pancakes yellow and lightning white cavemen were red while cavewomen and all other characters were "domestic" monsters might not change color when growing up redisplay cancelled objects in case their color changed (potions, spellbooks) ask if you want to play heard passtune add: make ^T intrinsic teleports use magical energy don't encase the Amulet (or invocation tools) inside cockatrice induced statues fix eating taking 1 turn less than number necessary, cheating you of nutrition fix inventory to avoid % in user-supplied names [pline(xprname())] fix crash when #force destroys unpaid chest in shop fix crash when movement reaches edge of screen on rogue level fix crash when two items in a row vanish from magic bag set bknown when Priests see item, fixing missing checks elsewhere set alignment of priest's quest artifact to match priest's starting alignment if the Mitre of Holiness gets stolen by the Wizard, reset int & wis stats always unlock quest stairs whenever leader acknowledges quest completion make mysterious force which locks quest stairs block objects as well as player duplicate shopkeeper names were possible on town level trying to rename shopkeepers left dangling pointers credit balance can prevent Kop summoning when player leaves shop suddenly suppress several shopkeeper messages (and buy|sell) is shk is asleep|paralyzed using charged objects ((engrave) wands, horns of plenty, etc.) in shops was free don't double bill for food eaten off shop floor (multi-turn to eat only) fix to prevent unpaid objects differing only in price from merging (only in inventory; they're not "unpaid" any more when dropped, so might merge) missing #ifdef SOUNDS in vault.c inconsistent MFLOPPY/MICRO use of dotcnt for saving add: wands of striking break potions add: directional healing spells add: pickup_types option, pickup -> autopickup disclosure option takes optional string value; killed counts and genocide list give better message when trying to set options which are compiled out add: hungry pets make begging noises centaurs and mariliths could wear inappropriate armor remove Medusa's tail and give her wings separate creatures that don't breathe from creatures that can breathe water you can't choke if you don't breathe Fort Knox eels were placed outside moat jellies for Juiblex, not Jabberwocks don't heal while praying, so that gods are more likely to heal you fix fireballs burning fire resistant players floating eyes could paralyze monsters indefinitely fix monster sleep/wakeup induced my musical instruments players hit by wands of sleep get chance to wake up when attacked by monster iron balls keep their "very heavy" weight fix vorpal blade/long worm misses allow monsters to kill players with vorpal blade and tsurugi fix objects falling through trapdoors; "shipping destination"'s overloaded use of obj coordinates could cause bogus screen update attempt (y >= ROWNO) prevent bad argument to rnl() from prayer_done() when praying in gehennom display message when boulder is pushed into pit avoid monsters deciding displaced or invisible characters were off the screen kicking embedded objects loose would break fobj chain (-> freeobj() panic) when using the cursor to look at remote objects, if the target object is embedded in something, mention that fact dropping gold inside a monster -> freeobj() panic gold picked up by pets wasn't in mgold and thus didn't show up on probing fix "stop *opening* the lock" even when you were locking it succubus stealing ring of adornment caused crash if she already had one monsters created by monster reading create monster didn't appear for scroll ID monsters explicitly casting spells of sleep or cold had messages reversed elf character could get impossible("snow boots not found?") stepping onto ice accept gray/grey except for spellbooks keep monsters from teleporting on no-teleport levels don't allow digging of trapdoors on the three wizard levels don't allow digging down (including drum of earthquake) to destroy portals fix digging down from within walls and solid rock; monsters could enter the resulting trapdoor/pit, but players couldn't fix digging down while flying; don't fall through destroy any engraving if a hole is dug down thru it, or ice it's in gets melted change many hardcoded "floor"s and a few "ground"s to use actual surface type fix blessed unicorn horn's restore ability feature (strength gain when weak) underwater: prevent turbulence from placing character inside solid wall underwater: suppress "you inhale water" message when removing amulet of magical breathing if you're polymorphed into a swimmer or nonbreather when using the 'A' command to take off armor from underneath other armor, account for time needed to take off and put back on outer garment(s) don't create doors over pits and trap doors when using a wand of locking fix mapping when you drop objects while following the guard out of a vault X11: some status didn't show up after restore UNIX: fix potential security hole accessing file through NETHACKOPTIONS setuid VMS: disable installed privileges when assigning i/o channel to terminal, opening termcap, or accessing user-specified config file Amiga: invalid showscore and numberpad options inserted by frontend nethack-3.6.0/doc/fixes31.30000664000076400007660000000232112467321052014250 0ustar paxedpaxedavoid divide by zero crash for eggs produced from horn of plenty prevent monsters from eating the invocation tools or Rider corpses make artifacts much less likely to be destroyed fix freezing lava in front a raised drawbridge fix digging pits in front of raised drawbridge; improve digging next to pools since random teleports have no --More-- prompt, have them purge REDO data to avoid repeating previous command before noticing changed context make magic portals function for monsters make numerous priest blessings increasingly rare, with an upper limit fix missing quotation marks in quest speech prevent monsters like killer bees from opening tins add: keep track of # player deaths, save game start time in struct u don't used "uncursed" with gold in containers in ending inventory display PC: Fix black/gray/white display problem X11: set input text portion of the dialog box so it is the width of the box X11: fix message window seperator redraw problem (thanks to Ivan D. Brawley ) VMS: avoid false "trickery" detection for bonesX#.##;1 levels VMS: prevent display of really long broadcast messages from clobbering stack VMS: prevent endless input loop upon remote terminal disconnect nethack-3.6.0/doc/fixes32.00000664000076400007660000005144712467321052014263 0ustar paxedpaxedprotect the Amulet and invocation tools from being destroyed when a disintegrated monster's inventory gets deleted prevent the Amulet and invocation tools from being buried, similar to box behavior (Book of the Dead would rot away as paper when buried) don't let polymorphed players eat any of the invocation tools pets are no longer highlighted when hallucinating keep glass gems from shattering in chests return errors from dgn_comp and lev_comp when called for fix hallucinated fruit juice message fix several monsters conveying inappropriate resistances fix misspellings of "Assassins' Guild" and "Minion of Huhetotl" set personal name flag for Pelias and Thoth Amon; clear it for Chromatic Dragon don't say "Picking the lock..." when using a skeleton key give feedback when applying key to current location but no boxes are present can't manipulate floor locks (chests) while levitating don't crash onto sink if permanently levitating due to eating a ring avoid resuming interrupted lock operation on chest that's been polymorphed wide-angle disintegration Beams O' Wrath disintegrate non-resistant shields and armor don't access zapped wand after it's been destroyed by divine lightning bolt separate graphics symbols for each trap, differently-colored traps allow wishes for greased objects, correct wishes for "poisoned rustproof" objects damage was calculated incorrectly when hitting with statues and boulders allow digging to finish when digging statues embedded in undiggable walls list identified invocation tools as "the item" instead of "a item" ignore rknown for unerodable objects when determining if it's fully identified flush output after eating mimic so '$' appears right away update botl for spell power after ^T or #invoke of "energy boost" artifact correct hunger check when casting spells correct various messages fix deliberately jumping into Stronghold trap doors make random level changes while escaping with Amulet more equitable when mysterious force randomly picks a location on the current level, send player into Wizard's tower if and only if already inside that tower any level change from one tower level to another preserves occupancy state mysterious force won't kick in when using portal to go up into Wizard's tower avoid "bad cursor position" situation when mystery force or cursed gain level potion causes level change within the Wizard's tower don't allow the Wizard to be resurrected on the Astral level only list "likely" objects when prompting for what to #invoke reset encumbrance and movement rate during successful prayer, in case it cures lycanthropy prevent cursed weapon that slips when thrown by monster from embedding in stone ki-rin is not humanoid all elves can see invisible gain intrinisics from eating amulets lose divine protection by killing co-aligned priests or converting alignment have quest leader check for absolute alignment as well as for piousness fix tombstone message when dying from kicking door while levitating bite, &c. attacks on displaced images said "swings wildly and misses" calculate score before creating bones, otherwise gold in bags gets overlooked Unique monsters no longer placed in bones files for blessed genocide, don't report failure for other classes' quest monsters could get both compressed and uncompressed explore mode save files ZEROCOMP's bwrite ignored possibility of write failure mimics imitating fruit caused "Bad fruit #0" on help commands fix off by one bug in level teleport trap destination for monsters if g.cube eats a non-empty container, engulf contents rather than devour them allow wizard to use blessed genocide of '*' to wipe out all monsters on level when digging a hole in ice, don't describe it as digging in the "floor" and unearth any objects buried there even when it refills with water when digging in a pit trap which ends up filling with water instead of becoming trap door, remove the trap; likewise for overflowing fountains can't dig pits under drawbridge portcullis; break bridge if hole would be made can't dig while caught in a web don't "swing your pick-axe through thin air" if target location is a web mark webs as seen when "monster is caught in a web" message is given whirly monsters pass through webs; some huge monsters tear them Sting cuts through webs have shk use plural if called for when referring to player's pick-axe(s) fix price stated by shk when picking up container holding merged items fix price stated by shk for #chat when standing on a container don't adjust food price due to hunger when player is selling, only when buying don't double bill shop corpses turned into tins don't make mundane objects known when they're outside the shk's expertise change to have shks possibly identify items sold for credit just like for cash when player sells something to broke shk for credit, don't offer more for it in credit than will be charged for it if player buys the item back when selling items in shop, don't try to adjust message/prompt based on COLNO when dying in shop entrance, make sure inventory in bones data is placed all the way inside the shop, hence owned by the shk make shk notice when shop door destroyed by wand or spell or digging downward reset unpaid objects if shk poly'd into jumpy monster teleports out of shop fix handling for shop objects kicked or thrown from one shop into another and for shop objects hit by cancellation beam add potions of oil; lamps can be refilled with them dipping rusty weapons in potions of oil removes rust allowing drinking from surrounding water if you are underwater fix non-merging potions of water due to water damage's incompatible dilution fix mon-merging scrolls of blank paper due to SCR_SCARE_MONSTER's spe usage fix D(ropping) subset of wielded darts,&c (worn mask got out of synch) fix #adjust merging wielded darts,&c into non-wielded ones allow #adjust when fixinv option disabled fix getobj's '?' help displaying one item when fixinv option disabled don't give characters with maxed out luck complete immunity to water damage don't allow AC -17 or better to provide invulnerability to zap attacks kicking cockatrices while barefooted will stone you change to inhibit displacement from operating through solid walls fix mblinded assignment for monsters hit by potion fumes give runesword same damage adjustments as broadsword extra verbosity for attacks caused by Stormbringer allow ghosts to step on garlic don't let vampires step on altars don't let monsters jump into polymorph traps covered by boulders, unless they can carry such, pass through, or squeeze under giants polymorphed into something else must drop any boulders being carried giants in pits become untrapped if a boulder is pushed in prevent traps from being generated on ladders don't "detect trigger hidden in soil" for previously detected land mine exploding and crashing doors wake up nearby monsters factor rings of increase damage into kicking damage handle omitted case for ball movement that would leave chain in odd position returning to stairs on top row of map is valid (fixes rogue quest bug) avoid giving "sad feeling" message for pet if lifesaving prevents its death don't rot away Rider's corpse if something is standing on it at revival time kill any engulfer (including poly'd player) trying to digest a Rider give Riders non-zero nutritional value so tinning kit doesn't ignore them save & restore u.usick_cause properly an eating pet can continue & finish eating while you're off its level fix object names: "a Dark One corpse", "statue of a Wizard of Yendor" killer_format: poisoned "by Pestilence", not "by a Pestilence"; ditto Juiblex killer prefix might be wrong after having been life-saved fix to avoid "invisible invisible {Priest|Minion of Whoever}" on tombstone fix bug with cold-resistant monsters attacking jellies (etc.) fix possible panics when restoring while swallowed or held when taming, make holder/swallower let go even if it just becomes peaceful reset area of visibility when hurtling backwards from recoil while levitating don't let hostile monsters who follow up/down stairs share final ascension add bodypart(HAIR) to correct some inappropriate messages display monsters inventory (if any) when mon zapped with wand of probing display inventory of encased items in statues zapped with wand of probing display inventory of buried items below, by zapping wand of probing downwards set dknown bit for all objects hit by probing beam add ceiling function to alter the ceiling messages appropriately fix 3.1.2's fix for reseting certain class-specific artifact properties add selection menus to pickup and some apply functions pre-menu container interface: don't let "%a" select all objects if no food is present; make user's " a" become "A" instead wake up monsters hit by potions thrown by other monsters suppress vault hint messages if player is in the vault make lev_comp check full object and monster names ([ring of] "protection" in objects[] was matching "protection from shape changers" in .des file) guarantee that stairs down from Juiblex swamp level always get created [sometimes got impossible("couldn't place lregion type 0")] prevent a three room level which has the stairs to the mines from also having a special room [so that those stairs can't end up placed in a shop] allow quest nemeses and other invocation tool guardians to wield artifacts Mitre of Holiness is not a weapon don't give "heat and smoke are gone" message when entering Vlad's tower if arriving from somewhere other than Gehennom (portal via W's quest arti) when a wielded cockatrice corpse rots away, set `unweapon' so that further combat will elicit "bashing with gloved hands" message fix behaviour of wielded eggs (breaking, stoning, etc) tiny chance for "queen bee" eggs, rather than always killer bee eggs change Tourist quest home base to Ankh-Morpork prevent activated statue traps from creating hidden monsters handle activated statue being the only object poly'd player is hiding under prevent reference to unseen underwater object when hiding monster attacks don't pluralize name when smelling opened tin of unique monster's meat make tins of unique monster's meat be empty in bones file don't leave a corpse in bones file if killed by disintegration breath don't leave a corpse when monsters disintegrate other monsters any food could be tinned (yielding giant ant meat) when corpse in inventory destroy all boulders in invocation area when creating stairs down to sanctum boulders landing on previously seen trapdoors will plug them instead of falling through or settling on top boulders on ice which gets melted will fill pool as if dropped don't let dead or sleeping priests give temple greetings chatting wakes up sleeping priests don't exercise wisdom when making prediscovered objects known during init don't generate any generic giants (mummy/zombie placeholder) on castle level pets and g.cubes will polymorph if they eat chameleon corpses slippery ice (temporary fumbling) only lasts until the next move avoid leash limbo if quest leader ejects you while leashed pet's not adjacent (ditto other unconventional level changes, like W's quest artifact) release attached leash if poly'd player eats it crash fix: handle other forms of monster-induced level change besides quest ejection (swallower expels onto portal, level teleporter, trap door) fix magic mapping of previously mapped maze walls dug away out of view assorted drawbridge fixes (kill credit, auto-pickup, drown survival handling) passtune becomes fully known once successfully played wiping out engravings leaves partial letters wipe random letters of trap engravings ("ad aerarium", "Vlad was here") eating wolfsbane while in werecritter form rehumanizes in addition to purifying don't penalize player (shop charges in general; bad luck for mirror) when a monster breaks something with a wand of striking when loading bones, keep track of unique monsters to avoid their duplication don't allow a demon prince to summon two copies of a unique demon lord enlightenment luck display ("extra", "reduced") did not agree with actual luck avoid duplicate spellbooks in character's initial inventory (affects priest) fix pets moving reluctantly onto cursed objects can't #loot while overtaxed time passes when items disappear on use of a cursed bag of holding #offer cannot convert or destroy an unaligned altar MUSEr's reflecting shield or amulet shouldn't become known when not seen fix check for wearing shield when monsters wield two-handed weapons don't restrict MUSE scimitar usage to strong monsters make dwarves less eager to switch back and forth between weapon and pick-axe clip swallow display at left & right map borders prevent recoil [hurtle() while levitating] when caught in a trap downward zap which freezes water or lava shouldn't bounce back up Vorpal Blade: don't let damage penalty (very low strength, negatively charged ring of increase damage) prevent beheaded monster from dying make sure player polymorphed into jabberwock is vulnerable to beheading make sure that when "The fiery blade burns the shade!" that it actually does damage (double-damage for non-silver must do at least 1hp damage) prevent divide by zero crash when hitting tame shade with non-silver weapon don't lose alignment when throwing gems to/at peaceful unicorns don't apply grease to worn armor if it's covered by other armor fix unnaming monsters via `C ' fix calling object types via `#name n ' fix off by one problem when shuffling some descriptions (scroll label "KIRJE" and "thick" spellbook never used; breathing amulet always "octagonal") exploding land mines can scatter or destroy objects at the trap location add rolling boulder traps try harder to make monster hit point and level gain avoid anomalous losses reduce odds of undead corpses on castle level and priest quest home level, to make it harder to lure wraiths to more favorable spot can't polymorph large piles of rocks into gems hit point gain from nurse healing throttled substantially make cursed bells be much less effective as instruments of abuse fully implement object charges for Bell of Opening allow '%' as destination on rogue level when specifying position by map feature fire traps can burn up scrolls and spellbooks on the floor fix inverted cancellation check for AD_SLOW and AD_DREN damage bullwhips can be applied to disarm monsters and hero bullwhips can be applied by hero to haul themself out of a pit ensure that thrown potions hit their mark if you are swallowed attempting to engrave on an altar causes altar_wrath differentiate between a hole and a trapdoor, digging always makes a hole check the right hit point values when polymorphed and encumbered improve guard behaviour in vaults when player is blind prevent dwarves from digging while wielding cursed weapons displacing a pet mimic unhides it '(' shows the proper tools as in use improve shk's handling of pick-axe damage and taming aging of items in ice boxes left in bones files fix genocide of '@' while polymorphed add gender to some unique monsters disallow digging down while phasing through non-diggable walls general fixes to various message sequencing problems prevent shopkeeper names from showing up while you are hallucinating prevent paralyzed pets from picking up items jellies for Juiblex, not Jabberwocks (done properly this time) rust monsters can't eat rustproofed objects general fixes to inventory merging of items monster inventory undergoes merging too; potentially affects probing and theft monsters ignore items they want to pick up that are on 'Elbereth' bows wielded by monsters now do proper (low) damage even nymphs may not pick up rider corpses treat cockatrice corpses in multiple item piles the same as one item piles "PACKORDER" feedback incorrect on parsing failure you can no longer choke on liquid stethoscope on secret doors displays properly when blind monster-hurled potions no longer produce quaff messages (or djinn) giant eels now hide with mundetected, not invisibility eels on the plane of water don't hide and aren't negatively impacted by being out of water don't give the big point bonus for eels if player is wearing breathing amulet fix display bug (newsym after Wait! message) temple priests now wear their cloaks Orcus is no longer peaceful (had been made so by bad bribery check) 'uskin' save and restore done properly don't improperly adjust int & wis for stolen non-worn P quest artifact don't allow Vorpal Blade to behead a monster when it swallowed you golems are not living and don't "die" in messages fix "Rocky solidifies. Now it's Rocky!" polymorphing into a flesh golem, which gets petrified by turning into a stone golem, now works when stoned correct "killed by a died" allow the Wizard to come back and harass at his next reincarnation time even if he's been left alive on some other level (fixes "paralysis" cheat) make monsters subject to "mysterious force" in Gehnnom while climbing stairs with the Amulet, so that once the Wizard has stolen it, his retreat when wounded doesn't become an easy way to carry it up changing attributes immediately checks encumber messages confused monsters get confused SCR_TELEPORTATION effects fixed "choked on eating too rich a meal" kicked objects won't stop at stairs if they don't fall general fixes to stealing from monster carrying cockatrice corpse a nymph who polymorphs herself while you're frozen during a multi-turn armor theft can't complete the theft if transformed into non-stealer monster consistent corpse probability no matter what killed monster (also removes a loophole allowing permanent rider death) MUSE monsters no longer wield weapon same as (not better than) current one incubi/succubi have hands, not claws make #jump be ineffective on air and water levels allow multiple sickness causes; vomiting only cures those involving food #prayer reward: give books for not-yet-known spells preference to known ones marker use no longer uses wishing interface, fixing several obscure bugs archeologists' and rogues' initial sack starts out empty candelabra "has now" 7 candles fixed. kicked objects would set dknown when the kick caused an injury, even though safely kicked objects wouldn't make cloaks subject to burning make exposed shirts subject to burning and rotting; greased ones defend against wrap attacks all types of fire damage affect worn armor [adds explosions, fire traps, and zapping yourself to previously handled zap/breath attacks by monsters] for explosions, destroy carried objects before killing player [affects bones] replace triggered land mine with pit before doing damage [bones] black dragon breath no longer referred to as "death" instead of disintegration don't make ring of gain strength known when gauntlets of power mask its effect can't have "slippery minor currents" or similar silly nohands body parts proper support for polymorphed players using wrap attacks cannibalism reduces luck as well as causing aggravation picking up an item which will merge works even when all 52 slots in use moving through diagonal openings checks how much you're carrying, not how much free space you have left monsters have same restrictions as players moving through diagonal openings picking up subset of heavy group works for picking one and gets feedback right taking subset of heavy merged group out of containers works the same as picking up subset of heavy merged group from floor when putting gold into containers, don't count its weight twice, thereby messing up the status line's encumbrance feedback fix the option parser's handling of attempting to negate string values teleporting a monster on a trap with a magic whistle sets the trap off iron ball dragging no longer confuses autopickup cumulative temporary intrinsic increments can't spill over into permanent bits eating food shouldn't give messages for intermediate states don't make wand of death become known after casting finger of death at yourself ignore case when checking artifacts against wish- or #name-specified name ignore confusion when reading scrolls of mail exploding runes for spellbook read failure doesn't imply that book explodes divine rescue from strangling destroys worn amulet of strangulation boulders pushed on level teleporters will level teleport; also, make one random level teleport function to keep all level teleports consistent MSDOS: add fake mail daemon MSDOS: add VGA tiles to tty port VMS: switch to lint-free, non-GPL'd termcap support code X11: map behind popup edges was occasionally not refreshed X11: allow permanent inventory window X11: when using tiles, highlight pets with "heart" overlay (should be changed to honor the `hilite_pet' run-time option) X11: click-in-message-windows crash fixed tty: fix panic when freeing endwin tty: fix behavior when recalled text needs to wrap beyond top line tty: allow selection from single line "help menu" (getobj's '?' response) tty: don't format data.base with hardcoded tabs that are ugly on non-tty ports tty: get rid of extra NHW_MENU space (improperly added when the menu was longer than the screen) tty: fix repeated "who are you?" prompting at game startup nethack-3.6.0/doc/fixes32.10000664000076400007660000001654512467321052014264 0ustar paxedpaxedGeneral Fixes and Modified Features ----------------------------------- give invocation message when teleporting onto invocation position flying players with water breathing may retrieve things from water remove message inconsistently assuming players can be mindless monsters wear best armor (not first armor) and may switch armors god doesn't give "strayed" message when your god is angry but a different god is the one giving the message divine wrath can hit engulfer if you are swallowed plug minor topten and oracle memory leaks monster throwing must allow for 0 damage (cream pies, non-silver vs. shades) break drawbridge if wand of striking is zapped down at open bridge or either up or down at its portcullis wand of striking zapped at ceiling might cause a rock to drop (like digging) wand of striking hitting a secret door with expose and break it zapping {teleportation,cancellation,make invisible,polymorph} down affects any existing engraving similarly to writing with such wands monsters may use fire horns and frost horns Guidebook.mn now formats backslashes correctly when using GNU groff tools Add missing trident case to weapon type categorization. Fix weapon proficiency handling for missiles. accept "armour" spelling again for marker use (when writing was disconnected from wishing, this got lost) restrict writing scrolls and books by description give better feedback for some writing results whirly/wall-passing monsters should not be immune to falling rocks relearn spellbook even when spell already known (object amnesia fix) objects that have been called something but not ID'd are subject to amnesia ask what to call unknown spellbook which crumbles to dust when mis-read bullwhip only tries to get you out of a pit when you're in a pit humanoids, gnomes, and ogres now eat; fungi and jellies don't centaurs, giants, and various others can respond to #chat potion of paralysis doesn't inherit prior nomovemsg #naming a nameable artifact when the object already had a name of the same length didn't create an artifact applying unID'd potion of oil is possible even not carrying any other items eligible to be applied make potion of oil become known after lighting it via apply fix remaining inconsistency which allowed diluted water don't let breaking a wand of digging on castle level produce holes, just pits make Nazgul's sleep gas actually put victims temporarily to sleep applying a carried, unlocked, trapped chest will set off the trap explosion due to #untrap failure on trapped door destroys it shouldn't hear curse/bless status of unseen scroll being read by monster give some variation in the amount of time it takes a corpse to rot away breakable objects hitting the ceiling or the hero's head will now break undead turning now gives credit to player for destroyed monsters undead turning now brings dead eggs back to hatchable status code added to support hatching of all eggs in a merged group of eggs fix display updating at egg's former location when floor egg hatches fix learning of egg type for hatched eggs statue traps created with monster inventory inside them probing shows contents of everything with contents, not just statues spells of healing and extra healing don't make target monster angry use cornuthaum cancellation factor can't kick underwater objects from land or vice versa objects falling through holes/trapdoors to random destinations obey arrival restrictions imposed by special levels being bare-handed counts as wrong projector when throwing projectiles reduce the range that Mjollnir can be thrown keep Medusa from continuing to move after she's been killed by reflection of her own gaze (fixes relmon panic) medusa's reflected gaze won't affect it if it has amulet/shield of reflection eating amulet of strangulation can choke when not satiated; also not gluttony intelligent pets hold onto one pick-axe and one unicorn horn keep exploding boulders from land mines from hitting you with "a rocks" objects carried by migrating monsters have no location more robust parsing of user-supplied option names; trailing characters matter don't generate spellbooks inside statues of tiny monsters treat Medusa level statues as petrified monsters (can't be stone-resistant, and have inventory) Medusa doesn't gaze more than once per round data.base: eliminate duplication of Orcrist/goblin king entry handle luck conferring artifacts correctly (both inventory and enlightenment) prevent arming land mines and bear traps in various inappropriate locations prevent easy shop exit by having shopkeeper disarm and pick up trap objects oilskin cloaks allow defender to slip away from grabbing attacker make reading the cursed Book of the Dead riskier enchanting stat-affecting armor now identifies it fix crash caused by specifying "pickup_types" without a value in config file or NETHACKOPTIONS (avoid attempt to use menu prior to interface init) kicking at empty lit corridor with lit_corridor enabled doesn't redraw as unlit when starting out with an oil lamp, make pre-discovered potions of oil show up in the discoveries list so that their varying description is available being crowned Hand of Elbereth enables minimal longsword proficiency even when Excalibur isn't bestowed bare-handed and martial arts weapon skill rankings use names instead of numbers Platform- and/or Interface-Specific Fixes ----------------------------------------- tty: reduce alloc/free activity done for message history tty: windowtype:unsupported_value pauses between listing allowed value(s) and proceding under default interface X11: free allocated memory during pre-exit cleanup X11: display help when DLB is enabled X11: fix popup inventory window shown for 'i' response to "what type of object?" prompt with menustyle={T,C} DLB: avoid excessive fseek calls (major performance hit for MSDOS) MFLOPPY: wasn't safe to enter endgame! traps, timers, and other level- specific data ended up being inherited from level 1 MSDOS: now can re-enter game after chdir'ing in shell from "!" MSDOS: fix it so -H allows starting a healer game, rather than usage statement MSDOS: display cursor during input prompts, not just when in the map MSDOS: fix several cursor-related glitches when moving the display MSDOS: prevent the use of F3,F4, and F5 before the map window is ready MSDOS: make flags.BIOS and flags.rawio the default when VGA tiles are used TERMINFO: colors were wrong for some systems, such as Linux Amiga: count substitute tiles properly MAC: avoid MW 68K struct copy optimization bug (in all developer releases up to and including DR9) by adjusting our structures so it doesn't occur MAC: fix crash when trying to drag scrollbar MAC: add UPP setup for UserItem FrameItem() MAC: boost partitions to 2M minimum General New Features -------------------- #qualifications command eliminated; subsumed into #enhance OEXTRA temporary compile-time option menu support for group accelerators to choose objects by class lev_comp supports specification of percentage chance for monsters and objects wielding Sunsword provides protection from light-induced blindness interactive setting of options via menu (Per Liboriussen, liborius@daimi.aau.dk) Platform- and/or Interface-Specific New Features ------------------------------------------------ MSDOS: Add support for preloading all tiles in protected mode environments MSDOS: Add support and initial tty Makefile for yet another compiler (Symantec) BeOS: preliminary support for new BeBox platform; initially tty only nethack-3.6.0/doc/fixes32.20000664000076400007660000001654312467321052014263 0ustar paxedpaxedGeneral Fixes and Modified Features ----------------------------------- make `recover' work with the additional element of version info added in 3.2.1 floating eyes cannot escape down stairs and ladders do not use body_part() inappropriately when snatching monster's weapon fix feedback for a confused long worm attacking itself avoid converting locked secret door into closed+locked normal door; doors should be flagged as either locked or closed but not both kicking a locked secret door mustn't yield an open normal door fixes for dipping weapons into potions of oil fix crash triggered when knocking off worn blindfold by applying cursed towel update screen display for vault guard picking up gold from fake corridor Chromatic Dragon was missing appropriate resistances for orange (sleep) and yellow (acid + stoning) dragons when triggering a chest trap, clear the trap flag immediately [bones fodder] when a boulder gets pushed into a pit where a monster is trapped, immediately redisplay the monster after giving messages rings of hunger dropped in sinks should have an effect even if player is blind player #offering a cockatrice corpse must pass a touch check hitting a rust monster with a pick-axe, iron ball, or chain will trigger rust damage to the weapon; ditto for rust traps when wielding such items cosmetic martial arts and bare-handed changes to skill arrays in u_init.c gain or lose weapon skill slots appropriately when polymorph into new person fix crash occuring when self-hit by uncaught boomerang when delivering a pline message during level change, don't display areas of the new level using line-of-sight data from the old one heavy iron balls may be thrown multiple spaces (presumably they roll), restoring old ball behavior get rid of "non-null minvent despite MM_NOINVENT" warning prevent a negative damage adjustment from boosting a target monster's HP give "bashing" message when first attacking something with unconventional wielded items besides just throwing weapons and non-weapon tools when restoring, reset weapon so that "bashing" message can be given again hole traps in bones data shouldn't be marked as unseen when carrying 52 items, don't check shop goods for mergability with invent because it will give false matches, yielding non-gold in slot '#' kicking a cockatrice corpse is now as dangerous as kicking a live cockatrice fix set_apparxy() crash when the Wizard returns via migrating monster list monster wearing armor is protected from disintegration breath like player monster wearing amulet of life saving survives disintegration breath greased helmets will block AD_DRIN attacks get rid of ancient check for welded weapons, which arbitrarily named or didn't name the weapon for no particular reason. levitation: sitting makes you tumble, kicking requires bracing empty bag of tricks won't cause bag of holding to explode prevent "force bolt" from hitting false match on *orc* data.base entry prevent "{wand,scroll,spellbook} of light" from matching "* light" entry non-confused genocide of player should not kill by "genocidal confusion" re-word message for monster grasping already-wielded unicorn horn fix various killer reasons when pushing boulders, make sure current is always top object at its location always clear unpaid items off shop bill when shk is teleported away, even if shk was already angry don't let broken wand of digging create traps at locations which already have traps (prevent it from turning a hole into a pit) don't give messages about unseen objects falling down holes fix to prevent kicked objects which stop on holes/downstairs from becoming unattached from any object list don't let flying creatures set off a rolling boulder trap fix to prevent seeing into a room by kicking an undiscovered locked secret door from outside account for case of monster throwing gem at PC unicorn schedule repair for shop door smashed by big monster update status line for energy used when "you fail to cast the spell correctly" polymorphed character will mimic gold after eating mimic corpse fix relmon panic when bashing weak undead with wielded potion of holy water holy and unholy water can trigger transformation in werecritters call update_inventory() when discovering or undiscovering (call " ") an object fix goto_level panic: if quest leader seals portal, delete portal trap from quest home level as well as from main dungeon's branch level [possible return to quest via 'W' quest artifact] prefix quest leader and/or nemesis name with "the" when appropriate at run-time rather than using hard-coded text in quest.txt fix endgame crash caused by string overflow when formatting priest|minion names dokick.c compiles when WEAPON_SKILLS is disabled burning objects go out when kicked monsters with arms but not legs (salamander, marilith) can't kick knights can't jump while poly'd into anything without legs try harder to get names for corpses of unique monsters right very high dexterity doesn't guarantee a hit for thrown potions and eggs blinding ammo thrown from inside an engulfer can't blind it monsters going through endgame portals arrive in same area as the player instead of ending up at the portal to the next level treat most of the moat on fakewiz levels as outside the special central area, so that falling or wading into the water and auto-teleporting out of it can't strand the character inside the room monsters created by animating a named figurine will inherit that name prevent possible player-controlled creation of unique monsters via tossing statues of such onto statue trap locations activating a statue trap with wand or pick-axe won't discard statue contents cursed non-weapons can't slip when thrown, as it was in 3.1.x don't reveal patron deity of high priests with the 'C' command's prompt two flags structures now, flags and iflags, the latter not saved with the game object name prefix buffer wasn't big enough for biggest possible case negatively enchanted weapons thrown by monsters could do negative damage prevent xorns from phazing through walls on astral level live Wizard won't teleport to your level if he's carrying the Amulet can't use 'C' to give the Wizard a name fix charging for shop goods broken via striking/force bolt prevent disintegration breath from destroying Famine and Pestilence and from triggering impossible("monster with zero hp?") for Death prevent attached ball and/or chain from becoming part of iron golem formed during polypiling (ball & chain movement later accessed freed memory, which either crashed or got "remove_object: obj not on floor" panic) Platform- and/or Interface-Specific Fixes ----------------------------------------- Mac: update `mrecover' Mac: handle `-@' character name suffix for explicitly requesting random role msdos: suppress tiles on rogue level when restoring games that were saved there tty: support group accelerators for PICK_ONE menus tty: after at a yn() prompt, don't blindly accept the character used to get back to the prompt as the yn() result [could trigger impossible("invalid sell response")] Unix+tty: guard against problems with delay_output,TRUE/FALSE macros X11: fix group accelerators and support them for PICK_ONE menus X11: implement tty-style counts for menu selections X11: proper pop-up placement with old-style window managers (eg X11R6 twm) General New Features -------------------- Platform- and/or Interface-Specific New Features ------------------------------------------------ nethack-3.6.0/doc/fixes32.30000664000076400007660000000323012467321052014251 0ustar paxedpaxedGeneral Fixes and Modified Features ----------------------------------- Y2K fix: use 4 digit year values for the dates in the score file updated COPYRIGHT_BANNER_A to reflect year of release prevent "late" pline calls from triggering a crash when the RIP window was displayed at end of game (observed when bones file rename failure under Win95 was reported to wizard mode users) being punished on the Plane of Water doesn't trigger a panic when air bubbles try to move the ball&chain or you around avoid rn2(0) divide by 0 for empty inventory when trying to crawl out of water don't let randomly placed monsters on special levels prevent explicitly placed monsters who target that location from being created (a web trap's spider resulted in no quest nemesis) don't let randomly placed stairs on special levels be covered by explicitly placed features such as fountains pager: guard against '%' in output from being treated as a printf formatting directive (using '/' or ';' to look at food yields "% blah blah") prayer result of ``escape from solid rock'' isn't inhibited by teleport restrictions (attempting to fix all troubles got stuck in a loop) report "file empty?" rather than "version mismatch" when that's the reason why a data file fails its validation check drum of earthquake can't destroy the high altars Platform- and/or Interface-Specific Fixes ----------------------------------------- micro (assorted): readmail()--don't show fake mail text when blind; also, update the "report bugs to" message to specify msdos: fix missing $(INCL) in dependency in djgpp Makefile mac: Will only dispatch events if the window system is initialized nethack-3.6.0/doc/fixes33.00000664000076400007660000005173212467321052014261 0ustar paxedpaxedGeneral Fixes and Modified Features ----------------------------------- objects falling down a level don't cause everything at destination to scatter randomize visible trap glyphs during hallucination don't match statue entry when looking up statue trap [after trap detection] do match statue entry when looking up "statue of a " when foo happens to precede statue in the database; likewise for figurines initialize random number generator before processing user configuration file (random role selection always selected tourist) support "character:X" and "role:X" in NETHACKOPTIONS as well as in config file allow colon as an alternative to equals sign for `OPTIONS:whatever' and equals sign as an alternative to colon for `pickup_types=?!="$' make rndexp (blessed gain level) be safe for 16 bit integer configurations don't add player's weapon proficiency bonus for weapon attacks by monsters create quest artifact crystal balls with 5 charges instead of 0 store ghost names in the same manner as other monster names (fix pet bug) boost kobold shaman level to 2 (was 1, too low to ever cast a spell) boost ogre king level to 9 (was 7, same as ogre lord) throwing quest artifact to quest leader won't cause anger; also, artifact will be caught and thrown back instead of being explicitly ignored boost level of fake players in endgame to match their rank titles don't lose odd hit points (integer division truncation) when splitting HP for cloned monsters update status line when cloning yourself halves your hit points suppress clone's initial inventory for poly'd player just as for monsters update the documention describing the O command polyself: immediately update vision when reverting to human from eyeless form use right pronoun when a mind flayer's attack is blocked by a monster's helmet tins of lizard meat are never rotten, just like the corresponding corpses tattered capes should not match ape entry in database booze should not match ooze entry in database lowered drawbridge should not match werecritter entry lengthen option file line length to 4*BUFSZ make zaps of death at polymorphed players work properly change way invisibility works, add remembered invis monsters and 'F' command don't list pick-axe and unicorn horn as likely candidates for charging give more accurate message when nymph steals multi-turn armor from female char fix splitting merged group of wielded weapons for menu mode version of #loot if a buried container rots away, bury rather than destroy any contents the 'W'ear command now only shows armor you can actually wear at this instant, instead of all armor you're not currently wearing wishing for a genocided monster egg gets a dead egg, not a generic egg "Unfortunately it is still genocided" printed only if monster is in range (particularly important for lifesaved monster genocided off-level). message for monster growing into genocided monster only printed if in range include number of attached candles when formatting candelabrum's name support attaching already lit candles to candelabrum range of candlelight varies with number of candles dropping ring of hunger onto sink won't falsely claim that undestroyed objects like the Amulet have vanished winged gargoyle can't wear body armor self probing and stethoscope display speed with same detail as enlightenment throwing attacks can trigger reprisals similar to hand-to-hand and zap attacks 'A' now works in dropping like when picking up make setting bear traps and land mines be a multi-turn occupation make lava be properly lit on special levels add orig.female flag to handle E quest monster situation clean up inconsistent quest text in initial legacy message, use "goddess" when appropriate allow FIRSTNEMESIS message to actually be printed taking a peaceful monster's weapon with applied bullwhip will anger victim applying an unpaid magic lamp will charge a low lighting fee instead of the djinni release fee teleporting a Rider will usually bring it near you instead of sending it away Riders can open locked doors without a key, just like the Wizard Riders, angels, and elves won't avoid stepping on Elbereth/scare monster when deciding where to walk Riders and angels will ignore the sanctuary effect of temples mind flayers cannot suck out brains by hitting long worm tails don't ignore object age when #offering a partially eaten corpse inability to pick up is not as general as nolimbs (blobs may pick up with pseudopods and purple worms by swallowing) wishing for a magic lamp produces an oil lamp, not a no-charges, possibly lit, magic lamp blobs may not ooze under doors if their inventory can't be squeezed through peaceful/tame monsters will not use bullwhips on the player ghosts were not inheriting player gender in bones files cannot wish for tins of untinnable (due to insubstantiality) monsters flying monsters cannot fall down stairs prevent divine retribution from destroying a wand which is being broken fix resuming to read a spellbook which has become blank since the prior read attempt got interrupted make recharging cancelled wands behave like recharging other cancelled objects prevent "late" pline calls from triggering a crash when the RIP window was displayed at end of game (observed when bones file rename failure under Win95 was reported to wizard mode users) cannot shatter soft weapons (whips, rubber hoses) being punished on the Plane of Water doesn't trigger a panic when air bubbles try to move the ball&chain or you around seen-invisible monsters are consistently visible but transparent, rather than looking like normal monsters kicked object message for hitting another object no longer claims it "stops" kicked object hits objects (plural) if quan>1 but there is nothing else there kicking an object which is embedded in a closed door behaves like one in rock can't kick object out of a known pit, but could when pit hadn't been seen yet pets, shopkeepers, unique monsters, trolls, and Riders retain their characteristics when killed and brought back to life being polymorphed into a black light makes you hallucination resistant don't attempt to perform panic save if the game is already over don't leave old game's timers, light sources, and shop data in place if aborted restore attempt reverts to starting new game [eventual panic] Magicbane carried by mplayers has a lower enchantment than other artifacts if pets take longer to untame than to starve, make them go wild anyway split up erosion to allow both rust and acid (or fire and rot) rust/fire/corrosion/rot now work in all cases (monster/monster, monster/you) upon arrival to quest, mark return portal as seen can't be blinded by light while asleep can't put boulders or big statues into containers engulfers which engulf a pile engulf 'several objects' polyself: use right set of hit points for hunger and strength loss polyself: likewise when checking for troubles during prayer polyself: stop mimicking gold immediately if shape change occurs polyself: change monster type when sex change occurs for succubus or incubus Y2K fix: use 4 digit year values for the dates in the score file when changing levels, update the screen to show the new level sooner when changing levels, a monster might displace you from the stairs upon arrival petrify polymorphed player who has protected hands but is using a non-hand attack on a cockatrice fix bug where barehanded AT_WEAP by polymorphed player on cockatrice worked prevent multiple purchases of clairvoyance at temple from overflowing the intrinsic's timed subfield and becoming permanent when cursed, greased or oilskin cloak might fail to protect against grabbing when any corpse wielded by a monster rots away, unwield it to avoid "bad monster weapon restore" hallucination affects priest and minion names don't try to make the word "aklys" singular bullwhip can't yank welded weapon from target eroded T-shirts now display the eroded shirt text consistently fix "killed by kicking something weird" when kicking a fountain disallow fruit names whose prefixes are valid for food (uncursed, numbers, etc.) properly handle wishing for fruits which start with other prefixes avoid rn2(0) divide by 0 for empty inventory when trying to crawl out of water don't let randomly placed monsters on special levels prevent explicitly placed monsters who target that location from being created (a web trap's spider resulted in no quest nemesis) don't let randomly placed stairs on special levels be covered by explicitly placed features such as fountains substitute random monsters when special level monsters have been genocided fix intrinsic blockage by worn items so that wielding a mummy wrapping or cornuthaum won't have the same special effect as wearing one magic markers created via polymorphing tools are flagged as being recharged unseen rust monster eating messages, and make tame rust monsters consistent with wild ones with regard to rustproofed items pager: guard against '%' in output from being treated as a printf formatting directive (using '/' or ';' to look at food yields "% blah blah") getpos: support shifted movement letters in number_pad as per help text getpos: properly truncate diagonal movements at map edge using #name to call an object type something could be used to distinguish fake amulet of yendor (appeared in discoveries list) from real (didn't) upon quest completion, leader now IDs quest artifact and also tells player that Bell of Opening is necessary if character doesn't already have it remove unwanted quote marks from quest message R 70 make polymorphed objects be likely to retain magic state: non-magic items usually yield other non-magic items, magic items yield magic ones make artifact mirrors unlikely to break when used to hit monsters make sure that nemeses don't leave corpses if the message says there's no body fix wizard-mode problem with generating Master of Thieves (was singularizing it) allow weapon-using monsters who ignore gems to throw darts make flint stones be the preferred ammo for sling wielding monsters gaining/losing telepathy via polymorph (i.e. mind flayer) redisplays monsters prayer result of ``escape from solid rock'' isn't inhibited by teleport restrictions (attempting to fix all troubles got stuck in a loop) fix surviving level teleport to a negative destination from somewhere other than the main dungeon (was corrupting the level maps) surviving level teleport to a negative destination ("you float down to earth") escapes the dungeon instead of arriving on level 1 dying due to level teleport directly to heaven won't leave bones kicking shades with blessed boots, punching with blessed gloves or when wearing silver rings, does the appropriate damage to them add artifacts to ending score and display prevent used objects like scrolls and potions which immediately cause the character's death from remaining in final inventory (disclosure+bones) blessed genocide of '@' will list the player's role during genocide disclosure moved skill definitions to their own file (skills.h) and embedded them in the object table. increased the maximum number of branches supported by dgn_comp. increased the number of characters permitted in a role name. the number of bits available for properties are expanded. water demons should not chat about being freed. since hallucinating players see monsters constantly change anyway, don't print message when werecritter changes artifacts which do fire/cold/electric damage to their targets can destroy carried objects which are susceptible to that type of damage some artifacts are now unaligned in order to be more accessible to all types of characters wizard mode ^F command reveals floor traps along with the map pager: '/' was not finding data.base entries for shopkeepers, mimics, or race/role spit when picking from the screen small monsters like hobbits and gnome zombies couldn't wear cloaks/wraps make sure non-erodable objects aren't eroded or erodeproof (could happen by wishing or object polymorph) consistently let iron non-weapons rust, etc. handle more spelling variations ("boots of speed",&c) when granting wishes fix 3.2.0 change which flags the castle and priest quest levels as graveyards when stepping on a spot where "there are several objects here" (so many objects that they aren't automatically shown to the user), report any dungeon feature such as stairs just like when there are fewer objects report "file empty?" rather than "version mismatch" when that's the reason why a data file fails its validation check to-hit bonuses don't accumulate for monsters with multiple weapon attacks skill definitions moved to skills.h skills are stored in the objects[] table. intrinsics and extrinsics are now >32 bit number of roles no longer limited to 26 letters renamed typename() to obj_typename() add "You hear a nearby zap" when monster is close fixed a bug that would print of "a Book of the Dead" instead of "The" fixed a bug so there is no delay when a rolling boulder trap is triggered completely out of sight fixed emergency_disrobe() so it will drop gold fixed a missing case that occurs (rarely) when praying during a full moon and your god is very pleased ask for confirmation before praying; no more accidental Alt-P more guilt messages when you do something which lowers alignment mplayers get more suitable equipment for their role allow spaces before = in the options file dragon scales/scale mail of all colors now work when worn by monsters (in 3.2.x, only gray conferred any special benefit) when shopkeeper takes cash from dead player's corpse, clear `been robbed' status if there's enough gold to cover the amount so that next player who loads level as bones data won't start out owing money merged scrolls of scare monster crumble to dust together, matching the existing feedback (was destroying one and leaving the rest) properly disallow wishing for venom and allow wishing for iron balls by class drum of earthquake can't destroy the high altars potion of oil can't be ignited while underwater zapping a wand of digging upwards while underwater won't dislodge a rock from the ceiling add "born" field so monster extinction limits the number created, not killed allow "okonomiyaki", etc. to pluralize properly (Ranma 1/2 is popular) fix off-by-one bug that disabled the check to see if you tried to name your fruit after a previously existing corpse or egg avoid a "glorkum" message if an object conveying a warning is stolen before the warning message is delivered flags.made_amulet flag was never being set make sure proper message is given when tinning cockatrice while a flesh golem fix punctuation on cancelled cobra's dry rattle message leash cannot choke monsters that do not breathe rothes are now brown, harder to confuse with much more powerful grey quadrupeds defer level change for every schedule_goto() call, not just while monsters are moving (player's move could cause an engulfer to expel character onto a level changing trap, then attempt to access stale monster and possibly trigger relmon panic or crash) fix obscure worm bug which did not consider the tail tip to be visible. Bug produced "You miss it" on 3.2 and a blatantly obvious 'I' in prerelease 3.3. water prayer: treat already blessed potions as `other' rather than as `water' water prayer: potions being blessed glow light blue rather than amber; hallucination affects the color seen when changed potions glow fix Death/Sandman #9 joke (should be 8) and make sure the message can be seen zapping Death with wand of death multiple times could cause hit points to wrap when pet attacks monster that attacks back, be sure it's in range (could be a worm attacked on the tail) Platform- and/or Interface-Specific Fixes ----------------------------------------- micro: -uwizard-{class} counts as -uwizard when allowing debug mode micro (assorted): readmail()--don't show fake mail text when blind; also, update the "report bugs to" message to specify devteam@nethack.org msdos: fix overlay separations in weapon.c msdos: fix problem breaking compile without REINCARNATION msdos: fix dependency in djgpp Makefile (wintty.c -> hack.h) tty: try to use terminfo sgr0 (aka termcap me) attribute to turn off all text attributes, instead of just using "rmso" (aka "se") attribute. tty: change name of nethack's termcap.h to be tcap.h tty: ^P at a long prompt printed an extra newline (and then wrapped oddly) tty: get repeat to work properly on extended commands tty/ASCIIGRAPH: rogue level uses PC Rogue colors and symbols nt: in TTY port, non-English keyboard layouts that depended on AltGr-+ sequence were getting "Unknown command 'M-\'" for '\','@','$','{','[',']','}'. tty and X11: avoid crashing trying to display long (>128 char) menu items X11: avoid setuid install problems by changing uid to real uid while opening the X11 connection. unix: compress/uncompress detects failure of the compressor, such as for filesystem full or missing compressor, and no longer deletes the valid file. In the uncompress case, such as uncompressing the save file, a message is generated as well. dlb: handle situation where lseek(,,SEEK_END) doesn't yield the size of the contents of a file (specifically, VMS "variable length" record format) vms: install.com couldn't handle the `copy readonly files' step when DLB wasn't enabled mac: added unix tty-ish menu flexability mac: stoped using OLDROUTINENAMES mac: added dlb support mac: Increased the maximum number of menu items, so the inventory won't get cut off at the bottom. mac: Changed the behavior of Cmd-Q so it uses the new #quit command. mac: Will only dispatch events if the window system is initialized. This fixes a bug that would crash the system if the user had an invalid option in the NetHack Defaults file. mac: Added an appropriate message when eating an apple. mac: Change the askname dialog for the new role patch. mac: Add a gray background to all dialogs. mac: Replace some improper calls to InitCursor(). mac: Remove a whole bunch of unused code. mac: Added Balloon Help messages. mac: Pop-up menus display the 3-letter file code instead of a single letter. mac: Pop-up menus and text item have a 3-dimensional look. General New Features -------------------- incorporate the "wizard patch" `#quit' command added `*' command added; displays inventory of all equipment currently in use add Stone To Flesh spell wands eventually explode if rechaged too many times show IDed Amulet of Yendor + invocation tools in own section of discoveries list; likewise for IDed artifacts add infravision add Eyes of the Overworld add lenses split players race from role in life cursed figurines cam spontaneously transform when carried `in_use' struct obj field is unconditional rather than just #if !NO_SIGNAL add the secondary weapon slot, e(x)change command, #twoweapon command, and "pushweapon" option. add the quiver slot, (Q)uiver command, (f)ire command, and "autoquiver" option (defaults to false). add the "pickup_burden" option which controls when the user is asked for confirmation when picking up an item. pole-weapons can be applied at a distance, and similarly used by monsters. '/' command's pick-a-location input (getpos) supports shortcuts to bypass the "more info?" prompt; ':' for '.'+'y', ',' for '.'+'n', ';' for ','+ESC monsters can throw cockatrice eggs at players prayer trouble "stuck in wall" takes boulders into consideration crysknives can be "fixed" vampires now #chat back new monsters: chickatrice,pyrolisk,fox,coyote,winter wolf cub,dingo, gas spore,flaming sphere,shocking sphere,lynx,panther,raven, glass piercer,mastodon,woodchuck,centipede,master mind flayer, pony,horse,warhorse,silver dragon,lichen,storm giant,arch-lich, dwarf mummy,green slime,disenchanter,monkey,dwarf zombie,ghoul, paper golem, gold golem,glass golem,prisoner,jellyfish,piranha, shark new objects: amulet of unchanging,silver dagger,silver spear, silver dragon scales/mail,robe,alchemy smock,kicking boots, kelp frond,eucalyptus leaf,scroll of earth,spell of drain life, potion of acid,potion of full healing,potion of polymorph, potion of sleeping,ring of free action,ring of gain constitution, ring of increase accuracy,ring of slow digestion,grappling hook, ring of sustain ability,wand of enlightenment,saddle,various gems add Monk role the old Elf role is replaced by the Ranger add Human, Elf, Dwarf, Gnome, and Orc races add multishot ammunition add graves, iron bars, trees, and arboreal levels dwarvish mattocks can be used to dig add leprechaun, cockatrice, and anthole special rooms add the Sokoban dungeon implement talking artifacts members of the clergy (aligned/high/player priests and monks) are generated with a robe instead of chain mail. new tin of meat types tinning kits and cameras have charges blessed magic mapping detects secret doors starting spells are known at start of game pre-discoveries are listed with an * voluntary challenges with #conduct add a funny message when eating tridents and flint stones allow debug-mode level teleport to the sanctum some #monster commands now consume energy trees can be kicked as a possible source of fruit Wile E. Coyote references when using '/' on a coyote Platform- and/or Interface-Specific New Features ------------------------------------------------ WinNT: implement mail support WinNT: console mouse support added to TTY port nethack-3.6.0/doc/fixes33.10000664000076400007660000006164212467321052014263 0ustar paxedpaxedGeneral Fixes and Modified Features ----------------------------------- discarding a tin without eating should not count towards food conduct expand 'nethack.cnf' in dat/help to include new names on some platforms using 'C' to name a steed produces a "pony tail" stopping reading a spellbook when "too much to comprehend" left in_use set conduct: eating meat{ball,stick,ring,huge chunk} counts as eating meat don't select gems--aside from rocks and known glass or flint--via autoquiver skilled slingers can shoot multiple rocks with one shot, like other archers orcs shooting orcish arrows from orcish bows get multishot bonus, like elves have 'Q' offer gems/stones as likely quiver candidates when wielding a sling 'Q' command--don't offer tools as likely quiver candidates spell hunger effect for wizards of high intelligence was not computed correctly fix "killed by the [master] mind flayer" bug redisplay correct trap glyphs when hallucination ends monsters under Conflict cannot attack other monsters that are already dead monsters that steal gold from monsters should teleport fix mummy wrappings worn by monsters to block invisibility applying a weapon or wieldable tool would sometimes give spurious messages about two-weapon combat applying a weapon or wieldable tool might not always end two-weapon combat receiving a divine gift artifact while wielding two weapons would unrestrict two-weapon skill instead of the skill for the artifact's type throwing and kicking while wielding two weapons exercised two-weapon skill when wielding two weapons, ')' command should show both giants cannot "easily pick up" boulders on the Sokoban level W command would let you wear an arbitrary item in your body armor slot if that was empty & uncovered and you carried extra armor for any filled slot W command would list entire inventory if you answered '?' to the "what do you want to wear?" prompt when all unworn armor couldn't be worn #looting and applying containers with menustyle != traditional would do bad things if you split a merged stack in quiver or secondary weapon slot save/restore while mounted or stuck could cause a game crash or other errors baby gray dragons should not be visible to infravision dying from a failed saddle attempt should name the monster without using hallucination spurious "Bummer, you've hit the ground" when hallucinating and dismounting constitution of <3 and >18 (possible in 3.3 because the ring of gain constitution was added) was not handled properly potion and wand of invisibility (on yourself) should not print message if you are already invisible, even if you can see invisible reviving tame monsters ended up tame but not peaceful and would attack you wishing for "rotproof" item is recognized as synonym for erodeproof your pair of boots "are" not affected when kicking rust monster should be "is" use article "a", not "an", with "eucalyptus leaf" fix crash if reviving troll has been genocided shouldn't see candles flicker when blind gas clouds use cloud symbol unchanging suppresses amulet of change, intrinsic lost by life-saving missing lucern hammer, silver dagger, silver spear in monster weapons buckled boots are brown Scorpius and centipedes are not web-makers race placeholders are M2_NOPOLY Monk species/leader/guardians are M1_HERBIVORE leader/nemesis flags fixed with |= instead of = freezing spheres won't leave corpses artifacts should add to ending score even if they are inside a bag being killed by a gas spore should not be treated as burning (most noticeable problem was that the death message did not include "killed by") remove a double period from "Caught himself in his own fireball.." automatic dog names restricted to dogs chatting with a monster that teleports after the chat (succubus, bribable demon) would put an 'I' symbol at the monster's destination stethoscope/probing should reveal identity of invisible monster, not use "it" wand of probing zapped at 'I' square with no monster should clear the 'I' cursed potion of invisibility drunk by monster should reveal 'I' kicked monster that evades kick by moving to unseen square should not leave 'I' in original position of monster closing a door on an invisible monster reveals the 'I' gas spores are recognized as having passive damage for purposes of pet attack since iron armor can now corrode, don't call all corroded armor "bronze armor" properly handle attacking a black pudding with a corrodeable weapon do not print "You still cannot see" when blind and removing lenses remove possibility of crashes when unseen monster engulfs items object shattered by wand should use plural verb when object is plural don't anger monsters when hitting them with invisibility or helpful unholy water for initial inventory, don't give out spellbooks in restricted spell skills for tourists' initial inventory, put darts in quiver rather than wield them artifact discoveries sometimes showed undiscovered object types (for example, Snickersnee as "katana" when katana was still known as "samurai sword") "iron bars" singularization exception should not also catch "candy bars" if a monster kills a monster by throwing acid, don't credit the kill to you leave two-weapon combat mode if either weapon is stolen or otherwise unwielded use worse of (two weapon skill, current weapon skill) when figuring skill bonuses and penaltys while fighting with two weapons never give back-stabbing or weapon-shattering bonus when using two weapons engulfing monster will not engulf your pony while you are riding arch-lich usually starts with an athame or quarterstaff do not say that "an" Asmodeus reads a scroll '?' command--short options help sometimes included garbage output '?' command--longer options help omitted several recent options eating an amulet of restful sleep now works properly getting hit by a potion of sleeping now works properly sleeping is reported by enlightenment detect unseen / secret door detection refreshes unseen monster (`I') glyphs monsters won't pick up objects in water (especially kelp) unseen check for monsters in explosions fixed "petrified by an " silver arrows cost a little more than other arrows javelin back in its own class dipping weapons in potion of oil now works properly freed prisoners become peaceful monk titles shortened so they aren't cut off elven Priests get their starting musical instrument you can now correctly ride centaurs fixed steed getting teleported (e.g. by Quantum mechanic) fix stethoscope/probing speed reporting, and slowing attack on player blessed detect monsters increments (not sets) the timeout, and produces a message if no monsters are on the level put "Elbereth" under the sokoban prize so that monsters don't eat it a weak race can still have a high strength if polymorphed into a strong monster make dingos non barking canines suppress zap up/down message for stone to flesh on non-stone levels fix missing spaces on sokoban level that made level impossible without cheating use case-insensitive comparison for wishing (needed for Master Key of Thievery) avoid commas in the player name because they confuse the record file note Sliming when using probing/stethoscope on yourself fix inconsistency: reflecting medusa's gaze while invisible didn't work, reflecting floating eye's gaze did Medusa should not drink potion of invisibility (the code only checked for wands) restore confirmation prompt for kicking pets and peaceful monsters ask for confirmation about kicking steed when kicking while mounted converting secondary weapon into an artifact (naming, dipping) stops #twoweapon a fully ID'd object converted into an artifact is no longer fully ID'd polymorphing an object by dipping in potion while inside a shop will only anger the shopkeeper if the object is shop merchandize make {wand,spellbook,potion} of polymorph immune to being polymorphed turning undead should count as calling on a deity for purposes of conduct fix "monster trail" problem caused by reading a scroll of magic mapping while engulfed don't give Slow_digestion-related message when non-digesting engulfer expels you vary vampire's chat responses according to time of day, tameness, and player form added fish_parts to mbodypart/body_part fixed do-while loop test criteria in create_mplayers() fix crash if reviving troll has been completely drained by Stormbringer, et al a stinking cloud should not kill a monster more than once player stops riding when nymph steals saddle don't ask for name for eaten ring of slow digestion if already identified don't let engulfed lifesaved monster beat you up while supposedly being totally digested lev_comp: honor class in OBJECT entries (user's '+',"identify" made scroll) fix uninitialized buffer/unprintable characters error when eggs hatch accept "aluminium" as variant spelling for "aluminum" don't die from lava while praying correctly display gems for the final score even when blinded throwing a boomerang from {wielded,secondary,quiver} weapon slot will have it be restored to that slot if caught upon return don't allow iron balls to pass through iron bars fix "What weird role is this? (E)" for names taken from 3.2.x score records make spell of jumping work properly when restricted in escape spells save traits of petrified monsters; animated statues are like revived corpses unmoving monsters seen by infrared are removed from/displayed on the screen when they leave/enter direct line-of-sight Sting and Orcrist get their anti-orc bonus against orc player characters buffer overrun caused by many long names in a single message polymorph can't indirectly transform scrolls of mail into blank scrolls via paper golem creation don't let savebones() name a ghost without checking for sufficient space don't report "killed by ghost of Foo called Foo" on tombstone or in record when breaking create monster wands, don't place monsters inside solid rock don't allow tainted cockatrice corpses to prevent stoning if you eat one oil isn't seen as dimly glowing if you're blind properly consider hallucination and blindness when printing sliming messages don't allow the player to jump through iron bars or walls (the latter only when wearing the Eyes of the Overworld) don't allow the player to hurtle through iron bars work around race condition between breaking a wand of teleportation, teleport control and autopickup rust traps should affect scrolls lev_comp returns error if level cannot be fully written out blank scrolls/spellbooks don't count as reading material fix seduction attacks to treat characters polymorphed into golems as neuter chaotic sacrificing on a chaotic altar may crash if demon creation fails failed demon summoning might cause monsndx panic avoid possible crash when casting fireball spell while engulfed or near the edge of the map prevent observation of dust clouds in rogue level doorways when blind cans of grease will no longer rust skip already dead monsters when scanning the full monster list; avoids monsndx panic and other potential trouble skip already dead shopkeepers when checking for tended shops level teleport high in the air while lifesaved should result in an escape the "stoned" flag wasn't reset when a monster was lifesaved from turning to stone, so the next monster you killed would always turn to stone wooden harp is not a magical object player characters got left at 10 when "normal" speed was increased to 12 time it takes a monster to change armor doesn't depend on whether you see it character can't be totally digested on first turn of being swallowed level 25 engulfer would trigger divide by 0 crash via evaluating rnd(0) wielded egg that hatched wasn't cleaning up worn objects and might cause crash mirror shouldn't show location of unseen monsters cloth headwear was being reported as leather when fire damaged modify moveloop so that time (moves) is not relative to the player's speed fix moveloop to account for player not accumulating enough movement points to move in a turn -- this fixes the reported "time is wrong when burdened" problem monsters should not teleport on levels that disallow teleportation consider existing poison resistance when printing message while eating don't allow various spells/effects to turn monsters into genocided species don't crash on abusing guardian angel (accessing edog) call useupall() rather than useup() for organic items burned by lava revive any Rider corpse which gets teleported wishing for gold should affect conduct gold detection should detect gold golems grease should affect the secondary weapon in two-weapon mode falling drawbridge, eating cockatrice eggs, delayed self-genocide all caused monsters to be fully named instead of using "it". change the You_hear message if hero is asleep various inventory changes did not immediately update when perm_invent was set avoid crash when multiple, cascading explosions occur pets are no longer permanently weakened by a brush with starvation doeat() doesn't leave rotten food half-set-up for resumption don't allow trying to resume eating a revived rider corpse shopkeepers, priests and peaceful monsters should get angry when you cast stinking cloud on them when crowning a neutral wizard who knows finger of death but isn't carrying its spellbook, don't drop his weapon (crash likely) similar greased and non-greased objects would merge together into one stack monster reading scroll of earth may be allowed an extra attack change message for failed attempt to mount steed while punished fix multi-shot throwing for darts and shuriken update monster multi-shot throwing to match player throwing prevent inappropriate use of "lungs" in creatures that have none change several instances of 'pline("The ' to 'pline_The("' monk characters kick as characters rather than as kicking monsters fix kicking shades by character polymorphed into kicking monster fix articles in some Sokoban trap messages and eliminate some superfluous messages restoring with damaged subroom shops on non-current level could dereference stale shk pointer prevent removal of levitation in sokoban pits from causing you to "float gently to the ground" peaceful/tame mindflayer now mindblasts hostile monsters and vice versa (the check was backwards) fix suppression of stone-to-flesh on unique monster statues kill player when drain life induces negative HPs rumors used as engravings should not refer to fortune cookies magic-resistant players/monsters unhurt by monsters zapping wands of striking fix time problem where disrobing took too long saddle that comes with a knight's initial horse should be known to player iron golems are sensitive to more ways of getting wet with water prevent odd contents of initial tourist tins and eggs (the contents were mostly from the quest level, producing many cave spider eggs) breaking a wielded wand doesn't leave it wielded if nymph hits monster on first attack and teleports away, suppress second attack kicking a mimic should reveal its presence using 'F' command on a pet with safepet should not produce "thin air" message polymorphing into slime or fire creature removes Slimed; becoming a new man resets the Slimed timer throwing cockatrice corpse barehanded should stone the player avoid "petrified by petrification" on tombstone avoid "turning into green slime" on tombstone (KILLED_BY didn't work if Slimed) since unchanging prevents sliming, make it reset any sliming already present avoid "You turn into a female succubus" redundancy player hit by potion of acid should take damage like monster "You are protected" in enlightenment display should include u.uspellprot chameleons that change into a non-moving, non-attacking form shouldn't get stuck fix bug where monsters didn't wield bow (etc.) before shooting arrows (etc.) medium size is too large for giant bats (it allows leaving plate mails when killed) player polymorphed to a ghoul resists sickness just like a ghoul monster player in werecritter beast form shouldn't polymorph into "human" player wearing scales of genocided dragon was getting duplicate "you feel dragon-ish" messages when polymorphing fix luck timeout for full moon and friday 13th monsters must wield polearms before using them, just like players when saving bones data, shopkeepers will claim dropped objects inside shops pets will now wear objects they pick up pets will now wield pick-axes when necessary limbless pets are no longer able to carry objects monsters cannot consider a mattock for digging if they are wearing a shield avoid a case where monsters keep switching between pick-axe and weapon override hallucination when reporting pets that ascended or escaped with player avoid duplicate pickup() calls when landing after falling through a hole added squeaky board traps to Lord Surtur's lair entrances cursed lenses no longer considered a major problem by deity prevent "seeing an image of someone stalking you" when Blind disallow potion of polymorph / ring of polymorph control starting combo disallow starting with blank paper tools shouldn't charge beyond 127 charges getting money from a fountain should set the looted flag pole-weapons won't bash and will advance skill when on steed blessed genocide of polymorphed unchanging player should kill picking up nothing should take no time quiver command should take no time potions should not be autoquivered as worthless glass players should not get double-billed when using or altering items silver dragons should have same resistance as other dragons golems should be un (reverse-)genocidable player should get blamed for destroying Minetown fountains by Excalibur dipping player should not get blamed for others destroying Minetown fountains digesting ghosts and shades as a purple worm should be nonvegan but vegetarian eating brains as a mind flayer should be nonvegetarian eating eggs should be nonvegan but vegetarian eating tripe, meat sticks, chunks of meat should be nonvegetarian headstones now implemented through engraving luck penalty for the remaining forms of "creative NetHacking" in sokoban don't penalize a turn if player cancels #ride direction Ranger quest is no longer a rip-off of the old Elf quest several Hello() messages were inappropriate for various monsters storm giants should talk monk leader and guardians should use clerical spells monks shouldn't start with scrolls of enchant weapon movement rate when saddled was miscalculated items under lava shouldn't been seen or picked up clicking in status line during `/' shouldn't cause getpos error huge chunk of meat should count as dogfood "Pardon me" when moving directly into peaceful monster shouldn't glow amulet and save life of digested monsters " gets angry!" only when you can see the square "Never hit with a wielded weapon" conduct should only count weapons and weptools lynxes should not have cold attacks Naming a specific object asks "What do you want to name *this* ___" "Having fun sitting on the floor" shouldn't over fountain "ball lightning" changed to "ball of lightning" "poisoned by a poisoned crude arrow" should be "killed by a poisoned orcish arrow" shouldn't see invisible monsters oozing under a door fix apostrophe for invisible seen-invisible crumbling-to-dust liches amulet of change when polymorphed into single-gender monster could produce inconsistent role name for Priest(ess) and Cave(wo)man prevent Fire Brand from "burning" a water elemental snatching cockatrice corpse gloveless by applying bullwhip will now stone inventory description of wielded two-handed weapon uses "weapon in hands" inventory description of secondary weapon explicitly lists it as non-wielded to reduce confusion about two weapon combat Bell of Opening removes attached iron ball when performing opening magic chatting to a monster who responds with "I'm trapped" reveals the trap Make tmp_at() work when called in the midst of a previous tmp_at() sequence Make the messages for attempting to wear lenses over a blindfold more clear Prevent buffer overflow when reading engravings that are BUFSZ in length paralyzation message on steed should not say your feet are frozen to the floor avoid buffer overflows and associated security problems from getenv(), program name, and user name Platform- and/or Interface-Specific Fixes ----------------------------------------- Mac: legacy message was being truncated Mac: black background left mess on backspace Mac: backgrounds set too early on game startup Mac: tty window positions not remembered after move Mac: tty window turned B&W when moved to bottom of screen Mac: tty quit command fixed Mac: remnants of previous hunger status now cleared MFLOPPY: add checkspace option to avoid problems with >2GB free space MSDOS: fix clearlocks() to look for the right file names, and not LEVELS.* (MFLOPPY only) MSDOS: remove djgpp stuff from the Microsoft C Makefile MSDOS: change NetHack.cnf to defaults.nh in NHAccess.nh comments MSDOS: add missing files to gcc 'make spotless' NT: WIN32 specific code in tty_nh_poskey() was missing the necessary code to clear window flags so after hitting ESC messages that should have displayed did not Linux: set MAILPATH properly Linux: don't use control characters on Rogue level with IBM graphics DEC UNIX: set MAILPATH properly, type lex functions properly, avoid conflict with curses over naming Qt: remove intermediate files on 'make spotless' Qt: modify makefile to allow use with BSD make and FreeBSD Qt: have player selection dialog come up when name specified Qt: use default menu accelerators and allow remapping X11: fix memory leaks is reading from dialogs X11, tty: avoid crashing when displaying empty menus, as from 'i' with perm_invent and no inventory tty: when given the choice of ANSI color (AF) vs standard color (Sf), choose ANSI since there is some disagreement as to the correct color order for Sf, but no such disagreement for AF. tty: add workaround for termcap misfeature in some Linux distributions which affects DECgraphics display Amiga: minimal functionality restored Amiga: recover created empty (and unused) save.info files Amiga: ^P works properly Amiga: windowcreating modified for better adaptivity Amiga: changed from intuition menus to gadtools menus Amiga: changed default colors in tilemode to those of gfxfile Amiga: window backfill works Amiga: playerselection adopted from tty-port Amiga: linesplitting in msg/inv/menu windows fixed Amiga: obey user configured pens in nethack.cnf Atari: tty port rescued from oblivion, Gem windowing added General New Features -------------------- gold/glass golems, glass piercers now resist acid added sharks, piranha, jellyfish, prisoners, and iron bars to special levels piranha can appear in swamp rooms hero falls off steed when fumbling or falling down stairs artifacts speak when applied engraving "x" is not literacy demons and vampires engrave in blood shopkeepers don't like riding customers can #chat down to steed own race in Gnomish Mines replaced with random monsters differentiate between light/gaze-induced blindness and other causes of blindness yellow dragon scale mail provides acid resistance polymorphed player digests engulf victims more slowly if Slow_digestion Conflict now affects steed's desire to keep its rider undead turning of bones level player corpse causes ghost to reunite with the corpse control-x in regular mode displays name, role, race, gender, and your deities. wizard mode can wish for pools of lava pythons now have infravision to emulate real pythons heat sense organ M-2 added as a shortcut for #twoweapon general file location mechanism you can choose to #loot the saddle from something now message changes for silver dragon scale mail glowing silver and pit vipers falling into pits support explicit `race=random', `alignment=random', and `gender=random' in startup options manes now grow up into lemures potions of healing and sickness affect Pestilence in the opposite way to their effect on other monsters introduction of a new method of warning where you sense the danger level of monsters on the level by displaying it at the monster's location introduction of a new method of warning for specific monsters the way Sting does for Orcs; you sense their presence anywhere on the current level artifacts can belong to specific races and won't be given as gift when "hated" Archeologists get a penalty for breaking "historic" statues hatching eggs in male player's inventory have chance of "Daddy?" steeds affected by more types of wands zapped down opening/knock versus steed drops saddle unwearing your steed's saddle (e.g. stolen, opening) causes dismount yet another funny message when whipping a horse corpse yet another funny message when mounting when hallucinating Bell, Book, and Candelabrum added to final score like artifacts new keywords coaligned and noncoaligned for altars (and monsters/priests) in special level descriptions quest start levels get coaligned altars if their roles have multiple alignments, and goal levels get noncoaligned altars ice vortices and freezing spheres are infravisible Platform- and/or Interface-Specific New Features ------------------------------------------------ X11, tty, Amiga: offer for player selection only choices consistent with those already made by config file/command line (e.g., only offer roles that are compatible with specified race) tty: eight_bit_tty option Amiga: implement menu_* accelerators and counting mac: the "record" file is created if it does not exist nethack-3.6.0/doc/fixes34.00000664000076400007660000010642412467321052014261 0ustar paxedpaxedGeneral Fixes and Modified Features ----------------------------------- prevent an extraneous selection prompt when a role with only a single possible gender, race, or align is specified be consistent with the use of twice and thrice in end of game reports use "kill" vs "destroy" more consistently looting bag of tricks on the floor doesn't then prompt for direction suppress "the" in "you kill the poor Fido" iron bars added to the Dark One's prison shouldn't be able to #loot without hands level compiler can specify cockatrice nests, leprechaun halls, antholes fix level compiler to allow specifying golems via '\'' in MONSTER directives fix bug where excalibur blasted lawful non-Knights unification of the strings "he"/"him"/"his" conflict caused vanishing vault guards to be killed with player getting credit/blame (also dmonsfree warning for double removal from map) monsters' conflict resistance check was unintentionally being affected by character's experience level stone-to-flesh was accessing freed memory, passing bad map coordinates to newsym that might be harmless but could trigger a crash prevent spurious "placing steed on map?" impossibles during save/restore prevent real "placing steed on map?" impossibility [sic] when creating bones dropping secondary or quivered weapon to lighten load in order to crawl out of water left the item flagged as still worn if #adjust combined two or more of main weapon, alternate weapon, and quiver the resulting stack would be flagged as worn in multiple slots and eventually trigger "Setworn: mask = ##." impossibility remove curse operated on secondary weapon even though it wasn't wielded update conduct immediately when eating corpses (character killed by eating poisonous corpse as first meal was described as "strict vegan") fix problem with amulets of change when polymorphed into succubus/incubus YAFM for pit fiends/pit vipers and pits should require seeing the monster woodchucks, cockatrices, and vampire bats should eat specifying a non-numeric value for amount when donating to temple priest or bribing demon prince produced random result mastodons can tear through webs praying on wrong deity's altar cursed holy water but ignored uncursed water polymorphed player's gaze now works properly as a pyrolisk fix "You drop the Wizard of Yendor's corpse into Wizard of Yendor's interior." make sure status line gets updated when turning-into-slime state changes when eating green slime, don't reset slime countdown if already infected stop current activity when you noticed you're turning into slime message given when displacing an unnamed pet into a polymorph trapped referred to it by its new monster type rather than by what you displaced player killed by ghoul turns into one in the bones file slings are not made of wood for post-amnesia deja vu messages, use "seems" rather than "looks" when blind avoid encumberance messages during startup attribute adjusting even a wumpus cannot escape the pits in Sokoban when a steed dies in a shop, don't charge for the saddle shopkeeper did not charge for use of an unpaid camera shopkeeper did not charge for items burned by breaking a wand of fire shopkeeper should charge when you transmute a potion shk notices if you use a grappling hook to remove an item from the shop adjust robbed shopkeeper's feedback when he or she plunders hero's corpse avoid giving away which monsters are saddled while hallucinating when polymorphed into a herbivorous monster, you should prefer vegan "corpses" when polymorphed into a hider, stop hiding after picking up the last object at a location throwing a wielded, returning weapon should not disable twoweapon mode monster should not wield cockatrice corpse without gloves on sharks have thick skin better message when killed by drinking a potion of sickness from a sink telepathically detected monsters will be described by name if they try to attack praying character taking cockatrice from or putting it into a container should stone you if you are unprotected don't fall into pits (or other traps) twice when dismounting fix two weapon combat bonus/penalty to avoid "weapon_hit_bonus: bad skill 2" unicorns were at a disadvantage on a noteleport level missing a cockatrice when polymorphed into a weapon-using monster but fighting hand-to-hand would stone the player eliminate ghoul creation abuse when engraving on a headstone loss of levitation due to a sink will result in touching a wielded cockatrice corpse, just like falling down stairs while burdened falling into a sink when constitution is greater than 20 won't raise hit points stinking cloud should not affect migrating monsters, causes dmonsfree error only display message about monster using a weapon against another monster if you can see the monster don't count artifact amulets (wizard's quest artifact) twice in final score prevent pets from picking up Rider corpses when polymorphed into a centaur, don't keep kicking monsters after they die when throwing at a monster that you see with infravision, don't say "it" avoid "the arrow misses the mimic" which left the mimic concealed #sit while water walking over a submerged object should sit on the water's surface rather than on that unreachable object suppress extra "the" when printing the names of certain mplayers do not try to engulf green slimes (same as for cockatrices) trying to eat the brains of a green slime is now properly handled for players monsters touching cockatrices check boots for feet and nothing for tentacles if being petrified, don't disable messages from further petrify attacks trap detection would generally not find trapped doors avoid spurious done eating message after choking and vomiting attribute distribution for several player types did not add up monsters shouldn't try to eat green slime as a cure for stoning lighting of arboreal levels should not be stopped by trees need to recalculate visible locations immediately when monster blinds player monsters shouldn't see through walls because player wears Eyes of the Overworld when pricing glass the same as valuable gems, be sure to use gems of same color nymph stealing armor from a fainted player should wake the player ensure status line updates when you stop running when time is shown repairing a trap in a shop doorway must replace the broken door or wall as well sleeping steed cannot climb stairs/ladders can't change levels when mounted on a steed which is carrying the Amulet more artifacts granted by a deity are rustproof monster name feedback when using the m movement prefix allowed player to distinguish between peaceful and hostile monsters while hallucinating scrolls should not fade when hitting rust monsters, only from rust traps blank scrolls should not fade even from rust traps can't eat or #offer food off the floor under circumstances other than encumbrance where you couldn't have picked it up off the floor first ensure correct message after passive freeze attack by gelatinous cube avoid buffer overwrite when several weapons slip from your hands at once prevent portal placement on Ranger quest from stranding player in left margin avoid crash when a trouble gets fixed before you finish praying sensed hidden monsters should fight back when attacked mindless monsters won't be grateful after unsuccessful #untrap attempts turning affects your religious conduct, even if your god does not help you rolling boulder trap's boulder will knock another one that it collides with into motion in its place make it harder to abuse detect monster and confusion spells prevent D[a from producing odd message sequence in (c)ombination mode avoid messages like "the silver bell" after being drained by mind flayer after polymorph, actually drop both weapons when a message says this happened curb unicorn horn creation abuse by limiting the chance of a unicorn leaving one if it has been revived accept -p and -r options with nethack -s, as documented avoid printing "spellbook of" Book of the Dead in list of discoveries eating non-food items made of leather or other animal parts now violates vegan/vegetarian conduct use correct skill when throwing something while in twoweapon mode secondary weapon can rust when hitting a rustmonster in twoweapon mode extra healing spell cures monster's blindness add missing quest message for throwing the quest artifact to the Monk leader pits, arrow and dart traps, webs, polymorph traps and sleeping gas traps can affect the steed allow game restoration while polymorphed and your race is genocided ensure that crysknives revert to worm teeth, even in containers do not print gas spore's name if you cannot see a gas spore explosion cursed two-handed weapons now keep you from changing body armor trapped pets cannot follow you to another level no corpse when unchanging hero dies while polymorphed into a G_NOCORPSE monster A-removing armour under cursed stuff no longer fails silently grease protects gloves from contact poison on books items picked up from an abandoned shop sometimes wouldn't merge with other compatible items in inventory ("no charge" bit wasn't being cleared) prevent cut-off death message by increasing DTHSZ check to not control teleports when unconscious should now work properly if armor the hero is donning is stolen or seduced off, attributes can be left permanently mis-adjusted ensure a message is printed in all non-obvious cases where a monster flees a fleeing monster that is holding you always results in a "get released" message ensure a monster flees for at least one "turn" explosion type can now be one of dark, noxious, muddy, wet, magical, fiery, or frosty flying (jumping or throwing recoil) over some traps (magic portals, fire traps) will now trigger the trap displacement does not work through walls you can't trip and fall or trip over rocks while riding reduce the chances of a monkey successfully stealing armor you are wearing monkeys can't steal cursed items that you're unable to remove or attached iron ball or items too heavy for them to carry trapped doors are not always detected after returning to a previous level trap detection sometimes showed non-trap locations to be traps eucalyptus was never chosen in random tree fruits due to an off-by-one bug allow knights to pursue and attack thieving monkeys without alignment penalty gaining levitation while over on sink causes an immediate fall quest leader should avoid leaving the quest start level voluntarily blind Medusa cannot gaze prevent dipping attached iron ball or embedded dragon scales into a potion of polymorph from confusing the game about what items are in use should not be able to cut down trees on Ranger quest start level arrow traps are not currently intended to shoot poisoned arrows fall off the horse if you mimic a pile of gold while riding martial attacks will not remove monsters from traps and will cause monsters to set off traps they land on while reeling/staggering prevent topten from using alloc after alloc failure Nazgul and erinyes are nopoly to ensure their numbers are never exceeded "player-@" randomly selects a race and "player -@" randomly selects everything that is not specified prevent spurious "quest portal already gone" when you use an artifact to return to the quest after being previously expelled prevent limbless shopkeepers from "leaping" and "grabbing" your backpack by changing the messages that you get prevent panic when riding while punished and falling down the stairs armor class shouldn't wrap from very negative to very positive searching should only credit you with finding an undetected monster if you couldn't sense it or spot it already monsters should not generally lose invisibility when polymorphing monster must have eyes or breathe to be affected by potion vapors stop dungeon file open failure from causing vision-related crash wishing for {statue,figurine,corpse} of long worm tail yields long worm instead chatting to an arbitrary shopkeeper (not a petrified one) who was created via statue animation produced strange results Yeenoghu's confusion attack is not a touch of death an eating steed should not be able to go up or down stairs, etc. you don't feel "great" when recovering with a unicorn horn but Slimed; also, make the same check for potions that make you feel "great" avoid panic during player-as-demon demon summoning when no demon is available change "Ouch! You bump into a door" message when riding prevent voluntary dismount of steed from passing you through walls in tight spots prevent throwing boulders, boxes, and chests and medium-to-large corpses and statues through iron bars only living eggs which touch cockatrices get turned to stone since monsters already refuse to zap empty wands, they shouldn't pick them up after praying, try to give a spellbook for which the player is not restricted after #dipping your weapon in hand or quiver into a potion of polymorph, leave it where it was message from rust trap states "robe" instead of "cloak" when applicable gas spore explosions were affecting your human hitpoints even if you were polyd and consequently you did not rehumanize prevent "You attack empty water" when attacking a spot on land while underwater prevent spurious "But you aren't drowning. You touch bottom." message when removing an amulet of magical breathing as an amphibious creature fix message given when a monster tries to disarm your multiple welded daggers with a bullwhip camera flash no longer stops at invisible monster monsters inside a stinking cloud should be blinded, just like the hero is vault guard shouldn't initiate conversation with you when you're hidden adult wolves are not small but lynxes are small turn off vision during a save operation to prevent impossible() from triggering a crash rolling boulder trap's boulder susceptible to land mines and teleport traps polymorphing below level 1 should kill player (needed to fix max-HP abuse) prevent "obj not free" panic when shopkeeper cannot get to a thrown pick-axe give feedback if Sokoban prevents polymorphed player from passing through walls eliminate Wounded_legs enlightenment message when riding since it refers to the steed's legs, not the hero's adjust the fumbling pick-axe message to reflect that the steed's legs got damaged, not the hero's quaffing a noncursed potion of speed no longer heals the steed's wounded legs prevent mounting of steed when you have Wounded_legs to prevent abuse; dismount does an unconditional healing of Wounded_legs during the Wounded_legs context switch wounded legs on a steed doesn't count as a prayer trouble wounded legs on a steed doesn't abuse dexterity make wounded legs gained by falling off a steed consistent (dexterity loss) land mines while mounted should hurt the steed self-genocide while sitting on a throne should not refer to scroll of genocide eating dogfood or fixing a squeaky board conveys experience but didn't check for gaining a new level demon bribes are 4x larger than they should be for co-aligned players specific monster warning no longer reveals the true monster name when you use the '/' command while hallucinating start_corpse_timeout() now takes corpse age into consideration rather than always assuming a fresh corpse, thus fixing potential icebox abuse player on an immediate diagonal from a monster reading a scroll of earth should be affected, just like monsters in similar locations objects that fall from monster's minvent as a result of monster polymorph are not polymorphed, consistent with items that remain in minvent quaffing a potion of gain ability while wearing ring of sustain ability displayed no message and identified the potion monsters still with WAITFORU strategy should not follow up/downstairs messages should reflect the fact that the Eyes of the Overworld mask the effects of blindness Amulet of life saving should save you from sickness that will kick in this turn player should stop waiting when a monster uses a polearm from a distance avoid stone-to-flesh blood pooling message when zapping ice and not stone when polymorphed into a silent creature, do not "pronounce" scroll formula ensure hilite turns off immediately when pet stops being tame hitting with a polearm counts as hitting with a weapon for conduct traps detected while blind and levitating were not displayed when a mind flayer uses its mind attack, it should wake the victim shapechangers restored from disk would no longer change shape allow "tame" prefix when using the wizmode C-g command to create new monster(s) display a more appropriate name for a high priestess when using ;/ commands change "The water elemental is on fire" to "The water elemental is boiling" blind, cancelled or nonseen invisible Medusa cannot gaze at other monsters fix impossible when spinning web on falling rock, rolling boulder and fire traps rust monsters can only eat items made of rustable material wands of fire are no longer flammable no matter what material they are displacing you pet into a trap which kills it affects killer conduct pets can now be displaced in untended shops only show lit walls if, like doors, the position next to them is lit too charge for an unpaid weapon used for engraving shopkeeper should charge for unpaid balls and used candles in containers when swallowed you could drop or throw a cockatrice corpse into a monster's stomach without stoning it despite the guaranteed hit steed would often not respond to an attack, even if you didn't move that turn after stepping in a polymorph trap, a monster may pick up the wrong items breaking an unpaid wand of teleportation wouldn't result in the proper charge next_shkp() was used inconsistently, potentially triggering an endless loop chaotic wizards usually get a spellbook when crowned, just like neutral ones monk quest: fix the two inaccessible chambers on the locate level rogue quest: fix the four inaccessible chambers on the home level; link the two inaccessible chambers on the locate level and provide a means of escaping from them; on the goal level, link most chambers together, resulting in just four disconnected regions, and force stairs to be in a different region from the nemesis angels can fly under #twoweapon fix it so that only Stormbringer carries out the blood-thirsty attacks, not both booby-trapped doors shouldn't make you stagger if you're riding encumbrance exertion checks should happen each time player moves mksobj_at: add way to suppress the chance of a new object being an artifact steed should be the one caught in a bear trap, even if player is polymorphed use a more appropriate message than "being held" when using < or > while swallowed or engulfed on stairs stinking cloud isn't useless and shouldn't be excluded from initial inventory shopkeeper will not try to buy food you are eating when inventory is full don't duplicate any gold inside containers when saving bones data can't tell between acid and holy/unholy water that burns like acid tame stuck monsters should release you after regaining their senses engraving Elbereth exercises wisdom, engraving anything else does not artifact bows get any special attack bonus added to missile to-hit roll monsters with gaze attacks should not try to blind the hero with potions players polymorphed into umber hulks should not try to eat boulders in Sokoban when a monster uses up a partially eaten food item, cleanup was not performed temple priests shouldn't be created with two robes give some quest leaders and nemeses equipment appropriate for their class mis-engraving "X" or "x" shouldn't violate illiterate conduct Heart of Ahriman now explicitly does double damage prevent NO_ATTK artifacts from accidentally doing double damage player polymorphed into monster that loses hp out of water should lose hp too make sure that all leashed monsters get released when bones data is saved eating a ring of levitation doesn't confer permanent intrinsic levitation silver hating monster using a bullwhip shouldn't snatch silver weapons into its inventory fracturing one of several boulders at a location should not unblock vision don't hide stairs, thrones, &c under spider webs when creating levels rediscovering forgotten object types behaved differently depending upon whether they had user assigned names at the time of amnesia taming while engulfed is limited to the engulfer restore blindness resistance to Archons if a shk is polymorphed into monster form which has Wizard-style tactics, don't let him teleport to the stairs if he's inside his shop when the player digs a hole through a shop's floor, don't let shopkeeper wander out of that shop while multi-turn digging is in progress don't protect alternate weapon and quivered objects against being taken by shk who grabs your pack when you dig a hole through his shop floor add missing break to POT_WATER case in potionbreath() keep monster from forgetting its weapon is cursed every other round multiple shot throwing stops immediately whenever you hurtle backwards don't panic if being billed for a burning or other timed object food that makes a monster peaceful should not re-anger it at the same time abusing a leashed pet could result in a leashed peaceful monster couldn't unleash steed while mounted trying and failing to wield an item could leave current weapon flagged as both "weapon in hand" and "alternate weapon" when `pushweapon' option is set handle OBJ_CONTAINED case for corpse revival so that trolls can revive from inside containers eating one of several merged partly eaten food items should take nutrition from only one of them coyote names should not disable printing of "tame" or "peaceful" Eyes of the Overworld protect from stun effect of Archon's radiance attack give feedback when putting on or taking off the Eyes of the Overworld causes blindness state to be toggled avoid spurious "you can see again" when temporary blindness being overridden by the Eyes of the Overworld times out removing blindfold or lenses via 'A(' gives same results as via 'R' make blindness with just 1 turn remaining be a candicate for repair by unicorn horn and healing potions/spells healing potions/spells shouldn't fix being creamed make pie throwing and venom spitting by the player be consistent with the effects of those attacks by monsters offering & tinning corpses on altars should work even while riding It was possible to faint after eating a fortune cookie and still read the fortune's text despite being unconscious when filling a pit containing a vortex, a surviving vortex gets untrapped teleporting no longer moves the iron ball to under you if that's not necessary; prevents odd ball movement when crawling out of water monsters now prefer to wear speed boots over other boots prevent crash when loading a special level specifying a mimic using m_object prevent crashes caused by dropping or shipping quivered or secondary weapons don't trigger spurious encumbrance messages on last turn of a multi-turn meal prevent food being restored to untouched status if interrupted while eating troll revival shouldn't increment the troll creation counter breaking mirrors and your eggs should be bad luck when kicking chests as well as throwing vampires should be G_NOCORPSE so you can't wish for them glass objects should break when thrown, just like when kicked in chests rocks/gems shouldn't be hard to throw by hand because they are ammo avoid all cases where splitting an object would result in two objects being quivered, wielded or otherwise having its owornflag set allow 'a' prompt when dropping many objects in shop for credit (Wingnut) monsters who get polymorphed while wearing dragon armor turn into dragons shape changers can't be killed by system shock when hit by polymorph Chromatic Dragon has silver scales too (she reflects) being killed when wishing for an artifact should retain that item in bones data the drain life spell should not wipe out engravings (especially not using a function that requires you to be able to reach the floor) monsters who can cast undirected spells don't need to be in combat with you to do so messages consistent for all monster spells monsters casting spells at your displaced image now set mspec_used monsters without ranged spells don't print curse messages for ranged spells going down to floor using > should set Heart of Ahriman invocation timeout riding a steed into water kills the steed if it cannot swim, with penalties gaze attacks now stop occupation proper death message when killed by "plain" high priest don't conceal the identity of Moloch's high priest blessed full healing can't recover levels lost when polymorphing into new man blessed full healing can recover at most half of other lost levels golden glow when praying will recover lost level if blessed full healing could gaining a level while polymorphed increases current monst hit points as well as latent human (or whatever) hit points pets should not try to go after food that they can't reach monsters shouldn't use wands of digging in Sokoban objects dropped in or travelling across lava pools can take damage monsters that enter lava can take damage eating an unpaid tin should calculate cost before not after eating spells shouldn't do negative damage when reading spellbooks, don't "continue studying" wrong book if original one gets destroyed after previous reading attempt has been interrupted correctly handle polymorphed quest leader swallowing zombies/mummies whole makes you sick, like when eating them normally impose additional teleport restrictions on the no-teleport Plane of Air landmines set off by pushed boulders have same effects as stepping on them secret corridor detected out of vision range is still displayed (prevents bug where wand of secret door detection found nothing but still identified) getobj can now see user-specified count when using inventory to make selection scalpel is stainless steel (i.e. METAL) not regular steel (IRON) eggs, potions & other breakables may break when they fall down stairs hurtling via grappling hook does not apply effects of destination location consider vortexes to be nonliving dragons have scales, not fur if player teleports a monster while swallowed on a noteleport level, the player should not teleport along with the monster prefixes that can appear in any order when wishing should include +/- and empty don't allow untrapping of adjacent traps in locations you can't move to summoning should summon any alignment if summoner's base alignment is A_NONE when dipping unicorn horn in potion, the potion might change bless status, so set bknown to FALSE grammar fixes such as "Eyes of the Overworld resists" and others score bonus was missing from scrolls of identify and fire make wands of speed or slow monster known if their effect on monsters is observed; likewise for speed boots gold detection "materially poor" message inappropriate if you have hidden_gold() cannot reflect back an invisible umber hulk or medusa's attack monsters with M3_WANTSBOOK often couldn't move in the Wizard-level Vlad should want the Candelabrum if you float_down on a trap in which you're already trapped, don't retrap applying whip toward hidden mimic displays mimic name before "Wait!" message stealing a container didn't multiply cost of stolen contained objects by quan halve air elemental damage to compensate for side effect of speed system strengthen Death; weaken Famine, Pestilence, and Demogorgon pet purple worms get nutrition from engulfing attack throwing an artifact upwards will trigger artifact hit effects when it falls being hit by Fire Brand stops the turning-into-slime process monsters hitting other monsters can split puddings with weapons be consistent with checking for iron weapons when splitting puddings prevent corpses of undead creatures just killed by undead turning from being instantly revived by the same undead turning attack allow fake player monsters to handle artifacts that don't match alignment/role chaotic monsters can use Stormbringer; lawful monsters can use Excalibur No "corridor disappears" message if Vault guard dies off-level slip while mounting and levitating at will should not cause damage if you see a monster jump into a trap in a secret corridor, it's not secret fixed a few places where unblock_point wasn't called but should have been cloned monsters should have the same name and tameness as the original you should stop eating (etc.) if a monster attacks you and misses half physical damage should apply to gas spores iron bars should affect wall corner wallification potion of polymorph shouldn't be identified if object being dipped into it ends up as the same type of object after polymorphing don't slap against the floor while riding and eating bad food got rid of "nori" (since it doesn't really translate "kelp frond" accurately) engraving in fog-covered location on in the Wizard quest said you engraved in air, not dust dipping non-weapons into burning potions of oil had no effect dipping arrows into burning potions resulted in rust damage Platform- and/or Interface-Specific Fixes ----------------------------------------- amiga: random crashes when opening menu window in fontmode eliminated amiga: proper action taken (cancel) when closing the menu window with closegadget or escape amiga: allow #/altmeta combination on foreign keymaps amiga: prevent plname[] overflow from askname() amiga: prevent writing outside basewindow (bottom) amiga: tilemode tombstone corrected on cybergfx screen amiga: don't clutter levels/ with foo.0 when quitting at playerselection micro: prevent a guaranteed impossible() if we ever have more than (COLNO - 1) levels in the game micro: fix out of bounds memory modification for file opens via PATH msdos: placeholder tiles accepted by the thin tile builder tiles: use pixel-accurate grid bug tile for grid bugs tty: correctly dismiss 1-line menus tty: clear screen before version incompatibility message so it doesn't just print the message overwriting previous screen text tty: pet was not always hilited tty: don't crash if the news file is present but empty unix/tty: give user a chance to see any error produced by (de)compression win32/tty: menus can take advantage of consoles larger than 80x25 win32/tty: add support for inverse attribute Gnome: workaround for GTK+ attempts to disallow setgid executables Qt: honor user preferences in startup dialog X11: map not displayed in color when using X11 windowtype w/o tiles X11: viewport scrolling could scroll the the wrong place with resized window X11: allow extra space added to map widget to be removed if widget shrinks X11: general solution to the problem that the meaning of font height varies among different implementations of X11 X11: make "slow" mode the default since it seems to be very prevalent General New Features -------------------- added travel command via '_' or mouse click config file processing detects multiple use of the same OPTION and prints a warning when it does make the player selection prompt more explicit in the information that it is going to request remove curse now operates on cursed leashes that are in active use give feedback when shooting/throwing more than one missile at a time monsters can now deliberately eat dead lizards to cure confusion general warning now allows you to attack unseen monsters, as long as you can see the warning glyph on the screen wand of fire & fireballs now burn webs wand of locking / wizard lock zapped down will close and remove trap doors exploding monsters wake nearby monsters various mindless, sphere monsters no longer need to breath sleeping gas no longer affects nonbreathing monsters vault guard doesn't notice you if you're mimicking gold good chance of untrapping monsters and pets caught in webs if you are polymorphed into a spider, and extremely small chance even if not stamina affects ability to throw heavy things objects merge in containers wishing for "nothing" yields no object and preserves wishless conduct genociding "none" destroys no monsters and preserves genocideless conduct coyote id naming shows only the true latin name if coyote is cancelled xorns can "speak" and can smell valuable metal if you find a trap but there is too much clutter to see it, have the game display it temporarily until a keypress rename the Wizard of Balance to Neferet the Green double the number of messages that apprentices/guards utter, with 5 for before the quest, and 5 after wizard mode ^G command can create monster by class, not just by name wizard mode ^G command takes a count kicking a sleeping/paralyzed steed now causes special effects allow overriding of the default boulder symbol via BOULDER option blessed scroll of detect food provides you with a one time ability to recognize food that may be harmful to you wizard mode WIZKIT config file option added to ease adding items to starting inventory for a debug session helping a sleeping/frozen monster from a trap might wake/unfreeze monster if the hero comes upon an obviously trapped monster the trap is considered seen thrown weapons that hit are now subject to passive damage locomotion-specific use of words, rather than just using "stagger" if you come upon a physically trapped, visible monster, you see the trap too, without searching for it allow looking and pickup inside monster's stomach or interior when swallowed add body_part(STOMACH) pets like tame nymphs, et al, now only steal non-cursed items monks usually get a spellbook rather than a weapon when crowned blessed gold detection now detects anything made of gold, not just coins, including candelabrum and gold rings new T-shirt messages from Scott Bigham option to get rid of resistance 'sparkle' (shieldeffect) (Scott Bigham) option for autodig (Malcolm Ryan) glowing Sunsword (inspired by Slashem) msg_window option for ^P in TTY mode (Jay Tilton) ninjas should get multishot bonus with yumi and ya (Dylan O'Donnell) put prisoners in the Dark One's dungeon (Dylan O'Donnell) touchstones; Archeologists start with one add leather cloak so soldiers don't have elven cloaks add Tom Friedetzky's BUC-patch with some alterations to the original add wizard #poly and #levelchange (originally levelgain; Dylan O'Donnell), add Jason Short's additional lenses use patch add new Gnomish Mines levels from Kelly Bailey's patch add Ken Arnold's patch to show unpaid item prices in inventory jousting by players wielding a lance while riding Knights start with lance rather than spear can start game without a pet via pettype:none (Dylan O'Donnell) allow disclose options to be more finally tuned, including being able to specify the default response for being prompted debug mode SPLEVTYPE environment variable to choose specific levels from when there are random selections artifacts have individual prices new window-port preference options added, and some existing options moved into the window-port preferences section made each of the end disclosure options customizable to "prompt;default no", "prompt;default yes", "show it without prompt", and "don't show it and don't prompt" add female role level names "Medica ossium", "Magistra", "Chevaliere", "Dame" more feedback about skill advancement from #enhance command USER_SOUNDS compilation option to enable use of SOUND and SOUNDDIR variables in the config file for user-specified sound clips for user-specified, regex-based message patterns resistance does not protect inventory from artifacts (cold vs Frost Brand,&c) phrase the prompts for P and R commands using "put on" and "remove" as the actions rather than repeating W and T commands' "wear" and "take off" dipping candles, et al, into burning potions lights them Platform- and/or Interface-Specific New Features ------------------------------------------------ amiga: screenmode requester amiga: 16 color font mode mac: command-key shortcuts in the player selection dialog vms: default compiler configuration in sys/vms/Makefile.* switched to DEC C win32: new graphical port contribution by Alex Kompel nethack-3.6.0/doc/fixes34.10000664000076400007660000007100712536476415014273 0ustar paxedpaxed$NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ General Fixes and Modified Features ----------------------------------- prevent panic() obj_not_free when pushing a boulder over a landmine there was no feedback when successfully hitting shock resistant monsters with Mjollnir via hand-to-hand attack unbought single-bite food eaten in shops was not billed properly charge for shop contents inside "no charge" containers add wishing for "nothing" and genociding "none" to the conduct section of the Guidebook allow both wishing and genocide to accept either "none" or "nothing" when the player wants to decline left word in format string in get_wet() causing "The spellbook fadefades" two bad wizkit items in a row shouldn't make the user hit space many times kicking thrones no longer loosens rocks wall symbol not replaced when digging while blind and levitating increment FQN_NUMBUF from 2 to 3 to prevent premature reuse of a buffer that caused a level creation error to be reported as a lock file error print regular death message when leashed, mounted steed dies of starvation fix more funny messages, new and old restore the behavior of bumping into closed doors when moving while impaired fix iron ball cases that could put the chain in solid rock discovering a mimic on a closed door location should not unblock the location don't drop corpse when a monster kills another monster on an inaccessible location (i.e. behave like xkilled behaves) half-physical-damage from gas spore explosion should only affect you Sunsword didn't stop glowing when hero killed a monster wielding it mimics caught in explosions with messages printed about them are discovered let lev_comp and dgn_comp accept optional carriage return character prior to the terminating newline in special level and dungeon description files Wizard of Yendor will start harassing you after the invocation if you've managed to get that far without ever killing him characters polymorphed into centaurs can't wear boots if an unknown rolling boulder trap kills a monster, you shouldn't be a murderer touchstone entry in data.base specific message for engraving headstone with wand of digging wielded/quivered chained ball should be unwielded when thrown polymorphing into a form that cannot twoweapon should immediately disable twoweapon mode; likewise when reverting from a monster form which can use two weapons to a normal form which can't taking partial count of merged objects from a container while your pack was full split the object and did not re-merge animal_parts are not always appropriate for ravens prevent panic if tombstone window cannot be created clarify travel command behavior in the Guidebook touch_artifact checks needed when snagging w/bullwhip and stealing cannot trip over submerged objects if you're water walking wand of striking was not identified if it activated a statue trap cannot sacrifice while you're swallowed player polymorphed into an eel cannot drown breathless/amphibious monsters avoid dmonsfree impossible message due to migrating a dead monster via mhurtle causing the monster to end up in a hole or other trap avoid temporary disappearing Burdened message due to updating status line midway thru in_container don't credit player's wisdom when makelevel creates random Elbereth engravings reduce insect/monster creation from monster spells and limit chain summons avoid "couldn't place lregion type 5" warning when arriving at Plane of Fire avoid crash due to delayed poly or were change no longer being valid ensure that Priest's ability to recognize B/U/C is considered in B/U/C menus can't push boulders through iron bars; traps can't roll such through either; likewise for objects thrown by monsters thrown objects susceptible to breaking might do so when they hit iron bars assorted monsters can pass through iron bars; ditto for polymorphed character attempting to dig iron bars will wake nearby monsters instead of yielding "you swing your pick-axe through thin air" autodig won't accept iron bars as candidate location allow knight to retaliate for all thefts except those "you gladly hand over..." randomize starting position on goal level for M, P, and S quests prevent the Wizard of Yendor from displacing the high priest of Moloch out of the Sanctum's temple ATR_BOLD on spell menu header travel command should restrict its shortest paths to areas of the map the hero knows about or might reasonably guess non-altar prayer should limit god action, not maximize it potions of acid explode, not dilute, so make water_damage behave this way lookat monster notes if you see monster is trapped don't crash when angry shopkeeper re-enters the shop and you pick up something monsters with WAITFORU strategy should act if successfully attacked by non-damaging attacks (e.g. seduction, rust damage) don't summon kops if credit covers cost of unpaid goods taken out of shop update swallowed display immediately if an engulfing monster polymorphs into another engulfing monster undo xname FAKE_AMULET_OF_YENDOR AD_DRIN check, the_unique_obj checks this case axes should chop trees; picks shouldn't chance to aim grappling hook when skilled or better level limit of monsters like naga hatchlings should be high enough to grow up scroll of enchant weapon will become discovered when read in some cases don't crash when using lookat on a boulder an BOULDER sym is unique attaching a single candle to fill candelabrum's last slot gave message with poor grammar: "The candelabrum now has seven candle attached." vault guards won't ask who you are if you're unconscious or paralyzed monsters should not repeatedly try to teleport on noteleport levels crocodiles legs are not designed for kicking open doors, chests, et al. walls of one of the luckstone locations in minend-3 were diggable minetn-6 could place downstairs in a cut-off location corpses in bones files don't retain their role characteristic boulder was not displayed if blind and discovered with a monster known via ESP behind it don't claim that statue comes to life if the monster it turns into is invisible fix goodpos() so worm segments don't get placed on top of each other (causing a possible display problem if the worm is cut in two) fix fountain noises on some special levels (castle, valk home, various mines) disallow mounting a trapped steed to avoid inappropriate trap effects #chat with meditating monster will rouse it suppress redundant message when stoning effect transforms a golem clear worn bits of any object grabbed by shopkeeper to avoid extract_nobj panic looting any container on a location should suppress looting nearby monsters give more specific message when forbidden role attempts to use twoweapon mode avoid double billing if #loot causes a shop's bag of holding to explode when polymorphed, player killing a paper or straw golem via fire damage would kill the golem twice, resulting in an impossible error usually stop mimicing if you polymorph while using #monster mimic capability under !GOLDOBJ, gold shouldn't disappear if you try to throw it at yourself under !GOLDOBJ, remove temp gold from inventory during restore Staff of Aesculapius did not always cure sliming correct singularization of fungi, liches, vortices prevent "remove_object: obj not on floor" panic for iron ball placement if riding while punished leads to a fall off steed when changing levels specifying -D (or -X) to enter explore mode while restarting from a save file was lost in the restore process fix crash when using lookat on an known invisible monster with monster syms set prevent getting stuck in infinite loop when using wizard mode #levelchange command to reduce level while having level-drain resistance naming an already wielded elven dagger "Sting" activates warning against orcs naming either of the wielded weapons unintentionally ends two-weapon combat Various nemesis monsters must resist stoning so their death messages make sense don't call DEBUG impossible in rn2 when a level 0 monster tries to cast a spell GOLDOBJ: don't call money2mon with 0 zero when killed by shopkeeper headstone writing was using the adjective "weird" when engraving with a wand of digging. don't report "you were riding" if you die as a result of dismounting allow #untrapping of chests that are co-located with floor traps and hero unmap "I" symbols when searching while blind and levitating monsters that are frozen or sleeping cannot be grateful for untrapping grammar of blessed-detection eating warning messages when eating 1 of N objects message for charging for items lost in a cursed magic bag wasn't always shown dropping gold on an altar printed no message and didn't change gnostic conduct don't allow cursed daggers thrown by monsters to go thru closed doors hero polymorphed into an exploding monster should explode when attacking thin air, just like the monster itself don't mark holes/trapdoors as seen if you levitate over them while blind player polymorphed as rust monster would lose gold in inventory by attempting to eat it, even though the eat failed no messages were printed when dowaterdemon or dowaternymph failed to create a monster doe to the G_GONE check knights should be able to avenge attacks from covetous monsters eating various rotten food items would not break vegan/vegetarian conduct unaligned special levels should inherit alignment from the dungeon Samurai quest was missing several doors Cancelled while polymorphed and Unchanging should provide feedback stone to flesh on a statue with contents would lose the contents if a monster was on the same location as the statue steed movement would use your speed if walking step by step kicking a known, unseen monster would sometimes leave behind an extra I symbol applying a lance against a long worm could cause an impossible a knight applying a lance did not do a caitiff check blessed gain level when already at level 30 won't reduce experience points keep counting spell skill exercise even after expert status is reached when a fountain dries up or a throne vanishes, make sure it really happens allow player to name polymorph potion if nothing seems to happen avoid crash when drinking a potion causes the hero to float up over a fire trap, for example, which might try to destroy the in-use potion in some situations, if hero stood still, a hostile dwarf would switch back and forth between weapon and pick-axe and never move uncontrolled teleports did not handle leashed pets minetown fountain warnings shouldn't prevent finding gems/coins in fountain order of container and objects was different for mazelike and roomfilled levels minetown guards only enforce town rules inside the town proper electric damage heals hero polymorphed into flesh golem rather than iron golem fix bug preventing wishing for bear traps (not beartrap objects) in debug mode be notified about cessation of hallucinations even if blind and the time when using '/' to examine multiple map items in succession, don't mislabel some with "or a splash of venom" after having looked at a '.' item martial arts kick that knocks a monster into a trap would result in warning "dmonsfree: 1 removed doesn't match 2 pending" if the trap was fatal if you can't see or sense a monster when it dies, don't set dknown on corpse effect of wearing or removing the Eyes of the Overworld took effect on the next move, but should take effect immediately. dragon scale mail is magic armor invoking or applying an artifact must pass a touch_artifact check document 'D'rop BUCX behavior in the Guidebook remove levitation boots over a portal, the portal teleport is delayed until your next command is typed. armor vs cursed two-handed weapon anomalies: with 'T', couldn't remove armor, but with 'A', could remove it, and with 'W', could put it on don't print ape data.base description for other words that end in "ape" prevent crash after animating a statue via stone_to_flesh by avoiding use of the obj in newsym() after it was deleted print "magic spreads" message when eating ring of increase damage, etc. grammar tid: "The looking glass miss the ." fix wishing for "looking glass" and " glass" Archeologists suffer same alignment penalty for statue destruction by stone_to_flesh as they do by other means of statue destruction being unable to see a vault guard doesn't prevent him from arriving in town, secret doors should be called "wall", not "fountain" in town, watch should not allow trees to be cut down cancel chat direction cancels the chat prevent "the mimic looks better" on an unrecognized mimic hit with healing spell after forcefighting a concealed lurker, the lurker wouldn't fight back when polymorphed into a hider, cease hiding during level changes let mind flayer grow up into master mind flayer; also giant/sewer rat and cave/large spider engulfing green slime as a purple worm was causing stoning not sliming zero entries in DUNGEON, MONSTERS, et al, of config file are now treated as preserving the default rather than being ignored enlightenment: don't misreport polymorphed lycanthrope as "in beast form" remove TIMED_DELAY from the features checked for version compatibility rolling boulder hitting monster stuck in pit should stop even when mon survives don't see chest trap gas colors while Blind adjust fruit name in potion juice messages if it has the form "foo of bar" wielded camera passes harmlessly through shade reading spellbooks while confused should allow tearing the book Breaking wand of digging dug through rock which should be undiggable. Breaking wand of digging near shop walls wouldn't anger the shopkeeper Shop walls wouldn't be restored if there were pits in the way. If there were a hole outside a shop, you could kick stuff out of the door into the hole without the shopkeeper noticing. curing hallucination while wielding Grayswandir should print a message removing unowned pick-axe from container in shop gave inappropriate message don't let monster end up with more current HP than max HP after life drain make sure that missing file trickery in wizard mode which is discovered during level change doesn't try to keep going after discarding current level contribution by Adam Wozniak adds several const & changes some char* to char[] fix impossible when hitting/jousting a monster causes it to be killed twice fix a GOLDOBJ crash/hang in take_gold() that could be triggered by reading a cursed spellbook, or by sitting on a throne kicking a tree could produce 0 to 4 killer bees but it should have been 1 to 5 mounting a steed allowed hero to make moves that would otherwise be disallowed including mounting diagonally in a shop doorway monsters lose intrinsic speed when pertrified if you have converted, the quest leader banishes you instead of asking you to come back later, and tells you that you won't succeed without Bell don't state that "you narrowly avoid losing all chance" message if you try to put on a helm of opposite alignment in the quest after converting fix enlightenment feedback for bonus or penalty on damage and chance to hit effects of purple worms consuming special monsters is now more consistent across eating, digesting and dropped corpses while engulfed avoid "you finish disrobing" when disarming via the 'A' command make sure corpses and statues which remember monster attributes don't keep ones that were conferred by no longer worn items (mainly speed boots) elevate the trouble priority of any cursed item which is preventing removal of a ring of levitation starving pets will eat more aggressively when a pet starves to death, say so instead of just "Fido dies." starved pet raised from dead shouldn't immediately starve again skilled spell of detected treasure wasn't acting like blessed potion of object detection (from Roderick Schertler) fix end of game attribute disclosure for levitation negated by sink kicking a box embedded in a wall will knock it free rather than bust it open stop running or travelling if the vibrating square message is triggered show correct gender in ^X display when polymorphed into non-humanoid form for wizard and explore modes, skip second screen of ^X output when first screen is cancelled by ESC for wizard mode, override confusion when using ^F to reveal map polyself into minotaur causes hard headgear to fall off with multiple leashes in use, 2nd had 50/50 chance of having unbounded length GOLDOBJ: coins aren't subject to curses/blesses and don't need identification can no longer activate a figurine while engulfed can't use figurines to get too many erinyes or Nazgul include currently wielded weapon among the list of likely choices for 'w' likewise for currently quivered ammo among choices for 'Q' only include unknown gems as likely choices when applying known touchstone prevent mbodypart() from returning animal parts for lights removing a ring might relearn what it is after amnesia sleeping shopkeeper shouldn't talk to digging player give more specific feedback when dipping unicorn horns into potions can see self via infravision or ESP or monster detection when invisible class genocide that killed polymorphed self while `Unchanging' reported incomplete cause of death and possibly left rest of class in bones class genocide of @ by human or elf character polymorphed into non-@ gave "you feel dead inside" message twice unskilled rider who can't reach items on floor also can't dip into moat or pool from flying steed when summoning nasty monsters, use new monster's type to decide if they can be placed on boulders, et al, not the summoning monster's type don't display the "intones:" prefix when !soundok since the message suffix won't be displayed in this case document "sound" option in Guidebook destroy traps that are buried by boulders dropped in water renamed debug commands: light sources -> lightsources, monpoly_control -> monpolycontrol, poly -> polyself detect attempt to swap places with big pet through narrow opening stinking clouds in bones files do not get their ttl set reasonably stinking clouds in bones files may incorrectly set player_inside breaking wand of digging on a drawbridge shouldn't dig/hole a pit in the bridge avoid mimicking gold when the character has the Unchanging attribute handle polearm wielded prior to mounting the same as one wielded while mounted, and one still used after dismounting like one wielded while not mounted non-lawful angels don't chat using lawful messages and shouldn't summon lawful help cancelled yellow lights should not explode against other monsters, as well as not exploding against you becoming confused, eg from nausia, while reading a spellbook should result in the usual confusion effects teleports should not be controlled if you're stunned, confusion should have some effect on your ability to control level teleports vault wall repair should remove traps subsequently created at affected spots don't reveal deity name when a high priest(ess) gives temple entry greeting for ordinary remove curse, don't uncurse quivered object unless it is suitable to be used as a quivered weapon (ammo or missile) salamanders have no legs and cannot ride all objects carried by a monster who's hit by a polymorph zap are protected from that zap, not just worn armor which falls off due to shape change sparkle option for display effects was ignored on explosions level teleport while on a sleeping steed caused panic and possible crash breaking wand of digging causing a shopkeeper to fall left unpaid items unpaid use get_adjacent_loc() rather than getdir() directly for some things where you want to ensure valid adjacent coordinates are returned minor experience calculation tweaks level telporting out of the dungeon while carrying unpaid shop goods would trigger "not on any bill" warnings during final inventory disclosure only hard helmets protect against falling piercers don't crash teleporting out of a monster while engulfed, punished but not carrying the ball web breaking should consider steed strength and other characteristics various missing or inappropriate "killed by" death messages second attack for two-weapon combat will miss if first knocks target away jousting effect no longer occurs every time riding character hits with lance skeletons should be able to wear the armor they're created with bouncing zaps should not bounce around the edge of closed doors mimics that are detected but not seen should not display as their mimiced form when the detection ends not all cavemen are human, so avoid using human in quest messages tengu is singular and plural, some rumors were incorrect don't let leader or nemesis be renamed non-moving monster are not affected by liquid 'A' command wouldn't remove cursed item from quiver or alternate weapon slot 'A' command behaved differently depending on menustyle when non-weapons were present in the quiver or alternate weapon inventory slots most cases of the hero dropping things need to check for dropping on an altar zapping undiggable trees with wand or spell of dig gave feedback about rock being able to see invisible shouldn't cause you to not notice when potion or spell of invisibility wears off can't successfully bribe a demon who happens to be carrying the Amulet while over water, killing a monster that had engulfed you does not result in the usual water effects removing a ring of levitation while engulfed should not invoke spoteffects feedback from invoking Orb of Detection was sometimes misleading or wrong ranger quest artifact (Longbow of Diana) confers reflection when wielded by monsters like it does for the player avoid discrepancies in size and associated armor-wearing ability between wizard gnome player and same player polymorphed into gnomish wizard by forcing newman() if poly-target matches your_race() add missing data.base entries for caveman, healer, monk, priest, and samurai allow "grey spellbook" as alternative spelling of "gray spellbook" handle attacks by cancelled monsters more consistently armor worn by monsters might negate some magic attacks like it does for hero give feedback and discovery when visible monster puts on cloak of invisibility really add artifacts inside carried containers to final score (3.3.1 fix displayed them them but didn't include any points for them) drop alternate weapon to terminate twoweapon combat if the alternate weapon gets cursed restore monster creation sanity checks to wizard mode ^G command prevent recoil from hurtling you through narrow areas that you wouldn't be able to move through intentionally grammar in cause of death when killed by slipping while mounting named steed ensure `m'enu is still an available traditional menu choice for menu-upon-request even when there is only one class of object present engraving on headstone will appropriately dull your weapon certain types of golems should not "catch fire" so adjust the messages no longer need to manually examine inventory after regaining sight in order to give a type name to an object picked up while blind when adding an object to inventory, it is possible for it to becomed both wielded and quivered if it merges with weapon and autoquiver is enabled include rocks as likely candidates for quivering if alternate weapon is a sling Asmodeus fails an is_armed() check, so code in m_initweap() to give him wands of fire and cold never got called; move the code to m_initinv() #rub would wield the target tool even when already being worn as eyewear monks lose their to-hit bonus for bare-handed attacking if wearing a shield fix case on leading character in "Crunched in the head..." in ball.c using travel mode to move next to a known trap and then trying to step onto that trap required an extra step; the first one ended up as a no-op punished with ball and chain on the same floor square as a trapped chest when it exploded resulted in panic "remove_object: obj not on floor" see_monsters() wasn't called when you lost the innate warning intrinsic due to level loss xorns sink if the drawbridge they're standing on is raised applying figurines to an adjacent spot over water does drowning checks fix sequencing of Magicbane's hit messages avoid buffer overflow from long or too many -s params wake up first if trying to crawl out of water while asleep while waiting, don't try to change into were form when already in were form steed should remember traps encountered while mounted killing shopkeeper by throwing unpaid things would result in "item not on bill" impossible error choking pet to death with cursed leash incurs various pet-killing penalties wielding Werebane prevents catching lycanthropy via monster attack (but not via eating, nor does it cure an existing case) character inflicted with lycanthropy is vulnerable to Werebane when in human/elf/&c form as well as when in beast form shopkeeper could get angry without remembering the customer name any object held by ghost during recorporealization would cease to exist including the Amulet of Yendor harassing monsters will be less likely to teleport to your location while they're running away from you randomize warning symbols during hallucination Platform- and/or Interface-Specific Fixes ----------------------------------------- wince: added Windows CE port from Alex Kompel win32: win32 build no longer defines MICRO win32: allow error save files to be generated win32: strip illegal file name characters from plname and replace with '_' win32: don't let recover build a save file out of level files belonging to an active NetHack.exe or NetHackw.exe process win32,winCE: SELF_RECOVER to let NetHack itself recover aborted games win32gui: make error() work; it was essentially non-operative in 3.4.0 win32gui: fix alignment of columns in menu windows win32gui: Window menu File|Save worked during #quit disclosure processing win32gui: make mswin_yn_function() case insensitive like the tty version win32gui: In msg window, gray out lines that are old and concatenate msgs win32gui: --More-- prompt if there are more messages than can fit this turn win32gui: flicker reduction because clear_nhwindow no longer redraws window win32gui: A caret bug was fixed win32gui: fix bug that caused two lines too many to be drawn on each paint win32gui: last line no longer highlighted win32gui: reduce the number of popups and support for !popup win32tty: honour the use_inverse option and default to ATR_BOLD if disabled win32tty: respond only to mouse clicks not mouse movement win32tty: allow ^C to abort the game at the "Who are you?" prompt win32tty: fix truncated score list win32tty: prevent ALT+CTRL from sending NUL to core with the meta bit set win32tty: international keyboard handling improved by letting ToAscii() generate input char based on VK and state of shift and caps lock Gnome: add support for non-square tiles Gnome: destroy main game windows correctly Gnome: Dylan Alex Simon's port of KDE-style worn window Gnome: Dylan Alex Simon's port of KDE-style hero cursor color Gnome/Linux: more portable getres*id workaround X11: restore support for non-square tiles when USE_XPM is defined X11: getlin dialog got steadily narrower each time it was used msdos: compiling without NO_TERMS resulted in a link-time error msdos: reworked Makefile.GCC to get rid of need to duplicate source files msdos,win32: stop doing chdir when NOCWD_ASSUMPTIONS is defined tty: remove #define DEBUG that forced debug behavior in production builds tty: correctly handle an empty TERM environment variable tty: don't lose messages when ESC has canceled their display tty: clear topl after pickup_burden prompt tty: support terms where turning off inverse video turns off color too tty: object selection at --More-- prompt after '?' didn't work anymore tty: ext command autocomplete now lets you enter auto-completed characters non-tty: silently ignore tty msg_window option to allow sharing of config file unix: install recover command into GAMEDIR by default vms: prevent error() from indirectly triggering hangup save during forced exit General New Features -------------------- lootabc option runmode option showrace option travel option cmdassist option to provide additional error feedback for some commands mouse_support wincap option scroll_amount wincap option to adjust how many cells to scroll at scroll_margin debug mode: #panic routine to test panic() and panic save file generation a new PANICLOG optional file to log the reason for panic and impossible messages added validate_prefix_locations() for early directory prefix validation fire traps are particularly bad for paper and straw golems cream pies can be 'a'pplied to cause direct temporary blindness eating newt corpse or tin of same can boost magical energy (Malcolm Ryan) applying a eucalyptus leaf produces a whistle effect (Malcolm Ryan) hobbits can wear elven mithril-coats eating mimics now has an hallucination effect prefix pickup command with 'm' to force menu of all objects present provide feedback which states the correct command when players try to use 'R' or 'P' for armour, or use 'W' or 'T' for accessories optional #portdebug wizard mode command to invoke port-specific debug routines nethack-3.6.0/doc/fixes34.20000664000076400007660000002435512536476415014300 0ustar paxedpaxed$NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ General Fixes and Modified Features ----------------------------------- avoid panic when secondary weapon is cursed while generating bones level don't crash when applying a figurine, candle, or bell that gets used up grammar bits two invisible monsters hitting one another should not be visible if only one monster in a monster-vs-monster fight is visible, show an I symbol for the other one whether it is an attacker or defender display "It" and not "The invisible " when an invisible pet eats food. include a hint about expected input when prompting for musical notes don't report "program initialization failed" if a panic occurs after the game is over include statue contents in end of game inventory disclosure treat handlessness as a major problem when deciding prayer outcome perform artifact touch checks when putting on accessories missing noun in message when horns pierce through your helmet don't use hcolor() for trapped chest gases when you aren't hallucinating the age of a potion of oil from a bones file wasn't being handled correctly putting gold in a container on the shop floor wasn't credited the way gold already in the container when dropped was credited avoid integer division rounding error when calculating carrying capacity don't lock/unlock a door while in a pit, to be consistent with door opening infravision should not make invisible player "visible" (it doesn't for monsters) Perseus statue should always be male charge correctly when breaking multiple objects with the same zap, avoids a dopay: not to shopkeeper impossible clean up funny lighting on the healer locate level allow all tame monsters that eat to consider food thrown to them the screen display wasn't always up to date after map topology changes jumping over a sokobon pit would result in the player next to, not in, the pit don't let arrow, rock or dart traps provide an infinite number of objects make enhanced ammo harder to break to make lesser number last longer dropping from height or throwing a normal container may damage contents some Magicbane messages treated "erinys" as plural initialize artifacts before processing $WIZKIT clean up inconsistency between various places quaff is documented is_damageable was using is_rottable incorrectly charge for use of an unpaid tinning kit avoid impossible when water freezes while hero is hiding under water avoid impossible after eating the object the hero is hiding under failed attempt to eat floor gold while polymorphed would lose the gold running that stops for closed doors should stop at mimics mimicking closed doors allow wishing for magenta potions (ignoring the rank name 'mage') fix an uninitialized memory access in non-quick dolookup fix were changing message that wasn't being displayed immediate encumbrance feedback when removing gauntlets of power make deliberately flying down the Castle's trap doors consistent with falling give more explicit feedback for exploding bag of holding help display for "list of game options" misformats runmode and scroll_amount pit created by land mine explosion doesn't start out concealed update map display sooner when pushed boulder triggers land mine explosion prevent several QBUFSZ sized buffers from overflowing and triggering fatal errors inside window port prompt routines make sure that leashed monsters are released prior to shopkeeper inheriting dead character's inventory attaching long named candle to long named candelabrum caused buffer overflow when polymorhed, only hand/weapon attack on disenchanter should result in damage to weapon, gloves, etc. killer should say "the" when choking on unique monster's corpse allow applying polearm on monster you can see via infravision killer reason shouldn't use "a" or "an" prefix for multiple projectiles scattered by land mine explosion killer reason for named missile could end up with garbage instead of the name make killer reason for various poisioning deaths be more consistent poison missiles were unintentionally more likely to inflict "deadly poison" than in pre-3.4.1 releases provide feedback when going invisible after eating a stalker killer on tombstone had no prefix for starvation/exhaustion case ensure proper message ordering for boulder trap messages clean up data set by join_map that is overlaid by MAPs on special levels clarify disclose option default in opthelp, and support "all" as old help said add more calls to update_inventory as the inventory changes don't charge for items picked up from monster's interior while swallowed choking while eating non-food always called the food "quick snack" short swords are not throwing weapons several sit-in-trap cases were unreachable curse candelabrum in bones, like other similar artifacts detecting a trap in a chest while confused should not exercise wisdom any golem statue hit with stone-to-flesh spell animates as flesh golem correct invalid startup gender selection can no longer untrap floor containers during unskilled riding can no longer easily set land mines and bear traps during unskilled riding refine cmdassist handling for armor vs accessories prevent monsters from level teleporting out of the quest into the main dungeon prevent monsters from level teleporting into the Sanctum prior to invocation "m," command sequence would let you see all objects at a location even when they included a cockatrice corpse which hero was unequipped to handle use correct pronoun for unique monsters hostile monsters who follow you between levels won't do so if they're fleeing options for font_size for map, menu, message, status, and text all had the same description of "the size of the map font" in options.c when dismounting by choice and unimpaired, try not to land in a known trap when jousting a pudding into a polymorh trap, it was possible to end up with two of the new type of monster don't allow polymorphed player to web over the stairs geographical shopkeeper updates stethoscope use should be free the first time it's use per player move travel command caches last position to make non-mouse less painful update pit trapped time when polymorphing to or from a monster that passes_walls show artifact hit message which affect the monster that swallowed the hero revived pet corpse from bones file should not be loyal to current player finding a statue trap you are about to dig should stop your occupation try to keep saddle at the same location as the steed corpse never display I symbol on the mounted hero/steed location pit digging is no longer stopped by a sleeping monster next to you ensure mksobj() always attaches timer to corpse, even if called with init FALSE only charge for eating one stacked tin, not all at once add flag to makemon() to allow monster to be created adjacent to the supplied coordinates if there is already a monster at the target location stone-to-flesh of spot with multiple statues can animate more than one use of stethoscope now deliberately impacted when hero is engulfed by whirly monster but fixed so it can sometimes work on your steed there too typos fixed in data.base add looting freehand() check to able_to_loot() to prevent opening container only to be told that you can't loot anything Schroedinger's Cat could be placed at wrong location when its box is carried travel while polymorphed into a grid bug should not move diagonally refine cmdassist handling for grid bugs when casting force bolt spell while engulfed go ahead and use the engulfers name in the hit message rather than "it" a fog cloud shouldn't pummel you with debris do not let an attached iron ball drag the hero through a location that the hero could not move normally hero's appearance should change immediately after mimicing completes avoid some uses of "it" in killer messages avoid "singular of null?" warning for info lookup of obscure user input there was no check for iron bars in dokick() so it defaulted to "empty space" if you couldn't see the rat created in a sink for some reason other than blindness, you would get "Eek there's it in the sink." digging a pit while stuck in the floor should always free the player quest guardians can no longer be created via stone-to-flesh on their statue stone-to-flesh no longer silently ignored by a statue of a unique monster wishing for quest guardian corpse now gives a generic corpse of the species prevent quest guardians from other classes from talking to you as if they were your quest guardian wake up shopkeeper if a shop transaction is attempted while he's immobilized statues created from monsters remember more monster attributes Platform- and/or Interface-Specific Fixes ----------------------------------------- Gnome: compilation problems on Redhat 7.2 and 8.0 unix: Makefile.utl would put OBJDIR objects in the wrong directory vms: create an empty paniclog file during playground installation win32tty: add subkeyvalue option to alter key values; Finnish keyboard fix win32tty: distinguish between black/gray/white (by Quietust) win32gui: prevent male Valkyrie and other incorrect startup settings win32gui: allow numeric quantity count on item selection during loot win32: some code in files.c was incorrectly assuming that a file descriptor return value of 0 from open() was invalid but it could be valid on win32gui where stdin, stdout, stderr aren't open; now it correctly checks for return value < 0 from open() tiles: high priest tile had a couple bad pixels tiles: bad pixels in Croesus and Yeenoghu tiles FreeBSD: incorrect srandom declaration unix: don't autosave if hangup occurs after game is over linux: add example use of nroff on recent Linux distros linux: use random() by default instead of lrand48() OpenBSD: time() prototype and correct default Mail program Gnome: compilation problems on Solaris unix: better error message for .nethackrc access problems vms: during installation, warn if dlb file creation or non-dlb playground setup is missing expected data files General New Features -------------------- debug mode level teleport menu via '?' Platform- and/or Interface-Specific New Features ------------------------------------------------ win32tty: keystroke handlers can be dynamically loaded to assist in resolving internationalization issues win32tty: add Ray Chason's code for international keyboard handling Solaris (and other SystemV variants): TIMED_DELAY support X11: NetHack.ad is now installed and used w/o user intervention nethack-3.6.0/doc/fixes34.30000664000076400007660000002002512536476415014267 0ustar paxedpaxed$NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ General Fixes and Modified Features ----------------------------------- monster draining the player using Stormbringer decreased monster's hitpoints polymorphing to a flaming sphere should cure slime like other flaming monsters grammar, spelling and other typos wishing for student corpse yielded a valkyrie one, not an archeologist one fix typo in bustling town down stairs declaration you could exceed the limits on nazgul and erinys counts via bones files fix inconsistency where you can't kick something out of a pit, but you can escape the pit and still pick it up; items are now assumed to be at the bottom of pit room cleanup, eg on Bustling Town, could incorrectly truncate room bounds for rooms that become L shared due to partial overlap with the MAP approaching Medusa while having reflection+invisibility+esp would cause her to turn herself to stone if you happened to be blind at the time Master Kaen's death message was not appropriate missing fountain tag in minend-3 do not pacify shopkeeper when the hero enters a shop if that hero previously angered the shopkeeper without ever visibly entering the shop attempting to place migrating monsters onto a monster-saturated level no longer triggers impossible() open_levelfile_exclusively() was showing the return value -1 in a panic message, even though that was the only possible value; show errno instead it was inappropriate to have a ghost "appear" in desecrated temple when you were blind and without telepathy accept wish for "grey spell book" not just "grey spellbook" do not double credit when putting gold into an unpaid container manes are nonliving poles and grappling hook worked thru walls when wearing Eyes of the Overworld more tweaks to fog cloud behavior when dismounting by choice and unimpaired, try not to land on a boulder casting stone-to-flesh on self while wielding a statue caused problems add tab support to menu strings for control-x minimal_enlightenment() if the monster that a statue represents is not made of flesh then don't allow stone_to_flesh to animate it, make a meatball instead attempting to saddle a cockatrice while wearing gloves shouldn't stone you kicking a closed drawbridge and dieing should not say "kicking a wall" cannot get blessed potions from sink, remove unreachable message couldn't insert gold into a container using full menu style if no other objects in inventory unless compiling with GOLDOBJ nagas eat always have warriors on the Valkyrie quest be female be more consistent with sounds when dropping into water surface() returns "bottom" when Underwater bill for all discarded, opened tins monsters that cannot pick things up cannot throw things either eating an amulet of unchanging un-changes you Vlad won't waste time trying to use wand of digging in his own tower non-weapon iron objects should rust when dipped in fountains since iron weapons rust suppress "turn to flee" message if monster is mfrozen don't silently interrupt monster's hold on you if Levitation/Flying ends while over water you could specifiy '~' with crystal ball and have it try to detect monsters, but it never revealed anything; show the entire long worm now allow a crystal ball to detect ghosts-and-shades via space key, and display the results using detected_mon_to_glyph() so that they show up in inverse video allow a crystal ball to detect boulders using the user-defined boulder symbol allow a crystal ball to detect mimics via ']' prevent boulder option from accepting a symbol that matches a monster symbol traveling while standing on a trap would sometime step in the wrong direction avoid traveling into water/lava, using usual running rules unchanging iron golem would still rehumanize in a rust trap fix an impossible rndmonst: bad `mndx' bug pets should not try to go after objects that they can't reach cutting a shopkeeper polymorphed in to a long worm would generate strange messages and could cause a crash reading a cursed scroll of light in a corridor wouldn't display correctly if lit_corridor option was disabled barbarians can become export in short sword skill samurai are now limited to master in martial arts skill; barbarians and cavemen are now limited to master in bare-handed combat skill tweak messages when werefoo summons help when polymorphed into a quantum mechanic, it was possible to jump into the water on a no teleport level and instinctively teleport when polymorphed into a quantum mechanic on a no teleport level and swallowed, no feedback was given when you teleported the swallower away allow Conflict-resistant monsters to respond to conflict attacks rather than sitting there and taking the attacks until they die prefer herbivorous stone-to-flesh message when hero is a vegitarian try even harder to avoid incorrect map display while changing levels no "freaked" message by exploding black light, unless you really are sleeping monster could respond to attacks by other monsters sleeping shopkeeper responds to various events without waking rotting corpses grammar fix allow successful teleport to more locations on debug mode level teleport menu trapped monster repeatedly switched between ranged and hand-to-hand weapon silver items such as wands avoided all the silver checks in hmon_hitmon() resuming an interrupted 'A' command could cause crash if pending worn item(s) were stolen or destroyed resuming interrupted 'A' sometimes ended with "You finished disrobing" twice when you're asleep you shouldn't "notice" monsters that have become undetected must be able to reach floor in order to use stethoscope on corpse or statue fix a few coordinate (y,y) -> (x,y) typos in apply.c, mon.c, and wizard.c killing a long worm on a drawbridge could produce a panic prevent "see it drop from your pack" when figurine monster becomes undetected attempting to drop a subset of a stack of multiple cursed loadstones could corrupt inventory or cause a crash "miss" message was missing for thrown or kicked gold not caught by a monster prevent recursive impossible() and panic() calls from leading to a stack overflow tainted meat didn't invoke cannibalism shopkeepers can't act as porters for the Amulet dismissed monsters can't remove special items from play Platform- and/or Interface-Specific Fixes ----------------------------------------- win32tty: fix visible CRLF characters during lockfile error message win32tty: switch to low level console routines win32tty: refrain from cursor movement until an input is pending (M. Lehotay) win32tty: distinguish blue, bright blue, cyan, and bright cyan (Nicholas Webb) win32tty: fix hanging problem when you ctrl-C at "Who are you?" prompt win32gui: you couldn't specify an alignment in defaults.nh and have it stick win32gui: allow race/gender/alignment selections beyond those specified in defaults.nh, while still honoring defaults.nh choices unix: don't define errno if NHSTDC unix: save file permissions could be wrong in explore/debug mode X11: avoid a possible crash when using window manger to close a player selection window Gnome: add Quiver menu item, fix outdated Quit menu item Gnome: key values on unsigned char platform could fail to compare correctly Gnome: real extended command menu so all extended commands can be entered Gnome: ignore interrupts to avoid infinite loop in gnome library tty: avoid crash displaying quit inventory if inventory was already displayed tty: use "bold" in menu heading if available and requested tty: differentiate between default unlit and lit corridor symbols winCE: ensure orphaned lockfile is always deleted on single-user handhelds General New Features -------------------- bones file compatibility info is now written into the dat/options file extend autodig to work downwards via '>' make attribute that is used to distinguish headings in a menu configurable add experimental build option AUTOPICKUP_EXCEPTIONS for filtering pickup of items by pattern matching against their doname() description include version number in paniclog entries add a section on "shops and shopping" to the Guidebook Platform- and/or Interface-Specific New Features ------------------------------------------------ nethack-3.6.0/doc/fixes35.00000664000076400007660000000011612536476415014264 0ustar paxedpaxed$NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ There was no NetHack 3.5.x release nethack-3.6.0/doc/fixes36.00000664000076400007660000022767112625515644014303 0ustar paxedpaxed$NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ General Fixes and Modified Features ----------------------------------- change the dreaded "Stop eating?" to "Continue eating?" with default "no" setmangry should not be called when a monster enters a bones region bad capitalization of msg when charging for something that catches light missing opthelp for use_inverse Never say "It moves only reluctantly" expert fireball/cone of cold could not target a monster seen only with infravision or ESP display "lotus juice", not "lotu juice" for the fruit juice name only humanoid angelic minions should get/use sword and armor paper, straw and wood golems resist cold the options lootabc, showrace, travelcmd, and runmode are now saved use mons[] array offsets in mnum field in save file rather than storing the ptr and calculating the distance from beginning of array two-weapon combat makes two attacks instead of having one attack hit with each weapon apply weapon skill to-hit bonus or penalty to bare-handed attacks only give monk's "cumbersome armor" message when the armor penalty causes an attack to miss dust vortex-induced blindness should kick in immediately when blindfold is removed or glop is wiped off prayer/unicorn-horn won't fix blindness while still engulfed in a dust vortex since it will just return immediately being confused and reading cursed scroll of charging drains your energy class genocide recognizes species name as an example of the class to genocide (Martin Snyder) internals: use Is_box rather than explicitly checking what it checks fix some unreachable messages (either make then reachable or remove them) can quiver coins when GOLDOBJ is defined make #loot behave same for GOLDOBJ as for !GOLDOBJ for GOLDOBJ, can pick gold up into $ when all 52 letters are in use, and can pick non-gold up into unused letter when gold uses one of 52 slots grammar, spelling and other typos keep various delayed killers separate to avoid mixed up messages don't place randomly-placed aquatic monsters in lava on special levels hiding monsters don't hide under cockatrice/chickatrice corpses "sound" option renamed to "acoustics" deafness now a full-fledged attribute water should flow into pits from broken wand of digging and drum of earthquake objects that fall thru trapdoors, et al, can break on impact support engraving in blood in special level files many instances of physical damage were not taking Half_physical_damage into account when reducing your hitpoints make it possible for the code to recognize your starting pet throughout the game via is_starting_pet(mon) macro healers notice when a wand of undead turning revives a monster so the wand is then identified update display if bestowed a spellbook while unable to see invisible self use small pool of static buffers for mon_nam() and Monnam() Acknowledge Schroedinger's cat at end of game grammar fixes for applying stethoscope to corpses and statues player polymorphed as a ceiling hider cannot reach the floor, but automatically unhide on #sit trappers do not hide on the ceiling fix "You hear The food ration tumbles downwards" for blinded pit dropping silver arrows weren't causing silver damage on some silver-haters when wielded wizard mode: avoid division by 0 crash for level teleport in the endgame if confusion overrides teleport control don't #sit on an object in a pit if you're only on the precipice fix message when pushing a boulder into a pool while riding plural of "Nazgul" is "Nazgul" not "Nazguls" trap messages referring to named steed were awkwardly worded when hallucination overrode use of the name some actions such as eating corpses off the floor didn't check whether hero could reach the bottom of a pit usmellmon() instead of "It turns into it" during monster polymorph grammar of messages regarding eating artifacts avoid a message about an invisible monster looking much better player polymorphed as a xorn could not pick up items in pits non-magical whistles do not work underwater try to restrict whistles and musical instruments to monsters that can blow don't display "turns to flee" message for a mimicing mimic don't display "turns to flee" message for a monster who has just died dipping acid in a fountain could cause an explosion but not destroy the potion thrown potions can sometimes hit a steed's saddle if your blindfold glows and you're not otherwise blinded, you can see it sync default documentation of "null" option with the code tripping over a cockatrice corpse didn't petrify, even when not wearing boots do not call swamps on the Juiblex level "moat" when freezing or drowning; likewise for Plane of Water when drowning keep score from wrapping around and becoming negative by capping it kicked objects do not slide when on the air or water levels added strsubst() to hacklib be consistent with use of "removing" rather than "lifting" for encumber messages associated with taking things out of a bag of holding when a giant carrying a boulder dies in a pit, ensure that the corpse is buried under the filled pit cursed scroll of destroy armor damaging cursed armor didn't adjust attributes add passive() flag that indicates uwep was destroyed during the turn polymorphed or shapechanged monster sometimes got erroneous hit points when blind and levitating > shouldn't say "stairs" if player has not seen them a slow-moving monster hidden under a rotting corpse was not immediately displayed when the corpse rotted away mimic that ends up on the rogue level should not mimic a closed door mimic should not mimic a boulder while on a pit or hole or closed door calculate weight of corpses on special levels correctly Sting could trigger premature display of orcs during savegame restore Sting now glows light blue again prevent "offering" or other words with similar ending from matching ring quote make cleric cast lightning blind as other lightning does change the wording slightly to use "one of " when a monster wielding multiple daggers thrusts them if you didn't see a rolling boulder fall into a pit, you only heard the sound of it doing so if you were blind fire trap was triggered twice in the same turn when melting ice was involved abandon the specialized djinn and ghost counters used for potion tuning and use the mvitals[].born field instead if you were Poison_resistant, only a *blessed* potion of sickness caused loss of hitpoints reviving invisible troll could appear visible until it moves adjust some of the shop repair messages shopkeeper removal of trap from shop doorway yields an open door instead of a closed one if an intact open door is present guarantee that hostile djinn released from bottles really are hostile handle lava when removing or losing water walking boots fix incomplete sentence occurring when unique monster's corpse fell down stairs fractured boulders or statues produced inconsistent object settings on the resulting rocks really fix rolling boulder bug C340-18, the previous "fix" reversed the test monster throwing greased weapon has same chance for slip/misfire as player killing a pet by displacing it into a trap now yields experience prevent a rolling boulder that is in motion from vanishing in bones files ensure that a sleeping steed doesn't answer a #chat eliminate two very minor anomalies when using Luck to adjust random numbers destroying a worn item via dipping in burning oil would not unwear/unwield the item properly, possibly leading to various strange behaviors avoid a panic splitbill when shopkeeper is trapped by the door grammar tidbit for message given when eating tainted meat is also cannibalism gas spores shouldn't be described as "unable to attack" while hero is praying incorrect screen display if engulfer gets turned to stone when trying to swallow while hero is poly'd into cockatrice panic on subsequent move if engulfer gets turned to stone and poly'd hero also has attached ball&chain give more specific messages when dropping weapons due to slippery fingers various helmet messages changed to distinguish between "helm" and "hat" helmets don't protect against cockatrice eggs thrown straight up breaking container contents in a shop didn't always charge for them some types of shop theft of a stack of items only charged for a single one some thefts weren't charged at all even though shopkeeper noticed wizard mode: WIZKIT wish for own quest artifact triggered crash at startup avoid "your steed is still eating" message when going through a magic portal cannot drink from fountain, sink or surrounding water while swallowed don't hallucinate anything for an exploding black light as it dies give blindness feedback when moving into/through stinking cloud fix case on monster name when monster reflects floating eye's gaze monsters "shrieking in pain" from a potion didn't wake anything up charge for reviving a shop owned corpse or reanimating a shop owned statue filled trap doors on castle can be re-dug message order when swapping places with a pet (e.g. into a trap), also use different term instead of "displace" flyers can get out of pits more easily than non-flyers allow use of the < command to try to exit a pit Master of Thieves as Tourist Nemesis still had STRAT_CLOSE co-aligned unicorns in bones could be hostile finding "something" posing as a statue while Blind should map_invisible() adding more candles than required to total 7 to a candelabrum which already had between 1 and 6 gave an ungrammatical message give correct message when a spellcasting monster summons other monsters correct experience calculation for monsters that cause nonphysical damage clean up messages when you stop levitation while riding a flying steed monsters evading a kick on noteleport levels would cause a "teleports" message interrupt current activity during certain stages of petrification or vomiting warning about bad food didn't recognize tin of Medusa meat eating tainted Medusa corpse caused food poisoning instead of petrification avoid potential stale pointer use after magic bag explosion nymphs and monkeys can't steal rings worn under gloves monkeys can't steal rings worn under cursed weapon succubi will remove hero's gloves before taking worn ring; incubi will do so before forcing ring to be put on mbodypart should return forehoof, not foreclaw, for horselike monsters; rear paws instead of rear claws for feet of d, f, r, and owlbear; hand, arm, leg, foot for yeti, sasquatch, monkey, ape, carnivorous ape further digging of an existing hole finishes in a single turn only prefix shopkeeper names with "Mr." or "Ms." when not a personal name account for all attacks when determining max_passive_dmg green slime should not affect noncorporeal monsters land mine explosion will destroy a drawbridge at same location avoid some more buffer overflows in query buffers containing object names avoid giving extra information about things that break out of sight dipping in acid can erode the dipped object avoid giving away wand type for near misses while blind avoid excessive repetition of "monsters are aware of your presence" monster's aggravation spell now affects meditating monsters handle pets sooner at end-of-game to avoid message delivery anomalies busy pet won't miss out upon ascension fix various places that "finally finished" could be displayed after the hero stopped doing something other than eating fix some cases where movement was disallowed but the hero was still conscious after destroying drawbridge, hero could appear to be in the wall sometimes shop items which hero is forced to buy could be sold back twice non-empty container dropped but not sold in a tended shop and then picked up after that shop became untended could be sold twice in another shop vision was not updated when polymorphing a statue into a boulder various actions--such as enchanting--performed on an unpaid shop object either force the hero to buy the item (when its value is lowered) or increase the current bill (when its value is raised) `I u' when carrying single unpaid item listed its cost twice armor which auto-curses when worn by hero should do same if worn by monster limit how high accuracy, damage, or protection can become via eating rings when blinded hero detects a trap by touch, make sure it shows up on the map confused remove curse will cause loss of knowledge of items' curse/bless state with astral vision, the ";" command should only display "normal vision" for things that could be seen without astral vision reanimating a statue containing gold produced double gold probing the resulting double-gold monster caused "static object freed" panic cursed wand might explode if used to engrave fatal wish from magic lamp left functional magic lamp in bones data fatal wish granted by monster left that monster in bones data death due to dipping potion of acid into a pool left the potion in bones data clear prompt from screen after ESC is used to abort "In what direction?" minor interface changes for interactively manipulating autopickup exceptions chatting with quest leader who was brought back from the dead gave warnings becoming green slime or mimicking gold violates "never changed form" conduct when a monster grew into a higher form which had previously been genocided, the message explaining its fate was only given if it was sensed via ESP hero could still see for brief period after being blinded by potion vapors avoid crash when thrown potion hits bars before a monster don't give messages about seeing things happen while asleep adjust health threshold where wounded hero will be healed by successful prayer protect hero from mind flayer's remote mental blast during successful prayer recognize if hero has already entered Gehennom by means other than usual route so that prompt can be skipped if Valley's stairs are subsequently used once you've passed the Valley, drawbridge tune is no longer a prayer reward fix up grammar and punctuation in variants of shopkeeper's price message regression, bug fixed in 3.4.1 reintroduced in 3.4.3: Sunsword continued to emit light after monster who was wielding got killed weaken "farming" strategies don't suppress corpse if you kill your own steed fix typo in tourist quest leader's greeting fix grammar for graveyard sounds when polymorphed avoid divide by zero crash if Luck drops below -1 while a prayer is in progress make hero inflicted with lycanthropy immune to level drain just like monsters describe locomotion method accurately when flyers traverse ladders or holes when there were multiple boulders at a location, moving one of them sometimes resulted in line-of-sight anomalies unicorn can't catch gems if it is asleep or paralyzed fix grammar when choking on gold prevent lose-level+regain-level cycle from arbitrarily boosting HP and Pw prevent polymorphing into "new man" at low level from magnifying HP and Pw some messages which referred to "mirror" ought to have used "looking glass" incubi react to mirrors losing a level while polymorphed affects hero's current monster HP as well as underlying normal HP mind flayer brain eating is subject to certain fatal targets and to cannibalism mind flayer can't eat brains of ghost or shade alignment of Angels was handled inconsistently corpses of unique monsters in bones behaved incorrectly if revived or eaten pets capable of digging could pass through walls and stone on the Rogue level don't generate mimics pretending to be closed doors when making Rogue level fix pluralization for "this tin smells like mother-in-laws" when hallucinating force user-specified fruit name to be singular avoid false matches when looking up fruit names ("grapefruit" isn't "grape") handle pluralization of man-at-arms and singularization of men-at-arms avoid inappropriate "the corridor disappears" when vault guard gets killed avoid inappropriate "the guard calms down" if vault guard's magic corridor reaches a spot where gold is embedded in the rock avoid having vault guard ask hero's name when hero is swallowed assigning an artifact name is rejected on objects with similar description to corresponding artifact's type rather than just those of the same type adjust feedback for gas spore explosion when hallucinating adjust message for gas effect from chest trap if hero resists hallucination cancelling non-shop objects in a shop's entrance would upset the shopkeeper traps detected by scroll or crystal ball overlooked carried or buried chests can't wish for a trapped box/chest/tin by specifying "poisoned" grammar bit if killed by stealing a cockatrice corpse from a monster identified touchstone can rub on gold like the data.base entry says restore the capability of rubbing any object against known touchstone being petrified by swallowing a cockatrice violates foodless conduct devouring Medusa whole is fatal tombstone's reason for death after being killed by mis-returning Mjollnir varied depending upon whether it was fully identified tombstone's reason for death from kicking an object could include so much detail about the object that is was too verbose several quest messages were worded inappropriately if the hero was blind a samurai quest guardian message used "ninja" where "ronin" was intended revive from fainting if vault guard or bribe-demanding demon approaches tame flaming spheres and shocking spheres shouldn't pick up items eating pet won't continue eating after becoming paralyzed or falling asleep can hear the opening or closing of an unseen drawbridge prevent "object lost" panic caused by accessing freed memory after worn non-fireproof water walking boots are destroyed by lava stop multi-turn running, searching, or resting early if levitation ends randomize shopkeeper names when hallucinating fix wording for "leprechaun steals gold from between your feet" when mounted Call command could be used to remotely identify which high priest is which large amorphous, whirly, noncorporeal, or slithy creatures can fit through tight diagonal gaps despite their size avoid "You summoned it!" for unseen monster produced by same-race offering fix monsndx panic which happened after currently moving monster expelled swallowed hero onto magic trap and was made tame by its effect; taming no longer replaces monster reduced message verbosity when re-entering a temple reduced message verbosity when monster with multiple attacks missed wildly recognize "mindflayer" as an alternative spelling for "mind flayer" putting on a never seen ring while blinded won't make the ring a discovery zapping a never seen wand while blinded won't make the wand a discovery zapping an unID'd wand of teleportation at self will discover it (usually) zapping unlocking magic at self while punished will remove attached chain treat mattock as blunt object when forcing locks restore capability to force locks with wielded statue only count successful statue creations against the monster limit in sp_lev.c don't see objects or read engraving when hero changes location (random teleport) or position (levitation timeout) while asleep or fainted unseen wand of striking zapped by unseen monster became known if it hit a door tweak knight quest messages guidebook grammar bits special level loader wasn't able to place random door in 1x1 room; could trigger divide-by-0 crash for user-developed custom levels polymorphed spellbooks may turn blank or be too faint to read make gender of quest leaders and nemeses consistent with data.base and quest messages Orion and Norn should be giant sized Orion, Norn, Cyclops and Lord Surtur should be able to tear webs avoid inappropriate message when using a cursed lamp while blind player polymorphed as a guardian naga spit the wrong kind of venom ensure monsters cannot teleport to or be created outside nonpassable bounds of special levels candles should not be fireproof put #define for potion occupant chance and cursed wand zap chance in one place recognize most instances where hallucinatory monster name should be treated as a personal name (to avoid "the Barney") instead of a description avoid giving misleading or redundant feedback when reading scrolls monsters could end up off the left side of the Ranger quest start level custom arrival message for special levels could be delivered too soon custom arrival message for special levels now supports quest text substitution prevent scroll of charging that has already disappeared from showing in the picklist of things to charge doors break instead of absorbing the blast of a broken wand of striking worms don't have scales, krakens have tentacles, stalkers have a head you no longer "fry to a crisp" as a water elemental change leather spellbook to leathery; pertains to appearance, not composition more precise probing/stethoscope feedback when engulfed make baby long worms have lower level than full grown ones use "your kraken" instead of "a kraken" when searching reveals a tame hidden monster Magicbane should not produce " are confused" message handle antholes more sensibly when ants aren't available avoid "Something's in the way" message with unidentified wand of locking cancelled nurses shouldn't say "Relax, this won't hurt a bit" check for hero location in digactualhole() before clearing u.utrap clear any pits that the hero digs in the vault guard's temporary corridor better handling for Fort Ludios and endgame in wizard mode's `^V ?' menu no free lunch for gelatinous cubes eating scrolls of mail eating gold in front of the vault guard will make the guard angry calculate engulf time differently for non-digestion attacks than for digestion preform autopickup and/or report on objects at the spot when a failed #untrap attempt causes the hero to move onto a trap's location shattering a monster's weapon didn't work as intended for stack of N>1 thrown silver weapon hitting silver-hating poly'd hero got double silver damage wielded silver weapon hitting silver-hating poly'd hero lacked silver message don't reveal surface information that you can neither feel or see if the hero or a monster is already in a pit don't have them "fall into a chasm" from drum of earthquake monsters who ate lizard corpses to cure confusion would lose intrinsic speed monsters couldn't eat lizard corpses to cure being stunned code handling a monster's use of potion or food to cure stoning or confusion was accessing freed memory after the object had been used up properly handle destruction of equipment carried by monsters hit by disintegration breath; life-saving retained conferred properties of formerly worn items (loss of steed's saddle caused much confusion) don't exercise or abuse wisdom when rumors get used for random graffiti don't exercise wisdom twice for each minor oracle consultation don't welcome the hero to Delphi if the Oracle was angered before first entry create_object() created lizard corpses without timers and troll corpses with their revive timers, then changed the corpsenm field when a potion of acid was dropped into water and exploded, nethack would continue to use already freed memory and later might panic or crash when jumping over an already seen trap, use an() to get appropriate grammar fix bad grammar when putting on not-yet-seen Eyes of the Overworld while blind don't "walk quietly" while levitating shopkeeper polymorphed into animal form can no longer speak don't give attribute adjustment messages ("you feel wise") unless the current value actually changes fix message handling when multiple shopkeepers are present at end of game 'C' command can't name shopkeepers or temple priests and other minions when "of " is intentionally being suppressed, an aligned or high priestess would be described as an aligned or high priest specifying role and/or race along with an invalid alignment for it/them in NETHACKOPTIONS or config file would yield a prompt which misleadingly mentioned the rejected alignment when asking player to pick alignment temple donation can recover protection previously stolen by attrcurse attack even when protection amount is so big that no increment would be given meditating monsters stop meditating when affected by something which wakes sleeping monsters monsters capable of hiding can't do so when trapped or while holding you limit recursive calls to spoteffects (poly'd hero fell into water, reverted to human because of it, fell into same water, then crawled out twice) ensure that the punishment ball and chain make it into save file after being temporarily orphaned from the normal chains in the swallowing code display the invisible monster glyph ('I') whenever an unseen monster forces poly'd hero out of hiding charge for thrown wand that shatters into a thousand pieces in a shop wielded light source susceptible to water gets extinguished when weapon rusts don't discover unknown bag of tricks when monster it releases is undetected escape the deleted trap after performing the invocation while trapped use alternate phrasing when life drain attack affects non-living creature bypass "wait! there's a creature hidden there" when attacking a hidden monster sensed by ongoing monster detection remove makedefs.c dependency that time_t and long are the same size terminal window set to 21 lines can cause a crash during player selection menus; have bot() check for valid youmonst.data make region ttl field a long instead of short to get rid of lint warnings about a possible loss of data free storage used to hold region messages in free_region() honor pushweapon when applying a tool or weapon causes it to become wielded in the quest, if the locate level hasn't been reached yet, don't fall or randomly teleport past it fix phrasing in monster against monster attack feedback when attacker is wielding stacked weapons pushing a boulder onto a level teleporter trap could issue repeat messages if shopkeeper or priest gets teleported while inside his shop or temple, give locations inside that room preference when choosing destination don't place hero on top of monster when arriving on level which is so full that the monster can't be moved out of the way tame/peaceful grabber/engulfer will release hero after conflict ends any grabber will release hero if it moves away while confused/stunned/afraid make changes in hallucination be reflected by changes in mimickery feedback have to see a divine gift in order to have it become a discovery honor the never-in-hell flag when selecting random monster type for corpses, eggs, figurines, and statues created in Gehennom hero is not subject to light-based blindness while fainted from hunger add Unaware pseudo-property to suppress various messages while unconscious engraving while underwater should use surface() which handles that case prevent obj_is_local panic during bones creation when splattered burning oil from a thrown potion of oil kills the hero don't leave lit potion intact when splattered burning oil from broken floor potion kills the hero fix region timeout detection, caused strange display of stinking cloud while wearing the Eyes of the Overworld try to keep migrating monsters from escaping the wizard tower affected monsters should always respect "Elbereth" try harder to keep dragged chain between ball and hero fireproof containers should not burn in lava missile which kills engulfer will now be placed prior to hero's return to map fix invalid pointer dereference after applying a wielded cream pie avoid drowned in a drowning and burned by burning if life-saving is inadequate bugles affect all monsters to some extent nurses are affected if player is polymorphed as a cockatrice getting a particular rotten food result can't make attempting to eat a corpse of one of the Riders be survivable pad shortest rumors to improve distribution of delivered rumors wake up sleeping steed when putting on saddle or mounting reveal hidden monsters who change levels or are magically summoned hero can't carry an unlimited number of boulders when poly'd into a giant stop wielding cockatrice corpse which triggered own death followed by life-save format various prompts to avoid "Query truncated" entries in paniclog prevent very large number of objects in # inventory slot from causing buffer overflow !fixinv config was using arbitrary characters instead of # for invent overflow for inventory display, include cost info on hero-owned containers holding shop goods shops now claim ownership of items created by using an unpaid horn of plenty shopkeepers shouldn't refer to non-male character as "cad" tweak levitation timeout if trap is being triggered on same turn it is to end don't report death by petrification if cockatrice kills hero via HP loss Riders are immune to green slime Rider corpses can't be engulfed by gelatinous cubes if Rider corpse revival fails, usually try again later instead of rotting away wielding a cloak of magic resistance or gray dragon scales, or carrying one in alternate weapon or quiver inventory slot, conferred magic resistance to polymorphed hero wielding a potion of blindness or carrying one in alternate weapon or quiver slot conferred resistance against light-based blindness to any hero worn item transformed by polymorph remains worn if feasible zapping closing or breaking magic up or down from beneath an open drawbridge's portcullis failed if bridge orientation was north-to-south (Valk quest) can't dip or apply grease to a worn item that's covered by another worn item sinking into lava didn't track passage of time properly sinking into lava eventually burns away slime; sitting in it always does after escaping lava by foot, if hero doesn't move he'll fall back in suppress corpse from bones data if death is due to being dissolved in lava suppress "you rise from the dead" if game ends due to be turned into slime hero poly'd into stone golem and wielding cockatrice corpse casts stone-to- flesh at self to become flesh golem will revert to stone if no gloves don't give erroneous " disappears" message for hero poly'd into quantum mechanic who hits engulfer while swallowed and blinded demon lords/princes can't be summoned to the elemental or Astral planes feedback from casting spell of protection was wrong in some situations can't engrave on floor while inside solid rock, wall, or closed door same-race sacrifice can't damage high altars allow corpses on floor to be offered at high altars allow hero to attempt to offer the Amulet at ordinary altars shooting range for crossbow isn't affected by strength; multi-shot volley is remove engravings at drawbridge location when it is opened, closed, or wrecked monster killed in midst of multi-shot volley throwing/shooting might cause freed memory to be accessed, potentially triggering a crash right-handed boomerang throw travels counterclockwise can't arm bear traps or land mines on Planes of Air or Water statues that "come to life" when trap activates shouldn't start out sleeping shopkeepers and priests wouldn't step on graves put in their rooms by bones can't throw if poly'd into form which lacks hands monsters can use ranged attacks over/around boulders, same as hero can't eat an artifact you're unable to touch attempting to kick beyond map edge performed an out of array bounds memory access; symptom seen was "show_glyph: bad pos" warning when blind attempting to engrave with an empty wand should always use a turn don't access freed memory after engraving "wrests one last charge" from wand a magic portal could be rendered inactive for the hero if a successful hangup save took place during level change; leaving the level by any means other than triggering the portal would reactivate it can't drop part of a stack of N weapons welded to hero's hand pickup still accepts m as command prefix, but now rejects F,g,G,M,numpad 5 scatter piles of kicked gold rather than move the entire pile at once hero wasn't allowed to affix candles to the candelabrum while underwater non-unicorn horn healing magic which cures sickness now also cures vomiting vomiting/nauseated state is included in enlightenment feedback vomiting countdown actually triggered the final vomit code twice rats aren't capable of vomiting fireproof, non-rustable weapon would be revealed as fireproof by hitting a rust-causing target; ditto for fixed crysknife surviving choking while eating various foods (cockatrice egg, fortune cookie, wolfsbane, others) didn't carry through to those foods' side-effects shapechangers who take on mimic or hider form will mimic or hide when feasible avoid War message if tinning a Rider corpse fails prevent long messages from triggering access violation or segmentation fault due to buffer overflow in pline() cursed corpse wielded by a monster isn't welded to its hand or paw fix grammar errors in samurai quest, wakarimasu ka? fix spelling of Dr Dolittle hero's sleep resistance shouldn't protect steed from sleeping gas trap #jump attempt fails if mounted on sleeping steed; jumping spell still works dropped wielded, in use leash should remain in inventory, since it's in-use wielded, in use leash can't be snatched by whip-wielding monster when using two weapons at once, whip-wielding monster can target either one if normal game save file is restored via `nethack -X', restore in normal mode--with save file deletion--and require confirmation ala 'X' command to make deferred switch into explore mode can't #force floor item while engulfed, levitating, or unskilled riding can't lock or unlock doors while engulfed if hero or monster standing on opened drawbridge survives its destruction, fall into water or lava instead of remaining on top don't give a speed change message when an immobile monster is seen to be hit by a wand of speed or slow monster when shopkeeper "gratefully inherits possessions" of hero who dies in shop doorway without owing the shop, move those items inside shop for bones dying in a shop while wielding two weapons could cause "Setworn: mask" warning make score file processing more bullet proof to avoid potential security issue stethoscope applied to hiding mimic will bring it out of hiding rephrase " evades your grasp" message if artifact is already held artifacts which subsequently evade your grasp/control after already being worn or wielded become unworn/unwielded towel equipped in weapon, alternate weapon, or quiver slot can be applied lit candle or potion of oil which burned out while equipped would leave stale weapon/alternate-weapon/quiver pointer that could cause panic or crash wielded/worn figurine which auto-transformed had same stale pointer bug likewise with casting stone-to-flesh on self for figurine of non-veggy monst format names of not yet id'd artifacts such that obj type shows for non-weapons hero with lycanthropy is vulnerable to silver in both human and beast form changing alignment or shape triggers a check for equipment evading hero's grasp passive fire effects can damage attackers' weapons make quest leader and nemesis be unlikely to be affected by traps wielded bow shouldn't affect outcome of kicked arrows ranged polearm hit can divide puddings and can use confuse monster effect charge for kicked shop-owned food if it gets used up taming a monster give better feedback when thrown shop-owned food gets used up taming a monster effect of negative AC on damage received was calculated differently than normal when deciding whether hero poly'd into pudding would split use a more precise jumping path for far, non-straight line destinations unicorn horn produced by revived monster will polymorph as if non-magic stone-to-flesh on any golem statue or golem figurine creates flesh golem stone-to-flesh which activates shop-owned figurine entails shop charges make giants be less likely to be randomly generated in Sokoban bear traps dish out some damage on initial entrapment bear traps and webs are harmless to water elementals hero with polymorph control and inflicted with lycanthropy can specify own werecritter or human werecritter monster types as polymorph target hero undergoing semi-controlled polymorph won't also undergo sex change when doppelgangers taking on new shape don't specifically pick nasty monster or role monster, bias the random form towards humanoid salamanders can use green slime corpses to cure themselves of petrification increase damage bonus applies when kicking while polymorphed into a monster form which has a kicking attack, just like for other kicks feedback about summoned monsters may use singular when it should use plural if magically removing steed's saddle is fatal, don't leave it saddled in bones charging prompt used wrong criteria when deciding whether to list rings rogue's backstab bonus doesn't apply for throwing attacks hiding monsters who are unhidden when hero leaves a level can hide upon return touching a pile of objects while blind affects hero even when the pile is big enough to give "there are many objects here" and not list them explosion while engulfed only affects engulfer and hero, not adjacent monsters eliminate case-sensitivity when converting words from singular to plural and vice versa, so some failing wishes like "Gauntlets of Power" now work breath attack directed at self by poly'd hero always hits an orc (or gnome) will respond to #chat if hero is also an orc (or gnome) override non-silver vs shades for artifacts which deal extra damage to undead assorted mirror fixes--mainly visibility issues kicking at "empty space" has side-effects so should use current turn using weapon to kill tame engulfer from inside triggered "placing defunct monster onto map?" warning some monsters can't be strangled; self-polymorph can stop/restart strangulation nymphs could steal carried boulders amnesia of object discoveries would never forget the very last one re-adjust gem generation probabilities when revisiting existing dungeon levels kick evasion shouldn't move monsters through walls kick evasion and jousting/staggering blows shouldn't move grid bugs diagonally #untrap didn't check whether hero could reach the ground digging/chopping a closed drawbridge message mentioned digging a "wall" attacking via applied polearm now honors the "confirm" option engulfer under influence of conflict or confusion could swallow monster at water/lava/trap spot and not be affected by destination til next move unicorn horn restoration no longer overrides sustain ability characteristic hider monster revived from corpse would start out hidden (even if own corpse was only object around to hide under) fix sequencing issues with dropping #invoked Heart of Ahriman applying an unpaid stack of potions of oil forced hero to buy all of them instead of just the one which got split off and lit sometimes when hero is forced to buy an unpaid shop item its price changed monster could attack with a polearm even after attempt to wield that failed sometimes got "you trip over it" after intervening messages following the one which described "it" wizard mode: WIZKIT wishes could overflow inventory's 52 slots code controlling item drops by small monsters still used pre-3.1.0 weight monsters who want the Amulet won't attack the Wizard to try to get it when loading bones files, censor suspect characters from player-supplied strings such as pet and fruit names opening or closing the castle drawbridge via music consumes a turn can't swap places with tame grid bug when moving diagonally can't move diagonally through a long worm's body (can still fight that way) require confirmation to read a scroll of mail if doing so will be the first violation of illiteracy conduct could get "suddenly you cannot see the " while invisible mon remained displayed due to telepathy or extended detection cutting a long worm in half would trigger segfault/accvio crash if the hit took parent down to 1 hit point or if long worms had become extinct cutting a level 0 long worm in half produced a new worm with 0 hit points using F to force an attack towards a boulder gave "you attack thin air" random "treasure drop" upon monster's death bypassed dropping side-effects melted ice on Valkyrie quest should be pool, not moat some variations of attempting to use open or close commands on a drawbridge didn't give drawbridge-specific feedback tin contents can now sometimes be accessed on the same turn that the tin starts being opened; when not, the opening feedback is more accurate Nth adjustment of feedback when observing a pet eating monsters who want the Amulet won't attack temple priests to try to get it blinded invisible hero can't see self as invisible via ';' or '/' it was possible to generate an object of 0 gold pieces by dropping 2**32 gold wizard mode's sanity_check option missed nested containers and migrating mons always update map display and use up turn if open or close command attempted while blind reveals change in door state or discloses non-door spot a hangup save while picking up gold from shop floor could duplicate that gold secret door detection's trap finding is no longer blocked by water or clouds on the Planes of Water and Air potion thrown by monster which hit a long worm's tail gave feedback about hitting its head implement energy vortex's previously unused energy drain attack changing alignment type resets alignment record to 0 (nominally aligned) jellyfish do not technically have a head while polymorphed, suppress attribute gain/lose earned by pre-poly exercise wizard mode #monpolycontrol prompting asked about "it" when monster was unseen reprompt if player fails to make a menu choice during inventory identification potion explosion during failed alchemy should awaken nearby monsters seen eels who were stuck in isolated pools would never re-hide can no longer get both strength and resistance from eating one giant corpse aborting key/lock pick usage via ESC at direction prompt no longer uses a move lit south wall of C quest leader's room contained dark gap at secret door spot when probing from inside an engulfer, "not carrying anything" overlooked hero archeologist shouldn't start with sling skill by carrying slingable touchstone wearing or removing an amulet of restful sleep clobbered permanent sleepiness if attempt to select a co-aligned artifact for first divine gift fails because none is available, choose one from among nonaligned artifacts ensure current_fruit gets set to the correct index when setting fruit option to existing entry whose fid is not the highest monsters already wearing suits can't put on shirts if breaking a wand of polymorph causes hero to drop items, don't transform them give "shuddering vibrations" feedback if breaking a poly wand uses up items if polymorph causes a monster to drop items, they won't be used up via shuddering vibrations or as golem creation fodder monsters who ate green slime corpses weren't turned into green slime "hand slip" while naming an object would never pick 'z' as a substitute letter hero would "gladly take off " for nymph or succubus even while asleep concealed mimic wasn't revealed if kicking attempt yielded a clumsy miss too accurate feedback given to a blinded hero when a monster summons insects if life-saved steed became untame, repeated "placing steed onto map?" warnings would be given as long as the hero remained mounted message sequencing for fatal explosions was confusing if feedback was given for carried items being destroyed when dipping something in holy/unholy water, only learn its new bless/curse state if hero sees it glow describe lit Sunsword as shining rather than glowing prevent poly'd shopkeepers from taking on forms that can't handle objects attempting to move direction 'u' as a grid bug performed #untrap command; the other diagonals reported "unknown command" instead of "you can't" mimic posing as statue or corpse now picks and maintains particular monst type trying to move down while levitating said "you are floating high above floor" even when being stuck in floor or lava blocked full levitation when levitating, don't show '>' as a likely direction for digging poly'd or mimicking hero who was hidden from monsters would still be treated as a normal target for their ranged attacks hero would remain stuck to an adjacent monster after rehumanizing if he had been attacked while hiding via #monster when poly'd into a small mimic hero poly'd into mimic and hiding as an object via #monster didn't unhide when polymorphing into non-mimic attacking via applied polearm never scuffed engraving underneath hero auto-wielding a polearm took no time if ESC was used to cancel target choice applying a bullwhip while at very edge of map could target beyond edge, potentially leading to a panic or crash prevent temple priests and minions from wearing helms of opposite alignment 'D' drop command didn't handle 'u' choice correctly if the only unpaid items were inside containers pearl rings shouldn't rust shouldn't be able to read a worn T-shirt when it's covered by a worn suit simplify hero placement on Castle level when climbing up stairs from Valley spell attack by low-Int hero could inflict negative damage some wand/spell/breath zaps that hit a secret door failed to reveal it wand explosion feedback about adjacent door was phrased as if for a wand zap improve the message sequencing when a thrown poisoned weapon loses is poison message "You hit the with all your might." could be issued if a boulder went away while it was being dug/broken with a pick-axe prevent "object lost" panic if/when drinking a wielded potion of polymorph causes hero's new form to drop weapon documentation tidbit: change Guidebook and in-game help for pickup_burden option to match game's 'O' command ("Unencumbered", not "Unburdened") writing while blind no longer possible for books, might fail for scrolls blanking items in pools while blind shouldn't reveal new obj description for ones which had been seen before becoming blind avoid infinite loop in topten output when killed by long-named monster grid bug could move diagonally 1 step using travel command attempting to open, close, or lock/unlock a door while confused or stunned uses up a move regardless of whether direction choice finds a door grammar fixes for vault guard messages given after player assigns guard a name wearing cloak of displacement auto-discovered it even when hero couldn't see wearing elven cloak auto-discovered it even when already stealthy putting on ring of stealth never auto-discovered it forgetting spells due to amnesia now sets memory retention to zero instead of removing them from hero's list of known spells shouldn't have been able write scrolls by guessing type name when they're only partly known via name assignment scrolls given names can be written by assigned name as well as by description fix writing feedback "the spellbook warps strangely, then turns parchment" make stone artifacts usually resist stone-to-flesh when reading an unknown scroll and learning it, discovery of teleportation was too late if hero happened to land on another scroll of teleportation using an unlocking tool on a closed door which was actually a mimic reported that there was no door to unlock instead of exposing the mimic purple worm could end up in wall or solid rock when swallowing ghost or xorn unpaid shop items stolen from hero by a monster remained on hero's shop bill #untrap toward known trap location containing concealed mimic would yield "{The mimic|It} {is in the way|isn't trapped}." but not reveal mimic some actions taken when blind would yield "Wait! That's a monster!" (for a mimic posing as a door) but not display the unseen monster glyph enhance life-saving by preventing subsequent poison from being fatal upon rescue from death due to spiked pit, dart trap, or poisoned missile don't create mail daemons when populating special levels with random demons teleport control and polymorph control are ineffective while hero is stunned don't report "fried to a crisp" for disintegration from divine wrath when polymorphed into an opposite sex monster, if you then become a new human while failing to polymorph into something else, you'd be told "you feel like a new man" for female or "a new woman" for male spellcasting monsters' spell selection became less likely to choose harder spells as their level got higher (including Wizard's "double trouble") Eye of the Aethiopica, Eyes of the Overworld, and Sceptre of Might must be worn or wielded rather than just carried to convey magic resistance Mitre of Holiness and Tsurugi of Muramasa convey Protection when worn/wielded effectiveness of magic cancellation by worn armor has been reduced Protection improves the effectiveness of magic cancellation the weight of a non-cursed bag of holding was sometimes off by 1 unit for number_pad:2 (MSDOS compatibility), M-5 (Alt+5, or Shift+keypad5 using MSDOS/Windows keystroke hackery) didn't function as G movement prefix if an angry shopkeeper chased the hero to a different level and then got paid off, he'd dismiss kops on that other level but not on his shop level objects inside the Wizard's Tower can't be teleport to outside and vice versa dying in lava and being life-saved or leaving bones would destroy ring of fire resistance if it happened to be made of wood, and also burn up scrolls of fire and spellbook of fireball surviving in lava boils away carried potions, but dying in lava and being life-saved or leaving bones would keep them intact when applicable, give "your body rises from the dead as an ..." even when bones data isn't being saved unlit candelabrum would become unlightable if its candles had exactly 1 turn of fuel left and it was applied anywhere other than the invocation spot have shk claim ownership of worn saddle dropped by dying pet if hero is not within the same shop at the time of the drop temporary loss of Dex from wounded legs will become permanent if it occurs while mounted and hero dismounts before steed's legs have healed for poly'd hero hiding on ceiling who gets attacked, make attacker's position be an eligible location for hero when vacating hero's spot for attacker to prevent ending up far away under crowded conditions for poly'd hero hiding on ceiling, attack by sea monsters won't move them into hero's position unless it is over water or they're already on land for poly'd hero hiding on ceiling, attack by long worm might fill hero's destination with worm's tail, so double check and maybe choose again poly'd hero can't hide on floor or ceiling when on Planes of Air or Water when shop prices are adjusted, handle roundoff (integer truncation) better for hero poly'd into a monster form that lacks a weapon attack but has a claw attack, use wielded weapon even when claw attack isn't the very first rename the SLEEPING property and Sleeping attribute to SLEEPY and Sleepy, resp. character escape sequence handling during options processing was vulnerable to malformed escapes and could potentially be abused to clobber the stack and launch a buffer overrun attack give alternate message for " turns to flee" when mon can't move all statues in a cockatrice nest were for giant ant if 'record' was empty when dying outside all shops on a level with multiple shopkeepers and one takes hero's stuff, choose one who is owed money over first one on fmon list hero poly'd into a critter without hands could still open tins if a vault guard was killed, his inventory would be dropped at <0,0> throwing gold to/at a vault guard will no longer be treated as an attack non-pit traps created in vault guard's temporary corridor would remain after the location reverted to solid rock using magic to light vault guard's temporary corridor would produce lit solid rock after reversion, and then yield lit corridor if dug out again if hero was blind, killing the vault guard while in his temporary corridor would leave hero encased in solid rock without informing player if hero dragged iron ball into temporary corridor and then killed vault guard, the portion of corridor currently in existence would become permanent on Plane of Water, restrict levitation and flying to air bubbles; elsewhere, restrict them such that they don't work inside solid rock wand/scroll/spell of light now hurts gremlins (lamp/candle light doesn't) ditto for hero in gremlin form (camera too) autosearch finds and transforms secret doors and corridors even while blind, but it wasn't updating the map to show them unless the hero could see fix message typo, "you sold some items inside for N gold piecess" hangup save made during magic mapping or detection performed while underwater could put hero on top of the water after restore fix bug preventing stone-resistant monster w/o gloves from wielding cockatrice items conferring life drain resistance were affected by drain life spell 'a'pply command could be used to recognize undiscovered potions of oil fix replacing an existing bones file in wizard mode [load?y, unlink?n, die?y, save?y, replace?y] for configurations using external file compression theft of worn armor with wear/unwear delay would interfere with completion of wearing or unwearing some other armor which also imposed a delay (disrupted wear attempt for +N helm of brilliance would result in loss of N points of Int and Wis; gauntlets of dexterity had similar problem) #sit while swallowed would give the wrong message alchemical explosion or evaporation only used up one potion instead of all the potions being dipped feedback for reverse-genocide was plural even when just one monster was created fix message given when part of a stack of items in a monster's inventory is being destroyed add "Boing!" message when hero zaps resistant monster with striking/force bolt adjust gaze reflection message when your scales are embedded in your skin adjust turning-to-stone or -slime messages when you have no limbs wizard mode ^F on Plane of Water marked portal as seen but didn't display it magic mapping now displays furniture in preference to known or remembered traps or objects and known traps in preference to remembered objects restrictions on diagonal movement were ignored when crawling out of water when using magic whistle, prevent steed from being affected (trap interaction) declining to attack a peaceful monster via movement used up nutrition even though no action took place declining to attack a peaceful monster via kicking woke nearby monsters and scuffed engraving at hero's location even though no action took place make hero be immune from stinking cloud damage during successful prayer very fast hero would sometimes take two consecutive moves with very fast monsters then getting two moves, instead of interleaving the activity when a monster zapped by polymorph drops inventory because of its new form, don't let that same zap hit the dropped item(s) entering an untended shop while blind gave an inappropriate message engraving feedback about partial text when weapon became too dull to finish was lacking sentence-ending period impossible() might display inaccurate feedback after updating paniclog fix crash which occurred if hero was teleported onto a sink while busy putting on or taking off levitation boots fix "object lost" panic (or even crash) when dropping multiple items while levitating and a lit potion of oil explodes and destroys some inventory fix "object_is_local" panic when saving bones after hero is killed by explosion produced by dropped or thrown lit potion of oil gold dropped on altar by hero wouldn't stack with gold dropped there by monster if lava burns up the player's water walking boots, the player falls in the messages for lava burning items up are always printed fix used-up magic trap trying to hit steed. messages are now printed when objects on the ground are eroded object erosion now always identifies fooproof objects grease protects from all types of erosion all sources of erosion now affect objects the same way passive attacks no longer erode armor covered by other armor dipping a fooproof item into acid no longer forgets that it's fooproof dipping a container into uncursed water now gets its contents wet sanitize petnames and fruit to prevent escape codes data.base "bat" overrode later "combat" entry data.base "gelatinous cube" and "jack boot" have their own entries data.base "vampire bat" matched twice; use the bat entry data.base dagger attribution started with spaces instead of tabs remove 'if (Deaf)' guards preceding You_hear which already checks deafness use a menu to loot multiple containers do_look() in post-3.4.3 used glyph prior to setting it in pager.c charge for a boulder that fills a pit in shop abuse wisdom in keeping with Rider eating message message inconsistency: death message "swallowed whole" was preceded by "You bite into" improve the messaging when a monster you can't see is causing an obstruction add option mention_walls, which gives feedback when bumping against a wall fix invalid pointer dereference in morguemon if ndemon returns NON_PM after object loss through polyshudder don't get left hiding under nothing if you're polymorphed into a hider show object symbols in menu headings in menus where those object symbols act as menu accelerators, toggleable via "menu_objsyms" option show t-shirt text at end of game inventory disclose hitting with a polearm remembers the position of the last monster you hit add messages for trying to pick up some terrain features boomerang makes noise when hitting a sink non-pet rust monsters would eat rust-proofed non-digestibles but ignore those non-digestibles otherwise kicking a grave may topple the gravestone allow showing legal positions for stinking cloud, jumping and polearms when asked for a location cloned creatures (of any type) don't deathdrop items pudding corpses behave somewhat differently than before mithril armor should have silver color lichen corpse is an acid indicator camera may contain a picture-painting demon some monsters can eat through iron bars inaccessible niches occasionally have iron bars in front sinks may teleport or polymorph shopkeepers give honorifics to vampires and elves when commands (D, A, object identify) mix object class filtering with BUCX filtering, take the intersection rather than the union (so ?B picks blessed scrolls rather than all scrolls plus blessed everything) bmask is stored with the objects on the Plane of Water to prevent segfault engraving on drawbridge with wand of digging should produce appropriate message instead of referring to gravel engraving Elbereth is less efficient as protection scare monster scroll now provides a better effect monsters without hands can no longer pick up piles of objects (with certain exceptions) uncursed enchant weapon now correctly fixes erosion scroll of earth messages cleaned up long worms can no longer be leashed the chest in the Castle containing the wishing wand can never be trapped the vibrating square is now a trap mimics wouldn't take on the form of "strange object" add an option to prevent omitting the uncursed status from inventory show prices when walking over the shop merchandise you shouldn't see Sting glow light blue if you're blind when jumping, bumping into something is noisy flesh golems hit by electricity healed by wrong amount fleeing monsters couldn't use stairs that lead to different dungeon branch casting spell of protection when previous casting(s) hadn't time out yet miscalculated the new AC increment remaining monsters continued to move after hero conceptually left the level when a monster knocked him onto a level-changing trap (this bug made it be feasible--but not practical--to level teleport with the Amulet) #turn for non-priest/non-knight attempts to cast "turn undead" spell, but was forcing the spell to target self rather than choose a direction potions of gain energy are more useful for recovering hero's spell energy spellcasting attempt of any spell while stunned now always fails spellcasting attempt of expired spell while confused will increase confusion duration rather than replace it add ways to get out of inaccessible niches in one of the minetown layouts Platform- and/or Interface-Specific Fixes ----------------------------------------- FreeBSD: compilation problems on FreeBSD 6.1 linux: compile support for TIOCGWINSZ by default smartphone: do not translate input when command helper is hidden (fixes Motorola Q keyboard bug) smartphone: new keypad layouts smartphone: wizard mode command layout smartphone: option to feed arbitrary text as a command to nethack core tty: when loading user's run-time configuration, explicitly negating one of {DEC,IBM,MAC}graphics options after enabling another of them switched to regular ASCII and left the earlier option inaccurately set to "on" tty: various bugfixes for very wide and/or tall screens tty+GOLDOBJ: dropping or looting by menu wouldn't honor a count for gold tty: fix crashing when a location has more than 32k items tty: fix segfault when MD termcap is not defined tty: do not cut off statuslines at 80 characters for wider term tty: prevent accidental escapes from string entries tty: hilight object piles unix: remove use of parentheses in nethack man page usage that confused a man page conversion tool unix: new -wwindowtype option unix: don't clobber old level files if 2nd hangup/disconnect occurs while reconnected user is responding to the "destroy old game?" prompt unix/Qt: saved games were not found if nethack was built with prefixes in use unix,vms: allow digits after first character in name at "Who are you?" prompt unix: implement fcntl(2) locking on systems that can handle it vms: the DLB configuration could fail to build if a file without a dot in its name happened to match a logical name Windows: starting a game with nethack.exe (tty) and saving, then restoring and finishing with nethackW.exe (win32) would display the high scores output in a series of popup windows, one for each line of text Windows, probably MSDOS and OS/2: attempting to use very first false rumor for cookie fortune or random engraving could produce garbled text when rumors.tru had CR+LF line ends instead of Unix-style LF lines #if CLIPPING: during teleport or hurtle, re-clip the map immediately instead of waiting until hero's next move winCE: disable processing of double-click messages if the first click causes map to scroll winCE: help text windows close immediately after open (unhandled WM_KEYDOWN in mhtext.c) winCE: correct coordinates used by action button winCE: wrap/unwrap text option for text windows winCE: hardware keyboard detection winCE: hide keypad when hardware keyboard is present winCE: backport message window highlighting from winnt port winCE: new icon with recommended image sizes pocketpc: menu window closes on up/down keys from first/last position win32gui: better handling of "more" prompt for messages that would have scrolled off the window win32gui: set correct checkmark on "Lock Windows" menu item on startup win32gui: redraw message window on resizing (it does not update properly otherwise) win32gui: fixed copy/paste error in read registry settings function win32gui: improved calculation of the size of the menu window win32gui: made auto-arrange windows on/off option (it was reset automatically which was unintuitive and in some cases annoying win32gui: fix a possible crash with AltGr-4 WM_KEYDOWN handling win32gui: use whatever alternate tile set is loaded in the menus win32tty: prevent early error messages from flashing by too fast and not seen win32tty: work around problem where display symbols were wrong or unrecognizable on systems where the default language for non-Unicode programs was not set to "US English" - courtesy Ray Chason win32tty: work around problem where some characters did not show up if the console code page was other than 437 X11: support dynamic switching of map mode via tiled_map option X11: added support for hilite_pet to text map mode X11: ensure vertical scrollbar shows up in text display windows X11: fix typo in mouse click sanity check; result might have pointed to spurious location after window resizing X11: use a plus sign to mark piles of objects platforms that support hangup: SAFERHANGUP to avoid losing objects in transit between lists when hangup occurs, and also avoid cheats due to well-timed hangups to stop a long melee build-from-source: dlb utility can handle arbitrary number of files General New Features -------------------- when you're teetering on the edge of a pit you can use '>' to enter the pit when you're flying over a pit you can use '>' to enter the pit when asked for a direction, a response of '?' yields help and then asks again when adding an item to inventory, try to stack it with the quiver slot before trying against other carried objects #adjust can be used to split an inventory stack cockatrice meat has a distinct flavor to some wish request for " armor" will match item named " mail" Fire Brand and Frost Brand have a chance to avoid taking rust damage support ^R (and ^L in numpad mode) to request display repaint during direction choosing and location choosing prompting modes intelligent pets will use keys to unlock doors destroyed drawbridge leaves some iron chains give feedback when a nearby monster grows into a stronger form familiars are now created without any starting inventory using the 'f' command when quiver is empty will fill quiver with player's response to the "what to throw?" prompt breaking a wand with the apply command has a chance to wrest an extra charge burying a punishment ball no longer ends your punishment #tip command (with M-T shortcut) to empty a container's contents onto floor add clicklook option to allow looking at things on the display by clicking right mouse button when floating mouse pointer over them Izchak's lighting store is now able to stock oil for your lamp provide core support for saving of message history in save file the following actions can now be continued after save/restore: digging, eating, studying, removing armor hero-created and monster-created ice will eventually melt away extend Warning to include ice danger wishing for particular variety of tin contents (deep fried, broiled, etc.) debug-mode wishing for random monster(s) via '*' debug-mode viewing of fully identified object descriptions without actually identifying the objects health-food store that stocks monk-appropriate foods in mine town when monk give more information about your attributes in debug mode polywarn to give intrinsic monster detection of limited species while poly'd rocks can skip on water sometimes allowing them to pass over water creatures vampires can now shapeshift into bats and fog clouds; the latter can be done at will to slip through locked doors shapeshifted vampire will transform back to vampire form after you defeat it and continue to fight in its native form container lknown flag for locked/unlocked/broken awareness container cknown flag for container content awareness plname is stored in the save file on all platforms now introduce support for negation of role, race, align, gender values to eliminate them from random selection and the pick list of startup choices some intelligent pets will avoid cannibalism keep track of which monsters were cloned from other monsters cloned and revived monsters become worth fewer points than ordinary ones number_pad:3 run-time option to use inverted phone keypad layout for movement number_pad:-1 to swap function of y and z keys; z to move NW, y to zap wands display spell retention information in the spell menu tame ghouls can eat old eggs new effect for reading a scroll of light while confused allow digging an adjacent pit with wand of digging while trapped in a pit #terrain command to show unobstructed view of map (w/o mons, objs, traps) digging can activate or disarm some types of traps some monsters can eat tins in addition to corpses to cure some ailments add ability to sort the list when viewing known spells with '+' command describe magic cancellation from worn armor in enlightment/end-of-game feedback disclose half physical and/or spell damage in enlightment/end-of-game feedback rephrase see invisibility enlightenment feedback when unable to see at all add atmospheric sound messages for temples sometimes give announcement message when monsters teleport to hero's vicinity obsolete config file keywords: GRAPHICS, OBJECTS, TRAPS, EFFECTS deprecated options: IBMGraphics, DECGraphics, boulder new options: symset, roguesymset for choosing a symbol set from symbols file new config file keyword: SYMBOLS for overriding character symbol values by name opening magic frees from bear traps and webs, activates trap doors closing magic activates bear traps and webs locking converts a hole into a trap door; striking does the opposite lembas and cram never rot unless cursed multiple squeaks for squeaky boards include time, user ID, and play mode in paniclog entries add oracle and rumor regarding priestly donations anti-magic traps have alternate effect on targets who have magic resistance the Amulet can be offered to Moloch javelins and spears now share the same weapon skill all stackable weapons are capable of being thrown/shot for multi-shot volleys worm teeth and crysknives have become stackable improved container interface acid can destroy iron bars OPTIONS=playmode:normal|explore|debug to choose mode without command-line score bonus for ascending is reduced or denied for changing alignment player can give a monster class when asked for type of monster to poly into likewise when asked about type for #monpolycontrol both controlled self-polymorph and #monpolycontrol accept ESC, "*" or "random" when asking for type of monster; ESC aborts #polyself command scroll of taming/spell of charm monster now gives some feedback doppelgangers can take on the shape of alternate roles' quest guardians pile_limit option to control when to switch to "there are objects here" vs listing objects on floor when hero goes over objects while moving some monsters will use fire to prevent selves being turned into green slime add `#vanquished' debug mode command C and #name commands are now same and use menu to choose monster vs object hallucination provides partial protection against gaze attacks attempting to read "dull" spellbook might cause hero to fall asleep dipping prompt is more precise using F to attack wall/boulder/statue while wielding pick digs/breaks target shapechangers shouldn't receive starting inventory of their initial shape streamline old ^X output and integrate it with enlightenment feedback; new ^X output includes expanded form of abbreviated bottom line info "killed by X" becomes "killed by a chameleon imitating X" when appropriate eating disenchanter corpses is now considered risky make '[' command more precise when poly'd hero has embedded dragon scales/mail fainting while wielding a cockatrice corpse will be fatal Sunsword's light radius depends on its curse/bless state Add M-C and M-R meta-key shortcuts for #conduct and #ride, respectively can now use ESC to cancel out of prompts for playing musical instruments being crowned gives an additional benefit: one extra skill slot/credit chatting to a gecko or shopkeeper while hallucinating gives alternate message mimic posing as door might steal hero's key when [un]locking is attempted polymorphing into a dragon while wearing dragon scale mail will cause that mail to revert to dragon scales flexibility for specifying "detect " vs " detection" when wishing when a sokoban puzzle has been completed (last pit or hole filled in), stop assessing luck penalties and lift most movement restrictions '`' command to show discoveries for one class of objects add "about nethack" to '?' menu as an alternate way to view 'v'+'#version' display version and build information at startup repeatedly setting the fruit option will check to see if fruits have been created, so the user can't easily overflow the maximum this way bones files now include extra data to identify dead hero and reason for death dipping multiple potions in another potion may only dip part of their stack make being inside a stinking cloud (when not immune or resistant) become a major trouble which is fixable by prayer introduce some variation in monster movement rates add database entry for shuriken and make it match throwing star add database entries for fedora, land mine, cream pie, bullwhip, blue jelly, and boomerang change command X to twoweapon toggle pressing @ when cursor positioning moves cursor on top of hero pressing # when cursor positioning toggles automatic description of features under the cursor cursor positioning ignores uninteresting dungeon features allow reading many more items when you're hiding under something a zap downward should not hit that something, while a zap upward should show more explicit reason why player was helpless at death added new hallucinatory-only gods options to create the character blind or nudist moving clouds on the plane of air disclose extinct species alongside genocided ones a tribute to Terry Pratchett some levels in Gehennom now use the old corridor-style maze instead of the new room-style. Beelzebub's level always does this and the "beetle legs" are restored. gnomes will occasionally have a candle stop travel or run when you get hungry 'I' command can accept 'B','U','C',or 'X' as an alternative to normal object class character to show inventory of items known to be blessed,&c debug-mode viewing of object weight prizes on various levels now protected by ?oSM scrolls as well as Elbereth regexes now use system libraries consistently for all pattern-matching systems wet towels deal more damage Platform- and/or Interface-Specific New Features ------------------------------------------------ pcmain: check for dlb_init failure rather than relying on dungeon open failure win32gui: support perm_invent win32gui: menu option to add/remove windows captions win32gui: support for saving/restoring message history win32gui: added menu options "Copy ASCII Screenshot To Clipboard" and "Save ASCII Screenshot To File" win32gui, win32tty: add support for looking for sysconf in %COMMONPROGRAMFILES% first and for user config file in %USERPROFILE% (improves support for multi-login Windows environments) win32tty: support for 'selectsaved' option for menu of existing save files to choose from at game startup tty: add window port routines for saving/restoring message history tty: enhanced role, race, &c selection at start of new game tty: implement : (menu_search) command smartphone: added "Type Cmd" command that allows to type arbitrary commands using phone keypad smartphone: added Q(quiver) command to "Attack" layout smartphone: fixed F command to prompt for direction unix,vms: altmeta option to handle terminals which send "ESC c" for Alt+c tty,win32gui,win32tty: add menucolors MSVC: send debugpline output to 'debug' window to declutter game screen NetHack Community Patches (or Variation) Included ------------------------------------------------- Roderick Schertler's pickup_thrown patch adopt/adapt/extend Malcolm Ryan's Statue Glyphs patch to work for tty and tiles adopt/adapt/improve the Paranoid_Quit patch; default is paranoid_confirm:pray paranoid_confirm:Confirm when requiring "yes" instead of y to confirm, also require explicit "no" to reject paranoid_confirm:quit yes vs y to quit or to enter explore mode paranoid_confirm:die yes vs y to die in explore or wizard mode paranoid_confirm:bones yes vs y to save bones when dying in wizard mode paranoid_confirm:attack yes vs y to attack a peaceful monster paranoid_confirm:pray y to confirm #pray; supersedes prayconfirm paranoid_confirm:Remove always pick from inventory for 'R' and 'T' adopt/adapt/improve Dungeon Overview Aardvark Joe's Extended Logfile Michael Deutschmann's use_darkgray Clive Crous' dark_room sortloot by Jeroen Demeyer and Jukka Lahtinen Auto open doors by Stefano Busti Code Cleanup and Reorganization ------------------------------- removed OVLx section dividers previously used for TRAMPOLINE overlay system move all flags that are system or port specific from flag struct to sysflags struct which is used only if SYSFLAGS is defined all fields in flags struct are unconditionally present monst cham field now a short and uses mons[] index rearrange some monster ordering to follow rule #2 listed at top of monst.c change region player_flags to more appropriate unsigned int instead of boolean remove remains of sync_hunger, which has been ifdef'd out for years new mextra structure housing pointers to mname, egd, epri, eshk, emin, edog consolidate vault.h, epri.h, eshk.h, emin.h and edog.h into new mextra.h new oextra structure housing pointers to oname, omonst, omid, olong, and omailcmd drawing symbols for DECGraphics, IBMGraphics, MACgraphics are now stored in an external symbol file that can be changed without rebuilding new hints-based configuration system allow documentation to be specialized to the options in the game binary add param to winsys ini routines to allow cleaner shifting during startup make STEED, EXP_ON_BOTL, REDO, AUTOPICKUP_EXCEPTIONS, GOLDOBJ, WIZARD, SINKS, REINCARNATION, TOURIST, KOPS and ELBERETH unconditional make SEDUCE compile-time unconditional but still removable through SYSCF clean up some DEBUG conditional code allow defining of generic usernames in config.h instead of hard-coding in role.c set indentation to 4 spaces in most source files nethack-3.6.0/doc/lev_comp.60000664000076400007660000002471312617413107014606 0ustar paxedpaxed.TH LEV_COMP 6 "16 May 1996" .\" NetHack 3.6 lev_comp.6 $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ .UC 4 .SH NAME lev_comp \- NetHack special levels compiler .SH SYNOPSIS .B lev_comp [ .B \-w ] [ .I files ] .PP If no arguments are given, it reads standard input. .SH DESCRIPTION .PP .I Lev_comp is a special level compiler for NetHack version 3.2 and higher. It takes description files as arguments and produces level files that can be loaded by NetHack at runtime. .PP The purpose of this tool is to provide NetHack administrators and implementors with a convenient way for adding special levels to the game, or modifying existing ones, without having to recompile the entire world. .PP The .B \-w option causes .I lev_comp to perform extra checks on the level and display extra warnings, however these warnings are sometimes superfluous, so they are not normally displayed. .SH GRAMMAR .PP .LP .nf .ta +8n +8n +8n +8n file : /* nothing */ | levels ; levels : level | level levels ; level : maze_level | room_level ; maze_level : maze_def flags lev_init messages regions ; room_level : level_def flags lev_init messages rreg_init rooms corridors_def ; level_def : LEVEL_ID ':' string ; lev_init : /* nothing */ | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled ; walled : BOOLEAN | RANDOM_TYPE ; flags : /* nothing */ | FLAGS_ID ':' flag_list ; flag_list : FLAG_TYPE ',' flag_list | FLAG_TYPE ; messages : /* nothing */ | message messages ; message : MESSAGE_ID ':' STRING ; rreg_init : /* nothing */ | rreg_init init_rreg ; init_rreg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_MONSTERS_ID ':' monster_list ; rooms : /* Nothing - dummy room for use with INIT_MAP */ | roomlist ; roomlist : aroom | aroom roomlist ; corridors_def : random_corridors | corridors ; random_corridors: RAND_CORRIDOR_ID ; corridors : /* nothing */ | corridors corridor ; corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec | CORRIDOR_ID ':' corr_spec ',' INTEGER ; corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' ; aroom : room_def room_details | subroom_def room_details ; subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill ; room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill ; roomfill : /* nothing */ | ',' BOOLEAN ; room_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; subroom_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_align : '(' h_justif ',' v_justif ')' | RANDOM_TYPE ; room_size : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_details : /* nothing */ | room_details room_detail ; room_detail : room_name | room_chance | room_door | monster_detail | object_detail | trap_detail | altar_detail | fountain_detail | sink_detail | pool_detail | gold_detail | engraving_detail | stair_detail ; room_name : NAME_ID ':' string ; room_chance : CHANCE_ID ':' INTEGER ; room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos ; secret : BOOLEAN | RANDOM_TYPE ; door_wall : DIRECTION | RANDOM_TYPE ; door_pos : INTEGER | RANDOM_TYPE ; maze_def : MAZE_ID ':' string ',' filling ; filling : CHAR | RANDOM_TYPE ; regions : aregion | aregion regions ; aregion : map_definition reg_init map_details ; map_definition : NOMAP_ID | map_geometry MAP_ID ; map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif ; h_justif : LEFT_OR_RIGHT | CENTER ; v_justif : TOP_OR_BOT | CENTER ; reg_init : /* nothing */ | reg_init init_reg ; init_reg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_PLACES_ID ':' place_list | RANDOM_MONSTERS_ID ':' monster_list ; object_list : object | object ',' object_list ; monster_list : monster | monster ',' monster_list ; place_list : place | place ',' place_list ; map_details : /* nothing */ | map_details map_detail ; map_detail : monster_detail | object_detail | door_detail | trap_detail | drawbridge_detail | region_detail | stair_region | portal_region | teleprt_region | branch_region | altar_detail | fountain_detail | mazewalk_detail | wallify_detail | ladder_detail | stair_detail | gold_detail | engraving_detail | diggable_detail | passwall_detail ; monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate monster_infos ; monster_infos : /* nothing */ | monster_infos monster_info ; monster_info : ',' string | ',' MON_ATTITUDE | ',' MON_ALERTNESS | ',' alignment | ',' MON_APPEARANCE string ; object_detail : OBJECT_ID object_desc | COBJECT_ID object_desc ; object_desc : chance ':' object_c ',' o_name ',' object_where object_infos ; object_where : coordinate | CONTAINED ; object_infos : /* nothing */ | ',' curse_state ',' monster_id ',' enchantment optional_name | ',' curse_state ',' enchantment optional_name | ',' monster_id ',' enchantment optional_name ; curse_state : RANDOM_TYPE | CURSE_TYPE ; monster_id : STRING ; enchantment : RANDOM_TYPE | INTEGER ; optional_name : /* nothing */ | ',' NONE | ',' STRING ; door_detail : DOOR_ID ':' door_state ',' coordinate ; trap_detail : TRAP_ID chance ':' trap_name ',' coordinate ; drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state ; mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION ; wallify_detail : WALLIFY_ID ; ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN ; stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN ; stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN ; portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' string ; teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail ; branch_region : BRANCH_ID ':' lev_region ',' lev_region ; teleprt_detail : /* empty */ | ',' UP_OR_DOWN ; lev_region : region | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; fountain_detail : FOUNTAIN_ID ':' coordinate ; sink_detail : SINK_ID ':' coordinate ; pool_detail : POOL_ID ':' coordinate ; diggable_detail : NON_DIGGABLE_ID ':' region ; passwall_detail : NON_PASSWALL_ID ':' region ; region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled ; altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type ; gold_detail : GOLD_ID ':' amount ',' coordinate ; engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string ; monster_c : monster | RANDOM_TYPE | m_register ; object_c : object | RANDOM_TYPE | o_register ; m_name : string | RANDOM_TYPE ; o_name : string | RANDOM_TYPE ; trap_name : string | RANDOM_TYPE ; room_type : string | RANDOM_TYPE ; prefilled : /* empty */ | ',' FILLING | ',' FILLING ',' BOOLEAN ; coordinate : coord | p_register | RANDOM_TYPE ; door_state : DOOR_STATE | RANDOM_TYPE ; light_state : LIGHT_STATE | RANDOM_TYPE ; alignment : ALIGNMENT | a_register | RANDOM_TYPE ; altar_type : ALTAR_TYPE | RANDOM_TYPE ; p_register : P_REGISTER '[' INTEGER ']' ; o_register : O_REGISTER '[' INTEGER ']' ; m_register : M_REGISTER '[' INTEGER ']' ; a_register : A_REGISTER '[' INTEGER ']' ; place : coord ; monster : CHAR ; object : CHAR ; string : STRING ; amount : INTEGER | RANDOM_TYPE ; chance : /* empty */ | PERCENT ; engraving_type : ENGRAVING_TYPE | RANDOM_TYPE ; coord : '(' INTEGER ',' INTEGER ')' ; region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; .fi .PP .I NOTE: .br Lines beginning with '#' are considered comments. .PP The contents of a "MAP" description of a maze is a rectangle showing the exact level map that should be used for the given part of a maze. Each character in the map corresponds to a location on the screen. Different location types are denoted using different ASCII characters. The following characters are recognized. To give an idea of how these are used, see the EXAMPLE, below. The maximum size of a map is normally 76 columns by 21 rows. .LP .nf .ta +8n +8n +8n \&'-' horizontal wall \&'|' vertical wall \&'+' a doorway (state is specified in a DOOR declaration) \&'A' open air \&'B' boundary room location (for bounding unwalled irregular regions) \&'C' cloudy air \&'I' ice \&'S' a secret door \&'H' a secret corridor \&'{' a fountain \&'\\' a throne \&'K' a sink \&'}' a part of a moat or other deep water \&'P' a pool \&'L' lava \&'W' water (yes, different from a pool) \&'T' a tree \&'F' iron bars \&'#' a corridor \&'.' a normal room location (unlit unless lit in a REGION declaration) \&' ' stone .fi .SH EXAMPLE .PP Here is an example of a description file (a very simple one): .LP .nf .ta +8n +8n +8n MAZE : "fortress", random GEOMETRY : center , center MAP }}}}}}}}} }}}|-|}}} }}|-.-|}} }|-...-|} }|.....|} }|-...-|} }}|-.-|}} }}}|-|}}} }}}}}}}}} ENDMAP MONSTER: '@', "Wizard of Yendor", (4,4) OBJECT: '"', "Amulet of Yendor", (4,4) # a hell hound flanking the Wiz on a random side RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4) MONSTER: 'd', "hell hound", place[0] # a chest on another random side OBJECT: '(', "chest", place[1] # a sack on a random side, with a diamond and maybe a ruby in it CONTAINER: '(', "sack", place[2] OBJECT: '*', "diamond", contained OBJECT[50%]: '*', "ruby", contained # a random dragon somewhere MONSTER: 'D', random, random # 3 out of 4 chance for a random trap in the EAST end TRAP[75%]: random, (6,4) # an electric eel below the SOUTH end MONSTER: ';', "electric eel", (4,8) # make the walls non-diggable NON_DIGGABLE: (0,0,8,8) TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8) .fi .PP This example will produce a file named "fortress" that can be integrated into one of the numerous mazes of the game. .PP Note especially the final, TELEPORT_REGION specification. This says that level teleports or other non-stairway arrivals on this level can land anywhere on the level except the area of the map. This shows the use of the ``levregion'' prefix allowed in certain region specifications. Normally, regions apply only to the most recent MAP specification, but when prefixed with ``levregion'', one can refer to any area of the level, regardless of the placement of the current MAP in the level. .SH AUTHOR .PP Jean-Christophe Collet, David Cohrs. .SH "SEE ALSO" .PP dgn_comp(6), nethack(6) .SH BUGS .PP Probably infinite. Most importantly, still needs additional bounds checking. nethack-3.6.0/doc/lev_comp.txt0000664000076400007660000004253512467321052015262 0ustar paxedpaxed LEV_COMP(6) 1996 LEV_COMP(6) NAME lev_comp - NetHack special levels compiler SYNOPSIS lev_comp [ -w ] [ files ] If no arguments are given, it reads standard input. DESCRIPTION Lev_comp is a special level compiler for NetHack version 3.2 and higher. It takes description files as arguments and produces level files that can be loaded by NetHack at run- time. The purpose of this tool is to provide NetHack administra- tors and implementors with a convenient way for adding spe- cial levels to the game, or modifying existing ones, without having to recompile the entire world. The -w option causes lev_comp to perform extra checks on the level and display extra warnings, however these warnings are sometimes superfluous, so they are not normally displayed. GRAMMAR file : /* nothing */ | levels ; levels : level | level levels ; level : maze_level | room_level ; maze_level : maze_def flags lev_init messages regions ; room_level : level_def flags lev_init messages rreg_init rooms corridors_def ; level_def : LEVEL_ID ':' string ; lev_init : /* nothing */ | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled ; walled : BOOLEAN | RANDOM_TYPE May Last change: 16 1 LEV_COMP(6) 1996 LEV_COMP(6) ; flags : /* nothing */ | FLAGS_ID ':' flag_list ; flag_list : FLAG_TYPE ',' flag_list | FLAG_TYPE ; messages : /* nothing */ | message messages ; message : MESSAGE_ID ':' STRING ; rreg_init : /* nothing */ | rreg_init init_rreg ; init_rreg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_MONSTERS_ID ':' monster_list ; rooms : /* Nothing - dummy room for use with INIT_MAP */ | roomlist ; roomlist : aroom | aroom roomlist ; corridors_def : random_corridors | corridors ; random_corridors: RAND_CORRIDOR_ID ; corridors : /* nothing */ | corridors corridor ; corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec | CORRIDOR_ID ':' corr_spec ',' INTEGER ; corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' ; aroom : room_def room_details May Last change: 16 2 LEV_COMP(6) 1996 LEV_COMP(6) | subroom_def room_details ; subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill ; room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill ; roomfill : /* nothing */ | ',' BOOLEAN ; room_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; subroom_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_align : '(' h_justif ',' v_justif ')' | RANDOM_TYPE ; room_size : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_details : /* nothing */ | room_details room_detail ; room_detail : room_name | room_chance | room_door | monster_detail | object_detail | trap_detail | altar_detail | fountain_detail | sink_detail | pool_detail | gold_detail | engraving_detail | stair_detail ; room_name : NAME_ID ':' string ; room_chance : CHANCE_ID ':' INTEGER May Last change: 16 3 LEV_COMP(6) 1996 LEV_COMP(6) ; room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos ; secret : BOOLEAN | RANDOM_TYPE ; door_wall : DIRECTION | RANDOM_TYPE ; door_pos : INTEGER | RANDOM_TYPE ; maze_def : MAZE_ID ':' string ',' filling ; filling : CHAR | RANDOM_TYPE ; regions : aregion | aregion regions ; aregion : map_definition reg_init map_details ; map_definition : NOMAP_ID | map_geometry MAP_ID ; map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif ; h_justif : LEFT_OR_RIGHT | CENTER ; v_justif : TOP_OR_BOT | CENTER ; reg_init : /* nothing */ | reg_init init_reg ; init_reg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_PLACES_ID ':' place_list May Last change: 16 4 LEV_COMP(6) 1996 LEV_COMP(6) | RANDOM_MONSTERS_ID ':' monster_list ; object_list : object | object ',' object_list ; monster_list : monster | monster ',' monster_list ; place_list : place | place ',' place_list ; map_details : /* nothing */ | map_details map_detail ; map_detail : monster_detail | object_detail | door_detail | trap_detail | drawbridge_detail | region_detail | stair_region | portal_region | teleprt_region | branch_region | altar_detail | fountain_detail | mazewalk_detail | wallify_detail | ladder_detail | stair_detail | gold_detail | engraving_detail | diggable_detail | passwall_detail ; monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate monster_infos ; monster_infos : /* nothing */ | monster_infos monster_info ; monster_info : ',' string | ',' MON_ATTITUDE | ',' MON_ALERTNESS May Last change: 16 5 LEV_COMP(6) 1996 LEV_COMP(6) | ',' alignment | ',' MON_APPEARANCE string ; object_detail : OBJECT_ID object_desc | COBJECT_ID object_desc ; object_desc : chance ':' object_c ',' o_name ',' object_where object_infos ; object_where : coordinate | CONTAINED ; object_infos : /* nothing */ | ',' curse_state ',' monster_id ',' enchantment optional_name | ',' curse_state ',' enchantment optional_name | ',' monster_id ',' enchantment optional_name ; curse_state : RANDOM_TYPE | CURSE_TYPE ; monster_id : STRING ; enchantment : RANDOM_TYPE | INTEGER ; optional_name : /* nothing */ | ',' NONE | ',' STRING ; door_detail : DOOR_ID ':' door_state ',' coordinate ; trap_detail : TRAP_ID chance ':' trap_name ',' coordinate ; drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state ; mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION ; wallify_detail : WALLIFY_ID ; May Last change: 16 6 LEV_COMP(6) 1996 LEV_COMP(6) ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN ; stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN ; stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN ; portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' string ; teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail ; branch_region : BRANCH_ID ':' lev_region ',' lev_region ; teleprt_detail : /* empty */ | ',' UP_OR_DOWN ; lev_region : region | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; fountain_detail : FOUNTAIN_ID ':' coordinate ; sink_detail : SINK_ID ':' coordinate ; pool_detail : POOL_ID ':' coordinate ; diggable_detail : NON_DIGGABLE_ID ':' region ; passwall_detail : NON_PASSWALL_ID ':' region ; region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled ; altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type ; gold_detail : GOLD_ID ':' amount ',' coordinate ; engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string ; May Last change: 16 7 LEV_COMP(6) 1996 LEV_COMP(6) monster_c : monster | RANDOM_TYPE | m_register ; object_c : object | RANDOM_TYPE | o_register ; m_name : string | RANDOM_TYPE ; o_name : string | RANDOM_TYPE ; trap_name : string | RANDOM_TYPE ; room_type : string | RANDOM_TYPE ; prefilled : /* empty */ | ',' FILLING | ',' FILLING ',' BOOLEAN ; coordinate : coord | p_register | RANDOM_TYPE ; door_state : DOOR_STATE | RANDOM_TYPE ; light_state : LIGHT_STATE | RANDOM_TYPE ; alignment : ALIGNMENT | a_register | RANDOM_TYPE ; altar_type : ALTAR_TYPE | RANDOM_TYPE ; May Last change: 16 8 LEV_COMP(6) 1996 LEV_COMP(6) p_register : P_REGISTER '[' INTEGER ']' ; o_register : O_REGISTER '[' INTEGER ']' ; m_register : M_REGISTER '[' INTEGER ']' ; a_register : A_REGISTER '[' INTEGER ']' ; place : coord ; monster : CHAR ; object : CHAR ; string : STRING ; amount : INTEGER | RANDOM_TYPE ; chance : /* empty */ | PERCENT ; engraving_type : ENGRAVING_TYPE | RANDOM_TYPE ; coord : '(' INTEGER ',' INTEGER ')' ; region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; NOTE: Lines beginning with '#' are considered comments. The contents of a "MAP" description of a maze is a rectangle showing the exact level map that should be used for the given part of a maze. Each character in the map corresponds to a location on the screen. Different location types are denoted using different ASCII characters. The following characters are recognized. To give an idea of how these are used, see the EXAMPLE, below. The maximum size of a map is May Last change: 16 9 LEV_COMP(6) 1996 LEV_COMP(6) normally 76 columns by 21 rows. '-' horizontal wall '|' vertical wall '+' a doorway (state is specified in a DOOR declaration) 'A' open air 'B' boundary room location (for bounding unwalled irregular regions) 'C' cloudy air 'I' ice 'S' a secret door 'H' a secret corridor '{' a fountain '\' a throne 'K' a sink (if SINKS is defined, else a room location) '}' a part of a moat or other deep water 'P' a pool 'L' lava 'W' water (yes, different from a pool) 'T' a tree 'F' iron bars '#' a corridor '.' a normal room location (unlit unless lit in a REGION declaration) ' ' stone EXAMPLE Here is an example of a description file (a very simple one): MAZE : "fortress", random GEOMETRY : center , center MAP }}}}}}}}} }}}|-|}}} }}|-.-|}} }|-...-|} }|.....|} }|-...-|} }}|-.-|}} }}}|-|}}} }}}}}}}}} ENDMAP MONSTER: '@', "Wizard of Yendor", (4,4) OBJECT: '"', "Amulet of Yendor", (4,4) # a hell hound flanking the Wiz on a random side RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4) MONSTER: 'd', "hell hound", place[0] # a chest on another random side OBJECT: '(', "chest", place[1] # a sack on a random side, with a diamond and maybe a ruby in it CONTAINER: '(', "sack", place[2] OBJECT: '*', "diamond", contained OBJECT[50%]: '*', "ruby", contained May Last change: 16 10 LEV_COMP(6) 1996 LEV_COMP(6) # a random dragon somewhere MONSTER: 'D', random, random # 3 out of 4 chance for a random trap in the EAST end TRAP[75%]: random, (6,4) # an electric eel below the SOUTH end MONSTER: ';', "electric eel", (4,8) # make the walls non-diggable NON_DIGGABLE: (0,0,8,8) TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8) This example will produce a file named "fortress" that can be integrated into one of the numerous mazes of the game. Note especially the final, TELEPORT_REGION specification. This says that level teleports or other non-stairway arrivals on this level can land anywhere on the level except the area of the map. This shows the use of the ``levre- gion'' prefix allowed in certain region specifications. Normally, regions apply only to the most recent MAP specifi- cation, but when prefixed with ``levregion'', one can refer to any area of the level, regardless of the placement of the current MAP in the level. AUTHOR Jean-Christophe Collet, David Cohrs. SEE ALSO dgn_comp(6), nethack(6) BUGS Probably infinite. Most importantly, still needs additional bounds checking. May Last change: 16 11 nethack-3.6.0/doc/makedefs.60000664000076400007660000001050612536476415014567 0ustar paxedpaxed.TH MAKEDEFS 6 "29 Apr 2010" .\" NetHack 3.6 makedefs.6 $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ .UC 4 .SH NAME makedefs \- NetHack miscellaneous build-time functions .SH SYNOPSIS .B makedefs { .B -o | .B -d | .B -e | .B -m | .B -v | .B -p | .B -q | .B -r | .B -h | .B -z } .P .B makedefs --input .I file .B --output .I file .BI -- command .SH DESCRIPTION .PP .B Makedefs is a build-time tool used for a variety of .BR NetHack (6) source file creation and modification tasks. For historical reasons, .B makedefs takes two types of command lines. When invoked with a short option, the files operated on are determined when .B makedefs is compiled. When invoked with a long option, the .B --input and .B --output options are used to specify the files for the .BI -- command. Each command is only available in one of the two formats. .SH SHORT COMMANDS Upper and lower case are both accepted for the short commands. .TP .B -o Generate .I onames.h. .br .TP .B -d Generate .I data.base. .br .TP .B -e Generate .I dungeon.pdf. The input file .I dungeon.def is passed through the same logic as that used by the .B --grep command; see the .B MDGREP FUNCTIONS section below for details. .br .TP .B -m Generate .I monster.c. .br .TP .B -v Generate .I date.h and .I options file. .br .TP .B -p Generate .I pm.h .br .TP .B -q Generate .IR quest.dat . .br .TP .B -r Generate the .I rumors file. .br .TP .B -s Generate the .I bogusmon , .I engrave and .IR epitaph files. .br .TP .B -h Generate the .B oracles file. .br .TP .B -z Generate .I vis_tab.c and .IR vis_tab.h . .SH LONG COMMANDS .TP .BI --debug Show debugging output. .br .TP .B --make \fR[\fIcommand\fR] Execute a short command. Command is given without preceding dash. .br .TP .BI --input " file" Specify the input .I file for the command (if needed). If the file is - standard input is read. .br .TP .BI --output " file" Specify the output .I file for the command (if needed). If the file is - standard output is written. .br .TP .B --svs \fR[\fIdelimiter\fR] Generate a version string to standard output without a trailing newline. If specified, the delimiter is used between each part of the version string. .br .TP .B --grep Filter the input .I file to the output .IR file . See the .B MDGREP FUNCTIONS section below for information on controlling the filtering operation. .br .TP .B --grep-showvars Show the name and value for each variable known to the grep option. .br .TP .B --grep-trace Turn on debug tracing for the grep function ( .B --grep must be specified as well). .br .TP .BI --grep-define " symbol" Force the value of .I symbol to be "defined." .I Symbol must already be known to .BR makedefs . .br .TP .BI --grep-undef " symbol" Force the definition of .I symbol to be "undefined." .I Symbol must already be known to .BR makedefs . .SH MDGREP FUNCTIONS The .B --grep command (and certain other commands) filter their input, on a line-by-line basis, according to control lines embedded in the input and on information gleaned from the .BR NetHack (6) configuration. This allows certain changes such as embedding platform-specific documentation into the master documentation files. .P Rules: .RS .IP - 4 The default conditional state is printing enabled. .IP - 4 Any line .I NOT starting with a caret (^) is either suppressed or passed through unchanged depending on the current conditional state. .IP - 4 Any line starting with a caret is a control line; as in C, zero or more spaces may be embedded in the line almost anywhere (except immediately after the caret); however the caret must be in column 1. .IP - 4 Conditionals may be nested. .IP - 4 .I Makedefs will exit with an error code if any errors are detected; processing will continue (if it can) to allow as many errors as possible to be detected. .IP - 4 Unknown identifiers are treated as both TRUE and as an error. Note that .BR --undef " or " #undef in the .BR NetHack (6) configuration are different from unknown. .RE .P Control lines: .RS .IP ^^ 4 a line starting with a (single) literal caret .IP ^# a comment .IP ^?\fIID if the .I ID is defined set the conditional state to TRUE .IP ^!\fIID if the .I ID is not defined set the conditional state to TRUE .IP ^: else; invert the conditional state .IP ^. end the most recent conditional .RE .\".SH EXAMPLES .SH AUTHOR The NetHack Development Team .SH "SEE ALSO" .PP .BR dgn_comp (6) nethack-3.6.0/doc/makedefs.txt0000664000076400007660000001114612504242744015231 0ustar paxedpaxedMAKEDEFS(6) MAKEDEFS(6) NAME makedefs - NetHack miscellaneous build-time functions SYNOPSIS makedefs { -o | -d | -e | -m | -v | -p | -q | -r | -h | -z } makedefs --input file --output file --command DESCRIPTION Makedefs is a build-time tool used for a variety of NetHack(6) source file creation and modification tasks. For historical reasons, makedefs takes two types of command lines. When invoked with a short option, the files operated on are determined when makedefs is compiled. When invoked with a long option, the --input and --output options are used to specify the files for the --command. Each command is only available in one of the two formats. SHORT COMMANDS Upper and lower case are both accepted for the short commands. -o Generate onames.h. -d Generate data.base. -e Generate dungeon.pdf. The input file dungeon.def is passed through the same logic as that used by the --grep command; see the MDGREP FUNCTIONS section below for details. -m Generate monster.c. -v Generate date.h and options file. -p Generate pm.h -q Generate quest.dat. -r Generate the rumors file. -h Generate the oracles file. -z Generate vis_tab.c and vis_tab.h. LONG COMMANDS --input file Specify the input file for the command (if needed). If the file is - standard input is read. --output file Specify the output file for the command (if needed). If the file is - standard output is written. --svs [delimiter] Generate a version string to standard output without a trailing newline. If specified, the delimiter is used between each part of the version string. --grep Filter the input file to the output file. See the MDGREP FUNC TIONS section below for information on controlling the filtering operation. --grep-showvars Show the name and value for each variable known to the grep option. --grep-trace Turn on debug tracing for the grep function ( --grep must be specified as well). --grep-define symbol Force the value of symbol to be "defined." Symbol must already be known to makedefs. --grep-undef symbol Force the definition of symbol to be "undefined." Symbol must already be known to makedefs. MDGREP FUNCTIONS The --grep command (and certain other commands) filter their input, on a line-by-line basis, according to control lines embedded in the input and on information gleaned from the NetHack(6) configuration. This allows certain changes such as embedding platform-specific documenta tion into the master documentation files. Rules: - The default conditional state is printing enabled. - Any line NOT starting with a caret (^) is either suppressed or passed through unchanged depending on the current condi tional state. - Any line starting with a caret is a control line; as in C, zero or more spaces may be embedded in the line almost any where (except immediately after the caret); however the caret must be in column 1. - Conditionals may be nested. - Makedefs will exit with an error code if any errors are detected; processing will continue (if it can) to allow as many errors as possible to be detected. - Unknown identifiers are treated as both TRUE and as an error. Note that --undef or #undef in the NetHack(6) con figuration are different from unknown. Control lines: ^^ a line starting with a (single) literal caret ^# a comment ^?ID if the ID is defined set the conditional state to TRUE ^!ID if the ID is not defined set the conditional state to TRUE ^: else; invert the conditional state ^. end the most recent conditional AUTHOR The NetHack Development Team SEE ALSO dgn_comp(6) 4th Berkeley Distribution 29 Apr 2010 MAKEDEFS(6) nethack-3.6.0/doc/nethack.60000664000076400007660000002022412536476415014423 0ustar paxedpaxed.TH NETHACK 6 "6 March 2004" .\" NetHack 3.6 nethack.6 $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ .SH NAME nethack \- Exploring The Mazes of Menace .SH SYNOPSIS .na .hy 0 .B nethack [ .B \-d .I directory ] [ .B \-n ] [ .B \-p .I profession ] [ .B \-r .I race ] [ .B \-[DX] ] [ .B \-u .I playername ] [ .B \-dec ] [ .B \-ibm ] .PP .B nethack [ .B \-d .I directory ] .B \-s [ .B \-v ] [ .B \-p .I profession ] [ .B \-r .I race ] [ .I playernames ] .ad .hy 14 .\" Make sure path is not hyphenated below .hw nethackdir .SH DESCRIPTION .PP .I NetHack is a display oriented Dungeons & Dragons(tm) - like game. The standard tty display and command structure resemble rogue. .PP Other, more graphical display options exist for most platforms. .PP To get started you really only need to know two commands. The command .B ? will give you a list of the available commands (as well as other information) and the command .B / will identify the things you see on the screen. .PP To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Few people achieve this; most never do. Those who have go down in history as heros among heroes - and then they find ways of making the game even harder. See the .I Guidebook section on Conduct if this game has gotten too easy for you. .PP When the game ends, whether by your dying, quitting, or escaping from the caves, .I NetHack will give you (a fragment of) the list of top scorers. The scoring is based on many aspects of your behavior, but a rough estimate is obtained by taking the amount of gold you've found in the cave plus four times your (real) experience. Precious stones may be worth a lot of gold when brought to the exit. There is a 10% penalty for getting yourself killed. .PP The environment variable NETHACKOPTIONS can be used to initialize many run-time options. The ? command provides a description of these options and syntax. (The .B \-dec and .B \-ibm command line options are equivalent to the .B decgraphics and .B ibmgraphics run-time options described there, and are provided purely for convenience on systems supporting multiple types of terminals.) .PP Because the option list can be very long (particularly when specifying graphics characters), options may also be included in a configuration file. The default is located in your home directory and named .nethackrc on Unix systems. On other systems, the default may be different, usually NetHack.cnf. On DOS or Windows, the name is defaults.nh, while on the Macintosh or BeOS, it is NetHack Defaults. The configuration file's location may be specified by setting NETHACKOPTIONS to a string consisting of an @ character followed by the filename. .PP The .B \-u .I playername option supplies the answer to the question "Who are you?". It overrides any name from the options or configuration file, USER, LOGNAME, or getlogin(), which will otherwise be tried in order. If none of these provides a useful name, the player will be asked for one. Player names (in conjunction with uids) are used to identify save files, so you can have several saved games under different names. Conversely, you must use the appropriate player name to restore a saved game. .PP A .I playername suffix can be used to specify the profession, race, alignment and/or gender of the character. The full syntax of the playername that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least the first three letters of the profession (this can also be specified using a separate .B \-p .I profession option). "rrr" are at least the first three letters of the character's race (this can also be specified using a separate .B \-r .I race option). "aaa" are at last the first three letters of the character's alignment, and "ggg" are at least the first three letters of the character's gender. Any of the parts of the suffix may be left out. .PP .B \-p .I profession can be used to determine the character profession, also known as the role. You can specify either the male or female name for the character role, or the first three characters of the role as an abbreviation. .B "\-p \@" has been retained to explicitly request that a random role be chosen. It may need to be quoted with a backslash (\\@) if @ is the "kill" character (see "stty") for the terminal, in order to prevent the current input line from being cleared. .PP Likewise, .B \-r .I race can be used to explicitly request that a race be chosen. .PP Leaving out any of these characteristics will result in you being prompted during the game startup for the information. .PP .PP The .B \-s option alone will print out the list of your scores on the current version. An immediately following .B \-v reports on all versions present in the score file. The .B \-s may also be followed by arguments .B \-p and .B \-r to print the scores of particular roles and races only. It may also be followed by one or more player names to print the scores of the players mentioned, by 'all' to print out all scores, or by a number to print that many top scores. .PP The .B \-n option suppresses printing of any news from the game administrator. .PP The .B \-D or .B \-X option will start the game in a special non-scoring discovery mode. .B \-D will, if the player is the game administrator, start in debugging (wizard) mode instead. .PP The .B \-d option, which must be the first argument if it appears, supplies a directory which is to serve as the playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). This option is usually only useful to the game administrator. The playground must contain several auxiliary files such as help files, the list of top scorers, and a subdirectory .I save where games are saved. .SH AUTHORS .PP Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the original hack, very much like rogue (but full of bugs). .PP Andries Brouwer continuously deformed their sources into an entirely different game. .PP Mike Stephenson has continued the perversion of sources, adding various warped character classes and sadistic traps with the help of many strange people who reside in that place between the worlds, the Usenet Zone. A number of these miscreants are immortalized in the historical roll of dishonor and various other places. .PP The resulting mess is now called NetHack, to denote its development by the Usenet. Andries Brouwer has made this request for the distinction, as he may eventually release a new version of his own. .SH FILES .PP All files are in the playground, normally /usr/games/lib/nethackdir. If DLB was defined during the compile, the data files and special levels will be inside a larger file, normally nhdat, instead of being separate files. .br .DT .ta \w'cmdhelp, opthelp, wizhelp\ \ \ 'u nethack The program itself. .br data, oracles, rumors Data files used by NetHack. .br options, quest.dat More data files. .br help, hh Help data files. .br cmdhelp, opthelp, wizhelp More help data files. .br *.lev Predefined special levels. .br dungeon Control file for special levels. .br history A short history of NetHack. .br license Rules governing redistribution. .br record The list of top scorers. .br logfile An extended list of games .br played. .br xlock.nnn Description of a dungeon level. .br perm Lock file for xlock.dd. .br bonesDD.nn Descriptions of the ghost and .br belongings of a deceased .br adventurer. .br save A subdirectory containing the .br saved games. .SH ENVIRONMENT .DT .ta \w'HACKPAGER or PAGER\ \ \ 'u USER or LOGNAME Your login name. .br HOME Your home directory. .br SHELL Your shell. .br TERM The type of your terminal. .br HACKPAGER or PAGER Replacement for default pager. .br MAIL Mailbox file. .br MAILREADER Replacement for default reader .br (probably /bin/mail or /usr/ucb/mail). .br NETHACKDIR Playground. .br NETHACKOPTIONS String predefining several NetHack .br options. .br In addition, SHOPTYPE is used in debugging (wizard) mode. .SH "SEE ALSO" .PP dgn_comp(6), lev_comp(6), recover(6) .SH BUGS .PP Probably infinite. .PP Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. nethack-3.6.0/doc/nethack.txt0000664000076400007660000002225112504242744015066 0ustar paxedpaxedNETHACK(6) NETHACK(6) NAME nethack - Exploring The Mazes of Menace SYNOPSIS nethack [ -d directory ] [ -n ] [ -p profession ] [ -r race ] [ -[DX] ] [ -u playername ] [ -dec ] [ -ibm ] nethack [ -d directory ] -s [ -v ] [ -p profession ] [ -r race ] [ playernames ] DESCRIPTION NetHack is a display oriented Dungeons & Dragons(tm) - like game. The standard tty display and command structure resemble rogue. Other, more graphical display options exist if you are using either a PC, or an X11 interface. To get started you really only need to know two commands. The command ? will give you a list of the available commands (as well as other information) and the command / will identify the things you see on the screen. To win the game (as opposed to merely playing to beat other peo- ple's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Nobody has achieved this yet; anybody who does will probably go down in history as a hero among heroes. When the game ends, whether by your dying, quitting, or escaping from the caves, NetHack will give you (a fragment of) the list of top scorers. The scoring is based on many aspects of your behav- ior, but a rough estimate is obtained by taking the amount of gold you've found in the cave plus four times your (real) experi- ence. Precious stones may be worth a lot of gold when brought to the exit. There is a 10% penalty for getting yourself killed. The environment variable NETHACKOPTIONS can be used to initialize many run-time options. The ? command provides a description of these options and syntax. (The -dec and -ibm command line options are equivalent to the decgraphics and ibmgraphics run- time options described there, and are provided purely for conve- nience on systems supporting multiple types of terminals.) Because the option list can be very long (particularly when spec- ifying graphics characters), options may also be included in a configuration file. The default is located in your home direc- tory and named .nethackrc on Unix systems. On other systems, the default may be different, usually NetHack.cnf. On DOS or Win- dows, the name is defaults.nh, while on the Macintosh or BeOS, it is NetHack Defaults. The configuration file's location may be specified by setting NETHACKOPTIONS to a string consisting of an @ character followed by the filename. The -u playername option supplies the answer to the question "Who are you?". It overrides any name from the options or configura- tion file, USER, LOGNAME, or getlogin(), which will otherwise be tried in order. If none of these provides a useful name, the player will be asked for one. Player names (in conjunction with uids) are used to identify save files, so you can have several saved games under different names. Conversely, you must use the appropriate player name to restore a saved game. A playername suffix can be used to specify the profession, race, alignment and/or gender of the character. The full syntax of the playername that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least the first three letters of the profession (this can also be specified using a separate -p profession option). "rrr" are at least the first three letters of the char- acter's race (this can also be specified using a separate -r race option). "aaa" are at last the first three letters of the char- acter's alignment, and "ggg" are at least the first three letters of the character's gender. Any of the parts of the suffix may be left out. -p profession can be used to determine the character profession, also known as the role. You can specify either the male or female name for the character role, or the first three characters of the role as an abbreviation. -p @ has been retained to explicitly request that a random role be chosen. It may need to be quoted with a backslash (\@) if @ is the "kill" character (see "stty") for the terminal, in order to prevent the current input line from being cleared. Likewise, -r race can be used to explicitly request that a race be chosen. Leaving out any of these characteristics will result in you being prompted during the game startup for the information. The -s option alone will print out the list of your scores on the current version. An immediately following -v reports on all ver- sions present in the score file. The -s may also be followed by arguments -p and -r to print the scores of particular roles and races only. It may also be followed by one or more player names to print the scores of the players mentioned, by 'all' to print out all scores, or by a number to print that many top scores. The -n option suppresses printing of any news from the game administrator. The -D or -X option will start the game in a special non-scoring discovery mode. -D will, if the player is the game administra- tor, start in debugging (wizard) mode instead. The -d option, which must be the first argument if it appears, supplies a directory which is to serve as the playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). This option is usually only useful to the game administrator. The playground must contain several auxiliary files such as help files, the list of top scorers, and a subdirectory save where games are saved. AUTHORS Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the original hack, very much like rogue (but full of bugs). Andries Brouwer continuously deformed their sources into an entirely different game. Mike Stephenson has continued the perversion of sources, adding various warped character classes and sadistic traps with the help of many strange people who reside in that place between the worlds, the Usenet Zone. A number of these miscreants are immor- talized in the historical roll of dishonor and various other places. The resulting mess is now called NetHack, to denote its develop- ment by the Usenet. Andries Brouwer has made this request for the distinction, as he may eventually release a new version of his own. FILES All files are in the playground, normally /usr/games/lib/nethackdir. If DLB was defined during the com- pile, the data files and special levels will be inside a larger file, normally nhdat, instead of being separate files. nethack The program itself. data, oracles, rumors Data files used by NetHack. options, quest.dat More data files. help, hh Help data files. cmdhelp, opthelp, wizhelp More help data files. *.lev Predefined special levels. dungeon Control file for special levels. history A short history of NetHack. license Rules governing redistribution. record The list of top scorers. logfile An extended list of games played. xlock.nnn Description of a dungeon level. perm Lock file for xlock.dd. bonesDD.nn Descriptions of the ghost and belongings of a deceased adventurer. save A subdirectory containing the saved games. ENVIRONMENT USER or LOGNAME Your login name. HOME Your home directory. SHELL Your shell. TERM The type of your terminal. HACKPAGER or PAGER Replacement for default pager. MAIL Mailbox file. MAILREADER Replacement for default reader (probably /bin/mail or /usr/ucb/mail). NETHACKDIR Playground. NETHACKOPTIONS String predefining several NetHack options. In addition, SHOPTYPE is used in debugging (wizard) mode. SEE ALSO dgn_comp(6), lev_comp(6), recover(6) BUGS Probably infinite. Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. 6 March 2004 NETHACK(6) nethack-3.6.0/doc/recover.60000664000076400007660000000770412536476415014463 0ustar paxedpaxed.TH RECOVER 6 "9 January 1993" .\" NetHack 3.6 recover.6 $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ .UC 4 .SH NAME recover \- recover a NetHack game interrupted by disaster .SH SYNOPSIS .B recover [ .B \-d .I directory ] .I "base1 base2" ... .SH DESCRIPTION .PP Occasionally, a NetHack game will be interrupted by disaster when the game or the system crashes. Prior to NetHack v3.1, these games were lost because various information like the player's inventory was kept only in memory. Now, all pertinent information can be written out to disk, so such games can be recovered at the point of the last level change. .PP The .I base options tell .I recover which files to process. Each base option specifies recovery of a separate game. .PP The .B \-d option, which must be the first argument if it appears, supplies a directory which is the NetHack playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). .PP ^?ALLDOCS For recovery to be possible, .I nethack must have been compiled with the INSURANCE option, and the run-time option .I checkpoint must also have been on. ^: ^?INSURANCE For recovery to be possible, .I nethack must have been compiled with the INSURANCE option (this configuration was), and the run-time option .I checkpoint must also have been on. ^: This configuration of .I nethack was created without support for recovery. ^. ^. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpointing, NetHack also writes out the level entered and the current game state on every level change. This naturally slows level changes down somewhat. .PP The level file names are of the form base.nn, where nn is an internal bookkeeping number for the level. The file base.0 is used for game identity, locking, and, when checkpointing, for the game state. Various OSes use different strategies for constructing the base name. Microcomputers use the character name, possibly truncated and modified to be a legal filename on that system. Multi-user systems use the (modified) character name prefixed by a user number to avoid conflicts, or "xlock" if the number of concurrent players is being limited. It may be necessary to look in the playground to find the correct base name of the interrupted game. .I recover will transform these level files into a save file of the same name as .I nethack would have used. .PP Since .I recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions with game security. Giving ordinary players access to .I recover through setuid or setgid is tantamount to leaving the playground world-writable, with respect to both cheating and messing up other players. For a single-user system, this of course does not change anything, so some of the microcomputer ports install .I recover by default. .PP For a multi-user system, the game administrator may want to arrange for all .0 files in the playground to be fed to recover when the host machine boots, and handle game crashes individually. If the user population is sufficiently trustworthy, .I recover can be installed with the same permissions the .I nethack executable has. In either case, .I recover is easily compiled from the distribution utility directory. .SH NOTES .PP Like .I nethack itself, .I recover will overwrite existing savefiles of the same name. Savefiles created by .I recover are uncompressed; they may be compressed afterwards if desired, but even a compression-using .I nethack will find them in the uncompressed form. .SH "SEE ALSO" nethack(6) .SH BUGS .PP .I recover makes no attempt to find out if a base name specifies a game in progress. If multiple machines share a playground, this would be impossible to determine. .PP .I recover should be taught to use the nethack playground locking mechanism to avoid conflicts. nethack-3.6.0/doc/recover.txt0000664000076400007660000001020412467321052015107 0ustar paxedpaxed RECOVER(6) 1993 RECOVER(6) NAME recover - recover a NetHack game interrupted by disaster SYNOPSIS recover [ -d directory ] base1 base2 ... DESCRIPTION Occasionally, a NetHack game will be interrupted by disaster when the game or the system crashes. Prior to NetHack v3.1, these games were lost because various information like the player's inventory was kept only in memory. Now, all per- tinent information can be written out to disk, so such games can be recovered at the point of the last level change. The base options tell recover which files to process. Each base option specifies recovery of a separate game. The -d option, which must be the first argument if it appears, supplies a directory which is the NetHack play- ground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). For recovery to be possible, nethack must have been compiled with the INSURANCE option, and the run-time option check- point must also have been on. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpointing, NetHack also writes out the level entered and the current game state on every level change. This naturally slows level changes down somewhat. The level file names are of the form base.nn, where nn is an internal bookkeeping number for the level. The file base.0 is used for game identity, locking, and, when checkpointing, for the game state. Various OSes use different strategies for constructing the base name. Microcomputers use the character name, possibly truncated and modified to be a legal filename on that system. Multi-user systems use the (modified) character name prefixed by a user number to avoid conflicts, or "xlock" if the number of concurrent players is being limited. It may be necessary to look in the play- ground to find the correct base name of the interrupted game. recover will transform these level files into a save file of the same name as nethack would have used. Since recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions with game security. Giving ordi- nary players access to recover through setuid or setgid is tantamount to leaving the playground world-writable, with respect to both cheating and messing up other players. For January Last change: 9 1 RECOVER(6) 1993 RECOVER(6) a single-user system, this of course does not change any- thing, so some of the microcomputer ports install recover by default. For a multi-user system, the game administrator may want to arrange for all .0 files in the playground to be fed to recover when the host machine boots, and handle game crashes individually. If the user population is sufficiently trustworthy, recover can be installed with the same permis- sions the nethack executable has. In either case, recover is easily compiled from the distribution utility directory. NOTES Like nethack itself, recover will overwrite existing save- files of the same name. Savefiles created by recover are uncompressed; they may be compressed afterwards if desired, but even a compression-using nethack will find them in the uncompressed form. SEE ALSO nethack(6) BUGS recover makes no attempt to find out if a base name speci- fies a game in progress. If multiple machines share a play- ground, this would be impossible to determine. recover should be taught to use the nethack playground lock- ing mechanism to avoid conflicts. January Last change: 9 2 nethack-3.6.0/doc/tmac.n0000664000076400007660000006102512504751012014006 0ustar paxedpaxed\" @(#)$Id: tmac.n,v 1.4 2002/01/19 13:41:15 michael.allison Exp $ .\" The News macro package .\" .\" This is the macro package that is used to format news documents. It .\" was written because many sites do not have one of the -mm or -ms pack- .\" ages that the documents use. This is NOT compatible with EITHER, but .\" (I hope) will become the standard for all news documents (man pages .\" excepted, since everyone seems to have -man.) .\" .\" This package was written using only the "NROFF/TROFF Users' Guide", .\" and therefore if you can run NROFF/TROFF, you can legitimately use .\" this package. However, because NROFF/TROFF are proprietary programs, .\" I cannot place this package in the public domain. This should not .\" matter, because if you legitimately have NROFF/TROFF, you have the .\" documentation; if not, you can't run off the documentation anyway. .\" .\" This package may be circulated freely with the news documentation; it .\" may not be sold, but is to be distributed with the unformatted news .\" documents. However, the name of the author and the place at which it .\" was written (in the author's own time, of course) are not to be .\" removed from the package regardless of how it is modified or altered. .\" Further, please do not distribute this package if you make any changes .\" because I don't want to get bug reports of macros I haven't written; .\" if you have a goodie you want me to add, send it to me and we'll talk. .\" (I really do like feedback!) I'd really appreciate your cooperation. .\" .\" Author: Matt Bishop .\" Research Institute for Advanced Computer Science .\" Mail Stop 230-5 .\" NASA Ames Research Center .\" Moffett Field, CA 94035 .\" .\" version 1.0 September 28, 1985 mab@riacs.arpa .\" initial version .\" version 1.1 October 25, 1985 mab@riacs.arpa .\" fixed an incredibly obscure footnote bug (that occurred twice in .\" the news documentation!) which put footnoted words on one page .\" and the footnote on the next if the word was in the next-to-last .\" or last line; commented it, and generally cleaned up .\" Version 1.2 October 27, 1985 mab@riacs.arpa .\" Added a few more comments and a check to keep footnotes lined up .\" with the bottom margin. .\" Version 1.3 February 12, 1986 mab@riacs.arpa .\" Added an error check to catch unmatched ef's and ed's .\" Version 1.4 December 29, 1986 mab@riacs.edu .\" Changed footnote for ux, pd, and vx macros and added a string .\" for rg ("Registered Trademark") .\" Version 1.5 January 2, 1989 Matt.Bishop@dartmouth.edu .\" Minor modifications for nroff compatibility .\" Version 1.6 March 15, 1989 Matt.Bishop@dartmouth.edu .\" ..!bear.dartmouth.edu!bishop .\" Fixed a bug in footnote handling (again, sigh ...) This one .\" occurred when the the "fo" trap position was reset just beneath .\" the current line; the footnote overflow trap would kick in and .\" never be closed. .\" .\" .\" ********** .\" these preserve and restore various things .\" they are used to shorten other macros .de yf \" restore fonts .ft \\n(f2 \" previous font .ft \\n(f1 \" current font .. .de yi \" restore indents 'in \\n(i2u \" previous indent 'in \\n(i1u \" current indent .. .de ys \" restore point sizes .ps \\n(s2 \" previous point size .ps \\n(s1 \" current point size .. .de yv \" restore vertical spacings .vs \\n(v2u \" previous vertical spacing .vs \\n(v1u \" current vertical spacing .. .de ya \" restore everything .yf \" restore fonts .yi \" restore indents .ys \" restore point sizes .yv \" restore vertical spacing .. .de zf \" preserve fonts .nr f1 \\n(.f \" current font .ft \" switch to previous font .nr f2 \\n(.f \" previous font .ft \" back to current font .. .de zi \" preserve indents .nr i1 \\n(.iu \" current indent 'in \" switch to previous indent .nr i2 \\n(.iu \" previous indent 'in \" back to current indent .. .de zs \" preserve point sizes .nr s1 \\n(.su \" current point size .ps \" switch to previous point size .nr s2 \\n(.su \" previous point size .ps \" back to current point size .. .de zv \" preserve vertical spacings .nr v1 \\n(.vu \" current vertical spacing .vs \" switch to previous vertical spacing .nr v2 \\n(.vu \" previous vertical spacing .vs \" back to current vertical spacing .. .de za \" save everything .zf \" save fonts .zi \" save indents .zs \" save point sizes .zv \" save vertical spacings .. .\" ********** .\" these actually print the header and footer titles .\" they are defined separately from the "hd" and "fo" macros .\" to make user redefinition easy .de pt \" print header title . \" omit header on first page .if \\n%>1 \{\ ' sp |\\$1u \" move to proper position . ft 1 \" change to default font . ps \\n(ps \" change to default point size . vs \\n(vs \" change to default spacing . tl '\\*(h0'\\*(h1'\\*(h2' \" center title . vs \" restore current vertical spacing . ps \" restore current point size . ft \" restore current font .\} .. .de pf \" print footer title .ft 1 \" change to default font .ps \\n(ps \" change to default point size .vs \\n(vs \" change to default spacing .ie \\n%=1 .tl '\\*(h0'\\*(h1'\\*(h2' \" on first page, print the header here .el .tl '\\*(f0'\\*(f1'\\*(f2' \" on other pages, print the footer .vs \" restore current vertical spacing .ps \" restore current point size .ft \" restore current font .. .\" ********** .\" these are the top of page (header) and bottom of page (footer) macros .\" they don't actually print anything, just call the right macros .de hd \" header -- do top of page processing .if t .if \\n(cm .tl '\(rn''' \" drop cut mark if needed .pt \\n(ttu \" print header .nr fc 0 1 \" init footnote count .nr fs \\n(.pu-\\n(bmu-1u \" if any footnotes, start print here .nr fp 0-\\n(bmu \" reset current footer place .ch fo -\\n(bmu \" reset footer trap .if \\n(dn .fz \" put leftover footnotes st bottom .ya \" restore font, etc. 'sp |\\n(tmu \" move to top of body .ns \" don't allow any more space .. .de fo \" footer -- do bottom of page processing .za \" save font, etc. .rs \" you want motions here .nr dn 0 \" clobber diversion size register .if \\n(fc .fd \" now print the footnotes, if any 'bp \" force out page .. .\" ********** .\" these are the footnote macros .\" here's an overview: .\" Footnotes are processed in environment #1, which is initialized .\" at the bottom of this package. When "fn" is called, nroff/troff .\" switches to this environment. The body of the footnote is saved .\" in the diversion "tf" (for "temporary footnote"), so you will .\" NEVER spring a trap during the first reading of a footnote. When .\" "ef" ("end footnote") is called, the diversion is closed. If .\" this is the first footnote on the page (ie, the number register .\" "fc" is 1), and the footnote height (plus the height of 1 line) .\" crosses the bottom margin, you get the footnoted word on one .\" page and the footnote on the other. In this case we just call .\" "fo" manually (taking case it cannot be re-invoked on the same .\" page!) If this situation does not occur, we just adjust the .\" footer trap's position upwards (we'll get to how far in a min- .\" ute); if this puts the trap above the current line, we reposi- .\" tion the trap just beneath the current line to be sure of trig- .\" triggering it once the current line is forced out. .\" To reposition the footer trap, we proceed as follows. Because .\" the trap may be sprung in the middle of a line, it is possible .\" that the footnote will not fit on the page (regardless of where .\" on the page the footnoted word occurs -- really!) if we move the .\" trap up by the size of the footnote diversion "tf". So, we .\" fudge things a little bit -- for the first footnote on each page .\" we move the footer trap up 1 extra line ("line" being 1v in env- .\" ironment #0). Unless the point size and vertical spacing are .\" increased between the first footnote and the footer trap's being .\" sprung, this will keep the footnotes on the same page as the .\" footnoted word. But as there may be now as much as 1v of space .\" between the footnote and the bottom margin, which looks HIDEOUS, .\" we use the number register "fs" to mark where the footer trap .\" would REALLY go, and just space to it when it comes time to put .\" out the footnotes. .de fd \" dump footnotes .nr gs 1v \" get a measure of 1 line in env #0 .ev 1 \" switch to footnote environment .nr gs +2v \" min of 2 lines of footnotes . \" if the number register ns > 0, . \" the last text line may contain a . \" footnote that is too big to fit; . \" this checks for such a note and . \" if so, forces the footnote into . \" the "fy" diversion that carries . \" it onto the next text page .ie (\\n(nsu>0)&(\\n(gsu>=\\n(.tu) 'sp \\n(gsu \" be sure you can get it down .el .if \\n(fsu>\\n(nlu 'sp \\n(fsu-\\n(nlu \" move to footnote start position 'nf \" don't reprocess footnotes 'in 0 \" don't indent them any more either .tf \" drop text of footnotes .rm tf .if '\\n(.z'fy' .di \" end overflow diversion, if any .nr fc 0 \" re-init footnote count .ev \" return to usual environment .. .de fn \" start footnote . \" look for nested footnotes -- ILLEGAL .ie \\n(if>0 .er "footnote within footnote" .el .da tf \" append footnote to footnote diversion .nr if +1 \" increment level of footnoting .nr fc +1 \" one more footnote on this page .if \\n(fc=1 .nr fp -1v \" The reason for this "fudge factor" . \" is that there is no way to force . \" NROFF/TROFF to invoke a macro at . \" the end of each line. At times, . \" the trap boundary will not match up . \" with the bottom of a line, so the . \" "fo" trap which is set at 2320 may . \" not be triggered until 2340 -- and . \" then the footnote won't fit. This . \" gives some slack so the footnote is . \" more likely to fit. *sigh* .ev 1 \" enter footnote environment .if \\n(fc=1 .fs \" drop separator if first footnote .br \" flush out any previous line in footnote .fi \" process footnote in fill mode .. .de ef \" end footnote .br \" flush out the line in footnote .ie \\n(if<=0 .er "end footnote has no corresponding begin footnote" .el \{\ . nr if -1 \" decrement level of footnoting . nr fg 2v \" remember this for repositioning fo . ev \" back to usual environment . if \\n(if=0 \{\ . di \" end of footnote proper . nr fp -\\n(dnu \" "fo" will be moved at least up this far . nr fs -\\n(dnu \" increase size of footnote . ch fo \\n(fpu \" reposition "fo" trap (first guess) . \" the first part of the "ie" clause . \" is taken in the special case . \" described above . ie (\\n(fc=1)&((\\n(nlu+1v+\\n(fgu)>=(\\n(.pu-\\n(bmu)) \{\ . nr ns \\n(dnu \" suppress footnote separator . \" since this footnote contains it . \" keep "fo" from being invoked twice . ch fo \\n(.pu+1i . fo \" force the page out AT ONCE . nr ns 0 \" re-enable footnote separator . \} . \" footnote won't fit completely . \" invoke the footer trap but . \" don't worry about the footnote . \" separator (it's already there) . el .if (\\n(nlu+1v)>=(\\n(.pu+\\n(fpu) \{\ . \" as before we must reposition the . \" "fo" trap to prevent "fo" from . \" being invoked twice . ch fo \\n(.pu+1i . fo \" force the page out AT ONCE . \} . \} .\} .. .de fs \" drop footnote separator . \" only if not already dropped .if \\n(ns=0 \l'1i' .nr ns 0 \" in case footnotes are over 1 page long .. .de fx \" process footnote overflow .if \\n(fc .di fy \" stuff them in the right place .. .de fz \" deposit footnote overflow .fn \" treat it as a footnote .nf \" it's already been processed .in 0 \" and indented .fy \" "fx" put it here .ef \" end the footnote .. .\" ********** .\" the ones after here are user-invoked (like "fn" and "ef" above) .\" title, author, etc. .de mt \" main title \& .sp |\\n(mtu \" space .ft 3 \" in bold .ps \\n(ps+2p \" large point size and .vs \\n(vs+2p \" vertical spacing .ce 1000 \" center the title .nr t2 1 \" space it .. .de au \" author .nr t2 0 \" spacing here .sp 2v \" space .ft 2 \" in italics .ps \\n(ps \" usual point size and .vs \\n(vs \" vertical spacing .ce 1000 \" center the name(s) .. .de ai \" author's institution .if \\n(t2 .sp 2v \" space after a title .nr t2 0 \" institution .ft 2 \" in italics .ps \\n(ps \" usual point size and .vs \\n(vs \" vertical spacing .ce 1000 \" center the name(s) .. .de bt \" begin text macro .nr t2 0 \" hold it here .nr it +1 \" mark as called .ce 0 \" end any centering .sn 3v \" a little bit of space .. .\" paragraph .de si \" start indented section .nr lo \\n(lm \" remember the current level .nr lm +1 \" go to the next level .ie '\\$1'' .nr l\\n(lm \\n(l\\n(lo+5n \" if no arg, indent 5n .el .nr l\\n(lm \\$1n \" otherwise, indent that much .. .de ei \" end indent .nr lm -1 \" down one level .if \\n(lm<0 .nr lm 0 \" make sure you don't go too far .. .de pg \" plain old paragraph .if !\\n(it .bt \" end the title and such .sn \\n(pdu \" inter-paragraph spacing .ft 1 \" reset a few things (paranoia) . \" these ONLY if not in footnote .ie \\n(if=0 \{\ . ps \\n(ps \" reset point size . vs \\n(vs \" reset vertical spacing . ne 1v+\\n(.Vu \" slightly more than 1 line .\} .el \{\ . ps \\n(ps-2p \" reset point size . vs \\n(vs-2p \" reset vertical spacing .\} .in \\n(l\\n(lmu \" stop any indenting .ce 0 \" stop any centering .if !'\\$1'L' .if !'\\$1'l' .ti +\\n(piu \" indent the sucker .. .de lp \" labelled paragraph .pg l \" reset paragraph .if \\n(.$>1 .nr li \\$2n \" if indent given use it .in +\\n(liu \" indent for paragraph .ti -\\n(liu \" force first line NOT to indent .ta +\\n(liu \" for the label \&\\$1\t\c .if \\w'\\$1'u>=(\\n(l\\n(lmu+\\n(liu) .br \" don't overwrite .. .\" The following two macros (hu & hn) have been modified for ELM usage. .\" If the macros have text as part of the macro call, the text will be .\" increased in size by two points. After printing the text, the font .\" will be returned to normal, otherwise the font will be left bold. .\" .\" section .de hu \" header, unnumbered . \" format: .hu [text] .if !\\n(it .bt \" end the title and such .br \" force out previous line .b .ie \\n(hP .ps \\n(hP .el .ps \\n(ps .ie \\n(hv .vs \\n(hv .el .vs \\n(vs .in \\n(l\\n(lmu \" stop any indenting .sn \\n(hsu \" inter-section spacing .ne 3v+\\n(.Vu \" slightly more than 3 lines .fi \" process the text, too .if \\n(.$>=1 \{\ .ps +2 \\$1 .\} .if \\n(.$>=2 \\$2 .if \\n(.$>=3 \\$3 .if \\n(.$>=4 \\$4 .if \\n(.$>=5 \\$5 .if \\n(.$>=6 \\$6 .if \\n(.$>=7 \\$7 .if \\n(.$>=8 \\$8 .if \\n(.$=9 \\$9 .if \\n(.$>=1 \{\ .ps -2 .br .ft 1 .\} .. .de hn \" header, numbered . \" format: .hn [level] [text] .if !\\n(it .bt \" end the title and such .br \" force out previous line .b .ie \\n(hP .ps \\n(hP .el .ps \\n(ps .ie \\n(hv .vs \\n(hv .el .vs \\n(vs .in \\n(l\\n(lmu \" stop any indenting .sn \\n(hsu \" inter-section spacing .ne 3v+\\n(.Vu \" slightly more than 3 lines .fi \" process the text, too .ie !'\\$1'' .nr hn \\$1 .el .nr hn 1 .ie \\n(hn>0 .nr hn -1 .el .nr hn 0 .ie \\n(hn=0 \{\ . nr h0 +1 \" add 1 to main section header . nr h1 0 \" zap remaining section numbers . nr h2 0 \" zap remaining section numbers . nr h3 0 \" zap remaining section numbers .ie \\n(.$>=2 \{\ .ps +2 \\n(h0. .ps -2 .\} .el \\n(h0. .\} .el .ie \\n(hn=1 \{\ . nr h1 +1 \" add 1 to the section header . nr h2 0 \" zap remaining section numbers . nr h3 0 \" zap remaining section numbers .ie \\n(.$>=2 \{\ .ps +2 \\n(h0.\\n(h1. .ps -2 .\} .el \\n(h0.\\n(h1. .\} .el .ie \\n(hn=2 \{\ . nr h2 +1 \" add 1 to the section header . nr h3 0 \" zap remaining section numbers .ie \\n(.$>=2 \{\ .ps +2 \\n(h0.\\n(h1.\\n(h2. .ps -2 .\} .el \\n(h0.\\n(h1.\\n(h2. .\} .el \{\ . nr h3 +1 \" add 1 to the section number .ie \\n(.$>=2 \{\ .ps +2 \\n(h0.\\n(h1.\\n(h2.\\n(h3. .ps -2 .\} .el \\n(h0.\\n(h1.\\n(h2.\\n(h3. .\} .if \\n(.$>=2 \{\ .ps +2 \\$2 .\} .if \\n(.$>=3 \\$3 .if \\n(.$>=4 \\$4 .if \\n(.$>=5 \\$5 .if \\n(.$>=6 \\$6 .if \\n(.$>=7 \\$7 .if \\n(.$>=8 \\$8 .if \\n(.$>=9 \\$9 .if \\n(.$>=2 \{\ .br .ft 1 .ps -2 .\} .. .\" displays (no floats, thank God!) .de sd \" start display . \" look for nested displays -- ILLEGAL .ie \\n(id>0 .er "display within display" .el \{\ . ie '\\$1'c' .nr sf 1 \" center the sucker . el .nr sf 0 \" don't center it .\} .sn \\n(pdu \" a little bit of space .ev 2 \" switch to display environment .nf \" what you type is what you get .if \\n(id=0 .di dd \" start saving text .rs \" don't eat leading space .nr id +1 \" increment level of display .. .de ed \" end display .br \" flush line .ie \\n(id<=0 .er "end display has no corresponding begin display" .el \{\ . nr id -1 \" decrement level of display . if \\n(id=0 \{\ . di \" end diversion . fi \" resume filling . in -\\n(piu \" dedent . ev \" pop environment . ne \\n(dnu \" be sure you have room . nf \" don't reprocess display . rs \" don't eat leading space . zi \" save indents . ie \\n(sf .in (\\n(llu-\\n(dlu)/2u \" center on the line length . el .in +\\n(piu \" indent the sucker . dd \" drop display . yi \" restore indents . \} .\} .fi \" resume filling .sn \\n(pdu \" a little bit of space .. .\" ********** .\" fonts -- if argument(s), apply only to first .de b \" bold (font 3) .ie \\n(.$>0 \\&\\$3\\f3\\$1\\fP\\$2 .el .ft 3 .. .de i \" italics (font 2) .ie \\n(.$>0 \\&\\$3\\f2\\$1\\fP\\$2 .el .ft 2 .. .de r \" roman (font 1) .ft 1 \" just restore it .. .de bi \" bold italics (embolden font 2) \\&\\$3\c \\kb\\f2\\$1\\fP\\h'|\\nbu+2u'\\f2\\$1\\fP\\$2 .. .\" ********** .\" point sizes -- if argument(s), apply only to first .de sm \" reduce point size by 2 .ie \\n(.$>0 \\&\\$3\\s-2\\$1\\s0\\$2 .el .ps -2 .. .de is \" increase point size by 2 .ie \\n(.$>0 \\&\\$3\\s+2\\$1\\s0\\$2 .el .ps +2 .. .de nl \" return to normal size .ps \\n(ps \" just reset the point size .. .\" ********** .\" handy force space/inhibit more space macros .de sn \" space, then turn on nospace mode .sp \\$1 \" space .ns \" ignore any more space requests .. .de sr \" force out space .rs \" turn on spacing mode .sp \\$1 \" space .. .\" ********** .\" end of text and error macros .de et \" end of text macro . \" this: (1) flushes rest of line . \" (2) trips the footer, taking . \" care of footnotes .sp \\n(.pu . \" check for open displays or footnotes .if \\n(id>0 .er "unfinished display" .if \\n(if>0 .er "unfinished footnote" . \" this one means an -mn bug (*sigh*) .if !'\\n(.z'' .er "diversion \\n(.z not closed" .. .de er \" print error message . \" flag it as an error .ds ws "** ERROR ** . \" if you have it, give the file name .if !'\\*(.f'' .as ws " file \\*(.f, . \" put out the line number .as ws " line \\n(.c . \" and finally the error message .tm \\*(ws: \\$1 .. .\" ********** .\" macros in this section are VERY specific to the news documentation .de pa \" protocol appellation (darn names!) \\&\\$3\\f2\\$1\\fP\\$2 .. .de ng \" news group name \\&\\$3\\f3\\$1\\fP\\$2 .. .de cn \" computer name \\&\\$3\\f2\\$1\\fP\\$2 .. .de hf \" header field \\&\\$3\\*(lq\\$1\\*(rq\\$2 .. .de cf \" contents of field \\&\\$3\\*(lq\\$1\\*(rq\\$2 .. .de qc \" quote control char (command) \\&\\$3\\f3<\\s-2\\$1\\s0>\\fP\\$2 .. .de qp \" quote printing char (command) \\&\\$3\\f3\\$1\\fP\\$2 .. .de op \" option \\&\\$3\\f3\\$1\\fP\\$2 .. .\" ********** .\" trademarked names .de pd \" print "PDP-11" .ie \\n(p1 \\&\\$2\\s-1PDP\\s0-11\\$1 .el \{\ . nr p1 +1 \" mark footnote as dropped \\&\\$2\\s-1PDP\\s0-11\\*(rg\\$1 . fn \" put out the footnote \\&\\*(rgPDP-11 is a registered trademark of Digital Equipment Corporation. . ef \" short and sweet ... .\} .. .de ux \" print "UNIX" .ie \\n(ux \\&\\$2\\s-1UNIX\\s0\\$1 .el \{\ . nr ux +1 \" mark footnote as dropped \\&\\$2\\s-1UNIX\\s0\\*(rg\\$1 . fn \" put out the footnote \\&\\*(rgUNIX is a registered trademark of AT&T. . ef \" short and sweet ... .\} .. .de vx \" print "VAX" .ie \\n(vx \\&\\$2\\s-1VAX\\s0\\$1 .el \{\ . nr vx +1 \" mark footnote as dropped \\&\\$2\\s-1VAX\\s0\\*(rg\\$1 . fn \" put out the footnote \\&\\*(rgVAX is a trademark of Digital Equipment Corporation. . ef \" short and sweet ... .\} .. .\" ********** .\" set up string and number registers . \" set up for the date .if \n(mo=1 .ds mo January .if \n(mo=2 .ds mo February .if \n(mo=3 .ds mo March .if \n(mo=4 .ds mo April .if \n(mo=5 .ds mo May .if \n(mo=6 .ds mo June .if \n(mo=7 .ds mo July .if \n(mo=8 .ds mo August .if \n(mo=9 .ds mo September .if \n(mo=10 .ds mo October .if \n(mo=11 .ds mo November .if \n(mo=12 .ds mo December .nr Yr \n(yr+1900 .ds dy "\*(mo \n(dy, \n(Yr .if \n(dw=1 .ds dw Sunday .if \n(dw=2 .ds dw Monday .if \n(dw=3 .ds dw Tuesday .if \n(dw=4 .ds dw Wednesday .if \n(dw=5 .ds dw Thursday .if \n(dw=6 .ds dw Friday .if \n(dw=7 .ds dw Saturday . \" NROFF dependencies .if n \{\ . \" string registers . ds rg (R) . ds lq "" . ds rq "" . ds f1 "\*(dy . \" number registers . nr hs 1v \" space before section header . nr pd 1v \" inter-paragraph spacing . nr bm 1.0i \" height of bottom margin .\} . \" NROFF dependencies .if t \{\ . \" string registers . ds rg \\u\\s-2\\(rg\\s0\\d . ds lq `` . ds rq '' . \" number registers . nr hs 1v \" space before section header . nr pd 0.3v \" inter-paragraph spacing . nr bm 1.0i+1v \" height of bottom margin (wacky laser) .\} . \" these are the same for [NT]ROFF .ds dg \(dg .ds vr "News Version B2.11 .ds pv "News macros 1.5 .ds h1 - % - .nr bt 0.5i+1v \" bottom of page to footer .nr cm 0 \" no cut marks .nr fc 0 1 \" init footnote count .nr fl 5.5i \" footnote line length .nr fp 0-\n(bmu \" fo macro trap location .nr h0 0 \" init section header level 0 .nr h1 0 \" init section header level 1 .nr h2 0 \" init section header level 2 .nr h3 0 \" init section header level 3 .nr id 0 \" 1 in display .nr if 0 \" 1 in keep .nr it 0 \" 1 when beyond title, etc. .nr li 5n \" indent for labelled paragraph .nr ll 6.5i \" line length .nr lm 0 \" left margin .nr l0 0 \" first indent level .nr mt 1.5i+1v \" title goes down this far .nr pi 5n \" regular paragraph indent .nr po 1.0i \" page offset .nr ps 10 \" point size .nr tm 1.0i \" height of top margin .nr tt 0.5i-0.5v \" top of page to header .nr p1 0 \" no PDP-TM message yet .nr ux 0 \" no UNIX-TM message yet .nr vx 0 \" no VAX-TM message yet .nr vs 12 \" vertical spacing .\" set things up .\" DSINC changes for XROFF .nr f1 1 .nr f2 1 .nr s1 10 .nr s2 10 .nr v1 12 .nr v2 12 .ps 10 .vs 12 .\" DSINC end changes for XROFF .po \n(pou \" set page offset .ps \n(ps \" set previous, current .ps \n(ps \" point sizes .vs \n(vs \" set previous, current .vs \n(vs \" vertical spacings .ll \n(llu \" set line length .lt \n(llu \" set title line length .ev 1 \" *** footnote environment .ps \n(ps-2p \" set previous, current .ps \n(ps-2p \" point sizes .vs \n(vs-2p \" set previous, current .vs \n(vs-2p \" vertical spacings .ll \n(flu \" set line length .lt \n(flu \" set title line length .ev \" *** pop environment .ev 2 \" *** footnote environment .ps \n(ps \" set previous, current .ps \n(ps \" point sizes .vs \n(vs \" set previous, current .vs \n(vs \" vertical spacings .ll \n(llu \" set line length .lt \n(llu \" set title line length .ev \" *** pop environment .\" now set internal registers (for the first header section) .nr f1 \n(.f \" saved font #1 .nr f2 \n(.f \" saved font #2 .nr s1 \n(.s \" saved point size #1 .nr s2 \n(.s \" saved point size #2 .nr v1 \n(.v \" saved vertical spacing #1 .nr v2 \n(.v \" saved vertical spacing #2 .\" install traps .wh 0i hd \" position header trap .wh -\n(bmu fo \" position footer trap .wh \n(.pu+1i fx \" put footnote overflow trap here .ch fx -\n(bmu \" move it over fo .wh -\n(btu pf \" print the bottom margin here .em et \" at end of file, call et .\" couple of miscellaneous requests .bd S 3 3 \" embolden special font chars if B .hy 2 \" don't hyphenate last lines nethack-3.6.0/doc/window.doc0000664000076400007660000014455112536476415014727 0ustar paxedpaxedNetHack 3.6 window.doc $NHDT-Date: 1433901374 2015/06/10 01:56:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.42 $ Introduction This file documents the support for various windowing systems in NetHack. The support is through a standard interface, separating the main NetHack code from window-system specific code. The implementation supports multiple window systems in the same binary. Even if you only wish to support one window-port on your port, you will need to follow the instructions in Section IX to get a compilable binary. Copyright 2003, David Cohrs NetHack may be freely redistributed. See license for details. Contents: I. Window Types and Terminology II. Interface Specification III. Global variables IV. WINCAP preferences support V. New or respecified common, high level routines VI. Helper routines VII. Game startup VIII. Conventions IX. Implementation and Multi-window support X. WINCHAIN I. Window Types and Terminology There are 4 basic window types, used to call create_nhwindow(): NHW_MESSAGE (top line) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) The tty window-port also uses NHW_BASE (the base display) internally. (The genl_status_* routines use NHW_STATUS for backward compatibility when displaying status information on the bottom lines. New code should not use NHW_STATUS. NHW_STATUS will be phased out over time.) NHW_MENU windows can be used for either menu or text display. Their basic feature is that for the tty-port, if the window is small enough, it appears in the corner of the tty display instead of overwriting the whole screen. The first call to add information to the window will decide if it is going to be used to display a menu or text. If start_menu() is called, then it will be used as a menu. If putstr() is called, it will be used as text. Once decided, there is no turning back. For the tty-port, if the data is too large for a single screen then the data is paged (with --more--) between pages. Only NHW_MENU type windows can be used for menus. NHW_TEXT windows are used to display a large amount of textual data. This is the type of window one would use for displaying a help file, for example. In the tty window-port, windows of type NHW_TEXT can page using the DEF_PAGER, if DEF_PAGER is defined. There exists an assumption that the font for text windows is monospaced. The help files are all formatted accordingly. "window" is always of type winid. This is currently implemented as an integer, but doesn't necessarily have to be done that way. There are a few fixed window names that are known throughout the code: WIN_MESSAGE (top line) WIN_MAP (main dungeon) WIN_INVEN (inventory) Other windows are created and destroyed as needed. (The genl_status_* routines use WIN_STATUS for backward compatibility when displaying status information on the bottom lines. New code should not use WIN_STATUS, or assume its presence. NHW_STATUS will be phased out over time.) "Port" in this document refers to a CPU/OS/hardware platform (UNIX, MSDOS TOS, etc.) "window-port" refers to the windowing platform. This is orthogonal (e.g. UNIX might use either a tty window-port or an X11 window-port). II. Interface Specification All functions below are void unless otherwise noted. A. Low-level routines: raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). curs(window, x, y) -- Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. -- For variable sized windows, like the old status window, the behavior when curs() is called outside the window's limits is unspecified. The mac port wraps to 0, with the status window being 2 lines high and 80 columns wide. -- Still used by curs_on_u(), obsolete status updates, screen locating (identify, teleport). -- NHW_MESSAGE, NHW_MENU and NHW_TEXT windows do not currently support curs in the tty window-port. putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. putmixed(window, attr, str) -- Print str on the window with the given attribute. In addition to printable ASCII characters (040-0126), sequences of encoded glyph values are supported. The glyph encoding sequence is \GXXXXNNNN, where: XXXX is a hexadecimal value. The value must match the randomly generated value for the current game in progress in order to be decoded. The value for the game in progress is stored in context.rndencode. This field minimizes unintentional decoding of player-supplied strings such as pet names, etc. NNNN is a hexadecimal value representing the glyph. If a window port does not yet support special handling of the glyph value, it can use genl_putmixed (mapglyph.c) which converts the encoded glyph into a character symbol. Multiple putmixed()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putmixed() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putmixed() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putmixed()s are done consecutively the user will see the first and then the second. get_nh_event() -- Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero and it must be non meta-zero too (zero with the meta-bit set). -- If platform uses it, should check program_state.done_hup and immediately return ASCII 033 (escape) if it is. This is required if the window-port supports SAFERHANGUP. -- ASCII 033 must also be returned rather than EOF (applies mainly to the tty window-port). -- The program_state.done_hup flag can be set asynchronously when SAFERHANGUP is defined and in that case, nhgetch() needs to detect that the value of program_state.done_hup changed and also return ASCII 033 in this case. int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 /* mouse click type 1 */ CLICK_2 /* mouse click type 2 */ The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. -- Otherwise follows the same behavior as nhgetch(). B. High-level routines: print_glyph(window, x, y, glyph, bkglyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). -- bkglyph is a background glyph for potential use by some graphical or tiled environments to allow the depiction to fall against a background consistent with the grid around x,y. If bkglyph is NO_GLYPH, then the parameter should be ignored (do nothing with it). char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. -- If choices is NULL, all possible inputs are accepted and returned, preserving case (upper or lower.) This means that if the calling function needs an exact match, it must handle user input correctness itself. -- ques should not be more than QBUFSZ-1 characters long. getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. -- getlin() can assume the input buffer is at least BUFSZ bytes in size and must truncate inputs to fit, including the nul character. int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. player_selection() -- Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. display_file(str, boolean complain) -- Display the file named str. Complain about missing files iff complain is TRUE. update_inventory() -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. update_positionbar(char *features) -- Optional, POSITIONBAR must be defined. Provide some additional information for use in a horizontal position bar (most useful on clipped displays). Features is a series of char pairs. The first char in the pair is a symbol and the second char is the column where it is currently located. A '<' is used to mark an upstairs, a '>' for a downstairs, and an '@' for the current player location. A zero char marks the end of the list. C. Window Utility Routines init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean exit_nhwindows(str) -- Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. window = create_nhwindow(type) -- Create a window of type "type." clear_nhwindow(window) -- Clear the given window, when appropriate. display_nhwindow(window, boolean blocking) -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. destroy_nhwindow(window) -- Destroy will dismiss the window if the window has not already been dismissed. start_menu(window) -- Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z], but there are a few exceptions such as the tty player selection code which uses '*'. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_ANY, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. char message_menu(char let, int how, const char *mesg) -- tty-specific hack to allow single line context-sensitive help to behave compatibly with multi-line help menus. -- This should only be called when a prompt is active; it sends `mesg' to the message window. For tty, it forces a --More-- prompt and enables `let' as a viable keystroke for dismissing that prompt, so that the original prompt can be answered from the message line "help menu". -- Return value is either `let', '\0' (no selection was made), or '\033' (explicit cancellation was requested). -- Interfaces which issue prompts and messages to separate windows typically won't need this functionality, so can substitute genl_message_menu (windows.c) instead. D. Status Display Routines status_init() -- core calls this to notify the window port that a status display is required. The window port should perform the necessary initialization in here, allocate memory, etc. status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable) -- notifies the window port which fields it is authorized to display. -- This may be called at any time, and is used to disable as well as enable fields, depending on the value of the final argument (TRUE = enable). -- fldindex could be one of the following from botl.h: BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION -- There are MAXBLSTATS status fields (from botl.h) status_update(int fldindex, genericptr_t ptr, int chg, int percentage) -- update the value of a status field. -- the fldindex identifies which field is changing and is an integer index value from botl.h -- fldindex could be any one of the following from botl.h: BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION -- fldindex could also be BL_FLUSH (-1), which is not really a field index, but is a special trigger to tell the windowport that it should redisplay all its status fields, even if no changes have been presented to it. -- ptr is usually a "char *", unless fldindex is BL_CONDITION. If fldindex is BL_CONDITION, then ptr is a long value with any or none of the following bits set (from botl.h): BL_MASK_BLIND 0x00000001L BL_MASK_CONF 0x00000002L BL_MASK_FOODPOIS 0x00000004L BL_MASK_ILL 0x00000008L BL_MASK_HALLU 0x00000010L BL_MASK_STUNNED 0x00000020L BL_MASK_SLIMED 0x00000040L -- The value passed for BL_GOLD includes a leading symbol for GOLD "$:nnn". If the window port needs to use the textual gold amount without the leading "$:" the port will have to add 2 to the passed "ptr" for the BL_GOLD case. status_finish() -- called when it is time for the window port to tear down the status display and free allocated memory, etc. status_threshold(int fldidx, int threshholdtype, anything threshold, int behavior, int under, int over) -- called when a hiliting preference is added, changed, or removed. -- the fldindex identifies which field is having its hiliting preference set. It is an integer index value from botl.h -- fldindex could be any one of the following from botl.h: BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION -- datatype is P_INT, P_UINT, P_LONG, or P_MASK. -- threshold is an "anything" union which can contain the datatype value. -- behavior is used to define how threshold is used and can be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE, or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above or below the threshold. BL_TH_VAL_PERCENTAGE treats the threshold value as a precentage of the maximum possible value. BL_TH_VAL_ABSOLUTE means that the threshold is an actual value. BL_TH_UPDOWN means that threshold is not used, and the two below/above hilite values indicate how to display something going down (under) or rising (over). -- under is the hilite attribute used if value is below the threshold. The attribute can be BL_HILITE_NONE, BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). -- over is the hilite attribute used if value is at or above the threshold. The attribute can be BL_HILITE_NONE, BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). E. Misc. Routines make_sound(???) -- To be determined later. THIS IS CURRENTLY UN-IMPLEMENTED. nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. askname() -- Ask the user for a player name. cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. number_pad(state) -- Initialize the number pad to the given state. suspend_nhwindows(str) -- Prepare the window to be suspended. resume_nhwindows() -- Restore the windows after being suspended. can_suspend() -- Tell the core if the window system will allow the game to be suspended now. If unconditionally yes or no, use genl_can_suspend_yes() or genl_can_suspend_no(). start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). outrip(winid, int, time_t) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. preference_update(preference) -- The player has just changed one of the wincap preference settings, and the NetHack core is notifying your window port of that change. If your window-port is capable of dynamically adjusting to the change then it should do so. Your window-port will only be notified of a particular change if it indicated that it wants to be by setting the corresponding bit in the wincap mask. getmsghistory(init) -- This is used to preserve message history between games by obtaining the messages from the window port so that the core can put them into the savefile. The routine is called repeatedly from the core save routine, and the window port routine is expected to successively return each message that it wants the game to store in the savefile, starting with the oldest message first, finishing with the most recent. If init is TRUE, start over again from most recent message. putmsghistory(msg) -- The is the counterpart to getmsghistory() for restores used to reload the port's message recall buffer. The routine is called repeatedly from the core restore routine, starting with the oldest message first, and finishing with the most recent one that it read from the savefile. The window port routine is expected to load the message recall buffers in such a way that the ordering remains correct. The window port routine should make no assumptions about how many messages are forthcoming, nor should it assume that another message will follow this one, so it must be careful to keep all pointers/indexes intact at the end of each call. If the window port receives more messages that can fit in its buffers, it is expected to scroll away the oldest from its buffers, much like it would with new messages being produced. III. Global variables The following global variables are defined in decl.c and must be used by the window interface to the rest of NetHack. char toplines[BUFSZ] Contains the last message printed to the WIN_MESSAGE window, used by Norep(). winid WIN_MESSAGE, WIN_MAP, WIN_INVEN The three standard windows. There is also a window called WIN_STATUS that is used only for backward compatibility in the genl_status_* set of generic status display functions. char *AE, *AS; Checked in options.c to see if we should load and switch to DECGraphics symset. It is #ifdefed VMS and UNIX. int LI, CO; Set in sys/unix/ioctl.c. The following appears to be Unix specific. Other ports using the tty window-port should also declare this variable in one of your sys/*.c files. short ospeed; Set and declared in sys/unix/unixtty.c (don't know about other sys files). The following global variable is defined in options.c. It equates a list of wincap option names with their associated bit-mask [see section IV WINCAP preferences support]. The array is zero-terminated. struct wc_Opt wc_options[]; One entry for each available WINCAP option. Each entry has a wc_name field and a wc_bit field. IV. WINCAP preferences support Starting with NetHack 3.4.0, the window interface was enhanced to provide a common way of setting window port user preferences from the config file, and from the command line for some settings. The wincap preference settings all have their underlying values stored in iflags fields. The names of the wincap related fields are all pre- fixed with wc_ or wc2_ to make it easy to identify them. Your window port can access the fields directly. Your window port identifies what options it will react to and support by setting bits in the window_procs wincap mask and/or wincap2 mask. See section IX for details of where the wincap masks reside. Two things control whether any preference setting appears in the 'O' command options menu during the game: 1. The option must be marked as being supported by having its bit set in the window_procs wincap or wincap2 mask. 2. The option must have its optflag field set to SET_IN_GAME in order to be able to set the option, or marked DISP_IN_GAME if you just want to reveal what the option is set to. Both conditions must be true to be able to see or set the option from within NetHack. The default values for the optflag field for all the options are hard-coded into the option in options.c. The default value for the wc_ options can be altered by calling set_wc_option_mod_status(optmask, status) The default value for the wc2_ options can be altered by calling set_wc2_option_mod_status(optmask, status) In each case, set the option modification status to one of SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME. The setting of any wincap or wincap2 option is handled by the NetHack core option processing code. You do not have to provide a parser in your window port, nor should you set the values for the iflags.wc_* and iflags.wc2_* fields directly within the port code. The port code should honor whatever values were put there by the core when processing options, either in the config file, or by the 'O' command. You may be wondering what values your window port will find in the iflags.wc_* and iflags.wc2_* fields for options that the user has not specified in his/her config file. Put another way, how does you port code tell if an option has not been set? The next paragraph explains that. If the core does not set an option, it will still be initialized to its default value. Those default values for the iflags.wc_* and iflags.wc_* fields are: o All boolean fields are initialized to the starting value specified for that option in the boolopt array in options.c. The window-port should respect that setting unless it has a very good reason for not doing so. o All int fields are initialized to zero. Zero is not a valid setting for any of the int options, so if your port code encounters a zero there, it can assume that the preference option was not specified. In that case, the window-port code should use a default setting that the port is comfortable with. It should write the default setting back into the iflags.wc_* field. That is the only time that your window-port could should update those fields. o All "char *" fields will be null pointers. Be sure to check for that in your window-port code before using such a pointer, or you'll end up triggering a nasty fault. Here are the wincap and wincap2 preference settings that your port can choose to support: wincap +--------------------+--------------------+--------------------+--------+ | | | iflags field | data | | player option | bit in wincap mask | for value | type | |--------------------+--------------------+--------------------+--------+ | align_message | WC_ALIGN_MESSAGE | wc_align_message |int | | align_status | WC_ALIGN_STATUS | wc_align_status |int | | ascii_map | WC_ASCII_MAP | wc_ascii_map |boolean | | color | WC_COLOR | wc_color |boolean | | eight_bit_tty | WC_EIGHT_BIT_IN | wc_eight_bit_input |boolean | | font_map | WC_FONT_MAP | wc_font_map |char * | | font_menu | WC_FONT_MENU | wc_font_menu |char * | | font_message | WC_FONT_MESSAGE | wc_font_message |char * | | font_status | WC_FONT_STATUS | wc_font_status |char * | | font_text | WC_FONT_TEXT | wc_font_text |char * | | font_size_map | WC_FONTSIZ_MAP | wc_fontsiz_map |int | | font_size_menu | WC_FONTSIZ_MENU | wc_fontsiz_menu |int | | font_size_message | WC_FONTSIZ_MESSAGE | wc_fontsiz_message |int | | font_size_status | WC_FONTSIZ_STATUS | wc_fontsiz_status |int | | font_size_text | WC_FONTSIZ_TEXT | wc_fontsiz_text |int | | hilite_pet | WC_HILITE_PET | wc_hilite_pet |boolean | | map_mode | WC_MAP_MODE | wc_map_mode |int | | player_selection | WC_PLAYER_SELECTION| wc_player_selection|int | | popup_dialog | WC_POPUP_DIALOG | wc_popup_dialog |boolean | | preload_tiles | WC_PRELOAD_TILES | wc_preload_tiles |boolean | | scroll_amount | WC_SCROLL_AMOUNT | wc_scroll_amount |int | | scroll_margin | WC_SCROLL_MARGIN | wc_scroll_margin |int | | splash_screen | WC_SPLASH_SCREEN | wc_splash_screen |boolean | | tiled_map | WC_TILED_MAP | wc_tiled_map |boolean | | tile_width | WC_TILE_WIDTH | wc_tile_width |int | | tile_height | WC_TILE_HEIGHT | wc_tile_height |int | | tile_file | WC_TILE_FILE | wc_tile_file |char * | | use_inverse | WC_INVERSE | wc_inverse |boolean | | vary_msgcount | WC_VARY_MSGCOUNT | wc_vary_msgcount |int | | windowcolors | WC_WINDOWCOLORS | wc_foregrnd_menu |char * | | | | wc_backgrnd_menu |char * | | | | wc_foregrnd_message|char * | | | | wc_backgrnd_message|char * | | | | wc_foregrnd_status |char * | | | | wc_backgrnd_status |char * | | | | wc_foregrnd_text |char * | | | | wc_backgrnd_text |char * | | mouse | WC_MOUSE_SUPPORT | wc_mouse_support |boolean | +--------------------+--------------------+--------------------+--------+ wincap2 +--------------------+--------------------+--------------------+--------+ | | | iflags field | data | | player option | bit in wincap mask | for value | type | |--------------------+--------------------+--------------------+--------+ | fullscreen | WC2_FULLSCREEN | wc2_fullscreen |boolean | | softkeyboard | WC2_SOFTKEYBOARD | wc2_softkeyboard |boolean | | wraptext | WC2_WRAPTEXT | wc2_wraptext |boolean | | selectsaved | WC2_SELECTSAVED | wc2_selectsaved |boolean | +--------------------+--------------------+--------------------+--------+ align_message -- where to place message window (top, bottom, left, right) align_status -- where to place status display (top, bottom, left, right). ascii_map -- port should display an ascii map if it can. color -- port should display color if it can. eight_bit_tty -- port should allow eight bit input. font_map -- port should use a font by this name for map window. font_menu -- port should use a font by this name for menu windows. font_message -- port should use a font by this name for message window. font_size_map -- port should use this size font for the map window. font_size_menu -- port should use this size font for menu windows. font_size_message -- port should use this size font for the message window. font_size_status-- port should use this size font for the status display. font_size_text -- port should use this size font for text windows. font_status -- port should use a font by this name for status display. font_text -- port should use a font by this name for text windows. fullscreen -- port should try to use the whole screen. hilite_pet -- port should mark pets in some special way on the map. map_mode -- port should display the map in the manner specified. player_selection -- dialog or prompts for choosing character. popup_dialog -- port should pop up dialog boxes for input. preload_tiles -- port should preload tiles into memory. scroll_amount -- scroll this amount when scroll_margin is reached. scroll_margin -- port should scroll the display when the hero or cursor is this number of cells away from the edge of the window. selectsaved -- if port can display a menu of the user's saved games do so. softkeyboard -- handhelds should display an on-screen keyboard if possible. splash_screen -- port should/should not display an opening splashscreen. tiled_map -- port should display a tiled map if it can. tile_width -- port should display tiles with this width or round to closest if it can. tile_height -- port should display tiles with this height or round to closest if it can. tile_file -- open this alternative tile file. The file name is likely to be window-port or platform specific. use_inverse -- port should display inverse when NetHack asks for it. vary_msgcount -- port should display this number of messages at a time in the message window. windowcolors -- port should use these colors for window foreground/background colors. Syntax: menu fore/back message fore/back status fore/back text fore/back wraptext -- port should wrap long lines of text if they don't fit in the visible area of the window mouse_support -- port should enable mouse support if possible Whenever one of these settings is adjusted, the port is notified of a change to the setting by calling the port's preference_update() routine. The port is only notified if it has indicated that it supports that option by setting the option's bit in the port's wincap mask. The port can choose to adjust for the change to an option that it receives notification about, or ignore it. The former approach is recommended. If you don't want to deal with a user-initiated setting change, then the port should call set_wc_option_mod_status(mask, SET_IN_FILE) to make the option invisible to the user. Functions available for the window port to call: set_wc_option_mod_status(optmask, status) -- Adjust the optflag field for a set of wincap options to specify whether the port wants the option to appear in the 'O' command options menu, The second parameter, "status" can be set to SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME (SET_IN_FILE implies that the option is completely hidden during the game). set_wc2_option_mod_status(optmask, status) -- Adjust the optflag field for a set of wincap2 options to specify whether the port wants the option to appear in the 'O' command options menu, The second parameter, "status" can be set to SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME (SET_IN_FILE implies that the option is completely hidden during the game). set_option_mod_status(optnam, status) -- Adjust the optflag field for one of the core options that is not part of the wincap suite. A port might use this to override the default initialization setting for status specified in options.c. Note that you have to specify the option by name and that you can only set one option per call unlike set_wc_option_mod_status(). Adding a new wincap option: To add a new wincap option, please follow all these steps: 1. Add the option to the wincap preference settings table above. Since wincap is full, your option will likely target wincap2 field. 2. Add the description to the paragraph below the chart. 3. Add the WC_ or WC2_ to the bit list in include/winprocs.h (in wincap2 if there is no room in wincap). 4. Add the wc_ or wc2_ field(s) to the iflags structure in flag.h. 5. Add the name and value to wc_options[] or wc2_options[] in options.c 6. Add an appropriate parser to parseoptions() in options.c. 7. Add code to display current value to get_compopt_value() in options.c. 8. Document the option in Guidebook.mn and Guidebook.tex. 9. Add the bit name to the OR'd values in your window port's winprocs struct wincap mask if your port supports the option. V. New or respecified common, high level routines These are not part of the interface, but mentioned here for your information. char display_inventory(lets, want_reply) -- Calls a start_menu()/add_menu()/select_menu() sequence. It returns the item selected, or '\0' if none is selected. Returns '\033' if the menu was canceled. raw_printf(str, ...) -- Like raw_print(), but accepts arguments like printf(). This routine processes the arguments and then calls raw_print(). -- The mac version #defines error raw_printf. I think this is a reasonable thing to do for most ports. pline(str, ...) -- Prints a string to WIN_MESSAGE using a printf() interface. It has the variants You(), Your(), Norep(), and others in pline.c which all use the same mechanism. pline() requires the variable "char toplines[]" be defined; Every putstr() on WIN_MESSAGE must copy str to toplines[] for use by Norep() and pline(). If the window system is not active (!iflags.window_inited) pline() uses raw_print(). VI. Helper Routines These are not part of the interface. They may be called by your window port routines to perform the desired task, instead of duplicating the necessary code in each window port. int mapglyph(int glyph, int *ochar, int *ocolor, unsigned *special, int x, int y) -- Maps glyph at x,y to NetHack ascii character and color. The return value is an index into the showsyms[] array, in case a port wants to index into its own alternative set of display symbols (such as a unicode set) instead of the default set. If the glyph represents something special such as a pet, that information is returned as set bits in "special.": MG_CORPSE 0x01 MG_INVIS 0x02 MG_DETECT 0x04 MG_PET 0x08 MG_RIDDEN 0x10 MG_STATUE 0x20 MG_OBJPILE 0x40 Usually called from the window port's print_glyph() routine. VII. Game startup The following is the general order in which calls from main() should be made, as they relate to the window system. The actual code may differ, but the order of the calls should be the same. choose_windows(DEFAULT_WINDOW_SYS) /* choose a default window system */ initoptions() /* read the resource file */ init_nhwindows() /* initialize the window system */ process_options(argc, argv) /* process command line options or equiv */ if(save file is present) { display_gamewindows() /* create & display the game windows */ dorestore() /* restore old game; pline()s are OK */ } else { player_selection() /* select a player type using a window */ display_gamewindows() /* create & display the game windows */ } pline("Hello, welcome..."); Choose_windows() is a common routine, and calling it in main() is necessary to initialize the function pointer table to _something_ so that calls to raw_print() will not fail. Choose_windows() should be called almost immediately upon entering main(). Look at unixmain.c for an example. Choose_windows will call an (optional) ini_routine with a single argument of WININIT to allow any needed setup. Because choose_windows() may be called multiple times during argument and option processing, to handle the case where ini_routines have side effects that need to be undone, the old ini_routine (if any) will be called with an argument of WININIT_UNDO before the new ini_routine (if any) is called (with WININIT). Display_gamewindows() is a common routine that displays the two standard game windows (WIN_MESSAGE, WIN_MAP), and the status display. It is normally called just before the "Hello, welcome" message. Process_options() is currently still unique to each port. There may be need in the future to make it possible to replace this on a per window-port basis. VIII. Conventions init_nhwindows() is expected to display a gee-whiz banner window, including the Copyright message. It is recommended that the COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C, and COPYRIGHT_BANNER_D macros from patchlevel.h and date.h be used for constructing the Copyright message. COPYRIGHT_BANNER_A is a quoted string that has the NetHack copyright declaration, COPYRIGHT_BANNER_B is a quoted string that states who the copyright belongs to, COPYRIGHT_BANNER_C is a quoted string generated by makedefs that includes version and build information. and COPYRIGHT_BANNER_D simply says "See License for details." Be sure to #include "patchlevel.h" and date.h to define these macros. Using the macros will prevent having to update the Copyright information in each window-port prior to each release. Ports (MSDOS, TOS, MAC, etc) _may_ use window-port specific routines in their port specific files, _AT_THEIR_OWN_RISK_. Since "port" and "window-port" are orthogonal, you make your "port" code less portable by using "window-port" specific routines. Every effort should be made to use window-port interface routines, unless there is something port specific that is better suited (e.g. msmsg() for MSDOS). The tty window-port is contained in win/tty, the X window port is contained in win/X11. The files in these directories contain _only_ window port code, and may be replaced completely by other window ports. IX. Implementation and Multi-window support NetHack 3.2 and higher support multiple window systems in the same binary. When writing a new window-port, you need to follow the following guidelines: 1) Pick a unique prefix to identify your window-port. For example, the tty window port uses "tty"; the X11 window-port uses "X11". 2) When declaring your interface function, precede the function names with your unique prefix. E.g: void tty_init_nhwindows() { /* code for initializing windows in the tty port */ } When calling window functions from within your port code, we suggest calling the prefixed version to avoid unnecessary overhead. However, you may safely call the non-prefixed version (e.g. putstr() rather than tty_putstr()) as long as you #include "hack.h". If you do not include hack.h and use the non-prefixed names, you will get compile or link-time errors. We also suggest declaring all functions and port-specific data with this prefix to avoid unexpected overlaps with other window-ports. The tty and X11 ports do not currently follow this suggestion, but do use separate non-overlapping convention for naming data and internal functions. 3) Declare a structure, "struct window_procs prefix_procs", (with your prefix instead of "prefix") and fill in names of all of your interface functions. The first entry in this structure is the name of your window-port, which should be the prefix. The second entry is the wincap mask that identifies what window port preference settings your port will react to and support. The other entries are the function addresses. Assuming that you followed the convention in (2), you can safely copy the structure definition from an existing window-port and just change the prefixes. That will guarantee that you get the order of your initializations correct (not all compilers will catch out-of-order function pointer declarations). 4) Add a #define to config.h identifying your window-port in the "Windowing systems" section. Follow the "prefix_GRAPHICS" convention for your window-port. 5) Add your prefix to the list of valid prefixes listed in the "Known systems are" comment. 6) Edit makedefs.c and add a string for your windowing system to window_opts inside an #ifdef prefix_GRAPHICS. 7) Edit windows.c and add an external reference to your prefix_procs inside an #ifdef prefix_GRAPHICS. Also add an entry to the win_choices structure for your window-port of the form: #ifdef prefix_GRAPHICS { &prefix_procs, prefix_init_function }, #endif The init_function is necessary for some compilers and systems to force correct linking. If your system does not need such massaging, you may put a null pointer here. You should declare prefix_procs and prefix_init_function as extern's in your win*.h file, and #include that file at the beginning of windows.c, also inside an #ifdef prefix_GRAPHICS. Some win*.h files are rather sensitive, and you might have to duplicate your prefix_procs and prefix_init_function's instead of including win*.h. The tty port includes wintty.h, the X11 port duplicates the declarations. 8) If your port uses Makefile.src, add the .c and .o files and an appropriate comment in the section on "WINSRC" and "WINOBJ". See Makefile.src for the style to use. If you don't use Makefile.src, we suggest using a similar convention for the make-equivalent used on your system. Also add your new source and binaries to WINSRC and WINOBJ (if you want the NetHack binary to include them, that is). 9) Look at your port's portmain.c (the file containing main()) and make sure that all of the calls match the the requirements laid out in Section VII. Now, proceed with compilation and installation as usual. Don't forget to edit Makefile.src (or its equivalent) and config.h to set the window-ports you want in your binary, the default window-port to use, and the .o's needed to build a valid game. One caveat. Unfortunately, if you incorrectly specify the DEFAULT_WINDOW_SYS, NetHack will dump core (or whatever) without printing any message, because raw_print() cannot function without first setting the window-port. X. WINCHAIN WINCHAIN is an optional facility that allows the SYSCF_FILE to specify a series of processors that will see each call from the core to the window port (and the resulting return chain). Processors are specified one at a time from the start of the chain (the core end) towards the window port as: OPTIONS=windowchain:+PROC where PROC is the name of the processor to add to the chain. The '+' is required and is part of the name of the processor (this distinguishes processors from window ports; in addition the '-' character is reserved for WINCHAIN internals). If WINCHAIN is not compiled into the NetHack binary, there is no overhead. If WINCHAIN is compiled into the NetHack binary but not used, overhead is limited to one function call during game setup and a trivial amount of data. Note that raw_print* calls will not go through the chain until initialization is complete (when *main.c calls commit_windowchain()). The only processor currently available is '+trace' which is a debugging facility for window ports. See the code in win/chain/wc_trace.c for details on where to find the log file and how to write to it from other parts of the code. A processor may be specified more than once; this is expected to be most useful for surrounding a processor being developed with before and after calls to +trace. nethack-3.6.0/include/align.h0000664000076400007660000000221512536476415015040 0ustar paxedpaxed/* NetHack 3.6 align.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Mike Stephenson, Izchak Miller 1991. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ALIGN_H #define ALIGN_H typedef schar aligntyp; /* basic alignment type */ typedef struct align { /* alignment & record */ aligntyp type; int record; } align; /* bounds for "record" -- respect initial alignments of 10 */ #define ALIGNLIM (10L + (moves / 200L)) #define A_NONE (-128) /* the value range of type */ #define A_CHAOTIC (-1) #define A_NEUTRAL 0 #define A_LAWFUL 1 #define A_COALIGNED 1 #define A_OPALIGNED (-1) #define AM_NONE 0 #define AM_CHAOTIC 1 #define AM_NEUTRAL 2 #define AM_LAWFUL 4 #define AM_MASK 7 #define AM_SPLEV_CO 3 #define AM_SPLEV_NONCO 7 #define Amask2align(x) \ ((aligntyp)((!(x)) ? A_NONE : ((x) == AM_LAWFUL) ? A_LAWFUL \ : ((int) x) - 2)) #define Align2amask(x) \ (((x) == A_NONE) ? AM_NONE : ((x) == A_LAWFUL) ? AM_LAWFUL : (x) + 2) #endif /* ALIGN_H */ nethack-3.6.0/include/amiconf.h0000664000076400007660000001157112536476415015367 0ustar paxedpaxed/* NetHack 3.6 amiconf.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1990, 1991, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef AMICONF_H #define AMICONF_H #undef abs /* avoid using macro form of abs */ #ifndef __SASC_60 #undef min /* this gets redefined */ #undef max /* this gets redefined */ #endif #include /* get time_t defined before use! */ #ifdef __SASC_60 /* since SAS can prevent re-inclusion */ #include /* general things, including builtins */ #include #endif #ifdef AZTEC_50 #include #define AZTEC_C_WORKAROUND /* Bug which turns up in sounds.c. Bummer... */ #define NO_SIGNAL /* 5.0 signal handling doesn't like SIGINT... */ #endif #ifdef _DCC #include #define _SIZE_T #define DCC30_BUG /* A bitfield bug (from dog.c, others) in DICE 3.0. */ #endif #ifndef __GNUC__ typedef long off_t; #endif #define MICRO /* must be defined to allow some inclusions */ #define NOCWD_ASSUMPTIONS /* Allow paths to be specified for HACKDIR, \ LEVELDIR, SAVEDIR, BONESDIR, DATADIR, \ SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ /* data librarian defs */ #ifndef NOCWD_ASSUMPTIONS #define DLBFILE "NetHack:nhdat" /* main library */ #define DLBFILE2 "NetHack:nhsdat" /* sound library */ #else #define DLBFILE "nhdat" /* main library */ #define DLBFILE2 "nhsdat" /* sound library */ #endif #define FILENAME_CMP stricmp /* case insensitive */ #ifndef __SASC_60 #define O_BINARY 0 #endif /* Compile in New Intuition look for 2.0 */ #ifdef IDCMP_CLOSEWINDOW #ifndef INTUI_NEW_LOOK #define INTUI_NEW_LOOK 1 #endif #endif #define MFLOPPY /* You'll probably want this; provides assistance \ * for typical personal computer configurations \ */ #define RANDOM /* ### amidos.c ### */ extern void FDECL(nethack_exit, (int)); /* ### amiwbench.c ### */ extern void NDECL(ami_wbench_init); extern void NDECL(ami_wbench_args); extern int FDECL(ami_wbench_getsave, (int)); extern void FDECL(ami_wbench_unlink, (char *)); extern int FDECL(ami_wbench_iconsize, (char *)); extern void FDECL(ami_wbench_iconwrite, (char *)); extern int FDECL(ami_wbench_badopt, (const char *)); extern void NDECL(ami_wbench_cleanup); extern void FDECL(getlind, (const char *, char *, const char *)); /* ### winreq.c ### */ extern void amii_setpens(int); extern void FDECL(exit, (int)); extern void NDECL(CleanUp); extern void FDECL(Abort, (long)); extern int NDECL(getpid); extern char *FDECL(CopyFile, (const char *, const char *)); extern int NDECL(kbhit); extern int NDECL(WindowGetchar); extern void FDECL(ami_argset, (int *, char *[])); extern void FDECL(ami_mkargline, (int *, char **[])); extern void FDECL(ami_wininit_data, (int)); #define FromWBench 0 /* A hint for compiler ... */ /* extern boolean FromWBench; /* how were we run? */ extern int ami_argc; extern char **ami_argv; #ifndef MICRO_H #include "micro.h" #endif #ifndef PCCONF_H #include "pcconf.h" /* remainder of stuff is almost same as the PC */ #endif #define remove(x) unlink(x) /* DICE wants rewind() to return void. We want it to return int. */ #if defined(_DCC) || defined(__GNUC__) #define rewind(f) fseek(f, 0, 0) #endif #ifdef AZTEC_C extern FILE *FDECL(freopen, (const char *, const char *, FILE *)); extern char *FDECL(gets, (char *)); #endif #define msmsg printf /* * If AZTEC_C we can't use the long cpath in vision.c.... */ #ifdef AZTEC_C #undef MACRO_CPATH #endif /* * (Possibly) configurable Amiga options: */ #define TEXTCOLOR /* Use colored monsters and objects */ #define HACKFONT /* Use special hack.font */ #define SHELL /* Have a shell escape command (!) */ #define MAIL /* Get mail at unexpected occasions */ #define DEFAULT_ICON "NetHack:default.icon" /* private icon */ #define AMIFLUSH /* toss typeahead (select flush in .cnf) */ /* #define OPT_DISPMAP /* enable fast_map option */ /* new window system options */ /* WRONG - AMIGA_INTUITION should go away */ #ifdef AMII_GRAPHICS #define AMIGA_INTUITION /* high power graphics interface (amii) */ #endif #define CHANGE_COLOR 1 #ifdef TEXTCOLOR #define DEPTH 6 /* Maximum depth of the screen allowed */ #else #define DEPTH 2 /* Four colors...sigh... */ #endif #define AMII_MAXCOLORS (1L << DEPTH) typedef unsigned short AMII_COLOR_TYPE; #define PORT_HELP "nethack:amii.hlp" #undef TERMLIB #define AMII_MUFFLED_VOLUME 40 #define AMII_SOFT_VOLUME 50 #define AMII_OKAY_VOLUME 60 #define AMII_LOUDER_VOLUME 80 #ifdef TTY_GRAPHICS #define ANSI_DEFAULT #endif extern int amibbs; /* BBS mode? */ #ifdef AMII_GRAPHICS extern int amii_numcolors; void FDECL(amii_setpens, (int)); #endif /* for cmd.c: override version in micro.h */ #ifdef __SASC_60 #undef M #define M(c) ((c) -128) #endif #endif /* AMICONF_H */ nethack-3.6.0/include/artifact.h0000664000076400007660000000662712536476415015556 0ustar paxedpaxed/* NetHack 3.6 artifact.h $NHDT-Date: 1433050871 2015/05/31 05:41:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ARTIFACT_H #define ARTIFACT_H #define SPFX_NONE 0x00000000L /* no special effects, just a bonus */ #define SPFX_NOGEN 0x00000001L /* item is special, bequeathed by gods */ #define SPFX_RESTR 0x00000002L /* item is restricted - can't be named */ #define SPFX_INTEL 0x00000004L /* item is self-willed - intelligent */ #define SPFX_SPEAK 0x00000008L /* item can speak (not implemented) */ #define SPFX_SEEK 0x00000010L /* item helps you search for things */ #define SPFX_WARN 0x00000020L /* item warns you of danger */ #define SPFX_ATTK 0x00000040L /* item has a special attack (attk) */ #define SPFX_DEFN 0x00000080L /* item has a special defence (defn) */ #define SPFX_DRLI 0x00000100L /* drains a level from monsters */ #define SPFX_SEARCH 0x00000200L /* helps searching */ #define SPFX_BEHEAD 0x00000400L /* beheads monsters */ #define SPFX_HALRES 0x00000800L /* blocks hallucinations */ #define SPFX_ESP 0x00001000L /* ESP (like amulet of ESP) */ #define SPFX_STLTH 0x00002000L /* Stealth */ #define SPFX_REGEN 0x00004000L /* Regeneration */ #define SPFX_EREGEN 0x00008000L /* Energy Regeneration */ #define SPFX_HSPDAM 0x00010000L /* 1/2 spell damage (on player) in combat */ #define SPFX_HPHDAM \ 0x00020000L /* 1/2 physical damage (on player) in combat */ #define SPFX_TCTRL 0x00040000L /* Teleportation Control */ #define SPFX_LUCK 0x00080000L /* Increase Luck (like Luckstone) */ #define SPFX_DMONS 0x00100000L /* attack bonus on one monster type */ #define SPFX_DCLAS 0x00200000L /* attack bonus on monsters w/ symbol mtype \ */ #define SPFX_DFLAG1 0x00400000L /* attack bonus on monsters w/ mflags1 flag \ */ #define SPFX_DFLAG2 0x00800000L /* attack bonus on monsters w/ mflags2 flag \ */ #define SPFX_DALIGN 0x01000000L /* attack bonus on non-aligned monsters */ #define SPFX_DBONUS 0x01F00000L /* attack bonus mask */ #define SPFX_XRAY 0x02000000L /* gives X-RAY vision to player */ #define SPFX_REFLECT 0x04000000L /* Reflection */ #define SPFX_PROTECT 0x08000000L /* Protection */ struct artifact { short otyp; const char *name; unsigned long spfx; /* special effect from wielding/wearing */ unsigned long cspfx; /* special effect just from carrying obj */ unsigned long mtype; /* monster type, symbol, or flag */ struct attack attk, defn, cary; uchar inv_prop; /* property obtained by invoking artifact */ aligntyp alignment; /* alignment of bequeathing gods */ short role; /* character role associated with */ short race; /* character race associated with */ long cost; /* price when sold to hero (default 100 x base cost) */ char acolor; /* color to use if artifact 'glows' */ }; /* invoked properties with special powers */ #define TAMING (LAST_PROP + 1) #define HEALING (LAST_PROP + 2) #define ENERGY_BOOST (LAST_PROP + 3) #define UNTRAP (LAST_PROP + 4) #define CHARGE_OBJ (LAST_PROP + 5) #define LEV_TELE (LAST_PROP + 6) #define CREATE_PORTAL (LAST_PROP + 7) #define ENLIGHTENING (LAST_PROP + 8) #define CREATE_AMMO (LAST_PROP + 9) #endif /* ARTIFACT_H */ nethack-3.6.0/include/artilist.h0000664000076400007660000002465212536476415015612 0ustar paxedpaxed/* NetHack 3.6 artilist.h $NHDT-Date: 1433050874 2015/05/31 05:41:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef MAKEDEFS_C /* in makedefs.c, all we care about is the list of names */ #define A(nam, typ, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, cost, clr) nam static const char *artifact_names[] = { #else /* in artifact.c, set up the actual artifact list structure */ #define A(nam, typ, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, cost, clr) \ { \ typ, nam, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, cost, clr \ } /* clang-format off */ #define NO_ATTK {0,0,0,0} /* no attack */ #define NO_DFNS {0,0,0,0} /* no defense */ #define NO_CARY {0,0,0,0} /* no carry effects */ #define DFNS(c) {0,c,0,0} #define CARY(c) {0,c,0,0} #define PHYS(a,b) {0,AD_PHYS,a,b} /* physical */ #define DRLI(a,b) {0,AD_DRLI,a,b} /* life drain */ #define COLD(a,b) {0,AD_COLD,a,b} #define FIRE(a,b) {0,AD_FIRE,a,b} #define ELEC(a,b) {0,AD_ELEC,a,b} /* electrical shock */ #define STUN(a,b) {0,AD_STUN,a,b} /* magical attack */ /* clang-format on */ STATIC_OVL NEARDATA struct artifact artilist[] = { #endif /* MAKEDEFS_C */ /* Artifact cost rationale: * 1. The more useful the artifact, the better its cost. * 2. Quest artifacts are highly valued. * 3. Chaotic artifacts are inflated due to scarcity (and balance). */ /* dummy element #0, so that all interesting indices are non-zero */ A("", STRANGE_OBJECT, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L, NO_COLOR), A("Excalibur", LONG_SWORD, (SPFX_NOGEN | SPFX_RESTR | SPFX_SEEK | SPFX_DEFN | SPFX_INTEL | SPFX_SEARCH), 0, 0, PHYS(5, 10), DRLI(0, 0), NO_CARY, 0, A_LAWFUL, PM_KNIGHT, NON_PM, 4000L, NO_COLOR), /* * Stormbringer only has a 2 because it can drain a level, * providing 8 more. */ A("Stormbringer", RUNESWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN | SPFX_INTEL | SPFX_DRLI), 0, 0, DRLI(5, 2), DRLI(0, 0), NO_CARY, 0, A_CHAOTIC, NON_PM, NON_PM, 8000L, NO_COLOR), /* * Mjollnir will return to the hand of the wielder when thrown * if the wielder is a Valkyrie wearing Gauntlets of Power. */ A("Mjollnir", WAR_HAMMER, /* Mjo:llnir */ (SPFX_RESTR | SPFX_ATTK), 0, 0, ELEC(5, 24), NO_DFNS, NO_CARY, 0, A_NEUTRAL, PM_VALKYRIE, NON_PM, 4000L, NO_COLOR), A("Cleaver", BATTLE_AXE, SPFX_RESTR, 0, 0, PHYS(3, 6), NO_DFNS, NO_CARY, 0, A_NEUTRAL, PM_BARBARIAN, NON_PM, 1500L, NO_COLOR), /* * Grimtooth glows in warning when elves are present, but its * damage bonus applies to all targets rather than just elves * (handled as special case in spec_dbon()). */ A("Grimtooth", ORCISH_DAGGER, (SPFX_RESTR | SPFX_WARN | SPFX_DFLAG2), 0, M2_ELF, PHYS(2, 6), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ORC, 300L, CLR_RED), /* * Orcrist and Sting have same alignment as elves. * * The combination of SPFX_WARN+SPFX_DFLAG2+M2_value will trigger * EWarn_of_mon for all monsters that have the M2_value flag. * Sting and Orcrist will warn of M2_ORC monsters. */ A("Orcrist", ELVEN_BROADSWORD, (SPFX_WARN | SPFX_DFLAG2), 0, M2_ORC, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, 2000L, CLR_BRIGHT_BLUE), /* bright blue is actually light blue */ A("Sting", ELVEN_DAGGER, (SPFX_WARN | SPFX_DFLAG2), 0, M2_ORC, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, 800L, CLR_BRIGHT_BLUE), /* * Magicbane is a bit different! Its magic fanfare * unbalances victims in addition to doing some damage. */ A("Magicbane", ATHAME, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, STUN(3, 4), DFNS(AD_MAGM), NO_CARY, 0, A_NEUTRAL, PM_WIZARD, NON_PM, 3500L, NO_COLOR), A("Frost Brand", LONG_SWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, COLD(5, 0), COLD(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 3000L, NO_COLOR), A("Fire Brand", LONG_SWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, FIRE(5, 0), FIRE(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 3000L, NO_COLOR), A("Dragonbane", BROADSWORD, (SPFX_RESTR | SPFX_DCLAS), 0, S_DRAGON, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 500L, NO_COLOR), A("Demonbane", LONG_SWORD, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_DEMON, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_LAWFUL, NON_PM, NON_PM, 2500L, NO_COLOR), A("Werebane", SILVER_SABER, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_WERE, PHYS(5, 0), DFNS(AD_WERE), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 1500L, NO_COLOR), A("Grayswandir", SILVER_SABER, (SPFX_RESTR | SPFX_HALRES), 0, 0, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_LAWFUL, NON_PM, NON_PM, 8000L, NO_COLOR), A("Giantslayer", LONG_SWORD, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_GIANT, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NEUTRAL, NON_PM, NON_PM, 200L, NO_COLOR), A("Ogresmasher", WAR_HAMMER, (SPFX_RESTR | SPFX_DCLAS), 0, S_OGRE, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 200L, NO_COLOR), A("Trollsbane", MORNING_STAR, (SPFX_RESTR | SPFX_DCLAS), 0, S_TROLL, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 200L, NO_COLOR), /* * Two problems: 1) doesn't let trolls regenerate heads, * 2) doesn't give unusual message for 2-headed monsters (but * allowing those at all causes more problems than worth the effort). */ A("Vorpal Blade", LONG_SWORD, (SPFX_RESTR | SPFX_BEHEAD), 0, 0, PHYS(5, 1), NO_DFNS, NO_CARY, 0, A_NEUTRAL, NON_PM, NON_PM, 4000L, NO_COLOR), /* * Ah, never shall I forget the cry, * or the shriek that shrieked he, * As I gnashed my teeth, and from my sheath * I drew my Snickersnee! * --Koko, Lord high executioner of Titipu * (From Sir W.S. Gilbert's "The Mikado") */ A("Snickersnee", KATANA, SPFX_RESTR, 0, 0, PHYS(0, 8), NO_DFNS, NO_CARY, 0, A_LAWFUL, PM_SAMURAI, NON_PM, 1200L, NO_COLOR), A("Sunsword", LONG_SWORD, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_UNDEAD, PHYS(5, 0), DFNS(AD_BLND), NO_CARY, 0, A_LAWFUL, NON_PM, NON_PM, 1500L, NO_COLOR), /* * The artifacts for the quest dungeon, all self-willed. */ A("The Orb of Detection", CRYSTAL_BALL, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), (SPFX_ESP | SPFX_HSPDAM), 0, NO_ATTK, NO_DFNS, CARY(AD_MAGM), INVIS, A_LAWFUL, PM_ARCHEOLOGIST, NON_PM, 2500L, NO_COLOR), A("The Heart of Ahriman", LUCKSTONE, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), SPFX_STLTH, 0, /* this stone does double damage if used as a projectile weapon */ PHYS(5, 0), NO_DFNS, NO_CARY, LEVITATION, A_NEUTRAL, PM_BARBARIAN, NON_PM, 2500L, NO_COLOR), A("The Sceptre of Might", MACE, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_DALIGN), 0, 0, PHYS(5, 0), DFNS(AD_MAGM), NO_CARY, CONFLICT, A_LAWFUL, PM_CAVEMAN, NON_PM, 2500L, NO_COLOR), #if 0 /* OBSOLETE */ A("The Palantir of Westernesse", CRYSTAL_BALL, (SPFX_NOGEN|SPFX_RESTR|SPFX_INTEL), (SPFX_ESP|SPFX_REGEN|SPFX_HSPDAM), 0, NO_ATTK, NO_DFNS, NO_CARY, TAMING, A_CHAOTIC, NON_PM , PM_ELF, 8000L, NO_COLOR ), #endif A("The Staff of Aesculapius", QUARTERSTAFF, (SPFX_NOGEN | SPFX_RESTR | SPFX_ATTK | SPFX_INTEL | SPFX_DRLI | SPFX_REGEN), 0, 0, DRLI(0, 0), DRLI(0, 0), NO_CARY, HEALING, A_NEUTRAL, PM_HEALER, NON_PM, 5000L, NO_COLOR), A("The Magic Mirror of Merlin", MIRROR, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK), SPFX_ESP, 0, NO_ATTK, NO_DFNS, CARY(AD_MAGM), 0, A_LAWFUL, PM_KNIGHT, NON_PM, 1500L, NO_COLOR), A("The Eyes of the Overworld", LENSES, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_XRAY), 0, 0, NO_ATTK, DFNS(AD_MAGM), NO_CARY, ENLIGHTENING, A_NEUTRAL, PM_MONK, NON_PM, 2500L, NO_COLOR), A("The Mitre of Holiness", HELM_OF_BRILLIANCE, (SPFX_NOGEN | SPFX_RESTR | SPFX_DFLAG2 | SPFX_INTEL | SPFX_PROTECT), 0, M2_UNDEAD, NO_ATTK, NO_DFNS, CARY(AD_FIRE), ENERGY_BOOST, A_LAWFUL, PM_PRIEST, NON_PM, 2000L, NO_COLOR), A("The Longbow of Diana", BOW, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_REFLECT), SPFX_ESP, 0, PHYS(5, 0), NO_DFNS, NO_CARY, CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM, 4000L, NO_COLOR), A("The Master Key of Thievery", SKELETON_KEY, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK), (SPFX_WARN | SPFX_TCTRL | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY, UNTRAP, A_CHAOTIC, PM_ROGUE, NON_PM, 3500L, NO_COLOR), A("The Tsurugi of Muramasa", TSURUGI, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_BEHEAD | SPFX_LUCK | SPFX_PROTECT), 0, 0, PHYS(0, 8), NO_DFNS, NO_CARY, 0, A_LAWFUL, PM_SAMURAI, NON_PM, 4500L, NO_COLOR), A("The Platinum Yendorian Express Card", CREDIT_CARD, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_DEFN), (SPFX_ESP | SPFX_HSPDAM), 0, NO_ATTK, NO_DFNS, CARY(AD_MAGM), CHARGE_OBJ, A_NEUTRAL, PM_TOURIST, NON_PM, 7000L, NO_COLOR), A("The Orb of Fate", CRYSTAL_BALL, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_LUCK), (SPFX_WARN | SPFX_HSPDAM | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY, LEV_TELE, A_NEUTRAL, PM_VALKYRIE, NON_PM, 3500L, NO_COLOR), A("The Eye of the Aethiopica", AMULET_OF_ESP, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), (SPFX_EREGEN | SPFX_HSPDAM), 0, NO_ATTK, DFNS(AD_MAGM), NO_CARY, CREATE_PORTAL, A_NEUTRAL, PM_WIZARD, NON_PM, 4000L, NO_COLOR), /* * terminator; otyp must be zero */ A(0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L, 0) /* 0 is CLR_BLACK rather than NO_COLOR but it doesn't matter here */ }; /* artilist[] (or artifact_names[]) */ #undef A #ifndef MAKEDEFS_C #undef NO_ATTK #undef NO_DFNS #undef DFNS #undef PHYS #undef DRLI #undef COLD #undef FIRE #undef ELEC #undef STUN #endif /*artilist.h*/ nethack-3.6.0/include/attrib.h0000664000076400007660000000251212536476415015233 0ustar paxedpaxed/* NetHack 3.6 attrib.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright 1988, Mike Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* attrib.h - Header file for character class processing. */ #ifndef ATTRIB_H #define ATTRIB_H #define A_STR 0 #define A_INT 1 #define A_WIS 2 #define A_DEX 3 #define A_CON 4 #define A_CHA 5 #define A_MAX 6 /* used in rn2() selection of attrib */ #define ABASE(x) (u.acurr.a[x]) #define ABON(x) (u.abon.a[x]) #define AEXE(x) (u.aexe.a[x]) #define ACURR(x) (acurr(x)) #define ACURRSTR (acurrstr()) /* should be: */ /* #define ACURR(x) (ABON(x) + ATEMP(x) + (Upolyd ? MBASE(x) : ABASE(x)) */ #define MCURR(x) (u.macurr.a[x]) #define AMAX(x) (u.amax.a[x]) #define MMAX(x) (u.mamax.a[x]) #define ATEMP(x) (u.atemp.a[x]) #define ATIME(x) (u.atime.a[x]) /* KMH -- Conveniences when dealing with strength constants */ #define STR18(x) (18 + (x)) /* 18/xx */ #define STR19(x) (100 + (x)) /* For 19 and above */ struct attribs { schar a[A_MAX]; }; #define ATTRMAX(x) \ ((x == A_STR && Upolyd && strongmonst(youmonst.data)) \ ? STR18(100) \ : urace.attrmax[x]) #define ATTRMIN(x) (urace.attrmin[x]) #endif /* ATTRIB_H */ nethack-3.6.0/include/beconf.h0000664000076400007660000000161212536476415015202 0ustar paxedpaxed/* NetHack 3.6 beconf.h $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Dean Luick 1996. */ /* NetHack may be freely redistributed. See license for details. */ /* Configuration for Be Inc.'s BeOS */ #ifndef BECONF_H #define BECONF_H /* * We must use UNWIDENED_PROTOTYPES because we mix C++ and C. */ #define index strchr #define rindex strrchr #define Rand rand /* Be should have a better rand function! */ #define tgetch getchar #define FCMASK 0666 #define PORT_ID "BeOS" #define TEXTCOLOR #define POSIX_TYPES #define SIG_RET_TYPE __signal_func_ptr #include /* for time_t */ #include /* for lseek() */ /* could go in extern.h, under bemain.c (or something..) */ void regularize(char *); /* instead of including system.h... */ #include #include #include #endif /* BECONF_H */ nethack-3.6.0/include/bitmfile.h0000664000076400007660000000152312536476415015542 0ustar paxedpaxed/****************************\ * Bitmap mit Farbtabelle als * * Graphik-Datei speichern * * Autor: Gabriel Schmidt * * (c} 1992 by MAXON-Computer * * -> Header-Datei * \****************************/ #ifndef H_TO_FILE #define H_TO_FILE /* #include */ #define UWORD unsigned short #define ULONG unsigned long #define UBYTE unsigned char #define XIMG_MAGIC 0x58494D47 typedef enum { IMG, XIMG } FILE_TYP; const char *get_file_ext(FILE_TYP typ); struct RGB { UWORD r, g, b; }; int bitmap_to_file(FILE_TYP typ, int ww, int wh, unsigned int pwx, unsigned int pwy, unsigned int planes, unsigned int colors, const char *filename, void (*get_color)(unsigned int colind, struct RGB *rgb), void (*get_pixel)(int x, int y, unsigned int *colind)); #endif nethack-3.6.0/include/botl.h0000664000076400007660000000546512536476415014720 0ustar paxedpaxed/* NetHack 3.6 botl.h $NHDT-Date: 1433105378 2015/05/31 20:49:38 $ $NHDT-Branch: status_hilite $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Michael Allison, 2003 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef BOTL_H #define BOTL_H /* MAXCO must hold longest uncompressed status line, and must be larger * than COLNO * * longest practical second status line at the moment is * Astral Plane $:12345 HP:700(700) Pw:111(111) AC:-127 Xp:30/123456789 * T:123456 Satiated Conf FoodPois Ill Blind Stun Hallu Overloaded * -- or somewhat over 130 characters */ #if COLNO <= 140 #define MAXCO 160 #else #define MAXCO (COLNO + 20) #endif #ifdef STATUS_VIA_WINDOWPORT #if 0 /* clang-format off */ #define BL_FLUSH -1 #define BL_TITLE 0 #define BL_STR 1 #define BL_DX 2 #define BL_CO 3 #define BL_IN 4 #define BL_WI 5 #define BL_CH 6 #define BL_ALIGN 7 #define BL_SCORE 8 #define BL_CAP 9 #define BL_GOLD 10 #define BL_ENE 11 #define BL_ENEMAX 12 #define BL_XP 13 #define BL_AC 14 #define BL_HD 15 #define BL_TIME 16 #define BL_HUNGER 17 #define BL_HP 18 #define BL_HPMAX 19 #define BL_LEVELDESC 20 #define BL_EXP 21 #define BL_CONDITION 22 /* clang-format on */ #else enum statusfields { BL_FLUSH = -1, BL_TITLE = 0, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION }; #define MAXBLSTATS BL_CONDITION+1 #define BEFORE 0 #define NOW 1 #endif /* Boolean condition bits for the condition mask */ /* clang-format off */ #define BL_MASK_BLIND 0x00000001L #define BL_MASK_CONF 0x00000002L #define BL_MASK_FOODPOIS 0x00000004L #define BL_MASK_ILL 0x00000008L #define BL_MASK_HALLU 0x00000010L #define BL_MASK_STUNNED 0x00000020L #define BL_MASK_SLIMED 0x00000040L /* clang-format on */ #define REASSESS_ONLY TRUE #ifdef STATUS_HILITES /* hilite status field behavior - coloridx values */ #define BL_HILITE_NONE -1 /* no hilite of this field */ #define BL_HILITE_INVERSE -2 /* inverse hilite */ #define BL_HILITE_BOLD -3 /* bold hilite */ /* or any CLR_ index (0 - 15) */ #define BL_TH_NONE 0 #define BL_TH_VAL_PERCENTAGE 100 /* threshold is percentage */ #define BL_TH_VAL_ABSOLUTE 101 /* threshold is particular value */ #define BL_TH_UPDOWN 102 /* threshold is up or down change */ #define BL_TH_CONDITION 103 /* threshold is bitmask of conditions */ #endif extern const char *status_fieldnames[]; /* in botl.c */ #endif #endif /* BOTL_H */ nethack-3.6.0/include/color.h0000664000076400007660000000333312610522241015044 0ustar paxedpaxed/* NetHack 3.6 color.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Steve Linhart, Eric Raymond, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef COLOR_H #define COLOR_H /* * The color scheme used is tailored for an IBM PC. It consists of the * standard 8 colors, followed by their bright counterparts. There are * exceptions, these are listed below. Bright black doesn't mean very * much, so it is used as the "default" foreground color of the screen. */ #define CLR_BLACK 0 #define CLR_RED 1 #define CLR_GREEN 2 #define CLR_BROWN 3 /* on IBM, low-intensity yellow is brown */ #define CLR_BLUE 4 #define CLR_MAGENTA 5 #define CLR_CYAN 6 #define CLR_GRAY 7 /* low-intensity white */ #define NO_COLOR 8 #define CLR_ORANGE 9 #define CLR_BRIGHT_GREEN 10 #define CLR_YELLOW 11 #define CLR_BRIGHT_BLUE 12 #define CLR_BRIGHT_MAGENTA 13 #define CLR_BRIGHT_CYAN 14 #define CLR_WHITE 15 #define CLR_MAX 16 /* The "half-way" point for tty based color systems. This is used in */ /* the tty color setup code. (IMHO, it should be removed - dean). */ #define BRIGHT 8 /* these can be configured */ #define HI_OBJ CLR_MAGENTA #define HI_METAL CLR_CYAN #define HI_COPPER CLR_YELLOW #define HI_SILVER CLR_GRAY #define HI_GOLD CLR_YELLOW #define HI_LEATHER CLR_BROWN #define HI_CLOTH CLR_BROWN #define HI_ORGANIC CLR_BROWN #define HI_WOOD CLR_BROWN #define HI_PAPER CLR_WHITE #define HI_GLASS CLR_BRIGHT_CYAN #define HI_MINERAL CLR_GRAY #define DRAGON_SILVER CLR_BRIGHT_CYAN #define HI_ZAP CLR_BRIGHT_BLUE struct menucoloring { struct nhregex *match; char *origstr; int color, attr; struct menucoloring *next; }; #endif /* COLOR_H */ nethack-3.6.0/include/config.h0000664000076400007660000004167412622541012015205 0ustar paxedpaxed/* NetHack 3.6 config.h $NHDT-Date: 1447728911 2015/11/17 02:55:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.91 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef CONFIG_H /* make sure the compiler does not see the typedefs twice */ #define CONFIG_H /* * Section 1: Operating and window systems selection. * Select the version of the OS you are using. * For "UNIX" select BSD, ULTRIX, SYSV, or HPUX in unixconf.h. * A "VMS" option is not needed since the VMS C-compilers * provide it (no need to change sec#1, vmsconf.h handles it). */ #define UNIX /* delete if no fork(), exec() available */ /* #define MSDOS */ /* in case it's not auto-detected */ /* #define OS2 */ /* define for OS/2 */ /* #define TOS */ /* define for Atari ST/TT */ /* #define STUPID */ /* avoid some complicated expressions if your C compiler chokes on them */ /* #define MINIMAL_TERM */ /* if a terminal handles highlighting or tabs poorly, try this define, used in pager.c and termcap.c */ /* #define ULTRIX_CC20 */ /* define only if using cc v2.0 on a DECstation */ /* #define ULTRIX_PROTO */ /* define for Ultrix 4.0 (or higher) on a DECstation; * if you get compiler errors, don't define this. */ /* Hint: if you're not developing code, don't define ULTRIX_PROTO. */ #include "config1.h" /* should auto-detect MSDOS, MAC, AMIGA, and WIN32 */ /* Windowing systems... * Define all of those you want supported in your binary. * Some combinations make no sense. See the installation document. */ #if !defined(NOTTYGRAPHICS) #define TTY_GRAPHICS /* good old tty based graphics */ #endif /* #define X11_GRAPHICS */ /* X11 interface */ /* #define QT_GRAPHICS */ /* Qt interface */ /* #define GNOME_GRAPHICS */ /* Gnome interface */ /* #define MSWIN_GRAPHICS */ /* Windows NT, CE, Graphics */ /* * Define the default window system. This should be one that is compiled * into your system (see defines above). Known window systems are: * * tty, X11, mac, amii, BeOS, Qt, Gem, Gnome */ /* MAC also means MAC windows */ #ifdef MAC #ifndef AUX #define DEFAULT_WINDOW_SYS "mac" #endif #endif /* Amiga supports AMII_GRAPHICS and/or TTY_GRAPHICS */ #ifdef AMIGA #define AMII_GRAPHICS /* (optional) */ #define DEFAULT_WINDOW_SYS "amii" /* "amii", "amitile" or "tty" */ #endif /* Atari supports GEM_GRAPHICS and/or TTY_GRAPHICS */ #ifdef TOS #define GEM_GRAPHICS /* Atari GEM interface (optional) */ #define DEFAULT_WINDOW_SYS "Gem" /* "Gem" or "tty" */ #endif #ifdef __BEOS__ #define BEOS_GRAPHICS /* (optional) */ #define DEFAULT_WINDOW_SYS "BeOS" /* "tty" */ #ifndef HACKDIR /* override the default hackdir below */ #define HACKDIR "/boot/apps/NetHack" #endif #endif #ifdef QT_GRAPHICS #ifndef DEFAULT_WC_TILED_MAP #define DEFAULT_WC_TILED_MAP /* Default to tiles if users doesn't say \ wc_ascii_map */ #endif #ifndef NOUSER_SOUNDS #define USER_SOUNDS /* Use sounds */ #endif #define USE_XPM /* Use XPM format for images (required) */ #define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "Qt" #endif #endif #ifdef GNOME_GRAPHICS #define USE_XPM /* Use XPM format for images (required) */ #define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "Gnome" #endif #endif #ifdef MSWIN_GRAPHICS #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "mswin" #endif #define HACKDIR "\\nethack" #endif #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "tty" #endif #ifdef X11_GRAPHICS /* * There are two ways that X11 tiles may be defined. (1) using a custom * format loaded by NetHack code, or (2) using the XPM format loaded by * the free XPM library. The second option allows you to then use other * programs to generate tiles files. For example, the PBMPlus tools * would allow: * xpmtoppm x11tiles_big.xpm */ /* # define USE_XPM */ /* Disable if you do not have the XPM library */ #ifdef USE_XPM #define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.xpm) */ #endif #ifndef DEFAULT_WC_TILED_MAP #define DEFAULT_WC_TILED_MAP /* Default to tiles */ #endif #endif /* * Section 2: Some global parameters and filenames. * * LOGFILE, XLOGFILE, NEWS and PANICLOG refer to files in * the playground directory. Commenting out LOGFILE, XLOGFILE, * NEWS or PANICLOG removes that feature from the game. * * Building with debugging features enabled is now unconditional; * the old WIZARD setting for that has been eliminated. * If SYSCF is enabled, WIZARD_NAME will be overridden at * runtime by the SYSCF WIZARDS value. * * SYSCF: (not supported by all ports) * If SYSCF is defined, the following configuration info is * available in a global config space, with the compiled-in * entries as defaults: * WIZARDS (a space-separated list of usernames of users who * can run the game in debug mode, aka wizard mode; * a value of * allows anyone to debug; * this does NOT default to compiled-in value) * EXPLORERS (who can use explore mode, aka discover mode) * SHELLERS (who can use ! to execute a shell subprocess) * MAXPLAYERS (see MAX_NR_OF_PLAYERS below and nethack.sh) * SUPPORT (how to get local support) [no default] * RECOVER (how to recover a game at your site) [no default] * For the record file (see topten.c): * PERSMAX (max entries for one person) * ENTRYMAX (max entries in the record file) * POINTSMIN (min points to get an entry) * PERS_IS_UID (0 or 1 - person is name or (numeric) userid) * Can force incubi/succubi behavior to be toned down to nymph-like: * SEDUCE (0 or 1 - runtime disable/enable SEDUCE option) * The following options pertain to crash reporting: * GREPPATH (the path to the system grep(1) utility) * GDBPATH (the path to the system gdb(1) program) * Regular nethack options can also be specified in order to * provide system-wide default values local to your system: * OPTIONS (same as in users' .nethackrc or defaults.nh) * * In the future there may be other ways to supply SYSCF * information (Windows registry, Apple resource forks, etc) * but at present the only supported method is via a text file. * If the program is built with SYSCF enabled, the file *must* * exist and be readable, otherwise the game will complain and * refuse to start. * SYSCF_FILE: file containing the SYSCF options shown above; * default is 'sysconf' in nethack's playground. */ #ifndef WIZARD_NAME /* allow for compile-time or Makefile changes */ #define WIZARD_NAME "wizard" /* value is ignored if SYSCF is enabled */ #endif #ifndef SYSCF #define SYSCF /* use a global configuration */ #define SYSCF_FILE "sysconf" /* global configuration is in a file */ #endif #ifndef GDBPATH #define GDBPATH "/usr/bin/gdb" #endif #ifndef GREPPATH #define GREPPATH "/bin/grep" #endif /* note: "larger" is in comparison with 'record', the high-scores file (whose name can be overridden via #define in global.h if desired) */ #define LOGFILE "logfile" /* larger file for debugging purposes */ #define XLOGFILE "xlogfile" /* even larger logfile */ #define NEWS "news" /* the file containing the latest hack news */ #define PANICLOG "paniclog" /* log of panic and impossible events */ /* * PERSMAX, POINTSMIN, ENTRYMAX, PERS_IS_UID: * These control the contents of 'record', the high-scores file. * They used to be located in topten.c rather than config.h, and * their values can be overridden at runtime (to increase ENTRYMAX, the * maximum number of scores to keep, for example) if SYSCF is enabled. */ #ifndef PERSMAX #define PERSMAX 3 /* entries per name/uid per char. allowed */ #endif #ifndef POINTSMIN #define POINTSMIN 1 /* must be > 0 */ #endif #ifndef ENTRYMAX #define ENTRYMAX 100 /* must be >= 10 */ #endif #ifndef PERS_IS_UID #if !defined(MICRO) && !defined(MAC) && !defined(WIN32) #define PERS_IS_UID 1 /* delete for PERSMAX per name; now per uid */ #else #define PERS_IS_UID 0 #endif #endif /* * If COMPRESS is defined, it should contain the full path name of your * 'compress' program. * * If you define COMPRESS, you must also define COMPRESS_EXTENSION * as the extension your compressor appends to filenames after * compression. Currently, only UNIX fully implements * COMPRESS; other ports should be able to uncompress save files a * la unixmain.c if so inclined. * * Defining ZLIB_COMP builds in support for zlib compression. If you * define ZLIB_COMP, you must link with a zlib library. Not all ports * support ZLIB_COMP. * * COMPRESS and ZLIB_COMP are mutually exclusive. * */ #if defined(UNIX) && !defined(ZLIB_COMP) && !defined(COMPRESS) /* path and file name extension for compression program */ #define COMPRESS "/usr/bin/compress" /* Lempel-Ziv compression */ #define COMPRESS_EXTENSION ".Z" /* compress's extension */ /* An example of one alternative you might want to use: */ /* #define COMPRESS "/usr/local/bin/gzip" */ /* FSF gzip compression */ /* #define COMPRESS_EXTENSION ".gz" */ /* normal gzip extension */ #endif #ifndef COMPRESS /* # define ZLIB_COMP */ /* ZLIB for compression */ #endif /* * Internal Compression Options * * Internal compression options RLECOMP and ZEROCOMP alter the data * that gets written to the save file by NetHack, in contrast * to COMPRESS or ZLIB_COMP which compress the entire file after * the NetHack data is written out. * * Defining RLECOMP builds in support for internal run-length * compression of level structures. If RLECOMP support is included * it can be toggled on/off at runtime via the config file option * rlecomp. * * Defining ZEROCOMP builds in support for internal zero-comp * compression of data. If ZEROCOMP support is included it can still * be toggled on/off at runtime via the config file option zerocomp. * * RLECOMP and ZEROCOMP support can be included even if * COMPRESS or ZLIB_COMP support is included. One reason for doing * so would be to provide savefile read compatibility with a savefile * where those options were in effect. With RLECOMP and/or ZEROCOMP * defined, NetHack can read an rlecomp or zerocomp savefile in, yet * re-save without them. * * Using any compression option will create smaller bones/level/save * files at the cost of additional code and time. */ /* # define INTERNAL_COMP */ /* defines both ZEROCOMP and RLECOMP */ /* # define ZEROCOMP */ /* Support ZEROCOMP compression */ /* # define RLECOMP */ /* Support RLECOMP compression */ /* * Data librarian. Defining DLB places most of the support files into * a tar-like file, thus making a neater installation. See *conf.h * for detailed configuration. */ /* #define DLB */ /* not supported on all platforms */ /* * Defining INSURANCE slows down level changes, but allows games that * died due to program or system crashes to be resumed from the point * of the last level change, after running a utility program. */ #define INSURANCE /* allow crashed game recovery */ #ifndef MAC #define CHDIR /* delete if no chdir() available */ #endif #ifdef CHDIR /* * If you define HACKDIR, then this will be the default playground; * otherwise it will be the current directory. */ #ifndef HACKDIR #define HACKDIR "/usr/games/lib/nethackdir" #endif /* * Some system administrators are stupid enough to make Hack suid root * or suid daemon, where daemon has other powers besides that of reading or * writing Hack files. In such cases one should be careful with chdir's * since the user might create files in a directory of his choice. * Of course SECURE is meaningful only if HACKDIR is defined. */ /* #define SECURE */ /* do setuid(getuid()) after chdir() */ /* * If it is desirable to limit the number of people that can play Hack * simultaneously, define HACKDIR, SECURE and MAX_NR_OF_PLAYERS (or use * MAXPLAYERS under SYSCF). * #define MAX_NR_OF_PLAYERS 6 */ #endif /* CHDIR */ /* If GENERIC_USERNAMES is defined, and the player's username is found * in the list, prompt for character name instead of using username. * A public server should probably disable this. */ #define GENERIC_USERNAMES "play player game games nethack nethacker" /* * Section 3: Definitions that may vary with system type. * For example, both schar and uchar should be short ints on * the AT&T 3B2/3B5/etc. family. */ /* * Uncomment the following line if your compiler doesn't understand the * 'void' type (and thus would give all sorts of compile errors without * this definition). */ /* #define NOVOID */ /* define if no "void" data type. */ /* * Uncomment the following line if your compiler falsely claims to be * a standard C compiler (i.e., defines __STDC__ without cause). * Examples are Apollo's cc (in some versions) and possibly SCO UNIX's rcc. */ /* #define NOTSTDC */ /* define for lying compilers */ #include "tradstdc.h" /* * type schar: * small signed integers (8 bits suffice) (eg. TOS) * typedef char schar; * will do when you have signed characters; otherwise use * typedef short int schar; */ #ifdef AZTEC #define schar char #else typedef signed char schar; #endif /* * type uchar: * small unsigned integers (8 bits suffice - but 7 bits do not) * typedef unsigned char uchar; * will be satisfactory if you have an "unsigned char" type; otherwise use * typedef unsigned short int uchar; */ #ifndef _AIX32 /* identical typedef in system file causes trouble */ typedef unsigned char uchar; #endif /* * Various structures have the option of using bitfields to save space. * If your C compiler handles bitfields well (e.g., it can initialize structs * containing bitfields), you can define BITFIELDS. Otherwise, the game will * allocate a separate character for each bitfield. (The bitfields used never * have more than 7 bits, and most are only 1 bit.) */ #define BITFIELDS /* Good bitfield handling */ /* #define STRNCMPI */ /* compiler/library has the strncmpi function */ /* * There are various choices for the NetHack vision system. There is a * choice of two algorithms with the same behavior. Defining VISION_TABLES * creates huge (60K) tables at compile time, drastically increasing data * size, but runs slightly faster than the alternate algorithm. (MSDOS in * particular cannot tolerate the increase in data size; other systems can * flip a coin weighted to local conditions.) * * If VISION_TABLES is not defined, things will be faster if you can use * MACRO_CPATH. Some cpps, however, cannot deal with the size of the * functions that have been macroized. */ /* #define VISION_TABLES */ /* use vision tables generated at compile time */ #ifndef VISION_TABLES #ifndef NO_MACRO_CPATH #define MACRO_CPATH /* use clear_path macros instead of functions */ #endif #endif #if !defined(MAC) #if !defined(NOCLIPPING) #define CLIPPING /* allow smaller screens -- ERS */ #endif #endif #define DOAGAIN '\001' /* ^A, the "redo" key used in cmd.c and getline.c */ /* * Section 4: EXPERIMENTAL STUFF * * Conditional compilation of new or experimental options are controlled here. * Enable any of these at your own risk -- there are almost certainly * bugs left here. */ /* #define STATUS_VIA_WINDOWPORT */ /* re-work of the status line updating process */ /* #define STATUS_HILITES */ /* support hilites of status fields */ /* #define WINCHAIN */ /* stacked window systems */ /* #define DEBUG_MIGRATING_MONS */ /* add a wizard-mode command to help debug migrating monsters */ /* SCORE_ON_BOTL is neither experimental nor inadequately tested, but doesn't seem to fit in any other section... */ /* #define SCORE_ON_BOTL */ /* enable the 'showscore' option to show estimated score on status line */ /* FREE_ALL_MEMORY is neither experimental nor inadequately tested, but it isn't necessary for successful operation of the program */ #define FREE_ALL_MEMORY /* free all memory at exit */ /* End of Section 4 */ #include "global.h" /* Define everything else according to choices above */ #endif /* CONFIG_H */ nethack-3.6.0/include/config1.h0000664000076400007660000001115412610522241015254 0ustar paxedpaxed/* NetHack 3.6 config1.h $NHDT-Date: 1432512781 2015/05/25 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef CONFIG1_H #define CONFIG1_H /* * MS DOS - compilers * * Microsoft C auto-defines MSDOS, * Borland C auto-defines __MSDOS__, * DJGPP auto-defines MSDOS. */ /* #define MSDOS */ /* use if not defined by compiler or cases below */ #ifdef __MSDOS__ /* for Borland C */ #ifndef MSDOS #define MSDOS #endif #endif #ifdef __TURBOC__ #define __MSC /* increase Borland C compatibility in libraries */ #endif #ifdef MSDOS #undef UNIX #endif /* * Mac Stuff. */ #if defined(__APPLE__) && defined(__MACH__) #define MACOSX #endif #ifdef macintosh /* Auto-defined symbol for MPW compilers (sc and mrc) */ #define MAC #endif #ifdef THINK_C /* Think C auto-defined symbol */ #define MAC #define NEED_VARARGS #endif #ifdef __MWERKS__ /* defined by Metrowerks' Codewarrior compiler */ #ifndef __BEOS__ /* BeOS */ #define MAC #endif #define NEED_VARARGS #define USE_STDARG #endif #if defined(MAC) || defined(__BEOS__) #define DLB #undef UNIX #endif #ifdef __BEOS__ #define NEED_VARARGS #endif /* * Amiga setup. */ #ifdef AZTEC_C /* Manx auto-defines this */ #ifdef MCH_AMIGA /* Manx auto-defines this for AMIGA */ #ifndef AMIGA #define AMIGA /* define for Commodore-Amiga */ #endif /* (SAS/C auto-defines AMIGA) */ #define AZTEC_50 /* define for version 5.0 of manx */ #endif #endif #ifdef __SASC_60 #define NEARDATA __near /* put some data close */ #else #ifdef _DCC #define NEARDATA __near /* put some data close */ #else #define NEARDATA #endif #endif #ifdef AMIGA #define NEED_VARARGS #undef UNIX #define DLB #define HACKDIR "NetHack:" #define NO_MACRO_CPATH #endif /* * Atari auto-detection */ #ifdef atarist #undef UNIX #ifndef TOS #define TOS #endif #else #ifdef __MINT__ #undef UNIX #ifndef TOS #define TOS #endif #endif #endif /* * Windows NT Autodetection */ #ifdef _WIN32_WCE #define WIN_CE #ifndef WIN32 #define WIN32 #endif #endif #if defined(_WIN32) && !defined(WIN32) #define WIN32 #endif #ifdef WIN32 #undef UNIX #undef MSDOS #define NHSTDC #define USE_STDARG #define NEED_VARARGS #ifndef WIN_CE #define STRNCMPI #define STRCMPI #endif #endif #if defined(__linux__) && defined(__GNUC__) && !defined(_GNU_SOURCE) /* ensure _GNU_SOURCE is defined before including any system headers */ #define _GNU_SOURCE #endif #ifdef VMS /* really old compilers need special handling, detected here */ #undef UNIX #ifdef __DECC #ifndef __DECC_VER /* buggy early versions want widened prototypes */ #define NOTSTDC /* except when typedefs are involved */ #define USE_VARARGS #else #define NHSTDC #define USE_STDARG #define POSIX_TYPES #define _DECC_V4_SOURCE /* avoid some incompatible V5.x changes */ #endif #undef __HIDE_FORBIDDEN_NAMES /* need non-ANSI library support functions */ #ifdef VAXC /* DEC C in VAX C compatibility mode; 'signed' works */ #define signed /* but causes diagnostic about VAX C not supporting it */ #endif #else #ifdef VAXC /* must use CC/DEFINE=ANCIENT_VAXC for vaxc v2.2 or older */ #define signed #ifdef ANCIENT_VAXC /* vaxc v2.2 and earlier [lots of warnings to come] */ #define KR1ED /* simulate defined() */ #define USE_VARARGS #else /* vaxc v2.3,2.4,or 3.x, or decc in vaxc mode */ #if defined(USE_PROTOTYPES) /* this breaks 2.2 (*forces* use of ANCIENT)*/ #define __STDC__ 0 /* vaxc is not yet ANSI compliant, but close enough */ #include #define UNWIDENED_PROTOTYPES #endif #define USE_STDARG #endif #endif /*VAXC*/ #endif /*__DECC*/ #ifdef VERYOLD_VMS /* v4.5 or earlier; no longer available for testing */ #define USE_OLDARGS /* is there, vprintf & vsprintf aren't */ #ifdef USE_VARARGS #undef USE_VARARGS #endif #ifdef USE_STDARG #undef USE_STDARG #endif #endif #endif /*VMS*/ #ifdef vax /* just in case someone thinks a DECstation is a vax. It's not, it's a mips */ #ifdef ULTRIX_PROTO #undef ULTRIX_PROTO #endif #ifdef ULTRIX_CC20 #undef ULTRIX_CC20 #endif #endif #ifdef KR1ED /* For compilers which cannot handle defined() */ #define defined(x) (-x - 1 != -1) /* Because: * #define FOO => FOO={} => defined( ) => (-1 != - - 1) => 1 * #define FOO 1 or on command-line -DFOO * => defined(1) => (-1 != - 1 - 1) => 1 * if FOO isn't defined, FOO=0. But some compilers default to 0 instead of 1 * for -DFOO, oh well. * => defined(0) => (-1 != - 0 - 1) => 0 * * But: * defined("") => (-1 != - "" - 1) * [which is an unavoidable catastrophe.] */ #endif #endif /* CONFIG1_H */ nethack-3.6.0/include/context.h0000664000076400007660000001163112622306536015424 0ustar paxedpaxed/* NetHack 3.6 context.h $NHDT-Date: 1447653421 2015/11/16 05:57:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* If you change the context structure make sure you increment EDITLEVEL in */ /* patchlevel.h if needed. */ #ifndef CONTEXT_H #define CONTEXT_H #define CONTEXTVERBSZ 30 /* * The context structure houses things that the game tracks * or adjusts during the game, to preserve game state or context. * * The entire structure is saved with the game. * */ struct dig_info { /* apply.c, hack.c */ int effort; d_level level; coord pos; long lastdigtime; boolean down, chew, warned, quiet; }; struct tin_info { struct obj *tin; unsigned o_id; /* o_id of tin in save file */ int usedtime, reqtime; }; struct book_info { struct obj *book; /* last/current book being xscribed */ unsigned o_id; /* o_id of book in save file */ schar delay; /* moves left for this spell */ }; struct takeoff_info { long mask; long what; int delay; boolean cancelled_don; char disrobing[CONTEXTVERBSZ + 1]; }; struct victual_info { struct obj *piece; /* the thing being eaten, or last thing that * was partially eaten, unless that thing was * a tin, which uses the tin structure above, * in which case this should be 0 */ unsigned o_id; /* o_id of food object in save file */ /* doeat() initializes these when piece is valid */ int usedtime, /* turns spent eating */ reqtime; /* turns required to eat */ int nmod; /* coded nutrition per turn */ Bitfield(canchoke, 1); /* was satiated at beginning */ /* start_eating() initializes these */ Bitfield(fullwarn, 1); /* have warned about being full */ Bitfield(eating, 1); /* victual currently being eaten */ Bitfield(doreset, 1); /* stop eating at end of turn */ }; struct warntype_info { unsigned long obj; /* object warn_of_mon monster type M2 */ unsigned long polyd; /* warn_of_mon monster type M2 due to poly */ struct permonst *species; /* particular species due to poly */ short speciesidx; /* index of above in mons[] (for save/restore) */ }; struct polearm_info { struct monst *hitmon; /* the monster we tried to hit last */ unsigned m_id; /* monster id of hitmon, in save file */ }; struct obj_split { unsigned parent_oid, /* set: splitobj(), */ child_oid; /* reset: clear_splitobjs() */ }; struct tribute_info { size_t tributesz; /* make it possible to skip this in future */ boolean enabled; /* Do we have tributes turned on? */ Bitfield(bookstock, 1); /* Have we stocked the book? */ Bitfield(Deathnotice,1); /* Did Death notice the book? */ /* Markers for other tributes can go here */ /* 30 free bits */ }; struct novel_tracking { /* for choosing random passage when reading novel */ unsigned id; /* novel oid from previous passage selection */ int count; /* number of passage indices available in pasg[] */ xchar pasg[30]; /* pasg[0..count] are passage indices */ }; struct context_info { unsigned ident; /* social security number for each monster */ unsigned no_of_wizards; /* 0, 1 or 2 (wizard and his shadow) */ unsigned run; /* 0: h (etc), 1: H (etc), 2: fh (etc) */ /* 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF- */ /* 8: travel */ unsigned startingpet_mid; int current_fruit; /* fruit->fid corresponding to pl_fruit[] */ int warnlevel; int rndencode; /* randomized escape sequence introducer */ long next_attrib_check; /* next attribute check */ long stethoscope_move; short stethoscope_movement; boolean travel; /* find way automatically to u.tx,u.ty */ boolean travel1; /* first travel step */ boolean forcefight; boolean nopick; /* do not pickup objects (as when running) */ boolean made_amulet; boolean mon_moving; /* monsters' turn to move */ boolean move; boolean mv; boolean bypasses; /* bypass flag is set on at least one fobj */ boolean botl; /* partially redo status line */ boolean botlx; /* print an entirely new bottom line */ boolean door_opened; /* set to true if door was opened during test_move */ struct dig_info digging; struct victual_info victual; struct tin_info tin; struct book_info spbook; struct takeoff_info takeoff; struct warntype_info warntype; struct polearm_info polearm; struct obj_split objsplit; /* track most recently split object stack */ struct tribute_info tribute; struct novel_tracking novel; }; extern NEARDATA struct context_info context; #endif /* CONTEXT_H */ nethack-3.6.0/include/coord.h0000664000076400007660000000055112536476415015055 0ustar paxedpaxed/* NetHack 3.6 coord.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef COORD_H #define COORD_H typedef struct nhcoord { xchar x, y; } coord; #endif /* COORD_H */ nethack-3.6.0/include/decl.h0000664000076400007660000003201512611126255014642 0ustar paxedpaxed/* NetHack 3.6 decl.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.76 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DECL_H #define DECL_H #define E extern E int NDECL((*occupation)); E int NDECL((*afternmv)); E const char *hname; E int hackpid; #if defined(UNIX) || defined(VMS) E int locknum; #endif #ifdef DEF_PAGER E char *catmore; #endif /* DEF_PAGER */ E char SAVEF[]; #ifdef MICRO E char SAVEP[]; #endif E NEARDATA int bases[MAXOCLASSES]; E NEARDATA int multi; E const char *multi_reason; E NEARDATA int nroom; E NEARDATA int nsubroom; E NEARDATA int occtime; #define WARNCOUNT 6 /* number of different warning levels */ E nhsym warnsyms[WARNCOUNT]; E NEARDATA int warn_obj_cnt; /* count of monsters meeting criteria */ E int x_maze_max, y_maze_max; E int otg_temp; E NEARDATA int in_doagain; E struct dgn_topology { /* special dungeon levels for speed */ d_level d_oracle_level; d_level d_bigroom_level; /* unused */ d_level d_rogue_level; d_level d_medusa_level; d_level d_stronghold_level; d_level d_valley_level; d_level d_wiz1_level; d_level d_wiz2_level; d_level d_wiz3_level; d_level d_juiblex_level; d_level d_orcus_level; d_level d_baalzebub_level; /* unused */ d_level d_asmodeus_level; /* unused */ d_level d_portal_level; /* only in goto_level() [do.c] */ d_level d_sanctum_level; d_level d_earth_level; d_level d_water_level; d_level d_fire_level; d_level d_air_level; d_level d_astral_level; xchar d_tower_dnum; xchar d_sokoban_dnum; xchar d_mines_dnum, d_quest_dnum; d_level d_qstart_level, d_qlocate_level, d_nemesis_level; d_level d_knox_level; d_level d_mineend_level; d_level d_sokoend_level; } dungeon_topology; /* macros for accessing the dungeon levels by their old names */ /* clang-format off */ #define oracle_level (dungeon_topology.d_oracle_level) #define bigroom_level (dungeon_topology.d_bigroom_level) #define rogue_level (dungeon_topology.d_rogue_level) #define medusa_level (dungeon_topology.d_medusa_level) #define stronghold_level (dungeon_topology.d_stronghold_level) #define valley_level (dungeon_topology.d_valley_level) #define wiz1_level (dungeon_topology.d_wiz1_level) #define wiz2_level (dungeon_topology.d_wiz2_level) #define wiz3_level (dungeon_topology.d_wiz3_level) #define juiblex_level (dungeon_topology.d_juiblex_level) #define orcus_level (dungeon_topology.d_orcus_level) #define baalzebub_level (dungeon_topology.d_baalzebub_level) #define asmodeus_level (dungeon_topology.d_asmodeus_level) #define portal_level (dungeon_topology.d_portal_level) #define sanctum_level (dungeon_topology.d_sanctum_level) #define earth_level (dungeon_topology.d_earth_level) #define water_level (dungeon_topology.d_water_level) #define fire_level (dungeon_topology.d_fire_level) #define air_level (dungeon_topology.d_air_level) #define astral_level (dungeon_topology.d_astral_level) #define tower_dnum (dungeon_topology.d_tower_dnum) #define sokoban_dnum (dungeon_topology.d_sokoban_dnum) #define mines_dnum (dungeon_topology.d_mines_dnum) #define quest_dnum (dungeon_topology.d_quest_dnum) #define qstart_level (dungeon_topology.d_qstart_level) #define qlocate_level (dungeon_topology.d_qlocate_level) #define nemesis_level (dungeon_topology.d_nemesis_level) #define knox_level (dungeon_topology.d_knox_level) #define mineend_level (dungeon_topology.d_mineend_level) #define sokoend_level (dungeon_topology.d_sokoend_level) /* clang-format on */ E NEARDATA stairway dnstair, upstair; /* stairs up and down */ #define xdnstair (dnstair.sx) #define ydnstair (dnstair.sy) #define xupstair (upstair.sx) #define yupstair (upstair.sy) E NEARDATA stairway dnladder, upladder; /* ladders up and down */ #define xdnladder (dnladder.sx) #define ydnladder (dnladder.sy) #define xupladder (upladder.sx) #define yupladder (upladder.sy) E NEARDATA stairway sstairs; E NEARDATA dest_area updest, dndest; /* level-change destination areas */ E NEARDATA coord inv_pos; E NEARDATA dungeon dungeons[]; E NEARDATA s_level *sp_levchn; #define dunlev_reached(x) (dungeons[(x)->dnum].dunlev_ureached) #include "quest.h" E struct q_score quest_status; E NEARDATA char pl_character[PL_CSIZ]; E NEARDATA char pl_race; /* character's race */ E NEARDATA char pl_fruit[PL_FSIZ]; E NEARDATA struct fruit *ffruit; E NEARDATA char tune[6]; #define MAXLINFO (MAXDUNGEON * MAXLEVEL) E struct linfo level_info[MAXLINFO]; E NEARDATA struct sinfo { int gameover; /* self explanatory? */ int stopprint; /* inhibit further end of game disclosure */ #ifdef HANGUPHANDLING volatile int done_hup; /* SIGHUP or moral equivalent received * -- no more screen output */ int preserve_locks; /* don't remove level files prior to exit */ #endif int something_worth_saving; /* in case of panic */ int panicking; /* `panic' is in progress */ int exiting; /* an exit handler is executing */ int in_moveloop; int in_impossible; #ifdef PANICLOG int in_paniclog; #endif int wizkit_wishing; } program_state; E boolean restoring; E const char quitchars[]; E const char vowels[]; E const char ynchars[]; E const char ynqchars[]; E const char ynaqchars[]; E const char ynNaqchars[]; E NEARDATA long yn_number; E const char disclosure_options[]; E NEARDATA int smeq[]; E NEARDATA int doorindex; E NEARDATA char *save_cm; E NEARDATA struct kinfo { struct kinfo *next; /* chain of delayed killers */ int id; /* uprop keys to ID a delayed killer */ int format; /* one of the killer formats */ #define KILLED_BY_AN 0 #define KILLED_BY 1 #define NO_KILLER_PREFIX 2 char name[BUFSZ]; /* actual killer name */ } killer; E long done_money; E const char *configfile; E char lastconfigfile[BUFSZ]; /* used for messaging */ E NEARDATA char plname[PL_NSIZ]; E NEARDATA char dogname[]; E NEARDATA char catname[]; E NEARDATA char horsename[]; E char preferred_pet; E const char *occtxt; /* defined when occupation != NULL */ E const char *nomovemsg; E char lock[]; E const schar xdir[], ydir[], zdir[]; E NEARDATA schar tbx, tby; /* set in mthrowu.c */ E NEARDATA struct multishot { int n, i; short o; boolean s; } m_shot; E NEARDATA long moves, monstermoves; E NEARDATA long wailmsg; E NEARDATA boolean in_mklev; E NEARDATA boolean stoned; E NEARDATA boolean unweapon; E NEARDATA boolean mrg_to_wielded; E NEARDATA boolean defer_see_monsters; E NEARDATA boolean in_steed_dismounting; E const int shield_static[]; #include "spell.h" E NEARDATA struct spell spl_book[]; /* sized in decl.c */ #include "color.h" #ifdef TEXTCOLOR E const int zapcolors[]; #endif E const struct class_sym def_oc_syms[MAXOCLASSES]; /* default class symbols */ E uchar oc_syms[MAXOCLASSES]; /* current class symbols */ E const struct class_sym def_monsyms[MAXMCLASSES]; /* default class symbols */ E uchar monsyms[MAXMCLASSES]; /* current class symbols */ #include "obj.h" E NEARDATA struct obj *invent, *uarm, *uarmc, *uarmh, *uarms, *uarmg, *uarmf, *uarmu, /* under-wear, so to speak */ *uskin, *uamul, *uleft, *uright, *ublindf, *uwep, *uswapwep, *uquiver; E NEARDATA struct obj *uchain; /* defined only when punished */ E NEARDATA struct obj *uball; E NEARDATA struct obj *migrating_objs; E NEARDATA struct obj *billobjs; E NEARDATA struct obj *current_wand, *thrownobj, *kickedobj; E NEARDATA struct obj zeroobj; /* init'd and defined in decl.c */ E NEARDATA anything zeroany; /* init'd and defined in decl.c */ #include "you.h" E NEARDATA struct you u; E NEARDATA time_t ubirthday; E NEARDATA struct u_realtime urealtime; #include "onames.h" #ifndef PM_H /* (pm.h has already been included via youprop.h) */ #include "pm.h" #endif E NEARDATA struct monst youmonst; /* init'd and defined in decl.c */ E NEARDATA struct monst *mydogs, *migrating_mons; E NEARDATA struct mvitals { uchar born; uchar died; uchar mvflags; } mvitals[NUMMONS]; E NEARDATA struct c_color_names { const char *const c_black, *const c_amber, *const c_golden, *const c_light_blue, *const c_red, *const c_green, *const c_silver, *const c_blue, *const c_purple, *const c_white, *const c_orange; } c_color_names; #define NH_BLACK c_color_names.c_black #define NH_AMBER c_color_names.c_amber #define NH_GOLDEN c_color_names.c_golden #define NH_LIGHT_BLUE c_color_names.c_light_blue #define NH_RED c_color_names.c_red #define NH_GREEN c_color_names.c_green #define NH_SILVER c_color_names.c_silver #define NH_BLUE c_color_names.c_blue #define NH_PURPLE c_color_names.c_purple #define NH_WHITE c_color_names.c_white #define NH_ORANGE c_color_names.c_orange /* The names of the colors used for gems, etc. */ E const char *c_obj_colors[]; E struct c_common_strings { const char *const c_nothing_happens, *const c_thats_enough_tries, *const c_silly_thing_to, *const c_shudder_for_moment, *const c_something, *const c_Something, *const c_You_can_move_again, *const c_Never_mind, *c_vision_clears, *const c_the_your[2]; } c_common_strings; #define nothing_happens c_common_strings.c_nothing_happens #define thats_enough_tries c_common_strings.c_thats_enough_tries #define silly_thing_to c_common_strings.c_silly_thing_to #define shudder_for_moment c_common_strings.c_shudder_for_moment #define something c_common_strings.c_something #define Something c_common_strings.c_Something #define You_can_move_again c_common_strings.c_You_can_move_again #define Never_mind c_common_strings.c_Never_mind #define vision_clears c_common_strings.c_vision_clears #define the_your c_common_strings.c_the_your /* material strings */ E const char *materialnm[]; /* Monster name articles */ #define ARTICLE_NONE 0 #define ARTICLE_THE 1 #define ARTICLE_A 2 #define ARTICLE_YOUR 3 /* Monster name suppress masks */ #define SUPPRESS_IT 0x01 #define SUPPRESS_INVISIBLE 0x02 #define SUPPRESS_HALLUCINATION 0x04 #define SUPPRESS_SADDLE 0x08 #define EXACT_NAME 0x0F /* Vision */ E NEARDATA boolean vision_full_recalc; /* TRUE if need vision recalc */ E NEARDATA char **viz_array; /* could see/in sight row pointers */ /* Window system stuff */ E NEARDATA winid WIN_MESSAGE; #ifndef STATUS_VIA_WINDOWPORT E NEARDATA winid WIN_STATUS; #endif E NEARDATA winid WIN_MAP, WIN_INVEN; /* pline (et al) for a single string argument (suppress compiler warning) */ #define pline1(cstr) pline("%s", cstr) #define Your1(cstr) Your("%s", cstr) #define You1(cstr) You("%s", cstr) #define verbalize1(cstr) verbalize("%s", cstr) #define You_hear1(cstr) You_hear("%s", cstr) #define Sprintf1(buf, cstr) Sprintf(buf, "%s", cstr) #define panic1(cstr) panic("%s", cstr) E char toplines[]; #ifndef TCAP_H E struct tc_gbl_data { /* also declared in tcap.h */ char *tc_AS, *tc_AE; /* graphics start and end (tty font swapping) */ int tc_LI, tc_CO; /* lines and columns */ } tc_gbl_data; #define AS tc_gbl_data.tc_AS #define AE tc_gbl_data.tc_AE #define LI tc_gbl_data.tc_LI #define CO tc_gbl_data.tc_CO #endif /* xxxexplain[] is in drawing.c */ E const char *const monexplain[], invisexplain[], *const oclass_names[]; /* Some systems want to use full pathnames for some subsets of file names, * rather than assuming that they're all in the current directory. This * provides all the subclasses that seem reasonable, and sets up for all * prefixes being null. Port code can set those that it wants. */ #define HACKPREFIX 0 #define LEVELPREFIX 1 #define SAVEPREFIX 2 #define BONESPREFIX 3 #define DATAPREFIX 4 /* this one must match hardcoded value in dlb.c */ #define SCOREPREFIX 5 #define LOCKPREFIX 6 #define SYSCONFPREFIX 7 #define CONFIGPREFIX 8 #define TROUBLEPREFIX 9 #define PREFIX_COUNT 10 /* used in files.c; xxconf.h can override if needed */ #ifndef FQN_MAX_FILENAME #define FQN_MAX_FILENAME 512 #endif #if defined(NOCWD_ASSUMPTIONS) || defined(VAR_PLAYGROUND) /* the bare-bones stuff is unconditional above to simplify coding; for * ports that actually use prefixes, add some more localized things */ #define PREFIXES_IN_USE #endif E char *fqn_prefix[PREFIX_COUNT]; #ifdef PREFIXES_IN_USE E char *fqn_prefix_names[PREFIX_COUNT]; #endif E NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo; struct autopickup_exception { struct nhregex *regex; char *pattern; boolean grab; struct autopickup_exception *next; }; struct plinemsg_type { xchar msgtype; /* one of MSGTYP_foo */ struct nhregex *regex; char *pattern; struct plinemsg_type *next; }; #define MSGTYP_NORMAL 0 #define MSGTYP_NOREP 1 #define MSGTYP_NOSHOW 2 #define MSGTYP_STOP 3 E struct plinemsg_type *plinemsg_types; #ifdef PANICTRACE E char *ARGV0; #endif #undef E #endif /* DECL_H */ nethack-3.6.0/include/def_os2.h0000664000076400007660000001041412536476415015267 0ustar paxedpaxed/* NetHack 3.6 def_os2.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * Only a small portion of all OS/2 defines are needed, so the * actual include files often need not be used. In fact, * including the full headers may stall the compile in DOS. */ #ifdef OS2_USESYSHEADERS #define INCL_NOPMAPI #define INCL_DOSFILEMGR #define INCL_DOS #define INCL_SUB #include #else typedef char CHAR; typedef void VOID; typedef unsigned char UCHAR; typedef unsigned short USHORT; typedef unsigned int UINT; typedef unsigned long ULONG; typedef unsigned char BYTE; #ifdef OS2_32BITAPI typedef unsigned long SHANDLE; typedef USHORT HKBD; typedef USHORT HVIO; #define CCHMAXPATHCOMP 256 #ifdef OS2_CSET2 #define API16 _Far16 _Pascal #define DAT16 #define API32 _System #define KbdGetStatus KBD16GETSTATUS #define KbdSetStatus KBD16SETSTATUS #define KbdCharIn KBD16CHARIN #define KbdPeek KBD16PEEK #define VioGetMode VIO16GETMODE #define VioSetCurPos VIO16SETCURPOS #else #define API16 #define DAT16 #define API32 #endif #define DAT #else /* OS2_32BITAPI */ typedef unsigned short SHANDLE; typedef SHANDLE HKBD; typedef SHANDLE HVIO; #define CCHMAXPATHCOMP 13 #ifdef OS2_MSC #define API16 pascal far #define DAT16 #endif #define DAT DAT16 #endif /* OS2_32BITAPI */ typedef USHORT *DAT16 PUSHORT; typedef BYTE *DAT16 PBYTE; typedef ULONG *DAT PULONG; typedef VOID *DAT PVOID; typedef SHANDLE HDIR; typedef HDIR *DAT PHDIR; typedef char *DAT16 PCH; typedef char *DAT PSZ; /* all supported compilers understand this */ #pragma pack(2) typedef struct { UCHAR chChar; UCHAR chScan; UCHAR fbStatus; UCHAR bNlsShift; USHORT fsState; ULONG time; } KBDKEYINFO; typedef KBDKEYINFO *DAT16 PKBDKEYINFO; /* File time and date types */ typedef struct { UINT twosecs : 5; UINT minutes : 6; UINT hours : 5; } FTIME; typedef struct { UINT day : 5; UINT month : 4; UINT year : 7; } FDATE; #ifdef OS2_32BITAPI typedef struct { ULONG oNextEntryOffset; FDATE fdateCreation; FTIME ftimeCreation; FDATE fdateLastAccess; FTIME ftimeLastAccess; FDATE fdateLastWrite; FTIME ftimeLastWrite; ULONG cbFile; ULONG cbFileAlloc; ULONG attrFile; UCHAR cchName; CHAR achName[CCHMAXPATHCOMP]; } FILEFINDBUF3; #else typedef struct { FDATE fdateCreation; FTIME ftimeCreation; FDATE fdateLastAccess; FTIME ftimeLastAccess; FDATE fdateLastWrite; FTIME ftimeLastWrite; ULONG cbFile; ULONG cbFileAlloc; USHORT attrFile; UCHAR cchName; CHAR achName[CCHMAXPATHCOMP]; } FILEFINDBUF; typedef FILEFINDBUF *DAT16 PFILEFINDBUF; #endif /* OS2_32BITAPI */ typedef struct { ULONG idFileSystem; ULONG cSectorUnit; ULONG cUnit; ULONG cUnitAvail; USHORT cbSector; } FSALLOCATE; typedef struct { USHORT cb; USHORT fsMask; USHORT chTurnAround; USHORT fsInterim; USHORT fsState; } KBDINFO; typedef KBDINFO *DAT16 PKBDINFO; typedef struct { USHORT cb; UCHAR fbType; UCHAR color; USHORT col; USHORT row; USHORT hres; USHORT vres; UCHAR fmt_ID; UCHAR attrib; ULONG buf_addr; ULONG buf_length; ULONG full_length; ULONG partial_length; PCH ext_data_addr; } VIOMODEINFO; typedef VIOMODEINFO *DAT16 PVIOMODEINFO; #pragma pack() /* OS2 API functions */ USHORT API16 KbdGetStatus(PKBDINFO, HKBD); USHORT API16 KbdSetStatus(PKBDINFO, HKBD); USHORT API16 KbdCharIn(PKBDKEYINFO, USHORT, HKBD); USHORT API16 KbdPeek(PKBDKEYINFO, HKBD); USHORT API16 VioGetMode(PVIOMODEINFO, HVIO); USHORT API16 VioSetCurPos(USHORT, USHORT, HVIO); #ifdef OS2_32BITAPI ULONG API32 DosQueryFSInfo(ULONG, ULONG, PVOID, ULONG); ULONG API32 DosFindFirst(PSZ, PHDIR, ULONG, PVOID, ULONG, PULONG, ULONG); ULONG API32 DosFindNext(HDIR, PVOID, ULONG, PULONG); ULONG API32 DosSetDefaultDisk(ULONG); #else USHORT API16 DosQFSInfo(USHORT, USHORT, PBYTE, USHORT); USHORT API16 DosFindFirst(PSZ, PHDIR, USHORT, PFILEFINDBUF, USHORT, PUSHORT, ULONG); USHORT API16 DosFindNext(HDIR, PFILEFINDBUF, USHORT, PUSHORT); USHORT API16 DosSelectDisk(USHORT); #endif /* OS2_32BITAPI */ #endif /* OS2_USESYSHEADERS */ nethack-3.6.0/include/dgn_file.h0000664000076400007660000000331012536476415015512 0ustar paxedpaxed/* NetHack 3.6 dgn_file.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) 1989 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DGN_FILE_H #define DGN_FILE_H #ifndef ALIGN_H #include "align.h" #endif /* * Structures manipulated by the dungeon loader & compiler */ struct couple { short base, rand; }; struct tmpdungeon { char name[24], protoname[24]; struct couple lev; int flags, chance, levels, branches, entry_lev; /* entry level for this dungeon */ char boneschar; }; struct tmplevel { char name[24]; struct couple lev; int chance, rndlevs, chain, flags; char boneschar; }; struct tmpbranch { char name[24]; /* destination dungeon name */ struct couple lev; int chain; /* index into tmplevel array (chained branch)*/ int type; /* branch type (see below) */ int up; /* branch is up or down */ }; /* * Values for type for tmpbranch structure. */ #define TBR_STAIR 0 /* connection with both ends having a staircase */ #define TBR_NO_UP 1 /* connection with no up staircase */ #define TBR_NO_DOWN 2 /* connection with no down staircase */ #define TBR_PORTAL 3 /* portal connection */ /* * Flags that map into the dungeon flags bitfields. */ #define TOWN 1 /* levels only */ #define HELLISH 2 #define MAZELIKE 4 #define ROGUELIKE 8 #define D_ALIGN_NONE 0 #define D_ALIGN_CHAOTIC (AM_CHAOTIC << 4) #define D_ALIGN_NEUTRAL (AM_NEUTRAL << 4) #define D_ALIGN_LAWFUL (AM_LAWFUL << 4) #define D_ALIGN_MASK 0x70 /* * Max number of prototype levels and branches. */ #define LEV_LIMIT 50 #define BRANCH_LIMIT 32 #endif /* DGN_FILE_H */ nethack-3.6.0/include/display.h0000664000076400007660000004320412623162643015406 0ustar paxedpaxed/* NetHack 3.6 display.h $NHDT-Date: 1447729027 2015/11/17 02:57:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DISPLAY_H #define DISPLAY_H #ifndef VISION_H #include "vision.h" #endif #ifndef MONDATA_H #include "mondata.h" /* for mindless() */ #endif /* * vobj_at() * * Returns the head of the list of objects that the player can see * at location (x,y). */ #define vobj_at(x, y) (level.objects[x][y]) /* * sensemon() * * Returns true if the hero can sense the given monster. This includes * monsters that are hiding or mimicing other monsters. */ #define tp_sensemon(mon) \ (/* The hero can always sense a monster IF: */ \ /* 1. the monster has a brain to sense */ \ (!mindless(mon->data)) \ /* AND 2a. hero is blind and telepathic */ \ && ((Blind && Blind_telepat) \ /* OR 2b. hero is using a telepathy inducing */ \ /* object and in range */ \ || (Unblind_telepat \ && (distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM))))) #define sensemon(mon) \ (tp_sensemon(mon) || Detect_monsters || MATCH_WARN_OF_MON(mon)) /* * mon_warning() is used to warn of any dangerous monsters in your * vicinity, and a glyph representing the warning level is displayed. */ #define mon_warning(mon) \ (Warning && !(mon)->mpeaceful && (distu((mon)->mx, (mon)->my) < 100) \ && (((int) ((mon)->m_lev / 4)) >= context.warnlevel)) /* * mon_visible() * * Returns true if the hero can see the monster. It is assumed that the * hero can physically see the location of the monster. The function * vobj_at() returns a pointer to an object that the hero can see there. * Infravision is not taken into account. */ #define mon_visible(mon) \ (/* The hero can see the monster IF the monster */ \ (!mon->minvis || See_invisible) /* 1. is not invisible */ \ && !mon->mundetected /* AND 2. not an undetected hider */ \ && !(mon->mburied || u.uburied)) /* AND 3. neither you nor it is buried */ /* * see_with_infrared() * * This function is true if the player can see a monster using infravision. * The caller must check for invisibility (invisible monsters are also * invisible to infravision), because this is usually called from within * canseemon() or canspotmon() which already check that. */ #define see_with_infrared(mon) \ (!Blind && Infravision && mon && infravisible(mon->data) \ && couldsee(mon->mx, mon->my)) /* * canseemon() * * This is the globally used canseemon(). It is not called within the display * routines. Like mon_visible(), but it checks to see if the hero sees the * location instead of assuming it. (And also considers worms.) */ #define canseemon(mon) \ ((mon->wormno ? worm_known(mon) \ : (cansee(mon->mx, mon->my) || see_with_infrared(mon))) \ && mon_visible(mon)) /* * canspotmon(mon) * * This function checks whether you can either see a monster or sense it by * telepathy, and is what you usually call for monsters about which nothing is * known. */ #define canspotmon(mon) (canseemon(mon) || sensemon(mon)) /* knowninvisible(mon) * This one checks to see if you know a monster is both there and invisible. * 1) If you can see the monster and have see invisible, it is assumed the * monster is transparent, but visible in some manner. (Earlier versions of * Nethack were really inconsistent on this.) * 2) If you can't see the monster, but can see its location and you have * telepathy that works when you can see, you can tell that there is a * creature in an apparently empty spot. * Infravision is not relevant; we assume that invisible monsters are also * invisible to infravision. */ #define knowninvisible(mon) \ (mtmp->minvis \ && ((cansee(mon->mx, mon->my) && (See_invisible || Detect_monsters)) \ || (!Blind && (HTelepat & ~INTRINSIC) \ && distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM)))) /* * is_safepet(mon) * * A special case check used in attack() and domove(). Placing the * definition here is convenient. */ #define is_safepet(mon) \ (mon && mon->mtame && canspotmon(mon) && flags.safe_dog && !Confusion \ && !Hallucination && !Stunned) /* * canseeself() * senseself() * canspotself() * * This returns true if the hero can see her/himself. * * Sensing yourself by touch is treated as seeing yourself, even if * unable to see. So when blind, being invisible won't affect your * self-perception, and when swallowed, the enclosing monster touches. */ #define canseeself() (Blind || u.uswallow || (!Invisible && !u.uundetected)) #define senseself() (Unblind_telepat || Detect_monsters) #define canspotself() (canseeself() || senseself()) /* * random_monster() * random_object() * random_trap() * * Respectively return a random monster, object, or trap number. */ #define random_monster() rn2(NUMMONS) #define random_object() rn1(NUM_OBJECTS - 1, 1) #define random_trap() rn1(TRAPNUM - 1, 1) /* * what_obj() * what_mon() * what_trap() * * If hallucinating, choose a random object/monster, otherwise, use the one * given. */ #define what_obj(obj) (Hallucination ? random_object() : obj) #define what_mon(mon) (Hallucination ? random_monster() : mon) #define what_trap(trp) (Hallucination ? random_trap() : trp) /* * covers_objects() * covers_traps() * * These routines are true if what is really at the given location will * "cover" any objects or traps that might be there. */ #define covers_objects(xx, yy) \ ((is_pool(xx, yy) && !Underwater) || (levl[xx][yy].typ == LAVAPOOL)) #define covers_traps(xx, yy) covers_objects(xx, yy) /* * tmp_at() control calls. */ #define DISP_BEAM (-1) /* Keep all glyphs showing & clean up at end. */ #define DISP_ALL (-2) /* Like beam, but still displayed if not visible. */ #define DISP_FLASH (-3) /* Clean up each glyph before displaying new one. */ #define DISP_ALWAYS (-4) /* Like flash, but still displayed if not visible. */ #define DISP_CHANGE (-5) /* Change glyph. */ #define DISP_END (-6) /* Clean up. */ #define DISP_FREEMEM (-7) /* Free all memory during exit only. */ /* Total number of cmap indices in the shield_static[] array. */ #define SHIELD_COUNT 21 /* * display_self() * * Display the hero. It is assumed that all checks necessary to determine * _if_ the hero can be seen have already been done. */ #define maybe_display_usteed(otherwise_self) \ ((u.usteed && mon_visible(u.usteed)) ? ridden_mon_to_glyph(u.usteed) \ : (otherwise_self)) #define display_self() \ show_glyph(u.ux, u.uy, \ maybe_display_usteed((youmonst.m_ap_type == M_AP_NOTHING) \ ? hero_glyph \ : (youmonst.m_ap_type == M_AP_FURNITURE) \ ? cmap_to_glyph(youmonst.mappearance) \ : (youmonst.m_ap_type == M_AP_OBJECT) \ ? objnum_to_glyph(youmonst.mappearance) \ /* else M_AP_MONSTER */ \ : monnum_to_glyph(youmonst.mappearance))) /* * A glyph is an abstraction that represents a _unique_ monster, object, * dungeon part, or effect. The uniqueness is important. For example, * It is not enough to have four (one for each "direction") zap beam glyphs, * we need a set of four for each beam type. Why go to so much trouble? * Because it is possible that any given window dependent display driver * [print_glyph()] can produce something different for each type of glyph. * That is, a beam of cold and a beam of fire would not only be different * colors, but would also be represented by different symbols. * * Glyphs are grouped for easy accessibility: * * monster Represents all the wild (not tame) monsters. Count: NUMMONS. * * pet Represents all of the tame monsters. Count: NUMMONS * * invisible Invisible monster placeholder. Count: 1 * * detect Represents all detected monsters. Count: NUMMONS * * corpse One for each monster. Count: NUMMONS * * ridden Represents all monsters being ridden. Count: NUMMONS * * object One for each object. Count: NUM_OBJECTS * * cmap One for each entry in the character map. The character map * is the dungeon features and other miscellaneous things. * Count: MAXPCHARS * * explosions A set of nine for each of the following seven explosion types: * dark, noxious, muddy, wet, magical, fiery, frosty. * The nine positions represent those surrounding the hero. * Count: MAXEXPCHARS * EXPL_MAX (EXPL_MAX is defined in hack.h) * * zap beam A set of four (there are four directions) for each beam type. * The beam type is shifted over 2 positions and the direction * is stored in the lower 2 bits. Count: NUM_ZAP << 2 * * swallow A set of eight for each monster. The eight positions rep- * resent those surrounding the hero. The monster number is * shifted over 3 positions and the swallow position is stored * in the lower three bits. Count: NUMMONS << 3 * * warning A set of six representing the different warning levels. * * The following are offsets used to convert to and from a glyph. */ #define NUM_ZAP 8 /* number of zap beam types */ #define GLYPH_MON_OFF 0 #define GLYPH_PET_OFF (NUMMONS + GLYPH_MON_OFF) #define GLYPH_INVIS_OFF (NUMMONS + GLYPH_PET_OFF) #define GLYPH_DETECT_OFF (1 + GLYPH_INVIS_OFF) #define GLYPH_BODY_OFF (NUMMONS + GLYPH_DETECT_OFF) #define GLYPH_RIDDEN_OFF (NUMMONS + GLYPH_BODY_OFF) #define GLYPH_OBJ_OFF (NUMMONS + GLYPH_RIDDEN_OFF) #define GLYPH_CMAP_OFF (NUM_OBJECTS + GLYPH_OBJ_OFF) #define GLYPH_EXPLODE_OFF ((MAXPCHARS - MAXEXPCHARS) + GLYPH_CMAP_OFF) #define GLYPH_ZAP_OFF ((MAXEXPCHARS * EXPL_MAX) + GLYPH_EXPLODE_OFF) #define GLYPH_SWALLOW_OFF ((NUM_ZAP << 2) + GLYPH_ZAP_OFF) #define GLYPH_WARNING_OFF ((NUMMONS << 3) + GLYPH_SWALLOW_OFF) #define GLYPH_STATUE_OFF (WARNCOUNT + GLYPH_WARNING_OFF) #define MAX_GLYPH (NUMMONS + GLYPH_STATUE_OFF) #define NO_GLYPH MAX_GLYPH #define GLYPH_INVISIBLE GLYPH_INVIS_OFF #define warning_to_glyph(mwarnlev) ((mwarnlev) + GLYPH_WARNING_OFF) #define mon_to_glyph(mon) \ ((int) what_mon(monsndx((mon)->data)) + GLYPH_MON_OFF) #define detected_mon_to_glyph(mon) \ ((int) what_mon(monsndx((mon)->data)) + GLYPH_DETECT_OFF) #define ridden_mon_to_glyph(mon) \ ((int) what_mon(monsndx((mon)->data)) + GLYPH_RIDDEN_OFF) #define pet_to_glyph(mon) \ ((int) what_mon(monsndx((mon)->data)) + GLYPH_PET_OFF) /* This has the unfortunate side effect of needing a global variable */ /* to store a result. 'otg_temp' is defined and declared in decl.{ch}. */ #define random_obj_to_glyph() \ ((otg_temp = random_object()) == CORPSE \ ? random_monster() + GLYPH_BODY_OFF \ : otg_temp + GLYPH_OBJ_OFF) #define obj_to_glyph(obj) \ (((obj)->otyp == STATUE) \ ? statue_to_glyph(obj) \ : Hallucination \ ? random_obj_to_glyph() \ : ((obj)->otyp == CORPSE) \ ? (int) (obj)->corpsenm + GLYPH_BODY_OFF \ : (int) (obj)->otyp + GLYPH_OBJ_OFF) /* MRKR: Statues now have glyphs corresponding to the monster they */ /* represent and look like monsters when you are hallucinating. */ #define statue_to_glyph(obj) \ (Hallucination ? random_monster() + GLYPH_MON_OFF \ : (int) (obj)->corpsenm + GLYPH_STATUE_OFF) #define cmap_to_glyph(cmap_idx) ((int) (cmap_idx) + GLYPH_CMAP_OFF) #define explosion_to_glyph(expltype, idx) \ ((((expltype) * MAXEXPCHARS) + ((idx) - S_explode1)) + GLYPH_EXPLODE_OFF) #define trap_to_glyph(trap) \ cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp))) /* Not affected by hallucination. Gives a generic body for CORPSE */ /* MRKR: ...and the generic statue */ #define objnum_to_glyph(onum) ((int) (onum) + GLYPH_OBJ_OFF) #define monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_MON_OFF) #define detected_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_DETECT_OFF) #define ridden_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_RIDDEN_OFF) #define petnum_to_glyph(mnum) ((int) (mnum) + GLYPH_PET_OFF) /* The hero's glyph when seen as a monster. */ #define hero_glyph \ monnum_to_glyph((Upolyd || !flags.showrace) \ ? u.umonnum \ : (flags.female && urace.femalenum != NON_PM) \ ? urace.femalenum \ : urace.malenum) /* * Change the given glyph into it's given type. Note: * 1) Pets, detected, and ridden monsters are animals and are converted * to the proper monster number. * 2) Bodies are all mapped into the generic CORPSE object * 3) If handed a glyph out of range for the type, these functions * will return NO_GLYPH (see exception below) * 4) glyph_to_swallow() does not return a showsyms[] index, but an * offset from the first swallow symbol. If handed something * out of range, it will return zero (for lack of anything better * to return). */ #define glyph_to_mon(glyph) \ (glyph_is_normal_monster(glyph) \ ? ((glyph) - GLYPH_MON_OFF) \ : glyph_is_pet(glyph) \ ? ((glyph) - GLYPH_PET_OFF) \ : glyph_is_detected_monster(glyph) \ ? ((glyph) - GLYPH_DETECT_OFF) \ : glyph_is_ridden_monster(glyph) \ ? ((glyph) - GLYPH_RIDDEN_OFF) \ : glyph_is_statue(glyph) \ ? ((glyph) - GLYPH_STATUE_OFF) \ : NO_GLYPH) #define glyph_to_obj(glyph) \ (glyph_is_body(glyph) \ ? CORPSE \ : glyph_is_statue(glyph) \ ? STATUE \ : glyph_is_normal_object(glyph) \ ? ((glyph) - GLYPH_OBJ_OFF) \ : NO_GLYPH) #define glyph_to_trap(glyph) \ (glyph_is_trap(glyph) ? ((int) defsym_to_trap((glyph) - GLYPH_CMAP_OFF)) \ : NO_GLYPH) #define glyph_to_cmap(glyph) \ (glyph_is_cmap(glyph) ? ((glyph) - GLYPH_CMAP_OFF) : NO_GLYPH) #define glyph_to_swallow(glyph) \ (glyph_is_swallow(glyph) ? (((glyph) - GLYPH_SWALLOW_OFF) & 0x7) : 0) #define glyph_to_warning(glyph) \ (glyph_is_warning(glyph) ? ((glyph) - GLYPH_WARNING_OFF) : NO_GLYPH); /* * Return true if the given glyph is what we want. Note that bodies are * considered objects. */ #define glyph_is_monster(glyph) \ (glyph_is_normal_monster(glyph) || glyph_is_pet(glyph) \ || glyph_is_ridden_monster(glyph) || glyph_is_detected_monster(glyph)) #define glyph_is_normal_monster(glyph) \ ((glyph) >= GLYPH_MON_OFF && (glyph) < (GLYPH_MON_OFF + NUMMONS)) #define glyph_is_pet(glyph) \ ((glyph) >= GLYPH_PET_OFF && (glyph) < (GLYPH_PET_OFF + NUMMONS)) #define glyph_is_body(glyph) \ ((glyph) >= GLYPH_BODY_OFF && (glyph) < (GLYPH_BODY_OFF + NUMMONS)) #define glyph_is_statue(glyph) \ ((glyph) >= GLYPH_STATUE_OFF && (glyph) < (GLYPH_STATUE_OFF + NUMMONS)) #define glyph_is_ridden_monster(glyph) \ ((glyph) >= GLYPH_RIDDEN_OFF && (glyph) < (GLYPH_RIDDEN_OFF + NUMMONS)) #define glyph_is_detected_monster(glyph) \ ((glyph) >= GLYPH_DETECT_OFF && (glyph) < (GLYPH_DETECT_OFF + NUMMONS)) #define glyph_is_invisible(glyph) ((glyph) == GLYPH_INVISIBLE) #define glyph_is_normal_object(glyph) \ ((glyph) >= GLYPH_OBJ_OFF && (glyph) < (GLYPH_OBJ_OFF + NUM_OBJECTS)) #define glyph_is_object(glyph) \ (glyph_is_normal_object(glyph) || glyph_is_statue(glyph) \ || glyph_is_body(glyph)) #define glyph_is_trap(glyph) \ ((glyph) >= (GLYPH_CMAP_OFF + trap_to_defsym(1)) \ && (glyph) < (GLYPH_CMAP_OFF + trap_to_defsym(1) + TRAPNUM)) #define glyph_is_cmap(glyph) \ ((glyph) >= GLYPH_CMAP_OFF && (glyph) < (GLYPH_CMAP_OFF + MAXPCHARS)) #define glyph_is_swallow(glyph) \ ((glyph) >= GLYPH_SWALLOW_OFF \ && (glyph) < (GLYPH_SWALLOW_OFF + (NUMMONS << 3))) #define glyph_is_warning(glyph) \ ((glyph) >= GLYPH_WARNING_OFF \ && (glyph) < (GLYPH_WARNING_OFF + WARNCOUNT)) #endif /* DISPLAY_H */ nethack-3.6.0/include/dlb.h0000664000076400007660000000714612536476415014517 0ustar paxedpaxed/* NetHack 3.6 dlb.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DLB_H #define DLB_H /* definitions for data library */ #ifdef DLB /* implementations */ #ifdef MAC #define DLBRSRC /* use Mac resources */ #else #define DLBLIB /* use a set of external files */ #endif #ifdef DLBLIB /* directory structure in memory */ typedef struct dlb_directory { char *fname; /* file name as seen from calling code */ long foffset; /* offset in lib file to start of this file */ long fsize; /* file size */ char handling; /* how to handle the file (compression, etc) */ } libdir; /* information about each open library */ typedef struct dlb_library { FILE *fdata; /* opened data file */ long fmark; /* current file mark */ libdir *dir; /* directory of library file */ char *sspace; /* pointer to string space */ long nentries; /* # of files in directory */ long rev; /* dlb file revision */ long strsize; /* dlb file string size */ } library; /* library definitions */ #ifndef DLBFILE #define DLBFILE "nhdat" /* name of library */ #endif #ifndef FILENAME_CMP #define FILENAME_CMP strcmp /* case sensitive */ #endif #endif /* DLBLIB */ typedef struct dlb_handle { FILE *fp; /* pointer to an external file, use if non-null */ #ifdef DLBLIB library *lib; /* pointer to library structure */ long start; /* offset of start of file */ long size; /* size of file */ long mark; /* current file marker */ #endif #ifdef DLBRSRC int fd; /* HandleFile file descriptor */ #endif } dlb; #if defined(ULTRIX_PROTO) && !defined(__STDC__) /* buggy old Ultrix compiler wants this for the (*dlb_fread_proc) and (*dlb_fgets_proc) prototypes in struct dlb_procs (dlb.c); we'll use it in all the declarations for consistency */ #define DLB_P struct dlb_handle * #else #define DLB_P dlb * #endif boolean NDECL(dlb_init); void NDECL(dlb_cleanup); dlb *FDECL(dlb_fopen, (const char *, const char *)); int FDECL(dlb_fclose, (DLB_P)); int FDECL(dlb_fread, (char *, int, int, DLB_P)); int FDECL(dlb_fseek, (DLB_P, long, int)); char *FDECL(dlb_fgets, (char *, int, DLB_P)); int FDECL(dlb_fgetc, (DLB_P)); long FDECL(dlb_ftell, (DLB_P)); /* Resource DLB entry points */ #ifdef DLBRSRC boolean rsrc_dlb_init(void); void rsrc_dlb_cleanup(void); boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode); int rsrc_dlb_fclose(dlb *dp); int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp); int rsrc_dlb_fseek(dlb *dp, long pos, int whence); char *rsrc_dlb_fgets(char *buf, int len, dlb *dp); int rsrc_dlb_fgetc(dlb *dp); long rsrc_dlb_ftell(dlb *dp); #endif #else /* DLB */ #define dlb FILE #define dlb_init() #define dlb_cleanup() #define dlb_fopen fopen #define dlb_fclose fclose #define dlb_fread fread #define dlb_fseek fseek #define dlb_fgets fgets #define dlb_fgetc fgetc #define dlb_ftell ftell #endif /* DLB */ /* various other I/O stuff we don't want to replicate everywhere */ #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #define RDTMODE "r" #if (defined(MSDOS) || defined(WIN32) || defined(TOS) || defined(OS2)) \ && defined(DLB) #define WRTMODE "w+b" #else #define WRTMODE "w+" #endif #if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) \ || defined(__MWERKS__) || defined(WIN32) #define RDBMODE "rb" #define WRBMODE "w+b" #else #define RDBMODE "r" #define WRBMODE "w+" #endif #endif /* DLB_H */ nethack-3.6.0/include/dungeon.h0000664000076400007660000002372112622603541015376 0ustar paxedpaxed/* NetHack 3.6 dungeon.h $NHDT-Date: 1447755969 2015/11/17 10:26:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DUNGEON_H #define DUNGEON_H typedef struct d_flags { /* dungeon/level type flags */ Bitfield(town, 1); /* is this a town? (levels only) */ Bitfield(hellish, 1); /* is this part of hell? */ Bitfield(maze_like, 1); /* is this a maze? */ Bitfield(rogue_like, 1); /* is this an old-fashioned presentation? */ Bitfield(align, 3); /* dungeon alignment. */ Bitfield(unused, 1); /* etc... */ } d_flags; typedef struct d_level { /* basic dungeon level element */ xchar dnum; /* dungeon number */ xchar dlevel; /* level number */ } d_level; typedef struct s_level { /* special dungeon level element */ struct s_level *next; d_level dlevel; /* dungeon & level numbers */ char proto[15]; /* name of prototype file (eg. "tower") */ char boneid; /* character to id level in bones files */ uchar rndlevs; /* no. of randomly available similar levels */ d_flags flags; /* type flags */ } s_level; typedef struct stairway { /* basic stairway identifier */ xchar sx, sy; /* x / y location of the stair */ d_level tolev; /* where does it go */ char up; /* what type of stairway (up/down) */ } stairway; /* level region types */ #define LR_DOWNSTAIR 0 #define LR_UPSTAIR 1 #define LR_PORTAL 2 #define LR_BRANCH 3 #define LR_TELE 4 #define LR_UPTELE 5 #define LR_DOWNTELE 6 typedef struct dest_area { /* non-stairway level change identifier */ xchar lx, ly; /* "lower" left corner (near [0,0]) */ xchar hx, hy; /* "upper" right corner (near [COLNO,ROWNO]) */ xchar nlx, nly; /* outline of invalid area */ xchar nhx, nhy; /* opposite corner of invalid area */ } dest_area; typedef struct dungeon { /* basic dungeon identifier */ char dname[24]; /* name of the dungeon (eg. "Hell") */ char proto[15]; /* name of prototype file (eg. "tower") */ char boneid; /* character to id dungeon in bones files */ d_flags flags; /* dungeon flags */ xchar entry_lev; /* entry level */ xchar num_dunlevs; /* number of levels in this dungeon */ xchar dunlev_ureached; /* how deep you have been in this dungeon */ int ledger_start, /* the starting depth in "real" terms */ depth_start; /* the starting depth in "logical" terms */ } dungeon; /* * A branch structure defines the connection between two dungeons. They * will be ordered by the dungeon number/level number of 'end1'. Ties * are resolved by 'end2'. 'Type' uses 'end1' arbitrarily as the primary * point. */ typedef struct branch { struct branch *next; /* next in the branch chain */ int id; /* branch identifier */ int type; /* type of branch */ d_level end1; /* "primary" end point */ d_level end2; /* other end point */ boolean end1_up; /* does end1 go up? */ } branch; /* branch types */ #define BR_STAIR 0 /* "Regular" connection, 2 staircases. */ #define BR_NO_END1 1 /* "Regular" connection. However, no stair from end1 to end2. There is a stair from end2 to end1. */ #define BR_NO_END2 2 /* "Regular" connection. However, no stair from end2 to end1. There is a stair from end1 to end2. */ #define BR_PORTAL 3 /* Connection by magic portals (traps) */ /* A particular dungeon contains num_dunlevs d_levels with dlevel 1.. * num_dunlevs. Ledger_start and depth_start are bases that are added * to the dlevel of a particular d_level to get the effective ledger_no * and depth for that d_level. * * Ledger_no is a bookkeeping number that gives a unique identifier for a * particular d_level (for level.?? files, e.g.). * * Depth corresponds to the number of floors below the surface. */ #define Is_astralevel(x) (on_level(x, &astral_level)) #define Is_earthlevel(x) (on_level(x, &earth_level)) #define Is_waterlevel(x) (on_level(x, &water_level)) #define Is_firelevel(x) (on_level(x, &fire_level)) #define Is_airlevel(x) (on_level(x, &air_level)) #define Is_medusa_level(x) (on_level(x, &medusa_level)) #define Is_oracle_level(x) (on_level(x, &oracle_level)) #define Is_valley(x) (on_level(x, &valley_level)) #define Is_juiblex_level(x) (on_level(x, &juiblex_level)) #define Is_asmo_level(x) (on_level(x, &asmodeus_level)) #define Is_baal_level(x) (on_level(x, &baalzebub_level)) #define Is_wiz1_level(x) (on_level(x, &wiz1_level)) #define Is_wiz2_level(x) (on_level(x, &wiz2_level)) #define Is_wiz3_level(x) (on_level(x, &wiz3_level)) #define Is_sanctum(x) (on_level(x, &sanctum_level)) #define Is_portal_level(x) (on_level(x, &portal_level)) #define Is_rogue_level(x) (on_level(x, &rogue_level)) #define Is_stronghold(x) (on_level(x, &stronghold_level)) #define Is_bigroom(x) (on_level(x, &bigroom_level)) #define Is_qstart(x) (on_level(x, &qstart_level)) #define Is_qlocate(x) (on_level(x, &qlocate_level)) #define Is_nemesis(x) (on_level(x, &nemesis_level)) #define Is_knox(x) (on_level(x, &knox_level)) #define Is_mineend_level(x) (on_level(x, &mineend_level)) #define Is_sokoend_level(x) (on_level(x, &sokoend_level)) #define In_sokoban(x) ((x)->dnum == sokoban_dnum) #define Inhell In_hell(&u.uz) /* now gehennom */ #define In_endgame(x) ((x)->dnum == astral_level.dnum) #define within_bounded_area(X, Y, LX, LY, HX, HY) \ ((X) >= (LX) && (X) <= (HX) && (Y) >= (LY) && (Y) <= (HY)) /* monster and object migration codes */ #define MIGR_NOWHERE (-1) /* failure flag for down_gate() */ #define MIGR_RANDOM 0 #define MIGR_APPROX_XY 1 /* approximate coordinates */ #define MIGR_EXACT_XY 2 /* specific coordinates */ #define MIGR_STAIRS_UP 3 #define MIGR_STAIRS_DOWN 4 #define MIGR_LADDER_UP 5 #define MIGR_LADDER_DOWN 6 #define MIGR_SSTAIRS 7 /* dungeon branch */ #define MIGR_PORTAL 8 /* magic portal */ #define MIGR_WITH_HERO 9 /* mon: followers; obj: trap door */ #define MIGR_NOBREAK 1024 /* bitmask: don't break on delivery */ #define MIGR_NOSCATTER 2048 /* don't scatter on delivery */ /* level information (saved via ledger number) */ struct linfo { unsigned char flags; #define VISITED 0x01 /* hero has visited this level */ #define FORGOTTEN 0x02 /* hero will forget this level when reached */ #define LFILE_EXISTS 0x04 /* a level file exists for this level */ /* Note: VISITED and LFILE_EXISTS are currently almost always * set at the same time. However they _mean_ different things. */ #ifdef MFLOPPY #define FROMPERM 1 /* for ramdisk use */ #define TOPERM 2 /* for ramdisk use */ #define ACTIVE 1 #define SWAPPED 2 int where; long time; long size; #endif /* MFLOPPY */ }; /* types and structures for dungeon map recording * * It is designed to eliminate the need for an external notes file for some * mundane dungeon elements. "Where was the last altar I passed?" etc... * Presumably the character can remember this sort of thing even if, months * later in real time picking up an old save game, I can't. * * To be consistent, one can assume that this map is in the player's mind and * has no physical correspondence (eliminating illiteracy/blind/hands/hands * free concerns). Therefore, this map is not exhaustive nor detailed ("some * fountains"). This makes it also subject to player conditions (amnesia). */ /* Because clearly Nethack needs more ways to specify alignment */ #define Amask2msa(x) ((x) == 4 ? 3 : (x) &AM_MASK) #define Msa2amask(x) ((x) == 3 ? 4 : (x)) #define MSA_NONE 0 /* unaligned or multiple alignments */ #define MSA_LAWFUL 1 #define MSA_NEUTRAL 2 #define MSA_CHAOTIC 3 /* what the player knows about a single dungeon level */ /* initialized in mklev() */ typedef struct mapseen { struct mapseen *next; /* next map in the chain */ branch *br; /* knows about branch via taking it in goto_level */ d_level lev; /* corresponding dungeon level */ struct mapseen_feat { /* feature knowledge that must be calculated from levl array */ Bitfield(nfount, 2); Bitfield(nsink, 2); Bitfield(naltar, 2); Bitfield(nthrone, 2); Bitfield(ngrave, 2); Bitfield(ntree, 2); Bitfield(water, 2); Bitfield(lava, 2); Bitfield(ice, 2); /* calculated from rooms array */ Bitfield(nshop, 2); Bitfield(ntemple, 2); /* altar alignment; MSA_NONE if there is more than one and they aren't all the same */ Bitfield(msalign, 2); Bitfield(shoptype, 5); } feat; struct mapseen_flags { Bitfield(unreachable, 1); /* can't get back to this level */ Bitfield(forgot, 1); /* player has forgotten about this level */ Bitfield(knownbones, 1); /* player aware of bones */ Bitfield(oracle, 1); Bitfield(sokosolved, 1); Bitfield(bigroom, 1); Bitfield(castle, 1); Bitfield(castletune, 1); /* add tune hint to castle annotation */ Bitfield(valley, 1); Bitfield(msanctum, 1); Bitfield(ludios, 1); Bitfield(roguelevel, 1); /* quest annotations: quest_summons is for main dungeon level with entry portal and is reset once quest has been finished; questing is for quest home (level 1) */ Bitfield(quest_summons, 1); /* heard summons from leader */ Bitfield(questing, 1); /* quest leader has unlocked quest stairs */ } flags; /* custom naming */ char *custom; unsigned custom_lth; struct mapseen_rooms { Bitfield(seen, 1); Bitfield(untended, 1); /* flag for shop without shk */ } msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as rooms[] */ /* dead heroes; might not have graves or ghosts */ struct cemetery *final_resting_place; /* same as level.bonesinfo */ } mapseen; #endif /* DUNGEON_H */ nethack-3.6.0/include/engrave.h0000664000076400007660000000150212536476415015373 0ustar paxedpaxed/* NetHack 3.6 engrave.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ENGRAVE_H #define ENGRAVE_H struct engr { struct engr *nxt_engr; char *engr_txt; xchar engr_x, engr_y; unsigned engr_lth; /* for save & restore; not length of text */ long engr_time; /* moment engraving was (will be) finished */ xchar engr_type; #define DUST 1 #define ENGRAVE 2 #define BURN 3 #define MARK 4 #define ENGR_BLOOD 5 #define HEADSTONE 6 #define N_ENGRAVE 6 }; #define newengr(lth) \ (struct engr *) alloc((unsigned)(lth) + sizeof(struct engr)) #define dealloc_engr(engr) free((genericptr_t)(engr)) #endif /* ENGRAVE_H */ nethack-3.6.0/include/extern.h0000664000076400007660000030334312627562712015256 0ustar paxedpaxed/* NetHack 3.6 extern.h $NHDT-Date: 1449051498 2015/12/02 10:18:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.520 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef EXTERN_H #define EXTERN_H #define E extern /* ### alloc.c ### */ #if 0 E long *FDECL(alloc, (unsigned int)); #endif E char *FDECL(fmt_ptr, (const genericptr)); /* This next pre-processor directive covers almost the entire file, * interrupted only occasionally to pick up specific functions as needed. */ #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) /* ### allmain.c ### */ E void FDECL(moveloop, (BOOLEAN_P)); E void NDECL(stop_occupation); E void NDECL(display_gamewindows); E void NDECL(newgame); E void FDECL(welcome, (BOOLEAN_P)); E time_t NDECL(get_realtime); /* ### apply.c ### */ E int NDECL(doapply); E int NDECL(dorub); E int NDECL(dojump); E int FDECL(jump, (int)); E int NDECL(number_leashed); E void FDECL(o_unleash, (struct obj *)); E void FDECL(m_unleash, (struct monst *, BOOLEAN_P)); E void NDECL(unleash_all); E boolean NDECL(next_to_u); E struct obj *FDECL(get_mleash, (struct monst *)); E const char *NDECL(beautiful); E void FDECL(check_leash, (XCHAR_P, XCHAR_P)); E boolean FDECL(um_dist, (XCHAR_P, XCHAR_P, XCHAR_P)); E boolean FDECL(snuff_candle, (struct obj *)); E boolean FDECL(snuff_lit, (struct obj *)); E boolean FDECL(catch_lit, (struct obj *)); E void FDECL(use_unicorn_horn, (struct obj *)); E boolean FDECL(tinnable, (struct obj *)); E void NDECL(reset_trapset); E void FDECL(fig_transform, (ANY_P *, long)); E int FDECL(unfixable_trouble_count, (BOOLEAN_P)); /* ### artifact.c ### */ E void NDECL(init_artifacts); E void FDECL(save_artifacts, (int)); E void FDECL(restore_artifacts, (int)); E const char *FDECL(artiname, (int)); E struct obj *FDECL(mk_artifact, (struct obj *, ALIGNTYP_P)); E const char *FDECL(artifact_name, (const char *, short *)); E boolean FDECL(exist_artifact, (int, const char *)); E void FDECL(artifact_exists, (struct obj *, const char *, BOOLEAN_P)); E int NDECL(nartifact_exist); E boolean FDECL(arti_immune, (struct obj *, int)); E boolean FDECL(spec_ability, (struct obj *, unsigned long)); E boolean FDECL(confers_luck, (struct obj *)); E boolean FDECL(arti_reflects, (struct obj *)); E boolean FDECL(shade_glare, (struct obj *)); E boolean FDECL(restrict_name, (struct obj *, const char *)); E boolean FDECL(defends, (int, struct obj *)); E boolean FDECL(defends_when_carried, (int, struct obj *)); E boolean FDECL(protects, (struct obj *, BOOLEAN_P)); E void FDECL(set_artifact_intrinsic, (struct obj *, BOOLEAN_P, long)); E int FDECL(touch_artifact, (struct obj *, struct monst *)); E int FDECL(spec_abon, (struct obj *, struct monst *)); E int FDECL(spec_dbon, (struct obj *, struct monst *, int)); E void FDECL(discover_artifact, (XCHAR_P)); E boolean FDECL(undiscovered_artifact, (XCHAR_P)); E int FDECL(disp_artifact_discoveries, (winid)); E boolean FDECL(artifact_hit, (struct monst *, struct monst *, struct obj *, int *, int)); E int NDECL(doinvoke); E boolean FDECL(finesse_ahriman, (struct obj *)); E void FDECL(arti_speak, (struct obj *)); E boolean FDECL(artifact_light, (struct obj *)); E long FDECL(spec_m2, (struct obj *)); E boolean FDECL(artifact_has_invprop, (struct obj *, UCHAR_P)); E long FDECL(arti_cost, (struct obj *)); E struct obj *FDECL(what_gives, (long *)); E const char *FDECL(glow_color, (int)); E void FDECL(Sting_effects, (int)); E int FDECL(retouch_object, (struct obj **, BOOLEAN_P)); E void FDECL(retouch_equipment, (int)); /* ### attrib.c ### */ E boolean FDECL(adjattrib, (int, int, int)); E void FDECL(gainstr, (struct obj *, int, BOOLEAN_P)); E void FDECL(losestr, (int)); E void FDECL(poisontell, (int, BOOLEAN_P)); E void FDECL(poisoned, (const char *, int, const char *, int, BOOLEAN_P)); E void FDECL(change_luck, (SCHAR_P)); E int FDECL(stone_luck, (BOOLEAN_P)); E void NDECL(set_moreluck); E void NDECL(restore_attrib); E void FDECL(exercise, (int, BOOLEAN_P)); E void NDECL(exerchk); E void FDECL(init_attr, (int)); E void NDECL(redist_attr); E void FDECL(adjabil, (int, int)); E int NDECL(newhp); E schar FDECL(acurr, (int)); E schar NDECL(acurrstr); E boolean FDECL(extremeattr, (int)); E void FDECL(adjalign, (int)); E int FDECL(is_innate, (int)); E char *FDECL(from_what, (int)); E void FDECL(uchangealign, (int, int)); /* ### ball.c ### */ E void FDECL(ballrelease, (BOOLEAN_P)); E void NDECL(ballfall); E void NDECL(placebc); E void NDECL(unplacebc); E void FDECL(set_bc, (int)); E void FDECL(move_bc, (int, int, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E boolean FDECL(drag_ball, (XCHAR_P, XCHAR_P, int *, xchar *, xchar *, xchar *, xchar *, boolean *, BOOLEAN_P)); E void FDECL(drop_ball, (XCHAR_P, XCHAR_P)); E void NDECL(drag_down); /* ### bones.c ### */ E void FDECL(sanitize_name, (char *)); E void FDECL(drop_upon_death, (struct monst *, struct obj *, int, int)); E boolean NDECL(can_make_bones); E void FDECL(savebones, (int, time_t, struct obj *)); E int NDECL(getbones); /* ### botl.c ### */ E int FDECL(xlev_to_rank, (int)); E int FDECL(title_to_mon, (const char *, int *, int *)); E void NDECL(max_rank_sz); #ifdef SCORE_ON_BOTL E long NDECL(botl_score); #endif E int FDECL(describe_level, (char *)); E const char *FDECL(rank_of, (int, SHORT_P, BOOLEAN_P)); E void NDECL(bot); #ifdef STATUS_VIA_WINDOWPORT E void FDECL(status_initialize, (BOOLEAN_P)); E void NDECL(status_finish); E void FDECL(status_notify_windowport, (BOOLEAN_P)); #ifdef STATUS_HILITES E boolean FDECL(set_status_hilites, (char *op, BOOLEAN_P)); E void FDECL(clear_status_hilites, (BOOLEAN_P)); E char *FDECL(get_status_hilites, (char *, int)); E boolean NDECL(status_hilite_menu); #endif #endif /* ### cmd.c ### */ E boolean FDECL(redraw_cmd, (CHAR_P)); #ifdef USE_TRAMPOLI E int NDECL(doextcmd); E int NDECL(domonability); E int NDECL(doprev_message); E int NDECL(timed_occupation); E int NDECL(doattributes); E int NDECL(wiz_detect); E int NDECL(wiz_genesis); E int NDECL(wiz_identify); E int NDECL(wiz_level_tele); E int NDECL(wiz_map); E int NDECL(wiz_where); E int NDECL(wiz_wish); #endif /* USE_TRAMPOLI */ E void NDECL(reset_occupations); E void FDECL(set_occupation, (int (*)(void), const char *, int)); E char NDECL(pgetchar); E void FDECL(pushch, (CHAR_P)); E void FDECL(savech, (CHAR_P)); E void NDECL(add_debug_extended_commands); E void FDECL(reset_commands, (BOOLEAN_P)); E void FDECL(rhack, (char *)); E int NDECL(doextlist); E int NDECL(extcmd_via_menu); E int NDECL(enter_explore_mode); E void FDECL(enlightenment, (int, int)); E void FDECL(youhiding, (BOOLEAN_P, int)); E void FDECL(show_conduct, (int)); E int FDECL(xytod, (SCHAR_P, SCHAR_P)); E void FDECL(dtoxy, (coord *, int)); E int FDECL(movecmd, (CHAR_P)); E int NDECL(dxdy_moveok); E int FDECL(getdir, (const char *)); E void NDECL(confdir); E const char *FDECL(directionname, (int)); E int FDECL(isok, (int, int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int, int, int)); #ifdef HANGUPHANDLING E void FDECL(hangup, (int)); E void NDECL(end_of_input); #endif E char NDECL(readchar); E void NDECL(sanity_check); E char FDECL(yn_function, (const char *, const char *, CHAR_P)); E boolean FDECL(paranoid_query, (BOOLEAN_P, const char *)); /* ### dbridge.c ### */ E boolean FDECL(is_pool, (int, int)); E boolean FDECL(is_lava, (int, int)); E boolean FDECL(is_pool_or_lava, (int, int)); E boolean FDECL(is_ice, (int, int)); E boolean FDECL(is_moat, (int, int)); E schar FDECL(db_under_typ, (int)); E int FDECL(is_drawbridge_wall, (int, int)); E boolean FDECL(is_db_wall, (int, int)); E boolean FDECL(find_drawbridge, (int *, int *)); E boolean FDECL(create_drawbridge, (int, int, int, BOOLEAN_P)); E void FDECL(open_drawbridge, (int, int)); E void FDECL(close_drawbridge, (int, int)); E void FDECL(destroy_drawbridge, (int, int)); /* ### decl.c ### */ E void NDECL(decl_init); /* ### detect.c ### */ E struct obj *FDECL(o_in, (struct obj *, CHAR_P)); E struct obj *FDECL(o_material, (struct obj *, unsigned)); E int FDECL(gold_detect, (struct obj *)); E int FDECL(food_detect, (struct obj *)); E int FDECL(object_detect, (struct obj *, int)); E int FDECL(monster_detect, (struct obj *, int)); E int FDECL(trap_detect, (struct obj *)); E const char *FDECL(level_distance, (d_level *)); E void FDECL(use_crystal_ball, (struct obj **)); E void NDECL(do_mapping); E void NDECL(do_vicinity_map); E void FDECL(cvt_sdoor_to_door, (struct rm *)); #ifdef USE_TRAMPOLI E void FDECL(findone, (int, int, genericptr_t)); E void FDECL(openone, (int, int, genericptr_t)); #endif E int NDECL(findit); E int NDECL(openit); E boolean FDECL(detecting, (void (*)(int, int, genericptr))); E void FDECL(find_trap, (struct trap *)); E int FDECL(dosearch0, (int)); E int NDECL(dosearch); E void NDECL(sokoban_detect); E void FDECL(reveal_terrain, (int, int)); /* ### dig.c ### */ E int FDECL(dig_typ, (struct obj *, XCHAR_P, XCHAR_P)); E boolean NDECL(is_digging); #ifdef USE_TRAMPOLI E int NDECL(dig); #endif E int NDECL(holetime); E boolean FDECL(dig_check, (struct monst *, BOOLEAN_P, int, int)); E void FDECL(digactualhole, (int, int, struct monst *, int)); E boolean FDECL(dighole, (BOOLEAN_P, BOOLEAN_P, coord *)); E int FDECL(use_pick_axe, (struct obj *)); E int FDECL(use_pick_axe2, (struct obj *)); E boolean FDECL(mdig_tunnel, (struct monst *)); E void FDECL(draft_message, (BOOLEAN_P)); E void FDECL(watch_dig, (struct monst *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void NDECL(zap_dig); E struct obj *FDECL(bury_an_obj, (struct obj *, boolean *)); E void FDECL(bury_objs, (int, int)); E void FDECL(unearth_objs, (int, int)); E void FDECL(rot_organic, (ANY_P *, long)); E void FDECL(rot_corpse, (ANY_P *, long)); E struct obj *FDECL(buried_ball, (coord *)); E void NDECL(buried_ball_to_punishment); E void NDECL(buried_ball_to_freedom); E schar FDECL(fillholetyp, (int, int, BOOLEAN_P)); E void FDECL(liquid_flow, (XCHAR_P, XCHAR_P, SCHAR_P, struct trap *, const char *)); E boolean FDECL(conjoined_pits, (struct trap *, struct trap *, BOOLEAN_P)); #if 0 E void FDECL(bury_monst, (struct monst *)); E void NDECL(bury_you); E void NDECL(unearth_you); E void NDECL(escape_tomb); E void FDECL(bury_obj, (struct obj *)); #endif /* ### display.c ### */ E void FDECL(magic_map_background, (XCHAR_P, XCHAR_P, int)); E void FDECL(map_background, (XCHAR_P, XCHAR_P, int)); E void FDECL(map_trap, (struct trap *, int)); E void FDECL(map_object, (struct obj *, int)); E void FDECL(map_invisible, (XCHAR_P, XCHAR_P)); E void FDECL(unmap_object, (int, int)); E void FDECL(map_location, (int, int, int)); E void FDECL(feel_newsym, (XCHAR_P, XCHAR_P)); E void FDECL(feel_location, (XCHAR_P, XCHAR_P)); E void FDECL(newsym, (int, int)); E void FDECL(shieldeff, (XCHAR_P, XCHAR_P)); E void FDECL(tmp_at, (int, int)); E void FDECL(swallowed, (int)); E void FDECL(under_ground, (int)); E void FDECL(under_water, (int)); E void NDECL(see_monsters); E void NDECL(set_mimic_blocking); E void NDECL(see_objects); E void NDECL(see_traps); E void NDECL(curs_on_u); E int NDECL(doredraw); E void NDECL(docrt); E void FDECL(show_glyph, (int, int, int)); E void NDECL(clear_glyph_buffer); E void FDECL(row_refresh, (int, int, int)); E void NDECL(cls); E void FDECL(flush_screen, (int)); E int FDECL(back_to_glyph, (XCHAR_P, XCHAR_P)); E int FDECL(zapdir_to_glyph, (int, int, int)); E int FDECL(glyph_at, (XCHAR_P, XCHAR_P)); E void NDECL(set_wall_state); E void FDECL(unset_seenv, (struct rm *, int, int, int, int)); /* ### do.c ### */ #ifdef USE_TRAMPOLI E int FDECL(drop, (struct obj *)); E int NDECL(wipeoff); #endif E int NDECL(dodrop); E boolean FDECL(boulder_hits_pool, (struct obj *, int, int, BOOLEAN_P)); E boolean FDECL(flooreffects, (struct obj *, int, int, const char *)); E void FDECL(doaltarobj, (struct obj *)); E boolean FDECL(canletgo, (struct obj *, const char *)); E void FDECL(dropx, (struct obj *)); E void FDECL(dropy, (struct obj *)); E void FDECL(dropz, (struct obj *, BOOLEAN_P)); E void FDECL(obj_no_longer_held, (struct obj *)); E int NDECL(doddrop); E int NDECL(dodown); E int NDECL(doup); #ifdef INSURANCE E void NDECL(save_currentstate); #endif E void FDECL(goto_level, (d_level *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(schedule_goto, (d_level *, BOOLEAN_P, BOOLEAN_P, int, const char *, const char *)); E void NDECL(deferred_goto); E boolean FDECL(revive_corpse, (struct obj *)); E void FDECL(revive_mon, (ANY_P *, long)); E int NDECL(donull); E int NDECL(dowipe); E void FDECL(set_wounded_legs, (long, int)); E void NDECL(heal_legs); /* ### do_name.c ### */ E int FDECL(getpos, (coord *, BOOLEAN_P, const char *)); E void FDECL(getpos_sethilite, (void (*f)(int))); E void FDECL(new_mname, (struct monst *, int)); E void FDECL(free_mname, (struct monst *)); E void FDECL(new_oname, (struct obj *, int)); E void FDECL(free_oname, (struct obj *)); E const char *FDECL(safe_oname, (struct obj *)); E struct monst *FDECL(christen_monst, (struct monst *, const char *)); E struct obj *FDECL(oname, (struct obj *, const char *)); E boolean FDECL(objtyp_is_callable, (int)); E int NDECL(docallcmd); E void FDECL(docall, (struct obj *)); E const char *NDECL(rndghostname); E char *FDECL(x_monnam, (struct monst *, int, const char *, int, BOOLEAN_P)); E char *FDECL(l_monnam, (struct monst *)); E char *FDECL(mon_nam, (struct monst *)); E char *FDECL(noit_mon_nam, (struct monst *)); E char *FDECL(Monnam, (struct monst *)); E char *FDECL(noit_Monnam, (struct monst *)); E char *FDECL(m_monnam, (struct monst *)); E char *FDECL(y_monnam, (struct monst *)); E char *FDECL(Adjmonnam, (struct monst *, const char *)); E char *FDECL(Amonnam, (struct monst *)); E char *FDECL(a_monnam, (struct monst *)); E char *FDECL(distant_monnam, (struct monst *, int, char *)); E char *FDECL(rndmonnam, (char *)); E const char *FDECL(hcolor, (const char *)); E const char *NDECL(rndcolor); E const char *NDECL(roguename); E struct obj *FDECL(realloc_obj, (struct obj *, int, genericptr_t, int, const char *)); E char *FDECL(coyotename, (struct monst *, char *)); E const char *FDECL(noveltitle, (int *)); E const char *FDECL(lookup_novel, (const char *, int *)); /* ### do_wear.c ### */ #ifdef USE_TRAMPOLI E int NDECL(Armor_on); E int NDECL(Boots_on); E int NDECL(Gloves_on); E int NDECL(Helmet_on); E int FDECL(select_off, (struct obj *)); E int NDECL(take_off); #endif E void FDECL(off_msg, (struct obj *)); E void FDECL(set_wear, (struct obj *)); E boolean FDECL(donning, (struct obj *)); E boolean FDECL(doffing, (struct obj *)); E void NDECL(cancel_don); E int FDECL(stop_donning, (struct obj *)); E int NDECL(Armor_off); E int NDECL(Armor_gone); E int NDECL(Helmet_off); E int NDECL(Gloves_off); E int NDECL(Boots_off); E int NDECL(Cloak_off); E int NDECL(Shield_off); E int NDECL(Shirt_off); E void NDECL(Amulet_off); E void FDECL(Ring_on, (struct obj *)); E void FDECL(Ring_off, (struct obj *)); E void FDECL(Ring_gone, (struct obj *)); E void FDECL(Blindf_on, (struct obj *)); E void FDECL(Blindf_off, (struct obj *)); E int NDECL(dotakeoff); E int NDECL(doremring); E int FDECL(cursed, (struct obj *)); E int FDECL(armoroff, (struct obj *)); E int FDECL(canwearobj, (struct obj *, long *, BOOLEAN_P)); E int NDECL(dowear); E int NDECL(doputon); E void NDECL(find_ac); E void NDECL(glibr); E struct obj *FDECL(some_armor, (struct monst *)); E struct obj *FDECL(stuck_ring, (struct obj *, int)); E struct obj *NDECL(unchanger); E void NDECL(reset_remarm); E int NDECL(doddoremarm); E int FDECL(destroy_arm, (struct obj *)); E void FDECL(adj_abon, (struct obj *, SCHAR_P)); E boolean FDECL(inaccessible_equipment, (struct obj *, const char *, BOOLEAN_P)); /* ### dog.c ### */ E void FDECL(newedog, (struct monst *)); E void FDECL(free_edog, (struct monst *)); E void FDECL(initedog, (struct monst *)); E struct monst *FDECL(make_familiar, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E struct monst *NDECL(makedog); E void NDECL(update_mlstmv); E void NDECL(losedogs); E void FDECL(mon_arrive, (struct monst *, BOOLEAN_P)); E void FDECL(mon_catchup_elapsed_time, (struct monst *, long)); E void FDECL(keepdogs, (BOOLEAN_P)); E void FDECL(migrate_to_level, (struct monst *, XCHAR_P, XCHAR_P, coord *)); E int FDECL(dogfood, (struct monst *, struct obj *)); E boolean FDECL(tamedog, (struct monst *, struct obj *)); E void FDECL(abuse_dog, (struct monst *)); E void FDECL(wary_dog, (struct monst *, BOOLEAN_P)); /* ### dogmove.c ### */ E struct obj *FDECL(droppables, (struct monst *)); E int FDECL(dog_nutrition, (struct monst *, struct obj *)); E int FDECL(dog_eat, (struct monst *, struct obj *, int, int, BOOLEAN_P)); E int FDECL(dog_move, (struct monst *, int)); #ifdef USE_TRAMPOLI E void FDECL(wantdoor, (int, int, genericptr_t)); #endif E void FDECL(finish_meating, (struct monst *)); /* ### dokick.c ### */ E boolean FDECL(ghitm, (struct monst *, struct obj *)); E void FDECL(container_impact_dmg, (struct obj *, XCHAR_P, XCHAR_P)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(obj_delivery, (BOOLEAN_P)); E schar FDECL(down_gate, (XCHAR_P, XCHAR_P)); E void FDECL(impact_drop, (struct obj *, XCHAR_P, XCHAR_P, XCHAR_P)); /* ### dothrow.c ### */ E int NDECL(dothrow); E int NDECL(dofire); E void FDECL(endmultishot, (BOOLEAN_P)); E void FDECL(hitfloor, (struct obj *)); E void FDECL(hurtle, (int, int, int, BOOLEAN_P)); E void FDECL(mhurtle, (struct monst *, int, int, int)); E void FDECL(throwit, (struct obj *, long, BOOLEAN_P)); E int FDECL(omon_adj, (struct monst *, struct obj *, BOOLEAN_P)); E int FDECL(thitmonst, (struct monst *, struct obj *)); E int FDECL(hero_breaks, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E int FDECL(breaks, (struct obj *, XCHAR_P, XCHAR_P)); E void FDECL(release_camera_demon, (struct obj *, XCHAR_P, XCHAR_P)); E void FDECL(breakobj, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(breaktest, (struct obj *)); E boolean FDECL(walk_path, (coord *, coord *, boolean (*)(genericptr, int, int), genericptr_t)); E boolean FDECL(hurtle_step, (genericptr_t, int, int)); /* ### drawing.c ### */ #endif /* !MAKEDEFS_C && !LEV_LEX_C */ E int FDECL(def_char_to_objclass, (CHAR_P)); E int FDECL(def_char_to_monclass, (CHAR_P)); #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) E void FDECL(switch_symbols, (int)); E void FDECL(assign_graphics, (int)); E void NDECL(init_r_symbols); E void NDECL(init_symbols); E void NDECL(update_bouldersym); E void NDECL(init_showsyms); E void NDECL(init_l_symbols); E void FDECL(clear_symsetentry, (int, BOOLEAN_P)); E void FDECL(update_l_symset, (struct symparse *, int)); E void FDECL(update_r_symset, (struct symparse *, int)); E boolean FDECL(cursed_object_at, (int, int)); /* ### dungeon.c ### */ E void FDECL(save_dungeon, (int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(restore_dungeon, (int)); E void FDECL(insert_branch, (branch *, BOOLEAN_P)); E void NDECL(init_dungeons); E s_level *FDECL(find_level, (const char *)); E s_level *FDECL(Is_special, (d_level *)); E branch *FDECL(Is_branchlev, (d_level *)); E boolean FDECL(builds_up, (d_level *)); E xchar FDECL(ledger_no, (d_level *)); E xchar NDECL(maxledgerno); E schar FDECL(depth, (d_level *)); E xchar FDECL(dunlev, (d_level *)); E xchar FDECL(dunlevs_in_dungeon, (d_level *)); E xchar FDECL(ledger_to_dnum, (XCHAR_P)); E xchar FDECL(ledger_to_dlev, (XCHAR_P)); E xchar FDECL(deepest_lev_reached, (BOOLEAN_P)); E boolean FDECL(on_level, (d_level *, d_level *)); E void FDECL(next_level, (BOOLEAN_P)); E void FDECL(prev_level, (BOOLEAN_P)); E void FDECL(u_on_newpos, (int, int)); E void FDECL(u_on_rndspot, (int)); E void FDECL(u_on_sstairs, (int)); E void NDECL(u_on_upstairs); E void NDECL(u_on_dnstairs); E boolean FDECL(On_stairs, (XCHAR_P, XCHAR_P)); E void FDECL(get_level, (d_level *, int)); E boolean FDECL(Is_botlevel, (d_level *)); E boolean FDECL(Can_fall_thru, (d_level *)); E boolean FDECL(Can_dig_down, (d_level *)); E boolean FDECL(Can_rise_up, (int, int, d_level *)); E boolean FDECL(has_ceiling, (d_level *)); E boolean FDECL(In_quest, (d_level *)); E boolean FDECL(In_mines, (d_level *)); E branch *FDECL(dungeon_branch, (const char *)); E boolean FDECL(at_dgn_entrance, (const char *)); E boolean FDECL(In_hell, (d_level *)); E boolean FDECL(In_V_tower, (d_level *)); E boolean FDECL(On_W_tower_level, (d_level *)); E boolean FDECL(In_W_tower, (int, int, d_level *)); E void FDECL(find_hell, (d_level *)); E void FDECL(goto_hell, (BOOLEAN_P, BOOLEAN_P)); E void FDECL(assign_level, (d_level *, d_level *)); E void FDECL(assign_rnd_level, (d_level *, d_level *, int)); E int FDECL(induced_align, (int)); E boolean FDECL(Invocation_lev, (d_level *)); E xchar NDECL(level_difficulty); E schar FDECL(lev_by_name, (const char *)); E schar FDECL(print_dungeon, (BOOLEAN_P, schar *, xchar *)); E char *FDECL(get_annotation, (d_level *)); E int NDECL(donamelevel); E int NDECL(dooverview); E void FDECL(show_overview, (int, int)); E void FDECL(forget_mapseen, (int)); E void FDECL(init_mapseen, (d_level *)); E void NDECL(recalc_mapseen); E void FDECL(mapseen_temple, (struct monst *)); E void FDECL(room_discovered, (int)); E void FDECL(recbranch_mapseen, (d_level *, d_level *)); E void FDECL(remdun_mapseen, (int)); /* ### eat.c ### */ #ifdef USE_TRAMPOLI E int NDECL(eatmdone); E int NDECL(eatfood); E int NDECL(opentin); E int NDECL(unfaint); #endif E void NDECL(eatmupdate); E boolean FDECL(is_edible, (struct obj *)); E void NDECL(init_uhunger); E int NDECL(Hear_again); E void NDECL(reset_eat); E int NDECL(doeat); E void NDECL(gethungry); E void FDECL(morehungry, (int)); E void FDECL(lesshungry, (int)); E boolean NDECL(is_fainted); E void NDECL(reset_faint); E void NDECL(violated_vegetarian); E void FDECL(newuhs, (BOOLEAN_P)); E struct obj *FDECL(floorfood, (const char *, int)); E void NDECL(vomit); E int FDECL(eaten_stat, (int, struct obj *)); E void FDECL(food_disappears, (struct obj *)); E void FDECL(food_substitution, (struct obj *, struct obj *)); E void FDECL(eating_conducts, (struct permonst *)); E int FDECL(eat_brains, (struct monst *, struct monst *, BOOLEAN_P, int *)); E void NDECL(fix_petrification); E void FDECL(consume_oeaten, (struct obj *, int)); E boolean FDECL(maybe_finished_meal, (BOOLEAN_P)); E void FDECL(set_tin_variety, (struct obj *, int)); E int FDECL(tin_variety_txt, (char *, int *)); E void FDECL(tin_details, (struct obj *, int, char *)); E boolean FDECL(Popeye, (int)); /* ### end.c ### */ E void FDECL(done1, (int)); E int NDECL(done2); #ifdef USE_TRAMPOLI E void FDECL(done_intr, (int)); #endif E void FDECL(done_in_by, (struct monst *, int)); #endif /* !MAKEDEFS_C && !LEV_LEX_C */ E void VDECL(panic, (const char *, ...)) PRINTF_F(1, 2) NORETURN; #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) E void FDECL(done, (int)); E void FDECL(container_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(terminate, (int)) NORETURN; E int NDECL(dovanquished); E int NDECL(num_genocides); E void FDECL(delayed_killer, (int, int, const char *)); E struct kinfo *FDECL(find_delayed_killer, (int)); E void FDECL(dealloc_killer, (struct kinfo *)); E void FDECL(save_killers, (int, int)); E void FDECL(restore_killers, (int)); E char *FDECL(build_english_list, (char *)); #if defined(PANICTRACE) && !defined(NO_SIGNAL) E void FDECL(panictrace_setsignals, (BOOLEAN_P)); #endif /* ### engrave.c ### */ E char *FDECL(random_engraving, (char *)); E void FDECL(wipeout_text, (char *, int, unsigned)); E boolean FDECL(can_reach_floor, (BOOLEAN_P)); E void FDECL(cant_reach_floor, (int, int, BOOLEAN_P, BOOLEAN_P)); E const char *FDECL(surface, (int, int)); E const char *FDECL(ceiling, (int, int)); E struct engr *FDECL(engr_at, (XCHAR_P, XCHAR_P)); E int FDECL(sengr_at, (const char *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(u_wipe_engr, (int)); E void FDECL(wipe_engr_at, (XCHAR_P, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(read_engr_at, (int, int)); E void FDECL(make_engr_at, (int, int, const char *, long, XCHAR_P)); E void FDECL(del_engr_at, (int, int)); E int NDECL(freehand); E int NDECL(doengrave); E void NDECL(sanitize_engravings); E void FDECL(save_engravings, (int, int)); E void FDECL(rest_engravings, (int)); E void FDECL(del_engr, (struct engr *)); E void FDECL(rloc_engr, (struct engr *)); E void FDECL(make_grave, (int, int, const char *)); /* ### exper.c ### */ E int NDECL(newpw); E int FDECL(experience, (struct monst *, int)); E void FDECL(more_experienced, (int, int)); E void FDECL(losexp, (const char *)); E void NDECL(newexplevel); E void FDECL(pluslvl, (BOOLEAN_P)); E long FDECL(rndexp, (BOOLEAN_P)); /* ### explode.c ### */ E void FDECL(explode, (int, int, int, int, CHAR_P, int)); E long FDECL(scatter, (int, int, int, unsigned int, struct obj *)); E void FDECL(splatter_burning_oil, (int, int)); E void FDECL(explode_oil, (struct obj *, int, int)); /* ### extralev.c ### */ E void NDECL(makeroguerooms); E void FDECL(corr, (int, int)); E void NDECL(makerogueghost); /* ### files.c ### */ E char *FDECL(fname_encode, (const char *, CHAR_P, char *, char *, int)); E char *FDECL(fname_decode, (CHAR_P, char *, char *, int)); E const char *FDECL(fqname, (const char *, int, int)); E FILE *FDECL(fopen_datafile, (const char *, const char *, int)); #ifdef MFLOPPY E void NDECL(set_lock_and_bones); #endif E void FDECL(set_levelfile_name, (char *, int)); E int FDECL(create_levelfile, (int, char *)); E int FDECL(open_levelfile, (int, char *)); E void FDECL(delete_levelfile, (int)); E void NDECL(clearlocks); E int FDECL(create_bonesfile, (d_level *, char **, char *)); #ifdef MFLOPPY E void NDECL(cancel_bonesfile); #endif E void FDECL(commit_bonesfile, (d_level *)); E int FDECL(open_bonesfile, (d_level *, char **)); E int FDECL(delete_bonesfile, (d_level *)); E void NDECL(compress_bonesfile); E void FDECL(set_savefile_name, (BOOLEAN_P)); #ifdef INSURANCE E void FDECL(save_savefile_name, (int)); #endif #ifndef MICRO E void NDECL(set_error_savefile); #endif E int NDECL(create_savefile); E int NDECL(open_savefile); E int NDECL(delete_savefile); E int NDECL(restore_saved_game); E void FDECL(nh_compress, (const char *)); E void FDECL(nh_uncompress, (const char *)); E boolean FDECL(lock_file, (const char *, int, int)); E void FDECL(unlock_file, (const char *)); #ifdef USER_SOUNDS E boolean FDECL(can_read_file, (const char *)); #endif E boolean FDECL(read_config_file, (const char *, int)); E void FDECL(check_recordfile, (const char *)); E void NDECL(read_wizkit); E int FDECL(read_sym_file, (int)); E int FDECL(parse_sym_line, (char *, int)); E void FDECL(paniclog, (const char *, const char *)); E int FDECL(validate_prefix_locations, (char *)); #ifdef SELECTSAVED E char *FDECL(plname_from_file, (const char *)); #endif E char **NDECL(get_saved_games); E void FDECL(free_saved_games, (char **)); #ifdef SELF_RECOVER E boolean NDECL(recover_savefile); #endif #ifdef SYSCF_FILE E void NDECL(assure_syscf_file); #endif E int FDECL(nhclose, (int)); #ifdef HOLD_LOCKFILE_OPEN E void NDECL(really_close); #endif #ifdef DEBUG E boolean FDECL(debugcore, (const char *, BOOLEAN_P)); #endif E boolean FDECL(read_tribute, (const char *, const char *, int, char *, int, unsigned)); E boolean FDECL(Death_quote, (char *, int)); /* ### fountain.c ### */ E void FDECL(floating_above, (const char *)); E void FDECL(dogushforth, (int)); #ifdef USE_TRAMPOLI E void FDECL(gush, (int, int, genericptr_t)); #endif E void FDECL(dryup, (XCHAR_P, XCHAR_P, BOOLEAN_P)); E void NDECL(drinkfountain); E void FDECL(dipfountain, (struct obj *)); E void FDECL(breaksink, (int, int)); E void NDECL(drinksink); /* ### hack.c ### */ E anything *FDECL(uint_to_any, (unsigned)); E anything *FDECL(long_to_any, (long)); E anything *FDECL(monst_to_any, (struct monst *)); E anything *FDECL(obj_to_any, (struct obj *)); E boolean FDECL(revive_nasty, (int, int, const char *)); E void FDECL(movobj, (struct obj *, XCHAR_P, XCHAR_P)); E boolean FDECL(may_dig, (XCHAR_P, XCHAR_P)); E boolean FDECL(may_passwall, (XCHAR_P, XCHAR_P)); E boolean FDECL(bad_rock, (struct permonst *, XCHAR_P, XCHAR_P)); E int FDECL(cant_squeeze_thru, (struct monst *)); E boolean FDECL(invocation_pos, (XCHAR_P, XCHAR_P)); E boolean FDECL(test_move, (int, int, int, int, int)); #ifdef DEBUG E int NDECL(wiz_debug_cmd_traveldisplay); #endif E boolean NDECL(u_rooted); E void NDECL(domove); E boolean NDECL(overexertion); E void NDECL(invocation_message); E boolean FDECL(pooleffects, (BOOLEAN_P)); E void FDECL(spoteffects, (BOOLEAN_P)); E char *FDECL(in_rooms, (XCHAR_P, XCHAR_P, int)); E boolean FDECL(in_town, (int, int)); E void FDECL(check_special_room, (BOOLEAN_P)); E int NDECL(dopickup); E void NDECL(lookaround); E boolean FDECL(crawl_destination, (int, int)); E int NDECL(monster_nearby); E void FDECL(nomul, (int)); E void FDECL(unmul, (const char *)); E void FDECL(losehp, (int, const char *, BOOLEAN_P)); E int NDECL(weight_cap); E int NDECL(inv_weight); E int NDECL(near_capacity); E int FDECL(calc_capacity, (int)); E int NDECL(max_capacity); E boolean FDECL(check_capacity, (const char *)); E int FDECL(inv_cnt, (BOOLEAN_P)); E long FDECL(money_cnt, (struct obj *)); /* ### hacklib.c ### */ E boolean FDECL(digit, (CHAR_P)); E boolean FDECL(letter, (CHAR_P)); E char FDECL(highc, (CHAR_P)); E char FDECL(lowc, (CHAR_P)); E char *FDECL(lcase, (char *)); E char *FDECL(ucase, (char *)); E char *FDECL(upstart, (char *)); E char *FDECL(mungspaces, (char *)); E char *FDECL(eos, (char *)); E boolean FDECL(str_end_is, (const char *, const char *)); E char *FDECL(strkitten, (char *, CHAR_P)); E void FDECL(copynchars, (char *, const char *, int)); E char FDECL(chrcasecpy, (int, int)); E char *FDECL(strcasecpy, (char *, const char *)); E char *FDECL(s_suffix, (const char *)); E char *FDECL(ing_suffix, (const char *)); E char *FDECL(xcrypt, (const char *, char *)); E boolean FDECL(onlyspace, (const char *)); E char *FDECL(tabexpand, (char *)); E char *FDECL(visctrl, (CHAR_P)); E char *FDECL(strsubst, (char *, const char *, const char *)); E const char *FDECL(ordin, (int)); E char *FDECL(sitoa, (int)); E int FDECL(sgn, (int)); E int FDECL(rounddiv, (long, int)); E int FDECL(dist2, (int, int, int, int)); E int FDECL(isqrt, (int)); E int FDECL(distmin, (int, int, int, int)); E boolean FDECL(online2, (int, int, int, int)); E boolean FDECL(pmatch, (const char *, const char *)); E boolean FDECL(pmatchi, (const char *, const char *)); E boolean FDECL(pmatchz, (const char *, const char *)); #ifndef STRNCMPI E int FDECL(strncmpi, (const char *, const char *, int)); #endif #ifndef STRSTRI E char *FDECL(strstri, (const char *, const char *)); #endif E boolean FDECL(fuzzymatch, (const char *, const char *, const char *, BOOLEAN_P)); E void NDECL(setrandom); E time_t NDECL(getnow); E int NDECL(getyear); #if 0 E char *FDECL(yymmdd, (time_t)); #endif E long FDECL(yyyymmdd, (time_t)); E long FDECL(hhmmss, (time_t)); E char *FDECL(yyyymmddhhmmss, (time_t)); E time_t FDECL(time_from_yyyymmddhhmmss, (char *)); E int NDECL(phase_of_the_moon); E boolean NDECL(friday_13th); E int NDECL(night); E int NDECL(midnight); /* ### invent.c ### */ E struct obj **FDECL(objarr_init, (int)); E void FDECL(objarr_set, (struct obj *, int, struct obj **, BOOLEAN_P)); E void FDECL(assigninvlet, (struct obj *)); E struct obj *FDECL(merge_choice, (struct obj *, struct obj *)); E int FDECL(merged, (struct obj **, struct obj **)); #ifdef USE_TRAMPOLI E int FDECL(ckunpaid, (struct obj *)); #endif E void FDECL(addinv_core1, (struct obj *)); E void FDECL(addinv_core2, (struct obj *)); E struct obj *FDECL(addinv, (struct obj *)); E struct obj *FDECL(hold_another_object, (struct obj *, const char *, const char *, const char *)); E void FDECL(useupall, (struct obj *)); E void FDECL(useup, (struct obj *)); E void FDECL(consume_obj_charge, (struct obj *, BOOLEAN_P)); E void FDECL(freeinv_core, (struct obj *)); E void FDECL(freeinv, (struct obj *)); E void FDECL(delallobj, (int, int)); E void FDECL(delobj, (struct obj *)); E struct obj *FDECL(sobj_at, (int, int, int)); E struct obj *FDECL(nxtobj, (struct obj *, int, BOOLEAN_P)); E struct obj *FDECL(carrying, (int)); E boolean NDECL(have_lizard); E struct obj *NDECL(u_have_novel); E struct obj *FDECL(o_on, (unsigned int, struct obj *)); E boolean FDECL(obj_here, (struct obj *, int, int)); E boolean NDECL(wearing_armor); E boolean FDECL(is_worn, (struct obj *)); E struct obj *FDECL(g_at, (int, int)); E struct obj *FDECL(getobj, (const char *, const char *)); E int FDECL(ggetobj, (const char *, int (*)(OBJ_P), int, BOOLEAN_P, unsigned *)); E int FDECL(askchain, (struct obj **, const char *, int, int (*)(OBJ_P), int (*)(OBJ_P), int, const char *)); E void FDECL(fully_identify_obj, (struct obj *)); E int FDECL(identify, (struct obj *)); E void FDECL(identify_pack, (int, BOOLEAN_P)); E void NDECL(learn_unseen_invent); E void FDECL(prinv, (const char *, struct obj *, long)); E char *FDECL(xprname, (struct obj *, const char *, CHAR_P, BOOLEAN_P, long, long)); E int NDECL(ddoinv); E char FDECL(display_inventory, (const char *, BOOLEAN_P)); E int FDECL(display_binventory, (int, int, BOOLEAN_P)); E struct obj *FDECL(display_cinventory, (struct obj *)); E struct obj *FDECL(display_minventory, (struct monst *, int, char *)); E int NDECL(dotypeinv); E const char *FDECL(dfeature_at, (int, int, char *)); E int FDECL(look_here, (int, BOOLEAN_P)); E int NDECL(dolook); E boolean FDECL(will_feel_cockatrice, (struct obj *, BOOLEAN_P)); E void FDECL(feel_cockatrice, (struct obj *, BOOLEAN_P)); E void FDECL(stackobj, (struct obj *)); E int NDECL(doprgold); E int NDECL(doprwep); E int NDECL(doprarm); E int NDECL(doprring); E int NDECL(dopramulet); E int NDECL(doprtool); E int NDECL(doprinuse); E void FDECL(useupf, (struct obj *, long)); E char *FDECL(let_to_name, (CHAR_P, BOOLEAN_P, BOOLEAN_P)); E void NDECL(free_invbuf); E void NDECL(reassign); E int NDECL(doorganize); E void NDECL(free_pickinv_cache); E int FDECL(count_unpaid, (struct obj *)); E int FDECL(count_buc, (struct obj *, int)); E long FDECL(count_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(carry_obj_effects, (struct obj *)); E const char *FDECL(currency, (long)); E void FDECL(silly_thing, (const char *, struct obj *)); /* ### ioctl.c ### */ #if defined(UNIX) || defined(__BEOS__) E void NDECL(getwindowsz); E void NDECL(getioctls); E void NDECL(setioctls); #ifdef SUSPEND E int NDECL(dosuspend); #endif /* SUSPEND */ #endif /* UNIX || __BEOS__ */ /* ### light.c ### */ E void FDECL(new_light_source, (XCHAR_P, XCHAR_P, int, int, ANY_P *)); E void FDECL(del_light_source, (int, ANY_P *)); E void FDECL(do_light_sources, (char **)); E struct monst *FDECL(find_mid, (unsigned, unsigned)); E void FDECL(save_light_sources, (int, int, int)); E void FDECL(restore_light_sources, (int)); E void FDECL(relink_light_sources, (BOOLEAN_P)); E void NDECL(light_sources_sanity_check); E void FDECL(obj_move_light_source, (struct obj *, struct obj *)); E boolean NDECL(any_light_source); E void FDECL(snuff_light_source, (int, int)); E boolean FDECL(obj_sheds_light, (struct obj *)); E boolean FDECL(obj_is_burning, (struct obj *)); E void FDECL(obj_split_light_source, (struct obj *, struct obj *)); E void FDECL(obj_merge_light_sources, (struct obj *, struct obj *)); E void FDECL(obj_adjust_light_radius, (struct obj *, int)); E int FDECL(candle_light_range, (struct obj *)); E int FDECL(arti_light_radius, (struct obj *)); E const char *FDECL(arti_light_description, (struct obj *)); E int NDECL(wiz_light_sources); /* ### lock.c ### */ #ifdef USE_TRAMPOLI E int NDECL(forcelock); E int NDECL(picklock); #endif E boolean FDECL(picking_lock, (int *, int *)); E boolean FDECL(picking_at, (int, int)); E void FDECL(breakchestlock, (struct obj *, BOOLEAN_P)); E void NDECL(reset_pick); E int FDECL(pick_lock, (struct obj *)); E int NDECL(doforce); E boolean FDECL(boxlock, (struct obj *, struct obj *)); E boolean FDECL(doorlock, (struct obj *, int, int)); E int NDECL(doopen); E boolean FDECL(stumble_on_door_mimic, (int, int)); E int FDECL(doopen_indir, (int, int)); E int NDECL(doclose); #ifdef MAC /* These declarations are here because the main code calls them. */ /* ### macfile.c ### */ E int FDECL(maccreat, (const char *, long)); E int FDECL(macopen, (const char *, int, long)); E int FDECL(macclose, (int)); E int FDECL(macread, (int, void *, unsigned)); E int FDECL(macwrite, (int, void *, unsigned)); E long FDECL(macseek, (int, long, short)); E int FDECL(macunlink, (const char *)); /* ### macmain.c ### */ E boolean NDECL(authorize_wizard_mode); /* ### macsnd.c ### */ E void FDECL(mac_speaker, (struct obj *, char *)); /* ### macunix.c ### */ E void FDECL(regularize, (char *)); E void NDECL(getlock); /* ### macwin.c ### */ E void FDECL(lock_mouse_cursor, (Boolean)); E int NDECL(SanePositions); /* ### mttymain.c ### */ E void FDECL(getreturn, (char *)); E void VDECL(msmsg, (const char *, ...)); E void NDECL(gettty); E void NDECL(setftty); E void FDECL(settty, (const char *)); E int NDECL(tgetch); E void FDECL(cmov, (int x, int y)); E void FDECL(nocmov, (int x, int y)); #endif /* MAC */ /* ### mail.c ### */ #ifdef MAIL #ifdef UNIX E void NDECL(getmailstatus); #endif E void NDECL(ckmailstatus); E void FDECL(readmail, (struct obj *)); #endif /* MAIL */ /* ### makemon.c ### */ E void FDECL(dealloc_monst, (struct monst *)); E boolean FDECL(is_home_elemental, (struct permonst *)); E struct monst *FDECL(clone_mon, (struct monst *, XCHAR_P, XCHAR_P)); E int FDECL(monhp_per_lvl, (struct monst *)); E void FDECL(newmonhp, (struct monst *, int)); E struct mextra *NDECL(newmextra); E void FDECL(copy_mextra, (struct monst *, struct monst *)); E void FDECL(dealloc_mextra, (struct monst *)); E struct monst *FDECL(makemon, (struct permonst *, int, int, int)); E boolean FDECL(create_critters, (int, struct permonst *, BOOLEAN_P)); E struct permonst *NDECL(rndmonst); E void FDECL(reset_rndmonst, (int)); E struct permonst *FDECL(mkclass, (CHAR_P, int)); E int FDECL(mkclass_poly, (int)); E int FDECL(adj_lev, (struct permonst *)); E struct permonst *FDECL(grow_up, (struct monst *, struct monst *)); E int FDECL(mongets, (struct monst *, int)); E int FDECL(golemhp, (int)); E boolean FDECL(peace_minded, (struct permonst *)); E void FDECL(set_malign, (struct monst *)); E void FDECL(newmcorpsenm, (struct monst *)); E void FDECL(freemcorpsenm, (struct monst *)); E void FDECL(set_mimic_sym, (struct monst *)); E int FDECL(mbirth_limit, (int)); E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P)); E void FDECL(mkmonmoney, (struct monst *, long)); E int FDECL(bagotricks, (struct obj *, BOOLEAN_P, int *)); E boolean FDECL(propagate, (int, BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(usmellmon, (struct permonst *)); /* ### mapglyph.c ### */ E int FDECL(mapglyph, (int, int *, int *, unsigned *, int, int)); E char *FDECL(encglyph, (int)); E void FDECL(genl_putmixed, (winid, int, const char *)); /* ### mcastu.c ### */ E int FDECL(castmu, (struct monst *, struct attack *, BOOLEAN_P, BOOLEAN_P)); E int FDECL(buzzmu, (struct monst *, struct attack *)); /* ### mhitm.c ### */ E int FDECL(fightm, (struct monst *)); E int FDECL(mattackm, (struct monst *, struct monst *)); E boolean FDECL(engulf_target, (struct monst *, struct monst *)); E int FDECL(mdisplacem, (struct monst *, struct monst *, BOOLEAN_P)); E void FDECL(paralyze_monst, (struct monst *, int)); E int FDECL(sleep_monst, (struct monst *, int, int)); E void FDECL(slept_monst, (struct monst *)); E void FDECL(xdrainenergym, (struct monst *, BOOLEAN_P)); E long FDECL(attk_protection, (int)); E void FDECL(rustm, (struct monst *, struct obj *)); /* ### mhitu.c ### */ E const char *FDECL(mpoisons_subj, (struct monst *, struct attack *)); E void NDECL(u_slow_down); E struct monst *NDECL(cloneu); E void FDECL(expels, (struct monst *, struct permonst *, BOOLEAN_P)); E struct attack *FDECL(getmattk, (struct permonst *, int, int *, struct attack *)); E int FDECL(mattacku, (struct monst *)); E int FDECL(magic_negation, (struct monst *)); E boolean NDECL(gulp_blnd_check); E int FDECL(gazemu, (struct monst *, struct attack *)); E void FDECL(mdamageu, (struct monst *, int)); E int FDECL(could_seduce, (struct monst *, struct monst *, struct attack *)); E int FDECL(doseduce, (struct monst *)); /* ### minion.c ### */ E void FDECL(newemin, (struct monst *)); E void FDECL(free_emin, (struct monst *)); E int FDECL(monster_census, (BOOLEAN_P)); E int FDECL(msummon, (struct monst *)); E void FDECL(summon_minion, (ALIGNTYP_P, BOOLEAN_P)); E int FDECL(demon_talk, (struct monst *)); E long FDECL(bribe, (struct monst *)); E int FDECL(dprince, (ALIGNTYP_P)); E int FDECL(dlord, (ALIGNTYP_P)); E int NDECL(llord); E int FDECL(ndemon, (ALIGNTYP_P)); E int NDECL(lminion); E void FDECL(lose_guardian_angel, (struct monst *)); E void NDECL(gain_guardian_angel); /* ### mklev.c ### */ #ifdef USE_TRAMPOLI E int FDECL(do_comp, (genericptr_t, genericptr_t)); #endif E void NDECL(sort_rooms); E void FDECL(add_room, (int, int, int, int, BOOLEAN_P, SCHAR_P, BOOLEAN_P)); E void FDECL(add_subroom, (struct mkroom *, int, int, int, int, BOOLEAN_P, SCHAR_P, BOOLEAN_P)); E void NDECL(makecorridors); E void FDECL(add_door, (int, int, struct mkroom *)); E void NDECL(mklev); #ifdef SPECIALIZATION E void FDECL(topologize, (struct mkroom *, BOOLEAN_P)); #else E void FDECL(topologize, (struct mkroom *)); #endif E void FDECL(place_branch, (branch *, XCHAR_P, XCHAR_P)); E boolean FDECL(occupied, (XCHAR_P, XCHAR_P)); E int FDECL(okdoor, (XCHAR_P, XCHAR_P)); E void FDECL(dodoor, (int, int, struct mkroom *)); E void FDECL(mktrap, (int, int, struct mkroom *, coord *)); E void FDECL(mkstairs, (XCHAR_P, XCHAR_P, CHAR_P, struct mkroom *)); E void NDECL(mkinvokearea); E void FDECL(mineralize, (int, int, int, int, BOOLEAN_P)); /* ### mkmap.c ### */ E void FDECL(flood_fill_rm, (int, int, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(remove_rooms, (int, int, int, int)); /* E void FDECL(mkmap, (lev_init *)); -- need sp_lev.h for lev_init */ /* ### mkmaze.c ### */ E void FDECL(wallification, (int, int, int, int)); E void FDECL(walkfrom, (int, int, SCHAR_P)); E void FDECL(makemaz, (const char *)); E void FDECL(mazexy, (coord *)); E void NDECL(bound_digging); E void FDECL(mkportal, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E boolean FDECL(bad_location, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E void FDECL(place_lregion, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, d_level *)); E void NDECL(fumaroles); E void NDECL(movebubbles); E void NDECL(water_friction); E void FDECL(save_waterlevel, (int, int)); E void FDECL(restore_waterlevel, (int)); E const char *FDECL(waterbody_name, (XCHAR_P, XCHAR_P)); /* ### mkobj.c ### */ E struct oextra *NDECL(newoextra); E void FDECL(copy_oextra, (struct obj *, struct obj *)); E void FDECL(dealloc_oextra, (struct obj *)); E void FDECL(newomonst, (struct obj *)); E void FDECL(free_omonst, (struct obj *)); E void FDECL(newomid, (struct obj *)); E void FDECL(free_omid, (struct obj *)); E void FDECL(newolong, (struct obj *)); E void FDECL(free_olong, (struct obj *)); E void FDECL(new_omailcmd, (struct obj *, const char *)); E void FDECL(free_omailcmd, (struct obj *)); E struct obj *FDECL(mkobj_at, (CHAR_P, int, int, BOOLEAN_P)); E struct obj *FDECL(mksobj_at, (int, int, int, BOOLEAN_P, BOOLEAN_P)); E struct obj *FDECL(mkobj, (CHAR_P, BOOLEAN_P)); E int NDECL(rndmonnum); E boolean FDECL(bogon_is_pname, (CHAR_P)); E struct obj *FDECL(splitobj, (struct obj *, long)); E struct obj *FDECL(unsplitobj, (struct obj *)); E void NDECL(clear_splitobjs); E void FDECL(replace_object, (struct obj *, struct obj *)); E void FDECL(bill_dummy_object, (struct obj *)); E void FDECL(costly_alteration, (struct obj *, int)); E struct obj *FDECL(mksobj, (int, BOOLEAN_P, BOOLEAN_P)); E int FDECL(bcsign, (struct obj *)); E int FDECL(weight, (struct obj *)); E struct obj *FDECL(mkgold, (long, int, int)); E struct obj *FDECL(mkcorpstat, (int, struct monst *, struct permonst *, int, int, unsigned)); E int FDECL(corpse_revive_type, (struct obj *)); E struct obj *FDECL(obj_attach_mid, (struct obj *, unsigned)); E struct monst *FDECL(get_mtraits, (struct obj *, BOOLEAN_P)); E struct obj *FDECL(mk_tt_object, (int, int, int)); E struct obj *FDECL(mk_named_object, (int, struct permonst *, int, int, const char *)); E struct obj *FDECL(rnd_treefruit_at, (int, int)); E void FDECL(set_corpsenm, (struct obj *, int)); E void FDECL(start_corpse_timeout, (struct obj *)); E void FDECL(bless, (struct obj *)); E void FDECL(unbless, (struct obj *)); E void FDECL(curse, (struct obj *)); E void FDECL(uncurse, (struct obj *)); E void FDECL(blessorcurse, (struct obj *, int)); E boolean FDECL(is_flammable, (struct obj *)); E boolean FDECL(is_rottable, (struct obj *)); E void FDECL(place_object, (struct obj *, int, int)); E void FDECL(remove_object, (struct obj *)); E void FDECL(discard_minvent, (struct monst *)); E void FDECL(obj_extract_self, (struct obj *)); E void FDECL(extract_nobj, (struct obj *, struct obj **)); E void FDECL(extract_nexthere, (struct obj *, struct obj **)); E int FDECL(add_to_minv, (struct monst *, struct obj *)); E struct obj *FDECL(add_to_container, (struct obj *, struct obj *)); E void FDECL(add_to_migration, (struct obj *)); E void FDECL(add_to_buried, (struct obj *)); E void FDECL(dealloc_obj, (struct obj *)); E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P)); E long FDECL(peek_at_iced_corpse_age, (struct obj *)); E int FDECL(hornoplenty, (struct obj *, BOOLEAN_P)); E void NDECL(obj_sanity_check); E struct obj *FDECL(obj_nexto, (struct obj *)); E struct obj *FDECL(obj_nexto_xy, (int, int, int, unsigned)); E struct obj *FDECL(obj_absorb, (struct obj **, struct obj **)); E struct obj *FDECL(obj_meld, (struct obj **, struct obj **)); /* ### mkroom.c ### */ E void FDECL(mkroom, (int)); E void FDECL(fill_zoo, (struct mkroom *)); E struct permonst *NDECL(antholemon); E boolean FDECL(nexttodoor, (int, int)); E boolean FDECL(has_dnstairs, (struct mkroom *)); E boolean FDECL(has_upstairs, (struct mkroom *)); E int FDECL(somex, (struct mkroom *)); E int FDECL(somey, (struct mkroom *)); E boolean FDECL(inside_room, (struct mkroom *, XCHAR_P, XCHAR_P)); E boolean FDECL(somexy, (struct mkroom *, coord *)); E void FDECL(mkundead, (coord *, BOOLEAN_P, int)); E struct permonst *NDECL(courtmon); E void FDECL(save_rooms, (int)); E void FDECL(rest_rooms, (int)); E struct mkroom *FDECL(search_special, (SCHAR_P)); E int FDECL(cmap_to_type, (int)); /* ### mon.c ### */ E void NDECL(mon_sanity_check); E int FDECL(undead_to_corpse, (int)); E int FDECL(genus, (int, int)); E int FDECL(pm_to_cham, (int)); E int FDECL(minliquid, (struct monst *)); E int NDECL(movemon); E int FDECL(meatmetal, (struct monst *)); E int FDECL(meatobj, (struct monst *)); E void FDECL(mpickgold, (struct monst *)); E boolean FDECL(mpickstuff, (struct monst *, const char *)); E int FDECL(curr_mon_load, (struct monst *)); E int FDECL(max_mon_load, (struct monst *)); E int FDECL(can_carry, (struct monst *, struct obj *)); E int FDECL(mfndpos, (struct monst *, coord *, long *, long)); E boolean FDECL(monnear, (struct monst *, int, int)); E void NDECL(dmonsfree); E int FDECL(mcalcmove, (struct monst *)); E void NDECL(mcalcdistress); E void FDECL(replmon, (struct monst *, struct monst *)); E void FDECL(relmon, (struct monst *, struct monst **)); E struct obj *FDECL(mlifesaver, (struct monst *)); E boolean FDECL(corpse_chance, (struct monst *, struct monst *, BOOLEAN_P)); E void FDECL(mondead, (struct monst *)); E void FDECL(mondied, (struct monst *)); E void FDECL(mongone, (struct monst *)); E void FDECL(monstone, (struct monst *)); E void FDECL(monkilled, (struct monst *, const char *, int)); E void FDECL(unstuck, (struct monst *)); E void FDECL(killed, (struct monst *)); E void FDECL(xkilled, (struct monst *, int)); E void FDECL(mon_to_stone, (struct monst *)); E void FDECL(mnexto, (struct monst *)); E void FDECL(maybe_mnexto, (struct monst *)); E boolean FDECL(mnearto, (struct monst *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(m_respond, (struct monst *)); E void FDECL(setmangry, (struct monst *)); E void FDECL(wakeup, (struct monst *)); E void NDECL(wake_nearby); E void FDECL(wake_nearto, (int, int, int)); E void FDECL(seemimic, (struct monst *)); E void NDECL(rescham); E void NDECL(restartcham); E void FDECL(restore_cham, (struct monst *)); E boolean FDECL(hideunder, (struct monst *)); E void FDECL(hide_monst, (struct monst *)); E void FDECL(mon_animal_list, (BOOLEAN_P)); E int FDECL(select_newcham_form, (struct monst *)); E void FDECL(mgender_from_permonst, (struct monst *, struct permonst *)); E int FDECL(newcham, (struct monst *, struct permonst *, BOOLEAN_P, BOOLEAN_P)); E int FDECL(can_be_hatched, (int)); E int FDECL(egg_type_from_parent, (int, BOOLEAN_P)); E boolean FDECL(dead_species, (int, BOOLEAN_P)); E void NDECL(kill_genocided_monsters); E void FDECL(golemeffects, (struct monst *, int, int)); E boolean FDECL(angry_guards, (BOOLEAN_P)); E void NDECL(pacify_guards); E void FDECL(decide_to_shapeshift, (struct monst *, int)); /* ### mondata.c ### */ E void FDECL(set_mon_data, (struct monst *, struct permonst *, int)); E struct attack *FDECL(attacktype_fordmg, (struct permonst *, int, int)); E boolean FDECL(attacktype, (struct permonst *, int)); E boolean FDECL(noattacks, (struct permonst *)); E boolean FDECL(poly_when_stoned, (struct permonst *)); E boolean FDECL(resists_drli, (struct monst *)); E boolean FDECL(resists_magm, (struct monst *)); E boolean FDECL(resists_blnd, (struct monst *)); E boolean FDECL(can_blnd, (struct monst *, struct monst *, UCHAR_P, struct obj *)); E boolean FDECL(ranged_attk, (struct permonst *)); E boolean FDECL(hates_silver, (struct permonst *)); E boolean FDECL(mon_hates_silver, (struct monst *)); E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_blow, (struct monst *)); E boolean FDECL(can_be_strangled, (struct monst *)); E boolean FDECL(can_track, (struct permonst *)); E boolean FDECL(breakarm, (struct permonst *)); E boolean FDECL(sliparm, (struct permonst *)); E boolean FDECL(sticks, (struct permonst *)); E boolean FDECL(cantvomit, (struct permonst *)); E int FDECL(num_horns, (struct permonst *)); /* E boolean FDECL(canseemon, (struct monst *)); */ E struct attack *FDECL(dmgtype_fromattack, (struct permonst *, int, int)); E boolean FDECL(dmgtype, (struct permonst *, int)); E int FDECL(max_passive_dmg, (struct monst *, struct monst *)); E boolean FDECL(same_race, (struct permonst *, struct permonst *)); E int FDECL(monsndx, (struct permonst *)); E int FDECL(name_to_mon, (const char *)); E int FDECL(name_to_monclass, (const char *, int *)); E int FDECL(gender, (struct monst *)); E int FDECL(pronoun_gender, (struct monst *)); E boolean FDECL(levl_follower, (struct monst *)); E int FDECL(little_to_big, (int)); E int FDECL(big_to_little, (int)); E const char *FDECL(locomotion, (const struct permonst *, const char *)); E const char *FDECL(stagger, (const struct permonst *, const char *)); E const char *FDECL(on_fire, (struct permonst *, struct attack *)); E const struct permonst *FDECL(raceptr, (struct monst *)); E boolean FDECL(olfaction, (struct permonst *)); /* ### monmove.c ### */ E boolean FDECL(itsstuck, (struct monst *)); E boolean FDECL(mb_trapped, (struct monst *)); E boolean FDECL(monhaskey, (struct monst *, BOOLEAN_P)); E void FDECL(mon_regen, (struct monst *, BOOLEAN_P)); E int FDECL(dochugw, (struct monst *)); E boolean FDECL(onscary, (int, int, struct monst *)); E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(mon_yells, (struct monst *, const char *)); E int FDECL(dochug, (struct monst *)); E int FDECL(m_move, (struct monst *, int)); E void FDECL(dissolve_bars, (int, int)); E boolean FDECL(closed_door, (int, int)); E boolean FDECL(accessible, (int, int)); E void FDECL(set_apparxy, (struct monst *)); E boolean FDECL(can_ooze, (struct monst *)); E boolean FDECL(can_fog, (struct monst *)); E boolean FDECL(should_displace, (struct monst *, coord *, long *, int, XCHAR_P, XCHAR_P)); E boolean FDECL(undesirable_disp, (struct monst *, XCHAR_P, XCHAR_P)); /* ### monst.c ### */ E void NDECL(monst_init); /* ### monstr.c ### */ E void NDECL(monstr_init); /* ### mplayer.c ### */ E struct monst *FDECL(mk_mplayer, (struct permonst *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(create_mplayers, (int, BOOLEAN_P)); E void FDECL(mplayer_talk, (struct monst *)); #if defined(MICRO) || defined(WIN32) /* ### msdos.c,os2.c,tos.c,winnt.c ### */ #ifndef WIN32 E int NDECL(tgetch); #endif #ifndef TOS E char NDECL(switchar); #endif #ifndef __GO32__ E long FDECL(freediskspace, (char *)); #ifdef MSDOS E int FDECL(findfirst_file, (char *)); E int NDECL(findnext_file); E long FDECL(filesize_nh, (char *)); #else E int FDECL(findfirst, (char *)); E int NDECL(findnext); E long FDECL(filesize, (char *)); #endif /* MSDOS */ E char *NDECL(foundfile_buffer); #endif /* __GO32__ */ E void FDECL(chdrive, (char *)); #ifndef TOS E void NDECL(disable_ctrlP); E void NDECL(enable_ctrlP); #endif #if defined(MICRO) && !defined(WINNT) E void NDECL(get_scr_size); #ifndef TOS E void FDECL(gotoxy, (int, int)); #endif #endif #ifdef TOS E int FDECL(_copyfile, (char *, char *)); E int NDECL(kbhit); E void NDECL(set_colors); E void NDECL(restore_colors); #ifdef SUSPEND E int NDECL(dosuspend); #endif #endif /* TOS */ #ifdef WIN32 E char *FDECL(get_username, (int *)); E void FDECL(nt_regularize, (char *)); E int NDECL((*nt_kbhit)); E void FDECL(Delay, (int)); #endif /* WIN32 */ #endif /* MICRO || WIN32 */ /* ### mthrowu.c ### */ E int FDECL(thitu, (int, int, struct obj *, const char *)); E int FDECL(ohitmon, (struct monst *, struct obj *, int, BOOLEAN_P)); E void FDECL(thrwmu, (struct monst *)); E int FDECL(spitmu, (struct monst *, struct attack *)); E int FDECL(breamu, (struct monst *, struct attack *)); E boolean FDECL(linedup, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, int)); E boolean FDECL(lined_up, (struct monst *)); E struct obj *FDECL(m_carrying, (struct monst *, int)); E void FDECL(m_useupall, (struct monst *, struct obj *)); E void FDECL(m_useup, (struct monst *, struct obj *)); E void FDECL(m_throw, (struct monst *, int, int, int, int, int, struct obj *)); E boolean FDECL(hits_bars, (struct obj **, int, int, int, int)); /* ### muse.c ### */ E boolean FDECL(find_defensive, (struct monst *)); E int FDECL(use_defensive, (struct monst *)); E int FDECL(rnd_defensive_item, (struct monst *)); E boolean FDECL(find_offensive, (struct monst *)); #ifdef USE_TRAMPOLI E int FDECL(mbhitm, (struct monst *, struct obj *)); #endif E int FDECL(use_offensive, (struct monst *)); E int FDECL(rnd_offensive_item, (struct monst *)); E boolean FDECL(find_misc, (struct monst *)); E int FDECL(use_misc, (struct monst *)); E int FDECL(rnd_misc_item, (struct monst *)); E boolean FDECL(searches_for_item, (struct monst *, struct obj *)); E boolean FDECL(mon_reflects, (struct monst *, const char *)); E boolean FDECL(ureflects, (const char *, const char *)); E boolean FDECL(munstone, (struct monst *, BOOLEAN_P)); E boolean FDECL(munslime, (struct monst *, BOOLEAN_P)); /* ### music.c ### */ E void FDECL(awaken_soldiers, (struct monst *)); E int FDECL(do_play_instrument, (struct obj *)); /* ### nhlan.c ### */ #ifdef LAN_FEATURES E void NDECL(init_lan_features); E char *NDECL(lan_username); #endif /* ### nhregex.c ### */ E struct nhregex *NDECL(regex_init); E boolean FDECL(regex_compile, (const char *, struct nhregex *)); E const char *FDECL(regex_error_desc, (struct nhregex *)); E boolean FDECL(regex_match, (const char *, struct nhregex *)); E void FDECL(regex_free, (struct nhregex *)); /* ### nttty.c ### */ #ifdef WIN32 E void NDECL(get_scr_size); E int NDECL(nttty_kbhit); E void FDECL(nttty_open, (int)); E void NDECL(nttty_rubout); E int NDECL(tgetch); E int FDECL(ntposkey, (int *, int *, int *)); E void FDECL(set_output_mode, (int)); E void NDECL(synch_cursor); #endif /* ### o_init.c ### */ E void NDECL(init_objects); E void FDECL(obj_shuffle_range, (int, int *, int *)); E int NDECL(find_skates); E void NDECL(oinit); E void FDECL(savenames, (int, int)); E void FDECL(restnames, (int)); E void FDECL(discover_object, (int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(undiscover_object, (int)); E int NDECL(dodiscovered); E int NDECL(doclassdisco); E void NDECL(rename_disco); /* ### objects.c ### */ E void NDECL(objects_init); /* ### objnam.c ### */ E char *FDECL(obj_typename, (int)); E char *FDECL(simple_typename, (int)); E boolean FDECL(obj_is_pname, (struct obj *)); E char *FDECL(distant_name, (struct obj *, char *(*)(OBJ_P))); E char *FDECL(fruitname, (BOOLEAN_P)); E char *FDECL(xname, (struct obj *)); E char *FDECL(mshot_xname, (struct obj *)); E boolean FDECL(the_unique_obj, (struct obj *)); E boolean FDECL(the_unique_pm, (struct permonst *)); E char *FDECL(doname, (struct obj *)); E char *FDECL(doname_with_price, (struct obj *)); E boolean FDECL(not_fully_identified, (struct obj *)); E char *FDECL(corpse_xname, (struct obj *, const char *, unsigned)); E char *FDECL(cxname, (struct obj *)); E char *FDECL(cxname_singular, (struct obj *)); E char *FDECL(killer_xname, (struct obj *)); E char *FDECL(short_oname, (struct obj *, char *(*)(OBJ_P), char *(*)(OBJ_P), unsigned)); E const char *FDECL(singular, (struct obj *, char *(*)(OBJ_P))); E char *FDECL(an, (const char *)); E char *FDECL(An, (const char *)); E char *FDECL(The, (const char *)); E char *FDECL(the, (const char *)); E char *FDECL(aobjnam, (struct obj *, const char *)); E char *FDECL(yobjnam, (struct obj *, const char *)); E char *FDECL(Yobjnam2, (struct obj *, const char *)); E char *FDECL(Tobjnam, (struct obj *, const char *)); E char *FDECL(otense, (struct obj *, const char *)); E char *FDECL(vtense, (const char *, const char *)); E char *FDECL(Doname2, (struct obj *)); E char *FDECL(yname, (struct obj *)); E char *FDECL(Yname2, (struct obj *)); E char *FDECL(ysimple_name, (struct obj *)); E char *FDECL(Ysimple_name2, (struct obj *)); E char *FDECL(simpleonames, (struct obj *)); E char *FDECL(ansimpleoname, (struct obj *)); E char *FDECL(thesimpleoname, (struct obj *)); E char *FDECL(bare_artifactname, (struct obj *)); E char *FDECL(makeplural, (const char *)); E char *FDECL(makesingular, (const char *)); E struct obj *FDECL(readobjnam, (char *, struct obj *)); E int FDECL(rnd_class, (int, int)); E const char *FDECL(suit_simple_name, (struct obj *)); E const char *FDECL(cloak_simple_name, (struct obj *)); E const char *FDECL(helm_simple_name, (struct obj *)); E const char *FDECL(mimic_obj_name, (struct monst *)); E char *FDECL(safe_qbuf, (char *, const char *, const char *, struct obj *, char *(*)(OBJ_P), char *(*)(OBJ_P), const char *)); /* ### options.c ### */ E void NDECL(reglyph_darkroom); E boolean FDECL(match_optname, (const char *, const char *, int, BOOLEAN_P)); E void NDECL(initoptions); E void NDECL(initoptions_init); E void NDECL(initoptions_finish); E void FDECL(parseoptions, (char *, BOOLEAN_P, BOOLEAN_P)); E int NDECL(doset); E int NDECL(dotogglepickup); E void NDECL(option_help); E void FDECL(next_opt, (winid, const char *)); E int FDECL(fruitadd, (char *, struct fruit *)); E int FDECL(choose_classes_menu, (const char *, int, BOOLEAN_P, char *, char *)); E void FDECL(add_menu_cmd_alias, (CHAR_P, CHAR_P)); E char FDECL(map_menu_cmd, (CHAR_P)); E void FDECL(assign_warnings, (uchar *)); E char *FDECL(nh_getenv, (const char *)); E void FDECL(set_duplicate_opt_detection, (int)); E void FDECL(set_wc_option_mod_status, (unsigned long, int)); E void FDECL(set_wc2_option_mod_status, (unsigned long, int)); E void FDECL(set_option_mod_status, (const char *, int)); E int FDECL(add_autopickup_exception, (const char *)); E void NDECL(free_autopickup_exceptions); E int FDECL(load_symset, (const char *, int)); E void NDECL(free_symsets); E void FDECL(parsesymbols, (char *)); E struct symparse *FDECL(match_sym, (char *)); E void NDECL(set_playmode); E int FDECL(sym_val, (char *)); E const char *FDECL(clr2colorname, (int)); E boolean FDECL(add_menu_coloring, (char *)); E boolean FDECL(get_menu_coloring, (char *, int *, int *)); E void NDECL(free_menu_coloring); E boolean FDECL(msgtype_parse_add, (char *)); E int FDECL(msgtype_type, (const char *)); E void NDECL(msgtype_free); /* ### pager.c ### */ E char *FDECL(self_lookat, (char *)); E boolean FDECL(object_from_map, (int,int,int,struct obj **)); E int NDECL(dowhatis); E int NDECL(doquickwhatis); E int NDECL(doidtrap); E int NDECL(dowhatdoes); E char *FDECL(dowhatdoes_core, (CHAR_P, char *)); E int NDECL(dohelp); E int NDECL(dohistory); E int FDECL(do_screen_description, (coord, BOOLEAN_P, int, char *, const char **)); E int FDECL(do_look, (int, coord *)); /* ### pcmain.c ### */ #if defined(MICRO) || defined(WIN32) #ifdef CHDIR E void FDECL(chdirx, (char *, BOOLEAN_P)); #endif /* CHDIR */ E boolean NDECL(authorize_wizard_mode); #endif /* MICRO || WIN32 */ /* ### pcsys.c ### */ #if defined(MICRO) || defined(WIN32) E void NDECL(flushout); E int NDECL(dosh); #ifdef MFLOPPY E void FDECL(eraseall, (const char *, const char *)); E void FDECL(copybones, (int)); E void NDECL(playwoRAMdisk); E int FDECL(saveDiskPrompt, (int)); E void NDECL(gameDiskPrompt); #endif E void FDECL(append_slash, (char *)); E void FDECL(getreturn, (const char *)); #ifndef AMIGA E void VDECL(msmsg, (const char *, ...)); #endif E FILE *FDECL(fopenp, (const char *, const char *)); #endif /* MICRO || WIN32 */ /* ### pctty.c ### */ #if defined(MICRO) || defined(WIN32) E void NDECL(gettty); E void FDECL(settty, (const char *)); E void NDECL(setftty); E void VDECL(error, (const char *, ...)); #if defined(TIMED_DELAY) && defined(_MSC_VER) E void FDECL(msleep, (unsigned)); #endif #endif /* MICRO || WIN32 */ /* ### pcunix.c ### */ #if defined(MICRO) E void FDECL(regularize, (char *)); #endif /* MICRO */ #if defined(PC_LOCKING) E void NDECL(getlock); #endif /* ### pickup.c ### */ E int FDECL(collect_obj_classes, (char *, struct obj *, BOOLEAN_P, boolean FDECL((*), (OBJ_P)), int *)); E boolean FDECL(rider_corpse_revival, (struct obj *, BOOLEAN_P)); E void FDECL(add_valid_menu_class, (int)); E boolean FDECL(allow_all, (struct obj *)); E boolean FDECL(allow_category, (struct obj *)); E boolean FDECL(is_worn_by_type, (struct obj *)); E int FDECL(ck_bag, (struct obj *)); #ifdef USE_TRAMPOLI E int FDECL(in_container, (struct obj *)); E int FDECL(out_container, (struct obj *)); #endif E int FDECL(pickup, (int)); E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P)); E int FDECL(query_category, (const char *, struct obj *, int, menu_item **, int)); E int FDECL(query_objlist, (const char *, struct obj *, int, menu_item **, int, boolean (*)(OBJ_P))); E struct obj *FDECL(pick_obj, (struct obj *)); E int NDECL(encumber_msg); E int NDECL(doloot); E boolean FDECL(container_gone, (int (*)(OBJ_P))); E boolean NDECL(u_handsy); E int FDECL(use_container, (struct obj **, int)); E int FDECL(loot_mon, (struct monst *, int *, boolean *)); E int NDECL(dotip); E boolean FDECL(is_autopickup_exception, (struct obj *, BOOLEAN_P)); /* ### pline.c ### */ E void VDECL(pline, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(Norep, (const char *, ...)) PRINTF_F(1, 2); E void NDECL(free_youbuf); E void VDECL(You, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(Your, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(You_feel, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(You_cant, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(You_hear, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(You_see, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(pline_The, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(There, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(verbalize, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(raw_printf, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(impossible, (const char *, ...)) PRINTF_F(1, 2); E const char *FDECL(align_str, (ALIGNTYP_P)); E void FDECL(mstatusline, (struct monst *)); E void NDECL(ustatusline); E void NDECL(self_invis_message); E void FDECL(pudding_merge_message, (struct obj *, struct obj *)); /* ### polyself.c ### */ E void NDECL(set_uasmon); E void NDECL(float_vs_flight); E void NDECL(change_sex); E void FDECL(polyself, (int)); E int FDECL(polymon, (int)); E void NDECL(rehumanize); E int NDECL(dobreathe); E int NDECL(dospit); E int NDECL(doremove); E int NDECL(dospinweb); E int NDECL(dosummon); E int NDECL(dogaze); E int NDECL(dohide); E int NDECL(dopoly); E int NDECL(domindblast); E void FDECL(skinback, (BOOLEAN_P)); E const char *FDECL(mbodypart, (struct monst *, int)); E const char *FDECL(body_part, (int)); E int NDECL(poly_gender); E void FDECL(ugolemeffects, (int, int)); /* ### potion.c ### */ E void FDECL(set_itimeout, (long *, long)); E void FDECL(incr_itimeout, (long *, int)); E void FDECL(make_confused, (long, BOOLEAN_P)); E void FDECL(make_stunned, (long, BOOLEAN_P)); E void FDECL(make_blinded, (long, BOOLEAN_P)); E void FDECL(make_sick, (long, const char *, BOOLEAN_P, int)); E void FDECL(make_slimed, (long, const char *)); E void FDECL(make_stoned, (long, const char *, int, const char *)); E void FDECL(make_vomiting, (long, BOOLEAN_P)); E boolean FDECL(make_hallucinated, (long, BOOLEAN_P, long)); E void FDECL(make_deaf, (long, BOOLEAN_P)); E int NDECL(dodrink); E int FDECL(dopotion, (struct obj *)); E int FDECL(peffects, (struct obj *)); E void FDECL(healup, (int, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(strange_feeling, (struct obj *, const char *)); E void FDECL(potionhit, (struct monst *, struct obj *, BOOLEAN_P)); E void FDECL(potionbreathe, (struct obj *)); E int NDECL(dodip); E void FDECL(mongrantswish, (struct monst **)); E void FDECL(djinni_from_bottle, (struct obj *)); E struct monst *FDECL(split_mon, (struct monst *, struct monst *)); E const char *NDECL(bottlename); /* ### pray.c ### */ E boolean FDECL(critically_low_hp, (BOOLEAN_P)); #ifdef USE_TRAMPOLI E int NDECL(prayer_done); #endif E int NDECL(dosacrifice); E boolean FDECL(can_pray, (BOOLEAN_P)); E int NDECL(dopray); E const char *NDECL(u_gname); E int NDECL(doturn); E const char *NDECL(a_gname); E const char *FDECL(a_gname_at, (XCHAR_P x, XCHAR_P y)); E const char *FDECL(align_gname, (ALIGNTYP_P)); E const char *FDECL(halu_gname, (ALIGNTYP_P)); E const char *FDECL(align_gtitle, (ALIGNTYP_P)); E void FDECL(altar_wrath, (int, int)); /* ### priest.c ### */ E int FDECL(move_special, (struct monst *, BOOLEAN_P, SCHAR_P, BOOLEAN_P, BOOLEAN_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E char FDECL(temple_occupied, (char *)); E boolean FDECL(inhistemple, (struct monst *)); E int FDECL(pri_move, (struct monst *)); E void FDECL(priestini, (d_level *, struct mkroom *, int, int, BOOLEAN_P)); E aligntyp FDECL(mon_aligntyp, (struct monst *)); E char *FDECL(priestname, (struct monst *, char *)); E boolean FDECL(p_coaligned, (struct monst *)); E struct monst *FDECL(findpriest, (CHAR_P)); E void FDECL(intemple, (int)); E void FDECL(forget_temple_entry, (struct monst *)); E void FDECL(priest_talk, (struct monst *)); E struct monst *FDECL(mk_roamer, (struct permonst *, ALIGNTYP_P, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(reset_hostility, (struct monst *)); E boolean FDECL(in_your_sanctuary, (struct monst *, XCHAR_P, XCHAR_P)); E void FDECL(ghod_hitsu, (struct monst *)); E void NDECL(angry_priest); E void NDECL(clearpriests); E void FDECL(restpriest, (struct monst *, BOOLEAN_P)); E void FDECL(newepri, (struct monst *)); E void FDECL(free_epri, (struct monst *)); /* ### quest.c ### */ E void NDECL(onquest); E void NDECL(nemdead); E void FDECL(artitouch, (struct obj *)); E boolean NDECL(ok_to_quest); E void FDECL(leader_speaks, (struct monst *)); E void NDECL(nemesis_speaks); E void FDECL(quest_chat, (struct monst *)); E void FDECL(quest_talk, (struct monst *)); E void FDECL(quest_stat_check, (struct monst *)); E void FDECL(finish_quest, (struct obj *)); /* ### questpgr.c ### */ E void NDECL(load_qtlist); E void NDECL(unload_qtlist); E short FDECL(quest_info, (int)); E const char *NDECL(ldrname); E boolean FDECL(is_quest_artifact, (struct obj *)); E void FDECL(com_pager, (int)); E void FDECL(qt_pager, (int)); E struct permonst *NDECL(qt_montype); E void NDECL(deliver_splev_message); /* ### random.c ### */ #if defined(RANDOM) && !defined(__GO32__) /* djgpp has its own random */ E void FDECL(srandom, (unsigned)); E char *FDECL(initstate, (unsigned, char *, int)); E char *FDECL(setstate, (char *)); E long NDECL(random); #endif /* RANDOM */ /* ### read.c ### */ E void FDECL(learnscroll, (struct obj *)); E char *FDECL(tshirt_text, (struct obj *, char *)); E int NDECL(doread); E boolean FDECL(is_chargeable, (struct obj *)); E void FDECL(recharge, (struct obj *, int)); E void FDECL(forget_objects, (int)); E void FDECL(forget_levels, (int)); E void NDECL(forget_traps); E void FDECL(forget_map, (int)); E int FDECL(seffects, (struct obj *)); E void FDECL(drop_boulder_on_player, (BOOLEAN_P, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(drop_boulder_on_monster, (int, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(wand_explode, (struct obj *, int)); #ifdef USE_TRAMPOLI E void FDECL(set_lit, (int, int, genericptr_t)); #endif E void FDECL(litroom, (BOOLEAN_P, struct obj *)); E void FDECL(do_genocide, (int)); E void FDECL(punish, (struct obj *)); E void NDECL(unpunish); E boolean FDECL(cant_revive, (int *, BOOLEAN_P, struct obj *)); E boolean NDECL(create_particular); /* ### rect.c ### */ E void NDECL(init_rect); E NhRect *FDECL(get_rect, (NhRect *)); E NhRect *NDECL(rnd_rect); E void FDECL(remove_rect, (NhRect *)); E void FDECL(add_rect, (NhRect *)); E void FDECL(split_rects, (NhRect *, NhRect *)); /* ## region.c ### */ E void NDECL(clear_regions); E void NDECL(run_regions); E boolean FDECL(in_out_region, (XCHAR_P, XCHAR_P)); E boolean FDECL(m_in_out_region, (struct monst *, XCHAR_P, XCHAR_P)); E void NDECL(update_player_regions); E void FDECL(update_monster_region, (struct monst *)); E NhRegion *FDECL(visible_region_at, (XCHAR_P, XCHAR_P)); E void FDECL(show_region, (NhRegion *, XCHAR_P, XCHAR_P)); E void FDECL(save_regions, (int, int)); E void FDECL(rest_regions, (int, BOOLEAN_P)); E NhRegion *FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int)); E boolean NDECL(region_danger); E void NDECL(region_safety); /* ### restore.c ### */ E void FDECL(inven_inuse, (BOOLEAN_P)); E int FDECL(dorecover, (int)); E void FDECL(restcemetery, (int, struct cemetery **)); E void FDECL(trickery, (char *)); E void FDECL(getlev, (int, int, XCHAR_P, BOOLEAN_P)); E void FDECL(get_plname_from_file, (int, char *)); #ifdef SELECTSAVED E int FDECL(restore_menu, (winid)); #endif E void NDECL(minit); E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *)); E void FDECL(mread, (int, genericptr_t, unsigned int)); E int FDECL(validate, (int, const char *)); E void NDECL(reset_restpref); E void FDECL(set_restpref, (const char *)); E void FDECL(set_savepref, (const char *)); /* ### rip.c ### */ E void FDECL(genl_outrip, (winid, int, time_t)); /* ### rnd.c ### */ E int FDECL(rn2, (int)); E int FDECL(rnl, (int)); E int FDECL(rnd, (int)); E int FDECL(d, (int, int)); E int FDECL(rne, (int)); E int FDECL(rnz, (int)); /* ### role.c ### */ E boolean FDECL(validrole, (int)); E boolean FDECL(validrace, (int, int)); E boolean FDECL(validgend, (int, int, int)); E boolean FDECL(validalign, (int, int, int)); E int NDECL(randrole); E int FDECL(randrace, (int)); E int FDECL(randgend, (int, int)); E int FDECL(randalign, (int, int)); E int FDECL(str2role, (const char *)); E int FDECL(str2race, (const char *)); E int FDECL(str2gend, (const char *)); E int FDECL(str2align, (const char *)); E boolean FDECL(ok_role, (int, int, int, int)); E int FDECL(pick_role, (int, int, int, int)); E boolean FDECL(ok_race, (int, int, int, int)); E int FDECL(pick_race, (int, int, int, int)); E boolean FDECL(ok_gend, (int, int, int, int)); E int FDECL(pick_gend, (int, int, int, int)); E boolean FDECL(ok_align, (int, int, int, int)); E int FDECL(pick_align, (int, int, int, int)); E void NDECL(rigid_role_checks); E boolean FDECL(setrolefilter, (const char *)); E boolean NDECL(gotrolefilter); E void NDECL(clearrolefilter); E char *FDECL(build_plselection_prompt, (char *, int, int, int, int, int)); E char *FDECL(root_plselection_prompt, (char *, int, int, int, int, int)); E void NDECL(plnamesuffix); E void FDECL(role_selection_prolog, (int, winid)); E void FDECL(role_menu_extra, (int, winid)); E void NDECL(role_init); E const char *FDECL(Hello, (struct monst *)); E const char *NDECL(Goodbye); /* ### rumors.c ### */ E char *FDECL(getrumor, (int, char *, BOOLEAN_P)); E char *FDECL(get_rnd_text, (const char *, char *)); E void FDECL(outrumor, (int, int)); E void FDECL(outoracle, (BOOLEAN_P, BOOLEAN_P)); E void FDECL(save_oracles, (int, int)); E void FDECL(restore_oracles, (int)); E int FDECL(doconsult, (struct monst *)); E void NDECL(rumor_check); /* ### save.c ### */ E int NDECL(dosave); E int NDECL(dosave0); E boolean FDECL(tricked_fileremoved, (int, char *)); #ifdef INSURANCE E void NDECL(savestateinlock); #endif #ifdef MFLOPPY E boolean FDECL(savelev, (int, XCHAR_P, int)); E boolean FDECL(swapin_file, (int)); E void NDECL(co_false); #else E void FDECL(savelev, (int, XCHAR_P, int)); #endif E genericptr_t FDECL(mon_to_buffer, (struct monst *, int *)); E void FDECL(bufon, (int)); E void FDECL(bufoff, (int)); E void FDECL(bflush, (int)); E void FDECL(bwrite, (int, genericptr_t, unsigned int)); E void FDECL(bclose, (int)); E void FDECL(def_bclose, (int)); #if defined(ZEROCOMP) E void FDECL(zerocomp_bclose, (int)); #endif E void FDECL(savecemetery, (int, int, struct cemetery **)); E void FDECL(savefruitchn, (int, int)); E void FDECL(store_plname_in_file, (int)); E void NDECL(free_dungeons); E void NDECL(freedynamicdata); E void FDECL(store_savefileinfo, (int)); /* ### shk.c ### */ E long FDECL(money2mon, (struct monst *, long)); E void FDECL(money2u, (struct monst *, long)); E void FDECL(shkgone, (struct monst *)); E void FDECL(set_residency, (struct monst *, BOOLEAN_P)); E void FDECL(replshk, (struct monst *, struct monst *)); E void FDECL(restshk, (struct monst *, BOOLEAN_P)); E char FDECL(inside_shop, (XCHAR_P, XCHAR_P)); E void FDECL(u_left_shop, (char *, BOOLEAN_P)); E void FDECL(remote_burglary, (XCHAR_P, XCHAR_P)); E void FDECL(u_entered_shop, (char *)); E void FDECL(pick_pick, (struct obj *)); E boolean FDECL(same_price, (struct obj *, struct obj *)); E void NDECL(shopper_financial_report); E int FDECL(inhishop, (struct monst *)); E struct monst *FDECL(shop_keeper, (CHAR_P)); E boolean FDECL(tended_shop, (struct mkroom *)); E boolean FDECL(is_unpaid, (struct obj *)); E void FDECL(delete_contents, (struct obj *)); E void FDECL(obfree, (struct obj *, struct obj *)); E void FDECL(home_shk, (struct monst *, BOOLEAN_P)); E void FDECL(make_happy_shk, (struct monst *, BOOLEAN_P)); E void FDECL(make_happy_shoppers, (BOOLEAN_P)); E void FDECL(hot_pursuit, (struct monst *)); E void FDECL(make_angry_shk, (struct monst *, XCHAR_P, XCHAR_P)); E int NDECL(dopay); E boolean FDECL(paybill, (int)); E void NDECL(finish_paybill); E struct obj *FDECL(find_oid, (unsigned)); E long FDECL(contained_cost, (struct obj *, struct monst *, long, BOOLEAN_P, BOOLEAN_P)); E long FDECL(contained_gold, (struct obj *)); E void FDECL(picked_container, (struct obj *)); E void FDECL(alter_cost, (struct obj *, long)); E long FDECL(unpaid_cost, (struct obj *, BOOLEAN_P)); E boolean FDECL(billable, (struct monst **, struct obj *, CHAR_P, BOOLEAN_P)); E void FDECL(addtobill, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(splitbill, (struct obj *, struct obj *)); E void FDECL(subfrombill, (struct obj *, struct monst *)); E long FDECL(stolen_value, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(sellobj_state, (int)); E void FDECL(sellobj, (struct obj *, XCHAR_P, XCHAR_P)); E int FDECL(doinvbill, (int)); E struct monst *FDECL(shkcatch, (struct obj *, XCHAR_P, XCHAR_P)); E void FDECL(add_damage, (XCHAR_P, XCHAR_P, long)); E int FDECL(repair_damage, (struct monst *, struct damage *, BOOLEAN_P)); E int FDECL(shk_move, (struct monst *)); E void FDECL(after_shk_move, (struct monst *)); E boolean FDECL(is_fshk, (struct monst *)); E void FDECL(shopdig, (int)); E void FDECL(pay_for_damage, (const char *, BOOLEAN_P)); E boolean FDECL(costly_spot, (XCHAR_P, XCHAR_P)); E struct obj *FDECL(shop_object, (XCHAR_P, XCHAR_P)); E void FDECL(price_quote, (struct obj *)); E void FDECL(shk_chat, (struct monst *)); E void FDECL(check_unpaid_usage, (struct obj *, BOOLEAN_P)); E void FDECL(check_unpaid, (struct obj *)); E void FDECL(costly_gold, (XCHAR_P, XCHAR_P, long)); E long FDECL(get_cost_of_shop_item, (struct obj *)); E boolean FDECL(block_door, (XCHAR_P, XCHAR_P)); E boolean FDECL(block_entry, (XCHAR_P, XCHAR_P)); E char *FDECL(shk_your, (char *, struct obj *)); E char *FDECL(Shk_Your, (char *, struct obj *)); /* ### shknam.c ### */ E void FDECL(neweshk, (struct monst *)); E void FDECL(free_eshk, (struct monst *)); E void FDECL(stock_room, (int, struct mkroom *)); E boolean FDECL(saleable, (struct monst *, struct obj *)); E int FDECL(get_shop_item, (int)); E const char *FDECL(shkname, (struct monst *)); E boolean FDECL(shkname_is_pname, (struct monst *)); E boolean FDECL(is_izchak, (struct monst *, BOOLEAN_P)); /* ### sit.c ### */ E void NDECL(take_gold); E int NDECL(dosit); E void NDECL(rndcurse); E void NDECL(attrcurse); /* ### sounds.c ### */ E void NDECL(dosounds); E const char *FDECL(growl_sound, (struct monst *)); E void FDECL(growl, (struct monst *)); E void FDECL(yelp, (struct monst *)); E void FDECL(whimper, (struct monst *)); E void FDECL(beg, (struct monst *)); E int NDECL(dotalk); #ifdef USER_SOUNDS E int FDECL(add_sound_mapping, (const char *)); E void FDECL(play_sound_for_message, (const char *)); #endif /* ### sys.c ### */ E void NDECL(sys_early_init); E void NDECL(sysopt_release); E void FDECL(sysopt_seduce_set, (int)); /* ### sys/msdos/sound.c ### */ #ifdef MSDOS E int FDECL(assign_soundcard, (char *)); #endif /* ### sp_lev.c ### */ E boolean FDECL(check_room, (xchar *, xchar *, xchar *, xchar *, BOOLEAN_P)); E boolean FDECL(create_room, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E void FDECL(create_secret_door, (struct mkroom *, XCHAR_P)); E boolean FDECL(dig_corridor, (coord *, coord *, BOOLEAN_P, SCHAR_P, SCHAR_P)); E void FDECL(fill_room, (struct mkroom *, BOOLEAN_P)); E boolean FDECL(load_special, (const char *)); /* ### spell.c ### */ #ifdef USE_TRAMPOLI E int NDECL(learn); #endif E int FDECL(study_book, (struct obj *)); E void FDECL(book_disappears, (struct obj *)); E void FDECL(book_substitution, (struct obj *, struct obj *)); E void NDECL(age_spells); E int NDECL(docast); E int FDECL(spell_skilltype, (int)); E int FDECL(spelleffects, (int, BOOLEAN_P)); E void NDECL(losespells); E int NDECL(dovspell); E void FDECL(initialspell, (struct obj *)); /* ### steal.c ### */ #ifdef USE_TRAMPOLI E int NDECL(stealarm); #endif E long FDECL(somegold, (long)); E void FDECL(stealgold, (struct monst *)); E void FDECL(remove_worn_item, (struct obj *, BOOLEAN_P)); E int FDECL(steal, (struct monst *, char *)); E int FDECL(mpickobj, (struct monst *, struct obj *)); E void FDECL(stealamulet, (struct monst *)); E void FDECL(maybe_absorb_item, (struct monst *, struct obj *, int, int)); E void FDECL(mdrop_obj, (struct monst *, struct obj *, BOOLEAN_P)); E void FDECL(mdrop_special_objs, (struct monst *)); E void FDECL(relobj, (struct monst *, int, BOOLEAN_P)); E struct obj *FDECL(findgold, (struct obj *)); /* ### steed.c ### */ E void NDECL(rider_cant_reach); E boolean FDECL(can_saddle, (struct monst *)); E int FDECL(use_saddle, (struct obj *)); E boolean FDECL(can_ride, (struct monst *)); E int NDECL(doride); E boolean FDECL(mount_steed, (struct monst *, BOOLEAN_P)); E void NDECL(exercise_steed); E void NDECL(kick_steed); E void FDECL(dismount_steed, (int)); E void FDECL(place_monster, (struct monst *, int, int)); E boolean FDECL(stucksteed, (BOOLEAN_P)); /* ### teleport.c ### */ E boolean FDECL(goodpos, (int, int, struct monst *, unsigned)); E boolean FDECL(enexto, (coord *, XCHAR_P, XCHAR_P, struct permonst *)); E boolean FDECL(enexto_core, (coord *, XCHAR_P, XCHAR_P, struct permonst *, unsigned)); E void FDECL(teleds, (int, int, BOOLEAN_P)); E boolean FDECL(safe_teleds, (BOOLEAN_P)); E boolean FDECL(teleport_pet, (struct monst *, BOOLEAN_P)); E void NDECL(tele); E boolean FDECL(scrolltele, (struct obj *)); E int NDECL(dotele); E void NDECL(level_tele); E void FDECL(domagicportal, (struct trap *)); E void FDECL(tele_trap, (struct trap *)); E void FDECL(level_tele_trap, (struct trap *)); E void FDECL(rloc_to, (struct monst *, int, int)); E boolean FDECL(rloc, (struct monst *, BOOLEAN_P)); E boolean FDECL(tele_restrict, (struct monst *)); E void FDECL(mtele_trap, (struct monst *, struct trap *, int)); E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *, BOOLEAN_P, int)); E boolean FDECL(rloco, (struct obj *)); E int NDECL(random_teleport_level); E boolean FDECL(u_teleport_mon, (struct monst *, BOOLEAN_P)); /* ### tile.c ### */ #ifdef USE_TILES E void FDECL(substitute_tiles, (d_level *)); #endif /* ### timeout.c ### */ E void NDECL(burn_away_slime); E void NDECL(nh_timeout); E void FDECL(fall_asleep, (int, BOOLEAN_P)); E void FDECL(attach_egg_hatch_timeout, (struct obj *, long)); E void FDECL(attach_fig_transform_timeout, (struct obj *)); E void FDECL(kill_egg, (struct obj *)); E void FDECL(hatch_egg, (ANY_P *, long)); E void FDECL(learn_egg_type, (int)); E void FDECL(burn_object, (ANY_P *, long)); E void FDECL(begin_burn, (struct obj *, BOOLEAN_P)); E void FDECL(end_burn, (struct obj *, BOOLEAN_P)); E void NDECL(do_storms); E boolean FDECL(start_timer, (long, SHORT_P, SHORT_P, ANY_P *)); E long FDECL(stop_timer, (SHORT_P, ANY_P *)); E long FDECL(peek_timer, (SHORT_P, ANY_P *)); E void NDECL(run_timers); E void FDECL(obj_move_timers, (struct obj *, struct obj *)); E void FDECL(obj_split_timers, (struct obj *, struct obj *)); E void FDECL(obj_stop_timers, (struct obj *)); E boolean FDECL(obj_has_timer, (struct obj *, SHORT_P)); E void FDECL(spot_stop_timers, (XCHAR_P, XCHAR_P, SHORT_P)); E long FDECL(spot_time_expires, (XCHAR_P, XCHAR_P, SHORT_P)); E long FDECL(spot_time_left, (XCHAR_P, XCHAR_P, SHORT_P)); E boolean FDECL(obj_is_local, (struct obj *)); E void FDECL(save_timers, (int, int, int)); E void FDECL(restore_timers, (int, int, BOOLEAN_P, long)); E void FDECL(relink_timers, (BOOLEAN_P)); E int NDECL(wiz_timeout_queue); E void NDECL(timer_sanity_check); /* ### topten.c ### */ E void FDECL(formatkiller, (char *, unsigned, int)); E void FDECL(topten, (int, time_t)); E void FDECL(prscore, (int, char **)); E struct obj *FDECL(tt_oname, (struct obj *)); /* ### track.c ### */ E void NDECL(initrack); E void NDECL(settrack); E coord *FDECL(gettrack, (int, int)); /* ### trap.c ### */ E boolean FDECL(burnarmor, (struct monst *)); E int FDECL(erode_obj, (struct obj *, const char *, int, int)); E boolean FDECL(grease_protect, (struct obj *, const char *, struct monst *)); E struct trap *FDECL(maketrap, (int, int, int)); E void FDECL(fall_through, (BOOLEAN_P)); E struct monst *FDECL(animate_statue, (struct obj *, XCHAR_P, XCHAR_P, int, int *)); E struct monst *FDECL(activate_statue_trap, (struct trap *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(dotrap, (struct trap *, unsigned)); E void FDECL(seetrap, (struct trap *)); E void FDECL(feeltrap, (struct trap *)); E int FDECL(mintrap, (struct monst *)); E void FDECL(instapetrify, (const char *)); E void FDECL(minstapetrify, (struct monst *, BOOLEAN_P)); E void FDECL(selftouch, (const char *)); E void FDECL(mselftouch, (struct monst *, const char *, BOOLEAN_P)); E void NDECL(float_up); E void FDECL(fill_pit, (int, int)); E int FDECL(float_down, (long, long)); E void NDECL(climb_pit); E boolean FDECL(fire_damage, (struct obj *, BOOLEAN_P, XCHAR_P, XCHAR_P)); E int FDECL(fire_damage_chain, (struct obj *, BOOLEAN_P, BOOLEAN_P, XCHAR_P, XCHAR_P)); E void acid_damage(struct obj *); E int FDECL(water_damage, (struct obj *, const char *, BOOLEAN_P)); E void FDECL(water_damage_chain, (struct obj *, BOOLEAN_P)); E boolean NDECL(drown); E void FDECL(drain_en, (int)); E int NDECL(dountrap); E void FDECL(cnv_trap_obj, (int, int, struct trap *, BOOLEAN_P)); E int FDECL(untrap, (BOOLEAN_P)); E boolean FDECL(openholdingtrap, (struct monst *, boolean *)); E boolean FDECL(closeholdingtrap, (struct monst *, boolean *)); E boolean FDECL(openfallingtrap, (struct monst *, BOOLEAN_P, boolean *)); E boolean FDECL(chest_trap, (struct obj *, int, BOOLEAN_P)); E void FDECL(deltrap, (struct trap *)); E boolean FDECL(delfloortrap, (struct trap *)); E struct trap *FDECL(t_at, (int, int)); E void FDECL(b_trapped, (const char *, int)); E boolean NDECL(unconscious); E void FDECL(blow_up_landmine, (struct trap *)); E int FDECL(launch_obj, (SHORT_P, int, int, int, int, int)); E boolean NDECL(launch_in_progress); E void NDECL(force_launch_placement); E boolean FDECL(uteetering_at_seen_pit, (struct trap *)); E boolean NDECL(lava_effects); E void NDECL(sink_into_lava); E void NDECL(sokoban_guilt); /* ### u_init.c ### */ E void NDECL(u_init); /* ### uhitm.c ### */ E void FDECL(erode_armor, (struct monst *, int)); E boolean FDECL(attack_checks, (struct monst *, struct obj *)); E void FDECL(check_caitiff, (struct monst *)); E int FDECL(find_roll_to_hit, (struct monst *, UCHAR_P, struct obj *, int *, int *)); E boolean FDECL(attack, (struct monst *)); E boolean FDECL(hmon, (struct monst *, struct obj *, int)); E int FDECL(damageum, (struct monst *, struct attack *)); E void FDECL(missum, (struct monst *, struct attack *, BOOLEAN_P)); E int FDECL(passive, (struct monst *, BOOLEAN_P, int, UCHAR_P, BOOLEAN_P)); E void FDECL(passive_obj, (struct monst *, struct obj *, struct attack *)); E void FDECL(stumble_onto_mimic, (struct monst *)); E int FDECL(flash_hits_mon, (struct monst *, struct obj *)); E void FDECL(light_hits_gremlin, (struct monst *, int)); /* ### unixmain.c ### */ #ifdef UNIX #ifdef PORT_HELP E void NDECL(port_help); #endif E void FDECL(sethanguphandler, (void (*)(int))); E boolean NDECL(authorize_wizard_mode); E boolean FDECL(check_user_string, (char *)); #endif /* UNIX */ /* ### unixtty.c ### */ #if defined(UNIX) || defined(__BEOS__) E void NDECL(gettty); E void FDECL(settty, (const char *)); E void NDECL(setftty); E void NDECL(intron); E void NDECL(introff); E void VDECL(error, (const char *, ...)) PRINTF_F(1, 2); #endif /* UNIX || __BEOS__ */ /* ### unixunix.c ### */ #ifdef UNIX E void NDECL(getlock); E void FDECL(regularize, (char *)); #if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV) E void FDECL(msleep, (unsigned)); #endif #ifdef SHELL E int NDECL(dosh); #endif /* SHELL */ #if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER) E int FDECL(child, (int)); #endif #ifdef PANICTRACE E boolean FDECL(file_exists, (const char *)); #endif #endif /* UNIX */ /* ### unixres.c ### */ #ifdef UNIX #ifdef GNOME_GRAPHICS E int FDECL(hide_privileges, (BOOLEAN_P)); #endif #endif /* UNIX */ /* ### vault.c ### */ E void FDECL(newegd, (struct monst *)); E void FDECL(free_egd, (struct monst *)); E boolean FDECL(grddead, (struct monst *)); E char FDECL(vault_occupied, (char *)); E void NDECL(invault); E int FDECL(gd_move, (struct monst *)); E void NDECL(paygd); E long NDECL(hidden_gold); E boolean NDECL(gd_sound); E void FDECL(vault_gd_watching, (unsigned int)); /* ### version.c ### */ E char *FDECL(version_string, (char *)); E char *FDECL(getversionstring, (char *)); E int NDECL(doversion); E int NDECL(doextversion); #ifdef MICRO E boolean FDECL(comp_times, (long)); #endif E boolean FDECL(check_version, (struct version_info *, const char *, BOOLEAN_P)); E boolean FDECL(uptodate, (int, const char *)); E void FDECL(store_version, (int)); E unsigned long FDECL(get_feature_notice_ver, (char *)); E unsigned long NDECL(get_current_feature_ver); E const char *FDECL(copyright_banner_line, (int)); #ifdef RUNTIME_PORT_ID E void FDECL(append_port_id, (char *)); #endif /* ### video.c ### */ #ifdef MSDOS E int FDECL(assign_video, (char *)); #ifdef NO_TERMS E void NDECL(gr_init); E void NDECL(gr_finish); #endif E void FDECL(tileview, (BOOLEAN_P)); #endif #ifdef VIDEOSHADES E int FDECL(assign_videoshades, (char *)); E int FDECL(assign_videocolors, (char *)); #endif /* ### vis_tab.c ### */ #ifdef VISION_TABLES E void NDECL(vis_tab_init); #endif /* ### vision.c ### */ E void NDECL(vision_init); E int FDECL(does_block, (int, int, struct rm *)); E void NDECL(vision_reset); E void FDECL(vision_recalc, (int)); E void FDECL(block_point, (int, int)); E void FDECL(unblock_point, (int, int)); E boolean FDECL(clear_path, (int, int, int, int)); E void FDECL(do_clear_area, (int, int, int, void (*)(int, int, genericptr), genericptr_t)); E unsigned FDECL(howmonseen, (struct monst *)); #ifdef VMS /* ### vmsfiles.c ### */ E int FDECL(vms_link, (const char *, const char *)); E int FDECL(vms_unlink, (const char *)); E int FDECL(vms_creat, (const char *, unsigned int)); E int FDECL(vms_open, (const char *, int, unsigned int)); E boolean FDECL(same_dir, (const char *, const char *)); E int FDECL(c__translate, (int)); E char *FDECL(vms_basename, (const char *)); /* ### vmsmail.c ### */ E unsigned long NDECL(init_broadcast_trapping); E unsigned long NDECL(enable_broadcast_trapping); E unsigned long NDECL(disable_broadcast_trapping); #if 0 E struct mail_info *NDECL(parse_next_broadcast); #endif /*0*/ /* ### vmsmain.c ### */ E int FDECL(main, (int, char **)); #ifdef CHDIR E void FDECL(chdirx, (const char *, BOOLEAN_P)); #endif /* CHDIR */ E void FDECL(sethanguphandler, (void (*)(int))); E boolean NDECL(authorize_wizard_mode); /* ### vmsmisc.c ### */ E void NDECL(vms_abort) NORETURN; E void FDECL(vms_exit, (int)) NORETURN; #ifdef PANICTRACE E void FDECL(vms_traceback, (int)); #endif /* ### vmstty.c ### */ E int NDECL(vms_getchar); E void NDECL(gettty); E void FDECL(settty, (const char *)); E void FDECL(shuttty, (const char *)); E void NDECL(setftty); E void NDECL(intron); E void NDECL(introff); E void VDECL(error, (const char *, ...)) PRINTF_F(1, 2); #ifdef TIMED_DELAY E void FDECL(msleep, (unsigned)); #endif /* ### vmsunix.c ### */ E void NDECL(getlock); E void FDECL(regularize, (char *)); E int NDECL(vms_getuid); E boolean FDECL(file_is_stmlf, (int)); E int FDECL(vms_define, (const char *, const char *, int)); E int FDECL(vms_putenv, (const char *)); E char *NDECL(verify_termcap); #if defined(CHDIR) || defined(SHELL) || defined(SECURE) E void NDECL(privoff); E void NDECL(privon); #endif #ifdef SHELL E int NDECL(dosh); #endif #if defined(SHELL) || defined(MAIL) E int FDECL(vms_doshell, (const char *, BOOLEAN_P)); #endif #ifdef SUSPEND E int NDECL(dosuspend); #endif #ifdef SELECTSAVED E int FDECL(vms_get_saved_games, (const char *, char ***)); #endif #endif /* VMS */ /* ### weapon.c ### */ E const char *FDECL(weapon_descr, (struct obj *)); E int FDECL(hitval, (struct obj *, struct monst *)); E int FDECL(dmgval, (struct obj *, struct monst *)); E struct obj *FDECL(select_rwep, (struct monst *)); E struct obj *FDECL(select_hwep, (struct monst *)); E void FDECL(possibly_unwield, (struct monst *, BOOLEAN_P)); E void FDECL(mwepgone, (struct monst *)); E int FDECL(mon_wield_item, (struct monst *)); E int NDECL(abon); E int NDECL(dbon); E void FDECL(wet_a_towel, (struct obj *, int, BOOLEAN_P)); E void FDECL(dry_a_towel, (struct obj *, int, BOOLEAN_P)); E int NDECL(enhance_weapon_skill); E void FDECL(unrestrict_weapon_skill, (int)); E void FDECL(use_skill, (int, int)); E void FDECL(add_weapon_skill, (int)); E void FDECL(lose_weapon_skill, (int)); E int FDECL(weapon_type, (struct obj *)); E int NDECL(uwep_skill_type); E int FDECL(weapon_hit_bonus, (struct obj *)); E int FDECL(weapon_dam_bonus, (struct obj *)); E void FDECL(skill_init, (const struct def_skill *)); /* ### were.c ### */ E void FDECL(were_change, (struct monst *)); E int FDECL(counter_were, (int)); E int FDECL(were_beastie, (int)); E void FDECL(new_were, (struct monst *)); E int FDECL(were_summon, (struct permonst *, BOOLEAN_P, int *, char *)); E void NDECL(you_were); E void FDECL(you_unwere, (BOOLEAN_P)); /* ### wield.c ### */ E void FDECL(setuwep, (struct obj *)); E void FDECL(setuqwep, (struct obj *)); E void FDECL(setuswapwep, (struct obj *)); E int NDECL(dowield); E int NDECL(doswapweapon); E int NDECL(dowieldquiver); E boolean FDECL(wield_tool, (struct obj *, const char *)); E int NDECL(can_twoweapon); E void NDECL(drop_uswapwep); E int NDECL(dotwoweapon); E void NDECL(uwepgone); E void NDECL(uswapwepgone); E void NDECL(uqwepgone); E void NDECL(untwoweapon); E int FDECL(chwepon, (struct obj *, int)); E int FDECL(welded, (struct obj *)); E void FDECL(weldmsg, (struct obj *)); E void FDECL(setmnotwielded, (struct monst *, struct obj *)); E boolean FDECL(mwelded, (struct obj *)); /* ### windows.c ### */ E void FDECL(choose_windows, (const char *)); #ifdef WINCHAIN void FDECL(addto_windowchain, (const char *s)); void NDECL(commit_windowchain); #endif E boolean NDECL(genl_can_suspend_no); E boolean NDECL(genl_can_suspend_yes); E char FDECL(genl_message_menu, (CHAR_P, int, const char *)); E void FDECL(genl_preference_update, (const char *)); E char *FDECL(genl_getmsghistory, (BOOLEAN_P)); E void FDECL(genl_putmsghistory, (const char *, BOOLEAN_P)); #ifdef HANGUPHANDLING E void NDECL(nhwindows_hangup); #endif #ifdef STATUS_VIA_WINDOWPORT E void NDECL(genl_status_init); E void NDECL(genl_status_finish); E void FDECL(genl_status_enablefield, (int, const char *, const char *, BOOLEAN_P)); E void FDECL(genl_status_update, (int, genericptr_t, int, int)); #ifdef STATUS_HILITES E void FDECL(genl_status_threshold, (int, int, anything, int, int, int)); #endif #endif /* ### wizard.c ### */ E void NDECL(amulet); E int FDECL(mon_has_amulet, (struct monst *)); E int FDECL(mon_has_special, (struct monst *)); E int FDECL(tactics, (struct monst *)); E void NDECL(aggravate); E void NDECL(clonewiz); E int NDECL(pick_nasty); E int FDECL(nasty, (struct monst *)); E void NDECL(resurrect); E void NDECL(intervene); E void NDECL(wizdead); E void FDECL(cuss, (struct monst *)); /* ### worm.c ### */ E int NDECL(get_wormno); E void FDECL(initworm, (struct monst *, int)); E void FDECL(worm_move, (struct monst *)); E void FDECL(worm_nomove, (struct monst *)); E void FDECL(wormgone, (struct monst *)); E void FDECL(wormhitu, (struct monst *)); E void FDECL(cutworm, (struct monst *, XCHAR_P, XCHAR_P, struct obj *)); E void FDECL(see_wsegs, (struct monst *)); E void FDECL(detect_wsegs, (struct monst *, BOOLEAN_P)); E void FDECL(save_worm, (int, int)); E void FDECL(rest_worm, (int)); E void FDECL(place_wsegs, (struct monst *)); E void FDECL(remove_worm, (struct monst *)); E void FDECL(place_worm_tail_randomly, (struct monst *, XCHAR_P, XCHAR_P)); E int FDECL(count_wsegs, (struct monst *)); E boolean FDECL(worm_known, (struct monst *)); E boolean FDECL(worm_cross, (int, int, int, int)); /* ### worn.c ### */ E void FDECL(setworn, (struct obj *, long)); E void FDECL(setnotworn, (struct obj *)); E long FDECL(wearslot, (struct obj *)); E void FDECL(mon_set_minvis, (struct monst *)); E void FDECL(mon_adjust_speed, (struct monst *, int, struct obj *)); E void FDECL(update_mon_intrinsics, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P)); E int FDECL(find_mac, (struct monst *)); E void FDECL(m_dowear, (struct monst *, BOOLEAN_P)); E struct obj *FDECL(which_armor, (struct monst *, long)); E void FDECL(mon_break_armor, (struct monst *, BOOLEAN_P)); E void FDECL(bypass_obj, (struct obj *)); E void NDECL(clear_bypasses); E void FDECL(bypass_objlist, (struct obj *, BOOLEAN_P)); E struct obj *FDECL(nxt_unbypassed_obj, (struct obj *)); E int FDECL(racial_exception, (struct monst *, struct obj *)); /* ### write.c ### */ E int FDECL(dowrite, (struct obj *)); /* ### zap.c ### */ E void FDECL(learnwand, (struct obj *)); E int FDECL(bhitm, (struct monst *, struct obj *)); E void FDECL(probe_monster, (struct monst *)); E boolean FDECL(get_obj_location, (struct obj *, xchar *, xchar *, int)); E boolean FDECL(get_mon_location, (struct monst *, xchar *, xchar *, int)); E struct monst *FDECL(get_container_location, (struct obj * obj, int *, int *)); E struct monst *FDECL(montraits, (struct obj *, coord *)); E struct monst *FDECL(revive, (struct obj *, BOOLEAN_P)); E int FDECL(unturn_dead, (struct monst *)); E void FDECL(cancel_item, (struct obj *)); E boolean FDECL(drain_item, (struct obj *)); E struct obj *FDECL(poly_obj, (struct obj *, int)); E boolean FDECL(obj_resists, (struct obj *, int, int)); E boolean FDECL(obj_shudders, (struct obj *)); E void FDECL(do_osshock, (struct obj *)); E int FDECL(bhito, (struct obj *, struct obj *)); E int FDECL(bhitpile, (struct obj *, int (*)(OBJ_P, OBJ_P), int, int, SCHAR_P)); E int FDECL(zappable, (struct obj *)); E void FDECL(zapnodir, (struct obj *)); E int NDECL(dozap); E int FDECL(zapyourself, (struct obj *, BOOLEAN_P)); E void FDECL(ubreatheu, (struct attack *)); E int FDECL(lightdamage, (struct obj *, BOOLEAN_P, int)); E boolean FDECL(flashburn, (long)); E boolean FDECL(cancel_monst, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void NDECL(zapsetup); E void NDECL(zapwrapup); E void FDECL(weffects, (struct obj *)); E int FDECL(spell_damage_bonus, (int)); E const char *FDECL(exclam, (int force)); E void FDECL(hit, (const char *, struct monst *, const char *)); E void FDECL(miss, (const char *, struct monst *)); E struct monst *FDECL(bhit, (int, int, int, int, int (*)(MONST_P, OBJ_P), int (*)(OBJ_P, OBJ_P), struct obj **)); E struct monst *FDECL(boomhit, (struct obj *, int, int)); E int FDECL(zhitm, (struct monst *, int, int, struct obj **)); E int FDECL(burn_floor_objects, (int, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(buzz, (int, int, XCHAR_P, XCHAR_P, int, int)); E void FDECL(melt_ice, (XCHAR_P, XCHAR_P, const char *)); E void FDECL(start_melt_ice_timeout, (XCHAR_P, XCHAR_P, long)); E void FDECL(melt_ice_away, (ANY_P *, long)); E int FDECL(zap_over_floor, (XCHAR_P, XCHAR_P, int, boolean *, SHORT_P)); E void FDECL(fracture_rock, (struct obj *)); E boolean FDECL(break_statue, (struct obj *)); E void FDECL(destroy_item, (int, int)); E int FDECL(destroy_mitem, (struct monst *, int, int)); E int FDECL(resist, (struct monst *, CHAR_P, int, int)); E void NDECL(makewish); #endif /* !MAKEDEFS_C && !LEV_LEX_C */ #undef E #endif /* EXTERN_H */ nethack-3.6.0/include/flag.h0000664000076400007660000004545012610522241014645 0ustar paxedpaxed/* NetHack 3.6 flag.h $NHDT-Date: 1435002669 2015/06/22 19:51:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.89 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* If you change the flag structure make sure you increment EDITLEVEL in */ /* patchlevel.h if needed. Changing the instance_flags structure does */ /* not require incrementing EDITLEVEL. */ #ifndef FLAG_H #define FLAG_H /* * Persistent flags that are saved and restored with the game. * */ struct flag { boolean acoustics; /* allow dungeon sound messages */ boolean autodig; /* MRKR: Automatically dig */ boolean autoquiver; /* Automatically fill quiver */ boolean autoopen; /* open doors by walking into them */ boolean beginner; boolean biff; /* enable checking for mail */ boolean bones; /* allow saving/loading bones */ boolean confirm; /* confirm before hitting tame monsters */ boolean dark_room; /* show shadows in lit rooms */ boolean debug; /* in debugging mode */ #define wizard flags.debug boolean end_own; /* list all own scores */ boolean explore; /* in exploration mode */ #define discover flags.explore boolean female; boolean friday13; /* it's Friday the 13th */ boolean help; /* look in data file for info about stuff */ boolean ignintr; /* ignore interrupts */ boolean ins_chkpt; /* checkpoint as appropriate; INSURANCE */ boolean invlet_constant; /* let objects keep their inventory symbol */ boolean legacy; /* print game entry "story" */ boolean lit_corridor; /* show a dark corr as lit if it is in sight */ boolean nap; /* `timed_delay' option for display effects */ boolean null; /* OK to send nulls to the terminal */ boolean perm_invent; /* keep full inventories up until dismissed */ boolean pickup; /* whether you pickup or move and look */ boolean pickup_thrown; /* auto-pickup items you threw */ boolean pushweapon; /* When wielding, push old weapon into second slot */ boolean rest_on_space; /* space means rest */ boolean safe_dog; /* give complete protection to the dog */ boolean showexp; /* show experience points */ boolean showscore; /* show score */ boolean silent; /* whether the bell rings or not */ boolean sortloot; /* sort items alphabetically when looting */ boolean sortpack; /* sorted inventory */ boolean sparkle; /* show "resisting" special FX (Scott Bigham) */ boolean standout; /* use standout for --More-- */ boolean time; /* display elapsed 'time' */ boolean tombstone; /* print tombstone */ boolean verbose; /* max battle info */ int end_top, end_around; /* describe desired score list */ unsigned moonphase; unsigned long suppress_alert; #define NEW_MOON 0 #define FULL_MOON 4 int paranoia_bits; /* alternate confirmation prompting */ #define PARANOID_CONFIRM 0x01 #define PARANOID_QUIT 0x02 #define PARANOID_DIE 0x04 #define PARANOID_BONES 0x08 #define PARANOID_HIT 0x10 #define PARANOID_PRAY 0x20 #define PARANOID_REMOVE 0x40 #define PARANOID_BREAKWAND 0x80 int pickup_burden; /* maximum burden before prompt */ int pile_limit; /* controls feedback when walking over objects */ char inv_order[MAXOCLASSES]; char pickup_types[MAXOCLASSES]; #define NUM_DISCLOSURE_OPTIONS 6 /* i,a,v,g,c,o (decl.c) */ #define DISCLOSE_PROMPT_DEFAULT_YES 'y' #define DISCLOSE_PROMPT_DEFAULT_NO 'n' #define DISCLOSE_YES_WITHOUT_PROMPT '+' #define DISCLOSE_NO_WITHOUT_PROMPT '-' char end_disclose[NUM_DISCLOSURE_OPTIONS + 1]; /* disclose various info upon exit */ char menu_style; /* User interface style setting */ boolean made_fruit; /* don't easily let the user overflow the number of fruits */ /* KMH, role patch -- Variables used during startup. * * If the user wishes to select a role, race, gender, and/or alignment * during startup, the choices should be recorded here. This * might be specified through command-line options, environmental * variables, a popup dialog box, menus, etc. * * These values are each an index into an array. They are not * characters or letters, because that limits us to 26 roles. * They are not booleans, because someday someone may need a neuter * gender. Negative values are used to indicate that the user * hasn't yet specified that particular value. If you determine * that the user wants a random choice, then you should set an * appropriate random value; if you just left the negative value, * the user would be asked again! * * These variables are stored here because the u structure is * cleared during character initialization, and because the * flags structure is restored for saved games. Thus, we can * use the same parameters to build the role entry for both * new and restored games. * * These variables should not be referred to after the character * is initialized or restored (specifically, after role_init() * is called). */ int initrole; /* starting role (index into roles[]) */ int initrace; /* starting race (index into races[]) */ int initgend; /* starting gender (index into genders[]) */ int initalign; /* starting alignment (index into aligns[]) */ int randomall; /* randomly assign everything not specified */ int pantheon; /* deity selection for priest character */ /* Items which were in iflags in 3.4.x to preserve savefile compatibility */ boolean lootabc; /* use "a/b/c" rather than "o/i/b" when looting */ boolean showrace; /* show hero glyph by race rather than by role */ boolean travelcmd; /* allow travel command */ int runmode; /* update screen display during run moves */ }; /* * System-specific flags that are saved with the game if SYSFLAGS is defined. */ #if defined(AMIFLUSH) || defined(AMII_GRAPHICS) || defined(OPT_DISPMAP) #define SYSFLAGS #else #if defined(MFLOPPY) || defined(MAC) #define SYSFLAGS #endif #endif #ifdef SYSFLAGS struct sysflag { char sysflagsid[10]; #ifdef AMIFLUSH boolean altmeta; /* use ALT keys as META */ boolean amiflush; /* kill typeahead */ #endif #ifdef AMII_GRAPHICS int numcols; unsigned short amii_dripens[20]; /* DrawInfo Pens currently there are 13 in v39 */ AMII_COLOR_TYPE amii_curmap[AMII_MAXCOLORS]; /* colormap */ #endif #ifdef OPT_DISPMAP boolean fast_map; /* use optimized, less flexible map display */ #endif #ifdef MFLOPPY boolean asksavedisk; #endif #ifdef MAC boolean page_wait; /* put up a --More-- after a page of messages */ #endif }; #endif /* * Flags that are set each time the game is started. * These are not saved with the game. * */ struct instance_flags { /* stuff that really isn't option or platform related. They are * set and cleared during the game to control the internal * behaviour of various NetHack functions and probably warrant * a structure of their own elsewhere some day. */ int in_lava_effects; /* hack for Boots_off() */ int last_msg; /* indicator of last message player saw */ int purge_monsters; /* # of dead monsters still on fmon list */ int override_ID; /* true to force full identification of objects */ int suppress_price; /* controls doname() for unpaid objects */ coord travelcc; /* coordinates for travel_cache */ boolean window_inited; /* true if init_nhwindows() completed */ boolean vision_inited; /* true if vision is ready */ boolean sanity_check; /* run sanity checks */ boolean mon_polycontrol; /* debug: control monster polymorphs */ /* stuff that is related to options and/or user or platform preferences */ unsigned msg_history; /* hint: # of top lines to save */ int menu_headings; /* ATR for menu headings */ int *opt_booldup; /* for duplication of boolean opts in config file */ int *opt_compdup; /* for duplication of compound opts in config file */ #ifdef ALTMETA boolean altmeta; /* Alt-c sends ESC c rather than M-c */ #endif boolean cbreak; /* in cbreak mode, rogue format */ boolean deferred_X; /* deferred entry into explore mode */ boolean num_pad; /* use numbers for movement commands */ boolean news; /* print news */ boolean implicit_uncursed; /* maybe omit "uncursed" status in inventory */ boolean mention_walls; /* give feedback when bumping walls */ boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean menu_head_objsym; /* Show obj symbol in menu headings */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ boolean renameallowed; /* can change hero name during role selection */ boolean renameinprogress; /* we are changing hero name */ boolean toptenwin; /* ending list in window instead of stdout */ boolean zerocomp; /* write zero-compressed save files */ boolean rlecomp; /* run-length comp of levels when writing savefile */ uchar num_pad_mode; boolean echo; /* 1 to echo characters */ boolean use_menu_color; /* use color in menus; only if wc_color */ boolean use_status_hilites; /* use color in status line */ boolean use_background_glyph; /* use background glyph when appropriate */ boolean hilite_pile; /* mark piles of objects with a hilite */ #if 0 boolean DECgraphics; /* use DEC VT-xxx extended character set */ boolean IBMgraphics; /* use IBM extended character set */ #ifdef MAC_GRAPHICS_ENV boolean MACgraphics; /* use Macintosh extended character set, as as defined in the special font HackFont */ #endif #endif uchar bouldersym; /* symbol for boulder display */ #ifdef TTY_GRAPHICS char prevmsg_window; /* type of old message window to use */ boolean extmenu; /* extended commands use menu interface */ #endif #ifdef MFLOPPY boolean checkspace; /* check disk space before writing files */ /* (in iflags to allow restore after moving * to >2GB partition) */ #endif #ifdef MICRO boolean BIOS; /* use IBM or ST BIOS calls when appropriate */ #endif #if defined(MICRO) || defined(WIN32) boolean rawio; /* whether can use rawio (IOCTL call) */ #endif #ifdef MAC_GRAPHICS_ENV boolean MACgraphics; /* use Macintosh extended character set, as as defined in the special font HackFont */ unsigned use_stone; /* use the stone ppats */ #endif #if defined(MSDOS) || defined(WIN32) boolean hassound; /* has a sound card */ boolean usesound; /* use the sound card */ boolean usepcspeaker; /* use the pc speaker */ boolean tile_view; boolean over_view; boolean traditional_view; #endif #ifdef MSDOS boolean hasvga; /* has a vga adapter */ boolean usevga; /* use the vga adapter */ boolean grmode; /* currently in graphics mode */ #endif #ifdef LAN_FEATURES boolean lan_mail; /* mail is initialized */ boolean lan_mail_fetched; /* mail is awaiting display */ #endif /* * Window capability support. */ boolean wc_color; /* use color graphics */ boolean wc_hilite_pet; /* hilight pets */ boolean wc_ascii_map; /* show map using traditional ascii */ boolean wc_tiled_map; /* show map using tiles */ boolean wc_preload_tiles; /* preload tiles into memory */ int wc_tile_width; /* tile width */ int wc_tile_height; /* tile height */ char *wc_tile_file; /* name of tile file;overrides default */ boolean wc_inverse; /* use inverse video for some things */ int wc_align_status; /* status win at top|bot|right|left */ int wc_align_message; /* message win at top|bot|right|left */ int wc_vary_msgcount; /* show more old messages at a time */ char *wc_foregrnd_menu; /* points to foregrnd color name for menu win */ char *wc_backgrnd_menu; /* points to backgrnd color name for menu win */ char *wc_foregrnd_message; /* points to foregrnd color name for msg win */ char *wc_backgrnd_message; /* points to backgrnd color name for msg win */ char * wc_foregrnd_status; /* points to foregrnd color name for status win */ char * wc_backgrnd_status; /* points to backgrnd color name for status win */ char *wc_foregrnd_text; /* points to foregrnd color name for text win */ char *wc_backgrnd_text; /* points to backgrnd color name for text win */ char *wc_font_map; /* points to font name for the map win */ char *wc_font_message; /* points to font name for message win */ char *wc_font_status; /* points to font name for status win */ char *wc_font_menu; /* points to font name for menu win */ char *wc_font_text; /* points to font name for text win */ int wc_fontsiz_map; /* font size for the map win */ int wc_fontsiz_message; /* font size for the message window */ int wc_fontsiz_status; /* font size for the status window */ int wc_fontsiz_menu; /* font size for the menu window */ int wc_fontsiz_text; /* font size for text windows */ int wc_scroll_amount; /* scroll this amount at scroll_margin */ int wc_scroll_margin; /* scroll map when this far from the edge */ int wc_map_mode; /* specify map viewing options, mostly for backward compatibility */ int wc_player_selection; /* method of choosing character */ boolean wc_splash_screen; /* display an opening splash screen or not */ boolean wc_popup_dialog; /* put queries in pop up dialogs instead of in the message window */ boolean wc_eight_bit_input; /* allow eight bit input */ boolean wc_mouse_support; /* allow mouse support */ boolean wc2_fullscreen; /* run fullscreen */ boolean wc2_softkeyboard; /* use software keyboard */ boolean wc2_wraptext; /* wrap text */ boolean wc2_selectsaved; /* display a menu of user's saved games */ boolean wc2_darkgray; /* try to use dark-gray color for black glyphs */ boolean cmdassist; /* provide detailed assistance for some commands */ boolean clicklook; /* allow right-clicking for look */ boolean obsolete; /* obsolete options can point at this, it isn't used */ struct autopickup_exception *autopickup_exceptions[2]; #define AP_LEAVE 0 #define AP_GRAB 1 #ifdef WIN32 #define MAX_ALTKEYHANDLER 25 char altkeyhandler[MAX_ALTKEYHANDLER]; #endif /* copies of values in struct u, used during detection when the originals are temporarily cleared; kept here rather than locally so that they can be restored during a hangup save */ Bitfield(save_uinwater, 1); Bitfield(save_uburied, 1); }; /* * Old deprecated names */ #ifdef TTY_GRAPHICS #define eight_bit_tty wc_eight_bit_input #endif #define use_color wc_color #define hilite_pet wc_hilite_pet #define use_inverse wc_inverse #ifdef MAC_GRAPHICS_ENV #define large_font obsolete #endif #ifdef MAC #define popup_dialog wc_popup_dialog #endif #define preload_tiles wc_preload_tiles extern NEARDATA struct flag flags; #ifdef SYSFLAGS extern NEARDATA struct sysflag sysflags; #endif extern NEARDATA struct instance_flags iflags; /* last_msg values */ #define PLNMSG_UNKNOWN 0 /* arbitrary */ #define PLNMSG_ONE_ITEM_HERE 1 /* "you see here" */ #define PLNMSG_TOWER_OF_FLAME 2 /* scroll of fire */ #define PLNMSG_CAUGHT_IN_EXPLOSION 3 /* explode() feedback */ #define PLNMSG_OBJ_GLOWS 4 /* "the glows " */ /* runmode options */ #define RUN_TPORT 0 /* don't update display until movement stops */ #define RUN_LEAP 1 /* update display every 7 steps */ #define RUN_STEP 2 /* update display every single step */ #define RUN_CRAWL 3 /* walk w/ extra delay after each update */ /* paranoid confirmation prompting */ /* any yes confirmations also require explicit no (or ESC) to reject */ #define ParanoidConfirm ((flags.paranoia_bits & PARANOID_CONFIRM) != 0) /* quit: yes vs y for "Really quit?" and "Enter explore mode?" */ #define ParanoidQuit ((flags.paranoia_bits & PARANOID_QUIT) != 0) /* die: yes vs y for "Die?" (dying in explore mode or wizard mode) */ #define ParanoidDie ((flags.paranoia_bits & PARANOID_DIE) != 0) /* hit: yes vs y for "Save bones?" in wizard mode */ #define ParanoidBones ((flags.paranoia_bits & PARANOID_BONES) != 0) /* hit: yes vs y for "Really attack ?" */ #define ParanoidHit ((flags.paranoia_bits & PARANOID_HIT) != 0) /* pray: ask "Really pray?" (accepts y answer, doesn't require yes), taking over for the old prayconfirm boolean option */ #define ParanoidPray ((flags.paranoia_bits & PARANOID_PRAY) != 0) /* remove: remove ('R') and takeoff ('T') commands prompt for an inventory item even when only one accessory or piece of armor is currently worn */ #define ParanoidRemove ((flags.paranoia_bits & PARANOID_REMOVE) != 0) /* breakwand: Applying a wand */ #define ParanoidBreakwand ((flags.paranoia_bits & PARANOID_BREAKWAND) != 0) /* command parsing, mainly dealing with number_pad handling; not saved and restored */ #ifdef NHSTDC /* forward declaration sufficient to declare pointers */ struct func_tab; /* from func_tab.h */ #endif /* commands[] is used to directly access cmdlist[] instead of looping through it to find the entry for a given input character; move_X is the character used for moving one step in direction X; alphadirchars corresponds to old sdir, dirchars corresponds to ``iflags.num_pad ? ndir : sdir''; pcHack_compat and phone_layout only matter when num_pad is on, swap_yz only matters when it's off */ struct cmd { unsigned serialno; /* incremented after each update */ boolean num_pad; /* same as iflags.num_pad except during updates */ boolean pcHack_compat; /* for numpad: affects 5, M-5, and M-0 */ boolean phone_layout; /* inverted keypad: 1,2,3 above, 7,8,9 below */ boolean swap_yz; /* German keyboards; use z to move NW, y to zap */ char move_W, move_NW, move_N, move_NE, move_E, move_SE, move_S, move_SW; const char *dirchars; /* current movement/direction characters */ const char *alphadirchars; /* same as dirchars if !numpad */ const struct func_tab *commands[256]; /* indexed by input character */ }; extern NEARDATA struct cmd Cmd; #endif /* FLAG_H */ nethack-3.6.0/include/func_tab.h0000664000076400007660000000112412536476415015525 0ustar paxedpaxed/* NetHack 3.6 func_tab.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef FUNC_TAB_H #define FUNC_TAB_H struct func_tab { char f_char; boolean can_if_buried; int NDECL((*f_funct)); const char *f_text; }; struct ext_func_tab { const char *ef_txt, *ef_desc; int NDECL((*ef_funct)); boolean can_if_buried; }; extern struct ext_func_tab extcmdlist[]; #endif /* FUNC_TAB_H */ nethack-3.6.0/include/gem_rsc.h0000664000076400007660000000462112536476415015370 0ustar paxedpaxed/* resource set indices for GEM_RSC */ #define MENU 0 /* menu */ #define DOABOUT 12 /* STRING in tree MENU */ #define DOQUIT 30 /* STRING in tree MENU */ #define STATUSLINE 1 /* form/dialog */ #define GRABSTATUS 1 /* BOX in tree STATUSLINE */ #define MAPWIN 2 /* form/dialog */ #define MAPBOX 0 /* BOX in tree MAPWIN */ #define MAPCURSOR 1 /* IBOX in tree MAPWIN */ #define ABOUT 3 /* form/dialog */ #define FLYABOUT 0 /* BOX in tree ABOUT */ #define OKABOUT 1 /* BUTTON in tree ABOUT */ #define NETHACKIMG0 3 /* ICON in tree ABOUT */ #define LINES 4 /* form/dialog */ #define FLYLINES 0 /* BOX in tree LINES */ #define QLINE 1 /* BUTTON in tree LINES */ #define LINESLIST 2 /* USERDEF in tree LINES */ #define YNCHOICE 5 /* form/dialog */ #define FLYYNCHOICE 0 /* BOX in tree YNCHOICE */ #define YNPROMPT 1 /* TEXT in tree YNCHOICE */ #define SOMECHARS 2 /* BOX in tree YNCHOICE */ #define YN1 3 /* BUTTON in tree YNCHOICE */ #define YNN 53 /* BUTTON in tree YNCHOICE */ #define ANYCHAR 55 /* BOX in tree YNCHOICE */ #define CHOSENCH 56 /* FBOXTEXT in tree YNCHOICE */ #define COUNT 58 /* FBOXTEXT in tree YNCHOICE */ #define YNOK 59 /* BUTTON in tree YNCHOICE */ #define LINEGET 6 /* form/dialog */ #define FLYLINEGET 0 /* BOX in tree LINEGET */ #define LGPROMPT 1 /* TEXT in tree LINEGET */ #define LGREPLY 2 /* FBOXTEXT in tree LINEGET */ #define QLG 3 /* BUTTON in tree LINEGET */ #define LGOK 4 /* BUTTON in tree LINEGET */ #define DIRECTION 7 /* form/dialog */ #define FLYDIRECTION 0 /* BOX in tree DIRECTION */ #define DIR1 5 /* BOXTEXT in tree DIRECTION */ #define DIR9 21 /* BOXTEXT in tree DIRECTION */ #define DIRDOWN 23 /* BOXTEXT in tree DIRECTION */ #define DIRUP 25 /* BOXTEXT in tree DIRECTION */ #define MSGWIN 8 /* form/dialog */ #define UPMSG 1 /* BOXCHAR in tree MSGWIN */ #define GRABMSGWIN 2 /* BOX in tree MSGWIN */ #define DNMSG 3 /* BOXCHAR in tree MSGWIN */ #define MSGLINES 4 /* USERDEF in tree MSGWIN */ #define NAMEGET 9 /* form/dialog */ #define FLYNAMEGET 0 /* BOX in tree NAMEGET */ #define PLNAME 2 /* FBOXTEXT in tree NAMEGET */ #define NETHACKPICTURE 4 /* BOXTEXT in tree NAMEGET */ #define PAGER 10 /* form/dialog */ #define FLYPAGER 0 /* BOX in tree PAGER */ #define QPAGER 1 /* BUTTON in tree PAGER */ #define NHICON 11 /* form/dialog */ nethack-3.6.0/include/global.h0000664000076400007660000002244612631241231015174 0ustar paxedpaxed/* NetHack 3.6 global.h $NHDT-Date: 1449116298 2015/12/03 04:18:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.46 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GLOBAL_H #define GLOBAL_H #include /* #define BETA */ /* development or beta testing [MRS] */ /* #define DEBUG */ /* * Files expected to exist in the playground directory. */ #define RECORD "record" /* file containing list of topscorers */ #define HELP "help" /* file containing command descriptions */ #define SHELP "hh" /* abbreviated form of the same */ #define DEBUGHELP "wizhelp" /* file containing debug mode cmds */ #define RUMORFILE "rumors" /* file with fortune cookies */ #define ORACLEFILE "oracles" /* file with oracular information */ #define DATAFILE "data" /* file giving the meaning of symbols used */ #define CMDHELPFILE "cmdhelp" /* file telling what commands do */ #define HISTORY "history" /* file giving nethack's history */ #define LICENSE "license" /* file with license information */ #define OPTIONFILE "opthelp" /* file explaining runtime options */ #define OPTIONS_USED "options" /* compile-time options, for #version */ #define SYMBOLS "symbols" /* replacement symbol sets */ #define EPITAPHFILE "epitaph" /* random epitaphs on graves */ #define ENGRAVEFILE "engrave" /* random engravings on the floor */ #define BOGUSMONFILE "bogusmon" /* hallucinatory monsters */ #define TRIBUTEFILE "tribute" /* 3.6 tribute to Terry Pratchett */ #define LEV_EXT ".lev" /* extension for special level files */ /* Assorted definitions that may depend on selections in config.h. */ /* * for DUMB preprocessor and compiler, e.g., cpp and pcc supplied * with Microport SysV/AT, which have small symbol tables; * DUMB if needed is defined in CFLAGS */ #ifdef DUMB #ifdef BITFIELDS #undef BITFIELDS #endif #ifndef STUPID #define STUPID #endif #endif /* DUMB */ /* * type xchar: small integers in the range 0 - 127, usually coordinates * although they are nonnegative they must not be declared unsigned * since otherwise comparisons with signed quantities are done incorrectly */ typedef schar xchar; #ifndef SKIP_BOOLEAN typedef xchar boolean; /* 0 or 1 */ #endif #ifndef TRUE /* defined in some systems' native include files */ #define TRUE ((boolean) 1) #define FALSE ((boolean) 0) #endif /* * type nhsym: loadable symbols go into this type */ typedef uchar nhsym; #ifndef STRNCMPI #ifndef __SASC_60 /* SAS/C already shifts to stricmp */ #define strcmpi(a, b) strncmpi((a), (b), -1) #endif #endif /* comment out to test effects of each #define -- these will probably * disappear eventually */ #ifdef INTERNAL_COMP #define RLECOMP /* run-length compression of levl array - JLee */ #define ZEROCOMP /* zero-run compression of everything - Olaf Seibert */ #endif /* #define SPECIALIZATION */ /* do "specialized" version of new topology */ #ifdef BITFIELDS #define Bitfield(x, n) unsigned x : n #else #define Bitfield(x, n) uchar x #endif #define SIZE(x) (int)(sizeof(x) / sizeof(x[0])) /* A limit for some NetHack int variables. It need not, and for comparable * scoring should not, depend on the actual limit on integers for a * particular machine, although it is set to the minimum required maximum * signed integer for C (2^15 -1). */ #define LARGEST_INT 32767 #include "coord.h" /* * Automatic inclusions for the subsidiary files. * Please don't change the order. It does matter. */ #ifdef VMS #include "vmsconf.h" #endif #ifdef UNIX #include "unixconf.h" #endif #ifdef OS2 #include "os2conf.h" #endif #ifdef MSDOS #include "pcconf.h" #endif #ifdef TOS #include "tosconf.h" #endif #ifdef AMIGA #include "amiconf.h" #endif #ifdef MAC #include "macconf.h" #endif #ifdef __BEOS__ #include "beconf.h" #endif #ifdef WIN32 #ifdef WIN_CE #include "wceconf.h" #else #include "ntconf.h" #endif #endif /* Displayable name of this port; don't redefine if defined in *conf.h */ #ifndef PORT_ID #ifdef AMIGA #define PORT_ID "Amiga" #endif #ifdef MAC #define PORT_ID "Mac" #endif #ifdef __APPLE__ #define PORT_ID "MacOSX" #endif #ifdef MSDOS #ifdef PC9800 #define PORT_ID "PC-9800" #else #define PORT_ID "PC" #endif #ifdef DJGPP #define PORT_SUB_ID "djgpp" #else #ifdef OVERLAY #define PORT_SUB_ID "overlaid" #else #define PORT_SUB_ID "non-overlaid" #endif #endif #endif #ifdef OS2 #define PORT_ID "OS/2" #endif #ifdef TOS #define PORT_ID "ST" #endif /* Check again in case something more specific has been defined above. */ #ifndef PORT_ID #ifdef UNIX #define PORT_ID "Unix" #endif #endif #ifdef VMS #define PORT_ID "VMS" #endif #ifdef WIN32 #define PORT_ID "Windows" #endif #endif #if defined(MICRO) #if !defined(AMIGA) && !defined(TOS) && !defined(OS2_HPFS) #define SHORT_FILENAMES /* filenames are 8.3 */ #endif #endif #ifdef VMS /* vms_exit() (sys/vms/vmsmisc.c) expects the non-VMS EXIT_xxx values below. * these definitions allow all systems to be treated uniformly, provided * main() routines do not terminate with return(), whose value is not * so massaged. */ #ifdef EXIT_SUCCESS #undef EXIT_SUCCESS #endif #ifdef EXIT_FAILURE #undef EXIT_FAILURE #endif #endif #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif #if defined(X11_GRAPHICS) || defined(QT_GRAPHICS) || defined(GNOME_GRAPHICS) \ || defined(WIN32) #ifndef USE_TILES #define USE_TILES /* glyph2tile[] will be available */ #endif #endif #if defined(AMII_GRAPHICS) || defined(GEM_GRAPHICS) #ifndef USE_TILES #define USE_TILES #endif #endif #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32) #define HANGUPHANDLING #endif #if defined(SAFERHANGUP) \ && (defined(NOSAVEONHANGUP) || !defined(HANGUPHANDLING)) #undef SAFERHANGUP #endif #define Sprintf (void) sprintf #define Strcat (void) strcat #define Strcpy (void) strcpy #ifdef NEED_VARARGS #define Vprintf (void) vprintf #define Vfprintf (void) vfprintf #define Vsprintf (void) vsprintf #endif /* primitive memory leak debugging; see alloc.c */ #ifdef MONITOR_HEAP extern long *FDECL(nhalloc, (unsigned int, const char *, int)); extern void FDECL(nhfree, (genericptr_t, const char *, int)); extern char *FDECL(nhdupstr, (const char *, const char *, int)); #ifndef __FILE__ #define __FILE__ "" #endif #ifndef __LINE__ #define __LINE__ 0 #endif #define alloc(a) nhalloc(a, __FILE__, (int) __LINE__) #define free(a) nhfree(a, __FILE__, (int) __LINE__) #define dupstr(s) nhdupstr(s, __FILE__, (int) __LINE__) #else /* !MONITOR_HEAP */ extern long *FDECL(alloc, (unsigned int)); /* alloc.c */ extern char *FDECL(dupstr, (const char *)); /* ditto */ #endif /* Used for consistency checks of various data files; declare it here so that utility programs which include config.h but not hack.h can see it. */ struct version_info { unsigned long incarnation; /* actual version number */ unsigned long feature_set; /* bitmask of config settings */ unsigned long entity_count; /* # of monsters and objects */ unsigned long struct_sizes1; /* size of key structs */ unsigned long struct_sizes2; /* size of more key structs */ }; struct savefile_info { unsigned long sfi1; /* compression etc. */ unsigned long sfi2; /* miscellaneous */ unsigned long sfi3; /* thirdparty */ }; #ifdef NHSTDC #define SFI1_EXTERNALCOMP (1UL) #define SFI1_RLECOMP (1UL << 1) #define SFI1_ZEROCOMP (1UL << 2) #else #define SFI1_EXTERNALCOMP (1L) #define SFI1_RLECOMP (1L << 1) #define SFI1_ZEROCOMP (1L << 2) #endif /* * Configurable internal parameters. * * Please be very careful if you are going to change one of these. Any * changes in these parameters, unless properly done, can render the * executable inoperative. */ /* size of terminal screen is (at least) (ROWNO+3) by COLNO */ #define COLNO 80 #define ROWNO 21 #define MAXNROFROOMS 40 /* max number of rooms per level */ #define MAX_SUBROOMS 24 /* max # of subrooms in a given room */ #define DOORMAX 120 /* max number of doors per level */ #define BUFSZ 256 /* for getlin buffers */ #define QBUFSZ 128 /* for building question text */ #define TBUFSZ 300 /* toplines[] buffer max msg: 3 81char names */ /* plus longest prefix plus a few extra words */ #define PL_NSIZ 32 /* name of player, ghost, shopkeeper */ #define PL_CSIZ 32 /* sizeof pl_character */ #define PL_FSIZ 32 /* fruit name */ #define PL_PSIZ \ 63 /* player-given names for pets, other \ * monsters, objects */ #define MAXDUNGEON 16 /* current maximum number of dungeons */ #define MAXLEVEL 32 /* max number of levels in one dungeon */ #define MAXSTAIRS 1 /* max # of special stairways in a dungeon */ #define ALIGNWEIGHT 4 /* generation weight of alignment */ #define MAXULEV 30 /* max character experience level */ #define MAXMONNO 120 /* extinct monst after this number created */ #define MHPMAX 500 /* maximum monster hp */ /* PANICTRACE: Always defined for BETA but only for supported platforms. */ #ifdef UNIX #ifdef BETA /* see end.c */ #ifndef PANICTRACE #define PANICTRACE #endif #endif #endif /* The following are meaningless if PANICTRACE is not defined: */ #if defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) #define PANICTRACE_LIBC #endif #if defined(MACOSX) #define PANICTRACE_LIBC #endif #ifdef UNIX #define PANICTRACE_GDB #endif #endif /* GLOBAL_H */ nethack-3.6.0/include/hack.h0000664000076400007660000003477112536476415014670 0ustar paxedpaxed/* NetHack 3.6 hack.h $NHDT-Date: 1434056948 2015/06/11 21:09:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.66 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef HACK_H #define HACK_H #ifndef CONFIG_H #include "config.h" #endif #include "lint.h" #define TELL 1 #define NOTELL 0 #define ON 1 #define OFF 0 #define BOLT_LIM 8 /* from this distance ranged attacks will be made */ #define MAX_CARR_CAP 1000 /* so that boulders can be heavier */ #define DUMMY \ { \ 0 \ } /* symbolic names for capacity levels */ #define UNENCUMBERED 0 #define SLT_ENCUMBER 1 /* Burdened */ #define MOD_ENCUMBER 2 /* Stressed */ #define HVY_ENCUMBER 3 /* Strained */ #define EXT_ENCUMBER 4 /* Overtaxed */ #define OVERLOADED 5 /* Overloaded */ /* hunger states - see hu_stat in eat.c */ #define SATIATED 0 #define NOT_HUNGRY 1 #define HUNGRY 2 #define WEAK 3 #define FAINTING 4 #define FAINTED 5 #define STARVED 6 /* Macros for how a rumor was delivered in outrumor() */ #define BY_ORACLE 0 #define BY_COOKIE 1 #define BY_PAPER 2 #define BY_OTHER 9 /* Macros for why you are no longer riding */ #define DISMOUNT_GENERIC 0 #define DISMOUNT_FELL 1 #define DISMOUNT_THROWN 2 #define DISMOUNT_POLY 3 #define DISMOUNT_ENGULFED 4 #define DISMOUNT_BONES 5 #define DISMOUNT_BYCHOICE 6 /* Special returns from mapglyph() */ #define MG_CORPSE 0x01 #define MG_INVIS 0x02 #define MG_DETECT 0x04 #define MG_PET 0x08 #define MG_RIDDEN 0x10 #define MG_STATUE 0x20 #define MG_OBJPILE 0x40 /* more than one stack of objects */ /* sellobj_state() states */ #define SELL_NORMAL (0) #define SELL_DELIBERATE (1) #define SELL_DONTSELL (2) /* alteration types--keep in synch with costly_alteration(mkobj.c) */ #define COST_CANCEL 0 /* standard cancellation */ #define COST_DRAIN 1 /* drain life upon an object */ #define COST_UNCHRG 2 /* cursed charging */ #define COST_UNBLSS 3 /* unbless (devalues holy water) */ #define COST_UNCURS 4 /* uncurse (devalues unholy water) */ #define COST_DECHNT 5 /* disenchant weapons or armor */ #define COST_DEGRD 6 /* removal of rustproofing, dulling via engraving */ #define COST_DILUTE 7 /* potion dilution */ #define COST_ERASE 8 /* scroll or spellbook blanking */ #define COST_BURN 9 /* dipped into flaming oil */ #define COST_NUTRLZ 10 /* neutralized via unicorn horn */ #define COST_DSTROY 11 /* wand breaking (bill first, useup later) */ #define COST_SPLAT 12 /* cream pie to own face (ditto) */ #define COST_BITE 13 /* start eating food */ #define COST_OPEN 14 /* open tin */ #define COST_BRKLCK 15 /* break box/chest's lock */ #define COST_RUST 16 /* rust damage */ #define COST_ROT 17 /* rotting attack */ #define COST_CORRODE 18 /* acid damage */ /* bitmask flags for corpse_xname(); PFX_THE takes precedence over ARTICLE, NO_PFX takes precedence over both */ #define CXN_NORMAL 0 /* no special handling */ #define CXN_SINGULAR 1 /* override quantity if greather than 1 */ #define CXN_NO_PFX 2 /* suppress "the" from "the Unique Monst */ #define CXN_PFX_THE 4 /* prefix with "the " (unless pname) */ #define CXN_ARTICLE 8 /* include a/an/the prefix */ #define CXN_NOCORPSE 16 /* suppress " corpse" suffix */ /* * This is the way the game ends. If these are rearranged, the arrays * in end.c and topten.c will need to be changed. Some parts of the * code assume that PANIC separates the deaths from the non-deaths. */ #define DIED 0 #define CHOKING 1 #define POISONING 2 #define STARVING 3 #define DROWNING 4 #define BURNING 5 #define DISSOLVED 6 #define CRUSHING 7 #define STONING 8 #define TURNED_SLIME 9 #define GENOCIDED 10 #define PANICKED 11 #define TRICKED 12 #define QUIT 13 #define ESCAPED 14 #define ASCENDED 15 #include "align.h" #include "dungeon.h" #include "monsym.h" #include "mkroom.h" #include "objclass.h" #include "youprop.h" #include "wintype.h" #include "context.h" #include "decl.h" #include "timeout.h" NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ /* types of calls to bhit() */ #define ZAPPED_WAND 0 #define THROWN_WEAPON 1 #define KICKED_WEAPON 2 #define FLASHED_LIGHT 3 #define INVIS_BEAM 4 /* attack mode for hmon() */ #define HMON_MELEE 0 /* hand-to-hand */ #define HMON_THROWN 1 /* normal ranged (or spitting while poly'd) */ #define HMON_KICKED 2 /* alternate ranged */ #define HMON_APPLIED 3 /* polearm, treated as ranged */ #define HMON_DRAGGED 4 /* attached iron ball, pulled into mon */ #define MATCH_WARN_OF_MON(mon) \ (Warn_of_mon && ((context.warntype.obj \ && (context.warntype.obj & (mon)->data->mflags2)) \ || (context.warntype.polyd \ && (context.warntype.polyd & (mon)->data->mflags2)) \ || (context.warntype.species \ && (context.warntype.species == (mon)->data)))) #include "trap.h" #include "flag.h" #include "rm.h" #include "vision.h" #include "display.h" #include "engrave.h" #include "rect.h" #include "region.h" /* Symbol offsets */ #define SYM_OFF_P (0) #define SYM_OFF_O (SYM_OFF_P + MAXPCHARS) #define SYM_OFF_M (SYM_OFF_O + MAXOCLASSES) #define SYM_OFF_W (SYM_OFF_M + MAXMCLASSES) #define SYM_OFF_X (SYM_OFF_W + WARNCOUNT) #define SYM_MAX (SYM_OFF_X + MAXOTHER) #ifdef USE_TRAMPOLI /* This doesn't belong here, but we have little choice \ */ #undef NDECL #define NDECL(f) f() #endif #include "extern.h" #include "winprocs.h" #include "sys.h" #ifdef USE_TRAMPOLI #include "wintty.h" #undef WINTTY_H #include "trampoli.h" #undef EXTERN_H #include "extern.h" #endif /* USE_TRAMPOLI */ /* flags to control makemon() */ #define NO_MM_FLAGS 0x00000 /* use this rather than plain 0 */ #define NO_MINVENT 0x00001 /* suppress minvent when creating mon */ #define MM_NOWAIT 0x00002 /* don't set STRAT_WAITMASK flags */ #define MM_NOCOUNTBIRTH \ 0x00004 /* don't increment born counter (for revival) */ #define MM_IGNOREWATER 0x00008 /* ignore water when positioning */ #define MM_ADJACENTOK \ 0x00010 /* it is acceptable to use adjacent coordinates */ #define MM_ANGRY 0x00020 /* monster is created angry */ #define MM_NONAME 0x00040 /* monster is not christened */ #define MM_EGD 0x00100 /* add egd structure */ #define MM_EPRI 0x00200 /* add epri structure */ #define MM_ESHK 0x00400 /* add eshk structure */ #define MM_EMIN 0x00800 /* add emin structure */ #define MM_EDOG 0x01000 /* add edog structure */ /* flags for make_corpse() and mkcorpstat() */ #define CORPSTAT_NONE 0x00 #define CORPSTAT_INIT 0x01 /* pass init flag to mkcorpstat */ #define CORPSTAT_BURIED 0x02 /* bury the corpse or statue */ /* flags for decide_to_shift() */ #define SHIFT_SEENMSG 0x01 /* put out a message if in sight */ #define SHIFT_MSG 0x02 /* always put out a message */ /* special mhpmax value when loading bones monster to flag as extinct or * genocided */ #define DEFUNCT_MONSTER (-100) /* macro form of adjustments of physical damage based on Half_physical_damage. * Can be used on-the-fly with the 1st parameter to losehp() if you don't * need to retain the dmg value beyond that call scope. * Take care to ensure it doesn't get used more than once in other instances. */ #define Maybe_Half_Phys(dmg) \ ((Half_physical_damage) ? (((dmg) + 1) / 2) : (dmg)) /* flags for special ggetobj status returns */ #define ALL_FINISHED 0x01 /* called routine already finished the job */ /* flags to control query_objlist() */ #define BY_NEXTHERE 0x1 /* follow objlist by nexthere field */ #define AUTOSELECT_SINGLE 0x2 /* if only 1 object, don't ask */ #define USE_INVLET 0x4 /* use object's invlet */ #define INVORDER_SORT 0x8 /* sort objects by packorder */ #define SIGNAL_NOMENU 0x10 /* return -1 rather than 0 if none allowed */ #define SIGNAL_ESCAPE 0x20 /* return -2 rather than 0 for ESC */ #define FEEL_COCKATRICE 0x40 /* engage cockatrice checks and react */ #define INCLUDE_HERO 0x80 /* show hero among engulfer's inventory */ /* Flags to control query_category() */ /* BY_NEXTHERE used by query_category() too, so skip 0x01 */ #define UNPAID_TYPES 0x02 #define GOLD_TYPES 0x04 #define WORN_TYPES 0x08 #define ALL_TYPES 0x10 #define BILLED_TYPES 0x20 #define CHOOSE_ALL 0x40 #define BUC_BLESSED 0x80 #define BUC_CURSED 0x100 #define BUC_UNCURSED 0x200 #define BUC_UNKNOWN 0x400 #define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED) #define ALL_TYPES_SELECTED -2 /* Flags to control find_mid() */ #define FM_FMON 0x01 /* search the fmon chain */ #define FM_MIGRATE 0x02 /* search the migrating monster chain */ #define FM_MYDOGS 0x04 /* search mydogs */ #define FM_EVERYWHERE (FM_FMON | FM_MIGRATE | FM_MYDOGS) /* Flags to control pick_[race,role,gend,align] routines in role.c */ #define PICK_RANDOM 0 #define PICK_RIGID 1 /* Flags to control dotrap() in trap.c */ #define FORCETRAP 0x01 /* triggering not left to chance */ #define NOWEBMSG 0x02 /* suppress stumble into web message */ #define FORCEBUNGLE 0x04 /* adjustments appropriate for bungling */ #define RECURSIVETRAP 0x08 /* trap changed into another type this same turn \ */ #define TOOKPLUNGE 0x10 /* used '>' to enter pit below you */ /* Flags to control test_move in hack.c */ #define DO_MOVE 0 /* really doing the move */ #define TEST_MOVE 1 /* test a normal move (move there next) */ #define TEST_TRAV 2 /* test a future travel location */ /*** some utility macros ***/ #define yn(query) yn_function(query, ynchars, 'n') #define ynq(query) yn_function(query, ynqchars, 'q') #define ynaq(query) yn_function(query, ynaqchars, 'y') #define nyaq(query) yn_function(query, ynaqchars, 'n') #define nyNaq(query) yn_function(query, ynNaqchars, 'n') #define ynNaq(query) yn_function(query, ynNaqchars, 'y') /* Macros for scatter */ #define VIS_EFFECTS 0x01 /* display visual effects */ #define MAY_HITMON 0x02 /* objects may hit monsters */ #define MAY_HITYOU 0x04 /* objects may hit you */ #define MAY_HIT (MAY_HITMON | MAY_HITYOU) #define MAY_DESTROY 0x08 /* objects may be destroyed at random */ #define MAY_FRACTURE 0x10 /* boulders & statues may fracture */ /* Macros for launching objects */ #define ROLL 0x01 /* the object is rolling */ #define FLING 0x02 /* the object is flying thru the air */ #define LAUNCH_UNSEEN 0x40 /* hero neither caused nor saw it */ #define LAUNCH_KNOWN 0x80 /* the hero caused this by explicit action */ /* Macros for explosion types */ #define EXPL_DARK 0 #define EXPL_NOXIOUS 1 #define EXPL_MUDDY 2 #define EXPL_WET 3 #define EXPL_MAGICAL 4 #define EXPL_FIERY 5 #define EXPL_FROSTY 6 #define EXPL_MAX 7 /* enlightenment control flags */ #define BASICENLIGHTENMENT 1 /* show mundane stuff */ #define MAGICENLIGHTENMENT 2 /* show intrinsics and such */ #define ENL_GAMEINPROGRESS 0 #define ENL_GAMEOVERALIVE 1 /* ascension, escape, quit, trickery */ #define ENL_GAMEOVERDEAD 2 /* Macros for messages referring to hands, eyes, feet, etc... */ #define ARM 0 #define EYE 1 #define FACE 2 #define FINGER 3 #define FINGERTIP 4 #define FOOT 5 #define HAND 6 #define HANDED 7 #define HEAD 8 #define LEG 9 #define LIGHT_HEADED 10 #define NECK 11 #define SPINE 12 #define TOE 13 #define HAIR 14 #define BLOOD 15 #define LUNG 16 #define NOSE 17 #define STOMACH 18 /* indices for some special tin types */ #define ROTTEN_TIN 0 #define HOMEMADE_TIN 1 #define SPINACH_TIN (-1) #define RANDOM_TIN (-2) #define HEALTHY_TIN (-3) /* Some misc definitions */ #define POTION_OCCUPANT_CHANCE(n) (13 + 2 * (n)) #define WAND_BACKFIRE_CHANCE 100 #define BALL_IN_MON (u.uswallow && uball && uball->where == OBJ_FREE) #define NODIAG(monnum) ((monnum) == PM_GRID_BUG) /* Flags to control menus */ #define MENUTYPELEN sizeof("traditional ") #define MENU_TRADITIONAL 0 #define MENU_COMBINATION 1 #define MENU_FULL 2 #define MENU_PARTIAL 3 #define MENU_SELECTED TRUE #define MENU_UNSELECTED FALSE /* * Option flags * Each higher number includes the characteristics of the numbers * below it. */ /* XXX This should be replaced with a bitmap. */ #define SET_IN_SYS 0 /* system config file option only */ #define SET_IN_FILE 1 /* config file option only */ #define SET_VIA_PROG 2 /* may be set via extern program, not seen in game */ #define DISP_IN_GAME 3 /* may be set via extern program, displayed in game \ */ #define SET_IN_GAME 4 /* may be set via extern program or set in the game */ #define SET__IS_VALUE_VALID(s) ((s < SET_IN_SYS) || (s > SET_IN_GAME)) #define FEATURE_NOTICE_VER(major, minor, patch) \ (((unsigned long) major << 24) | ((unsigned long) minor << 16) \ | ((unsigned long) patch << 8) | ((unsigned long) 0)) #define FEATURE_NOTICE_VER_MAJ (flags.suppress_alert >> 24) #define FEATURE_NOTICE_VER_MIN \ (((unsigned long) (0x0000000000FF0000L & flags.suppress_alert)) >> 16) #define FEATURE_NOTICE_VER_PATCH \ (((unsigned long) (0x000000000000FF00L & flags.suppress_alert)) >> 8) #ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define plur(x) (((x) == 1) ? "" : "s") #define ARM_BONUS(obj) \ (objects[(obj)->otyp].a_ac + (obj)->spe \ - min((int) greatest_erosion(obj), objects[(obj)->otyp].a_ac)) #define makeknown(x) discover_object((x), TRUE, TRUE) #define distu(xx, yy) dist2((int)(xx), (int)(yy), (int) u.ux, (int) u.uy) #define onlineu(xx, yy) online2((int)(xx), (int)(yy), (int) u.ux, (int) u.uy) #define rn1(x, y) (rn2(x) + (y)) /* negative armor class is randomly weakened to prevent invulnerability */ #define AC_VALUE(AC) ((AC) >= 0 ? (AC) : -rnd(-(AC))) #if defined(MICRO) && !defined(__DJGPP__) #define getuid() 1 #define getlogin() ((char *) 0) #endif /* MICRO */ #if defined(OVERLAY) #define USE_OVLx #define STATIC_DCL extern #define STATIC_OVL #define STATIC_VAR #else /* !OVERLAY */ #define STATIC_DCL static #define STATIC_OVL static #define STATIC_VAR static #endif /* OVERLAY */ /* Macro for a few items that are only static if we're not overlaid.... */ #if defined(USE_TRAMPOLI) || defined(USE_OVLx) #define STATIC_PTR #else #define STATIC_PTR static #endif /* The function argument to qsort() requires a particular * calling convention under WINCE which is not the default * in that environment. */ #if defined(WIN_CE) #define CFDECLSPEC __cdecl #else #define CFDECLSPEC #endif #define DEVTEAM_EMAIL "devteam@nethack.org" #define DEVTEAM_URL "http://www.nethack.org" #endif /* HACK_H */ nethack-3.6.0/include/lev.h0000664000076400007660000000263112536476415014536 0ustar paxedpaxed/* NetHack 3.6 lev.h $NHDT-Date: 1432512781 2015/05/25 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Common include file for save and restore routines */ #ifndef LEV_H #define LEV_H #define COUNT_SAVE 0x1 #define WRITE_SAVE 0x2 #define FREE_SAVE 0x4 #define MAX_BMASK 4 /* operations of the various saveXXXchn & co. routines */ #define perform_bwrite(mode) ((mode) & (COUNT_SAVE | WRITE_SAVE)) #define release_data(mode) ((mode) &FREE_SAVE) /* The following are used in mkmaze.c */ struct container { struct container *next; xchar x, y; short what; genericptr_t list; }; #define CONS_OBJ 0 #define CONS_MON 1 #define CONS_HERO 2 #define CONS_TRAP 3 struct bubble { xchar x, y; /* coordinates of the upper left corner */ schar dx, dy; /* the general direction of the bubble's movement */ uchar bm[MAX_BMASK + 2]; /* bubble bit mask */ struct bubble *prev, *next; /* need to traverse the list up and down */ struct container *cons; }; /* used in light.c */ typedef struct ls_t { struct ls_t *next; xchar x, y; /* source's position */ short range; /* source's current range */ short flags; short type; /* type of light source */ anything id; /* source's identifier */ } light_source; #endif /* LEV_H */ nethack-3.6.0/include/lint.h0000664000076400007660000000574612631241231014706 0ustar paxedpaxed/* NetHack 3.6 lint.h $NHDT-Date: 1449269910 2015/12/04 22:58:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.3 $ */ /* NetHack may be freely redistributed. See license for details. */ /* * Hacks to suppress compiler warnings. Use with caution. * Assumes it has been preceded by '#include "config.h"' but * not necessarily by '#include "hack.h"'. */ #ifndef LINT_H #define LINT_H /* cast away implicit const from a string literal (caller's responsibility to ensure that) in order to avoid a warning from 'gcc -Wwrite-strings' (also caller's responsibility to ensure it isn't actually modified!) */ #define nhStr(str) ((char *) str) #if defined(GCC_WARN) && !defined(FORCE_ARG_USAGE) #define FORCE_ARG_USAGE #endif #ifdef FORCE_ARG_USAGE /* force an unused function argument to become used in an arbitrary manner in order to suppress warning about unused function arguments; viable for scalar and pointer arguments */ #define nhUse(arg) nhUse_dummy += (unsigned) arg; extern unsigned nhUse_dummy; #else #define nhUse(arg) /*empty*/ #endif /* * This stuff isn't related to lint suppression but lives here to * avoid cluttering up hack.h. */ /* [DEBUG shouldn't be defined unless you know what you're doing...] */ #ifdef DEBUG #define showdebug(file) debugcore(file, TRUE) #define explicitdebug(file) debugcore(file, FALSE) #define ifdebug(stmt) \ do { \ if (showdebug(__FILE__)) { \ stmt; \ } \ } while (0) #ifdef _MSC_VER /* if we have microsoft's C runtime we can use these instead */ #include #define crtdebug(stmt) \ do { \ if (showdebug(__FILE__)) { \ stmt; \ } \ _RPT0(_CRT_WARN, "\n"); \ } while (0) #define debugpline0(str) crtdebug(_RPT0(_CRT_WARN, str)) #define debugpline1(fmt, arg) crtdebug(_RPT1(_CRT_WARN, fmt, arg)) #define debugpline2(fmt, a1, a2) crtdebug(_RPT2(_CRT_WARN, fmt, a1, a2)) #define debugpline3(fmt, a1, a2, a3) \ crtdebug(_RPT3(_CRT_WARN, fmt, a1, a2, a3)) #define debugpline4(fmt, a1, a2, a3, a4) \ crtdebug(_RPT4(_CRT_WARN, fmt, a1, a2, a3, a4)) #else /* these don't require compiler support for C99 variadic macros */ #define debugpline0(str) ifdebug(pline(str)) #define debugpline1(fmt, arg) ifdebug(pline(fmt, arg)) #define debugpline2(fmt, a1, a2) ifdebug(pline(fmt, a1, a2)) #define debugpline3(fmt, a1, a2, a3) ifdebug(pline(fmt, a1, a2, a3)) #define debugpline4(fmt, a1, a2, a3, a4) ifdebug(pline(fmt, a1, a2, a3, a4)) #endif #else #define debugpline0(str) /*empty*/ #define debugpline1(fmt, arg) /*empty*/ #define debugpline2(fmt, a1, a2) /*empty*/ #define debugpline3(fmt, a1, a2, a3) /*empty*/ #define debugpline4(fmt, a1, a2, a3, a4) /*empty*/ #endif /*DEBUG*/ #endif /* LINT_H */ nethack-3.6.0/include/load_img.h0000664000076400007660000000323512536476415015524 0ustar paxedpaxed /* ------------------------------------------- */ #define XIMG 0x58494D47 /* Header of GEM Image Files */ typedef struct IMG_HEADER { short version; /* Img file format version (1) */ short length; /* Header length in words (8) */ short planes; /* Number of bit-planes (1) */ short pat_len; /* length of Patterns (2) */ short pix_w; /* Pixel width in 1/1000 mmm (372) */ short pix_h; /* Pixel height in 1/1000 mmm (372) */ short img_w; /* Pixels per line (=(x+7)/8 Bytes) */ short img_h; /* Total number of lines */ long magic; /* Contains "XIMG" if standard color */ short paltype; /* palette type (0=RGB (short each)) */ short *palette; /* palette etc. */ char *addr; /* Address for the depacked bit-planes */ } IMG_header; /* ------------------------------------------- */ /* error codes */ #define ERR_HEADER 1 #define ERR_ALLOC 2 #define ERR_FILE 3 #define ERR_DEPACK 4 #define ERR_COLOR 5 /* saves the current colorpalette with col colors in palette */ void get_colors(int handle, short *palette, int col); /* sets col colors from palette */ void img_set_colors(int handle, short *palette, int col); /* converts MFDB of size from standard to deviceformat (0 if succeded, else * error). */ int convert(MFDB *, long); /* transforms image in VDI-Device format */ int transform_img(MFDB *); /* Loads & depacks IMG (0 if succeded, else error). */ /* Bitplanes are one after another in address IMG_HEADER.addr. */ int depack_img(char *, IMG_header *); /* Halves IMG in Device-format, dest memory has to be allocated*/ int half_img(MFDB *, MFDB *); nethack-3.6.0/include/mac-carbon.h0000664000076400007660000000202712536476415015751 0ustar paxedpaxed/* NetHack 3.6 mac-carbon.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /* NetHack may be freely redistributed. See license for details. */ /* Compiler prefix file for the Macintosh Carbon port. * * IMPORTANT: This file is intended only as a compiler prefix * file and must NEVER be included by other source (.c or .h) * files. * * Usage for MacOS X Project Builder: * Project menu -> Edit Active Target '_target_' -> * target settings dialog -> Settings -> Simple View -> * GCC Compiler Settings -> * set "Prefix Header" to include/mac-carbon.h * * Usage for Metrowerks CodeWarrior: * Edit menu -> _target_ Settings -> Language Settings -> * C/C++ Language -> * set "Prefix File" to include/mac-carbon.h */ #define MAC #undef UNIX /* May already be defined by CodeWarrior as 0 or 1 */ #ifdef TARGET_API_MAC_CARBON #undef TARGET_API_MAC_CARBON #endif #define TARGET_API_MAC_CARBON 1 #define GCC_WARN nethack-3.6.0/include/mac-qt.h0000664000076400007660000000202312536476415015125 0ustar paxedpaxed/* NetHack 3.6 mac-qt.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /* NetHack may be freely redistributed. See license for details. */ /* Compiler prefix file for the Macintosh Qt port. * * IMPORTANT: This file is intended only as a compiler prefix * file and must NEVER be included by other source (.c or .h) * files. * * Usage for MacOS X Project Builder: * Project menu -> Edit Active Target '_target_' -> * target settings dialog -> Settings -> Simple View -> * GCC Compiler Settings -> * set "Prefix Header" to include/mac-qt.h * * Usage for Metrowerks CodeWarrior: * Edit menu -> _target_ Settings -> Language Settings -> * C/C++ Language -> * set "Prefix File" to include/mac-qt.h */ #undef MAC #define UNIX #define BSD /* May already be defined by CodeWarrior as 0 or 1 */ #ifdef TARGET_API_MAC_CARBON #undef TARGET_API_MAC_CARBON #endif #define TARGET_API_MAC_CARBON 0 #define GCC_WARN nethack-3.6.0/include/mac-term.h0000664000076400007660000000222112536476415015450 0ustar paxedpaxed/* NetHack 3.6 mac-term.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /* NetHack may be freely redistributed. See license for details. */ /* Compiler prefix file for the MacOS X Terminal.app port. * * IMPORTANT: This file is intended only as a compiler prefix * file and must NEVER be included by other source (.c or .h) * files. * * Usage for MacOS X Project Builder: * Project menu -> Edit Active Target '_target_' -> * target settings dialog -> Settings -> Simple View -> * GCC Compiler Settings -> * set "Prefix Header" to include/mac-term.h * * Usage for Metrowerks CodeWarrior: * Edit menu -> _target_ Settings -> Language Settings -> * C/C++ Language -> * set "Prefix File" to include/mac-term.h */ /* Stuff needed for the core of NetHack */ #undef MAC #define UNIX #define BSD #define __FreeBSD__ /* Darwin is based on FreeBSD */ #define GCC_WARN /* May already be defined by CodeWarrior as 0 or 1 */ #ifdef TARGET_API_MAC_CARBON #undef TARGET_API_MAC_CARBON #endif #define TARGET_API_MAC_CARBON 0 /* Not Carbon */ nethack-3.6.0/include/macconf.h0000664000076400007660000000634212536476415015361 0ustar paxedpaxed/* NetHack 3.6 macconf.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef MAC #ifndef MACCONF_H #define MACCONF_H /* * Compiler selection is based on the following symbols: * * __SC__ sc, a MPW 68k compiler * __MRC__ mrc, a MPW PowerPC compiler * THINK_C Think C compiler * __MWERKS__ Metrowerks' Codewarrior compiler * * We use these early in config.h to define some needed symbols, * including MAC. # # The Metrowerks compiler defines __STDC__ (which sets NHSTC) and uses # WIDENED_PROTOTYPES (defined if UNWIDENED_PROTOTYPES is undefined and # NHSTDC is defined). */ #ifndef __powerc #define MAC68K /* 68K mac (non-powerpc) */ #endif #ifndef TARGET_API_MAC_CARBON #define TARGET_API_MAC_CARBON 0 #endif #ifndef __MACH__ #define RANDOM #endif #define NO_SIGNAL /* You wouldn't believe our signals ... */ #define FILENAME 256 #define NO_TERMS /* For tty port (see wintty.h) */ #define TEXTCOLOR /* For Mac TTY interface */ #define CHANGE_COLOR /* Use these two includes instead of system.h. */ #include #include /* Uncomment this line if your headers don't already define off_t */ /*typedef long off_t;*/ #include /* for time_t */ /* * Try and keep the number of files here to an ABSOLUTE minimum ! * include the relevant files in the relevant .c files instead ! */ #if TARGET_API_MAC_CARBON #ifdef GNUC /* Avoid including -- it has a conflicting expl() */ #define __FP__ #include #else /* Avoid including -- it uses GENERATINGPOWERPC */ #define __FENV__ #include #include #endif #else #include #endif /* * We could use the PSN under sys 7 here ... * ...but it wouldn't matter... */ #define getpid() 1 #define getuid() 1 #define index strchr #define rindex strrchr #define Rand random extern void error(const char *, ...); #if !defined(O_WRONLY) #if defined(__MWERKS__) && !TARGET_API_MAC_CARBON #include #endif #include #endif /* * Don't redefine these Unix IO functions when making LevComp or DgnComp for * MPW. With MPW, we make them into MPW tools, which use unix IO. SPEC_LEV * and DGN_COMP are defined when compiling for LevComp and DgnComp * respectively. */ #if !((defined(__SC__) || defined(__MRC__) || defined(__MACH__)) \ && (defined(SPEC_LEV) || defined(DGN_COMP))) #define creat maccreat #define open macopen #define close macclose #define read macread #define write macwrite #define lseek macseek #ifdef __MWERKS__ #define unlink _unlink #endif #endif #define YY_NEVER_INTERACTIVE 1 #define TEXT_TYPE 'TEXT' #define LEVL_TYPE 'LEVL' #define BONE_TYPE 'BONE' #define SAVE_TYPE 'SAVE' #define PREF_TYPE 'PREF' #define DATA_TYPE 'DATA' #define MAC_CREATOR 'nh31' /* Registered with DTS ! */ #define TEXT_CREATOR 'ttxt' /* Something the user can actually edit */ /* * Define PORT_HELP to be the name of the port-specfic help file. * This file is included into the resource fork of the application. */ #define PORT_HELP "MacHelp" #define MAC_GRAPHICS_ENV #endif /* ! MACCONF_H */ #endif /* MAC */ nethack-3.6.0/include/macpopup.h0000664000076400007660000000103112610522241015543 0ustar paxedpaxed/* NetHack 3.6 macpopup.h $NHDT-Date: 1432512781 2015/05/25 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Nethack Development Team, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MACPOPUP_H #define MACPOPUP_H /* ### mmodal.c ### */ extern void FlashButton(DialogRef, short); extern char queued_resp(char *resp); extern char topl_yn_function(const char *query, const char *resp, char def); extern int get_line_from_key_queue(char *bufp); #endif /* MACPOPUP_H */ nethack-3.6.0/include/mactty.h0000664000076400007660000002626512622603541015246 0ustar paxedpaxed/* NetHack 3.6 mactty.h $NHDT-Date: 1447755970 2015/11/17 10:26:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * This header is the supported external interface for the "tty" window * package. This package sports care-free handling of "dumb" tty windows * (preferably using monospaced fonts) - it does NOT remember the strings * sent to it; rather, it uses an offscreen bitmap. * * For best performance, make sure it is aligned on a 32-pixel boundary * (or at least a 16-pixel one) in black & white. For 24bit color, * alignment doesn't matter, and for 8-bit color, alignment to every * fourth pixel is most efficient. * * (c) Copyright 1993 Jon W{tte */ /* * You should really not poke in the structures used by the tty window. * However, since it uses the wRefCon of windows (by calling GetWRefCon * and SetWRefCon) you lose that possibility. If you still want to store * information about a window, the FIRST location _pointed to_ by the * wRefCon will be a void * that you can use for whatever reasons. Don't * take the address of this variable and expect it to stay the same * across calls to the tty window. * * void * my_config_ptr = * ( void * * ) GetWRefCon ( tty_window ) ; */ /* * The library uses the window's port temporarily through SetPortBits; * that means you shouldn't do any funky things to the clipping region * etc. Actually, you shouldn't even resize the window, as that will clip * new drawing. * * Also, if you use this library under Pascal, remember that the string * passed to add_tty_string() is a "C" style string with NO length byte, * and a terminating zero byte at the end instead. */ #ifndef _H_tty_public #define _H_tty_public #undef red /* undef internal color const strings from decl */ #undef green #undef blue #if 1 /*!TARGET_API_MAC_CARBON*/ #include #endif /* * Error code returned when it's probably our fault, or * bad parameters. */ #define general_failure 1 /* * Base resource id's for window types */ #define WIN_BASE_RES 128 #define WIN_BASE_KIND 128 /* * Commonly used characters */ #define CHAR_ENTER ((char) 3) #define CHAR_BELL ((char) 7) #define CHAR_BS ((char) 8) #define CHAR_LF ((char) 10) #define CHAR_CR ((char) 13) #define CHAR_ESC ((char) 27) #define CHAR_BLANK ((char) 32) #define CHAR_DELETE ((char) 127) extern char game_active; /* flag to window rendering routines not to use ppat */ /* * If you want some fancy operations that not a normal TTY device normally * supports, use EXTENDED_SUPPORT. For frames, area erases and area scrolls, * plus bitmap graphics - RESOLUTION DEPENDENT, be sure to call * get_tty_metrics and use those limits. */ #define EXTENDED_SUPPORT 0 /* * if you print a lot of single characters, accumulating each one in a * clipping region will take too much time. Instead, define this, which * will clip in rects. */ #define CLIP_RECT_ONLY 1 typedef enum tty_attrib { /* * Flags relating to the general functioning of the window. * These flags are passed at create_tty time, and changing them * later will clear the screen. */ TTY_ATTRIB_FLAGS, /* * When using proportional fonts, this will place each character * separately, ensuring aligned columns (but looking ugly and taking * time) */ #define TA_MOVE_EACH_CHAR 1L /* * This means draw each change as it occurs instead of collecting the area * and draw it all at once at update_tty() - slower, but more reliable. */ #define TA_ALWAYS_REFRESH 2L /* * When reaching the right end, we either just stop drawing, or wrap to the * next line. */ #define TA_WRAP_AROUND 4L /* * Overstrike means that characters are added on top of each other; i e don't * clear the letter beneath. This is faster, using srcOr under QuickDraw */ #define TA_OVERSTRIKE 8L /* * We may want the window not to scroll when we reach the end line, * but stop drawing instead. */ #define TA_INHIBIT_VERT_SCROLL 16L /* * Foreground and background colors. These only affect characters * drawn by subsequent calls; not what's already there (but it does * affect clears) * On b/w screens these do nothing. */ TTY_ATTRIB_FOREGROUND, TTY_ATTRIB_BACKGROUND, #define TA_RGB_TO_TTY(r) \ ((((long) ((r).red >> 8) & 0xff) << 16) \ + (((long) ((r).green >> 8) & 0xff) << 8) \ + ((long) ((r).blue >> 8) & 0xff)) /* * Attributes relating to the cursor, and character set mappings */ TTY_ATTRIB_CURSOR, /* * Blinking cursor is more noticeable when it's idle */ #define TA_BLINKING_CURSOR 1L /* * When handling input, do we echo characters as they are typed? */ #define TA_ECHO_INPUT 2L /* * Do we return each character code separately, or map delete etc? Note * that non-raw input means getchar won't return anything until the user * has typed a return. */ #define TA_RAW_INPUT 4L /* * Do we print every character as it is (including BS, NL and CR!) or do * do we interpret characters such as NL, BS and CR? */ #define TA_RAW_OUTPUT 8L /* * When getting a NL, do we also move to the left? */ #define TA_NL_ADD_CR 16L /* * When getting a CR, do we also move down? */ #define TA_CR_ADD_NL 32L /* * Wait for input or return what we've got? */ #define TA_NONBLOCKING_IO 64L /* * Use this macro to cast a function pointer to a tty attribute; this will * help portability to systems where a function pointer doesn't fit in a long */ #define TA_ATTRIB_FUNC(x) ((long) (x)) /* * This symbolic constant is used to check the number of attributes */ TTY_NUMBER_ATTRIBUTES } tty_attrib; /* * Character returned by end-of-file condition */ #define TTY_EOF -1 /* * Create the window according to a resource WIND template. * The window pointer pointed to by window should be NULL to * allocate the window record dynamically, or point to a * WindowRecord structure already allocated. * * Passing in_color means you have to be sure there's color support; * on the Mac, this means 32bit QuickDraw present, else it will * crash. Not passing in_color means everything's rendered in * black & white. */ extern short create_tty(WindowPtr *window, short resource_id, Boolean in_color); /* * Use init_tty_name or init_tty_number to initialize a window * once allocated by create_tty. Size parameters are in characters. */ extern short init_tty_number(WindowPtr window, short font_number, short font_size, short x_size, short y_size); /* * Close and deallocate a window and its data */ extern short destroy_tty(WindowPtr window); /* * Change the font and font size used in the window for drawing after * the calls are made. To change the coordinate system, be sure to call * force_tty_coordinate_system_recalc() - else it may look strange if * the new font doesn't match the old one. */ extern short set_tty_font_name(winid window_type, char *name); extern short force_tty_coordinate_system_recalc(WindowPtr window); /* * Getting some metrics about the tty and its drawing. */ extern short get_tty_metrics(WindowPtr window, short *x_size, short *y_size, short *x_size_pixels, short *y_size_pixels, short *font_number, short *font_size, short *char_width, short *row_height); /* * The basic move cursor function. 0,0 is topleft. */ extern short move_tty_cursor(WindowPtr window, short x_pos, short y_pos); /* * Flush all changes done to a tty to the screen (see TA_ALWAYS_UPDATE above) */ extern short update_tty(WindowPtr window); /* * Add a character to the tty and update the cursor position */ extern short add_tty_char(WindowPtr window, short character); /* * Add a string of characters to the tty and update the cursor * position. The string is 0-terminated! */ extern short add_tty_string(WindowPtr window, const char *string); /* * Change or read an attribute of the tty. Note that some attribute changes * may clear the screen. See the above enum and defines for values. * Attributes can be both function pointers and special flag values. */ extern short get_tty_attrib(WindowPtr window, tty_attrib attrib, long *value); extern short set_tty_attrib(WindowPtr window, tty_attrib attrib, long value); /* * Scroll the actual TTY image, in characters, positive means up/left * scroll_tty ( my_tty , 0 , 1 ) means a linefeed. Is always carried out * directly, regardless of the wait-update setting. Does updates before * scrolling. */ extern short scroll_tty(WindowPtr window, short delta_x, short delta_y); /* * Erase the offscreen bitmap and move the cursor to 0,0. Re-init some window * values (font etc) Is always carried out directly on-screen, regardless of * the wait-for-update setting. Clears update area. */ extern short clear_tty(WindowPtr window); /* * Call this routine with a window (always _mt_window) and a time (usually * from most recent event) to determine if cursor in window should be blinked */ extern short blink_cursor(WindowPtr window, long when); /* * For screen dumps, open the printer port and call this function. Can be used * for clipboard as well (only for a PICT, though; this library doesn't * concern * itself with characters, just bitmaps) */ extern short image_tty(EventRecord *theEvent, WindowPtr window); /* * For erasing just an area of characters */ extern short clear_tty_window(WindowPtr window, short from_row, short from_col, short to_row, short to_col); /* * get and set the invalid region of the main window */ extern short get_invalid_region(WindowPtr window, Rect *inval_rect); extern short set_invalid_region(WindowPtr window, Rect *inval_rect); /* * Now in macsnd.c, which seemed like a good place */ extern void tty_nhbell(); #if EXTENDED_SUPPORT /* * Various versions of delete character/s, insert line/s etc can be handled by * this general-purpose function. Negative num_ means delete, positive means * insert, and you can never be sure which of row and col operations come * first * if you specify both... */ extern short mangle_tty_rows_columns(WindowPtr window, short from_row, short num_rows, short from_col, short num_cols); /* * For framing an area without using grahpics characters. * Note that the given limits are those used for framing, you should not * draw in them. frame_fatness should typically be 1-5, and may be clipped * if it is too large. */ extern short frame_tty_window(WindowPtr window, short from_row, short from_col, short to_row, short to_col, short frame_fatness); /* * For inverting specific characters after the fact. May look funny in color. */ extern short invert_tty_window(WindowPtr window, short from_row, short from_col, short to_row, short to_col); /* * For drawing lines on the tty - VERY DEVICE DEPENDENT. Use get_tty_metrics. */ extern short draw_tty_line(WindowPtr window, short from_x, short from_y, short to_x, short to_y); #endif /* EXTENDED_SUPPORT */ #endif /* _H_tty_public */ nethack-3.6.0/include/macwin.h0000664000076400007660000001512412622603541015213 0ustar paxedpaxed/* NetHack 3.6 macwin.h $NHDT-Date: 1447755970 2015/11/17 10:26:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MACWIN_H #define MACWIN_H #undef red /* undef internal color const strings from decl */ #undef green #undef blue #ifndef __MACH__ #include #include #endif /* more headers */ #ifdef THINK_C #include /* for CtoPStr and PtoCStr */ #endif /* resources */ #define PLAYER_NAME_RES_ID 1001 /* fake some things if we don't have universal headers.. */ #if 0 /*ndef NewUserItemProc*/ typedef pascal void (*UserItemProcPtr)(WindowPtr theWindow, short itemNo); typedef UserItemProcPtr UserItemUPP; #define NewUserItemProc(p) (UserItemUPP)(p) typedef pascal void (*ControlActionProcPtr)(ControlHandle theControl, short partCode); typedef ControlActionProcPtr ControlActionUPP; #define NewControlActionProc(p) (ControlActionUPP)(p) typedef ModalFilterProcPtr ModalFilterUPP; #define DisposeRoutineDescriptor(p) #endif /* misc */ #ifdef __MWERKS__ #define ResumeProcPtr long /* for call to InitDialogs */ #endif /* working dirs structure */ typedef struct macdirs { Str32 dataName; short dataRefNum; long dataDirID; Str32 saveName; short saveRefNum; long saveDirID; Str32 levelName; short levelRefNum; long levelDirID; } MacDirs; typedef struct macflags { Bitfield(processes, 1); Bitfield(color, 1); Bitfield(folders, 1); Bitfield(tempMem, 1); Bitfield(help, 1); Bitfield(fsSpec, 1); Bitfield(trueType, 1); Bitfield(aux, 1); Bitfield(alias, 1); Bitfield(standardFile, 1); Bitfield(hasDebugger, 1); Bitfield(hasAE, 1); Bitfield(gotOpen, 1); } MacFlags; extern MacDirs theDirs; /* used in macfile.c */ extern MacFlags macFlags; /* * Mac windows */ #define NUM_MACWINDOWS 15 #define TEXT_BLOCK 512L /* Window constants */ #define kMapWindow 0 #define kStatusWindow 1 #define kMessageWindow 2 #define kTextWindow 3 #define kMenuWindow 4 #define kLastWindowKind kMenuWindow /* * This determines the minimum logical line length in text windows * That is; even if physical width is less, this is where line breaks * go at the minimum. 350 is about right for score lines with a * geneva 10 pt font. */ #define MIN_RIGHT 350 typedef struct { anything id; char accelerator; char groupAcc; short line; } MacMHMenuItem; typedef struct NhWindow { WindowPtr its_window; short font_number; short font_size; short char_width; short row_height; short ascent_height; short x_size; short y_size; short x_curs; short y_curs; short last_more_lin; /* Used by message window */ short save_lin; /* Used by message window */ short miSize; /* size of menu items arrays */ short miLen; /* number of menu items in array */ MacMHMenuItem **menuInfo; /* Used by menus (array handle) */ char menuChar; /* next menu accelerator to use */ short **menuSelected; /* list of selected elements from list */ short miSelLen; /* number of items selected */ short how; /* menu mode */ char drawn; Handle windowText; long windowTextLen; short scrollPos; ControlHandle scrollBar; } NhWindow; extern Boolean CheckNhWin(WindowPtr mac_win); #define NUM_STAT_ROWS 2 #define NUM_ROWS 22 #define NUM_COLS 80 /* We shouldn't use column 0 */ #define QUEUE_LEN 24 extern NhWindow *theWindows; extern struct window_procs mac_procs; #define NHW_BASE 0 extern winid BASE_WINDOW, WIN_MAP, WIN_MESSAGE, WIN_INVEN, WIN_STATUS; /* * External declarations for the window routines. */ #define E extern /* ### dprintf.c ### */ extern void dprintf(char *, ...); /* ### maccurs.c ### */ extern Boolean RetrievePosition(short, short *, short *); extern Boolean RetrieveSize(short, short, short, short *, short *); extern void SaveWindowPos(WindowPtr); extern void SaveWindowSize(WindowPtr); extern Boolean FDECL(RetrieveWinPos, (WindowPtr, short *, short *)); /* ### macerrs.c ### */ extern void showerror(char *, const char *); extern Boolean itworked(short); extern void mustwork(short); extern void attemptingto(char *); /* appear to be unused extern void comment(char *,long); extern void pushattemptingto(char *); extern void popattempt(void); */ /* ### macfile.c ### */ /* extern char *macgets(int fd, char *ptr, unsigned len); unused */ extern void FDECL(C2P, (const char *c, unsigned char *p)); extern void FDECL(P2C, (const unsigned char *p, char *c)); /* ### macmenu.c ### */ extern void DoMenuEvt(long); extern void InitMenuRes(void); extern void AdjustMenus(short); #define DimMenuBar() AdjustMenus(1) #define UndimMenuBar() AdjustMenus(0) /* ### macmain.c ### */ extern void FDECL(process_openfile, (short s_vol, long s_dir, Str255 fNm, OSType ft)); /* ### macwin.c ### */ extern void AddToKeyQueue(unsigned char, Boolean); extern unsigned char GetFromKeyQueue(void); void trans_num_keys(EventRecord *); extern void NDECL(InitMac); int FDECL(try_key_queue, (char *)); void FDECL(enter_topl_mode, (char *)); void FDECL(leave_topl_mode, (char *)); void FDECL(topl_set_resp, (char *, char)); Boolean FDECL(topl_key, (unsigned char, Boolean)); E void FDECL(HandleEvent, (EventRecord *)); /* used in mmodal.c */ extern void NDECL(port_help); extern Boolean small_screen; E void FDECL(mac_init_nhwindows, (int *, char **)); E void NDECL(mac_askname); E void NDECL(mac_get_nh_event); E void FDECL(mac_exit_nhwindows, (const char *)); E winid FDECL(mac_create_nhwindow, (int)); E void FDECL(mac_clear_nhwindow, (winid)); E void FDECL(mac_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(mac_destroy_nhwindow, (winid)); E void FDECL(mac_curs, (winid, int, int)); E void FDECL(mac_putstr, (winid, int, const char *)); E void FDECL(mac_start_menu, (winid)); E void FDECL(mac_add_menu, (winid, int, const anything *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); E void FDECL(mac_end_menu, (winid, const char *)); E int FDECL(mac_select_menu, (winid, int, menu_item **)); #ifdef CLIPPING E void FDECL(mac_cliparound, (int, int)); #endif E int NDECL(mac_nhgetch); E int FDECL(mac_nh_poskey, (int *, int *, int *)); E int NDECL(mac_doprev_message); E char FDECL(mac_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(mac_getlin, (const char *, char *)); E int NDECL(mac_get_ext_cmd); E void FDECL(mac_number_pad, (int)); E void NDECL(mac_delay_output); #undef E #endif /* ! MACWIN_H */ nethack-3.6.0/include/mail.h0000664000076400007660000000141212536476415014666 0ustar paxedpaxed/* NetHack 3.6 mail.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* NetHack may be freely redistributed. See license for details. */ /* used by ckmailstatus() to pass information to the mail-daemon in newmail() */ #ifndef MAIL_H #define MAIL_H #define MSG_OTHER 0 /* catch-all; none of the below... */ #define MSG_MAIL 1 /* unimportant, uninteresting mail message */ #define MSG_CALL 2 /* annoying phone/talk/chat-type interruption */ struct mail_info { int message_typ; /* MSG_foo value */ const char *display_txt; /* text for daemon to verbalize */ const char *object_nam; /* text to tag object with */ const char *response_cmd; /* command to eventually execute */ }; #endif /* MAIL_H */ nethack-3.6.0/include/mextra.h0000664000076400007660000001517312610522241015233 0ustar paxedpaxed/* NetHack 3.6 mextra.h $NHDT-Date: 1432512781 2015/05/25 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MEXTRA_H #define MEXTRA_H #ifndef ALIGN_H #include "align.h" #endif /* * Adding new mextra structures: * * 1. Add the structure definition and any required macros in this file * above the mextra struct. * 2. Add a pointer to your new struct to the mextra struct in this *file. * 3. Add a referencing macro at the bottom of this file after the *mextra * struct (see MNAME, EGD, EPRI, ESHK, EMIN, or EDOG for examples). * 4. Create a newXX(mtmp) function and possibly a free_XX(mtmp) *function * in an appropriate new or existing source file and add a prototype * for it to include/extern.h. * * void FDECL(newXX, (struct monst *)); * void FDECL(free_XX, (struct monst *)); * * void * newXX(mtmp) * struct monst *mtmp; * { * if (!mtmp->mextra) mtmp->mextra = newmextra(); * if (!XX(mtmp)) { * XX(mtmp) = (struct XX *)alloc(sizeof(struct XX)); * (void) memset((genericptr_t) XX(mtmp), * 0, sizeof(struct XX)); * } * } * * 5. Consider adding a new makemon flag MM_XX flag to include/hack.h *and * a corresponding change to makemon() if you require your structure * to be added at monster creation time. Initialize your struct * after a successful return from makemon(). * * src/makemon.c: if (mmflags & MM_XX) newXX(mtmp); * your new code: mon = makemon(&mons[mnum], x, y, MM_XX); * * 6. Adjust size_monst() in src/cmd.c appropriately. * 7. Adjust dealloc_mextra() in src/mon.c to clean up * properly during monst deallocation. * 8. Adjust copy_mextra() in src/mon.c to make duplicate * copies of your struct or data on another monst struct. * 9. Adjust restmon() in src/restore.c to deal with your * struct or data during a restore. * 10. Adjust savemon() in src/save.c to deal with your * struct or data during a save. */ /*** ** formerly vault.h -- vault guard extension */ #define FCSIZ (ROWNO + COLNO) #define GD_EATGOLD 0x01 #define GD_DESTROYGOLD 0x02 struct fakecorridor { xchar fx, fy, ftyp; }; struct egd { int fcbeg, fcend; /* fcend: first unused pos */ int vroom; /* room number of the vault */ xchar gdx, gdy; /* goal of guard's walk */ xchar ogx, ogy; /* guard's last position */ d_level gdlevel; /* level (& dungeon) guard was created in */ xchar warncnt; /* number of warnings to follow */ Bitfield(gddone, 1); /* true iff guard has released player */ Bitfield(witness, 2); /* the guard saw you do something */ Bitfield(unused, 5); struct fakecorridor fakecorr[FCSIZ]; }; /*** ** formerly epri.h -- temple priest extension */ struct epri { aligntyp shralign; /* alignment of priest's shrine */ schar shroom; /* index in rooms */ coord shrpos; /* position of shrine */ d_level shrlevel; /* level (& dungeon) of shrine */ long intone_time, /* used to limit verbosity +*/ enter_time, /*+ of temple entry messages */ hostile_time, /* forbidding feeling */ peaceful_time; /* sense of peace */ }; /* note: roaming priests (no shrine) switch from ispriest to isminion (and emin extension) */ /*** ** formerly eshk.h -- shopkeeper extension */ #define REPAIR_DELAY 5 /* minimum delay between shop damage & repair */ #define BILLSZ 200 struct bill_x { unsigned bo_id; boolean useup; long price; /* price per unit */ long bquan; /* amount used up */ }; struct eshk { long robbed; /* amount stolen by most recent customer */ long credit; /* amount credited to customer */ long debit; /* amount of debt for using unpaid items */ long loan; /* shop-gold picked (part of debit) */ int shoptype; /* the value of rooms[shoproom].rtype */ schar shoproom; /* index in rooms; set by inshop() */ schar unused; /* to force alignment for stupid compilers */ boolean following; /* following customer since he owes us sth */ boolean surcharge; /* angry shk inflates prices */ boolean dismiss_kops; /* pacified shk sends kops away */ coord shk; /* usual position shopkeeper */ coord shd; /* position shop door */ d_level shoplevel; /* level (& dungeon) of his shop */ int billct; /* no. of entries of bill[] in use */ struct bill_x bill[BILLSZ]; struct bill_x *bill_p; int visitct; /* nr of visits by most recent customer */ char customer[PL_NSIZ]; /* most recent customer */ char shknam[PL_NSIZ]; }; /*** ** formerly emin.h -- minion extension */ struct emin { aligntyp min_align; /* alignment of minion */ boolean renegade; /* hostile co-aligned priest or Angel */ }; /*** ** formerly edog.h -- pet extension */ /* various types of pet food, the lower, the better liked */ #define DOGFOOD 0 #define CADAVER 1 #define ACCFOOD 2 #define MANFOOD 3 #define APPORT 4 #define POISON 5 #define UNDEF 6 #define TABU 7 struct edog { long droptime; /* moment dog dropped object */ unsigned dropdist; /* dist of dropped obj from @ */ int apport; /* amount of training */ long whistletime; /* last time he whistled */ long hungrytime; /* will get hungry at this time */ coord ogoal; /* previous goal location */ int abuse; /* track abuses to this pet */ int revivals; /* count pet deaths */ int mhpmax_penalty; /* while starving, points reduced */ Bitfield(killed_by_u, 1); /* you attempted to kill him */ }; /*** ** mextra.h -- collection of all monster extensions */ struct mextra { char *mname; struct egd *egd; struct epri *epri; struct eshk *eshk; struct emin *emin; struct edog *edog; int mcorpsenm; /* obj->corpsenm for mimic posing as statue or corpse */ }; #define MNAME(mon) ((mon)->mextra->mname) #define EGD(mon) ((mon)->mextra->egd) #define EPRI(mon) ((mon)->mextra->epri) #define ESHK(mon) ((mon)->mextra->eshk) #define EMIN(mon) ((mon)->mextra->emin) #define EDOG(mon) ((mon)->mextra->edog) #define MCORPSENM(mon) ((mon)->mextra->mcorpsenm) #define has_mname(mon) ((mon)->mextra && MNAME(mon)) #define has_mcorpsenm(mon) ((mon)->mextra && MCORPSENM(mon) != NON_PM) #endif /* MEXTRA_H */ nethack-3.6.0/include/mfndpos.h0000664000076400007660000000254312536476415015420 0ustar paxedpaxed/* NetHack 3.6 mfndpos.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MFNDPOS_H #define MFNDPOS_H #define ALLOW_MDISP 0x00001000L /* can displace a monster out of its way */ #define ALLOW_TRAPS 0x00020000L /* can enter traps */ #define ALLOW_U 0x00040000L /* can attack you */ #define ALLOW_M 0x00080000L /* can attack other monsters */ #define ALLOW_TM 0x00100000L /* can attack tame monsters */ #define ALLOW_ALL (ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS) #define NOTONL 0x00200000L /* avoids direct line to player */ #define OPENDOOR 0x00400000L /* opens closed doors */ #define UNLOCKDOOR 0x00800000L /* unlocks locked doors */ #define BUSTDOOR 0x01000000L /* breaks any doors */ #define ALLOW_ROCK 0x02000000L /* pushes rocks */ #define ALLOW_WALL 0x04000000L /* walks thru walls */ #define ALLOW_DIG 0x08000000L /* digs */ #define ALLOW_BARS 0x10000000L /* may pass thru iron bars */ #define ALLOW_SANCT 0x20000000L /* enters temples */ #define ALLOW_SSM 0x40000000L /* ignores scare monster */ #ifdef NHSTDC #define NOGARLIC 0x80000000UL /* hates garlic */ #else #define NOGARLIC 0x80000000L /* hates garlic */ #endif #endif /* MFNDPOS_H */ nethack-3.6.0/include/micro.h0000664000076400007660000000103512536476415015056 0ustar paxedpaxed/* NetHack 3.6 micro.h $NHDT-Date: 1432512781 2015/05/25 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* micro.h - function declarations for various microcomputers */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MICRO_H #define MICRO_H extern const char *alllevels, *allbones; extern char levels[], bones[], permbones[], hackdir[]; extern int ramdisk; #ifndef C #define C(c) (0x1f & (c)) #endif #ifndef M #define M(c) (((char) 0x80) | (c)) #endif #define ABORT C('a') #endif /* MICRO_H */ nethack-3.6.0/include/mkroom.h0000664000076400007660000001067612536476415015264 0ustar paxedpaxed/* NetHack 3.6 mkroom.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MKROOM_H #define MKROOM_H /* mkroom.h - types and structures for room and shop initialization */ struct mkroom { schar lx, hx, ly, hy; /* usually xchar, but hx may be -1 */ schar rtype; /* type of room (zoo, throne, etc...) */ schar orig_rtype; /* same as rtype, but not zeroed later */ schar rlit; /* is the room lit ? */ schar needfill; /* sp_lev: does the room need filling? */ schar needjoining; /* sp_lev */ schar doorct; /* door count */ schar fdoor; /* index for the first door of the room */ schar nsubrooms; /* number of subrooms */ boolean irregular; /* true if room is non-rectangular */ struct mkroom *sbrooms[MAX_SUBROOMS]; /* Subrooms pointers */ struct monst *resident; /* priest/shopkeeper/guard for this room */ }; struct shclass { const char *name; /* name of the shop type */ char symb; /* this identifies the shop type */ int prob; /* the shop type probability in % */ schar shdist; /* object placement type */ #define D_SCATTER 0 /* normal placement */ #define D_SHOP 1 /* shop-like placement */ #define D_TEMPLE 2 /* temple-like placement */ struct itp { int iprob; /* probability of an item type */ int itype; /* item type: if >=0 a class, if < 0 a specific item */ } iprobs[6]; const char *const *shknms; /* list of shopkeeper names for this type */ }; extern NEARDATA struct mkroom rooms[(MAXNROFROOMS + 1) * 2]; extern NEARDATA struct mkroom *subrooms; /* the normal rooms on the current level are described in rooms[0..n] for * some n= rooms && (x) < rooms + MAXNROFROOMS) #define IS_ROOM_INDEX(x) ((x) >= 0 && (x) < MAXNROFROOMS) #define IS_SUBROOM_PTR(x) ((x) >= subrooms && (x) < subrooms + MAXNROFROOMS) #define IS_SUBROOM_INDEX(x) ((x) > MAXNROFROOMS && (x) < (MAXNROFROOMS * 2)) #define ROOM_INDEX(x) ((x) -rooms) #define SUBROOM_INDEX(x) ((x) -subrooms) #define IS_LAST_ROOM_PTR(x) (ROOM_INDEX(x) == nroom) #define IS_LAST_SUBROOM_PTR(x) (!nsubroom || SUBROOM_INDEX(x) == nsubroom) #endif /* MKROOM_H */ nethack-3.6.0/include/monattk.h0000664000076400007660000001003612536476415015423 0ustar paxedpaxed/* NetHack 3.6 monattk.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* NetHack may be freely redistributed. See license for details. */ /* Copyright 1988, M. Stephenson */ #ifndef MONATTK_H #define MONATTK_H /* Add new attack types below - ordering affects experience (exper.c). * Attacks > AT_BUTT are worth extra experience. */ #define AT_ANY (-1) /* fake attack; dmgtype_fromattack wildcard */ #define AT_NONE 0 /* passive monster (ex. acid blob) */ #define AT_CLAW 1 /* claw (punch, hit, etc.) */ #define AT_BITE 2 /* bite */ #define AT_KICK 3 /* kick */ #define AT_BUTT 4 /* head butt (ex. a unicorn) */ #define AT_TUCH 5 /* touches */ #define AT_STNG 6 /* sting */ #define AT_HUGS 7 /* crushing bearhug */ #define AT_SPIT 10 /* spits substance - ranged */ #define AT_ENGL 11 /* engulf (swallow or by a cloud) */ #define AT_BREA 12 /* breath - ranged */ #define AT_EXPL 13 /* explodes - proximity */ #define AT_BOOM 14 /* explodes when killed */ #define AT_GAZE 15 /* gaze - ranged */ #define AT_TENT 16 /* tentacles */ #define AT_WEAP 254 /* uses weapon */ #define AT_MAGC 255 /* uses magic spell(s) */ /* Add new damage types below. * * Note that 1-10 correspond to the types of attack used in buzz(). * Please don't disturb the order unless you rewrite the buzz() code. */ #define AD_ANY (-1) /* fake damage; attacktype_fordmg wildcard */ #define AD_PHYS 0 /* ordinary physical */ #define AD_MAGM 1 /* magic missiles */ #define AD_FIRE 2 /* fire damage */ #define AD_COLD 3 /* frost damage */ #define AD_SLEE 4 /* sleep ray */ #define AD_DISN 5 /* disintegration (death ray) */ #define AD_ELEC 6 /* shock damage */ #define AD_DRST 7 /* drains str (poison) */ #define AD_ACID 8 /* acid damage */ #define AD_SPC1 9 /* for extension of buzz() */ #define AD_SPC2 10 /* for extension of buzz() */ #define AD_BLND 11 /* blinds (yellow light) */ #define AD_STUN 12 /* stuns */ #define AD_SLOW 13 /* slows */ #define AD_PLYS 14 /* paralyses */ #define AD_DRLI 15 /* drains life levels (Vampire) */ #define AD_DREN 16 /* drains magic energy */ #define AD_LEGS 17 /* damages legs (xan) */ #define AD_STON 18 /* petrifies (Medusa, cockatrice) */ #define AD_STCK 19 /* sticks to you (mimic) */ #define AD_SGLD 20 /* steals gold (leppie) */ #define AD_SITM 21 /* steals item (nymphs) */ #define AD_SEDU 22 /* seduces & steals multiple items */ #define AD_TLPT 23 /* teleports you (Quantum Mech.) */ #define AD_RUST 24 /* rusts armour (Rust Monster)*/ #define AD_CONF 25 /* confuses (Umber Hulk) */ #define AD_DGST 26 /* digests opponent (trapper, etc.) */ #define AD_HEAL 27 /* heals opponent's wounds (nurse) */ #define AD_WRAP 28 /* special "stick" for eels */ #define AD_WERE 29 /* confers lycanthropy */ #define AD_DRDX 30 /* drains dexterity (quasit) */ #define AD_DRCO 31 /* drains constitution */ #define AD_DRIN 32 /* drains intelligence (mind flayer) */ #define AD_DISE 33 /* confers diseases */ #define AD_DCAY 34 /* decays organics (brown Pudding) */ #define AD_SSEX 35 /* Succubus seduction (extended) */ #define AD_HALU 36 /* causes hallucination */ #define AD_DETH 37 /* for Death only */ #define AD_PEST 38 /* for Pestilence only */ #define AD_FAMN 39 /* for Famine only */ #define AD_SLIM 40 /* turns you into green slime */ #define AD_ENCH 41 /* remove enchantment (disenchanter) */ #define AD_CORR 42 /* corrode armor (black pudding) */ #define AD_CLRC 240 /* random clerical spell */ #define AD_SPEL 241 /* random magic spell */ #define AD_RBRE 242 /* random breath weapon */ #define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */ #define AD_CURS 253 /* random curse (ex. gremlin) */ /* * Monster to monster attacks. When a monster attacks another (mattackm), * any or all of the following can be returned. See mattackm() for more * details. */ #define MM_MISS 0x0 /* aggressor missed */ #define MM_HIT 0x1 /* aggressor hit defender */ #define MM_DEF_DIED 0x2 /* defender died */ #define MM_AGR_DIED 0x4 /* aggressor died */ #endif /* MONATTK_H */ nethack-3.6.0/include/mondata.h0000664000076400007660000002515012540247410015356 0ustar paxedpaxed/* NetHack 3.6 mondata.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONDATA_H #define MONDATA_H #define verysmall(ptr) ((ptr)->msize < MZ_SMALL) #define bigmonst(ptr) ((ptr)->msize >= MZ_LARGE) #define pm_resistance(ptr, typ) (((ptr)->mresists & (typ)) != 0) #define resists_fire(mon) (((mon)->mintrinsics & MR_FIRE) != 0) #define resists_cold(mon) (((mon)->mintrinsics & MR_COLD) != 0) #define resists_sleep(mon) (((mon)->mintrinsics & MR_SLEEP) != 0) #define resists_disint(mon) (((mon)->mintrinsics & MR_DISINT) != 0) #define resists_elec(mon) (((mon)->mintrinsics & MR_ELEC) != 0) #define resists_poison(mon) (((mon)->mintrinsics & MR_POISON) != 0) #define resists_acid(mon) (((mon)->mintrinsics & MR_ACID) != 0) #define resists_ston(mon) (((mon)->mintrinsics & MR_STONE) != 0) #define is_lminion(mon) \ (is_minion((mon)->data) && mon_aligntyp(mon) == A_LAWFUL) #define is_flyer(ptr) (((ptr)->mflags1 & M1_FLY) != 0L) #define is_floater(ptr) ((ptr)->mlet == S_EYE || (ptr)->mlet == S_LIGHT) #define is_clinger(ptr) (((ptr)->mflags1 & M1_CLING) != 0L) #define is_swimmer(ptr) (((ptr)->mflags1 & M1_SWIM) != 0L) #define breathless(ptr) (((ptr)->mflags1 & M1_BREATHLESS) != 0L) #define amphibious(ptr) \ (((ptr)->mflags1 & (M1_AMPHIBIOUS | M1_BREATHLESS)) != 0L) #define passes_walls(ptr) (((ptr)->mflags1 & M1_WALLWALK) != 0L) #define amorphous(ptr) (((ptr)->mflags1 & M1_AMORPHOUS) != 0L) #define noncorporeal(ptr) ((ptr)->mlet == S_GHOST) #define tunnels(ptr) (((ptr)->mflags1 & M1_TUNNEL) != 0L) #define needspick(ptr) (((ptr)->mflags1 & M1_NEEDPICK) != 0L) #define hides_under(ptr) (((ptr)->mflags1 & M1_CONCEAL) != 0L) #define is_hider(ptr) (((ptr)->mflags1 & M1_HIDE) != 0L) #define haseyes(ptr) (((ptr)->mflags1 & M1_NOEYES) == 0L) #define eyecount(ptr) \ (!haseyes(ptr) ? 0 : ((ptr) == &mons[PM_CYCLOPS] \ || (ptr) == &mons[PM_FLOATING_EYE]) \ ? 1 \ : 2) #define nohands(ptr) (((ptr)->mflags1 & M1_NOHANDS) != 0L) #define nolimbs(ptr) (((ptr)->mflags1 & M1_NOLIMBS) == M1_NOLIMBS) #define notake(ptr) (((ptr)->mflags1 & M1_NOTAKE) != 0L) #define has_head(ptr) (((ptr)->mflags1 & M1_NOHEAD) == 0L) #define has_horns(ptr) (num_horns(ptr) > 0) #define is_whirly(ptr) \ ((ptr)->mlet == S_VORTEX || (ptr) == &mons[PM_AIR_ELEMENTAL]) #define flaming(ptr) \ ((ptr) == &mons[PM_FIRE_VORTEX] || (ptr) == &mons[PM_FLAMING_SPHERE] \ || (ptr) == &mons[PM_FIRE_ELEMENTAL] || (ptr) == &mons[PM_SALAMANDER]) #define is_silent(ptr) ((ptr)->msound == MS_SILENT) #define unsolid(ptr) (((ptr)->mflags1 & M1_UNSOLID) != 0L) #define mindless(ptr) (((ptr)->mflags1 & M1_MINDLESS) != 0L) #define humanoid(ptr) (((ptr)->mflags1 & M1_HUMANOID) != 0L) #define is_animal(ptr) (((ptr)->mflags1 & M1_ANIMAL) != 0L) #define slithy(ptr) (((ptr)->mflags1 & M1_SLITHY) != 0L) #define is_wooden(ptr) ((ptr) == &mons[PM_WOOD_GOLEM]) #define thick_skinned(ptr) (((ptr)->mflags1 & M1_THICK_HIDE) != 0L) #define slimeproof(ptr) \ ((ptr) == &mons[PM_GREEN_SLIME] || flaming(ptr) || noncorporeal(ptr)) #define lays_eggs(ptr) (((ptr)->mflags1 & M1_OVIPAROUS) != 0L) #define regenerates(ptr) (((ptr)->mflags1 & M1_REGEN) != 0L) #define perceives(ptr) (((ptr)->mflags1 & M1_SEE_INVIS) != 0L) #define can_teleport(ptr) (((ptr)->mflags1 & M1_TPORT) != 0L) #define control_teleport(ptr) (((ptr)->mflags1 & M1_TPORT_CNTRL) != 0L) #define telepathic(ptr) \ ((ptr) == &mons[PM_FLOATING_EYE] || (ptr) == &mons[PM_MIND_FLAYER] \ || (ptr) == &mons[PM_MASTER_MIND_FLAYER]) #define is_armed(ptr) attacktype(ptr, AT_WEAP) #define acidic(ptr) (((ptr)->mflags1 & M1_ACID) != 0L) #define poisonous(ptr) (((ptr)->mflags1 & M1_POIS) != 0L) #define carnivorous(ptr) (((ptr)->mflags1 & M1_CARNIVORE) != 0L) #define herbivorous(ptr) (((ptr)->mflags1 & M1_HERBIVORE) != 0L) #define metallivorous(ptr) (((ptr)->mflags1 & M1_METALLIVORE) != 0L) #define polyok(ptr) (((ptr)->mflags2 & M2_NOPOLY) == 0L) #define is_shapeshifter(ptr) (((ptr)->mflags2 & M2_SHAPESHIFTER) != 0L) #define is_undead(ptr) (((ptr)->mflags2 & M2_UNDEAD) != 0L) #define is_were(ptr) (((ptr)->mflags2 & M2_WERE) != 0L) #define is_elf(ptr) (((ptr)->mflags2 & M2_ELF) != 0L) #define is_dwarf(ptr) (((ptr)->mflags2 & M2_DWARF) != 0L) #define is_gnome(ptr) (((ptr)->mflags2 & M2_GNOME) != 0L) #define is_orc(ptr) (((ptr)->mflags2 & M2_ORC) != 0L) #define is_human(ptr) (((ptr)->mflags2 & M2_HUMAN) != 0L) #define your_race(ptr) (((ptr)->mflags2 & urace.selfmask) != 0L) #define is_bat(ptr) \ ((ptr) == &mons[PM_BAT] || (ptr) == &mons[PM_GIANT_BAT] \ || (ptr) == &mons[PM_VAMPIRE_BAT]) #define is_bird(ptr) ((ptr)->mlet == S_BAT && !is_bat(ptr)) #define is_giant(ptr) (((ptr)->mflags2 & M2_GIANT) != 0L) #define is_golem(ptr) ((ptr)->mlet == S_GOLEM) #define is_domestic(ptr) (((ptr)->mflags2 & M2_DOMESTIC) != 0L) #define is_demon(ptr) (((ptr)->mflags2 & M2_DEMON) != 0L) #define is_mercenary(ptr) (((ptr)->mflags2 & M2_MERC) != 0L) #define is_male(ptr) (((ptr)->mflags2 & M2_MALE) != 0L) #define is_female(ptr) (((ptr)->mflags2 & M2_FEMALE) != 0L) #define is_neuter(ptr) (((ptr)->mflags2 & M2_NEUTER) != 0L) #define is_wanderer(ptr) (((ptr)->mflags2 & M2_WANDER) != 0L) #define always_hostile(ptr) (((ptr)->mflags2 & M2_HOSTILE) != 0L) #define always_peaceful(ptr) (((ptr)->mflags2 & M2_PEACEFUL) != 0L) #define race_hostile(ptr) (((ptr)->mflags2 & urace.hatemask) != 0L) #define race_peaceful(ptr) (((ptr)->mflags2 & urace.lovemask) != 0L) #define extra_nasty(ptr) (((ptr)->mflags2 & M2_NASTY) != 0L) #define strongmonst(ptr) (((ptr)->mflags2 & M2_STRONG) != 0L) #define can_breathe(ptr) attacktype(ptr, AT_BREA) #define cantwield(ptr) (nohands(ptr) || verysmall(ptr)) #define could_twoweap(ptr) ((ptr)->mattk[1].aatyp == AT_WEAP) #define cantweararm(ptr) (breakarm(ptr) || sliparm(ptr)) #define throws_rocks(ptr) (((ptr)->mflags2 & M2_ROCKTHROW) != 0L) #define type_is_pname(ptr) (((ptr)->mflags2 & M2_PNAME) != 0L) #define is_lord(ptr) (((ptr)->mflags2 & M2_LORD) != 0L) #define is_prince(ptr) (((ptr)->mflags2 & M2_PRINCE) != 0L) #define is_ndemon(ptr) \ (is_demon(ptr) && (((ptr)->mflags2 & (M2_LORD | M2_PRINCE)) == 0L)) #define is_dlord(ptr) (is_demon(ptr) && is_lord(ptr)) #define is_dprince(ptr) (is_demon(ptr) && is_prince(ptr)) #define is_minion(ptr) (((ptr)->mflags2 & M2_MINION) != 0L) #define likes_gold(ptr) (((ptr)->mflags2 & M2_GREEDY) != 0L) #define likes_gems(ptr) (((ptr)->mflags2 & M2_JEWELS) != 0L) #define likes_objs(ptr) (((ptr)->mflags2 & M2_COLLECT) != 0L || is_armed(ptr)) #define likes_magic(ptr) (((ptr)->mflags2 & M2_MAGIC) != 0L) #define webmaker(ptr) \ ((ptr) == &mons[PM_CAVE_SPIDER] || (ptr) == &mons[PM_GIANT_SPIDER]) #define is_unicorn(ptr) ((ptr)->mlet == S_UNICORN && likes_gems(ptr)) #define is_longworm(ptr) \ (((ptr) == &mons[PM_BABY_LONG_WORM]) || ((ptr) == &mons[PM_LONG_WORM]) \ || ((ptr) == &mons[PM_LONG_WORM_TAIL])) #define is_covetous(ptr) ((ptr->mflags3 & M3_COVETOUS)) #define infravision(ptr) ((ptr->mflags3 & M3_INFRAVISION)) #define infravisible(ptr) ((ptr->mflags3 & M3_INFRAVISIBLE)) #define is_displacer(ptr) (((ptr)->mflags3 & M3_DISPLACES) != 0L) #define is_mplayer(ptr) \ (((ptr) >= &mons[PM_ARCHEOLOGIST]) && ((ptr) <= &mons[PM_WIZARD])) #define is_watch(ptr) \ ((ptr) == &mons[PM_WATCHMAN] || (ptr) == &mons[PM_WATCH_CAPTAIN]) #define is_rider(ptr) \ ((ptr) == &mons[PM_DEATH] || (ptr) == &mons[PM_FAMINE] \ || (ptr) == &mons[PM_PESTILENCE]) #define is_placeholder(ptr) \ ((ptr) == &mons[PM_ORC] || (ptr) == &mons[PM_GIANT] \ || (ptr) == &mons[PM_ELF] || (ptr) == &mons[PM_HUMAN]) /* return TRUE if the monster tends to revive */ #define is_reviver(ptr) (is_rider(ptr) || (ptr)->mlet == S_TROLL) /* monsters whose corpses and statues need special handling; note that high priests and the Wizard of Yendor are flagged as unique even though they really aren't; that's ok here */ #define unique_corpstat(ptr) (((ptr)->geno & G_UNIQ) != 0) /* this returns the light's range, or 0 if none; if we add more light emitting monsters, we'll likely have to add a new light range field to mons[] */ #define emits_light(ptr) \ (((ptr)->mlet == S_LIGHT || (ptr) == &mons[PM_FLAMING_SPHERE] \ || (ptr) == &mons[PM_SHOCKING_SPHERE] \ || (ptr) == &mons[PM_FIRE_VORTEX]) \ ? 1 \ : ((ptr) == &mons[PM_FIRE_ELEMENTAL]) ? 1 : 0) /* [note: the light ranges above were reduced to 1 for performance...] */ #define likes_lava(ptr) \ (ptr == &mons[PM_FIRE_ELEMENTAL] || ptr == &mons[PM_SALAMANDER]) #define pm_invisible(ptr) \ ((ptr) == &mons[PM_STALKER] || (ptr) == &mons[PM_BLACK_LIGHT]) /* could probably add more */ #define likes_fire(ptr) \ ((ptr) == &mons[PM_FIRE_VORTEX] || (ptr) == &mons[PM_FLAMING_SPHERE] \ || likes_lava(ptr)) #define touch_petrifies(ptr) \ ((ptr) == &mons[PM_COCKATRICE] || (ptr) == &mons[PM_CHICKATRICE]) #define is_mind_flayer(ptr) \ ((ptr) == &mons[PM_MIND_FLAYER] || (ptr) == &mons[PM_MASTER_MIND_FLAYER]) #define is_vampire(ptr) ((ptr)->mlet == S_VAMPIRE) #define nonliving(ptr) \ (is_golem(ptr) || is_undead(ptr) || (ptr)->mlet == S_VORTEX \ || (ptr) == &mons[PM_MANES]) /* Used for conduct with corpses, tins, and digestion attacks */ /* G_NOCORPSE monsters might still be swallowed as a purple worm */ /* Maybe someday this could be in mflags... */ #define vegan(ptr) \ ((ptr)->mlet == S_BLOB || (ptr)->mlet == S_JELLY \ || (ptr)->mlet == S_FUNGUS || (ptr)->mlet == S_VORTEX \ || (ptr)->mlet == S_LIGHT \ || ((ptr)->mlet == S_ELEMENTAL && (ptr) != &mons[PM_STALKER]) \ || ((ptr)->mlet == S_GOLEM && (ptr) != &mons[PM_FLESH_GOLEM] \ && (ptr) != &mons[PM_LEATHER_GOLEM]) || noncorporeal(ptr)) #define vegetarian(ptr) \ (vegan(ptr) \ || ((ptr)->mlet == S_PUDDING && (ptr) != &mons[PM_BLACK_PUDDING])) #define befriend_with_obj(ptr, obj) \ ((obj)->oclass == FOOD_CLASS && is_domestic(ptr)) #endif /* MONDATA_H */ nethack-3.6.0/include/monflag.h0000664000076400007660000002312612536476415015375 0ustar paxedpaxed/* NetHack 3.6 monflag.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONFLAG_H #define MONFLAG_H #define MS_SILENT 0 /* makes no sound */ #define MS_BARK 1 /* if full moon, may howl */ #define MS_MEW 2 /* mews or hisses */ #define MS_ROAR 3 /* roars */ #define MS_GROWL 4 /* growls */ #define MS_SQEEK 5 /* squeaks, as a rodent */ #define MS_SQAWK 6 /* squawks, as a bird */ #define MS_HISS 7 /* hisses */ #define MS_BUZZ 8 /* buzzes (killer bee) */ #define MS_GRUNT 9 /* grunts (or speaks own language) */ #define MS_NEIGH 10 /* neighs, as an equine */ #define MS_WAIL 11 /* wails, as a tortured soul */ #define MS_GURGLE 12 /* gurgles, as liquid or through saliva */ #define MS_BURBLE 13 /* burbles (jabberwock) */ #define MS_ANIMAL 13 /* up to here are animal noises */ #define MS_SHRIEK 15 /* wakes up others */ #define MS_BONES 16 /* rattles bones (skeleton) */ #define MS_LAUGH 17 /* grins, smiles, giggles, and laughs */ #define MS_MUMBLE 18 /* says something or other */ #define MS_IMITATE 19 /* imitates others (leocrotta) */ #define MS_ORC MS_GRUNT /* intelligent brutes */ #define MS_HUMANOID 20 /* generic traveling companion */ #define MS_ARREST 21 /* "Stop in the name of the law!" (Kops) */ #define MS_SOLDIER 22 /* army and watchmen expressions */ #define MS_GUARD 23 /* "Please drop that gold and follow me." */ #define MS_DJINNI 24 /* "Thank you for freeing me!" */ #define MS_NURSE 25 /* "Take off your shirt, please." */ #define MS_SEDUCE 26 /* "Hello, sailor." (Nymphs) */ #define MS_VAMPIRE 27 /* vampiric seduction, Vlad's exclamations */ #define MS_BRIBE 28 /* asks for money, or berates you */ #define MS_CUSS 29 /* berates (demons) or intimidates (Wiz) */ #define MS_RIDER 30 /* astral level special monsters */ #define MS_LEADER 31 /* your class leader */ #define MS_NEMESIS 32 /* your nemesis */ #define MS_GUARDIAN 33 /* your leader's guards */ #define MS_SELL 34 /* demand payment, complain about shoplifters */ #define MS_ORACLE 35 /* do a consultation */ #define MS_PRIEST 36 /* ask for contribution; do cleansing */ #define MS_SPELL 37 /* spellcaster not matching any of the above */ #define MS_WERE 38 /* lycanthrope in human form */ #define MS_BOAST 39 /* giants */ #define MR_FIRE 0x01 /* resists fire */ #define MR_COLD 0x02 /* resists cold */ #define MR_SLEEP 0x04 /* resists sleep */ #define MR_DISINT 0x08 /* resists disintegration */ #define MR_ELEC 0x10 /* resists electricity */ #define MR_POISON 0x20 /* resists poison */ #define MR_ACID 0x40 /* resists acid */ #define MR_STONE 0x80 /* resists petrification */ /* other resistances: magic, sickness */ /* other conveyances: teleport, teleport control, telepathy */ /* individual resistances */ #define MR2_SEE_INVIS 0x0100 /* see invisible */ #define MR2_LEVITATE 0x0200 /* levitation */ #define MR2_WATERWALK 0x0400 /* water walking */ #define MR2_MAGBREATH 0x0800 /* magical breathing */ #define MR2_DISPLACED 0x1000 /* displaced */ #define MR2_STRENGTH 0x2000 /* gauntlets of power */ #define MR2_FUMBLING 0x4000 /* clumsy */ #define M1_FLY 0x00000001L /* can fly or float */ #define M1_SWIM 0x00000002L /* can traverse water */ #define M1_AMORPHOUS 0x00000004L /* can flow under doors */ #define M1_WALLWALK 0x00000008L /* can phase thru rock */ #define M1_CLING 0x00000010L /* can cling to ceiling */ #define M1_TUNNEL 0x00000020L /* can tunnel thru rock */ #define M1_NEEDPICK 0x00000040L /* needs pick to tunnel */ #define M1_CONCEAL 0x00000080L /* hides under objects */ #define M1_HIDE 0x00000100L /* mimics, blends in with ceiling */ #define M1_AMPHIBIOUS 0x00000200L /* can survive underwater */ #define M1_BREATHLESS 0x00000400L /* doesn't need to breathe */ #define M1_NOTAKE 0x00000800L /* cannot pick up objects */ #define M1_NOEYES 0x00001000L /* no eyes to gaze into or blind */ #define M1_NOHANDS 0x00002000L /* no hands to handle things */ #define M1_NOLIMBS 0x00006000L /* no arms/legs to kick/wear on */ #define M1_NOHEAD 0x00008000L /* no head to behead */ #define M1_MINDLESS 0x00010000L /* has no mind--golem, zombie, mold */ #define M1_HUMANOID 0x00020000L /* has humanoid head/arms/torso */ #define M1_ANIMAL 0x00040000L /* has animal body */ #define M1_SLITHY 0x00080000L /* has serpent body */ #define M1_UNSOLID 0x00100000L /* has no solid or liquid body */ #define M1_THICK_HIDE 0x00200000L /* has thick hide or scales */ #define M1_OVIPAROUS 0x00400000L /* can lay eggs */ #define M1_REGEN 0x00800000L /* regenerates hit points */ #define M1_SEE_INVIS 0x01000000L /* can see invisible creatures */ #define M1_TPORT 0x02000000L /* can teleport */ #define M1_TPORT_CNTRL 0x04000000L /* controls where it teleports to */ #define M1_ACID 0x08000000L /* acidic to eat */ #define M1_POIS 0x10000000L /* poisonous to eat */ #define M1_CARNIVORE 0x20000000L /* eats corpses */ #define M1_HERBIVORE 0x40000000L /* eats fruits */ #define M1_OMNIVORE 0x60000000L /* eats both */ #ifdef NHSTDC #define M1_METALLIVORE 0x80000000UL /* eats metal */ #else #define M1_METALLIVORE 0x80000000L /* eats metal */ #endif #define M2_NOPOLY 0x00000001L /* players mayn't poly into one */ #define M2_UNDEAD 0x00000002L /* is walking dead */ #define M2_WERE 0x00000004L /* is a lycanthrope */ #define M2_HUMAN 0x00000008L /* is a human */ #define M2_ELF 0x00000010L /* is an elf */ #define M2_DWARF 0x00000020L /* is a dwarf */ #define M2_GNOME 0x00000040L /* is a gnome */ #define M2_ORC 0x00000080L /* is an orc */ #define M2_DEMON 0x00000100L /* is a demon */ #define M2_MERC 0x00000200L /* is a guard or soldier */ #define M2_LORD 0x00000400L /* is a lord to its kind */ #define M2_PRINCE 0x00000800L /* is an overlord to its kind */ #define M2_MINION 0x00001000L /* is a minion of a deity */ #define M2_GIANT 0x00002000L /* is a giant */ #define M2_SHAPESHIFTER 0x00004000L /* is a shapeshifting species */ #define M2_MALE 0x00010000L /* always male */ #define M2_FEMALE 0x00020000L /* always female */ #define M2_NEUTER 0x00040000L /* neither male nor female */ #define M2_PNAME 0x00080000L /* monster name is a proper name */ #define M2_HOSTILE 0x00100000L /* always starts hostile */ #define M2_PEACEFUL 0x00200000L /* always starts peaceful */ #define M2_DOMESTIC 0x00400000L /* can be tamed by feeding */ #define M2_WANDER 0x00800000L /* wanders randomly */ #define M2_STALK 0x01000000L /* follows you to other levels */ #define M2_NASTY 0x02000000L /* extra-nasty monster (more xp) */ #define M2_STRONG 0x04000000L /* strong (or big) monster */ #define M2_ROCKTHROW 0x08000000L /* throws boulders */ #define M2_GREEDY 0x10000000L /* likes gold */ #define M2_JEWELS 0x20000000L /* likes gems */ #define M2_COLLECT 0x40000000L /* picks up weapons and food */ #ifdef NHSTDC #define M2_MAGIC 0x80000000UL /* picks up magic items */ #else #define M2_MAGIC 0x80000000L /* picks up magic items */ #endif #define M3_WANTSAMUL 0x0001 /* would like to steal the amulet */ #define M3_WANTSBELL 0x0002 /* wants the bell */ #define M3_WANTSBOOK 0x0004 /* wants the book */ #define M3_WANTSCAND 0x0008 /* wants the candelabrum */ #define M3_WANTSARTI 0x0010 /* wants the quest artifact */ #define M3_WANTSALL 0x001f /* wants any major artifact */ #define M3_WAITFORU 0x0040 /* waits to see you or get attacked */ #define M3_CLOSE 0x0080 /* lets you close unless attacked */ #define M3_COVETOUS 0x001f /* wants something */ #define M3_WAITMASK 0x00c0 /* waiting... */ /* Infravision is currently implemented for players only */ #define M3_INFRAVISION 0x0100 /* has infravision */ #define M3_INFRAVISIBLE 0x0200 /* visible by infravision */ #define M3_DISPLACES 0x0400 /* moves monsters out of its way */ #define MZ_TINY 0 /* < 2' */ #define MZ_SMALL 1 /* 2-4' */ #define MZ_MEDIUM 2 /* 4-7' */ #define MZ_HUMAN MZ_MEDIUM /* human-sized */ #define MZ_LARGE 3 /* 7-12' */ #define MZ_HUGE 4 /* 12-25' */ #define MZ_GIGANTIC 7 /* off the scale */ /* Monster races -- must stay within ROLE_RACEMASK */ /* Eventually this may become its own field */ #define MH_HUMAN M2_HUMAN #define MH_ELF M2_ELF #define MH_DWARF M2_DWARF #define MH_GNOME M2_GNOME #define MH_ORC M2_ORC /* for mons[].geno (constant during game) */ #define G_UNIQ 0x1000 /* generated only once */ #define G_NOHELL 0x0800 /* not generated in "hell" */ #define G_HELL 0x0400 /* generated only in "hell" */ #define G_NOGEN 0x0200 /* generated only specially */ #define G_SGROUP 0x0080 /* appear in small groups normally */ #define G_LGROUP 0x0040 /* appear in large groups normally */ #define G_GENO 0x0020 /* can be genocided */ #define G_NOCORPSE 0x0010 /* no corpse left ever */ #define G_FREQ 0x0007 /* creation frequency mask */ /* for mvitals[].mvflags (variant during game), along with G_NOCORPSE */ #define G_KNOWN 0x0004 /* have been encountered */ #define G_GONE (G_GENOD | G_EXTINCT) #define G_GENOD 0x0002 /* have been genocided */ #define G_EXTINCT \ 0x0001 /* have been extinguished as \ population control */ #define MV_KNOWS_EGG \ 0x0008 /* player recognizes egg of this \ monster type */ #endif /* MONFLAG_H */ nethack-3.6.0/include/monst.h0000664000076400007660000001511012610726721015073 0ustar paxedpaxed/* NetHack 3.6 monst.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONST_H #define MONST_H /* The weapon_check flag is used two ways: * 1) When calling mon_wield_item, is 2-6 depending on what is desired. * 2) Between calls to mon_wield_item, is 0 or 1 depending on whether or not * the weapon is known by the monster to be cursed (so it shouldn't bother * trying for another weapon). * I originally planned to also use 0 if the monster already had its best * weapon, to avoid the overhead of a call to mon_wield_item, but it turns out * that there are enough situations which might make a monster change its * weapon that this is impractical. --KAA */ #define NO_WEAPON_WANTED 0 #define NEED_WEAPON 1 #define NEED_RANGED_WEAPON 2 #define NEED_HTH_WEAPON 3 #define NEED_PICK_AXE 4 #define NEED_AXE 5 #define NEED_PICK_OR_AXE 6 /* The following flags are used for the second argument to display_minventory * in invent.c: * * MINV_NOLET If set, don't display inventory letters on monster's inventory. * MINV_ALL If set, display all items in monster's inventory, otherwise * just display wielded weapons and worn items. */ #define MINV_NOLET 0x01 #define MINV_ALL 0x02 #ifndef MEXTRA_H #include "mextra.h" #endif struct monst { struct monst *nmon; struct permonst *data; unsigned m_id; short mnum; /* permanent monster index number */ short cham; /* if shapeshifter, orig mons[] idx goes here */ short movement; /* movement points (derived from permonst definition and added effects */ uchar m_lev; /* adjusted difficulty level of monster */ aligntyp malign; /* alignment of this monster, relative to the player (positive = good to kill) */ xchar mx, my; xchar mux, muy; /* where the monster thinks you are */ #define MTSZ 4 coord mtrack[MTSZ]; /* monster track */ int mhp, mhpmax; unsigned mappearance; /* for undetected mimics and the wiz */ uchar m_ap_type; /* what mappearance is describing: */ #define M_AP_NOTHING \ 0 /* mappearance is unused -- monster appears \ as itself */ #define M_AP_FURNITURE 1 /* stairs, a door, an altar, etc. */ #define M_AP_OBJECT 2 /* an object */ #define M_AP_MONSTER 3 /* a monster */ schar mtame; /* level of tameness, implies peaceful */ unsigned short mintrinsics; /* low 8 correspond to mresists */ int mspec_used; /* monster's special ability attack timeout */ Bitfield(female, 1); /* is female */ Bitfield(minvis, 1); /* currently invisible */ Bitfield(invis_blkd, 1); /* invisibility blocked */ Bitfield(perminvis, 1); /* intrinsic minvis value */ Bitfield(mcan, 1); /* has been cancelled */ Bitfield(mburied, 1); /* has been buried */ Bitfield(mundetected, 1); /* not seen in present hiding place */ /* implies one of M1_CONCEAL or M1_HIDE, * but not mimic (that is, snake, spider, * trapper, piercer, eel) */ Bitfield(mcansee, 1); /* cansee 1, temp.blinded 0, blind 0 */ Bitfield(mspeed, 2); /* current speed */ Bitfield(permspeed, 2); /* intrinsic mspeed value */ Bitfield(mrevived, 1); /* has been revived from the dead */ Bitfield(mcloned, 1); /* has been cloned from another */ Bitfield(mavenge, 1); /* did something to deserve retaliation */ Bitfield(mflee, 1); /* fleeing */ Bitfield(mfleetim, 7); /* timeout for mflee */ Bitfield(msleeping, 1); /* asleep until woken */ Bitfield(mblinded, 7); /* cansee 0, temp.blinded n, blind 0 */ Bitfield(mstun, 1); /* stunned (off balance) */ Bitfield(mfrozen, 7); Bitfield(mcanmove, 1); /* paralysis, similar to mblinded */ Bitfield(mconf, 1); /* confused */ Bitfield(mpeaceful, 1); /* does not attack unprovoked */ Bitfield(mtrapped, 1); /* trapped in a pit, web or bear trap */ Bitfield(mleashed, 1); /* monster is on a leash */ Bitfield(isshk, 1); /* is shopkeeper */ Bitfield(isminion, 1); /* is a minion */ Bitfield(isgd, 1); /* is guard */ Bitfield(ispriest, 1); /* is a priest */ Bitfield(iswiz, 1); /* is the Wizard of Yendor */ Bitfield(wormno, 5); /* at most 31 worms on any level */ /* 2 free bits */ #define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */ unsigned long mstrategy; /* for monsters with mflag3: current strategy */ #ifdef NHSTDC #define STRAT_APPEARMSG 0x80000000UL #else #define STRAT_APPEARMSG 0x80000000L #endif #define STRAT_ARRIVE 0x40000000L /* just arrived on current level */ #define STRAT_WAITFORU 0x20000000L #define STRAT_CLOSE 0x10000000L #define STRAT_WAITMASK (STRAT_CLOSE | STRAT_WAITFORU) #define STRAT_HEAL 0x08000000L #define STRAT_GROUND 0x04000000L #define STRAT_MONSTR 0x02000000L #define STRAT_PLAYER 0x01000000L #define STRAT_NONE 0x00000000L #define STRAT_STRATMASK 0x0f000000L #define STRAT_XMASK 0x00ff0000L #define STRAT_YMASK 0x0000ff00L #define STRAT_GOAL 0x000000ffL #define STRAT_GOALX(s) ((xchar)((s & STRAT_XMASK) >> 16)) #define STRAT_GOALY(s) ((xchar)((s & STRAT_YMASK) >> 8)) long mtrapseen; /* bitmap of traps we've been trapped in */ long mlstmv; /* for catching up with lost time */ long mspare1; struct obj *minvent; struct obj *mw; long misc_worn_check; xchar weapon_check; int meating; /* monster is eating timeout */ struct mextra *mextra; /* point to mextra struct */ }; #define newmonst() (struct monst *) alloc(sizeof(struct monst)) /* these are in mspeed */ #define MSLOW 1 /* slow monster */ #define MFAST 2 /* speeded monster */ #define MON_WEP(mon) ((mon)->mw) #define MON_NOWEP(mon) ((mon)->mw = (struct obj *) 0) #define DEADMONSTER(mon) ((mon)->mhp < 1) #define is_starting_pet(mon) ((mon)->m_id == context.startingpet_mid) #define is_vampshifter(mon) \ ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LORD \ || (mon)->cham == PM_VLAD_THE_IMPALER) #define is_door_mappear(mon) ((mon)->m_ap_type == M_AP_FURNITURE \ && ((mon)->mappearance == S_hcdoor || (mon)->mappearance == S_vcdoor)) #define is_obj_mappear(mon,otyp) ((mon)->m_ap_type == M_AP_OBJECT \ && (mon)->mappearance == (otyp)) #endif /* MONST_H */ nethack-3.6.0/include/monsym.h0000664000076400007660000000775212536476415015303 0ustar paxedpaxed/* NetHack 3.6 monsym.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Monster symbols and creation information rev 1.0 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONSYM_H #define MONSYM_H /* * Monster classes. Below, are the corresponding default characters for * them. Monster class 0 is not used or defined so we can use it as a * NULL character. */ /* clang-format off */ #define S_ANT 1 #define S_BLOB 2 #define S_COCKATRICE 3 #define S_DOG 4 #define S_EYE 5 #define S_FELINE 6 #define S_GREMLIN 7 #define S_HUMANOID 8 #define S_IMP 9 #define S_JELLY 10 #define S_KOBOLD 11 #define S_LEPRECHAUN 12 #define S_MIMIC 13 #define S_NYMPH 14 #define S_ORC 15 #define S_PIERCER 16 #define S_QUADRUPED 17 #define S_RODENT 18 #define S_SPIDER 19 #define S_TRAPPER 20 #define S_UNICORN 21 #define S_VORTEX 22 #define S_WORM 23 #define S_XAN 24 #define S_LIGHT 25 #define S_ZRUTY 26 #define S_ANGEL 27 #define S_BAT 28 #define S_CENTAUR 29 #define S_DRAGON 30 #define S_ELEMENTAL 31 #define S_FUNGUS 32 #define S_GNOME 33 #define S_GIANT 34 #define S_invisible 35 /* non-class present in def_monsyms[] */ #define S_JABBERWOCK 36 #define S_KOP 37 #define S_LICH 38 #define S_MUMMY 39 #define S_NAGA 40 #define S_OGRE 41 #define S_PUDDING 42 #define S_QUANTMECH 43 #define S_RUSTMONST 44 #define S_SNAKE 45 #define S_TROLL 46 #define S_UMBER 47 #define S_VAMPIRE 48 #define S_WRAITH 49 #define S_XORN 50 #define S_YETI 51 #define S_ZOMBIE 52 #define S_HUMAN 53 #define S_GHOST 54 #define S_GOLEM 55 #define S_DEMON 56 #define S_EEL 57 #define S_LIZARD 58 #define S_WORM_TAIL 59 #define S_MIMIC_DEF 60 /* clang-format on */ #define MAXMCLASSES 61 /* number of monster classes */ /* * Default characters for monsters. These correspond to the monster classes * above. */ /* clang-format off */ #define DEF_ANT 'a' #define DEF_BLOB 'b' #define DEF_COCKATRICE 'c' #define DEF_DOG 'd' #define DEF_EYE 'e' #define DEF_FELINE 'f' #define DEF_GREMLIN 'g' #define DEF_HUMANOID 'h' #define DEF_IMP 'i' #define DEF_JELLY 'j' #define DEF_KOBOLD 'k' #define DEF_LEPRECHAUN 'l' #define DEF_MIMIC 'm' #define DEF_NYMPH 'n' #define DEF_ORC 'o' #define DEF_PIERCER 'p' #define DEF_QUADRUPED 'q' #define DEF_RODENT 'r' #define DEF_SPIDER 's' #define DEF_TRAPPER 't' #define DEF_UNICORN 'u' #define DEF_VORTEX 'v' #define DEF_WORM 'w' #define DEF_XAN 'x' #define DEF_LIGHT 'y' #define DEF_ZRUTY 'z' #define DEF_ANGEL 'A' #define DEF_BAT 'B' #define DEF_CENTAUR 'C' #define DEF_DRAGON 'D' #define DEF_ELEMENTAL 'E' #define DEF_FUNGUS 'F' #define DEF_GNOME 'G' #define DEF_GIANT 'H' #define DEF_JABBERWOCK 'J' #define DEF_KOP 'K' #define DEF_LICH 'L' #define DEF_MUMMY 'M' #define DEF_NAGA 'N' #define DEF_OGRE 'O' #define DEF_PUDDING 'P' #define DEF_QUANTMECH 'Q' #define DEF_RUSTMONST 'R' #define DEF_SNAKE 'S' #define DEF_TROLL 'T' #define DEF_UMBER 'U' #define DEF_VAMPIRE 'V' #define DEF_WRAITH 'W' #define DEF_XORN 'X' #define DEF_YETI 'Y' #define DEF_ZOMBIE 'Z' #define DEF_HUMAN '@' #define DEF_GHOST ' ' #define DEF_GOLEM '\'' #define DEF_DEMON '&' #define DEF_EEL ';' #define DEF_LIZARD ':' #define DEF_INVISIBLE 'I' #define DEF_WORM_TAIL '~' #define DEF_MIMIC_DEF ']' /* clang-format on */ #endif /* MONSYM_H */ nethack-3.6.0/include/mttypriv.h0000664000076400007660000000261512536476415015650 0ustar paxedpaxed/* NetHack 3.6 mttypriv.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains private structures used to implement the * tty windows - note that these structures may change between * minor releases! */ #ifndef _H_tty_private #define _H_tty_private #ifndef _H_tty_public #include "mactty.h" #endif #if !TARGET_API_MAC_CARBON #include #include #include #endif #define TA_TO_RGB(ta, rgb) \ (((rgb).red = (((ta) >> 16) & 0xff) * 257), \ ((rgb).green = (((ta) >> 8) & 0xff) * 257), \ ((rgb).blue = ((ta) &0xff) * 257)), \ rgb typedef struct tty_record { WindowPtr its_window; short font_number; short font_size; short char_width; short row_height; short ascent_height; short x_size; short y_size; short x_curs; short y_curs; GWorldPtr its_window_world; BitMap its_bits; GrafPtr offscreen_port; GWorldPtr offscreen_world; #if CLIP_RECT_ONLY Rect invalid_rect; #else RgnHandle invalid_part; #endif long attribute[TTY_NUMBER_ATTRIBUTES]; long last_cursor; Boolean was_allocated; Boolean curs_state; Boolean uses_gworld; } tty_record; #endif /* _H_tty_private */ nethack-3.6.0/include/ntconf.h0000664000076400007660000001677512622262031015234 0ustar paxedpaxed/* NetHack 3.6 ntconf.h $NHDT-Date: 1447424077 2015/11/13 14:14:37 $ $NHDT-Branch: master $:$NHDT-Revision: 1.48 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef NTCONF_H #define NTCONF_H /* #define SHELL /* nt use of pcsys routines caused a hang */ #define RANDOM /* have Berkeley random(3) */ #define TEXTCOLOR /* Color text */ #define EXEPATH /* Allow .exe location to be used as HACKDIR */ #define TRADITIONAL_GLYPHMAP /* Store glyph mappings at level change time */ #define LAN_FEATURES /* Include code for lan-aware features. Untested in \ 3.4.0*/ #define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */ /* without first receiving confirmation. */ #define HOLD_LOCKFILE_OPEN /* Keep an exclusive lock on the .0 file */ #define SELF_RECOVER /* Allow the game itself to recover from an aborted \ game */ #define SYSCF /* Use a global configuration */ #define SYSCF_FILE "sysconf" /* Use a file to hold the SYSCF configuration \ */ #define USER_SOUNDS /*#define CHANGE_COLOR*/ /* allow palette changes */ #define SELECTSAVED /* Provide menu of saved games to choose from at start \ */ /* * ----------------------------------------------------------------- * The remaining code shouldn't need modification. * ----------------------------------------------------------------- */ /* #define SHORT_FILENAMES /* All NT filesystems support long names now */ #ifdef MICRO #undef MICRO /* never define this! */ #endif #define NOCWD_ASSUMPTIONS /* Always define this. There are assumptions that \ it is defined for WIN32. \ Allow paths to be specified for HACKDIR, \ LEVELDIR, SAVEDIR, BONESDIR, DATADIR, \ SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ #define NO_TERMS #define ASCIIGRAPH #ifdef OPTIONS_USED #undef OPTIONS_USED #endif #define OPTIONS_USED "options" #define OPTIONS_FILE OPTIONS_USED #define PORT_HELP "porthelp" #define PORT_DEBUG /* include ability to debug international keyboard issues \ */ #define SAFERHANGUP /* Define SAFERHANGUP to delay hangup processing \ * until the main command loop. 'safer' because it \ * avoids certain cheats and also avoids losing \ * objects being thrown when the hangup occurs. \ */ /* Stuff to help the user with some common, yet significant errors */ #define INTERJECT_PANIC 0 #define INTERJECTION_TYPES (INTERJECT_PANIC + 1) extern void FDECL(interject_assistance, (int, int, genericptr_t, genericptr_t)); extern void FDECL(interject, (int)); /* *=============================================== * Compiler-specific adjustments *=============================================== */ #ifdef _MSC_VER #if (_MSC_VER > 1000) /* Visual C 8 warning elimination */ #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE #endif #ifndef _SCL_SECURE_NO_DEPRECATE #define _SCL_SECURE_NO_DEPRECATE #endif #ifndef _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE #endif #pragma warning(disable : 4996) /* VC8 deprecation warnings */ #pragma warning(disable : 4142) /* benign redefinition */ #pragma warning(disable : 4267) /* conversion from 'size_t' to XX */ #if (_MSC_VER > 1600) #pragma warning(disable : 4459) /* hide global declaration */ #endif /* _MSC_VER > 1600 */ #endif /* _MSC_VER > 1000 */ #pragma warning(disable : 4761) /* integral size mismatch in arg; conv \ supp*/ #ifdef YYPREFIX #pragma warning(disable : 4102) /* unreferenced label */ #endif #ifdef __cplusplus /* suppress a warning in cppregex.cpp */ #pragma warning(disable : 4101) /* unreferenced local variable */ #endif #endif /* _MSC_VER */ #define RUNTIME_PORT_ID /* trigger run-time port identification for \ * identification of exe CPU architecture \ */ /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) #include /* Provides prototypes of exit(), spawn() */ #endif #include /* Provides prototypes of strncmpi(), etc. */ #ifdef STRNCMPI #define strncmpi(a, b, c) strnicmp(a, b, c) #endif /* Visual Studio defines this in their own headers, which we don't use */ #ifndef snprintf #define snprintf _snprintf #pragma warning( \ disable : 4996) /* deprecation warning suggesting snprintf_s */ #endif #include #include #include #ifdef __BORLANDC__ #undef randomize #undef random #endif #define PATHLEN BUFSZ /* maximum pathlength */ #define FILENAME BUFSZ /* maximum filename length (conservative) */ #if defined(_MAX_PATH) && defined(_MAX_FNAME) #if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ) #undef PATHLEN #undef FILENAME #define PATHLEN _MAX_PATH #define FILENAME _MAX_FNAME #endif #endif #define NO_SIGNAL #define index strchr #define rindex strrchr /* Time stuff */ #include #define USE_STDARG #ifdef RANDOM /* Use the high quality random number routines. */ #define Rand() random() #else #define Rand() rand() #endif #include #define FCMASK (_S_IREAD | _S_IWRITE) /* file creation mask */ #define regularize nt_regularize #define HLOCK "NHPERM" #ifndef M #define M(c) ((char) (0x80 | (c))) /* #define M(c) ((c) - 128) */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif #if defined(DLB) #define FILENAME_CMP stricmp /* case insensitive */ #endif /* this was part of the MICRO stuff in the past */ extern const char *alllevels, *allbones; extern char hackdir[]; #define ABORT C('a') #define getuid() 1 #define getlogin() ((char *) 0) extern void NDECL(win32_abort); extern void FDECL(nttty_preference_update, (const char *)); extern void NDECL(toggle_mouse_support); extern void FDECL(map_subkeyvalue, (char *)); extern void NDECL(load_keyboard_handler); extern void NDECL(raw_clear_screen); #include #ifndef __BORLANDC__ #include #include #else int _RTLENTRY _EXPFUNC access(const char _FAR *__path, int __amode); int _RTLENTRY _EXPFUNC _chdrive(int __drive); int _RTLENTRYF _EXPFUNC32 chdir(const char _FAR *__path); char _FAR *_RTLENTRY _EXPFUNC getcwd(char _FAR *__buf, int __buflen); int _RTLENTRY _EXPFUNC write(int __handle, const void _FAR *__buf, unsigned __len); int _RTLENTRY _EXPFUNC creat(const char _FAR *__path, int __amode); int _RTLENTRY _EXPFUNC close(int __handle); int _RTLENTRY _EXPFUNC _close(int __handle); int _RTLENTRY _EXPFUNC open(const char _FAR *__path, int __access, ... /*unsigned mode*/); long _RTLENTRY _EXPFUNC lseek(int __handle, long __offset, int __fromwhere); int _RTLENTRY _EXPFUNC read(int __handle, void _FAR *__buf, unsigned __len); #endif #include #undef kbhit /* Use our special NT kbhit */ #define kbhit (*nt_kbhit) #ifdef LAN_FEATURES #define MAX_LAN_USERNAME 20 #endif #ifndef alloca #define ALLOCA_HACK /* used in util/panic.c */ #endif extern int FDECL(set_win32_option, (const char *, const char *)); #define LEFTBUTTON FROM_LEFT_1ST_BUTTON_PRESSED #define RIGHTBUTTON RIGHTMOST_BUTTON_PRESSED #define MIDBUTTON FROM_LEFT_2ND_BUTTON_PRESSED #define MOUSEMASK (LEFTBUTTON | RIGHTBUTTON | MIDBUTTON) #ifdef CHANGE_COLOR extern int FDECL(alternative_palette, (char *)); #endif #endif /* NTCONF_H */ nethack-3.6.0/include/obj.h0000664000076400007660000004404312610726721014514 0ustar paxedpaxed/* NetHack 3.6 obj.h $NHDT-Date: 1445126423 2015/10/18 00:00:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.50 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef OBJ_H #define OBJ_H /* #define obj obj_nh */ /* uncomment for SCO UNIX, which has a conflicting * typedef for "obj" in */ union vptrs { struct obj *v_nexthere; /* floor location lists */ struct obj *v_ocontainer; /* point back to container */ struct monst *v_ocarry; /* point back to carrying monst */ }; /**** *** oextra -- collection of all object extensions ** (see the note at the bottom of this file before adding oextra fields) */ struct oextra { char *oname; /* ptr to name of object */ struct monst *omonst; /* ptr to attached monst struct */ unsigned *omid; /* ptr to m_id */ long *olong; /* ptr to misc long (temporary gold object) */ char *omailcmd; /* response_cmd for mail deliver */ }; struct obj { struct obj *nobj; union vptrs v; #define nexthere v.v_nexthere #define ocontainer v.v_ocontainer #define ocarry v.v_ocarry struct obj *cobj; /* contents list for containers */ unsigned o_id; xchar ox, oy; short otyp; /* object class number */ unsigned owt; long quan; /* number of items */ schar spe; /* quality of weapon, armor or ring (+ or -) number of charges for wand ( >= -1 ) marks your eggs, tin variety and spinach tins royal coffers for a court ( == 2) tells which fruit a fruit is special for uball and amulet historic and gender for statues */ #define STATUE_HISTORIC 0x01 #define STATUE_MALE 0x02 #define STATUE_FEMALE 0x04 char oclass; /* object class */ char invlet; /* designation in inventory */ char oartifact; /* artifact array index */ xchar where; /* where the object thinks it is */ #define OBJ_FREE 0 /* object not attached to anything */ #define OBJ_FLOOR 1 /* object on floor */ #define OBJ_CONTAINED 2 /* object in a container */ #define OBJ_INVENT 3 /* object in the hero's inventory */ #define OBJ_MINVENT 4 /* object in a monster inventory */ #define OBJ_MIGRATING 5 /* object sent off to another level */ #define OBJ_BURIED 6 /* object buried */ #define OBJ_ONBILL 7 /* object on shk bill */ #define NOBJ_STATES 8 xchar timed; /* # of fuses (timers) attached to this obj */ Bitfield(cursed, 1); Bitfield(blessed, 1); Bitfield(unpaid, 1); /* on some bill */ Bitfield(no_charge, 1); /* if shk shouldn't charge for this */ Bitfield(known, 1); /* exact nature known */ Bitfield(dknown, 1); /* color or text known */ Bitfield(bknown, 1); /* blessing or curse known */ Bitfield(rknown, 1); /* rustproof or not known */ Bitfield(oeroded, 2); /* rusted/burnt weapon/armor */ Bitfield(oeroded2, 2); /* corroded/rotted weapon/armor */ #define greatest_erosion(otmp) \ (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded \ : (otmp)->oeroded2) #define MAX_ERODE 3 #define orotten oeroded /* rotten food */ #define odiluted oeroded /* diluted potions */ #define norevive oeroded2 Bitfield(oerodeproof, 1); /* erodeproof weapon/armor */ Bitfield(olocked, 1); /* object is locked */ Bitfield(obroken, 1); /* lock has been broken */ #define degraded_horn obroken /* unicorn horn will poly to non-magic */ Bitfield(otrapped, 1); /* container is trapped */ /* or accidental tripped rolling boulder trap */ #define opoisoned otrapped /* object (weapon) is coated with poison */ Bitfield(recharged, 3); /* number of times it's been recharged */ #define on_ice recharged /* corpse on ice */ Bitfield(lamplit, 1); /* a light-source -- can be lit */ Bitfield( globby, 1); /* globby; will combine with like types on adjacent squares */ Bitfield(greased, 1); /* covered with grease */ Bitfield(nomerge, 1); /* set temporarily to prevent merging */ Bitfield(was_thrown, 1); /* thrown by hero since last picked up */ Bitfield(in_use, 1); /* for magic items before useup items */ Bitfield(bypass, 1); /* mark this as an object to be skipped by bhito() */ Bitfield(cknown, 1); /* contents of container assumed to be known */ Bitfield(lknown, 1); /* locked/unlocked status is known */ /* 4 free bits */ int corpsenm; /* type of corpse is mons[corpsenm] */ #define leashmon corpsenm /* gets m_id of attached pet */ #define fromsink corpsenm /* a potion from a sink */ #define novelidx corpsenm /* 3.6.0 tribute - the index of the novel title */ #define record_achieve_special corpsenm int usecount; /* overloaded for various things that tally */ #define spestudied usecount /* # of times a spellbook has been studied */ unsigned oeaten; /* nutrition left in food, if partly eaten */ long age; /* creation date */ long owornmask; struct oextra *oextra; /* pointer to oextra struct */ }; #define newobj() (struct obj *) alloc(sizeof(struct obj)) /*** ** oextra referencing and testing macros */ #define ONAME(o) ((o)->oextra->oname) #define OMID(o) ((o)->oextra->omid) #define OMONST(o) ((o)->oextra->omonst) #define OLONG(o) ((o)->oextra->olong) #define OMAILCMD(o) ((o)->oextra->omailcmd) #define has_oname(o) ((o)->oextra && ONAME(o)) #define has_omid(o) ((o)->oextra && OMID(o)) #define has_omonst(o) ((o)->oextra && OMONST(o)) #define has_olong(o) ((o)->oextra && OLONG(o)) #define has_omailcmd(o) ((o)->oextra && OMAILCMD(o)) /* Weapons and weapon-tools */ /* KMH -- now based on skill categories. Formerly: * #define is_sword(otmp) (otmp->oclass == WEAPON_CLASS && \ * objects[otmp->otyp].oc_wepcat == WEP_SWORD) * #define is_blade(otmp) (otmp->oclass == WEAPON_CLASS && \ * (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \ * objects[otmp->otyp].oc_wepcat == WEP_SWORD)) * #define is_weptool(o) ((o)->oclass == TOOL_CLASS && \ * objects[(o)->otyp].oc_weptool) * #define is_multigen(otyp) (otyp <= SHURIKEN) * #define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN) */ #define is_blade(otmp) \ (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= P_DAGGER \ && objects[otmp->otyp].oc_skill <= P_SABER) #define is_axe(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && objects[otmp->otyp].oc_skill == P_AXE) #define is_pick(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && objects[otmp->otyp].oc_skill == P_PICK_AXE) #define is_sword(otmp) \ (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= P_SHORT_SWORD \ && objects[otmp->otyp].oc_skill <= P_SABER) #define is_pole(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && (objects[otmp->otyp].oc_skill == P_POLEARMS \ || objects[otmp->otyp].oc_skill == P_LANCE)) #define is_spear(otmp) \ (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill == P_SPEAR) #define is_launcher(otmp) \ (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill >= P_BOW \ && objects[otmp->otyp].oc_skill <= P_CROSSBOW) #define is_ammo(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == GEM_CLASS) \ && objects[otmp->otyp].oc_skill >= -P_CROSSBOW \ && objects[otmp->otyp].oc_skill <= -P_BOW) #define matching_launcher(a, l) \ ((l) && objects[(a)->otyp].oc_skill == -objects[(l)->otyp].oc_skill) #define ammo_and_launcher(a, l) (is_ammo(a) && matching_launcher(a, l)) #define is_missile(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && objects[otmp->otyp].oc_skill >= -P_BOOMERANG \ && objects[otmp->otyp].oc_skill <= -P_DART) #define is_weptool(o) \ ((o)->oclass == TOOL_CLASS && objects[(o)->otyp].oc_skill != P_NONE) /* towel is not a weptool: spe isn't an enchantment, cursed towel doesn't weld to hand, and twoweapon won't work with one */ #define is_wet_towel(o) ((o)->otyp == TOWEL && (o)->spe > 0) #define bimanual(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && objects[otmp->otyp].oc_bimanual) #define is_multigen(otmp) \ (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \ && objects[otmp->otyp].oc_skill <= -P_BOW) #define is_poisonable(otmp) \ (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \ && objects[otmp->otyp].oc_skill <= -P_BOW) #define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING) /* Armor */ #define is_shield(otmp) \ (otmp->oclass == ARMOR_CLASS \ && objects[otmp->otyp].oc_armcat == ARM_SHIELD) #define is_helmet(otmp) \ (otmp->oclass == ARMOR_CLASS && objects[otmp->otyp].oc_armcat == ARM_HELM) #define is_boots(otmp) \ (otmp->oclass == ARMOR_CLASS \ && objects[otmp->otyp].oc_armcat == ARM_BOOTS) #define is_gloves(otmp) \ (otmp->oclass == ARMOR_CLASS \ && objects[otmp->otyp].oc_armcat == ARM_GLOVES) #define is_cloak(otmp) \ (otmp->oclass == ARMOR_CLASS \ && objects[otmp->otyp].oc_armcat == ARM_CLOAK) #define is_shirt(otmp) \ (otmp->oclass == ARMOR_CLASS \ && objects[otmp->otyp].oc_armcat == ARM_SHIRT) #define is_suit(otmp) \ (otmp->oclass == ARMOR_CLASS && objects[otmp->otyp].oc_armcat == ARM_SUIT) #define is_elven_armor(otmp) \ ((otmp)->otyp == ELVEN_LEATHER_HELM \ || (otmp)->otyp == ELVEN_MITHRIL_COAT || (otmp)->otyp == ELVEN_CLOAK \ || (otmp)->otyp == ELVEN_SHIELD || (otmp)->otyp == ELVEN_BOOTS) #define is_orcish_armor(otmp) \ ((otmp)->otyp == ORCISH_HELM || (otmp)->otyp == ORCISH_CHAIN_MAIL \ || (otmp)->otyp == ORCISH_RING_MAIL || (otmp)->otyp == ORCISH_CLOAK \ || (otmp)->otyp == URUK_HAI_SHIELD || (otmp)->otyp == ORCISH_SHIELD) #define is_dwarvish_armor(otmp) \ ((otmp)->otyp == DWARVISH_IRON_HELM \ || (otmp)->otyp == DWARVISH_MITHRIL_COAT \ || (otmp)->otyp == DWARVISH_CLOAK \ || (otmp)->otyp == DWARVISH_ROUNDSHIELD) #define is_gnomish_armor(otmp) (FALSE) /* Eggs and other food */ #define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */ #define stale_egg(egg) \ ((monstermoves - (egg)->age) > (2 * MAX_EGG_HATCH_TIME)) #define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN) #define polyfodder(obj) (ofood(obj) && pm_to_cham((obj)->corpsenm) != NON_PM) #define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH) #define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE) #define Is_pudding(o) \ (o->otyp == GLOB_OF_GRAY_OOZE || o->otyp == GLOB_OF_BROWN_PUDDING \ || o->otyp == GLOB_OF_GREEN_SLIME || o->otyp == GLOB_OF_BLACK_PUDDING) /* Containers */ #define carried(o) ((o)->where == OBJ_INVENT) #define mcarried(o) ((o)->where == OBJ_MINVENT) #define Has_contents(o) \ (/* (Is_container(o) || (o)->otyp == STATUE) && */ \ (o)->cobj != (struct obj *) 0) #define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS) #define Is_box(otmp) (otmp->otyp == LARGE_BOX || otmp->otyp == CHEST) #define Is_mbag(otmp) \ (otmp->otyp == BAG_OF_HOLDING || otmp->otyp == BAG_OF_TRICKS) #define SchroedingersBox(o) ((o)->otyp == LARGE_BOX && (o)->spe == 1) /* dragon gear */ #define Is_dragon_scales(obj) \ ((obj)->otyp >= GRAY_DRAGON_SCALES && (obj)->otyp <= YELLOW_DRAGON_SCALES) #define Is_dragon_mail(obj) \ ((obj)->otyp >= GRAY_DRAGON_SCALE_MAIL \ && (obj)->otyp <= YELLOW_DRAGON_SCALE_MAIL) #define Is_dragon_armor(obj) (Is_dragon_scales(obj) || Is_dragon_mail(obj)) #define Dragon_scales_to_pm(obj) \ &mons[PM_GRAY_DRAGON + (obj)->otyp - GRAY_DRAGON_SCALES] #define Dragon_mail_to_pm(obj) \ &mons[PM_GRAY_DRAGON + (obj)->otyp - GRAY_DRAGON_SCALE_MAIL] #define Dragon_to_scales(pm) (GRAY_DRAGON_SCALES + (pm - mons)) /* Elven gear */ #define is_elven_weapon(otmp) \ ((otmp)->otyp == ELVEN_ARROW || (otmp)->otyp == ELVEN_SPEAR \ || (otmp)->otyp == ELVEN_DAGGER || (otmp)->otyp == ELVEN_SHORT_SWORD \ || (otmp)->otyp == ELVEN_BROADSWORD || (otmp)->otyp == ELVEN_BOW) #define is_elven_obj(otmp) (is_elven_armor(otmp) || is_elven_weapon(otmp)) /* Orcish gear */ #define is_orcish_obj(otmp) \ (is_orcish_armor(otmp) || (otmp)->otyp == ORCISH_ARROW \ || (otmp)->otyp == ORCISH_SPEAR || (otmp)->otyp == ORCISH_DAGGER \ || (otmp)->otyp == ORCISH_SHORT_SWORD || (otmp)->otyp == ORCISH_BOW) /* Dwarvish gear */ #define is_dwarvish_obj(otmp) \ (is_dwarvish_armor(otmp) || (otmp)->otyp == DWARVISH_SPEAR \ || (otmp)->otyp == DWARVISH_SHORT_SWORD \ || (otmp)->otyp == DWARVISH_MATTOCK) /* Gnomish gear */ #define is_gnomish_obj(otmp) (is_gnomish_armor(otmp)) /* Light sources */ #define Is_candle(otmp) \ (otmp->otyp == TALLOW_CANDLE || otmp->otyp == WAX_CANDLE) #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */ /* MAGIC_LAMP intentionally excluded below */ /* age field of this is relative age rather than absolute */ #define age_is_relative(otmp) \ ((otmp)->otyp == BRASS_LANTERN || (otmp)->otyp == OIL_LAMP \ || (otmp)->otyp == CANDELABRUM_OF_INVOCATION \ || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \ || (otmp)->otyp == POT_OIL) /* object can be ignited */ #define ignitable(otmp) \ ((otmp)->otyp == BRASS_LANTERN || (otmp)->otyp == OIL_LAMP \ || (otmp)->otyp == CANDELABRUM_OF_INVOCATION \ || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \ || (otmp)->otyp == POT_OIL) /* things that can be read */ #define is_readable(otmp) \ ((otmp)->otyp == FORTUNE_COOKIE || (otmp)->otyp == T_SHIRT \ || (otmp)->otyp == ALCHEMY_SMOCK || (otmp)->otyp == CREDIT_CARD \ || (otmp)->otyp == CAN_OF_GREASE || (otmp)->otyp == MAGIC_MARKER \ || (otmp)->oclass == COIN_CLASS || (otmp)->oartifact == ART_ORB_OF_FATE \ || (otmp)->otyp == CANDY_BAR) /* special stones */ #define is_graystone(obj) \ ((obj)->otyp == LUCKSTONE || (obj)->otyp == LOADSTONE \ || (obj)->otyp == FLINT || (obj)->otyp == TOUCHSTONE) /* misc */ #define is_flimsy(otmp) \ (objects[(otmp)->otyp].oc_material <= LEATHER \ || (otmp)->otyp == RUBBER_HOSE) /* helpers, simple enough to be macros */ #define is_plural(o) \ ((o)->quan > 1 || (o)->oartifact == ART_EYES_OF_THE_OVERWORLD) /* Flags for get_obj_location(). */ #define CONTAINED_TOO 0x1 #define BURIED_TOO 0x2 /* object erosion types */ #define ERODE_BURN 0 #define ERODE_RUST 1 #define ERODE_ROT 2 #define ERODE_CORRODE 3 /* erosion flags for erode_obj() */ #define EF_NONE 0 #define EF_GREASE 0x1 /* check for a greased object */ #define EF_DESTROY 0x2 /* potentially destroy the object */ #define EF_VERBOSE 0x4 /* print extra messages */ #define EF_PAY 0x8 /* it's the player's fault */ /* erosion return values for erode_obj(), water_damage() */ #define ER_NOTHING 0 /* nothing happened */ #define ER_GREASED 1 /* protected by grease */ #define ER_DAMAGED 2 /* object was damaged in some way */ #define ER_DESTROYED 3 /* object was destroyed */ /* * Notes for adding new oextra structures: * * 1. Add the structure definition and any required macros in an *appropriate * header file that precedes this one. * 2. Add a pointer to your new struct to the oextra struct in this *file. * 3. Add a referencing macro to this file after the newobj macro above * (see ONAME, OMONST, OMIN, OLONG, or OMAILCMD for examples). * 4. Add a testing macro after the set of referencing macros * (see has_oname(), has_omonst(), has_omin(), has_olong(), * has_omailcmd() for examples). * 5. Create a newXX(otmp) function and possibly a free_XX(otmp) *function * in an appropriate new or existing source file and add a prototype * for it to include/extern.h. The majority of these are currently * located in mkobj.c for convenience. * * void FDECL(newXX, (struct obj *)); * void FDECL(free_XX, (struct obj *)); * * void * newxx(otmp) * struct obj *otmp; * { * if (!otmp->oextra) otmp->oextra = newoextra(); * if (!XX(otmp)) { * XX(otmp) = (struct XX *)alloc(sizeof(struct xx)); * (void) memset((genericptr_t) XX(otmp), * 0, sizeof(struct xx)); * } * } * * 6. Adjust size_obj() in src/cmd.c appropriately. * 7. Adjust dealloc_oextra() in src/mkobj.c to clean up * properly during obj deallocation. * 8. Adjust copy_oextra() in src/mkobj.c to make duplicate * copies of your struct or data onto another obj struct. * 9. Adjust restobj() in src/restore.c to deal with your * struct or data during a restore. * 10. Adjust saveobj() in src/save.c to deal with your * struct or data during a save. */ #endif /* OBJ_H */ nethack-3.6.0/include/objclass.h0000664000076400007660000001513012622603541015532 0ustar paxedpaxed/* NetHack 3.6 objclass.h $NHDT-Date: 1447755971 2015/11/17 10:26:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef OBJCLASS_H #define OBJCLASS_H /* definition of a class of objects */ struct objclass { short oc_name_idx; /* index of actual name */ short oc_descr_idx; /* description when name unknown */ char *oc_uname; /* called by user */ Bitfield(oc_name_known, 1); Bitfield(oc_merge, 1); /* merge otherwise equal objects */ Bitfield(oc_uses_known, 1); /* obj->known affects full description */ /* otherwise, obj->dknown and obj->bknown */ /* tell all, and obj->known should always */ /* be set for proper merging behavior */ Bitfield(oc_pre_discovered, 1); /* Already known at start of game; */ /* won't be listed as a discovery. */ Bitfield(oc_magic, 1); /* inherently magical object */ Bitfield(oc_charged, 1); /* may have +n or (n) charges */ Bitfield(oc_unique, 1); /* special one-of-a-kind object */ Bitfield(oc_nowish, 1); /* cannot wish for this object */ Bitfield(oc_big, 1); #define oc_bimanual oc_big /* for weapons & tools used as weapons */ #define oc_bulky oc_big /* for armor */ Bitfield(oc_tough, 1); /* hard gems/rings */ Bitfield(oc_dir, 2); #define NODIR 1 /* for wands/spells: non-directional */ #define IMMEDIATE 2 /* directional */ #define RAY 3 /* zap beams */ #define PIERCE 1 /* for weapons & tools used as weapons */ #define SLASH 2 /* (latter includes iron ball & chain) */ #define WHACK 0 /*Bitfield(oc_subtyp,3);*/ /* Now too big for a bitfield... see below */ Bitfield(oc_material, 5); #define LIQUID 1 /* currently only for venom */ #define WAX 2 #define VEGGY 3 /* foodstuffs */ #define FLESH 4 /* ditto */ #define PAPER 5 #define CLOTH 6 #define LEATHER 7 #define WOOD 8 #define BONE 9 #define DRAGON_HIDE 10 /* not leather! */ #define IRON 11 /* Fe - includes steel */ #define METAL 12 /* Sn, &c. */ #define COPPER 13 /* Cu - includes brass */ #define SILVER 14 /* Ag */ #define GOLD 15 /* Au */ #define PLATINUM 16 /* Pt */ #define MITHRIL 17 #define PLASTIC 18 #define GLASS 19 #define GEMSTONE 20 #define MINERAL 21 #define is_organic(otmp) (objects[otmp->otyp].oc_material <= WOOD) #define is_metallic(otmp) \ (objects[otmp->otyp].oc_material >= IRON \ && objects[otmp->otyp].oc_material <= MITHRIL) /* primary damage: fire/rust/--- */ /* is_flammable(otmp), is_rottable(otmp) in mkobj.c */ #define is_rustprone(otmp) (objects[otmp->otyp].oc_material == IRON) /* secondary damage: rot/acid/acid */ #define is_corrodeable(otmp) \ (objects[otmp->otyp].oc_material == COPPER \ || objects[otmp->otyp].oc_material == IRON) #define is_damageable(otmp) \ (is_rustprone(otmp) || is_flammable(otmp) || is_rottable(otmp) \ || is_corrodeable(otmp)) schar oc_subtyp; #define oc_skill oc_subtyp /* Skills of weapons, spellbooks, tools, gems */ #define oc_armcat oc_subtyp /* for armor */ #define ARM_SHIELD 1 /* needed for special wear function */ #define ARM_HELM 2 #define ARM_GLOVES 3 #define ARM_BOOTS 4 #define ARM_CLOAK 5 #define ARM_SHIRT 6 #define ARM_SUIT 0 uchar oc_oprop; /* property (invis, &c.) conveyed */ char oc_class; /* object class */ schar oc_delay; /* delay when using such an object */ uchar oc_color; /* color of the object */ short oc_prob; /* probability, used in mkobj() */ unsigned short oc_weight; /* encumbrance (1 cn = 0.1 lb.) */ short oc_cost; /* base cost in shops */ /* Check the AD&D rules! The FIRST is small monster damage. */ /* for weapons, and tools, rocks, and gems useful as weapons */ schar oc_wsdam, oc_wldam; /* max small/large monster damage */ schar oc_oc1, oc_oc2; #define oc_hitbon oc_oc1 /* weapons: "to hit" bonus */ #define a_ac oc_oc1 /* armor class, used in ARM_BONUS in do.c */ #define a_can oc_oc2 /* armor: used in mhitu.c */ #define oc_level oc_oc2 /* books: spell level */ unsigned short oc_nutrition; /* food value */ }; struct class_sym { char sym; const char *name; const char *explain; }; struct objdescr { const char *oc_name; /* actual name */ const char *oc_descr; /* description when name unknown */ }; extern NEARDATA struct objclass objects[]; extern NEARDATA struct objdescr obj_descr[]; /* * All objects have a class. Make sure that all classes have a corresponding * symbol below. */ #define RANDOM_CLASS 0 /* used for generating random objects */ #define ILLOBJ_CLASS 1 #define WEAPON_CLASS 2 #define ARMOR_CLASS 3 #define RING_CLASS 4 #define AMULET_CLASS 5 #define TOOL_CLASS 6 #define FOOD_CLASS 7 #define POTION_CLASS 8 #define SCROLL_CLASS 9 #define SPBOOK_CLASS 10 /* actually SPELL-book */ #define WAND_CLASS 11 #define COIN_CLASS 12 #define GEM_CLASS 13 #define ROCK_CLASS 14 #define BALL_CLASS 15 #define CHAIN_CLASS 16 #define VENOM_CLASS 17 #define MAXOCLASSES 18 #define ALLOW_COUNT (MAXOCLASSES + 1) /* Can be used in the object class */ #define ALL_CLASSES (MAXOCLASSES + 2) /* input to getobj(). */ #define ALLOW_NONE (MAXOCLASSES + 3) #define BURNING_OIL (MAXOCLASSES + 1) /* Can be used as input to explode. */ #define MON_EXPLODE (MAXOCLASSES + 2) /* Exploding monster (e.g. gas spore) */ #if 0 /* moved to decl.h so that makedefs.c won't see them */ extern const struct class_sym def_oc_syms[MAXOCLASSES]; /* default class symbols */ extern uchar oc_syms[MAXOCLASSES]; /* current class symbols */ #endif /* Default definitions of all object-symbols (must match classes above). */ #define ILLOBJ_SYM ']' /* also used for mimics */ #define WEAPON_SYM ')' #define ARMOR_SYM '[' #define RING_SYM '=' #define AMULET_SYM '"' #define TOOL_SYM '(' #define FOOD_SYM '%' #define POTION_SYM '!' #define SCROLL_SYM '?' #define SPBOOK_SYM '+' #define WAND_SYM '/' #define GOLD_SYM '$' #define GEM_SYM '*' #define ROCK_SYM '`' #define BALL_SYM '0' #define CHAIN_SYM '_' #define VENOM_SYM '.' struct fruit { char fname[PL_FSIZ]; int fid; struct fruit *nextf; }; #define newfruit() (struct fruit *) alloc(sizeof(struct fruit)) #define dealloc_fruit(rind) free((genericptr_t)(rind)) #define OBJ_NAME(obj) (obj_descr[(obj).oc_name_idx].oc_name) #define OBJ_DESCR(obj) (obj_descr[(obj).oc_descr_idx].oc_descr) #endif /* OBJCLASS_H */ nethack-3.6.0/include/os2conf.h0000664000076400007660000000473412536476415015327 0ustar paxedpaxed/* NetHack 3.6 os2conf.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993, 1996. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef OS2 #ifndef OS2CONF_H #define OS2CONF_H /* * Compiler configuration. Compiler may be * selected either here or in Makefile.os2. */ /* #define OS2_MSC /* Microsoft C 5.1 and 6.0 */ #define OS2_GCC /* GCC emx 0.8f */ /* #define OS2_CSET2 /* IBM C Set/2 (courtesy Jeff Urlwin) */ /* #define OS2_CSET2_VER_1 /* CSet/2 version selection */ /* #define OS2_CSET2_VER_2 /* - " - */ /* * System configuration. */ #define OS2_USESYSHEADERS /* use compiler's own system headers */ /* #define OS2_HPFS /* use OS/2 High Performance File System */ #if defined(OS2_GCC) || defined(OS2_CSET2) #define OS2_32BITAPI /* enable for compilation in OS/2 2.0 */ #endif /* * Other configurable options. Generally no * reason to touch the defaults, I think. */ /*#define MFLOPPY /* floppy and ramdisk support */ #define RANDOM /* Berkeley random(3) */ #define SHELL /* shell escape */ /* #define TERMLIB /* use termcap file */ #define ANSI_DEFAULT /* allows NetHack to run without termcap file */ #define TEXTCOLOR /* allow color */ /* * The remaining code shouldn't need modification. */ #ifdef MSDOS #undef MSDOS /* MSC autodefines this but we don't want it */ #endif #ifndef MICRO #define MICRO /* must be defined to allow some inclusions */ #endif #if !defined(TERMLIB) && !defined(ANSI_DEFAULT) #define ANSI_DEFAULT /* have to have one or the other */ #endif #define PATHLEN 260 /* maximum pathlength (HPFS) */ #define FILENAME 260 /* maximum filename length (HPFS) */ #ifndef MICRO_H #include "micro.h" /* necessary externs for [os_name].c */ #endif #ifndef SYSTEM_H #include "system.h" #endif #ifndef index #define index strchr #endif #ifndef rindex #define rindex strrchr #endif #include /* the high quality random number routines */ #ifdef RANDOM #define Rand() random() #else #define Rand() rand() #endif /* file creation mask */ #include #include #define FCMASK (S_IREAD | S_IWRITE) #include #ifdef __EMX__ #include #define sethanguphandler(foo) (void) signal(SIGHUP, (SIG_RET_TYPE) foo) #endif void hangup(int i); #endif /* OS2CONF_H */ #endif /* OS2 */ nethack-3.6.0/include/patchlevel.h0000664000076400007660000004123312631241231016056 0ustar paxedpaxed/* NetHack 3.6 patchlevel.h $NHDT-Date: 1447755971 2015/11/17 10:26:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.112 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* NetHack 3.6.0 */ #define VERSION_MAJOR 3 #define VERSION_MINOR 6 /* * PATCHLEVEL is updated for each release. */ #define PATCHLEVEL 0 /* * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ #define EDITLEVEL 2 #define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2015" #define COPYRIGHT_BANNER_B \ " By Stichting Mathematisch Centrum and M. Stephenson." /* COPYRIGHT_BANNER_C is generated by makedefs into date.h */ #define COPYRIGHT_BANNER_D " See license for details." /* * If two or more successive releases have compatible data files, define * this with the version number of the oldest such release so that the * new release will accept old save and bones files. The format is * 0xMMmmPPeeL * 0x = literal prefix "0x", MM = major version, mm = minor version, * PP = patch level, ee = edit level, L = literal suffix "L", * with all four numbers specified as two hexadecimal digits. */ /* #define VERSION_COMPATIBILITY 0x03050000L */ /****************************************************************************/ /* Version 3.6.x */ /* * NetHack 3.6.0, December 7, 2015 * * Hundreds of bug fixes. * Some code reorganization. * Some new features. * Variations of some community patches rolled in. */ /****************************************************************************/ /* Version 3.5.x */ /* Version 3.5 was never officially released. */ /****************************************************************************/ /* Version 3.4.x */ /* Patch 3, December 7, 2003 * Several dozen general bug fixes including at least one fatal bug * Correct several inconsistencies * Handle level completely filled with monsters better * Performance enhancements for win32tty port on Windows 98 and Me * win32gui player selection fixes * X11 player selection fixes, one of which could be fatal * Eliminated a gold-in-shop-container cheat * Include bones file version compatibility info in options file */ /* Patch 2, August 30, 2003 * Fix a fatal bug that caused a crash when applying figurine, candle, or * bell that gets used up * Fix a fatal bug that triggered a panic when your secondary weapon was * cursed during bones file creation * Several dozen general bug fixes * Fixed some Gnome compilation problems on Redhat 7.2 and 8.0 * Fixed a problem in the util Makefile * Use random() by default under linux instead of lrand48() * win32 tty adjustments and support for loading alternative key handlers */ /* Patch 1, February 22, 2003 * Fix a few fatal errors including one for reentering shops, one * involving land mines and boulders/statues, one for delayed * polymorph, and one from a chest trap exploding ball and chain * Fix a buffer overflow that could lead to security problems * Hundreds of general bug fixes * Several message and other glitches corrected * Travel command adjustments and ability to disable travel command * message recall window extensions (by Christian Cooper) * win32: some interface improvements * unix: improved tile support * gnome: some fixes, and some enhancements by Dylan Alex Simon * winCE: Windows CE port included (by Alex Kompel) */ /* * NetHack 3.4.0, March 20, 2002 * * Hundreds of general bug fixes including some for sliming, zapping, *conduct, * and several more for riding * Eliminated a few potentially fatal bugs including one for stone-to-flesh, * trouble-fixing during prayer, riding down stairs while punished, * polyd player demon summoning, throwing digging tools into shops, and * a couple from having the vision system enabled at inappropriate times * Corrected some incorrect calculations in final scoring * Enhanced config file processing and alert to duplication of entries * Player selection prompt enhancements for TTY and X11 * Objects merge in containers * Wish for "nothing", and genocide "none" to preserve your conduct * Changes to Wizard quest * Added the travel command which works by mouse click or '_' command * Config file BOULDER option to specify the symbol for displaying boulders * Incorporate modified versions of several 3.3.1 patches that have been * in circulation in the NetHack community * New Gnomish Mines levels (courtesy Kelly Bailey) * Mac: command-key shortcuts in the player selection dialog * Amiga: screenmode requester, and several amiga specific bug fixes * Win32 graphical port contributed by Alex Kompel is now included */ /* Version 3.4 */ /****************************************************************************/ /* Version 3.3.x */ /* Patch 1, August 9, 2000 * Many, many general fixes, including a number for riding, twoweapon, * and invisible monsters * A security fix for a couple of potentially exploitable buffer overflows * in previous versions * Redo Ranger quest * Introduction of differentiation between different causes of blindness * Overhaul of warning * Functionality restored to Amiga (courtesy Janne Salmijarvi) and Atari * (courtesy Christian "Marvin" Bressler) ports * Mac: multiple interface fixes * win32: fixed bug that caused messages to stop displaying after escape * tty: use ANSI color (AF) over standard color (Sf) when given the choice * several ports: offer for player selection only choices consistent with * those already made by config file/command line (e.g., only offer roles * that are compatible with specified race) */ /* * NetHack 3.3.0, December 10, 1999 * * Implement the differentiation of character class or role from the * character race. * Removal of the Elf class, in preference to the Elf as a race. * Introduction of Dwarves, Elves, Gnomes and Orcs as distinct races in * addition to the Human "norm". * Addition of the Monk and Ranger classes. * Integrate some of the features of several branch versions of the game, * notably NetHack--, NHplus, SLASH, and Slash'em. * Adopt "the wizard patch" spellcasting system. * Support for the Qt widget set. * Y2K fix: use 4 digit year values for the dates in the score file * updated COPYRIGHT_BANNER_A to reflect year of release. * Dozens of other bug fixes, and minor improvements. */ /* Version 3.3 */ /****************************************************************************/ /* Version 3.2.x */ /* Patch 3, December 10, 1999 * Released simultaneously with 3.3.0 for the benefit of * ports and platforms that were unable to get working * versions of 3.3.0 ready prior to the year 2000. It * consisted of just a few bug fixes and offered no new * functionality changes over 3.2.2. * * Y2K fix: use 4 digit year values for the dates in the score file * updated COPYRIGHT_BANNER_A to reflect year of release * Fatal Mac bug removed * DOS Makefile problem removed * several bugs that could potentially trigger crashes removed */ /* Patch 2, December 10, 1996 * fix the `recover' utility * fix priest/minion name overflow which could cause Astral Plane crashes * avoid crash when hit by own thrown boomerang * " " " worn blindfold pushed off by applying cursed towel * handle returning live Wizard correctly in deep dungeon levels * don't occasionally display unseen areas of new levels during level change * other minor display fixes * fix several minor reason for death inconsistencies and shop bugs * high dexterity doesn't guarantee that thrown eggs & potions will hit * * Selected platform- or configuration-specific changes: * Mac: update `mrecover' * MSDOS: don't switch into tiles mode when resuming play on rogue level * tty: support object class characters for 'I' command in menu mode * Unix: work around several compilation problems * X11: as tty above, plus implement tty-style count handling in menus; * better window placement support for old window managers */ /* Patch 1, May 28, 1996 * eliminate `#qualifications'; fix weapon proficiency handling for missiles * keep Medusa from continuing to move after she's been killed by reflection * of her own gaze (fixes relmon panic) * make monsters a little smarter; assorted eating and chatting changes * fix object amnesia for spellbooks; fix Nazgul's sleep gas attack * fix bullwhip usage for case of having recently been in a trap * egg hatching fixes, oil potion fixes, magic marker fixes * support object class chars as selection accelerators for some menus * stricter parsing of run-time options at startup time * interactive setting of options via menu (courtesy Per Liboriussen) * * Selected platform- or configuration-specific changes: * Amiga: fix panic for tiles display in Gnomish mines * BeOS: preliminary support for new BeBox platform; initially tty only * DLB: avoid excessive fseek calls (major performance hit for MSDOS) * HPUX: workaround for gcc-2.6.3 bug adversely affecting monster generation * Mac: avoid MW 68K struct copy optimization bug which caused crashes; * fix dragging of scrollbar; boost partitions to 2MB minimum * MSDOS: wasn't safe to enter endgame for MFLOPPY configuration; * fix re-entry into game after "!" (shell escape) + chdir + EXIT; * F3/F4/F5 display interface swapping improvements; * add support for preloading all tiles in protected mode environment * TERMINFO: colors were wrong for some systems, such as Linux * X11: display help files properly */ /* * NetHack 3.2.0, April 11, 1996 * enhancements to the windowing systems including "tiles" or icons to * visually represent monsters and objects (courtesy Warwick Allison) * window based menu system introduced for inventory and selection * moving light sources besides the player * improved #untrap (courtesy Helge Hafting) * spellcasting logic changes to balance spellcasting towards magic-using * classes (courtesy Stephen White) * many, many bug fixes and abuse eliminations */ /* Version 3.2 */ /****************************************************************************/ /* Version 3.1.x */ /* * Patch 3, July 12, 1993 * further revise Mac windowing and extend to Think C (courtesy * Barton House) * fix confusing black/gray/white display on some MSDOS hardware * remove fatal bugs dealing with horns of plenty and VMS bones levels, * as well as more minor ones */ /* * Patch 2, June 1, 1993 * add tty windowing to Mac and Amiga ports and revise native windowing * allow direct screen I/O for MS-DOS versions instead of going through * termcap routines (courtesy Michael Allison and Kevin Smolkowski) * changes for NEC PC-9800 and various termcap.zip fixes by Yamamoto Keizo * SYSV 386 music driver ported to 386BSD (courtesy Andrew Chernov) and * SCO UNIX (courtesy Andreas Arens) * enhanced pickup and disclosure options * removed fatal bugs dealing with cursed bags of holding, renaming * shopkeepers, objects falling through trapdoors on deep levels, * and kicking embedded objects loose, and many more minor ones */ /* * Patch 1, February 25, 1993 * add Windows NT console port (courtesy Michael Allison) * polishing of Amiga, Mac, and X11 windowing * fixing many small bugs, including the infamous 3.0 nurse relmon bug */ /* * NetHack 3.1.0, January 25, 1993 * many, many changes and bugfixes -- some of the highlights include: * display rewrite using line-of-sight vision * general window interface, with the ability to use multiple interfaces * in the same executable * intelligent monsters * enhanced dungeon mythology * branching dungeons with more special levels, quest dungeons, and * multi-level endgame * more artifacts and more uses for artifacts * generalization to multiple shops with damage repair * X11 interface * ability to recover crashed games * full rewrite of Macintosh port * Amiga splitter * directory rearrangement (dat, doc, sys, win, util) */ /* Version 3.1 */ /****************************************************************************/ /* Version 3.0 */ /* * Patch 10, February 5, 1991 * extend overlay manager to multiple files for easier binary distribution * allow for more system and compiler variance * remove more small insects */ /* * Patch 9, June 26, 1990 * clear up some confusing documentation * smooth some more rough edges in various ports * and fix a couple more bugs */ /* * Patch 8, June 3, 1990 * further debug and refine Macintosh port * refine the overlay manager, rearrange the OVLx breakdown for better * efficiency, rename the overlay macros, and split off the overlay * instructions to Install.ovl * introduce NEARDATA for better Amiga efficiency * support for more VMS versions (courtesy Joshua Delahunty and Pat Rankin) * more const fixes * better support for common graphics (DEC VT and IBM) * and a number of simple fixes and consistency extensions */ /* * Patch 7, February 19, 1990 * refine overlay support to handle portions of .c files through OVLx * (courtesy above plus Kevin Smolkowski) * update and extend Amiga port and documentation (courtesy Richard Addison, * Jochen Erwied, Mark Gooderum, Ken Lorber, Greg Olson, Mike Passaretti, * and Gregg Wonderly) * refine and extend Macintosh port and documentation (courtesy Johnny Lee, * Kevin Sitze, Michael Sokolov, Andy Swanson, Jon Watte, and Tom West) * refine VMS documentation * continuing ANSIfication, this time of const usage * teach '/' about differences within monster classes * smarter eating code (yet again), death messages, and treatment of * non-animal monsters, monster unconsciousness, and naming * extended version command to give compilation options * and the usual bug fixes and hole plugs */ /* * Patch 6, November 19, 1989 * add overlay support for MS-DOS (courtesy Pierre Martineau, Stephen * Spackman, and Norm Meluch) * refine Macintosh port * different door states show as different symbols (courtesy Ari Huttunen) * smarter drawbridges (courtesy Kevin Darcy) * add CLIPPING and split INFERNO off HARD * further refine eating code wrt picking up and resumption * make first few levels easier, by adding :x monsters and increasing initial * attribute points and hitting probability * teach '/' about configurable symbols */ /* * Patch 5, October 15, 1989 * add support for Macintosh OS (courtesy Johnny Lee) * fix annoying dependency loop via new color.h file * allow interruption while eating -- general handling of partially eaten * food * smarter treatment of iron balls (courtesy Kevin Darcy) * a handful of other bug fixes */ /* * Patch 4, September 27, 1989 * add support for VMS (courtesy David Gentzel) * move monster-on-floor references into functions and implement the new * lookup structure for both objects and monsters * extend the definitions of objects and monsters to provide "living color" * in the dungeon, instead of a single monster color * ifdef varargs usage to satisfy ANSI compilers * standardize on the color 'gray' * assorted bug fixes */ /* * Patch 3, September 6, 1989 * add war hammers and revise object prices * extend prototypes to ANSI compilers in addition to the previous MSDOS ones * move object-on-floor references into functions in preparation for planned * data structures to allow faster access and better colors * fix some more bugs, and extend the portability of things added in earlier * patches */ /* * Patch 2, August 16, 1989 * add support for OS/2 (courtesy Timo Hakulinen) * add a better makefile for MicroSoft C (courtesy Paul Gyugyi) * more accommodation of compilers and preprocessors * add better screen-size sensing * expand color use for PCs and introduce it for SVR3 UNIX machines * extend '/' to multiple identifications * allow meta key to be used to invoke extended commands * fix various minor bugs, and do further code cleaning */ /* * Patch 1, July 31, 1989 * add support for Atari TOS (courtesy Eric Smith) and Andrew File System * (courtesy Ralf Brown) * include the uuencoded version of termcap.arc for the MSDOS versions that * was included with 2.2 and 2.3 * make a number of simple changes to accommodate various compilers * fix a handful of bugs, and do some code cleaning elsewhere * add more instructions for new environments and things commonly done wrong */ /* * NetHack 3.0 baseline release, July, 1989 */ /* Version 3.0 */ /****************************************************************************/ /*patchlevel.h*/ nethack-3.6.0/include/pcconf.h0000664000076400007660000002275612617413107015217 0ustar paxedpaxed/* NetHack 3.6 pcconf.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef PCCONF_H #define PCCONF_H #define MICRO /* always define this! */ #ifdef MSDOS /* some of this material is MS-DOS specific */ /* * Automatic Defines: * * __GO32__ is defined automatically by the djgpp port of gcc. * __DJGPP__ is defined automatically by djgpp version 2 and above. * _MSC_VER is defined automatically by Microsoft C. * __BORLANDC__ is defined automatically by Borland C. * __SC__ is defined automatically by Symantec C. * Note: 3.6.x was not verified with Symantec C. */ /* * The following options are somewhat configurable depending on * your compiler. */ /* * For pre-V7.0 Microsoft Compilers only, manually define OVERLAY here. */ /*#define OVERLAY */ /* Manual overlay definition (MSC 6.0ax only) */ #ifndef __GO32__ #define MFLOPPY /* Support for floppy drives and ramdisks by dgk */ #endif #define SHELL /* via exec of COMMAND.COM */ #ifdef __BORLANDC__ #define PCMUSIC /* Music option, enable very basic pc speaker music notes */ #endif /* * Screen control options * * You may uncomment: * ANSI_DEFAULT * or TERMLIB * or ANSI_DEFAULT and TERMLIB * or NO_TERMS */ /* # define TERMLIB */ /* enable use of termcap file /etc/termcap */ /* or ./termcap for MSDOS (SAC) */ /* compile and link in Fred Fish's termcap library, */ /* enclosed in TERMCAP.ARC, to use this */ /* # define ANSI_DEFAULT */ /* allows NetHack to run without a ./termcap */ #define NO_TERMS /* Allows Nethack to run without ansi.sys by linking */ /* screen routines into the .exe */ #ifdef NO_TERMS /* if NO_TERMS select one screen package below */ #define SCREEN_BIOS /* Use bios calls for all screen control */ /* #define SCREEN_DJGPPFAST */ /* Use djgpp fast screen routines */ #endif /* # define PC9800 */ /* Allows NetHack to run on NEC PC-9800 machines */ /* Yamamoto Keizo */ /* * PC video hardware support options (for graphical tile support) * * You may uncomment any/all of the options below. * */ #ifndef SUPPRESS_GRAPHICS #if (defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST)) && !defined(PC9800) #ifdef USE_TILES #define SCREEN_VGA /* Include VGA graphics routines in the build */ #endif #endif #else #undef NO_TERMS #undef SCREEN_BIOS #undef SCREEN_DJGPPFAST #undef SCREEN_VGA #undef TERMLIB #define ANSI_DEFAULT #endif #define RANDOM /* have Berkeley random(3) */ #define MAIL /* Allows for fake mail daemon to deliver mail */ /* in the MSDOS version. (For AMIGA MAIL see */ /* amiconf.h). In the future this will be the */ /* hook for mail reader implementation. */ /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__) #include /* Provides prototypes of exit(), spawn() */ #endif #if defined(_MSC_VER) && (_MSC_VER >= 7) #include #include #ifdef strcmpi #undef strcmpi #endif #include /* Provides prototypes of strncmpi(), etc. */ #include #include #include #define SIG_RET_TYPE void(__cdecl *)(int) #define M(c) ((char) (0x80 | (c))) #define vprintf printf #define vfprintf fprintf #define vsprintf sprintf #endif #if defined(__BORLANDC__) && defined(STRNCMPI) #include /* Provides prototypes of strncmpi(), etc. */ #endif #if defined(__DJGPP__) #define _NAIVE_DOS_REGS #include #include /* Provides prototypes of strncmpi(), etc. */ #ifndef M #define M(c) ((char) (0x80 | (c))) #endif #endif /* * On the VMS and unix, this option controls whether a delay is done by * the clock, or whether it is done by excess output. On the PC, however, * there is always a clock to use for the delay. The TIMED_DELAY option * on MSDOS (without the termcap routines) is used to determine whether to * include the delay routines in the code (and thus, provides a compile time * method to turn off napping for visual effect). However, it is also used * in the music code to wait between different notes. So it is needed in that * case as well. * Whereas on the VMS and unix, flags.nap is a run-time option controlling * whether there is a delay by clock or by excess output, on MSDOS it is * simply a flag to turn on or off napping for visual effects at run-time. */ #define TIMED_DELAY /* enable the `timed_delay' run-time option */ #ifdef PCMUSIC #define TIMED_DELAY /* need it anyway */ #endif #define NOCWD_ASSUMPTIONS /* Allow paths to be specified for HACKDIR, \ LEVELDIR, SAVEDIR, BONESDIR, DATADIR, \ SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR. \ */ #endif /* MSDOS configuration stuff */ #define PATHLEN 64 /* maximum pathlength */ #define FILENAME 80 /* maximum filename length (conservative) */ #ifndef MICRO_H #include "micro.h" /* contains necessary externs for [os_name].c */ #endif /* =================================================== * The remaining code shouldn't need modification. */ #ifndef SYSTEM_H #if !defined(_MSC_VER) #include "system.h" #endif #endif #ifdef __DJGPP__ #include /* close(), etc. */ /* lock() in io.h interferes with lock[] in decl.h */ #define lock djlock #include #undef lock #include /* kbhit() */ #define PC_LOCKING #define HOLD_LOCKFILE_OPEN #define SELF_RECOVER /* NetHack itself can recover games */ #endif #ifdef MSDOS #ifndef EXEPATH #define EXEPATH /* HACKDIR is .exe location if not explicitly defined */ #endif #endif #if defined(_MSC_VER) && defined(MSDOS) #if (_MSC_VER >= 700) && !defined(FUNCTION_LEVEL_LINKING) #ifndef MOVERLAY #define MOVERLAY /* Microsoft's MOVE overlay system (MSC >= 7.0) */ #endif #endif #define PC_LOCKING #endif /* Borland Stuff */ #if defined(__BORLANDC__) #if defined(__OVERLAY__) && !defined(VROOMM) /* __OVERLAY__ is automatically defined by Borland C if overlay option is on */ #define VROOMM /* Borland's VROOMM overlay system */ #endif #if !defined(STKSIZ) #define STKSIZ 5 * 1024 /* Use a default of 5K stack for Borland C */ /* This macro is used in any file that contains */ /* a main() function. */ #endif #define PC_LOCKING #endif #ifdef PC_LOCKING #define HLOCK "NHPERM" #endif #ifndef index #define index strchr #endif #ifndef rindex #define rindex strrchr #endif #ifndef AMIGA #include #endif #ifdef RANDOM /* Use the high quality random number routines. */ #define Rand() random() #else #define Rand() rand() #endif #ifndef TOS #define FCMASK 0660 /* file creation mask */ #endif #include #ifdef MSDOS #define TEXTCOLOR /* */ #define PORT_HELP "msdoshlp.txt" /* msdos port specific help file */ #endif /* Sanity check, do not modify these blocks. */ /* OVERLAY must be defined with MOVERLAY or VROOMM */ #if (defined(MOVERLAY) || defined(VROOMM)) #ifndef OVERLAY #define OVERLAY #endif #endif #if defined(FUNCTION_LEVEL_LINKING) #define OVERLAY #endif #if defined(OVERLAY) && !defined(MOVERLAY) && !defined(VROOMM) \ && !defined(FUNCTION_LEVEL_LINKING) #define USE_TRAMPOLI #endif #if defined(MSDOS) && defined(NO_TERMS) #ifdef TERMLIB #if defined(_MSC_VER) || defined(__SC__) #pragma message("Warning -- TERMLIB defined with NO_TERMS in pcconf.h") #pragma message(" Forcing undef of TERMLIB") #endif #undef TERMLIB #endif #ifdef ANSI_DEFAULT #if defined(_MSC_VER) || defined(__SC__) #pragma message("Warning -- ANSI_DEFAULT defined with NO_TERMS in pcconf.h") #pragma message(" Forcing undef of ANSI_DEFAULT") #endif #undef ANSI_DEFAULT #endif /* only one screen package is allowed */ #if defined(SCREEN_BIOS) && defined(SCREEN_DJGPPFAST) #if defined(_MSC_VER) || defined(__SC__) #pragma message("Warning -- More than one screen package defined in pcconf.h") #endif #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__) #if defined(SCREEN_DJGPPFAST) #if defined(_MSC_VER) || defined(__SC__) #pragma message(" Forcing undef of SCREEN_DJGPPFAST") #endif #undef SCREEN_DJGPPFAST /* Can't use djgpp fast with other compilers anyway \ */ #endif #else /* djgpp C compiler */ #if defined(SCREEN_BIOS) #undef SCREEN_BIOS #endif #endif #endif #define ASCIIGRAPH #ifdef TEXTCOLOR #define VIDEOSHADES #endif /* SCREEN_8514, SCREEN_VESA are only placeholders presently - sub VGA instead */ #if defined(SCREEN_8514) || defined(SCREEN_VESA) #undef SCREEN_8514 #undef SCREEN_VESA #define SCREEN_VGA #endif /* Graphical tile sanity checks */ #ifdef SCREEN_VGA #define SIMULATE_CURSOR #define POSITIONBAR /* Select appropriate tile file format, and map size */ #define PLANAR_FILE #define SMALL_MAP #endif #endif /* End of sanity check block */ #if defined(MSDOS) && defined(DLB) #define FILENAME_CMP stricmp /* case insensitive */ #endif #if defined(_MSC_VER) && (_MSC_VER >= 7) #pragma warning(disable : 4131) #pragma warning(disable : 4135) #pragma warning(disable : 4309) #pragma warning(disable : 4746) #pragma warning(disable : 4761) #endif #ifdef TIMED_DELAY #ifdef __DJGPP__ #define msleep(k) (void) usleep((k) *1000) #endif #ifdef __BORLANDC__ #define msleep(k) delay(k) #endif #ifdef __SC__ #define msleep(k) (void) usleep((long)((k) *1000)) #endif #endif #endif /* PCCONF_H */ nethack-3.6.0/include/permonst.h0000664000076400007660000000533312536476415015621 0ustar paxedpaxed/* NetHack 3.6 permonst.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef PERMONST_H #define PERMONST_H /* This structure covers all attack forms. * aatyp is the gross attack type (eg. claw, bite, breath, ...) * adtyp is the damage type (eg. physical, fire, cold, spell, ...) * damn is the number of hit dice of damage from the attack. * damd is the number of sides on each die. * * Some attacks can do no points of damage. Additionally, some can * have special effects *and* do damage as well. If damn and damd * are set, they may have a special meaning. For example, if set * for a blinding attack, they determine the amount of time blinded. */ struct attack { uchar aatyp; uchar adtyp, damn, damd; }; /* Max # of attacks for any given monster. */ #define NATTK 6 /* Weight of a human body */ #define WT_HUMAN 1450 #ifndef ALIGN_H #include "align.h" #endif #include "monattk.h" #include "monflag.h" struct permonst { const char *mname; /* full name */ char mlet; /* symbol */ schar mlevel, /* base monster level */ mmove, /* move speed */ ac, /* (base) armor class */ mr; /* (base) magic resistance */ aligntyp maligntyp; /* basic monster alignment */ unsigned short geno; /* creation/geno mask value */ struct attack mattk[NATTK]; /* attacks matrix */ unsigned short cwt, /* weight of corpse */ cnutrit; /* its nutritional value */ uchar msound; /* noise it makes (6 bits) */ uchar msize; /* physical size (3 bits) */ uchar mresists; /* resistances */ uchar mconveys; /* conveyed by eating */ unsigned long mflags1, /* boolean bitflags */ mflags2; /* more boolean bitflags */ unsigned short mflags3; /* yet more boolean bitflags */ #ifdef TEXTCOLOR uchar mcolor; /* color to use */ #endif }; extern NEARDATA struct permonst mons[]; /* the master list of monster types */ #define VERY_SLOW 3 #define SLOW_SPEED 9 #define NORMAL_SPEED 12 /* movement rates */ #define FAST_SPEED 15 #define VERY_FAST 24 #define NON_PM PM_PLAYERMON /* "not a monster" */ #define LOW_PM (NON_PM + 1) /* first monster in mons[] */ #define SPECIAL_PM PM_LONG_WORM_TAIL /* [normal] < ~ < [special] */ /* mons[SPECIAL_PM] through mons[NUMMONS-1], inclusive, are never generated randomly and cannot be polymorphed into */ #endif /* PERMONST_H */ nethack-3.6.0/include/prop.h0000664000076400007660000001124312555636173014727 0ustar paxedpaxed/* NetHack 3.6 prop.h $NHDT-Date: 1437877163 2015/07/26 02:19:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef PROP_H #define PROP_H /*** What the properties are ***/ /* Resistances to troubles */ #define FIRE_RES 1 #define COLD_RES 2 #define SLEEP_RES 3 #define DISINT_RES 4 #define SHOCK_RES 5 #define POISON_RES 6 #define ACID_RES 7 #define STONE_RES 8 /* note: for the first eight properties, MR_xxx == (1 << (xxx_RES - 1)) */ #define DRAIN_RES 9 #define SICK_RES 10 #define INVULNERABLE 11 #define ANTIMAGIC 12 /* Troubles */ #define STUNNED 13 #define CONFUSION 14 #define BLINDED 15 #define DEAF 16 #define SICK 17 #define STONED 18 #define STRANGLED 19 #define VOMITING 20 #define GLIB 21 #define SLIMED 22 #define HALLUC 23 #define HALLUC_RES 24 #define FUMBLING 25 #define WOUNDED_LEGS 26 #define SLEEPY 27 #define HUNGER 28 /* Vision and senses */ #define SEE_INVIS 29 #define TELEPAT 30 #define WARNING 31 #define WARN_OF_MON 32 #define WARN_UNDEAD 33 #define SEARCHING 34 #define CLAIRVOYANT 35 #define INFRAVISION 36 #define DETECT_MONSTERS 37 /* Appearance and behavior */ #define ADORNED 38 #define INVIS 39 #define DISPLACED 40 #define STEALTH 41 #define AGGRAVATE_MONSTER 42 #define CONFLICT 43 /* Transportation */ #define JUMPING 44 #define TELEPORT 45 #define TELEPORT_CONTROL 46 #define LEVITATION 47 #define FLYING 48 #define WWALKING 49 #define SWIMMING 50 #define MAGICAL_BREATHING 51 #define PASSES_WALLS 52 /* Physical attributes */ #define SLOW_DIGESTION 53 #define HALF_SPDAM 54 #define HALF_PHDAM 55 #define REGENERATION 56 #define ENERGY_REGENERATION 57 #define PROTECTION 58 #define PROT_FROM_SHAPE_CHANGERS 59 #define POLYMORPH 60 #define POLYMORPH_CONTROL 61 #define UNCHANGING 62 #define FAST 63 #define REFLECTING 64 #define FREE_ACTION 65 #define FIXED_ABIL 66 #define LIFESAVED 67 #define LAST_PROP (LIFESAVED) /*** Where the properties come from ***/ /* Definitions were moved here from obj.h and you.h */ struct prop { /*** Properties conveyed by objects ***/ long extrinsic; /* Armor */ #define W_ARM 0x00000001L /* Body armor */ #define W_ARMC 0x00000002L /* Cloak */ #define W_ARMH 0x00000004L /* Helmet/hat */ #define W_ARMS 0x00000008L /* Shield */ #define W_ARMG 0x00000010L /* Gloves/gauntlets */ #define W_ARMF 0x00000020L /* Footwear */ #define W_ARMU 0x00000040L /* Undershirt */ #define W_ARMOR (W_ARM | W_ARMC | W_ARMH | W_ARMS | W_ARMG | W_ARMF | W_ARMU) /* Weapons and artifacts */ #define W_WEP 0x00000100L /* Wielded weapon */ #define W_QUIVER 0x00000200L /* Quiver for (f)iring ammo */ #define W_SWAPWEP 0x00000400L /* Secondary weapon */ #define W_WEAPON (W_WEP | W_SWAPWEP | W_QUIVER) #define W_ART 0x00001000L /* Carrying artifact (not really worn) */ #define W_ARTI 0x00002000L /* Invoked artifact (not really worn) */ /* Amulets, rings, tools, and other items */ #define W_AMUL 0x00010000L /* Amulet */ #define W_RINGL 0x00020000L /* Left ring */ #define W_RINGR 0x00040000L /* Right ring */ #define W_RING (W_RINGL | W_RINGR) #define W_TOOL 0x00080000L /* Eyewear */ #define W_ACCESSORY (W_RING | W_AMUL | W_TOOL) /* historical note: originally in slash'em, 'worn' saddle stayed in hero's inventory; in nethack, it's kept in the steed's inventory */ #define W_SADDLE 0x00100000L /* KMH -- For riding monsters */ #define W_BALL 0x00200000L /* Punishment ball */ #define W_CHAIN 0x00400000L /* Punishment chain */ /*** Property is blocked by an object ***/ long blocked; /* Same assignments as extrinsic */ /*** Timeouts, permanent properties, and other flags ***/ long intrinsic; /* Timed properties */ #define TIMEOUT 0x00ffffffL /* Up to 16 million turns */ /* Permanent properties */ #define FROMEXPER 0x01000000L /* Gain/lose with experience, for role */ #define FROMRACE 0x02000000L /* Gain/lose with experience, for race */ #define FROMOUTSIDE 0x04000000L /* By corpses, prayer, thrones, etc. */ #define INTRINSIC (FROMOUTSIDE | FROMRACE | FROMEXPER) /* Control flags */ #define FROMFORM 0x10000000L /* Polyd; conferred by monster form */ #define I_SPECIAL 0x20000000L /* Property is controllable */ }; /*** Definitions for backwards compatibility ***/ #define LEFT_RING W_RINGL #define RIGHT_RING W_RINGR #define LEFT_SIDE LEFT_RING #define RIGHT_SIDE RIGHT_RING #define BOTH_SIDES (LEFT_SIDE | RIGHT_SIDE) #define WORN_ARMOR W_ARM #define WORN_CLOAK W_ARMC #define WORN_HELMET W_ARMH #define WORN_SHIELD W_ARMS #define WORN_GLOVES W_ARMG #define WORN_BOOTS W_ARMF #define WORN_AMUL W_AMUL #define WORN_BLINDF W_TOOL #define WORN_SHIRT W_ARMU #endif /* PROP_H */ nethack-3.6.0/include/qt_clust.h0000664000076400007660000000127412536476415015610 0ustar paxedpaxed/* NetHack 3.6 qt_clust.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef clusterizer_H #define clusterizer_H #include class Clusterizer { public: Clusterizer(int maxclusters); ~Clusterizer(); void add(int x, int y); // 1x1 rectangle (point) void add(int x, int y, int w, int h); void add(const QRect &rect); void clear(); int clusters() { return count; } const QRect &operator[](int i); private: QRect *cluster; int count; const int max; }; #endif nethack-3.6.0/include/qt_kde0.h0000664000076400007660000000052412536476415015276 0ustar paxedpaxed/* NetHack 3.6 qt_kde0.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QT_DUMMYKDE #define QT_DUMMYKDE class KTopLevelWidget : public QMainWindow { Q_OBJECT }; #endif nethack-3.6.0/include/qt_win.h0000664000076400007660000004721412622603541015243 0ustar paxedpaxed// NetHack 3.6 qt_win.h $NHDT-Date: 1447755972 2015/11/17 10:26:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ // Copyright (c) Warwick Allison, 1999. // NetHack may be freely redistributed. See license for details. // // Qt Binding for NetHack 3.4 // // Unfortunately, this doesn't use Qt as well as I would like, // primarily because NetHack is fundamentally a getkey-type // program rather than being event driven (hence the ugly key // and click buffer rather), but also because this is my first // major application of Qt. // #ifndef qt_win_h #define qt_win_h #define QT_CLEAN_NAMESPACE #include #include #include #include #include #if defined(QWS) #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 300 #include // Should stop using QTableView #define QTableView QtTableView #else #include #endif #include #include #ifdef KDE #include #include #endif #include "qt_clust.h" class QVBox; class QMenuBar; class QRadioButton; class NhPSListView; ////////////////////////////////////////////////////////////// // // The beautiful, abstracted and well-modelled classes... // ////////////////////////////////////////////////////////////// class NetHackQtGlyphs; class NetHackQtLineEdit : public QLineEdit { public: NetHackQtLineEdit(); NetHackQtLineEdit(QWidget *parent, const char *name); void fakeEvent(int key, int ascii, int state); }; class NetHackQtSettings : public QDialog { Q_OBJECT public: // Size of window - used to decide default sizes NetHackQtSettings(int width, int height); NetHackQtGlyphs &glyphs(); const QFont &normalFont(); const QFont &normalFixedFont(); const QFont &largeFont(); bool ynInMessages(); signals: void fontChanged(); void tilesChanged(); public slots: void toggleGlyphSize(); void setGlyphSize(bool); private: QSpinBox tilewidth; QSpinBox tileheight; QLabel widthlbl; QLabel heightlbl; QCheckBox whichsize; QSize othersize; QComboBox fontsize; QFont normal, normalfixed, large; NetHackQtGlyphs *theglyphs; private slots: void resizeTiles(); }; class NetHackQtKeyBuffer { public: NetHackQtKeyBuffer(); bool Empty() const; bool Full() const; void Put(int k, int ascii, int state); void Put(char a); void Put(const char *str); int GetKey(); int GetAscii(); int GetState(); int TopKey() const; int TopAscii() const; int TopState() const; private: enum { maxkey = 64 }; int key[maxkey]; int ascii[maxkey]; int state[maxkey]; int in, out; }; class NetHackQtClickBuffer { public: NetHackQtClickBuffer(); bool Empty() const; bool Full() const; void Put(int x, int y, int mod); int NextX() const; int NextY() const; int NextMod() const; void Get(); private: enum { maxclick = 64 }; struct ClickRec { int x, y, mod; } click[maxclick]; int in, out; }; class NetHackQtSavedGameSelector : public QDialog { public: NetHackQtSavedGameSelector(const char **saved); int choose(); }; class NetHackQtPlayerSelector : private QDialog { Q_OBJECT public: enum { R_None = -1, R_Quit = -2, R_Rand = -3 }; NetHackQtPlayerSelector(NetHackQtKeyBuffer &); protected: virtual void done(int); public slots: void Quit(); void Random(); void selectName(const QString &n); void selectRole(); void selectRace(); void setupOthers(); void selectGender(int); void selectAlignment(int); public: bool Choose(); private: NetHackQtKeyBuffer &keysource; NhPSListView *role; NhPSListView *race; QRadioButton **gender; QRadioButton **alignment; bool fully_specified_role; }; class NetHackQtStringRequestor : QDialog { private: QLabel prompt; NetHackQtLineEdit input; QPushButton *okay; QPushButton *cancel; NetHackQtKeyBuffer &keysource; virtual void done(int); public: NetHackQtStringRequestor(NetHackQtKeyBuffer &, const char *p, const char *cancelstr = "Cancel"); void SetDefault(const char *); bool Get(char *buffer, int maxchar = 80); virtual void resizeEvent(QResizeEvent *); }; class NetHackQtExtCmdRequestor : public QDialog { Q_OBJECT NetHackQtKeyBuffer &keysource; public: NetHackQtExtCmdRequestor(NetHackQtKeyBuffer &ks); int get(); private slots: void cancel(); void done(int i); }; class NetHackQtWindow { public: NetHackQtWindow(); virtual ~NetHackQtWindow(); virtual QWidget *Widget() = 0; virtual void Clear(); virtual void Display(bool block); virtual bool Destroy(); virtual void CursorTo(int x, int y); virtual void PutStr(int attr, const char *text); virtual void StartMenu(); virtual void AddMenu(int glyph, const ANY_P *identifier, char ch, char gch, int attr, const char *str, bool presel); virtual void EndMenu(const char *prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); virtual void ClipAround(int x, int y); virtual void PrintGlyph(int x, int y, int glyph); virtual void UseRIP(int how, time_t when); int nhid; }; class NetHackQtGlyphs { public: NetHackQtGlyphs(); int width() const { return size.width(); } int height() const { return size.height(); } void toggleSize(); void setSize(int w, int h); void drawGlyph(QPainter &, int glyph, int pixelx, int pixely); void drawCell(QPainter &, int glyph, int cellx, int celly); private: QImage img; QPixmap pm, pm1, pm2; QSize size; int tiles_per_row; }; class BlackScrollView : public QScrollView { public: BlackScrollView() { viewport()->setBackgroundColor(black); } }; class NetHackQtMapWindow : public QWidget, public NetHackQtWindow { Q_OBJECT private: NetHackQtClickBuffer &clicksink; unsigned short glyph[ROWNO][COLNO]; unsigned short & Glyph(int x, int y) { return glyph[y][x]; } QPoint cursor; BlackScrollView viewport; QPixmap pet_annotation; Clusterizer change; QFont *rogue_font; QString messages; QRect messages_rect; void Changed(int x, int y); signals: void resized(); private slots: void updateTiles(); void moveMessages(int x, int y); #ifdef SAFERHANGUP void timeout(); #endif protected: virtual void paintEvent(QPaintEvent *); virtual void mousePressEvent(QMouseEvent *); public: NetHackQtMapWindow(NetHackQtClickBuffer &click_sink); ~NetHackQtMapWindow(); virtual QWidget *Widget(); virtual bool Destroy(); virtual void Clear(); virtual void Display(bool block); virtual void CursorTo(int x, int y); virtual void PutStr(int attr, const char *text); virtual void ClipAround(int x, int y); virtual void PrintGlyph(int x, int y, int glyph); void Scroll(int dx, int dy); // For messages void displayMessages(bool block); void putMessage(int attr, const char *text); void clearMessages(); void clickCursor(); }; class NetHackQtScrollText; class NetHackQtMessageWindow : QObject, public NetHackQtWindow { Q_OBJECT public: NetHackQtMessageWindow(); ~NetHackQtMessageWindow(); virtual QWidget *Widget(); virtual void Clear(); virtual void Display(bool block); virtual void PutStr(int attr, const char *text); void Scroll(int dx, int dy); void setMap(NetHackQtMapWindow *); private: NetHackQtScrollText *list; bool changed; NetHackQtMapWindow *map; private slots: void updateFont(); }; class NetHackQtLabelledIcon : public QWidget { public: NetHackQtLabelledIcon(QWidget *parent, const char *label); NetHackQtLabelledIcon(QWidget *parent, const char *label, const QPixmap &icon); enum { NoNum = -99999 }; void setLabel(const char *, bool lower = TRUE); // a string void setLabel(const char *, long, const char *tail = ""); // a number void setLabel(const char *, long show_value, long comparative_value, const char *tail = ""); void setIcon(const QPixmap &); virtual void setFont(const QFont &); void highlightWhenChanging(); void lowIsGood(); void dissipateHighlight(); virtual void show(); protected: void resizeEvent(QResizeEvent *); private: void initHighlight(); void setAlignments(); void highlight(const QPalette &highlight); void unhighlight(); bool low_is_good; int prev_value; int turn_count; /* last time the value changed */ QPalette hl_good; QPalette hl_bad; QLabel *label; QLabel *icon; }; class NetHackQtStatusWindow : QWidget, public NetHackQtWindow { Q_OBJECT public: NetHackQtStatusWindow(); virtual QWidget *Widget(); virtual void Clear(); virtual void Display(bool block); virtual void CursorTo(int x, int y); virtual void PutStr(int attr, const char *text); void fadeHighlighting(); protected: void resizeEvent(QResizeEvent *); private slots: void doUpdate(); private: enum { hilight_time = 1 }; QPixmap p_str; QPixmap p_dex; QPixmap p_con; QPixmap p_int; QPixmap p_wis; QPixmap p_cha; QPixmap p_chaotic; QPixmap p_neutral; QPixmap p_lawful; QPixmap p_satiated; QPixmap p_hungry; QPixmap p_confused; QPixmap p_sick_fp; QPixmap p_sick_il; QPixmap p_blind; QPixmap p_stunned; QPixmap p_hallu; QPixmap p_encumber[5]; NetHackQtLabelledIcon name; NetHackQtLabelledIcon dlevel; NetHackQtLabelledIcon str; NetHackQtLabelledIcon dex; NetHackQtLabelledIcon con; NetHackQtLabelledIcon intel; NetHackQtLabelledIcon wis; NetHackQtLabelledIcon cha; NetHackQtLabelledIcon gold; NetHackQtLabelledIcon hp; NetHackQtLabelledIcon power; NetHackQtLabelledIcon ac; NetHackQtLabelledIcon level; NetHackQtLabelledIcon exp; NetHackQtLabelledIcon align; NetHackQtLabelledIcon time; NetHackQtLabelledIcon score; NetHackQtLabelledIcon hunger; NetHackQtLabelledIcon confused; NetHackQtLabelledIcon sick_fp; NetHackQtLabelledIcon sick_il; NetHackQtLabelledIcon blind; NetHackQtLabelledIcon stunned; NetHackQtLabelledIcon hallu; NetHackQtLabelledIcon encumber; QFrame hline1; QFrame hline2; QFrame hline3; int cursy; bool first_set; void nullOut(); void updateStats(); void checkTurnEvents(); }; class NetHackQtMenuDialog : public QDialog { Q_OBJECT public: NetHackQtMenuDialog(); void Accept(); void Reject(); void SetResult(int); virtual void done(int); protected: void resizeEvent(QResizeEvent *); signals: void Resized(); }; class NetHackQtMenuWindow : public QTableView, public NetHackQtWindow { Q_OBJECT public: NetHackQtMenuWindow(NetHackQtKeyBuffer &); ~NetHackQtMenuWindow(); virtual QWidget *Widget(); virtual void StartMenu(); virtual void AddMenu(int glyph, const ANY_P *identifier, char ch, char gch, int attr, const char *str, bool presel); virtual void EndMenu(const char *prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); public slots: void All(); void ChooseNone(); void Invert(); void Search(); void Layout(); void ToggleSelect(int); protected: virtual void keyPressEvent(QKeyEvent *); // virtual void mouseDoubleClickEvent(QMouseEvent*); virtual void mousePressEvent(QMouseEvent *); virtual void mouseReleaseEvent(QMouseEvent *); virtual void mouseMoveEvent(QMouseEvent *); virtual void focusOutEvent(QFocusEvent *); virtual void focusInEvent(QFocusEvent *); virtual void paintCell(QPainter *, int, int); virtual int cellWidth(int col); private: struct MenuItem { MenuItem(); ~MenuItem(); int glyph; ANY_P identifier; int attr; const char *str; int count; char ch; bool selected; bool Selectable() const { return identifier.a_void != 0; } }; QArray item; int itemcount; int str_width; bool str_fixed; int next_accel; NetHackQtKeyBuffer &keysource; NetHackQtMenuDialog *dialog; QPushButton *ok; QPushButton *cancel; QPushButton *all; QPushButton *none; QPushButton *invert; QPushButton *search; QLabel prompt; int how; bool has_glyphs; int pressed; bool was_sel; }; class NetHackQtTextListBox; class NetHackQtRIP : public QWidget { private: static QPixmap *pixmap; char **line; int riplines; public: NetHackQtRIP(QWidget *parent); void setLines(char **l, int n); protected: virtual void paintEvent(QPaintEvent *event); QSize sizeHint() const; }; class NetHackQtTextWindow : public QDialog, public NetHackQtWindow { Q_OBJECT public: NetHackQtTextWindow(NetHackQtKeyBuffer &); ~NetHackQtTextWindow(); virtual QWidget *Widget(); virtual void Clear(); virtual bool Destroy(); virtual void Display(bool block); virtual void PutStr(int attr, const char *text); virtual void UseRIP(int how, time_t when); public slots: void Search(); protected: virtual void done(int); virtual void keyPressEvent(QKeyEvent *); private slots: void doUpdate(); private: NetHackQtKeyBuffer &keysource; bool use_rip; bool str_fixed; QPushButton ok; QPushButton search; NetHackQtTextListBox *lines; NetHackQtRIP rip; }; class NetHackQtMenuOrTextWindow : public NetHackQtWindow { private: NetHackQtWindow *actual; NetHackQtKeyBuffer &keysource; public: NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer &); virtual QWidget *Widget(); // Text virtual void Clear(); virtual bool Destroy(); virtual void Display(bool block); virtual void PutStr(int attr, const char *text); // Menu virtual void StartMenu(); virtual void AddMenu(int glyph, const ANY_P *identifier, char ch, char gch, int attr, const char *str, bool presel); virtual void EndMenu(const char *prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); }; class NetHackQtDelay : QObject { private: int msec; public: NetHackQtDelay(int ms); void wait(); virtual void timerEvent(QTimerEvent *timer); }; class NetHackQtInvUsageWindow : public QWidget { public: NetHackQtInvUsageWindow(QWidget *parent); virtual void paintEvent(QPaintEvent *); private: void drawWorn(QPainter &painter, obj *, int x, int y, bool canbe = TRUE); }; // This class is the main widget for NetHack // // It is a collection of Message, Map, and Status windows. In the current // version of nethack there is only one of each, and this class makes this // assumption, not showing itself until all are inserted. // // This class simply knows how to layout such children sensibly. // // Since it is only responsible for layout, the class does not // note the actual class of the windows. // #ifndef KDE #include "qt_kde0.h" #endif class NetHackQtMainWindow : public KTopLevelWidget { Q_OBJECT public: NetHackQtMainWindow(NetHackQtKeyBuffer &); void AddMessageWindow(NetHackQtMessageWindow *window); void AddMapWindow(NetHackQtMapWindow *window); void AddStatusWindow(NetHackQtStatusWindow *window); void RemoveWindow(NetHackQtWindow *window); void updateInventory(); void fadeHighlighting(); public slots: void doMenuItem(int); void doKeys(const QString &); protected: virtual void resizeEvent(QResizeEvent *); virtual void keyPressEvent(QKeyEvent *); virtual void keyReleaseEvent(QKeyEvent *event); virtual void closeEvent(QCloseEvent *); private slots: void layout(); void raiseMap(); void zoomMap(); void raiseMessages(); void raiseStatus(); private: void ShowIfReady(); #ifdef KDE KMenuBar *menubar; #else QMenuBar *menubar; #endif NetHackQtMessageWindow *message; NetHackQtMapWindow *map; NetHackQtStatusWindow *status; NetHackQtInvUsageWindow *invusage; NetHackQtKeyBuffer &keysink; QWidgetStack *stack; int dirkey; const char **macro; }; class NetHackQtYnDialog : QDialog { Q_OBJECT private: const char *question; const char *choices; char def; NetHackQtKeyBuffer &keysource; protected: virtual void keyPressEvent(QKeyEvent *); virtual void done(int); private slots: void doneItem(int); public: NetHackQtYnDialog(NetHackQtKeyBuffer &keysource, const char *, const char *, char); char Exec(); }; #ifdef KDE #define NetHackQtBindBase KApplication #elif defined(QWS) #define NetHackQtBindBase QPEApplication #else #define NetHackQtBindBase QApplication #endif class NetHackQtBind : NetHackQtBindBase { private: // Single-instance preservation... NetHackQtBind(int &argc, char **argv); static NetHackQtBind *instance; static NetHackQtKeyBuffer keybuffer; static NetHackQtClickBuffer clickbuffer; static QWidget *splash; static NetHackQtMainWindow *main; public: static void qt_init_nhwindows(int *argc, char **argv); static void qt_player_selection(); static void qt_askname(); static void qt_get_nh_event(); static void qt_exit_nhwindows(const char *); static void qt_suspend_nhwindows(const char *); static void qt_resume_nhwindows(); static winid qt_create_nhwindow(int type); static void qt_clear_nhwindow(winid wid); static void qt_display_nhwindow(winid wid, BOOLEAN_P block); static void qt_destroy_nhwindow(winid wid); static void qt_curs(winid wid, int x, int y); static void qt_putstr(winid wid, int attr, const char *text); static void qt_display_file(const char *filename, BOOLEAN_P must_exist); static void qt_start_menu(winid wid); static void qt_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P ch, CHAR_P gch, int attr, const char *str, BOOLEAN_P presel); static void qt_end_menu(winid wid, const char *prompt); static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list); static void qt_update_inventory(); static void qt_mark_synch(); static void qt_wait_synch(); static void qt_cliparound(int x, int y); static void qt_cliparound_window(winid wid, int x, int y); static void qt_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph); static void qt_raw_print(const char *str); static void qt_raw_print_bold(const char *str); static int qt_nhgetch(); static int qt_nh_poskey(int *x, int *y, int *mod); static void qt_nhbell(); static int qt_doprev_message(); static char qt_yn_function(const char *question, const char *choices, CHAR_P def); static void qt_getlin(const char *prompt, char *line); static int qt_get_ext_cmd(); static void qt_number_pad(int); static void qt_delay_output(); static void qt_start_screen(); static void qt_end_screen(); static void qt_outrip(winid wid, int how, time_t when); static int qt_kbhit(); private: virtual bool notify(QObject *receiver, QEvent *event); }; #endif nethack-3.6.0/include/qt_xpms.h0000664000076400007660000012354612536476415015454 0ustar paxedpaxed/* clang-format off */ /* pixels */ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX@$ @XXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXX$$+#X$ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXXX@$#o @XXXXXXXXX", "XXXXXXXXXXXXXXXXXX$XX OXXXXXXXX", "XXXXXXXXXXXXXXXXX@ # $@$ $XXXXXXXX", "XXXXXXXXXXXXXXXXX@.+ $XXXO @XXXXXXX", "XXXXXXXXXXXXXXXXX O@ XXXXX@ @XXXXXXX", "XXXXXXXXXXXXXXXXX @O $XXXXX@$ @XXXXXXX", "XXXXXXXXXXXXXXXXX O+ @XXXXO++ @XXXXXXX", "XXXXXXXXXXXXXXXXX @+ $@OXO$#$ XXXXXXXX", "XXXXXXXXXXXXXXXXX O@ $ @$Xo $XXXXXXXX", "XXXXXXXXXXXXXXXXX +O $X##+ $XXXXXXXXX", "XXXXXXXXXXXXXXXXX +@ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXX oO $XXXXXXXXXXX", "XXXXXXXXO@@@@@ +# $XXXXXXXXXXXX", "XXXXXXO +o########$ $@XXXXXXXXX", "XXXXXX +#+.$XXXXXXXX", "XXXXXX @O @XXXXXXX", "XXXXXX$ $@ $@@$ @XXXXXXX", "XXXXXXX@@@@XXXXXX + @XXXX@$ OXXXXXXX", "XXXXXXXXXXXXXXXX@ # @XXXXXXX@@OXXXXXXXX", "XXXXXXXXXXXXXXXX@.+ @XXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX$O@ XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX @O XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX #$ @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # OXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@.X XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX ++ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @+ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX O@ @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX +O @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX$ OXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX@@OXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ static const char *cns_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #F85848", "X c #949E9E", "o c #F8B090", "O c #E00028", "+ c #7C3400", "@ c None", "# c #B0B0B0", "$ c #F82C24", "% c #F89E6C", "& c #FF0000", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #C80050", "> c #CEAA90", ", c #303030", "< c #FFB691", /* pixels */ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@.oo.o$ ;@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@>.o.%%O,@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@$oo.o. ,@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@.oo$oo+ =@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@..o&oo$ ,@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@#.o.oo. =@.$%@@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o..oo& O.%ooo@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.&%o.$oo%O++;@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.+$%$o.@@@@@@@@@@@", "@@@@@@@@@@@@@.oo++o%$$ ,@@$.oo@@@@@@@@@@", "@@@@@@@@@@@@>.oo+Oo$o%.@@$oo..-@@@@@@@@@", "@@@@@@@@@@@@..o%;.o&%.$..o%O ++>@@@@@@@@", "@@@@@@@@@@@@>.$O:%o.O::::O* $oooo@@@@@@@", "@@@@@@@@@@@@::::::$$:OO&OO::oo%.;=@@@@@@", "@@@@@@@@@@@.::::::::O&&&&&O::++ ,@@@@@@", "@@@@@@@@@@>:::O&&OO&&&&&&&&:: ;@@@@@", "@@@@@@@@@@=::O&&&&&O:O&&&&&O: ,=@@@@@@@", "@@@@@@@@@@:::&&&&&&&&:&&&&&O: ;@@@@@@@@", "@@@@@@@@@@::O&&&&&&&&:&O&&&O:, ;@@@@@@@@", "@@@@@@@@@@::O&&&&O&O&OO&O&&O:+ ;@@@@@@@@", "@@@@@@@@@@::&&&O&&&&&O:&&&&O:, @@@@@@@@", "@@@@@@@@@@::O&&&&&O&&&:O&O&::+ @@@@@@@@", "@@@@@@@@@@::O&&O&&&&O&OO&&&:: @@@@@@@@", "@@@@@@@@@@=::O&&&&O&&&O:&&&:: @@@@@@@@", "@@@@@@@@@@.:::O&&O&&&&&:&OO:: @@@@@@@@", "@@@@@@@@@@@:::::&&&&O&O:&&O:, @@@@@@@@", "@@@@@@@@@@.>:::::O&&&&&:&&::+ ;@@@@@@@@", "@@@@@@@@@@>.<::::O&&O&O:&&:: @@@@@@@@@", "@@@@@@@@@@@.o%,:::O&&&O:&O:, @@@@@@@@@", "@@@@@@@@@@@$o. :::OO&OO&::, ;@@@@@@@@@", "@@@@@@@@@@@&o%+ ,::O&OO&O:: =@@@@@@@@@", "@@@@@@@@@@@.oo+ :::OO::: ,@@@@@@@@@@", "@@@@@@@@@@@..oO +::::: =@@@@@@@@@@", "@@@@@@@@@@@@.<.+ ,+, ,@@@@@@@@@@@", "@@@@@@@@@@@@Oo<+ @X, ,@@@@@@@@@@@@", "@@@@@@@@@@@@.%o$ @@@@@;, ;@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o., =@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" }; /* XPM */ static const char *confused_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO", "OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO", "OOOOOOOOOOO+=.=====.=++++===OO==+O=+OOOO", "OOOOOOOOOOO=+===.+=o==o===+&OoO======OOO", "OOOOOOOO+O+====OO+=o&&&&Oo==o&oO+==+=.O.", "OOOO+.+=+O==+&&o=oooOo&o&ooo=&oooO==O=+=", "OOOOOOOO++O===oo=oo&=&o&&oo=o==&o+==++==", "OOOOOOOO=o.=O====o&OO&o&oo&o&&oo=======O", "OOOOOOOo===+=O=O=ooO=ooooOOo=o&O=====OOO", "OOOOOOOOO+==+=======O=oo====O=o=O===+OOO", "OOOOOOOOO.=#=X=+====O========O======OOOO", "OOOOOOO.#Xo++.=#%====O==========OO==+OOO", "OOOOOO+Xo#+#+.#=.==X====+====O=+=+==+OOO", "OOOOO.+.+O===##.#=X.====oX##===o+OO.OOOO", "OOOOO#+####O#O##o.#+==#X#O#+...=OOo=+OOO", "OOOO++#o+#+X++++#.#O.#+#X.#+X+==+OO=oOOO", "OOOO#+.+..X+.##X++#++#..+XX#+##+..OOOOOO", "OOOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOO", "OOOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOO", "OOOOO#+#+.+++#++.+++##+X###+X+X##+**OOOO", "OOOOO#..#OO#+.##o###.+..++.+#X+#+#* @OOO", "OOOOO+#.#O+#+#O.+++.###+##++###+.#* $OOO", "OOOOOOXX+#+#+#o..X##++#+..##.#+### *OOO", "OOOOOOOX#.#X+#+#+#+.#+..+####%XX%% OOO", "OOOOOOOO.%%X.#+#+#.++#+#+#+.X++=.% *OOO", "OOOOOOOOO.* *##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX=.+++#X $OOO", "OOOOOOOOOOOO.* %%X..#X%=.####%X* $OOO", "OOOOOOOOOOOOOO.$ *XX%%%=.#X%###=* OOOO", "OOOOOOOOOOOOOOOOOO+%%%=%%#.+.#=* @OOOO", "OOOOOOOOOOOOOOOOOOo=%%%==X##X%* OOOOO", "OOOOOOOOOOOOOOOOOOO+X%%%%X=%* @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X *@OOOOOO", "OOOOOOOOOOOOOOOOOOOO=%%%X* *$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%= .OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%% OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO" }; /* XPM */ static const char *dex_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #B64700", "* c #909090", "= c #606060", "- c #CEAA90", "; c #DADAB6", ": c #303030", "> c #F86800", ", c #FFB691", "< c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "###############-%-######################", "##############-%X<-#####################", "#########-<<-#-%XX+==###################", "#########%,X< :<,X%@ :##################", "#########-XX%: @;X%+ *#################", "##########<,X& :<<%+: :#################", "######->+#-%%%: <,XX@ #################", "######%X%@ <,,& @XXX+ :++-#############", "######-: +XX+ #########", "#####+%%@@,X%<,XXXXXXX<:@XXX<: =########", "####$%XX< <,<,XX& ########", "#####$%<%X@%XXXX<%XX< =#######", "#######<;X%XXXXX<<,XXXXXX%,XXXXXXXXX%@ #######", "##########- c #788C8C", ", c #606060", "< c #406868", "1 c #C80050", "2 c #FFFFFF", "3 c #FFFF00", "4 c #00B6FF", "5 c #CEAA90", "6 c #DADAB6", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$353333335*$$$$$$$$$$$$$$$", "$$$$$$$$$$$$*33333333#7@3335$$$$$$$$$$$$", "$$$$$$$$$65333333333@7777#333*$$$$$$$$$$", "$$$$$$$$$3333333333377777733333===%$$$$$", "$$$$$$$533333333333#7777777333%=====$$$$", "$$$$$$ #3333333333o>7777773330======%$$$", "$$$$5---O#33333o3944077777333*=======$$$", "$$$$-----O333333>4444.77333330======%$$$", "$$$ ---O--;3333344444443333333:====5$$$$", "$$$ O-----733333444444433333333 ==035$$$", "$$$3--O--O333333>44444>33333333333333$$$", "$$533---O33333333944493333#333333333356$", "$$33867733333o33333:o333333o3333333333$$", "$532+2233333#333333333333oooo3#3333333%$", "6522222+33333333333333333oooooo33o3333*$", "$+22+22263333333o3333333ooooooo333333356", "662222+2533333333333333#ooooooo33333333$", "$32+22223333o3#33333o333ooooooo3#333333%", "$33222233333333333#333333ooooo333333333$", "$33368333333333333330626*oooo#333333o33%", "%333335== 33oo333333222223#333333333333$", "$3333=====:ooooo333+22+2263333333.>o333%", "$5333=====oooooo33322222223333339444935$", "$*33 ====>ooooooo3362+222633333.44444>3$", "$%330====:ooooooo333222+23333334444444$$", "$$333177 =oooXoo#333*626333333;4444444$$", "$$53##777&3oooo3333333333333#--,444449$$", "$$$3;77777#3o333333333333333O---94449$$$", "$$%*@77777#33333333333333337O----O:o3$$$", "$$$5777777333 333333333333;---O-O73$$$$", "$$$$#7777730====#:.,33333333------3$$$$$", "$$$$$577333=====qqqq<0333333#O---35$$$$$", "$$$$$%53335====qqqqqq.33o333337735$$$$$$", "$$$$$$$533 ====qqqqqqq3333333333%$$$$$$$", "$$$$$$$$%33====qqqqqqq333333333%$$$$$$$$", "$$$$$$$$$$50===qqqqqq,3333333:$$$$$$$$$$", "$$$$$$$$$%6%5503,qqq<333#335%$$$$$$$$$$$", "$$$$$$$$$$$$$%$*53,03335o$%%$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$" }; /* XPM */ static const char *hungry_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 15 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO========OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO=============OOOOOOOOOOOOO", "OO;XX;@OOOOO================OOOOOOOO;XOO", "OO;%-;$OOOO==================OOOOOOO;XOO", "OO;-%;$OOO========@$#@========OOOOO+;;$O", "OO;%-;$OO=======- -*======*OOOO.;;$O", "OO;-%;$O======* @====.$$&=====@OOO.;;$O", "OO;X%;$O====== -========*@=====*.OO+;;$O", "OO;;;X$o====* -==========@======$OO;;;$O", "OO+;;-+o====- =============o====#@O+;;$O", "OOO;%$O===== @=============&====*$O;;;$O", "OOO+%OO====@ ==============&=====-OO;;$O", "OOo;-Oo====$ ==============o&==== OO;;$O", "OOO+%OO====@ ==============&===== O+;;#O", "OOO;-Oo====$-==============&&==== O+;;-O", "OOO;;+O=====$*============&&====* OO;;%+", "OOO;;$o=====$.============&&====X-OO;;$O", "OOO;;$O======*.===&======&&=====-$=O;;$O", "OOO;;$Oo=====.==========&&=====* @O+;;$O", "OOO;;$OO=======oo=====&&&======$-OOO;;$O", "OOO;;$OOo=======&o&&&&&&======$ @OOO;;$O", "OOO;;$OOOO========&=&========* $OOOO;;$O", "OO+;;$OOOOo=================* -OOOOO#;$O", "OOO;;$OOOOO=*==============@ -=OOOOO;;$O", "OOO;;$OOOOOOO+*==========*- $OOOOOOO;;$O", "OOOX-$OOOOOOOO@X@*====*#- -.OOOOOOOOX-$O", "OOOOOOOOOOOOOO=*@$- -$.=OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO=O==O=O=OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *hvy_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO", "OOOOOOOOOOOo==============X*OOOOOOOOOOOO", "OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO", "OOOOOOOOOO&============X===% $OOOOOOOOOO", "OOOOOOOOOoo===*%====***%===%* OOOOOOOOOO", "OOOOOOOOOoO==% %===* %==X* @OOOOOOOOO", "OOOOOOOOO&===% *==% X==**===% $OOOOOOOOO", "OOOOOOOOoo===% %==% ===% ===X OOOOOOOOO", "OOOOOOOOoO==== *== *==== *==X* @OOOOOOOO", "OOOOOOOO&===== %== %==== %===% $OOOOOOOO", "OOOOOOOoo===== *== *==== *===%* OOOOOOOO", "OOOOOOOoO===== %==% ===* ====X* @OOOOOOO", "OOOOOOO&===X== *==% X==**=====% $OOOOOOO", "OOOOOOoo===== *==* %=====X OOOOOOO", "OOOOOOoO=====*%%X===*%*X======%* @OOOOOO", "OOOOOOo====================X===* $OOOOOO", "OOOOOOO=%X%XXXX%XXXXXXXXX%X=%X% OOOOOO", "OOOOOOO.=********************** OOOOOO", "OOOOOOOOO OOOOOO", "OOOOOOOOO. @OOOOOO", "OOOOOOOOOOOoOOoOoOoOoOoOoOOoOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *int_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOO+#.X.##@#OOOOOOOOOOOOOOOOOO", "OOOOOOOO+##@X#O++.#+#.##OOOOOOOOOOOOOOOO", "OOOOOO+#Xo++#X#%#+##o#O#.#+OOOOOOOOOOOOO", "OOOOO.Xo#+#++##+.XX#..+.+..XOOOOOOOOOOOO", "OOOO++.+O.+O##+#.X###..OX#.+X+OOOOOOOOOO", "OOOO#+####O#O##o##+###X#+#+.#..OOOOOOOOO", "OOO.+#o+#+X++++#.#O+#+#X.#+X++X+OOOOOOOO", "OOO.+.+..X+.##X++#++#..+XX#+#X+..OOOOOOO", "OOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOOO", "OOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOOO", "OOOO#+#+.+++#++.+++##+X###+X+X##+&&OOOOO", "OOOO#..#OO#+.##o###.+..++.+#X+#+#& @OOOO", "OOOO.#.#O+#+#O.+++.###+##++###+.# $OOOO", "OOOOOXX+#+#+#o..X##++#+..##.#+### &OOOO", "OOOOOOX#.#X+#+#+#+.#+..+####XX%X% OOOO", "OOOOOOO.%%X.#+#+#.++#+#+#+.%++*+% &OOOO", "OOOOOOOO@& &##+#+.O####.+XXX%%%#% $OOOO", "OOOOOOOOOO. %X.+.#+++XXX*.+++#% $OOOO", "OOOOOOOOOOO@& %%X..#XXX.####%%& $OOOO", "OOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOOO", "OOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOOO", "OOOOOOOOOOOOOOOOOO*%%%*.X##XX& OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%X*%& @OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%% &@OOOOOOO", "OOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+%%%* .OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+*%%% OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *lawful_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 10 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #606060", "$ c #FFFFFF", "% c #303030", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOo$$$$$$oOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO$$o$$o$$$$$OOOOOOOOOO", "OOOOOOOOOOOOOOOOOOo$$$$$$$o$$ooOOOOOOOOO", "OOOOOOOOOOOOOOOOOO$o$$$o$$$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$$+ .o$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$+%OOOO$o$$$oOOOOOOO", "OOOOOOOOOOOOOOOOO$$o$X@OOOOo$$$ooOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$%OOOOOo$$$..OOOOOOO", "OOOOOOOOOOOOOOOOO$$$$@OOOOo$$oo##OOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$ooOoo$$$o OOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$o$$$$o#%OOOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$o$$$$$o@%OOOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$$o$o.%OOOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$o$$oo@#%OOOOOOOOOOO", "OOOOOOOOoooooo$$$$$$$$$$$% %OOOOOOOOOOOO", "OOOOOOO$$$$$$$$$$$$o$$o$$$$$$$oOOOOOOOOO", "OOOOOO$$$$$$$$$o$$$$$$$$$$$$o$$oOOOOOOOO", "OOOOOO$$o$ooooo##+o$$+##@oo$$$$$oOOOOOOO", "OOOOOOo$$#% %#$$$+%##%%#ooo$O#OOOOOOO", "OOOOOOOo@##OOOOO+$$$##OOOO#%%##%@OOOOOOO", "OOOOOOOOOOOOOOOOo$$$##OOOOOOO##@OOOOOOOO", "OOOOOOOOOOOOOOOOo$$o##OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+$$$o OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$o$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o%@OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$o##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$# @OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO.#@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *mod_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOo&&&&&&&&&oXOOOOOOOOOOOOOOO", "OOOOOOOOOOOO+&=========X%@OOOOOOOOOOOOOO", "OOOOOOOOOOOOO&=====X====% @OOOOOOOOOOOOO", "OOOOOOOOOOOOoO==X=======X* OOOOOOOOOOOOO", "OOOOOOOOOOOO&====*%*%*===* $OOOOOOOOOOOO", "OOOOOOOOOOO+&===X ===% *OOOOOOOOOOOO", "OOOOOOOOOOOoO===**=======X* OOOOOOOOOOOO", "OOOOOOOOOOO&===% %=======X% $OOOOOOOOOOO", "OOOOOOOOOOO&===% %*%%=====% *OOOOOOOOOOO", "OOOOOOOOOOoO===* ====X* OOOOOOOOOOO", "OOOOOOOOOO&=========* X===X% $OOOOOOOOOO", "OOOOOOOOO+&=========% *====% *OOOOOOOOOO", "OOOOOOOOOoO===% %=== %====%* OOOOOOOOOO", "OOOOOOOOO&====* *==X===% $OOOOOOOOO", "OOOOOOOOO&======*%*%X=======% *OOOOOOOOO", "OOOOOOOOOo==X===============% OOOOOOOOO", "OOOOOOOOO=XXXXXXXXXX%X%X%X%%% $OOOOOOOO", "OOOOOOOOOO=%**************** $OOOOOOOO", "OOOOOOOOOOO$ $OOOOOOOO", "OOOOOOOOOOOO* *OOOOOOOOO", "OOOOOOOOOOOOOoOOoOoOoOoOoOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *neutral_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #00B6FF", "= c #303030", "- c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO.------.OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO-+O&o.-----OOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+-&o--------.OOOOOOOOO", "OOOOOOOOOOOOOOOOOO-oo----------+OOOOOOOO", "OOOOOOOOOOOOOOOOO+-&--% #-------OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-X=OOO.-----+OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-%#OOOO.-----OOOOOOO", "OOOOOOOOOOOOOOOOO--O-=OOOOO+---X#OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-XOOOO+OO--=$OOOOOOO", "OOOOOOOOOOOOOOOOO-OO--++OO-&--- OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-----+oo--%=OOOOOOOO", "OOOOOOOOOOOOOOOOO--O--+o&&o--%=OOOOOOOOO", "OOOOOOOOOOOOOOOOO-oo*-------%=OOOOOOOOOO", "OOOOOOOOOOOOOOOOO-oO------%%=OOOOOOOOOOO", "OOOOOOOO+.+-+.---O&------= =OOOOOOOOOOOO", "OOOOOO+-oo&&&&&&&&------------.OOOOOOOOO", "OOOOOO---------------X-----O&Oo-OOOOOOOO", "OOOOOO---------%=%---%%=%----OO-.OOOOOOO", "OOOOOO---== =%---%=%%===----%XOOOOOOO", "OOOOOOO-#$%OOOOOO-+-%$OOOO%===%=@OOOOOOO", "OOOOOOOOOOOOOOOO.-&-=%OOOOOOO%%#OOOOOOOO", "OOOOOOOOOOOOOOOo-O+-%$OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%%OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-=$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--o-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+-&- .OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-Oo- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO%%OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-o-%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO---%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--% #OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOX$@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *ovr_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOoO+=+OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOo=#===+OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo=.OO@X=OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo#OO* #X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+=.XX+=#* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO+=O=.=OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO#.=+OO@ $OOOOOOOOOOOOOO", "OOOOOOOOOooooooooo&O.#+#XooooOOOOOOOOOOO", "OOOOOOOOO&OOoOoOoOOOOOOOOOoO%@OOOOOOOOOO", "OOOOOOOOoO==================X*@OOOOOOOOO", "OOOOOOOO&===================X% @OOOOOOOO", "OOOOOOOO&==%*%*%*%*%*%*%*%*==% *OOOOOOOO", "OOOOOOOoO==%*%%*%%*%%*%*%*%==X* OOOOOOOO", "OOOOOOO&======================* $OOOOOOO", "OOOOOO+&=== ===% *OOOOOOO", "OOOOOOoO======================X* OOOOOOO", "OOOOOO&=======================X% $OOOOOO", "OOOOOOo========================% *OOOOOO", "OOOOOoO===*%X=====%%======%%===X* OOOOOO", "OOOOO&==% %==% *==== %==* $OOOOO", "OOOOO&== *==**== **% *=X% %%* ==% *OOOOO", "OOOOoO==%%==* =* ===% == %=== %=X* OOOOO", "OOOO&=======% =**===% %X %X==* =X% $OOOO", "OOOO&======% %= %==== %% ====* ==% *OOOO", "OOOoO=====% *== *==== %* ====% ==X* OOOO", "OOO&====XX *===**===% X% X=== *===* $OOO", "OO+&====X *====* ===% == *=== %===% *OOO", "OOoO===% %*%*== *** %==% %** ====X* OOO", "OO&====% ==X *====* %====X% $OO", "OO&================================% *OO", "OOo===X============================% OO", "OO=XXXXXXXXXXXX%XXXX%X%X%XXXXX%X%X%% $O", "OOO=%****************************** $O", "OOOO$ $O", "OOOOO* *OO", "OOOOOOOOOOoOOoOOoOOoOOoOOoOOoOOoOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *pet_mark_xpm[] = { /* width height ncolors chars_per_pixel */ "8 7 2 1", /* colors */ ". c None", " c #FF0000", /* pixels */ "........", ".. . .", ". ", ". ", ".. .", "... ..", ".... ..." }; /* XPM */ static const char *pet_mark_small_xpm[] = { /* width height ncolors chars_per_pixel */ "5 5 2 1", /* colors */ ". c None", "X c #FF0000", /* pixels */ ".X.X.", "XXXXX", ".XXX.", "..X.." }; /* XPM */ static const char *satiated_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #914700", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #406868", "> c #FFFFFF", ", c #CEAA90", "< c #DADAB6", "1 c #303030", "2 c #FFB691", "3 c #6C91B6", "4 c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "################<<<<<<<<################", "##############<<<<<<<<<<$#$$$###########", "############<<<<<<<<<<$:31:3:###########", "###########<<<<<<%42<<#:3:133-##########", "##########<<<<<%<<;;=o$131:33;##########", "#########<<<<<<,1 ::31:33;,#########", "########<<<<<<, =<<<<.13:133;<=########", "########<<<%2, 1<<<<<<#333:33;<,=#######", "#######<<<3-=<33;<<@o######", "#######O<<<<<,#<<<<<<<<.3:<3-;<, =######", "########<<<<2<<<<<<<<<>#31<33o<11#######", "########O<<<<44<>O>>>>>#3:<3.;- =#######", "##########<<<4<<<<><><<$3:<331 ;<#######", "##########<<<<<<<%2<<<<$3:<33 1#########", "###########O,<<<<<<<<<<#31<331##########", "#############.<<<<<<<<<$3:133;##########", "##############=;=,<<<<,o 1;;=##########", "###############<=;1 1;=##############", "#################<# c #B64700", ", c #909090", "< c #788C8C", "1 c #606060", "2 c #406868", "3 c #FFFFFF", "4 c #CEAA90", "5 c #DADAB6", "6 c #303030", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "****************************************", "*************#333333333#****************", "***********##33333#333333#**************", "**********#33333#33333#33*==************", "*********#33##33-;-3#3333399************", "********#33#33#3-@ 33333#33=.***********", "********#3*#33-;;;;;-33333#99***********", "*******#3*3333-;;;;@ 33#333#9=**********", "*******#333#33#3-;-33#*##33399**********", "******#3#3333333-@-#333#9933*9=*********", "******#333#33#3333333#333*9999=*********", "******#333333333#3#33333333*999*********", "******#3#33#33333333#33#3333#9=*********", "******#333334>&&:&&>::44,3#33#9*********", "******#33*::&41OOO6:4O 0::4433=*********", "******#3:>,0:O0O1O+O:OXO,O+2+OOo4<+1104:>:#*********", "******.&:1OOO,14X2O48:O80,440:,*********", "******4::>OOO%8-X4O4%O,84+O0X&>=********", "******.::>,O 99*X+<$,+.o*1O4&0:*********", "******>:0&4O5qq9#10OO3qq9,+X:1:*********", "****=>,,::,O4qq9X+O>O-qq9O2X0,>*********", "******4:>OOOO48882OOOO+4OOO07*4*********", "******4*,4OO+OXX3O5************", "*********=0%,OO,>:>>O +1OO4*************", "**********=%+OO:::1:::6+:7**************", "***********7&OO:O+O,O1OO+1**************", "***********40OO,O4:OOO11O<5*************", "**********=4 +O1O2+O2+O0O***************", "************72O+1+21-OOO%5**************", "************0%1OOOO+O+174***************", "*************%%O,OO1407-=***************", "**************-$>%0%:74*****************", "****************54044*=*****************", "*****************=*=********************" }; /* XPM */ static const char *sick_il_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #FF0000", "* c #914700", "= c #B64700", "- c #909090", "; c #606060", ": c #FFFFFF", "> c #CEAA90", ", c #DADAB6", "< c #F86800", "1 c #FFB691", "2 c #6C91B6", "3 c #F88C48", "4 c #0000FF", /* pixels */ "########################################", "#############O:::::::::O################", "###########OO:::::O::::::O##############", "##########O:::::O:::::O::#$$############", "#########O::OO::%&%:O:::::22############", "########O::O::O:%o :::::O::$.###########", "########O:#O::%&&&&&%:::::O22###########", "#######O:#::::%&&&&o ::O:::O2$##########", "#######O:::O::O:%&%::O#OO:::22##########", "######O:O:::::::%o%O:::O22::#2$#########", "######O:::O::O:::::::O:::#2222$#########", "######O:::::::::O:O::::::::#222#########", "######O:O::O::::::::O::O::::O2$#########", "######O:::::>=@@=**=**>>-:O::O2#########", "######O::#**@3>%* ;=>=3;<@>>::$#########", "######O:** >=>XXXX1X >>+>%*%*;O#########", "######O3@*,X%XXXXXXX>X%XX >*=*O#########", "######.@@3XXXXXXXXXXXXXXX>X>3*-#########", "######>***>X% >XXXXX3XXXXXX%>*=>########", "######.***> 22#XXX<%X22#XXX@+;#########", "######=*3@X>O442OXX==%XX11111O1+%X111XX%<#>#########", "######.,;XXXXXX1O1X%3XXXXX%+3###########", "########3=XXXXXX:XXXXXXXXX+<>$##########", "########>+XXXXXX%-3->XXXX%+<############", "#########%3XXXXXX>- -%XXX%<%$###########", "#########$############", "##########+%XXXXXXXXXXXX%+<#############", "##########%3XXX>=****3XX%<%#############", "##########>+XXX**=3-*@3>3+##############", "###########<%XX >XX%X;%X3+##############", "###########%3XX>XX++XXXX<%$#############", "##########$>+XXXXXXXXXXX<###############", "############<%XXXXXXXXX3+###############", "###########$%+XXXXXXXX%<>###############", "#############++XXXXXX%<%$###############", "#############$%<<3333<%#################", "#################%3>>$##################", "#################$#$####################" }; /* XPM */ static const char *slt_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO&&&&&&&X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo======X*OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOoO======X**OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO&====X===% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoo==%* %==%* OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoO=% % =X* @OOOOOOOOOOOOO", "OOOOOOOOOOOOO&==**==% %=% $OOOOOOOOOOOOO", "OOOOOOOOOOOOoo==%%==* %=X OOOOOOOOOOOOO", "OOOOOOOOOOOOoO=====* X==X* @OOOOOOOOOOOO", "OOOOOOOOOOOO&=====* %====% $OOOOOOOOOOOO", "OOOOOOOOOOOoo==== X=====%* OOOOOOOOOOOO", "OOOOOOOOOOOo+===* *%*%%==X* @OOOOOOOOOOO", "OOOOOOOOOOO&==== %===% $OOOOOOOOOOO", "OOOOOOOOOOO&==============% OOOOOOOOOOO", "OOOOOOOOOOO==============X% @OOOOOOOOOO", "OOOOOOOOOOO+%%%%%%%%%%%%%% $OOOOOOOOOO", "OOOOOOOOOOOOO% $OOOOOOOOOO", "OOOOOOOOOOOOO@ @OOOOOOOOOO", "OOOOOOOOOOOOOO@$$$$$$$$$$$$$@OOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *str_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 17 1", /* colors */ " c #000000", ". c #F8B090", "X c #5C7A7A", "o c #F87A24", "O c #7C3400", "+ c None", "@ c #B0B0B0", "# c #F89E6C", "$ c #B64700", "% c #909090", "& c #606060", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #F86800", ": c #FFB691", "> c #F88C48", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++++++*>*>#++++++++++++++++", "++++++++++++++++*#o>..*#o*++++++++++++++", "+++++++++++++++o#.#>.....o++++++++++++++", "+++++++++++++++;>;#.o.>..#$X++++++++++++", "+++++++++++++++o#>.o.>:...o %++++++++++", "++++++++++++++o##>>#o##>..#O -++++++++++", "++++++++++++++>#.oo#>..>...O ++++++++++", "++++++++++++++*o##.>>;o#...o ++++++++++", "+++++++++++++++*;o#........>- &+++++++++", "+++++++++++++++++#>>;o......O -+++++++++", "+++++++++++++++++@+@+o>.....$ +++++++++", "+++++++++++++++++++++*;.#...>- %++++++++", "++++++++++++++++++++++;>o....$ &++++++++", "++++++++++++++++++++++#>>....>- %+++++++", "+++++++++++++++++++++++;#>....; -+++++++", "+++++++++++++++++++++++o#>....>O %++++++", "+++++++++++++++++++++++*>o.....; -++++++", "+++++++++++++#>**+++++++;#.....>O %+++++", "+o#+++++++*o;>>>>o#+++++o##.....; -+++++", "+:#o*++++oo#..*..*>;*+++#>#.....>O %++++", "+:=#o#+*;>.:==:....#;*++@o.......; &++++", "+::..>;o#.=::::......o*++;.......>O ++++", "+.....#o.:.=:.........o#+;........$ ++++", "+......#o..:...........#o;>.......o &+++", "+........#..............*>o......:o- +++", "+..................#o>#...#o.......O +++", "+...............>o>#.......#>......O &++", "+..................................o -++", "+..................................> ++", "+..................................> ++", "+.................................#$ &+", "+................................>$ &+", "+..#>$o>#..............#>;>>>oOOO- ++", "+...#O OOOOO$>>>>>>>$OO %++", "+...o -&&++++", "+..#O -&&%++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static const char *stunned_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOO&$OOOO@OOO@@OO@OOOOOOOOOOOOO", "OOOOOOOOOOO@& $OO@&&$$@ O@$$OOOOOOOOOOOO", "OOOOOOOOOOOO$$ @@@$ &&OOO@$OOOOOOOOOOOO", "OOOOOOOOOOOOO@@&$$$$&O$OO$O &@O@OOOOOOOO", "OOOOOO@@@@@@OO@$$O$&$@@OO& &&$O&OOOOOOO", "OOOOOO&&&& & $ &&@$ &O@$& &&&$ & $OOOOOO", "OOOOOO$&OO &&&$ $$ $& $$&$&&&OOOOOOO", "OOOOOO@@O@$ &+ # &O$$ $$&O@OOOOO", "OOOOOOOO@X%$ %& %% & && $$@@@@OOOO", "OOOOOOO+$$@+ &%%%&%& & &@OOO&&OOO", "OOOOOO.Xo%+ &&%%%%%&& & OO@$&&OOO", "OOOOO++ $$&&$ && %&%%& &O@&$&OOOO", "OOOOO####$ X&&& && &%& & &&OOOO", "OOOO++#.+## $&# %& & & &$ OOOO", "OOOO#+++.@&%&& &#&%& & $ @OOOOOO", "OOOO##....#+$#@%#& $%$&@&$$% & X##$@OOOO", "OOOO.+#+.+@#+#+$&$X#%&%.+& %&#++.$&OOOOO", "OOOOO#+#+.+++#$$%&++&X+X#&#+&+&##+ &OOOO", "OOOOO#..#OO#+@%#o##X.@..++.+$&+#+#& @OOO", "OOOOO+#.#O+#+#O@++@$$##+##++###+.#& $OOO", "OOOOOOXX+#+#+#o.@%&$++#+..##.#+### &OOO", "OOOOOOOX#.#X+#+#+##&#+..+####%XX%% OOO", "OOOOOOOO+%%X.#+#+#.++#+#+#+.X++*.% &OOO", "OOOOOOOOO@& &##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX*.+++#X $OOO", "OOOOOOOOOOOO@& %%X..#X%#.####%X& $OOO", "OOOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOO", "OOOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOO", "OOOOOOOOOOOOOOOOOOO*%%%**X##X%& OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X*X& @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X &@OOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%* @OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%& OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO" }; /* XPM */ static const char *wis_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c None", "O c #B0B0B0", "+ c #909090", "@ c #788C8C", "# c #606060", "$ c #406868", "% c #FFFFFF", "& c #303030", "* c #6C91B6", "= c #0000FF", /* pixels */ "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooo+#& &#oooooooooooooooooooo", "oooooooooooo+& #oooooooooooooooooo", "ooooooooooo+ &====&& &ooooooooooooooooo", "oooooooooo+ &==& ===%& +ooooooooooooooo", "ooooooooo+&%=== ===%%o&&oooooooooooooo", "oooooooo.&%%===& ===%o& #+ooooooooooo", "oooo&###&&%%*=======$#&ooo#& #+oooooooo", "ooooo###o+&X$=====& #oo##oooo+######oooo", "oooooooooooo######@oo##ooooooooooooooooo", "oooooooooooooOoOoOo##ooooooooooooooooooo", "ooooooooooooooooo+#+ooo+&#oooooooooooooo", "ooooooooooooooooooooooo#oooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; /* clang-format on */ nethack-3.6.0/include/qtext.h0000664000076400007660000000606012536476415015115 0ustar paxedpaxed/* NetHack 3.6 qtext.h $NHDT-Date: 1432594167 2015/05/25 22:49:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) Mike Stephenson 1991. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QTEXT_H #define QTEXT_H #define N_HDR 16 /* Maximum number of categories */ /* (i.e., num roles + 1) */ #define LEN_HDR 3 /* Maximum length of a category name */ struct qtmsg { int msgnum; char delivery; long offset, size, summary_size; }; #ifdef MAKEDEFS_C /***** MAKEDEFS *****/ #define N_MSG 100 /* arbitrary */ struct msghdr { int n_msg; struct qtmsg qt_msg[N_MSG]; }; struct qthdr { int n_hdr; char id[N_HDR][LEN_HDR]; long offset[N_HDR]; }; /* Error message macros */ #define CREC_IN_MSG "Control record encountered during message - line %d\n" #define DUP_MSG "Duplicate message number at line %d\n" #define END_NOT_IN_MSG "End record encountered before message - line %d\n" #define TEXT_NOT_IN_MSG "Text encountered outside message - line %d\n" #define UNREC_CREC "Unrecognized Control record at line %d\n" #define MAL_SUM "Malformed summary in End record - line %d\n" #define DUMB_SUM "Summary for single line message is useless - line %d\n" #define CTRL_TRUNC "Control record truncated at line %d\n" #define TEXT_TRUNC "Text record truncated at line %d\n" #define OUT_OF_HEADERS \ "Too many message types (line %d)\nAdjust N_HDR in qtext.h and " \ "recompile.\n" #define OUT_OF_MESSAGES \ "Too many messages in class (line %d)\nAdjust N_MSG in qtext.h and " \ "recompile.\n" #else /***** !MAKEDEFS *****/ struct qtlists { struct qtmsg *common, #if 0 /* UNUSED but available */ *chrace, #endif *chrole; }; /* * Quest message defines. Used in quest.c to trigger off "realistic" * dialogue to the player. */ #define QT_FIRSTTIME 1 #define QT_NEXTTIME 2 #define QT_OTHERTIME 3 #define QT_GUARDTALK 5 /* 5 random things guards say before quest */ #define QT_GUARDTALK2 10 /* 5 random things guards say after quest */ #define QT_FIRSTLEADER 15 #define QT_NEXTLEADER 16 #define QT_OTHERLEADER 17 #define QT_LASTLEADER 18 #define QT_BADLEVEL 19 #define QT_BADALIGN 20 #define QT_ASSIGNQUEST 21 #define QT_ENCOURAGE 25 /* 1-10 random encouragement messages */ #define QT_FIRSTLOCATE 35 #define QT_NEXTLOCATE 36 #define QT_FIRSTGOAL 40 #define QT_NEXTGOAL 41 #define QT_FIRSTNEMESIS 50 #define QT_NEXTNEMESIS 51 #define QT_OTHERNEMESIS 52 #define QT_NEMWANTSIT 53 /* you somehow got the artifact */ #define QT_DISCOURAGE 60 /* 1-10 random maledictive messages */ #define QT_GOTIT 70 #define QT_KILLEDNEM 80 #define QT_OFFEREDIT 81 #define QT_OFFEREDIT2 82 #define QT_POSTHANKS 90 #define QT_HASAMULET 91 /* * Message defines for common text used in maledictions. */ #define COMMON_ID "-" /* Common message id value */ #define QT_ANGELIC 10 #define QTN_ANGELIC 10 #define QT_DEMONIC 30 #define QTN_DEMONIC 20 #define QT_BANISHED 60 #endif /***** !MAKEDEFS *****/ #endif /* QTEXT_H */ nethack-3.6.0/include/qttableview.h0000664000076400007660000001467112536476415016306 0ustar paxedpaxed/********************************************************************** ** $NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ ** $Id: qttableview.h,v 1.2 2002/03/09 03:13:13 jwalz Exp $ ** ** Definition of QtTableView class ** ** Created : 941115 ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file contains a class moved out of the Qt GUI Toolkit API. It ** may be used, distributed and modified without limitation. ** **********************************************************************/ #ifndef QTTABLEVIEW_H #define QTTABLEVIEW_H #ifndef QT_H #include #endif // QT_H #ifndef QT_NO_QTTABLEVIEW class QScrollBar; class QCornerSquare; class QtTableView : public QFrame { Q_OBJECT public: virtual void setBackgroundColor(const QColor &); virtual void setPalette(const QPalette &); void show(); void repaint(bool erase = TRUE); void repaint(int x, int y, int w, int h, bool erase = TRUE); void repaint(const QRect &, bool erase = TRUE); protected: QtTableView(QWidget *parent = 0, const char *name = 0, WFlags f = 0); ~QtTableView(); int numRows() const; virtual void setNumRows(int); int numCols() const; virtual void setNumCols(int); int topCell() const; virtual void setTopCell(int row); int leftCell() const; virtual void setLeftCell(int col); virtual void setTopLeftCell(int row, int col); int xOffset() const; virtual void setXOffset(int); int yOffset() const; virtual void setYOffset(int); virtual void setOffset(int x, int y, bool updateScrBars = TRUE); virtual int cellWidth(int col); virtual int cellHeight(int row); int cellWidth() const; int cellHeight() const; virtual void setCellWidth(int); virtual void setCellHeight(int); virtual int totalWidth(); virtual int totalHeight(); uint tableFlags() const; bool testTableFlags(uint f) const; virtual void setTableFlags(uint f); void clearTableFlags(uint f = ~0); bool autoUpdate() const; virtual void setAutoUpdate(bool); void updateCell(int row, int column, bool erase = TRUE); QRect cellUpdateRect() const; QRect viewRect() const; int lastRowVisible() const; int lastColVisible() const; bool rowIsVisible(int row) const; bool colIsVisible(int col) const; QScrollBar *verticalScrollBar() const; QScrollBar *horizontalScrollBar() const; private slots: void horSbValue(int); void horSbSliding(int); void horSbSlidingDone(); void verSbValue(int); void verSbSliding(int); void verSbSlidingDone(); protected: virtual void paintCell(QPainter *, int row, int col) = 0; virtual void setupPainter(QPainter *); void paintEvent(QPaintEvent *); void resizeEvent(QResizeEvent *); int findRow(int yPos) const; int findCol(int xPos) const; bool rowYPos(int row, int *yPos) const; bool colXPos(int col, int *xPos) const; int maxXOffset(); int maxYOffset(); int maxColOffset(); int maxRowOffset(); int minViewX() const; int minViewY() const; int maxViewX() const; int maxViewY() const; int viewWidth() const; int viewHeight() const; void scroll(int xPixels, int yPixels); void updateScrollBars(); void updateTableSize(); private: void coverCornerSquare(bool); void snapToGrid(bool horizontal, bool vertical); virtual void setHorScrollBar(bool on, bool update = TRUE); virtual void setVerScrollBar(bool on, bool update = TRUE); void updateView(); int findRawRow(int yPos, int *cellMaxY, int *cellMinY = 0, bool goOutsideView = FALSE) const; int findRawCol(int xPos, int *cellMaxX, int *cellMinX = 0, bool goOutsideView = FALSE) const; int maxColsVisible() const; void updateScrollBars(uint); void updateFrameSize(); void doAutoScrollBars(); void showOrHideScrollBars(); int nRows; int nCols; int xOffs, yOffs; int xCellOffs, yCellOffs; short xCellDelta, yCellDelta; short cellH, cellW; uint eraseInPaint : 1; uint verSliding : 1; uint verSnappingOff : 1; uint horSliding : 1; uint horSnappingOff : 1; uint coveringCornerSquare : 1; uint sbDirty : 8; uint inSbUpdate : 1; uint tFlags; QRect cellUpdateR; QScrollBar *vScrollBar; QScrollBar *hScrollBar; QCornerSquare *cornerSquare; private: // Disabled copy constructor and operator= #if defined(Q_DISABLE_COPY) QtTableView(const QtTableView &); QtTableView &operator=(const QtTableView &); #endif }; const uint Tbl_vScrollBar = 0x00000001; const uint Tbl_hScrollBar = 0x00000002; const uint Tbl_autoVScrollBar = 0x00000004; const uint Tbl_autoHScrollBar = 0x00000008; const uint Tbl_autoScrollBars = 0x0000000C; const uint Tbl_clipCellPainting = 0x00000100; const uint Tbl_cutCellsV = 0x00000200; const uint Tbl_cutCellsH = 0x00000400; const uint Tbl_cutCells = 0x00000600; const uint Tbl_scrollLastHCell = 0x00000800; const uint Tbl_scrollLastVCell = 0x00001000; const uint Tbl_scrollLastCell = 0x00001800; const uint Tbl_smoothHScrolling = 0x00002000; const uint Tbl_smoothVScrolling = 0x00004000; const uint Tbl_smoothScrolling = 0x00006000; const uint Tbl_snapToHGrid = 0x00008000; const uint Tbl_snapToVGrid = 0x00010000; const uint Tbl_snapToGrid = 0x00018000; inline int QtTableView::numRows() const { return nRows; } inline int QtTableView::numCols() const { return nCols; } inline int QtTableView::topCell() const { return yCellOffs; } inline int QtTableView::leftCell() const { return xCellOffs; } inline int QtTableView::xOffset() const { return xOffs; } inline int QtTableView::yOffset() const { return yOffs; } inline int QtTableView::cellHeight() const { return cellH; } inline int QtTableView::cellWidth() const { return cellW; } inline uint QtTableView::tableFlags() const { return tFlags; } inline bool QtTableView::testTableFlags(uint f) const { return (tFlags & f) != 0; } inline QRect QtTableView::cellUpdateRect() const { return cellUpdateR; } inline bool QtTableView::autoUpdate() const { return isUpdatesEnabled(); } inline void QtTableView::repaint(bool erase) { repaint(0, 0, width(), height(), erase); } inline void QtTableView::repaint(const QRect &r, bool erase) { repaint(r.x(), r.y(), r.width(), r.height(), erase); } inline void QtTableView::updateScrollBars() { updateScrollBars(0); } #endif // QT_NO_QTTABLEVIEW #endif // QTTABLEVIEW_H nethack-3.6.0/include/quest.h0000664000076400007660000000433512536476415015114 0ustar paxedpaxed/* NetHack 3.6 quest.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Mike Stephenson 1991. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QUEST_H #define QUEST_H struct q_score { /* Quest "scorecard" */ Bitfield(first_start, 1); /* only set the first time */ Bitfield(met_leader, 1); /* has met the leader */ Bitfield(not_ready, 3); /* rejected due to alignment, etc. */ Bitfield(pissed_off, 1); /* got the leader angry */ Bitfield(got_quest, 1); /* got the quest assignment */ Bitfield(first_locate, 1); /* only set the first time */ Bitfield(met_intermed, 1); /* used if the locate is a person. */ Bitfield(got_final, 1); /* got the final quest assignment */ Bitfield(made_goal, 3); /* # of times on goal level */ Bitfield(met_nemesis, 1); /* has met the nemesis before */ Bitfield(killed_nemesis, 1); /* set when the nemesis is killed */ Bitfield(in_battle, 1); /* set when nemesis fighting you */ Bitfield(cheater, 1); /* set if cheating detected */ Bitfield(touched_artifact, 1); /* for a special message */ Bitfield(offered_artifact, 1); /* offered to leader */ Bitfield(got_thanks, 1); /* final message from leader */ /* used by questpgr code when messages want to use pronouns (set up at game start instead of waiting until monster creation; 1 bit each would suffice--nobody involved is actually neuter) */ Bitfield(ldrgend, 2); /* leader's gender: 0=male, 1=female, 2=neuter */ Bitfield(nemgend, 2); /* nemesis's gender */ Bitfield(godgend, 2); /* deity's gender */ /* keep track of leader presence/absence even if leader is polymorphed, raised from dead, etc */ Bitfield(leader_is_dead, 1); unsigned leader_m_id; }; #define MAX_QUEST_TRIES 7 /* exceed this and you "fail" */ #define MIN_QUEST_ALIGN 20 /* at least this align.record to start */ /* note: align 20 matches "pious" as reported by enlightenment (cmd.c) */ #define MIN_QUEST_LEVEL 14 /* at least this u.ulevel to start */ /* note: exp.lev. 14 is threshold level for 5th rank (class title, role.c) */ #endif /* QUEST_H */ nethack-3.6.0/include/rect.h0000664000076400007660000000055312536476415014706 0ustar paxedpaxed/* NetHack 3.6 rect.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) 1990 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #ifndef RECT_H #define RECT_H typedef struct nhrect { xchar lx, ly; xchar hx, hy; } NhRect; #endif /* RECT_H */ nethack-3.6.0/include/region.h0000664000076400007660000000601512610522241015211 0ustar paxedpaxed/* NetHack 3.6 region.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #ifndef REGION_H #define REGION_H /* generic callback function */ typedef boolean FDECL((*callback_proc), (genericptr_t, genericptr_t)); /* * player_flags */ #define REG_HERO_INSIDE 0x01 #define REG_NOT_HEROS 0x02 #define hero_inside(r) ((r)->player_flags & REG_HERO_INSIDE) #define heros_fault(r) (!((r)->player_flags & REG_NOT_HEROS)) #define set_hero_inside(r) ((r)->player_flags |= REG_HERO_INSIDE) #define clear_hero_inside(r) ((r)->player_flags &= ~REG_HERO_INSIDE) #define set_heros_fault(r) ((r)->player_flags &= ~REG_NOT_HEROS) #define clear_heros_fault(r) ((r)->player_flags |= REG_NOT_HEROS) /* * Note: if you change the size/type of any of the fields below, * or add any/remove any fields, you must update the * bwrite() calls in save_regions(), and the * mread() calls in rest_regions() in src/region.c * to reflect the changes. */ typedef struct { NhRect bounding_box; /* Bounding box of the region */ NhRect *rects; /* Rectangles composing the region */ short nrects; /* Number of rectangles */ boolean attach_2_u; /* Region attached to player ? */ unsigned int attach_2_m; /* Region attached to monster ? */ /*struct obj *attach_2_o;*/ /* Region attached to object ? UNUSED YET */ const char *enter_msg; /* Message when entering */ const char *leave_msg; /* Message when leaving */ long ttl; /* Time to live. -1 is forever */ short expire_f; /* Function to call when region's ttl expire */ short can_enter_f; /* Function to call to check whether the player can, or can not, enter the region */ short enter_f; /* Function to call when the player enters*/ short can_leave_f; /* Function to call to check whether the player can, or can not, leave the region */ short leave_f; /* Function to call when the player leaves */ short inside_f; /* Function to call every turn if player's inside */ unsigned int player_flags; /* (see above) */ unsigned int *monsters; /* Monsters currently inside this region */ short n_monst; /* Number of monsters inside this region */ short max_monst; /* Maximum number of monsters that can be listed without having to grow the array */ #define MONST_INC 5 /* Should probably do the same thing about objects */ boolean visible; /* Is the region visible ? */ int glyph; /* Which glyph to use if visible */ anything arg; /* Optional user argument (Ex: strength of force field, damage of a fire zone, ...*/ } NhRegion; #endif /* REGION_H */ nethack-3.6.0/include/rm.h0000664000076400007660000004552312610522241014353 0ustar paxedpaxed/* NetHack 3.6 rm.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.41 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef RM_H #define RM_H /* * The dungeon presentation graphics code and data structures were rewritten * and generalized for NetHack's release 2 by Eric S. Raymond (eric@snark) * building on Don G. Kneller's MS-DOS implementation. See drawing.c for * the code that permits the user to set the contents of the symbol structure. * * The door representation was changed by Ari * Huttunen(ahuttune@niksula.hut.fi) */ /* * TLCORNER TDWALL TRCORNER * +- -+- -+ * | | | * * TRWALL CROSSWALL TLWALL HWALL * | | | * +- -+- -+ --- * | | | * * BLCORNER TUWALL BRCORNER VWALL * | | | | * +- -+- -+ | */ /* Level location types. [Some debugging code in src/display.c defines array type_names[] which contains an entry for each of these, so needs to be kept in sync if any new types are added or existing ones renumbered.] */ #define STONE 0 #define VWALL 1 #define HWALL 2 #define TLCORNER 3 #define TRCORNER 4 #define BLCORNER 5 #define BRCORNER 6 #define CROSSWALL 7 /* For pretty mazes and special levels */ #define TUWALL 8 #define TDWALL 9 #define TLWALL 10 #define TRWALL 11 #define DBWALL 12 #define TREE 13 /* KMH */ #define SDOOR 14 #define SCORR 15 #define POOL 16 #define MOAT 17 /* pool that doesn't boil, adjust messages */ #define WATER 18 #define DRAWBRIDGE_UP 19 #define LAVAPOOL 20 #define IRONBARS 21 /* KMH */ #define DOOR 22 #define CORR 23 #define ROOM 24 #define STAIRS 25 #define LADDER 26 #define FOUNTAIN 27 #define THRONE 28 #define SINK 29 #define GRAVE 30 #define ALTAR 31 #define ICE 32 #define DRAWBRIDGE_DOWN 33 #define AIR 34 #define CLOUD 35 #define MAX_TYPE 36 #define INVALID_TYPE 127 /* * Avoid using the level types in inequalities: * these types are subject to change. * Instead, use one of the macros below. */ #define IS_WALL(typ) ((typ) && (typ) <= DBWALL) #define IS_STWALL(typ) ((typ) <= DBWALL) /* STONE <= (typ) <= DBWALL */ #define IS_ROCK(typ) ((typ) < POOL) /* absolutely nonaccessible */ #define IS_DOOR(typ) ((typ) == DOOR) #define IS_TREE(typ) \ ((typ) == TREE || (level.flags.arboreal && (typ) == STONE)) #define ACCESSIBLE(typ) ((typ) >= DOOR) /* good position */ #define IS_ROOM(typ) ((typ) >= ROOM) /* ROOM, STAIRS, furniture.. */ #define ZAP_POS(typ) ((typ) >= POOL) #define SPACE_POS(typ) ((typ) > DOOR) #define IS_POOL(typ) ((typ) >= POOL && (typ) <= DRAWBRIDGE_UP) #define IS_THRONE(typ) ((typ) == THRONE) #define IS_FOUNTAIN(typ) ((typ) == FOUNTAIN) #define IS_SINK(typ) ((typ) == SINK) #define IS_GRAVE(typ) ((typ) == GRAVE) #define IS_ALTAR(typ) ((typ) == ALTAR) #define IS_DRAWBRIDGE(typ) \ ((typ) == DRAWBRIDGE_UP || (typ) == DRAWBRIDGE_DOWN) #define IS_FURNITURE(typ) ((typ) >= STAIRS && (typ) <= ALTAR) #define IS_AIR(typ) ((typ) == AIR || (typ) == CLOUD) #define IS_SOFT(typ) ((typ) == AIR || (typ) == CLOUD || IS_POOL(typ)) /* * The screen symbols may be the default or defined at game startup time. * See drawing.c for defaults. * Note: {ibm|dec}_graphics[] arrays (also in drawing.c) must be kept in * synch. */ /* begin dungeon characters */ #define S_stone 0 #define S_vwall 1 #define S_hwall 2 #define S_tlcorn 3 #define S_trcorn 4 #define S_blcorn 5 #define S_brcorn 6 #define S_crwall 7 #define S_tuwall 8 #define S_tdwall 9 #define S_tlwall 10 #define S_trwall 11 #define S_ndoor 12 #define S_vodoor 13 #define S_hodoor 14 #define S_vcdoor 15 /* closed door, vertical wall */ #define S_hcdoor 16 /* closed door, horizontal wall */ #define S_bars 17 /* KMH -- iron bars */ #define S_tree 18 /* KMH */ #define S_room 19 #define S_darkroom 20 #define S_corr 21 #define S_litcorr 22 #define S_upstair 23 #define S_dnstair 24 #define S_upladder 25 #define S_dnladder 26 #define S_altar 27 #define S_grave 28 #define S_throne 29 #define S_sink 30 #define S_fountain 31 #define S_pool 32 #define S_ice 33 #define S_lava 34 #define S_vodbridge 35 #define S_hodbridge 36 #define S_vcdbridge 37 /* closed drawbridge, vertical wall */ #define S_hcdbridge 38 /* closed drawbridge, horizontal wall */ #define S_air 39 #define S_cloud 40 #define S_water 41 /* end dungeon characters, begin traps */ #define S_arrow_trap 42 #define S_dart_trap 43 #define S_falling_rock_trap 44 #define S_squeaky_board 45 #define S_bear_trap 46 #define S_land_mine 47 #define S_rolling_boulder_trap 48 #define S_sleeping_gas_trap 49 #define S_rust_trap 50 #define S_fire_trap 51 #define S_pit 52 #define S_spiked_pit 53 #define S_hole 54 #define S_trap_door 55 #define S_teleportation_trap 56 #define S_level_teleporter 57 #define S_magic_portal 58 #define S_web 59 #define S_statue_trap 60 #define S_magic_trap 61 #define S_anti_magic_trap 62 #define S_polymorph_trap 63 #define S_vibrating_square 64 /* end traps, begin special effects */ #define S_vbeam 65 /* The 4 zap beam symbols. Do NOT separate. */ #define S_hbeam 66 /* To change order or add, see function */ #define S_lslant 67 /* zapdir_to_glyph() in display.c. */ #define S_rslant 68 #define S_digbeam 69 /* dig beam symbol */ #define S_flashbeam 70 /* camera flash symbol */ #define S_boomleft 71 /* thrown boomerang, open left, e.g ')' */ #define S_boomright 72 /* thrown boomerang, open right, e.g. '(' */ #define S_ss1 73 /* 4 magic shield glyphs */ #define S_ss2 74 #define S_ss3 75 #define S_ss4 76 #define S_poisoncloud 77 #define S_goodpos 78 /* valid position for targeting */ /* The 8 swallow symbols. Do NOT separate. To change order or add, see */ /* the function swallow_to_glyph() in display.c. */ #define S_sw_tl 79 /* swallow top left [1] */ #define S_sw_tc 80 /* swallow top center [2] Order: */ #define S_sw_tr 81 /* swallow top right [3] */ #define S_sw_ml 82 /* swallow middle left [4] 1 2 3 */ #define S_sw_mr 83 /* swallow middle right [6] 4 5 6 */ #define S_sw_bl 84 /* swallow bottom left [7] 7 8 9 */ #define S_sw_bc 85 /* swallow bottom center [8] */ #define S_sw_br 86 /* swallow bottom right [9] */ #define S_explode1 87 /* explosion top left */ #define S_explode2 88 /* explosion top center */ #define S_explode3 89 /* explosion top right Ex. */ #define S_explode4 90 /* explosion middle left */ #define S_explode5 91 /* explosion middle center /-\ */ #define S_explode6 92 /* explosion middle right |@| */ #define S_explode7 93 /* explosion bottom left \-/ */ #define S_explode8 94 /* explosion bottom center */ #define S_explode9 95 /* explosion bottom right */ /* end effects */ #define MAXPCHARS 96 /* maximum number of mapped characters */ #define MAXDCHARS 42 /* maximum of mapped dungeon characters */ #define MAXTCHARS 22 /* maximum of mapped trap characters */ #define MAXECHARS 31 /* maximum of mapped effects characters */ #define MAXEXPCHARS 9 /* number of explosion characters */ #define DARKROOMSYM (Is_rogue_level(&u.uz) ? S_stone : S_darkroom) struct symdef { uchar sym; const char *explanation; #ifdef TEXTCOLOR uchar color; #endif }; struct symparse { unsigned range; #define SYM_CONTROL 1 /* start/finish markers */ #define SYM_PCHAR 2 /* index into showsyms */ #define SYM_OC 3 /* index into oc_syms */ #define SYM_MON 4 /* index into monsyms */ #define SYM_OTH 5 /* misc */ int idx; const char *name; }; /* misc symbol definitions */ #define SYM_BOULDER 0 #define SYM_INVISIBLE 1 #define MAXOTHER 2 /* linked list of symsets and their characteristics */ struct symsetentry { struct symsetentry *next; /* next in list */ char *name; /* ptr to symset name */ char *desc; /* ptr to description */ int idx; /* an index value */ int handling; /* known handlers value */ Bitfield(nocolor, 1); /* don't use color if set */ Bitfield(primary, 1); /* restricted for use as primary set */ Bitfield(rogue, 1); /* restricted for use as rogue lev set */ /* 5 free bits */ }; /* * Graphics sets for display symbols */ #define DEFAULT_GRAPHICS 0 /* regular characters: '-', '+', &c */ #define PRIMARY 0 /* primary graphics set */ #define ROGUESET 1 /* rogue graphics set */ #define NUM_GRAPHICS 2 /* * special symbol set handling types ( for invoking callbacks, etc.) * Must match the order of the known_handlers strings * in drawing.c */ #define H_UNK 0 #define H_IBM 1 #define H_DEC 2 extern const struct symdef defsyms[MAXPCHARS]; /* defaults */ extern const struct symdef def_warnsyms[WARNCOUNT]; extern int currentgraphics; /* from drawing.c */ extern nhsym showsyms[]; extern struct symsetentry symset[NUM_GRAPHICS]; /* from drawing.c */ #define SYMHANDLING(ht) (symset[currentgraphics].handling == (ht)) /* * The 5 possible states of doors */ #define D_NODOOR 0 #define D_BROKEN 1 #define D_ISOPEN 2 #define D_CLOSED 4 #define D_LOCKED 8 #define D_TRAPPED 16 #define D_SECRET 32 /* only used by sp_lev.c, NOT in rm-struct */ /* * Some altars are considered as shrines, so we need a flag. */ #define AM_SHRINE 8 /* * Thrones should only be looted once. */ #define T_LOOTED 1 /* * Trees have more than one kick result. */ #define TREE_LOOTED 1 #define TREE_SWARM 2 /* * Fountains have limits, and special warnings. */ #define F_LOOTED 1 #define F_WARNED 2 #define FOUNTAIN_IS_WARNED(x, y) (levl[x][y].looted & F_WARNED) #define FOUNTAIN_IS_LOOTED(x, y) (levl[x][y].looted & F_LOOTED) #define SET_FOUNTAIN_WARNED(x, y) levl[x][y].looted |= F_WARNED; #define SET_FOUNTAIN_LOOTED(x, y) levl[x][y].looted |= F_LOOTED; #define CLEAR_FOUNTAIN_WARNED(x, y) levl[x][y].looted &= ~F_WARNED; #define CLEAR_FOUNTAIN_LOOTED(x, y) levl[x][y].looted &= ~F_LOOTED; /* * Doors are even worse :-) The special warning has a side effect * of instantly trapping the door, and if it was defined as trapped, * the guards consider that you have already been warned! */ #define D_WARNED 16 /* * Sinks have 3 different types of loot that shouldn't be abused */ #define S_LPUDDING 1 #define S_LDWASHER 2 #define S_LRING 4 /* * The four directions for a DrawBridge. */ #define DB_NORTH 0 #define DB_SOUTH 1 #define DB_EAST 2 #define DB_WEST 3 #define DB_DIR 3 /* mask for direction */ /* * What's under a drawbridge. */ #define DB_MOAT 0 #define DB_LAVA 4 #define DB_ICE 8 #define DB_FLOOR 16 #define DB_UNDER 28 /* mask for underneath */ /* * Wall information. */ #define WM_MASK 0x07 /* wall mode (bottom three bits) */ #define W_NONDIGGABLE 0x08 #define W_NONPASSWALL 0x10 /* * Ladders (in Vlad's tower) may be up or down. */ #define LA_UP 1 #define LA_DOWN 2 /* * Room areas may be iced pools */ #define ICED_POOL 8 #define ICED_MOAT 16 /* * The structure describing a coordinate position. * Before adding fields, remember that this will significantly affect * the size of temporary files and save files. * * Also remember that the run-length encoding for some ports in save.c * must be updated to consider the field. */ struct rm { int glyph; /* what the hero thinks is there */ schar typ; /* what is really there */ uchar seenv; /* seen vector */ Bitfield(flags, 5); /* extra information for typ */ Bitfield(horizontal, 1); /* wall/door/etc is horiz. (more typ info) */ Bitfield(lit, 1); /* speed hack for lit rooms */ Bitfield(waslit, 1); /* remember if a location was lit */ Bitfield(roomno, 6); /* room # for special rooms */ Bitfield(edge, 1); /* marks boundaries for special rooms*/ Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */ }; #define SET_TYPLIT(x, y, ttyp, llit) \ { \ if ((x) >= 0 && (y) >= 0 && (x) < COLNO && (y) < ROWNO) { \ if ((ttyp) < MAX_TYPE) \ levl[(x)][(y)].typ = (ttyp); \ if ((ttyp) == LAVAPOOL) \ levl[(x)][(y)].lit = 1; \ else if ((schar)(llit) != -2) { \ if ((schar)(llit) == -1) \ levl[(x)][(y)].lit = rn2(2); \ else \ levl[(x)][(y)].lit = (llit); \ } \ } \ } /* * Add wall angle viewing by defining "modes" for each wall type. Each * mode describes which parts of a wall are finished (seen as as wall) * and which are unfinished (seen as rock). * * We use the bottom 3 bits of the flags field for the mode. This comes * in conflict with secret doors, but we avoid problems because until * a secret door becomes discovered, we know what sdoor's bottom three * bits are. * * The following should cover all of the cases. * * type mode Examples: R=rock, F=finished * ----- ---- ---------------------------- * WALL: 0 none hwall, mode 1 * 1 left/top (1/2 rock) RRR * 2 right/bottom (1/2 rock) --- * FFF * * CORNER: 0 none trcorn, mode 2 * 1 outer (3/4 rock) FFF * 2 inner (1/4 rock) F+- * F|R * * TWALL: 0 none tlwall, mode 3 * 1 long edge (1/2 rock) F|F * 2 bottom left (on a tdwall) -+F * 3 bottom right (on a tdwall) R|F * * CRWALL: 0 none crwall, mode 5 * 1 top left (1/4 rock) R|F * 2 top right (1/4 rock) -+- * 3 bottom left (1/4 rock) F|R * 4 bottom right (1/4 rock) * 5 top left & bottom right (1/2 rock) * 6 bottom left & top right (1/2 rock) */ #define WM_W_LEFT 1 /* vertical or horizontal wall */ #define WM_W_RIGHT 2 #define WM_W_TOP WM_W_LEFT #define WM_W_BOTTOM WM_W_RIGHT #define WM_C_OUTER 1 /* corner wall */ #define WM_C_INNER 2 #define WM_T_LONG 1 /* T wall */ #define WM_T_BL 2 #define WM_T_BR 3 #define WM_X_TL 1 /* cross wall */ #define WM_X_TR 2 #define WM_X_BL 3 #define WM_X_BR 4 #define WM_X_TLBR 5 #define WM_X_BLTR 6 /* * Seen vector values. The seen vector is an array of 8 bits, one for each * octant around a given center x: * * 0 1 2 * 7 x 3 * 6 5 4 * * In the case of walls, a single wall square can be viewed from 8 possible * directions. If we know the type of wall and the directions from which * it has been seen, then we can determine what it looks like to the hero. */ #define SV0 0x1 #define SV1 0x2 #define SV2 0x4 #define SV3 0x8 #define SV4 0x10 #define SV5 0x20 #define SV6 0x40 #define SV7 0x80 #define SVALL 0xFF #define doormask flags #define altarmask flags #define wall_info flags #define ladder flags #define drawbridgemask flags #define looted flags #define icedpool flags #define blessedftn horizontal /* a fountain that grants attribs */ #define disturbed horizontal /* a grave that has been disturbed */ struct damage { struct damage *next; long when, cost; coord place; schar typ; }; /* for bones levels: identify the dead character, who might have died on an existing bones level; if so, most recent victim will be first in list */ struct cemetery { struct cemetery *next; /* next struct is previous dead character... */ /* "plname" + "-ROLe" + "-RACe" + "-GENder" + "-ALIgnment" + \0 */ char who[PL_NSIZ + 4 * (1 + 3) + 1]; /* death reason, same as in score/log file */ char how[100 + 1]; /* [DTHSZ+1] */ /* date+time in string of digits rather than binary */ char when[4 + 2 + 2 + 2 + 2 + 2 + 1]; /* "YYYYMMDDhhmmss\0" */ /* final resting place spot */ schar frpx, frpy; boolean bonesknown; }; struct levelflags { uchar nfountains; /* number of fountains on level */ uchar nsinks; /* number of sinks on the level */ /* Several flags that give hints about what's on the level */ Bitfield(has_shop, 1); Bitfield(has_vault, 1); Bitfield(has_zoo, 1); Bitfield(has_court, 1); Bitfield(has_morgue, 1); Bitfield(has_beehive, 1); Bitfield(has_barracks, 1); Bitfield(has_temple, 1); Bitfield(has_swamp, 1); Bitfield(noteleport, 1); Bitfield(hardfloor, 1); Bitfield(nommap, 1); Bitfield(hero_memory, 1); /* hero has memory */ Bitfield(shortsighted, 1); /* monsters are shortsighted */ Bitfield(graveyard, 1); /* has_morgue, but remains set */ Bitfield(sokoban_rules, 1); /* fill pits and holes w/ boulders */ Bitfield(is_maze_lev, 1); Bitfield(is_cavernous_lev, 1); Bitfield(arboreal, 1); /* Trees replace rock */ Bitfield(wizard_bones, 1); /* set if level came from a bones file which was created in wizard mode (or normal mode descendant of such) */ Bitfield(corrmaze, 1); /* Whether corridors are used for the maze rather than ROOM */ }; typedef struct { struct rm locations[COLNO][ROWNO]; #ifndef MICROPORT_BUG struct obj *objects[COLNO][ROWNO]; struct monst *monsters[COLNO][ROWNO]; #else struct obj *objects[1][ROWNO]; char *yuk1[COLNO - 1][ROWNO]; struct monst *monsters[1][ROWNO]; char *yuk2[COLNO - 1][ROWNO]; #endif struct obj *objlist; struct obj *buriedobjlist; struct monst *monlist; struct damage *damagelist; struct cemetery *bonesinfo; struct levelflags flags; } dlevel_t; extern schar lastseentyp[COLNO][ROWNO]; /* last seen/touched dungeon typ */ extern dlevel_t level; /* structure describing the current level */ /* * Macros for compatibility with old code. Someday these will go away. */ #define levl level.locations #define fobj level.objlist #define fmon level.monlist /* * Covert a trap number into the defsym graphics array. * Convert a defsym number into a trap number. * Assumes that arrow trap will always be the first trap. */ #define trap_to_defsym(t) (S_arrow_trap + (t) -1) #define defsym_to_trap(d) ((d) -S_arrow_trap + 1) #define OBJ_AT(x, y) (level.objects[x][y] != (struct obj *) 0) /* * Macros for encapsulation of level.monsters references. */ #define MON_AT(x, y) \ (level.monsters[x][y] != (struct monst *) 0 \ && !(level.monsters[x][y])->mburied) #define MON_BURIED_AT(x, y) \ (level.monsters[x][y] != (struct monst *) 0 \ && (level.monsters[x][y])->mburied) #define place_worm_seg(m, x, y) level.monsters[x][y] = m #define remove_monster(x, y) level.monsters[x][y] = (struct monst *) 0 #define m_at(x, y) (MON_AT(x, y) ? level.monsters[x][y] : (struct monst *) 0) #define m_buried_at(x, y) \ (MON_BURIED_AT(x, y) ? level.monsters[x][y] : (struct monst *) 0) /* restricted movement, potential luck penalties */ #define Sokoban level.flags.sokoban_rules #endif /* RM_H */ nethack-3.6.0/include/skills.h0000664000076400007660000000706712610522241015237 0ustar paxedpaxed/* NetHack 3.6 skills.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SKILLS_H #define SKILLS_H /* Much of this code was taken from you.h. It is now * in a separate file so it can be included in objects.c. */ /* Code to denote that no skill is applicable */ #define P_NONE 0 /* Weapon Skills -- Stephen White * Order matters and are used in macros. * Positive values denote hand-to-hand weapons or launchers. * Negative values denote ammunition or missiles. * Update weapon.c if you amend any skills. * Also used for oc_subtyp. */ #define P_DAGGER 1 #define P_KNIFE 2 #define P_AXE 3 #define P_PICK_AXE 4 #define P_SHORT_SWORD 5 #define P_BROAD_SWORD 6 #define P_LONG_SWORD 7 #define P_TWO_HANDED_SWORD 8 #define P_SCIMITAR 9 #define P_SABER 10 #define P_CLUB 11 /* Heavy-shafted bludgeon */ #define P_MACE 12 #define P_MORNING_STAR 13 /* Spiked bludgeon */ #define P_FLAIL 14 /* Two pieces hinged or chained together */ #define P_HAMMER 15 /* Heavy head on the end */ #define P_QUARTERSTAFF 16 /* Long-shafted bludgeon */ #define P_POLEARMS 17 #define P_SPEAR 18 /* includes javelin */ #define P_TRIDENT 19 #define P_LANCE 20 #define P_BOW 21 #define P_SLING 22 #define P_CROSSBOW 23 #define P_DART 24 #define P_SHURIKEN 25 #define P_BOOMERANG 26 #define P_WHIP 27 #define P_UNICORN_HORN 28 /* last weapon */ #define P_FIRST_WEAPON P_DAGGER #define P_LAST_WEAPON P_UNICORN_HORN /* Spell Skills added by Larry Stewart-Zerba */ #define P_ATTACK_SPELL 29 #define P_HEALING_SPELL 30 #define P_DIVINATION_SPELL 31 #define P_ENCHANTMENT_SPELL 32 #define P_CLERIC_SPELL 33 #define P_ESCAPE_SPELL 34 #define P_MATTER_SPELL 35 #define P_FIRST_SPELL P_ATTACK_SPELL #define P_LAST_SPELL P_MATTER_SPELL /* Other types of combat */ #define P_BARE_HANDED_COMBAT 36 /* actually weaponless; gloves are ok */ #define P_MARTIAL_ARTS P_BARE_HANDED_COMBAT /* Role distinguishes */ #define P_TWO_WEAPON_COMBAT 37 /* Finally implemented */ #define P_RIDING 38 /* How well you control your steed */ #define P_LAST_H_TO_H P_RIDING #define P_FIRST_H_TO_H P_BARE_HANDED_COMBAT #define P_NUM_SKILLS (P_LAST_H_TO_H + 1) /* These roles qualify for a martial arts bonus */ #define martial_bonus() (Role_if(PM_SAMURAI) || Role_if(PM_MONK)) /* * These are the standard weapon skill levels. It is important that * the lowest "valid" skill be be 1. The code calculates the * previous amount to practice by calling practice_needed_to_advance() * with the current skill-1. To work out for the UNSKILLED case, * a value of 0 needed. */ #define P_ISRESTRICTED 0 #define P_UNSKILLED 1 #define P_BASIC 2 #define P_SKILLED 3 #define P_EXPERT 4 #define P_MASTER 5 /* Unarmed combat/martial arts only */ #define P_GRAND_MASTER 6 /* Unarmed combat/martial arts only */ #define practice_needed_to_advance(level) ((level) * (level) *20) /* The hero's skill in various weapons. */ struct skills { xchar skill; xchar max_skill; unsigned short advance; }; #define P_SKILL(type) (u.weapon_skills[type].skill) #define P_MAX_SKILL(type) (u.weapon_skills[type].max_skill) #define P_ADVANCE(type) (u.weapon_skills[type].advance) #define P_RESTRICTED(type) (u.weapon_skills[type].skill == P_ISRESTRICTED) #define P_SKILL_LIMIT 60 /* Max number of skill advancements */ /* Initial skill matrix structure; used in u_init.c and weapon.c */ struct def_skill { xchar skill; xchar skmax; }; #endif /* SKILLS_H */ nethack-3.6.0/include/sp_lev.h0000664000076400007660000003623712607356654015252 0ustar paxedpaxed/* NetHack 3.6 sp_lev.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SP_LEV_H #define SP_LEV_H /* wall directions */ #define W_NORTH 1 #define W_SOUTH 2 #define W_EAST 4 #define W_WEST 8 #define W_ANY (W_NORTH | W_SOUTH | W_EAST | W_WEST) /* MAP limits */ #define MAP_X_LIM 76 #define MAP_Y_LIM 21 /* Per level flags */ #define NOTELEPORT 0x00000001L #define HARDFLOOR 0x00000002L #define NOMMAP 0x00000004L #define SHORTSIGHTED 0x00000008L #define ARBOREAL 0x00000010L #define MAZELEVEL 0x00000020L #define PREMAPPED 0x00000040L /* premapped level & sokoban rules */ #define SHROUD 0x00000080L #define GRAVEYARD 0x00000100L #define ICEDPOOLS 0x00000200L /* for ice locations: ICED_POOL vs ICED_MOAT \ */ #define SOLIDIFY 0x00000400L /* outer areas are nondiggable & nonpasswall */ #define CORRMAZE 0x00000800L /* for maze levels only */ #define CHECK_INACCESSIBLES 0x00001000L /* check for inaccessible areas and generate ways to escape from them */ /* different level layout initializers */ #define LVLINIT_NONE 0 #define LVLINIT_SOLIDFILL 1 #define LVLINIT_MAZEGRID 2 #define LVLINIT_MINES 3 #define LVLINIT_ROGUE 4 /* max. layers of object containment */ #define MAX_CONTAINMENT 10 /* max. # of random registers */ #define MAX_REGISTERS 10 /* max. nested depth of subrooms */ #define MAX_NESTED_ROOMS 5 /* max. # of opcodes per special level */ #define SPCODER_MAX_RUNTIME 65536 /* Opcodes for creating the level * If you change these, also change opcodestr[] in util/lev_main.c */ enum opcode_defs { SPO_NULL = 0, SPO_MESSAGE, SPO_MONSTER, SPO_OBJECT, SPO_ENGRAVING, SPO_ROOM, SPO_SUBROOM, SPO_DOOR, SPO_STAIR, SPO_LADDER, SPO_ALTAR, SPO_FOUNTAIN, SPO_SINK, SPO_POOL, SPO_TRAP, SPO_GOLD, SPO_CORRIDOR, SPO_LEVREGION, SPO_DRAWBRIDGE, SPO_MAZEWALK, SPO_NON_DIGGABLE, SPO_NON_PASSWALL, SPO_WALLIFY, SPO_MAP, SPO_ROOM_DOOR, SPO_REGION, SPO_MINERALIZE, SPO_CMP, SPO_JMP, SPO_JL, SPO_JLE, SPO_JG, SPO_JGE, SPO_JE, SPO_JNE, SPO_TERRAIN, SPO_REPLACETERRAIN, SPO_EXIT, SPO_ENDROOM, SPO_POP_CONTAINER, SPO_PUSH, SPO_POP, SPO_RN2, SPO_DEC, SPO_INC, SPO_MATH_ADD, SPO_MATH_SUB, SPO_MATH_MUL, SPO_MATH_DIV, SPO_MATH_MOD, SPO_MATH_SIGN, SPO_COPY, SPO_END_MONINVENT, SPO_GRAVE, SPO_FRAME_PUSH, SPO_FRAME_POP, SPO_CALL, SPO_RETURN, SPO_INITLEVEL, SPO_LEVEL_FLAGS, SPO_VAR_INIT, /* variable_name data */ SPO_SHUFFLE_ARRAY, SPO_DICE, SPO_SEL_ADD, SPO_SEL_POINT, SPO_SEL_RECT, SPO_SEL_FILLRECT, SPO_SEL_LINE, SPO_SEL_RNDLINE, SPO_SEL_GROW, SPO_SEL_FLOOD, SPO_SEL_RNDCOORD, SPO_SEL_ELLIPSE, SPO_SEL_FILTER, SPO_SEL_GRADIENT, SPO_SEL_COMPLEMENT, MAX_SP_OPCODES }; /* MONSTER and OBJECT can take a variable number of parameters, * they also pop different # of values from the stack. So, * first we pop a value that tells what the _next_ value will * mean. */ /* MONSTER */ #define SP_M_V_PEACEFUL 0 #define SP_M_V_ALIGN 1 #define SP_M_V_ASLEEP 2 #define SP_M_V_APPEAR 3 #define SP_M_V_NAME 4 #define SP_M_V_FEMALE 5 #define SP_M_V_INVIS 6 #define SP_M_V_CANCELLED 7 #define SP_M_V_REVIVED 8 #define SP_M_V_AVENGE 9 #define SP_M_V_FLEEING 10 #define SP_M_V_BLINDED 11 #define SP_M_V_PARALYZED 12 #define SP_M_V_STUNNED 13 #define SP_M_V_CONFUSED 14 #define SP_M_V_SEENTRAPS 15 #define SP_M_V_END 16 /* end of variable parameters */ /* OBJECT */ #define SP_O_V_SPE 0 #define SP_O_V_CURSE 1 #define SP_O_V_CORPSENM 2 #define SP_O_V_NAME 3 #define SP_O_V_QUAN 4 #define SP_O_V_BURIED 5 #define SP_O_V_LIT 6 #define SP_O_V_ERODED 7 #define SP_O_V_LOCKED 8 #define SP_O_V_TRAPPED 9 #define SP_O_V_RECHARGED 10 #define SP_O_V_INVIS 11 #define SP_O_V_GREASED 12 #define SP_O_V_BROKEN 13 #define SP_O_V_COORD 14 #define SP_O_V_END 15 /* end of variable parameters */ /* When creating objects, we need to know whether * it's a container and/or contents. */ #define SP_OBJ_CONTENT 0x1 #define SP_OBJ_CONTAINER 0x2 /* SPO_FILTER types */ #define SPOFILTER_PERCENT 0 #define SPOFILTER_SELECTION 1 #define SPOFILTER_MAPCHAR 2 /* gradient filter types */ #define SEL_GRADIENT_RADIAL 0 #define SEL_GRADIENT_SQUARE 1 /* variable types */ #define SPOVAR_NULL 0x00 #define SPOVAR_INT 0x01 /* l */ #define SPOVAR_STRING 0x02 /* str */ #define SPOVAR_VARIABLE 0x03 /* str (contains the variable name) */ #define SPOVAR_COORD \ 0x04 /* coordinate, encoded in l; use SP_COORD_X() and SP_COORD_Y() */ #define SPOVAR_REGION 0x05 /* region, encoded in l; use SP_REGION_X1() etc \ */ #define SPOVAR_MAPCHAR 0x06 /* map char, in l */ #define SPOVAR_MONST \ 0x07 /* monster class & specific monster, encoded in l; use SP_MONST_... \ */ #define SPOVAR_OBJ \ 0x08 /* object class & specific object type, encoded in l; use \ SP_OBJ_... */ #define SPOVAR_SEL 0x09 /* selection. char[COLNO][ROWNO] in str */ #define SPOVAR_ARRAY 0x40 /* used in splev_var & lc_vardefs, not in opvar */ #define SP_COORD_IS_RANDOM 0x01000000 /* Humidity flags for get_location() and friends, used with * SP_COORD_PACK_RANDOM() */ #define DRY 0x1 #define WET 0x2 #define HOT 0x4 #define SOLID 0x8 #define ANY_LOC 0x10 /* even outside the level */ #define NO_LOC_WARN 0x20 /* no complaints and set x & y to -1, if no loc */ #define SP_COORD_X(l) (l & 0xff) #define SP_COORD_Y(l) ((l >> 16) & 0xff) #define SP_COORD_PACK(x, y) (((x) &0xff) + (((y) &0xff) << 16)) #define SP_COORD_PACK_RANDOM(f) (SP_COORD_IS_RANDOM | (f)) #define SP_REGION_X1(l) (l & 0xff) #define SP_REGION_Y1(l) ((l >> 8) & 0xff) #define SP_REGION_X2(l) ((l >> 16) & 0xff) #define SP_REGION_Y2(l) ((l >> 24) & 0xff) #define SP_REGION_PACK(x1, y1, x2, y2) \ (((x1) &0xff) + (((y1) &0xff) << 8) + (((x2) &0xff) << 16) \ + (((y2) &0xff) << 24)) #define SP_MONST_CLASS(l) (l & 0xff) #define SP_MONST_PM(l) ((l >> 8) & 0xffff) #define SP_MONST_PACK(m, c) (((m) << 8) + ((char) (c))) #define SP_OBJ_CLASS(l) (l & 0xff) #define SP_OBJ_TYP(l) ((l >> 8) & 0xffff) #define SP_OBJ_PACK(o, c) (((o) << 8) + ((char) (c))) #define SP_MAPCHAR_TYP(l) (l & 0xff) #define SP_MAPCHAR_LIT(l) ((l >> 8) & 0xff) #define SP_MAPCHAR_PACK(typ, lit) (((lit) << 8) + ((char) (typ))) struct opvar { xchar spovartyp; /* one of SPOVAR_foo */ union { char *str; long l; } vardata; }; struct splev_var { struct splev_var *next; char *name; xchar svtyp; /* SPOVAR_foo */ union { struct opvar *value; struct opvar **arrayvalues; } data; long array_len; }; struct splevstack { long depth; long depth_alloc; struct opvar **stackdata; }; struct sp_frame { struct sp_frame *next; struct splevstack *stack; struct splev_var *variables; long n_opcode; }; struct sp_coder { struct splevstack *stack; struct sp_frame *frame; int premapped; boolean solidify; struct mkroom *croom; struct mkroom *tmproomlist[MAX_NESTED_ROOMS + 1]; boolean failed_room[MAX_NESTED_ROOMS + 1]; int n_subroom; boolean exit_script; int lvl_is_joined; boolean check_inaccessibles; int opcode; /* current opcode */ struct opvar *opdat; /* current push data (req. opcode == SPO_PUSH) */ }; /* special level coder CPU flags */ #define SP_CPUFLAG_LT 1 #define SP_CPUFLAG_GT 2 #define SP_CPUFLAG_EQ 4 #define SP_CPUFLAG_ZERO 8 /* * Structures manipulated by the special levels loader & compiler */ #define packed_coord long typedef struct { xchar is_random; long getloc_flags; int x, y; } unpacked_coord; typedef struct { int cmp_what; int cmp_val; } opcmp; typedef struct { long jmp_target; } opjmp; typedef union str_or_len { char *str; int len; } Str_or_Len; typedef struct { xchar init_style; /* one of LVLINIT_foo */ long flags; schar filling; boolean init_present, padding; char fg, bg; boolean smoothed, joined; xchar lit, walled; boolean icedpools; } lev_init; typedef struct { xchar wall, pos, secret, mask; } room_door; typedef struct { packed_coord coord; xchar x, y, type; } trap; typedef struct { Str_or_Len name, appear_as; short id; aligntyp align; packed_coord coord; xchar x, y, class, appear; schar peaceful, asleep; short female, invis, cancelled, revived, avenge, fleeing, blinded, paralyzed, stunned, confused; long seentraps; short has_invent; } monster; typedef struct { Str_or_Len name; int corpsenm; short id, spe; packed_coord coord; xchar x, y, class, containment; schar curse_state; int quan; short buried; short lit; short eroded, locked, trapped, recharged, invis, greased, broken; } object; typedef struct { packed_coord coord; xchar x, y; aligntyp align; xchar shrine; } altar; typedef struct { xchar x1, y1, x2, y2; xchar rtype, rlit, rirreg; } region; typedef struct { xchar ter, tlit; } terrain; typedef struct { xchar chance; xchar x1, y1, x2, y2; xchar fromter, toter, tolit; } replaceterrain; /* values for rtype are defined in dungeon.h */ typedef struct { struct { xchar x1, y1, x2, y2; } inarea; struct { xchar x1, y1, x2, y2; } delarea; boolean in_islev, del_islev; xchar rtype, padding; Str_or_Len rname; } lev_region; typedef struct { struct { xchar room; xchar wall; xchar door; } src, dest; } corridor; typedef struct _room { Str_or_Len name; Str_or_Len parent; xchar x, y, w, h; xchar xalign, yalign; xchar rtype, chance, rlit, filled, joined; } room; typedef struct { schar zaligntyp; schar keep_region; schar halign, valign; char xsize, ysize; char **map; } mazepart; typedef struct { int opcode; struct opvar *opdat; } _opcode; typedef struct { _opcode *opcodes; long n_opcodes; } sp_lev; typedef struct { xchar x, y, direction, count, lit; char typ; } spill; /* only used by lev_comp */ struct lc_funcdefs_parm { char *name; char parmtype; struct lc_funcdefs_parm *next; }; struct lc_funcdefs { struct lc_funcdefs *next; char *name; long addr; sp_lev code; long n_called; struct lc_funcdefs_parm *params; long n_params; }; struct lc_vardefs { struct lc_vardefs *next; char *name; long var_type; /* SPOVAR_foo */ long n_used; }; struct lc_breakdef { struct lc_breakdef *next; struct opvar *breakpoint; int break_depth; }; /* * Quick! Avert your eyes while you still have a chance! */ #ifdef SPEC_LEV /* compiling lev_comp rather than nethack */ #ifdef USE_OLDARGS #undef VA_ARGS #undef VA_DECL #undef VA_DECL2 #undef VA_SHIFT #define VA_ARGS \ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, \ arg12, arg13, arg14 #define VA_DECL(typ1, var1) \ (var1, VA_ARGS) typ1 var1; \ char *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8, *arg9, \ *arg10, *arg11, *arg12, *arg13, *arg14; \ { #define VA_DECL2(typ1, var1, typ2, var2) \ (var1, var2, VA_ARGS) typ1 var1; \ typ2 var2; \ char *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8, *arg9, \ *arg10, *arg11, *arg12, *arg13, *arg14; \ { /* unlike in the core, lev_comp's VA_SHIFT is completely safe, because callers always pass all these arguments */ #define VA_SHIFT() \ (arg1 = arg2, arg2 = arg3, arg3 = arg4, arg4 = arg5, arg5 = arg6, \ arg6 = arg7, arg7 = arg8, arg8 = arg9, arg9 = arg10, arg10 = arg11, \ arg11 = arg12, arg12 = arg13, arg13 = arg14, arg14 = 0) /* standard NULL may be either (void *)0 or plain 0, both of which would need to be explicitly cast to (char *) here */ typedef char *Va; #define VA_PASS1(a1) \ (Va) a1, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS2(a1, a2) \ (Va) a1, (Va) a2, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS3(a1, a2, a3) \ (Va) a1, (Va) a2, (Va) a3, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS4(a1, a2, a3, a4) \ (Va) a1, (Va) a2, (Va) a3, (Va) a4, (Va) 0, (Va) 0, (Va) 0, (Va) 0, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS5(a1, a2, a3, a4, a5) \ (Va) a1, (Va) a2, (Va) a3, (Va) a4, (Va) a5, (Va) 0, (Va) 0, (Va) 0, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS7(a1, a2, a3, a4, a5, a6, a7) \ (Va) a1, (Va) a2, (Va) a3, (Va) a4, (Va) a5, (Va) a6, (Va) a7, (Va) 0, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS8(a1, a2, a3, a4, a5, a6, a7, a8) \ (Va) a1, (Va) a2, (Va) a3, (Va) a4, (Va) a5, (Va) a6, (Va) a7, (Va) a8, \ (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS9(a1, a2, a3, a4, a5, a6, a7, a8, a9) \ (Va) a1, (Va) a2, (Va) a3, (Va) a4, (Va) a5, (Va) a6, (Va) a7, (Va) a8, \ (Va) a9, (Va) 0, (Va) 0, (Va) 0, (Va) 0, (Va) 0 #define VA_PASS14(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, \ a14) \ (Va) a1, (Va) a2, (Va) a3, (Va) a4, (Va) a5, (Va) a6, (Va) a7, (Va) a8, \ (Va) a9, (Va) a10, (Va) a11, (Va) a12, (Va) a13, (Va) a14 #else /*!USE_OLDARGS*/ /* USE_STDARG and USE_VARARGS don't need to pass dummy arguments or cast real ones */ #define VA_PASS1(a1) a1 #define VA_PASS2(a1, a2) a1, a2 #define VA_PASS3(a1, a2, a3) a1, a2, a3 #define VA_PASS4(a1, a2, a3, a4) a1, a2, a3, a4 #define VA_PASS5(a1, a2, a3, a4, a5) a1, a2, a3, a4, a5 #define VA_PASS7(a1, a2, a3, a4, a5, a6, a7) a1, a2, a3, a4, a5, a6, a7 #define VA_PASS8(a1, a2, a3, a4, a5, a6, a7, a8) \ a1, a2, a3, a4, a5, a6, a7, a8 #define VA_PASS9(a1, a2, a3, a4, a5, a6, a7, a8, a9) \ a1, a2, a3, a4, a5, a6, a7, a8, a9 #define VA_PASS14(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, \ a14) \ a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 #endif /*?USE_OLDARGS*/ /* You were warned to avert your eyes.... */ #endif /*SPEC_LEV*/ #endif /* SP_LEV_H */ nethack-3.6.0/include/spell.h0000664000076400007660000000143612536476415015071 0ustar paxedpaxed/* NetHack 3.6 spell.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright 1986, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SPELL_H #define SPELL_H #define NO_SPELL 0 /* spellbook re-use control; used when reading and when polymorphing */ #define MAX_SPELL_STUDY 3 struct spell { short sp_id; /* spell id (== object.otyp) */ xchar sp_lev; /* power level */ int sp_know; /* knowlege of spell */ }; /* levels of memory destruction with a scroll of amnesia */ #define ALL_MAP 0x1 #define ALL_SPELLS 0x2 #define decrnknow(spell) spl_book[spell].sp_know-- #define spellid(spell) spl_book[spell].sp_id #define spellknow(spell) spl_book[spell].sp_know #endif /* SPELL_H */ nethack-3.6.0/include/sys.h0000664000076400007660000000307012631241231014542 0ustar paxedpaxed/* NetHack 3.6 sys.h $NHDT-Date: 1449296291 2015/12/05 06:18:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SYS_H #define SYS_H struct sysopt { char *support; /* local support contact */ char *recover; /* how to run recover - may be overridden by win port */ char *wizards; /* space-separated list of usernames */ char *fmtd_wizard_list; /* formatted version of wizards; null or "one" or "one or two" or "one, two, or three", &c */ char *explorers; /* like wizards, but for access to explore mode */ char *shellers; /* like wizards, for ! command (-DSHELL); also ^Z */ char *debugfiles; /* files to show debugplines in. '*' is all. */ int env_dbgfl; /* 1: debugfiles comes from getenv("DEBUGFILES") * so sysconf's DEBUGFILES shouldn't override it; * 0: getenv() hasn't been attempted yet; * -1: getenv() didn't find a value for DEBUGFILES. */ int maxplayers; int seduce; int check_save_uid; /* restoring savefile checks UID? */ /* record file */ int persmax; int pers_is_uid; int entrymax; int pointsmin; int tt_oname_maxrank; /* panic options */ char *gdbpath; char *greppath; int panictrace_gdb; int panictrace_libc; }; extern struct sysopt sysopt; #define SYSOPT_SEDUCE sysopt.seduce #endif /* SYS_H */ nethack-3.6.0/include/system.h0000664000076400007660000003637012631241231015261 0ustar paxedpaxed/* NetHack 3.6 system.h $NHDT-Date: 1449269772 2015/12/04 22:56:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SYSTEM_H #define SYSTEM_H #if !defined(__cplusplus) && !defined(__GO32__) #define E extern /* some old may not define off_t and size_t; if your system is * one of these, define them by hand below */ #if (defined(VMS) && !defined(__GNUC__)) || defined(MAC) #include #else #ifndef AMIGA #include #endif #endif #if (defined(MICRO) && !defined(TOS)) || defined(ANCIENT_VAXC) #if !defined(_SIZE_T) && !defined(__size_t) /* __size_t for CSet/2 */ #define _SIZE_T #if !((defined(MSDOS) || defined(OS2)) \ && defined(_SIZE_T_DEFINED)) /* MSC 5.1 */ #if !(defined(__GNUC__) && defined(AMIGA)) typedef unsigned int size_t; #endif #endif #endif #endif /* MICRO && !TOS */ #if defined(__TURBOC__) || defined(MAC) #include /* time_t is not in */ #endif #if defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC)) /* The Ultrix v3.0 seems to be very wrong. */ #define time_t long #endif #if defined(ULTRIX) || defined(VMS) #define off_t long #endif #if defined(AZTEC) || defined(THINKC4) || defined(__TURBOC__) typedef long off_t; #endif #endif /* !__cplusplus && !__GO32__ */ /* You may want to change this to fit your system, as this is almost * impossible to get right automatically. * This is the type of signal handling functions. */ #if !defined(OS2) && (defined(_MSC_VER) || defined(__TURBOC__) \ || defined(__SC__) || defined(WIN32)) #define SIG_RET_TYPE void(__cdecl *)(int) #endif #ifndef SIG_RET_TYPE #if defined(NHSTDC) || defined(POSIX_TYPES) || defined(OS2) || defined(__DECC) #define SIG_RET_TYPE void (*)() #endif #endif #ifndef SIG_RET_TYPE #if defined(ULTRIX) || defined(SUNOS4) || defined(SVR3) || defined(SVR4) /* SVR3 is defined automatically by some systems */ #define SIG_RET_TYPE void (*)() #endif #endif #ifndef SIG_RET_TYPE /* BSD, SIII, SVR2 and earlier, Sun3.5 and earlier */ #define SIG_RET_TYPE int (*)() #endif #if !defined(__cplusplus) && !defined(__GO32__) #if defined(BSD) || defined(ULTRIX) || defined(RANDOM) #ifdef random #undef random #endif #if !defined(__SC__) && !defined(LINUX) E long NDECL(random); #endif #if (!defined(SUNOS4) && !defined(bsdi) && !defined(__FreeBSD__)) \ || defined(RANDOM) E void FDECL(srandom, (unsigned int)); #else #if !defined(bsdi) && !defined(__FreeBSD__) E int FDECL(srandom, (unsigned int)); #endif #endif #else E long lrand48(); E void srand48(); #endif /* BSD || ULTRIX || RANDOM */ #if !defined(BSD) || defined(ultrix) /* real BSD wants all these to return int */ #ifndef MICRO E void FDECL(exit, (int)); #endif /* MICRO */ /* compensate for some CSet/2 bogosities */ #if defined(OS2_CSET2) && defined(OS2_CSET2_VER_2) #define open _open #define close _close #define read _read #define write _write #define lseek _lseek #define chdir _chdir #define getcwd _getcwd #define setmode _setmode #endif /* OS2_CSET2 && OS2_CSET2_VER_2 */ /* If flex thinks that we're not __STDC__ it declares free() to return int and we die. We must use __STDC__ instead of NHSTDC because the former is naturally what flex tests for. */ #if defined(__STDC__) || !defined(FLEX_SCANNER) #ifndef OS2_CSET2 #ifndef MONITOR_HEAP E void FDECL(free, (genericptr_t)); #endif #endif #endif #if !defined(__SASC_60) && !defined(_DCC) && !defined(__SC__) #if defined(AMIGA) && !defined(AZTEC_50) && !defined(__GNUC__) E int FDECL(perror, (const char *)); #else #if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) E void FDECL(perror, (const char *)); #endif #endif #endif #endif #ifndef NeXT #ifdef POSIX_TYPES E void FDECL(qsort, (genericptr_t, size_t, size_t, int (*)(const genericptr, const genericptr))); #else #if defined(BSD) || defined(ULTRIX) E int qsort(); #else #if !defined(LATTICE) && !defined(AZTEC_50) E void FDECL(qsort, (genericptr_t, size_t, size_t, int (*)(const genericptr, const genericptr))); #endif #endif #endif #endif /* NeXT */ #ifndef __SASC_60 #if !defined(AZTEC_50) && !defined(__GNUC__) /* may already be defined */ #ifdef ULTRIX #ifdef ULTRIX_PROTO E int FDECL(lseek, (int, off_t, int)); #else E long FDECL(lseek, (int, off_t, int)); #endif /* Ultrix 3.0 man page mistakenly says it returns an int. */ E int FDECL(write, (int, char *, int)); E int FDECL(link, (const char *, const char *)); #else #ifndef bsdi E long FDECL(lseek, (int, long, int)); #endif #if defined(POSIX_TYPES) || defined(__TURBOC__) #ifndef bsdi E int FDECL(write, (int, const void *, unsigned)); #endif #else #ifndef __MWERKS__ /* metrowerks defines write via universal headers */ E int FDECL(write, (int, genericptr_t, unsigned)); #endif #endif #endif /* ULTRIX */ #ifdef OS2_CSET2 /* IBM CSet/2 */ #ifdef OS2_CSET2_VER_1 E int FDECL(unlink, (char *)); #else E int FDECL(unlink, (const char *)); /* prototype is ok in ver >= 2 */ #endif #else #ifndef __SC__ E int FDECL(unlink, (const char *)); #endif #endif #endif /* AZTEC_50 && __GNUC__ */ #ifdef MAC #ifndef __CONDITIONALMACROS__ /* universal headers */ E int FDECL(close, (int)); /* unistd.h */ E int FDECL(read, (int, char *, int)); /* unistd.h */ E int FDECL(chdir, (const char *)); /* unistd.h */ E char *FDECL(getcwd, (char *, int)); /* unistd.h */ #endif E int FDECL(open, (const char *, int)); #endif #if defined(MICRO) E int FDECL(close, (int)); #ifndef __EMX__ E int FDECL(read, (int, genericptr_t, unsigned int)); #endif E int FDECL(open, (const char *, int, ...)); E int FDECL(dup2, (int, int)); E int FDECL(setmode, (int, int)); E int NDECL(kbhit); #if !defined(_DCC) #if defined(__TURBOC__) E int FDECL(chdir, (const char *)); #else #ifndef __EMX__ E int FDECL(chdir, (char *)); #endif #endif #ifndef __EMX__ E char *FDECL(getcwd, (char *, int)); #endif #endif /* !_DCC */ #endif #ifdef ULTRIX E int FDECL(close, (int)); E int FDECL(atoi, (const char *)); E long FDECL(atol, (const char *)); E int FDECL(chdir, (const char *)); #if !defined(ULTRIX_CC20) && !defined(__GNUC__) E int FDECL(chmod, (const char *, int)); E mode_t FDECL(umask, (int)); #endif E int FDECL(read, (int, genericptr_t, unsigned)); /* these aren't quite right, but this saves including lots of system files */ E int FDECL(stty, (int, genericptr_t)); E int FDECL(gtty, (int, genericptr_t)); E int FDECL(ioctl, (int, int, char *)); E int FDECL(isatty, (int)); /* 1==yes, 0==no, -1==error */ #include #if defined(ULTRIX_PROTO) || defined(__GNUC__) E int NDECL(fork); #else E long NDECL(fork); #endif #endif /* ULTRIX */ #ifdef VMS #ifndef abs E int FDECL(abs, (int)); #endif E int FDECL(atexit, (void (*)(void))); E int FDECL(atoi, (const char *)); E long FDECL(atol, (const char *)); E int FDECL(chdir, (const char *)); E int FDECL(chown, (const char *, unsigned, unsigned)); #ifdef __DECC_VER E int FDECL(chmod, (const char *, mode_t)); E mode_t FDECL(umask, (mode_t)); #else E int FDECL(chmod, (const char *, int)); E int FDECL(umask, (int)); #endif /* #include */ E int FDECL(close, (int)); E int VDECL(creat, (const char *, unsigned, ...)); E int FDECL(delete, (const char *)); E int FDECL(fstat, (/*_ int, stat_t * _*/)); E int FDECL(isatty, (int)); /* 1==yes, 0==no, -1==error */ E long FDECL(lseek, (int, long, int)); E int VDECL(open, (const char *, int, unsigned, ...)); E int FDECL(read, (int, genericptr_t, unsigned)); E int FDECL(rename, (const char *, const char *)); E int FDECL(stat, (/*_ const char *,stat_t * _*/)); E int FDECL(write, (int, const genericptr, unsigned)); #endif #endif /* __SASC_60 */ /* both old & new versions of Ultrix want these, but real BSD does not */ #ifdef ultrix E void abort(); E void bcopy(); #ifdef ULTRIX E int FDECL(system, (const char *)); #ifndef _UNISTD_H_ E int FDECL(execl, (const char *, ...)); #endif #endif #endif #ifdef MICRO E void NDECL(abort); E void FDECL(_exit, (int)); E int FDECL(system, (const char *)); #endif #if defined(HPUX) && !defined(_POSIX_SOURCE) E long NDECL(fork); #endif #ifdef POSIX_TYPES /* The POSIX string.h is required to define all the mem* and str* functions */ #include #else #if defined(SYSV) || defined(VMS) || defined(MAC) || defined(SUNOS4) #if defined(NHSTDC) || (defined(VMS) && !defined(ANCIENT_VAXC)) #if !defined(_AIX32) && !(defined(SUNOS4) && defined(__STDC__)) /* Solaris unbundled cc (acc) */ E int FDECL(memcmp, (const void *, const void *, size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); #endif #else #ifndef memcmp /* some systems seem to macro these back to b*() */ E int memcmp(); #endif #ifndef memcpy E char *memcpy(); #endif #ifndef memset E char *memset(); #endif #endif #else #ifdef HPUX E int FDECL(memcmp, (char *, char *, int)); E void *FDECL(memcpy, (char *, char *, int)); E void *FDECL(memset, (char *, int, int)); #endif #endif #endif /* POSIX_TYPES */ #if defined(MICRO) && !defined(LATTICE) #if defined(TOS) && defined(__GNUC__) E int FDECL(memcmp, (const void *, const void *, size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); #else #if defined(AZTEC_50) || defined(NHSTDC) || defined(WIN32) E int FDECL(memcmp, (const void *, const void *, size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); #else E int FDECL(memcmp, (char *, char *, unsigned int)); E char *FDECL(memcpy, (char *, char *, unsigned int)); E char *FDECL(memset, (char *, int, int)); #endif /* AZTEC_50 || NHSTDC */ #endif /* TOS */ #endif /* MICRO */ #if defined(BSD) && defined(ultrix) /* i.e., old versions of Ultrix */ E void sleep(); #endif #if defined(ULTRIX) || defined(SYSV) E unsigned sleep(); #endif #if defined(HPUX) E unsigned int FDECL(sleep, (unsigned int)); #endif #ifdef VMS E int FDECL(sleep, (unsigned)); #endif E char *FDECL(getenv, (const char *)); E char *getlogin(); #if defined(HPUX) && !defined(_POSIX_SOURCE) E long NDECL(getuid); E long NDECL(getgid); E long NDECL(getpid); #else #ifdef POSIX_TYPES E pid_t NDECL(getpid); E uid_t NDECL(getuid); E gid_t NDECL(getgid); #ifdef VMS E pid_t NDECL(getppid); #endif #else /*!POSIX_TYPES*/ #ifndef getpid /* Borland C defines getpid() as a macro */ E int NDECL(getpid); #endif #ifdef VMS E int NDECL(getppid); E unsigned NDECL(getuid); E unsigned NDECL(getgid); #endif #if defined(ULTRIX) && !defined(_UNISTD_H_) E unsigned NDECL(getuid); E unsigned NDECL(getgid); E int FDECL(setgid, (int)); E int FDECL(setuid, (int)); #endif #endif /*?POSIX_TYPES*/ #endif /*?(HPUX && !_POSIX_SOURCE)*/ /* add more architectures as needed */ #if defined(HPUX) #define seteuid(x) setreuid(-1, (x)); #endif /*# string(s).h #*/ #if !defined(_XtIntrinsic_h) && !defined(POSIX_TYPES) /* #includes ; so does defining POSIX_TYPES */ #if (defined(ULTRIX) || defined(NeXT)) && defined(__GNUC__) #include #else E char *FDECL(strcpy, (char *, const char *)); E char *FDECL(strncpy, (char *, const char *, size_t)); E char *FDECL(strcat, (char *, const char *)); E char *FDECL(strncat, (char *, const char *, size_t)); E char *FDECL(strpbrk, (const char *, const char *)); #if defined(SYSV) || defined(MICRO) || defined(MAC) || defined(VMS) \ || defined(HPUX) E char *FDECL(strchr, (const char *, int)); E char *FDECL(strrchr, (const char *, int)); #else /* BSD */ E char *FDECL(index, (const char *, int)); E char *FDECL(rindex, (const char *, int)); #endif E int FDECL(strcmp, (const char *, const char *)); E int FDECL(strncmp, (const char *, const char *, size_t)); #if defined(MICRO) || defined(MAC) || defined(VMS) E size_t FDECL(strlen, (const char *)); #else #ifdef HPUX E unsigned int FDECL(strlen, (char *)); #else #if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) E int FDECL(strlen, (const char *)); #endif #endif /* HPUX */ #endif /* MICRO */ #endif /* ULTRIX */ #endif /* !_XtIntrinsic_h_ && !POSIX_TYPES */ #if defined(ULTRIX) && defined(__GNUC__) E char *FDECL(index, (const char *, int)); E char *FDECL(rindex, (const char *, int)); #endif /* Old varieties of BSD have char *sprintf(). * Newer varieties of BSD have int sprintf() but allow for the old char *. * Several varieties of SYSV and PC systems also have int sprintf(). * If your system doesn't agree with this breakdown, you may want to change * this declaration, especially if your machine treats the types differently. * If your system defines sprintf, et al, in stdio.h, add to the initial * #if. */ #if defined(ULTRIX) || defined(__DECC) || defined(__SASC_60) || defined(WIN32) #define SPRINTF_PROTO #endif #if (defined(SUNOS4) && defined(__STDC__)) || defined(_AIX32) #define SPRINTF_PROTO #endif #if defined(TOS) || defined(AZTEC_50) || defined(__sgi) || defined(__GNUC__) /* problem with prototype mismatches */ #define SPRINTF_PROTO #endif #if defined(__MWERKS__) || defined(__SC__) /* Metrowerks already has a prototype for sprintf() */ #define SPRINTF_PROTO #endif #ifndef SPRINTF_PROTO #if defined(POSIX_TYPES) || defined(DGUX) || defined(NeXT) || !defined(BSD) E int FDECL(sprintf, (char *, const char *, ...)); #else #define OLD_SPRINTF E char *sprintf(); #endif #endif #ifdef SPRINTF_PROTO #undef SPRINTF_PROTO #endif #ifndef __SASC_60 #ifdef NEED_VARARGS #if defined(USE_STDARG) || defined(USE_VARARGS) #if !defined(SVR4) && !defined(apollo) #if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) #if !(defined(SUNOS4) && defined(__STDC__)) /* Solaris unbundled cc (acc) */ E int FDECL(vsprintf, (char *, const char *, va_list)); E int FDECL(vfprintf, (FILE *, const char *, va_list)); E int FDECL(vprintf, (const char *, va_list)); #endif #endif #endif #else #define vprintf printf #define vfprintf fprintf #define vsprintf sprintf #endif #endif /* NEED_VARARGS */ #endif #ifdef MICRO E int FDECL(tgetent, (const char *, const char *)); E void FDECL(tputs, (const char *, int, int (*)())); E int FDECL(tgetnum, (const char *)); E int FDECL(tgetflag, (const char *)); E char *FDECL(tgetstr, (const char *, char **)); E char *FDECL(tgoto, (const char *, int, int)); #else #if !(defined(HPUX) && defined(_POSIX_SOURCE)) E int FDECL(tgetent, (char *, const char *)); E void FDECL(tputs, (const char *, int, int (*)())); #endif E int FDECL(tgetnum, (const char *)); E int FDECL(tgetflag, (const char *)); E char *FDECL(tgetstr, (const char *, char **)); E char *FDECL(tgoto, (const char *, int, int)); #endif #if defined(ALLOC_C) || defined(MAKEDEFS_C) E genericptr_t FDECL(malloc, (size_t)); E genericptr_t FDECL(realloc, (genericptr_t, size_t)); #endif /* time functions */ #ifndef LATTICE #if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) E struct tm *FDECL(localtime, (const time_t *)); #endif #endif #if defined(ULTRIX) || (defined(BSD) && defined(POSIX_TYPES)) \ || defined(SYSV) || defined(MICRO) || defined(VMS) || defined(MAC) \ || (defined(HPUX) && defined(_POSIX_SOURCE)) E time_t FDECL(time, (time_t *)); #else E long FDECL(time, (time_t *)); #endif /* ULTRIX */ #ifdef VMS /* used in makedefs.c, but missing from gcc-vms's */ E char *FDECL(ctime, (const time_t *)); #endif #ifdef MICRO #ifdef abs #undef abs #endif E int FDECL(abs, (int)); #ifdef atoi #undef atoi #endif E int FDECL(atoi, (const char *)); #endif #undef E #endif /* !__cplusplus && !__GO32__ */ #endif /* SYSTEM_H */ nethack-3.6.0/include/tcap.h0000664000076400007660000000315012536476415014674 0ustar paxedpaxed/* NetHack 3.6 tcap.h $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1989. */ /* NetHack may be freely redistributed. See license for details. */ /* not named termcap.h because it may conflict with a system header */ #ifndef TCAP_H #define TCAP_H #ifndef MICRO #define TERMLIB /* include termcap code */ #endif /* might display need graphics code? */ #if !defined(AMIGA) && !defined(TOS) && !defined(MAC) #if defined(TERMLIB) || defined(OS2) || defined(MSDOS) #define ASCIIGRAPH #endif #endif #ifndef DECL_H extern struct tc_gbl_data { /* also declared in decl.h; defined in decl.c */ char *tc_AS, *tc_AE; /* graphics start and end (tty font swapping) */ int tc_LI, tc_CO; /* lines and columns */ } tc_gbl_data; #define AS tc_gbl_data.tc_AS #define AE tc_gbl_data.tc_AE #define LI tc_gbl_data.tc_LI #define CO tc_gbl_data.tc_CO #endif extern struct tc_lcl_data { /* defined and set up in termcap.c */ char *tc_CM, *tc_ND, *tc_CD; char *tc_HI, *tc_HE, *tc_US, *tc_UE; boolean tc_ul_hack; } tc_lcl_data; /* some curses.h declare CM etc. */ #define nh_CM tc_lcl_data.tc_CM #define nh_ND tc_lcl_data.tc_ND #define nh_CD tc_lcl_data.tc_CD #define nh_HI tc_lcl_data.tc_HI #define nh_HE tc_lcl_data.tc_HE #define nh_US tc_lcl_data.tc_US #define nh_UE tc_lcl_data.tc_UE #define ul_hack tc_lcl_data.tc_ul_hack extern short ospeed; /* set up in termcap.c */ #ifdef TEXTCOLOR #ifdef TOS extern const char *hilites[CLR_MAX]; #else extern NEARDATA char *hilites[CLR_MAX]; #endif #endif #endif /* TCAP_H */ nethack-3.6.0/include/tile2x11.h0000664000076400007660000000107612536476415015323 0ustar paxedpaxed/* NetHack 3.6 tile2x11.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TILE2X11_H #define TILE2X11_H /* * Header for the x11 tile map. */ typedef struct { unsigned long version; unsigned long ncolors; unsigned long tile_width; unsigned long tile_height; unsigned long ntiles; unsigned long per_row; } x11_header; /* how wide each row in the tile file is, in tiles */ #define TILES_PER_ROW (40) #endif /* TILE2X11_H */ nethack-3.6.0/include/timeout.h0000664000076400007660000000307112536476415015435 0ustar paxedpaxed/* NetHack 3.6 timeout.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright 1994, Dean Luick */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TIMEOUT_H #define TIMEOUT_H /* generic timeout function */ typedef void FDECL((*timeout_proc), (ANY_P *, long)); /* kind of timer */ #define TIMER_LEVEL 0 /* event specific to level */ #define TIMER_GLOBAL 1 /* event follows current play */ #define TIMER_OBJECT 2 /* event follows a object */ #define TIMER_MONSTER 3 /* event follows a monster */ /* save/restore timer ranges */ #define RANGE_LEVEL 0 /* save/restore timers staying on level */ #define RANGE_GLOBAL 1 /* save/restore timers following global play */ /* * Timeout functions. Add a define here, then put it in the table * in timeout.c. "One more level of indirection will fix everything." */ #define ROT_ORGANIC 0 /* for buried organics */ #define ROT_CORPSE 1 #define REVIVE_MON 2 #define BURN_OBJECT 3 #define HATCH_EGG 4 #define FIG_TRANSFORM 5 #define MELT_ICE_AWAY 6 #define NUM_TIME_FUNCS 7 /* used in timeout.c */ typedef struct fe { struct fe *next; /* next item in chain */ long timeout; /* when we time out */ unsigned long tid; /* timer ID */ short kind; /* kind of use */ short func_index; /* what to call when we time out */ anything arg; /* pointer to timeout argument */ Bitfield(needs_fixup, 1); /* does arg need to be patched? */ } timer_element; #endif /* TIMEOUT_H */ nethack-3.6.0/include/tosconf.h0000664000076400007660000000421112536476415015417 0ustar paxedpaxed/* NetHack 3.6 tosconf.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef TOS #ifndef TOSCONF_H #define TOSCONF_H #define MICRO /* must be defined to allow some inclusions */ /* Adjust these options to suit your compiler. The default here is for GNU C with the MiNT library. */ /*#define NO_SIGNAL /* library doesn't support signals */ /*#define NO_FSTAT /* library doesn't have fstat() call */ #define MINT /* library supports MiNT extensions to TOS */ #ifdef __MINT__ #define MINT #endif #ifdef O_BINARY #define FCMASK O_BINARY #else #define FCMASK 0660 #define O_BINARY 0 #endif #ifdef UNIXDEBUG #define remove(x) unlink(x) #endif /* configurable options */ #define MFLOPPY /* floppy support */ #define RANDOM /* improved random numbers */ #define SHELL /* allow spawning of shell */ #define TERMLIB /* use termcap */ #define TEXTCOLOR /* allow color */ #define MAIL /* enable the fake maildemon */ #ifdef MINT #define SUSPEND /* allow suspending the game */ #endif #ifndef TERMLIB #define ANSI_DEFAULT /* use vt52 by default */ #endif #if defined(__GNUC__) || defined(__MINT__) /* actually, only more recent GNU C libraries have strcmpi * on the other hand, they're free -- if yours is out of * date, grab the most recent from atari.archive.umich.edu */ #define STRNCMPI #undef strcmpi extern int FDECL(strcmpi, (const char *, const char *)); extern int FDECL(strncmpi, (const char *, const char *, size_t)); #endif #include #include /* instead of including system.h from pcconf.h */ #include #include #include #define SIG_RET_TYPE __Sigfunc #define SYSTEM_H #ifndef MICRO_H #include "micro.h" #endif #ifndef PCCONF_H #include "pcconf.h" /* remainder of stuff is same as the PC */ #endif #ifdef TEXTCOLOR extern boolean colors_changed; /* in tos.c */ #endif #ifdef __GNUC__ #define GCC_BUG /* correct a gcc bug involving double for loops */ #endif #endif /* TOSCONF_H */ #endif /* TOS */ nethack-3.6.0/include/tradstdc.h0000664000076400007660000003077012624522452015554 0ustar paxedpaxed/* NetHack 3.6 tradstdc.h $NHDT-Date: 1448210011 2015/11/22 16:33:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TRADSTDC_H #define TRADSTDC_H #if defined(DUMB) && !defined(NOVOID) #define NOVOID #endif #ifdef NOVOID #define void int #endif /* * Borland C provides enough ANSI C compatibility in its Borland C++ * mode to warrant this. But it does not set __STDC__ unless it compiles * in its ANSI keywords only mode, which prevents use of and * far pointer use. */ #if (defined(__STDC__) || defined(__TURBOC__)) && !defined(NOTSTDC) #define NHSTDC #endif #if defined(ultrix) && defined(__STDC__) && !defined(__LANGUAGE_C) /* Ultrix seems to be in a constant state of flux. This check attempts to * set up ansi compatibility if it wasn't set up correctly by the compiler. */ #ifdef mips #define __mips mips #endif #ifdef LANGUAGE_C #define __LANGUAGE_C LANGUAGE_C #endif #endif /* * ANSI X3J11 detection. * Makes substitutes for compatibility with the old C standard. */ /* Decide how to handle variable parameter lists: * USE_STDARG means use the ANSI facilities (only ANSI compilers * should do this, and only if the library supports it). * USE_VARARGS means use the facilities. Again, this should only * be done if the library supports it. ANSI is *not* required for this. * Otherwise, the kludgy old methods are used. * The defaults are USE_STDARG for ANSI compilers, and USE_OLDARGS for * others. */ /* #define USE_VARARGS */ /* use instead of */ /* #define USE_OLDARGS */ /* don't use any variable argument facilities */ #if defined(apollo) /* Apollos have stdarg(3) but not stdarg.h */ #define USE_VARARGS #endif #if defined(NHSTDC) || defined(ULTRIX_PROTO) || defined(MAC) #if !defined(USE_VARARGS) && !defined(USE_OLDARGS) && !defined(USE_STDARG) #define USE_STDARG #endif #endif #ifdef NEED_VARARGS /* only define these if necessary */ /* * These have changed since 3.4.3. VA_END() now provides an explicit * closing brace to complement VA_DECL()'s hidden opening brace, so code * started with VA_DECL() needs an extra opening brace to complement * the explicit final closing brace. This was done so that the source * would look less strange, where VA_DECL() appeared to introduce a * function whose opening brace was missing; there are now visible and * invisible braces at beginning and end. Sample usage: void foo VA_DECL(int, arg) --macro expansion has a hidden opening brace { --new, explicit opening brace (actually introduces a nested block) VA_START(bar); ...code for foo... VA_END(); --expansion now provides a closing brace for the nested block } --existing closing brace, still pairs with the hidden one in VA_DECL() * Reading the code--or using source browsing tools which match braces-- * results in seeing a matched set of braces. Usage of VA_END() is * potentially trickier, but nethack uses it in a straightforward manner. */ #ifdef USE_STDARG #include #define VA_DECL(typ1, var1) \ (typ1 var1, ...) \ { \ va_list the_args; #define VA_DECL2(typ1, var1, typ2, var2) \ (typ1 var1, typ2 var2, ...) \ { \ va_list the_args; #define VA_INIT(var1, typ1) #define VA_NEXT(var1, typ1) var1 = va_arg(the_args, typ1) #define VA_ARGS the_args #define VA_START(x) va_start(the_args, x) #define VA_END() \ va_end(the_args); \ } #if defined(ULTRIX_PROTO) && !defined(_VA_LIST_) #define _VA_LIST_ /* prevents multiple def in stdio.h */ #endif #else #ifdef USE_VARARGS #include #define VA_DECL(typ1, var1) \ (va_alist) va_dcl \ { \ va_list the_args; \ typ1 var1; #define VA_DECL2(typ1, var1, typ2, var2) \ (va_alist) va_dcl \ { \ va_list the_args; \ typ1 var1; \ typ2 var2; #define VA_ARGS the_args #define VA_START(x) va_start(the_args) #define VA_INIT(var1, typ1) var1 = va_arg(the_args, typ1) #define VA_NEXT(var1, typ1) var1 = va_arg(the_args, typ1) #define VA_END() \ va_end(the_args); \ } #else /*USE_OLDARGS*/ #define VA_ARGS arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 #define VA_DECL(typ1, var1) \ (var1, VA_ARGS) typ1 var1; \ char *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8, *arg9; \ { #define VA_DECL2(typ1, var1, typ2, var2) \ (var1, var2, VA_ARGS) typ1 var1; \ typ2 var2; \ char *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8, *arg9; \ { #define VA_START(x) #define VA_INIT(var1, typ1) /* This is inherently risky, and should only be attempted as a very last resort; manipulating arguments which haven't actually been passed may or may not cause severe trouble depending on the function-calling/argument-passing mechanism being used. [nethack's core doesn't use VA_NEXT() so doesn't use VA_SHIFT() either, and this definition is just retained for completeness. lev_comp does use VA_NEXT(), but it passes all 'argX' arguments.] */ #define VA_SHIFT() \ (arg1 = arg2, arg2 = arg3, arg3 = arg4, arg4 = arg5, arg5 = arg6, \ arg6 = arg7, arg7 = arg8, arg8 = arg9) #define VA_NEXT(var1, typ1) ((var1 = (typ1) arg1), VA_SHIFT(), var1) #define VA_END() } #endif #endif #endif /* NEED_VARARGS */ #if defined(NHSTDC) || defined(MSDOS) || defined(MAC) \ || defined(ULTRIX_PROTO) || defined(__BEOS__) /* * Used for robust ANSI parameter forward declarations: * int VDECL(sprintf, (char *, const char *, ...)); * * NDECL() is used for functions with zero arguments; * FDECL() is used for functions with a fixed number of arguments; * VDECL() is used for functions with a variable number of arguments. * Separate macros are needed because ANSI will mix old-style declarations * with prototypes, except in the case of varargs, and the OVERLAY-specific * trampoli.* mechanism conflicts with the ANSI <> syntax. */ #define NDECL(f) f(void) /* overridden later if USE_TRAMPOLI set */ #define FDECL(f, p) f p #if defined(MSDOS) || defined(USE_STDARG) #define VDECL(f, p) f p #else #define VDECL(f, p) f() #endif /* * Used for definitions of functions which take no arguments to force * an explicit match with the NDECL prototype. Needed in some cases * (MS Visual C 2005) for functions called through pointers. */ #define VOID_ARGS void /* generic pointer, always a macro; genericptr_t is usually a typedef */ #define genericptr void * #if (defined(ULTRIX_PROTO) && !defined(__GNUC__)) || defined(OS2_CSET2) /* Cover for Ultrix on a DECstation with 2.0 compiler, which coredumps on * typedef void * genericptr_t; * extern void a(void(*)(int, genericptr_t)); * Using the #define is OK for other compiler versions too. */ /* And IBM CSet/2. The redeclaration of free hoses the compile. */ #define genericptr_t genericptr #else #if !defined(NHSTDC) && !defined(MAC) #define const #define signed #define volatile #endif #endif /* * Suppress `const' if necessary and not handled elsewhere. * Don't use `#if defined(xxx) && !defined(const)' * because some compilers choke on `defined(const)'. * This has been observed with Lattice, MPW, and High C. */ #if (defined(ULTRIX_PROTO) && !defined(NHSTDC)) || defined(apollo) /* the system header files don't use `const' properly */ #ifndef const #define const #endif #endif #else /* NHSTDC */ /* a "traditional" C compiler */ #define NDECL(f) f() #define FDECL(f, p) f() #define VDECL(f, p) f() #define VOID_ARGS /*empty*/ #if defined(AMIGA) || defined(HPUX) || defined(POSIX_TYPES) \ || defined(__DECC) || defined(__BORLANDC__) #define genericptr void * #endif #ifndef genericptr #define genericptr char * #endif /* * Traditional C compilers don't have "signed", "const", or "volatile". */ #define signed #define const #define volatile #endif /* NHSTDC */ #ifndef genericptr_t typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif #if defined(MICRO) || defined(WIN32) /* We actually want to know which systems have an ANSI run-time library * to know which support the %p format for printing pointers. * Due to the presence of things like gcc, NHSTDC is not a good test. * So we assume microcomputers have all converted to ANSI and bigger * computers which may have older libraries give reasonable results with * casting pointers to unsigned long int (fmt_ptr() in alloc.c). */ #define HAS_PTR_FMT #endif /* * According to ANSI, prototypes for old-style declarations must widen the * arguments to int. However, the MSDOS compilers accept shorter arguments * (char, short, etc.) in prototypes and do typechecking with them. Therefore * this mess to allow the better typechecking while also allowing some * prototypes for the ANSI compilers so people quit trying to fix the * prototypes to match the standard and thus lose the typechecking. */ #if defined(MSDOS) && !defined(__GO32__) #define UNWIDENED_PROTOTYPES #endif #if defined(AMIGA) && !defined(AZTEC_50) #define UNWIDENED_PROTOTYPES #endif #if defined(macintosh) && (defined(__SC__) || defined(__MRC__)) #define WIDENED_PROTOTYPES #endif #if defined(__MWERKS__) && defined(__BEOS__) #define UNWIDENED_PROTOTYPES #endif #if defined(WIN32) #define UNWIDENED_PROTOTYPES #endif #if defined(ULTRIX_PROTO) && defined(ULTRIX_CC20) #define UNWIDENED_PROTOTYPES #endif #if defined(apollo) #define UNWIDENED_PROTOTYPES #endif #ifndef UNWIDENED_PROTOTYPES #if defined(NHSTDC) || defined(ULTRIX_PROTO) || defined(THINK_C) #ifndef WIDENED_PROTOTYPES #define WIDENED_PROTOTYPES #endif #endif #endif /* These are used for arguments within FDECL/VDECL prototype declarations. */ #ifdef UNWIDENED_PROTOTYPES #define CHAR_P char #define SCHAR_P schar #define UCHAR_P uchar #define XCHAR_P xchar #define SHORT_P short #ifndef SKIP_BOOLEAN #define BOOLEAN_P boolean #endif #define ALIGNTYP_P aligntyp #else #ifdef WIDENED_PROTOTYPES #define CHAR_P int #define SCHAR_P int #define UCHAR_P int #define XCHAR_P int #define SHORT_P int #define BOOLEAN_P int #define ALIGNTYP_P int #else /* Neither widened nor unwidened prototypes. Argument list expansion * by FDECL/VDECL always empty; all xxx_P vanish so defs aren't needed. */ #endif #endif /* OBJ_P and MONST_P should _only_ be used for declaring function pointers. */ #if defined(ULTRIX_PROTO) && !defined(__STDC__) /* The ultrix 2.0 and 2.1 compilers (on Ultrix 4.0 and 4.2 respectively) can't * handle "struct obj *" constructs in prototypes. Their bugs are different, * but both seem to work if we put "void*" in the prototype instead. This * gives us minimal prototype checking but avoids the compiler bugs. */ #define OBJ_P void * #define MONST_P void * #else #define OBJ_P struct obj * #define MONST_P struct monst * #endif #if 0 /* The problem below is still the case through 4.0.5F, but the suggested * compiler flags in the Makefiles suppress the nasty messages, so we don't * need to be quite so drastic. */ #if defined(__sgi) && !defined(__GNUC__) /* * As of IRIX 4.0.1, /bin/cc claims to be an ANSI compiler, but it thinks * it's impossible for a prototype to match an old-style definition with * unwidened argument types. Thus, we have to turn off all NetHack * prototypes, and avoid declaring several system functions, since the system * include files have prototypes and the compiler also complains that * prototyped and unprototyped declarations don't match. */ #undef NDECL #undef FDECL #undef VDECL #define NDECL(f) f() #define FDECL(f, p) f() #define VDECL(f, p) f() #undef VOID_ARGS #define VOID_ARGS /*empty*/ #endif #endif /* MetaWare High-C defaults to unsigned chars */ /* AIX 3.2 needs this also */ #if defined(__HC__) || defined(_AIX32) #undef signed #endif /* * Allow gcc2 to check parameters of printf-like calls with -Wformat; * append this to a prototype declaration (see pline() in extern.h). */ #ifdef __GNUC__ #if __GNUC__ >= 2 #define PRINTF_F(f, v) __attribute__((format(printf, f, v))) #endif #if __GNUC__ >= 3 #define UNUSED __attribute__((unused)) #define NORETURN __attribute__((noreturn)) #endif #endif #ifndef PRINTF_F #define PRINTF_F(f, v) #endif #ifndef UNUSED #define UNUSED #endif #ifndef NORETURN #define NORETURN #endif #endif /* TRADSTDC_H */ nethack-3.6.0/include/trampoli.h0000664000076400007660000001734712536476415015611 0ustar paxedpaxed/* NetHack 3.6 trampoli.h $NHDT-Date: 1433806581 2015/06/08 23:36:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) 1989, by Norm Meluch and Stephen Spackman */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TRAMPOLI_H #define TRAMPOLI_H #ifdef USE_TRAMPOLI /* ### apply.c ### */ #define dig() dig_() #define doapply() doapply_() #define dojump() dojump_() #define dorub() dorub_() /* ### artifact.c ### */ #define doinvoke() doinvoke_() /* ### cmd.c ### */ #define doextcmd() doextcmd_() #define doextlist() doextlist_() #define domonability() domonability_() #define enter_explore_mode() enter_explore_mode_() #define doprev_message() doprev_message_() #define timed_occupation() timed_occupation_() #define wiz_attributes() wiz_attributes_() #define wiz_detect() wiz_detect_() #define wiz_genesis() wiz_genesis_() #define wiz_identify() wiz_identify_() #define wiz_level_tele() wiz_level_tele_() #define wiz_map() wiz_map_() #define wiz_where() wiz_where_() #define wiz_wish() wiz_wish_() /* ### display.c ### */ #define doredraw() doredraw_() /* ### do.c ### */ #define doddrop() doddrop_() #define dodown() dodown_() #define dodrop() dodrop_() #define donull() donull_() #define doup() doup_() #define dowipe() dowipe_() #define drop(x) drop_(x) #define wipeoff() wipeoff_() /* ### do_name.c ### */ #define ddocall() ddocall_() #define do_mname() do_mname_() /* ### do_wear.c ### */ #define Armor_off() Armor_off_() #define Boots_off() Boots_off_() #define Gloves_off() Gloves_off_() #define Helmet_off() Helmet_off_() #define Armor_on() Armor_on_() #define Boots_on() Boots_on_() #define Gloves_on() Gloves_on_() #define Helmet_on() Helmet_on_() #define doddoremarm() doddoremarm_() #define doputon() doputon_() #define doremring() doremring_() #define dotakeoff() dotakeoff_() #define dowear() dowear_() #define select_off(x) select_off_(x) #define take_off() take_off_() /* ### dogmove.c ### */ #define wantdoor(x, y, dummy) wantdoor_(x, y, dummy) /* ### dokick.c ### */ #define dokick() dokick_() /* ### dothrow.c ### */ #define dothrow() dothrow_() /* ### eat.c ### */ #define Hear_again() Hear_again_() #define eatmdone() eatmdone_() #define doeat() doeat_() #define eatfood() eatfood_() #define opentin() opentin_() #define unfaint() unfaint_() /* ### end.c ### */ #define done1(sig) done1_(sig) #define done2() done2_() #define done_intr(sig) done_intr_(sig) #if defined(UNIX) || defined(VMS) || defined(__EMX__) #define done_hangup(sig) done_hangup_(sig) #endif /* ### engrave.c ### */ #define doengrave() doengrave_() /* ### fountain.c ### */ #define gush(x, y, poolcnt) gush_(x, y, poolcnt) /* ### hack.c ### */ #define dopickup() dopickup_() #define identify(x) identify_(x) /* ### invent.c ### */ #define ckunpaid(x) ckunpaid_(x) #define ddoinv() ddoinv_() #define dolook() dolook_() #define dopramulet() dopramulet_() #define doprarm() doprarm_() #define doprgold() doprgold_() #define doprring() doprring_() #define doprtool() doprtool_() #define doprwep() doprwep_() #define dotypeinv() dotypeinv_() #define doorganize() doorganize_() /* ### ioctl.c ### */ #ifdef UNIX #ifdef SUSPEND #define dosuspend() dosuspend_() #endif /* SUSPEND */ #endif /* UNIX */ /* ### lock.c ### */ #define doclose() doclose_() #define doforce() doforce_() #define doopen() doopen_() #define forcelock() forcelock_() #define picklock() picklock_() /* ### mklev.c ### */ #define do_comp(x, y) comp_(x, y) /* ### mondata.c ### */ /* See comment in trampoli.c before uncommenting canseemon. */ /* #define canseemon(x) canseemon_(x) */ /* ### muse.c ### */ #define mbhitm(x, y) mbhitm_(x, y) /* ### o_init.c ### */ #define dodiscovered() dodiscovered_() /* ### objnam.c ### */ #define doname(x) doname_(x) #define xname(x) xname_(x) /* ### options.c ### */ #define doset() doset_() #define dotogglepickup() dotogglepickup_() /* ### pager.c ### */ #define dohelp() dohelp_() #define dohistory() dohistory_() #ifdef UNIX #define intruph() intruph_() #endif /* UNIX */ #define dowhatdoes() dowhatdoes_() #define dowhatis() dowhatis_() #define doquickwhatis() doquickwhatis_() /* ### pcsys.c ### */ #ifdef SHELL #define dosh() dosh_() #endif /* SHELL */ /* ### pickup.c ### */ #define ck_bag(x) ck_bag_(x) #define doloot() doloot_() #define in_container(x) in_container_(x) #define out_container(x) out_container_(x) /* ### potion.c ### */ #define dodrink() dodrink_() #define dodip() dodip_() /* ### pray.c ### */ #define doturn() doturn_() #define dopray() dopray_() #define prayer_done() prayer_done_() #define dosacrifice() dosacrifice_() /* ### read.c ### */ #define doread() doread_() #define set_lit(x, y, val) set_lit_(x, y, val) /* ### rip.c ### */ #define genl_outrip(tmpwin, how) genl_outrip_(tmpwin, how) /* ### save.c ### */ #define dosave() dosave_() #if defined(UNIX) || defined(VMS) || defined(__EMX__) #define hangup(sig) hangup_(sig) #endif /* ### search.c ### */ #define doidtrap() doidtrap_() #define dosearch() dosearch_() #define findone(zx, zy, num) findone_(zx, zy, num) #define openone(zx, zy, num) openone_(zx, zy, num) /* ### shk.c ### */ #define dopay() dopay_() /* ### sit.c ### */ #define dosit() dosit_() /* ### sounds.c ### */ #define dotalk() dotalk_() /* ### spell.c ### */ #define learn() learn_() #define docast() docast_() #define dovspell() dovspell_() /* ### steal.c ### */ #define stealarm() stealarm_() /* ### trap.c ### */ #define dotele() dotele_() #define dountrap() dountrap_() #define float_down() float_down_() /* ### version.c ### */ #define doversion() doversion_() #define doextversion() doextversion_() /* ### wield.c ### */ #define dowield() dowield_() /* ### zap.c ### */ #define bhitm(x, y) bhitm_(x, y) #define bhito(x, y) bhito_(x, y) #define dozap() dozap_() /* ### getline.c ### */ #define tty_getlin(x, y) tty_getlin_(x, y) #define tty_get_ext_cmd() tty_get_ext_cmd_() /* ### termcap.c ### */ #define tty_nhbell() tty_nhbell_() #define tty_number_pad(x) tty_number_pad_(x) #define tty_delay_output() tty_delay_output_() #define tty_start_screen() tty_start_screen_() #define tty_end_screen() tty_end_screen_() /* ### topl.c ### */ #define tty_doprev_message() tty_doprev_message_() #define tty_yn_function(x, y, z) tty_yn_function_(x, y, z) /* ### wintty.c ### */ #define tty_init_nhwindows(x, y) tty_init_nhwindows_(x, y) #define tty_player_selection() tty_player_selection_() #define tty_askname() tty_askname_() #define tty_get_nh_event() tty_get_nh_event_() #define tty_exit_nhwindows(x) tty_exit_nhwindows_(x) #define tty_suspend_nhwindows(x) tty_suspend_nhwindows_(x) #define tty_resume_nhwindows() tty_resume_nhwindows_() #define tty_create_nhwindow(x) tty_create_nhwindow_(x) #define tty_clear_nhwindow(x) tty_clear_nhwindow_(x) #define tty_display_nhwindow(x, y) tty_display_nhwindow_(x, y) #define tty_destroy_nhwindow(x) tty_destroy_nhwindow_(x) #define tty_curs(x, y, z) tty_curs_(x, y, z) #define tty_putstr(x, y, z) tty_putstr_(x, y, z) #define tty_display_file(x, y) tty_display_file_(x, y) #define tty_start_menu(x) tty_start_menu_(x) #define tty_add_menu(a, b, c, d, e, f, g, h) \ tty_add_menu_(a, b, c, d, e, f, g, h) #define tty_end_menu(a, b) tty_end_menu_(a, b) #define tty_select_menu(a, b, c) tty_select_menu_(a, b, c) #define tty_update_inventory() tty_update_inventory_() #define tty_mark_synch() tty_mark_synch_() #define tty_wait_synch() tty_wait_synch_() #ifdef CLIPPING #define tty_cliparound(x, y) tty_cliparound_(x, y) #endif #ifdef POSITIONBAR #define tty_update_positionbar(x) tty_update_positionbar_(x) #endif #define tty_print_glyph(a, b, c, d, e) tty_print_glyph_(a, b, c, d, e) #define tty_raw_print(x) tty_raw_print_(x) #define tty_raw_print_bold(x) tty_raw_print_bold_(x) #define tty_nhgetch() tty_nhgetch_() #define tty_nh_poskey(x, y, z) tty_nh_poskey_(x, y, z) #endif /* USE_TRAMPOLI */ #endif /* TRAMPOLI_H */ nethack-3.6.0/include/trap.h0000664000076400007660000000501212536476415014712 0ustar paxedpaxed/* NetHack 3.6 trap.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* note for 3.1.0 and later: no longer manipulated by 'makedefs' */ #ifndef TRAP_H #define TRAP_H union vlaunchinfo { short v_launch_otyp; /* type of object to be triggered */ coord v_launch2; /* secondary launch point (for boulders) */ uchar v_conjoined; /* conjoined pit locations */ short v_tnote; /* boards: 12 notes */ }; struct trap { struct trap *ntrap; xchar tx, ty; d_level dst; /* destination for portals */ coord launch; Bitfield(ttyp, 5); Bitfield(tseen, 1); Bitfield(once, 1); Bitfield(madeby_u, 1); /* So monsters may take offence when you trap them. Recognizing who made the trap isn't completely unreasonable, everybody has their own style. This flag is also needed when you untrap a monster. It would be too easy to make a monster peaceful if you could set a trap for it and then untrap it. */ union vlaunchinfo vl; #define launch_otyp vl.v_launch_otyp #define launch2 vl.v_launch2 #define conjoined vl.v_conjoined #define tnote vl.v_tnote }; extern struct trap *ftrap; #define newtrap() (struct trap *) alloc(sizeof(struct trap)) #define dealloc_trap(trap) free((genericptr_t)(trap)) /* reasons for statue animation */ #define ANIMATE_NORMAL 0 #define ANIMATE_SHATTER 1 #define ANIMATE_SPELL 2 /* reasons for animate_statue's failure */ #define AS_OK 0 /* didn't fail */ #define AS_NO_MON 1 /* makemon failed */ #define AS_MON_IS_UNIQUE 2 /* statue monster is unique */ /* Note: if adding/removing a trap, adjust trap_engravings[] in mklev.c */ /* unconditional traps */ #define NO_TRAP 0 #define ARROW_TRAP 1 #define DART_TRAP 2 #define ROCKTRAP 3 #define SQKY_BOARD 4 #define BEAR_TRAP 5 #define LANDMINE 6 #define ROLLING_BOULDER_TRAP 7 #define SLP_GAS_TRAP 8 #define RUST_TRAP 9 #define FIRE_TRAP 10 #define PIT 11 #define SPIKED_PIT 12 #define HOLE 13 #define TRAPDOOR 14 #define TELEP_TRAP 15 #define LEVEL_TELEP 16 #define MAGIC_PORTAL 17 #define WEB 18 #define STATUE_TRAP 19 #define MAGIC_TRAP 20 #define ANTI_MAGIC 21 #define POLY_TRAP 22 #define VIBRATING_SQUARE 23 #define TRAPNUM 24 #endif /* TRAP_H */ nethack-3.6.0/include/unixconf.h0000664000076400007660000003053212622603541015566 0ustar paxedpaxed/* NetHack 3.6 unixconf.h $NHDT-Date: 1447755973 2015/11/17 10:26:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef UNIX #ifndef UNIXCONF_H #define UNIXCONF_H /* * Some include files are in a different place under SYSV * BSD SYSV * * * * Some routines are called differently * index strchr * rindex strrchr * */ /* define exactly one of the following four choices */ /* #define BSD 1 */ /* define for 4.n/Free/Open/Net BSD */ /* also for relatives like SunOS 4.x, DG/UX, and */ /* older versions of Linux */ /* #define ULTRIX */ /* define for Ultrix v3.0 or higher (but not lower) */ /* Use BSD for < v3.0 */ /* "ULTRIX" not to be confused with "ultrix" */ #define SYSV /* define for System V, Solaris 2.x, newer versions */ /* of Linux */ /* #define HPUX */ /* Hewlett-Packard's Unix, version 6.5 or higher */ /* use SYSV for < v6.5 */ /* define any of the following that are appropriate */ #define SVR4 /* use in addition to SYSV for System V Release 4 */ /* including Solaris 2+ */ #define NETWORK /* if running on a networked system */ /* e.g. Suns sharing a playground through NFS */ /* #define SUNOS4 */ /* SunOS 4.x */ /* #define LINUX */ /* Another Unix clone */ /* #define CYGWIN32 */ /* Unix on Win32 -- use with case sensitive defines */ /* #define GENIX */ /* Yet Another Unix Clone */ /* #define HISX */ /* Bull Unix for XPS Machines */ /* #define BOS */ /* Bull Open Software - Unix for DPX/2 Machines */ /* #define UNIXPC */ /* use in addition to SYSV for AT&T 7300/3B1 */ /* #define AIX_31 */ /* In AIX 3.1 (IBM RS/6000) use BSD ioctl's to gain * job control (note that AIX is SYSV otherwise) * Also define this for AIX 3.2 */ #define TERMINFO /* uses terminfo rather than termcap */ /* Should be defined for most SYSV, SVR4 (including * Solaris 2+), HPUX, and Linux systems. In * particular, it should NOT be defined for the UNIXPC * unless you remove the use of the shared library in * the Makefile */ #define TEXTCOLOR /* Use System V r3.2 terminfo color support * and/or ANSI color support on termcap systems * and/or X11 color */ #define POSIX_JOB_CONTROL /* use System V / Solaris 2.x / POSIX job control * (e.g., VSUSP) */ #define POSIX_TYPES /* use POSIX types for system calls and termios */ /* Define for many recent OS releases, including * those with specific defines (since types are * changing toward the standard from earlier chaos). * For example, platforms using the GNU libraries, * Linux, Solaris 2.x */ /* #define OPENWINBUG */ /* avoid a problem using OpenWindows 3.0 for X11 on SunOS 4.1.x, x>= 2. Do not define for other X11 implementations. */ /* #define PYRAMID_BUG */ /* avoid a bug on the Pyramid */ /* #define BSD_43_BUG */ /* for real 4.3BSD cc's without schain botch fix */ /* #define MICROPORT_BUG */ /* problems with large arrays in structs */ /* #define MICROPORT_286_BUG */ /* changes needed in termcap.c to get it to run with Microport Sys V/AT version 2.4. By Jay Maynard */ /* #define AIXPS_2BUG */ /* avoid a problem with little_to_big() optimization */ /* #define RANDOM */ /* if neither random/srandom nor lrand48/srand48 is available from your system */ /* see sys/unix/snd86unx.shr for more information on these */ /* #define UNIX386MUSIC */ /* play real music through speaker on systems with music driver installed */ /* #define VPIX_MUSIC */ /* play real music through speaker on systems with built-in VPIX support */ /* * The next two defines are intended mainly for the Andrew File System, * which does not allow hard links. If NO_FILE_LINKS is defined, lock files * will be created in LOCKDIR using open() instead of in the playground using * link(). * Ralf Brown, 7/26/89 (from v2.3 hack of 10/10/88) */ /* #define NO_FILE_LINKS */ /* if no hard links */ /* #define LOCKDIR "/usr/games/lib/nethackdir" */ /* where to put locks */ /* * If you want the static parts of your playground on a read-only file * system, define VAR_PLAYGROUND to be where the variable parts are kept. */ /* #define VAR_PLAYGROUND "/var/lib/games/nethack" */ /* * Define DEF_PAGER as your default pager, e.g. "/bin/cat" or "/usr/ucb/more" * If defined, it can be overridden by the environment variable PAGER. * Hack will use its internal pager if DEF_PAGER is not defined. * (This might be preferable for security reasons.) */ /* #define DEF_PAGER ".../mydir/mypager" */ /* * Define PORT_HELP to be the name of the port-specfic help file. * This file is found in HACKDIR. * Normally, you shouldn't need to change this. * There is currently no port-specific help for Unix systems. */ /* #define PORT_HELP "Unixhelp" */ #ifdef TTY_GRAPHICS /* * To enable the `timed_delay' option for using a timer rather than extra * screen output when pausing for display effect. Requires that `msleep' * function be available (with time argument specified in milliseconds). * Various output devices can produce wildly varying delays when the * "extra output" method is used, but not all systems provide access to * a fine-grained timer. */ /* #define TIMED_DELAY */ /* usleep() */ #endif /* * If you define MAIL, then the player will be notified of new mail * when it arrives. If you also define DEF_MAILREADER then this will * be the default mail reader, and can be overridden by the environment * variable MAILREADER; otherwise an internal pager will be used. * A stat system call is done on the mailbox every MAILCKFREQ moves. */ #if !defined(NOMAIL) #define MAIL /* Deliver mail during the game */ #endif /* The Andrew Message System does mail a little differently from normal * UNIX. Mail is deposited in the user's own directory in ~/Mailbox * (another directory). MAILBOX is the element that will be added on to * the user's home directory path to generate the Mailbox path - just in * case other Andrew sites do it differently from CMU. * dan lovinger * dl2n+@andrew.cmu.edu (dec 19 1989) */ /* #define AMS */ /* use Andrew message system for mail */ /* NO_MAILREADER is for kerberos authenticating filesystems where it is * essentially impossible to securely exec child processes, like mail * readers, when the game is running under a special token. * dan */ /* #define NO_MAILREADER */ /* have mail daemon just tell player of mail */ #ifdef MAIL #if defined(BSD) || defined(ULTRIX) #ifdef AMS #define AMS_MAILBOX "/Mailbox" #else #if defined(__FreeBSD__) || defined(__OpenBSD__) #define DEF_MAILREADER "/usr/bin/mail" #else #define DEF_MAILREADER "/usr/ucb/Mail" #endif #endif #else #if (defined(SYSV) || defined(DGUX) || defined(HPUX)) && !defined(LINUX) #if defined(M_XENIX) #define DEF_MAILREADER "/usr/bin/mail" #else #ifdef __sgi #define DEF_MAILREADER "/usr/sbin/Mail" #else #define DEF_MAILREADER "/usr/bin/mailx" #endif #endif #else #define DEF_MAILREADER "/bin/mail" #endif #endif #define MAILCKFREQ 50 #endif /* MAIL */ /* * Some terminals or terminal emulators send two character sequence "ESC c" * when Alt+c is pressed. The altmeta run-time option allows the user to * request that "ESC c" be treated as M-c. */ #define ALTMETA /* support altmeta run-time option */ #ifdef COMPRESS /* Some implementations of compress need a 'quiet' option. * If you've got one of these versions, put -q here. * You can also include any other strange options your compress needs. * If you have a normal compress, just leave it commented out. */ /* #define COMPRESS_OPTIONS "-q" */ #endif #define FCMASK 0660 /* file creation mask */ /* fcntl(2) is a POSIX-portable call for manipulating file descriptors. * Comment out the USE_FCNTL if for some reason you have a strange * OS/filesystem combination for which fcntl(2) does not work. */ #ifdef POSIX_TYPES #define USE_FCNTL #endif /* * The remainder of the file should not need to be changed. */ #ifdef _AUX_SOURCE #ifdef AUX /* gcc ? */ #define _SYSV_SOURCE #define _BSD_SOURCE #else #define AUX #endif #endif /* _AUX_SOURCE */ #if defined(LINUX) || defined(bsdi) #ifndef POSIX_TYPES #define POSIX_TYPES #endif #ifndef POSIX_JOB_CONTROL #define POSIX_JOB_CONTROL #endif #endif /* * BSD/ULTRIX systems are normally the only ones that can suspend processes. * Suspending NetHack processes cleanly should be easy to add to other systems * that have SIGTSTP in the Berkeley sense. Currently the only such systems * known to work are HPUX and AIX 3.1; other systems will probably require * tweaks to unixtty.c and ioctl.c. * * POSIX defines a slightly different type of job control, which should be * equivalent for NetHack's purposes. POSIX_JOB_CONTROL should work on * various recent SYSV versions (with possibly tweaks to unixtty.c again). */ #ifndef POSIX_JOB_CONTROL #if defined(BSD) || defined(ULTRIX) || defined(HPUX) || defined(AIX_31) #define BSD_JOB_CONTROL #else #if defined(SVR4) #define POSIX_JOB_CONTROL #endif #endif #endif #if defined(BSD_JOB_CONTROL) || defined(POSIX_JOB_CONTROL) || defined(AUX) #define SUSPEND /* let ^Z suspend the game */ #endif /* * Define SAFERHANGUP to delay hangup processing until the main command * loop. 'safer' because it avoids certain cheats and also avoids losing * objects being thrown when the hangup occurs. All unix windowports * support SAFERHANGUP (couldn't define it here otherwise). */ #define SAFERHANGUP #if defined(BSD) || defined(ULTRIX) #include #else #include #endif #define HLOCK "perm" /* an empty file used for locking purposes */ #define tgetch getchar #ifndef NOSHELL #define SHELL /* do not delete the '!' command */ #endif #include "system.h" #if defined(POSIX_TYPES) || defined(__GNUC__) #include #include #endif #if defined(POSIX_TYPES) || defined(__GNUC__) || defined(BSD) \ || defined(ULTRIX) #include #endif #if defined(BSD) || defined(ULTRIX) #if !defined(DGUX) && !defined(SUNOS4) #define memcpy(d, s, n) bcopy(s, d, n) #define memcmp(s1, s2, n) bcmp(s2, s1, n) #endif #ifdef SUNOS4 #include #endif #else /* therefore SYSV */ #ifndef index /* some systems seem to do this for you */ #define index strchr #endif #ifndef rindex #define rindex strrchr #endif #endif /* Use the high quality random number routines. */ #if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) \ || defined(RANDOM) || defined(__APPLE__) #define Rand() random() #else #define Rand() lrand48() #endif #ifdef TIMED_DELAY #if defined(SUNOS4) || defined(LINUX) || (defined(BSD) && !defined(ULTRIX)) #define msleep(k) usleep((k) *1000) #endif #ifdef ULTRIX #define msleep(k) napms(k) #endif #endif #ifdef hc /* older versions of the MetaWare High-C compiler define this */ #ifdef __HC__ #undef __HC__ #endif #define __HC__ hc #undef hc #endif #if defined(GNOME_GRAPHICS) #if defined(LINUX) #include #if defined(__NR_getresuid) && defined(__NR_getresgid) /* ie., >= v2.1.44 */ #define GETRES_SUPPORT #endif #else #if defined(BSD) || defined(SVR4) /* * [ALI] We assume that SVR4 means we can safely include syscall.h * (although it's really a BSDism). This is certainly true for Solaris 2.5, * Solaris 7, Solaris 8 and Compaq Tru64 5.1 * Later BSD systems will have the getresid system calls. */ #include #if (defined(SYS_getuid) || defined(SYS_getresuid)) \ && (defined(SYS_getgid) || defined(SYS_getresgid)) #define GETRES_SUPPORT #endif #endif /* BSD || SVR4 */ #endif /* LINUX */ #endif /* GNOME_GRAPHICS */ #endif /* UNIXCONF_H */ #endif /* UNIX */ nethack-3.6.0/include/vision.h0000664000076400007660000000472612536476415015266 0ustar paxedpaxed/* NetHack 3.6 vision.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef VISION_H #define VISION_H #if 0 /* (moved to decl.h) */ extern boolean vision_full_recalc; /* TRUE if need vision recalc */ extern char **viz_array; /* could see/in sight row pointers */ extern char *viz_rmin; /* min could see indices */ extern char *viz_rmax; /* max could see indices */ #endif #define COULD_SEE 0x1 /* location could be seen, if it were lit */ #define IN_SIGHT 0x2 /* location can be seen */ #define TEMP_LIT 0x4 /* location is temporarily lit */ /* * Light source sources */ #define LS_OBJECT 0 #define LS_MONSTER 1 /* * cansee() - Returns true if the hero can see the location. * * couldsee() - Returns true if the hero has a clear line of sight to * the location. */ #define cansee(x, y) (viz_array[y][x] & IN_SIGHT) #define couldsee(x, y) (viz_array[y][x] & COULD_SEE) #define templit(x, y) (viz_array[y][x] & TEMP_LIT) /* * The following assume the monster is not blind. * * m_cansee() - Returns true if the monster can see the given location. * * m_canseeu() - Returns true if the monster could see the hero. Assumes * that if the hero has a clear line of sight to the monster's * location and the hero is visible, then monster can see the * hero. */ #define m_cansee(mtmp, x2, y2) clear_path((mtmp)->mx, (mtmp)->my, (x2), (y2)) #define m_canseeu(m) \ ((!Invis || perceives((m)->data)) \ && !(Underwater || u.uburied || (m)->mburied) \ ? couldsee((m)->mx, (m)->my) \ : 0) /* * Circle information */ #define MAX_RADIUS 15 /* this is in points from the source */ /* Use this macro to get a list of distances of the edges (see vision.c). */ #define circle_ptr(z) (&circle_data[(int) circle_start[z]]) /* howmonseen() bitmask values */ #define MONSEEN_NORMAL 0x0001 /* normal vision */ #define MONSEEN_SEEINVIS 0x0002 /* seeing invisible */ #define MONSEEN_INFRAVIS 0x0004 /* via infravision */ #define MONSEEN_TELEPAT 0x0008 /* via telepathy */ #define MONSEEN_XRAYVIS 0x0010 /* via Xray vision */ #define MONSEEN_DETECT 0x0020 /* via extended monster detection */ #define MONSEEN_WARNMON 0x0040 /* via type-specific warning */ #endif /* VISION_H */ nethack-3.6.0/include/vmsconf.h0000664000076400007660000002301612536476415015423 0ustar paxedpaxed/* NetHack 3.6 vmsconf.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef VMS #ifndef VMSCONF_H #define VMSCONF_H /* * Edit these to choose values appropriate for your site. * WIZARD is the username allowed to use the debug option of nethack; no harm * is done by leaving it as a username that doesn't exist at your site. * HACKDIR can be overridden at run-time with the logical name HACKDIR, as in * $ define hackdir disk$users:[games.nethack] * Trailing NULs are present in the default values in order to make some * extra room for patching longer values into an existing executable. */ #define Local_WIZARD "NHWIZARD\0\0\0\0" #define Local_HACKDIR "DISK$USERS:[GAMES.NETHACK.3_5_X.PLAY]\0\0\0\0\0\0\0\0" /* * This section cleans up the stuff done in config.h so that it * shouldn't need to be modified. It's conservative so that if * config.h is actually edited, the changes won't impact us. */ #ifdef UNIX #undef UNIX #endif #ifdef HACKDIR #undef HACKDIR #endif #ifdef WIZARD_NAME #undef WIZARD_NAME #endif #define HACKDIR Local_HACKDIR #define WIZARD_NAME Local_WIZARD #ifndef SYSCF #define SYSCF #endif /* filenames require punctuation to avoid redirection via logical names */ #undef RECORD #define RECORD "record;1" /* scoreboard file (retains high scores) */ #undef LOGFILE #define LOGFILE "logfile;0" /* optional file (records all games) */ #undef SYSCF_FILE #define SYSCF_FILE "sysconf;0" #define HLOCK "perm;1" /* an empty file used for locking purposes */ /* want compression--for level & save files--performed within NetHack itself */ #ifdef COMPRESS #undef COMPRESS #endif #ifndef INTERNAL_COMP #define INTERNAL_COMP #endif /* * If nethack.exe will be installed with privilege so that the playground * won't need to be left unprotected, define SECURE to suppress a couple * of file protection fixups (protection of bones files and ownership of * save files). */ /* #define SECURE */ /* * If you use SECURE you'll need to link /noTraceback, in which case * there's no point trying to get extra PANICTRACE info and this might * as well be commented out. When enabled, the sysconf file controls * how to handle it (note that we're hijacking the Unix GDB setting): PANICTRACE_GDB=0 #behave as if PANICTRACE was disabled PANICTRACE_GDB=1 #at conclusion of panic, show a call traceback and exit PANICTRACE_GDB=2 #at conclusion of panic, show a call traceback and then * # remain in the debugger for more interactive debugging * # (not as useful as it might sound since we're normally * # linked /noDebug so there's no symbol table accessible) */ #define PANICTRACE /* * Put the readonly data files into a single container rather than into * separate files in the playground directory. */ #define DLB /* use data librarian code */ /* * Provide menu of saved games to choose from at start. * [Player needs to use ``nethack "-ugames"'' for this to work.] */ #define SELECTSAVED /* * You may define TEXTCOLOR if your system has any terminals that recognize * ANSI color sequences of the form ``[#;#m'', where the first # is * a number between 40 and 47 represented background color, and the second * # is a number between 30 and 37 representing the foreground color. * GIGI terminals and DECterm windows on color VAXstations support these * color escape sequences, as do some 3rd party terminals and many micro * computers. */ /* #define TEXTCOLOR */ /* * If you define USE_QIO_INPUT, then you'll get raw characters from the * keyboard, not unlike those of the unix version of Nethack. This will * allow you to use the Escape key in normal gameplay, and the appropriate * control characters in Wizard mode. It will work most like the unix * version. * It will also avoid "" being displayed when ^Y is pressed. * * Otherwise, the VMS SMG calls will be used. These calls block use of * the escape key, as well as certain control keys, so gameplay is not * the same, although the differences are fairly negligible. You must * then use a VTxxx function key or two s to give an ESC response. */ #define USE_QIO_INPUT /* use SYS$QIOW instead of SMG$READ_KEYSTROKE */ /* * Allow the user to decide whether to pause via timer or excess screen * output for various display effects like explosions and moving objects. */ #define TIMED_DELAY /* enable the `timed_delay' run-time option */ /* * If you define MAIL, then NetHack will capture incoming broadcast * messages such as "New mail from so-and-so" and "Print job completed," * and then deliver them to the player. For mail and phone broadcasts * a scroll of mail will be created, which when read will cause NetHack * to prompt the player for a command to spawn in order to respond. The * latter capability will not be available if SHELL is disabled below. * If you undefine MAIL, broadcasts will go straight to the terminal, * resulting in disruption of the screen display; use to redraw. */ #define MAIL /* enable broadcast trapping */ /* * SHELL enables the player to 'escape' into a spawned subprocess via * the '!' command. Logout or attach back to the parent to resume play. * If the player attaches back to NetHack, then a subsequent escape will * re-attach to the existing subprocess. Any such subprocess left over * at game exit will be deleted by an exit handler. * SUSPEND enables someone running NetHack in a subprocess to reconnect * to the parent process with the command; this is not very * close to Unix job control, but it's better than nothing. */ #define SHELL /* do not delete the '!' command */ #define SUSPEND /* don't delete the ^Z command, such as it is */ /* * Some terminals or terminal emulators send two character sequence "ESC c" * when Alt+c is pressed. The altmeta run-time option allows the user to * request that "ESC c" be treated as M-c, which means that if nethack sees * ESC when it is waiting for a command, it will wait for another character * (even if user intended that ESC to be standalone to cancel a count prefix). */ #define ALTMETA /* support altmeta run-time option */ #define RANDOM /* use sys/share/random.c instead of vaxcrtl rand */ #define FCMASK 0660 /* file creation mask */ /* * The remainder of the file should not need to be changed. */ /* data librarian defs */ #ifdef DLB #define DLBFILE "nh-data.dlb" /* * Since we can do without case insensitive filename comparison, * avoid enabling it because that requires compiling and linking * src/hacklib into util/dlb_main. */ /* # define FILENAME_CMP strcmpi */ /* case insensitive */ #endif #if defined(VAXC) && !defined(ANCIENT_VAXC) #ifdef volatile #undef volatile #endif #ifdef const #undef const #endif #endif #ifdef __DECC #define STRICT_REF_DEF /* used in lev_main.c */ #endif #ifdef STRICT_REF_DEF #define DEFINE_OSPEED #endif #ifndef alloca /* bison generated foo_yacc.c might try to use alloca() */ #ifdef __GNUC__ #define alloca __builtin_alloca #else #define ALLOCA_HACK /* used in util/panic.c */ #endif #endif #ifdef _DECC_V4_SOURCE /* excludes some necessary typedefs when _DECC_V4_SOURCE is defined */ #include #ifndef __PID_T #define __PID_T typedef __pid_t pid_t; #endif #ifndef __UID_T #define __UID_T typedef __uid_t uid_t; #endif #ifndef __GID_T #define __GID_T typedef __gid_t gid_t; #endif #ifndef __MODE_T #define __MODE_T typedef __mode_t mode_t; #endif #endif /* _DECC_V4_SOURCE */ #include #if 0 /* is missing for old gcc versions; skip it to save time */ #include #else /* values needed from missing include file */ #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #define O_CREAT 0x200 #define O_TRUNC 0x400 #endif #define tgetch vms_getchar #include "system.h" #define index strchr #define rindex strrchr /* Use the high quality random number routines. */ #if defined(RANDOM) #define Rand() random() /* VMS V7 adds these entry points to DECC$SHR; stick with the nethack-supplied code to avoid having to deal with version-specific conditionalized builds */ #define random nh_random #define srandom nh_srandom #define initstate nh_initstate #define setstate nh_setstate #else #define Rand() rand() #endif #ifndef __GNUC__ #ifndef bcopy #define bcopy(s, d, n) memcpy((d), (s), (n)) /* vaxcrtl */ #endif #endif #define abort() vms_abort() /* vmsmisc.c */ #define creat(f, m) vms_creat(f, m) /* vmsfiles.c */ #define exit(sts) vms_exit(sts) /* vmsmisc.c */ #define getuid() vms_getuid() /* vmsunix.c */ #define link(f1, f2) vms_link(f1, f2) /* vmsfiles.c */ #define open(f, k, m) vms_open(f, k, m) /* vmsfiles.c */ #define fopen(f, m) vms_fopen(f, m) /* vmsfiles.c */ /* #define unlink(f0) vms_unlink(f0) /* vmsfiles.c */ #ifdef VERYOLD_VMS #define unlink(f0) delete (f0) /* vaxcrtl */ #else #define unlink(f0) remove(f0) /* vaxcrtl, decc$shr */ #endif #define C$$TRANSLATE(n) c__translate(n) /* vmsfiles.c */ /* VMS global names are case insensitive... */ #define An vms_an #define The vms_the #define Shk_Your vms_shk_your /* avoid global symbol in Alpha/VMS V1.5 STARLET library (link trouble) */ #define ospeed vms_ospeed /* used in several files which don't #include "extern.h" */ extern void FDECL(vms_exit, (int)); extern int FDECL(vms_open, (const char *, int, unsigned)); extern FILE *FDECL(vms_fopen, (const char *, const char *)); char *FDECL(vms_basename, (const char *)); /* vmsfiles.c */ #endif /* VMSCONF_H */ #endif /* VMS */ nethack-3.6.0/include/wceconf.h0000664000076400007660000002312412610522241015352 0ustar paxedpaxed/* NetHack 3.6 wceconf.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WCECONF_H #define WCECONF_H #pragma warning(disable : 4142) /* benign redefinition of type */ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include /* Detect the target device */ #if defined(WIN32_PLATFORM_PSPC) #if _WIN32_WCE >= 300 #define WIN_CE_POCKETPC #else #define WIN_CE_PS2xx #endif #elif defined(WIN32_PLATFORM_HPCPRO) #define WIN_CE_HPCPRO #elif defined(WIN32_PLATFORM_WFSP) #define WIN_CE_SMARTPHONE #else #error "Unsupported Windows CE platform" #endif /* #define SHELL /* nt use of pcsys routines caused a hang */ #define RANDOM /* have Berkeley random(3) */ #define TEXTCOLOR /* Color text */ #define EXEPATH /* Allow .exe location to be used as HACKDIR */ #define TRADITIONAL_GLYPHMAP /* Store glyph mappings at level change time */ #define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */ /* without first receiving confirmation. */ #define SELF_RECOVER /* Allow the game itself to recover from an aborted \ game */ #define NOTSTDC /* no strerror() */ #define USER_SOUNDS /* * ----------------------------------------------------------------- * The remaining code shouldn't need modification. * ----------------------------------------------------------------- */ /* #define SHORT_FILENAMES /* All NT filesystems support long names now */ #ifdef MICRO #undef MICRO /* never define this! */ #endif #define NOCWD_ASSUMPTIONS /* Always define this. There are assumptions that \ it is defined for WIN32. \ Allow paths to be specified for HACKDIR, \ LEVELDIR, SAVEDIR, BONESDIR, DATADIR, \ SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ #define NO_TERMS #define ASCIIGRAPH #ifdef OPTIONS_USED #undef OPTIONS_USED #endif #ifdef MSWIN_GRAPHICS #define OPTIONS_USED "guioptions" #else #define OPTIONS_USED "ttyoptions" #endif #define OPTIONS_FILE OPTIONS_USED #define PORT_HELP "porthelp" #define SAFERHANGUP /* Define SAFERHANGUP to delay hangup processing \ * until the main command loop. 'safer' because it \ * avoids certain cheats and also avoids losing \ * objects being thrown when the hangup occurs. \ */ #if defined(WIN_CE_POCKETPC) #define PORT_CE_PLATFORM "Pocket PC" #elif defined(WIN_CE_PS2xx) #define PORT_CE_PLATFORM "Palm-size PC 2.11" #elif defined(WIN_CE_HPCPRO) #define PORT_CE_PLATFORM "H/PC Pro 2.11" #elif defined(WIN_CE_SMARTPHONE) #define PORT_CE_PLATFORM "Smartphone 2002" #endif #if defined(ARM) #define PORT_CE_CPU "ARM" #elif defined(PPC) #define PORT_CE_CPU "PPC" #elif defined(ALPHA) #define PORT_CE_CPU "ALPHA" #elif defined(SH3) #define PORT_CE_CPU "SH3" #elif defined(SH4) #define PORT_CE_CPU "SH4" #elif defined(MIPS) #define PORT_CE_CPU "MIPS" #elif defined(X86) || defined(_X86_) #define PORT_CE_CPU "X86" #else #error Only ARM, PPC, ALPHA, SH3, SH4, MIPS and X86 supported #endif #define RUNTIME_PORT_ID /* trigger run-time port identification since \ Makedefs is bootstrapped on a cross-platform. */ #include /* Provides prototypes of strncmpi(), etc. */ #ifdef STRNCMPI #define strncmpi(a, b, c) _strnicmp(a, b, c) #endif #ifdef STRCMPI #define strcmpi(a, b) _stricmp(a, b) #define stricmp(a, b) _stricmp(a, b) #endif #include #define PATHLEN BUFSZ /* maximum pathlength */ #define FILENAME BUFSZ /* maximum filename length (conservative) */ #if defined(_MAX_PATH) && defined(_MAX_FNAME) #if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ) #undef PATHLEN #undef FILENAME #define PATHLEN _MAX_PATH #define FILENAME _MAX_FNAME #endif #endif #define NO_SIGNAL #define index strchr #define rindex strrchr #define USE_STDARG #ifdef RANDOM /* Use the high quality random number routines. */ #define Rand() random() #else #define Rand() rand() #endif #define FCMASK 0660 /* file creation mask */ #define regularize nt_regularize #define HLOCK "NHPERM" #ifndef M #define M(c) ((char) (0x80 | (c))) /* #define M(c) ((c) - 128) */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif #if defined(DLB) #define FILENAME_CMP _stricmp /* case insensitive */ #endif #if 0 extern char levels[], bones[], permbones[], #endif /* 0 */ /* this was part of the MICRO stuff in the past */ extern const char *alllevels, *allbones; extern char hackdir[]; #define ABORT C('a') #define getuid() 1 #define getlogin() ((char *) 0) extern void NDECL(win32_abort); #ifdef WIN32CON extern void FDECL(nttty_preference_update, (const char *)); extern void NDECL(toggle_mouse_support); #endif #ifndef alloca #define ALLOCA_HACK /* used in util/panic.c */ #endif #ifdef _MSC_VER #if 0 #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4305) /* init, conv from 'const int' to 'char' */ #endif #pragma warning(disable : 4761) /* integral size mismatch in arg; conv \ supp*/ #ifdef YYPREFIX #pragma warning(disable : 4102) /* unreferenced label */ #endif #endif /* UNICODE stuff */ #define NHSTR_BUFSIZE 255 #ifdef UNICODE #define NH_W2A(w, a, cb) \ (WideCharToMultiByte(CP_ACP, 0, (w), -1, (a), (cb), NULL, NULL), (a)) #define NH_A2W(a, w, cb) \ (MultiByteToWideChar(CP_ACP, 0, (a), -1, (w), (cb)), (w)) #else #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb))) #endif extern int FDECL(set_win32_option, (const char *, const char *)); /* * 3.4.3 addition - Stuff to help the user with some common, yet significant * errors * Let's make it NOP for now */ #define interject_assistance(_1, _2, _3, _4) #define interject(_1) /* Missing definitions */ extern int mswin_have_input(); #define kbhit mswin_have_input #define getenv(a) ((char *) NULL) /* __stdio.h__ */ #define perror(a) #define freopen(a, b, c) fopen(a, b) extern int isatty(int); /* __time.h___ */ #ifndef _TIME_T_DEFINED typedef __int64 time_t; /* time value */ #define _TIME_T_DEFINED /* avoid multiple def's of time_t */ #endif #ifndef _TM_DEFINED struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag - - NOT IMPLEMENTED */ }; #define _TM_DEFINED #endif extern struct tm *__cdecl localtime(const time_t *); extern time_t __cdecl time(time_t *); extern time_t __cdecl mktime(struct tm *tb); /* __stdio.h__ */ #ifndef BUFSIZ #define BUFSIZ 255 #endif #define rewind(stream) (void) fseek(stream, 0L, SEEK_SET) /* __io.h__ */ typedef long off_t; extern int __cdecl close(int); extern int __cdecl creat(const char *, int); extern int __cdecl eof(int); extern long __cdecl lseek(int, long, int); extern int __cdecl open(const char *, int, ...); extern int __cdecl read(int, void *, unsigned int); extern int __cdecl unlink(const char *); extern int __cdecl write(int, const void *, unsigned int); extern int __cdecl rename(const char *, const char *); extern int __cdecl access(const char *, int); #ifdef DeleteFile #undef DeleteFile #endif #define DeleteFile(a) unlink(a) int chdir(const char *dirname); extern char *getcwd(char *buffer, int maxlen); /* __stdlib.h__ */ #define abort() (void) TerminateProcess(GetCurrentProcess(), 0) #ifndef strdup #define strdup _strdup #endif /* sys/stat.h */ #define S_IWRITE GENERIC_WRITE #define S_IREAD GENERIC_READ /* CE 2.xx is missing even more stuff */ #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) #define ZeroMemory(p, s) memset((p), 0, (s)) extern int __cdecl isupper(int c); extern int __cdecl isdigit(int c); extern int __cdecl isspace(int c); extern int __cdecl isprint(int c); extern char *__cdecl _strdup(const char *s); extern char *__cdecl strrchr(const char *string, int c); extern int __cdecl _stricmp(const char *a, const char *b); extern FILE *__cdecl fopen(const char *filename, const char *mode); extern int __cdecl fscanf(FILE *f, const char *format, ...); extern int __cdecl fprintf(FILE *f, const char *format, ...); extern int __cdecl vfprintf(FILE *f, const char *format, va_list args); extern int __cdecl fgetc(FILE *f); extern char *__cdecl fgets(char *s, int size, FILE *f); extern int __cdecl printf(const char *format, ...); extern int __cdecl vprintf(const char *format, va_list args); extern int __cdecl puts(const char *s); extern FILE *__cdecl _getstdfilex(int desc); extern int __cdecl fclose(FILE *f); extern size_t __cdecl fread(void *p, size_t size, size_t count, FILE *f); extern size_t __cdecl fwrite(const void *p, size_t size, size_t count, FILE *f); extern int __cdecl fflush(FILE *f); extern int __cdecl feof(FILE *f); extern int __cdecl fseek(FILE *f, long offset, int from); extern long __cdecl ftell(FILE *f); #endif /* ARM - the processor; avoids conflict with ARM in hack.h */ #ifdef ARM #undef ARM #endif /* leave - Windows CE defines leave as part of exception handling (__leave) It conflicts with existing sources and since we don't use exceptions it is safe to undefine it */ #ifdef leave #undef leave #endif #endif /* WCECONF_H */ nethack-3.6.0/include/winGnome.h0000664000076400007660000000075112536476415015534 0ustar paxedpaxed/* NetHack 3.6 winGnome.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINGNOME_H #define WINGNOME_H #define E extern E struct window_procs Gnome_procs; #undef E #define NHW_WORN 6 extern winid WIN_WORN; #endif /* WINGNOME_H */ nethack-3.6.0/include/winX.h0000664000076400007660000004002512610522241014652 0ustar paxedpaxed/* NetHack 3.6 winX.h $NHDT-Date: 1433806583 2015/06/08 23:36:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Definitions for the X11 window-port. See doc/window.doc for details on * the window interface. */ #ifndef WINX_H #define WINX_H #ifndef E #define E extern #endif #if defined(BOS) || defined(NHSTDC) #define DIMENSION_P int #else #ifdef WIDENED_PROTOTYPES #define DIMENSION_P unsigned int #else #define DIMENSION_P Dimension #endif #endif /* * Generic text buffer. */ #define START_SIZE 512 /* starting text buffer size */ struct text_buffer { char *text; int text_size; int text_last; int num_lines; }; /* * Information specific to a map window. */ struct text_map_info_t { unsigned char text[ROWNO][COLNO]; /* Actual displayed screen. */ #ifdef TEXTCOLOR unsigned char colors[ROWNO][COLNO]; /* Color of each character. */ GC color_gcs[CLR_MAX], /* GC for each color */ inv_color_gcs[CLR_MAX]; /* GC for each inverse color */ #define copy_gc color_gcs[NO_COLOR] #define inv_copy_gc inv_color_gcs[NO_COLOR] #else GC copy_gc, /* Drawing GC */ inv_copy_gc; /* Inverse drawing GC */ #endif int square_width, /* Saved font information so */ square_height, /* we can calculate the correct */ square_ascent, /* placement of changes. */ square_lbearing; }; struct tile_glyph_info_t { unsigned short glyph; unsigned special; }; struct tile_map_info_t { struct tile_glyph_info_t glyphs[ROWNO][COLNO]; /* Saved glyph numbers. */ GC white_gc; GC black_gc; unsigned long image_width; /* dimensions of tile image */ unsigned long image_height; int square_width, /* Saved tile information so */ square_height, /* we can calculate the correct */ square_ascent, /* placement of changes. */ square_lbearing; }; struct map_info_t { Dimension viewport_width, /* Saved viewport size, so we can */ viewport_height; /* clip to cursor on a resize. */ unsigned char t_start[ROWNO], /* Starting column for new info. */ t_stop[ROWNO]; /* Ending column for new info. */ boolean is_tile; /* true if currently using tiles */ struct text_map_info_t text_map; struct tile_map_info_t tile_map; }; /* * Information specific to a message window. */ struct line_element { struct line_element *next; char *line; /* char buffer */ int buf_length; /* length of buffer */ int str_length; /* length of string in buffer */ }; struct mesg_info_t { XFontStruct *fs; /* Font for the window. */ int num_lines; /* line count */ struct line_element *head; /* head of circular line queue */ struct line_element *line_here; /* current drawn line position */ struct line_element *last_pause; /* point to the line after the prev */ /* bottom of screen */ struct line_element *last_pause_head; /* pointer to head of previous */ /* turn */ GC gc; /* GC for text drawing */ int char_width, /* Saved font information so we can */ char_height, /* calculate the correct placement */ char_ascent, /* of changes. */ char_lbearing; Dimension viewport_width, /* Saved viewport size, so we can adjust */ viewport_height; /* the slider on a resize. */ Boolean dirty; /* Lines have been added to the window. */ }; /* * Information specific to a "text" status window. */ struct status_info_t { struct text_buffer text; /* Just a text buffer. */ }; /* * Information specific to a menu window. First a structure for each * menu entry, then the structure for each menu window. */ typedef struct x11_mi { struct x11_mi *next; anything identifier; /* Opaque type to identify this selection */ long pick_count; /* specific selection count; -1 if none */ char *str; /* The text of the item. */ int attr; /* Attribute for the line. */ boolean selected; /* Been selected? */ char selector; /* Char used to select this entry. */ char gselector; /* Group selector. */ } x11_menu_item; struct menu { x11_menu_item *base; /* Starting pointer for item list. */ x11_menu_item *last; /* End pointer for item list. */ const char *query; /* Query string. */ const char *gacc; /* Group accelerators. */ int count; /* Number of strings. */ String *list_pointer; /* String list. */ Boolean *sensitive; /* Active list. */ char curr_selector; /* Next keyboard accelerator to assign, */ /* if 0, then we're out. */ }; struct menu_info_t { struct menu curr_menu; /* Menu being displayed. */ struct menu new_menu; /* New menu being built. */ XFontStruct *fs; /* Font for the window. */ long menu_count; /* number entered by user */ Dimension line_height; /* Total height of a line of text. */ Dimension internal_height; /* Internal height between widget & border */ Dimension internal_width; /* Internal width between widget & border */ short how; /* Menu mode PICK_NONE, PICK_ONE, PICK_ANY */ boolean valid_widgets; /* TRUE if widgets have been created. */ boolean is_menu; /* Has been confirmed to being a menu window. */ boolean is_active; /* TRUE when waiting for user input. */ boolean is_up; /* TRUE when window is popped-up. */ boolean cancelled; /* Menu has been explicitly cancelled. */ boolean counting; /* true when menu_count has a valid value */ }; /* * Information specific to a text window. */ struct text_info_t { struct text_buffer text; XFontStruct *fs; /* Font for the text window. */ int max_width; /* Width of widest line so far. */ int extra_width, /* Sum of left and right border widths. */ extra_height; /* Sum of top and bottom border widths. */ boolean blocked; /* */ boolean destroy_on_ack; /* Destroy this window when acknowledged. */ #ifdef GRAPHIC_TOMBSTONE boolean is_rip; /* This window needs a tombstone. */ #endif }; /* * Basic window structure. */ struct xwindow { int type; /* type of nethack window */ Widget popup; /* direct parent of widget w or viewport */ Widget w; /* the widget that does things */ Dimension pixel_width; /* window size, in pixels */ Dimension pixel_height; int prevx, cursx; /* Cursor position, only used by */ int prevy, cursy; /* map and "plain" status windows.*/ union { struct map_info_t *Map_info; /* map window info */ struct mesg_info_t *Mesg_info; /* message window info */ struct status_info_t *Status_info; /* status window info */ struct menu_info_t *Menu_info; /* menu window info */ struct text_info_t *Text_info; /* menu window info */ } Win_info; boolean keep_window; }; /* Defines to use for the window information union. */ #define map_information Win_info.Map_info #define mesg_information Win_info.Mesg_info #define status_information Win_info.Status_info #define menu_information Win_info.Menu_info #define text_information Win_info.Text_info #define MAX_WINDOWS 20 /* max number of open windows */ #define NHW_NONE 0 /* Unallocated window type. Must be */ /* different from any other NHW_* type. */ #define NO_CLICK 0 /* No click occurred on the map window. Must */ /* be different than CLICK_1 and CLICK_2. */ #define DEFAULT_MESSAGE_WIDTH 60 /* width in chars of the message window */ #define DISPLAY_FILE_SIZE 35 /* Max number of lines in the default */ /* file display window. */ #define MAX_KEY_STRING 64 /* String size for converting a keypress */ /* event into a character(s) */ #define DEFAULT_LINES_DISPLAYED 12 /* # of lines displayed message window */ #define MAX_HISTORY 60 /* max history saved on message window */ /* Window variables (winX.c). */ E struct xwindow window_list[MAX_WINDOWS]; E XtAppContext app_context; /* context of application */ E Widget toplevel; /* toplevel widget */ E Atom wm_delete_window; /* delete window protocol */ E boolean exit_x_event; /* exit condition for event loop */ #define EXIT_ON_KEY_PRESS 0 /* valid values for exit_x_event */ #define EXIT_ON_KEY_OR_BUTTON_PRESS 1 #define EXIT_ON_EXIT 2 #define EXIT_ON_SENT_EVENT 3 E int click_x, click_y, click_button, updated_inventory; typedef struct { Boolean slow; Boolean autofocus; Boolean message_line; Boolean double_tile_size; /* double tile size */ String tile_file; /* name of file to open for tiles */ String icon; /* name of desired icon */ int message_lines; /* number of lines to attempt to show */ String pet_mark_bitmap; /* X11 bitmap file used to mark pets */ Pixel pet_mark_color; /* color of pet mark */ String pilemark_bitmap; /* X11 bitmap file used to mark item piles */ Pixel pilemark_color; /* color of item pile mark */ #ifdef GRAPHIC_TOMBSTONE String tombstone; /* name of XPM file for tombstone */ int tombtext_x; /* x-coord of center of first tombstone text */ int tombtext_y; /* y-coord of center of first tombstone text */ int tombtext_dx; /* x-displacement between tombstone line */ int tombtext_dy; /* y-displacement between tombstone line */ #endif } AppResources; E AppResources appResources; E void (*input_func)(); extern struct window_procs X11_procs; /* Check for an invalid window id. */ #define check_winid(window) \ if ((window) < 0 || (window) >= MAX_WINDOWS) { \ panic("illegal windid [%d] in %s at line %d", window, __FILE__, \ __LINE__); \ } /* ### dialogs.c ### */ E Widget FDECL(CreateDialog, (Widget, String, XtCallbackProc, XtCallbackProc)); E void FDECL(SetDialogPrompt, (Widget, String)); E String FDECL(GetDialogResponse, (Widget)); E void FDECL(SetDialogResponse, (Widget, String)); E void FDECL(positionpopup, (Widget, BOOLEAN_P)); /* ### winX.c ### */ E struct xwindow *FDECL(find_widget, (Widget)); E Boolean FDECL(nhApproxColor, (Screen *, Colormap, char *, XColor *)); E Dimension FDECL(nhFontHeight, (Widget)); E char FDECL(key_event_to_char, (XKeyEvent *)); E void FDECL(msgkey, (Widget, XtPointer, XEvent *)); E void FDECL(nh_XtPopup, (Widget, int, Widget)); E void FDECL(nh_XtPopdown, (Widget)); E void FDECL(win_X11_init, (int)); E void FDECL(nh_keyscroll, (Widget, XEvent *, String *, Cardinal *)); /* ### winmesg.c ### */ E void FDECL(set_message_slider, (struct xwindow *)); E void FDECL(create_message_window, (struct xwindow *, BOOLEAN_P, Widget)); E void FDECL(destroy_message_window, (struct xwindow *)); E void FDECL(display_message_window, (struct xwindow *)); E void FDECL(append_message, (struct xwindow *, const char *)); E void FDECL(set_last_pause, (struct xwindow *)); /* ### winmap.c ### */ E void NDECL(post_process_tiles); E void FDECL(check_cursor_visibility, (struct xwindow *)); E void FDECL(display_map_window, (struct xwindow *)); E void FDECL(clear_map_window, (struct xwindow *)); E void FDECL(map_input, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(set_map_size, (struct xwindow *, DIMENSION_P, DIMENSION_P)); E void FDECL(create_map_window, (struct xwindow *, BOOLEAN_P, Widget)); E void FDECL(destroy_map_window, (struct xwindow *)); E int FDECL(x_event, (int)); /* ### winmenu.c ### */ E void FDECL(menu_delete, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(menu_key, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(create_menu_window, (struct xwindow *)); E void FDECL(destroy_menu_window, (struct xwindow *)); /* ### winmisc.c ### */ E void FDECL(ps_key, (Widget, XEvent *, String *, Cardinal *)); /* player selection action */ E void FDECL(race_key, (Widget, XEvent *, String *, Cardinal *)); /* race selection action */ E void FDECL(gend_key, (Widget, XEvent *, String *, Cardinal *)); /* gender */ E void FDECL(algn_key, (Widget, XEvent *, String *, Cardinal *)); /* alignment */ E void FDECL(ec_delete, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(ec_key, (Widget, XEvent *, String *, Cardinal *)); /* extended command action */ /* ### winstatus.c ### */ E void FDECL(create_status_window, (struct xwindow *, BOOLEAN_P, Widget)); E void FDECL(destroy_status_window, (struct xwindow *)); E void FDECL(adjust_status, (struct xwindow *, const char *)); E void NDECL(null_out_status); E void NDECL(check_turn_events); /* ### wintext.c ### */ E void FDECL(delete_text, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(dismiss_text, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(key_dismiss_text, (Widget, XEvent *, String *, Cardinal *)); #ifdef GRAPHIC_TOMBSTONE E void FDECL(rip_dismiss_text, (Widget, XEvent *, String *, Cardinal *)); #endif E void FDECL(add_to_text_window, (struct xwindow *, int, const char *)); E void FDECL(display_text_window, (struct xwindow *, BOOLEAN_P)); E void FDECL(create_text_window, (struct xwindow *)); E void FDECL(destroy_text_window, (struct xwindow *)); E void FDECL(clear_text_window, (struct xwindow *)); E void FDECL(append_text_buffer, (struct text_buffer *, const char *, BOOLEAN_P)); /* text buffer routines */ E void FDECL(init_text_buffer, (struct text_buffer *)); E void FDECL(clear_text_buffer, (struct text_buffer *)); E void FDECL(free_text_buffer, (struct text_buffer *)); #ifdef GRAPHIC_TOMBSTONE E void FDECL(calculate_rip_text, (int, time_t)); #endif /* ### winval.c ### */ E Widget FDECL(create_value, (Widget, const char *)); E void FDECL(set_name, (Widget, const char *)); E void FDECL(set_name_width, (Widget, int)); E int FDECL(get_name_width, (Widget)); E void FDECL(set_value, (Widget, const char *)); E void FDECL(set_value_width, (Widget, int)); E int FDECL(get_value_width, (Widget)); E void FDECL(hilight_value, (Widget)); E void FDECL(swap_fg_bg, (Widget)); /* external declarations */ E void FDECL(X11_init_nhwindows, (int *, char **)); E void NDECL(X11_player_selection); E void NDECL(X11_askname); E void NDECL(X11_get_nh_event); E void FDECL(X11_exit_nhwindows, (const char *)); E void FDECL(X11_suspend_nhwindows, (const char *)); E void NDECL(X11_resume_nhwindows); E winid FDECL(X11_create_nhwindow, (int)); E void FDECL(X11_clear_nhwindow, (winid)); E void FDECL(X11_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(X11_destroy_nhwindow, (winid)); E void FDECL(X11_curs, (winid, int, int)); E void FDECL(X11_putstr, (winid, int, const char *)); E void FDECL(X11_display_file, (const char *, BOOLEAN_P)); E void FDECL(X11_start_menu, (winid)); E void FDECL(X11_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); E void FDECL(X11_end_menu, (winid, const char *)); E int FDECL(X11_select_menu, (winid, int, MENU_ITEM_P **)); E void NDECL(X11_update_inventory); E void NDECL(X11_mark_synch); E void NDECL(X11_wait_synch); #ifdef CLIPPING E void FDECL(X11_cliparound, (int, int)); #endif E void FDECL(X11_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); E void FDECL(X11_raw_print, (const char *)); E void FDECL(X11_raw_print_bold, (const char *)); E int NDECL(X11_nhgetch); E int FDECL(X11_nh_poskey, (int *, int *, int *)); E void NDECL(X11_nhbell); E int NDECL(X11_doprev_message); E char FDECL(X11_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(X11_getlin, (const char *, char *)); E int NDECL(X11_get_ext_cmd); E void FDECL(X11_number_pad, (int)); E void NDECL(X11_delay_output); /* other defs that really should go away (they're tty specific) */ E void NDECL(X11_start_screen); E void NDECL(X11_end_screen); #ifdef GRAPHIC_TOMBSTONE E void FDECL(X11_outrip, (winid, int, time_t)); #else E void FDECL(genl_outrip, (winid, int, time_t)); #endif E void FDECL(X11_preference_update, (const char *)); #endif /* WINX_H */ nethack-3.6.0/include/winami.h0000664000076400007660000001114412536476415015233 0ustar paxedpaxed/* NetHack 3.6 winami.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991. */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINAMI_H #define WINAMI_H #define MAXWINTAGS 5 /* * Information specific to a menu window. First a structure for each * menu entry, then the structure for each menu window. */ typedef struct amii_mi { struct amii_mi *next; anything identifier; /* Opaque type to identify this selection */ long glyph; /* Glyph for menu item */ long count; /* Object count */ char selected; /* Been selected? */ char selector; /* Char used to select this entry. */ char gselector; /* Group selector */ char canselect; /* Can user select this entry. */ char attr; /* Attribute for the line. */ char *str; /* The text of the item. */ } amii_menu_item; struct amii_menu { amii_menu_item *items; /* Starting pointer for item list. */ amii_menu_item *last; /* End pointer for item list. */ const char *query; /* Query string */ int count; /* Number of strings. */ char chr; /* Character to assign for accelerator */ }; /* descriptor for Amiga Intuition-based windows. If we decide to cope with * tty-style windows also, then things will need to change. */ /* per-window data */ struct amii_WinDesc { xchar type; /* type of window */ struct amii_menu menu; boolean active; /* true if window is active */ boolean wasup; /* true if menu/text window was already open */ short disprows; /* Rows displayed so far (used for paging in message win) */ xchar offx, offy; /* offset from topleft of display */ short vwx, vwy, vcx, vcy; /* View cursor location */ short rows, cols; /* dimensions */ short curx, cury; /* current cursor position */ short maxrow, maxcol; /* the maximum size used -- for INVEN wins */ /* maxcol is also used by WIN_MESSAGE for */ /* tracking the ^P command */ char **data; /* window data [row][column] */ menu_item *mi; /* Menu information */ char *resp; /* valid menu responses (for NHW_INVEN) */ char *canresp; /* cancel responses; 1st is the return value */ char *morestr; /* string to display instead of default */ /* amiga stuff */ struct Window *win; /* Intuition window pointer */ #ifdef INTUI_NEW_LOOK struct ExtNewWindow *newwin; /* NewWindow alloc'd */ #else struct NewWindow *newwin; /* ExtNewWindow alloc'd */ #endif #ifdef INTUI_NEW_LOOK struct TagItem wintags[MAXWINTAGS]; /* Tag items for this window */ #else long wintags[MAXWINTAGS * 2]; #endif void *hook; /* Hook structure pointer for tiles version */ #define FLMAP_INGLYPH 1 /* An NHW_MAP window is in glyph mode */ #define FLMAP_CURSUP 2 /* An NHW_MAP window has the cursor displayed */ #define FLMAP_SKIP 4 #define FLMSG_FIRST \ 1 /* First message in the NHW_MESSAGE window for this turn */ long wflags; short cursx, cursy; /* Where the cursor is displayed at */ short curs_apen, /* Color cursor is displayed in */ curs_bpen; }; /* descriptor for intuition-based displays -- all the per-display data */ /* this is a generic thing - think of it as Screen level */ struct amii_DisplayDesc { /* we need this for Screen size (which will vary with display mode) */ uchar rows, cols; /* width & height of display in text units */ short xpix, ypix; /* width and height of display in pixels */ int toplin; /* flag for topl stuff */ int rawprint; /* number of raw_printed lines since synch */ winid lastwin; /* last window used for I/O */ }; typedef enum { WEUNK, WEKEY, WEMOUSE, WEMENU, } WETYPE; typedef struct WEVENT { WETYPE type; union { int key; struct { int x, y; int qual; } mouse; long menucode; } un; } WEVENT; #define MAXWIN 20 /* maximum number of windows, cop-out */ /* port specific variable declarations */ extern winid WIN_BASE; extern winid WIN_OVER; #define NHW_BASE 6 #define NHW_OVER 7 /* overview window */ extern struct amii_WinDesc *amii_wins[MAXWIN + 1]; extern struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ extern char morc; /* last character typed to xwaitforspace */ extern char defmorestr[]; /* default --more-- prompt */ #endif /* WINAMI_H */ nethack-3.6.0/include/wingem.h0000664000076400007660000000740412536476415015241 0ustar paxedpaxed/* NetHack 3.6 wingem.h $NHDT-Date: 1433806582 2015/06/08 23:36:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Christian Bressler, 1999 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINGEM_H #define WINGEM_H #define E extern /* menu structure */ typedef struct Gmi { struct Gmi *Gmi_next; int Gmi_glyph; long Gmi_identifier; char Gmi_accelerator, Gmi_groupacc; int Gmi_attr; char *Gmi_str; long Gmi_count; int Gmi_selected; } Gem_menu_item; #define MAXWIN 20 /* maximum number of windows, cop-out */ extern struct window_procs Gem_procs; /* ### wingem1.c ### */ #ifdef CLIPPING E void NDECL(setclipped); #endif E void FDECL(docorner, (int, int)); E void NDECL(end_glyphout); E void FDECL(g_putch, (int)); E void FDECL(win_Gem_init, (int)); E int NDECL(mar_gem_init); E char NDECL(mar_ask_class); E char *NDECL(mar_ask_name); E int FDECL(mar_create_window, (int)); E void FDECL(mar_destroy_nhwindow, (int)); E void FDECL(mar_print_glyph, (int, int, int, int, int)); E void FDECL(mar_print_line, (int, int, int, char *)); E void FDECL(mar_set_message, (char *, char *, char *)); E Gem_menu_item *NDECL(mar_hol_inv); E void FDECL(mar_set_menu_type, (int)); E void NDECL(mar_reverse_menu); E void FDECL(mar_set_menu_title, (const char *)); E void NDECL(mar_set_accelerators); E void FDECL(mar_add_menu, (winid, Gem_menu_item *)); E void FDECL(mar_change_menu_2_text, (winid)); E void FDECL(mar_add_message, (const char *)); E void NDECL(mar_status_dirty); E int FDECL(mar_hol_win_type, (int)); E void NDECL(mar_clear_messagewin); E void FDECL(mar_set_no_glyph, (int)); E void NDECL(mar_map_curs_weiter); /* external declarations */ E void FDECL(Gem_init_nhwindows, (int *, char **)); E void NDECL(Gem_player_selection); E void NDECL(Gem_askname); E void NDECL(Gem_get_nh_event); E void FDECL(Gem_exit_nhwindows, (const char *)); E void FDECL(Gem_suspend_nhwindows, (const char *)); E void NDECL(Gem_resume_nhwindows); E winid FDECL(Gem_create_nhwindow, (int)); E void FDECL(Gem_clear_nhwindow, (winid)); E void FDECL(Gem_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(Gem_dismiss_nhwindow, (winid)); E void FDECL(Gem_destroy_nhwindow, (winid)); E void FDECL(Gem_curs, (winid, int, int)); E void FDECL(Gem_putstr, (winid, int, const char *)); E void FDECL(Gem_display_file, (const char *, BOOLEAN_P)); E void FDECL(Gem_start_menu, (winid)); E void FDECL(Gem_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); E void FDECL(Gem_end_menu, (winid, const char *)); E int FDECL(Gem_select_menu, (winid, int, MENU_ITEM_P **)); E char FDECL(Gem_message_menu, (CHAR_P, int, const char *)); E void NDECL(Gem_update_inventory); E void NDECL(Gem_mark_synch); E void NDECL(Gem_wait_synch); #ifdef CLIPPING E void FDECL(Gem_cliparound, (int, int)); #endif #ifdef POSITIONBAR E void FDECL(Gem_update_positionbar, (char *)); #endif E void FDECL(Gem_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); E void FDECL(Gem_raw_print, (const char *)); E void FDECL(Gem_raw_print_bold, (const char *)); E int NDECL(Gem_nhgetch); E int FDECL(Gem_nh_poskey, (int *, int *, int *)); E void NDECL(Gem_nhbell); E int NDECL(Gem_doprev_message); E char FDECL(Gem_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(Gem_getlin, (const char *, char *)); E int NDECL(Gem_get_ext_cmd); E void FDECL(Gem_number_pad, (int)); E void NDECL(Gem_delay_output); #ifdef CHANGE_COLOR E void FDECL(Gem_change_color, (int color, long rgb, int reverse)); E char *NDECL(Gem_get_color_string); #endif /* other defs that really should go away (they're tty specific) */ E void NDECL(Gem_start_screen); E void NDECL(Gem_end_screen); E void FDECL(genl_outrip, (winid, int, time_t)); #undef E #endif /* WINGEM_H */ nethack-3.6.0/include/winprocs.h0000664000076400007660000004072312536476415015620 0ustar paxedpaxed/* NetHack 3.6 winprocs.h $NHDT-Date: 1433806582 2015/06/08 23:36:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.36 $ */ /* Copyright (c) David Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINPROCS_H #define WINPROCS_H #include "botl.h" /* NB: this MUST match chain_procs below */ struct window_procs { const char *name; /* Names should start with [a-z]. Names must * not start with '-'. Names starting with * '+' are reserved for processors. */ unsigned long wincap; /* window port capability options supported */ unsigned long wincap2; /* additional window port capability options supported */ void FDECL((*win_init_nhwindows), (int *, char **)); void NDECL((*win_player_selection)); void NDECL((*win_askname)); void NDECL((*win_get_nh_event)); void FDECL((*win_exit_nhwindows), (const char *)); void FDECL((*win_suspend_nhwindows), (const char *)); void NDECL((*win_resume_nhwindows)); winid FDECL((*win_create_nhwindow), (int)); void FDECL((*win_clear_nhwindow), (winid)); void FDECL((*win_display_nhwindow), (winid, BOOLEAN_P)); void FDECL((*win_destroy_nhwindow), (winid)); void FDECL((*win_curs), (winid, int, int)); void FDECL((*win_putstr), (winid, int, const char *)); void FDECL((*win_putmixed), (winid, int, const char *)); void FDECL((*win_display_file), (const char *, BOOLEAN_P)); void FDECL((*win_start_menu), (winid)); void FDECL((*win_add_menu), (winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); void FDECL((*win_end_menu), (winid, const char *)); int FDECL((*win_select_menu), (winid, int, MENU_ITEM_P **)); char FDECL((*win_message_menu), (CHAR_P, int, const char *)); void NDECL((*win_update_inventory)); void NDECL((*win_mark_synch)); void NDECL((*win_wait_synch)); #ifdef CLIPPING void FDECL((*win_cliparound), (int, int)); #endif #ifdef POSITIONBAR void FDECL((*win_update_positionbar), (char *)); #endif void FDECL((*win_print_glyph), (winid, XCHAR_P, XCHAR_P, int, int)); void FDECL((*win_raw_print), (const char *)); void FDECL((*win_raw_print_bold), (const char *)); int NDECL((*win_nhgetch)); int FDECL((*win_nh_poskey), (int *, int *, int *)); void NDECL((*win_nhbell)); int NDECL((*win_doprev_message)); char FDECL((*win_yn_function), (const char *, const char *, CHAR_P)); void FDECL((*win_getlin), (const char *, char *)); int NDECL((*win_get_ext_cmd)); void FDECL((*win_number_pad), (int)); void NDECL((*win_delay_output)); #ifdef CHANGE_COLOR void FDECL((*win_change_color), (int, long, int)); #ifdef MAC void FDECL((*win_change_background), (int)); short FDECL((*win_set_font_name), (winid, char *)); #endif char *NDECL((*win_get_color_string)); #endif /* other defs that really should go away (they're tty specific) */ void NDECL((*win_start_screen)); void NDECL((*win_end_screen)); void FDECL((*win_outrip), (winid, int, time_t)); void FDECL((*win_preference_update), (const char *)); char *FDECL((*win_getmsghistory), (BOOLEAN_P)); void FDECL((*win_putmsghistory), (const char *, BOOLEAN_P)); #ifdef STATUS_VIA_WINDOWPORT void NDECL((*win_status_init)); void NDECL((*win_status_finish)); void FDECL((*win_status_enablefield), (int, const char *, const char *, BOOLEAN_P)); void FDECL((*win_status_update), (int, genericptr_t, int, int)); #ifdef STATUS_HILITES void FDECL((*win_status_threshold), (int, int, anything, int, int, int)); #endif #endif boolean NDECL((*win_can_suspend)); }; extern #ifdef HANGUPHANDLING volatile #endif NEARDATA struct window_procs windowprocs; /* * If you wish to only support one window system and not use procedure * pointers, add the appropriate #ifdef below. */ #define init_nhwindows (*windowprocs.win_init_nhwindows) #define player_selection (*windowprocs.win_player_selection) #define askname (*windowprocs.win_askname) #define get_nh_event (*windowprocs.win_get_nh_event) #define exit_nhwindows (*windowprocs.win_exit_nhwindows) #define suspend_nhwindows (*windowprocs.win_suspend_nhwindows) #define resume_nhwindows (*windowprocs.win_resume_nhwindows) #define create_nhwindow (*windowprocs.win_create_nhwindow) #define clear_nhwindow (*windowprocs.win_clear_nhwindow) #define display_nhwindow (*windowprocs.win_display_nhwindow) #define destroy_nhwindow (*windowprocs.win_destroy_nhwindow) #define curs (*windowprocs.win_curs) #define putstr (*windowprocs.win_putstr) #define putmixed (*windowprocs.win_putmixed) #define display_file (*windowprocs.win_display_file) #define start_menu (*windowprocs.win_start_menu) #define add_menu (*windowprocs.win_add_menu) #define end_menu (*windowprocs.win_end_menu) #define select_menu (*windowprocs.win_select_menu) #define message_menu (*windowprocs.win_message_menu) #define update_inventory (*windowprocs.win_update_inventory) #define mark_synch (*windowprocs.win_mark_synch) #define wait_synch (*windowprocs.win_wait_synch) #ifdef CLIPPING #define cliparound (*windowprocs.win_cliparound) #endif #ifdef POSITIONBAR #define update_positionbar (*windowprocs.win_update_positionbar) #endif #define print_glyph (*windowprocs.win_print_glyph) #define raw_print (*windowprocs.win_raw_print) #define raw_print_bold (*windowprocs.win_raw_print_bold) #define nhgetch (*windowprocs.win_nhgetch) #define nh_poskey (*windowprocs.win_nh_poskey) #define nhbell (*windowprocs.win_nhbell) #define nh_doprev_message (*windowprocs.win_doprev_message) #define getlin (*windowprocs.win_getlin) #define get_ext_cmd (*windowprocs.win_get_ext_cmd) #define number_pad (*windowprocs.win_number_pad) #define delay_output (*windowprocs.win_delay_output) #ifdef CHANGE_COLOR #define change_color (*windowprocs.win_change_color) #ifdef MAC #define change_background (*windowprocs.win_change_background) #define set_font_name (*windowprocs.win_set_font_name) #endif #define get_color_string (*windowprocs.win_get_color_string) #endif /* 3.4.2: There is a real yn_function() in the core now, which does * some buffer length validation on the parameters prior to * invoking the window port routine. yn_function() is in cmd.c */ /* #define yn_function (*windowprocs.win_yn_function) */ /* other defs that really should go away (they're tty specific) */ #define start_screen (*windowprocs.win_start_screen) #define end_screen (*windowprocs.win_end_screen) #define outrip (*windowprocs.win_outrip) #define preference_update (*windowprocs.win_preference_update) #define getmsghistory (*windowprocs.win_getmsghistory) #define putmsghistory (*windowprocs.win_putmsghistory) #ifdef STATUS_VIA_WINDOWPORT /* there is a status_initialize() in botl.c, * which calls win_status_init() directly; same with status_finish. */ #define status_enablefield (*windowprocs.win_status_enablefield) #define status_update (*windowprocs.win_status_update) #ifdef STATUS_HILITES #define status_threshold (*windowprocs.win_status_threshold) #endif #endif /* * WINCAP * Window port preference capability bits. * Some day this might be better in its own wincap.h file. */ #define WC_COLOR 0x01L /* 01 Port can display things in color */ #define WC_HILITE_PET 0x02L /* 02 supports hilite pet */ #define WC_ASCII_MAP 0x04L /* 03 supports an ascii map */ #define WC_TILED_MAP 0x08L /* 04 supports a tiled map */ #define WC_PRELOAD_TILES 0x10L /* 05 supports pre-loading tiles */ #define WC_TILE_WIDTH 0x20L /* 06 prefer this width of tile */ #define WC_TILE_HEIGHT 0x40L /* 07 prefer this height of tile */ #define WC_TILE_FILE 0x80L /* 08 alternative tile file name */ #define WC_INVERSE 0x100L /* 09 Port supports inverse video */ #define WC_ALIGN_MESSAGE \ 0x200L /* 10 supports message alignmt top|b|l|r */ #define WC_ALIGN_STATUS 0x400L /* 11 supports status alignmt top|b|l|r */ #define WC_VARY_MSGCOUNT \ 0x800L /* 12 supports varying message window */ #define WC_FONT_MAP 0x1000L /* 13 supports specification of map win font */ #define WC_FONT_MESSAGE \ 0x2000L /* 14 supports specification of msg win font */ #define WC_FONT_STATUS 0x4000L /* 15 supports specification of sts win font \ */ #define WC_FONT_MENU 0x8000L /* 16 supports specification of mnu win font */ #define WC_FONT_TEXT 0x10000L /* 17 supports specification of txt win font \ */ #define WC_FONTSIZ_MAP \ 0x20000L /* 18 supports specification of map win font */ #define WC_FONTSIZ_MESSAGE \ 0x40000L /* 19 supports specification of msg win font */ #define WC_FONTSIZ_STATUS \ 0x80000L /* 20 supports specification of sts win font */ #define WC_FONTSIZ_MENU \ 0x100000L /* 21 supports specification of mnu win font */ #define WC_FONTSIZ_TEXT \ 0x200000L /* 22 supports specification of txt win font */ #define WC_SCROLL_MARGIN \ 0x400000L /* 23 supports setting scroll margin for map */ #define WC_SPLASH_SCREEN \ 0x800000L /* 24 supports display of splash screen */ #define WC_POPUP_DIALOG \ 0x1000000L /* 25 supports queries in pop dialogs */ #define WC_SCROLL_AMOUNT \ 0x2000000L /* 26 scroll this amount at scroll margin */ #define WC_EIGHT_BIT_IN \ 0x4000000L /* 27 8-bit character input */ #define WC_PERM_INVENT \ 0x8000000L /* 28 8-bit character input */ #define WC_MAP_MODE \ 0x10000000L /* 29 map_mode option */ #define WC_WINDOWCOLORS \ 0x20000000L /* 30 background color for message window */ #define WC_PLAYER_SELECTION \ 0x40000000L /* 31 background color for message window */ #ifdef NHSTDC #define WC_MOUSE_SUPPORT \ 0x80000000UL /* 32 mouse support */ #else #define WC_MOUSE_SUPPORT \ 0x80000000L /* 32 mouse support */ #endif /* no free bits */ #define WC2_FULLSCREEN 0x01L /* 01 display full screen */ #define WC2_SOFTKEYBOARD 0x02L /* 02 software keyboard */ #define WC2_WRAPTEXT 0x04L /* 03 wrap long lines of text */ #define WC2_HILITE_STATUS \ 0x08L /* 04 hilite fields in status */ #define WC2_SELECTSAVED 0x10L /* 05 saved game selection menu */ #define WC2_DARKGRAY 0x20L /* 06 use bold black for black glyphs */ /* 26 free bits */ #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 #define ALIGN_TOP 3 #define ALIGN_BOTTOM 4 /* player_selection */ #define VIA_DIALOG 0 #define VIA_PROMPTS 1 /* map_mode settings - deprecated */ #define MAP_MODE_TILES 0 #define MAP_MODE_ASCII4x6 1 #define MAP_MODE_ASCII6x8 2 #define MAP_MODE_ASCII8x8 3 #define MAP_MODE_ASCII16x8 4 #define MAP_MODE_ASCII7x12 5 #define MAP_MODE_ASCII8x12 6 #define MAP_MODE_ASCII16x12 7 #define MAP_MODE_ASCII12x16 8 #define MAP_MODE_ASCII10x18 9 #define MAP_MODE_ASCII_FIT_TO_SCREEN 10 #define MAP_MODE_TILES_FIT_TO_SCREEN 11 #if 0 #define WC_SND_SOUND 0x01L /* 01 Port has some sound capabilities */ #define WC_SND_SPEAKER 0x02L /* 02 Sound supported via built-in speaker */ #define WC_SND_STEREO 0x04L /* 03 Stereo sound supported */ #define WC_SND_RAW 0x08L /* 04 Raw sound supported */ #define WC_SND_WAVE 0x10L /* 05 Wave support */ #define WC_SND_MIDI 0x20L /* 06 Midi support */ /* 26 free bits */ #endif struct wc_Opt { const char *wc_name; unsigned long wc_bit; }; /* role selection by player_selection(); this ought to be in the core... */ #define RS_NAME 0 #define RS_ROLE 1 #define RS_RACE 2 #define RS_GENDER 3 #define RS_ALGNMNT 4 #define RS_filter 5 #define RS_menu_arg(x) (ROLE_RANDOM - ((x) + 1)) /* 0..5 -> -3..-8 */ /* Choose_windows() may be called multiple times; these constants tell the * init function whether the window system is coming or going. */ #define WININIT 0 #define WININIT_UNDO 1 #ifdef WINCHAIN /* Setup phases for window chain elements. void * rv = X_procs_chain(int, int, void *, void *, void *); Xprivate* ALLOC n 0 0 0 - INIT n self next nextdata where: Xprivate* is anything window chain entry type X wants back n is the link count (starting with 1) self is the Xprivate* returned earlier next is struct winprocs * or struct chainprocs * for the next link nextdata is the Xprivate* for the next link in the chain */ #define WINCHAIN_ALLOC 0 #define WINCHAIN_INIT 1 #define CARGS void * extern FILE *wc_tracelogf; /* Expose log file for additional debugging. */ struct chain_procs { const char *name; /* Names should start with [a-z]. Names must * not start with '-'. Names starting with * '+' are reserved for processors. */ unsigned long wincap; /* window port capability options supported */ unsigned long wincap2; /* additional window port capability options supported */ void FDECL((*win_init_nhwindows), (CARGS, int *, char **)); void FDECL((*win_player_selection), (CARGS)); void FDECL((*win_askname), (CARGS)); void FDECL((*win_get_nh_event), (CARGS)); void FDECL((*win_exit_nhwindows), (CARGS, const char *)); void FDECL((*win_suspend_nhwindows), (CARGS, const char *)); void FDECL((*win_resume_nhwindows), (CARGS)); winid FDECL((*win_create_nhwindow), (CARGS, int)); void FDECL((*win_clear_nhwindow), (CARGS, winid)); void FDECL((*win_display_nhwindow), (CARGS, winid, BOOLEAN_P)); void FDECL((*win_destroy_nhwindow), (CARGS, winid)); void FDECL((*win_curs), (CARGS, winid, int, int)); void FDECL((*win_putstr), (CARGS, winid, int, const char *)); void FDECL((*win_putmixed), (CARGS, winid, int, const char *)); void FDECL((*win_display_file), (CARGS, const char *, BOOLEAN_P)); void FDECL((*win_start_menu), (CARGS, winid)); void FDECL((*win_add_menu), (CARGS, winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); void FDECL((*win_end_menu), (CARGS, winid, const char *)); int FDECL((*win_select_menu), (CARGS, winid, int, MENU_ITEM_P **)); char FDECL((*win_message_menu), (CARGS, CHAR_P, int, const char *)); void FDECL((*win_update_inventory), (CARGS)); void FDECL((*win_mark_synch), (CARGS)); void FDECL((*win_wait_synch), (CARGS)); #ifdef CLIPPING void FDECL((*win_cliparound), (CARGS, int, int)); #endif #ifdef POSITIONBAR void FDECL((*win_update_positionbar), (CARGS, char *)); #endif void FDECL((*win_print_glyph), (CARGS, winid, XCHAR_P, XCHAR_P, int, int)); void FDECL((*win_raw_print), (CARGS, const char *)); void FDECL((*win_raw_print_bold), (CARGS, const char *)); int FDECL((*win_nhgetch), (CARGS)); int FDECL((*win_nh_poskey), (CARGS, int *, int *, int *)); void FDECL((*win_nhbell), (CARGS)); int FDECL((*win_doprev_message), (CARGS)); char FDECL((*win_yn_function), (CARGS, const char *, const char *, CHAR_P)); void FDECL((*win_getlin), (CARGS, const char *, char *)); int FDECL((*win_get_ext_cmd), (CARGS)); void FDECL((*win_number_pad), (CARGS, int)); void FDECL((*win_delay_output), (CARGS)); #ifdef CHANGE_COLOR void FDECL((*win_change_color), (CARGS, int, long, int)); #ifdef MAC void FDECL((*win_change_background), (CARGS, int)); short FDECL((*win_set_font_name), (CARGS, winid, char *)); #endif char *FDECL((*win_get_color_string), (CARGS)); #endif /* other defs that really should go away (they're tty specific) */ void FDECL((*win_start_screen), (CARGS)); void FDECL((*win_end_screen), (CARGS)); void FDECL((*win_outrip), (CARGS, winid, int, time_t)); void FDECL((*win_preference_update), (CARGS, const char *)); char *FDECL((*win_getmsghistory), (CARGS, BOOLEAN_P)); void FDECL((*win_putmsghistory), (CARGS, const char *, BOOLEAN_P)); #ifdef STATUS_VIA_WINDOWPORT void FDECL((*win_status_init), (CARGS)); void FDECL((*win_status_finish), (CARGS)); void FDECL((*win_status_enablefield), (CARGS, int, const char *, const char *, BOOLEAN_P)); void FDECL((*win_status_update), (CARGS, int, genericptr_t, int, int)); #ifdef STATUS_HILITES void FDECL((*win_status_threshold), (CARGS, int, int, anything, int, int, int)); #endif #endif boolean FDECL((*win_can_suspend), (CARGS)); }; #endif /* WINCHAIN */ #endif /* WINPROCS_H */ nethack-3.6.0/include/wintty.h0000664000076400007660000002115712536476415015312 0ustar paxedpaxed/* NetHack 3.6 wintty.h $NHDT-Date: 1433806583 2015/06/08 23:36:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) David Cohrs, 1991,1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINTTY_H #define WINTTY_H #define E extern #ifndef WINDOW_STRUCTS #define WINDOW_STRUCTS /* menu structure */ typedef struct tty_mi { struct tty_mi *next; anything identifier; /* user identifier */ long count; /* user count */ char *str; /* description string (including accelerator) */ int attr; /* string attribute */ boolean selected; /* TRUE if selected by user */ char selector; /* keyboard accelerator */ char gselector; /* group accelerator */ } tty_menu_item; /* descriptor for tty-based windows */ struct WinDesc { int flags; /* window flags */ xchar type; /* type of window */ boolean active; /* true if window is active */ short offx, offy; /* offset from topleft of display */ long rows, cols; /* dimensions */ long curx, cury; /* current cursor position */ long maxrow, maxcol; /* the maximum size used -- for MENU wins */ /* maxcol is also used by WIN_MESSAGE for */ /* tracking the ^P command */ short *datlen; /* allocation size for *data */ char **data; /* window data [row][column] */ char *morestr; /* string to display instead of default */ tty_menu_item *mlist; /* menu information (MENU) */ tty_menu_item **plist; /* menu page pointers (MENU) */ long plist_size; /* size of allocated plist (MENU) */ long npages; /* number of pages in menu (MENU) */ long nitems; /* total number of items (MENU) */ short how; /* menu mode - pick 1 or N (MENU) */ char menu_ch; /* menu char (MENU) */ }; /* window flags */ #define WIN_CANCELLED 1 #define WIN_STOP 1 /* for NHW_MESSAGE; stops output */ #define WIN_LOCKHISTORY 2 /* for NHW_MESSAGE; suppress history updates */ /* descriptor for tty-based displays -- all the per-display data */ struct DisplayDesc { short rows, cols; /* width and height of tty display */ short curx, cury; /* current cursor position on the screen */ #ifdef TEXTCOLOR int color; /* current color */ #endif int attrs; /* attributes in effect */ int toplin; /* flag for topl stuff */ int rawprint; /* number of raw_printed lines since synch */ int inmore; /* non-zero if more() is active */ int inread; /* non-zero if reading a character */ int intr; /* non-zero if inread was interrupted */ winid lastwin; /* last window used for I/O */ char dismiss_more; /* extra character accepted at --More-- */ }; #endif /* WINDOW_STRUCTS */ #define MAXWIN 20 /* maximum number of windows, cop-out */ /* tty dependent window types */ #ifdef NHW_BASE #undef NHW_BASE #endif #define NHW_BASE 6 extern struct window_procs tty_procs; /* port specific variable declarations */ extern winid BASE_WINDOW; extern struct WinDesc *wins[MAXWIN]; extern struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ extern char morc; /* last character typed to xwaitforspace */ extern char defmorestr[]; /* default --more-- prompt */ /* port specific external function references */ /* ### getline.c ### */ E void FDECL(xwaitforspace, (const char *)); /* ### termcap.c, video.c ### */ E void FDECL(tty_startup, (int *, int *)); #ifndef NO_TERMS E void NDECL(tty_shutdown); #endif #if defined(apollo) /* Apollos don't widen old-style function definitions properly -- they try to * be smart and use the prototype, or some such strangeness. So we have to * define UNWIDENDED_PROTOTYPES (in tradstdc.h), which makes CHAR_P below a * char. But the tputs termcap call was compiled as if xputc's argument * actually would be expanded. So here, we have to make an exception. */ E void FDECL(xputc, (int)); #else E void FDECL(xputc, (CHAR_P)); #endif E void FDECL(xputs, (const char *)); #if defined(SCREEN_VGA) || defined(SCREEN_8514) E void FDECL(xputg, (int, int, unsigned)); #endif E void NDECL(cl_end); E void NDECL(clear_screen); E void NDECL(home); E void NDECL(standoutbeg); E void NDECL(standoutend); #if 0 E void NDECL(revbeg); E void NDECL(boldbeg); E void NDECL(blinkbeg); E void NDECL(dimbeg); E void NDECL(m_end); #endif E void NDECL(backsp); E void NDECL(graph_on); E void NDECL(graph_off); E void NDECL(cl_eos); /* * termcap.c (or facsimiles in other ports) is the right place for doing * strange and arcane things such as outputting escape sequences to select * a color or whatever. wintty.c should concern itself with WHERE to put * stuff in a window. */ E void FDECL(term_start_attr, (int attr)); E void FDECL(term_end_attr, (int attr)); E void NDECL(term_start_raw_bold); E void NDECL(term_end_raw_bold); #ifdef TEXTCOLOR E void NDECL(term_end_color); E void FDECL(term_start_color, (int color)); E int FDECL(has_color, (int color)); #endif /* TEXTCOLOR */ /* ### topl.c ### */ E void FDECL(addtopl, (const char *)); E void NDECL(more); E void FDECL(update_topl, (const char *)); E void FDECL(putsyms, (const char *)); /* ### wintty.c ### */ #ifdef CLIPPING E void NDECL(setclipped); #endif E void FDECL(docorner, (int, int)); E void NDECL(end_glyphout); E void FDECL(g_putch, (int)); E void FDECL(win_tty_init, (int)); /* external declarations */ E void FDECL(tty_init_nhwindows, (int *, char **)); E void NDECL(tty_player_selection); E void NDECL(tty_askname); E void NDECL(tty_get_nh_event); E void FDECL(tty_exit_nhwindows, (const char *)); E void FDECL(tty_suspend_nhwindows, (const char *)); E void NDECL(tty_resume_nhwindows); E winid FDECL(tty_create_nhwindow, (int)); E void FDECL(tty_clear_nhwindow, (winid)); E void FDECL(tty_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(tty_dismiss_nhwindow, (winid)); E void FDECL(tty_destroy_nhwindow, (winid)); E void FDECL(tty_curs, (winid, int, int)); E void FDECL(tty_putstr, (winid, int, const char *)); E void FDECL(tty_display_file, (const char *, BOOLEAN_P)); E void FDECL(tty_start_menu, (winid)); E void FDECL(tty_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); E void FDECL(tty_end_menu, (winid, const char *)); E int FDECL(tty_select_menu, (winid, int, MENU_ITEM_P **)); E char FDECL(tty_message_menu, (CHAR_P, int, const char *)); E void NDECL(tty_update_inventory); E void NDECL(tty_mark_synch); E void NDECL(tty_wait_synch); #ifdef CLIPPING E void FDECL(tty_cliparound, (int, int)); #endif #ifdef POSITIONBAR E void FDECL(tty_update_positionbar, (char *)); #endif E void FDECL(tty_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); E void FDECL(tty_raw_print, (const char *)); E void FDECL(tty_raw_print_bold, (const char *)); E int NDECL(tty_nhgetch); E int FDECL(tty_nh_poskey, (int *, int *, int *)); E void NDECL(tty_nhbell); E int NDECL(tty_doprev_message); E char FDECL(tty_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(tty_getlin, (const char *, char *)); E int NDECL(tty_get_ext_cmd); E void FDECL(tty_number_pad, (int)); E void NDECL(tty_delay_output); #ifdef CHANGE_COLOR E void FDECL(tty_change_color, (int color, long rgb, int reverse)); #ifdef MAC E void FDECL(tty_change_background, (int white_or_black)); E short FDECL(set_tty_font_name, (winid, char *)); #endif E char *NDECL(tty_get_color_string); #endif #ifdef STATUS_VIA_WINDOWPORT E void NDECL(tty_status_init); E void FDECL(tty_status_update, (int, genericptr_t, int, int)); #ifdef STATUS_HILITES E void FDECL(tty_status_threshold, (int, int, anything, int, int, int)); #endif #endif /* other defs that really should go away (they're tty specific) */ E void NDECL(tty_start_screen); E void NDECL(tty_end_screen); E void FDECL(genl_outrip, (winid, int, time_t)); E char *FDECL(tty_getmsghistory, (BOOLEAN_P)); E void FDECL(tty_putmsghistory, (const char *, BOOLEAN_P)); #ifdef NO_TERMS #ifdef MAC #ifdef putchar #undef putchar #undef putc #endif #define putchar term_putc #define fflush term_flush #define puts term_puts E int FDECL(term_putc, (int c)); E int FDECL(term_flush, (void *desc)); E int FDECL(term_puts, (const char *str)); #endif /* MAC */ #if defined(MSDOS) || defined(WIN32) #if defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST) || defined(WIN32) #undef putchar #undef putc #undef puts #define putchar(x) xputc(x) /* these are in video.c, nttty.c */ #define putc(x) xputc(x) #define puts(x) xputs(x) #endif /*SCREEN_BIOS || SCREEN_DJGPPFAST || WIN32 */ #ifdef POSITIONBAR E void FDECL(video_update_positionbar, (char *)); #endif #endif /*MSDOS*/ #endif /*NO_TERMS*/ #undef E #endif /* WINTTY_H */ nethack-3.6.0/include/wintype.h0000664000076400007660000000623012536476415015446 0ustar paxedpaxed/* NetHack 3.6 wintype.h $NHDT-Date: 1433207914 2015/06/02 01:18:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINTYPE_H #define WINTYPE_H typedef int winid; /* a window identifier */ /* generic parameter - must not be any larger than a pointer */ typedef union any { genericptr_t a_void; struct obj *a_obj; struct monst *a_monst; int a_int; char a_char; schar a_schar; unsigned int a_uint; long a_long; unsigned long a_ulong; int *a_iptr; long *a_lptr; unsigned long *a_ulptr; unsigned *a_uptr; const char *a_string; /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ /* (buggy old Ultrix compiler) */ /* symbolic names for the data types housed in anything */ /* clang-format off */ #define ANY_VOID 1 #define ANY_OBJ 2 /* struct obj */ #define ANY_MONST 3 /* struct monst (not used) */ #define ANY_INT 4 /* int */ #define ANY_CHAR 5 /* char */ #define ANY_UCHAR 6 /* unsigned char */ #define ANY_SCHAR 7 /* signed char */ #define ANY_UINT 8 /* unsigned int */ #define ANY_LONG 9 /* long */ #define ANY_ULONG 10 /* unsigned long */ #define ANY_IPTR 11 /* pointer to int */ #define ANY_UPTR 12 /* pointer to unsigned int */ #define ANY_LPTR 13 /* pointer to long */ #define ANY_ULPTR 14 /* pointer to unsigned long */ #define ANY_STR 15 /* pointer to null-terminated char string */ #define ANY_MASK32 16 /* 32-bit mask (stored as unsigned long) */ /* clang-format on */ /* menu return list */ typedef struct mi { anything item; /* identifier */ long count; /* count */ } menu_item; #define MENU_ITEM_P struct mi /* select_menu() "how" argument types */ #define PICK_NONE 0 /* user picks nothing (display only) */ #define PICK_ONE 1 /* only pick one */ #define PICK_ANY 2 /* can pick any amount */ /* window types */ /* any additional port specific types should be defined in win*.h */ #define NHW_MESSAGE 1 #define NHW_STATUS 2 #define NHW_MAP 3 #define NHW_MENU 4 #define NHW_TEXT 5 /* attribute types for putstr; the same as the ANSI value, for convenience */ #define ATR_NONE 0 #define ATR_BOLD 1 #define ATR_DIM 2 #define ATR_ULINE 4 #define ATR_BLINK 5 #define ATR_INVERSE 7 /* nh_poskey() modifier types */ #define CLICK_1 1 #define CLICK_2 2 /* invalid winid */ #define WIN_ERR ((winid) -1) /* menu window keyboard commands (may be mapped) */ /* clang-format off */ #define MENU_FIRST_PAGE '^' #define MENU_LAST_PAGE '|' #define MENU_NEXT_PAGE '>' #define MENU_PREVIOUS_PAGE '<' #define MENU_SELECT_ALL '.' #define MENU_UNSELECT_ALL '-' #define MENU_INVERT_ALL '@' #define MENU_SELECT_PAGE ',' #define MENU_UNSELECT_PAGE '\\' #define MENU_INVERT_PAGE '~' #define MENU_SEARCH ':' /* clang-format on */ #endif /* WINTYPE_H */ nethack-3.6.0/include/xwindow.h0000664000076400007660000000553612536476415015456 0ustar paxedpaxed/* NetHack 3.6 xwindow.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef _xwindow_h #define _xwindow_h /**************************************************************** * * Window widget * ****************************************************************/ /* Resources: Name Class RepType Default Value ---- ----- ------- ------------- background Background Pixel XtDefaultBackground border BorderColor Pixel XtDefaultForeground borderWidth BorderWidth Dimension 1 destroyCallback Callback Pointer NULL height Height Dimension 0 mappedWhenManaged MappedWhenManaged Boolean True sensitive Sensitive Boolean True width Width Dimension 0 x Position Position 0 y Position Position 0 rows Width Dimension 21 columns Height Dimension 80 foreground Color Pixel XtDefaultForeground black Color Pixel "black" red Color Pixel "red" green Color Pixel "pale green" brown Color Pixel "brown" blue Color Pixel "blue" magenta Color Pixel "magenta" cyan Color Pixel "light cyan" gray Color Pixel "gray" //no color// orange Color Pixel "orange" bright_green Color Pixel "green" yellow Color Pixel "yellow" bright_blue Color Pixel "royal blue" bright_magenta Color Pixel "violet" bright_cyan Color Pixel "cyan" white Color Pixel "white" font Font XFontStruct* XtDefaultFont exposeCallback Callback Callback NULL callback Callback Callback NULL resizeCallback Callback Callback NULL */ /* define any special resource names here that are not in */ #define XtNrows "rows" #define XtNcolumns "columns" #define XtNblack "black" #define XtNred "red" #define XtNgreen "green" #define XtNbrown "brown" #define XtNblue "blue" #define XtNmagenta "magenta" #define XtNcyan "cyan" #define XtNgray "gray" #define XtNorange "orange" #define XtNbright_green "bright_green" #define XtNyellow "yellow" #define XtNbright_blue "bright_blue" #define XtNbright_magenta "bright_magenta" #define XtNbright_cyan "bright_cyan" #define XtNwhite "white" #define XtNexposeCallback "exposeCallback" #define XtNresizeCallback "resizeCallback" extern XFontStruct *WindowFontStruct(/* Widget */); extern Font WindowFont(/* Widget */); #define XtCWindowResource "WindowResource" #define XtCRows "Rows" #define XtCColumns "Columns" /* declare specific WindowWidget class and instance datatypes */ typedef struct _WindowClassRec *WindowWidgetClass; typedef struct _WindowRec *WindowWidget; /* declare the class constant */ extern WidgetClass windowWidgetClass; #endif /* _xwindow_h */ nethack-3.6.0/include/xwindowp.h0000664000076400007660000000300512536476415015623 0ustar paxedpaxed/* NetHack 3.6 xwindowp.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef _xwindowp_h #define _xwindowp_h #include "xwindow.h" #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif /* include superclass private header file */ #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif /* define unique representation types not found in */ #define XtRWindowResource "WindowResource" typedef struct { int empty; } WindowClassPart; typedef struct _WindowClassRec { CoreClassPart core_class; WindowClassPart window_class; } WindowClassRec; extern WindowClassRec windowClassRec; typedef struct { /* resources */ Dimension rows; Dimension columns; Pixel foreground; Pixel black; Pixel red; Pixel green; Pixel brown; Pixel blue; Pixel magenta; Pixel cyan; Pixel gray; Pixel orange; Pixel bright_green; Pixel yellow; Pixel bright_blue; Pixel bright_magenta; Pixel bright_cyan; Pixel white; XFontStruct *font; XtCallbackList expose_callback; XtCallbackList input_callback; XtCallbackList resize_callback; /* private state */ /* (none) */ } WindowPart; typedef struct _WindowRec { CorePart core; WindowPart window; } WindowRec; #endif /* _xwindowp_h */ nethack-3.6.0/include/you.h0000664000076400007660000003717212536476415014574 0ustar paxedpaxed/* NetHack 3.6 you.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.29 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef YOU_H #define YOU_H #include "attrib.h" #include "monst.h" #ifndef PROP_H #include "prop.h" /* (needed here for util/makedefs.c) */ #endif #include "skills.h" /*** Substructures ***/ struct RoleName { const char *m; /* name when character is male */ const char *f; /* when female; null if same as male */ }; struct RoleAdvance { /* "fix" is the fixed amount, "rnd" is the random amount */ xchar infix, inrnd; /* at character initialization */ xchar lofix, lornd; /* gained per level < urole.xlev */ xchar hifix, hirnd; /* gained per level >= urole.xlev */ }; struct u_have { Bitfield(amulet, 1); /* carrying Amulet */ Bitfield(bell, 1); /* carrying Bell */ Bitfield(book, 1); /* carrying Book */ Bitfield(menorah, 1); /* carrying Candelabrum */ Bitfield(questart, 1); /* carrying the Quest Artifact */ Bitfield(unused, 3); }; struct u_event { Bitfield(minor_oracle, 1); /* received at least 1 cheap oracle */ Bitfield(major_oracle, 1); /* " expensive oracle */ Bitfield(read_tribute, 1); /* read a passage from a novel */ Bitfield(qcalled, 1); /* called by Quest leader to do task */ Bitfield(qexpelled, 1); /* expelled from the Quest dungeon */ Bitfield(qcompleted, 1); /* successfully completed Quest task */ Bitfield(uheard_tune, 2); /* 1=know about, 2=heard passtune */ Bitfield(uopened_dbridge, 1); /* opened the drawbridge */ Bitfield(invoked, 1); /* invoked Gate to the Sanctum level */ Bitfield(gehennom_entered, 1); /* entered Gehennom via Valley */ Bitfield(uhand_of_elbereth, 2); /* became Hand of Elbereth */ Bitfield(udemigod, 1); /* killed the wiz */ Bitfield(uvibrated, 1); /* stepped on "vibrating square" */ Bitfield(ascended, 1); /* has offered the Amulet */ }; struct u_achieve { Bitfield(amulet, 1); /* touched Amulet */ Bitfield(bell, 1); /* touched Bell */ Bitfield(book, 1); /* touched Book */ Bitfield(menorah, 1); /* touched Candelabrum */ Bitfield(enter_gehennom, 1); /* entered Gehennom (or Valley) by any means */ Bitfield(ascended, 1); /* not quite the same as u.uevent.ascended */ Bitfield(mines_luckstone, 1); /* got a luckstone at end of mines */ Bitfield(finish_sokoban, 1); /* obtained the sokoban prize */ Bitfield(killed_medusa, 1); }; struct u_realtime { long realtime; /* actual playing time up until the last restore, seconds */ time_t restored; /* time the game was started or restored */ time_t endtime; }; /* KMH, conduct -- * These are voluntary challenges. Each field denotes the number of * times a challenge has been violated. */ struct u_conduct { /* number of times... */ long unvegetarian; /* eaten any animal */ long unvegan; /* ... or any animal byproduct */ long food; /* ... or any comestible */ long gnostic; /* used prayer, priest, or altar */ long weaphit; /* hit a monster with a weapon */ long killer; /* killed a monster yourself */ long literate; /* read something (other than BotD) */ long polypiles; /* polymorphed an object */ long polyselfs; /* transformed yourself */ long wishes; /* used a wish */ long wisharti; /* wished for an artifact */ /* genocides already listed at end of game */ }; struct u_roleplay { boolean blind; /* permanently blind */ boolean nudist; /* has not worn any armor, ever */ long numbones; /* # of bones files loaded */ }; /*** Unified structure containing role information ***/ struct Role { /*** Strings that name various things ***/ struct RoleName name; /* the role's name (from u_init.c) */ struct RoleName rank[9]; /* names for experience levels (from botl.c) */ const char *lgod, *ngod, *cgod; /* god names (from pray.c) */ const char *filecode; /* abbreviation for use in file names */ const char *homebase; /* quest leader's location (from questpgr.c) */ const char *intermed; /* quest intermediate goal (from questpgr.c) */ /*** Indices of important monsters and objects ***/ short malenum, /* index (PM_) as a male (botl.c) */ femalenum, /* ...or as a female (NON_PM == same) */ petnum, /* PM_ of preferred pet (NON_PM == random) */ ldrnum, /* PM_ of quest leader (questpgr.c) */ guardnum, /* PM_ of quest guardians (questpgr.c) */ neminum, /* PM_ of quest nemesis (questpgr.c) */ enemy1num, /* specific quest enemies (NON_PM == random) */ enemy2num; char enemy1sym, /* quest enemies by class (S_) */ enemy2sym; short questarti; /* index (ART_) of quest artifact (questpgr.c) */ /*** Bitmasks ***/ short allow; /* bit mask of allowed variations */ #define ROLE_RACEMASK 0x0ff8 /* allowable races */ #define ROLE_GENDMASK 0xf000 /* allowable genders */ #define ROLE_MALE 0x1000 #define ROLE_FEMALE 0x2000 #define ROLE_NEUTER 0x4000 #define ROLE_ALIGNMASK AM_MASK /* allowable alignments */ #define ROLE_LAWFUL AM_LAWFUL #define ROLE_NEUTRAL AM_NEUTRAL #define ROLE_CHAOTIC AM_CHAOTIC /*** Attributes (from attrib.c and exper.c) ***/ xchar attrbase[A_MAX]; /* lowest initial attributes */ xchar attrdist[A_MAX]; /* distribution of initial attributes */ struct RoleAdvance hpadv; /* hit point advancement */ struct RoleAdvance enadv; /* energy advancement */ xchar xlev; /* cutoff experience level */ xchar initrecord; /* initial alignment record */ /*** Spell statistics (from spell.c) ***/ int spelbase; /* base spellcasting penalty */ int spelheal; /* penalty (-bonus) for healing spells */ int spelshld; /* penalty for wearing any shield */ int spelarmr; /* penalty for wearing metal armour */ int spelstat; /* which stat (A_) is used */ int spelspec; /* spell (SPE_) the class excels at */ int spelsbon; /* penalty (-bonus) for that spell */ /*** Properties in variable-length arrays ***/ /* intrinsics (see attrib.c) */ /* initial inventory (see u_init.c) */ /* skills (see u_init.c) */ /*** Don't forget to add... ***/ /* quest leader, guardians, nemesis (monst.c) */ /* quest artifact (artilist.h) */ /* quest dungeon definition (dat/Xyz.dat) */ /* quest text (dat/quest.txt) */ /* dictionary entries (dat/data.bas) */ }; extern const struct Role roles[]; /* table of available roles */ extern struct Role urole; #define Role_if(X) (urole.malenum == (X)) #define Role_switch (urole.malenum) /* used during initialization for race, gender, and alignment as well as for character class */ #define ROLE_NONE (-1) #define ROLE_RANDOM (-2) /*** Unified structure specifying race information ***/ struct Race { /*** Strings that name various things ***/ const char *noun; /* noun ("human", "elf") */ const char *adj; /* adjective ("human", "elven") */ const char *coll; /* collective ("humanity", "elvenkind") */ const char *filecode; /* code for filenames */ struct RoleName individual; /* individual as a noun ("man", "elf") */ /*** Indices of important monsters and objects ***/ short malenum, /* PM_ as a male monster */ femalenum, /* ...or as a female (NON_PM == same) */ mummynum, /* PM_ as a mummy */ zombienum; /* PM_ as a zombie */ /*** Bitmasks ***/ short allow; /* bit mask of allowed variations */ short selfmask, /* your own race's bit mask */ lovemask, /* bit mask of always peaceful */ hatemask; /* bit mask of always hostile */ /*** Attributes ***/ xchar attrmin[A_MAX]; /* minimum allowable attribute */ xchar attrmax[A_MAX]; /* maximum allowable attribute */ struct RoleAdvance hpadv; /* hit point advancement */ struct RoleAdvance enadv; /* energy advancement */ #if 0 /* DEFERRED */ int nv_range; /* night vision range */ int xray_range; /* X-ray vision range */ #endif /*** Properties in variable-length arrays ***/ /* intrinsics (see attrib.c) */ /*** Don't forget to add... ***/ /* quest leader, guardians, nemesis (monst.c) */ /* quest dungeon definition (dat/Xyz.dat) */ /* quest text (dat/quest.txt) */ /* dictionary entries (dat/data.bas) */ }; extern const struct Race races[]; /* Table of available races */ extern struct Race urace; #define Race_if(X) (urace.malenum == (X)) #define Race_switch (urace.malenum) /*** Unified structure specifying gender information ***/ struct Gender { const char *adj; /* male/female/neuter */ const char *he; /* he/she/it */ const char *him; /* him/her/it */ const char *his; /* his/her/its */ const char *filecode; /* file code */ short allow; /* equivalent ROLE_ mask */ }; #define ROLE_GENDERS 2 /* number of permitted player genders */ /* increment to 3 if you allow neuter roles */ extern const struct Gender genders[]; /* table of available genders */ #define uhe() (genders[flags.female ? 1 : 0].he) #define uhim() (genders[flags.female ? 1 : 0].him) #define uhis() (genders[flags.female ? 1 : 0].his) #define mhe(mtmp) (genders[pronoun_gender(mtmp)].he) #define mhim(mtmp) (genders[pronoun_gender(mtmp)].him) #define mhis(mtmp) (genders[pronoun_gender(mtmp)].his) /*** Unified structure specifying alignment information ***/ struct Align { const char *noun; /* law/balance/chaos */ const char *adj; /* lawful/neutral/chaotic */ const char *filecode; /* file code */ short allow; /* equivalent ROLE_ mask */ aligntyp value; /* equivalent A_ value */ }; #define ROLE_ALIGNS 3 /* number of permitted player alignments */ extern const struct Align aligns[]; /* table of available alignments */ /*** Information about the player ***/ struct you { xchar ux, uy; schar dx, dy, dz; /* direction of move (or zap or ... ) */ schar di; /* direction of FF */ xchar tx, ty; /* destination of travel */ xchar ux0, uy0; /* initial position FF */ d_level uz, uz0; /* your level on this and the previous turn */ d_level utolev; /* level monster teleported you to, or uz */ uchar utotype; /* bitmask of goto_level() flags for utolev */ boolean umoved; /* changed map location (post-move) */ int last_str_turn; /* 0: none, 1: half turn, 2: full turn */ /* +: turn right, -: turn left */ int ulevel; /* 1 to MAXULEV */ int ulevelmax; unsigned utrap; /* trap timeout */ unsigned utraptype; /* defined if utrap nonzero */ #define TT_BEARTRAP 0 #define TT_PIT 1 #define TT_WEB 2 #define TT_LAVA 3 #define TT_INFLOOR 4 #define TT_BURIEDBALL 5 char urooms[5]; /* rooms (roomno + 3) occupied now */ char urooms0[5]; /* ditto, for previous position */ char uentered[5]; /* rooms (roomno + 3) entered this turn */ char ushops[5]; /* shop rooms (roomno + 3) occupied now */ char ushops0[5]; /* ditto, for previous position */ char ushops_entered[5]; /* ditto, shops entered this turn */ char ushops_left[5]; /* ditto, shops exited this turn */ int uhunger; /* refd only in eat.c and shk.c */ unsigned uhs; /* hunger state - see eat.c */ struct prop uprops[LAST_PROP + 1]; unsigned umconf; Bitfield(usick_type, 2); #define SICK_VOMITABLE 0x01 #define SICK_NONVOMITABLE 0x02 #define SICK_ALL 0x03 /* These ranges can never be more than MAX_RANGE (vision.h). */ int nv_range; /* current night vision range */ int xray_range; /* current xray vision range */ /* * These variables are valid globally only when punished and blind. */ #define BC_BALL 0x01 /* bit mask for ball in 'bc_felt' below */ #define BC_CHAIN 0x02 /* bit mask for chain in 'bc_felt' below */ int bglyph; /* glyph under the ball */ int cglyph; /* glyph under the chain */ int bc_order; /* ball & chain order [see bc_order() in ball.c] */ int bc_felt; /* mask for ball/chain being felt */ int umonster; /* hero's "real" monster num */ int umonnum; /* current monster number */ int mh, mhmax, mtimedone; /* for polymorph-self */ struct attribs macurr, /* for monster attribs */ mamax; /* for monster attribs */ int ulycn; /* lycanthrope type */ unsigned ucreamed; unsigned uswldtim; /* time you have been swallowed */ Bitfield(uswallow, 1); /* true if swallowed */ Bitfield(uinwater, 1); /* if you're currently in water (only underwater possible currently) */ Bitfield(uundetected, 1); /* if you're a hiding monster/piercer */ Bitfield(mfemale, 1); /* saved human value of flags.female */ Bitfield(uinvulnerable, 1); /* you're invulnerable (praying) */ Bitfield(uburied, 1); /* you're buried */ Bitfield(uedibility, 1); /* blessed food detection; sense unsafe food */ /* 1 free bit! */ unsigned udg_cnt; /* how long you have been demigod */ struct u_achieve uachieve; /* achievements */ struct u_event uevent; /* certain events have happened */ struct u_have uhave; /* you're carrying special objects */ struct u_conduct uconduct; /* KMH, conduct */ struct u_roleplay uroleplay; struct attribs acurr, /* your current attributes (eg. str)*/ aexe, /* for gain/loss via "exercise" */ abon, /* your bonus attributes (eg. str) */ amax, /* your max attributes (eg. str) */ atemp, /* used for temporary loss/gain */ atime; /* used for loss/gain countdown */ align ualign; /* character alignment */ #define CONVERT 2 #define A_ORIGINAL 1 #define A_CURRENT 0 aligntyp ualignbase[CONVERT]; /* for ualign conversion record */ schar uluck, moreluck; /* luck and luck bonus */ #define Luck (u.uluck + u.moreluck) #define LUCKADD 3 /* added value when carrying luck stone */ #define LUCKMAX 10 #define LUCKMIN (-10) schar uhitinc; schar udaminc; schar uac; uchar uspellprot; /* protection by SPE_PROTECTION */ uchar usptime; /* #moves until uspellprot-- */ uchar uspmtime; /* #moves between uspellprot-- */ int uhp, uhpmax; int uen, uenmax; /* magical energy - M. Stephenson */ xchar uhpinc[MAXULEV], ueninc[MAXULEV]; /* increases from level gain */ int ugangr; /* if the gods are angry at you */ int ugifts; /* number of artifacts bestowed */ int ublessed, ublesscnt; /* blessing/duration from #pray */ long umoney0; long uspare1; long uexp, urexp; long ucleansed; /* to record moves when player was cleansed */ long usleep; /* sleeping; monstermove you last started */ int uinvault; struct monst *ustuck; struct monst *usteed; long ugallop; int urideturns; int umortality; /* how many times you died */ int ugrave_arise; /* you die and become something aside from a ghost */ int weapon_slots; /* unused skill slots */ int skills_advanced; /* # of advances made so far */ xchar skill_record[P_SKILL_LIMIT]; /* skill advancements */ struct skills weapon_skills[P_NUM_SKILLS]; boolean twoweap; /* KMH -- Using two-weapon combat */ }; /* end of `struct you' */ #define Upolyd (u.umonnum != u.umonster) #endif /* YOU_H */ nethack-3.6.0/include/youprop.h0000664000076400007660000003603012610522241015443 0ustar paxedpaxed/* NetHack 3.6 youprop.h $NHDT-Date: 1433291407 2015/06/03 00:30:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.23 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef YOUPROP_H #define YOUPROP_H #include "prop.h" #include "permonst.h" #include "mondata.h" #include "pm.h" /* KMH, intrinsics patch. * Reorganized and rewritten for >32-bit properties. * HXxx refers to intrinsic bitfields while in human form. * EXxx refers to extrinsic bitfields from worn objects. * BXxx refers to the cause of the property being blocked. * Xxx refers to any source, including polymorph forms. * [Post-3.4.3: HXxx now includes a FROMFORM bit to handle * intrinsic conferred by being polymorphed.] */ #define maybe_polyd(if_so, if_not) (Upolyd ? (if_so) : (if_not)) /*** Resistances to troubles ***/ /* With intrinsics and extrinsics */ #define HFire_resistance u.uprops[FIRE_RES].intrinsic #define EFire_resistance u.uprops[FIRE_RES].extrinsic #define Fire_resistance (HFire_resistance || EFire_resistance) #define HCold_resistance u.uprops[COLD_RES].intrinsic #define ECold_resistance u.uprops[COLD_RES].extrinsic #define Cold_resistance (HCold_resistance || ECold_resistance) #define HSleep_resistance u.uprops[SLEEP_RES].intrinsic #define ESleep_resistance u.uprops[SLEEP_RES].extrinsic #define Sleep_resistance (HSleep_resistance || ESleep_resistance) #define HDisint_resistance u.uprops[DISINT_RES].intrinsic #define EDisint_resistance u.uprops[DISINT_RES].extrinsic #define Disint_resistance (HDisint_resistance || EDisint_resistance) #define HShock_resistance u.uprops[SHOCK_RES].intrinsic #define EShock_resistance u.uprops[SHOCK_RES].extrinsic #define Shock_resistance (HShock_resistance || EShock_resistance) #define HPoison_resistance u.uprops[POISON_RES].intrinsic #define EPoison_resistance u.uprops[POISON_RES].extrinsic #define Poison_resistance (HPoison_resistance || EPoison_resistance) #define HDrain_resistance u.uprops[DRAIN_RES].intrinsic #define EDrain_resistance u.uprops[DRAIN_RES].extrinsic #define Drain_resistance (HDrain_resistance || EDrain_resistance) /* Hxxx due to FROMFORM only */ #define HAntimagic u.uprops[ANTIMAGIC].intrinsic #define EAntimagic u.uprops[ANTIMAGIC].extrinsic #define Antimagic (HAntimagic || EAntimagic) #define HAcid_resistance u.uprops[ACID_RES].intrinsic #define EAcid_resistance u.uprops[ACID_RES].extrinsic #define Acid_resistance (HAcid_resistance || EAcid_resistance) #define HStone_resistance u.uprops[STONE_RES].intrinsic #define EStone_resistance u.uprops[STONE_RES].extrinsic #define Stone_resistance (HStone_resistance || EStone_resistance) /* Intrinsics only */ #define HSick_resistance u.uprops[SICK_RES].intrinsic #define Sick_resistance (HSick_resistance || defends(AD_DISE, uwep)) #define Invulnerable u.uprops[INVULNERABLE].intrinsic /* [Tom] */ /*** Troubles ***/ /* Pseudo-property */ #define Punished (uball != 0) /* Those implemented solely as timeouts (we use just intrinsic) */ #define HStun u.uprops[STUNNED].intrinsic #define Stunned HStun #define HConfusion u.uprops[CONFUSION].intrinsic #define Confusion HConfusion #define Blinded u.uprops[BLINDED].intrinsic #define Blindfolded (ublindf && ublindf->otyp != LENSES) /* ...means blind because of a cover */ #define Blind \ ((u.uroleplay.blind || Blinded || Blindfolded \ || !haseyes(youmonst.data)) \ && !(ublindf && ublindf->oartifact == ART_EYES_OF_THE_OVERWORLD)) /* ...the Eyes operate even when you really are blind or don't have any eyes */ #define Blindfolded_only \ (Blindfolded && ublindf->oartifact != ART_EYES_OF_THE_OVERWORLD \ && !u.uroleplay.blind && !Blinded && haseyes(youmonst.data)) /* ...blind because of a blindfold, and *only* that */ #define Sick u.uprops[SICK].intrinsic #define Stoned u.uprops[STONED].intrinsic #define Strangled u.uprops[STRANGLED].intrinsic #define Vomiting u.uprops[VOMITING].intrinsic #define Glib u.uprops[GLIB].intrinsic #define Slimed u.uprops[SLIMED].intrinsic /* [Tom] */ /* Hallucination is solely a timeout */ #define HHallucination u.uprops[HALLUC].intrinsic #define HHalluc_resistance u.uprops[HALLUC_RES].intrinsic #define EHalluc_resistance u.uprops[HALLUC_RES].extrinsic #define Halluc_resistance (HHalluc_resistance || EHalluc_resistance) #define Hallucination (HHallucination && !Halluc_resistance) /* Timeout, plus a worn mask */ #define HDeaf u.uprops[DEAF].intrinsic #define EDeaf u.uprops[DEAF].extrinsic #define Deaf (HDeaf || EDeaf) #define HFumbling u.uprops[FUMBLING].intrinsic #define EFumbling u.uprops[FUMBLING].extrinsic #define Fumbling (HFumbling || EFumbling) #define HWounded_legs u.uprops[WOUNDED_LEGS].intrinsic #define EWounded_legs u.uprops[WOUNDED_LEGS].extrinsic #define Wounded_legs (HWounded_legs || EWounded_legs) #define HSleepy u.uprops[SLEEPY].intrinsic #define ESleepy u.uprops[SLEEPY].extrinsic #define Sleepy (HSleepy || ESleepy) #define HHunger u.uprops[HUNGER].intrinsic #define EHunger u.uprops[HUNGER].extrinsic #define Hunger (HHunger || EHunger) /*** Vision and senses ***/ #define HSee_invisible u.uprops[SEE_INVIS].intrinsic #define ESee_invisible u.uprops[SEE_INVIS].extrinsic #define See_invisible (HSee_invisible || ESee_invisible) #define HTelepat u.uprops[TELEPAT].intrinsic #define ETelepat u.uprops[TELEPAT].extrinsic #define Blind_telepat (HTelepat || ETelepat) #define Unblind_telepat (ETelepat) #define HWarning u.uprops[WARNING].intrinsic #define EWarning u.uprops[WARNING].extrinsic #define Warning (HWarning || EWarning) /* Warning for a specific type of monster */ #define HWarn_of_mon u.uprops[WARN_OF_MON].intrinsic #define EWarn_of_mon u.uprops[WARN_OF_MON].extrinsic #define Warn_of_mon (HWarn_of_mon || EWarn_of_mon) #define HUndead_warning u.uprops[WARN_UNDEAD].intrinsic #define Undead_warning (HUndead_warning) #define HSearching u.uprops[SEARCHING].intrinsic #define ESearching u.uprops[SEARCHING].extrinsic #define Searching (HSearching || ESearching) #define HClairvoyant u.uprops[CLAIRVOYANT].intrinsic #define EClairvoyant u.uprops[CLAIRVOYANT].extrinsic #define BClairvoyant u.uprops[CLAIRVOYANT].blocked #define Clairvoyant ((HClairvoyant || EClairvoyant) && !BClairvoyant) #define HInfravision u.uprops[INFRAVISION].intrinsic #define EInfravision u.uprops[INFRAVISION].extrinsic #define Infravision (HInfravision || EInfravision) #define HDetect_monsters u.uprops[DETECT_MONSTERS].intrinsic #define EDetect_monsters u.uprops[DETECT_MONSTERS].extrinsic #define Detect_monsters (HDetect_monsters || EDetect_monsters) /*** Appearance and behavior ***/ #define Adornment u.uprops[ADORNED].extrinsic #define HInvis u.uprops[INVIS].intrinsic #define EInvis u.uprops[INVIS].extrinsic #define BInvis u.uprops[INVIS].blocked #define Invis ((HInvis || EInvis) && !BInvis) #define Invisible (Invis && !See_invisible) /* Note: invisibility also hides inventory and steed */ #define EDisplaced u.uprops[DISPLACED].extrinsic #define Displaced EDisplaced #define HStealth u.uprops[STEALTH].intrinsic #define EStealth u.uprops[STEALTH].extrinsic #define BStealth u.uprops[STEALTH].blocked #define Stealth ((HStealth || EStealth) && !BStealth) #define HAggravate_monster u.uprops[AGGRAVATE_MONSTER].intrinsic #define EAggravate_monster u.uprops[AGGRAVATE_MONSTER].extrinsic #define Aggravate_monster (HAggravate_monster || EAggravate_monster) #define HConflict u.uprops[CONFLICT].intrinsic #define EConflict u.uprops[CONFLICT].extrinsic #define Conflict (HConflict || EConflict) /*** Transportation ***/ #define HJumping u.uprops[JUMPING].intrinsic #define EJumping u.uprops[JUMPING].extrinsic #define Jumping (HJumping || EJumping) #define HTeleportation u.uprops[TELEPORT].intrinsic #define ETeleportation u.uprops[TELEPORT].extrinsic #define Teleportation (HTeleportation || ETeleportation) #define HTeleport_control u.uprops[TELEPORT_CONTROL].intrinsic #define ETeleport_control u.uprops[TELEPORT_CONTROL].extrinsic #define Teleport_control (HTeleport_control || ETeleport_control) #define HLevitation u.uprops[LEVITATION].intrinsic #define ELevitation u.uprops[LEVITATION].extrinsic #define BLevitation u.uprops[LEVITATION].blocked #define Levitation ((HLevitation || ELevitation) && !BLevitation) /* Can't touch surface, can't go under water; overrides all others */ #define Lev_at_will \ (((HLevitation & I_SPECIAL) != 0L || (ELevitation & W_ARTI) != 0L) \ && (HLevitation & ~(I_SPECIAL | TIMEOUT)) == 0L \ && (ELevitation & ~W_ARTI) == 0L) #define HFlying u.uprops[FLYING].intrinsic #define EFlying u.uprops[FLYING].extrinsic #define BFlying u.uprops[FLYING].blocked #define Flying \ ((HFlying || EFlying || (u.usteed && is_flyer(u.usteed->data))) \ && !BFlying) /* May touch surface; does not override any others */ #define Wwalking (u.uprops[WWALKING].extrinsic && !Is_waterlevel(&u.uz)) /* Don't get wet, can't go under water; overrides others except levitation */ /* Wwalking is meaningless on water level */ #define HSwimming u.uprops[SWIMMING].intrinsic #define ESwimming u.uprops[SWIMMING].extrinsic /* [Tom] */ #define Swimming \ (HSwimming || ESwimming || (u.usteed && is_swimmer(u.usteed->data))) /* Get wet, don't go under water unless if amphibious */ #define HMagical_breathing u.uprops[MAGICAL_BREATHING].intrinsic #define EMagical_breathing u.uprops[MAGICAL_BREATHING].extrinsic #define Amphibious \ (HMagical_breathing || EMagical_breathing || amphibious(youmonst.data)) /* Get wet, may go under surface */ #define Breathless \ (HMagical_breathing || EMagical_breathing || breathless(youmonst.data)) #define Underwater (u.uinwater) /* Note that Underwater and u.uinwater are both used in code. The latter form is for later implementation of other in-water states, like swimming, wading, etc. */ #define HPasses_walls u.uprops[PASSES_WALLS].intrinsic #define EPasses_walls u.uprops[PASSES_WALLS].extrinsic #define Passes_walls (HPasses_walls || EPasses_walls) /*** Physical attributes ***/ #define HSlow_digestion u.uprops[SLOW_DIGESTION].intrinsic #define ESlow_digestion u.uprops[SLOW_DIGESTION].extrinsic #define Slow_digestion (HSlow_digestion || ESlow_digestion) /* KMH */ #define HHalf_spell_damage u.uprops[HALF_SPDAM].intrinsic #define EHalf_spell_damage u.uprops[HALF_SPDAM].extrinsic #define Half_spell_damage (HHalf_spell_damage || EHalf_spell_damage) /* * Physical damage * * Damage is NOT physical damage if (in order of priority): * 1. it already qualifies for some other special category * for which a special resistance already exists in the game * including: cold, fire, shock, acid, and magic. * Note that fire is extended to include all non-acid forms of * burning, even boiling water since that is already dealt with * by fire resistance, and in most or all cases is caused by fire. * 2. it doesn't leave a mark. Marks include destruction of, or * damage to, an internal organ (including the brain), * lacerations, bruises, crushed body parts, bleeding. * * The following were evaluated and determined _NOT_ to be * susceptible to Half_physical_damage protection: * Being caught in a fireball [fire damage] * Sitting in lava [lava damage] * Thrown potion (acid) [acid damage] * Splattered burning oil from thrown potion [fire damage] * Mixing water and acid [acid damage] * Molten lava (entering or being splashed) [lava damage] * boiling water from a sink [fire damage] * Fire traps [fire damage] * Scrolls of fire (confused and otherwise) [fire damage] * Alchemical explosion [not physical] * System shock [shock damage] * Bag of holding explosion [magical] * Being undead-turned by your god [magical] * Level-drain [magical] * Magical explosion of a magic trap [magical] * Sitting on a throne with a bad effect [magical] * Contaminated water from a sink [poison/sickness] * Contact-poisoned spellbooks [poison/sickness] * Eating acidic/poisonous/mildly-old corpses [poison/sickness] * Eating a poisoned weapon while polyselfed [poison/sickness] * Engulfing a zombie or mummy (AT_ENGL in hmonas) [poison/sickness] * Quaffed potions of sickness, lit oil, acid [poison/sickness] * Pyrolisks' fiery gaze [fire damage] * Any passive attack [most don't qualify] */ #define HHalf_physical_damage u.uprops[HALF_PHDAM].intrinsic #define EHalf_physical_damage u.uprops[HALF_PHDAM].extrinsic #define Half_physical_damage (HHalf_physical_damage || EHalf_physical_damage) #define HRegeneration u.uprops[REGENERATION].intrinsic #define ERegeneration u.uprops[REGENERATION].extrinsic #define Regeneration (HRegeneration || ERegeneration) #define HEnergy_regeneration u.uprops[ENERGY_REGENERATION].intrinsic #define EEnergy_regeneration u.uprops[ENERGY_REGENERATION].extrinsic #define Energy_regeneration (HEnergy_regeneration || EEnergy_regeneration) #define HProtection u.uprops[PROTECTION].intrinsic #define EProtection u.uprops[PROTECTION].extrinsic #define Protection (HProtection || EProtection) #define HProtection_from_shape_changers \ u.uprops[PROT_FROM_SHAPE_CHANGERS].intrinsic #define EProtection_from_shape_changers \ u.uprops[PROT_FROM_SHAPE_CHANGERS].extrinsic #define Protection_from_shape_changers \ (HProtection_from_shape_changers || EProtection_from_shape_changers) #define HPolymorph u.uprops[POLYMORPH].intrinsic #define EPolymorph u.uprops[POLYMORPH].extrinsic #define Polymorph (HPolymorph || EPolymorph) #define HPolymorph_control u.uprops[POLYMORPH_CONTROL].intrinsic #define EPolymorph_control u.uprops[POLYMORPH_CONTROL].extrinsic #define Polymorph_control (HPolymorph_control || EPolymorph_control) #define HUnchanging u.uprops[UNCHANGING].intrinsic #define EUnchanging u.uprops[UNCHANGING].extrinsic #define Unchanging (HUnchanging || EUnchanging) /* KMH */ #define HFast u.uprops[FAST].intrinsic #define EFast u.uprops[FAST].extrinsic #define Fast (HFast || EFast) #define Very_fast ((HFast & ~INTRINSIC) || EFast) #define HReflecting u.uprops[REFLECTING].intrinsic #define EReflecting u.uprops[REFLECTING].extrinsic #define Reflecting (HReflecting || EReflecting) #define Free_action u.uprops[FREE_ACTION].extrinsic /* [Tom] */ #define Fixed_abil u.uprops[FIXED_ABIL].extrinsic /* KMH */ #define Lifesaved u.uprops[LIFESAVED].extrinsic /* * Some pseudo-properties. */ /* unconscious() includes u.usleep but not is_fainted(); the multi test is redundant but allows the function calls to be skipped most of the time */ #define Unaware (multi < 0 && (unconscious() || is_fainted())) #define Hate_silver (u.ulycn >= LOW_PM || hates_silver(youmonst.data)) #endif /* YOUPROP_H */ nethack-3.6.0/src/allmain.c0000664000076400007660000005704612617615230014524 0ustar paxedpaxed/* NetHack 3.6 allmain.c $NHDT-Date: 1446975459 2015/11/08 09:37:39 $ $NHDT-Branch: master $:$NHDT-Revision: 1.66 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* various code that was replicated in *main.c */ #include "hack.h" #ifndef NO_SIGNAL #include #endif #ifdef POSITIONBAR STATIC_DCL void NDECL(do_positionbar); #endif void moveloop(resuming) boolean resuming; { #if defined(MICRO) || defined(WIN32) char ch; int abort_lev; #endif int moveamt = 0, wtcap = 0, change = 0; boolean monscanmove = FALSE; /* Note: these initializers don't do anything except guarantee that we're linked properly. */ decl_init(); monst_init(); monstr_init(); /* monster strengths */ objects_init(); if (wizard) add_debug_extended_commands(); /* if a save file created in normal mode is now being restored in explore mode, treat it as normal restore followed by 'X' command to use up the save file and require confirmation for explore mode */ if (resuming && iflags.deferred_X) (void) enter_explore_mode(); /* side-effects from the real world */ flags.moonphase = phase_of_the_moon(); if (flags.moonphase == FULL_MOON) { You("are lucky! Full moon tonight."); change_luck(1); } else if (flags.moonphase == NEW_MOON) { pline("Be careful! New moon tonight."); } flags.friday13 = friday_13th(); if (flags.friday13) { pline("Watch out! Bad things can happen on Friday the 13th."); change_luck(-1); } if (!resuming) { /* new game */ context.rndencode = rnd(9000); set_wear((struct obj *) 0); /* for side-effects of starting gear */ (void) pickup(1); /* autopickup at initial location */ } else { /* restore old game */ #ifndef WIN32 update_inventory(); /* for perm_invent */ #endif read_engr_at(u.ux, u.uy); /* subset of pickup() */ } #ifdef WIN32 update_inventory(); /* for perm_invent */ #endif (void) encumber_msg(); /* in case they auto-picked up something */ if (defer_see_monsters) { defer_see_monsters = FALSE; see_monsters(); } initrack(); u.uz0.dlevel = u.uz.dlevel; youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */ context.move = 0; program_state.in_moveloop = 1; for (;;) { #ifdef SAFERHANGUP if (program_state.done_hup) end_of_input(); #endif get_nh_event(); #ifdef POSITIONBAR do_positionbar(); #endif if (context.move) { /* actual time passed */ youmonst.movement -= NORMAL_SPEED; do { /* hero can't move this turn loop */ wtcap = encumber_msg(); context.mon_moving = TRUE; do { monscanmove = movemon(); if (youmonst.movement >= NORMAL_SPEED) break; /* it's now your turn */ } while (monscanmove); context.mon_moving = FALSE; if (!monscanmove && youmonst.movement < NORMAL_SPEED) { /* both you and the monsters are out of steam this round */ /* set up for a new turn */ struct monst *mtmp; mcalcdistress(); /* adjust monsters' trap, blind, etc */ /* reallocate movement rations to monsters */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) mtmp->movement += mcalcmove(mtmp); if (!rn2(u.uevent.udemigod ? 25 : (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70)) (void) makemon((struct permonst *) 0, 0, 0, NO_MM_FLAGS); /* calculate how much time passed. */ if (u.usteed && u.umoved) { /* your speed doesn't augment steed's speed */ moveamt = mcalcmove(u.usteed); } else { moveamt = youmonst.data->mmove; if (Very_fast) { /* speed boots or potion */ /* average movement is 1.67 times normal */ moveamt += NORMAL_SPEED / 2; if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2; } else if (Fast) { /* average movement is 1.33 times normal */ if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2; } } switch (wtcap) { case UNENCUMBERED: break; case SLT_ENCUMBER: moveamt -= (moveamt / 4); break; case MOD_ENCUMBER: moveamt -= (moveamt / 2); break; case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break; case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break; default: break; } youmonst.movement += moveamt; if (youmonst.movement < 0) youmonst.movement = 0; settrack(); monstermoves++; moves++; /********************************/ /* once-per-turn things go here */ /********************************/ if (Glib) glibr(); nh_timeout(); run_regions(); if (u.ublesscnt) u.ublesscnt--; if (flags.time && !context.run) context.botl = 1; /* One possible result of prayer is healing. Whether or * not you get healed depends on your current hit points. * If you are allowed to regenerate during the prayer, the * end-of-prayer calculation messes up on this. * Another possible result is rehumanization, which * requires * that encumbrance and movement rate be recalculated. */ if (u.uinvulnerable) { /* for the moment at least, you're in tiptop shape */ wtcap = UNENCUMBERED; } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz)) { /* eel out of water loses hp, same as for monsters; as hp gets lower, rate of further loss slows down */ if (u.mh > 1 && rn2(u.mh) > rn2(8) && (!Half_physical_damage || !(moves % 2L))) { u.mh--; context.botl = 1; } else if (u.mh < 1) rehumanize(); } else if (Upolyd && u.mh < u.mhmax) { if (u.mh < 1) rehumanize(); else if (Regeneration || (wtcap < MOD_ENCUMBER && !(moves % 20))) { context.botl = 1; u.mh++; } } else if (u.uhp < u.uhpmax && (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) { if (u.ulevel > 9 && !(moves % 3)) { int heal, Con = (int) ACURR(A_CON); if (Con <= 12) { heal = 1; } else { heal = rnd(Con); if (heal > u.ulevel - 9) heal = u.ulevel - 9; } context.botl = 1; u.uhp += heal; if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; } else if (Regeneration || (u.ulevel <= 9 && !(moves % ((MAXULEV + 12) / (u.ulevel + 2) + 1)))) { context.botl = 1; u.uhp++; } } /* moving around while encumbered is hard work */ if (wtcap > MOD_ENCUMBER && u.umoved) { if (!(wtcap < EXT_ENCUMBER ? moves % 30 : moves % 10)) { if (Upolyd && u.mh > 1) { u.mh--; } else if (!Upolyd && u.uhp > 1) { u.uhp--; } else { You("pass out from exertion!"); exercise(A_CON, FALSE); fall_asleep(-10, FALSE); } } } if ((u.uen < u.uenmax) && ((wtcap < MOD_ENCUMBER && (!(moves % ((MAXULEV + 8 - u.ulevel) * (Role_if(PM_WIZARD) ? 3 : 4) / 6)))) || Energy_regeneration)) { u.uen += rn1( (int) (ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1, 1); if (u.uen > u.uenmax) u.uen = u.uenmax; context.botl = 1; } if (!u.uinvulnerable) { if (Teleportation && !rn2(85)) { xchar old_ux = u.ux, old_uy = u.uy; tele(); if (u.ux != old_ux || u.uy != old_uy) { if (!next_to_u()) { check_leash(old_ux, old_uy); } /* clear doagain keystrokes */ pushch(0); savech(0); } } /* delayed change may not be valid anymore */ if ((change == 1 && !Polymorph) || (change == 2 && u.ulycn == NON_PM)) change = 0; if (Polymorph && !rn2(100)) change = 1; else if (u.ulycn >= LOW_PM && !Upolyd && !rn2(80 - (20 * night()))) change = 2; if (change && !Unchanging) { if (multi >= 0) { if (occupation) stop_occupation(); else nomul(0); if (change == 1) polyself(0); else you_were(); change = 0; } } } if (Searching && multi >= 0) (void) dosearch0(1); dosounds(); do_storms(); gethungry(); age_spells(); exerchk(); invault(); if (u.uhave.amulet) amulet(); if (!rn2(40 + (int) (ACURR(A_DEX) * 3))) u_wipe_engr(rnd(3)); if (u.uevent.udemigod && !u.uinvulnerable) { if (u.udg_cnt) u.udg_cnt--; if (!u.udg_cnt) { intervene(); u.udg_cnt = rn1(200, 50); } } restore_attrib(); /* underwater and waterlevel vision are done here */ if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) movebubbles(); else if (Is_firelevel(&u.uz)) fumaroles(); else if (Underwater) under_water(0); /* vision while buried done here */ else if (u.uburied) under_ground(0); /* when immobile, count is in turns */ if (multi < 0) { if (++multi == 0) { /* finished yet? */ unmul((char *) 0); /* if unmul caused a level change, take it now */ if (u.utotype) deferred_goto(); } } } } while (youmonst.movement < NORMAL_SPEED); /* hero can't move loop */ /******************************************/ /* once-per-hero-took-time things go here */ /******************************************/ if (context.bypasses) clear_bypasses(); if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz) && !BClairvoyant && !(moves % 15) && !rn2(2)) do_vicinity_map(); if (u.utrap && u.utraptype == TT_LAVA) sink_into_lava(); /* when/if hero escapes from lava, he can't just stay there */ else if (!u.umoved) (void) pooleffects(FALSE); } /* actual time passed */ /****************************************/ /* once-per-player-input things go here */ /****************************************/ clear_splitobjs(); find_ac(); if (!context.mv || Blind) { /* redo monsters if hallu or wearing a helm of telepathy */ if (Hallucination) { /* update screen randomly */ see_monsters(); see_objects(); see_traps(); if (u.uswallow) swallowed(0); } else if (Unblind_telepat) { see_monsters(); } else if (Warning || Warn_of_mon) see_monsters(); if (vision_full_recalc) vision_recalc(0); /* vision! */ } if (context.botl || context.botlx) { bot(); curs_on_u(); } context.move = 1; if (multi >= 0 && occupation) { #if defined(MICRO) || defined(WIN32) abort_lev = 0; if (kbhit()) { if ((ch = pgetchar()) == ABORT) abort_lev++; else pushch(ch); } if (!abort_lev && (*occupation)() == 0) #else if ((*occupation)() == 0) #endif occupation = 0; if ( #if defined(MICRO) || defined(WIN32) abort_lev || #endif monster_nearby()) { stop_occupation(); reset_eat(); } #if defined(MICRO) || defined(WIN32) if (!(++occtime % 7)) display_nhwindow(WIN_MAP, FALSE); #endif continue; } if (iflags.sanity_check) sanity_check(); #ifdef CLIPPING /* just before rhack */ cliparound(u.ux, u.uy); #endif u.umoved = FALSE; if (multi > 0) { lookaround(); if (!multi) { /* lookaround may clear multi */ context.move = 0; if (flags.time) context.botl = 1; continue; } if (context.mv) { if (multi < COLNO && !--multi) context.travel = context.travel1 = context.mv = context.run = 0; domove(); } else { --multi; rhack(save_cm); } } else if (multi == 0) { #ifdef MAIL ckmailstatus(); #endif rhack((char *) 0); } if (u.utotype) /* change dungeon level */ deferred_goto(); /* after rhack() */ /* !context.move here: multiple movement command stopped */ else if (flags.time && (!context.move || !context.mv)) context.botl = 1; if (vision_full_recalc) vision_recalc(0); /* vision! */ /* when running in non-tport mode, this gets done through domove() */ if ((!context.run || flags.runmode == RUN_TPORT) && (multi && (!context.travel ? !(multi % 7) : !(moves % 7L)))) { if (flags.time && context.run) context.botl = 1; display_nhwindow(WIN_MAP, FALSE); } } } void stop_occupation() { if (occupation) { if (!maybe_finished_meal(TRUE)) You("stop %s.", occtxt); occupation = 0; context.botl = 1; /* in case u.uhs changed */ nomul(0); pushch(0); } } void display_gamewindows() { WIN_MESSAGE = create_nhwindow(NHW_MESSAGE); #ifdef STATUS_VIA_WINDOWPORT status_initialize(0); #else WIN_STATUS = create_nhwindow(NHW_STATUS); #endif WIN_MAP = create_nhwindow(NHW_MAP); WIN_INVEN = create_nhwindow(NHW_MENU); #ifdef MAC /* This _is_ the right place for this - maybe we will * have to split display_gamewindows into create_gamewindows * and show_gamewindows to get rid of this ifdef... */ if (!strcmp(windowprocs.name, "mac")) SanePositions(); #endif /* * The mac port is not DEPENDENT on the order of these * displays, but it looks a lot better this way... */ #ifndef STATUS_VIA_WINDOWPORT display_nhwindow(WIN_STATUS, FALSE); #endif display_nhwindow(WIN_MESSAGE, FALSE); clear_glyph_buffer(); display_nhwindow(WIN_MAP, FALSE); } void newgame() { int i; #ifdef MFLOPPY gameDiskPrompt(); #endif context.botlx = 1; context.ident = 1; context.stethoscope_move = -1L; context.warnlevel = 1; context.next_attrib_check = 600L; /* arbitrary first setting */ context.tribute.enabled = TRUE; /* turn on 3.6 tributes */ context.tribute.tributesz = sizeof(struct tribute_info); for (i = 0; i < NUMMONS; i++) mvitals[i].mvflags = mons[i].geno & G_NOCORPSE; init_objects(); /* must be before u_init() */ flags.pantheon = -1; /* role_init() will reset this */ role_init(); /* must be before init_dungeons(), u_init(), * and init_artifacts() */ init_dungeons(); /* must be before u_init() to avoid rndmonst() * creating odd monsters for any tins and eggs * in hero's initial inventory */ init_artifacts(); /* before u_init() in case $WIZKIT specifies * any artifacts */ u_init(); #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif #ifdef NEWS if (iflags.news) display_file(NEWS, FALSE); #endif load_qtlist(); /* load up the quest text info */ /* quest_init(); -- Now part of role_init() */ mklev(); u_on_upstairs(); if (wizard) obj_delivery(FALSE); /* finish wizkit */ vision_reset(); /* set up internals for level (after mklev) */ check_special_room(FALSE); if (MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy)); (void) makedog(); docrt(); if (flags.legacy) { flush_screen(1); com_pager(1); } #ifdef INSURANCE save_currentstate(); #endif program_state.something_worth_saving++; /* useful data now exists */ urealtime.realtime = 0L; #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *) &urealtime.restored); #else (void) time(&urealtime.restored); #endif /* Success! */ welcome(TRUE); return; } /* show "welcome [back] to nethack" message at program startup */ void welcome(new_game) boolean new_game; /* false => restoring an old game */ { char buf[BUFSZ]; boolean currentgend = Upolyd ? u.mfemale : flags.female; /* * The "welcome back" message always describes your innate form * even when polymorphed or wearing a helm of opposite alignment. * Alignment is shown unconditionally for new games; for restores * it's only shown if it has changed from its original value. * Sex is shown for new games except when it is redundant; for * restores it's only shown if different from its original value. */ *buf = '\0'; if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT]) Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL])); if (!urole.name.f && (new_game ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE) : currentgend != flags.initgend)) Sprintf(eos(buf), " %s", genders[currentgend].adj); pline(new_game ? "%s %s, welcome to NetHack! You are a%s %s %s." : "%s %s, the%s %s %s, welcome back to NetHack!", Hello((struct monst *) 0), plname, buf, urace.adj, (currentgend && urole.name.f) ? urole.name.f : urole.name.m); } #ifdef POSITIONBAR STATIC_DCL void do_positionbar() { static char pbar[COLNO]; char *p; p = pbar; /* up stairway */ if (upstair.sx && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) == S_upstair || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) == S_upladder)) { *p++ = '<'; *p++ = upstair.sx; } if (sstairs.sx && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_upstair || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_upladder)) { *p++ = '<'; *p++ = sstairs.sx; } /* down stairway */ if (dnstair.sx && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) == S_dnstair || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) == S_dnladder)) { *p++ = '>'; *p++ = dnstair.sx; } if (sstairs.sx && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_dnstair || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_dnladder)) { *p++ = '>'; *p++ = sstairs.sx; } /* hero location */ if (u.ux) { *p++ = '@'; *p++ = u.ux; } /* fence post */ *p = 0; update_positionbar(pbar); } #endif /*allmain.c*/ nethack-3.6.0/src/alloc.c0000664000076400007660000001010212625266740014166 0ustar paxedpaxed/* NetHack 3.6 alloc.c $NHDT-Date: 1446975460 2015/11/08 09:37:40 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* to get the malloc() prototype from system.h */ #define ALLOC_C /* comment line for pre-compiled headers */ /* since this file is also used in auxiliary programs, don't include all the * function declarations for all of nethack */ #define EXTERN_H /* comment line for pre-compiled headers */ #include "config.h" char *FDECL(fmt_ptr, (const genericptr)); #ifdef MONITOR_HEAP #undef alloc #undef free extern void FDECL(free, (genericptr_t)); static void NDECL(heapmon_init); static FILE *heaplog = 0; static boolean tried_heaplog = FALSE; #endif long *FDECL(alloc, (unsigned int)); extern void VDECL(panic, (const char *, ...)) PRINTF_F(1, 2); long * alloc(lth) register unsigned int lth; { #ifdef LINT /* * a ridiculous definition, suppressing * "possible pointer alignment problem" for (long *) malloc() * from lint */ long dummy = ftell(stderr); if (lth) dummy = 0; /* make sure arg is used */ return &dummy; #else register genericptr_t ptr; ptr = malloc(lth); #ifndef MONITOR_HEAP if (!ptr) panic("Memory allocation failure; cannot get %u bytes", lth); #endif return (long *) ptr; #endif } #ifdef HAS_PTR_FMT #define PTR_FMT "%p" #define PTR_TYP genericptr_t #else #define PTR_FMT "%06lx" #define PTR_TYP unsigned long #endif /* A small pool of static formatting buffers. * PTRBUFSIZ: We assume that pointers will be formatted as integers in * hexadecimal, requiring at least 16+1 characters for each buffer to handle * 64-bit systems, but the standard doesn't mandate that encoding and an * implementation could do something different for %p, so we make some * extra room. * PTRBUFCNT: Number of formatted values which can be in use at the same * time. To have more, callers need to make copies of them as they go. */ #define PTRBUFCNT 4 #define PTRBUFSIZ 32 static char ptrbuf[PTRBUFCNT][PTRBUFSIZ]; static int ptrbufidx = 0; /* format a pointer for display purposes; returns a static buffer */ char * fmt_ptr(ptr) const genericptr ptr; { char *buf; buf = ptrbuf[ptrbufidx]; if (++ptrbufidx >= PTRBUFCNT) ptrbufidx = 0; Sprintf(buf, PTR_FMT, (PTR_TYP) ptr); return buf; } #ifdef MONITOR_HEAP /* If ${NH_HEAPLOG} is defined and we can create a file by that name, then we'll log the allocation and release information to that file. */ static void heapmon_init() { char *logname = getenv("NH_HEAPLOG"); if (logname && *logname) heaplog = fopen(logname, "w"); tried_heaplog = TRUE; } long * nhalloc(lth, file, line) unsigned int lth; const char *file; int line; { long *ptr = alloc(lth); if (!tried_heaplog) heapmon_init(); if (heaplog) (void) fprintf(heaplog, "+%5u %s %4d %s\n", lth, fmt_ptr((genericptr_t) ptr), line, file); /* potential panic in alloc() was deferred til here */ if (!ptr) panic("Cannot get %u bytes, line %d of %s", lth, line, file); return ptr; } void nhfree(ptr, file, line) genericptr_t ptr; const char *file; int line; { if (!tried_heaplog) heapmon_init(); if (heaplog) (void) fprintf(heaplog, "- %s %4d %s\n", fmt_ptr((genericptr_t) ptr), line, file); free(ptr); } /* strdup() which uses our alloc() rather than libc's malloc(), with caller tracking */ char * nhdupstr(string, file, line) const char *string; const char *file; int line; { return strcpy((char *) nhalloc(strlen(string) + 1, file, line), string); } #undef dupstr #endif /* MONITOR_HEAP */ /* strdup() which uses our alloc() rather than libc's malloc(); not used when MONITOR_HEAP is enabled, but included unconditionally in case utility programs get built using a different setting for that */ char * dupstr(string) const char *string; { return strcpy((char *) alloc(strlen(string) + 1), string); } /*alloc.c*/ nethack-3.6.0/src/apply.c0000664000076400007660000034247012624166366014243 0ustar paxedpaxed/* NetHack 3.6 apply.c $NHDT-Date: 1446808436 2015/11/06 11:13:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.210 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" extern boolean notonhead; /* for long worms */ STATIC_DCL int FDECL(use_camera, (struct obj *)); STATIC_DCL int FDECL(use_towel, (struct obj *)); STATIC_DCL boolean FDECL(its_dead, (int, int, int *)); STATIC_DCL int FDECL(use_stethoscope, (struct obj *)); STATIC_DCL void FDECL(use_whistle, (struct obj *)); STATIC_DCL void FDECL(use_magic_whistle, (struct obj *)); STATIC_DCL void FDECL(use_leash, (struct obj *)); STATIC_DCL int FDECL(use_mirror, (struct obj *)); STATIC_DCL void FDECL(use_bell, (struct obj **)); STATIC_DCL void FDECL(use_candelabrum, (struct obj *)); STATIC_DCL void FDECL(use_candle, (struct obj **)); STATIC_DCL void FDECL(use_lamp, (struct obj *)); STATIC_DCL void FDECL(light_cocktail, (struct obj *)); STATIC_PTR void FDECL(display_jump_positions, (int)); STATIC_DCL void FDECL(use_tinning_kit, (struct obj *)); STATIC_DCL void FDECL(use_figurine, (struct obj **)); STATIC_DCL void FDECL(use_grease, (struct obj *)); STATIC_DCL void FDECL(use_trap, (struct obj *)); STATIC_DCL void FDECL(use_stone, (struct obj *)); STATIC_PTR int NDECL(set_trap); /* occupation callback */ STATIC_DCL int FDECL(use_whip, (struct obj *)); STATIC_PTR void FDECL(display_polearm_positions, (int)); STATIC_DCL int FDECL(use_pole, (struct obj *)); STATIC_DCL int FDECL(use_cream_pie, (struct obj *)); STATIC_DCL int FDECL(use_grapple, (struct obj *)); STATIC_DCL int FDECL(do_break_wand, (struct obj *)); STATIC_DCL boolean FDECL(figurine_location_checks, (struct obj *, coord *, BOOLEAN_P)); STATIC_DCL void FDECL(add_class, (char *, CHAR_P)); STATIC_DCL void FDECL(setapplyclasses, (char *)); STATIC_DCL boolean FDECL(is_valid_jump_pos, (int, int, int, BOOLEAN_P)); STATIC_DCL boolean FDECL(find_poleable_mon, (coord *, int, int)); #ifdef AMIGA void FDECL(amii_speaker, (struct obj *, char *, int)); #endif static const char no_elbow_room[] = "don't have enough elbow-room to maneuver."; STATIC_OVL int use_camera(obj) struct obj *obj; { struct monst *mtmp; if (Underwater) { pline("Using your camera underwater would void the warranty."); return 0; } if (!getdir((char *) 0)) return 0; if (obj->spe <= 0) { pline1(nothing_happens); return 1; } consume_obj_charge(obj, TRUE); if (obj->cursed && !rn2(2)) { (void) zapyourself(obj, TRUE); } else if (u.uswallow) { You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); } else if (u.dz) { You("take a picture of the %s.", (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy)); } else if (!u.dx && !u.dy) { (void) zapyourself(obj, TRUE); } else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT, (int FDECL((*), (MONST_P, OBJ_P))) 0, (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj)) != 0) { obj->ox = u.ux, obj->oy = u.uy; (void) flash_hits_mon(mtmp, obj); } return 1; } STATIC_OVL int use_towel(obj) struct obj *obj; { boolean drying_feedback = (obj == uwep); if (!freehand()) { You("have no free %s!", body_part(HAND)); return 0; } else if (obj == ublindf) { You("cannot use it while you're wearing it!"); return 0; } else if (obj->cursed) { long old; switch (rn2(3)) { case 2: old = Glib; incr_itimeout(&Glib, rn1(10, 3)); Your("%s %s!", makeplural(body_part(HAND)), (old ? "are filthier than ever" : "get slimy")); if (is_wet_towel(obj)) dry_a_towel(obj, -1, drying_feedback); return 1; case 1: if (!ublindf) { old = u.ucreamed; u.ucreamed += rn1(10, 3); pline("Yecch! Your %s %s gunk on it!", body_part(FACE), (old ? "has more" : "now has")); make_blinded(Blinded + (long) u.ucreamed - old, TRUE); } else { const char *what; what = (ublindf->otyp == LENSES) ? "lenses" : (obj->otyp == ublindf->otyp) ? "other towel" : "blindfold"; if (ublindf->cursed) { You("push your %s %s.", what, rn2(2) ? "cock-eyed" : "crooked"); } else { struct obj *saved_ublindf = ublindf; You("push your %s off.", what); Blindf_off(ublindf); dropx(saved_ublindf); } } if (is_wet_towel(obj)) dry_a_towel(obj, -1, drying_feedback); return 1; case 0: break; } } if (Glib) { Glib = 0; You("wipe off your %s.", makeplural(body_part(HAND))); if (is_wet_towel(obj)) dry_a_towel(obj, -1, drying_feedback); return 1; } else if (u.ucreamed) { Blinded -= u.ucreamed; u.ucreamed = 0; if (!Blinded) { pline("You've got the glop off."); if (!gulp_blnd_check()) { Blinded = 1; make_blinded(0L, TRUE); } } else { Your("%s feels clean now.", body_part(FACE)); } if (is_wet_towel(obj)) dry_a_towel(obj, -1, drying_feedback); return 1; } Your("%s and %s are already clean.", body_part(FACE), makeplural(body_part(HAND))); return 0; } /* maybe give a stethoscope message based on floor objects */ STATIC_OVL boolean its_dead(rx, ry, resp) int rx, ry, *resp; { char buf[BUFSZ]; boolean more_corpses; struct permonst *mptr; struct obj *corpse = sobj_at(CORPSE, rx, ry), *statue = sobj_at(STATUE, rx, ry); if (!can_reach_floor(TRUE)) { /* levitation or unskilled riding */ corpse = 0; /* can't reach corpse on floor */ /* you can't reach tiny statues (even though you can fight tiny monsters while levitating--consistency, what's that?) */ while (statue && mons[statue->corpsenm].msize == MZ_TINY) statue = nxtobj(statue, STATUE, TRUE); } /* when both corpse and statue are present, pick the uppermost one */ if (corpse && statue) { if (nxtobj(statue, CORPSE, TRUE) == corpse) corpse = 0; /* corpse follows statue; ignore it */ else statue = 0; /* corpse precedes statue; ignore statue */ } more_corpses = (corpse && nxtobj(corpse, CORPSE, TRUE)); /* additional stethoscope messages from jyoung@apanix.apana.org.au */ if (!corpse && !statue) { ; /* nothing to do */ } else if (Hallucination) { if (!corpse) { /* it's a statue */ Strcpy(buf, "You're both stoned"); } else if (corpse->quan == 1L && !more_corpses) { int gndr = 2; /* neuter: "it" */ struct monst *mtmp = get_mtraits(corpse, FALSE); /* (most corpses don't retain the monster's sex, so we're usually forced to use generic pronoun here) */ if (mtmp) { mptr = &mons[mtmp->mnum]; /* can't use mhe() here; it calls pronoun_gender() which expects monster to be on the map (visibility check) */ if ((humanoid(mptr) || (mptr->geno & G_UNIQ) || type_is_pname(mptr)) && !is_neuter(mptr)) gndr = (int) mtmp->female; } else { mptr = &mons[corpse->corpsenm]; if (is_female(mptr)) gndr = 1; else if (is_male(mptr)) gndr = 0; } Sprintf(buf, "%s's dead", genders[gndr].he); /* "he"/"she"/"it" */ buf[0] = highc(buf[0]); } else { /* plural */ Strcpy(buf, "They're dead"); } /* variations on "He's dead, Jim." (Star Trek's Dr McCoy) */ You_hear("a voice say, \"%s, Jim.\"", buf); *resp = 1; return TRUE; } else if (corpse) { boolean here = (rx == u.ux && ry == u.uy), one = (corpse->quan == 1L && !more_corpses), reviver = FALSE; if (Role_if(PM_HEALER)) { /* ok to reset `corpse' here; we're done with it */ do { if (obj_has_timer(corpse, REVIVE_MON)) reviver = TRUE; else corpse = nxtobj(corpse, CORPSE, TRUE); } while (corpse && !reviver); } You("determine that %s unfortunate being%s %s%s dead.", one ? (here ? "this" : "that") : (here ? "these" : "those"), one ? "" : "s", one ? "is" : "are", reviver ? " mostly" : ""); return TRUE; } else { /* statue */ const char *what, *how; mptr = &mons[statue->corpsenm]; if (Blind) { /* ignore statue->dknown; it'll always be set */ Sprintf(buf, "%s %s", (rx == u.ux && ry == u.uy) ? "This" : "That", humanoid(mptr) ? "person" : "creature"); what = buf; } else { what = mptr->mname; if (!type_is_pname(mptr)) what = The(what); } how = "fine"; if (Role_if(PM_HEALER)) { struct trap *ttmp = t_at(rx, ry); if (ttmp && ttmp->ttyp == STATUE_TRAP) how = "extraordinary"; else if (Has_contents(statue)) how = "remarkable"; } pline("%s is in %s health for a statue.", what, how); return TRUE; } return FALSE; /* no corpse or statue */ } static const char hollow_str[] = "a hollow sound. This must be a secret %s!"; /* Strictly speaking it makes no sense for usage of a stethoscope to not take any time; however, unless it did, the stethoscope would be almost useless. As a compromise, one use per turn is free, another uses up the turn; this makes curse status have a tangible effect. */ STATIC_OVL int use_stethoscope(obj) register struct obj *obj; { struct monst *mtmp; struct rm *lev; int rx, ry, res; boolean interference = (u.uswallow && is_whirly(u.ustuck->data) && !rn2(Role_if(PM_HEALER) ? 10 : 3)); if (nohands(youmonst.data)) { You("have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (Deaf) { You_cant("hear anything!"); return 0; } else if (!freehand()) { You("have no free %s.", body_part(HAND)); return 0; } if (!getdir((char *) 0)) return 0; res = (moves == context.stethoscope_move) && (youmonst.movement == context.stethoscope_movement); context.stethoscope_move = moves; context.stethoscope_movement = youmonst.movement; if (u.usteed && u.dz > 0) { if (interference) { pline("%s interferes.", Monnam(u.ustuck)); mstatusline(u.ustuck); } else mstatusline(u.usteed); return res; } else if (u.uswallow && (u.dx || u.dy || u.dz)) { mstatusline(u.ustuck); return res; } else if (u.uswallow && interference) { pline("%s interferes.", Monnam(u.ustuck)); mstatusline(u.ustuck); return res; } else if (u.dz) { if (Underwater) You_hear("faint splashing."); else if (u.dz < 0 || !can_reach_floor(TRUE)) cant_reach_floor(u.ux, u.uy, (u.dz < 0), TRUE); else if (its_dead(u.ux, u.uy, &res)) ; /* message already given */ else if (Is_stronghold(&u.uz)) You_hear("the crackling of hellfire."); else pline_The("%s seems healthy enough.", surface(u.ux, u.uy)); return res; } else if (obj->cursed && !rn2(2)) { You_hear("your heart beat."); return res; } if (Stunned || (Confusion && !rn2(5))) confdir(); if (!u.dx && !u.dy) { ustatusline(); return res; } rx = u.ux + u.dx; ry = u.uy + u.dy; if (!isok(rx, ry)) { You_hear("a faint typing noise."); return 0; } if ((mtmp = m_at(rx, ry)) != 0) { const char *mnm = x_monnam(mtmp, ARTICLE_A, (const char *) 0, SUPPRESS_IT | SUPPRESS_INVISIBLE, FALSE); if (mtmp->mundetected) { if (!canspotmon(mtmp)) There("is %s hidden there.", mnm); mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); } else if (mtmp->mappearance) { const char *what = "thing"; switch (mtmp->m_ap_type) { case M_AP_OBJECT: what = simple_typename(mtmp->mappearance); break; case M_AP_MONSTER: /* ignore Hallucination here */ what = mons[mtmp->mappearance].mname; break; case M_AP_FURNITURE: what = defsyms[mtmp->mappearance].explanation; break; } seemimic(mtmp); pline("That %s is really %s", what, mnm); } else if (flags.verbose && !canspotmon(mtmp)) { There("is %s there.", mnm); } mstatusline(mtmp); if (!canspotmon(mtmp)) map_invisible(rx, ry); return res; } if (glyph_is_invisible(levl[rx][ry].glyph)) { unmap_object(rx, ry); newsym(rx, ry); pline_The("invisible monster must have moved."); } lev = &levl[rx][ry]; switch (lev->typ) { case SDOOR: You_hear(hollow_str, "door"); cvt_sdoor_to_door(lev); /* ->typ = DOOR */ feel_newsym(rx, ry); return res; case SCORR: You_hear(hollow_str, "passage"); lev->typ = CORR; unblock_point(rx, ry); feel_newsym(rx, ry); return res; } if (!its_dead(rx, ry, &res)) You("hear nothing special."); /* not You_hear() */ return res; } static const char whistle_str[] = "produce a %s whistling sound."; STATIC_OVL void use_whistle(obj) struct obj *obj; { if (!can_blow(&youmonst)) { You("are incapable of using the whistle."); } else if (Underwater) { You("blow bubbles through %s.", yname(obj)); } else { You(whistle_str, obj->cursed ? "shrill" : "high"); wake_nearby(); } } STATIC_OVL void use_magic_whistle(obj) struct obj *obj; { register struct monst *mtmp, *nextmon; if (!can_blow(&youmonst)) { You("are incapable of using the whistle."); } else if (obj->cursed && !rn2(2)) { You("produce a %shigh-pitched humming noise.", Underwater ? "very " : ""); wake_nearby(); } else { int pet_cnt = 0, omx, omy; /* it's magic! it works underwater too (at a higher pitch) */ You(whistle_str, Hallucination ? "normal" : Underwater ? "strange, high-pitched" : "strange"); for (mtmp = fmon; mtmp; mtmp = nextmon) { nextmon = mtmp->nmon; /* trap might kill mon */ if (DEADMONSTER(mtmp)) continue; /* steed is already at your location, so not affected; this avoids trap issues if you're on a trap location */ if (mtmp == u.usteed) continue; if (mtmp->mtame) { if (mtmp->mtrapped) { /* no longer in previous trap (affects mintrap) */ mtmp->mtrapped = 0; fill_pit(mtmp->mx, mtmp->my); } /* mimic must be revealed before we know whether it actually moves because line-of-sight may change */ if (mtmp->m_ap_type) seemimic(mtmp); omx = mtmp->mx, omy = mtmp->my; mnexto(mtmp); if (mtmp->mx != omx || mtmp->my != omy) { mtmp->mundetected = 0; /* reveal non-mimic hider */ if (canspotmon(mtmp)) ++pet_cnt; if (mintrap(mtmp) == 2) change_luck(-1); } } } if (pet_cnt > 0) makeknown(obj->otyp); } } boolean um_dist(x, y, n) xchar x, y, n; { return (boolean) (abs(u.ux - x) > n || abs(u.uy - y) > n); } int number_leashed() { int i = 0; struct obj *obj; for (obj = invent; obj; obj = obj->nobj) if (obj->otyp == LEASH && obj->leashmon != 0) i++; return i; } /* otmp is about to be destroyed or stolen */ void o_unleash(otmp) register struct obj *otmp; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == (unsigned) otmp->leashmon) mtmp->mleashed = 0; otmp->leashmon = 0; } /* mtmp is about to die, or become untame */ void m_unleash(mtmp, feedback) register struct monst *mtmp; boolean feedback; { register struct obj *otmp; if (feedback) { if (canseemon(mtmp)) pline("%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp)); else Your("leash falls slack."); } for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id) otmp->leashmon = 0; mtmp->mleashed = 0; } /* player is about to die (for bones) */ void unleash_all() { register struct obj *otmp; register struct monst *mtmp; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == LEASH) otmp->leashmon = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) mtmp->mleashed = 0; } #define MAXLEASHED 2 static boolean leashable(mtmp) struct monst *mtmp; { return (boolean) (mtmp->mnum != PM_LONG_WORM); } /* ARGSUSED */ STATIC_OVL void use_leash(obj) struct obj *obj; { coord cc; register struct monst *mtmp; int spotmon; if (!obj->leashmon && number_leashed() >= MAXLEASHED) { You("cannot leash any more pets."); return; } if (!get_adjacent_loc((char *) 0, (char *) 0, u.ux, u.uy, &cc)) return; if ((cc.x == u.ux) && (cc.y == u.uy)) { if (u.usteed && u.dz > 0) { mtmp = u.usteed; spotmon = 1; goto got_target; } pline("Leash yourself? Very funny..."); return; } if (!(mtmp = m_at(cc.x, cc.y))) { There("is no creature there."); return; } spotmon = canspotmon(mtmp); got_target: if (!mtmp->mtame) { if (!spotmon) There("is no creature there."); else pline("%s %s leashed!", Monnam(mtmp), (!obj->leashmon) ? "cannot be" : "is not"); return; } if (!obj->leashmon) { if (mtmp->mleashed) { pline("This %s is already leashed.", spotmon ? l_monnam(mtmp) : "monster"); return; } if (!leashable(mtmp)) { pline("The leash won't fit onto %s%s.", spotmon ? "your " : "", l_monnam(mtmp)); return; } You("slip the leash around %s%s.", spotmon ? "your " : "", l_monnam(mtmp)); mtmp->mleashed = 1; obj->leashmon = (int) mtmp->m_id; mtmp->msleeping = 0; return; } if (obj->leashmon != (int) mtmp->m_id) { pline("This leash is not attached to that creature."); return; } else { if (obj->cursed) { pline_The("leash would not come off!"); obj->bknown = TRUE; return; } mtmp->mleashed = 0; obj->leashmon = 0; You("remove the leash from %s%s.", spotmon ? "your " : "", l_monnam(mtmp)); } return; } /* assuming mtmp->mleashed has been checked */ struct obj * get_mleash(mtmp) struct monst *mtmp; { struct obj *otmp; otmp = invent; while (otmp) { if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id) return otmp; otmp = otmp->nobj; } return (struct obj *) 0; } boolean next_to_u() { register struct monst *mtmp; register struct obj *otmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->mleashed) { if (distu(mtmp->mx, mtmp->my) > 2) mnexto(mtmp); if (distu(mtmp->mx, mtmp->my) > 2) { for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id) { if (otmp->cursed) return FALSE; You_feel("%s leash go slack.", (number_leashed() > 1) ? "a" : "the"); mtmp->mleashed = 0; otmp->leashmon = 0; } } } } /* no pack mules for the Amulet */ if (u.usteed && mon_has_amulet(u.usteed)) return FALSE; return TRUE; } void check_leash(x, y) register xchar x, y; { register struct obj *otmp; register struct monst *mtmp; for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->otyp != LEASH || otmp->leashmon == 0) continue; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((int) mtmp->m_id == otmp->leashmon) break; } if (!mtmp) { impossible("leash in use isn't attached to anything?"); otmp->leashmon = 0; continue; } if (dist2(u.ux, u.uy, mtmp->mx, mtmp->my) > dist2(x, y, mtmp->mx, mtmp->my)) { if (!um_dist(mtmp->mx, mtmp->my, 3)) { ; /* still close enough */ } else if (otmp->cursed && !breathless(mtmp->data)) { if (um_dist(mtmp->mx, mtmp->my, 5) || (mtmp->mhp -= rnd(2)) <= 0) { long save_pacifism = u.uconduct.killer; Your("leash chokes %s to death!", mon_nam(mtmp)); /* hero might not have intended to kill pet, but that's the result of his actions; gain experience, lose pacifism, take alignment and luck hit, make corpse less likely to remain tame after revival */ xkilled(mtmp, 0); /* no "you kill it" message */ /* life-saving doesn't ordinarily reset this */ if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism; } else { pline("%s is choked by the leash!", Monnam(mtmp)); /* tameness eventually drops to 1 here (never 0) */ if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--; } } else { if (um_dist(mtmp->mx, mtmp->my, 5)) { pline("%s leash snaps loose!", s_suffix(Monnam(mtmp))); m_unleash(mtmp, FALSE); } else { You("pull on the leash."); if (mtmp->data->msound != MS_SILENT) switch (rn2(3)) { case 0: growl(mtmp); break; case 1: yelp(mtmp); break; default: whimper(mtmp); break; } } } } } } const char * beautiful() { return ((ACURR(A_CHA) > 14) ? ((poly_gender() == 1) ? "beautiful" : "handsome") : "ugly"); } #define WEAK 3 /* from eat.c */ static const char look_str[] = "look %s."; STATIC_OVL int use_mirror(obj) struct obj *obj; { const char *mirror, *uvisage; struct monst *mtmp; unsigned how_seen; char mlet; boolean vis, invis_mirror, useeit, monable; if (!getdir((char *) 0)) return 0; invis_mirror = Invis; useeit = !Blind && (!invis_mirror || See_invisible); uvisage = beautiful(); mirror = simpleonames(obj); /* "mirror" or "looking glass" */ if (obj->cursed && !rn2(2)) { if (!Blind) pline_The("%s fogs up and doesn't reflect!", mirror); return 1; } if (!u.dx && !u.dy && !u.dz) { if (!useeit) { You_cant("see your %s %s.", uvisage, body_part(FACE)); } else { if (u.umonnum == PM_FLOATING_EYE) { if (Free_action) { You("stiffen momentarily under your gaze."); } else { if (Hallucination) pline("Yow! The %s stares back!", mirror); else pline("Yikes! You've frozen yourself!"); if (!Hallucination || !rn2(4)) { nomul(-rnd(MAXULEV + 6 - u.ulevel)); multi_reason = "gazing into a mirror"; } nomovemsg = 0; /* default, "you can move again" */ } } else if (youmonst.data->mlet == S_VAMPIRE) You("don't have a reflection."); else if (u.umonnum == PM_UMBER_HULK) { pline("Huh? That doesn't look like you!"); make_confused(HConfusion + d(3, 4), FALSE); } else if (Hallucination) You(look_str, hcolor((char *) 0)); else if (Sick) You(look_str, "peaked"); else if (u.uhs >= WEAK) You(look_str, "undernourished"); else You("look as %s as ever.", uvisage); } return 1; } if (u.uswallow) { if (useeit) You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); return 1; } if (Underwater) { if (useeit) You(Hallucination ? "give the fish a chance to fix their makeup." : "reflect the murky water."); return 1; } if (u.dz) { if (useeit) You("reflect the %s.", (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy)); return 1; } mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM, (int FDECL((*), (MONST_P, OBJ_P))) 0, (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj); if (!mtmp || !haseyes(mtmp->data) || notonhead) return 1; /* couldsee(mtmp->mx, mtmp->my) is implied by the fact that bhit() targetted it, so we can ignore possibility of X-ray vision */ vis = canseemon(mtmp); /* ways to directly see monster (excludes X-ray vision, telepathy, extended detection, type-specific warning) */ #define SEENMON (MONSEEN_NORMAL | MONSEEN_SEEINVIS | MONSEEN_INFRAVIS) how_seen = vis ? howmonseen(mtmp) : 0; /* whether monster is able to use its vision-based capabilities */ monable = !mtmp->mcan && (!mtmp->minvis || perceives(mtmp->data)); mlet = mtmp->data->mlet; if (mtmp->msleeping) { if (vis) pline("%s is too tired to look at your %s.", Monnam(mtmp), mirror); } else if (!mtmp->mcansee) { if (vis) pline("%s can't see anything right now.", Monnam(mtmp)); } else if (invis_mirror && !perceives(mtmp->data)) { if (vis) pline("%s fails to notice your %s.", Monnam(mtmp), mirror); /* infravision doesn't produce an image in the mirror */ } else if ((how_seen & SEENMON) == MONSEEN_INFRAVIS) { if (vis) /* (redundant) */ pline("%s is too far away to see %sself in the dark.", Monnam(mtmp), mhim(mtmp)); /* some monsters do special things */ } else if (mlet == S_VAMPIRE || mlet == S_GHOST || is_vampshifter(mtmp)) { if (vis) pline("%s doesn't have a reflection.", Monnam(mtmp)); } else if (monable && mtmp->data == &mons[PM_MEDUSA]) { if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!")) return 1; if (vis) pline("%s is turned to stone!", Monnam(mtmp)); stoned = TRUE; killed(mtmp); } else if (monable && mtmp->data == &mons[PM_FLOATING_EYE]) { int tmp = d((int) mtmp->m_lev, (int) mtmp->data->mattk[0].damd); if (!rn2(4)) tmp = 120; if (vis) pline("%s is frozen by its reflection.", Monnam(mtmp)); else You_hear("%s stop moving.", something); paralyze_monst(mtmp, (int) mtmp->mfrozen + tmp); } else if (monable && mtmp->data == &mons[PM_UMBER_HULK]) { if (vis) pline("%s confuses itself!", Monnam(mtmp)); mtmp->mconf = 1; } else if (monable && (mlet == S_NYMPH || mtmp->data == &mons[PM_SUCCUBUS] || mtmp->data == &mons[PM_INCUBUS])) { if (vis) { char buf[BUFSZ]; /* "She" or "He" */ pline("%s admires %sself in your %s.", Monnam(mtmp), mhim(mtmp), mirror); pline("%s takes it!", upstart(strcpy(buf, mhe(mtmp)))); } else pline("It steals your %s!", mirror); setnotworn(obj); /* in case mirror was wielded */ freeinv(obj); (void) mpickobj(mtmp, obj); if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data) && (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) { if (vis) pline("%s is frightened by its reflection.", Monnam(mtmp)); monflee(mtmp, d(2, 4), FALSE, FALSE); } else if (!Blind) { if (mtmp->minvis && !See_invisible) ; else if ((mtmp->minvis && !perceives(mtmp->data)) /* redundant: can't get here if these are true */ || !haseyes(mtmp->data) || notonhead || !mtmp->mcansee) pline("%s doesn't seem to notice %s reflection.", Monnam(mtmp), mhis(mtmp)); else pline("%s ignores %s reflection.", Monnam(mtmp), mhis(mtmp)); } return 1; } STATIC_OVL void use_bell(optr) struct obj **optr; { register struct obj *obj = *optr; struct monst *mtmp; boolean wakem = FALSE, learno = FALSE, ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe), invoking = (obj->otyp == BELL_OF_OPENING && invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)); You("ring %s.", the(xname(obj))); if (Underwater || (u.uswallow && ordinary)) { #ifdef AMIGA amii_speaker(obj, "AhDhGqEqDhEhAqDqFhGw", AMII_MUFFLED_VOLUME); #endif pline("But the sound is muffled."); } else if (invoking && ordinary) { /* needs to be recharged... */ pline("But it makes no sound."); learno = TRUE; /* help player figure out why */ } else if (ordinary) { #ifdef AMIGA amii_speaker(obj, "ahdhgqeqdhehaqdqfhgw", AMII_MUFFLED_VOLUME); #endif if (obj->cursed && !rn2(4) /* note: once any of them are gone, we stop all of them */ && !(mvitals[PM_WOOD_NYMPH].mvflags & G_GONE) && !(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) && !(mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE) && (mtmp = makemon(mkclass(S_NYMPH, 0), u.ux, u.uy, NO_MINVENT)) != 0) { You("summon %s!", a_monnam(mtmp)); if (!obj_resists(obj, 93, 100)) { pline("%s shattered!", Tobjnam(obj, "have")); useup(obj); *optr = 0; } else switch (rn2(3)) { default: break; case 1: mon_adjust_speed(mtmp, 2, (struct obj *) 0); break; case 2: /* no explanation; it just happens... */ nomovemsg = ""; multi_reason = NULL; nomul(-rnd(2)); break; } } wakem = TRUE; } else { /* charged Bell of Opening */ consume_obj_charge(obj, TRUE); if (u.uswallow) { if (!obj->cursed) (void) openit(); else pline1(nothing_happens); } else if (obj->cursed) { coord mm; mm.x = u.ux; mm.y = u.uy; mkundead(&mm, FALSE, NO_MINVENT); wakem = TRUE; } else if (invoking) { pline("%s an unsettling shrill sound...", Tobjnam(obj, "issue")); #ifdef AMIGA amii_speaker(obj, "aefeaefeaefeaefeaefe", AMII_LOUDER_VOLUME); #endif obj->age = moves; learno = TRUE; wakem = TRUE; } else if (obj->blessed) { int res = 0; #ifdef AMIGA amii_speaker(obj, "ahahahDhEhCw", AMII_SOFT_VOLUME); #endif if (uchain) { unpunish(); res = 1; } else if (u.utrap && u.utraptype == TT_BURIEDBALL) { buried_ball_to_freedom(); res = 1; } res += openit(); switch (res) { case 0: pline1(nothing_happens); break; case 1: pline("%s opens...", Something); learno = TRUE; break; default: pline("Things open around you..."); learno = TRUE; break; } } else { /* uncursed */ #ifdef AMIGA amii_speaker(obj, "AeFeaeFeAefegw", AMII_OKAY_VOLUME); #endif if (findit() != 0) learno = TRUE; else pline1(nothing_happens); } } /* charged BofO */ if (learno) { makeknown(BELL_OF_OPENING); obj->known = 1; } if (wakem) wake_nearby(); } STATIC_OVL void use_candelabrum(obj) register struct obj *obj; { const char *s = (obj->spe != 1) ? "candles" : "candle"; if (obj->lamplit) { You("snuff the %s.", s); end_burn(obj, TRUE); return; } if (obj->spe <= 0) { pline("This %s has no %s.", xname(obj), s); return; } if (Underwater) { You("cannot make fire under water."); return; } if (u.uswallow || obj->cursed) { if (!Blind) pline_The("%s %s for a moment, then %s.", s, vtense(s, "flicker"), vtense(s, "die")); return; } if (obj->spe < 7) { There("%s only %d %s in %s.", vtense(s, "are"), obj->spe, s, the(xname(obj))); if (!Blind) pline("%s lit. %s dimly.", obj->spe == 1 ? "It is" : "They are", Tobjnam(obj, "shine")); } else { pline("%s's %s burn%s", The(xname(obj)), s, (Blind ? "." : " brightly!")); } if (!invocation_pos(u.ux, u.uy) || On_stairs(u.ux, u.uy)) { pline_The("%s %s being rapidly consumed!", s, vtense(s, "are")); /* this used to be obj->age /= 2, rounding down; an age of 1 would yield 0, confusing begin_burn() and producing an unlightable, unrefillable candelabrum; round up instead */ obj->age = (obj->age + 1L) / 2L; } else { if (obj->spe == 7) { if (Blind) pline("%s a strange warmth!", Tobjnam(obj, "radiate")); else pline("%s with a strange light!", Tobjnam(obj, "glow")); } obj->known = 1; } begin_burn(obj, FALSE); } STATIC_OVL void use_candle(optr) struct obj **optr; { register struct obj *obj = *optr; register struct obj *otmp; const char *s = (obj->quan != 1) ? "candles" : "candle"; char qbuf[QBUFSZ], qsfx[QBUFSZ], *q; if (u.uswallow) { You(no_elbow_room); return; } otmp = carrying(CANDELABRUM_OF_INVOCATION); if (!otmp || otmp->spe == 7) { use_lamp(obj); return; } /* first, minimal candelabrum suffix for formatting candles */ Sprintf(qsfx, " to\033%s?", thesimpleoname(otmp)); /* next, format the candles as a prefix for the candelabrum */ (void) safe_qbuf(qbuf, "Attach ", qsfx, obj, yname, thesimpleoname, s); /* strip temporary candelabrum suffix */ if ((q = strstri(qbuf, " to\033")) != 0) Strcpy(q, " to "); /* last, format final "attach candles to candelabrum?" query */ if (yn(safe_qbuf(qbuf, qbuf, "?", otmp, yname, thesimpleoname, "it")) == 'n') { use_lamp(obj); return; } else { if ((long) otmp->spe + obj->quan > 7L) { obj = splitobj(obj, 7L - (long) otmp->spe); /* avoid a grammatical error if obj->quan gets reduced to 1 candle from more than one */ s = (obj->quan != 1) ? "candles" : "candle"; } else *optr = 0; You("attach %ld%s %s to %s.", obj->quan, !otmp->spe ? "" : " more", s, the(xname(otmp))); if (!otmp->spe || otmp->age > obj->age) otmp->age = obj->age; otmp->spe += (int) obj->quan; if (otmp->lamplit && !obj->lamplit) pline_The("new %s magically %s!", s, vtense(s, "ignite")); else if (!otmp->lamplit && obj->lamplit) pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes"); if (obj->unpaid) verbalize("You %s %s, you bought %s!", otmp->lamplit ? "burn" : "use", (obj->quan > 1L) ? "them" : "it", (obj->quan > 1L) ? "them" : "it"); if (obj->quan < 7L && otmp->spe == 7) pline("%s now has seven%s candles attached.", The(xname(otmp)), otmp->lamplit ? " lit" : ""); /* candelabrum's light range might increase */ if (otmp->lamplit) obj_merge_light_sources(otmp, otmp); /* candles are no longer a separate light source */ if (obj->lamplit) end_burn(obj, TRUE); /* candles are now gone */ useupall(obj); } } /* call in drop, throw, and put in box, etc. */ boolean snuff_candle(otmp) struct obj *otmp; { boolean candle = Is_candle(otmp); if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION) && otmp->lamplit) { char buf[BUFSZ]; xchar x, y; boolean many = candle ? (otmp->quan > 1L) : (otmp->spe > 1); (void) get_obj_location(otmp, &x, &y, 0); if (otmp->where == OBJ_MINVENT ? cansee(x, y) : !Blind) pline("%s%scandle%s flame%s extinguished.", Shk_Your(buf, otmp), (candle ? "" : "candelabrum's "), (many ? "s'" : "'s"), (many ? "s are" : " is")); end_burn(otmp, TRUE); return TRUE; } return FALSE; } /* called when lit lamp is hit by water or put into a container or you've been swallowed by a monster; obj might be in transit while being thrown or dropped so don't assume that its location is valid */ boolean snuff_lit(obj) struct obj *obj; { xchar x, y; if (obj->lamplit) { if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL) { (void) get_obj_location(obj, &x, &y, 0); if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind) pline("%s %s out!", Yname2(obj), otense(obj, "go")); end_burn(obj, TRUE); return TRUE; } if (snuff_candle(obj)) return TRUE; } return FALSE; } /* Called when potentially lightable object is affected by fire_damage(). Return TRUE if object was lit and FALSE otherwise --ALI */ boolean catch_lit(obj) struct obj *obj; { xchar x, y; if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) { if ((obj->otyp == MAGIC_LAMP || obj->otyp == CANDELABRUM_OF_INVOCATION) && obj->spe == 0) return FALSE; else if (obj->otyp != MAGIC_LAMP && obj->age == 0) return FALSE; if (!get_obj_location(obj, &x, &y, 0)) return FALSE; if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->cursed) return FALSE; if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN) && obj->cursed && !rn2(2)) return FALSE; if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind) pline("%s %s light!", Yname2(obj), otense(obj, "catch")); if (obj->otyp == POT_OIL) makeknown(obj->otyp); if (carried(obj) && obj->unpaid && costly_spot(u.ux, u.uy)) { /* if it catches while you have it, then it's your tough luck */ check_unpaid(obj); verbalize("That's in addition to the cost of %s %s, of course.", yname(obj), obj->quan == 1L ? "itself" : "themselves"); bill_dummy_object(obj); } begin_burn(obj, FALSE); return TRUE; } return FALSE; } STATIC_OVL void use_lamp(obj) struct obj *obj; { char buf[BUFSZ]; if (obj->lamplit) { if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN) pline("%slamp is now off.", Shk_Your(buf, obj)); else You("snuff out %s.", yname(obj)); end_burn(obj, TRUE); return; } if (Underwater) { pline(!Is_candle(obj) ? "This is not a diving lamp" : "Sorry, fire and water don't mix."); return; } /* magic lamps with an spe == 0 (wished for) cannot be lit */ if ((!Is_candle(obj) && obj->age == 0) || (obj->otyp == MAGIC_LAMP && obj->spe == 0)) { if (obj->otyp == BRASS_LANTERN) Your("lamp has run out of power."); else pline("This %s has no oil.", xname(obj)); return; } if (obj->cursed && !rn2(2)) { if (!Blind) pline("%s for a moment, then %s.", Tobjnam(obj, "flicker"), otense(obj, "die")); } else { if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN) { check_unpaid(obj); pline("%slamp is now on.", Shk_Your(buf, obj)); } else { /* candle(s) */ pline("%s flame%s %s%s", s_suffix(Yname2(obj)), plur(obj->quan), otense(obj, "burn"), Blind ? "." : " brightly!"); if (obj->unpaid && costly_spot(u.ux, u.uy) && obj->age == 20L * (long) objects[obj->otyp].oc_cost) { const char *ithem = (obj->quan > 1L) ? "them" : "it"; verbalize("You burn %s, you bought %s!", ithem, ithem); bill_dummy_object(obj); } } begin_burn(obj, FALSE); } } STATIC_OVL void light_cocktail(obj) struct obj *obj; /* obj is a potion of oil */ { char buf[BUFSZ]; boolean split1off; if (u.uswallow) { You(no_elbow_room); return; } if (obj->lamplit) { You("snuff the lit potion."); end_burn(obj, TRUE); /* * Free & add to re-merge potion. This will average the * age of the potions. Not exactly the best solution, * but its easy. */ freeinv(obj); (void) addinv(obj); return; } else if (Underwater) { There("is not enough oxygen to sustain a fire."); return; } split1off = (obj->quan > 1L); if (split1off) obj = splitobj(obj, 1L); You("light %spotion.%s", shk_your(buf, obj), Blind ? "" : " It gives off a dim light."); if (obj->unpaid && costly_spot(u.ux, u.uy)) { /* Normally, we shouldn't both partially and fully charge * for an item, but (Yendorian Fuel) Taxes are inevitable... */ check_unpaid(obj); verbalize("That's in addition to the cost of the potion, of course."); bill_dummy_object(obj); } makeknown(obj->otyp); begin_burn(obj, FALSE); /* after shop billing */ if (split1off) { obj_extract_self(obj); /* free from inv */ obj->nomerge = 1; obj = hold_another_object(obj, "You drop %s!", doname(obj), (const char *) 0); if (obj) obj->nomerge = 0; } } static NEARDATA const char cuddly[] = { TOOL_CLASS, GEM_CLASS, 0 }; int dorub() { struct obj *obj = getobj(cuddly, "rub"); if (obj && obj->oclass == GEM_CLASS) { if (is_graystone(obj)) { use_stone(obj); return 1; } else { pline("Sorry, I don't know how to use that."); return 0; } } if (!obj || !wield_tool(obj, "rub")) return 0; /* now uwep is obj */ if (uwep->otyp == MAGIC_LAMP) { if (uwep->spe > 0 && !rn2(3)) { check_unpaid_usage(uwep, TRUE); /* unusual item use */ /* bones preparation: perform the lamp transformation before releasing the djinni in case the latter turns out to be fatal (a hostile djinni has no chance to attack yet, but an indebted one who grants a wish might bestow an artifact which blasts the hero with lethal results) */ uwep->otyp = OIL_LAMP; uwep->spe = 0; /* for safety */ uwep->age = rn1(500, 1000); if (uwep->lamplit) begin_burn(uwep, TRUE); djinni_from_bottle(uwep); makeknown(MAGIC_LAMP); update_inventory(); } else if (rn2(2)) { You("%s smoke.", !Blind ? "see a puff of" : "smell"); } else pline1(nothing_happens); } else if (obj->otyp == BRASS_LANTERN) { /* message from Adventure */ pline("Rubbing the electric lamp is not particularly rewarding."); pline("Anyway, nothing exciting happens."); } else pline1(nothing_happens); return 1; } int dojump() { /* Physical jump */ return jump(0); } boolean is_valid_jump_pos(x, y, magic, showmsg) int x, y, magic; boolean showmsg; { if (!magic && !(HJumping & ~INTRINSIC) && !EJumping && distu(x, y) != 5) { /* The Knight jumping restriction still applies when riding a * horse. After all, what shape is the knight piece in chess? */ if (showmsg) pline("Illegal move!"); return FALSE; } else if (distu(x, y) > (magic ? 6 + magic * 3 : 9)) { if (showmsg) pline("Too far!"); return FALSE; } else if (!cansee(x, y)) { if (showmsg) You("cannot see where to land!"); return FALSE; } else if (!isok(x, y)) { if (showmsg) You("cannot jump there!"); return FALSE; } return TRUE; } static int jumping_is_magic; void display_jump_positions(state) int state; { if (state == 0) { tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos)); } else if (state == 1) { int x, y, dx, dy; for (dx = -4; dx <= 4; dx++) for (dy = -4; dy <= 4; dy++) { x = dx + (int) u.ux; y = dy + (int) u.uy; if (isok(x, y) && ACCESSIBLE(levl[x][y].typ) && is_valid_jump_pos(x, y, jumping_is_magic, FALSE)) tmp_at(x, y); } } else { tmp_at(DISP_END, 0); } } int jump(magic) int magic; /* 0=Physical, otherwise skill level */ { coord cc; if (!magic && (nolimbs(youmonst.data) || slithy(youmonst.data))) { /* normally (nolimbs || slithy) implies !Jumping, but that isn't necessarily the case for knights */ You_cant("jump; you have no legs!"); return 0; } else if (!magic && !Jumping) { You_cant("jump very far."); return 0; /* if steed is immobile, can't do physical jump but can do spell one */ } else if (!magic && u.usteed && stucksteed(FALSE)) { /* stucksteed gave " won't move" message */ return 0; } else if (u.uswallow) { if (magic) { You("bounce around a little."); return 1; } pline("You've got to be kidding!"); return 0; } else if (u.uinwater) { if (magic) { You("swish around a little."); return 1; } pline("This calls for swimming, not jumping!"); return 0; } else if (u.ustuck) { if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) { You("pull free from %s.", mon_nam(u.ustuck)); u.ustuck = 0; return 1; } if (magic) { You("writhe a little in the grasp of %s!", mon_nam(u.ustuck)); return 1; } You("cannot escape from %s!", mon_nam(u.ustuck)); return 0; } else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { if (magic) { You("flail around a little."); return 1; } You("don't have enough traction to jump."); return 0; } else if (!magic && near_capacity() > UNENCUMBERED) { You("are carrying too much to jump!"); return 0; } else if (!magic && (u.uhunger <= 100 || ACURR(A_STR) < 6)) { You("lack the strength to jump!"); return 0; } else if (!magic && Wounded_legs) { long wl = (Wounded_legs & BOTH_SIDES); const char *bp = body_part(LEG); if (wl == BOTH_SIDES) bp = makeplural(bp); if (u.usteed) pline("%s is in no shape for jumping.", Monnam(u.usteed)); else Your("%s%s %s in no shape for jumping.", (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "", bp, (wl == BOTH_SIDES) ? "are" : "is"); return 0; } else if (u.usteed && u.utrap) { pline("%s is stuck in a trap.", Monnam(u.usteed)); return 0; } pline("Where do you want to jump?"); cc.x = u.ux; cc.y = u.uy; jumping_is_magic = magic; getpos_sethilite(display_jump_positions); if (getpos(&cc, TRUE, "the desired position") < 0) return 0; /* user pressed ESC */ if (!is_valid_jump_pos(cc.x, cc.y, magic, TRUE)) { return 0; } else { coord uc; int range, temp; if (u.utrap) switch (u.utraptype) { case TT_BEARTRAP: { long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; You("rip yourself free of the bear trap! Ouch!"); losehp(Maybe_Half_Phys(rnd(10)), "jumping out of a bear trap", KILLED_BY); set_wounded_legs(side, rn1(1000, 500)); break; } case TT_PIT: You("leap from the pit!"); break; case TT_WEB: You("tear the web apart as you pull yourself free!"); deltrap(t_at(u.ux, u.uy)); break; case TT_LAVA: You("pull yourself above the lava!"); u.utrap = 0; return 1; case TT_BURIEDBALL: case TT_INFLOOR: You("strain your %s, but you're still %s.", makeplural(body_part(LEG)), (u.utraptype == TT_INFLOOR) ? "stuck in the floor" : "attached to the buried ball"); set_wounded_legs(LEFT_SIDE, rn1(10, 11)); set_wounded_legs(RIGHT_SIDE, rn1(10, 11)); return 1; } /* * Check the path from uc to cc, calling hurtle_step at each * location. The final position actually reached will be * in cc. */ uc.x = u.ux; uc.y = u.uy; /* calculate max(abs(dx), abs(dy)) as the range */ range = cc.x - uc.x; if (range < 0) range = -range; temp = cc.y - uc.y; if (temp < 0) temp = -temp; if (range < temp) range = temp; (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range); teleds(cc.x, cc.y, TRUE); sokoban_guilt(); nomul(-1); multi_reason = "jumping around"; nomovemsg = ""; morehungry(rnd(25)); return 1; } } boolean tinnable(corpse) struct obj *corpse; { if (corpse->oeaten) return 0; if (!mons[corpse->corpsenm].cnutrit) return 0; return 1; } STATIC_OVL void use_tinning_kit(obj) struct obj *obj; { struct obj *corpse, *can; /* This takes only 1 move. If this is to be changed to take many * moves, we've got to deal with decaying corpses... */ if (obj->spe <= 0) { You("seem to be out of tins."); return; } if (!(corpse = floorfood("tin", 2))) return; if (corpse->oeaten) { You("cannot tin %s which is partly eaten.", something); return; } if (touch_petrifies(&mons[corpse->corpsenm]) && !Stone_resistance && !uarmg) { char kbuf[BUFSZ]; if (poly_when_stoned(youmonst.data)) You("tin %s without wearing gloves.", an(mons[corpse->corpsenm].mname)); else { pline("Tinning %s without wearing gloves is a fatal mistake...", an(mons[corpse->corpsenm].mname)); Sprintf(kbuf, "trying to tin %s without gloves", an(mons[corpse->corpsenm].mname)); } instapetrify(kbuf); } if (is_rider(&mons[corpse->corpsenm])) { if (revive_corpse(corpse)) verbalize("Yes... But War does not preserve its enemies..."); else pline_The("corpse evades your grasp."); return; } if (mons[corpse->corpsenm].cnutrit == 0) { pline("That's too insubstantial to tin."); return; } consume_obj_charge(obj, TRUE); if ((can = mksobj(TIN, FALSE, FALSE)) != 0) { static const char you_buy_it[] = "You tin it, you bought it!"; can->corpsenm = corpse->corpsenm; can->cursed = obj->cursed; can->blessed = obj->blessed; can->owt = weight(can); can->known = 1; /* Mark tinned tins. No spinach allowed... */ set_tin_variety(can, HOMEMADE_TIN); if (carried(corpse)) { if (corpse->unpaid) verbalize(you_buy_it); useup(corpse); } else { if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge) verbalize(you_buy_it); useupf(corpse, 1L); } can = hold_another_object(can, "You make, but cannot pick up, %s.", doname(can), (const char *) 0); } else impossible("Tinning failed."); } void use_unicorn_horn(obj) struct obj *obj; { #define PROP_COUNT 7 /* number of properties we're dealing with */ #define ATTR_COUNT (A_MAX * 3) /* number of attribute points we might fix */ int idx, val, val_limit, trouble_count, unfixable_trbl, did_prop, did_attr; int trouble_list[PROP_COUNT + ATTR_COUNT]; if (obj && obj->cursed) { long lcount = (long) rn1(90, 10); switch (rn2(13) / 2) { /* case 6 is half as likely as the others */ case 0: make_sick((Sick & TIMEOUT) ? (Sick & TIMEOUT) / 3L + 1L : (long) rn1(ACURR(A_CON), 20), xname(obj), TRUE, SICK_NONVOMITABLE); break; case 1: make_blinded((Blinded & TIMEOUT) + lcount, TRUE); break; case 2: if (!Confusion) You("suddenly feel %s.", Hallucination ? "trippy" : "confused"); make_confused((HConfusion & TIMEOUT) + lcount, TRUE); break; case 3: make_stunned((HStun & TIMEOUT) + lcount, TRUE); break; case 4: (void) adjattrib(rn2(A_MAX), -1, FALSE); break; case 5: (void) make_hallucinated((HHallucination & TIMEOUT) + lcount, TRUE, 0L); break; case 6: if (Deaf) /* make_deaf() won't give feedback when already deaf */ pline("Nothing seems to happen."); make_deaf((HDeaf & TIMEOUT) + lcount, TRUE); break; } return; } /* * Entries in the trouble list use a very simple encoding scheme. */ #define prop2trbl(X) ((X) + A_MAX) #define attr2trbl(Y) (Y) #define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X) #define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y) #define TimedTrouble(P) (((P) && !((P) & ~TIMEOUT)) ? ((P) & TIMEOUT) : 0L) trouble_count = unfixable_trbl = did_prop = did_attr = 0; /* collect property troubles */ if (TimedTrouble(Sick)) prop_trouble(SICK); if (TimedTrouble(Blinded) > (long) u.ucreamed && !(u.uswallow && attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))) prop_trouble(BLINDED); if (TimedTrouble(HHallucination)) prop_trouble(HALLUC); if (TimedTrouble(Vomiting)) prop_trouble(VOMITING); if (TimedTrouble(HConfusion)) prop_trouble(CONFUSION); if (TimedTrouble(HStun)) prop_trouble(STUNNED); if (TimedTrouble(HDeaf)) prop_trouble(DEAF); unfixable_trbl = unfixable_trouble_count(TRUE); /* collect attribute troubles */ for (idx = 0; idx < A_MAX; idx++) { if (ABASE(idx) >= AMAX(idx)) continue; val_limit = AMAX(idx); /* don't recover strength lost from hunger */ if (idx == A_STR && u.uhs >= WEAK) val_limit--; if (Fixed_abil) { /* potion/spell of restore ability override sustain ability intrinsic but unicorn horn usage doesn't */ unfixable_trbl += val_limit - ABASE(idx); continue; } /* don't recover more than 3 points worth of any attribute */ if (val_limit > ABASE(idx) + 3) val_limit = ABASE(idx) + 3; for (val = ABASE(idx); val < val_limit; val++) attr_trouble(idx); /* keep track of unfixed trouble, for message adjustment below */ unfixable_trbl += (AMAX(idx) - val_limit); } if (trouble_count == 0) { pline1(nothing_happens); return; } else if (trouble_count > 1) { /* shuffle */ int i, j, k; for (i = trouble_count - 1; i > 0; i--) if ((j = rn2(i + 1)) != i) { k = trouble_list[j]; trouble_list[j] = trouble_list[i]; trouble_list[i] = k; } } /* * Chances for number of troubles to be fixed * 0 1 2 3 4 5 6 7 * blessed: 22.7% 22.7% 19.5% 15.4% 10.7% 5.7% 2.6% 0.8% * uncursed: 35.4% 35.4% 22.9% 6.3% 0 0 0 0 */ val_limit = rn2(d(2, (obj && obj->blessed) ? 4 : 2)); if (val_limit > trouble_count) val_limit = trouble_count; /* fix [some of] the troubles */ for (val = 0; val < val_limit; val++) { idx = trouble_list[val]; switch (idx) { case prop2trbl(SICK): make_sick(0L, (char *) 0, TRUE, SICK_ALL); did_prop++; break; case prop2trbl(BLINDED): make_blinded((long) u.ucreamed, TRUE); did_prop++; break; case prop2trbl(HALLUC): (void) make_hallucinated(0L, TRUE, 0L); did_prop++; break; case prop2trbl(VOMITING): make_vomiting(0L, TRUE); did_prop++; break; case prop2trbl(CONFUSION): make_confused(0L, TRUE); did_prop++; break; case prop2trbl(STUNNED): make_stunned(0L, TRUE); did_prop++; break; case prop2trbl(DEAF): make_deaf(0L, TRUE); did_prop++; break; default: if (idx >= 0 && idx < A_MAX) { ABASE(idx) += 1; did_attr++; } else panic("use_unicorn_horn: bad trouble? (%d)", idx); break; } } if (did_attr) pline("This makes you feel %s!", (did_prop + did_attr) == (trouble_count + unfixable_trbl) ? "great" : "better"); else if (!did_prop) pline("Nothing seems to happen."); context.botl = (did_attr || did_prop); #undef PROP_COUNT #undef ATTR_COUNT #undef prop2trbl #undef attr2trbl #undef prop_trouble #undef attr_trouble #undef TimedTrouble } /* * Timer callback routine: turn figurine into monster */ void fig_transform(arg, timeout) anything *arg; long timeout; { struct obj *figurine = arg->a_obj; struct monst *mtmp; coord cc; boolean cansee_spot, silent, okay_spot; boolean redraw = FALSE; boolean suppress_see = FALSE; char monnambuf[BUFSZ], carriedby[BUFSZ]; if (!figurine) { debugpline0("null figurine in fig_transform()"); return; } silent = (timeout != monstermoves); /* happened while away */ okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0); if (figurine->where == OBJ_INVENT || figurine->where == OBJ_MINVENT) okay_spot = enexto(&cc, cc.x, cc.y, &mons[figurine->corpsenm]); if (!okay_spot || !figurine_location_checks(figurine, &cc, TRUE)) { /* reset the timer to try again later */ (void) start_timer((long) rnd(5000), TIMER_OBJECT, FIG_TRANSFORM, obj_to_any(figurine)); return; } cansee_spot = cansee(cc.x, cc.y); mtmp = make_familiar(figurine, cc.x, cc.y, TRUE); if (mtmp) { char and_vanish[BUFSZ]; struct obj *mshelter = level.objects[mtmp->mx][mtmp->my]; Sprintf(monnambuf, "%s", an(m_monnam(mtmp))); and_vanish[0] = '\0'; if ((mtmp->minvis && !See_invisible) || (mtmp->data->mlet == S_MIMIC && mtmp->m_ap_type != M_AP_NOTHING)) suppress_see = TRUE; if (mtmp->mundetected) { if (hides_under(mtmp->data) && mshelter) { Sprintf(and_vanish, " and %s under %s", locomotion(mtmp->data, "crawl"), doname(mshelter)); } else if (mtmp->data->mlet == S_MIMIC || mtmp->data->mlet == S_EEL) { suppress_see = TRUE; } else Strcpy(and_vanish, " and vanish"); } switch (figurine->where) { case OBJ_INVENT: if (Blind || suppress_see) You_feel("%s %s from your pack!", something, locomotion(mtmp->data, "drop")); else You_see("%s %s out of your pack%s!", monnambuf, locomotion(mtmp->data, "drop"), and_vanish); break; case OBJ_FLOOR: if (cansee_spot && !silent) { if (suppress_see) pline("%s suddenly vanishes!", an(xname(figurine))); else You_see("a figurine transform into %s%s!", monnambuf, and_vanish); redraw = TRUE; /* update figurine's map location */ } break; case OBJ_MINVENT: if (cansee_spot && !silent && !suppress_see) { struct monst *mon; mon = figurine->ocarry; /* figurine carrying monster might be invisible */ if (canseemon(figurine->ocarry)) { Sprintf(carriedby, "%s pack", s_suffix(a_monnam(mon))); } else if (is_pool(mon->mx, mon->my)) Strcpy(carriedby, "empty water"); else Strcpy(carriedby, "thin air"); You_see("%s %s out of %s%s!", monnambuf, locomotion(mtmp->data, "drop"), carriedby, and_vanish); } break; #if 0 case OBJ_MIGRATING: break; #endif default: impossible("figurine came to life where? (%d)", (int) figurine->where); break; } } /* free figurine now */ if (carried(figurine)) { useup(figurine); } else { obj_extract_self(figurine); obfree(figurine, (struct obj *) 0); } if (redraw) newsym(cc.x, cc.y); } STATIC_OVL boolean figurine_location_checks(obj, cc, quietly) struct obj *obj; coord *cc; boolean quietly; { xchar x, y; if (carried(obj) && u.uswallow) { if (!quietly) You("don't have enough room in here."); return FALSE; } x = cc ? cc->x : u.ux; y = cc ? cc->y : u.uy; if (!isok(x, y)) { if (!quietly) You("cannot put the figurine there."); return FALSE; } if (IS_ROCK(levl[x][y].typ) && !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x, y))) { if (!quietly) You("cannot place a figurine in %s!", IS_TREE(levl[x][y].typ) ? "a tree" : "solid rock"); return FALSE; } if (sobj_at(BOULDER, x, y) && !passes_walls(&mons[obj->corpsenm]) && !throws_rocks(&mons[obj->corpsenm])) { if (!quietly) You("cannot fit the figurine on the boulder."); return FALSE; } return TRUE; } STATIC_OVL void use_figurine(optr) struct obj **optr; { register struct obj *obj = *optr; xchar x, y; coord cc; if (u.uswallow) { /* can't activate a figurine while swallowed */ if (!figurine_location_checks(obj, (coord *) 0, FALSE)) return; } if (!getdir((char *) 0)) { context.move = multi = 0; return; } x = u.ux + u.dx; y = u.uy + u.dy; cc.x = x; cc.y = y; /* Passing FALSE arg here will result in messages displayed */ if (!figurine_location_checks(obj, &cc, FALSE)) return; You("%s and it transforms.", (u.dx || u.dy) ? "set the figurine beside you" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || is_pool(cc.x, cc.y)) ? "release the figurine" : (u.dz < 0 ? "toss the figurine into the air" : "set the figurine on the ground")); (void) make_familiar(obj, cc.x, cc.y, FALSE); (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj)); useup(obj); *optr = 0; } static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 }; STATIC_OVL void use_grease(obj) struct obj *obj; { struct obj *otmp; if (Glib) { pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); dropx(obj); return; } if (obj->spe > 0) { if ((obj->cursed || Fumbling) && !rn2(2)) { consume_obj_charge(obj, TRUE); pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); dropx(obj); return; } otmp = getobj(lubricables, "grease"); if (!otmp) return; if (inaccessible_equipment(otmp, "grease", FALSE)) return; consume_obj_charge(obj, TRUE); if (otmp != &zeroobj) { You("cover %s with a thick layer of grease.", yname(otmp)); otmp->greased = 1; if (obj->cursed && !nohands(youmonst.data)) { incr_itimeout(&Glib, rnd(15)); pline("Some of the grease gets all over your %s.", makeplural(body_part(HAND))); } } else { incr_itimeout(&Glib, rnd(15)); You("coat your %s with grease.", makeplural(body_part(FINGER))); } } else { if (obj->known) pline("%s empty.", Tobjnam(obj, "are")); else pline("%s to be empty.", Tobjnam(obj, "seem")); } update_inventory(); } static struct trapinfo { struct obj *tobj; xchar tx, ty; int time_needed; boolean force_bungle; } trapinfo; void reset_trapset() { trapinfo.tobj = 0; trapinfo.force_bungle = 0; } /* touchstones - by Ken Arnold */ STATIC_OVL void use_stone(tstone) struct obj *tstone; { struct obj *obj; boolean do_scratch; const char *streak_color, *choices; char stonebuf[QBUFSZ]; static const char scritch[] = "\"scritch, scritch\""; static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 }; static const char coins_gems[3] = { COIN_CLASS, GEM_CLASS, 0 }; /* in case it was acquired while blinded */ if (!Blind) tstone->dknown = 1; /* when the touchstone is fully known, don't bother listing extra junk as likely candidates for rubbing */ choices = (tstone->otyp == TOUCHSTONE && tstone->dknown && objects[TOUCHSTONE].oc_name_known) ? coins_gems : allowall; Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan)); if ((obj = getobj(choices, stonebuf)) == 0) return; if (obj == tstone && obj->quan == 1L) { You_cant("rub %s on itself.", the(xname(obj))); return; } if (tstone->otyp == TOUCHSTONE && tstone->cursed && obj->oclass == GEM_CLASS && !is_graystone(obj) && !obj_resists(obj, 80, 100)) { if (Blind) pline("You feel something shatter."); else if (Hallucination) pline("Oh, wow, look at the pretty shards."); else pline("A sharp crack shatters %s%s.", (obj->quan > 1L) ? "one of " : "", the(xname(obj))); useup(obj); return; } if (Blind) { pline(scritch); return; } else if (Hallucination) { pline("Oh wow, man: Fractals!"); return; } do_scratch = FALSE; streak_color = 0; switch (obj->oclass) { case GEM_CLASS: /* these have class-specific handling below */ case RING_CLASS: if (tstone->otyp != TOUCHSTONE) { do_scratch = TRUE; } else if (obj->oclass == GEM_CLASS && (tstone->blessed || (!tstone->cursed && (Role_if(PM_ARCHEOLOGIST) || Race_if(PM_GNOME))))) { makeknown(TOUCHSTONE); makeknown(obj->otyp); prinv((char *) 0, obj, 0L); return; } else { /* either a ring or the touchstone was not effective */ if (objects[obj->otyp].oc_material == GLASS) { do_scratch = TRUE; break; } } streak_color = c_obj_colors[objects[obj->otyp].oc_color]; break; /* gem or ring */ default: switch (objects[obj->otyp].oc_material) { case CLOTH: pline("%s a little more polished now.", Tobjnam(tstone, "look")); return; case LIQUID: if (!obj->known) /* note: not "whetstone" */ You("must think this is a wetstone, do you?"); else pline("%s a little wetter now.", Tobjnam(tstone, "are")); return; case WAX: streak_color = "waxy"; break; /* okay even if not touchstone */ case WOOD: streak_color = "wooden"; break; /* okay even if not touchstone */ case GOLD: do_scratch = TRUE; /* scratching and streaks */ streak_color = "golden"; break; case SILVER: do_scratch = TRUE; /* scratching and streaks */ streak_color = "silvery"; break; default: /* Objects passing the is_flimsy() test will not scratch a stone. They will leave streaks on non-touchstones and touchstones alike. */ if (is_flimsy(obj)) streak_color = c_obj_colors[objects[obj->otyp].oc_color]; else do_scratch = (tstone->otyp != TOUCHSTONE); break; } break; /* default oclass */ } Sprintf(stonebuf, "stone%s", plur(tstone->quan)); if (do_scratch) You("make %s%sscratch marks on the %s.", streak_color ? streak_color : (const char *) "", streak_color ? " " : "", stonebuf); else if (streak_color) You_see("%s streaks on the %s.", streak_color, stonebuf); else pline(scritch); return; } /* Place a landmine/bear trap. Helge Hafting */ STATIC_OVL void use_trap(otmp) struct obj *otmp; { int ttyp, tmp; const char *what = (char *) 0; char buf[BUFSZ]; int levtyp = levl[u.ux][u.uy].typ; const char *occutext = "setting the trap"; if (nohands(youmonst.data)) what = "without hands"; else if (Stunned) what = "while stunned"; else if (u.uswallow) what = is_animal(u.ustuck->data) ? "while swallowed" : "while engulfed"; else if (Underwater) what = "underwater"; else if (Levitation) what = "while levitating"; else if (is_pool(u.ux, u.uy)) what = "in water"; else if (is_lava(u.ux, u.uy)) what = "in lava"; else if (On_stairs(u.ux, u.uy)) what = (u.ux == xdnladder || u.ux == xupladder) ? "on the ladder" : "on the stairs"; else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp) || closed_door(u.ux, u.uy) || t_at(u.ux, u.uy)) what = "here"; else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) what = (levtyp == AIR) ? "in midair" : (levtyp == CLOUD) ? "in a cloud" : "in this place"; /* Air/Water Plane catch-all */ if (what) { You_cant("set a trap %s!", what); reset_trapset(); return; } ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP; if (otmp == trapinfo.tobj && u.ux == trapinfo.tx && u.uy == trapinfo.ty) { You("resume setting %s%s.", shk_your(buf, otmp), defsyms[trap_to_defsym(what_trap(ttyp))].explanation); set_occupation(set_trap, occutext, 0); return; } trapinfo.tobj = otmp; trapinfo.tx = u.ux, trapinfo.ty = u.uy; tmp = ACURR(A_DEX); trapinfo.time_needed = (tmp > 17) ? 2 : (tmp > 12) ? 3 : (tmp > 7) ? 4 : 5; if (Blind) trapinfo.time_needed *= 2; tmp = ACURR(A_STR); if (ttyp == BEAR_TRAP && tmp < 18) trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4; /*[fumbling and/or confusion and/or cursed object check(s) should be incorporated here instead of in set_trap]*/ if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { boolean chance; if (Fumbling || otmp->cursed) chance = (rnl(10) > 3); else chance = (rnl(10) > 5); You("aren't very skilled at reaching from %s.", mon_nam(u.usteed)); Sprintf(buf, "Continue your attempt to set %s?", the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); if (yn(buf) == 'y') { if (chance) { switch (ttyp) { case LANDMINE: /* set it off */ trapinfo.time_needed = 0; trapinfo.force_bungle = TRUE; break; case BEAR_TRAP: /* drop it without arming it */ reset_trapset(); You("drop %s!", the(defsyms[trap_to_defsym(what_trap(ttyp))] .explanation)); dropx(otmp); return; } } } else { reset_trapset(); return; } } You("begin setting %s%s.", shk_your(buf, otmp), defsyms[trap_to_defsym(what_trap(ttyp))].explanation); set_occupation(set_trap, occutext, 0); return; } STATIC_PTR int set_trap() { struct obj *otmp = trapinfo.tobj; struct trap *ttmp; int ttyp; if (!otmp || !carried(otmp) || u.ux != trapinfo.tx || u.uy != trapinfo.ty) { /* ?? */ reset_trapset(); return 0; } if (--trapinfo.time_needed > 0) return 1; /* still busy */ ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP; ttmp = maketrap(u.ux, u.uy, ttyp); if (ttmp) { ttmp->madeby_u = 1; feeltrap(ttmp); if (*in_rooms(u.ux, u.uy, SHOPBASE)) { add_damage(u.ux, u.uy, 0L); /* schedule removal */ } if (!trapinfo.force_bungle) You("finish arming %s.", the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); if (((otmp->cursed || Fumbling) && (rnl(10) > 5)) || trapinfo.force_bungle) dotrap(ttmp, (unsigned) (trapinfo.force_bungle ? FORCEBUNGLE : 0)); } else { /* this shouldn't happen */ Your("trap setting attempt fails."); } useup(otmp); reset_trapset(); return 0; } STATIC_OVL int use_whip(obj) struct obj *obj; { char buf[BUFSZ]; struct monst *mtmp; struct obj *otmp; int rx, ry, proficient, res = 0; const char *msg_slipsfree = "The bullwhip slips free."; const char *msg_snap = "Snap!"; if (obj != uwep) { if (!wield_tool(obj, "lash")) return 0; else res = 1; } if (!getdir((char *) 0)) return res; if (u.uswallow) { mtmp = u.ustuck; rx = mtmp->mx; ry = mtmp->my; } else { if (Stunned || (Confusion && !rn2(5))) confdir(); rx = u.ux + u.dx; ry = u.uy + u.dy; if (!isok(rx, ry)) { You("miss."); return res; } mtmp = m_at(rx, ry); } /* fake some proficiency checks */ proficient = 0; if (Role_if(PM_ARCHEOLOGIST)) ++proficient; if (ACURR(A_DEX) < 6) proficient--; else if (ACURR(A_DEX) >= 14) proficient += (ACURR(A_DEX) - 14); if (Fumbling) --proficient; if (proficient > 3) proficient = 3; if (proficient < 0) proficient = 0; if (u.uswallow && attack(u.ustuck)) { There("is not enough room to flick your bullwhip."); } else if (Underwater) { There("is too much resistance to flick your bullwhip."); } else if (u.dz < 0) { You("flick a bug off of the %s.", ceiling(u.ux, u.uy)); } else if ((!u.dx && !u.dy) || (u.dz > 0)) { int dam; /* Sometimes you hit your steed by mistake */ if (u.usteed && !rn2(proficient + 2)) { You("whip %s!", mon_nam(u.usteed)); kick_steed(); return 1; } if (Levitation || u.usteed) { /* Have a shot at snaring something on the floor */ otmp = level.objects[u.ux][u.uy]; if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) { pline("Why beat a dead horse?"); return 1; } if (otmp && proficient) { You("wrap your bullwhip around %s on the %s.", an(singular(otmp, xname)), surface(u.ux, u.uy)); if (rnl(6) || pickup_object(otmp, 1L, TRUE) < 1) pline1(msg_slipsfree); return 1; } } dam = rnd(2) + dbon() + obj->spe; if (dam <= 0) dam = 1; You("hit your %s with your bullwhip.", body_part(FOOT)); Sprintf(buf, "killed %sself with %s bullwhip", uhim(), uhis()); losehp(Maybe_Half_Phys(dam), buf, NO_KILLER_PREFIX); context.botl = 1; return 1; } else if ((Fumbling || Glib) && !rn2(5)) { pline_The("bullwhip slips out of your %s.", body_part(HAND)); dropx(obj); } else if (u.utrap && u.utraptype == TT_PIT) { /* * Assumptions: * * if you're in a pit * - you are attempting to get out of the pit * or, if you are applying it towards a small monster * - then it is assumed that you are trying to hit it * else if the monster is wielding a weapon * - you are attempting to disarm a monster * else * - you are attempting to hit the monster. * * if you're confused (and thus off the mark) * - you only end up hitting. * */ const char *wrapped_what = (char *) 0; if (mtmp) { if (bigmonst(mtmp->data)) { wrapped_what = strcpy(buf, mon_nam(mtmp)); } else if (proficient) { if (attack(mtmp)) return 1; else pline1(msg_snap); } } if (!wrapped_what) { if (IS_FURNITURE(levl[rx][ry].typ)) wrapped_what = something; else if (sobj_at(BOULDER, rx, ry)) wrapped_what = "a boulder"; } if (wrapped_what) { coord cc; cc.x = rx; cc.y = ry; You("wrap your bullwhip around %s.", wrapped_what); if (proficient && rn2(proficient + 2)) { if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) { You("yank yourself out of the pit!"); teleds(cc.x, cc.y, TRUE); u.utrap = 0; vision_full_recalc = 1; } } else { pline1(msg_slipsfree); } if (mtmp) wakeup(mtmp); } else pline1(msg_snap); } else if (mtmp) { if (!canspotmon(mtmp) && !glyph_is_invisible(levl[rx][ry].glyph)) { pline("A monster is there that you couldn't see."); map_invisible(rx, ry); } otmp = MON_WEP(mtmp); /* can be null */ if (otmp) { char onambuf[BUFSZ]; const char *mon_hand; boolean gotit = proficient && (!Fumbling || !rn2(10)); Strcpy(onambuf, cxname(otmp)); if (gotit) { mon_hand = mbodypart(mtmp, HAND); if (bimanual(otmp)) mon_hand = makeplural(mon_hand); } else mon_hand = 0; /* lint suppression */ You("wrap your bullwhip around %s.", yname(otmp)); if (gotit && mwelded(otmp)) { pline("%s welded to %s %s%c", (otmp->quan == 1L) ? "It is" : "They are", mhis(mtmp), mon_hand, !otmp->bknown ? '!' : '.'); otmp->bknown = 1; gotit = FALSE; /* can't pull it free */ } if (gotit) { obj_extract_self(otmp); possibly_unwield(mtmp, FALSE); setmnotwielded(mtmp, otmp); switch (rn2(proficient + 1)) { case 2: /* to floor near you */ You("yank %s to the %s!", yname(otmp), surface(u.ux, u.uy)); place_object(otmp, u.ux, u.uy); stackobj(otmp); break; case 3: #if 0 /* right to you */ if (!rn2(25)) { /* proficient with whip, but maybe not so proficient at catching weapons */ int hitu, hitvalu; hitvalu = 8 + otmp->spe; hitu = thitu(hitvalu, dmgval(otmp, &youmonst), otmp, (char *)0); if (hitu) { pline_The("%s hits you as you try to snatch it!", the(onambuf)); } place_object(otmp, u.ux, u.uy); stackobj(otmp); break; } #endif /* 0 */ /* right into your inventory */ You("snatch %s!", yname(otmp)); if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !uarmg && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { char kbuf[BUFSZ]; Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname)); pline("Snatching %s is a fatal mistake.", kbuf); instapetrify(kbuf); } otmp = hold_another_object( otmp, "You drop %s!", doname(otmp), (const char *) 0); break; default: /* to floor beneath mon */ You("yank %s from %s %s!", the(onambuf), s_suffix(mon_nam(mtmp)), mon_hand); obj_no_longer_held(otmp); place_object(otmp, mtmp->mx, mtmp->my); stackobj(otmp); break; } } else { pline1(msg_slipsfree); } wakeup(mtmp); } else { if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp)) stumble_onto_mimic(mtmp); else You("flick your bullwhip towards %s.", mon_nam(mtmp)); if (proficient) { if (attack(mtmp)) return 1; else pline1(msg_snap); } } } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { /* it must be air -- water checked above */ You("snap your whip through thin air."); } else { pline1(msg_snap); } return 1; } static const char not_enough_room[] = "There's not enough room here to use that.", where_to_hit[] = "Where do you want to hit?", cant_see_spot[] = "won't hit anything if you can't see that spot.", cant_reach[] = "can't reach that spot from here."; /* find pos of monster in range, if only one monster */ boolean find_poleable_mon(pos, min_range, max_range) coord *pos; int min_range, max_range; { struct monst *mtmp; struct monst *selmon = (struct monst *) 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp && !DEADMONSTER(mtmp) && !mtmp->mtame && cansee(mtmp->mx, mtmp->my) && distu(mtmp->mx, mtmp->my) <= max_range && distu(mtmp->mx, mtmp->my) >= min_range) { if (selmon) return FALSE; selmon = mtmp; } if (!selmon) return FALSE; pos->x = selmon->mx; pos->y = selmon->my; return TRUE; } static int polearm_range_min = -1; static int polearm_range_max = -1; void display_polearm_positions(state) int state; { if (state == 0) { tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos)); } else if (state == 1) { int x, y, dx, dy; for (dx = -4; dx <= 4; dx++) for (dy = -4; dy <= 4; dy++) { x = dx + (int) u.ux; y = dy + (int) u.uy; if (isok(x, y) && ACCESSIBLE(levl[x][y].typ) && distu(x, y) >= polearm_range_min && distu(x, y) <= polearm_range_max) { tmp_at(x, y); } } } else { tmp_at(DISP_END, 0); } } /* Distance attacks by pole-weapons */ STATIC_OVL int use_pole(obj) struct obj *obj; { int res = 0, typ, max_range, min_range, glyph; coord cc; struct monst *mtmp; struct monst *hitm = context.polearm.hitmon; /* Are you allowed to use the pole? */ if (u.uswallow) { pline(not_enough_room); return 0; } if (obj != uwep) { if (!wield_tool(obj, "swing")) return 0; else res = 1; } /* assert(obj == uwep); */ /* * Calculate allowable range (pole's reach is always 2 steps): * unskilled and basic: orthogonal direction, 4..4; * skilled: as basic, plus knight's jump position, 4..5; * expert: as skilled, plus diagonal, 4..8. * ...9... * .85458. * .52125. * 9410149 * .52125. * .85458. * ...9... * (Note: no roles in nethack can become expert or better * for polearm skill; Yeoman in slash'em can become expert.) */ min_range = 4; typ = uwep_skill_type(); if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4; else if (P_SKILL(typ) == P_SKILLED) max_range = 5; else max_range = 8; /* (P_SKILL(typ) >= P_EXPERT) */ polearm_range_min = min_range; polearm_range_max = max_range; /* Prompt for a location */ pline(where_to_hit); cc.x = u.ux; cc.y = u.uy; if (!find_poleable_mon(&cc, min_range, max_range) && hitm && !DEADMONSTER(hitm) && cansee(hitm->mx, hitm->my) && distu(hitm->mx, hitm->my) <= max_range && distu(hitm->mx, hitm->my) >= min_range) { cc.x = hitm->mx; cc.y = hitm->my; } getpos_sethilite(display_polearm_positions); if (getpos(&cc, TRUE, "the spot to hit") < 0) return res; /* ESC; uses turn iff polearm became wielded */ glyph = glyph_at(cc.x, cc.y); if (distu(cc.x, cc.y) > max_range) { pline("Too far!"); return res; } else if (distu(cc.x, cc.y) < min_range) { pline("Too close!"); return res; } else if (!cansee(cc.x, cc.y) && !glyph_is_monster(glyph) && !glyph_is_invisible(glyph) && !glyph_is_statue(glyph)) { You(cant_see_spot); return res; } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */ You(cant_reach); return res; } context.polearm.hitmon = NULL; /* Attack the monster there */ bhitpos = cc; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *) 0) { if (attack_checks(mtmp, uwep)) return res; if (overexertion()) return 1; /* burn nutrition; maybe pass out */ context.polearm.hitmon = mtmp; check_caitiff(mtmp); notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my); (void) thitmonst(mtmp, uwep); } else if (glyph_is_statue(glyph) /* might be hallucinatory */ && sobj_at(STATUE, bhitpos.x, bhitpos.y)) { struct trap *t = t_at(bhitpos.x, bhitpos.y); if (t && t->ttyp == STATUE_TRAP && activate_statue_trap(t, t->tx, t->ty, FALSE)) { ; /* feedback has been give by animate_statue() */ } else { /* Since statues look like monsters now, we say something different from "you miss" or "there's nobody there". Note: we only do this when a statue is displayed here, because the player is probably attempting to attack it; other statues obscured by anything are just ignored. */ pline("Thump! Your blow bounces harmlessly off the statue."); wake_nearto(bhitpos.x, bhitpos.y, 25); } } else { /* no monster here and no statue seen or remembered here */ if (glyph_is_invisible(glyph)) { /* now you know that nothing is there... */ unmap_object(bhitpos.x, bhitpos.y); newsym(bhitpos.x, bhitpos.y); } You("miss; there is no one there to hit."); } u_wipe_engr(2); /* same as for melee or throwing */ return 1; } STATIC_OVL int use_cream_pie(obj) struct obj *obj; { boolean wasblind = Blind; boolean wascreamed = u.ucreamed; boolean several = FALSE; if (obj->quan > 1L) { several = TRUE; obj = splitobj(obj, 1L); } if (Hallucination) You("give yourself a facial."); else pline("You immerse your %s in %s%s.", body_part(FACE), several ? "one of " : "", several ? makeplural(the(xname(obj))) : the(xname(obj))); if (can_blnd((struct monst *) 0, &youmonst, AT_WEAP, obj)) { int blindinc = rnd(25); u.ucreamed += blindinc; make_blinded(Blinded + (long) blindinc, FALSE); if (!Blind || (Blind && wasblind)) pline("There's %ssticky goop all over your %s.", wascreamed ? "more " : "", body_part(FACE)); else /* Blind && !wasblind */ You_cant("see through all the sticky goop on your %s.", body_part(FACE)); } setnotworn(obj); /* useup() is appropriate, but we want costly_alteration()'s message */ costly_alteration(obj, COST_SPLAT); obj_extract_self(obj); delobj(obj); return 0; } STATIC_OVL int use_grapple(obj) struct obj *obj; { int res = 0, typ, max_range = 4, tohit; boolean save_confirm; coord cc; struct monst *mtmp; struct obj *otmp; /* Are you allowed to use the hook? */ if (u.uswallow) { pline(not_enough_room); return 0; } if (obj != uwep) { if (!wield_tool(obj, "cast")) return 0; else res = 1; } /* assert(obj == uwep); */ /* Prompt for a location */ pline(where_to_hit); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the spot to hit") < 0) return res; /* ESC; uses turn iff grapnel became wielded */ /* Calculate range; unlike use_pole(), there's no minimum for range */ typ = uwep_skill_type(); if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4; else if (P_SKILL(typ) == P_SKILLED) max_range = 5; else max_range = 8; if (distu(cc.x, cc.y) > max_range) { pline("Too far!"); return res; } else if (!cansee(cc.x, cc.y)) { You(cant_see_spot); return res; } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */ You(cant_reach); return res; } /* What do you want to hit? */ tohit = rn2(5); if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) { winid tmpwin = create_nhwindow(NHW_MENU); anything any; char buf[BUFSZ]; menu_item *selected; any = zeroany; /* set all bits to zero */ any.a_int = 1; /* use index+1 (cant use 0) as identifier */ start_menu(tmpwin); any.a_int++; Sprintf(buf, "an object on the %s", surface(cc.x, cc.y)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); any.a_int++; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "a monster", MENU_UNSELECTED); any.a_int++; Sprintf(buf, "the %s", surface(cc.x, cc.y)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); end_menu(tmpwin, "Aim for what?"); tohit = rn2(4); if (select_menu(tmpwin, PICK_ONE, &selected) > 0 && rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2)) tohit = selected[0].item.a_int - 1; free((genericptr_t) selected); destroy_nhwindow(tmpwin); } /* possibly scuff engraving at your feet; any engraving at the target location is unaffected */ if (tohit == 2 || !rn2(2)) u_wipe_engr(rnd(2)); /* What did you hit? */ switch (tohit) { case 0: /* Trap */ /* FIXME -- untrap needs to deal with non-adjacent traps */ break; case 1: /* Object */ if ((otmp = level.objects[cc.x][cc.y]) != 0) { You("snag an object from the %s!", surface(cc.x, cc.y)); (void) pickup_object(otmp, 1L, FALSE); /* If pickup fails, leave it alone */ newsym(cc.x, cc.y); return 1; } break; case 2: /* Monster */ bhitpos = cc; if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *) 0) break; notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my); save_confirm = flags.confirm; if (verysmall(mtmp->data) && !rn2(4) && enexto(&cc, u.ux, u.uy, (struct permonst *) 0)) { flags.confirm = FALSE; (void) attack_checks(mtmp, uwep); flags.confirm = save_confirm; check_caitiff(mtmp); /* despite fact there's no damage */ You("pull in %s!", mon_nam(mtmp)); mtmp->mundetected = 0; rloc_to(mtmp, cc.x, cc.y); return 1; } else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data)) || rn2(4)) { flags.confirm = FALSE; (void) attack_checks(mtmp, uwep); flags.confirm = save_confirm; check_caitiff(mtmp); (void) thitmonst(mtmp, uwep); return 1; } /* FALL THROUGH */ case 3: /* Surface */ if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y)) pline_The("hook slices through the %s.", surface(cc.x, cc.y)); else { You("are yanked toward the %s!", surface(cc.x, cc.y)); hurtle(sgn(cc.x - u.ux), sgn(cc.y - u.uy), 1, FALSE); spoteffects(TRUE); } return 1; default: /* Yourself (oops!) */ if (P_SKILL(typ) <= P_BASIC) { You("hook yourself!"); losehp(Maybe_Half_Phys(rn1(10, 10)), "a grappling hook", KILLED_BY); return 1; } break; } pline1(nothing_happens); return 1; } #define BY_OBJECT ((struct monst *) 0) /* return 1 if the wand is broken, hence some time elapsed */ STATIC_OVL int do_break_wand(obj) struct obj *obj; { static const char nothing_else_happens[] = "But nothing else happens..."; register int i, x, y; register struct monst *mon; int dmg, damage; boolean affects_objects; boolean shop_damage = FALSE; boolean fillmsg = FALSE; int expltype = EXPL_MAGICAL; char confirm[QBUFSZ], buf[BUFSZ]; boolean is_fragile = (!strcmp(OBJ_DESCR(objects[obj->otyp]), "balsa")); if (!paranoid_query(ParanoidBreakwand, safe_qbuf(confirm, "Are you really sure you want to break ", "?", obj, yname, ysimple_name, "the wand"))) return 0; if (nohands(youmonst.data)) { You_cant("break %s without hands!", yname(obj)); return 0; } else if (ACURR(A_STR) < (is_fragile ? 5 : 10)) { You("don't have the strength to break %s!", yname(obj)); return 0; } pline("Raising %s high above your %s, you break it in two!", yname(obj), body_part(HEAD)); /* [ALI] Do this first so that wand is removed from bill. Otherwise, * the freeinv() below also hides it from setpaid() which causes problems. */ if (obj->unpaid) { check_unpaid(obj); /* Extra charge for use */ costly_alteration(obj, COST_DSTROY); } current_wand = obj; /* destroy_item might reset this */ freeinv(obj); /* hide it from destroy_item instead... */ setnotworn(obj); /* so we need to do this ourselves */ if (!zappable(obj)) { pline(nothing_else_happens); goto discard_broken_wand; } /* successful call to zappable() consumes a charge; put it back */ obj->spe++; /* might have "wrested" a final charge, taking it from 0 to -1; if so, we just brought it back up to 0, which wouldn't do much below so give it 1..3 charges now, usually making it stronger than an ordinary last charge (the wand is already gone from inventory, so perm_invent can't accidentally reveal this) */ if (!obj->spe) obj->spe = rnd(3); obj->ox = u.ux; obj->oy = u.uy; dmg = obj->spe * 4; affects_objects = FALSE; switch (obj->otyp) { case WAN_WISHING: case WAN_NOTHING: case WAN_LOCKING: case WAN_PROBING: case WAN_ENLIGHTENMENT: case WAN_OPENING: case WAN_SECRET_DOOR_DETECTION: pline(nothing_else_happens); goto discard_broken_wand; case WAN_DEATH: case WAN_LIGHTNING: dmg *= 4; goto wanexpl; case WAN_FIRE: expltype = EXPL_FIERY; case WAN_COLD: if (expltype == EXPL_MAGICAL) expltype = EXPL_FROSTY; dmg *= 2; case WAN_MAGIC_MISSILE: wanexpl: explode(u.ux, u.uy, -(obj->otyp), dmg, WAND_CLASS, expltype); makeknown(obj->otyp); /* explode describes the effect */ goto discard_broken_wand; case WAN_STRIKING: /* we want this before the explosion instead of at the very end */ pline("A wall of force smashes down around you!"); dmg = d(1 + obj->spe, 6); /* normally 2d12 */ /*FALLTHRU*/ case WAN_CANCELLATION: case WAN_POLYMORPH: case WAN_TELEPORTATION: case WAN_UNDEAD_TURNING: affects_objects = TRUE; break; default: break; } /* magical explosion and its visual effect occur before specific effects */ /* [TODO? This really ought to prevent the explosion from being fatal so that we never leave a bones file where none of the surrounding targets (or underlying objects) got affected yet.] */ explode(obj->ox, obj->oy, -(obj->otyp), rnd(dmg), WAND_CLASS, EXPL_MAGICAL); /* prepare for potential feedback from polymorph... */ zapsetup(); /* this makes it hit us last, so that we can see the action first */ for (i = 0; i <= 8; i++) { bhitpos.x = x = obj->ox + xdir[i]; bhitpos.y = y = obj->oy + ydir[i]; if (!isok(x, y)) continue; if (obj->otyp == WAN_DIGGING) { schar typ; if (dig_check(BY_OBJECT, FALSE, x, y)) { if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) { /* normally, pits and holes don't anger guards, but they * do if it's a wall or door that's being dug */ watch_dig((struct monst *) 0, x, y, TRUE); if (*in_rooms(x, y, SHOPBASE)) shop_damage = TRUE; } /* * Let liquid flow into the newly created pits. * Adjust corresponding code in music.c for * drum of earthquake if you alter this sequence. */ typ = fillholetyp(x, y, FALSE); if (typ != ROOM) { levl[x][y].typ = typ; liquid_flow(x, y, typ, t_at(x, y), fillmsg ? (char *) 0 : "Some holes are quickly filled with %s!"); fillmsg = TRUE; } else digactualhole(x, y, BY_OBJECT, (rn2(obj->spe) < 3 || (!Can_dig_down(&u.uz) && !levl[x][y].candig)) ? PIT : HOLE); } continue; } else if (obj->otyp == WAN_CREATE_MONSTER) { /* u.ux,u.uy creates it near you--x,y might create it in rock */ (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); continue; } else if (x != u.ux || y != u.uy) { /* * Wand breakage is targetting a square adjacent to the hero, * which might contain a monster or a pile of objects or both. * Handle objects last; avoids having undead turning raise an * undead's corpse and then attack resulting undead monster. * obj->bypass in bhitm() prevents the polymorphing of items * dropped due to monster's polymorph and prevents undead * turning that kills an undead from raising resulting corpse. */ if ((mon = m_at(x, y)) != 0) { (void) bhitm(mon, obj); /* if (context.botl) bot(); */ } if (affects_objects && level.objects[x][y]) { (void) bhitpile(obj, bhito, x, y, 0); if (context.botl) bot(); /* potion effects */ } } else { /* * Wand breakage is targetting the hero. Using xdir[]+ydir[] * deltas for location selection causes this case to happen * after all the surrounding squares have been handled. * Process objects first, in case damage is fatal and leaves * bones, or teleportation sends one or more of the objects to * same destination as hero (lookhere/autopickup); also avoids * the polymorphing of gear dropped due to hero's transformation. * (Unlike with monsters being hit by zaps, we can't rely on use * of obj->bypass in the zap code to accomplish that last case * since it's also used by retouch_equipment() for polyself.) */ if (affects_objects && level.objects[x][y]) { (void) bhitpile(obj, bhito, x, y, 0); if (context.botl) bot(); /* potion effects */ } damage = zapyourself(obj, FALSE); if (damage) { Sprintf(buf, "killed %sself by breaking a wand", uhim()); losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX); } if (context.botl) bot(); /* blindness */ } } /* potentially give post zap/break feedback */ zapwrapup(); /* Note: if player fell thru, this call is a no-op. Damage is handled in digactualhole in that case */ if (shop_damage) pay_for_damage("dig into", FALSE); if (obj->otyp == WAN_LIGHT) litroom(TRUE, obj); /* only needs to be done once */ discard_broken_wand: obj = current_wand; /* [see dozap() and destroy_item()] */ current_wand = 0; if (obj) delobj(obj); nomul(0); return 1; } STATIC_OVL void add_class(cl, class) char *cl; char class; { char tmp[2]; tmp[0] = class; tmp[1] = '\0'; Strcat(cl, tmp); } static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 }; /* augment tools[] if various items are carried */ STATIC_OVL void setapplyclasses(class_list) char class_list[]; { register struct obj *otmp; int otyp; boolean knowoil, knowtouchstone, addpotions, addstones, addfood; knowoil = objects[POT_OIL].oc_name_known; knowtouchstone = objects[TOUCHSTONE].oc_name_known; addpotions = addstones = addfood = FALSE; for (otmp = invent; otmp; otmp = otmp->nobj) { otyp = otmp->otyp; if (otyp == POT_OIL || (otmp->oclass == POTION_CLASS && (!otmp->dknown || (!knowoil && !objects[otyp].oc_name_known)))) addpotions = TRUE; if (otyp == TOUCHSTONE || (is_graystone(otmp) && (!otmp->dknown || (!knowtouchstone && !objects[otyp].oc_name_known)))) addstones = TRUE; if (otyp == CREAM_PIE || otyp == EUCALYPTUS_LEAF) addfood = TRUE; } class_list[0] = '\0'; if (addpotions || addstones) add_class(class_list, ALL_CLASSES); Strcat(class_list, tools); if (addpotions) add_class(class_list, POTION_CLASS); if (addstones) add_class(class_list, GEM_CLASS); if (addfood) add_class(class_list, FOOD_CLASS); } /* the 'a' command */ int doapply() { struct obj *obj; register int res = 1; char class_list[MAXOCLASSES + 2]; if (check_capacity((char *) 0)) return 0; setapplyclasses(class_list); /* tools[] */ obj = getobj(class_list, "use or apply"); if (!obj) return 0; if (!retouch_object(&obj, FALSE)) return 1; /* evading your grasp costs a turn; just be grateful that you don't drop it as well */ if (obj->oclass == WAND_CLASS) return do_break_wand(obj); switch (obj->otyp) { case BLINDFOLD: case LENSES: if (obj == ublindf) { if (!cursed(obj)) Blindf_off(obj); } else if (!ublindf) { Blindf_on(obj); } else { You("are already %s.", ublindf->otyp == TOWEL ? "covered by a towel" : ublindf->otyp == BLINDFOLD ? "wearing a blindfold" : "wearing lenses"); } break; case CREAM_PIE: res = use_cream_pie(obj); break; case BULLWHIP: res = use_whip(obj); break; case GRAPPLING_HOOK: res = use_grapple(obj); break; case LARGE_BOX: case CHEST: case ICE_BOX: case SACK: case BAG_OF_HOLDING: case OILSKIN_SACK: res = use_container(&obj, 1); break; case BAG_OF_TRICKS: (void) bagotricks(obj, FALSE, (int *) 0); break; case CAN_OF_GREASE: use_grease(obj); break; case LOCK_PICK: case CREDIT_CARD: case SKELETON_KEY: res = (pick_lock(obj) != 0); break; case PICK_AXE: case DWARVISH_MATTOCK: res = use_pick_axe(obj); break; case TINNING_KIT: use_tinning_kit(obj); break; case LEASH: use_leash(obj); break; case SADDLE: res = use_saddle(obj); break; case MAGIC_WHISTLE: use_magic_whistle(obj); break; case TIN_WHISTLE: use_whistle(obj); break; case EUCALYPTUS_LEAF: /* MRKR: Every Australian knows that a gum leaf makes an excellent * whistle, especially if your pet is a tame kangaroo named Skippy. */ if (obj->blessed) { use_magic_whistle(obj); /* sometimes the blessing will be worn off */ if (!rn2(49)) { if (!Blind) { pline("%s %s.", Yobjnam2(obj, "glow"), hcolor("brown")); obj->bknown = 1; } unbless(obj); } } else { use_whistle(obj); } break; case STETHOSCOPE: res = use_stethoscope(obj); break; case MIRROR: res = use_mirror(obj); break; case BELL: case BELL_OF_OPENING: use_bell(&obj); break; case CANDELABRUM_OF_INVOCATION: use_candelabrum(obj); break; case WAX_CANDLE: case TALLOW_CANDLE: use_candle(&obj); break; case OIL_LAMP: case MAGIC_LAMP: case BRASS_LANTERN: use_lamp(obj); break; case POT_OIL: light_cocktail(obj); break; case EXPENSIVE_CAMERA: res = use_camera(obj); break; case TOWEL: res = use_towel(obj); break; case CRYSTAL_BALL: use_crystal_ball(&obj); break; case MAGIC_MARKER: res = dowrite(obj); break; case TIN_OPENER: if (!carrying(TIN)) { You("have no tin to open."); goto xit; } You("cannot open a tin without eating or discarding its contents."); if (flags.verbose) pline("In order to eat, use the 'e' command."); if (obj != uwep) pline( "Opening the tin will be much easier if you wield the tin opener."); goto xit; case FIGURINE: use_figurine(&obj); break; case UNICORN_HORN: use_unicorn_horn(obj); break; case WOODEN_FLUTE: case MAGIC_FLUTE: case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: case WOODEN_HARP: case MAGIC_HARP: case BUGLE: case LEATHER_DRUM: case DRUM_OF_EARTHQUAKE: res = do_play_instrument(obj); break; case HORN_OF_PLENTY: /* not a musical instrument */ (void) hornoplenty(obj, FALSE); break; case LAND_MINE: case BEARTRAP: use_trap(obj); break; case FLINT: case LUCKSTONE: case LOADSTONE: case TOUCHSTONE: use_stone(obj); break; default: /* Pole-weapons can strike at a distance */ if (is_pole(obj)) { res = use_pole(obj); break; } else if (is_pick(obj) || is_axe(obj)) { res = use_pick_axe(obj); break; } pline("Sorry, I don't know how to use that."); xit: nomul(0); return 0; } if (res && obj && obj->oartifact) arti_speak(obj); nomul(0); return res; } /* Keep track of unfixable troubles for purposes of messages saying you feel * great. */ int unfixable_trouble_count(is_horn) boolean is_horn; { int unfixable_trbl = 0; if (Stoned) unfixable_trbl++; if (Strangled) unfixable_trbl++; if (Wounded_legs && !u.usteed) unfixable_trbl++; if (Slimed) unfixable_trbl++; /* lycanthropy is undesirable, but it doesn't actually make you feel bad */ if (!is_horn || (Confusion & ~TIMEOUT)) unfixable_trbl++; if (!is_horn || (Sick & ~TIMEOUT)) unfixable_trbl++; if (!is_horn || (HHallucination & ~TIMEOUT)) unfixable_trbl++; if (!is_horn || (Vomiting & ~TIMEOUT)) unfixable_trbl++; if (!is_horn || (HStun & ~TIMEOUT)) unfixable_trbl++; if (!is_horn || (HDeaf & ~TIMEOUT)) unfixable_trbl++; return unfixable_trbl; } /*apply.c*/ nethack-3.6.0/src/artifact.c0000664000076400007660000020723612623162643014704 0ustar paxedpaxed/* NetHack 3.6 artifact.c $NHDT-Date: 1446369462 2015/11/01 09:17:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.96 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" #include "artilist.h" /* * Note: both artilist[] and artiexist[] have a dummy element #0, * so loops over them should normally start at #1. The primary * exception is the save & restore code, which doesn't care about * the contents, just the total size. */ extern boolean notonhead; /* for long worms */ #define get_artifact(o) \ (((o) && (o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0) STATIC_DCL boolean FDECL(bane_applies, (const struct artifact *, struct monst *)); STATIC_DCL int FDECL(spec_applies, (const struct artifact *, struct monst *)); STATIC_DCL int FDECL(arti_invoke, (struct obj *)); STATIC_DCL boolean FDECL(Mb_hit, (struct monst * magr, struct monst *mdef, struct obj *, int *, int, BOOLEAN_P, char *)); STATIC_DCL unsigned long FDECL(abil_to_spfx, (long *)); STATIC_DCL uchar FDECL(abil_to_adtyp, (long *)); STATIC_DCL boolean FDECL(untouchable, (struct obj *, BOOLEAN_P)); /* The amount added to the victim's total hit points to insure that the victim will be killed even after damage bonus/penalty adjustments. Most such penalties are small, and 200 is plenty; the exception is half physical damage. 3.3.1 and previous versions tried to use a very large number to account for this case; now, we just compute the fatal damage by adding it to 2 times the total hit points instead of 1 time. Note: this will still break if they have more than about half the number of hit points that will fit in a 15 bit integer. */ #define FATAL_DAMAGE_MODIFIER 200 /* coordinate effects from spec_dbon() with messages in artifact_hit() */ STATIC_OVL int spec_dbon_applies = 0; /* flags including which artifacts have already been created */ static boolean artiexist[1 + NROFARTIFACTS + 1]; /* and a discovery list for them (no dummy first entry here) */ STATIC_OVL xchar artidisco[NROFARTIFACTS]; STATIC_DCL void NDECL(hack_artifacts); STATIC_DCL boolean FDECL(attacks, (int, struct obj *)); /* handle some special cases; must be called after u_init() */ STATIC_OVL void hack_artifacts() { struct artifact *art; int alignmnt = aligns[flags.initalign].value; /* Fix up the alignments of "gift" artifacts */ for (art = artilist + 1; art->otyp; art++) if (art->role == Role_switch && art->alignment != A_NONE) art->alignment = alignmnt; /* Excalibur can be used by any lawful character, not just knights */ if (!Role_if(PM_KNIGHT)) artilist[ART_EXCALIBUR].role = NON_PM; /* Fix up the quest artifact */ if (urole.questarti) { artilist[urole.questarti].alignment = alignmnt; artilist[urole.questarti].role = Role_switch; } return; } /* zero out the artifact existence list */ void init_artifacts() { (void) memset((genericptr_t) artiexist, 0, sizeof artiexist); (void) memset((genericptr_t) artidisco, 0, sizeof artidisco); hack_artifacts(); } void save_artifacts(fd) int fd; { bwrite(fd, (genericptr_t) artiexist, sizeof artiexist); bwrite(fd, (genericptr_t) artidisco, sizeof artidisco); } void restore_artifacts(fd) int fd; { mread(fd, (genericptr_t) artiexist, sizeof artiexist); mread(fd, (genericptr_t) artidisco, sizeof artidisco); hack_artifacts(); /* redo non-saved special cases */ } const char * artiname(artinum) int artinum; { if (artinum <= 0 || artinum > NROFARTIFACTS) return ""; return artilist[artinum].name; } /* Make an artifact. If a specific alignment is specified, then an object of the appropriate alignment is created from scratch, or 0 is returned if none is available. (If at least one aligned artifact has already been given, then unaligned ones also become eligible for this.) If no alignment is given, then 'otmp' is converted into an artifact of matching type, or returned as-is if that's not possible. For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);'' for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''. */ struct obj * mk_artifact(otmp, alignment) struct obj *otmp; /* existing object; ignored if alignment specified */ aligntyp alignment; /* target alignment, or A_NONE */ { const struct artifact *a; int m, n, altn; boolean by_align = (alignment != A_NONE); short o_typ = (by_align || !otmp) ? 0 : otmp->otyp; boolean unique = !by_align && otmp && objects[o_typ].oc_unique; short eligible[NROFARTIFACTS]; n = altn = 0; /* no candidates found yet */ eligible[0] = 0; /* lint suppression */ /* gather eligible artifacts */ for (m = 1, a = &artilist[m]; a->otyp; a++, m++) { if (artiexist[m]) continue; if ((a->spfx & SPFX_NOGEN) || unique) continue; if (!by_align) { /* looking for a particular type of item; not producing a divine gift so we don't care about role's first choice */ if (a->otyp == o_typ) eligible[n++] = m; continue; /* move on to next possibility */ } /* we're looking for an alignment-specific item suitable for hero's role+race */ if ((a->alignment == alignment || a->alignment == A_NONE) /* avoid enemies' equipment */ && (a->race == NON_PM || !race_hostile(&mons[a->race]))) { /* when a role-specific first choice is available, use it */ if (Role_if(a->role)) { /* make this be the only possibility in the list */ eligible[0] = m; n = 1; break; /* skip all other candidates */ } /* found something to consider for random selection */ if (a->alignment != A_NONE || u.ugifts > 0) { /* right alignment, or non-aligned with at least 1 previous gift bestowed, makes this one viable */ eligible[n++] = m; } else { /* non-aligned with no previous gifts; if no candidates have been found yet, record this one as a[nother] fallback possibility in case all aligned candidates have been used up (via wishing, naming, bones, random generation) */ if (!n) eligible[altn++] = m; /* [once a regular candidate is found, the list is overwritten and `altn' becomes irrelevant] */ } } } /* resort to fallback list if main list was empty */ if (!n) n = altn; if (n) { /* found at least one candidate; pick one at random */ m = eligible[rn2(n)]; /* [0..n-1] */ a = &artilist[m]; /* make an appropriate object if necessary, then christen it */ if (by_align) otmp = mksobj((int) a->otyp, TRUE, FALSE); if (otmp) { otmp = oname(otmp, a->name); otmp->oartifact = m; artiexist[m] = TRUE; } } else { /* nothing appropriate could be found; return original object */ if (by_align) otmp = 0; /* (there was no original object) */ } return otmp; } /* * Returns the full name (with articles and correct capitalization) of an * artifact named "name" if one exists, or NULL, it not. * The given name must be rather close to the real name for it to match. * The object type of the artifact is returned in otyp if the return value * is non-NULL. */ const char * artifact_name(name, otyp) const char *name; short *otyp; { register const struct artifact *a; register const char *aname; if (!strncmpi(name, "the ", 4)) name += 4; for (a = artilist + 1; a->otyp; a++) { aname = a->name; if (!strncmpi(aname, "the ", 4)) aname += 4; if (!strcmpi(name, aname)) { *otyp = a->otyp; return a->name; } } return (char *) 0; } boolean exist_artifact(otyp, name) int otyp; const char *name; { register const struct artifact *a; boolean *arex; if (otyp && *name) for (a = artilist + 1, arex = artiexist + 1; a->otyp; a++, arex++) if ((int) a->otyp == otyp && !strcmp(a->name, name)) return *arex; return FALSE; } void artifact_exists(otmp, name, mod) struct obj *otmp; const char *name; boolean mod; { register const struct artifact *a; if (otmp && *name) for (a = artilist + 1; a->otyp; a++) if (a->otyp == otmp->otyp && !strcmp(a->name, name)) { register int m = (int) (a - artilist); otmp->oartifact = (char) (mod ? m : 0); otmp->age = 0; if (otmp->otyp == RIN_INCREASE_DAMAGE) otmp->spe = 0; artiexist[m] = mod; break; } return; } int nartifact_exist() { int a = 0; int n = SIZE(artiexist); while (n > 1) if (artiexist[--n]) a++; return a; } boolean spec_ability(otmp, abil) struct obj *otmp; unsigned long abil; { const struct artifact *arti = get_artifact(otmp); return (boolean) (arti && (arti->spfx & abil) != 0L); } /* used so that callers don't need to known about SPFX_ codes */ boolean confers_luck(obj) struct obj *obj; { /* might as well check for this too */ if (obj->otyp == LUCKSTONE) return TRUE; return (boolean) (obj->oartifact && spec_ability(obj, SPFX_LUCK)); } /* used to check whether a monster is getting reflection from an artifact */ boolean arti_reflects(obj) struct obj *obj; { const struct artifact *arti = get_artifact(obj); if (arti) { /* while being worn */ if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT)) return TRUE; /* just being carried */ if (arti->cspfx & SPFX_REFLECT) return TRUE; } return FALSE; } /* decide whether this obj is effective when attacking against shades; does not consider the bonus for blessed objects versus undead */ boolean shade_glare(obj) struct obj *obj; { const struct artifact *arti; /* any silver object is effective */ if (objects[obj->otyp].oc_material == SILVER) return TRUE; /* non-silver artifacts with bonus against undead also are effective */ arti = get_artifact(obj); if (arti && (arti->spfx & SPFX_DFLAG2) && arti->mtype == M2_UNDEAD) return TRUE; /* [if there was anything with special bonus against noncorporeals, it would be effective too] */ /* otherwise, harmless to shades */ return FALSE; } /* returns 1 if name is restricted for otmp->otyp */ boolean restrict_name(otmp, name) struct obj *otmp; const char *name; { register const struct artifact *a; const char *aname, *odesc, *other; boolean sametype[NUM_OBJECTS]; int i, lo, hi, otyp = otmp->otyp, ocls = objects[otyp].oc_class; if (!*name) return FALSE; if (!strncmpi(name, "the ", 4)) name += 4; /* decide what types of objects are the same as otyp; if it's been discovered, then only itself matches; otherwise, include all other undiscovered objects of the same class which have the same description or share the same pool of shuffled descriptions */ (void) memset((genericptr_t) sametype, 0, sizeof sametype); /* FALSE */ sametype[otyp] = TRUE; if (!objects[otyp].oc_name_known && (odesc = OBJ_DESCR(objects[otyp])) != 0) { obj_shuffle_range(otyp, &lo, &hi); for (i = bases[ocls]; i < NUM_OBJECTS; i++) { if (objects[i].oc_class != ocls) break; if (!objects[i].oc_name_known && (other = OBJ_DESCR(objects[i])) != 0 && (!strcmp(odesc, other) || (i >= lo && i <= hi))) sametype[i] = TRUE; } } /* Since almost every artifact is SPFX_RESTR, it doesn't cost us much to do the string comparison before the spfx check. Bug fix: don't name multiple elven daggers "Sting". */ for (a = artilist + 1; a->otyp; a++) { if (!sametype[a->otyp]) continue; aname = a->name; if (!strncmpi(aname, "the ", 4)) aname += 4; if (!strcmp(aname, name)) return (boolean) ((a->spfx & (SPFX_NOGEN | SPFX_RESTR)) != 0 || otmp->quan > 1L); } return FALSE; } STATIC_OVL boolean attacks(adtyp, otmp) int adtyp; struct obj *otmp; { register const struct artifact *weap; if ((weap = get_artifact(otmp)) != 0) return (boolean) (weap->attk.adtyp == adtyp); return FALSE; } boolean defends(adtyp, otmp) int adtyp; struct obj *otmp; { register const struct artifact *weap; if ((weap = get_artifact(otmp)) != 0) return (boolean) (weap->defn.adtyp == adtyp); return FALSE; } /* used for monsters */ boolean defends_when_carried(adtyp, otmp) int adtyp; struct obj *otmp; { register const struct artifact *weap; if ((weap = get_artifact(otmp)) != 0) return (boolean) (weap->cary.adtyp == adtyp); return FALSE; } /* determine whether an item confers Protection */ boolean protects(otmp, being_worn) struct obj *otmp; boolean being_worn; { const struct artifact *arti; if (being_worn && objects[otmp->otyp].oc_oprop == PROTECTION) return TRUE; arti = get_artifact(otmp); if (!arti) return FALSE; return (boolean) ((arti->cspfx & SPFX_PROTECT) != 0 || (being_worn && (arti->spfx & SPFX_PROTECT) != 0)); } /* * a potential artifact has just been worn/wielded/picked-up or * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask. */ void set_artifact_intrinsic(otmp, on, wp_mask) register struct obj *otmp; boolean on; long wp_mask; { long *mask = 0; register const struct artifact *oart = get_artifact(otmp); register uchar dtyp; register long spfx; if (!oart) return; /* effects from the defn field */ dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp; if (dtyp == AD_FIRE) mask = &EFire_resistance; else if (dtyp == AD_COLD) mask = &ECold_resistance; else if (dtyp == AD_ELEC) mask = &EShock_resistance; else if (dtyp == AD_MAGM) mask = &EAntimagic; else if (dtyp == AD_DISN) mask = &EDisint_resistance; else if (dtyp == AD_DRST) mask = &EPoison_resistance; if (mask && wp_mask == W_ART && !on) { /* find out if some other artifact also confers this intrinsic */ /* if so, leave the mask alone */ register struct obj *obj; for (obj = invent; obj; obj = obj->nobj) if (obj != otmp && obj->oartifact) { register const struct artifact *art = get_artifact(obj); if (art->cary.adtyp == dtyp) { mask = (long *) 0; break; } } } if (mask) { if (on) *mask |= wp_mask; else *mask &= ~wp_mask; } /* intrinsics from the spfx field; there could be more than one */ spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx; if (spfx && wp_mask == W_ART && !on) { /* don't change any spfx also conferred by other artifacts */ register struct obj *obj; for (obj = invent; obj; obj = obj->nobj) if (obj != otmp && obj->oartifact) { register const struct artifact *art = get_artifact(obj); spfx &= ~art->cspfx; } } if (spfx & SPFX_SEARCH) { if (on) ESearching |= wp_mask; else ESearching &= ~wp_mask; } if (spfx & SPFX_HALRES) { /* make_hallucinated must (re)set the mask itself to get * the display right */ /* restoring needed because this is the only artifact intrinsic * that can print a message--need to guard against being printed * when restoring a game */ (void) make_hallucinated((long) !on, restoring ? FALSE : TRUE, wp_mask); } if (spfx & SPFX_ESP) { if (on) ETelepat |= wp_mask; else ETelepat &= ~wp_mask; see_monsters(); } if (spfx & SPFX_STLTH) { if (on) EStealth |= wp_mask; else EStealth &= ~wp_mask; } if (spfx & SPFX_REGEN) { if (on) ERegeneration |= wp_mask; else ERegeneration &= ~wp_mask; } if (spfx & SPFX_TCTRL) { if (on) ETeleport_control |= wp_mask; else ETeleport_control &= ~wp_mask; } if (spfx & SPFX_WARN) { if (spec_m2(otmp)) { if (on) { EWarn_of_mon |= wp_mask; context.warntype.obj |= spec_m2(otmp); } else { EWarn_of_mon &= ~wp_mask; context.warntype.obj &= ~spec_m2(otmp); } see_monsters(); } else { if (on) EWarning |= wp_mask; else EWarning &= ~wp_mask; } } if (spfx & SPFX_EREGEN) { if (on) EEnergy_regeneration |= wp_mask; else EEnergy_regeneration &= ~wp_mask; } if (spfx & SPFX_HSPDAM) { if (on) EHalf_spell_damage |= wp_mask; else EHalf_spell_damage &= ~wp_mask; } if (spfx & SPFX_HPHDAM) { if (on) EHalf_physical_damage |= wp_mask; else EHalf_physical_damage &= ~wp_mask; } if (spfx & SPFX_XRAY) { /* this assumes that no one else is using xray_range */ if (on) u.xray_range = 3; else u.xray_range = -1; vision_full_recalc = 1; } if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) { if (on) EReflecting |= wp_mask; else EReflecting &= ~wp_mask; } if (spfx & SPFX_PROTECT) { if (on) EProtection |= wp_mask; else EProtection &= ~wp_mask; } if (wp_mask == W_ART && !on && oart->inv_prop) { /* might have to turn off invoked power too */ if (oart->inv_prop <= LAST_PROP && (u.uprops[oart->inv_prop].extrinsic & W_ARTI)) (void) arti_invoke(otmp); } } /* touch_artifact()'s return value isn't sufficient to tell whether it dished out damage, and tracking changes to u.uhp, u.mh, Lifesaved when trying to avoid second wounding is too cumbersome */ STATIC_VAR boolean touch_blasted; /* for retouch_object() */ /* * creature (usually hero) tries to touch (pick up or wield) an artifact obj. * Returns 0 if the object refuses to be touched. * This routine does not change any object chains. * Ignores such things as gauntlets, assuming the artifact is not * fooled by such trappings. */ int touch_artifact(obj, mon) struct obj *obj; struct monst *mon; { register const struct artifact *oart = get_artifact(obj); boolean badclass, badalign, self_willed, yours; touch_blasted = FALSE; if (!oart) return 1; yours = (mon == &youmonst); /* all quest artifacts are self-willed; it this ever changes, `badclass' will have to be extended to explicitly include quest artifacts */ self_willed = ((oart->spfx & SPFX_INTEL) != 0); if (yours) { badclass = self_willed && ((oart->role != NON_PM && !Role_if(oart->role)) || (oart->race != NON_PM && !Race_if(oart->race))); badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE && (oart->alignment != u.ualign.type || u.ualign.record < 0); } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) { badclass = self_willed && oart->role != NON_PM && oart != &artilist[ART_EXCALIBUR]; badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE && (oart->alignment != mon_aligntyp(mon)); } else { /* an M3_WANTSxxx monster or a fake player */ /* special monsters trying to take the Amulet, invocation tools or quest item can touch anything except `spec_applies' artifacts */ badclass = badalign = FALSE; } /* weapons which attack specific categories of monsters are bad for them even if their alignments happen to match */ if (!badalign) badalign = bane_applies(oart, mon); if (((badclass || badalign) && self_willed) || (badalign && (!yours || !rn2(4)))) { int dmg, tmp; char buf[BUFSZ]; if (!yours) return 0; You("are blasted by %s power!", s_suffix(the(xname(obj)))); touch_blasted = TRUE; dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4)); /* add half (maybe quarter) of the usual silver damage bonus */ if (objects[obj->otyp].oc_material == SILVER && Hate_silver) tmp = rnd(10), dmg += Maybe_Half_Phys(tmp); Sprintf(buf, "touching %s", oart->name); losehp(dmg, buf, KILLED_BY); /* magic damage, not physical */ exercise(A_WIS, FALSE); } /* can pick it up unless you're totally non-synch'd with the artifact */ if (badclass && badalign && self_willed) { if (yours) { if (!carried(obj)) pline("%s your grasp!", Tobjnam(obj, "evade")); else pline("%s beyond your control!", Tobjnam(obj, "are")); } return 0; } return 1; } /* decide whether an artifact itself is vulnerable to a particular type of erosion damage, independent of the properties of its bearer */ boolean arti_immune(obj, dtyp) struct obj *obj; int dtyp; { register const struct artifact *weap = get_artifact(obj); if (!weap) return FALSE; if (dtyp == AD_PHYS) return FALSE; /* nothing is immune to phys dmg */ return (boolean) (weap->attk.adtyp == dtyp || weap->defn.adtyp == dtyp || weap->cary.adtyp == dtyp); } STATIC_OVL boolean bane_applies(oart, mon) const struct artifact *oart; struct monst *mon; { struct artifact atmp; if (oart && (oart->spfx & SPFX_DBONUS) != 0) { atmp = *oart; atmp.spfx &= SPFX_DBONUS; /* clear other spfx fields */ if (spec_applies(&atmp, mon)) return TRUE; } return FALSE; } /* decide whether an artifact's special attacks apply against mtmp */ STATIC_OVL int spec_applies(weap, mtmp) register const struct artifact *weap; struct monst *mtmp; { struct permonst *ptr; boolean yours; if (!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK))) return (weap->attk.adtyp == AD_PHYS); yours = (mtmp == &youmonst); ptr = mtmp->data; if (weap->spfx & SPFX_DMONS) { return (ptr == &mons[(int) weap->mtype]); } else if (weap->spfx & SPFX_DCLAS) { return (weap->mtype == (unsigned long) ptr->mlet); } else if (weap->spfx & SPFX_DFLAG1) { return ((ptr->mflags1 & weap->mtype) != 0L); } else if (weap->spfx & SPFX_DFLAG2) { return ((ptr->mflags2 & weap->mtype) || (yours && ((!Upolyd && (urace.selfmask & weap->mtype)) || ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM)))); } else if (weap->spfx & SPFX_DALIGN) { return yours ? (u.ualign.type != weap->alignment) : (ptr->maligntyp == A_NONE || sgn(ptr->maligntyp) != weap->alignment); } else if (weap->spfx & SPFX_ATTK) { struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp)); if (defending_weapon && defending_weapon->oartifact && defends((int) weap->attk.adtyp, defending_weapon)) return FALSE; switch (weap->attk.adtyp) { case AD_FIRE: return !(yours ? Fire_resistance : resists_fire(mtmp)); case AD_COLD: return !(yours ? Cold_resistance : resists_cold(mtmp)); case AD_ELEC: return !(yours ? Shock_resistance : resists_elec(mtmp)); case AD_MAGM: case AD_STUN: return !(yours ? Antimagic : (rn2(100) < ptr->mr)); case AD_DRST: return !(yours ? Poison_resistance : resists_poison(mtmp)); case AD_DRLI: return !(yours ? Drain_resistance : resists_drli(mtmp)); case AD_STON: return !(yours ? Stone_resistance : resists_ston(mtmp)); default: impossible("Weird weapon special attack."); } } return 0; } /* return the M2 flags of monster that an artifact's special attacks apply * against */ long spec_m2(otmp) struct obj *otmp; { const struct artifact *artifact = get_artifact(otmp); if (artifact) return artifact->mtype; return 0L; } /* special attack bonus */ int spec_abon(otmp, mon) struct obj *otmp; struct monst *mon; { const struct artifact *weap = get_artifact(otmp); /* no need for an extra check for `NO_ATTK' because this will always return 0 for any artifact which has that attribute */ if (weap && weap->attk.damn && spec_applies(weap, mon)) return rnd((int) weap->attk.damn); return 0; } /* special damage bonus */ int spec_dbon(otmp, mon, tmp) struct obj *otmp; struct monst *mon; int tmp; { register const struct artifact *weap = get_artifact(otmp); if (!weap || (weap->attk.adtyp == AD_PHYS /* check for `NO_ATTK' */ && weap->attk.damn == 0 && weap->attk.damd == 0)) spec_dbon_applies = FALSE; else if (otmp->oartifact == ART_GRIMTOOTH) /* Grimtooth has SPFX settings to warn against elves but we want its damage bonus to apply to all targets, so bypass spec_applies() */ spec_dbon_applies = TRUE; else spec_dbon_applies = spec_applies(weap, mon); if (spec_dbon_applies) return weap->attk.damd ? rnd((int) weap->attk.damd) : max(tmp, 1); return 0; } /* add identified artifact to discoveries list */ void discover_artifact(m) xchar m; { int i; /* look for this artifact in the discoveries list; if we hit an empty slot then it's not present, so add it */ for (i = 0; i < NROFARTIFACTS; i++) if (artidisco[i] == 0 || artidisco[i] == m) { artidisco[i] = m; return; } /* there is one slot per artifact, so we should never reach the end without either finding the artifact or an empty slot... */ impossible("couldn't discover artifact (%d)", (int) m); } /* used to decide whether an artifact has been fully identified */ boolean undiscovered_artifact(m) xchar m; { int i; /* look for this artifact in the discoveries list; if we hit an empty slot then it's undiscovered */ for (i = 0; i < NROFARTIFACTS; i++) if (artidisco[i] == m) return FALSE; else if (artidisco[i] == 0) break; return TRUE; } /* display a list of discovered artifacts; return their count */ int disp_artifact_discoveries(tmpwin) winid tmpwin; /* supplied by dodiscover() */ { int i, m, otyp; char buf[BUFSZ]; for (i = 0; i < NROFARTIFACTS; i++) { if (artidisco[i] == 0) break; /* empty slot implies end of list */ if (tmpwin == WIN_ERR) continue; /* for WIN_ERR, we just count */ if (i == 0) putstr(tmpwin, iflags.menu_headings, "Artifacts"); m = artidisco[i]; otyp = artilist[m].otyp; Sprintf(buf, " %s [%s %s]", artiname(m), align_str(artilist[m].alignment), simple_typename(otyp)); putstr(tmpwin, 0, buf); } return i; } /* * Magicbane's intrinsic magic is incompatible with normal * enchantment magic. Thus, its effects have a negative * dependence on spe. Against low mr victims, it typically * does "double athame" damage, 2d4. Occasionally, it will * cast unbalancing magic which effectively averages out to * 4d4 damage (3d4 against high mr victims), for spe = 0. * * Prior to 3.4.1, the cancel (aka purge) effect always * included the scare effect too; now it's one or the other. * Likewise, the stun effect won't be combined with either * of those two; it will be chosen separately or possibly * used as a fallback when scare or cancel fails. * * [Historical note: a change to artifact_hit() for 3.4.0 * unintentionally made all of Magicbane's special effects * be blocked if the defender successfully saved against a * stun attack. As of 3.4.1, those effects can occur but * will be slightly less likely than they were in 3.3.x.] */ #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */ static const char *const mb_verb[2][4] = { { "probe", "stun", "scare", "cancel" }, { "prod", "amaze", "tickle", "purge" }, }; #define MB_INDEX_PROBE 0 #define MB_INDEX_STUN 1 #define MB_INDEX_SCARE 2 #define MB_INDEX_CANCEL 3 /* called when someone is being hit by Magicbane */ STATIC_OVL boolean Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee) struct monst *magr, *mdef; /* attacker and defender */ struct obj *mb; /* Magicbane */ int *dmgptr; /* extra damage target will suffer */ int dieroll; /* d20 that has already scored a hit */ boolean vis; /* whether the action can be seen */ char *hittee; /* target's name: "you" or mon_nam(mdef) */ { struct permonst *old_uasmon; const char *verb, *fakename; boolean youattack = (magr == &youmonst), youdefend = (mdef == &youmonst), resisted = FALSE, do_stun, do_confuse, result; int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2; result = FALSE; /* no message given yet */ /* the most severe effects are less likely at higher enchantment */ if (mb->spe >= 3) scare_dieroll /= (1 << (mb->spe / 3)); /* if target successfully resisted the artifact damage bonus, reduce overall likelihood of the assorted special effects */ if (!spec_dbon_applies) dieroll += 1; /* might stun even when attempting a more severe effect, but in that case it will only happen if the other effect fails; extra damage will apply regardless; 3.4.1: sometimes might just probe even when it hasn't been enchanted */ do_stun = (max(mb->spe, 0) < rn2(spec_dbon_applies ? 11 : 7)); /* the special effects also boost physical damage; increments are generally cumulative, but since the stun effect is based on a different criterium its damage might not be included; the base damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending on target's resistance check against AD_STUN (handled by caller) [note that a successful save against AD_STUN doesn't actually prevent the target from ending up stunned] */ attack_indx = MB_INDEX_PROBE; *dmgptr += rnd(4); /* (2..3)d4 */ if (do_stun) { attack_indx = MB_INDEX_STUN; *dmgptr += rnd(4); /* (3..4)d4 */ } if (dieroll <= scare_dieroll) { attack_indx = MB_INDEX_SCARE; *dmgptr += rnd(4); /* (3..5)d4 */ } if (dieroll <= (scare_dieroll / 2)) { attack_indx = MB_INDEX_CANCEL; *dmgptr += rnd(4); /* (4..6)d4 */ } /* give the hit message prior to inflicting the effects */ verb = mb_verb[!!Hallucination][attack_indx]; if (youattack || youdefend || vis) { result = TRUE; pline_The("magic-absorbing blade %s %s!", vtense((const char *) 0, verb), hittee); /* assume probing has some sort of noticeable feedback even if it is being done by one monster to another */ if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); } /* now perform special effects */ switch (attack_indx) { case MB_INDEX_CANCEL: old_uasmon = youmonst.data; /* No mdef->mcan check: even a cancelled monster can be polymorphed * into a golem, and the "cancel" effect acts as if some magical * energy remains in spellcasting defenders to be absorbed later. */ if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) { resisted = TRUE; } else { do_stun = FALSE; if (youdefend) { if (youmonst.data != old_uasmon) *dmgptr = 0; /* rehumanized, so no more damage */ if (u.uenmax > 0) { You("lose magical energy!"); u.uenmax--; if (u.uen > 0) u.uen--; context.botl = 1; } } else { if (mdef->data == &mons[PM_CLAY_GOLEM]) mdef->mhp = 1; /* cancelled clay golems will die */ if (youattack && attacktype(mdef->data, AT_MAGC)) { You("absorb magical energy!"); u.uenmax++; u.uen++; context.botl = 1; } } } break; case MB_INDEX_SCARE: if (youdefend) { if (Antimagic) { resisted = TRUE; } else { nomul(-3); multi_reason = "being scared stiff"; nomovemsg = ""; if (magr && magr == u.ustuck && sticks(youmonst.data)) { u.ustuck = (struct monst *) 0; You("release %s!", mon_nam(magr)); } } } else { if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL)) resisted = TRUE; else monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr)); } if (!resisted) do_stun = FALSE; break; case MB_INDEX_STUN: do_stun = TRUE; /* (this is redundant...) */ break; case MB_INDEX_PROBE: if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) { pline_The("%s is insightful.", verb); /* pre-damage status */ probe_monster(mdef); } break; } /* stun if that was selected and a worse effect didn't occur */ if (do_stun) { if (youdefend) make_stunned(((HStun & TIMEOUT) + 3L), FALSE); else mdef->mstun = 1; /* avoid extra stun message below if we used mb_verb["stun"] above */ if (attack_indx == MB_INDEX_STUN) do_stun = FALSE; } /* lastly, all this magic can be confusing... */ do_confuse = !rn2(12); if (do_confuse) { if (youdefend) make_confused((HConfusion & TIMEOUT) + 4L, FALSE); else mdef->mconf = 1; } /* now give message(s) describing side-effects; don't let vtense() be fooled by assigned name ending in 's' */ fakename = youdefend ? "you" : "mon"; if (youattack || youdefend || vis) { (void) upstart(hittee); /* capitalize */ if (resisted) { pline("%s %s!", hittee, vtense(fakename, "resist")); shieldeff(youdefend ? u.ux : mdef->mx, youdefend ? u.uy : mdef->my); } if ((do_stun || do_confuse) && flags.verbose) { char buf[BUFSZ]; buf[0] = '\0'; if (do_stun) Strcat(buf, "stunned"); if (do_stun && do_confuse) Strcat(buf, " and "); if (do_confuse) Strcat(buf, "confused"); pline("%s %s %s%c", hittee, vtense(fakename, "are"), buf, (do_stun && do_confuse) ? '!' : '.'); } } return result; } /* Function used when someone attacks someone else with an artifact * weapon. Only adds the special (artifact) damage, and returns a 1 if it * did something special (in which case the caller won't print the normal * hit message). This should be called once upon every artifact attack; * dmgval() no longer takes artifact bonuses into account. Possible * extension: change the killer so that when an orc kills you with * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc". */ boolean artifact_hit(magr, mdef, otmp, dmgptr, dieroll) struct monst *magr, *mdef; struct obj *otmp; int *dmgptr; int dieroll; /* needed for Magicbane and vorpal blades */ { boolean youattack = (magr == &youmonst); boolean youdefend = (mdef == &youmonst); boolean vis = (!youattack && magr && cansee(magr->mx, magr->my)) || (!youdefend && cansee(mdef->mx, mdef->my)) || (youattack && u.uswallow && mdef == u.ustuck && !Blind); boolean realizes_damage; const char *wepdesc; static const char you[] = "you"; char hittee[BUFSZ]; Strcpy(hittee, youdefend ? you : mon_nam(mdef)); /* The following takes care of most of the damage, but not all-- * the exception being for level draining, which is specially * handled. Messages are done in this function, however. */ *dmgptr += spec_dbon(otmp, mdef, *dmgptr); if (youattack && youdefend) { impossible("attacking yourself with weapon?"); return FALSE; } realizes_damage = (youdefend || vis /* feel the effect even if not seen */ || (youattack && mdef == u.ustuck)); /* the four basic attacks: fire, cold, shock and missiles */ if (attacks(AD_FIRE, otmp)) { if (realizes_damage) pline_The("fiery blade %s %s%c", !spec_dbon_applies ? "hits" : (mdef->data == &mons[PM_WATER_ELEMENTAL]) ? "vaporizes part of" : "burns", hittee, !spec_dbon_applies ? '.' : '!'); if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE); if (!rn2(4)) (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); if (!rn2(7)) (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (youdefend && Slimed) burn_away_slime(); return realizes_damage; } if (attacks(AD_COLD, otmp)) { if (realizes_damage) pline_The("ice-cold blade %s %s%c", !spec_dbon_applies ? "hits" : "freezes", hittee, !spec_dbon_applies ? '.' : '!'); if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD); return realizes_damage; } if (attacks(AD_ELEC, otmp)) { if (realizes_damage) pline_The("massive hammer hits%s %s%c", !spec_dbon_applies ? "" : "! Lightning strikes", hittee, !spec_dbon_applies ? '.' : '!'); if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC); if (!rn2(5)) (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC); return realizes_damage; } if (attacks(AD_MAGM, otmp)) { if (realizes_damage) pline_The("imaginary widget hits%s %s%c", !spec_dbon_applies ? "" : "! A hail of magic missiles strikes", hittee, !spec_dbon_applies ? '.' : '!'); return realizes_damage; } if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) { /* Magicbane's special attacks (possibly modifies hittee[]) */ return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee); } if (!spec_dbon_applies) { /* since damage bonus didn't apply, nothing more to do; no further attacks have side-effects on inventory */ return FALSE; } /* We really want "on a natural 20" but Nethack does it in */ /* reverse from AD&D. */ if (spec_ability(otmp, SPFX_BEHEAD)) { if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) { wepdesc = "The razor-sharp blade"; /* not really beheading, but so close, why add another SPFX */ if (youattack && u.uswallow && mdef == u.ustuck) { You("slice %s wide open!", mon_nam(mdef)); *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; return TRUE; } if (!youdefend) { /* allow normal cutworm() call to add extra damage */ if (notonhead) return FALSE; if (bigmonst(mdef->data)) { if (youattack) You("slice deeply into %s!", mon_nam(mdef)); else if (vis) pline("%s cuts deeply into %s!", Monnam(magr), hittee); *dmgptr *= 2; return TRUE; } *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; pline("%s cuts %s in half!", wepdesc, mon_nam(mdef)); otmp->dknown = TRUE; return TRUE; } else { if (bigmonst(youmonst.data)) { pline("%s cuts deeply into you!", magr ? Monnam(magr) : wepdesc); *dmgptr *= 2; return TRUE; } /* Players with negative AC's take less damage instead * of just not getting hit. We must add a large enough * value to the damage so that this reduction in * damage does not prevent death. */ *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER; pline("%s cuts you in half!", wepdesc); otmp->dknown = TRUE; return TRUE; } } else if (otmp->oartifact == ART_VORPAL_BLADE && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) { static const char *const behead_msg[2] = { "%s beheads %s!", "%s decapitates %s!" }; if (youattack && u.uswallow && mdef == u.ustuck) return FALSE; wepdesc = artilist[ART_VORPAL_BLADE].name; if (!youdefend) { if (!has_head(mdef->data) || notonhead || u.uswallow) { if (youattack) pline("Somehow, you miss %s wildly.", mon_nam(mdef)); else if (vis) pline("Somehow, %s misses wildly.", mon_nam(magr)); *dmgptr = 0; return (boolean) (youattack || vis); } if (noncorporeal(mdef->data) || amorphous(mdef->data)) { pline("%s slices through %s %s.", wepdesc, s_suffix(mon_nam(mdef)), mbodypart(mdef, NECK)); return TRUE; } *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, mon_nam(mdef)); if (Hallucination && !flags.female) pline("Good job Henry, but that wasn't Anne."); otmp->dknown = TRUE; return TRUE; } else { if (!has_head(youmonst.data)) { pline("Somehow, %s misses you wildly.", magr ? mon_nam(magr) : wepdesc); *dmgptr = 0; return TRUE; } if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) { pline("%s slices through your %s.", wepdesc, body_part(NECK)); return TRUE; } *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER; pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you"); otmp->dknown = TRUE; /* Should amulets fall off? */ return TRUE; } } } if (spec_ability(otmp, SPFX_DRLI)) { /* some non-living creatures (golems, vortices) are vulnerable to life drain effects */ const char *life = nonliving(mdef->data) ? "animating force" : "life"; if (!youdefend) { if (vis) { if (otmp->oartifact == ART_STORMBRINGER) pline_The("%s blade draws the %s from %s!", hcolor(NH_BLACK), life, mon_nam(mdef)); else pline("%s draws the %s from %s!", The(distant_name(otmp, xname)), life, mon_nam(mdef)); } if (mdef->m_lev == 0) { *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; } else { int drain = monhp_per_lvl(mdef); *dmgptr += drain; mdef->mhpmax -= drain; mdef->m_lev--; drain /= 2; if (drain) healup(drain, 0, FALSE, FALSE); } return vis; } else { /* youdefend */ int oldhpmax = u.uhpmax; if (Blind) You_feel("an %s drain your %s!", (otmp->oartifact == ART_STORMBRINGER) ? "unholy blade" : "object", life); else if (otmp->oartifact == ART_STORMBRINGER) pline_The("%s blade drains your %s!", hcolor(NH_BLACK), life); else pline("%s drains your %s!", The(distant_name(otmp, xname)), life); losexp("life drainage"); if (magr && magr->mhp < magr->mhpmax) { magr->mhp += (oldhpmax - u.uhpmax) / 2; if (magr->mhp > magr->mhpmax) magr->mhp = magr->mhpmax; } return TRUE; } } return FALSE; } static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 }; static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 }; /* #invoke: an "ugly check" filters out most objects */ /* the #invoke command */ int doinvoke() { struct obj *obj; obj = getobj(invoke_types, "invoke"); if (!obj) return 0; if (!retouch_object(&obj, FALSE)) return 1; return arti_invoke(obj); } STATIC_OVL int arti_invoke(obj) struct obj *obj; { register const struct artifact *oart = get_artifact(obj); if (!obj) { impossible("arti_invoke without obj"); return 0; } if (!oart || !oart->inv_prop) { if (obj->otyp == CRYSTAL_BALL) use_crystal_ball(&obj); else pline1(nothing_happens); return 1; } if (oart->inv_prop > LAST_PROP) { /* It's a special power, not "just" a property */ if (obj->age > monstermoves) { /* the artifact is tired :-) */ You_feel("that %s %s ignoring you.", the(xname(obj)), otense(obj, "are")); /* and just got more so; patience is essential... */ obj->age += (long) d(3, 10); return 1; } obj->age = monstermoves + rnz(100); switch (oart->inv_prop) { case TAMING: { struct obj pseudo; pseudo = zeroobj; /* neither cursed nor blessed, zero oextra too */ pseudo.otyp = SCR_TAMING; (void) seffects(&pseudo); break; } case HEALING: { int healamt = (u.uhpmax + 1 - u.uhp) / 2; long creamed = (long) u.ucreamed; if (Upolyd) healamt = (u.mhmax + 1 - u.mh) / 2; if (healamt || Sick || Slimed || Blinded > creamed) You_feel("better."); else goto nothing_special; if (healamt > 0) { if (Upolyd) u.mh += healamt; else u.uhp += healamt; } if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL); if (Slimed) make_slimed(0L, (char *) 0); if (Blinded > creamed) make_blinded(creamed, FALSE); context.botl = 1; break; } case ENERGY_BOOST: { int epboost = (u.uenmax + 1 - u.uen) / 2; if (epboost > 120) epboost = 120; /* arbitrary */ else if (epboost < 12) epboost = u.uenmax - u.uen; if (epboost) { You_feel("re-energized."); u.uen += epboost; context.botl = 1; } else goto nothing_special; break; } case UNTRAP: { if (!untrap(TRUE)) { obj->age = 0; /* don't charge for changing their mind */ return 0; } break; } case CHARGE_OBJ: { struct obj *otmp = getobj(recharge_type, "charge"); boolean b_effect; if (!otmp) { obj->age = 0; return 0; } b_effect = obj->blessed && (Role_switch == oart->role || !oart->role); recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0); update_inventory(); break; } case LEV_TELE: level_tele(); break; case CREATE_PORTAL: { int i, num_ok_dungeons, last_ok_dungeon = 0; d_level newlev; extern int n_dgns; /* from dungeon.c */ winid tmpwin = create_nhwindow(NHW_MENU); anything any; any = zeroany; /* set all bits to zero */ start_menu(tmpwin); /* use index+1 (cant use 0) as identifier */ for (i = num_ok_dungeons = 0; i < n_dgns; i++) { if (!dungeons[i].dunlev_ureached) continue; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, dungeons[i].dname, MENU_UNSELECTED); num_ok_dungeons++; last_ok_dungeon = i; } end_menu(tmpwin, "Open a portal to which dungeon?"); if (num_ok_dungeons > 1) { /* more than one entry; display menu for choices */ menu_item *selected; int n; n = select_menu(tmpwin, PICK_ONE, &selected); if (n <= 0) { destroy_nhwindow(tmpwin); goto nothing_special; } i = selected[0].item.a_int - 1; free((genericptr_t) selected); } else i = last_ok_dungeon; /* also first & only OK dungeon */ destroy_nhwindow(tmpwin); /* * i is now index into dungeon structure for the new dungeon. * Find the closest level in the given dungeon, open * a use-once portal to that dungeon and go there. * The closest level is either the entry or dunlev_ureached. */ newlev.dnum = i; if (dungeons[i].depth_start >= depth(&u.uz)) newlev.dlevel = dungeons[i].entry_lev; else newlev.dlevel = dungeons[i].dunlev_ureached; if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) || newlev.dnum == u.uz.dnum || !next_to_u()) { You_feel("very disoriented for a moment."); } else { if (!Blind) You("are surrounded by a shimmering sphere!"); else You_feel("weightless for a moment."); goto_level(&newlev, FALSE, FALSE, FALSE); } break; } case ENLIGHTENING: enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); break; case CREATE_AMMO: { struct obj *otmp = mksobj(ARROW, TRUE, FALSE); if (!otmp) goto nothing_special; otmp->blessed = obj->blessed; otmp->cursed = obj->cursed; otmp->bknown = obj->bknown; if (obj->blessed) { if (otmp->spe < 0) otmp->spe = 0; otmp->quan += rnd(10); } else if (obj->cursed) { if (otmp->spe > 0) otmp->spe = 0; } else otmp->quan += rnd(5); otmp->owt = weight(otmp); otmp = hold_another_object(otmp, "Suddenly %s out.", aobjnam(otmp, "fall"), (const char *) 0); break; } } } else { long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI), iprop = u.uprops[oart->inv_prop].intrinsic; boolean on = (eprop & W_ARTI) != 0; /* true if prop just set */ if (on && obj->age > monstermoves) { /* the artifact is tired :-) */ u.uprops[oart->inv_prop].extrinsic ^= W_ARTI; You_feel("that %s %s ignoring you.", the(xname(obj)), otense(obj, "are")); /* can't just keep repeatedly trying */ obj->age += (long) d(3, 10); return 1; } else if (!on) { /* when turning off property, determine downtime */ /* arbitrary for now until we can tune this -dlc */ obj->age = monstermoves + rnz(100); } if ((eprop & ~W_ARTI) || iprop) { nothing_special: /* you had the property from some other source too */ if (carried(obj)) You_feel("a surge of power, but nothing seems to happen."); return 1; } switch (oart->inv_prop) { case CONFLICT: if (on) You_feel("like a rabble-rouser."); else You_feel("the tension decrease around you."); break; case LEVITATION: if (on) { float_up(); spoteffects(FALSE); } else (void) float_down(I_SPECIAL | TIMEOUT, W_ARTI); break; case INVIS: if (BInvis || Blind) goto nothing_special; newsym(u.ux, u.uy); if (on) Your("body takes on a %s transparency...", Hallucination ? "normal" : "strange"); else Your("body seems to unfade..."); break; } } return 1; } /* will freeing this object from inventory cause levitation to end? */ boolean finesse_ahriman(obj) struct obj *obj; { const struct artifact *oart; struct prop save_Lev; boolean result; /* if we aren't levitating or this isn't an artifact which confers levitation via #invoke then freeinv() won't toggle levitation */ if (!Levitation || (oart = get_artifact(obj)) == 0 || oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI)) return FALSE; /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI; probe ahead to see whether that actually results in floating down; (this assumes that there aren't two simultaneously invoked artifacts both conferring levitation--safe, since if there were two of them, invoking the 2nd would negate the 1st rather than stack with it) */ save_Lev = u.uprops[LEVITATION]; HLevitation &= ~(I_SPECIAL | TIMEOUT); ELevitation &= ~W_ARTI; result = (boolean) !Levitation; u.uprops[LEVITATION] = save_Lev; return result; } /* WAC return TRUE if artifact is always lit */ boolean artifact_light(obj) struct obj *obj; { return (boolean) (get_artifact(obj) && obj->oartifact == ART_SUNSWORD); } /* KMH -- Talking artifacts are finally implemented */ void arti_speak(obj) struct obj *obj; { register const struct artifact *oart = get_artifact(obj); const char *line; char buf[BUFSZ]; /* Is this a speaking artifact? */ if (!oart || !(oart->spfx & SPFX_SPEAK)) return; line = getrumor(bcsign(obj), buf, TRUE); if (!*line) line = "NetHack rumors file closed for renovation."; pline("%s:", Tobjnam(obj, "whisper")); verbalize1(line); return; } boolean artifact_has_invprop(otmp, inv_prop) struct obj *otmp; uchar inv_prop; { const struct artifact *arti = get_artifact(otmp); return (boolean) (arti && (arti->inv_prop == inv_prop)); } /* Return the price sold to the hero of a given artifact or unique item */ long arti_cost(otmp) struct obj *otmp; { if (!otmp->oartifact) return (long) objects[otmp->otyp].oc_cost; else if (artilist[(int) otmp->oartifact].cost) return artilist[(int) otmp->oartifact].cost; else return (100L * (long) objects[otmp->otyp].oc_cost); } STATIC_OVL uchar abil_to_adtyp(abil) long *abil; { struct abil2adtyp_tag { long *abil; uchar adtyp; } abil2adtyp[] = { { &EFire_resistance, AD_FIRE }, { &ECold_resistance, AD_COLD }, { &EShock_resistance, AD_ELEC }, { &EAntimagic, AD_MAGM }, { &EDisint_resistance, AD_DISN }, { &EPoison_resistance, AD_DRST }, }; int k; for (k = 0; k < SIZE(abil2adtyp); k++) { if (abil2adtyp[k].abil == abil) return abil2adtyp[k].adtyp; } return 0; } STATIC_OVL unsigned long abil_to_spfx(abil) long *abil; { static const struct abil2spfx_tag { long *abil; unsigned long spfx; } abil2spfx[] = { { &ESearching, SPFX_SEARCH }, { &EHalluc_resistance, SPFX_HALRES }, { &ETelepat, SPFX_ESP }, { &EStealth, SPFX_STLTH }, { &ERegeneration, SPFX_REGEN }, { &ETeleport_control, SPFX_TCTRL }, { &EWarn_of_mon, SPFX_WARN }, { &EWarning, SPFX_WARN }, { &EEnergy_regeneration, SPFX_EREGEN }, { &EHalf_spell_damage, SPFX_HSPDAM }, { &EHalf_physical_damage, SPFX_HPHDAM }, { &EReflecting, SPFX_REFLECT }, }; int k; for (k = 0; k < SIZE(abil2spfx); k++) { if (abil2spfx[k].abil == abil) return abil2spfx[k].spfx; } return 0L; } /* * Return the first item that is conveying a particular intrinsic. */ struct obj * what_gives(abil) long *abil; { struct obj *obj; uchar dtyp; unsigned long spfx; long wornbits; long wornmask = (W_ARM | W_ARMC | W_ARMH | W_ARMS | W_ARMG | W_ARMF | W_ARMU | W_AMUL | W_RINGL | W_RINGR | W_TOOL /* [do W_ART and W_ARTI actually belong here?] */ | W_ART | W_ARTI); if (u.twoweap) wornmask |= W_SWAPWEP; dtyp = abil_to_adtyp(abil); spfx = abil_to_spfx(abil); wornbits = (wornmask & *abil); for (obj = invent; obj; obj = obj->nobj) { if (obj->oartifact && (abil != &EWarn_of_mon || context.warntype.obj)) { const struct artifact *art = get_artifact(obj); if (art) { if (dtyp) { if (art->cary.adtyp == dtyp || art->defn.adtyp == dtyp) return obj; } if (spfx) { /* property conferred when carried */ if ((art->cspfx & spfx) == spfx) return obj; /* property conferred when wielded or worn */ if ((art->spfx & spfx) == spfx && obj->owornmask) return obj; } } } else { if (wornbits && wornbits == (wornmask & obj->owornmask)) return obj; } } return (struct obj *) 0; } const char * glow_color(arti_indx) int arti_indx; { int colornum = artilist[arti_indx].acolor; const char *colorstr = clr2colorname(colornum); return hcolor(colorstr); } /* use for warning "glow" for Sting, Orcrist, and Grimtooth */ void Sting_effects(orc_count) int orc_count; /* new count (warn_obj_cnt is old count); -1 is a flag value */ { if (uwep && (uwep->oartifact == ART_STING || uwep->oartifact == ART_ORCRIST || uwep->oartifact == ART_GRIMTOOTH)) { if (orc_count == -1 && warn_obj_cnt > 0) { /* -1 means that blindness has just been toggled; give a 'continue' message that eventual 'stop' message will match */ pline("%s is %s.", bare_artifactname(uwep), !Blind ? "glowing" : "quivering"); } else if (orc_count > 0 && warn_obj_cnt == 0) { /* 'start' message */ if (!Blind) pline("%s %s %s!", bare_artifactname(uwep), otense(uwep, "glow"), glow_color(uwep->oartifact)); else pline("%s quivers slightly.", bare_artifactname(uwep)); } else if (orc_count == 0 && warn_obj_cnt > 0) { /* 'stop' message */ pline("%s stops %s.", bare_artifactname(uwep), !Blind ? "glowing" : "quivering"); } } } /* called when hero is wielding/applying/invoking a carried item, or after undergoing a transformation (alignment change, lycanthropy, polymorph) which might affect item access */ int retouch_object(objp, loseit) struct obj **objp; /* might be destroyed or unintentionally dropped */ boolean loseit; /* whether to drop it if hero can longer touch it */ { struct obj *obj = *objp; if (touch_artifact(obj, &youmonst)) { char buf[BUFSZ]; int dmg = 0, tmp; boolean ag = (objects[obj->otyp].oc_material == SILVER && Hate_silver), bane = bane_applies(get_artifact(obj), &youmonst); /* nothing else to do if hero can successfully handle this object */ if (!ag && !bane) return 1; /* hero can't handle this object, but didn't get touch_artifact()'s " evades your grasp|control" message; give an alternate one */ You_cant("handle %s%s!", yname(obj), obj->owornmask ? " anymore" : ""); /* also inflict damage unless touch_artifact() already did so */ if (!touch_blasted) { /* damage is somewhat arbitrary; half the usual 1d20 physical for silver, 1d10 magical for bane, potentially both */ if (ag) tmp = rnd(10), dmg += Maybe_Half_Phys(tmp); if (bane) dmg += rnd(10); Sprintf(buf, "handling %s", killer_xname(obj)); losehp(dmg, buf, KILLED_BY); exercise(A_CON, FALSE); } } /* removing a worn item might result in loss of levitation, dropping the hero onto a polymorph trap or into water or lava and potentially dropping or destroying the item */ if (obj->owornmask) { struct obj *otmp; remove_worn_item(obj, FALSE); for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp == obj) break; if (!otmp) *objp = obj = 0; } /* if we still have it and caller wants us to drop it, do so now */ if (loseit && obj) { if (Levitation) { freeinv(obj); hitfloor(obj); } else { /* dropx gives a message iff item lands on an altar */ if (!IS_ALTAR(levl[u.ux][u.uy].typ)) pline("%s to the %s.", Tobjnam(obj, "fall"), surface(u.ux, u.uy)); dropx(obj); } *objp = obj = 0; /* no longer in inventory */ } return 0; } /* an item which is worn/wielded or an artifact which conveys something via being carried or which has an #invoke effect currently in operation undergoes a touch test; if it fails, it will be unworn/unwielded and revoked but not dropped */ STATIC_OVL boolean untouchable(obj, drop_untouchable) struct obj *obj; boolean drop_untouchable; { struct artifact *art; boolean beingworn, carryeffect, invoked; long wearmask = ~(W_QUIVER | (u.twoweap ? 0L : W_SWAPWEP) | W_BALL); beingworn = ((obj->owornmask & wearmask) != 0L /* some items in use don't have any wornmask setting */ || (obj->oclass == TOOL_CLASS && (obj->lamplit || (obj->otyp == LEASH && obj->leashmon) || (Is_container(obj) && Has_contents(obj))))); if ((art = get_artifact(obj)) != 0) { carryeffect = (art->cary.adtyp || art->cspfx); invoked = (art->inv_prop > 0 && art->inv_prop <= LAST_PROP && (u.uprops[art->inv_prop].extrinsic & W_ARTI) != 0L); } else { carryeffect = invoked = FALSE; } if (beingworn || carryeffect || invoked) { if (!retouch_object(&obj, drop_untouchable)) { /* " is beyond your control" or "you can't handle " has been given and it is now unworn/unwielded and possibly dropped (depending upon caller); if dropped, carried effect was turned off, else we leave that alone; we turn off invocation property here if still carried */ if (invoked && obj) arti_invoke(obj); /* reverse #invoke */ return TRUE; } } return FALSE; } /* check all items currently in use (mostly worn) for touchability */ void retouch_equipment(dropflag) int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */ { static int nesting = 0; /* recursion control */ struct obj *obj; boolean dropit, had_gloves = (uarmg != 0); int had_rings = (!!uleft + !!uright); /* * We can potentially be called recursively if losing/unwearing * an item causes worn helm of opposite alignment to come off or * be destroyed. * * BUG: if the initial call was due to putting on a helm of * opposite alignment and it does come off to trigger recursion, * after the inner call executes, the outer call will finish * using the non-helm alignment rather than the helm alignment * which triggered this in the first place. */ if (!nesting++) clear_bypasses(); /* init upon initial entry */ dropit = (dropflag > 0); /* drop all or drop weapon */ /* check secondary weapon first, before possibly unwielding primary */ if (u.twoweap) (void) untouchable(uswapwep, dropit); /* check primary weapon next so that they're handled together */ if (uwep) (void) untouchable(uwep, dropit); /* in case someone is daft enough to add artifact or silver saddle */ if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) { /* untouchable() calls retouch_object() which expects an object in hero's inventory, but remove_worn_item() will be harmless for saddle and we're suppressing drop, so this works as intended */ if (untouchable(obj, FALSE)) dismount_steed(DISMOUNT_THROWN); } /* * TODO? Force off gloves if either or both rings are going to * become unworn; force off cloak [suit] before suit [shirt]. * The torso handling is hypothetical; the case for gloves is * not, due to the possibility of unwearing silver rings. */ dropit = (dropflag == 1); /* all untouchable items */ /* loss of levitation (silver ring, or Heart of Ahriman invocation) might cause hero to lose inventory items (by dropping into lava, for instance), so inventory traversal needs to rescan the whole invent chain each time it moves on to another object; we use bypass handling to keep track of which items have already been processed */ while ((obj = nxt_unbypassed_obj(invent)) != 0) (void) untouchable(obj, dropit); if (had_rings != (!!uleft + !!uright) && uarmg && uarmg->cursed) uncurse(uarmg); /* temporary? hack for ring removal plausibility */ if (had_gloves && !uarmg) selftouch("After losing your gloves, you"); if (!--nesting) clear_bypasses(); /* reset upon final exit */ } /*artifact.c*/ nethack-3.6.0/src/attrib.c0000664000076400007660000010247112631241231014355 0ustar paxedpaxed/* NetHack 3.6 attrib.c $NHDT-Date: 1449269911 2015/12/04 22:58:31 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* attribute modification routines. */ #include "hack.h" #include /* part of the output on gain or loss of attribute */ static const char *const plusattr[] = { "strong", "smart", "wise", "agile", "tough", "charismatic" }, *const minusattr[] = { "weak", "stupid", "foolish", "clumsy", "fragile", "repulsive" }; static const struct innate { schar ulevel; long *ability; const char *gainstr, *losestr; } arc_abil[] = { { 1, &(HStealth), "", "" }, { 1, &(HFast), "", "" }, { 10, &(HSearching), "perceptive", "" }, { 0, 0, 0, 0 } }, bar_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 7, &(HFast), "quick", "slow" }, { 15, &(HStealth), "stealthy", "" }, { 0, 0, 0, 0 } }, cav_abil[] = { { 7, &(HFast), "quick", "slow" }, { 15, &(HWarning), "sensitive", "" }, { 0, 0, 0, 0 } }, hea_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 15, &(HWarning), "sensitive", "" }, { 0, 0, 0, 0 } }, kni_abil[] = { { 7, &(HFast), "quick", "slow" }, { 0, 0, 0, 0 } }, mon_abil[] = { { 1, &(HFast), "", "" }, { 1, &(HSleep_resistance), "", "" }, { 1, &(HSee_invisible), "", "" }, { 3, &(HPoison_resistance), "healthy", "" }, { 5, &(HStealth), "stealthy", "" }, { 7, &(HWarning), "sensitive", "" }, { 9, &(HSearching), "perceptive", "unaware" }, { 11, &(HFire_resistance), "cool", "warmer" }, { 13, &(HCold_resistance), "warm", "cooler" }, { 15, &(HShock_resistance), "insulated", "conductive" }, { 17, &(HTeleport_control), "controlled", "uncontrolled" }, { 0, 0, 0, 0 } }, pri_abil[] = { { 15, &(HWarning), "sensitive", "" }, { 20, &(HFire_resistance), "cool", "warmer" }, { 0, 0, 0, 0 } }, ran_abil[] = { { 1, &(HSearching), "", "" }, { 7, &(HStealth), "stealthy", "" }, { 15, &(HSee_invisible), "", "" }, { 0, 0, 0, 0 } }, rog_abil[] = { { 1, &(HStealth), "", "" }, { 10, &(HSearching), "perceptive", "" }, { 0, 0, 0, 0 } }, sam_abil[] = { { 1, &(HFast), "", "" }, { 15, &(HStealth), "stealthy", "" }, { 0, 0, 0, 0 } }, tou_abil[] = { { 10, &(HSearching), "perceptive", "" }, { 20, &(HPoison_resistance), "hardy", "" }, { 0, 0, 0, 0 } }, val_abil[] = { { 1, &(HCold_resistance), "", "" }, { 1, &(HStealth), "", "" }, { 7, &(HFast), "quick", "slow" }, { 0, 0, 0, 0 } }, wiz_abil[] = { { 15, &(HWarning), "sensitive", "" }, { 17, &(HTeleport_control), "controlled", "uncontrolled" }, { 0, 0, 0, 0 } }, /* Intrinsics conferred by race */ elf_abil[] = { { 4, &(HSleep_resistance), "awake", "tired" }, { 0, 0, 0, 0 } }, orc_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 0, 0, 0, 0 } }; STATIC_DCL void NDECL(exerper); STATIC_DCL void FDECL(postadjabil, (long *)); STATIC_DCL const struct innate *FDECL(check_innate_abil, (long *, long)); STATIC_DCL int FDECL(innately, (long *)); /* adjust an attribute; return TRUE if change is made, FALSE otherwise */ boolean adjattrib(ndx, incr, msgflg) int ndx, incr; int msgflg; /* positive => no message, zero => message, and */ { /* negative => conditional (msg if change made) */ int old_acurr; boolean abonflg; const char *attrstr; if (Fixed_abil || !incr) return FALSE; if ((ndx == A_INT || ndx == A_WIS) && uarmh && uarmh->otyp == DUNCE_CAP) { if (msgflg == 0) Your("cap constricts briefly, then relaxes again."); return FALSE; } old_acurr = ACURR(ndx); if (incr > 0) { ABASE(ndx) += incr; if (ABASE(ndx) > AMAX(ndx)) { incr = ABASE(ndx) - AMAX(ndx); AMAX(ndx) += incr; if (AMAX(ndx) > ATTRMAX(ndx)) AMAX(ndx) = ATTRMAX(ndx); ABASE(ndx) = AMAX(ndx); } attrstr = plusattr[ndx]; abonflg = (ABON(ndx) < 0); } else { ABASE(ndx) += incr; if (ABASE(ndx) < ATTRMIN(ndx)) { incr = ABASE(ndx) - ATTRMIN(ndx); ABASE(ndx) = ATTRMIN(ndx); AMAX(ndx) += incr; if (AMAX(ndx) < ATTRMIN(ndx)) AMAX(ndx) = ATTRMIN(ndx); } attrstr = minusattr[ndx]; abonflg = (ABON(ndx) > 0); } if (ACURR(ndx) == old_acurr) { if (msgflg == 0 && flags.verbose) pline("You're %s as %s as you can get.", abonflg ? "currently" : "already", attrstr); return FALSE; } if (msgflg <= 0) You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr); context.botl = 1; if (moves > 1 && (ndx == A_STR || ndx == A_CON)) (void) encumber_msg(); return TRUE; } void gainstr(otmp, incr, givemsg) struct obj *otmp; int incr; boolean givemsg; { int num = incr; if (!num) { if (ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6)); else if (ABASE(A_STR) < STR18(85)) num = rnd(10); else num = 1; } (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, givemsg ? -1 : 1); } /* may kill you; cause may be poison or monster like 'a' */ void losestr(num) register int num; { int ustr = ABASE(A_STR) - num; while (ustr < 3) { ++ustr; --num; if (Upolyd) { u.mh -= 6; u.mhmax -= 6; } else { u.uhp -= 6; u.uhpmax -= 6; } } (void) adjattrib(A_STR, -num, 1); } static const struct poison_effect_message { void VDECL((*delivery_func), (const char *, ...)); const char *effect_msg; } poiseff[] = { { You_feel, "weaker" }, /* A_STR */ { Your, "brain is on fire" }, /* A_INT */ { Your, "judgement is impaired" }, /* A_WIS */ { Your, "muscles won't obey you" }, /* A_DEX */ { You_feel, "very sick" }, /* A_CON */ { You, "break out in hives" } /* A_CHA */ }; /* feedback for attribute loss due to poisoning */ void poisontell(typ, exclaim) int typ; /* which attribute */ boolean exclaim; /* emphasis */ { void VDECL((*func), (const char *, ...)) = poiseff[typ].delivery_func; (*func)("%s%c", poiseff[typ].effect_msg, exclaim ? '!' : '.'); } /* called when an attack or trap has poisoned the hero (used to be in mon.c) */ void poisoned(reason, typ, pkiller, fatal, thrown_weapon) const char *reason, /* controls what messages we display */ *pkiller; /* for score+log file if fatal */ int typ, fatal; /* if fatal is 0, limit damage to adjattrib */ boolean thrown_weapon; /* thrown weapons are less deadly */ { int i, loss, kprefix = KILLED_BY_AN; /* inform player about being poisoned unless that's already been done; "blast" has given a "blast of poison gas" message; "poison arrow", "poison dart", etc have implicitly given poison messages too... */ if (strcmp(reason, "blast") && !strstri(reason, "poison")) { boolean plural = (reason[strlen(reason) - 1] == 's') ? 1 : 0; /* avoid "The" Orcus's sting was poisoned... */ pline("%s%s %s poisoned!", isupper(*reason) ? "" : "The ", reason, plural ? "were" : "was"); } if (Poison_resistance) { if (!strcmp(reason, "blast")) shieldeff(u.ux, u.uy); pline_The("poison doesn't seem to affect you."); return; } /* suppress killer prefix if it already has one */ i = name_to_mon(pkiller); if (i >= LOW_PM && (mons[i].geno & G_UNIQ)) { kprefix = KILLED_BY; if (!type_is_pname(&mons[i])) pkiller = the(pkiller); } else if (!strncmpi(pkiller, "the ", 4) || !strncmpi(pkiller, "an ", 3) || !strncmpi(pkiller, "a ", 2)) { /*[ does this need a plural check too? ]*/ kprefix = KILLED_BY; } i = !fatal ? 1 : rn2(fatal + (thrown_weapon ? 20 : 0)); if (i == 0 && typ != A_CHA) { /* instant kill */ u.uhp = -1; pline_The("poison was deadly..."); } else if (i > 5) { /* HP damage; more likely--but less severe--with missiles */ loss = thrown_weapon ? rnd(6) : rn1(10, 6); losehp(loss, pkiller, kprefix); /* poison damage */ } else { /* attribute loss; if typ is A_STR, reduction in current and maximum HP will occur once strength has dropped down to 3 */ loss = (thrown_weapon || !fatal) ? 1 : d(2, 2); /* was rn1(3,3) */ /* check that a stat change was made */ if (adjattrib(typ, -loss, 1)) poisontell(typ, TRUE); } if (u.uhp < 1) { killer.format = kprefix; Strcpy(killer.name, pkiller); /* "Poisoned by a poisoned ___" is redundant */ done(strstri(pkiller, "poison") ? DIED : POISONING); } (void) encumber_msg(); } void change_luck(n) register schar n; { u.uluck += n; if (u.uluck < 0 && u.uluck < LUCKMIN) u.uluck = LUCKMIN; if (u.uluck > 0 && u.uluck > LUCKMAX) u.uluck = LUCKMAX; } int stone_luck(parameter) boolean parameter; /* So I can't think up of a good name. So sue me. --KAA */ { register struct obj *otmp; register long bonchance = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if (confers_luck(otmp)) { if (otmp->cursed) bonchance -= otmp->quan; else if (otmp->blessed) bonchance += otmp->quan; else if (parameter) bonchance += otmp->quan; } return sgn((int) bonchance); } /* there has just been an inventory change affecting a luck-granting item */ void set_moreluck() { int luckbon = stone_luck(TRUE); if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0; else if (luckbon >= 0) u.moreluck = LUCKADD; else u.moreluck = -LUCKADD; } void restore_attrib() { int i; for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */ if (ATEMP(i) && ATIME(i)) { if (!(--(ATIME(i)))) { /* countdown for change */ ATEMP(i) += ATEMP(i) > 0 ? -1 : 1; if (ATEMP(i)) /* reset timer */ ATIME(i) = 100 / ACURR(A_CON); } } } (void) encumber_msg(); } #define AVAL 50 /* tune value for exercise gains */ void exercise(i, inc_or_dec) int i; boolean inc_or_dec; { debugpline0("Exercise:"); if (i == A_INT || i == A_CHA) return; /* can't exercise these */ /* no physical exercise while polymorphed; the body's temporary */ if (Upolyd && i != A_WIS) return; if (abs(AEXE(i)) < AVAL) { /* * Law of diminishing returns (Part I): * * Gain is harder at higher attribute values. * 79% at "3" --> 0% at "18" * Loss is even at all levels (50%). * * Note: *YES* ACURR is the right one to use. */ AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2); debugpline3("%s, %s AEXE = %d", (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" : (i == A_DEX) ? "Dex" : "Con", (inc_or_dec) ? "inc" : "dec", AEXE(i)); } if (moves > 0 && (i == A_STR || i == A_CON)) (void) encumber_msg(); } STATIC_OVL void exerper() { if (!(moves % 10)) { /* Hunger Checks */ int hs = (u.uhunger > 1000) ? SATIATED : (u.uhunger > 150) ? NOT_HUNGRY : (u.uhunger > 50) ? HUNGRY : (u.uhunger > 0) ? WEAK : FAINTING; debugpline0("exerper: Hunger checks"); switch (hs) { case SATIATED: exercise(A_DEX, FALSE); if (Role_if(PM_MONK)) exercise(A_WIS, FALSE); break; case NOT_HUNGRY: exercise(A_CON, TRUE); break; case WEAK: exercise(A_STR, FALSE); if (Role_if(PM_MONK)) /* fasting */ exercise(A_WIS, TRUE); break; case FAINTING: case FAINTED: exercise(A_CON, FALSE); break; } /* Encumbrance Checks */ debugpline0("exerper: Encumber checks"); switch (near_capacity()) { case MOD_ENCUMBER: exercise(A_STR, TRUE); break; case HVY_ENCUMBER: exercise(A_STR, TRUE); exercise(A_DEX, FALSE); break; case EXT_ENCUMBER: exercise(A_DEX, FALSE); exercise(A_CON, FALSE); break; } } /* status checks */ if (!(moves % 5)) { debugpline0("exerper: Status checks"); if ((HClairvoyant & (INTRINSIC | TIMEOUT)) && !BClairvoyant) exercise(A_WIS, TRUE); if (HRegeneration) exercise(A_STR, TRUE); if (Sick || Vomiting) exercise(A_CON, FALSE); if (Confusion || Hallucination) exercise(A_WIS, FALSE); if ((Wounded_legs && !u.usteed) || Fumbling || HStun) exercise(A_DEX, FALSE); } } /* exercise/abuse text (must be in attribute order, not botl order); phrased as "You must have been [][0]." or "You haven't been [][1]." */ static NEARDATA const char *const exertext[A_MAX][2] = { { "exercising diligently", "exercising properly" }, /* Str */ { 0, 0 }, /* Int */ { "very observant", "paying attention" }, /* Wis */ { "working on your reflexes", "working on reflexes lately" }, /* Dex */ { "leading a healthy life-style", "watching your health" }, /* Con */ { 0, 0 }, /* Cha */ }; void exerchk() { int i, ax, mod_val, lolim, hilim; /* Check out the periodic accumulations */ exerper(); if (moves >= context.next_attrib_check) { debugpline1("exerchk: ready to test. multi = %d.", multi); } /* Are we ready for a test? */ if (moves >= context.next_attrib_check && !multi) { debugpline0("exerchk: testing."); /* * Law of diminishing returns (Part II): * * The effects of "exercise" and "abuse" wear * off over time. Even if you *don't* get an * increase/decrease, you lose some of the * accumulated effects. */ for (i = 0; i < A_MAX; ++i) { ax = AEXE(i); /* nothing to do here if no exercise or abuse has occurred (Int and Cha always fall into this category) */ if (!ax) continue; /* ok to skip nextattrib */ mod_val = sgn(ax); /* +1 or -1; used below */ /* no further effect for exercise if at max or abuse if at min; can't exceed 18 via exercise even if actual max is higher */ lolim = ATTRMIN(i); /* usually 3; might be higher */ hilim = ATTRMAX(i); /* usually 18; maybe lower or higher */ if (hilim > 18) hilim = 18; if ((ax < 0) ? (ABASE(i) <= lolim) : (ABASE(i) >= hilim)) goto nextattrib; /* can't exercise non-Wisdom while polymorphed; previous exercise/abuse gradually wears off without impact then */ if (Upolyd && i != A_WIS) goto nextattrib; debugpline2("exerchk: testing %s (%d).", (i == A_STR) ? "Str" : (i == A_INT) ? "Int?" : (i == A_WIS) ? "Wis" : (i == A_DEX) ? "Dex" : (i == A_CON) ? "Con" : (i == A_CHA) ? "Cha?" : "???", ax); /* * Law of diminishing returns (Part III): * * You don't *always* gain by exercising. * [MRS 92/10/28 - Treat Wisdom specially for balance.] */ if (rn2(AVAL) > ((i != A_WIS) ? (abs(ax) * 2 / 3) : abs(ax))) goto nextattrib; debugpline1("exerchk: changing %d.", i); if (adjattrib(i, mod_val, -1)) { debugpline1("exerchk: changed %d.", i); /* if you actually changed an attrib - zero accumulation */ AEXE(i) = ax = 0; /* then print an explanation */ You("%s %s.", (mod_val > 0) ? "must have been" : "haven't been", exertext[i][(mod_val > 0) ? 0 : 1]); } nextattrib: /* this used to be ``AEXE(i) /= 2'' but that would produce platform-dependent rounding/truncation for negative vals */ AEXE(i) = (abs(ax) / 2) * mod_val; } context.next_attrib_check += rn1(200, 800); debugpline1("exerchk: next check at %ld.", context.next_attrib_check); } } void init_attr(np) register int np; { register int i, x, tryct; for (i = 0; i < A_MAX; i++) { ABASE(i) = AMAX(i) = urole.attrbase[i]; ATEMP(i) = ATIME(i) = 0; np -= urole.attrbase[i]; } tryct = 0; while (np > 0 && tryct < 100) { x = rn2(100); for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ; if (i >= A_MAX) continue; /* impossible */ if (ABASE(i) >= ATTRMAX(i)) { tryct++; continue; } tryct = 0; ABASE(i)++; AMAX(i)++; np--; } tryct = 0; while (np < 0 && tryct < 100) { /* for redistribution */ x = rn2(100); for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ; if (i >= A_MAX) continue; /* impossible */ if (ABASE(i) <= ATTRMIN(i)) { tryct++; continue; } tryct = 0; ABASE(i)--; AMAX(i)--; np++; } } void redist_attr() { register int i, tmp; for (i = 0; i < A_MAX; i++) { if (i == A_INT || i == A_WIS) continue; /* Polymorphing doesn't change your mind */ tmp = AMAX(i); AMAX(i) += (rn2(5) - 2); if (AMAX(i) > ATTRMAX(i)) AMAX(i) = ATTRMAX(i); if (AMAX(i) < ATTRMIN(i)) AMAX(i) = ATTRMIN(i); ABASE(i) = ABASE(i) * AMAX(i) / tmp; /* ABASE(i) > ATTRMAX(i) is impossible */ if (ABASE(i) < ATTRMIN(i)) ABASE(i) = ATTRMIN(i); } (void) encumber_msg(); } STATIC_OVL void postadjabil(ability) long *ability; { if (!ability) return; if (ability == &(HWarning) || ability == &(HSee_invisible)) see_monsters(); } STATIC_OVL const struct innate * check_innate_abil(ability, frommask) long *ability; long frommask; { const struct innate *abil = 0; if (frommask == FROMEXPER) switch (Role_switch) { case PM_ARCHEOLOGIST: abil = arc_abil; break; case PM_BARBARIAN: abil = bar_abil; break; case PM_CAVEMAN: abil = cav_abil; break; case PM_HEALER: abil = hea_abil; break; case PM_KNIGHT: abil = kni_abil; break; case PM_MONK: abil = mon_abil; break; case PM_PRIEST: abil = pri_abil; break; case PM_RANGER: abil = ran_abil; break; case PM_ROGUE: abil = rog_abil; break; case PM_SAMURAI: abil = sam_abil; break; case PM_TOURIST: abil = tou_abil; break; case PM_VALKYRIE: abil = val_abil; break; case PM_WIZARD: abil = wiz_abil; break; default: break; } else if (frommask == FROMRACE) switch (Race_switch) { case PM_ELF: abil = elf_abil; break; case PM_ORC: abil = orc_abil; break; case PM_HUMAN: case PM_DWARF: case PM_GNOME: default: break; } while (abil && abil->ability) { if ((abil->ability == ability) && (u.ulevel >= abil->ulevel)) return abil; abil++; } return (struct innate *) 0; } /* * returns 1 if FROMRACE or FROMEXPER and exper level == 1 * returns 2 if FROMEXPER and exper level > 1 * otherwise returns 0 */ STATIC_OVL int innately(ability) long *ability; { const struct innate *iptr; if ((iptr = check_innate_abil(ability, FROMRACE)) != 0) return 1; else if ((iptr = check_innate_abil(ability, FROMEXPER)) != 0) return (iptr->ulevel == 1) ? 1 : 2; return 0; } int is_innate(propidx) int propidx; { if (propidx == BLINDED && !haseyes(youmonst.data)) return 1; return innately(&u.uprops[propidx].intrinsic); } char * from_what(propidx) int propidx; /* special cases can have negative values */ { static char buf[BUFSZ]; buf[0] = '\0'; /* * Restrict the source of the attributes just to debug mode for now */ if (wizard) { static NEARDATA const char because_of[] = " because of %s"; if (propidx >= 0) { char *p; struct obj *obj = (struct obj *) 0; int innate = is_innate(propidx); if (innate == 2) Strcpy(buf, " because of your experience"); else if (innate == 1) Strcpy(buf, " innately"); else if (wizard && (obj = what_gives(&u.uprops[propidx].extrinsic))) Sprintf(buf, because_of, obj->oartifact ? bare_artifactname(obj) : ysimple_name(obj)); else if (propidx == BLINDED && u.uroleplay.blind) Sprintf(buf, " from birth"); else if (propidx == BLINDED && Blindfolded_only) Sprintf(buf, because_of, ysimple_name(ublindf)); /* remove some verbosity and/or redundancy */ if ((p = strstri(buf, " pair of ")) != 0) copynchars(p + 1, p + 9, BUFSZ); /* overlapping buffers ok */ else if (propidx == STRANGLED && (p = strstri(buf, " of strangulation")) != 0) *p = '\0'; } else { /* negative property index */ /* if more blocking capabilities get implemented we'll need to replace this with what_blocks() comparable to what_gives() */ switch (-propidx) { case BLINDED: if (ublindf && ublindf->oartifact == ART_EYES_OF_THE_OVERWORLD) Sprintf(buf, because_of, bare_artifactname(ublindf)); break; case INVIS: if (u.uprops[INVIS].blocked & W_ARMC) Sprintf(buf, because_of, ysimple_name(uarmc)); /* mummy wrapping */ break; case CLAIRVOYANT: if (wizard && (u.uprops[CLAIRVOYANT].blocked & W_ARMH)) Sprintf(buf, because_of, ysimple_name(uarmh)); /* cornuthaum */ break; } } } /*wizard*/ return buf; } void adjabil(oldlevel, newlevel) int oldlevel, newlevel; { register const struct innate *abil, *rabil; long prevabil, mask = FROMEXPER; switch (Role_switch) { case PM_ARCHEOLOGIST: abil = arc_abil; break; case PM_BARBARIAN: abil = bar_abil; break; case PM_CAVEMAN: abil = cav_abil; break; case PM_HEALER: abil = hea_abil; break; case PM_KNIGHT: abil = kni_abil; break; case PM_MONK: abil = mon_abil; break; case PM_PRIEST: abil = pri_abil; break; case PM_RANGER: abil = ran_abil; break; case PM_ROGUE: abil = rog_abil; break; case PM_SAMURAI: abil = sam_abil; break; case PM_TOURIST: abil = tou_abil; break; case PM_VALKYRIE: abil = val_abil; break; case PM_WIZARD: abil = wiz_abil; break; default: abil = 0; break; } switch (Race_switch) { case PM_ELF: rabil = elf_abil; break; case PM_ORC: rabil = orc_abil; break; case PM_HUMAN: case PM_DWARF: case PM_GNOME: default: rabil = 0; break; } while (abil || rabil) { /* Have we finished with the intrinsics list? */ if (!abil || !abil->ability) { /* Try the race intrinsics */ if (!rabil || !rabil->ability) break; abil = rabil; rabil = 0; mask = FROMRACE; } prevabil = *(abil->ability); if (oldlevel < abil->ulevel && newlevel >= abil->ulevel) { /* Abilities gained at level 1 can never be lost * via level loss, only via means that remove _any_ * sort of ability. A "gain" of such an ability from * an outside source is devoid of meaning, so we set * FROMOUTSIDE to avoid such gains. */ if (abil->ulevel == 1) *(abil->ability) |= (mask | FROMOUTSIDE); else *(abil->ability) |= mask; if (!(*(abil->ability) & INTRINSIC & ~mask)) { if (*(abil->gainstr)) You_feel("%s!", abil->gainstr); } } else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) { *(abil->ability) &= ~mask; if (!(*(abil->ability) & INTRINSIC)) { if (*(abil->losestr)) You_feel("%s!", abil->losestr); else if (*(abil->gainstr)) You_feel("less %s!", abil->gainstr); } } if (prevabil != *(abil->ability)) /* it changed */ postadjabil(abil->ability); abil++; } if (oldlevel > 0) { if (newlevel > oldlevel) add_weapon_skill(newlevel - oldlevel); else lose_weapon_skill(oldlevel - newlevel); } } int newhp() { int hp, conplus; if (u.ulevel == 0) { /* Initialize hit points */ hp = urole.hpadv.infix + urace.hpadv.infix; if (urole.hpadv.inrnd > 0) hp += rnd(urole.hpadv.inrnd); if (urace.hpadv.inrnd > 0) hp += rnd(urace.hpadv.inrnd); if (moves <= 1L) { /* initial hero; skip for polyself to new man */ /* Initialize alignment stuff */ u.ualign.type = aligns[flags.initalign].value; u.ualign.record = urole.initrecord; } /* no Con adjustment for initial hit points */ } else { if (u.ulevel < urole.xlev) { hp = urole.hpadv.lofix + urace.hpadv.lofix; if (urole.hpadv.lornd > 0) hp += rnd(urole.hpadv.lornd); if (urace.hpadv.lornd > 0) hp += rnd(urace.hpadv.lornd); } else { hp = urole.hpadv.hifix + urace.hpadv.hifix; if (urole.hpadv.hirnd > 0) hp += rnd(urole.hpadv.hirnd); if (urace.hpadv.hirnd > 0) hp += rnd(urace.hpadv.hirnd); } if (ACURR(A_CON) <= 3) conplus = -2; else if (ACURR(A_CON) <= 6) conplus = -1; else if (ACURR(A_CON) <= 14) conplus = 0; else if (ACURR(A_CON) <= 16) conplus = 1; else if (ACURR(A_CON) == 17) conplus = 2; else if (ACURR(A_CON) == 18) conplus = 3; else conplus = 4; hp += conplus; } if (hp <= 0) hp = 1; if (u.ulevel < MAXULEV) u.uhpinc[u.ulevel] = (xchar) hp; return hp; } schar acurr(x) int x; { register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]); if (x == A_STR) { if (tmp >= 125 || (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER)) return (schar) 125; else #ifdef WIN32_BUG return (x = ((tmp <= 3) ? 3 : tmp)); #else return (schar) ((tmp <= 3) ? 3 : tmp); #endif } else if (x == A_CHA) { if (tmp < 18 && (youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS)) return (schar) 18; } else if (x == A_INT || x == A_WIS) { /* yes, this may raise int/wis if player is sufficiently * stupid. there are lower levels of cognition than "dunce". */ if (uarmh && uarmh->otyp == DUNCE_CAP) return (schar) 6; } #ifdef WIN32_BUG return (x = ((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp)); #else return (schar) ((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp); #endif } /* condense clumsy ACURR(A_STR) value into value that fits into game formulas */ schar acurrstr() { register int str = ACURR(A_STR); if (str <= 18) return (schar) str; if (str <= 121) return (schar) (19 + str / 50); /* map to 19..21 */ else return (schar) (min(str, 125) - 100); /* 22..25 */ } /* when wearing (or taking off) an unID'd item, this routine is used to distinguish between observable +0 result and no-visible-effect due to an attribute not being able to exceed maximum or minimum */ boolean extremeattr(attrindx) /* does attrindx's value match its max or min? */ int attrindx; { /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */ int lolimit = 3, hilimit = 25, curval = ACURR(attrindx); /* upper limit for Str is 25 but its value is encoded differently */ if (attrindx == A_STR) { hilimit = STR19(25); /* 125 */ /* lower limit for Str can also be 25 */ if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) lolimit = hilimit; } /* this exception is hypothetical; the only other worn item affecting Int or Wis is another helmet so can't be in use at the same time */ if (attrindx == A_INT || attrindx == A_WIS) { if (uarmh && uarmh->otyp == DUNCE_CAP) hilimit = lolimit = 6; } /* are we currently at either limit? */ return (curval == lolimit || curval == hilimit) ? TRUE : FALSE; } /* avoid possible problems with alignment overflow, and provide a centralized location for any future alignment limits */ void adjalign(n) int n; { int newalign = u.ualign.record + n; if (n < 0) { if (newalign < u.ualign.record) u.ualign.record = newalign; } else if (newalign > u.ualign.record) { u.ualign.record = newalign; if (u.ualign.record > ALIGNLIM) u.ualign.record = ALIGNLIM; } } /* change hero's alignment type, possibly losing use of artifacts */ void uchangealign(newalign, reason) int newalign; int reason; /* 0==conversion, 1==helm-of-OA on, 2==helm-of-OA off */ { aligntyp oldalign = u.ualign.type; u.ublessed = 0; /* lose divine protection */ context.botl = 1; /* status line needs updating */ if (reason == 0) { /* conversion via altar */ u.ualignbase[A_CURRENT] = (aligntyp) newalign; /* worn helm of opposite alignment might block change */ if (!uarmh || uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT) u.ualign.type = u.ualignbase[A_CURRENT]; You("have a %ssense of a new direction.", (u.ualign.type != oldalign) ? "sudden " : ""); } else { /* putting on or taking off a helm of opposite alignment */ u.ualign.type = (aligntyp) newalign; if (reason == 1) Your("mind oscillates %s.", Hallucination ? "wildly" : "briefly"); else if (reason == 2) Your("mind is %s.", Hallucination ? "much of a muchness" : "back in sync with your body"); } if (u.ualign.type != oldalign) { u.ualign.record = 0; /* slate is wiped clean */ retouch_equipment(0); } } /*attrib.c*/ nethack-3.6.0/src/ball.c0000664000076400007660000007071012617122742014013 0ustar paxedpaxed/* NetHack 3.6 ball.c $NHDT-Date: 1446808438 2015/11/06 11:13:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Ball & Chain * =============================================================*/ #include "hack.h" STATIC_DCL int NDECL(bc_order); STATIC_DCL void NDECL(litter); void ballrelease(showmsg) boolean showmsg; { if (carried(uball)) { if (showmsg) pline("Startled, you drop the iron ball."); if (uwep == uball) setuwep((struct obj *) 0); if (uswapwep == uball) setuswapwep((struct obj *) 0); if (uquiver == uball) setuqwep((struct obj *) 0); ; if (uwep != uball) freeinv(uball); } } void ballfall() { boolean gets_hit; gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) && ((uwep == uball) ? FALSE : (boolean) rn2(5))); ballrelease(TRUE); if (gets_hit) { int dmg = rn1(7, 25); pline_The("iron ball falls on your %s.", body_part(HEAD)); if (uarmh) { if (is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); dmg = 3; } else if (flags.verbose) pline("%s does not protect you.", Yname2(uarmh)); } losehp(Maybe_Half_Phys(dmg), "crunched in the head by an iron ball", NO_KILLER_PREFIX); } } /* * To make this work, we have to mess with the hero's mind. The rules for * ball&chain are: * * 1. If the hero can see them, fine. * 2. If the hero can't see either, it isn't seen. * 3. If either is felt it is seen. * 4. If either is felt and moved, it disappears. * * If the hero can see, then when a move is done, the ball and chain are * first picked up, the positions under them are corrected, then they * are moved after the hero moves. Not too bad. * * If the hero is blind, then she can "feel" the ball and/or chain at any * time. However, when the hero moves, the felt ball and/or chain become * unfelt and whatever was felt "under" the ball&chain appears. Pretty * nifty, but it requires that the ball&chain "remember" what was under * them --- i.e. they pick-up glyphs when they are felt and drop them when * moved (and felt). When swallowed, the ball&chain are pulled completely * off of the dungeon, but are still on the object chain. They are placed * under the hero when she is expelled. */ /* * from you.h * int u.bglyph glyph under the ball * int u.cglyph glyph under the chain * int u.bc_felt mask for ball/chain being felt * #define BC_BALL 0x01 bit mask in u.bc_felt for ball * #define BC_CHAIN 0x02 bit mask in u.bc_felt for chain * int u.bc_order ball & chain order * * u.bc_felt is also manipulated in display.c and read.c, the others only * in this file. None of these variables are valid unless the player is * Blind. */ /* values for u.bc_order */ #define BCPOS_DIFFER 0 /* ball & chain at different positions */ #define BCPOS_CHAIN 1 /* chain on top of ball */ #define BCPOS_BALL 2 /* ball on top of chain */ /* * Place the ball & chain under the hero. Make sure that the ball & chain * variables are set (actually only needed when blind, but what the heck). * It is assumed that when this is called, the ball and chain are NOT * attached to the object list. * * Should not be called while swallowed except on waterlevel. */ void placebc() { if (!uchain || !uball) { impossible("Where are your ball and chain?"); return; } (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */ if (carried(uball)) /* the ball is carried */ u.bc_order = BCPOS_DIFFER; else { /* ball might rust -- already checked when carried */ (void) flooreffects(uball, u.ux, u.uy, ""); place_object(uball, u.ux, u.uy); u.bc_order = BCPOS_CHAIN; } place_object(uchain, u.ux, u.uy); u.bglyph = u.cglyph = levl[u.ux][u.uy].glyph; /* pick up glyph */ newsym(u.ux, u.uy); } void unplacebc() { if (u.uswallow) { if (Is_waterlevel(&u.uz)) { /* we need to proceed with the removal from the floor * so that movebubbles() processing will disregard it as * intended. Ignore all the vision stuff. */ if (!carried(uball)) obj_extract_self(uball); obj_extract_self(uchain); } /* ball&chain not unplaced while swallowed */ return; } if (!carried(uball)) { obj_extract_self(uball); if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */ levl[uball->ox][uball->oy].glyph = u.bglyph; newsym(uball->ox, uball->oy); } obj_extract_self(uchain); if (Blind && (u.bc_felt & BC_CHAIN)) /* drop glyph */ levl[uchain->ox][uchain->oy].glyph = u.cglyph; newsym(uchain->ox, uchain->oy); u.bc_felt = 0; /* feel nothing */ } /* * Return the stacking of the hero's ball & chain. This assumes that the * hero is being punished. */ STATIC_OVL int bc_order() { struct obj *obj; if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball) || u.uswallow) return BCPOS_DIFFER; for (obj = level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) { if (obj == uchain) return BCPOS_CHAIN; if (obj == uball) return BCPOS_BALL; } impossible("bc_order: ball&chain not in same location!"); return BCPOS_DIFFER; } /* * set_bc() * * The hero is either about to go blind or already blind and just punished. * Set up the ball and chain variables so that the ball and chain are "felt". */ void set_bc(already_blind) int already_blind; { int ball_on_floor = !carried(uball); u.bc_order = bc_order(); /* get the order */ u.bc_felt = ball_on_floor ? BC_BALL | BC_CHAIN : BC_CHAIN; /* felt */ if (already_blind || u.uswallow) { u.cglyph = u.bglyph = levl[u.ux][u.uy].glyph; return; } /* * Since we can still see, remove the ball&chain and get the glyph that * would be beneath them. Then put the ball&chain back. This is pretty * disgusting, but it will work. */ remove_object(uchain); if (ball_on_floor) remove_object(uball); newsym(uchain->ox, uchain->oy); u.cglyph = levl[uchain->ox][uchain->oy].glyph; if (u.bc_order == BCPOS_DIFFER) { /* different locations */ place_object(uchain, uchain->ox, uchain->oy); newsym(uchain->ox, uchain->oy); if (ball_on_floor) { newsym(uball->ox, uball->oy); /* see under ball */ u.bglyph = levl[uball->ox][uball->oy].glyph; place_object(uball, uball->ox, uball->oy); newsym(uball->ox, uball->oy); /* restore ball */ } } else { u.bglyph = u.cglyph; if (u.bc_order == BCPOS_CHAIN) { place_object(uball, uball->ox, uball->oy); place_object(uchain, uchain->ox, uchain->oy); } else { place_object(uchain, uchain->ox, uchain->oy); place_object(uball, uball->ox, uball->oy); } newsym(uball->ox, uball->oy); } } /* * move_bc() * * Move the ball and chain. This is called twice for every move. The first * time to pick up the ball and chain before the move, the second time to * place the ball and chain after the move. If the ball is carried, this * function should never have BC_BALL as part of its control. * * Should not be called while swallowed. */ void move_bc(before, control, ballx, bally, chainx, chainy) int before, control; xchar ballx, bally, chainx, chainy; /* only matter !before */ { if (Blind) { /* * The hero is blind. Time to work hard. The ball and chain that * are attached to the hero are very special. The hero knows that * they are attached, so when they move, the hero knows that they * aren't at the last position remembered. This is complicated * by the fact that the hero can "feel" the surrounding locations * at any time, hence, making one or both of them show up again. * So, we have to keep track of which is felt at any one time and * act accordingly. */ if (!before) { if ((control & BC_CHAIN) && (control & BC_BALL)) { /* * Both ball and chain moved. If felt, drop glyph. */ if (u.bc_felt & BC_BALL) levl[uball->ox][uball->oy].glyph = u.bglyph; if (u.bc_felt & BC_CHAIN) levl[uchain->ox][uchain->oy].glyph = u.cglyph; u.bc_felt = 0; /* Pick up glyph at new location. */ u.bglyph = levl[ballx][bally].glyph; u.cglyph = levl[chainx][chainy].glyph; movobj(uball, ballx, bally); movobj(uchain, chainx, chainy); } else if (control & BC_BALL) { if (u.bc_felt & BC_BALL) { if (u.bc_order == BCPOS_DIFFER) { /* ball by itself */ levl[uball->ox][uball->oy].glyph = u.bglyph; } else if (u.bc_order == BCPOS_BALL) { if (u.bc_felt & BC_CHAIN) { /* know chain is there */ map_object(uchain, 0); } else { levl[uball->ox][uball->oy].glyph = u.bglyph; } } u.bc_felt &= ~BC_BALL; /* no longer feel the ball */ } /* Pick up glyph at new position. */ u.bglyph = (ballx != chainx || bally != chainy) ? levl[ballx][bally].glyph : u.cglyph; movobj(uball, ballx, bally); } else if (control & BC_CHAIN) { if (u.bc_felt & BC_CHAIN) { if (u.bc_order == BCPOS_DIFFER) { levl[uchain->ox][uchain->oy].glyph = u.cglyph; } else if (u.bc_order == BCPOS_CHAIN) { if (u.bc_felt & BC_BALL) { map_object(uball, 0); } else { levl[uchain->ox][uchain->oy].glyph = u.cglyph; } } u.bc_felt &= ~BC_CHAIN; } /* Pick up glyph at new position. */ u.cglyph = (ballx != chainx || bally != chainy) ? levl[chainx][chainy].glyph : u.bglyph; movobj(uchain, chainx, chainy); } u.bc_order = bc_order(); /* reset the order */ } } else { /* * The hero is not blind. To make this work correctly, we need to * pick up the ball and chain before the hero moves, then put them * in their new positions after the hero moves. */ if (before) { if (!control) { /* * Neither ball nor chain is moving, so remember which was * on top until !before. Use the variable u.bc_order * since it is only valid when blind. */ u.bc_order = bc_order(); } remove_object(uchain); newsym(uchain->ox, uchain->oy); if (!carried(uball)) { remove_object(uball); newsym(uball->ox, uball->oy); } } else { int on_floor = !carried(uball); if ((control & BC_CHAIN) || (!control && u.bc_order == BCPOS_CHAIN)) { /* If the chain moved or nothing moved & chain on top. */ if (on_floor) place_object(uball, ballx, bally); place_object(uchain, chainx, chainy); /* chain on top */ } else { place_object(uchain, chainx, chainy); if (on_floor) place_object(uball, ballx, bally); /* ball on top */ } newsym(chainx, chainy); if (on_floor) newsym(ballx, bally); } } } /* return TRUE if the caller needs to place the ball and chain down again * * Should not be called while swallowed. Should be called before movement, * because we might want to move the ball or chain to the hero's old * position. * * It is called if we are moving. It is also called if we are teleporting * *if* the ball doesn't move and we thus must drag the chain. It is not * called for ordinary teleportation. * * allow_drag is only used in the ugly special case where teleporting must * drag the chain, while an identical-looking movement must drag both the ball * and chain. */ boolean drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay, allow_drag) xchar x, y; int *bc_control; xchar *ballx, *bally, *chainx, *chainy; boolean *cause_delay; boolean allow_drag; { struct trap *t = (struct trap *) 0; boolean already_in_rock; *ballx = uball->ox; *bally = uball->oy; *chainx = uchain->ox; *chainy = uchain->oy; *bc_control = 0; *cause_delay = FALSE; if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */ move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); return TRUE; } /* only need to move the chain? */ if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) { xchar oldchainx = uchain->ox, oldchainy = uchain->oy; *bc_control = BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (carried(uball)) { /* move chain only if necessary */ if (distmin(x, y, uchain->ox, uchain->oy) > 1) { *chainx = u.ux; *chainy = u.uy; } return TRUE; } #define CHAIN_IN_MIDDLE(chx, chy) \ (distmin(x, y, chx, chy) <= 1 \ && distmin(chx, chy, uball->ox, uball->oy) <= 1) #define IS_CHAIN_ROCK(x, y) \ (IS_ROCK(levl[x][y].typ) \ || (IS_DOOR(levl[x][y].typ) \ && (levl[x][y].doormask & (D_CLOSED | D_LOCKED)))) /* Don't ever move the chain into solid rock. If we have to, then instead * undo the move_bc() and jump to the drag ball code. Note that this also * means the "cannot carry and drag" message will not appear, since unless we * moved at least two squares there is no possibility of the chain position * being in solid rock. */ #define SKIP_TO_DRAG \ { \ *chainx = oldchainx; \ *chainy = oldchainy; \ move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \ goto drag; \ } if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy) || IS_CHAIN_ROCK(uball->ox, uball->oy)) already_in_rock = TRUE; else already_in_rock = FALSE; switch (dist2(x, y, uball->ox, uball->oy)) { /* two spaces diagonal from ball, move chain inbetween */ case 8: *chainx = (uball->ox + x) / 2; *chainy = (uball->oy + y) / 2; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; /* player is distance 2/1 from ball; move chain to one of the * two spaces between * @ * __ * 0 */ case 5: { xchar tempx, tempy, tempx2, tempy2; /* find position closest to current position of chain */ /* no effect if current position is already OK */ if (abs(x - uball->ox) == 1) { tempx = x; tempx2 = uball->ox; tempy = tempy2 = (uball->oy + y) / 2; } else { tempx = tempx2 = (uball->ox + x) / 2; tempy = y; tempy2 = uball->oy; } if (IS_CHAIN_ROCK(tempx, tempy) && !IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { if (allow_drag) { /* Avoid pathological case *if* not teleporting: * 0 0_ * _X move northeast -----> X@ * @ */ if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && dist2(x, y, tempx, tempy) == 1) SKIP_TO_DRAG; /* Avoid pathological case *if* not teleporting: * 0 0 * _X move east -----> X_ * @ @ */ if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && dist2(x, y, tempx, tempy) == 2) SKIP_TO_DRAG; } *chainx = tempx2; *chainy = tempy2; } else if (!IS_CHAIN_ROCK(tempx, tempy) && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { if (allow_drag) { if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && dist2(x, y, tempx2, tempy2) == 1) SKIP_TO_DRAG; if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && dist2(x, y, tempx2, tempy2) == 2) SKIP_TO_DRAG; } *chainx = tempx; *chainy = tempy; } else if (IS_CHAIN_ROCK(tempx, tempy) && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { SKIP_TO_DRAG; } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) < dist2(tempx2, tempy2, uchain->ox, uchain->oy) || ((dist2(tempx, tempy, uchain->ox, uchain->oy) == dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) { *chainx = tempx; *chainy = tempy; } else { *chainx = tempx2; *chainy = tempy2; } break; } /* ball is two spaces horizontal or vertical from player; move*/ /* chain inbetween *unless* current chain position is OK */ case 4: if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; *chainx = (x + uball->ox) / 2; *chainy = (y + uball->oy) / 2; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; /* ball is one space diagonal from player. Check for the * following special case: * @ * _ moving southwest becomes @_ * 0 0 * (This will also catch teleporting that happens to resemble * this case, but oh well.) Otherwise fall through. */ case 2: if (dist2(x, y, uball->ox, uball->oy) == 2 && dist2(x, y, uchain->ox, uchain->oy) == 4) { if (uchain->oy == y) *chainx = uball->ox; else *chainy = uball->oy; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; } /* fall through */ case 1: case 0: /* do nothing if possible */ if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; /* otherwise try to drag chain to player's old position */ if (CHAIN_IN_MIDDLE(u.ux, u.uy)) { *chainx = u.ux; *chainy = u.uy; break; } /* otherwise use player's new position (they must have teleported, for this to happen) */ *chainx = x; *chainy = y; break; default: impossible("bad chain movement"); break; } #undef SKIP_TO_DRAG #undef CHAIN_IN_MIDDLE return TRUE; } drag: if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) { You("cannot %sdrag the heavy iron ball.", invent ? "carry all that and also " : ""); nomul(0); return FALSE; } if ((is_pool(uchain->ox, uchain->oy) /* water not mere continuation of previous water */ && (levl[uchain->ox][uchain->oy].typ == POOL || !is_pool(uball->ox, uball->oy) || levl[uball->ox][uball->oy].typ == POOL)) || ((t = t_at(uchain->ox, uchain->oy)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE || t->ttyp == TRAPDOOR))) { if (Levitation) { You_feel("a tug from the iron ball."); if (t) t->tseen = 1; } else { struct monst *victim; You("are jerked back by the iron ball!"); if ((victim = m_at(uchain->ox, uchain->oy)) != 0) { int tmp; tmp = -2 + Luck + find_mac(victim); tmp += omon_adj(victim, uball, TRUE); if (tmp >= rnd(20)) (void) hmon(victim, uball, HMON_DRAGGED); else miss(xname(uball), victim); } /* now check again in case mon died */ if (!m_at(uchain->ox, uchain->oy)) { u.ux = uchain->ox; u.uy = uchain->oy; newsym(u.ux0, u.uy0); } nomul(0); *bc_control = BC_BALL; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); *ballx = uchain->ox; *bally = uchain->oy; move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); spoteffects(TRUE); return FALSE; } } *bc_control = BC_BALL | BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (dist2(x, y, u.ux, u.uy) > 2) { /* Awful case: we're still in range of the ball, so we thought we * could only move the chain, but it turned out that the target * square for the chain was rock, so we had to drag it instead. * But we can't drag it either, because we teleported and are more * than one square from our old position. Revert to the teleport * behavior. */ *ballx = *chainx = x; *bally = *chainy = y; } else { xchar newchainx = u.ux, newchainy = u.uy; /* * Generally, chain moves to hero's previous location and ball * moves to chain's previous location, except that we try to * keep the chain directly between the hero and the ball. But, * take the simple approach if the hero's previous location or * the potential between location is inaccessible. */ if (dist2(x, y, uchain->ox, uchain->oy) == 4 && !IS_CHAIN_ROCK(newchainx, newchainy)) { newchainx = (x + uchain->ox) / 2; newchainy = (y + uchain->oy) / 2; if (IS_CHAIN_ROCK(newchainx, newchainy)) { /* don't let chain move to inaccessible location */ newchainx = u.ux; newchainy = u.uy; } } *ballx = uchain->ox; *bally = uchain->oy; *chainx = newchainx; *chainy = newchainy; } #undef IS_CHAIN_ROCK *cause_delay = TRUE; return TRUE; } /* * drop_ball() * * The punished hero drops or throws her iron ball. If the hero is * blind, we must reset the order and glyph. Check for side effects. * This routine expects the ball to be already placed. * * Should not be called while swallowed. */ void drop_ball(x, y) xchar x, y; { if (Blind) { /* get the order */ u.bc_order = bc_order(); /* pick up glyph */ u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph; } if (x != u.ux || y != u.uy) { struct trap *t; const char *pullmsg = "The ball pulls you out of the %s!"; if (u.utrap && u.utraptype != TT_INFLOOR && u.utraptype != TT_BURIEDBALL) { switch (u.utraptype) { case TT_PIT: pline(pullmsg, "pit"); break; case TT_WEB: pline(pullmsg, "web"); pline_The("web is destroyed!"); deltrap(t_at(u.ux, u.uy)); break; case TT_LAVA: pline(pullmsg, "lava"); break; case TT_BEARTRAP: { register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; pline(pullmsg, "bear trap"); set_wounded_legs(side, rn1(1000, 500)); if (!u.usteed) { Your("%s %s is severely damaged.", (side == LEFT_SIDE) ? "left" : "right", body_part(LEG)); losehp(Maybe_Half_Phys(2), "leg damage from being pulled out of a bear trap", KILLED_BY); } break; } } u.utrap = 0; fill_pit(u.ux, u.uy); } u.ux0 = u.ux; u.uy0 = u.uy; if (!Levitation && !MON_AT(x, y) && !u.utrap && (is_pool(x, y) || ((t = t_at(x, y)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { u.ux = x; u.uy = y; } else { u.ux = x - u.dx; u.uy = y - u.dy; } vision_full_recalc = 1; /* hero has moved, recalculate vision later */ if (Blind) { /* drop glyph under the chain */ if (u.bc_felt & BC_CHAIN) levl[uchain->ox][uchain->oy].glyph = u.cglyph; u.bc_felt = 0; /* feel nothing */ /* pick up new glyph */ u.cglyph = (u.bc_order) ? u.bglyph : levl[u.ux][u.uy].glyph; } movobj(uchain, u.ux, u.uy); /* has a newsym */ if (Blind) { u.bc_order = bc_order(); } newsym(u.ux0, u.uy0); /* clean up old position */ if (u.ux0 != u.ux || u.uy0 != u.uy) { spoteffects(TRUE); sokoban_guilt(); } } } STATIC_OVL void litter() { struct obj *otmp = invent, *nextobj; int capacity = weight_cap(); while (otmp) { nextobj = otmp->nobj; if ((otmp != uball) && (rnd(capacity) <= (int) otmp->owt)) { if (canletgo(otmp, "")) { pline("%s you down the stairs.", Yobjnam2(otmp, "follow")); dropx(otmp); } } otmp = nextobj; } } void drag_down() { boolean forward; uchar dragchance = 3; /* * Assume that the ball falls forward if: * * a) the character is wielding it, or * b) the character has both hands available to hold it (i.e. is * not wielding any weapon), or * c) (perhaps) it falls forward out of his non-weapon hand */ forward = carried(uball) && (uwep == uball || !uwep || !rn2(3)); if (carried(uball)) You("lose your grip on the iron ball."); if (forward) { if (rn2(6)) { pline_The("iron ball drags you downstairs!"); losehp(Maybe_Half_Phys(rnd(6)), "dragged downstairs by an iron ball", NO_KILLER_PREFIX); litter(); } } else { if (rn2(2)) { pline_The("iron ball smacks into you!"); losehp(Maybe_Half_Phys(rnd(20)), "iron ball collision", KILLED_BY_AN); exercise(A_STR, FALSE); dragchance -= 2; } if ((int) dragchance >= rnd(6)) { pline_The("iron ball drags you downstairs!"); losehp(Maybe_Half_Phys(rnd(3)), "dragged downstairs by an iron ball", NO_KILLER_PREFIX); exercise(A_STR, FALSE); litter(); } } } /*ball.c*/ nethack-3.6.0/src/bones.c0000664000076400007660000005500212631241231014173 0ustar paxedpaxed/* NetHack 3.6 bones.c $NHDT-Date: 1449269914 2015/12/04 22:58:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.66 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" extern char bones[]; /* from files.c */ #ifdef MFLOPPY extern long bytes_counted; #endif STATIC_DCL boolean FDECL(no_bones_level, (d_level *)); STATIC_DCL void FDECL(goodfruit, (int)); STATIC_DCL void FDECL(resetobjs, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(fixuporacle, (struct monst *)); STATIC_OVL boolean no_bones_level(lev) d_level *lev; { extern d_level save_dlevel; /* in do.c */ s_level *sptr; if (ledger_no(&save_dlevel)) assign_level(lev, &save_dlevel); return (boolean) (((sptr = Is_special(lev)) != 0 && !sptr->boneid) || !dungeons[lev->dnum].boneid /* no bones on the last or multiway branch levels in any dungeon (level 1 isn't multiway) */ || Is_botlevel(lev) || (Is_branchlev(lev) && lev->dlevel > 1) /* no bones in the invocation level */ || (In_hell(lev) && lev->dlevel == dunlevs_in_dungeon(lev) - 1)); } /* Call this function for each fruit object saved in the bones level: it marks * that particular type of fruit as existing (the marker is that that type's * ID is positive instead of negative). This way, when we later save the * chain of fruit types, we know to only save the types that exist. */ STATIC_OVL void goodfruit(id) int id; { register struct fruit *f; for (f = ffruit; f; f = f->nextf) { if (f->fid == -id) { f->fid = id; return; } } } STATIC_OVL void resetobjs(ochain, restore) struct obj *ochain; boolean restore; { struct obj *otmp, *nobj; for (otmp = ochain; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->cobj) resetobjs(otmp->cobj, restore); if (otmp->in_use) { obj_extract_self(otmp); dealloc_obj(otmp); continue; } if (restore) { /* artifact bookkeeping needs to be done during restore; other fixups are done while saving */ if (otmp->oartifact) { if (exist_artifact(otmp->otyp, safe_oname(otmp)) || is_quest_artifact(otmp)) { /* prevent duplicate--revert to ordinary obj */ otmp->oartifact = 0; if (has_oname(otmp)) free_oname(otmp); } else { artifact_exists(otmp, safe_oname(otmp), TRUE); } } else if (has_oname(otmp)) { sanitize_name(ONAME(otmp)); } } else { /* saving */ /* do not zero out o_ids for ghost levels anymore */ if (objects[otmp->otyp].oc_uses_known) otmp->known = 0; otmp->dknown = otmp->bknown = 0; otmp->rknown = 0; otmp->lknown = 0; otmp->cknown = 0; otmp->invlet = 0; otmp->no_charge = 0; otmp->was_thrown = 0; /* strip user-supplied names */ /* Statue and some corpse names are left intact, presumably in case they came from score file. [TODO: this ought to be done differently--names which came from such a source or came from any stoned or killed monster should be flagged in some manner; then we could just check the flag here and keep "real" names (dead pets, &c) while discarding player notes attached to statues.] */ if (has_oname(otmp) && !(otmp->oartifact || otmp->otyp == STATUE || otmp->otyp == SPE_NOVEL || (otmp->otyp == CORPSE && otmp->corpsenm >= SPECIAL_PM))) { free_oname(otmp); } if (otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe); #ifdef MAIL else if (otmp->otyp == SCR_MAIL) otmp->spe = 1; #endif else if (otmp->otyp == EGG) otmp->spe = 0; else if (otmp->otyp == TIN) { /* make tins of unique monster's meat be empty */ if (otmp->corpsenm >= LOW_PM && unique_corpstat(&mons[otmp->corpsenm])) otmp->corpsenm = NON_PM; } else if (otmp->otyp == CORPSE || otmp->otyp == STATUE) { int mnum = otmp->corpsenm; /* Discard incarnation details of unique monsters (by passing null instead of otmp for object), shopkeepers (by passing false for revival flag), temple priests, and vault guards in order to prevent corpse revival or statue reanimation. */ if (has_omonst(otmp) && cant_revive(&mnum, FALSE, (struct obj *) 0)) { free_omonst(otmp); /* mnum is now either human_zombie or doppelganger; for corpses of uniques, we need to force the transformation now rather than wait until a revival attempt, otherwise eating this corpse would behave as if it remains unique */ if (mnum == PM_DOPPELGANGER && otmp->otyp == CORPSE) set_corpsenm(otmp, mnum); } } else if (otmp->otyp == AMULET_OF_YENDOR) { /* no longer the real Amulet */ otmp->otyp = FAKE_AMULET_OF_YENDOR; curse(otmp); } else if (otmp->otyp == CANDELABRUM_OF_INVOCATION) { if (otmp->lamplit) end_burn(otmp, TRUE); otmp->otyp = WAX_CANDLE; otmp->age = 50L; /* assume used */ if (otmp->spe > 0) otmp->quan = (long) otmp->spe; otmp->spe = 0; otmp->owt = weight(otmp); curse(otmp); } else if (otmp->otyp == BELL_OF_OPENING) { otmp->otyp = BELL; curse(otmp); } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) { otmp->otyp = SPE_BLANK_PAPER; curse(otmp); } } } } /* while loading bones, strip out text possibly supplied by old player that might accidentally or maliciously disrupt new player's display */ void sanitize_name(namebuf) char *namebuf; { int c; boolean strip_8th_bit = !strcmp(windowprocs.name, "tty") && !iflags.wc_eight_bit_input; /* it's tempting to skip this for single-user platforms, since only the current player could have left these bones--except things like "hearse" and other bones exchange schemes make that assumption false */ while (*namebuf) { c = *namebuf & 0177; if (c < ' ' || c == '\177') { /* non-printable or undesirable */ *namebuf = '.'; } else if (c != *namebuf) { /* expected to be printable if user wants such things */ if (strip_8th_bit) *namebuf = '_'; } ++namebuf; } } /* called by savebones(); also by finish_paybill(shk.c) */ void drop_upon_death(mtmp, cont, x, y) struct monst *mtmp; struct obj *cont; int x, y; { struct obj *otmp; u.twoweap = 0; /* ensure curse() won't cause swapwep to drop twice */ while ((otmp = invent) != 0) { obj_extract_self(otmp); obj_no_longer_held(otmp); otmp->owornmask = 0; /* lamps don't go out when dropped */ if ((cont || artifact_light(otmp)) && obj_is_burning(otmp)) end_burn(otmp, TRUE); /* smother in statue */ if (otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe); if (rn2(5)) curse(otmp); if (mtmp) (void) add_to_minv(mtmp, otmp); else if (cont) (void) add_to_container(cont, otmp); else place_object(otmp, x, y); } if (cont) cont->owt = weight(cont); } /* possibly restore oracle's room and/or put her back inside it; returns False if she's on the wrong level and should be removed, True otherwise */ STATIC_OVL boolean fixuporacle(oracle) struct monst *oracle; { coord cc; int ridx, o_ridx; /* oracle doesn't move, but knight's joust or monk's staggering blow could push her onto a hole in the floor; at present, traps don't activate in such situation hence she won't fall to another level; however, that could change so be prepared to cope with such things */ if (!Is_oracle_level(&u.uz)) return FALSE; oracle->mpeaceful = 1; o_ridx = levl[oracle->mx][oracle->my].roomno - ROOMOFFSET; if (o_ridx >= 0 && rooms[o_ridx].rtype == DELPHI) return TRUE; /* no fixup needed */ /* * The Oracle isn't in DELPHI room. Either hero entered her chamber * and got the one-time welcome message, converting it into an * ordinary room, or she got teleported out, or both. Try to put * her back inside her room, if necessary, and restore its type. */ /* find original delphi chamber; should always succeed */ for (ridx = 0; ridx < SIZE(rooms); ++ridx) if (rooms[ridx].orig_rtype == DELPHI) break; if (o_ridx != ridx && ridx < SIZE(rooms)) { /* room found and she's not not in it, so try to move her there */ cc.x = (rooms[ridx].lx + rooms[ridx].hx) / 2; cc.y = (rooms[ridx].ly + rooms[ridx].hy) / 2; if (enexto(&cc, cc.x, cc.y, oracle->data)) { rloc_to(oracle, cc.x, cc.y); o_ridx = levl[oracle->mx][oracle->my].roomno - ROOMOFFSET; } /* [if her room is already full, she might end up outside; that's ok, next hero just won't get any welcome message, same as used to happen before this fixup was introduced] */ } if (ridx == o_ridx) /* if she's in her room, mark it as such */ rooms[ridx].rtype = DELPHI; return TRUE; /* keep oracle in new bones file */ } /* check whether bones are feasible */ boolean can_make_bones() { register struct trap *ttmp; if (!flags.bones) return FALSE; if (ledger_no(&u.uz) <= 0 || ledger_no(&u.uz) > maxledgerno()) return FALSE; if (no_bones_level(&u.uz)) return FALSE; /* no bones for specific levels */ if (u.uswallow) { return FALSE; /* no bones when swallowed */ } if (!Is_branchlev(&u.uz)) { /* no bones on non-branches with portals */ for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) if (ttmp->ttyp == MAGIC_PORTAL) return FALSE; } if (depth(&u.uz) <= 0 /* bulletproofing for endgame */ || (!rn2(1 + (depth(&u.uz) >> 2)) /* fewer ghosts on low levels */ && !wizard)) return FALSE; /* don't let multiple restarts generate multiple copies of objects in bones files */ if (discover) return FALSE; return TRUE; } /* save bones and possessions of a deceased adventurer */ void savebones(how, when, corpse) int how; time_t when; struct obj *corpse; { int fd, x, y; struct trap *ttmp; struct monst *mtmp; struct permonst *mptr; struct fruit *f; struct cemetery *newbones; char c, *bonesid; char whynot[BUFSZ]; /* caller has already checked `can_make_bones()' */ clear_bypasses(); fd = open_bonesfile(&u.uz, &bonesid); if (fd >= 0) { (void) nhclose(fd); if (wizard) { if (yn("Bones file already exists. Replace it?") == 'y') { if (delete_bonesfile(&u.uz)) goto make_bones; else pline("Cannot unlink old bones."); } } /* compression can change the file's name, so must wait until after any attempt to delete this file */ compress_bonesfile(); return; } make_bones: unleash_all(); /* in case these characters are not in their home bases */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mptr = mtmp->data; if (mtmp->iswiz || mptr == &mons[PM_MEDUSA] || mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER || mptr == &mons[PM_VLAD_THE_IMPALER] || (mptr == &mons[PM_ORACLE] && !fixuporacle(mtmp))) mongone(mtmp); } if (u.usteed) dismount_steed(DISMOUNT_BONES); dmonsfree(); /* discard dead or gone monsters */ /* mark all fruits as nonexistent; when we come to them we'll mark * them as existing (using goodfruit()) */ for (f = ffruit; f; f = f->nextf) f->fid = -f->fid; /* check iron balls separately--maybe they're not carrying it */ if (uball) uball->owornmask = uchain->owornmask = 0; /* dispose of your possessions, usually cursed */ if (u.ugrave_arise == (NON_PM - 1)) { struct obj *otmp; /* embed your possessions in your statue */ otmp = mk_named_object(STATUE, &mons[u.umonnum], u.ux, u.uy, plname); drop_upon_death((struct monst *) 0, otmp, u.ux, u.uy); if (!otmp) return; /* couldn't make statue */ mtmp = (struct monst *) 0; } else if (u.ugrave_arise < LOW_PM) { /* drop everything */ drop_upon_death((struct monst *) 0, (struct obj *) 0, u.ux, u.uy); /* trick makemon() into allowing monster creation * on your location */ in_mklev = TRUE; mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, MM_NONAME); in_mklev = FALSE; if (!mtmp) return; mtmp = christen_monst(mtmp, plname); if (corpse) (void) obj_attach_mid(corpse, mtmp->m_id); } else { /* give your possessions to the monster you become */ in_mklev = TRUE; /* use as-is */ mtmp = makemon(&mons[u.ugrave_arise], u.ux, u.uy, NO_MINVENT); in_mklev = FALSE; if (!mtmp) { drop_upon_death((struct monst *) 0, (struct obj *) 0, u.ux, u.uy); u.ugrave_arise = NON_PM; /* in case caller cares */ return; } /* give mummy-from-hero a wrapping unless hero already carries one; don't bother forcing it to become worn */ if (mtmp->data->mlet == S_MUMMY && !carrying(MUMMY_WRAPPING)) (void) mongets(mtmp, MUMMY_WRAPPING); mtmp = christen_monst(mtmp, plname); newsym(u.ux, u.uy); /* ["Your body rises from the dead as an ..." used to be given here, but it has been moved to done() so that it gets delivered even when savebones() isn't called] */ drop_upon_death(mtmp, (struct obj *) 0, u.ux, u.uy); m_dowear(mtmp, TRUE); } if (mtmp) { mtmp->m_lev = (u.ulevel ? u.ulevel : 1); mtmp->mhp = mtmp->mhpmax = u.uhpmax; mtmp->female = flags.female; mtmp->msleeping = 1; } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { resetobjs(mtmp->minvent, FALSE); /* do not zero out m_ids for bones levels any more */ mtmp->mlstmv = 0L; if (mtmp->mtame) mtmp->mtame = mtmp->mpeaceful = 0; } for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { ttmp->madeby_u = 0; ttmp->tseen = (ttmp->ttyp == HOLE); } resetobjs(fobj, FALSE); resetobjs(level.buriedobjlist, FALSE); /* Hero is no longer on the map. */ u.ux = u.uy = 0; /* Clear all memory from the level. */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { levl[x][y].seenv = 0; levl[x][y].waslit = 0; levl[x][y].glyph = cmap_to_glyph(S_stone); lastseentyp[x][y] = 0; } /* Attach bones info to the current level before saving. */ newbones = (struct cemetery *) alloc(sizeof *newbones); /* entries are '\0' terminated but have fixed length allocations, so pre-fill with spaces to initialize any excess room */ (void) memset((genericptr_t) newbones, ' ', sizeof *newbones); /* format name+role,&c, death reason, and date+time; gender and alignment reflect final values rather than what the character started out as, same as topten and logfile entries */ Sprintf(newbones->who, "%s-%.3s-%.3s-%.3s-%.3s", plname, urole.filecode, urace.filecode, genders[flags.female].filecode, aligns[1 - u.ualign.type].filecode); formatkiller(newbones->how, sizeof newbones->how, how); Strcpy(newbones->when, yyyymmddhhmmss(when)); /* final resting place, used to decide when bones are discovered */ newbones->frpx = u.ux, newbones->frpy = u.uy; newbones->bonesknown = FALSE; /* if current character died on a bones level, the cemetery list will have multiple entries, most recent (this dead hero) first */ newbones->next = level.bonesinfo; level.bonesinfo = newbones; /* flag these bones if they are being created in wizard mode; they might already be flagged as such, even when we're playing in normal mode, if this level came from a previous bones file */ if (wizard) level.flags.wizard_bones = 1; fd = create_bonesfile(&u.uz, &bonesid, whynot); if (fd < 0) { if (wizard) pline1(whynot); /* bones file creation problems are silent to the player. * Keep it that way, but place a clue into the paniclog. */ paniclog("savebones", whynot); return; } c = (char) (strlen(bonesid) + 1); #ifdef MFLOPPY /* check whether there is room */ if (iflags.checkspace) { savelev(fd, ledger_no(&u.uz), COUNT_SAVE); /* savelev() initializes bytes_counted to 0, so it must come * first here even though it does not in the real save. the * resulting extra bflush() at the end of savelev() may increase * bytes_counted by a couple over what the real usage will be. * * note it is safe to call store_version() here only because * bufon() is null for ZEROCOMP, which MFLOPPY uses -- otherwise * this code would have to know the size of the version * information itself. */ store_version(fd); store_savefileinfo(fd); bwrite(fd, (genericptr_t) &c, sizeof c); bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */ savefruitchn(fd, COUNT_SAVE); bflush(fd); if (bytes_counted > freediskspace(bones)) { /* not enough room */ if (wizard) pline("Insufficient space to create bones file."); (void) nhclose(fd); cancel_bonesfile(); return; } co_false(); /* make sure stuff before savelev() gets written */ } #endif /* MFLOPPY */ store_version(fd); store_savefileinfo(fd); bwrite(fd, (genericptr_t) &c, sizeof c); bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */ savefruitchn(fd, WRITE_SAVE | FREE_SAVE); update_mlstmv(); /* update monsters for eventual restoration */ savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); bclose(fd); commit_bonesfile(&u.uz); compress_bonesfile(); } int getbones() { register int fd; register int ok; char c, *bonesid, oldbonesid[10]; if (discover) /* save bones files for real games */ return 0; if (!flags.bones) return 0; /* wizard check added by GAN 02/05/87 */ if (rn2(3) /* only once in three times do we find bones */ && !wizard) return 0; if (no_bones_level(&u.uz)) return 0; fd = open_bonesfile(&u.uz, &bonesid); if (fd < 0) return 0; if (validate(fd, bones) != 0) { if (!wizard) pline("Discarding unuseable bones; no need to panic..."); ok = FALSE; } else { ok = TRUE; if (wizard) { if (yn("Get bones?") == 'n') { (void) nhclose(fd); compress_bonesfile(); return 0; } } mread(fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */ mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */ if (strcmp(bonesid, oldbonesid) != 0) { char errbuf[BUFSZ]; Sprintf(errbuf, "This is bones level '%s', not '%s'!", oldbonesid, bonesid); if (wizard) { pline1(errbuf); ok = FALSE; /* won't die of trickery */ } trickery(errbuf); } else { register struct monst *mtmp; getlev(fd, 0, 0, TRUE); /* Note that getlev() now keeps tabs on unique * monsters such as demon lords, and tracks the * birth counts of all species just as makemon() * does. If a bones monster is extinct or has been * subject to genocide, their mhpmax will be * set to the magic DEFUNCT_MONSTER cookie value. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (has_mname(mtmp)) sanitize_name(MNAME(mtmp)); if (mtmp->mhpmax == DEFUNCT_MONSTER) { if (wizard) { debugpline1("Removing defunct monster %s from bones.", mtmp->data->mname); } mongone(mtmp); } else /* to correctly reset named artifacts on the level */ resetobjs(mtmp->minvent, TRUE); } resetobjs(fobj, TRUE); resetobjs(level.buriedobjlist, TRUE); } } (void) nhclose(fd); sanitize_engravings(); u.uroleplay.numbones++; if (wizard) { if (yn("Unlink bones?") == 'n') { compress_bonesfile(); return ok; } } if (!delete_bonesfile(&u.uz)) { /* When N games try to simultaneously restore the same * bones file, N-1 of them will fail to delete it * (the first N-1 under AmigaDOS, the last N-1 under UNIX). * So no point in a mysterious message for a normal event * -- just generate a new level for those N-1 games. */ /* pline("Cannot unlink bones."); */ return 0; } return ok; } /*bones.c*/ nethack-3.6.0/src/botl.c0000664000076400007660000014010512623532454014037 0ustar paxedpaxed/* NetHack 3.6 botl.c $NHDT-Date: 1447978683 2015/11/20 00:18:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.69 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include extern const char *hu_stat[]; /* defined in eat.c */ const char *const enc_stat[] = { "", "Burdened", "Stressed", "Strained", "Overtaxed", "Overloaded" }; STATIC_OVL NEARDATA int mrank_sz = 0; /* loaded by max_rank_sz (from u_init) */ STATIC_DCL const char *NDECL(rank); #ifndef STATUS_VIA_WINDOWPORT STATIC_DCL void NDECL(bot1); STATIC_DCL void NDECL(bot2); STATIC_OVL void bot1() { char newbot1[MAXCO]; register char *nb; register int i, j; Strcpy(newbot1, plname); if ('a' <= newbot1[0] && newbot1[0] <= 'z') newbot1[0] += 'A' - 'a'; newbot1[10] = 0; Sprintf(nb = eos(newbot1), " the "); if (Upolyd) { char mbot[BUFSZ]; int k = 0; Strcpy(mbot, mons[u.umonnum].mname); while (mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') mbot[k] += 'A' - 'a'; k++; } Strcpy(nb = eos(nb), mbot); } else Strcpy(nb = eos(nb), rank()); Sprintf(nb = eos(nb), " "); i = mrank_sz + 15; j = (int) ((nb + 2) - newbot1); /* strlen(newbot1) but less computation */ if ((i - j) > 0) Sprintf(nb = eos(nb), "%*s", i - j, " "); /* pad with spaces */ if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) Sprintf(nb = eos(nb), "St:%2d ", ACURR(A_STR) - 100); else if (ACURR(A_STR) < STR18(100)) Sprintf(nb = eos(nb), "St:18/%02d ", ACURR(A_STR) - 18); else Sprintf(nb = eos(nb), "St:18/** "); } else Sprintf(nb = eos(nb), "St:%-1d ", ACURR(A_STR)); Sprintf(nb = eos(nb), "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d", ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA)); Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? " Chaotic" : (u.ualign.type == A_NEUTRAL) ? " Neutral" : " Lawful"); #ifdef SCORE_ON_BOTL if (flags.showscore) Sprintf(nb = eos(nb), " S:%ld", botl_score()); #endif curs(WIN_STATUS, 1, 0); putstr(WIN_STATUS, 0, newbot1); } STATIC_OVL void bot2() { char newbot2[MAXCO]; register char *nb; int hp, hpmax; int cap = near_capacity(); hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; if (hp < 0) hp = 0; (void) describe_level(newbot2); Sprintf(nb = eos(newbot2), "%s:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", encglyph(objnum_to_glyph(GOLD_PIECE)), money_cnt(invent), hp, hpmax, u.uen, u.uenmax, u.uac); if (Upolyd) Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel); else if (flags.showexp) Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel, u.uexp); else Sprintf(nb = eos(nb), " Exp:%u", u.ulevel); if (flags.time) Sprintf(nb = eos(nb), " T:%ld", moves); if (strcmp(hu_stat[u.uhs], " ")) { Sprintf(nb = eos(nb), " "); Strcat(newbot2, hu_stat[u.uhs]); } if (Confusion) Sprintf(nb = eos(nb), " Conf"); if (Sick) { if (u.usick_type & SICK_VOMITABLE) Sprintf(nb = eos(nb), " FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) Sprintf(nb = eos(nb), " Ill"); } if (Blind) Sprintf(nb = eos(nb), " Blind"); if (Stunned) Sprintf(nb = eos(nb), " Stun"); if (Hallucination) Sprintf(nb = eos(nb), " Hallu"); if (Slimed) Sprintf(nb = eos(nb), " Slime"); if (cap > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); curs(WIN_STATUS, 1, 1); putmixed(WIN_STATUS, 0, newbot2); } void bot() { if (youmonst.data) { bot1(); bot2(); } context.botl = context.botlx = 0; } #endif /* !STATUS_VIA_WINDOWPORT */ /* convert experience level (1..30) to rank index (0..8) */ int xlev_to_rank(xlev) int xlev; { return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8; } #if 0 /* not currently needed */ /* convert rank index (0..8) to experience level (1..30) */ int rank_to_xlev(rank) int rank; { return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30; } #endif const char * rank_of(lev, monnum, female) int lev; short monnum; boolean female; { register const struct Role *role; register int i; /* Find the role */ for (role = roles; role->name.m; role++) if (monnum == role->malenum || monnum == role->femalenum) break; if (!role->name.m) role = &urole; /* Find the rank */ for (i = xlev_to_rank((int) lev); i >= 0; i--) { if (female && role->rank[i].f) return role->rank[i].f; if (role->rank[i].m) return role->rank[i].m; } /* Try the role name, instead */ if (female && role->name.f) return role->name.f; else if (role->name.m) return role->name.m; return "Player"; } STATIC_OVL const char * rank() { return rank_of(u.ulevel, Role_switch, flags.female); } int title_to_mon(str, rank_indx, title_length) const char *str; int *rank_indx, *title_length; { register int i, j; /* Loop through each of the roles */ for (i = 0; roles[i].name.m; i++) for (j = 0; j < 9; j++) { if (roles[i].rank[j].m && !strncmpi(str, roles[i].rank[j].m, strlen(roles[i].rank[j].m))) { if (rank_indx) *rank_indx = j; if (title_length) *title_length = strlen(roles[i].rank[j].m); return roles[i].malenum; } if (roles[i].rank[j].f && !strncmpi(str, roles[i].rank[j].f, strlen(roles[i].rank[j].f))) { if (rank_indx) *rank_indx = j; if (title_length) *title_length = strlen(roles[i].rank[j].f); return (roles[i].femalenum != NON_PM) ? roles[i].femalenum : roles[i].malenum; } } return NON_PM; } void max_rank_sz() { register int i, r, maxr = 0; for (i = 0; i < 9; i++) { if (urole.rank[i].m && (r = strlen(urole.rank[i].m)) > maxr) maxr = r; if (urole.rank[i].f && (r = strlen(urole.rank[i].f)) > maxr) maxr = r; } mrank_sz = maxr; return; } #ifdef SCORE_ON_BOTL long botl_score() { long deepest = deepest_lev_reached(FALSE); long utotal; utotal = money_cnt(invent) + hidden_gold(); if ((utotal -= u.umoney0) < 0L) utotal = 0L; utotal += u.urexp + (50 * (deepest - 1)) + (deepest > 30 ? 10000 : deepest > 20 ? 1000 * (deepest - 20) : 0); if (utotal < u.urexp) utotal = LONG_MAX; /* wrap around */ return utotal; } #endif /* SCORE_ON_BOTL */ /* provide the name of the current level for display by various ports */ int describe_level(buf) char *buf; { int ret = 1; /* TODO: Add in dungeon name */ if (Is_knox(&u.uz)) Sprintf(buf, "%s ", dungeons[u.uz.dnum].dname); else if (In_quest(&u.uz)) Sprintf(buf, "Home %d ", dunlev(&u.uz)); else if (In_endgame(&u.uz)) Sprintf(buf, Is_astralevel(&u.uz) ? "Astral Plane " : "End Game "); else { /* ports with more room may expand this one */ Sprintf(buf, "Dlvl:%-2d ", depth(&u.uz)); ret = 0; } return ret; } #ifdef STATUS_VIA_WINDOWPORT /* =======================================================================*/ /* structure that tracks the status details in the core */ struct istat_s { long time; unsigned anytype; anything a; char *val; int valwidth; enum statusfields idxmax; enum statusfields fld; }; STATIC_DCL void NDECL(init_blstats); STATIC_DCL char *FDECL(anything_to_s, (char *, anything *, int)); STATIC_DCL void FDECL(s_to_anything, (anything *, char *, int)); STATIC_OVL int FDECL(percentage, (struct istat_s *, struct istat_s *)); STATIC_OVL int FDECL(compare_blstats, (struct istat_s *, struct istat_s *)); #ifdef STATUS_HILITES STATIC_DCL boolean FDECL(assign_hilite, (char *, char *, char *, char *, BOOLEAN_P)); STATIC_DCL const char *FDECL(clridx_to_s, (char *, int)); #endif /* If entries are added to this, botl.h will require updating too */ STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = { { 0L, ANY_STR, { (genericptr_t) 0 }, (char *) 0, 80, 0, BL_TITLE}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_STR}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_DX}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_CO}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_IN}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_WI}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_CH}, { 0L, ANY_STR, { (genericptr_t) 0 }, (char *) 0, 40, 0, BL_ALIGN}, { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_SCORE}, { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_CAP}, { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 30, 0, BL_GOLD}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, BL_ENEMAX, BL_ENE}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_ENEMAX}, { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_XP}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_AC}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_HD}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_TIME}, { 0L, ANY_UINT, { (genericptr_t) 0 }, (char *) 0, 40, 0, BL_HUNGER}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, BL_HPMAX, BL_HP}, { 0L, ANY_INT, { (genericptr_t) 0 }, (char *) 0, 10, 0, BL_HPMAX}, { 0L, ANY_STR, { (genericptr_t) 0 }, (char *) 0, 80, 0, BL_LEVELDESC}, { 0L, ANY_LONG, { (genericptr_t) 0 }, (char *) 0, 20, 0, BL_EXP}, { 0L, ANY_MASK32, { (genericptr_t) 0 }, (char *) 0, 0, 0, BL_CONDITION} }; static struct fieldid_t { const char *fieldname; enum statusfields fldid; } fieldids[] = { {"title", BL_TITLE}, {"strength", BL_STR}, {"dexterity", BL_DX}, {"constitution", BL_CO}, {"intelligence", BL_IN}, {"wisdom", BL_WI}, {"charisma", BL_CH}, {"alignment", BL_ALIGN}, {"score", BL_SCORE}, {"carrying-capacity", BL_CAP}, {"gold", BL_GOLD}, {"power", BL_ENE}, {"power-max", BL_ENEMAX}, {"experience-level", BL_XP}, {"armor-class", BL_AC}, {"HD", BL_HD}, {"time", BL_TIME}, {"hunger", BL_HUNGER}, {"hitpoints", BL_HP}, {"hitpoints-max", BL_HPMAX}, {"dungeon-level", BL_LEVELDESC}, {"experience", BL_EXP}, {"condition", BL_CONDITION}, }; struct istat_s blstats[2][MAXBLSTATS]; static boolean blinit = FALSE, update_all = FALSE; void bot() { char buf[BUFSZ]; register char *nb; static int idx = 0, idx_p, idxmax; boolean updated = FALSE; unsigned anytype; int i, pc, chg, cap; struct istat_s *curr, *prev; boolean valset[MAXBLSTATS], chgval = FALSE; if (!blinit) panic("bot before init."); if (!youmonst.data) { context.botl = context.botlx = 0; update_all = FALSE; return; } cap = near_capacity(); idx_p = idx; idx = 1 - idx; /* 0 -> 1, 1 -> 0 */ /* clear the "value set" indicators */ (void) memset((genericptr_t) valset, 0, MAXBLSTATS * sizeof(boolean)); /* * Player name and title. */ buf[0] = '\0'; Strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A' - 'a'; buf[10] = 0; Sprintf(nb = eos(buf), " the "); if (Upolyd) { char mbot[BUFSZ]; int k = 0; Strcpy(mbot, mons[u.umonnum].mname); while (mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') mbot[k] += 'A' - 'a'; k++; } Sprintf1(nb = eos(nb), mbot); } else Sprintf1(nb = eos(nb), rank()); Sprintf(blstats[idx][BL_TITLE].val, "%-29s", buf); valset[BL_TITLE] = TRUE; /* indicate val already set */ /* Strength */ buf[0] = '\0'; blstats[idx][BL_STR].a.a_int = ACURR(A_STR); if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) Sprintf(buf, "%2d", ACURR(A_STR) - 100); else if (ACURR(A_STR) < STR18(100)) Sprintf(buf, "18/%02d", ACURR(A_STR) - 18); else Sprintf(buf, "18/**"); } else Sprintf(buf, "%-1d", ACURR(A_STR)); Strcpy(blstats[idx][BL_STR].val, buf); valset[BL_STR] = TRUE; /* indicate val already set */ /* Dexterity, constitution, intelligence, wisdom, charisma. */ blstats[idx][BL_DX].a.a_int = ACURR(A_DEX); blstats[idx][BL_CO].a.a_int = ACURR(A_CON); blstats[idx][BL_IN].a.a_int = ACURR(A_INT); blstats[idx][BL_WI].a.a_int = ACURR(A_WIS); blstats[idx][BL_CH].a.a_int = ACURR(A_CHA); /* Alignment */ Strcpy(blstats[idx][BL_ALIGN].val, (u.ualign.type == A_CHAOTIC) ? "Chaotic" : (u.ualign.type == A_NEUTRAL) ? "Neutral" : "Lawful"); /* Score */ blstats[idx][BL_SCORE].a.a_long = #ifdef SCORE_ON_BOTL botl_score(); #else 0; #endif /* Hit points */ blstats[idx][BL_HP].a.a_int = Upolyd ? u.mh : u.uhp; blstats[idx][BL_HPMAX].a.a_int = Upolyd ? u.mhmax : u.uhpmax; if (blstats[idx][BL_HP].a.a_int < 0) blstats[idx][BL_HP].a.a_int = 0; /* Dungeon level. */ (void) describe_level(blstats[idx][BL_LEVELDESC].val); valset[BL_LEVELDESC] = TRUE; /* indicate val already set */ /* Gold */ blstats[idx][BL_GOLD].a.a_long = money_cnt(invent); /* * The tty port needs to display the current symbol for gold * as a field header, so to accommodate that we pass gold with * that already included. If a window port needs to use the text * gold amount without the leading "$:" the port will have to * add 2 to the value pointer it was passed in status_update() * for the BL_GOLD case. * * Another quirk of BL_GOLD is that the field display may have * changed if a new symbol set was loaded, or we entered or left * the rogue level. */ Sprintf(blstats[idx][BL_GOLD].val, "%s:%ld", encglyph(objnum_to_glyph(GOLD_PIECE)), blstats[idx][BL_GOLD].a.a_long); valset[BL_GOLD] = TRUE; /* indicate val already set */ /* Power (magical energy) */ blstats[idx][BL_ENE].a.a_int = u.uen; blstats[idx][BL_ENEMAX].a.a_int = u.uenmax; /* Armor class */ blstats[idx][BL_AC].a.a_int = u.uac; /* Monster level (if Upolyd) */ if (Upolyd) blstats[idx][BL_HD].a.a_int = mons[u.umonnum].mlevel; else blstats[idx][BL_HD].a.a_int = 0; /* Experience */ blstats[idx][BL_XP].a.a_int = u.ulevel; blstats[idx][BL_EXP].a.a_int = u.uexp; /* Time (moves) */ blstats[idx][BL_TIME].a.a_long = moves; /* Hunger */ blstats[idx][BL_HUNGER].a.a_uint = u.uhs; *(blstats[idx][BL_HUNGER].val) = '\0'; if (strcmp(hu_stat[u.uhs], " ") != 0) Strcpy(blstats[idx][BL_HUNGER].val, hu_stat[u.uhs]); valset[BL_HUNGER] = TRUE; /* Carrying capacity */ *(blstats[idx][BL_CAP].val) = '\0'; blstats[idx][BL_CAP].a.a_int = cap; if (cap > UNENCUMBERED) Strcpy(blstats[idx][BL_CAP].val, enc_stat[cap]); valset[BL_CAP] = TRUE; /* Conditions */ if (Blind) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_BLIND; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_BLIND; if (Confusion) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_CONF; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_CONF; if (Sick && u.usick_type & SICK_VOMITABLE) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_FOODPOIS; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_FOODPOIS; if (Sick && u.usick_type & SICK_NONVOMITABLE) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_ILL; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_ILL; if (Hallucination) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_HALLU; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_HALLU; if (Stunned) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STUNNED; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_STUNNED; if (Slimed) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_SLIMED; else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_SLIMED; /* * Now pass the changed values to window port. */ for (i = 0; i < MAXBLSTATS; i++) { if (((i == BL_SCORE) && !flags.showscore) || ((i == BL_EXP) && !flags.showexp) || ((i == BL_TIME) && !flags.time) || ((i == BL_HD) && !Upolyd) || ((i == BL_XP || i == BL_EXP) && Upolyd)) continue; anytype = blstats[idx][i].anytype; curr = &blstats[idx][i]; prev = &blstats[idx_p][i]; chg = 0; if (update_all || ((chg = compare_blstats(prev, curr)) != 0) || ((chgval = (valset[i] && strcmp(blstats[idx][i].val, blstats[idx_p][i].val))) != 0)) { idxmax = blstats[idx][i].idxmax; pc = (idxmax) ? percentage(curr, &blstats[idx][idxmax]) : 0; if (!valset[i]) (void) anything_to_s(curr->val, &curr->a, anytype); if (anytype != ANY_MASK32) { status_update(i, (genericptr_t) curr->val, valset[i] ? chgval : chg, pc); } else { status_update(i, /* send pointer to mask */ (genericptr_t) &curr->a.a_ulong, chg, 0); } updated = TRUE; } } /* * It is possible to get here, with nothing having been pushed * to the window port, when none of the info has changed. In that * case, we need to force a call to status_update() when * context.botlx is set. The tty port in particular has a problem * if that isn't done, since it sets context.botlx when a menu or * text display obliterates the status line. * * To work around it, we call status_update() with fictitious * index of BL_FLUSH (-1). */ if (context.botlx && !updated) status_update(BL_FLUSH, (genericptr_t) 0, 0, 0); context.botl = context.botlx = 0; update_all = FALSE; } void status_initialize(reassessment) boolean reassessment; /* TRUE = just reassess fields w/o other initialization*/ { int i; const char *fieldfmt = (const char *)0; const char *fieldname = (const char *)0; if (!reassessment) { init_blstats(); (*windowprocs.win_status_init)(); blinit = TRUE; #ifdef STATUS_HILITES status_notify_windowport(TRUE); #endif } for (i = 0; i < MAXBLSTATS; ++i) { enum statusfields fld = initblstats[i].fld; switch (fld) { case BL_TITLE: fieldfmt = "%s"; fieldname = "title"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_STR: fieldfmt = " St:%s"; fieldname = "strength"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_DX: fieldfmt = " Dx:%s"; fieldname = "dexterity"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_CO: fieldfmt = " Co:%s"; fieldname = "constitution"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_IN: fieldfmt = " In:%s"; fieldname = "intelligence"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_WI: fieldfmt = " Wi:%s"; fieldname = "wisdom"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_CH: fieldfmt = " Ch:%s"; fieldname = "charisma"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_ALIGN: fieldfmt = " %s"; fieldname = "alignment"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_SCORE: fieldfmt = " S:%s"; fieldname = "score"; status_enablefield(fld, fieldname, fieldfmt, (!flags.showscore) ? FALSE : TRUE); break; case BL_CAP: fieldfmt = " %s"; fieldname = "carrying-capacity"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_GOLD: fieldfmt = " %s"; fieldname = "gold"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_ENE: fieldfmt = " Pw:%s"; fieldname = "power"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_ENEMAX: fieldfmt = "(%s)"; fieldname = "power-max"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_XP: fieldfmt = " Xp:%s"; fieldname = "experience-level"; status_enablefield(fld, fieldname, fieldfmt, (Upolyd) ? FALSE : TRUE); break; case BL_AC: fieldfmt = " AC:%s"; fieldname = "armor-class"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_HD: fieldfmt = " HD:%s"; fieldname = "HD"; status_enablefield(fld, fieldname, fieldfmt, (!Upolyd) ? FALSE : TRUE); break; case BL_TIME: fieldfmt = " T:%s"; fieldname = "time"; status_enablefield(fld, fieldname, fieldfmt, (!flags.time) ? FALSE : TRUE); break; case BL_HUNGER: fieldfmt = " %s"; fieldname = "hunger"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_HP: fieldfmt = " HP:%s"; fieldname = "hitpoints"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_HPMAX: fieldfmt = "(%s)"; fieldname = "hitpoint-max"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_LEVELDESC: fieldfmt = "%s"; fieldname = "dungeon-level"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_EXP: fieldfmt = "/%s"; fieldname = "experience"; status_enablefield(fld, fieldname, fieldfmt, (!flags.showexp || Upolyd) ? FALSE : TRUE); break; case BL_CONDITION: fieldfmt = "%S"; fieldname = "condition"; status_enablefield(fld, fieldname, fieldfmt, TRUE); break; case BL_FLUSH: default: break; } } update_all = TRUE; } void status_finish() { int i; /* call the window port cleanup routine first */ (*windowprocs.win_status_finish)(); /* free memory that we alloc'd now */ for (i = 0; i < MAXBLSTATS; ++i) { if (blstats[0][i].val) free((genericptr_t) blstats[0][i].val); if (blstats[1][i].val) free((genericptr_t) blstats[1][i].val); } } STATIC_OVL void init_blstats() { static boolean initalready = FALSE; int i, j; if (initalready) { impossible("init_blstats called more than once."); return; } initalready = TRUE; for (i = BEFORE; i <= NOW; ++i) { for (j = 0; j < MAXBLSTATS; ++j) { blstats[i][j] = initblstats[j]; blstats[i][j].a = zeroany; if (blstats[i][j].valwidth) { blstats[i][j].val = (char *) alloc(blstats[i][j].valwidth); blstats[i][j].val[0] = '\0'; } else blstats[i][j].val = (char *) 0; } } } STATIC_OVL char * anything_to_s(buf, a, anytype) char *buf; anything *a; int anytype; { if (!buf) return (char *) 0; switch (anytype) { case ANY_ULONG: Sprintf(buf, "%lu", a->a_ulong); break; case ANY_MASK32: Sprintf(buf, "%lx", a->a_ulong); break; case ANY_LONG: Sprintf(buf, "%ld", a->a_long); break; case ANY_INT: Sprintf(buf, "%d", a->a_int); break; case ANY_UINT: Sprintf(buf, "%u", a->a_uint); break; case ANY_IPTR: Sprintf(buf, "%d", *a->a_iptr); break; case ANY_LPTR: Sprintf(buf, "%ld", *a->a_lptr); break; case ANY_ULPTR: Sprintf(buf, "%lu", *a->a_ulptr); break; case ANY_UPTR: Sprintf(buf, "%u", *a->a_uptr); break; case ANY_STR: /* do nothing */ ; break; default: buf[0] = '\0'; } return buf; } STATIC_OVL void s_to_anything(a, buf, anytype) anything *a; char *buf; int anytype; { if (!buf || !a) return; switch (anytype) { case ANY_LONG: a->a_long = atol(buf); break; case ANY_INT: a->a_int = atoi(buf); break; case ANY_UINT: a->a_uint = (unsigned) atoi(buf); break; case ANY_ULONG: a->a_ulong = (unsigned long) atol(buf); break; case ANY_IPTR: if (a->a_iptr) *a->a_iptr = atoi(buf); break; case ANY_UPTR: if (a->a_uptr) *a->a_uptr = (unsigned) atoi(buf); break; case ANY_LPTR: if (a->a_lptr) *a->a_lptr = atol(buf); break; case ANY_ULPTR: if (a->a_ulptr) *a->a_ulptr = (unsigned long) atol(buf); break; case ANY_MASK32: a->a_ulong = (unsigned long) atol(buf); break; default: a->a_void = 0; break; } return; } STATIC_OVL int compare_blstats(bl1, bl2) struct istat_s *bl1, *bl2; { int anytype, result = 0; if (!bl1 || !bl2) { panic("compare_blstat: bad istat pointer %s, %s", fmt_ptr((genericptr_t) bl1), fmt_ptr((genericptr_t) bl2)); } anytype = bl1->anytype; if ((!bl1->a.a_void || !bl2->a.a_void) && (anytype == ANY_IPTR || anytype == ANY_UPTR || anytype == ANY_LPTR || anytype == ANY_ULPTR)) { panic("compare_blstat: invalid pointer %s, %s", fmt_ptr((genericptr_t) bl1->a.a_void), fmt_ptr((genericptr_t) bl2->a.a_void)); } switch (anytype) { case ANY_INT: result = (bl1->a.a_int < bl2->a.a_int) ? 1 : (bl1->a.a_int > bl2->a.a_int) ? -1 : 0; break; case ANY_IPTR: result = (*bl1->a.a_iptr < *bl2->a.a_iptr) ? 1 : (*bl1->a.a_iptr > *bl2->a.a_iptr) ? -1 : 0; break; case ANY_LONG: result = (bl1->a.a_long < bl2->a.a_long) ? 1 : (bl1->a.a_long > bl2->a.a_long) ? -1 : 0; break; case ANY_LPTR: result = (*bl1->a.a_lptr < *bl2->a.a_lptr) ? 1 : (*bl1->a.a_lptr > *bl2->a.a_lptr) ? -1 : 0; break; case ANY_UINT: result = (bl1->a.a_uint < bl2->a.a_uint) ? 1 : (bl1->a.a_uint > bl2->a.a_uint) ? -1 : 0; break; case ANY_UPTR: result = (*bl1->a.a_uptr < *bl2->a.a_uptr) ? 1 : (*bl1->a.a_uptr > *bl2->a.a_uptr) ? -1 : 0; break; case ANY_ULONG: result = (bl1->a.a_ulong < bl2->a.a_ulong) ? 1 : (bl1->a.a_ulong > bl2->a.a_ulong) ? -1 : 0; break; case ANY_ULPTR: result = (*bl1->a.a_ulptr < *bl2->a.a_ulptr) ? 1 : (*bl1->a.a_ulptr > *bl2->a.a_ulptr) ? -1 : 0; break; case ANY_STR: if (strcmp(bl1->val, bl2->val) == 0) result = 0; else result = 1; break; case ANY_MASK32: if (bl1->a.a_ulong == bl2->a.a_ulong) result = 0; else result = 1; break; default: result = 1; } return result; } STATIC_OVL int percentage(bl, maxbl) struct istat_s *bl, *maxbl; { int result = 0; int anytype; if (!bl || !maxbl) { impossible("percentage: bad istat pointer %s, %s", fmt_ptr((genericptr_t) bl), fmt_ptr((genericptr_t) maxbl)); return 0; } anytype = bl->anytype; if (maxbl->a.a_void) { switch (anytype) { case ANY_INT: result = ((100 * bl->a.a_int) / maxbl->a.a_int); break; case ANY_LONG: result = (int) ((100L * bl->a.a_long) / maxbl->a.a_long); break; case ANY_UINT: result = (int) ((100U * bl->a.a_uint) / maxbl->a.a_uint); break; case ANY_ULONG: result = (int) ((100UL * bl->a.a_ulong) / maxbl->a.a_ulong); break; case ANY_IPTR: result = ((100 * (*bl->a.a_iptr)) / (*maxbl->a.a_iptr)); break; case ANY_LPTR: result = (int) ((100L * (*bl->a.a_lptr)) / (*maxbl->a.a_lptr)); break; case ANY_UPTR: result = (int) ((100U * (*bl->a.a_uptr)) / (*maxbl->a.a_uptr)); break; case ANY_ULPTR: result = (int) ((100UL * (*bl->a.a_ulptr)) / (*maxbl->a.a_ulptr)); break; } } return result; } #ifdef STATUS_HILITES /****************************************************************************/ /* Core status hiliting support */ /****************************************************************************/ struct hilite_s { boolean set; unsigned anytype; anything threshold; int behavior; int coloridx[2]; }; struct hilite_s status_hilites[MAXBLSTATS]; /* * This is the parser for the hilite options * Example: * OPTION=hilite_status: hitpoints/10%/red/normal * * set_hilite_status() separates each hilite entry into its 4 component * strings, then calls assign_hilite() to make the adjustments. */ boolean set_status_hilites(op, from_configfile) char *op; boolean from_configfile; { char hsbuf[4][QBUFSZ]; boolean rslt, badopt = FALSE; int fldnum, num = 0, ccount = 0; char c; num = fldnum = 0; hsbuf[0][0] = hsbuf[1][0] = hsbuf[2][0] = hsbuf[3][0] = '\0'; while (*op && fldnum < 4 && ccount < (QBUFSZ - 2)) { c = lowc(*op); if (c == ' ') { if (fldnum >= 2) { rslt = assign_hilite(&hsbuf[0][0], &hsbuf[1][0], &hsbuf[2][0], &hsbuf[3][0], from_configfile); if (!rslt) { badopt = TRUE; break; } } hsbuf[0][0] = hsbuf[1][0] = '\0'; hsbuf[2][0] = hsbuf[3][0] = '\0'; fldnum = 0; ccount = 0; } else if (c == '/') { fldnum++; ccount = 0; } else { hsbuf[fldnum][ccount++] = c; hsbuf[fldnum][ccount] = '\0'; } op++; } if (fldnum >= 2 && !badopt) { rslt = assign_hilite(&hsbuf[0][0], &hsbuf[1][0], &hsbuf[2][0], &hsbuf[3][0], from_configfile); if (!rslt) badopt = TRUE; } if (badopt) return FALSE; return TRUE; } void clear_status_hilites(from_configfile) boolean from_configfile; { int i; anything it; it = zeroany; for (i = 0; i < MAXBLSTATS; ++i) { (void) memset((genericptr_t) &status_hilites[i], 0, sizeof(struct hilite_s)); /* notify window port */ if (!from_configfile) status_threshold(i, blstats[0][i].anytype, it, 0, 0, 0); } } STATIC_OVL boolean assign_hilite(sa, sb, sc, sd, from_configfile) char *sa, *sb, *sc, *sd; boolean from_configfile; { char *tmp, *how; int i = -1, dt = -1, idx = -1; int coloridx[2] = { -1, -1 }; boolean inverse[2] = { FALSE, FALSE }; boolean bold[2] = { FALSE, FALSE }; boolean normal[2] = { 0, 0 }; boolean percent = FALSE, down_up = FALSE, changed = FALSE; anything threshold; enum statusfields fld = BL_FLUSH; threshold.a_void = 0; /* Example: * hilite_status: hitpoints/10%/red/normal */ /* field name to statusfield */ for (i = 0; sa && i < SIZE(fieldids); ++i) { if (strcmpi(sa, fieldids[i].fieldname) == 0) { idx = i; fld = fieldids[i].fldid; break; } } if (idx == -1) return FALSE; status_hilites[idx].set = FALSE; /* mark it "unset" */ /* threshold */ if (!sb) return FALSE; if ((strcmpi(sb, "updown") == 0) || (strcmpi(sb, "downup") == 0) || (strcmpi(sb, "up") == 0) || (strcmpi(sb, "down") == 0)) { down_up = TRUE; } else if ((strcmpi(sb, "changed") == 0) && (fld == BL_TITLE || fld == BL_ALIGN || fld == BL_LEVELDESC || fld == BL_CONDITION)) { changed = TRUE; /* changed is only thing allowed */ } else { tmp = sb; while (*tmp) { if (*tmp == '%') { *tmp = '\0'; percent = TRUE; break; } else if (!index("0123456789", *tmp)) return FALSE; tmp++; } if (strlen(sb) > 0) { dt = blstats[0][idx].anytype; if (percent) dt = ANY_INT; (void) s_to_anything(&threshold, sb, dt); } else return FALSE; if (percent && (threshold.a_int < 1 || threshold.a_int > 100)) return FALSE; if (!threshold.a_void && (strcmp(sb, "0") != 0)) return FALSE; } /* actions */ for (i = 0; i < 2; ++i) { if (!i) how = sc; else how = sd; if (!how) { if (!i) return FALSE; else break; /* sc is mandatory; sd is not */ } if (strcmpi(how, "bold") == 0) { bold[i] = TRUE; } else if (strcmpi(how, "inverse") == 0) { inverse[i] = TRUE; } else if (strcmpi(how, "normal") == 0) { normal[i] = TRUE; } else { int k; char colorname[BUFSZ]; for (k = 0; k < CLR_MAX; ++k) { /* we have to make a copy to change space to dash */ (void) strcpy(colorname, c_obj_colors[k]); for (tmp = index(colorname, ' '); tmp; tmp = index(colorname, ' ')) *tmp = '-'; if (strcmpi(how, colorname) == 0) { coloridx[i] = k; break; } } if (k >= CLR_MAX) return FALSE; } } /* Assign the values */ for (i = 0; i < 2; ++i) { if (inverse[i]) status_hilites[idx].coloridx[i] = BL_HILITE_INVERSE; else if (bold[i]) status_hilites[idx].coloridx[i] = BL_HILITE_BOLD; else if (coloridx[i]) status_hilites[idx].coloridx[i] = coloridx[i]; else status_hilites[idx].coloridx[i] = BL_HILITE_NONE; } if (percent) status_hilites[idx].behavior = BL_TH_VAL_PERCENTAGE; else if (down_up) status_hilites[idx].behavior = BL_TH_UPDOWN; else if (threshold.a_void) status_hilites[idx].behavior = BL_TH_VAL_ABSOLUTE; else status_hilites[idx].behavior = BL_TH_NONE; if (status_hilites[idx].behavior != BL_TH_NONE) { status_hilites[idx].threshold = threshold; status_hilites[idx].set = TRUE; } status_hilites[idx].anytype = dt; /* Now finally, we notify the window port */ if (!from_configfile) status_threshold(idx, status_hilites[idx].anytype, status_hilites[idx].threshold, status_hilites[idx].behavior, status_hilites[idx].coloridx[0], status_hilites[idx].coloridx[1]); return TRUE; } void status_notify_windowport(all) boolean all; { int idx; anything it; it = zeroany; for (idx = 0; idx < MAXBLSTATS; ++idx) { if (status_hilites[idx].set) status_threshold(idx, status_hilites[idx].anytype, status_hilites[idx].threshold, status_hilites[idx].behavior, status_hilites[idx].coloridx[0], status_hilites[idx].coloridx[1]); else status_threshold(idx, blstats[0][idx].anytype, it, 0, 0, 0); } } /* * get_status_hilites * * Returns a string containing all the status hilites in the * same format that is used to specify a status hilite preference * in the config file. */ char * get_status_hilites(buf, bufsiz) char *buf; int bufsiz; { int i, j, k, coloridx; const char *text = (char *) 0; char tmp[BUFSZ], colorname[BUFSZ]; boolean val_percentage, val_absolute, up_down; boolean added_one = FALSE; if (!buf) return (char *) 0; *buf = '\0'; bufsiz--; /* required trailing null */ for (i = 0; i < MAXBLSTATS; ++i) { val_percentage = val_absolute = up_down = FALSE; if (status_hilites[i].set) { if (!added_one) added_one = TRUE; else { Strcat(buf, " "); bufsiz--; } k = strlen(fieldids[i].fieldname); if (k < bufsiz) { Strcat(buf, fieldids[i].fieldname); bufsiz -= k; } if (bufsiz > 1) { Strcat(buf, "/"); bufsiz--; } if (status_hilites[i].behavior == BL_TH_VAL_PERCENTAGE) { val_percentage = TRUE; } else if (status_hilites[i].behavior == BL_TH_VAL_ABSOLUTE) { val_absolute = TRUE; } else if (status_hilites[i].behavior == BL_TH_UPDOWN) { up_down = TRUE; text = "updown"; } if (status_hilites[i].behavior != BL_TH_UPDOWN) { anything_to_s(tmp, &status_hilites[i].threshold, blstats[0][i].anytype); text = tmp; } k = strlen(text); if (k < (bufsiz - 1)) { Strcat(buf, text); if (val_percentage) Strcat(buf, "%"), k++; bufsiz -= k; } for (j = 0; j < 2; ++j) { if (bufsiz > 1) { Strcat(buf, "/"); bufsiz--; } coloridx = status_hilites[i].coloridx[j]; if (coloridx < 0) { if (coloridx == BL_HILITE_BOLD) text = "bold"; else if (coloridx == BL_HILITE_INVERSE) text = "inverse"; else text = "normal"; } else { char *blank; (void) strcpy(colorname, c_obj_colors[coloridx]); for (blank = index(colorname, ' '); blank; blank = index(colorname, ' ')) *blank = '-'; text = colorname; } k = strlen(text); if (k < bufsiz) { Strcat(buf, text); bufsiz -= k; } } } } return buf; } STATIC_OVL const char * clridx_to_s(buf, idx) char *buf; int idx; { static const char *a[] = { "bold", "inverse", "normal" }; char* p = 0; if (buf) { buf[0] = '\0'; if (idx < 0 && idx >= BL_HILITE_BOLD) Strcpy(buf, a[idx + 3]); else if (idx >= 0 && idx < CLR_MAX) Strcpy(buf, c_obj_colors[idx]); /* replace spaces with - */ for(p = buf; *p; p++) if(*p == ' ') *p = '-'; } return buf; } boolean status_hilite_menu() { int i, j, k, pick_cnt, pick_idx, opt_idx; menu_item *statfield_picks = (menu_item *) 0; const char *fieldname; int field_picks[MAXBLSTATS], res; struct hilite_s hltemp[MAXBLSTATS]; char buf[BUFSZ], thresholdbuf[BUFSZ], below[BUFSZ], above[BUFSZ]; winid tmpwin; anything any; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < MAXBLSTATS; i++) { (void) memset(&hltemp[i], 0, sizeof(struct hilite_s)); fieldname = fieldids[i].fieldname; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fieldname, MENU_UNSELECTED); field_picks[i] = 0; } end_menu(tmpwin, "Change hilite on which status field(s):"); if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &statfield_picks)) > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_idx = statfield_picks[pick_idx].item.a_int - 1; field_picks[opt_idx] = 1; } free((genericptr_t) statfield_picks); statfield_picks = (menu_item *) 0; } destroy_nhwindow(tmpwin); if (pick_cnt < 0) return FALSE; for (i = 0; i < MAXBLSTATS; i++) { if (field_picks[i]) { menu_item *pick = (menu_item *) 0; Sprintf(buf, "Threshold behavior options for %s:", fieldids[i].fieldname); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); if (i == BL_CONDITION) { any = zeroany; any.a_int = BL_TH_CONDITION + 1; add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE, "Condition bitmask threshold.", MENU_UNSELECTED); } any = zeroany; any.a_int = BL_TH_NONE + 1; add_menu(tmpwin, NO_GLYPH, &any, 'n', 0, ATR_NONE, "None", MENU_UNSELECTED); if (i != BL_CONDITION) { if (blstats[0][i].idxmax > 0) { any = zeroany; any.a_int = BL_TH_VAL_PERCENTAGE + 1; add_menu(tmpwin, NO_GLYPH, &any, 'p', 0, ATR_NONE, "Percentage threshold.", MENU_UNSELECTED); } any = zeroany; any.a_int = BL_TH_UPDOWN + 1; add_menu(tmpwin, NO_GLYPH, &any, 'u', 0, ATR_NONE, "UpDown threshold.", MENU_UNSELECTED); any = zeroany; any.a_int = BL_TH_VAL_ABSOLUTE + 1; add_menu(tmpwin, NO_GLYPH, &any, 'v', 0, ATR_NONE, "Value threshold.", MENU_UNSELECTED); } end_menu(tmpwin, buf); if ((res = select_menu(tmpwin, PICK_ONE, &pick)) > 0) { hltemp[i].behavior = pick->item.a_int - 1; free((genericptr_t) pick); } destroy_nhwindow(tmpwin); if (res < 0) return FALSE; if (hltemp[i].behavior == BL_TH_UPDOWN) { Sprintf(below, "%s decreases", fieldids[i].fieldname); Sprintf(above, "%s increases", fieldids[i].fieldname); } else if (hltemp[i].behavior) { /* Have them enter the threshold*/ Sprintf( buf, "Set %s threshold to what%s?", fieldids[i].fieldname, (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? " percentage" : (hltemp[i].behavior == BL_TH_CONDITION) ? " mask" : ""); getlin(buf, thresholdbuf); if (thresholdbuf[0] == '\033') return FALSE; (void) s_to_anything(&hltemp[i].threshold, thresholdbuf, blstats[0][i].anytype); if (!hltemp[i].threshold.a_void) return FALSE; Sprintf(below, "%s falls below %s%s", fieldids[i].fieldname, thresholdbuf, (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%" : ""); Sprintf(above, "%s rises above %s%s", fieldids[i].fieldname, thresholdbuf, (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%" : ""); } for (j = 0; j < 2 && (hltemp[i].behavior != BL_TH_NONE); ++j) { char prompt[QBUFSZ]; /* j == 0 below, j == 1 above */ menu_item *pick2 = (menu_item *) 0; Sprintf(prompt, "Display how when %s?", j ? above : below); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (k = -3; k < CLR_MAX; ++k) { /* if (k == -1) continue; */ any = zeroany; any.a_int = (k >= 0) ? k + 1 : k; if (k > 0) add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, c_obj_colors[k], MENU_UNSELECTED); else if (k == -1) add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "normal", MENU_UNSELECTED); else if (k == -2) add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "inverse", MENU_UNSELECTED); else if (k == -3) add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "bold", MENU_UNSELECTED); } end_menu(tmpwin, prompt); if ((res = select_menu(tmpwin, PICK_ONE, &pick2)) > 0) { hltemp[i].coloridx[j] = (pick2->item.a_char > 0) ? pick2->item.a_int - 1 : pick2->item.a_int; free((genericptr_t) pick2); } destroy_nhwindow(tmpwin); if (res < 0) return FALSE; } } } buf[0] = '\0'; for (i = 0; i < MAXBLSTATS; i++) { if (field_picks[i]) { Sprintf(eos(buf), "%s/%s%s/", fieldids[i].fieldname, (hltemp[i].behavior == BL_TH_UPDOWN) ? "updown" : anything_to_s(thresholdbuf, &hltemp[i].threshold, blstats[0][i].anytype), (hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%" : ""); /* borrow thresholdbuf for use with these last two */ Sprintf(eos(buf), "%s/", clridx_to_s(thresholdbuf, hltemp[i].coloridx[0])); Sprintf(eos(buf), "%s ", clridx_to_s(thresholdbuf, hltemp[i].coloridx[1])); } } return set_status_hilites(buf, FALSE); } #endif /*STATUS_HILITES*/ #endif /*STATUS_VIA_WINDOWPORT*/ /*botl.c*/ nethack-3.6.0/src/cmd.c0000664000076400007660000042025612623162643013651 0ustar paxedpaxed/* NetHack 3.6 cmd.c $NHDT-Date: 1446975462 2015/11/08 09:37:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.206 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "func_tab.h" #ifdef ALTMETA STATIC_VAR boolean alt_esc = FALSE; #endif struct cmd Cmd = { 0 }; /* flag.h */ extern const char *hu_stat[]; /* hunger status from eat.c */ extern const char *enc_stat[]; /* encumbrance status from botl.c */ #ifdef UNIX /* * Some systems may have getchar() return EOF for various reasons, and * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. */ #if defined(SYSV) || defined(DGUX) || defined(HPUX) #define NR_OF_EOFS 20 #endif #endif #define CMD_TRAVEL (char) 0x90 #define CMD_CLICKLOOK (char) 0x8F #ifdef DEBUG extern int NDECL(wiz_debug_cmd_bury); extern int NDECL(wiz_debug_cmd_traveldisplay); #endif #ifdef DUMB /* stuff commented out in extern.h, but needed here */ extern int NDECL(doapply); /**/ extern int NDECL(dorub); /**/ extern int NDECL(dojump); /**/ extern int NDECL(doextlist); /**/ extern int NDECL(enter_explore_mode); /**/ extern int NDECL(dodrop); /**/ extern int NDECL(doddrop); /**/ extern int NDECL(dodown); /**/ extern int NDECL(doup); /**/ extern int NDECL(donull); /**/ extern int NDECL(dowipe); /**/ extern int NDECL(docallcnd); /**/ extern int NDECL(dotakeoff); /**/ extern int NDECL(doremring); /**/ extern int NDECL(dowear); /**/ extern int NDECL(doputon); /**/ extern int NDECL(doddoremarm); /**/ extern int NDECL(dokick); /**/ extern int NDECL(dofire); /**/ extern int NDECL(dothrow); /**/ extern int NDECL(doeat); /**/ extern int NDECL(done2); /**/ extern int NDECL(vanquished); /**/ extern int NDECL(doengrave); /**/ extern int NDECL(dopickup); /**/ extern int NDECL(ddoinv); /**/ extern int NDECL(dotypeinv); /**/ extern int NDECL(dolook); /**/ extern int NDECL(doprgold); /**/ extern int NDECL(doprwep); /**/ extern int NDECL(doprarm); /**/ extern int NDECL(doprring); /**/ extern int NDECL(dopramulet); /**/ extern int NDECL(doprtool); /**/ extern int NDECL(dosuspend); /**/ extern int NDECL(doforce); /**/ extern int NDECL(doopen); /**/ extern int NDECL(doclose); /**/ extern int NDECL(dosh); /**/ extern int NDECL(dodiscovered); /**/ extern int NDECL(doclassdisco); /**/ extern int NDECL(doset); /**/ extern int NDECL(dotogglepickup); /**/ extern int NDECL(dowhatis); /**/ extern int NDECL(doquickwhatis); /**/ extern int NDECL(dowhatdoes); /**/ extern int NDECL(dohelp); /**/ extern int NDECL(dohistory); /**/ extern int NDECL(doloot); /**/ extern int NDECL(dodrink); /**/ extern int NDECL(dodip); /**/ extern int NDECL(dosacrifice); /**/ extern int NDECL(dopray); /**/ extern int NDECL(dotip); /**/ extern int NDECL(doturn); /**/ extern int NDECL(doredraw); /**/ extern int NDECL(doread); /**/ extern int NDECL(dosave); /**/ extern int NDECL(dosearch); /**/ extern int NDECL(doidtrap); /**/ extern int NDECL(dopay); /**/ extern int NDECL(dosit); /**/ extern int NDECL(dotalk); /**/ extern int NDECL(docast); /**/ extern int NDECL(dovspell); /**/ extern int NDECL(dotele); /**/ extern int NDECL(dountrap); /**/ extern int NDECL(doversion); /**/ extern int NDECL(doextversion); /**/ extern int NDECL(doswapweapon); /**/ extern int NDECL(dowield); /**/ extern int NDECL(dowieldquiver); /**/ extern int NDECL(dozap); /**/ extern int NDECL(doorganize); /**/ #endif /* DUMB */ static int NDECL(dosuspend_core); /**/ static int NDECL((*timed_occ_fn)); STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); STATIC_PTR int NDECL(domonability); STATIC_PTR int NDECL(dooverview_or_wiz_where); STATIC_PTR int NDECL(dotravel); STATIC_PTR int NDECL(doterrain); STATIC_PTR int NDECL(wiz_wish); STATIC_PTR int NDECL(wiz_identify); STATIC_PTR int NDECL(wiz_map); STATIC_PTR int NDECL(wiz_genesis); STATIC_PTR int NDECL(wiz_where); STATIC_PTR int NDECL(wiz_detect); STATIC_PTR int NDECL(wiz_panic); STATIC_PTR int NDECL(wiz_polyself); STATIC_PTR int NDECL(wiz_level_tele); STATIC_PTR int NDECL(wiz_level_change); STATIC_PTR int NDECL(wiz_show_seenv); STATIC_PTR int NDECL(wiz_show_vision); STATIC_PTR int NDECL(wiz_smell); STATIC_PTR int NDECL(wiz_mon_polycontrol); STATIC_PTR int NDECL(wiz_show_wmodes); STATIC_DCL void NDECL(wiz_map_levltyp); STATIC_DCL void NDECL(wiz_levltyp_legend); #if defined(__BORLANDC__) && !defined(_WIN32) extern void FDECL(show_borlandc_stats, (winid)); #endif #ifdef DEBUG_MIGRATING_MONS STATIC_PTR int NDECL(wiz_migrate_mons); #endif STATIC_DCL int FDECL(size_monst, (struct monst *)); STATIC_DCL int FDECL(size_obj, (struct obj *)); STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *)); STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *)); STATIC_PTR int NDECL(wiz_show_stats); STATIC_DCL boolean FDECL(accept_menu_prefix, (int NDECL((*)))); #ifdef PORT_DEBUG STATIC_DCL int NDECL(wiz_port_debug); #endif STATIC_PTR int NDECL(wiz_rumor_check); STATIC_DCL char FDECL(cmd_from_func, (int NDECL((*)))); STATIC_PTR int NDECL(doattributes); STATIC_PTR int NDECL(doconduct); /**/ STATIC_DCL void FDECL(enlght_line, (const char *, const char *, const char *, const char *)); STATIC_DCL char *FDECL(enlght_combatinc, (const char *, int, int, char *)); STATIC_DCL void FDECL(enlght_halfdmg, (int, int)); STATIC_DCL boolean NDECL(walking_on_water); STATIC_DCL boolean FDECL(cause_known, (int)); STATIC_DCL char *FDECL(attrval, (int, int, char *)); STATIC_DCL void FDECL(background_enlightenment, (int, int)); STATIC_DCL void FDECL(characteristics_enlightenment, (int, int)); STATIC_DCL void FDECL(one_characteristic, (int, int, int)); STATIC_DCL void FDECL(status_enlightenment, (int, int)); STATIC_DCL void FDECL(attributes_enlightenment, (int, int)); static const char *readchar_queue = ""; static coord clicklook_cc; STATIC_DCL char *NDECL(parse); STATIC_DCL boolean FDECL(help_dir, (CHAR_P, const char *)); STATIC_PTR int doprev_message(VOID_ARGS) { return nh_doprev_message(); } /* Count down by decrementing multi */ STATIC_PTR int timed_occupation(VOID_ARGS) { (*timed_occ_fn)(); if (multi > 0) multi--; return multi > 0; } /* If you have moved since initially setting some occupations, they * now shouldn't be able to restart. * * The basic rule is that if you are carrying it, you can continue * since it is with you. If you are acting on something at a distance, * your orientation to it must have changed when you moved. * * The exception to this is taking off items, since they can be taken * off in a number of ways in the intervening time, screwing up ordering. * * Currently: Take off all armor. * Picking Locks / Forcing Chests. * Setting traps. */ void reset_occupations() { reset_remarm(); reset_pick(); reset_trapset(); } /* If a time is given, use it to timeout this function, otherwise the * function times out by its own means. */ void set_occupation(fn, txt, xtime) int NDECL((*fn)); const char *txt; int xtime; { if (xtime) { occupation = timed_occupation; timed_occ_fn = fn; } else occupation = fn; occtxt = txt; occtime = 0; return; } STATIC_DCL char NDECL(popch); /* Provide a means to redo the last command. The flag `in_doagain' is set * to true while redoing the command. This flag is tested in commands that * require additional input (like `throw' which requires a thing and a * direction), and the input prompt is not shown. Also, while in_doagain is * TRUE, no keystrokes can be saved into the saveq. */ #define BSIZE 20 static char pushq[BSIZE], saveq[BSIZE]; static NEARDATA int phead, ptail, shead, stail; STATIC_OVL char popch() { /* If occupied, return '\0', letting tgetch know a character should * be read from the keyboard. If the character read is not the * ABORT character (as checked in pcmain.c), that character will be * pushed back on the pushq. */ if (occupation) return '\0'; if (in_doagain) return (char) ((shead != stail) ? saveq[stail++] : '\0'); else return (char) ((phead != ptail) ? pushq[ptail++] : '\0'); } char pgetchar() /* courtesy of aeb@cwi.nl */ { register int ch; if (!(ch = popch())) ch = nhgetch(); return (char) ch; } /* A ch == 0 resets the pushq */ void pushch(ch) char ch; { if (!ch) phead = ptail = 0; if (phead < BSIZE) pushq[phead++] = ch; return; } /* A ch == 0 resets the saveq. Only save keystrokes when not * replaying a previous command. */ void savech(ch) char ch; { if (!in_doagain) { if (!ch) phead = ptail = shead = stail = 0; else if (shead < BSIZE) saveq[shead++] = ch; } return; } /* here after # - now read a full-word command */ STATIC_PTR int doextcmd(VOID_ARGS) { int idx, retval; int NDECL((*func)); /* keep repeating until we don't run help or quit */ do { idx = get_ext_cmd(); if (idx < 0) return 0; /* quit */ func = extcmdlist[idx].ef_funct; if (iflags.menu_requested && !accept_menu_prefix(func)) { pline("'m' prefix has no effect for this command."); iflags.menu_requested = FALSE; } retval = (*func)(); } while (func == doextlist); return retval; } /* here after #? - now list all full-word commands */ int doextlist(VOID_ARGS) { register const struct ext_func_tab *efp; char buf[BUFSZ]; winid datawin; datawin = create_nhwindow(NHW_TEXT); putstr(datawin, 0, ""); putstr(datawin, 0, " Extended Commands List"); putstr(datawin, 0, ""); putstr(datawin, 0, " Press '#', then type:"); putstr(datawin, 0, ""); for (efp = extcmdlist; efp->ef_txt; efp++) { Sprintf(buf, " %-15s - %s.", efp->ef_txt, efp->ef_desc); putstr(datawin, 0, buf); } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); return 0; } #ifdef TTY_GRAPHICS #define MAX_EXT_CMD 50 /* Change if we ever have > 50 ext cmds */ /* * This is currently used only by the tty port and is * controlled via runtime option 'extmenu'. * ``# ?'' is counted towards the limit of the number of commands, * so we actually support MAX_EXT_CMD-1 "real" extended commands. * * Here after # - now show pick-list of possible commands. */ int extcmd_via_menu() { const struct ext_func_tab *efp; menu_item *pick_list = (menu_item *) 0; winid win; anything any; const struct ext_func_tab *choices[MAX_EXT_CMD + 1]; char buf[BUFSZ]; char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20]; int i, n, nchoices, acount; int ret, biggest; int accelerator, prevaccelerator; int matchlevel = 0; ret = 0; cbuf[0] = '\0'; biggest = 0; while (!ret) { i = n = 0; any = zeroany; /* populate choices */ for (efp = extcmdlist; efp->ef_txt; efp++) { if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) { choices[i] = efp; if ((int) strlen(efp->ef_desc) > biggest) { biggest = strlen(efp->ef_desc); Sprintf(fmtstr, "%%-%ds", biggest + 15); } if (++i > MAX_EXT_CMD) { #if defined(BETA) impossible( "Exceeded %d extended commands in doextcmd() menu; 'extmenu' disabled.", MAX_EXT_CMD); #endif /* BETA */ iflags.extmenu = 0; return -1; } } } choices[i] = (struct ext_func_tab *) 0; nchoices = i; /* if we're down to one, we have our selection so get out of here */ if (nchoices == 1) { for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++) if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) { ret = i; break; } break; } /* otherwise... */ win = create_nhwindow(NHW_MENU); start_menu(win); accelerator = prevaccelerator = 0; acount = 0; for (i = 0; choices[i]; ++i) { accelerator = choices[i]->ef_txt[matchlevel]; if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) { if (acount) { /* flush extended cmds for that letter already in buf */ Sprintf(buf, fmtstr, prompt); any.a_char = prevaccelerator; add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); acount = 0; } } prevaccelerator = accelerator; if (!acount || nchoices < (ROWNO - 3)) { Sprintf(prompt, "%s [%s]", choices[i]->ef_txt, choices[i]->ef_desc); } else if (acount == 1) { Sprintf(prompt, "%s or %s", choices[i - 1]->ef_txt, choices[i]->ef_txt); } else { Strcat(prompt, " or "); Strcat(prompt, choices[i]->ef_txt); } ++acount; } if (acount) { /* flush buf */ Sprintf(buf, fmtstr, prompt); any.a_char = prevaccelerator; add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); } Sprintf(prompt, "Extended Command: %s", cbuf); end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n == 1) { if (matchlevel > (QBUFSZ - 2)) { free((genericptr_t) pick_list); #if defined(BETA) impossible("Too many chars (%d) entered in extcmd_via_menu()", matchlevel); #endif ret = -1; } else { cbuf[matchlevel++] = pick_list[0].item.a_char; cbuf[matchlevel] = '\0'; free((genericptr_t) pick_list); } } else { if (matchlevel) { ret = 0; matchlevel = 0; } else ret = -1; } } return ret; } #endif /* TTY_GRAPHICS */ /* #monster command - use special monster ability while polymorphed */ STATIC_PTR int domonability(VOID_ARGS) { if (can_breathe(youmonst.data)) return dobreathe(); else if (attacktype(youmonst.data, AT_SPIT)) return dospit(); else if (youmonst.data->mlet == S_NYMPH) return doremove(); else if (attacktype(youmonst.data, AT_GAZE)) return dogaze(); else if (is_were(youmonst.data)) return dosummon(); else if (webmaker(youmonst.data)) return dospinweb(); else if (is_hider(youmonst.data)) return dohide(); else if (is_mind_flayer(youmonst.data)) return domindblast(); else if (u.umonnum == PM_GREMLIN) { if (IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { if (split_mon(&youmonst, (struct monst *) 0)) dryup(u.ux, u.uy, TRUE); } else There("is no fountain here."); } else if (is_unicorn(youmonst.data)) { use_unicorn_horn((struct obj *) 0); return 1; } else if (youmonst.data->msound == MS_SHRIEK) { You("shriek."); if (u.uburied) pline("Unfortunately sound does not carry well through rock."); else aggravate(); } else if (youmonst.data->mlet == S_VAMPIRE) return dopoly(); else if (Upolyd) pline("Any special ability you may have is purely reflexive."); else You("don't have a special ability in your normal form!"); return 0; } int enter_explore_mode(VOID_ARGS) { if (wizard) { You("are in debug mode."); } else if (discover) { You("are already in explore mode."); } else { #ifdef SYSCF #if defined(UNIX) if (!sysopt.explorers || !sysopt.explorers[0] || !check_user_string(sysopt.explorers)) { You("cannot access explore mode."); return 0; } #endif #endif pline( "Beware! From explore mode there will be no return to normal game."); if (paranoid_query(ParanoidQuit, "Do you want to enter explore mode?")) { clear_nhwindow(WIN_MESSAGE); You("are now in non-scoring explore mode."); discover = TRUE; } else { clear_nhwindow(WIN_MESSAGE); pline("Resuming normal game."); } } return 0; } STATIC_PTR int dooverview_or_wiz_where(VOID_ARGS) { if (wizard) return wiz_where(); else dooverview(); return 0; } /* ^W command - wish for something */ STATIC_PTR int wiz_wish(VOID_ARGS) /* Unlimited wishes for debug mode by Paul Polderman */ { if (wizard) { boolean save_verbose = flags.verbose; flags.verbose = FALSE; makewish(); flags.verbose = save_verbose; (void) encumber_msg(); } else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_wish))); return 0; } /* ^I command - reveal and optionally identify hero's inventory */ STATIC_PTR int wiz_identify(VOID_ARGS) { if (wizard) { iflags.override_ID = (int) cmd_from_func(wiz_identify); if (display_inventory((char *) 0, TRUE) == -1) identify_pack(0, FALSE); iflags.override_ID = 0; } else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_identify))); return 0; } /* ^F command - reveal the level map and any traps on it */ STATIC_PTR int wiz_map(VOID_ARGS) { if (wizard) { struct trap *t; long save_Hconf = HConfusion, save_Hhallu = HHallucination; HConfusion = HHallucination = 0L; for (t = ftrap; t != 0; t = t->ntrap) { t->tseen = 1; map_trap(t, TRUE); } do_mapping(); HConfusion = save_Hconf; HHallucination = save_Hhallu; } else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_map))); return 0; } /* ^G command - generate monster(s); a count prefix will be honored */ STATIC_PTR int wiz_genesis(VOID_ARGS) { if (wizard) (void) create_particular(); else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_genesis))); return 0; } /* ^O command - display dungeon layout */ STATIC_PTR int wiz_where(VOID_ARGS) { if (wizard) (void) print_dungeon(FALSE, (schar *) 0, (xchar *) 0); else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_where))); return 0; } /* ^E command - detect unseen (secret doors, traps, hidden monsters) */ STATIC_PTR int wiz_detect(VOID_ARGS) { if (wizard) (void) findit(); else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_detect))); return 0; } /* ^V command - level teleport */ STATIC_PTR int wiz_level_tele(VOID_ARGS) { if (wizard) level_tele(); else pline("Unavailable command '%s'.", visctrl((int) cmd_from_func(wiz_level_tele))); return 0; } /* #monpolycontrol command - choose new form for shapechangers, polymorphees */ STATIC_PTR int wiz_mon_polycontrol(VOID_ARGS) { iflags.mon_polycontrol = !iflags.mon_polycontrol; pline("Monster polymorph control is %s.", iflags.mon_polycontrol ? "on" : "off"); return 0; } /* #levelchange command - adjust hero's experience level */ STATIC_PTR int wiz_level_change(VOID_ARGS) { char buf[BUFSZ]; int newlevel; int ret; getlin("To what experience level do you want to be set?", buf); (void) mungspaces(buf); if (buf[0] == '\033' || buf[0] == '\0') ret = 0; else ret = sscanf(buf, "%d", &newlevel); if (ret != 1) { pline1(Never_mind); return 0; } if (newlevel == u.ulevel) { You("are already that experienced."); } else if (newlevel < u.ulevel) { if (u.ulevel == 1) { You("are already as inexperienced as you can get."); return 0; } if (newlevel < 1) newlevel = 1; while (u.ulevel > newlevel) losexp("#levelchange"); } else { if (u.ulevel >= MAXULEV) { You("are already as experienced as you can get."); return 0; } if (newlevel > MAXULEV) newlevel = MAXULEV; while (u.ulevel < newlevel) pluslvl(FALSE); } u.ulevelmax = u.ulevel; return 0; } /* #panic command - test program's panic handling */ STATIC_PTR int wiz_panic(VOID_ARGS) { if (yn("Do you want to call panic() and end your game?") == 'y') panic("Crash test."); return 0; } /* #polyself command - change hero's form */ STATIC_PTR int wiz_polyself(VOID_ARGS) { polyself(1); return 0; } /* #seenv command */ STATIC_PTR int wiz_show_seenv(VOID_ARGS) { winid win; int x, y, v, startx, stopx, curx; char row[COLNO + 1]; win = create_nhwindow(NHW_TEXT); /* * Each seenv description takes up 2 characters, so center * the seenv display around the hero. */ startx = max(1, u.ux - (COLNO / 4)); stopx = min(startx + (COLNO / 2), COLNO); /* can't have a line exactly 80 chars long */ if (stopx - startx == COLNO / 2) startx++; for (y = 0; y < ROWNO; y++) { for (x = startx, curx = 0; x < stopx; x++, curx += 2) { if (x == u.ux && y == u.uy) { row[curx] = row[curx + 1] = '@'; } else { v = levl[x][y].seenv & 0xff; if (v == 0) row[curx] = row[curx + 1] = ' '; else Sprintf(&row[curx], "%02x", v); } } /* remove trailing spaces */ for (x = curx - 1; x >= 0; x--) if (row[x] != ' ') break; row[x + 1] = '\0'; putstr(win, 0, row); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } /* #vision command */ STATIC_PTR int wiz_show_vision(VOID_ARGS) { winid win; int x, y, v; char row[COLNO + 1]; win = create_nhwindow(NHW_TEXT); Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit", COULD_SEE, IN_SIGHT, TEMP_LIT); putstr(win, 0, row); putstr(win, 0, ""); for (y = 0; y < ROWNO; y++) { for (x = 1; x < COLNO; x++) { if (x == u.ux && y == u.uy) row[x] = '@'; else { v = viz_array[y][x]; /* data access should be hidden */ if (v == 0) row[x] = ' '; else row[x] = '0' + viz_array[y][x]; } } /* remove trailing spaces */ for (x = COLNO - 1; x >= 1; x--) if (row[x] != ' ') break; row[x + 1] = '\0'; putstr(win, 0, &row[1]); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } /* #wmode command */ STATIC_PTR int wiz_show_wmodes(VOID_ARGS) { winid win; int x, y; char row[COLNO + 1]; struct rm *lev; boolean istty = !strcmp(windowprocs.name, "tty"); win = create_nhwindow(NHW_TEXT); if (istty) putstr(win, 0, ""); /* tty only: blank top line */ for (y = 0; y < ROWNO; y++) { for (x = 0; x < COLNO; x++) { lev = &levl[x][y]; if (x == u.ux && y == u.uy) row[x] = '@'; else if (IS_WALL(lev->typ) || lev->typ == SDOOR) row[x] = '0' + (lev->wall_info & WM_MASK); else if (lev->typ == CORR) row[x] = '#'; else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ)) row[x] = '.'; else row[x] = 'x'; } row[COLNO] = '\0'; /* map column 0, levl[0][], is off the left edge of the screen */ putstr(win, 0, &row[1]); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } /* wizard mode variant of #terrain; internal levl[][].typ values in base-36 */ STATIC_OVL void wiz_map_levltyp(VOID_ARGS) { winid win; int x, y, terrain; char row[COLNO + 1]; boolean istty = !strcmp(windowprocs.name, "tty"); win = create_nhwindow(NHW_TEXT); /* map row 0, levl[][0], is drawn on the second line of tty screen */ if (istty) putstr(win, 0, ""); /* tty only: blank top line */ for (y = 0; y < ROWNO; y++) { /* map column 0, levl[0][], is off the left edge of the screen; it should always have terrain type "undiggable stone" */ for (x = 1; x < COLNO; x++) { terrain = levl[x][y].typ; /* assumes there aren't more than 10+26+26 terrain types */ row[x - 1] = (char) ((terrain == 0 && !may_dig(x, y)) ? '*' : (terrain < 10) ? '0' + terrain : (terrain < 36) ? 'a' + terrain - 10 : 'A' + terrain - 36); } if (levl[0][y].typ != 0 || may_dig(0, y)) row[x++] = '!'; row[x] = '\0'; putstr(win, 0, row); } { char dsc[BUFSZ]; s_level *slev = Is_special(&u.uz); Sprintf(dsc, "D:%d,L:%d", u.uz.dnum, u.uz.dlevel); /* [dungeon branch features currently omitted] */ /* special level features */ if (slev) { Sprintf(eos(dsc), " \"%s\"", slev->proto); /* special level flags (note: dungeon.def doesn't set `maze' or `hell' for any specific levels so those never show up) */ if (slev->flags.maze_like) Strcat(dsc, " mazelike"); if (slev->flags.hellish) Strcat(dsc, " hellish"); if (slev->flags.town) Strcat(dsc, " town"); if (slev->flags.rogue_like) Strcat(dsc, " roguelike"); /* alignment currently omitted to save space */ } /* level features */ if (level.flags.nfountains) Sprintf(eos(dsc), " %c:%d", defsyms[S_fountain].sym, (int) level.flags.nfountains); if (level.flags.nsinks) Sprintf(eos(dsc), " %c:%d", defsyms[S_sink].sym, (int) level.flags.nsinks); if (level.flags.has_vault) Strcat(dsc, " vault"); if (level.flags.has_shop) Strcat(dsc, " shop"); if (level.flags.has_temple) Strcat(dsc, " temple"); if (level.flags.has_court) Strcat(dsc, " throne"); if (level.flags.has_zoo) Strcat(dsc, " zoo"); if (level.flags.has_morgue) Strcat(dsc, " morgue"); if (level.flags.has_barracks) Strcat(dsc, " barracks"); if (level.flags.has_beehive) Strcat(dsc, " hive"); if (level.flags.has_swamp) Strcat(dsc, " swamp"); /* level flags */ if (level.flags.noteleport) Strcat(dsc, " noTport"); if (level.flags.hardfloor) Strcat(dsc, " noDig"); if (level.flags.nommap) Strcat(dsc, " noMMap"); if (!level.flags.hero_memory) Strcat(dsc, " noMem"); if (level.flags.shortsighted) Strcat(dsc, " shortsight"); if (level.flags.graveyard) Strcat(dsc, " graveyard"); if (level.flags.is_maze_lev) Strcat(dsc, " maze"); if (level.flags.is_cavernous_lev) Strcat(dsc, " cave"); if (level.flags.arboreal) Strcat(dsc, " tree"); if (Sokoban) Strcat(dsc, " sokoban-rules"); /* non-flag info; probably should include dungeon branching checks (extra stairs and magic portals) here */ if (Invocation_lev(&u.uz)) Strcat(dsc, " invoke"); if (On_W_tower_level(&u.uz)) Strcat(dsc, " tower"); /* append a branch identifier for completeness' sake */ if (u.uz.dnum == 0) Strcat(dsc, " dungeon"); else if (u.uz.dnum == mines_dnum) Strcat(dsc, " mines"); else if (In_sokoban(&u.uz)) Strcat(dsc, " sokoban"); else if (u.uz.dnum == quest_dnum) Strcat(dsc, " quest"); else if (Is_knox(&u.uz)) Strcat(dsc, " ludios"); else if (u.uz.dnum == 1) Strcat(dsc, " gehennom"); else if (u.uz.dnum == tower_dnum) Strcat(dsc, " vlad"); else if (In_endgame(&u.uz)) Strcat(dsc, " endgame"); else { /* somebody's added a dungeon branch we're not expecting */ const char *brname = dungeons[u.uz.dnum].dname; if (!brname || !*brname) brname = "unknown"; if (!strncmpi(brname, "the ", 4)) brname += 4; Sprintf(eos(dsc), " %s", brname); } /* limit the line length to map width */ if (strlen(dsc) >= COLNO) dsc[COLNO - 1] = '\0'; /* truncate */ putstr(win, 0, dsc); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return; } /* temporary? hack, since level type codes aren't the same as screen symbols and only the latter have easily accessible descriptions */ static const char *levltyp[] = { "stone", "vertical wall", "horizontal wall", "top-left corner wall", "top-right corner wall", "bottom-left corner wall", "bottom-right corner wall", "cross wall", "tee-up wall", "tee-down wall", "tee-left wall", "tee-right wall", "drawbridge wall", "tree", "secret door", "secret corridor", "pool", "moat", "water", "drawbridge up", "lava pool", "iron bars", "door", "corridor", "room", "stairs", "ladder", "fountain", "throne", "sink", "grave", "altar", "ice", "drawbridge down", "air", "cloud", /* not a real terrain type, but used for undiggable stone by wiz_map_levltyp() */ "unreachable/undiggable", /* padding in case the number of entries above is odd */ "" }; /* explanation of base-36 output from wiz_map_levltyp() */ STATIC_OVL void wiz_levltyp_legend(VOID_ARGS) { winid win; int i, j, last, c; const char *dsc, *fmt; char buf[BUFSZ]; win = create_nhwindow(NHW_TEXT); putstr(win, 0, "#terrain encodings:"); putstr(win, 0, ""); fmt = " %c - %-28s"; /* TODO: include tab-separated variant for win32 */ *buf = '\0'; /* output in pairs, left hand column holds [0],[1],...,[N/2-1] and right hand column holds [N/2],[N/2+1],...,[N-1]; N ('last') will always be even, and may or may not include the empty string entry to pad out the final pair, depending upon how many other entries are present in levltyp[] */ last = SIZE(levltyp) & ~1; for (i = 0; i < last / 2; ++i) for (j = i; j < last; j += last / 2) { dsc = levltyp[j]; c = !*dsc ? ' ' : !strncmp(dsc, "unreachable", 11) ? '*' /* same int-to-char conversion as wiz_map_levltyp() */ : (j < 10) ? '0' + j : (j < 36) ? 'a' + j - 10 : 'A' + j - 36; Sprintf(eos(buf), fmt, c, dsc); if (j > i) { putstr(win, 0, buf); *buf = '\0'; } } display_nhwindow(win, TRUE); destroy_nhwindow(win); return; } /* #wizsmell command - test usmellmon(). */ STATIC_PTR int wiz_smell(VOID_ARGS) { int ans = 0; int mndx; /* monster index */ coord cc; /* screen pos of unknown glyph */ int glyph; /* glyph at selected position */ cc.x = u.ux; cc.y = u.uy; mndx = 0; /* gcc -Wall lint */ if (!olfaction(youmonst.data)) { You("are incapable of detecting odors in your present form."); return 0; } pline("You can move the cursor to a monster that you want to smell."); do { pline("Pick a monster to smell."); ans = getpos(&cc, TRUE, "a monster"); if (ans < 0 || cc.x < 0) { return 0; /* done */ } /* Convert the glyph at the selected position to a mndxbol. */ glyph = glyph_at(cc.x, cc.y); if (glyph_is_monster(glyph)) mndx = glyph_to_mon(glyph); else mndx = 0; /* Is it a monster? */ if (mndx) { if (!usmellmon(&mons[mndx])) pline("That monster seems to give off no smell."); } else pline("That is not a monster."); } while (TRUE); return 0; } /* #wizrumorcheck command - verify each rumor access */ STATIC_PTR int wiz_rumor_check(VOID_ARGS) { rumor_check(); return 0; } /* #terrain command -- show known map, inspired by crawl's '|' command */ STATIC_PTR int doterrain(VOID_ARGS) { winid men; menu_item *sel; anything any; int n; int which; /* * normal play: choose between known map without mons, obj, and traps * (to see underlying terrain only), or * known map without mons and objs (to see traps under mons and objs), or * known map without mons (to see objects under monsters); * explore mode: normal choices plus full map (w/o mons, objs, traps); * wizard mode: normal and explore choices plus * a dump of the internal levl[][].typ codes w/ level flags, or * a legend for the levl[][].typ codes dump */ men = create_nhwindow(NHW_MENU); any = zeroany; any.a_int = 1; add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, "known map without monsters, objects, and traps", MENU_SELECTED); any.a_int = 2; add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, "known map without monsters and objects", MENU_UNSELECTED); any.a_int = 3; add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, "known map without monsters", MENU_UNSELECTED); if (discover || wizard) { any.a_int = 4; add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, "full map without monsters, objects, and traps", MENU_UNSELECTED); if (wizard) { any.a_int = 5; add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, "internal levl[][].typ codes in base-36", MENU_UNSELECTED); any.a_int = 6; add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE, "legend of base-36 levl[][].typ codes", MENU_UNSELECTED); } } end_menu(men, "View which?"); n = select_menu(men, PICK_ONE, &sel); destroy_nhwindow(men); /* * n < 0: player used ESC to cancel; * n == 0: preselected entry was explicitly chosen and got toggled off; * n == 1: preselected entry was implicitly chosen via |; * n == 2: another entry was explicitly chosen, so skip preselected one. */ which = (n < 0) ? -1 : (n == 0) ? 1 : sel[0].item.a_int; if (n > 1 && which == 1) which = sel[1].item.a_int; if (n > 0) free((genericptr_t) sel); switch (which) { case 1: reveal_terrain(0, 0); break; /* known map */ case 2: reveal_terrain(0, 1); break; /* known map with traps */ case 3: reveal_terrain(0, 1|2); break; /* known map w/ traps & objs */ case 4: reveal_terrain(1, 0); break; /* full map */ case 5: wiz_map_levltyp(); break; /* map internals */ case 6: wiz_levltyp_legend(); break; /* internal details */ default: break; } return 0; /* no time elapses */ } /* -enlightenment and conduct- */ static winid en_win = WIN_ERR; static const char You_[] = "You ", are[] = "are ", were[] = "were ", have[] = "have ", had[] = "had ", can[] = "can ", could[] = "could "; static const char have_been[] = "have been ", have_never[] = "have never ", never[] = "never "; #define enl_msg(prefix, present, past, suffix, ps) \ enlght_line(prefix, final ? past : present, suffix, ps) #define you_are(attr, ps) enl_msg(You_, are, were, attr, ps) #define you_have(attr, ps) enl_msg(You_, have, had, attr, ps) #define you_can(attr, ps) enl_msg(You_, can, could, attr, ps) #define you_have_been(goodthing) enl_msg(You_, have_been, were, goodthing, "") #define you_have_never(badthing) \ enl_msg(You_, have_never, never, badthing, "") #define you_have_X(something) \ enl_msg(You_, have, (const char *) "", something, "") static void enlght_line(start, middle, end, ps) const char *start, *middle, *end, *ps; { char buf[BUFSZ]; Sprintf(buf, " %s%s%s%s.", start, middle, end, ps); putstr(en_win, 0, buf); } /* format increased chance to hit or damage or defense (Protection) */ static char * enlght_combatinc(inctyp, incamt, final, outbuf) const char *inctyp; int incamt, final; char *outbuf; { const char *modif, *bonus; boolean invrt; int absamt; absamt = abs(incamt); /* Protection amount is typically larger than damage or to-hit; reduce magnitude by a third in order to stretch modifier ranges (small:1..5, moderate:6..10, large:11..19, huge:20+) */ if (!strcmp(inctyp, "defense")) absamt = (absamt * 2) / 3; if (absamt <= 3) modif = "small"; else if (absamt <= 6) modif = "moderate"; else if (absamt <= 12) modif = "large"; else modif = "huge"; modif = !incamt ? "no" : an(modif); /* ("no" case shouldn't happen) */ bonus = (incamt >= 0) ? "bonus" : "penalty"; /* "bonus " (to hit) vs " bonus" (damage, defense) */ invrt = strcmp(inctyp, "to hit") ? TRUE : FALSE; Sprintf(outbuf, "%s %s %s", modif, invrt ? inctyp : bonus, invrt ? bonus : inctyp); if (final || wizard) Sprintf(eos(outbuf), " (%s%d)", (incamt > 0) ? "+" : "", incamt); return outbuf; } /* report half physical or half spell damage */ STATIC_OVL void enlght_halfdmg(category, final) int category; int final; { const char *category_name; char buf[BUFSZ]; switch (category) { case HALF_PHDAM: category_name = "physical"; break; case HALF_SPDAM: category_name = "spell"; break; default: category_name = "unknown"; break; } Sprintf(buf, " %s %s damage", (final || wizard) ? "half" : "reduced", category_name); enl_msg(You_, "take", "took", buf, from_what(category)); } /* is hero actively using water walking capability on water (or lava)? */ STATIC_OVL boolean walking_on_water() { if (u.uinwater || Levitation || Flying) return FALSE; return (boolean) (Wwalking && (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy))); } /* check whether hero is wearing something that player definitely knows confers the target property; item must have been seen and its type discovered but it doesn't necessarily have to be fully identified */ STATIC_OVL boolean cause_known(propindx) int propindx; /* index of a property which can be conveyed by worn item */ { register struct obj *o; long mask = W_ARMOR | W_AMUL | W_RING | W_TOOL; /* simpler than from_what()/what_gives(); we don't attempt to handle artifacts and we deliberately ignore wielded items */ for (o = invent; o; o = o->nobj) { if (!(o->owornmask & mask)) continue; if ((int) objects[o->otyp].oc_oprop == propindx && objects[o->otyp].oc_name_known && o->dknown) return TRUE; } return FALSE; } /* format a characteristic value, accommodating Strength's strangeness */ STATIC_OVL char * attrval(attrindx, attrvalue, resultbuf) int attrindx, attrvalue; char resultbuf[]; /* should be at least [7] to hold "18/100\0" */ { if (attrindx != A_STR || attrvalue <= 18) Sprintf(resultbuf, "%d", attrvalue); else if (attrvalue > STR18(100)) /* 19 to 25 */ Sprintf(resultbuf, "%d", attrvalue - 100); else /* simplify "18/ **" to be "18/100" */ Sprintf(resultbuf, "18/%02d", attrvalue - 18); return resultbuf; } void enlightenment(mode, final) int mode; /* BASICENLIGHTENMENT | MAGICENLIGHTENMENT (| both) */ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */ { char buf[BUFSZ], tmpbuf[BUFSZ]; Strcpy(tmpbuf, plname); *tmpbuf = highc(*tmpbuf); /* same adjustment as bottom line */ /* as in background_enlightenment, when poly'd we need to use the saved gender in u.mfemale rather than the current you-as-monster gender */ Sprintf(buf, "%s the %s's attributes:", tmpbuf, ((Upolyd ? u.mfemale : flags.female) && urole.name.f) ? urole.name.f : urole.name.m); en_win = create_nhwindow(NHW_MENU); /* title */ putstr(en_win, 0, buf); /* "Conan the Archeologist's attributes:" */ /* background and characteristics; ^X or end-of-game disclosure */ if (mode & BASICENLIGHTENMENT) { /* role, race, alignment, deities */ background_enlightenment(mode, final); /* strength, dexterity, &c */ characteristics_enlightenment(mode, final); } /* expanded status line information, including things which aren't included there due to space considerations--such as obvious alternative movement indicators (riding, levitation, &c), and various troubles (turning to stone, trapped, confusion, &c); shown for both basic and magic enlightenment */ status_enlightenment(mode, final); /* remaining attributes; shown for potion,&c or wizard mode and explore mode ^X or end of game disclosure */ if (mode & MAGICENLIGHTENMENT) { /* intrinsics and other traditional enlightenment feedback */ attributes_enlightenment(mode, final); } display_nhwindow(en_win, TRUE); destroy_nhwindow(en_win); en_win = WIN_ERR; } /*ARGSUSED*/ /* display role, race, alignment and such to en_win */ STATIC_OVL void background_enlightenment(unused_mode, final) int unused_mode UNUSED; int final; { const char *role_titl, *rank_titl; int innategend, difgend, difalgn; char buf[BUFSZ], tmpbuf[BUFSZ]; /* note that if poly'd, we need to use u.mfemale instead of flags.female to access hero's saved gender-as-human/elf/&c rather than current one */ innategend = (Upolyd ? u.mfemale : flags.female) ? 1 : 0; role_titl = (innategend && urole.name.f) ? urole.name.f : urole.name.m; rank_titl = rank_of(u.ulevel, Role_switch, innategend); putstr(en_win, 0, ""); /* separator after title */ putstr(en_win, 0, "Background:"); /* if polymorphed, report current shape before underlying role; will be repeated as first status: "you are transformed" and also among various attributes: "you are in beast form" (after being told about lycanthropy) or "you are polymorphed into " (with countdown timer appended for wizard mode); we really want the player to know he's not a samurai at the moment... */ if (Upolyd) { struct permonst *uasmon = youmonst.data; tmpbuf[0] = '\0'; /* here we always use current gender, not saved role gender */ if (!is_male(uasmon) && !is_female(uasmon) && !is_neuter(uasmon)) Sprintf(tmpbuf, "%s ", genders[flags.female ? 1 : 0].adj); Sprintf(buf, "%sin %s%s form", !final ? "currently " : "", tmpbuf, uasmon->mname); you_are(buf, ""); } /* report role; omit gender if it's redundant (eg, "female priestess") */ tmpbuf[0] = '\0'; if (!urole.name.f && ((urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE) || innategend != flags.initgend)) Sprintf(tmpbuf, "%s ", genders[innategend].adj); buf[0] = '\0'; if (Upolyd) Strcpy(buf, "actually "); /* "You are actually a ..." */ if (!strcmpi(rank_titl, role_titl)) { /* omit role when rank title matches it */ Sprintf(eos(buf), "%s, level %d %s%s", an(rank_titl), u.ulevel, tmpbuf, urace.noun); } else { Sprintf(eos(buf), "%s, a level %d %s%s %s", an(rank_titl), u.ulevel, tmpbuf, urace.adj, role_titl); } you_are(buf, ""); /* report alignment (bypass you_are() in order to omit ending period) */ Sprintf(buf, " %s%s%s, %son a mission for %s", You_, !final ? are : were, align_str(u.ualign.type), /* helm of opposite alignment (might hide conversion) */ (u.ualign.type != u.ualignbase[A_CURRENT]) ? "temporarily " /* permanent conversion */ : (u.ualign.type != u.ualignbase[A_ORIGINAL]) ? "now " /* atheist (ignored in very early game) */ : (!u.uconduct.gnostic && moves > 1000L) ? "nominally " /* lastly, normal case */ : "", u_gname()); putstr(en_win, 0, buf); /* show the rest of this game's pantheon (finishes previous sentence) [appending "also Moloch" at the end would allow for straightforward trailing "and" on all three aligned entries but looks too verbose] */ Sprintf(buf, " who %s opposed by", !final ? "is" : "was"); if (u.ualign.type != A_LAWFUL) Sprintf(eos(buf), " %s (%s) and", align_gname(A_LAWFUL), align_str(A_LAWFUL)); if (u.ualign.type != A_NEUTRAL) Sprintf(eos(buf), " %s (%s)%s", align_gname(A_NEUTRAL), align_str(A_NEUTRAL), (u.ualign.type != A_CHAOTIC) ? " and" : ""); if (u.ualign.type != A_CHAOTIC) Sprintf(eos(buf), " %s (%s)", align_gname(A_CHAOTIC), align_str(A_CHAOTIC)); Strcat(buf, "."); /* terminate sentence */ putstr(en_win, 0, buf); /* show original alignment,gender,race,role if any have been changed; giving separate message for temporary alignment change bypasses need for tricky phrasing otherwise necessitated by possibility of having helm of opposite alignment mask a permanent alignment conversion */ difgend = (innategend != flags.initgend); difalgn = (((u.ualign.type != u.ualignbase[A_CURRENT]) ? 1 : 0) + ((u.ualignbase[A_CURRENT] != u.ualignbase[A_ORIGINAL]) ? 2 : 0)); if (difalgn & 1) { /* have temporary alignment so report permanent one */ Sprintf(buf, "actually %s", align_str(u.ualignbase[A_CURRENT])); you_are(buf, ""); difalgn &= ~1; /* suppress helm from "started out " message */ } if (difgend || difalgn) { /* sex change or perm align change or both */ Sprintf(buf, " You started out %s%s%s.", difgend ? genders[flags.initgend].adj : "", (difgend && difalgn) ? " and " : "", difalgn ? align_str(u.ualignbase[A_ORIGINAL]) : ""); putstr(en_win, 0, buf); } } /* characteristics: expanded version of bottom line strength, dexterity, &c */ STATIC_OVL void characteristics_enlightenment(mode, final) int mode; int final; { putstr(en_win, 0, ""); /* separator after background */ putstr(en_win, 0, final ? "Final Characteristics:" : "Current Characteristics:"); /* bottom line order */ one_characteristic(mode, final, A_STR); /* strength */ one_characteristic(mode, final, A_DEX); /* dexterity */ one_characteristic(mode, final, A_CON); /* constitution */ one_characteristic(mode, final, A_INT); /* intelligence */ one_characteristic(mode, final, A_WIS); /* wisdom */ one_characteristic(mode, final, A_CHA); /* charisma */ } /* display one attribute value for characteristics_enlightenment() */ STATIC_OVL void one_characteristic(mode, final, attrindx) int mode, final, attrindx; { boolean hide_innate_value = FALSE, interesting_alimit; int acurrent, abase, apeak, alimit; const char *attrname, *paren_pfx; char subjbuf[BUFSZ], valubuf[BUFSZ], valstring[32]; /* being polymorphed or wearing certain cursed items prevents hero from reliably tracking changes to characteristics so we don't show base & peak values then; when the items aren't cursed, hero could take them off to check underlying values and we show those in such case so that player doesn't need to actually resort to doing that */ if (Upolyd) { hide_innate_value = TRUE; } else if (Fixed_abil) { if (stuck_ring(uleft, RIN_SUSTAIN_ABILITY) || stuck_ring(uright, RIN_SUSTAIN_ABILITY)) hide_innate_value = TRUE; } switch (attrindx) { case A_STR: attrname = "strength"; if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER && uarmg->cursed) hide_innate_value = TRUE; break; case A_DEX: attrname = "dexterity"; break; case A_CON: attrname = "constitution"; break; case A_INT: attrname = "intelligence"; if (uarmh && uarmh->otyp == DUNCE_CAP && uarmh->cursed) hide_innate_value = TRUE; break; case A_WIS: attrname = "wisdom"; if (uarmh && uarmh->otyp == DUNCE_CAP && uarmh->cursed) hide_innate_value = TRUE; break; case A_CHA: attrname = "charisma"; break; default: return; /* impossible */ }; /* note: final disclosure includes MAGICENLIGHTENTMENT */ if ((mode & MAGICENLIGHTENMENT) && !Upolyd) hide_innate_value = FALSE; acurrent = ACURR(attrindx); (void) attrval(attrindx, acurrent, valubuf); /* Sprintf(valubuf,"%d",) */ Sprintf(subjbuf, "Your %s ", attrname); if (!hide_innate_value) { /* show abase, amax, and/or attrmax if acurr doesn't match abase (a magic bonus or penalty is in effect) or abase doesn't match amax (some points have been lost to poison or exercise abuse and are restorable) or attrmax is different from normal human (while game is in progress; trying to reduce dependency on spoilers to keep track of such stuff) or attrmax was different from abase (at end of game; this attribute wasn't maxed out) */ abase = ABASE(attrindx); apeak = AMAX(attrindx); alimit = ATTRMAX(attrindx); /* criterium for whether the limit is interesting varies */ interesting_alimit = final ? TRUE /* was originally `(abase != alimit)' */ : (alimit != (attrindx != A_STR ? 18 : STR18(100))); paren_pfx = final ? " (" : " (current; "; if (acurrent != abase) { Sprintf(eos(valubuf), "%sbase:%s", paren_pfx, attrval(attrindx, abase, valstring)); paren_pfx = ", "; } if (abase != apeak) { Sprintf(eos(valubuf), "%speak:%s", paren_pfx, attrval(attrindx, apeak, valstring)); paren_pfx = ", "; } if (interesting_alimit) { Sprintf(eos(valubuf), "%s%slimit:%s", paren_pfx, /* more verbose if exceeding 'limit' due to magic bonus */ (acurrent > alimit) ? "innate " : "", attrval(attrindx, alimit, valstring)); /* paren_pfx = ", "; */ } if (acurrent != abase || abase != apeak || interesting_alimit) Strcat(valubuf, ")"); } enl_msg(subjbuf, "is ", "was ", valubuf, ""); } /* status: selected obvious capabilities, assorted troubles */ STATIC_OVL void status_enlightenment(mode, final) int mode; int final; { boolean magic = (mode & MAGICENLIGHTENMENT) ? TRUE : FALSE; int cap; char buf[BUFSZ], youtoo[BUFSZ]; boolean Riding = (u.usteed /* if hero dies while dismounting, u.usteed will still be set; we want to ignore steed in that situation */ && !(final == ENL_GAMEOVERDEAD && !strcmp(killer.name, "riding accident"))); const char *steedname = (!Riding ? (char *) 0 : x_monnam(u.usteed, u.usteed->mtame ? ARTICLE_YOUR : ARTICLE_THE, (char *) 0, (SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION), FALSE)); /*\ * Status (many are abbreviated on bottom line; others are or * should be discernible to the hero hence to the player) \*/ putstr(en_win, 0, ""); /* separator after title or characteristics */ putstr(en_win, 0, final ? "Final Status:" : "Current Status:"); Strcpy(youtoo, You_); /* not a traditional status but inherently obvious to player; more detail given below (attributes section) for magic enlightenment */ if (Upolyd) you_are("transformed", ""); /* not a trouble, but we want to display riding status before maybe reporting steed as trapped or hero stuck to cursed saddle */ if (Riding) { Sprintf(buf, "riding %s", steedname); you_are(buf, ""); Sprintf(eos(youtoo), "and %s ", steedname); } /* other movement situations that hero should always know */ if (Levitation) { if (Lev_at_will && magic) you_are("levitating, at will", ""); else enl_msg(youtoo, are, were, "levitating", from_what(LEVITATION)); } else if (Flying) { /* can only fly when not levitating */ enl_msg(youtoo, are, were, "flying", from_what(FLYING)); } if (Underwater) { you_are("underwater", ""); } else if (u.uinwater) { you_are(Swimming ? "swimming" : "in water", from_what(SWIMMING)); } else if (walking_on_water()) { /* show active Wwalking here, potential Wwalking elsewhere */ Sprintf(buf, "walking on %s", is_pool(u.ux, u.uy) ? "water" : is_lava(u.ux, u.uy) ? "lava" : surface(u.ux, u.uy)); /* catchall; shouldn't happen */ you_are(buf, from_what(WWALKING)); } if (Upolyd && (u.uundetected || youmonst.m_ap_type != M_AP_NOTHING)) youhiding(TRUE, final); /* internal troubles, mostly in the order that prayer ranks them */ if (Stoned) you_are("turning to stone", ""); if (Slimed) you_are("turning into slime", ""); if (Strangled) { if (u.uburied) { you_are("buried", ""); } else { Strcpy(buf, "being strangled"); if (wizard) Sprintf(eos(buf), " (%ld)", (Strangled & TIMEOUT)); you_are(buf, from_what(STRANGLED)); } } if (Sick) { /* prayer lumps these together; botl puts Ill before FoodPois */ if (u.usick_type & SICK_NONVOMITABLE) you_are("terminally sick from illness", ""); if (u.usick_type & SICK_VOMITABLE) you_are("terminally sick from food poisoning", ""); } if (Vomiting) you_are("nauseated", ""); if (Stunned) you_are("stunned", ""); if (Confusion) you_are("confused", ""); if (Hallucination) you_are("hallucinating", ""); if (Blind) { /* from_what() (currently wizard-mode only) checks !haseyes() before u.uroleplay.blind, so we should too */ Sprintf(buf, "%s blind", !haseyes(youmonst.data) ? "innately" : u.uroleplay.blind ? "permanently" /* better phrasing desperately wanted... */ : Blindfolded_only ? "deliberately" : "temporarily"); if (wizard && (Blinded & TIMEOUT) != 0L && !u.uroleplay.blind && haseyes(youmonst.data)) Sprintf(eos(buf), " (%ld)", (Blinded & TIMEOUT)); /* !haseyes: avoid "you are innately blind innately" */ you_are(buf, !haseyes(youmonst.data) ? "" : from_what(BLINDED)); } if (Deaf) you_are("deaf", from_what(DEAF)); /* external troubles, more or less */ if (Punished) { if (uball) { Sprintf(buf, "chained to %s", ansimpleoname(uball)); } else { impossible("Punished without uball?"); Strcpy(buf, "punished"); } you_are(buf, ""); } if (u.utrap) { char predicament[BUFSZ]; struct trap *t; boolean anchored = (u.utraptype == TT_BURIEDBALL); if (anchored) { Strcpy(predicament, "tethered to something buried"); } else if (u.utraptype == TT_INFLOOR || u.utraptype == TT_LAVA) { Sprintf(predicament, "stuck in %s", the(surface(u.ux, u.uy))); } else { Strcpy(predicament, "trapped"); if ((t = t_at(u.ux, u.uy)) != 0) Sprintf(eos(predicament), " in %s", an(defsyms[trap_to_defsym(t->ttyp)].explanation)); } if (u.usteed) { /* not `Riding' here */ Sprintf(buf, "%s%s ", anchored ? "you and " : "", steedname); *buf = highc(*buf); enl_msg(buf, (anchored ? "are " : "is "), (anchored ? "were " : "was "), predicament, ""); } else you_are(predicament, ""); } /* (u.utrap) */ if (u.uswallow) { Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck)); if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim); you_are(buf, ""); } else if (u.ustuck) { Sprintf(buf, "%s %s", (Upolyd && sticks(youmonst.data)) ? "holding" : "held by", a_monnam(u.ustuck)); you_are(buf, ""); } if (Riding) { struct obj *saddle = which_armor(u.usteed, W_SADDLE); if (saddle && saddle->cursed) { Sprintf(buf, "stuck to %s %s", s_suffix(steedname), simpleonames(saddle)); you_are(buf, ""); } } if (Wounded_legs) { /* when mounted, Wounded_legs applies to steed rather than to hero; we only report steed's wounded legs in wizard mode */ if (u.usteed) { /* not `Riding' here */ if (wizard && steedname) { Strcpy(buf, steedname); *buf = highc(*buf); enl_msg(buf, " has", " had", " wounded legs", ""); } } else { Sprintf(buf, "wounded %s", makeplural(body_part(LEG))); you_have(buf, ""); } } if (Glib) { Sprintf(buf, "slippery %s", makeplural(body_part(FINGER))); you_have(buf, ""); } if (Fumbling) { if (magic || cause_known(FUMBLING)) enl_msg(You_, "fumble", "fumbled", "", from_what(FUMBLING)); } if (Sleepy) { if (magic || cause_known(SLEEPY)) { Strcpy(buf, from_what(SLEEPY)); if (wizard) Sprintf(eos(buf), " (%ld)", (HSleepy & TIMEOUT)); enl_msg("You ", "fall", "fell", " asleep uncontrollably", buf); } } /* hunger/nutrition */ if (Hunger) { if (magic || cause_known(HUNGER)) enl_msg(You_, "hunger", "hungered", " rapidly", from_what(HUNGER)); } Strcpy(buf, hu_stat[u.uhs]); /* hunger status; omitted if "normal" */ mungspaces(buf); /* strip trailing spaces */ if (*buf) { *buf = lowc(*buf); /* override capitalization */ if (!strcmp(buf, "weak")) Strcat(buf, " from severe hunger"); else if (!strncmp(buf, "faint", 5)) /* fainting, fainted */ Strcat(buf, " due to starvation"); you_are(buf, ""); } /* encumbrance */ if ((cap = near_capacity()) > UNENCUMBERED) { const char *adj = "?_?"; /* (should always get overridden) */ Strcpy(buf, enc_stat[cap]); *buf = lowc(*buf); switch (cap) { case SLT_ENCUMBER: adj = "slightly"; break; /* burdened */ case MOD_ENCUMBER: adj = "moderately"; break; /* stressed */ case HVY_ENCUMBER: adj = "very"; break; /* strained */ case EXT_ENCUMBER: adj = "extremely"; break; /* overtaxed */ case OVERLOADED: adj = "not possible"; break; } Sprintf(eos(buf), "; movement %s %s%s", !final ? "is" : "was", adj, (cap < OVERLOADED) ? " slowed" : ""); you_are(buf, ""); } else { /* last resort entry, guarantees Status section is non-empty (no longer needed for that purpose since weapon status added; still useful though) */ you_are("unencumbered", ""); } /* report being weaponless; distinguish whether gloves are worn */ if (!uwep) { you_are(uarmg ? "empty handed" /* gloves imply hands */ : humanoid(youmonst.data) /* hands but no weapon and no gloves */ ? "bare handed" /* alternate phrasing for paws or lack of hands */ : "not wielding anything", ""); /* two-weaponing implies a weapon (not other odd stuff) in each hand */ } else if (u.twoweap) { you_are("wielding two weapons at once", ""); /* report most weapons by their skill class (so a katana will be described as a long sword, for instance; mattock and hook are exceptions), or wielded non-weapon item by its object class */ } else { const char *what = weapon_descr(uwep); if (!strcmpi(what, "armor") || !strcmpi(what, "food") || !strcmpi(what, "venom")) Sprintf(buf, "wielding some %s", what); else Sprintf(buf, "wielding %s", (uwep->quan == 1L) ? an(what) : makeplural(what)); you_are(buf, ""); } /* report 'nudity' */ if (!uarm && !uarmu && !uarmc && !uarmg && !uarmf && !uarmh) { if (u.uroleplay.nudist) enl_msg(You_, "do", "did", " not wear any armor", ""); else you_are("not wearing any armor", ""); } } /* attributes: intrinsics and the like, other non-obvious capabilities */ void attributes_enlightenment(unused_mode, final) int unused_mode UNUSED; int final; { static NEARDATA const char if_surroundings_permitted[] = " if surroundings permitted"; int ltmp, armpro; char buf[BUFSZ]; /*\ * Attributes \*/ putstr(en_win, 0, ""); putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:"); if (u.uevent.uhand_of_elbereth) { static const char *const hofe_titles[3] = { "the Hand of Elbereth", "the Envoy of Balance", "the Glory of Arioch" }; you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1], ""); } /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */ if (u.ualign.record >= 20) you_are("piously aligned", ""); else if (u.ualign.record > 13) you_are("devoutly aligned", ""); else if (u.ualign.record > 8) you_are("fervently aligned", ""); else if (u.ualign.record > 3) you_are("stridently aligned", ""); else if (u.ualign.record == 3) you_are("aligned", ""); else if (u.ualign.record > 0) you_are("haltingly aligned", ""); else if (u.ualign.record == 0) you_are("nominally aligned", ""); else if (u.ualign.record >= -3) you_have("strayed", ""); else if (u.ualign.record >= -8) you_have("sinned", ""); else you_have("transgressed", ""); if (wizard) { Sprintf(buf, " %d", u.ualign.record); enl_msg("Your alignment ", "is", "was", buf, ""); } /*** Resistances to troubles ***/ if (Invulnerable) you_are("invulnerable", from_what(INVULNERABLE)); if (Antimagic) you_are("magic-protected", from_what(ANTIMAGIC)); if (Fire_resistance) you_are("fire resistant", from_what(FIRE_RES)); if (Cold_resistance) you_are("cold resistant", from_what(COLD_RES)); if (Sleep_resistance) you_are("sleep resistant", from_what(SLEEP_RES)); if (Disint_resistance) you_are("disintegration-resistant", from_what(DISINT_RES)); if (Shock_resistance) you_are("shock resistant", from_what(SHOCK_RES)); if (Poison_resistance) you_are("poison resistant", from_what(POISON_RES)); if (Acid_resistance) you_are("acid resistant", from_what(ACID_RES)); if (Drain_resistance) you_are("level-drain resistant", from_what(DRAIN_RES)); if (Sick_resistance) you_are("immune to sickness", from_what(SICK_RES)); if (Stone_resistance) you_are("petrification resistant", from_what(STONE_RES)); if (Halluc_resistance) enl_msg(You_, "resist", "resisted", " hallucinations", from_what(HALLUC_RES)); if (u.uedibility) you_can("recognize detrimental food", ""); /*** Vision and senses ***/ if (!Blind && (Blinded || !haseyes(youmonst.data))) you_can("see", from_what(-BLINDED)); /* Eyes of the Overworld */ if (See_invisible) { if (!Blind) enl_msg(You_, "see", "saw", " invisible", from_what(SEE_INVIS)); else enl_msg(You_, "will see", "would have seen", " invisible when not blind", from_what(SEE_INVIS)); } if (Blind_telepat) you_are("telepathic", from_what(TELEPAT)); if (Warning) you_are("warned", from_what(WARNING)); if (Warn_of_mon && context.warntype.obj) { Sprintf(buf, "aware of the presence of %s", (context.warntype.obj & M2_ORC) ? "orcs" : (context.warntype.obj & M2_ELF) ? "elves" : (context.warntype.obj & M2_DEMON) ? "demons" : something); you_are(buf, from_what(WARN_OF_MON)); } if (Warn_of_mon && context.warntype.polyd) { Sprintf(buf, "aware of the presence of %s", ((context.warntype.polyd & (M2_HUMAN | M2_ELF)) == (M2_HUMAN | M2_ELF)) ? "humans and elves" : (context.warntype.polyd & M2_HUMAN) ? "humans" : (context.warntype.polyd & M2_ELF) ? "elves" : (context.warntype.polyd & M2_ORC) ? "orcs" : (context.warntype.polyd & M2_DEMON) ? "demons" : "certain monsters"); you_are(buf, ""); } if (Warn_of_mon && context.warntype.speciesidx) { Sprintf(buf, "aware of the presence of %s", makeplural(mons[context.warntype.speciesidx].mname)); you_are(buf, from_what(WARN_OF_MON)); } if (Undead_warning) you_are("warned of undead", from_what(WARN_UNDEAD)); if (Searching) you_have("automatic searching", from_what(SEARCHING)); if (Clairvoyant) you_are("clairvoyant", from_what(CLAIRVOYANT)); else if ((HClairvoyant || EClairvoyant) && BClairvoyant) { Strcpy(buf, from_what(-CLAIRVOYANT)); if (!strncmp(buf, " because of ", 12)) /* overwrite substring; strncpy doesn't add terminator */ (void) strncpy(buf, " if not for ", 12); enl_msg(You_, "could be", "could have been", " clairvoyant", buf); } if (Infravision) you_have("infravision", from_what(INFRAVISION)); if (Detect_monsters) you_are("sensing the presence of monsters", ""); if (u.umconf) you_are("going to confuse monsters", ""); /*** Appearance and behavior ***/ if (Adornment) { int adorn = 0; if (uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe; if (uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe; /* the sum might be 0 (+0 ring or two which negate each other); that yields "you are charismatic" (which isn't pointless because it potentially impacts seduction attacks) */ Sprintf(buf, "%scharismatic", (adorn > 0) ? "more " : (adorn < 0) ? "less " : ""); you_are(buf, from_what(ADORNED)); } if (Invisible) you_are("invisible", from_what(INVIS)); else if (Invis) you_are("invisible to others", from_what(INVIS)); /* ordinarily "visible" is redundant; this is a special case for the situation when invisibility would be an expected attribute */ else if ((HInvis || EInvis) && BInvis) you_are("visible", from_what(-INVIS)); if (Displaced) you_are("displaced", from_what(DISPLACED)); if (Stealth) you_are("stealthy", from_what(STEALTH)); if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters", from_what(AGGRAVATE_MONSTER)); if (Conflict) enl_msg("You cause", "", "d", " conflict", from_what(CONFLICT)); /*** Transportation ***/ if (Jumping) you_can("jump", from_what(JUMPING)); if (Teleportation) you_can("teleport", from_what(TELEPORT)); if (Teleport_control) you_have("teleport control", from_what(TELEPORT_CONTROL)); /* actively levitating handled earlier as a status condition */ if (BLevitation) { /* levitation is blocked */ long save_BLev = BLevitation; BLevitation = 0L; if (Levitation) enl_msg(You_, "would levitate", "would have levitated", if_surroundings_permitted, ""); BLevitation = save_BLev; } /* actively flying handled earlier as a status condition */ if (BFlying) { /* flight is blocked */ long save_BFly = BFlying; BFlying = 0L; if (Flying) enl_msg(You_, "would fly", "would have flown", Levitation ? "if you weren't levitating" : (save_BFly == FROMOUTSIDE) ? if_surroundings_permitted /* both surroundings and [latent] levitation */ : " if circumstances permitted", ""); BFlying = save_BFly; } /* actively walking on water handled earlier as a status condition */ if (Wwalking && !walking_on_water()) you_can("walk on water", from_what(WWALKING)); /* actively swimming (in water but not under it) handled earlier */ if (Swimming && (Underwater || !u.uinwater)) you_can("swim", from_what(SWIMMING)); if (Breathless) you_can("survive without air", from_what(MAGICAL_BREATHING)); else if (Amphibious) you_can("breathe water", from_what(MAGICAL_BREATHING)); if (Passes_walls) you_can("walk through walls", from_what(PASSES_WALLS)); /*** Physical attributes ***/ if (Regeneration) enl_msg("You regenerate", "", "d", "", from_what(REGENERATION)); if (Slow_digestion) you_have("slower digestion", from_what(SLOW_DIGESTION)); if (u.uhitinc) you_have(enlght_combatinc("to hit", u.uhitinc, final, buf), ""); if (u.udaminc) you_have(enlght_combatinc("damage", u.udaminc, final, buf), ""); if (u.uspellprot || Protection) { int prot = 0; if (uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe; if (uright && uright->otyp == RIN_PROTECTION) prot += uright->spe; if (HProtection & INTRINSIC) prot += u.ublessed; prot += u.uspellprot; if (prot) you_have(enlght_combatinc("defense", prot, final, buf), ""); } if ((armpro = magic_negation(&youmonst)) > 0) { /* magic cancellation factor, conferred by worn armor */ static const char *const mc_types[] = { "" /*ordinary*/, "warded", "guarded", "protected", }; /* sanity check */ if (armpro >= SIZE(mc_types)) armpro = SIZE(mc_types) - 1; you_are(mc_types[armpro], ""); } if (Half_physical_damage) enlght_halfdmg(HALF_PHDAM, final); if (Half_spell_damage) enlght_halfdmg(HALF_SPDAM, final); /* polymorph and other shape change */ if (Protection_from_shape_changers) you_are("protected from shape changers", from_what(PROT_FROM_SHAPE_CHANGERS)); if (Unchanging) { const char *what = 0; if (!Upolyd) /* Upolyd handled below after current form */ you_can("not change from your current form", from_what(UNCHANGING)); /* blocked shape changes */ if (Polymorph) what = !final ? "polymorph" : "have polymorphed"; else if (u.ulycn >= LOW_PM) what = !final ? "change shape" : "have changed shape"; if (what) { Sprintf(buf, "would %s periodically", what); /* omit from_what(UNCHANGING); too verbose */ enl_msg(You_, buf, buf, " if not locked into your current form", ""); } } else if (Polymorph) { you_are("polymorphing periodically", from_what(POLYMORPH)); } if (Polymorph_control) you_have("polymorph control", from_what(POLYMORPH_CONTROL)); if (Upolyd && u.umonnum != u.ulycn) { /* foreign shape (except were-form which is handled below) */ Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname)); if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone); you_are(buf, ""); } if (lays_eggs(youmonst.data) && flags.female) /* Upolyd */ you_can("lay eggs", ""); if (u.ulycn >= LOW_PM) { /* "you are a werecreature [in beast form]" */ Strcpy(buf, an(mons[u.ulycn].mname)); if (u.umonnum == u.ulycn) { Strcat(buf, " in beast form"); if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone); } you_are(buf, ""); } if (Unchanging && Upolyd) /* !Upolyd handled above */ you_can("not change from your current form", from_what(UNCHANGING)); if (Hate_silver) you_are("harmed by silver", ""); /* movement and non-armor-based protection */ if (Fast) you_are(Very_fast ? "very fast" : "fast", from_what(FAST)); if (Reflecting) you_have("reflection", from_what(REFLECTING)); if (Free_action) you_have("free action", from_what(FREE_ACTION)); if (Fixed_abil) you_have("fixed abilities", from_what(FIXED_ABIL)); if (Lifesaved) enl_msg("Your life ", "will be", "would have been", " saved", ""); /*** Miscellany ***/ if (Luck) { ltmp = abs((int) Luck); Sprintf(buf, "%s%slucky", ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "", Luck < 0 ? "un" : ""); if (wizard) Sprintf(eos(buf), " (%d)", Luck); you_are(buf, ""); } else if (wizard) enl_msg("Your luck ", "is", "was", " zero", ""); if (u.moreluck > 0) you_have("extra luck", ""); else if (u.moreluck < 0) you_have("reduced luck", ""); if (carrying(LUCKSTONE) || stone_luck(TRUE)) { ltmp = stone_luck(0); if (ltmp <= 0) enl_msg("Bad luck ", "does", "did", " not time out for you", ""); if (ltmp >= 0) enl_msg("Good luck ", "does", "did", " not time out for you", ""); } if (u.ugangr) { Sprintf(buf, " %sangry with you", u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : ""); if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr); enl_msg(u_gname(), " is", " was", buf, ""); } else { /* * We need to suppress this when the game is over, because death * can change the value calculated by can_pray(), potentially * resulting in a false claim that you could have prayed safely. */ if (!final) { #if 0 /* "can [not] safely pray" vs "could [not] have safely prayed" */ Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ", final ? "have " : "", final ? "ed" : ""); #else Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not "); #endif if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt); you_can(buf, ""); } } /* named fruit debugging (doesn't really belong here...) */ if (wizard) { int fcount = 0; struct fruit *f; char buf2[BUFSZ]; for (f = ffruit; f; f = f->nextf) { Sprintf(buf, "Fruit %d ", ++fcount); Sprintf(buf2, "%s (id %d)", f->fname, f->fid); enl_msg(buf, "is ", "was ", buf2, ""); } enl_msg("The current fruit ", "is ", "was ", pl_fruit, ""); Sprintf(buf, "%d", flags.made_fruit); enl_msg("The made fruit flag ", "is ", "was ", buf, ""); } { const char *p; buf[0] = '\0'; if (final < 2) { /* still in progress, or quit/escaped/ascended */ p = "survived after being killed "; switch (u.umortality) { case 0: p = !final ? (char *) 0 : "survived"; break; case 1: Strcpy(buf, "once"); break; case 2: Strcpy(buf, "twice"); break; case 3: Strcpy(buf, "thrice"); break; default: Sprintf(buf, "%d times", u.umortality); break; } } else { /* game ended in character's death */ p = "are dead"; switch (u.umortality) { case 0: impossible("dead without dying?"); case 1: break; /* just "are dead" */ default: Sprintf(buf, " (%d%s time!)", u.umortality, ordin(u.umortality)); break; } } if (p) enl_msg(You_, "have been killed ", p, buf, ""); } } #if 0 /* no longer used */ STATIC_DCL boolean NDECL(minimal_enlightenment); /* * Courtesy function for non-debug, non-explorer mode players * to help refresh them about who/what they are. * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise. */ STATIC_OVL boolean minimal_enlightenment() { winid tmpwin; menu_item *selected; anything any; int genidx, n; char buf[BUFSZ], buf2[BUFSZ]; static const char untabbed_fmtstr[] = "%-15s: %-12s"; static const char untabbed_deity_fmtstr[] = "%-17s%s"; static const char tabbed_fmtstr[] = "%s:\t%-12s"; static const char tabbed_deity_fmtstr[] = "%s\t%s"; static const char *fmtstr; static const char *deity_fmtstr; fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr; deity_fmtstr = iflags.menu_tab_sep ? tabbed_deity_fmtstr : untabbed_deity_fmtstr; any = zeroany; buf[0] = buf2[0] = '\0'; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Starting", FALSE); /* Starting name, race, role, gender */ Sprintf(buf, fmtstr, "name", plname); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "race", urace.noun); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "role", (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Starting alignment */ Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL])); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Current name, race, role, gender */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Current", FALSE); Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); if (Upolyd) { Sprintf(buf, fmtstr, "role (base)", (u.mfemale && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } else { Sprintf(buf, fmtstr, "role", (flags.female && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } /* don't want poly_gender() here; it forces `2' for non-humanoids */ genidx = is_neuter(youmonst.data) ? 2 : flags.female; Sprintf(buf, fmtstr, "gender", genders[genidx].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); if (Upolyd && (int) u.mfemale != genidx) { Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } /* Current alignment */ Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Deity list */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Deities", FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_CHAOTIC) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" : (u.ualign.type == A_CHAOTIC) ? " (c)" : ""); Sprintf(buf, fmtstr, "Chaotic", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_NEUTRAL) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" : (u.ualign.type == A_NEUTRAL) ? " (c)" : ""); Sprintf(buf, fmtstr, "Neutral", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" : (u.ualign.type == A_LAWFUL) ? " (c)" : ""); Sprintf(buf, fmtstr, "Lawful", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); end_menu(tmpwin, "Base Attributes"); n = select_menu(tmpwin, PICK_NONE, &selected); destroy_nhwindow(tmpwin); return (boolean) (n != -1); } #endif /*0*/ /* ^X command */ STATIC_PTR int doattributes(VOID_ARGS) { int mode = BASICENLIGHTENMENT; /* show more--as if final disclosure--for wizard and explore modes */ if (wizard || discover) mode |= MAGICENLIGHTENMENT; enlightenment(mode, ENL_GAMEINPROGRESS); return 0; } void youhiding(via_enlghtmt, msgflag) boolean via_enlghtmt; /* englightment line vs topl message */ int msgflag; /* for variant message phrasing */ { char *bp, buf[BUFSZ]; Strcpy(buf, "hiding"); if (youmonst.m_ap_type != M_AP_NOTHING) { /* mimic; hero is only able to mimic a strange object or gold or hallucinatory alternative to gold, so we skip the details for the hypothetical furniture and monster cases */ bp = eos(strcpy(buf, "mimicking")); if (youmonst.m_ap_type == M_AP_OBJECT) { Sprintf(bp, " %s", an(simple_typename(youmonst.mappearance))); } else if (youmonst.m_ap_type == M_AP_FURNITURE) { Strcpy(bp, " something"); } else if (youmonst.m_ap_type == M_AP_MONSTER) { Strcpy(bp, " someone"); } else { ; /* something unexpected; leave 'buf' as-is */ } } else if (u.uundetected) { bp = eos(buf); /* points past "hiding" */ if (youmonst.data->mlet == S_EEL) { if (is_pool(u.ux, u.uy)) Sprintf(bp, " in the %s", waterbody_name(u.ux, u.uy)); } else if (hides_under(youmonst.data)) { struct obj *o = level.objects[u.ux][u.uy]; if (o) Sprintf(bp, " underneath %s", ansimpleoname(o)); } else if (is_clinger(youmonst.data) || Flying) { /* Flying: 'lurker above' hides on ceiling but doesn't cling */ Sprintf(bp, " on the %s", ceiling(u.ux, u.uy)); } else { /* on floor; is_hider() but otherwise not special: 'trapper' */ if (u.utrap && u.utraptype == TT_PIT) { struct trap *t = t_at(u.ux, u.uy); Sprintf(bp, " in a %spit", (t && t->ttyp == SPIKED_PIT) ? "spiked " : ""); } else Sprintf(bp, " on the %s", surface(u.ux, u.uy)); } } else { ; /* shouldn't happen; will result in generic "you are hiding" */ } if (via_enlghtmt) { int final = msgflag; /* 'final' is used by you_are() macro */ you_are(buf, ""); } else { /* for dohide(), when player uses '#monster' command */ You("are %s %s.", msgflag ? "already" : "now", buf); } } /* KMH, #conduct * (shares enlightenment's tense handling) */ STATIC_PTR int doconduct(VOID_ARGS) { show_conduct(0); return 0; } void show_conduct(final) int final; { char buf[BUFSZ]; int ngenocided; /* Create the conduct window */ en_win = create_nhwindow(NHW_MENU); putstr(en_win, 0, "Voluntary challenges:"); if (u.uroleplay.blind) you_have_been("blind from birth"); if (u.uroleplay.nudist) you_have_been("faithfully nudist"); if (!u.uconduct.food) enl_msg(You_, "have gone", "went", " without food", ""); /* But beverages are okay */ else if (!u.uconduct.unvegan) you_have_X("followed a strict vegan diet"); else if (!u.uconduct.unvegetarian) you_have_been("vegetarian"); if (!u.uconduct.gnostic) you_have_been("an atheist"); if (!u.uconduct.weaphit) { you_have_never("hit with a wielded weapon"); } else if (wizard) { Sprintf(buf, "used a wielded weapon %ld time%s", u.uconduct.weaphit, plur(u.uconduct.weaphit)); you_have_X(buf); } if (!u.uconduct.killer) you_have_been("a pacifist"); if (!u.uconduct.literate) { you_have_been("illiterate"); } else if (wizard) { Sprintf(buf, "read items or engraved %ld time%s", u.uconduct.literate, plur(u.uconduct.literate)); you_have_X(buf); } ngenocided = num_genocides(); if (ngenocided == 0) { you_have_never("genocided any monsters"); } else { Sprintf(buf, "genocided %d type%s of monster%s", ngenocided, plur(ngenocided), plur(ngenocided)); you_have_X(buf); } if (!u.uconduct.polypiles) { you_have_never("polymorphed an object"); } else if (wizard) { Sprintf(buf, "polymorphed %ld item%s", u.uconduct.polypiles, plur(u.uconduct.polypiles)); you_have_X(buf); } if (!u.uconduct.polyselfs) { you_have_never("changed form"); } else if (wizard) { Sprintf(buf, "changed form %ld time%s", u.uconduct.polyselfs, plur(u.uconduct.polyselfs)); you_have_X(buf); } if (!u.uconduct.wishes) { you_have_X("used no wishes"); } else { Sprintf(buf, "used %ld wish%s", u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : ""); you_have_X(buf); if (!u.uconduct.wisharti) enl_msg(You_, "have not wished", "did not wish", " for any artifacts", ""); } /* Pop up the window and wait for a key */ display_nhwindow(en_win, TRUE); destroy_nhwindow(en_win); en_win = WIN_ERR; } #ifndef M #ifndef NHSTDC #define M(c) (0x80 | (c)) #else #define M(c) ((c) -128) #endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif static const struct func_tab cmdlist[] = { { C('d'), FALSE, dokick }, /* "D" is for door!...? Msg is in dokick.c */ { C('e'), TRUE, wiz_detect }, { C('f'), TRUE, wiz_map }, { C('g'), TRUE, wiz_genesis }, { C('i'), TRUE, wiz_identify }, { C('l'), TRUE, doredraw }, /* if number_pad is set */ { C('n'), TRUE, donamelevel }, /* if number_pad is set */ { C('o'), TRUE, dooverview_or_wiz_where }, /* depends on wizard status */ { C('p'), TRUE, doprev_message }, { C('r'), TRUE, doredraw }, { C('t'), TRUE, dotele }, { C('v'), TRUE, wiz_level_tele }, { C('w'), TRUE, wiz_wish }, { C('x'), TRUE, doattributes }, { C('z'), TRUE, dosuspend_core }, { 'a', FALSE, doapply }, { 'A', FALSE, doddoremarm }, { M('a'), TRUE, doorganize }, { M('A'), TRUE, donamelevel }, /* #annotate */ /* 'b', 'B' : go sw */ { 'c', FALSE, doclose }, { 'C', TRUE, docallcmd }, { M('c'), TRUE, dotalk }, { M('C'), TRUE, doconduct }, /* #conduct */ { 'd', FALSE, dodrop }, { 'D', FALSE, doddrop }, { M('d'), FALSE, dodip }, { 'e', FALSE, doeat }, { 'E', FALSE, doengrave }, { M('e'), TRUE, enhance_weapon_skill }, { 'f', FALSE, dofire }, /* 'F' : fight (one time) */ { M('f'), FALSE, doforce }, /* 'g', 'G' : multiple go */ /* 'h', 'H' : go west */ { 'h', TRUE, dohelp }, /* if number_pad is set */ { 'i', TRUE, ddoinv }, { 'I', TRUE, dotypeinv }, /* Robert Viduya */ { M('i'), TRUE, doinvoke }, /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */ { 'j', FALSE, dojump }, /* if number_pad is on */ { M('j'), FALSE, dojump }, { 'k', FALSE, dokick }, /* if number_pad is on */ { 'l', FALSE, doloot }, /* if number_pad is on */ { M('l'), FALSE, doloot }, /* 'n' prefixes a count if number_pad is on */ { M('m'), TRUE, domonability }, { 'N', TRUE, docallcmd }, /* if number_pad is on */ { M('n'), TRUE, docallcmd }, { M('N'), TRUE, docallcmd }, { 'o', FALSE, doopen }, { 'O', TRUE, doset }, { M('o'), FALSE, dosacrifice }, { M('O'), TRUE, dooverview }, /* #overview */ { 'p', FALSE, dopay }, { 'P', FALSE, doputon }, { M('p'), TRUE, dopray }, { 'q', FALSE, dodrink }, { 'Q', FALSE, dowieldquiver }, { M('q'), TRUE, done2 }, { 'r', FALSE, doread }, { 'R', FALSE, doremring }, { M('r'), FALSE, dorub }, { M('R'), FALSE, doride }, /* #ride */ { 's', TRUE, dosearch, "searching" }, { 'S', TRUE, dosave }, { M('s'), FALSE, dosit }, { 't', FALSE, dothrow }, { 'T', FALSE, dotakeoff }, { M('t'), TRUE, doturn }, { M('T'), FALSE, dotip }, /* #tip */ /* 'u', 'U' : go ne */ { 'u', FALSE, dountrap }, /* if number_pad is on */ { M('u'), FALSE, dountrap }, { 'v', TRUE, doversion }, { 'V', TRUE, dohistory }, { M('v'), TRUE, doextversion }, { 'w', FALSE, dowield }, { 'W', FALSE, dowear }, { M('w'), FALSE, dowipe }, { 'x', FALSE, doswapweapon }, { 'X', FALSE, dotwoweapon }, /* 'y', 'Y' : go nw */ { 'z', FALSE, dozap }, { 'Z', TRUE, docast }, { '<', FALSE, doup }, { '>', FALSE, dodown }, { '/', TRUE, dowhatis }, { '&', TRUE, dowhatdoes }, { '?', TRUE, dohelp }, { M('?'), TRUE, doextlist }, #ifdef SHELL { '!', TRUE, dosh }, #endif { '.', TRUE, donull, "waiting" }, { ' ', TRUE, donull, "waiting" }, { ',', FALSE, dopickup }, { ':', TRUE, dolook }, { ';', TRUE, doquickwhatis }, { '^', TRUE, doidtrap }, { '\\', TRUE, dodiscovered }, /* Robert Viduya */ { '`', TRUE, doclassdisco }, { '@', TRUE, dotogglepickup }, { M('2'), FALSE, dotwoweapon }, { WEAPON_SYM, TRUE, doprwep }, { ARMOR_SYM, TRUE, doprarm }, { RING_SYM, TRUE, doprring }, { AMULET_SYM, TRUE, dopramulet }, { TOOL_SYM, TRUE, doprtool }, { '*', TRUE, doprinuse }, /* inventory of all equipment in use */ { GOLD_SYM, TRUE, doprgold }, { SPBOOK_SYM, TRUE, dovspell }, /* Mike Stephenson */ { '#', TRUE, doextcmd }, { '_', TRUE, dotravel }, { 0, 0, 0, 0 } }; struct ext_func_tab extcmdlist[] = { { "adjust", "adjust inventory letters", doorganize, TRUE }, { "annotate", "name current level", donamelevel, TRUE }, { "chat", "talk to someone", dotalk, TRUE }, /* converse? */ { "conduct", "list voluntary challenges you have maintained", doconduct, TRUE }, { "dip", "dip an object into something", dodip, FALSE }, { "enhance", "advance or check weapon and spell skills", enhance_weapon_skill, TRUE }, { "exploremode", "enter explore mode", enter_explore_mode, TRUE }, { "force", "force a lock", doforce, FALSE }, { "invoke", "invoke an object's powers", doinvoke, TRUE }, { "jump", "jump to a location", dojump, FALSE }, { "loot", "loot a box on the floor", doloot, FALSE }, { "monster", "use a monster's special ability", domonability, TRUE }, { "name", "name a monster or an object", docallcmd, TRUE }, { "offer", "offer a sacrifice to the gods", dosacrifice, FALSE }, { "overview", "show an overview of the dungeon", dooverview, TRUE }, { "pray", "pray to the gods for help", dopray, TRUE }, { "quit", "exit without saving current game", done2, TRUE }, { "ride", "ride (or stop riding) a monster", doride, FALSE }, { "rub", "rub a lamp or a stone", dorub, FALSE }, { "sit", "sit down", dosit, FALSE }, { "terrain", "show map without obstructions", doterrain, TRUE }, { "tip", "empty a container", dotip, FALSE }, { "turn", "turn undead", doturn, TRUE }, { "twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE }, { "untrap", "untrap something", dountrap, FALSE }, { "version", "list compile time options for this version of NetHack", doextversion, TRUE }, { "wipe", "wipe off your face", dowipe, FALSE }, { "?", "get this list of extended commands", doextlist, TRUE }, /* * There must be a blank entry here for every entry in the table * below. */ { (char *) 0, (char *) 0, donull, TRUE }, /* levelchange */ { (char *) 0, (char *) 0, donull, TRUE }, /* lightsources */ #ifdef DEBUG_MIGRATING_MONS { (char *) 0, (char *) 0, donull, TRUE }, /* migratemons */ #endif { (char *) 0, (char *) 0, donull, TRUE }, /* monpolycontrol */ { (char *) 0, (char *) 0, donull, TRUE }, /* panic */ { (char *) 0, (char *) 0, donull, TRUE }, /* polyself */ #ifdef PORT_DEBUG { (char *) 0, (char *) 0, donull, TRUE }, /* portdebug */ #endif { (char *) 0, (char *) 0, donull, TRUE }, /* seenv */ { (char *) 0, (char *) 0, donull, TRUE }, /* stats */ { (char *) 0, (char *) 0, donull, TRUE }, /* timeout */ { (char *) 0, (char *) 0, donull, TRUE }, /* vanquished */ { (char *) 0, (char *) 0, donull, TRUE }, /* vision */ { (char *) 0, (char *) 0, donull, TRUE }, /* wizsmell */ #ifdef DEBUG { (char *) 0, (char *) 0, donull, TRUE }, /* wizdebug_traveldisplay */ { (char *) 0, (char *) 0, donull, TRUE }, /* wizdebug_bury */ #endif { (char *) 0, (char *) 0, donull, TRUE }, /* wizrumorcheck */ { (char *) 0, (char *) 0, donull, TRUE }, /* wmode */ { (char *) 0, (char *) 0, donull, TRUE } /* sentinel */ }; /* there must be a placeholder in the table above for every entry here */ static const struct ext_func_tab debug_extcmdlist[] = { { "levelchange", "change experience level", wiz_level_change, TRUE }, { "lightsources", "show mobile light sources", wiz_light_sources, TRUE }, #ifdef DEBUG_MIGRATING_MONS { "migratemons", "migrate n random monsters", wiz_migrate_mons, TRUE }, #endif { "monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE }, { "panic", "test panic routine (fatal to game)", wiz_panic, TRUE }, { "polyself", "polymorph self", wiz_polyself, TRUE }, #ifdef PORT_DEBUG { "portdebug", "wizard port debug command", wiz_port_debug, TRUE }, #endif { "seenv", "show seen vectors", wiz_show_seenv, TRUE }, { "stats", "show memory statistics", wiz_show_stats, TRUE }, { "timeout", "look at timeout queue", wiz_timeout_queue, TRUE }, { "vanquished", "list vanquished monsters", dovanquished, TRUE }, { "vision", "show vision array", wiz_show_vision, TRUE }, { "wizsmell", "smell monster", wiz_smell, TRUE }, #ifdef DEBUG { "wizdebug_traveldisplay", "wizard debug: toggle travel display", wiz_debug_cmd_traveldisplay, TRUE }, { "wizdebug_bury", "wizard debug: bury objs under and around you", wiz_debug_cmd_bury, TRUE }, #endif { "wizrumorcheck", "verify rumor boundaries", wiz_rumor_check, TRUE }, { "wmode", "show wall modes", wiz_show_wmodes, TRUE }, { (char *) 0, (char *) 0, donull, TRUE } }; /* * Insert debug commands into the extended command list. This function * assumes that the last entry will be the help entry. * * You must add entries in ext_func_tab every time you add one to the * debug_extcmdlist(). */ void add_debug_extended_commands() { int i, j, k, n; /* count the # of help entries */ for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++) ; for (i = 0; debug_extcmdlist[i].ef_txt; i++) { /* need enough room for "?" entry plus terminator */ if (n + 2 >= SIZE(extcmdlist)) panic("Too many debugging commands!"); for (j = 0; j < n; j++) if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break; /* insert i'th debug entry into extcmdlist[j], pushing down */ for (k = n; k >= j; --k) extcmdlist[k + 1] = extcmdlist[k]; extcmdlist[j] = debug_extcmdlist[i]; n++; /* now an extra entry */ } } STATIC_OVL char cmd_from_func(fn) int NDECL((*fn)); { int i; for (i = 0; i < SIZE(cmdlist); ++i) if (cmdlist[i].f_funct == fn) return cmdlist[i].f_char; return 0; } static const char template[] = "%-18s %4ld %6ld"; static const char count_str[] = " count bytes"; static const char separator[] = "------------------ ----- ------"; STATIC_OVL int size_obj(otmp) struct obj *otmp; { int sz = (int) sizeof(struct obj); if (otmp->oextra) { sz += (int) sizeof(struct oextra); if (ONAME(otmp)) sz += (int) strlen(ONAME(otmp)) + 1; if (OMONST(otmp)) sz += (int) sizeof(struct monst); if (OMID(otmp)) sz += (int) sizeof(unsigned); if (OLONG(otmp)) sz += (int) sizeof(long); if (OMAILCMD(otmp)) sz += (int) strlen(OMAILCMD(otmp)) + 1; } return sz; } STATIC_OVL void count_obj(chain, total_count, total_size, top, recurse) struct obj *chain; long *total_count; long *total_size; boolean top; boolean recurse; { long count, size; struct obj *obj; for (count = size = 0, obj = chain; obj; obj = obj->nobj) { if (top) { count++; size += size_obj(obj); } if (recurse && obj->cobj) count_obj(obj->cobj, total_count, total_size, TRUE, TRUE); } *total_count += count; *total_size += size; } STATIC_OVL void obj_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct obj *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; count_obj(chain, &count, &size, TRUE, FALSE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void mon_invent_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct monst *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; struct monst *mon; for (mon = chain; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, TRUE, FALSE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void contained(win, src, total_count, total_size) winid win; const char *src; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; struct monst *mon; count_obj(invent, &count, &size, FALSE, TRUE); count_obj(fobj, &count, &size, FALSE, TRUE); count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE); count_obj(migrating_objs, &count, &size, FALSE, TRUE); /* DEADMONSTER check not required in this loop since they have no * inventory */ for (mon = fmon; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); for (mon = migrating_mons; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL int size_monst(mtmp) struct monst *mtmp; { int sz = (int) sizeof(struct monst); if (mtmp->mextra) { sz += (int) sizeof(struct mextra); if (MNAME(mtmp)) sz += (int) strlen(MNAME(mtmp)) + 1; if (EGD(mtmp)) sz += (int) sizeof(struct egd); if (EPRI(mtmp)) sz += (int) sizeof(struct epri); if (ESHK(mtmp)) sz += (int) sizeof(struct eshk); if (EMIN(mtmp)) sz += (int) sizeof(struct emin); if (EDOG(mtmp)) sz += (int) sizeof(struct edog); /* mextra->mcorpsenm doesn't point to more memory */ } return sz; } STATIC_OVL void mon_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct monst *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count, size; struct monst *mon; for (count = size = 0, mon = chain; mon; mon = mon->nmon) { count++; size += size_monst(mon); } *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } /* * Display memory usage of all monsters and objects on the level. */ static int wiz_show_stats() { char buf[BUFSZ]; winid win; long total_obj_size = 0, total_obj_count = 0; long total_mon_size = 0, total_mon_count = 0; win = create_nhwindow(NHW_TEXT); putstr(win, 0, "Current memory statistics:"); putstr(win, 0, ""); Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj)); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, count_str); obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size); obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size); obj_chain(win, "buried", level.buriedobjlist, &total_obj_count, &total_obj_size); obj_chain(win, "migrating obj", migrating_objs, &total_obj_count, &total_obj_size); mon_invent_chain(win, "minvent", fmon, &total_obj_count, &total_obj_size); mon_invent_chain(win, "migrating minvent", migrating_mons, &total_obj_count, &total_obj_size); contained(win, "contained", &total_obj_count, &total_obj_size); putstr(win, 0, separator); Sprintf(buf, template, "Total", total_obj_count, total_obj_size); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, ""); Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst)); putstr(win, 0, buf); putstr(win, 0, ""); mon_chain(win, "fmon", fmon, &total_mon_count, &total_mon_size); mon_chain(win, "migrating", migrating_mons, &total_mon_count, &total_mon_size); putstr(win, 0, separator); Sprintf(buf, template, "Total", total_mon_count, total_mon_size); putstr(win, 0, buf); #if defined(__BORLANDC__) && !defined(_WIN32) show_borlandc_stats(win); #endif display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } void sanity_check() { obj_sanity_check(); timer_sanity_check(); mon_sanity_check(); light_sources_sanity_check(); } #ifdef DEBUG_MIGRATING_MONS static int wiz_migrate_mons() { int mcount = 0; char inbuf[BUFSZ]; struct permonst *ptr; struct monst *mtmp; d_level tolevel; getlin("How many random monsters to migrate? [0]", inbuf); if (*inbuf == '\033') return 0; mcount = atoi(inbuf); if (mcount < 0 || mcount > (COLNO * ROWNO) || Is_botlevel(&u.uz)) return 0; while (mcount > 0) { if (Is_stronghold(&u.uz)) assign_level(&tolevel, &valley_level); else get_level(&tolevel, depth(&u.uz) + 1); ptr = rndmonst(); mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS); if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *) 0); mcount--; } return 0; } #endif #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c)) #define unmeta(c) (0x7f & (c)) /* called at startup and after number_pad is twiddled */ void reset_commands(initial) boolean initial; { static const char sdir[] = "hykulnjb><", sdir_swap_yz[] = "hzkulnjb><", ndir[] = "47896321><", ndir_phone_layout[] = "41236987><"; static const int ylist[] = { 'y', 'Y', C('y'), M('y'), M('Y'), M(C('y')) }; const struct func_tab *cmdtmp; boolean flagtemp; int c, i, updated = 0; if (initial) { updated = 1; for (i = 0; i < SIZE(cmdlist); i++) { c = cmdlist[i].f_char & 0xff; Cmd.commands[c] = &cmdlist[i]; } Cmd.num_pad = FALSE; Cmd.pcHack_compat = Cmd.phone_layout = Cmd.swap_yz = FALSE; } else { /* basic num_pad */ flagtemp = iflags.num_pad; if (flagtemp != Cmd.num_pad) { Cmd.num_pad = flagtemp; ++updated; } /* swap_yz mode (only applicable for !num_pad) */ flagtemp = (iflags.num_pad_mode & 1) ? !Cmd.num_pad : FALSE; if (flagtemp != Cmd.swap_yz) { Cmd.swap_yz = flagtemp; ++updated; /* Cmd.swap_yz has been toggled; perform the swap (or reverse previous one) */ for (i = 0; i < SIZE(ylist); i++) { c = ylist[i] & 0xff; cmdtmp = Cmd.commands[c]; /* tmp = [y] */ Cmd.commands[c] = Cmd.commands[c + 1]; /* [y] = [z] */ Cmd.commands[c + 1] = cmdtmp; /* [z] = tmp */ } } /* MSDOS compatibility mode (only applicable for num_pad) */ flagtemp = (iflags.num_pad_mode & 1) ? Cmd.num_pad : FALSE; if (flagtemp != Cmd.pcHack_compat) { Cmd.pcHack_compat = flagtemp; ++updated; /* pcHack_compat has been toggled */ c = M('5') & 0xff; cmdtmp = Cmd.commands['5']; Cmd.commands['5'] = Cmd.commands[c]; Cmd.commands[c] = cmdtmp; c = M('0') & 0xff; Cmd.commands[c] = Cmd.pcHack_compat ? Cmd.commands['I'] : 0; } /* phone keypad layout (only applicable for num_pad) */ flagtemp = (iflags.num_pad_mode & 2) ? Cmd.num_pad : FALSE; if (flagtemp != Cmd.phone_layout) { Cmd.phone_layout = flagtemp; ++updated; /* phone_layout has been toggled */ for (i = 0; i < 3; i++) { c = '1' + i; /* 1,2,3 <-> 7,8,9 */ cmdtmp = Cmd.commands[c]; /* tmp = [1] */ Cmd.commands[c] = Cmd.commands[c + 6]; /* [1] = [7] */ Cmd.commands[c + 6] = cmdtmp; /* [7] = tmp */ c = (M('1') & 0xff) + i; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */ cmdtmp = Cmd.commands[c]; /* tmp = [M-1] */ Cmd.commands[c] = Cmd.commands[c + 6]; /* [M-1] = [M-7] */ Cmd.commands[c + 6] = cmdtmp; /* [M-7] = tmp */ } } } /*?initial*/ if (updated) Cmd.serialno++; Cmd.dirchars = !Cmd.num_pad ? (!Cmd.swap_yz ? sdir : sdir_swap_yz) : (!Cmd.phone_layout ? ndir : ndir_phone_layout); Cmd.alphadirchars = !Cmd.num_pad ? Cmd.dirchars : sdir; Cmd.move_W = Cmd.dirchars[0]; Cmd.move_NW = Cmd.dirchars[1]; Cmd.move_N = Cmd.dirchars[2]; Cmd.move_NE = Cmd.dirchars[3]; Cmd.move_E = Cmd.dirchars[4]; Cmd.move_SE = Cmd.dirchars[5]; Cmd.move_S = Cmd.dirchars[6]; Cmd.move_SW = Cmd.dirchars[7]; } STATIC_OVL boolean accept_menu_prefix(cmd_func) int NDECL((*cmd_func)); { if (cmd_func == dopickup || cmd_func == dotip || cmd_func == doextcmd || cmd_func == doextlist) return TRUE; return FALSE; } void rhack(cmd) register char *cmd; { boolean do_walk, do_rush, prefix_seen, bad_command, firsttime = (cmd == 0); iflags.menu_requested = FALSE; #ifdef SAFERHANGUP if (program_state.done_hup) end_of_input(); #endif if (firsttime) { context.nopick = 0; cmd = parse(); } if (*cmd == '\033') { context.move = FALSE; return; } if (*cmd == DOAGAIN && !in_doagain && saveq[0]) { in_doagain = TRUE; stail = 0; rhack((char *) 0); /* read and execute command */ in_doagain = FALSE; return; } /* Special case of *cmd == ' ' handled better below */ if (!*cmd || *cmd == (char) 0377) { nhbell(); context.move = FALSE; return; /* probably we just had an interrupt */ } /* handle most movement commands */ do_walk = do_rush = prefix_seen = FALSE; context.travel = context.travel1 = 0; switch (*cmd) { case 'g': if (movecmd(cmd[1])) { context.run = 2; do_rush = TRUE; } else prefix_seen = TRUE; break; case '5': if (!Cmd.num_pad) break; /* else FALLTHRU */ case 'G': if (movecmd(lowc(cmd[1]))) { context.run = 3; do_rush = TRUE; } else prefix_seen = TRUE; break; case '-': if (!Cmd.num_pad) break; /* else FALLTHRU */ /* Effects of movement commands and invisible monsters: * m: always move onto space (even if 'I' remembered) * F: always attack space (even if 'I' not remembered) * normal movement: attack if 'I', move otherwise. */ case 'F': if (movecmd(cmd[1])) { context.forcefight = 1; do_walk = TRUE; } else prefix_seen = TRUE; break; case 'm': if (movecmd(cmd[1]) || u.dz) { context.run = 0; context.nopick = 1; if (!u.dz) do_walk = TRUE; else cmd[0] = cmd[1]; /* "m<" or "m>" */ } else prefix_seen = TRUE; break; case 'M': if (movecmd(lowc(cmd[1]))) { context.run = 1; context.nopick = 1; do_rush = TRUE; } else prefix_seen = TRUE; break; case '0': if (!Cmd.num_pad) break; (void) ddoinv(); /* a convenience borrowed from the PC */ context.move = FALSE; multi = 0; return; case CMD_CLICKLOOK: if (iflags.clicklook) { context.move = FALSE; do_look(2, &clicklook_cc); } return; case CMD_TRAVEL: if (flags.travelcmd) { context.travel = 1; context.travel1 = 1; context.run = 8; context.nopick = 1; do_rush = TRUE; break; } /*FALLTHRU*/ default: if (movecmd(*cmd)) { /* ordinary movement */ context.run = 0; /* only matters here if it was 8 */ do_walk = TRUE; } else if (movecmd(Cmd.num_pad ? unmeta(*cmd) : lowc(*cmd))) { context.run = 1; do_rush = TRUE; } else if (movecmd(unctrl(*cmd))) { context.run = 3; do_rush = TRUE; } break; } /* some special prefix handling */ /* overload 'm' prefix to mean "request a menu" */ if (prefix_seen && cmd[0] == 'm') { /* (for func_tab cast, see below) */ const struct func_tab *ft = Cmd.commands[cmd[1] & 0xff]; int NDECL((*func)) = ft ? ((struct func_tab *) ft)->f_funct : 0; if (func && accept_menu_prefix(func)) { iflags.menu_requested = TRUE; ++cmd; } } if ((do_walk || do_rush) && !context.travel && !dxdy_moveok()) { /* trying to move diagonally as a grid bug; this used to be treated by movecmd() as not being a movement attempt, but that didn't provide for any feedback and led to strangeness if the key pressed ('u' in particular) was overloaded for num_pad use */ You_cant("get there from here..."); context.run = 0; context.nopick = context.forcefight = FALSE; context.move = context.mv = FALSE; multi = 0; return; } if (do_walk) { if (multi) context.mv = TRUE; domove(); context.forcefight = 0; return; } else if (do_rush) { if (firsttime) { if (!multi) multi = max(COLNO, ROWNO); u.last_str_turn = 0; } context.mv = TRUE; domove(); return; } else if (prefix_seen && cmd[1] == '\033') { /* */ /* don't report "unknown command" for change of heart... */ bad_command = FALSE; } else if (*cmd == ' ' && !flags.rest_on_space) { bad_command = TRUE; /* skip cmdlist[] loop */ /* handle all other commands */ } else { register const struct func_tab *tlist; int res, NDECL((*func)); #if 0 /* obsolete - scan through the cmdlist array looking for *cmd */ for (tlist = cmdlist; tlist->f_char; tlist++) { if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue; #else /* current - use *cmd to directly index cmdlist array */ if ((tlist = Cmd.commands[*cmd & 0xff]) != 0) { #endif if (u.uburied && !tlist->can_if_buried) { You_cant("do that while you are buried!"); res = 0; } else { /* we discard 'const' because some compilers seem to have trouble with the pointer passed to set_occupation() */ func = ((struct func_tab *) tlist)->f_funct; if (tlist->f_text && !occupation && multi) set_occupation(func, tlist->f_text, multi); res = (*func)(); /* perform the command */ } if (!res) { context.move = FALSE; multi = 0; } return; } /* if we reach here, cmd wasn't found in cmdlist[] */ bad_command = TRUE; } if (bad_command) { char expcmd[10]; register char c, *cp = expcmd; while ((c = *cmd++) != '\0' && (int) (cp - expcmd) < (int) (sizeof expcmd - 3)) { if (c >= 040 && c < 0177) { *cp++ = c; } else if (c & 0200) { *cp++ = 'M'; *cp++ = '-'; *cp++ = c & ~0200; } else { *cp++ = '^'; *cp++ = c ^ 0100; } } *cp = '\0'; if (!prefix_seen || !iflags.cmdassist || !help_dir(0, "Invalid direction key!")) Norep("Unknown command '%s'.", expcmd); } /* didn't move */ context.move = FALSE; multi = 0; return; } /* convert an x,y pair into a direction code */ int xytod(x, y) schar x, y; { register int dd; for (dd = 0; dd < 8; dd++) if (x == xdir[dd] && y == ydir[dd]) return dd; return -1; } /* convert a direction code into an x,y pair */ void dtoxy(cc, dd) coord *cc; register int dd; { cc->x = xdir[dd]; cc->y = ydir[dd]; return; } /* also sets u.dz, but returns false for <> */ int movecmd(sym) char sym; { register const char *dp = index(Cmd.dirchars, sym); u.dz = 0; if (!dp || !*dp) return 0; u.dx = xdir[dp - Cmd.dirchars]; u.dy = ydir[dp - Cmd.dirchars]; u.dz = zdir[dp - Cmd.dirchars]; #if 0 /* now handled elsewhere */ if (u.dx && u.dy && NODIAG(u.umonnum)) { u.dx = u.dy = 0; return 0; } #endif return !u.dz; } /* grid bug handling which used to be in movecmd() */ int dxdy_moveok() { if (u.dx && u.dy && NODIAG(u.umonnum)) u.dx = u.dy = 0; return u.dx || u.dy; } /* decide whether a character (user input keystroke) requests screen repaint */ boolean redraw_cmd(c) char c; { return (boolean) (c == C('r') || (Cmd.num_pad && c == C('l'))); } /* * uses getdir() but unlike getdir() it specifically * produces coordinates using the direction from getdir() * and verifies that those coordinates are ok. * * If the call to getdir() returns 0, Never_mind is displayed. * If the resulting coordinates are not okay, emsg is displayed. * * Returns non-zero if coordinates in cc are valid. */ int get_adjacent_loc(prompt, emsg, x, y, cc) const char *prompt, *emsg; xchar x, y; coord *cc; { xchar new_x, new_y; if (!getdir(prompt)) { pline1(Never_mind); return 0; } new_x = x + u.dx; new_y = y + u.dy; if (cc && isok(new_x, new_y)) { cc->x = new_x; cc->y = new_y; } else { if (emsg) pline1(emsg); return 0; } return 1; } int getdir(s) const char *s; { char dirsym; int is_mov; retry: if (in_doagain || *readchar_queue) dirsym = readchar(); else dirsym = yn_function((s && *s != '^') ? s : "In what direction?", (char *) 0, '\0'); /* remove the prompt string so caller won't have to */ clear_nhwindow(WIN_MESSAGE); if (redraw_cmd(dirsym)) { /* ^R */ docrt(); /* redraw */ goto retry; } savech(dirsym); if (dirsym == '.' || dirsym == 's') { u.dx = u.dy = u.dz = 0; } else if (!(is_mov = movecmd(dirsym)) && !u.dz) { boolean did_help = FALSE, help_requested; if (!index(quitchars, dirsym)) { help_requested = (dirsym == '?'); if (help_requested || iflags.cmdassist) { did_help = help_dir((s && *s == '^') ? dirsym : 0, help_requested ? (const char *) 0 : "Invalid direction key!"); if (help_requested) goto retry; } if (!did_help) pline("What a strange direction!"); } return 0; } else if (is_mov && !dxdy_moveok()) { You_cant("orient yourself that direction."); return 0; } if (!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir(); return 1; } STATIC_OVL boolean help_dir(sym, msg) char sym; const char *msg; { char ctrl; winid win; static const char wiz_only_list[] = "EFGIOVW"; char buf[BUFSZ], buf2[BUFSZ], *explain; win = create_nhwindow(NHW_TEXT); if (!win) return FALSE; if (msg) { Sprintf(buf, "cmdassist: %s", msg); putstr(win, 0, buf); putstr(win, 0, ""); } if (letter(sym)) { sym = highc(sym); ctrl = (sym - 'A') + 1; if ((explain = dowhatdoes_core(ctrl, buf2)) && (!index(wiz_only_list, sym) || wizard)) { Sprintf(buf, "Are you trying to use ^%c%s?", sym, index(wiz_only_list, sym) ? "" : " as specified in the Guidebook"); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, explain); putstr(win, 0, ""); putstr(win, 0, "To use that command, you press"); Sprintf(buf, "the key, and the <%c> key at the same time.", sym); putstr(win, 0, buf); putstr(win, 0, ""); } } if (NODIAG(u.umonnum)) { putstr(win, 0, "Valid direction keys in your current form are:"); Sprintf(buf, " %c ", Cmd.move_N); putstr(win, 0, buf); putstr(win, 0, " | "); Sprintf(buf, " %c- . -%c", Cmd.move_W, Cmd.move_E); putstr(win, 0, buf); putstr(win, 0, " | "); Sprintf(buf, " %c ", Cmd.move_S); putstr(win, 0, buf); } else { putstr(win, 0, "Valid direction keys are:"); Sprintf(buf, " %c %c %c", Cmd.move_NW, Cmd.move_N, Cmd.move_NE); putstr(win, 0, buf); putstr(win, 0, " \\ | / "); Sprintf(buf, " %c- . -%c", Cmd.move_W, Cmd.move_E); putstr(win, 0, buf); putstr(win, 0, " / | \\ "); Sprintf(buf, " %c %c %c", Cmd.move_SW, Cmd.move_S, Cmd.move_SE); putstr(win, 0, buf); }; putstr(win, 0, ""); putstr(win, 0, " < up"); putstr(win, 0, " > down"); putstr(win, 0, " . direct at yourself"); if (msg) { /* non-null msg means that this wasn't an explicit user request */ putstr(win, 0, ""); putstr(win, 0, "(Suppress this message with !cmdassist in config file.)"); } display_nhwindow(win, FALSE); destroy_nhwindow(win); return TRUE; } void confdir() { register int x = NODIAG(u.umonnum) ? 2 * rn2(4) : rn2(8); u.dx = xdir[x]; u.dy = ydir[x]; return; } const char * directionname(dir) int dir; { static NEARDATA const char *const dirnames[] = { "west", "northwest", "north", "northeast", "east", "southeast", "south", "southwest", "down", "up", }; if (dir < 0 || dir >= SIZE(dirnames)) return "invalid"; return dirnames[dir]; } int isok(x, y) register int x, y; { /* x corresponds to curx, so x==1 is the first column. Ach. %% */ return x >= 1 && x <= COLNO - 1 && y >= 0 && y <= ROWNO - 1; } static NEARDATA int last_multi; /* * convert a MAP window position into a movecmd */ const char * click_to_cmd(x, y, mod) int x, y, mod; { int dir; static char cmd[4]; cmd[1] = 0; if (iflags.clicklook && mod == CLICK_2) { clicklook_cc.x = x; clicklook_cc.y = y; cmd[0] = CMD_CLICKLOOK; return cmd; } x -= u.ux; y -= u.uy; if (flags.travelcmd) { if (abs(x) <= 1 && abs(y) <= 1) { x = sgn(x), y = sgn(y); } else { u.tx = u.ux + x; u.ty = u.uy + y; cmd[0] = CMD_TRAVEL; return cmd; } if (x == 0 && y == 0) { /* here */ if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) { cmd[0] = mod == CLICK_1 ? 'q' : M('d'); return cmd; } else if (IS_THRONE(levl[u.ux][u.uy].typ)) { cmd[0] = M('s'); return cmd; } else if ((u.ux == xupstair && u.uy == yupstair) || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up) || (u.ux == xupladder && u.uy == yupladder)) { return "<"; } else if ((u.ux == xdnstair && u.uy == ydnstair) || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up) || (u.ux == xdnladder && u.uy == ydnladder)) { return ">"; } else if (OBJ_AT(u.ux, u.uy)) { cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ','; return cmd; } else { return "."; /* just rest */ } } /* directional commands */ dir = xytod(x, y); if (!m_at(u.ux + x, u.uy + y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) { cmd[1] = Cmd.dirchars[dir]; cmd[2] = '\0'; if (IS_DOOR(levl[u.ux + x][u.uy + y].typ)) { /* slight assistance to the player: choose kick/open for them */ if (levl[u.ux + x][u.uy + y].doormask & D_LOCKED) { cmd[0] = C('d'); return cmd; } if (levl[u.ux + x][u.uy + y].doormask & D_CLOSED) { cmd[0] = 'o'; return cmd; } } if (levl[u.ux + x][u.uy + y].typ <= SCORR) { cmd[0] = 's'; cmd[1] = 0; return cmd; } } } else { /* convert without using floating point, allowing sloppy clicking */ if (x > 2 * abs(y)) x = 1, y = 0; else if (y > 2 * abs(x)) x = 0, y = 1; else if (x < -2 * abs(y)) x = -1, y = 0; else if (y < -2 * abs(x)) x = 0, y = -1; else x = sgn(x), y = sgn(y); if (x == 0 && y == 0) /* map click on player to "rest" command */ return "."; dir = xytod(x, y); } /* move, attack, etc. */ cmd[1] = 0; if (mod == CLICK_1) { cmd[0] = Cmd.dirchars[dir]; } else { cmd[0] = (Cmd.num_pad ? M(Cmd.dirchars[dir]) : (Cmd.dirchars[dir] - 'a' + 'A')); /* run command */ } return cmd; } STATIC_OVL char * parse() { #ifdef LINT /* static char in_line[COLNO]; */ char in_line[COLNO]; #else static char in_line[COLNO]; #endif register int foo; boolean prezero = FALSE; multi = 0; context.move = 1; flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */ #ifdef ALTMETA alt_esc = iflags.altmeta; /* readchar() hack */ #endif if (!Cmd.num_pad || (foo = readchar()) == 'n') for (;;) { foo = readchar(); if (foo >= '0' && foo <= '9') { multi = 10 * multi + foo - '0'; if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT; if (multi > 9) { clear_nhwindow(WIN_MESSAGE); Sprintf(in_line, "Count: %d", multi); pline1(in_line); mark_synch(); } last_multi = multi; if (!multi && foo == '0') prezero = TRUE; } else break; /* not a digit */ } #ifdef ALTMETA alt_esc = FALSE; /* readchar() reset */ #endif if (foo == '\033') { /* esc cancels count (TH) */ clear_nhwindow(WIN_MESSAGE); multi = last_multi = 0; } else if (foo == DOAGAIN || in_doagain) { multi = last_multi; } else { last_multi = multi; savech(0); /* reset input queue */ savech((char) foo); } if (multi) { multi--; save_cm = in_line; } else { save_cm = (char *) 0; } /* in 3.4.3 this was in rhack(), where it was too late to handle M-5 */ if (Cmd.pcHack_compat) { /* This handles very old inconsistent DOS/Windows behaviour in a different way: earlier, the keyboard handler mapped these, which caused counts to be strange when entered from the number pad. Now do not map them until here. */ switch (foo) { case '5': foo = 'g'; break; case M('5'): foo = 'G'; break; case M('0'): foo = 'I'; break; default: break; /* as is */ } } in_line[0] = foo; in_line[1] = '\0'; if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' || foo == 'F' || (Cmd.num_pad && (foo == '5' || foo == '-'))) { foo = readchar(); savech((char) foo); in_line[1] = foo; in_line[2] = 0; } clear_nhwindow(WIN_MESSAGE); if (prezero) in_line[0] = '\033'; return in_line; } #ifdef HANGUPHANDLING /* some very old systems, or descendents of such systems, expect signal handlers to have return type `int', but they don't actually inspect the return value so we should be safe using `void' unconditionally */ /*ARGUSED*/ void hangup(sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused UNUSED; { if (program_state.exiting) program_state.in_moveloop = 0; nhwindows_hangup(); #ifdef SAFERHANGUP /* When using SAFERHANGUP, the done_hup flag it tested in rhack and a couple of other places; actual hangup handling occurs then. This is 'safer' because it disallows certain cheats and also protects against losing objects in the process of being thrown, but also potentially riskier because the disconnected program must continue running longer before attempting a hangup save. */ program_state.done_hup++; /* defer hangup iff game appears to be in progress */ if (program_state.in_moveloop && program_state.something_worth_saving) return; #endif /* SAFERHANGUP */ end_of_input(); } void end_of_input() { #ifdef NOSAVEONHANGUP #ifdef INSURANCE if (flags.ins_chkpt && program_state.something_worth_saving) program_statue.preserve_locks = 1; /* keep files for recovery */ #endif program_state.something_worth_saving = 0; /* don't save */ #endif #ifndef SAFERHANGUP if (!program_state.done_hup++) #endif if (program_state.something_worth_saving) (void) dosave0(); if (iflags.window_inited) exit_nhwindows((char *) 0); clearlocks(); terminate(EXIT_SUCCESS); /*NOTREACHED*/ /* not necessarily true for vms... */ return; } #endif /* HANGUPHANDLING */ char readchar() { register int sym; int x = u.ux, y = u.uy, mod = 0; if (*readchar_queue) sym = *readchar_queue++; else sym = in_doagain ? pgetchar() : nh_poskey(&x, &y, &mod); #ifdef NR_OF_EOFS if (sym == EOF) { register int cnt = NR_OF_EOFS; /* * Some SYSV systems seem to return EOFs for various reasons * (?like when one hits break or for interrupted systemcalls?), * and we must see several before we quit. */ do { clearerr(stdin); /* omit if clearerr is undefined */ sym = pgetchar(); } while (--cnt && sym == EOF); } #endif /* NR_OF_EOFS */ if (sym == EOF) { #ifdef HANGUPHANDLING hangup(0); /* call end_of_input() or set program_state.done_hup */ #endif sym = '\033'; #ifdef ALTMETA } else if (sym == '\033' && alt_esc) { /* iflags.altmeta: treat two character ``ESC c'' as single `M-c' */ sym = *readchar_queue ? *readchar_queue++ : pgetchar(); if (sym == EOF || sym == 0) sym = '\033'; else if (sym != '\033') sym |= 0200; /* force 8th bit on */ #endif /*ALTMETA*/ } else if (sym == 0) { /* click event */ readchar_queue = click_to_cmd(x, y, mod); sym = *readchar_queue++; } return (char) sym; } STATIC_PTR int dotravel(VOID_ARGS) { /* Keyboard travel command */ static char cmd[2]; coord cc; if (!flags.travelcmd) return 0; cmd[1] = 0; cc.x = iflags.travelcc.x; cc.y = iflags.travelcc.y; if (cc.x == -1 && cc.y == -1) { /* No cached destination, start attempt from current position */ cc.x = u.ux; cc.y = u.uy; } pline("Where do you want to travel to?"); if (getpos(&cc, TRUE, "the desired destination") < 0) { /* user pressed ESC */ return 0; } iflags.travelcc.x = u.tx = cc.x; iflags.travelcc.y = u.ty = cc.y; cmd[0] = CMD_TRAVEL; readchar_queue = cmd; return 0; } #ifdef PORT_DEBUG extern void NDECL(win32con_debug_keystrokes); extern void NDECL(win32con_handler_info); int wiz_port_debug() { int n, k; winid win; anything any; int item = 'a'; int num_menu_selections; struct menu_selection_struct { char *menutext; void NDECL((*fn)); } menu_selections[] = { #ifdef WIN32 { "test win32 keystrokes (tty only)", win32con_debug_keystrokes }, { "show keystroke handler information (tty only)", win32con_handler_info }, #endif { (char *) 0, (void NDECL((*) )) 0 } /* array terminator */ }; num_menu_selections = SIZE(menu_selections) - 1; if (num_menu_selections > 0) { menu_item *pick_list; win = create_nhwindow(NHW_MENU); start_menu(win); for (k = 0; k < num_menu_selections; ++k) { any.a_int = k + 1; add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE, menu_selections[k].menutext, MENU_UNSELECTED); } end_menu(win, "Which port debugging feature?"); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n > 0) { n = pick_list[0].item.a_int - 1; free((genericptr_t) pick_list); /* execute the function */ (*menu_selections[n].fn)(); } } else pline("No port-specific debug capability defined."); return 0; } #endif /*PORT_DEBUG*/ /* * Parameter validator for generic yes/no function to prevent * the core from sending too long a prompt string to the * window port causing a buffer overflow there. */ char yn_function(query, resp, def) const char *query, *resp; char def; { char qbuf[QBUFSZ]; iflags.last_msg = PLNMSG_UNKNOWN; /* most recent pline is clobbered */ /* maximum acceptable length is QBUFSZ-1 */ if (strlen(query) < QBUFSZ) return (*windowprocs.win_yn_function)(query, resp, def); /* caller shouldn't have passed anything this long */ paniclog("Query truncated: ", query); (void) strncpy(qbuf, query, QBUFSZ - 1 - 3); Strcpy(&qbuf[QBUFSZ - 1 - 3], "..."); return (*windowprocs.win_yn_function)(qbuf, resp, def); } /* for paranoid_confirm:quit,die,attack prompting */ boolean paranoid_query(be_paranoid, prompt) boolean be_paranoid; const char *prompt; { boolean confirmed_ok; /* when paranoid, player must respond with "yes" rather than just 'y' to give the go-ahead for this query; default is "no" unless the ParanoidConfirm flag is set in which case there's no default */ if (be_paranoid) { char qbuf[QBUFSZ], ans[BUFSZ]; const char *promptprefix = "", *responsetype = ParanoidConfirm ? "(yes|no)" : "(yes) [no]"; int trylimit = 6; /* 1 normal, 5 more with "Yes or No:" prefix */ /* in addition to being paranoid about this particular query, we might be even more paranoid about all paranoia responses (ie, ParanoidConfirm is set) in which case we require "no" to reject in addition to "yes" to confirm (except we won't loop if response is ESC; it means no) */ do { Sprintf(qbuf, "%s%s %s", promptprefix, prompt, responsetype); getlin(qbuf, ans); (void) mungspaces(ans); confirmed_ok = !strcmpi(ans, "yes"); if (confirmed_ok || *ans == '\033') break; promptprefix = "\"Yes\" or \"No\": "; } while (ParanoidConfirm && strcmpi(ans, "no") && --trylimit); } else confirmed_ok = (yn(prompt) == 'y'); return confirmed_ok; } int dosuspend_core() { #ifdef SUSPEND /* Does current window system support suspend? */ if ((*windowprocs.win_can_suspend)()) { /* NB: SYSCF SHELLERS handled in port code. */ dosuspend(); } else #endif Norep("Suspend command not available."); return 0; } /*cmd.c*/ nethack-3.6.0/src/dbridge.c0000664000076400007660000007067512631241231014502 0ustar paxedpaxed/* NetHack 3.6 dbridge.c $NHDT-Date: 1449269914 2015/12/04 22:58:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.35 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the drawbridge manipulation (create, open, close, * destroy). * * Added comprehensive monster-handling, and the "entity" structure to * deal with players as well. - 11/89 * * Any traps and/or engravings at either the portcullis or span location * are destroyed whenever the bridge is lowered, raised, or destroyed. * (Engraving handling could be extended to flag whether an engraving on * the DB_UNDER surface is hidden by the lowered bridge, or one on the * bridge itself is hidden because the bridge has been raised, but that * seems like an awful lot of effort for very little gain.) */ #include "hack.h" STATIC_DCL void FDECL(get_wall_for_db, (int *, int *)); STATIC_DCL struct entity *FDECL(e_at, (int, int)); STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *)); STATIC_DCL void FDECL(u_to_e, (struct entity *)); STATIC_DCL void FDECL(set_entity, (int, int, struct entity *)); STATIC_DCL const char *FDECL(e_nam, (struct entity *)); STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *)); STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int)); STATIC_DCL void FDECL(e_died, (struct entity *, int, int)); STATIC_DCL boolean FDECL(automiss, (struct entity *)); STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P)); STATIC_DCL boolean FDECL(e_jumps, (struct entity *)); STATIC_DCL void FDECL(do_entity, (struct entity *)); boolean is_pool(x, y) int x, y; { schar ltyp; if (!isok(x, y)) return FALSE; ltyp = levl[x][y].typ; /* The ltyp == MOAT is not redundant with is_moat, because the * Juiblex level does not have moats, although it has MOATs. There * is probably a better way to express this. */ if (ltyp == POOL || ltyp == MOAT || ltyp == WATER || is_moat(x, y)) return TRUE; return FALSE; } boolean is_lava(x, y) int x, y; { schar ltyp; if (!isok(x, y)) return FALSE; ltyp = levl[x][y].typ; if (ltyp == LAVAPOOL || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA)) return TRUE; return FALSE; } boolean is_pool_or_lava(x, y) int x, y; { if (is_pool(x, y) || is_lava(x, y)) return TRUE; else return FALSE; } boolean is_ice(x, y) int x, y; { schar ltyp; if (!isok(x, y)) return FALSE; ltyp = levl[x][y].typ; if (ltyp == ICE || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) return TRUE; return FALSE; } boolean is_moat(x, y) int x, y; { schar ltyp; if (!isok(x, y)) return FALSE; ltyp = levl[x][y].typ; if (!Is_juiblex_level(&u.uz) && (ltyp == MOAT || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT))) return TRUE; return FALSE; } schar db_under_typ(mask) int mask; { switch (mask & DB_UNDER) { case DB_ICE: return ICE; break; case DB_LAVA: return LAVAPOOL; break; case DB_MOAT: return MOAT; break; default: return STONE; break; } } /* * We want to know whether a wall (or a door) is the portcullis (passageway) * of an eventual drawbridge. * * Return value: the direction of the drawbridge. */ int is_drawbridge_wall(x, y) int x, y; { struct rm *lev; lev = &levl[x][y]; if (lev->typ != DOOR && lev->typ != DBWALL) return -1; if (IS_DRAWBRIDGE(levl[x + 1][y].typ) && (levl[x + 1][y].drawbridgemask & DB_DIR) == DB_WEST) return DB_WEST; if (IS_DRAWBRIDGE(levl[x - 1][y].typ) && (levl[x - 1][y].drawbridgemask & DB_DIR) == DB_EAST) return DB_EAST; if (IS_DRAWBRIDGE(levl[x][y - 1].typ) && (levl[x][y - 1].drawbridgemask & DB_DIR) == DB_SOUTH) return DB_SOUTH; if (IS_DRAWBRIDGE(levl[x][y + 1].typ) && (levl[x][y + 1].drawbridgemask & DB_DIR) == DB_NORTH) return DB_NORTH; return -1; } /* * Use is_db_wall where you want to verify that a * drawbridge "wall" is UP in the location x, y * (instead of UP or DOWN, as with is_drawbridge_wall). */ boolean is_db_wall(x, y) int x, y; { return (boolean) (levl[x][y].typ == DBWALL); } /* * Return true with x,y pointing to the drawbridge if x,y initially indicate * a drawbridge or drawbridge wall. */ boolean find_drawbridge(x, y) int *x, *y; { int dir; if (IS_DRAWBRIDGE(levl[*x][*y].typ)) return TRUE; dir = is_drawbridge_wall(*x, *y); if (dir >= 0) { switch (dir) { case DB_NORTH: (*y)++; break; case DB_SOUTH: (*y)--; break; case DB_EAST: (*x)--; break; case DB_WEST: (*x)++; break; } return TRUE; } return FALSE; } /* * Find the drawbridge wall associated with a drawbridge. */ STATIC_OVL void get_wall_for_db(x, y) int *x, *y; { switch (levl[*x][*y].drawbridgemask & DB_DIR) { case DB_NORTH: (*y)--; break; case DB_SOUTH: (*y)++; break; case DB_EAST: (*x)++; break; case DB_WEST: (*x)--; break; } } /* * Creation of a drawbridge at pos x,y. * dir is the direction. * flag must be put to TRUE if we want the drawbridge to be opened. */ boolean create_drawbridge(x, y, dir, flag) int x, y, dir; boolean flag; { int x2, y2; boolean horiz; boolean lava = levl[x][y].typ == LAVAPOOL; /* assume initialized map */ x2 = x; y2 = y; switch (dir) { case DB_NORTH: horiz = TRUE; y2--; break; case DB_SOUTH: horiz = TRUE; y2++; break; case DB_EAST: horiz = FALSE; x2++; break; default: impossible("bad direction in create_drawbridge"); /*FALLTHRU*/ case DB_WEST: horiz = FALSE; x2--; break; } if (!IS_WALL(levl[x2][y2].typ)) return FALSE; if (flag) { /* We want the bridge open */ levl[x][y].typ = DRAWBRIDGE_DOWN; levl[x2][y2].typ = DOOR; levl[x2][y2].doormask = D_NODOOR; } else { levl[x][y].typ = DRAWBRIDGE_UP; levl[x2][y2].typ = DBWALL; /* Drawbridges are non-diggable. */ levl[x2][y2].wall_info = W_NONDIGGABLE; } levl[x][y].horizontal = !horiz; levl[x2][y2].horizontal = horiz; levl[x][y].drawbridgemask = dir; if (lava) levl[x][y].drawbridgemask |= DB_LAVA; return TRUE; } struct entity { struct monst *emon; /* youmonst for the player */ struct permonst *edata; /* must be non-zero for record to be valid */ int ex, ey; }; #define ENTITIES 2 static NEARDATA struct entity occupants[ENTITIES]; STATIC_OVL struct entity * e_at(x, y) int x, y; { int entitycnt; for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) if ((occupants[entitycnt].edata) && (occupants[entitycnt].ex == x) && (occupants[entitycnt].ey == y)) break; debugpline1("entitycnt = %d", entitycnt); #ifdef D_DEBUG wait_synch(); #endif return (entitycnt == ENTITIES) ? (struct entity *) 0 : &(occupants[entitycnt]); } STATIC_OVL void m_to_e(mtmp, x, y, etmp) struct monst *mtmp; int x, y; struct entity *etmp; { etmp->emon = mtmp; if (mtmp) { etmp->ex = x; etmp->ey = y; if (mtmp->wormno && (x != mtmp->mx || y != mtmp->my)) etmp->edata = &mons[PM_LONG_WORM_TAIL]; else etmp->edata = mtmp->data; } else etmp->edata = (struct permonst *) 0; } STATIC_OVL void u_to_e(etmp) struct entity *etmp; { etmp->emon = &youmonst; etmp->ex = u.ux; etmp->ey = u.uy; etmp->edata = youmonst.data; } STATIC_OVL void set_entity(x, y, etmp) int x, y; struct entity *etmp; { if ((x == u.ux) && (y == u.uy)) u_to_e(etmp); else if (MON_AT(x, y)) m_to_e(m_at(x, y), x, y, etmp); else etmp->edata = (struct permonst *) 0; } #define is_u(etmp) (etmp->emon == &youmonst) #define e_canseemon(etmp) \ (is_u(etmp) ? (boolean) TRUE : canseemon(etmp->emon)) /* * e_strg is a utility routine which is not actually in use anywhere, since * the specialized routines below suffice for all current purposes. */ /* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */ STATIC_OVL const char * e_nam(etmp) struct entity *etmp; { return is_u(etmp) ? "you" : mon_nam(etmp->emon); } /* * Generates capitalized entity name, makes 2nd -> 3rd person conversion on * verb, where necessary. */ STATIC_OVL const char * E_phrase(etmp, verb) struct entity *etmp; const char *verb; { static char wholebuf[80]; Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon)); if (!verb || !*verb) return wholebuf; Strcat(wholebuf, " "); if (is_u(etmp)) Strcat(wholebuf, verb); else Strcat(wholebuf, vtense((char *) 0, verb)); return wholebuf; } /* * Simple-minded "can it be here?" routine */ STATIC_OVL boolean e_survives_at(etmp, x, y) struct entity *etmp; int x, y; { if (noncorporeal(etmp->edata)) return TRUE; if (is_pool(x, y)) return (boolean) ((is_u(etmp) && (Wwalking || Amphibious || Swimming || Flying || Levitation)) || is_swimmer(etmp->edata) || is_flyer(etmp->edata) || is_floater(etmp->edata)); /* must force call to lava_effects in e_died if is_u */ if (is_lava(x, y)) return (boolean) ((is_u(etmp) && (Levitation || Flying)) || likes_lava(etmp->edata) || is_flyer(etmp->edata)); if (is_db_wall(x, y)) return (boolean) (is_u(etmp) ? Passes_walls : passes_walls(etmp->edata)); return TRUE; } STATIC_OVL void e_died(etmp, dest, how) struct entity *etmp; int dest, how; { if (is_u(etmp)) { if (how == DROWNING) { killer.name[0] = 0; /* drown() sets its own killer */ (void) drown(); } else if (how == BURNING) { killer.name[0] = 0; /* lava_effects() sets own killer */ (void) lava_effects(); } else { coord xy; /* use more specific killer if specified */ if (!killer.name[0]) { killer.format = KILLED_BY_AN; Strcpy(killer.name, "falling drawbridge"); } done(how); /* So, you didn't die */ if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) { pline("A %s force teleports you away...", Hallucination ? "normal" : "strange"); teleds(xy.x, xy.y, FALSE); } /* otherwise on top of the drawbridge is the * only viable spot in the dungeon, so stay there */ } } /* we might have crawled out of the moat to survive */ etmp->ex = u.ux, etmp->ey = u.uy; } else { int entitycnt; killer.name[0] = 0; /* fake "digested to death" damage-type suppresses corpse */ #define mk_message(dest) ((dest & 1) ? "" : (char *) 0) #define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS) /* if monsters are moving, one of them caused the destruction */ if (context.mon_moving) monkilled(etmp->emon, mk_message(dest), mk_corpse(dest)); else /* you caused it */ xkilled(etmp->emon, dest); etmp->edata = (struct permonst *) 0; /* dead long worm handling */ for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) { if (etmp != &(occupants[entitycnt]) && etmp->emon == occupants[entitycnt].emon) occupants[entitycnt].edata = (struct permonst *) 0; } #undef mk_message #undef mk_corpse } } /* * These are never directly affected by a bridge or portcullis. */ STATIC_OVL boolean automiss(etmp) struct entity *etmp; { return (boolean) ((is_u(etmp) ? Passes_walls : passes_walls(etmp->edata)) || noncorporeal(etmp->edata)); } /* * Does falling drawbridge or portcullis miss etmp? */ STATIC_OVL boolean e_missed(etmp, chunks) struct entity *etmp; boolean chunks; { int misses; if (chunks) { debugpline0("Do chunks miss?"); } if (automiss(etmp)) return TRUE; if (is_flyer(etmp->edata) && (is_u(etmp) ? !Unaware : (etmp->emon->mcanmove && !etmp->emon->msleeping))) /* flying requires mobility */ misses = 5; /* out of 8 */ else if (is_floater(etmp->edata) || (is_u(etmp) && Levitation)) /* doesn't require mobility */ misses = 3; else if (chunks && is_pool(etmp->ex, etmp->ey)) misses = 2; /* sitting ducks */ else misses = 0; if (is_db_wall(etmp->ex, etmp->ey)) misses -= 3; /* less airspace */ debugpline1("Miss chance = %d (out of 8)", misses); return (misses >= rnd(8)) ? TRUE : FALSE; } /* * Can etmp jump from death? */ STATIC_OVL boolean e_jumps(etmp) struct entity *etmp; { int tmp = 4; /* out of 10 */ if (is_u(etmp) ? (Unaware || Fumbling) : (!etmp->emon->mcanmove || etmp->emon->msleeping || !etmp->edata->mmove || etmp->emon->wormno)) return FALSE; if (is_u(etmp) ? Confusion : etmp->emon->mconf) tmp -= 2; if (is_u(etmp) ? Stunned : etmp->emon->mstun) tmp -= 3; if (is_db_wall(etmp->ex, etmp->ey)) tmp -= 2; /* less room to maneuver */ debugpline2("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp); return (tmp >= rnd(10)) ? TRUE : FALSE; } STATIC_OVL void do_entity(etmp) struct entity *etmp; { int newx, newy, at_portcullis, oldx, oldy; boolean must_jump = FALSE, relocates = FALSE, e_inview; struct rm *crm; if (!etmp->edata) return; e_inview = e_canseemon(etmp); oldx = etmp->ex; oldy = etmp->ey; at_portcullis = is_db_wall(oldx, oldy); crm = &levl[oldx][oldy]; if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) { if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ))) pline_The("%s passes through %s!", at_portcullis ? "portcullis" : "drawbridge", e_nam(etmp)); if (is_u(etmp)) spoteffects(FALSE); return; } if (e_missed(etmp, FALSE)) { if (at_portcullis) { pline_The("portcullis misses %s!", e_nam(etmp)); } else { debugpline1("The drawbridge misses %s!", e_nam(etmp)); } if (e_survives_at(etmp, oldx, oldy)) { return; } else { debugpline0("Mon can't survive here"); if (at_portcullis) must_jump = TRUE; else relocates = TRUE; /* just ride drawbridge in */ } } else { if (crm->typ == DRAWBRIDGE_DOWN) { pline("%s crushed underneath the drawbridge.", E_phrase(etmp, "are")); /* no jump */ e_died(etmp, e_inview ? 3 : 2, CRUSHING); /* no corpse */ return; /* Note: Beyond this point, we know we're */ } /* not at an opened drawbridge, since all */ must_jump = TRUE; /* *missable* creatures survive on the */ } /* square, and all the unmissed ones die. */ if (must_jump) { if (at_portcullis) { if (e_jumps(etmp)) { relocates = TRUE; debugpline0("Jump succeeds!"); } else { if (e_inview) pline("%s crushed by the falling portcullis!", E_phrase(etmp, "are")); else if (!Deaf) You_hear("a crushing sound."); e_died(etmp, e_inview ? 3 : 2, CRUSHING); /* no corpse */ return; } } else { /* tries to jump off bridge to original square */ relocates = !e_jumps(etmp); debugpline1("Jump %s!", (relocates) ? "fails" : "succeeds"); } } /* * Here's where we try to do relocation. Assumes that etmp is not * arriving * at the portcullis square while the drawbridge is falling, since this * square * would be inaccessible (i.e. etmp started on drawbridge square) or * unnecessary (i.e. etmp started here) in such a situation. */ debugpline0("Doing relocation."); newx = oldx; newy = oldy; (void) find_drawbridge(&newx, &newy); if ((newx == oldx) && (newy == oldy)) get_wall_for_db(&newx, &newy); debugpline0("Checking new square for occupancy."); if (relocates && (e_at(newx, newy))) { /* * Standoff problem: one or both entities must die, and/or both * switch * places. Avoid infinite recursion by checking first whether the * other * entity is staying put. Clean up if we happen to move/die in * recursion. */ struct entity *other; other = e_at(newx, newy); debugpline1("New square is occupied by %s", e_nam(other)); if (e_survives_at(other, newx, newy) && automiss(other)) { relocates = FALSE; /* "other" won't budge */ debugpline1("%s suicide.", E_phrase(etmp, "commit")); } else { debugpline1("Handling %s", e_nam(other)); while ((e_at(newx, newy) != 0) && (e_at(newx, newy) != etmp)) do_entity(other); debugpline1("Checking existence of %s", e_nam(etmp)); #ifdef D_DEBUG wait_synch(); #endif if (e_at(oldx, oldy) != etmp) { debugpline1("%s moved or died in recursion somewhere", E_phrase(etmp, "have")); #ifdef D_DEBUG wait_synch(); #endif return; } } } if (relocates && !e_at(newx, newy)) { /* if e_at() entity = worm tail */ debugpline1("Moving %s", e_nam(etmp)); if (!is_u(etmp)) { remove_monster(etmp->ex, etmp->ey); place_monster(etmp->emon, newx, newy); update_monster_region(etmp->emon); } else { u.ux = newx; u.uy = newy; } etmp->ex = newx; etmp->ey = newy; e_inview = e_canseemon(etmp); } debugpline1("Final disposition of %s", e_nam(etmp)); #ifdef D_DEBUG wait_synch(); #endif if (is_db_wall(etmp->ex, etmp->ey)) { debugpline1("%s in portcullis chamber", E_phrase(etmp, "are")); #ifdef D_DEBUG wait_synch(); #endif if (e_inview) { if (is_u(etmp)) { You("tumble towards the closed portcullis!"); if (automiss(etmp)) You("pass through it!"); else pline_The("drawbridge closes in..."); } else pline("%s behind the drawbridge.", E_phrase(etmp, "disappear")); } if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { killer.format = KILLED_BY_AN; Strcpy(killer.name, "closing drawbridge"); e_died(etmp, 0, CRUSHING); /* no message */ return; } debugpline1("%s in here", E_phrase(etmp, "survive")); } else { debugpline1("%s on drawbridge square", E_phrase(etmp, "are")); if (is_pool(etmp->ex, etmp->ey) && !e_inview) if (!Deaf) You_hear("a splash."); if (e_survives_at(etmp, etmp->ex, etmp->ey)) { if (e_inview && !is_flyer(etmp->edata) && !is_floater(etmp->edata)) pline("%s from the bridge.", E_phrase(etmp, "fall")); return; } debugpline1("%s cannot survive on the drawbridge square", E_phrase(etmp, NULL)); if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey)) if (e_inview && !is_u(etmp)) { /* drown() will supply msgs if nec. */ boolean lava = is_lava(etmp->ex, etmp->ey); if (Hallucination) pline("%s the %s and disappears.", E_phrase(etmp, "drink"), lava ? "lava" : "moat"); else pline("%s into the %s.", E_phrase(etmp, "fall"), lava ? "lava" : "moat"); } killer.format = NO_KILLER_PREFIX; Strcpy(killer.name, "fell from a drawbridge"); e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */ (is_pool(etmp->ex, etmp->ey)) ? DROWNING : (is_lava(etmp->ex, etmp->ey)) ? BURNING : CRUSHING); /*no corpse*/ return; } } /* * Close the drawbridge located at x,y */ void close_drawbridge(x, y) int x, y; { register struct rm *lev1, *lev2; struct trap *t; int x2, y2; lev1 = &levl[x][y]; if (lev1->typ != DRAWBRIDGE_DOWN) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); if (cansee(x, y) || cansee(x2, y2)) You_see("a drawbridge %s up!", (((u.ux == x || u.uy == y) && !Underwater) || distu(x2, y2) < distu(x, y)) ? "coming" : "going"); else /* "5 gears turn" for castle drawbridge tune */ You_hear("chains rattling and gears turning."); lev1->typ = DRAWBRIDGE_UP; lev2 = &levl[x2][y2]; lev2->typ = DBWALL; switch (lev1->drawbridgemask & DB_DIR) { case DB_NORTH: case DB_SOUTH: lev2->horizontal = TRUE; break; case DB_WEST: case DB_EAST: lev2->horizontal = FALSE; break; } lev2->wall_info = W_NONDIGGABLE; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* Do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */ do_entity(&(occupants[1])); if (OBJ_AT(x, y) && !Deaf) You_hear("smashing and crushing."); (void) revive_nasty(x, y, (char *) 0); (void) revive_nasty(x2, y2, (char *) 0); delallobj(x, y); delallobj(x2, y2); if ((t = t_at(x, y)) != 0) deltrap(t); if ((t = t_at(x2, y2)) != 0) deltrap(t); del_engr_at(x, y); del_engr_at(x2, y2); newsym(x, y); newsym(x2, y2); block_point(x2, y2); /* vision */ } /* * Open the drawbridge located at x,y */ void open_drawbridge(x, y) int x, y; { register struct rm *lev1, *lev2; struct trap *t; int x2, y2; lev1 = &levl[x][y]; if (lev1->typ != DRAWBRIDGE_UP) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); if (cansee(x, y) || cansee(x2, y2)) You_see("a drawbridge %s down!", (distu(x2, y2) < distu(x, y)) ? "going" : "coming"); else /* "5 gears turn" for castle drawbridge tune */ You_hear("gears turning and chains rattling."); lev1->typ = DRAWBRIDGE_DOWN; lev2 = &levl[x2][y2]; lev2->typ = DOOR; lev2->doormask = D_NODOOR; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */ do_entity(&(occupants[1])); (void) revive_nasty(x, y, (char *) 0); delallobj(x, y); if ((t = t_at(x, y)) != 0) deltrap(t); if ((t = t_at(x2, y2)) != 0) deltrap(t); del_engr_at(x, y); del_engr_at(x2, y2); newsym(x, y); newsym(x2, y2); unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; } /* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(x, y) int x, y; { register struct rm *lev1, *lev2; struct trap *t; struct obj *otmp; int x2, y2, i; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); lev1 = &levl[x][y]; if (!IS_DRAWBRIDGE(lev1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); lev2 = &levl[x2][y2]; if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT || (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) { struct obj *otmp2; boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA; if (lev1->typ == DRAWBRIDGE_UP) { if (cansee(x2, y2)) pline_The("portcullis of the drawbridge falls into the %s!", lava ? "lava" : "moat"); else if (!Deaf) You_hear("a loud *SPLASH*!"); } else { if (cansee(x, y)) pline_The("drawbridge collapses into the %s!", lava ? "lava" : "moat"); else if (!Deaf) You_hear("a loud *SPLASH*!"); } lev1->typ = lava ? LAVAPOOL : MOAT; lev1->drawbridgemask = 0; if ((otmp2 = sobj_at(BOULDER, x, y)) != 0) { obj_extract_self(otmp2); (void) flooreffects(otmp2, x, y, "fall"); } } else { if (cansee(x, y)) pline_The("drawbridge disintegrates!"); else You_hear("a loud *CRASH*!"); lev1->typ = ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM); lev1->icedpool = ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); lev2->typ = DOOR; lev2->doormask = D_NODOOR; if ((t = t_at(x, y)) != 0) deltrap(t); if ((t = t_at(x2, y2)) != 0) deltrap(t); del_engr_at(x, y); del_engr_at(x2, y2); for (i = rn2(6); i > 0; --i) { /* scatter some debris */ /* doesn't matter if we happen to pick or ; since drawbridges are never placed diagonally, those pairings will always match one of or */ otmp = mksobj_at(IRON_CHAIN, rn2(2) ? x : x2, rn2(2) ? y : y2, TRUE, FALSE); /* a force of 5 here would yield a radius of 2 for iron chain; anything less produces a radius of 1 */ (void) scatter(otmp->ox, otmp->oy, 1, MAY_HIT, otmp); } newsym(x, y); newsym(x2, y2); if (!does_block(x2, y2, lev2)) unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { e_inview = e_canseemon(etmp2); if (!automiss(etmp2)) { if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); killer.format = KILLED_BY_AN; Strcpy(killer.name, "exploding drawbridge"); e_died(etmp2, e_inview ? 3 : 2, CRUSHING); /*no corpse*/ } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { e_inview = e_canseemon(etmp1); if (e_missed(etmp1, TRUE)) { debugpline1("%s spared!", E_phrase(etmp1, "are")); /* if there is water or lava here, fall in now */ if (is_u(etmp1)) spoteffects(FALSE); else (void) minliquid(etmp1->emon); } else { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline("%s into some heavy metal!", E_phrase(etmp1, "get")); else pline("%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (!Deaf && !is_u(etmp1) && !is_pool(x, y)) { You_hear("a crushing sound."); } else { debugpline1("%s from shrapnel", E_phrase(etmp1, "die")); } } killer.format = KILLED_BY_AN; Strcpy(killer.name, "collapsing drawbridge"); e_died(etmp1, e_inview ? 3 : 2, CRUSHING); /*no corpse*/ if (levl[etmp1->ex][etmp1->ey].typ == MOAT) do_entity(etmp1); } } } /*dbridge.c*/ nethack-3.6.0/src/decl.c0000664000076400007660000002621412617615230014007 0ustar paxedpaxed/* NetHack 3.6 decl.c $NHDT-Date: 1446975463 2015/11/08 09:37:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" int NDECL((*afternmv)); int NDECL((*occupation)); /* from xxxmain.c */ const char *hname = 0; /* name of the game (argv[0] of main) */ int hackpid = 0; /* current process id */ #if defined(UNIX) || defined(VMS) int locknum = 0; /* max num of simultaneous users */ #endif #ifdef DEF_PAGER char *catmore = 0; /* default pager */ #endif NEARDATA int bases[MAXOCLASSES] = DUMMY; NEARDATA int multi = 0; const char *multi_reason = NULL; NEARDATA int nroom = 0; NEARDATA int nsubroom = 0; NEARDATA int occtime = 0; /* maze limits must be even; masking off lowest bit guarantees that */ int x_maze_max = (COLNO - 1) & ~1, y_maze_max = (ROWNO - 1) & ~1; int otg_temp; /* used by object_to_glyph() [otg] */ NEARDATA int in_doagain = 0; /* * The following structure will be initialized at startup time with * the level numbers of some "important" things in the game. */ struct dgn_topology dungeon_topology = { DUMMY }; struct q_score quest_status = DUMMY; NEARDATA int warn_obj_cnt = 0; NEARDATA int smeq[MAXNROFROOMS + 1] = DUMMY; NEARDATA int doorindex = 0; NEARDATA char *save_cm = 0; NEARDATA struct kinfo killer = DUMMY; NEARDATA long done_money = 0; const char *nomovemsg = 0; NEARDATA char plname[PL_NSIZ] = DUMMY; /* player name */ NEARDATA char pl_character[PL_CSIZ] = DUMMY; NEARDATA char pl_race = '\0'; NEARDATA char pl_fruit[PL_FSIZ] = DUMMY; NEARDATA struct fruit *ffruit = (struct fruit *) 0; NEARDATA char tune[6] = DUMMY; const char *occtxt = DUMMY; const char quitchars[] = " \r\n\033"; const char vowels[] = "aeiouAEIOU"; const char ynchars[] = "yn"; const char ynqchars[] = "ynq"; const char ynaqchars[] = "ynaq"; const char ynNaqchars[] = "yn#aq"; NEARDATA long yn_number = 0L; const char disclosure_options[] = "iavgco"; #if defined(MICRO) || defined(WIN32) char hackdir[PATHLEN]; /* where rumors, help, record are */ #ifdef MICRO char levels[PATHLEN]; /* where levels are */ #endif #endif /* MICRO || WIN32 */ #ifdef MFLOPPY char permbones[PATHLEN]; /* where permanent copy of bones go */ int ramdisk = FALSE; /* whether to copy bones to levels or not */ int saveprompt = TRUE; const char *alllevels = "levels.*"; const char *allbones = "bones*.*"; #endif struct linfo level_info[MAXLINFO]; NEARDATA struct sinfo program_state; /* x/y/z deltas for the 10 movement directions (8 compass pts, 2 up/down) */ const schar xdir[10] = { -1, -1, 0, 1, 1, 1, 0, -1, 0, 0 }; const schar ydir[10] = { 0, -1, -1, -1, 0, 1, 1, 1, 0, 0 }; const schar zdir[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, -1 }; NEARDATA schar tbx = 0, tby = 0; /* mthrowu: target */ /* for xname handling of multiple shot missile volleys: number of shots, index of current one, validity check, shoot vs throw */ NEARDATA struct multishot m_shot = { 0, 0, STRANGE_OBJECT, FALSE }; NEARDATA dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */ NEARDATA s_level *sp_levchn; NEARDATA stairway upstair = { 0, 0, { 0, 0 }, 0 }, dnstair = { 0, 0, { 0, 0 }, 0 }; NEARDATA stairway upladder = { 0, 0, { 0, 0 }, 0 }, dnladder = { 0, 0, { 0, 0 }, 0 }; NEARDATA stairway sstairs = { 0, 0, { 0, 0 }, 0 }; NEARDATA dest_area updest = { 0, 0, 0, 0, 0, 0, 0, 0 }; NEARDATA dest_area dndest = { 0, 0, 0, 0, 0, 0, 0, 0 }; NEARDATA coord inv_pos = { 0, 0 }; NEARDATA boolean defer_see_monsters = FALSE; NEARDATA boolean in_mklev = FALSE; NEARDATA boolean stoned = FALSE; /* done to monsters hit by 'c' */ NEARDATA boolean unweapon = FALSE; NEARDATA boolean mrg_to_wielded = FALSE; /* weapon picked is merged with wielded one */ NEARDATA boolean in_steed_dismounting = FALSE; NEARDATA coord bhitpos = DUMMY; NEARDATA coord doors[DOORMAX] = { DUMMY }; NEARDATA struct mkroom rooms[(MAXNROFROOMS + 1) * 2] = { DUMMY }; NEARDATA struct mkroom *subrooms = &rooms[MAXNROFROOMS + 1]; struct mkroom *upstairs_room, *dnstairs_room, *sstairs_room; dlevel_t level; /* level map */ struct trap *ftrap = (struct trap *) 0; NEARDATA struct monst youmonst = DUMMY; NEARDATA struct context_info context = DUMMY; NEARDATA struct flag flags = DUMMY; #ifdef SYSFLAGS NEARDATA struct sysflag sysflags = DUMMY; #endif NEARDATA struct instance_flags iflags = DUMMY; NEARDATA struct you u = DUMMY; NEARDATA time_t ubirthday = DUMMY; NEARDATA struct u_realtime urealtime = DUMMY; schar lastseentyp[COLNO][ROWNO] = { DUMMY }; /* last seen/touched dungeon typ */ NEARDATA struct obj *invent = (struct obj *) 0, *uwep = (struct obj *) 0, *uarm = (struct obj *) 0, *uswapwep = (struct obj *) 0, *uquiver = (struct obj *) 0, /* quiver */ *uarmu = (struct obj *) 0, /* under-wear, so to speak */ *uskin = (struct obj *) 0, /* dragon armor, if a dragon */ *uarmc = (struct obj *) 0, *uarmh = (struct obj *) 0, *uarms = (struct obj *) 0, *uarmg = (struct obj *) 0, *uarmf = (struct obj *) 0, *uamul = (struct obj *) 0, *uright = (struct obj *) 0, *uleft = (struct obj *) 0, *ublindf = (struct obj *) 0, *uchain = (struct obj *) 0, *uball = (struct obj *) 0; /* some objects need special handling during destruction or placement */ NEARDATA struct obj *current_wand = 0, /* wand currently zapped/applied */ *thrownobj = 0, /* object in flight due to throwing */ *kickedobj = 0; /* object in flight due to kicking */ #ifdef TEXTCOLOR /* * This must be the same order as used for buzz() in zap.c. */ const int zapcolors[NUM_ZAP] = { HI_ZAP, /* 0 - missile */ CLR_ORANGE, /* 1 - fire */ CLR_WHITE, /* 2 - frost */ HI_ZAP, /* 3 - sleep */ CLR_BLACK, /* 4 - death */ CLR_WHITE, /* 5 - lightning */ CLR_YELLOW, /* 6 - poison gas */ CLR_GREEN, /* 7 - acid */ }; #endif /* text color */ const int shield_static[SHIELD_COUNT] = { S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, /* 7 per row */ S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, }; NEARDATA struct spell spl_book[MAXSPELL + 1] = { DUMMY }; NEARDATA long moves = 1L, monstermoves = 1L; /* These diverge when player is Fast */ NEARDATA long wailmsg = 0L; /* objects that are moving to another dungeon level */ NEARDATA struct obj *migrating_objs = (struct obj *) 0; /* objects not yet paid for */ NEARDATA struct obj *billobjs = (struct obj *) 0; /* used to zero all elements of a struct obj */ NEARDATA struct obj zeroobj = DUMMY; /* used to zero out union any; initializer deliberately omitted */ NEARDATA anything zeroany; /* originally from dog.c */ NEARDATA char dogname[PL_PSIZ] = DUMMY; NEARDATA char catname[PL_PSIZ] = DUMMY; NEARDATA char horsename[PL_PSIZ] = DUMMY; char preferred_pet; /* '\0', 'c', 'd', 'n' (none) */ /* monsters that went down/up together with @ */ NEARDATA struct monst *mydogs = (struct monst *) 0; /* monsters that are moving to another dungeon level */ NEARDATA struct monst *migrating_mons = (struct monst *) 0; NEARDATA struct mvitals mvitals[NUMMONS]; NEARDATA struct c_color_names c_color_names = { "black", "amber", "golden", "light blue", "red", "green", "silver", "blue", "purple", "white", "orange" }; struct menucoloring *menu_colorings = NULL; const char *c_obj_colors[] = { "black", /* CLR_BLACK */ "red", /* CLR_RED */ "green", /* CLR_GREEN */ "brown", /* CLR_BROWN */ "blue", /* CLR_BLUE */ "magenta", /* CLR_MAGENTA */ "cyan", /* CLR_CYAN */ "gray", /* CLR_GRAY */ "transparent", /* no_color */ "orange", /* CLR_ORANGE */ "bright green", /* CLR_BRIGHT_GREEN */ "yellow", /* CLR_YELLOW */ "bright blue", /* CLR_BRIGHT_BLUE */ "bright magenta", /* CLR_BRIGHT_MAGENTA */ "bright cyan", /* CLR_BRIGHT_CYAN */ "white", /* CLR_WHITE */ }; struct c_common_strings c_common_strings = { "Nothing happens.", "That's enough tries!", "That is a silly thing to %s.", "shudder for a moment.", "something", "Something", "You can move again.", "Never mind.", "vision quickly clears.", { "the", "your" } }; /* NOTE: the order of these words exactly corresponds to the order of oc_material values #define'd in objclass.h. */ const char *materialnm[] = { "mysterious", "liquid", "wax", "organic", "flesh", "paper", "cloth", "leather", "wooden", "bone", "dragonhide", "iron", "metal", "copper", "silver", "gold", "platinum", "mithril", "plastic", "glass", "gemstone", "stone" }; /* Vision */ NEARDATA boolean vision_full_recalc = 0; NEARDATA char **viz_array = 0; /* used in cansee() and couldsee() macros */ /* Global windowing data, defined here for multi-window-system support */ NEARDATA winid WIN_MESSAGE = WIN_ERR; #ifndef STATUS_VIA_WINDOWPORT NEARDATA winid WIN_STATUS = WIN_ERR; #endif NEARDATA winid WIN_MAP = WIN_ERR, WIN_INVEN = WIN_ERR; char toplines[TBUFSZ]; /* Windowing stuff that's really tty oriented, but present for all ports */ struct tc_gbl_data tc_gbl_data = { 0, 0, 0, 0 }; /* AS,AE, LI,CO */ char *fqn_prefix[PREFIX_COUNT] = { (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0 }; #ifdef PREFIXES_IN_USE char *fqn_prefix_names[PREFIX_COUNT] = { "hackdir", "leveldir", "savedir", "bonesdir", "datadir", "scoredir", "lockdir", "sysconfdir", "configdir", "troubledir" }; #endif NEARDATA struct savefile_info sfcap = { #ifdef NHSTDC 0x00000000UL #else 0x00000000L #endif #if defined(COMPRESS) || defined(ZLIB_COMP) | SFI1_EXTERNALCOMP #endif #if defined(ZEROCOMP) | SFI1_ZEROCOMP #endif #if defined(RLECOMP) | SFI1_RLECOMP #endif , #ifdef NHSTDC 0x00000000UL, 0x00000000UL #else 0x00000000L, 0x00000000L #endif }; NEARDATA struct savefile_info sfrestinfo, sfsaveinfo = { #ifdef NHSTDC 0x00000000UL #else 0x00000000L #endif #if defined(COMPRESS) || defined(ZLIB_COMP) | SFI1_EXTERNALCOMP #endif #if defined(ZEROCOMP) | SFI1_ZEROCOMP #endif #if defined(RLECOMP) | SFI1_RLECOMP #endif , #ifdef NHSTDC 0x00000000UL, 0x00000000UL #else 0x00000000L, 0x00000000L #endif }; struct plinemsg_type *plinemsg_types = (struct plinemsg_type *) 0; #ifdef PANICTRACE char *ARGV0; #endif /* support for lint.h */ unsigned nhUse_dummy = 0; /* dummy routine used to force linkage */ void decl_init() { return; } /*decl.c*/ nethack-3.6.0/src/detect.c0000664000076400007660000014736012625033011014344 0ustar paxedpaxed/* NetHack 3.6 detect.c $NHDT-Date: 1446369464 2015/11/01 09:17:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.61 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * Detection routines, including crystal ball, magic mapping, and search * command. */ #include "hack.h" #include "artifact.h" extern boolean known; /* from read.c */ STATIC_DCL void FDECL(do_dknown_of, (struct obj *)); STATIC_DCL boolean FDECL(check_map_spot, (int, int, CHAR_P, unsigned)); STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P, unsigned)); STATIC_DCL void FDECL(sense_trap, (struct trap *, XCHAR_P, XCHAR_P, int)); STATIC_DCL int FDECL(detect_obj_traps, (struct obj *, BOOLEAN_P, int)); STATIC_DCL void FDECL(show_map_spot, (int, int)); STATIC_PTR void FDECL(findone, (int, int, genericptr_t)); STATIC_PTR void FDECL(openone, (int, int, genericptr_t)); /* Recursively search obj for an object in class oclass and return 1st found */ struct obj * o_in(obj, oclass) struct obj *obj; char oclass; { register struct obj *otmp; struct obj *temp; if (obj->oclass == oclass) return obj; if (Has_contents(obj)) { for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (otmp->oclass == oclass) return otmp; else if (Has_contents(otmp) && (temp = o_in(otmp, oclass))) return temp; } return (struct obj *) 0; } /* Recursively search obj for an object made of specified material. * Return first found. */ struct obj * o_material(obj, material) struct obj *obj; unsigned material; { register struct obj *otmp; struct obj *temp; if (objects[obj->otyp].oc_material == material) return obj; if (Has_contents(obj)) { for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (objects[otmp->otyp].oc_material == material) return otmp; else if (Has_contents(otmp) && (temp = o_material(otmp, material))) return temp; } return (struct obj *) 0; } STATIC_OVL void do_dknown_of(obj) struct obj *obj; { struct obj *otmp; obj->dknown = 1; if (Has_contents(obj)) { for (otmp = obj->cobj; otmp; otmp = otmp->nobj) do_dknown_of(otmp); } } /* Check whether the location has an outdated object displayed on it. */ STATIC_OVL boolean check_map_spot(x, y, oclass, material) int x, y; char oclass; unsigned material; { int glyph; register struct obj *otmp; register struct monst *mtmp; glyph = glyph_at(x, y); if (glyph_is_object(glyph)) { /* there's some object shown here */ if (oclass == ALL_CLASSES) { return (boolean) !(level.objects[x][y] /* stale if nothing here */ || ((mtmp = m_at(x, y)) != 0 && mtmp->minvent)); } else { if (material && objects[glyph_to_obj(glyph)].oc_material == material) { /* object shown here is of interest because material matches */ for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (o_material(otmp, GOLD)) return FALSE; /* didn't find it; perhaps a monster is carrying it */ if ((mtmp = m_at(x, y)) != 0) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (o_material(otmp, GOLD)) return FALSE; } /* detection indicates removal of this object from the map */ return TRUE; } if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) { /* obj shown here is of interest because its class matches */ for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (o_in(otmp, oclass)) return FALSE; /* didn't find it; perhaps a monster is carrying it */ if ((mtmp = m_at(x, y)) != 0) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (o_in(otmp, oclass)) return FALSE; } /* detection indicates removal of this object from the map */ return TRUE; } } } return FALSE; } /* * When doing detection, remove stale data from the map display (corpses * rotted away, objects carried away by monsters, etc) so that it won't * reappear after the detection has completed. Return true if noticeable * change occurs. */ STATIC_OVL boolean clear_stale_map(oclass, material) char oclass; unsigned material; { register int zx, zy; boolean change_made = FALSE; for (zx = 1; zx < COLNO; zx++) for (zy = 0; zy < ROWNO; zy++) if (check_map_spot(zx, zy, oclass, material)) { unmap_object(zx, zy); change_made = TRUE; } return change_made; } /* look for gold, on the floor or in monsters' possession */ int gold_detect(sobj) register struct obj *sobj; { register struct obj *obj; register struct monst *mtmp; struct obj *temp; boolean stale; known = stale = clear_stale_map(COIN_CLASS, (unsigned) (sobj->blessed ? GOLD : 0)); /* look for gold carried by monsters (might be in a container) */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; /* probably not needed in this case but... */ if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { known = TRUE; goto outgoldmap; /* skip further searching */ } else for (obj = mtmp->minvent; obj; obj = obj->nobj) if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; goto outgoldmap; } else if (o_in(obj, COIN_CLASS)) { known = TRUE; goto outgoldmap; /* skip further searching */ } } /* look for gold objects */ for (obj = fobj; obj; obj = obj->nobj) { if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; } else if (o_in(obj, COIN_CLASS)) { known = TRUE; if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; } } if (!known) { /* no gold found on floor or monster's inventory. adjust message if you have gold in your inventory */ if (sobj) { char buf[BUFSZ]; if (youmonst.data == &mons[PM_GOLD_GOLEM]) { Sprintf(buf, "You feel like a million %s!", currency(2L)); } else if (hidden_gold() || money_cnt(invent)) Strcpy(buf, "You feel worried about your future financial situation."); else Strcpy(buf, "You feel materially poor."); strange_feeling(sobj, buf); } return 1; } /* only under me - no separate display required */ if (stale) docrt(); You("notice some gold between your %s.", makeplural(body_part(FOOT))); return 0; outgoldmap: cls(); iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; u.uinwater = u.uburied = 0; /* Discover gold locations. */ for (obj = fobj; obj; obj = obj->nobj) { if (sobj->blessed && (temp = o_material(obj, GOLD))) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp, 1); } else if ((temp = o_in(obj, COIN_CLASS))) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp, 1); } } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; /* probably overkill here */ if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { struct obj gold; gold = zeroobj; /* ensure oextra is cleared too */ gold.otyp = GOLD_PIECE; gold.ox = mtmp->mx; gold.oy = mtmp->my; map_object(&gold, 1); } else for (obj = mtmp->minvent; obj; obj = obj->nobj) if (sobj->blessed && (temp = o_material(obj, GOLD))) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp, 1); break; } else if ((temp = o_in(obj, COIN_CLASS))) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp, 1); break; } } newsym(u.ux, u.uy); u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; You_feel("very greedy, and sense gold!"); exercise(A_WIS, TRUE); display_nhwindow(WIN_MAP, TRUE); docrt(); if (Underwater) under_water(2); if (u.uburied) under_ground(2); return 0; } /* returns 1 if nothing was detected */ /* returns 0 if something was detected */ int food_detect(sobj) register struct obj *sobj; { register struct obj *obj; register struct monst *mtmp; register int ct = 0, ctu = 0; boolean confused = (Confusion || (sobj && sobj->cursed)), stale; char oclass = confused ? POTION_CLASS : FOOD_CLASS; const char *what = confused ? something : "food"; stale = clear_stale_map(oclass, 0); for (obj = fobj; obj; obj = obj->nobj) if (o_in(obj, oclass)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; else ct++; } for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) { /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */ for (obj = mtmp->minvent; obj; obj = obj->nobj) if (o_in(obj, oclass)) { ct++; break; } } if (!ct && !ctu) { known = stale && !confused; if (stale) { docrt(); You("sense a lack of %s nearby.", what); if (sobj && sobj->blessed) { if (!u.uedibility) Your("%s starts to tingle.", body_part(NOSE)); u.uedibility = 1; } } else if (sobj) { char buf[BUFSZ]; Sprintf(buf, "Your %s twitches%s.", body_part(NOSE), (sobj->blessed && !u.uedibility) ? " then starts to tingle" : ""); if (sobj->blessed && !u.uedibility) { boolean savebeginner = flags.beginner; flags.beginner = FALSE; /* prevent non-delivery of message */ strange_feeling(sobj, buf); flags.beginner = savebeginner; u.uedibility = 1; } else strange_feeling(sobj, buf); } return !stale; } else if (!ct) { known = TRUE; You("%s %s nearby.", sobj ? "smell" : "sense", what); if (sobj && sobj->blessed) { if (!u.uedibility) pline("Your %s starts to tingle.", body_part(NOSE)); u.uedibility = 1; } } else { struct obj *temp; known = TRUE; cls(); iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; u.uinwater = u.uburied = 0; for (obj = fobj; obj; obj = obj->nobj) if ((temp = o_in(obj, oclass)) != 0) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp, 1); } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) /* no DEADMONSTER(mtmp) check needed since dmons never have * inventory */ for (obj = mtmp->minvent; obj; obj = obj->nobj) if ((temp = o_in(obj, oclass)) != 0) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp, 1); break; /* skip rest of this monster's inventory */ } newsym(u.ux, u.uy); u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; if (sobj) { if (sobj->blessed) { Your("%s %s to tingle and you smell %s.", body_part(NOSE), u.uedibility ? "continues" : "starts", what); u.uedibility = 1; } else Your("%s tingles and you smell %s.", body_part(NOSE), what); } else You("sense %s.", what); display_nhwindow(WIN_MAP, TRUE); exercise(A_WIS, TRUE); docrt(); if (Underwater) under_water(2); if (u.uburied) under_ground(2); } return 0; } /* * Used for scrolls, potions, spells, and crystal balls. Returns: * * 1 - nothing was detected * 0 - something was detected */ int object_detect(detector, class) struct obj *detector; /* object doing the detecting */ int class; /* an object class, 0 for all */ { register int x, y; char stuff[BUFSZ]; int is_cursed = (detector && detector->cursed); int do_dknown = (detector && (detector->oclass == POTION_CLASS || detector->oclass == SPBOOK_CLASS) && detector->blessed); int ct = 0, ctu = 0; register struct obj *obj, *otmp = (struct obj *) 0; register struct monst *mtmp; int sym, boulder = 0; if (class < 0 || class >= MAXOCLASSES) { impossible("object_detect: illegal class %d", class); class = 0; } /* Special boulder symbol check - does the class symbol happen * to match iflags.bouldersym which is a user-defined? * If so, that means we aren't sure what they really wanted to * detect. Rather than trump anything, show both possibilities. * We can exclude checking the buried obj chain for boulders below. */ sym = class ? def_oc_syms[class].sym : 0; if (sym && iflags.bouldersym && sym == iflags.bouldersym) boulder = ROCK_CLASS; if (Hallucination || (Confusion && class == SCROLL_CLASS)) Strcpy(stuff, something); else Strcpy(stuff, class ? def_oc_syms[class].name : "objects"); if (boulder && class != ROCK_CLASS) Strcat(stuff, " and/or large stones"); if (do_dknown) for (obj = invent; obj; obj = obj->nobj) do_dknown_of(obj); for (obj = fobj; obj; obj = obj->nobj) { if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; else ct++; } if (do_dknown) do_dknown_of(obj); } for (obj = level.buriedobjlist; obj; obj = obj->nobj) { if (!class || o_in(obj, class)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; else ct++; } if (do_dknown) do_dknown_of(obj); } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) { if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++; if (do_dknown) do_dknown_of(obj); } if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT && (!class || class == objects[mtmp->mappearance].oc_class)) || (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) { ct++; break; } } if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) { if (!ctu) { if (detector) strange_feeling(detector, "You feel a lack of something."); return 1; } You("sense %s nearby.", stuff); return 0; } cls(); iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; u.uinwater = u.uburied = 0; /* * Map all buried objects first. */ for (obj = level.buriedobjlist; obj; obj = obj->nobj) if (!class || (otmp = o_in(obj, class))) { if (class) { if (otmp != obj) { otmp->ox = obj->ox; otmp->oy = obj->oy; } map_object(otmp, 1); } else map_object(obj, 1); } /* * If we are mapping all objects, map only the top object of a pile or * the first object in a monster's inventory. Otherwise, go looking * for a matching object class and display the first one encountered * at each location. * * Objects on the floor override buried objects. */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if ((!class && !boulder) || (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) { if (class || boulder) { if (otmp != obj) { otmp->ox = obj->ox; otmp->oy = obj->oy; } map_object(otmp, 1); } else map_object(obj, 1); break; } /* Objects in the monster's inventory override floor objects. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) if ((!class && !boulder) || (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) { if (!class && !boulder) otmp = obj; otmp->ox = mtmp->mx; /* at monster location */ otmp->oy = mtmp->my; map_object(otmp, 1); break; } /* Allow a mimic to override the detected objects it is carrying. */ if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT && (!class || class == objects[mtmp->mappearance].oc_class)) { struct obj temp; temp.oextra = (struct oextra *) 0; temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */ temp.ox = mtmp->mx; temp.oy = mtmp->my; temp.corpsenm = PM_TENGU; /* if mimicing a corpse */ map_object(&temp, 1); } else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) { struct obj gold; gold = zeroobj; /* ensure oextra is cleared too */ gold.otyp = GOLD_PIECE; gold.ox = mtmp->mx; gold.oy = mtmp->my; map_object(&gold, 1); } } newsym(u.ux, u.uy); u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; You("detect the %s of %s.", ct ? "presence" : "absence", stuff); display_nhwindow(WIN_MAP, TRUE); /* * What are we going to do when the hero does an object detect while blind * and the detected object covers a known pool? */ docrt(); /* this will correctly reset vision */ if (Underwater) under_water(2); if (u.uburied) under_ground(2); return 0; } /* * Used by: crystal balls, potions, fountains * * Returns 1 if nothing was detected. * Returns 0 if something was detected. */ int monster_detect(otmp, mclass) register struct obj *otmp; /* detecting object (if any) */ int mclass; /* monster class, 0 for all */ { register struct monst *mtmp; int mcnt = 0; /* Note: This used to just check fmon for a non-zero value * but in versions since 3.3.0 fmon can test TRUE due to the * presence of dmons, so we have to find at least one * with positive hit-points to know for sure. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp)) { mcnt++; break; } if (!mcnt) { if (otmp) strange_feeling(otmp, Hallucination ? "You get the heebie jeebies." : "You feel threatened."); return 1; } else { boolean woken = FALSE; cls(); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (!mclass || mtmp->data->mlet == mclass || (mtmp->data == &mons[PM_LONG_WORM] && mclass == S_WORM_TAIL)) if (mtmp->mx > 0) { if (mclass && def_monsyms[mclass].sym == ' ') show_glyph(mtmp->mx, mtmp->my, detected_mon_to_glyph(mtmp)); else show_glyph(mtmp->mx, mtmp->my, mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp)); /* don't be stingy - display entire worm */ if (mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp, 0); } if (otmp && otmp->cursed && (mtmp->msleeping || !mtmp->mcanmove)) { mtmp->msleeping = mtmp->mfrozen = 0; mtmp->mcanmove = 1; woken = TRUE; } } display_self(); You("sense the presence of monsters."); if (woken) pline("Monsters sense the presence of you."); display_nhwindow(WIN_MAP, TRUE); docrt(); if (Underwater) under_water(2); if (u.uburied) under_ground(2); } return 0; } STATIC_OVL void sense_trap(trap, x, y, src_cursed) struct trap *trap; xchar x, y; int src_cursed; { if (Hallucination || src_cursed) { struct obj obj; /* fake object */ obj.oextra = (struct oextra *) 0; if (trap) { obj.ox = trap->tx; obj.oy = trap->ty; } else { obj.ox = x; obj.oy = y; } obj.otyp = (src_cursed) ? GOLD_PIECE : random_object(); obj.corpsenm = random_monster(); /* if otyp == CORPSE */ map_object(&obj, 1); } else if (trap) { map_trap(trap, 1); trap->tseen = 1; } else { struct trap temp_trap; /* fake trap */ temp_trap.tx = x; temp_trap.ty = y; temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */ map_trap(&temp_trap, 1); } } #define OTRAP_NONE 0 /* nothing found */ #define OTRAP_HERE 1 /* found at hero's location */ #define OTRAP_THERE 2 /* found at any other location */ /* check a list of objects for chest traps; return 1 if found at , 2 if found at some other spot, 3 if both, 0 otherwise; optionally update the map to show where such traps were found */ STATIC_OVL int detect_obj_traps(objlist, show_them, how) struct obj *objlist; boolean show_them; int how; /* 1 for misleading map feedback */ { struct obj *otmp; xchar x, y; int result = OTRAP_NONE; for (otmp = objlist; otmp; otmp = otmp->nobj) { if (Is_box(otmp) && otmp->otrapped && get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) { result |= (x == u.ux && y == u.uy) ? OTRAP_HERE : OTRAP_THERE; if (show_them) sense_trap((struct trap *) 0, x, y, how); } if (Has_contents(otmp)) result |= detect_obj_traps(otmp->cobj, show_them, how); } return result; } /* the detections are pulled out so they can * also be used in the crystal ball routine * returns 1 if nothing was detected * returns 0 if something was detected */ int trap_detect(sobj) register struct obj *sobj; /* sobj is null if crystal ball, *scroll if gold detection scroll */ { register struct trap *ttmp; struct monst *mon; int door, glyph, tr; int cursed_src = sobj && sobj->cursed; boolean found = FALSE; coord cc; /* floor/ceiling traps */ for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { if (ttmp->tx != u.ux || ttmp->ty != u.uy) goto outtrapmap; else found = TRUE; } /* chest traps (might be buried or carried) */ if ((tr = detect_obj_traps(fobj, FALSE, 0)) != OTRAP_NONE) { if (tr & OTRAP_THERE) goto outtrapmap; else found = TRUE; } if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0)) != OTRAP_NONE) { if (tr & OTRAP_THERE) goto outtrapmap; else found = TRUE; } for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; if ((tr = detect_obj_traps(mon->minvent, FALSE, 0)) != OTRAP_NONE) { if (tr & OTRAP_THERE) goto outtrapmap; else found = TRUE; } } if (detect_obj_traps(invent, FALSE, 0) != OTRAP_NONE) found = TRUE; /* door traps */ for (door = 0; door < doorindex; door++) { cc = doors[door]; if (levl[cc.x][cc.y].doormask & D_TRAPPED) { if (cc.x != u.ux || cc.y != u.uy) goto outtrapmap; else found = TRUE; } } if (!found) { char buf[BUFSZ]; Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE))); strange_feeling(sobj, buf); return 1; } /* traps exist, but only under me - no separate display required */ Your("%s itch.", makeplural(body_part(TOE))); return 0; outtrapmap: cls(); iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; u.uinwater = u.uburied = 0; /* show chest traps first, so that subsequent floor trap display will override if both types are present at the same location */ (void) detect_obj_traps(fobj, TRUE, cursed_src); (void) detect_obj_traps(level.buriedobjlist, TRUE, cursed_src); for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; (void) detect_obj_traps(mon->minvent, TRUE, cursed_src); } (void) detect_obj_traps(invent, TRUE, cursed_src); for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) sense_trap(ttmp, 0, 0, cursed_src); for (door = 0; door < doorindex; door++) { cc = doors[door]; if (levl[cc.x][cc.y].doormask & D_TRAPPED) sense_trap((struct trap *) 0, cc.x, cc.y, cursed_src); } /* redisplay hero unless sense_trap() revealed something at */ glyph = glyph_at(u.ux, u.uy); if (!(glyph_is_trap(glyph) || glyph_is_object(glyph))) newsym(u.ux, u.uy); u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; You_feel("%s.", cursed_src ? "very greedy" : "entrapped"); /* wait for user to respond, then reset map display to normal */ display_nhwindow(WIN_MAP, TRUE); docrt(); if (Underwater) under_water(2); if (u.uburied) under_ground(2); return 0; } const char * level_distance(where) d_level *where; { register schar ll = depth(&u.uz) - depth(where); register boolean indun = (u.uz.dnum == where->dnum); if (ll < 0) { if (ll < (-8 - rn2(3))) if (!indun) return "far away"; else return "far below"; else if (ll < -1) if (!indun) return "away below you"; else return "below you"; else if (!indun) return "in the distance"; else return "just below"; } else if (ll > 0) { if (ll > (8 + rn2(3))) if (!indun) return "far away"; else return "far above"; else if (ll > 1) if (!indun) return "away above you"; else return "above you"; else if (!indun) return "in the distance"; else return "just above"; } else if (!indun) return "in the distance"; else return "near you"; } static const struct { const char *what; d_level *where; } level_detects[] = { { "Delphi", &oracle_level }, { "Medusa's lair", &medusa_level }, { "a castle", &stronghold_level }, { "the Wizard of Yendor's tower", &wiz1_level }, }; void use_crystal_ball(optr) struct obj **optr; { char ch; int oops; struct obj *obj = *optr; if (Blind) { pline("Too bad you can't see %s.", the(xname(obj))); return; } oops = (rnd(20) > ACURR(A_INT) || obj->cursed); if (oops && (obj->spe > 0)) { switch (rnd(obj->oartifact ? 4 : 5)) { case 1: pline("%s too much to comprehend!", Tobjnam(obj, "are")); break; case 2: pline("%s you!", Tobjnam(obj, "confuse")); make_confused((HConfusion & TIMEOUT) + (long) rnd(100), FALSE); break; case 3: if (!resists_blnd(&youmonst)) { pline("%s your vision!", Tobjnam(obj, "damage")); make_blinded((Blinded & TIMEOUT) + (long) rnd(100), FALSE); if (!Blind) Your1(vision_clears); } else { pline("%s your vision.", Tobjnam(obj, "assault")); You("are unaffected!"); } break; case 4: pline("%s your mind!", Tobjnam(obj, "zap")); (void) make_hallucinated( (HHallucination & TIMEOUT) + (long) rnd(100), FALSE, 0L); break; case 5: pline("%s!", Tobjnam(obj, "explode")); useup(obj); *optr = obj = 0; /* it's gone */ /* physical damage cause by the shards and force */ losehp(Maybe_Half_Phys(rnd(30)), "exploding crystal ball", KILLED_BY_AN); break; } if (obj) consume_obj_charge(obj, TRUE); return; } if (Hallucination) { if (!obj->spe) { pline("All you see is funky %s haze.", hcolor((char *) 0)); } else { switch (rnd(6)) { case 1: You("grok some groovy globs of incandescent lava."); break; case 2: pline("Whoa! Psychedelic colors, %s!", poly_gender() == 1 ? "babe" : "dude"); break; case 3: pline_The("crystal pulses with sinister %s light!", hcolor((char *) 0)); break; case 4: You_see("goldfish swimming above fluorescent rocks."); break; case 5: You_see( "tiny snowflakes spinning around a miniature farmhouse."); break; default: pline("Oh wow... like a kaleidoscope!"); break; } consume_obj_charge(obj, TRUE); } return; } /* read a single character */ if (flags.verbose) You("may look for an object or monster symbol."); ch = yn_function("What do you look for?", (char *) 0, '\0'); /* Don't filter out ' ' here; it has a use */ if ((ch != def_monsyms[S_GHOST].sym) && index(quitchars, ch)) { if (flags.verbose) pline1(Never_mind); return; } You("peer into %s...", the(xname(obj))); nomul(-rnd(10)); multi_reason = "gazing into a crystal ball"; nomovemsg = ""; if (obj->spe <= 0) pline_The("vision is unclear."); else { int class; int ret = 0; makeknown(CRYSTAL_BALL); consume_obj_charge(obj, TRUE); /* special case: accept ']' as synonym for mimic * we have to do this before the def_char_to_objclass check */ if (ch == DEF_MIMIC_DEF) ch = DEF_MIMIC; if ((class = def_char_to_objclass(ch)) != MAXOCLASSES) ret = object_detect((struct obj *) 0, class); else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES) ret = monster_detect((struct obj *) 0, class); else if (iflags.bouldersym && (ch == iflags.bouldersym)) ret = object_detect((struct obj *) 0, ROCK_CLASS); else switch (ch) { case '^': ret = trap_detect((struct obj *) 0); break; default: { int i = rn2(SIZE(level_detects)); You_see("%s, %s.", level_detects[i].what, level_distance(level_detects[i].where)); } ret = 0; break; } if (ret) { if (!rn2(100)) /* make them nervous */ You_see("the Wizard of Yendor gazing out at you."); else pline_The("vision is unclear."); } } return; } STATIC_OVL void show_map_spot(x, y) register int x, y; { struct rm *lev; struct trap *t; int oldglyph; if (Confusion && rn2(7)) return; lev = &levl[x][y]; lev->seenv = SVALL; /* Secret corridors are found, but not secret doors. */ if (lev->typ == SCORR) { lev->typ = CORR; unblock_point(x, y); } /* * Force the real background, then if it's not furniture and there's * a known trap there, display the trap, else if there was an object * shown there, redisplay the object. So during mapping, furniture * takes precedence over traps, which take precedence over objects, * opposite to how normal vision behaves. */ oldglyph = glyph_at(x, y); if (level.flags.hero_memory) { magic_map_background(x, y, 0); newsym(x, y); /* show it, if not blocked */ } else { magic_map_background(x, y, 1); /* display it */ } if (!IS_FURNITURE(lev->typ)) { if ((t = t_at(x, y)) != 0 && t->tseen) { map_trap(t, 1); } else if (glyph_is_trap(oldglyph) || glyph_is_object(oldglyph)) { show_glyph(x, y, oldglyph); if (level.flags.hero_memory) lev->glyph = oldglyph; } } } void do_mapping() { register int zx, zy; iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; u.uinwater = u.uburied = 0; for (zx = 1; zx < COLNO; zx++) for (zy = 0; zy < ROWNO; zy++) show_map_spot(zx, zy); u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; if (!level.flags.hero_memory || Underwater) { flush_screen(1); /* flush temp screen */ display_nhwindow(WIN_MAP, TRUE); /* wait */ docrt(); } exercise(A_WIS, TRUE); } void do_vicinity_map() { register int zx, zy; int lo_y = (u.uy - 5 < 0 ? 0 : u.uy - 5), hi_y = (u.uy + 6 > ROWNO ? ROWNO : u.uy + 6), lo_x = (u.ux - 9 < 1 ? 1 : u.ux - 9), /* avoid column 0 */ hi_x = (u.ux + 10 > COLNO ? COLNO : u.ux + 10); for (zx = lo_x; zx < hi_x; zx++) for (zy = lo_y; zy < hi_y; zy++) show_map_spot(zx, zy); if (!level.flags.hero_memory || Underwater) { flush_screen(1); /* flush temp screen */ display_nhwindow(WIN_MAP, TRUE); /* wait */ docrt(); } } /* convert a secret door into a normal door */ void cvt_sdoor_to_door(lev) struct rm *lev; { int newmask = lev->doormask & ~WM_MASK; if (Is_rogue_level(&u.uz)) /* rogue didn't have doors, only doorways */ newmask = D_NODOOR; else /* newly exposed door is closed */ if (!(newmask & D_LOCKED)) newmask |= D_CLOSED; lev->typ = DOOR; lev->doormask = newmask; } STATIC_PTR void findone(zx, zy, num) int zx, zy; genericptr_t num; { register struct trap *ttmp; register struct monst *mtmp; if (levl[zx][zy].typ == SDOOR) { cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ magic_map_background(zx, zy, 0); newsym(zx, zy); (*(int *) num)++; } else if (levl[zx][zy].typ == SCORR) { levl[zx][zy].typ = CORR; unblock_point(zx, zy); magic_map_background(zx, zy, 0); newsym(zx, zy); (*(int *) num)++; } else if ((ttmp = t_at(zx, zy)) != 0) { if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) { ttmp->tseen = 1; newsym(zx, zy); (*(int *) num)++; } } else if ((mtmp = m_at(zx, zy)) != 0) { if (mtmp->m_ap_type) { seemimic(mtmp); (*(int *) num)++; } if (mtmp->mundetected && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) { mtmp->mundetected = 0; newsym(zx, zy); (*(int *) num)++; } if (!canspotmon(mtmp) && !glyph_is_invisible(levl[zx][zy].glyph)) map_invisible(zx, zy); } else if (glyph_is_invisible(levl[zx][zy].glyph)) { unmap_object(zx, zy); newsym(zx, zy); (*(int *) num)++; } } STATIC_PTR void openone(zx, zy, num) int zx, zy; genericptr_t num; { register struct trap *ttmp; register struct obj *otmp; int *num_p = (int *) num; if (OBJ_AT(zx, zy)) { for (otmp = level.objects[zx][zy]; otmp; otmp = otmp->nexthere) { if (Is_box(otmp) && otmp->olocked) { otmp->olocked = 0; (*num_p)++; } } /* let it fall to the next cases. could be on trap. */ } if (levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR && (levl[zx][zy].doormask & (D_CLOSED | D_LOCKED)))) { if (levl[zx][zy].typ == SDOOR) cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ if (levl[zx][zy].doormask & D_TRAPPED) { if (distu(zx, zy) < 3) b_trapped("door", 0); else Norep("You %s an explosion!", cansee(zx, zy) ? "see" : (!Deaf ? "hear" : "feel the shock of")); wake_nearto(zx, zy, 11 * 11); levl[zx][zy].doormask = D_NODOOR; } else levl[zx][zy].doormask = D_ISOPEN; unblock_point(zx, zy); newsym(zx, zy); (*num_p)++; } else if (levl[zx][zy].typ == SCORR) { levl[zx][zy].typ = CORR; unblock_point(zx, zy); newsym(zx, zy); (*num_p)++; } else if ((ttmp = t_at(zx, zy)) != 0) { struct monst *mon; boolean dummy; /* unneeded "you notice it arg" */ if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) { ttmp->tseen = 1; newsym(zx, zy); (*num_p)++; } mon = (zx == u.ux && zy == u.uy) ? &youmonst : m_at(zx, zy); if (openholdingtrap(mon, &dummy) || openfallingtrap(mon, TRUE, &dummy)) (*num_p)++; } else if (find_drawbridge(&zx, &zy)) { /* make sure it isn't an open drawbridge */ open_drawbridge(zx, zy); (*num_p)++; } } /* returns number of things found */ int findit() { int num = 0; if (u.uswallow) return 0; do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num); return num; } /* returns number of things found and opened */ int openit() { int num = 0; if (u.uswallow) { if (is_animal(u.ustuck->data)) { if (Blind) pline("Its mouth opens!"); else pline("%s opens its mouth!", Monnam(u.ustuck)); } expels(u.ustuck, u.ustuck->data, TRUE); return -1; } do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num); return num; } /* callback hack for overriding vision in do_clear_area() */ boolean detecting(func) void FDECL((*func), (int, int, genericptr_t)); { return (func == findone || func == openone); } void find_trap(trap) struct trap *trap; { int tt = what_trap(trap->ttyp); boolean cleared = FALSE; trap->tseen = 1; exercise(A_WIS, TRUE); feel_newsym(trap->tx, trap->ty); if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) { /* There's too much clutter to see your find otherwise */ cls(); map_trap(trap, 1); display_self(); cleared = TRUE; } You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation)); if (cleared) { display_nhwindow(WIN_MAP, TRUE); /* wait */ docrt(); } } int dosearch0(aflag) register int aflag; /* intrinsic autosearch vs explicit searching */ { #ifdef GCC_BUG /* some versions of gcc seriously muck up nested loops. if you get strange crashes while searching in a version compiled with gcc, try putting #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the makefile). */ volatile xchar x, y; #else register xchar x, y; #endif register struct trap *trap; register struct monst *mtmp; if (u.uswallow) { if (!aflag) pline("What are you looking for? The exit?"); } else { int fund = (uwep && uwep->oartifact && spec_ability(uwep, SPFX_SEARCH)) ? uwep->spe : 0; if (ublindf && ublindf->otyp == LENSES && !Blind) fund += 2; /* JDS: lenses help searching */ if (fund > 5) fund = 5; for (x = u.ux - 1; x < u.ux + 2; x++) for (y = u.uy - 1; y < u.uy + 2; y++) { if (!isok(x, y)) continue; if (x == u.ux && y == u.uy) continue; if (Blind && !aflag) feel_location(x, y); if (levl[x][y].typ == SDOOR) { if (rnl(7 - fund)) continue; cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ exercise(A_WIS, TRUE); nomul(0); feel_location(x, y); /* make sure it shows up */ You("find a hidden door."); } else if (levl[x][y].typ == SCORR) { if (rnl(7 - fund)) continue; levl[x][y].typ = CORR; unblock_point(x, y); /* vision */ exercise(A_WIS, TRUE); nomul(0); feel_location(x, y); /* make sure it shows up */ You("find a hidden passage."); } else { /* Be careful not to find anything in an SCORR or SDOOR */ if ((mtmp = m_at(x, y)) != 0 && !aflag) { if (mtmp->m_ap_type) { seemimic(mtmp); find: exercise(A_WIS, TRUE); if (!canspotmon(mtmp)) { if (glyph_is_invisible(levl[x][y].glyph)) { /* found invisible monster in a square * which already has an 'I' in it. * Logically, this should still take * time and lead to a return(1), but * if we did that the player would keep * finding the same monster every turn. */ continue; } else { You_feel("an unseen monster!"); map_invisible(x, y); } } else if (!sensemon(mtmp)) You("find %s.", mtmp->mtame ? y_monnam(mtmp) : a_monnam(mtmp)); return 1; } if (!canspotmon(mtmp)) { if (mtmp->mundetected && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) mtmp->mundetected = 0; newsym(x, y); goto find; } } /* see if an invisible monster has moved--if Blind, * feel_location() already did it */ if (!aflag && !mtmp && !Blind && glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } if ((trap = t_at(x, y)) && !trap->tseen && !rnl(8)) { nomul(0); if (trap->ttyp == STATUE_TRAP) { if (activate_statue_trap(trap, x, y, FALSE)) exercise(A_WIS, TRUE); return 1; } else { find_trap(trap); } } } } } return 1; } /* the 's' command -- explicit searching */ int dosearch() { return dosearch0(0); } /* Pre-map the sokoban levels */ void sokoban_detect() { register int x, y; register struct trap *ttmp; register struct obj *obj; /* Map the background and boulders */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { levl[x][y].seenv = SVALL; levl[x][y].waslit = TRUE; map_background(x, y, 1); if ((obj = sobj_at(BOULDER, x, y)) != 0) map_object(obj, 1); } /* Map the traps */ for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { ttmp->tseen = 1; map_trap(ttmp, 1); /* set sokoban_rules when there is at least one pit or hole */ if (ttmp->ttyp == PIT || ttmp->ttyp == HOLE) Sokoban = 1; } } /* idea from crawl; show known portion of map without any monsters, objects, or traps occluding the view of the underlying terrain */ void reveal_terrain(full, which_subset) int full; /* wizard|explore modes allow player to request full map */ int which_subset; /* when not full, whether to suppress objs and/or traps */ { if ((Hallucination || Stunned || Confusion) && !full) { You("are too disoriented for this."); } else { int x, y, glyph, levl_glyph, default_glyph; uchar seenv; unsigned save_swallowed; struct monst *mtmp; struct trap *t; char buf[BUFSZ]; boolean keep_traps = (which_subset & 1) !=0, keep_objs = (which_subset & 2) != 0, keep_mons = (which_subset & 4) != 0; /* actually always 0 */ save_swallowed = u.uswallow; iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied; u.uinwater = u.uburied = 0; u.uswallow = 0; default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone); /* for 'full', show the actual terrain for the entire level, otherwise what the hero remembers for seen locations with monsters, objects, and/or traps removed as caller dictates */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { seenv = (full || level.flags.hero_memory) ? levl[x][y].seenv : cansee(x, y) ? SVALL : 0; if (full) { levl[x][y].seenv = SVALL; glyph = back_to_glyph(x, y); levl[x][y].seenv = seenv; } else { levl_glyph = level.flags.hero_memory ? levl[x][y].glyph : seenv ? back_to_glyph(x, y) : default_glyph; /* glyph_at() returns the displayed glyph, which might be a monster. levl[][].glyph contains the remembered glyph, which will never be a monster (unless it is the invisible monster glyph, which is handled like an object, replacing any object or trap at its spot) */ glyph = !save_swallowed ? glyph_at(x, y) : levl_glyph; if (keep_mons && x == u.ux && y == u.uy && save_swallowed) glyph = mon_to_glyph(u.ustuck); else if (((glyph_is_monster(glyph) || glyph_is_warning(glyph)) && !keep_mons) || glyph_is_swallow(glyph)) glyph = levl_glyph; if (((glyph_is_object(glyph) && !keep_objs) || glyph_is_invisible(glyph)) && keep_traps && !covers_traps(x, y)) { if ((t = t_at(x, y)) != 0 && t->tseen) glyph = trap_to_glyph(t); } if ((glyph_is_object(glyph) && !keep_objs) || (glyph_is_trap(glyph) && !keep_traps) || glyph_is_invisible(glyph)) { if (!seenv) { glyph = default_glyph; } else if (lastseentyp[x][y] == levl[x][y].typ) { glyph = back_to_glyph(x, y); } else { /* look for a mimic here posing as furniture; if we don't find one, we'll have to fake it */ if ((mtmp = m_at(x, y)) != 0 && mtmp->m_ap_type == M_AP_FURNITURE) { glyph = cmap_to_glyph(mtmp->mappearance); } else { /* we have a topology type but we want a screen symbol in order to derive a glyph; some screen symbols need the flags field of levl[][] in addition to the type (to disambiguate STAIRS to S_upstair or S_dnstair, for example; current flags might not be intended for remembered type, but we've got no other choice) */ schar save_typ = levl[x][y].typ; levl[x][y].typ = lastseentyp[x][y]; glyph = back_to_glyph(x, y); levl[x][y].typ = save_typ; } } } } show_glyph(x, y, glyph); } /* [TODO: highlight hero's location somehow] */ u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied; if (save_swallowed) u.uswallow = 1; flush_screen(1); if (full) { Strcpy(buf, "underlying terrain"); } else { Strcpy(buf, "known terrain"); if (keep_traps) Sprintf(eos(buf), "%s traps", (keep_objs || keep_mons) ? "," : " and"); if (keep_objs) Sprintf(eos(buf), "%s%s objects", (keep_traps || keep_mons) ? "," : "", keep_mons ? "" : " and"); if (keep_mons) Sprintf(eos(buf), "%s and monsters", (keep_traps || keep_objs) ? "," : ""); } pline("Showing %s only...", buf); display_nhwindow(WIN_MAP, TRUE); /* give "--More--" prompt */ docrt(); /* redraw the screen, restoring regular map */ if (Underwater) under_water(2); if (u.uburied) under_ground(2); } return; } /*detect.c*/ nethack-3.6.0/src/dig.c0000664000076400007660000021425012631241231013632 0ustar paxedpaxed/* NetHack 3.6 dig.c $NHDT-Date: 1449269915 2015/12/04 22:58:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.103 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" static NEARDATA boolean did_dig_msg; STATIC_DCL boolean NDECL(rm_waslit); STATIC_DCL void FDECL(mkcavepos, (XCHAR_P, XCHAR_P, int, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P)); STATIC_DCL int NDECL(dig); STATIC_DCL void FDECL(dig_up_grave, (coord *)); STATIC_DCL int FDECL(adj_pit_checks, (coord *, char *)); STATIC_DCL void FDECL(pit_flow, (struct trap *, SCHAR_P)); /* Indices returned by dig_typ() */ #define DIGTYP_UNDIGGABLE 0 #define DIGTYP_ROCK 1 #define DIGTYP_STATUE 2 #define DIGTYP_BOULDER 3 #define DIGTYP_DOOR 4 #define DIGTYP_TREE 5 STATIC_OVL boolean rm_waslit() { register xchar x, y; if (levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit) return TRUE; for (x = u.ux - 2; x < u.ux + 3; x++) for (y = u.uy - 1; y < u.uy + 2; y++) if (isok(x, y) && levl[x][y].waslit) return TRUE; return FALSE; } /* Change level topology. Messes with vision tables and ignores things like * boulders in the name of a nice effect. Vision will get fixed up again * immediately after the effect is complete. */ STATIC_OVL void mkcavepos(x, y, dist, waslit, rockit) xchar x, y; int dist; boolean waslit, rockit; { register struct rm *lev; if (!isok(x, y)) return; lev = &levl[x][y]; if (rockit) { register struct monst *mtmp; if (IS_ROCK(lev->typ)) return; if (t_at(x, y)) return; /* don't cover the portal */ if ((mtmp = m_at(x, y)) != 0) /* make sure crucial monsters survive */ if (!passes_walls(mtmp->data)) (void) rloc(mtmp, TRUE); } else if (lev->typ == ROOM) return; unblock_point(x, y); /* make sure vision knows this location is open */ /* fake out saved state */ lev->seenv = 0; lev->doormask = 0; if (dist < 3) lev->lit = (rockit ? FALSE : TRUE); if (waslit) lev->waslit = (rockit ? FALSE : TRUE); lev->horizontal = FALSE; /* short-circuit vision recalc */ viz_array[y][x] = (dist < 3) ? (IN_SIGHT | COULD_SEE) : COULD_SEE; lev->typ = (rockit ? STONE : ROOM); if (dist >= 3) impossible("mkcavepos called with dist %d", dist); feel_newsym(x, y); } STATIC_OVL void mkcavearea(rockit) register boolean rockit; { int dist; xchar xmin = u.ux, xmax = u.ux; xchar ymin = u.uy, ymax = u.uy; register xchar i; register boolean waslit = rm_waslit(); if (rockit) pline("Crash! The ceiling collapses around you!"); else pline("A mysterious force %s cave around you!", (levl[u.ux][u.uy].typ == CORR) ? "creates a" : "extends the"); display_nhwindow(WIN_MESSAGE, TRUE); for (dist = 1; dist <= 2; dist++) { xmin--; xmax++; /* top and bottom */ if (dist < 2) { /* the area is wider that it is high */ ymin--; ymax++; for (i = xmin + 1; i < xmax; i++) { mkcavepos(i, ymin, dist, waslit, rockit); mkcavepos(i, ymax, dist, waslit, rockit); } } /* left and right */ for (i = ymin; i <= ymax; i++) { mkcavepos(xmin, i, dist, waslit, rockit); mkcavepos(xmax, i, dist, waslit, rockit); } flush_screen(1); /* make sure the new glyphs shows up */ delay_output(); } if (!rockit && levl[u.ux][u.uy].typ == CORR) { levl[u.ux][u.uy].typ = ROOM; if (waslit) levl[u.ux][u.uy].waslit = TRUE; newsym(u.ux, u.uy); /* in case player is invisible */ } vision_full_recalc = 1; /* everything changed */ } /* When digging into location , what are you actually digging into? */ int dig_typ(otmp, x, y) struct obj *otmp; xchar x, y; { boolean ispick; if (!otmp) return DIGTYP_UNDIGGABLE; ispick = is_pick(otmp); if (!ispick && !is_axe(otmp)) return DIGTYP_UNDIGGABLE; return ((ispick && sobj_at(STATUE, x, y)) ? DIGTYP_STATUE : (ispick && sobj_at(BOULDER, x, y)) ? DIGTYP_BOULDER : closed_door(x, y) ? DIGTYP_DOOR : IS_TREE(levl[x][y].typ) ? (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) : (ispick && IS_ROCK(levl[x][y].typ) && (!level.flags.arboreal || IS_WALL(levl[x][y].typ))) ? DIGTYP_ROCK : DIGTYP_UNDIGGABLE); } boolean is_digging() { if (occupation == dig) { return TRUE; } return FALSE; } #define BY_YOU (&youmonst) #define BY_OBJECT ((struct monst *) 0) boolean dig_check(madeby, verbose, x, y) struct monst *madeby; boolean verbose; int x, y; { struct trap *ttmp = t_at(x, y); const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; if (On_stairs(x, y)) { if (x == xdnladder || x == xupladder) { if (verbose) pline_The("ladder resists your effort."); } else if (verbose) pline_The("stairs are too hard to %s.", verb); return FALSE; } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) { if (verbose) pline_The("throne is too hard to break apart."); return FALSE; } else if (IS_ALTAR(levl[x][y].typ) && (madeby != BY_OBJECT || Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { if (verbose) pline_The("altar is too hard to break apart."); return FALSE; } else if (Is_airlevel(&u.uz)) { if (verbose) You("cannot %s thin air.", verb); return FALSE; } else if (Is_waterlevel(&u.uz)) { if (verbose) pline_The("water splashes and subsides."); return FALSE; } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR && (levl[x][y].wall_info & W_NONDIGGABLE) != 0) || (ttmp && (ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE || (!Can_dig_down(&u.uz) && !levl[x][y].candig)))) { if (verbose) pline_The("%s here is too hard to %s.", surface(x, y), verb); return FALSE; } else if (sobj_at(BOULDER, x, y)) { if (verbose) There("isn't enough room to %s here.", verb); return FALSE; } else if (madeby == BY_OBJECT /* the block against existing traps is mainly to prevent broken wands from turning holes into pits */ && (ttmp || is_pool_or_lava(x, y))) { /* digging by player handles pools separately */ return FALSE; } return TRUE; } STATIC_OVL int dig(VOID_ARGS) { register struct rm *lev; register xchar dpx = context.digging.pos.x, dpy = context.digging.pos.y; register boolean ispick = uwep && is_pick(uwep); const char *verb = (!uwep || is_pick(uwep)) ? "dig into" : "chop through"; lev = &levl[dpx][dpy]; /* perhaps a nymph stole your pick-axe while you were busy digging */ /* or perhaps you teleported away */ if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) || !on_level(&context.digging.level, &u.uz) || ((context.digging.down ? (dpx != u.ux || dpy != u.uy) : (distu(dpx, dpy) > 2)))) return 0; if (context.digging.down) { if (!dig_check(BY_YOU, TRUE, u.ux, u.uy)) return 0; } else { /* !context.digging.down */ if (IS_TREE(lev->typ) && !may_dig(dpx, dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) { pline("This tree seems to be petrified."); return 0; } if (IS_ROCK(lev->typ) && !may_dig(dpx, dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) { pline("This %s is too hard to %s.", is_db_wall(dpx, dpy) ? "drawbridge" : "wall", verb); return 0; } } if (Fumbling && !rn2(3)) { switch (rn2(3)) { case 0: if (!welded(uwep)) { You("fumble and drop %s.", yname(uwep)); dropx(uwep); } else { if (u.usteed) pline("%s and %s %s!", Yobjnam2(uwep, "bounce"), otense(uwep, "hit"), mon_nam(u.usteed)); else pline("Ouch! %s and %s you!", Yobjnam2(uwep, "bounce"), otense(uwep, "hit")); set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); } break; case 1: pline("Bang! You hit with the broad side of %s!", the(xname(uwep))); break; default: Your("swing misses its mark."); break; } return 0; } context.digging.effort += 10 + rn2(5) + abon() + uwep->spe - greatest_erosion(uwep) + u.udaminc; if (Race_if(PM_DWARF)) context.digging.effort *= 2; if (context.digging.down) { struct trap *ttmp = t_at(dpx, dpy); if (context.digging.effort > 250 || (ttmp && ttmp->ttyp == HOLE)) { (void) dighole(FALSE, FALSE, (coord *) 0); (void) memset((genericptr_t) &context.digging, 0, sizeof context.digging); return 0; /* done with digging */ } if (context.digging.effort <= 50 || (ttmp && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT))) { return 1; } else if (ttmp && (ttmp->ttyp == LANDMINE || (ttmp->ttyp == BEAR_TRAP && !u.utrap))) { /* digging onto a set object trap triggers it; hero should have used #untrap first */ dotrap(ttmp, FORCETRAP); /* restart completely from scratch if we resume digging */ (void) memset((genericptr_t) &context.digging, 0, sizeof context.digging); return 0; } else if (ttmp && ttmp->ttyp == BEAR_TRAP && u.utrap) { if (rnl(7) > (Fumbling ? 1 : 4)) { char kbuf[BUFSZ]; int dmg = dmgval(uwep, &youmonst) + dbon(); if (dmg < 1) dmg = 1; else if (uarmf) dmg = (dmg + 1) / 2; You("hit yourself in the %s.", body_part(FOOT)); Sprintf(kbuf, "chopping off %s own %s", uhis(), body_part(FOOT)); losehp(Maybe_Half_Phys(dmg), kbuf, KILLED_BY); } else { You("destroy the bear trap with %s.", yobjnam(uwep, (const char *) 0)); u.utrap = 0; /* release from trap */ deltrap(ttmp); } /* we haven't made any progress toward a pit yet */ context.digging.effort = 0; return 0; } if (IS_ALTAR(lev->typ)) { altar_wrath(dpx, dpy); angry_priest(); } /* make pit at */ if (dighole(TRUE, FALSE, (coord *) 0)) { context.digging.level.dnum = 0; context.digging.level.dlevel = -1; } return 0; } if (context.digging.effort > 100) { register const char *digtxt, *dmgtxt = (const char *) 0; register struct obj *obj; register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) { if (break_statue(obj)) digtxt = "The statue shatters."; else /* it was a statue trap; break_statue() * printed a message and updated the screen */ digtxt = (char *) 0; } else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) { struct obj *bobj; fracture_rock(obj); if ((bobj = sobj_at(BOULDER, dpx, dpy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(bobj); place_object(bobj, dpx, dpy); } digtxt = "The boulder falls apart."; } else if (lev->typ == STONE || lev->typ == SCORR || IS_TREE(lev->typ)) { if (Is_earthlevel(&u.uz)) { if (uwep->blessed && !rn2(3)) { mkcavearea(FALSE); goto cleanup; } else if ((uwep->cursed && !rn2(4)) || (!uwep->blessed && !rn2(6))) { mkcavearea(TRUE); goto cleanup; } } if (IS_TREE(lev->typ)) { digtxt = "You cut down the tree."; lev->typ = ROOM; if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy); } else { digtxt = "You succeed in cutting away some rock."; lev->typ = CORR; } } else if (IS_WALL(lev->typ)) { if (shopedge) { add_damage(dpx, dpy, 10L * ACURRSTR); dmgtxt = "damage"; } if (level.flags.is_maze_lev) { lev->typ = ROOM; } else if (level.flags.is_cavernous_lev && !in_town(dpx, dpy)) { lev->typ = CORR; } else { lev->typ = DOOR; lev->doormask = D_NODOOR; } digtxt = "You make an opening in the wall."; } else if (lev->typ == SDOOR) { cvt_sdoor_to_door(lev); /* ->typ = DOOR */ digtxt = "You break through a secret door!"; if (!(lev->doormask & D_TRAPPED)) lev->doormask = D_BROKEN; } else if (closed_door(dpx, dpy)) { digtxt = "You break through the door."; if (shopedge) { add_damage(dpx, dpy, 400L); dmgtxt = "break"; } if (!(lev->doormask & D_TRAPPED)) lev->doormask = D_BROKEN; } else return 0; /* statue or boulder got taken */ if (!does_block(dpx, dpy, &levl[dpx][dpy])) unblock_point(dpx, dpy); /* vision: can see through */ feel_newsym(dpx, dpy); if (digtxt && !context.digging.quiet) pline1(digtxt); /* after newsym */ if (dmgtxt) pay_for_damage(dmgtxt, FALSE); if (Is_earthlevel(&u.uz) && !rn2(3)) { register struct monst *mtmp; switch (rn2(2)) { case 0: mtmp = makemon(&mons[PM_EARTH_ELEMENTAL], dpx, dpy, NO_MM_FLAGS); break; default: mtmp = makemon(&mons[PM_XORN], dpx, dpy, NO_MM_FLAGS); break; } if (mtmp) pline_The("debris from your digging comes to life!"); } if (IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) { lev->doormask = D_NODOOR; b_trapped("door", 0); newsym(dpx, dpy); } cleanup: context.digging.lastdigtime = moves; context.digging.quiet = FALSE; context.digging.level.dnum = 0; context.digging.level.dlevel = -1; return 0; } else { /* not enough effort has been spent yet */ static const char *const d_target[6] = { "", "rock", "statue", "boulder", "door", "tree" }; int dig_target = dig_typ(uwep, dpx, dpy); if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) { if (*in_rooms(dpx, dpy, SHOPBASE)) { pline("This %s seems too hard to %s.", IS_DOOR(lev->typ) ? "door" : "wall", verb); return 0; } } else if (dig_target == DIGTYP_UNDIGGABLE || (dig_target == DIGTYP_ROCK && !IS_ROCK(lev->typ))) return 0; /* statue or boulder got taken */ if (!did_dig_msg) { You("hit the %s with all your might.", d_target[dig_target]); did_dig_msg = TRUE; } } return 1; } /* When will hole be finished? Very rough indication used by shopkeeper. */ int holetime() { if (occupation != dig || !*u.ushops) return -1; return ((250 - context.digging.effort) / 20); } /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */ schar fillholetyp(x, y, fill_if_any) int x, y; boolean fill_if_any; /* force filling if it exists at all */ { register int x1, y1; int lo_x = max(1, x - 1), hi_x = min(x + 1, COLNO - 1), lo_y = max(0, y - 1), hi_y = min(y + 1, ROWNO - 1); int pool_cnt = 0, moat_cnt = 0, lava_cnt = 0; for (x1 = lo_x; x1 <= hi_x; x1++) for (y1 = lo_y; y1 <= hi_y; y1++) if (is_moat(x1, y1)) moat_cnt++; else if (is_pool(x1, y1)) /* This must come after is_moat since moats are pools * but not vice-versa. */ pool_cnt++; else if (is_lava(x1, y1)) lava_cnt++; if (!fill_if_any) pool_cnt /= 3; /* not as much liquid as the others */ if ((lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1)) || (lava_cnt && fill_if_any)) return LAVAPOOL; else if ((moat_cnt > 0 && rn2(moat_cnt + 1)) || (moat_cnt && fill_if_any)) return MOAT; else if ((pool_cnt > 0 && rn2(pool_cnt + 1)) || (pool_cnt && fill_if_any)) return POOL; else return ROOM; } void digactualhole(x, y, madeby, ttyp) register int x, y; struct monst *madeby; int ttyp; { struct obj *oldobjs, *newobjs; register struct trap *ttmp; char surface_type[BUFSZ]; struct rm *lev = &levl[x][y]; boolean shopdoor; struct monst *mtmp = m_at(x, y); /* may be madeby */ boolean madeby_u = (madeby == BY_YOU); boolean madeby_obj = (madeby == BY_OBJECT); boolean at_u = (x == u.ux) && (y == u.uy); boolean wont_fall = Levitation || Flying; if (at_u && u.utrap) { if (u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); else if (u.utraptype == TT_INFLOOR) u.utrap = 0; } /* these furniture checks were in dighole(), but wand breaking bypasses that routine and calls us directly */ if (IS_FOUNTAIN(lev->typ)) { dogushforth(FALSE); SET_FOUNTAIN_WARNED(x, y); /* force dryup */ dryup(x, y, madeby_u); return; } else if (IS_SINK(lev->typ)) { breaksink(x, y); return; } else if (lev->typ == DRAWBRIDGE_DOWN || (is_drawbridge_wall(x, y) >= 0)) { int bx = x, by = y; /* if under the portcullis, the bridge is adjacent */ (void) find_drawbridge(&bx, &by); destroy_drawbridge(bx, by); return; } if (ttyp != PIT && (!Can_dig_down(&u.uz) && !lev->candig)) { impossible("digactualhole: can't dig %s on this level.", defsyms[trap_to_defsym(ttyp)].explanation); ttyp = PIT; } /* maketrap() might change it, also, in this situation, surface() returns an inappropriate string for a grave */ if (IS_GRAVE(lev->typ)) Strcpy(surface_type, "grave"); else Strcpy(surface_type, surface(x, y)); shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE); oldobjs = level.objects[x][y]; ttmp = maketrap(x, y, ttyp); if (!ttmp) return; newobjs = level.objects[x][y]; ttmp->madeby_u = madeby_u; ttmp->tseen = 0; if (cansee(x, y)) seetrap(ttmp); else if (madeby_u) feeltrap(ttmp); if (ttyp == PIT) { if (madeby_u) { if (x != u.ux || y != u.uy) You("dig an adjacent pit."); else You("dig a pit in the %s.", surface_type); if (shopdoor) pay_for_damage("ruin", FALSE); } else if (!madeby_obj && canseemon(madeby)) pline("%s digs a pit in the %s.", Monnam(madeby), surface_type); else if (cansee(x, y) && flags.verbose) pline("A pit appears in the %s.", surface_type); if (at_u) { if (!wont_fall) { u.utrap = rn1(4, 2); u.utraptype = TT_PIT; vision_full_recalc = 1; /* vision limits change */ } else u.utrap = 0; if (oldobjs != newobjs) /* something unearthed */ (void) pickup(1); /* detects pit */ } else if (mtmp) { if (is_flyer(mtmp->data) || is_floater(mtmp->data)) { if (canseemon(mtmp)) pline("%s %s over the pit.", Monnam(mtmp), (is_flyer(mtmp->data)) ? "flies" : "floats"); } else if (mtmp != madeby) (void) mintrap(mtmp); } } else { /* was TRAPDOOR now a HOLE*/ if (madeby_u) You("dig a hole through the %s.", surface_type); else if (!madeby_obj && canseemon(madeby)) pline("%s digs a hole through the %s.", Monnam(madeby), surface_type); else if (cansee(x, y) && flags.verbose) pline("A hole appears in the %s.", surface_type); if (at_u) { if (!u.ustuck && !wont_fall && !next_to_u()) { You("are jerked back by your pet!"); wont_fall = TRUE; } /* Floor objects get a chance of falling down. The case where * the hero does NOT fall down is treated here. The case * where the hero does fall down is treated in goto_level(). */ if (u.ustuck || wont_fall) { if (newobjs) impact_drop((struct obj *) 0, x, y, 0); if (oldobjs != newobjs) (void) pickup(1); if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE); } else { d_level newlevel; if (*u.ushops && madeby_u) shopdig(1); /* shk might snatch pack */ /* handle earlier damage, eg breaking wand of digging */ else if (!madeby_u) pay_for_damage("dig into", TRUE); You("fall through..."); /* Earlier checks must ensure that the destination * level exists and is in the present dungeon. */ newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel + 1; goto_level(&newlevel, FALSE, TRUE, FALSE); /* messages for arriving in special rooms */ spoteffects(FALSE); } } else { if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE); if (newobjs) impact_drop((struct obj *) 0, x, y, 0); if (mtmp) { /*[don't we need special sokoban handling here?]*/ if (is_flyer(mtmp->data) || is_floater(mtmp->data) || mtmp->data == &mons[PM_WUMPUS] || (mtmp->wormno && count_wsegs(mtmp) > 5) || mtmp->data->msize >= MZ_HUGE) return; if (mtmp == u.ustuck) /* probably a vortex */ return; /* temporary? kludge */ if (teleport_pet(mtmp, FALSE)) { d_level tolevel; if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { if (canseemon(mtmp)) pline("%s avoids the trap.", Monnam(mtmp)); return; } else { get_level(&tolevel, depth(&u.uz) + 1); } if (mtmp->isshk) make_angry_shk(mtmp, 0, 0); migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *) 0); } } } } } /* * Called from dighole(), but also from do_break_wand() * in apply.c. */ void liquid_flow(x, y, typ, ttmp, fillmsg) xchar x, y; schar typ; struct trap *ttmp; const char *fillmsg; { boolean u_spot = (x == u.ux && y == u.uy); if (ttmp) (void) delfloortrap(ttmp); /* if any objects were frozen here, they're released now */ unearth_objs(x, y); if (fillmsg) pline(fillmsg, typ == LAVAPOOL ? "lava" : "water"); if (u_spot && !(Levitation || Flying)) { if (typ == LAVAPOOL) (void) lava_effects(); else if (!Wwalking) (void) drown(); } } /* return TRUE if digging succeeded, FALSE otherwise */ boolean dighole(pit_only, by_magic, cc) boolean pit_only, by_magic; coord *cc; { register struct trap *ttmp; struct rm *lev; struct obj *boulder_here; schar typ; xchar dig_x, dig_y; boolean nohole; if (!cc) { dig_x = u.ux; dig_y = u.uy; } else { dig_x = cc->x; dig_y = cc->y; if (!isok(dig_x, dig_y)) return FALSE; } ttmp = t_at(dig_x, dig_y); lev = &levl[dig_x][dig_y]; nohole = (!Can_dig_down(&u.uz) && !lev->candig); if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE || nohole)) || (IS_ROCK(lev->typ) && lev->typ != SDOOR && (lev->wall_info & W_NONDIGGABLE) != 0)) { pline_The("%s %shere is too hard to dig in.", surface(dig_x, dig_y), (dig_x != u.ux || dig_y != u.uy) ? "t" : ""); } else if (is_pool_or_lava(dig_x, dig_y)) { pline_The("%s sloshes furiously for a moment, then subsides.", is_lava(dig_x, dig_y) ? "lava" : "water"); wake_nearby(); /* splashing */ } else if (lev->typ == DRAWBRIDGE_DOWN || (is_drawbridge_wall(dig_x, dig_y) >= 0)) { /* drawbridge_down is the platform crossing the moat when the bridge is extended; drawbridge_wall is the open "doorway" or closed "door" where the portcullis/mechanism is located */ if (pit_only) { pline_The("drawbridge seems too hard to dig through."); return FALSE; } else { int x = dig_x, y = dig_y; /* if under the portcullis, the bridge is adjacent */ (void) find_drawbridge(&x, &y); destroy_drawbridge(x, y); return TRUE; } } else if ((boulder_here = sobj_at(BOULDER, dig_x, dig_y)) != 0) { if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) && rn2(2)) { pline_The("boulder settles into the %spit.", (dig_x != u.ux || dig_y != u.uy) ? "adjacent " : ""); ttmp->ttyp = PIT; /* crush spikes */ } else { /* * digging makes a hole, but the boulder immediately * fills it. Final outcome: no hole, no boulder. */ pline("KADOOM! The boulder falls in!"); (void) delfloortrap(ttmp); } delobj(boulder_here); return TRUE; } else if (IS_GRAVE(lev->typ)) { digactualhole(dig_x, dig_y, BY_YOU, PIT); dig_up_grave(cc); return TRUE; } else if (lev->typ == DRAWBRIDGE_UP) { /* must be floor or ice, other cases handled above */ /* dig "pit" and let fluid flow in (if possible) */ typ = fillholetyp(dig_x, dig_y, FALSE); if (typ == ROOM) { /* * We can't dig a hole here since that will destroy * the drawbridge. The following is a cop-out. --dlc */ pline_The("%s %shere is too hard to dig in.", surface(dig_x, dig_y), (dig_x != u.ux || dig_y != u.uy) ? "t" : ""); return FALSE; } lev->drawbridgemask &= ~DB_UNDER; lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT; liquid_flow(dig_x, dig_y, typ, ttmp, "As you dig, the hole fills with %s!"); return TRUE; /* the following two are here for the wand of digging */ } else if (IS_THRONE(lev->typ)) { pline_The("throne is too hard to break apart."); } else if (IS_ALTAR(lev->typ)) { pline_The("altar is too hard to break apart."); } else { typ = fillholetyp(dig_x, dig_y, FALSE); if (typ != ROOM) { lev->typ = typ; liquid_flow(dig_x, dig_y, typ, ttmp, "As you dig, the hole fills with %s!"); return TRUE; } /* magical digging disarms settable traps */ if (by_magic && ttmp && (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP)) { int otyp = (ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP; /* convert trap into buried object (deletes trap) */ cnv_trap_obj(otyp, 1, ttmp, TRUE); } /* finally we get to make a hole */ if (nohole || pit_only) digactualhole(dig_x, dig_y, BY_YOU, PIT); else digactualhole(dig_x, dig_y, BY_YOU, HOLE); return TRUE; } return FALSE; } STATIC_OVL void dig_up_grave(cc) coord *cc; { struct obj *otmp; xchar dig_x, dig_y; if (!cc) { dig_x = u.ux; dig_y = u.uy; } else { dig_x = cc->x; dig_y = cc->y; if (!isok(dig_x, dig_y)) return; } /* Grave-robbing is frowned upon... */ exercise(A_WIS, FALSE); if (Role_if(PM_ARCHEOLOGIST)) { adjalign(-sgn(u.ualign.type) * 3); You_feel("like a despicable grave-robber!"); } else if (Role_if(PM_SAMURAI)) { adjalign(-sgn(u.ualign.type)); You("disturb the honorable dead!"); } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) { adjalign(-sgn(u.ualign.type)); You("have violated the sanctity of this grave!"); } switch (rn2(5)) { case 0: case 1: You("unearth a corpse."); if (!!(otmp = mk_tt_object(CORPSE, dig_x, dig_y))) otmp->age -= 100; /* this is an *OLD* corpse */ ; break; case 2: if (!Blind) pline(Hallucination ? "Dude! The living dead!" : "The grave's owner is very upset!"); (void) makemon(mkclass(S_ZOMBIE, 0), dig_x, dig_y, NO_MM_FLAGS); break; case 3: if (!Blind) pline(Hallucination ? "I want my mummy!" : "You've disturbed a tomb!"); (void) makemon(mkclass(S_MUMMY, 0), dig_x, dig_y, NO_MM_FLAGS); break; default: /* No corpse */ pline_The("grave seems unused. Strange...."); break; } levl[dig_x][dig_y].typ = ROOM; del_engr_at(dig_x, dig_y); newsym(dig_x, dig_y); return; } int use_pick_axe(obj) struct obj *obj; { const char *sdp, *verb; char *dsp, dirsyms[12], qbuf[BUFSZ]; boolean ispick; int rx, ry, downok, res = 0; /* Check tool */ if (obj != uwep) { if (!wield_tool(obj, "swing")) return 0; else res = 1; } ispick = is_pick(obj); verb = ispick ? "dig" : "chop"; if (u.utrap && u.utraptype == TT_WEB) { pline("%s you can't %s while entangled in a web.", /* res==0 => no prior message; res==1 => just got "You now wield a pick-axe." message */ !res ? "Unfortunately," : "But", verb); return res; } /* construct list of directions to show player for likely choices */ downok = !!can_reach_floor(FALSE); dsp = dirsyms; for (sdp = Cmd.dirchars; *sdp; ++sdp) { /* filter out useless directions */ if (u.uswallow) { ; /* all directions are viable when swallowed */ } else if (movecmd(*sdp)) { /* normal direction, within plane of the level map; movecmd() sets u.dx, u.dy, u.dz and returns !u.dz */ if (!dxdy_moveok()) continue; /* handle NODIAG */ rx = u.ux + u.dx; ry = u.uy + u.dy; if (!isok(rx, ry) || dig_typ(obj, rx, ry) == DIGTYP_UNDIGGABLE) continue; } else { /* up or down; we used to always include down, so that there would always be at least one choice shown, but it shouldn't be a likely candidate when floating high above the floor; include up instead in that situation (as a silly candidate rather than a likely one...) */ if ((u.dz > 0) ^ downok) continue; } /* include this direction */ *dsp++ = *sdp; } *dsp = 0; Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms); if (!getdir(qbuf)) return res; return use_pick_axe2(obj); } /* MRKR: use_pick_axe() is split in two to allow autodig to bypass */ /* the "In what direction do you want to dig?" query. */ /* use_pick_axe2() uses the existing u.dx, u.dy and u.dz */ int use_pick_axe2(obj) struct obj *obj; { register int rx, ry; register struct rm *lev; struct trap *trap, *trap_with_u; int dig_target; boolean ispick = is_pick(obj); const char *verbing = ispick ? "digging" : "chopping"; if (u.uswallow && attack(u.ustuck)) { ; /* return 1 */ } else if (Underwater) { pline("Turbulence torpedoes your %s attempts.", verbing); } else if (u.dz < 0) { if (Levitation) You("don't have enough leverage."); else You_cant("reach the %s.", ceiling(u.ux, u.uy)); } else if (!u.dx && !u.dy && !u.dz) { char buf[BUFSZ]; int dam; dam = rnd(2) + dbon() + obj->spe; if (dam <= 0) dam = 1; You("hit yourself with %s.", yname(uwep)); Sprintf(buf, "%s own %s", uhis(), OBJ_NAME(objects[obj->otyp])); losehp(Maybe_Half_Phys(dam), buf, KILLED_BY); context.botl = 1; return 1; } else if (u.dz == 0) { if (Stunned || (Confusion && !rn2(5))) confdir(); rx = u.ux + u.dx; ry = u.uy + u.dy; if (!isok(rx, ry)) { pline("Clash!"); return 1; } lev = &levl[rx][ry]; if (MON_AT(rx, ry) && attack(m_at(rx, ry))) return 1; dig_target = dig_typ(obj, rx, ry); if (dig_target == DIGTYP_UNDIGGABLE) { /* ACCESSIBLE or POOL */ trap = t_at(rx, ry); if (trap && trap->ttyp == WEB) { if (!trap->tseen) { seetrap(trap); There("is a spider web there!"); } pline("%s entangled in the web.", Yobjnam2(obj, "become")); /* you ought to be able to let go; tough luck */ /* (maybe `move_into_trap()' would be better) */ nomul(-d(2, 2)); multi_reason = "stuck in a spider web"; nomovemsg = "You pull free."; } else if (lev->typ == IRONBARS) { pline("Clang!"); wake_nearby(); } else if (IS_TREE(lev->typ)) You("need an axe to cut down a tree."); else if (IS_ROCK(lev->typ)) You("need a pick to dig rock."); else if (!ispick && (sobj_at(STATUE, rx, ry) || sobj_at(BOULDER, rx, ry))) { boolean vibrate = !rn2(3); pline("Sparks fly as you whack the %s.%s", sobj_at(STATUE, rx, ry) ? "statue" : "boulder", vibrate ? " The axe-handle vibrates violently!" : ""); if (vibrate) losehp(Maybe_Half_Phys(2), "axing a hard object", KILLED_BY); } else if (u.utrap && u.utraptype == TT_PIT && trap && (trap_with_u = t_at(u.ux, u.uy)) && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !conjoined_pits(trap, trap_with_u, FALSE)) { int idx; for (idx = 0; idx < 8; idx++) { if (xdir[idx] == u.dx && ydir[idx] == u.dy) break; } /* idx is valid if < 8 */ if (idx < 8) { int adjidx = (idx + 4) % 8; trap_with_u->conjoined |= (1 << idx); trap->conjoined |= (1 << adjidx); pline("You clear some debris from between the pits."); } } else if (u.utrap && u.utraptype == TT_PIT && (trap_with_u = t_at(u.ux, u.uy))) { You("swing %s, but the rubble has no place to go.", yobjnam(obj, (char *) 0)); } else You("swing %s through thin air.", yobjnam(obj, (char *) 0)); } else { static const char *const d_action[6] = { "swinging", "digging", "chipping the statue", "hitting the boulder", "chopping at the door", "cutting the tree" }; did_dig_msg = FALSE; context.digging.quiet = FALSE; if (context.digging.pos.x != rx || context.digging.pos.y != ry || !on_level(&context.digging.level, &u.uz) || context.digging.down) { if (flags.autodig && dig_target == DIGTYP_ROCK && !context.digging.down && context.digging.pos.x == u.ux && context.digging.pos.y == u.uy && (moves <= context.digging.lastdigtime + 2 && moves >= context.digging.lastdigtime)) { /* avoid messages if repeated autodigging */ did_dig_msg = TRUE; context.digging.quiet = TRUE; } context.digging.down = context.digging.chew = FALSE; context.digging.warned = FALSE; context.digging.pos.x = rx; context.digging.pos.y = ry; assign_level(&context.digging.level, &u.uz); context.digging.effort = 0; if (!context.digging.quiet) You("start %s.", d_action[dig_target]); } else { You("%s %s.", context.digging.chew ? "begin" : "continue", d_action[dig_target]); context.digging.chew = FALSE; } set_occupation(dig, verbing, 0); } } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { /* it must be air -- water checked above */ You("swing %s through thin air.", yobjnam(obj, (char *) 0)); } else if (!can_reach_floor(FALSE)) { cant_reach_floor(u.ux, u.uy, FALSE, FALSE); } else if (is_pool_or_lava(u.ux, u.uy)) { /* Monsters which swim also happen not to be able to dig */ You("cannot stay under%s long enough.", is_pool(u.ux, u.uy) ? "water" : " the lava"); } else if ((trap = t_at(u.ux, u.uy)) != 0 && uteetering_at_seen_pit(trap)) { dotrap(trap, FORCEBUNGLE); /* might escape trap and still be teetering at brink */ if (!u.utrap) cant_reach_floor(u.ux, u.uy, FALSE, TRUE); } else if (!ispick /* can only dig down with an axe when doing so will trigger or disarm a trap here */ && (!trap || (trap->ttyp != LANDMINE && trap->ttyp != BEAR_TRAP))) { pline("%s merely scratches the %s.", Yobjnam2(obj, (char *) 0), surface(u.ux, u.uy)); u_wipe_engr(3); } else { if (context.digging.pos.x != u.ux || context.digging.pos.y != u.uy || !on_level(&context.digging.level, &u.uz) || !context.digging.down) { context.digging.chew = FALSE; context.digging.down = TRUE; context.digging.warned = FALSE; context.digging.pos.x = u.ux; context.digging.pos.y = u.uy; assign_level(&context.digging.level, &u.uz); context.digging.effort = 0; You("start %s downward.", verbing); if (*u.ushops) shopdig(0); } else You("continue %s downward.", verbing); did_dig_msg = FALSE; set_occupation(dig, verbing, 0); } return 1; } /* * Town Watchmen frown on damage to the town walls, trees or fountains. * It's OK to dig holes in the ground, however. * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0 * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing) */ void watch_dig(mtmp, x, y, zap) struct monst *mtmp; xchar x, y; boolean zap; { struct rm *lev = &levl[x][y]; if (in_town(x, y) && (closed_door(x, y) || lev->typ == SDOOR || IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) { if (!mtmp) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data) && mtmp->mcansee && m_canseeu(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) break; } } if (mtmp) { if (zap || context.digging.warned) { verbalize("Halt, vandal! You're under arrest!"); (void) angry_guards(!!Deaf); } else { const char *str; if (IS_DOOR(lev->typ)) str = "door"; else if (IS_TREE(lev->typ)) str = "tree"; else if (IS_ROCK(lev->typ)) str = "wall"; else str = "fountain"; verbalize("Hey, stop damaging that %s!", str); context.digging.warned = TRUE; } if (is_digging()) stop_occupation(); } } } /* Return TRUE if monster died, FALSE otherwise. Called from m_move(). */ boolean mdig_tunnel(mtmp) register struct monst *mtmp; { register struct rm *here; int pile = rnd(12); here = &levl[mtmp->mx][mtmp->my]; if (here->typ == SDOOR) cvt_sdoor_to_door(here); /* ->typ = DOOR */ /* Eats away door if present & closed or locked */ if (closed_door(mtmp->mx, mtmp->my)) { if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); unblock_point(mtmp->mx, mtmp->my); /* vision */ if (here->doormask & D_TRAPPED) { here->doormask = D_NODOOR; if (mb_trapped(mtmp)) { /* mtmp is killed */ newsym(mtmp->mx, mtmp->my); return TRUE; } } else { if (!rn2(3) && flags.verbose) /* not too often.. */ draft_message(TRUE); /* "You feel an unexpected draft." */ here->doormask = D_BROKEN; } newsym(mtmp->mx, mtmp->my); return FALSE; } else if (here->typ == SCORR) { here->typ = CORR; unblock_point(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); draft_message(FALSE); /* "You feel a draft." */ return FALSE; } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */ return FALSE; /* Only rock, trees, and walls fall through to this point. */ if ((here->wall_info & W_NONDIGGABLE) != 0) { impossible("mdig_tunnel: %s at (%d,%d) is undiggable", (IS_WALL(here->typ) ? "wall" : IS_TREE(here->typ) ? "tree" : "stone"), (int) mtmp->mx, (int) mtmp->my); return FALSE; /* still alive */ } if (IS_WALL(here->typ)) { /* KMH -- Okay on arboreal levels (room walls are still stone) */ if (flags.verbose && !rn2(5)) You_hear("crashing rock."); if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); if (level.flags.is_maze_lev) { here->typ = ROOM; } else if (level.flags.is_cavernous_lev && !in_town(mtmp->mx, mtmp->my)) { here->typ = CORR; } else { here->typ = DOOR; here->doormask = D_NODOOR; } } else if (IS_TREE(here->typ)) { here->typ = ROOM; if (pile && pile < 5) (void) rnd_treefruit_at(mtmp->mx, mtmp->my); } else { here->typ = CORR; if (pile && pile < 5) (void) mksobj_at((pile == 1) ? BOULDER : ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); } newsym(mtmp->mx, mtmp->my); if (!sobj_at(BOULDER, mtmp->mx, mtmp->my)) unblock_point(mtmp->mx, mtmp->my); /* vision */ return FALSE; } #define STRIDENT 4 /* from pray.c */ /* draft refers to air currents, but can be a pun on "draft" as conscription for military service (probably not a good pun if it has to be explained) */ void draft_message(unexpected) boolean unexpected; { /* * [Bug or TODO? Have caller pass coordinates and use the travel * mechanism to determine whether there is a path between * destroyed door (or exposed secret corridor) and hero's location. * When there is no such path, no draft should be felt.] */ if (unexpected) { if (!Hallucination) You_feel("an unexpected draft."); else /* U.S. classification system uses 1-A for eligible to serve and 4-F for ineligible due to physical or mental defect; some intermediate values exist but are rarely seen */ You_feel("like you are %s.", (ACURR(A_STR) < 6 || ACURR(A_DEX) < 6 || ACURR(A_CON) < 6 || ACURR(A_CHA) < 6 || ACURR(A_INT) < 6 || ACURR(A_WIS) < 6) ? "4-F" : "1-A"); } else { if (!Hallucination) { You_feel("a draft."); } else { /* "marching" is deliberately ambiguous; it might mean drills after entering military service or mean engaging in protests */ static const char *draft_reaction[] = { "enlisting", "marching", "protesting", "fleeing", }; int dridx; /* Lawful: 0..1, Neutral: 1..2, Chaotic: 2..3 */ dridx = rn1(2, 1 - sgn(u.ualign.type)); if (u.ualign.record < STRIDENT) /* L: +(0..2), N: +(-1..1), C: +(-2..0); all: 0..3 */ dridx += rn1(3, sgn(u.ualign.type) - 1); You_feel("like %s.", draft_reaction[dridx]); } } } /* digging via wand zap or spell cast */ void zap_dig() { struct rm *room; struct monst *mtmp; struct obj *otmp; struct trap *trap_with_u = (struct trap *) 0; int zx, zy, diridx = 8, digdepth, flow_x = -1, flow_y = -1; boolean shopdoor, shopwall, maze_dig, pitdig = FALSE, pitflow = FALSE; /* * Original effect (approximately): * from CORR: dig until we pierce a wall * from ROOM: pierce wall and dig until we reach * an ACCESSIBLE place. * Currently: dig for digdepth positions; * also down on request of Lennart Augustsson. * 3.6.0: from a PIT: dig one adjacent pit. */ if (u.uswallow) { mtmp = u.ustuck; if (!is_whirly(mtmp->data)) { if (is_animal(mtmp->data)) You("pierce %s %s wall!", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); mtmp->mhp = 1; /* almost dead */ expels(mtmp, mtmp->data, !is_animal(mtmp->data)); } return; } /* swallowed */ if (u.dz) { if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) { if (u.dz < 0 || On_stairs(u.ux, u.uy)) { int dmg; if (On_stairs(u.ux, u.uy)) pline_The("beam bounces off the %s and hits the %s.", (u.ux == xdnladder || u.ux == xupladder) ? "ladder" : "stairs", ceiling(u.ux, u.uy)); You("loosen a rock from the %s.", ceiling(u.ux, u.uy)); pline("It falls on your %s!", body_part(HEAD)); dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6); losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN); otmp = mksobj_at(ROCK, u.ux, u.uy, FALSE, FALSE); if (otmp) { (void) xname(otmp); /* set dknown, maybe bknown */ stackobj(otmp); } newsym(u.ux, u.uy); } else { watch_dig((struct monst *) 0, u.ux, u.uy, TRUE); (void) dighole(FALSE, TRUE, (coord *) 0); } } return; } /* up or down */ /* normal case: digging across the level */ shopdoor = shopwall = FALSE; maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz); zx = u.ux + u.dx; zy = u.uy + u.dy; if (u.utrap && u.utraptype == TT_PIT && (trap_with_u = t_at(u.ux, u.uy))) { pitdig = TRUE; for (diridx = 0; diridx < 8; diridx++) { if (xdir[diridx] == u.dx && ydir[diridx] == u.dy) break; /* diridx is valid if < 8 */ } } digdepth = rn1(18, 8); tmp_at(DISP_BEAM, cmap_to_glyph(S_digbeam)); while (--digdepth >= 0) { if (!isok(zx, zy)) break; room = &levl[zx][zy]; tmp_at(zx, zy); delay_output(); /* wait a little bit */ if (pitdig) { /* we are already in a pit if this is true */ coord cc; struct trap *adjpit = t_at(zx, zy); if ((diridx < 8) && !conjoined_pits(adjpit, trap_with_u, FALSE)) { digdepth = 0; /* limited to the adjacent location only */ if (!(adjpit && (adjpit->ttyp == PIT || adjpit->ttyp == SPIKED_PIT))) { char buf[BUFSZ]; cc.x = zx; cc.y = zy; if (!adj_pit_checks(&cc, buf)) { if (buf[0]) pline1(buf); } else { /* this can also result in a pool at zx,zy */ dighole(TRUE, TRUE, &cc); adjpit = t_at(zx, zy); } } if (adjpit && (adjpit->ttyp == PIT || adjpit->ttyp == SPIKED_PIT)) { int adjidx = (diridx + 4) % 8; trap_with_u->conjoined |= (1 << diridx); adjpit->conjoined |= (1 << adjidx); flow_x = zx; flow_y = zy; pitflow = TRUE; } if (is_pool(zx, zy) || is_lava(zx, zy)) { flow_x = zx - u.dx; flow_y = zy - u.dy; pitflow = TRUE; } break; } } else if (closed_door(zx, zy) || room->typ == SDOOR) { if (*in_rooms(zx, zy, SHOPBASE)) { add_damage(zx, zy, 400L); shopdoor = TRUE; } if (room->typ == SDOOR) room->typ = DOOR; else if (cansee(zx, zy)) pline_The("door is razed!"); watch_dig((struct monst *) 0, zx, zy, TRUE); room->doormask = D_NODOOR; unblock_point(zx, zy); /* vision */ digdepth -= 2; if (maze_dig) break; } else if (maze_dig) { if (IS_WALL(room->typ)) { if (!(room->wall_info & W_NONDIGGABLE)) { if (*in_rooms(zx, zy, SHOPBASE)) { add_damage(zx, zy, 200L); shopwall = TRUE; } room->typ = ROOM; unblock_point(zx, zy); /* vision */ } else if (!Blind) pline_The("wall glows then fades."); break; } else if (IS_TREE(room->typ)) { /* check trees before stone */ if (!(room->wall_info & W_NONDIGGABLE)) { room->typ = ROOM; unblock_point(zx, zy); /* vision */ } else if (!Blind) pline_The("tree shudders but is unharmed."); break; } else if (room->typ == STONE || room->typ == SCORR) { if (!(room->wall_info & W_NONDIGGABLE)) { room->typ = CORR; unblock_point(zx, zy); /* vision */ } else if (!Blind) pline_The("rock glows then fades."); break; } } else if (IS_ROCK(room->typ)) { if (!may_dig(zx, zy)) break; if (IS_WALL(room->typ) || room->typ == SDOOR) { if (*in_rooms(zx, zy, SHOPBASE)) { add_damage(zx, zy, 200L); shopwall = TRUE; } watch_dig((struct monst *) 0, zx, zy, TRUE); if (level.flags.is_cavernous_lev && !in_town(zx, zy)) { room->typ = CORR; } else { room->typ = DOOR; room->doormask = D_NODOOR; } digdepth -= 2; } else if (IS_TREE(room->typ)) { room->typ = ROOM; digdepth -= 2; } else { /* IS_ROCK but not IS_WALL or SDOOR */ room->typ = CORR; digdepth--; } unblock_point(zx, zy); /* vision */ } zx += u.dx; zy += u.dy; } /* while */ tmp_at(DISP_END, 0); /* closing call */ if (pitflow && isok(flow_x, flow_y)) { struct trap *ttmp = t_at(flow_x, flow_y); if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT)) { schar filltyp = fillholetyp(ttmp->tx, ttmp->ty, TRUE); if (filltyp != ROOM) pit_flow(ttmp, filltyp); } } if (shopdoor || shopwall) pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE); return; } /* * This checks what is on the surface above the * location where an adjacent pit might be created if * you're zapping a wand of digging laterally while * down in the pit. */ STATIC_OVL int adj_pit_checks(cc, msg) coord *cc; char *msg; { int ltyp; struct rm *room; const char *foundation_msg = "The foundation is too hard to dig through from this angle."; if (!cc) return FALSE; if (!isok(cc->x, cc->y)) return FALSE; *msg = '\0'; room = &levl[cc->x][cc->y]; ltyp = room->typ; if (is_pool(cc->x, cc->y) || is_lava(cc->x, cc->y)) { /* this is handled by the caller after we return FALSE */ return FALSE; } else if (closed_door(cc->x, cc->y) || room->typ == SDOOR) { /* We reject this here because dighole() isn't prepared to deal with this case */ Strcpy(msg, foundation_msg); return FALSE; } else if (IS_WALL(ltyp)) { /* if (room->wall_info & W_NONDIGGABLE) */ Strcpy(msg, foundation_msg); return FALSE; } else if (IS_TREE(ltyp)) { /* check trees before stone */ /* if (room->wall_info & W_NONDIGGABLE) */ Strcpy(msg, "The tree's roots glow then fade."); return FALSE; } else if (ltyp == STONE || ltyp == SCORR) { if (room->wall_info & W_NONDIGGABLE) { Strcpy(msg, "The rock glows then fades."); return FALSE; } } else if (ltyp == IRONBARS) { /* "set of iron bars" */ Strcpy(msg, "The bars go much deeper than your pit."); #if 0 } else if (is_lava(cc->x, cc->y)) { } else if (is_ice(cc->x, cc->y)) { } else if (is_pool(cc->x, cc->y)) { } else if (IS_GRAVE(ltyp)) { #endif } else if (IS_SINK(ltyp)) { Strcpy(msg, "A tangled mass of plumbing remains below the sink."); return FALSE; } else if ((cc->x == xupladder && cc->y == yupladder) /* ladder up */ || (cc->x == xdnladder && cc->y == ydnladder)) { /* " down */ Strcpy(msg, "The ladder is unaffected."); return FALSE; } else { const char *supporting = (const char *) 0; if (IS_FOUNTAIN(ltyp)) supporting = "fountain"; else if (IS_THRONE(ltyp)) supporting = "throne"; else if (IS_ALTAR(ltyp)) supporting = "altar"; else if ((cc->x == xupstair && cc->y == yupstair) || (cc->x == sstairs.sx && cc->y == sstairs.sy && sstairs.up)) /* "staircase up" */ supporting = "stairs"; else if ((cc->x == xdnstair && cc->y == ydnstair) || (cc->x == sstairs.sx && cc->y == sstairs.sy && !sstairs.up)) /* "staircase down" */ supporting = "stairs"; else if (ltyp == DRAWBRIDGE_DOWN /* "lowered drawbridge" */ || ltyp == DBWALL) /* "raised drawbridge" */ supporting = "drawbridge"; if (supporting) { Sprintf(msg, "The %s%ssupporting structures remain intact.", supporting ? s_suffix(supporting) : "", supporting ? " " : ""); return FALSE; } } return TRUE; } /* * Ensure that all conjoined pits fill up. */ STATIC_OVL void pit_flow(trap, filltyp) struct trap *trap; schar filltyp; { if (trap && (filltyp != ROOM) && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { struct trap t; int idx; t = *trap; levl[trap->tx][trap->ty].typ = filltyp; liquid_flow(trap->tx, trap->ty, filltyp, trap, (trap->tx == u.ux && trap->ty == u.uy) ? "Suddenly %s flows in from the adjacent pit!" : (char *) 0); for (idx = 0; idx < 8; ++idx) { if (t.conjoined & (1 << idx)) { int x, y; struct trap *t2; x = t.tx + xdir[idx]; y = t.ty + ydir[idx]; t2 = t_at(x, y); #if 0 /* cannot do this back-check; liquid_flow() * called deltrap() which cleaned up the * conjoined fields on both pits. */ if (t2 && (t2->conjoined & (1 << ((idx + 4) % 8)))) #endif /* recursion */ pit_flow(t2, filltyp); } } } } struct obj * buried_ball(cc) coord *cc; { xchar check_x, check_y; struct obj *otmp, *otmp2; if (u.utraptype == TT_BURIEDBALL) for (otmp = level.buriedobjlist; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->otyp != HEAVY_IRON_BALL) continue; /* try the exact location first */ if (otmp->ox == cc->x && otmp->oy == cc->y) return otmp; /* Now try the vicinity */ /* * (x-2,y-2) (x+2,y-2) * (x,y) * (x-2,y+2) (x+2,y+2) */ for (check_x = cc->x - 2; check_x <= cc->x + 2; ++check_x) for (check_y = cc->y - 2; check_y <= cc->y + 2; ++check_y) { if (check_x == cc->x && check_y == cc->y) continue; if (isok(check_x, check_y) && (otmp->ox == check_x && otmp->oy == check_y)) { cc->x = check_x; cc->y = check_y; return otmp; } } } return (struct obj *) 0; } void buried_ball_to_punishment() { coord cc; struct obj *ball; cc.x = u.ux; cc.y = u.uy; ball = buried_ball(&cc); if (ball) { obj_extract_self(ball); #if 0 /* rusting buried metallic objects is not implemented yet */ if (ball->timed) (void) stop_timer(RUST_METAL, obj_to_any(ball)); #endif punish(ball); /* use ball as flag for unearthed buried ball */ u.utrap = 0; u.utraptype = 0; del_engr_at(cc.x, cc.y); newsym(cc.x, cc.y); } } void buried_ball_to_freedom() { coord cc; struct obj *ball; cc.x = u.ux; cc.y = u.uy; ball = buried_ball(&cc); if (ball) { obj_extract_self(ball); #if 0 /* rusting buried metallic objects is not implemented yet */ if (ball->timed) (void) stop_timer(RUST_METAL, obj_to_any(ball)); #endif place_object(ball, cc.x, cc.y); stackobj(ball); u.utrap = 0; u.utraptype = 0; del_engr_at(cc.x, cc.y); newsym(cc.x, cc.y); } } /* move objects from fobj/nexthere lists to buriedobjlist, keeping position information */ struct obj * bury_an_obj(otmp, dealloced) struct obj *otmp; boolean *dealloced; { struct obj *otmp2; boolean under_ice; debugpline1("bury_an_obj: %s", xname(otmp)); if (dealloced) *dealloced = FALSE; if (otmp == uball) { unpunish(); u.utrap = rn1(50, 20); u.utraptype = TT_BURIEDBALL; pline_The("iron ball gets buried!"); } /* after unpunish(), or might get deallocated chain */ otmp2 = otmp->nexthere; /* * obj_resists(,0,0) prevents Rider corpses from being buried. * It also prevents The Amulet and invocation tools from being * buried. Since they can't be confined to bags and statues, * it makes sense that they can't be buried either, even though * the real reason there (direct accessibility when carried) is * completely different. */ if (otmp == uchain || obj_resists(otmp, 0, 0)) return otmp2; if (otmp->otyp == LEASH && otmp->leashmon != 0) o_unleash(otmp); if (otmp->lamplit && otmp->otyp != POT_OIL) end_burn(otmp, TRUE); obj_extract_self(otmp); under_ice = is_ice(otmp->ox, otmp->oy); if (otmp->otyp == ROCK && !under_ice) { /* merges into burying material */ if (dealloced) *dealloced = TRUE; obfree(otmp, (struct obj *) 0); return otmp2; } /* * Start a rot on organic material. Not corpses -- they * are already handled. */ if (otmp->otyp == CORPSE) { ; /* should cancel timer if under_ice */ } else if ((under_ice ? otmp->oclass == POTION_CLASS : is_organic(otmp)) && !obj_resists(otmp, 5, 95)) { (void) start_timer((under_ice ? 0L : 250L) + (long) rnd(250), TIMER_OBJECT, ROT_ORGANIC, obj_to_any(otmp)); #if 0 /* rusting of buried metal not yet implemented */ } else if (is_rustprone(otmp)) { (void) start_timer((long) rnd((otmp->otyp == HEAVY_IRON_BALL) ? 1500 : 250), TIMER_OBJECT, RUST_METAL, obj_to_any(otmp)); #endif } add_to_buried(otmp); return otmp2; } void bury_objs(x, y) int x, y; { struct obj *otmp, *otmp2; if (level.objects[x][y] != (struct obj *) 0) { debugpline2("bury_objs: at <%d,%d>", x, y); } for (otmp = level.objects[x][y]; otmp; otmp = otmp2) otmp2 = bury_an_obj(otmp, (boolean *) 0); /* don't expect any engravings here, but just in case */ del_engr_at(x, y); newsym(x, y); } /* move objects from buriedobjlist to fobj/nexthere lists */ void unearth_objs(x, y) int x, y; { struct obj *otmp, *otmp2, *bball; coord cc; debugpline2("unearth_objs: at <%d,%d>", x, y); cc.x = x; cc.y = y; bball = buried_ball(&cc); for (otmp = level.buriedobjlist; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox == x && otmp->oy == y) { if (bball && otmp == bball && u.utraptype == TT_BURIEDBALL) { buried_ball_to_punishment(); } else { obj_extract_self(otmp); if (otmp->timed) (void) stop_timer(ROT_ORGANIC, obj_to_any(otmp)); place_object(otmp, x, y); stackobj(otmp); } } } del_engr_at(x, y); newsym(x, y); } /* * The organic material has rotted away while buried. As an expansion, * we could add add partial damage. A damage count is kept in the object * and every time we are called we increment the count and reschedule another * timeout. Eventually the object rots away. * * This is used by buried objects other than corpses. When a container rots * away, any contents become newly buried objects. */ /* ARGSUSED */ void rot_organic(arg, timeout) anything *arg; long timeout UNUSED; { struct obj *obj = arg->a_obj; while (Has_contents(obj)) { /* We don't need to place contained object on the floor first, but we do need to update its map coordinates. */ obj->cobj->ox = obj->ox, obj->cobj->oy = obj->oy; /* Everything which can be held in a container can also be buried, so bury_an_obj's use of obj_extract_self insures that Has_contents(obj) will eventually become false. */ (void) bury_an_obj(obj->cobj, (boolean *) 0); } obj_extract_self(obj); obfree(obj, (struct obj *) 0); } /* * Called when a corpse has rotted completely away. */ void rot_corpse(arg, timeout) anything *arg; long timeout; { xchar x = 0, y = 0; struct obj *obj = arg->a_obj; boolean on_floor = obj->where == OBJ_FLOOR, in_invent = obj->where == OBJ_INVENT; if (on_floor) { x = obj->ox; y = obj->oy; } else if (in_invent) { if (flags.verbose) { char *cname = corpse_xname(obj, (const char *) 0, CXN_NO_PFX); Your("%s%s %s away%c", obj == uwep ? "wielded " : "", cname, otense(obj, "rot"), obj == uwep ? '!' : '.'); } if (obj == uwep) { uwepgone(); /* now bare handed */ stop_occupation(); } else if (obj == uswapwep) { uswapwepgone(); stop_occupation(); } else if (obj == uquiver) { uqwepgone(); stop_occupation(); } } else if (obj->where == OBJ_MINVENT && obj->owornmask) { if (obj == MON_WEP(obj->ocarry)) setmnotwielded(obj->ocarry, obj); } else if (obj->where == OBJ_MIGRATING) { /* clear destination flag so that obfree()'s check for freeing a worn object doesn't get a false hit */ obj->owornmask = 0L; } rot_organic(arg, timeout); if (on_floor) { struct monst *mtmp = m_at(x, y); /* a hiding monster may be exposed */ if (mtmp && !OBJ_AT(x, y) && mtmp->mundetected && hides_under(mtmp->data)) { mtmp->mundetected = 0; } else if (x == u.ux && y == u.uy && u.uundetected && hides_under(youmonst.data)) (void) hideunder(&youmonst); newsym(x, y); } else if (in_invent) update_inventory(); } #if 0 void bury_monst(mtmp) struct monst *mtmp; { debugpline1("bury_monst: %s", mon_nam(mtmp)); if (canseemon(mtmp)) { if (is_flyer(mtmp->data) || is_floater(mtmp->data)) { pline_The("%s opens up, but %s is not swallowed!", surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); return; } else pline_The("%s opens up and swallows %s!", surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); } mtmp->mburied = TRUE; wakeup(mtmp); /* at least give it a chance :-) */ newsym(mtmp->mx, mtmp->my); } void bury_you() { debugpline0("bury_you"); if (!Levitation && !Flying) { if (u.uswallow) You_feel("a sensation like falling into a trap!"); else pline_The("%s opens beneath you and you fall in!", surface(u.ux, u.uy)); u.uburied = TRUE; if (!Strangled && !Breathless) Strangled = 6; under_ground(1); } } void unearth_you() { debugpline0("unearth_you"); u.uburied = FALSE; under_ground(0); if (!uamul || uamul->otyp != AMULET_OF_STRANGULATION) Strangled = 0; vision_recalc(0); } void escape_tomb() { debugpline0("escape_tomb"); if ((Teleportation || can_teleport(youmonst.data)) && (Teleport_control || rn2(3) < Luck+2)) { You("attempt a teleport spell."); (void) dotele(); /* calls unearth_you() */ } else if (u.uburied) { /* still buried after 'port attempt */ boolean good; if (amorphous(youmonst.data) || Passes_walls || noncorporeal(youmonst.data) || (unsolid(youmonst.data) && youmonst.data != &mons[PM_WATER_ELEMENTAL]) || (tunnels(youmonst.data) && !needspick(youmonst.data))) { You("%s up through the %s.", (tunnels(youmonst.data) && !needspick(youmonst.data)) ? "try to tunnel" : (amorphous(youmonst.data)) ? "ooze" : "phase", surface(u.ux, u.uy)); good = (tunnels(youmonst.data) && !needspick(youmonst.data)) ? dighole(TRUE, FALSE, (coord *)0) : TRUE; if (good) unearth_you(); } } } void bury_obj(otmp) struct obj *otmp; { debugpline0("bury_obj"); if (cansee(otmp->ox, otmp->oy)) pline_The("objects on the %s tumble into a hole!", surface(otmp->ox, otmp->oy)); bury_objs(otmp->ox, otmp->oy); } #endif /*0*/ #ifdef DEBUG /* bury everything at your loc and around */ int wiz_debug_cmd_bury() { int x, y; for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) if (isok(x, y)) bury_objs(x, y); return 0; } #endif /* DEBUG */ /*dig.c*/ nethack-3.6.0/src/display.c0000664000076400007660000022733212620277605014555 0ustar paxedpaxed/* NetHack 3.6 display.c $NHDT-Date: 1446808439 2015/11/06 11:13:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ /* * THE NEW DISPLAY CODE * * The old display code has been broken up into three parts: vision, display, * and drawing. Vision decides what locations can and cannot be physically * seen by the hero. Display decides _what_ is displayed at a given location. * Drawing decides _how_ to draw a monster, fountain, sword, etc. * * The display system uses information from the vision system to decide * what to draw at a given location. The routines for the vision system * can be found in vision.c and vision.h. The routines for display can * be found in this file (display.c) and display.h. The drawing routines * are part of the window port. See doc/window.doc for the drawing * interface. * * The display system deals with an abstraction called a glyph. Anything * that could possibly be displayed has a unique glyph identifier. * * What is seen on the screen is a combination of what the hero remembers * and what the hero currently sees. Objects and dungeon features (walls * doors, etc) are remembered when out of sight. Monsters and temporary * effects are not remembered. Each location on the level has an * associated glyph. This is the hero's _memory_ of what he or she has * seen there before. * * Display rules: * * If the location is in sight, display in order: * visible (or sensed) monsters * visible objects * known traps * background * * If the location is out of sight, display in order: * sensed monsters (telepathy) * memory * * * * Here is a list of the major routines in this file to be used externally: * * newsym * * Possibly update the screen location (x,y). This is the workhorse routine. * It is always correct --- where correct means following the in-sight/out- * of-sight rules. **Most of the code should use this routine.** This * routine updates the map and displays monsters. * * * map_background * map_object * map_trap * map_invisible * unmap_object * * If you absolutely must override the in-sight/out-of-sight rules, there * are two possibilities. First, you can mess with vision to force the * location in sight then use newsym(), or you can use the map_* routines. * The first has not been tried [no need] and the second is used in the * detect routines --- detect object, magic mapping, etc. The map_* * routines *change* what the hero remembers. All changes made by these * routines will be sticky --- they will survive screen redraws. Do *not* * use these for things that only temporarily change the screen. These * routines are also used directly by newsym(). unmap_object is used to * clear a remembered object when/if detection reveals it isn't there. * * * show_glyph * * This is direct (no processing in between) buffered access to the screen. * Temporary screen effects are run through this and its companion, * flush_screen(). There is yet a lower level routine, print_glyph(), * but this is unbuffered and graphic dependent (i.e. it must be surrounded * by graphic set-up and tear-down routines). Do not use print_glyph(). * * * see_monsters * see_objects * see_traps * * These are only used when something affects all of the monsters or * objects or traps. For objects and traps, the only thing is hallucination. * For monsters, there are hallucination and changing from/to blindness, etc. * * * tmp_at * * This is a useful interface for displaying temporary items on the screen. * Its interface is different than previously, so look at it carefully. * * * * Parts of the rm structure that are used: * * typ - What is really there. * glyph - What the hero remembers. This will never be a monster. * Monsters "float" above this. * lit - True if the position is lit. An optimization for * lit/unlit rooms. * waslit - True if the position was *remembered* as lit. * seenv - A vector of bits representing the directions from which the * hero has seen this position. The vector's primary use is * determining how walls are seen. E.g. a wall sometimes looks * like stone on one side, but is seen as wall from the other. * Other uses are for unmapping detected objects and felt * locations, where we need to know if the hero has ever * seen the location. * flags - Additional information for the typ field. Different for * each typ. * horizontal - Indicates whether the wall or door is horizontal or * vertical. */ #include "hack.h" STATIC_DCL void FDECL(display_monster, (XCHAR_P, XCHAR_P, struct monst *, int, XCHAR_P)); STATIC_DCL int FDECL(swallow_to_glyph, (int, int)); STATIC_DCL void FDECL(display_warning, (struct monst *)); STATIC_DCL int FDECL(check_pos, (int, int, int)); STATIC_DCL int FDECL(get_bk_glyph, (XCHAR_P, XCHAR_P)); /*#define WA_VERBOSE*/ /* give (x,y) locations for all "bad" spots */ #ifdef WA_VERBOSE STATIC_DCL boolean FDECL(more_than_one, (int, int, int, int, int)); #endif STATIC_DCL int FDECL(set_twall, (int, int, int, int, int, int, int, int)); STATIC_DCL int FDECL(set_wall, (int, int, int)); STATIC_DCL int FDECL(set_corn, (int, int, int, int, int, int, int, int)); STATIC_DCL int FDECL(set_crosswall, (int, int)); STATIC_DCL void FDECL(set_seenv, (struct rm *, int, int, int, int)); STATIC_DCL void FDECL(t_warn, (struct rm *)); STATIC_DCL int FDECL(wall_angle, (struct rm *)); #define remember_topology(x, y) (lastseentyp[x][y] = levl[x][y].typ) /* * magic_map_background() * * This function is similar to map_background (see below) except we pay * attention to and correct unexplored, lit ROOM and CORR spots. */ void magic_map_background(x, y, show) xchar x, y; int show; { int glyph = back_to_glyph(x, y); /* assumes hero can see x,y */ struct rm *lev = &levl[x][y]; /* * Correct for out of sight lit corridors and rooms that the hero * doesn't remember as lit. */ if (!cansee(x, y) && !lev->waslit) { /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ if (lev->typ == ROOM && glyph == cmap_to_glyph(S_room)) glyph = cmap_to_glyph((flags.dark_room && iflags.use_color) ? (DARKROOMSYM) : S_stone); else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr)) glyph = cmap_to_glyph(S_corr); } if (level.flags.hero_memory) lev->glyph = glyph; if (show) show_glyph(x, y, glyph); remember_topology(x, y); } /* * The routines map_background(), map_object(), and map_trap() could just * as easily be: * * map_glyph(x,y,glyph,show) * * Which is called with the xx_to_glyph() in the call. Then I can get * rid of 3 routines that don't do very much anyway. And then stop * having to create fake objects and traps. However, I am reluctant to * make this change. */ /* FIXME: some of these use xchars for x and y, and some use ints. Make * this consistent. */ /* * map_background() * * Make the real background part of our map. This routine assumes that * the hero can physically see the location. Update the screen if directed. */ void map_background(x, y, show) register xchar x, y; register int show; { register int glyph = back_to_glyph(x, y); if (level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); } /* * map_trap() * * Map the trap and print it out if directed. This routine assumes that the * hero can physically see the location. */ void map_trap(trap, show) register struct trap *trap; register int show; { register int x = trap->tx, y = trap->ty; register int glyph = trap_to_glyph(trap); if (level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); } /* * map_object() * * Map the given object. This routine assumes that the hero can physically * see the location of the object. Update the screen if directed. */ void map_object(obj, show) register struct obj *obj; register int show; { register int x = obj->ox, y = obj->oy; register int glyph = obj_to_glyph(obj); if (level.flags.hero_memory) { /* MRKR: While hallucinating, statues are seen as random monsters */ /* but remembered as random objects. */ if (Hallucination && obj->otyp == STATUE) { levl[x][y].glyph = random_obj_to_glyph(); } else { levl[x][y].glyph = glyph; } } if (show) show_glyph(x, y, glyph); } /* * map_invisible() * * Make the hero remember that a square contains an invisible monster. * This is a special case in that the square will continue to be displayed * this way even when the hero is close enough to see it. To get rid of * this and display the square's actual contents, use unmap_object() followed * by newsym() if necessary. */ void map_invisible(x, y) register xchar x, y; { if (x != u.ux || y != u.uy) { /* don't display I at hero's location */ if (level.flags.hero_memory) levl[x][y].glyph = GLYPH_INVISIBLE; show_glyph(x, y, GLYPH_INVISIBLE); } } /* * unmap_object() * * Remove something from the map when the hero realizes it's not there any * more. Replace it with background or known trap, but not with any other * If this is used for detection, a full screen update is imminent anyway; * if this is used to get rid of an invisible monster notation, we might have * to call newsym(). */ void unmap_object(x, y) register int x, y; { register struct trap *trap; if (!level.flags.hero_memory) return; if ((trap = t_at(x, y)) != 0 && trap->tseen && !covers_traps(x, y)) map_trap(trap, 0); else if (levl[x][y].seenv) { struct rm *lev = &levl[x][y]; map_background(x, y, 0); /* turn remembered dark room squares dark */ if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) lev->glyph = cmap_to_glyph(S_stone); } else levl[x][y].glyph = cmap_to_glyph(S_stone); /* default val */ } /* * map_location() * * Make whatever at this location show up. This is only for non-living * things. This will not handle feeling invisible objects correctly. * * Internal to display.c, this is a #define for speed. */ #define _map_location(x, y, show) \ { \ register struct obj *obj; \ register struct trap *trap; \ \ if ((obj = vobj_at(x, y)) && !covers_objects(x, y)) \ map_object(obj, show); \ else if ((trap = t_at(x, y)) && trap->tseen && !covers_traps(x, y)) \ map_trap(trap, show); \ else \ map_background(x, y, show); \ \ remember_topology(x, y); \ } void map_location(x, y, show) int x, y, show; { _map_location(x, y, show); } #define DETECTED 2 #define PHYSICALLY_SEEN 1 #define is_worm_tail(mon) ((mon) && ((x != (mon)->mx) || (y != (mon)->my))) /* * display_monster() * * Note that this is *not* a map_XXXX() function! Monsters sort of float * above everything. * * Yuck. Display body parts by recognizing that the display position is * not the same as the monster position. Currently the only body part is * a worm tail. * */ STATIC_OVL void display_monster(x, y, mon, sightflags, worm_tail) register xchar x, y; /* display position */ register struct monst *mon; /* monster to display */ int sightflags; /* 1 if the monster is physically seen; 2 if detected using Detect_monsters */ xchar worm_tail; /* mon is actually a worm tail */ { boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING); int sensed = (mon_mimic && (Protection_from_shape_changers || sensemon(mon))); /* * We must do the mimic check first. If the mimic is mimicing something, * and the location is in sight, we have to change the hero's memory * so that when the position is out of sight, the hero remembers what * the mimic was mimicing. */ if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) { switch (mon->m_ap_type) { default: impossible("display_monster: bad m_ap_type value [ = %d ]", (int) mon->m_ap_type); case M_AP_NOTHING: show_glyph(x, y, mon_to_glyph(mon)); break; case M_AP_FURNITURE: { /* * This is a poor man's version of map_background(). I can't * use map_background() because we are overriding what is in * the 'typ' field. Maybe have map_background()'s parameters * be (x,y,glyph) instead of just (x,y). * * mappearance is currently set to an S_ index value in * makemon.c. */ int sym = mon->mappearance, glyph = cmap_to_glyph(sym); levl[x][y].glyph = glyph; if (!sensed) { show_glyph(x, y, glyph); /* override real topology with mimic's fake one */ lastseentyp[x][y] = cmap_to_type(sym); } break; } case M_AP_OBJECT: { /* Make a fake object to send to map_object(). */ struct obj obj; obj = zeroobj; obj.ox = x; obj.oy = y; obj.otyp = mon->mappearance; /* might be mimicing a corpse or statue */ obj.corpsenm = has_mcorpsenm(mon) ? MCORPSENM(mon) : PM_TENGU; map_object(&obj, !sensed); break; } case M_AP_MONSTER: show_glyph(x, y, monnum_to_glyph(what_mon((int) mon->mappearance))); break; } } /* If the mimic is unsuccessfully mimicing something, display the monster */ if (!mon_mimic || sensed) { int num; /* [ALI] Only use detected glyphs when monster wouldn't be * visible by any other means. */ if (sightflags == DETECTED && !mon->mtame) { if (worm_tail) num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); else num = detected_mon_to_glyph(mon); } else if (mon->mtame && !Hallucination) { if (worm_tail) num = petnum_to_glyph(PM_LONG_WORM_TAIL); else num = pet_to_glyph(mon); } else { if (worm_tail) num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); else num = mon_to_glyph(mon); } show_glyph(x, y, num); } } /* * display_warning() * * This is also *not* a map_XXXX() function! Monster warnings float * above everything just like monsters do, but only if the monster * is not showing. * * Do not call for worm tails. */ STATIC_OVL void display_warning(mon) register struct monst *mon; { int x = mon->mx, y = mon->my; int wl = (int) (mon->m_lev / 4); int glyph; if (mon_warning(mon)) { if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1; /* 3.4.1: this really ought to be rn2(WARNCOUNT), but value "0" isn't handled correctly by the what_is routine so avoid it */ if (Hallucination) wl = rn1(WARNCOUNT - 1, 1); glyph = warning_to_glyph(wl); } else if (MATCH_WARN_OF_MON(mon)) { glyph = mon_to_glyph(mon); } else { impossible("display_warning did not match warning type?"); return; } show_glyph(x, y, glyph); } /* * feel_newsym() * * When hero knows what happened to location, even when blind. */ void feel_newsym(x, y) xchar x, y; { if (Blind) feel_location(x, y); else newsym(x, y); } /* * feel_location() * * Feel the given location. This assumes that the hero is blind and that * the given position is either the hero's or one of the eight squares * adjacent to the hero (except for a boulder push). * If an invisible monster has gone away, that will be discovered. If an * invisible monster has appeared, this will _not_ be discovered since * searching only finds one monster per turn so we must check that separately. */ void feel_location(x, y) xchar x, y; { struct rm *lev; struct obj *boulder; register struct monst *mon; if (!isok(x, y)) return; lev = &(levl[x][y]); /* If the hero's memory of an invisible monster is accurate, we want to * keep * him from detecting the same monster over and over again on each turn. * We must return (so we don't erase the monster). (We must also, in the * search function, be sure to skip over previously detected 'I's.) */ if (glyph_is_invisible(lev->glyph) && m_at(x, y)) return; /* The hero can't feel non pool locations while under water. */ if (Underwater && !Is_waterlevel(&u.uz) && !is_pool(x, y)) return; /* Set the seen vector as if the hero had seen it. It doesn't matter if the hero is levitating or not. */ set_seenv(lev, u.ux, u.uy, x, y); if (!can_reach_floor(FALSE)) { /* * Levitation Rules. It is assumed that the hero can feel the state * of the walls around herself and can tell if she is in a corridor, * room, or doorway. Boulders are felt because they are large enough. * Anything else is unknown because the hero can't reach the ground. * This makes things difficult. * * Check (and display) in order: * * + Stone, walls, and closed doors. * + Boulders. [see a boulder before a doorway] * + Doors. * + Room/water positions * + Everything else (hallways!) */ if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) && (lev->doormask & (D_LOCKED | D_CLOSED)))) { map_background(x, y, 1); } else if ((boulder = sobj_at(BOULDER, x, y)) != 0) { map_object(boulder, 1); } else if (IS_DOOR(lev->typ)) { map_background(x, y, 1); } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) { /* * An open room or water location. Normally we wouldn't touch * this, but we have to get rid of remembered boulder symbols. * This will only occur in rare occasions when the hero goes * blind and doesn't find a boulder where expected (something * came along and picked it up). We know that there is not a * boulder at this location. Show fountains, pools, etc. * underneath if already seen. Otherwise, show the appropriate * floor symbol. * * Similarly, if the hero digs a hole in a wall or feels a * location * that used to contain an unseen monster. In these cases, * there's no reason to assume anything was underneath, so * just show the appropriate floor symbol. If something was * embedded in the wall, the glyph will probably already * reflect that. Don't change the symbol in this case. * * This isn't quite correct. If the boulder was on top of some * other objects they should be seen once the boulder is removed. * However, we have no way of knowing that what is there now * was there then. So we let the hero have a lapse of memory. * We could also just display what is currently on the top of the * object stack (if anything). */ if (lev->glyph == objnum_to_glyph(BOULDER)) { if (lev->typ != ROOM && lev->seenv) { map_background(x, y, 1); } else { lev->glyph = (flags.dark_room && iflags.use_color && !Is_rogue_level(&u.uz)) ? cmap_to_glyph(S_darkroom) : (lev->waslit ? cmap_to_glyph(S_room) : cmap_to_glyph(S_stone)); show_glyph(x, y, lev->glyph); } } else if ((lev->glyph >= cmap_to_glyph(S_stone) && lev->glyph < cmap_to_glyph(S_darkroom)) || glyph_is_invisible(levl[x][y].glyph)) { lev->glyph = (flags.dark_room && iflags.use_color && !Is_rogue_level(&u.uz)) ? cmap_to_glyph(S_darkroom) : (lev->waslit ? cmap_to_glyph(S_room) : cmap_to_glyph(S_stone)); show_glyph(x, y, lev->glyph); } } else { /* We feel it (I think hallways are the only things left). */ map_background(x, y, 1); /* Corridors are never felt as lit (unless remembered that way) */ /* (lit_corridor only). */ if (lev->typ == CORR && lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); else if (lev->typ == ROOM && flags.dark_room && iflags.use_color && lev->glyph == cmap_to_glyph(S_room)) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_darkroom)); } } else { _map_location(x, y, 1); if (Punished) { /* * A ball or chain is only felt if it is first on the object * location list. Otherwise, we need to clear the felt bit --- * something has been dropped on the ball/chain. If the bit is * not cleared, then when the ball/chain is moved it will drop * the wrong glyph. */ if (uchain->ox == x && uchain->oy == y) { if (level.objects[x][y] == uchain) u.bc_felt |= BC_CHAIN; else u.bc_felt &= ~BC_CHAIN; /* do not feel the chain */ } if (!carried(uball) && uball->ox == x && uball->oy == y) { if (level.objects[x][y] == uball) u.bc_felt |= BC_BALL; else u.bc_felt &= ~BC_BALL; /* do not feel the ball */ } } /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ if (lev->typ == ROOM && lev->glyph == cmap_to_glyph(S_room) && (!lev->waslit || (flags.dark_room && iflags.use_color))) show_glyph(x, y, lev->glyph = cmap_to_glyph( flags.dark_room ? S_darkroom : S_stone)); else if (lev->typ == CORR && lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); } /* draw monster on top if we can sense it */ if ((x != u.ux || y != u.uy) && (mon = m_at(x, y)) && sensemon(mon)) display_monster(x, y, mon, (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN : DETECTED, is_worm_tail(mon)); } /* * newsym() * * Possibly put a new glyph at the given location. */ void newsym(x, y) register int x, y; { register struct monst *mon; register struct rm *lev = &(levl[x][y]); register int see_it; register xchar worm_tail; if (in_mklev) return; #ifdef HANGUPHANDLING if (program_state.done_hup) return; #endif /* only permit updating the hero when swallowed */ if (u.uswallow) { if (x == u.ux && y == u.uy) display_self(); return; } if (Underwater && !Is_waterlevel(&u.uz)) { /* don't do anything unless (x,y) is an adjacent underwater position */ int dx, dy; if (!is_pool(x, y)) return; dx = x - u.ux; if (dx < 0) dx = -dx; dy = y - u.uy; if (dy < 0) dy = -dy; if (dx > 1 || dy > 1) return; } /* Can physically see the location. */ if (cansee(x, y)) { NhRegion *reg = visible_region_at(x, y); /* * Don't use templit here: E.g. * * lev->waslit = !!(lev->lit || templit(x,y)); * * Otherwise we have the "light pool" problem, where non-permanently * lit areas just out of sight stay remembered as lit. They should * re-darken. * * Perhaps ALL areas should revert to their "unlit" look when * out of sight. */ lev->waslit = (lev->lit != 0); /* remember lit condition */ /* normal region shown only on accessible positions, but poison clouds * also shown above lava, pools and moats. */ if (reg != NULL && (ACCESSIBLE(lev->typ) || (reg->glyph == cmap_to_glyph(S_poisoncloud) && (lev->typ == LAVAPOOL || lev->typ == POOL || lev->typ == MOAT)))) { show_region(reg, x, y); return; } if (x == u.ux && y == u.uy) { if (canspotself()) { _map_location(x, y, 0); /* map *under* self */ display_self(); } else /* we can see what is there */ _map_location(x, y, 1); } else { mon = m_at(x, y); worm_tail = is_worm_tail(mon); see_it = mon && (worm_tail ? (!mon->minvis || See_invisible) : (mon_visible(mon)) || tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)); if (mon && (see_it || (!worm_tail && Detect_monsters))) { if (mon->mtrapped) { struct trap *trap = t_at(x, y); int tt = trap ? trap->ttyp : NO_TRAP; /* if monster is in a physical trap, you see the trap too */ if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB) { trap->tseen = TRUE; } } _map_location(x, y, 0); /* map under the monster */ /* also gets rid of any invisibility glyph */ display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail); } else if (mon && mon_warning(mon) && !is_worm_tail(mon)) { display_warning(mon); } else if (glyph_is_invisible(levl[x][y].glyph)) { map_invisible(x, y); } else _map_location(x, y, 1); /* map the location */\ } /* Can't see the location. */ } else { if (x == u.ux && y == u.uy) { feel_location(u.ux, u.uy); /* forces an update */ if (canspotself()) display_self(); } else if ((mon = m_at(x, y)) && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon) || (see_with_infrared(mon) && mon_visible(mon)))) || Detect_monsters)) { /* Monsters are printed every time. */ /* This also gets rid of any invisibility glyph */ display_monster(x, y, mon, see_it ? 0 : DETECTED, is_worm_tail(mon) ? TRUE : FALSE); } else if ((mon = m_at(x, y)) && mon_warning(mon) && !is_worm_tail(mon)) { display_warning(mon); } /* * If the location is remembered as being both dark (waslit is false) * and lit (glyph is a lit room or lit corridor) then it was either: * * (1) A dark location that the hero could see through night * vision. * * (2) Darkened while out of the hero's sight. This can happen * when cursed scroll of light is read. * * In either case, we have to manually correct the hero's memory to * match waslit. Deciding when to change waslit is non-trivial. * * Note: If flags.lit_corridor is set, then corridors act like room * squares. That is, they light up if in night vision range. * If flags.lit_corridor is not set, then corridors will * remain dark unless lit by a light spell and may darken * again, as discussed above. * * These checks and changes must be here and not in back_to_glyph(). * They are dependent on the position being out of sight. */ else if (Is_rogue_level(&u.uz)) { if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM && !lev->waslit) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone)); else goto show_mem; } else if (!lev->waslit || (flags.dark_room && iflags.use_color)) { if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) show_glyph(x, y, lev->glyph = cmap_to_glyph(DARKROOMSYM)); else goto show_mem; } else { show_mem: show_glyph(x, y, lev->glyph); } } } #undef is_worm_tail /* * shieldeff() * * Put magic shield pyrotechnics at the given location. This *could* be * pulled into a platform dependent routine for fancier graphics if desired. */ void shieldeff(x, y) xchar x, y; { register int i; if (!flags.sparkle) return; if (cansee(x, y)) { /* Don't see anything if can't see the location */ for (i = 0; i < SHIELD_COUNT; i++) { show_glyph(x, y, cmap_to_glyph(shield_static[i])); flush_screen(1); /* make sure the glyph shows up */ delay_output(); } newsym(x, y); /* restore the old information */ } } /* * tmp_at() * * Temporarily place glyphs on the screen. Do not call delay_output(). It * is up to the caller to decide if it wants to wait [presently, everyone * but explode() wants to delay]. * * Call: * (DISP_BEAM, glyph) open, initialize glyph * (DISP_FLASH, glyph) open, initialize glyph * (DISP_ALWAYS, glyph) open, initialize glyph * (DISP_CHANGE, glyph) change glyph * (DISP_END, 0) close & clean up (second argument doesn't * matter) * (DISP_FREEMEM, 0) only used to prevent memory leak during * exit) * (x, y) display the glyph at the location * * DISP_BEAM - Display the given glyph at each location, but do not erase * any until the close call. * DISP_FLASH - Display the given glyph at each location, but erase the * previous location's glyph. * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account. */ #define TMP_AT_MAX_GLYPHS (COLNO * 2) static struct tmp_glyph { coord saved[TMP_AT_MAX_GLYPHS]; /* previously updated positions */ int sidx; /* index of next unused slot in saved[] */ int style; /* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */ int glyph; /* glyph to use when printing */ struct tmp_glyph *prev; } tgfirst; void tmp_at(x, y) int x, y; { static struct tmp_glyph *tglyph = (struct tmp_glyph *) 0; struct tmp_glyph *tmp; switch (x) { case DISP_BEAM: case DISP_ALL: case DISP_FLASH: case DISP_ALWAYS: if (!tglyph) tmp = &tgfirst; else /* nested effect; we need dynamic memory */ tmp = (struct tmp_glyph *) alloc(sizeof(struct tmp_glyph)); tmp->prev = tglyph; tglyph = tmp; tglyph->sidx = 0; tglyph->style = x; tglyph->glyph = y; flush_screen(0); /* flush buffered glyphs */ return; case DISP_FREEMEM: /* in case game ends with tmp_at() in progress */ while (tglyph) { tmp = tglyph->prev; if (tglyph != &tgfirst) free((genericptr_t) tglyph); tglyph = tmp; } return; default: break; } if (!tglyph) panic("tmp_at: tglyph not initialized"); switch (x) { case DISP_CHANGE: tglyph->glyph = y; break; case DISP_END: if (tglyph->style == DISP_BEAM || tglyph->style == DISP_ALL) { register int i; /* Erase (reset) from source to end */ for (i = 0; i < tglyph->sidx; i++) newsym(tglyph->saved[i].x, tglyph->saved[i].y); } else { /* DISP_FLASH or DISP_ALWAYS */ if (tglyph->sidx) /* been called at least once */ newsym(tglyph->saved[0].x, tglyph->saved[0].y); } /* tglyph->sidx = 0; -- about to be freed, so not necessary */ tmp = tglyph->prev; if (tglyph != &tgfirst) free((genericptr_t) tglyph); tglyph = tmp; break; default: /* do it */ if (!isok(x, y)) break; if (tglyph->style == DISP_BEAM || tglyph->style == DISP_ALL) { if (tglyph->style != DISP_ALL && !cansee(x, y)) break; if (tglyph->sidx >= TMP_AT_MAX_GLYPHS) break; /* too many locations */ /* save pos for later erasing */ tglyph->saved[tglyph->sidx].x = x; tglyph->saved[tglyph->sidx].y = y; tglyph->sidx += 1; } else { /* DISP_FLASH/ALWAYS */ if (tglyph->sidx) { /* not first call, so reset previous pos */ newsym(tglyph->saved[0].x, tglyph->saved[0].y); tglyph->sidx = 0; /* display is presently up to date */ } if (!cansee(x, y) && tglyph->style != DISP_ALWAYS) break; tglyph->saved[0].x = x; tglyph->saved[0].y = y; tglyph->sidx = 1; } show_glyph(x, y, tglyph->glyph); /* show it */ flush_screen(0); /* make sure it shows up */ break; } /* end case */ } /* * swallowed() * * The hero is swallowed. Show a special graphics sequence for this. This * bypasses all of the display routines and messes with buffered screen * directly. This method works because both vision and display check for * being swallowed. */ void swallowed(first) int first; { static xchar lastx, lasty; /* last swallowed position */ int swallower, left_ok, rght_ok; if (first) cls(); else { register int x, y; /* Clear old location */ for (y = lasty - 1; y <= lasty + 1; y++) for (x = lastx - 1; x <= lastx + 1; x++) if (isok(x, y)) show_glyph(x, y, cmap_to_glyph(S_stone)); } swallower = monsndx(u.ustuck->data); /* assume isok(u.ux,u.uy) */ left_ok = isok(u.ux - 1, u.uy); rght_ok = isok(u.ux + 1, u.uy); /* * Display the hero surrounded by the monster's stomach. */ if (isok(u.ux, u.uy - 1)) { if (left_ok) show_glyph(u.ux - 1, u.uy - 1, swallow_to_glyph(swallower, S_sw_tl)); show_glyph(u.ux, u.uy - 1, swallow_to_glyph(swallower, S_sw_tc)); if (rght_ok) show_glyph(u.ux + 1, u.uy - 1, swallow_to_glyph(swallower, S_sw_tr)); } if (left_ok) show_glyph(u.ux - 1, u.uy, swallow_to_glyph(swallower, S_sw_ml)); display_self(); if (rght_ok) show_glyph(u.ux + 1, u.uy, swallow_to_glyph(swallower, S_sw_mr)); if (isok(u.ux, u.uy + 1)) { if (left_ok) show_glyph(u.ux - 1, u.uy + 1, swallow_to_glyph(swallower, S_sw_bl)); show_glyph(u.ux, u.uy + 1, swallow_to_glyph(swallower, S_sw_bc)); if (rght_ok) show_glyph(u.ux + 1, u.uy + 1, swallow_to_glyph(swallower, S_sw_br)); } /* Update the swallowed position. */ lastx = u.ux; lasty = u.uy; } /* * under_water() * * Similar to swallowed() in operation. Shows hero when underwater * except when in water level. Special routines exist for that. */ void under_water(mode) int mode; { static xchar lastx, lasty; static boolean dela; register int x, y; /* swallowing has a higher precedence than under water */ if (Is_waterlevel(&u.uz) || u.uswallow) return; /* full update */ if (mode == 1 || dela) { cls(); dela = FALSE; /* delayed full update */ } else if (mode == 2) { dela = TRUE; return; /* limited update */ } else { for (y = lasty - 1; y <= lasty + 1; y++) for (x = lastx - 1; x <= lastx + 1; x++) if (isok(x, y)) show_glyph(x, y, cmap_to_glyph(S_stone)); } for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) if (isok(x, y) && is_pool(x, y)) { if (Blind && !(x == u.ux && y == u.uy)) show_glyph(x, y, cmap_to_glyph(S_stone)); else newsym(x, y); } lastx = u.ux; lasty = u.uy; } /* * under_ground() * * Very restricted display. You can only see yourself. */ void under_ground(mode) int mode; { static boolean dela; /* swallowing has a higher precedence than under ground */ if (u.uswallow) return; /* full update */ if (mode == 1 || dela) { cls(); dela = FALSE; /* delayed full update */ } else if (mode == 2) { dela = TRUE; return; /* limited update */ } else { newsym(u.ux, u.uy); } } /* ========================================================================= */ /* * Loop through all of the monsters and update them. Called when: * + going blind & telepathic * + regaining sight & telepathic * + getting and losing infravision * + hallucinating * + doing a full screen redraw * + see invisible times out or a ring of see invisible is taken off * + when a potion of see invisible is quaffed or a ring of see * invisible is put on * + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c] * + losing telepathy while blind [xkilled() in mon.c, attrcurse() in * sit.c] */ void see_monsters() { register struct monst *mon; int new_warn_obj_cnt = 0; if (defer_see_monsters) return; for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; newsym(mon->mx, mon->my); if (mon->wormno) see_wsegs(mon); if (Warn_of_mon && (context.warntype.obj & mon->data->mflags2) != 0L) new_warn_obj_cnt++; } /* * Make Sting glow blue or stop glowing if required. */ if (new_warn_obj_cnt != warn_obj_cnt) { Sting_effects(new_warn_obj_cnt); warn_obj_cnt = new_warn_obj_cnt; } /* when mounted, hero's location gets caught by monster loop */ if (!u.usteed) newsym(u.ux, u.uy); } /* * Block/unblock light depending on what a mimic is mimicing and if it's * invisible or not. Should be called only when the state of See_invisible * changes. */ void set_mimic_blocking() { register struct monst *mon; for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; if (mon->minvis && (is_door_mappear(mon) || is_obj_mappear(mon,BOULDER))) { if (See_invisible) block_point(mon->mx, mon->my); else unblock_point(mon->mx, mon->my); } } } /* * Loop through all of the object *locations* and update them. Called when * + hallucinating. */ void see_objects() { register struct obj *obj; for (obj = fobj; obj; obj = obj->nobj) if (vobj_at(obj->ox, obj->oy) == obj) newsym(obj->ox, obj->oy); } /* * Update hallucinated traps. */ void see_traps() { struct trap *trap; int glyph; for (trap = ftrap; trap; trap = trap->ntrap) { glyph = glyph_at(trap->tx, trap->ty); if (glyph_is_trap(glyph)) newsym(trap->tx, trap->ty); } } /* * Put the cursor on the hero. Flush all accumulated glyphs before doing it. */ void curs_on_u() { flush_screen(1); /* Flush waiting glyphs & put cursor on hero */ } int doredraw() { docrt(); return 0; } void docrt() { register int x, y; register struct rm *lev; if (!u.ux) return; /* display isn't ready yet */ if (u.uswallow) { swallowed(1); return; } if (Underwater && !Is_waterlevel(&u.uz)) { under_water(1); return; } if (u.uburied) { under_ground(1); return; } /* shut down vision */ vision_recalc(2); /* * This routine assumes that cls() does the following: * + fills the physical screen with the symbol for rock * + clears the glyph buffer */ cls(); /* display memory */ for (x = 1; x < COLNO; x++) { lev = &levl[x][0]; for (y = 0; y < ROWNO; y++, lev++) if (lev->glyph != cmap_to_glyph(S_stone)) show_glyph(x, y, lev->glyph); } /* see what is to be seen */ vision_recalc(0); /* overlay with monsters */ see_monsters(); context.botlx = 1; /* force a redraw of the bottom line */ } /* ========================================================================= */ /* Glyph Buffering (3rd screen) ============================================ */ typedef struct { xchar new; /* perhaps move this bit into the rm structure. */ int glyph; } gbuf_entry; static gbuf_entry gbuf[ROWNO][COLNO]; static char gbuf_start[ROWNO]; static char gbuf_stop[ROWNO]; /* * Store the glyph in the 3rd screen for later flushing. */ void show_glyph(x, y, glyph) int x, y, glyph; { /* * Check for bad positions and glyphs. */ if (!isok(x, y)) { const char *text; int offset; /* column 0 is invalid, but it's often used as a flag, so ignore it */ if (x == 0) return; /* * This assumes an ordering of the offsets. See display.h for * the definition. */ if (glyph >= GLYPH_WARNING_OFF && glyph < GLYPH_STATUE_OFF) { /* a warning */ text = "warning"; offset = glyph - GLYPH_WARNING_OFF; } else if (glyph >= GLYPH_SWALLOW_OFF) { /* swallow border */ text = "swallow border"; offset = glyph - GLYPH_SWALLOW_OFF; } else if (glyph >= GLYPH_ZAP_OFF) { /* zap beam */ text = "zap beam"; offset = glyph - GLYPH_ZAP_OFF; } else if (glyph >= GLYPH_EXPLODE_OFF) { /* explosion */ text = "explosion"; offset = glyph - GLYPH_EXPLODE_OFF; } else if (glyph >= GLYPH_CMAP_OFF) { /* cmap */ text = "cmap_index"; offset = glyph - GLYPH_CMAP_OFF; } else if (glyph >= GLYPH_OBJ_OFF) { /* object */ text = "object"; offset = glyph - GLYPH_OBJ_OFF; } else if (glyph >= GLYPH_RIDDEN_OFF) { /* ridden mon */ text = "ridden mon"; offset = glyph - GLYPH_RIDDEN_OFF; } else if (glyph >= GLYPH_BODY_OFF) { /* a corpse */ text = "corpse"; offset = glyph - GLYPH_BODY_OFF; } else if (glyph >= GLYPH_DETECT_OFF) { /* detected mon */ text = "detected mon"; offset = glyph - GLYPH_DETECT_OFF; } else if (glyph >= GLYPH_INVIS_OFF) { /* invisible mon */ text = "invisible mon"; offset = glyph - GLYPH_INVIS_OFF; } else if (glyph >= GLYPH_PET_OFF) { /* a pet */ text = "pet"; offset = glyph - GLYPH_PET_OFF; } else { /* a monster */ text = "monster"; offset = glyph; } impossible("show_glyph: bad pos %d %d with glyph %d [%s %d].", x, y, glyph, text, offset); return; } if (glyph >= MAX_GLYPH) { impossible("show_glyph: bad glyph %d [max %d] at (%d,%d).", glyph, MAX_GLYPH, x, y); return; } if (gbuf[y][x].glyph != glyph || iflags.use_background_glyph) { gbuf[y][x].glyph = glyph; gbuf[y][x].new = 1; if (gbuf_start[y] > x) gbuf_start[y] = x; if (gbuf_stop[y] < x) gbuf_stop[y] = x; } } /* * Reset the changed glyph borders so that none of the 3rd screen has * changed. */ #define reset_glyph_bbox() \ { \ int i; \ \ for (i = 0; i < ROWNO; i++) { \ gbuf_start[i] = COLNO - 1; \ gbuf_stop[i] = 0; \ } \ } static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) }; /* * Turn the 3rd screen into stone. */ void clear_glyph_buffer() { register int x, y; register gbuf_entry *gptr; for (y = 0; y < ROWNO; y++) { gptr = &gbuf[y][0]; for (x = COLNO; x; x--) { *gptr++ = nul_gbuf; } } reset_glyph_bbox(); } /* * Assumes that the indicated positions are filled with S_stone glyphs. */ void row_refresh(start, stop, y) int start, stop, y; { register int x; for (x = start; x <= stop; x++) if (gbuf[y][x].glyph != cmap_to_glyph(S_stone)) print_glyph(WIN_MAP, x, y, gbuf[y][x].glyph, get_bk_glyph(x,y)); } void cls() { static boolean in_cls = 0; if (in_cls) return; in_cls = TRUE; display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ context.botlx = 1; /* force update of botl window */ clear_nhwindow(WIN_MAP); /* clear physical screen */ clear_glyph_buffer(); /* this is sort of an extra effort, but OK */ in_cls = FALSE; } /* * Synch the third screen with the display. */ void flush_screen(cursor_on_u) int cursor_on_u; { /* Prevent infinite loops on errors: * flush_screen->print_glyph->impossible->pline->flush_screen */ static boolean flushing = 0; static boolean delay_flushing = 0; register int x, y; if (cursor_on_u == -1) delay_flushing = !delay_flushing; if (delay_flushing) return; if (flushing) return; /* if already flushing then return */ flushing = 1; #ifdef HANGUPHANDLING if (program_state.done_hup) return; #endif for (y = 0; y < ROWNO; y++) { register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]]; for (; x <= gbuf_stop[y]; gptr++, x++) if (gptr->new) { print_glyph(WIN_MAP, x, y, gptr->glyph, get_bk_glyph(x, y)); gptr->new = 0; } } if (cursor_on_u) curs(WIN_MAP, u.ux, u.uy); /* move cursor to the hero */ display_nhwindow(WIN_MAP, FALSE); reset_glyph_bbox(); flushing = 0; if (context.botl || context.botlx) bot(); } /* ========================================================================= */ /* * back_to_glyph() * * Use the information in the rm structure at the given position to create * a glyph of a background. * * I had to add a field in the rm structure (horizontal) so that we knew * if open doors and secret doors were horizontal or vertical. Previously, * the screen symbol had the horizontal/vertical information set at * level generation time. * * I used the 'ladder' field (really doormask) for deciding if stairwells * were up or down. I didn't want to check the upstairs and dnstairs * variables. */ int back_to_glyph(x, y) xchar x, y; { int idx; struct rm *ptr = &(levl[x][y]); switch (ptr->typ) { case SCORR: case STONE: idx = level.flags.arboreal ? S_tree : S_stone; break; case ROOM: idx = S_room; break; case CORR: idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; break; case HWALL: case VWALL: case TLCORNER: case TRCORNER: case BLCORNER: case BRCORNER: case CROSSWALL: case TUWALL: case TDWALL: case TLWALL: case TRWALL: case SDOOR: idx = ptr->seenv ? wall_angle(ptr) : S_stone; break; case DOOR: if (ptr->doormask) { if (ptr->doormask & D_BROKEN) idx = S_ndoor; else if (ptr->doormask & D_ISOPEN) idx = (ptr->horizontal) ? S_hodoor : S_vodoor; else /* else is closed */ idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor; } else idx = S_ndoor; break; case IRONBARS: idx = S_bars; break; case TREE: idx = S_tree; break; case POOL: case MOAT: idx = S_pool; break; case STAIRS: idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair; break; case LADDER: idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder; break; case FOUNTAIN: idx = S_fountain; break; case SINK: idx = S_sink; break; case ALTAR: idx = S_altar; break; case GRAVE: idx = S_grave; break; case THRONE: idx = S_throne; break; case LAVAPOOL: idx = S_lava; break; case ICE: idx = S_ice; break; case AIR: idx = S_air; break; case CLOUD: idx = S_cloud; break; case WATER: idx = S_water; break; case DBWALL: idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge; break; case DRAWBRIDGE_UP: switch (ptr->drawbridgemask & DB_UNDER) { case DB_MOAT: idx = S_pool; break; case DB_LAVA: idx = S_lava; break; case DB_ICE: idx = S_ice; break; case DB_FLOOR: idx = S_room; break; default: impossible("Strange db-under: %d", ptr->drawbridgemask & DB_UNDER); idx = S_room; /* something is better than nothing */ break; } break; case DRAWBRIDGE_DOWN: idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge; break; default: impossible("back_to_glyph: unknown level type [ = %d ]", ptr->typ); idx = S_room; break; } return cmap_to_glyph(idx); } /* * swallow_to_glyph() * * Convert a monster number and a swallow location into the correct glyph. * If you don't want a patchwork monster while hallucinating, decide on * a random monster in swallowed() and don't use what_mon() here. */ STATIC_OVL int swallow_to_glyph(mnum, loc) int mnum; int loc; { if (loc < S_sw_tl || S_sw_br < loc) { impossible("swallow_to_glyph: bad swallow location"); loc = S_sw_br; } return ((int) (what_mon(mnum) << 3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; } /* * zapdir_to_glyph() * * Change the given zap direction and beam type into a glyph. Each beam * type has four glyphs, one for each of the symbols below. The order of * the zap symbols [0-3] as defined in rm.h are: * * | S_vbeam ( 0, 1) or ( 0,-1) * - S_hbeam ( 1, 0) or (-1, 0) * \ S_lslant ( 1, 1) or (-1,-1) * / S_rslant (-1, 1) or ( 1,-1) */ int zapdir_to_glyph(dx, dy, beam_type) register int dx, dy; int beam_type; { if (beam_type >= NUM_ZAP) { impossible("zapdir_to_glyph: illegal beam type"); beam_type = 0; } dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0; return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF; } /* * Utility routine for dowhatis() used to find out the glyph displayed at * the location. This isn't necessarily the same as the glyph in the levl * structure, so we must check the "third screen". */ int glyph_at(x, y) xchar x, y; { if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO) return cmap_to_glyph(S_room); /* XXX */ return gbuf[y][x].glyph; } /* * This will be used to get the glyph for the background so that * it can potentially be merged into graphical window ports * to improve the appearance of stuff on dark room * squares and the plane of air etc. * * Until that is working correctly in the branch, however, for now * we just return NO_GLYPH as an indicator to ignore it. */ STATIC_OVL int get_bk_glyph(x,y) xchar x, y; { int idx, bkglyph = NO_GLYPH; struct rm *lev = &levl[x][y]; if (iflags.use_background_glyph) { switch (lev->typ) { case SCORR: case STONE: idx = level.flags.arboreal ? S_tree : S_stone; break; case ROOM: idx = S_room; break; case CORR: idx = (lev->waslit || flags.lit_corridor) ? S_litcorr : S_corr; break; case ICE: idx = S_ice; break; case AIR: idx = S_air; break; case CLOUD: idx = S_cloud; break; case WATER: idx = S_water; break; default: idx = S_room; break; } if (!cansee(x, y) && (!lev->waslit || flags.dark_room)) { /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ if (lev->typ == CORR && idx == S_litcorr) idx = S_corr; else if (idx == S_room) idx = (flags.dark_room && iflags.use_color) ? DARKROOMSYM : S_stone; } if (idx != S_room) bkglyph = cmap_to_glyph(idx); } return bkglyph; } /* ------------------------------------------------------------------------- */ /* Wall Angle -------------------------------------------------------------- */ #ifdef WA_VERBOSE static const char *FDECL(type_to_name, (int)); static void FDECL(error4, (int, int, int, int, int, int)); static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */ static const char *type_names[MAX_TYPE] = { "STONE", "VWALL", "HWALL", "TLCORNER", "TRCORNER", "BLCORNER", "BRCORNER", "CROSSWALL", "TUWALL", "TDWALL", "TLWALL", "TRWALL", "DBWALL", "TREE", "SDOOR", "SCORR", "POOL", "MOAT", "WATER", "DRAWBRIDGE_UP", "LAVAPOOL", "IRON_BARS", "DOOR", "CORR", "ROOM", "STAIRS", "LADDER", "FOUNTAIN", "THRONE", "SINK", "GRAVE", "ALTAR", "ICE", "DRAWBRIDGE_DOWN", "AIR", "CLOUD" }; static const char * type_to_name(type) int type; { return (type < 0 || type >= MAX_TYPE) ? "unknown" : type_names[type]; } static void error4(x, y, a, b, c, dd) int x, y, a, b, c, dd; { pline("set_wall_state: %s @ (%d,%d) %s%s%s%s", type_to_name(levl[x][y].typ), x, y, a ? "1" : "", b ? "2" : "", c ? "3" : "", dd ? "4" : ""); bad_count[levl[x][y].typ]++; } #endif /* WA_VERBOSE */ /* * Return 'which' if position is implies an unfinished exterior. Return * zero otherwise. Unfinished implies outer area is rock or a corridor. * * Things that are ambiguous: lava */ STATIC_OVL int check_pos(x, y, which) int x, y, which; { int type; if (!isok(x, y)) return which; type = levl[x][y].typ; if (IS_ROCK(type) || type == CORR || type == SCORR) return which; return 0; } /* Return TRUE if more than one is non-zero. */ /*ARGSUSED*/ #ifdef WA_VERBOSE STATIC_OVL boolean more_than_one(x, y, a, b, c) int x, y, a, b, c; { if ((a && (b | c)) || (b && (a | c)) || (c && (a | b))) { error4(x, y, a, b, c, 0); return TRUE; } return FALSE; } #else #define more_than_one(x, y, a, b, c) \ (((a) && ((b) | (c))) || ((b) && ((a) | (c))) || ((c) && ((a) | (b)))) #endif /* Return the wall mode for a T wall. */ STATIC_OVL int set_twall(x0, y0, x1, y1, x2, y2, x3, y3) int x0, y0; /* used #if WA_VERBOSE */ int x1, y1, x2, y2, x3, y3; { int wmode, is_1, is_2, is_3; nhUse(x0); nhUse(y0); is_1 = check_pos(x1, y1, WM_T_LONG); is_2 = check_pos(x2, y2, WM_T_BL); is_3 = check_pos(x3, y3, WM_T_BR); if (more_than_one(x0, y0, is_1, is_2, is_3)) { wmode = 0; } else { wmode = is_1 + is_2 + is_3; } return wmode; } /* Return wall mode for a horizontal or vertical wall. */ STATIC_OVL int set_wall(x, y, horiz) int x, y, horiz; { int wmode, is_1, is_2; if (horiz) { is_1 = check_pos(x, y - 1, WM_W_TOP); is_2 = check_pos(x, y + 1, WM_W_BOTTOM); } else { is_1 = check_pos(x - 1, y, WM_W_LEFT); is_2 = check_pos(x + 1, y, WM_W_RIGHT); } if (more_than_one(x, y, is_1, is_2, 0)) { wmode = 0; } else { wmode = is_1 + is_2; } return wmode; } /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */ STATIC_OVL int set_corn(x1, y1, x2, y2, x3, y3, x4, y4) int x1, y1, x2, y2, x3, y3, x4, y4; { int wmode, is_1, is_2, is_3, is_4; is_1 = check_pos(x1, y1, 1); is_2 = check_pos(x2, y2, 1); is_3 = check_pos(x3, y3, 1); is_4 = check_pos(x4, y4, 1); /* inner location */ /* * All 4 should not be true. So if the inner location is rock, * use it. If all of the outer 3 are true, use outer. We currently * can't cover the case where only part of the outer is rock, so * we just say that all the walls are finished (if not overridden * by the inner section). */ if (is_4) { wmode = WM_C_INNER; } else if (is_1 && is_2 && is_3) wmode = WM_C_OUTER; else wmode = 0; /* finished walls on all sides */ return wmode; } /* Return mode for a crosswall. */ STATIC_OVL int set_crosswall(x, y) int x, y; { int wmode, is_1, is_2, is_3, is_4; is_1 = check_pos(x - 1, y - 1, 1); is_2 = check_pos(x + 1, y - 1, 1); is_3 = check_pos(x + 1, y + 1, 1); is_4 = check_pos(x - 1, y + 1, 1); wmode = is_1 + is_2 + is_3 + is_4; if (wmode > 1) { if (is_1 && is_3 && (is_2 + is_4 == 0)) { wmode = WM_X_TLBR; } else if (is_2 && is_4 && (is_1 + is_3 == 0)) { wmode = WM_X_BLTR; } else { #ifdef WA_VERBOSE error4(x, y, is_1, is_2, is_3, is_4); #endif wmode = 0; } } else if (is_1) wmode = WM_X_TL; else if (is_2) wmode = WM_X_TR; else if (is_3) wmode = WM_X_BR; else if (is_4) wmode = WM_X_BL; return wmode; } /* Called from mklev. Scan the level and set the wall modes. */ void set_wall_state() { int x, y; int wmode; struct rm *lev; #ifdef WA_VERBOSE for (x = 0; x < MAX_TYPE; x++) bad_count[x] = 0; #endif for (x = 0; x < COLNO; x++) for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) { switch (lev->typ) { case SDOOR: wmode = set_wall(x, y, (int) lev->horizontal); break; case VWALL: wmode = set_wall(x, y, 0); break; case HWALL: wmode = set_wall(x, y, 1); break; case TDWALL: wmode = set_twall(x, y, x, y - 1, x - 1, y + 1, x + 1, y + 1); break; case TUWALL: wmode = set_twall(x, y, x, y + 1, x + 1, y - 1, x - 1, y - 1); break; case TLWALL: wmode = set_twall(x, y, x + 1, y, x - 1, y - 1, x - 1, y + 1); break; case TRWALL: wmode = set_twall(x, y, x - 1, y, x + 1, y + 1, x + 1, y - 1); break; case TLCORNER: wmode = set_corn(x - 1, y - 1, x, y - 1, x - 1, y, x + 1, y + 1); break; case TRCORNER: wmode = set_corn(x, y - 1, x + 1, y - 1, x + 1, y, x - 1, y + 1); break; case BLCORNER: wmode = set_corn(x, y + 1, x - 1, y + 1, x - 1, y, x + 1, y - 1); break; case BRCORNER: wmode = set_corn(x + 1, y, x + 1, y + 1, x, y + 1, x - 1, y - 1); break; case CROSSWALL: wmode = set_crosswall(x, y); break; default: wmode = -1; /* don't set wall info */ break; } if (wmode >= 0) lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode; } #ifdef WA_VERBOSE /* check if any bad positions found */ for (x = y = 0; x < MAX_TYPE; x++) if (bad_count[x]) { if (y == 0) { y = 1; /* only print once */ pline("set_wall_type: wall mode problems with: "); } pline("%s %d;", type_names[x], bad_count[x]); } #endif /* WA_VERBOSE */ } /* ------------------------------------------------------------------------- */ /* This matrix is used here and in vision.c. */ unsigned char seenv_matrix[3][3] = { { SV2, SV1, SV0 }, { SV3, SVALL, SV7 }, { SV4, SV5, SV6 } }; #define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0)) /* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */ STATIC_OVL void set_seenv(lev, x0, y0, x, y) struct rm *lev; int x0, y0, x, y; /* from, to */ { int dx = x - x0, dy = y0 - y; lev->seenv |= seenv_matrix[sign(dy) + 1][sign(dx) + 1]; } /* Called by blackout(vault.c) when vault guard removes temporary corridor, turning spot back into stone; is an adjacent spot. */ void unset_seenv(lev, x0, y0, x1, y1) struct rm *lev; /* &levl[x1][y1] */ int x0, y0, x1, y1; /* from, to; abs(x1-x0)==1 && abs(y0-y1)==1 */ { int dx = x1 - x0, dy = y0 - y1; lev->seenv &= ~seenv_matrix[dy + 1][dx + 1]; } /* ------------------------------------------------------------------------- */ /* T wall types, one for each row in wall_matrix[][]. */ #define T_d 0 #define T_l 1 #define T_u 2 #define T_r 3 /* * These are the column names of wall_matrix[][]. They are the "results" * of a tdwall pattern match. All T walls are rotated so they become * a tdwall. Then we do a single pattern match, but return the * correct result for the original wall by using different rows for * each of the wall types. */ #define T_stone 0 #define T_tlcorn 1 #define T_trcorn 2 #define T_hwall 3 #define T_tdwall 4 static const int wall_matrix[4][5] = { { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall }, /* tdwall */ { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall }, /* tlwall */ { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall }, /* tuwall */ { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall }, /* trwall */ }; /* Cross wall types, one for each "solid" quarter. Rows of cross_matrix[][]. */ #define C_bl 0 #define C_tl 1 #define C_tr 2 #define C_br 3 /* * These are the column names for cross_matrix[][]. They express results * in C_br (bottom right) terms. All crosswalls with a single solid * quarter are rotated so the solid section is at the bottom right. * We pattern match on that, but return the correct result depending * on which row we'ere looking at. */ #define C_trcorn 0 #define C_brcorn 1 #define C_blcorn 2 #define C_tlwall 3 #define C_tuwall 4 #define C_crwall 5 static const int cross_matrix[4][6] = { { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall }, { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall }, { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall }, { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall }, }; /* Print out a T wall warning and all interesting info. */ STATIC_OVL void t_warn(lev) struct rm *lev; { static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x"; const char *wname; if (lev->typ == TUWALL) wname = "tuwall"; else if (lev->typ == TLWALL) wname = "tlwall"; else if (lev->typ == TRWALL) wname = "trwall"; else if (lev->typ == TDWALL) wname = "tdwall"; else wname = "unknown"; impossible(warn_str, wname, lev->wall_info & WM_MASK, (unsigned int) lev->seenv); } /* * Return the correct graphics character index using wall type, wall mode, * and the seen vector. It is expected that seenv is non zero. * * All T-wall vectors are rotated to be TDWALL. All single crosswall * blocks are rotated to bottom right. All double crosswall are rotated * to W_X_BLTR. All results are converted back. * * The only way to understand this is to take out pen and paper and * draw diagrams. See rm.h for more details on the wall modes and * seen vector (SV). */ STATIC_OVL int wall_angle(lev) struct rm *lev; { register unsigned int seenv = lev->seenv & 0xff; const int *row; int col, idx; #define only(sv, bits) (((sv) & (bits)) && !((sv) & ~(bits))) switch (lev->typ) { case TUWALL: row = wall_matrix[T_u]; seenv = (seenv >> 4 | seenv << 4) & 0xff; /* rotate to tdwall */ goto do_twall; case TLWALL: row = wall_matrix[T_l]; seenv = (seenv >> 2 | seenv << 6) & 0xff; /* rotate to tdwall */ goto do_twall; case TRWALL: row = wall_matrix[T_r]; seenv = (seenv >> 6 | seenv << 2) & 0xff; /* rotate to tdwall */ goto do_twall; case TDWALL: row = wall_matrix[T_d]; do_twall: switch (lev->wall_info & WM_MASK) { case 0: if (seenv == SV4) { col = T_tlcorn; } else if (seenv == SV6) { col = T_trcorn; } else if (seenv & (SV3 | SV5 | SV7) || ((seenv & SV4) && (seenv & SV6))) { col = T_tdwall; } else if (seenv & (SV0 | SV1 | SV2)) { col = (seenv & (SV4 | SV6) ? T_tdwall : T_hwall); } else { t_warn(lev); col = T_stone; } break; case WM_T_LONG: if (seenv & (SV3 | SV4) && !(seenv & (SV5 | SV6 | SV7))) { col = T_tlcorn; } else if (seenv & (SV6 | SV7) && !(seenv & (SV3 | SV4 | SV5))) { col = T_trcorn; } else if ((seenv & SV5) || ((seenv & (SV3 | SV4)) && (seenv & (SV6 | SV7)))) { col = T_tdwall; } else { /* only SV0|SV1|SV2 */ if (!only(seenv, SV0 | SV1 | SV2)) t_warn(lev); col = T_stone; } break; case WM_T_BL: #if 0 /* older method, fixed */ if (only(seenv, SV4|SV5)) { col = T_tlcorn; } else if ((seenv & (SV0|SV1|SV2)) && only(seenv, SV0|SV1|SV2|SV6|SV7)) { col = T_hwall; } else if ((seenv & SV3) || ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) { col = T_tdwall; } else { if (seenv != SV6) t_warn(lev); col = T_stone; } #endif /* 0 */ if (only(seenv, SV4 | SV5)) col = T_tlcorn; else if ((seenv & (SV0 | SV1 | SV2 | SV7)) && !(seenv & (SV3 | SV4 | SV5))) col = T_hwall; else if (only(seenv, SV6)) col = T_stone; else col = T_tdwall; break; case WM_T_BR: #if 0 /* older method, fixed */ if (only(seenv, SV5|SV6)) { col = T_trcorn; } else if ((seenv & (SV0|SV1|SV2)) && only(seenv, SV0|SV1|SV2|SV3|SV4)) { col = T_hwall; } else if ((seenv & SV7) || ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) { col = T_tdwall; } else { if (seenv != SV4) t_warn(lev); col = T_stone; } #endif /* 0 */ if (only(seenv, SV5 | SV6)) col = T_trcorn; else if ((seenv & (SV0 | SV1 | SV2 | SV3)) && !(seenv & (SV5 | SV6 | SV7))) col = T_hwall; else if (only(seenv, SV4)) col = T_stone; else col = T_tdwall; break; default: impossible("wall_angle: unknown T wall mode %d", lev->wall_info & WM_MASK); col = T_stone; break; } idx = row[col]; break; case SDOOR: if (lev->horizontal) goto horiz; /* fall through */ case VWALL: switch (lev->wall_info & WM_MASK) { case 0: idx = seenv ? S_vwall : S_stone; break; case 1: idx = seenv & (SV1 | SV2 | SV3 | SV4 | SV5) ? S_vwall : S_stone; break; case 2: idx = seenv & (SV0 | SV1 | SV5 | SV6 | SV7) ? S_vwall : S_stone; break; default: impossible("wall_angle: unknown vwall mode %d", lev->wall_info & WM_MASK); idx = S_stone; break; } break; case HWALL: horiz: switch (lev->wall_info & WM_MASK) { case 0: idx = seenv ? S_hwall : S_stone; break; case 1: idx = seenv & (SV3 | SV4 | SV5 | SV6 | SV7) ? S_hwall : S_stone; break; case 2: idx = seenv & (SV0 | SV1 | SV2 | SV3 | SV7) ? S_hwall : S_stone; break; default: impossible("wall_angle: unknown hwall mode %d", lev->wall_info & WM_MASK); idx = S_stone; break; } break; #define set_corner(idx, lev, which, outer, inner, name) \ switch ((lev)->wall_info & WM_MASK) { \ case 0: \ idx = which; \ break; \ case WM_C_OUTER: \ idx = seenv & (outer) ? which : S_stone; \ break; \ case WM_C_INNER: \ idx = seenv & ~(inner) ? which : S_stone; \ break; \ default: \ impossible("wall_angle: unknown %s mode %d", name, \ (lev)->wall_info &WM_MASK); \ idx = S_stone; \ break; \ } case TLCORNER: set_corner(idx, lev, S_tlcorn, (SV3 | SV4 | SV5), SV4, "tlcorn"); break; case TRCORNER: set_corner(idx, lev, S_trcorn, (SV5 | SV6 | SV7), SV6, "trcorn"); break; case BLCORNER: set_corner(idx, lev, S_blcorn, (SV1 | SV2 | SV3), SV2, "blcorn"); break; case BRCORNER: set_corner(idx, lev, S_brcorn, (SV7 | SV0 | SV1), SV0, "brcorn"); break; case CROSSWALL: switch (lev->wall_info & WM_MASK) { case 0: if (seenv == SV0) idx = S_brcorn; else if (seenv == SV2) idx = S_blcorn; else if (seenv == SV4) idx = S_tlcorn; else if (seenv == SV6) idx = S_trcorn; else if (!(seenv & ~(SV0 | SV1 | SV2)) && (seenv & SV1 || seenv == (SV0 | SV2))) idx = S_tuwall; else if (!(seenv & ~(SV2 | SV3 | SV4)) && (seenv & SV3 || seenv == (SV2 | SV4))) idx = S_trwall; else if (!(seenv & ~(SV4 | SV5 | SV6)) && (seenv & SV5 || seenv == (SV4 | SV6))) idx = S_tdwall; else if (!(seenv & ~(SV0 | SV6 | SV7)) && (seenv & SV7 || seenv == (SV0 | SV6))) idx = S_tlwall; else idx = S_crwall; break; case WM_X_TL: row = cross_matrix[C_tl]; seenv = (seenv >> 4 | seenv << 4) & 0xff; goto do_crwall; case WM_X_TR: row = cross_matrix[C_tr]; seenv = (seenv >> 6 | seenv << 2) & 0xff; goto do_crwall; case WM_X_BL: row = cross_matrix[C_bl]; seenv = (seenv >> 2 | seenv << 6) & 0xff; goto do_crwall; case WM_X_BR: row = cross_matrix[C_br]; do_crwall: if (seenv == SV4) idx = S_stone; else { seenv = seenv & ~SV4; /* strip SV4 */ if (seenv == SV0) { col = C_brcorn; } else if (seenv & (SV2 | SV3)) { if (seenv & (SV5 | SV6 | SV7)) col = C_crwall; else if (seenv & (SV0 | SV1)) col = C_tuwall; else col = C_blcorn; } else if (seenv & (SV5 | SV6)) { if (seenv & (SV1 | SV2 | SV3)) col = C_crwall; else if (seenv & (SV0 | SV7)) col = C_tlwall; else col = C_trcorn; } else if (seenv & SV1) { col = seenv & SV7 ? C_crwall : C_tuwall; } else if (seenv & SV7) { col = seenv & SV1 ? C_crwall : C_tlwall; } else { impossible("wall_angle: bottom of crwall check"); col = C_crwall; } idx = row[col]; } break; case WM_X_TLBR: if (only(seenv, SV1 | SV2 | SV3)) idx = S_blcorn; else if (only(seenv, SV5 | SV6 | SV7)) idx = S_trcorn; else if (only(seenv, SV0 | SV4)) idx = S_stone; else idx = S_crwall; break; case WM_X_BLTR: if (only(seenv, SV0 | SV1 | SV7)) idx = S_brcorn; else if (only(seenv, SV3 | SV4 | SV5)) idx = S_tlcorn; else if (only(seenv, SV2 | SV6)) idx = S_stone; else idx = S_crwall; break; default: impossible("wall_angle: unknown crosswall mode"); idx = S_stone; break; } break; default: impossible("wall_angle: unexpected wall type %d", lev->typ); idx = S_stone; } return idx; } /*display.c*/ nethack-3.6.0/src/dlb.c0000664000076400007660000003325212617615230013641 0ustar paxedpaxed/* NetHack 3.6 dlb.c $NHDT-Date: 1446975464 2015/11/08 09:37:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "dlb.h" #ifdef __DJGPP__ #include #endif #define DATAPREFIX 4 #if defined(OVERLAY) #define STATIC_DCL extern #define STATIC_OVL #else /* !OVERLAY */ #define STATIC_DCL static #define STATIC_OVL static #endif /* OVERLAY */ #ifdef DLB /* * Data librarian. Present a STDIO-like interface to NetHack while * multiplexing on one or more "data libraries". If a file is not found * in a given library, look for it outside the libraries. */ typedef struct dlb_procs { boolean NDECL((*dlb_init_proc)); void NDECL((*dlb_cleanup_proc)); boolean FDECL((*dlb_fopen_proc), (DLB_P, const char *, const char *)); int FDECL((*dlb_fclose_proc), (DLB_P)); int FDECL((*dlb_fread_proc), (char *, int, int, DLB_P)); int FDECL((*dlb_fseek_proc), (DLB_P, long, int)); char *FDECL((*dlb_fgets_proc), (char *, int, DLB_P)); int FDECL((*dlb_fgetc_proc), (DLB_P)); long FDECL((*dlb_ftell_proc), (DLB_P)); } dlb_procs_t; /* without extern.h via hack.h, these haven't been declared for us */ extern FILE *FDECL(fopen_datafile, (const char *, const char *, int)); #ifdef DLBLIB /* * Library Implementation: * * When initialized, we open all library files and read in their tables * of contents. The library files stay open all the time. When * a open is requested, the libraries' directories are searched. If * successful, we return a descriptor that contains the library, file * size, and current file mark. This descriptor is used for all * successive calls. * * The ability to open more than one library is supported but used * only in the Amiga port (the second library holds the sound files). * For Unix, the idea would be to split the NetHack library * into text and binary parts, where the text version could be shared. */ #define MAX_LIBS 4 static library dlb_libs[MAX_LIBS]; STATIC_DCL boolean FDECL(readlibdir, (library * lp)); STATIC_DCL boolean FDECL(find_file, (const char *name, library **lib, long *startp, long *sizep)); STATIC_DCL boolean NDECL(lib_dlb_init); STATIC_DCL void NDECL(lib_dlb_cleanup); STATIC_DCL boolean FDECL(lib_dlb_fopen, (dlb *, const char *, const char *)); STATIC_DCL int FDECL(lib_dlb_fclose, (dlb *)); STATIC_DCL int FDECL(lib_dlb_fread, (char *, int, int, dlb *)); STATIC_DCL int FDECL(lib_dlb_fseek, (dlb *, long, int)); STATIC_DCL char *FDECL(lib_dlb_fgets, (char *, int, dlb *)); STATIC_DCL int FDECL(lib_dlb_fgetc, (dlb *)); STATIC_DCL long FDECL(lib_dlb_ftell, (dlb *)); /* not static because shared with dlb_main.c */ boolean FDECL(open_library, (const char *lib_name, library *lp)); void FDECL(close_library, (library * lp)); /* without extern.h via hack.h, these haven't been declared for us */ extern char *FDECL(eos, (char *)); /* * Read the directory out of the library. Return 1 if successful, * 0 if it failed. * * NOTE: An improvement of the file structure should be the file * size as part of the directory entry or perhaps in place of the * offset -- the offset can be calculated by a running tally of * the sizes. * * Library file structure: * * HEADER: * %3ld library FORMAT revision (currently rev 1) * %1c space * %8ld # of files in archive (includes 1 for directory) * %1c space * %8ld size of allocation for string space for directory names * %1c space * %8ld library offset - sanity check - lseek target for start of first file * %1c space * %8ld size - sanity check - byte size of complete archive file * * followed by one DIRECTORY entry for each file in the archive, including * the directory itself: * %1c handling information (compression, etc.) Always ' ' in rev 1. * %s file name * %1c space * %8ld offset in archive file of start of this file * %c newline * * followed by the contents of the files */ #define DLB_MIN_VERS 1 /* min library version readable by this code */ #define DLB_MAX_VERS 1 /* max library version readable by this code */ /* * Read the directory from the library file. This will allocate and * fill in our globals. The file pointer is reset back to position * zero. If any part fails, leave nothing that needs to be deallocated. * * Return TRUE on success, FALSE on failure. */ STATIC_OVL boolean readlibdir(lp) library *lp; /* library pointer to fill in */ { int i; char *sp; long liboffset, totalsize; if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n", &lp->rev, &lp->nentries, &lp->strsize, &liboffset, &totalsize) != 5) return FALSE; if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS) return FALSE; lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir)); lp->sspace = (char *) alloc(lp->strsize); /* read in each directory entry */ for (i = 0, sp = lp->sspace; i < lp->nentries; i++) { lp->dir[i].fname = sp; if (fscanf(lp->fdata, "%c%s %ld\n", &lp->dir[i].handling, sp, &lp->dir[i].foffset) != 3) { free((genericptr_t) lp->dir); free((genericptr_t) lp->sspace); lp->dir = (libdir *) 0; lp->sspace = (char *) 0; return FALSE; } sp = eos(sp) + 1; } /* calculate file sizes using offset information */ for (i = 0; i < lp->nentries; i++) { if (i == lp->nentries - 1) lp->dir[i].fsize = totalsize - lp->dir[i].foffset; else lp->dir[i].fsize = lp->dir[i + 1].foffset - lp->dir[i].foffset; } (void) fseek(lp->fdata, 0L, SEEK_SET); /* reset back to zero */ lp->fmark = 0; return TRUE; } /* * Look for the file in our directory structure. Return 1 if successful, * 0 if not found. Fill in the size and starting position. */ STATIC_OVL boolean find_file(name, lib, startp, sizep) const char *name; library **lib; long *startp, *sizep; { int i, j; library *lp; for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) { lp = &dlb_libs[i]; for (j = 0; j < lp->nentries; j++) { if (FILENAME_CMP(name, lp->dir[j].fname) == 0) { *lib = lp; *startp = lp->dir[j].foffset; *sizep = lp->dir[j].fsize; return TRUE; } } } *lib = (library *) 0; *startp = *sizep = 0; return FALSE; } /* * Open the library of the given name and fill in the given library * structure. Return TRUE if successful, FALSE otherwise. */ boolean open_library(lib_name, lp) const char *lib_name; library *lp; { boolean status = FALSE; lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX); if (lp->fdata) { if (readlibdir(lp)) { status = TRUE; } else { (void) fclose(lp->fdata); lp->fdata = (FILE *) 0; } } return status; } void close_library(lp) library *lp; { (void) fclose(lp->fdata); free((genericptr_t) lp->dir); free((genericptr_t) lp->sspace); (void) memset((char *) lp, 0, sizeof(library)); } /* * Open the library file once using stdio. Keep it open, but * keep track of the file position. */ STATIC_OVL boolean lib_dlb_init(VOID_ARGS) { /* zero out array */ (void) memset((char *) &dlb_libs[0], 0, sizeof(dlb_libs)); /* To open more than one library, add open library calls here. */ if (!open_library(DLBFILE, &dlb_libs[0])) return FALSE; #ifdef DLBFILE2 if (!open_library(DLBFILE2, &dlb_libs[1])) { close_library(&dlb_libs[0]); return FALSE; } #endif return TRUE; } STATIC_OVL void lib_dlb_cleanup(VOID_ARGS) { int i; /* close the data file(s) */ for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) close_library(&dlb_libs[i]); } /*ARGSUSED*/ STATIC_OVL boolean lib_dlb_fopen(dp, name, mode) dlb *dp; const char *name; const char *mode UNUSED; { long start, size; library *lp; /* look up file in directory */ if (find_file(name, &lp, &start, &size)) { dp->lib = lp; dp->start = start; dp->size = size; dp->mark = 0; return TRUE; } return FALSE; /* failed */ } /*ARGUSED*/ STATIC_OVL int lib_dlb_fclose(dp) dlb *dp UNUSED; { /* nothing needs to be done */ return 0; } STATIC_OVL int lib_dlb_fread(buf, size, quan, dp) char *buf; int size, quan; dlb *dp; { long pos, nread, nbytes; /* make sure we don't read into the next file */ if ((dp->size - dp->mark) < (size * quan)) quan = (dp->size - dp->mark) / size; if (quan == 0) return 0; pos = dp->start + dp->mark; if (dp->lib->fmark != pos) { fseek(dp->lib->fdata, pos, SEEK_SET); /* check for error??? */ dp->lib->fmark = pos; } nread = fread(buf, size, quan, dp->lib->fdata); nbytes = nread * size; dp->mark += nbytes; dp->lib->fmark += nbytes; return nread; } STATIC_OVL int lib_dlb_fseek(dp, pos, whence) dlb *dp; long pos; int whence; { long curpos; switch (whence) { case SEEK_CUR: curpos = dp->mark + pos; break; case SEEK_END: curpos = dp->size - pos; break; default: /* set */ curpos = pos; break; } if (curpos < 0) curpos = 0; if (curpos > dp->size) curpos = dp->size; dp->mark = curpos; return 0; } STATIC_OVL char * lib_dlb_fgets(buf, len, dp) char *buf; int len; dlb *dp; { int i; char *bp, c = 0; if (len <= 0) return buf; /* sanity check */ /* return NULL on EOF */ if (dp->mark >= dp->size) return (char *) 0; len--; /* save room for null */ for (i = 0, bp = buf; i < len && dp->mark < dp->size && c != '\n'; i++, bp++) { if (dlb_fread(bp, 1, 1, dp) <= 0) break; /* EOF or error */ c = *bp; } *bp = '\0'; #if defined(MSDOS) || defined(WIN32) if ((bp = index(buf, '\r')) != 0) { *bp++ = '\n'; *bp = '\0'; } #endif return buf; } STATIC_OVL int lib_dlb_fgetc(dp) dlb *dp; { char c; if (lib_dlb_fread(&c, 1, 1, dp) != 1) return EOF; return (int) c; } STATIC_OVL long lib_dlb_ftell(dp) dlb *dp; { return dp->mark; } const dlb_procs_t lib_dlb_procs = { lib_dlb_init, lib_dlb_cleanup, lib_dlb_fopen, lib_dlb_fclose, lib_dlb_fread, lib_dlb_fseek, lib_dlb_fgets, lib_dlb_fgetc, lib_dlb_ftell }; #endif /* DLBLIB */ #ifdef DLBRSRC const dlb_procs_t rsrc_dlb_procs = { rsrc_dlb_init, rsrc_dlb_cleanup, rsrc_dlb_fopen, rsrc_dlb_fclose, rsrc_dlb_fread, rsrc_dlb_fseek, rsrc_dlb_fgets, rsrc_dlb_fgetc, rsrc_dlb_ftell }; #endif /* Global wrapper functions ------------------------------------------------ */ #define do_dlb_init (*dlb_procs->dlb_init_proc) #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc) #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc) #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc) #define do_dlb_fread (*dlb_procs->dlb_fread_proc) #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc) #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc) #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc) #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc) static const dlb_procs_t *dlb_procs; static boolean dlb_initialized = FALSE; boolean dlb_init() { if (!dlb_initialized) { #ifdef DLBLIB dlb_procs = &lib_dlb_procs; #endif #ifdef DLBRSRC dlb_procs = &rsrc_dlb_procs; #endif if (dlb_procs) dlb_initialized = do_dlb_init(); } return dlb_initialized; } void dlb_cleanup() { if (dlb_initialized) { do_dlb_cleanup(); dlb_initialized = FALSE; } } dlb * dlb_fopen(name, mode) const char *name, *mode; { FILE *fp; dlb *dp; if (!dlb_initialized) return (dlb *) 0; /* only support reading; ignore possible binary flag */ if (!mode || mode[0] != 'r') return (dlb *) 0; dp = (dlb *) alloc(sizeof(dlb)); if (do_dlb_fopen(dp, name, mode)) dp->fp = (FILE *) 0; else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0) dp->fp = fp; else { /* can't find anything */ free((genericptr_t) dp); dp = (dlb *) 0; } return dp; } int dlb_fclose(dp) dlb *dp; { int ret = 0; if (dlb_initialized) { if (dp->fp) ret = fclose(dp->fp); else ret = do_dlb_fclose(dp); free((genericptr_t) dp); } return ret; } int dlb_fread(buf, size, quan, dp) char *buf; int size, quan; dlb *dp; { if (!dlb_initialized || size <= 0 || quan <= 0) return 0; if (dp->fp) return (int) fread(buf, size, quan, dp->fp); return do_dlb_fread(buf, size, quan, dp); } int dlb_fseek(dp, pos, whence) dlb *dp; long pos; int whence; { if (!dlb_initialized) return EOF; if (dp->fp) return fseek(dp->fp, pos, whence); return do_dlb_fseek(dp, pos, whence); } char * dlb_fgets(buf, len, dp) char *buf; int len; dlb *dp; { if (!dlb_initialized) return (char *) 0; if (dp->fp) return fgets(buf, len, dp->fp); return do_dlb_fgets(buf, len, dp); } int dlb_fgetc(dp) dlb *dp; { if (!dlb_initialized) return EOF; if (dp->fp) return fgetc(dp->fp); return do_dlb_fgetc(dp); } long dlb_ftell(dp) dlb *dp; { if (!dlb_initialized) return 0; if (dp->fp) return ftell(dp->fp); return do_dlb_ftell(dp); } #endif /* DLB */ /*dlb.c*/ nethack-3.6.0/src/do.c0000664000076400007660000017112512617615230013504 0ustar paxedpaxed/* NetHack 3.6 do.c $NHDT-Date: 1446975464 2015/11/08 09:37:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.149 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */ #include "hack.h" #include "lev.h" STATIC_DCL void FDECL(trycall, (struct obj *)); STATIC_DCL void NDECL(polymorph_sink); STATIC_DCL boolean NDECL(teleport_sink); STATIC_DCL void FDECL(dosinkring, (struct obj *)); STATIC_PTR int FDECL(drop, (struct obj *)); STATIC_PTR int NDECL(wipeoff); STATIC_DCL int FDECL(menu_drop, (int)); STATIC_DCL int NDECL(currentlevel_rewrite); STATIC_DCL void NDECL(final_level); /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */ extern int n_dgns; /* number of dungeons, from dungeon.c */ static NEARDATA const char drop_types[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; /* 'd' command: drop one inventory item */ int dodrop() { int result, i = (invent) ? 0 : (SIZE(drop_types) - 1); if (*u.ushops) sellobj_state(SELL_DELIBERATE); result = drop(getobj(&drop_types[i], "drop")); if (*u.ushops) sellobj_state(SELL_NORMAL); reset_occupations(); return result; } /* Called when a boulder is dropped, thrown, or pushed. If it ends up * in a pool, it either fills the pool up or sinks away. In either case, * it's gone for good... If the destination is not a pool, returns FALSE. */ boolean boulder_hits_pool(otmp, rx, ry, pushing) struct obj *otmp; register int rx, ry; boolean pushing; { if (!otmp || otmp->otyp != BOULDER) { impossible("Not a boulder?"); } else if (!Is_waterlevel(&u.uz) && is_pool_or_lava(rx, ry)) { boolean lava = is_lava(rx, ry), fills_up; const char *what = waterbody_name(rx, ry); schar ltyp = levl[rx][ry].typ; int chance = rn2(10); /* water: 90%; lava: 10% */ fills_up = lava ? chance == 0 : chance != 0; if (fills_up) { struct trap *ttmp = t_at(rx, ry); if (ltyp == DRAWBRIDGE_UP) { levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ levl[rx][ry].drawbridgemask |= DB_FLOOR; } else levl[rx][ry].typ = ROOM; if (ttmp) (void) delfloortrap(ttmp); bury_objs(rx, ry); newsym(rx, ry); if (pushing) { char whobuf[BUFSZ]; Strcpy(whobuf, "you"); if (u.usteed) Strcpy(whobuf, y_monnam(u.usteed)); pline("%s %s %s into the %s.", upstart(whobuf), vtense(whobuf, "push"), the(xname(otmp)), what); if (flags.verbose && !Blind) pline("Now you can cross it!"); /* no splashing in this case */ } } if (!fills_up || !pushing) { /* splashing occurs */ if (!u.uinwater) { if (pushing ? !Blind : cansee(rx, ry)) { There("is a large splash as %s %s the %s.", the(xname(otmp)), fills_up ? "fills" : "falls into", what); } else if (!Deaf) You_hear("a%s splash.", lava ? " sizzling" : ""); wake_nearto(rx, ry, 40); } if (fills_up && u.uinwater && distu(rx, ry) == 0) { u.uinwater = 0; docrt(); vision_full_recalc = 1; You("find yourself on dry land again!"); } else if (lava && distu(rx, ry) <= 2) { int dmg; You("are hit by molten lava%c", Fire_resistance ? '.' : '!'); burn_away_slime(); dmg = d((Fire_resistance ? 1 : 3), 6); losehp(Maybe_Half_Phys(dmg), /* lava damage */ "molten lava", KILLED_BY); } else if (!fills_up && flags.verbose && (pushing ? !Blind : cansee(rx, ry))) pline("It sinks without a trace!"); } /* boulder is now gone */ if (pushing) delobj(otmp); else obfree(otmp, (struct obj *) 0); return TRUE; } return FALSE; } /* Used for objects which sometimes do special things when dropped; must be * called with the object not in any chain. Returns TRUE if the object goes * away. */ boolean flooreffects(obj, x, y, verb) struct obj *obj; int x, y; const char *verb; { struct trap *t; struct monst *mtmp; struct obj *otmp; if (obj->where != OBJ_FREE) panic("flooreffects: obj not free"); /* make sure things like water_damage() have no pointers to follow */ obj->nobj = obj->nexthere = (struct obj *) 0; if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) { return TRUE; } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || (u.utrap && u.ux == x && u.uy == y)) { if (*verb) pline_The("boulder %s into the pit%s.", vtense((const char *) 0, verb), (mtmp) ? "" : " with you"); if (mtmp) { if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) { if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data)) return FALSE; /* still alive */ } mtmp->mtrapped = 0; } else { if (!Passes_walls && !throws_rocks(youmonst.data)) { losehp(Maybe_Half_Phys(rnd(15)), "squished under a boulder", NO_KILLER_PREFIX); return FALSE; /* player remains trapped */ } else u.utrap = 0; } } if (*verb) { if (Blind && (x == u.ux) && (y == u.uy)) { You_hear("a CRASH! beneath you."); } else if (!Blind && cansee(x, y)) { pline_The("boulder %s%s.", t->tseen ? "" : "triggers and ", t->ttyp == TRAPDOOR ? "plugs a trap door" : t->ttyp == HOLE ? "plugs a hole" : "fills a pit"); } else { You_hear("a boulder %s.", verb); } } deltrap(t); useupf(obj, 1L); bury_objs(x, y); newsym(x, y); return TRUE; } else if (is_lava(x, y)) { return fire_damage(obj, FALSE, x, y); } else if (is_pool(x, y)) { /* Reasonably bulky objects (arbitrary) splash when dropped. * If you're floating above the water even small things make * noise. Stuff dropped near fountains always misses */ if ((Blind || (Levitation || Flying)) && !Deaf && ((x == u.ux) && (y == u.uy))) { if (!Underwater) { if (weight(obj) > 9) { pline("Splash!"); } else if (Levitation || Flying) { pline("Plop!"); } } map_background(x, y, 0); newsym(x, y); } return water_damage(obj, NULL, FALSE) == ER_DESTROYED; } else if (u.ux == x && u.uy == y && (t = t_at(x, y)) != 0 && uteetering_at_seen_pit(t)) { if (Blind && !Deaf) You_hear("%s tumble downwards.", the(xname(obj))); else pline("%s %s into %s pit.", The(xname(obj)), otense(obj, "tumble"), the_your[t->madeby_u]); } else if (obj->globby) { /* Globby things like puddings might stick together */ while (obj && (otmp = obj_nexto_xy(obj->otyp, x, y, obj->o_id)) != (struct obj *) 0) { pudding_merge_message(obj, otmp); /* intentionally not getting the melded object; obj_meld may set * obj to null. */ (void) obj_meld(&obj, &otmp); } return (boolean) (obj == NULL); } return FALSE; } /* obj is an object dropped on an altar */ void doaltarobj(obj) register struct obj *obj; { if (Blind) return; if (obj->oclass != COIN_CLASS) { /* KMH, conduct */ u.uconduct.gnostic++; } else { /* coins don't have bless/curse status */ obj->blessed = obj->cursed = 0; } if (obj->blessed || obj->cursed) { There("is %s flash as %s %s the altar.", an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), doname(obj), otense(obj, "hit")); if (!Hallucination) obj->bknown = 1; } else { pline("%s %s on the altar.", Doname2(obj), otense(obj, "land")); if (obj->oclass != COIN_CLASS) obj->bknown = 1; } } STATIC_OVL void trycall(obj) register struct obj *obj; { if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) docall(obj); } /* Transforms the sink at the player's position into a fountain, throne, altar or grave. */ STATIC_DCL void polymorph_sink() { if (levl[u.ux][u.uy].typ != SINK) return; level.flags.nsinks--; levl[u.ux][u.uy].doormask = 0; switch (rn2(4)) { default: case 0: levl[u.ux][u.uy].typ = FOUNTAIN; level.flags.nfountains++; break; case 1: levl[u.ux][u.uy].typ = THRONE; break; case 2: levl[u.ux][u.uy].typ = ALTAR; levl[u.ux][u.uy].altarmask = Align2amask(rn2((int) A_LAWFUL + 2) - 1); break; case 3: levl[u.ux][u.uy].typ = ROOM; make_grave(u.ux, u.uy, (char *) 0); break; } pline_The("sink transforms into %s!", (levl[u.ux][u.uy].typ == THRONE) ? "a throne" : an(surface(u.ux, u.uy))); newsym(u.ux, u.uy); } /* Teleports the sink at the player's position; return True if sink teleported. */ STATIC_DCL boolean teleport_sink() { int cx, cy; int cnt = 0; struct trap *trp; struct engr *eng; do { cx = rnd(COLNO - 1); cy = rn2(ROWNO); trp = t_at(cx, cy); eng = engr_at(cx, cy); } while ((levl[cx][cy].typ != ROOM || trp || eng || cansee(cx, cy)) && cnt++ < 200); if (levl[cx][cy].typ == ROOM && !trp && !eng) { /* create sink at new position */ levl[cx][cy].typ = SINK; levl[cx][cy].looted = levl[u.ux][u.uy].looted; newsym(cx, cy); /* remove old sink */ levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].looted = 0; newsym(u.ux, u.uy); return TRUE; } return FALSE; } /* obj is a ring being dropped over a kitchen sink */ STATIC_OVL void dosinkring(obj) register struct obj *obj; { struct obj *otmp, *otmp2; boolean ideed = TRUE; boolean nosink = FALSE; You("drop %s down the drain.", doname(obj)); obj->in_use = TRUE; /* block free identification via interrupt */ switch (obj->otyp) { /* effects that can be noticed without eyes */ case RIN_SEARCHING: You("thought %s got lost in the sink, but there it is!", yname(obj)); goto giveback; case RIN_SLOW_DIGESTION: pline_The("ring is regurgitated!"); giveback: obj->in_use = FALSE; dropx(obj); trycall(obj); return; case RIN_LEVITATION: pline_The("sink quivers upward for a moment."); break; case RIN_POISON_RESISTANCE: You("smell rotten %s.", makeplural(fruitname(FALSE))); break; case RIN_AGGRAVATE_MONSTER: pline("Several %s buzz angrily around the sink.", Hallucination ? makeplural(rndmonnam(NULL)) : "flies"); break; case RIN_SHOCK_RESISTANCE: pline("Static electricity surrounds the sink."); break; case RIN_CONFLICT: You_hear("loud noises coming from the drain."); break; case RIN_SUSTAIN_ABILITY: /* KMH */ pline_The("water flow seems fixed."); break; case RIN_GAIN_STRENGTH: pline_The("water flow seems %ser now.", (obj->spe < 0) ? "weak" : "strong"); break; case RIN_GAIN_CONSTITUTION: pline_The("water flow seems %ser now.", (obj->spe < 0) ? "less" : "great"); break; case RIN_INCREASE_ACCURACY: /* KMH */ pline_The("water flow %s the drain.", (obj->spe < 0) ? "misses" : "hits"); break; case RIN_INCREASE_DAMAGE: pline_The("water's force seems %ser now.", (obj->spe < 0) ? "small" : "great"); break; case RIN_HUNGER: ideed = FALSE; for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp != uball && otmp != uchain && !obj_resists(otmp, 1, 99)) { if (!Blind) { pline("Suddenly, %s %s from the sink!", doname(otmp), otense(otmp, "vanish")); ideed = TRUE; } delobj(otmp); } } break; case MEAT_RING: /* Not the same as aggravate monster; besides, it's obvious. */ pline("Several flies buzz around the sink."); break; default: ideed = FALSE; break; } if (!Blind && !ideed && obj->otyp != RIN_HUNGER) { ideed = TRUE; switch (obj->otyp) { /* effects that need eyes */ case RIN_ADORNMENT: pline_The("faucets flash brightly for a moment."); break; case RIN_REGENERATION: pline_The("sink looks as good as new."); break; case RIN_INVISIBILITY: You("don't see anything happen to the sink."); break; case RIN_FREE_ACTION: You_see("the ring slide right down the drain!"); break; case RIN_SEE_INVISIBLE: You_see("some %s in the sink.", Hallucination ? "oxygen molecules" : "air"); break; case RIN_STEALTH: pline_The("sink seems to blend into the floor for a moment."); break; case RIN_FIRE_RESISTANCE: pline_The("hot water faucet flashes brightly for a moment."); break; case RIN_COLD_RESISTANCE: pline_The("cold water faucet flashes brightly for a moment."); break; case RIN_PROTECTION_FROM_SHAPE_CHAN: pline_The("sink looks nothing like a fountain."); break; case RIN_PROTECTION: pline_The("sink glows %s for a moment.", hcolor((obj->spe < 0) ? NH_BLACK : NH_SILVER)); break; case RIN_WARNING: pline_The("sink glows %s for a moment.", hcolor(NH_WHITE)); break; case RIN_TELEPORTATION: nosink = teleport_sink(); pline_The("sink %svanishes.", nosink ? "" : "momentarily "); break; case RIN_TELEPORT_CONTROL: pline_The("sink looks like it is being beamed aboard somewhere."); break; case RIN_POLYMORPH: polymorph_sink(); nosink = TRUE; break; case RIN_POLYMORPH_CONTROL: pline_The( "sink momentarily looks like a regularly erupting geyser."); break; } } if (ideed) trycall(obj); else if (!nosink) You_hear("the ring bouncing down the drainpipe."); if (!rn2(20) && !nosink) { pline_The("sink backs up, leaving %s.", doname(obj)); obj->in_use = FALSE; dropx(obj); } else useup(obj); } /* some common tests when trying to drop or throw items */ boolean canletgo(obj, word) struct obj *obj; const char *word; { if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) { if (*word) Norep("You cannot %s %s you are wearing.", word, something); return FALSE; } if (obj->otyp == LOADSTONE && obj->cursed) { /* getobj() kludge sets corpsenm to user's specified count when refusing to split a stack of cursed loadstones */ if (*word) { /* getobj() ignores a count for throwing since that is implicitly forced to be 1; replicate its kludge... */ if (!strcmp(word, "throw") && obj->quan > 1L) obj->corpsenm = 1; pline("For some reason, you cannot %s%s the stone%s!", word, obj->corpsenm ? " any of" : "", plur(obj->quan)); } obj->corpsenm = 0; /* reset */ obj->bknown = 1; return FALSE; } if (obj->otyp == LEASH && obj->leashmon != 0) { if (*word) pline_The("leash is tied around your %s.", body_part(HAND)); return FALSE; } if (obj->owornmask & W_SADDLE) { if (*word) You("cannot %s %s you are sitting on.", word, something); return FALSE; } return TRUE; } STATIC_PTR int drop(obj) register struct obj *obj; { if (!obj) return 0; if (!canletgo(obj, "drop")) return 0; if (obj == uwep) { if (welded(uwep)) { weldmsg(obj); return 0; } setuwep((struct obj *) 0); } if (obj == uquiver) { setuqwep((struct obj *) 0); } if (obj == uswapwep) { setuswapwep((struct obj *) 0); } if (u.uswallow) { /* barrier between you and the floor */ if (flags.verbose) { char buf[BUFSZ]; /* doname can call s_suffix, reusing its buffer */ Strcpy(buf, s_suffix(mon_nam(u.ustuck))); You("drop %s into %s %s.", doname(obj), buf, mbodypart(u.ustuck, STOMACH)); } } else { if ((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) && IS_SINK(levl[u.ux][u.uy].typ)) { dosinkring(obj); return 1; } if (!can_reach_floor(TRUE)) { /* we might be levitating due to #invoke Heart of Ahriman; if so, levitation would end during call to freeinv() and we want hitfloor() to happen before float_down() */ boolean levhack = finesse_ahriman(obj); if (levhack) ELevitation = W_ART; /* other than W_ARTI */ if (flags.verbose) You("drop %s.", doname(obj)); /* Ensure update when we drop gold objects */ if (obj->oclass == COIN_CLASS) context.botl = 1; freeinv(obj); hitfloor(obj); if (levhack) float_down(I_SPECIAL | TIMEOUT, W_ARTI | W_ART); return 1; } if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) You("drop %s.", doname(obj)); } dropx(obj); return 1; } /* dropx - take dropped item out of inventory; called in several places - may produce output (eg ship_object() and dropy() -> sellobj() both produce output) */ void dropx(obj) register struct obj *obj; { /* Ensure update when we drop gold objects */ if (obj->oclass == COIN_CLASS) context.botl = 1; freeinv(obj); if (!u.uswallow) { if (ship_object(obj, u.ux, u.uy, FALSE)) return; if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); /* set bknown */ } dropy(obj); } /* dropy - put dropped object at destination; called from lots of places */ void dropy(obj) struct obj *obj; { dropz(obj, FALSE); } /* dropz - really put dropped object at its destination... */ void dropz(obj, with_impact) struct obj *obj; boolean with_impact; { if (obj == uwep) setuwep((struct obj *) 0); if (obj == uquiver) setuqwep((struct obj *) 0); if (obj == uswapwep) setuswapwep((struct obj *) 0); if (!u.uswallow && flooreffects(obj, u.ux, u.uy, "drop")) return; /* uswallow check done by GAN 01/29/87 */ if (u.uswallow) { boolean could_petrify = FALSE; boolean could_poly = FALSE; boolean could_slime = FALSE; boolean could_grow = FALSE; boolean could_heal = FALSE; if (obj != uball) { /* mon doesn't pick up ball */ if (obj->otyp == CORPSE) { could_petrify = touch_petrifies(&mons[obj->corpsenm]); could_poly = polyfodder(obj); could_slime = (obj->corpsenm == PM_GREEN_SLIME); could_grow = (obj->corpsenm == PM_WRAITH); could_heal = (obj->corpsenm == PM_NURSE); } (void) mpickobj(u.ustuck, obj); if (is_animal(u.ustuck->data)) { if (could_poly || could_slime) { (void) newcham(u.ustuck, could_poly ? (struct permonst *) 0 : &mons[PM_GREEN_SLIME], FALSE, could_slime); delobj(obj); /* corpse is digested */ } else if (could_petrify) { minstapetrify(u.ustuck, TRUE); /* Don't leave a cockatrice corpse in a statue */ if (!u.uswallow) delobj(obj); } else if (could_grow) { (void) grow_up(u.ustuck, (struct monst *) 0); delobj(obj); /* corpse is digested */ } else if (could_heal) { u.ustuck->mhp = u.ustuck->mhpmax; delobj(obj); /* corpse is digested */ } } } } else { place_object(obj, u.ux, u.uy); if (with_impact) container_impact_dmg(obj, u.ux, u.uy); if (obj == uball) drop_ball(u.ux, u.uy); else if (level.flags.has_shop) sellobj(obj, u.ux, u.uy); stackobj(obj); if (Blind && Levitation) map_object(obj, 0); newsym(u.ux, u.uy); /* remap location under self */ } } /* things that must change when not held; recurse into containers. Called for both player and monsters */ void obj_no_longer_held(obj) struct obj *obj; { if (!obj) { return; } else if (Has_contents(obj)) { struct obj *contents; for (contents = obj->cobj; contents; contents = contents->nobj) obj_no_longer_held(contents); } switch (obj->otyp) { case CRYSKNIFE: /* Normal crysknife reverts to worm tooth when not held by hero * or monster; fixed crysknife has only 10% chance of reverting. * When a stack of the latter is involved, it could be worthwhile * to give each individual crysknife its own separate 10% chance, * but we aren't in any position to handle stack splitting here. */ if (!obj->oerodeproof || !rn2(10)) { /* if monsters aren't moving, assume player is responsible */ if (!context.mon_moving && !program_state.gameover) costly_alteration(obj, COST_DEGRD); obj->otyp = WORM_TOOTH; obj->oerodeproof = 0; } break; } } /* 'D' command: drop several things */ int doddrop() { int result = 0; add_valid_menu_class(0); /* clear any classes already there */ if (*u.ushops) sellobj_state(SELL_DELIBERATE); if (flags.menu_style != MENU_TRADITIONAL || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1) result = menu_drop(result); if (*u.ushops) sellobj_state(SELL_NORMAL); reset_occupations(); return result; } /* Drop things from the hero's inventory, using a menu. */ STATIC_OVL int menu_drop(retry) int retry; { int n, i, n_dropped = 0; long cnt; struct obj *otmp, *otmp2; menu_item *pick_list; boolean all_categories = TRUE; boolean drop_everything = FALSE; if (retry) { all_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { all_categories = FALSE; n = query_category("Drop what type of items?", invent, UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, &pick_list, PICK_ANY); if (!n) goto drop_done; for (i = 0; i < n; i++) { if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_categories = TRUE; else if (pick_list[i].item.a_int == 'A') drop_everything = TRUE; else add_valid_menu_class(pick_list[i].item.a_int); } free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { unsigned ggoresults = 0; all_categories = FALSE; /* Gather valid classes via traditional NetHack method */ i = ggetobj("drop", drop, 0, TRUE, &ggoresults); if (i == -2) all_categories = TRUE; if (ggoresults & ALL_FINISHED) { n_dropped = i; goto drop_done; } } if (drop_everything) { /* * Dropping a burning potion of oil while levitating can cause * an explosion which might destroy some of hero's inventory, * so the old code * for (otmp = invent; otmp; otmp = otmp2) { * otmp2 = otmp->nobj; * n_dropped += drop(otmp); * } * was unreliable and could lead to an "object lost" panic. * * Use the bypass bit to mark items already processed (hence * not droppable) and rescan inventory until no unbypassed * items remain. */ bypass_objlist(invent, FALSE); /* clear bypass bit for invent */ while ((otmp = nxt_unbypassed_obj(invent)) != 0) n_dropped += drop(otmp); /* we might not have dropped everything (worn armor, welded weapon, cursed loadstones), so reset any remaining inventory to normal */ bypass_objlist(invent, FALSE); } else { /* should coordinate with perm invent, maybe not show worn items */ n = query_objlist("What would you like to drop?", invent, USE_INVLET | INVORDER_SORT, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n > 0) { /* * picklist[] contains a set of pointers into inventory, but * as soon as something gets dropped, they might become stale * (see the drop_everything code above for an explanation). * Just checking to see whether one is still in the invent * chain is not sufficient validation since destroyed items * will be freed and items we've split here might have already * reused that memory and put the same pointer value back into * invent. Ditto for using invlet to validate. So we start * by setting bypass on all of invent, then check each pointer * to verify that it is in invent and has that bit set. */ bypass_objlist(invent, TRUE); for (i = 0; i < n; i++) { otmp = pick_list[i].item.a_obj; for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj) if (otmp2 == otmp) break; if (!otmp2 || !otmp2->bypass) continue; /* found next selected invent item */ cnt = pick_list[i].count; if (cnt < otmp->quan) { if (welded(otmp)) { ; /* don't split */ } else if (otmp->otyp == LOADSTONE && otmp->cursed) { /* same kludge as getobj(), for canletgo()'s use */ otmp->corpsenm = (int) cnt; /* don't split */ } else { otmp = splitobj(otmp, cnt); } } n_dropped += drop(otmp); } bypass_objlist(invent, FALSE); /* reset invent to normal */ free((genericptr_t) pick_list); } } drop_done: return n_dropped; } /* on a ladder, used in goto_level */ static NEARDATA boolean at_ladder = FALSE; /* the '>' command */ int dodown() { struct trap *trap = 0; boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)), ladder_down = (u.ux == xdnladder && u.uy == ydnladder); if (u_rooted()) return 1; if (stucksteed(TRUE)) { return 0; } /* Levitation might be blocked, but player can still use '>' to turn off controlled levitation */ if (HLevitation || ELevitation) { if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) { /* end controlled levitation */ if (ELevitation & W_ARTI) { struct obj *obj; for (obj = invent; obj; obj = obj->nobj) { if (obj->oartifact && artifact_has_invprop(obj, LEVITATION)) { if (obj->age < monstermoves) obj->age = monstermoves; obj->age += rnz(100); } } } if (float_down(I_SPECIAL | TIMEOUT, W_ARTI)) { return 1; /* came down, so moved */ } else if (!HLevitation && !ELevitation) { Your("latent levitation ceases."); return 1; /* did something, effectively moved */ } } if (BLevitation) { ; /* weren't actually floating after all */ } else if (Blind) { /* Avoid alerting player to an unknown stair or ladder. * Changes the message for a covered, known staircase * too; staircase knowledge is not stored anywhere. */ if (stairs_down) stairs_down = (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnstair); else if (ladder_down) ladder_down = (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnladder); } floating_above(stairs_down ? "stairs" : ladder_down ? "ladder" : surface(u.ux, u.uy)); return 0; /* didn't move */ } if (!stairs_down && !ladder_down) { trap = t_at(u.ux, u.uy); if (trap && uteetering_at_seen_pit(trap)) { dotrap(trap, TOOKPLUNGE); return 1; } else if (!trap || (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) || !Can_fall_thru(&u.uz) || !trap->tseen) { if (flags.autodig && !context.nopick && uwep && is_pick(uwep)) { return use_pick_axe2(uwep); } else { You_cant("go down here."); return 0; } } } if (u.ustuck) { You("are %s, and cannot go down.", !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); return 1; } if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) { You("are standing at the gate to Gehennom."); pline("Unspeakable cruelty and harm lurk down there."); if (yn("Are you sure you want to enter?") != 'y') return 0; else pline("So be it."); u.uevent.gehennom_entered = 1; /* don't ask again */ } if (!next_to_u()) { You("are held back by your pet!"); return 0; } if (trap) You("%s %s.", Flying ? "fly" : locomotion(youmonst.data, "jump"), trap->ttyp == HOLE ? "down the hole" : "through the trap door"); if (trap && Is_stronghold(&u.uz)) { goto_hell(FALSE, TRUE); } else { at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); next_level(!trap); at_ladder = FALSE; } return 1; } /* the '<' command */ int doup() { if (u_rooted()) return 1; /* "up" to get out of a pit... */ if (u.utrap && u.utraptype == TT_PIT) { climb_pit(); return 1; } if ((u.ux != xupstair || u.uy != yupstair) && (!xupladder || u.ux != xupladder || u.uy != yupladder) && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy || !sstairs.up)) { You_cant("go up here."); return 0; } if (stucksteed(TRUE)) { return 0; } if (u.ustuck) { You("are %s, and cannot go up.", !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); return 1; } if (near_capacity() > SLT_ENCUMBER) { /* No levitation check; inv_weight() already allows for it */ Your("load is too heavy to climb the %s.", levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder"); return 1; } if (ledger_no(&u.uz) == 1) { if (yn("Beware, there will be no return! Still climb?") != 'y') return 0; } if (!next_to_u()) { You("are held back by your pet!"); return 0; } at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); prev_level(TRUE); at_ladder = FALSE; return 1; } d_level save_dlevel = { 0, 0 }; /* check that we can write out the current level */ STATIC_OVL int currentlevel_rewrite() { register int fd; char whynot[BUFSZ]; /* since level change might be a bit slow, flush any buffered screen * output (like "you fall through a trap door") */ mark_synch(); fd = create_levelfile(ledger_no(&u.uz), whynot); if (fd < 0) { /* * This is not quite impossible: e.g., we may have * exceeded our quota. If that is the case then we * cannot leave this level, and cannot save either. * Another possibility is that the directory was not * writable. */ pline1(whynot); return -1; } #ifdef MFLOPPY if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) { (void) nhclose(fd); delete_levelfile(ledger_no(&u.uz)); pline("NetHack is out of disk space for making levels!"); You("can save, quit, or continue playing."); return -1; } #endif return fd; } #ifdef INSURANCE void save_currentstate() { int fd; if (flags.ins_chkpt) { /* write out just-attained level, with pets and everything */ fd = currentlevel_rewrite(); if (fd < 0) return; bufon(fd); savelev(fd, ledger_no(&u.uz), WRITE_SAVE); bclose(fd); } /* write out non-level state */ savestateinlock(); } #endif /* static boolean badspot(x, y) register xchar x, y; { return (boolean) ((levl[x][y].typ != ROOM && levl[x][y].typ != AIR && levl[x][y].typ != CORR) || MON_AT(x, y)); } */ void goto_level(newlevel, at_stairs, falling, portal) d_level *newlevel; boolean at_stairs, falling, portal; { int fd, l_idx; xchar new_ledger; boolean cant_go_back, up = (depth(newlevel) < depth(&u.uz)), newdungeon = (u.uz.dnum != newlevel->dnum), was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz), familiar = FALSE; boolean new = FALSE; /* made a new level? */ struct monst *mtmp; char whynot[BUFSZ]; char *annotation; if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) newlevel->dlevel = dunlevs_in_dungeon(newlevel); if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */ if (!u.uhave.amulet) return; /* must have the Amulet */ if (!wizard) /* wizard ^V can bypass Earth level */ assign_level(newlevel, &earth_level); /* (redundant) */ } new_ledger = ledger_no(newlevel); if (new_ledger <= 0) done(ESCAPED); /* in fact < 0 is impossible */ /* If you have the amulet and are trying to get out of Gehennom, * going up a set of stairs sometimes does some very strange things! * Biased against law and towards chaos. (The chance to be sent * down multiple levels when attempting to go up are significantly * less than the corresponding comment in older versions indicated * due to overlooking the effect of the call to assign_rnd_lvl().) * * Odds for making it to the next level up, or of being sent down: * "up" L N C * +1 75.0 75.0 75.0 * 0 6.25 8.33 12.5 * -1 11.46 12.50 12.5 * -2 5.21 4.17 0.0 * -3 2.08 0.0 0.0 */ if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) { if (!rn2(4)) { int odds = 3 + (int) u.ualign.type, /* 2..4 */ diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ if (diff != 0) { assign_rnd_level(newlevel, &u.uz, diff); /* if inside the tower, stay inside */ if (was_in_W_tower && !On_W_tower_level(newlevel)) diff = 0; } if (diff == 0) assign_level(newlevel, &u.uz); new_ledger = ledger_no(newlevel); pline("A mysterious force momentarily surrounds you..."); if (on_level(newlevel, &u.uz)) { (void) safe_teleds(FALSE); (void) next_to_u(); return; } else at_stairs = at_ladder = FALSE; } } /* Prevent the player from going past the first quest level unless * (s)he has been given the go-ahead by the leader. */ if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { pline("A mysterious force prevents you from descending."); return; } if (on_level(newlevel, &u.uz)) return; /* this can happen */ /* tethered movement makes level change while trapped feasible */ if (u.utrap && u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); /* (before we save/leave old level) */ fd = currentlevel_rewrite(); if (fd < 0) return; if (falling) /* assuming this is only trap door or hole */ impact_drop((struct obj *) 0, u.ux, u.uy, newlevel->dlevel); check_special_room(TRUE); /* probably was a trap door */ if (Punished) unplacebc(); u.utrap = 0; /* needed in level_tele */ fill_pit(u.ux, u.uy); u.ustuck = 0; /* idem */ u.uinwater = 0; u.uundetected = 0; /* not hidden, even if means are available */ keepdogs(FALSE); if (u.uswallow) /* idem */ u.uswldtim = u.uswallow = 0; recalc_mapseen(); /* recalculate map overview before we leave the level */ /* * We no longer see anything on the level. Make sure that this * follows u.uswallow set to null since uswallow overrides all * normal vision. */ vision_recalc(2); /* * Save the level we're leaving. If we're entering the endgame, * we can get rid of all existing levels because they cannot be * reached any more. We still need to use savelev()'s cleanup * for the level being left, to recover dynamic memory in use and * to avoid dangling timers and light sources. */ cant_go_back = (newdungeon && In_endgame(newlevel)); if (!cant_go_back) { update_mlstmv(); /* current monsters are becoming inactive */ bufon(fd); /* use buffered output */ } savelev(fd, ledger_no(&u.uz), cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); bclose(fd); if (cant_go_back) { /* discard unreachable levels; keep #0 */ for (l_idx = maxledgerno(); l_idx > 0; --l_idx) delete_levelfile(l_idx); /* mark #overview data for all dungeon branches as uninteresting */ for (l_idx = 0; l_idx < n_dgns; ++l_idx) remdun_mapseen(l_idx); } if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY); #ifdef USE_TILES substitute_tiles(newlevel); #endif /* record this level transition as a potential seen branch unless using * some non-standard means of transportation (level teleport). */ if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum)) recbranch_mapseen(&u.uz, newlevel); assign_level(&u.uz0, &u.uz); assign_level(&u.uz, newlevel); assign_level(&u.utolev, newlevel); u.utotype = 0; if (!builds_up(&u.uz)) { /* usual case */ if (dunlev(&u.uz) > dunlev_reached(&u.uz)) dunlev_reached(&u.uz) = dunlev(&u.uz); } else { if (dunlev_reached(&u.uz) == 0 || dunlev(&u.uz) < dunlev_reached(&u.uz)) dunlev_reached(&u.uz) = dunlev(&u.uz); } reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ /* set default level change destination areas */ /* the special level code may override these */ (void) memset((genericptr_t) &updest, 0, sizeof updest); (void) memset((genericptr_t) &dndest, 0, sizeof dndest); if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { /* entering this level for first time; make it now */ if (level_info[new_ledger].flags & (FORGOTTEN | VISITED)) { impossible("goto_level: returning to discarded level?"); level_info[new_ledger].flags &= ~(FORGOTTEN | VISITED); } mklev(); new = TRUE; /* made the level */ } else { /* returning to previously visited level; reload it */ fd = open_levelfile(new_ledger, whynot); if (tricked_fileremoved(fd, whynot)) { /* we'll reach here if running in wizard mode */ error("Cannot continue this game."); } minit(); /* ZEROCOMP */ getlev(fd, hackpid, new_ledger, FALSE); (void) nhclose(fd); oinit(); /* reassign level dependent obj probabilities */ } reglyph_darkroom(); /* do this prior to level-change pline messages */ vision_reset(); /* clear old level's line-of-sight */ vision_full_recalc = 0; /* don't let that reenable vision yet */ flush_screen(-1); /* ensure all map flushes are postponed */ if (portal && !In_endgame(&u.uz)) { /* find the portal on the new level */ register struct trap *ttrap; for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) if (ttrap->ttyp == MAGIC_PORTAL) break; if (!ttrap) panic("goto_level: no corresponding portal!"); seetrap(ttrap); u_on_newpos(ttrap->tx, ttrap->ty); } else if (at_stairs && !In_endgame(&u.uz)) { if (up) { if (at_ladder) u_on_newpos(xdnladder, ydnladder); else if (newdungeon) u_on_sstairs(1); else u_on_dnstairs(); /* you climb up the {stairs|ladder}; fly up the stairs; fly up along the ladder */ pline("%s %s up%s the %s.", (Punished && !Levitation) ? "With great effort you" : "You", Flying ? "fly" : "climb", (Flying && at_ladder) ? " along" : "", at_ladder ? "ladder" : "stairs"); } else { /* down */ if (at_ladder) u_on_newpos(xupladder, yupladder); else if (newdungeon) u_on_sstairs(0); else u_on_upstairs(); if (!u.dz) { ; /* stayed on same level? (no transit effects) */ } else if (Flying) { if (flags.verbose) You("fly down %s.", at_ladder ? "along the ladder" : "the stairs"); } else if (near_capacity() > UNENCUMBERED || Punished || Fumbling) { You("fall down the %s.", at_ladder ? "ladder" : "stairs"); if (Punished) { drag_down(); ballrelease(FALSE); } /* falling off steed has its own losehp() call */ if (u.usteed) dismount_steed(DISMOUNT_FELL); else losehp(Maybe_Half_Phys(rnd(3)), at_ladder ? "falling off a ladder" : "tumbling down a flight of stairs", KILLED_BY); selftouch("Falling, you"); } else { /* ordinary descent */ if (flags.verbose) You("%s.", at_ladder ? "climb down the ladder" : "descend the stairs"); } } } else { /* trap door or level_tele or In_endgame */ u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0)); if (falling) { if (Punished) ballfall(); selftouch("Falling, you"); } } if (Punished) placebc(); obj_delivery(FALSE); losedogs(); kill_genocided_monsters(); /* for those wiped out while in limbo */ /* * Expire all timers that have gone off while away. Must be * after migrating monsters and objects are delivered * (losedogs and obj_delivery). */ run_timers(); initrack(); if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) { /* There's a monster at your target destination; it might be one which accompanied you--see mon_arrive(dogmove.c)--or perhaps it was already here. Randomly move you to an adjacent spot or else the monster to any nearby location. Prior to 3.3.0 the latter was done unconditionally. */ coord cc; if (!rn2(2) && enexto(&cc, u.ux, u.uy, youmonst.data) && distu(cc.x, cc.y) <= 2) u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ else mnexto(mtmp); if ((mtmp = m_at(u.ux, u.uy)) != 0) { /* there was an unconditional impossible("mnearto failed") here, but it's not impossible and we're prepared to cope with the situation, so only say something when debugging */ if (wizard) pline("(monster in hero's way)"); if (!rloc(mtmp, TRUE)) /* no room to move it; send it away, to return later */ migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_RANDOM, (coord *) 0); } } /* initial movement of bubbles just before vision_recalc */ if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) movebubbles(); else if (Is_firelevel(&u.uz)) fumaroles(); if (level_info[new_ledger].flags & FORGOTTEN) { forget_map(ALL_MAP); /* forget the map */ forget_traps(); /* forget all traps too */ familiar = TRUE; level_info[new_ledger].flags &= ~FORGOTTEN; } /* Reset the screen. */ vision_reset(); /* reset the blockages */ docrt(); /* does a full vision recalc */ flush_screen(-1); /* * Move all plines beyond the screen reset. */ /* special levels can have a custom arrival message */ deliver_splev_message(); /* give room entrance message, if any */ check_special_room(FALSE); /* deliver objects traveling with player */ obj_delivery(TRUE); /* Check whether we just entered Gehennom. */ if (!In_hell(&u.uz0) && Inhell) { if (Is_valley(&u.uz)) { You("arrive at the Valley of the Dead..."); pline_The("odor of burnt flesh and decay pervades the air."); #ifdef MICRO display_nhwindow(WIN_MESSAGE, FALSE); #endif You_hear("groans and moans everywhere."); } else pline("It is hot here. You smell smoke..."); u.uachieve.enter_gehennom = 1; } /* in case we've managed to bypass the Valley's stairway down */ if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1; if (familiar) { static const char *const fam_msgs[4] = { "You have a sense of deja vu.", "You feel like you've been here before.", "This place %s familiar...", 0 /* no message */ }; static const char *const halu_fam_msgs[4] = { "Whoa! Everything %s different.", "You are surrounded by twisty little passages, all alike.", "Gee, this %s like uncle Conan's place...", 0 /* no message */ }; const char *mesg; char buf[BUFSZ]; int which = rn2(4); if (Hallucination) mesg = halu_fam_msgs[which]; else mesg = fam_msgs[which]; if (mesg && index(mesg, '%')) { Sprintf(buf, mesg, !Blind ? "looks" : "seems"); mesg = buf; } if (mesg) pline1(mesg); } /* special location arrival messages/events */ if (In_endgame(&u.uz)) { if (new &&on_level(&u.uz, &astral_level)) final_level(); /* guardian angel,&c */ else if (newdungeon && u.uhave.amulet) resurrect(); /* force confrontation with Wizard */ } else if (In_quest(&u.uz)) { onquest(); /* might be reaching locate|goal level */ } else if (In_V_tower(&u.uz)) { if (newdungeon && In_hell(&u.uz0)) pline_The("heat and smoke are gone."); } else if (Is_knox(&u.uz)) { /* alarm stops working once Croesus has died */ if (new || !mvitals[PM_CROESUS].died) { You("have penetrated a high security area!"); pline("An alarm sounds!"); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mtmp->msleeping = 0; } } } else { if (new && Is_rogue_level(&u.uz)) You("enter what seems to be an older, more primitive world."); /* main dungeon message from your quest leader */ if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && !(u.uevent.qcompleted || u.uevent.qexpelled || quest_status.leader_is_dead)) { if (!u.uevent.qcalled) { u.uevent.qcalled = 1; com_pager(2); /* main "leader needs help" message */ } else { /* reminder message */ com_pager(Role_if(PM_ROGUE) ? 4 : 3); } } } assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ #ifdef INSURANCE save_currentstate(); #endif if ((annotation = get_annotation(&u.uz))) You("remember this level as %s.", annotation); /* assume this will always return TRUE when changing level */ (void) in_out_region(u.ux, u.uy); (void) pickup(1); context.polearm.hitmon = NULL; } STATIC_OVL void final_level() { struct monst *mtmp; /* reset monster hostility relative to player */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; reset_hostility(mtmp); } /* create some player-monsters */ create_mplayers(rn1(4, 3), TRUE); /* create a guardian angel next to player, if worthy */ gain_guardian_angel(); } static char *dfr_pre_msg = 0, /* pline() before level change */ *dfr_post_msg = 0; /* pline() after level change */ /* change levels at the end of this turn, after monsters finish moving */ void schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg) d_level *tolev; boolean at_stairs, falling; int portal_flag; const char *pre_msg, *post_msg; { int typmask = 0100; /* non-zero triggers `deferred_goto' */ /* destination flags (`goto_level' args) */ if (at_stairs) typmask |= 1; if (falling) typmask |= 2; if (portal_flag) typmask |= 4; if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */ u.utotype = typmask; /* destination level */ assign_level(&u.utolev, tolev); if (pre_msg) dfr_pre_msg = dupstr(pre_msg); if (post_msg) dfr_post_msg = dupstr(post_msg); } /* handle something like portal ejection */ void deferred_goto() { if (!on_level(&u.uz, &u.utolev)) { d_level dest; int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */ assign_level(&dest, &u.utolev); if (dfr_pre_msg) pline1(dfr_pre_msg); goto_level(&dest, !!(typmask & 1), !!(typmask & 2), !!(typmask & 4)); if (typmask & 0200) { /* remove portal */ struct trap *t = t_at(u.ux, u.uy); if (t) { deltrap(t); newsym(u.ux, u.uy); } } if (dfr_post_msg) pline1(dfr_post_msg); } u.utotype = 0; /* our caller keys off of this */ if (dfr_pre_msg) free((genericptr_t) dfr_pre_msg), dfr_pre_msg = 0; if (dfr_post_msg) free((genericptr_t) dfr_post_msg), dfr_post_msg = 0; } /* * Return TRUE if we created a monster for the corpse. If successful, the * corpse is gone. */ boolean revive_corpse(corpse) struct obj *corpse; { struct monst *mtmp, *mcarry; boolean is_uwep, chewed; xchar where; char cname[BUFSZ]; struct obj *container = (struct obj *) 0; int container_where = 0; where = corpse->where; is_uwep = (corpse == uwep); chewed = (corpse->oeaten != 0); Strcpy(cname, corpse_xname(corpse, chewed ? "bite-covered" : (const char *) 0, CXN_SINGULAR)); mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0; if (where == OBJ_CONTAINED) { struct monst *mtmp2; container = corpse->ocontainer; mtmp2 = get_container_location(container, &container_where, (int *) 0); /* container_where is the outermost container's location even if * nested */ if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2; } mtmp = revive(corpse, FALSE); /* corpse is gone if successful */ if (mtmp) { switch (where) { case OBJ_INVENT: if (is_uwep) pline_The("%s writhes out of your grasp!", cname); else You_feel("squirming in your backpack!"); break; case OBJ_FLOOR: if (cansee(mtmp->mx, mtmp->my)) pline("%s rises from the dead!", chewed ? Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); break; case OBJ_MINVENT: /* probably a nymph's */ if (cansee(mtmp->mx, mtmp->my)) { if (canseemon(mcarry)) pline("Startled, %s drops %s as it revives!", mon_nam(mcarry), an(cname)); else pline("%s suddenly appears!", chewed ? Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); } break; case OBJ_CONTAINED: { char sackname[BUFSZ]; if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) && mcarry && canseemon(mcarry) && container) { pline("%s writhes out of %s!", Amonnam(mtmp), yname(container)); } else if (container_where == OBJ_INVENT && container) { Strcpy(sackname, an(xname(container))); pline("%s %s out of %s in your pack!", Blind ? Something : Amonnam(mtmp), locomotion(mtmp->data, "writhes"), sackname); } else if (container_where == OBJ_FLOOR && container && cansee(mtmp->mx, mtmp->my)) { Strcpy(sackname, an(xname(container))); pline("%s escapes from %s!", Amonnam(mtmp), sackname); } break; } default: /* we should be able to handle the other cases... */ impossible("revive_corpse: lost corpse @ %d", where); break; } return TRUE; } return FALSE; } /* Revive the corpse via a timeout. */ /*ARGSUSED*/ void revive_mon(arg, timeout) anything *arg; long timeout UNUSED; { struct obj *body = arg->a_obj; struct permonst *mptr = &mons[body->corpsenm]; struct monst *mtmp; xchar x, y; /* corpse will revive somewhere else if there is a monster in the way; Riders get a chance to try to bump the obstacle out of their way */ if ((mptr->mflags3 & M3_DISPLACES) != 0 && body->where == OBJ_FLOOR && get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) { boolean notice_it = canseemon(mtmp); /* before rloc() */ char *monname = Monnam(mtmp); if (rloc(mtmp, TRUE)) { if (notice_it && !canseemon(mtmp)) pline("%s vanishes.", monname); else if (!notice_it && canseemon(mtmp)) pline("%s appears.", Monnam(mtmp)); /* not pre-rloc monname */ else if (notice_it && dist2(mtmp->mx, mtmp->my, x, y) > 2) pline("%s teleports.", monname); /* saw it and still see it */ } } /* if we succeed, the corpse is gone */ if (!revive_corpse(body)) { long when; int action; if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */ action = REVIVE_MON; for (when = 3L; when < 67L; when++) if (!rn2(3)) break; } else { /* rot this corpse away */ You_feel("%sless hassled.", is_rider(mptr) ? "much " : ""); action = ROT_CORPSE; when = 250L - (monstermoves - body->age); if (when < 1L) when = 1L; } (void) start_timer(when, TIMER_OBJECT, action, arg); } } int donull() { return 1; /* Do nothing, but let other things happen */ } STATIC_PTR int wipeoff(VOID_ARGS) { if (u.ucreamed < 4) u.ucreamed = 0; else u.ucreamed -= 4; if (Blinded < 4) Blinded = 0; else Blinded -= 4; if (!Blinded) { pline("You've got the glop off."); u.ucreamed = 0; if (!gulp_blnd_check()) { Blinded = 1; make_blinded(0L, TRUE); } return 0; } else if (!u.ucreamed) { Your("%s feels clean now.", body_part(FACE)); return 0; } return 1; /* still busy */ } int dowipe() { if (u.ucreamed) { static NEARDATA char buf[39]; Sprintf(buf, "wiping off your %s", body_part(FACE)); set_occupation(wipeoff, buf, 0); /* Not totally correct; what if they change back after now * but before they're finished wiping? */ return 1; } Your("%s is already clean.", body_part(FACE)); return 1; } void set_wounded_legs(side, timex) register long side; register int timex; { /* KMH -- STEED * If you are riding, your steed gets the wounded legs instead. * You still call this function, but don't lose hp. * Caller is also responsible for adjusting messages. */ if (!Wounded_legs) { ATEMP(A_DEX)--; context.botl = 1; } if (!Wounded_legs || (HWounded_legs & TIMEOUT)) HWounded_legs = timex; EWounded_legs = side; (void) encumber_msg(); } void heal_legs() { if (Wounded_legs) { if (ATEMP(A_DEX) < 0) { ATEMP(A_DEX)++; context.botl = 1; } if (!u.usteed) { const char *legs = body_part(LEG); if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) legs = makeplural(legs); /* this used to say "somewhat better" but that was misleading since legs are being fully healed */ Your("%s %s better.", legs, vtense(legs, "feel")); } HWounded_legs = EWounded_legs = 0; /* Wounded_legs reduces carrying capacity, so we want an encumbrance check when they're healed. However, while dismounting, first steed's legs get healed, then hero is dropped to floor and a new encumbrance check is made [in dismount_steed()]. So don't give encumbrance feedback during the dismount stage because it could seem to be shown out of order and it might be immediately contradicted [able to carry more when steed becomes healthy, then possible floor feedback, then able to carry less when back on foot]. */ if (!in_steed_dismounting) (void) encumber_msg(); } } /*do.c*/ nethack-3.6.0/src/do_name.c0000664000076400007660000012516312617122742014506 0ustar paxedpaxed/* NetHack 3.6 do_name.c $NHDT-Date: 1446808440 2015/11/06 11:14:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); STATIC_DCL void NDECL(do_mname); STATIC_DCL void FDECL(do_oname, (struct obj *)); STATIC_DCL void NDECL(namefloorobj); STATIC_DCL char *FDECL(bogusmon, (char *,char *)); extern const char what_is_an_unknown_object[]; /* from pager.c */ #define NUMMBUF 5 /* manage a pool of BUFSZ buffers, so callers don't have to */ STATIC_OVL char * nextmbuf() { static char NEARDATA bufs[NUMMBUF][BUFSZ]; static int bufidx = 0; bufidx = (bufidx + 1) % NUMMBUF; return bufs[bufidx]; } /* function for getpos() to highlight desired map locations. * parameter value 0 = initialize, 1 = highlight, 2 = done */ void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0; void getpos_sethilite(f) void FDECL((*f), (int)); { getpos_hilitefunc = f; } /* the response for '?' help request in getpos() */ STATIC_OVL void getpos_help(force, goal) boolean force; const char *goal; { char sbuf[BUFSZ]; boolean doing_what_is; winid tmpwin = create_nhwindow(NHW_MENU); Sprintf(sbuf, "Use [%c%c%c%c] to move the cursor to %s.", /* hjkl */ Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal); putstr(tmpwin, 0, sbuf); putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time."); putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); if (getpos_hilitefunc != NULL) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); /* disgusting hack; the alternate selection characters work for any getpos call, but they only matter for dowhatis (and doquickwhatis) */ doing_what_is = (goal == what_is_an_unknown_object); Sprintf(sbuf, "Type a .%s when you are at the right place.", doing_what_is ? " or , or ; or :" : ""); putstr(tmpwin, 0, sbuf); if (!force) putstr(tmpwin, 0, "Type Space or Escape when you're done."); putstr(tmpwin, 0, ""); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } int getpos(ccp, force, goal) coord *ccp; boolean force; const char *goal; { int result = 0; int cx, cy, i, c; int sidx, tx, ty; boolean msg_given = TRUE; /* clear message window by default */ boolean auto_msg = FALSE; boolean show_goal_msg = FALSE; static const char pick_chars[] = ".,;:"; const char *cp; boolean hilite_state = FALSE; if (!goal) goal = "desired location"; if (flags.verbose) { pline("(For instructions type a ?)"); msg_given = TRUE; } cx = ccp->x; cy = ccp->y; #ifdef CLIPPING cliparound(cx, cy); #endif curs(WIN_MAP, cx, cy); flush_screen(0); #ifdef MAC lock_mouse_cursor(TRUE); #endif for (;;) { if (show_goal_msg) { pline("Move cursor to %s:", goal); curs(WIN_MAP, cx, cy); flush_screen(0); show_goal_msg = FALSE; } else if (auto_msg && !msg_given && !hilite_state) { coord cc; int sym = 0; char tmpbuf[BUFSZ]; const char *firstmatch = NULL; cc.x = cx; cc.y = cy; if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { pline1(firstmatch); curs(WIN_MAP, cx, cy); flush_screen(0); } } c = nh_poskey(&tx, &ty, &sidx); if (hilite_state) { (*getpos_hilitefunc)(2); hilite_state = FALSE; curs(WIN_MAP, cx, cy); flush_screen(0); } if (auto_msg) msg_given = FALSE; if (c == '\033') { cx = cy = -10; msg_given = TRUE; /* force clear */ result = -1; break; } if (c == 0) { if (!isok(tx, ty)) continue; /* a mouse click event, just assign and return */ cx = tx; cy = ty; break; } if ((cp = index(pick_chars, c)) != 0) { /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */ result = (int) (cp - pick_chars); break; } for (i = 0; i < 8; i++) { int dx, dy; if (Cmd.dirchars[i] == c) { /* a normal movement letter or digit */ dx = xdir[i]; dy = ydir[i]; } else if (Cmd.alphadirchars[i] == lowc((char) c) || (Cmd.num_pad && Cmd.dirchars[i] == (c & 0177))) { /* a shifted movement letter or Meta-digit */ dx = 8 * xdir[i]; dy = 8 * ydir[i]; } else continue; /* truncate at map edge; diagonal moves complicate this... */ if (cx + dx < 1) { dy -= sgn(dy) * (1 - (cx + dx)); dx = 1 - cx; /* so that (cx+dx == 1) */ } else if (cx + dx > COLNO - 1) { dy += sgn(dy) * ((COLNO - 1) - (cx + dx)); dx = (COLNO - 1) - cx; } if (cy + dy < 0) { dx -= sgn(dx) * (0 - (cy + dy)); dy = 0 - cy; /* so that (cy+dy == 0) */ } else if (cy + dy > ROWNO - 1) { dx += sgn(dx) * ((ROWNO - 1) - (cy + dy)); dy = (ROWNO - 1) - cy; } cx += dx; cy += dy; goto nxtc; } if (c == '?' || redraw_cmd(c)) { if (c == '?') getpos_help(force, goal); else /* ^R */ docrt(); /* redraw */ /* update message window to reflect that we're still targetting */ show_goal_msg = TRUE; msg_given = TRUE; } else if ((c == '$') && (getpos_hilitefunc != NULL)) { if (!hilite_state) { (*getpos_hilitefunc)(0); (*getpos_hilitefunc)(1); hilite_state = TRUE; } goto nxtc; } else if (c == '#') { auto_msg = !auto_msg; pline("Automatic description %sis %s.", flags.verbose ? "of features under cursor " : "", auto_msg ? "on" : "off"); if (!auto_msg) show_goal_msg = TRUE; msg_given = TRUE; goto nxtc; } else if (c == '@') { cx = u.ux; cy = u.uy; goto nxtc; } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; int pass, lo_x, lo_y, hi_x, hi_y, k = 0; (void) memset((genericptr_t) matching, 0, sizeof matching); for (sidx = 1; sidx < MAXPCHARS; sidx++) if (c == defsyms[sidx].sym || c == (int) showsyms[sidx]) matching[sidx] = (char) ++k; if (k) { for (pass = 0; pass <= 1; pass++) { /* pass 0: just past current pos to lower right; pass 1: upper left corner to current pos */ lo_y = (pass == 0) ? cy : 0; hi_y = (pass == 0) ? ROWNO - 1 : cy; for (ty = lo_y; ty <= hi_y; ty++) { lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1; hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1; for (tx = lo_x; tx <= hi_x; tx++) { /* look at dungeon feature, not at * user-visible glyph */ k = back_to_glyph(tx, ty); /* uninteresting background glyph */ if (glyph_is_cmap(k) && (IS_DOOR(levl[tx][ty].typ) || glyph_to_cmap(k) == S_room || glyph_to_cmap(k) == S_darkroom || glyph_to_cmap(k) == S_corr || glyph_to_cmap(k) == S_litcorr)) { /* what hero remembers to be at tx,ty */ k = glyph_at(tx, ty); } if (glyph_is_cmap(k) && matching[glyph_to_cmap(k)] && levl[tx][ty].seenv && (!IS_WALL(levl[tx][ty].typ)) && (levl[tx][ty].typ != SDOOR) && glyph_to_cmap(k) != S_room && glyph_to_cmap(k) != S_corr && glyph_to_cmap(k) != S_litcorr) { cx = tx, cy = ty; if (msg_given) { clear_nhwindow(WIN_MESSAGE); msg_given = FALSE; } goto nxtc; } } /* column */ } /* row */ } /* pass */ pline("Can't find dungeon feature '%c'.", c); msg_given = TRUE; goto nxtc; } else { char note[QBUFSZ]; if (!force) Strcpy(note, "aborted"); else Sprintf(note, "use %c%c%c%c or .", /* hjkl */ Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E); pline("Unknown direction: '%s' (%s).", visctrl((char) c), note); msg_given = TRUE; } /* k => matching */ } /* !quitchars */ if (force) goto nxtc; pline("Done."); msg_given = FALSE; /* suppress clear */ cx = -1; cy = 0; result = 0; /* not -1 */ break; } nxtc: ; #ifdef CLIPPING cliparound(cx, cy); #endif curs(WIN_MAP, cx, cy); flush_screen(0); } #ifdef MAC lock_mouse_cursor(FALSE); #endif if (msg_given) clear_nhwindow(WIN_MESSAGE); ccp->x = cx; ccp->y = cy; getpos_hilitefunc = NULL; return result; } /* allocate space for a monster's name; removes old name if there is one */ void new_mname(mon, lth) struct monst *mon; int lth; /* desired length (caller handles adding 1 for terminator) */ { if (lth) { /* allocate mextra if necessary; otherwise get rid of old name */ if (!mon->mextra) mon->mextra = newmextra(); else free_mname(mon); /* already has mextra, might also have name */ MNAME(mon) = (char *) alloc((unsigned) lth); } else { /* zero length: the new name is empty; get rid of the old name */ if (has_mname(mon)) free_mname(mon); } } /* release a monster's name; retains mextra even if all fields are now null */ void free_mname(mon) struct monst *mon; { if (has_mname(mon)) { free((genericptr_t) MNAME(mon)); MNAME(mon) = (char *) 0; } } /* allocate space for an object's name; removes old name if there is one */ void new_oname(obj, lth) struct obj *obj; int lth; /* desired length (caller handles adding 1 for terminator) */ { if (lth) { /* allocate oextra if necessary; otherwise get rid of old name */ if (!obj->oextra) obj->oextra = newoextra(); else free_oname(obj); /* already has oextra, might also have name */ ONAME(obj) = (char *) alloc((unsigned) lth); } else { /* zero length: the new name is empty; get rid of the old name */ if (has_oname(obj)) free_oname(obj); } } /* release an object's name; retains oextra even if all fields are now null */ void free_oname(obj) struct obj *obj; { if (has_oname(obj)) { free((genericptr_t) ONAME(obj)); ONAME(obj) = (char *) 0; } } /* safe_oname() always returns a valid pointer to * a string, either the pointer to an object's name * if it has one, or a pointer to an empty string * if it doesn't. */ const char * safe_oname(obj) struct obj *obj; { if (has_oname(obj)) return ONAME(obj); return ""; } /* historical note: this returns a monster pointer because it used to allocate a new bigger block of memory to hold the monster and its name */ struct monst * christen_monst(mtmp, name) struct monst *mtmp; const char *name; { int lth; char buf[PL_PSIZ]; /* dogname & catname are PL_PSIZ arrays; object names have same limit */ lth = (name && *name) ? ((int) strlen(name) + 1) : 0; if (lth > PL_PSIZ) { lth = PL_PSIZ; name = strncpy(buf, name, PL_PSIZ - 1); buf[PL_PSIZ - 1] = '\0'; } new_mname(mtmp, lth); /* removes old name if one is present */ if (lth) Strcpy(MNAME(mtmp), name); return mtmp; } /* allow player to assign a name to some chosen monster */ STATIC_OVL void do_mname() { char buf[BUFSZ], monnambuf[BUFSZ]; coord cc; register int cx, cy; register struct monst *mtmp; char qbuf[QBUFSZ]; if (Hallucination) { You("would never recognize it anyway."); return; } cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, FALSE, "the monster you want to name") < 0 || (cx = cc.x) < 0) return; cy = cc.y; if (cx == u.ux && cy == u.uy) { if (u.usteed && canspotmon(u.usteed)) mtmp = u.usteed; else { pline("This %s creature is called %s and cannot be renamed.", beautiful(), plname); return; } } else mtmp = m_at(cx, cy); if (!mtmp || (!sensemon(mtmp) && (!(cansee(cx, cy) || see_with_infrared(mtmp)) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT || (mtmp->minvis && !See_invisible)))) { pline("I see no monster there."); return; } /* special case similar to the one in lookat() */ Sprintf(qbuf, "What do you want to call %s?", distant_monnam(mtmp, ARTICLE_THE, monnambuf)); getlin(qbuf, buf); if (!*buf || *buf == '\033') return; /* strip leading and trailing spaces; unnames monster if all spaces */ (void) mungspaces(buf); /* unique monsters have their own specific names or titles; shopkeepers, temple priests and other minions use alternate name formatting routines which ignore any user-supplied name */ if (mtmp->data->geno & G_UNIQ) pline("%s doesn't like being called names!", upstart(monnambuf)); else if (mtmp->isshk && !(Deaf || mtmp->msleeping || !mtmp->mcanmove || mtmp->data->msound <= MS_ANIMAL)) verbalize("I'm %s, not %s.", shkname(mtmp), buf); else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk) pline("%s will not accept the name %s.", upstart(monnambuf), buf); else (void) christen_monst(mtmp, buf); } /* * This routine changes the address of obj. Be careful not to call it * when there might be pointers around in unknown places. For now: only * when obj is in the inventory. */ STATIC_OVL void do_oname(obj) register struct obj *obj; { char *bufp, buf[BUFSZ], bufcpy[BUFSZ], qbuf[QBUFSZ]; const char *aname; short objtyp; /* Do this now because there's no point in even asking for a name */ if (obj->otyp == SPE_NOVEL) { pline("%s already has a published name.", Ysimple_name2(obj)); return; } Sprintf(qbuf, "What do you want to name %s ", is_plural(obj) ? "these" : "this"); (void) safe_qbuf(qbuf, qbuf, "?", obj, xname, simpleonames, "item"); getlin(qbuf, buf); if (!*buf || *buf == '\033') return; /* strip leading and trailing spaces; unnames item if all spaces */ (void) mungspaces(buf); /* relax restrictions over proper capitalization for artifacts */ if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp) Strcpy(buf, aname); if (obj->oartifact) { pline_The("artifact seems to resist the attempt."); return; } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) { /* this used to change one letter, substituting a value of 'a' through 'y' (due to an off by one error, 'z' would never be selected) and then force that to upper case if such was the case of the input; now, the hand slip scuffs one or two letters as if the text had been trodden upon, sometimes picking punctuation instead of an arbitrary letter; unfortunately, we have to cover the possibility of it targetting spaces so failing to make any change (we know that it must eventually target a nonspace because buf[] matches a valid artifact name) */ Strcpy(bufcpy, buf); /* for "the Foo of Bar", only scuff "Foo of Bar" part */ bufp = !strncmpi(bufcpy, "the ", 4) ? (buf + 4) : buf; do { wipeout_text(bufp, rnd(2), (unsigned) 0); } while (!strcmp(buf, bufcpy)); pline("While engraving, your %s slips.", body_part(HAND)); display_nhwindow(WIN_MESSAGE, FALSE); You("engrave: \"%s\".", buf); } obj = oname(obj, buf); } struct obj * oname(obj, name) struct obj *obj; const char *name; { int lth; char buf[PL_PSIZ]; lth = *name ? (int) (strlen(name) + 1) : 0; if (lth > PL_PSIZ) { lth = PL_PSIZ; name = strncpy(buf, name, PL_PSIZ - 1); buf[PL_PSIZ - 1] = '\0'; } /* If named artifact exists in the game, do not create another. * Also trying to create an artifact shouldn't de-artifact * it (e.g. Excalibur from prayer). In this case the object * will retain its current name. */ if (obj->oartifact || (lth && exist_artifact(obj->otyp, name))) return obj; new_oname(obj, lth); /* removes old name if one is present */ if (lth) Strcpy(ONAME(obj), name); if (lth) artifact_exists(obj, name, TRUE); if (obj->oartifact) { /* can't dual-wield with artifact as secondary weapon */ if (obj == uswapwep) untwoweapon(); /* activate warning if you've just named your weapon "Sting" */ if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP); /* if obj is owned by a shop, increase your bill */ if (obj->unpaid) alter_cost(obj, 0L); } if (carried(obj)) update_inventory(); return obj; } static NEARDATA const char callable[] = { SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 }; boolean objtyp_is_callable(i) int i; { return (boolean) (objects[i].oc_uname || (OBJ_DESCR(objects[i]) && index(callable, objects[i].oc_class))); } /* C and #name commands - player can name monster or object or type of obj */ int docallcmd() { struct obj *obj; winid win; anything any; menu_item *pick_list = 0; char ch, allowall[2]; /* if player wants a,b,c instead of i,o when looting, do that here too */ boolean abc = flags.lootabc; win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; any.a_char = 'm'; /* group accelerator 'C' */ add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'C', ATR_NONE, "a monster", MENU_UNSELECTED); if (invent) { /* we use y and n as accelerators so that we can accept user's response keyed to old "name an individual object?" prompt */ any.a_char = 'i'; /* group accelerator 'y' */ add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'y', ATR_NONE, "a particular object in inventory", MENU_UNSELECTED); any.a_char = 'o'; /* group accelerator 'n' */ add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'n', ATR_NONE, "the type of an object in inventory", MENU_UNSELECTED); } any.a_char = 'f'; /* group accelerator ',' (or ':' instead?) */ add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, ',', ATR_NONE, "the type of an object upon the floor", MENU_UNSELECTED); any.a_char = 'd'; /* group accelerator '\' */ add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, '\\', ATR_NONE, "the type of an object on discoveries list", MENU_UNSELECTED); any.a_char = 'a'; /* group accelerator 'l' */ add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'l', ATR_NONE, "record an annotation for the current level", MENU_UNSELECTED); end_menu(win, "What do you want to name?"); if (select_menu(win, PICK_ONE, &pick_list) > 0) { ch = pick_list[0].item.a_char; free((genericptr_t) pick_list); } else ch = 'q'; destroy_nhwindow(win); switch (ch) { default: case 'q': break; case 'm': /* name a visible monster */ do_mname(); break; case 'i': /* name an individual object in inventory */ allowall[0] = ALL_CLASSES; allowall[1] = '\0'; obj = getobj(allowall, "name"); if (obj) do_oname(obj); break; case 'o': /* name a type of object in inventory */ obj = getobj(callable, "call"); if (obj) { /* behave as if examining it in inventory; this might set dknown if it was picked up while blind and the hero can now see */ (void) xname(obj); if (!obj->dknown) { You("would never recognize another one."); #if 0 } else if (!objtyp_is_callable(obj->otyp)) { You("know those as well as you ever will."); #endif } else { docall(obj); } } break; case 'f': /* name a type of object visible on the floor */ namefloorobj(); break; case 'd': /* name a type of object on the discoveries list */ rename_disco(); break; case 'a': /* annotate level */ donamelevel(); break; } return 0; } void docall(obj) register struct obj *obj; { char buf[BUFSZ], qbuf[QBUFSZ]; struct obj otemp; register char **str1; if (!obj->dknown) return; /* probably blind */ otemp = *obj; otemp.quan = 1L; otemp.oextra = (struct oextra *) 0; if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink) /* kludge, meaning it's sink water */ Sprintf(qbuf, "Call a stream of %s fluid:", OBJ_DESCR(objects[otemp.otyp])); else Sprintf(qbuf, "Call %s:", an(xname(&otemp))); getlin(qbuf, buf); if (!*buf || *buf == '\033') return; /* clear old name */ str1 = &(objects[obj->otyp].oc_uname); if (*str1) free((genericptr_t) *str1); /* strip leading and trailing spaces; uncalls item if all spaces */ (void) mungspaces(buf); if (!*buf) { if (*str1) { /* had name, so possibly remove from disco[] */ /* strip name first, for the update_inventory() call from undiscover_object() */ *str1 = (char *) 0; undiscover_object(obj->otyp); } } else { *str1 = dupstr(buf); discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */ } } STATIC_OVL void namefloorobj() { coord cc; int glyph; char buf[BUFSZ]; struct obj *obj = 0; boolean fakeobj = FALSE, use_plural; cc.x = u.ux, cc.y = u.uy; /* "dot for under/over you" only makes sense when the cursor hasn't been moved off the hero's '@' yet, but there's no way to adjust the help text once getpos() has started */ Sprintf(buf, "object on map (or '.' for one %s you)", (u.uundetected && hides_under(youmonst.data)) ? "over" : "under"); if (getpos(&cc, FALSE, buf) < 0 || cc.x <= 0) return; if (cc.x == u.ux && cc.y == u.uy) { obj = vobj_at(u.ux, u.uy); } else { glyph = glyph_at(cc.x, cc.y); if (glyph_is_object(glyph)) fakeobj = object_from_map(glyph, cc.x, cc.y, &obj); /* else 'obj' stays null */ } if (!obj) { /* "under you" is safe here since there's no object to hide under */ pline("There doesn't seem to be any object %s.", (cc.x == u.ux && cc.y == u.uy) ? "under you" : "there"); return; } /* note well: 'obj' might be as instance of STRANGE_OBJECT if target is a mimic; passing that to xname (directly or via simpleonames) would yield "glorkum" so we need to handle it explicitly; it will always fail the Hallucination test and pass the !callable test, resulting in the "can't be assigned a type name" message */ Strcpy(buf, (obj->otyp != STRANGE_OBJECT) ? simpleonames(obj) : obj_descr[STRANGE_OBJECT].oc_name); use_plural = (obj->quan > 1L); if (Hallucination) { const char *unames[6]; char tmpbuf[BUFSZ]; /* straight role name */ unames[0] = ((Upolyd ? u.mfemale : flags.female) && urole.name.f) ? urole.name.f : urole.name.m; /* random rank title for hero's role */ unames[1] = rank_of(rnd(30), Role_switch, flags.female); /* random fake monster */ unames[2] = bogusmon(tmpbuf, (char *) 0); /* increased chance for fake monster */ unames[3] = unames[2]; /* traditional */ unames[4] = roguename(); /* silly */ unames[5] = "Wibbly Wobbly"; pline("%s %s to call you \"%s.\"", The(buf), use_plural ? "decide" : "decides", unames[rn2(SIZE(unames))]); } else if (!objtyp_is_callable(obj->otyp)) { pline("%s %s can't be assigned a type name.", use_plural ? "Those" : "That", buf); } else if (!obj->dknown) { You("don't know %s %s well enough to name %s.", use_plural ? "those" : "that", buf, use_plural ? "them" : "it"); } else { docall(obj); } if (fakeobj) dealloc_obj(obj); } static const char *const ghostnames[] = { /* these names should have length < PL_NSIZ */ /* Capitalize the names for aesthetics -dgk */ "Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile", "Frans", "Fred", "Greg", "Hether", "Jay", "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue", "Stephan", "Lance Braccus", "Shadowhawk" }; /* ghost names formerly set by x_monnam(), now by makemon() instead */ const char * rndghostname() { return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *) plname; } /* * Monster naming functions: * x_monnam is the generic monster-naming function. * seen unseen detected named * mon_nam: the newt it the invisible orc Fido * noit_mon_nam:the newt (as if detected) the invisible orc Fido * l_monnam: newt it invisible orc dog called Fido * Monnam: The newt It The invisible orc Fido * noit_Monnam: The newt (as if detected) The invisible orc Fido * Adjmonnam: The poor newt It The poor invisible orc The poor Fido * Amonnam: A newt It An invisible orc Fido * a_monnam: a newt it an invisible orc Fido * m_monnam: newt xan orc Fido * y_monnam: your newt your xan your invisible orc Fido */ /* Bug: if the monster is a priest or shopkeeper, not every one of these * options works, since those are special cases. */ char * x_monnam(mtmp, article, adjective, suppress, called) register struct monst *mtmp; int article; /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious * ARTICLE_YOUR: "your" on pets, "the" on everything else * * If the monster would be referred to as "it" or if the monster has a name * _and_ there is no adjective, "invisible", "saddled", etc., override this * and always use no article. */ const char *adjective; int suppress; /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE. * EXACT_NAME: combination of all the above */ boolean called; { char *buf = nextmbuf(); struct permonst *mdat = mtmp->data; const char *pm_name = mdat->mname; boolean do_hallu, do_invis, do_it, do_saddle; boolean name_at_start, has_adjectives; char *bp; if (program_state.gameover) suppress |= SUPPRESS_HALLUCINATION; if (article == ARTICLE_YOUR && !mtmp->mtame) article = ARTICLE_THE; do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION); do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE); do_it = !canspotmon(mtmp) && article != ARTICLE_YOUR && !program_state.gameover && mtmp != u.usteed && !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT); do_saddle = !(suppress & SUPPRESS_SADDLE); buf[0] = '\0'; /* unseen monsters, etc. Use "it" */ if (do_it) { Strcpy(buf, "it"); return buf; } /* priests and minions: don't even use this function */ if (mtmp->ispriest || mtmp->isminion) { char priestnambuf[BUFSZ]; char *name; long save_prop = EHalluc_resistance; unsigned save_invis = mtmp->minvis; /* when true name is wanted, explicitly block Hallucination */ if (!do_hallu) EHalluc_resistance = 1L; if (!do_invis) mtmp->minvis = 0; name = priestname(mtmp, priestnambuf); EHalluc_resistance = save_prop; mtmp->minvis = save_invis; if (article == ARTICLE_NONE && !strncmp(name, "the ", 4)) name += 4; return strcpy(buf, name); } /* an "aligned priest" not flagged as a priest or minion should be "priest" or "priestess" (normally handled by priestname()) */ if (mdat == &mons[PM_ALIGNED_PRIEST]) pm_name = mtmp->female ? "priestess" : "priest"; else if (mdat == &mons[PM_HIGH_PRIEST] && mtmp->female) pm_name = "high priestess"; /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating, * none of this applies. */ if (mtmp->isshk && !do_hallu) { if (adjective && article == ARTICLE_THE) { /* pathological case: "the angry Asidonhopo the blue dragon" sounds silly */ Strcpy(buf, "the "); Strcat(strcat(buf, adjective), " "); Strcat(buf, shkname(mtmp)); return buf; } Strcat(buf, shkname(mtmp)); if (mdat == &mons[PM_SHOPKEEPER] && !do_invis) return buf; Strcat(buf, " the "); if (do_invis) Strcat(buf, "invisible "); Strcat(buf, pm_name); return buf; } /* Put the adjectives in the buffer */ if (adjective) Strcat(strcat(buf, adjective), " "); if (do_invis) Strcat(buf, "invisible "); if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind && !Hallucination) Strcat(buf, "saddled "); if (buf[0] != 0) has_adjectives = TRUE; else has_adjectives = FALSE; /* Put the actual monster name or type into the buffer now */ /* Be sure to remember whether the buffer starts with a name */ if (do_hallu) { char rnamecode; char *rname = rndmonnam(&rnamecode); Strcat(buf, rname); name_at_start = bogon_is_pname(rnamecode); } else if (has_mname(mtmp)) { char *name = MNAME(mtmp); if (mdat == &mons[PM_GHOST]) { Sprintf(eos(buf), "%s ghost", s_suffix(name)); name_at_start = TRUE; } else if (called) { Sprintf(eos(buf), "%s called %s", pm_name, name); name_at_start = (boolean) type_is_pname(mdat); } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) { /* the */ char pbuf[BUFSZ]; Strcpy(pbuf, name); pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */ if (has_adjectives) Strcat(pbuf, buf); Strcat(pbuf, bp + 5); /* append the rest of the name */ Strcpy(buf, pbuf); article = ARTICLE_NONE; name_at_start = TRUE; } else { Strcat(buf, name); name_at_start = TRUE; } } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) { char pbuf[BUFSZ]; Strcpy(pbuf, rank_of((int) mtmp->m_lev, monsndx(mdat), (boolean) mtmp->female)); Strcat(buf, lcase(pbuf)); name_at_start = FALSE; } else { Strcat(buf, pm_name); name_at_start = (boolean) type_is_pname(mdat); } if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) { if (mdat == &mons[PM_WIZARD_OF_YENDOR]) article = ARTICLE_THE; else article = ARTICLE_NONE; } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) { article = ARTICLE_THE; } { char buf2[BUFSZ]; switch (article) { case ARTICLE_YOUR: Strcpy(buf2, "your "); Strcat(buf2, buf); Strcpy(buf, buf2); return buf; case ARTICLE_THE: Strcpy(buf2, "the "); Strcat(buf2, buf); Strcpy(buf, buf2); return buf; case ARTICLE_A: return an(buf); case ARTICLE_NONE: default: return buf; } } } char * l_monnam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE); } char * mon_nam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_THE, (char *) 0, (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE); } /* print the name as if mon_nam() was called, but assume that the player * can always see the monster--used for probing and for monsters aggravating * the player with a cursed potion of invisibility */ char * noit_mon_nam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_THE, (char *) 0, (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT) : SUPPRESS_IT, FALSE); } char * Monnam(mtmp) struct monst *mtmp; { register char *bp = mon_nam(mtmp); *bp = highc(*bp); return bp; } char * noit_Monnam(mtmp) struct monst *mtmp; { register char *bp = noit_mon_nam(mtmp); *bp = highc(*bp); return bp; } /* monster's own name */ char * m_monnam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, EXACT_NAME, FALSE); } /* pet name: "your little dog" */ char * y_monnam(mtmp) struct monst *mtmp; { int prefix, suppression_flag; prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE; suppression_flag = (has_mname(mtmp) /* "saddled" is redundant when mounted */ || mtmp == u.usteed) ? SUPPRESS_SADDLE : 0; return x_monnam(mtmp, prefix, (char *) 0, suppression_flag, FALSE); } char * Adjmonnam(mtmp, adj) struct monst *mtmp; const char *adj; { char *bp = x_monnam(mtmp, ARTICLE_THE, adj, has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); *bp = highc(*bp); return bp; } char * a_monnam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_A, (char *) 0, has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); } char * Amonnam(mtmp) struct monst *mtmp; { char *bp = a_monnam(mtmp); *bp = highc(*bp); return bp; } /* used for monster ID by the '/', ';', and 'C' commands to block remote identification of the endgame altars via their attending priests */ char * distant_monnam(mon, article, outbuf) struct monst *mon; int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */ char *outbuf; { /* high priest(ess)'s identity is concealed on the Astral Plane, unless you're adjacent (overridden for hallucination which does its own obfuscation) */ if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) { Strcpy(outbuf, article == ARTICLE_THE ? "the " : ""); Strcat(outbuf, mon->female ? "high priestess" : "high priest"); } else { Strcpy(outbuf, x_monnam(mon, article, (char *) 0, 0, TRUE)); } return outbuf; } /* fake monsters used to be in a hard-coded array, now in a data file */ STATIC_OVL char * bogusmon(buf, code) char *buf, *code; { char *mname = buf; get_rnd_text(BOGUSMONFILE, buf); /* strip prefix if present */ if (!letter(*mname)) { if (code) *code = *mname; ++mname; } else { if (code) *code = '\0'; } return mname; } /* return a random monster name, for hallucination */ char * rndmonnam(code) char *code; { static char buf[BUFSZ]; char *mname; int name; #define BOGUSMONSIZE 100 /* arbitrary */ if (code) *code = '\0'; do { name = rn1(SPECIAL_PM + BOGUSMONSIZE - LOW_PM, LOW_PM); } while (name < SPECIAL_PM && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN))); if (name >= SPECIAL_PM) { mname = bogusmon(buf, code); } else { mname = strcpy(buf, mons[name].mname); } return mname; #undef BOGUSMONSIZE } /* check bogusmon prefix to decide whether it's a personal name */ boolean bogon_is_pname(code) char code; { if (!code) return FALSE; return index("-+=", code) ? TRUE : FALSE; } /* name of a Rogue player */ const char * roguename() { char *i, *opts; if ((opts = nh_getenv("ROGUEOPTS")) != 0) { for (i = opts; *i; i++) if (!strncmp("name=", i, 5)) { char *j; if ((j = index(i + 5, ',')) != 0) *j = (char) 0; return i + 5; } } return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold") : "Glenn Wichman"; } static NEARDATA const char *const hcolors[] = { "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white", "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter", "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley", "blotchy", "guernsey-spotted", "polka-dotted", "square", "round", "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime", "strawberry-banana", "peppermint", "romantic", "incandescent", "octarine", /* Discworld: the Colour of Magic */ }; const char * hcolor(colorpref) const char *colorpref; { return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))] : colorpref; } /* return a random real color unless hallucinating */ const char * rndcolor() { int k = rn2(CLR_MAX); return Hallucination ? hcolor((char *) 0) : (k == NO_COLOR) ? "colorless" : c_obj_colors[k]; } /* Aliases for road-runner nemesis */ static const char *const coynames[] = { "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus", "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius", "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus", "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus", "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus", "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris", "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii", "Canis latrans" }; char * coyotename(mtmp, buf) struct monst *mtmp; char *buf; { if (mtmp && buf) { Sprintf(buf, "%s - %s", x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE), mtmp->mcan ? coynames[SIZE(coynames) - 1] : coynames[rn2(SIZE(coynames) - 1)]); } return buf; } /* make sure "The Colour of Magic" remains the first entry in here */ static const char *const sir_Terry_novels[] = { "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort", "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric", "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods", "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times", "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent", "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time", "The Last Hero", "The Amazing Maurice and his Educated Rodents", "Night Watch", "The Wee Free Men", "Monstrous Regiment", "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith", "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff", "Raising Steam", "The Shepherd's Crown" }; const char * noveltitle(novidx) int *novidx; { int j, k = SIZE(sir_Terry_novels); j = rn2(k); if (novidx) { if (*novidx == -1) *novidx = j; else if (*novidx >= 0 && *novidx < k) j = *novidx; } return sir_Terry_novels[j]; } const char * lookup_novel(lookname, idx) const char *lookname; int *idx; { int k; /* Take American or U.K. spelling of this one */ if (!strcmpi(The(lookname), "The Color of Magic")) lookname = sir_Terry_novels[0]; for (k = 0; k < SIZE(sir_Terry_novels); ++k) { if (!strcmpi(lookname, sir_Terry_novels[k]) || !strcmpi(The(lookname), sir_Terry_novels[k])) { if (idx) *idx = k; return sir_Terry_novels[k]; } } /* name not found; if novelidx is already set, override the name */ if (idx && *idx >= 0 && *idx < SIZE(sir_Terry_novels)) return sir_Terry_novels[*idx]; return (const char *) 0; } /*do_name.c*/ nethack-3.6.0/src/do_wear.c0000664000076400007660000024671312623162643014532 0ustar paxedpaxed/* NetHack 3.6 do_wear.c $NHDT-Date: 1446975698 2015/11/08 09:41:38 $ $NHDT-Branch: master $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" static NEARDATA const char see_yourself[] = "see yourself"; static NEARDATA const char unknown_type[] = "Unknown type of %s (%d)"; static NEARDATA const char c_armor[] = "armor", c_suit[] = "suit", c_shirt[] = "shirt", c_cloak[] = "cloak", c_gloves[] = "gloves", c_boots[] = "boots", c_helmet[] = "helmet", c_shield[] = "shield", c_weapon[] = "weapon", c_sword[] = "sword", c_axe[] = "axe", c_that_[] = "that"; static NEARDATA const long takeoff_order[] = { WORN_BLINDF, W_WEP, WORN_SHIELD, WORN_GLOVES, LEFT_RING, RIGHT_RING, WORN_CLOAK, WORN_HELMET, WORN_AMUL, WORN_ARMOR, WORN_SHIRT, WORN_BOOTS, W_SWAPWEP, W_QUIVER, 0L }; STATIC_DCL void FDECL(on_msg, (struct obj *)); STATIC_DCL void FDECL(toggle_stealth, (struct obj *, long, BOOLEAN_P)); STATIC_DCL void FDECL(toggle_displacement, (struct obj *, long, BOOLEAN_P)); STATIC_PTR int NDECL(Armor_on); STATIC_PTR int NDECL(Boots_on); STATIC_PTR int NDECL(Cloak_on); STATIC_PTR int NDECL(Helmet_on); STATIC_PTR int NDECL(Gloves_on); STATIC_DCL void FDECL(wielding_corpse, (struct obj *, BOOLEAN_P)); STATIC_PTR int NDECL(Shield_on); STATIC_PTR int NDECL(Shirt_on); STATIC_DCL void NDECL(Amulet_on); STATIC_DCL void FDECL(learnring, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(Ring_off_or_gone, (struct obj *, BOOLEAN_P)); STATIC_PTR int FDECL(select_off, (struct obj *)); STATIC_DCL struct obj *NDECL(do_takeoff); STATIC_PTR int NDECL(take_off); STATIC_DCL int FDECL(menu_remarm, (int)); STATIC_DCL void FDECL(count_worn_stuff, (struct obj **, BOOLEAN_P)); STATIC_PTR int FDECL(armor_or_accessory_off, (struct obj *)); STATIC_PTR int FDECL(accessory_or_armor_on, (struct obj *)); STATIC_DCL void FDECL(already_wearing, (const char *)); STATIC_DCL void FDECL(already_wearing2, (const char *, const char *)); void off_msg(otmp) struct obj *otmp; { if (flags.verbose) You("were wearing %s.", doname(otmp)); } /* for items that involve no delay */ STATIC_OVL void on_msg(otmp) struct obj *otmp; { if (flags.verbose) { char how[BUFSZ]; /* call xname() before obj_is_pname(); formatting obj's name might set obj->dknown and that affects the pname test */ const char *otmp_name = xname(otmp); how[0] = '\0'; if (otmp->otyp == TOWEL) Sprintf(how, " around your %s", body_part(HEAD)); You("are now wearing %s%s.", obj_is_pname(otmp) ? the(otmp_name) : an(otmp_name), how); } } /* starting equipment gets auto-worn at beginning of new game, and we don't want stealth or displacement feedback then */ static boolean initial_don = FALSE; /* manipulated in set_wear() */ /* putting on or taking off an item which confers stealth; give feedback and discover it iff stealth state is changing */ STATIC_OVL void toggle_stealth(obj, oldprop, on) struct obj *obj; long oldprop; /* prop[].extrinsic, with obj->owornmask stripped by caller */ boolean on; { if (on ? initial_don : context.takeoff.cancelled_don) return; if (!oldprop /* extrinsic stealth from something else */ && !HStealth /* intrinsic stealth */ && !BStealth) { /* stealth blocked by something */ if (obj->otyp == RIN_STEALTH) learnring(obj, TRUE); else makeknown(obj->otyp); if (on) { if (!is_boots(obj)) You("move very quietly."); else if (Levitation || Flying) You("float imperceptibly."); else You("walk very quietly."); } else { You("sure are noisy."); } } } /* putting on or taking off an item which confers displacement; give feedback and discover it iff displacement state is changing *and* hero is able to see self (or sense monsters) */ STATIC_OVL void toggle_displacement(obj, oldprop, on) struct obj *obj; long oldprop; /* prop[].extrinsic, with obj->owornmask stripped by caller */ boolean on; { if (on ? initial_don : context.takeoff.cancelled_don) return; if (!oldprop /* extrinsic displacement from something else */ && !(u.uprops[DISPLACED].intrinsic) /* (theoretical) */ && !(u.uprops[DISPLACED].blocked) /* (also theoretical) */ /* we don't use canseeself() here because it augments vision with touch, which isn't appropriate for deciding whether we'll notice that monsters have trouble spotting the hero */ && ((!Blind /* see anything */ && !u.uswallow /* see surroundings */ && !Invisible) /* see self */ /* actively sensing nearby monsters via telepathy or extended monster detection overrides vision considerations because hero also senses self in this situation */ || (Unblind_telepat || (Blind_telepat && Blind) || Detect_monsters))) { makeknown(obj->otyp); You_feel("that monsters%s have difficulty pinpointing your location.", on ? "" : " no longer"); } } /* * The Type_on() functions should be called *after* setworn(). * The Type_off() functions call setworn() themselves. * [Blindf_on() is an exception and calls setworn() itself.] */ STATIC_PTR int Boots_on(VOID_ARGS) { long oldprop = u.uprops[objects[uarmf->otyp].oc_oprop].extrinsic & ~WORN_BOOTS; switch (uarmf->otyp) { case LOW_BOOTS: case IRON_SHOES: case HIGH_BOOTS: case JUMPING_BOOTS: case KICKING_BOOTS: break; case WATER_WALKING_BOOTS: if (u.uinwater) spoteffects(TRUE); /* (we don't need a lava check here since boots can't be put on while feet are stuck) */ break; case SPEED_BOOTS: /* Speed boots are still better than intrinsic speed, */ /* though not better than potion speed */ if (!oldprop && !(HFast & TIMEOUT)) { makeknown(uarmf->otyp); You_feel("yourself speed up%s.", (oldprop || HFast) ? " a bit more" : ""); } break; case ELVEN_BOOTS: toggle_stealth(uarmf, oldprop, TRUE); break; case FUMBLE_BOOTS: if (!oldprop && !(HFumbling & ~TIMEOUT)) incr_itimeout(&HFumbling, rnd(20)); break; case LEVITATION_BOOTS: if (!oldprop && !HLevitation && !BLevitation) { makeknown(uarmf->otyp); float_up(); spoteffects(FALSE); } else { float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ } break; default: impossible(unknown_type, c_boots, uarmf->otyp); } return 0; } int Boots_off(VOID_ARGS) { struct obj *otmp = uarmf; int otyp = otmp->otyp; long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_BOOTS; context.takeoff.mask &= ~W_ARMF; /* For levitation, float_down() returns if Levitation, so we * must do a setworn() _before_ the levitation case. */ setworn((struct obj *) 0, W_ARMF); switch (otyp) { case SPEED_BOOTS: if (!Very_fast && !context.takeoff.cancelled_don) { makeknown(otyp); You_feel("yourself slow down%s.", Fast ? " a bit" : ""); } break; case WATER_WALKING_BOOTS: /* check for lava since fireproofed boots make it viable */ if ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) && !Levitation && !Flying && !is_clinger(youmonst.data) && !context.takeoff.cancelled_don /* avoid recursive call to lava_effects() */ && !iflags.in_lava_effects) { /* make boots known in case you survive the drowning */ makeknown(otyp); spoteffects(TRUE); } break; case ELVEN_BOOTS: toggle_stealth(otmp, oldprop, FALSE); break; case FUMBLE_BOOTS: if (!oldprop && !(HFumbling & ~TIMEOUT)) HFumbling = EFumbling = 0; break; case LEVITATION_BOOTS: if (!oldprop && !HLevitation && !BLevitation && !context.takeoff.cancelled_don) { (void) float_down(0L, 0L); makeknown(otyp); } else { float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ } break; case LOW_BOOTS: case IRON_SHOES: case HIGH_BOOTS: case JUMPING_BOOTS: case KICKING_BOOTS: break; default: impossible(unknown_type, c_boots, otyp); } context.takeoff.cancelled_don = FALSE; return 0; } STATIC_PTR int Cloak_on(VOID_ARGS) { long oldprop = u.uprops[objects[uarmc->otyp].oc_oprop].extrinsic & ~WORN_CLOAK; switch (uarmc->otyp) { case ORCISH_CLOAK: case DWARVISH_CLOAK: case CLOAK_OF_MAGIC_RESISTANCE: case ROBE: case LEATHER_CLOAK: break; case CLOAK_OF_PROTECTION: makeknown(uarmc->otyp); break; case ELVEN_CLOAK: toggle_stealth(uarmc, oldprop, TRUE); break; case CLOAK_OF_DISPLACEMENT: toggle_displacement(uarmc, oldprop, TRUE); break; case MUMMY_WRAPPING: /* Note: it's already being worn, so we have to cheat here. */ if ((HInvis || EInvis) && !Blind) { newsym(u.ux, u.uy); You("can %s!", See_invisible ? "no longer see through yourself" : see_yourself); } break; case CLOAK_OF_INVISIBILITY: /* since cloak of invisibility was worn, we know mummy wrapping wasn't, so no need to check `oldprop' against blocked */ if (!oldprop && !HInvis && !Blind) { makeknown(uarmc->otyp); newsym(u.ux, u.uy); pline("Suddenly you can%s yourself.", See_invisible ? " see through" : "not see"); } break; case OILSKIN_CLOAK: pline("%s very tightly.", Tobjnam(uarmc, "fit")); break; /* Alchemy smock gives poison _and_ acid resistance */ case ALCHEMY_SMOCK: EAcid_resistance |= WORN_CLOAK; break; default: impossible(unknown_type, c_cloak, uarmc->otyp); } return 0; } int Cloak_off(VOID_ARGS) { struct obj *otmp = uarmc; int otyp = otmp->otyp; long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_CLOAK; context.takeoff.mask &= ~W_ARMC; /* For mummy wrapping, taking it off first resets `Invisible'. */ setworn((struct obj *) 0, W_ARMC); switch (otyp) { case ORCISH_CLOAK: case DWARVISH_CLOAK: case CLOAK_OF_PROTECTION: case CLOAK_OF_MAGIC_RESISTANCE: case OILSKIN_CLOAK: case ROBE: case LEATHER_CLOAK: break; case ELVEN_CLOAK: toggle_stealth(otmp, oldprop, FALSE); break; case CLOAK_OF_DISPLACEMENT: toggle_displacement(otmp, oldprop, FALSE); break; case MUMMY_WRAPPING: if (Invis && !Blind) { newsym(u.ux, u.uy); You("can %s.", See_invisible ? "see through yourself" : "no longer see yourself"); } break; case CLOAK_OF_INVISIBILITY: if (!oldprop && !HInvis && !Blind) { makeknown(CLOAK_OF_INVISIBILITY); newsym(u.ux, u.uy); pline("Suddenly you can %s.", See_invisible ? "no longer see through yourself" : see_yourself); } break; /* Alchemy smock gives poison _and_ acid resistance */ case ALCHEMY_SMOCK: EAcid_resistance &= ~WORN_CLOAK; break; default: impossible(unknown_type, c_cloak, otyp); } return 0; } STATIC_PTR int Helmet_on(VOID_ARGS) { switch (uarmh->otyp) { case FEDORA: case HELMET: case DENTED_POT: case ELVEN_LEATHER_HELM: case DWARVISH_IRON_HELM: case ORCISH_HELM: case HELM_OF_TELEPATHY: break; case HELM_OF_BRILLIANCE: adj_abon(uarmh, uarmh->spe); break; case CORNUTHAUM: /* people think marked wizards know what they're talking * about, but it takes trained arrogance to pull it off, * and the actual enchantment of the hat is irrelevant. */ ABON(A_CHA) += (Role_if(PM_WIZARD) ? 1 : -1); context.botl = 1; makeknown(uarmh->otyp); break; case HELM_OF_OPPOSITE_ALIGNMENT: /* changing alignment can toggle off active artifact properties, including levitation; uarmh could get dropped or destroyed here */ uchangealign((u.ualign.type != A_NEUTRAL) ? -u.ualign.type : (uarmh->o_id % 2) ? A_CHAOTIC : A_LAWFUL, 1); /* makeknown(uarmh->otyp); -- moved below, after xname() */ /*FALLTHRU*/ case DUNCE_CAP: if (uarmh && !uarmh->cursed) { if (Blind) pline("%s for a moment.", Tobjnam(uarmh, "vibrate")); else pline("%s %s for a moment.", Tobjnam(uarmh, "glow"), hcolor(NH_BLACK)); curse(uarmh); } context.botl = 1; /* reveal new alignment or INT & WIS */ if (Hallucination) { pline("My brain hurts!"); /* Monty Python's Flying Circus */ } else if (uarmh && uarmh->otyp == DUNCE_CAP) { You_feel("%s.", /* track INT change; ignore WIS */ ACURR(A_INT) <= (ABASE(A_INT) + ABON(A_INT) + ATEMP(A_INT)) ? "like sitting in a corner" : "giddy"); } else { /* [message moved to uchangealign()] */ makeknown(HELM_OF_OPPOSITE_ALIGNMENT); } break; default: impossible(unknown_type, c_helmet, uarmh->otyp); } return 0; } int Helmet_off(VOID_ARGS) { context.takeoff.mask &= ~W_ARMH; switch (uarmh->otyp) { case FEDORA: case HELMET: case DENTED_POT: case ELVEN_LEATHER_HELM: case DWARVISH_IRON_HELM: case ORCISH_HELM: break; case DUNCE_CAP: context.botl = 1; break; case CORNUTHAUM: if (!context.takeoff.cancelled_don) { ABON(A_CHA) += (Role_if(PM_WIZARD) ? -1 : 1); context.botl = 1; } break; case HELM_OF_TELEPATHY: /* need to update ability before calling see_monsters() */ setworn((struct obj *) 0, W_ARMH); see_monsters(); return 0; case HELM_OF_BRILLIANCE: if (!context.takeoff.cancelled_don) adj_abon(uarmh, -uarmh->spe); break; case HELM_OF_OPPOSITE_ALIGNMENT: /* changing alignment can toggle off active artifact properties, including levitation; uarmh could get dropped or destroyed here */ uchangealign(u.ualignbase[A_CURRENT], 2); break; default: impossible(unknown_type, c_helmet, uarmh->otyp); } setworn((struct obj *) 0, W_ARMH); context.takeoff.cancelled_don = FALSE; return 0; } STATIC_PTR int Gloves_on(VOID_ARGS) { long oldprop = u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; switch (uarmg->otyp) { case LEATHER_GLOVES: break; case GAUNTLETS_OF_FUMBLING: if (!oldprop && !(HFumbling & ~TIMEOUT)) incr_itimeout(&HFumbling, rnd(20)); break; case GAUNTLETS_OF_POWER: makeknown(uarmg->otyp); context.botl = 1; /* taken care of in attrib.c */ break; case GAUNTLETS_OF_DEXTERITY: adj_abon(uarmg, uarmg->spe); break; default: impossible(unknown_type, c_gloves, uarmg->otyp); } return 0; } STATIC_OVL void wielding_corpse(obj, voluntary) struct obj *obj; boolean voluntary; /* taking gloves off on purpose? */ { char kbuf[BUFSZ]; if (!obj || obj->otyp != CORPSE) return; if (obj != uwep && (obj != uswapwep || !u.twoweap)) return; if (touch_petrifies(&mons[obj->corpsenm]) && !Stone_resistance) { You("now wield %s in your bare %s.", corpse_xname(obj, (const char *) 0, CXN_ARTICLE), makeplural(body_part(HAND))); Sprintf(kbuf, "%s gloves while wielding %s", voluntary ? "removing" : "losing", killer_xname(obj)); instapetrify(kbuf); /* life-saved; can't continue wielding cockatrice corpse though */ remove_worn_item(obj, FALSE); } } int Gloves_off(VOID_ARGS) { long oldprop = u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; boolean on_purpose = !context.mon_moving && !uarmg->in_use; context.takeoff.mask &= ~W_ARMG; switch (uarmg->otyp) { case LEATHER_GLOVES: break; case GAUNTLETS_OF_FUMBLING: if (!oldprop && !(HFumbling & ~TIMEOUT)) HFumbling = EFumbling = 0; break; case GAUNTLETS_OF_POWER: makeknown(uarmg->otyp); context.botl = 1; /* taken care of in attrib.c */ break; case GAUNTLETS_OF_DEXTERITY: if (!context.takeoff.cancelled_don) adj_abon(uarmg, -uarmg->spe); break; default: impossible(unknown_type, c_gloves, uarmg->otyp); } setworn((struct obj *) 0, W_ARMG); context.takeoff.cancelled_don = FALSE; (void) encumber_msg(); /* immediate feedback for GoP */ /* prevent wielding cockatrice when not wearing gloves */ if (uwep && uwep->otyp == CORPSE) wielding_corpse(uwep, on_purpose); /* KMH -- ...or your secondary weapon when you're wielding it [This case can't actually happen; twoweapon mode won't engage if a corpse has been set up as the alternate weapon.] */ if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE) wielding_corpse(uswapwep, on_purpose); return 0; } STATIC_PTR int Shield_on(VOID_ARGS) { /* no shield currently requires special handling when put on, but we keep this uncommented in case somebody adds a new one which does */ switch (uarms->otyp) { case SMALL_SHIELD: case ELVEN_SHIELD: case URUK_HAI_SHIELD: case ORCISH_SHIELD: case DWARVISH_ROUNDSHIELD: case LARGE_SHIELD: case SHIELD_OF_REFLECTION: break; default: impossible(unknown_type, c_shield, uarms->otyp); } return 0; } int Shield_off(VOID_ARGS) { context.takeoff.mask &= ~W_ARMS; /* no shield currently requires special handling when taken off, but we keep this uncommented in case somebody adds a new one which does */ switch (uarms->otyp) { case SMALL_SHIELD: case ELVEN_SHIELD: case URUK_HAI_SHIELD: case ORCISH_SHIELD: case DWARVISH_ROUNDSHIELD: case LARGE_SHIELD: case SHIELD_OF_REFLECTION: break; default: impossible(unknown_type, c_shield, uarms->otyp); } setworn((struct obj *) 0, W_ARMS); return 0; } STATIC_PTR int Shirt_on(VOID_ARGS) { /* no shirt currently requires special handling when put on, but we keep this uncommented in case somebody adds a new one which does */ switch (uarmu->otyp) { case HAWAIIAN_SHIRT: case T_SHIRT: break; default: impossible(unknown_type, c_shirt, uarmu->otyp); } return 0; } int Shirt_off(VOID_ARGS) { context.takeoff.mask &= ~W_ARMU; /* no shirt currently requires special handling when taken off, but we keep this uncommented in case somebody adds a new one which does */ switch (uarmu->otyp) { case HAWAIIAN_SHIRT: case T_SHIRT: break; default: impossible(unknown_type, c_shirt, uarmu->otyp); } setworn((struct obj *) 0, W_ARMU); return 0; } /* This must be done in worn.c, because one of the possible intrinsics * conferred is fire resistance, and we have to immediately set * HFire_resistance in worn.c since worn.c will check it before returning. */ STATIC_PTR int Armor_on(VOID_ARGS) { return 0; } int Armor_off(VOID_ARGS) { context.takeoff.mask &= ~W_ARM; setworn((struct obj *) 0, W_ARM); context.takeoff.cancelled_don = FALSE; return 0; } /* The gone functions differ from the off functions in that if you die from * taking it off and have life saving, you still die. */ int Armor_gone() { context.takeoff.mask &= ~W_ARM; setnotworn(uarm); context.takeoff.cancelled_don = FALSE; return 0; } STATIC_OVL void Amulet_on() { /* make sure amulet isn't wielded; can't use remove_worn_item() here because it has already been set worn in amulet slot */ if (uamul == uwep) setuwep((struct obj *) 0); else if (uamul == uswapwep) setuswapwep((struct obj *) 0); else if (uamul == uquiver) setuqwep((struct obj *) 0); switch (uamul->otyp) { case AMULET_OF_ESP: case AMULET_OF_LIFE_SAVING: case AMULET_VERSUS_POISON: case AMULET_OF_REFLECTION: case AMULET_OF_MAGICAL_BREATHING: case FAKE_AMULET_OF_YENDOR: break; case AMULET_OF_UNCHANGING: if (Slimed) make_slimed(0L, (char *) 0); break; case AMULET_OF_CHANGE: { int orig_sex = poly_gender(); if (Unchanging) break; change_sex(); /* Don't use same message as polymorph */ if (orig_sex != poly_gender()) { makeknown(AMULET_OF_CHANGE); You("are suddenly very %s!", flags.female ? "feminine" : "masculine"); context.botl = 1; } else /* already polymorphed into single-gender monster; only changed the character's base sex */ You("don't feel like yourself."); pline_The("amulet disintegrates!"); if (orig_sex == poly_gender() && uamul->dknown && !objects[AMULET_OF_CHANGE].oc_name_known && !objects[AMULET_OF_CHANGE].oc_uname) docall(uamul); useup(uamul); break; } case AMULET_OF_STRANGULATION: if (can_be_strangled(&youmonst)) { makeknown(AMULET_OF_STRANGULATION); pline("It constricts your throat!"); Strangled = 6L; } break; case AMULET_OF_RESTFUL_SLEEP: { long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT); /* avoid clobbering FROMOUTSIDE bit, which might have gotten set by previously eating one of these amulets */ if (newnap < oldnap || oldnap == 0L) HSleepy = (HSleepy & ~TIMEOUT) | newnap; } break; case AMULET_OF_YENDOR: break; } } void Amulet_off() { context.takeoff.mask &= ~W_AMUL; switch (uamul->otyp) { case AMULET_OF_ESP: /* need to update ability before calling see_monsters() */ setworn((struct obj *) 0, W_AMUL); see_monsters(); return; case AMULET_OF_LIFE_SAVING: case AMULET_VERSUS_POISON: case AMULET_OF_REFLECTION: case AMULET_OF_CHANGE: case AMULET_OF_UNCHANGING: case FAKE_AMULET_OF_YENDOR: break; case AMULET_OF_MAGICAL_BREATHING: if (Underwater) { /* HMagical_breathing must be set off before calling drown() */ setworn((struct obj *) 0, W_AMUL); if (!breathless(youmonst.data) && !amphibious(youmonst.data) && !Swimming) { You("suddenly inhale an unhealthy amount of water!"); (void) drown(); } return; } break; case AMULET_OF_STRANGULATION: if (Strangled) { if (Breathless) Your("%s is no longer constricted!", body_part(NECK)); else You("can breathe more easily!"); Strangled = 0L; } break; case AMULET_OF_RESTFUL_SLEEP: setworn((struct obj *) 0, W_AMUL); /* HSleepy = 0L; -- avoid clobbering FROMOUTSIDE bit */ if (!ESleepy && !(HSleepy & ~TIMEOUT)) HSleepy &= ~TIMEOUT; /* clear timeout bits */ return; case AMULET_OF_YENDOR: break; } setworn((struct obj *) 0, W_AMUL); return; } /* handle ring discovery; comparable to learnwand() */ STATIC_OVL void learnring(ring, observed) struct obj *ring; boolean observed; { int ringtype = ring->otyp; /* if effect was observeable then we usually discover the type */ if (observed) { /* if we already know the ring type which accomplishes this effect (assumes there is at most one type for each effect), mark this ring as having been seen (no need for makeknown); otherwise if we have seen this ring, discover its type */ if (objects[ringtype].oc_name_known) ring->dknown = 1; else if (ring->dknown) makeknown(ringtype); #if 0 /* see learnwand() */ else ring->eknown = 1; #endif } /* make enchantment of charged ring known (might be +0) and update perm invent window if we've seen this ring and know its type */ if (ring->dknown && objects[ringtype].oc_name_known) { if (objects[ringtype].oc_charged) ring->known = 1; update_inventory(); } } void Ring_on(obj) register struct obj *obj; { long oldprop = u.uprops[objects[obj->otyp].oc_oprop].extrinsic; int old_attrib, which; boolean observable; /* make sure ring isn't wielded; can't use remove_worn_item() here because it has already been set worn in a ring slot */ if (obj == uwep) setuwep((struct obj *) 0); else if (obj == uswapwep) setuswapwep((struct obj *) 0); else if (obj == uquiver) setuqwep((struct obj *) 0); /* only mask out W_RING when we don't have both left and right rings of the same type */ if ((oldprop & W_RING) != W_RING) oldprop &= ~W_RING; switch (obj->otyp) { case RIN_TELEPORTATION: case RIN_REGENERATION: case RIN_SEARCHING: case RIN_HUNGER: case RIN_AGGRAVATE_MONSTER: case RIN_POISON_RESISTANCE: case RIN_FIRE_RESISTANCE: case RIN_COLD_RESISTANCE: case RIN_SHOCK_RESISTANCE: case RIN_CONFLICT: case RIN_TELEPORT_CONTROL: case RIN_POLYMORPH: case RIN_POLYMORPH_CONTROL: case RIN_FREE_ACTION: case RIN_SLOW_DIGESTION: case RIN_SUSTAIN_ABILITY: case MEAT_RING: break; case RIN_STEALTH: toggle_stealth(obj, oldprop, TRUE); break; case RIN_WARNING: see_monsters(); break; case RIN_SEE_INVISIBLE: /* can now see invisible monsters */ set_mimic_blocking(); /* do special mimic handling */ see_monsters(); if (Invis && !oldprop && !HSee_invisible && !Blind) { newsym(u.ux, u.uy); pline("Suddenly you are transparent, but there!"); learnring(obj, TRUE); } break; case RIN_INVISIBILITY: if (!oldprop && !HInvis && !BInvis && !Blind) { learnring(obj, TRUE); newsym(u.ux, u.uy); self_invis_message(); } break; case RIN_LEVITATION: if (!oldprop && !HLevitation && !BLevitation) { float_up(); learnring(obj, TRUE); spoteffects(FALSE); /* for sinks */ } else { float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ } break; case RIN_GAIN_STRENGTH: which = A_STR; goto adjust_attrib; case RIN_GAIN_CONSTITUTION: which = A_CON; goto adjust_attrib; case RIN_ADORNMENT: which = A_CHA; adjust_attrib: old_attrib = ACURR(which); ABON(which) += obj->spe; observable = (old_attrib != ACURR(which)); /* if didn't change, usually means ring is +0 but might be because nonzero couldn't go below min or above max; learn +0 enchantment if attribute value is not stuck at a limit [and ring has been seen and its type is already discovered, both handled by learnring()] */ if (observable || !extremeattr(which)) learnring(obj, observable); context.botl = 1; break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc += obj->spe; break; case RIN_INCREASE_DAMAGE: u.udaminc += obj->spe; break; case RIN_PROTECTION_FROM_SHAPE_CHAN: rescham(); break; case RIN_PROTECTION: /* usually learn enchantment and discover type; won't happen if ring is unseen or if it's +0 and the type hasn't been discovered yet */ observable = (obj->spe != 0); learnring(obj, observable); if (obj->spe) find_ac(); /* updates botl */ break; } } STATIC_OVL void Ring_off_or_gone(obj, gone) register struct obj *obj; boolean gone; { long mask = (obj->owornmask & W_RING); int old_attrib, which; boolean observable; context.takeoff.mask &= ~mask; if (!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask)) impossible("Strange... I didn't know you had that ring."); if (gone) setnotworn(obj); else setworn((struct obj *) 0, obj->owornmask); switch (obj->otyp) { case RIN_TELEPORTATION: case RIN_REGENERATION: case RIN_SEARCHING: case RIN_HUNGER: case RIN_AGGRAVATE_MONSTER: case RIN_POISON_RESISTANCE: case RIN_FIRE_RESISTANCE: case RIN_COLD_RESISTANCE: case RIN_SHOCK_RESISTANCE: case RIN_CONFLICT: case RIN_TELEPORT_CONTROL: case RIN_POLYMORPH: case RIN_POLYMORPH_CONTROL: case RIN_FREE_ACTION: case RIN_SLOW_DIGESTION: case RIN_SUSTAIN_ABILITY: case MEAT_RING: break; case RIN_STEALTH: toggle_stealth(obj, (EStealth & ~mask), FALSE); break; case RIN_WARNING: see_monsters(); break; case RIN_SEE_INVISIBLE: /* Make invisible monsters go away */ if (!See_invisible) { set_mimic_blocking(); /* do special mimic handling */ see_monsters(); } if (Invisible && !Blind) { newsym(u.ux, u.uy); pline("Suddenly you cannot see yourself."); learnring(obj, TRUE); } break; case RIN_INVISIBILITY: if (!Invis && !BInvis && !Blind) { newsym(u.ux, u.uy); Your("body seems to unfade%s.", See_invisible ? " completely" : ".."); learnring(obj, TRUE); } break; case RIN_LEVITATION: if (!BLevitation) { (void) float_down(0L, 0L); if (!Levitation) learnring(obj, TRUE); } else { float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ } break; case RIN_GAIN_STRENGTH: which = A_STR; goto adjust_attrib; case RIN_GAIN_CONSTITUTION: which = A_CON; goto adjust_attrib; case RIN_ADORNMENT: which = A_CHA; adjust_attrib: old_attrib = ACURR(which); ABON(which) -= obj->spe; observable = (old_attrib != ACURR(which)); /* same criteria as Ring_on() */ if (observable || !extremeattr(which)) learnring(obj, observable); context.botl = 1; break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc -= obj->spe; break; case RIN_INCREASE_DAMAGE: u.udaminc -= obj->spe; break; case RIN_PROTECTION: /* might have been put on while blind and we can now see or perhaps been forgotten due to amnesia */ observable = (obj->spe != 0); learnring(obj, observable); if (obj->spe) find_ac(); /* updates botl */ break; case RIN_PROTECTION_FROM_SHAPE_CHAN: /* If you're no longer protected, let the chameleons * change shape again -dgk */ restartcham(); break; } } void Ring_off(obj) struct obj *obj; { Ring_off_or_gone(obj, FALSE); } void Ring_gone(obj) struct obj *obj; { Ring_off_or_gone(obj, TRUE); } void Blindf_on(otmp) register struct obj *otmp; { boolean already_blind = Blind, changed = FALSE; /* blindfold might be wielded; release it for wearing */ if (otmp->owornmask & W_WEAPON) remove_worn_item(otmp, FALSE); setworn(otmp, W_TOOL); on_msg(otmp); if (Blind && !already_blind) { changed = TRUE; if (flags.verbose) You_cant("see any more."); /* set ball&chain variables before the hero goes blind */ if (Punished) set_bc(0); } else if (already_blind && !Blind) { changed = TRUE; /* "You are now wearing the Eyes of the Overworld." */ if (u.uroleplay.blind) { /* this can only happen by putting on the Eyes of the Overworld; that shouldn't actually produce a permanent cure, but we can't let the "blind from birth" conduct remain intact */ pline("For the first time in your life, you can see!"); u.uroleplay.blind = FALSE; } else You("can see!"); } if (changed) { /* blindness has just been toggled */ if (Blind_telepat || Infravision) see_monsters(); vision_full_recalc = 1; /* recalc vision limits */ if (!Blind) learn_unseen_invent(); context.botl = 1; } } void Blindf_off(otmp) register struct obj *otmp; { boolean was_blind = Blind, changed = FALSE; if (!otmp) { impossible("Blindf_off without otmp"); return; } context.takeoff.mask &= ~W_TOOL; setworn((struct obj *) 0, otmp->owornmask); off_msg(otmp); if (Blind) { if (was_blind) { /* "still cannot see" makes no sense when removing lenses since they can't have been the cause of your blindness */ if (otmp->otyp != LENSES) You("still cannot see."); } else { changed = TRUE; /* !was_blind */ /* "You were wearing the Eyes of the Overworld." */ You_cant("see anything now!"); /* set ball&chain variables before the hero goes blind */ if (Punished) set_bc(0); } } else if (was_blind) { if (!gulp_blnd_check()) { changed = TRUE; /* !Blind */ You("can see again."); } } if (changed) { /* blindness has just been toggled */ if (Blind_telepat || Infravision) see_monsters(); vision_full_recalc = 1; /* recalc vision limits */ if (!Blind) learn_unseen_invent(); context.botl = 1; } } /* called in moveloop()'s prologue to set side-effects of worn start-up items; also used by poly_obj() when a worn item gets transformed */ void set_wear(obj) struct obj *obj; /* if null, do all worn items; otherwise just obj itself */ { initial_don = !obj; if (!obj ? ublindf != 0 : (obj == ublindf)) (void) Blindf_on(ublindf); if (!obj ? uright != 0 : (obj == uright)) (void) Ring_on(uright); if (!obj ? uleft != 0 : (obj == uleft)) (void) Ring_on(uleft); if (!obj ? uamul != 0 : (obj == uamul)) (void) Amulet_on(); if (!obj ? uarmu != 0 : (obj == uarmu)) (void) Shirt_on(); if (!obj ? uarm != 0 : (obj == uarm)) (void) Armor_on(); if (!obj ? uarmc != 0 : (obj == uarmc)) (void) Cloak_on(); if (!obj ? uarmf != 0 : (obj == uarmf)) (void) Boots_on(); if (!obj ? uarmg != 0 : (obj == uarmg)) (void) Gloves_on(); if (!obj ? uarmh != 0 : (obj == uarmh)) (void) Helmet_on(); if (!obj ? uarms != 0 : (obj == uarms)) (void) Shield_on(); initial_don = FALSE; } /* check whether the target object is currently being put on (or taken off-- also checks for doffing) */ boolean donning(otmp) struct obj *otmp; { /* long what = (occupation == take_off) ? context.takeoff.what : 0L; */ long what = context.takeoff.what; /* if nonzero, occupation is implied */ boolean result = FALSE; /* 'W' and 'T' set afternmv, 'A' sets context.takeoff.what */ if (otmp == uarm) result = (afternmv == Armor_on || afternmv == Armor_off || what == WORN_ARMOR); else if (otmp == uarmu) result = (afternmv == Shirt_on || afternmv == Shirt_off || what == WORN_SHIRT); else if (otmp == uarmc) result = (afternmv == Cloak_on || afternmv == Cloak_off || what == WORN_CLOAK); else if (otmp == uarmf) result = (afternmv == Boots_on || afternmv == Boots_off || what == WORN_BOOTS); else if (otmp == uarmh) result = (afternmv == Helmet_on || afternmv == Helmet_off || what == WORN_HELMET); else if (otmp == uarmg) result = (afternmv == Gloves_on || afternmv == Gloves_off || what == WORN_GLOVES); else if (otmp == uarms) result = (afternmv == Shield_on || afternmv == Shield_off || what == WORN_SHIELD); return result; } /* check whether the target object is currently being taken off, so that stop_donning() and steal() can vary messages */ boolean doffing(otmp) struct obj *otmp; { long what = context.takeoff.what; boolean result = FALSE; /* 'T' (also 'W') sets afternmv, 'A' sets context.takeoff.what */ if (otmp == uarm) result = (afternmv == Armor_off || what == WORN_ARMOR); else if (otmp == uarmu) result = (afternmv == Shirt_off || what == WORN_SHIRT); else if (otmp == uarmc) result = (afternmv == Cloak_off || what == WORN_CLOAK); else if (otmp == uarmf) result = (afternmv == Boots_off || what == WORN_BOOTS); else if (otmp == uarmh) result = (afternmv == Helmet_off || what == WORN_HELMET); else if (otmp == uarmg) result = (afternmv == Gloves_off || what == WORN_GLOVES); else if (otmp == uarms) result = (afternmv == Shield_off || what == WORN_SHIELD); return result; } void cancel_don() { /* the piece of armor we were donning/doffing has vanished, so stop * wasting time on it (and don't dereference it when donning would * otherwise finish) */ context.takeoff.cancelled_don = (afternmv == Boots_on || afternmv == Helmet_on || afternmv == Gloves_on || afternmv == Armor_on); afternmv = 0; nomovemsg = (char *) 0; multi = 0; context.takeoff.delay = 0; context.takeoff.what = 0L; } /* called by steal() during theft from hero; interrupt donning/doffing */ int stop_donning(stolenobj) struct obj *stolenobj; /* no message if stolenobj is already being doffing */ { char buf[BUFSZ]; struct obj *otmp; boolean putting_on; int result = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if ((otmp->owornmask & W_ARMOR) && donning(otmp)) break; /* at most one item will pass donning() test at any given time */ if (!otmp) return 0; /* donning() returns True when doffing too; doffing() is more specific */ putting_on = !doffing(otmp); /* cancel_don() looks at afternmv; it also serves as cancel_doff() */ cancel_don(); /* don't want _on() or _off() being called by unmul() since the on or off action isn't completing */ afternmv = 0; if (putting_on || otmp != stolenobj) { Sprintf(buf, "You stop %s %s.", putting_on ? "putting on" : "taking off", thesimpleoname(otmp)); } else { buf[0] = '\0'; /* silently stop doffing stolenobj */ result = -multi; /* remember this before calling unmul() */ } unmul(buf); /* while putting on, item becomes worn immediately but side-effects are deferred until the delay expires; when interrupted, make it unworn (while taking off, item stays worn until the delay expires; when interrupted, leave it worn) */ if (putting_on) remove_worn_item(otmp, FALSE); return result; } /* both 'clothes' and 'accessories' now include both armor and accessories; TOOL_CLASS is for eyewear, FOOD_CLASS is for MEAT_RING */ static NEARDATA const char clothes[] = { ARMOR_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, 0 }; static NEARDATA const char accessories[] = { RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, ARMOR_CLASS, 0 }; STATIC_VAR NEARDATA int Narmorpieces, Naccessories; /* assign values to Narmorpieces and Naccessories */ STATIC_OVL void count_worn_stuff(which, accessorizing) struct obj **which; /* caller wants this when count is 1 */ boolean accessorizing; { struct obj *otmp; Narmorpieces = Naccessories = 0; #define MOREWORN(x,wtyp) do { if (x) { wtyp++; otmp = x; } } while (0) otmp = 0; MOREWORN(uarmh, Narmorpieces); MOREWORN(uarms, Narmorpieces); MOREWORN(uarmg, Narmorpieces); MOREWORN(uarmf, Narmorpieces); /* for cloak/suit/shirt, we only count the outermost item so that it can be taken off without confirmation if final count ends up as 1 */ if (uarmc) MOREWORN(uarmc, Narmorpieces); else if (uarm) MOREWORN(uarm, Narmorpieces); else if (uarmu) MOREWORN(uarmu, Narmorpieces); if (!accessorizing) *which = otmp; /* default item iff Narmorpieces is 1 */ otmp = 0; MOREWORN(uleft, Naccessories); MOREWORN(uright, Naccessories); MOREWORN(uamul, Naccessories); MOREWORN(ublindf, Naccessories); if (accessorizing) *which = otmp; /* default item iff Naccessories is 1 */ #undef MOREWORN } /* take off one piece or armor or one accessory; shared by dotakeoff('T') and doremring('R') */ STATIC_OVL int armor_or_accessory_off(obj) struct obj *obj; { if (!(obj->owornmask & (W_ARMOR | W_ACCESSORY))) { You("are not wearing that."); return 0; } reset_remarm(); /* clear context.takeoff.mask and context.takeoff.what */ (void) select_off(obj); if (!context.takeoff.mask) return 0; /* none of armoroff()/Ring_/Amulet/Blindf_off() use context.takeoff.mask */ reset_remarm(); if (obj->owornmask & W_ARMOR) { (void) armoroff(obj); } else if (obj == uright || obj == uleft) { /* Sometimes we want to give the off_msg before removing and * sometimes after; for instance, "you were wearing a moonstone * ring (on right hand)" is desired but "you were wearing a * square amulet (being worn)" is not because of the redundant * "being worn". */ off_msg(obj); Ring_off(obj); } else if (obj == uamul) { Amulet_off(); off_msg(obj); } else if (obj == ublindf) { Blindf_off(obj); /* does its own off_msg */ } else { impossible("removing strange accessory?"); if (obj->owornmask) remove_worn_item(obj, FALSE); } return 1; } /* the 'T' command */ int dotakeoff() { struct obj *otmp = (struct obj *) 0; count_worn_stuff(&otmp, FALSE); if (!Narmorpieces && !Naccessories) { /* assert( GRAY_DRAGON_SCALES > YELLOW_DRAGON_SCALE_MAIL ); */ if (uskin) pline_The("%s merged with your skin!", uskin->otyp >= GRAY_DRAGON_SCALES ? "dragon scales are" : "dragon scale mail is"); else pline("Not wearing any armor or accessories."); return 0; } if (Narmorpieces != 1 || ParanoidRemove) otmp = getobj(clothes, "take off"); if (!otmp) return 0; if (otmp == uskin || ((otmp == uarm) && uarmc) || ((otmp == uarmu) && (uarmc || uarm))) { char why[BUFSZ], what[BUFSZ]; why[0] = what[0] = '\0'; if (otmp != uskin) { if (uarmc) Strcat(what, cloak_simple_name(uarmc)); if ((otmp == uarmu) && uarm) { if (uarmc) Strcat(what, " and "); Strcat(what, suit_simple_name(uarm)); } Sprintf(why, " without taking off your %s first", what); } You_cant("take that off%s.", why); return 0; } return armor_or_accessory_off(otmp); } /* the 'R' command */ int doremring() { struct obj *otmp = 0; count_worn_stuff(&otmp, TRUE); if (!Naccessories && !Narmorpieces) { pline("Not wearing any accessories or armor."); return 0; } if (Naccessories != 1 || ParanoidRemove) otmp = getobj(accessories, "remove"); if (!otmp) return 0; return armor_or_accessory_off(otmp); } /* Check if something worn is cursed _and_ unremovable. */ int cursed(otmp) register struct obj *otmp; { /* Curses, like chickens, come home to roost. */ if ((otmp == uwep) ? welded(otmp) : (int) otmp->cursed) { boolean use_plural = (is_boots(otmp) || is_gloves(otmp) || otmp->otyp == LENSES || otmp->quan > 1L); You("can't. %s cursed.", use_plural ? "They are" : "It is"); otmp->bknown = TRUE; return 1; } return 0; } int armoroff(otmp) register struct obj *otmp; { register int delay = -objects[otmp->otyp].oc_delay; if (cursed(otmp)) return 0; if (delay) { nomul(delay); multi_reason = "disrobing"; if (is_helmet(otmp)) { /* ick... */ nomovemsg = !strcmp(helm_simple_name(otmp), "hat") ? "You finish taking off your hat." : "You finish taking off your helmet."; afternmv = Helmet_off; } else if (is_gloves(otmp)) { nomovemsg = "You finish taking off your gloves."; afternmv = Gloves_off; } else if (is_boots(otmp)) { nomovemsg = "You finish taking off your boots."; afternmv = Boots_off; } else { nomovemsg = "You finish taking off your suit."; afternmv = Armor_off; } } else { /* Be warned! We want off_msg after removing the item to * avoid "You were wearing ____ (being worn)." However, an * item which grants fire resistance might cause some trouble * if removed in Hell and lifesaving puts it back on; in this * case the message will be printed at the wrong time (after * the messages saying you died and were lifesaved). Luckily, * no cloak, shield, or fast-removable armor grants fire * resistance, so we can safely do the off_msg afterwards. * Rings do grant fire resistance, but for rings we want the * off_msg before removal anyway so there's no problem. Take * care in adding armors granting fire resistance; this code * might need modification. * 3.2 (actually 3.1 even): that comment is obsolete since * fire resistance is not required for Gehennom so setworn() * doesn't force the resistance granting item to be re-worn * after being lifesaved anymore. */ if (is_cloak(otmp)) (void) Cloak_off(); else if (is_shield(otmp)) (void) Shield_off(); else setworn((struct obj *) 0, otmp->owornmask & W_ARMOR); off_msg(otmp); } context.takeoff.mask = context.takeoff.what = 0L; return 1; } STATIC_OVL void already_wearing(cc) const char *cc; { You("are already wearing %s%c", cc, (cc == c_that_) ? '!' : '.'); } STATIC_OVL void already_wearing2(cc1, cc2) const char *cc1, *cc2; { You_cant("wear %s because you're wearing %s there already.", cc1, cc2); } /* * canwearobj checks to see whether the player can wear a piece of armor * * inputs: otmp (the piece of armor) * noisy (if TRUE give error messages, otherwise be quiet about it) * output: mask (otmp's armor type) */ int canwearobj(otmp, mask, noisy) struct obj *otmp; long *mask; boolean noisy; { int err = 0; const char *which; which = is_cloak(otmp) ? c_cloak : is_shirt(otmp) ? c_shirt : is_suit(otmp) ? c_suit : 0; if (which && cantweararm(youmonst.data) /* same exception for cloaks as used in m_dowear() */ && (which != c_cloak || youmonst.data->msize != MZ_SMALL) && (racial_exception(&youmonst, otmp) < 1)) { if (noisy) pline_The("%s will not fit on your body.", which); return 0; } else if (otmp->owornmask & W_ARMOR) { if (noisy) already_wearing(c_that_); return 0; } if (welded(uwep) && bimanual(uwep) && (is_suit(otmp) || is_shirt(otmp))) { if (noisy) You("cannot do that while holding your %s.", is_sword(uwep) ? c_sword : c_weapon); return 0; } if (is_helmet(otmp)) { if (uarmh) { if (noisy) already_wearing(an(helm_simple_name(uarmh))); err++; } else if (Upolyd && has_horns(youmonst.data) && !is_flimsy(otmp)) { /* (flimsy exception matches polyself handling) */ if (noisy) pline_The("%s won't fit over your horn%s.", helm_simple_name(otmp), plur(num_horns(youmonst.data))); err++; } else *mask = W_ARMH; } else if (is_shield(otmp)) { if (uarms) { if (noisy) already_wearing(an(c_shield)); err++; } else if (uwep && bimanual(uwep)) { if (noisy) You("cannot wear a shield while wielding a two-handed %s.", is_sword(uwep) ? c_sword : (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon); err++; } else if (u.twoweap) { if (noisy) You("cannot wear a shield while wielding two weapons."); err++; } else *mask = W_ARMS; } else if (is_boots(otmp)) { if (uarmf) { if (noisy) already_wearing(c_boots); err++; } else if (Upolyd && slithy(youmonst.data)) { if (noisy) You("have no feet..."); /* not body_part(FOOT) */ err++; } else if (Upolyd && youmonst.data->mlet == S_CENTAUR) { /* break_armor() pushes boots off for centaurs, so don't let dowear() put them back on... */ if (noisy) pline("You have too many hooves to wear %s.", c_boots); /* makeplural(body_part(FOOT)) yields "rear hooves" which sounds odd */ err++; } else if (u.utrap && (u.utraptype == TT_BEARTRAP || u.utraptype == TT_INFLOOR || u.utraptype == TT_LAVA || u.utraptype == TT_BURIEDBALL)) { if (u.utraptype == TT_BEARTRAP) { if (noisy) Your("%s is trapped!", body_part(FOOT)); } else if (u.utraptype == TT_INFLOOR || u.utraptype == TT_LAVA) { if (noisy) Your("%s are stuck in the %s!", makeplural(body_part(FOOT)), surface(u.ux, u.uy)); } else { /*TT_BURIEDBALL*/ if (noisy) Your("%s is attached to the buried ball!", body_part(LEG)); } err++; } else *mask = W_ARMF; } else if (is_gloves(otmp)) { if (uarmg) { if (noisy) already_wearing(c_gloves); err++; } else if (welded(uwep)) { if (noisy) You("cannot wear gloves over your %s.", is_sword(uwep) ? c_sword : c_weapon); err++; } else *mask = W_ARMG; } else if (is_shirt(otmp)) { if (uarm || uarmc || uarmu) { if (uarmu) { if (noisy) already_wearing(an(c_shirt)); } else { if (noisy) You_cant("wear that over your %s.", (uarm && !uarmc) ? c_armor : cloak_simple_name(uarmc)); } err++; } else *mask = W_ARMU; } else if (is_cloak(otmp)) { if (uarmc) { if (noisy) already_wearing(an(cloak_simple_name(uarmc))); err++; } else *mask = W_ARMC; } else if (is_suit(otmp)) { if (uarmc) { if (noisy) You("cannot wear armor over a %s.", cloak_simple_name(uarmc)); err++; } else if (uarm) { if (noisy) already_wearing("some armor"); err++; } else *mask = W_ARM; } else { /* getobj can't do this after setting its allow_all flag; that happens if you have armor for slots that are covered up or extra armor for slots that are filled */ if (noisy) silly_thing("wear", otmp); err++; } /* Unnecessary since now only weapons and special items like pick-axes get * welded to your hand, not armor if (welded(otmp)) { if (!err++) { if (noisy) weldmsg(otmp); } } */ return !err; } STATIC_OVL int accessory_or_armor_on(obj) struct obj *obj; { long mask = 0L; boolean armor, ring, eyewear; if (obj->owornmask & (W_ACCESSORY | W_ARMOR)) { already_wearing(c_that_); return 0; } armor = (obj->oclass == ARMOR_CLASS); ring = (obj->oclass == RING_CLASS || obj->otyp == MEAT_RING); eyewear = (obj->otyp == BLINDFOLD || obj->otyp == TOWEL || obj->otyp == LENSES); /* checks which are performed prior to actually touching the item */ if (armor) { if (!canwearobj(obj, &mask, TRUE)) return 0; if (obj->otyp == HELM_OF_OPPOSITE_ALIGNMENT && qstart_level.dnum == u.uz.dnum) { /* in quest */ if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) You("narrowly avoid losing all chance at your goal."); else /* converted */ You("are suddenly overcome with shame and change your mind."); u.ublessed = 0; /* lose your god's protection */ makeknown(obj->otyp); context.botl = 1; /*for AC after zeroing u.ublessed */ return 1; } } else { /* accessory */ if (ring) { char answer, qbuf[QBUFSZ]; int res = 0; if (nolimbs(youmonst.data)) { You("cannot make the ring stick to your body."); return 0; } if (uleft && uright) { There("are no more %s%s to fill.", humanoid(youmonst.data) ? "ring-" : "", makeplural(body_part(FINGER))); return 0; } if (uleft) { mask = RIGHT_RING; } else if (uright) { mask = LEFT_RING; } else { do { Sprintf(qbuf, "Which %s%s, Right or Left?", humanoid(youmonst.data) ? "ring-" : "", body_part(FINGER)); answer = yn_function(qbuf, "rl", '\0'); switch (answer) { case '\0': return 0; case 'l': case 'L': mask = LEFT_RING; break; case 'r': case 'R': mask = RIGHT_RING; break; } } while (!mask); } if (uarmg && uarmg->cursed) { res = !uarmg->bknown; uarmg->bknown = 1; You("cannot remove your gloves to put on the ring."); return res; /* uses move iff we learned gloves are cursed */ } if (uwep) { res = !uwep->bknown; /* check this before calling welded() */ if ((mask == RIGHT_RING || bimanual(uwep)) && welded(uwep)) { const char *hand = body_part(HAND); /* welded will set bknown */ if (bimanual(uwep)) hand = makeplural(hand); You("cannot free your weapon %s to put on the ring.", hand); return res; /* uses move iff we learned weapon is cursed */ } } } else if (obj->oclass == AMULET_CLASS) { if (uamul) { already_wearing("an amulet"); return 0; } } else if (eyewear) { if (ublindf) { if (ublindf->otyp == TOWEL) Your("%s is already covered by a towel.", body_part(FACE)); else if (ublindf->otyp == BLINDFOLD) { if (obj->otyp == LENSES) already_wearing2("lenses", "a blindfold"); else already_wearing("a blindfold"); } else if (ublindf->otyp == LENSES) { if (obj->otyp == BLINDFOLD) already_wearing2("a blindfold", "some lenses"); else already_wearing("some lenses"); } else { already_wearing(something); /* ??? */ } return 0; } } else { /* neither armor nor accessory */ You_cant("wear that!"); return 0; } } if (!retouch_object(&obj, FALSE)) return 1; /* costs a turn even though it didn't get worn */ if (armor) { int delay; obj->known = 1; /* since AC is shown on the status line */ /* if the armor is wielded, release it for wearing */ if (obj->owornmask & W_WEAPON) remove_worn_item(obj, FALSE); setworn(obj, mask); delay = -objects[obj->otyp].oc_delay; if (delay) { nomul(delay); multi_reason = "dressing up"; if (is_boots(obj)) afternmv = Boots_on; if (is_helmet(obj)) afternmv = Helmet_on; if (is_gloves(obj)) afternmv = Gloves_on; if (obj == uarm) afternmv = Armor_on; nomovemsg = "You finish your dressing maneuver."; } else { if (is_cloak(obj)) (void) Cloak_on(); if (is_shield(obj)) (void) Shield_on(); if (is_shirt(obj)) (void) Shirt_on(); on_msg(obj); } context.takeoff.mask = context.takeoff.what = 0L; } else { /* not armor */ boolean give_feedback = FALSE; /* [releasing wielded accessory handled in Xxx_on()] */ if (ring) { setworn(obj, mask); Ring_on(obj); give_feedback = TRUE; } else if (obj->oclass == AMULET_CLASS) { setworn(obj, W_AMUL); Amulet_on(); /* no feedback here if amulet of change got used up */ give_feedback = (uamul != 0); } else if (eyewear) { /* setworn() handled by Blindf_on() */ Blindf_on(obj); /* message handled by Blindf_on(); leave give_feedback False */ } /* feedback for ring or for amulet other than 'change' */ if (give_feedback && is_worn(obj)) prinv((char *) 0, obj, 0L); } return 1; } /* the 'W' command */ int dowear() { struct obj *otmp; /* cantweararm() checks for suits of armor, not what we want here; verysmall() or nohands() checks for shields, gloves, etc... */ if ((verysmall(youmonst.data) || nohands(youmonst.data))) { pline("Don't even bother."); return 0; } if (uarm && uarmu && uarmc && uarmh && uarms && uarmg && uarmf && uleft && uright && uamul && ublindf) { /* 'W' message doesn't mention accessories */ You("are already wearing a full complement of armor."); return 0; } otmp = getobj(clothes, "wear"); return otmp ? accessory_or_armor_on(otmp) : 0; } /* the 'P' command */ int doputon() { struct obj *otmp; if (uleft && uright && uamul && ublindf && uarm && uarmu && uarmc && uarmh && uarms && uarmg && uarmf) { /* 'P' message doesn't mention armor */ Your("%s%s are full, and you're already wearing an amulet and %s.", humanoid(youmonst.data) ? "ring-" : "", makeplural(body_part(FINGER)), (ublindf->otyp == LENSES) ? "some lenses" : "a blindfold"); return 0; } otmp = getobj(accessories, "put on"); return otmp ? accessory_or_armor_on(otmp) : 0; } /* calculate current armor class */ void find_ac() { int uac = mons[u.umonnum].ac; /* base armor class for current form */ /* armor class from worn gear */ if (uarm) uac -= ARM_BONUS(uarm); if (uarmc) uac -= ARM_BONUS(uarmc); if (uarmh) uac -= ARM_BONUS(uarmh); if (uarmf) uac -= ARM_BONUS(uarmf); if (uarms) uac -= ARM_BONUS(uarms); if (uarmg) uac -= ARM_BONUS(uarmg); if (uarmu) uac -= ARM_BONUS(uarmu); if (uleft && uleft->otyp == RIN_PROTECTION) uac -= uleft->spe; if (uright && uright->otyp == RIN_PROTECTION) uac -= uright->spe; /* armor class from other sources */ if (HProtection & INTRINSIC) uac -= u.ublessed; uac -= u.uspellprot; /* [The magic binary numbers 127 and -128 should be replaced with the * mystic decimal numbers 99 and -99 which require no explanation to * the uninitiated and would cap the width of a status line value at * one less character.] */ if (uac < -128) uac = -128; /* u.uac is an schar */ else if (uac > 127) uac = 127; /* for completeness */ if (uac != u.uac) { u.uac = uac; context.botl = 1; } } void glibr() { register struct obj *otmp; int xfl = 0; boolean leftfall, rightfall, wastwoweap = FALSE; const char *otherwep = 0, *thiswep, *which, *hand; leftfall = (uleft && !uleft->cursed && (!uwep || !welded(uwep) || !bimanual(uwep))); rightfall = (uright && !uright->cursed && (!welded(uwep))); if (!uarmg && (leftfall || rightfall) && !nolimbs(youmonst.data)) { /* changed so cursed rings don't fall off, GAN 10/30/86 */ Your("%s off your %s.", (leftfall && rightfall) ? "rings slip" : "ring slips", (leftfall && rightfall) ? makeplural(body_part(FINGER)) : body_part(FINGER)); xfl++; if (leftfall) { otmp = uleft; Ring_off(uleft); dropx(otmp); } if (rightfall) { otmp = uright; Ring_off(uright); dropx(otmp); } } otmp = uswapwep; if (u.twoweap && otmp) { /* secondary weapon doesn't need nearly as much handling as primary; when in two-weapon mode, we know it's one-handed with something else in the other hand and also that it's a weapon or weptool rather than something unusual, plus we don't need to compare its type with the primary */ otherwep = is_sword(otmp) ? c_sword : weapon_descr(otmp); if (otmp->quan > 1L) otherwep = makeplural(otherwep); hand = body_part(HAND); which = "left "; Your("%s %s%s from your %s%s.", otherwep, xfl ? "also " : "", otense(otmp, "slip"), which, hand); xfl++; wastwoweap = TRUE; setuswapwep((struct obj *) 0); /* clears u.twoweap */ if (canletgo(otmp, "")) dropx(otmp); } otmp = uwep; if (otmp && !welded(otmp)) { long savequan = otmp->quan; /* nice wording if both weapons are the same type */ thiswep = is_sword(otmp) ? c_sword : weapon_descr(otmp); if (otherwep && strcmp(thiswep, makesingular(otherwep))) otherwep = 0; if (otmp->quan > 1L) { /* most class names for unconventional wielded items are ok, but if wielding multiple apples or rations we don't want "your foods slip", so force non-corpse food to be singular; skipping makeplural() isn't enough--we need to fool otense() too */ if (!strcmp(thiswep, "food")) otmp->quan = 1L; else thiswep = makeplural(thiswep); } hand = body_part(HAND); which = ""; if (bimanual(otmp)) hand = makeplural(hand); else if (wastwoweap) which = "right "; /* preceding msg was about left */ pline("%s %s%s %s%s from your %s%s.", !strncmp(thiswep, "corpse", 6) ? "The" : "Your", otherwep ? "other " : "", thiswep, xfl ? "also " : "", otense(otmp, "slip"), which, hand); /* xfl++; */ otmp->quan = savequan; setuwep((struct obj *) 0); if (canletgo(otmp, "")) dropx(otmp); } } struct obj * some_armor(victim) struct monst *victim; { register struct obj *otmph, *otmp; otmph = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC); if (!otmph) otmph = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM); if (!otmph) otmph = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU); otmp = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH); if (otmp && (!otmph || !rn2(4))) otmph = otmp; otmp = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG); if (otmp && (!otmph || !rn2(4))) otmph = otmp; otmp = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF); if (otmp && (!otmph || !rn2(4))) otmph = otmp; otmp = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS); if (otmp && (!otmph || !rn2(4))) otmph = otmp; return otmph; } /* used for praying to check and fix levitation trouble */ struct obj * stuck_ring(ring, otyp) struct obj *ring; int otyp; { if (ring != uleft && ring != uright) { impossible("stuck_ring: neither left nor right?"); return (struct obj *) 0; } if (ring && ring->otyp == otyp) { /* reasons ring can't be removed match those checked by select_off(); limbless case has extra checks because ordinarily it's temporary */ if (nolimbs(youmonst.data) && uamul && uamul->otyp == AMULET_OF_UNCHANGING && uamul->cursed) return uamul; if (welded(uwep) && (ring == uright || bimanual(uwep))) return uwep; if (uarmg && uarmg->cursed) return uarmg; if (ring->cursed) return ring; } /* either no ring or not right type or nothing prevents its removal */ return (struct obj *) 0; } /* also for praying; find worn item that confers "Unchanging" attribute */ struct obj * unchanger() { if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) return uamul; return 0; } STATIC_PTR int select_off(otmp) register struct obj *otmp; { struct obj *why; char buf[BUFSZ]; if (!otmp) return 0; *buf = '\0'; /* lint suppression */ /* special ring checks */ if (otmp == uright || otmp == uleft) { if (nolimbs(youmonst.data)) { pline_The("ring is stuck."); return 0; } why = 0; /* the item which prevents ring removal */ if (welded(uwep) && (otmp == uright || bimanual(uwep))) { Sprintf(buf, "free a weapon %s", body_part(HAND)); why = uwep; } else if (uarmg && uarmg->cursed) { Sprintf(buf, "take off your %s", c_gloves); why = uarmg; } if (why) { You("cannot %s to remove the ring.", buf); why->bknown = TRUE; return 0; } } /* special glove checks */ if (otmp == uarmg) { if (welded(uwep)) { You("are unable to take off your %s while wielding that %s.", c_gloves, is_sword(uwep) ? c_sword : c_weapon); uwep->bknown = TRUE; return 0; } else if (Glib) { You_cant("take off the slippery %s with your slippery %s.", c_gloves, makeplural(body_part(FINGER))); return 0; } } /* special boot checks */ if (otmp == uarmf) { if (u.utrap && u.utraptype == TT_BEARTRAP) { pline_The("bear trap prevents you from pulling your %s out.", body_part(FOOT)); return 0; } else if (u.utrap && u.utraptype == TT_INFLOOR) { You("are stuck in the %s, and cannot pull your %s out.", surface(u.ux, u.uy), makeplural(body_part(FOOT))); return 0; } } /* special suit and shirt checks */ if (otmp == uarm || otmp == uarmu) { why = 0; /* the item which prevents disrobing */ if (uarmc && uarmc->cursed) { Sprintf(buf, "remove your %s", cloak_simple_name(uarmc)); why = uarmc; } else if (otmp == uarmu && uarm && uarm->cursed) { Sprintf(buf, "remove your %s", c_suit); why = uarm; } else if (welded(uwep) && bimanual(uwep)) { Sprintf(buf, "release your %s", is_sword(uwep) ? c_sword : (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon); why = uwep; } if (why) { You("cannot %s to take off %s.", buf, the(xname(otmp))); why->bknown = TRUE; return 0; } } /* basic curse check */ if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) { ; /* some items can be removed even when cursed */ } else { /* otherwise, this is fundamental */ if (cursed(otmp)) return 0; } if (otmp == uarm) context.takeoff.mask |= WORN_ARMOR; else if (otmp == uarmc) context.takeoff.mask |= WORN_CLOAK; else if (otmp == uarmf) context.takeoff.mask |= WORN_BOOTS; else if (otmp == uarmg) context.takeoff.mask |= WORN_GLOVES; else if (otmp == uarmh) context.takeoff.mask |= WORN_HELMET; else if (otmp == uarms) context.takeoff.mask |= WORN_SHIELD; else if (otmp == uarmu) context.takeoff.mask |= WORN_SHIRT; else if (otmp == uleft) context.takeoff.mask |= LEFT_RING; else if (otmp == uright) context.takeoff.mask |= RIGHT_RING; else if (otmp == uamul) context.takeoff.mask |= WORN_AMUL; else if (otmp == ublindf) context.takeoff.mask |= WORN_BLINDF; else if (otmp == uwep) context.takeoff.mask |= W_WEP; else if (otmp == uswapwep) context.takeoff.mask |= W_SWAPWEP; else if (otmp == uquiver) context.takeoff.mask |= W_QUIVER; else impossible("select_off: %s???", doname(otmp)); return 0; } STATIC_OVL struct obj * do_takeoff() { struct obj *otmp = (struct obj *) 0; struct takeoff_info *doff = &context.takeoff; if (doff->what == W_WEP) { if (!cursed(uwep)) { setuwep((struct obj *) 0); You("are empty %s.", body_part(HANDED)); u.twoweap = FALSE; } } else if (doff->what == W_SWAPWEP) { setuswapwep((struct obj *) 0); You("no longer have a second weapon readied."); u.twoweap = FALSE; } else if (doff->what == W_QUIVER) { setuqwep((struct obj *) 0); You("no longer have ammunition readied."); } else if (doff->what == WORN_ARMOR) { otmp = uarm; if (!cursed(otmp)) (void) Armor_off(); } else if (doff->what == WORN_CLOAK) { otmp = uarmc; if (!cursed(otmp)) (void) Cloak_off(); } else if (doff->what == WORN_BOOTS) { otmp = uarmf; if (!cursed(otmp)) (void) Boots_off(); } else if (doff->what == WORN_GLOVES) { otmp = uarmg; if (!cursed(otmp)) (void) Gloves_off(); } else if (doff->what == WORN_HELMET) { otmp = uarmh; if (!cursed(otmp)) (void) Helmet_off(); } else if (doff->what == WORN_SHIELD) { otmp = uarms; if (!cursed(otmp)) (void) Shield_off(); } else if (doff->what == WORN_SHIRT) { otmp = uarmu; if (!cursed(otmp)) (void) Shirt_off(); } else if (doff->what == WORN_AMUL) { otmp = uamul; if (!cursed(otmp)) Amulet_off(); } else if (doff->what == LEFT_RING) { otmp = uleft; if (!cursed(otmp)) Ring_off(uleft); } else if (doff->what == RIGHT_RING) { otmp = uright; if (!cursed(otmp)) Ring_off(uright); } else if (doff->what == WORN_BLINDF) { if (!cursed(ublindf)) Blindf_off(ublindf); } else { impossible("do_takeoff: taking off %lx", doff->what); } return otmp; } /* occupation callback for 'A' */ STATIC_PTR int take_off(VOID_ARGS) { register int i; register struct obj *otmp; struct takeoff_info *doff = &context.takeoff; if (doff->what) { if (doff->delay > 0) { doff->delay--; return 1; /* still busy */ } else { if ((otmp = do_takeoff())) off_msg(otmp); } doff->mask &= ~doff->what; doff->what = 0L; } for (i = 0; takeoff_order[i]; i++) if (doff->mask & takeoff_order[i]) { doff->what = takeoff_order[i]; break; } otmp = (struct obj *) 0; doff->delay = 0; if (doff->what == 0L) { You("finish %s.", doff->disrobing); return 0; } else if (doff->what == W_WEP) { doff->delay = 1; } else if (doff->what == W_SWAPWEP) { doff->delay = 1; } else if (doff->what == W_QUIVER) { doff->delay = 1; } else if (doff->what == WORN_ARMOR) { otmp = uarm; /* If a cloak is being worn, add the time to take it off and put * it back on again. Kludge alert! since that time is 0 for all * known cloaks, add 1 so that it actually matters... */ if (uarmc) doff->delay += 2 * objects[uarmc->otyp].oc_delay + 1; } else if (doff->what == WORN_CLOAK) { otmp = uarmc; } else if (doff->what == WORN_BOOTS) { otmp = uarmf; } else if (doff->what == WORN_GLOVES) { otmp = uarmg; } else if (doff->what == WORN_HELMET) { otmp = uarmh; } else if (doff->what == WORN_SHIELD) { otmp = uarms; } else if (doff->what == WORN_SHIRT) { otmp = uarmu; /* add the time to take off and put back on armor and/or cloak */ if (uarm) doff->delay += 2 * objects[uarm->otyp].oc_delay; if (uarmc) doff->delay += 2 * objects[uarmc->otyp].oc_delay + 1; } else if (doff->what == WORN_AMUL) { doff->delay = 1; } else if (doff->what == LEFT_RING) { doff->delay = 1; } else if (doff->what == RIGHT_RING) { doff->delay = 1; } else if (doff->what == WORN_BLINDF) { doff->delay = 2; } else { impossible("take_off: taking off %lx", doff->what); return 0; /* force done */ } if (otmp) doff->delay += objects[otmp->otyp].oc_delay; /* Since setting the occupation now starts the counter next move, that * would always produce a delay 1 too big per item unless we subtract * 1 here to account for it. */ if (doff->delay > 0) doff->delay--; set_occupation(take_off, doff->disrobing, 0); return 1; /* get busy */ } /* clear saved context to avoid inappropriate resumption of interrupted 'A' */ void reset_remarm() { context.takeoff.what = context.takeoff.mask = 0L; context.takeoff.disrobing[0] = '\0'; } /* the 'A' command -- remove multiple worn items */ int doddoremarm() { int result = 0; if (context.takeoff.what || context.takeoff.mask) { You("continue %s.", context.takeoff.disrobing); set_occupation(take_off, context.takeoff.disrobing, 0); return 0; } else if (!uwep && !uswapwep && !uquiver && !uamul && !ublindf && !uleft && !uright && !wearing_armor()) { You("are not wearing anything."); return 0; } add_valid_menu_class(0); /* reset */ if (flags.menu_style != MENU_TRADITIONAL || (result = ggetobj("take off", select_off, 0, FALSE, (unsigned *) 0)) < -1) result = menu_remarm(result); if (context.takeoff.mask) { /* default activity for armor and/or accessories, possibly combined with weapons */ (void) strncpy(context.takeoff.disrobing, "disrobing", CONTEXTVERBSZ); /* specific activity when handling weapons only */ if (!(context.takeoff.mask & ~W_WEAPON)) (void) strncpy(context.takeoff.disrobing, "disarming", CONTEXTVERBSZ); (void) take_off(); } /* The time to perform the command is already completely accounted for * in take_off(); if we return 1, that would add an extra turn to each * disrobe. */ return 0; } STATIC_OVL int menu_remarm(retry) int retry; { int n, i = 0; menu_item *pick_list; boolean all_worn_categories = TRUE; if (retry) { all_worn_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { all_worn_categories = FALSE; n = query_category("What type of things do you want to take off?", invent, WORN_TYPES | ALL_TYPES, &pick_list, PICK_ANY); if (!n) return 0; for (i = 0; i < n; i++) { if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_worn_categories = TRUE; else add_valid_menu_class(pick_list[i].item.a_int); } free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { all_worn_categories = FALSE; if (ggetobj("take off", select_off, 0, TRUE, (unsigned *) 0) == -2) all_worn_categories = TRUE; } n = query_objlist("What do you want to take off?", invent, SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT, &pick_list, PICK_ANY, all_worn_categories ? is_worn : is_worn_by_type); if (n > 0) { for (i = 0; i < n; i++) (void) select_off(pick_list[i].item.a_obj); free((genericptr_t) pick_list); } else if (n < 0 && flags.menu_style != MENU_COMBINATION) { There("is nothing else you can remove or unwield."); } return 0; } /* hit by destroy armor scroll/black dragon breath/monster spell */ int destroy_arm(atmp) register struct obj *atmp; { register struct obj *otmp; #define DESTROY_ARM(o) \ ((otmp = (o)) != 0 && (!atmp || atmp == otmp) \ && (!obj_resists(otmp, 0, 90)) \ ? (otmp->in_use = TRUE) \ : FALSE) if (DESTROY_ARM(uarmc)) { if (donning(otmp)) cancel_don(); Your("%s crumbles and turns to dust!", cloak_simple_name(uarmc)); (void) Cloak_off(); useup(otmp); } else if (DESTROY_ARM(uarm)) { if (donning(otmp)) cancel_don(); Your("armor turns to dust and falls to the %s!", surface(u.ux, u.uy)); (void) Armor_gone(); useup(otmp); } else if (DESTROY_ARM(uarmu)) { if (donning(otmp)) cancel_don(); Your("shirt crumbles into tiny threads and falls apart!"); (void) Shirt_off(); useup(otmp); } else if (DESTROY_ARM(uarmh)) { if (donning(otmp)) cancel_don(); Your("%s turns to dust and is blown away!", helm_simple_name(uarmh)); (void) Helmet_off(); useup(otmp); } else if (DESTROY_ARM(uarmg)) { if (donning(otmp)) cancel_don(); Your("gloves vanish!"); (void) Gloves_off(); useup(otmp); selftouch("You"); } else if (DESTROY_ARM(uarmf)) { if (donning(otmp)) cancel_don(); Your("boots disintegrate!"); (void) Boots_off(); useup(otmp); } else if (DESTROY_ARM(uarms)) { if (donning(otmp)) cancel_don(); Your("shield crumbles away!"); (void) Shield_off(); useup(otmp); } else { return 0; /* could not destroy anything */ } #undef DESTROY_ARM stop_occupation(); return 1; } void adj_abon(otmp, delta) register struct obj *otmp; register schar delta; { if (uarmg && uarmg == otmp && otmp->otyp == GAUNTLETS_OF_DEXTERITY) { if (delta) { makeknown(uarmg->otyp); ABON(A_DEX) += (delta); } context.botl = 1; } if (uarmh && uarmh == otmp && otmp->otyp == HELM_OF_BRILLIANCE) { if (delta) { makeknown(uarmh->otyp); ABON(A_INT) += (delta); ABON(A_WIS) += (delta); } context.botl = 1; } } /* decide whether a worn item is covered up by some other worn item, used for dipping into liquid and applying grease; some criteria are different than select_off()'s */ boolean inaccessible_equipment(obj, verb, only_if_known_cursed) struct obj *obj; const char *verb; /* "dip" or "grease", or null to avoid messages */ boolean only_if_known_cursed; /* ignore covering unless known to be cursed */ { static NEARDATA const char need_to_take_off_outer_armor[] = "need to take off %s to %s %s."; char buf[BUFSZ]; boolean anycovering = !only_if_known_cursed; /* more comprehensible... */ #define BLOCKSACCESS(x) (anycovering || ((x)->cursed && (x)->bknown)) if (!obj || !obj->owornmask) return FALSE; /* not inaccessible */ /* check for suit covered by cloak */ if (obj == uarm && uarmc && BLOCKSACCESS(uarmc)) { if (verb) { Strcpy(buf, yname(uarmc)); You(need_to_take_off_outer_armor, buf, verb, yname(obj)); } return TRUE; } /* check for shirt covered by suit and/or cloak */ if (obj == uarmu && ((uarm && BLOCKSACCESS(uarm)) || (uarmc && BLOCKSACCESS(uarmc)))) { if (verb) { char cloaktmp[QBUFSZ], suittmp[QBUFSZ]; /* if sameprefix, use yname and xname to get "your cloak and suit" or "Manlobbi's cloak and suit"; otherwise, use yname and yname to get "your cloak and Manlobbi's suit" or vice versa */ boolean sameprefix = (uarm && uarmc && !strcmp(shk_your(cloaktmp, uarmc), shk_your(suittmp, uarm))); *buf = '\0'; if (uarmc) Strcat(buf, yname(uarmc)); if (uarm && uarmc) Strcat(buf, " and "); if (uarm) Strcat(buf, sameprefix ? xname(uarm) : yname(uarm)); You(need_to_take_off_outer_armor, buf, verb, yname(obj)); } return TRUE; } /* check for ring covered by gloves */ if ((obj == uleft || obj == uright) && uarmg && BLOCKSACCESS(uarmg)) { if (verb) { Strcpy(buf, yname(uarmg)); You(need_to_take_off_outer_armor, buf, verb, yname(obj)); } return TRUE; } /* item is not inaccessible */ return FALSE; } /*do_wear.c*/ nethack-3.6.0/src/dog.c0000664000076400007660000010662512617413107013655 0ustar paxedpaxed/* NetHack 3.6 dog.c $NHDT-Date: 1446808440 2015/11/06 11:14:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.52 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL int NDECL(pet_type); void newedog(mtmp) struct monst *mtmp; { if (!mtmp->mextra) mtmp->mextra = newmextra(); if (!EDOG(mtmp)) { EDOG(mtmp) = (struct edog *) alloc(sizeof(struct edog)); (void) memset((genericptr_t) EDOG(mtmp), 0, sizeof(struct edog)); } } void free_edog(mtmp) struct monst *mtmp; { if (mtmp->mextra && EDOG(mtmp)) { free((genericptr_t) EDOG(mtmp)); EDOG(mtmp) = (struct edog *) 0; } mtmp->mtame = 0; } void initedog(mtmp) register struct monst *mtmp; { mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5; mtmp->mpeaceful = 1; mtmp->mavenge = 0; set_malign(mtmp); /* recalc alignment now that it's tamed */ mtmp->mleashed = 0; mtmp->meating = 0; EDOG(mtmp)->droptime = 0; EDOG(mtmp)->dropdist = 10000; EDOG(mtmp)->apport = 10; EDOG(mtmp)->whistletime = 0; EDOG(mtmp)->hungrytime = 1000 + monstermoves; EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ EDOG(mtmp)->ogoal.y = -1; EDOG(mtmp)->abuse = 0; EDOG(mtmp)->revivals = 0; EDOG(mtmp)->mhpmax_penalty = 0; EDOG(mtmp)->killed_by_u = 0; } STATIC_OVL int pet_type() { if (urole.petnum != NON_PM) return urole.petnum; else if (preferred_pet == 'c') return PM_KITTEN; else if (preferred_pet == 'd') return PM_LITTLE_DOG; else return rn2(2) ? PM_KITTEN : PM_LITTLE_DOG; } struct monst * make_familiar(otmp, x, y, quietly) register struct obj *otmp; xchar x, y; boolean quietly; { struct permonst *pm; struct monst *mtmp = 0; int chance, trycnt = 100; do { if (otmp) { /* figurine; otherwise spell */ int mndx = otmp->corpsenm; pm = &mons[mndx]; /* activating a figurine provides one way to exceed the maximum number of the target critter created--unless it has a special limit (erinys, Nazgul) */ if ((mvitals[mndx].mvflags & G_EXTINCT) && mbirth_limit(mndx) != MAXMONNO) { if (!quietly) /* have just been given "You the figurine and it transforms." message */ pline("... into a pile of dust."); break; /* mtmp is null */ } } else if (!rn2(3)) { pm = &mons[pet_type()]; } else { pm = rndmonst(); if (!pm) { if (!quietly) There("seems to be nothing available for a familiar."); break; } } mtmp = makemon(pm, x, y, MM_EDOG | MM_IGNOREWATER | NO_MINVENT); if (otmp && !mtmp) { /* monster was genocided or square occupied */ if (!quietly) pline_The("figurine writhes and then shatters into pieces!"); break; } } while (!mtmp && --trycnt > 0); if (!mtmp) return (struct monst *) 0; if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp)) return (struct monst *) 0; initedog(mtmp); mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ chance = rn2(10); /* 0==tame, 1==peaceful, 2==hostile */ if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2; /* 0,1,2: b=80%,10,10; nc=10%,80,10; c=10%,10,80 */ if (chance > 0) { mtmp->mtame = 0; /* not tame after all */ if (chance == 2) { /* hostile (cursed figurine) */ if (!quietly) You("get a bad feeling about this."); mtmp->mpeaceful = 0; set_malign(mtmp); } } /* if figurine has been named, give same name to the monster */ if (has_oname(otmp)) mtmp = christen_monst(mtmp, ONAME(otmp)); } set_malign(mtmp); /* more alignment changes */ newsym(mtmp->mx, mtmp->my); /* must wield weapon immediately since pets will otherwise drop it */ if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) { mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); } return mtmp; } struct monst * makedog() { register struct monst *mtmp; register struct obj *otmp; const char *petname; int pettype; static int petname_used = 0; if (preferred_pet == 'n') return ((struct monst *) 0); pettype = pet_type(); if (pettype == PM_LITTLE_DOG) petname = dogname; else if (pettype == PM_PONY) petname = horsename; else petname = catname; /* default pet names */ if (!*petname && pettype == PM_LITTLE_DOG) { /* All of these names were for dogs. */ if (Role_if(PM_CAVEMAN)) petname = "Slasher"; /* The Warrior */ if (Role_if(PM_SAMURAI)) petname = "Hachi"; /* Shibuya Station */ if (Role_if(PM_BARBARIAN)) petname = "Idefix"; /* Obelix */ if (Role_if(PM_RANGER)) petname = "Sirius"; /* Orion's dog */ } mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG); if (!mtmp) return ((struct monst *) 0); /* pets were genocided */ context.startingpet_mid = mtmp->m_id; /* Horses already wear a saddle */ if (pettype == PM_PONY && !!(otmp = mksobj(SADDLE, TRUE, FALSE))) { if (mpickobj(mtmp, otmp)) panic("merged saddle?"); mtmp->misc_worn_check |= W_SADDLE; otmp->dknown = otmp->bknown = otmp->rknown = 1; otmp->owornmask = W_SADDLE; otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, TRUE); } if (!petname_used++ && *petname) mtmp = christen_monst(mtmp, petname); initedog(mtmp); return mtmp; } /* record `last move time' for all monsters prior to level save so that mon_arrive() can catch up for lost time when they're restored later */ void update_mlstmv() { struct monst *mon; /* monst->mlstmv used to be updated every time `monst' actually moved, but that is no longer the case so we just do a blanket assignment */ for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; mon->mlstmv = monstermoves; } } void losedogs() { register struct monst *mtmp, *mtmp0 = 0, *mtmp2; int dismissKops = 0; /* * First, scan migrating_mons for shopkeepers who want to dismiss Kops, * and scan mydogs for shopkeepers who want to retain kops. * Second, dismiss kops if warranted, making more room for arrival. * Third, place monsters accompanying the hero. * Last, place migrating monsters coming to this level. * * Hero might eventually be displaced (due to the third step, but * occurring later), which is the main reason to do the second step * sooner (in turn necessitating the first step, rather than combining * the list scans with monster placement). */ /* check for returning shk(s) */ for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { if (mtmp->mux != u.uz.dnum || mtmp->muy != u.uz.dlevel) continue; if (mtmp->isshk) { if (ESHK(mtmp)->dismiss_kops) { if (dismissKops == 0) dismissKops = 1; ESHK(mtmp)->dismiss_kops = FALSE; /* reset */ } else if (!mtmp->mpeaceful) { /* an unpacified shk is returning; don't dismiss kops even if another pacified one is willing to do so */ dismissKops = -1; /* [keep looping; later monsters might need ESHK reset] */ } } } /* make the same check for mydogs */ for (mtmp = mydogs; mtmp && dismissKops >= 0; mtmp = mtmp->nmon) { if (mtmp->isshk) { /* hostile shk might accompany hero [ESHK(mtmp)->dismiss_kops can't be set here; it's only used for migrating_mons] */ if (!mtmp->mpeaceful) dismissKops = -1; } } /* when a hostile shopkeeper chases hero to another level and then gets paid off there, get rid of summoned kops here now that he has returned to his shop level */ if (dismissKops > 0) make_happy_shoppers(TRUE); /* place pets and/or any other monsters who accompany hero */ while ((mtmp = mydogs) != 0) { mydogs = mtmp->nmon; mon_arrive(mtmp, TRUE); } /* time for migrating monsters to arrive */ for (mtmp = migrating_mons; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) { if (mtmp == migrating_mons) migrating_mons = mtmp->nmon; else mtmp0->nmon = mtmp->nmon; mon_arrive(mtmp, FALSE); } else mtmp0 = mtmp; } } /* called from resurrect() in addition to losedogs() */ void mon_arrive(mtmp, with_you) struct monst *mtmp; boolean with_you; { struct trap *t; xchar xlocale, ylocale, xyloc, xyflags, wander; int num_segs; mtmp->nmon = fmon; fmon = mtmp; if (mtmp->isshk) set_residency(mtmp, FALSE); num_segs = mtmp->wormno; /* baby long worms have no tail so don't use is_longworm() */ if (mtmp->data == &mons[PM_LONG_WORM]) { mtmp->wormno = get_wormno(); if (mtmp->wormno) initworm(mtmp, num_segs); } else mtmp->wormno = 0; /* some monsters might need to do something special upon arrival _after_ the current level has been fully set up; see dochug() */ mtmp->mstrategy |= STRAT_ARRIVE; /* make sure mnexto(rloc_to(set_apparxy())) doesn't use stale data */ mtmp->mux = u.ux, mtmp->muy = u.uy; xyloc = mtmp->mtrack[0].x; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; mtmp->mtrack[0].x = mtmp->mtrack[0].y = 0; mtmp->mtrack[1].x = mtmp->mtrack[1].y = 0; if (mtmp == u.usteed) return; /* don't place steed on the map */ if (with_you) { /* When a monster accompanies you, sometimes it will arrive at your intended destination and you'll end up next to that spot. This code doesn't control the final outcome; goto_level(do.c) decides who ends up at your target spot when there is a monster there too. */ if (!MON_AT(u.ux, u.uy) && !rn2(mtmp->mtame ? 10 : mtmp->mpeaceful ? 5 : 2)) rloc_to(mtmp, u.ux, u.uy); else mnexto(mtmp); return; } /* * The monster arrived on this level independently of the player. * Its coordinate fields were overloaded for use as flags that * specify its final destination. */ if (mtmp->mlstmv < monstermoves - 1L) { /* heal monster for time spent in limbo */ long nmv = monstermoves - 1L - mtmp->mlstmv; mon_catchup_elapsed_time(mtmp, nmv); mtmp->mlstmv = monstermoves - 1L; /* let monster move a bit on new level (see placement code below) */ wander = (xchar) min(nmv, 8); } else wander = 0; switch (xyloc) { case MIGR_APPROX_XY: /* {x,y}locale set above */ break; case MIGR_EXACT_XY: wander = 0; break; case MIGR_WITH_HERO: xlocale = u.ux, ylocale = u.uy; break; case MIGR_STAIRS_UP: xlocale = xupstair, ylocale = yupstair; break; case MIGR_STAIRS_DOWN: xlocale = xdnstair, ylocale = ydnstair; break; case MIGR_LADDER_UP: xlocale = xupladder, ylocale = yupladder; break; case MIGR_LADDER_DOWN: xlocale = xdnladder, ylocale = ydnladder; break; case MIGR_SSTAIRS: xlocale = sstairs.sx, ylocale = sstairs.sy; break; case MIGR_PORTAL: if (In_endgame(&u.uz)) { /* there is no arrival portal for endgame levels */ /* BUG[?]: for simplicity, this code relies on the fact that we know that the current endgame levels always build upwards and never have any exclusion subregion inside their TELEPORT_REGION settings. */ xlocale = rn1(updest.hx - updest.lx + 1, updest.lx); ylocale = rn1(updest.hy - updest.ly + 1, updest.ly); break; } /* find the arrival portal */ for (t = ftrap; t; t = t->ntrap) if (t->ttyp == MAGIC_PORTAL) break; if (t) { xlocale = t->tx, ylocale = t->ty; break; } else { impossible("mon_arrive: no corresponding portal?"); } /*FALLTHRU*/ default: case MIGR_RANDOM: xlocale = ylocale = 0; break; } if (xlocale && wander) { /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ char *r = in_rooms(xlocale, ylocale, 0); if (r && *r) { coord c; /* somexy() handles irregular rooms */ if (somexy(&rooms[*r - ROOMOFFSET], &c)) xlocale = c.x, ylocale = c.y; else xlocale = ylocale = 0; } else { /* not in a room */ int i, j; i = max(1, xlocale - wander); j = min(COLNO - 1, xlocale + wander); xlocale = rn1(j - i, i); i = max(0, ylocale - wander); j = min(ROWNO - 1, ylocale + wander); ylocale = rn1(j - i, i); } } /* moved a bit */ mtmp->mx = 0; /*(already is 0)*/ mtmp->my = xyflags; if (xlocale) (void) mnearto(mtmp, xlocale, ylocale, FALSE); else { if (!rloc(mtmp, TRUE)) { /* * Failed to place migrating monster, * probably because the level is full. * Dump the monster's cargo and leave the monster dead. */ struct obj *obj; while ((obj = mtmp->minvent) != 0) { obj_extract_self(obj); obj_no_longer_held(obj); if (obj->owornmask & W_WEP) setmnotwielded(mtmp, obj); obj->owornmask = 0L; if (xlocale && ylocale) place_object(obj, xlocale, ylocale); else if (rloco(obj)) { if (!get_obj_location(obj, &xlocale, &ylocale, 0)) impossible("Can't find relocated object."); } } (void) mkcorpstat(CORPSE, (struct monst *) 0, mtmp->data, xlocale, ylocale, CORPSTAT_NONE); mongone(mtmp); } } } /* heal monster for time spent elsewhere */ void mon_catchup_elapsed_time(mtmp, nmv) struct monst *mtmp; long nmv; /* number of moves */ { int imv = 0; /* avoid zillions of casts and lint warnings */ #if defined(DEBUG) || defined(BETA) if (nmv < 0L) { /* crash likely... */ panic("catchup from future time?"); /*NOTREACHED*/ return; } else if (nmv == 0L) { /* safe, but should'nt happen */ impossible("catchup from now?"); } else #endif if (nmv >= LARGEST_INT) /* paranoia */ imv = LARGEST_INT - 1; else imv = (int) nmv; /* might stop being afraid, blind or frozen */ /* set to 1 and allow final decrement in movemon() */ if (mtmp->mblinded) { if (imv >= (int) mtmp->mblinded) mtmp->mblinded = 1; else mtmp->mblinded -= imv; } if (mtmp->mfrozen) { if (imv >= (int) mtmp->mfrozen) mtmp->mfrozen = 1; else mtmp->mfrozen -= imv; } if (mtmp->mfleetim) { if (imv >= (int) mtmp->mfleetim) mtmp->mfleetim = 1; else mtmp->mfleetim -= imv; } /* might recover from temporary trouble */ if (mtmp->mtrapped && rn2(imv + 1) > 40 / 2) mtmp->mtrapped = 0; if (mtmp->mconf && rn2(imv + 1) > 50 / 2) mtmp->mconf = 0; if (mtmp->mstun && rn2(imv + 1) > 10 / 2) mtmp->mstun = 0; /* might finish eating or be able to use special ability again */ if (imv > mtmp->meating) finish_meating(mtmp); else mtmp->meating -= imv; if (imv > mtmp->mspec_used) mtmp->mspec_used = 0; else mtmp->mspec_used -= imv; /* reduce tameness for every 150 moves you are separated */ if (mtmp->mtame) { int wilder = (imv + 75) / 150; if (mtmp->mtame > wilder) mtmp->mtame -= wilder; /* less tame */ else if (mtmp->mtame > rn2(wilder)) mtmp->mtame = 0; /* untame */ else mtmp->mtame = mtmp->mpeaceful = 0; /* hostile! */ } /* check to see if it would have died as a pet; if so, go wild instead * of dying the next time we call dog_move() */ if (mtmp->mtame && !mtmp->isminion && (carnivorous(mtmp->data) || herbivorous(mtmp->data))) { struct edog *edog = EDOG(mtmp); if ((monstermoves > edog->hungrytime + 500 && mtmp->mhp < 3) || (monstermoves > edog->hungrytime + 750)) mtmp->mtame = mtmp->mpeaceful = 0; } if (!mtmp->mtame && mtmp->mleashed) { /* leashed monsters should always be with hero, consequently never losing any time to be accounted for later */ impossible("catching up for leashed monster?"); m_unleash(mtmp, FALSE); } /* recover lost hit points */ if (!regenerates(mtmp->data)) imv /= 20; if (mtmp->mhp + imv >= mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; else mtmp->mhp += imv; } /* called when you move to another level */ void keepdogs(pets_only) boolean pets_only; /* true for ascension or final escape */ { register struct monst *mtmp, *mtmp2; register struct obj *obj; int num_segs; boolean stay_behind; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (pets_only) { if (!mtmp->mtame) continue; /* reject non-pets */ /* don't block pets from accompanying hero's dungeon escape or ascension simply due to mundane trifles; unlike level change for steed, don't bother trying to achieve a normal trap escape first */ mtmp->mtrapped = 0; mtmp->meating = 0; mtmp->msleeping = 0; mtmp->mfrozen = 0; mtmp->mcanmove = 1; } if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) /* the wiz will level t-port from anywhere to chase the amulet; if you don't have it, will chase you only if in range. -3. */ || (u.uhave.amulet && mtmp->iswiz)) && ((!mtmp->msleeping && mtmp->mcanmove) /* eg if level teleport or new trap, steed has no control to avoid following */ || (mtmp == u.usteed)) /* monster won't follow if it hasn't noticed you yet */ && !(mtmp->mstrategy & STRAT_WAITFORU)) { stay_behind = FALSE; if (mtmp->mtrapped) (void) mintrap(mtmp); /* try to escape */ if (mtmp == u.usteed) { /* make sure steed is eligible to accompany hero */ mtmp->mtrapped = 0; /* escape trap */ mtmp->meating = 0; /* terminate eating */ mdrop_special_objs(mtmp); /* drop Amulet */ } else if (mtmp->meating || mtmp->mtrapped) { if (canseemon(mtmp)) pline("%s is still %s.", Monnam(mtmp), mtmp->meating ? "eating" : "trapped"); stay_behind = TRUE; } else if (mon_has_amulet(mtmp)) { if (canseemon(mtmp)) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); stay_behind = TRUE; } if (stay_behind) { if (mtmp->mleashed) { pline("%s leash suddenly comes loose.", humanoid(mtmp->data) ? (mtmp->female ? "Her" : "His") : "Its"); m_unleash(mtmp, FALSE); } if (mtmp == u.usteed) { /* can't happen unless someone makes a change which scrambles the stay_behind logic above */ impossible("steed left behind?"); dismount_steed(DISMOUNT_GENERIC); } continue; } if (mtmp->isshk) set_residency(mtmp, TRUE); if (mtmp->wormno) { register int cnt; /* NOTE: worm is truncated to # segs = max wormno size */ cnt = count_wsegs(mtmp); num_segs = min(cnt, MAX_NUM_WORMS - 1); wormgone(mtmp); } else num_segs = 0; /* set minvent's obj->no_charge to 0 */ for (obj = mtmp->minvent; obj; obj = obj->nobj) { if (Has_contents(obj)) picked_container(obj); /* does the right thing */ obj->no_charge = 0; } relmon(mtmp, &mydogs); /* move it from map to mydogs */ mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */ mtmp->wormno = num_segs; mtmp->mlstmv = monstermoves; } else if (mtmp->iswiz) { /* we want to be able to find him when his next resurrection chance comes up, but have him resume his present location if player returns to this level before that time */ migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_EXACT_XY, (coord *) 0); } else if (mtmp->mleashed) { /* this can happen if your quest leader ejects you from the "home" level while a leashed pet isn't next to you */ pline("%s leash goes slack.", s_suffix(Monnam(mtmp))); m_unleash(mtmp, FALSE); } } } void migrate_to_level(mtmp, tolev, xyloc, cc) register struct monst *mtmp; xchar tolev; /* destination level */ xchar xyloc; /* MIGR_xxx destination xy location: */ coord *cc; /* optional destination coordinates */ { register struct obj *obj; d_level new_lev; xchar xyflags; int num_segs = 0; /* count of worm segments */ if (mtmp->isshk) set_residency(mtmp, TRUE); if (mtmp->wormno) { register int cnt; /* **** NOTE: worm is truncated to # segs = max wormno size **** */ cnt = count_wsegs(mtmp); num_segs = min(cnt, MAX_NUM_WORMS - 1); wormgone(mtmp); } /* set minvent's obj->no_charge to 0 */ for (obj = mtmp->minvent; obj; obj = obj->nobj) { if (Has_contents(obj)) picked_container(obj); /* does the right thing */ obj->no_charge = 0; } if (mtmp->mleashed) { mtmp->mtame--; m_unleash(mtmp, TRUE); } relmon(mtmp, &migrating_mons); /* move it from map to migrating_mons */ new_lev.dnum = ledger_to_dnum((xchar) tolev); new_lev.dlevel = ledger_to_dlev((xchar) tolev); /* overload mtmp->[mx,my], mtmp->[mux,muy], and mtmp->mtrack[] as */ /* destination codes (setup flag bits before altering mx or my) */ xyflags = (depth(&new_lev) < depth(&u.uz)); /* 1 => up */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz)) xyflags |= 2; mtmp->wormno = num_segs; mtmp->mlstmv = monstermoves; mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx; mtmp->mtrack[1].y = cc ? cc->y : mtmp->my; mtmp->mtrack[0].x = xyloc; mtmp->mtrack[0].y = xyflags; mtmp->mux = new_lev.dnum; mtmp->muy = new_lev.dlevel; mtmp->mx = mtmp->my = 0; /* this implies migration */ if (mtmp == context.polearm.hitmon) context.polearm.hitmon = NULL; } /* return quality of food; the lower the better */ /* fungi will eat even tainted food */ int dogfood(mon, obj) struct monst *mon; register struct obj *obj; { struct permonst *mptr = mon->data, *fptr = 0; boolean carni = carnivorous(mptr), herbi = herbivorous(mptr), starving; if (is_quest_artifact(obj) || obj_resists(obj, 0, 95)) return obj->cursed ? TABU : APPORT; switch (obj->oclass) { case FOOD_CLASS: if (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG) fptr = &mons[obj->corpsenm]; if (obj->otyp == CORPSE && is_rider(fptr)) return TABU; if ((obj->otyp == CORPSE || obj->otyp == EGG) && touch_petrifies(fptr) && !resists_ston(mon)) return POISON; if (!carni && !herbi) return obj->cursed ? UNDEF : APPORT; /* a starving pet will eat almost anything */ starving = (mon->mtame && !mon->isminion && EDOG(mon)->mhpmax_penalty); /* ghouls prefer old corpses and unhatchable eggs, yum! they'll eat fresh non-veggy corpses and hatchable eggs when starving; they never eat stone-to-flesh'd meat */ if (mptr == &mons[PM_GHOUL]) { if (obj->otyp == CORPSE) return (peek_at_iced_corpse_age(obj) + 50L <= monstermoves && fptr != &mons[PM_LIZARD] && fptr != &mons[PM_LICHEN]) ? DOGFOOD : (starving && !vegan(fptr)) ? ACCFOOD : POISON; if (obj->otyp == EGG) return stale_egg(obj) ? CADAVER : starving ? ACCFOOD : POISON; return TABU; } switch (obj->otyp) { case TRIPE_RATION: case MEATBALL: case MEAT_RING: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: return carni ? DOGFOOD : MANFOOD; case EGG: return carni ? CADAVER : MANFOOD; case CORPSE: if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves && obj->corpsenm != PM_LIZARD && obj->corpsenm != PM_LICHEN && mptr->mlet != S_FUNGUS) || (acidic(fptr) && !resists_acid(mon)) || (poisonous(fptr) && !resists_poison(mon))) return POISON; /* turning into slime is preferable to starvation */ else if (fptr == &mons[PM_GREEN_SLIME] && !slimeproof(mon->data)) return starving ? ACCFOOD : POISON; else if (vegan(fptr)) return herbi ? CADAVER : MANFOOD; /* most humanoids will avoid cannibalism unless starving; arbitrary: elves won't eat other elves even then */ else if (humanoid(mptr) && same_race(mptr, fptr) && (!is_undead(mptr) && fptr->mlet != S_KOBOLD && fptr->mlet != S_ORC && fptr->mlet != S_OGRE)) return (starving && carni && !is_elf(mptr)) ? ACCFOOD : TABU; else return carni ? CADAVER : MANFOOD; case CLOVE_OF_GARLIC: return (is_undead(mptr) || is_vampshifter(mon)) ? TABU : (herbi || starving) ? ACCFOOD : MANFOOD; case TIN: return metallivorous(mptr) ? ACCFOOD : MANFOOD; case APPLE: case CARROT: return herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD; case BANANA: return (mptr->mlet == S_YETI) ? DOGFOOD : (herbi || starving) ? ACCFOOD : MANFOOD; default: if (starving) return ACCFOOD; return (obj->otyp > SLIME_MOLD) ? (carni ? ACCFOOD : MANFOOD) : (herbi ? ACCFOOD : MANFOOD); } default: if (obj->otyp == AMULET_OF_STRANGULATION || obj->otyp == RIN_SLOW_DIGESTION) return TABU; if (mon_hates_silver(mon) && objects[obj->otyp].oc_material == SILVER) return TABU; if (mptr == &mons[PM_GELATINOUS_CUBE] && is_organic(obj)) return ACCFOOD; if (metallivorous(mptr) && is_metallic(obj) && (is_rustprone(obj) || mptr != &mons[PM_RUST_MONSTER])) { /* Non-rustproofed ferrous based metals are preferred. */ return (is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD : ACCFOOD; } if (!obj->cursed && obj->oclass != BALL_CLASS && obj->oclass != CHAIN_CLASS) return APPORT; /*FALLTHRU*/ case ROCK_CLASS: return UNDEF; } } /* * With the separate mextra structure added in 3.6.x this always * operates on the original mtmp. It now returns TRUE if the taming * succeeded. */ boolean tamedog(mtmp, obj) register struct monst *mtmp; register struct obj *obj; { /* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */ if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA] || (mtmp->data->mflags3 & M3_WANTSARTI)) return FALSE; /* worst case, at least it'll be peaceful. */ mtmp->mpeaceful = 1; set_malign(mtmp); if (flags.moonphase == FULL_MOON && night() && rn2(6) && obj && mtmp->data->mlet == S_DOG) return FALSE; /* If we cannot tame it, at least it's no longer afraid. */ mtmp->mflee = 0; mtmp->mfleetim = 0; /* make grabber let go now, whether it becomes tame or not */ if (mtmp == u.ustuck) { if (u.uswallow) expels(mtmp, mtmp->data, TRUE); else if (!(Upolyd && sticks(youmonst.data))) unstuck(mtmp); } /* feeding it treats makes it tamer */ if (mtmp->mtame && obj) { int tasty; if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating && ((tasty = dogfood(mtmp, obj)) == DOGFOOD || (tasty <= ACCFOOD && EDOG(mtmp)->hungrytime <= monstermoves))) { /* pet will "catch" and eat this thrown food */ if (canseemon(mtmp)) { boolean big_corpse = (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM && mons[obj->corpsenm].msize > mtmp->data->msize); pline("%s catches %s%s", Monnam(mtmp), the(xname(obj)), !big_corpse ? "." : ", or vice versa!"); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s.", Tobjnam(obj, "stop")); /* dog_eat expects a floor object */ place_object(obj, mtmp->mx, mtmp->my); (void) dog_eat(mtmp, obj, mtmp->mx, mtmp->my, FALSE); /* eating might have killed it, but that doesn't matter here; a non-null result suppresses "miss" message for thrown food and also implies that the object has been deleted */ return TRUE; } else return FALSE; } if (mtmp->mtame || !mtmp->mcanmove /* monsters with conflicting structures cannot be tamed */ || mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion || is_covetous(mtmp->data) || is_human(mtmp->data) || (is_demon(mtmp->data) && !is_demon(youmonst.data)) || (obj && dogfood(mtmp, obj) >= MANFOOD)) return FALSE; if (mtmp->m_id == quest_status.leader_m_id) return FALSE; /* add the pet extension */ newedog(mtmp); initedog(mtmp); if (obj) { /* thrown food */ /* defer eating until the edog extension has been set up */ place_object(obj, mtmp->mx, mtmp->my); /* put on floor */ /* devour the food (might grow into larger, genocided monster) */ if (dog_eat(mtmp, obj, mtmp->mx, mtmp->my, TRUE) == 2) return TRUE; /* oops, it died... */ /* `obj' is now obsolete */ } newsym(mtmp->mx, mtmp->my); if (attacktype(mtmp->data, AT_WEAP)) { mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); } return TRUE; } /* * Called during pet revival or pet life-saving. * If you killed the pet, it revives wild. * If you abused the pet a lot while alive, it revives wild. * If you abused the pet at all while alive, it revives untame. * If the pet wasn't abused and was very tame, it might revive tame. */ void wary_dog(mtmp, was_dead) struct monst *mtmp; boolean was_dead; { struct edog *edog; boolean quietly = was_dead; finish_meating(mtmp); if (!mtmp->mtame) return; edog = !mtmp->isminion ? EDOG(mtmp) : 0; /* if monster was starving when it died, undo that now */ if (edog && edog->mhpmax_penalty) { mtmp->mhpmax += edog->mhpmax_penalty; mtmp->mhp += edog->mhpmax_penalty; /* heal it */ edog->mhpmax_penalty = 0; } if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) { mtmp->mpeaceful = mtmp->mtame = 0; if (edog->abuse >= 0 && edog->abuse < 10) if (!rn2(edog->abuse + 1)) mtmp->mpeaceful = 1; if (!quietly && cansee(mtmp->mx, mtmp->my)) { if (haseyes(youmonst.data)) { if (haseyes(mtmp->data)) pline("%s %s to look you in the %s.", Monnam(mtmp), mtmp->mpeaceful ? "seems unable" : "refuses", body_part(EYE)); else pline("%s avoids your gaze.", Monnam(mtmp)); } } } else { /* chance it goes wild anyway - Pet Sematary */ mtmp->mtame = rn2(mtmp->mtame + 1); if (!mtmp->mtame) mtmp->mpeaceful = rn2(2); } if (!mtmp->mtame) { if (!quietly && canspotmon(mtmp)) pline("%s %s.", Monnam(mtmp), mtmp->mpeaceful ? "is no longer tame" : "has become feral"); newsym(mtmp->mx, mtmp->my); /* a life-saved monster might be leashed; don't leave it that way if it's no longer tame */ if (mtmp->mleashed) m_unleash(mtmp, TRUE); if (mtmp == u.usteed) dismount_steed(DISMOUNT_THROWN); } else if (edog) { /* it's still a pet; start a clean pet-slate now */ edog->revivals++; edog->killed_by_u = 0; edog->abuse = 0; edog->ogoal.x = edog->ogoal.y = -1; if (was_dead || edog->hungrytime < monstermoves + 500L) edog->hungrytime = monstermoves + 500L; if (was_dead) { edog->droptime = 0L; edog->dropdist = 10000; edog->whistletime = 0L; edog->apport = 5; } /* else lifesaved, so retain current values */ } } void abuse_dog(mtmp) struct monst *mtmp; { if (!mtmp->mtame) return; if (Aggravate_monster || Conflict) mtmp->mtame /= 2; else mtmp->mtame--; if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->abuse++; if (!mtmp->mtame && mtmp->mleashed) m_unleash(mtmp, TRUE); /* don't make a sound if pet is in the middle of leaving the level */ /* newsym isn't necessary in this case either */ if (mtmp->mx != 0) { if (mtmp->mtame && rn2(mtmp->mtame)) yelp(mtmp); else growl(mtmp); /* give them a moment's worry */ if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); } } /*dog.c*/ nethack-3.6.0/src/dogmove.c0000664000076400007660000011377512616314177014556 0ustar paxedpaxed/* NetHack 3.6 dogmove.c $NHDT-Date: 1446604109 2015/11/04 02:28:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.56 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" extern boolean notonhead; STATIC_DCL boolean FDECL(dog_hunger, (struct monst *, struct edog *)); STATIC_DCL int FDECL(dog_invent, (struct monst *, struct edog *, int)); STATIC_DCL int FDECL(dog_goal, (struct monst *, struct edog *, int, int, int)); STATIC_DCL boolean FDECL(can_reach_location, (struct monst *, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); STATIC_DCL boolean FDECL(could_reach_item, (struct monst *, XCHAR_P, XCHAR_P)); STATIC_DCL void FDECL(quickmimic, (struct monst *)); /* pick a carried item for pet to drop */ struct obj * droppables(mon) struct monst *mon; { struct obj *obj, *wep, dummy, *pickaxe, *unihorn, *key; dummy = zeroobj; dummy.otyp = GOLD_PIECE; /* not STRANGE_OBJECT or tools of interest */ dummy.oartifact = 1; /* so real artifact won't override "don't keep it" */ pickaxe = unihorn = key = (struct obj *) 0; wep = MON_WEP(mon); if (is_animal(mon->data) || mindless(mon->data)) { /* won't hang on to any objects of these types */ pickaxe = unihorn = key = &dummy; /* act as if already have them */ } else { /* don't hang on to pick-axe if can't use one or don't need one */ if (!tunnels(mon->data) || !needspick(mon->data)) pickaxe = &dummy; /* don't hang on to key if can't open doors */ if (nohands(mon->data) || verysmall(mon->data)) key = &dummy; } if (wep) { if (is_pick(wep)) pickaxe = wep; if (wep->otyp == UNICORN_HORN) unihorn = wep; /* don't need any wielded check for keys... */ } for (obj = mon->minvent; obj; obj = obj->nobj) { switch (obj->otyp) { case DWARVISH_MATTOCK: /* reject mattock if couldn't wield it */ if (which_armor(mon, W_ARMS)) break; /* keep mattock in preference to pick unless pick is already wielded or is an artifact and mattock isn't */ if (pickaxe && pickaxe->otyp == PICK_AXE && pickaxe != wep && (!pickaxe->oartifact || obj->oartifact)) return pickaxe; /* drop the one we earlier decided to keep */ /*FALLTHRU*/ case PICK_AXE: if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) { if (pickaxe) return pickaxe; pickaxe = obj; /* keep this digging tool */ continue; } break; case UNICORN_HORN: /* reject cursed unicorn horns */ if (obj->cursed) break; /* keep artifact unihorn in preference to ordinary one */ if (!unihorn || (obj->oartifact && !unihorn->oartifact)) { if (unihorn) return unihorn; unihorn = obj; /* keep this unicorn horn */ continue; } break; case SKELETON_KEY: /* keep key in preference to lock-pick */ if (key && key->otyp == LOCK_PICK && (!key->oartifact || obj->oartifact)) return key; /* drop the one we earlier decided to keep */ /*FALLTHRU*/ case LOCK_PICK: /* keep lock-pick in preference to credit card */ if (key && key->otyp == CREDIT_CARD && (!key->oartifact || obj->oartifact)) return key; /*FALLTHRU*/ case CREDIT_CARD: if (!key || (obj->oartifact && !key->oartifact)) { if (key) return key; key = obj; /* keep this unlocking tool */ continue; } break; default: break; } if (!obj->owornmask && obj != wep) return obj; } return (struct obj *) 0; /* don't drop anything */ } static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */ STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t)); boolean cursed_object_at(x, y) int x, y; { struct obj *otmp; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->cursed) return TRUE; return FALSE; } int dog_nutrition(mtmp, obj) struct monst *mtmp; struct obj *obj; { int nutrit; /* * It is arbitrary that the pet takes the same length of time to eat * as a human, but gets more nutritional value. */ if (obj->oclass == FOOD_CLASS) { if (obj->otyp == CORPSE) { mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6); nutrit = mons[obj->corpsenm].cnutrit; } else { mtmp->meating = objects[obj->otyp].oc_delay; nutrit = objects[obj->otyp].oc_nutrition; } switch (mtmp->data->msize) { case MZ_TINY: nutrit *= 8; break; case MZ_SMALL: nutrit *= 6; break; default: case MZ_MEDIUM: nutrit *= 5; break; case MZ_LARGE: nutrit *= 4; break; case MZ_HUGE: nutrit *= 3; break; case MZ_GIGANTIC: nutrit *= 2; break; } if (obj->oeaten) { mtmp->meating = eaten_stat(mtmp->meating, obj); nutrit = eaten_stat(nutrit, obj); } } else if (obj->oclass == COIN_CLASS) { mtmp->meating = (int) (obj->quan / 2000) + 1; if (mtmp->meating < 0) mtmp->meating = 1; nutrit = (int) (obj->quan / 20); if (nutrit < 0) nutrit = 0; } else { /* Unusual pet such as gelatinous cube eating odd stuff. * meating made consistent with wild monsters in mon.c. * nutrit made consistent with polymorphed player nutrit in * eat.c. (This also applies to pets eating gold.) */ mtmp->meating = obj->owt / 20 + 1; nutrit = 5 * objects[obj->otyp].oc_nutrition; } return nutrit; } /* returns 2 if pet dies, otherwise 1 */ int dog_eat(mtmp, obj, x, y, devour) register struct monst *mtmp; register struct obj *obj; /* if unpaid, then thrown or kicked by hero */ int x, y; /* dog's starting location, might be different from current */ boolean devour; { register struct edog *edog = EDOG(mtmp); boolean poly, grow, heal, slimer, deadmimic; int nutrit; long oprice; char objnambuf[BUFSZ]; objnambuf[0] = '\0'; if (edog->hungrytime < monstermoves) edog->hungrytime = monstermoves; nutrit = dog_nutrition(mtmp, obj); deadmimic = (obj->otyp == CORPSE && (obj->corpsenm == PM_SMALL_MIMIC || obj->corpsenm == PM_LARGE_MIMIC || obj->corpsenm == PM_GIANT_MIMIC)); slimer = (obj->otyp == CORPSE && obj->corpsenm == PM_GREEN_SLIME); poly = polyfodder(obj); grow = mlevelgain(obj); heal = mhealup(obj); if (devour) { if (mtmp->meating > 1) mtmp->meating /= 2; if (nutrit > 1) nutrit = (nutrit * 3) / 4; } edog->hungrytime += nutrit; mtmp->mconf = 0; if (edog->mhpmax_penalty) { /* no longer starving */ mtmp->mhpmax += edog->mhpmax_penalty; edog->mhpmax_penalty = 0; } if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2; if (mtmp->mtame < 20) mtmp->mtame++; if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */ newsym(x, y); newsym(mtmp->mx, mtmp->my); } /* food items are eaten one at a time; entire stack for other stuff */ if (obj->quan > 1L && obj->oclass == FOOD_CLASS) obj = splitobj(obj, 1L); if (obj->unpaid) iflags.suppress_price++; if (is_pool(x, y) && !Underwater) { /* Don't print obj */ /* TODO: Reveal presence of sea monster (especially sharks) */ } else { /* food is at monster's current location, ; was monster's location at start of this turn; they might be the same but will be different when the monster is moving+eating on same turn */ boolean seeobj = cansee(mtmp->mx, mtmp->my), sawpet = cansee(x, y) && mon_visible(mtmp); /* Observe the action if either the food location or the pet itself is in view. When pet which was in view moves to an unseen spot to eat the food there, avoid referring to that pet as "it". However, we want "it" if invisible/unsensed pet eats visible food. */ if (sawpet || (seeobj && canspotmon(mtmp))) { if (tunnels(mtmp->data)) pline("%s digs in.", noit_Monnam(mtmp)); else pline("%s %s %s.", noit_Monnam(mtmp), devour ? "devours" : "eats", distant_name(obj, doname)); } else if (seeobj) pline("It %s %s.", devour ? "devours" : "eats", distant_name(obj, doname)); } if (obj->unpaid) { Strcpy(objnambuf, xname(obj)); iflags.suppress_price--; } /* It's a reward if it's DOGFOOD and the player dropped/threw it. */ /* We know the player had it if invlet is set -dlc */ if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet) #ifdef LINT edog->apport = 0; #else edog->apport += (int) (200L / ((long) edog->dropdist + monstermoves - edog->droptime)); #endif if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) { /* The object's rustproofing is gone now */ if (obj->unpaid) costly_alteration(obj, COST_DEGRD); obj->oerodeproof = 0; mtmp->mstun = 1; if (canseemon(mtmp) && flags.verbose) { pline("%s spits %s out in disgust!", Monnam(mtmp), distant_name(obj, doname)); } } else if (obj == uball) { unpunish(); delobj(obj); /* we assume this can't be unpaid */ } else if (obj == uchain) { unpunish(); } else { if (obj->unpaid) { /* edible item owned by shop has been thrown or kicked by hero and caught by tame or food-tameable monst */ oprice = unpaid_cost(obj, TRUE); pline("That %s will cost you %ld %s.", objnambuf, oprice, currency(oprice)); /* delobj->obfree will handle actual shop billing update */ } delobj(obj); } #if 0 /* pet is eating, so slime recovery is not feasible... */ /* turning into slime might be cureable */ if (slimer && munslime(mtmp, FALSE)) { /* but the cure (fire directed at self) might be fatal */ if (mtmp->mhp < 1) return 2; slimer = FALSE; /* sliming is avoided, skip polymorph */ } #endif if (poly || slimer) { struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0; (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my)); } /* limit "instant" growth to prevent potential abuse */ if (grow && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15) { if (!grow_up(mtmp, (struct monst *) 0)) return 2; } if (heal) mtmp->mhp = mtmp->mhpmax; if (deadmimic) quickmimic(mtmp); return 1; } /* hunger effects -- returns TRUE on starvation */ STATIC_OVL boolean dog_hunger(mtmp, edog) register struct monst *mtmp; register struct edog *edog; { if (monstermoves > edog->hungrytime + 500) { if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { edog->hungrytime = monstermoves + 500; /* but not too high; it might polymorph */ } else if (!edog->mhpmax_penalty) { /* starving pets are limited in healing */ int newmhpmax = mtmp->mhpmax / 3; mtmp->mconf = 1; edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax; mtmp->mhpmax = newmhpmax; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; if (mtmp->mhp < 1) goto dog_died; if (cansee(mtmp->mx, mtmp->my)) pline("%s is confused from hunger.", Monnam(mtmp)); else if (couldsee(mtmp->mx, mtmp->my)) beg(mtmp); else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { dog_died: if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) pline("%s starves.", Monnam(mtmp)); else You_feel("%s for a moment.", Hallucination ? "bummed" : "sad"); mondied(mtmp); return TRUE; } } return FALSE; } /* do something with object (drop, pick up, eat) at current position * returns 1 if object eaten (since that counts as dog's move), 2 if died */ STATIC_OVL int dog_invent(mtmp, edog, udist) register struct monst *mtmp; register struct edog *edog; int udist; { register int omx, omy, carryamt = 0; struct obj *obj, *otmp; if (mtmp->msleeping || !mtmp->mcanmove) return 0; omx = mtmp->mx; omy = mtmp->my; /* if we are carrying something then we drop it (perhaps near @) */ /* Note: if apport == 1 then our behaviour is independent of udist */ /* Use udist+1 so steed won't cause divide by zero */ if (droppables(mtmp)) { if (!rn2(udist + 1) || !rn2(edog->apport)) if (rn2(10) < edog->apport) { relobj(mtmp, (int) mtmp->minvis, TRUE); if (edog->apport > 1) edog->apport--; edog->dropdist = udist; /* hpscdi!jon */ edog->droptime = monstermoves; } } else { if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass) #ifdef MAIL && obj->otyp != SCR_MAIL #endif ) { int edible = dogfood(mtmp, obj); if ((edible <= CADAVER /* starving pet is more aggressive about eating */ || (edog->mhpmax_penalty && edible == ACCFOOD)) && could_reach_item(mtmp, obj->ox, obj->oy)) return dog_eat(mtmp, obj, omx, omy, FALSE); carryamt = can_carry(mtmp, obj); if (carryamt > 0 && !obj->cursed && could_reach_item(mtmp, obj->ox, obj->oy)) { if (rn2(20) < edog->apport + 3) { if (rn2(udist) || !rn2(edog->apport)) { otmp = obj; if (carryamt != obj->quan) otmp = splitobj(obj, carryamt); if (cansee(omx, omy) && flags.verbose) pline("%s picks up %s.", Monnam(mtmp), distant_name(otmp, doname)); obj_extract_self(otmp); newsym(omx, omy); (void) mpickobj(mtmp, otmp); if (attacktype(mtmp->data, AT_WEAP) && mtmp->weapon_check == NEED_WEAPON) { mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); } m_dowear(mtmp, FALSE); } } } } } return 0; } /* set dog's goal -- gtyp, gx, gy returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */ STATIC_OVL int dog_goal(mtmp, edog, after, udist, whappr) register struct monst *mtmp; struct edog *edog; int after, udist, whappr; { register int omx, omy; boolean in_masters_sight, dog_has_minvent; register struct obj *obj; xchar otyp; int appr; /* Steeds don't move on their own will */ if (mtmp == u.usteed) return -2; omx = mtmp->mx; omy = mtmp->my; in_masters_sight = couldsee(omx, omy); dog_has_minvent = (droppables(mtmp) != 0); if (!edog || mtmp->mleashed) { /* he's not going anywhere... */ gtyp = APPORT; gx = u.ux; gy = u.uy; } else { #define DDIST(x, y) (dist2(x, y, omx, omy)) #define SQSRCHRADIUS 5 int min_x, max_x, min_y, max_y; register int nx, ny; gtyp = UNDEF; /* no goal as yet */ gx = gy = 0; /* suppress 'used before set' message */ if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1; if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; /* nearby food is the first choice, then other objects */ for (obj = fobj; obj; obj = obj->nobj) { nx = obj->ox; ny = obj->oy; if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { otyp = dogfood(mtmp, obj); /* skip inferior goals */ if (otyp > gtyp || otyp == UNDEF) continue; /* avoid cursed items unless starving */ if (cursed_object_at(nx, ny) && !(edog->mhpmax_penalty && otyp < MANFOOD)) continue; /* skip completely unreachable goals */ if (!could_reach_item(mtmp, nx, ny) || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny)) continue; if (otyp < MANFOOD) { if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) { gx = nx; gy = ny; gtyp = otyp; } } else if (gtyp == UNDEF && in_masters_sight && !dog_has_minvent && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) && (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) && edog->apport > rn2(8) && can_carry(mtmp, obj) > 0) { gx = nx; gy = ny; gtyp = APPORT; } } } } /* follow player if appropriate */ if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) { gx = u.ux; gy = u.uy; if (after && udist <= 4 && gx == u.ux && gy == u.uy) return -2; appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; if (udist > 1) { if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr || (dog_has_minvent && rn2(edog->apport))) appr = 1; } /* if you have dog food it'll follow you more closely */ if (appr == 0) { obj = invent; while (obj) { if (dogfood(mtmp, obj) == DOGFOOD) { appr = 1; break; } obj = obj->nobj; } } } else appr = 1; /* gtyp != UNDEF */ if (mtmp->mconf) appr = 0; #define FARAWAY (COLNO + 2) /* position outside screen */ if (gx == u.ux && gy == u.uy && !in_masters_sight) { register coord *cp; cp = gettrack(omx, omy); if (cp) { gx = cp->x; gy = cp->y; if (edog) edog->ogoal.x = 0; } else { /* assume master hasn't moved far, and reuse previous goal */ if (edog && edog->ogoal.x && ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) { gx = edog->ogoal.x; gy = edog->ogoal.y; edog->ogoal.x = 0; } else { int fardist = FARAWAY * FARAWAY; gx = gy = FARAWAY; /* random */ do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist); /* here gx == FARAWAY e.g. when dog is in a vault */ if (gx == FARAWAY || (gx == omx && gy == omy)) { gx = u.ux; gy = u.uy; } else if (edog) { edog->ogoal.x = gx; edog->ogoal.y = gy; } } } } else if (edog) { edog->ogoal.x = 0; } return appr; } /* return 0 (no move), 1 (move) or 2 (dead) */ int dog_move(mtmp, after) register struct monst *mtmp; register int after; /* this is extra fast monster movement */ { int omx, omy; /* original mtmp position */ int appr, whappr, udist; int i, j, k; register struct edog *edog = EDOG(mtmp); struct obj *obj = (struct obj *) 0; xchar otyp; boolean has_edog, cursemsg[9], do_eat = FALSE; boolean better_with_displacing = FALSE; xchar nix, niy; /* position mtmp is (considering) moving to */ register int nx, ny; /* temporary coordinates */ xchar cnt, uncursedcnt, chcnt; int chi = -1, nidist, ndist; coord poss[9]; long info[9], allowflags; #define GDIST(x, y) (dist2(x, y, gx, gy)) /* * Tame Angels have isminion set and an ispriest structure instead of * an edog structure. Fortunately, guardian Angels need not worry * about mundane things like eating and fetching objects, and can * spend all their energy defending the player. (They are the only * monsters with other structures that can be tame.) */ has_edog = !mtmp->isminion; omx = mtmp->mx; omy = mtmp->my; if (has_edog && dog_hunger(mtmp, edog)) return 2; /* starved */ udist = distu(omx, omy); /* Let steeds eat and maybe throw rider during Conflict */ if (mtmp == u.usteed) { if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { dismount_steed(DISMOUNT_THROWN); return 1; } udist = 1; } else if (!udist) /* maybe we tamed him while being swallowed --jgm */ return 0; nix = omx; /* set before newdogpos */ niy = omy; cursemsg[0] = FALSE; /* lint suppression */ info[0] = 0; /* ditto */ if (has_edog) { j = dog_invent(mtmp, edog, udist); if (j == 2) return 2; /* died */ else if (j == 1) goto newdogpos; /* eating something */ whappr = (monstermoves - edog->whistletime < 5); } else whappr = 0; appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist, whappr); if (appr == -2) return 0; allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS; if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (is_displacer(mtmp->data)) allowflags |= ALLOW_MDISP; if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { allowflags |= ALLOW_U; if (!has_edog) { /* Guardian angel refuses to be conflicted; rather, * it disappears, angrily, and sends in some nasties */ lose_guardian_angel(mtmp); return 2; /* current monster is gone */ } } #if 0 /* [this is now handled in dochug()] */ if (!Conflict && !mtmp->mconf && mtmp == u.ustuck && !sticks(youmonst.data)) { unstuck(mtmp); /* swallowed case handled above */ You("get released!"); } #endif if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (monhaskey(mtmp, TRUE)) allowflags |= UNLOCKDOOR; /* note: the Wizard and Riders can unlock doors without a key; they won't use that ability if someone manages to tame them */ } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; if (tunnels(mtmp->data) && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */ allowflags |= ALLOW_DIG; cnt = mfndpos(mtmp, poss, info, allowflags); /* Normally dogs don't step on cursed items, but if they have no * other choice they will. This requires checking ahead of time * to see how many uncursed item squares are around. */ uncursedcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP)) continue; if (cursed_object_at(nx, ny)) continue; uncursedcnt++; } better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy); chcnt = 0; chi = -1; nidist = GDIST(nix, niy); for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; cursemsg[i] = FALSE; /* if leashed, we drag him along. */ if (mtmp->mleashed && distu(nx, ny) > 4) continue; /* if a guardian, try to stay close by choice */ if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist) continue; if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { int mstatus; register struct monst *mtmp2 = m_at(nx, ny); if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee && (perceives(mtmp->data) || !mtmp2->minvis)) || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10)) || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) || ((mtmp->mhp * 4 < mtmp->mhpmax || mtmp2->data->msound == MS_GUARDIAN || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful && !Conflict) || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp))) continue; if (after) return 0; /* hit only once each move */ notonhead = 0; mstatus = mattackm(mtmp, mtmp2); /* aggressor (pet) died */ if (mstatus & MM_AGR_DIED) return 2; if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4) && mtmp2->mlstmv != monstermoves && !onscary(mtmp->mx, mtmp->my, mtmp2) /* monnear check needed: long worms hit on tail */ && monnear(mtmp2, mtmp->mx, mtmp->my)) { mstatus = mattackm(mtmp2, mtmp); /* return attack */ if (mstatus & MM_DEF_DIED) return 2; } return 0; } if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny) && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) { int mstatus; register struct monst *mtmp2 = m_at(nx, ny); mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */ if (mstatus & MM_DEF_DIED) return 2; return 0; } { /* Dog avoids harmful traps, but perhaps it has to pass one * in order to follow player. (Non-harmful traps do not * have ALLOW_TRAPS in info[].) The dog only avoids the * trap if you've seen it, unlike enemies who avoid traps * if they've seen some trap of that type sometime in the * past. (Neither behavior is really realistic.) */ struct trap *trap; if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) { if (mtmp->mleashed) { if (!Deaf) whimper(mtmp); } else /* 1/40 chance of stepping on it anyway, in case * it has to pass one to follow the player... */ if (trap->tseen && rn2(40)) continue; } } /* dog eschews cursed objects, but likes dog food */ /* (minion isn't interested; `cursemsg' stays FALSE) */ if (has_edog) for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { if (obj->cursed) cursemsg[i] = TRUE; else if ((otyp = dogfood(mtmp, obj)) < MANFOOD && (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) { /* Note: our dog likes the food so much that he * might eat it even when it conceals a cursed object */ nix = nx; niy = ny; chi = i; do_eat = TRUE; cursemsg[i] = FALSE; /* not reluctant */ goto newdogpos; } } /* didn't find something to eat; if we saw a cursed item and aren't being forced to walk on it, usually keep looking */ if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 && rn2(13 * uncursedcnt)) continue; /* lessen the chance of backtracking to previous position(s) */ k = has_edog ? uncursedcnt : cnt; for (j = 0; j < MTSZ && j < k - 1; j++) if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) if (rn2(MTSZ * (k - j))) goto nxti; j = ((ndist = GDIST(nx, ny)) - nidist) * appr; if ((j == 0 && !rn2(++chcnt)) || j < 0 || (j > 0 && !whappr && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) { nix = nx; niy = ny; nidist = ndist; if (j < 0) chcnt = 0; chi = i; } nxti: ; } newdogpos: if (nix != omx || niy != omy) { struct obj *mw_tmp; boolean wasseen; if (info[chi] & ALLOW_U) { if (mtmp->mleashed) { /* play it safe */ pline("%s breaks loose of %s leash!", Monnam(mtmp), mhis(mtmp)); m_unleash(mtmp, FALSE); } (void) mattacku(mtmp); return 0; } if (!m_in_out_region(mtmp, nix, niy)) return 1; if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy)) || closed_door(nix, niy)) && mtmp->weapon_check != NO_WEAPON_WANTED && tunnels(mtmp->data) && needspick(mtmp->data)) { if (closed_door(nix, niy)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_PICK_OR_AXE; } else if (IS_TREE(levl[nix][niy].typ)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_AXE; } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { mtmp->weapon_check = NEED_PICK_AXE; } if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) return 0; } /* insert a worm_move() if worms ever begin to eat things */ wasseen = canseemon(mtmp); remove_monster(omx, omy); place_monster(mtmp, nix, niy); if (cursemsg[chi] && (wasseen || canseemon(mtmp))) pline("%s moves only reluctantly.", noit_Monnam(mtmp)); for (j = MTSZ - 1; j > 0; j--) mtmp->mtrack[j] = mtmp->mtrack[j - 1]; mtmp->mtrack[0].x = omx; mtmp->mtrack[0].y = omy; /* We have to know if the pet's gonna do a combined eat and * move before moving it, but it can't eat until after being * moved. Thus the do_eat flag. */ if (do_eat) { if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2; } } else if (mtmp->mleashed && distu(omx, omy) > 4) { /* an incredible kludge, but the only way to keep pooch near * after it spends time eating or in a trap, etc. */ coord cc; nx = sgn(omx - u.ux); ny = sgn(omy - u.uy); cc.x = u.ux + nx; cc.y = u.uy + ny; if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; i = xytod(nx, ny); for (j = (i + 7) % 8; j < (i + 1) % 8; j++) { dtoxy(&cc, j); if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; } for (j = (i + 6) % 8; j < (i + 2) % 8; j++) { dtoxy(&cc, j); if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; } cc.x = mtmp->mx; cc.y = mtmp->my; dognext: if (!m_in_out_region(mtmp, nix, niy)) return 1; remove_monster(mtmp->mx, mtmp->my); place_monster(mtmp, cc.x, cc.y); newsym(cc.x, cc.y); set_apparxy(mtmp); } return 1; } /* check if a monster could pick up objects from a location */ STATIC_OVL boolean could_reach_item(mon, nx, ny) struct monst *mon; xchar nx, ny; { if ((!is_pool(nx, ny) || is_swimmer(mon->data)) && (!is_lava(nx, ny) || likes_lava(mon->data)) && (!sobj_at(BOULDER, nx, ny) || throws_rocks(mon->data))) return TRUE; return FALSE; } /* Hack to prevent a dog from being endlessly stuck near an object that * it can't reach, such as caught in a teleport scroll niche. It recursively * checks to see if the squares in between are good. The checking could be * a little smarter; a full check would probably be useful in m_move() too. * Since the maximum food distance is 5, this should never be more than 5 * calls deep. */ STATIC_OVL boolean can_reach_location(mon, mx, my, fx, fy) struct monst *mon; xchar mx, my, fx, fy; { int i, j; int dist; if (mx == fx && my == fy) return TRUE; if (!isok(mx, my)) return FALSE; /* should not happen */ dist = dist2(mx, my, fx, fy); for (i = mx - 1; i <= mx + 1; i++) { for (j = my - 1; j <= my + 1; j++) { if (!isok(i, j)) continue; if (dist2(i, j, fx, fy) >= dist) continue; if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) && (!may_dig(i, j) || !tunnels(mon->data))) continue; if (IS_DOOR(levl[i][j].typ) && (levl[i][j].doormask & (D_CLOSED | D_LOCKED))) continue; if (!could_reach_item(mon, i, j)) continue; if (can_reach_location(mon, i, j, fx, fy)) return TRUE; } } return FALSE; } /*ARGSUSED*/ /* do_clear_area client */ STATIC_PTR void wantdoor(x, y, distance) int x, y; genericptr_t distance; { int ndist; if (*(int *) distance > (ndist = distu(x, y))) { gx = x; gy = y; *(int *) distance = ndist; } } static struct qmchoices { int mndx; /* type of pet, 0 means any */ char mlet; /* symbol of pet, 0 means any */ unsigned mappearance; /* mimic this */ uchar m_ap_type; /* what is the thing it is mimicing? */ } qm[] = { /* Things that some pets might be thinking about at the time */ { PM_LITTLE_DOG, 0, PM_KITTEN, M_AP_MONSTER }, { PM_DOG, 0, PM_HOUSECAT, M_AP_MONSTER }, { PM_LARGE_DOG, 0, PM_LARGE_CAT, M_AP_MONSTER }, { PM_KITTEN, 0, PM_LITTLE_DOG, M_AP_MONSTER }, { PM_HOUSECAT, 0, PM_DOG, M_AP_MONSTER }, { PM_LARGE_CAT, 0, PM_LARGE_DOG, M_AP_MONSTER }, { PM_HOUSECAT, 0, PM_GIANT_RAT, M_AP_MONSTER }, { 0, S_DOG, SINK, M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */ { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */ }; void finish_meating(mtmp) struct monst *mtmp; { mtmp->meating = 0; if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == NON_PM) { /* was eating a mimic and now appearance needs resetting */ mtmp->m_ap_type = 0; mtmp->mappearance = 0; newsym(mtmp->mx, mtmp->my); } } STATIC_OVL void quickmimic(mtmp) struct monst *mtmp; { int idx = 0, trycnt = 5, spotted; char buf[BUFSZ]; if (Protection_from_shape_changers || !mtmp->meating) return; do { idx = rn2(SIZE(qm)); if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx) break; if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet) break; if (qm[idx].mndx == 0 && qm[idx].mlet == 0) break; } while (--trycnt > 0); if (trycnt == 0) idx = SIZE(qm) - 1; Strcpy(buf, mon_nam(mtmp)); spotted = canspotmon(mtmp); mtmp->m_ap_type = qm[idx].m_ap_type; mtmp->mappearance = qm[idx].mappearance; if (spotted || cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) { /* this isn't quite right; if sensing a monster without being able to see its location, you really shouldn't be told you sense it becoming furniture or an object that you can't see (on the other hand, perhaps you're sensing a brief glimpse of its mind as it changes form) */ newsym(mtmp->mx, mtmp->my); You("%s %s appear where %s was!", cansee(mtmp->mx, mtmp->my) ? "see" : "sense", (mtmp->m_ap_type == M_AP_FURNITURE) ? an(defsyms[mtmp->mappearance].explanation) : (mtmp->m_ap_type == M_AP_OBJECT && OBJ_DESCR(objects[mtmp->mappearance])) ? an(OBJ_DESCR(objects[mtmp->mappearance])) : (mtmp->m_ap_type == M_AP_OBJECT && OBJ_NAME(objects[mtmp->mappearance])) ? an(OBJ_NAME(objects[mtmp->mappearance])) : (mtmp->m_ap_type == M_AP_MONSTER) ? an(mons[mtmp->mappearance].mname) : something, buf); display_nhwindow(WIN_MAP, TRUE); } } /*dogmove.c*/ nethack-3.6.0/src/dokick.c0000664000076400007660000016322712620277605014356 0ustar paxedpaxed/* NetHack 3.6 dokick.c $NHDT-Date: 1446955295 2015/11/08 04:01:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.104 $ */ /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH]) #define martial() \ (martial_bonus() || is_bigfoot(youmonst.data) \ || (uarmf && uarmf->otyp == KICKING_BOOTS)) static NEARDATA struct rm *maploc, nowhere; static NEARDATA const char *gate_str; /* kickedobj (decl.c) tracks a kicked object until placed or destroyed */ extern boolean notonhead; /* for long worms */ STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P)); STATIC_DCL boolean FDECL(maybe_kick_monster, (struct monst *, XCHAR_P, XCHAR_P)); STATIC_DCL void FDECL(kick_monster, (struct monst *, XCHAR_P, XCHAR_P)); STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P)); STATIC_DCL int FDECL(really_kick_object, (XCHAR_P, XCHAR_P)); STATIC_DCL char *FDECL(kickstr, (char *)); STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long)); STATIC_DCL void FDECL(drop_to, (coord *, SCHAR_P)); static const char kick_passes_thru[] = "kick passes harmlessly through"; STATIC_OVL void kickdmg(mon, clumsy) register struct monst *mon; register boolean clumsy; { register int mdx, mdy; register int dmg = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 15; int kick_skill = P_NONE; int blessed_foot_damage = 0; boolean trapkilled = FALSE; if (uarmf && uarmf->otyp == KICKING_BOOTS) dmg += 5; /* excessive wt affects dex, so it affects dmg */ if (clumsy) dmg /= 2; /* kicking a dragon or an elephant will not harm it */ if (thick_skinned(mon->data)) dmg = 0; /* attacking a shade is useless */ if (mon->data == &mons[PM_SHADE]) dmg = 0; if ((is_undead(mon->data) || is_demon(mon->data) || is_vampshifter(mon)) && uarmf && uarmf->blessed) blessed_foot_damage = 1; if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) { pline_The("%s.", kick_passes_thru); /* doesn't exercise skill or abuse alignment or frighten pet, and shades have no passive counterattack */ return; } if (mon->m_ap_type) seemimic(mon); check_caitiff(mon); /* squeeze some guilt feelings... */ if (mon->mtame) { abuse_dog(mon); if (mon->mtame) monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE); else mon->mflee = 0; } if (dmg > 0) { /* convert potential damage to actual damage */ dmg = rnd(dmg); if (martial()) { if (dmg > 1) kick_skill = P_MARTIAL_ARTS; dmg += rn2(ACURR(A_DEX) / 2 + 1); } /* a good kick exercises your dex */ exercise(A_DEX, TRUE); } if (blessed_foot_damage) dmg += rnd(4); if (uarmf) dmg += uarmf->spe; dmg += u.udaminc; /* add ring(s) of increase damage */ if (dmg > 0) mon->mhp -= dmg; if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3) && mon->mcanmove && mon != u.ustuck && !mon->mtrapped) { /* see if the monster has a place to move into */ mdx = mon->mx + u.dx; mdy = mon->my + u.dy; if (goodpos(mdx, mdy, mon, 0)) { pline("%s reels from the blow.", Monnam(mon)); if (m_in_out_region(mon, mdx, mdy)) { remove_monster(mon->mx, mon->my); newsym(mon->mx, mon->my); place_monster(mon, mdx, mdy); newsym(mon->mx, mon->my); set_apparxy(mon); if (mintrap(mon) == 2) trapkilled = TRUE; } } } (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK, FALSE); if (mon->mhp <= 0 && !trapkilled) killed(mon); /* may bring up a dialog, so put this after all messages */ if (kick_skill != P_NONE) /* exercise proficiency */ use_skill(kick_skill, 1); } STATIC_OVL boolean maybe_kick_monster(mon, x, y) struct monst *mon; xchar x, y; { if (mon) { boolean save_forcefight = context.forcefight; bhitpos.x = x; bhitpos.y = y; if (!mon->mpeaceful || !canspotmon(mon)) context.forcefight = TRUE; /* attack even if invisible */ /* kicking might be halted by discovery of hidden monster, by player declining to attack peaceful monster, or by passing out due to encumbrance */ if (attack_checks(mon, (struct obj *) 0) || overexertion()) mon = 0; /* don't kick after all */ context.forcefight = save_forcefight; } return (boolean) (mon != 0); } STATIC_OVL void kick_monster(mon, x, y) struct monst *mon; xchar x, y; { boolean clumsy = FALSE; int i, j; /* anger target even if wild miss will occur */ setmangry(mon); if (Levitation && !rn2(3) && verysmall(mon->data) && !is_flyer(mon->data)) { pline("Floating in the air, you miss wildly!"); exercise(A_DEX, FALSE); (void) passive(mon, FALSE, 1, AT_KICK, FALSE); return; } /* reveal hidden target even if kick ends up missing (note: being hidden doesn't affect chance to hit so neither does this reveal) */ if (mon->mundetected || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER)) { if (mon->m_ap_type) seemimic(mon); mon->mundetected = 0; if (!canspotmon(mon)) map_invisible(x, y); else newsym(x, y); There("is %s here.", canspotmon(mon) ? a_monnam(mon) : "something hidden"); } /* Kick attacks by kicking monsters are normal attacks, not special. * This is almost always worthless, since you can either take one turn * and do all your kicks, or else take one turn and attack the monster * normally, getting all your attacks _including_ all your kicks. * If you have >1 kick attack, you get all of them. */ if (Upolyd && attacktype(youmonst.data, AT_KICK)) { struct attack *uattk; int sum, kickdieroll, armorpenalty, attknum = 0, tmp = find_roll_to_hit(mon, AT_KICK, (struct obj *) 0, &attknum, &armorpenalty); for (i = 0; i < NATTK; i++) { /* first of two kicks might have provoked counterattack that has incapacitated the hero (ie, floating eye) */ if (multi < 0) break; uattk = &youmonst.data->mattk[i]; /* we only care about kicking attacks here */ if (uattk->aatyp != AT_KICK) continue; if (mon->data == &mons[PM_SHADE] && (!uarmf || !uarmf->blessed)) { /* doesn't matter whether it would have hit or missed, and shades have no passive counterattack */ Your("%s %s.", kick_passes_thru, mon_nam(mon)); break; /* skip any additional kicks */ } else if (tmp > (kickdieroll = rnd(20))) { You("kick %s.", mon_nam(mon)); sum = damageum(mon, uattk); (void) passive(mon, (boolean) (sum > 0), (sum != 2), AT_KICK, FALSE); if (sum == 2) break; /* Defender died */ } else { missum(mon, uattk, (tmp + armorpenalty > kickdieroll)); (void) passive(mon, FALSE, 1, AT_KICK, FALSE); } } return; } i = -inv_weight(); j = weight_cap(); if (i < (j * 3) / 10) { if (!rn2((i < j / 10) ? 2 : (i < j / 5) ? 3 : 4)) { if (martial() && !rn2(2)) goto doit; Your("clumsy kick does no damage."); (void) passive(mon, FALSE, 1, AT_KICK, FALSE); return; } if (i < j / 10) clumsy = TRUE; else if (!rn2((i < j / 5) ? 2 : 3)) clumsy = TRUE; } if (Fumbling) clumsy = TRUE; else if (uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25)) clumsy = TRUE; doit: You("kick %s.", mon_nam(mon)); if (!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) && mon->mcansee && !mon->mtrapped && !thick_skinned(mon->data) && mon->data->mlet != S_EEL && haseyes(mon->data) && mon->mcanmove && !mon->mstun && !mon->mconf && !mon->msleeping && mon->data->mmove >= 12) { if (!nohands(mon->data) && !rn2(martial() ? 5 : 3)) { pline("%s blocks your %skick.", Monnam(mon), clumsy ? "clumsy " : ""); (void) passive(mon, FALSE, 1, AT_KICK, FALSE); return; } else { maybe_mnexto(mon); if (mon->mx != x || mon->my != y) { if (glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } pline("%s %s, %s evading your %skick.", Monnam(mon), (!level.flags.noteleport && can_teleport(mon->data)) ? "teleports" : is_floater(mon->data) ? "floats" : is_flyer(mon->data) ? "swoops" : (nolimbs(mon->data) || slithy(mon->data)) ? "slides" : "jumps", clumsy ? "easily" : "nimbly", clumsy ? "clumsy " : ""); (void) passive(mon, FALSE, 1, AT_KICK, FALSE); return; } } } kickdmg(mon, clumsy); } /* * Return TRUE if caught (the gold taken care of), FALSE otherwise. * The gold object is *not* attached to the fobj chain! */ boolean ghitm(mtmp, gold) register struct monst *mtmp; register struct obj *gold; { boolean msg_given = FALSE; if (!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest && !mtmp->isgd && !is_mercenary(mtmp->data)) { wakeup(mtmp); } else if (!mtmp->mcanmove) { /* too light to do real damage */ if (canseemon(mtmp)) { pline_The("%s harmlessly %s %s.", xname(gold), otense(gold, "hit"), mon_nam(mtmp)); msg_given = TRUE; } } else { long umoney, value = gold->quan * objects[gold->otyp].oc_cost; mtmp->msleeping = 0; finish_meating(mtmp); if (!mtmp->isgd && !rn2(4)) /* not always pleasing */ setmangry(mtmp); /* greedy monsters catch gold */ if (cansee(mtmp->mx, mtmp->my)) pline("%s catches the gold.", Monnam(mtmp)); (void) mpickobj(mtmp, gold); gold = (struct obj *) 0; /* obj has been freed */ if (mtmp->isshk) { long robbed = ESHK(mtmp)->robbed; if (robbed) { robbed -= value; if (robbed < 0L) robbed = 0L; pline_The("amount %scovers %s recent losses.", !robbed ? "" : "partially ", mhis(mtmp)); ESHK(mtmp)->robbed = robbed; if (!robbed) make_happy_shk(mtmp, FALSE); } else { if (mtmp->mpeaceful) { ESHK(mtmp)->credit += value; You("have %ld %s in credit.", ESHK(mtmp)->credit, currency(ESHK(mtmp)->credit)); } else verbalize("Thanks, scum!"); } } else if (mtmp->ispriest) { if (mtmp->mpeaceful) verbalize("Thank you for your contribution."); else verbalize("Thanks, scum!"); } else if (mtmp->isgd) { umoney = money_cnt(invent); /* Some of these are iffy, because a hostile guard won't become peaceful and resume leading hero out of the vault. If he did do that, player could try fighting, then weasle out of being killed by throwing his/her gold when losing. */ verbalize( umoney ? "Drop the rest and follow me." : hidden_gold() ? "You still have hidden gold. Drop it now." : mtmp->mpeaceful ? "I'll take care of that; please move along." : "I'll take that; now get moving."); } else if (is_mercenary(mtmp->data)) { long goldreqd = 0L; if (rn2(3)) { if (mtmp->data == &mons[PM_SOLDIER]) goldreqd = 100L; else if (mtmp->data == &mons[PM_SERGEANT]) goldreqd = 250L; else if (mtmp->data == &mons[PM_LIEUTENANT]) goldreqd = 500L; else if (mtmp->data == &mons[PM_CAPTAIN]) goldreqd = 750L; if (goldreqd) { umoney = money_cnt(invent); if (value > goldreqd + (umoney + u.ulevel * rn2(5)) / ACURR(A_CHA)) mtmp->mpeaceful = TRUE; } } if (mtmp->mpeaceful) verbalize("That should do. Now beat it!"); else verbalize("That's not enough, coward!"); } return TRUE; } if (!msg_given) miss(xname(gold), mtmp); return FALSE; } /* container is kicked, dropped, thrown or otherwise impacted by player. * Assumes container is on floor. Checks contents for possible damage. */ void container_impact_dmg(obj, x, y) struct obj *obj; xchar x, y; /* coordinates where object was before the impact, not after */ { struct monst *shkp; struct obj *otmp, *otmp2; long loss = 0L; boolean costly, insider, frominv; /* only consider normal containers */ if (!Is_container(obj) || !Has_contents(obj) || Is_mbag(obj)) return; costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && costly_spot(x, y)); insider = (*u.ushops && inside_shop(u.ux, u.uy) && *in_rooms(x, y, SHOPBASE) == *u.ushops); /* if dropped or thrown, shop ownership flags are set on this obj */ frominv = (obj != kickedobj); for (otmp = obj->cobj; otmp; otmp = otmp2) { const char *result = (char *) 0; otmp2 = otmp->nobj; if (objects[otmp->otyp].oc_material == GLASS && otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) { result = "shatter"; } else if (otmp->otyp == EGG && !rn2(3)) { result = "cracking"; } if (result) { if (otmp->otyp == MIRROR) change_luck(-2); /* eggs laid by you. penalty is -1 per egg, max 5, * but it's always exactly 1 that breaks */ if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) change_luck(-1); You_hear("a muffled %s.", result); if (costly) { if (frominv && !otmp->unpaid) otmp->no_charge = 1; loss += stolen_value(otmp, x, y, (boolean) shkp->mpeaceful, TRUE); } if (otmp->quan > 1L) { useup(otmp); } else { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } /* contents of this container are no longer known */ obj->cknown = 0; } } if (costly && loss) { if (!insider) { You("caused %ld %s worth of damage!", loss, currency(loss)); make_angry_shk(shkp, x, y); } else { You("owe %s %ld %s for objects destroyed.", mon_nam(shkp), loss, currency(loss)); } } } /* jacket around really_kick_object */ STATIC_OVL int kick_object(x, y) xchar x, y; { int res = 0; /* if a pile, the "top" object gets kicked */ kickedobj = level.objects[x][y]; if (kickedobj) { /* kick object; if doing is fatal, done() will clean up kickedobj */ res = really_kick_object(x, y); kickedobj = (struct obj *) 0; } return res; } /* guts of kick_object */ STATIC_OVL int really_kick_object(x, y) xchar x, y; { int range; struct monst *mon, *shkp = 0; struct trap *trap; char bhitroom; boolean costly, isgold, slide = FALSE; /* kickedobj should always be set due to conditions of call */ if (!kickedobj || kickedobj->otyp == BOULDER || kickedobj == uball || kickedobj == uchain) return 0; if ((trap = t_at(x, y)) != 0 && (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls) || trap->ttyp == WEB)) { if (!trap->tseen) find_trap(trap); You_cant("kick %s that's in a %s!", something, Hallucination ? "tizzy" : (trap->ttyp == WEB) ? "web" : "pit"); return 1; } if (Fumbling && !rn2(3)) { Your("clumsy kick missed."); return 1; } if (!uarmf && kickedobj->otyp == CORPSE && touch_petrifies(&mons[kickedobj->corpsenm]) && !Stone_resistance) { You("kick %s with your bare %s.", corpse_xname(kickedobj, (const char *) 0, CXN_PFX_THE), makeplural(body_part(FOOT))); if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) { ; /* hero has been transformed but kick continues */ } else { /* normalize body shape here; foot, not body_part(FOOT) */ Sprintf(killer.name, "kicking %s barefoot", killer_xname(kickedobj)); instapetrify(killer.name); } } /* range < 2 means the object will not move. */ /* maybe dexterity should also figure here. */ range = (int) ((ACURRSTR) / 2 - kickedobj->owt / 40); if (martial()) range += rnd(3); if (is_pool(x, y)) { /* you're in the water too; significantly reduce range */ range = range / 3 + 1; /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */ } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { /* you're in air, since is_pool did not match */ range += rnd(3); } else { if (is_ice(x, y)) range += rnd(3), slide = TRUE; if (kickedobj->greased) range += rnd(3), slide = TRUE; } /* Mjollnir is magically too heavy to kick */ if (kickedobj->oartifact == ART_MJOLLNIR) range = 1; /* see if the object has a place to move into */ if (!ZAP_POS(levl[x + u.dx][y + u.dy].typ) || closed_door(x + u.dx, y + u.dy)) range = 1; costly = (!(kickedobj->no_charge && !Has_contents(kickedobj)) && (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0 && costly_spot(x, y)); isgold = (kickedobj->oclass == COIN_CLASS); if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) { if ((!martial() && rn2(20) > ACURR(A_DEX)) || IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) { if (Blind) pline("It doesn't come loose."); else pline("%s %sn't come loose.", The(distant_name(kickedobj, xname)), otense(kickedobj, "do")); return (!rn2(3) || martial()); } if (Blind) pline("It comes loose."); else pline("%s %s loose.", The(distant_name(kickedobj, xname)), otense(kickedobj, "come")); obj_extract_self(kickedobj); newsym(x, y); if (costly && (!costly_spot(u.ux, u.uy) || !index(u.urooms, *in_rooms(x, y, SHOPBASE)))) addtobill(kickedobj, FALSE, FALSE, FALSE); if (!flooreffects(kickedobj, u.ux, u.uy, "fall")) { place_object(kickedobj, u.ux, u.uy); stackobj(kickedobj); newsym(u.ux, u.uy); } return 1; } /* a box gets a chance of breaking open here */ if (Is_box(kickedobj)) { boolean otrp = kickedobj->otrapped; if (range < 2) pline("THUD!"); container_impact_dmg(kickedobj, x, y); if (kickedobj->olocked) { if (!rn2(5) || (martial() && !rn2(2))) { You("break open the lock!"); breakchestlock(kickedobj, FALSE); if (otrp) (void) chest_trap(kickedobj, LEG, FALSE); return 1; } } else { if (!rn2(3) || (martial() && !rn2(2))) { pline_The("lid slams open, then falls shut."); kickedobj->lknown = 1; if (otrp) (void) chest_trap(kickedobj, LEG, FALSE); return 1; } } if (range < 2) return 1; /* else let it fall through to the next cases... */ } /* fragile objects should not be kicked */ if (hero_breaks(kickedobj, kickedobj->ox, kickedobj->oy, FALSE)) return 1; /* too heavy to move. range is calculated as potential distance from * player, so range == 2 means the object may move up to one square * from its current position */ if (range < 2) { if (!Is_box(kickedobj)) pline("Thump!"); return (!rn2(3) || martial()); } if (kickedobj->quan > 1L) { if (!isgold) { kickedobj = splitobj(kickedobj, 1L); } else { if (rn2(20)) { static NEARDATA const char *const flyingcoinmsg[] = { "scatter the coins", "knock coins all over the place", "send coins flying in all directions", }; pline("Thwwpingg!"); You("%s!", flyingcoinmsg[rn2(SIZE(flyingcoinmsg))]); (void) scatter(x, y, rn2(3) + 1, VIS_EFFECTS | MAY_HIT, kickedobj); newsym(x, y); return 1; } if (kickedobj->quan > 300L) { pline("Thump!"); return (!rn2(3) || martial()); } } } if (slide && !Blind) pline("Whee! %s %s across the %s.", Doname2(kickedobj), otense(kickedobj, "slide"), surface(x, y)); if (costly && !isgold) addtobill(kickedobj, FALSE, FALSE, TRUE); obj_extract_self(kickedobj); (void) snuff_candle(kickedobj); newsym(x, y); mon = bhit(u.dx, u.dy, range, KICKED_WEAPON, (int FDECL((*), (MONST_P, OBJ_P))) 0, (int FDECL((*), (OBJ_P, OBJ_P))) 0, &kickedobj); if (!kickedobj) return 1; /* object broken */ if (mon) { if (mon->isshk && kickedobj->where == OBJ_MINVENT && kickedobj->ocarry == mon) return 1; /* alert shk caught it */ notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y); if (isgold ? ghitm(mon, kickedobj) /* caught? */ : thitmonst(mon, kickedobj)) /* hit && used up? */ return 1; } /* the object might have fallen down a hole; ship_object() will have taken care of shop billing */ if (kickedobj->where == OBJ_MIGRATING) return 1; bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE); if (costly && (!costly_spot(bhitpos.x, bhitpos.y) || *in_rooms(x, y, SHOPBASE) != bhitroom)) { if (isgold) costly_gold(x, y, kickedobj->quan); else (void) stolen_value(kickedobj, x, y, (boolean) shkp->mpeaceful, FALSE); } if (flooreffects(kickedobj, bhitpos.x, bhitpos.y, "fall")) return 1; if (kickedobj->unpaid) subfrombill(kickedobj, shkp); place_object(kickedobj, bhitpos.x, bhitpos.y); stackobj(kickedobj); newsym(kickedobj->ox, kickedobj->oy); return 1; } /* cause of death if kicking kills kicker */ STATIC_OVL char * kickstr(buf) char *buf; { const char *what; if (kickedobj) what = killer_xname(kickedobj); else if (maploc == &nowhere) what = "nothing"; else if (IS_DOOR(maploc->typ)) what = "a door"; else if (IS_TREE(maploc->typ)) what = "a tree"; else if (IS_STWALL(maploc->typ)) what = "a wall"; else if (IS_ROCK(maploc->typ)) what = "a rock"; else if (IS_THRONE(maploc->typ)) what = "a throne"; else if (IS_FOUNTAIN(maploc->typ)) what = "a fountain"; else if (IS_GRAVE(maploc->typ)) what = "a headstone"; else if (IS_SINK(maploc->typ)) what = "a sink"; else if (IS_ALTAR(maploc->typ)) what = "an altar"; else if (IS_DRAWBRIDGE(maploc->typ)) what = "a drawbridge"; else if (maploc->typ == STAIRS) what = "the stairs"; else if (maploc->typ == LADDER) what = "a ladder"; else if (maploc->typ == IRONBARS) what = "an iron bar"; else what = "something weird"; return strcat(strcpy(buf, "kicking "), what); } int dokick() { int x, y; int avrg_attrib; int dmg = 0, glyph, oldglyph = -1; register struct monst *mtmp; boolean no_kick = FALSE; char buf[BUFSZ]; if (nolimbs(youmonst.data) || slithy(youmonst.data)) { You("have no legs to kick with."); no_kick = TRUE; } else if (verysmall(youmonst.data)) { You("are too small to do any kicking."); no_kick = TRUE; } else if (u.usteed) { if (yn_function("Kick your steed?", ynchars, 'y') == 'y') { You("kick %s.", mon_nam(u.usteed)); kick_steed(); return 1; } else { return 0; } } else if (Wounded_legs) { /* note: jump() has similar code */ long wl = (EWounded_legs & BOTH_SIDES); const char *bp = body_part(LEG); if (wl == BOTH_SIDES) bp = makeplural(bp); Your("%s%s %s in no shape for kicking.", (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "", bp, (wl == BOTH_SIDES) ? "are" : "is"); no_kick = TRUE; } else if (near_capacity() > SLT_ENCUMBER) { Your("load is too heavy to balance yourself for a kick."); no_kick = TRUE; } else if (youmonst.data->mlet == S_LIZARD) { Your("legs cannot kick effectively."); no_kick = TRUE; } else if (u.uinwater && !rn2(2)) { Your("slow motion kick doesn't hit anything."); no_kick = TRUE; } else if (u.utrap) { no_kick = TRUE; switch (u.utraptype) { case TT_PIT: if (!Passes_walls) pline("There's not enough room to kick down here."); else no_kick = FALSE; break; case TT_WEB: case TT_BEARTRAP: You_cant("move your %s!", body_part(LEG)); break; default: break; } } if (no_kick) { /* ignore direction typed before player notices kick failed */ display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */ return 0; } if (!getdir((char *) 0)) return 0; if (!u.dx && !u.dy) return 0; x = u.ux + u.dx; y = u.uy + u.dy; /* KMH -- Kicking boots always succeed */ if (uarmf && uarmf->otyp == KICKING_BOOTS) avrg_attrib = 99; else avrg_attrib = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3; if (u.uswallow) { switch (rn2(3)) { case 0: You_cant("move your %s!", body_part(LEG)); break; case 1: if (is_animal(u.ustuck->data)) { pline("%s burps loudly.", Monnam(u.ustuck)); break; } default: Your("feeble kick has no effect."); break; } return 1; } else if (u.utrap && u.utraptype == TT_PIT) { /* must be Passes_walls */ You("kick at the side of the pit."); return 1; } if (Levitation) { int xx, yy; xx = u.ux - u.dx; yy = u.uy - u.dy; /* doors can be opened while levitating, so they must be * reachable for bracing purposes * Possible extension: allow bracing against stuff on the side? */ if (isok(xx, yy) && !IS_ROCK(levl[xx][yy].typ) && !IS_DOOR(levl[xx][yy].typ) && (!Is_airlevel(&u.uz) || !OBJ_AT(xx, yy))) { You("have nothing to brace yourself against."); return 0; } } mtmp = isok(x, y) ? m_at(x, y) : 0; /* might not kick monster if it is hidden and becomes revealed, if it is peaceful and player declines to attack, or if the hero passes out due to encumbrance with low hp; context.move will be 1 unless player declines to kick peaceful monster */ if (mtmp) { oldglyph = glyph_at(x, y); if (!maybe_kick_monster(mtmp, x, y)) return context.move; } wake_nearby(); u_wipe_engr(2); if (!isok(x, y)) { maploc = &nowhere; goto ouch; } maploc = &levl[x][y]; /* * The next five tests should stay in their present order: * monsters, pools, objects, non-doors, doors. * * [FIXME: Monsters who are hidden underneath objects or * in pools should lead to hero kicking the concealment * rather than the monster, probably exposing the hidden * monster in the process. And monsters who are hidden on * ceiling shouldn't be kickable (unless hero is flying?); * kicking toward them should just target whatever is on * the floor at that spot.] */ if (mtmp) { /* save mtmp->data (for recoil) in case mtmp gets killed */ struct permonst *mdat = mtmp->data; kick_monster(mtmp, x, y); glyph = glyph_at(x, y); /* see comment in attack_checks() */ if (mtmp->mhp <= 0) { /* DEADMONSTER() */ /* if we mapped an invisible monster and immediately killed it, we don't want to forget what we thought was there before the kick */ if (glyph != oldglyph && glyph_is_invisible(glyph)) show_glyph(x, y, oldglyph); } else if (!canspotmon(mtmp) /* check ; monster that evades kick by jumping to an unseen square doesn't leave an I behind */ && mtmp->mx == x && mtmp->my == y && !glyph_is_invisible(glyph) && !(u.uswallow && mtmp == u.ustuck)) { map_invisible(x, y); } /* recoil if floating */ if ((Is_airlevel(&u.uz) || Levitation) && context.move) { int range; range = ((int) youmonst.data->cwt + (weight_cap() + inv_weight())); if (range < 1) range = 1; /* divide by zero avoidance */ range = (3 * (int) mdat->cwt) / range; if (range < 1) range = 1; hurtle(-u.dx, -u.dy, range, TRUE); } return 1; } if (glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } if (is_pool(x, y) ^ !!u.uinwater) { /* objects normally can't be removed from water by kicking */ You("splash some water around."); return 1; } if (OBJ_AT(x, y) && (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || sobj_at(BOULDER, x, y))) { if (kick_object(x, y)) { if (Is_airlevel(&u.uz)) hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */ return 1; } goto ouch; } if (!IS_DOOR(maploc->typ)) { if (maploc->typ == SDOOR) { if (!Levitation && rn2(30) < avrg_attrib) { cvt_sdoor_to_door(maploc); /* ->typ = DOOR */ pline("Crash! %s a secret door!", /* don't "kick open" when it's locked unless it also happens to be trapped */ (maploc->doormask & (D_LOCKED | D_TRAPPED)) == D_LOCKED ? "Your kick uncovers" : "You kick open"); exercise(A_DEX, TRUE); if (maploc->doormask & D_TRAPPED) { maploc->doormask = D_NODOOR; b_trapped("door", FOOT); } else if (maploc->doormask != D_NODOOR && !(maploc->doormask & D_LOCKED)) maploc->doormask = D_ISOPEN; feel_newsym(x, y); /* we know it's gone */ if (maploc->doormask == D_ISOPEN || maploc->doormask == D_NODOOR) unblock_point(x, y); /* vision */ return 1; } else goto ouch; } if (maploc->typ == SCORR) { if (!Levitation && rn2(30) < avrg_attrib) { pline("Crash! You kick open a secret passage!"); exercise(A_DEX, TRUE); maploc->typ = CORR; feel_newsym(x, y); /* we know it's gone */ unblock_point(x, y); /* vision */ return 1; } else goto ouch; } if (IS_THRONE(maploc->typ)) { register int i; if (Levitation) goto dumb; if ((Luck < 0 || maploc->doormask) && !rn2(3)) { maploc->typ = ROOM; maploc->doormask = 0; /* don't leave loose ends.. */ (void) mkgold((long) rnd(200), x, y); if (Blind) pline("CRASH! You destroy it."); else { pline("CRASH! You destroy the throne."); newsym(x, y); } exercise(A_DEX, TRUE); return 1; } else if (Luck > 0 && !rn2(3) && !maploc->looted) { (void) mkgold((long) rn1(201, 300), x, y); i = Luck + 1; if (i > 6) i = 6; while (i--) (void) mksobj_at( rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE - 1), x, y, FALSE, TRUE); if (Blind) You("kick %s loose!", something); else { You("kick loose some ornamental coins and gems!"); newsym(x, y); } /* prevent endless milking */ maploc->looted = T_LOOTED; return 1; } else if (!rn2(4)) { if (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) { fall_through(FALSE); return 1; } else goto ouch; } goto ouch; } if (IS_ALTAR(maploc->typ)) { if (Levitation) goto dumb; You("kick %s.", (Blind ? something : "the altar")); if (!rn2(3)) goto ouch; altar_wrath(x, y); exercise(A_DEX, TRUE); return 1; } if (IS_FOUNTAIN(maploc->typ)) { if (Levitation) goto dumb; You("kick %s.", (Blind ? something : "the fountain")); if (!rn2(3)) goto ouch; /* make metal boots rust */ if (uarmf && rn2(3)) if (water_damage(uarmf, "metal boots", TRUE) == ER_NOTHING) { Your("boots get wet."); /* could cause short-lived fumbling here */ } exercise(A_DEX, TRUE); return 1; } if (IS_GRAVE(maploc->typ)) { if (Levitation) goto dumb; if (rn2(4)) goto ouch; exercise(A_WIS, FALSE); if (Role_if(PM_ARCHEOLOGIST) || Role_if(PM_SAMURAI) || ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10))) { adjalign(-sgn(u.ualign.type)); } maploc->typ = ROOM; maploc->doormask = 0; (void) mksobj_at(ROCK, x, y, TRUE, FALSE); del_engr_at(x, y); if (Blind) pline("Crack! %s broke!", Something); else { pline_The("headstone topples over and breaks!"); newsym(x, y); } return 1; } if (maploc->typ == IRONBARS) goto ouch; if (IS_TREE(maploc->typ)) { struct obj *treefruit; /* nothing, fruit or trouble? 75:23.5:1.5% */ if (rn2(3)) { if (!rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) You_hear("a low buzzing."); /* a warning */ goto ouch; } if (rn2(15) && !(maploc->looted & TREE_LOOTED) && (treefruit = rnd_treefruit_at(x, y))) { long nfruit = 8L - rnl(7), nfall; short frtype = treefruit->otyp; treefruit->quan = nfruit; if (is_plural(treefruit)) pline("Some %s fall from the tree!", xname(treefruit)); else pline("%s falls from the tree!", An(xname(treefruit))); nfall = scatter(x, y, 2, MAY_HIT, treefruit); if (nfall != nfruit) { /* scatter left some in the tree, but treefruit * may not refer to the correct object */ treefruit = mksobj(frtype, TRUE, FALSE); treefruit->quan = nfruit - nfall; pline("%ld %s got caught in the branches.", nfruit - nfall, xname(treefruit)); dealloc_obj(treefruit); } exercise(A_DEX, TRUE); exercise(A_WIS, TRUE); /* discovered a new food source! */ newsym(x, y); maploc->looted |= TREE_LOOTED; return 1; } else if (!(maploc->looted & TREE_SWARM)) { int cnt = rnl(4) + 2; int made = 0; coord mm; mm.x = x; mm.y = y; while (cnt--) { if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE]) && makemon(&mons[PM_KILLER_BEE], mm.x, mm.y, MM_ANGRY)) made++; } if (made) pline("You've attracted the tree's former occupants!"); else You("smell stale honey."); maploc->looted |= TREE_SWARM; return 1; } goto ouch; } if (IS_SINK(maploc->typ)) { int gend = poly_gender(); short washerndx = (gend == 1 || (gend == 2 && rn2(2))) ? PM_INCUBUS : PM_SUCCUBUS; if (Levitation) goto dumb; if (rn2(5)) { if (!Deaf) pline("Klunk! The pipes vibrate noisily."); else pline("Klunk!"); exercise(A_DEX, TRUE); return 1; } else if (!(maploc->looted & S_LPUDDING) && !rn2(3) && !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) { if (Blind) You_hear("a gushing sound."); else pline("A %s ooze gushes up from the drain!", hcolor(NH_BLACK)); (void) makemon(&mons[PM_BLACK_PUDDING], x, y, NO_MM_FLAGS); exercise(A_DEX, TRUE); newsym(x, y); maploc->looted |= S_LPUDDING; return 1; } else if (!(maploc->looted & S_LDWASHER) && !rn2(3) && !(mvitals[washerndx].mvflags & G_GONE)) { /* can't resist... */ pline("%s returns!", (Blind ? Something : "The dish washer")); if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS)) newsym(x, y); maploc->looted |= S_LDWASHER; exercise(A_DEX, TRUE); return 1; } else if (!rn2(3)) { pline("Flupp! %s.", (Blind ? "You hear a sloshing sound" : "Muddy waste pops up from the drain")); if (!(maploc->looted & S_LRING)) { /* once per sink */ if (!Blind) You_see("a ring shining in its midst."); (void) mkobj_at(RING_CLASS, x, y, TRUE); newsym(x, y); exercise(A_DEX, TRUE); exercise(A_WIS, TRUE); /* a discovery! */ maploc->looted |= S_LRING; } return 1; } goto ouch; } if (maploc->typ == STAIRS || maploc->typ == LADDER || IS_STWALL(maploc->typ)) { if (!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN) goto dumb; ouch: pline("Ouch! That hurts!"); exercise(A_DEX, FALSE); exercise(A_STR, FALSE); if (isok(x, y)) { if (Blind) feel_location(x, y); /* we know we hit it */ if (is_drawbridge_wall(x, y) >= 0) { pline_The("drawbridge is unaffected."); /* update maploc to refer to the drawbridge */ (void) find_drawbridge(&x, &y); maploc = &levl[x][y]; } } if (!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); dmg = rnd(ACURR(A_CON) > 15 ? 3 : 5); losehp(Maybe_Half_Phys(dmg), kickstr(buf), KILLED_BY); if (Is_airlevel(&u.uz) || Levitation) hurtle(-u.dx, -u.dy, rn1(2, 4), TRUE); /* assume it's heavy */ return 1; } goto dumb; } if (maploc->doormask == D_ISOPEN || maploc->doormask == D_BROKEN || maploc->doormask == D_NODOOR) { dumb: exercise(A_DEX, FALSE); if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) { You("kick at empty space."); if (Blind) feel_location(x, y); } else { pline("Dumb move! You strain a muscle."); exercise(A_STR, FALSE); set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); } if ((Is_airlevel(&u.uz) || Levitation) && rn2(2)) hurtle(-u.dx, -u.dy, 1, TRUE); return 1; /* uses a turn */ } /* not enough leverage to kick open doors while levitating */ if (Levitation) goto ouch; exercise(A_DEX, TRUE); /* door is known to be CLOSED or LOCKED */ if (rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) { boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE; /* break the door */ if (maploc->doormask & D_TRAPPED) { if (flags.verbose) You("kick the door."); exercise(A_STR, FALSE); maploc->doormask = D_NODOOR; b_trapped("door", FOOT); } else if (ACURR(A_STR) > 18 && !rn2(5) && !shopdoor) { pline("As you kick the door, it shatters to pieces!"); exercise(A_STR, TRUE); maploc->doormask = D_NODOOR; } else { pline("As you kick the door, it crashes open!"); exercise(A_STR, TRUE); maploc->doormask = D_BROKEN; } feel_newsym(x, y); /* we know we broke it */ unblock_point(x, y); /* vision */ if (shopdoor) { add_damage(x, y, 400L); pay_for_damage("break", FALSE); } if (in_town(x, y)) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { mon_yells(mtmp, "Halt, thief! You're under arrest!"); (void) angry_guards(FALSE); break; } } } else { if (Blind) feel_location(x, y); /* we know we hit it */ exercise(A_STR, TRUE); pline("WHAMMM!!!"); if (in_town(x, y)) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data) && mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my)) { if (levl[x][y].looted & D_WARNED) { mon_yells(mtmp, "Halt, vandal! You're under arrest!"); (void) angry_guards(FALSE); } else { mon_yells(mtmp, "Hey, stop damaging that door!"); levl[x][y].looted |= D_WARNED; } break; } } } return 1; } STATIC_OVL void drop_to(cc, loc) coord *cc; schar loc; { /* cover all the MIGR_xxx choices generated by down_gate() */ switch (loc) { case MIGR_RANDOM: /* trap door or hole */ if (Is_stronghold(&u.uz)) { cc->x = valley_level.dnum; cc->y = valley_level.dlevel; break; } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) { cc->y = cc->x = 0; break; } /* else fall to the next cases */ case MIGR_STAIRS_UP: case MIGR_LADDER_UP: cc->x = u.uz.dnum; cc->y = u.uz.dlevel + 1; break; case MIGR_SSTAIRS: cc->x = sstairs.tolev.dnum; cc->y = sstairs.tolev.dlevel; break; default: case MIGR_NOWHERE: /* y==0 means "nowhere", in which case x doesn't matter */ cc->y = cc->x = 0; break; } } /* player or missile impacts location, causing objects to fall down */ void impact_drop(missile, x, y, dlev) struct obj *missile; /* caused impact, won't drop itself */ xchar x, y; /* location affected */ xchar dlev; /* if !0 send to dlev near player */ { schar toloc; register struct obj *obj, *obj2; register struct monst *shkp; long oct, dct, price, debit, robbed; boolean angry, costly, isrock; coord cc; if (!OBJ_AT(x, y)) return; toloc = down_gate(x, y); drop_to(&cc, toloc); if (!cc.y) return; if (dlev) { /* send objects next to player falling through trap door. * checked in obj_delivery(). */ toloc = MIGR_WITH_HERO; cc.y = dlev; } costly = costly_spot(x, y); price = debit = robbed = 0L; angry = FALSE; shkp = (struct monst *) 0; /* if 'costly', we must keep a record of ESHK(shkp) before * it undergoes changes through the calls to stolen_value. * the angry bit must be reset, if needed, in this fn, since * stolen_value is called under the 'silent' flag to avoid * unsavory pline repetitions. */ if (costly) { if ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0) { debit = ESHK(shkp)->debit; robbed = ESHK(shkp)->robbed; angry = !shkp->mpeaceful; } } isrock = (missile && missile->otyp == ROCK); oct = dct = 0L; for (obj = level.objects[x][y]; obj; obj = obj2) { obj2 = obj->nexthere; if (obj == missile) continue; /* number of objects in the pile */ oct += obj->quan; if (obj == uball || obj == uchain) continue; /* boulders can fall too, but rarely & never due to rocks */ if ((isrock && obj->otyp == BOULDER) || rn2(obj->otyp == BOULDER ? 30 : 3)) continue; obj_extract_self(obj); if (costly) { price += stolen_value( obj, x, y, (costly_spot(u.ux, u.uy) && index(u.urooms, *in_rooms(x, y, SHOPBASE))), TRUE); /* set obj->no_charge to 0 */ if (Has_contents(obj)) picked_container(obj); /* does the right thing */ if (obj->oclass != COIN_CLASS) obj->no_charge = 0; } add_to_migration(obj); obj->ox = cc.x; obj->oy = cc.y; obj->owornmask = (long) toloc; /* number of fallen objects */ dct += obj->quan; } if (dct && cansee(x, y)) { /* at least one object fell */ const char *what = (dct == 1L ? "object falls" : "objects fall"); if (missile) pline("From the impact, %sother %s.", dct == oct ? "the " : dct == 1L ? "an" : "", what); else if (oct == dct) pline("%s adjacent %s %s.", dct == 1L ? "The" : "All the", what, gate_str); else pline("%s adjacent %s %s.", dct == 1L ? "One of the" : "Some of the", dct == 1L ? "objects falls" : what, gate_str); } if (costly && shkp && price) { if (ESHK(shkp)->robbed > robbed) { You("removed %ld %s worth of goods!", price, currency(price)); if (cansee(shkp->mx, shkp->my)) { if (ESHK(shkp)->customer[0] == 0) (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ); if (angry) pline("%s is infuriated!", Monnam(shkp)); else pline("\"%s, you are a thief!\"", plname); } else You_hear("a scream, \"Thief!\""); hot_pursuit(shkp); (void) angry_guards(FALSE); return; } if (ESHK(shkp)->debit > debit) { long amt = (ESHK(shkp)->debit - debit); You("owe %s %ld %s for goods lost.", Monnam(shkp), amt, currency(amt)); } } } /* NOTE: ship_object assumes otmp was FREED from fobj or invent. * is the point of drop. otmp is _not_ an resident: * otmp is either a kicked, dropped, or thrown object. */ boolean ship_object(otmp, x, y, shop_floor_obj) xchar x, y; struct obj *otmp; boolean shop_floor_obj; { schar toloc; xchar ox, oy; coord cc; struct obj *obj; struct trap *t; boolean nodrop, unpaid, container, impact = FALSE; long n = 0L; if (!otmp) return FALSE; if ((toloc = down_gate(x, y)) == MIGR_NOWHERE) return FALSE; drop_to(&cc, toloc); if (!cc.y) return FALSE; /* objects other than attached iron ball always fall down ladder, but have a chance of staying otherwise */ nodrop = (otmp == uball) || (otmp == uchain) || (toloc != MIGR_LADDER_UP && rn2(3)); container = Has_contents(otmp); unpaid = is_unpaid(otmp); if (OBJ_AT(x, y)) { for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if (obj != otmp) n += obj->quan; if (n) impact = TRUE; } /* boulders never fall through trap doors, but they might knock other things down before plugging the hole */ if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0) && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { if (impact) impact_drop(otmp, x, y, 0); return FALSE; /* let caller finish the drop */ } if (cansee(x, y)) otransit_msg(otmp, nodrop, n); if (nodrop) { if (impact) impact_drop(otmp, x, y, 0); return FALSE; } if (unpaid || shop_floor_obj) { if (unpaid) { (void) stolen_value(otmp, u.ux, u.uy, TRUE, FALSE); } else { ox = otmp->ox; oy = otmp->oy; (void) stolen_value( otmp, ox, oy, (costly_spot(u.ux, u.uy) && index(u.urooms, *in_rooms(ox, oy, SHOPBASE))), FALSE); } /* set otmp->no_charge to 0 */ if (container) picked_container(otmp); /* happens to do the right thing */ if (otmp->oclass != COIN_CLASS) otmp->no_charge = 0; } if (otmp->owornmask) remove_worn_item(otmp, TRUE); /* some things break rather than ship */ if (breaktest(otmp)) { const char *result; if (objects[otmp->otyp].oc_material == GLASS || otmp->otyp == EXPENSIVE_CAMERA) { if (otmp->otyp == MIRROR) change_luck(-2); result = "crash"; } else { /* penalty for breaking eggs laid by you */ if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) change_luck((schar) -min(otmp->quan, 5L)); result = "splat"; } You_hear("a muffled %s.", result); obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); return TRUE; } add_to_migration(otmp); otmp->ox = cc.x; otmp->oy = cc.y; otmp->owornmask = (long) toloc; /* boulder from rolling boulder trap, no longer part of the trap */ if (otmp->otyp == BOULDER) otmp->otrapped = 0; if (impact) { /* the objs impacted may be in a shop other than * the one in which the hero is located. another * check for a shk is made in impact_drop. it is, e.g., * possible to kick/throw an object belonging to one * shop into another shop through a gap in the wall, * and cause objects belonging to the other shop to * fall down a trap door--thereby getting two shopkeepers * angry at the hero in one shot. */ impact_drop(otmp, x, y, 0); newsym(x, y); } return TRUE; } void obj_delivery(near_hero) boolean near_hero; { register struct obj *otmp, *otmp2; register int nx, ny; int where; boolean nobreak, noscatter; for (otmp = migrating_objs; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue; where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ nobreak = (where & MIGR_NOBREAK) != 0; noscatter = (where & MIGR_WITH_HERO) != 0; where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER); if (!near_hero ^ (where == MIGR_WITH_HERO)) continue; obj_extract_self(otmp); otmp->owornmask = 0L; switch (where) { case MIGR_STAIRS_UP: nx = xupstair, ny = yupstair; break; case MIGR_LADDER_UP: nx = xupladder, ny = yupladder; break; case MIGR_SSTAIRS: nx = sstairs.sx, ny = sstairs.sy; break; case MIGR_WITH_HERO: nx = u.ux, ny = u.uy; break; default: case MIGR_RANDOM: nx = ny = 0; break; } if (nx > 0) { place_object(otmp, nx, ny); if (!nobreak && !IS_SOFT(levl[nx][ny].typ)) { if (where == MIGR_WITH_HERO) { if (breaks(otmp, nx, ny)) continue; } else if (breaktest(otmp)) { /* assume it broke before player arrived, no messages */ delobj(otmp); continue; } } stackobj(otmp); if (!noscatter) (void) scatter(nx, ny, rnd(2), 0, otmp); } else { /* random location */ /* set dummy coordinates because there's no current position for rloco() to update */ otmp->ox = otmp->oy = 0; if (rloco(otmp) && !nobreak && breaktest(otmp)) { /* assume it broke before player arrived, no messages */ delobj(otmp); } } } } STATIC_OVL void otransit_msg(otmp, nodrop, num) register struct obj *otmp; register boolean nodrop; long num; { char obuf[BUFSZ]; Sprintf(obuf, "%s%s", (otmp->otyp == CORPSE && type_is_pname(&mons[otmp->corpsenm])) ? "" : "The ", cxname(otmp)); if (num) { /* means: other objects are impacted */ Sprintf(eos(obuf), " %s %s object%s", otense(otmp, "hit"), num == 1L ? "another" : "other", num > 1L ? "s" : ""); if (nodrop) Sprintf(eos(obuf), "."); else Sprintf(eos(obuf), " and %s %s.", otense(otmp, "fall"), gate_str); pline1(obuf); } else if (!nodrop) pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str); } /* migration destination for objects which fall down to next level */ schar down_gate(x, y) xchar x, y; { struct trap *ttmp; gate_str = 0; /* this matches the player restriction in goto_level() */ if (on_level(&u.uz, &qstart_level) && !ok_to_quest()) return MIGR_NOWHERE; if ((xdnstair == x && ydnstair == y) || (sstairs.sx == x && sstairs.sy == y && !sstairs.up)) { gate_str = "down the stairs"; return (xdnstair == x && ydnstair == y) ? MIGR_STAIRS_UP : MIGR_SSTAIRS; } if (xdnladder == x && ydnladder == y) { gate_str = "down the ladder"; return MIGR_LADDER_UP; } if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) { gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door" : "through the hole"; return MIGR_RANDOM; } return MIGR_NOWHERE; } /*dokick.c*/ nethack-3.6.0/src/dothrow.c0000664000076400007660000020376412621207145014572 0ustar paxedpaxed/* NetHack 3.6 dothrow.c $NHDT-Date: 1446975465 2015/11/08 09:37:45 $ $NHDT-Branch: master $:$NHDT-Revision: 1.113 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Contains code for 't' (throw) */ #include "hack.h" STATIC_DCL int FDECL(throw_obj, (struct obj *, int)); STATIC_DCL boolean FDECL(ok_to_throw, (int *)); STATIC_DCL void NDECL(autoquiver); STATIC_DCL int FDECL(gem_accept, (struct monst *, struct obj *)); STATIC_DCL void FDECL(tmiss, (struct obj *, struct monst *, BOOLEAN_P)); STATIC_DCL int FDECL(throw_gold, (struct obj *)); STATIC_DCL void FDECL(check_shop_obj, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); STATIC_DCL void FDECL(breakmsg, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(toss_up, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(throwing_weapon, (struct obj *)); STATIC_DCL void FDECL(sho_obj_return_to_u, (struct obj * obj)); STATIC_DCL boolean FDECL(mhurtle_step, (genericptr_t, int, int)); static NEARDATA const char toss_objs[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 }; /* different default choices when wielding a sling (gold must be included) */ static NEARDATA const char bullets[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 }; /* thrownobj (decl.c) tracks an object until it lands */ extern boolean notonhead; /* for long worms */ /* Throw the selected object, asking for direction */ STATIC_OVL int throw_obj(obj, shotlimit) struct obj *obj; int shotlimit; { struct obj *otmp; int multishot; schar skill; long wep_mask; boolean twoweap, weakmultishot; /* ask "in what direction?" */ if (!getdir((char *) 0)) { /* No direction specified, so cancel the throw; * might need to undo an object split. * We used to use freeinv(obj),addinv(obj) here, but that can * merge obj into another stack--usually quiver--even if it hadn't * been split from there (possibly triggering a panic in addinv), * and freeinv+addinv potentially has other side-effects. */ if (obj->o_id == context.objsplit.parent_oid || obj->o_id == context.objsplit.child_oid) (void) unsplitobj(obj); return 0; /* no time passes */ } /* * Throwing money is usually for getting rid of it when * a leprechaun approaches, or for bribing an oncoming * angry monster. So throw the whole object. * * If the money is in quiver, throw one coin at a time, * possibly using a sling. */ if (obj->oclass == COIN_CLASS && obj != uquiver) return throw_gold(obj); if (!canletgo(obj, "throw")) return 0; if (obj->oartifact == ART_MJOLLNIR && obj != uwep) { pline("%s must be wielded before it can be thrown.", The(xname(obj))); return 0; } if ((obj->oartifact == ART_MJOLLNIR && ACURR(A_STR) < STR19(25)) || (obj->otyp == BOULDER && !throws_rocks(youmonst.data))) { pline("It's too heavy."); return 1; } if (!u.dx && !u.dy && !u.dz) { You("cannot throw an object at yourself."); return 0; } u_wipe_engr(2); if (!uarmg && obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm]) && !Stone_resistance) { You("throw %s with your bare %s.", corpse_xname(obj, (const char *) 0, CXN_PFX_THE), /* throwing with one hand, but pluralize since the expression "with your bare hands" sounds better */ makeplural(body_part(HAND))); Sprintf(killer.name, "throwing %s bare-handed", killer_xname(obj)); instapetrify(killer.name); } if (welded(obj)) { weldmsg(obj); return 1; } if (is_wet_towel(obj)) dry_a_towel(obj, -1, FALSE); /* Multishot calculations * (potential volley of up to N missiles; default for N is 1) */ multishot = 1; skill = objects[obj->otyp].oc_skill; if (obj->quan > 1L /* no point checking if there's only 1 */ /* ammo requires corresponding launcher be wielded */ && (is_ammo(obj) ? matching_launcher(obj, uwep) /* otherwise any stackable (non-ammo) weapon */ : obj->oclass == WEAPON_CLASS) && !(Confusion || Stunned)) { /* some roles don't get a volley bonus until becoming expert */ weakmultishot = (Role_if(PM_WIZARD) || Role_if(PM_PRIEST) || (Role_if(PM_HEALER) && skill != P_KNIFE) || (Role_if(PM_TOURIST) && skill != -P_DART) /* poor dexterity also inhibits multishot */ || Fumbling || ACURR(A_DEX) <= 6); /* Bonus if the player is proficient in this weapon... */ switch (P_SKILL(weapon_type(obj))) { case P_EXPERT: multishot++; /*FALLTHRU*/ case P_SKILLED: if (!weakmultishot) multishot++; break; default: /* basic or unskilled: no bonus */ break; } /* ...or is using a special weapon for their role... */ switch (Role_switch) { case PM_CAVEMAN: /* give bonus for low-tech gear */ if (skill == -P_SLING || skill == P_SPEAR) multishot++; break; case PM_MONK: /* allow higher volley count despite skill limitation */ if (skill == -P_SHURIKEN) multishot++; break; case PM_RANGER: /* arbitrary; encourage use of other missiles beside daggers */ if (skill != P_DAGGER) multishot++; break; case PM_ROGUE: /* possibly should add knives... */ if (skill == P_DAGGER) multishot++; break; case PM_SAMURAI: /* role-specific launcher and its ammo */ if (obj->otyp == YA && uwep && uwep->otyp == YUMI) multishot++; break; default: break; /* No bonus */ } /* ...or using their race's special bow; no bonus for spears */ if (!weakmultishot) switch (Race_switch) { case PM_ELF: if (obj->otyp == ELVEN_ARROW && uwep && uwep->otyp == ELVEN_BOW) multishot++; break; case PM_ORC: if (obj->otyp == ORCISH_ARROW && uwep && uwep->otyp == ORCISH_BOW) multishot++; break; case PM_GNOME: /* arbitrary; there isn't any gnome-specific gear */ if (skill == -P_CROSSBOW) multishot++; break; case PM_HUMAN: case PM_DWARF: default: break; /* No bonus */ } /* crossbows are slow to load and probably shouldn't allow multiple shots at all, but that would result in players never using them; instead, high strength is necessary to load and shoot quickly */ if (multishot > 1 && skill == -P_CROSSBOW && ammo_and_launcher(obj, uwep) && (int) ACURRSTR < (Race_if(PM_GNOME) ? 16 : 18)) multishot = rnd(multishot); multishot = rnd(multishot); if ((long) multishot > obj->quan) multishot = (int) obj->quan; if (shotlimit > 0 && multishot > shotlimit) multishot = shotlimit; } m_shot.s = ammo_and_launcher(obj, uwep) ? TRUE : FALSE; /* give a message if shooting more than one, or if player attempted to specify a count */ if (multishot > 1 || shotlimit > 0) { /* "You shoot N arrows." or "You throw N daggers." */ You("%s %d %s.", m_shot.s ? "shoot" : "throw", multishot, /* (might be 1 if player gave shotlimit) */ (multishot == 1) ? singular(obj, xname) : xname(obj)); } wep_mask = obj->owornmask; m_shot.o = obj->otyp; m_shot.n = multishot; for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) { twoweap = u.twoweap; /* split this object off from its slot if necessary */ if (obj->quan > 1L) { otmp = splitobj(obj, 1L); } else { otmp = obj; if (otmp->owornmask) remove_worn_item(otmp, FALSE); } freeinv(otmp); throwit(otmp, wep_mask, twoweap); } m_shot.n = m_shot.i = 0; m_shot.o = STRANGE_OBJECT; m_shot.s = FALSE; return 1; } /* common to dothrow() and dofire() */ STATIC_OVL boolean ok_to_throw(shotlimit_p) int *shotlimit_p; /* (see dothrow()) */ { /* kludge to work around parse()'s pre-decrement of `multi' */ *shotlimit_p = (multi || save_cm) ? multi + 1 : 0; multi = 0; /* reset; it's been used up */ if (notake(youmonst.data)) { You("are physically incapable of throwing or shooting anything."); return FALSE; } else if (nohands(youmonst.data)) { You_cant("throw or shoot without hands."); /* not body_part(HAND) */ return FALSE; /*[what about !freehand(), aside from cursed missile launcher?]*/ } if (check_capacity((char *) 0)) return FALSE; return TRUE; } /* t command - throw */ int dothrow() { register struct obj *obj; int shotlimit; /* * Since some characters shoot multiple missiles at one time, * allow user to specify a count prefix for 'f' or 't' to limit * number of items thrown (to avoid possibly hitting something * behind target after killing it, or perhaps to conserve ammo). * * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)'' * and took 3 turns. Now it means ``t(shoot at most 3 missiles)''. * * [3.6.0: shot count setup has been moved into ok_to_throw().] */ if (!ok_to_throw(&shotlimit)) return 0; obj = getobj(uslinging() ? bullets : toss_objs, "throw"); /* it is also possible to throw food */ /* (or jewels, or iron balls... ) */ return obj ? throw_obj(obj, shotlimit) : 0; } /* KMH -- Automatically fill quiver */ /* Suggested by Jeffrey Bay */ static void autoquiver() { struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0; if (uquiver) return; /* Scan through the inventory */ for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->owornmask || otmp->oartifact || !otmp->dknown) { ; /* Skip it */ } else if (otmp->otyp == ROCK /* seen rocks or known flint or known glass */ || (otmp->otyp == FLINT && objects[otmp->otyp].oc_name_known) || (otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS && objects[otmp->otyp].oc_name_known)) { if (uslinging()) oammo = otmp; else if (ammo_and_launcher(otmp, uswapwep)) altammo = otmp; else if (!omisc) omisc = otmp; } else if (otmp->oclass == GEM_CLASS) { ; /* skip non-rock gems--they're ammo but player has to select them explicitly */ } else if (is_ammo(otmp)) { if (ammo_and_launcher(otmp, uwep)) /* Ammo matched with launcher (bow+arrow, crossbow+bolt) */ oammo = otmp; else if (ammo_and_launcher(otmp, uswapwep)) altammo = otmp; else /* Mismatched ammo (no better than an ordinary weapon) */ omisc = otmp; } else if (is_missile(otmp)) { /* Missile (dart, shuriken, etc.) */ omissile = otmp; } else if (otmp->oclass == WEAPON_CLASS && throwing_weapon(otmp)) { /* Ordinary weapon */ if (objects[otmp->otyp].oc_skill == P_DAGGER && !omissile) omissile = otmp; else omisc = otmp; } } /* Pick the best choice */ if (oammo) setuqwep(oammo); else if (omissile) setuqwep(omissile); else if (altammo) setuqwep(altammo); else if (omisc) setuqwep(omisc); return; } /* f command -- fire: throw from the quiver */ int dofire() { int shotlimit; struct obj *obj; /* * Same as dothrow(), except we use quivered missile instead * of asking what to throw/shoot. * * If quiver is empty, we use autoquiver to fill it when the * corresponding option is on. If the option is off or if * autoquiver doesn't select anything, we ask what to throw. * For the last, if player's response is a stack, we put * that stack into quiver slot provided it's not wielded. */ if (!ok_to_throw(&shotlimit)) return 0; if ((obj = uquiver) == 0) { if (!flags.autoquiver) { You("have no ammunition readied."); } else { autoquiver(); if ((obj = uquiver) == 0) You("have nothing appropriate for your quiver."); } /* if autoquiver is disabled or has failed, prompt for missile; fill quiver with it if it's not wielded */ if (!obj) { obj = getobj(uslinging() ? bullets : toss_objs, "throw"); /* Q command doesn't allow gold in quiver */ if (obj && !obj->owornmask && obj->oclass != COIN_CLASS) setuqwep(obj); /* demi-autoquiver */ } /* give feedback if quiver has now been filled */ if (uquiver) { uquiver->owornmask &= ~W_QUIVER; /* less verbose */ prinv("You ready:", uquiver, 0L); uquiver->owornmask |= W_QUIVER; } } return obj ? throw_obj(obj, shotlimit) : 0; } /* if in midst of multishot shooting/throwing, stop early */ void endmultishot(verbose) boolean verbose; { if (m_shot.i < m_shot.n) { if (verbose && !context.mon_moving) { You("stop %s after the %d%s %s.", m_shot.s ? "firing" : "throwing", m_shot.i, ordin(m_shot.i), m_shot.s ? "shot" : "toss"); } m_shot.n = m_shot.i; /* make current shot be the last */ } } /* * Object hits floor at hero's feet. Called from drop() and throwit(). */ void hitfloor(obj) register struct obj *obj; { if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) { dropy(obj); return; } if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); else pline("%s hit%s the %s.", Doname2(obj), (obj->quan == 1L) ? "s" : "", surface(u.ux, u.uy)); if (hero_breaks(obj, u.ux, u.uy, TRUE)) return; if (ship_object(obj, u.ux, u.uy, FALSE)) return; dropz(obj, TRUE); } /* * Walk a path from src_cc to dest_cc, calling a proc for each location * except the starting one. If the proc returns FALSE, stop walking * and return FALSE. If stopped early, dest_cc will be the location * before the failed callback. */ boolean walk_path(src_cc, dest_cc, check_proc, arg) coord *src_cc; coord *dest_cc; boolean FDECL((*check_proc), (genericptr_t, int, int)); genericptr_t arg; { int x, y, dx, dy, x_change, y_change, err, i, prev_x, prev_y; boolean keep_going = TRUE; /* Use Bresenham's Line Algorithm to walk from src to dest */ dx = dest_cc->x - src_cc->x; dy = dest_cc->y - src_cc->y; prev_x = x = src_cc->x; prev_y = y = src_cc->y; if (dx < 0) { x_change = -1; dx = -dx; } else x_change = 1; if (dy < 0) { y_change = -1; dy = -dy; } else y_change = 1; i = err = 0; if (dx < dy) { while (i++ < dy) { prev_x = x; prev_y = y; y += y_change; err += dx << 1; if (err > dy) { x += x_change; err -= dy << 1; } /* check for early exit condition */ if (!(keep_going = (*check_proc)(arg, x, y))) break; } } else { while (i++ < dx) { prev_x = x; prev_y = y; x += x_change; err += dy << 1; if (err > dx) { y += y_change; err -= dx << 1; } /* check for early exit condition */ if (!(keep_going = (*check_proc)(arg, x, y))) break; } } if (keep_going) return TRUE; /* successful */ dest_cc->x = prev_x; dest_cc->y = prev_y; return FALSE; } /* * Single step for the hero flying through the air from jumping, flying, * etc. Called from hurtle() and jump() via walk_path(). We expect the * argument to be a pointer to an integer -- the range -- which is * used in the calculation of points off if we hit something. * * Bumping into monsters won't cause damage but will wake them and make * them angry. Auto-pickup isn't done, since you don't have control over * your movements at the time. * * Possible additions/changes: * o really attack monster if we hit one * o set stunned if we hit a wall or door * o reset nomul when we stop * o creepy feeling if pass through monster (if ever implemented...) * o bounce off walls * o let jumps go over boulders */ boolean hurtle_step(arg, x, y) genericptr_t arg; int x, y; { int ox, oy, *range = (int *) arg; struct obj *obj; struct monst *mon; boolean may_pass = TRUE; struct trap *ttmp; int dmg = 0; if (!isok(x, y)) { You_feel("the spirits holding you back."); return FALSE; } else if (!in_out_region(x, y)) { return FALSE; } else if (*range == 0) { return FALSE; /* previous step wants to stop now */ } if (!Passes_walls || !(may_pass = may_passwall(x, y))) { if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) { const char *s; pline("Ouch!"); if (IS_TREE(levl[x][y].typ)) s = "bumping into a tree"; else if (IS_ROCK(levl[x][y].typ)) s = "bumping into a wall"; else s = "bumping into a door"; dmg = rnd(2 + *range); losehp(Maybe_Half_Phys(dmg), s, KILLED_BY); wake_nearto(x,y, 10); return FALSE; } if (levl[x][y].typ == IRONBARS) { You("crash into some iron bars. Ouch!"); dmg = rnd(2 + *range); losehp(Maybe_Half_Phys(dmg), "crashing into iron bars", KILLED_BY); wake_nearto(x,y, 20); return FALSE; } if ((obj = sobj_at(BOULDER, x, y)) != 0) { You("bump into a %s. Ouch!", xname(obj)); dmg = rnd(2 + *range); losehp(Maybe_Half_Phys(dmg), "bumping into a boulder", KILLED_BY); wake_nearto(x,y, 10); return FALSE; } if (!may_pass) { /* did we hit a no-dig non-wall position? */ You("smack into something!"); dmg = rnd(2 + *range); losehp(Maybe_Half_Phys(dmg), "touching the edge of the universe", KILLED_BY); wake_nearto(x,y, 10); return FALSE; } if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y) && bad_rock(youmonst.data, x, u.uy)) { boolean too_much = (invent && (inv_weight() + weight_cap() > 600)); /* Move at a diagonal. */ if (bigmonst(youmonst.data) || too_much) { You("%sget forcefully wedged into a crevice.", too_much ? "and all your belongings " : ""); dmg = rnd(2 + *range); losehp(Maybe_Half_Phys(dmg), "wedging into a narrow crevice", KILLED_BY); wake_nearto(x,y, 10); return FALSE; } } } if ((mon = m_at(x, y)) != 0) { You("bump into %s.", a_monnam(mon)); wakeup(mon); wake_nearto(x,y, 10); return FALSE; } if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y) && bad_rock(youmonst.data, x, u.uy)) { /* Move at a diagonal. */ if (Sokoban) { You("come to an abrupt halt!"); return FALSE; } } ox = u.ux; oy = u.uy; u_on_newpos(x, y); /* set u., u.usteed->; cliparound(); */ newsym(ox, oy); /* update old position */ vision_recalc(1); /* update for new position */ flush_screen(1); /* FIXME: * Each trap should really trigger on the recoil if * it would trigger during normal movement. However, * not all the possible side-effects of this are * tested [as of 3.4.0] so we trigger those that * we have tested, and offer a message for the * ones that we have not yet tested. */ if ((ttmp = t_at(x, y)) != 0) { if (ttmp->ttyp == MAGIC_PORTAL) { dotrap(ttmp, 0); return FALSE; } else if (ttmp->ttyp == VIBRATING_SQUARE) { pline("The ground vibrates as you pass it."); dotrap(ttmp, 0); /* doesn't print messages */ } else if (ttmp->ttyp == FIRE_TRAP) { dotrap(ttmp, 0); } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) && Sokoban) { /* Air currents overcome the recoil */ dotrap(ttmp, 0); *range = 0; return TRUE; } else { if (ttmp->tseen) You("pass right over %s.", an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation)); } } if (--*range < 0) /* make sure our range never goes negative */ *range = 0; if (*range != 0) delay_output(); return TRUE; } STATIC_OVL boolean mhurtle_step(arg, x, y) genericptr_t arg; int x, y; { struct monst *mon = (struct monst *) arg; /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially * rather than just stopping before. */ if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) { remove_monster(mon->mx, mon->my); newsym(mon->mx, mon->my); place_monster(mon, x, y); newsym(mon->mx, mon->my); set_apparxy(mon); (void) mintrap(mon); return TRUE; } return FALSE; } /* * The player moves through the air for a few squares as a result of * throwing or kicking something. * * dx and dy should be the direction of the hurtle, not of the original * kick or throw and be only. */ void hurtle(dx, dy, range, verbose) int dx, dy, range; boolean verbose; { coord uc, cc; /* The chain is stretched vertically, so you shouldn't be able to move * very far diagonally. The premise that you should be able to move one * spot leads to calculations that allow you to only move one spot away * from the ball, if you are levitating over the ball, or one spot * towards the ball, if you are at the end of the chain. Rather than * bother with all of that, assume that there is no slack in the chain * for diagonal movement, give the player a message and return. */ if (Punished && !carried(uball)) { You_feel("a tug from the iron ball."); nomul(0); return; } else if (u.utrap) { You("are anchored by the %s.", u.utraptype == TT_WEB ? "web" : u.utraptype == TT_LAVA ? "lava" : u.utraptype == TT_INFLOOR ? surface(u.ux, u.uy) : u.utraptype == TT_BURIEDBALL ? "buried ball" : "trap"); nomul(0); return; } /* make sure dx and dy are [-1,0,1] */ dx = sgn(dx); dy = sgn(dy); if (!range || (!dx && !dy) || u.ustuck) return; /* paranoia */ nomul(-range); multi_reason = "moving through the air"; nomovemsg = ""; /* it just happens */ if (verbose) You("%s in the opposite direction.", range > 1 ? "hurtle" : "float"); /* if we're in the midst of shooting multiple projectiles, stop */ endmultishot(TRUE); sokoban_guilt(); uc.x = u.ux; uc.y = u.uy; /* this setting of cc is only correct if dx and dy are [-1,0,1] only */ cc.x = u.ux + (dx * range); cc.y = u.uy + (dy * range); (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range); } /* Move a monster through the air for a few squares. */ void mhurtle(mon, dx, dy, range) struct monst *mon; int dx, dy, range; { coord mc, cc; /* At the very least, debilitate the monster */ mon->movement = 0; mon->mstun = 1; /* Is the monster stuck or too heavy to push? * (very large monsters have too much inertia, even floaters and flyers) */ if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped) return; /* Make sure dx and dy are [-1,0,1] */ dx = sgn(dx); dy = sgn(dy); if (!range || (!dx && !dy)) return; /* paranoia */ /* don't let grid bugs be hurtled diagonally */ if (dx && dy && NODIAG(monsndx(mon->data))) return; /* Send the monster along the path */ mc.x = mon->mx; mc.y = mon->my; cc.x = mon->mx + (dx * range); cc.y = mon->my + (dy * range); (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t) mon); return; } STATIC_OVL void check_shop_obj(obj, x, y, broken) struct obj *obj; xchar x, y; boolean broken; { struct monst *shkp = shop_keeper(*u.ushops); if (!shkp) return; if (broken || !costly_spot(x, y) || *in_rooms(x, y, SHOPBASE) != *u.ushops) { /* thrown out of a shop or into a different shop */ if (is_unpaid(obj)) (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful, FALSE); if (broken) obj->no_charge = 1; } else { if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) { if (is_unpaid(obj)) subfrombill(obj, shkp); else if (x != shkp->mx || y != shkp->my) sellobj(obj, x, y); } } } /* * Hero tosses an object upwards with appropriate consequences. * * Returns FALSE if the object is gone. */ STATIC_OVL boolean toss_up(obj, hitsroof) struct obj *obj; boolean hitsroof; { const char *action; boolean petrifier = ((obj->otyp == EGG || obj->otyp == CORPSE) && touch_petrifies(&mons[obj->corpsenm])); /* note: obj->quan == 1 */ if (!has_ceiling(&u.uz)) { action = "flies up into"; /* into "the sky" or "the water above" */ } else if (hitsroof) { if (breaktest(obj)) { pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy)); breakmsg(obj, !Blind); breakobj(obj, u.ux, u.uy, TRUE, TRUE); return FALSE; } action = "hits"; } else { action = "almost hits"; } pline("%s %s the %s, then falls back on top of your %s.", Doname2(obj), action, ceiling(u.ux, u.uy), body_part(HEAD)); /* object now hits you */ if (obj->oclass == POTION_CLASS) { potionhit(&youmonst, obj, TRUE); } else if (breaktest(obj)) { int otyp = obj->otyp; int blindinc; /* need to check for blindness result prior to destroying obj */ blindinc = ((otyp == CREAM_PIE || otyp == BLINDING_VENOM) /* AT_WEAP is ok here even if attack type was AT_SPIT */ && can_blnd(&youmonst, &youmonst, AT_WEAP, obj)) ? rnd(25) : 0; breakmsg(obj, !Blind); breakobj(obj, u.ux, u.uy, TRUE, TRUE); obj = 0; /* it's now gone */ switch (otyp) { case EGG: if (petrifier && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { /* egg ends up "all over your face"; perhaps visored helmet should still save you here */ if (uarmh) Your("%s fails to protect you.", helm_simple_name(uarmh)); goto petrify; } case CREAM_PIE: case BLINDING_VENOM: pline("You've got it all over your %s!", body_part(FACE)); if (blindinc) { if (otyp == BLINDING_VENOM && !Blind) pline("It blinds you!"); u.ucreamed += blindinc; make_blinded(Blinded + (long) blindinc, FALSE); if (!Blind) Your1(vision_clears); } break; default: break; } return FALSE; } else { /* neither potion nor other breaking object */ boolean less_damage = uarmh && is_metallic(uarmh), artimsg = FALSE; int dmg = dmgval(obj, &youmonst); if (obj->oartifact) /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */ artimsg = artifact_hit((struct monst *) 0, &youmonst, obj, &dmg, rn1(18, 2)); if (!dmg) { /* probably wasn't a weapon; base damage on weight */ dmg = (int) obj->owt / 100; if (dmg < 1) dmg = 1; else if (dmg > 6) dmg = 6; if (youmonst.data == &mons[PM_SHADE] && objects[obj->otyp].oc_material != SILVER) dmg = 0; } if (dmg > 1 && less_damage) dmg = 1; if (dmg > 0) dmg += u.udaminc; if (dmg < 0) dmg = 0; /* beware negative rings of increase damage */ dmg = Maybe_Half_Phys(dmg); if (uarmh) { if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) { if (!artimsg) pline("Fortunately, you are wearing a hard helmet."); /* helmet definitely protects you when it blocks petrification */ } else if (!petrifier) { if (flags.verbose) Your("%s does not protect you.", helm_simple_name(uarmh)); } } else if (petrifier && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { petrify: killer.format = KILLED_BY; Strcpy(killer.name, "elementary physics"); /* "what goes up..." */ You("turn to stone."); if (obj) dropy(obj); /* bypass most of hitfloor() */ thrownobj = 0; /* now either gone or on floor */ done(STONING); return obj ? TRUE : FALSE; } hitfloor(obj); thrownobj = 0; losehp(Maybe_Half_Phys(dmg), "falling object", KILLED_BY_AN); } return TRUE; } /* return true for weapon meant to be thrown; excludes ammo */ STATIC_OVL boolean throwing_weapon(obj) struct obj *obj; { return (boolean) (is_missile(obj) || is_spear(obj) /* daggers and knife (excludes scalpel) */ || (is_blade(obj) && !is_sword(obj) && (objects[obj->otyp].oc_dir & PIERCE)) /* special cases [might want to add AXE] */ || obj->otyp == WAR_HAMMER || obj->otyp == AKLYS); } /* the currently thrown object is returning to you (not for boomerangs) */ STATIC_OVL void sho_obj_return_to_u(obj) struct obj *obj; { /* might already be our location (bounced off a wall) */ if (bhitpos.x != u.ux || bhitpos.y != u.uy) { int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy; tmp_at(DISP_FLASH, obj_to_glyph(obj)); while (x != u.ux || y != u.uy) { tmp_at(x, y); delay_output(); x -= u.dx; y -= u.dy; } tmp_at(DISP_END, 0); } } /* throw an object, NB: obj may be consumed in the process */ void throwit(obj, wep_mask, twoweap) struct obj *obj; long wep_mask; /* used to re-equip returning boomerang */ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ { register struct monst *mon; register int range, urange; boolean crossbowing, impaired = (Confusion || Stunned || Blind || Hallucination || Fumbling); notonhead = FALSE; /* reset potentially stale value */ if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) { boolean slipok = TRUE; if (ammo_and_launcher(obj, uwep)) pline("%s!", Tobjnam(obj, "misfire")); else { /* only slip if it's greased or meant to be thrown */ if (obj->greased || throwing_weapon(obj)) /* BUG: this message is grammatically incorrect if obj has a plural name; greased gloves or boots for instance. */ pline("%s as you throw it!", Tobjnam(obj, "slip")); else slipok = FALSE; } if (slipok) { u.dx = rn2(3) - 1; u.dy = rn2(3) - 1; if (!u.dx && !u.dy) u.dz = 1; impaired = TRUE; } } if ((u.dx || u.dy || (u.dz < 1)) && calc_capacity((int) obj->owt) > SLT_ENCUMBER && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) : (u.uhp < 10 && u.uhp != u.uhpmax)) && obj->owt > (unsigned) ((Upolyd ? u.mh : u.uhp) * 2) && !Is_airlevel(&u.uz)) { You("have so little stamina, %s drops from your grasp.", the(xname(obj))); exercise(A_CON, FALSE); u.dx = u.dy = 0; u.dz = 1; } thrownobj = obj; thrownobj->was_thrown = 1; if (u.uswallow) { mon = u.ustuck; bhitpos.x = mon->mx; bhitpos.y = mon->my; } else if (u.dz) { if (u.dz < 0 && Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR && !impaired) { pline("%s the %s and returns to your hand!", Tobjnam(obj, "hit"), ceiling(u.ux, u.uy)); obj = addinv(obj); (void) encumber_msg(); setuwep(obj); u.twoweap = twoweap; } else if (u.dz < 0) { (void) toss_up(obj, rn2(5) && !Underwater); } else if (u.dz > 0 && u.usteed && obj->oclass == POTION_CLASS && rn2(6)) { /* alternative to prayer or wand of opening/spell of knock for dealing with cursed saddle: throw holy water > */ potionhit(u.usteed, obj, TRUE); } else { hitfloor(obj); } thrownobj = (struct obj *) 0; return; } else if (obj->otyp == BOOMERANG && !Underwater) { if (Is_airlevel(&u.uz) || Levitation) hurtle(-u.dx, -u.dy, 1, TRUE); mon = boomhit(obj, u.dx, u.dy); if (mon == &youmonst) { /* the thing was caught */ exercise(A_DEX, TRUE); obj = addinv(obj); (void) encumber_msg(); if (wep_mask && !(obj->owornmask & wep_mask)) { setworn(obj, wep_mask); u.twoweap = twoweap; } thrownobj = (struct obj *) 0; return; } } else { /* crossbow range is independent of strength */ crossbowing = (ammo_and_launcher(obj, uwep) && weapon_type(uwep) == P_CROSSBOW); urange = (crossbowing ? 18 : (int) ACURRSTR) / 2; /* balls are easy to throw or at least roll; * also, this insures the maximum range of a ball is greater * than 1, so the effects from throwing attached balls are * actually possible */ if (obj->otyp == HEAVY_IRON_BALL) range = urange - (int) (obj->owt / 100); else range = urange - (int) (obj->owt / 40); if (obj == uball) { if (u.ustuck) range = 1; else if (range >= 5) range = 5; } if (range < 1) range = 1; if (is_ammo(obj)) { if (ammo_and_launcher(obj, uwep)) { if (crossbowing) range = BOLT_LIM; else range++; } else if (obj->oclass != GEM_CLASS) range /= 2; } if (Is_airlevel(&u.uz) || Levitation) { /* action, reaction... */ urange -= range; if (urange < 1) urange = 1; range -= urange; if (range < 1) range = 1; } if (obj->otyp == BOULDER) range = 20; /* you must be giant */ else if (obj->oartifact == ART_MJOLLNIR) range = (range + 1) / 2; /* it's heavy */ else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR) range = 1; if (Underwater) range = 1; mon = bhit(u.dx, u.dy, range, THROWN_WEAPON, (int FDECL((*), (MONST_P, OBJ_P))) 0, (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj); thrownobj = obj; /* obj may be null now */ /* have to do this after bhit() so u.ux & u.uy are correct */ if (Is_airlevel(&u.uz) || Levitation) hurtle(-u.dx, -u.dy, urange, TRUE); if (!obj) return; } if (mon) { boolean obj_gone; if (mon->isshk && obj->where == OBJ_MINVENT && obj->ocarry == mon) { thrownobj = (struct obj *) 0; return; /* alert shk caught it */ } (void) snuff_candle(obj); notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my); obj_gone = thitmonst(mon, obj); /* Monster may have been tamed; this frees old mon */ mon = m_at(bhitpos.x, bhitpos.y); /* [perhaps this should be moved into thitmonst or hmon] */ if (mon && mon->isshk && (!inside_shop(u.ux, u.uy) || !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops))) hot_pursuit(mon); if (obj_gone) thrownobj = 0; } if (!thrownobj) { ; /* missile has already been handled */ } else if (u.uswallow) { /* ball is not picked up by monster */ if (obj != uball) (void) mpickobj(u.ustuck, obj); thrownobj = (struct obj *) 0; } else { /* the code following might become part of dropy() */ if (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE) && rn2(100)) { /* we must be wearing Gauntlets of Power to get here */ sho_obj_return_to_u(obj); /* display its flight */ if (!impaired && rn2(100)) { pline("%s to your hand!", Tobjnam(obj, "return")); obj = addinv(obj); (void) encumber_msg(); setuwep(obj); u.twoweap = twoweap; if (cansee(bhitpos.x, bhitpos.y)) newsym(bhitpos.x, bhitpos.y); } else { int dmg = rn2(2); if (!dmg) { pline(Blind ? "%s lands %s your %s." : "%s back to you, landing %s your %s.", Blind ? Something : Tobjnam(obj, "return"), Levitation ? "beneath" : "at", makeplural(body_part(FOOT))); } else { dmg += rnd(3); pline(Blind ? "%s your %s!" : "%s back toward you, hitting your %s!", Tobjnam(obj, Blind ? "hit" : "fly"), body_part(ARM)); (void) artifact_hit((struct monst *) 0, &youmonst, obj, &dmg, 0); losehp(Maybe_Half_Phys(dmg), killer_xname(obj), KILLED_BY); } if (ship_object(obj, u.ux, u.uy, FALSE)) { thrownobj = (struct obj *) 0; return; } dropy(obj); } thrownobj = (struct obj *) 0; return; } if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj)) { tmp_at(DISP_FLASH, obj_to_glyph(obj)); tmp_at(bhitpos.x, bhitpos.y); delay_output(); tmp_at(DISP_END, 0); breakmsg(obj, cansee(bhitpos.x, bhitpos.y)); breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE); thrownobj = (struct obj *) 0; return; } if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall")) { thrownobj = (struct obj *) 0; return; } obj_no_longer_held(obj); if (mon && mon->isshk && is_pick(obj)) { if (cansee(bhitpos.x, bhitpos.y)) pline("%s snatches up %s.", Monnam(mon), the(xname(obj))); if (*u.ushops || obj->unpaid) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); (void) mpickobj(mon, obj); /* may merge and free obj */ thrownobj = (struct obj *) 0; return; } (void) snuff_candle(obj); if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) { thrownobj = (struct obj *) 0; return; } thrownobj = (struct obj *) 0; place_object(obj, bhitpos.x, bhitpos.y); /* container contents might break; do so before turning ownership of thrownobj over to shk (container_impact_dmg handles item already owned by shop) */ if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ)) /* is spot where you initiated throw, not bhitpos */ container_impact_dmg(obj, u.ux, u.uy); /* charge for items thrown out of shop; shk takes possession for items thrown into one */ if ((*u.ushops || obj->unpaid) && obj != uball) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); stackobj(obj); if (obj == uball) drop_ball(bhitpos.x, bhitpos.y); if (cansee(bhitpos.x, bhitpos.y)) newsym(bhitpos.x, bhitpos.y); if (obj_sheds_light(obj)) vision_full_recalc = 1; } } /* an object may hit a monster; various factors adjust the chance of hitting */ int omon_adj(mon, obj, mon_notices) struct monst *mon; struct obj *obj; boolean mon_notices; { int tmp = 0; /* size of target affects the chance of hitting */ tmp += (mon->data->msize - MZ_MEDIUM); /* -2..+5 */ /* sleeping target is more likely to be hit */ if (mon->msleeping) { tmp += 2; if (mon_notices) mon->msleeping = 0; } /* ditto for immobilized target */ if (!mon->mcanmove || !mon->data->mmove) { tmp += 4; if (mon_notices && mon->data->mmove && !rn2(10)) { mon->mcanmove = 1; mon->mfrozen = 0; } } /* some objects are more likely to hit than others */ switch (obj->otyp) { case HEAVY_IRON_BALL: if (obj != uball) tmp += 2; break; case BOULDER: tmp += 6; break; default: if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) tmp += hitval(obj, mon); break; } return tmp; } /* thrown object misses target monster */ STATIC_OVL void tmiss(obj, mon, maybe_wakeup) struct obj *obj; struct monst *mon; boolean maybe_wakeup; { const char *missile = mshot_xname(obj); /* If the target can't be seen or doesn't look like a valid target, avoid "the arrow misses it," or worse, "the arrows misses the mimic." An attentive player will still notice that this is different from an arrow just landing short of any target (no message in that case), so will realize that there is a valid target here anyway. */ if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER)) pline("%s %s.", The(missile), otense(obj, "miss")); else miss(missile, mon); if (maybe_wakeup && !rn2(3)) wakeup(mon); return; } #define quest_arti_hits_leader(obj, mon) \ (obj->oartifact && is_quest_artifact(obj) \ && mon->m_id == quest_status.leader_m_id) /* * Object thrown by player arrives at monster's location. * Return 1 if obj has disappeared or otherwise been taken care of, * 0 if caller must take care of it. * Also used for kicked objects and for polearms/grapnel applied at range. */ int thitmonst(mon, obj) register struct monst *mon; register struct obj *obj; /* thrownobj or kickedobj or uwep */ { register int tmp; /* Base chance to hit */ register int disttmp; /* distance modifier */ int otyp = obj->otyp, hmode; boolean guaranteed_hit = (u.uswallow && mon == u.ustuck); hmode = (obj == uwep) ? HMON_APPLIED : (obj == kickedobj) ? HMON_KICKED : HMON_THROWN; /* Differences from melee weapons: * * Dex still gives a bonus, but strength does not. * Polymorphed players lacking attacks may still throw. * There's a base -1 to hit. * No bonuses for fleeing or stunned targets (they don't dodge * melee blows as readily, but dodging arrows is hard anyway). * Not affected by traps, etc. * Certain items which don't in themselves do damage ignore tmp. * Distance and monster size affect chance to hit. */ tmp = -1 + Luck + find_mac(mon) + u.uhitinc + maybe_polyd(youmonst.data->mlevel, u.ulevel); if (ACURR(A_DEX) < 4) tmp -= 3; else if (ACURR(A_DEX) < 6) tmp -= 2; else if (ACURR(A_DEX) < 8) tmp -= 1; else if (ACURR(A_DEX) >= 14) tmp += (ACURR(A_DEX) - 14); /* Modify to-hit depending on distance; but keep it sane. * Polearms get a distance penalty even when wielded; it's * hard to hit at a distance. */ disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my); if (disttmp < -4) disttmp = -4; tmp += disttmp; /* gloves are a hindrance to proper use of bows */ if (uarmg && uwep && objects[uwep->otyp].oc_skill == P_BOW) { switch (uarmg->otyp) { case GAUNTLETS_OF_POWER: /* metal */ tmp -= 2; break; case GAUNTLETS_OF_FUMBLING: tmp -= 3; break; case LEATHER_GLOVES: case GAUNTLETS_OF_DEXTERITY: break; default: impossible("Unknown type of gloves (%d)", uarmg->otyp); break; } } tmp += omon_adj(mon, obj, TRUE); if (is_orc(mon->data) && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) tmp++; if (guaranteed_hit) { tmp += 1000; /* Guaranteed hit */ } if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) { if (mon->msleeping || !mon->mcanmove) { tmiss(obj, mon, FALSE); return 0; } else if (mon->mtame) { pline("%s catches and drops %s.", Monnam(mon), the(xname(obj))); return 0; } else { pline("%s catches %s.", Monnam(mon), the(xname(obj))); return gem_accept(mon, obj); } } /* don't make game unwinnable if naive player throws artifact at leader... (kicked artifact is ok too; HMON_APPLIED could occur if quest artifact polearm or grapnel ever gets added) */ if (hmode != HMON_APPLIED && quest_arti_hits_leader(obj, mon)) { /* not wakeup(), which angers non-tame monsters */ mon->msleeping = 0; mon->mstrategy &= ~STRAT_WAITMASK; if (mon->mcanmove) { pline("%s catches %s.", Monnam(mon), the(xname(obj))); if (mon->mpeaceful) { boolean next2u = monnear(mon, u.ux, u.uy); finish_quest(obj); /* acknowledge quest completion */ pline("%s %s %s back to you.", Monnam(mon), (next2u ? "hands" : "tosses"), the(xname(obj))); if (!next2u) sho_obj_return_to_u(obj); obj = addinv(obj); /* back into your inventory */ (void) encumber_msg(); } else { /* angry leader caught it and isn't returning it */ if (*u.ushops || obj->unpaid) /* not very likely... */ check_shop_obj(obj, mon->mx, mon->my, FALSE); (void) mpickobj(mon, obj); } return 1; /* caller doesn't need to place it */ } return 0; } if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { if (hmode == HMON_KICKED) { /* throwing adjustments and weapon skill bonus don't apply */ tmp -= (is_ammo(obj) ? 5 : 3); } else if (is_ammo(obj)) { if (!ammo_and_launcher(obj, uwep)) { tmp -= 4; } else { tmp += uwep->spe - greatest_erosion(uwep); tmp += weapon_hit_bonus(uwep); if (uwep->oartifact) tmp += spec_abon(uwep, mon); /* * Elves and Samurais are highly trained w/bows, * especially their own special types of bow. * Polymorphing won't make you a bow expert. */ if ((Race_if(PM_ELF) || Role_if(PM_SAMURAI)) && (!Upolyd || your_race(youmonst.data)) && objects[uwep->otyp].oc_skill == P_BOW) { tmp++; if (Race_if(PM_ELF) && uwep->otyp == ELVEN_BOW) tmp++; else if (Role_if(PM_SAMURAI) && uwep->otyp == YUMI) tmp++; } } } else { /* thrown non-ammo or applied polearm/grapnel */ if (otyp == BOOMERANG) /* arbitrary */ tmp += 4; else if (throwing_weapon(obj)) /* meant to be thrown */ tmp += 2; else if (obj == thrownobj) /* not meant to be thrown */ tmp -= 2; /* we know we're dealing with a weapon or weptool handled by WEAPON_SKILLS once ammo objects have been excluded */ tmp += weapon_hit_bonus(obj); } if (tmp >= rnd(20)) { if (hmode == HMON_APPLIED) u.uconduct.weaphit++; if (hmon(mon, obj, hmode)) { /* mon still alive */ cutworm(mon, bhitpos.x, bhitpos.y, obj); } exercise(A_DEX, TRUE); /* if hero is swallowed and projectile kills the engulfer, obj gets added to engulfer's inventory and then dropped, so we can't safely use that pointer anymore; it escapes the chance to be used up here... */ if (!thrownobj) return 1; /* projectiles other than magic stones sometimes disappear when thrown */ if (objects[otyp].oc_skill < P_NONE && objects[otyp].oc_skill > -P_BOOMERANG && !objects[otyp].oc_magic) { /* we were breaking 2/3 of everything unconditionally. * we still don't want anything to survive unconditionally, * but we need ammo to stay around longer on average. */ int broken, chance; chance = 3 + greatest_erosion(obj) - obj->spe; if (chance > 1) broken = rn2(chance); else broken = !rn2(4); if (obj->blessed && !rnl(4)) broken = 0; if (broken) { if (*u.ushops || obj->unpaid) check_shop_obj(obj, bhitpos.x, bhitpos.y, TRUE); obfree(obj, (struct obj *) 0); return 1; } } passive_obj(mon, obj, (struct attack *) 0); } else { tmiss(obj, mon, TRUE); if (hmode == HMON_APPLIED) wakeup(mon); } } else if (otyp == HEAVY_IRON_BALL) { exercise(A_STR, TRUE); if (tmp >= rnd(20)) { int was_swallowed = guaranteed_hit; exercise(A_DEX, TRUE); if (!hmon(mon, obj, hmode)) { /* mon killed */ if (was_swallowed && !u.uswallow && obj == uball) return 1; /* already did placebc() */ } } else { tmiss(obj, mon, TRUE); } } else if (otyp == BOULDER) { exercise(A_STR, TRUE); if (tmp >= rnd(20)) { exercise(A_DEX, TRUE); (void) hmon(mon, obj, hmode); } else { tmiss(obj, mon, TRUE); } } else if ((otyp == EGG || otyp == CREAM_PIE || otyp == BLINDING_VENOM || otyp == ACID_VENOM) && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) { (void) hmon(mon, obj, hmode); return 1; /* hmon used it up */ } else if (obj->oclass == POTION_CLASS && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) { potionhit(mon, obj, TRUE); return 1; } else if (befriend_with_obj(mon->data, obj) || (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) { if (tamedog(mon, obj)) { return 1; /* obj is gone */ } else { tmiss(obj, mon, FALSE); mon->msleeping = 0; mon->mstrategy &= ~STRAT_WAITMASK; } } else if (guaranteed_hit) { /* this assumes that guaranteed_hit is due to swallowing */ wakeup(mon); if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) { if (is_animal(u.ustuck->data)) { minstapetrify(u.ustuck, TRUE); /* Don't leave a cockatrice corpse available in a statue */ if (!u.uswallow) { delobj(obj); return 1; } } } pline("%s into %s %s.", Tobjnam(obj, "vanish"), s_suffix(mon_nam(mon)), is_animal(u.ustuck->data) ? "entrails" : "currents"); } else { tmiss(obj, mon, TRUE); } return 0; } STATIC_OVL int gem_accept(mon, obj) register struct monst *mon; register struct obj *obj; { char buf[BUFSZ]; boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type); boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE; int ret = 0; static NEARDATA const char nogood[] = " is not interested in your junk."; static NEARDATA const char acceptgift[] = " accepts your gift."; static NEARDATA const char maybeluck[] = " hesitatingly"; static NEARDATA const char noluck[] = " graciously"; static NEARDATA const char addluck[] = " gratefully"; Strcpy(buf, Monnam(mon)); mon->mpeaceful = 1; mon->mavenge = 0; /* object properly identified */ if (obj->dknown && objects[obj->otyp].oc_name_known) { if (is_gem) { if (is_buddy) { Strcat(buf, addluck); change_luck(5); } else { Strcat(buf, maybeluck); change_luck(rn2(7) - 3); } } else { Strcat(buf, nogood); goto nopick; } /* making guesses */ } else if (has_oname(obj) || objects[obj->otyp].oc_uname) { if (is_gem) { if (is_buddy) { Strcat(buf, addluck); change_luck(2); } else { Strcat(buf, maybeluck); change_luck(rn2(3) - 1); } } else { Strcat(buf, nogood); goto nopick; } /* value completely unknown to @ */ } else { if (is_gem) { if (is_buddy) { Strcat(buf, addluck); change_luck(1); } else { Strcat(buf, maybeluck); change_luck(rn2(3) - 1); } } else { Strcat(buf, noluck); } } Strcat(buf, acceptgift); if (*u.ushops || obj->unpaid) check_shop_obj(obj, mon->mx, mon->my, TRUE); (void) mpickobj(mon, obj); /* may merge and free obj */ ret = 1; nopick: if (!Blind) pline1(buf); if (!tele_restrict(mon)) (void) rloc(mon, TRUE); return ret; } /* * Comments about the restructuring of the old breaks() routine. * * There are now three distinct phases to object breaking: * breaktest() - which makes the check/decision about whether the * object is going to break. * breakmsg() - which outputs a message about the breakage, * appropriate for that particular object. Should * only be called after a positive breaktest(). * on the object and, if it going to be called, * it must be called before calling breakobj(). * Calling breakmsg() is optional. * breakobj() - which actually does the breakage and the side-effects * of breaking that particular object. This should * only be called after a positive breaktest() on the * object. * * Each of the above routines is currently static to this source module. * There are two routines callable from outside this source module which * perform the routines above in the correct sequence. * * hero_breaks() - called when an object is to be broken as a result * of something that the hero has done. (throwing it, * kicking it, etc.) * breaks() - called when an object is to be broken for some * reason other than the hero doing something to it. */ /* * The hero causes breakage of an object (throwing, dropping it, etc.) * Return 0 if the object didn't break, 1 if the object broke. */ int hero_breaks(obj, x, y, from_invent) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ boolean from_invent; /* thrown or dropped by player; maybe on shop bill */ { boolean in_view = Blind ? FALSE : (from_invent || cansee(x, y)); if (!breaktest(obj)) return 0; breakmsg(obj, in_view); breakobj(obj, x, y, TRUE, from_invent); return 1; } /* * The object is going to break for a reason other than the hero doing * something to it. * Return 0 if the object doesn't break, 1 if the object broke. */ int breaks(obj, x, y) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ { boolean in_view = Blind ? FALSE : cansee(x, y); if (!breaktest(obj)) return 0; breakmsg(obj, in_view); breakobj(obj, x, y, FALSE, FALSE); return 1; } void release_camera_demon(obj, x, y) struct obj *obj; xchar x, y; { struct monst *mtmp; if (!rn2(3) && (mtmp = makemon(&mons[rn2(3) ? PM_HOMUNCULUS : PM_IMP], x, y, NO_MM_FLAGS)) != 0) { if (canspotmon(mtmp)) pline("%s is released!", Hallucination ? An(rndmonnam(NULL)) : "The picture-painting demon"); mtmp->mpeaceful = !obj->cursed; set_malign(mtmp); } } /* * Unconditionally break an object. Assumes all resistance checks * and break messages have been delivered prior to getting here. */ void breakobj(obj, x, y, hero_caused, from_invent) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ boolean hero_caused; /* is this the hero's fault? */ boolean from_invent; { boolean fracture = FALSE; switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { case MIRROR: if (hero_caused) change_luck(-2); break; case POT_WATER: /* really, all potions */ obj->in_use = 1; /* in case it's fatal */ if (obj->otyp == POT_OIL && obj->lamplit) { explode_oil(obj, x, y); } else if (distu(x, y) <= 2) { if (!breathless(youmonst.data) || haseyes(youmonst.data)) { if (obj->otyp != POT_WATER) { if (!breathless(youmonst.data)) { /* [what about "familiar odor" when known?] */ You("smell a peculiar odor..."); } else { const char *eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); Your("%s %s.", eyes, vtense(eyes, "water")); } } potionbreathe(obj); } } /* monster breathing isn't handled... [yet?] */ break; case EXPENSIVE_CAMERA: release_camera_demon(obj, x, y); break; case EGG: /* breaking your own eggs is bad luck */ if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM) change_luck((schar) -min(obj->quan, 5L)); break; case BOULDER: case STATUE: /* caller will handle object disposition; we're just doing the shop theft handling */ fracture = TRUE; break; default: break; } if (hero_caused) { if (from_invent || obj->unpaid) { if (*u.ushops || obj->unpaid) check_shop_obj(obj, x, y, TRUE); } else if (!obj->no_charge && costly_spot(x, y)) { /* it is assumed that the obj is a floor-object */ char *o_shop = in_rooms(x, y, SHOPBASE); struct monst *shkp = shop_keeper(*o_shop); if (shkp) { /* (implies *o_shop != '\0') */ static NEARDATA long lastmovetime = 0L; static NEARDATA boolean peaceful_shk = FALSE; /* We want to base shk actions on her peacefulness at start of this turn, so that "simultaneous" multiple breakage isn't drastically worse than single breakage. (ought to be done via ESHK) */ if (moves != lastmovetime) peaceful_shk = shkp->mpeaceful; if (stolen_value(obj, x, y, peaceful_shk, FALSE) > 0L && (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy)) && moves != lastmovetime) make_angry_shk(shkp, x, y); lastmovetime = moves; } } } if (!fracture) delobj(obj); } /* * Check to see if obj is going to break, but don't actually break it. * Return 0 if the object isn't going to break, 1 if it is. */ boolean breaktest(obj) struct obj *obj; { if (obj_resists(obj, 1, 99)) return 0; if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact && obj->oclass != GEM_CLASS) return 1; switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { case EXPENSIVE_CAMERA: case POT_WATER: /* really, all potions */ case EGG: case CREAM_PIE: case MELON: case ACID_VENOM: case BLINDING_VENOM: return 1; default: return 0; } } STATIC_OVL void breakmsg(obj, in_view) struct obj *obj; boolean in_view; { const char *to_pieces; to_pieces = ""; switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { default: /* glass or crystal wand */ if (obj->oclass != WAND_CLASS) impossible("breaking odd object?"); case CRYSTAL_PLATE_MAIL: case LENSES: case MIRROR: case CRYSTAL_BALL: case EXPENSIVE_CAMERA: to_pieces = " into a thousand pieces"; /*FALLTHRU*/ case POT_WATER: /* really, all potions */ if (!in_view) You_hear("%s shatter!", something); else pline("%s shatter%s%s!", Doname2(obj), (obj->quan == 1L) ? "s" : "", to_pieces); break; case EGG: case MELON: pline("Splat!"); break; case CREAM_PIE: if (in_view) pline("What a mess!"); break; case ACID_VENOM: case BLINDING_VENOM: pline("Splash!"); break; } } STATIC_OVL int throw_gold(obj) struct obj *obj; { int range, odx, ody; register struct monst *mon; if (!u.dx && !u.dy && !u.dz) { You("cannot throw gold at yourself."); return 0; } freeinv(obj); if (u.uswallow) { pline(is_animal(u.ustuck->data) ? "%s in the %s's entrails." : "%s into %s.", "The money disappears", mon_nam(u.ustuck)); add_to_minv(u.ustuck, obj); return 1; } if (u.dz) { if (u.dz < 0 && !Is_airlevel(&u.uz) && !Underwater && !Is_waterlevel(&u.uz)) { pline_The("gold hits the %s, then falls back on top of your %s.", ceiling(u.ux, u.uy), body_part(HEAD)); /* some self damage? */ if (uarmh) pline("Fortunately, you are wearing %s!", an(helm_simple_name(uarmh))); } bhitpos.x = u.ux; bhitpos.y = u.uy; } else { /* consistent with range for normal objects */ range = (int) ((ACURRSTR) / 2 - obj->owt / 40); /* see if the gold has a place to move into */ odx = u.ux + u.dx; ody = u.uy + u.dy; if (!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) { bhitpos.x = u.ux; bhitpos.y = u.uy; } else { mon = bhit(u.dx, u.dy, range, THROWN_WEAPON, (int FDECL((*), (MONST_P, OBJ_P))) 0, (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj); if (!obj) return 1; /* object is gone */ if (mon) { if (ghitm(mon, obj)) /* was it caught? */ return 1; } else { if (ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) return 1; } } } if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall")) return 1; if (u.dz > 0) pline_The("gold hits the %s.", surface(bhitpos.x, bhitpos.y)); place_object(obj, bhitpos.x, bhitpos.y); if (*u.ushops) sellobj(obj, bhitpos.x, bhitpos.y); stackobj(obj); newsym(bhitpos.x, bhitpos.y); return 1; } /*dothrow.c*/ nethack-3.6.0/src/drawing.c0000664000076400007660000007104212620277605014536 0ustar paxedpaxed/* NetHack 3.6 drawing.c $NHDT-Date: 1447124657 2015/11/10 03:04:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) NetHack Development Team 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "tcap.h" /* Relevant header information in rm.h, objclass.h, and monsym.h. */ #ifdef C #undef C #endif #ifdef TEXTCOLOR #define C(n) n #else #define C(n) #endif struct symsetentry symset[NUM_GRAPHICS]; int currentgraphics = 0; nhsym showsyms[SYM_MAX] = DUMMY; /* symbols to be displayed */ nhsym l_syms[SYM_MAX] = DUMMY; /* loaded symbols */ nhsym r_syms[SYM_MAX] = DUMMY; /* rogue symbols */ nhsym warnsyms[WARNCOUNT] = DUMMY; /* the current warning display symbols */ const char invisexplain[] = "remembered, unseen, creature"; /* Default object class symbols. See objclass.h. * {symbol, name, explain} * name: used in object_detect(). * explain: used in do_look(). */ const struct class_sym def_oc_syms[MAXOCLASSES] = { { '\0', "", "" }, /* placeholder for the "random class" */ { ILLOBJ_SYM, "illegal objects", "strange object" }, { WEAPON_SYM, "weapons", "weapon" }, { ARMOR_SYM, "armor", "suit or piece of armor" }, { RING_SYM, "rings", "ring" }, { AMULET_SYM, "amulets", "amulet" }, { TOOL_SYM, "tools", "useful item (pick-axe, key, lamp...)" }, { FOOD_SYM, "food", "piece of food" }, { POTION_SYM, "potions", "potion" }, { SCROLL_SYM, "scrolls", "scroll" }, { SPBOOK_SYM, "spellbooks", "spellbook" }, { WAND_SYM, "wands", "wand" }, { GOLD_SYM, "coins", "pile of coins" }, { GEM_SYM, "rocks", "gem or rock" }, { ROCK_SYM, "large stones", "boulder or statue" }, { BALL_SYM, "iron balls", "iron ball" }, { CHAIN_SYM, "chains", "iron chain" }, { VENOM_SYM, "venoms", "splash of venom" } }; /* Default monster class symbols. See monsym.h. */ const struct class_sym def_monsyms[MAXMCLASSES] = { { '\0', "", "" }, { DEF_ANT, "", "ant or other insect" }, { DEF_BLOB, "", "blob" }, { DEF_COCKATRICE, "", "cockatrice" }, { DEF_DOG, "", "dog or other canine" }, { DEF_EYE, "", "eye or sphere" }, { DEF_FELINE, "", "cat or other feline" }, { DEF_GREMLIN, "", "gremlin" }, { DEF_HUMANOID, "", "humanoid" }, { DEF_IMP, "", "imp or minor demon" }, { DEF_JELLY, "", "jelly" }, { DEF_KOBOLD, "", "kobold" }, { DEF_LEPRECHAUN, "", "leprechaun" }, { DEF_MIMIC, "", "mimic" }, { DEF_NYMPH, "", "nymph" }, { DEF_ORC, "", "orc" }, { DEF_PIERCER, "", "piercer" }, { DEF_QUADRUPED, "", "quadruped" }, { DEF_RODENT, "", "rodent" }, { DEF_SPIDER, "", "arachnid or centipede" }, { DEF_TRAPPER, "", "trapper or lurker above" }, { DEF_UNICORN, "", "unicorn or horse" }, { DEF_VORTEX, "", "vortex" }, { DEF_WORM, "", "worm" }, { DEF_XAN, "", "xan or other mythical/fantastic insect" }, { DEF_LIGHT, "", "light" }, { DEF_ZRUTY, "", "zruty" }, { DEF_ANGEL, "", "angelic being" }, { DEF_BAT, "", "bat or bird" }, { DEF_CENTAUR, "", "centaur" }, { DEF_DRAGON, "", "dragon" }, { DEF_ELEMENTAL, "", "elemental" }, { DEF_FUNGUS, "", "fungus or mold" }, { DEF_GNOME, "", "gnome" }, { DEF_GIANT, "", "giant humanoid" }, { '\0', "", "invisible monster" }, { DEF_JABBERWOCK, "", "jabberwock" }, { DEF_KOP, "", "Keystone Kop" }, { DEF_LICH, "", "lich" }, { DEF_MUMMY, "", "mummy" }, { DEF_NAGA, "", "naga" }, { DEF_OGRE, "", "ogre" }, { DEF_PUDDING, "", "pudding or ooze" }, { DEF_QUANTMECH, "", "quantum mechanic" }, { DEF_RUSTMONST, "", "rust monster or disenchanter" }, { DEF_SNAKE, "", "snake" }, { DEF_TROLL, "", "troll" }, { DEF_UMBER, "", "umber hulk" }, { DEF_VAMPIRE, "", "vampire" }, { DEF_WRAITH, "", "wraith" }, { DEF_XORN, "", "xorn" }, { DEF_YETI, "", "apelike creature" }, { DEF_ZOMBIE, "", "zombie" }, { DEF_HUMAN, "", "human or elf" }, { DEF_GHOST, "", "ghost" }, { DEF_GOLEM, "", "golem" }, { DEF_DEMON, "", "major demon" }, { DEF_EEL, "", "sea monster" }, { DEF_LIZARD, "", "lizard" }, { DEF_WORM_TAIL, "", "long worm tail" }, { DEF_MIMIC_DEF, "", "mimic" }, }; const struct symdef def_warnsyms[WARNCOUNT] = { /* white warning */ { '0', "unknown creature causing you worry", C(CLR_WHITE) }, /* pink warning */ { '1', "unknown creature causing you concern", C(CLR_RED) }, /* red warning */ { '2', "unknown creature causing you anxiety", C(CLR_RED) }, /* ruby warning */ { '3', "unknown creature causing you disquiet", C(CLR_RED) }, /* purple warning */ { '4', "unknown creature causing you alarm", C(CLR_MAGENTA) }, /* black warning */ { '5', "unknown creature causing you dread", C(CLR_BRIGHT_MAGENTA) }, }; /* * Default screen symbols with explanations and colors. */ const struct symdef defsyms[MAXPCHARS] = { /* 0*/ { ' ', "dark part of a room", C(NO_COLOR) }, /* stone */ { '|', "wall", C(CLR_GRAY) }, /* vwall */ { '-', "wall", C(CLR_GRAY) }, /* hwall */ { '-', "wall", C(CLR_GRAY) }, /* tlcorn */ { '-', "wall", C(CLR_GRAY) }, /* trcorn */ { '-', "wall", C(CLR_GRAY) }, /* blcorn */ { '-', "wall", C(CLR_GRAY) }, /* brcorn */ { '-', "wall", C(CLR_GRAY) }, /* crwall */ { '-', "wall", C(CLR_GRAY) }, /* tuwall */ { '-', "wall", C(CLR_GRAY) }, /* tdwall */ /*10*/ { '|', "wall", C(CLR_GRAY) }, /* tlwall */ { '|', "wall", C(CLR_GRAY) }, /* trwall */ { '.', "doorway", C(CLR_GRAY) }, /* ndoor */ { '-', "open door", C(CLR_BROWN) }, /* vodoor */ { '|', "open door", C(CLR_BROWN) }, /* hodoor */ { '+', "closed door", C(CLR_BROWN) }, /* vcdoor */ { '+', "closed door", C(CLR_BROWN) }, /* hcdoor */ { '#', "iron bars", C(HI_METAL) }, /* bars */ { '#', "tree", C(CLR_GREEN) }, /* tree */ { '.', "floor of a room", C(CLR_GRAY) }, /* room */ /*20*/ { '.', "dark part of a room", C(CLR_BLACK) }, /* dark room */ { '#', "corridor", C(CLR_GRAY) }, /* dark corr */ { '#', "lit corridor", C(CLR_GRAY) }, /* lit corr (see mapglyph.c) */ { '<', "staircase up", C(CLR_GRAY) }, /* upstair */ { '>', "staircase down", C(CLR_GRAY) }, /* dnstair */ { '<', "ladder up", C(CLR_BROWN) }, /* upladder */ { '>', "ladder down", C(CLR_BROWN) }, /* dnladder */ { '_', "altar", C(CLR_GRAY) }, /* altar */ { '|', "grave", C(CLR_GRAY) }, /* grave */ { '\\', "opulent throne", C(HI_GOLD) }, /* throne */ /*30*/ { '#', "sink", C(CLR_GRAY) }, /* sink */ { '{', "fountain", C(CLR_BLUE) }, /* fountain */ { '}', "water", C(CLR_BLUE) }, /* pool */ { '.', "ice", C(CLR_CYAN) }, /* ice */ { '}', "molten lava", C(CLR_RED) }, /* lava */ { '.', "lowered drawbridge", C(CLR_BROWN) }, /* vodbridge */ { '.', "lowered drawbridge", C(CLR_BROWN) }, /* hodbridge */ { '#', "raised drawbridge", C(CLR_BROWN) }, /* vcdbridge */ { '#', "raised drawbridge", C(CLR_BROWN) }, /* hcdbridge */ { ' ', "air", C(CLR_CYAN) }, /* open air */ /*40*/ { '#', "cloud", C(CLR_GRAY) }, /* [part of] a cloud */ { '}', "water", C(CLR_BLUE) }, /* under water */ { '^', "arrow trap", C(HI_METAL) }, /* trap */ { '^', "dart trap", C(HI_METAL) }, /* trap */ { '^', "falling rock trap", C(CLR_GRAY) }, /* trap */ { '^', "squeaky board", C(CLR_BROWN) }, /* trap */ { '^', "bear trap", C(HI_METAL) }, /* trap */ { '^', "land mine", C(CLR_RED) }, /* trap */ { '^', "rolling boulder trap", C(CLR_GRAY) }, /* trap */ { '^', "sleeping gas trap", C(HI_ZAP) }, /* trap */ /*50*/ { '^', "rust trap", C(CLR_BLUE) }, /* trap */ { '^', "fire trap", C(CLR_ORANGE) }, /* trap */ { '^', "pit", C(CLR_BLACK) }, /* trap */ { '^', "spiked pit", C(CLR_BLACK) }, /* trap */ { '^', "hole", C(CLR_BROWN) }, /* trap */ { '^', "trap door", C(CLR_BROWN) }, /* trap */ { '^', "teleportation trap", C(CLR_MAGENTA) }, /* trap */ { '^', "level teleporter", C(CLR_MAGENTA) }, /* trap */ { '^', "magic portal", C(CLR_BRIGHT_MAGENTA) }, /* trap */ { '"', "web", C(CLR_GRAY) }, /* web */ /*60*/ { '^', "statue trap", C(CLR_GRAY) }, /* trap */ { '^', "magic trap", C(HI_ZAP) }, /* trap */ { '^', "anti-magic field", C(HI_ZAP) }, /* trap */ { '^', "polymorph trap", C(CLR_BRIGHT_GREEN) }, /* trap */ { '^', "vibrating square", C(CLR_YELLOW) }, /* trap */ { '|', "wall", C(CLR_GRAY) }, /* vbeam */ { '-', "wall", C(CLR_GRAY) }, /* hbeam */ { '\\', "wall", C(CLR_GRAY) }, /* lslant */ { '/', "wall", C(CLR_GRAY) }, /* rslant */ { '*', "", C(CLR_WHITE) }, /* dig beam */ { '!', "", C(CLR_WHITE) }, /* camera flash beam */ { ')', "", C(HI_WOOD) }, /* boomerang open left */ /*70*/ { '(', "", C(HI_WOOD) }, /* boomerang open right */ { '0', "", C(HI_ZAP) }, /* 4 magic shield symbols */ { '#', "", C(HI_ZAP) }, { '@', "", C(HI_ZAP) }, { '*', "", C(HI_ZAP) }, { '#', "poison cloud", C(CLR_BRIGHT_GREEN) }, /* part of a cloud */ { '?', "valid position", C(CLR_BRIGHT_GREEN) }, /* target position */ { '/', "", C(CLR_GREEN) }, /* swallow top left */ { '-', "", C(CLR_GREEN) }, /* swallow top center */ { '\\', "", C(CLR_GREEN) }, /* swallow top right */ /*80*/ { '|', "", C(CLR_GREEN) }, /* swallow middle left */ { '|', "", C(CLR_GREEN) }, /* swallow middle right */ { '\\', "", C(CLR_GREEN) }, /* swallow bottom left */ { '-', "", C(CLR_GREEN) }, /* swallow bottom center */ { '/', "", C(CLR_GREEN) }, /* swallow bottom right */ { '/', "", C(CLR_ORANGE) }, /* explosion top left */ { '-', "", C(CLR_ORANGE) }, /* explosion top center */ { '\\', "", C(CLR_ORANGE) }, /* explosion top right */ { '|', "", C(CLR_ORANGE) }, /* explosion middle left */ { ' ', "", C(CLR_ORANGE) }, /* explosion middle center*/ /*90*/ { '|', "", C(CLR_ORANGE) }, /* explosion middle right */ { '\\', "", C(CLR_ORANGE) }, /* explosion bottom left */ { '-', "", C(CLR_ORANGE) }, /* explosion bottom center*/ { '/', "", C(CLR_ORANGE) }, /* explosion bottom right */ }; /* default rogue level symbols */ static const uchar def_r_oc_syms[MAXOCLASSES] = { /* 0*/ '\0', ILLOBJ_SYM, WEAPON_SYM, ']', /* armor */ RING_SYM, /* 5*/ ',', /* amulet */ TOOL_SYM, ':', /* food */ POTION_SYM, SCROLL_SYM, /*10*/ SPBOOK_SYM, WAND_SYM, GEM_SYM, /* gold -- yes it's the same as gems */ GEM_SYM, ROCK_SYM, /*15*/ BALL_SYM, CHAIN_SYM, VENOM_SYM }; #undef C #ifdef TERMLIB void NDECL((*decgraphics_mode_callback)) = 0; /* set in tty_start_screen() */ #endif /* TERMLIB */ #ifdef PC9800 void NDECL((*ibmgraphics_mode_callback)) = 0; /* set in tty_start_screen() */ void NDECL((*ascgraphics_mode_callback)) = 0; /* set in tty_start_screen() */ #endif /* * Convert the given character to an object class. If the character is not * recognized, then MAXOCLASSES is returned. Used in detect.c, invent.c, * objnam.c, options.c, pickup.c, sp_lev.c, lev_main.c, and tilemap.c. */ int def_char_to_objclass(ch) char ch; { int i; for (i = 1; i < MAXOCLASSES; i++) if (ch == def_oc_syms[i].sym) break; return i; } /* * Convert a character into a monster class. This returns the _first_ * match made. If there are are no matches, return MAXMCLASSES. * Used in detect.c, options.c, read.c, sp_lev.c, and lev_main.c */ int def_char_to_monclass(ch) char ch; { int i; for (i = 1; i < MAXMCLASSES; i++) if (ch == def_monsyms[i].sym) break; return i; } /* * Explanations of the functions found below: * * init_symbols() * Sets the current display symbols, the * loadable symbols to the default NetHack * symbols, including the r_syms rogue level * symbols. This would typically be done * immediately after execution begins. Any * previously loaded external symbol sets are * discarded. * * switch_symbols(arg) * Called to swap in new current display symbols * (showsyms) from either the default symbols, * or from the loaded symbols. * * If (arg == 0) then showsyms are taken from * defsyms, def_oc_syms, and def_monsyms. * * If (arg != 0), which is the normal expected * usage, then showsyms are taken from the * adjustable display symbols found in l_syms. * l_syms may have been loaded from an external * symbol file by config file options or interactively * in the Options menu. * * assign_graphics(arg) * * This is used in the game core to toggle in and * out of other {rogue} level display modes. * * If arg is ROGUESET, this places the rogue level * symbols from r_syms into showsyms. * * If arg is PRIMARY, this places the symbols * from l_monsyms into showsyms. * * update_l_symset() * Update a member of the loadable (l_*) symbol set. * * update_r_symset() * Update a member of the rogue (r_*) symbol set. * */ void init_symbols() { init_l_symbols(); init_showsyms(); init_r_symbols(); } void update_bouldersym() { showsyms[SYM_BOULDER + SYM_OFF_X] = iflags.bouldersym; l_syms[SYM_BOULDER + SYM_OFF_X] = iflags.bouldersym; r_syms[SYM_BOULDER + SYM_OFF_X] = iflags.bouldersym; } void init_showsyms() { register int i; for (i = 0; i < MAXPCHARS; i++) showsyms[i + SYM_OFF_P] = defsyms[i].sym; for (i = 0; i < MAXOCLASSES; i++) showsyms[i + SYM_OFF_O] = def_oc_syms[i].sym; for (i = 0; i < MAXMCLASSES; i++) showsyms[i + SYM_OFF_M] = def_monsyms[i].sym; for (i = 0; i < WARNCOUNT; i++) showsyms[i + SYM_OFF_W] = def_warnsyms[i].sym; for (i = 0; i < MAXOTHER; i++) { if (i == SYM_BOULDER) showsyms[i + SYM_OFF_X] = iflags.bouldersym ? iflags.bouldersym : def_oc_syms[ROCK_CLASS].sym; else if (i == SYM_INVISIBLE) showsyms[i + SYM_OFF_X] = DEF_INVISIBLE; } } /* initialize defaults for the loadable symset */ void init_l_symbols() { register int i; for (i = 0; i < MAXPCHARS; i++) l_syms[i + SYM_OFF_P] = defsyms[i].sym; for (i = 0; i < MAXOCLASSES; i++) l_syms[i + SYM_OFF_O] = def_oc_syms[i].sym; for (i = 0; i < MAXMCLASSES; i++) l_syms[i + SYM_OFF_M] = def_monsyms[i].sym; for (i = 0; i < WARNCOUNT; i++) l_syms[i + SYM_OFF_W] = def_warnsyms[i].sym; for (i = 0; i < MAXOTHER; i++) { if (i == SYM_BOULDER) l_syms[i + SYM_OFF_X] = iflags.bouldersym ? iflags.bouldersym : def_oc_syms[ROCK_CLASS].sym; else if (i == SYM_INVISIBLE) l_syms[i + SYM_OFF_X] = DEF_INVISIBLE; } clear_symsetentry(PRIMARY, FALSE); } void init_r_symbols() { register int i; /* These are defaults that can get overwritten later by the roguesymbols option */ for (i = 0; i < MAXPCHARS; i++) r_syms[i + SYM_OFF_P] = defsyms[i].sym; r_syms[S_vodoor] = r_syms[S_hodoor] = r_syms[S_ndoor] = '+'; r_syms[S_upstair] = r_syms[S_dnstair] = '%'; for (i = 0; i < MAXOCLASSES; i++) r_syms[i + SYM_OFF_O] = def_r_oc_syms[i]; for (i = 0; i < MAXMCLASSES; i++) r_syms[i + SYM_OFF_M] = def_monsyms[i].sym; for (i = 0; i < WARNCOUNT; i++) r_syms[i + SYM_OFF_W] = def_warnsyms[i].sym; for (i = 0; i < MAXOTHER; i++) { if (i == SYM_BOULDER) r_syms[i + SYM_OFF_X] = iflags.bouldersym ? iflags.bouldersym : def_oc_syms[ROCK_CLASS].sym; else if (i == SYM_INVISIBLE) r_syms[i + SYM_OFF_X] = DEF_INVISIBLE; } clear_symsetentry(ROGUESET, FALSE); /* default on Rogue level is no color * but some symbol sets can override that */ symset[ROGUESET].nocolor = 1; } void assign_graphics(whichset) int whichset; { register int i; switch (whichset) { case ROGUESET: /* Adjust graphics display characters on Rogue levels */ for (i = 0; i < SYM_MAX; i++) showsyms[i] = r_syms[i]; #if defined(MSDOS) && defined(USE_TILES) if (iflags.grmode) tileview(FALSE); #endif currentgraphics = ROGUESET; break; case PRIMARY: default: for (i = 0; i < SYM_MAX; i++) showsyms[i] = l_syms[i]; #if defined(MSDOS) && defined(USE_TILES) if (iflags.grmode) tileview(TRUE); #endif currentgraphics = PRIMARY; break; } } void switch_symbols(nondefault) int nondefault; { register int i; if (nondefault) { for (i = 0; i < SYM_MAX; i++) showsyms[i] = l_syms[i]; #ifdef PC9800 if (SYMHANDLING(H_IBM) && ibmgraphics_mode_callback) (*ibmgraphics_mode_callback)(); else if (!symset[currentgraphics].name && ascgraphics_mode_callback) (*ascgraphics_mode_callback)(); #endif #ifdef TERMLIB if (SYMHANDLING(H_DEC) && decgraphics_mode_callback) (*decgraphics_mode_callback)(); #endif } else init_symbols(); } void update_l_symset(symp, val) struct symparse *symp; int val; { l_syms[symp->idx] = val; } void update_r_symset(symp, val) struct symparse *symp; int val; { r_syms[symp->idx] = val; } void clear_symsetentry(which_set, name_too) int which_set; boolean name_too; { if (symset[which_set].desc) free((genericptr_t) symset[which_set].desc); symset[which_set].desc = (char *) 0; symset[which_set].handling = H_UNK; symset[which_set].nocolor = 0; /* initialize restriction bits */ symset[which_set].primary = 0; symset[which_set].rogue = 0; if (name_too) { if (symset[which_set].name) free((genericptr_t) symset[which_set].name); symset[which_set].name = (char *) 0; } } /* * If you are adding code somewhere to be able to recognize * particular types of symset "handling", define a * H_XXX macro in include/rm.h and add the name * to this array at the matching offset. */ const char *known_handling[] = { "UNKNOWN", /* H_UNK */ "IBM", /* H_IBM */ "DEC", /* H_DEC */ (const char *) 0, }; /* * Accepted keywords for symset restrictions. * These can be virtually anything that you want to * be able to test in the code someplace. * Be sure to: * - add a corresponding Bitfield to the symsetentry struct in rm.h * - initialize the field to zero in parse_sym_line in the SYM_CONTROL * case 0 section of the idx switch. The location is prefaced with * with a comment stating "initialize restriction bits". * - set the value appropriately based on the index of your keyword * under the case 5 sections of the same SYM_CONTROL idx switches. * - add the field to clear_symsetentry() */ const char *known_restrictions[] = { "primary", "rogue", (const char *) 0, }; struct symparse loadsyms[] = { { SYM_CONTROL, 0, "start" }, { SYM_CONTROL, 0, "begin" }, { SYM_CONTROL, 1, "finish" }, { SYM_CONTROL, 2, "handling" }, { SYM_CONTROL, 3, "description" }, { SYM_CONTROL, 4, "color" }, { SYM_CONTROL, 4, "colour" }, { SYM_CONTROL, 5, "restrictions" }, { SYM_PCHAR, S_stone, "S_stone" }, { SYM_PCHAR, S_vwall, "S_vwall" }, { SYM_PCHAR, S_hwall, "S_hwall" }, { SYM_PCHAR, S_tlcorn, "S_tlcorn" }, { SYM_PCHAR, S_trcorn, "S_trcorn" }, { SYM_PCHAR, S_blcorn, "S_blcorn" }, { SYM_PCHAR, S_brcorn, "S_brcorn" }, { SYM_PCHAR, S_crwall, "S_crwall" }, { SYM_PCHAR, S_tuwall, "S_tuwall" }, { SYM_PCHAR, S_tdwall, "S_tdwall" }, { SYM_PCHAR, S_tlwall, "S_tlwall" }, { SYM_PCHAR, S_trwall, "S_trwall" }, { SYM_PCHAR, S_ndoor, "S_ndoor" }, { SYM_PCHAR, S_vodoor, "S_vodoor" }, { SYM_PCHAR, S_hodoor, "S_hodoor" }, { SYM_PCHAR, S_vcdoor, "S_vcdoor" }, { SYM_PCHAR, S_hcdoor, "S_hcdoor" }, { SYM_PCHAR, S_bars, "S_bars" }, { SYM_PCHAR, S_tree, "S_tree" }, { SYM_PCHAR, S_room, "S_room" }, { SYM_PCHAR, S_corr, "S_corr" }, { SYM_PCHAR, S_litcorr, "S_litcorr" }, { SYM_PCHAR, S_upstair, "S_upstair" }, { SYM_PCHAR, S_dnstair, "S_dnstair" }, { SYM_PCHAR, S_upladder, "S_upladder" }, { SYM_PCHAR, S_dnladder, "S_dnladder" }, { SYM_PCHAR, S_altar, "S_altar" }, { SYM_PCHAR, S_grave, "S_grave" }, { SYM_PCHAR, S_throne, "S_throne" }, { SYM_PCHAR, S_sink, "S_sink" }, { SYM_PCHAR, S_fountain, "S_fountain" }, { SYM_PCHAR, S_pool, "S_pool" }, { SYM_PCHAR, S_ice, "S_ice" }, { SYM_PCHAR, S_lava, "S_lava" }, { SYM_PCHAR, S_vodbridge, "S_vodbridge" }, { SYM_PCHAR, S_hodbridge, "S_hodbridge" }, { SYM_PCHAR, S_vcdbridge, "S_vcdbridge" }, { SYM_PCHAR, S_hcdbridge, "S_hcdbridge" }, { SYM_PCHAR, S_air, "S_air" }, { SYM_PCHAR, S_cloud, "S_cloud" }, { SYM_PCHAR, S_poisoncloud, "S_poisoncloud" }, { SYM_PCHAR, S_water, "S_water" }, { SYM_PCHAR, S_arrow_trap, "S_arrow_trap" }, { SYM_PCHAR, S_dart_trap, "S_dart_trap" }, { SYM_PCHAR, S_falling_rock_trap, "S_falling_rock_trap" }, { SYM_PCHAR, S_squeaky_board, "S_squeaky_board" }, { SYM_PCHAR, S_bear_trap, "S_bear_trap" }, { SYM_PCHAR, S_land_mine, "S_land_mine" }, { SYM_PCHAR, S_rolling_boulder_trap, "S_rolling_boulder_trap" }, { SYM_PCHAR, S_sleeping_gas_trap, "S_sleeping_gas_trap" }, { SYM_PCHAR, S_rust_trap, "S_rust_trap" }, { SYM_PCHAR, S_fire_trap, "S_fire_trap" }, { SYM_PCHAR, S_pit, "S_pit" }, { SYM_PCHAR, S_spiked_pit, "S_spiked_pit" }, { SYM_PCHAR, S_hole, "S_hole" }, { SYM_PCHAR, S_trap_door, "S_trap_door" }, { SYM_PCHAR, S_teleportation_trap, "S_teleportation_trap" }, { SYM_PCHAR, S_level_teleporter, "S_level_teleporter" }, { SYM_PCHAR, S_magic_portal, "S_magic_portal" }, { SYM_PCHAR, S_web, "S_web" }, { SYM_PCHAR, S_statue_trap, "S_statue_trap" }, { SYM_PCHAR, S_magic_trap, "S_magic_trap" }, { SYM_PCHAR, S_anti_magic_trap, "S_anti_magic_trap" }, { SYM_PCHAR, S_polymorph_trap, "S_polymorph_trap" }, { SYM_PCHAR, S_vbeam, "S_vbeam" }, { SYM_PCHAR, S_hbeam, "S_hbeam" }, { SYM_PCHAR, S_lslant, "S_lslant" }, { SYM_PCHAR, S_rslant, "S_rslant" }, { SYM_PCHAR, S_digbeam, "S_digbeam" }, { SYM_PCHAR, S_flashbeam, "S_flashbeam" }, { SYM_PCHAR, S_boomleft, "S_boomleft" }, { SYM_PCHAR, S_boomright, "S_boomright" }, { SYM_PCHAR, S_goodpos, "S_goodpos" }, { SYM_PCHAR, S_ss1, "S_ss1" }, { SYM_PCHAR, S_ss2, "S_ss2" }, { SYM_PCHAR, S_ss3, "S_ss3" }, { SYM_PCHAR, S_ss4, "S_ss4" }, { SYM_PCHAR, S_sw_tl, "S_sw_tl" }, { SYM_PCHAR, S_sw_tc, "S_sw_tc" }, { SYM_PCHAR, S_sw_tr, "S_sw_tr" }, { SYM_PCHAR, S_sw_ml, "S_sw_ml" }, { SYM_PCHAR, S_sw_mr, "S_sw_mr" }, { SYM_PCHAR, S_sw_bl, "S_sw_bl" }, { SYM_PCHAR, S_sw_bc, "S_sw_bc" }, { SYM_PCHAR, S_sw_br, "S_sw_br" }, { SYM_PCHAR, S_explode1, "S_explode1" }, { SYM_PCHAR, S_explode2, "S_explode2" }, { SYM_PCHAR, S_explode3, "S_explode3" }, { SYM_PCHAR, S_explode4, "S_explode4" }, { SYM_PCHAR, S_explode5, "S_explode5" }, { SYM_PCHAR, S_explode6, "S_explode6" }, { SYM_PCHAR, S_explode7, "S_explode7" }, { SYM_PCHAR, S_explode8, "S_explode8" }, { SYM_PCHAR, S_explode9, "S_explode9" }, { SYM_OC, WEAPON_CLASS + SYM_OFF_O, "S_weapon" }, { SYM_OC, ARMOR_CLASS + SYM_OFF_O, "S_armor" }, { SYM_OC, ARMOR_CLASS + SYM_OFF_O, "S_armour" }, { SYM_OC, RING_CLASS + SYM_OFF_O, "S_ring" }, { SYM_OC, AMULET_CLASS + SYM_OFF_O, "S_amulet" }, { SYM_OC, TOOL_CLASS + SYM_OFF_O, "S_tool" }, { SYM_OC, FOOD_CLASS + SYM_OFF_O, "S_food" }, { SYM_OC, POTION_CLASS + SYM_OFF_O, "S_potion" }, { SYM_OC, SCROLL_CLASS + SYM_OFF_O, "S_scroll" }, { SYM_OC, SPBOOK_CLASS + SYM_OFF_O, "S_book" }, { SYM_OC, WAND_CLASS + SYM_OFF_O, "S_wand" }, { SYM_OC, COIN_CLASS + SYM_OFF_O, "S_coin" }, { SYM_OC, GEM_CLASS + SYM_OFF_O, "S_gem" }, { SYM_OC, ROCK_CLASS + SYM_OFF_O, "S_rock" }, { SYM_OC, BALL_CLASS + SYM_OFF_O, "S_ball" }, { SYM_OC, CHAIN_CLASS + SYM_OFF_O, "S_chain" }, { SYM_OC, VENOM_CLASS + SYM_OFF_O, "S_venom" }, { SYM_MON, S_ANT + SYM_OFF_M, "S_ant" }, { SYM_MON, S_BLOB + SYM_OFF_M, "S_blob" }, { SYM_MON, S_COCKATRICE + SYM_OFF_M, "S_cockatrice" }, { SYM_MON, S_DOG + SYM_OFF_M, "S_dog" }, { SYM_MON, S_EYE + SYM_OFF_M, "S_eye" }, { SYM_MON, S_FELINE + SYM_OFF_M, "S_feline" }, { SYM_MON, S_GREMLIN + SYM_OFF_M, "S_gremlin" }, { SYM_MON, S_HUMANOID + SYM_OFF_M, "S_humanoid" }, { SYM_MON, S_IMP + SYM_OFF_M, "S_imp" }, { SYM_MON, S_JELLY + SYM_OFF_M, "S_jelly" }, { SYM_MON, S_KOBOLD + SYM_OFF_M, "S_kobold" }, { SYM_MON, S_LEPRECHAUN + SYM_OFF_M, "S_leprechaun" }, { SYM_MON, S_MIMIC + SYM_OFF_M, "S_mimic" }, { SYM_MON, S_NYMPH + SYM_OFF_M, "S_nymph" }, { SYM_MON, S_ORC + SYM_OFF_M, "S_orc" }, { SYM_MON, S_PIERCER + SYM_OFF_M, "S_piercer" }, { SYM_MON, S_QUADRUPED + SYM_OFF_M, "S_quadruped" }, { SYM_MON, S_RODENT + SYM_OFF_M, "S_rodent" }, { SYM_MON, S_SPIDER + SYM_OFF_M, "S_spider" }, { SYM_MON, S_TRAPPER + SYM_OFF_M, "S_trapper" }, { SYM_MON, S_UNICORN + SYM_OFF_M, "S_unicorn" }, { SYM_MON, S_VORTEX + SYM_OFF_M, "S_vortex" }, { SYM_MON, S_WORM + SYM_OFF_M, "S_worm" }, { SYM_MON, S_XAN + SYM_OFF_M, "S_xan" }, { SYM_MON, S_LIGHT + SYM_OFF_M, "S_light" }, { SYM_MON, S_ZRUTY + SYM_OFF_M, "S_zruty" }, { SYM_MON, S_ANGEL + SYM_OFF_M, "S_angel" }, { SYM_MON, S_BAT + SYM_OFF_M, "S_bat" }, { SYM_MON, S_CENTAUR + SYM_OFF_M, "S_centaur" }, { SYM_MON, S_DRAGON + SYM_OFF_M, "S_dragon" }, { SYM_MON, S_ELEMENTAL + SYM_OFF_M, "S_elemental" }, { SYM_MON, S_FUNGUS + SYM_OFF_M, "S_fungus" }, { SYM_MON, S_GNOME + SYM_OFF_M, "S_gnome" }, { SYM_MON, S_GIANT + SYM_OFF_M, "S_giant" }, { SYM_MON, S_JABBERWOCK + SYM_OFF_M, "S_jabberwock" }, { SYM_MON, S_KOP + SYM_OFF_M, "S_kop" }, { SYM_MON, S_LICH + SYM_OFF_M, "S_lich" }, { SYM_MON, S_MUMMY + SYM_OFF_M, "S_mummy" }, { SYM_MON, S_NAGA + SYM_OFF_M, "S_naga" }, { SYM_MON, S_OGRE + SYM_OFF_M, "S_ogre" }, { SYM_MON, S_PUDDING + SYM_OFF_M, "S_pudding" }, { SYM_MON, S_QUANTMECH + SYM_OFF_M, "S_quantmech" }, { SYM_MON, S_RUSTMONST + SYM_OFF_M, "S_rustmonst" }, { SYM_MON, S_SNAKE + SYM_OFF_M, "S_snake" }, { SYM_MON, S_TROLL + SYM_OFF_M, "S_troll" }, { SYM_MON, S_UMBER + SYM_OFF_M, "S_umber" }, { SYM_MON, S_VAMPIRE + SYM_OFF_M, "S_vampire" }, { SYM_MON, S_WRAITH + SYM_OFF_M, "S_wraith" }, { SYM_MON, S_XORN + SYM_OFF_M, "S_xorn" }, { SYM_MON, S_YETI + SYM_OFF_M, "S_yeti" }, { SYM_MON, S_ZOMBIE + SYM_OFF_M, "S_zombie" }, { SYM_MON, S_HUMAN + SYM_OFF_M, "S_human" }, { SYM_MON, S_GHOST + SYM_OFF_M, "S_ghost" }, { SYM_MON, S_GOLEM + SYM_OFF_M, "S_golem" }, { SYM_MON, S_DEMON + SYM_OFF_M, "S_demon" }, { SYM_MON, S_EEL + SYM_OFF_M, "S_eel" }, { SYM_MON, S_LIZARD + SYM_OFF_M, "S_lizard" }, { SYM_MON, S_WORM_TAIL + SYM_OFF_M, "S_worm_tail" }, { SYM_MON, S_MIMIC_DEF + SYM_OFF_M, "S_mimic_def" }, { SYM_OTH, SYM_BOULDER + SYM_OFF_X, "S_boulder" }, { SYM_OTH, SYM_INVISIBLE + SYM_OFF_X, "S_invisible" }, { 0, 0, (const char *) 0 } /* fence post */ }; /*drawing.c*/ nethack-3.6.0/src/dungeon.c0000664000076400007660000026607212626765533014563 0ustar paxedpaxed/* NetHack 3.6 dungeon.c $NHDT-Date: 1448862377 2015/11/30 05:46:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.69 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dgn_file.h" #include "dlb.h" #include "lev.h" #define DUNGEON_FILE "dungeon" #define X_START "x-strt" #define X_LOCATE "x-loca" #define X_GOAL "x-goal" struct proto_dungeon { struct tmpdungeon tmpdungeon[MAXDUNGEON]; struct tmplevel tmplevel[LEV_LIMIT]; s_level *final_lev[LEV_LIMIT]; /* corresponding level pointers */ struct tmpbranch tmpbranch[BRANCH_LIMIT]; int start; /* starting index of current dungeon sp levels */ int n_levs; /* number of tmplevel entries */ int n_brs; /* number of tmpbranch entries */ }; int n_dgns; /* number of dungeons (also used in mklev.c and do.c) */ static branch *branches = (branch *) 0; /* dungeon branch list */ mapseen *mapseenchn = (struct mapseen *) 0; /*DUNGEON_OVERVIEW*/ struct lchoice { int idx; schar lev[MAXLINFO]; schar playerlev[MAXLINFO]; xchar dgn[MAXLINFO]; char menuletter; }; static void FDECL(Fread, (genericptr_t, int, int, dlb *)); STATIC_DCL xchar FDECL(dname_to_dnum, (const char *)); STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *)); STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *)); STATIC_DCL int FDECL(level_range, (XCHAR_P, int, int, int, struct proto_dungeon *, int *)); STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *)); STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *)); STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *)); STATIC_DCL void FDECL(add_level, (s_level *)); STATIC_DCL void FDECL(init_level, (int, int, struct proto_dungeon *)); STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *)); STATIC_DCL xchar FDECL(pick_level, (boolean *, int)); STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *)); STATIC_DCL boolean FDECL(unplaced_floater, (struct dungeon *)); STATIC_DCL boolean FDECL(unreachable_level, (d_level *, BOOLEAN_P)); STATIC_DCL void FDECL(tport_menu, (winid, char *, struct lchoice *, d_level *, BOOLEAN_P)); STATIC_DCL const char *FDECL(br_string, (int)); STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *)); STATIC_DCL mapseen *FDECL(load_mapseen, (int)); STATIC_DCL void FDECL(save_mapseen, (int, mapseen *)); STATIC_DCL mapseen *FDECL(find_mapseen, (d_level *)); STATIC_DCL void FDECL(print_mapseen, (winid, mapseen *, int, int, BOOLEAN_P)); STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *)); STATIC_DCL void FDECL(traverse_mapseenchn, (BOOLEAN_P, winid, int, int, int *)); STATIC_DCL const char *FDECL(seen_string, (XCHAR_P, const char *)); STATIC_DCL const char *FDECL(br_string2, (branch *)); STATIC_DCL const char *FDECL(endgamelevelname, (char *, int)); STATIC_DCL const char *FDECL(shop_string, (int)); STATIC_DCL char *FDECL(tunesuffix, (mapseen *, char *)); #ifdef DEBUG #define DD dungeons[i] STATIC_DCL void NDECL(dumpit); STATIC_OVL void dumpit() { int i; s_level *x; branch *br; if (!explicitdebug(__FILE__)) return; for (i = 0; i < n_dgns; i++) { fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, DD.dname, DD.proto); fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n", DD.num_dunlevs, DD.dunlev_ureached); fprintf(stderr, " depth_start %d, ledger_start %d\n", DD.depth_start, DD.ledger_start); fprintf(stderr, " flags:%s%s%s\n", DD.flags.rogue_like ? " rogue_like" : "", DD.flags.maze_like ? " maze_like" : "", DD.flags.hellish ? " hellish" : ""); getchar(); } fprintf(stderr, "\nSpecial levels:\n"); for (x = sp_levchn; x; x = x->next) { fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs); fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel); fprintf(stderr, "flags:%s%s%s%s\n", x->flags.rogue_like ? " rogue_like" : "", x->flags.maze_like ? " maze_like" : "", x->flags.hellish ? " hellish" : "", x->flags.town ? " town" : ""); getchar(); } fprintf(stderr, "\nBranches:\n"); for (br = branches; br; br = br->next) { fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", br->id, br->type == BR_STAIR ? "stair" : br->type == BR_NO_END1 ? "no end1" : br->type == BR_NO_END2 ? "no end2" : br->type == BR_PORTAL ? "portal" : "unknown", br->end1.dnum, br->end1.dlevel, br->end2.dnum, br->end2.dlevel, br->end1_up ? "end1 up" : "end1 down"); } getchar(); fprintf(stderr, "\nDone\n"); getchar(); } #endif /* Save the dungeon structures. */ void save_dungeon(fd, perform_write, free_data) int fd; boolean perform_write, free_data; { branch *curr, *next; mapseen *curr_ms, *next_ms; int count; if (perform_write) { bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns); bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned) n_dgns); bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology); bwrite(fd, (genericptr_t) tune, sizeof tune); for (count = 0, curr = branches; curr; curr = curr->next) count++; bwrite(fd, (genericptr_t) &count, sizeof(count)); for (curr = branches; curr; curr = curr->next) bwrite(fd, (genericptr_t) curr, sizeof(branch)); count = maxledgerno(); bwrite(fd, (genericptr_t) &count, sizeof count); bwrite(fd, (genericptr_t) level_info, (unsigned) count * sizeof(struct linfo)); bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos); for (count = 0, curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next) count++; bwrite(fd, (genericptr_t) &count, sizeof(count)); for (curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next) save_mapseen(fd, curr_ms); } if (free_data) { for (curr = branches; curr; curr = next) { next = curr->next; free((genericptr_t) curr); } branches = 0; for (curr_ms = mapseenchn; curr_ms; curr_ms = next_ms) { next_ms = curr_ms->next; if (curr_ms->custom) free((genericptr_t) curr_ms->custom); free((genericptr_t) curr_ms); } mapseenchn = 0; } } /* Restore the dungeon structures. */ void restore_dungeon(fd) int fd; { branch *curr, *last; int count, i; mapseen *curr_ms, *last_ms; mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns)); mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned) n_dgns); mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology); mread(fd, (genericptr_t) tune, sizeof tune); last = branches = (branch *) 0; mread(fd, (genericptr_t) &count, sizeof(count)); for (i = 0; i < count; i++) { curr = (branch *) alloc(sizeof(branch)); mread(fd, (genericptr_t) curr, sizeof(branch)); curr->next = (branch *) 0; if (last) last->next = curr; else branches = curr; last = curr; } mread(fd, (genericptr_t) &count, sizeof(count)); if (count >= MAXLINFO) panic("level information count larger (%d) than allocated size", count); mread(fd, (genericptr_t) level_info, (unsigned) count * sizeof(struct linfo)); mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos); mread(fd, (genericptr_t) &count, sizeof(count)); last_ms = (mapseen *) 0; for (i = 0; i < count; i++) { curr_ms = load_mapseen(fd); curr_ms->next = (mapseen *) 0; if (last_ms) last_ms->next = curr_ms; else mapseenchn = curr_ms; last_ms = curr_ms; } } static void Fread(ptr, size, nitems, stream) genericptr_t ptr; int size, nitems; dlb *stream; { int cnt; if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) { panic( "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.", (size * nitems), (size * cnt)); terminate(EXIT_FAILURE); } } STATIC_OVL xchar dname_to_dnum(s) const char *s; { xchar i; for (i = 0; i < n_dgns; i++) if (!strcmp(dungeons[i].dname, s)) return i; panic("Couldn't resolve dungeon number for name \"%s\".", s); /*NOT REACHED*/ return (xchar) 0; } s_level * find_level(s) const char *s; { s_level *curr; for (curr = sp_levchn; curr; curr = curr->next) if (!strcmpi(s, curr->proto)) break; return curr; } /* Find the branch that links the named dungeon. */ STATIC_OVL int find_branch(s, pd) const char *s; /* dungeon name */ struct proto_dungeon *pd; { int i; if (pd) { for (i = 0; i < pd->n_brs; i++) if (!strcmp(pd->tmpbranch[i].name, s)) break; if (i == pd->n_brs) panic("find_branch: can't find %s", s); } else { /* support for level tport by name */ branch *br; const char *dnam; for (br = branches; br; br = br->next) { dnam = dungeons[br->end2.dnum].dname; if (!strcmpi(dnam, s) || (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s))) break; } i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1; } return i; } /* * Find the "parent" by searching the prototype branch list for the branch * listing, then figuring out to which dungeon it belongs. */ STATIC_OVL xchar parent_dnum(s, pd) const char *s; /* dungeon name */ struct proto_dungeon *pd; { int i; xchar pdnum; i = find_branch(s, pd); /* * Got branch, now find parent dungeon. Stop if we have reached * "this" dungeon (if we haven't found it by now it is an error). */ for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++) if ((i -= pd->tmpdungeon[pdnum].branches) < 0) return pdnum; panic("parent_dnum: couldn't resolve branch."); /*NOT REACHED*/ return (xchar) 0; } /* * Return a starting point and number of successive positions a level * or dungeon entrance can occupy. * * Note: This follows the acouple (instead of the rcouple) rules for a * negative random component (randc < 0). These rules are found * in dgn_comp.y. The acouple [absolute couple] section says that * a negative random component means from the (adjusted) base to the * end of the dungeon. */ STATIC_OVL int level_range(dgn, base, randc, chain, pd, adjusted_base) xchar dgn; int base, randc, chain; struct proto_dungeon *pd; int *adjusted_base; { int lmax = dungeons[dgn].num_dunlevs; if (chain >= 0) { /* relative to a special level */ s_level *levtmp = pd->final_lev[chain]; if (!levtmp) panic("level_range: empty chain level!"); base += levtmp->dlevel.dlevel; } else { /* absolute in the dungeon */ /* from end of dungeon */ if (base < 0) base = (lmax + base + 1); } if (base < 1 || base > lmax) panic("level_range: base value out of range"); *adjusted_base = base; if (randc == -1) { /* from base to end of dungeon */ return (lmax - base + 1); } else if (randc) { /* make sure we don't run off the end of the dungeon */ return (((base + randc - 1) > lmax) ? lmax - base + 1 : randc); } /* else only one choice */ return 1; } STATIC_OVL xchar parent_dlevel(s, pd) const char *s; struct proto_dungeon *pd; { int i, j, num, base, dnum = parent_dnum(s, pd); branch *curr; i = find_branch(s, pd); num = level_range(dnum, pd->tmpbranch[i].lev.base, pd->tmpbranch[i].lev.rand, pd->tmpbranch[i].chain, pd, &base); /* KMH -- Try our best to find a level without an existing branch */ i = j = rn2(num); do { if (++i >= num) i = 0; for (curr = branches; curr; curr = curr->next) if ((curr->end1.dnum == dnum && curr->end1.dlevel == base + i) || (curr->end2.dnum == dnum && curr->end2.dlevel == base + i)) break; } while (curr && i != j); return (base + i); } /* Convert from the temporary branch type to the dungeon branch type. */ STATIC_OVL int correct_branch_type(tbr) struct tmpbranch *tbr; { switch (tbr->type) { case TBR_STAIR: return BR_STAIR; case TBR_NO_UP: return tbr->up ? BR_NO_END1 : BR_NO_END2; case TBR_NO_DOWN: return tbr->up ? BR_NO_END2 : BR_NO_END1; case TBR_PORTAL: return BR_PORTAL; } impossible("correct_branch_type: unknown branch type"); return BR_STAIR; } /* * Add the given branch to the branch list. The branch list is ordered * by end1 dungeon and level followed by end2 dungeon and level. If * extract_first is true, then the branch is already part of the list * but needs to be repositioned. */ void insert_branch(new_branch, extract_first) branch *new_branch; boolean extract_first; { branch *curr, *prev; long new_val, curr_val, prev_val; if (extract_first) { for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next) if (curr == new_branch) break; if (!curr) panic("insert_branch: not found"); if (prev) prev->next = curr->next; else branches = curr->next; } new_branch->next = (branch *) 0; /* Convert the branch into a unique number so we can sort them. */ #define branch_val(bp) \ ((((long) (bp)->end1.dnum * (MAXLEVEL + 1) + (long) (bp)->end1.dlevel) \ * (MAXDUNGEON + 1) * (MAXLEVEL + 1)) \ + ((long) (bp)->end2.dnum * (MAXLEVEL + 1) + (long) (bp)->end2.dlevel)) /* * Insert the new branch into the correct place in the branch list. */ prev = (branch *) 0; prev_val = -1; new_val = branch_val(new_branch); for (curr = branches; curr; prev_val = curr_val, prev = curr, curr = curr->next) { curr_val = branch_val(curr); if (prev_val < new_val && new_val <= curr_val) break; } if (prev) { new_branch->next = curr; prev->next = new_branch; } else { new_branch->next = branches; branches = new_branch; } } /* Add a dungeon branch to the branch list. */ STATIC_OVL branch * add_branch(dgn, child_entry_level, pd) int dgn; int child_entry_level; struct proto_dungeon *pd; { static int branch_id = 0; int branch_num; branch *new_branch; branch_num = find_branch(dungeons[dgn].dname, pd); new_branch = (branch *) alloc(sizeof(branch)); new_branch->next = (branch *) 0; new_branch->id = branch_id++; new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]); new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd); new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd); new_branch->end2.dnum = dgn; new_branch->end2.dlevel = child_entry_level; new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE; insert_branch(new_branch, FALSE); return new_branch; } /* * Add new level to special level chain. Insert it in level order with the * other levels in this dungeon. This assumes that we are never given a * level that has a dungeon number less than the dungeon number of the * last entry. */ STATIC_OVL void add_level(new_lev) s_level *new_lev; { s_level *prev, *curr; prev = (s_level *) 0; for (curr = sp_levchn; curr; curr = curr->next) { if (curr->dlevel.dnum == new_lev->dlevel.dnum && curr->dlevel.dlevel > new_lev->dlevel.dlevel) break; prev = curr; } if (!prev) { new_lev->next = sp_levchn; sp_levchn = new_lev; } else { new_lev->next = curr; prev->next = new_lev; } } STATIC_OVL void init_level(dgn, proto_index, pd) int dgn, proto_index; struct proto_dungeon *pd; { s_level *new_level; struct tmplevel *tlevel = &pd->tmplevel[proto_index]; pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */ if (!wizard && tlevel->chance <= rn2(100)) return; pd->final_lev[proto_index] = new_level = (s_level *) alloc(sizeof(s_level)); /* load new level with data */ Strcpy(new_level->proto, tlevel->name); new_level->boneid = tlevel->boneschar; new_level->dlevel.dnum = dgn; new_level->dlevel.dlevel = 0; /* for now */ new_level->flags.town = !!(tlevel->flags & TOWN); new_level->flags.hellish = !!(tlevel->flags & HELLISH); new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE); new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE); new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4); if (!new_level->flags.align) new_level->flags.align = ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4); new_level->rndlevs = tlevel->rndlevs; new_level->next = (s_level *) 0; } STATIC_OVL int possible_places(idx, map, pd) int idx; /* prototype index */ boolean *map; /* array MAXLEVEL+1 in length */ struct proto_dungeon *pd; { int i, start, count; s_level *lev = pd->final_lev[idx]; /* init level possibilities */ for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE; /* get base and range and set those entries to true */ count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base, pd->tmplevel[idx].lev.rand, pd->tmplevel[idx].chain, pd, &start); for (i = start; i < start + count; i++) map[i] = TRUE; /* mark off already placed levels */ for (i = pd->start; i < idx; i++) { if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) { map[pd->final_lev[i]->dlevel.dlevel] = FALSE; --count; } } return count; } /* Pick the nth TRUE entry in the given boolean array. */ STATIC_OVL xchar pick_level(map, nth) boolean *map; /* an array MAXLEVEL+1 in size */ int nth; { int i; for (i = 1; i <= MAXLEVEL; i++) if (map[i] && !nth--) return (xchar) i; panic("pick_level: ran out of valid levels"); return 0; } #ifdef DDEBUG static void FDECL(indent, (int)); static void indent(d) int d; { while (d-- > 0) fputs(" ", stderr); } #endif /* * Place a level. First, find the possible places on a dungeon map * template. Next pick one. Then try to place the next level. If * successful, we're done. Otherwise, try another (and another) until * all possible places have been tried. If all possible places have * been exhausted, return false. */ STATIC_OVL boolean place_level(proto_index, pd) int proto_index; struct proto_dungeon *pd; { boolean map[MAXLEVEL + 1]; /* valid levels are 1..MAXLEVEL inclusive */ s_level *lev; int npossible; #ifdef DDEBUG int i; #endif if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */ lev = pd->final_lev[proto_index]; /* No level created for this prototype, goto next. */ if (!lev) return place_level(proto_index + 1, pd); npossible = possible_places(proto_index, map, pd); for (; npossible; --npossible) { lev->dlevel.dlevel = pick_level(map, rn2(npossible)); #ifdef DDEBUG indent(proto_index - pd->start); fprintf(stderr, "%s: trying %d [ ", lev->proto, lev->dlevel.dlevel); for (i = 1; i <= MAXLEVEL; i++) if (map[i]) fprintf(stderr, "%d ", i); fprintf(stderr, "]\n"); #endif if (place_level(proto_index + 1, pd)) return TRUE; map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */ } #ifdef DDEBUG indent(proto_index - pd->start); fprintf(stderr, "%s: failed\n", lev->proto); #endif return FALSE; } struct level_map { const char *lev_name; d_level *lev_spec; } level_map[] = { { "air", &air_level }, { "asmodeus", &asmodeus_level }, { "astral", &astral_level }, { "baalz", &baalzebub_level }, { "bigrm", &bigroom_level }, { "castle", &stronghold_level }, { "earth", &earth_level }, { "fakewiz1", &portal_level }, { "fire", &fire_level }, { "juiblex", &juiblex_level }, { "knox", &knox_level }, { "medusa", &medusa_level }, { "oracle", &oracle_level }, { "orcus", &orcus_level }, { "rogue", &rogue_level }, { "sanctum", &sanctum_level }, { "valley", &valley_level }, { "water", &water_level }, { "wizard1", &wiz1_level }, { "wizard2", &wiz2_level }, { "wizard3", &wiz3_level }, { "minend", &mineend_level }, { "soko1", &sokoend_level }, { X_START, &qstart_level }, { X_LOCATE, &qlocate_level }, { X_GOAL, &nemesis_level }, { "", (d_level *) 0 } }; /* initialize the "dungeon" structs */ void init_dungeons() { dlb *dgn_file; register int i, cl = 0, cb = 0; register s_level *x; struct proto_dungeon pd; struct level_map *lev_map; struct version_info vers_info; pd.n_levs = pd.n_brs = 0; dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE); if (!dgn_file) { char tbuf[BUFSZ]; Sprintf(tbuf, "Cannot open dungeon description - \"%s", DUNGEON_FILE); #ifdef DLBRSRC /* using a resource from the executable */ Strcat(tbuf, "\" resource!"); #else /* using a file or DLB file */ #if defined(DLB) Strcat(tbuf, "\" from "); #ifdef PREFIXES_IN_USE Strcat(tbuf, "\n\""); if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]); #else Strcat(tbuf, "\""); #endif Strcat(tbuf, DLBFILE); #endif Strcat(tbuf, "\" file!"); #endif #ifdef WIN32 interject_assistance(1, INTERJECT_PANIC, (genericptr_t) tbuf, (genericptr_t) fqn_prefix[DATAPREFIX]); #endif panic1(tbuf); } /* validate the data's version against the program's version */ Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file); /* we'd better clear the screen now, since when error messages come from * check_version() they will be printed using pline(), which doesn't * mix with the raw messages that might be already on the screen */ if (iflags.window_inited) clear_nhwindow(WIN_MAP); if (!check_version(&vers_info, DUNGEON_FILE, TRUE)) panic("Dungeon description not valid."); /* * Read in each dungeon and transfer the results to the internal * dungeon arrays. */ sp_levchn = (s_level *) 0; Fread((genericptr_t) &n_dgns, sizeof(int), 1, dgn_file); if (n_dgns >= MAXDUNGEON) panic("init_dungeons: too many dungeons"); for (i = 0; i < n_dgns; i++) { Fread((genericptr_t) &pd.tmpdungeon[i], sizeof(struct tmpdungeon), 1, dgn_file); if (!wizard && pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) { int j; /* skip over any levels or branches */ for (j = 0; j < pd.tmpdungeon[i].levels; j++) Fread((genericptr_t) &pd.tmplevel[cl], sizeof(struct tmplevel), 1, dgn_file); for (j = 0; j < pd.tmpdungeon[i].branches; j++) Fread((genericptr_t) &pd.tmpbranch[cb], sizeof(struct tmpbranch), 1, dgn_file); n_dgns--; i--; continue; } Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name); Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname); dungeons[i].boneid = pd.tmpdungeon[i].boneschar; if (pd.tmpdungeon[i].lev.rand) dungeons[i].num_dunlevs = (xchar) rn1(pd.tmpdungeon[i].lev.rand, pd.tmpdungeon[i].lev.base); else dungeons[i].num_dunlevs = (xchar) pd.tmpdungeon[i].lev.base; if (!i) { dungeons[i].ledger_start = 0; dungeons[i].depth_start = 1; dungeons[i].dunlev_ureached = 1; } else { dungeons[i].ledger_start = dungeons[i - 1].ledger_start + dungeons[i - 1].num_dunlevs; dungeons[i].dunlev_ureached = 0; } dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH); dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE); dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE); dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4); /* * Set the entry level for this dungeon. The pd.tmpdungeon entry * value means: * < 0 from bottom (-1 == bottom level) * 0 default (top) * > 0 actual level (1 = top) * * Note that the entry_lev field in the dungeon structure is * redundant. It is used only here and in print_dungeon(). */ if (pd.tmpdungeon[i].entry_lev < 0) { dungeons[i].entry_lev = dungeons[i].num_dunlevs + pd.tmpdungeon[i].entry_lev + 1; if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1; } else if (pd.tmpdungeon[i].entry_lev > 0) { dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev; if (dungeons[i].entry_lev > dungeons[i].num_dunlevs) dungeons[i].entry_lev = dungeons[i].num_dunlevs; } else { /* default */ dungeons[i].entry_lev = 1; /* defaults to top level */ } if (i) { /* set depth */ branch *br; schar from_depth; boolean from_up; br = add_branch(i, dungeons[i].entry_lev, &pd); /* Get the depth of the connecting end. */ if (br->end1.dnum == i) { from_depth = depth(&br->end2); from_up = !br->end1_up; } else { from_depth = depth(&br->end1); from_up = br->end1_up; } /* * Calculate the depth of the top of the dungeon via * its branch. First, the depth of the entry point: * * depth of branch from "parent" dungeon * + -1 or 1 depending on a up or down stair or * 0 if portal * * Followed by the depth of the top of the dungeon: * * - (entry depth - 1) * * We'll say that portals stay on the same depth. */ dungeons[i].depth_start = from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1)) - (dungeons[i].entry_lev - 1); } /* this is redundant - it should have been flagged by dgn_comp */ if (dungeons[i].num_dunlevs > MAXLEVEL) dungeons[i].num_dunlevs = MAXLEVEL; pd.start = pd.n_levs; /* save starting point */ pd.n_levs += pd.tmpdungeon[i].levels; if (pd.n_levs > LEV_LIMIT) panic("init_dungeon: too many special levels"); /* * Read in the prototype special levels. Don't add generated * special levels until they are all placed. */ for (; cl < pd.n_levs; cl++) { Fread((genericptr_t) &pd.tmplevel[cl], sizeof(struct tmplevel), 1, dgn_file); init_level(i, cl, &pd); } /* * Recursively place the generated levels for this dungeon. This * routine will attempt all possible combinations before giving * up. */ if (!place_level(pd.start, &pd)) panic("init_dungeon: couldn't place levels"); #ifdef DDEBUG fprintf(stderr, "--- end of dungeon %d ---\n", i); fflush(stderr); getchar(); #endif for (; pd.start < pd.n_levs; pd.start++) if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]); pd.n_brs += pd.tmpdungeon[i].branches; if (pd.n_brs > BRANCH_LIMIT) panic("init_dungeon: too many branches"); for (; cb < pd.n_brs; cb++) Fread((genericptr_t) &pd.tmpbranch[cb], sizeof(struct tmpbranch), 1, dgn_file); } (void) dlb_fclose(dgn_file); for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7); tune[5] = 0; /* * Find most of the special levels and dungeons so we can access their * locations quickly. */ for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) { x = find_level(lev_map->lev_name); if (x) { assign_level(lev_map->lev_spec, &x->dlevel); if (!strncmp(lev_map->lev_name, "x-", 2)) { /* This is where the name substitution on the * levels of the quest dungeon occur. */ Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]); } else if (lev_map->lev_spec == &knox_level) { branch *br; /* * Kludge to allow floating Knox entrance. We * specify a floating entrance by the fact that * its entrance (end1) has a bogus dnum, namely * n_dgns. */ for (br = branches; br; br = br->next) if (on_level(&br->end2, &knox_level)) break; if (br) br->end1.dnum = n_dgns; /* adjust the branch's position on the list */ insert_branch(br, TRUE); } } } /* * I hate hardwiring these names. :-( */ quest_dnum = dname_to_dnum("The Quest"); sokoban_dnum = dname_to_dnum("Sokoban"); mines_dnum = dname_to_dnum("The Gnomish Mines"); tower_dnum = dname_to_dnum("Vlad's Tower"); /* one special fixup for dummy surface level */ if ((x = find_level("dummy")) != 0) { i = x->dlevel.dnum; /* the code above puts earth one level above dungeon level #1, making the dummy level overlay level 1; but the whole reason for having the dummy level is to make earth have depth -1 instead of 0, so adjust the start point to shift endgame up */ if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start) dungeons[i].depth_start -= 1; /* TO DO: strip "dummy" out all the way here, so that it's hidden from feedback. */ } #ifdef DEBUG dumpit(); #endif } /* return the level number for lev in *this* dungeon */ xchar dunlev(lev) d_level *lev; { return lev->dlevel; } /* return the lowest level number for *this* dungeon */ xchar dunlevs_in_dungeon(lev) d_level *lev; { return dungeons[lev->dnum].num_dunlevs; } /* return the lowest level explored in the game*/ xchar deepest_lev_reached(noquest) boolean noquest; { /* this function is used for three purposes: to provide a factor * of difficulty in monster generation; to provide a factor of * difficulty in experience calculations (botl.c and end.c); and * to insert the deepest level reached in the game in the topten * display. the 'noquest' arg switch is required for the latter. * * from the player's point of view, going into the Quest is _not_ * going deeper into the dungeon -- it is going back "home", where * the dungeon starts at level 1. given the setup in dungeon.def, * the depth of the Quest (thought of as starting at level 1) is * never lower than the level of entry into the Quest, so we exclude * the Quest from the topten "deepest level reached" display * calculation. _However_ the Quest is a difficult dungeon, so we * include it in the factor of difficulty calculations. */ register int i; d_level tmp; register schar ret = 0; for (i = 0; i < n_dgns; i++) { if (noquest && i == quest_dnum) continue; tmp.dlevel = dungeons[i].dunlev_ureached; if (tmp.dlevel == 0) continue; tmp.dnum = i; if (depth(&tmp) > ret) ret = depth(&tmp); } return (xchar) ret; } /* return a bookkeeping level number for purpose of comparisons and save/restore */ xchar ledger_no(lev) d_level *lev; { return (xchar) (lev->dlevel + dungeons[lev->dnum].ledger_start); } /* * The last level in the bookkeeping list of level is the bottom of the last * dungeon in the dungeons[] array. * * Maxledgerno() -- which is the max number of levels in the bookkeeping * list, should not be confused with dunlevs_in_dungeon(lev) -- which * returns the max number of levels in lev's dungeon, and both should * not be confused with deepest_lev_reached() -- which returns the lowest * depth visited by the player. */ xchar maxledgerno() { return (xchar) (dungeons[n_dgns - 1].ledger_start + dungeons[n_dgns - 1].num_dunlevs); } /* return the dungeon that this ledgerno exists in */ xchar ledger_to_dnum(ledgerno) xchar ledgerno; { register int i; /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */ for (i = 0; i < n_dgns; i++) if (dungeons[i].ledger_start < ledgerno && ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs) return (xchar) i; panic("level number out of range [ledger_to_dnum(%d)]", (int) ledgerno); /*NOT REACHED*/ return (xchar) 0; } /* return the level of the dungeon this ledgerno exists in */ xchar ledger_to_dlev(ledgerno) xchar ledgerno; { return (xchar) (ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start); } /* returns the depth of a level, in floors below the surface (note levels in different dungeons can have the same depth) */ schar depth(lev) d_level *lev; { return (schar) (dungeons[lev->dnum].depth_start + lev->dlevel - 1); } /* are "lev1" and "lev2" actually the same? */ boolean on_level(lev1, lev2) d_level *lev1, *lev2; { return (boolean) (lev1->dnum == lev2->dnum && lev1->dlevel == lev2->dlevel); } /* is this level referenced in the special level chain? */ s_level * Is_special(lev) d_level *lev; { s_level *levtmp; for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next) if (on_level(lev, &levtmp->dlevel)) return levtmp; return (s_level *) 0; } /* * Is this a multi-dungeon branch level? If so, return a pointer to the * branch. Otherwise, return null. */ branch * Is_branchlev(lev) d_level *lev; { branch *curr; for (curr = branches; curr; curr = curr->next) { if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2)) return curr; } return (branch *) 0; } /* returns True iff the branch 'lev' is in a branch which builds up */ boolean builds_up(lev) d_level *lev; { dungeon *dptr = &dungeons[lev->dnum]; /* * FIXME: this misclassifies a single level branch reached via stairs * from below. Saving grace is that no such branches currently exist. */ return (boolean) (dptr->num_dunlevs > 1 && dptr->entry_lev == dptr->num_dunlevs); } /* goto the next level (or appropriate dungeon) */ void next_level(at_stairs) boolean at_stairs; { if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) { /* Taking a down dungeon branch. */ goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE); } else { /* Going down a stairs or jump in a trap door. */ d_level newlevel; newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel + 1; goto_level(&newlevel, at_stairs, !at_stairs, FALSE); } } /* goto the previous level (or appropriate dungeon) */ void prev_level(at_stairs) boolean at_stairs; { if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) { /* Taking an up dungeon branch. */ /* KMH -- Upwards branches are okay if not level 1 */ /* (Just make sure it doesn't go above depth 1) */ if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED); else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE); } else { /* Going up a stairs or rising through the ceiling. */ d_level newlevel; newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel - 1; goto_level(&newlevel, at_stairs, FALSE, FALSE); } } void u_on_newpos(x, y) int x, y; { u.ux = x; u.uy = y; #ifdef CLIPPING cliparound(u.ux, u.uy); #endif /* ridden steed always shares hero's location */ if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy; /* when changing levels, don't leave old position set with stale values from previous level */ if (!on_level(&u.uz, &u.uz0)) u.ux0 = u.ux, u.uy0 = u.uy; } /* place you on a random location */ void u_on_rndspot(upflag) int upflag; { int up = (upflag & 1), was_in_W_tower = (upflag & 2); /* * Place the hero at a random location within the relevant region. * place_lregion(xTELE) -> put_lregion_here(xTELE) -> u_on_newpos() * Unspecified region (.lx == 0) defaults to entire level. */ if (was_in_W_tower && On_W_tower_level(&u.uz)) /* Stay inside the Wizard's tower when feasible. We use the W Tower's exclusion region for the destination instead of its enclosing region. Note: up vs down doesn't matter in this case because both specify the same exclusion area. */ place_lregion(dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, 0, 0, 0, 0, LR_DOWNTELE, (d_level *) 0); else if (up) place_lregion(updest.lx, updest.ly, updest.hx, updest.hy, updest.nlx, updest.nly, updest.nhx, updest.nhy, LR_UPTELE, (d_level *) 0); else place_lregion(dndest.lx, dndest.ly, dndest.hx, dndest.hy, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, LR_DOWNTELE, (d_level *) 0); } /* place you on the special staircase */ void u_on_sstairs(upflag) int upflag; { if (sstairs.sx) u_on_newpos(sstairs.sx, sstairs.sy); else u_on_rndspot(upflag); } /* place you on upstairs (or special equivalent) */ void u_on_upstairs() { if (xupstair) u_on_newpos(xupstair, yupstair); else u_on_sstairs(0); /* destination upstairs implies moving down */ } /* place you on dnstairs (or special equivalent) */ void u_on_dnstairs() { if (xdnstair) u_on_newpos(xdnstair, ydnstair); else u_on_sstairs(1); /* destination dnstairs implies moving up */ } boolean On_stairs(x, y) xchar x, y; { return (boolean) ((x == xupstair && y == yupstair) || (x == xdnstair && y == ydnstair) || (x == xdnladder && y == ydnladder) || (x == xupladder && y == yupladder) || (x == sstairs.sx && y == sstairs.sy)); } boolean Is_botlevel(lev) d_level *lev; { return (boolean) (lev->dlevel == dungeons[lev->dnum].num_dunlevs); } boolean Can_dig_down(lev) d_level *lev; { return (boolean) (!level.flags.hardfloor && !Is_botlevel(lev) && !Invocation_lev(lev)); } /* * Like Can_dig_down (above), but also allows falling through on the * stronghold level. Normally, the bottom level of a dungeon resists * both digging and falling. */ boolean Can_fall_thru(lev) d_level *lev; { return (boolean) (Can_dig_down(lev) || Is_stronghold(lev)); } /* * True if one can rise up a level (e.g. cursed gain level). * This happens on intermediate dungeon levels or on any top dungeon * level that has a stairwell style branch to the next higher dungeon. * Checks for amulets and such must be done elsewhere. */ boolean Can_rise_up(x, y, lev) int x, y; d_level *lev; { /* can't rise up from inside the top of the Wizard's tower */ /* KMH -- or in sokoban */ if (In_endgame(lev) || In_sokoban(lev) || (Is_wiz1_level(lev) && In_W_tower(x, y, lev))) return FALSE; return (boolean) (lev->dlevel > 1 || (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 && sstairs.sx && sstairs.up)); } boolean has_ceiling(lev) d_level *lev; { /* [what about level 1 of the quest?] */ return (boolean) (!Is_airlevel(lev) && !Is_waterlevel(lev)); } /* * It is expected that the second argument of get_level is a depth value, * either supplied by the user (teleport control) or randomly generated. * But more than one level can be at the same depth. If the target level * is "above" the present depth location, get_level must trace "up" from * the player's location (through the ancestors dungeons) the dungeon * within which the target level is located. With only one exception * which does not pass through this routine (see level_tele), teleporting * "down" is confined to the current dungeon. At present, level teleport * in dungeons that build up is confined within them. */ void get_level(newlevel, levnum) d_level *newlevel; int levnum; { branch *br; xchar dgn = u.uz.dnum; if (levnum <= 0) { /* can only currently happen in endgame */ levnum = u.uz.dlevel; } else if (levnum > dungeons[dgn].depth_start + dungeons[dgn].num_dunlevs - 1) { /* beyond end of dungeon, jump to last level */ levnum = dungeons[dgn].num_dunlevs; } else { /* The desired level is in this dungeon or a "higher" one. */ /* * Branch up the tree until we reach a dungeon that contains the * levnum. */ if (levnum < dungeons[dgn].depth_start) { do { /* * Find the parent dungeon of this dungeon. * * This assumes that end2 is always the "child" and it is * unique. */ for (br = branches; br; br = br->next) if (br->end2.dnum == dgn) break; if (!br) panic("get_level: can't find parent dungeon"); dgn = br->end1.dnum; } while (levnum < dungeons[dgn].depth_start); } /* We're within the same dungeon; calculate the level. */ levnum = levnum - dungeons[dgn].depth_start + 1; } newlevel->dnum = dgn; newlevel->dlevel = levnum; } /* are you in the quest dungeon? */ boolean In_quest(lev) d_level *lev; { return (boolean) (lev->dnum == quest_dnum); } /* are you in the mines dungeon? */ boolean In_mines(lev) d_level *lev; { return (boolean) (lev->dnum == mines_dnum); } /* * Return the branch for the given dungeon. * * This function assumes: * + This is not called with "Dungeons of Doom". * + There is only _one_ branch to a given dungeon. * + Field end2 is the "child" dungeon. */ branch * dungeon_branch(s) const char *s; { branch *br; xchar dnum; dnum = dname_to_dnum(s); /* Find the branch that connects to dungeon i's branch. */ for (br = branches; br; br = br->next) if (br->end2.dnum == dnum) break; if (!br) panic("dgn_entrance: can't find entrance to %s", s); return br; } /* * This returns true if the hero is on the same level as the entrance to * the named dungeon. * * Called from do.c and mklev.c. * * Assumes that end1 is always the "parent". */ boolean at_dgn_entrance(s) const char *s; { branch *br; br = dungeon_branch(s); return on_level(&u.uz, &br->end1) ? TRUE : FALSE; } /* is `lev' part of Vlad's tower? */ boolean In_V_tower(lev) d_level *lev; { return (boolean) (lev->dnum == tower_dnum); } /* is `lev' a level containing the Wizard's tower? */ boolean On_W_tower_level(lev) d_level *lev; { return (boolean) (Is_wiz1_level(lev) || Is_wiz2_level(lev) || Is_wiz3_level(lev)); } /* is of `lev' inside the Wizard's tower? */ boolean In_W_tower(x, y, lev) int x, y; d_level *lev; { if (!On_W_tower_level(lev)) return FALSE; /* * Both of the exclusion regions for arriving via level teleport * (from above or below) define the tower's boundary. * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} ); */ if (dndest.nlx > 0) return (boolean) within_bounded_area(x, y, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy); else impossible("No boundary for Wizard's Tower?"); return FALSE; } /* are you in one of the Hell levels? */ boolean In_hell(lev) d_level *lev; { return (boolean) (dungeons[lev->dnum].flags.hellish); } /* sets *lev to be the gateway to Gehennom... */ void find_hell(lev) d_level *lev; { lev->dnum = valley_level.dnum; lev->dlevel = 1; } /* go directly to hell... */ void goto_hell(at_stairs, falling) boolean at_stairs, falling; { d_level lev; find_hell(&lev); goto_level(&lev, at_stairs, falling, FALSE); } /* equivalent to dest = source */ void assign_level(dest, src) d_level *dest, *src; { dest->dnum = src->dnum; dest->dlevel = src->dlevel; } /* dest = src + rn1(range) */ void assign_rnd_level(dest, src, range) d_level *dest, *src; int range; { dest->dnum = src->dnum; dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)); if (dest->dlevel > dunlevs_in_dungeon(dest)) dest->dlevel = dunlevs_in_dungeon(dest); else if (dest->dlevel < 1) dest->dlevel = 1; } int induced_align(pct) int pct; { s_level *lev = Is_special(&u.uz); aligntyp al; if (lev && lev->flags.align) if (rn2(100) < pct) return lev->flags.align; if (dungeons[u.uz.dnum].flags.align) if (rn2(100) < pct) return dungeons[u.uz.dnum].flags.align; al = rn2(3) - 1; return Align2amask(al); } boolean Invocation_lev(lev) d_level *lev; { return (boolean) (In_hell(lev) && lev->dlevel == dungeons[lev->dnum].num_dunlevs - 1); } /* use instead of depth() wherever a degree of difficulty is made * dependent on the location in the dungeon (eg. monster creation). */ xchar level_difficulty() { int res; if (In_endgame(&u.uz)) { res = depth(&sanctum_level) + u.ulevel / 2; } else if (u.uhave.amulet) { res = deepest_lev_reached(FALSE); } else { res = depth(&u.uz); /* depth() is the number of elevation units (levels) below the theoretical surface; in a builds-up branch, that value ends up making the harder to reach levels be treated as if they were easier; adjust for the extra effort involved in going down to the entrance and then up to the location */ if (builds_up(&u.uz)) res += 2 * (dungeons[u.uz.dnum].entry_lev - u.uz.dlevel + 1); /* * 'Proof' by example: suppose the entrance to sokoban is * on dungeon level 9, leading up to bottom sokoban level * of 8 [entry_lev]. When the hero is on sokoban level 8 * [uz.dlevel], depth() yields eight but he has ventured * one level beyond 9, so difficulty depth should be 10: * 8 + 2 * (8 - 8 + 1) => 10. * Going up to 7, depth is 7 but hero will be two beyond 9: * 7 + 2 * (8 - 7 + 1) => 11. * When he goes up to level 6, three levels beyond 9: * 6 + 2 * (8 - 6 + 1) => 12. * And the top level of sokoban at 5, four levels beyond 9: * 5 + 2 * (8 - 5 + 1) => 13. * The same applies to Vlad's Tower, although the increment * there is inconsequential compared to overall depth. */ } return (xchar) res; } /* Take one word and try to match it to a level. * Recognized levels are as shown by print_dungeon(). */ schar lev_by_name(nam) const char *nam; { schar lev = 0; s_level *slev; d_level dlev; const char *p; int idx, idxtoo; char buf[BUFSZ]; /* allow strings like "the oracle level" to find "oracle" */ if (!strncmpi(nam, "the ", 4)) nam += 4; if ((p = strstri(nam, " level")) != 0 && p == eos((char *) nam) - 6) { nam = strcpy(buf, nam); *(eos(buf) - 6) = '\0'; } /* hell is the old name, and wouldn't match; gehennom would match its branch, yielding the castle level instead of the valley of the dead */ if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) { if (In_V_tower(&u.uz)) nam = " to Vlad's tower"; /* branch to... */ else nam = "valley"; } if ((slev = find_level(nam)) != 0) { dlev = slev->dlevel; idx = ledger_no(&dlev); if ((dlev.dnum == u.uz.dnum /* within same branch, or else main dungeon <-> gehennom */ || (u.uz.dnum == valley_level.dnum && dlev.dnum == medusa_level.dnum) || (u.uz.dnum == medusa_level.dnum && dlev.dnum == valley_level.dnum)) && (/* either wizard mode or else seen and not forgotten */ wizard || (level_info[idx].flags & (FORGOTTEN | VISITED)) == VISITED)) { lev = depth(&slev->dlevel); } } else { /* not a specific level; try branch names */ idx = find_branch(nam, (struct proto_dungeon *) 0); /* " to Xyzzy" */ if (idx < 0 && (p = strstri(nam, " to ")) != 0) idx = find_branch(p + 4, (struct proto_dungeon *) 0); if (idx >= 0) { idxtoo = (idx >> 8) & 0x00FF; idx &= 0x00FF; if (/* either wizard mode, or else _both_ sides of branch seen */ wizard || ((level_info[idx].flags & (FORGOTTEN | VISITED)) == VISITED && (level_info[idxtoo].flags & (FORGOTTEN | VISITED)) == VISITED)) { if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo; dlev.dnum = ledger_to_dnum(idx); dlev.dlevel = ledger_to_dlev(idx); lev = depth(&dlev); } } } return lev; } STATIC_OVL boolean unplaced_floater(dptr) struct dungeon *dptr; { branch *br; int idx = (int) (dptr - dungeons); /* if other floating branches are added, this will need to change */ if (idx != knox_level.dnum) return FALSE; for (br = branches; br; br = br->next) if (br->end1.dnum == n_dgns && br->end2.dnum == idx) return TRUE; return FALSE; } STATIC_OVL boolean unreachable_level(lvl_p, unplaced) d_level *lvl_p; boolean unplaced; { s_level *dummy; if (unplaced) return TRUE; if (In_endgame(&u.uz) && !In_endgame(lvl_p)) return TRUE; if ((dummy = find_level("dummy")) != 0 && on_level(lvl_p, &dummy->dlevel)) return TRUE; return FALSE; } static void tport_menu(win, entry, lchoices, lvl_p, unreachable) winid win; char *entry; struct lchoice *lchoices; d_level *lvl_p; boolean unreachable; { char tmpbuf[BUFSZ]; anything any; lchoices->lev[lchoices->idx] = lvl_p->dlevel; lchoices->dgn[lchoices->idx] = lvl_p->dnum; lchoices->playerlev[lchoices->idx] = depth(lvl_p); any = zeroany; if (unreachable) { /* not selectable, but still consumes next menuletter; prepend padding in place of missing menu selector */ Sprintf(tmpbuf, " %s", entry); entry = tmpbuf; } else { any.a_int = lchoices->idx + 1; } add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 0, ATR_NONE, entry, MENU_UNSELECTED); /* this assumes there are at most 52 interesting levels */ if (lchoices->menuletter == 'z') lchoices->menuletter = 'A'; else lchoices->menuletter++; lchoices->idx++; return; } /* Convert a branch type to a string usable by print_dungeon(). */ STATIC_OVL const char * br_string(type) int type; { switch (type) { case BR_PORTAL: return "Portal"; case BR_NO_END1: return "Connection"; case BR_NO_END2: return "One way stair"; case BR_STAIR: return "Stair"; } return " (unknown)"; } /* Print all child branches between the lower and upper bounds. */ STATIC_OVL void print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices_p) winid win; int dnum; int lower_bound; int upper_bound; boolean bymenu; struct lchoice *lchoices_p; { branch *br; char buf[BUFSZ]; /* This assumes that end1 is the "parent". */ for (br = branches; br; br = br->next) { if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel && br->end1.dlevel <= upper_bound) { Sprintf(buf, " %s to %s: %d", br_string(br->type), dungeons[br->end2.dnum].dname, depth(&br->end1)); if (bymenu) tport_menu(win, buf, lchoices_p, &br->end1, unreachable_level(&br->end1, FALSE)); else putstr(win, 0, buf); } } } /* Print available dungeon information. */ schar print_dungeon(bymenu, rlev, rdgn) boolean bymenu; schar *rlev; xchar *rdgn; { int i, last_level, nlev; char buf[BUFSZ]; const char *descr; boolean first, unplaced; s_level *slev; dungeon *dptr; branch *br; anything any; struct lchoice lchoices; winid win = create_nhwindow(NHW_MENU); if (bymenu) { start_menu(win); lchoices.idx = 0; lchoices.menuletter = 'a'; } for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) { if (bymenu && In_endgame(&u.uz) && i != astral_level.dnum) continue; unplaced = unplaced_floater(dptr); descr = unplaced ? "depth" : "level"; nlev = dptr->num_dunlevs; if (nlev > 1) Sprintf(buf, "%s: %s %d to %d", dptr->dname, makeplural(descr), dptr->depth_start, dptr->depth_start + nlev - 1); else Sprintf(buf, "%s: %s %d", dptr->dname, descr, dptr->depth_start); /* Most entrances are uninteresting. */ if (dptr->entry_lev != 1) { if (dptr->entry_lev == nlev) Strcat(buf, ", entrance from below"); else Sprintf(eos(buf), ", entrance on %d", dptr->depth_start + dptr->entry_lev - 1); } if (bymenu) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED); } else putstr(win, 0, buf); /* * Circle through the special levels to find levels that are in * this dungeon. */ for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) { if (slev->dlevel.dnum != i) continue; /* print any branches before this level */ print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &lchoices); Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel)); if (Is_stronghold(&slev->dlevel)) Sprintf(eos(buf), " (tune %s)", tune); if (bymenu) tport_menu(win, buf, &lchoices, &slev->dlevel, unreachable_level(&slev->dlevel, unplaced)); else putstr(win, 0, buf); last_level = slev->dlevel.dlevel; } /* print branches after the last special level */ print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices); } if (bymenu) { int n; menu_item *selected; int idx; end_menu(win, "Level teleport to where:"); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n > 0) { idx = selected[0].item.a_int - 1; free((genericptr_t) selected); if (rlev && rdgn) { *rlev = lchoices.lev[idx]; *rdgn = lchoices.dgn[idx]; return lchoices.playerlev[idx]; } } return 0; } /* Print out floating branches (if any). */ for (first = TRUE, br = branches; br; br = br->next) { if (br->end1.dnum == n_dgns) { if (first) { putstr(win, 0, ""); putstr(win, 0, "Floating branches"); first = FALSE; } Sprintf(buf, " %s to %s", br_string(br->type), dungeons[br->end2.dnum].dname); putstr(win, 0, buf); } } /* I hate searching for the invocation pos while debugging. -dean */ if (Invocation_lev(&u.uz)) { putstr(win, 0, ""); Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)", inv_pos.x, inv_pos.y, u.ux, u.uy); putstr(win, 0, buf); } /* * The following is based on the assumption that the inter-level portals * created by the level compiler (not the dungeon compiler) only exist * one per level (currently true, of course). */ else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz) || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) { struct trap *trap; for (trap = ftrap; trap; trap = trap->ntrap) if (trap->ttyp == MAGIC_PORTAL) break; putstr(win, 0, ""); if (trap) Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", trap->tx, trap->ty, u.ux, u.uy); else Sprintf(buf, "No portal found."); putstr(win, 0, buf); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } /* Record that the player knows about a branch from a level. This function * will determine whether or not it was a "real" branch that was taken. * This function should not be called for a transition done via level * teleport or via the Eye. */ void recbranch_mapseen(source, dest) d_level *source; d_level *dest; { mapseen *mptr; branch *br; /* not a branch */ if (source->dnum == dest->dnum) return; /* we only care about forward branches */ for (br = branches; br; br = br->next) { if (on_level(source, &br->end1) && on_level(dest, &br->end2)) break; if (on_level(source, &br->end2) && on_level(dest, &br->end1)) return; } /* branch not found, so not a real branch. */ if (!br) return; if ((mptr = find_mapseen(source)) != 0) { if (mptr->br && br != mptr->br) impossible("Two branches on the same level?"); mptr->br = br; } else { impossible("Can't note branch for unseen level (%d, %d)", source->dnum, source->dlevel); } } char * get_annotation(lev) d_level *lev; { mapseen *mptr; if ((mptr = find_mapseen(lev))) return mptr->custom; return NULL; } /* #annotate command - add a custom name to the current level */ int donamelevel() { mapseen *mptr; char nbuf[BUFSZ]; /* Buffer for response */ if (!(mptr = find_mapseen(&u.uz))) return 0; if (mptr->custom) { char tmpbuf[BUFSZ]; Sprintf(tmpbuf, "Replace annotation \"%.30s%s\" with?", mptr->custom, strlen(mptr->custom) > 30 ? "..." : ""); getlin(tmpbuf, nbuf); } else getlin("What do you want to call this dungeon level?", nbuf); if (index(nbuf, '\033')) return 0; (void) mungspaces(nbuf); /* discard old annotation, if any */ if (mptr->custom) { free((genericptr_t) mptr->custom); mptr->custom = (char *) 0; mptr->custom_lth = 0; } /* add new annotation, unless it's empty or a single space */ if (*nbuf && strcmp(nbuf, " ")) { mptr->custom = dupstr(nbuf); mptr->custom_lth = strlen(mptr->custom); } return 0; } /* find the particular mapseen object in the chain; may return null */ STATIC_OVL mapseen * find_mapseen(lev) d_level *lev; { mapseen *mptr; for (mptr = mapseenchn; mptr; mptr = mptr->next) if (on_level(&(mptr->lev), lev)) break; return mptr; } void forget_mapseen(ledger_num) int ledger_num; { mapseen *mptr; struct cemetery *bp; for (mptr = mapseenchn; mptr; mptr = mptr->next) if (dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel == ledger_num) break; /* if not found, then nothing to forget */ if (mptr) { mptr->flags.forgot = 1; mptr->br = (branch *) 0; /* custom names are erased, not just forgotten until revisited */ if (mptr->custom) { mptr->custom_lth = 0; free((genericptr_t) mptr->custom); mptr->custom = (char *) 0; } (void) memset((genericptr_t) mptr->msrooms, 0, sizeof mptr->msrooms); for (bp = mptr->final_resting_place; bp; bp = bp->next) bp->bonesknown = FALSE; } } STATIC_OVL void save_mapseen(fd, mptr) int fd; mapseen *mptr; { branch *curr; int brindx; for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx) if (curr == mptr->br) break; bwrite(fd, (genericptr_t) &brindx, sizeof brindx); bwrite(fd, (genericptr_t) &mptr->lev, sizeof mptr->lev); bwrite(fd, (genericptr_t) &mptr->feat, sizeof mptr->feat); bwrite(fd, (genericptr_t) &mptr->flags, sizeof mptr->flags); bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof mptr->custom_lth); if (mptr->custom_lth) bwrite(fd, (genericptr_t) mptr->custom, mptr->custom_lth); bwrite(fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms); savecemetery(fd, WRITE_SAVE, &mptr->final_resting_place); } STATIC_OVL mapseen * load_mapseen(fd) int fd; { int branchnum, brindx; mapseen *load; branch *curr; load = (mapseen *) alloc(sizeof *load); mread(fd, (genericptr_t) &branchnum, sizeof branchnum); for (brindx = 0, curr = branches; curr; curr = curr->next, ++brindx) if (brindx == branchnum) break; load->br = curr; mread(fd, (genericptr_t) &load->lev, sizeof load->lev); mread(fd, (genericptr_t) &load->feat, sizeof load->feat); mread(fd, (genericptr_t) &load->flags, sizeof load->flags); mread(fd, (genericptr_t) &load->custom_lth, sizeof load->custom_lth); if (load->custom_lth) { /* length doesn't include terminator (which isn't saved & restored) */ load->custom = (char *) alloc(load->custom_lth + 1); mread(fd, (genericptr_t) load->custom, load->custom_lth); load->custom[load->custom_lth] = '\0'; } else load->custom = 0; mread(fd, (genericptr_t) &load->msrooms, sizeof load->msrooms); restcemetery(fd, &load->final_resting_place); return load; } /* Remove all mapseen objects for a particular dnum. * Useful during quest expulsion to remove quest levels. * [No longer deleted, just marked as unreachable. #overview will * ignore such levels, end of game disclosure will include them.] */ void remdun_mapseen(dnum) int dnum; { mapseen *mptr, **mptraddr; mptraddr = &mapseenchn; while ((mptr = *mptraddr) != 0) { if (mptr->lev.dnum == dnum) { #if 1 /* use this... */ mptr->flags.unreachable = 1; } #else /* old deletion code */ *mptraddr = mptr->next; if (mptr->custom) free((genericptr_t) mptr->custom); if (mptr->final_resting_place) savecemetery(-1, FREE_SAVE, &mptr->final_resting_place); free((genericptr_t) mptr); } else #endif mptraddr = &mptr->next; } } void init_mapseen(lev) d_level *lev; { /* Create a level and insert in "sorted" order. This is an insertion * sort first by dungeon (in order of discovery) and then by level number. */ mapseen *mptr, *init, *prev; init = (mapseen *) alloc(sizeof *init); (void) memset((genericptr_t) init, 0, sizeof *init); /* memset is fine for feature bits, flags, and rooms array; explicitly initialize pointers to null */ init->next = 0, init->br = 0, init->custom = 0; init->final_resting_place = 0; /* lastseentyp[][] is reused for each level, so get rid of previous level's data */ (void) memset((genericptr_t) lastseentyp, 0, sizeof lastseentyp); init->lev.dnum = lev->dnum; init->lev.dlevel = lev->dlevel; /* walk until we get to the place where we should insert init */ for (mptr = mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next) if (mptr->lev.dnum > init->lev.dnum || (mptr->lev.dnum == init->lev.dnum && mptr->lev.dlevel > init->lev.dlevel)) break; if (!prev) { init->next = mapseenchn; mapseenchn = init; } else { mptr = prev->next; prev->next = init; init->next = mptr; } } #define INTEREST(feat) \ ((feat).nfount || (feat).nsink || (feat).nthrone || (feat).naltar \ || (feat).ngrave || (feat).ntree || (feat).nshop || (feat).ntemple) /* || (feat).water || (feat).ice || (feat).lava */ /* returns true if this level has something interesting to print out */ STATIC_OVL boolean interest_mapseen(mptr) mapseen *mptr; { if (on_level(&u.uz, &mptr->lev)) return TRUE; if (mptr->flags.unreachable || mptr->flags.forgot) return FALSE; /* level is of interest if it has an auto-generated annotation */ if (mptr->flags.oracle || mptr->flags.bigroom || mptr->flags.roguelevel || mptr->flags.castle || mptr->flags.valley || mptr->flags.msanctum || mptr->flags.quest_summons || mptr->flags.questing) return TRUE; /* when in Sokoban, list all sokoban levels visited; when not in it, list any visited Sokoban level which remains unsolved (will usually only be furthest one reached, but it's possible to enter pits and climb out on the far side on the first Sokoban level; also, wizard mode overrides teleport restrictions) */ if (In_sokoban(&mptr->lev) && (In_sokoban(&u.uz) || !mptr->flags.sokosolved)) return TRUE; /* when in the endgame, list all endgame levels visited, whether they have annotations or not, so that #overview doesn't become extremely sparse once the rest of the dungeon has been flagged as unreachable */ if (In_endgame(&u.uz)) return (boolean) In_endgame(&mptr->lev); /* level is of interest if it has non-zero feature count or known bones or user annotation or known connection to another dungeon branch or is the furthest level reached in its branch */ return (boolean) (INTEREST(mptr->feat) || (mptr->final_resting_place && (mptr->flags.knownbones || wizard)) || mptr->custom || mptr->br || (mptr->lev.dlevel == dungeons[mptr->lev.dnum].dunlev_ureached)); } /* recalculate mapseen for the current level */ void recalc_mapseen() { mapseen *mptr; struct monst *mtmp; struct cemetery *bp, **bonesaddr; unsigned i, ridx; int x, y, ltyp, count, atmp; /* Should not happen in general, but possible if in the process * of being booted from the quest. The mapseen object gets * removed during the expulsion but prior to leaving the level * [Since quest expulsion no longer deletes quest mapseen data, * null return from find_mapseen() should now be impossible.] */ if (!(mptr = find_mapseen(&u.uz))) return; /* reset all features; mptr->feat.* = 0; */ (void) memset((genericptr_t) &mptr->feat, 0, sizeof mptr->feat); /* reset most flags; some level-specific ones are left as-is */ if (mptr->flags.unreachable) { mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */ if (In_quest(&u.uz)) { mapseen *mptrtmp = mapseenchn; /* when quest was unreachable due to ejection and portal removal, getting back to it via arti-invoke should revive annotation data for all quest levels, not just the one we're on now */ do { if (mptrtmp->lev.dnum == mptr->lev.dnum) mptrtmp->flags.unreachable = 0; mptrtmp = mptrtmp->next; } while (mptrtmp); } } mptr->flags.knownbones = 0; mptr->flags.sokosolved = In_sokoban(&u.uz) && !Sokoban; /* mptr->flags.bigroom retains previous value when hero can't see */ if (!Blind) mptr->flags.bigroom = Is_bigroom(&u.uz); else if (mptr->flags.forgot) mptr->flags.bigroom = 0; mptr->flags.roguelevel = Is_rogue_level(&u.uz); mptr->flags.oracle = 0; /* recalculated during room traversal below */ mptr->flags.castletune = 0; /* flags.castle, flags.valley, flags.msanctum retain previous value */ mptr->flags.forgot = 0; /* flags.quest_summons disabled once quest finished */ mptr->flags.quest_summons = (at_dgn_entrance("The Quest") && u.uevent.qcalled && !(u.uevent.qcompleted || u.uevent.qexpelled || quest_status.leader_is_dead)); mptr->flags.questing = (on_level(&u.uz, &qstart_level) && quest_status.got_quest); /* track rooms the hero is in */ for (i = 0; i < SIZE(u.urooms); ++i) { if (!u.urooms[i]) continue; ridx = u.urooms[i] - ROOMOFFSET; mptr->msrooms[ridx].seen = 1; mptr->msrooms[ridx].untended = (rooms[ridx].rtype >= SHOPBASE) ? (!(mtmp = shop_keeper(u.urooms[i])) || !inhishop(mtmp)) : (rooms[ridx].rtype == TEMPLE) ? (!(mtmp = findpriest(u.urooms[i])) || !inhistemple(mtmp)) : 0; } /* recalculate room knowledge: for now, just shops and temples * this could be extended to an array of 0..SHOPBASE */ for (i = 0; i < SIZE(mptr->msrooms); ++i) { if (mptr->msrooms[i].seen) { if (rooms[i].rtype >= SHOPBASE) { if (mptr->msrooms[i].untended) mptr->feat.shoptype = SHOPBASE - 1; else if (!mptr->feat.nshop) mptr->feat.shoptype = rooms[i].rtype; else if (mptr->feat.shoptype != (unsigned) rooms[i].rtype) mptr->feat.shoptype = 0; count = mptr->feat.nshop + 1; if (count <= 3) mptr->feat.nshop = count; } else if (rooms[i].rtype == TEMPLE) { /* altar and temple alignment handled below */ count = mptr->feat.ntemple + 1; if (count <= 3) mptr->feat.ntemple = count; } else if (rooms[i].orig_rtype == DELPHI) { mptr->flags.oracle = 1; } } } /* Update lastseentyp with typ if and only if it is in sight or the * hero can feel it on their current location (i.e. not levitating). * This *should* give the "last known typ" for each dungeon location. * (At the very least, it's a better assumption than determining what * the player knows from the glyph and the typ (which is isn't quite * enough information in some cases)). * * It was reluctantly added to struct rm to track. Alternatively * we could track "features" and then update them all here, and keep * track of when new features are created or destroyed, but this * seemed the most elegant, despite adding more data to struct rm. * [3.6.0: we're using lastseentyp[][] rather than level.locations * to track the features seen.] * * Although no current windowing systems (can) do this, this would add * the ability to have non-dungeon glyphs float above the last known * dungeon glyph (i.e. items on fountains). */ for (x = 1; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) { ltyp = levl[x][y].typ; if (ltyp == DRAWBRIDGE_UP) ltyp = db_under_typ(levl[x][y].drawbridgemask); if ((mtmp = m_at(x, y)) != 0 && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp)) ltyp = cmap_to_type(mtmp->mappearance); lastseentyp[x][y] = ltyp; } switch (lastseentyp[x][y]) { #if 0 case ICE: count = mptr->feat.ice + 1; if (count <= 3) mptr->feat.ice = count; break; case POOL: case MOAT: case WATER: count = mptr->feat.water + 1; if (count <= 3) mptr->feat.water = count; break; case LAVAPOOL: count = mptr->feat.lava + 1; if (count <= 3) mptr->feat.lava = count; break; #endif case TREE: count = mptr->feat.ntree + 1; if (count <= 3) mptr->feat.ntree = count; break; case FOUNTAIN: count = mptr->feat.nfount + 1; if (count <= 3) mptr->feat.nfount = count; break; case THRONE: count = mptr->feat.nthrone + 1; if (count <= 3) mptr->feat.nthrone = count; break; case SINK: count = mptr->feat.nsink + 1; if (count <= 3) mptr->feat.nsink = count; break; case GRAVE: count = mptr->feat.ngrave + 1; if (count <= 3) mptr->feat.ngrave = count; break; case ALTAR: atmp = (Is_astralevel(&u.uz) && (levl[x][y].seenv & SVALL) != SVALL) ? MSA_NONE : Amask2msa(levl[x][y].altarmask); if (!mptr->feat.naltar) mptr->feat.msalign = atmp; else if (mptr->feat.msalign != atmp) mptr->feat.msalign = MSA_NONE; count = mptr->feat.naltar + 1; if (count <= 3) mptr->feat.naltar = count; break; /* An automatic annotation is added to the Castle and * to Fort Ludios once their structure's main entrance * has been seen (in person or via magic mapping). * DOOR: possibly a lowered drawbridge's open portcullis; * DBWALL: a raised drawbridge's "closed door"; * DRAWBRIDGE_DOWN: the span provided by lowered bridge, * with moat or other terrain hidden underneath; * DRAWBRIDGE_UP: moat in front of a raised drawbridge, * not recognizable as a bridge location unless/until * the adjacent DBWALL has been seen. */ case DOOR: if (is_drawbridge_wall(x, y) < 0) break; /* else FALLTHRU */ case DBWALL: case DRAWBRIDGE_DOWN: if (Is_stronghold(&u.uz)) mptr->flags.castle = 1, mptr->flags.castletune = 1; else if (Is_knox(&u.uz)) mptr->flags.ludios = 1; break; default: break; } } } if (level.bonesinfo && !mptr->final_resting_place) { /* clone the bonesinfo so we aren't dependent upon this level being in memory */ bonesaddr = &mptr->final_resting_place; bp = level.bonesinfo; do { *bonesaddr = (struct cemetery *) alloc(sizeof **bonesaddr); **bonesaddr = *bp; bp = bp->next; bonesaddr = &(*bonesaddr)->next; } while (bp); *bonesaddr = 0; } /* decide which past hero deaths have become known; there's no guarantee of either a grave or a ghost, so we go by whether the current hero has seen the map location where each old one died */ for (bp = mptr->final_resting_place; bp; bp = bp->next) if (lastseentyp[bp->frpx][bp->frpy]) { bp->bonesknown = TRUE; mptr->flags.knownbones = 1; } } /*ARGUSED*/ /* valley and sanctum levels get automatic annotation once temple is entered */ void mapseen_temple(priest) struct monst *priest UNUSED; /* currently unused; might be useful someday */ { mapseen *mptr = find_mapseen(&u.uz); if (Is_valley(&u.uz)) mptr->flags.valley = 1; else if (Is_sanctum(&u.uz)) mptr->flags.msanctum = 1; } /* room entry message has just been delivered so learn room even if blind */ void room_discovered(roomno) int roomno; { mapseen *mptr = find_mapseen(&u.uz); mptr->msrooms[roomno].seen = 1; } /* #overview command */ int dooverview() { show_overview(0, 0); return 0; } /* called for #overview or for end of game disclosure */ void show_overview(why, reason) int why; /* 0 => #overview command, 1 or 2 => final disclosure (1: hero lived, 2: hero died) */ int reason; /* how hero died; used when disclosing end-of-game level */ { winid win; int lastdun = -1; /* lazy initialization */ (void) recalc_mapseen(); win = create_nhwindow(NHW_MENU); /* show the endgame levels before the rest of the dungeon, so that the Planes (dnum 5-ish) come out above main dungeon (dnum 0) */ if (In_endgame(&u.uz)) traverse_mapseenchn(TRUE, win, why, reason, &lastdun); /* if game is over or we're not in the endgame yet, show the dungeon */ if (why > 0 || !In_endgame(&u.uz)) traverse_mapseenchn(FALSE, win, why, reason, &lastdun); display_nhwindow(win, TRUE); destroy_nhwindow(win); } /* display endgame levels or non-endgame levels, not both */ STATIC_OVL void traverse_mapseenchn(viewendgame, win, why, reason, lastdun_p) boolean viewendgame; winid win; int why, reason, *lastdun_p; { mapseen *mptr; boolean showheader; for (mptr = mapseenchn; mptr; mptr = mptr->next) { if (viewendgame ^ In_endgame(&mptr->lev)) continue; /* only print out info for a level or a dungeon if interest */ if (why > 0 || interest_mapseen(mptr)) { showheader = (boolean) (mptr->lev.dnum != *lastdun_p); print_mapseen(win, mptr, why, reason, showheader); *lastdun_p = mptr->lev.dnum; } } } STATIC_OVL const char * seen_string(x, obj) xchar x; const char *obj; { /* players are computer scientists: 0, 1, 2, n */ switch (x) { case 0: return "no"; /* an() returns too much. index is ok in this case */ case 1: return index(vowels, *obj) ? "an" : "a"; case 2: return "some"; case 3: return "many"; } return "(unknown)"; } /* better br_string */ STATIC_OVL const char * br_string2(br) branch *br; { /* Special case: quest portal says closed if kicked from quest */ boolean closed_portal = (br->end2.dnum == quest_dnum && u.uevent.qexpelled); switch (br->type) { case BR_PORTAL: return closed_portal ? "Sealed portal" : "Portal"; case BR_NO_END1: return "Connection"; case BR_NO_END2: return br->end1_up ? "One way stairs up" : "One way stairs down"; case BR_STAIR: return br->end1_up ? "Stairs up" : "Stairs down"; } return "(unknown)"; } /* get the name of an endgame level; topten.c does something similar */ STATIC_OVL const char * endgamelevelname(outbuf, indx) char *outbuf; int indx; { const char *planename = 0; *outbuf = '\0'; switch (indx) { case -5: Strcpy(outbuf, "Astral Plane"); break; case -4: planename = "Water"; break; case -3: planename = "Fire"; break; case -2: planename = "Air"; break; case -1: planename = "Earth"; break; } if (planename) Sprintf(outbuf, "Plane of %s", planename); else if (!*outbuf) Sprintf(outbuf, "unknown plane #%d", indx); return outbuf; } STATIC_OVL const char * shop_string(rtype) int rtype; { const char *str = "shop"; /* catchall */ /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */ switch (rtype) { case SHOPBASE - 1: str = "untended shop"; break; /* see recalc_mapseen */ case SHOPBASE: str = "general store"; break; case ARMORSHOP: str = "armor shop"; break; case SCROLLSHOP: str = "scroll shop"; break; case POTIONSHOP: str = "potion shop"; break; case WEAPONSHOP: str = "weapon shop"; break; case FOODSHOP: str = "delicatessen"; break; case RINGSHOP: str = "jewelers"; break; case WANDSHOP: str = "wand shop"; break; case BOOKSHOP: str = "bookstore"; break; case FODDERSHOP: str = "health food store"; break; case CANDLESHOP: str = "lighting shop"; break; default: break; } return str; } /* if player knows about the mastermind tune, append it to Castle annotation; if drawbridge has been destroyed, flags.castletune will be zero */ STATIC_OVL char * tunesuffix(mptr, outbuf) mapseen *mptr; char *outbuf; { *outbuf = '\0'; if (mptr->flags.castletune && u.uevent.uheard_tune) { char tmp[BUFSZ]; if (u.uevent.uheard_tune == 2) Sprintf(tmp, "notes \"%s\"", tune); else Strcpy(tmp, "5-note tune"); Sprintf(outbuf, " (play %s to open or close drawbridge)", tmp); } return outbuf; } /* some utility macros for print_mapseen */ #define TAB " " /* three spaces */ #if 0 #define BULLET "" /* empty; otherwise output becomes cluttered */ #define PREFIX TAB TAB BULLET #else /*!0*/ /* K&R: don't require support for concatenation of adjacent string literals */ #define PREFIX " " /* two TABs + empty BULLET: six spaces */ #endif #define COMMA (i++ > 0 ? ", " : PREFIX) /* "iterate" once; safe to use as ``if (cond) ADDTOBUF(); else whatever;'' */ #define ADDNTOBUF(nam, var) \ do { \ if (var) \ Sprintf(eos(buf), "%s%s %s%s", COMMA, seen_string((var), (nam)), \ (nam), plur(var)); \ } while (0) #define ADDTOBUF(nam, var) \ do { \ if (var) \ Sprintf(eos(buf), "%s%s", COMMA, (nam)); \ } while (0) STATIC_OVL void print_mapseen(win, mptr, final, how, printdun) winid win; mapseen *mptr; int final; /* 0: not final; 1: game over, alive; 2: game over, dead */ int how; /* cause of death; only used if final==2 and mptr->lev==u.uz */ boolean printdun; { char buf[BUFSZ], tmpbuf[BUFSZ]; int i, depthstart, dnum; boolean died_here = (final == 2 && on_level(&u.uz, &mptr->lev)); /* Damnable special cases */ /* The quest and knox should appear to be level 1 to match * other text. */ dnum = mptr->lev.dnum; if (dnum == quest_dnum || dnum == knox_level.dnum) depthstart = 1; else depthstart = dungeons[dnum].depth_start; if (printdun) { if (dungeons[dnum].dunlev_ureached == dungeons[dnum].entry_lev /* suppress the negative numbers in the endgame */ || In_endgame(&mptr->lev)) Sprintf(buf, "%s:", dungeons[dnum].dname); else if (builds_up(&mptr->lev)) Sprintf(buf, "%s: levels %d up to %d", dungeons[dnum].dname, depthstart + dungeons[dnum].entry_lev - 1, depthstart + dungeons[dnum].dunlev_ureached - 1); else Sprintf(buf, "%s: levels %d to %d", dungeons[dnum].dname, depthstart, depthstart + dungeons[dnum].dunlev_ureached - 1); putstr(win, !final ? ATR_INVERSE : 0, buf); } /* calculate level number */ i = depthstart + mptr->lev.dlevel - 1; if (In_endgame(&mptr->lev)) Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i)); else /* FIXME: when this branch has only one level (Ft.Ludios), * listing "Level 1:" for it might confuse inexperienced * players into thinking there's more than one. */ Sprintf(buf, "%sLevel %d:", TAB, i); /* wizmode prints out proto dungeon names for clarity */ if (wizard) { s_level *slev; if ((slev = Is_special(&mptr->lev)) != 0) Sprintf(eos(buf), " [%s]", slev->proto); } /* [perhaps print custom annotation on its own line when it's long] */ if (mptr->custom) Sprintf(eos(buf), " (%s)", mptr->custom); if (on_level(&u.uz, &mptr->lev)) Sprintf(eos(buf), " <- You %s here.", (!final || (final == 1 && how == ASCENDED)) ? "are" : "were"); putstr(win, !final ? ATR_BOLD : 0, buf); if (mptr->flags.forgot) return; if (INTEREST(mptr->feat)) { buf[0] = 0; i = 0; /* interest counter */ /* List interests in an order vaguely corresponding to * how important they are. */ if (mptr->feat.nshop > 0) { if (mptr->feat.nshop > 1) ADDNTOBUF("shop", mptr->feat.nshop); else Sprintf(eos(buf), "%s%s", COMMA, an(shop_string(mptr->feat.shoptype))); } if (mptr->feat.naltar > 0) { /* Temples + non-temple altars get munged into just "altars" */ if (mptr->feat.ntemple != mptr->feat.naltar) ADDNTOBUF("altar", mptr->feat.naltar); else ADDNTOBUF("temple", mptr->feat.ntemple); /* only print out altar's god if they are all to your god */ if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type) Sprintf(eos(buf), " to %s", align_gname(u.ualign.type)); } ADDNTOBUF("throne", mptr->feat.nthrone); ADDNTOBUF("fountain", mptr->feat.nfount); ADDNTOBUF("sink", mptr->feat.nsink); ADDNTOBUF("grave", mptr->feat.ngrave); ADDNTOBUF("tree", mptr->feat.ntree); #if 0 ADDTOBUF("water", mptr->feat.water); ADDTOBUF("lava", mptr->feat.lava); ADDTOBUF("ice", mptr->feat.ice); #endif /* capitalize afterwards */ i = strlen(PREFIX); buf[i] = highc(buf[i]); /* capitalizing it makes it a sentence; terminate with '.' */ Strcat(buf, "."); putstr(win, 0, buf); } /* we assume that these are mutually exclusive */ *buf = '\0'; if (mptr->flags.oracle) { Sprintf(buf, "%sOracle of Delphi.", PREFIX); } else if (In_sokoban(&mptr->lev)) { Sprintf(buf, "%s%s.", PREFIX, mptr->flags.sokosolved ? "Solved" : "Unsolved"); } else if (mptr->flags.bigroom) { Sprintf(buf, "%sA very big room.", PREFIX); } else if (mptr->flags.roguelevel) { Sprintf(buf, "%sA primitive area.", PREFIX); } else if (mptr->flags.quest_summons) { Sprintf(buf, "%sSummoned by %s.", PREFIX, ldrname()); } else if (on_level(&mptr->lev, &qstart_level)) { Sprintf(buf, "%sHome%s.", PREFIX, mptr->flags.unreachable ? " (no way back...)" : ""); if (u.uevent.qcompleted) Sprintf(buf, "%sCompleted quest for %s.", PREFIX, ldrname()); else if (mptr->flags.questing) Sprintf(buf, "%sGiven quest by %s.", PREFIX, ldrname()); } else if (mptr->flags.ludios) { /* presence of the ludios branch in #overview output indicates that the player has made it onto the level; presence of this annotation indicates that the fort's entrance has been seen (or mapped) */ Sprintf(buf, "%sFort Ludios.", PREFIX); } else if (mptr->flags.castle) { Sprintf(buf, "%sThe castle%s.", PREFIX, tunesuffix(mptr, tmpbuf)); } else if (mptr->flags.valley) { Sprintf(buf, "%sValley of the Dead.", PREFIX); } else if (mptr->flags.msanctum) { Sprintf(buf, "%sMoloch's Sanctum.", PREFIX); } if (*buf) putstr(win, 0, buf); /* print out branches */ if (mptr->br) { Sprintf(buf, "%s%s to %s", PREFIX, br_string2(mptr->br), dungeons[mptr->br->end2.dnum].dname); /* Since mapseen objects are printed out in increasing order * of dlevel, clarify which level this branch is going to * if the branch goes upwards. Unless it's the end game. */ if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2))) Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2))); Strcat(buf, "."); putstr(win, 0, buf); } /* maybe print out bones details */ if (mptr->final_resting_place || final) { struct cemetery *bp; int kncnt = !died_here ? 0 : 1; for (bp = mptr->final_resting_place; bp; bp = bp->next) if (bp->bonesknown || wizard || final) ++kncnt; if (kncnt) { Sprintf(buf, "%s%s", PREFIX, "Final resting place for"); putstr(win, 0, buf); if (died_here) { /* disclosure occurs before bones creation, so listing dead hero here doesn't give away whether bones are produced */ formatkiller(tmpbuf, sizeof tmpbuf, how); /* rephrase a few death reasons to work with "you" */ (void) strsubst(tmpbuf, " himself", " yourself"); (void) strsubst(tmpbuf, " herself", " yourself"); (void) strsubst(tmpbuf, " his ", " your "); (void) strsubst(tmpbuf, " her ", " your "); Sprintf(buf, "%s%syou, %s%c", PREFIX, TAB, tmpbuf, --kncnt ? ',' : '.'); putstr(win, 0, buf); } for (bp = mptr->final_resting_place; bp; bp = bp->next) { if (bp->bonesknown || wizard || final) { Sprintf(buf, "%s%s%s, %s%c", PREFIX, TAB, bp->who, bp->how, --kncnt ? ',' : '.'); putstr(win, 0, buf); } } } } } /*dungeon.c*/ nethack-3.6.0/src/eat.c0000664000076400007660000031463512631241231013650 0ustar paxedpaxed/* NetHack 3.6 eat.c $NHDT-Date: 1449269916 2015/12/04 22:58:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.154 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(eatmdone); STATIC_PTR int NDECL(eatfood); STATIC_PTR void FDECL(costly_tin, (int)); STATIC_PTR int NDECL(opentin); STATIC_PTR int NDECL(unfaint); STATIC_DCL const char *FDECL(food_xname, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(choke, (struct obj *)); STATIC_DCL void NDECL(recalc_wt); STATIC_DCL struct obj *FDECL(touchfood, (struct obj *)); STATIC_DCL void NDECL(do_reset_eat); STATIC_DCL void FDECL(done_eating, (BOOLEAN_P)); STATIC_DCL void FDECL(cprefx, (int)); STATIC_DCL int FDECL(intrinsic_possible, (int, struct permonst *)); STATIC_DCL void FDECL(givit, (int, struct permonst *)); STATIC_DCL void FDECL(cpostfx, (int)); STATIC_DCL void FDECL(consume_tin, (const char *)); STATIC_DCL void FDECL(start_tin, (struct obj *)); STATIC_DCL int FDECL(eatcorpse, (struct obj *)); STATIC_DCL void FDECL(start_eating, (struct obj *)); STATIC_DCL void FDECL(fprefx, (struct obj *)); STATIC_DCL void FDECL(fpostfx, (struct obj *)); STATIC_DCL int NDECL(bite); STATIC_DCL int FDECL(edibility_prompts, (struct obj *)); STATIC_DCL int FDECL(rottenfood, (struct obj *)); STATIC_DCL void NDECL(eatspecial); STATIC_DCL int FDECL(bounded_increase, (int, int, int)); STATIC_DCL void FDECL(accessory_has_effect, (struct obj *)); STATIC_DCL void FDECL(eataccessory, (struct obj *)); STATIC_DCL const char *FDECL(foodword, (struct obj *)); STATIC_DCL int FDECL(tin_variety, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(maybe_cannibal, (int, BOOLEAN_P)); char msgbuf[BUFSZ]; /* also used to see if you're allowed to eat cats and dogs */ #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC)) /* monster types that cause hero to be turned into stone if eaten */ #define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA]) /* Rider corpses are treated as non-rotting so that attempting to eat one will be sure to reach the stage of eating where that meal is fatal */ #define nonrotting_corpse(mnum) \ ((mnum) == PM_LIZARD || (mnum) == PM_LICHEN || is_rider(&mons[mnum])) /* non-rotting non-corpses; unlike lizard corpses, these items will behave as if rotten if they are cursed (fortune cookies handled elsewhere) */ #define nonrotting_food(otyp) \ ((otyp) == LEMBAS_WAFER || (otyp) == CRAM_RATION) STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 }; STATIC_OVL NEARDATA const char offerfodder[] = { FOOD_CLASS, AMULET_CLASS, 0 }; /* Gold must come first for getobj(). */ STATIC_OVL NEARDATA const char allobj[] = { COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 }; STATIC_OVL boolean force_save_hs = FALSE; /* see hunger states in hack.h - texts used on bottom line */ const char *hu_stat[] = { "Satiated", " ", "Hungry ", "Weak ", "Fainting", "Fainted ", "Starved " }; /* * Decide whether a particular object can be eaten by the possibly * polymorphed character. Not used for monster checks. */ boolean is_edible(obj) register struct obj *obj; { /* protect invocation tools but not Rider corpses (handled elsewhere)*/ /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */ if (objects[obj->otyp].oc_unique) return FALSE; /* above also prevents the Amulet from being eaten, so we must never allow fake amulets to be eaten either [which is already the case] */ if (metallivorous(youmonst.data) && is_metallic(obj) && (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj))) return TRUE; if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) /* [g.cubes can eat containers and retain all contents as engulfed items, but poly'd player can't do that] */ && !Has_contents(obj)) return TRUE; /* return (boolean) !!index(comestibles, obj->oclass); */ return (boolean) (obj->oclass == FOOD_CLASS); } void init_uhunger() { u.uhunger = 900; u.uhs = NOT_HUNGRY; } /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */ static const struct { const char *txt; /* description */ int nut; /* nutrition */ Bitfield(fodder, 1); /* stocked by health food shops */ Bitfield(greasy, 1); /* causes slippery fingers */ } tintxts[] = { { "rotten", -50, 0, 0 }, /* ROTTEN_TIN = 0 */ { "homemade", 50, 1, 0 }, /* HOMEMADE_TIN = 1 */ { "soup made from", 20, 1, 0 }, { "french fried", 40, 0, 1 }, { "pickled", 40, 1, 0 }, { "boiled", 50, 1, 0 }, { "smoked", 50, 1, 0 }, { "dried", 55, 1, 0 }, { "deep fried", 60, 0, 1 }, { "szechuan", 70, 1, 0 }, { "broiled", 80, 0, 0 }, { "stir fried", 80, 0, 1 }, { "sauteed", 95, 0, 0 }, { "candied", 100, 1, 0 }, { "pureed", 500, 1, 0 }, { "", 0, 0, 0 } }; #define TTSZ SIZE(tintxts) static char *eatmbuf = 0; /* set by cpostfx() */ /* called after mimicing is over */ STATIC_PTR int eatmdone(VOID_ARGS) { /* release `eatmbuf' */ if (eatmbuf) { if (nomovemsg == eatmbuf) nomovemsg = 0; free((genericptr_t) eatmbuf), eatmbuf = 0; } /* update display */ if (youmonst.m_ap_type) { youmonst.m_ap_type = M_AP_NOTHING; newsym(u.ux, u.uy); } return 0; } /* called when hallucination is toggled */ void eatmupdate() { const char *altmsg = 0; int altapp = 0; /* lint suppression */ if (!eatmbuf || nomovemsg != eatmbuf) return; if (is_obj_mappear(&youmonst,ORANGE) && !Hallucination) { /* revert from hallucinatory to "normal" mimicking */ altmsg = "You now prefer mimicking yourself."; altapp = GOLD_PIECE; } else if (is_obj_mappear(&youmonst,GOLD_PIECE) && Hallucination) { /* won't happen; anything which might make immobilized hero begin hallucinating (black light attack, theft of Grayswandir) will terminate the mimicry first */ altmsg = "Your rind escaped intact."; altapp = ORANGE; } if (altmsg) { /* replace end-of-mimicking message */ if (strlen(altmsg) > strlen(eatmbuf)) { free((genericptr_t) eatmbuf); eatmbuf = (char *) alloc(strlen(altmsg) + 1); } nomovemsg = strcpy(eatmbuf, altmsg); /* update current image */ youmonst.mappearance = altapp; newsym(u.ux, u.uy); } } /* ``[the(] singular(food, xname) [)]'' */ STATIC_OVL const char * food_xname(food, the_pfx) struct obj *food; boolean the_pfx; { const char *result; if (food->otyp == CORPSE) { result = corpse_xname(food, (const char *) 0, CXN_SINGULAR | (the_pfx ? CXN_PFX_THE : 0)); /* not strictly needed since pname values are capitalized and the() is a no-op for them */ if (type_is_pname(&mons[food->corpsenm])) the_pfx = FALSE; } else { /* the ordinary case */ result = singular(food, xname); } if (the_pfx) result = the(result); return result; } /* Created by GAN 01/28/87 * Amended by AKP 09/22/87: if not hard, don't choke, just vomit. * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk. * 11/10/89: if hard, rarely vomit anyway, for slim chance. * * To a full belly all food is bad. (It.) */ STATIC_OVL void choke(food) struct obj *food; { /* only happens if you were satiated */ if (u.uhs != SATIATED) { if (!food || food->otyp != AMULET_OF_STRANGULATION) return; } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) { adjalign(-1); /* gluttony is unchivalrous */ You_feel("like a glutton!"); } exercise(A_CON, FALSE); if (Breathless || (!Strangled && !rn2(20))) { /* choking by eating AoS doesn't involve stuffing yourself */ if (food && food->otyp == AMULET_OF_STRANGULATION) { You("choke, but recover your composure."); return; } You("stuff yourself and then vomit voluminously."); morehungry(1000); /* you just got *very* sick! */ vomit(); } else { killer.format = KILLED_BY_AN; /* * Note all "killer"s below read "Choked on %s" on the * high score list & tombstone. So plan accordingly. */ if (food) { You("choke over your %s.", foodword(food)); if (food->oclass == COIN_CLASS) { Strcpy(killer.name, "very rich meal"); } else { killer.format = KILLED_BY; Strcpy(killer.name, killer_xname(food)); } } else { You("choke over it."); Strcpy(killer.name, "quick snack"); } You("die..."); done(CHOKING); } } /* modify object wt. depending on time spent consuming it */ STATIC_OVL void recalc_wt() { struct obj *piece = context.victual.piece; if (!piece) { impossible("recalc_wt without piece"); return; } debugpline1("Old weight = %d", piece->owt); debugpline2("Used time = %d, Req'd time = %d", context.victual.usedtime, context.victual.reqtime); piece->owt = weight(piece); debugpline1("New weight = %d", piece->owt); } /* called when eating interrupted by an event */ void reset_eat() { /* we only set a flag here - the actual reset process is done after * the round is spent eating. */ if (context.victual.eating && !context.victual.doreset) { debugpline0("reset_eat..."); context.victual.doreset = TRUE; } return; } STATIC_OVL struct obj * touchfood(otmp) struct obj *otmp; { if (otmp->quan > 1L) { if (!carried(otmp)) (void) splitobj(otmp, otmp->quan - 1L); else otmp = splitobj(otmp, 1L); debugpline0("split object,"); } if (!otmp->oeaten) { costly_alteration(otmp, COST_BITE); otmp->oeaten = (otmp->otyp == CORPSE ? mons[otmp->corpsenm].cnutrit : objects[otmp->otyp].oc_nutrition); } if (carried(otmp)) { freeinv(otmp); if (inv_cnt(FALSE) >= 52) { sellobj_state(SELL_DONTSELL); dropy(otmp); sellobj_state(SELL_NORMAL); } else { otmp->nomerge = 1; /* used to prevent merge */ otmp = addinv(otmp); otmp->nomerge = 0; } } return otmp; } /* When food decays, in the middle of your meal, we don't want to dereference * any dangling pointers, so set it to null (which should still trigger * do_reset_eat() at the beginning of eatfood()) and check for null pointers * in do_reset_eat(). */ void food_disappears(obj) struct obj *obj; { if (obj == context.victual.piece) { context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; } if (obj->timed) obj_stop_timers(obj); } /* renaming an object used to result in it having a different address, so the sequence start eating/opening, get interrupted, name the food, resume eating/opening would restart from scratch */ void food_substitution(old_obj, new_obj) struct obj *old_obj, *new_obj; { if (old_obj == context.victual.piece) { context.victual.piece = new_obj; context.victual.o_id = new_obj->o_id; } if (old_obj == context.tin.tin) { context.tin.tin = new_obj; context.tin.o_id = new_obj->o_id; } } STATIC_OVL void do_reset_eat() { debugpline0("do_reset_eat..."); if (context.victual.piece) { context.victual.o_id = 0; context.victual.piece = touchfood(context.victual.piece); if (context.victual.piece) context.victual.o_id = context.victual.piece->o_id; recalc_wt(); } context.victual.fullwarn = context.victual.eating = context.victual.doreset = FALSE; /* Do not set canchoke to FALSE; if we continue eating the same object * we need to know if canchoke was set when they started eating it the * previous time. And if we don't continue eating the same object * canchoke always gets recalculated anyway. */ stop_occupation(); newuhs(FALSE); } /* called each move during eating process */ STATIC_PTR int eatfood(VOID_ARGS) { if (!context.victual.piece || (!carried(context.victual.piece) && !obj_here(context.victual.piece, u.ux, u.uy))) { /* maybe it was stolen? */ do_reset_eat(); return 0; } if (!context.victual.eating) return 0; if (++context.victual.usedtime <= context.victual.reqtime) { if (bite()) return 0; return 1; /* still busy */ } else { /* done */ done_eating(TRUE); return 0; } } STATIC_OVL void done_eating(message) boolean message; { context.victual.piece->in_use = TRUE; occupation = 0; /* do this early, so newuhs() knows we're done */ newuhs(FALSE); if (nomovemsg) { if (message) pline1(nomovemsg); nomovemsg = 0; } else if (message) You("finish eating %s.", food_xname(context.victual.piece, TRUE)); if (context.victual.piece->otyp == CORPSE) cpostfx(context.victual.piece->corpsenm); else fpostfx(context.victual.piece); if (carried(context.victual.piece)) useup(context.victual.piece); else useupf(context.victual.piece, 1L); context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; context.victual.fullwarn = context.victual.eating = context.victual.doreset = FALSE; } void eating_conducts(pd) struct permonst *pd; { u.uconduct.food++; if (!vegan(pd)) u.uconduct.unvegan++; if (!vegetarian(pd)) violated_vegetarian(); } /* handle side-effects of mind flayer's tentacle attack */ int eat_brains(magr, mdef, visflag, dmg_p) struct monst *magr, *mdef; boolean visflag; int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ { struct permonst *pd = mdef->data; boolean give_nutrit = FALSE; int result = MM_HIT, xtra_dmg = rnd(10); if (noncorporeal(pd)) { if (visflag) pline("%s brain is unharmed.", (mdef == &youmonst) ? "Your" : s_suffix(Monnam(mdef))); return MM_MISS; /* side-effects can't occur */ } else if (magr == &youmonst) { You("eat %s brain!", s_suffix(mon_nam(mdef))); } else if (mdef == &youmonst) { Your("brain is eaten!"); } else { /* monster against monster */ if (visflag) pline("%s brain is eaten!", s_suffix(Monnam(mdef))); } if (flesh_petrifies(pd)) { /* mind flayer has attempted to eat the brains of a petrification inducing critter (most likely Medusa; attacking a cockatrice via tentacle-touch should have been caught before reaching this far) */ if (magr == &youmonst) { if (!Stone_resistance && !Stoned) make_stoned(5L, (char *) 0, KILLED_BY_AN, pd->mname); } else { /* no need to check for poly_when_stoned or Stone_resistance; mind flayers don't have those capabilities */ if (visflag) pline("%s turns to stone!", Monnam(magr)); monstone(magr); if (magr->mhp > 0) { /* life-saved; don't continue eating the brains */ return MM_MISS; } else { if (magr->mtame && !visflag) /* parallels mhitm.c's brief_feeling */ You("have a sad thought for a moment, then is passes."); return MM_AGR_DIED; } } } if (magr == &youmonst) { /* * player mind flayer is eating something's brain */ eating_conducts(pd); if (mindless(pd)) { /* (cannibalism not possible here) */ pline("%s doesn't notice.", Monnam(mdef)); /* all done; no extra harm inflicted upon target */ return MM_MISS; } else if (is_rider(pd)) { pline("Ingesting that is fatal."); Sprintf(killer.name, "unwisely ate the brain of %s", pd->mname); killer.format = NO_KILLER_PREFIX; done(DIED); /* life-saving needed to reach here */ exercise(A_WIS, FALSE); *dmg_p += xtra_dmg; /* Rider takes extra damage */ } else { morehungry(-rnd(30)); /* cannot choke */ if (ABASE(A_INT) < AMAX(A_INT)) { /* recover lost Int; won't increase current max */ ABASE(A_INT) += rnd(4); if (ABASE(A_INT) > AMAX(A_INT)) ABASE(A_INT) = AMAX(A_INT); context.botl = 1; } exercise(A_WIS, TRUE); *dmg_p += xtra_dmg; } /* targetting another mind flayer or your own underlying species is cannibalism */ (void) maybe_cannibal(monsndx(pd), TRUE); } else if (mdef == &youmonst) { /* * monster mind flayer is eating hero's brain */ /* no such thing as mindless players */ if (ABASE(A_INT) <= ATTRMIN(A_INT)) { static NEARDATA const char brainlessness[] = "brainlessness"; if (Lifesaved) { Strcpy(killer.name, brainlessness); killer.format = KILLED_BY; done(DIED); /* amulet of life saving has now been used up */ pline("Unfortunately your brain is still gone."); /* sanity check against adding other forms of life-saving */ u.uprops[LIFESAVED].extrinsic = u.uprops[LIFESAVED].intrinsic = 0L; } else { Your("last thought fades away."); } Strcpy(killer.name, brainlessness); killer.format = KILLED_BY; done(DIED); /* can only get here when in wizard or explore mode and user has explicitly chosen not to die; arbitrarily boost intelligence */ ABASE(A_INT) = ATTRMIN(A_INT) + 2; You_feel("like a scarecrow."); } give_nutrit = TRUE; /* in case a conflicted pet is doing this */ exercise(A_WIS, FALSE); /* caller handles Int and memory loss */ } else { /* mhitm */ /* * monster mind flayer is eating another monster's brain */ if (mindless(pd)) { if (visflag) pline("%s doesn't notice.", Monnam(mdef)); return MM_MISS; } else if (is_rider(pd)) { mondied(magr); if (magr->mhp <= 0) result = MM_AGR_DIED; /* Rider takes extra damage regardless of whether attacker dies */ *dmg_p += xtra_dmg; } else { *dmg_p += xtra_dmg; give_nutrit = TRUE; if (*dmg_p >= mdef->mhp && visflag) pline("%s last thought fades away...", s_suffix(Monnam(mdef))); } } if (give_nutrit && magr->mtame && !magr->isminion) { EDOG(magr)->hungrytime += rnd(60); magr->mconf = 0; } return result; } /* eating a corpse or egg of one's own species is usually naughty */ STATIC_OVL boolean maybe_cannibal(pm, allowmsg) int pm; boolean allowmsg; { static NEARDATA long ate_brains = 0L; struct permonst *fptr = &mons[pm]; /* food type */ /* when poly'd into a mind flayer, multiple tentacle hits in one turn cause multiple digestion checks to occur; avoid giving multiple luck penalties for the same attack */ if (moves == ate_brains) return FALSE; ate_brains = moves; /* ate_anything, not just brains... */ if (!CANNIBAL_ALLOWED() /* non-cannibalistic heroes shouldn't eat own species ever and also shouldn't eat current species when polymorphed (even if having the form of something which doesn't care about cannibalism--hero's innate traits aren't altered) */ && (your_race(fptr) || (Upolyd && same_race(youmonst.data, fptr)))) { if (allowmsg) { if (Upolyd && your_race(fptr)) You("have a bad feeling deep inside."); You("cannibal! You will regret this!"); } HAggravate_monster |= FROMOUTSIDE; change_luck(-rn1(4, 2)); /* -5..-2 */ return TRUE; } return FALSE; } STATIC_OVL void cprefx(pm) register int pm; { (void) maybe_cannibal(pm, TRUE); if (flesh_petrifies(&mons[pm])) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { Sprintf(killer.name, "tasting %s meat", mons[pm].mname); killer.format = KILLED_BY; You("turn to stone."); done(STONING); if (context.victual.piece) context.victual.eating = FALSE; return; /* lifesaved */ } } switch (pm) { case PM_LITTLE_DOG: case PM_DOG: case PM_LARGE_DOG: case PM_KITTEN: case PM_HOUSECAT: case PM_LARGE_CAT: /* cannibals are allowed to eat domestic animals without penalty */ if (!CANNIBAL_ALLOWED()) { You_feel("that eating the %s was a bad idea.", mons[pm].mname); HAggravate_monster |= FROMOUTSIDE; } break; case PM_LIZARD: if (Stoned) fix_petrification(); break; case PM_DEATH: case PM_PESTILENCE: case PM_FAMINE: { pline("Eating that is instantly fatal."); Sprintf(killer.name, "unwisely ate the body of %s", mons[pm].mname); killer.format = NO_KILLER_PREFIX; done(DIED); /* life-saving needed to reach here */ exercise(A_WIS, FALSE); /* It so happens that since we know these monsters */ /* cannot appear in tins, context.victual.piece will always */ /* be what we want, which is not generally true. */ if (revive_corpse(context.victual.piece)) { context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; } return; } case PM_GREEN_SLIME: if (!Slimed && !Unchanging && !slimeproof(youmonst.data)) { You("don't feel very well."); make_slimed(10L, (char *) 0); delayed_killer(SLIMED, KILLED_BY_AN, ""); } /* Fall through */ default: if (acidic(&mons[pm]) && Stoned) fix_petrification(); break; } } void fix_petrification() { char buf[BUFSZ]; if (Hallucination) Sprintf(buf, "What a pity--you just ruined a future piece of %sart!", ACURR(A_CHA) > 15 ? "fine " : ""); else Strcpy(buf, "You feel limber!"); make_stoned(0L, buf, 0, (char *) 0); } /* * If you add an intrinsic that can be gotten by eating a monster, add it * to intrinsic_possible() and givit(). (It must already be in prop.h to * be an intrinsic property.) * It would be very easy to make the intrinsics not try to give you one * that you already had by checking to see if you have it in * intrinsic_possible() instead of givit(), but we're not that nice. */ /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */ STATIC_OVL int intrinsic_possible(type, ptr) int type; register struct permonst *ptr; { int res = 0; #ifdef DEBUG #define ifdebugresist(Msg) \ do { \ if (res) \ debugpline0(Msg); \ } while (0) #else #define ifdebugresist(Msg) /*empty*/ #endif switch (type) { case FIRE_RES: res = (ptr->mconveys & MR_FIRE) != 0; ifdebugresist("can get fire resistance"); break; case SLEEP_RES: res = (ptr->mconveys & MR_SLEEP) != 0; ifdebugresist("can get sleep resistance"); break; case COLD_RES: res = (ptr->mconveys & MR_COLD) != 0; ifdebugresist("can get cold resistance"); break; case DISINT_RES: res = (ptr->mconveys & MR_DISINT) != 0; ifdebugresist("can get disintegration resistance"); break; case SHOCK_RES: /* shock (electricity) resistance */ res = (ptr->mconveys & MR_ELEC) != 0; ifdebugresist("can get shock resistance"); break; case POISON_RES: res = (ptr->mconveys & MR_POISON) != 0; ifdebugresist("can get poison resistance"); break; case TELEPORT: res = can_teleport(ptr); ifdebugresist("can get teleport"); break; case TELEPORT_CONTROL: res = control_teleport(ptr); ifdebugresist("can get teleport control"); break; case TELEPAT: res = telepathic(ptr); ifdebugresist("can get telepathy"); break; default: /* res stays 0 */ break; } #undef ifdebugresist return res; } /* givit() tries to give you an intrinsic based on the monster's level * and what type of intrinsic it is trying to give you. */ STATIC_OVL void givit(type, ptr) int type; register struct permonst *ptr; { register int chance; debugpline1("Attempting to give intrinsic %d", type); /* some intrinsics are easier to get than others */ switch (type) { case POISON_RES: if ((ptr == &mons[PM_KILLER_BEE] || ptr == &mons[PM_SCORPION]) && !rn2(4)) chance = 1; else chance = 15; break; case TELEPORT: chance = 10; break; case TELEPORT_CONTROL: chance = 12; break; case TELEPAT: chance = 1; break; default: chance = 15; break; } if (ptr->mlevel <= rn2(chance)) return; /* failed die roll */ switch (type) { case FIRE_RES: debugpline0("Trying to give fire resistance"); if (!(HFire_resistance & FROMOUTSIDE)) { You(Hallucination ? "be chillin'." : "feel a momentary chill."); HFire_resistance |= FROMOUTSIDE; } break; case SLEEP_RES: debugpline0("Trying to give sleep resistance"); if (!(HSleep_resistance & FROMOUTSIDE)) { You_feel("wide awake."); HSleep_resistance |= FROMOUTSIDE; } break; case COLD_RES: debugpline0("Trying to give cold resistance"); if (!(HCold_resistance & FROMOUTSIDE)) { You_feel("full of hot air."); HCold_resistance |= FROMOUTSIDE; } break; case DISINT_RES: debugpline0("Trying to give disintegration resistance"); if (!(HDisint_resistance & FROMOUTSIDE)) { You_feel(Hallucination ? "totally together, man." : "very firm."); HDisint_resistance |= FROMOUTSIDE; } break; case SHOCK_RES: /* shock (electricity) resistance */ debugpline0("Trying to give shock resistance"); if (!(HShock_resistance & FROMOUTSIDE)) { if (Hallucination) You_feel("grounded in reality."); else Your("health currently feels amplified!"); HShock_resistance |= FROMOUTSIDE; } break; case POISON_RES: debugpline0("Trying to give poison resistance"); if (!(HPoison_resistance & FROMOUTSIDE)) { You_feel(Poison_resistance ? "especially healthy." : "healthy."); HPoison_resistance |= FROMOUTSIDE; } break; case TELEPORT: debugpline0("Trying to give teleport"); if (!(HTeleportation & FROMOUTSIDE)) { You_feel(Hallucination ? "diffuse." : "very jumpy."); HTeleportation |= FROMOUTSIDE; } break; case TELEPORT_CONTROL: debugpline0("Trying to give teleport control"); if (!(HTeleport_control & FROMOUTSIDE)) { You_feel(Hallucination ? "centered in your personal space." : "in control of yourself."); HTeleport_control |= FROMOUTSIDE; } break; case TELEPAT: debugpline0("Trying to give telepathy"); if (!(HTelepat & FROMOUTSIDE)) { You_feel(Hallucination ? "in touch with the cosmos." : "a strange mental acuity."); HTelepat |= FROMOUTSIDE; /* If blind, make sure monsters show up. */ if (Blind) see_monsters(); } break; default: debugpline0("Tried to give an impossible intrinsic"); break; } } /* called after completely consuming a corpse */ STATIC_OVL void cpostfx(pm) register int pm; { register int tmp = 0; boolean catch_lycanthropy = FALSE; /* in case `afternmv' didn't get called for previously mimicking gold, clean up now to avoid `eatmbuf' memory leak */ if (eatmbuf) (void) eatmdone(); switch (pm) { case PM_NEWT: /* MRKR: "eye of newt" may give small magical energy boost */ if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) { int old_uen = u.uen; u.uen += rnd(3); if (u.uen > u.uenmax) { if (!rn2(3)) u.uenmax++; u.uen = u.uenmax; } if (old_uen != u.uen) { You_feel("a mild buzz."); context.botl = 1; } } break; case PM_WRAITH: pluslvl(FALSE); break; case PM_HUMAN_WERERAT: catch_lycanthropy = TRUE; u.ulycn = PM_WERERAT; break; case PM_HUMAN_WEREJACKAL: catch_lycanthropy = TRUE; u.ulycn = PM_WEREJACKAL; break; case PM_HUMAN_WEREWOLF: catch_lycanthropy = TRUE; u.ulycn = PM_WEREWOLF; break; case PM_NURSE: if (Upolyd) u.mh = u.mhmax; else u.uhp = u.uhpmax; context.botl = 1; break; case PM_STALKER: if (!Invis) { set_itimeout(&HInvis, (long) rn1(100, 50)); if (!Blind && !BInvis) self_invis_message(); } else { if (!(HInvis & INTRINSIC)) You_feel("hidden!"); HInvis |= FROMOUTSIDE; HSee_invisible |= FROMOUTSIDE; } newsym(u.ux, u.uy); /*FALLTHRU*/ case PM_YELLOW_LIGHT: case PM_GIANT_BAT: make_stunned((HStun & TIMEOUT) + 30L, FALSE); /*FALLTHRU*/ case PM_BAT: make_stunned((HStun & TIMEOUT) + 30L, FALSE); break; case PM_GIANT_MIMIC: tmp += 10; /*FALLTHRU*/ case PM_LARGE_MIMIC: tmp += 20; /*FALLTHRU*/ case PM_SMALL_MIMIC: tmp += 20; if (youmonst.data->mlet != S_MIMIC && !Unchanging) { char buf[BUFSZ]; u.uconduct.polyselfs++; /* you're changing form */ You_cant("resist the temptation to mimic %s.", Hallucination ? "an orange" : "a pile of gold"); /* A pile of gold can't ride. */ if (u.usteed) dismount_steed(DISMOUNT_FELL); nomul(-tmp); multi_reason = "pretending to be a pile of gold"; Sprintf(buf, Hallucination ? "You suddenly dread being peeled and mimic %s again!" : "You now prefer mimicking %s again.", an(Upolyd ? youmonst.data->mname : urace.noun)); eatmbuf = dupstr(buf); nomovemsg = eatmbuf; afternmv = eatmdone; /* ??? what if this was set before? */ youmonst.m_ap_type = M_AP_OBJECT; youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE; newsym(u.ux, u.uy); curs_on_u(); /* make gold symbol show up now */ display_nhwindow(WIN_MAP, TRUE); } break; case PM_QUANTUM_MECHANIC: Your("velocity suddenly seems very uncertain!"); if (HFast & INTRINSIC) { HFast &= ~INTRINSIC; You("seem slower."); } else { HFast |= FROMOUTSIDE; You("seem faster."); } break; case PM_LIZARD: if ((HStun & TIMEOUT) > 2) make_stunned(2L, FALSE); if ((HConfusion & TIMEOUT) > 2) make_confused(2L, FALSE); break; case PM_CHAMELEON: case PM_DOPPELGANGER: case PM_SANDESTIN: /* moot--they don't leave corpses */ if (Unchanging) { You_feel("momentarily different."); /* same as poly trap */ } else { You_feel("a change coming over you."); polyself(0); } break; case PM_DISENCHANTER: /* picks an intrinsic at random and removes it; there's no feedback if hero already lacks the chosen ability */ debugpline0("using attrcurse to strip an intrinsic"); attrcurse(); break; case PM_MIND_FLAYER: case PM_MASTER_MIND_FLAYER: if (ABASE(A_INT) < ATTRMAX(A_INT)) { if (!rn2(2)) { pline("Yum! That was real brain food!"); (void) adjattrib(A_INT, 1, FALSE); break; /* don't give them telepathy, too */ } } else { pline("For some reason, that tasted bland."); } /*FALLTHRU*/ default: { struct permonst *ptr = &mons[pm]; boolean conveys_STR = is_giant(ptr); int i, count; if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) || pm == PM_VIOLET_FUNGUS) { pline("Oh wow! Great stuff!"); (void) make_hallucinated((HHallucination & TIMEOUT) + 200L, FALSE, 0L); } /* Check the monster for all of the intrinsics. If this * monster can give more than one, pick one to try to give * from among all it can give. * * Strength from giants is now treated like an intrinsic * rather than being given unconditionally. */ count = 0; /* number of possible intrinsics */ tmp = 0; /* which one we will try to give */ if (conveys_STR) { count = 1; tmp = -1; /* use -1 as fake prop index for STR */ debugpline1("\"Intrinsic\" strength, %d", tmp); } for (i = 1; i <= LAST_PROP; i++) { if (!intrinsic_possible(i, ptr)) continue; ++count; /* a 1 in count chance of replacing the old choice with this one, and a count-1 in count chance of keeping the old choice (note that 1 in 1 and 0 in 1 are what we want for the first candidate) */ if (!rn2(count)) { debugpline2("Intrinsic %d replacing %d", i, tmp); tmp = i; } } /* if strength is the only candidate, give it 50% chance */ if (conveys_STR && count == 1 && !rn2(2)) tmp = 0; /* if something was chosen, give it now (givit() might fail) */ if (tmp == -1) gainstr((struct obj *) 0, 0, TRUE); else if (tmp > 0) givit(tmp, ptr); } break; } if (catch_lycanthropy) retouch_equipment(2); return; } void violated_vegetarian() { u.uconduct.unvegetarian++; if (Role_if(PM_MONK)) { You_feel("guilty."); adjalign(-1); } return; } /* common code to check and possibly charge for 1 context.tin.tin, * will split() context.tin.tin if necessary */ STATIC_PTR void costly_tin(alter_type) int alter_type; /* COST_xxx */ { struct obj *tin = context.tin.tin; if (carried(tin) ? tin->unpaid : (costly_spot(tin->ox, tin->oy) && !tin->no_charge)) { if (tin->quan > 1L) { tin = context.tin.tin = splitobj(tin, 1L); context.tin.o_id = tin->o_id; } costly_alteration(tin, alter_type); } } int tin_variety_txt(s, tinvariety) char *s; int *tinvariety; { int k, l; if (s && tinvariety) { *tinvariety = -1; for (k = 0; k < TTSZ - 1; ++k) { l = (int) strlen(tintxts[k].txt); if (!strncmpi(s, tintxts[k].txt, l) && ((int) strlen(s) > l) && s[l] == ' ') { *tinvariety = k; return (l + 1); } } } return 0; } /* * This assumes that buf already contains the word "tin", * as is the case with caller xname(). */ void tin_details(obj, mnum, buf) struct obj *obj; int mnum; char *buf; { char buf2[BUFSZ]; int r = tin_variety(obj, TRUE); if (obj && buf) { if (r == SPINACH_TIN) Strcat(buf, " of spinach"); else if (mnum == NON_PM) Strcpy(buf, "empty tin"); else { if ((obj->cknown || iflags.override_ID) && obj->spe < 0) { if (r == ROTTEN_TIN || r == HOMEMADE_TIN) { /* put these before the word tin */ Sprintf(buf2, "%s %s of ", tintxts[r].txt, buf); Strcpy(buf, buf2); } else { Sprintf(eos(buf), " of %s ", tintxts[r].txt); } } else { Strcpy(eos(buf), " of "); } if (vegetarian(&mons[mnum])) Sprintf(eos(buf), "%s", mons[mnum].mname); else Sprintf(eos(buf), "%s meat", mons[mnum].mname); } } } void set_tin_variety(obj, forcetype) struct obj *obj; int forcetype; { register int r; if (forcetype == SPINACH_TIN || (forcetype == HEALTHY_TIN && (obj->corpsenm == NON_PM /* empty or already spinach */ || !vegetarian(&mons[obj->corpsenm])))) { /* replace meat */ obj->corpsenm = NON_PM; /* not based on any monster */ obj->spe = 1; /* spinach */ return; } else if (forcetype == HEALTHY_TIN) { r = tin_variety(obj, FALSE); if (r < 0 || r >= TTSZ) r = ROTTEN_TIN; /* shouldn't happen */ while ((r == ROTTEN_TIN && !obj->cursed) || !tintxts[r].fodder) r = rn2(TTSZ - 1); } else if (forcetype >= 0 && forcetype < TTSZ - 1) { r = forcetype; } else { /* RANDOM_TIN */ r = rn2(TTSZ - 1); /* take your pick */ if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm)) r = HOMEMADE_TIN; /* lizards don't rot */ } obj->spe = -(r + 1); /* offset by 1 to allow index 0 */ } STATIC_OVL int tin_variety(obj, disp) struct obj *obj; boolean disp; /* we're just displaying so leave things alone */ { register int r; if (obj->spe == 1) { r = SPINACH_TIN; } else if (obj->cursed) { r = ROTTEN_TIN; /* always rotten if cursed */ } else if (obj->spe < 0) { r = -(obj->spe); --r; /* get rid of the offset */ } else r = rn2(TTSZ - 1); if (!disp && r == HOMEMADE_TIN && !obj->blessed && !rn2(7)) r = ROTTEN_TIN; /* some homemade tins go bad */ if (r == ROTTEN_TIN && nonrotting_corpse(obj->corpsenm)) r = HOMEMADE_TIN; /* lizards don't rot */ return r; } STATIC_OVL void consume_tin(mesg) const char *mesg; { const char *what; int which, mnum, r; struct obj *tin = context.tin.tin; r = tin_variety(tin, FALSE); if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) { b_trapped("tin", 0); costly_tin(COST_DSTROY); goto use_up_tin; } pline1(mesg); /* "You succeed in opening the tin." */ if (r != SPINACH_TIN) { mnum = tin->corpsenm; if (mnum == NON_PM) { pline("It turns out to be empty."); tin->dknown = tin->known = 1; costly_tin(COST_OPEN); goto use_up_tin; } which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */ if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE) && (Stone_resistance || Hallucination)) { what = "chicken"; which = 1; /* suppress pluralization */ } else if (Hallucination) { what = rndmonnam(NULL); } else { what = mons[mnum].mname; if (the_unique_pm(&mons[mnum])) which = 2; else if (type_is_pname(&mons[mnum])) which = 1; } if (which == 0) what = makeplural(what); else if (which == 2) what = the(what); pline("It smells like %s.", what); if (yn("Eat it?") == 'n') { if (flags.verbose) You("discard the open tin."); if (!Hallucination) tin->dknown = tin->known = 1; costly_tin(COST_OPEN); goto use_up_tin; } /* in case stop_occupation() was called on previous meal */ context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; context.victual.fullwarn = context.victual.eating = context.victual.doreset = FALSE; You("consume %s %s.", tintxts[r].txt, mons[mnum].mname); eating_conducts(&mons[mnum]); tin->dknown = tin->known = 1; cprefx(mnum); cpostfx(mnum); /* charge for one at pre-eating cost */ costly_tin(COST_OPEN); if (tintxts[r].nut < 0) /* rotten */ make_vomiting((long) rn1(15, 10), FALSE); else lesshungry(tintxts[r].nut); if (tintxts[r].greasy) { /* Assume !Glib, because you can't open tins when Glib. */ incr_itimeout(&Glib, rnd(15)); pline("Eating %s food made your %s very slippery.", tintxts[r].txt, makeplural(body_part(FINGER))); } } else { /* spinach... */ if (tin->cursed) { pline("It contains some decaying%s%s substance.", Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN)); } else { pline("It contains spinach."); tin->dknown = tin->known = 1; } if (yn("Eat it?") == 'n') { if (flags.verbose) You("discard the open tin."); costly_tin(COST_OPEN); goto use_up_tin; } /* * Same order as with non-spinach above: * conduct update, side-effects, shop handling, and nutrition. */ u.uconduct .food++; /* don't need vegan/vegetarian checks for spinach */ if (!tin->cursed) pline("This makes you feel like %s!", Hallucination ? "Swee'pea" : "Popeye"); gainstr(tin, 0, FALSE); costly_tin(COST_OPEN); lesshungry(tin->blessed ? 600 /* blessed */ : !tin->cursed ? (400 + rnd(200)) /* uncursed */ : (200 + rnd(400))); /* cursed */ } use_up_tin: if (carried(tin)) useup(tin); else useupf(tin, 1L); context.tin.tin = (struct obj *) 0; context.tin.o_id = 0; } /* called during each move whilst opening a tin */ STATIC_PTR int opentin(VOID_ARGS) { /* perhaps it was stolen (although that should cause interruption) */ if (!carried(context.tin.tin) && (!obj_here(context.tin.tin, u.ux, u.uy) || !can_reach_floor(TRUE))) return 0; /* %% probably we should use tinoid */ if (context.tin.usedtime++ >= 50) { You("give up your attempt to open the tin."); return 0; } if (context.tin.usedtime < context.tin.reqtime) return 1; /* still busy */ consume_tin("You succeed in opening the tin."); return 0; } /* called when starting to open a tin */ STATIC_OVL void start_tin(otmp) struct obj *otmp; { const char *mesg = 0; register int tmp; if (metallivorous(youmonst.data)) { mesg = "You bite right into the metal tin..."; tmp = 0; } else if (cantwield(youmonst.data)) { /* nohands || verysmall */ You("cannot handle the tin properly to open it."); return; } else if (otmp->blessed) { /* 50/50 chance for immediate access vs 1 turn delay (unless wielding blessed tin opener which always yields immediate access); 1 turn delay case is non-deterministic: getting interrupted and retrying might yield another 1 turn delay or might open immediately on 2nd (or 3rd, 4th, ...) try */ tmp = (uwep && uwep->blessed && uwep->otyp == TIN_OPENER) ? 0 : rn2(2); if (!tmp) mesg = "The tin opens like magic!"; else pline_The("tin seems easy to open."); } else if (uwep) { switch (uwep->otyp) { case TIN_OPENER: mesg = "You easily open the tin."; /* iff tmp==0 */ tmp = rn2(uwep->cursed ? 3 : !uwep->blessed ? 2 : 1); break; case DAGGER: case SILVER_DAGGER: case ELVEN_DAGGER: case ORCISH_DAGGER: case ATHAME: case CRYSKNIFE: tmp = 3; break; case PICK_AXE: case AXE: tmp = 6; break; default: goto no_opener; } pline("Using %s you try to open the tin.", yobjnam(uwep, (char *) 0)); } else { no_opener: pline("It is not so easy to open this tin."); if (Glib) { pline_The("tin slips from your %s.", makeplural(body_part(FINGER))); if (otmp->quan > 1L) { otmp = splitobj(otmp, 1L); } if (carried(otmp)) dropx(otmp); else stackobj(otmp); return; } tmp = rn1(1 + 500 / ((int) (ACURR(A_DEX) + ACURRSTR)), 10); } context.tin.tin = otmp; context.tin.o_id = otmp->o_id; if (!tmp) { consume_tin(mesg); /* begin immediately */ } else { context.tin.reqtime = tmp; context.tin.usedtime = 0; set_occupation(opentin, "opening the tin", 0); } return; } /* called when waking up after fainting */ int Hear_again(VOID_ARGS) { /* Chance of deafness going away while fainted/sleeping/etc. */ if (!rn2(2)) make_deaf(0L, FALSE); return 0; } /* called on the "first bite" of rotten food */ STATIC_OVL int rottenfood(obj) struct obj *obj; { pline("Blecch! Rotten %s!", foodword(obj)); if (!rn2(4)) { if (Hallucination) You_feel("rather trippy."); else You_feel("rather %s.", body_part(LIGHT_HEADED)); make_confused(HConfusion + d(2, 4), FALSE); } else if (!rn2(4) && !Blind) { pline("Everything suddenly goes dark."); make_blinded((long) d(2, 10), FALSE); if (!Blind) Your1(vision_clears); } else if (!rn2(3)) { const char *what, *where; int duration = rnd(10); if (!Blind) what = "goes", where = "dark"; else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) what = "you lose control of", where = "yourself"; else what = "you slap against the", where = (u.usteed) ? "saddle" : surface(u.ux, u.uy); pline_The("world spins and %s %s.", what, where); incr_itimeout(&HDeaf, duration); nomul(-duration); multi_reason = "unconscious from rotten food"; nomovemsg = "You are conscious again."; afternmv = Hear_again; return 1; } return 0; } /* called when a corpse is selected as food */ STATIC_OVL int eatcorpse(otmp) struct obj *otmp; { int tp = 0, mnum = otmp->corpsenm; long rotted = 0L; int retcode = 0; boolean stoneable = (flesh_petrifies(&mons[mnum]) && !Stone_resistance && !poly_when_stoned(youmonst.data)); /* KMH, conduct */ if (!vegan(&mons[mnum])) u.uconduct.unvegan++; if (!vegetarian(&mons[mnum])) violated_vegetarian(); if (!nonrotting_corpse(mnum)) { long age = peek_at_iced_corpse_age(otmp); rotted = (monstermoves - age) / (10L + rn2(20)); if (otmp->cursed) rotted += 2L; else if (otmp->blessed) rotted -= 2L; } if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) { boolean cannibal = maybe_cannibal(mnum, FALSE); pline("Ulch - that %s was tainted%s!", mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" : !vegetarian(&mons[mnum]) ? "meat" : "protoplasm", cannibal ? ", you cannibal" : ""); if (Sick_resistance) { pline("It doesn't seem at all sickening, though..."); } else { long sick_time; sick_time = (long) rn1(10, 10); /* make sure new ill doesn't result in improvement */ if (Sick && (sick_time > Sick)) sick_time = (Sick > 1L) ? Sick - 1L : 1L; make_sick(sick_time, corpse_xname(otmp, "rotted", CXN_NORMAL), TRUE, SICK_VOMITABLE); } if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); return 2; } else if (acidic(&mons[mnum]) && !Acid_resistance) { tp++; You("have a very bad case of stomach acid."); /* not body_part() */ losehp(rnd(15), "acidic corpse", KILLED_BY_AN); /* acid damage */ } else if (poisonous(&mons[mnum]) && rn2(5)) { tp++; pline("Ecch - that must have been poisonous!"); if (!Poison_resistance) { losestr(rnd(4)); losehp(rnd(15), "poisonous corpse", KILLED_BY_AN); } else You("seem unaffected by the poison."); /* now any corpse left too long will make you mildly ill */ } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) { tp++; You_feel("%ssick.", (Sick) ? "very " : ""); losehp(rnd(8), "cadaver", KILLED_BY_AN); } /* delay is weight dependent */ context.victual.reqtime = 3 + (mons[mnum].cwt >> 6); if (!tp && !nonrotting_corpse(mnum) && (otmp->orotten || !rn2(7))) { if (rottenfood(otmp)) { otmp->orotten = TRUE; (void) touchfood(otmp); retcode = 1; } if (!mons[otmp->corpsenm].cnutrit) { /* no nutrition: rots away, no message if you passed out */ if (!retcode) pline_The("corpse rots away completely."); if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); retcode = 2; } if (!retcode) consume_oeaten(otmp, 2); /* oeaten >>= 2 */ } else if ((mnum == PM_COCKATRICE || mnum == PM_CHICKATRICE) && (Stone_resistance || Hallucination)) { pline("This tastes just like chicken!"); } else if (mnum == PM_FLOATING_EYE && u.umonnum == PM_RAVEN) { You("peck the eyeball with delight."); } else { /* [is this right? omnivores end up always disliking the taste] */ boolean yummy = vegan(&mons[mnum]) ? (!carnivorous(youmonst.data) && herbivorous(youmonst.data)) : (carnivorous(youmonst.data) && !herbivorous(youmonst.data)); pline("%s%s %s!", type_is_pname(&mons[mnum]) ? "" : the_unique_pm(&mons[mnum]) ? "The " : "This ", food_xname(otmp, FALSE), Hallucination ? (yummy ? ((u.umonnum == PM_TIGER) ? "is gr-r-reat" : "is gnarly") : "is grody") : (yummy ? "is delicious" : "tastes terrible")); } return retcode; } /* called as you start to eat */ STATIC_OVL void start_eating(otmp) struct obj *otmp; { const char *old_nomovemsg, *save_nomovemsg; debugpline2("start_eating: %lx (victual = %lx)", (unsigned long) otmp, (unsigned long) context.victual.piece); debugpline1("reqtime = %d", context.victual.reqtime); debugpline1("(original reqtime = %d)", objects[otmp->otyp].oc_delay); debugpline1("nmod = %d", context.victual.nmod); debugpline1("oeaten = %d", otmp->oeaten); context.victual.fullwarn = context.victual.doreset = FALSE; context.victual.eating = TRUE; if (otmp->otyp == CORPSE || otmp->globby) { cprefx(context.victual.piece->corpsenm); if (!context.victual.piece || !context.victual.eating) { /* rider revived, or died and lifesaved */ return; } } old_nomovemsg = nomovemsg; if (bite()) { /* survived choking, finish off food that's nearly done; need this to handle cockatrice eggs, fortune cookies, etc */ if (++context.victual.usedtime >= context.victual.reqtime) { /* don't want done_eating() to issue nomovemsg if it is due to vomit() called by bite() */ save_nomovemsg = nomovemsg; if (!old_nomovemsg) nomovemsg = 0; done_eating(FALSE); if (!old_nomovemsg) nomovemsg = save_nomovemsg; } return; } if (++context.victual.usedtime >= context.victual.reqtime) { /* print "finish eating" message if they just resumed -dlc */ done_eating(context.victual.reqtime > 1 ? TRUE : FALSE); return; } Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE)); set_occupation(eatfood, msgbuf, 0); } /* * called on "first bite" of (non-corpse) food. * used for non-rotten non-tin non-corpse food */ STATIC_OVL void fprefx(otmp) struct obj *otmp; { switch (otmp->otyp) { case FOOD_RATION: if (u.uhunger <= 200) pline(Hallucination ? "Oh wow, like, superior, man!" : "That food really hit the spot!"); else if (u.uhunger <= 700) pline("That satiated your %s!", body_part(STOMACH)); break; case TRIPE_RATION: if (carnivorous(youmonst.data) && !humanoid(youmonst.data)) pline("That tripe ration was surprisingly good!"); else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) pline(Hallucination ? "Tastes great! Less filling!" : "Mmm, tripe... not bad!"); else { pline("Yak - dog food!"); more_experienced(1, 0); newexplevel(); /* not cannibalism, but we use similar criteria for deciding whether to be sickened by this meal */ if (rn2(2) && !CANNIBAL_ALLOWED()) make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE); } break; case MEATBALL: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: case MEAT_RING: goto give_feedback; case CLOVE_OF_GARLIC: if (is_undead(youmonst.data)) { make_vomiting((long) rn1(context.victual.reqtime, 5), FALSE); break; } /* else FALLTHRU */ default: if (otmp->otyp == SLIME_MOLD && !otmp->cursed && otmp->spe == context.current_fruit) { pline("My, that was a %s %s!", Hallucination ? "primo" : "yummy", singular(otmp, xname)); } else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) { ; /* skip core joke; feedback deferred til fpostfx() */ #if defined(MAC) || defined(MACOSX) /* KMH -- Why should Unix have all the fun? We check MACOSX before UNIX to get the Apple-specific apple message; the '#if UNIX' code will still kick in for pear. */ } else if (otmp->otyp == APPLE) { pline("Delicious! Must be a Macintosh!"); #endif #ifdef UNIX } else if (otmp->otyp == APPLE || otmp->otyp == PEAR) { if (!Hallucination) { pline("Core dumped."); } else { /* This is based on an old Usenet joke, a fake a.out manual * page */ int x = rnd(100); pline("%s -- core dumped.", (x <= 75) ? "Segmentation fault" : (x <= 99) ? "Bus error" : "Yo' mama"); } #endif } else if (otmp->otyp == EGG && stale_egg(otmp)) { pline("Ugh. Rotten egg."); /* perhaps others like it */ make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE); } else { give_feedback: pline("This %s is %s", singular(otmp, xname), otmp->cursed ? (Hallucination ? "grody!" : "terrible!") : (otmp->otyp == CRAM_RATION || otmp->otyp == K_RATION || otmp->otyp == C_RATION) ? "bland." : Hallucination ? "gnarly!" : "delicious!"); } break; /* default */ } /* switch */ } /* increment a combat intrinsic with limits on its growth */ STATIC_OVL int bounded_increase(old, inc, typ) int old, inc, typ; { int absold, absinc, sgnold, sgninc; /* don't include any amount coming from worn rings */ if (uright && uright->otyp == typ) old -= uright->spe; if (uleft && uleft->otyp == typ) old -= uleft->spe; absold = abs(old), absinc = abs(inc); sgnold = sgn(old), sgninc = sgn(inc); if (absinc == 0 || sgnold != sgninc || absold + absinc < 10) { ; /* use inc as-is */ } else if (absold + absinc < 20) { absinc = rnd(absinc); /* 1..n */ if (absold + absinc < 10) absinc = 10 - absold; inc = sgninc * absinc; } else if (absold + absinc < 40) { absinc = rn2(absinc) ? 1 : 0; if (absold + absinc < 20) absinc = rnd(20 - absold); inc = sgninc * absinc; } else { inc = 0; /* no further increase allowed via this method */ } return old + inc; } STATIC_OVL void accessory_has_effect(otmp) struct obj *otmp; { pline("Magic spreads through your body as you digest the %s.", otmp->oclass == RING_CLASS ? "ring" : "amulet"); } STATIC_OVL void eataccessory(otmp) struct obj *otmp; { int typ = otmp->otyp; long oldprop; /* Note: rings are not so common that this is unbalancing. */ /* (How often do you even _find_ 3 rings of polymorph in a game?) */ oldprop = u.uprops[objects[typ].oc_oprop].intrinsic; if (otmp == uleft || otmp == uright) { Ring_gone(otmp); if (u.uhp <= 0) return; /* died from sink fall */ } otmp->known = otmp->dknown = 1; /* by taste */ if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) { switch (otmp->otyp) { default: if (!objects[typ].oc_oprop) break; /* should never happen */ if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE)) accessory_has_effect(otmp); u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE; switch (typ) { case RIN_SEE_INVISIBLE: set_mimic_blocking(); see_monsters(); if (Invis && !oldprop && !ESee_invisible && !perceives(youmonst.data) && !Blind) { newsym(u.ux, u.uy); pline("Suddenly you can see yourself."); makeknown(typ); } break; case RIN_INVISIBILITY: if (!oldprop && !EInvis && !BInvis && !See_invisible && !Blind) { newsym(u.ux, u.uy); Your("body takes on a %s transparency...", Hallucination ? "normal" : "strange"); makeknown(typ); } break; case RIN_PROTECTION_FROM_SHAPE_CHAN: rescham(); break; case RIN_LEVITATION: /* undo the `.intrinsic |= FROMOUTSIDE' done above */ u.uprops[LEVITATION].intrinsic = oldprop; if (!Levitation) { float_up(); incr_itimeout(&HLevitation, d(10, 20)); makeknown(typ); } break; } /* inner switch */ break; /* default case of outer switch */ case RIN_ADORNMENT: accessory_has_effect(otmp); if (adjattrib(A_CHA, otmp->spe, -1)) makeknown(typ); break; case RIN_GAIN_STRENGTH: accessory_has_effect(otmp); if (adjattrib(A_STR, otmp->spe, -1)) makeknown(typ); break; case RIN_GAIN_CONSTITUTION: accessory_has_effect(otmp); if (adjattrib(A_CON, otmp->spe, -1)) makeknown(typ); break; case RIN_INCREASE_ACCURACY: accessory_has_effect(otmp); u.uhitinc = (schar) bounded_increase((int) u.uhitinc, otmp->spe, RIN_INCREASE_ACCURACY); break; case RIN_INCREASE_DAMAGE: accessory_has_effect(otmp); u.udaminc = (schar) bounded_increase((int) u.udaminc, otmp->spe, RIN_INCREASE_DAMAGE); break; case RIN_PROTECTION: accessory_has_effect(otmp); HProtection |= FROMOUTSIDE; u.ublessed = bounded_increase(u.ublessed, otmp->spe, RIN_PROTECTION); context.botl = 1; break; case RIN_FREE_ACTION: /* Give sleep resistance instead */ if (!(HSleep_resistance & FROMOUTSIDE)) accessory_has_effect(otmp); if (!Sleep_resistance) You_feel("wide awake."); HSleep_resistance |= FROMOUTSIDE; break; case AMULET_OF_CHANGE: accessory_has_effect(otmp); makeknown(typ); change_sex(); You("are suddenly very %s!", flags.female ? "feminine" : "masculine"); context.botl = 1; break; case AMULET_OF_UNCHANGING: /* un-change: it's a pun */ if (!Unchanging && Upolyd) { accessory_has_effect(otmp); makeknown(typ); rehumanize(); } break; case AMULET_OF_STRANGULATION: /* bad idea! */ /* no message--this gives no permanent effect */ choke(otmp); break; case AMULET_OF_RESTFUL_SLEEP: { /* another bad idea! */ long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT); if (!(HSleepy & FROMOUTSIDE)) accessory_has_effect(otmp); HSleepy |= FROMOUTSIDE; /* might also be wearing one; use shorter of two timeouts */ if (newnap < oldnap || oldnap == 0L) HSleepy = (HSleepy & ~TIMEOUT) | newnap; break; } case RIN_SUSTAIN_ABILITY: case AMULET_OF_LIFE_SAVING: case AMULET_OF_REFLECTION: /* nice try */ /* can't eat Amulet of Yendor or fakes, * and no oc_prop even if you could -3. */ break; } } } /* called after eating non-food */ STATIC_OVL void eatspecial() { struct obj *otmp = context.victual.piece; /* lesshungry wants an occupation to handle choke messages correctly */ set_occupation(eatfood, "eating non-food", 0); lesshungry(context.victual.nmod); occupation = 0; context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; context.victual.eating = 0; if (otmp->oclass == COIN_CLASS) { if (carried(otmp)) useupall(otmp); else useupf(otmp, otmp->quan); vault_gd_watching(GD_EATGOLD); return; } #ifdef MAIL if (otmp->otyp == SCR_MAIL) { /* no nutrition */ pline("This junk mail is less than satisfying."); } #endif if (otmp->oclass == POTION_CLASS) { otmp->quan++; /* dopotion() does a useup() */ (void) dopotion(otmp); } else if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS) { eataccessory(otmp); } else if (otmp->otyp == LEASH && otmp->leashmon) { o_unleash(otmp); } /* KMH -- idea by "Tommy the Terrorist" */ if (otmp->otyp == TRIDENT && !otmp->cursed) { /* sugarless chewing gum which used to be heavily advertised on TV */ pline(Hallucination ? "Four out of five dentists agree." : "That was pure chewing satisfaction!"); exercise(A_WIS, TRUE); } if (otmp->otyp == FLINT && !otmp->cursed) { /* chewable vitamin for kids based on "The Flintstones" TV cartoon */ pline("Yabba-dabba delicious!"); exercise(A_CON, TRUE); } if (otmp == uwep && otmp->quan == 1L) uwepgone(); if (otmp == uquiver && otmp->quan == 1L) uqwepgone(); if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone(); if (otmp == uball) unpunish(); if (otmp == uchain) unpunish(); /* but no useup() */ else if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); } /* NOTE: the order of these words exactly corresponds to the order of oc_material values #define'd in objclass.h. */ static const char *foodwords[] = { "meal", "liquid", "wax", "food", "meat", "paper", "cloth", "leather", "wood", "bone", "scale", "metal", "metal", "metal", "silver", "gold", "platinum", "mithril", "plastic", "glass", "rich food", "stone" }; STATIC_OVL const char * foodword(otmp) struct obj *otmp; { if (otmp->oclass == FOOD_CLASS) return "food"; if (otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS && otmp->dknown) makeknown(otmp->otyp); return foodwords[objects[otmp->otyp].oc_material]; } /* called after consuming (non-corpse) food */ STATIC_OVL void fpostfx(otmp) struct obj *otmp; { switch (otmp->otyp) { case SPRIG_OF_WOLFSBANE: if (u.ulycn >= LOW_PM || is_were(youmonst.data)) you_unwere(TRUE); break; case CARROT: if (!u.uswallow || !attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND)) make_blinded((long) u.ucreamed, TRUE); break; case FORTUNE_COOKIE: outrumor(bcsign(otmp), BY_COOKIE); if (!Blind) u.uconduct.literate++; break; case LUMP_OF_ROYAL_JELLY: /* This stuff seems to be VERY healthy! */ gainstr(otmp, 1, TRUE); if (Upolyd) { u.mh += otmp->cursed ? -rnd(20) : rnd(20); if (u.mh > u.mhmax) { if (!rn2(17)) u.mhmax++; u.mh = u.mhmax; } else if (u.mh <= 0) { rehumanize(); } } else { u.uhp += otmp->cursed ? -rnd(20) : rnd(20); if (u.uhp > u.uhpmax) { if (!rn2(17)) u.uhpmax++; u.uhp = u.uhpmax; } else if (u.uhp <= 0) { killer.format = KILLED_BY_AN; Strcpy(killer.name, "rotten lump of royal jelly"); done(POISONING); } } if (!otmp->cursed) heal_legs(); break; case EGG: if (flesh_petrifies(&mons[otmp->corpsenm])) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { if (!Stoned) { Sprintf(killer.name, "%s egg", mons[otmp->corpsenm].mname); make_stoned(5L, (char *) 0, KILLED_BY_AN, killer.name); } } /* note: no "tastes like chicken" message for eggs */ } break; case EUCALYPTUS_LEAF: if (Sick && !otmp->cursed) make_sick(0L, (char *) 0, TRUE, SICK_ALL); if (Vomiting && !otmp->cursed) make_vomiting(0L, TRUE); break; case APPLE: if (otmp->cursed && !Sleep_resistance) { /* Snow White; 'poisoned' applies to [a subset of] weapons, not food, so we substitute cursed; fortunately our hero won't have to wait for a prince to be rescued/revived */ if (Race_if(PM_DWARF) && Hallucination) verbalize("Heigh-ho, ho-hum, I think I'll skip work today."); else if (Deaf || !flags.acoustics) You("fall asleep."); else You_hear("sinister laughter as you fall asleep..."); fall_asleep(-rn1(11, 20), TRUE); } break; } return; } #if 0 /* intended for eating a spellbook while polymorphed, but not used; "leather" applied to appearance, not composition, and has been changed to "leathery" to reflect that */ STATIC_DCL boolean FDECL(leather_cover, (struct obj *)); STATIC_OVL boolean leather_cover(otmp) struct obj *otmp; { const char *odesc = OBJ_DESCR(objects[otmp->otyp]); if (odesc && (otmp->oclass == SPBOOK_CLASS)) { if (!strcmp(odesc, "leather")) return TRUE; } return FALSE; } #endif /* * return 0 if the food was not dangerous. * return 1 if the food was dangerous and you chose to stop. * return 2 if the food was dangerous and you chose to eat it anyway. */ STATIC_OVL int edibility_prompts(otmp) struct obj *otmp; { /* Blessed food detection grants hero a one-use * ability to detect food that is unfit for consumption * or dangerous and avoid it. */ char buf[BUFSZ], foodsmell[BUFSZ], it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ]; boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE; int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm; long rotted = 0L; Strcpy(foodsmell, Tobjnam(otmp, "smell")); Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they"); Sprintf(eat_it_anyway, "Eat %s anyway?", (otmp->quan == 1L) ? "it" : "one"); if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) { /* These checks must match those in eatcorpse() */ stoneorslime = (flesh_petrifies(&mons[mnum]) && !Stone_resistance && !poly_when_stoned(youmonst.data)); if (mnum == PM_GREEN_SLIME || otmp->otyp == GLOB_OF_GREEN_SLIME) stoneorslime = (!Unchanging && !slimeproof(youmonst.data)); if (cadaver && !nonrotting_corpse(mnum)) { long age = peek_at_iced_corpse_age(otmp); /* worst case rather than random in this calculation to force prompt */ rotted = (monstermoves - age) / (10L + 0 /* was rn2(20) */); if (otmp->cursed) rotted += 2L; else if (otmp->blessed) rotted -= 2L; } } /* * These problems with food should be checked in * order from most detrimental to least detrimental. */ if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) { /* Tainted meat */ Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (stoneorslime) { Sprintf(buf, "%s like %s could be something very dangerous! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (otmp->orotten || (cadaver && rotted > 3L)) { /* Rotten */ Sprintf(buf, "%s like %s could be rotten! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) { /* poisonous */ Sprintf(buf, "%s like %s might be poisonous! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) { /* causes sleep, for long enough to be dangerous */ Sprintf(buf, "%s like %s might have been poisoned. %s", foodsmell, it_or_they, eat_it_anyway); return (yn_function(buf, ynchars, 'n') == 'n') ? 1 : 2; } if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian && Role_if(PM_MONK)) { Sprintf(buf, "%s unhealthy. %s", foodsmell, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) { Sprintf(buf, "%s rather acidic. %s", foodsmell, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp) && otmp->oerodeproof) { Sprintf(buf, "%s disgusting to you right now. %s", foodsmell, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } /* * Breaks conduct, but otherwise safe. */ if (!u.uconduct.unvegan && ((material == LEATHER || material == BONE || material == DRAGON_HIDE || material == WAX) || (cadaver && !vegan(&mons[mnum])))) { Sprintf(buf, "%s foul and unfamiliar to you. %s", foodsmell, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (!u.uconduct.unvegetarian && ((material == LEATHER || material == BONE || material == DRAGON_HIDE) || (cadaver && !vegetarian(&mons[mnum])))) { Sprintf(buf, "%s unfamiliar to you. %s", foodsmell, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) { /* Tainted meat with Sick_resistance */ Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf, ynchars, 'n') == 'n') return 1; else return 2; } return 0; } /* 'e' command */ int doeat() { struct obj *otmp; int basenutrit; /* nutrition of full item */ boolean dont_start = FALSE, nodelicious = FALSE; if (Strangled) { pline("If you can't breathe air, how can you consume solids?"); return 0; } if (!(otmp = floorfood("eat", 0))) return 0; if (check_capacity((char *) 0)) return 0; if (u.uedibility) { int res = edibility_prompts(otmp); if (res) { Your( "%s stops tingling and your sense of smell returns to normal.", body_part(NOSE)); u.uedibility = 0; if (res == 1) return 0; } } /* We have to make non-foods take 1 move to eat, unless we want to * do ridiculous amounts of coding to deal with partly eaten plate * mails, players who polymorph back to human in the middle of their * metallic meal, etc.... */ if (!(carried(otmp) ? retouch_object(&otmp, FALSE) : touch_artifact(otmp, &youmonst))) { return 1; } else if (!is_edible(otmp)) { You("cannot eat that!"); return 0; } else if ((otmp->owornmask & (W_ARMOR | W_TOOL | W_AMUL | W_SADDLE)) != 0) { /* let them eat rings */ You_cant("eat %s you're wearing.", something); return 0; } if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) { otmp->rknown = TRUE; if (otmp->quan > 1L) { if (!carried(otmp)) (void) splitobj(otmp, otmp->quan - 1L); else otmp = splitobj(otmp, 1L); } pline("Ulch - that %s was rustproofed!", xname(otmp)); /* The regurgitated object's rustproofing is gone now */ otmp->oerodeproof = 0; make_stunned((HStun & TIMEOUT) + (long) rn2(10), TRUE); You("spit %s out onto the %s.", the(xname(otmp)), surface(u.ux, u.uy)); if (carried(otmp)) { freeinv(otmp); dropy(otmp); } stackobj(otmp); return 1; } /* KMH -- Slow digestion is... indigestible */ if (otmp->otyp == RIN_SLOW_DIGESTION) { pline("This ring is indigestible!"); (void) rottenfood(otmp); if (otmp->dknown && !objects[otmp->otyp].oc_name_known && !objects[otmp->otyp].oc_uname) docall(otmp); return 1; } if (otmp->oclass != FOOD_CLASS) { int material; context.victual.reqtime = 1; context.victual.piece = otmp; context.victual.o_id = otmp->o_id; /* Don't split it, we don't need to if it's 1 move */ context.victual.usedtime = 0; context.victual.canchoke = (u.uhs == SATIATED); /* Note: gold weighs 1 pt. for each 1000 pieces (see pickup.c) so gold and non-gold is consistent. */ if (otmp->oclass == COIN_CLASS) basenutrit = ((otmp->quan > 200000L) ? 2000 : (int) (otmp->quan / 100L)); else if (otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) basenutrit = weight(otmp); /* oc_nutrition is usually weight anyway */ else basenutrit = objects[otmp->otyp].oc_nutrition; #ifdef MAIL if (otmp->otyp == SCR_MAIL) { basenutrit = 0; nodelicious = TRUE; } #endif context.victual.nmod = basenutrit; context.victual.eating = TRUE; /* needed for lesshungry() */ material = objects[otmp->otyp].oc_material; if (material == LEATHER || material == BONE || material == DRAGON_HIDE) { u.uconduct.unvegan++; violated_vegetarian(); } else if (material == WAX) u.uconduct.unvegan++; u.uconduct.food++; if (otmp->cursed) (void) rottenfood(otmp); if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) { pline("Ecch - that must have been poisonous!"); if (!Poison_resistance) { losestr(rnd(4)); losehp(rnd(15), xname(otmp), KILLED_BY_AN); } else You("seem unaffected by the poison."); } else if (!otmp->cursed && !nodelicious) { pline("%s%s is delicious!", (obj_is_pname(otmp) && otmp->oartifact < ART_ORB_OF_DETECTION) ? "" : "This ", (otmp->oclass == COIN_CLASS) ? foodword(otmp) : singular(otmp, xname)); } eatspecial(); return 1; } if (otmp == context.victual.piece) { /* If they weren't able to choke, they don't suddenly become able to * choke just because they were interrupted. On the other hand, if * they were able to choke before, if they lost food it's possible * they shouldn't be able to choke now. */ if (u.uhs != SATIATED) context.victual.canchoke = FALSE; context.victual.o_id = 0; context.victual.piece = touchfood(otmp); if (context.victual.piece) context.victual.o_id = context.victual.piece->o_id; You("resume your meal."); start_eating(context.victual.piece); return 1; } /* nothing in progress - so try to find something. */ /* tins are a special case */ /* tins must also check conduct separately in case they're discarded */ if (otmp->otyp == TIN) { start_tin(otmp); return 1; } /* KMH, conduct */ u.uconduct.food++; context.victual.o_id = 0; context.victual.piece = otmp = touchfood(otmp); if (context.victual.piece) context.victual.o_id = context.victual.piece->o_id; context.victual.usedtime = 0; /* Now we need to calculate delay and nutritional info. * The base nutrition calculated here and in eatcorpse() accounts * for normal vs. rotten food. The reqtime and nutrit values are * then adjusted in accordance with the amount of food left. */ if (otmp->otyp == CORPSE || otmp->globby) { int tmp = eatcorpse(otmp); if (tmp == 2) { /* used up */ context.victual.piece = (struct obj *) 0; context.victual.o_id = 0; return 1; } else if (tmp) dont_start = TRUE; /* if not used up, eatcorpse sets up reqtime and may modify oeaten */ } else { /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are * all handled in the != FOOD_CLASS case, above. */ switch (objects[otmp->otyp].oc_material) { case FLESH: u.uconduct.unvegan++; if (otmp->otyp != EGG) { violated_vegetarian(); } break; default: if (otmp->otyp == PANCAKE || otmp->otyp == FORTUNE_COOKIE /*eggs*/ || otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR /*milk*/ || otmp->otyp == LUMP_OF_ROYAL_JELLY) u.uconduct.unvegan++; break; } context.victual.reqtime = objects[otmp->otyp].oc_delay; if (otmp->otyp != FORTUNE_COOKIE && (otmp->cursed || (!nonrotting_food(otmp->otyp) && (monstermoves - otmp->age) > (otmp->blessed ? 50L : 30L) && (otmp->orotten || !rn2(7))))) { if (rottenfood(otmp)) { otmp->orotten = TRUE; dont_start = TRUE; } consume_oeaten(otmp, 1); /* oeaten >>= 1 */ } else fprefx(otmp); } /* re-calc the nutrition */ if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit; else basenutrit = objects[otmp->otyp].oc_nutrition; debugpline1("before rounddiv: context.victual.reqtime == %d", context.victual.reqtime); debugpline2("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit); context.victual.reqtime = (basenutrit == 0) ? 0 : rounddiv(context.victual.reqtime * (long) otmp->oeaten, basenutrit); debugpline1("after rounddiv: context.victual.reqtime == %d", context.victual.reqtime); /* * calculate the modulo value (nutrit. units per round eating) * note: this isn't exact - you actually lose a little nutrition due * to this method. * TODO: add in a "remainder" value to be given at the end of the meal. */ if (context.victual.reqtime == 0 || otmp->oeaten == 0) /* possible if most has been eaten before */ context.victual.nmod = 0; else if ((int) otmp->oeaten >= context.victual.reqtime) context.victual.nmod = -((int) otmp->oeaten / context.victual.reqtime); else context.victual.nmod = context.victual.reqtime % otmp->oeaten; context.victual.canchoke = (u.uhs == SATIATED); if (!dont_start) start_eating(otmp); return 1; } /* Take a single bite from a piece of food, checking for choking and * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise. */ STATIC_OVL int bite() { if (context.victual.canchoke && u.uhunger >= 2000) { choke(context.victual.piece); return 1; } if (context.victual.doreset) { do_reset_eat(); return 0; } force_save_hs = TRUE; if (context.victual.nmod < 0) { lesshungry(-context.victual.nmod); consume_oeaten(context.victual.piece, context.victual.nmod); /* -= -nmod */ } else if (context.victual.nmod > 0 && (context.victual.usedtime % context.victual.nmod)) { lesshungry(1); consume_oeaten(context.victual.piece, -1); /* -= 1 */ } force_save_hs = FALSE; recalc_wt(); return 0; } /* as time goes by - called by moveloop() and domove() */ void gethungry() { if (u.uinvulnerable) return; /* you don't feel hungrier */ if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */ && (carnivorous(youmonst.data) || herbivorous(youmonst.data)) && !Slow_digestion) u.uhunger--; /* ordinary food consumption */ if (moves % 2) { /* odd turns */ /* Regeneration uses up food, unless due to an artifact */ if ((HRegeneration & ~FROMFORM) || (ERegeneration & ~(W_ARTI | W_WEP))) u.uhunger--; if (near_capacity() > SLT_ENCUMBER) u.uhunger--; } else { /* even turns */ if (Hunger) u.uhunger--; /* Conflict uses up food too */ if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--; /* +0 charged rings don't do anything, so don't affect hunger */ /* Slow digestion still uses ring hunger */ switch ((int) (moves % 20)) { /* note: use even cases only */ case 4: if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged)) u.uhunger--; break; case 8: if (uamul) u.uhunger--; break; case 12: if (uright && (uright->spe || !objects[uright->otyp].oc_charged)) u.uhunger--; break; case 16: if (u.uhave.amulet) u.uhunger--; break; default: break; } } newuhs(TRUE); } /* called after vomiting and after performing feats of magic */ void morehungry(num) int num; { u.uhunger -= num; newuhs(TRUE); } /* called after eating (and after drinking fruit juice) */ void lesshungry(num) int num; { /* See comments in newuhs() for discussion on force_save_hs */ boolean iseating = (occupation == eatfood) || force_save_hs; debugpline1("lesshungry(%d)", num); u.uhunger += num; if (u.uhunger >= 2000) { if (!iseating || context.victual.canchoke) { if (iseating) { choke(context.victual.piece); reset_eat(); } else choke(occupation == opentin ? context.tin.tin : (struct obj *) 0); /* no reset_eat() */ } } else { /* Have lesshungry() report when you're nearly full so all eating * warns when you're about to choke. */ if (u.uhunger >= 1500) { if (!context.victual.eating || (context.victual.eating && !context.victual.fullwarn)) { pline("You're having a hard time getting all of it down."); nomovemsg = "You're finally finished."; if (!context.victual.eating) { multi = -2; } else { context.victual.fullwarn = TRUE; if (context.victual.canchoke && context.victual.reqtime > 1) { /* a one-gulp food will not survive a stop */ if (yn_function("Continue eating?", ynchars, 'n') != 'y') { reset_eat(); nomovemsg = (char *) 0; } } } } } } newuhs(FALSE); } STATIC_PTR int unfaint(VOID_ARGS) { (void) Hear_again(); if (u.uhs > FAINTING) u.uhs = FAINTING; stop_occupation(); context.botl = 1; return 0; } boolean is_fainted() { return (boolean) (u.uhs == FAINTED); } /* call when a faint must be prematurely terminated */ void reset_faint() { if (afternmv == unfaint) unmul("You revive."); } /* compute and comment on your (new?) hunger status */ void newuhs(incr) boolean incr; { unsigned newhs; static unsigned save_hs; static boolean saved_hs = FALSE; int h = u.uhunger; newhs = (h > 1000) ? SATIATED : (h > 150) ? NOT_HUNGRY : (h > 50) ? HUNGRY : (h > 0) ? WEAK : FAINTING; /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY. * This should not produce the message "you only feel hungry now"; * that message should only appear if HUNGRY is an endpoint. Therefore * we check to see if we're in the middle of eating. If so, we save * the first hunger status, and at the end of eating we decide what * message to print based on the _entire_ meal, not on each little bit. */ /* It is normally possible to check if you are in the middle of a meal * by checking occupation == eatfood, but there is one special case: * start_eating() can call bite() for your first bite before it * sets the occupation. * Anyone who wants to get that case to work _without_ an ugly static * force_save_hs variable, feel free. */ /* Note: If you become a certain hunger status in the middle of the * meal, and still have that same status at the end of the meal, * this will incorrectly print the associated message at the end of * the meal instead of the middle. Such a case is currently * impossible, but could become possible if a message for SATIATED * were added or if HUNGRY and WEAK were separated by a big enough * gap to fit two bites. */ if (occupation == eatfood || force_save_hs) { if (!saved_hs) { save_hs = u.uhs; saved_hs = TRUE; } u.uhs = newhs; return; } else { if (saved_hs) { u.uhs = save_hs; saved_hs = FALSE; } } if (newhs == FAINTING) { if (is_fainted()) newhs = FAINTED; if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) { if (!is_fainted() && multi >= 0 /* %% */) { int duration = 10 - (u.uhunger / 10); /* stop what you're doing, then faint */ stop_occupation(); You("faint from lack of food."); if (!Levitation) selftouch("Falling, you"); incr_itimeout(&HDeaf, duration); nomul(-duration); multi_reason = "fainted from lack of food"; nomovemsg = "You regain consciousness."; afternmv = unfaint; newhs = FAINTED; } } else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) { u.uhs = STARVED; context.botl = 1; bot(); You("die from starvation."); killer.format = KILLED_BY; Strcpy(killer.name, "starvation"); done(STARVING); /* if we return, we lifesaved, and that calls newuhs */ return; } } if (newhs != u.uhs) { if (newhs >= WEAK && u.uhs < WEAK) losestr(1); /* this may kill you -- see below */ else if (newhs < WEAK && u.uhs >= WEAK) losestr(-1); switch (newhs) { case HUNGRY: if (Hallucination) { You((!incr) ? "now have a lesser case of the munchies." : "are getting the munchies."); } else You((!incr) ? "only feel hungry now." : (u.uhunger < 145) ? "feel hungry." : "are beginning to feel hungry."); if (incr && occupation && (occupation != eatfood && occupation != opentin)) stop_occupation(); context.travel = context.travel1 = context.mv = context.run = 0; break; case WEAK: if (Hallucination) pline((!incr) ? "You still have the munchies." : "The munchies are interfering with your motor capabilities."); else if (incr && (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE))) pline("%s needs food, badly!", (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m : "Elf"); else You((!incr) ? "feel weak now." : (u.uhunger < 45) ? "feel weak." : "are beginning to feel weak."); if (incr && occupation && (occupation != eatfood && occupation != opentin)) stop_occupation(); context.travel = context.travel1 = context.mv = context.run = 0; break; } u.uhs = newhs; context.botl = 1; bot(); if ((Upolyd ? u.mh : u.uhp) < 1) { You("die from hunger and exhaustion."); killer.format = KILLED_BY; Strcpy(killer.name, "exhaustion"); done(STARVING); return; } } } /* Returns an object representing food. * Object may be either on floor or in inventory. */ struct obj * floorfood(verb, corpsecheck) const char *verb; int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ { register struct obj *otmp; char qbuf[QBUFSZ]; char c; boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */ offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */ /* if we can't touch floor objects then use invent food only */ if (!can_reach_floor(TRUE) || (feeding && u.usteed) || (is_pool_or_lava(u.ux, u.uy) && (Wwalking || is_clinger(youmonst.data) || (Flying && !Breathless)))) goto skipfloor; if (feeding && metallivorous(youmonst.data)) { struct obj *gold; struct trap *ttmp = t_at(u.ux, u.uy); if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) { /* If not already stuck in the trap, perhaps there should be a chance to becoming trapped? Probably not, because then the trap would just get eaten on the _next_ turn... */ Sprintf(qbuf, "There is a bear trap here (%s); eat it?", (u.utrap && u.utraptype == TT_BEARTRAP) ? "holding you" : "armed"); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { u.utrap = u.utraptype = 0; deltrap(ttmp); return mksobj(BEARTRAP, TRUE, FALSE); } else if (c == 'q') { return (struct obj *) 0; } } if (youmonst.data != &mons[PM_RUST_MONSTER] && (gold = g_at(u.ux, u.uy)) != 0) { if (gold->quan == 1L) Sprintf(qbuf, "There is 1 gold piece here; eat it?"); else Sprintf(qbuf, "There are %ld gold pieces here; eat them?", gold->quan); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { return gold; } else if (c == 'q') { return (struct obj *) 0; } } } /* Is there some food (probably a heavy corpse) here on the ground? */ for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { if (corpsecheck ? (otmp->otyp == CORPSE && (corpsecheck == 1 || tinnable(otmp))) : feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) : otmp->oclass == FOOD_CLASS) { char qsfx[QBUFSZ]; boolean one = (otmp->quan == 1L); /* "There is here; it?" or "There are here; one?" */ Sprintf(qbuf, "There %s ", otense(otmp, "are")); Sprintf(qsfx, " here; %s %s?", verb, one ? "it" : "one"); (void) safe_qbuf(qbuf, qbuf, qsfx, otmp, doname, ansimpleoname, one ? something : (const char *) "things"); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') return otmp; else if (c == 'q') return (struct obj *) 0; } } skipfloor: /* We cannot use ALL_CLASSES since that causes getobj() to skip its * "ugly checks" and we need to check for inedible items. */ otmp = getobj(feeding ? allobj : offering ? offerfodder : comestibles, verb); if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS)) if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) { You_cant("%s that!", verb); return (struct obj *) 0; } return otmp; } /* Side effects of vomiting */ /* added nomul (MRS) - it makes sense, you're too busy being sick! */ void vomit() /* A good idea from David Neves */ { if (cantvomit(youmonst.data)) /* doesn't cure food poisoning; message assumes that we aren't dealing with some esoteric body_part() */ Your("jaw gapes convulsively."); else make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE); nomul(-2); multi_reason = "vomiting"; nomovemsg = You_can_move_again; } int eaten_stat(base, obj) int base; struct obj *obj; { long uneaten_amt, full_amount; uneaten_amt = (long) obj->oeaten; full_amount = (obj->otyp == CORPSE) ? (long) mons[obj->corpsenm].cnutrit : (long) objects[obj->otyp].oc_nutrition; if (uneaten_amt > full_amount) { impossible( "partly eaten food (%ld) more nutritious than untouched food (%ld)", uneaten_amt, full_amount); uneaten_amt = full_amount; } base = (int) (full_amount ? (long) base * uneaten_amt / full_amount : 0L); return (base < 1) ? 1 : base; } /* reduce obj's oeaten field, making sure it never hits or passes 0 */ void consume_oeaten(obj, amt) struct obj *obj; int amt; { /* * This is a hack to try to squelch several long standing mystery * food bugs. A better solution would be to rewrite the entire * victual handling mechanism from scratch using a less complex * model. Alternatively, this routine could call done_eating() * or food_disappears() but its callers would need revisions to * cope with context.victual.piece unexpectedly going away. * * Multi-turn eating operates by setting the food's oeaten field * to its full nutritional value and then running a counter which * independently keeps track of whether there is any food left. * The oeaten field can reach exactly zero on the last turn, and * the object isn't removed from inventory until the next turn * when the "you finish eating" message gets delivered, so the * food would be restored to the status of untouched during that * interval. This resulted in unexpected encumbrance messages * at the end of a meal (if near enough to a threshold) and would * yield full food if there was an interruption on the critical * turn. Also, there have been reports over the years of food * becoming massively heavy or producing unlimited satiation; * this would occur if reducing oeaten via subtraction attempted * to drop it below 0 since its unsigned type would produce a * huge positive value instead. So far, no one has figured out * _why_ that inappropriate subtraction might sometimes happen. */ if (amt > 0) { /* bit shift to divide the remaining amount of food */ obj->oeaten >>= amt; } else { /* simple decrement; value is negative so we actually add it */ if ((int) obj->oeaten > -amt) obj->oeaten += amt; else obj->oeaten = 0; } if (obj->oeaten == 0) { if (obj == context.victual.piece) /* always true unless wishing... */ context.victual.reqtime = context.victual.usedtime; /* no bites left */ obj->oeaten = 1; /* smallest possible positive value */ } } /* called when eatfood occupation has been interrupted, or in the case of theft, is about to be interrupted */ boolean maybe_finished_meal(stopping) boolean stopping; { /* in case consume_oeaten() has decided that the food is all gone */ if (occupation == eatfood && context.victual.usedtime >= context.victual.reqtime) { if (stopping) occupation = 0; /* for do_reset_eat */ (void) eatfood(); /* calls done_eating() to use up context.victual.piece */ return TRUE; } return FALSE; } /* Tin of to the rescue? Decide whether current occupation is an attempt to eat a tin of something capable of saving hero's life. We don't care about consumption of non-tinned food here because special effects there take place on first bite rather than at end of occupation. [Popeye the Sailor gets out of trouble by eating tins of spinach. :-] */ boolean Popeye(threat) int threat; { struct obj *otin; int mndx; if (occupation != opentin) return FALSE; otin = context.tin.tin; /* make sure hero still has access to tin */ if (!carried(otin) && (!obj_here(otin, u.ux, u.uy) || !can_reach_floor(TRUE))) return FALSE; /* unknown tin is assumed to be helpful */ if (!otin->known) return TRUE; /* known tin is helpful if it will stop life-threatening problem */ mndx = otin->corpsenm; switch (threat) { /* note: not used; hunger code bypasses stop_occupation() when eating */ case HUNGER: return (boolean) (mndx != NON_PM || otin->spe == 1); /* flesh from lizards and acidic critters stops petrification */ case STONED: return (boolean) (mndx >= LOW_PM && (mndx == PM_LIZARD || acidic(&mons[mndx]))); /* no tins can cure these (yet?) */ case SLIMED: case SICK: case VOMITING: break; default: break; } return FALSE; } /*eat.c*/ nethack-3.6.0/src/end.c0000664000076400007660000015130212625266574013657 0ustar paxedpaxed/* NetHack 3.6 end.c $NHDT-Date: 1448241780 2015/11/23 01:23:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.108 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #define NEED_VARARGS /* comment line for pre-compiled headers */ #include "hack.h" #include "lev.h" #ifndef NO_SIGNAL #include #endif #include #include #include "dlb.h" /* add b to long a, convert wraparound to max value */ #define nowrap_add(a, b) (a = ((a + b) < 0 ? LONG_MAX : (a + b))) /* these probably ought to be generated by makedefs, like LAST_GEM */ #define FIRST_GEM DILITHIUM_CRYSTAL #define FIRST_AMULET AMULET_OF_ESP #define LAST_AMULET AMULET_OF_YENDOR struct valuable_data { long count; int typ; }; static struct valuable_data gems[LAST_GEM + 1 - FIRST_GEM + 1], /* 1 extra for glass */ amulets[LAST_AMULET + 1 - FIRST_AMULET]; static struct val_list { struct valuable_data *list; int size; } valuables[] = { { gems, sizeof gems / sizeof *gems }, { amulets, sizeof amulets / sizeof *amulets }, { 0, 0 } }; #ifndef NO_SIGNAL STATIC_PTR void FDECL(done_intr, (int)); #if defined(UNIX) || defined(VMS) || defined(__EMX__) static void FDECL(done_hangup, (int)); #endif #endif STATIC_DCL void FDECL(disclose, (int, BOOLEAN_P)); STATIC_DCL void FDECL(get_valuables, (struct obj *)); STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *, int)); STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid)); STATIC_DCL void FDECL(really_done, (int)) NORETURN; STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int)); STATIC_DCL void FDECL(savelife, (int)); STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P)); STATIC_DCL void FDECL(list_genocided, (CHAR_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *)); STATIC_DCL int NDECL(num_extinct); #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2) extern void FDECL(nethack_exit, (int)); #else #define nethack_exit exit #endif #define done_stopprint program_state.stopprint #ifndef PANICTRACE #define NH_abort NH_abort_ #endif #ifdef AMIGA #define NH_abort_() Abort(0) #else #ifdef SYSV #define NH_abort_() (void) abort() #else #ifdef WIN32 #define NH_abort_() win32_abort() #else #define NH_abort_() abort() #endif #endif /* !SYSV */ #endif /* !AMIGA */ #ifdef PANICTRACE #include #ifdef PANICTRACE_LIBC #include #endif /* What do we try and in what order? Tradeoffs: * libc: +no external programs required * -requires newish libc/glibc * -requires -rdynamic * gdb: +gives more detailed information * +works on more OS versions * -requires -g, which may preclude -O on some compilers */ #ifdef SYSCF #define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb #ifdef PANICTRACE_LIBC #define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc #else #define SYSOPT_PANICTRACE_LIBC 0 #endif #else #define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2) #ifdef PANICTRACE_LIBC #define SYSOPT_PANICTRACE_LIBC 1 #else #define SYSOPT_PANICTRACE_LIBC 0 #endif #endif static void NDECL(NH_abort); #ifndef NO_SIGNAL static void FDECL(panictrace_handler, (int)); #endif static boolean NDECL(NH_panictrace_libc); static boolean NDECL(NH_panictrace_gdb); #ifndef NO_SIGNAL /*ARGSUSED*/ void panictrace_handler( sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused UNUSED; { #define SIG_MSG "\nSignal received.\n" (void) write(2, SIG_MSG, sizeof(SIG_MSG) - 1); NH_abort(); } void panictrace_setsignals(set) boolean set; { #define SETSIGNAL(sig) \ (void) signal(sig, set ? (SIG_RET_TYPE) panictrace_handler : SIG_DFL); #ifdef SIGILL SETSIGNAL(SIGILL); #endif #ifdef SIGTRAP SETSIGNAL(SIGTRAP); #endif #ifdef SIGIOT SETSIGNAL(SIGIOT); #endif #ifdef SIGBUS SETSIGNAL(SIGBUS); #endif #ifdef SIGFPE SETSIGNAL(SIGFPE); #endif #ifdef SIGSEGV SETSIGNAL(SIGSEGV); #endif #ifdef SIGSTKFLT SETSIGNAL(SIGSTKFLT); #endif #ifdef SIGSYS SETSIGNAL(SIGSYS); #endif #ifdef SIGEMT SETSIGNAL(SIGEMT); #endif #undef SETSIGNAL } #endif /* NO_SIGNAL */ static void NH_abort() { int gdb_prio = SYSOPT_PANICTRACE_GDB; int libc_prio = SYSOPT_PANICTRACE_LIBC; static boolean aborting = FALSE; if (aborting) return; aborting = TRUE; #ifndef VMS if (gdb_prio == libc_prio && gdb_prio > 0) gdb_prio++; if (gdb_prio > libc_prio) { NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc()); } else { NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb()); } #else /* VMS */ /* overload otherwise unused priority for debug mode: 1 = show traceback and exit; 2 = show traceback and stay in debugger */ /* if (wizard && gdb_prio == 1) gdb_prio = 2; */ vms_traceback(gdb_prio); (void) libc_prio; /* half-hearted attempt at lint suppression */ #endif /* ?VMS */ #ifndef NO_SIGNAL panictrace_setsignals(FALSE); #endif NH_abort_(); } static boolean NH_panictrace_libc() { #ifdef PANICTRACE_LIBC void *bt[20]; size_t count, x; char **info; raw_print("Generating more information you may report:\n"); count = backtrace(bt, SIZE(bt)); info = backtrace_symbols(bt, count); for (x = 0; x < count; x++) { raw_printf("[%lu] %s", (unsigned long) x, info[x]); } /* free(info); -- Don't risk it. */ return TRUE; #else return FALSE; #endif /* !PANICTRACE_LIBC */ } /* * fooPATH file system path for foo * fooVAR (possibly const) variable containing fooPATH */ #ifdef PANICTRACE_GDB #ifdef SYSCF #define GDBVAR sysopt.gdbpath #define GREPVAR sysopt.greppath #else /* SYSCF */ #define GDBVAR GDBPATH #define GREPVAR GREPPATH #endif /* SYSCF */ #endif /* PANICTRACE_GDB */ static boolean NH_panictrace_gdb() { #ifdef PANICTRACE_GDB /* A (more) generic method to get a stack trace - invoke * gdb on ourself. */ char *gdbpath = GDBVAR; char *greppath = GREPVAR; char buf[BUFSZ]; FILE *gdb; if (gdbpath == NULL || gdbpath[0] == 0) return FALSE; if (greppath == NULL || greppath[0] == 0) return FALSE; sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", gdbpath, ARGV0, getpid(), greppath); gdb = popen(buf, "w"); if (gdb) { raw_print("Generating more information you may report:\n"); fprintf(gdb, "bt\nquit\ny"); fflush(gdb); sleep(4); /* ugly */ pclose(gdb); return TRUE; } else { return FALSE; } #else return FALSE; #endif /* !PANICTRACE_GDB */ } #endif /* PANICTRACE */ /* * The order of these needs to match the macros in hack.h. */ static NEARDATA const char *deaths[] = { /* the array of death */ "died", "choked", "poisoned", "starvation", "drowning", "burning", "dissolving under the heat and pressure", "crushed", "turned to stone", "turned into slime", "genocided", "panic", "trickery", "quit", "escaped", "ascended" }; static NEARDATA const char *ends[] = { /* "when you %s" */ "died", "choked", "were poisoned", "starved", "drowned", "burned", "dissolved in the lava", "were crushed", "turned to stone", "turned into slime", "were genocided", "panicked", "were tricked", "quit", "escaped", "ascended" }; static boolean Schroedingers_cat = FALSE; /*ARGSUSED*/ void done1(sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused UNUSED; { #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif if (flags.ignintr) { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif clear_nhwindow(WIN_MESSAGE); curs_on_u(); wait_synch(); if (multi > 0) nomul(0); } else { (void) done2(); } } /* "#quit" command or keyboard interrupt */ int done2() { if (!paranoid_query(ParanoidQuit, "Really quit?")) { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif clear_nhwindow(WIN_MESSAGE); curs_on_u(); wait_synch(); if (multi > 0) nomul(0); if (multi == 0) { u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */ u.usleep = 0; } return 0; } #if (defined(UNIX) || defined(VMS) || defined(LATTICE)) if (wizard) { int c; #ifdef VMS extern int debuggable; /* sys/vms/vmsmisc.c, vmsunix.c */ c = !debuggable ? 'n' : ynq("Enter debugger?"); #else #ifdef LATTICE c = ynq("Create SnapShot?"); #else c = ynq("Dump core?"); #endif #endif if (c == 'y') { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif exit_nhwindows((char *) 0); NH_abort(); } else if (c == 'q') done_stopprint++; } #endif #ifndef LINT done(QUIT); #endif return 0; } #ifndef NO_SIGNAL /*ARGSUSED*/ STATIC_PTR void done_intr(sig_unused) /* called as signal() handler, so sent at least 1 arg */ int sig_unused UNUSED; { done_stopprint++; (void) signal(SIGINT, SIG_IGN); #if defined(UNIX) || defined(VMS) (void) signal(SIGQUIT, SIG_IGN); #endif return; } #if defined(UNIX) || defined(VMS) || defined(__EMX__) /* signal() handler */ static void done_hangup(sig) int sig; { program_state.done_hup++; sethanguphandler((void FDECL((*), (int) )) SIG_IGN); done_intr(sig); return; } #endif #endif /* NO_SIGNAL */ void done_in_by(mtmp, how) struct monst *mtmp; int how; { char buf[BUFSZ]; struct permonst *mptr = mtmp->data, *champtr = ((mtmp->cham >= LOW_PM) ? &mons[mtmp->cham] : mptr); boolean distorted = (boolean) (Hallucination && canspotmon(mtmp)), mimicker = (mtmp->m_ap_type == M_AP_MONSTER), imitator = (mptr != champtr || mimicker); You((how == STONING) ? "turn to stone..." : "die..."); mark_synch(); /* flush buffered screen output */ buf[0] = '\0'; killer.format = KILLED_BY_AN; /* "killed by the high priest of Crom" is okay, "killed by the high priest" alone isn't */ if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker) && !(mptr == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) { if (!type_is_pname(mptr)) Strcat(buf, "the "); killer.format = KILLED_BY; } /* _the_ ghost of Dudley */ if (mptr == &mons[PM_GHOST] && has_mname(mtmp)) { Strcat(buf, "the "); killer.format = KILLED_BY; } if (mtmp->minvis) Strcat(buf, "invisible "); if (distorted) Strcat(buf, "hallucinogen-distorted "); if (imitator) { char shape[BUFSZ]; const char *realnm = champtr->mname, *fakenm = mptr->mname; boolean alt = is_vampshifter(mtmp); if (mimicker) { /* realnm is already correct because champtr==mptr; set up fake mptr for type_is_pname/the_unique_pm */ mptr = &mons[mtmp->mappearance]; fakenm = mptr->mname; } else if (alt && strstri(realnm, "vampire") && !strcmp(fakenm, "vampire bat")) { /* special case: use "vampire in bat form" in preference to redundant looking "vampire in vampire bat form" */ fakenm = "bat"; } /* for the alternate format, always suppress any article; pname and the_unique should also have s_suffix() applied, but vampires don't take on any shapes which warrant that */ if (alt || type_is_pname(mptr)) /* no article */ Strcpy(shape, fakenm); else if (the_unique_pm(mptr)) /* "the"; don't use the() here */ Sprintf(shape, "the %s", fakenm); else /* "a"/"an" */ Strcpy(shape, an(fakenm)); /* omit "called" to avoid excessive verbosity */ Sprintf(eos(buf), alt ? "%s in %s form" : mimicker ? "%s disguised as %s" : "%s imitating %s", realnm, shape); mptr = mtmp->data; /* reset for mimicker case */ } else if (mptr == &mons[PM_GHOST]) { Strcat(buf, "ghost"); if (has_mname(mtmp)) Sprintf(eos(buf), " of %s", MNAME(mtmp)); } else if (mtmp->isshk) { const char *shknm = shkname(mtmp), *honorific = shkname_is_pname(mtmp) ? "" : mtmp->female ? "Ms. " : "Mr. "; Sprintf(eos(buf), "%s%s, the shopkeeper", honorific, shknm); killer.format = KILLED_BY; } else if (mtmp->ispriest || mtmp->isminion) { /* m_monnam() suppresses "the" prefix plus "invisible", and it overrides the effect of Hallucination on priestname() */ Strcat(buf, m_monnam(mtmp)); } else { Strcat(buf, mptr->mname); if (has_mname(mtmp)) Sprintf(eos(buf), " called %s", MNAME(mtmp)); } Strcpy(killer.name, buf); if (mptr->mlet == S_WRAITH) u.ugrave_arise = PM_WRAITH; else if (mptr->mlet == S_MUMMY && urace.mummynum != NON_PM) u.ugrave_arise = urace.mummynum; else if (mptr->mlet == S_VAMPIRE && Race_if(PM_HUMAN)) u.ugrave_arise = PM_VAMPIRE; else if (mptr == &mons[PM_GHOUL]) u.ugrave_arise = PM_GHOUL; /* this could happen if a high-end vampire kills the hero when ordinary vampires are genocided; ditto for wraiths */ if (u.ugrave_arise >= LOW_PM && (mvitals[u.ugrave_arise].mvflags & G_GENOD)) u.ugrave_arise = NON_PM; done(how); return; } #if defined(WIN32) && !defined(SYSCF) #define NOTIFY_NETHACK_BUGS #endif /*VARARGS1*/ void panic VA_DECL(const char *, str) { VA_START(str); VA_INIT(str, char *); if (program_state.panicking++) NH_abort(); /* avoid loops - this should never happen*/ if (iflags.window_inited) { raw_print("\r\nOops..."); wait_synch(); /* make sure all pending output gets flushed */ exit_nhwindows((char *) 0); iflags.window_inited = 0; /* they're gone; force raw_print()ing */ } raw_print(program_state.gameover ? "Postgame wrapup disrupted." : !program_state.something_worth_saving ? "Program initialization has failed." : "Suddenly, the dungeon collapses."); #ifndef MICRO #if defined(NOTIFY_NETHACK_BUGS) if (!wizard) raw_printf("Report the following error to \"%s\" or at \"%s\".", DEVTEAM_EMAIL, DEVTEAM_URL); else if (program_state.something_worth_saving) raw_print("\nError save file being written.\n"); #else if (!wizard) { const char *maybe_rebuild = !program_state.something_worth_saving ? "." : "\nand it may be possible to rebuild."; if (sysopt.support) raw_printf("To report this error, %s%s", sysopt.support, maybe_rebuild); else if (sysopt.fmtd_wizard_list) /* formatted SYSCF WIZARDS */ raw_printf("To report this error, contact %s%s", sysopt.fmtd_wizard_list, maybe_rebuild); else raw_printf("Report error to \"%s\"%s", WIZARD_NAME, maybe_rebuild); } #endif /* XXX can we move this above the prints? Then we'd be able to * suppress "it may be possible to rebuild" based on dosave0() * or say it's NOT possible to rebuild. */ if (program_state.something_worth_saving) { set_error_savefile(); if (dosave0()) { /* os/win port specific recover instructions */ if (sysopt.recover) raw_printf("%s", sysopt.recover); } } #endif { char buf[BUFSZ]; Vsprintf(buf, str, VA_ARGS); raw_print(buf); paniclog("panic", buf); } #ifdef WIN32 interject(INTERJECT_PANIC); #endif #if defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32) if (wizard) NH_abort(); /* generate core dump */ #endif VA_END(); really_done(PANICKED); } STATIC_OVL boolean should_query_disclose_option(category, defquery) int category; char *defquery; { int idx; char *dop; *defquery = 'n'; if ((dop = index(disclosure_options, category)) != 0) { idx = (int) (dop - disclosure_options); if (idx < 0 || idx >= NUM_DISCLOSURE_OPTIONS) { impossible( "should_query_disclose_option: bad disclosure index %d %c", idx, category); *defquery = DISCLOSE_PROMPT_DEFAULT_YES; return TRUE; } if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) { *defquery = 'y'; return FALSE; } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) { *defquery = 'n'; return FALSE; } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) { *defquery = 'y'; return TRUE; } else { *defquery = 'n'; return TRUE; } } impossible("should_query_disclose_option: bad category %c", category); return TRUE; } STATIC_OVL void disclose(how, taken) int how; boolean taken; { char c = '\0', defquery; char qbuf[QBUFSZ]; boolean ask = FALSE; if (invent && !done_stopprint) { if (taken) Sprintf(qbuf, "Do you want to see what you had when you %s?", (how == QUIT) ? "quit" : "died"); else Strcpy(qbuf, "Do you want your possessions identified?"); ask = should_query_disclose_option('i', &defquery); c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery; if (c == 'y') { struct obj *obj; for (obj = invent; obj; obj = obj->nobj) { makeknown(obj->otyp); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; if (Is_container(obj) || obj->otyp == STATUE) obj->cknown = obj->lknown = 1; } (void) display_inventory((char *) 0, TRUE); container_contents(invent, TRUE, TRUE, FALSE); } if (c == 'q') done_stopprint++; } if (!done_stopprint) { ask = should_query_disclose_option('a', &defquery); c = ask ? yn_function("Do you want to see your attributes?", ynqchars, defquery) : defquery; if (c == 'y') enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT), (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD); if (c == 'q') done_stopprint++; } if (!done_stopprint) { ask = should_query_disclose_option('v', &defquery); list_vanquished(defquery, ask); } if (!done_stopprint) { ask = should_query_disclose_option('g', &defquery); list_genocided(defquery, ask); } if (!done_stopprint) { ask = should_query_disclose_option('c', &defquery); c = ask ? yn_function("Do you want to see your conduct?", ynqchars, defquery) : defquery; if (c == 'y') show_conduct((how >= PANICKED) ? 1 : 2); if (c == 'q') done_stopprint++; } if (!done_stopprint) { ask = should_query_disclose_option('o', &defquery); c = ask ? yn_function("Do you want to see the dungeon overview?", ynqchars, defquery) : defquery; if (c == 'y') show_overview((how >= PANICKED) ? 1 : 2, how); if (c == 'q') done_stopprint++; } } /* try to get the player back in a viable state after being killed */ STATIC_OVL void savelife(how) int how; { int uhpmin = max(2 * u.ulevel, 10); if (u.uhpmax < uhpmin) u.uhpmax = uhpmin; u.uhp = u.uhpmax; u.uswldtim = 0; if (u.uhunger < 500) { u.uhunger = 500; newuhs(FALSE); } /* cure impending doom of sickness hero won't have time to fix */ if ((Sick & TIMEOUT) == 1L) { u.usick_type = 0; set_itimeout(&Sick, 0L); } if (how == CHOKING) init_uhunger(); nomovemsg = "You survived that attempt on your life."; context.move = 0; if (multi > 0) multi = 0; else multi = -1; if (u.utrap && u.utraptype == TT_LAVA) u.utrap = 0; context.botl = 1; u.ugrave_arise = NON_PM; HUnchanging = 0L; curs_on_u(); } /* * Get valuables from the given list. Revised code: the list always remains * intact. */ STATIC_OVL void get_valuables(list) struct obj *list; /* inventory or container contents */ { register struct obj *obj; register int i; /* find amulets and gems, ignoring all artifacts */ for (obj = list; obj; obj = obj->nobj) if (Has_contents(obj)) { get_valuables(obj->cobj); } else if (obj->oartifact) { continue; } else if (obj->oclass == AMULET_CLASS) { i = obj->otyp - FIRST_AMULET; if (!amulets[i].count) { amulets[i].count = obj->quan; amulets[i].typ = obj->otyp; } else amulets[i].count += obj->quan; /* always adds one */ } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) { i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM; if (!gems[i].count) { gems[i].count = obj->quan; gems[i].typ = obj->otyp; } else gems[i].count += obj->quan; } return; } /* * Sort collected valuables, most frequent to least. We could just * as easily use qsort, but we don't care about efficiency here. */ STATIC_OVL void sort_valuables(list, size) struct valuable_data list[]; int size; /* max value is less than 20 */ { register int i, j; struct valuable_data ltmp; /* move greater quantities to the front of the list */ for (i = 1; i < size; i++) { if (list[i].count == 0) continue; /* empty slot */ ltmp = list[i]; /* structure copy */ for (j = i; j > 0; --j) if (list[j - 1].count >= ltmp.count) break; else { list[j] = list[j - 1]; } list[j] = ltmp; } return; } #define CAT_CHECK 2 STATIC_OVL boolean odds_and_ends(list, what) struct obj *list; int what; { struct obj *otmp; for (otmp = list; otmp; otmp = otmp->nobj) { switch (what) { case CAT_CHECK: /* Schroedinger's Cat */ /* Ascending is deterministic */ if (SchroedingersBox(otmp)) return rn2(2); break; } if (Has_contents(otmp)) return odds_and_ends(otmp->cobj, what); } return FALSE; } /* called twice; first to calculate total, then to list relevant items */ STATIC_OVL void artifact_score(list, counting, endwin) struct obj *list; boolean counting; /* true => add up points; false => display them */ winid endwin; { char pbuf[BUFSZ]; struct obj *otmp; long value, points; short dummy; /* object type returned by artifact_name() */ for (otmp = list; otmp; otmp = otmp->nobj) { if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING || otmp->otyp == SPE_BOOK_OF_THE_DEAD || otmp->otyp == CANDELABRUM_OF_INVOCATION) { value = arti_cost(otmp); /* zorkmid value */ points = value * 5 / 2; /* score value */ if (counting) { nowrap_add(u.urexp, points); } else { makeknown(otmp->otyp); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; /* assumes artifacts don't have quan > 1 */ Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)", the_unique_obj(otmp) ? "The " : "", otmp->oartifact ? artifact_name(xname(otmp), &dummy) : OBJ_NAME(objects[otmp->otyp]), value, currency(value), points); putstr(endwin, 0, pbuf); } } if (Has_contents(otmp)) artifact_score(otmp->cobj, counting, endwin); } } /* Be careful not to call panic from here! */ void done(how) int how; { if (how == TRICKED) { if (killer.name[0]) { paniclog("trickery", killer.name); killer.name[0] = 0; } if (wizard) { You("are a very tricky wizard, it seems."); return; } } if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED)) killer.format = NO_KILLER_PREFIX; /* Avoid killed by "a" burning or "a" starvation */ if (!killer.name[0] && (how == STARVING || how == BURNING)) killer.format = KILLED_BY; if (!killer.name[0] || how >= PANICKED) Strcpy(killer.name, deaths[how]); if (how < PANICKED) u.umortality++; if (Lifesaved && (how <= GENOCIDED)) { pline("But wait..."); makeknown(AMULET_OF_LIFE_SAVING); Your("medallion %s!", !Blind ? "begins to glow" : "feels warm"); if (how == CHOKING) You("vomit ..."); You_feel("much better!"); pline_The("medallion crumbles to dust!"); if (uamul) useup(uamul); (void) adjattrib(A_CON, -1, TRUE); savelife(how); if (how == GENOCIDED) { pline("Unfortunately you are still genocided..."); } else { killer.name[0] = 0; killer.format = 0; return; } } if ((wizard || discover) && (how <= GENOCIDED) && !paranoid_query(ParanoidDie, "Die?")) { pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die"); savelife(how); killer.name[0] = 0; killer.format = 0; return; } really_done(how); } /* separated from done() in order to specify the __noreturn__ attribute */ STATIC_OVL void really_done(how) int how; { boolean taken; char pbuf[BUFSZ]; winid endwin = WIN_ERR; boolean bones_ok, have_windows = iflags.window_inited; struct obj *corpse = (struct obj *) 0; time_t endtime; long umoney; long tmp; /* * The game is now over... */ program_state.gameover = 1; /* in case of a subsequent panic(), there's no point trying to save */ program_state.something_worth_saving = 0; /* render vision subsystem inoperative */ iflags.vision_inited = 0; /* might have been killed while using a disposable item, so make sure it's gone prior to inventory disclosure and creation of bones data */ inven_inuse(TRUE); /* maybe not on object lists; if an active light source, would cause big trouble (`obj_is_local' panic) for savebones() -> savelev() */ if (thrownobj && thrownobj->where == OBJ_FREE) dealloc_obj(thrownobj); if (kickedobj && kickedobj->where == OBJ_FREE) dealloc_obj(kickedobj); /* remember time of death here instead of having bones, rip, and topten figure it out separately and possibly getting different time or even day if player is slow responding to --More-- */ endtime = getnow(); urealtime.realtime += (long) (endtime - urealtime.restored); /* Sometimes you die on the first move. Life's not fair. * On those rare occasions you get hosed immediately, go out * smiling... :-) -3. */ if (moves <= 1 && how < PANICKED) /* You die... --More-- */ pline("Do not pass go. Do not collect 200 %s.", currency(200L)); if (have_windows) wait_synch(); /* flush screen output */ #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done_intr); #if defined(UNIX) || defined(VMS) || defined(__EMX__) (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr); sethanguphandler(done_hangup); #endif #endif /* NO_SIGNAL */ bones_ok = (how < GENOCIDED) && can_make_bones(); if (bones_ok && launch_in_progress()) force_launch_placement(); /* maintain ugrave_arise even for !bones_ok */ if (how == PANICKED) u.ugrave_arise = (NON_PM - 3); /* no corpse, no grave */ else if (how == BURNING || how == DISSOLVED) /* corpse burns up too */ u.ugrave_arise = (NON_PM - 2); /* leave no corpse */ else if (how == STONING) u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */ else if (how == TURNED_SLIME) u.ugrave_arise = PM_GREEN_SLIME; /* if pets will contribute to score, populate mydogs list now (bones creation isn't a factor, but pline() messaging is) */ if (how == ESCAPED || how == ASCENDED) keepdogs(TRUE); if (how == QUIT) { killer.format = NO_KILLER_PREFIX; if (u.uhp < 1) { how = DIED; u.umortality++; /* skipped above when how==QUIT */ Strcpy(killer.name, "quit while already on Charon's boat"); } } if (how == ESCAPED || how == PANICKED) killer.format = NO_KILLER_PREFIX; if (how != PANICKED) { /* these affect score and/or bones, but avoid them during panic */ taken = paybill((how == ESCAPED) ? -1 : (how != QUIT)); paygd(); clearpriests(); } else taken = FALSE; /* lint; assert( !bones_ok ); */ clearlocks(); if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE); if (strcmp(flags.end_disclose, "none") && how != PANICKED) disclose(how, taken); /* finish_paybill should be called after disclosure but before bones */ if (bones_ok && taken) finish_paybill(); /* grave creation should be after disclosure so it doesn't have this grave in the current level's features for #overview */ if (bones_ok && u.ugrave_arise == NON_PM && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) { int mnum = u.umonnum; if (!Upolyd) { /* Base corpse on race when not poly'd since original * u.umonnum is based on role, and all role monsters * are human. */ mnum = (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : urace.malenum; } corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname); Sprintf(pbuf, "%s, ", plname); formatkiller(eos(pbuf), sizeof pbuf - strlen(pbuf), how); make_grave(u.ux, u.uy, pbuf); } pbuf[0] = '\0'; /* clear grave text; also lint suppression */ /* calculate score, before creating bones [container gold] */ { int deepest = deepest_lev_reached(FALSE); umoney = money_cnt(invent); tmp = u.umoney0; umoney += hidden_gold(); /* accumulate gold from containers */ tmp = umoney - tmp; /* net gain */ if (tmp < 0L) tmp = 0L; if (how < PANICKED) tmp -= tmp / 10L; tmp += 50L * (long) (deepest - 1); if (deepest > 20) tmp += 1000L * (long) ((deepest > 30) ? 10 : deepest - 20); nowrap_add(u.urexp, tmp); /* ascension gives a score bonus iff offering to original deity */ if (how == ASCENDED && u.ualign.type == u.ualignbase[A_ORIGINAL]) { /* retaining original alignment: score *= 2; converting, then using helm-of-OA to switch back: *= 1.5 */ tmp = (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) ? u.urexp : (u.urexp / 2L); nowrap_add(u.urexp, tmp); } } if (u.ugrave_arise >= LOW_PM && u.ugrave_arise != PM_GREEN_SLIME) { /* give this feedback even if bones aren't going to be created, so that its presence or absence doesn't tip off the player to new bones or their lack; it might be a lie if makemon fails */ Your("body rises from the dead as %s...", an(mons[u.ugrave_arise].mname)); display_nhwindow(WIN_MESSAGE, FALSE); } if (bones_ok) { if (!wizard || paranoid_query(ParanoidBones, "Save bones?")) savebones(how, endtime, corpse); /* corpse may be invalid pointer now so ensure that it isn't used again */ corpse = (struct obj *) 0; } /* update gold for the rip output, which can't use hidden_gold() (containers will be gone by then if bones just got saved...) */ done_money = umoney; /* clean up unneeded windows */ if (have_windows) { wait_synch(); free_pickinv_cache(); /* extra persistent window if perm_invent */ if (WIN_INVEN != WIN_ERR) destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR; #ifndef STATUS_VIA_WINDOWPORT destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR; #endif destroy_nhwindow(WIN_MESSAGE), WIN_MESSAGE = WIN_ERR; if (!done_stopprint || flags.tombstone) endwin = create_nhwindow(NHW_TEXT); if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR) outrip(endwin, how, endtime); } else done_stopprint = 1; /* just avoid any more output */ if (u.uhave.amulet) { Strcat(killer.name, " (with the Amulet)"); } else if (how == ESCAPED) { if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */ Strcat(killer.name, " (in celestial disgrace)"); else if (carrying(FAKE_AMULET_OF_YENDOR)) Strcat(killer.name, " (with a fake Amulet)"); /* don't bother counting to see whether it should be plural */ } if (!done_stopprint) { Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname, (how != ASCENDED) ? (const char *) ((flags.female && urole.name.f) ? urole.name.f : urole.name.m) : (const char *) (flags.female ? "Demigoddess" : "Demigod")); putstr(endwin, 0, pbuf); putstr(endwin, 0, ""); } if (how == ESCAPED || how == ASCENDED) { struct monst *mtmp; struct obj *otmp; register struct val_list *val; register int i; for (val = valuables; val->list; val++) for (i = 0; i < val->size; i++) { val->list[i].count = 0L; } get_valuables(invent); /* add points for collected valuables */ for (val = valuables; val->list; val++) for (i = 0; i < val->size; i++) if (val->list[i].count != 0L) { tmp = val->list[i].count * (long) objects[val->list[i].typ].oc_cost; nowrap_add(u.urexp, tmp); } /* count the points for artifacts */ artifact_score(invent, TRUE, endwin); viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */ mtmp = mydogs; if (!done_stopprint) Strcpy(pbuf, "You"); if (!Schroedingers_cat) /* check here in case disclosure was off */ Schroedingers_cat = odds_and_ends(invent, CAT_CHECK); if (Schroedingers_cat) { int mhp, m_lev = adj_lev(&mons[PM_HOUSECAT]); mhp = d(m_lev, 8); nowrap_add(u.urexp, mhp); if (!done_stopprint) Strcat(eos(pbuf), " and Schroedinger's cat"); } if (mtmp) { while (mtmp) { if (!done_stopprint) Sprintf(eos(pbuf), " and %s", mon_nam(mtmp)); if (mtmp->mtame) nowrap_add(u.urexp, mtmp->mhp); mtmp = mtmp->nmon; } if (!done_stopprint) putstr(endwin, 0, pbuf); pbuf[0] = '\0'; } else { if (!done_stopprint) Strcat(pbuf, " "); } if (!done_stopprint) { Sprintf(eos(pbuf), "%s with %ld point%s,", how == ASCENDED ? "went to your reward" : "escaped from the dungeon", u.urexp, plur(u.urexp)); putstr(endwin, 0, pbuf); } if (!done_stopprint) artifact_score(invent, FALSE, endwin); /* list artifacts */ /* list valuables here */ for (val = valuables; val->list; val++) { sort_valuables(val->list, val->size); for (i = 0; i < val->size && !done_stopprint; i++) { int typ = val->list[i].typ; long count = val->list[i].count; if (count == 0L) continue; if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) { otmp = mksobj(typ, FALSE, FALSE); makeknown(otmp->otyp); otmp->known = 1; /* for fake amulets */ otmp->dknown = 1; /* seen it (blindness fix) */ if (has_oname(otmp)) free_oname(otmp); otmp->quan = count; Sprintf(pbuf, "%8ld %s (worth %ld %s),", count, xname(otmp), count * (long) objects[typ].oc_cost, currency(2L)); obfree(otmp, (struct obj *) 0); } else { Sprintf(pbuf, "%8ld worthless piece%s of colored glass,", count, plur(count)); } putstr(endwin, 0, pbuf); } } } else if (!done_stopprint) { /* did not escape or ascend */ if (u.uz.dnum == 0 && u.uz.dlevel <= 0) { /* level teleported out of the dungeon; `how' is DIED, due to falling or to "arriving at heaven prematurely" */ Sprintf(pbuf, "You %s beyond the confines of the dungeon", (u.uz.dlevel < 0) ? "passed away" : ends[how]); } else { /* more conventional demise */ const char *where = dungeons[u.uz.dnum].dname; if (Is_astralevel(&u.uz)) where = "The Astral Plane"; Sprintf(pbuf, "You %s in %s", ends[how], where); if (!In_endgame(&u.uz) && !Is_knox(&u.uz)) Sprintf(eos(pbuf), " on dungeon level %d", In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz)); } Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp)); putstr(endwin, 0, pbuf); } if (!done_stopprint) { Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney, plur(umoney), moves, plur(moves)); putstr(endwin, 0, pbuf); } if (!done_stopprint) { Sprintf(pbuf, "You were level %d with a maximum of %d hit point%s when you %s.", u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]); putstr(endwin, 0, pbuf); putstr(endwin, 0, ""); } if (!done_stopprint) display_nhwindow(endwin, TRUE); if (endwin != WIN_ERR) destroy_nhwindow(endwin); /* "So when I die, the first thing I will see in Heaven is a * score list?" */ if (have_windows && !iflags.toptenwin) exit_nhwindows((char *) 0), have_windows = FALSE; topten(how, endtime); if (have_windows) exit_nhwindows((char *) 0); if (done_stopprint) { raw_print(""); raw_print(""); } terminate(EXIT_SUCCESS); } void container_contents(list, identified, all_containers, reportempty) struct obj *list; boolean identified, all_containers, reportempty; { register struct obj *box, *obj; struct obj **oarray; int i, n; char *invlet; char buf[BUFSZ]; boolean cat, deadcat; for (box = list; box; box = box->nobj) { if (Is_container(box) || box->otyp == STATUE) { box->cknown = 1; /* we're looking at the contents now */ if (identified) box->lknown = 1; cat = deadcat = FALSE; if (SchroedingersBox(box) && !Schroedingers_cat) { /* Schroedinger's Cat? */ cat = odds_and_ends(box, CAT_CHECK); if (cat) Schroedingers_cat = TRUE; else deadcat = TRUE; box->spe = 0; } if (box->otyp == BAG_OF_TRICKS) { continue; /* wrong type of container */ } else if (box->cobj) { winid tmpwin = create_nhwindow(NHW_MENU); /* count the number of items */ for (n = 0, obj = box->cobj; obj; obj = obj->nobj) n++; /* Make a temporary array to store the objects sorted */ oarray = objarr_init(n); /* Add objects to the array */ i = 0; invlet = flags.inv_order; nextclass: for (obj = box->cobj; obj; obj = obj->nobj) { if (!flags.sortpack || obj->oclass == *invlet) { objarr_set( obj, i++, oarray, (flags.sortloot == 'f' || flags.sortloot == 'l')); } } /* for loop */ if (flags.sortpack) { if (*++invlet) goto nextclass; } Sprintf(buf, "Contents of %s:", the(xname(box))); putstr(tmpwin, 0, buf); putstr(tmpwin, 0, ""); for (i = 0; i < n; i++) { obj = oarray[i]; if (identified) { makeknown(obj->otyp); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; if (Is_container(obj) || obj->otyp == STATUE) obj->cknown = obj->lknown = 1; } putstr(tmpwin, 0, doname(obj)); } free(oarray); if (cat) putstr(tmpwin, 0, "Schroedinger's cat"); else if (deadcat) putstr(tmpwin, 0, "Schroedinger's dead cat"); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); if (all_containers) container_contents(box->cobj, identified, TRUE, reportempty); } else if (cat || deadcat) { pline("%s Schroedinger's %scat!", Tobjnam(box, "contain"), deadcat ? "dead " : ""); display_nhwindow(WIN_MESSAGE, FALSE); } else if (reportempty) { pline("%s is empty.", upstart(thesimpleoname(box))); display_nhwindow(WIN_MESSAGE, FALSE); } } if (!all_containers) break; } } /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */ void terminate(status) int status; { program_state.in_moveloop = 0; /* won't be returning to normal play */ #ifdef MAC getreturn("to exit"); #endif /* don't bother to try to release memory if we're in panic mode, to avoid trouble in case that happens to be due to memory problems */ if (!program_state.panicking) { freedynamicdata(); dlb_cleanup(); } #ifdef VMS /* * This is liable to draw a warning if compiled with gcc, but it's * more important to flag panic() -> really_done() -> terminate() * as __noreturn__ then to avoid the warning. */ /* don't call exit() if already executing within an exit handler; that would cancel any other pending user-mode handlers */ if (program_state.exiting) return; #endif program_state.exiting = 1; nethack_exit(status); } /* #vanquished command */ int dovanquished() { list_vanquished('a', FALSE); return 0; } STATIC_OVL void list_vanquished(defquery, ask) char defquery; boolean ask; { register int i, lev; int ntypes = 0, max_lev = 0, nkilled; long total_killed = 0L; char c; winid klwin; char buf[BUFSZ]; /* get totals first */ for (i = LOW_PM; i < NUMMONS; i++) { if (mvitals[i].died) ntypes++; total_killed += (long) mvitals[i].died; if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel; } /* vanquished creatures list; * includes all dead monsters, not just those killed by the player */ if (ntypes != 0) { c = ask ? yn_function( "Do you want an account of creatures vanquished?", ynqchars, defquery) : defquery; if (c == 'q') done_stopprint++; if (c == 'y' || c == 'a') { klwin = create_nhwindow(NHW_MENU); putstr(klwin, 0, "Vanquished creatures:"); putstr(klwin, 0, ""); /* countdown by monster "toughness" */ for (lev = max_lev; lev >= 0; lev--) for (i = LOW_PM; i < NUMMONS; i++) if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) { if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) { Sprintf(buf, "%s%s", !type_is_pname(&mons[i]) ? "The " : "", mons[i].mname); if (nkilled > 1) { switch (nkilled) { case 2: Sprintf(eos(buf), " (twice)"); break; case 3: Sprintf(eos(buf), " (thrice)"); break; default: Sprintf(eos(buf), " (%d times)", nkilled); break; } } } else { /* trolls or undead might have come back, but we don't keep track of that */ if (nkilled == 1) Strcpy(buf, an(mons[i].mname)); else Sprintf(buf, "%d %s", nkilled, makeplural(mons[i].mname)); } putstr(klwin, 0, buf); } /* * if (Hallucination) * putstr(klwin, 0, "and a partridge in a pear tree"); */ if (ntypes > 1) { putstr(klwin, 0, ""); Sprintf(buf, "%ld creatures vanquished.", total_killed); putstr(klwin, 0, buf); } display_nhwindow(klwin, TRUE); destroy_nhwindow(klwin); } } else if (defquery == 'a') { /* #dovanquished rather than final disclosure, so pline() is ok */ pline("No monsters have been vanquished."); } } /* number of monster species which have been genocided */ int num_genocides() { int i, n = 0; for (i = LOW_PM; i < NUMMONS; ++i) if (mvitals[i].mvflags & G_GENOD) ++n; return n; } int num_extinct() { int i, n = 0; for (i = LOW_PM; i < NUMMONS; ++i) if (!(mvitals[i].mvflags & G_GENOD) && (mvitals[i].mvflags & G_GONE) && !(mons[i].geno & G_UNIQ)) ++n; return n; } STATIC_OVL void list_genocided(defquery, ask) char defquery; boolean ask; { register int i; int ngenocided, nextinct; char c; winid klwin; char buf[BUFSZ]; ngenocided = num_genocides(); nextinct = num_extinct(); /* genocided or extinct species list */ if (ngenocided != 0 || nextinct != 0) { Sprintf(buf, "Do you want a list of %sspecies%s%s?", (nextinct && !ngenocided) ? "extinct " : "", (ngenocided) ? " genocided" : "", (nextinct && ngenocided) ? " and extinct" : ""); c = ask ? yn_function(buf, ynqchars, defquery) : defquery; if (c == 'q') done_stopprint++; if (c == 'y') { klwin = create_nhwindow(NHW_MENU); Sprintf(buf, "%s%s species:", (ngenocided) ? "Genocided" : "Extinct", (nextinct && ngenocided) ? " or extinct" : ""); putstr(klwin, 0, buf); putstr(klwin, 0, ""); for (i = LOW_PM; i < NUMMONS; i++) if (mvitals[i].mvflags & G_GONE && !(mons[i].geno & G_UNIQ)) { if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) Sprintf(buf, "%s%s", !type_is_pname(&mons[i]) ? "" : "the ", mons[i].mname); else Strcpy(buf, makeplural(mons[i].mname)); if (!(mvitals[i].mvflags & G_GENOD)) Strcat(buf, " (extinct)"); putstr(klwin, 0, buf); } putstr(klwin, 0, ""); if (ngenocided > 0) { Sprintf(buf, "%d species genocided.", ngenocided); putstr(klwin, 0, buf); } if (nextinct > 0) { Sprintf(buf, "%d species extinct.", nextinct); putstr(klwin, 0, buf); } display_nhwindow(klwin, TRUE); destroy_nhwindow(klwin); } } } /* set a delayed killer, ensure non-delayed killer is cleared out */ void delayed_killer(id, format, killername) int id; int format; const char *killername; { struct kinfo *k = find_delayed_killer(id); if (k == (struct kinfo *) 0) { /* no match, add a new delayed killer to the list */ k = (struct kinfo *) alloc(sizeof(struct kinfo)); k->id = id; k->next = killer.next; killer.next = k; } k->format = format; Strcpy(k->name, killername ? killername : ""); killer.name[0] = 0; } struct kinfo * find_delayed_killer(id) int id; { struct kinfo *k; for (k = killer.next; k != (struct kinfo *) 0; k = k->next) { if (k->id == id) break; } return k; } void dealloc_killer(kptr) struct kinfo *kptr; { struct kinfo *prev = &killer, *k; if (kptr == (struct kinfo *) 0) return; for (k = killer.next; k != (struct kinfo *) 0; k = k->next) { if (k == kptr) break; prev = k; } if (k == (struct kinfo *) 0) { impossible("dealloc_killer not on list"); } else { prev->next = k->next; free((genericptr_t) k); } } void save_killers(fd, mode) int fd; int mode; { struct kinfo *kptr; if (perform_bwrite(mode)) { for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { bwrite(fd, (genericptr_t) kptr, sizeof(struct kinfo)); } } if (release_data(mode)) { while (killer.next) { kptr = killer.next->next; free((genericptr_t) killer.next); killer.next = kptr; } } } void restore_killers(fd) int fd; { struct kinfo *kptr; for (kptr = &killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { mread(fd, (genericptr_t) kptr, sizeof(struct kinfo)); if (kptr->next) { kptr->next = (struct kinfo *) alloc(sizeof(struct kinfo)); } } } static int wordcount(p) char *p; { int words = 0; while (*p) { while (*p && isspace((uchar) *p)) p++; if (*p) words++; while (*p && !isspace((uchar) *p)) p++; } return words; } static void bel_copy1(inp, out) char **inp, *out; { char *in = *inp; out += strlen(out); /* eos() */ while (*in && isspace((uchar) *in)) in++; while (*in && !isspace((uchar) *in)) *out++ = *in++; *out = '\0'; *inp = in; } char * build_english_list(in) char *in; { char *out, *p = in; int len = (int) strlen(p), words = wordcount(p); /* +3: " or " - " "; +(words - 1): (N-1)*(", " - " ") */ if (words > 1) len += 3 + (words - 1); out = (char *) alloc(len + 1); *out = '\0'; /* bel_copy1() appends */ switch (words) { case 0: impossible("no words in list"); break; case 1: /* "single" */ bel_copy1(&p, out); break; default: if (words == 2) { /* "first or second" */ bel_copy1(&p, out); Strcat(out, " "); } else { /* "first, second, or third */ do { bel_copy1(&p, out); Strcat(out, ", "); } while (--words > 1); } Strcat(out, "or "); bel_copy1(&p, out); break; } return out; } /*end.c*/ nethack-3.6.0/src/engrave.c0000664000076400007660000011670212611620016014521 0ustar paxedpaxed/* NetHack 3.6 engrave.c $NHDT-Date: 1445388915 2015/10/21 00:55:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" STATIC_VAR NEARDATA struct engr *head_engr; char * random_engraving(outbuf) char *outbuf; { const char *rumor; /* a random engraving may come from the "rumors" file, or from the "engrave" file (formerly in an array here) */ if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor) (void) get_rnd_text(ENGRAVEFILE, outbuf); wipeout_text(outbuf, (int) (strlen(outbuf) / 4), 0); return outbuf; } /* Partial rubouts for engraving characters. -3. */ static const struct { char wipefrom; const char *wipeto; } rubouts[] = { { 'A', "^" }, { 'B', "Pb[" }, { 'C', "(" }, { 'D', "|)[" }, { 'E', "|FL[_" }, { 'F', "|-" }, { 'G', "C(" }, { 'H', "|-" }, { 'I', "|" }, { 'K', "|<" }, { 'L', "|_" }, { 'M', "|" }, { 'N', "|\\" }, { 'O', "C(" }, { 'P', "F" }, { 'Q', "C(" }, { 'R', "PF" }, { 'T', "|" }, { 'U', "J" }, { 'V', "/\\" }, { 'W', "V/\\" }, { 'Z', "/" }, { 'b', "|" }, { 'd', "c|" }, { 'e', "c" }, { 'g', "c" }, { 'h', "n" }, { 'j', "i" }, { 'k', "|" }, { 'l', "|" }, { 'm', "nr" }, { 'n', "r" }, { 'o', "c" }, { 'q', "c" }, { 'w', "v" }, { 'y', "v" }, { ':', "." }, { ';', ",:" }, { ',', "." }, { '=', "-" }, { '+', "-|" }, { '*', "+" }, { '@', "0" }, { '0', "C(" }, { '1', "|" }, { '6', "o" }, { '7', "/" }, { '8', "3o" } }; /* degrade some of the characters in a string */ void wipeout_text(engr, cnt, seed) char *engr; int cnt; unsigned seed; /* for semi-controlled randomization */ { char *s; int i, j, nxt, use_rubout, lth = (int) strlen(engr); if (lth && cnt > 0) { while (cnt--) { /* pick next character */ if (!seed) { /* random */ nxt = rn2(lth); use_rubout = rn2(4); } else { /* predictable; caller can reproduce the same sequence by supplying the same arguments later, or a pseudo-random sequence by varying any of them */ nxt = seed % lth; seed *= 31, seed %= (BUFSZ - 1); use_rubout = seed & 3; } s = &engr[nxt]; if (*s == ' ') continue; /* rub out unreadable & small punctuation marks */ if (index("?.,'`-|_", *s)) { *s = ' '; continue; } if (!use_rubout) i = SIZE(rubouts); else for (i = 0; i < SIZE(rubouts); i++) if (*s == rubouts[i].wipefrom) { /* * Pick one of the substitutes at random. */ if (!seed) j = rn2(strlen(rubouts[i].wipeto)); else { seed *= 31, seed %= (BUFSZ - 1); j = seed % (strlen(rubouts[i].wipeto)); } *s = rubouts[i].wipeto[j]; break; } /* didn't pick rubout; use '?' for unreadable character */ if (i == SIZE(rubouts)) *s = '?'; } } /* trim trailing spaces */ while (lth && engr[lth - 1] == ' ') engr[--lth] = '\0'; } /* check whether hero can reach something at ground level */ boolean can_reach_floor(check_pit) boolean check_pit; { struct trap *t; if (u.uswallow) return FALSE; /* Restricted/unskilled riders can't reach the floor */ if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) return FALSE; if (check_pit && !Flying && (t = t_at(u.ux, u.uy)) != 0 && uteetering_at_seen_pit(t)) return FALSE; return (boolean) ((!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) && (!u.uundetected || !is_hider(youmonst.data) || u.umonnum == PM_TRAPPER)); } /* give a message after caller has determined that hero can't reach */ void cant_reach_floor(x, y, up, check_pit) int x, y; boolean up, check_pit; { You("can't reach the %s.", up ? ceiling(x, y) : (check_pit && can_reach_floor(FALSE)) ? "bottom of the pit" : surface(x, y)); } const char * surface(x, y) register int x, y; { register struct rm *lev = &levl[x][y]; if (x == u.ux && y == u.uy && u.uswallow && is_animal(u.ustuck->data)) return "maw"; else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz)) return "air"; else if (is_pool(x, y)) return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water"; else if (is_ice(x, y)) return "ice"; else if (is_lava(x, y)) return "lava"; else if (lev->typ == DRAWBRIDGE_DOWN) return "bridge"; else if (IS_ALTAR(levl[x][y].typ)) return "altar"; else if (IS_GRAVE(levl[x][y].typ)) return "headstone"; else if (IS_FOUNTAIN(levl[x][y].typ)) return "fountain"; else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) || IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR) return "floor"; else return "ground"; } const char * ceiling(x, y) register int x, y; { register struct rm *lev = &levl[x][y]; const char *what; /* other room types will no longer exist when we're interested -- * see check_special_room() */ if (*in_rooms(x, y, VAULT)) what = "vault's ceiling"; else if (*in_rooms(x, y, TEMPLE)) what = "temple's ceiling"; else if (*in_rooms(x, y, SHOPBASE)) what = "shop's ceiling"; else if (Is_waterlevel(&u.uz)) /* water plane has no surface; its air bubbles aren't below sky */ what = "water above"; else if (IS_AIR(lev->typ)) what = "sky"; else if (Underwater) what = "water's surface"; else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) || IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR) what = "ceiling"; else what = "rock cavern"; return what; } struct engr * engr_at(x, y) xchar x, y; { register struct engr *ep = head_engr; while (ep) { if (x == ep->engr_x && y == ep->engr_y) return ep; ep = ep->nxt_engr; } return (struct engr *) 0; } /* Decide whether a particular string is engraved at a specified * location; a case-insensitive substring match is used. * Ignore headstones, in case the player names herself "Elbereth". * * If strict checking is requested, the word is only considered to be * present if it is intact and is the first word in the engraving. * ("Elbereth burrito" matches; "o Elbereth" does not.) */ int sengr_at(s, x, y, strict) const char *s; xchar x, y; boolean strict; { register struct engr *ep = engr_at(x, y); if (ep && ep->engr_type != HEADSTONE && ep->engr_time <= moves) { return strict ? (strncmpi(ep->engr_txt, s, strlen(s)) == 0) : (strstri(ep->engr_txt, s) != 0); } return FALSE; } void u_wipe_engr(cnt) int cnt; { if (can_reach_floor(TRUE)) wipe_engr_at(u.ux, u.uy, cnt, FALSE); } void wipe_engr_at(x, y, cnt, magical) xchar x, y, cnt, magical; { register struct engr *ep = engr_at(x, y); /* Headstones are indelible */ if (ep && ep->engr_type != HEADSTONE) { debugpline1("asked to erode %d characters", cnt); if (ep->engr_type != BURN || is_ice(x, y) || (magical && !rn2(2))) { if (ep->engr_type != DUST && ep->engr_type != ENGR_BLOOD) { cnt = rn2(1 + 50 / (cnt + 1)) ? 0 : 1; debugpline1("actually eroding %d characters", cnt); } wipeout_text(ep->engr_txt, (int) cnt, 0); while (ep->engr_txt[0] == ' ') ep->engr_txt++; if (!ep->engr_txt[0]) del_engr(ep); } } } void read_engr_at(x, y) int x, y; { register struct engr *ep = engr_at(x, y); int sensed = 0; char buf[BUFSZ]; /* Sensing an engraving does not require sight, * nor does it necessarily imply comprehension (literacy). */ if (ep && ep->engr_txt[0]) { switch (ep->engr_type) { case DUST: if (!Blind) { sensed = 1; pline("%s is written here in the %s.", Something, is_ice(x, y) ? "frost" : "dust"); } break; case ENGRAVE: case HEADSTONE: if (!Blind || can_reach_floor(TRUE)) { sensed = 1; pline("%s is engraved here on the %s.", Something, surface(x, y)); } break; case BURN: if (!Blind || can_reach_floor(TRUE)) { sensed = 1; pline("Some text has been %s into the %s here.", is_ice(x, y) ? "melted" : "burned", surface(x, y)); } break; case MARK: if (!Blind) { sensed = 1; pline("There's some graffiti on the %s here.", surface(x, y)); } break; case ENGR_BLOOD: /* "It's a message! Scrawled in blood!" * "What's it say?" * "It says... `See you next Wednesday.'" -- Thriller */ if (!Blind) { sensed = 1; You_see("a message scrawled in blood here."); } break; default: impossible("%s is written in a very strange way.", Something); sensed = 1; } if (sensed) { char *et; unsigned maxelen = BUFSZ - sizeof("You feel the words: \"\". "); if (strlen(ep->engr_txt) > maxelen) { (void) strncpy(buf, ep->engr_txt, (int) maxelen); buf[maxelen] = '\0'; et = buf; } else et = ep->engr_txt; You("%s: \"%s\".", (Blind) ? "feel the words" : "read", et); if (context.run > 1) nomul(0); } } } void make_engr_at(x, y, s, e_time, e_type) int x, y; const char *s; long e_time; xchar e_type; { struct engr *ep; if ((ep = engr_at(x, y)) != 0) del_engr(ep); ep = newengr(strlen(s) + 1); ep->nxt_engr = head_engr; head_engr = ep; ep->engr_x = x; ep->engr_y = y; ep->engr_txt = (char *) (ep + 1); Strcpy(ep->engr_txt, s); /* engraving Elbereth shows wisdom */ if (!in_mklev && !strcmp(s, "Elbereth")) exercise(A_WIS, TRUE); ep->engr_time = e_time; ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE - 1); ep->engr_lth = strlen(s) + 1; } /* delete any engraving at location */ void del_engr_at(x, y) int x, y; { register struct engr *ep = engr_at(x, y); if (ep) del_engr(ep); } /* * freehand - returns true if player has a free hand */ int freehand() { return (!uwep || !welded(uwep) || (!bimanual(uwep) && (!uarms || !uarms->cursed))); } static NEARDATA const char styluses[] = { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, GEM_CLASS, RING_CLASS, 0 }; /* Mohs' Hardness Scale: * 1 - Talc 6 - Orthoclase * 2 - Gypsum 7 - Quartz * 3 - Calcite 8 - Topaz * 4 - Fluorite 9 - Corundum * 5 - Apatite 10 - Diamond * * Since granite is an igneous rock hardness ~ 7, anything >= 8 should * probably be able to scratch the rock. * Devaluation of less hard gems is not easily possible because obj struct * does not contain individual oc_cost currently. 7/91 * * steel - 5-8.5 (usu. weapon) * diamond - 10 * jade - 5-6 (nephrite) * ruby - 9 (corundum) * turquoise - 5-6 * sapphire - 9 (corundum) * opal - 5-6 * topaz - 8 * glass - ~5.5 * emerald - 7.5-8 (beryl) * dilithium - 4-5?? * aquamarine - 7.5-8 (beryl) * iron - 4-5 * garnet - 7.25 (var. 6.5-8) * fluorite - 4 * agate - 7 (quartz) * brass - 3-4 * amethyst - 7 (quartz) * gold - 2.5-3 * jasper - 7 (quartz) * silver - 2.5-3 * onyx - 7 (quartz) * copper - 2.5-3 * moonstone - 6 (orthoclase) * amber - 2-2.5 */ /* return 1 if action took 1 (or more) moves, 0 if error or aborted */ int doengrave() { boolean dengr = FALSE; /* TRUE if we wipe out the current engraving */ boolean doblind = FALSE; /* TRUE if engraving blinds the player */ boolean doknown = FALSE; /* TRUE if we identify the stylus */ boolean eow = FALSE; /* TRUE if we are overwriting oep */ boolean jello = FALSE; /* TRUE if we are engraving in slime */ boolean ptext = TRUE; /* TRUE if we must prompt for engrave text */ boolean teleengr = FALSE; /* TRUE if we move the old engraving */ boolean zapwand = FALSE; /* TRUE if we remove a wand charge */ xchar type = DUST; /* Type of engraving made */ char buf[BUFSZ]; /* Buffer for final/poly engraving text */ char ebuf[BUFSZ]; /* Buffer for initial engraving text */ char fbuf[BUFSZ]; /* Buffer for "your fingers" */ char qbuf[QBUFSZ]; /* Buffer for query text */ char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */ const char *everb; /* Present tense of engraving type */ const char *eloc; /* Where the engraving is (ie dust/floor/...) */ char *sp; /* Place holder for space count of engr text */ int len; /* # of nonspace chars of new engraving text */ int maxelen; /* Max allowable length of engraving text */ struct engr *oep = engr_at(u.ux, u.uy); /* The current engraving */ struct obj *otmp; /* Object selected with which to engrave */ char *writer; multi = 0; /* moves consumed */ nomovemsg = (char *) 0; /* occupation end message */ buf[0] = (char) 0; ebuf[0] = (char) 0; post_engr_text[0] = (char) 0; maxelen = BUFSZ - 1; if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE) type = ENGR_BLOOD; /* Can the adventurer engrave at all? */ if (u.uswallow) { if (is_animal(u.ustuck->data)) { pline("What would you write? \"Jonah was here\"?"); return 0; } else if (is_whirly(u.ustuck->data)) { cant_reach_floor(u.ux, u.uy, FALSE, FALSE); return 0; } else jello = TRUE; } else if (is_lava(u.ux, u.uy)) { You_cant("write on the %s!", surface(u.ux, u.uy)); return 0; } else if (is_pool(u.ux, u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { You_cant("write on the %s!", surface(u.ux, u.uy)); return 0; } if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) /* in bubble */) { You_cant("write in thin air!"); return 0; } else if (!accessible(u.ux, u.uy)) { /* stone, tree, wall, secret corridor, pool, lava, bars */ You_cant("write here."); return 0; } if (cantwield(youmonst.data)) { You_cant("even hold anything!"); return 0; } if (check_capacity((char *) 0)) return 0; /* One may write with finger, or weapon, or wand, or..., or... * Edited by GAN 10/20/86 so as not to change weapon wielded. */ otmp = getobj(styluses, "write with"); if (!otmp) /* otmp == zeroobj if fingers */ return 0; if (otmp == &zeroobj) { Strcat(strcpy(fbuf, "your "), makeplural(body_part(FINGER))); writer = fbuf; } else writer = yname(otmp); /* There's no reason you should be able to write with a wand * while both your hands are tied up. */ if (!freehand() && otmp != uwep && !otmp->owornmask) { You("have no free %s to write with!", body_part(HAND)); return 0; } if (jello) { You("tickle %s with %s.", mon_nam(u.ustuck), writer); Your("message dissolves..."); return 0; } if (otmp->oclass != WAND_CLASS && !can_reach_floor(TRUE)) { cant_reach_floor(u.ux, u.uy, FALSE, TRUE); return 0; } if (IS_ALTAR(levl[u.ux][u.uy].typ)) { You("make a motion towards the altar with %s.", writer); altar_wrath(u.ux, u.uy); return 0; } if (IS_GRAVE(levl[u.ux][u.uy].typ)) { if (otmp == &zeroobj) { /* using only finger */ You("would only make a small smudge on the %s.", surface(u.ux, u.uy)); return 0; } else if (!levl[u.ux][u.uy].disturbed) { You("disturb the undead!"); levl[u.ux][u.uy].disturbed = 1; (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS); exercise(A_WIS, FALSE); return 1; } } /* SPFX for items */ switch (otmp->oclass) { default: case AMULET_CLASS: case CHAIN_CLASS: case POTION_CLASS: case COIN_CLASS: break; case RING_CLASS: /* "diamond" rings and others should work */ case GEM_CLASS: /* diamonds & other hard gems should work */ if (objects[otmp->otyp].oc_tough) { type = ENGRAVE; break; } break; case ARMOR_CLASS: if (is_boots(otmp)) { type = DUST; break; } /*FALLTHRU*/ /* Objects too large to engrave with */ case BALL_CLASS: case ROCK_CLASS: You_cant("engrave with such a large object!"); ptext = FALSE; break; /* Objects too silly to engrave with */ case FOOD_CLASS: case SCROLL_CLASS: case SPBOOK_CLASS: pline("%s would get %s.", Yname2(otmp), is_ice(u.ux, u.uy) ? "all frosty" : "too dirty"); ptext = FALSE; break; case RANDOM_CLASS: /* This should mean fingers */ break; /* The charge is removed from the wand before prompting for * the engraving text, because all kinds of setup decisions * and pre-engraving messages are based upon knowing what type * of engraving the wand is going to do. Also, the player * will have potentially seen "You wrest .." message, and * therefore will know they are using a charge. */ case WAND_CLASS: if (zappable(otmp)) { check_unpaid(otmp); if (otmp->cursed && !rn2(WAND_BACKFIRE_CHANCE)) { wand_explode(otmp, 0); return 1; } zapwand = TRUE; if (!can_reach_floor(TRUE)) ptext = FALSE; switch (otmp->otyp) { /* DUST wands */ default: break; /* NODIR wands */ case WAN_LIGHT: case WAN_SECRET_DOOR_DETECTION: case WAN_CREATE_MONSTER: case WAN_WISHING: case WAN_ENLIGHTENMENT: zapnodir(otmp); break; /* IMMEDIATE wands */ /* If wand is "IMMEDIATE", remember to affect the * previous engraving even if turning to dust. */ case WAN_STRIKING: Strcpy(post_engr_text, "The wand unsuccessfully fights your attempt to write!"); break; case WAN_SLOW_MONSTER: if (!Blind) { Sprintf(post_engr_text, "The bugs on the %s slow down!", surface(u.ux, u.uy)); } break; case WAN_SPEED_MONSTER: if (!Blind) { Sprintf(post_engr_text, "The bugs on the %s speed up!", surface(u.ux, u.uy)); } break; case WAN_POLYMORPH: if (oep) { if (!Blind) { type = (xchar) 0; /* random */ (void) random_engraving(buf); } dengr = TRUE; } break; case WAN_NOTHING: case WAN_UNDEAD_TURNING: case WAN_OPENING: case WAN_LOCKING: case WAN_PROBING: break; /* RAY wands */ case WAN_MAGIC_MISSILE: ptext = TRUE; if (!Blind) { Sprintf(post_engr_text, "The %s is riddled by bullet holes!", surface(u.ux, u.uy)); } break; /* can't tell sleep from death - Eric Backus */ case WAN_SLEEP: case WAN_DEATH: if (!Blind) { Sprintf(post_engr_text, "The bugs on the %s stop moving!", surface(u.ux, u.uy)); } break; case WAN_COLD: if (!Blind) Strcpy(post_engr_text, "A few ice cubes drop from the wand."); if (!oep || (oep->engr_type != BURN)) break; case WAN_CANCELLATION: case WAN_MAKE_INVISIBLE: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline_The("engraving on the %s vanishes!", surface(u.ux, u.uy)); dengr = TRUE; } break; case WAN_TELEPORTATION: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline_The("engraving on the %s vanishes!", surface(u.ux, u.uy)); teleengr = TRUE; } break; /* type = ENGRAVE wands */ case WAN_DIGGING: ptext = TRUE; type = ENGRAVE; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of digging!", xname(otmp)); doknown = TRUE; } Strcpy(post_engr_text, Blind ? "You hear drilling!" : IS_GRAVE(levl[u.ux][u.uy].typ) ? "Chips fly out from the headstone." : is_ice(u.ux, u.uy) ? "Ice chips fly up from the ice surface!" : (level.locations[u.ux][u.uy].typ == DRAWBRIDGE_DOWN) ? "Splinters fly up from the bridge." : "Gravel flies up from the floor."); break; /* type = BURN wands */ case WAN_FIRE: ptext = TRUE; type = BURN; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of fire!", xname(otmp)); doknown = TRUE; } Strcpy(post_engr_text, Blind ? "You feel the wand heat up." : "Flames fly from the wand."); break; case WAN_LIGHTNING: ptext = TRUE; type = BURN; if (!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of lightning!", xname(otmp)); doknown = TRUE; } if (!Blind) { Strcpy(post_engr_text, "Lightning arcs from the wand."); doblind = TRUE; } else Strcpy(post_engr_text, "You hear crackling!"); break; /* type = MARK wands */ /* type = ENGR_BLOOD wands */ } } else { /* end if zappable */ /* failing to wrest one last charge takes time */ ptext = FALSE; /* use "early exit" below, return 1 */ /* give feedback here if we won't be getting the "can't reach floor" message below */ if (can_reach_floor(TRUE)) { /* cancelled wand turns to dust */ if (otmp->spe < 0) zapwand = TRUE; /* empty wand just doesn't write */ else pline_The("wand is too worn out to engrave."); } } break; case WEAPON_CLASS: if (is_blade(otmp)) { if ((int) otmp->spe > -3) type = ENGRAVE; else pline("%s too dull for engraving.", Yobjnam2(otmp, "are")); } break; case TOOL_CLASS: if (otmp == ublindf) { pline( "That is a bit difficult to engrave with, don't you think?"); return 0; } switch (otmp->otyp) { case MAGIC_MARKER: if (otmp->spe <= 0) Your("marker has dried out."); else type = MARK; break; case TOWEL: /* Can't really engrave with a towel */ ptext = FALSE; if (oep) if (oep->engr_type == DUST || oep->engr_type == ENGR_BLOOD || oep->engr_type == MARK) { if (is_wet_towel(otmp)) dry_a_towel(otmp, -1, TRUE); if (!Blind) You("wipe out the message here."); else pline("%s %s.", Yobjnam2(otmp, "get"), is_ice(u.ux, u.uy) ? "frosty" : "dusty"); dengr = TRUE; } else pline("%s can't wipe out this engraving.", Yname2(otmp)); else pline("%s %s.", Yobjnam2(otmp, "get"), is_ice(u.ux, u.uy) ? "frosty" : "dusty"); break; default: break; } break; case VENOM_CLASS: if (wizard) { pline("Writing a poison pen letter??"); break; } /*FALLTHRU*/ case ILLOBJ_CLASS: impossible("You're engraving with an illegal object!"); break; } if (IS_GRAVE(levl[u.ux][u.uy].typ)) { if (type == ENGRAVE || type == 0) { type = HEADSTONE; } else { /* ensures the "cannot wipe out" case */ type = DUST; dengr = FALSE; teleengr = FALSE; buf[0] = '\0'; } } /* * End of implement setup */ /* Identify stylus */ if (doknown) { learnwand(otmp); if (objects[otmp->otyp].oc_name_known) more_experienced(0, 10); } if (teleengr) { rloc_engr(oep); oep = (struct engr *) 0; } if (dengr) { del_engr(oep); oep = (struct engr *) 0; } /* Something has changed the engraving here */ if (*buf) { make_engr_at(u.ux, u.uy, buf, moves, type); pline_The("engraving now reads: \"%s\".", buf); ptext = FALSE; } if (zapwand && (otmp->spe < 0)) { pline("%s %sturns to dust.", The(xname(otmp)), Blind ? "" : "glows violently, then "); if (!IS_GRAVE(levl[u.ux][u.uy].typ)) You( "are not going to get anywhere trying to write in the %s with your dust.", is_ice(u.ux, u.uy) ? "frost" : "dust"); useup(otmp); otmp = 0; /* wand is now gone */ ptext = FALSE; } /* Early exit for some implements. */ if (!ptext) { if (otmp && otmp->oclass == WAND_CLASS && !can_reach_floor(TRUE)) cant_reach_floor(u.ux, u.uy, FALSE, TRUE); return 1; } /* * Special effects should have deleted the current engraving (if * possible) by now. */ if (oep) { register char c = 'n'; /* Give player the choice to add to engraving. */ if (type == HEADSTONE) { /* no choice, only append */ c = 'y'; } else if (type == oep->engr_type && (!Blind || oep->engr_type == BURN || oep->engr_type == ENGRAVE)) { c = yn_function("Do you want to add to the current engraving?", ynqchars, 'y'); if (c == 'q') { pline1(Never_mind); return 0; } } if (c == 'n' || Blind) { if (oep->engr_type == DUST || oep->engr_type == ENGR_BLOOD || oep->engr_type == MARK) { if (!Blind) { You("wipe out the message that was %s here.", (oep->engr_type == DUST) ? "written in the dust" : (oep->engr_type == ENGR_BLOOD) ? "scrawled in blood" : "written"); del_engr(oep); oep = (struct engr *) 0; } else /* Don't delete engr until after we *know* we're engraving */ eow = TRUE; } else if (type == DUST || type == MARK || type == ENGR_BLOOD) { You("cannot wipe out the message that is %s the %s here.", oep->engr_type == BURN ? (is_ice(u.ux, u.uy) ? "melted into" : "burned into") : "engraved in", surface(u.ux, u.uy)); return 1; } else if (type != oep->engr_type || c == 'n') { if (!Blind || can_reach_floor(TRUE)) You("will overwrite the current message."); eow = TRUE; } } } eloc = surface(u.ux, u.uy); switch (type) { default: everb = (oep && !eow ? "add to the weird writing on" : "write strangely on"); break; case DUST: everb = (oep && !eow ? "add to the writing in" : "write in"); eloc = is_ice(u.ux, u.uy) ? "frost" : "dust"; break; case HEADSTONE: everb = (oep && !eow ? "add to the epitaph on" : "engrave on"); break; case ENGRAVE: everb = (oep && !eow ? "add to the engraving in" : "engrave in"); break; case BURN: everb = (oep && !eow ? (is_ice(u.ux, u.uy) ? "add to the text melted into" : "add to the text burned into") : (is_ice(u.ux, u.uy) ? "melt into" : "burn into")); break; case MARK: everb = (oep && !eow ? "add to the graffiti on" : "scribble on"); break; case ENGR_BLOOD: everb = (oep && !eow ? "add to the scrawl on" : "scrawl on"); break; } /* Tell adventurer what is going on */ if (otmp != &zeroobj) You("%s the %s with %s.", everb, eloc, doname(otmp)); else You("%s the %s with your %s.", everb, eloc, makeplural(body_part(FINGER))); /* Prompt for engraving! */ Sprintf(qbuf, "What do you want to %s the %s here?", everb, eloc); getlin(qbuf, ebuf); /* convert tabs to spaces and condense consecutive spaces to one */ mungspaces(ebuf); /* Count the actual # of chars engraved not including spaces */ len = strlen(ebuf); for (sp = ebuf; *sp; sp++) if (*sp == ' ') len -= 1; if (len == 0 || index(ebuf, '\033')) { if (zapwand) { if (!Blind) pline("%s, then %s.", Tobjnam(otmp, "glow"), otense(otmp, "fade")); return 1; } else { pline1(Never_mind); return 0; } } /* A single `x' is the traditional signature of an illiterate person */ if (len != 1 || (!index(ebuf, 'x') && !index(ebuf, 'X'))) u.uconduct.literate++; /* Mix up engraving if surface or state of mind is unsound. Note: this won't add or remove any spaces. */ for (sp = ebuf; *sp; sp++) { if (*sp == ' ') continue; if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) || (Blind && !rn2(11)) || (Confusion && !rn2(7)) || (Stunned && !rn2(4)) || (Hallucination && !rn2(2))) *sp = ' ' + rnd(96 - 2); /* ASCII '!' thru '~' (excludes ' ' and DEL) */ } /* Previous engraving is overwritten */ if (eow) { del_engr(oep); oep = (struct engr *) 0; } /* Figure out how long it took to engrave, and if player has * engraved too much. */ switch (type) { default: multi = -(len / 10); if (multi) nomovemsg = "You finish your weird engraving."; break; case DUST: multi = -(len / 10); if (multi) nomovemsg = "You finish writing in the dust."; break; case HEADSTONE: case ENGRAVE: multi = -(len / 10); if (otmp->oclass == WEAPON_CLASS && (otmp->otyp != ATHAME || otmp->cursed)) { multi = -len; maxelen = ((otmp->spe + 3) * 2) + 1; /* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11 * Note: this does not allow a +0 anything (except an athame) * to engrave "Elbereth" all at once. * However, you can engrave "Elb", then "ere", then "th". */ pline("%s dull.", Yobjnam2(otmp, "get")); costly_alteration(otmp, COST_DEGRD); if (len > maxelen) { multi = -maxelen; otmp->spe = -3; } else if (len > 1) otmp->spe -= len >> 1; else otmp->spe -= 1; /* Prevent infinite engraving */ } else if (otmp->oclass == RING_CLASS || otmp->oclass == GEM_CLASS) { multi = -len; } if (multi) nomovemsg = "You finish engraving."; break; case BURN: multi = -(len / 10); if (multi) nomovemsg = is_ice(u.ux, u.uy) ? "You finish melting your message into the ice." : "You finish burning your message into the floor."; break; case MARK: multi = -(len / 10); if (otmp->otyp == MAGIC_MARKER) { maxelen = otmp->spe * 2; /* one charge / 2 letters */ if (len > maxelen) { Your("marker dries out."); otmp->spe = 0; multi = -(maxelen / 10); } else if (len > 1) otmp->spe -= len >> 1; else otmp->spe -= 1; /* Prevent infinite graffiti */ } if (multi) nomovemsg = "You finish defacing the dungeon."; break; case ENGR_BLOOD: multi = -(len / 10); if (multi) nomovemsg = "You finish scrawling."; break; } /* Chop engraving down to size if necessary */ if (len > maxelen) { for (sp = ebuf; maxelen && *sp; sp++) if (*sp == ' ') maxelen--; if (!maxelen && *sp) { *sp = '\0'; if (multi) nomovemsg = "You cannot write any more."; You("are only able to write \"%s\".", ebuf); } } if (oep) /* add to existing engraving */ Strcpy(buf, oep->engr_txt); (void) strncat(buf, ebuf, BUFSZ - (int) strlen(buf) - 1); /* Put the engraving onto the map */ make_engr_at(u.ux, u.uy, buf, moves - multi, type); if (post_engr_text[0]) pline("%s", post_engr_text); if (doblind && !resists_blnd(&youmonst)) { You("are blinded by the flash!"); make_blinded((long) rnd(50), FALSE); if (!Blind) Your1(vision_clears); } return 1; } /* while loading bones, clean up text which might accidentally or maliciously disrupt player's terminal when displayed */ void sanitize_engravings() { struct engr *ep; for (ep = head_engr; ep; ep = ep->nxt_engr) { sanitize_name(ep->engr_txt); } } void save_engravings(fd, mode) int fd, mode; { struct engr *ep, *ep2; unsigned no_more_engr = 0; for (ep = head_engr; ep; ep = ep2) { ep2 = ep->nxt_engr; if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) { bwrite(fd, (genericptr_t) &ep->engr_lth, sizeof ep->engr_lth); bwrite(fd, (genericptr_t) ep, sizeof (struct engr) + ep->engr_lth); } if (release_data(mode)) dealloc_engr(ep); } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &no_more_engr, sizeof no_more_engr); if (release_data(mode)) head_engr = 0; } void rest_engravings(fd) int fd; { struct engr *ep; unsigned lth; head_engr = 0; while (1) { mread(fd, (genericptr_t) <h, sizeof lth); if (lth == 0) return; ep = newengr(lth); mread(fd, (genericptr_t) ep, sizeof (struct engr) + lth); ep->nxt_engr = head_engr; head_engr = ep; ep->engr_txt = (char *) (ep + 1); /* Andreas Bormann */ /* Mark as finished for bones levels -- no problem for * normal levels as the player must have finished engraving * to be able to move again. */ ep->engr_time = moves; } } void del_engr(ep) register struct engr *ep; { if (ep == head_engr) { head_engr = ep->nxt_engr; } else { register struct engr *ept; for (ept = head_engr; ept; ept = ept->nxt_engr) if (ept->nxt_engr == ep) { ept->nxt_engr = ep->nxt_engr; break; } if (!ept) { impossible("Error in del_engr?"); return; } } dealloc_engr(ep); } /* randomly relocate an engraving */ void rloc_engr(ep) struct engr *ep; { int tx, ty, tryct = 200; do { if (--tryct < 0) return; tx = rn1(COLNO - 3, 2); ty = rn2(ROWNO); } while (engr_at(tx, ty) || !goodpos(tx, ty, (struct monst *) 0, 0)); ep->engr_x = tx; ep->engr_y = ty; } /* Create a headstone at the given location. * The caller is responsible for newsym(x, y). */ void make_grave(x, y, str) int x, y; const char *str; { char buf[BUFSZ]; /* Can we put a grave here? */ if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x, y)) return; /* Make the grave */ levl[x][y].typ = GRAVE; /* Engrave the headstone */ del_engr_at(x, y); if (!str) str = get_rnd_text(EPITAPHFILE, buf); make_engr_at(x, y, str, 0L, HEADSTONE); return; } /*engrave.c*/ nethack-3.6.0/src/exper.c0000664000076400007660000002242112625266272014226 0ustar paxedpaxed/* NetHack 3.6 exper.c $NHDT-Date: 1446975467 2015/11/08 09:37:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include STATIC_DCL long FDECL(newuexp, (int)); STATIC_DCL int FDECL(enermod, (int)); STATIC_OVL long newuexp(lev) int lev; { if (lev < 10) return (10L * (1L << lev)); if (lev < 20) return (10000L * (1L << (lev - 10))); return (10000000L * ((long) (lev - 19))); } STATIC_OVL int enermod(en) int en; { switch (Role_switch) { case PM_PRIEST: case PM_WIZARD: return (2 * en); case PM_HEALER: case PM_KNIGHT: return ((3 * en) / 2); case PM_BARBARIAN: case PM_VALKYRIE: return ((3 * en) / 4); default: return en; } } /* calculate spell power/energy points for new level */ int newpw() { int en = 0, enrnd, enfix; if (u.ulevel == 0) { en = urole.enadv.infix + urace.enadv.infix; if (urole.enadv.inrnd > 0) en += rnd(urole.enadv.inrnd); if (urace.enadv.inrnd > 0) en += rnd(urace.enadv.inrnd); } else { enrnd = (int) ACURR(A_WIS) / 2; if (u.ulevel < urole.xlev) { enrnd += urole.enadv.lornd + urace.enadv.lornd; enfix = urole.enadv.lofix + urace.enadv.lofix; } else { enrnd += urole.enadv.hirnd + urace.enadv.hirnd; enfix = urole.enadv.hifix + urace.enadv.hifix; } en = enermod(rn1(enrnd, enfix)); } if (en <= 0) en = 1; if (u.ulevel < MAXULEV) u.ueninc[u.ulevel] = (xchar) en; return en; } /* return # of exp points for mtmp after nk killed */ int experience(mtmp, nk) register struct monst *mtmp; register int nk; { register struct permonst *ptr = mtmp->data; int i, tmp, tmp2; tmp = 1 + mtmp->m_lev * mtmp->m_lev; /* For higher ac values, give extra experience */ if ((i = find_mac(mtmp)) < 3) tmp += (7 - i) * ((i < 0) ? 2 : 1); /* For very fast monsters, give extra experience */ if (ptr->mmove > NORMAL_SPEED) tmp += (ptr->mmove > (3 * NORMAL_SPEED / 2)) ? 5 : 3; /* For each "special" attack type give extra experience */ for (i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].aatyp; if (tmp2 > AT_BUTT) { if (tmp2 == AT_WEAP) tmp += 5; else if (tmp2 == AT_MAGC) tmp += 10; else tmp += 3; } } /* For each "special" damage type give extra experience */ for (i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].adtyp; if (tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2 * mtmp->m_lev; else if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_SLIM)) tmp += 50; else if (tmp2 != AD_PHYS) tmp += mtmp->m_lev; /* extra heavy damage bonus */ if ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23) tmp += mtmp->m_lev; if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious) tmp += 1000; } /* For certain "extra nasty" monsters, give even more */ if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev); /* For higher level monsters, an additional bonus is given */ if (mtmp->m_lev > 8) tmp += 50; #ifdef MAIL /* Mail daemons put up no fight. */ if (mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1; #endif if (mtmp->mrevived || mtmp->mcloned) { /* * Reduce experience awarded for repeated killings of * "the same monster". Kill count includes all of this * monster's type which have been killed--including the * current monster--regardless of how they were created. * 1.. 20 full experience * 21.. 40 xp / 2 * 41.. 80 xp / 4 * 81..120 xp / 8 * 121..180 xp / 16 * 181..240 xp / 32 * 241..255+ xp / 64 */ for (i = 0, tmp2 = 20; nk > tmp2 && tmp > 1; ++i) { tmp = (tmp + 1) / 2; nk -= tmp2; if (i & 1) tmp2 += 20; } } return (tmp); } void more_experienced(exper, rexp) register int exper, rexp; { long newexp = u.uexp + exper; long rexpincr = 4 * exper + rexp; long newrexp = u.urexp + rexpincr; /* cap experience and score on wraparound */ if (newexp < 0 && exper > 0) newexp = LONG_MAX; if (newrexp < 0 && rexpincr > 0) newrexp = LONG_MAX; u.uexp = newexp; u.urexp = newrexp; if (exper #ifdef SCORE_ON_BOTL || flags.showscore #endif ) context.botl = 1; if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000)) flags.beginner = 0; } /* e.g., hit by drain life attack */ void losexp(drainer) const char *drainer; /* cause of death, if drain should be fatal */ { register int num; /* override life-drain resistance when handling an explicit wizard mode request to reduce level; never fatal though */ if (drainer && !strcmp(drainer, "#levelchange")) drainer = 0; else if (resists_drli(&youmonst)) return; if (u.ulevel > 1) { pline("%s level %d.", Goodbye(), u.ulevel--); /* remove intrinsic abilities */ adjabil(u.ulevel + 1, u.ulevel); reset_rndmonst(NON_PM); /* new monster selection */ } else { if (drainer) { killer.format = KILLED_BY; if (killer.name != drainer) Strcpy(killer.name, drainer); done(DIED); } /* no drainer or lifesaved */ u.uexp = 0; } num = (int) u.uhpinc[u.ulevel]; u.uhpmax -= num; if (u.uhpmax < 1) u.uhpmax = 1; u.uhp -= num; if (u.uhp < 1) u.uhp = 1; else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; num = (int) u.ueninc[u.ulevel]; u.uenmax -= num; if (u.uenmax < 0) u.uenmax = 0; u.uen -= num; if (u.uen < 0) u.uen = 0; else if (u.uen > u.uenmax) u.uen = u.uenmax; if (u.uexp > 0) u.uexp = newuexp(u.ulevel) - 1; if (Upolyd) { num = monhp_per_lvl(&youmonst); u.mhmax -= num; u.mh -= num; if (u.mh <= 0) rehumanize(); } context.botl = 1; } /* * Make experience gaining similar to AD&D(tm), whereby you can at most go * up by one level at a time, extra expr possibly helping you along. * After all, how much real experience does one get shooting a wand of death * at a dragon created with a wand of polymorph?? */ void newexplevel() { if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel)) pluslvl(TRUE); } void pluslvl(incr) boolean incr; /* true iff via incremental experience growth */ { /* (false for potion of gain level) */ int hpinc, eninc; if (!incr) You_feel("more experienced."); /* increase hit points (when polymorphed, do monster form first in order to retain normal human/whatever increase for later) */ if (Upolyd) { hpinc = monhp_per_lvl(&youmonst); u.mhmax += hpinc; u.mh += hpinc; } hpinc = newhp(); u.uhpmax += hpinc; u.uhp += hpinc; /* increase spell power/energy points */ eninc = newpw(); u.uenmax += eninc; u.uen += eninc; /* increase level (unless already maxxed) */ if (u.ulevel < MAXULEV) { /* increase experience points to reflect new level */ if (incr) { long tmp = newuexp(u.ulevel + 1); if (u.uexp >= tmp) u.uexp = tmp - 1; } else { u.uexp = newuexp(u.ulevel); } ++u.ulevel; if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel; pline("Welcome to experience level %d.", u.ulevel); adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */ reset_rndmonst(NON_PM); /* new monster selection */ } context.botl = 1; } /* compute a random amount of experience points suitable for the hero's experience level: base number of points needed to reach the current level plus a random portion of what it takes to get to the next level */ long rndexp(gaining) boolean gaining; /* gaining XP via potion vs setting XP for polyself */ { long minexp, maxexp, diff, factor, result; minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1); maxexp = newuexp(u.ulevel); diff = maxexp - minexp, factor = 1L; /* make sure that `diff' is an argument which rn2() can handle */ while (diff >= (long) LARGEST_INT) diff /= 2L, factor *= 2L; result = minexp + factor * (long) rn2((int) diff); /* 3.4.1: if already at level 30, add to current experience points rather than to threshold needed to reach the current level; otherwise blessed potions of gain level can result in lowering the experience points instead of raising them */ if (u.ulevel == MAXULEV && gaining) { result += (u.uexp - minexp); /* avoid wrapping (over 400 blessed potions needed for that...) */ if (result < u.uexp) result = u.uexp; } return result; } /*exper.c*/ nethack-3.6.0/src/explode.c0000664000076400007660000006725212617615230014547 0ustar paxedpaxed/* NetHack 3.6 explode.c $NHDT-Date: 1446955298 2015/11/08 04:01:38 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Note: Arrays are column first, while the screen is row first */ static int explosion[3][3] = { { S_explode1, S_explode4, S_explode7 }, { S_explode2, S_explode5, S_explode8 }, { S_explode3, S_explode6, S_explode9 } }; /* Note: I had to choose one of three possible kinds of "type" when writing * this function: a wand type (like in zap.c), an adtyp, or an object type. * Wand types get complex because they must be converted to adtyps for * determining such things as fire resistance. Adtyps get complex in that * they don't supply enough information--was it a player or a monster that * did it, and with a wand, spell, or breath weapon? Object types share both * these disadvantages.... * * Important note about Half_physical_damage: * Unlike losehp(), explode() makes the Half_physical_damage adjustments * itself, so the caller should never have done that ahead of time. * It has to be done this way because the damage value is applied to * things beside the player. Care is taken within explode() to ensure * that Half_physical_damage only affects the damage applied to the hero. */ void explode(x, y, type, dam, olet, expltype) int x, y; int type; /* the same as in zap.c; passes -(wand typ) for some WAND_CLASS */ int dam; char olet; int expltype; { int i, j, k, damu = dam; boolean starting = 1; boolean visible, any_shield; int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */ const char *str = (const char *) 0; int idamres, idamnonres; struct monst *mtmp, *mdef = 0; uchar adtyp; int explmask[3][3]; /* 0=normal explosion, 1=do shieldeff, 2=do nothing */ boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE, do_hallu = FALSE, inside_engulfer; char hallu_buf[BUFSZ]; short exploding_wand_typ = 0; if (olet == WAND_CLASS) { /* retributive strike */ /* 'type' is passed as (wand's object type * -1); save object type and convert 'type' itself to zap-type */ if (type < 0) { type = -type; exploding_wand_typ = (short) type; /* most attack wands produce specific explosions; other types produce a generic magical explosion */ if (objects[type].oc_dir == RAY && type != WAN_DIGGING && type != WAN_SLEEP) { type -= WAN_MAGIC_MISSILE; if (type < 0 || type > 9) { impossible("explode: wand has bad zap type (%d).", type); type = 0; } } else type = 0; } switch (Role_switch) { case PM_PRIEST: case PM_MONK: case PM_WIZARD: damu /= 5; break; case PM_HEALER: case PM_KNIGHT: damu /= 2; break; default: break; } } /* muse_unslime: SCR_FIRE */ if (expltype < 0) { /* hero gets credit/blame for killing this monster, not others */ mdef = m_at(x, y); expltype = -expltype; } /* if hero is engulfed and caused the explosion, only hero and engulfer will be affected */ inside_engulfer = (u.uswallow && type >= 0); if (olet == MON_EXPLODE) { str = killer.name; do_hallu = Hallucination && strstri(str, "'s explosion"); adtyp = AD_PHYS; } else switch (abs(type) % 10) { case 0: str = "magical blast"; adtyp = AD_MAGM; break; case 1: str = (olet == BURNING_OIL) ? "burning oil" : (olet == SCROLL_CLASS) ? "tower of flame" : "fireball"; /* fire damage, not physical damage */ adtyp = AD_FIRE; break; case 2: str = "ball of cold"; adtyp = AD_COLD; break; case 4: str = (olet == WAND_CLASS) ? "death field" : "disintegration field"; adtyp = AD_DISN; break; case 5: str = "ball of lightning"; adtyp = AD_ELEC; break; case 6: str = "poison gas cloud"; adtyp = AD_DRST; break; case 7: str = "splash of acid"; adtyp = AD_ACID; break; default: impossible("explosion base type %d?", type); return; } any_shield = visible = FALSE; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { if (!isok(i + x - 1, j + y - 1)) { explmask[i][j] = 2; continue; } else explmask[i][j] = 0; if (i + x - 1 == u.ux && j + y - 1 == u.uy) { switch (adtyp) { case AD_PHYS: explmask[i][j] = 0; break; case AD_MAGM: explmask[i][j] = !!Antimagic; break; case AD_FIRE: explmask[i][j] = !!Fire_resistance; break; case AD_COLD: explmask[i][j] = !!Cold_resistance; break; case AD_DISN: explmask[i][j] = (olet == WAND_CLASS) ? !!(nonliving(youmonst.data) || is_demon(youmonst.data)) : !!Disint_resistance; break; case AD_ELEC: explmask[i][j] = !!Shock_resistance; break; case AD_DRST: explmask[i][j] = !!Poison_resistance; break; case AD_ACID: explmask[i][j] = !!Acid_resistance; physical_dmg = TRUE; break; default: impossible("explosion type %d?", adtyp); break; } } /* can be both you and mtmp if you're swallowed */ mtmp = m_at(i + x - 1, j + y - 1); if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy) mtmp = u.usteed; if (mtmp) { if (mtmp->mhp < 1) explmask[i][j] = 2; else switch (adtyp) { case AD_PHYS: break; case AD_MAGM: explmask[i][j] |= resists_magm(mtmp); break; case AD_FIRE: explmask[i][j] |= resists_fire(mtmp); break; case AD_COLD: explmask[i][j] |= resists_cold(mtmp); break; case AD_DISN: explmask[i][j] |= (olet == WAND_CLASS) ? (nonliving(mtmp->data) || is_demon(mtmp->data) || is_vampshifter(mtmp)) : resists_disint(mtmp); break; case AD_ELEC: explmask[i][j] |= resists_elec(mtmp); break; case AD_DRST: explmask[i][j] |= resists_poison(mtmp); break; case AD_ACID: explmask[i][j] |= resists_acid(mtmp); break; default: impossible("explosion type %d?", adtyp); break; } } if (mtmp && cansee(i + x - 1, j + y - 1) && !canspotmon(mtmp)) map_invisible(i + x - 1, j + y - 1); else if (!mtmp && glyph_is_invisible( levl[i + x - 1][j + y - 1].glyph)) { unmap_object(i + x - 1, j + y - 1); newsym(i + x - 1, j + y - 1); } if (cansee(i + x - 1, j + y - 1)) visible = TRUE; if (explmask[i][j] == 1) any_shield = TRUE; } if (visible) { /* Start the explosion */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { if (explmask[i][j] == 2) continue; tmp_at(starting ? DISP_BEAM : DISP_CHANGE, explosion_to_glyph(expltype, explosion[i][j])); tmp_at(i + x - 1, j + y - 1); starting = 0; } curs_on_u(); /* will flush screen and output */ if (any_shield && flags.sparkle) { /* simulate shield effect */ for (k = 0; k < SHIELD_COUNT; k++) { for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { if (explmask[i][j] == 1) /* * Bypass tmp_at() and send the shield glyphs * directly to the buffered screen. tmp_at() * will clean up the location for us later. */ show_glyph(i + x - 1, j + y - 1, cmap_to_glyph(shield_static[k])); } curs_on_u(); /* will flush screen and output */ delay_output(); } /* Cover last shield glyph with blast symbol. */ for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { if (explmask[i][j] == 1) show_glyph( i + x - 1, j + y - 1, explosion_to_glyph(expltype, explosion[i][j])); } } else { /* delay a little bit. */ delay_output(); delay_output(); } tmp_at(DISP_END, 0); /* clear the explosion */ } else { if (olet == MON_EXPLODE) { str = "explosion"; generic = TRUE; } if (!Deaf && olet != SCROLL_CLASS) You_hear("a blast."); } if (dam) for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { if (explmask[i][j] == 2) continue; if (i + x - 1 == u.ux && j + y - 1 == u.uy) uhurt = (explmask[i][j] == 1) ? 1 : 2; /* for inside_engulfer, only is affected */ else if (inside_engulfer) continue; idamres = idamnonres = 0; if (type >= 0 && !u.uswallow) (void) zap_over_floor((xchar) (i + x - 1), (xchar) (j + y - 1), type, &shopdamage, exploding_wand_typ); mtmp = m_at(i + x - 1, j + y - 1); if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy) mtmp = u.usteed; if (!mtmp) continue; if (do_hallu) { /* replace "gas spore" with a different description for each target (we can't distinguish personal names like "Barney" here in order to suppress "the" below, so avoid any which begins with a capital letter) */ do { Sprintf(hallu_buf, "%s explosion", s_suffix(rndmonnam(NULL))); } while (*hallu_buf != lowc(*hallu_buf)); str = hallu_buf; } if (u.uswallow && mtmp == u.ustuck) { const char *adj = NULL; if (is_animal(u.ustuck->data)) { switch (adtyp) { case AD_FIRE: adj = "heartburn"; break; case AD_COLD: adj = "chilly"; break; case AD_DISN: if (olet == WAND_CLASS) adj = "irradiated by pure energy"; else adj = "perforated"; break; case AD_ELEC: adj = "shocked"; break; case AD_DRST: adj = "poisoned"; break; case AD_ACID: adj = "an upset stomach"; break; default: adj = "fried"; break; } pline("%s gets %s!", Monnam(u.ustuck), adj); } else { switch (adtyp) { case AD_FIRE: adj = "toasted"; break; case AD_COLD: adj = "chilly"; break; case AD_DISN: if (olet == WAND_CLASS) adj = "overwhelmed by pure energy"; else adj = "perforated"; break; case AD_ELEC: adj = "shocked"; break; case AD_DRST: adj = "intoxicated"; break; case AD_ACID: adj = "burned"; break; default: adj = "fried"; break; } pline("%s gets slightly %s!", Monnam(u.ustuck), adj); } } else if (cansee(i + x - 1, j + y - 1)) { if (mtmp->m_ap_type) seemimic(mtmp); pline("%s is caught in the %s!", Monnam(mtmp), str); } idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp); idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp); if (explmask[i][j] == 1) { golemeffects(mtmp, (int) adtyp, dam + idamres); mtmp->mhp -= idamnonres; } else { /* call resist with 0 and do damage manually so 1) we can * get out the message before doing the damage, and 2) we * can * call mondied, not killed, if it's not your blast */ int mdam = dam; if (resist(mtmp, olet, 0, FALSE)) { /* inside_engulfer: == */ if (cansee(i + x - 1, j + y - 1) || inside_engulfer) pline("%s resists the %s!", Monnam(mtmp), str); mdam = (dam + 1) / 2; } if (mtmp == u.ustuck) mdam *= 2; if (resists_cold(mtmp) && adtyp == AD_FIRE) mdam *= 2; else if (resists_fire(mtmp) && adtyp == AD_COLD) mdam *= 2; mtmp->mhp -= mdam; mtmp->mhp -= (idamres + idamnonres); } if (mtmp->mhp <= 0) { if (mdef ? (mtmp == mdef) : !context.mon_moving) killed(mtmp); else monkilled(mtmp, "", (int) adtyp); } else if (!context.mon_moving) { /* all affected monsters, even if mdef is set */ setmangry(mtmp); } } /* Do your injury last */ if (uhurt) { /* give message for any monster-induced explosion or player-induced one other than scroll of fire */ if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) { if (do_hallu) { /* (see explanation above) */ do { Sprintf(hallu_buf, "%s explosion", s_suffix(rndmonnam(NULL))); } while (*hallu_buf != lowc(*hallu_buf)); str = hallu_buf; } You("are caught in the %s!", str); iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION; } /* do property damage first, in case we end up leaving bones */ if (adtyp == AD_FIRE) burn_away_slime(); if (Invulnerable) { damu = 0; You("are unharmed!"); } else if (adtyp == AD_PHYS || physical_dmg) damu = Maybe_Half_Phys(damu); if (adtyp == AD_FIRE) (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, (int) adtyp); destroy_item(SPBOOK_CLASS, (int) adtyp); destroy_item(POTION_CLASS, (int) adtyp); destroy_item(RING_CLASS, (int) adtyp); destroy_item(WAND_CLASS, (int) adtyp); ugolemeffects((int) adtyp, damu); if (uhurt == 2) { if (Upolyd) u.mh -= damu; else u.uhp -= damu; context.botl = 1; } if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) { if (Upolyd) { rehumanize(); } else { if (olet == MON_EXPLODE) { /* killer handled by caller */ if (generic) killer.name[0] = 0; else if (str != killer.name && str != hallu_buf) Strcpy(killer.name, str); killer.format = KILLED_BY_AN; } else if (type >= 0 && olet != SCROLL_CLASS) { killer.format = NO_KILLER_PREFIX; Sprintf(killer.name, "caught %sself in %s own %s", uhim(), uhis(), str); } else { killer.format = (!strcmpi(str, "tower of flame") || !strcmpi(str, "fireball")) ? KILLED_BY_AN : KILLED_BY; Strcpy(killer.name, str); } if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/ pline("It is fatal."); else pline_The("%s is fatal.", str); /* Known BUG: BURNING suppresses corpse in bones data, but done does not handle killer reason correctly */ done((adtyp == AD_FIRE) ? BURNING : DIED); } } exercise(A_STR, FALSE); } if (shopdamage) { pay_for_damage(adtyp == AD_FIRE ? "burn away" : adtyp == AD_COLD ? "shatter" : adtyp == AD_DISN ? "disintegrate" : "destroy", FALSE); } /* explosions are noisy */ i = dam * dam; if (i < 50) i = 50; /* in case random damage is very small */ if (inside_engulfer) i = (i + 3) / 4; wake_nearto(x, y, i); } struct scatter_chain { struct scatter_chain *next; /* pointer to next scatter item */ struct obj *obj; /* pointer to the object */ xchar ox; /* location of */ xchar oy; /* item */ schar dx; /* direction of */ schar dy; /* travel */ int range; /* range of object */ boolean stopped; /* flag for in-motion/stopped */ }; /* * scflags: * VIS_EFFECTS Add visual effects to display * MAY_HITMON Objects may hit monsters * MAY_HITYOU Objects may hit hero * MAY_HIT Objects may hit you or monsters * MAY_DESTROY Objects may be destroyed at random * MAY_FRACTURE Stone objects can be fractured (statues, boulders) */ /* returns number of scattered objects */ long scatter(sx, sy, blastforce, scflags, obj) int sx, sy; /* location of objects to scatter */ int blastforce; /* force behind the scattering */ unsigned int scflags; struct obj *obj; /* only scatter this obj */ { register struct obj *otmp; register int tmp; int farthest = 0; uchar typ; long qtmp; boolean used_up; boolean individual_object = obj ? TRUE : FALSE; struct monst *mtmp; struct scatter_chain *stmp, *stmp2 = 0; struct scatter_chain *schain = (struct scatter_chain *) 0; long total = 0L; while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) { if (otmp->quan > 1L) { qtmp = otmp->quan - 1L; if (qtmp > LARGEST_INT) qtmp = LARGEST_INT; qtmp = (long) rnd((int) qtmp); otmp = splitobj(otmp, qtmp); } else { obj = (struct obj *) 0; /* all used */ } obj_extract_self(otmp); used_up = FALSE; /* 9 in 10 chance of fracturing boulders or statues */ if ((scflags & MAY_FRACTURE) && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE)) && rn2(10)) { if (otmp->otyp == BOULDER) { pline("%s apart.", Tobjnam(otmp, "break")); fracture_rock(otmp); place_object(otmp, sx, sy); if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(otmp); place_object(otmp, sx, sy); } } else { struct trap *trap; if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP) deltrap(trap); pline("%s.", Tobjnam(otmp, "crumble")); (void) break_statue(otmp); place_object(otmp, sx, sy); /* put fragments on floor */ } used_up = TRUE; /* 1 in 10 chance of destruction of obj; glass, egg destruction */ } else if ((scflags & MAY_DESTROY) && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS || otmp->otyp == EGG))) { if (breaks(otmp, (xchar) sx, (xchar) sy)) used_up = TRUE; } if (!used_up) { stmp = (struct scatter_chain *) alloc(sizeof(struct scatter_chain)); stmp->next = (struct scatter_chain *) 0; stmp->obj = otmp; stmp->ox = sx; stmp->oy = sy; tmp = rn2(8); /* get the direction */ stmp->dx = xdir[tmp]; stmp->dy = ydir[tmp]; tmp = blastforce - (otmp->owt / 40); if (tmp < 1) tmp = 1; stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */ if (farthest < stmp->range) farthest = stmp->range; stmp->stopped = FALSE; if (!schain) schain = stmp; else stmp2->next = stmp; stmp2 = stmp; } } while (farthest-- > 0) { for (stmp = schain; stmp; stmp = stmp->next) { if ((stmp->range-- > 0) && (!stmp->stopped)) { bhitpos.x = stmp->ox + stmp->dx; bhitpos.y = stmp->oy + stmp->dy; typ = levl[bhitpos.x][bhitpos.y].typ; if (!isok(bhitpos.x, bhitpos.y)) { bhitpos.x -= stmp->dx; bhitpos.y -= stmp->dy; stmp->stopped = TRUE; } else if (!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) { bhitpos.x -= stmp->dx; bhitpos.y -= stmp->dy; stmp->stopped = TRUE; } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (scflags & MAY_HITMON) { stmp->range--; if (ohitmon(mtmp, stmp->obj, 1, FALSE)) { stmp->obj = (struct obj *) 0; stmp->stopped = TRUE; } } } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (scflags & MAY_HITYOU) { int hitvalu, hitu; if (multi) nomul(0); hitvalu = 8 + stmp->obj->spe; if (bigmonst(youmonst.data)) hitvalu++; hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst), stmp->obj, (char *) 0); if (hitu) { stmp->range -= 3; stop_occupation(); } } } else { if (scflags & VIS_EFFECTS) { /* tmp_at(bhitpos.x, bhitpos.y); */ /* delay_output(); */ } } stmp->ox = bhitpos.x; stmp->oy = bhitpos.y; } } } for (stmp = schain; stmp; stmp = stmp2) { int x, y; stmp2 = stmp->next; x = stmp->ox; y = stmp->oy; if (stmp->obj) { if (x != sx || y != sy) total += stmp->obj->quan; place_object(stmp->obj, x, y); stackobj(stmp->obj); } free((genericptr_t) stmp); newsym(x, y); } return total; } /* * Splatter burning oil from x,y to the surrounding area. * * This routine should really take a how and direction parameters. * The how is how it was caused, e.g. kicked verses thrown. The * direction is which way to spread the flaming oil. Different * "how"s would give different dispersal patterns. For example, * kicking a burning flask will splatter differently from a thrown * flask hitting the ground. * * For now, just perform a "regular" explosion. */ void splatter_burning_oil(x, y) int x, y; { /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */ #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */ explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY); } /* lit potion of oil is exploding; extinguish it as a light source before possibly killing the hero and attempting to save bones */ void explode_oil(obj, x, y) struct obj *obj; int x, y; { if (!obj->lamplit) impossible("exploding unlit oil"); end_burn(obj, TRUE); splatter_burning_oil(x, y); } /*explode.c*/ nethack-3.6.0/src/extralev.c0000664000076400007660000002555012617615230014734 0ustar paxedpaxed/* NetHack 3.6 extralev.c $NHDT-Date: 1446975468 2015/11/08 09:37:48 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ /* * Support code for "rogue"-style level. */ #include "hack.h" struct rogueroom { xchar rlx, rly; xchar dx, dy; boolean real; uchar doortable; int nroom; /* Only meaningful for "real" rooms */ }; #define UP 1 #define DOWN 2 #define LEFT 4 #define RIGHT 8 static NEARDATA struct rogueroom r[3][3]; STATIC_DCL void FDECL(roguejoin, (int, int, int, int, int)); STATIC_DCL void FDECL(roguecorr, (int, int, int)); STATIC_DCL void FDECL(miniwalk, (int, int)); STATIC_OVL void roguejoin(x1, y1, x2, y2, horiz) int x1, y1, x2, y2; int horiz; { register int x, y, middle; if (horiz) { middle = x1 + rn2(x2 - x1 + 1); for (x = min(x1, middle); x <= max(x1, middle); x++) corr(x, y1); for (y = min(y1, y2); y <= max(y1, y2); y++) corr(middle, y); for (x = min(middle, x2); x <= max(middle, x2); x++) corr(x, y2); } else { middle = y1 + rn2(y2 - y1 + 1); for (y = min(y1, middle); y <= max(y1, middle); y++) corr(x1, y); for (x = min(x1, x2); x <= max(x1, x2); x++) corr(x, middle); for (y = min(middle, y2); y <= max(middle, y2); y++) corr(x2, y); } } STATIC_OVL void roguecorr(x, y, dir) int x, y, dir; { register int fromx, fromy, tox, toy; if (dir == DOWN) { r[x][y].doortable &= ~DOWN; if (!r[x][y].real) { fromx = r[x][y].rlx; fromy = r[x][y].rly; fromx += 1 + 26 * x; fromy += 7 * y; } else { fromx = r[x][y].rlx + rn2(r[x][y].dx); fromy = r[x][y].rly + r[x][y].dy; fromx += 1 + 26 * x; fromy += 7 * y; if (!IS_WALL(levl[fromx][fromy].typ)) impossible("down: no wall at %d,%d?", fromx, fromy); dodoor(fromx, fromy, &rooms[r[x][y].nroom]); levl[fromx][fromy].doormask = D_NODOOR; fromy++; } if (y >= 2) { impossible("down door from %d,%d going nowhere?", x, y); return; } y++; r[x][y].doortable &= ~UP; if (!r[x][y].real) { tox = r[x][y].rlx; toy = r[x][y].rly; tox += 1 + 26 * x; toy += 7 * y; } else { tox = r[x][y].rlx + rn2(r[x][y].dx); toy = r[x][y].rly - 1; tox += 1 + 26 * x; toy += 7 * y; if (!IS_WALL(levl[tox][toy].typ)) impossible("up: no wall at %d,%d?", tox, toy); dodoor(tox, toy, &rooms[r[x][y].nroom]); levl[tox][toy].doormask = D_NODOOR; toy--; } roguejoin(fromx, fromy, tox, toy, FALSE); return; } else if (dir == RIGHT) { r[x][y].doortable &= ~RIGHT; if (!r[x][y].real) { fromx = r[x][y].rlx; fromy = r[x][y].rly; fromx += 1 + 26 * x; fromy += 7 * y; } else { fromx = r[x][y].rlx + r[x][y].dx; fromy = r[x][y].rly + rn2(r[x][y].dy); fromx += 1 + 26 * x; fromy += 7 * y; if (!IS_WALL(levl[fromx][fromy].typ)) impossible("down: no wall at %d,%d?", fromx, fromy); dodoor(fromx, fromy, &rooms[r[x][y].nroom]); levl[fromx][fromy].doormask = D_NODOOR; fromx++; } if (x >= 2) { impossible("right door from %d,%d going nowhere?", x, y); return; } x++; r[x][y].doortable &= ~LEFT; if (!r[x][y].real) { tox = r[x][y].rlx; toy = r[x][y].rly; tox += 1 + 26 * x; toy += 7 * y; } else { tox = r[x][y].rlx - 1; toy = r[x][y].rly + rn2(r[x][y].dy); tox += 1 + 26 * x; toy += 7 * y; if (!IS_WALL(levl[tox][toy].typ)) impossible("left: no wall at %d,%d?", tox, toy); dodoor(tox, toy, &rooms[r[x][y].nroom]); levl[tox][toy].doormask = D_NODOOR; tox--; } roguejoin(fromx, fromy, tox, toy, TRUE); return; } else impossible("corridor in direction %d?", dir); } /* Modified walkfrom() from mkmaze.c */ STATIC_OVL void miniwalk(x, y) int x, y; { register int q, dir; int dirs[4]; while (1) { q = 0; #define doorhere (r[x][y].doortable) if (x > 0 && (!(doorhere & LEFT)) && (!r[x - 1][y].doortable || !rn2(10))) dirs[q++] = 0; if (x < 2 && (!(doorhere & RIGHT)) && (!r[x + 1][y].doortable || !rn2(10))) dirs[q++] = 1; if (y > 0 && (!(doorhere & UP)) && (!r[x][y - 1].doortable || !rn2(10))) dirs[q++] = 2; if (y < 2 && (!(doorhere & DOWN)) && (!r[x][y + 1].doortable || !rn2(10))) dirs[q++] = 3; /* Rogue levels aren't just 3 by 3 mazes; they have some extra * connections, thus that 1/10 chance */ if (!q) return; dir = dirs[rn2(q)]; switch (dir) { /* Move in direction */ case 0: doorhere |= LEFT; x--; doorhere |= RIGHT; break; case 1: doorhere |= RIGHT; x++; doorhere |= LEFT; break; case 2: doorhere |= UP; y--; doorhere |= DOWN; break; case 3: doorhere |= DOWN; y++; doorhere |= UP; break; } miniwalk(x, y); } } void makeroguerooms() { register int x, y; /* Rogue levels are structured 3 by 3, with each section containing * a room or an intersection. The minimum width is 2 each way. * One difference between these and "real" Rogue levels: real Rogue * uses 24 rows and NetHack only 23. So we cheat a bit by making the * second row of rooms not as deep. * * Each normal space has 6/7 rows and 25 columns in which a room may * actually be placed. Walls go from rows 0-5/6 and columns 0-24. * Not counting walls, the room may go in * rows 1-5 and columns 1-23 (numbering starting at 0). A room * coordinate of this type may be converted to a level coordinate * by adding 1+28*x to the column, and 7*y to the row. (The 1 * is because column 0 isn't used [we only use 1-78]). * Room height may be 2-4 (2-5 on last row), length 2-23 (not * counting walls). */ #define here r[x][y] nroom = 0; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { /* Note: we want to insure at least 1 room. So, if the * first 8 are all dummies, force the last to be a room. */ if (!rn2(5) && (nroom || (x < 2 && y < 2))) { /* Arbitrary: dummy rooms may only go where real * ones do. */ here.real = FALSE; here.rlx = rn1(22, 2); here.rly = rn1((y == 2) ? 4 : 3, 2); } else { here.real = TRUE; here.dx = rn1(22, 2); /* 2-23 long, plus walls */ here.dy = rn1((y == 2) ? 4 : 3, 2); /* 2-5 high, plus walls */ /* boundaries of room floor */ here.rlx = rnd(23 - here.dx + 1); here.rly = rnd(((y == 2) ? 5 : 4) - here.dy + 1); nroom++; } here.doortable = 0; } miniwalk(rn2(3), rn2(3)); nroom = 0; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { if (here.real) { /* Make a room */ int lowx, lowy, hix, hiy; r[x][y].nroom = nroom; smeq[nroom] = nroom; lowx = 1 + 26 * x + here.rlx; lowy = 7 * y + here.rly; hix = 1 + 26 * x + here.rlx + here.dx - 1; hiy = 7 * y + here.rly + here.dy - 1; /* Strictly speaking, it should be lit only if above * level 10, but since Rogue rooms are only * encountered below level 10, use !rn2(7). */ add_room(lowx, lowy, hix, hiy, (boolean) !rn2(7), OROOM, FALSE); } } /* Now, add connecting corridors. */ for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { if (here.doortable & DOWN) roguecorr(x, y, DOWN); if (here.doortable & RIGHT) roguecorr(x, y, RIGHT); if (here.doortable & LEFT) impossible("left end of %d, %d never connected?", x, y); if (here.doortable & UP) impossible("up end of %d, %d never connected?", x, y); } } void corr(x, y) int x, y; { if (rn2(50)) { levl[x][y].typ = CORR; } else { levl[x][y].typ = SCORR; } } void makerogueghost() { register struct monst *ghost; struct obj *ghostobj; struct mkroom *croom; int x, y; if (!nroom) return; /* Should never happen */ croom = &rooms[rn2(nroom)]; x = somex(croom); y = somey(croom); if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS))) return; ghost->msleeping = 1; ghost = christen_monst(ghost, roguename()); if (rn2(4)) { ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE); ghostobj->quan = (long) rnd(7); ghostobj->owt = weight(ghostobj); } if (rn2(2)) { ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE); ghostobj->spe = rnd(3); if (rn2(4)) curse(ghostobj); } else { ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE); ghostobj->spe = rnd(5) - 2; if (rn2(4)) curse(ghostobj); } ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE); ghostobj->spe = 1; if (rn2(4)) curse(ghostobj); ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE); ghostobj->spe = 0; ghostobj->quan = (long) rn1(10, 25); ghostobj->owt = weight(ghostobj); if (rn2(4)) curse(ghostobj); if (rn2(2)) { ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE); ghostobj->spe = rn2(3); if (!rn2(3)) ghostobj->oerodeproof = TRUE; if (rn2(4)) curse(ghostobj); } else { ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE); ghostobj->spe = rnd(5) - 2; if (!rn2(3)) ghostobj->oerodeproof = TRUE; if (rn2(4)) curse(ghostobj); } if (rn2(2)) { ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE); ghostobj->known = TRUE; } } /*extralev.c*/ nethack-3.6.0/src/files.c0000664000076400007660000032023012631241231014165 0ustar paxedpaxed/* NetHack 3.6 files.c $NHDT-Date: 1449296293 2015/12/05 06:18:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.192 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #ifdef TTY_GRAPHICS #include "wintty.h" /* more() */ #endif #if (!defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)) \ || defined(USE_FCNTL) #include #endif #include #ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */ #if (_MSC_VER >= 600) #define SKIP_ERRNO #endif #else #ifdef NHSTDC #define SKIP_ERRNO #endif #endif #ifndef SKIP_ERRNO #ifdef _DCC const #endif extern int errno; #endif #ifdef ZLIB_COMP /* RLC 09 Mar 1999: Support internal ZLIB */ #include "zlib.h" #ifndef COMPRESS_EXTENSION #define COMPRESS_EXTENSION ".gz" #endif #endif #if defined(UNIX) && defined(QT_GRAPHICS) #include #include #include #endif #if defined(UNIX) || defined(VMS) || !defined(NO_SIGNAL) #include #endif #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32) #ifndef GNUDOS #include #else #include #endif #endif #ifndef O_BINARY /* used for micros, no-op for others */ #define O_BINARY 0 #endif #ifdef PREFIXES_IN_USE #define FQN_NUMBUF 4 static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; #endif #if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32) char bones[] = "bonesnn.xxx"; char lock[PL_NSIZ + 14] = "1lock"; /* long enough for uid+name+.99 */ #else #if defined(MFLOPPY) char bones[FILENAME]; /* pathname of bones files */ char lock[FILENAME]; /* pathname of level files */ #endif #if defined(VMS) char bones[] = "bonesnn.xxx;1"; char lock[PL_NSIZ + 17] = "1lock"; /* long enough for _uid+name+.99;1 */ #endif #if defined(WIN32) char bones[] = "bonesnn.xxx"; char lock[PL_NSIZ + 25]; /* long enough for username+-+name+.99 */ #endif #endif #if defined(UNIX) || defined(__BEOS__) #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ #else #ifdef VMS #define SAVESIZE (PL_NSIZ + 22) /* [.save]player.e;1 */ #else #if defined(WIN32) #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ #else #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ #endif #endif #endif #if !defined(SAVE_EXTENSION) #ifdef MICRO #define SAVE_EXTENSION ".sav" #endif #ifdef WIN32 #define SAVE_EXTENSION ".NetHack-saved-game" #endif #endif char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */ #ifdef MICRO char SAVEP[SAVESIZE]; /* holds path of directory for save file */ #endif #ifdef HOLD_LOCKFILE_OPEN struct level_ftrack { int init; int fd; /* file descriptor for level file */ int oflag; /* open flags */ boolean nethack_thinks_it_is_open; /* Does NetHack think it's open? */ } lftrack; #if defined(WIN32) #include #endif #endif /*HOLD_LOCKFILE_OPEN*/ #define WIZKIT_MAX 128 static char wizkit[WIZKIT_MAX]; STATIC_DCL FILE *NDECL(fopen_wizkit_file); STATIC_DCL void FDECL(wizkit_addinv, (struct obj *)); #ifdef AMIGA extern char PATH[]; /* see sys/amiga/amidos.c */ extern char bbs_id[]; static int lockptr; #ifdef __SASC_60 #include #endif #include extern void FDECL(amii_set_text_font, (char *, int)); #endif #if defined(WIN32) || defined(MSDOS) static int lockptr; #ifdef MSDOS #define Delay(a) msleep(a) #endif #define Close close #ifndef WIN_CE #define DeleteFile unlink #endif #endif #ifdef MAC #undef unlink #define unlink macunlink #endif #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) \ || defined(__MWERKS__) #define PRAGMA_UNUSED #endif #ifdef USER_SOUNDS extern char *sounddir; #endif extern int n_dgns; /* from dungeon.c */ #if defined(UNIX) && defined(QT_GRAPHICS) #define SELECTSAVED #endif #ifdef SELECTSAVED STATIC_PTR int FDECL(CFDECLSPEC strcmp_wrap, (const void *, const void *)); #endif STATIC_DCL char *FDECL(set_bonesfile_name, (char *, d_level *)); STATIC_DCL char *NDECL(set_bonestemp_name); #ifdef COMPRESS STATIC_DCL void FDECL(redirect, (const char *, const char *, FILE *, BOOLEAN_P)); #endif #if defined(COMPRESS) || defined(ZLIB_COMP) STATIC_DCL void FDECL(docompress_file, (const char *, BOOLEAN_P)); #endif #if defined(ZLIB_COMP) STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *)); #endif #ifndef USE_FCNTL STATIC_DCL char *FDECL(make_lockname, (const char *, char *)); #endif STATIC_DCL FILE *FDECL(fopen_config_file, (const char *, int)); STATIC_DCL int FDECL(get_uchars, (FILE *, char *, char *, uchar *, BOOLEAN_P, int, const char *)); int FDECL(parse_config_line, (FILE *, char *, int)); STATIC_DCL FILE *NDECL(fopen_sym_file); STATIC_DCL void FDECL(set_symhandling, (char *, int)); #ifdef NOCWD_ASSUMPTIONS STATIC_DCL void FDECL(adjust_prefix, (char *, int)); #endif #ifdef SELF_RECOVER STATIC_DCL boolean FDECL(copy_bytes, (int, int)); #endif #ifdef HOLD_LOCKFILE_OPEN STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int)); #endif /* * fname_encode() * * Args: * legal zero-terminated list of acceptable file name characters * quotechar lead-in character used to quote illegal characters as * hex digits * s string to encode * callerbuf buffer to house result * bufsz size of callerbuf * * Notes: * The hex digits 0-9 and A-F are always part of the legal set due to * their use in the encoding scheme, even if not explicitly included in * 'legal'. * * Sample: * The following call: * (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", * '%', "This is a % test!", buf, 512); * results in this encoding: * "This%20is%20a%20%25%20test%21" */ char * fname_encode(legal, quotechar, s, callerbuf, bufsz) const char *legal; char quotechar; char *s, *callerbuf; int bufsz; { char *sp, *op; int cnt = 0; static char hexdigits[] = "0123456789ABCDEF"; sp = s; op = callerbuf; *op = '\0'; while (*sp) { /* Do we have room for one more character or encoding? */ if ((bufsz - cnt) <= 4) return callerbuf; if (*sp == quotechar) { (void) sprintf(op, "%c%02X", quotechar, *sp); op += 3; cnt += 3; } else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) { *op++ = *sp; *op = '\0'; cnt++; } else { (void) sprintf(op, "%c%02X", quotechar, *sp); op += 3; cnt += 3; } sp++; } return callerbuf; } /* * fname_decode() * * Args: * quotechar lead-in character used to quote illegal characters as * hex digits * s string to decode * callerbuf buffer to house result * bufsz size of callerbuf */ char * fname_decode(quotechar, s, callerbuf, bufsz) char quotechar; char *s, *callerbuf; int bufsz; { char *sp, *op; int k, calc, cnt = 0; static char hexdigits[] = "0123456789ABCDEF"; sp = s; op = callerbuf; *op = '\0'; calc = 0; while (*sp) { /* Do we have room for one more character? */ if ((bufsz - cnt) <= 2) return callerbuf; if (*sp == quotechar) { sp++; for (k = 0; k < 16; ++k) if (*sp == hexdigits[k]) break; if (k >= 16) return callerbuf; /* impossible, so bail */ calc = k << 4; sp++; for (k = 0; k < 16; ++k) if (*sp == hexdigits[k]) break; if (k >= 16) return callerbuf; /* impossible, so bail */ calc += k; sp++; *op++ = calc; *op = '\0'; } else { *op++ = *sp++; *op = '\0'; } cnt++; } return callerbuf; } #ifdef PREFIXES_IN_USE #define UNUSED_if_not_PREFIXES_IN_USE /*empty*/ #else #define UNUSED_if_not_PREFIXES_IN_USE UNUSED #endif /*ARGSUSED*/ const char * fqname(basenam, whichprefix, buffnum) const char *basenam; int whichprefix UNUSED_if_not_PREFIXES_IN_USE; int buffnum UNUSED_if_not_PREFIXES_IN_USE; { #ifndef PREFIXES_IN_USE return basenam; #else if (!basenam || whichprefix < 0 || whichprefix >= PREFIX_COUNT) return basenam; if (!fqn_prefix[whichprefix]) return basenam; if (buffnum < 0 || buffnum >= FQN_NUMBUF) { impossible("Invalid fqn_filename_buffer specified: %d", buffnum); buffnum = 0; } if (strlen(fqn_prefix[whichprefix]) + strlen(basenam) >= FQN_MAX_FILENAME) { impossible("fqname too long: %s + %s", fqn_prefix[whichprefix], basenam); return basenam; /* XXX */ } Strcpy(fqn_filename_buffer[buffnum], fqn_prefix[whichprefix]); return strcat(fqn_filename_buffer[buffnum], basenam); #endif } int validate_prefix_locations(reasonbuf) char *reasonbuf; /* reasonbuf must be at least BUFSZ, supplied by caller */ { #if defined(NOCWD_ASSUMPTIONS) FILE *fp; const char *filename; int prefcnt, failcount = 0; char panicbuf1[BUFSZ], panicbuf2[BUFSZ]; const char *details; #endif if (reasonbuf) reasonbuf[0] = '\0'; #if defined(NOCWD_ASSUMPTIONS) for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) { /* don't test writing to configdir or datadir; they're readonly */ if (prefcnt == SYSCONFPREFIX || prefcnt == CONFIGPREFIX || prefcnt == DATAPREFIX) continue; filename = fqname("validate", prefcnt, 3); if ((fp = fopen(filename, "w"))) { fclose(fp); (void) unlink(filename); } else { if (reasonbuf) { if (failcount) Strcat(reasonbuf, ", "); Strcat(reasonbuf, fqn_prefix_names[prefcnt]); } /* the paniclog entry gets the value of errno as well */ Sprintf(panicbuf1, "Invalid %s", fqn_prefix_names[prefcnt]); #if defined(NHSTDC) && !defined(NOTSTDC) if (!(details = strerror(errno))) #endif details = ""; Sprintf(panicbuf2, "\"%s\", (%d) %s", fqn_prefix[prefcnt], errno, details); paniclog(panicbuf1, panicbuf2); failcount++; } } if (failcount) return 0; else #endif return 1; } /* fopen a file, with OS-dependent bells and whistles */ /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */ FILE * fopen_datafile(filename, mode, prefix) const char *filename, *mode; int prefix; { FILE *fp; filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0); fp = fopen(filename, mode); return fp; } /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ #ifdef MFLOPPY /* Set names for bones[] and lock[] */ void set_lock_and_bones() { if (!ramdisk) { Strcpy(levels, permbones); Strcpy(bones, permbones); } append_slash(permbones); append_slash(levels); #ifdef AMIGA strncat(levels, bbs_id, PATHLEN); #endif append_slash(bones); Strcat(bones, "bonesnn.*"); Strcpy(lock, levels); #ifndef AMIGA Strcat(lock, alllevels); #endif return; } #endif /* MFLOPPY */ /* Construct a file name for a level-type file, which is of the form * something.level (with any old level stripped off). * This assumes there is space on the end of 'file' to append * a two digit number. This is true for 'level' * but be careful if you use it for other things -dgk */ void set_levelfile_name(file, lev) char *file; int lev; { char *tf; tf = rindex(file, '.'); if (!tf) tf = eos(file); Sprintf(tf, ".%d", lev); #ifdef VMS Strcat(tf, ";1"); #endif return; } int create_levelfile(lev, errbuf) int lev; char errbuf[]; { int fd; const char *fq_lock; if (errbuf) *errbuf = '\0'; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 0); #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ #ifdef HOLD_LOCKFILE_OPEN if (lev == 0) fd = open_levelfile_exclusively( fq_lock, lev, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY); else #endif fd = open(fq_lock, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else #ifdef MAC fd = maccreat(fq_lock, LEVL_TYPE); #else fd = creat(fq_lock, FCMASK); #endif #endif /* MICRO || WIN32 */ if (fd >= 0) level_info[lev].flags |= LFILE_EXISTS; else if (errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).", lock, lev, errno); return fd; } int open_levelfile(lev, errbuf) int lev; char errbuf[]; { int fd; const char *fq_lock; if (errbuf) *errbuf = '\0'; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 0); #ifdef MFLOPPY /* If not currently accessible, swap it in. */ if (level_info[lev].where != ACTIVE) swapin_file(lev); #endif #ifdef MAC fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE); #else #ifdef HOLD_LOCKFILE_OPEN if (lev == 0) fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY); else #endif fd = open(fq_lock, O_RDONLY | O_BINARY, 0); #endif /* for failure, return an explanation that our caller can use; settle for `lock' instead of `fq_lock' because the latter might end up being too big for nethack's BUFSZ */ if (fd < 0 && errbuf) Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).", lock, lev, errno); return fd; } void delete_levelfile(lev) int lev; { /* * Level 0 might be created by port specific code that doesn't * call create_levfile(), so always assume that it exists. */ if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) { set_levelfile_name(lock, lev); #ifdef HOLD_LOCKFILE_OPEN if (lev == 0) really_close(); #endif (void) unlink(fqname(lock, LEVELPREFIX, 0)); level_info[lev].flags &= ~LFILE_EXISTS; } } void clearlocks() { #ifdef HANGUPHANDLING if (program_state.preserve_locks) return; #endif #if !defined(PC_LOCKING) && defined(MFLOPPY) && !defined(AMIGA) eraseall(levels, alllevels); if (ramdisk) eraseall(permbones, alllevels); #else { register int x; #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #if defined(UNIX) || defined(VMS) sethanguphandler((void FDECL((*), (int) )) SIG_IGN); #endif /* can't access maxledgerno() before dungeons are created -dlc */ for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--) delete_levelfile(x); /* not all levels need be present */ } #endif /* ?PC_LOCKING,&c */ } #if defined(SELECTSAVED) /* qsort comparison routine */ STATIC_OVL int CFDECLSPEC strcmp_wrap(p, q) const void *p; const void *q; { #if defined(UNIX) && defined(QT_GRAPHICS) return strncasecmp(*(char **) p, *(char **) q, 16); #else return strncmpi(*(char **) p, *(char **) q, 16); #endif } #endif #ifdef HOLD_LOCKFILE_OPEN STATIC_OVL int open_levelfile_exclusively(name, lev, oflag) const char *name; int lev, oflag; { int reslt, fd; if (!lftrack.init) { lftrack.init = 1; lftrack.fd = -1; } if (lftrack.fd >= 0) { /* check for compatible access */ if (lftrack.oflag == oflag) { fd = lftrack.fd; reslt = lseek(fd, 0L, SEEK_SET); if (reslt == -1L) panic("open_levelfile_exclusively: lseek failed %d", errno); lftrack.nethack_thinks_it_is_open = TRUE; } else { really_close(); fd = sopen(name, oflag, SH_DENYRW, FCMASK); lftrack.fd = fd; lftrack.oflag = oflag; lftrack.nethack_thinks_it_is_open = TRUE; } } else { fd = sopen(name, oflag, SH_DENYRW, FCMASK); lftrack.fd = fd; lftrack.oflag = oflag; if (fd >= 0) lftrack.nethack_thinks_it_is_open = TRUE; } return fd; } void really_close() { int fd = lftrack.fd; lftrack.nethack_thinks_it_is_open = FALSE; lftrack.fd = -1; lftrack.oflag = 0; if (fd != -1) (void) close(fd); return; } int nhclose(fd) int fd; { if (lftrack.fd == fd) { really_close(); /* close it, but reopen it to hold it */ fd = open_levelfile(0, (char *) 0); lftrack.nethack_thinks_it_is_open = FALSE; return 0; } return close(fd); } #else int nhclose(fd) int fd; { return close(fd); } #endif /* ---------- END LEVEL FILE HANDLING ----------- */ /* ---------- BEGIN BONES FILE HANDLING ----------- */ /* set up "file" to be file name for retrieving bones, and return a * bonesid to be read/written in the bones file. */ STATIC_OVL char * set_bonesfile_name(file, lev) char *file; d_level *lev; { s_level *sptr; char *dptr; Sprintf(file, "bon%c%s", dungeons[lev->dnum].boneid, In_quest(lev) ? urole.filecode : "0"); dptr = eos(file); if ((sptr = Is_special(lev)) != 0) Sprintf(dptr, ".%c", sptr->boneid); else Sprintf(dptr, ".%d", lev->dlevel); #ifdef VMS Strcat(dptr, ";1"); #endif return (dptr - 2); } /* set up temporary file name for writing bones, to avoid another game's * trying to read from an uncompleted bones file. we want an uncontentious * name, so use one in the namespace reserved for this game's level files. * (we are not reading or writing level files while writing bones files, so * the same array may be used instead of copying.) */ STATIC_OVL char * set_bonestemp_name() { char *tf; tf = rindex(lock, '.'); if (!tf) tf = eos(lock); Sprintf(tf, ".bn"); #ifdef VMS Strcat(tf, ";1"); #endif return lock; } int create_bonesfile(lev, bonesid, errbuf) d_level *lev; char **bonesid; char errbuf[]; { const char *file; int fd; if (errbuf) *errbuf = '\0'; *bonesid = set_bonesfile_name(bones, lev); file = set_bonestemp_name(); file = fqname(file, BONESPREFIX, 0); #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else #ifdef MAC fd = maccreat(file, BONE_TYPE); #else fd = creat(file, FCMASK); #endif #endif if (fd < 0 && errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).", lock, *bonesid, errno); #if defined(VMS) && !defined(SECURE) /* Re-protect bones file with world:read+write+execute+delete access. umask() doesn't seem very reliable; also, vaxcrtl won't let us set delete access without write access, which is what's really wanted. Can't simply create it with the desired protection because creat ANDs the mask with the user's default protection, which usually denies some or all access to world. */ (void) chmod(file, FCMASK | 007); /* allow other users full access */ #endif /* VMS && !SECURE */ return fd; } #ifdef MFLOPPY /* remove partial bonesfile in process of creation */ void cancel_bonesfile() { const char *tempname; tempname = set_bonestemp_name(); tempname = fqname(tempname, BONESPREFIX, 0); (void) unlink(tempname); } #endif /* MFLOPPY */ /* move completed bones file to proper name */ void commit_bonesfile(lev) d_level *lev; { const char *fq_bones, *tempname; int ret; (void) set_bonesfile_name(bones, lev); fq_bones = fqname(bones, BONESPREFIX, 0); tempname = set_bonestemp_name(); tempname = fqname(tempname, BONESPREFIX, 1); #if (defined(SYSV) && !defined(SVR4)) || defined(GENIX) /* old SYSVs don't have rename. Some SVR3's may, but since they * also have link/unlink, it doesn't matter. :-) */ (void) unlink(fq_bones); ret = link(tempname, fq_bones); ret += unlink(tempname); #else ret = rename(tempname, fq_bones); #endif if (wizard && ret != 0) pline("couldn't rename %s to %s.", tempname, fq_bones); } int open_bonesfile(lev, bonesid) d_level *lev; char **bonesid; { const char *fq_bones; int fd; *bonesid = set_bonesfile_name(bones, lev); fq_bones = fqname(bones, BONESPREFIX, 0); nh_uncompress(fq_bones); /* no effect if nonexistent */ #ifdef MAC fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE); #else fd = open(fq_bones, O_RDONLY | O_BINARY, 0); #endif return fd; } int delete_bonesfile(lev) d_level *lev; { (void) set_bonesfile_name(bones, lev); return !(unlink(fqname(bones, BONESPREFIX, 0)) < 0); } /* assume we're compressing the recently read or created bonesfile, so the * file name is already set properly */ void compress_bonesfile() { nh_compress(fqname(bones, BONESPREFIX, 0)); } /* ---------- END BONES FILE HANDLING ----------- */ /* ---------- BEGIN SAVE FILE HANDLING ----------- */ /* set savefile name in OS-dependent manner from pre-existing plname, * avoiding troublesome characters */ void set_savefile_name(regularize_it) boolean regularize_it; { #ifdef VMS Sprintf(SAVEF, "[.save]%d%s", getuid(), plname); if (regularize_it) regularize(SAVEF + 7); Strcat(SAVEF, ";1"); #else #if defined(MICRO) Strcpy(SAVEF, SAVEP); #ifdef AMIGA strncat(SAVEF, bbs_id, PATHLEN); #endif { int i = strlen(SAVEP); #ifdef AMIGA /* plname has to share space with SAVEP and ".sav" */ (void) strncat(SAVEF, plname, FILENAME - i - 4); #else (void) strncat(SAVEF, plname, 8); #endif if (regularize_it) regularize(SAVEF + i); } Strcat(SAVEF, SAVE_EXTENSION); #else #if defined(WIN32) { static const char okchars[] = "*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-."; const char *legal = okchars; char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; /* Obtain the name of the logged on user and incorporate * it into the name. */ Sprintf(fnamebuf, "%s-%s", get_username(0), plname); if (regularize_it) ++legal; /* skip '*' wildcard character */ (void) fname_encode(legal, '%', fnamebuf, encodedfnamebuf, BUFSZ); Sprintf(SAVEF, "%s%s", encodedfnamebuf, SAVE_EXTENSION); } #else /* not VMS or MICRO or WIN32 */ Sprintf(SAVEF, "save/%d%s", (int) getuid(), plname); if (regularize_it) regularize(SAVEF + 5); /* avoid . or / in name */ #endif /* WIN32 */ #endif /* MICRO */ #endif /* VMS */ } #ifdef INSURANCE void save_savefile_name(fd) int fd; { (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF)); } #endif #ifndef MICRO /* change pre-existing savefile name to indicate an error savefile */ void set_error_savefile() { #ifdef VMS { char *semi_colon = rindex(SAVEF, ';'); if (semi_colon) *semi_colon = '\0'; } Strcat(SAVEF, ".e;1"); #else #ifdef MAC Strcat(SAVEF, "-e"); #else Strcat(SAVEF, ".e"); #endif #endif } #endif /* create save file, overwriting one if it already exists */ int create_savefile() { const char *fq_save; int fd; fq_save = fqname(SAVEF, SAVEPREFIX, 0); #if defined(MICRO) || defined(WIN32) fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); #else #ifdef MAC fd = maccreat(fq_save, SAVE_TYPE); #else fd = creat(fq_save, FCMASK); #endif #if defined(VMS) && !defined(SECURE) /* Make sure the save file is owned by the current process. That's the default for non-privileged users, but for priv'd users the file will be owned by the directory's owner instead of the user. */ #undef getuid (void) chown(fq_save, getuid(), getgid()); #define getuid() vms_getuid() #endif /* VMS && !SECURE */ #endif /* MICRO */ return fd; } /* open savefile for reading */ int open_savefile() { const char *fq_save; int fd; fq_save = fqname(SAVEF, SAVEPREFIX, 0); #ifdef MAC fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); #else fd = open(fq_save, O_RDONLY | O_BINARY, 0); #endif return fd; } /* delete savefile */ int delete_savefile() { (void) unlink(fqname(SAVEF, SAVEPREFIX, 0)); return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ } /* try to open up a save file and prepare to restore it */ int restore_saved_game() { const char *fq_save; int fd; reset_restpref(); set_savefile_name(TRUE); #ifdef MFLOPPY if (!saveDiskPrompt(1)) return -1; #endif /* MFLOPPY */ fq_save = fqname(SAVEF, SAVEPREFIX, 0); nh_uncompress(fq_save); if ((fd = open_savefile()) < 0) return fd; if (validate(fd, fq_save) != 0) { (void) nhclose(fd), fd = -1; (void) delete_savefile(); } return fd; } #if defined(SELECTSAVED) char * plname_from_file(filename) const char *filename; { int fd; char *result = 0; Strcpy(SAVEF, filename); #ifdef COMPRESS_EXTENSION SAVEF[strlen(SAVEF) - strlen(COMPRESS_EXTENSION)] = '\0'; #endif nh_uncompress(SAVEF); if ((fd = open_savefile()) >= 0) { if (validate(fd, filename) == 0) { char tplname[PL_NSIZ]; get_plname_from_file(fd, tplname); result = dupstr(tplname); } (void) nhclose(fd); } nh_compress(SAVEF); return result; #if 0 /* --------- obsolete - used to be ifndef STORE_PLNAME_IN_FILE ----*/ #if defined(UNIX) && defined(QT_GRAPHICS) /* Name not stored in save file, so we have to extract it from the filename, which loses information (eg. "/", "_", and "." characters are lost. */ int k; int uid; char name[64]; /* more than PL_NSIZ */ #ifdef COMPRESS_EXTENSION #define EXTSTR COMPRESS_EXTENSION #else #define EXTSTR "" #endif if ( sscanf( filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name ) == 2 ) { #undef EXTSTR /* "_" most likely means " ", which certainly looks nicer */ for (k=0; name[k]; k++) if ( name[k] == '_' ) name[k] = ' '; return dupstr(name); } else #endif /* UNIX && QT_GRAPHICS */ { return 0; } /* --------- end of obsolete code ----*/ #endif /* 0 - WAS STORE_PLNAME_IN_FILE*/ } #endif /* defined(SELECTSAVED) */ char ** get_saved_games() { #if defined(SELECTSAVED) int n, j = 0; char **result = 0; #ifdef WIN32 { char *foundfile; const char *fq_save; Strcpy(plname, "*"); set_savefile_name(FALSE); #if defined(ZLIB_COMP) Strcat(SAVEF, COMPRESS_EXTENSION); #endif fq_save = fqname(SAVEF, SAVEPREFIX, 0); n = 0; foundfile = foundfile_buffer(); if (findfirst((char *) fq_save)) { do { ++n; } while (findnext()); } if (n > 0) { result = (char **) alloc((n + 1) * sizeof(char *)); /* at most */ (void) memset((genericptr_t) result, 0, (n + 1) * sizeof(char *)); if (findfirst((char *) fq_save)) { j = n = 0; do { char *r; r = plname_from_file(foundfile); if (r) result[j++] = r; ++n; } while (findnext()); } } } #endif #if defined(UNIX) && defined(QT_GRAPHICS) /* posixly correct version */ int myuid = getuid(); DIR *dir; if ((dir = opendir(fqname("save", SAVEPREFIX, 0)))) { for (n = 0; readdir(dir); n++) ; closedir(dir); if (n > 0) { int i; if (!(dir = opendir(fqname("save", SAVEPREFIX, 0)))) return 0; result = (char **) alloc((n + 1) * sizeof(char *)); /* at most */ (void) memset((genericptr_t) result, 0, (n + 1) * sizeof(char *)); for (i = 0, j = 0; i < n; i++) { int uid; char name[64]; /* more than PL_NSIZ */ struct dirent *entry = readdir(dir); if (!entry) break; if (sscanf(entry->d_name, "%d%63s", &uid, name) == 2) { if (uid == myuid) { char filename[BUFSZ]; char *r; Sprintf(filename, "save/%d%s", uid, name); r = plname_from_file(filename); if (r) result[j++] = r; } } } closedir(dir); } } #endif #ifdef VMS Strcpy(plname, "*"); set_savefile_name(FALSE); j = vms_get_saved_games(SAVEF, &result); #endif /* VMS */ if (j > 0) { if (j > 1) qsort(result, j, sizeof (char *), strcmp_wrap); result[j] = 0; return result; } else if (result) { /* could happen if save files are obsolete */ free_saved_games(result); } #endif /* SELECTSAVED */ return 0; } void free_saved_games(saved) char **saved; { if (saved) { int i = 0; while (saved[i]) free((genericptr_t) saved[i++]); free((genericptr_t) saved); } } /* ---------- END SAVE FILE HANDLING ----------- */ /* ---------- BEGIN FILE COMPRESSION HANDLING ----------- */ #ifdef COMPRESS STATIC_OVL void redirect(filename, mode, stream, uncomp) const char *filename, *mode; FILE *stream; boolean uncomp; { if (freopen(filename, mode, stream) == (FILE *) 0) { (void) fprintf(stderr, "freopen of %s for %scompress failed\n", filename, uncomp ? "un" : ""); terminate(EXIT_FAILURE); } } /* * using system() is simpler, but opens up security holes and causes * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any * setuid is renounced by /bin/sh, so the files cannot be accessed. * * cf. child() in unixunix.c. */ STATIC_OVL void docompress_file(filename, uncomp) const char *filename; boolean uncomp; { char cfn[80]; FILE *cf; const char *args[10]; #ifdef COMPRESS_OPTIONS char opts[80]; #endif int i = 0; int f; #ifdef TTY_GRAPHICS boolean istty = !strncmpi(windowprocs.name, "tty", 3); #endif Strcpy(cfn, filename); #ifdef COMPRESS_EXTENSION Strcat(cfn, COMPRESS_EXTENSION); #endif /* when compressing, we know the file exists */ if (uncomp) { if ((cf = fopen(cfn, RDBMODE)) == (FILE *) 0) return; (void) fclose(cf); } args[0] = COMPRESS; if (uncomp) args[++i] = "-d"; /* uncompress */ #ifdef COMPRESS_OPTIONS { /* we can't guarantee there's only one additional option, sigh */ char *opt; boolean inword = FALSE; Strcpy(opts, COMPRESS_OPTIONS); opt = opts; while (*opt) { if ((*opt == ' ') || (*opt == '\t')) { if (inword) { *opt = '\0'; inword = FALSE; } } else if (!inword) { args[++i] = opt; inword = TRUE; } opt++; } } #endif args[++i] = (char *) 0; #ifdef TTY_GRAPHICS /* If we don't do this and we are right after a y/n question *and* * there is an error message from the compression, the 'y' or 'n' can * end up being displayed after the error message. */ if (istty) mark_synch(); #endif f = fork(); if (f == 0) { /* child */ #ifdef TTY_GRAPHICS /* any error messages from the compression must come out after * the first line, because the more() to let the user read * them will have to clear the first line. This should be * invisible if there are no error messages. */ if (istty) raw_print(""); #endif /* run compressor without privileges, in case other programs * have surprises along the line of gzip once taking filenames * in GZIP. */ /* assume all compressors will compress stdin to stdout * without explicit filenames. this is true of at least * compress and gzip, those mentioned in config.h. */ if (uncomp) { redirect(cfn, RDBMODE, stdin, uncomp); redirect(filename, WRBMODE, stdout, uncomp); } else { redirect(filename, RDBMODE, stdin, uncomp); redirect(cfn, WRBMODE, stdout, uncomp); } (void) setgid(getgid()); (void) setuid(getuid()); (void) execv(args[0], (char *const *) args); perror((char *) 0); (void) fprintf(stderr, "Exec to %scompress %s failed.\n", uncomp ? "un" : "", filename); terminate(EXIT_FAILURE); } else if (f == -1) { perror((char *) 0); pline("Fork to %scompress %s failed.", uncomp ? "un" : "", filename); return; } #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); (void) wait((int *) &i); (void) signal(SIGINT, (SIG_RET_TYPE) done1); if (wizard) (void) signal(SIGQUIT, SIG_DFL); #else /* I don't think we can really cope with external compression * without signals, so we'll declare that compress failed and * go on. (We could do a better job by forcing off external * compression if there are no signals, but we want this for * testing with FailSafeC */ i = 1; #endif if (i == 0) { /* (un)compress succeeded: remove file left behind */ if (uncomp) (void) unlink(cfn); else (void) unlink(filename); } else { /* (un)compress failed; remove the new, bad file */ if (uncomp) { raw_printf("Unable to uncompress %s", filename); (void) unlink(filename); } else { /* no message needed for compress case; life will go on */ (void) unlink(cfn); } #ifdef TTY_GRAPHICS /* Give them a chance to read any error messages from the * compression--these would go to stdout or stderr and would get * overwritten only in tty mode. It's still ugly, since the * messages are being written on top of the screen, but at least * the user can read them. */ if (istty && iflags.window_inited) { clear_nhwindow(WIN_MESSAGE); more(); /* No way to know if this is feasible */ /* doredraw(); */ } #endif } } #endif /* COMPRESS */ #if defined(COMPRESS) || defined(ZLIB_COMP) #define UNUSED_if_not_COMPRESS /*empty*/ #else #define UNUSED_if_not_COMPRESS UNUSED #endif /* compress file */ void nh_compress(filename) const char *filename UNUSED_if_not_COMPRESS; { #if !defined(COMPRESS) && !defined(ZLIB_COMP) #ifdef PRAGMA_UNUSED #pragma unused(filename) #endif #else docompress_file(filename, FALSE); #endif } /* uncompress file if it exists */ void nh_uncompress(filename) const char *filename UNUSED_if_not_COMPRESS; { #if !defined(COMPRESS) && !defined(ZLIB_COMP) #ifdef PRAGMA_UNUSED #pragma unused(filename) #endif #else docompress_file(filename, TRUE); #endif } #ifdef ZLIB_COMP /* RLC 09 Mar 1999: Support internal ZLIB */ STATIC_OVL boolean make_compressed_name(filename, cfn) const char *filename; char *cfn; { #ifndef SHORT_FILENAMES /* Assume free-form filename with no 8.3 restrictions */ strcpy(cfn, filename); strcat(cfn, COMPRESS_EXTENSION); return TRUE; #else #ifdef SAVE_EXTENSION char *bp = (char *) 0; strcpy(cfn, filename); if ((bp = strstri(cfn, SAVE_EXTENSION))) { strsubst(bp, SAVE_EXTENSION, ".saz"); return TRUE; } else { /* find last occurrence of bon */ bp = eos(cfn); while (bp-- > cfn) { if (strstri(bp, "bon")) { strsubst(bp, "bon", "boz"); return TRUE; } } } #endif /* SAVE_EXTENSION */ return FALSE; #endif /* SHORT_FILENAMES */ } STATIC_OVL void docompress_file(filename, uncomp) const char *filename; boolean uncomp; { gzFile compressedfile; FILE *uncompressedfile; char cfn[256]; char buf[1024]; unsigned len, len2; if (!make_compressed_name(filename, cfn)) return; if (!uncomp) { /* Open the input and output files */ /* Note that gzopen takes "wb" as its mode, even on systems where fopen takes "r" and "w" */ uncompressedfile = fopen(filename, RDBMODE); if (!uncompressedfile) { pline("Error in zlib docompress_file %s", filename); return; } compressedfile = gzopen(cfn, "wb"); if (compressedfile == NULL) { if (errno == 0) { pline("zlib failed to allocate memory"); } else { panic("Error in docompress_file %d", errno); } fclose(uncompressedfile); return; } /* Copy from the uncompressed to the compressed file */ while (1) { len = fread(buf, 1, sizeof(buf), uncompressedfile); if (ferror(uncompressedfile)) { pline("Failure reading uncompressed file"); pline("Can't compress %s.", filename); fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(cfn); return; } if (len == 0) break; /* End of file */ len2 = gzwrite(compressedfile, buf, len); if (len2 == 0) { pline("Failure writing compressed file"); pline("Can't compress %s.", filename); fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(cfn); return; } } fclose(uncompressedfile); gzclose(compressedfile); /* Delete the file left behind */ (void) unlink(filename); } else { /* uncomp */ /* Open the input and output files */ /* Note that gzopen takes "rb" as its mode, even on systems where fopen takes "r" and "w" */ compressedfile = gzopen(cfn, "rb"); if (compressedfile == NULL) { if (errno == 0) { pline("zlib failed to allocate memory"); } else if (errno != ENOENT) { panic("Error in zlib docompress_file %s, %d", filename, errno); } return; } uncompressedfile = fopen(filename, WRBMODE); if (!uncompressedfile) { pline("Error in zlib docompress file uncompress %s", filename); gzclose(compressedfile); return; } /* Copy from the compressed to the uncompressed file */ while (1) { len = gzread(compressedfile, buf, sizeof(buf)); if (len == (unsigned) -1) { pline("Failure reading compressed file"); pline("Can't uncompress %s.", filename); fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(filename); return; } if (len == 0) break; /* End of file */ fwrite(buf, 1, len, uncompressedfile); if (ferror(uncompressedfile)) { pline("Failure writing uncompressed file"); pline("Can't uncompress %s.", filename); fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(filename); return; } } fclose(uncompressedfile); gzclose(compressedfile); /* Delete the file left behind */ (void) unlink(cfn); } } #endif /* RLC 09 Mar 1999: End ZLIB patch */ /* ---------- END FILE COMPRESSION HANDLING ----------- */ /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ static int nesting = 0; #if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */ static int lockfd; /* for lock_file() to pass to unlock_file() */ #endif #ifdef USE_FCNTL struct flock sflock; /* for unlocking, same as above */ #endif #define HUP if (!program_state.done_hup) #ifndef USE_FCNTL STATIC_OVL char * make_lockname(filename, lockname) const char *filename; char *lockname; { #if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(WIN32) \ || defined(MSDOS) #ifdef NO_FILE_LINKS Strcpy(lockname, LOCKDIR); Strcat(lockname, "/"); Strcat(lockname, filename); #else Strcpy(lockname, filename); #endif #ifdef VMS { char *semi_colon = rindex(lockname, ';'); if (semi_colon) *semi_colon = '\0'; } Strcat(lockname, ".lock;1"); #else Strcat(lockname, "_lock"); #endif return lockname; #else /* !(UNIX || VMS || AMIGA || WIN32 || MSDOS) */ #ifdef PRAGMA_UNUSED #pragma unused(filename) #endif lockname[0] = '\0'; return (char *) 0; #endif } #endif /* !USE_FCNTL */ /* lock a file */ boolean lock_file(filename, whichprefix, retryct) const char *filename; int whichprefix; int retryct; { #if defined(PRAGMA_UNUSED) && !(defined(UNIX) || defined(VMS)) \ && !(defined(AMIGA) || defined(WIN32) || defined(MSDOS)) #pragma unused(retryct) #endif #ifndef USE_FCNTL char locknambuf[BUFSZ]; const char *lockname; #endif nesting++; if (nesting > 1) { impossible("TRIED TO NEST LOCKS"); return TRUE; } #ifndef USE_FCNTL lockname = make_lockname(filename, locknambuf); #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ lockname = fqname(lockname, LOCKPREFIX, 2); #endif #endif filename = fqname(filename, whichprefix, 0); #ifdef USE_FCNTL lockfd = open(filename, O_RDWR); if (lockfd == -1) { HUP raw_printf("Cannot open file %s. This is a program bug.", filename); } sflock.l_type = F_WRLCK; sflock.l_whence = SEEK_SET; sflock.l_start = 0; sflock.l_len = 0; #endif #if defined(UNIX) || defined(VMS) #ifdef USE_FCNTL while (fcntl(lockfd, F_SETLK, &sflock) == -1) { #else #ifdef NO_FILE_LINKS while ((lockfd = open(lockname, O_RDWR | O_CREAT | O_EXCL, 0666)) == -1) { #else while (link(filename, lockname) == -1) { #endif #endif #ifdef USE_FCNTL if (retryct--) { HUP raw_printf( "Waiting for release of fcntl lock on %s. (%d retries left).", filename, retryct); sleep(1); } else { HUP(void) raw_print("I give up. Sorry."); HUP raw_printf("Some other process has an unnatural grip on %s.", filename); nesting--; return FALSE; } #else register int errnosv = errno; switch (errnosv) { /* George Barbanis */ case EEXIST: if (retryct--) { HUP raw_printf( "Waiting for access to %s. (%d retries left).", filename, retryct); #if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) #endif sleep(1); } else { HUP(void) raw_print("I give up. Sorry."); HUP raw_printf("Perhaps there is an old %s around?", lockname); nesting--; return FALSE; } break; case ENOENT: HUP raw_printf("Can't find file %s to lock!", filename); nesting--; return FALSE; case EACCES: HUP raw_printf("No write permission to lock %s!", filename); nesting--; return FALSE; #ifdef VMS /* c__translate(vmsfiles.c) */ case EPERM: /* could be misleading, but usually right */ HUP raw_printf("Can't lock %s due to directory protection.", filename); nesting--; return FALSE; #endif case EROFS: /* take a wild guess at the underlying cause */ HUP perror(lockname); HUP raw_printf("Cannot lock %s.", filename); HUP raw_printf( "(Perhaps you are running NetHack from inside the distribution package?)."); nesting--; return FALSE; default: HUP perror(lockname); HUP raw_printf("Cannot lock %s for unknown reason (%d).", filename, errnosv); nesting--; return FALSE; } #endif /* USE_FCNTL */ } #endif /* UNIX || VMS */ #if (defined(AMIGA) || defined(WIN32) || defined(MSDOS)) \ && !defined(USE_FCNTL) #ifdef AMIGA #define OPENFAILURE(fd) (!fd) lockptr = 0; #else #define OPENFAILURE(fd) (fd < 0) lockptr = -1; #endif while (--retryct && OPENFAILURE(lockptr)) { #if defined(WIN32) && !defined(WIN_CE) lockptr = sopen(lockname, O_RDWR | O_CREAT, SH_DENYRW, S_IWRITE); #else (void) DeleteFile(lockname); /* in case dead process was here first */ #ifdef AMIGA lockptr = Open(lockname, MODE_NEWFILE); #else lockptr = open(lockname, O_RDWR | O_CREAT | O_EXCL, S_IWRITE); #endif #endif if (OPENFAILURE(lockptr)) { raw_printf("Waiting for access to %s. (%d retries left).", filename, retryct); Delay(50); } } if (!retryct) { raw_printf("I give up. Sorry."); nesting--; return FALSE; } #endif /* AMIGA || WIN32 || MSDOS */ return TRUE; } #ifdef VMS /* for unlock_file, use the unlink() routine in vmsunix.c */ #ifdef unlink #undef unlink #endif #define unlink(foo) vms_unlink(foo) #endif /* unlock file, which must be currently locked by lock_file */ void unlock_file(filename) const char *filename; { #ifndef USE_FCNTL char locknambuf[BUFSZ]; const char *lockname; #endif if (nesting == 1) { #ifdef USE_FCNTL sflock.l_type = F_UNLCK; if (fcntl(lockfd, F_SETLK, &sflock) == -1) { HUP raw_printf("Can't remove fcntl lock on %s.", filename); (void) close(lockfd); } #else lockname = make_lockname(filename, locknambuf); #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ lockname = fqname(lockname, LOCKPREFIX, 2); #endif #if defined(UNIX) || defined(VMS) if (unlink(lockname) < 0) HUP raw_printf("Can't unlink %s.", lockname); #ifdef NO_FILE_LINKS (void) nhclose(lockfd); #endif #endif /* UNIX || VMS */ #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) if (lockptr) Close(lockptr); DeleteFile(lockname); lockptr = 0; #endif /* AMIGA || WIN32 || MSDOS */ #endif /* USE_FCNTL */ } nesting--; } /* ---------- END FILE LOCKING HANDLING ----------- */ /* ---------- BEGIN CONFIG FILE HANDLING ----------- */ const char *configfile = #ifdef UNIX ".nethackrc"; #else #if defined(MAC) || defined(__BEOS__) "NetHack Defaults"; #else #if defined(MSDOS) || defined(WIN32) "defaults.nh"; #else "NetHack.cnf"; #endif #endif #endif /* used for messaging */ char lastconfigfile[BUFSZ]; #ifdef MSDOS /* conflict with speed-dial under windows * for XXX.cnf file so support of NetHack.cnf * is for backward compatibility only. * Preferred name (and first tried) is now defaults.nh but * the game will try the old name if there * is no defaults.nh. */ const char *backward_compat_configfile = "nethack.cnf"; #endif #ifndef MFLOPPY #define fopenp fopen #endif STATIC_OVL FILE * fopen_config_file(filename, src) const char *filename; int src; { FILE *fp; #if defined(UNIX) || defined(VMS) char tmp_config[BUFSZ]; char *envp; #endif /* If src != SET_IN_SYS, "filename" is an environment variable, so it * should hang around. If set, it is expected to be a full path name * (if relevant) */ if (filename) { #ifdef UNIX if ((src != SET_IN_SYS) && access(filename, 4) == -1) { /* 4 is R_OK on newer systems */ /* nasty sneaky attempt to read file through * NetHack's setuid permissions -- this is the only * place a file name may be wholly under the player's * control (but SYSCF_FILE is not under the player's * control so it's OK). */ raw_printf("Access to %s denied (%d).", filename, errno); wait_synch(); /* fall through to standard names */ } else #endif #ifdef PREFIXES_IN_USE if (src == SET_IN_SYS) { (void) strncpy(lastconfigfile, fqname(filename, SYSCONFPREFIX, 0), BUFSZ - 1); } else #endif /* always honor sysconf first before anything else */ (void) strncpy(lastconfigfile, filename, BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) return fp; if ((fp = fopenp(filename, "r")) != (FILE *) 0) { return fp; #if defined(UNIX) || defined(VMS) } else { /* access() above probably caught most problems for UNIX */ raw_printf("Couldn't open requested config file %s (%d).", filename, errno); wait_synch(); /* fall through to standard names */ #endif } } #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) != (FILE *) 0) return fp; if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; #ifdef MSDOS if ((fp = fopenp(fqname(backward_compat_configfile, CONFIGPREFIX, 0), "r")) != (FILE *) 0) return fp; if ((fp = fopenp(backward_compat_configfile, "r")) != (FILE *) 0) return fp; #endif #else /* constructed full path names don't need fqname() */ #ifdef VMS (void) strncpy(lastconfigfile, fqname("nethackini", CONFIGPREFIX, 0), BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) { return fp; } (void) strncpy(lastconfigfile, "sys$login:nethack.ini", BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) { return fp; } envp = nh_getenv("HOME"); if (!envp) Strcpy(tmp_config, "NetHack.cnf"); else Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf"); (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(tmp_config, "r")) != (FILE *) 0) return fp; #else /* should be only UNIX left */ envp = nh_getenv("HOME"); if (!envp) Strcpy(tmp_config, ".nethackrc"); else Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) return fp; #if defined(__APPLE__) /* try an alternative */ if (envp) { Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults"); (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) return fp; Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults.txt"); (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); lastconfigfile[BUFSZ - 1] = '\0'; if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) return fp; } #endif if (errno != ENOENT) { const char *details; /* e.g., problems when setuid NetHack can't search home * directory restricted to user */ #if defined(NHSTDC) && !defined(NOTSTDC) if ((details = strerror(errno)) == 0) #endif details = ""; raw_printf("Couldn't open default config file %s %s(%d).", lastconfigfile, details, errno); wait_synch(); } #endif /* Unix */ #endif return (FILE *) 0; } /* * Retrieve a list of integers from a file into a uchar array. * * NOTE: zeros are inserted unless modlist is TRUE, in which case the list * location is unchanged. Callers must handle zeros if modlist is FALSE. */ STATIC_OVL int get_uchars(fp, buf, bufp, list, modlist, size, name) FILE *fp; /* input file pointer */ char *buf; /* read buffer, must be of size BUFSZ */ char *bufp; /* current pointer */ uchar *list; /* return list */ boolean modlist; /* TRUE: list is being modified in place */ int size; /* return list size */ const char *name; /* name of option for error message */ { unsigned int num = 0; int count = 0; boolean havenum = FALSE; while (1) { switch (*bufp) { case ' ': case '\0': case '\t': case '\n': if (havenum) { /* if modifying in place, don't insert zeros */ if (num || !modlist) list[count] = num; count++; num = 0; havenum = FALSE; } if (count == size || !*bufp) return count; bufp++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': havenum = TRUE; num = num * 10 + (*bufp - '0'); bufp++; break; case '\\': if (fp == (FILE *) 0) goto gi_error; do { if (!fgets(buf, BUFSZ, fp)) goto gi_error; } while (buf[0] == '#'); bufp = buf; break; default: gi_error: raw_printf("Syntax error in %s", name); wait_synch(); return count; } } /*NOTREACHED*/ } #ifdef NOCWD_ASSUMPTIONS STATIC_OVL void adjust_prefix(bufp, prefixid) char *bufp; int prefixid; { char *ptr; if (!bufp) return; /* Backward compatibility, ignore trailing ;n */ if ((ptr = index(bufp, ';')) != 0) *ptr = '\0'; if (strlen(bufp) > 0) { fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2); Strcpy(fqn_prefix[prefixid], bufp); append_slash(fqn_prefix[prefixid]); } } #endif #define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE) int parse_config_line(fp, origbuf, src) FILE *fp; char *origbuf; int src; { #if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) static boolean ramdisk_specified = FALSE; #endif #ifdef SYSCF int n; #endif char *bufp, *altp, buf[BUFSZ]; uchar translate[MAXPCHARS]; int len; /* convert any tab to space, condense consecutive spaces into one, remove leading and trailing spaces (exception: if there is nothing but spaces, one of them will be kept even though it leads/trails) */ mungspaces(strcpy(buf, origbuf)); /* lines beginning with '#' are comments; accept empty lines too */ if (!*buf || *buf == '#' || !strcmp(buf, " ")) return 1; /* find the '=' or ':' */ bufp = index(buf, '='); altp = index(buf, ':'); if (!bufp || (altp && altp < bufp)) bufp = altp; if (!bufp) return 0; /* skip past '=', then space between it and value, if any */ ++bufp; if (*bufp == ' ') ++bufp; /* Go through possible variables */ /* some of these (at least LEVELS and SAVE) should now set the * appropriate fqn_prefix[] rather than specialized variables */ if (match_varname(buf, "OPTIONS", 4)) { /* hack: un-mungspaces to allow consecutive spaces in general options until we verify that this is unnecessary; '=' or ':' is guaranteed to be present */ bufp = index(origbuf, '='); altp = index(origbuf, ':'); if (!bufp || (altp && altp < bufp)) bufp = altp; ++bufp; /* skip '='; parseoptions() handles spaces */ parseoptions(bufp, TRUE, TRUE); if (plname[0]) /* If a name was given */ plnamesuffix(); /* set the character class */ } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) { add_autopickup_exception(bufp); } else if (match_varname(buf, "MSGTYPE", 7)) { (void) msgtype_parse_add(bufp); #ifdef NOCWD_ASSUMPTIONS } else if (match_varname(buf, "HACKDIR", 4)) { adjust_prefix(bufp, HACKPREFIX); } else if (match_varname(buf, "LEVELDIR", 4) || match_varname(buf, "LEVELS", 4)) { adjust_prefix(bufp, LEVELPREFIX); } else if (match_varname(buf, "SAVEDIR", 4)) { adjust_prefix(bufp, SAVEPREFIX); } else if (match_varname(buf, "BONESDIR", 5)) { adjust_prefix(bufp, BONESPREFIX); } else if (match_varname(buf, "DATADIR", 4)) { adjust_prefix(bufp, DATAPREFIX); } else if (match_varname(buf, "SCOREDIR", 4)) { adjust_prefix(bufp, SCOREPREFIX); } else if (match_varname(buf, "LOCKDIR", 4)) { adjust_prefix(bufp, LOCKPREFIX); } else if (match_varname(buf, "CONFIGDIR", 4)) { adjust_prefix(bufp, CONFIGPREFIX); } else if (match_varname(buf, "TROUBLEDIR", 4)) { adjust_prefix(bufp, TROUBLEPREFIX); #else /*NOCWD_ASSUMPTIONS*/ #ifdef MICRO } else if (match_varname(buf, "HACKDIR", 4)) { (void) strncpy(hackdir, bufp, PATHLEN - 1); #ifdef MFLOPPY } else if (match_varname(buf, "RAMDISK", 3)) { /* The following ifdef is NOT in the wrong * place. For now, we accept and silently * ignore RAMDISK */ #ifndef AMIGA if (strlen(bufp) >= PATHLEN) bufp[PATHLEN - 1] = '\0'; Strcpy(levels, bufp); ramdisk = (strcmp(permbones, levels) != 0); ramdisk_specified = TRUE; #endif #endif } else if (match_varname(buf, "LEVELS", 4)) { if (strlen(bufp) >= PATHLEN) bufp[PATHLEN - 1] = '\0'; Strcpy(permbones, bufp); if (!ramdisk_specified || !*levels) Strcpy(levels, bufp); ramdisk = (strcmp(permbones, levels) != 0); } else if (match_varname(buf, "SAVE", 4)) { #ifdef MFLOPPY extern int saveprompt; #endif char *ptr; if ((ptr = index(bufp, ';')) != 0) { *ptr = '\0'; #ifdef MFLOPPY if (*(ptr + 1) == 'n' || *(ptr + 1) == 'N') { saveprompt = FALSE; } #endif } #if defined(SYSFLAGS) && defined(MFLOPPY) else saveprompt = sysflags.asksavedisk; #endif (void) strncpy(SAVEP, bufp, SAVESIZE - 1); append_slash(SAVEP); #endif /* MICRO */ #endif /*NOCWD_ASSUMPTIONS*/ } else if (match_varname(buf, "NAME", 4)) { (void) strncpy(plname, bufp, PL_NSIZ - 1); plnamesuffix(); } else if (match_varname(buf, "ROLE", 4) || match_varname(buf, "CHARACTER", 4)) { if ((len = str2role(bufp)) >= 0) flags.initrole = len; } else if (match_varname(buf, "DOGNAME", 3)) { (void) strncpy(dogname, bufp, PL_PSIZ - 1); } else if (match_varname(buf, "CATNAME", 3)) { (void) strncpy(catname, bufp, PL_PSIZ - 1); #ifdef SYSCF } else if (src == SET_IN_SYS && match_varname(buf, "WIZARDS", 7)) { if (sysopt.wizards) free((genericptr_t) sysopt.wizards); sysopt.wizards = dupstr(bufp); if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) { /* pre-format WIZARDS list now; it's displayed during a panic and since that panic might be due to running out of memory, we don't want to risk attempting to allocate any memory then */ if (sysopt.fmtd_wizard_list) free((genericptr_t) sysopt.fmtd_wizard_list); sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards); } } else if (src == SET_IN_SYS && match_varname(buf, "SHELLERS", 8)) { if (sysopt.shellers) free((genericptr_t) sysopt.shellers); sysopt.shellers = dupstr(bufp); } else if (src == SET_IN_SYS && match_varname(buf, "EXPLORERS", 7)) { if (sysopt.explorers) free((genericptr_t) sysopt.explorers); sysopt.explorers = dupstr(bufp); } else if (src == SET_IN_SYS && match_varname(buf, "DEBUGFILES", 5)) { /* if showdebug() has already been called (perhaps we've added some debugpline() calls to option processing) and has found a value for getenv("DEBUGFILES"), don't override that */ if (sysopt.env_dbgfl <= 0) { if (sysopt.debugfiles) free((genericptr_t) sysopt.debugfiles); sysopt.debugfiles = dupstr(bufp); } } else if (src == SET_IN_SYS && match_varname(buf, "SUPPORT", 7)) { if (sysopt.support) free((genericptr_t) sysopt.support); sysopt.support = dupstr(bufp); } else if (src == SET_IN_SYS && match_varname(buf, "RECOVER", 7)) { if (sysopt.recover) free((genericptr_t) sysopt.recover); sysopt.recover = dupstr(bufp); } else if (src == SET_IN_SYS && match_varname(buf, "CHECK_SAVE_UID", 14)) { n = atoi(bufp); sysopt.check_save_uid = n; } else if (match_varname(buf, "SEDUCE", 6)) { n = !!atoi(bufp); /* XXX this could be tighter */ /* allow anyone to turn it off, but only sysconf to turn it on*/ if (src != SET_IN_SYS && n != 0) { raw_printf("Illegal value in SEDUCE"); return 0; } sysopt.seduce = n; sysopt_seduce_set(sysopt.seduce); } else if (src == SET_IN_SYS && match_varname(buf, "MAXPLAYERS", 10)) { n = atoi(bufp); /* XXX to get more than 25, need to rewrite all lock code */ if (n < 1 || n > 25) { raw_printf("Illegal value in MAXPLAYERS (maximum is 25)."); return 0; } sysopt.maxplayers = n; } else if (src == SET_IN_SYS && match_varname(buf, "PERSMAX", 7)) { n = atoi(bufp); if (n < 1) { raw_printf("Illegal value in PERSMAX (minimum is 1)."); return 0; } sysopt.persmax = n; } else if (src == SET_IN_SYS && match_varname(buf, "PERS_IS_UID", 11)) { n = atoi(bufp); if (n != 0 && n != 1) { raw_printf("Illegal value in PERS_IS_UID (must be 0 or 1)."); return 0; } sysopt.pers_is_uid = n; } else if (src == SET_IN_SYS && match_varname(buf, "ENTRYMAX", 8)) { n = atoi(bufp); if (n < 10) { raw_printf("Illegal value in ENTRYMAX (minimum is 10)."); return 0; } sysopt.entrymax = n; } else if ((src == SET_IN_SYS) && match_varname(buf, "POINTSMIN", 9)) { n = atoi(bufp); if (n < 1) { raw_printf("Illegal value in POINTSMIN (minimum is 1)."); return 0; } sysopt.pointsmin = n; } else if (src == SET_IN_SYS && match_varname(buf, "MAX_STATUENAME_RANK", 10)) { n = atoi(bufp); if (n < 1) { raw_printf( "Illegal value in MAX_STATUENAME_RANK (minimum is 1)."); return 0; } sysopt.tt_oname_maxrank = n; /* SYSCF PANICTRACE options */ } else if (src == SET_IN_SYS && match_varname(buf, "PANICTRACE_LIBC", 15)) { n = atoi(bufp); #if defined(PANICTRACE) && defined(PANICTRACE_LIBC) if (n < 0 || n > 2) { raw_printf("Illegal value in PANICTRACE_LIBC (not 0,1,2)."); return 0; } #endif sysopt.panictrace_libc = n; } else if (src == SET_IN_SYS && match_varname(buf, "PANICTRACE_GDB", 14)) { n = atoi(bufp); #if defined(PANICTRACE) if (n < 0 || n > 2) { raw_printf("Illegal value in PANICTRACE_GDB (not 0,1,2)."); return 0; } #endif sysopt.panictrace_gdb = n; } else if (src == SET_IN_SYS && match_varname(buf, "GDBPATH", 7)) { #if defined(PANICTRACE) && !defined(VMS) if (!file_exists(bufp)) { raw_printf("File specified in GDBPATH does not exist."); return 0; } #endif if (sysopt.gdbpath) free((genericptr_t) sysopt.gdbpath); sysopt.gdbpath = dupstr(bufp); } else if (src == SET_IN_SYS && match_varname(buf, "GREPPATH", 7)) { #if defined(PANICTRACE) && !defined(VMS) if (!file_exists(bufp)) { raw_printf("File specified in GREPPATH does not exist."); return 0; } #endif if (sysopt.greppath) free((genericptr_t) sysopt.greppath); sysopt.greppath = dupstr(bufp); #endif /* SYSCF */ } else if (match_varname(buf, "BOULDER", 3)) { (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE, 1, "BOULDER"); } else if (match_varname(buf, "MENUCOLOR", 9)) { (void) add_menu_coloring(bufp); } else if (match_varname(buf, "WARNINGS", 5)) { (void) get_uchars(fp, buf, bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); assign_warnings(translate); } else if (match_varname(buf, "SYMBOLS", 4)) { char *op, symbuf[BUFSZ]; boolean morelines; do { /* check for line continuation (trailing '\') */ op = eos(bufp); morelines = (--op >= bufp && *op == '\\'); if (morelines) { *op = '\0'; /* strip trailing space now that '\' is gone */ if (--op >= bufp && *op == ' ') *op = '\0'; } /* parse here */ parsesymbols(bufp); if (morelines) { do { *symbuf = '\0'; if (!fgets(symbuf, BUFSZ, fp)) { morelines = FALSE; break; } mungspaces(symbuf); bufp = symbuf; } while (*bufp == '#'); } } while (morelines); switch_symbols(TRUE); } else if (match_varname(buf, "WIZKIT", 6)) { (void) strncpy(wizkit, bufp, WIZKIT_MAX - 1); #ifdef AMIGA } else if (match_varname(buf, "FONT", 4)) { char *t; if (t = strchr(buf + 5, ':')) { *t = 0; amii_set_text_font(buf + 5, atoi(t + 1)); *t = ':'; } } else if (match_varname(buf, "PATH", 4)) { (void) strncpy(PATH, bufp, PATHLEN - 1); } else if (match_varname(buf, "DEPTH", 5)) { extern int amii_numcolors; int val = atoi(bufp); amii_numcolors = 1L << min(DEPTH, val); #ifdef SYSFLAGS } else if (match_varname(buf, "DRIPENS", 7)) { int i, val; char *t; for (i = 0, t = strtok(bufp, ",/"); t != (char *) 0; i < 20 && (t = strtok((char *) 0, ",/")), ++i) { sscanf(t, "%d", &val); sysflags.amii_dripens[i] = val; } #endif } else if (match_varname(buf, "SCREENMODE", 10)) { extern long amii_scrnmode; if (!stricmp(bufp, "req")) amii_scrnmode = 0xffffffff; /* Requester */ else if (sscanf(bufp, "%x", &amii_scrnmode) != 1) amii_scrnmode = 0; } else if (match_varname(buf, "MSGPENS", 7)) { extern int amii_msgAPen, amii_msgBPen; char *t = strtok(bufp, ",/"); if (t) { sscanf(t, "%d", &amii_msgAPen); if (t = strtok((char *) 0, ",/")) sscanf(t, "%d", &amii_msgBPen); } } else if (match_varname(buf, "TEXTPENS", 8)) { extern int amii_textAPen, amii_textBPen; char *t = strtok(bufp, ",/"); if (t) { sscanf(t, "%d", &amii_textAPen); if (t = strtok((char *) 0, ",/")) sscanf(t, "%d", &amii_textBPen); } } else if (match_varname(buf, "MENUPENS", 8)) { extern int amii_menuAPen, amii_menuBPen; char *t = strtok(bufp, ",/"); if (t) { sscanf(t, "%d", &amii_menuAPen); if (t = strtok((char *) 0, ",/")) sscanf(t, "%d", &amii_menuBPen); } } else if (match_varname(buf, "STATUSPENS", 10)) { extern int amii_statAPen, amii_statBPen; char *t = strtok(bufp, ",/"); if (t) { sscanf(t, "%d", &amii_statAPen); if (t = strtok((char *) 0, ",/")) sscanf(t, "%d", &amii_statBPen); } } else if (match_varname(buf, "OTHERPENS", 9)) { extern int amii_otherAPen, amii_otherBPen; char *t = strtok(bufp, ",/"); if (t) { sscanf(t, "%d", &amii_otherAPen); if (t = strtok((char *) 0, ",/")) sscanf(t, "%d", &amii_otherBPen); } } else if (match_varname(buf, "PENS", 4)) { extern unsigned short amii_init_map[AMII_MAXCOLORS]; int i; char *t; for (i = 0, t = strtok(bufp, ",/"); i < AMII_MAXCOLORS && t != (char *) 0; t = strtok((char *) 0, ",/"), ++i) { sscanf(t, "%hx", &amii_init_map[i]); } amii_setpens(amii_numcolors = i); } else if (match_varname(buf, "FGPENS", 6)) { extern int foreg[AMII_MAXCOLORS]; int i; char *t; for (i = 0, t = strtok(bufp, ",/"); i < AMII_MAXCOLORS && t != (char *) 0; t = strtok((char *) 0, ",/"), ++i) { sscanf(t, "%d", &foreg[i]); } } else if (match_varname(buf, "BGPENS", 6)) { extern int backg[AMII_MAXCOLORS]; int i; char *t; for (i = 0, t = strtok(bufp, ",/"); i < AMII_MAXCOLORS && t != (char *) 0; t = strtok((char *) 0, ",/"), ++i) { sscanf(t, "%d", &backg[i]); } #endif /*AMIGA*/ #ifdef USER_SOUNDS } else if (match_varname(buf, "SOUNDDIR", 8)) { sounddir = dupstr(bufp); } else if (match_varname(buf, "SOUND", 5)) { add_sound_mapping(bufp); #endif #ifdef QT_GRAPHICS /* These should move to wc_ options */ } else if (match_varname(buf, "QT_TILEWIDTH", 12)) { extern char *qt_tilewidth; if (qt_tilewidth == NULL) qt_tilewidth = dupstr(bufp); } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) { extern char *qt_tileheight; if (qt_tileheight == NULL) qt_tileheight = dupstr(bufp); } else if (match_varname(buf, "QT_FONTSIZE", 11)) { extern char *qt_fontsize; if (qt_fontsize == NULL) qt_fontsize = dupstr(bufp); } else if (match_varname(buf, "QT_COMPACT", 10)) { extern int qt_compact_mode; qt_compact_mode = atoi(bufp); #endif } else return 0; return 1; } #ifdef USER_SOUNDS boolean can_read_file(filename) const char *filename; { return (boolean) (access(filename, 4) == 0); } #endif /* USER_SOUNDS */ boolean read_config_file(filename, src) const char *filename; int src; { char buf[4 * BUFSZ], *p; FILE *fp; boolean rv = TRUE; /* assume successful parse */ if (!(fp = fopen_config_file(filename, src))) return FALSE; /* begin detection of duplicate configfile options */ set_duplicate_opt_detection(1); while (fgets(buf, sizeof buf, fp)) { #ifdef notyet /* XXX Don't call read() in parse_config_line, read as callback or reassemble line at this level. OR: Forbid multiline stuff for alternate config sources. */ #endif if ((p = index(buf, '\n')) != 0) *p = '\0'; if (!parse_config_line(fp, buf, src)) { static const char badoptionline[] = "Bad option line: \"%s\""; /* truncate buffer if it's long; this is actually conservative */ if (strlen(buf) > BUFSZ - sizeof badoptionline) buf[BUFSZ - sizeof badoptionline] = '\0'; raw_printf(badoptionline, buf); wait_synch(); rv = FALSE; } } (void) fclose(fp); /* turn off detection of duplicate configfile options */ set_duplicate_opt_detection(0); return rv; } STATIC_OVL FILE * fopen_wizkit_file() { FILE *fp; #if defined(VMS) || defined(UNIX) char tmp_wizkit[BUFSZ]; #endif char *envp; envp = nh_getenv("WIZKIT"); if (envp && *envp) (void) strncpy(wizkit, envp, WIZKIT_MAX - 1); if (!wizkit[0]) return (FILE *) 0; #ifdef UNIX if (access(wizkit, 4) == -1) { /* 4 is R_OK on newer systems */ /* nasty sneaky attempt to read file through * NetHack's setuid permissions -- this is a * place a file name may be wholly under the player's * control */ raw_printf("Access to %s denied (%d).", wizkit, errno); wait_synch(); /* fall through to standard names */ } else #endif if ((fp = fopenp(wizkit, "r")) != (FILE *) 0) { return fp; #if defined(UNIX) || defined(VMS) } else { /* access() above probably caught most problems for UNIX */ raw_printf("Couldn't open requested config file %s (%d).", wizkit, errno); wait_synch(); #endif } #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) if ((fp = fopenp(fqname(wizkit, CONFIGPREFIX, 0), "r")) != (FILE *) 0) return fp; #else #ifdef VMS envp = nh_getenv("HOME"); if (envp) Sprintf(tmp_wizkit, "%s%s", envp, wizkit); else Sprintf(tmp_wizkit, "%s%s", "sys$login:", wizkit); if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *) 0) return fp; #else /* should be only UNIX left */ envp = nh_getenv("HOME"); if (envp) Sprintf(tmp_wizkit, "%s/%s", envp, wizkit); else Strcpy(tmp_wizkit, wizkit); if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *) 0) return fp; else if (errno != ENOENT) { /* e.g., problems when setuid NetHack can't search home * directory restricted to user */ raw_printf("Couldn't open default wizkit file %s (%d).", tmp_wizkit, errno); wait_synch(); } #endif #endif return (FILE *) 0; } /* add to hero's inventory if there's room, otherwise put item on floor */ STATIC_DCL void wizkit_addinv(obj) struct obj *obj; { if (!obj || obj == &zeroobj) return; /* subset of starting inventory pre-ID */ obj->dknown = 1; if (Role_if(PM_PRIEST)) obj->bknown = 1; /* same criteria as lift_object()'s check for available inventory slot */ if (obj->oclass != COIN_CLASS && inv_cnt(FALSE) >= 52 && !merge_choice(invent, obj)) { /* inventory overflow; can't just place & stack object since hero isn't in position yet, so schedule for arrival later */ add_to_migration(obj); obj->ox = 0; /* index of main dungeon */ obj->oy = 1; /* starting level number */ obj->owornmask = (long) (MIGR_WITH_HERO | MIGR_NOBREAK | MIGR_NOSCATTER); } else { (void) addinv(obj); } } void read_wizkit() { FILE *fp; char *ep, buf[BUFSZ]; struct obj *otmp; boolean bad_items = FALSE, skip = FALSE; if (!wizard || !(fp = fopen_wizkit_file())) return; program_state.wizkit_wishing = 1; while (fgets(buf, (int) (sizeof buf), fp)) { ep = index(buf, '\n'); if (skip) { /* in case previous line was too long */ if (ep) skip = FALSE; /* found newline; next line is normal */ } else { if (!ep) skip = TRUE; /* newline missing; discard next fgets */ else *ep = '\0'; /* remove newline */ if (buf[0]) { otmp = readobjnam(buf, (struct obj *) 0); if (otmp) { if (otmp != &zeroobj) wizkit_addinv(otmp); } else { /* .60 limits output line width to 79 chars */ raw_printf("Bad wizkit item: \"%.60s\"", buf); bad_items = TRUE; } } } } program_state.wizkit_wishing = 0; if (bad_items) wait_synch(); (void) fclose(fp); return; } extern struct symsetentry *symset_list; /* options.c */ extern struct symparse loadsyms[]; /* drawing.c */ extern const char *known_handling[]; /* drawing.c */ extern const char *known_restrictions[]; /* drawing.c */ static int symset_count = 0; /* for pick-list building only */ static boolean chosen_symset_start = FALSE, chosen_symset_end = FALSE; STATIC_OVL FILE * fopen_sym_file() { FILE *fp; fp = fopen_datafile(SYMBOLS, "r", HACKPREFIX); return fp; } /* * Returns 1 if the chose symset was found and loaded. * 0 if it wasn't found in the sym file or other problem. */ int read_sym_file(which_set) int which_set; { char buf[4 * BUFSZ]; FILE *fp; if (!(fp = fopen_sym_file())) return 0; symset_count = 0; chosen_symset_start = chosen_symset_end = FALSE; while (fgets(buf, 4 * BUFSZ, fp)) { if (!parse_sym_line(buf, which_set)) { raw_printf("Bad symbol line: \"%.50s\"", buf); wait_synch(); } } (void) fclose(fp); if (!chosen_symset_end && !chosen_symset_start) return (symset[which_set].name == 0) ? 1 : 0; if (!chosen_symset_end) { raw_printf("Missing finish for symset \"%s\"", symset[which_set].name ? symset[which_set].name : "unknown"); wait_synch(); } return 1; } /* returns 0 on error */ int parse_sym_line(buf, which_set) char *buf; int which_set; { int val, i; struct symparse *symp = (struct symparse *) 0; char *bufp, *commentp, *altp; /* convert each instance of whitespace (tabs, consecutive spaces) into a single space; leading and trailing spaces are stripped */ mungspaces(buf); if (!*buf || *buf == '#' || !strcmp(buf, " ")) return 1; /* remove trailing comment, if any */ if ((commentp = rindex(buf, '#')) != 0) { *commentp = '\0'; /* remove space preceding the stripped comment, if any; we know 'commentp > buf' because *buf=='#' was caught above */ if (commentp[-1] == ' ') *--commentp = '\0'; } /* find the '=' or ':' */ bufp = index(buf, '='); altp = index(buf, ':'); if (!bufp || (altp && altp < bufp)) bufp = altp; if (!bufp) { if (strncmpi(buf, "finish", 6) == 0) { /* end current graphics set */ if (chosen_symset_start) chosen_symset_end = TRUE; chosen_symset_start = FALSE; return 1; } return 0; } /* skip '=' and space which follows, if any */ ++bufp; if (*bufp == ' ') ++bufp; symp = match_sym(buf); if (!symp) return 0; if (!symset[which_set].name) { /* A null symset name indicates that we're just building a pick-list of possible symset values from the file, so only do that */ if (symp->range == SYM_CONTROL) { struct symsetentry *tmpsp; switch (symp->idx) { case 0: tmpsp = (struct symsetentry *) alloc(sizeof (struct symsetentry)); tmpsp->next = (struct symsetentry *) 0; if (!symset_list) { symset_list = tmpsp; symset_count = 0; } else { symset_count++; tmpsp->next = symset_list; symset_list = tmpsp; } tmpsp->idx = symset_count; tmpsp->name = dupstr(bufp); tmpsp->desc = (char *) 0; tmpsp->nocolor = 0; /* initialize restriction bits */ tmpsp->primary = 0; tmpsp->rogue = 0; break; case 2: /* handler type identified */ tmpsp = symset_list; /* most recent symset */ tmpsp->handling = H_UNK; i = 0; while (known_handling[i]) { if (!strcmpi(known_handling[i], bufp)) { tmpsp->handling = i; break; /* while loop */ } i++; } break; case 3: /* description:something */ tmpsp = symset_list; /* most recent symset */ if (tmpsp && !tmpsp->desc) tmpsp->desc = dupstr(bufp); break; case 5: /* restrictions: xxxx*/ tmpsp = symset_list; /* most recent symset */ for (i = 0; known_restrictions[i]; ++i) { if (!strcmpi(known_restrictions[i], bufp)) { switch (i) { case 0: tmpsp->primary = 1; break; case 1: tmpsp->rogue = 1; break; } break; /* while loop */ } } break; } } return 1; } if (symp->range) { if (symp->range == SYM_CONTROL) { switch (symp->idx) { case 0: /* start of symset */ if (!strcmpi(bufp, symset[which_set].name)) { /* matches desired one */ chosen_symset_start = TRUE; /* these init_*() functions clear symset fields too */ if (which_set == ROGUESET) init_r_symbols(); else if (which_set == PRIMARY) init_l_symbols(); } break; case 1: /* finish symset */ if (chosen_symset_start) chosen_symset_end = TRUE; chosen_symset_start = FALSE; break; case 2: /* handler type identified */ if (chosen_symset_start) set_symhandling(bufp, which_set); break; /* case 3: (description) is ignored here */ case 4: /* color:off */ if (chosen_symset_start) { if (bufp) { if (!strcmpi(bufp, "true") || !strcmpi(bufp, "yes") || !strcmpi(bufp, "on")) symset[which_set].nocolor = 0; else if (!strcmpi(bufp, "false") || !strcmpi(bufp, "no") || !strcmpi(bufp, "off")) symset[which_set].nocolor = 1; } } break; case 5: /* restrictions: xxxx*/ if (chosen_symset_start) { int n = 0; while (known_restrictions[n]) { if (!strcmpi(known_restrictions[n], bufp)) { switch (n) { case 0: symset[which_set].primary = 1; break; case 1: symset[which_set].rogue = 1; break; } break; /* while loop */ } n++; } } break; } } else { /* !SYM_CONTROL */ val = sym_val(bufp); if (chosen_symset_start) { if (which_set == PRIMARY) { update_l_symset(symp, val); } else if (which_set == ROGUESET) { update_r_symset(symp, val); } } } } return 1; } STATIC_OVL void set_symhandling(handling, which_set) char *handling; int which_set; { int i = 0; symset[which_set].handling = H_UNK; while (known_handling[i]) { if (!strcmpi(known_handling[i], handling)) { symset[which_set].handling = i; return; } i++; } } /* ---------- END CONFIG FILE HANDLING ----------- */ /* ---------- BEGIN SCOREBOARD CREATION ----------- */ #ifdef OS2_CODEVIEW #define UNUSED_if_not_OS2_CODEVIEW /*empty*/ #else #define UNUSED_if_not_OS2_CODEVIEW UNUSED #endif /* verify that we can write to scoreboard file; if not, try to create one */ /*ARGUSED*/ void check_recordfile(dir) const char *dir UNUSED_if_not_OS2_CODEVIEW; { #if defined(PRAGMA_UNUSED) && !defined(OS2_CODEVIEW) #pragma unused(dir) #endif const char *fq_record; int fd; #if defined(UNIX) || defined(VMS) fq_record = fqname(RECORD, SCOREPREFIX, 0); fd = open(fq_record, O_RDWR, 0); if (fd >= 0) { #ifdef VMS /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */ if (!file_is_stmlf(fd)) { raw_printf( "Warning: scoreboard file %s is not in stream_lf format", fq_record); wait_synch(); } #endif (void) nhclose(fd); /* RECORD is accessible */ } else if ((fd = open(fq_record, O_CREAT | O_RDWR, FCMASK)) >= 0) { (void) nhclose(fd); /* RECORD newly created */ #if defined(VMS) && !defined(SECURE) /* Re-protect RECORD with world:read+write+execute+delete access. */ (void) chmod(fq_record, FCMASK | 007); #endif /* VMS && !SECURE */ } else { raw_printf("Warning: cannot write scoreboard file %s", fq_record); wait_synch(); } #endif /* !UNIX && !VMS */ #if defined(MICRO) || defined(WIN32) char tmp[PATHLEN]; #ifdef OS2_CODEVIEW /* explicit path on opening for OS/2 */ /* how does this work when there isn't an explicit path or fopenp * for later access to the file via fopen_datafile? ? */ (void) strncpy(tmp, dir, PATHLEN - 1); tmp[PATHLEN - 1] = '\0'; if ((strlen(tmp) + 1 + strlen(RECORD)) < (PATHLEN - 1)) { append_slash(tmp); Strcat(tmp, RECORD); } fq_record = tmp; #else Strcpy(tmp, RECORD); fq_record = fqname(RECORD, SCOREPREFIX, 0); #endif if ((fd = open(fq_record, O_RDWR)) < 0) { /* try to create empty record */ #if defined(AZTEC_C) || defined(_DCC) \ || (defined(__GNUC__) && defined(__AMIGA__)) /* Aztec doesn't use the third argument */ /* DICE doesn't like it */ if ((fd = open(fq_record, O_CREAT | O_RDWR)) < 0) { #else if ((fd = open(fq_record, O_CREAT | O_RDWR, S_IREAD | S_IWRITE)) < 0) { #endif raw_printf("Warning: cannot write record %s", tmp); wait_synch(); } else (void) nhclose(fd); } else /* open succeeded */ (void) nhclose(fd); #else /* MICRO || WIN32*/ #ifdef MAC /* Create the "record" file, if necessary */ fq_record = fqname(RECORD, SCOREPREFIX, 0); fd = macopen(fq_record, O_RDWR | O_CREAT, TEXT_TYPE); if (fd != -1) macclose(fd); #endif /* MAC */ #endif /* MICRO || WIN32*/ } /* ---------- END SCOREBOARD CREATION ----------- */ /* ---------- BEGIN PANIC/IMPOSSIBLE LOG ----------- */ /*ARGSUSED*/ void paniclog(type, reason) const char *type; /* panic, impossible, trickery */ const char *reason; /* explanation */ { #ifdef PANICLOG FILE *lfile; char buf[BUFSZ]; if (!program_state.in_paniclog) { program_state.in_paniclog = 1; lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); if (lfile) { time_t now = getnow(); int uid = getuid(); char playmode = wizard ? 'D' : discover ? 'X' : '-'; (void) fprintf(lfile, "%s %08ld %06ld %d %c: %s %s\n", version_string(buf), yyyymmdd(now), hhmmss(now), uid, playmode, type, reason); (void) fclose(lfile); } program_state.in_paniclog = 0; } #endif /* PANICLOG */ return; } /* ---------- END PANIC/IMPOSSIBLE LOG ----------- */ #ifdef SELF_RECOVER /* ---------- BEGIN INTERNAL RECOVER ----------- */ boolean recover_savefile() { int gfd, lfd, sfd; int lev, savelev, hpid, pltmpsiz; xchar levc; struct version_info version_data; int processed[256]; char savename[SAVESIZE], errbuf[BUFSZ]; struct savefile_info sfi; char tmpplbuf[PL_NSIZ]; for (lev = 0; lev < 256; lev++) processed[lev] = 0; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created * savefile info * player name * and game state */ gfd = open_levelfile(0, errbuf); if (gfd < 0) { raw_printf("%s\n", errbuf); return FALSE; } if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { raw_printf("\n%s\n%s\n", "Checkpoint data incompletely written or subsequently clobbered.", "Recovery impossible."); (void) nhclose(gfd); return FALSE; } if (read(gfd, (genericptr_t) &savelev, sizeof(savelev)) != sizeof(savelev)) { raw_printf( "\nCheckpointing was not in effect for %s -- recovery impossible.\n", lock); (void) nhclose(gfd); return FALSE; } if ((read(gfd, (genericptr_t) savename, sizeof savename) != sizeof savename) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) || (read(gfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)) { raw_printf("\nError reading %s -- can't recover.\n", lock); (void) nhclose(gfd); return FALSE; } /* save file should contain: * version info * savefile info * player name * current level (including pets) * (non-level-based) game state * other levels */ set_savefile_name(TRUE); sfd = create_savefile(); if (sfd < 0) { raw_printf("\nCannot recover savefile %s.\n", SAVEF); (void) nhclose(gfd); return FALSE; } lfd = open_levelfile(savelev, errbuf); if (lfd < 0) { raw_printf("\n%s\n", errbuf); (void) nhclose(gfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } if (write(sfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) { raw_printf("\nError writing %s; recovery failed.", SAVEF); (void) nhclose(gfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) { raw_printf("\nError writing %s; recovery failed (savefile_info).\n", SAVEF); (void) nhclose(gfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) { raw_printf("Error writing %s; recovery failed (player name size).\n", SAVEF); (void) nhclose(gfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } if (write(sfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) { raw_printf("Error writing %s; recovery failed (player name).\n", SAVEF); (void) nhclose(gfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } if (!copy_bytes(lfd, sfd)) { (void) nhclose(lfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } (void) nhclose(lfd); processed[savelev] = 1; if (!copy_bytes(gfd, sfd)) { (void) nhclose(lfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } (void) nhclose(gfd); processed[0] = 1; for (lev = 1; lev < 256; lev++) { /* level numbers are kept in xchars in save.c, so the * maximum level number (for the endlevel) must be < 256 */ if (lev != savelev) { lfd = open_levelfile(lev, (char *) 0); if (lfd >= 0) { /* any or all of these may not exist */ levc = (xchar) lev; write(sfd, (genericptr_t) &levc, sizeof(levc)); if (!copy_bytes(lfd, sfd)) { (void) nhclose(lfd); (void) nhclose(sfd); delete_savefile(); return FALSE; } (void) nhclose(lfd); processed[lev] = 1; } } } (void) nhclose(sfd); #ifdef HOLD_LOCKFILE_OPEN really_close(); #endif /* * We have a successful savefile! * Only now do we erase the level files. */ for (lev = 0; lev < 256; lev++) { if (processed[lev]) { const char *fq_lock; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 3); (void) unlink(fq_lock); } } return TRUE; } boolean copy_bytes(ifd, ofd) int ifd, ofd; { char buf[BUFSIZ]; int nfrom, nto; do { nfrom = read(ifd, buf, BUFSIZ); nto = write(ofd, buf, nfrom); if (nto != nfrom) return FALSE; } while (nfrom == BUFSIZ); return TRUE; } /* ---------- END INTERNAL RECOVER ----------- */ #endif /*SELF_RECOVER*/ /* ---------- OTHER ----------- */ #ifdef SYSCF #ifdef SYSCF_FILE void assure_syscf_file() { int fd; /* * All we really care about is the end result - can we read the file? * So just check that directly. * * Not tested on most of the old platforms (which don't attempt * to implement SYSCF). * Some ports don't like open()'s optional third argument; * VMS overrides open() usage with a macro which requires it. */ #ifndef VMS fd = open(SYSCF_FILE, O_RDONLY); #else fd = open(SYSCF_FILE, O_RDONLY, 0); #endif if (fd >= 0) { /* readable */ close(fd); return; } raw_printf("Unable to open SYSCF_FILE.\n"); exit(EXIT_FAILURE); } #endif /* SYSCF_FILE */ #endif /* SYSCF */ #ifdef DEBUG /* used by debugpline() to decide whether to issue a message * from a particular source file; caller passes __FILE__ and we check * whether it is in the source file list supplied by SYSCF's DEBUGFILES * * pass FALSE to override wildcard matching; useful for files * like dungeon.c and questpgr.c, which generate a ridiculous amount of * output if DEBUG is defined and effectively block the use of a wildcard */ boolean debugcore(filename, wildcards) const char *filename; boolean wildcards; { const char *debugfiles, *p; if (!filename || !*filename) return FALSE; /* sanity precaution */ if (sysopt.env_dbgfl == 0) { /* check once for DEBUGFILES in the environment; if found, it supersedes the sysconf value [note: getenv() rather than nh_getenv() since a long value is valid and doesn't pose any sort of overflow risk here] */ if ((p = getenv("DEBUGFILES")) != 0) { if (sysopt.debugfiles) free((genericptr_t) sysopt.debugfiles); sysopt.debugfiles = dupstr(p); sysopt.env_dbgfl = 1; } else sysopt.env_dbgfl = -1; } debugfiles = sysopt.debugfiles; /* usual case: sysopt.debugfiles will be empty */ if (!debugfiles || !*debugfiles) return FALSE; /* strip filename's path if present */ #ifdef UNIX if ((p = rindex(filename, '/')) != 0) filename = p + 1; #endif #ifdef VMS filename = vms_basename(filename); /* vms_basename strips off 'type' suffix as well as path and version; we want to put suffix back (".c" assumed); since it always returns a pointer to a static buffer, we can safely modify its result */ Strcat((char *) filename, ".c"); #endif /* * Wildcard match will only work if there's a single pattern (which * might be a single file name without any wildcarding) rather than * a space-separated list. * [to NOT do: We could step through the space-separated list and * attempt a wildcard match against each element, but that would be * overkill for the intended usage.] */ if (wildcards && pmatch(debugfiles, filename)) return TRUE; /* check whether filename is an element of the list */ if ((p = strstr(debugfiles, filename)) != 0) { int l = (int) strlen(filename); if ((p == debugfiles || p[-1] == ' ' || p[-1] == '/') && (p[l] == ' ' || p[l] == '\0')) return TRUE; } return FALSE; } #endif /*DEBUG*/ /* ---------- BEGIN TRIBUTE ----------- */ /* 3.6 tribute code */ #define SECTIONSCOPE 1 #define TITLESCOPE 2 #define PASSAGESCOPE 3 #define MAXPASSAGES SIZE(context.novel.pasg) /* 30 */ static int FDECL(choose_passage, (int, unsigned)); /* choose a random passage that hasn't been chosen yet; once all have been chosen, reset the tracking to make all passages available again */ static int choose_passage(passagecnt, oid) int passagecnt; /* total of available passages, 1..MAXPASSAGES */ unsigned oid; /* book.o_id, used to determine whether re-reading same book */ { int idx, res; if (passagecnt < 1) return 0; if (passagecnt > MAXPASSAGES) passagecnt = MAXPASSAGES; /* if a different book or we've used up all the passages already, reset in order to have all 'passagecnt' passages available */ if (oid != context.novel.id || context.novel.count == 0) { context.novel.id = oid; context.novel.count = passagecnt; for (idx = 0; idx < MAXPASSAGES; idx++) context.novel.pasg[idx] = (xchar) ((idx < passagecnt) ? idx + 1 : 0); } idx = rn2(context.novel.count); res = (int) context.novel.pasg[idx]; /* move the last slot's passage index into the slot just used and reduce the number of passages available */ context.novel.pasg[idx] = context.novel.pasg[--context.novel.count]; return res; } /* Returns True if you were able to read something. */ boolean read_tribute(tribsection, tribtitle, tribpassage, nowin_buf, bufsz, oid) const char *tribsection, *tribtitle; int tribpassage, bufsz; char *nowin_buf; unsigned oid; /* book identifier */ { dlb *fp; char *endp; char line[BUFSZ], lastline[BUFSZ]; int scope = 0; int linect = 0, passagecnt = 0, targetpassage = 0; const char *badtranslation = "an incomprehensible foreign translation"; boolean matchedsection = FALSE, matchedtitle = FALSE; winid tribwin = WIN_ERR; boolean grasped = FALSE; boolean foundpassage = FALSE; /* check for mandatories */ if (!tribsection || !tribtitle) { if (!nowin_buf) pline("It's %s of \"%s\"!", badtranslation, tribtitle); return grasped; } debugpline3("read_tribute %s, %s, %d.", tribsection, tribtitle, tribpassage); fp = dlb_fopen(TRIBUTEFILE, "r"); if (!fp) { /* this is actually an error - cannot open tribute file! */ if (!nowin_buf) pline("You feel too overwhelmed to continue!"); return grasped; } /* * Syntax (not case-sensitive): * %section books * * In the books section: * %title booktitle (n) * where booktitle=book title without quotes * (n)= total number of passages present for this title * %passage k * where k=sequential passage number * * %e ends the passage/book/section * If in a passage, it marks the end of that passage. * If in a book, it marks the end of that book. * If in a section, it marks the end of that section. * * %section death */ *line = *lastline = '\0'; while (dlb_fgets(line, sizeof line, fp) != 0) { linect++; if ((endp = index(line, '\n')) != 0) *endp = 0; switch (line[0]) { case '%': if (!strncmpi(&line[1], "section ", sizeof("section ") - 1)) { char *st = &line[9]; /* 9 from "%section " */ scope = SECTIONSCOPE; if (!strcmpi(st, tribsection)) matchedsection = TRUE; else matchedsection = FALSE; } else if (!strncmpi(&line[1], "title ", sizeof("title ") - 1)) { char *st = &line[7]; /* 7 from "%title " */ char *p1, *p2; if ((p1 = index(st, '(')) != 0) { *p1++ = '\0'; (void) mungspaces(st); if ((p2 = index(p1, ')')) != 0) { *p2 = '\0'; passagecnt = atoi(p1); if (passagecnt > MAXPASSAGES) passagecnt = MAXPASSAGES; scope = TITLESCOPE; if (matchedsection && !strcmpi(st, tribtitle)) { matchedtitle = TRUE; targetpassage = !tribpassage ? choose_passage(passagecnt, oid) : (tribpassage <= passagecnt) ? tribpassage : 0; } else { matchedtitle = FALSE; } } } } else if (!strncmpi(&line[1], "passage ", sizeof("passage ") - 1)) { int passagenum = 0; char *st = &line[9]; /* 9 from "%passage " */ while (*st == ' ' || *st == '\t') st++; if (*st && digit(*st) && (strlen(st) < 3)) passagenum = atoi(st); if (passagenum && (passagenum <= passagecnt)) { scope = PASSAGESCOPE; if (matchedtitle && (passagenum == targetpassage)) { if (!nowin_buf) tribwin = create_nhwindow(NHW_MENU); else foundpassage = TRUE; } } } else if (!strncmpi(&line[1], "e ", sizeof("e ") - 1)) { if (matchedtitle && scope == PASSAGESCOPE && ((!nowin_buf && tribwin != WIN_ERR) || (nowin_buf && foundpassage))) goto cleanup; if (scope == TITLESCOPE) matchedtitle = FALSE; if (scope == SECTIONSCOPE) matchedsection = FALSE; if (scope) --scope; } else { debugpline1("tribute file error: bad %% command, line %d.", linect); } break; case '#': /* comment only, next! */ break; default: if (matchedtitle && scope == PASSAGESCOPE) { if (!nowin_buf && tribwin != WIN_ERR) { putstr(tribwin, 0, line); Strcpy(lastline, line); } else if (nowin_buf) { if ((int) strlen(line) < bufsz - 1) Strcpy(nowin_buf, line); } } } } cleanup: (void) dlb_fclose(fp); if (!nowin_buf && tribwin != WIN_ERR) { if (matchedtitle && scope == PASSAGESCOPE) { display_nhwindow(tribwin, FALSE); /* put the final attribution line into message history, analogous to the summary line from long quest messages */ if (index(lastline, '[')) mungspaces(lastline); /* to remove leading spaces */ else /* construct one if necessary */ Sprintf(lastline, "[%s, by Terry Pratchett]", tribtitle); putmsghistory(lastline, FALSE); } destroy_nhwindow(tribwin); tribwin = WIN_ERR; grasped = TRUE; } else { if (!nowin_buf) pline("It seems to be %s of \"%s\"!", badtranslation, tribtitle); else if (foundpassage) grasped = TRUE; } return grasped; } boolean Death_quote(buf, bufsz) char *buf; int bufsz; { unsigned death_oid = 1; /* chance of oid #1 being a novel is negligible */ return read_tribute("Death", "Death Quotes", 0, buf, bufsz, death_oid); } /* ---------- END TRIBUTE ----------- */ /*files.c*/ nethack-3.6.0/src/fountain.c0000664000076400007660000004551612610073562014730 0ustar paxedpaxed/* NetHack 3.6 fountain.c $NHDT-Date: 1444937416 2015/10/15 19:30:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.55 $ */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* NetHack may be freely redistributed. See license for details. */ /* Code for drinking from fountains. */ #include "hack.h" STATIC_DCL void NDECL(dowatersnakes); STATIC_DCL void NDECL(dowaterdemon); STATIC_DCL void NDECL(dowaternymph); STATIC_PTR void FDECL(gush, (int, int, genericptr_t)); STATIC_DCL void NDECL(dofindgem); /* used when trying to dip in or drink from fountain or sink or pool while levitating above it, or when trying to move downwards in that state */ void floating_above(what) const char *what; { const char *umsg = "are floating high above the %s."; if (u.utrap && (u.utraptype == TT_INFLOOR || u.utraptype == TT_LAVA)) { /* when stuck in floor (not possible at fountain or sink location, so must be attempting to move down), override the usual message */ umsg = "are trapped in the %s."; what = surface(u.ux, u.uy); /* probably redundant */ } You(umsg, what); } /* Fountain of snakes! */ STATIC_OVL void dowatersnakes() { register int num = rn1(5, 2); struct monst *mtmp; if (!(mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) { if (!Blind) pline("An endless stream of %s pours forth!", Hallucination ? makeplural(rndmonnam(NULL)) : "snakes"); else You_hear("%s hissing!", something); while (num-- > 0) if ((mtmp = makemon(&mons[PM_WATER_MOCCASIN], u.ux, u.uy, NO_MM_FLAGS)) != 0 && t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } else pline_The("fountain bubbles furiously for a moment, then calms."); } /* Water demon */ STATIC_OVL void dowaterdemon() { struct monst *mtmp; if (!(mvitals[PM_WATER_DEMON].mvflags & G_GONE)) { if ((mtmp = makemon(&mons[PM_WATER_DEMON], u.ux, u.uy, NO_MM_FLAGS)) != 0) { if (!Blind) You("unleash %s!", a_monnam(mtmp)); else You_feel("the presence of evil."); /* Give those on low levels a (slightly) better chance of survival */ if (rnd(100) > (80 + level_difficulty())) { pline("Grateful for %s release, %s grants you a wish!", mhis(mtmp), mhe(mtmp)); /* give a wish and discard the monster (mtmp set to null) */ mongrantswish(&mtmp); } else if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } } else pline_The("fountain bubbles furiously for a moment, then calms."); } /* Water Nymph */ STATIC_OVL void dowaternymph() { register struct monst *mtmp; if (!(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) && (mtmp = makemon(&mons[PM_WATER_NYMPH], u.ux, u.uy, NO_MM_FLAGS)) != 0) { if (!Blind) You("attract %s!", a_monnam(mtmp)); else You_hear("a seductive voice."); mtmp->msleeping = 0; if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } else if (!Blind) pline("A large bubble rises to the surface and pops."); else You_hear("a loud pop."); } /* Gushing forth along LOS from (u.ux, u.uy) */ void dogushforth(drinking) int drinking; { int madepool = 0; do_clear_area(u.ux, u.uy, 7, gush, (genericptr_t) &madepool); if (!madepool) { if (drinking) Your("thirst is quenched."); else pline("Water sprays all over you."); } } STATIC_PTR void gush(x, y, poolcnt) int x, y; genericptr_t poolcnt; { register struct monst *mtmp; register struct trap *ttmp; if (((x + y) % 2) || (x == u.ux && y == u.uy) || (rn2(1 + distmin(u.ux, u.uy, x, y))) || (levl[x][y].typ != ROOM) || (sobj_at(BOULDER, x, y)) || nexttodoor(x, y)) return; if ((ttmp = t_at(x, y)) != 0 && !delfloortrap(ttmp)) return; if (!((*(int *) poolcnt)++)) pline("Water gushes forth from the overflowing fountain!"); /* Put a pool at x, y */ levl[x][y].typ = POOL; /* No kelp! */ del_engr_at(x, y); water_damage_chain(level.objects[x][y], TRUE); if ((mtmp = m_at(x, y)) != 0) (void) minliquid(mtmp); else newsym(x, y); } /* Find a gem in the sparkling waters. */ STATIC_OVL void dofindgem() { if (!Blind) You("spot a gem in the sparkling waters!"); else You_feel("a gem here!"); (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE - 1), u.ux, u.uy, FALSE, FALSE); SET_FOUNTAIN_LOOTED(u.ux, u.uy); newsym(u.ux, u.uy); exercise(A_WIS, TRUE); /* a discovery! */ } void dryup(x, y, isyou) xchar x, y; boolean isyou; { if (IS_FOUNTAIN(levl[x][y].typ) && (!rn2(3) || FOUNTAIN_IS_WARNED(x, y))) { if (isyou && in_town(x, y) && !FOUNTAIN_IS_WARNED(x, y)) { struct monst *mtmp; SET_FOUNTAIN_WARNED(x, y); /* Warn about future fountain use. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { pline("%s yells:", Amonnam(mtmp)); verbalize("Hey, stop using that fountain!"); break; } } /* You can see or hear this effect */ if (!mtmp) pline_The("flow reduces to a trickle."); return; } if (isyou && wizard) { if (yn("Dry up fountain?") == 'n') return; } /* replace the fountain with ordinary floor */ levl[x][y].typ = ROOM; levl[x][y].looted = 0; levl[x][y].blessedftn = 0; if (cansee(x, y)) pline_The("fountain dries up!"); /* The location is seen if the hero/monster is invisible or felt if the hero is blind. */ newsym(x, y); level.flags.nfountains--; if (isyou && in_town(x, y)) (void) angry_guards(FALSE); } } void drinkfountain() { /* What happens when you drink from a fountain? */ register boolean mgkftn = (levl[u.ux][u.uy].blessedftn == 1); register int fate = rnd(30); if (Levitation) { floating_above("fountain"); return; } if (mgkftn && u.uluck >= 0 && fate >= 10) { int i, ii, littleluck = (u.uluck < 4); pline("Wow! This makes you feel great!"); /* blessed restore ability */ for (ii = 0; ii < A_MAX; ii++) if (ABASE(ii) < AMAX(ii)) { ABASE(ii) = AMAX(ii); context.botl = 1; } /* gain ability, blessed if "natural" luck is high */ i = rn2(A_MAX); /* start at a random attribute */ for (ii = 0; ii < A_MAX; ii++) { if (adjattrib(i, 1, littleluck ? -1 : 0) && littleluck) break; if (++i >= A_MAX) i = 0; } display_nhwindow(WIN_MESSAGE, FALSE); pline("A wisp of vapor escapes the fountain..."); exercise(A_WIS, TRUE); levl[u.ux][u.uy].blessedftn = 0; return; } if (fate < 10) { pline_The("cool draught refreshes you."); u.uhunger += rnd(10); /* don't choke on water */ newuhs(FALSE); if (mgkftn) return; } else { switch (fate) { case 19: /* Self-knowledge */ You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); exercise(A_WIS, TRUE); pline_The("feeling subsides."); break; case 20: /* Foul water */ pline_The("water is foul! You gag and vomit."); morehungry(rn1(20, 11)); vomit(); break; case 21: /* Poisonous */ pline_The("water is contaminated!"); if (Poison_resistance) { pline("Perhaps it is runoff from the nearby %s farm.", fruitname(FALSE)); losehp(rnd(4), "unrefrigerated sip of juice", KILLED_BY_AN); break; } losestr(rn1(4, 3)); losehp(rnd(10), "contaminated water", KILLED_BY); exercise(A_CON, FALSE); break; case 22: /* Fountain of snakes! */ dowatersnakes(); break; case 23: /* Water demon */ dowaterdemon(); break; case 24: /* Curse an item */ { register struct obj *obj; pline("This water's no good!"); morehungry(rn1(20, 11)); exercise(A_CON, FALSE); for (obj = invent; obj; obj = obj->nobj) if (!rn2(5)) curse(obj); break; } case 25: /* See invisible */ if (Blind) { if (Invisible) { You("feel transparent."); } else { You("feel very self-conscious."); pline("Then it passes."); } } else { You_see("an image of someone stalking you."); pline("But it disappears."); } HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); exercise(A_WIS, TRUE); break; case 26: /* See Monsters */ (void) monster_detect((struct obj *) 0, 0); exercise(A_WIS, TRUE); break; case 27: /* Find a gem in the sparkling waters. */ if (!FOUNTAIN_IS_LOOTED(u.ux, u.uy)) { dofindgem(); break; } case 28: /* Water Nymph */ dowaternymph(); break; case 29: /* Scare */ { register struct monst *mtmp; pline("This water gives you bad breath!"); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; monflee(mtmp, 0, FALSE, FALSE); } break; } case 30: /* Gushing forth in this room */ dogushforth(TRUE); break; default: pline("This tepid water is tasteless."); break; } } dryup(u.ux, u.uy, TRUE); } void dipfountain(obj) register struct obj *obj; { if (Levitation) { floating_above("fountain"); return; } /* Don't grant Excalibur when there's more than one object. */ /* (quantity could be > 1 if merged daggers got polymorphed) */ if (obj->otyp == LONG_SWORD && obj->quan == 1L && u.ulevel >= 5 && !rn2(6) && !obj->oartifact && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) { if (u.ualign.type != A_LAWFUL) { /* Ha! Trying to cheat her. */ pline( "A freezing mist rises from the water and envelopes the sword."); pline_The("fountain disappears!"); curse(obj); if (obj->spe > -6 && !rn2(3)) obj->spe--; obj->oerodeproof = FALSE; exercise(A_WIS, FALSE); } else { /* The lady of the lake acts! - Eric Backus */ /* Be *REAL* nice */ pline( "From the murky depths, a hand reaches up to bless the sword."); pline("As the hand retreats, the fountain disappears!"); obj = oname(obj, artiname(ART_EXCALIBUR)); discover_artifact(ART_EXCALIBUR); bless(obj); obj->oeroded = obj->oeroded2 = 0; obj->oerodeproof = TRUE; exercise(A_WIS, TRUE); } update_inventory(); levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].looted = 0; newsym(u.ux, u.uy); level.flags.nfountains--; if (in_town(u.ux, u.uy)) (void) angry_guards(FALSE); return; } else { int er = water_damage(obj, NULL, TRUE); if (obj->otyp == POT_ACID && er != ER_DESTROYED) { /* Acid and water don't mix */ useup(obj); return; } else if (er != ER_NOTHING && !rn2(2)) { /* no further effect */ return; } } switch (rnd(30)) { case 16: /* Curse the item */ curse(obj); break; case 17: case 18: case 19: case 20: /* Uncurse the item */ if (obj->cursed) { if (!Blind) pline_The("water glows for a moment."); uncurse(obj); } else { pline("A feeling of loss comes over you."); } break; case 21: /* Water Demon */ dowaterdemon(); break; case 22: /* Water Nymph */ dowaternymph(); break; case 23: /* an Endless Stream of Snakes */ dowatersnakes(); break; case 24: /* Find a gem */ if (!FOUNTAIN_IS_LOOTED(u.ux, u.uy)) { dofindgem(); break; } case 25: /* Water gushes forth */ dogushforth(FALSE); break; case 26: /* Strange feeling */ pline("A strange tingling runs up your %s.", body_part(ARM)); break; case 27: /* Strange feeling */ You_feel("a sudden chill."); break; case 28: /* Strange feeling */ pline("An urge to take a bath overwhelms you."); { long money = money_cnt(invent); struct obj *otmp; if (money > 10) { /* Amount to lose. Might get rounded up as fountains don't * pay change... */ money = somegold(money) / 10; for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) { int denomination = objects[otmp->otyp].oc_cost; long coin_loss = (money + denomination - 1) / denomination; coin_loss = min(coin_loss, otmp->quan); otmp->quan -= coin_loss; money -= coin_loss * denomination; if (!otmp->quan) delobj(otmp); } You("lost some of your money in the fountain!"); CLEAR_FOUNTAIN_LOOTED(u.ux, u.uy); exercise(A_WIS, FALSE); } } break; case 29: /* You see coins */ /* We make fountains have more coins the closer you are to the * surface. After all, there will have been more people going * by. Just like a shopping mall! Chris Woodbury */ if (FOUNTAIN_IS_LOOTED(u.ux, u.uy)) break; SET_FOUNTAIN_LOOTED(u.ux, u.uy); (void) mkgold((long) (rnd((dunlevs_in_dungeon(&u.uz) - dunlev(&u.uz) + 1) * 2) + 5), u.ux, u.uy); if (!Blind) pline("Far below you, you see coins glistening in the water."); exercise(A_WIS, TRUE); newsym(u.ux, u.uy); break; } update_inventory(); dryup(u.ux, u.uy, TRUE); } void breaksink(x, y) int x, y; { if (cansee(x, y) || (x == u.ux && y == u.uy)) pline_The("pipes break! Water spurts out!"); level.flags.nsinks--; levl[x][y].doormask = 0; levl[x][y].typ = FOUNTAIN; level.flags.nfountains++; newsym(x, y); } void drinksink() { struct obj *otmp; struct monst *mtmp; if (Levitation) { floating_above("sink"); return; } switch (rn2(20)) { case 0: You("take a sip of very cold water."); break; case 1: You("take a sip of very warm water."); break; case 2: You("take a sip of scalding hot water."); if (Fire_resistance) pline("It seems quite tasty."); else losehp(rnd(6), "sipping boiling water", KILLED_BY); /* boiling water burns considered fire damage */ break; case 3: if (mvitals[PM_SEWER_RAT].mvflags & G_GONE) pline_The("sink seems quite dirty."); else { mtmp = makemon(&mons[PM_SEWER_RAT], u.ux, u.uy, NO_MM_FLAGS); if (mtmp) pline("Eek! There's %s in the sink!", (Blind || !canspotmon(mtmp)) ? "something squirmy" : a_monnam(mtmp)); } break; case 4: do { otmp = mkobj(POTION_CLASS, FALSE); if (otmp->otyp == POT_WATER) { obfree(otmp, (struct obj *) 0); otmp = (struct obj *) 0; } } while (!otmp); otmp->cursed = otmp->blessed = 0; pline("Some %s liquid flows from the faucet.", Blind ? "odd" : hcolor(OBJ_DESCR(objects[otmp->otyp]))); otmp->dknown = !(Blind || Hallucination); otmp->quan++; /* Avoid panic upon useup() */ otmp->fromsink = 1; /* kludge for docall() */ (void) dopotion(otmp); obfree(otmp, (struct obj *) 0); break; case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) { You("find a ring in the sink!"); (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE); levl[u.ux][u.uy].looted |= S_LRING; exercise(A_WIS, TRUE); newsym(u.ux, u.uy); } else pline("Some dirty water backs up in the drain."); break; case 6: breaksink(u.ux, u.uy); break; case 7: pline_The("water moves as though of its own will!"); if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE) || !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, NO_MM_FLAGS)) pline("But it quiets down."); break; case 8: pline("Yuk, this water tastes awful."); more_experienced(1, 0); newexplevel(); break; case 9: pline("Gaggg... this tastes like sewage! You vomit."); morehungry(rn1(30 - ACURR(A_CON), 11)); vomit(); break; case 10: pline("This water contains toxic wastes!"); if (!Unchanging) { You("undergo a freakish metamorphosis!"); polyself(0); } break; /* more odd messages --JJB */ case 11: You_hear("clanking from the pipes..."); break; case 12: You_hear("snatches of song from among the sewers..."); break; case 19: if (Hallucination) { pline("From the murky drain, a hand reaches up... --oops--"); break; } default: You("take a sip of %s water.", rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot"); } } /*fountain.c*/ nethack-3.6.0/src/hack.c0000664000076400007660000027402212625266426014020 0ustar paxedpaxed/* NetHack 3.6 hack.c $NHDT-Date: 1446604111 2015/11/04 02:28:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.155 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* #define DEBUG */ /* uncomment for debugging */ STATIC_DCL void NDECL(maybe_wail); STATIC_DCL int NDECL(moverock); STATIC_DCL int FDECL(still_chewing, (XCHAR_P, XCHAR_P)); STATIC_DCL void NDECL(dosinkfall); STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P)); STATIC_DCL boolean FDECL(trapmove, (int, int, struct trap *)); STATIC_DCL void NDECL(switch_terrain); STATIC_DCL struct monst *FDECL(monstinroom, (struct permonst *, int)); STATIC_DCL boolean FDECL(doorless_door, (int, int)); STATIC_DCL void FDECL(move_update, (BOOLEAN_P)); #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE) static anything tmp_anything; anything * uint_to_any(ui) unsigned ui; { tmp_anything = zeroany; tmp_anything.a_uint = ui; return &tmp_anything; } anything * long_to_any(lng) long lng; { tmp_anything = zeroany; tmp_anything.a_long = lng; return &tmp_anything; } anything * monst_to_any(mtmp) struct monst *mtmp; { tmp_anything = zeroany; tmp_anything.a_monst = mtmp; return &tmp_anything; } anything * obj_to_any(obj) struct obj *obj; { tmp_anything = zeroany; tmp_anything.a_obj = obj; return &tmp_anything; } boolean revive_nasty(x, y, msg) int x, y; const char *msg; { register struct obj *otmp, *otmp2; struct monst *mtmp; coord cc; boolean revived = FALSE; for (otmp = level.objects[x][y]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp->otyp == CORPSE && (is_rider(&mons[otmp->corpsenm]) || otmp->corpsenm == PM_WIZARD_OF_YENDOR)) { /* move any living monster already at that location */ if ((mtmp = m_at(x, y)) && enexto(&cc, x, y, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); if (msg) Norep("%s", msg); revived = revive_corpse(otmp); } } /* this location might not be safe, if not, move revived monster */ if (revived) { mtmp = m_at(x, y); if (mtmp && !goodpos(x, y, mtmp, 0) && enexto(&cc, x, y, mtmp->data)) { rloc_to(mtmp, cc.x, cc.y); } /* else impossible? */ } return revived; } STATIC_OVL int moverock() { register xchar rx, ry, sx, sy; register struct obj *otmp; register struct trap *ttmp; register struct monst *mtmp; sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */ while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { /* make sure that this boulder is visible as the top object */ if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy); rx = u.ux + 2 * u.dx; /* boulder destination position */ ry = u.uy + 2 * u.dy; nomul(0); if (Levitation || Is_airlevel(&u.uz)) { if (Blind) feel_location(sx, sy); You("don't have enough leverage to push %s.", the(xname(otmp))); /* Give them a chance to climb over it? */ return -1; } if (verysmall(youmonst.data) && !u.usteed) { if (Blind) feel_location(sx, sy); pline("You're too small to push that %s.", xname(otmp)); goto cannot_push; } if (isok(rx, ry) && !IS_ROCK(levl[rx][ry].typ) && levl[rx][ry].typ != IRONBARS && (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || doorless_door(rx, ry)) && !sobj_at(BOULDER, rx, ry)) { ttmp = t_at(rx, ry); mtmp = m_at(rx, ry); /* KMH -- Sokoban doesn't let you push boulders diagonally */ if (Sokoban && u.dx && u.dy) { if (Blind) feel_location(sx, sy); pline("%s won't roll diagonally on this %s.", The(xname(otmp)), surface(sx, sy)); goto cannot_push; } if (revive_nasty(rx, ry, "You sense movement on the other side.")) return -1; if (mtmp && !noncorporeal(mtmp->data) && (!mtmp->mtrapped || !(ttmp && ((ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT))))) { if (Blind) feel_location(sx, sy); if (canspotmon(mtmp)) pline("There's %s on the other side.", a_monnam(mtmp)); else { You_hear("a monster behind %s.", the(xname(otmp))); map_invisible(rx, ry); } if (flags.verbose) pline("Perhaps that's why %s cannot move it.", u.usteed ? y_monnam(u.usteed) : "you"); goto cannot_push; } if (ttmp) { /* if a trap operates on the boulder, don't attempt to move any others at this location; return -1 if another boulder is in hero's way, or 0 if he should advance to the vacated boulder position */ switch (ttmp->ttyp) { case LANDMINE: if (rn2(10)) { obj_extract_self(otmp); place_object(otmp, rx, ry); newsym(sx, sy); pline("KAABLAMM!!! %s %s land mine.", Tobjnam(otmp, "trigger"), ttmp->madeby_u ? "your" : "a"); blow_up_landmine(ttmp); /* if the boulder remains, it should fill the pit */ fill_pit(u.ux, u.uy); if (cansee(rx, ry)) newsym(rx, ry); return sobj_at(BOULDER, sx, sy) ? -1 : 0; } break; case SPIKED_PIT: case PIT: obj_extract_self(otmp); /* vision kludge to get messages right; the pit will temporarily be seen even if this is one among multiple boulders */ if (!Blind) viz_array[ry][rx] |= IN_SIGHT; if (!flooreffects(otmp, rx, ry, "fall")) { place_object(otmp, rx, ry); } if (mtmp && !Blind) newsym(rx, ry); return sobj_at(BOULDER, sx, sy) ? -1 : 0; case HOLE: case TRAPDOOR: if (Blind) pline("Kerplunk! You no longer feel %s.", the(xname(otmp))); else pline("%s%s and %s a %s in the %s!", Tobjnam(otmp, (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"), (ttmp->ttyp == TRAPDOOR) ? "" : " into", otense(otmp, "plug"), (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole", surface(rx, ry)); deltrap(ttmp); delobj(otmp); bury_objs(rx, ry); levl[rx][ry].wall_info &= ~W_NONDIGGABLE; levl[rx][ry].candig = 1; if (cansee(rx, ry)) newsym(rx, ry); return sobj_at(BOULDER, sx, sy) ? -1 : 0; case LEVEL_TELEP: case TELEP_TRAP: { int newlev = 0; /* lint suppression */ d_level dest; if (ttmp->ttyp == LEVEL_TELEP) { newlev = random_teleport_level(); if (newlev == depth(&u.uz) || In_endgame(&u.uz)) /* trap didn't work; skip "disappears" message */ goto dopush; } if (u.usteed) pline("%s pushes %s and suddenly it disappears!", upstart(y_monnam(u.usteed)), the(xname(otmp))); else You("push %s and suddenly it disappears!", the(xname(otmp))); if (ttmp->ttyp == TELEP_TRAP) { (void) rloco(otmp); } else { obj_extract_self(otmp); add_to_migration(otmp); get_level(&dest, newlev); otmp->ox = dest.dnum; otmp->oy = dest.dlevel; otmp->owornmask = (long) MIGR_RANDOM; } seetrap(ttmp); return sobj_at(BOULDER, sx, sy) ? -1 : 0; } default: break; /* boulder not affected by this trap */ } } if (closed_door(rx, ry)) goto nopushmsg; if (boulder_hits_pool(otmp, rx, ry, TRUE)) continue; /* * Re-link at top of fobj chain so that pile order is preserved * when level is restored. */ if (otmp != fobj) { remove_object(otmp); place_object(otmp, otmp->ox, otmp->oy); } { #ifdef LINT /* static long lastmovetime; */ long lastmovetime; lastmovetime = 0; #else /* note: reset to zero after save/restore cycle */ static NEARDATA long lastmovetime; #endif dopush: if (!u.usteed) { if (moves > lastmovetime + 2 || moves < lastmovetime) pline("With %s effort you move %s.", throws_rocks(youmonst.data) ? "little" : "great", the(xname(otmp))); exercise(A_STR, TRUE); } else pline("%s moves %s.", upstart(y_monnam(u.usteed)), the(xname(otmp))); lastmovetime = moves; } /* Move the boulder *after* the message. */ if (glyph_is_invisible(levl[rx][ry].glyph)) unmap_object(rx, ry); movobj(otmp, rx, ry); /* does newsym(rx,ry) */ if (Blind) { feel_location(rx, ry); feel_location(sx, sy); } else { newsym(sx, sy); } } else { nopushmsg: if (u.usteed) pline("%s tries to move %s, but cannot.", upstart(y_monnam(u.usteed)), the(xname(otmp))); else You("try to move %s, but in vain.", the(xname(otmp))); if (Blind) feel_location(sx, sy); cannot_push: if (throws_rocks(youmonst.data)) { if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { You("aren't skilled enough to %s %s from %s.", (flags.pickup && !Sokoban) ? "pick up" : "push aside", the(xname(otmp)), y_monnam(u.usteed)); } else { pline("However, you can easily %s.", (flags.pickup && !Sokoban) ? "pick it up" : "push it aside"); sokoban_guilt(); break; } break; } if (!u.usteed && (((!invent || inv_weight() <= -850) && (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ) && IS_ROCK(levl[sx][u.uy].typ)))) || verysmall(youmonst.data))) { pline( "However, you can squeeze yourself into a small opening."); sokoban_guilt(); break; } else return -1; } } return 0; } /* * still_chewing() * * Chew on a wall, door, or boulder. Returns TRUE if still eating, FALSE * when done. */ STATIC_OVL int still_chewing(x, y) xchar x, y; { struct rm *lev = &levl[x][y]; struct obj *boulder = sobj_at(BOULDER, x, y); const char *digtxt = (char *) 0, *dmgtxt = (char *) 0; if (context.digging.down) /* not continuing previous dig (w/ pick-axe) */ (void) memset((genericptr_t) &context.digging, 0, sizeof(struct dig_info)); if (!boulder && IS_ROCK(lev->typ) && !may_dig(x, y)) { You("hurt your teeth on the %s.", (lev->typ == IRONBARS) ? "bars" : IS_TREE(lev->typ) ? "tree" : "hard stone"); nomul(0); return 1; } else if (context.digging.pos.x != x || context.digging.pos.y != y || !on_level(&context.digging.level, &u.uz)) { context.digging.down = FALSE; context.digging.chew = TRUE; context.digging.warned = FALSE; context.digging.pos.x = x; context.digging.pos.y = y; assign_level(&context.digging.level, &u.uz); /* solid rock takes more work & time to dig through */ context.digging.effort = (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; You("start chewing %s %s.", (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS) ? "on a" : "a hole in the", boulder ? "boulder" : IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : lev->typ == IRONBARS ? "bar" : "door"); watch_dig((struct monst *) 0, x, y, FALSE); return 1; } else if ((context.digging.effort += (30 + u.udaminc)) <= 100) { if (flags.verbose) You("%s chewing on the %s.", context.digging.chew ? "continue" : "begin", boulder ? "boulder" : IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : (lev->typ == IRONBARS) ? "bars" : "door"); context.digging.chew = TRUE; watch_dig((struct monst *) 0, x, y, FALSE); return 1; } /* Okay, you've chewed through something */ u.uconduct.food++; u.uhunger += rnd(20); if (boulder) { delobj(boulder); /* boulder goes bye-bye */ You("eat the boulder."); /* yum */ /* * The location could still block because of * 1. More than one boulder * 2. Boulder stuck in a wall/stone/door. * * [perhaps use does_block() below (from vision.c)] */ if (IS_ROCK(lev->typ) || closed_door(x, y) || sobj_at(BOULDER, x, y)) { block_point(x, y); /* delobj will unblock the point */ /* reset dig state */ (void) memset((genericptr_t) &context.digging, 0, sizeof(struct dig_info)); return 1; } } else if (IS_WALL(lev->typ)) { if (*in_rooms(x, y, SHOPBASE)) { add_damage(x, y, 10L * ACURRSTR); dmgtxt = "damage"; } digtxt = "chew a hole in the wall."; if (level.flags.is_maze_lev) { lev->typ = ROOM; } else if (level.flags.is_cavernous_lev && !in_town(x, y)) { lev->typ = CORR; } else { lev->typ = DOOR; lev->doormask = D_NODOOR; } } else if (IS_TREE(lev->typ)) { digtxt = "chew through the tree."; lev->typ = ROOM; } else if (lev->typ == IRONBARS) { digtxt = "eat through the bars."; dissolve_bars(x, y); } else if (lev->typ == SDOOR) { if (lev->doormask & D_TRAPPED) { lev->doormask = D_NODOOR; b_trapped("secret door", 0); } else { digtxt = "chew through the secret door."; lev->doormask = D_BROKEN; } lev->typ = DOOR; } else if (IS_DOOR(lev->typ)) { if (*in_rooms(x, y, SHOPBASE)) { add_damage(x, y, 400L); dmgtxt = "break"; } if (lev->doormask & D_TRAPPED) { lev->doormask = D_NODOOR; b_trapped("door", 0); } else { digtxt = "chew through the door."; lev->doormask = D_BROKEN; } } else { /* STONE or SCORR */ digtxt = "chew a passage through the rock."; lev->typ = CORR; } unblock_point(x, y); /* vision */ newsym(x, y); if (digtxt) You1(digtxt); /* after newsym */ if (dmgtxt) pay_for_damage(dmgtxt, FALSE); (void) memset((genericptr_t) &context.digging, 0, sizeof(struct dig_info)); return 0; } void movobj(obj, ox, oy) register struct obj *obj; register xchar ox, oy; { /* optimize by leaving on the fobj chain? */ remove_object(obj); newsym(obj->ox, obj->oy); place_object(obj, ox, oy); newsym(ox, oy); } static NEARDATA const char fell_on_sink[] = "fell onto a sink"; STATIC_OVL void dosinkfall() { register struct obj *obj; int dmg; boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS), innate_lev = ((HLevitation & (FROMOUTSIDE | FROMFORM)) != 0L), ufall = (!innate_lev && !(HFlying || EFlying)); /* BFlying */ if (!ufall) { You(innate_lev ? "wobble unsteadily for a moment." : "gain control of your flight."); } else { long save_ELev = ELevitation, save_HLev = HLevitation; /* fake removal of levitation in advance so that final disclosure will be right in case this turns out to be fatal; fortunately the fact that rings and boots are really still worn has no effect on bones data */ ELevitation = HLevitation = 0L; You("crash to the floor!"); dmg = rn1(8, 25 - (int) ACURR(A_CON)); losehp(Maybe_Half_Phys(dmg), fell_on_sink, NO_KILLER_PREFIX); exercise(A_DEX, FALSE); selftouch("Falling, you"); for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) { You("fell on %s.", doname(obj)); losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink, NO_KILLER_PREFIX); exercise(A_CON, FALSE); } ELevitation = save_ELev; HLevitation = save_HLev; } /* * Interrupt multi-turn putting on/taking off of armor (in which * case we reached the sink due to being teleported while busy; * in 3.4.3, Boots_on()/Boots_off() [called via (*aftermv)() when * 'multi' reaches 0] triggered a crash if we were donning/doffing * levitation boots [because the Boots_off() below causes 'uarmf' * to be null by the time 'aftermv' gets called]). * * Interrupt donning/doffing if we fall onto the sink, or if the * code below is going to remove levitation boots even when we * haven't fallen (innate floating or flying becoming unblocked). */ if (ufall || lev_boots) { (void) stop_donning(lev_boots ? uarmf : (struct obj *) 0); /* recalculate in case uarmf just got set to null */ lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS); } /* remove worn levitation items */ ELevitation &= ~W_ARTI; HLevitation &= ~(I_SPECIAL | TIMEOUT); HLevitation++; if (uleft && uleft->otyp == RIN_LEVITATION) { obj = uleft; Ring_off(obj); off_msg(obj); } if (uright && uright->otyp == RIN_LEVITATION) { obj = uright; Ring_off(obj); off_msg(obj); } if (lev_boots) { obj = uarmf; (void) Boots_off(); off_msg(obj); } HLevitation--; /* probably moot; we're either still levitating or went through float_down(), but make sure BFlying is up to date */ float_vs_flight(); } /* intended to be called only on ROCKs or TREEs */ boolean may_dig(x, y) register xchar x, y; { struct rm *lev = &levl[x][y]; return (boolean) !((IS_STWALL(lev->typ) || IS_TREE(lev->typ)) && (lev->wall_info & W_NONDIGGABLE)); } boolean may_passwall(x, y) register xchar x, y; { return (boolean) !(IS_STWALL(levl[x][y].typ) && (levl[x][y].wall_info & W_NONPASSWALL)); } boolean bad_rock(mdat, x, y) struct permonst *mdat; register xchar x, y; { return (boolean) ((Sokoban && sobj_at(BOULDER, x, y)) || (IS_ROCK(levl[x][y].typ) && (!tunnels(mdat) || needspick(mdat) || !may_dig(x, y)) && !(passes_walls(mdat) && may_passwall(x, y)))); } /* caller has already decided that it's a tight diagonal; check whether a monster--who might be the hero--can fit through, and if not then return the reason why: 1: can't fit, 2: possessions won't fit, 3: sokoban */ int /* returns 0 if we can squeeze through */ cant_squeeze_thru(mon) struct monst *mon; { int amt; struct permonst *ptr = mon->data; /* too big? */ if (bigmonst(ptr) && !(amorphous(ptr) || is_whirly(ptr) || noncorporeal(ptr) || slithy(ptr) || can_fog(mon))) return 1; /* lugging too much junk? */ amt = (mon == &youmonst) ? inv_weight() + weight_cap() : curr_mon_load(mon); if (amt > 600) return 2; /* Sokoban restriction applies to hero only */ if (mon == &youmonst && Sokoban) return 3; /* can squeeze through */ return 0; } boolean invocation_pos(x, y) xchar x, y; { return (boolean) (Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y); } /* return TRUE if (dx,dy) is an OK place to move * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV */ boolean test_move(ux, uy, dx, dy, mode) int ux, uy, dx, dy; int mode; { int x = ux + dx; int y = uy + dy; register struct rm *tmpr = &levl[x][y]; register struct rm *ust; context.door_opened = FALSE; /* * Check for physical obstacles. First, the place we are going. */ if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) { if (Blind && mode == DO_MOVE) feel_location(x, y); if (Passes_walls && may_passwall(x, y)) { ; /* do nothing */ } else if (tmpr->typ == IRONBARS) { if ((dmgtype(youmonst.data, AD_RUST) || dmgtype(youmonst.data, AD_CORR)) && mode == DO_MOVE && still_chewing(x, y)) { return FALSE; } if (!(Passes_walls || passes_bars(youmonst.data))) { if (iflags.mention_walls) You("cannot pass through the bars."); return FALSE; } } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { /* Eat the rock. */ if (mode == DO_MOVE && still_chewing(x, y)) return FALSE; } else if (flags.autodig && !context.run && !context.nopick && uwep && is_pick(uwep)) { /* MRKR: Automatic digging when wielding the appropriate tool */ if (mode == DO_MOVE) (void) use_pick_axe2(uwep); return FALSE; } else { if (mode == DO_MOVE) { if (Is_stronghold(&u.uz) && is_db_wall(x, y)) pline_The("drawbridge is up!"); /* sokoban restriction stays even after puzzle is solved */ else if (Passes_walls && !may_passwall(x, y) && In_sokoban(&u.uz)) pline_The("Sokoban walls resist your ability."); else if (iflags.mention_walls) pline("It's a wall."); } return FALSE; } } else if (IS_DOOR(tmpr->typ)) { if (closed_door(x, y)) { if (Blind && mode == DO_MOVE) feel_location(x, y); if (Passes_walls) ; /* do nothing */ else if (can_ooze(&youmonst)) { if (mode == DO_MOVE) You("ooze under the door."); } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { /* Eat the door. */ if (mode == DO_MOVE && still_chewing(x, y)) return FALSE; } else { if (mode == DO_MOVE) { if (amorphous(youmonst.data)) You( "try to ooze under the door, but can't squeeze your possessions through."); if (flags.autoopen && !context.run && !Confusion && !Stunned && !Fumbling) { context.door_opened = context.move = doopen_indir(x, y); } else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { if (u.usteed) { You_cant("lead %s through that closed door.", y_monnam(u.usteed)); } else { pline("Ouch! You bump into a door."); exercise(A_DEX, FALSE); } } else pline("That door is closed."); } } else if (mode == TEST_TRAV) goto testdiag; return FALSE; } } else { testdiag: if (dx && dy && !Passes_walls && (!doorless_door(x, y) || block_door(x, y))) { /* Diagonal moves into a door are not allowed. */ if (Blind && mode == DO_MOVE) feel_location(x, y); return FALSE; } } } if (dx && dy && bad_rock(youmonst.data, ux, y) && bad_rock(youmonst.data, x, uy)) { /* Move at a diagonal. */ switch (cant_squeeze_thru(&youmonst)) { case 3: if (mode == DO_MOVE) You("cannot pass that way."); return FALSE; case 2: if (mode == DO_MOVE) You("are carrying too much to get through."); return FALSE; case 1: if (mode == DO_MOVE) Your("body is too large to fit through."); return FALSE; default: break; /* can squeeze through */ } } else if (dx && dy && worm_cross(ux, uy, x, y)) { /* consecutive long worm segments are at and */ if (mode == DO_MOVE) pline("%s is in your way.", Monnam(m_at(ux, y))); return FALSE; } /* Pick travel path that does not require crossing a trap. * Avoid water and lava using the usual running rules. * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */ if (context.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) { struct trap *t = t_at(x, y); if ((t && t->tseen) || (!Levitation && !Flying && !is_clinger(youmonst.data) && is_pool_or_lava(x, y) && levl[x][y].seenv)) return FALSE; } ust = &levl[ux][uy]; /* Now see if other things block our way . . */ if (dx && dy && !Passes_walls && IS_DOOR(ust->typ) && (!doorless_door(ux, uy) || block_entry(x, y))) { /* Can't move at a diagonal out of a doorway with door. */ return FALSE; } if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) { if (!(Blind || Hallucination) && (context.run >= 2) && mode != TEST_TRAV) return FALSE; if (mode == DO_MOVE) { /* tunneling monsters will chew before pushing */ if (tunnels(youmonst.data) && !needspick(youmonst.data) && !Sokoban) { if (still_chewing(x, y)) return FALSE; } else if (moverock() < 0) return FALSE; } else if (mode == TEST_TRAV) { struct obj *obj; /* don't pick two boulders in a row, unless there's a way thru */ if (sobj_at(BOULDER, ux, uy) && !Sokoban) { if (!Passes_walls && !(tunnels(youmonst.data) && !needspick(youmonst.data)) && !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) && !((obj = carrying(WAN_DIGGING)) && !objects[obj->otyp].oc_name_known)) return FALSE; } } /* assume you'll be able to push it when you get there... */ } /* OK, it is a legal place to move. */ return TRUE; } #ifdef DEBUG static boolean trav_debug = FALSE; /* in this case, toggle display of travel debug info */ int wiz_debug_cmd_traveldisplay() { trav_debug = !trav_debug; return 0; } #endif /* DEBUG */ /* * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy). * A shortest path is returned. If guess is TRUE, consider various * inaccessible locations as valid intermediate path points. * Returns TRUE if a path was found. */ STATIC_OVL boolean findtravelpath(guess) boolean guess; { /* if travel to adjacent, reachable location, use normal movement rules */ if (!guess && context.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1 && !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) { context.run = 0; if (test_move(u.ux, u.uy, u.tx - u.ux, u.ty - u.uy, TEST_MOVE)) { u.dx = u.tx - u.ux; u.dy = u.ty - u.uy; nomul(0); iflags.travelcc.x = iflags.travelcc.y = -1; return TRUE; } context.run = 8; } if (u.tx != u.ux || u.ty != u.uy) { xchar travel[COLNO][ROWNO]; xchar travelstepx[2][COLNO * ROWNO]; xchar travelstepy[2][COLNO * ROWNO]; xchar tx, ty, ux, uy; int n = 1; /* max offset in travelsteps */ int set = 0; /* two sets current and previous */ int radius = 1; /* search radius */ int i; /* If guessing, first find an "obvious" goal location. The obvious * goal is the position the player knows of, or might figure out * (couldsee) that is closest to the target on a straight path. */ if (guess) { tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty; } else { tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy; } noguess: (void) memset((genericptr_t) travel, 0, sizeof(travel)); travelstepx[0][0] = tx; travelstepy[0][0] = ty; while (n != 0) { int nn = 0; for (i = 0; i < n; i++) { int dir; int x = travelstepx[set][i]; int y = travelstepy[set][i]; static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; /* no diagonal movement for grid bugs */ int dirmax = NODIAG(u.umonnum) ? 4 : 8; for (dir = 0; dir < dirmax; ++dir) { int nx = x + xdir[ordered[dir]]; int ny = y + ydir[ordered[dir]]; if (!isok(nx, ny)) continue; if ((!Passes_walls && !can_ooze(&youmonst) && closed_door(x, y)) || sobj_at(BOULDER, x, y)) { /* closed doors and boulders usually * cause a delay, so prefer another path */ if (travel[x][y] > radius - 3) { travelstepx[1 - set][nn] = x; travelstepy[1 - set][nn] = y; /* don't change travel matrix! */ nn++; continue; } } if (test_move(x, y, nx - x, ny - y, TEST_TRAV) && (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) { if (nx == ux && ny == uy) { if (!guess) { u.dx = x - ux; u.dy = y - uy; if (x == u.tx && y == u.ty) { nomul(0); /* reset run so domove run checks work */ context.run = 8; iflags.travelcc.x = iflags.travelcc.y = -1; } return TRUE; } } else if (!travel[nx][ny]) { travelstepx[1 - set][nn] = nx; travelstepy[1 - set][nn] = ny; travel[nx][ny] = radius; nn++; } } } } #ifdef DEBUG if (trav_debug) { /* Use of warning glyph is arbitrary. It stands out. */ tmp_at(DISP_ALL, warning_to_glyph(1)); for (i = 0; i < nn; ++i) { tmp_at(travelstepx[1 - set][i], travelstepy[1 - set][i]); } delay_output(); if (flags.runmode == RUN_CRAWL) { delay_output(); delay_output(); } tmp_at(DISP_END, 0); } #endif /* DEBUG */ n = nn; set = 1 - set; radius++; } /* if guessing, find best location in travel matrix and go there */ if (guess) { int px = tx, py = ty; /* pick location */ int dist, nxtdist, d2, nd2; dist = distmin(ux, uy, tx, ty); d2 = dist2(ux, uy, tx, ty); for (tx = 1; tx < COLNO; ++tx) for (ty = 0; ty < ROWNO; ++ty) if (travel[tx][ty]) { nxtdist = distmin(ux, uy, tx, ty); if (nxtdist == dist && couldsee(tx, ty)) { nd2 = dist2(ux, uy, tx, ty); if (nd2 < d2) { /* prefer non-zigzag path */ px = tx; py = ty; d2 = nd2; } } else if (nxtdist < dist && couldsee(tx, ty)) { px = tx; py = ty; dist = nxtdist; d2 = dist2(ux, uy, tx, ty); } } if (px == u.ux && py == u.uy) { /* no guesses, just go in the general direction */ u.dx = sgn(u.tx - u.ux); u.dy = sgn(u.ty - u.uy); if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE)) return TRUE; goto found; } #ifdef DEBUG if (trav_debug) { /* Use of warning glyph is arbitrary. It stands out. */ tmp_at(DISP_ALL, warning_to_glyph(2)); tmp_at(px, py); delay_output(); if (flags.runmode == RUN_CRAWL) { delay_output(); delay_output(); delay_output(); delay_output(); } tmp_at(DISP_END, 0); } #endif /* DEBUG */ tx = px; ty = py; ux = u.ux; uy = u.uy; set = 0; n = radius = 1; guess = FALSE; goto noguess; } return FALSE; } found: u.dx = 0; u.dy = 0; nomul(0); return FALSE; } /* try to escape being stuck in a trapped state by walking out of it; return true iff moving should continue to intended destination (all failures and most successful escapes leave hero at original spot) */ STATIC_OVL boolean trapmove(x, y, desttrap) int x, y; /* targetted destination, */ struct trap *desttrap; /* nonnull if another trap at */ { boolean anchored; const char *predicament, *culprit; char *steedname = !u.usteed ? (char *) 0 : y_monnam(u.usteed); if (!u.utrap) return TRUE; /* sanity check */ switch (u.utraptype) { case TT_BEARTRAP: if (flags.verbose) { predicament = "caught in a bear trap"; if (u.usteed) Norep("%s is %s.", upstart(steedname), predicament); else Norep("You are %s.", predicament); } /* [why does diagonal movement give quickest escape?] */ if ((u.dx && u.dy) || !rn2(5)) u.utrap--; break; case TT_PIT: if (desttrap && desttrap->tseen && (desttrap->ttyp == PIT || desttrap->ttyp == SPIKED_PIT)) return TRUE; /* move into adjacent pit */ /* try to escape; position stays same regardless of success */ climb_pit(); break; case TT_WEB: if (uwep && uwep->oartifact == ART_STING) { u.utrap = 0; pline("Sting cuts through the web!"); break; /* escape trap but don't move */ } if (--u.utrap) { if (flags.verbose) { predicament = "stuck to the web"; if (u.usteed) Norep("%s is %s.", upstart(steedname), predicament); else Norep("You are %s.", predicament); } } else { if (u.usteed) pline("%s breaks out of the web.", upstart(steedname)); else You("disentangle yourself."); } break; case TT_LAVA: if (flags.verbose) { predicament = "stuck in the lava"; if (u.usteed) Norep("%s is %s.", upstart(steedname), predicament); else Norep("You are %s.", predicament); } if (!is_lava(x, y)) { u.utrap--; if ((u.utrap & 0xff) == 0) { u.utrap = 0; if (u.usteed) You("lead %s to the edge of the lava.", steedname); else You("pull yourself to the edge of the lava."); } } u.umoved = TRUE; break; case TT_INFLOOR: case TT_BURIEDBALL: anchored = (u.utraptype == TT_BURIEDBALL); if (anchored) { coord cc; cc.x = u.ux, cc.y = u.uy; /* can move normally within radius 1 of buried ball */ if (buried_ball(&cc) && dist2(x, y, cc.x, cc.y) <= 2) { /* ugly hack: we need to issue some message here in case "you are chained to the buried ball" was the most recent message given, otherwise our next attempt to move out of tether range after this successful move would have its can't-do-that message suppressed by Norep */ if (flags.verbose) Norep("You move within the chain's reach."); return TRUE; } } if (--u.utrap) { if (flags.verbose) { if (anchored) { predicament = "chained to the"; culprit = "buried ball"; } else { predicament = "stuck in the"; culprit = surface(u.ux, u.uy); } if (u.usteed) { if (anchored) Norep("You and %s are %s %s.", steedname, predicament, culprit); else Norep("%s is %s %s.", upstart(steedname), predicament, culprit); } else Norep("You are %s %s.", predicament, culprit); } } else { if (u.usteed) pline("%s finally %s free.", upstart(steedname), !anchored ? "lurches" : "wrenches the ball"); else You("finally %s free.", !anchored ? "wriggle" : "wrench the ball"); if (anchored) buried_ball_to_punishment(); } break; default: impossible("trapmove: stuck in unknown trap? (%d)", (int) u.utraptype); break; } return FALSE; } boolean u_rooted() { if (!youmonst.data->mmove) { You("are rooted %s.", Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? "in place" : "to the ground"); nomul(0); return TRUE; } return FALSE; } void domove() { register struct monst *mtmp; register struct rm *tmpr; register xchar x, y; struct trap *trap = NULL; int wtcap; boolean on_ice; xchar chainx = 0, chainy = 0, ballx = 0, bally = 0; /* ball&chain new positions */ int bc_control = 0; /* control for ball&chain */ boolean cause_delay = FALSE; /* dragging ball will skip a move */ u_wipe_engr(rnd(5)); if (context.travel) { if (!findtravelpath(FALSE)) (void) findtravelpath(TRUE); context.travel1 = 0; } if (((wtcap = near_capacity()) >= OVERLOADED || (wtcap > SLT_ENCUMBER && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) : (u.uhp < 10 && u.uhp != u.uhpmax)))) && !Is_airlevel(&u.uz)) { if (wtcap < OVERLOADED) { You("don't have enough stamina to move."); exercise(A_CON, FALSE); } else You("collapse under your load."); nomul(0); return; } if (u.uswallow) { u.dx = u.dy = 0; u.ux = x = u.ustuck->mx; u.uy = y = u.ustuck->my; mtmp = u.ustuck; } else { if (Is_airlevel(&u.uz) && rn2(4) && !Levitation && !Flying) { switch (rn2(3)) { case 0: You("tumble in place."); exercise(A_DEX, FALSE); break; case 1: You_cant("control your movements very well."); break; case 2: pline("It's hard to walk in thin air."); exercise(A_DEX, TRUE); break; } return; } /* check slippery ice */ on_ice = !Levitation && is_ice(u.ux, u.uy); if (on_ice) { static int skates = 0; if (!skates) skates = find_skates(); if ((uarmf && uarmf->otyp == skates) || resists_cold(&youmonst) || Flying || is_floater(youmonst.data) || is_clinger(youmonst.data) || is_whirly(youmonst.data)) on_ice = FALSE; else if (!rn2(Cold_resistance ? 3 : 2)) { HFumbling |= FROMOUTSIDE; HFumbling &= ~TIMEOUT; HFumbling += 1; /* slip on next move */ } } if (!on_ice && (HFumbling & FROMOUTSIDE)) HFumbling &= ~FROMOUTSIDE; x = u.ux + u.dx; y = u.uy + u.dy; if (Stunned || (Confusion && !rn2(5))) { register int tries = 0; do { if (tries++ > 50) { nomul(0); return; } confdir(); x = u.ux + u.dx; y = u.uy + u.dy; } while (!isok(x, y) || bad_rock(youmonst.data, x, y)); } /* turbulence might alter your actual destination */ if (u.uinwater) { water_friction(); if (!u.dx && !u.dy) { nomul(0); return; } x = u.ux + u.dx; y = u.uy + u.dy; } if (!isok(x, y)) { nomul(0); return; } if (((trap = t_at(x, y)) && trap->tseen) || (Blind && !Levitation && !Flying && !is_clinger(youmonst.data) && is_pool_or_lava(x, y) && levl[x][y].seenv)) { if (context.run >= 2) { nomul(0); context.move = 0; return; } else nomul(0); } if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) { if (distu(u.ustuck->mx, u.ustuck->my) > 2) { /* perhaps it fled (or was teleported or ... ) */ u.ustuck = 0; } else if (sticks(youmonst.data)) { /* When polymorphed into a sticking monster, * u.ustuck means it's stuck to you, not you to it. */ You("release %s.", mon_nam(u.ustuck)); u.ustuck = 0; } else { /* If holder is asleep or paralyzed: * 37.5% chance of getting away, * 12.5% chance of waking/releasing it; * otherwise: * 7.5% chance of getting away. * [strength ought to be a factor] * If holder is tame and there is no conflict, * guaranteed escape. */ switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { case 0: case 1: case 2: pull_free: You("pull free from %s.", mon_nam(u.ustuck)); u.ustuck = 0; break; case 3: if (!u.ustuck->mcanmove) { /* it's free to move on next turn */ u.ustuck->mfrozen = 1; u.ustuck->msleeping = 0; } /*FALLTHRU*/ default: if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) goto pull_free; You("cannot escape from %s!", mon_nam(u.ustuck)); nomul(0); return; } } } mtmp = m_at(x, y); if (mtmp) { /* Don't attack if you're running, and can see it */ /* We should never get here if forcefight */ if (context.run && ((!Blind && mon_visible(mtmp) && ((mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) || Protection_from_shape_changers)) || sensemon(mtmp))) { nomul(0); context.move = 0; return; } } } u.ux0 = u.ux; u.uy0 = u.uy; bhitpos.x = x; bhitpos.y = y; tmpr = &levl[x][y]; /* attack monster */ if (mtmp) { nomul(0); /* only attack if we know it's there */ /* or if we used the 'F' command to fight blindly */ /* or if it hides_under, in which case we call attack() to print * the Wait! message. * This is different from ceiling hiders, who aren't handled in * attack(). */ /* If they used a 'm' command, trying to move onto a monster * prints the below message and wastes a turn. The exception is * if the monster is unseen and the player doesn't remember an * invisible monster--then, we fall through to attack() and * attack_check(), which still wastes a turn, but prints a * different message and makes the player remember the monster. */ if (context.nopick && (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))) { if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp)) stumble_onto_mimic(mtmp); else if (mtmp->mpeaceful && !Hallucination) pline("Pardon me, %s.", m_monnam(mtmp)); else You("move right into %s.", mon_nam(mtmp)); return; } if (context.forcefight || !mtmp->mundetected || sensemon(mtmp) || ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && !is_safepet(mtmp))) { /* try to attack; note that it might evade */ /* also, we don't attack tame when _safepet_ */ if (attack(mtmp)) return; } } /* specifying 'F' with no monster wastes a turn */ if (context.forcefight /* remembered an 'I' && didn't use a move command */ || (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) { struct obj *boulder = 0; boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)), solid = !accessible(x, y); int glyph = glyph_at(x, y); /* might be monster */ char buf[BUFSZ]; if (!Underwater) { boulder = sobj_at(BOULDER, x, y); /* if a statue is displayed at the target location, player is attempting to attack it [and boulder handling below is suitable for handling that] */ if (glyph_is_statue(glyph) || (Hallucination && glyph_is_monster(glyph))) boulder = sobj_at(STATUE, x, y); /* force fight at boulder/statue or wall/door while wielding pick: start digging to break the boulder or wall */ if (context.forcefight /* can we dig? */ && uwep && dig_typ(uwep, x, y) /* should we dig? */ && !glyph_is_invisible(glyph) && !glyph_is_monster(glyph)) { (void) use_pick_axe2(uwep); return; } } /* about to become known empty -- remove 'I' if present */ unmap_object(x, y); if (boulder) map_object(boulder, TRUE); newsym(x, y); glyph = glyph_at(x, y); /* might have just changed */ if (boulder) Strcpy(buf, ansimpleoname(boulder)); else if (Underwater && !is_pool(x, y)) /* Underwater, targetting non-water; the map just shows blank because you don't see remembered terrain while underwater; although the hero can attack an adjacent monster this way, assume he can't reach out far enough to distinguish terrain */ Sprintf(buf, (Is_waterlevel(&u.uz) && levl[x][y].typ == AIR) ? "an air bubble" : "nothing"); else if (solid) /* glyph might indicate unseen terrain if hero is blind; unlike searching, this won't reveal what that terrain is (except for solid rock, where the glyph would otherwise yield ludicrous "dark part of a room") */ Strcpy(buf, (levl[x][y].typ == STONE) ? "solid rock" : glyph_is_cmap(glyph) ? the(defsyms[glyph_to_cmap(glyph)].explanation) : (const char *) "an unknown obstacle"); /* note: 'solid' is misleadingly named and catches pools of water and lava as well as rock and walls */ else Strcpy(buf, "thin air"); You("%s%s %s.", !(boulder || solid) ? "" : !explo ? "harmlessly " : "futilely ", explo ? "explode at" : "attack", buf); nomul(0); if (explo) { wake_nearby(); u.mh = -1; /* dead in the current form */ rehumanize(); } return; } if (glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } /* not attacking an animal, so we try to move */ if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { nomul(0); return; } if (u_rooted()) return; if (u.utrap) { if (!trapmove(x, y, trap)) return; } if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) { if (!context.door_opened) { context.move = 0; nomul(0); } return; } /* Move ball and chain. */ if (Punished) if (!drag_ball(x, y, &bc_control, &ballx, &bally, &chainx, &chainy, &cause_delay, TRUE)) return; /* Check regions entering/leaving */ if (!in_out_region(x, y)) return; /* now move the hero */ mtmp = m_at(x, y); u.ux += u.dx; u.uy += u.dy; /* Move your steed, too */ if (u.usteed) { u.usteed->mx = u.ux; u.usteed->my = u.uy; exercise_steed(); } /* * If safepet at destination then move the pet to the hero's * previous location using the same conditions as in attack(). * there are special extenuating circumstances: * (1) if the pet dies then your god angers, * (2) if the pet gets trapped then your god may disapprove, * (3) if the pet was already trapped and you attempt to free it * not only do you encounter the trap but you may frighten your * pet causing it to go wild! moral: don't abuse this privilege. * * Ceiling-hiding pets are skipped by this section of code, to * be caught by the normal falling-monster code. */ if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { /* if trapped, there's a chance the pet goes wild */ if (mtmp->mtrapped) { if (!rn2(mtmp->mtame)) { mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0; if (mtmp->mleashed) m_unleash(mtmp, TRUE); growl(mtmp); } else { yelp(mtmp); } } mtmp->mundetected = 0; if (mtmp->m_ap_type) seemimic(mtmp); else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && sobj_at(BOULDER, trap->tx, trap->ty)) { /* can't swap places with pet pinned in a pit by a boulder */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { /* can't swap places when pet can't move to your spot */ u.ux = u.ux0, u.uy = u.uy0; You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp))); } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0) && bad_rock(mtmp->data, u.ux0, y) && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { /* can't swap places when pet won't fit thru the opening */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); } else { char pnambuf[BUFSZ]; /* save its current description in case of polymorph */ Strcpy(pnambuf, y_monnam(mtmp)); mtmp->mtrapped = 0; remove_monster(x, y); place_monster(mtmp, u.ux0, u.uy0); newsym(x, y); newsym(u.ux0, u.uy0); You("%s %s.", mtmp->mtame ? "swap places with" : "frighten", pnambuf); /* check for displacing it into pools and traps */ switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { case 0: break; case 1: /* trapped */ case 3: /* changed levels */ /* there's already been a trap message, reinforce it */ abuse_dog(mtmp); adjalign(-3); break; case 2: /* drowned or died... * you killed your pet by direct action, so get experience * and possibly penalties; * we want the level gain message, if it happens, to occur * before the guilt message below */ { /* minliquid() and mintrap() call mondead() rather than killed() so we duplicate some of the latter here */ int tmp, mndx; u.uconduct.killer++; mndx = monsndx(mtmp->data); tmp = experience(mtmp, (int) mvitals[mndx].died); more_experienced(tmp, 0); newexplevel(); /* will decide if you go up */ } /* That's no way to treat a pet! Your god gets angry. * * [This has always been pretty iffy. Why does your * patron deity care at all, let alone enough to get mad?] */ if (rn2(4)) { You_feel("guilty about losing your pet like this."); u.ugangr++; adjalign(-15); } break; default: pline("that's strange, unknown mintrap result!"); break; } } } reset_occupations(); if (context.run) { if (context.run < 8) if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || IS_FURNITURE(tmpr->typ)) nomul(0); } if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || u.dx || u.dy) (void) hideunder(&youmonst); /* * Mimics (or whatever) become noticeable if they move and are * imitating something that doesn't move. We could extend this * to non-moving monsters... */ if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT || youmonst.m_ap_type == M_AP_FURNITURE)) youmonst.m_ap_type = M_AP_NOTHING; check_leash(u.ux0, u.uy0); if (u.ux0 != u.ux || u.uy0 != u.uy) { u.umoved = TRUE; /* Clean old position -- vision_recalc() will print our new one. */ newsym(u.ux0, u.uy0); /* Since the hero has moved, adjust what can be seen/unseen. */ vision_recalc(1); /* Do the work now in the recover time. */ invocation_message(); } if (Punished) /* put back ball and chain */ move_bc(0, bc_control, ballx, bally, chainx, chainy); spoteffects(TRUE); /* delay next move because of ball dragging */ /* must come after we finished picking up, in spoteffects() */ if (cause_delay) { nomul(-2); multi_reason = "dragging an iron ball"; nomovemsg = ""; } if (context.run && flags.runmode != RUN_TPORT) { /* display every step or every 7th step depending upon mode */ if (flags.runmode != RUN_LEAP || !(moves % 7L)) { if (flags.time) context.botl = 1; curs_on_u(); delay_output(); if (flags.runmode == RUN_CRAWL) { delay_output(); delay_output(); delay_output(); delay_output(); } } } } /* combat increases metabolism */ boolean overexertion() { /* this used to be part of domove() when moving to a monster's position, but is now called by attack() so that it doesn't execute if you decline to attack a peaceful monster */ gethungry(); if ((moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) { int *hp = (!Upolyd ? &u.uhp : &u.mh); if (*hp > 1) { *hp -= 1; } else { You("pass out from exertion!"); exercise(A_CON, FALSE); fall_asleep(-10, FALSE); } } return (boolean) (multi < 0); /* might have fainted (forced to sleep) */ } void invocation_message() { /* a special clue-msg when on the Invocation position */ if (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { char buf[BUFSZ]; struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION); nomul(0); /* stop running or travelling */ if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed)); else if (Levitation || Flying) Strcpy(buf, "beneath you"); else Sprintf(buf, "under your %s", makeplural(body_part(FOOT))); You_feel("a strange vibration %s.", buf); u.uevent.uvibrated = 1; if (otmp && otmp->spe == 7 && otmp->lamplit) pline("%s %s!", The(xname(otmp)), Blind ? "throbs palpably" : "glows with a strange light"); } } /* moving onto different terrain; might be going into solid rock, inhibiting levitation or flight, or coming back out of such, reinstating levitation/flying */ STATIC_OVL void switch_terrain() { struct rm *lev = &levl[u.ux][u.uy]; boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy) || (Is_waterlevel(&u.uz) && lev->typ == WATER)); if (blocklev) { /* called from spoteffects(), skip float_down() */ if (Levitation) You_cant("levitate in here."); BLevitation |= FROMOUTSIDE; } else if (BLevitation) { BLevitation &= ~FROMOUTSIDE; if (Levitation) float_up(); } /* the same terrain that blocks levitation also blocks flight */ if (blocklev) { if (Flying) You_cant("fly in here."); BFlying |= FROMOUTSIDE; } else if (BFlying) { BFlying &= ~FROMOUTSIDE; float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ /* [minor bug: we don't know whether this is beginning flight or resuming it; that could be tracked so that this message could be adjusted to "resume flying", but isn't worth the effort...] */ if (Flying) You("start flying."); } } /* extracted from spoteffects; called by spoteffects to check for entering or leaving a pool of water/lava, and by moveloop to check for staying on one returns true to skip rest of spoteffects */ boolean pooleffects(newspot) boolean newspot; /* true if called by spoteffects */ { /* check for leaving water */ if (u.uinwater) { boolean still_inwater = FALSE; /* assume we're getting out */ if (!is_pool(u.ux, u.uy)) { if (Is_waterlevel(&u.uz)) You("pop into an air bubble."); else if (is_lava(u.ux, u.uy)) You("leave the water..."); /* oops! */ else You("are on solid %s again.", is_ice(u.ux, u.uy) ? "ice" : "land"); } else if (Is_waterlevel(&u.uz)) { still_inwater = TRUE; } else if (Levitation) { You("pop out of the water like a cork!"); } else if (Flying) { You("fly out of the water."); } else if (Wwalking) { You("slowly rise above the surface."); } else { still_inwater = TRUE; } if (!still_inwater) { boolean was_underwater = (Underwater && !Is_waterlevel(&u.uz)); u.uinwater = 0; /* leave the water */ if (was_underwater) { /* restore vision */ docrt(); vision_full_recalc = 1; } } } /* check for entering water or lava */ if (!u.ustuck && !Levitation && !Flying && is_pool_or_lava(u.ux, u.uy)) { if (u.usteed && (is_flyer(u.usteed->data) || is_floater(u.usteed->data) || is_clinger(u.usteed->data))) { /* floating or clinging steed keeps hero safe (is_flyer() test is redundant; it can't be true since Flying yielded false) */ return FALSE; } else if (u.usteed) { /* steed enters pool */ dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC); /* dismount_steed() -> float_down() -> pickup() (float_down doesn't do autopickup on Air or Water) */ if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) return FALSE; /* even if we actually end up at same location, float_down() has already done spoteffect()'s trap and pickup actions */ if (newspot) check_special_room(FALSE); /* spoteffects */ return TRUE; } /* not mounted */ /* drown(),lava_effects() return true if hero changes location while surviving the problem */ if (is_lava(u.ux, u.uy)) { if (lava_effects()) return TRUE; } else if (!Wwalking && (newspot || !u.uinwater || !(Swimming || Amphibious))) { if (drown()) return TRUE; } } return FALSE; } void spoteffects(pick) boolean pick; { static int inspoteffects = 0; static coord spotloc; static int spotterrain; static struct trap *spottrap = (struct trap *) 0; static unsigned spottraptyp = NO_TRAP; struct trap *trap = t_at(u.ux, u.uy); register struct monst *mtmp; /* prevent recursion from affecting the hero all over again [hero poly'd to iron golem enters water here, drown() inflicts damage that triggers rehumanize() which calls spoteffects()...] */ if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y /* except when reason is transformed terrain (ice -> water) */ && spotterrain == levl[u.ux][u.uy].typ /* or transformed trap (land mine -> pit) */ && (!spottrap || !trap || trap->ttyp == spottraptyp)) return; ++inspoteffects; spotterrain = levl[u.ux][u.uy].typ; spotloc.x = u.ux, spotloc.y = u.uy; /* moving onto different terrain might cause Levitation to toggle */ if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0)) switch_terrain(); if (pooleffects(TRUE)) goto spotdone; check_special_room(FALSE); if (IS_SINK(levl[u.ux][u.uy].typ) && Levitation) dosinkfall(); if (!in_steed_dismounting) { /* if dismounting, we'll check again later */ boolean pit; /* if levitation is due to time out at the end of this turn, allowing it to do so could give the perception that a trap here is being triggered twice, so adjust the timeout to prevent that */ if (trap && (HLevitation & TIMEOUT) == 1L && !ELevitation && !(HLevitation & ~TIMEOUT)) { if (rn2(2)) { /* defer timeout */ incr_itimeout(&HLevitation, 1L); } else { /* timeout early */ if (float_down(I_SPECIAL | TIMEOUT, 0L)) { /* levitation has ended; we've already triggered any trap and [usually] performed autopickup */ trap = 0; pick = FALSE; } } } /* * If not a pit, pickup before triggering trap. * If pit, trigger trap before pickup. */ pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)); if (pick && !pit) (void) pickup(1); if (trap) { /* * dotrap on a fire trap calls melt_ice() which triggers * spoteffects() (again) which can trigger the same fire * trap (again). Use static spottrap to prevent that. * We track spottraptyp because some traps morph * (landmine to pit) and any new trap type * should get triggered. */ if (!spottrap || spottraptyp != trap->ttyp) { spottrap = trap; spottraptyp = trap->ttyp; dotrap(trap, 0); /* fall into arrow trap, etc. */ spottrap = (struct trap *) 0; spottraptyp = NO_TRAP; } } if (pick && pit) (void) pickup(1); } /* Warning alerts you to ice danger */ if (Warning && is_ice(u.ux, u.uy)) { static const char *const icewarnings[] = { "The ice seems very soft and slushy.", "You feel the ice shift beneath you!", "The ice, is gonna BREAK!", /* The Dead Zone */ }; long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY); if (time_left && time_left < 15L) pline1((time_left < 5L) ? icewarnings[2] : (time_left < 10L) ? icewarnings[1] : icewarnings[0]); } if ((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) { mtmp->mundetected = mtmp->msleeping = 0; switch (mtmp->data->mlet) { case S_PIERCER: pline("%s suddenly drops from the %s!", Amonnam(mtmp), ceiling(u.ux, u.uy)); if (mtmp->mtame) /* jumps to greet you, not attack */ ; else if (uarmh && is_metallic(uarmh)) pline("Its blow glances off your %s.", helm_simple_name(uarmh)); else if (u.uac + 3 <= rnd(20)) You("are almost hit by %s!", x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); else { int dmg; You("are hit by %s!", x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); dmg = d(4, 6); if (Half_physical_damage) dmg = (dmg + 1) / 2; mdamageu(mtmp, dmg); } break; default: /* monster surprises you. */ if (mtmp->mtame) pline("%s jumps near you from the %s.", Amonnam(mtmp), ceiling(u.ux, u.uy)); else if (mtmp->mpeaceful) { You("surprise %s!", Blind && !sensemon(mtmp) ? something : a_monnam(mtmp)); mtmp->mpeaceful = 0; } else pline("%s attacks you by surprise!", Amonnam(mtmp)); break; } mnexto(mtmp); /* have to move the monster */ } spotdone: if (!--inspoteffects) { spotterrain = STONE; /* 0 */ spotloc.x = spotloc.y = 0; } return; } /* returns first matching monster */ STATIC_OVL struct monst * monstinroom(mdat, roomno) struct permonst *mdat; int roomno; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->data == mdat && index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET)) return mtmp; } return (struct monst *) 0; } char * in_rooms(x, y, typewanted) register xchar x, y; register int typewanted; { static char buf[5]; char rno, *ptr = &buf[4]; int typefound, min_x, min_y, max_x, max_y_offset, step; register struct rm *lev; #define goodtype(rno) \ (!typewanted \ || ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) \ || ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) switch (rno = levl[x][y].roomno) { case NO_ROOM: return ptr; case SHARED: step = 2; break; case SHARED_PLUS: step = 1; break; default: /* i.e. a regular room # */ if (goodtype(rno)) *(--ptr) = rno; return ptr; } min_x = x - 1; max_x = x + 1; if (x < 1) min_x += step; else if (x >= COLNO) max_x -= step; min_y = y - 1; max_y_offset = 2; if (min_y < 0) { min_y += step; max_y_offset -= step; } else if ((min_y + max_y_offset) >= ROWNO) max_y_offset -= step; for (x = min_x; x <= max_x; x += step) { lev = &levl[x][min_y]; y = 0; if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno) && goodtype(rno)) *(--ptr) = rno; y += step; if (y > max_y_offset) continue; if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno) && goodtype(rno)) *(--ptr) = rno; y += step; if (y > max_y_offset) continue; if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno) && goodtype(rno)) *(--ptr) = rno; } return ptr; } /* is (x,y) in a town? */ boolean in_town(x, y) register int x, y; { s_level *slev = Is_special(&u.uz); register struct mkroom *sroom; boolean has_subrooms = FALSE; if (!slev || !slev->flags.town) return FALSE; /* * See if (x,y) is in a room with subrooms, if so, assume it's the * town. If there are no subrooms, the whole level is in town. */ for (sroom = &rooms[0]; sroom->hx > 0; sroom++) { if (sroom->nsubrooms > 0) { has_subrooms = TRUE; if (inside_room(sroom, x, y)) return TRUE; } } return !has_subrooms; } STATIC_OVL void move_update(newlev) register boolean newlev; { char *ptr1, *ptr2, *ptr3, *ptr4; Strcpy(u.urooms0, u.urooms); Strcpy(u.ushops0, u.ushops); if (newlev) { u.urooms[0] = '\0'; u.uentered[0] = '\0'; u.ushops[0] = '\0'; u.ushops_entered[0] = '\0'; Strcpy(u.ushops_left, u.ushops0); return; } Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0)); for (ptr1 = &u.urooms[0], ptr2 = &u.uentered[0], ptr3 = &u.ushops[0], ptr4 = &u.ushops_entered[0]; *ptr1; ptr1++) { if (!index(u.urooms0, *ptr1)) *(ptr2++) = *ptr1; if (IS_SHOP(*ptr1 - ROOMOFFSET)) { *(ptr3++) = *ptr1; if (!index(u.ushops0, *ptr1)) *(ptr4++) = *ptr1; } } *ptr2 = '\0'; *ptr3 = '\0'; *ptr4 = '\0'; /* filter u.ushops0 -> u.ushops_left */ for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++) if (!index(u.ushops, *ptr1)) *(ptr2++) = *ptr1; *ptr2 = '\0'; } void check_special_room(newlev) register boolean newlev; { register struct monst *mtmp; char *ptr; move_update(newlev); if (*u.ushops0) u_left_shop(u.ushops_left, newlev); if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ return; /* no entrance messages necessary */ /* Did we just enter a shop? */ if (*u.ushops_entered) u_entered_shop(u.ushops_entered); for (ptr = &u.uentered[0]; *ptr; ptr++) { int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype; boolean msg_given = TRUE; /* Did we just enter some other special room? */ /* vault.c insists that a vault remain a VAULT, * and temples should remain TEMPLEs, * but everything else gives a message only the first time */ switch (rt) { case ZOO: pline("Welcome to David's treasure zoo!"); break; case SWAMP: pline("It %s rather %s down here.", Blind ? "feels" : "looks", Blind ? "humid" : "muddy"); break; case COURT: You("enter an opulent throne room!"); break; case LEPREHALL: You("enter a leprechaun hall!"); break; case MORGUE: if (midnight()) { const char *run = locomotion(youmonst.data, "Run"); pline("%s away! %s away!", run, run); } else You("have an uncanny feeling..."); break; case BEEHIVE: You("enter a giant beehive!"); break; case COCKNEST: You("enter a disgusting nest!"); break; case ANTHOLE: You("enter an anthole!"); break; case BARRACKS: if (monstinroom(&mons[PM_SOLDIER], roomno) || monstinroom(&mons[PM_SERGEANT], roomno) || monstinroom(&mons[PM_LIEUTENANT], roomno) || monstinroom(&mons[PM_CAPTAIN], roomno)) You("enter a military barracks!"); else You("enter an abandoned barracks."); break; case DELPHI: { struct monst *oracle = monstinroom(&mons[PM_ORACLE], roomno); if (oracle) { if (!oracle->mpeaceful) verbalize("You're in Delphi, %s.", plname); else verbalize("%s, %s, welcome to Delphi!", Hello((struct monst *) 0), plname); } else msg_given = FALSE; break; } case TEMPLE: intemple(roomno + ROOMOFFSET); /*FALLTHRU*/ default: msg_given = (rt == TEMPLE); rt = 0; break; } if (msg_given) room_discovered(roomno); if (rt != 0) { rooms[roomno].rtype = OROOM; if (!search_special(rt)) { /* No more room of that type */ switch (rt) { case COURT: level.flags.has_court = 0; break; case SWAMP: level.flags.has_swamp = 0; break; case MORGUE: level.flags.has_morgue = 0; break; case ZOO: level.flags.has_zoo = 0; break; case BARRACKS: level.flags.has_barracks = 0; break; case TEMPLE: level.flags.has_temple = 0; break; case BEEHIVE: level.flags.has_beehive = 0; break; } } if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (!Stealth && !rn2(3)) mtmp->msleeping = 0; } } } return; } int dopickup() { int count; struct trap *traphere = t_at(u.ux, u.uy); /* awful kludge to work around parse()'s pre-decrement */ count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; multi = 0; /* always reset */ /* uswallow case added by GAN 01/29/87 */ if (u.uswallow) { if (!u.ustuck->minvent) { if (is_animal(u.ustuck->data)) { You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck))); pline("But it's kind of slimy, so you drop it."); } else You("don't %s anything in here to pick up.", Blind ? "feel" : "see"); return 1; } else { int tmpcount = -count; return loot_mon(u.ustuck, &tmpcount, (boolean *) 0); } } if (is_pool(u.ux, u.uy)) { if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) || (Flying && !Breathless)) { You("cannot dive into the water to pick things up."); return 0; } else if (!Underwater) { You_cant("even see the bottom, let alone pick up %s.", something); return 0; } } if (is_lava(u.ux, u.uy)) { if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) || (Flying && !Breathless)) { You_cant("reach the bottom to pick things up."); return 0; } else if (!likes_lava(youmonst.data)) { You("would burn to a crisp trying to pick things up."); return 0; } } if (!OBJ_AT(u.ux, u.uy)) { register struct rm *lev = &levl[u.ux][u.uy]; if (IS_THRONE(lev->typ)) pline("It must weigh%s a ton!", lev->looted ? " almost" : ""); else if (IS_SINK(lev->typ)) pline_The("plumbing connects it to the floor."); else if (IS_GRAVE(lev->typ)) You("don't need a gravestone. Yet."); else if (IS_FOUNTAIN(lev->typ)) You("could drink the water..."); else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN)) pline("It won't come off the hinges."); else There("is nothing here to pick up."); return 0; } if (!can_reach_floor(TRUE)) { if (traphere && uteetering_at_seen_pit(traphere)) You("cannot reach the bottom of the pit."); else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) rider_cant_reach(); else if (Blind && !can_reach_floor(TRUE)) You("cannot reach anything here."); else You("cannot reach the %s.", surface(u.ux, u.uy)); return 0; } return pickup(-count); } /* stop running if we see something interesting */ /* turn around a corner if that is the only way we can proceed */ /* do not turn left or right twice */ void lookaround() { register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9; register int corrct = 0, noturn = 0; register struct monst *mtmp; register struct trap *trap; /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */ /* they polymorphed while in the middle of a long move. */ if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) { nomul(0); return; } if (Blind || context.run == 0) return; for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y)) continue; if (u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue; if (x == u.ux && y == u.uy) continue; if ((mtmp = m_at(x, y)) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) { if ((context.run != 1 && !mtmp->mtame) || (x == u.ux + u.dx && y == u.uy + u.dy)) goto stop; } if (levl[x][y].typ == STONE) continue; if (x == u.ux - u.dx && y == u.uy - u.dy) continue; if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) || IS_AIR(levl[x][y].typ)) continue; else if (closed_door(x, y) || (mtmp && is_door_mappear(mtmp))) { if (x != u.ux && y != u.uy) continue; if (context.run != 1) goto stop; goto bcorr; } else if (levl[x][y].typ == CORR) { bcorr: if (levl[u.ux][u.uy].typ != ROOM) { if (context.run == 1 || context.run == 3 || context.run == 8) { i = dist2(x, y, u.ux + u.dx, u.uy + u.dy); if (i > 2) continue; if (corrct == 1 && dist2(x, y, x0, y0) != 1) noturn = 1; if (i < i0) { i0 = i; x0 = x; y0 = y; m0 = mtmp ? 1 : 0; } } corrct++; } continue; } else if ((trap = t_at(x, y)) && trap->tseen) { if (context.run == 1) goto bcorr; /* if you must */ if (x == u.ux + u.dx && y == u.uy + u.dy) goto stop; continue; } else if (is_pool_or_lava(x, y)) { /* water and lava only stop you if directly in front, and stop * you even if you are running */ if (!Levitation && !Flying && !is_clinger(youmonst.data) && x == u.ux + u.dx && y == u.uy + u.dy) /* No Wwalking check; otherwise they'd be able * to test boots by trying to SHIFT-direction * into a pool and seeing if the game allowed it */ goto stop; continue; } else { /* e.g. objects or trap or stairs */ if (context.run == 1) goto bcorr; if (context.run == 8) continue; if (mtmp) continue; /* d */ if (((x == u.ux - u.dx) && (y != u.uy + u.dy)) || ((y == u.uy - u.dy) && (x != u.ux + u.dx))) continue; } stop: nomul(0); return; } /* end for loops */ if (corrct > 1 && context.run == 2) goto stop; if ((context.run == 1 || context.run == 3 || context.run == 8) && !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) { /* make sure that we do not turn too far */ if (i0 == 2) { if (u.dx == y0 - u.uy && u.dy == u.ux - x0) i = 2; /* straight turn right */ else i = -2; /* straight turn left */ } else if (u.dx && u.dy) { if ((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy)) i = -1; /* half turn left */ else i = 1; /* half turn right */ } else { if ((x0 - u.ux == y0 - u.uy && !u.dy) || (x0 - u.ux != y0 - u.uy && u.dy)) i = 1; /* half turn right */ else i = -1; /* half turn left */ } i += u.last_str_turn; if (i <= 2 && i >= -2) { u.last_str_turn = i; u.dx = x0 - u.ux; u.dy = y0 - u.uy; } } } /* check for a doorway which lacks its door (NODOOR or BROKEN) */ STATIC_OVL boolean doorless_door(x, y) int x, y; { struct rm *lev_p = &levl[x][y]; if (!IS_DOOR(lev_p->typ)) return FALSE; /* all rogue level doors are doorless but disallow diagonal access, so we treat them as if their non-existant doors were actually present */ if (Is_rogue_level(&u.uz)) return FALSE; return !(lev_p->doormask & ~(D_NODOOR | D_BROKEN)); } /* used by drown() to check whether hero can crawl from water to */ boolean crawl_destination(x, y) int x, y; { /* is location ok in general? */ if (!goodpos(x, y, &youmonst, 0)) return FALSE; /* orthogonal movement is unrestricted when destination is ok */ if (x == u.ux || y == u.uy) return TRUE; /* diagonal movement has some restrictions */ if (NODIAG(u.umonnum)) return FALSE; /* poly'd into a grid bug... */ if (Passes_walls) return TRUE; /* or a xorn... */ /* pool could be next to a door, conceivably even inside a shop */ if (IS_DOOR(levl[x][y].typ) && (!doorless_door(x, y) || block_door(x, y))) return FALSE; /* finally, are we trying to squeeze through a too-narrow gap? */ return !(bad_rock(youmonst.data, u.ux, y) && bad_rock(youmonst.data, x, u.uy)); } /* something like lookaround, but we are not running */ /* react only to monsters that might hit us */ int monster_nearby() { register int x, y; register struct monst *mtmp; /* Also see the similar check in dochugw() in monmove.c */ for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y)) continue; if (x == u.ux && y == u.uy) continue; if ((mtmp = m_at(x, y)) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT && (!mtmp->mpeaceful || Hallucination) && (!is_hider(mtmp->data) || !mtmp->mundetected) && !noattacks(mtmp->data) && mtmp->mcanmove && !mtmp->msleeping /* aplvax!jcn */ && !onscary(u.ux, u.uy, mtmp) && canspotmon(mtmp)) return 1; } return 0; } void nomul(nval) register int nval; { if (multi < nval) return; /* This is a bug fix by ab@unido */ u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */ u.usleep = 0; multi = nval; if (nval == 0) multi_reason = NULL; context.travel = context.travel1 = context.mv = context.run = 0; } /* called when a non-movement, multi-turn action has completed */ void unmul(msg_override) const char *msg_override; { multi = 0; /* caller will usually have done this already */ if (msg_override) nomovemsg = msg_override; else if (!nomovemsg) nomovemsg = You_can_move_again; if (*nomovemsg) pline1(nomovemsg); nomovemsg = 0; u.usleep = 0; multi_reason = NULL; if (afternmv) (*afternmv)(); afternmv = 0; } STATIC_OVL void maybe_wail() { static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES, SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES, TELEPORT_CONTROL, STEALTH, FAST, INVIS }; if (moves <= wailmsg + 50) return; wailmsg = moves; if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) { const char *who; int i, powercnt; who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m : "Elf"; if (u.uhp == 1) { pline("%s is about to die.", who); } else { for (i = 0, powercnt = 0; i < SIZE(powers); ++i) if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt; pline(powercnt >= 4 ? "%s, all your powers will be lost..." : "%s, your life force is running out.", who); } } else { You_hear(u.uhp == 1 ? "the wailing of the Banshee..." : "the howling of the CwnAnnwn..."); } } void losehp(n, knam, k_format) register int n; register const char *knam; boolean k_format; { if (Upolyd) { u.mh -= n; if (u.mhmax < u.mh) u.mhmax = u.mh; context.botl = 1; if (u.mh < 1) rehumanize(); else if (n > 0 && u.mh * 10 < u.mhmax && Unchanging) maybe_wail(); return; } u.uhp -= n; if (u.uhp > u.uhpmax) u.uhpmax = u.uhp; /* perhaps n was negative */ context.botl = 1; if (u.uhp < 1) { killer.format = k_format; if (killer.name != knam) /* the thing that killed you */ Strcpy(killer.name, knam ? knam : ""); You("die..."); done(DIED); } else if (n > 0 && u.uhp * 10 < u.uhpmax) { maybe_wail(); } } int weight_cap() { register long carrcap; carrcap = 25 * (ACURRSTR + ACURR(A_CON)) + 50; if (Upolyd) { /* consistent with can_carry() in mon.c */ if (youmonst.data->mlet == S_NYMPH) carrcap = MAX_CARR_CAP; else if (!youmonst.data->cwt) carrcap = (carrcap * (long) youmonst.data->msize) / MZ_HUMAN; else if (!strongmonst(youmonst.data) || (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN))) carrcap = (carrcap * (long) youmonst.data->cwt / WT_HUMAN); } if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */ || (u.usteed && strongmonst(u.usteed->data))) carrcap = MAX_CARR_CAP; else { if (carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP; if (!Flying) { if (EWounded_legs & LEFT_SIDE) carrcap -= 100; if (EWounded_legs & RIGHT_SIDE) carrcap -= 100; } if (carrcap < 0) carrcap = 0; } return (int) carrcap; } static int wc; /* current weight_cap(); valid after call to inv_weight() */ /* returns how far beyond the normal capacity the player is currently. */ /* inv_weight() is negative if the player is below normal capacity. */ int inv_weight() { register struct obj *otmp = invent; register int wt = 0; while (otmp) { if (otmp->oclass == COIN_CLASS) wt += (int) (((long) otmp->quan + 50L) / 100L); else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) wt += otmp->owt; otmp = otmp->nobj; } wc = weight_cap(); return (wt - wc); } /* * Returns 0 if below normal capacity, or the number of "capacity units" * over the normal capacity the player is loaded. Max is 5. */ int calc_capacity(xtra_wt) int xtra_wt; { int cap, wt = inv_weight() + xtra_wt; if (wt <= 0) return UNENCUMBERED; if (wc <= 1) return OVERLOADED; cap = (wt * 2 / wc) + 1; return min(cap, OVERLOADED); } int near_capacity() { return calc_capacity(0); } int max_capacity() { int wt = inv_weight(); return (wt - (2 * wc)); } boolean check_capacity(str) const char *str; { if (near_capacity() >= EXT_ENCUMBER) { if (str) pline1(str); else You_cant("do that while carrying so much stuff."); return 1; } return 0; } int inv_cnt(incl_gold) boolean incl_gold; { register struct obj *otmp = invent; register int ct = 0; while (otmp) { if (incl_gold || otmp->invlet != GOLD_SYM) ct++; otmp = otmp->nobj; } return ct; } /* Counts the money in an object chain. */ /* Intended use is for your or some monsters inventory, */ /* now that u.gold/m.gold is gone.*/ /* Counting money in a container might be possible too. */ long money_cnt(otmp) struct obj *otmp; { while (otmp) { /* Must change when silver & copper is implemented: */ if (otmp->oclass == COIN_CLASS) return otmp->quan; otmp = otmp->nobj; } return 0L; } /*hack.c*/ nethack-3.6.0/src/hacklib.c0000664000076400007660000006150712620077026014500 0ustar paxedpaxed/* NetHack 3.6 hacklib.c $NHDT-Date: 1446336792 2015/11/01 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Robert Patrick Rankin, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* for config.h+extern.h */ /*= Assorted 'small' utility routines. They're virtually independent of NetHack, except that rounddiv may call panic(). setrandom calls one of srandom(), srand48(), or srand() depending upon configuration. return type routine name argument type(s) boolean digit (char) boolean letter (char) char highc (char) char lowc (char) char * lcase (char *) char * ucase (char *) char * upstart (char *) char * mungspaces (char *) char * eos (char *) boolean str_end_is (const char *, const char *) char * strkitten (char *,char) void copynchars (char *,const char *,int) char chrcasecpy (int,int) char * strcasecpy (char *,const char *) char * s_suffix (const char *) char * ing_suffix (const char *) char * xcrypt (const char *, char *) boolean onlyspace (const char *) char * tabexpand (char *) char * visctrl (char) char * strsubst (char *, const char *, const char *) const char * ordin (int) char * sitoa (int) int sgn (int) int rounddiv (long, int) int distmin (int, int, int, int) int dist2 (int, int, int, int) boolean online2 (int, int) boolean pmatch (const char *, const char *) boolean pmatchi (const char *, const char *) boolean pmatchz (const char *, const char *) int strncmpi (const char *, const char *, int) char * strstri (const char *, const char *) boolean fuzzymatch (const char *,const char *, const char *, boolean) void setrandom (void) time_t getnow (void) int getyear (void) char * yymmdd (time_t) long yyyymmdd (time_t) long hhmmss (time_t) char * yyyymmddhhmmss (time_t) time_t time_from_yyyymmddhhmmss (char *) int phase_of_the_moon (void) boolean friday_13th (void) int night (void) int midnight (void) =*/ #ifdef LINT #define Static /* pacify lint */ #else #define Static static #endif static boolean FDECL(pmatch_internal, (const char *, const char *, BOOLEAN_P, const char *)); /* is 'c' a digit? */ boolean digit(c) char c; { return (boolean) ('0' <= c && c <= '9'); } /* is 'c' a letter? note: '@' classed as letter */ boolean letter(c) char c; { return (boolean) ('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); } /* force 'c' into uppercase */ char highc(c) char c; { return (char) (('a' <= c && c <= 'z') ? (c & ~040) : c); } /* force 'c' into lowercase */ char lowc(c) char c; { return (char) (('A' <= c && c <= 'Z') ? (c | 040) : c); } /* convert a string into all lowercase */ char * lcase(s) char *s; { register char *p; for (p = s; *p; p++) if ('A' <= *p && *p <= 'Z') *p |= 040; return s; } /* convert a string into all uppercase */ char * ucase(s) char *s; { register char *p; for (p = s; *p; p++) if ('a' <= *p && *p <= 'z') *p &= ~040; return s; } /* convert first character of a string to uppercase */ char * upstart(s) char *s; { if (s) *s = highc(*s); return s; } /* remove excess whitespace from a string buffer (in place) */ char * mungspaces(bp) char *bp; { register char c, *p, *p2; boolean was_space = TRUE; for (p = p2 = bp; (c = *p) != '\0'; p++) { if (c == '\n') break; /* treat newline the same as end-of-string */ if (c == '\t') c = ' '; if (c != ' ' || !was_space) *p2++ = c; was_space = (c == ' '); } if (was_space && p2 > bp) p2--; *p2 = '\0'; return bp; } /* return the end of a string (pointing at '\0') */ char * eos(s) register char *s; { while (*s) s++; /* s += strlen(s); */ return s; } /* determine whether 'str' ends in 'chkstr' */ boolean str_end_is(str, chkstr) const char *str, *chkstr; { int clen = (int) strlen(chkstr); if ((int) strlen(str) >= clen) return (boolean) (!strncmp(eos((char *) str) - clen, chkstr, clen)); return FALSE; } /* append a character to a string (in place): strcat(s, {c,'\0'}); */ char * strkitten(s, c) char *s; char c; { char *p = eos(s); *p++ = c; *p = '\0'; return s; } /* truncating string copy */ void copynchars(dst, src, n) char *dst; const char *src; int n; { /* copies at most n characters, stopping sooner if terminator reached; treats newline as input terminator; unlike strncpy, always supplies '\0' terminator so dst must be able to hold at least n+1 characters */ while (n > 0 && *src != '\0' && *src != '\n') { *dst++ = *src++; --n; } *dst = '\0'; } /* convert char nc into oc's case; mostly used by strcasecpy */ char chrcasecpy(oc, nc) int oc, nc; { #if 0 /* this will be necessary if we switch to */ oc = (int) (unsigned char) oc; nc = (int) (unsigned char) nc; #endif if ('a' <= oc && oc <= 'z') { /* old char is lower case; if new char is upper case, downcase it */ if ('A' <= nc && nc <= 'Z') nc += 'a' - 'A'; /* lowc(nc) */ } else if ('A' <= oc && oc <= 'Z') { /* old char is upper case; if new char is lower case, upcase it */ if ('a' <= nc && nc <= 'z') nc += 'A' - 'a'; /* highc(nc) */ } return (char) nc; } /* overwrite string, preserving old chars' case; for case-insensitive editions of makeplural() and makesingular(); src might be shorter, same length, or longer than dst */ char * strcasecpy(dst, src) char *dst; const char *src; { char *result = dst; int ic, oc, dst_exhausted = 0; /* while dst has characters, replace each one with corresponding character from src, converting case in the process if they differ; once dst runs out, propagate the case of its last character to any remaining src; if dst starts empty, it must be a pointer to the tail of some other string because we examine the char at dst[-1] */ while ((ic = (int) *src++) != '\0') { if (!dst_exhausted && !*dst) dst_exhausted = 1; oc = (int) *(dst - dst_exhausted); *dst++ = chrcasecpy(oc, ic); } *dst = '\0'; return result; } /* return a name converted to possessive */ char * s_suffix(s) const char *s; { Static char buf[BUFSZ]; Strcpy(buf, s); if (!strcmpi(buf, "it")) /* it -> its */ Strcat(buf, "s"); else if (!strcmpi(buf, "you")) /* you -> your */ Strcat(buf, "r"); else if (*(eos(buf) - 1) == 's') /* Xs -> Xs' */ Strcat(buf, "'"); else /* X -> X's */ Strcat(buf, "'s"); return buf; } /* construct a gerund (a verb formed by appending "ing" to a noun) */ char * ing_suffix(s) const char *s; { const char *vowel = "aeiouy"; static char buf[BUFSZ]; char onoff[10]; char *p; Strcpy(buf, s); p = eos(buf); onoff[0] = *p = *(p + 1) = '\0'; if ((strlen(buf) > 4) && (!strcmpi(p - 3, " on") || !strcmpi(p - 4, " off") || !strcmpi(p - 5, " with"))) { p = strrchr(buf, ' '); Strcpy(onoff, p); } if (!index(vowel, *(p - 1)) && index(vowel, *(p - 2)) && !index(vowel, *(p - 3))) { /* tip -> tipp + ing */ *p = *(p - 1); *(p + 1) = '\0'; } else if (!strcmpi(p - 2, "ie")) { /* vie -> vy + ing */ *(p - 2) = 'y'; *(p - 1) = '\0'; } else if (*(p - 1) == 'e') /* grease -> greas + ing */ *(p - 1) = '\0'; Strcat(buf, "ing"); if (onoff[0]) Strcat(buf, onoff); return buf; } /* trivial text encryption routine (see makedefs) */ char * xcrypt(str, buf) const char *str; char *buf; { register const char *p; register char *q; register int bitmask; for (bitmask = 1, p = str, q = buf; *p; q++) { *q = *p++; if (*q & (32 | 64)) *q ^= bitmask; if ((bitmask <<= 1) >= 32) bitmask = 1; } *q = '\0'; return buf; } /* is a string entirely whitespace? */ boolean onlyspace(s) const char *s; { for (; *s; s++) if (*s != ' ' && *s != '\t') return FALSE; return TRUE; } /* expand tabs into proper number of spaces */ char * tabexpand(sbuf) char *sbuf; { char buf[BUFSZ]; register char *bp, *s = sbuf; register int idx; if (!*s) return sbuf; /* warning: no bounds checking performed */ for (bp = buf, idx = 0; *s; s++) if (*s == '\t') { do *bp++ = ' '; while (++idx % 8); } else { *bp++ = *s; idx++; } *bp = 0; return strcpy(sbuf, buf); } /* make a displayable string from a character */ char * visctrl(c) char c; { Static char ccc[3]; c &= 0177; ccc[2] = '\0'; if (c < 040) { ccc[0] = '^'; ccc[1] = c | 0100; /* letter */ } else if (c == 0177) { ccc[0] = '^'; ccc[1] = c & ~0100; /* '?' */ } else { ccc[0] = c; /* printable character */ ccc[1] = '\0'; } return ccc; } /* substitute a word or phrase in a string (in place) */ /* caller is responsible for ensuring that bp points to big enough buffer */ char * strsubst(bp, orig, replacement) char *bp; const char *orig, *replacement; { char *found, buf[BUFSZ]; if (bp) { found = strstr(bp, orig); if (found) { Strcpy(buf, found + strlen(orig)); Strcpy(found, replacement); Strcat(bp, buf); } } return bp; } /* return the ordinal suffix of a number */ const char * ordin(n) int n; /* note: should be non-negative */ { register int dd = n % 10; return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" : (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd"; } /* make a signed digit string from a number */ char * sitoa(n) int n; { Static char buf[13]; Sprintf(buf, (n < 0) ? "%d" : "+%d", n); return buf; } /* return the sign of a number: -1, 0, or 1 */ int sgn(n) int n; { return (n < 0) ? -1 : (n != 0); } /* calculate x/y, rounding as appropriate */ int rounddiv(x, y) long x; int y; { int r, m; int divsgn = 1; if (y == 0) panic("division by zero in rounddiv"); else if (y < 0) { divsgn = -divsgn; y = -y; } if (x < 0) { divsgn = -divsgn; x = -x; } r = x / y; m = x % y; if (2 * m >= y) r++; return divsgn * r; } /* distance between two points, in moves */ int distmin(x0, y0, x1, y1) int x0, y0, x1, y1; { register int dx = x0 - x1, dy = y0 - y1; if (dx < 0) dx = -dx; if (dy < 0) dy = -dy; /* The minimum number of moves to get from (x0,y0) to (x1,y1) is the * larger of the [absolute value of the] two deltas. */ return (dx < dy) ? dy : dx; } /* square of euclidean distance between pair of pts */ int dist2(x0, y0, x1, y1) int x0, y0, x1, y1; { register int dx = x0 - x1, dy = y0 - y1; return dx * dx + dy * dy; } /* integer square root function without using floating point */ int isqrt(val) int val; { int rt = 0; int odd = 1; /* * This could be replaced by a faster algorithm, but has not been because: * + the simple algorithm is easy to read; * + this algorithm does not require 64-bit support; * + in current usage, the values passed to isqrt() are not really that * large, so the performance difference is negligible; * + isqrt() is used in only few places, which are not bottle-necks. */ while (val >= odd) { val = val - odd; odd = odd + 2; rt = rt + 1; } return rt; } /* are two points lined up (on a straight line)? */ boolean online2(x0, y0, x1, y1) int x0, y0, x1, y1; { int dx = x0 - x1, dy = y0 - y1; /* If either delta is zero then they're on an orthogonal line, * else if the deltas are equal (signs ignored) they're on a diagonal. */ return (boolean) (!dy || !dx || dy == dx || dy == -dx); } /* guts of pmatch(), pmatchi(), and pmatchz(); match a string against a pattern */ static boolean pmatch_internal(patrn, strng, ci, sk) const char *patrn, *strng; boolean ci; /* True => case-insensitive, False => case-sensitive */ const char *sk; /* set of characters to skip */ { char s, p; /* * Simple pattern matcher: '*' matches 0 or more characters, '?' matches * any single character. Returns TRUE if 'strng' matches 'patrn'. */ pmatch_top: if (!sk) { s = *strng++; p = *patrn++; /* get next chars and pre-advance */ } else { /* fuzzy match variant of pmatch; particular characters are ignored */ do { s = *strng++; } while (index(sk, s)); do { p = *patrn++; } while (index(sk, p)); } if (!p) /* end of pattern */ return (boolean) (s == '\0'); /* matches iff end of string too */ else if (p == '*') /* wildcard reached */ return (boolean) ((!*patrn || pmatch_internal(patrn, strng - 1, ci, sk)) ? TRUE : s ? pmatch_internal(patrn - 1, strng, ci, sk) : FALSE); else if ((ci ? lowc(p) != lowc(s) : p != s) /* check single character */ && (p != '?' || !s)) /* & single-char wildcard */ return FALSE; /* doesn't match */ else /* return pmatch_internal(patrn, strng, ci, sk); */ goto pmatch_top; /* optimize tail recursion */ } /* case-sensitive wildcard match */ boolean pmatch(patrn, strng) const char *patrn, *strng; { return pmatch_internal(patrn, strng, FALSE, (const char *) 0); } /* case-insensitive wildcard match */ boolean pmatchi(patrn, strng) const char *patrn, *strng; { return pmatch_internal(patrn, strng, TRUE, (const char *) 0); } /* case-insensitive wildcard fuzzymatch */ boolean pmatchz(patrn, strng) const char *patrn, *strng; { /* ignore spaces, tabs (just in case), dashes, and underscores */ static const char fuzzychars[] = " \t-_"; return pmatch_internal(patrn, strng, TRUE, fuzzychars); } #ifndef STRNCMPI /* case insensitive counted string comparison */ int strncmpi(s1, s2, n) /*{ aka strncasecmp }*/ register const char *s1, *s2; register int n; /*(should probably be size_t, which is unsigned)*/ { register char t1, t2; while (n--) { if (!*s2) return (*s1 != 0); /* s1 >= s2 */ else if (!*s1) return -1; /* s1 < s2 */ t1 = lowc(*s1++); t2 = lowc(*s2++); if (t1 != t2) return (t1 > t2) ? 1 : -1; } return 0; /* s1 == s2 */ } #endif /* STRNCMPI */ #ifndef STRSTRI /* case insensitive substring search */ char * strstri(str, sub) const char *str; const char *sub; { register const char *s1, *s2; register int i, k; #define TABSIZ 0x20 /* 0x40 would be case-sensitive */ char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */ #if 0 assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */ assert( &lowc != 0 ); /* can't be unsafe macro */ #endif /* special case: empty substring */ if (!*sub) return (char *) str; /* do some useful work while determining relative lengths */ for (i = 0; i < TABSIZ; i++) tstr[i] = tsub[i] = 0; /* init */ for (k = 0, s1 = str; *s1; k++) tstr[*s1++ & (TABSIZ - 1)]++; for (s2 = sub; *s2; --k) tsub[*s2++ & (TABSIZ - 1)]++; /* evaluate the info we've collected */ if (k < 0) return (char *) 0; /* sub longer than str, so can't match */ for (i = 0; i < TABSIZ; i++) /* does sub have more 'x's than str? */ if (tsub[i] > tstr[i]) return (char *) 0; /* match not possible */ /* now actually compare the substring repeatedly to parts of the string */ for (i = 0; i <= k; i++) { s1 = &str[i]; s2 = sub; while (lowc(*s1++) == lowc(*s2++)) if (!*s2) return (char *) &str[i]; /* full match */ } return (char *) 0; /* not found */ } #endif /* STRSTRI */ /* compare two strings for equality, ignoring the presence of specified characters (typically whitespace) and possibly ignoring case */ boolean fuzzymatch(s1, s2, ignore_chars, caseblind) const char *s1, *s2; const char *ignore_chars; boolean caseblind; { register char c1, c2; do { while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue; while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue; if (!c1 || !c2) break; /* stop when end of either string is reached */ if (caseblind) { c1 = lowc(c1); c2 = lowc(c2); } } while (c1 == c2); /* match occurs only when the end of both strings has been reached */ return (boolean) (!c1 && !c2); } /* * Time routines * * The time is used for: * - seed for rand() * - year on tombstone and yyyymmdd in record file * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON) * - night and midnight (the undead are dangerous at midnight) * - determination of what files are "very old" */ /* TIME_type: type of the argument to time(); we actually use &(time_t) */ #if defined(BSD) && !defined(POSIX_TYPES) #define TIME_type long * #else #define TIME_type time_t * #endif /* LOCALTIME_type: type of the argument to localtime() */ #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ || (defined(BSD) && !defined(POSIX_TYPES)) #define LOCALTIME_type long * #else #define LOCALTIME_type time_t * #endif #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \ && !defined(_DCC) && !defined(__GNUC__) extern struct tm *FDECL(localtime, (time_t *)); #endif STATIC_DCL struct tm *NDECL(getlt); void setrandom() { unsigned long seed = (unsigned long) getnow(); /* time((TIME_type) 0) */ #if defined(UNIX) || defined(VMS) { unsigned long pid = (unsigned long) getpid(); /* Quick dirty band-aid to prevent PRNG prediction */ if (pid) { if (!(pid & 3L)) pid -= 1L; seed *= pid; } } #endif /* the types are different enough here that sweeping the different * routine names into one via #defines is even more confusing */ #ifdef RANDOM /* srandom() from sys/share/random.c */ srandom((unsigned int) seed); #else #if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \ || defined(CYGWIN32) /* system srandom() */ #if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4) (void) #endif srandom((int) seed); #else #ifdef UNIX /* system srand48() */ srand48((long) seed); #else /* poor quality system routine */ srand((int) seed); #endif #endif #endif } time_t getnow() { time_t datetime = 0; (void) time((TIME_type) &datetime); return datetime; } STATIC_OVL struct tm * getlt() { time_t date = getnow(); return localtime((LOCALTIME_type) &date); } int getyear() { return (1900 + getlt()->tm_year); } #if 0 /* This routine is no longer used since in 20YY it yields "1YYmmdd". */ char * yymmdd(date) time_t date; { Static char datestr[10]; struct tm *lt; if (date == 0) lt = getlt(); else lt = localtime((LOCALTIME_type) &date); Sprintf(datestr, "%02d%02d%02d", lt->tm_year, lt->tm_mon + 1, lt->tm_mday); return datestr; } #endif long yyyymmdd(date) time_t date; { long datenum; struct tm *lt; if (date == 0) lt = getlt(); else lt = localtime((LOCALTIME_type) &date); /* just in case somebody's localtime supplies (year % 100) rather than the expected (year - 1900) */ if (lt->tm_year < 70) datenum = (long) lt->tm_year + 2000L; else datenum = (long) lt->tm_year + 1900L; /* yyyy --> yyyymm */ datenum = datenum * 100L + (long) (lt->tm_mon + 1); /* yyyymm --> yyyymmdd */ datenum = datenum * 100L + (long) lt->tm_mday; return datenum; } long hhmmss(date) time_t date; { long timenum; struct tm *lt; if (date == 0) lt = getlt(); else lt = localtime((LOCALTIME_type) &date); timenum = lt->tm_hour * 10000L + lt->tm_min * 100L + lt->tm_sec; return timenum; } char * yyyymmddhhmmss(date) time_t date; { long datenum; static char datestr[15]; struct tm *lt; if (date == 0) lt = getlt(); else #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ || defined(BSD) lt = localtime((long *) (&date)); #else lt = localtime(&date); #endif /* just in case somebody's localtime supplies (year % 100) rather than the expected (year - 1900) */ if (lt->tm_year < 70) datenum = (long) lt->tm_year + 2000L; else datenum = (long) lt->tm_year + 1900L; Sprintf(datestr, "%04ld%02d%02d%02d%02d%02d", datenum, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec); debugpline1("yyyymmddhhmmss() produced date string %s", datestr); return datestr; } time_t time_from_yyyymmddhhmmss(buf) char *buf; { int k; time_t timeresult = (time_t) 0; struct tm t, *lt; char *g, *p, y[5], mo[3], md[3], h[3], mi[3], s[3]; if (buf && strlen(buf) == 14) { g = buf; p = y; /* year */ for (k = 0; k < 4; ++k) *p++ = *g++; *p = '\0'; p = mo; /* month */ for (k = 0; k < 2; ++k) *p++ = *g++; *p = '\0'; p = md; /* day */ for (k = 0; k < 2; ++k) *p++ = *g++; *p = '\0'; p = h; /* hour */ for (k = 0; k < 2; ++k) *p++ = *g++; *p = '\0'; p = mi; /* minutes */ for (k = 0; k < 2; ++k) *p++ = *g++; *p = '\0'; p = s; /* seconds */ for (k = 0; k < 2; ++k) *p++ = *g++; *p = '\0'; lt = getlt(); if (lt) { t = *lt; t.tm_year = atoi(y) - 1900; t.tm_mon = atoi(mo) - 1; t.tm_mday = atoi(md); t.tm_hour = atoi(h); t.tm_min = atoi(mi); t.tm_sec = atoi(s); timeresult = mktime(&t); } if ((int) timeresult == -1) debugpline1("time_from_yyyymmddhhmmss(%s) would have returned -1", buf ? buf : ""); else return timeresult; } return (time_t) 0; } /* * moon period = 29.53058 days ~= 30, year = 365.2422 days * days moon phase advances on first day of year compared to preceding year * = 365.2422 - 12*29.53058 ~= 11 * years in Metonic cycle (time until same phases fall on the same days of * the month) = 18.6 ~= 19 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 * (29 as initial condition) * current phase in days = first day phase + days elapsed in year * 6 moons ~= 177 days * 177 ~= 8 reported phases * 22 * + 11/22 for rounding */ int phase_of_the_moon() /* 0-7, with 0: new, 4: full */ { register struct tm *lt = getlt(); register int epact, diy, goldn; diy = lt->tm_yday; goldn = (lt->tm_year % 19) + 1; epact = (11 * goldn + 18) % 30; if ((epact == 25 && goldn > 11) || epact == 24) epact++; return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7); } boolean friday_13th() { register struct tm *lt = getlt(); /* tm_wday (day of week; 0==Sunday) == 5 => Friday */ return (boolean) (lt->tm_wday == 5 && lt->tm_mday == 13); } int night() { register int hour = getlt()->tm_hour; return (hour < 6 || hour > 21); } int midnight() { return (getlt()->tm_hour == 0); } /*hacklib.c*/ nethack-3.6.0/src/invent.c0000664000076400007660000034745112622262031014405 0ustar paxedpaxed/* NetHack 3.6 invent.c $NHDT-Date: 1447576348 2015/11/15 08:32:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.179 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #define NOINVSYM '#' #define CONTAINED_SYM '>' /* designator for inside a container */ STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *)); STATIC_DCL void NDECL(reorder_invent); STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *)); STATIC_DCL void FDECL(noarmor, (BOOLEAN_P)); STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *)); STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *)); STATIC_DCL boolean FDECL(only_here, (struct obj *)); STATIC_DCL void FDECL(compactify, (char *)); STATIC_DCL boolean FDECL(splittable, (struct obj *)); STATIC_DCL boolean FDECL(taking_off, (const char *)); STATIC_DCL boolean FDECL(putting_on, (const char *)); STATIC_PTR int FDECL(ckunpaid, (struct obj *)); STATIC_PTR int FDECL(ckvalidcat, (struct obj *)); STATIC_PTR char *FDECL(safeq_xprname, (struct obj *)); STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *)); STATIC_DCL char FDECL(display_pickinv, (const char *, BOOLEAN_P, long *)); STATIC_DCL char FDECL(display_used_invlets, (CHAR_P)); STATIC_DCL void FDECL(tally_BUCX, (struct obj *, int *, int *, int *, int *, int *)); STATIC_DCL boolean FDECL(this_type_only, (struct obj *)); STATIC_DCL void NDECL(dounpaid); STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **)); STATIC_DCL void FDECL(menu_identify, (int)); STATIC_DCL boolean FDECL(tool_in_use, (struct obj *)); STATIC_DCL char FDECL(obj_to_let, (struct obj *)); static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */ /* wizards can wish for venom, which will become an invisible inventory * item without this. putting it in inv_order would mean venom would * suddenly become a choice for all the inventory-class commands, which * would probably cause mass confusion. the test for inventory venom * is only WIZARD and not wizard because the wizard can leave venom lying * around on a bones level for normal players to find. [Note to the * confused: 'WIZARD' used to be a compile-time conditional so this was * guarded by #ifdef WIZARD/.../#endif.] */ static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */ STATIC_OVL int CFDECLSPEC sortloot_cmp(obj1, obj2) struct obj *obj1; struct obj *obj2; { int val1 = 0; int val2 = 0; /* Sort object names in lexicographical order, ignoring quantity. */ int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2)); if (name_cmp != 0) { return name_cmp; } /* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown * to 0. */ val1 = obj1->bknown ? (obj1->blessed << 2) + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed : 0; val2 = obj2->bknown ? (obj2->blessed << 2) + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed : 0; if (val1 != val2) { return val2 - val1; /* Because bigger is better. */ } /* Sort by greasing. This will put the objects in degreasing order. */ val1 = obj1->greased; val2 = obj2->greased; if (val1 != val2) { return val2 - val1; /* Because bigger is better. */ } /* Sort by erosion. The effective amount is what matters. */ val1 = greatest_erosion(obj1); val2 = greatest_erosion(obj2); if (val1 != val2) { return val1 - val2; /* Because bigger is WORSE. */ } /* Sort by erodeproofing. Map known-invulnerable to 1, and both * known-vulnerable and unknown-vulnerability to 0, because that's how * they're displayed. */ val1 = obj1->rknown && obj1->oerodeproof; val2 = obj2->rknown && obj2->oerodeproof; if (val1 != val2) { return val2 - val1; /* Because bigger is better. */ } /* Sort by enchantment. Map unknown to -1000, which is comfortably below * the range of ->spe. */ val1 = obj1->known ? obj1->spe : -1000; val2 = obj2->known ? obj2->spe : -1000; if (val1 != val2) { return val2 - val1; /* Because bigger is better. */ } /* They're identical, as far as we're concerned, but we want to force a determistic order between them. */ return (obj1->o_id > obj2->o_id) ? 1 : -1; } struct obj ** objarr_init(n) int n; { return (struct obj **) alloc(n * sizeof(struct obj *)); } void objarr_set(otmp, idx, oarray, dosort) struct obj *otmp; int idx; struct obj **oarray; boolean dosort; { if (dosort) { int j; for (j = idx; j; j--) { if (sortloot_cmp(otmp, oarray[j - 1]) > 0) break; oarray[j] = oarray[j - 1]; } oarray[j] = otmp; } else { oarray[idx] = otmp; } } void assigninvlet(otmp) register struct obj *otmp; { boolean inuse[52]; register int i; register struct obj *obj; /* there should be at most one of these in inventory... */ if (otmp->oclass == COIN_CLASS) { otmp->invlet = GOLD_SYM; return; } for (i = 0; i < 52; i++) inuse[i] = FALSE; for (obj = invent; obj; obj = obj->nobj) if (obj != otmp) { i = obj->invlet; if ('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else if ('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE; if (i == otmp->invlet) otmp->invlet = 0; } if ((i = otmp->invlet) && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z'))) return; for (i = lastinvnr + 1; i != lastinvnr; i++) { if (i == 52) { i = -1; continue; } if (!inuse[i]) break; } otmp->invlet = (inuse[i] ? NOINVSYM : (i < 26) ? ('a' + i) : ('A' + i - 26)); lastinvnr = i; } /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */ #define inv_rank(o) ((o)->invlet ^ 040) /* sort the inventory; used by addinv() and doorganize() */ STATIC_OVL void reorder_invent() { struct obj *otmp, *prev, *next; boolean need_more_sorting; do { /* * We expect at most one item to be out of order, so this * isn't nearly as inefficient as it may first appear. */ need_more_sorting = FALSE; for (otmp = invent, prev = 0; otmp;) { next = otmp->nobj; if (next && inv_rank(next) < inv_rank(otmp)) { need_more_sorting = TRUE; if (prev) prev->nobj = next; else invent = next; otmp->nobj = next->nobj; next->nobj = otmp; prev = next; } else { prev = otmp; otmp = next; } } } while (need_more_sorting); } #undef inv_rank /* scan a list of objects to see whether another object will merge with one of them; used in pickup.c when all 52 inventory slots are in use, to figure out whether another object could still be picked up */ struct obj * merge_choice(objlist, obj) struct obj *objlist, *obj; { struct monst *shkp; int save_nocharge; if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */ return (struct obj *) 0; /* if this is an item on the shop floor, the attributes it will have when carried are different from what they are now; prevent that from eliciting an incorrect result from mergable() */ save_nocharge = obj->no_charge; if (objlist == invent && obj->where == OBJ_FLOOR && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) { if (obj->no_charge) obj->no_charge = 0; /* A billable object won't have its `unpaid' bit set, so would erroneously seem to be a candidate to merge with a similar ordinary object. That's no good, because once it's really picked up, it won't merge after all. It might merge with another unpaid object, but we can't check that here (depends too much upon shk's bill) and if it doesn't merge it would end up in the '#' overflow inventory slot, so reject it now. */ else if (inhishop(shkp)) return (struct obj *) 0; } while (objlist) { if (mergable(objlist, obj)) break; objlist = objlist->nobj; } obj->no_charge = save_nocharge; return objlist; } /* merge obj with otmp and delete obj if types agree */ int merged(potmp, pobj) struct obj **potmp, **pobj; { register struct obj *otmp = *potmp, *obj = *pobj; if (mergable(otmp, obj)) { /* Approximate age: we do it this way because if we were to * do it "accurately" (merge only when ages are identical) * we'd wind up never merging any corpses. * otmp->age = otmp->age*(1-proportion) + obj->age*proportion; * * Don't do the age manipulation if lit. We would need * to stop the burn on both items, then merge the age, * then restart the burn. */ if (!obj->lamplit) otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan)) / (otmp->quan + obj->quan); otmp->quan += obj->quan; /* temporary special case for gold objects!!!! */ if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp); /* and puddings!!!1!!one! */ else if (!Is_pudding(otmp)) otmp->owt += obj->owt; if (!has_oname(otmp) && has_oname(obj)) otmp = *potmp = oname(otmp, ONAME(obj)); obj_extract_self(obj); /* really should merge the timeouts */ if (obj->lamplit) obj_merge_light_sources(obj, otmp); if (obj->timed) obj_stop_timers(obj); /* follows lights */ /* fixup for `#adjust' merging wielded darts, daggers, &c */ if (obj->owornmask && carried(otmp)) { long wmask = otmp->owornmask | obj->owornmask; /* Both the items might be worn in competing slots; merger preference (regardless of which is which): primary weapon + alternate weapon -> primary weapon; primary weapon + quiver -> primary weapon; alternate weapon + quiver -> alternate weapon. (Prior to 3.3.0, it was not possible for the two stacks to be worn in different slots and `obj' didn't need to be unworn when merging.) */ if (wmask & W_WEP) wmask = W_WEP; else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP; else if (wmask & W_QUIVER) wmask = W_QUIVER; else { impossible("merging strangely worn items (%lx)", wmask); wmask = otmp->owornmask; } if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp); setworn(otmp, wmask); setnotworn(obj); #if 0 /* (this should not be necessary, since items already in a monster's inventory don't ever get merged into other objects [only vice versa]) */ } else if (obj->owornmask && mcarried(otmp)) { if (obj == MON_WEP(otmp->ocarry)) { MON_WEP(otmp->ocarry) = otmp; otmp->owornmask = W_WEP; } #endif /*0*/ } /* handle puddings a bit differently; absorption will * free the other object automatically so we can just * return out from here. */ if (Is_pudding(obj)) { pudding_merge_message(otmp, obj); obj_absorb(potmp, pobj); return 1; } obfree(obj, otmp); /* free(obj), bill->otmp */ return 1; } return 0; } /* * Adjust hero intrinsics as if this object was being added to the hero's * inventory. Called _before_ the object has been added to the hero's * inventory. * * This is called when adding objects to the hero's inventory normally (via * addinv) or when an object in the hero's inventory has been polymorphed * in-place. * * It may be valid to merge this code with with addinv_core2(). */ void addinv_core1(obj) struct obj *obj; { if (obj->oclass == COIN_CLASS) { context.botl = 1; } else if (obj->otyp == AMULET_OF_YENDOR) { if (u.uhave.amulet) impossible("already have amulet?"); u.uhave.amulet = 1; u.uachieve.amulet = 1; } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { if (u.uhave.menorah) impossible("already have candelabrum?"); u.uhave.menorah = 1; u.uachieve.menorah = 1; } else if (obj->otyp == BELL_OF_OPENING) { if (u.uhave.bell) impossible("already have silver bell?"); u.uhave.bell = 1; u.uachieve.bell = 1; } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (u.uhave.book) impossible("already have the book?"); u.uhave.book = 1; u.uachieve.book = 1; } else if (obj->oartifact) { if (is_quest_artifact(obj)) { if (u.uhave.questart) impossible("already have quest artifact?"); u.uhave.questart = 1; artitouch(obj); } set_artifact_intrinsic(obj, 1, W_ART); } if (obj->otyp == LUCKSTONE && obj->record_achieve_special) { u.uachieve.mines_luckstone = 1; obj->record_achieve_special = 0; } else if ((obj->otyp == AMULET_OF_REFLECTION || obj->otyp == BAG_OF_HOLDING) && obj->record_achieve_special) { u.uachieve.finish_sokoban = 1; obj->record_achieve_special = 0; } } /* * Adjust hero intrinsics as if this object was being added to the hero's * inventory. Called _after_ the object has been added to the hero's * inventory. * * This is called when adding objects to the hero's inventory normally (via * addinv) or when an object in the hero's inventory has been polymorphed * in-place. */ void addinv_core2(obj) struct obj *obj; { if (confers_luck(obj)) { /* new luckstone must be in inventory by this point * for correct calculation */ set_moreluck(); } } /* * Add obj to the hero's inventory. Make sure the object is "free". * Adjust hero attributes as necessary. */ struct obj * addinv(obj) struct obj *obj; { struct obj *otmp, *prev; int saved_otyp = (int) obj->otyp; /* for panic */ if (obj->where != OBJ_FREE) panic("addinv: obj not free"); /* normally addtobill() clears no_charge when items in a shop are picked up, but won't do so if the shop has become untended */ obj->no_charge = 0; /* should not be set in hero's invent */ if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ obj->was_thrown = 0; /* not meaningful for invent */ addinv_core1(obj); /* merge with quiver in preference to any other inventory slot in case quiver and wielded weapon are both eligible; adding extra to quivered stack is more useful than to wielded one */ if (uquiver && merged(&uquiver, &obj)) { obj = uquiver; if (!obj) panic("addinv: null obj after quiver merge otyp=%d", saved_otyp); goto added; } /* merge if possible; find end of chain in the process */ for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj) if (merged(&otmp, &obj)) { obj = otmp; if (!obj) panic("addinv: null obj after merge otyp=%d", saved_otyp); goto added; } /* didn't merge, so insert into chain */ assigninvlet(obj); if (flags.invlet_constant || !prev) { obj->nobj = invent; /* insert at beginning */ invent = obj; if (flags.invlet_constant) reorder_invent(); } else { prev->nobj = obj; /* insert at end */ obj->nobj = 0; } obj->where = OBJ_INVENT; added: addinv_core2(obj); carry_obj_effects(obj); /* carrying affects the obj */ update_inventory(); return obj; } /* * Some objects are affected by being carried. * Make those adjustments here. Called _after_ the object * has been added to the hero's or monster's inventory, * and after hero's intrinsics have been updated. */ void carry_obj_effects(obj) struct obj *obj; { /* Cursed figurines can spontaneously transform when carried. */ if (obj->otyp == FIGURINE) { if (obj->cursed && obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)) { attach_fig_transform_timeout(obj); } } } /* Add an item to the inventory unless we're fumbling or it refuses to be * held (via touch_artifact), and give a message. * If there aren't any free inventory slots, we'll drop it instead. * If both success and failure messages are NULL, then we're just doing the * fumbling/slot-limit checking for a silent grab. In any case, * touch_artifact will print its own messages if they are warranted. */ struct obj * hold_another_object(obj, drop_fmt, drop_arg, hold_msg) struct obj *obj; const char *drop_fmt, *drop_arg, *hold_msg; { char buf[BUFSZ]; if (!Blind) obj->dknown = 1; /* maximize mergibility */ if (obj->oartifact) { /* place_object may change these */ boolean crysknife = (obj->otyp == CRYSKNIFE); int oerode = obj->oerodeproof; boolean wasUpolyd = Upolyd; /* in case touching this object turns out to be fatal */ place_object(obj, u.ux, u.uy); if (!touch_artifact(obj, &youmonst)) { obj_extract_self(obj); /* remove it from the floor */ dropy(obj); /* now put it back again :-) */ return obj; } else if (wasUpolyd && !Upolyd) { /* loose your grip if you revert your form */ if (drop_fmt) pline(drop_fmt, drop_arg); obj_extract_self(obj); dropy(obj); return obj; } obj_extract_self(obj); if (crysknife) { obj->otyp = CRYSKNIFE; obj->oerodeproof = oerode; } } if (Fumbling) { if (drop_fmt) pline(drop_fmt, drop_arg); dropy(obj); } else { long oquan = obj->quan; int prev_encumbr = near_capacity(); /* before addinv() */ /* encumbrance only matters if it would now become worse than max( current_value, stressed ) */ if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER; /* addinv() may redraw the entire inventory, overwriting drop_arg when it comes from something like doname() */ if (drop_arg) drop_arg = strcpy(buf, drop_arg); obj = addinv(obj); if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed) && near_capacity() > prev_encumbr)) { if (drop_fmt) pline(drop_fmt, drop_arg); /* undo any merge which took place */ if (obj->quan > oquan) obj = splitobj(obj, oquan); dropx(obj); } else { if (flags.autoquiver && !uquiver && !obj->owornmask && (is_missile(obj) || ammo_and_launcher(obj, uwep) || ammo_and_launcher(obj, uswapwep))) setuqwep(obj); if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan); } } return obj; } /* useup() all of an item regardless of its quantity */ void useupall(obj) struct obj *obj; { setnotworn(obj); freeinv(obj); obfree(obj, (struct obj *) 0); /* deletes contents also */ } void useup(obj) register struct obj *obj; { /* Note: This works correctly for containers because they (containers) don't merge. */ if (obj->quan > 1L) { obj->in_use = FALSE; /* no longer in use */ obj->quan--; obj->owt = weight(obj); update_inventory(); } else { useupall(obj); } } /* use one charge from an item and possibly incur shop debt for it */ void consume_obj_charge(obj, maybe_unpaid) struct obj *obj; boolean maybe_unpaid; /* false if caller handles shop billing */ { if (maybe_unpaid) check_unpaid(obj); obj->spe -= 1; if (obj->known) update_inventory(); } /* * Adjust hero's attributes as if this object was being removed from the * hero's inventory. This should only be called from freeinv() and * where we are polymorphing an object already in the hero's inventory. * * Should think of a better name... */ void freeinv_core(obj) struct obj *obj; { if (obj->oclass == COIN_CLASS) { context.botl = 1; return; } else if (obj->otyp == AMULET_OF_YENDOR) { if (!u.uhave.amulet) impossible("don't have amulet?"); u.uhave.amulet = 0; } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { if (!u.uhave.menorah) impossible("don't have candelabrum?"); u.uhave.menorah = 0; } else if (obj->otyp == BELL_OF_OPENING) { if (!u.uhave.bell) impossible("don't have silver bell?"); u.uhave.bell = 0; } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (!u.uhave.book) impossible("don't have the book?"); u.uhave.book = 0; } else if (obj->oartifact) { if (is_quest_artifact(obj)) { if (!u.uhave.questart) impossible("don't have quest artifact?"); u.uhave.questart = 0; } set_artifact_intrinsic(obj, 0, W_ART); } if (obj->otyp == LOADSTONE) { curse(obj); } else if (confers_luck(obj)) { set_moreluck(); context.botl = 1; } else if (obj->otyp == FIGURINE && obj->timed) { (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj)); } } /* remove an object from the hero's inventory */ void freeinv(obj) register struct obj *obj; { extract_nobj(obj, &invent); freeinv_core(obj); update_inventory(); } void delallobj(x, y) int x, y; { struct obj *otmp, *otmp2; for (otmp = level.objects[x][y]; otmp; otmp = otmp2) { if (otmp == uball) unpunish(); /* after unpunish(), or might get deallocated chain */ otmp2 = otmp->nexthere; if (otmp == uchain) continue; delobj(otmp); } } /* destroy object in fobj chain (if unpaid, it remains on the bill) */ void delobj(obj) register struct obj *obj; { boolean update_map; if (obj->otyp == AMULET_OF_YENDOR || obj->otyp == CANDELABRUM_OF_INVOCATION || obj->otyp == BELL_OF_OPENING || obj->otyp == SPE_BOOK_OF_THE_DEAD) { /* player might be doing something stupid, but we * can't guarantee that. assume special artifacts * are indestructible via drawbridges, and exploding * chests, and golem creation, and ... */ return; } update_map = (obj->where == OBJ_FLOOR); obj_extract_self(obj); if (update_map) newsym(obj->ox, obj->oy); obfree(obj, (struct obj *) 0); /* frees contents also */ } /* try to find a particular type of object at designated map location */ struct obj * sobj_at(otyp, x, y) int otyp; int x, y; { register struct obj *otmp; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->otyp == otyp) break; return otmp; } /* sobj_at(&c) traversal -- find next object of specified type */ struct obj * nxtobj(obj, type, by_nexthere) struct obj *obj; int type; boolean by_nexthere; { register struct obj *otmp; otmp = obj; /* start with the object after this one */ do { otmp = !by_nexthere ? otmp->nobj : otmp->nexthere; if (!otmp) break; } while (otmp->otyp != type); return otmp; } struct obj * carrying(type) register int type; { register struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == type) return otmp; return (struct obj *) 0; } /* Fictional and not-so-fictional currencies. * http://concord.wikia.com/wiki/List_of_Fictional_Currencies */ static const char *const currencies[] = { "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */ "Ankh-Morpork Dollar", /* Discworld */ "auric", /* The Domination of Draka */ "buckazoid", /* Space Quest */ "cirbozoid", /* Starslip */ "credit chit", /* Deus Ex */ "cubit", /* Battlestar Galactica */ "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */ "fretzer", /* Jules Verne */ "imperial credit", /* Star Wars */ "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */ "kongbuck", /* Snow Crash */ "nanite", /* System Shock 2 */ "quatloo", /* Star Trek, Sim City */ "simoleon", /* Sim City */ "solari", /* Spaceballs */ "spacebuck", /* Spaceballs */ "sporebuck", /* Spore */ "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */ "woolong", /* Cowboy Bebop */ "zorkmid", /* Zork, NetHack */ }; const char * currency(amount) long amount; { const char *res; res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid"; if (amount != 1L) res = makeplural(res); return res; } boolean have_lizard() { register struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD) return TRUE; return FALSE; } /* 3.6.0 tribute */ struct obj * u_have_novel() { register struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == SPE_NOVEL) return otmp; return (struct obj *) 0; } struct obj * o_on(id, objchn) unsigned int id; register struct obj *objchn; { struct obj *temp; while (objchn) { if (objchn->o_id == id) return objchn; if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj))) return temp; objchn = objchn->nobj; } return (struct obj *) 0; } boolean obj_here(obj, x, y) register struct obj *obj; int x, y; { register struct obj *otmp; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (obj == otmp) return TRUE; return FALSE; } struct obj * g_at(x, y) register int x, y; { register struct obj *obj = level.objects[x][y]; while (obj) { if (obj->oclass == COIN_CLASS) return obj; obj = obj->nexthere; } return (struct obj *) 0; } /* compact a string of inventory letters by dashing runs of letters */ STATIC_OVL void compactify(buf) register char *buf; { register int i1 = 1, i2 = 1; register char ilet, ilet1, ilet2; ilet2 = buf[0]; ilet1 = buf[1]; buf[++i2] = buf[++i1]; ilet = buf[i1]; while (ilet) { if (ilet == ilet1 + 1) { if (ilet1 == ilet2 + 1) buf[i2 - 1] = ilet1 = '-'; else if (ilet2 == '-') { buf[i2 - 1] = ++ilet1; buf[i2] = buf[++i1]; ilet = buf[i1]; continue; } } else if (ilet == NOINVSYM) { /* compact three or more consecutive '#' characters into "#-#" */ if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM) buf[i2 - 1] = '-'; else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-' && buf[i2 - 1] == NOINVSYM) --i2; } ilet2 = ilet1; ilet1 = ilet; buf[++i2] = buf[++i1]; ilet = buf[i1]; } } /* some objects shouldn't be split when count given to getobj or askchain */ STATIC_OVL boolean splittable(obj) struct obj *obj; { return !((obj->otyp == LOADSTONE && obj->cursed) || (obj == uwep && welded(uwep))); } /* match the prompt for either 'T' or 'R' command */ STATIC_OVL boolean taking_off(action) const char *action; { return !strcmp(action, "take off") || !strcmp(action, "remove"); } /* match the prompt for either 'W' or 'P' command */ STATIC_OVL boolean putting_on(action) const char *action; { return !strcmp(action, "wear") || !strcmp(action, "put on"); } /* * getobj returns: * struct obj *xxx: object to do something with. * (struct obj *) 0 error return: no object. * &zeroobj explicitly no object (as in w-). !!!! test if gold can be used in unusual ways (eaten etc.) !!!! may be able to remove "usegold" */ struct obj * getobj(let, word) register const char *let, *word; { register struct obj *otmp; register char ilet; char buf[BUFSZ], qbuf[QBUFSZ]; char lets[BUFSZ], altlets[BUFSZ], *ap; register int foo = 0; register char *bp = buf; xchar allowcnt = 0; /* 0, 1 or 2 */ struct obj *firstobj = invent; boolean usegold = FALSE; /* can't use gold because its illegal */ boolean allowall = FALSE; boolean allownone = FALSE; boolean useboulder = FALSE; xchar foox = 0; long cnt, prevcnt; boolean prezero; long dummymask; if (*let == ALLOW_COUNT) let++, allowcnt = 1; if (*let == COIN_CLASS) let++, usegold = TRUE; /* Equivalent of an "ugly check" for gold */ if (usegold && !strcmp(word, "eat") && (!metallivorous(youmonst.data) || youmonst.data == &mons[PM_RUST_MONSTER])) usegold = FALSE; if (*let == ALL_CLASSES) let++, allowall = TRUE; if (*let == ALLOW_NONE) let++, allownone = TRUE; /* "ugly check" for reading fortune cookies, part 1. * The normal 'ugly check' keeps the object on the inventory list. * We don't want to do that for shirts/cookies, so the check for * them is handled a bit differently (and also requires that we set * allowall in the caller). */ if (allowall && !strcmp(word, "read")) allowall = FALSE; /* another ugly check: show boulders (not statues) */ if (*let == WEAPON_CLASS && !strcmp(word, "throw") && throws_rocks(youmonst.data)) useboulder = TRUE; if (allownone) *bp++ = '-'; if (bp > buf && bp[-1] == '-') *bp++ = ' '; ap = altlets; if (!flags.invlet_constant) reassign(); for (otmp = firstobj; otmp; otmp = otmp->nobj) { if (&bp[foo] == &buf[sizeof buf - 1] || ap == &altlets[sizeof altlets - 1]) { /* we must have a huge number of NOINVSYM items somehow */ impossible("getobj: inventory overflow"); break; } if (!*let || index(let, otmp->oclass) || (usegold && otmp->invlet == GOLD_SYM) || (useboulder && otmp->otyp == BOULDER)) { register int otyp = otmp->otyp; bp[foo++] = otmp->invlet; /* clang-format off */ /* *INDENT-OFF* */ /* ugly check: remove inappropriate things */ if ( (taking_off(word) /* exclude if not worn */ && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY))) || (putting_on(word) /* exclude if already worn */ && (otmp->owornmask & (W_ARMOR | W_ACCESSORY))) #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */ || (!strcmp(word, "wield") && (otmp->owornmask & W_WEP)) #endif || (!strcmp(word, "ready") /* exclude if wielded */ && (otmp == uwep || (otmp == uswapwep && u.twoweap))) || ((!strcmp(word, "dip") || !strcmp(word, "grease")) && inaccessible_equipment(otmp, (const char *) 0, FALSE)) ) { foo--; foox++; } /* Second ugly check; unlike the first it won't trigger an * "else" in "you don't have anything else to ___". */ else if ( (putting_on(word) && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES))) || (!strcmp(word, "wield") && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) || (!strcmp(word, "eat") && !is_edible(otmp)) || (!strcmp(word, "sacrifice") && (otyp != CORPSE && otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR)) || (!strcmp(word, "write with") && (otmp->oclass == TOOL_CLASS && otyp != MAGIC_MARKER && otyp != TOWEL)) || (!strcmp(word, "tin") && (otyp != CORPSE || !tinnable(otmp))) || (!strcmp(word, "rub") && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN) || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) || (!strcmp(word, "use or apply") /* Picks, axes, pole-weapons, bullwhips */ && ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || (otmp->oclass == POTION_CLASS /* only applicable potion is oil, and it will only be offered as a choice when already discovered */ && (otyp != POT_OIL || !otmp->dknown || !objects[POT_OIL].oc_name_known)) || (otmp->oclass == FOOD_CLASS && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) || (!strcmp(word, "invoke") && !otmp->oartifact && !objects[otyp].oc_unique && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && otyp != CRYSTAL_BALL /* synonym for apply */ /* note: presenting the possibility of invoking non-artifact mirrors and/or lamps is simply a cruel deception... */ && otyp != MIRROR && otyp != MAGIC_LAMP && (otyp != OIL_LAMP /* don't list known oil lamp */ || (otmp->dknown && objects[OIL_LAMP].oc_name_known))) || (!strcmp(word, "untrap with") && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE) || (otmp->oclass == POTION_CLASS /* only applicable potion is oil, and it will only be offered as a choice when already discovered */ && (otyp != POT_OIL || !otmp->dknown || !objects[POT_OIL].oc_name_known)))) || (!strcmp(word, "tip") && !Is_container(otmp) /* include horn of plenty if sufficiently discovered */ && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || !objects[HORN_OF_PLENTY].oc_name_known)) || (!strcmp(word, "charge") && !is_chargeable(otmp)) || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) ) { foo--; } /* Third ugly check: acceptable but not listed as likely * candidates in the prompt or in the inventory subset if * player responds with '?'. */ else if ( /* ugly check for unworn armor that can't be worn */ (putting_on(word) && *let == ARMOR_CLASS && !canwearobj(otmp, &dummymask, FALSE)) /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */ || ((putting_on(word) || taking_off(word)) && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS))) /* or unsuitable items rubbed on known touchstone */ || (!strncmp(word, "rub on the stone", 16) && *let == GEM_CLASS && otmp->dknown && objects[otyp].oc_name_known) /* suppress corpses on astral, amulets elsewhere */ || (!strcmp(word, "sacrifice") /* (!astral && amulet) || (astral && !amulet) */ && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) /* suppress container being stashed into */ || (!strcmp(word, "stash") && !ck_bag(otmp)) /* worn armor or accessory covered by cursed worn armor */ || (taking_off(word) && inaccessible_equipment(otmp, (const char *) 0, TRUE)) ) { /* acceptable but not listed as likely candidate */ foo--; allowall = TRUE; *ap++ = otmp->invlet; } /* *INDENT-ON* */ /* clang-format on */ } else { /* "ugly check" for reading fortune cookies, part 2 */ if ((!strcmp(word, "read") && is_readable(otmp))) allowall = usegold = TRUE; } } bp[foo] = 0; if (foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; Strcpy(lets, bp); /* necessary since we destroy buf */ if (foo > 5) /* compactify string */ compactify(bp); *ap = '\0'; if (!foo && !allowall && !allownone) { You("don't have anything %sto %s.", foox ? "else " : "", word); return (struct obj *) 0; } for (;;) { cnt = 0; if (allowcnt == 2) allowcnt = 1; /* abort previous count */ prezero = FALSE; if (!buf[0]) { Sprintf(qbuf, "What do you want to %s? [*]", word); } else { Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf); } if (in_doagain) ilet = readchar(); else ilet = yn_function(qbuf, (char *) 0, '\0'); if (digit(ilet) && !allowcnt) { pline("No count allowed with this command."); continue; } if (ilet == '0') prezero = TRUE; while (digit(ilet)) { if (ilet != '?' && ilet != '*') savech(ilet); /* accumulate unless cnt has overflowed */ if (allowcnt < 3) { prevcnt = cnt; cnt = 10L * cnt + (long) (ilet - '0'); /* signal presence of cnt */ allowcnt = (cnt >= prevcnt) ? 2 : 3; } ilet = readchar(); } if (allowcnt == 3) { /* overflow detected; force cnt to be invalid */ cnt = -1L; allowcnt = 2; } if (index(quitchars, ilet)) { if (flags.verbose) pline1(Never_mind); return (struct obj *) 0; } if (ilet == '-') { if (!allownone) { char *suf = (char *) 0; strcpy(buf, word); if ((bp = strstr(buf, " on the ")) != 0) { /* rub on the stone[s] */ *bp = '\0'; suf = (bp + 1); } if ((bp = strstr(buf, " or ")) != 0) { *bp = '\0'; bp = (rn2(2) ? buf : (bp + 4)); } else bp = buf; You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "", suf ? suf : ""); } return (allownone ? &zeroobj : (struct obj *) 0); } /* since gold is now kept in inventory, we need to do processing for select-from-invent before checking whether gold has been picked */ if (ilet == '?' || ilet == '*') { char *allowed_choices = (ilet == '?') ? lets : (char *) 0; long ctmp = 0; if (ilet == '?' && !*lets && *altlets) allowed_choices = altlets; ilet = display_pickinv(allowed_choices, TRUE, allowcnt ? &ctmp : (long *) 0); if (!ilet) continue; if (allowcnt && ctmp >= 0) { cnt = ctmp; if (!cnt) prezero = TRUE; allowcnt = 2; } if (ilet == '\033') { if (flags.verbose) pline1(Never_mind); return (struct obj *) 0; } /* they typed a letter (not a space) at the prompt */ } /* find the item which was picked */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->invlet == ilet) break; /* some items have restrictions */ if (ilet == def_oc_syms[COIN_CLASS].sym /* guard against the [hypothetical] chace of having more than one invent slot of gold and picking the non-'$' one */ || (otmp && otmp->oclass == COIN_CLASS)) { if (!usegold) { You("cannot %s gold.", word); return (struct obj *) 0; } /* Historic note: early Nethack had a bug which was * first reported for Larn, where trying to drop 2^32-n * gold pieces was allowed, and did interesting things * to your money supply. The LRS is the tax bureau * from Larn. */ if (allowcnt == 2 && cnt <= 0) { if (cnt < 0 || !prezero) pline_The( "LRS would be very interested to know you have that much."); return (struct obj *) 0; } } if (allowcnt == 2 && !strcmp(word, "throw")) { /* permit counts for throwing gold, but don't accept * counts for other things since the throw code will * split off a single item anyway */ if (ilet != def_oc_syms[COIN_CLASS].sym && !(otmp && otmp->oclass == COIN_CLASS)) allowcnt = 1; if (cnt == 0 && prezero) return (struct obj *) 0; if (cnt > 1) { You("can only throw one item at a time."); continue; } } context.botl = 1; /* May have changed the amount of money */ savech(ilet); /* [we used to set otmp (by finding ilet in invent) here, but that's been moved above so that otmp can be checked earlier] */ /* verify the chosen object */ if (!otmp) { You("don't have that object."); if (in_doagain) return (struct obj *) 0; continue; } else if (cnt < 0 || otmp->quan < cnt) { You("don't have that many! You have only %ld.", otmp->quan); if (in_doagain) return (struct obj *) 0; continue; } break; } if (!allowall && let && !index(let, otmp->oclass) && !(usegold && otmp->oclass == COIN_CLASS)) { silly_thing(word, otmp); return (struct obj *) 0; } if (allowcnt == 2) { /* cnt given */ if (cnt == 0) return (struct obj *) 0; if (cnt != otmp->quan) { /* don't split a stack of cursed loadstones */ if (splittable(otmp)) otmp = splitobj(otmp, cnt); else if (otmp->otyp == LOADSTONE && otmp->cursed) /* kludge for canletgo()'s can't-drop-this message */ otmp->corpsenm = (int) cnt; } } return otmp; } void silly_thing(word, otmp) const char *word; struct obj *otmp; { #if 1 /* 'P','R' vs 'W','T' handling is obsolete */ nhUse(otmp); #else const char *s1, *s2, *s3, *what; int ocls = otmp->oclass, otyp = otmp->otyp; s1 = s2 = s3 = 0; /* check for attempted use of accessory commands ('P','R') on armor and for corresponding armor commands ('W','T') on accessories */ if (ocls == ARMOR_CLASS) { if (!strcmp(word, "put on")) s1 = "W", s2 = "wear", s3 = ""; else if (!strcmp(word, "remove")) s1 = "T", s2 = "take", s3 = " off"; } else if ((ocls == RING_CLASS || otyp == MEAT_RING) || ocls == AMULET_CLASS || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) { if (!strcmp(word, "wear")) s1 = "P", s2 = "put", s3 = " on"; else if (!strcmp(word, "take off")) s1 = "R", s2 = "remove", s3 = ""; } if (s1) { what = "that"; /* quantity for armor and accessory objects is always 1, but some things should be referred to as plural */ if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) what = "those"; pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); } else #endif pline(silly_thing_to, word); } STATIC_PTR int ckvalidcat(otmp) struct obj *otmp; { /* use allow_category() from pickup.c */ return (int) allow_category(otmp); } STATIC_PTR int ckunpaid(otmp) struct obj *otmp; { return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj))); } boolean wearing_armor() { return (boolean) (uarm || uarmc || uarmf || uarmg || uarmh || uarms || uarmu); } boolean is_worn(otmp) struct obj *otmp; { return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON)) ? TRUE : FALSE; } /* extra xprname() input that askchain() can't pass through safe_qbuf() */ STATIC_VAR struct xprnctx { char let; boolean dot; } safeq_xprn_ctx; /* safe_qbuf() -> short_oname() callback */ STATIC_PTR char * safeq_xprname(obj) struct obj *obj; { return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot, 0L, 0L); } /* alternate safe_qbuf() -> short_oname() callback */ STATIC_PTR char * safeq_shortxprname(obj) struct obj *obj; { return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let, safeq_xprn_ctx.dot, 0L, 0L); } static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 }; /* interactive version of getobj - used for Drop, Identify and */ /* Takeoff (A). Return the number of times fn was called successfully */ /* If combo is TRUE, we just use this to get a category list */ int ggetobj(word, fn, mx, combo, resultflags) const char *word; int FDECL((*fn), (OBJ_P)), mx; boolean combo; /* combination menu flag */ unsigned *resultflags; { int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0; boolean FDECL((*filter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0; boolean takeoff, ident, allflag, m_seen; int itemcount; int oletct, iletct, unpaid, oc_of_sym; char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5]; char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */ char buf[BUFSZ], qbuf[QBUFSZ]; if (resultflags) *resultflags = 0; takeoff = ident = allflag = m_seen = FALSE; if (!invent) { You("have nothing to %s.", word); return 0; } add_valid_menu_class(0); /* reset */ if (taking_off(word)) { takeoff = TRUE; filter = is_worn; } else if (!strcmp(word, "identify")) { ident = TRUE; filter = not_fully_identified; } iletct = collect_obj_classes(ilets, invent, FALSE, filter, &itemcount); unpaid = count_unpaid(invent); if (ident && !iletct) { return -1; /* no further identifications */ } else if (!takeoff && (unpaid || invent)) { ilets[iletct++] = ' '; if (unpaid) ilets[iletct++] = 'u'; if (count_buc(invent, BUC_BLESSED)) ilets[iletct++] = 'B'; if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U'; if (count_buc(invent, BUC_CURSED)) ilets[iletct++] = 'C'; if (count_buc(invent, BUC_UNKNOWN)) ilets[iletct++] = 'X'; if (invent) ilets[iletct++] = 'a'; } else if (takeoff && invent) { ilets[iletct++] = ' '; } ilets[iletct++] = 'i'; if (!combo) ilets[iletct++] = 'm'; /* allow menu presentation on request */ ilets[iletct] = '\0'; for (;;) { Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", word, ilets); getlin(qbuf, buf); if (buf[0] == '\033') return 0; if (index(buf, 'i')) { if (display_inventory((char *) 0, TRUE) == '\033') return 0; } else break; } extra_removeables[0] = '\0'; if (takeoff) { /* arbitrary types of items can be placed in the weapon slots [any duplicate entries in extra_removeables[] won't matter] */ if (uwep) (void) strkitten(extra_removeables, uwep->oclass); if (uswapwep) (void) strkitten(extra_removeables, uswapwep->oclass); if (uquiver) (void) strkitten(extra_removeables, uquiver->oclass); } ip = buf; olets[oletct = 0] = '\0'; while ((sym = *ip++) != '\0') { if (sym == ' ') continue; oc_of_sym = def_char_to_objclass(sym); if (takeoff && oc_of_sym != MAXOCLASSES) { if (index(extra_removeables, oc_of_sym)) { ; /* skip rest of takeoff checks */ } else if (!index(removeables, oc_of_sym)) { pline("Not applicable."); return 0; } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) { noarmor(FALSE); return 0; } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep && !uquiver) { You("are not wielding anything."); return 0; } else if (oc_of_sym == RING_CLASS && !uright && !uleft) { You("are not wearing rings."); return 0; } else if (oc_of_sym == AMULET_CLASS && !uamul) { You("are not wearing an amulet."); return 0; } else if (oc_of_sym == TOOL_CLASS && !ublindf) { You("are not wearing a blindfold."); return 0; } } if (oc_of_sym == COIN_CLASS && !combo) { context.botl = 1; } else if (sym == 'a') { allflag = TRUE; } else if (sym == 'A') { /* same as the default */; } else if (sym == 'u') { add_valid_menu_class('u'); ckfn = ckunpaid; } else if (sym == 'B') { add_valid_menu_class('B'); ckfn = ckvalidcat; } else if (sym == 'U') { add_valid_menu_class('U'); ckfn = ckvalidcat; } else if (sym == 'C') { add_valid_menu_class('C'); ckfn = ckvalidcat; } else if (sym == 'X') { add_valid_menu_class('X'); ckfn = ckvalidcat; } else if (sym == 'm') { m_seen = TRUE; } else if (oc_of_sym == MAXOCLASSES) { You("don't have any %c's.", sym); } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */ if (!index(olets, oc_of_sym)) { add_valid_menu_class(oc_of_sym); olets[oletct++] = oc_of_sym; olets[oletct] = 0; } } } if (m_seen) { return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3; } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) { return 0; #if 0 /* !!!! test gold dropping */ } else if (allowgold == 2 && !oletct) { return 1; /* you dropped gold (or at least tried to) */ #endif } else { int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); /* * askchain() has already finished the job in this case * so set a special flag to convey that back to the caller * so that it won't continue processing. * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. */ if (combo && allflag && resultflags) *resultflags |= ALL_FINISHED; return cnt; } } /* * Walk through the chain starting at objchn and ask for all objects * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull) * whether the action in question (i.e., fn) has to be performed. * If allflag then no questions are asked. Max gives the max nr of * objects to be treated. Return the number of objects treated. */ int askchain(objchn, olets, allflag, fn, ckfn, mx, word) struct obj **objchn; register int allflag, mx; register const char *olets, *word; /* olets is an Obj Class char array */ register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P)); { struct obj *otmp, *otmpo; register char sym, ilet; register int cnt = 0, dud = 0, tmp; boolean takeoff, nodot, ident, take_out, put_in, first, ininv; char qbuf[QBUFSZ], qpfx[QBUFSZ]; takeoff = taking_off(word); ident = !strcmp(word, "identify"); take_out = !strcmp(word, "take out"); put_in = !strcmp(word, "put in"); nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident || takeoff || take_out || put_in); ininv = (*objchn == invent); first = TRUE; /* Changed so the askchain is interrogated in the order specified. * For example, if a person specifies =/ then first all rings will be * asked about followed by all wands -dgk */ nextclass: ilet = 'a' - 1; if (*objchn && (*objchn)->oclass == COIN_CLASS) ilet--; /* extra iteration */ /* * Multiple Drop can change the invent chain while it operates * (dropping a burning potion of oil while levitating creates * an explosion which can destroy inventory items), so simple * list traversal * for (otmp = *objchn; otmp; otmp = otmp2) { * otmp2 = otmp->nobj; * ... * } * is inadequate here. Use each object's bypass bit to keep * track of which list elements have already been processed. */ bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */ while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) { if (ilet == 'z') ilet = 'A'; else ilet++; if (olets && *olets && otmp->oclass != *olets) continue; if (takeoff && !is_worn(otmp)) continue; if (ident && !not_fully_identified(otmp)) continue; if (ckfn && !(*ckfn)(otmp)) continue; if (!allflag) { safeq_xprn_ctx.let = ilet; safeq_xprn_ctx.dot = !nodot; *qpfx = '\0'; if (first) { /* traditional_loot() skips prompting when only one class of objects is involved, so prefix the first object being queried here with an explanation why */ if (take_out || put_in) Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx); first = FALSE; } (void) safe_qbuf( qbuf, qpfx, "?", otmp, ininv ? safeq_xprname : doname, ininv ? safeq_shortxprname : ansimpleoname, "item"); sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf) : nyNaq(qbuf); } else sym = 'y'; otmpo = otmp; if (sym == '#') { /* Number was entered; split the object unless it corresponds to 'none' or 'all'. 2 special cases: cursed loadstones and welded weapons (eg, multiple daggers) will remain as merged unit; done to avoid splitting an object that won't be droppable (even if we're picking up rather than dropping). */ if (!yn_number) sym = 'n'; else { sym = 'y'; if (yn_number < otmp->quan && splittable(otmp)) otmp = splitobj(otmp, yn_number); } } switch (sym) { case 'a': allflag = 1; case 'y': tmp = (*fn)(otmp); if (tmp < 0) { if (container_gone(fn)) { /* otmp caused magic bag to explode; both are now gone */ otmp = 0; /* and return */ } else if (otmp && otmp != otmpo) { /* split occurred, merge again */ (void) merged(&otmpo, &otmp); } goto ret; } cnt += tmp; if (--mx == 0) goto ret; case 'n': if (nodot) dud++; default: break; case 'q': /* special case for seffects() */ if (ident) cnt = -1; goto ret; } } if (olets && *olets && *++olets) goto nextclass; if (!takeoff && (dud || cnt)) pline("That was all."); else if (!dud && !cnt) pline("No applicable objects."); ret: bypass_objlist(*objchn, FALSE); return cnt; } /* * Object identification routines: */ /* make an object actually be identified; no display updating */ void fully_identify_obj(otmp) struct obj *otmp; { makeknown(otmp->otyp); if (otmp->oartifact) discover_artifact((xchar) otmp->oartifact); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; if (Is_container(otmp) || otmp->otyp == STATUE) otmp->cknown = otmp->lknown = 1; if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) learn_egg_type(otmp->corpsenm); } /* ggetobj callback routine; identify an object and give immediate feedback */ int identify(otmp) struct obj *otmp; { fully_identify_obj(otmp); prinv((char *) 0, otmp, 0L); return 1; } /* menu of unidentified objects; select and identify up to id_limit of them */ STATIC_OVL void menu_identify(id_limit) int id_limit; { menu_item *pick_list; int n, i, first = 1, tryct = 5; char buf[BUFSZ]; /* assumptions: id_limit > 0 and at least one unID'd item is present */ while (id_limit) { Sprintf(buf, "What would you like to identify %s?", first ? "first" : "next"); n = query_objlist(buf, invent, SIGNAL_NOMENU | SIGNAL_ESCAPE | USE_INVLET | INVORDER_SORT, &pick_list, PICK_ANY, not_fully_identified); if (n > 0) { if (n > id_limit) n = id_limit; for (i = 0; i < n; i++, id_limit--) (void) identify(pick_list[i].item.a_obj); free((genericptr_t) pick_list); mark_synch(); /* Before we loop to pop open another menu */ first = 0; } else if (n == -2) { /* player used ESC to quit menu */ break; } else if (n == -1) { /* no eligible items found */ pline("That was all."); break; } else if (!--tryct) { /* stop re-prompting */ pline1(thats_enough_tries); break; } else { /* try again */ pline("Choose an item; use ESC to decline."); } } } /* dialog with user to identify a given number of items; 0 means all */ void identify_pack(id_limit, learning_id) int id_limit; boolean learning_id; /* true if we just read unknown identify scroll */ { struct obj *obj, *the_obj; int n, unid_cnt; unid_cnt = 0; the_obj = 0; /* if unid_cnt ends up 1, this will be it */ for (obj = invent; obj; obj = obj->nobj) if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj; if (!unid_cnt) { You("have already identified all %sof your possessions.", learning_id ? "the rest " : ""); } else if (!id_limit || id_limit >= unid_cnt) { /* identify everything */ if (unid_cnt == 1) { (void) identify(the_obj); } else { /* TODO: use fully_identify_obj and cornline/menu/whatever here */ for (obj = invent; obj; obj = obj->nobj) if (not_fully_identified(obj)) (void) identify(obj); } } else { /* identify up to `id_limit' items */ n = 0; if (flags.menu_style == MENU_TRADITIONAL) do { n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *) 0); if (n < 0) break; /* quit or no eligible items */ } while ((id_limit -= n) > 0); if (n == 0 || n < -1) menu_identify(id_limit); } update_inventory(); } /* called when regaining sight; mark inventory objects which were picked up while blind as now having been seen */ void learn_unseen_invent() { struct obj *otmp; if (Blind) return; /* sanity check */ for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->dknown) continue; /* already seen */ /* set dknown, perhaps bknown (for priest[ess]) */ (void) xname(otmp); /* * If object->eknown gets implemented (see learnwand(zap.c)), * handle deferred discovery here. */ } update_inventory(); } /* should of course only be called for things in invent */ STATIC_OVL char obj_to_let(obj) struct obj *obj; { if (!flags.invlet_constant) { obj->invlet = NOINVSYM; reassign(); } return obj->invlet; } /* * Print the indicated quantity of the given object. If quan == 0L then use * the current quantity. */ void prinv(prefix, obj, quan) const char *prefix; struct obj *obj; long quan; { if (!prefix) prefix = ""; pline("%s%s%s", prefix, *prefix ? " " : "", xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan)); } char * xprname(obj, txt, let, dot, cost, quan) struct obj *obj; const char *txt; /* text to print instead of obj */ char let; /* inventory letter */ boolean dot; /* append period; (dot && cost => Iu) */ long cost; /* cost (for inventory of unpaid or expended items) */ long quan; /* if non-0, print this quantity, not obj->quan */ { #ifdef LINT /* handle static char li[BUFSZ]; */ char li[BUFSZ]; #else static char li[BUFSZ]; #endif boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM; long savequan = 0; if (quan && obj) { savequan = obj->quan; obj->quan = quan; } /* * If let is: * * Then obj == null and we are printing a total amount. * > Then the object is contained and doesn't have an inventory letter. */ if (cost != 0 || let == '*') { /* if dot is true, we're doing Iu, otherwise Ix */ Sprintf(li, "%c - %-45s %6ld %s", (dot && use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), cost, currency(cost)); } else { /* ordinary inventory display or pickup message */ Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), (dot ? "." : "")); } if (savequan) obj->quan = savequan; return li; } /* the 'i' command */ int ddoinv() { (void) display_inventory((char *) 0, FALSE); return 0; } /* * find_unpaid() * * Scan the given list of objects. If last_found is NULL, return the first * unpaid object found. If last_found is not NULL, then skip over unpaid * objects until last_found is reached, then set last_found to NULL so the * next unpaid object is returned. This routine recursively follows * containers. */ STATIC_OVL struct obj * find_unpaid(list, last_found) struct obj *list, **last_found; { struct obj *obj; while (list) { if (list->unpaid) { if (*last_found) { /* still looking for previous unpaid object */ if (list == *last_found) *last_found = (struct obj *) 0; } else return ((*last_found = list)); } if (Has_contents(list)) { if ((obj = find_unpaid(list->cobj, last_found)) != 0) return obj; } list = list->nobj; } return (struct obj *) 0; } /* for perm_invent when operating on a partial inventory display, so that the persistent one doesn't get shrunk during filtering for item selection then regrown to full inventory, possibly being resized in the process */ static winid cached_pickinv_win = WIN_ERR; void free_pickinv_cache() { if (cached_pickinv_win != WIN_ERR) { destroy_nhwindow(cached_pickinv_win); cached_pickinv_win = WIN_ERR; } } /* * Internal function used by display_inventory and getobj that can display * inventory and return a count as well as a letter. If out_cnt is not null, * any count returned from the menu selection is placed here. */ STATIC_OVL char display_pickinv(lets, want_reply, out_cnt) register const char *lets; boolean want_reply; long *out_cnt; { struct obj *otmp; char ilet, ret; char *invlet = flags.inv_order; int i, n, classcount; winid win; /* windows being used */ anything any; menu_item *selected; struct obj **oarray; if (flags.perm_invent && lets && *lets) { /* partial inventory in perm_invent setting; don't operate on full inventory window, use an alternate one instead; create the first time needed and keep it for re-use as needed later */ if (cached_pickinv_win == WIN_ERR) cached_pickinv_win = create_nhwindow(NHW_MENU); win = cached_pickinv_win; } else win = WIN_INVEN; /* * Exit early if no inventory -- but keep going if we are doing * a permanent inventory update. We need to keep going so the * permanent inventory window updates itself to remove the last * item(s) dropped. One down side: the addition of the exception * for permanent inventory window updates _can_ pop the window * up when it's not displayed -- even if it's empty -- because we * don't know at this level if its up or not. This may not be * an issue if empty checks are done before hand and the call * to here is short circuited away. */ if (!invent && !(flags.perm_invent && !lets && !want_reply)) { pline("Not carrying anything."); return 0; } /* oxymoron? temporarily assign permanent inventory letters */ if (!flags.invlet_constant) reassign(); if (lets && strlen(lets) == 1 && !iflags.override_ID) { /* when only one item of interest, use pline instead of menus; we actually use a fake message-line menu in order to allow the user to perform selection at the --More-- prompt for tty */ ret = '\0'; for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->invlet == lets[0]) { ret = message_menu( lets[0], want_reply ? PICK_ONE : PICK_NONE, xprname(otmp, (char *) 0, lets[0], TRUE, 0L, 0L)); if (out_cnt) *out_cnt = -1L; /* select all */ break; } } return ret; } /* count the number of items */ for (n = 0, otmp = invent; otmp; otmp = otmp->nobj) if (!lets || !*lets || index(lets, otmp->invlet)) n++; oarray = objarr_init(n); /* Add objects to the array */ i = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if (!lets || !*lets || index(lets, otmp->invlet)) { objarr_set(otmp, i++, oarray, (flags.sortloot == 'f')); } start_menu(win); any = zeroany; if (wizard && iflags.override_ID) { char prompt[BUFSZ]; any.a_char = -1; /* wiz_identify stuffed the wiz_identify cmd character into iflags.override_ID */ Sprintf(prompt, "Debug Identify (%s to permanently identify)", visctrl(iflags.override_ID)); add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, prompt, MENU_UNSELECTED); } nextclass: classcount = 0; any = zeroany; /* set all bits to zero */ for (i = 0; i < n; i++) { otmp = oarray[i]; ilet = otmp->invlet; any = zeroany; /* zero */ if (!flags.sortpack || otmp->oclass == *invlet) { if (flags.sortpack && !classcount) { add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, let_to_name(*invlet, FALSE, (want_reply && iflags.menu_head_objsym)), MENU_UNSELECTED); classcount++; } any.a_char = ilet; add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); } } if (flags.sortpack) { if (*++invlet) goto nextclass; if (--invlet != venom_inv) { invlet = venom_inv; goto nextclass; } } free(oarray); end_menu(win, (char *) 0); n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); if (n > 0) { ret = selected[0].item.a_char; if (out_cnt) *out_cnt = selected[0].count; free((genericptr_t) selected); } else ret = !n ? '\0' : '\033'; /* cancelled */ return ret; } /* * If lets == NULL or "", list all objects in the inventory. Otherwise, * list all objects with object classes that match the order in lets. * * Returns the letter identifier of a selected item, or 0 if nothing * was selected. */ char display_inventory(lets, want_reply) const char *lets; boolean want_reply; { return display_pickinv(lets, want_reply, (long *) 0); } /* * Show what is current using inventory letters. * */ STATIC_OVL char display_used_invlets(avoidlet) char avoidlet; { struct obj *otmp; char ilet, ret = 0; char *invlet = flags.inv_order; int n, classcount, invdone = 0; winid win; anything any; menu_item *selected; if (invent) { win = create_nhwindow(NHW_MENU); start_menu(win); while (!invdone) { any = zeroany; /* set all bits to zero */ classcount = 0; for (otmp = invent; otmp; otmp = otmp->nobj) { ilet = otmp->invlet; if (ilet == avoidlet) continue; if (!flags.sortpack || otmp->oclass == *invlet) { if (flags.sortpack && !classcount) { any = zeroany; /* zero */ add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, let_to_name(*invlet, FALSE, FALSE), MENU_UNSELECTED); classcount++; } any.a_char = ilet; add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); } } if (flags.sortpack && *++invlet) continue; invdone = 1; } end_menu(win, "Inventory letters used:"); n = select_menu(win, PICK_NONE, &selected); if (n > 0) { ret = selected[0].item.a_char; free((genericptr_t) selected); } else ret = !n ? '\0' : '\033'; /* cancelled */ destroy_nhwindow(win); } return ret; } /* * Returns the number of unpaid items within the given list. This includes * contained objects. */ int count_unpaid(list) struct obj *list; { int count = 0; while (list) { if (list->unpaid) count++; if (Has_contents(list)) count += count_unpaid(list->cobj); list = list->nobj; } return count; } /* * Returns the number of items with b/u/c/unknown within the given list. * This does NOT include contained objects. * * Assumes that the hero sees or touches or otherwise senses the objects * at some point: bknown is forced for priest[ess], like in xname(). */ int count_buc(list, type) struct obj *list; int type; { int count = 0; for (; list; list = list->nobj) { /* coins are "none of the above" as far as BUCX filtering goes */ if (list->oclass == COIN_CLASS) continue; /* priests always know bless/curse state */ if (Role_if(PM_PRIEST)) list->bknown = 1; /* check whether this object matches the requested type */ if (!list->bknown ? (type == BUC_UNKNOWN) : list->blessed ? (type == BUC_BLESSED) : list->cursed ? (type == BUC_CURSED) : (type == BUC_UNCURSED)) ++count; } return count; } /* similar to count_buc(), but tallies all states at once rather than looking for a specific type */ STATIC_OVL void tally_BUCX(list, bcp, ucp, ccp, xcp, ocp) struct obj *list; int *bcp, *ucp, *ccp, *xcp, *ocp; { *bcp = *ucp = *ccp = *xcp = *ocp = 0; for (; list; list = list->nobj) { if (list->oclass == COIN_CLASS) { ++(*ocp); /* "other" */ continue; } /* priests always know bless/curse state */ if (Role_if(PM_PRIEST)) list->bknown = 1; if (!list->bknown) ++(*xcp); else if (list->blessed) ++(*bcp); else if (list->cursed) ++(*ccp); else /* neither blessed nor cursed => uncursed */ ++(*ucp); } } long count_contents(container, nested, quantity, everything) struct obj *container; boolean nested, /* include contents of any nested containers */ quantity, /* count all vs count separate stacks */ everything; /* all objects vs only unpaid objects */ { struct obj *otmp; long count = 0L; for (otmp = container->cobj; otmp; otmp = otmp->nobj) { if (nested && Has_contents(otmp)) count += count_contents(otmp, nested, quantity, everything); if (everything || otmp->unpaid) count += quantity ? otmp->quan : 1L; } return count; } STATIC_OVL void dounpaid() { winid win; struct obj *otmp, *marker; register char ilet; char *invlet = flags.inv_order; int classcount, count, num_so_far; long cost, totcost; count = count_unpaid(invent); if (count == 1) { marker = (struct obj *) 0; otmp = find_unpaid(invent, &marker); cost = unpaid_cost(otmp, FALSE); iflags.suppress_price++; /* suppress "(unpaid)" suffix */ pline1(xprname(otmp, distant_name(otmp, doname), carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE, cost, 0L)); iflags.suppress_price--; return; } win = create_nhwindow(NHW_MENU); cost = totcost = 0; num_so_far = 0; /* count of # printed so far */ if (!flags.invlet_constant) reassign(); do { classcount = 0; for (otmp = invent; otmp; otmp = otmp->nobj) { ilet = otmp->invlet; if (otmp->unpaid) { if (!flags.sortpack || otmp->oclass == *invlet) { if (flags.sortpack && !classcount) { putstr(win, 0, let_to_name(*invlet, TRUE, FALSE)); classcount++; } totcost += cost = unpaid_cost(otmp, FALSE); iflags.suppress_price++; /* suppress "(unpaid)" suffix */ putstr(win, 0, xprname(otmp, distant_name(otmp, doname), ilet, TRUE, cost, 0L)); iflags.suppress_price--; num_so_far++; } } } } while (flags.sortpack && (*++invlet)); if (count > num_so_far) { /* something unpaid is contained */ if (flags.sortpack) putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE)); /* * Search through the container objects in the inventory for * unpaid items. The top level inventory items have already * been listed. */ for (otmp = invent; otmp; otmp = otmp->nobj) { if (Has_contents(otmp)) { long contcost = 0L; marker = (struct obj *) 0; /* haven't found any */ while (find_unpaid(otmp->cobj, &marker)) { totcost += cost = unpaid_cost(marker, FALSE); contcost += cost; if (otmp->cknown) { iflags.suppress_price++; /* suppress "(unpaid)" sfx */ putstr(win, 0, xprname(marker, distant_name(marker, doname), CONTAINED_SYM, TRUE, cost, 0L)); iflags.suppress_price--; } } if (!otmp->cknown) { char contbuf[BUFSZ]; /* Shopkeeper knows what to charge for contents */ Sprintf(contbuf, "%s contents", s_suffix(xname(otmp))); putstr(win, 0, xprname((struct obj *) 0, contbuf, CONTAINED_SYM, TRUE, contcost, 0L)); } } } } putstr(win, 0, ""); putstr(win, 0, xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L)); display_nhwindow(win, FALSE); destroy_nhwindow(win); } /* query objlist callback: return TRUE if obj type matches "this_type" */ static int this_type; STATIC_OVL boolean this_type_only(obj) struct obj *obj; { boolean res = (obj->oclass == this_type); if (obj->oclass != COIN_CLASS) { switch (this_type) { case 'B': res = (obj->bknown && obj->blessed); break; case 'U': res = (obj->bknown && !(obj->blessed || obj->cursed)); break; case 'C': res = (obj->bknown && obj->cursed); break; case 'X': res = !obj->bknown; break; default: break; /* use 'res' as-is */ } } return res; } /* the 'I' command */ int dotypeinv() { char c = '\0'; int n, i = 0; char *extra_types, types[BUFSZ]; int class_count, oclass, unpaid_count, itemcount; int bcnt, ccnt, ucnt, xcnt, ocnt; boolean billx = *u.ushops && doinvbill(0); menu_item *pick_list; boolean traditional = TRUE; const char *prompt = "What type of object do you want an inventory of?"; if (!invent && !billx) { You("aren't carrying anything."); return 0; } unpaid_count = count_unpaid(invent); tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt); if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style == MENU_FULL || flags.menu_style == MENU_PARTIAL) { traditional = FALSE; i = UNPAID_TYPES; if (billx) i |= BILLED_TYPES; if (bcnt) i |= BUC_BLESSED; if (ucnt) i |= BUC_UNCURSED; if (ccnt) i |= BUC_CURSED; if (xcnt) i |= BUC_UNKNOWN; n = query_category(prompt, invent, i, &pick_list, PICK_ONE); if (!n) return 0; this_type = c = pick_list[0].item.a_int; free((genericptr_t) pick_list); } } if (traditional) { /* collect a list of classes of objects carried, for use as a prompt */ types[0] = 0; class_count = collect_obj_classes(types, invent, FALSE, (boolean FDECL((*), (OBJ_P))) 0, &itemcount); if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0) types[class_count++] = ' '; if (unpaid_count) types[class_count++] = 'u'; if (billx) types[class_count++] = 'x'; if (bcnt) types[class_count++] = 'B'; if (ucnt) types[class_count++] = 'U'; if (ccnt) types[class_count++] = 'C'; if (xcnt) types[class_count++] = 'X'; types[class_count] = '\0'; /* add everything not already included; user won't see these */ extra_types = eos(types); *extra_types++ = '\033'; if (!unpaid_count) *extra_types++ = 'u'; if (!billx) *extra_types++ = 'x'; if (!bcnt) *extra_types++ = 'B'; if (!ucnt) *extra_types++ = 'U'; if (!ccnt) *extra_types++ = 'C'; if (!xcnt) *extra_types++ = 'X'; *extra_types = '\0'; /* for index() */ for (i = 0; i < MAXOCLASSES; i++) if (!index(types, def_oc_syms[i].sym)) { *extra_types++ = def_oc_syms[i].sym; *extra_types = '\0'; } if (class_count > 1) { c = yn_function(prompt, types, '\0'); savech(c); if (c == '\0') { clear_nhwindow(WIN_MESSAGE); return 0; } } else { /* only one thing to itemize */ if (unpaid_count) c = 'u'; else if (billx) c = 'x'; else c = types[0]; } } if (c == 'x' || (c == 'X' && billx && !xcnt)) { if (billx) (void) doinvbill(1); else pline("No used-up objects%s.", unpaid_count ? " on your shopping bill" : ""); return 0; } if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) { if (unpaid_count) dounpaid(); else You("are not carrying any unpaid objects."); return 0; } if (traditional) { if (index("BUCX", c)) oclass = c; /* not a class but understood by this_type_only() */ else oclass = def_char_to_objclass(c); /* change to object class */ if (oclass == COIN_CLASS) return doprgold(); if (index(types, c) > index(types, '\033')) { /* '> ESC' => hidden choice, something known not to be carried */ const char *which = 0; switch (c) { case 'B': which = "known to be blessed"; break; case 'U': which = "known to be uncursed"; break; case 'C': which = "known to be cursed"; break; case 'X': You( "have no objects whose blessed/uncursed/cursed status is unknown."); break; /* better phrasing is desirable */ default: which = "such"; break; } if (which) You("have no %s objects.", which); return 0; } this_type = oclass; } if (query_objlist((char *) 0, invent, (flags.invlet_constant ? USE_INVLET : 0) | INVORDER_SORT, &pick_list, PICK_NONE, this_type_only) > 0) free((genericptr_t) pick_list); return 0; } /* return a string describing the dungeon feature at if there is one worth mentioning at that location; otherwise null */ const char * dfeature_at(x, y, buf) int x, y; char *buf; { struct rm *lev = &levl[x][y]; int ltyp = lev->typ, cmap = -1; const char *dfeature = 0; static char altbuf[BUFSZ]; if (IS_DOOR(ltyp)) { switch (lev->doormask) { case D_NODOOR: cmap = S_ndoor; break; /* "doorway" */ case D_ISOPEN: cmap = S_vodoor; break; /* "open door" */ case D_BROKEN: dfeature = "broken door"; break; default: cmap = S_vcdoor; break; /* "closed door" */ } /* override door description for open drawbridge */ if (is_drawbridge_wall(x, y) >= 0) dfeature = "open drawbridge portcullis", cmap = -1; } else if (IS_FOUNTAIN(ltyp)) cmap = S_fountain; /* "fountain" */ else if (IS_THRONE(ltyp)) cmap = S_throne; /* "opulent throne" */ else if (is_lava(x, y)) cmap = S_lava; /* "molten lava" */ else if (is_ice(x, y)) cmap = S_ice; /* "ice" */ else if (is_pool(x, y)) dfeature = "pool of water"; else if (IS_SINK(ltyp)) cmap = S_sink; /* "sink" */ else if (IS_ALTAR(ltyp)) { Sprintf(altbuf, "%saltar to %s (%s)", ((lev->altarmask & AM_SHRINE) && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) ? "high " : "", a_gname(), align_str(Amask2align(lev->altarmask & ~AM_SHRINE))); dfeature = altbuf; } else if ((x == xupstair && y == yupstair) || (x == sstairs.sx && y == sstairs.sy && sstairs.up)) cmap = S_upstair; /* "staircase up" */ else if ((x == xdnstair && y == ydnstair) || (x == sstairs.sx && y == sstairs.sy && !sstairs.up)) cmap = S_dnstair; /* "staircase down" */ else if (x == xupladder && y == yupladder) cmap = S_upladder; /* "ladder up" */ else if (x == xdnladder && y == ydnladder) cmap = S_dnladder; /* "ladder down" */ else if (ltyp == DRAWBRIDGE_DOWN) cmap = S_vodbridge; /* "lowered drawbridge" */ else if (ltyp == DBWALL) cmap = S_vcdbridge; /* "raised drawbridge" */ else if (IS_GRAVE(ltyp)) cmap = S_grave; /* "grave" */ else if (ltyp == TREE) cmap = S_tree; /* "tree" */ else if (ltyp == IRONBARS) dfeature = "set of iron bars"; if (cmap >= 0) dfeature = defsyms[cmap].explanation; if (dfeature) Strcpy(buf, dfeature); return dfeature; } /* look at what is here; if there are many objects (pile_limit or more), don't show them unless obj_cnt is 0 */ int look_here(obj_cnt, picked_some) int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */ boolean picked_some; { struct obj *otmp; struct trap *trap; const char *verb = Blind ? "feel" : "see"; const char *dfeature = (char *) 0; char fbuf[BUFSZ], fbuf2[BUFSZ]; winid tmpwin; boolean skip_objects, felt_cockatrice = FALSE; /* default pile_limit is 5; a value of 0 means "never skip" (and 1 effectively forces "always skip") */ skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit); if (u.uswallow && u.ustuck) { struct monst *mtmp = u.ustuck; Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); /* Skip "Contents of " by using fbuf index 12 */ You("%s to %s what is lying in %s.", Blind ? "try" : "look around", verb, &fbuf[12]); otmp = mtmp->minvent; if (otmp) { for (; otmp; otmp = otmp->nobj) { /* If swallower is an animal, it should have become stone * but... */ if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); } if (Blind) Strcpy(fbuf, "You feel"); Strcat(fbuf, ":"); (void) display_minventory(mtmp, MINV_ALL, fbuf); } else { You("%s no objects here.", verb); } return !!Blind; } if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen) There("is %s here.", an(defsyms[trap_to_defsym(trap->ttyp)].explanation)); otmp = level.objects[u.ux][u.uy]; dfeature = dfeature_at(u.ux, u.uy, fbuf2); if (dfeature && !strcmp(dfeature, "pool of water") && Underwater) dfeature = 0; if (Blind) { boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz); if (dfeature && !strncmp(dfeature, "altar ", 6)) { /* don't say "altar" twice, dfeature has more info */ You("try to feel what is here."); } else { const char *where = (Blind && !can_reach_floor(TRUE)) ? "lying beneath you" : "lying here on the ", *onwhat = (Blind && !can_reach_floor(TRUE)) ? "" : surface(u.ux, u.uy); You("try to feel what is %s%s.", drift ? "floating here" : where, drift ? "" : onwhat); } if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy))) dfeature = 0; /* ice already identified */ if (!can_reach_floor(TRUE)) { pline("But you can't reach it!"); return 0; } } if (dfeature) Sprintf(fbuf, "There is %s here.", an(dfeature)); if (!otmp || is_lava(u.ux, u.uy) || (is_pool(u.ux, u.uy) && !Underwater)) { if (dfeature) pline1(fbuf); read_engr_at(u.ux, u.uy); /* Eric Backus */ if (!skip_objects && (Blind || !dfeature)) You("%s no objects here.", verb); return !!Blind; } /* we know there is something here */ if (skip_objects) { if (dfeature) pline1(fbuf); read_engr_at(u.ux, u.uy); /* Eric Backus */ if (obj_cnt == 1 && otmp->quan == 1L) There("is %s object here.", picked_some ? "another" : "an"); else There("are %s%s objects here.", (obj_cnt < 5) ? "a few" : (obj_cnt < 10) ? "several" : "many", picked_some ? " more" : ""); for (; otmp; otmp = otmp->nexthere) if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { pline("%s %s%s.", (obj_cnt > 1) ? "Including" : (otmp->quan > 1L) ? "They're" : "It's", corpse_xname(otmp, (const char *) 0, CXN_ARTICLE), poly_when_stoned(youmonst.data) ? "" : ", unfortunately"); feel_cockatrice(otmp, FALSE); break; } } else if (!otmp->nexthere) { /* only one object */ if (dfeature) pline1(fbuf); read_engr_at(u.ux, u.uy); /* Eric Backus */ You("%s here %s.", verb, doname_with_price(otmp)); iflags.last_msg = PLNMSG_ONE_ITEM_HERE; if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); } else { char buf[BUFSZ]; display_nhwindow(WIN_MESSAGE, FALSE); tmpwin = create_nhwindow(NHW_MENU); if (dfeature) { putstr(tmpwin, 0, fbuf); putstr(tmpwin, 0, ""); } Sprintf(buf, "%s that %s here:", picked_some ? "Other things" : "Things", Blind ? "you feel" : "are"); putstr(tmpwin, 0, buf); for (; otmp; otmp = otmp->nexthere) { if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { felt_cockatrice = TRUE; Sprintf(buf, "%s...", doname(otmp)); putstr(tmpwin, 0, buf); break; } putstr(tmpwin, 0, doname_with_price(otmp)); } display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); if (felt_cockatrice) feel_cockatrice(otmp, FALSE); read_engr_at(u.ux, u.uy); /* Eric Backus */ } return !!Blind; } /* the ':' command - explicitly look at what is here, including all objects */ int dolook() { return look_here(0, FALSE); } boolean will_feel_cockatrice(otmp, force_touch) struct obj *otmp; boolean force_touch; { if ((Blind || force_touch) && !uarmg && !Stone_resistance && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) return TRUE; return FALSE; } void feel_cockatrice(otmp, force_touch) struct obj *otmp; boolean force_touch; { char kbuf[BUFSZ]; if (will_feel_cockatrice(otmp, force_touch)) { /* "the corpse" */ Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE)); if (poly_when_stoned(youmonst.data)) You("touched %s with your bare %s.", kbuf, makeplural(body_part(HAND))); else pline("Touching %s is a fatal mistake...", kbuf); /* normalize body shape here; hand, not body_part(HAND) */ Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp)); /* will call polymon() for the poly_when_stoned() case */ instapetrify(kbuf); } } void stackobj(obj) struct obj *obj; { struct obj *otmp; for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere) if (otmp != obj && merged(&obj, &otmp)) break; return; } /* returns TRUE if obj & otmp can be merged */ STATIC_OVL boolean mergable(otmp, obj) register struct obj *otmp, *obj; { int objnamelth = 0, otmpnamelth = 0; if (obj == otmp) return FALSE; /* already the same object */ if (obj->otyp != otmp->otyp) return FALSE; /* coins of the same kind will always merge */ if (obj->oclass == COIN_CLASS) return TRUE; if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe || obj->dknown != otmp->dknown || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass) return FALSE; if (obj->nomerge) /* explicitly marked to prevent merge */ return FALSE; if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS) && (obj->oerodeproof != otmp->oerodeproof || obj->rknown != otmp->rknown)) return FALSE; if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) return FALSE; if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { if (obj->corpsenm != otmp->corpsenm) return FALSE; } /* hatching eggs don't merge; ditto for revivable corpses */ if ((obj->otyp == EGG && (obj->timed || otmp->timed)) || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM && is_reviver(&mons[otmp->corpsenm]))) return FALSE; /* allow candle merging only if their ages are close */ /* see begin_burn() for a reference for the magic "25" */ if (Is_candle(obj) && obj->age / 25 != otmp->age / 25) return FALSE; /* burning potions of oil never merge */ if (obj->otyp == POT_OIL && obj->lamplit) return FALSE; /* don't merge surcharged item with base-cost item */ if (obj->unpaid && !same_price(obj, otmp)) return FALSE; /* if they have names, make sure they're the same */ objnamelth = strlen(safe_oname(obj)); otmpnamelth = strlen(safe_oname(otmp)); if ((objnamelth != otmpnamelth && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE)) || (objnamelth && otmpnamelth && strncmp(ONAME(obj), ONAME(otmp), objnamelth))) return FALSE; /* for the moment, any additional information is incompatible */ if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp) || has_omid(otmp) || has_olong(otmp)) return FALSE; if (obj->oartifact != otmp->oartifact) return FALSE; if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) { return (boolean) objects[obj->otyp].oc_merge; } else return FALSE; } /* the '$' command */ int doprgold() { /* the messages used to refer to "carrying gold", but that didn't take containers into account */ long umoney = money_cnt(invent); if (!umoney) Your("wallet is empty."); else Your("wallet contains %ld %s.", umoney, currency(umoney)); shopper_financial_report(); return 0; } /* the ')' command */ int doprwep() { if (!uwep) { You("are empty %s.", body_part(HANDED)); } else { prinv((char *) 0, uwep, 0L); if (u.twoweap) prinv((char *) 0, uswapwep, 0L); } return 0; } /* caller is responsible for checking !wearing_armor() */ STATIC_OVL void noarmor(report_uskin) boolean report_uskin; { if (!uskin || !report_uskin) { You("are not wearing any armor."); } else { char *p, *uskinname, buf[BUFSZ]; uskinname = strcpy(buf, simpleonames(uskin)); /* shorten "set of dragon scales" to " scales" and " dragon scale mail" to " scale mail" */ if (!strncmpi(uskinname, "set of ", 7)) uskinname += 7; if ((p = strstri(uskinname, " dragon ")) != 0) while ((p[1] = p[8]) != '\0') ++p; You("are not wearing armor but have %s embedded in your skin.", uskinname); } } /* the '[' command */ int doprarm() { char lets[8]; register int ct = 0; /* * Note: players sometimes get here by pressing a function key which * transmits ''ESC [ '' rather than by pressing '['; * there's nothing we can--or should-do about that here. */ if (!wearing_armor()) { noarmor(TRUE); } else { if (uarmu) lets[ct++] = obj_to_let(uarmu); if (uarm) lets[ct++] = obj_to_let(uarm); if (uarmc) lets[ct++] = obj_to_let(uarmc); if (uarmh) lets[ct++] = obj_to_let(uarmh); if (uarms) lets[ct++] = obj_to_let(uarms); if (uarmg) lets[ct++] = obj_to_let(uarmg); if (uarmf) lets[ct++] = obj_to_let(uarmf); lets[ct] = 0; (void) display_inventory(lets, FALSE); } return 0; } /* the '=' command */ int doprring() { if (!uleft && !uright) You("are not wearing any rings."); else { char lets[3]; register int ct = 0; if (uleft) lets[ct++] = obj_to_let(uleft); if (uright) lets[ct++] = obj_to_let(uright); lets[ct] = 0; (void) display_inventory(lets, FALSE); } return 0; } /* the '"' command */ int dopramulet() { if (!uamul) You("are not wearing an amulet."); else prinv((char *) 0, uamul, 0L); return 0; } STATIC_OVL boolean tool_in_use(obj) struct obj *obj; { if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L) return TRUE; if (obj->oclass != TOOL_CLASS) return FALSE; return (boolean) (obj == uwep || obj->lamplit || (obj->otyp == LEASH && obj->leashmon)); } /* the '(' command */ int doprtool() { struct obj *otmp; int ct = 0; char lets[52 + 1]; for (otmp = invent; otmp; otmp = otmp->nobj) if (tool_in_use(otmp)) lets[ct++] = obj_to_let(otmp); lets[ct] = '\0'; if (!ct) You("are not using any tools."); else (void) display_inventory(lets, FALSE); return 0; } /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands; show inventory of all currently wielded, worn, or used objects */ int doprinuse() { struct obj *otmp; int ct = 0; char lets[52 + 1]; for (otmp = invent; otmp; otmp = otmp->nobj) if (is_worn(otmp) || tool_in_use(otmp)) lets[ct++] = obj_to_let(otmp); lets[ct] = '\0'; if (!ct) You("are not wearing or wielding anything."); else (void) display_inventory(lets, FALSE); return 0; } /* * uses up an object that's on the floor, charging for it as necessary */ void useupf(obj, numused) register struct obj *obj; long numused; { register struct obj *otmp; boolean at_u = (obj->ox == u.ux && obj->oy == u.uy); /* burn_floor_objects() keeps an object pointer that it tries to * useupf() multiple times, so obj must survive if plural */ if (obj->quan > numused) otmp = splitobj(obj, numused); else otmp = obj; if (costly_spot(otmp->ox, otmp->oy)) { if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0))) addtobill(otmp, FALSE, FALSE, FALSE); else (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); } delobj(otmp); if (at_u && u.uundetected && hides_under(youmonst.data)) (void) hideunder(&youmonst); } /* * Conversion from a class to a string for printing. * This must match the object class order. */ STATIC_VAR NEARDATA const char *names[] = { 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins", "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms" }; static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' }; static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" }; static NEARDATA char *invbuf = (char *) 0; static NEARDATA unsigned invbufsiz = 0; char * let_to_name(let, unpaid, showsym) char let; boolean unpaid, showsym; { const char *ocsymfmt = " ('%c')"; const int invbuf_sympadding = 8; /* arbitrary */ const char *class_name; const char *pos; int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0; unsigned len; if (oclass) class_name = names[oclass]; else if ((pos = index(oth_symbols, let)) != 0) class_name = oth_names[pos - oth_symbols]; else class_name = names[0]; len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "") + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0); if (len > invbufsiz) { if (invbuf) free((genericptr_t) invbuf); invbufsiz = len + 10; /* add slop to reduce incremental realloc */ invbuf = (char *) alloc(invbufsiz); } if (unpaid) Strcat(strcpy(invbuf, "Unpaid "), class_name); else Strcpy(invbuf, class_name); if ((oclass != 0) && showsym) { char *bp = eos(invbuf); int mlen = invbuf_sympadding - strlen(class_name); while (--mlen > 0) { *bp = ' '; bp++; } *bp = '\0'; Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym); } return invbuf; } /* release the static buffer used by let_to_name() */ void free_invbuf() { if (invbuf) free((genericptr_t) invbuf), invbuf = (char *) 0; invbufsiz = 0; } /* give consecutive letters to every item in inventory (for !fixinv mode); gold is always forced to '$' slot at head of list */ void reassign() { int i; struct obj *obj, *prevobj, *goldobj; /* first, remove [first instance of] gold from invent, if present */ prevobj = goldobj = 0; for (obj = invent; obj; prevobj = obj, obj = obj->nobj) if (obj->oclass == COIN_CLASS) { goldobj = obj; if (prevobj) prevobj->nobj = goldobj->nobj; else invent = goldobj->nobj; break; } /* second, re-letter the rest of the list */ for (obj = invent, i = 0; obj; obj = obj->nobj, i++) obj->invlet = (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM; /* third, assign gold the "letter" '$' and re-insert it at head */ if (goldobj) { goldobj->invlet = GOLD_SYM; goldobj->nobj = invent; invent = goldobj; } if (i >= 52) i = 52 - 1; lastinvnr = i; } /* #adjust command * * User specifies a 'from' slot for inventory stack to move, * then a 'to' slot for its destination. Open slots and those * filled by compatible stacks are listed as likely candidates * but user can pick any inventory letter (including 'from'). * All compatible items found are gathered into the 'from' * stack as it is moved. If the 'to' slot isn't empty and * doesn't merge, then its stack is swapped to the 'from' slot. * * If the user specifies a count when choosing the 'from' slot, * and that count is less than the full size of the stack, * then the stack will be split. The 'count' portion is moved * to the destination, and the only candidate for merging with * it is the stack already at the 'to' slot, if any. When the * destination is non-empty but won't merge, whatever is there * will be moved to an open slot; if there isn't any open slot * available, the adjustment attempt fails. * * Splitting has one special case: if 'to' slot is non-empty * and is compatible with 'from' in all respects except for * user-assigned names, the 'count' portion being moved is * effectively renamed so that it will merge with 'to' stack. */ int doorganize() /* inventory organizer by Del Lamb */ { struct obj *obj, *otmp, *splitting, *bumped; int ix, cur, trycnt; char let; char alphabet[52 + 1], buf[52 + 1]; char qbuf[QBUFSZ]; char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */ const char *adj_type; if (!invent) { You("aren't carrying anything to adjust."); return 0; } if (!flags.invlet_constant) reassign(); /* get object the user wants to organize (the 'from' slot) */ allowall[0] = ALLOW_COUNT; allowall[1] = ALL_CLASSES; allowall[2] = '\0'; if (!(obj = getobj(allowall, "adjust"))) return 0; /* figure out whether user gave a split count to getobj() */ splitting = bumped = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->nobj == obj) { /* knowledge of splitobj() operation */ if (otmp->invlet == obj->invlet) splitting = otmp; break; } /* initialize the list with all lower and upper case letters */ for (ix = 0, let = 'a'; let <= 'z';) alphabet[ix++] = let++; for (let = 'A'; let <= 'Z';) alphabet[ix++] = let++; alphabet[ix] = '\0'; /* for floating inv letters, truncate list after the first open slot */ if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52) alphabet[ix + (splitting ? 0 : 1)] = '\0'; /* blank out all the letters currently in use in the inventory */ /* except those that will be merged with the selected object */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp != obj && !mergable(otmp, obj)) { let = otmp->invlet; if (let >= 'a' && let <= 'z') alphabet[let - 'a'] = ' '; else if (let >= 'A' && let <= 'Z') alphabet[let - 'A' + 26] = ' '; } /* compact the list by removing all the blanks */ for (ix = cur = 0; alphabet[ix]; ix++) if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix]; if (!cur && obj->invlet == NOINVSYM) buf[cur++] = NOINVSYM; buf[cur] = '\0'; /* and by dashing runs of letters */ if (cur > 5) compactify(buf); /* get 'to' slot to use as destination */ Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf, invent ? " (? see used letters)" : ""); for (trycnt = 1; ; ++trycnt) { let = yn_function(qbuf, (char *) 0, '\0'); if (let == '?' || let == '*') { let = display_used_invlets(splitting ? obj->invlet : 0); if (!let) continue; if (let == '\033') goto noadjust; } if (index(quitchars, let) /* adjusting to same slot is meaningful since all compatible stacks get collected along the way, but splitting to same slot is not */ || (splitting && let == obj->invlet)) { noadjust: if (splitting) (void) merged(&splitting, &obj); pline1(Never_mind); return 0; } if ((letter(let) && let != '@') || index(buf, let)) break; /* got one */ if (trycnt == 5) goto noadjust; pline("Select an inventory slot letter."); /* else try again */ } /* change the inventory and print the resulting item */ adj_type = !splitting ? "Moving:" : "Splitting:"; /* * don't use freeinv/addinv to avoid double-touching artifacts, * dousing lamps, losing luck, cursing loadstone, etc. */ extract_nobj(obj, &invent); for (otmp = invent; otmp;) { if (!splitting) { if (merged(&otmp, &obj)) { adj_type = "Merging:"; obj = otmp; otmp = otmp->nobj; extract_nobj(obj, &invent); continue; /* otmp has already been updated */ } else if (otmp->invlet == let) { adj_type = "Swapping:"; otmp->invlet = obj->invlet; } } else { /* splitting: don't merge extra compatible stacks; if destination is compatible, do merge with it, otherwise bump whatever is there to an open slot */ if (otmp->invlet == let) { int olth = 0; if (has_oname(obj)) olth = strlen(ONAME(obj)); /* ugly hack: if these objects aren't going to merge solely because they have conflicting user-assigned names, strip off the name of the one being moved */ if (olth && !obj->oartifact && !mergable(otmp, obj)) { char *holdname = ONAME(obj); ONAME(obj) = (char *) 0; /* restore name iff merging is still not possible */ if (!mergable(otmp, obj)) { ONAME(obj) = holdname; holdname = (char *) 0; } else free((genericptr_t) holdname); } if (merged(&otmp, &obj)) { obj = otmp; extract_nobj(obj, &invent); } else if (inv_cnt(FALSE) >= 52) { (void) merged(&splitting, &obj); /* undo split */ /* "knapsack cannot accommodate any more items" */ Your("pack is too full."); return 0; } else { bumped = otmp; extract_nobj(bumped, &invent); } break; } /* found 'to' slot */ } /* splitting */ otmp = otmp->nobj; } /* inline addinv; insert loose object at beginning of inventory */ obj->invlet = let; obj->nobj = invent; obj->where = OBJ_INVENT; invent = obj; reorder_invent(); if (bumped) { /* splitting the 'from' stack is causing an incompatible stack in the 'to' slot to be moved into an open one; we need to do another inline insertion to inventory */ assigninvlet(bumped); bumped->nobj = invent; bumped->where = OBJ_INVENT; invent = bumped; reorder_invent(); } /* messages deferred until inventory has been fully reestablished */ prinv(adj_type, obj, 0L); if (bumped) prinv("Moving:", bumped, 0L); if (splitting) clear_splitobjs(); /* reset splitobj context */ update_inventory(); return 0; } /* common to display_minventory and display_cinventory */ STATIC_OVL void invdisp_nothing(hdr, txt) const char *hdr, *txt; { winid win; anything any; menu_item *selected; any = zeroany; win = create_nhwindow(NHW_MENU); start_menu(win); add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED); end_menu(win, (char *) 0); if (select_menu(win, PICK_NONE, &selected) > 0) free((genericptr_t) selected); destroy_nhwindow(win); return; } /* query_objlist callback: return things that are worn or wielded */ STATIC_OVL boolean worn_wield_only(obj) struct obj *obj; { #if 1 /* check for things that *are* worn or wielded (only used for monsters, so we don't worry about excluding W_CHAIN, W_ARTI and the like) */ return (boolean) (obj->owornmask != 0L); #else /* this used to check for things that *might* be worn or wielded, but that's not particularly interesting */ if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING) return TRUE; return (boolean) (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS || obj->oclass == AMULET_CLASS || obj->oclass == RING_CLASS); #endif } /* * Display a monster's inventory. * Returns a pointer to the object from the monster's inventory selected * or NULL if nothing was selected. * * By default, only worn and wielded items are displayed. The caller * can pick one. Modifier flags are: * * MINV_NOLET - nothing selectable * MINV_ALL - display all inventory */ struct obj * display_minventory(mon, dflags, title) register struct monst *mon; int dflags; char *title; { struct obj *ret; char tmp[QBUFSZ]; int n; menu_item *selected = 0; int do_all = (dflags & MINV_ALL) != 0, incl_hero = (do_all && u.uswallow && mon == u.ustuck), have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero); Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)), do_all ? "possessions" : "armament"); if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) { /* Fool the 'weapon in hand' routine into * displaying 'weapon in claw', etc. properly. */ youmonst.data = mon->data; n = query_objlist(title ? title : tmp, mon->minvent, INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0), &selected, (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE, do_all ? allow_all : worn_wield_only); set_uasmon(); } else { invdisp_nothing(title ? title : tmp, "(none)"); n = 0; } if (n > 0) { ret = selected[0].item.a_obj; free((genericptr_t) selected); } else ret = (struct obj *) 0; return ret; } /* * Display the contents of a container in inventory style. * Currently, this is only used for statues, via wand of probing. */ struct obj * display_cinventory(obj) register struct obj *obj; { struct obj *ret; char qbuf[QBUFSZ]; int n; menu_item *selected = 0; (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname, "that"); if (obj->cobj) { n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected, PICK_NONE, allow_all); } else { invdisp_nothing(qbuf, "(empty)"); n = 0; } if (n > 0) { ret = selected[0].item.a_obj; free((genericptr_t) selected); } else ret = (struct obj *) 0; obj->cknown = 1; return ret; } /* query objlist callback: return TRUE if obj is at given location */ static coord only; STATIC_OVL boolean only_here(obj) struct obj *obj; { return (obj->ox == only.x && obj->oy == only.y); } /* * Display a list of buried items in inventory style. Return a non-zero * value if there were items at that spot. * * Currently, this is only used with a wand of probing zapped downwards. */ int display_binventory(x, y, as_if_seen) int x, y; boolean as_if_seen; { struct obj *obj; menu_item *selected = 0; int n; /* count # of objects here */ for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj) if (obj->ox == x && obj->oy == y) { if (as_if_seen) obj->dknown = 1; n++; } if (n) { only.x = x; only.y = y; if (query_objlist("Things that are buried here:", level.buriedobjlist, INVORDER_SORT, &selected, PICK_NONE, only_here) > 0) free((genericptr_t) selected); only.x = only.y = 0; } return n; } /*invent.c*/ nethack-3.6.0/src/light.c0000664000076400007660000005446712614623007014220 0ustar paxedpaxed/* NetHack 3.6 light.c $NHDT-Date: 1446191876 2015/10/30 07:57:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Dean Luick, 1994 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" /* for checking save modes */ /* * Mobile light sources. * * This implementation minimizes memory at the expense of extra * recalculations. * * Light sources are "things" that have a physical position and range. * They have a type, which gives us information about them. Currently * they are only attached to objects and monsters. Note well: the * polymorphed-player handling assumes that both youmonst.m_id and * youmonst.mx will always remain 0. * * Light sources, like timers, either follow game play (RANGE_GLOBAL) or * stay on a level (RANGE_LEVEL). Light sources are unique by their * (type, id) pair. For light sources attached to objects, this id * is a pointer to the object. * * The major working function is do_light_sources(). It is called * when the vision system is recreating its "could see" array. Here * we add a flag (TEMP_LIT) to the array for all locations that are lit * via a light source. The bad part of this is that we have to * re-calculate the LOS of each light source every time the vision * system runs. Even if the light sources and any topology (vision blocking * positions) have not changed. The good part is that no extra memory * is used, plus we don't have to figure out how far the sources have moved, * or if the topology has changed. * * The structure of the save/restore mechanism is amazingly similar to * the timer save/restore. This is because they both have the same * principals of having pointers into objects that must be recalculated * across saves and restores. */ /* flags */ #define LSF_SHOW 0x1 /* display the light source */ #define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */ static light_source *light_base = 0; STATIC_DCL void FDECL(write_ls, (int, light_source *)); STATIC_DCL int FDECL(maybe_write_ls, (int, int, BOOLEAN_P)); /* imported from vision.c, for small circles */ extern char circle_data[]; extern char circle_start[]; /* Create a new light source. */ void new_light_source(x, y, range, type, id) xchar x, y; int range, type; anything *id; { light_source *ls; if (range > MAX_RADIUS || range < 1) { impossible("new_light_source: illegal range %d", range); return; } ls = (light_source *) alloc(sizeof(light_source)); ls->next = light_base; ls->x = x; ls->y = y; ls->range = range; ls->type = type; ls->id = *id; ls->flags = 0; light_base = ls; vision_full_recalc = 1; /* make the source show up */ } /* * Delete a light source. This assumes only one light source is attached * to an object at a time. */ void del_light_source(type, id) int type; anything *id; { light_source *curr, *prev; anything tmp_id; tmp_id = zeroany; /* need to be prepared for dealing a with light source which has only been partially restored during a level change (in particular: chameleon vs prot. from shape changers) */ switch (type) { case LS_OBJECT: tmp_id.a_uint = id->a_obj->o_id; break; case LS_MONSTER: tmp_id.a_uint = id->a_monst->m_id; break; default: tmp_id.a_uint = 0; break; } for (prev = 0, curr = light_base; curr; prev = curr, curr = curr->next) { if (curr->type != type) continue; if (curr->id.a_obj == ((curr->flags & LSF_NEEDS_FIXUP) ? tmp_id.a_obj : id->a_obj)) { if (prev) prev->next = curr->next; else light_base = curr->next; free((genericptr_t) curr); vision_full_recalc = 1; return; } } impossible("del_light_source: not found type=%d, id=%s", type, fmt_ptr((genericptr_t) id->a_obj)); } /* Mark locations that are temporarily lit via mobile light sources. */ void do_light_sources(cs_rows) char **cs_rows; { int x, y, min_x, max_x, max_y, offset; char *limits; short at_hero_range = 0; light_source *ls; char *row; for (ls = light_base; ls; ls = ls->next) { ls->flags &= ~LSF_SHOW; /* * Check for moved light sources. It may be possible to * save some effort if an object has not moved, but not in * the current setup -- we need to recalculate for every * vision recalc. */ if (ls->type == LS_OBJECT) { if (get_obj_location(ls->id.a_obj, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } else if (ls->type == LS_MONSTER) { if (get_mon_location(ls->id.a_monst, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } /* minor optimization: don't bother with duplicate light sources */ /* at hero */ if (ls->x == u.ux && ls->y == u.uy) { if (at_hero_range >= ls->range) ls->flags &= ~LSF_SHOW; else at_hero_range = ls->range; } if (ls->flags & LSF_SHOW) { /* * Walk the points in the circle and see if they are * visible from the center. If so, mark'em. * * Kevin's tests indicated that doing this brute-force * method is faster for radius <= 3 (or so). */ limits = circle_ptr(ls->range); if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO - 1; if ((y = (ls->y - ls->range)) < 0) y = 0; for (; y <= max_y; y++) { row = cs_rows[y]; offset = limits[abs(y - ls->y)]; if ((min_x = (ls->x - offset)) < 0) min_x = 0; if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO - 1; if (ls->x == u.ux && ls->y == u.uy) { /* * If the light source is located at the hero, then * we can use the COULD_SEE bits already calculated * by the vision system. More importantly than * this optimization, is that it allows the vision * system to correct problems with clear_path(). * The function clear_path() is a simple LOS * path checker that doesn't go out of its way * make things look "correct". The vision system * does this. */ for (x = min_x; x <= max_x; x++) if (row[x] & COULD_SEE) row[x] |= TEMP_LIT; } else { for (x = min_x; x <= max_x; x++) if ((ls->x == x && ls->y == y) || clear_path((int) ls->x, (int) ls->y, x, y)) row[x] |= TEMP_LIT; } } } } } /* (mon->mx == 0) implies migrating */ #define mon_is_local(mon) ((mon)->mx > 0) struct monst * find_mid(nid, fmflags) unsigned nid; unsigned fmflags; { struct monst *mtmp; if (!nid) return &youmonst; if (fmflags & FM_FMON) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && mtmp->m_id == nid) return mtmp; if (fmflags & FM_MIGRATE) for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == nid) return mtmp; if (fmflags & FM_MYDOGS) for (mtmp = mydogs; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == nid) return mtmp; return (struct monst *) 0; } /* Save all light sources of the given range. */ void save_light_sources(fd, mode, range) int fd, mode, range; { int count, actual, is_global; light_source **prev, *curr; if (perform_bwrite(mode)) { count = maybe_write_ls(fd, range, FALSE); bwrite(fd, (genericptr_t) &count, sizeof count); actual = maybe_write_ls(fd, range, TRUE); if (actual != count) panic("counted %d light sources, wrote %d! [range=%d]", count, actual, range); } if (release_data(mode)) { for (prev = &light_base; (curr = *prev) != 0;) { if (!curr->id.a_monst) { impossible("save_light_sources: no id! [range=%d]", range); is_global = 0; } else switch (curr->type) { case LS_OBJECT: is_global = !obj_is_local(curr->id.a_obj); break; case LS_MONSTER: is_global = !mon_is_local(curr->id.a_monst); break; default: is_global = 0; impossible("save_light_sources: bad type (%d) [range=%d]", curr->type, range); break; } /* if global and not doing local, or vice versa, remove it */ if (is_global ^ (range == RANGE_LEVEL)) { *prev = curr->next; free((genericptr_t) curr); } else { prev = &(*prev)->next; } } } } /* * Pull in the structures from disk, but don't recalculate the object * pointers. */ void restore_light_sources(fd) int fd; { int count; light_source *ls; /* restore elements */ mread(fd, (genericptr_t) &count, sizeof count); while (count-- > 0) { ls = (light_source *) alloc(sizeof(light_source)); mread(fd, (genericptr_t) ls, sizeof(light_source)); ls->next = light_base; light_base = ls; } } /* Relink all lights that are so marked. */ void relink_light_sources(ghostly) boolean ghostly; { char which; unsigned nid; light_source *ls; for (ls = light_base; ls; ls = ls->next) { if (ls->flags & LSF_NEEDS_FIXUP) { if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ghostly) { if (!lookup_id_mapping(ls->id.a_uint, &nid)) impossible("relink_light_sources: no id mapping"); } else nid = ls->id.a_uint; if (ls->type == LS_OBJECT) { which = 'o'; ls->id.a_obj = find_oid(nid); } else { which = 'm'; ls->id.a_monst = find_mid(nid, FM_EVERYWHERE); } if (!ls->id.a_monst) impossible("relink_light_sources: cant find %c_id %d", which, nid); } else impossible("relink_light_sources: bad type (%d)", ls->type); ls->flags &= ~LSF_NEEDS_FIXUP; } } } /* * Part of the light source save routine. Count up the number of light * sources that would be written. If write_it is true, actually write * the light source out. */ STATIC_OVL int maybe_write_ls(fd, range, write_it) int fd, range; boolean write_it; { int count = 0, is_global; light_source *ls; for (ls = light_base; ls; ls = ls->next) { if (!ls->id.a_monst) { impossible("maybe_write_ls: no id! [range=%d]", range); continue; } switch (ls->type) { case LS_OBJECT: is_global = !obj_is_local(ls->id.a_obj); break; case LS_MONSTER: is_global = !mon_is_local(ls->id.a_monst); break; default: is_global = 0; impossible("maybe_write_ls: bad type (%d) [range=%d]", ls->type, range); break; } /* if global and not doing local, or vice versa, count it */ if (is_global ^ (range == RANGE_LEVEL)) { count++; if (write_it) write_ls(fd, ls); } } return count; } void light_sources_sanity_check() { light_source *ls; struct monst *mtmp; struct obj *otmp; unsigned int auint; for (ls = light_base; ls; ls = ls->next) { if (!ls->id.a_monst) panic("insane light source: no id!"); if (ls->type == LS_OBJECT) { otmp = (struct obj *) ls->id.a_obj; auint = otmp->o_id; if (find_oid(auint) != otmp) panic("insane light source: can't find obj #%u!", auint); } else if (ls->type == LS_MONSTER) { mtmp = (struct monst *) ls->id.a_monst; auint = mtmp->m_id; if (find_mid(auint, FM_EVERYWHERE) != mtmp) panic("insane light source: can't find mon #%u!", auint); } else { panic("insane light source: bad ls type %d", ls->type); } } } /* Write a light source structure to disk. */ STATIC_OVL void write_ls(fd, ls) int fd; light_source *ls; { anything arg_save; struct obj *otmp; struct monst *mtmp; if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ls->flags & LSF_NEEDS_FIXUP) { bwrite(fd, (genericptr_t) ls, sizeof(light_source)); } else { /* replace object pointer with id for write, then put back */ arg_save = ls->id; if (ls->type == LS_OBJECT) { otmp = ls->id.a_obj; ls->id = zeroany; ls->id.a_uint = otmp->o_id; if (find_oid((unsigned) ls->id.a_uint) != otmp) impossible("write_ls: can't find obj #%u!", ls->id.a_uint); } else { /* ls->type == LS_MONSTER */ mtmp = (struct monst *) ls->id.a_monst; ls->id = zeroany; ls->id.a_uint = mtmp->m_id; if (find_mid((unsigned) ls->id.a_uint, FM_EVERYWHERE) != mtmp) impossible("write_ls: can't find mon #%u!", ls->id.a_uint); } ls->flags |= LSF_NEEDS_FIXUP; bwrite(fd, (genericptr_t) ls, sizeof(light_source)); ls->id = arg_save; ls->flags &= ~LSF_NEEDS_FIXUP; } } else { impossible("write_ls: bad type (%d)", ls->type); } } /* Change light source's ID from src to dest. */ void obj_move_light_source(src, dest) struct obj *src, *dest; { light_source *ls; for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id.a_obj == src) ls->id.a_obj = dest; src->lamplit = 0; dest->lamplit = 1; } /* return true if there exist any light sources */ boolean any_light_source() { return (boolean) (light_base != (light_source *) 0); } /* * Snuff an object light source if at (x,y). This currently works * only for burning light sources. */ void snuff_light_source(x, y) int x, y; { light_source *ls; struct obj *obj; for (ls = light_base; ls; ls = ls->next) /* * Is this position check valid??? Can I assume that the positions * will always be correct because the objects would have been * updated with the last vision update? [Is that recent enough???] */ if (ls->type == LS_OBJECT && ls->x == x && ls->y == y) { obj = ls->id.a_obj; if (obj_is_burning(obj)) { /* The only way to snuff Sunsword is to unwield it. Darkness * scrolls won't affect it. (If we got here because it was * dropped or thrown inside a monster, this won't matter * anyway because it will go out when dropped.) */ if (artifact_light(obj)) continue; end_burn(obj, obj->otyp != MAGIC_LAMP); /* * The current ls element has just been removed (and * ls->next is now invalid). Return assuming that there * is only one light source attached to each object. */ return; } } } /* Return TRUE if object sheds any light at all. */ boolean obj_sheds_light(obj) struct obj *obj; { /* so far, only burning objects shed light */ return obj_is_burning(obj); } /* Return TRUE if sheds light AND will be snuffed by end_burn(). */ boolean obj_is_burning(obj) struct obj *obj; { return (boolean) (obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj) || artifact_light(obj))); } /* copy the light source(s) attached to src, and attach it/them to dest */ void obj_split_light_source(src, dest) struct obj *src, *dest; { light_source *ls, *new_ls; for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id.a_obj == src) { /* * Insert the new source at beginning of list. This will * never interfere us walking down the list - we are already * past the insertion point. */ new_ls = (light_source *) alloc(sizeof(light_source)); *new_ls = *ls; if (Is_candle(src)) { /* split candles may emit less light than original group */ ls->range = candle_light_range(src); new_ls->range = candle_light_range(dest); vision_full_recalc = 1; /* in case range changed */ } new_ls->id.a_obj = dest; new_ls->next = light_base; light_base = new_ls; dest->lamplit = 1; /* now an active light source */ } } /* light source `src' has been folded into light source `dest'; used for merging lit candles and adding candle(s) to lit candelabrum */ void obj_merge_light_sources(src, dest) struct obj *src, *dest; { light_source *ls; /* src == dest implies adding to candelabrum */ if (src != dest) end_burn(src, TRUE); /* extinguish candles */ for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id.a_obj == dest) { ls->range = candle_light_range(dest); vision_full_recalc = 1; /* in case range changed */ break; } } /* light source `obj' is being made brighter or dimmer */ void obj_adjust_light_radius(obj, new_radius) struct obj *obj; int new_radius; { light_source *ls; for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id.a_obj == obj) { if (new_radius != ls->range) vision_full_recalc = 1; ls->range = new_radius; return; } impossible("obj_adjust_light_radius: can't find %s", xname(obj)); } /* Candlelight is proportional to the number of candles; minimum range is 2 rather than 1 for playability. */ int candle_light_range(obj) struct obj *obj; { int radius; if (obj->otyp == CANDELABRUM_OF_INVOCATION) { /* * The special candelabrum emits more light than the * corresponding number of candles would. * 1..3 candles, range 2 (minimum range); * 4..6 candles, range 3 (normal lamp range); * 7 candles, range 4 (bright). */ radius = (obj->spe < 4) ? 2 : (obj->spe < 7) ? 3 : 4; } else if (Is_candle(obj)) { /* * Range is incremented by powers of 7 so that it will take * wizard mode quantities of candles to get more light than * from a lamp, without imposing an arbitrary limit. * 1..6 candles, range 2; * 7..48 candles, range 3; * 49..342 candles, range 4; &c. */ long n = obj->quan; radius = 1; /* always incremented at least once */ do { radius++; n /= 7L; } while (n > 0L); } else { /* we're only called for lit candelabrum or candles */ /* impossible("candlelight for %d?", obj->otyp); */ radius = 3; /* lamp's value */ } return radius; } /* light emitting artifact's range depends upon its curse/bless state */ int arti_light_radius(obj) struct obj *obj; { /* * Used by begin_burn() when setting up a new light source * (obj->lamplit will already be set by this point) and * also by bless()/unbless()/uncurse()/curse() to decide * whether to call obj_adjust_light_radius(). */ /* sanity check [simplifies usage by bless()/curse()/&c] */ if (!obj->lamplit || !artifact_light(obj)) return 0; /* cursed radius of 1 is not noticeable for an item that's carried by the hero but is if it's carried by a monster or left lit on the floor (not applicable for Sunsword) */ return (obj->blessed ? 3 : !obj->cursed ? 2 : 1); } /* adverb describing lit artifact's light; depends on curse/bless state */ const char * arti_light_description(obj) struct obj *obj; { switch (arti_light_radius(obj)) { case 3: return "brilliantly"; /* blessed */ case 2: return "brightly"; /* uncursed */ case 1: return "dimly"; /* cursed */ default: break; } return "strangely"; } int wiz_light_sources() { winid win; char buf[BUFSZ]; light_source *ls; win = create_nhwindow(NHW_MENU); /* corner text window */ if (win == WIN_ERR) return 0; Sprintf(buf, "Mobile light sources: hero @ (%2d,%2d)", u.ux, u.uy); putstr(win, 0, buf); putstr(win, 0, ""); if (light_base) { putstr(win, 0, "location range flags type id"); putstr(win, 0, "-------- ----- ------ ---- -------"); for (ls = light_base; ls; ls = ls->next) { Sprintf(buf, " %2d,%2d %2d 0x%04x %s %s", ls->x, ls->y, ls->range, ls->flags, (ls->type == LS_OBJECT ? "obj" : ls->type == LS_MONSTER ? (mon_is_local(ls->id.a_monst) ? "mon" : (ls->id.a_monst == &youmonst) ? "you" /* migrating monster */ : "") : "???"), fmt_ptr(ls->id.a_void)); putstr(win, 0, buf); } } else putstr(win, 0, ""); display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } /*light.c*/ nethack-3.6.0/src/lock.c0000664000076400007660000010003612623162643014025 0ustar paxedpaxed/* NetHack 3.6 lock.c $NHDT-Date: 1446955300 2015/11/08 04:01:40 $ $NHDT-Branch: master $:$NHDT-Revision: 1.67 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(picklock); STATIC_PTR int NDECL(forcelock); /* at most one of `door' and `box' should be non-null at any given time */ STATIC_VAR NEARDATA struct xlock_s { struct rm *door; struct obj *box; int picktyp, /* key|pick|card for unlock, sharp vs blunt for #force */ chance, usedtime; } xlock; STATIC_DCL const char *NDECL(lock_action); STATIC_DCL boolean FDECL(obstructed, (int, int, BOOLEAN_P)); STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *)); boolean picking_lock(x, y) int *x, *y; { if (occupation == picklock) { *x = u.ux + u.dx; *y = u.uy + u.dy; return TRUE; } else { *x = *y = 0; return FALSE; } } boolean picking_at(x, y) int x, y; { return (boolean) (occupation == picklock && xlock.door == &levl[x][y]); } /* produce an occupation string appropriate for the current activity */ STATIC_OVL const char * lock_action() { /* "unlocking"+2 == "locking" */ static const char *actions[] = { "unlocking the door", /* [0] */ "unlocking the chest", /* [1] */ "unlocking the box", /* [2] */ "picking the lock" /* [3] */ }; /* if the target is currently unlocked, we're trying to lock it now */ if (xlock.door && !(xlock.door->doormask & D_LOCKED)) return actions[0] + 2; /* "locking the door" */ else if (xlock.box && !xlock.box->olocked) return xlock.box->otyp == CHEST ? actions[1] + 2 : actions[2] + 2; /* otherwise we're trying to unlock it */ else if (xlock.picktyp == LOCK_PICK) return actions[3]; /* "picking the lock" */ else if (xlock.picktyp == CREDIT_CARD) return actions[3]; /* same as lock_pick */ else if (xlock.door) return actions[0]; /* "unlocking the door" */ else if (xlock.box) return xlock.box->otyp == CHEST ? actions[1] : actions[2]; else return actions[3]; } /* try to open/close a lock */ STATIC_PTR int picklock(VOID_ARGS) { if (xlock.box) { if ((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) { return ((xlock.usedtime = 0)); /* you or it moved */ } } else { /* door */ if (xlock.door != &(levl[u.ux + u.dx][u.uy + u.dy])) { return ((xlock.usedtime = 0)); /* you moved */ } switch (xlock.door->doormask) { case D_NODOOR: pline("This doorway has no door."); return ((xlock.usedtime = 0)); case D_ISOPEN: You("cannot lock an open door."); return ((xlock.usedtime = 0)); case D_BROKEN: pline("This door is broken."); return ((xlock.usedtime = 0)); } } if (xlock.usedtime++ >= 50 || nohands(youmonst.data)) { You("give up your attempt at %s.", lock_action()); exercise(A_DEX, TRUE); /* even if you don't succeed */ return ((xlock.usedtime = 0)); } if (rn2(100) >= xlock.chance) return 1; /* still busy */ You("succeed in %s.", lock_action()); if (xlock.door) { if (xlock.door->doormask & D_TRAPPED) { b_trapped("door", FINGER); xlock.door->doormask = D_NODOOR; unblock_point(u.ux + u.dx, u.uy + u.dy); if (*in_rooms(u.ux + u.dx, u.uy + u.dy, SHOPBASE)) add_damage(u.ux + u.dx, u.uy + u.dy, 0L); newsym(u.ux + u.dx, u.uy + u.dy); } else if (xlock.door->doormask & D_LOCKED) xlock.door->doormask = D_CLOSED; else xlock.door->doormask = D_LOCKED; } else { xlock.box->olocked = !xlock.box->olocked; xlock.box->lknown = 1; if (xlock.box->otrapped) (void) chest_trap(xlock.box, FINGER, FALSE); } exercise(A_DEX, TRUE); return ((xlock.usedtime = 0)); } void breakchestlock(box, destroyit) struct obj *box; boolean destroyit; { if (!destroyit) { /* bill for the box but not for its contents */ struct obj *hide_contents = box->cobj; box->cobj = 0; costly_alteration(box, COST_BRKLCK); box->cobj = hide_contents; box->olocked = 0; box->obroken = 1; box->lknown = 1; } else { /* #force has destroyed this box (at ) */ struct obj *otmp; struct monst *shkp = (*u.ushops && costly_spot(u.ux, u.uy)) ? shop_keeper(*u.ushops) : 0; boolean costly = (boolean) (shkp != 0), peaceful_shk = costly && (boolean) shkp->mpeaceful; long loss = 0L; pline("In fact, you've totally destroyed %s.", the(xname(box))); /* Put the contents on ground at the hero's feet. */ while ((otmp = box->cobj) != 0) { obj_extract_self(otmp); if (!rn2(3) || otmp->oclass == POTION_CLASS) { chest_shatter_msg(otmp); if (costly) loss += stolen_value(otmp, u.ux, u.uy, peaceful_shk, TRUE); if (otmp->quan == 1L) { obfree(otmp, (struct obj *) 0); continue; } useup(otmp); } if (box->otyp == ICE_BOX && otmp->otyp == CORPSE) { otmp->age = monstermoves - otmp->age; /* actual age */ start_corpse_timeout(otmp); } place_object(otmp, u.ux, u.uy); stackobj(otmp); } if (costly) loss += stolen_value(box, u.ux, u.uy, peaceful_shk, TRUE); if (loss) You("owe %ld %s for objects destroyed.", loss, currency(loss)); delobj(box); } } /* try to force a locked chest */ STATIC_PTR int forcelock(VOID_ARGS) { if ((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) return ((xlock.usedtime = 0)); /* you or it moved */ if (xlock.usedtime++ >= 50 || !uwep || nohands(youmonst.data)) { You("give up your attempt to force the lock."); if (xlock.usedtime >= 50) /* you made the effort */ exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE); return ((xlock.usedtime = 0)); } if (xlock.picktyp) { /* blade */ if (rn2(1000 - (int) uwep->spe) > (992 - greatest_erosion(uwep) * 10) && !uwep->cursed && !obj_resists(uwep, 0, 99)) { /* for a +0 weapon, probability that it survives an unsuccessful * attempt to force the lock is (.992)^50 = .67 */ pline("%sour %s broke!", (uwep->quan > 1L) ? "One of y" : "Y", xname(uwep)); useup(uwep); You("give up your attempt to force the lock."); exercise(A_DEX, TRUE); return ((xlock.usedtime = 0)); } } else /* blunt */ wake_nearby(); /* due to hammering on the container */ if (rn2(100) >= xlock.chance) return 1; /* still busy */ You("succeed in forcing the lock."); breakchestlock(xlock.box, (boolean) (!xlock.picktyp && !rn2(3))); exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE); return ((xlock.usedtime = 0)); } void reset_pick() { xlock.usedtime = xlock.chance = xlock.picktyp = 0; xlock.door = 0; xlock.box = 0; } /* for doapply(); if player gives a direction or resumes an interrupted previous attempt then it costs hero a move even if nothing ultimately happens; when told "can't do that" before being asked for direction or player cancels with ESC while giving direction, it doesn't */ #define PICKLOCK_LEARNED_SOMETHING (-1) /* time passes */ #define PICKLOCK_DID_NOTHING 0 /* no time passes */ #define PICKLOCK_DID_SOMETHING 1 /* player is applying a key, lock pick, or credit card */ int pick_lock(pick) struct obj *pick; { int picktyp, c, ch; coord cc; struct rm *door; struct obj *otmp; char qbuf[QBUFSZ]; picktyp = pick->otyp; /* check whether we're resuming an interrupted previous attempt */ if (xlock.usedtime && picktyp == xlock.picktyp) { static char no_longer[] = "Unfortunately, you can no longer %s %s."; if (nohands(youmonst.data)) { const char *what = (picktyp == LOCK_PICK) ? "pick" : "key"; if (picktyp == CREDIT_CARD) what = "card"; pline(no_longer, "hold the", what); reset_pick(); return PICKLOCK_LEARNED_SOMETHING; } else if (u.uswallow || (xlock.box && !can_reach_floor(TRUE))) { pline(no_longer, "reach the", "lock"); reset_pick(); return PICKLOCK_LEARNED_SOMETHING; } else { const char *action = lock_action(); You("resume your attempt at %s.", action); set_occupation(picklock, action, 0); return PICKLOCK_DID_SOMETHING; } } if (nohands(youmonst.data)) { You_cant("hold %s -- you have no hands!", doname(pick)); return PICKLOCK_DID_NOTHING; } else if (u.uswallow) { You_cant("%sunlock %s.", (picktyp == CREDIT_CARD) ? "" : "lock or ", mon_nam(u.ustuck)); return PICKLOCK_DID_NOTHING; } if ((picktyp != LOCK_PICK && picktyp != CREDIT_CARD && picktyp != SKELETON_KEY)) { impossible("picking lock with object %d?", picktyp); return PICKLOCK_DID_NOTHING; } ch = 0; /* lint suppression */ if (!get_adjacent_loc((char *) 0, "Invalid location!", u.ux, u.uy, &cc)) return PICKLOCK_DID_NOTHING; if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */ const char *verb; char qsfx[QBUFSZ]; boolean it; int count; if (u.dz < 0) { There("isn't any sort of lock up %s.", Levitation ? "here" : "there"); return PICKLOCK_LEARNED_SOMETHING; } else if (is_lava(u.ux, u.uy)) { pline("Doing that would probably melt %s.", yname(pick)); return PICKLOCK_LEARNED_SOMETHING; } else if (is_pool(u.ux, u.uy) && !Underwater) { pline_The("water has no lock."); return PICKLOCK_LEARNED_SOMETHING; } count = 0; c = 'n'; /* in case there are no boxes here */ for (otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { ++count; if (!can_reach_floor(TRUE)) { You_cant("reach %s from up here.", the(xname(otmp))); return PICKLOCK_LEARNED_SOMETHING; } it = 0; if (otmp->obroken) verb = "fix"; else if (!otmp->olocked) verb = "lock", it = 1; else if (picktyp != LOCK_PICK) verb = "unlock", it = 1; else verb = "pick"; /* "There is here; ?" */ Sprintf(qsfx, " here; %s %s?", verb, it ? "it" : "its lock"); (void) safe_qbuf(qbuf, "There is ", qsfx, otmp, doname, ansimpleoname, "a box"); otmp->lknown = 1; c = ynq(qbuf); if (c == 'q') return 0; if (c == 'n') continue; if (otmp->obroken) { You_cant("fix its broken lock with %s.", doname(pick)); return PICKLOCK_LEARNED_SOMETHING; } else if (picktyp == CREDIT_CARD && !otmp->olocked) { /* credit cards are only good for unlocking */ You_cant("do that with %s.", an(simple_typename(picktyp))); return PICKLOCK_LEARNED_SOMETHING; } switch (picktyp) { case CREDIT_CARD: ch = ACURR(A_DEX) + 20 * Role_if(PM_ROGUE); break; case LOCK_PICK: ch = 4 * ACURR(A_DEX) + 25 * Role_if(PM_ROGUE); break; case SKELETON_KEY: ch = 75 + ACURR(A_DEX); break; default: ch = 0; } if (otmp->cursed) ch /= 2; xlock.picktyp = picktyp; xlock.box = otmp; xlock.door = 0; break; } if (c != 'y') { if (!count) There("doesn't seem to be any sort of lock here."); return PICKLOCK_LEARNED_SOMETHING; /* decided against all boxes */ } } else { /* pick the lock in a door */ struct monst *mtmp; if (u.utrap && u.utraptype == TT_PIT) { You_cant("reach over the edge of the pit."); return PICKLOCK_LEARNED_SOMETHING; } door = &levl[cc.x][cc.y]; mtmp = m_at(cc.x, cc.y); if (mtmp && canseemon(mtmp) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) { if (picktyp == CREDIT_CARD && (mtmp->isshk || mtmp->data == &mons[PM_ORACLE])) verbalize("No checks, no credit, no problem."); else pline("I don't think %s would appreciate that.", mon_nam(mtmp)); return PICKLOCK_LEARNED_SOMETHING; } else if (mtmp && is_door_mappear(mtmp)) { /* "The door actually was a !" */ stumble_onto_mimic(mtmp); /* mimic might keep the key (50% chance, 10% for PYEC) */ maybe_absorb_item(mtmp, pick, 50, 10); return PICKLOCK_LEARNED_SOMETHING; } if (!IS_DOOR(door->typ)) { if (is_drawbridge_wall(cc.x, cc.y) >= 0) You("%s no lock on the drawbridge.", Blind ? "feel" : "see"); else You("%s no door there.", Blind ? "feel" : "see"); return PICKLOCK_LEARNED_SOMETHING; } switch (door->doormask) { case D_NODOOR: pline("This doorway has no door."); return PICKLOCK_LEARNED_SOMETHING; case D_ISOPEN: You("cannot lock an open door."); return PICKLOCK_LEARNED_SOMETHING; case D_BROKEN: pline("This door is broken."); return PICKLOCK_LEARNED_SOMETHING; default: /* credit cards are only good for unlocking */ if (picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) { You_cant("lock a door with a credit card."); return PICKLOCK_LEARNED_SOMETHING; } Sprintf(qbuf, "%s it?", (door->doormask & D_LOCKED) ? "Unlock" : "Lock"); c = yn(qbuf); if (c == 'n') return 0; switch (picktyp) { case CREDIT_CARD: ch = 2 * ACURR(A_DEX) + 20 * Role_if(PM_ROGUE); break; case LOCK_PICK: ch = 3 * ACURR(A_DEX) + 30 * Role_if(PM_ROGUE); break; case SKELETON_KEY: ch = 70 + ACURR(A_DEX); break; default: ch = 0; } xlock.door = door; xlock.box = 0; } } context.move = 0; xlock.chance = ch; xlock.picktyp = picktyp; xlock.usedtime = 0; set_occupation(picklock, lock_action(), 0); return PICKLOCK_DID_SOMETHING; } /* try to force a chest with your weapon */ int doforce() { register struct obj *otmp; register int c, picktyp; char qbuf[QBUFSZ]; if (u.uswallow) { You_cant("force anything from inside here."); return 0; } if (!uwep /* proper type test */ || ((uwep->oclass == WEAPON_CLASS || is_weptool(uwep)) ? (objects[uwep->otyp].oc_skill < P_DAGGER || objects[uwep->otyp].oc_skill == P_FLAIL || objects[uwep->otyp].oc_skill > P_LANCE) : uwep->oclass != ROCK_CLASS)) { You_cant("force anything %s weapon.", !uwep ? "when not wielding a" : (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep)) ? "without a proper" : "with that"); return 0; } if (!can_reach_floor(TRUE)) { cant_reach_floor(u.ux, u.uy, FALSE, TRUE); return 0; } picktyp = is_blade(uwep) && !is_pick(uwep); if (xlock.usedtime && xlock.box && picktyp == xlock.picktyp) { You("resume your attempt to force the lock."); set_occupation(forcelock, "forcing the lock", 0); return 1; } /* A lock is made only for the honest man, the thief will break it. */ xlock.box = (struct obj *) 0; for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { if (otmp->obroken || !otmp->olocked) { There("is %s here, but its lock is already %s.", doname(otmp), otmp->obroken ? "broken" : "unlocked"); otmp->lknown = 1; continue; } (void) safe_qbuf(qbuf, "There is ", " here; force its lock?", otmp, doname, ansimpleoname, "a box"); otmp->lknown = 1; c = ynq(qbuf); if (c == 'q') return 0; if (c == 'n') continue; if (picktyp) You("force %s into a crack and pry.", yname(uwep)); else You("start bashing it with %s.", yname(uwep)); xlock.box = otmp; xlock.chance = objects[uwep->otyp].oc_wldam * 2; xlock.picktyp = picktyp; xlock.usedtime = 0; break; } if (xlock.box) set_occupation(forcelock, "forcing the lock", 0); else You("decide not to force the issue."); return 1; } boolean stumble_on_door_mimic(x, y) int x, y; { struct monst *mtmp; if ((mtmp = m_at(x, y)) && is_door_mappear(mtmp) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp); return TRUE; } return FALSE; } /* the 'O' command - try to open a door */ int doopen() { return doopen_indir(0, 0); } /* try to open a door in direction u.dx/u.dy */ int doopen_indir(x, y) int x, y; { coord cc; register struct rm *door; boolean portcullis; int res = 0; if (nohands(youmonst.data)) { You_cant("open anything -- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { You_cant("reach over the edge of the pit."); return 0; } if (x > 0 && y > 0) { cc.x = x; cc.y = y; } else if (!get_adjacent_loc((char *) 0, (char *) 0, u.ux, u.uy, &cc)) return 0; if ((cc.x == u.ux) && (cc.y == u.uy)) return 0; if (stumble_on_door_mimic(cc.x, cc.y)) return 1; /* when choosing a direction is impaired, use a turn regardless of whether a door is successfully targetted */ if (Confusion || Stunned) res = 1; door = &levl[cc.x][cc.y]; portcullis = (is_drawbridge_wall(cc.x, cc.y) >= 0); if (Blind) { int oldglyph = door->glyph; schar oldlastseentyp = lastseentyp[cc.x][cc.y]; feel_location(cc.x, cc.y); if (door->glyph != oldglyph || lastseentyp[cc.x][cc.y] != oldlastseentyp) res = 1; /* learned something */ } if (portcullis || !IS_DOOR(door->typ)) { /* closed portcullis or spot that opened bridge would span */ if (is_db_wall(cc.x, cc.y) || door->typ == DRAWBRIDGE_UP) There("is no obvious way to open the drawbridge."); else if (portcullis || door->typ == DRAWBRIDGE_DOWN) pline_The("drawbridge is already open."); else You("%s no door there.", Blind ? "feel" : "see"); return res; } if (!(door->doormask & D_CLOSED)) { const char *mesg; switch (door->doormask) { case D_BROKEN: mesg = " is broken"; break; case D_NODOOR: mesg = "way has no door"; break; case D_ISOPEN: mesg = " is already open"; break; default: mesg = " is locked"; break; } pline("This door%s.", mesg); return res; } if (verysmall(youmonst.data)) { pline("You're too small to pull the door open."); return res; } /* door is known to be CLOSED */ if (rnl(20) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) { pline_The("door opens."); if (door->doormask & D_TRAPPED) { b_trapped("door", FINGER); door->doormask = D_NODOOR; if (*in_rooms(cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L); } else door->doormask = D_ISOPEN; feel_newsym(cc.x, cc.y); /* the hero knows she opened it */ unblock_point(cc.x, cc.y); /* vision: new see through there */ } else { exercise(A_STR, TRUE); pline_The("door resists!"); } return 1; } STATIC_OVL boolean obstructed(x, y, quietly) register int x, y; boolean quietly; { register struct monst *mtmp = m_at(x, y); if (mtmp && mtmp->m_ap_type != M_AP_FURNITURE) { if (mtmp->m_ap_type == M_AP_OBJECT) goto objhere; if (!quietly) { if ((mtmp->mx != x) || (mtmp->my != y)) { /* worm tail */ pline("%s%s blocks the way!", !canspotmon(mtmp) ? Something : s_suffix(Monnam(mtmp)), !canspotmon(mtmp) ? "" : " tail"); } else { pline("%s blocks the way!", !canspotmon(mtmp) ? "Some creature" : Monnam(mtmp)); } } if (!canspotmon(mtmp)) map_invisible(x, y); return TRUE; } if (OBJ_AT(x, y)) { objhere: if (!quietly) pline("%s's in the way.", Something); return TRUE; } return FALSE; } /* the 'C' command - try to close a door */ int doclose() { register int x, y; register struct rm *door; boolean portcullis; int res = 0; if (nohands(youmonst.data)) { You_cant("close anything -- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { You_cant("reach over the edge of the pit."); return 0; } if (!getdir((char *) 0)) return 0; x = u.ux + u.dx; y = u.uy + u.dy; if ((x == u.ux) && (y == u.uy)) { You("are in the way!"); return 1; } if (!isok(x, y)) goto nodoor; if (stumble_on_door_mimic(x, y)) return 1; /* when choosing a direction is impaired, use a turn regardless of whether a door is successfully targetted */ if (Confusion || Stunned) res = 1; door = &levl[x][y]; portcullis = (is_drawbridge_wall(x, y) >= 0); if (Blind) { int oldglyph = door->glyph; schar oldlastseentyp = lastseentyp[x][y]; feel_location(x, y); if (door->glyph != oldglyph || lastseentyp[x][y] != oldlastseentyp) res = 1; /* learned something */ } if (portcullis || !IS_DOOR(door->typ)) { /* is_db_wall: closed portcullis */ if (is_db_wall(x, y) || door->typ == DRAWBRIDGE_UP) pline_The("drawbridge is already closed."); else if (portcullis || door->typ == DRAWBRIDGE_DOWN) There("is no obvious way to close the drawbridge."); else { nodoor: You("%s no door there.", Blind ? "feel" : "see"); } return res; } if (door->doormask == D_NODOOR) { pline("This doorway has no door."); return res; } else if (obstructed(x, y, FALSE)) { return res; } else if (door->doormask == D_BROKEN) { pline("This door is broken."); return res; } else if (door->doormask & (D_CLOSED | D_LOCKED)) { pline("This door is already closed."); return res; } if (door->doormask == D_ISOPEN) { if (verysmall(youmonst.data) && !u.usteed) { pline("You're too small to push the door closed."); return res; } if (u.usteed || rn2(25) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) { pline_The("door closes."); door->doormask = D_CLOSED; feel_newsym(x, y); /* the hero knows she closed it */ block_point(x, y); /* vision: no longer see there */ } else { exercise(A_STR, TRUE); pline_The("door resists!"); } } return 1; } /* box obj was hit with spell or wand effect otmp; returns true if something happened */ boolean boxlock(obj, otmp) struct obj *obj, *otmp; /* obj *is* a box */ { boolean res = 0; switch (otmp->otyp) { case WAN_LOCKING: case SPE_WIZARD_LOCK: if (!obj->olocked) { /* lock it; fix if broken */ pline("Klunk!"); obj->olocked = 1; obj->obroken = 0; if (Role_if(PM_WIZARD)) obj->lknown = 1; else obj->lknown = 0; res = 1; } /* else already closed and locked */ break; case WAN_OPENING: case SPE_KNOCK: if (obj->olocked) { /* unlock; couldn't be broken */ pline("Klick!"); obj->olocked = 0; res = 1; if (Role_if(PM_WIZARD)) obj->lknown = 1; else obj->lknown = 0; } else /* silently fix if broken */ obj->obroken = 0; break; case WAN_POLYMORPH: case SPE_POLYMORPH: /* maybe start unlocking chest, get interrupted, then zap it; we must avoid any attempt to resume unlocking it */ if (xlock.box == obj) reset_pick(); break; } return res; } /* Door/secret door was hit with spell or wand effect otmp; returns true if something happened */ boolean doorlock(otmp, x, y) struct obj *otmp; int x, y; { register struct rm *door = &levl[x][y]; boolean res = TRUE; int loudness = 0; const char *msg = (const char *) 0; const char *dustcloud = "A cloud of dust"; const char *quickly_dissipates = "quickly dissipates"; boolean mysterywand = (otmp->oclass == WAND_CLASS && !otmp->dknown); if (door->typ == SDOOR) { switch (otmp->otyp) { case WAN_OPENING: case SPE_KNOCK: case WAN_STRIKING: case SPE_FORCE_BOLT: door->typ = DOOR; door->doormask = D_CLOSED | (door->doormask & D_TRAPPED); newsym(x, y); if (cansee(x, y)) pline("A door appears in the wall!"); if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) return TRUE; break; /* striking: continue door handling below */ case WAN_LOCKING: case SPE_WIZARD_LOCK: default: return FALSE; } } switch (otmp->otyp) { case WAN_LOCKING: case SPE_WIZARD_LOCK: if (Is_rogue_level(&u.uz)) { boolean vis = cansee(x, y); /* Can't have real locking in Rogue, so just hide doorway */ if (vis) pline("%s springs up in the older, more primitive doorway.", dustcloud); else You_hear("a swoosh."); if (obstructed(x, y, mysterywand)) { if (vis) pline_The("cloud %s.", quickly_dissipates); return FALSE; } block_point(x, y); door->typ = SDOOR; if (vis) pline_The("doorway vanishes!"); newsym(x, y); return TRUE; } if (obstructed(x, y, mysterywand)) return FALSE; /* Don't allow doors to close over traps. This is for pits */ /* & trap doors, but is it ever OK for anything else? */ if (t_at(x, y)) { /* maketrap() clears doormask, so it should be NODOOR */ pline("%s springs up in the doorway, but %s.", dustcloud, quickly_dissipates); return FALSE; } switch (door->doormask & ~D_TRAPPED) { case D_CLOSED: msg = "The door locks!"; break; case D_ISOPEN: msg = "The door swings shut, and locks!"; break; case D_BROKEN: msg = "The broken door reassembles and locks!"; break; case D_NODOOR: msg = "A cloud of dust springs up and assembles itself into a door!"; break; default: res = FALSE; break; } block_point(x, y); door->doormask = D_LOCKED | (door->doormask & D_TRAPPED); newsym(x, y); break; case WAN_OPENING: case SPE_KNOCK: if (door->doormask & D_LOCKED) { msg = "The door unlocks!"; door->doormask = D_CLOSED | (door->doormask & D_TRAPPED); } else res = FALSE; break; case WAN_STRIKING: case SPE_FORCE_BOLT: if (door->doormask & (D_LOCKED | D_CLOSED)) { if (door->doormask & D_TRAPPED) { if (MON_AT(x, y)) (void) mb_trapped(m_at(x, y)); else if (flags.verbose) { if (cansee(x, y)) pline("KABOOM!! You see a door explode."); else You_hear("a distant explosion."); } door->doormask = D_NODOOR; unblock_point(x, y); newsym(x, y); loudness = 40; break; } door->doormask = D_BROKEN; if (flags.verbose) { if (cansee(x, y)) pline_The("door crashes open!"); else You_hear("a crashing sound."); } unblock_point(x, y); newsym(x, y); /* force vision recalc before printing more messages */ if (vision_full_recalc) vision_recalc(0); loudness = 20; } else res = FALSE; break; default: impossible("magic (%d) attempted on door.", otmp->otyp); break; } if (msg && cansee(x, y)) pline1(msg); if (loudness > 0) { /* door was destroyed */ wake_nearto(x, y, loudness); if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); } if (res && picking_at(x, y)) { /* maybe unseen monster zaps door you're unlocking */ stop_occupation(); reset_pick(); } return res; } STATIC_OVL void chest_shatter_msg(otmp) struct obj *otmp; { const char *disposition; const char *thing; long save_Blinded; if (otmp->oclass == POTION_CLASS) { You("%s %s shatter!", Blind ? "hear" : "see", an(bottlename())); if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(otmp); return; } /* We have functions for distant and singular names, but not one */ /* which does _both_... */ save_Blinded = Blinded; Blinded = 1; thing = singular(otmp, xname); Blinded = save_Blinded; switch (objects[otmp->otyp].oc_material) { case PAPER: disposition = "is torn to shreds"; break; case WAX: disposition = "is crushed"; break; case VEGGY: disposition = "is pulped"; break; case FLESH: disposition = "is mashed"; break; case GLASS: disposition = "shatters"; break; case WOOD: disposition = "splinters to fragments"; break; default: disposition = "is destroyed"; break; } pline("%s %s!", An(thing), disposition); } /*lock.c*/ nethack-3.6.0/src/mail.c0000664000076400007660000004310212610522241014005 0ustar paxedpaxed/* NetHack 3.6 mail.c $NHDT-Date: 1436754892 2015/07/13 02:34:52 $ $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef MAIL #include "mail.h" /* * Notify user when new mail has arrived. Idea by Merlyn Leroy. * * The mail daemon can move with less than usual restraint. It can: * - move diagonally from a door * - use secret and closed doors * - run through a monster ("Gangway!", etc.) * - run over pools & traps * * Possible extensions: * - Open the file MAIL and do fstat instead of stat for efficiency. * (But sh uses stat, so this cannot be too bad.) * - Examine the mail and produce a scroll of mail named "From somebody". * - Invoke MAILREADER in such a way that only this single letter is *read. * - Do something to the text when the scroll is enchanted or cancelled. * - Make the daemon always appear at a stairwell, and have it find a * path to the hero. * * Note by Olaf Seibert: On the Amiga, we usually don't get mail. So we go * through most of the effects at 'random' moments. * Note by Paul Winner: The MSDOS port also 'fakes' the mail daemon at * random intervals. */ STATIC_DCL boolean FDECL(md_start, (coord *)); STATIC_DCL boolean FDECL(md_stop, (coord *, coord *)); STATIC_DCL boolean FDECL(md_rush, (struct monst *, int, int)); STATIC_DCL void FDECL(newmail, (struct mail_info *)); extern char *viz_rmin, *viz_rmax; /* line-of-sight limits (vision.c) */ #if !defined(UNIX) && !defined(VMS) int mustgetmail = -1; #endif #ifdef UNIX #include #include /* DON'T trust all Unices to declare getpwuid() in */ #if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX) #if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__)) /* DO trust all SVR4 to typedef uid_t in (probably to a long) */ #if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX) extern struct passwd *FDECL(getpwuid, (uid_t)); #else extern struct passwd *FDECL(getpwuid, (int)); #endif #endif #endif static struct stat omstat, nmstat; static char *mailbox = (char *) 0; static long laststattime; #if !defined(MAILPATH) && defined(AMS) /* Just a placeholder for AMS */ #define MAILPATH "/dev/null" #endif #if !defined(MAILPATH) && (defined(LINUX) || defined(__osf__)) #define MAILPATH "/var/spool/mail/" #endif #if !defined(MAILPATH) && defined(__FreeBSD__) #define MAILPATH "/var/mail/" #endif #if !defined(MAILPATH) && (defined(BSD) || defined(ULTRIX)) #define MAILPATH "/usr/spool/mail/" #endif #if !defined(MAILPATH) && (defined(SYSV) || defined(HPUX)) #define MAILPATH "/usr/mail/" #endif void getmailstatus() { if (!mailbox && !(mailbox = nh_getenv("MAIL"))) { #ifdef MAILPATH #ifdef AMS struct passwd ppasswd; (void) memcpy(&ppasswd, getpwuid(getuid()), sizeof(struct passwd)); if (ppasswd.pw_dir) { mailbox = (char *) alloc((unsigned) strlen(ppasswd.pw_dir) + sizeof(AMS_MAILBOX)); Strcpy(mailbox, ppasswd.pw_dir); Strcat(mailbox, AMS_MAILBOX); } else return; #else const char *pw_name = getpwuid(getuid())->pw_name; mailbox = (char *) alloc(sizeof(MAILPATH) + strlen(pw_name)); Strcpy(mailbox, MAILPATH); Strcat(mailbox, pw_name); #endif /* AMS */ #else return; #endif } if (stat(mailbox, &omstat)) { #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\".", mailbox); mailbox = 0; #else omstat.st_mtime = 0; #endif } } #endif /* UNIX */ /* * Pick coordinates for a starting position for the mail daemon. Called * from newmail() and newphone(). */ STATIC_OVL boolean md_start(startp) coord *startp; { coord testcc; /* scratch coordinates */ int row; /* current row we are checking */ int lax; /* if TRUE, pick a position in sight. */ int dd; /* distance to current point */ int max_distance; /* max distance found so far */ /* * If blind and not telepathic, then it doesn't matter what we pick --- * the hero is not going to see it anyway. So pick a nearby position. */ if (Blind && !Blind_telepat) { if (!enexto(startp, u.ux, u.uy, (struct permonst *) 0)) return FALSE; /* no good positions */ return TRUE; } /* * Arrive at an up or down stairwell if it is in line of sight from the * hero. */ if (couldsee(upstair.sx, upstair.sy)) { startp->x = upstair.sx; startp->y = upstair.sy; return TRUE; } if (couldsee(dnstair.sx, dnstair.sy)) { startp->x = dnstair.sx; startp->y = dnstair.sy; return TRUE; } /* * Try to pick a location out of sight next to the farthest position away * from the hero. If this fails, try again, just picking the farthest * position that could be seen. What we really ought to be doing is * finding a path from a stairwell... * * The arrays viz_rmin[] and viz_rmax[] are set even when blind. These * are the LOS limits for each row. */ lax = 0; /* be picky */ max_distance = -1; retry: for (row = 0; row < ROWNO; row++) { if (viz_rmin[row] < viz_rmax[row]) { /* There are valid positions on this row. */ dd = distu(viz_rmin[row], row); if (dd > max_distance) { if (lax) { max_distance = dd; startp->y = row; startp->x = viz_rmin[row]; } else if (enexto(&testcc, (xchar) viz_rmin[row], row, (struct permonst *) 0) && !cansee(testcc.x, testcc.y) && couldsee(testcc.x, testcc.y)) { max_distance = dd; *startp = testcc; } } dd = distu(viz_rmax[row], row); if (dd > max_distance) { if (lax) { max_distance = dd; startp->y = row; startp->x = viz_rmax[row]; } else if (enexto(&testcc, (xchar) viz_rmax[row], row, (struct permonst *) 0) && !cansee(testcc.x, testcc.y) && couldsee(testcc.x, testcc.y)) { max_distance = dd; *startp = testcc; } } } } if (max_distance < 0) { if (!lax) { lax = 1; /* just find a position */ goto retry; } return FALSE; } return TRUE; } /* * Try to choose a stopping point as near as possible to the starting * position while still adjacent to the hero. If all else fails, try * enexto(). Use enexto() as a last resort because enexto() chooses * its point randomly, which is not what we want. */ STATIC_OVL boolean md_stop(stopp, startp) coord *stopp; /* stopping position (we fill it in) */ coord *startp; /* starting position (read only) */ { int x, y, distance, min_distance = -1; for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; if (accessible(x, y) && !MON_AT(x, y)) { distance = dist2(x, y, startp->x, startp->y); if (min_distance < 0 || distance < min_distance || (distance == min_distance && rn2(2))) { stopp->x = x; stopp->y = y; min_distance = distance; } } } /* If we didn't find a good spot, try enexto(). */ if (min_distance < 0 && !enexto(stopp, u.ux, u.uy, &mons[PM_MAIL_DAEMON])) return FALSE; return TRUE; } /* Let the mail daemon have a larger vocabulary. */ static NEARDATA const char *mail_text[] = { "Gangway!", "Look out!", "Pardon me!" }; #define md_exclamations() (mail_text[rn2(3)]) /* * Make the mail daemon run through the dungeon. The daemon will run over * any monsters that are in its path, but will replace them later. Return * FALSE if the md gets stuck in a position where there is a monster. Return * TRUE otherwise. */ STATIC_OVL boolean md_rush(md, tx, ty) struct monst *md; register int tx, ty; /* destination of mail daemon */ { struct monst *mon; /* displaced monster */ register int dx, dy; /* direction counters */ int fx = md->mx, fy = md->my; /* current location */ int nfx = fx, nfy = fy, /* new location */ d1, d2; /* shortest distances */ /* * It is possible that the monster at (fx,fy) is not the md when: * the md rushed the hero and failed, and is now starting back. */ if (m_at(fx, fy) == md) { remove_monster(fx, fy); /* pick up from orig position */ newsym(fx, fy); } /* * At the beginning and exit of this loop, md is not placed in the * dungeon. */ while (1) { /* Find a good location next to (fx,fy) closest to (tx,ty). */ d1 = dist2(fx, fy, tx, ty); for (dx = -1; dx <= 1; dx++) for (dy = -1; dy <= 1; dy++) if ((dx || dy) && isok(fx + dx, fy + dy) && !IS_STWALL(levl[fx + dx][fy + dy].typ)) { d2 = dist2(fx + dx, fy + dy, tx, ty); if (d2 < d1) { d1 = d2; nfx = fx + dx; nfy = fy + dy; } } /* Break if the md couldn't find a new position. */ if (nfx == fx && nfy == fy) break; fx = nfx; /* this is our new position */ fy = nfy; /* Break if the md reaches its destination. */ if (fx == tx && fy == ty) break; if ((mon = m_at(fx, fy)) != 0) /* save monster at this position */ verbalize1(md_exclamations()); else if (fx == u.ux && fy == u.uy) verbalize("Excuse me."); place_monster(md, fx, fy); /* put md down */ newsym(fx, fy); /* see it */ flush_screen(0); /* make sure md shows up */ delay_output(); /* wait a little bit */ /* Remove md from the dungeon. Restore original mon, if necessary. */ if (mon) { if ((mon->mx != fx) || (mon->my != fy)) place_worm_seg(mon, fx, fy); else place_monster(mon, fx, fy); } else remove_monster(fx, fy); newsym(fx, fy); } /* * Check for a monster at our stopping position (this is possible, but * very unlikely). If one exists, then have the md leave in disgust. */ if ((mon = m_at(fx, fy)) != 0) { place_monster(md, fx, fy); /* display md with text below */ newsym(fx, fy); verbalize("This place's too crowded. I'm outta here."); if ((mon->mx != fx) || (mon->my != fy)) /* put mon back */ place_worm_seg(mon, fx, fy); else place_monster(mon, fx, fy); newsym(fx, fy); return FALSE; } place_monster(md, fx, fy); /* place at final spot */ newsym(fx, fy); flush_screen(0); delay_output(); /* wait a little bit */ return TRUE; } /* Deliver a scroll of mail. */ /*ARGSUSED*/ STATIC_OVL void newmail(info) struct mail_info *info; { struct monst *md; coord start, stop; boolean message_seen = FALSE; /* Try to find good starting and stopping places. */ if (!md_start(&start) || !md_stop(&stop, &start)) goto give_up; /* Make the daemon. Have it rush towards the hero. */ if (!(md = makemon(&mons[PM_MAIL_DAEMON], start.x, start.y, NO_MM_FLAGS))) goto give_up; if (!md_rush(md, stop.x, stop.y)) goto go_back; message_seen = TRUE; verbalize("%s, %s! %s.", Hello(md), plname, info->display_txt); if (info->message_typ) { struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE); if (info->object_nam) obj = oname(obj, info->object_nam); if (info->response_cmd) new_omailcmd(obj, info->response_cmd); if (distu(md->mx, md->my) > 2) verbalize("Catch!"); display_nhwindow(WIN_MESSAGE, FALSE); obj = hold_another_object(obj, "Oops!", (const char *) 0, (const char *) 0); } /* zip back to starting location */ go_back: (void) md_rush(md, start.x, start.y); mongone(md); /* deliver some classes of messages even if no daemon ever shows up */ give_up: if (!message_seen && info->message_typ == MSG_OTHER) pline("Hark! \"%s.\"", info->display_txt); } #if !defined(UNIX) && !defined(VMS) void ckmailstatus() { if (u.uswallow || !flags.biff) return; if (mustgetmail < 0) { #if defined(AMIGA) || defined(MSDOS) || defined(TOS) mustgetmail = (moves < 2000) ? (100 + rn2(2000)) : (2000 + rn2(3000)); #endif return; } if (--mustgetmail <= 0) { static struct mail_info deliver = { MSG_MAIL, "I have some mail for you", 0, 0 }; newmail(&deliver); mustgetmail = -1; } } /*ARGSUSED*/ void readmail(otmp) struct obj *otmp; { static char *junk[] = { NULL, /* placeholder for "Report bugs to .", */ "Please disregard previous letter.", "Welcome to NetHack.", #ifdef AMIGA "Only Amiga makes it possible.", "CATS have all the answers.", #endif "This mail complies with the Yendorian Anti-Spam Act (YASA)", "Please find enclosed a small token to represent your Owlbear", "**FR33 P0T10N 0F FULL H34L1NG**", "Please return to sender (Asmodeus)", "Buy a potion of gain level for only $19.99! Guaranteed to be blessed!", "Invitation: Visit the NetHack web site at http://www.nethack.org!" }; /* XXX replace with more general substitution code and add local * contact message. Also use DEVTEAM_URL */ if (junk[0] == NULL) { #define BUGS_FORMAT "Report bugs to <%s>." /* +2 from '%s' suffices as substitute for usual +1 for terminator */ junk[0] = (char *) alloc(strlen(BUGS_FORMAT) + strlen(DEVTEAM_EMAIL)); Sprintf(junk[0], BUGS_FORMAT, DEVTEAM_EMAIL); #undef BUGS_FORMAT } if (Blind) { pline("Unfortunately you cannot see what it says."); } else pline("It reads: \"%s\"", junk[rn2(SIZE(junk))]); } #endif /* !UNIX && !VMS */ #ifdef UNIX void ckmailstatus() { if (!mailbox || u.uswallow || !flags.biff #ifdef MAILCKFREQ || moves < laststattime + MAILCKFREQ #endif ) return; laststattime = moves; if (stat(mailbox, &nmstat)) { #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox); mailbox = 0; #else nmstat.st_mtime = 0; #endif } else if (nmstat.st_mtime > omstat.st_mtime) { if (nmstat.st_size) { static struct mail_info deliver = { #ifndef NO_MAILREADER MSG_MAIL, "I have some mail for you", #else /* suppress creation and delivery of scroll of mail */ MSG_OTHER, "You have some mail in the outside world", #endif 0, 0 }; newmail(&deliver); } getmailstatus(); /* might be too late ... */ } } /*ARGSUSED*/ void readmail(otmp) struct obj *otmp; { #ifdef DEF_MAILREADER /* This implies that UNIX is defined */ register const char *mr = 0; display_nhwindow(WIN_MESSAGE, FALSE); if (!(mr = nh_getenv("MAILREADER"))) mr = DEF_MAILREADER; if (child(1)) { (void) execl(mr, mr, (char *) 0); terminate(EXIT_FAILURE); } #else #ifndef AMS /* AMS mailboxes are directories */ display_file(mailbox, TRUE); #endif /* AMS */ #endif /* DEF_MAILREADER */ /* get new stat; not entirely correct: there is a small time window where we do not see new mail */ getmailstatus(); } #endif /* UNIX */ #ifdef VMS extern NDECL(struct mail_info *parse_next_broadcast); volatile int broadcasts = 0; void ckmailstatus() { struct mail_info *brdcst; if (u.uswallow || !flags.biff) return; while (broadcasts > 0) { /* process all trapped broadcasts [until] */ broadcasts--; if ((brdcst = parse_next_broadcast()) != 0) { newmail(brdcst); break; /* only handle one real message at a time */ } } } void readmail(otmp) struct obj *otmp; { #ifdef SHELL /* can't access mail reader without spawning subprocess */ const char *txt, *cmd; char *p, buf[BUFSZ], qbuf[BUFSZ]; int len; /* there should be a command in OMAILCMD */ if (has_oname(otmp)) txt = ONAME(otmp); else txt = ""; len = strlen(txt); if (has_omailcmd(otmp)) cmd = OMAILCMD(otmp); if (!cmd || !*cmd) cmd = "SPAWN"; Sprintf(qbuf, "System command (%s)", cmd); getlin(qbuf, buf); if (*buf != '\033') { for (p = eos(buf); p > buf; *p = '\0') if (*--p != ' ') break; /* strip trailing spaces */ if (*buf) cmd = buf; /* use user entered command */ if (!strcmpi(cmd, "SPAWN") || !strcmp(cmd, "!")) cmd = (char *) 0; /* interactive escape */ vms_doshell(cmd, TRUE); (void) sleep(1); } #endif /* SHELL */ } #endif /* VMS */ #endif /* MAIL */ /*mail.c*/ nethack-3.6.0/src/makemon.c0000664000076400007660000021354312631241231014522 0ustar paxedpaxed/* NetHack 3.6 makemon.c $NHDT-Date: 1449269917 2015/12/04 22:58:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.105 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include STATIC_VAR NEARDATA struct monst zeromonst; /* this assumes that a human quest leader or nemesis is an archetype of the corresponding role; that isn't so for some roles (tourist for instance) but is for the priests and monks we use it for... */ #define quest_mon_represents_role(mptr, role_pm) \ (mptr->mlet == S_HUMAN && Role_if(role_pm) \ && (mptr->msound == MS_LEADER || mptr->msound == MS_NEMESIS)) STATIC_DCL boolean FDECL(uncommon, (int)); STATIC_DCL int FDECL(align_shift, (struct permonst *)); STATIC_DCL boolean FDECL(mk_gen_ok, (int, int, int)); STATIC_DCL boolean FDECL(wrong_elem_type, (struct permonst *)); STATIC_DCL void FDECL(m_initgrp, (struct monst *, int, int, int)); STATIC_DCL void FDECL(m_initthrow, (struct monst *, int, int)); STATIC_DCL void FDECL(m_initweap, (struct monst *)); STATIC_DCL void FDECL(m_initinv, (struct monst *)); STATIC_DCL boolean FDECL(makemon_rnd_goodpos, (struct monst *, unsigned, coord *)); extern const int monstr[]; #define m_initsgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 3) #define m_initlgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 10) #define toostrong(monindx, lev) (monstr[monindx] > lev) #define tooweak(monindx, lev) (monstr[monindx] < lev) boolean is_home_elemental(ptr) struct permonst *ptr; { if (ptr->mlet == S_ELEMENTAL) switch (monsndx(ptr)) { case PM_AIR_ELEMENTAL: return Is_airlevel(&u.uz); case PM_FIRE_ELEMENTAL: return Is_firelevel(&u.uz); case PM_EARTH_ELEMENTAL: return Is_earthlevel(&u.uz); case PM_WATER_ELEMENTAL: return Is_waterlevel(&u.uz); } return FALSE; } /* * Return true if the given monster cannot exist on this elemental level. */ STATIC_OVL boolean wrong_elem_type(ptr) struct permonst *ptr; { if (ptr->mlet == S_ELEMENTAL) { return (boolean) !is_home_elemental(ptr); } else if (Is_earthlevel(&u.uz)) { /* no restrictions? */ } else if (Is_waterlevel(&u.uz)) { /* just monsters that can swim */ if (!is_swimmer(ptr)) return TRUE; } else if (Is_firelevel(&u.uz)) { if (!pm_resistance(ptr, MR_FIRE)) return TRUE; } else if (Is_airlevel(&u.uz)) { if (!(is_flyer(ptr) && ptr->mlet != S_TRAPPER) && !is_floater(ptr) && !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr)) return TRUE; } return FALSE; } /* make a group just like mtmp */ STATIC_OVL void m_initgrp(mtmp, x, y, n) register struct monst *mtmp; register int x, y, n; { coord mm; register int cnt = rnd(n); struct monst *mon; #if defined(__GNUC__) && (defined(HPUX) || defined(DGUX)) /* There is an unresolved problem with several people finding that * the game hangs eating CPU; if interrupted and restored, the level * will be filled with monsters. Of those reports giving system type, * there were two DG/UX and two HP-UX, all using gcc as the compiler. * hcroft@hpopb1.cern.ch, using gcc 2.6.3 on HP-UX, says that the * problem went away for him and another reporter-to-newsgroup * after adding this debugging code. This has almost got to be a * compiler bug, but until somebody tracks it down and gets it fixed, * might as well go with the "but it went away when I tried to find * it" code. */ int cnttmp, cntdiv; cnttmp = cnt; debugpline4("init group call <%d,%d>, n=%d, cnt=%d.", x, y, n, cnt); cntdiv = ((u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1); #endif /* Tuning: cut down on swarming at low character levels [mrs] */ cnt /= (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1; #if defined(__GNUC__) && (defined(HPUX) || defined(DGUX)) if (cnt != (cnttmp / cntdiv)) { pline("cnt=%d using %d, cnttmp=%d, cntdiv=%d", cnt, (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1, cnttmp, cntdiv); } #endif if (!cnt) cnt++; #if defined(__GNUC__) && (defined(HPUX) || defined(DGUX)) if (cnt < 0) cnt = 1; if (cnt > 10) cnt = 10; #endif mm.x = x; mm.y = y; while (cnt--) { if (peace_minded(mtmp->data)) continue; /* Don't create groups of peaceful monsters since they'll get * in our way. If the monster has a percentage chance so some * are peaceful and some are not, the result will just be a * smaller group. */ if (enexto(&mm, mm.x, mm.y, mtmp->data)) { mon = makemon(mtmp->data, mm.x, mm.y, NO_MM_FLAGS); if (mon) { mon->mpeaceful = FALSE; mon->mavenge = 0; set_malign(mon); /* Undo the second peace_minded() check in makemon(); if the * monster turned out to be peaceful the first time we * didn't create it at all; we don't want a second check. */ } } } } STATIC_OVL void m_initthrow(mtmp, otyp, oquan) struct monst *mtmp; int otyp, oquan; { register struct obj *otmp; otmp = mksobj(otyp, TRUE, FALSE); otmp->quan = (long) rn1(oquan, 3); otmp->owt = weight(otmp); if (otyp == ORCISH_ARROW) otmp->opoisoned = TRUE; (void) mpickobj(mtmp, otmp); } STATIC_OVL void m_initweap(mtmp) register struct monst *mtmp; { register struct permonst *ptr = mtmp->data; register int mm = monsndx(ptr); struct obj *otmp; int bias, spe2, w1, w2; if (Is_rogue_level(&u.uz)) return; /* * First a few special cases: * giants get a boulder to throw sometimes * ettins get clubs * kobolds get darts to throw * centaurs get some sort of bow & arrows or bolts * soldiers get all sorts of things * kops get clubs & cream pies. */ switch (ptr->mlet) { case S_GIANT: if (rn2(2)) (void) mongets(mtmp, (mm != PM_ETTIN) ? BOULDER : CLUB); break; case S_HUMAN: if (is_mercenary(ptr)) { w1 = w2 = 0; switch (mm) { case PM_WATCHMAN: case PM_SOLDIER: if (!rn2(3)) { w1 = rn1(BEC_DE_CORBIN - PARTISAN + 1, PARTISAN); w2 = rn2(2) ? DAGGER : KNIFE; } else w1 = rn2(2) ? SPEAR : SHORT_SWORD; break; case PM_SERGEANT: w1 = rn2(2) ? FLAIL : MACE; break; case PM_LIEUTENANT: w1 = rn2(2) ? BROADSWORD : LONG_SWORD; break; case PM_CAPTAIN: case PM_WATCH_CAPTAIN: w1 = rn2(2) ? LONG_SWORD : SILVER_SABER; break; default: if (!rn2(4)) w1 = DAGGER; if (!rn2(7)) w2 = SPEAR; break; } if (w1) (void) mongets(mtmp, w1); if (!w2 && w1 != DAGGER && !rn2(4)) w2 = KNIFE; if (w2) (void) mongets(mtmp, w2); } else if (is_elf(ptr)) { if (rn2(2)) (void) mongets(mtmp, rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK); if (rn2(2)) (void) mongets(mtmp, ELVEN_LEATHER_HELM); else if (!rn2(4)) (void) mongets(mtmp, ELVEN_BOOTS); if (rn2(2)) (void) mongets(mtmp, ELVEN_DAGGER); switch (rn2(3)) { case 0: if (!rn2(4)) (void) mongets(mtmp, ELVEN_SHIELD); if (rn2(3)) (void) mongets(mtmp, ELVEN_SHORT_SWORD); (void) mongets(mtmp, ELVEN_BOW); m_initthrow(mtmp, ELVEN_ARROW, 12); break; case 1: (void) mongets(mtmp, ELVEN_BROADSWORD); if (rn2(2)) (void) mongets(mtmp, ELVEN_SHIELD); break; case 2: if (rn2(2)) { (void) mongets(mtmp, ELVEN_SPEAR); (void) mongets(mtmp, ELVEN_SHIELD); } break; } if (mm == PM_ELVENKING) { if (rn2(3) || (in_mklev && Is_earthlevel(&u.uz))) (void) mongets(mtmp, PICK_AXE); if (!rn2(50)) (void) mongets(mtmp, CRYSTAL_BALL); } } else if (ptr->msound == MS_PRIEST || quest_mon_represents_role(ptr, PM_PRIEST)) { otmp = mksobj(MACE, FALSE, FALSE); if (otmp) { otmp->spe = rnd(3); if (!rn2(2)) curse(otmp); (void) mpickobj(mtmp, otmp); } } else if (mm == PM_NINJA) { /* extra quest villains */ (void) mongets(mtmp, rn2(4) ? SHURIKEN : DART); (void) mongets(mtmp, rn2(4) ? SHORT_SWORD : AXE); } break; case S_ANGEL: if (humanoid(ptr)) { /* create minion stuff; can't use mongets */ otmp = mksobj(LONG_SWORD, FALSE, FALSE); /* maybe make it special */ if (!rn2(20) || is_lord(ptr)) otmp = oname(otmp, artiname(rn2(2) ? ART_DEMONBANE : ART_SUNSWORD)); bless(otmp); otmp->oerodeproof = TRUE; spe2 = rn2(4); otmp->spe = max(otmp->spe, spe2); (void) mpickobj(mtmp, otmp); otmp = mksobj(!rn2(4) || is_lord(ptr) ? SHIELD_OF_REFLECTION : LARGE_SHIELD, FALSE, FALSE); otmp->cursed = FALSE; otmp->oerodeproof = TRUE; otmp->spe = 0; (void) mpickobj(mtmp, otmp); } break; case S_HUMANOID: if (mm == PM_HOBBIT) { switch (rn2(3)) { case 0: (void) mongets(mtmp, DAGGER); break; case 1: (void) mongets(mtmp, ELVEN_DAGGER); break; case 2: (void) mongets(mtmp, SLING); break; } if (!rn2(10)) (void) mongets(mtmp, ELVEN_MITHRIL_COAT); if (!rn2(10)) (void) mongets(mtmp, DWARVISH_CLOAK); } else if (is_dwarf(ptr)) { if (rn2(7)) (void) mongets(mtmp, DWARVISH_CLOAK); if (rn2(7)) (void) mongets(mtmp, IRON_SHOES); if (!rn2(4)) { (void) mongets(mtmp, DWARVISH_SHORT_SWORD); /* note: you can't use a mattock with a shield */ if (rn2(2)) (void) mongets(mtmp, DWARVISH_MATTOCK); else { (void) mongets(mtmp, rn2(2) ? AXE : DWARVISH_SPEAR); (void) mongets(mtmp, DWARVISH_ROUNDSHIELD); } (void) mongets(mtmp, DWARVISH_IRON_HELM); if (!rn2(3)) (void) mongets(mtmp, DWARVISH_MITHRIL_COAT); } else { (void) mongets(mtmp, !rn2(3) ? PICK_AXE : DAGGER); } } break; case S_KOP: /* create Keystone Kops with cream pies to throw. As suggested by KAA. [MRS] */ if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2); if (!rn2(3)) (void) mongets(mtmp, (rn2(2)) ? CLUB : RUBBER_HOSE); break; case S_ORC: if (rn2(2)) (void) mongets(mtmp, ORCISH_HELM); switch ((mm != PM_ORC_CAPTAIN) ? mm : rn2(2) ? PM_MORDOR_ORC : PM_URUK_HAI) { case PM_MORDOR_ORC: if (!rn2(3)) (void) mongets(mtmp, SCIMITAR); if (!rn2(3)) (void) mongets(mtmp, ORCISH_SHIELD); if (!rn2(3)) (void) mongets(mtmp, KNIFE); if (!rn2(3)) (void) mongets(mtmp, ORCISH_CHAIN_MAIL); break; case PM_URUK_HAI: if (!rn2(3)) (void) mongets(mtmp, ORCISH_CLOAK); if (!rn2(3)) (void) mongets(mtmp, ORCISH_SHORT_SWORD); if (!rn2(3)) (void) mongets(mtmp, IRON_SHOES); if (!rn2(3)) { (void) mongets(mtmp, ORCISH_BOW); m_initthrow(mtmp, ORCISH_ARROW, 12); } if (!rn2(3)) (void) mongets(mtmp, URUK_HAI_SHIELD); break; default: if (mm != PM_ORC_SHAMAN && rn2(2)) (void) mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0) ? ORCISH_DAGGER : SCIMITAR); } break; case S_OGRE: if (!rn2(mm == PM_OGRE_KING ? 3 : mm == PM_OGRE_LORD ? 6 : 12)) (void) mongets(mtmp, BATTLE_AXE); else (void) mongets(mtmp, CLUB); break; case S_TROLL: if (!rn2(2)) switch (rn2(4)) { case 0: (void) mongets(mtmp, RANSEUR); break; case 1: (void) mongets(mtmp, PARTISAN); break; case 2: (void) mongets(mtmp, GLAIVE); break; case 3: (void) mongets(mtmp, SPETUM); break; } break; case S_KOBOLD: if (!rn2(4)) m_initthrow(mtmp, DART, 12); break; case S_CENTAUR: if (rn2(2)) { if (ptr == &mons[PM_FOREST_CENTAUR]) { (void) mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); } else { (void) mongets(mtmp, CROSSBOW); m_initthrow(mtmp, CROSSBOW_BOLT, 12); } } break; case S_WRAITH: (void) mongets(mtmp, KNIFE); (void) mongets(mtmp, LONG_SWORD); break; case S_ZOMBIE: if (!rn2(4)) (void) mongets(mtmp, LEATHER_ARMOR); if (!rn2(4)) (void) mongets(mtmp, (rn2(3) ? KNIFE : SHORT_SWORD)); break; case S_LIZARD: if (mm == PM_SALAMANDER) (void) mongets(mtmp, (rn2(7) ? SPEAR : rn2(3) ? TRIDENT : STILETTO)); break; case S_DEMON: switch (mm) { case PM_BALROG: (void) mongets(mtmp, BULLWHIP); (void) mongets(mtmp, BROADSWORD); break; case PM_ORCUS: (void) mongets(mtmp, WAN_DEATH); /* the Wand of Orcus */ break; case PM_HORNED_DEVIL: (void) mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP); break; case PM_DISPATER: (void) mongets(mtmp, WAN_STRIKING); break; case PM_YEENOGHU: (void) mongets(mtmp, FLAIL); break; } /* prevent djinn and mail daemons from leaving objects when * they vanish */ if (!is_demon(ptr)) break; /*FALLTHRU*/ default: /* * Now the general case, some chance of getting some type * of weapon for "normal" monsters. Certain special types * of monsters will get a bonus chance or different selections. */ bias = is_lord(ptr) + is_prince(ptr) * 2 + extra_nasty(ptr); switch (rnd(14 - (2 * bias))) { case 1: if (strongmonst(ptr)) (void) mongets(mtmp, BATTLE_AXE); else m_initthrow(mtmp, DART, 12); break; case 2: if (strongmonst(ptr)) (void) mongets(mtmp, TWO_HANDED_SWORD); else { (void) mongets(mtmp, CROSSBOW); m_initthrow(mtmp, CROSSBOW_BOLT, 12); } break; case 3: (void) mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); break; case 4: if (strongmonst(ptr)) (void) mongets(mtmp, LONG_SWORD); else m_initthrow(mtmp, DAGGER, 3); break; case 5: if (strongmonst(ptr)) (void) mongets(mtmp, LUCERN_HAMMER); else (void) mongets(mtmp, AKLYS); break; default: break; } break; } if ((int) mtmp->m_lev > rn2(75)) (void) mongets(mtmp, rnd_offensive_item(mtmp)); } /* * Makes up money for monster's inventory. * This will change with silver & copper coins */ void mkmonmoney(mtmp, amount) struct monst *mtmp; long amount; { struct obj *gold = mksobj(GOLD_PIECE, FALSE, FALSE); gold->quan = amount; add_to_minv(mtmp, gold); } STATIC_OVL void m_initinv(mtmp) register struct monst *mtmp; { register int cnt; register struct obj *otmp; register struct permonst *ptr = mtmp->data; if (Is_rogue_level(&u.uz)) return; /* * Soldiers get armour & rations - armour approximates their ac. * Nymphs may get mirror or potion of object detection. */ switch (ptr->mlet) { case S_HUMAN: if (is_mercenary(ptr)) { register int mac; switch (monsndx(ptr)) { case PM_GUARD: mac = -1; break; case PM_SOLDIER: mac = 3; break; case PM_SERGEANT: mac = 0; break; case PM_LIEUTENANT: mac = -2; break; case PM_CAPTAIN: mac = -3; break; case PM_WATCHMAN: mac = 3; break; case PM_WATCH_CAPTAIN: mac = -2; break; default: impossible("odd mercenary %d?", monsndx(ptr)); mac = 0; break; } if (mac < -1 && rn2(5)) mac += 7 + mongets(mtmp, (rn2(5)) ? PLATE_MAIL : CRYSTAL_PLATE_MAIL); else if (mac < 3 && rn2(5)) mac += 6 + mongets(mtmp, (rn2(3)) ? SPLINT_MAIL : BANDED_MAIL); else if (rn2(5)) mac += 3 + mongets(mtmp, (rn2(3)) ? RING_MAIL : STUDDED_LEATHER_ARMOR); else mac += 2 + mongets(mtmp, LEATHER_ARMOR); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, HELMET); else if (mac < 10 && rn2(2)) mac += 1 + mongets(mtmp, DENTED_POT); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, SMALL_SHIELD); else if (mac < 10 && rn2(2)) mac += 2 + mongets(mtmp, LARGE_SHIELD); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, LOW_BOOTS); else if (mac < 10 && rn2(2)) mac += 2 + mongets(mtmp, HIGH_BOOTS); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, LEATHER_GLOVES); else if (mac < 10 && rn2(2)) mac += 1 + mongets(mtmp, LEATHER_CLOAK); if (ptr != &mons[PM_GUARD] && ptr != &mons[PM_WATCHMAN] && ptr != &mons[PM_WATCH_CAPTAIN]) { if (!rn2(3)) (void) mongets(mtmp, K_RATION); if (!rn2(2)) (void) mongets(mtmp, C_RATION); if (ptr != &mons[PM_SOLDIER] && !rn2(3)) (void) mongets(mtmp, BUGLE); } else if (ptr == &mons[PM_WATCHMAN] && rn2(3)) (void) mongets(mtmp, TIN_WHISTLE); } else if (ptr == &mons[PM_SHOPKEEPER]) { (void) mongets(mtmp, SKELETON_KEY); switch (rn2(4)) { /* MAJOR fall through ... */ case 0: (void) mongets(mtmp, WAN_MAGIC_MISSILE); case 1: (void) mongets(mtmp, POT_EXTRA_HEALING); case 2: (void) mongets(mtmp, POT_HEALING); case 3: (void) mongets(mtmp, WAN_STRIKING); } } else if (ptr->msound == MS_PRIEST || quest_mon_represents_role(ptr, PM_PRIEST)) { (void) mongets(mtmp, rn2(7) ? ROBE : rn2(3) ? CLOAK_OF_PROTECTION : CLOAK_OF_MAGIC_RESISTANCE); (void) mongets(mtmp, SMALL_SHIELD); mkmonmoney(mtmp, (long) rn1(10, 20)); } else if (quest_mon_represents_role(ptr, PM_MONK)) { (void) mongets(mtmp, rn2(11) ? ROBE : CLOAK_OF_MAGIC_RESISTANCE); } break; case S_NYMPH: if (!rn2(2)) (void) mongets(mtmp, MIRROR); if (!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION); break; case S_GIANT: if (ptr == &mons[PM_MINOTAUR]) { if (!rn2(3) || (in_mklev && Is_earthlevel(&u.uz))) (void) mongets(mtmp, WAN_DIGGING); } else if (is_giant(ptr)) { for (cnt = rn2((int) (mtmp->m_lev / 2)); cnt; cnt--) { otmp = mksobj(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE - 1), FALSE, FALSE); otmp->quan = (long) rn1(2, 3); otmp->owt = weight(otmp); (void) mpickobj(mtmp, otmp); } } break; case S_WRAITH: if (ptr == &mons[PM_NAZGUL]) { otmp = mksobj(RIN_INVISIBILITY, FALSE, FALSE); curse(otmp); (void) mpickobj(mtmp, otmp); } break; case S_LICH: if (ptr == &mons[PM_MASTER_LICH] && !rn2(13)) (void) mongets(mtmp, (rn2(7) ? ATHAME : WAN_NOTHING)); else if (ptr == &mons[PM_ARCH_LICH] && !rn2(3)) { otmp = mksobj(rn2(3) ? ATHAME : QUARTERSTAFF, TRUE, rn2(13) ? FALSE : TRUE); if (otmp->spe < 2) otmp->spe = rnd(3); if (!rn2(4)) otmp->oerodeproof = 1; (void) mpickobj(mtmp, otmp); } break; case S_MUMMY: if (rn2(7)) (void) mongets(mtmp, MUMMY_WRAPPING); break; case S_QUANTMECH: if (!rn2(20)) { otmp = mksobj(LARGE_BOX, FALSE, FALSE); otmp->spe = 1; /* flag for special box */ otmp->owt = weight(otmp); (void) mpickobj(mtmp, otmp); } break; case S_LEPRECHAUN: mkmonmoney(mtmp, (long) d(level_difficulty(), 30)); break; case S_DEMON: /* moved here from m_initweap() because these don't have AT_WEAP so m_initweap() is not called for them */ if (ptr == &mons[PM_ICE_DEVIL] && !rn2(4)) { (void) mongets(mtmp, SPEAR); } else if (ptr == &mons[PM_ASMODEUS]) { (void) mongets(mtmp, WAN_COLD); (void) mongets(mtmp, WAN_FIRE); } break; case S_GNOME: if (!rn2((In_mines(&u.uz) && in_mklev) ? 20 : 60)) { otmp = mksobj(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, TRUE, FALSE); otmp->quan = 1; otmp->owt = weight(otmp); if (!mpickobj(mtmp, otmp) && !levl[mtmp->mx][mtmp->my].lit) begin_burn(otmp, FALSE); } break; default: break; } /* ordinary soldiers rarely have access to magic (or gold :-) */ if (ptr == &mons[PM_SOLDIER] && rn2(13)) return; if ((int) mtmp->m_lev > rn2(50)) (void) mongets(mtmp, rnd_defensive_item(mtmp)); if ((int) mtmp->m_lev > rn2(100)) (void) mongets(mtmp, rnd_misc_item(mtmp)); if (likes_gold(ptr) && !findgold(mtmp->minvent) && !rn2(5)) mkmonmoney(mtmp, (long) d(level_difficulty(), mtmp->minvent ? 5 : 10)); } /* Note: for long worms, always call cutworm (cutworm calls clone_mon) */ struct monst * clone_mon(mon, x, y) struct monst *mon; xchar x, y; /* clone's preferred location or 0 (near mon) */ { coord mm; struct monst *m2; /* may be too weak or have been extinguished for population control */ if (mon->mhp <= 1 || (mvitals[monsndx(mon->data)].mvflags & G_EXTINCT)) return (struct monst *) 0; if (x == 0) { mm.x = mon->mx; mm.y = mon->my; if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y)) return (struct monst *) 0; } else if (!isok(x, y)) { return (struct monst *) 0; /* paranoia */ } else { mm.x = x; mm.y = y; if (MON_AT(mm.x, mm.y)) { if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y)) return (struct monst *) 0; } } m2 = newmonst(); *m2 = *mon; /* copy condition of old monster */ m2->mextra = (struct mextra *) 0; m2->nmon = fmon; fmon = m2; m2->m_id = context.ident++; if (!m2->m_id) m2->m_id = context.ident++; /* ident overflowed */ m2->mx = mm.x; m2->my = mm.y; m2->mcloned = 1; m2->minvent = (struct obj *) 0; /* objects don't clone */ m2->mleashed = FALSE; /* Max HP the same, but current HP halved for both. The caller * might want to override this by halving the max HP also. * When current HP is odd, the original keeps the extra point. */ m2->mhpmax = mon->mhpmax; m2->mhp = mon->mhp / 2; mon->mhp -= m2->mhp; /* since shopkeepers and guards will only be cloned if they've been * polymorphed away from their original forms, the clone doesn't have * room for the extra information. we also don't want two shopkeepers * around for the same shop. */ if (mon->isshk) m2->isshk = FALSE; if (mon->isgd) m2->isgd = FALSE; if (mon->ispriest) m2->ispriest = FALSE; place_monster(m2, m2->mx, m2->my); if (emits_light(m2->data)) new_light_source(m2->mx, m2->my, emits_light(m2->data), LS_MONSTER, monst_to_any(m2)); if (has_mname(mon)) { m2 = christen_monst(m2, MNAME(mon)); } else if (mon->isshk) { m2 = christen_monst(m2, shkname(mon)); } /* not all clones caused by player are tame or peaceful */ if (!context.mon_moving) { if (mon->mtame) m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0; else if (mon->mpeaceful) m2->mpeaceful = rn2(max(2 + u.uluck, 2)) ? 1 : 0; } newsym(m2->mx, m2->my); /* display the new monster */ if (m2->mtame) { if (mon->isminion) { newemin(m2); if (EMIN(mon)) *(EMIN(m2)) = *(EMIN(mon)); } else { /* because m2 is a copy of mon it is tame but not init'ed. * however, tamedog will not re-tame a tame dog, so m2 * must be made non-tame to get initialized properly. */ m2->mtame = 0; if (tamedog(m2, (struct obj *) 0)) { *(EDOG(m2)) = *(EDOG(mon)); } } } set_malign(m2); return m2; } /* * Propagate a species * * Once a certain number of monsters are created, don't create any more * at random (i.e. make them extinct). The previous (3.2) behavior was * to do this when a certain number had _died_, which didn't make * much sense. * * Returns FALSE propagation unsuccessful * TRUE propagation successful */ boolean propagate(mndx, tally, ghostly) int mndx; boolean tally; boolean ghostly; { boolean result; uchar lim = mbirth_limit(mndx); boolean gone = (mvitals[mndx].mvflags & G_GONE) != 0; /* geno'd|extinct */ result = (((int) mvitals[mndx].born < lim) && !gone) ? TRUE : FALSE; /* if it's unique, don't ever make it again */ if (mons[mndx].geno & G_UNIQ) mvitals[mndx].mvflags |= G_EXTINCT; if (mvitals[mndx].born < 255 && tally && (!ghostly || (ghostly && result))) mvitals[mndx].born++; if ((int) mvitals[mndx].born >= lim && !(mons[mndx].geno & G_NOGEN) && !(mvitals[mndx].mvflags & G_EXTINCT)) { if (wizard) { debugpline1("Automatically extinguished %s.", makeplural(mons[mndx].mname)); } mvitals[mndx].mvflags |= G_EXTINCT; reset_rndmonst(mndx); } return result; } /* amount of HP to lose from level drain (or gain from Stormbringer) */ int monhp_per_lvl(mon) struct monst *mon; { struct permonst *ptr = mon->data; int hp = rnd(8); /* default is d8 */ /* like newmonhp, but home elementals are ignored, riders use normal d8 */ if (is_golem(ptr)) { /* draining usually won't be applicable for these critters */ hp = golemhp(monsndx(ptr)) / (int) ptr->mlevel; } else if (ptr->mlevel > 49) { /* arbitrary; such monsters won't be involved in draining anyway */ hp = 4 + rnd(4); /* 5..8 */ } else if (ptr->mlet == S_DRAGON && monsndx(ptr) >= PM_GRAY_DRAGON) { /* adult dragons; newmonhp() uses In_endgame(&u.uz) ? 8 : 4 + rnd(4) */ hp = 4 + rn2(5); /* 4..8 */ } else if (!mon->m_lev) { /* level 0 monsters use 1d4 instead of Nd8 */ hp = rnd(4); } return hp; } /* set up a new monster's initial level and hit points; used by newcham() as well as by makemon() */ void newmonhp(mon, mndx) struct monst *mon; int mndx; { struct permonst *ptr = &mons[mndx]; mon->m_lev = adj_lev(ptr); if (is_golem(ptr)) { mon->mhpmax = mon->mhp = golemhp(mndx); } else if (is_rider(ptr)) { /* we want low HP, but a high mlevel so they can attack well */ mon->mhpmax = mon->mhp = d(10, 8); } else if (ptr->mlevel > 49) { /* "special" fixed hp monster * the hit points are encoded in the mlevel in a somewhat strange * way to fit in the 50..127 positive range of a signed character * above the 1..49 that indicate "normal" monster levels */ mon->mhpmax = mon->mhp = 2 * (ptr->mlevel - 6); mon->m_lev = mon->mhp / 4; /* approximation */ } else if (ptr->mlet == S_DRAGON && mndx >= PM_GRAY_DRAGON) { /* adult dragons */ mon->mhpmax = mon->mhp = (int) (In_endgame(&u.uz) ? (8 * mon->m_lev) : (4 * mon->m_lev + d((int) mon->m_lev, 4))); } else if (!mon->m_lev) { mon->mhpmax = mon->mhp = rnd(4); } else { mon->mhpmax = mon->mhp = d((int) mon->m_lev, 8); if (is_home_elemental(ptr)) mon->mhpmax = (mon->mhp *= 3); } } struct mextra * newmextra() { struct mextra *mextra; mextra = (struct mextra *) alloc(sizeof(struct mextra)); mextra->mname = 0; mextra->egd = 0; mextra->epri = 0; mextra->eshk = 0; mextra->emin = 0; mextra->edog = 0; mextra->mcorpsenm = NON_PM; return mextra; } boolean makemon_rnd_goodpos(mon, gpflags, cc) struct monst *mon; unsigned gpflags; coord *cc; { int tryct = 0; int nx,ny; boolean good; do { nx = rn1(COLNO - 3, 2); ny = rn2(ROWNO); good = (!in_mklev && cansee(nx,ny)) ? FALSE : goodpos(nx, ny, mon, gpflags); } while ((++tryct < 50) && !good); if (!good) { /* else go through all map positions, twice, first round ignoring positions in sight, and pick first good one. skip first round if we're in special level loader or blind */ int xofs = nx; int yofs = ny; int dx,dy; int bl = (in_mklev || Blind) ? 1 : 0; for ( ; bl < 2; bl++) { for (dx = 0; dx < COLNO; dx++) for (dy = 0; dy < ROWNO; dy++) { nx = ((dx + xofs) % (COLNO - 1)) + 1; ny = ((dy + yofs) % (ROWNO - 1)) + 1; if (bl == 0 && cansee(nx,ny)) continue; if (goodpos(nx, ny, mon, gpflags)) goto gotgood; } if (bl == 0 && (!mon || mon->data->mmove)) { /* all map positions are visible (or not good), try to pick something logical */ if (dnstair.sx && !rn2(2)) { nx = dnstair.sx; ny = dnstair.sy; } else if (upstair.sx && !rn2(2)) { nx = upstair.sx; ny = upstair.sy; } else if (dnladder.sx && !rn2(2)) { nx = dnladder.sx; ny = dnladder.sy; } else if (upladder.sx && !rn2(2)) { nx = upladder.sx; ny = upladder.sy; } if (goodpos(nx, ny, mon, gpflags)) goto gotgood; } } } else { gotgood: cc->x = nx; cc->y = ny; return TRUE; } return FALSE; } /* * called with [x,y] = coordinates; * [0,0] means anyplace * [u.ux,u.uy] means: near player (if !in_mklev) * * In case we make a monster group, only return the one at [x,y]. */ struct monst * makemon(ptr, x, y, mmflags) register struct permonst *ptr; register int x, y; int mmflags; { register struct monst *mtmp; int mndx, mcham, ct, mitem; boolean anymon = (!ptr); boolean byyou = (x == u.ux && y == u.uy); boolean allow_minvent = ((mmflags & NO_MINVENT) == 0); boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0); unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0; /* if caller wants random location, do it here */ if (x == 0 && y == 0) { coord cc; struct monst fakemon; cc.x = cc.y = 0; /* lint suppression */ fakemon.data = ptr; /* set up for goodpos */ if (!makemon_rnd_goodpos(ptr ? &fakemon : (struct monst *)0, gpflags, &cc)) return (struct monst *) 0; x = cc.x; y = cc.y; } else if (byyou && !in_mklev) { coord bypos; if (enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) { x = bypos.x; y = bypos.y; } else return (struct monst *) 0; } /* Does monster already exist at the position? */ if (MON_AT(x, y)) { if ((mmflags & MM_ADJACENTOK) != 0) { coord bypos; if (enexto_core(&bypos, x, y, ptr, gpflags)) { x = bypos.x; y = bypos.y; } else return (struct monst *) 0; } else return (struct monst *) 0; } if (ptr) { mndx = monsndx(ptr); /* if you are to make a specific monster and it has already been genocided, return */ if (mvitals[mndx].mvflags & G_GENOD) return (struct monst *) 0; if (wizard && (mvitals[mndx].mvflags & G_EXTINCT)) { debugpline1("Explicitly creating extinct monster %s.", mons[mndx].mname); } } else { /* make a random (common) monster that can survive here. * (the special levels ask for random monsters at specific * positions, causing mass drowning on the medusa level, * for instance.) */ int tryct = 0; /* maybe there are no good choices */ struct monst fakemon; do { if (!(ptr = rndmonst())) { debugpline0("Warning: no monster."); return (struct monst *) 0; /* no more monsters! */ } fakemon.data = ptr; /* set up for goodpos */ } while (++tryct <= 50 /* in Sokoban, don't accept a giant on first try; after that, boulder carriers are fair game */ && ((tryct == 1 && throws_rocks(ptr) && In_sokoban(&u.uz)) || !goodpos(x, y, &fakemon, gpflags))); mndx = monsndx(ptr); } (void) propagate(mndx, countbirth, FALSE); mtmp = newmonst(); *mtmp = zeromonst; /* clear all entries in structure */ if (mmflags & MM_EGD) newegd(mtmp); if (mmflags & MM_EPRI) newepri(mtmp); if (mmflags & MM_ESHK) neweshk(mtmp); if (mmflags & MM_EMIN) newemin(mtmp); if (mmflags & MM_EDOG) newedog(mtmp); mtmp->nmon = fmon; fmon = mtmp; mtmp->m_id = context.ident++; if (!mtmp->m_id) mtmp->m_id = context.ident++; /* ident overflowed */ set_mon_data(mtmp, ptr, 0); if (ptr->msound == MS_LEADER && quest_info(MS_LEADER) == mndx) quest_status.leader_m_id = mtmp->m_id; mtmp->mnum = mndx; /* set up level and hit points */ newmonhp(mtmp, mndx); if (is_female(ptr)) mtmp->female = TRUE; else if (is_male(ptr)) mtmp->female = FALSE; /* leader and nemesis gender is usually hardcoded in mons[], but for ones which can be random, it has already been chosen (in role_init(), for possible use by the quest pager code) */ else if (ptr->msound == MS_LEADER && quest_info(MS_LEADER) == mndx) mtmp->female = quest_status.ldrgend; else if (ptr->msound == MS_NEMESIS && quest_info(MS_NEMESIS) == mndx) mtmp->female = quest_status.nemgend; else mtmp->female = rn2(2); /* ignored for neuters */ if (In_sokoban(&u.uz) && !mindless(ptr)) /* know about traps here */ mtmp->mtrapseen = (1L << (PIT - 1)) | (1L << (HOLE - 1)); /* quest leader and nemesis both know about all trap types */ if (ptr->msound == MS_LEADER || ptr->msound == MS_NEMESIS) mtmp->mtrapseen = ~0; place_monster(mtmp, x, y); mtmp->mcansee = mtmp->mcanmove = TRUE; mtmp->mpeaceful = (mmflags & MM_ANGRY) ? FALSE : peace_minded(ptr); switch (ptr->mlet) { case S_MIMIC: set_mimic_sym(mtmp); break; case S_SPIDER: case S_SNAKE: if (in_mklev) if (x && y) (void) mkobj_at(0, x, y, TRUE); (void) hideunder(mtmp); break; case S_LIGHT: case S_ELEMENTAL: if (mndx == PM_STALKER || mndx == PM_BLACK_LIGHT) { mtmp->perminvis = TRUE; mtmp->minvis = TRUE; } break; case S_EEL: (void) hideunder(mtmp); break; case S_LEPRECHAUN: mtmp->msleeping = 1; break; case S_JABBERWOCK: case S_NYMPH: if (rn2(5) && !u.uhave.amulet) mtmp->msleeping = 1; break; case S_ORC: if (Race_if(PM_ELF)) mtmp->mpeaceful = FALSE; break; case S_UNICORN: if (is_unicorn(ptr) && sgn(u.ualign.type) == sgn(ptr->maligntyp)) mtmp->mpeaceful = TRUE; break; case S_BAT: if (Inhell && is_bat(ptr)) mon_adjust_speed(mtmp, 2, (struct obj *) 0); break; } if ((ct = emits_light(mtmp->data)) > 0) new_light_source(mtmp->mx, mtmp->my, ct, LS_MONSTER, monst_to_any(mtmp)); mitem = 0; /* extra inventory item for this monster */ if (mndx == PM_VLAD_THE_IMPALER) mitem = CANDELABRUM_OF_INVOCATION; mtmp->cham = NON_PM; /* default is "not a shapechanger" */ if ((mcham = pm_to_cham(mndx)) != NON_PM) { /* this is a shapechanger after all */ if (Protection_from_shape_changers || mndx == PM_VLAD_THE_IMPALER) { ; /* stuck in its natural form (NON_PM) */ } else { mtmp->cham = mcham; /* Note: shapechanger's initial form used to be chosen here with rndmonst(), yielding a monster which was appropriate to the level's difficulty but ignored the changer's usual type selection so would be inappropriate for vampshifters. Let newcham() pick the shape. */ if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE)) allow_minvent = FALSE; } } else if (mndx == PM_WIZARD_OF_YENDOR) { mtmp->iswiz = TRUE; context.no_of_wizards++; if (context.no_of_wizards == 1 && Is_earthlevel(&u.uz)) mitem = SPE_DIG; } else if (mndx == PM_GHOST && !(mmflags & MM_NONAME)) { mtmp = christen_monst(mtmp, rndghostname()); } else if (mndx == PM_CROESUS) { mitem = TWO_HANDED_SWORD; } else if (ptr->msound == MS_NEMESIS) { mitem = BELL_OF_OPENING; } else if (mndx == PM_PESTILENCE) { mitem = POT_SICKNESS; } if (mitem && allow_minvent) (void) mongets(mtmp, mitem); if (in_mklev) { if ((is_ndemon(ptr) || mndx == PM_WUMPUS || mndx == PM_LONG_WORM || mndx == PM_GIANT_EEL) && !u.uhave.amulet && rn2(5)) mtmp->msleeping = TRUE; } else { if (byyou) { newsym(mtmp->mx, mtmp->my); set_apparxy(mtmp); } } if (is_dprince(ptr) && ptr->msound == MS_BRIBE) { mtmp->mpeaceful = mtmp->minvis = mtmp->perminvis = 1; mtmp->mavenge = 0; if (uwep && uwep->oartifact == ART_EXCALIBUR) mtmp->mpeaceful = mtmp->mtame = FALSE; } #ifndef DCC30_BUG if (mndx == PM_LONG_WORM && (mtmp->wormno = get_wormno()) != 0) #else /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the same expression. */ if (mndx == PM_LONG_WORM && (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) #endif { /* we can now create worms with tails - 11/91 */ initworm(mtmp, rn2(5)); if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, x, y); } /* it's possible to create an ordinary monster of some special types; make sure their extended data is initialized to something sensible if caller hasn't specified MM_EPRI|MM_EMIN (when they're specified, caller intends to handle this itself) */ if ((mndx == PM_ALIGNED_PRIEST || mndx == PM_HIGH_PRIEST) ? !(mmflags & (MM_EPRI | MM_EMIN)) : (mndx == PM_ANGEL && !(mmflags & MM_EMIN) && !rn2(3))) { struct emin *eminp; newemin(mtmp); eminp = EMIN(mtmp); mtmp->isminion = 1; /* make priest be a roamer */ eminp->min_align = rn2(3) - 1; /* no A_NONE */ eminp->renegade = (boolean) ((mmflags & MM_ANGRY) ? 1 : !rn2(3)); mtmp->mpeaceful = (eminp->min_align == u.ualign.type) ? !eminp->renegade : eminp->renegade; } set_malign(mtmp); /* having finished peaceful changes */ if (anymon) { if ((ptr->geno & G_SGROUP) && rn2(2)) { m_initsgrp(mtmp, mtmp->mx, mtmp->my); } else if (ptr->geno & G_LGROUP) { if (rn2(3)) m_initlgrp(mtmp, mtmp->mx, mtmp->my); else m_initsgrp(mtmp, mtmp->mx, mtmp->my); } } if (allow_minvent) { if (is_armed(ptr)) m_initweap(mtmp); /* equip with weapons / armor */ m_initinv(mtmp); /* add on a few special items incl. more armor */ m_dowear(mtmp, TRUE); } else { /* no initial inventory is allowed */ if (mtmp->minvent) discard_minvent(mtmp); mtmp->minvent = (struct obj *) 0; /* caller expects this */ } if (ptr->mflags3 && !(mmflags & MM_NOWAIT)) { if (ptr->mflags3 & M3_WAITFORU) mtmp->mstrategy |= STRAT_WAITFORU; if (ptr->mflags3 & M3_CLOSE) mtmp->mstrategy |= STRAT_CLOSE; if (ptr->mflags3 & (M3_WAITMASK | M3_COVETOUS)) mtmp->mstrategy |= STRAT_APPEARMSG; } if (!in_mklev) newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */ return mtmp; } int mbirth_limit(mndx) int mndx; { /* assert(MAXMONNO < 255); */ return (mndx == PM_NAZGUL ? 9 : mndx == PM_ERINYS ? 3 : MAXMONNO); } /* used for wand/scroll/spell of create monster */ /* returns TRUE iff you know monsters have been created */ boolean create_critters(cnt, mptr, neverask) int cnt; struct permonst *mptr; /* usually null; used for confused reading */ boolean neverask; { coord c; int x, y; struct monst *mon; boolean known = FALSE; boolean ask = (wizard && !neverask); while (cnt--) { if (ask) { if (create_particular()) { known = TRUE; continue; } else ask = FALSE; /* ESC will shut off prompting */ } x = u.ux, y = u.uy; /* if in water, try to encourage an aquatic monster by finding and then specifying another wet location */ if (!mptr && u.uinwater && enexto(&c, x, y, &mons[PM_GIANT_EEL])) x = c.x, y = c.y; mon = makemon(mptr, x, y, NO_MM_FLAGS); if (mon && canspotmon(mon)) known = TRUE; } return known; } STATIC_OVL boolean uncommon(mndx) int mndx; { if (mons[mndx].geno & (G_NOGEN | G_UNIQ)) return TRUE; if (mvitals[mndx].mvflags & G_GONE) return TRUE; if (Inhell) return (boolean) (mons[mndx].maligntyp > A_NEUTRAL); else return (boolean) ((mons[mndx].geno & G_HELL) != 0); } /* * shift the probability of a monster's generation by * comparing the dungeon alignment and monster alignment. * return an integer in the range of 0-5. */ STATIC_OVL int align_shift(ptr) register struct permonst *ptr; { static NEARDATA long oldmoves = 0L; /* != 1, starting value of moves */ static NEARDATA s_level *lev; register int alshift; if (oldmoves != moves) { lev = Is_special(&u.uz); oldmoves = moves; } switch ((lev) ? lev->flags.align : dungeons[u.uz.dnum].flags.align) { default: /* just in case */ case AM_NONE: alshift = 0; break; case AM_LAWFUL: alshift = (ptr->maligntyp + 20) / (2 * ALIGNWEIGHT); break; case AM_NEUTRAL: alshift = (20 - abs(ptr->maligntyp)) / ALIGNWEIGHT; break; case AM_CHAOTIC: alshift = (-(ptr->maligntyp - 20)) / (2 * ALIGNWEIGHT); break; } return alshift; } static NEARDATA struct { int choice_count; char mchoices[SPECIAL_PM]; /* value range is 0..127 */ } rndmonst_state = { -1, { 0 } }; /* select a random monster type */ struct permonst * rndmonst() { register struct permonst *ptr; register int mndx, ct; if (u.uz.dnum == quest_dnum && rn2(7) && (ptr = qt_montype()) != 0) return ptr; if (rndmonst_state.choice_count < 0) { /* need to recalculate */ int zlevel, minmlev, maxmlev; boolean elemlevel; boolean upper; rndmonst_state.choice_count = 0; /* look for first common monster */ for (mndx = LOW_PM; mndx < SPECIAL_PM; mndx++) { if (!uncommon(mndx)) break; rndmonst_state.mchoices[mndx] = 0; } if (mndx == SPECIAL_PM) { /* evidently they've all been exterminated */ debugpline0("rndmonst: no common mons!"); return (struct permonst *) 0; } /* else `mndx' now ready for use below */ zlevel = level_difficulty(); /* determine the level of the weakest monster to make. */ minmlev = zlevel / 6; /* determine the level of the strongest monster to make. */ maxmlev = (zlevel + u.ulevel) / 2; upper = Is_rogue_level(&u.uz); elemlevel = In_endgame(&u.uz) && !Is_astralevel(&u.uz); /* * Find out how many monsters exist in the range we have selected. */ for ( ; mndx < SPECIAL_PM; mndx++) { /* (`mndx' initialized above) */ ptr = &mons[mndx]; rndmonst_state.mchoices[mndx] = 0; if (tooweak(mndx, minmlev) || toostrong(mndx, maxmlev)) continue; if (upper && !isupper(def_monsyms[(int) (ptr->mlet)].sym)) continue; if (elemlevel && wrong_elem_type(ptr)) continue; if (uncommon(mndx)) continue; if (Inhell && (ptr->geno & G_NOHELL)) continue; ct = (int) (ptr->geno & G_FREQ) + align_shift(ptr); if (ct < 0 || ct > 127) panic("rndmonst: bad count [#%d: %d]", mndx, ct); rndmonst_state.choice_count += ct; rndmonst_state.mchoices[mndx] = (char) ct; } /* * Possible modification: if choice_count is "too low", * expand minmlev..maxmlev range and try again. */ } /* choice_count+mchoices[] recalc */ if (rndmonst_state.choice_count <= 0) { /* maybe no common mons left, or all are too weak or too strong */ debugpline1("rndmonst: choice_count=%d", rndmonst_state.choice_count); return (struct permonst *) 0; } /* * Now, select a monster at random. */ ct = rnd(rndmonst_state.choice_count); for (mndx = LOW_PM; mndx < SPECIAL_PM; mndx++) if ((ct -= (int) rndmonst_state.mchoices[mndx]) <= 0) break; if (mndx == SPECIAL_PM || uncommon(mndx)) { /* shouldn't happen */ impossible("rndmonst: bad `mndx' [#%d]", mndx); return (struct permonst *) 0; } return &mons[mndx]; } /* called when you change level (experience or dungeon depth) or when monster species can no longer be created (genocide or extinction) */ void reset_rndmonst(mndx) int mndx; /* particular species that can no longer be created */ { /* cached selection info is out of date */ if (mndx == NON_PM) { rndmonst_state.choice_count = -1; /* full recalc needed */ } else if (mndx < SPECIAL_PM) { rndmonst_state.choice_count -= rndmonst_state.mchoices[mndx]; rndmonst_state.mchoices[mndx] = 0; } /* note: safe to ignore extinction of unique monsters */ } /* decide whether it's ok to generate a candidate monster by mkclass() */ STATIC_OVL boolean mk_gen_ok(mndx, mvflagsmask, genomask) int mndx, mvflagsmask, genomask; { struct permonst *ptr = &mons[mndx]; if (mvitals[mndx].mvflags & mvflagsmask) return FALSE; if (ptr->geno & genomask) return FALSE; if (is_placeholder(ptr)) return FALSE; #ifdef MAIL /* special levels might ask for random demon type; reject this one */ if (ptr == &mons[PM_MAIL_DAEMON]) return FALSE; #endif return TRUE; } /* Make one of the multiple types of a given monster class. * The second parameter specifies a special casing bit mask * to allow the normal genesis masks to be deactivated. * Returns Null if no monsters in that class can be made. */ struct permonst * mkclass(class, spc) char class; int spc; { register int first, last, num = 0; int maxmlev, mask = (G_NOGEN | G_UNIQ) & ~spc; maxmlev = level_difficulty() >> 1; if (class < 1 || class >= MAXMCLASSES) { impossible("mkclass called with bad class!"); return (struct permonst *) 0; } /* Assumption #1: monsters of a given class are contiguous in the * mons[] array. */ for (first = LOW_PM; first < SPECIAL_PM; first++) if (mons[first].mlet == class) break; if (first == SPECIAL_PM) return (struct permonst *) 0; for (last = first; last < SPECIAL_PM && mons[last].mlet == class; last++) if (mk_gen_ok(last, G_GONE, mask)) { /* consider it */ if (num && toostrong(last, maxmlev) && monstr[last] != monstr[last - 1] && rn2(2)) break; num += mons[last].geno & G_FREQ; } if (!num) return (struct permonst *) 0; /* Assumption #2: monsters of a given class are presented in ascending * order of strength. */ for (num = rnd(num); num > 0; first++) if (mk_gen_ok(first, G_GONE, mask)) { /* skew towards lower value monsters at lower exp. levels */ num -= mons[first].geno & G_FREQ; if (num && adj_lev(&mons[first]) > (u.ulevel * 2)) { /* but not when multiple monsters are same level */ if (mons[first].mlevel != mons[first + 1].mlevel) num--; } } first--; /* correct an off-by-one error */ return &mons[first]; } /* like mkclass(), but excludes difficulty considerations; used when player with polycontrol picks a class instead of a specific type; genocided types are avoided but extinct ones are acceptable; we don't check polyok() here--caller accepts some choices !polyok() would reject */ int mkclass_poly(class) int class; { register int first, last, num = 0; for (first = LOW_PM; first < SPECIAL_PM; first++) if (mons[first].mlet == class) break; if (first == SPECIAL_PM) return NON_PM; for (last = first; last < SPECIAL_PM && mons[last].mlet == class; last++) if (mk_gen_ok(last, G_GENOD, (G_NOGEN | G_UNIQ))) num += mons[last].geno & G_FREQ; if (!num) return NON_PM; for (num = rnd(num); num > 0; first++) if (mk_gen_ok(first, G_GENOD, (G_NOGEN | G_UNIQ))) num -= mons[first].geno & G_FREQ; first--; /* correct an off-by-one error */ return first; } /* adjust strength of monsters based on u.uz and u.ulevel */ int adj_lev(ptr) register struct permonst *ptr; { int tmp, tmp2; if (ptr == &mons[PM_WIZARD_OF_YENDOR]) { /* does not depend on other strengths, but does get stronger * every time he is killed */ tmp = ptr->mlevel + mvitals[PM_WIZARD_OF_YENDOR].died; if (tmp > 49) tmp = 49; return tmp; } if ((tmp = ptr->mlevel) > 49) return 50; /* "special" demons/devils */ tmp2 = (level_difficulty() - tmp); if (tmp2 < 0) tmp--; /* if mlevel > u.uz decrement tmp */ else tmp += (tmp2 / 5); /* else increment 1 per five diff */ tmp2 = (u.ulevel - ptr->mlevel); /* adjust vs. the player */ if (tmp2 > 0) tmp += (tmp2 / 4); /* level as well */ tmp2 = (3 * ((int) ptr->mlevel)) / 2; /* crude upper limit */ if (tmp2 > 49) tmp2 = 49; /* hard upper limit */ return ((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */ } /* monster earned experience and will gain some hit points; it might also grow into a bigger monster (baby to adult, soldier to officer, etc) */ struct permonst * grow_up(mtmp, victim) struct monst *mtmp, *victim; { int oldtype, newtype, max_increase, cur_increase, lev_limit, hp_threshold; struct permonst *ptr = mtmp->data; /* monster died after killing enemy but before calling this function */ /* currently possible if killing a gas spore */ if (mtmp->mhp <= 0) return (struct permonst *) 0; /* note: none of the monsters with special hit point calculations have both little and big forms */ oldtype = monsndx(ptr); newtype = little_to_big(oldtype); if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; /* growth limits differ depending on method of advancement */ if (victim) { /* killed a monster */ /* * The HP threshold is the maximum number of hit points for the * current level; once exceeded, a level will be gained. * Possible bug: if somehow the hit points are already higher * than that, monster will gain a level without any increase in HP. */ hp_threshold = mtmp->m_lev * 8; /* normal limit */ if (!mtmp->m_lev) hp_threshold = 4; else if (is_golem(ptr)) /* strange creatures */ hp_threshold = ((mtmp->mhpmax / 10) + 1) * 10 - 1; else if (is_home_elemental(ptr)) hp_threshold *= 3; lev_limit = 3 * (int) ptr->mlevel / 2; /* same as adj_lev() */ /* If they can grow up, be sure the level is high enough for that */ if (oldtype != newtype && mons[newtype].mlevel > lev_limit) lev_limit = (int) mons[newtype].mlevel; /* number of hit points to gain; unlike for the player, we put the limit at the bottom of the next level rather than the top */ max_increase = rnd((int) victim->m_lev + 1); if (mtmp->mhpmax + max_increase > hp_threshold + 1) max_increase = max((hp_threshold + 1) - mtmp->mhpmax, 0); cur_increase = (max_increase > 1) ? rn2(max_increase) : 0; } else { /* a gain level potion or wraith corpse; always go up a level unless already at maximum (49 is hard upper limit except for demon lords, who start at 50 and can't go any higher) */ max_increase = cur_increase = rnd(8); hp_threshold = 0; /* smaller than `mhpmax + max_increase' */ lev_limit = 50; /* recalc below */ } mtmp->mhpmax += max_increase; mtmp->mhp += cur_increase; if (mtmp->mhpmax <= hp_threshold) return ptr; /* doesn't gain a level */ if (is_mplayer(ptr)) lev_limit = 30; /* same as player */ else if (lev_limit < 5) lev_limit = 5; /* arbitrary */ else if (lev_limit > 49) lev_limit = (ptr->mlevel > 49 ? 50 : 49); if ((int) ++mtmp->m_lev >= mons[newtype].mlevel && newtype != oldtype) { ptr = &mons[newtype]; if (mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */ if (canspotmon(mtmp)) pline("As %s grows up into %s, %s %s!", mon_nam(mtmp), an(ptr->mname), mhe(mtmp), nonliving(ptr) ? "expires" : "dies"); set_mon_data(mtmp, ptr, -1); /* keep mvitals[] accurate */ mondied(mtmp); return (struct permonst *) 0; } else if (canspotmon(mtmp)) { pline("%s %s %s.", Monnam(mtmp), humanoid(ptr) ? "becomes" : "grows up into", an(ptr->mname)); } set_mon_data(mtmp, ptr, 1); /* preserve intrinsics */ newsym(mtmp->mx, mtmp->my); /* color may change */ lev_limit = (int) mtmp->m_lev; /* never undo increment */ } /* sanity checks */ if ((int) mtmp->m_lev > lev_limit) { mtmp->m_lev--; /* undo increment */ /* HP might have been allowed to grow when it shouldn't */ if (mtmp->mhpmax == hp_threshold + 1) mtmp->mhpmax--; } if (mtmp->mhpmax > 50 * 8) mtmp->mhpmax = 50 * 8; /* absolute limit */ if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; return ptr; } int mongets(mtmp, otyp) register struct monst *mtmp; int otyp; { register struct obj *otmp; int spe; if (!otyp) return 0; otmp = mksobj(otyp, TRUE, FALSE); if (otmp) { if (mtmp->data->mlet == S_DEMON) { /* demons never get blessed objects */ if (otmp->blessed) curse(otmp); } else if (is_lminion(mtmp)) { /* lawful minions don't get cursed, bad, or rusting objects */ otmp->cursed = FALSE; if (otmp->spe < 0) otmp->spe = 0; otmp->oerodeproof = TRUE; } else if (is_mplayer(mtmp->data) && is_sword(otmp)) { otmp->spe = (3 + rn2(4)); } if (otmp->otyp == CANDELABRUM_OF_INVOCATION) { otmp->spe = 0; otmp->age = 0L; otmp->lamplit = FALSE; otmp->blessed = otmp->cursed = FALSE; } else if (otmp->otyp == BELL_OF_OPENING) { otmp->blessed = otmp->cursed = FALSE; } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) { otmp->blessed = FALSE; otmp->cursed = TRUE; } /* leaders don't tolerate inferior quality battle gear */ if (is_prince(mtmp->data)) { if (otmp->oclass == WEAPON_CLASS && otmp->spe < 1) otmp->spe = 1; else if (otmp->oclass == ARMOR_CLASS && otmp->spe < 0) otmp->spe = 0; } spe = otmp->spe; (void) mpickobj(mtmp, otmp); /* might free otmp */ return spe; } return 0; } int golemhp(type) int type; { switch (type) { case PM_STRAW_GOLEM: return 20; case PM_PAPER_GOLEM: return 20; case PM_ROPE_GOLEM: return 30; case PM_LEATHER_GOLEM: return 40; case PM_GOLD_GOLEM: return 40; case PM_WOOD_GOLEM: return 50; case PM_FLESH_GOLEM: return 40; case PM_CLAY_GOLEM: return 50; case PM_STONE_GOLEM: return 60; case PM_GLASS_GOLEM: return 60; case PM_IRON_GOLEM: return 80; default: return 0; } } /* * Alignment vs. yours determines monster's attitude to you. * (Some "animal" types are co-aligned, but also hungry.) */ boolean peace_minded(ptr) register struct permonst *ptr; { aligntyp mal = ptr->maligntyp, ual = u.ualign.type; if (always_peaceful(ptr)) return TRUE; if (always_hostile(ptr)) return FALSE; if (ptr->msound == MS_LEADER || ptr->msound == MS_GUARDIAN) return TRUE; if (ptr->msound == MS_NEMESIS) return FALSE; if (race_peaceful(ptr)) return TRUE; if (race_hostile(ptr)) return FALSE; /* the monster is hostile if its alignment is different from the * player's */ if (sgn(mal) != sgn(ual)) return FALSE; /* Negative monster hostile to player with Amulet. */ if (mal < A_NEUTRAL && u.uhave.amulet) return FALSE; /* minions are hostile to players that have strayed at all */ if (is_minion(ptr)) return (boolean) (u.ualign.record >= 0); /* Last case: a chance of a co-aligned monster being * hostile. This chance is greater if the player has strayed * (u.ualign.record negative) or the monster is not strongly aligned. */ return (boolean) (!!rn2(16 + (u.ualign.record < -15 ? -15 : u.ualign.record)) && !!rn2(2 + abs(mal))); } /* Set malign to have the proper effect on player alignment if monster is * killed. Negative numbers mean it's bad to kill this monster; positive * numbers mean it's good. Since there are more hostile monsters than * peaceful monsters, the penalty for killing a peaceful monster should be * greater than the bonus for killing a hostile monster to maintain balance. * Rules: * it's bad to kill peaceful monsters, potentially worse to kill always- * peaceful monsters; * it's never bad to kill a hostile monster, although it may not be good. */ void set_malign(mtmp) struct monst *mtmp; { schar mal = mtmp->data->maligntyp; boolean coaligned; if (mtmp->ispriest || mtmp->isminion) { /* some monsters have individual alignments; check them */ if (mtmp->ispriest && EPRI(mtmp)) mal = EPRI(mtmp)->shralign; else if (mtmp->isminion && EMIN(mtmp)) mal = EMIN(mtmp)->min_align; /* unless alignment is none, set mal to -5,0,5 */ /* (see align.h for valid aligntyp values) */ if (mal != A_NONE) mal *= 5; } coaligned = (sgn(mal) == sgn(u.ualign.type)); if (mtmp->data->msound == MS_LEADER) { mtmp->malign = -20; } else if (mal == A_NONE) { if (mtmp->mpeaceful) mtmp->malign = 0; else mtmp->malign = 20; /* really hostile */ } else if (always_peaceful(mtmp->data)) { int absmal = abs(mal); if (mtmp->mpeaceful) mtmp->malign = -3 * max(5, absmal); else mtmp->malign = 3 * max(5, absmal); /* renegade */ } else if (always_hostile(mtmp->data)) { int absmal = abs(mal); if (coaligned) mtmp->malign = 0; else mtmp->malign = max(5, absmal); } else if (coaligned) { int absmal = abs(mal); if (mtmp->mpeaceful) mtmp->malign = -3 * max(3, absmal); else /* renegade */ mtmp->malign = max(3, absmal); } else /* not coaligned and therefore hostile */ mtmp->malign = abs(mal); } /* allocate a new mcorpsenm field for a monster; only need mextra itself */ void newmcorpsenm(mtmp) struct monst *mtmp; { if (!mtmp->mextra) mtmp->mextra = newmextra(); MCORPSENM(mtmp) = NON_PM; /* not initialized yet */ } /* release monster's mcorpsenm field; basically a no-op */ void freemcorpsenm(mtmp) struct monst *mtmp; { if (has_mcorpsenm(mtmp)) MCORPSENM(mtmp) = NON_PM; } static NEARDATA char syms[] = { MAXOCLASSES, MAXOCLASSES + 1, RING_CLASS, WAND_CLASS, WEAPON_CLASS, FOOD_CLASS, COIN_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS, AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS, S_MIMIC_DEF, S_MIMIC_DEF, }; void set_mimic_sym(mtmp) register struct monst *mtmp; { int typ, roomno, rt; unsigned appear, ap_type; int s_sym; struct obj *otmp; int mx, my; if (!mtmp) return; mx = mtmp->mx; my = mtmp->my; typ = levl[mx][my].typ; /* only valid for INSIDE of room */ roomno = levl[mx][my].roomno - ROOMOFFSET; if (roomno >= 0) rt = rooms[roomno].rtype; #ifdef SPECIALIZATION else if (IS_ROOM(typ)) rt = OROOM, roomno = 0; #endif else rt = 0; /* roomno < 0 case for GCC_WARN */ if (OBJ_AT(mx, my)) { ap_type = M_AP_OBJECT; appear = level.objects[mx][my]->otyp; } else if (IS_DOOR(typ) || IS_WALL(typ) || typ == SDOOR || typ == SCORR) { ap_type = M_AP_FURNITURE; /* * If there is a wall to the left that connects to this * location, then the mimic mimics a horizontal closed door. * This does not allow doors to be in corners of rooms. * Since rogue has no closed doors, mimic a wall there * (yes, mimics can end up on this level by various means). */ if (mx != 0 && (levl[mx - 1][my].typ == HWALL || levl[mx - 1][my].typ == TLCORNER || levl[mx - 1][my].typ == TRWALL || levl[mx - 1][my].typ == BLCORNER || levl[mx - 1][my].typ == TDWALL || levl[mx - 1][my].typ == CROSSWALL || levl[mx - 1][my].typ == TUWALL)) appear = Is_rogue_level(&u.uz) ? S_hwall : S_hcdoor; else appear = Is_rogue_level(&u.uz) ? S_vwall : S_vcdoor; if (!mtmp->minvis || See_invisible) block_point(mx, my); /* vision */ } else if (level.flags.is_maze_lev && !In_sokoban(&u.uz) && rn2(2)) { ap_type = M_AP_OBJECT; appear = STATUE; } else if (roomno < 0 && !t_at(mx, my)) { ap_type = M_AP_OBJECT; appear = BOULDER; if (!mtmp->minvis || See_invisible) block_point(mx, my); /* vision */ } else if (rt == ZOO || rt == VAULT) { ap_type = M_AP_OBJECT; appear = GOLD_PIECE; } else if (rt == DELPHI) { if (rn2(2)) { ap_type = M_AP_OBJECT; appear = STATUE; } else { ap_type = M_AP_FURNITURE; appear = S_fountain; } } else if (rt == TEMPLE) { ap_type = M_AP_FURNITURE; appear = S_altar; /* * We won't bother with beehives, morgues, barracks, throne rooms * since they shouldn't contain too many mimics anyway... */ } else if (rt >= SHOPBASE) { s_sym = get_shop_item(rt - SHOPBASE); if (s_sym < 0) { ap_type = M_AP_OBJECT; appear = -s_sym; } else { if (s_sym == RANDOM_CLASS) s_sym = syms[rn2((int) sizeof(syms) - 2) + 2]; goto assign_sym; } } else { s_sym = syms[rn2((int) sizeof(syms))]; assign_sym: if (s_sym == MAXOCLASSES || s_sym == MAXOCLASSES + 1) { ap_type = M_AP_FURNITURE; appear = (s_sym == MAXOCLASSES) ? S_upstair : S_dnstair; } else { ap_type = M_AP_OBJECT; if (s_sym == S_MIMIC_DEF) { appear = STRANGE_OBJECT; } else if (s_sym == COIN_CLASS) { appear = GOLD_PIECE; } else { otmp = mkobj((char) s_sym, FALSE); appear = otmp->otyp; /* make sure container contents are free'ed */ obfree(otmp, (struct obj *) 0); } } } mtmp->m_ap_type = ap_type; mtmp->mappearance = appear; if (ap_type == M_AP_OBJECT && (appear == STATUE || appear == CORPSE || appear == FIGURINE || appear == EGG)) { newmcorpsenm(mtmp); MCORPSENM(mtmp) = rndmonnum(); if (appear == EGG && !can_be_hatched(MCORPSENM(mtmp))) MCORPSENM(mtmp) = NON_PM; /* revert to generic egg */ } } /* release monster from bag of tricks; return number of monsters created */ int bagotricks(bag, tipping, seencount) struct obj *bag; boolean tipping; /* caller emptying entire contents; affects shop handling */ int *seencount; /* secondary output */ { int moncount = 0; if (!bag || bag->otyp != BAG_OF_TRICKS) { impossible("bad bag o' tricks"); } else if (bag->spe < 1) { /* if tipping known empty bag, give normal empty container message */ pline1((tipping && bag->cknown) ? "It's empty." : nothing_happens); /* now known to be empty if sufficiently discovered */ if (bag->dknown && objects[bag->otyp].oc_name_known) bag->cknown = 1; } else { struct monst *mtmp; int creatcnt = 1, seecount = 0; consume_obj_charge(bag, !tipping); if (!rn2(23)) creatcnt += rnd(7); do { mtmp = makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); if (mtmp) { ++moncount; if (canspotmon(mtmp)) ++seecount; } } while (--creatcnt > 0); if (seecount) { if (seencount) *seencount += seecount; if (bag->dknown) makeknown(BAG_OF_TRICKS); } else if (!tipping) { pline1(!moncount ? nothing_happens : "Nothing seems to happen."); } } return moncount; } /*makemon.c*/ nethack-3.6.0/src/mapglyph.c0000664000076400007660000002635112624522452014724 0ustar paxedpaxed/* NetHack 3.6 mapglyph.c $NHDT-Date: 1448175698 2015/11/22 07:01:38 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #if defined(TTY_GRAPHICS) #include "wintty.h" /* for prototype of has_color() only */ #endif #include "color.h" #define HI_DOMESTIC CLR_WHITE /* monst.c */ static int explcolors[] = { CLR_BLACK, /* dark */ CLR_GREEN, /* noxious */ CLR_BROWN, /* muddy */ CLR_BLUE, /* wet */ CLR_MAGENTA, /* magical */ CLR_ORANGE, /* fiery */ CLR_WHITE, /* frosty */ }; #if !defined(TTY_GRAPHICS) #define has_color(n) TRUE #endif #ifdef TEXTCOLOR #define zap_color(n) color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) color = iflags.use_color ? defsyms[n].color : NO_COLOR #define obj_color(n) color = iflags.use_color ? objects[n].oc_color : NO_COLOR #define mon_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define invis_color(n) color = NO_COLOR #define pet_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define warn_color(n) \ color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR #define explode_color(n) color = iflags.use_color ? explcolors[n] : NO_COLOR #else /* no text color */ #define zap_color(n) #define cmap_color(n) #define obj_color(n) #define mon_color(n) #define invis_color(n) #define pet_color(c) #define warn_color(n) #define explode_color(n) #endif #if defined(USE_TILES) && defined(MSDOS) #define HAS_ROGUE_IBM_GRAPHICS \ (currentgraphics == ROGUESET && SYMHANDLING(H_IBM) && !iflags.grmode) #else #define HAS_ROGUE_IBM_GRAPHICS \ (currentgraphics == ROGUESET && SYMHANDLING(H_IBM)) #endif /*ARGSUSED*/ int mapglyph(glyph, ochar, ocolor, ospecial, x, y) int glyph, *ocolor, x, y; int *ochar; unsigned *ospecial; { register int offset, idx; int color = NO_COLOR; nhsym ch; unsigned special = 0; /* condense multiple tests in macro version down to single */ boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS; boolean has_rogue_color = (has_rogue_ibm_graphics && symset[currentgraphics].nocolor == 0); /* * Map the glyph back to a character and color. * * Warning: For speed, this makes an assumption on the order of * offsets. The order is set in display.h. */ if ((offset = (glyph - GLYPH_STATUE_OFF)) >= 0) { /* a statue */ idx = mons[offset].mlet + SYM_OFF_M; if (has_rogue_color) color = CLR_RED; else obj_color(STATUE); special |= MG_STATUE; if (level.objects[x][y] && level.objects[x][y]->nexthere) special |= MG_OBJPILE; } else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */ idx = offset + SYM_OFF_W; if (has_rogue_color) color = NO_COLOR; else warn_color(offset); } else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ /* see swallow_to_glyph() in display.c */ idx = (S_sw_tl + (offset & 0x7)) + SYM_OFF_P; if (has_rogue_color && iflags.use_color) color = NO_COLOR; else mon_color(offset >> 3); } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ /* see zapdir_to_glyph() in display.c */ idx = (S_vbeam + (offset & 0x3)) + SYM_OFF_P; if (has_rogue_color && iflags.use_color) color = NO_COLOR; else zap_color((offset >> 2)); } else if ((offset = (glyph - GLYPH_EXPLODE_OFF)) >= 0) { /* explosion */ idx = ((offset % MAXEXPCHARS) + S_explode1) + SYM_OFF_P; explode_color(offset / MAXEXPCHARS); } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ idx = offset + SYM_OFF_P; if (has_rogue_color && iflags.use_color) { if (offset >= S_vwall && offset <= S_hcdoor) color = CLR_BROWN; else if (offset >= S_arrow_trap && offset <= S_polymorph_trap) color = CLR_MAGENTA; else if (offset == S_corr || offset == S_litcorr) color = CLR_GRAY; else if (offset >= S_room && offset <= S_water && offset != S_darkroom) color = CLR_GREEN; else color = NO_COLOR; #ifdef TEXTCOLOR /* provide a visible difference if normal and lit corridor * use the same symbol */ } else if (iflags.use_color && offset == S_litcorr && showsyms[idx] == showsyms[S_corr + SYM_OFF_P]) { color = CLR_WHITE; #endif } else { cmap_color(offset); } } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) { /* object */ idx = objects[offset].oc_class + SYM_OFF_O; if (offset == BOULDER) idx = SYM_BOULDER + SYM_OFF_X; if (has_rogue_color && iflags.use_color) { switch (objects[offset].oc_class) { case COIN_CLASS: color = CLR_YELLOW; break; case FOOD_CLASS: color = CLR_RED; break; default: color = CLR_BRIGHT_BLUE; break; } } else obj_color(offset); if (offset != BOULDER && level.objects[x][y] && level.objects[x][y]->nexthere) special |= MG_OBJPILE; } else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */ idx = mons[offset].mlet + SYM_OFF_M; if (has_rogue_color) /* This currently implies that the hero is here -- monsters */ /* don't ride (yet...). Should we set it to yellow like in */ /* the monster case below? There is no equivalent in rogue. */ color = NO_COLOR; /* no need to check iflags.use_color */ else mon_color(offset); special |= MG_RIDDEN; } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ idx = objects[CORPSE].oc_class + SYM_OFF_O; if (has_rogue_color && iflags.use_color) color = CLR_RED; else mon_color(offset); special |= MG_CORPSE; if (level.objects[x][y] && level.objects[x][y]->nexthere) special |= MG_OBJPILE; } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */ idx = mons[offset].mlet + SYM_OFF_M; if (has_rogue_color) color = NO_COLOR; /* no need to check iflags.use_color */ else mon_color(offset); /* Disabled for now; anyone want to get reverse video to work? */ /* is_reverse = TRUE; */ special |= MG_DETECT; } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) { /* invisible */ idx = SYM_INVISIBLE + SYM_OFF_X; if (has_rogue_color) color = NO_COLOR; /* no need to check iflags.use_color */ else invis_color(offset); special |= MG_INVIS; } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) { /* a pet */ idx = mons[offset].mlet + SYM_OFF_M; if (has_rogue_color) color = NO_COLOR; /* no need to check iflags.use_color */ else pet_color(offset); special |= MG_PET; } else { /* a monster */ idx = mons[glyph].mlet + SYM_OFF_M; if (has_rogue_color && iflags.use_color) { if (x == u.ux && y == u.uy) /* actually player should be yellow-on-gray if in corridor */ color = CLR_YELLOW; else color = NO_COLOR; } else { mon_color(glyph); #ifdef TEXTCOLOR /* special case the hero for `showrace' option */ if (iflags.use_color && x == u.ux && y == u.uy && flags.showrace && !Upolyd) color = HI_DOMESTIC; #endif } } ch = showsyms[idx]; #ifdef TEXTCOLOR /* Turn off color if no color defined, or rogue level w/o PC graphics. */ if (!has_color(color) || (Is_rogue_level(&u.uz) && !has_rogue_color)) color = NO_COLOR; #endif *ochar = (int) ch; *ospecial = special; #ifdef TEXTCOLOR *ocolor = color; #endif return idx; } char * encglyph(glyph) int glyph; { static char encbuf[20]; Sprintf(encbuf, "\\G%04X%04X", context.rndencode, glyph); return encbuf; } /* * This differs from putstr() because the str parameter can * contain a sequence of characters representing: * \GXXXXNNNN a glyph value, encoded by encglyph(). * * For window ports that haven't yet written their own * XXX_putmixed() routine, this general one can be used. * It replaces the encoded glyph sequence with a single * showsyms[] char, then just passes that string onto * putstr(). */ void genl_putmixed(window, attr, str) winid window; int attr; const char *str; { static const char hex[] = "00112233445566778899aAbBcCdDeEfF"; char buf[BUFSZ]; const char *cp = str; char *put = buf; while (*cp) { if (*cp == '\\') { int rndchk, dcount, so, gv, ch = 0, oc = 0; unsigned os = 0; const char *dp, *save_cp; save_cp = cp++; switch (*cp) { case 'G': /* glyph value \GXXXXNNNN*/ rndchk = dcount = 0; for (++cp; *cp && ++dcount <= 4; ++cp) if ((dp = index(hex, *cp)) != 0) rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); else break; if (rndchk == context.rndencode) { gv = dcount = 0; for (; *cp && ++dcount <= 4; ++cp) if ((dp = index(hex, *cp)) != 0) gv = (gv * 16) + ((int) (dp - hex) / 2); else break; so = mapglyph(gv, &ch, &oc, &os, 0, 0); *put++ = showsyms[so]; /* 'cp' is ready for the next loop iteration and '*cp' should not be copied at the end of this iteration */ continue; } else { /* possible forgery - leave it the way it is */ cp = save_cp; } break; #if 0 case 'S': /* symbol offset */ so = rndchk = dcount = 0; for (++cp; *cp && ++dcount <= 4; ++cp) if ((dp = index(hex, *cp)) != 0) rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); else break; if (rndchk == context.rndencode) { dcount = 0; for (; *cp && ++dcount <= 2; ++cp) if ((dp = index(hex, *cp)) != 0) so = (so * 16) + ((int) (dp - hex) / 2); else break; } *put++ = showsyms[so]; break; #endif case '\\': break; } } *put++ = *cp++; } *put = '\0'; /* now send it to the normal putstr */ putstr(window, attr, buf); } /*mapglyph.c*/ nethack-3.6.0/src/mcastu.c0000664000076400007660000006753612625266237014420 0ustar paxedpaxed/* NetHack 3.6 mcastu.c $NHDT-Date: 1436753517 2015/07/13 02:11:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* monster mage spells */ #define MGC_PSI_BOLT 0 #define MGC_CURE_SELF 1 #define MGC_HASTE_SELF 2 #define MGC_STUN_YOU 3 #define MGC_DISAPPEAR 4 #define MGC_WEAKEN_YOU 5 #define MGC_DESTRY_ARMR 6 #define MGC_CURSE_ITEMS 7 #define MGC_AGGRAVATION 8 #define MGC_SUMMON_MONS 9 #define MGC_CLONE_WIZ 10 #define MGC_DEATH_TOUCH 11 /* monster cleric spells */ #define CLC_OPEN_WOUNDS 0 #define CLC_CURE_SELF 1 #define CLC_CONFUSE_YOU 2 #define CLC_PARALYZE 3 #define CLC_BLIND_YOU 4 #define CLC_INSECTS 5 #define CLC_CURSE_ITEMS 6 #define CLC_LIGHTNING 7 #define CLC_FIRE_PILLAR 8 #define CLC_GEYSER 9 STATIC_DCL void FDECL(cursetxt, (struct monst *, BOOLEAN_P)); STATIC_DCL int FDECL(choose_magic_spell, (int)); STATIC_DCL int FDECL(choose_clerical_spell, (int)); STATIC_DCL void FDECL(cast_wizard_spell, (struct monst *, int, int)); STATIC_DCL void FDECL(cast_cleric_spell, (struct monst *, int, int)); STATIC_DCL boolean FDECL(is_undirected_spell, (unsigned int, int)); STATIC_DCL boolean FDECL(spell_would_be_useless, (struct monst *, unsigned int, int)); extern const char *const flash_types[]; /* from zap.c */ /* feedback when frustrated monster couldn't cast a spell */ STATIC_OVL void cursetxt(mtmp, undirected) struct monst *mtmp; boolean undirected; { if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) { const char *point_msg; /* spellcasting monsters are impolite */ if (undirected) point_msg = "all around, then curses"; else if ((Invis && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) || is_obj_mappear(&youmonst, STRANGE_OBJECT) || u.uundetected) point_msg = "and curses in your general direction"; else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) point_msg = "and curses at your displaced image"; else point_msg = "at you, then curses"; pline("%s points %s.", Monnam(mtmp), point_msg); } else if ((!(moves % 4) || !rn2(4))) { if (!Deaf) Norep("You hear a mumbled curse."); } } /* convert a level based random selection into a specific mage spell; inappropriate choices will be screened out by spell_would_be_useless() */ STATIC_OVL int choose_magic_spell(spellval) int spellval; { /* for 3.4.3 and earlier, val greater than 22 selected the default spell */ while (spellval > 24 && rn2(25)) spellval = rn2(spellval); switch (spellval) { case 24: case 23: if (Antimagic || Hallucination) return MGC_PSI_BOLT; /* else FALL THROUGH */ case 22: case 21: case 20: return MGC_DEATH_TOUCH; case 19: case 18: return MGC_CLONE_WIZ; case 17: case 16: case 15: return MGC_SUMMON_MONS; case 14: case 13: return MGC_AGGRAVATION; case 12: case 11: case 10: return MGC_CURSE_ITEMS; case 9: case 8: return MGC_DESTRY_ARMR; case 7: case 6: return MGC_WEAKEN_YOU; case 5: case 4: return MGC_DISAPPEAR; case 3: return MGC_STUN_YOU; case 2: return MGC_HASTE_SELF; case 1: return MGC_CURE_SELF; case 0: default: return MGC_PSI_BOLT; } } /* convert a level based random selection into a specific cleric spell */ STATIC_OVL int choose_clerical_spell(spellnum) int spellnum; { /* for 3.4.3 and earlier, num greater than 13 selected the default spell */ while (spellnum > 15 && rn2(16)) spellnum = rn2(spellnum); switch (spellnum) { case 15: case 14: if (rn2(3)) return CLC_OPEN_WOUNDS; /* else FALL THROUGH */ case 13: return CLC_GEYSER; case 12: return CLC_FIRE_PILLAR; case 11: return CLC_LIGHTNING; case 10: case 9: return CLC_CURSE_ITEMS; case 8: return CLC_INSECTS; case 7: case 6: return CLC_BLIND_YOU; case 5: case 4: return CLC_PARALYZE; case 3: case 2: return CLC_CONFUSE_YOU; case 1: return CLC_CURE_SELF; case 0: default: return CLC_OPEN_WOUNDS; } } /* return values: * 1: successful spell * 0: unsuccessful spell */ int castmu(mtmp, mattk, thinks_it_foundyou, foundyou) register struct monst *mtmp; register struct attack *mattk; boolean thinks_it_foundyou; boolean foundyou; { int dmg, ml = mtmp->m_lev; int ret; int spellnum = 0; /* Three cases: * -- monster is attacking you. Search for a useful spell. * -- monster thinks it's attacking you. Search for a useful spell, * without checking for undirected. If the spell found is directed, * it fails with cursetxt() and loss of mspec_used. * -- monster isn't trying to attack. Select a spell once. Don't keep * searching; if that spell is not useful (or if it's directed), * return and do something else. * Since most spells are directed, this means that a monster that isn't * attacking casts spells only a small portion of the time that an * attacking monster does. */ if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) { int cnt = 40; do { spellnum = rn2(ml); if (mattk->adtyp == AD_SPEL) spellnum = choose_magic_spell(spellnum); else spellnum = choose_clerical_spell(spellnum); /* not trying to attack? don't allow directed spells */ if (!thinks_it_foundyou) { if (!is_undirected_spell(mattk->adtyp, spellnum) || spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) { if (foundyou) impossible( "spellcasting monster found you and doesn't know it?"); return 0; } break; } } while (--cnt > 0 && spell_would_be_useless(mtmp, mattk->adtyp, spellnum)); if (cnt == 0) return 0; } /* monster unable to cast spells? */ if (mtmp->mcan || mtmp->mspec_used || !ml) { cursetxt(mtmp, is_undirected_spell(mattk->adtyp, spellnum)); return (0); } if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) { mtmp->mspec_used = 10 - mtmp->m_lev; if (mtmp->mspec_used < 2) mtmp->mspec_used = 2; } /* monster can cast spells, but is casting a directed spell at the wrong place? If so, give a message, and return. Do this *after* penalizing mspec_used. */ if (!foundyou && thinks_it_foundyou && !is_undirected_spell(mattk->adtyp, spellnum)) { pline("%s casts a spell at %s!", canseemon(mtmp) ? Monnam(mtmp) : "Something", levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); return (0); } nomul(0); if (rn2(ml * 10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */ if (canseemon(mtmp) && !Deaf) pline_The("air crackles around %s.", mon_nam(mtmp)); return (0); } if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) { pline("%s casts a spell%s!", canspotmon(mtmp) ? Monnam(mtmp) : "Something", is_undirected_spell(mattk->adtyp, spellnum) ? "" : (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at a spot near you" : (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at your displaced image" : " at you"); } /* * As these are spells, the damage is related to the level * of the monster casting the spell. */ if (!foundyou) { dmg = 0; if (mattk->adtyp != AD_SPEL && mattk->adtyp != AD_CLRC) { impossible( "%s casting non-hand-to-hand version of hand-to-hand spell %d?", Monnam(mtmp), mattk->adtyp); return (0); } } else if (mattk->damd) dmg = d((int) ((ml / 2) + mattk->damn), (int) mattk->damd); else dmg = d((int) ((ml / 2) + 1), 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; ret = 1; switch (mattk->adtyp) { case AD_FIRE: pline("You're enveloped in flames."); if (Fire_resistance) { shieldeff(u.ux, u.uy); pline("But you resist the effects."); dmg = 0; } burn_away_slime(); break; case AD_COLD: pline("You're covered in frost."); if (Cold_resistance) { shieldeff(u.ux, u.uy); pline("But you resist the effects."); dmg = 0; } break; case AD_MAGM: You("are hit by a shower of missiles!"); if (Antimagic) { shieldeff(u.ux, u.uy); pline_The("missiles bounce off!"); dmg = 0; } else dmg = d((int) mtmp->m_lev / 2 + 1, 6); break; case AD_SPEL: /* wizard spell */ case AD_CLRC: /* clerical spell */ { if (mattk->adtyp == AD_SPEL) cast_wizard_spell(mtmp, dmg, spellnum); else cast_cleric_spell(mtmp, dmg, spellnum); dmg = 0; /* done by the spell casting functions */ break; } } if (dmg) mdamageu(mtmp, dmg); return (ret); } /* monster wizard and cleric spellcasting functions */ /* If dmg is zero, then the monster is not casting at you. If the monster is intentionally not casting at you, we have previously called spell_would_be_useless() and spellnum should always be a valid undirected spell. If you modify either of these, be sure to change is_undirected_spell() and spell_would_be_useless(). */ STATIC_OVL void cast_wizard_spell(mtmp, dmg, spellnum) struct monst *mtmp; int dmg; int spellnum; { if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) { impossible("cast directed wizard spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case MGC_DEATH_TOUCH: pline("Oh no, %s's using the touch of death!", mhe(mtmp)); if (nonliving(youmonst.data) || is_demon(youmonst.data)) { You("seem no deader than before."); } else if (!Antimagic && rn2(mtmp->m_lev) > 12) { if (Hallucination) { You("have an out of body experience."); } else { killer.format = KILLED_BY_AN; Strcpy(killer.name, "touch of death"); done(DIED); } } else { if (Antimagic) shieldeff(u.ux, u.uy); pline("Lucky for you, it didn't work!"); } dmg = 0; break; case MGC_CLONE_WIZ: if (mtmp->iswiz && context.no_of_wizards == 1) { pline("Double Trouble..."); clonewiz(); dmg = 0; } else impossible("bad wizard cloning?"); break; case MGC_SUMMON_MONS: { int count; count = nasty(mtmp); /* summon something nasty */ if (mtmp->iswiz) verbalize("Destroy the thief, my pet%s!", plur(count)); else { const char *mappear = (count == 1) ? "A monster appears" : "Monsters appear"; /* messages not quite right if plural monsters created but only a single monster is seen */ if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around a spot near you!", mappear); else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around your displaced image!", mappear); else pline("%s from nowhere!", mappear); } dmg = 0; break; } case MGC_AGGRAVATION: You_feel("that monsters are aware of your presence."); aggravate(); dmg = 0; break; case MGC_CURSE_ITEMS: You_feel("as if you need some help."); rndcurse(); dmg = 0; break; case MGC_DESTRY_ARMR: if (Antimagic) { shieldeff(u.ux, u.uy); pline("A field of force surrounds you!"); } else if (!destroy_arm(some_armor(&youmonst))) { Your("skin itches."); } dmg = 0; break; case MGC_WEAKEN_YOU: /* drain strength */ if (Antimagic) { shieldeff(u.ux, u.uy); You_feel("momentarily weakened."); } else { You("suddenly feel weaker!"); dmg = mtmp->m_lev - 6; if (Half_spell_damage) dmg = (dmg + 1) / 2; losestr(rnd(dmg)); if (u.uhp < 1) done_in_by(mtmp, DIED); } dmg = 0; break; case MGC_DISAPPEAR: /* makes self invisible */ if (!mtmp->minvis && !mtmp->invis_blkd) { if (canseemon(mtmp)) pline("%s suddenly %s!", Monnam(mtmp), !See_invisible ? "disappears" : "becomes transparent"); mon_set_minvis(mtmp); dmg = 0; } else impossible("no reason for monster to cast disappear spell?"); break; case MGC_STUN_YOU: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (!Stunned) You_feel("momentarily disoriented."); make_stunned(1L, FALSE); } else { You(Stunned ? "struggle to keep your balance." : "reel..."); dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4); if (Half_spell_damage) dmg = (dmg + 1) / 2; make_stunned((HStun & TIMEOUT) + (long) dmg, FALSE); } dmg = 0; break; case MGC_HASTE_SELF: mon_adjust_speed(mtmp, 1, (struct obj *) 0); dmg = 0; break; case MGC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case MGC_PSI_BOLT: /* prior to 3.4.0 Antimagic was setting the damage to 1--this made the spell virtually harmless to players with magic res. */ if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) You("get a slight %sache.", body_part(HEAD)); else if (dmg <= 10) Your("brain is on fire!"); else if (dmg <= 20) Your("%s suddenly aches painfully!", body_part(HEAD)); else Your("%s suddenly aches very painfully!", body_part(HEAD)); break; default: impossible("mcastu: invalid magic spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); } STATIC_OVL void cast_cleric_spell(mtmp, dmg, spellnum) struct monst *mtmp; int dmg; int spellnum; { if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) { impossible("cast directed cleric spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case CLC_GEYSER: /* this is physical damage (force not heat), * not magical damage or fire damage */ pline("A sudden geyser slams into you from nowhere!"); dmg = d(8, 6); if (Half_physical_damage) dmg = (dmg + 1) / 2; break; case CLC_FIRE_PILLAR: pline("A pillar of fire strikes all around you!"); if (Fire_resistance) { shieldeff(u.ux, u.uy); dmg = 0; } else dmg = d(8, 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; burn_away_slime(); (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); (void) burn_floor_objects(u.ux, u.uy, TRUE, FALSE); break; case CLC_LIGHTNING: { boolean reflects; pline("A bolt of lightning strikes down at you from above!"); reflects = ureflects("It bounces off your %s%s.", ""); if (reflects || Shock_resistance) { shieldeff(u.ux, u.uy); dmg = 0; if (reflects) break; } else dmg = d(8, 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; destroy_item(WAND_CLASS, AD_ELEC); destroy_item(RING_CLASS, AD_ELEC); (void) flashburn((long) rnd(100)); break; } case CLC_CURSE_ITEMS: You_feel("as if you need some help."); rndcurse(); dmg = 0; break; case CLC_INSECTS: { /* Try for insects, and if there are none left, go for (sticks to) snakes. -3. */ struct permonst *pm = mkclass(S_ANT, 0); struct monst *mtmp2 = (struct monst *) 0; char let = (pm ? S_ANT : S_SNAKE); boolean success = FALSE, seecaster; int i, quan, oldseen, newseen; coord bypos; const char *fmt; oldseen = monster_census(TRUE); quan = (mtmp->m_lev < 2) ? 1 : rnd((int) mtmp->m_lev / 2); if (quan < 3) quan = 3; for (i = 0; i <= quan; i++) { if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data)) break; if ((pm = mkclass(let, 0)) != 0 && (mtmp2 = makemon(pm, bypos.x, bypos.y, MM_ANGRY)) != 0) { success = TRUE; mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0; set_malign(mtmp2); } } newseen = monster_census(TRUE); /* not canspotmon(), which includes unseen things sensed via warning */ seecaster = canseemon(mtmp) || tp_sensemon(mtmp) || Detect_monsters; fmt = 0; if (!seecaster) { char *arg; /* [not const: upstart(N==1 ? an() : makeplural())] */ const char *what = (let == S_SNAKE) ? "snake" : "insect"; if (newseen <= oldseen || Unaware) { /* unseen caster fails or summons unseen critters, or unconscious hero ("You dream that you hear...") */ You_hear("someone summoning %s.", makeplural(what)); } else { /* unseen caster summoned seen critter(s) */ arg = (newseen == oldseen + 1) ? an(what) : makeplural(what); if (!Deaf) You_hear("someone summoning something, and %s %s.", arg, vtense(arg, "appear")); else pline("%s %s.", upstart(arg), vtense(arg, "appear")); } /* seen caster, possibly producing unseen--or just one--critters; hero is told what the caster is doing and doesn't necessarily observe complete accuracy of that caster's results (in other words, no need to fuss with visibility or singularization; player is told what's happening even if hero is unconscious) */ } else if (!success) fmt = "%s casts at a clump of sticks, but nothing happens."; else if (let == S_SNAKE) fmt = "%s transforms a clump of sticks into snakes!"; else if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) fmt = "%s summons insects around a spot near you!"; else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) fmt = "%s summons insects around your displaced image!"; else fmt = "%s summons insects!"; if (fmt) pline(fmt, Monnam(mtmp)); dmg = 0; break; } case CLC_BLIND_YOU: /* note: resists_blnd() doesn't apply here */ if (!Blinded) { int num_eyes = eyecount(youmonst.data); pline("Scales cover your %s!", (num_eyes == 1) ? body_part(EYE) : makeplural(body_part(EYE))); make_blinded(Half_spell_damage ? 100L : 200L, FALSE); if (!Blind) Your1(vision_clears); dmg = 0; } else impossible("no reason for monster to cast blindness spell?"); break; case CLC_PARALYZE: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (multi >= 0) You("stiffen briefly."); nomul(-1); multi_reason = "paralyzed by a monster"; } else { if (multi >= 0) You("are frozen in place!"); dmg = 4 + (int) mtmp->m_lev; if (Half_spell_damage) dmg = (dmg + 1) / 2; nomul(-dmg); multi_reason = "paralyzed by a monster"; } nomovemsg = 0; dmg = 0; break; case CLC_CONFUSE_YOU: if (Antimagic) { shieldeff(u.ux, u.uy); You_feel("momentarily dizzy."); } else { boolean oldprop = !!Confusion; dmg = (int) mtmp->m_lev; if (Half_spell_damage) dmg = (dmg + 1) / 2; make_confused(HConfusion + dmg, TRUE); if (Hallucination) You_feel("%s!", oldprop ? "trippier" : "trippy"); else You_feel("%sconfused!", oldprop ? "more " : ""); } dmg = 0; break; case CLC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case CLC_OPEN_WOUNDS: if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) Your("skin itches badly for a moment."); else if (dmg <= 10) pline("Wounds appear on your body!"); else if (dmg <= 20) pline("Severe wounds appear on your body!"); else Your("body is covered with painful wounds!"); break; default: impossible("mcastu: invalid clerical spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); } STATIC_DCL boolean is_undirected_spell(adtyp, spellnum) unsigned int adtyp; int spellnum; { if (adtyp == AD_SPEL) { switch (spellnum) { case MGC_CLONE_WIZ: case MGC_SUMMON_MONS: case MGC_AGGRAVATION: case MGC_DISAPPEAR: case MGC_HASTE_SELF: case MGC_CURE_SELF: return TRUE; default: break; } } else if (adtyp == AD_CLRC) { switch (spellnum) { case CLC_INSECTS: case CLC_CURE_SELF: return TRUE; default: break; } } return FALSE; } /* Some spells are useless under some circumstances. */ STATIC_DCL boolean spell_would_be_useless(mtmp, adtyp, spellnum) struct monst *mtmp; unsigned int adtyp; int spellnum; { /* Some spells don't require the player to really be there and can be cast * by the monster when you're invisible, yet still shouldn't be cast when * the monster doesn't even think you're there. * This check isn't quite right because it always uses your real position. * We really want something like "if the monster could see mux, muy". */ boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my); if (adtyp == AD_SPEL) { /* aggravate monsters, etc. won't be cast by peaceful monsters */ if (mtmp->mpeaceful && (spellnum == MGC_AGGRAVATION || spellnum == MGC_SUMMON_MONS || spellnum == MGC_CLONE_WIZ)) return TRUE; /* haste self when already fast */ if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF) return TRUE; /* invisibility when already invisible */ if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR) return TRUE; /* peaceful monster won't cast invisibility if you can't see invisible, same as when monsters drink potions of invisibility. This doesn't really make a lot of sense, but lets the player avoid hitting peaceful monsters by mistake */ if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR) return TRUE; /* healing when already healed */ if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF) return TRUE; /* don't summon monsters if it doesn't think you're around */ if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS || (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ))) return TRUE; if ((!mtmp->iswiz || context.no_of_wizards > 1) && spellnum == MGC_CLONE_WIZ) return TRUE; /* aggravation (global wakeup) when everyone is already active */ if (spellnum == MGC_AGGRAVATION) { struct monst *nxtmon; for (nxtmon = fmon; nxtmon; nxtmon = nxtmon->nmon) { if (DEADMONSTER(nxtmon)) continue; if ((nxtmon->mstrategy & STRAT_WAITFORU) != 0 || nxtmon->msleeping || !nxtmon->mcanmove) break; } /* if nothing needs to be awakened then this spell is useless but caster might not realize that [chance to pick it then must be very small otherwise caller's many retry attempts will eventually end up picking it too often] */ if (!nxtmon) return rn2(100) ? TRUE : FALSE; } } else if (adtyp == AD_CLRC) { /* summon insects/sticks to snakes won't be cast by peaceful monsters */ if (mtmp->mpeaceful && spellnum == CLC_INSECTS) return TRUE; /* healing when already healed */ if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF) return TRUE; /* don't summon insects if it doesn't think you're around */ if (!mcouldseeu && spellnum == CLC_INSECTS) return TRUE; /* blindness spell on blinded player */ if (Blinded && spellnum == CLC_BLIND_YOU) return TRUE; } return FALSE; } /* convert 1..10 to 0..9; add 10 for second group (spell casting) */ #define ad_to_typ(k) (10 + (int) k - 1) /* monster uses spell (ranged) */ int buzzmu(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { /* don't print constant stream of curse messages for 'normal' spellcasting monsters at range */ if (mattk->adtyp > AD_SPC2) return (0); if (mtmp->mcan) { cursetxt(mtmp, FALSE); return (0); } if (lined_up(mtmp) && rn2(3)) { nomul(0); if (mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */ if (canseemon(mtmp)) pline("%s zaps you with a %s!", Monnam(mtmp), flash_types[ad_to_typ(mattk->adtyp)]); buzz(-ad_to_typ(mattk->adtyp), (int) mattk->damn, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); } else impossible("Monster spell %d cast", mattk->adtyp - 1); } return (1); } /*mcastu.c*/ nethack-3.6.0/src/mhitm.c0000664000076400007660000014734312625266356014237 0ustar paxedpaxed/* NetHack 3.6 mhitm.c $NHDT-Date: 1446854229 2015/11/06 23:57:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.83 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" extern boolean notonhead; static NEARDATA boolean vis, far_noise; static NEARDATA long noisetime; static NEARDATA struct obj *otmp; static const char brief_feeling[] = "have a %s feeling for a moment, then it passes."; STATIC_DCL char *FDECL(mon_nam_too, (char *, struct monst *, struct monst *)); STATIC_DCL int FDECL(hitmm, (struct monst *, struct monst *, struct attack *)); STATIC_DCL int FDECL(gazemm, (struct monst *, struct monst *, struct attack *)); STATIC_DCL int FDECL(gulpmm, (struct monst *, struct monst *, struct attack *)); STATIC_DCL int FDECL(explmm, (struct monst *, struct monst *, struct attack *)); STATIC_DCL int FDECL(mdamagem, (struct monst *, struct monst *, struct attack *)); STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *)); STATIC_DCL void FDECL(noises, (struct monst *, struct attack *)); STATIC_DCL void FDECL(missmm, (struct monst *, struct monst *, struct attack *)); STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *, BOOLEAN_P, int)); /* Needed for the special case of monsters wielding vorpal blades (rare). * If we use this a lot it should probably be a parameter to mdamagem() * instead of a global variable. */ static int dieroll; /* returns mon_nam(mon) relative to other_mon; normal name unless they're the same, in which case the reference is to {him|her|it} self */ STATIC_OVL char * mon_nam_too(outbuf, mon, other_mon) char *outbuf; struct monst *mon, *other_mon; { Strcpy(outbuf, mon_nam(mon)); if (mon == other_mon) switch (pronoun_gender(mon)) { case 0: Strcpy(outbuf, "himself"); break; case 1: Strcpy(outbuf, "herself"); break; default: Strcpy(outbuf, "itself"); break; } return outbuf; } STATIC_OVL void noises(magr, mattk) register struct monst *magr; register struct attack *mattk; { boolean farq = (distu(magr->mx, magr->my) > 15); if (!Deaf && (farq != far_noise || moves - noisetime > 10)) { far_noise = farq; noisetime = moves; You_hear("%s%s.", (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises", farq ? " in the distance" : ""); } } STATIC_OVL void missmm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { const char *fmt; char buf[BUFSZ], mdef_name[BUFSZ]; if (vis) { if (!canspotmon(magr)) map_invisible(magr->mx, magr->my); if (!canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); if (mdef->m_ap_type) seemimic(mdef); if (magr->m_ap_type) seemimic(magr); fmt = (could_seduce(magr, mdef, mattk) && !magr->mcan) ? "%s pretends to be friendly to" : "%s misses"; Sprintf(buf, fmt, Monnam(magr)); pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr)); } else noises(magr, mattk); } /* * fightm() -- fight some other monster * * Returns: * 0 - Monster did nothing. * 1 - If the monster made an attack. The monster might have died. * * There is an exception to the above. If mtmp has the hero swallowed, * then we report that the monster did nothing so it will continue to * digest the hero. */ /* have monsters fight each other */ int fightm(mtmp) register struct monst *mtmp; { register struct monst *mon, *nmon; int result, has_u_swallowed; #ifdef LINT nmon = 0; #endif /* perhaps the monster will resist Conflict */ if (resist(mtmp, RING_CLASS, 0, 0)) return 0; if (u.ustuck == mtmp) { /* perhaps we're holding it... */ if (itsstuck(mtmp)) return 0; } has_u_swallowed = (u.uswallow && (mtmp == u.ustuck)); for (mon = fmon; mon; mon = nmon) { nmon = mon->nmon; if (nmon == mtmp) nmon = mtmp->nmon; /* Be careful to ignore monsters that are already dead, since we * might be calling this before we've cleaned them up. This can * happen if the monster attacked a cockatrice bare-handedly, for * instance. */ if (mon != mtmp && !DEADMONSTER(mon)) { if (monnear(mtmp, mon->mx, mon->my)) { if (!u.uswallow && (mtmp == u.ustuck)) { if (!rn2(4)) { pline("%s releases you!", Monnam(mtmp)); u.ustuck = 0; } else break; } /* mtmp can be killed */ bhitpos.x = mon->mx; bhitpos.y = mon->my; notonhead = 0; result = mattackm(mtmp, mon); if (result & MM_AGR_DIED) return 1; /* mtmp died */ /* * If mtmp has the hero swallowed, lie and say there * was no attack (this allows mtmp to digest the hero). */ if (has_u_swallowed) return 0; /* Allow attacked monsters a chance to hit back. Primarily * to allow monsters that resist conflict to respond. */ if ((result & MM_HIT) && !(result & MM_DEF_DIED) && rn2(4) && mon->movement >= NORMAL_SPEED) { mon->movement -= NORMAL_SPEED; notonhead = 0; (void) mattackm(mon, mtmp); /* return attack */ } return (result & MM_HIT) ? 1 : 0; } } } return 0; } /* * mdisplacem() -- attacker moves defender out of the way; * returns same results as mattackm(). */ int mdisplacem(magr, mdef, quietly) register struct monst *magr, *mdef; boolean quietly; { struct permonst *pa, *pd; int tx, ty, fx, fy; /* sanity checks; could matter if we unexpectedly get a long worm */ if (!magr || !mdef || magr == mdef) return MM_MISS; pa = magr->data, pd = mdef->data; tx = mdef->mx, ty = mdef->my; /* destination */ fx = magr->mx, fy = magr->my; /* current location */ if (m_at(fx, fy) != magr || m_at(tx, ty) != mdef) return MM_MISS; /* The 1 in 7 failure below matches the chance in attack() * for pet displacement. */ if (!rn2(7)) return MM_MISS; /* Grid bugs cannot displace at an angle. */ if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx && magr->my != mdef->my) return MM_MISS; /* undetected monster becomes un-hidden if it is displaced */ if (mdef->mundetected) mdef->mundetected = 0; if (mdef->m_ap_type && mdef->m_ap_type != M_AP_MONSTER) seemimic(mdef); /* wake up the displaced defender */ mdef->msleeping = 0; mdef->mstrategy &= ~STRAT_WAITMASK; finish_meating(mdef); /* * Set up the visibility of action. * You can observe monster displacement if you can see both of * the monsters involved. */ vis = (canspotmon(magr) && canspotmon(mdef)); if (touch_petrifies(pd) && !resists_ston(magr)) { if (which_armor(magr, W_ARMG) != 0) { if (poly_when_stoned(pa)) { mon_to_stone(magr); return MM_HIT; /* no damage during the polymorph */ } if (!quietly && canspotmon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); if (magr->mhp > 0) return MM_HIT; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); return MM_AGR_DIED; } } remove_monster(fx, fy); /* pick up from orig position */ remove_monster(tx, ty); place_monster(magr, tx, ty); /* put down at target spot */ place_monster(mdef, fx, fy); if (vis && !quietly) pline("%s moves %s out of %s way!", Monnam(magr), mon_nam(mdef), is_rider(pa) ? "the" : mhis(magr)); newsym(fx, fy); /* see it */ newsym(tx, ty); /* all happen */ flush_screen(0); /* make sure it shows up */ return MM_HIT; } /* * mattackm() -- a monster attacks another monster. * * --------- aggressor died * / ------- defender died * / / ----- defender was hit * / / / * x x x * * 0x4 MM_AGR_DIED * 0x2 MM_DEF_DIED * 0x1 MM_HIT * 0x0 MM_MISS * * Each successive attack has a lower probability of hitting. Some rely on * success of previous attacks. ** this doen't seem to be implemented -dl ** * * In the case of exploding monsters, the monster dies as well. */ int mattackm(magr, mdef) register struct monst *magr, *mdef; { int i, /* loop counter */ tmp, /* amour class difference */ strike, /* hit this attack */ attk, /* attack attempted this time */ struck = 0, /* hit at least once */ res[NATTK]; /* results of all attacks */ struct attack *mattk, alt_attk; struct permonst *pa, *pd; if (!magr || !mdef) return MM_MISS; /* mike@genat */ if (!magr->mcanmove || magr->msleeping) return MM_MISS; pa = magr->data; pd = mdef->data; /* Grid bugs cannot attack at an angle. */ if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx && magr->my != mdef->my) return MM_MISS; /* Calculate the armour class differential. */ tmp = find_mac(mdef) + magr->m_lev; if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) { tmp += 4; mdef->msleeping = 0; } /* undetect monsters become un-hidden if they are attacked */ if (mdef->mundetected) { mdef->mundetected = 0; newsym(mdef->mx, mdef->my); if (canseemon(mdef) && !sensemon(mdef)) { if (Unaware) You("dream of %s.", (mdef->data->geno & G_UNIQ) ? a_monnam(mdef) : makeplural(m_monnam(mdef))); else pline("Suddenly, you notice %s.", a_monnam(mdef)); } } /* Elves hate orcs. */ if (is_elf(pa) && is_orc(pd)) tmp++; /* Set up the visibility of action */ vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my) && (canspotmon(magr) || canspotmon(mdef))); /* Set flag indicating monster has moved this turn. Necessary since a * monster might get an attack out of sequence (i.e. before its move) in * some cases, in which case this still counts as its move for the round * and it shouldn't move again. */ magr->mlstmv = monstermoves; /* Now perform all attacks for the monster. */ for (i = 0; i < NATTK; i++) { res[i] = MM_MISS; mattk = getmattk(pa, i, res, &alt_attk); otmp = (struct obj *) 0; attk = 1; switch (mattk->aatyp) { case AT_WEAP: /* "hand to hand" attacks */ if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) { magr->weapon_check = NEED_HTH_WEAPON; if (mon_wield_item(magr) != 0) return 0; } possibly_unwield(magr, FALSE); otmp = MON_WEP(magr); if (otmp) { if (vis) mswingsm(magr, mdef, otmp); tmp += hitval(otmp, mdef); } /*FALLTHRU*/ case AT_CLAW: case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: case AT_TENT: /* Nymph that teleported away on first attack? */ if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) return MM_MISS; /* Monsters won't attack cockatrices physically if they * have a weapon instead. This instinct doesn't work for * players, or under conflict or confusion. */ if (!magr->mconf && !Conflict && otmp && mattk->aatyp != AT_WEAP && touch_petrifies(mdef->data)) { strike = 0; break; } dieroll = rnd(20 + i); strike = (tmp > dieroll); /* KMH -- don't accumulate to-hit bonuses */ if (otmp) tmp -= hitval(otmp, mdef); if (strike) { res[i] = hitmm(magr, mdef, mattk); if ((mdef->data == &mons[PM_BLACK_PUDDING] || mdef->data == &mons[PM_BROWN_PUDDING]) && otmp && objects[otmp->otyp].oc_material == IRON && mdef->mhp > 1 && !mdef->mcan) { if (clone_mon(mdef, 0, 0)) { if (vis) { char buf[BUFSZ]; Strcpy(buf, Monnam(mdef)); pline("%s divides as %s hits it!", buf, mon_nam(magr)); } } } } else missmm(magr, mdef, mattk); break; case AT_HUGS: /* automatic if prev two attacks succeed */ strike = (i >= 2 && res[i - 1] == MM_HIT && res[i - 2] == MM_HIT); if (strike) res[i] = hitmm(magr, mdef, mattk); break; case AT_GAZE: strike = 0; res[i] = gazemm(magr, mdef, mattk); break; case AT_EXPL: res[i] = explmm(magr, mdef, mattk); if (res[i] == MM_MISS) { /* cancelled--no attack */ strike = 0; attk = 0; } else strike = 1; /* automatic hit */ break; case AT_ENGL: if (u.usteed && (mdef == u.usteed)) { strike = 0; break; } /* Engulfing attacks are directed at the hero if * possible. -dlc */ if (u.uswallow && magr == u.ustuck) strike = 0; else { if ((strike = (tmp > rnd(20 + i)))) res[i] = gulpmm(magr, mdef, mattk); else missmm(magr, mdef, mattk); } break; default: /* no attack */ strike = 0; attk = 0; break; } if (attk && !(res[i] & MM_AGR_DIED)) res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED); if (res[i] & MM_DEF_DIED) return res[i]; if (res[i] & MM_AGR_DIED) return res[i]; /* return if aggressor can no longer attack */ if (!magr->mcanmove || magr->msleeping) return res[i]; if (res[i] & MM_HIT) struck = 1; /* at least one hit */ } return (struck ? MM_HIT : MM_MISS); } /* Returns the result of mdamagem(). */ STATIC_OVL int hitmm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { if (vis) { int compat; char buf[BUFSZ], mdef_name[BUFSZ]; if (!canspotmon(magr)) map_invisible(magr->mx, magr->my); if (!canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); if (mdef->m_ap_type) seemimic(mdef); if (magr->m_ap_type) seemimic(magr); if ((compat = could_seduce(magr, mdef, mattk)) && !magr->mcan) { Sprintf(buf, "%s %s", Monnam(magr), mdef->mcansee ? "smiles at" : "talks to"); pline("%s %s %s.", buf, mon_nam(mdef), compat == 2 ? "engagingly" : "seductively"); } else { char magr_name[BUFSZ]; Strcpy(magr_name, Monnam(magr)); switch (mattk->aatyp) { case AT_BITE: Sprintf(buf, "%s bites", magr_name); break; case AT_STNG: Sprintf(buf, "%s stings", magr_name); break; case AT_BUTT: Sprintf(buf, "%s butts", magr_name); break; case AT_TUCH: Sprintf(buf, "%s touches", magr_name); break; case AT_TENT: Sprintf(buf, "%s tentacles suck", s_suffix(magr_name)); break; case AT_HUGS: if (magr != u.ustuck) { Sprintf(buf, "%s squeezes", magr_name); break; } default: Sprintf(buf, "%s hits", magr_name); } pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr)); } } else noises(magr, mattk); return mdamagem(magr, mdef, mattk); } /* Returns the same values as mdamagem(). */ STATIC_OVL int gazemm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { char buf[BUFSZ]; if (vis) { Sprintf(buf, "%s gazes at", Monnam(magr)); pline("%s %s...", buf, mon_nam(mdef)); } if (magr->mcan || !magr->mcansee || (magr->minvis && !perceives(mdef->data)) || !mdef->mcansee || mdef->msleeping) { if (vis) pline("but nothing happens."); return MM_MISS; } /* call mon_reflects 2x, first test, then, if visible, print message */ if (magr->data == &mons[PM_MEDUSA] && mon_reflects(mdef, (char *) 0)) { if (canseemon(mdef)) (void) mon_reflects(mdef, "The gaze is reflected away by %s %s."); if (mdef->mcansee) { if (mon_reflects(magr, (char *) 0)) { if (canseemon(magr)) (void) mon_reflects( magr, "The gaze is reflected away by %s %s."); return MM_MISS; } if (mdef->minvis && !perceives(magr->data)) { if (canseemon(magr)) { pline( "%s doesn't seem to notice that %s gaze was reflected.", Monnam(magr), mhis(magr)); } return MM_MISS; } if (canseemon(magr)) pline("%s is turned to stone!", Monnam(magr)); monstone(magr); if (magr->mhp > 0) return MM_MISS; return MM_AGR_DIED; } } return mdamagem(magr, mdef, mattk); } /* return True if magr is allowed to swallow mdef, False otherwise */ boolean engulf_target(magr, mdef) struct monst *magr, *mdef; { struct rm *lev; int dx, dy; /* can't swallow something that's too big */ if (mdef->data->msize >= MZ_HUGE) return FALSE; /* (hypothetical) engulfers who can pass through walls aren't limited by rock|trees|bars */ if ((magr == &youmonst) ? Passes_walls : passes_walls(magr->data)) return TRUE; /* don't swallow something in a spot where attacker wouldn't otherwise be able to move onto; we don't want to engulf a wall-phaser and end up with a non-phaser inside a wall */ dx = mdef->mx, dy = mdef->my; if (mdef == &youmonst) dx = u.ux, dy = u.uy; lev = &levl[dx][dy]; if (IS_ROCK(lev->typ) || closed_door(dx, dy) || IS_TREE(lev->typ) /* not passes_bars(); engulfer isn't squeezing through */ || (lev->typ == IRONBARS && !is_whirly(magr->data))) return FALSE; return TRUE; } /* Returns the same values as mattackm(). */ STATIC_OVL int gulpmm(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { xchar ax, ay, dx, dy; int status; char buf[BUFSZ]; struct obj *obj; if (!engulf_target(magr, mdef)) return MM_MISS; if (vis) { Sprintf(buf, "%s swallows", Monnam(magr)); pline("%s %s.", buf, mon_nam(mdef)); } for (obj = mdef->minvent; obj; obj = obj->nobj) (void) snuff_lit(obj); /* * All of this manipulation is needed to keep the display correct. * There is a flush at the next pline(). */ ax = magr->mx; ay = magr->my; dx = mdef->mx; dy = mdef->my; /* * Leave the defender in the monster chain at it's current position, * but don't leave it on the screen. Move the aggressor to the * defender's position. */ remove_monster(ax, ay); place_monster(magr, dx, dy); newsym(ax, ay); /* erase old position */ newsym(dx, dy); /* update new position */ status = mdamagem(magr, mdef, mattk); if ((status & (MM_AGR_DIED | MM_DEF_DIED)) == (MM_AGR_DIED | MM_DEF_DIED)) { ; /* both died -- do nothing */ } else if (status & MM_DEF_DIED) { /* defender died */ /* * Note: remove_monster() was called in relmon(), wiping out * magr from level.monsters[mdef->mx][mdef->my]. We need to * put it back and display it. -kd */ place_monster(magr, dx, dy); newsym(dx, dy); /* aggressor moves to and might encounter trouble there */ if (minliquid(magr) || (t_at(dx, dy) && mintrap(magr) == 2)) status |= MM_AGR_DIED; } else if (status & MM_AGR_DIED) { /* aggressor died */ place_monster(mdef, dx, dy); newsym(dx, dy); } else { /* both alive, put them back */ if (cansee(dx, dy)) pline("%s is regurgitated!", Monnam(mdef)); place_monster(magr, ax, ay); place_monster(mdef, dx, dy); newsym(ax, ay); newsym(dx, dy); } return status; } STATIC_OVL int explmm(magr, mdef, mattk) struct monst *magr, *mdef; struct attack *mattk; { int result; if (magr->mcan) return MM_MISS; if (cansee(magr->mx, magr->my)) pline("%s explodes!", Monnam(magr)); else noises(magr, mattk); result = mdamagem(magr, mdef, mattk); /* Kill off aggressor if it didn't die. */ if (!(result & MM_AGR_DIED)) { mondead(magr); if (magr->mhp > 0) return result; /* life saved */ result |= MM_AGR_DIED; } if (magr->mtame) /* give this one even if it was visible */ You(brief_feeling, "melancholy"); return result; } /* * See comment at top of mattackm(), for return values. */ STATIC_OVL int mdamagem(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { struct obj *obj; char buf[BUFSZ]; struct permonst *pa = magr->data, *pd = mdef->data; int armpro, num, tmp = d((int) mattk->damn, (int) mattk->damd), res = MM_MISS; boolean cancelled; if ((touch_petrifies(pd) /* or flesh_petrifies() */ || (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA])) && !resists_ston(magr)) { long protector = attk_protection((int) mattk->aatyp), wornitems = magr->misc_worn_check; /* wielded weapon gives same protection as gloves here */ if (otmp != 0) wornitems |= W_ARMG; if (protector == 0L || (protector != ~0L && (wornitems & protector) != protector)) { if (poly_when_stoned(pa)) { mon_to_stone(magr); return MM_HIT; /* no damage during the polymorph */ } if (vis) pline("%s turns to stone!", Monnam(magr)); monstone(magr); if (magr->mhp > 0) return MM_HIT; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); return MM_AGR_DIED; } } /* cancellation factor is the same as when attacking the hero */ armpro = magic_negation(mdef); cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); switch (mattk->adtyp) { case AD_DGST: /* eating a Rider or its corpse is fatal */ if (is_rider(pd)) { if (vis) pline("%s %s!", Monnam(magr), (pd == &mons[PM_FAMINE]) ? "belches feebly, shrivels up and dies" : (pd == &mons[PM_PESTILENCE]) ? "coughs spasmodically and collapses" : "vomits violently and drops dead"); mondied(magr); if (magr->mhp > 0) return 0; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "queasy"); return MM_AGR_DIED; } if (flags.verbose && !Deaf) verbalize("Burrrrp!"); tmp = mdef->mhp; /* Use up amulet of life saving */ if (!!(obj = mlifesaver(mdef))) m_useup(mdef, obj); /* Is a corpse for nutrition possible? It may kill magr */ if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1) break; /* Pets get nutrition from swallowing monster whole. * No nutrition from G_NOCORPSE monster, eg, undead. * DGST monsters don't die from undead corpses */ num = monsndx(pd); if (magr->mtame && !magr->isminion && !(mvitals[num].mvflags & G_NOCORPSE)) { struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE); int nutrit; set_corpsenm(virtualcorpse, num); nutrit = dog_nutrition(magr, virtualcorpse); dealloc_obj(virtualcorpse); /* only 50% nutrition, 25% of normal eating time */ if (magr->meating > 1) magr->meating = (magr->meating + 3) / 4; if (nutrit > 1) nutrit /= 2; EDOG(magr)->hungrytime += nutrit; } break; case AD_STUN: if (magr->mcan) break; if (canseemon(mdef)) pline("%s %s for a moment.", Monnam(mdef), makeplural(stagger(pd, "stagger"))); mdef->mstun = 1; goto physical; case AD_LEGS: if (magr->mcan) { tmp = 0; break; } goto physical; case AD_WERE: case AD_HEAL: case AD_PHYS: physical: if (mattk->aatyp == AT_KICK && thick_skinned(pd)) { tmp = 0; } else if (mattk->aatyp == AT_WEAP) { if (otmp) { if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) goto do_stone; tmp += dmgval(otmp, mdef); if (otmp->oartifact) { (void) artifact_hit(magr, mdef, otmp, &tmp, dieroll); if (mdef->mhp <= 0) return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } if (tmp) rustm(mdef, otmp); } } else if (pa == &mons[PM_PURPLE_WORM] && pd == &mons[PM_SHRIEKER]) { /* hack to enhance mm_aggression(); we don't want purple worm's bite attack to kill a shrieker because then it won't swallow the corpse; but if the target survives, the subsequent engulf attack should accomplish that */ if (tmp >= mdef->mhp && mdef->mhp > 1) tmp = mdef->mhp - 1; } break; case AD_FIRE: if (cancelled) { tmp = 0; break; } if (vis) pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (vis) pline("%s burns completely!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) pline("May %s roast in peace.", mon_nam(mdef)); return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (resists_fire(mdef)) { if (vis) pline_The("fire doesn't seem to burn %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); golemeffects(mdef, AD_FIRE, tmp); tmp = 0; } /* only potions damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); break; case AD_COLD: if (cancelled) { tmp = 0; break; } if (vis) pline("%s is covered in frost!", Monnam(mdef)); if (resists_cold(mdef)) { if (vis) pline_The("frost doesn't seem to chill %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); golemeffects(mdef, AD_COLD, tmp); tmp = 0; } tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); break; case AD_ELEC: if (cancelled) { tmp = 0; break; } if (vis) pline("%s gets zapped!", Monnam(mdef)); tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); if (resists_elec(mdef)) { if (vis) pline_The("zap doesn't shock %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); golemeffects(mdef, AD_ELEC, tmp); tmp = 0; } /* only rings damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC); break; case AD_ACID: if (magr->mcan) { tmp = 0; break; } if (resists_acid(mdef)) { if (vis) pline("%s is covered in acid, but it seems harmless.", Monnam(mdef)); tmp = 0; } else if (vis) { pline("%s is covered in acid!", Monnam(mdef)); pline("It burns %s!", mon_nam(mdef)); } if (!rn2(30)) erode_armor(mdef, ERODE_CORRODE); if (!rn2(6)) acid_damage(MON_WEP(mdef)); break; case AD_RUST: if (magr->mcan) break; if (pd == &mons[PM_IRON_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) pline("May %s rust in peace.", mon_nam(mdef)); return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } erode_armor(mdef, ERODE_RUST); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_CORR: if (magr->mcan) break; erode_armor(mdef, ERODE_CORRODE); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_DCAY: if (magr->mcan) break; if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) pline("May %s rot in peace.", mon_nam(mdef)); return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } erode_armor(mdef, ERODE_CORRODE); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_STON: if (magr->mcan) break; do_stone: /* may die from the acid if it eats a stone-curing corpse */ if (munstone(mdef, FALSE)) goto post_stone; if (poly_when_stoned(pd)) { mon_to_stone(mdef); tmp = 0; break; } if (!resists_ston(mdef)) { if (vis) pline("%s turns to stone!", Monnam(mdef)); monstone(mdef); post_stone: if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "peculiarly sad"); return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } tmp = (mattk->adtyp == AD_STON ? 0 : 1); break; case AD_TLPT: if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) { char mdef_Monnam[BUFSZ]; /* save the name before monster teleports, otherwise we'll get "it" in the suddenly disappears message */ if (vis) Strcpy(mdef_Monnam, Monnam(mdef)); mdef->mstrategy &= ~STRAT_WAITFORU; (void) rloc(mdef, TRUE); if (vis && !canspotmon(mdef) && mdef != u.usteed) pline("%s suddenly disappears!", mdef_Monnam); } break; case AD_SLEE: if (!cancelled && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is put to sleep by %s.", buf, mon_nam(magr)); } mdef->mstrategy &= ~STRAT_WAITFORU; slept_monst(mdef); } break; case AD_PLYS: if (!cancelled && mdef->mcanmove) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is frozen by %s.", buf, mon_nam(magr)); } paralyze_monst(mdef, rnd(10)); } break; case AD_SLOW: if (!cancelled && mdef->mspeed != MSLOW) { unsigned int oldspeed = mdef->mspeed; mon_adjust_speed(mdef, -1, (struct obj *) 0); mdef->mstrategy &= ~STRAT_WAITFORU; if (mdef->mspeed != oldspeed && vis) pline("%s slows down.", Monnam(mdef)); } break; case AD_CONF: /* Since confusing another monster doesn't have a real time * limit, setting spec_used would not really be right (though * we still should check for it). */ if (!magr->mcan && !mdef->mconf && !magr->mspec_used) { if (vis) pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; mdef->mstrategy &= ~STRAT_WAITFORU; } break; case AD_BLND: if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) { register unsigned rnd_tmp; if (vis && mdef->mcansee) pline("%s is blinded.", Monnam(mdef)); rnd_tmp = d((int) mattk->damn, (int) mattk->damd); if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127; mdef->mblinded = rnd_tmp; mdef->mcansee = 0; mdef->mstrategy &= ~STRAT_WAITFORU; } tmp = 0; break; case AD_HALU: if (!magr->mcan && haseyes(pd) && mdef->mcansee) { if (vis) pline("%s looks %sconfused.", Monnam(mdef), mdef->mconf ? "more " : ""); mdef->mconf = 1; mdef->mstrategy &= ~STRAT_WAITFORU; } tmp = 0; break; case AD_CURS: if (!night() && (pa == &mons[PM_GREMLIN])) break; if (!magr->mcan && !rn2(10)) { mdef->mcan = 1; /* cancelled regardless of lifesave */ mdef->mstrategy &= ~STRAT_WAITFORU; if (is_were(pd) && pd->mlet != S_HUMAN) were_change(mdef); if (pd == &mons[PM_CLAY_GOLEM]) { if (vis) { pline("Some writing vanishes from %s head!", s_suffix(mon_nam(mdef))); pline("%s is destroyed!", Monnam(mdef)); } mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "strangely sad"); return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } if (!Deaf) { if (!vis) You_hear("laughter."); else pline("%s chuckles.", Monnam(magr)); } } break; case AD_SGLD: tmp = 0; if (magr->mcan) break; /* technically incorrect; no check for stealing gold from * between mdef's feet... */ { struct obj *gold = findgold(mdef->minvent); if (!gold) break; obj_extract_self(gold); add_to_minv(magr, gold); } mdef->mstrategy &= ~STRAT_WAITFORU; if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals some gold from %s.", buf, mon_nam(mdef)); } if (!tele_restrict(magr)) { (void) rloc(magr, TRUE); if (vis && !canspotmon(magr)) pline("%s suddenly disappears!", buf); } break; case AD_DRLI: if (!cancelled && !rn2(3) && !resists_drli(mdef)) { tmp = d(2, 6); if (vis) pline("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= tmp; if (mdef->m_lev == 0) tmp = mdef->mhp; else mdef->m_lev--; /* Automatic kill if drained past level 0 */ } break; case AD_SSEX: case AD_SITM: /* for now these are the same */ case AD_SEDU: if (magr->mcan) break; /* find an object to steal, non-cursed if magr is tame */ for (obj = mdef->minvent; obj; obj = obj->nobj) if (!magr->mtame || !obj->cursed) break; if (obj) { char onambuf[BUFSZ], mdefnambuf[BUFSZ]; /* make a special x_monnam() call that never omits the saddle, and save it for later messages */ Strcpy(mdefnambuf, x_monnam(mdef, ARTICLE_THE, (char *) 0, 0, FALSE)); otmp = obj; if (u.usteed == mdef && otmp == which_armor(mdef, W_SADDLE)) /* "You can no longer ride ." */ dismount_steed(DISMOUNT_POLY); obj_extract_self(otmp); if (otmp->owornmask) { mdef->misc_worn_check &= ~otmp->owornmask; if (otmp->owornmask & W_WEP) mwepgone(mdef); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); } /* add_to_minv() might free otmp [if it merges] */ if (vis) Strcpy(onambuf, doname(otmp)); (void) add_to_minv(magr, otmp); if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals %s from %s!", buf, onambuf, mdefnambuf); } possibly_unwield(mdef, FALSE); mdef->mstrategy &= ~STRAT_WAITFORU; mselftouch(mdef, (const char *) 0, FALSE); if (mdef->mhp <= 0) return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); if (pa->mlet == S_NYMPH && !tele_restrict(magr)) { (void) rloc(magr, TRUE); if (vis && !canspotmon(magr)) pline("%s suddenly disappears!", buf); } } tmp = 0; break; case AD_DREN: if (!cancelled && !rn2(4)) xdrainenergym(mdef, vis && mattk->aatyp != AT_ENGL); tmp = 0; break; case AD_DRST: case AD_DRDX: case AD_DRCO: if (!cancelled && !rn2(8)) { if (vis) pline("%s %s was poisoned!", s_suffix(Monnam(magr)), mpoisons_subj(magr, mattk)); if (resists_poison(mdef)) { if (vis) pline_The("poison doesn't seem to affect %s.", mon_nam(mdef)); } else { if (rn2(10)) tmp += rn1(10, 6); else { if (vis) pline_The("poison was deadly..."); tmp = mdef->mhp; } } } break; case AD_DRIN: if (notonhead || !has_head(pd)) { if (vis) pline("%s doesn't seem harmed.", Monnam(mdef)); /* Not clear what to do for green slimes */ tmp = 0; break; } if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) { if (vis) { Strcpy(buf, s_suffix(Monnam(mdef))); pline("%s helmet blocks %s attack to %s head.", buf, s_suffix(mon_nam(magr)), mhis(mdef)); } break; } res = eat_brains(magr, mdef, vis, &tmp); break; case AD_SLIM: if (cancelled) break; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { if (!munslime(mdef, FALSE) && mdef->mhp > 0) { if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis)) pd = mdef->data; mdef->mstrategy &= ~STRAT_WAITFORU; res = MM_HIT; } /* munslime attempt could have been fatal, potentially to multiple monsters (SCR_FIRE) */ if (magr->mhp < 1) res |= MM_AGR_DIED; if (mdef->mhp < 1) res |= MM_DEF_DIED; tmp = 0; } break; case AD_STCK: if (cancelled) tmp = 0; break; case AD_WRAP: /* monsters cannot grab one another, it's too hard */ if (magr->mcan) tmp = 0; break; case AD_ENCH: /* there's no msomearmor() function, so just do damage */ /* if (cancelled) break; */ break; default: tmp = 0; break; } if (!tmp) return res; if ((mdef->mhp -= tmp) < 1) { if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */ remove_monster(mdef->mx, mdef->my); mdef->mhp = 1; /* otherwise place_monster will complain */ place_monster(mdef, mdef->mx, mdef->my); mdef->mhp = 0; } monkilled(mdef, "", (int) mattk->adtyp); if (mdef->mhp > 0) return res; /* mdef lifesaved */ else if (res == MM_AGR_DIED) return (MM_DEF_DIED | MM_AGR_DIED); if (mattk->adtyp == AD_DGST) { /* various checks similar to dog_eat and meatobj. * after monkilled() to provide better message ordering */ if (mdef->cham >= LOW_PM) { (void) newcham(magr, (struct permonst *) 0, FALSE, TRUE); } else if (pd == &mons[PM_GREEN_SLIME] && !slimeproof(pa)) { (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE); } else if (pd == &mons[PM_WRAITH]) { (void) grow_up(magr, (struct monst *) 0); /* don't grow up twice */ return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED)); } else if (pd == &mons[PM_NURSE]) { magr->mhp = magr->mhpmax; } } /* caveat: above digestion handling doesn't keep `pa' up to date */ return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } return (res == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT; } void paralyze_monst(mon, amt) struct monst *mon; int amt; { if (amt > 127) amt = 127; mon->mcanmove = 0; mon->mfrozen = amt; mon->meating = 0; /* terminate any meal-in-progress */ mon->mstrategy &= ~STRAT_WAITFORU; } /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */ int sleep_monst(mon, amt, how) struct monst *mon; int amt, how; { if (resists_sleep(mon) || (how >= 0 && resist(mon, (char) how, 0, NOTELL))) { shieldeff(mon->mx, mon->my); } else if (mon->mcanmove) { finish_meating(mon); /* terminate any meal-in-progress */ amt += (int) mon->mfrozen; if (amt > 0) { /* sleep for N turns */ mon->mcanmove = 0; mon->mfrozen = min(amt, 127); } else { /* sleep until awakened */ mon->msleeping = 1; } return 1; } return 0; } /* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */ void slept_monst(mon) struct monst *mon; { if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck && !sticks(youmonst.data) && !u.uswallow) { pline("%s grip relaxes.", s_suffix(Monnam(mon))); unstuck(mon); } } void rustm(mdef, obj) struct monst *mdef; struct obj *obj; { int dmgtyp; if (!mdef || !obj) return; /* just in case */ /* AD_ACID is handled in passivemm */ if (dmgtype(mdef->data, AD_CORR)) dmgtyp = ERODE_CORRODE; else if (dmgtype(mdef->data, AD_RUST)) dmgtyp = ERODE_RUST; else if (dmgtype(mdef->data, AD_FIRE)) dmgtyp = ERODE_BURN; else return; (void) erode_obj(obj, NULL, dmgtyp, EF_GREASE | EF_VERBOSE); } STATIC_OVL void mswingsm(magr, mdef, otemp) struct monst *magr, *mdef; struct obj *otemp; { if (flags.verbose && !Blind && mon_visible(magr)) { pline("%s %s %s%s %s at %s.", Monnam(magr), (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings", (otemp->quan > 1L) ? "one of " : "", mhis(magr), xname(otemp), mon_nam(mdef)); } } /* * Passive responses by defenders. Does not replicate responses already * handled above. Returns same values as mattackm. */ STATIC_OVL int passivemm(magr, mdef, mhit, mdead) register struct monst *magr, *mdef; boolean mhit; int mdead; { register struct permonst *mddat = mdef->data; register struct permonst *madat = magr->data; char buf[BUFSZ]; int i, tmp; for (i = 0;; i++) { if (i >= NATTK) return (mdead | mhit); /* no passive attacks */ if (mddat->mattk[i].aatyp == AT_NONE) break; } if (mddat->mattk[i].damn) tmp = d((int) mddat->mattk[i].damn, (int) mddat->mattk[i].damd); else if (mddat->mattk[i].damd) tmp = d((int) mddat->mlevel + 1, (int) mddat->mattk[i].damd); else tmp = 0; /* These affect the enemy even if defender killed */ switch (mddat->mattk[i].adtyp) { case AD_ACID: if (mhit && !rn2(2)) { Strcpy(buf, Monnam(magr)); if (canseemon(magr)) pline("%s is splashed by %s acid!", buf, s_suffix(mon_nam(mdef))); if (resists_acid(magr)) { if (canseemon(magr)) pline("%s is not affected.", Monnam(magr)); tmp = 0; } } else tmp = 0; if (!rn2(30)) erode_armor(magr, ERODE_CORRODE); if (!rn2(6)) acid_damage(MON_WEP(magr)); goto assess_dmg; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (mhit && !mdef->mcan && otmp) { (void) drain_item(otmp); /* No message */ } break; default: break; } if (mdead || mdef->mcan) return (mdead | mhit); /* These affect the enemy only if defender is still alive */ if (rn2(3)) switch (mddat->mattk[i].adtyp) { case AD_PLYS: /* Floating eye */ if (tmp > 127) tmp = 127; if (mddat == &mons[PM_FLOATING_EYE]) { if (!rn2(4)) tmp = 127; if (magr->mcansee && haseyes(madat) && mdef->mcansee && (perceives(madat) || !mdef->minvis)) { Sprintf(buf, "%s gaze is reflected by %%s %%s.", s_suffix(Monnam(mdef))); if (mon_reflects(magr, canseemon(magr) ? buf : (char *) 0)) return (mdead | mhit); Strcpy(buf, Monnam(magr)); if (canseemon(magr)) pline("%s is frozen by %s gaze!", buf, s_suffix(mon_nam(mdef))); paralyze_monst(magr, tmp); return (mdead | mhit); } } else { /* gelatinous cube */ Strcpy(buf, Monnam(magr)); if (canseemon(magr)) pline("%s is frozen by %s.", buf, mon_nam(mdef)); paralyze_monst(magr, tmp); return (mdead | mhit); } return 1; case AD_COLD: if (resists_cold(magr)) { if (canseemon(magr)) { pline("%s is mildly chilly.", Monnam(magr)); golemeffects(magr, AD_COLD, tmp); } tmp = 0; break; } if (canseemon(magr)) pline("%s is suddenly very cold!", Monnam(magr)); mdef->mhp += tmp / 2; if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp; if (mdef->mhpmax > ((int) (mdef->m_lev + 1) * 8)) (void) split_mon(mdef, magr); break; case AD_STUN: if (!magr->mstun) { magr->mstun = 1; if (canseemon(magr)) pline("%s %s...", Monnam(magr), makeplural(stagger(magr->data, "stagger"))); } tmp = 0; break; case AD_FIRE: if (resists_fire(magr)) { if (canseemon(magr)) { pline("%s is mildly warmed.", Monnam(magr)); golemeffects(magr, AD_FIRE, tmp); } tmp = 0; break; } if (canseemon(magr)) pline("%s is suddenly very hot!", Monnam(magr)); break; case AD_ELEC: if (resists_elec(magr)) { if (canseemon(magr)) { pline("%s is mildly tingled.", Monnam(magr)); golemeffects(magr, AD_ELEC, tmp); } tmp = 0; break; } if (canseemon(magr)) pline("%s is jolted with electricity!", Monnam(magr)); break; default: tmp = 0; break; } else tmp = 0; assess_dmg: if ((magr->mhp -= tmp) <= 0) { monkilled(magr, "", (int) mddat->mattk[i].adtyp); return (mdead | mhit | MM_AGR_DIED); } return (mdead | mhit); } /* hero or monster has successfully hit target mon with drain energy attack */ void xdrainenergym(mon, givemsg) struct monst *mon; boolean givemsg; { if (mon->mspec_used < 20 /* limit draining */ && (attacktype(mon->data, AT_MAGC) || attacktype(mon->data, AT_BREA))) { mon->mspec_used += d(2, 2); if (givemsg) pline("%s seems lethargic.", Monnam(mon)); } } /* "aggressive defense"; what type of armor prevents specified attack from touching its target? */ long attk_protection(aatyp) int aatyp; { long w_mask = 0L; switch (aatyp) { case AT_NONE: case AT_SPIT: case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_BREA: case AT_MAGC: w_mask = ~0L; /* special case; no defense needed */ break; case AT_CLAW: case AT_TUCH: case AT_WEAP: w_mask = W_ARMG; /* caller needs to check for weapon */ break; case AT_KICK: w_mask = W_ARMF; break; case AT_BUTT: w_mask = W_ARMH; break; case AT_HUGS: w_mask = (W_ARMC | W_ARMG); /* attacker needs both to be protected */ break; case AT_BITE: case AT_STNG: case AT_ENGL: case AT_TENT: default: w_mask = 0L; /* no defense available */ break; } return w_mask; } /*mhitm.c*/ nethack-3.6.0/src/mhitu.c0000664000076400007660000027271412617413107014235 0ustar paxedpaxed/* NetHack 3.6 mhitu.c $NHDT-Date: 1446854230 2015/11/06 23:57:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.130 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" STATIC_VAR NEARDATA struct obj *otmp; STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *)); STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *, struct attack *)); STATIC_DCL void FDECL(mayberem, (struct obj *, const char *)); STATIC_DCL boolean FDECL(diseasemu, (struct permonst *)); STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *)); STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *)); STATIC_DCL int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P)); STATIC_DCL void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *)); STATIC_DCL void FDECL(mswings, (struct monst *, struct obj *)); STATIC_DCL void FDECL(wildmiss, (struct monst *, struct attack *)); STATIC_DCL void FDECL(hitmsg, (struct monst *, struct attack *)); /* See comment in mhitm.c. If we use this a lot it probably should be */ /* changed to a parameter to mhitu. */ static int dieroll; STATIC_OVL void hitmsg(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { int compat; /* Note: if opposite gender, "seductively" */ /* If same gender, "engagingly" for nymph, normal msg for others */ if ((compat = could_seduce(mtmp, &youmonst, mattk)) && !mtmp->mcan && !mtmp->mspec_used) { pline("%s %s you %s.", Monnam(mtmp), Blind ? "talks to" : "smiles at", compat == 2 ? "engagingly" : "seductively"); } else switch (mattk->aatyp) { case AT_BITE: pline("%s bites!", Monnam(mtmp)); break; case AT_KICK: pline("%s kicks%c", Monnam(mtmp), thick_skinned(youmonst.data) ? '.' : '!'); break; case AT_STNG: pline("%s stings!", Monnam(mtmp)); break; case AT_BUTT: pline("%s butts!", Monnam(mtmp)); break; case AT_TUCH: pline("%s touches you!", Monnam(mtmp)); break; case AT_TENT: pline("%s tentacles suck you!", s_suffix(Monnam(mtmp))); break; case AT_EXPL: case AT_BOOM: pline("%s explodes!", Monnam(mtmp)); break; default: pline("%s hits!", Monnam(mtmp)); } } /* monster missed you */ STATIC_OVL void missmu(mtmp, nearmiss, mattk) struct monst *mtmp; boolean nearmiss; struct attack *mattk; { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); if (could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan) pline("%s pretends to be friendly.", Monnam(mtmp)); else pline("%s %smisses!", Monnam(mtmp), (nearmiss && flags.verbose) ? "just " : ""); stop_occupation(); } /* monster swings obj */ STATIC_OVL void mswings(mtmp, otemp) struct monst *mtmp; struct obj *otemp; { if (flags.verbose && !Blind && mon_visible(mtmp)) { pline("%s %s %s%s %s.", Monnam(mtmp), (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings", (otemp->quan > 1L) ? "one of " : "", mhis(mtmp), xname(otemp)); } } /* return how a poison attack was delivered */ const char * mpoisons_subj(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { if (mattk->aatyp == AT_WEAP) { struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp); /* "Foo's attack was poisoned." is pretty lame, but at least it's better than "sting" when not a stinging attack... */ return (!mwep || !mwep->opoisoned) ? "attack" : "weapon"; } else { return (mattk->aatyp == AT_TUCH) ? "contact" : (mattk->aatyp == AT_GAZE) ? "gaze" : (mattk->aatyp == AT_BITE) ? "bite" : "sting"; } } /* called when your intrinsic speed is taken away */ void u_slow_down() { HFast = 0L; if (!Fast) You("slow down."); else /* speed boots */ Your("quickness feels less natural."); exercise(A_DEX, FALSE); } /* monster attacked your displaced image */ STATIC_OVL void wildmiss(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { int compat; /* no map_invisible() -- no way to tell where _this_ is coming from */ if (!flags.verbose) return; if (!cansee(mtmp->mx, mtmp->my)) return; /* maybe it's attacking an image around the corner? */ compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) && could_seduce(mtmp, &youmonst, (struct attack *) 0)); if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { const char *swings = mattk->aatyp == AT_BITE ? "snaps" : mattk->aatyp == AT_KICK ? "kicks" : (mattk->aatyp == AT_STNG || mattk->aatyp == AT_BUTT || nolimbs(mtmp->data)) ? "lunges" : "swings"; if (compat) pline("%s tries to touch you and misses!", Monnam(mtmp)); else switch (rn2(3)) { case 0: pline("%s %s wildly and misses!", Monnam(mtmp), swings); break; case 1: pline("%s attacks a spot beside you.", Monnam(mtmp)); break; case 2: pline("%s strikes at %s!", Monnam(mtmp), levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); break; default: pline("%s %s wildly!", Monnam(mtmp), swings); break; } } else if (Displaced) { if (compat) pline("%s smiles %s at your %sdisplaced image...", Monnam(mtmp), compat == 2 ? "engagingly" : "seductively", Invis ? "invisible " : ""); else pline("%s strikes at your %sdisplaced image and misses you!", /* Note: if you're both invisible and displaced, * only monsters which see invisible will attack your * displaced image, since the displaced image is also * invisible. */ Monnam(mtmp), Invis ? "invisible " : ""); } else if (Underwater) { /* monsters may miss especially on water level where bubbles shake the player here and there */ if (compat) pline("%s reaches towards your distorted image.", Monnam(mtmp)); else pline("%s is fooled by water reflections and misses!", Monnam(mtmp)); } else impossible("%s attacks you without knowing your location?", Monnam(mtmp)); } void expels(mtmp, mdat, message) struct monst *mtmp; struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */ boolean message; { if (message) { if (is_animal(mdat)) You("get regurgitated!"); else { char blast[40]; register int i; blast[0] = '\0'; for (i = 0; i < NATTK; i++) if (mdat->mattk[i].aatyp == AT_ENGL) break; if (mdat->mattk[i].aatyp != AT_ENGL) impossible("Swallower has no engulfing attack?"); else { if (is_whirly(mdat)) { switch (mdat->mattk[i].adtyp) { case AD_ELEC: Strcpy(blast, " in a shower of sparks"); break; case AD_COLD: Strcpy(blast, " in a blast of frost"); break; } } else Strcpy(blast, " with a squelch"); You("get expelled from %s%s!", mon_nam(mtmp), blast); } } } unstuck(mtmp); /* ball&chain returned in unstuck() */ mnexto(mtmp); newsym(u.ux, u.uy); spoteffects(TRUE); /* to cover for a case where mtmp is not in a next square */ if (um_dist(mtmp->mx, mtmp->my, 1)) pline("Brrooaa... You land hard at some distance."); } /* select a monster's next attack, possibly substituting for its usual one */ struct attack * getmattk(mptr, indx, prev_result, alt_attk_buf) struct permonst *mptr; int indx, prev_result[]; struct attack *alt_attk_buf; { struct attack *attk = &mptr->mattk[indx]; /* prevent a monster with two consecutive disease or hunger attacks from hitting with both of them on the same turn; if the first has already hit, switch to a stun attack for the second */ if (indx > 0 && prev_result[indx - 1] > 0 && (attk->adtyp == AD_DISE || attk->adtyp == AD_PEST || attk->adtyp == AD_FAMN) && attk->adtyp == mptr->mattk[indx - 1].adtyp) { *alt_attk_buf = *attk; attk = alt_attk_buf; attk->adtyp = AD_STUN; } return attk; } /* * mattacku: monster attacks you * returns 1 if monster dies (e.g. "yellow light"), 0 otherwise * Note: if you're displaced or invisible the monster might attack the * wrong position... * Assumption: it's attacking you or an empty square; if there's another * monster which it attacks by mistake, the caller had better * take care of it... */ int mattacku(mtmp) register struct monst *mtmp; { struct attack *mattk, alt_attk; int i, j, tmp, sum[NATTK]; struct permonst *mdat = mtmp->data; boolean ranged = (distu(mtmp->mx, mtmp->my) > 3); /* Is it near you? Affects your actions */ boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy); /* Does it think it's near you? Affects its actions */ boolean foundyou = (mtmp->mux == u.ux && mtmp->muy == u.uy); /* Is it attacking you or your image? */ boolean youseeit = canseemon(mtmp); /* Might be attacking your image around the corner, or * invisible, or you might be blind.... */ boolean skipnonmagc = FALSE; /* Are further physical attack attempts useless? */ if (!ranged) nomul(0); if (mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data))) return 0; /* If swallowed, can only be affected by u.ustuck */ if (u.uswallow) { if (mtmp != u.ustuck) return 0; u.ustuck->mux = u.ux; u.ustuck->muy = u.uy; range2 = 0; foundyou = 1; if (u.uinvulnerable) return 0; /* stomachs can't hurt you! */ } else if (u.usteed) { if (mtmp == u.usteed) /* Your steed won't attack you */ return 0; /* Orcs like to steal and eat horses and the like */ if (!rn2(is_orc(mtmp->data) ? 2 : 4) && distu(mtmp->mx, mtmp->my) <= 2) { /* Attack your steed instead */ i = mattackm(mtmp, u.usteed); if ((i & MM_AGR_DIED)) return 1; /* make sure steed is still alive and within range */ if ((i & MM_DEF_DIED) || !u.usteed || distu(mtmp->mx, mtmp->my) > 2) return 0; /* Let your steed retaliate */ return !!(mattackm(u.usteed, mtmp) & MM_DEF_DIED); } } if (u.uundetected && !range2 && foundyou && !u.uswallow) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); u.uundetected = 0; if (is_hider(youmonst.data) && u.umonnum != PM_TRAPPER) { /* ceiling hider */ coord cc; /* maybe we need a unexto() function? */ struct obj *obj; You("fall from the %s!", ceiling(u.ux, u.uy)); /* take monster off map now so that its location is eligible for placing hero; we assume that a removed monster remembers its old spot */ remove_monster(mtmp->mx, mtmp->my); if (!enexto(&cc, u.ux, u.uy, youmonst.data) /* a fish won't voluntarily swap positions when it's in water and hero is over land */ || (mtmp->data->mlet == S_EEL && is_pool(mtmp->mx, mtmp->my) && !is_pool(u.ux, u.uy))) { /* couldn't find any spot for hero; this used to kill off attacker, but now we just give a "miss" message and keep both mtmp and hero at their original positions; hero has become unconcealed so mtmp's next move will be a regular attack */ place_monster(mtmp, mtmp->mx, mtmp->my); /* put back */ newsym(u.ux, u.uy); /* u.uundetected was toggled */ pline("%s draws back as you drop!", Monnam(mtmp)); return 0; } /* put mtmp at hero's spot and move hero to */ newsym(mtmp->mx, mtmp->my); /* finish removal */ place_monster(mtmp, u.ux, u.uy); if (mtmp->wormno) { worm_move(mtmp); /* tail hasn't grown, so if it now occupies then one of its original spots must be free */ if (m_at(cc.x, cc.y)) (void) enexto(&cc, u.ux, u.uy, youmonst.data); } teleds(cc.x, cc.y, TRUE); /* move hero */ set_apparxy(mtmp); newsym(u.ux, u.uy); if (youmonst.data->mlet != S_PIERCER) return 0; /* lurkers don't attack */ obj = which_armor(mtmp, WORN_HELMET); if (obj && is_metallic(obj)) { Your("blow glances off %s %s.", s_suffix(mon_nam(mtmp)), helm_simple_name(obj)); } else { if (3 + find_mac(mtmp) <= rnd(20)) { pline("%s is hit by a falling piercer (you)!", Monnam(mtmp)); if ((mtmp->mhp -= d(3, 6)) < 1) killed(mtmp); } else pline("%s is almost hit by a falling piercer (you)!", Monnam(mtmp)); } } else { /* surface hider */ if (!youseeit) { pline("It tries to move where you are hiding."); } else { /* Ugly kludge for eggs. The message is phrased so as * to be directed at the monster, not the player, * which makes "laid by you" wrong. For the * parallelism to work, we can't rephrase it, so we * zap the "laid by you" momentarily instead. */ struct obj *obj = level.objects[u.ux][u.uy]; if (obj || u.umonnum == PM_TRAPPER || (youmonst.data->mlet == S_EEL && is_pool(u.ux, u.uy))) { int save_spe = 0; /* suppress warning */ if (obj) { save_spe = obj->spe; if (obj->otyp == EGG) obj->spe = 0; } if (youmonst.data->mlet == S_EEL || u.umonnum == PM_TRAPPER) pline( "Wait, %s! There's a hidden %s named %s there!", m_monnam(mtmp), youmonst.data->mname, plname); else pline( "Wait, %s! There's a %s named %s hiding under %s!", m_monnam(mtmp), youmonst.data->mname, plname, doname(level.objects[u.ux][u.uy])); if (obj) obj->spe = save_spe; } else impossible("hiding under nothing?"); } newsym(u.ux, u.uy); } return 0; } /* hero might be a mimic, concealed via #monster */ if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type && !range2 && foundyou && !u.uswallow) { boolean sticky = sticks(youmonst.data); if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); if (sticky && !youseeit) pline("It gets stuck on you."); else pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp), youmonst.data->mname, plname); if (sticky) u.ustuck = mtmp; youmonst.m_ap_type = M_AP_NOTHING; youmonst.mappearance = 0; newsym(u.ux, u.uy); return 0; } /* non-mimic hero might be mimicking an object after eating m corpse */ if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); if (!youseeit) pline("%s %s!", Something, (likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ? "tries to pick you up" : "disturbs you"); else pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp), mimic_obj_name(&youmonst), an(mons[u.umonnum].mname), plname); if (multi < 0) { /* this should always be the case */ char buf[BUFSZ]; Sprintf(buf, "You appear to be %s again.", Upolyd ? (const char *) an(youmonst.data->mname) : (const char *) "yourself"); unmul(buf); /* immediately stop mimicking */ } return 0; } /* Work out the armor class differential */ tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */ tmp += mtmp->m_lev; if (multi < 0) tmp += 4; if ((Invis && !perceives(mdat)) || !mtmp->mcansee) tmp -= 2; if (mtmp->mtrapped) tmp -= 2; if (tmp <= 0) tmp = 1; /* make eels visible the moment they hit/miss us */ if (mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx, mtmp->my)) { mtmp->minvis = 0; newsym(mtmp->mx, mtmp->my); } /* Special demon handling code */ if ((mtmp->cham == NON_PM) && is_demon(mdat) && !range2 && mtmp->data != &mons[PM_BALROG] && mtmp->data != &mons[PM_SUCCUBUS] && mtmp->data != &mons[PM_INCUBUS]) if (!mtmp->mcan && !rn2(13)) (void) msummon(mtmp); /* Special lycanthrope handling code */ if ((mtmp->cham == NON_PM) && is_were(mdat) && !range2) { if (is_human(mdat)) { if (!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp); } else if (!rn2(30) && !mtmp->mcan) new_were(mtmp); mdat = mtmp->data; if (!rn2(10) && !mtmp->mcan) { int numseen, numhelp; char buf[BUFSZ], genericwere[BUFSZ]; Strcpy(genericwere, "creature"); numhelp = were_summon(mdat, FALSE, &numseen, genericwere); if (youseeit) { pline("%s summons help!", Monnam(mtmp)); if (numhelp > 0) { if (numseen == 0) You_feel("hemmed in."); } else pline("But none comes."); } else { const char *from_nowhere; if (!Deaf) { pline("%s %s!", Something, makeplural(growl_sound(mtmp))); from_nowhere = ""; } else from_nowhere = " from nowhere"; if (numhelp > 0) { if (numseen < 1) You_feel("hemmed in."); else { if (numseen == 1) Sprintf(buf, "%s appears", an(genericwere)); else Sprintf(buf, "%s appear", makeplural(genericwere)); pline("%s%s!", upstart(buf), from_nowhere); } } /* else no help came; but you didn't know it tried */ } } } if (u.uinvulnerable) { /* monsters won't attack you */ if (mtmp == u.ustuck) pline("%s loosens its grip slightly.", Monnam(mtmp)); else if (!range2) { if (youseeit || sensemon(mtmp)) pline("%s starts to attack you, but pulls back.", Monnam(mtmp)); else You_feel("%s move nearby.", something); } return 0; } /* Unlike defensive stuff, don't let them use item _and_ attack. */ if (find_offensive(mtmp)) { int foo = use_offensive(mtmp); if (foo != 0) return (foo == 1); } for (i = 0; i < NATTK; i++) { sum[i] = 0; mattk = getmattk(mdat, i, sum, &alt_attk); if ((u.uswallow && mattk->aatyp != AT_ENGL) || (skipnonmagc && mattk->aatyp != AT_MAGC)) continue; switch (mattk->aatyp) { case AT_CLAW: /* "hand to hand" attacks */ case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: case AT_TENT: if (!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict || !touch_petrifies(youmonst.data))) { if (foundyou) { if (tmp > (j = rnd(20 + i))) { if (mattk->aatyp != AT_KICK || !thick_skinned(youmonst.data)) sum[i] = hitmu(mtmp, mattk); } else missmu(mtmp, (tmp == j), mattk); } else { wildmiss(mtmp, mattk); /* skip any remaining non-spell attacks */ skipnonmagc = TRUE; } } break; case AT_HUGS: /* automatic if prev two attacks succeed */ /* Note: if displaced, prev attacks never succeeded */ if ((!range2 && i >= 2 && sum[i - 1] && sum[i - 2]) || mtmp == u.ustuck) sum[i] = hitmu(mtmp, mattk); break; case AT_GAZE: /* can affect you either ranged or not */ /* Medusa gaze already operated through m_respond in dochug(); don't gaze more than once per round. */ if (mdat != &mons[PM_MEDUSA]) sum[i] = gazemu(mtmp, mattk); break; case AT_EXPL: /* automatic hit if next to, and aimed at you */ if (!range2) sum[i] = explmu(mtmp, mattk, foundyou); break; case AT_ENGL: if (!range2) { if (foundyou) { if (u.uswallow || tmp > (j = rnd(20 + i))) { /* Force swallowing monster to be * displayed even when player is * moving away */ flush_screen(1); sum[i] = gulpmu(mtmp, mattk); } else { missmu(mtmp, (tmp == j), mattk); } } else if (is_animal(mtmp->data)) { pline("%s gulps some air!", Monnam(mtmp)); } else { if (youseeit) pline("%s lunges forward and recoils!", Monnam(mtmp)); else You_hear("a %s nearby.", is_whirly(mtmp->data) ? "rushing noise" : "splat"); } } break; case AT_BREA: if (range2) sum[i] = breamu(mtmp, mattk); /* Note: breamu takes care of displacement */ break; case AT_SPIT: if (range2) sum[i] = spitmu(mtmp, mattk); /* Note: spitmu takes care of displacement */ break; case AT_WEAP: if (range2) { if (!Is_rogue_level(&u.uz)) thrwmu(mtmp); } else { int hittmp = 0; /* Rare but not impossible. Normally the monster * wields when 2 spaces away, but it can be * teleported or whatever.... */ if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { mtmp->weapon_check = NEED_HTH_WEAPON; /* mon_wield_item resets weapon_check as appropriate */ if (mon_wield_item(mtmp) != 0) break; } if (foundyou) { otmp = MON_WEP(mtmp); if (otmp) { hittmp = hitval(otmp, &youmonst); tmp += hittmp; mswings(mtmp, otmp); } if (tmp > (j = dieroll = rnd(20 + i))) sum[i] = hitmu(mtmp, mattk); else missmu(mtmp, (tmp == j), mattk); /* KMH -- Don't accumulate to-hit bonuses */ if (otmp) tmp -= hittmp; } else { wildmiss(mtmp, mattk); /* skip any remaining non-spell attacks */ skipnonmagc = TRUE; } } break; case AT_MAGC: if (range2) sum[i] = buzzmu(mtmp, mattk); else sum[i] = castmu(mtmp, mattk, TRUE, foundyou); break; default: /* no attack */ break; } if (context.botl) bot(); /* give player a chance of waking up before dying -kaa */ if (sum[i] == 1) { /* successful attack */ if (u.usleep && u.usleep < monstermoves && !rn2(10)) { multi = -1; nomovemsg = "The combat suddenly awakens you."; } } if (sum[i] == 2) return 1; /* attacker dead */ if (sum[i] == 3) break; /* attacker teleported, no more attacks */ /* sum[i] == 0: unsuccessful attack */ } return 0; } STATIC_OVL boolean diseasemu(mdat) struct permonst *mdat; { if (Sick_resistance) { You_feel("a slight illness."); return FALSE; } else { make_sick(Sick ? Sick / 3L + 1L : (long) rn1(ACURR(A_CON), 20), mdat->mname, TRUE, SICK_NONVOMITABLE); return TRUE; } } /* check whether slippery clothing protects from hug or wrap attack */ STATIC_OVL boolean u_slip_free(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { struct obj *obj = (uarmc ? uarmc : uarm); if (!obj) obj = uarmu; if (mattk->adtyp == AD_DRIN) obj = uarmh; /* if your cloak/armor is greased, monster slips off; this protection might fail (33% chance) when the armor is cursed */ if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) && (!obj->cursed || rn2(3))) { pline("%s %s your %s %s!", Monnam(mtmp), (mattk->adtyp == AD_WRAP) ? "slips off of" : "grabs you, but cannot hold onto", obj->greased ? "greased" : "slippery", /* avoid "slippery slippery cloak" for undiscovered oilskin cloak */ (obj->greased || objects[obj->otyp].oc_name_known) ? xname(obj) : cloak_simple_name(obj)); if (obj->greased && !rn2(2)) { pline_The("grease wears off."); obj->greased = 0; update_inventory(); } return TRUE; } return FALSE; } /* armor that sufficiently covers the body might be able to block magic */ int magic_negation(mon) struct monst *mon; { struct obj *o; long wearmask; int armpro, mc = 0; boolean is_you = (mon == &youmonst), gotprot = is_you ? (EProtection != 0L) /* high priests have innate protection */ : (mon->data == &mons[PM_HIGH_PRIEST]); for (o = is_you ? invent : mon->minvent; o; o = o->nobj) { /* a_can field is only applicable for armor (which must be worn) */ if ((o->owornmask & W_ARMOR) != 0L) { armpro = objects[o->otyp].a_can; if (armpro > mc) mc = armpro; } /* if we've already confirmed Protection, skip additional checks */ if (is_you || gotprot) continue; /* omit W_SWAPWEP+W_QUIVER; W_ART+W_ARTI handled by protects() */ wearmask = W_ARMOR | W_ACCESSORY; if (o->oclass == WEAPON_CLASS || is_weptool(o)) wearmask |= W_WEP; if (protects(o, ((o->owornmask & wearmask) != 0L) ? TRUE : FALSE)) gotprot = TRUE; } if (gotprot) { /* extrinsic Protection increases mc by 1 */ if (mc < 3) mc += 1; } else if (mc < 1) { /* intrinsic Protection is weaker (play balance; obtaining divine protection is too easy); it confers minimum mc 1 instead of 0 */ if ((is_you && ((HProtection && u.ublessed) || u.uspellprot)) /* aligned priests and angels have innate intrinsic Protection */ || (mon->data == &mons[PM_ALIGNED_PRIEST] || is_minion(mon->data))) mc = 1; } return mc; } /* * hitmu: monster hits you * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise * 3 if the monster lives but teleported/paralyzed, so it can't keep * attacking you */ STATIC_OVL int hitmu(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { register struct permonst *mdat = mtmp->data; register int uncancelled, ptmp; int dmg, armpro, permdmg; char buf[BUFSZ]; struct permonst *olduasmon = youmonst.data; int res; if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); /* If the monster is undetected & hits you, you should know where * the attack came from. */ if (mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) { mtmp->mundetected = 0; if (!(Blind ? Blind_telepat : Unblind_telepat)) { struct obj *obj; const char *what; if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) { if (Blind && !obj->dknown) what = something; else if (is_pool(mtmp->mx, mtmp->my) && !Underwater) what = "the water"; else what = doname(obj); pline("%s was hidden under %s!", Amonnam(mtmp), what); } newsym(mtmp->mx, mtmp->my); } } /* First determine the base damage done */ dmg = d((int) mattk->damn, (int) mattk->damd); if ((is_undead(mdat) || is_vampshifter(mtmp)) && midnight()) dmg += d((int) mattk->damn, (int) mattk->damd); /* extra damage */ /* Next a cancellation factor. * Use uncancelled when cancellation factor takes into account certain * armor's special magic protection. Otherwise just use !mtmp->mcan. */ armpro = magic_negation(&youmonst); uncancelled = !mtmp->mcan && (rn2(10) >= 3 * armpro); permdmg = 0; /* Now, adjust damages via resistances or specific attacks */ switch (mattk->adtyp) { case AD_PHYS: if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) { if (!u.ustuck && rn2(2)) { if (u_slip_free(mtmp, mattk)) { dmg = 0; } else { u.ustuck = mtmp; pline("%s grabs you!", Monnam(mtmp)); } } else if (u.ustuck == mtmp) { exercise(A_STR, FALSE); You("are being %s.", (mtmp->data == &mons[PM_ROPE_GOLEM]) ? "choked" : "crushed"); } } else { /* hand to hand weapon */ if (mattk->aatyp == AT_WEAP && otmp) { int tmp; if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) { dmg = 1; pline("%s hits you with the %s corpse.", Monnam(mtmp), mons[otmp->corpsenm].mname); if (!Stoned) goto do_stone; } dmg += dmgval(otmp, &youmonst); if (dmg <= 0) dmg = 1; if (!(otmp->oartifact && artifact_hit(mtmp, &youmonst, otmp, &dmg, dieroll))) hitmsg(mtmp, mattk); if (!dmg) break; if (objects[otmp->otyp].oc_material == SILVER && Hate_silver) { pline_The("silver sears your flesh!"); exercise(A_CON, FALSE); } /* this redundancy necessary because you have to take the damage _before_ being cloned; need to have at least 2 hp left to split */ tmp = dmg; if (u.uac < 0) tmp -= rnd(-u.uac); if (tmp < 1) tmp = 1; if (u.mh - tmp > 1 && objects[otmp->otyp].oc_material == IRON && (u.umonnum == PM_BLACK_PUDDING || u.umonnum == PM_BROWN_PUDDING)) { if (tmp > 1) exercise(A_STR, FALSE); /* inflict damage now; we know it can't be fatal */ u.mh -= tmp; context.botl = 1; dmg = 0; /* don't inflict more damage below */ if (cloneu()) You("divide as %s hits you!", mon_nam(mtmp)); } rustm(&youmonst, otmp); } else if (mattk->aatyp != AT_TUCH || dmg != 0 || mtmp != u.ustuck) hitmsg(mtmp, mattk); } break; case AD_DISE: hitmsg(mtmp, mattk); if (!diseasemu(mdat)) dmg = 0; break; case AD_FIRE: hitmsg(mtmp, mattk); if (uncancelled) { pline("You're %s!", on_fire(youmonst.data, mattk)); if (youmonst.data == &mons[PM_STRAW_GOLEM] || youmonst.data == &mons[PM_PAPER_GOLEM]) { You("roast!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } else if (Fire_resistance) { pline_The("fire doesn't feel hot!"); dmg = 0; } if ((int) mtmp->m_lev > rn2(20)) destroy_item(SCROLL_CLASS, AD_FIRE); if ((int) mtmp->m_lev > rn2(20)) destroy_item(POTION_CLASS, AD_FIRE); if ((int) mtmp->m_lev > rn2(25)) destroy_item(SPBOOK_CLASS, AD_FIRE); burn_away_slime(); } else dmg = 0; break; case AD_COLD: hitmsg(mtmp, mattk); if (uncancelled) { pline("You're covered in frost!"); if (Cold_resistance) { pline_The("frost doesn't seem cold!"); dmg = 0; } if ((int) mtmp->m_lev > rn2(20)) destroy_item(POTION_CLASS, AD_COLD); } else dmg = 0; break; case AD_ELEC: hitmsg(mtmp, mattk); if (uncancelled) { You("get zapped!"); if (Shock_resistance) { pline_The("zap doesn't shock you!"); dmg = 0; } if ((int) mtmp->m_lev > rn2(20)) destroy_item(WAND_CLASS, AD_ELEC); if ((int) mtmp->m_lev > rn2(20)) destroy_item(RING_CLASS, AD_ELEC); } else dmg = 0; break; case AD_SLEE: hitmsg(mtmp, mattk); if (uncancelled && multi >= 0 && !rn2(5)) { if (Sleep_resistance) break; fall_asleep(-rnd(10), TRUE); if (Blind) You("are put to sleep!"); else You("are put to sleep by %s!", mon_nam(mtmp)); } break; case AD_BLND: if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) { if (!Blind) pline("%s blinds you!", Monnam(mtmp)); make_blinded(Blinded + (long) dmg, FALSE); if (!Blind) Your1(vision_clears); } dmg = 0; break; case AD_DRST: ptmp = A_STR; goto dopois; case AD_DRDX: ptmp = A_DEX; goto dopois; case AD_DRCO: ptmp = A_CON; dopois: hitmsg(mtmp, mattk); if (uncancelled && !rn2(8)) { Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk)); poisoned(buf, ptmp, mdat->mname, 30, FALSE); } break; case AD_DRIN: hitmsg(mtmp, mattk); if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) { You("don't seem harmed."); /* Not clear what to do for green slimes */ break; } if (u_slip_free(mtmp, mattk)) break; if (uarmh && rn2(8)) { /* not body_part(HEAD) */ Your("%s blocks the attack to your head.", helm_simple_name(uarmh)); break; } if (Half_physical_damage) dmg = (dmg + 1) / 2; mdamageu(mtmp, dmg); if (!uarmh || uarmh->otyp != DUNCE_CAP) { /* eat_brains() will miss if target is mindless (won't happen here; hero is considered to retain his mind regardless of current shape) or is noncorporeal (can't happen here; no one can poly into a ghost or shade) so this check for missing is academic */ if (eat_brains(mtmp, &youmonst, TRUE, (int *) 0) == MM_MISS) break; } /* adjattrib gives dunce cap message when appropriate */ (void) adjattrib(A_INT, -rnd(2), FALSE); forget_levels(25); /* lose memory of 25% of levels */ forget_objects(25); /* lose memory of 25% of objects */ break; case AD_PLYS: hitmsg(mtmp, mattk); if (uncancelled && multi >= 0 && !rn2(3)) { if (Free_action) { You("momentarily stiffen."); } else { if (Blind) You("are frozen!"); else You("are frozen by %s!", mon_nam(mtmp)); nomovemsg = You_can_move_again; nomul(-rnd(10)); multi_reason = "paralyzed by a monster"; exercise(A_DEX, FALSE); } } break; case AD_DRLI: hitmsg(mtmp, mattk); if (uncancelled && !rn2(3) && !Drain_resistance) { losexp("life drainage"); } break; case AD_LEGS: { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left"; /* This case is too obvious to ignore, but Nethack is not in * general very good at considering height--most short monsters * still _can_ attack you when you're flying or mounted. * [FIXME: why can't a flying attacker overcome this?] */ if (u.usteed || Levitation || Flying) { pline("%s tries to reach your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); dmg = 0; } else if (mtmp->mcan) { pline("%s nuzzles against your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); dmg = 0; } else { if (uarmf) { if (rn2(2) && (uarmf->otyp == LOW_BOOTS || uarmf->otyp == IRON_SHOES)) pline("%s pricks the exposed part of your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); else if (!rn2(5)) pline("%s pricks through your %s boot!", Monnam(mtmp), sidestr); else { pline("%s scratches your %s boot!", Monnam(mtmp), sidestr); dmg = 0; break; } } else pline("%s pricks your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); set_wounded_legs(side, rnd(60 - ACURR(A_DEX))); exercise(A_STR, FALSE); exercise(A_DEX, FALSE); } break; } case AD_STON: /* cockatrice */ hitmsg(mtmp, mattk); if (!rn2(3)) { if (mtmp->mcan) { if (!Deaf) You_hear("a cough from %s!", mon_nam(mtmp)); } else { if (!Deaf) You_hear("%s hissing!", s_suffix(mon_nam(mtmp))); if (!rn2(10) || (flags.moonphase == NEW_MOON && !have_lizard())) { do_stone: if (!Stoned && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { int kformat = KILLED_BY_AN; const char *kname = mtmp->data->mname; if (mtmp->data->geno & G_UNIQ) { if (!type_is_pname(mtmp->data)) kname = the(kname); kformat = KILLED_BY; } make_stoned(5L, (char *) 0, kformat, kname); return 1; /* done_in_by(mtmp, STONING); */ } } } } break; case AD_STCK: hitmsg(mtmp, mattk); if (uncancelled && !u.ustuck && !sticks(youmonst.data)) u.ustuck = mtmp; break; case AD_WRAP: if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) { if (!u.ustuck && !rn2(10)) { if (u_slip_free(mtmp, mattk)) { dmg = 0; } else { pline("%s swings itself around you!", Monnam(mtmp)); u.ustuck = mtmp; } } else if (u.ustuck == mtmp) { if (is_pool(mtmp->mx, mtmp->my) && !Swimming && !Amphibious) { boolean moat = (levl[mtmp->mx][mtmp->my].typ != POOL) && (levl[mtmp->mx][mtmp->my].typ != WATER) && !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz); pline("%s drowns you...", Monnam(mtmp)); killer.format = KILLED_BY_AN; Sprintf(killer.name, "%s by %s", moat ? "moat" : "pool of water", an(mtmp->data->mname)); done(DROWNING); } else if (mattk->aatyp == AT_HUGS) You("are being crushed."); } else { dmg = 0; if (flags.verbose) pline("%s brushes against your %s.", Monnam(mtmp), body_part(LEG)); } } else dmg = 0; break; case AD_WERE: hitmsg(mtmp, mattk); if (uncancelled && !rn2(4) && u.ulycn == NON_PM && !Protection_from_shape_changers && !defends(AD_WERE, uwep)) { You_feel("feverish."); exercise(A_CON, FALSE); u.ulycn = monsndx(mdat); retouch_equipment(2); } break; case AD_SGLD: hitmsg(mtmp, mattk); if (youmonst.data->mlet == mdat->mlet) break; if (!mtmp->mcan) stealgold(mtmp); break; case AD_SSEX: if (SYSOPT_SEDUCE) { if (could_seduce(mtmp, &youmonst, mattk) == 1 && !mtmp->mcan) if (doseduce(mtmp)) return 3; break; } /* else FALLTHRU */ case AD_SITM: /* for now these are the same */ case AD_SEDU: if (is_animal(mtmp->data)) { hitmsg(mtmp, mattk); if (mtmp->mcan) break; /* Continue below */ } else if (dmgtype(youmonst.data, AD_SEDU) || (SYSOPT_SEDUCE && dmgtype(youmonst.data, AD_SSEX))) { pline("%s %s.", Monnam(mtmp), mtmp->minvent ? "brags about the goods some dungeon explorer provided" : "makes some remarks about how difficult theft is lately"); if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); return 3; } else if (mtmp->mcan) { if (!Blind) { pline("%s tries to %s you, but you seem %s.", Adjmonnam(mtmp, "plain"), flags.female ? "charm" : "seduce", flags.female ? "unaffected" : "uninterested"); } if (rn2(3)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); return 3; } break; } buf[0] = '\0'; switch (steal(mtmp, buf)) { case -1: return 2; case 0: break; default: if (!is_animal(mtmp->data) && !tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); if (is_animal(mtmp->data) && *buf) { if (canseemon(mtmp)) pline("%s tries to %s away with %s.", Monnam(mtmp), locomotion(mtmp->data, "run"), buf); } monflee(mtmp, 0, FALSE, FALSE); return 3; } break; case AD_SAMU: hitmsg(mtmp, mattk); /* when the Wiz hits, 1/20 steals the amulet */ if (u.uhave.amulet || u.uhave.bell || u.uhave.book || u.uhave.menorah || u.uhave.questart) /* carrying the Quest Artifact */ if (!rn2(20)) stealamulet(mtmp); break; case AD_TLPT: hitmsg(mtmp, mattk); if (uncancelled) { if (flags.verbose) Your("position suddenly seems very uncertain!"); tele(); } break; case AD_RUST: hitmsg(mtmp, mattk); if (mtmp->mcan) break; if (u.umonnum == PM_IRON_GOLEM) { You("rust!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } erode_armor(&youmonst, ERODE_RUST); break; case AD_CORR: hitmsg(mtmp, mattk); if (mtmp->mcan) break; erode_armor(&youmonst, ERODE_CORRODE); break; case AD_DCAY: hitmsg(mtmp, mattk); if (mtmp->mcan) break; if (u.umonnum == PM_WOOD_GOLEM || u.umonnum == PM_LEATHER_GOLEM) { You("rot!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } erode_armor(&youmonst, ERODE_ROT); break; case AD_HEAL: /* a cancelled nurse is just an ordinary monster, * nurses don't heal those that cause petrification */ if (mtmp->mcan || (Upolyd && touch_petrifies(youmonst.data))) { hitmsg(mtmp, mattk); break; } if (!uwep && !uarmu && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) { boolean goaway = FALSE; pline("%s hits! (I hope you don't mind.)", Monnam(mtmp)); if (Upolyd) { u.mh += rnd(7); if (!rn2(7)) { /* no upper limit necessary; effect is temporary */ u.mhmax++; if (!rn2(13)) goaway = TRUE; } if (u.mh > u.mhmax) u.mh = u.mhmax; } else { u.uhp += rnd(7); if (!rn2(7)) { /* hard upper limit via nurse care: 25 * ulevel */ if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10)) u.uhpmax++; if (!rn2(13)) goaway = TRUE; } if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; } if (!rn2(3)) exercise(A_STR, TRUE); if (!rn2(3)) exercise(A_CON, TRUE); if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL); context.botl = 1; if (goaway) { mongone(mtmp); return 2; } else if (!rn2(33)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); monflee(mtmp, d(3, 6), TRUE, FALSE); return 3; } dmg = 0; } else { if (Role_if(PM_HEALER)) { if (!Deaf && !(moves % 5)) verbalize("Doc, I can't help you unless you cooperate."); dmg = 0; } else hitmsg(mtmp, mattk); } break; case AD_CURS: hitmsg(mtmp, mattk); if (!night() && mdat == &mons[PM_GREMLIN]) break; if (!mtmp->mcan && !rn2(10)) { if (!Deaf) { if (Blind) You_hear("laughter."); else pline("%s chuckles.", Monnam(mtmp)); } if (u.umonnum == PM_CLAY_GOLEM) { pline("Some writing vanishes from your head!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } attrcurse(); } break; case AD_STUN: hitmsg(mtmp, mattk); if (!mtmp->mcan && !rn2(4)) { make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE); dmg /= 2; } break; case AD_ACID: hitmsg(mtmp, mattk); if (!mtmp->mcan && !rn2(3)) if (Acid_resistance) { pline("You're covered in acid, but it seems harmless."); dmg = 0; } else { pline("You're covered in acid! It burns!"); exercise(A_STR, FALSE); } else dmg = 0; break; case AD_SLOW: hitmsg(mtmp, mattk); if (uncancelled && HFast && !defends(AD_SLOW, uwep) && !rn2(4)) u_slow_down(); break; case AD_DREN: hitmsg(mtmp, mattk); if (uncancelled && !rn2(4)) drain_en(dmg); dmg = 0; break; case AD_CONF: hitmsg(mtmp, mattk); if (!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) { mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6)); if (Confusion) You("are getting even more confused."); else You("are getting confused."); make_confused(HConfusion + dmg, FALSE); } dmg = 0; break; case AD_DETH: pline("%s reaches out with its deadly touch.", Monnam(mtmp)); if (is_undead(youmonst.data)) { /* Still does normal damage */ pline("Was that the touch of death?"); break; } switch (rn2(20)) { case 19: case 18: case 17: if (!Antimagic) { killer.format = KILLED_BY_AN; Strcpy(killer.name, "touch of death"); done(DIED); dmg = 0; break; } /* else FALLTHRU */ default: /* case 16: ... case 5: */ You_feel("your life force draining away..."); permdmg = 1; /* actual damage done below */ break; case 4: case 3: case 2: case 1: case 0: if (Antimagic) shieldeff(u.ux, u.uy); pline("Lucky for you, it didn't work!"); dmg = 0; break; } break; case AD_PEST: pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp)); (void) diseasemu(mdat); /* plus the normal damage */ break; case AD_FAMN: pline("%s reaches out, and your body shrivels.", Monnam(mtmp)); exercise(A_CON, FALSE); if (!is_fainted()) morehungry(rn1(40, 40)); /* plus the normal damage */ break; case AD_SLIM: hitmsg(mtmp, mattk); if (!uncancelled) break; if (flaming(youmonst.data)) { pline_The("slime burns away!"); dmg = 0; } else if (Unchanging || noncorporeal(youmonst.data) || youmonst.data == &mons[PM_GREEN_SLIME]) { You("are unaffected."); dmg = 0; } else if (!Slimed) { You("don't feel very well."); make_slimed(10L, (char *) 0); delayed_killer(SLIMED, KILLED_BY_AN, mtmp->data->mname); } else pline("Yuck!"); break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ hitmsg(mtmp, mattk); /* uncancelled is sufficient enough; please don't make this attack less frequent */ if (uncancelled) { struct obj *obj = some_armor(&youmonst); if (drain_item(obj)) { pline("%s less effective.", Yobjnam2(obj, "seem")); } } break; default: dmg = 0; break; } if (u.uhp < 1) done_in_by(mtmp, DIED); /* Negative armor class reduces damage done instead of fully protecting * against hits. */ if (dmg && u.uac < 0) { dmg -= rnd(-u.uac); if (dmg < 1) dmg = 1; } if (dmg) { if (Half_physical_damage /* Mitre of Holiness */ || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) && (is_undead(mtmp->data) || is_demon(mtmp->data) || is_vampshifter(mtmp)))) dmg = (dmg + 1) / 2; if (permdmg) { /* Death's life force drain */ int lowerlimit, *hpmax_p; /* * Apply some of the damage to permanent hit points: * polymorphed 100% against poly'd hpmax * hpmax > 25*lvl 100% against normal hpmax * hpmax > 10*lvl 50..100% * hpmax > 5*lvl 25..75% * otherwise 0..50% * Never reduces hpmax below 1 hit point per level. */ permdmg = rn2(dmg / 2 + 1); if (Upolyd || u.uhpmax > 25 * u.ulevel) permdmg = dmg; else if (u.uhpmax > 10 * u.ulevel) permdmg += dmg / 2; else if (u.uhpmax > 5 * u.ulevel) permdmg += dmg / 4; if (Upolyd) { hpmax_p = &u.mhmax; /* [can't use youmonst.m_lev] */ lowerlimit = min((int) youmonst.data->mlevel, u.ulevel); } else { hpmax_p = &u.uhpmax; lowerlimit = u.ulevel; } if (*hpmax_p - permdmg > lowerlimit) *hpmax_p -= permdmg; else if (*hpmax_p > lowerlimit) *hpmax_p = lowerlimit; /* else unlikely... * already at or below minimum threshold; do nothing */ context.botl = 1; } mdamageu(mtmp, dmg); } if (dmg) res = passiveum(olduasmon, mtmp, mattk); else res = 1; stop_occupation(); return res; } /* An interface for use when taking a blindfold off, for example, * to see if an engulfing attack should immediately take affect, like * a passive attack. TRUE if engulfing blindness occurred */ boolean gulp_blnd_check() { struct attack *mattk; if (!Blinded && u.uswallow && (mattk = attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND)) && can_blnd(u.ustuck, &youmonst, mattk->aatyp, (struct obj *) 0)) { ++u.uswldtim; /* compensate for gulpmu change */ (void) gulpmu(u.ustuck, mattk); return TRUE; } return FALSE; } /* monster swallows you, or damage if u.uswallow */ STATIC_OVL int gulpmu(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { struct trap *t = t_at(u.ux, u.uy); int tmp = d((int) mattk->damn, (int) mattk->damd); int tim_tmp; register struct obj *otmp2; int i; boolean physical_damage = FALSE; if (!u.uswallow) { /* swallows you */ int omx = mtmp->mx, omy = mtmp->my; if (!engulf_target(mtmp, &youmonst)) return 0; if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) && sobj_at(BOULDER, u.ux, u.uy)) return 0; if (Punished) unplacebc(); /* ball&chain go away */ remove_monster(omx, omy); mtmp->mtrapped = 0; /* no longer on old trap */ place_monster(mtmp, u.ux, u.uy); u.ustuck = mtmp; newsym(mtmp->mx, mtmp->my); if (is_animal(mtmp->data) && u.usteed) { char buf[BUFSZ]; /* Too many quirks presently if hero and steed * are swallowed. Pretend purple worms don't * like horses for now :-) */ Strcpy(buf, mon_nam(u.usteed)); pline("%s lunges forward and plucks you off %s!", Monnam(mtmp), buf); dismount_steed(DISMOUNT_ENGULFED); } else pline("%s engulfs you!", Monnam(mtmp)); stop_occupation(); reset_occupations(); /* behave as if you had moved */ if (u.utrap) { You("are released from the %s!", u.utraptype == TT_WEB ? "web" : "trap"); u.utrap = 0; } i = number_leashed(); if (i > 0) { const char *s = (i > 1) ? "leashes" : "leash"; pline_The("%s %s loose.", s, vtense(s, "snap")); unleash_all(); } if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) { /* put the attacker back where it started; the resulting statue will end up there */ remove_monster(mtmp->mx, mtmp->my); /* u.ux,u.uy */ place_monster(mtmp, omx, omy); minstapetrify(mtmp, TRUE); /* normally unstuck() would do this, but we're not fully swallowed yet so that won't work here */ if (Punished) placebc(); u.ustuck = 0; return (mtmp->mhp > 0) ? 0 : 2; } display_nhwindow(WIN_MESSAGE, FALSE); vision_recalc(2); /* hero can't see anything */ u.uswallow = 1; /* for digestion, shorter time is more dangerous; for other swallowings, longer time means more chances for the swallower to attack */ if (mattk->adtyp == AD_DGST) { tim_tmp = 25 - (int) mtmp->m_lev; if (tim_tmp > 0) tim_tmp = rnd(tim_tmp) / 2; else if (tim_tmp < 0) tim_tmp = -(rnd(-tim_tmp) / 2); /* having good armor & high constitution makes it take longer for you to be digested, but you'll end up trapped inside for longer too */ tim_tmp += -u.uac + 10 + (ACURR(A_CON) / 3 - 1); } else { /* higher level attacker takes longer to eject hero */ tim_tmp = rnd((int) mtmp->m_lev + 10 / 2); } /* u.uswldtim always set > 1 */ u.uswldtim = (unsigned) ((tim_tmp < 2) ? 2 : tim_tmp); swallowed(1); for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj) (void) snuff_lit(otmp2); } if (mtmp != u.ustuck) return 0; if (u.uswldtim > 0) u.uswldtim -= 1; switch (mattk->adtyp) { case AD_DGST: physical_damage = TRUE; if (Slow_digestion) { /* Messages are handled below */ u.uswldtim = 0; tmp = 0; } else if (u.uswldtim == 0) { pline("%s totally digests you!", Monnam(mtmp)); tmp = u.uhp; if (Half_physical_damage) tmp *= 2; /* sorry */ } else { pline("%s%s digests you!", Monnam(mtmp), (u.uswldtim == 2) ? " thoroughly" : (u.uswldtim == 1) ? " utterly" : ""); exercise(A_STR, FALSE); } break; case AD_PHYS: physical_damage = TRUE; if (mtmp->data == &mons[PM_FOG_CLOUD]) { You("are laden with moisture and %s", flaming(youmonst.data) ? "are smoldering out!" : Breathless ? "find it mildly uncomfortable." : amphibious(youmonst.data) ? "feel comforted." : "can barely breathe!"); /* NB: Amphibious includes Breathless */ if (Amphibious && !flaming(youmonst.data)) tmp = 0; } else { You("are pummeled with debris!"); exercise(A_STR, FALSE); } break; case AD_ACID: if (Acid_resistance) { You("are covered with a seemingly harmless goo."); tmp = 0; } else { if (Hallucination) pline("Ouch! You've been slimed!"); else You("are covered in slime! It burns!"); exercise(A_STR, FALSE); } break; case AD_BLND: if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) { if (!Blind) { long was_blinded = Blinded; if (!Blinded) You_cant("see in here!"); make_blinded((long) tmp, FALSE); if (!was_blinded && !Blind) Your1(vision_clears); } else /* keep him blind until disgorged */ make_blinded(Blinded + 1, FALSE); } tmp = 0; break; case AD_ELEC: if (!mtmp->mcan && rn2(2)) { pline_The("air around you crackles with electricity."); if (Shock_resistance) { shieldeff(u.ux, u.uy); You("seem unhurt."); ugolemeffects(AD_ELEC, tmp); tmp = 0; } } else tmp = 0; break; case AD_COLD: if (!mtmp->mcan && rn2(2)) { if (Cold_resistance) { shieldeff(u.ux, u.uy); You_feel("mildly chilly."); ugolemeffects(AD_COLD, tmp); tmp = 0; } else You("are freezing to death!"); } else tmp = 0; break; case AD_FIRE: if (!mtmp->mcan && rn2(2)) { if (Fire_resistance) { shieldeff(u.ux, u.uy); You_feel("mildly hot."); ugolemeffects(AD_FIRE, tmp); tmp = 0; } else You("are burning to a crisp!"); burn_away_slime(); } else tmp = 0; break; case AD_DISE: if (!diseasemu(mtmp->data)) tmp = 0; break; case AD_DREN: /* AC magic cancellation doesn't help when engulfed */ if (!mtmp->mcan && rn2(4)) drain_en(tmp); tmp = 0; break; default: physical_damage = TRUE; tmp = 0; break; } if (physical_damage) tmp = Maybe_Half_Phys(tmp); mdamageu(mtmp, tmp); if (tmp) stop_occupation(); if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) { pline("%s very hurriedly %s you!", Monnam(mtmp), is_animal(mtmp->data) ? "regurgitates" : "expels"); expels(mtmp, mtmp->data, FALSE); } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) { You("get %s!", is_animal(mtmp->data) ? "regurgitated" : "expelled"); if (flags.verbose && (is_animal(mtmp->data) || (dmgtype(mtmp->data, AD_DGST) && Slow_digestion))) pline("Obviously %s doesn't like your taste.", mon_nam(mtmp)); expels(mtmp, mtmp->data, FALSE); } return 1; } /* monster explodes in your face */ STATIC_OVL int explmu(mtmp, mattk, ufound) register struct monst *mtmp; register struct attack *mattk; boolean ufound; { boolean physical_damage = TRUE, kill_agr = TRUE; if (mtmp->mcan) return 0; if (!ufound) pline("%s explodes at a spot in %s!", canseemon(mtmp) ? Monnam(mtmp) : "It", levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); else { register int tmp = d((int) mattk->damn, (int) mattk->damd); register boolean not_affected = defends((int) mattk->adtyp, uwep); hitmsg(mtmp, mattk); switch (mattk->adtyp) { case AD_COLD: physical_damage = FALSE; not_affected |= Cold_resistance; goto common; case AD_FIRE: physical_damage = FALSE; not_affected |= Fire_resistance; goto common; case AD_ELEC: physical_damage = FALSE; not_affected |= Shock_resistance; common: if (!not_affected) { if (ACURR(A_DEX) > rnd(20)) { You("duck some of the blast."); tmp = (tmp + 1) / 2; } else { if (flags.verbose) You("get blasted!"); } if (mattk->adtyp == AD_FIRE) burn_away_slime(); if (physical_damage) tmp = Maybe_Half_Phys(tmp); mdamageu(mtmp, tmp); } break; case AD_BLND: not_affected = resists_blnd(&youmonst); if (!not_affected) { /* sometimes you're affected even if it's invisible */ if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) { You("are blinded by a blast of light!"); make_blinded((long) tmp, FALSE); if (!Blind) Your1(vision_clears); } else if (flags.verbose) You("get the impression it was not terribly bright."); } break; case AD_HALU: not_affected |= Blind || (u.umonnum == PM_BLACK_LIGHT || u.umonnum == PM_VIOLET_FUNGUS || dmgtype(youmonst.data, AD_STUN)); if (!not_affected) { boolean chg; if (!Hallucination) You("are caught in a blast of kaleidoscopic light!"); /* avoid hallucinating the black light as it dies */ mondead(mtmp); /* remove it from map now */ kill_agr = FALSE; /* already killed (maybe lifesaved) */ chg = make_hallucinated(HHallucination + (long) tmp, FALSE, 0L); You("%s.", chg ? "are freaked out" : "seem unaffected"); } break; default: break; } if (not_affected) { You("seem unaffected by it."); ugolemeffects((int) mattk->adtyp, tmp); } } if (kill_agr) mondead(mtmp); wake_nearto(mtmp->mx, mtmp->my, 7 * 7); return (mtmp->mhp > 0) ? 0 : 2; } /* monster gazes at you */ int gazemu(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { static const char *const reactions[] = { "confused", /* [0] */ "stunned", /* [1] */ "puzzled", "dazzled", /* [2,3] */ "irritated", "inflamed", /* [4,5] */ "tired", /* [6] */ "dulled", /* [7] */ }; int react = -1; boolean cancelled = (mtmp->mcan != 0), already = FALSE; /* assumes that hero has to see monster's gaze in order to be affected, rather than monster just having to look at hero; when hallucinating, hero's brain doesn't register what it's seeing correctly so the gaze is usually ineffective [this could be taken a lot farther and select a gaze effect appropriate to what's currently being displayed, giving ordinary monsters a gaze attack when hero thinks he or she is facing a gazing creature, but let's not go that far...] */ if (Hallucination && rn2(4)) cancelled = TRUE; switch (mattk->adtyp) { case AD_STON: if (cancelled || !mtmp->mcansee) { if (!canseemon(mtmp)) break; /* silently */ pline("%s %s.", Monnam(mtmp), (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan) ? "doesn't look all that ugly" : "gazes ineffectually"); break; } if (Reflecting && couldsee(mtmp->mx, mtmp->my) && mtmp->data == &mons[PM_MEDUSA]) { /* hero has line of sight to Medusa and she's not blind */ boolean useeit = canseemon(mtmp); if (useeit) (void) ureflects("%s gaze is reflected by your %s.", s_suffix(Monnam(mtmp))); if (mon_reflects( mtmp, !useeit ? (char *) 0 : "The gaze is reflected away by %s %s!")) break; if (!m_canseeu(mtmp)) { /* probably you're invisible */ if (useeit) pline( "%s doesn't seem to notice that %s gaze was reflected.", Monnam(mtmp), mhis(mtmp)); break; } if (useeit) pline("%s is turned to stone!", Monnam(mtmp)); stoned = TRUE; killed(mtmp); if (mtmp->mhp > 0) break; return 2; } if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && !Stone_resistance) { You("meet %s gaze.", s_suffix(mon_nam(mtmp))); stop_occupation(); if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) break; You("turn to stone..."); killer.format = KILLED_BY; Strcpy(killer.name, mtmp->data->mname); done(STONING); } break; case AD_CONF: if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) { if (cancelled) { react = 0; /* "confused" */ already = (mtmp->mconf != 0); } else { int conf = d(3, 4); mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6)); if (!Confusion) pline("%s gaze confuses you!", s_suffix(Monnam(mtmp))); else You("are getting more and more confused."); make_confused(HConfusion + conf, FALSE); stop_occupation(); } } break; case AD_STUN: if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) { if (cancelled) { react = 1; /* "stunned" */ already = (mtmp->mstun != 0); } else { int stun = d(2, 6); mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6)); pline("%s stares piercingly at you!", Monnam(mtmp)); make_stunned((HStun & TIMEOUT) + (long) stun, TRUE); stop_occupation(); } } break; case AD_BLND: if (canseemon(mtmp) && !resists_blnd(&youmonst) && distu(mtmp->mx, mtmp->my) <= BOLT_LIM * BOLT_LIM) { if (cancelled) { react = rn1(2, 2); /* "puzzled" || "dazzled" */ already = (mtmp->mcansee == 0); /* Archons gaze every round; we don't want cancelled ones giving the "seems puzzled/dazzled" message that often */ if (mtmp->mcan && mtmp->data == &mons[PM_ARCHON] && rn2(5)) react = -1; } else { int blnd = d((int) mattk->damn, (int) mattk->damd); You("are blinded by %s radiance!", s_suffix(mon_nam(mtmp))); make_blinded((long) blnd, FALSE); stop_occupation(); /* not blind at this point implies you're wearing the Eyes of the Overworld; make them block this particular stun attack too */ if (!Blind) Your1(vision_clears); else make_stunned((long) d(1, 3), TRUE); } } break; case AD_FIRE: if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) { if (cancelled) { react = rn1(2, 4); /* "irritated" || "inflamed" */ } else { int dmg = d(2, 6), lev = (int) mtmp->m_lev; pline("%s attacks you with a fiery gaze!", Monnam(mtmp)); stop_occupation(); if (Fire_resistance) { pline_The("fire doesn't feel hot!"); dmg = 0; } burn_away_slime(); if (lev > rn2(20)) destroy_item(SCROLL_CLASS, AD_FIRE); if (lev > rn2(20)) destroy_item(POTION_CLASS, AD_FIRE); if (lev > rn2(25)) destroy_item(SPBOOK_CLASS, AD_FIRE); if (dmg) mdamageu(mtmp, dmg); } } break; #ifdef PM_BEHOLDER /* work in progress */ case AD_SLEE: if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && multi >= 0 && !rn2(5) && !Sleep_resistance) { if (cancelled) { react = 6; /* "tired" */ already = (mtmp->mfrozen != 0); /* can't happen... */ } else { fall_asleep(-rnd(10), TRUE); pline("%s gaze makes you very sleepy...", s_suffix(Monnam(mtmp))); } } break; case AD_SLOW: if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && (HFast & (INTRINSIC | TIMEOUT)) && !defends(AD_SLOW, uwep) && !rn2(4)) { if (cancelled) { react = 7; /* "dulled" */ already = (mtmp->mspeed == MSLOW); } else { u_slow_down(); stop_occupation(); } } break; #endif /* BEHOLDER */ default: impossible("Gaze attack %d?", mattk->adtyp); break; } if (react >= 0) { if (Hallucination && rn2(3)) react = rn2(SIZE(reactions)); /* cancelled/hallucinatory feedback; monster might look "confused", "stunned",&c but we don't actually set corresponding attribute */ pline("%s looks %s%s.", Monnam(mtmp), !rn2(3) ? "" : already ? "quite " : (!rn2(2) ? "a bit " : "somewhat "), reactions[react]); } return 0; } /* mtmp hits you for n points damage */ void mdamageu(mtmp, n) register struct monst *mtmp; register int n; { context.botl = 1; if (Upolyd) { u.mh -= n; if (u.mh < 1) rehumanize(); } else { u.uhp -= n; if (u.uhp < 1) done_in_by(mtmp, DIED); } } /* returns 0 if seduction impossible, * 1 if fine, * 2 if wrong gender for nymph */ int could_seduce(magr, mdef, mattk) struct monst *magr, *mdef; struct attack *mattk; { register struct permonst *pagr; boolean agrinvis, defperc; xchar genagr, gendef; if (is_animal(magr->data)) return 0; if (magr == &youmonst) { pagr = youmonst.data; agrinvis = (Invis != 0); genagr = poly_gender(); } else { pagr = magr->data; agrinvis = magr->minvis; genagr = gender(magr); } if (mdef == &youmonst) { defperc = (See_invisible != 0); gendef = poly_gender(); } else { defperc = perceives(mdef->data); gendef = gender(mdef); } if (agrinvis && !defperc && (!SYSOPT_SEDUCE || (mattk && mattk->adtyp != AD_SSEX))) return 0; if (pagr->mlet != S_NYMPH && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS]) || (SYSOPT_SEDUCE && mattk && mattk->adtyp != AD_SSEX))) return 0; if (genagr == 1 - gendef) return 1; else return (pagr->mlet == S_NYMPH) ? 2 : 0; } /* Returns 1 if monster teleported */ int doseduce(mon) register struct monst *mon; { register struct obj *ring, *nring; boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */ int tried_gloves = 0; char qbuf[QBUFSZ]; if (mon->mcan || mon->mspec_used) { pline("%s acts as though %s has got a %sheadache.", Monnam(mon), mhe(mon), mon->mcan ? "severe " : ""); return 0; } if (unconscious()) { pline("%s seems dismayed at your lack of response.", Monnam(mon)); return 0; } if (Blind) pline("It caresses you..."); else You_feel("very attracted to %s.", mon_nam(mon)); /* if in the process of putting armor on or taking armor off, interrupt that activity now */ (void) stop_donning((struct obj *) 0); /* don't try to take off gloves if cursed weapon blocks them */ if (welded(uwep)) tried_gloves = 1; for (ring = invent; ring; ring = nring) { nring = ring->nobj; if (ring->otyp != RIN_ADORNMENT) continue; if (fem) { if (ring->owornmask && uarmg) { /* don't take off worn ring if gloves are in the way */ if (!tried_gloves++) mayberem(uarmg, "gloves"); if (uarmg) continue; /* next ring might not be worn */ } if (rn2(20) < ACURR(A_CHA)) { (void) safe_qbuf(qbuf, "\"That ", " looks pretty. May I have it?\"", ring, xname, simpleonames, "ring"); makeknown(RIN_ADORNMENT); if (yn(qbuf) == 'n') continue; } else pline("%s decides she'd like %s, and takes it.", Blind ? "She" : Monnam(mon), yname(ring)); makeknown(RIN_ADORNMENT); if (ring == uleft || ring == uright) Ring_gone(ring); if (ring == uwep) setuwep((struct obj *) 0); if (ring == uswapwep) setuswapwep((struct obj *) 0); if (ring == uquiver) setuqwep((struct obj *) 0); freeinv(ring); (void) mpickobj(mon, ring); } else { if (uleft && uright && uleft->otyp == RIN_ADORNMENT && uright->otyp == RIN_ADORNMENT) break; if (ring == uleft || ring == uright) continue; if (uarmg) { /* don't put on ring if gloves are in the way */ if (!tried_gloves++) mayberem(uarmg, "gloves"); if (uarmg) break; /* no point trying further rings */ } if (rn2(20) < ACURR(A_CHA)) { (void) safe_qbuf(qbuf, "\"That ", " looks pretty. Would you wear it for me?\"", ring, xname, simpleonames, "ring"); makeknown(RIN_ADORNMENT); if (yn(qbuf) == 'n') continue; } else { pline("%s decides you'd look prettier wearing %s,", Blind ? "He" : Monnam(mon), yname(ring)); pline("and puts it on your finger."); } makeknown(RIN_ADORNMENT); if (!uright) { pline("%s puts %s on your right %s.", Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND)); setworn(ring, RIGHT_RING); } else if (!uleft) { pline("%s puts %s on your left %s.", Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND)); setworn(ring, LEFT_RING); } else if (uright && uright->otyp != RIN_ADORNMENT) { pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon), yname(uright), yname(ring)); Ring_gone(uright); setworn(ring, RIGHT_RING); } else if (uleft && uleft->otyp != RIN_ADORNMENT) { pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon), yname(uleft), yname(ring)); Ring_gone(uleft); setworn(ring, LEFT_RING); } else impossible("ring replacement"); Ring_on(ring); prinv((char *) 0, ring, 0L); } } if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh && !uarmu) pline("%s murmurs sweet nothings into your ear.", Blind ? (fem ? "She" : "He") : Monnam(mon)); else pline("%s murmurs in your ear, while helping you undress.", Blind ? (fem ? "She" : "He") : Monnam(mon)); mayberem(uarmc, cloak_simple_name(uarmc)); if (!uarmc) mayberem(uarm, "suit"); mayberem(uarmf, "boots"); if (!tried_gloves) mayberem(uarmg, "gloves"); mayberem(uarms, "shield"); mayberem(uarmh, helm_simple_name(uarmh)); if (!uarmc && !uarm) mayberem(uarmu, "shirt"); if (uarm || uarmc) { verbalize("You're such a %s; I wish...", flags.female ? "sweet lady" : "nice guy"); if (!tele_restrict(mon)) (void) rloc(mon, TRUE); return 1; } if (u.ualign.type == A_CHAOTIC) adjalign(1); /* by this point you have discovered mon's identity, blind or not... */ pline("Time stands still while you and %s lie in each other's arms...", noit_mon_nam(mon)); if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) { /* Don't bother with mspec_used here... it didn't get tired! */ pline("%s seems to have enjoyed it more than you...", noit_Monnam(mon)); switch (rn2(5)) { case 0: You_feel("drained of energy."); u.uen = 0; u.uenmax -= rnd(Half_physical_damage ? 5 : 10); exercise(A_CON, FALSE); if (u.uenmax < 0) u.uenmax = 0; break; case 1: You("are down in the dumps."); (void) adjattrib(A_CON, -1, TRUE); exercise(A_CON, FALSE); context.botl = 1; break; case 2: Your("senses are dulled."); (void) adjattrib(A_WIS, -1, TRUE); exercise(A_WIS, FALSE); context.botl = 1; break; case 3: if (!resists_drli(&youmonst)) { You_feel("out of shape."); losexp("overexertion"); } else { You("have a curious feeling..."); } break; case 4: { int tmp; You_feel("exhausted."); exercise(A_STR, FALSE); tmp = rn1(10, 6); losehp(Maybe_Half_Phys(tmp), "exhaustion", KILLED_BY); break; } } } else { mon->mspec_used = rnd(100); /* monster is worn out */ You("seem to have enjoyed it more than %s...", noit_mon_nam(mon)); switch (rn2(5)) { case 0: You_feel("raised to your full potential."); exercise(A_CON, TRUE); u.uen = (u.uenmax += rnd(5)); break; case 1: You_feel("good enough to do it again."); (void) adjattrib(A_CON, 1, TRUE); exercise(A_CON, TRUE); context.botl = 1; break; case 2: You("will always remember %s...", noit_mon_nam(mon)); (void) adjattrib(A_WIS, 1, TRUE); exercise(A_WIS, TRUE); context.botl = 1; break; case 3: pline("That was a very educational experience."); pluslvl(FALSE); exercise(A_WIS, TRUE); break; case 4: You_feel("restored to health!"); u.uhp = u.uhpmax; if (Upolyd) u.mh = u.mhmax; exercise(A_STR, TRUE); context.botl = 1; break; } } if (mon->mtame) /* don't charge */ ; else if (rn2(20) < ACURR(A_CHA)) { pline("%s demands that you pay %s, but you refuse...", noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon)); } else if (u.umonnum == PM_LEPRECHAUN) pline("%s tries to take your money, but fails...", noit_Monnam(mon)); else { long cost; long umoney = money_cnt(invent); if (umoney > (long) LARGEST_INT - 10L) cost = (long) rnd(LARGEST_INT) + 500L; else cost = (long) rnd((int) umoney + 10) + 500L; if (mon->mpeaceful) { cost /= 5L; if (!cost) cost = 1L; } if (cost > umoney) cost = umoney; if (!cost) verbalize("It's on the house!"); else { pline("%s takes %ld %s for services rendered!", noit_Monnam(mon), cost, currency(cost)); money2mon(mon, cost); context.botl = 1; } } if (!rn2(25)) mon->mcan = 1; /* monster is worn out */ if (!tele_restrict(mon)) (void) rloc(mon, TRUE); return 1; } STATIC_OVL void mayberem(obj, str) register struct obj *obj; const char *str; { char qbuf[QBUFSZ]; if (!obj || !obj->owornmask) return; if (rn2(20) < ACURR(A_CHA)) { Sprintf(qbuf, "\"Shall I remove your %s, %s?\"", str, (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart")); if (yn(qbuf) == 'n') return; } else { char hairbuf[BUFSZ]; Sprintf(hairbuf, "let me run my fingers through your %s", body_part(HAIR)); verbalize("Take off your %s; %s.", str, (obj == uarm) ? "let's get a little closer" : (obj == uarmc || obj == uarms) ? "it's in the way" : (obj == uarmf) ? "let me rub your feet" : (obj == uarmg) ? "they're too clumsy" : (obj == uarmu) ? "let me massage you" /* obj == uarmh */ : hairbuf); } remove_worn_item(obj, TRUE); } STATIC_OVL int passiveum(olduasmon, mtmp, mattk) struct permonst *olduasmon; register struct monst *mtmp; register struct attack *mattk; { int i, tmp; for (i = 0;; i++) { if (i >= NATTK) return 1; if (olduasmon->mattk[i].aatyp == AT_NONE || olduasmon->mattk[i].aatyp == AT_BOOM) break; } if (olduasmon->mattk[i].damn) tmp = d((int) olduasmon->mattk[i].damn, (int) olduasmon->mattk[i].damd); else if (olduasmon->mattk[i].damd) tmp = d((int) olduasmon->mlevel + 1, (int) olduasmon->mattk[i].damd); else tmp = 0; /* These affect the enemy even if you were "killed" (rehumanized) */ switch (olduasmon->mattk[i].adtyp) { case AD_ACID: if (!rn2(2)) { pline("%s is splashed by your acid!", Monnam(mtmp)); if (resists_acid(mtmp)) { pline("%s is not affected.", Monnam(mtmp)); tmp = 0; } } else tmp = 0; if (!rn2(30)) erode_armor(mtmp, ERODE_CORRODE); if (!rn2(6)) acid_damage(MON_WEP(mtmp)); goto assess_dmg; case AD_STON: /* cockatrice */ { long protector = attk_protection((int) mattk->aatyp), wornitems = mtmp->misc_worn_check; /* wielded weapon gives same protection as gloves here */ if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG; if (!resists_ston(mtmp) && (protector == 0L || (protector != ~0L && (wornitems & protector) != protector))) { if (poly_when_stoned(mtmp->data)) { mon_to_stone(mtmp); return 1; } pline("%s turns to stone!", Monnam(mtmp)); stoned = 1; xkilled(mtmp, 0); if (mtmp->mhp > 0) return 1; return 2; } return 1; } case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (otmp) { (void) drain_item(otmp); /* No message */ } return 1; default: break; } if (!Upolyd) return 1; /* These affect the enemy only if you are still a monster */ if (rn2(3)) switch (youmonst.data->mattk[i].adtyp) { case AD_PHYS: if (youmonst.data->mattk[i].aatyp == AT_BOOM) { You("explode!"); /* KMH, balance patch -- this is okay with unchanging */ rehumanize(); goto assess_dmg; } break; case AD_PLYS: /* Floating eye */ if (tmp > 127) tmp = 127; if (u.umonnum == PM_FLOATING_EYE) { if (!rn2(4)) tmp = 127; if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3) && (perceives(mtmp->data) || !Invis)) { if (Blind) pline("As a blind %s, you cannot defend yourself.", youmonst.data->mname); else { if (mon_reflects(mtmp, "Your gaze is reflected by %s %s.")) return 1; pline("%s is frozen by your gaze!", Monnam(mtmp)); paralyze_monst(mtmp, tmp); return 3; } } } else { /* gelatinous cube */ pline("%s is frozen by you.", Monnam(mtmp)); paralyze_monst(mtmp, tmp); return 3; } return 1; case AD_COLD: /* Brown mold or blue jelly */ if (resists_cold(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("%s is mildly chilly.", Monnam(mtmp)); golemeffects(mtmp, AD_COLD, tmp); tmp = 0; break; } pline("%s is suddenly very cold!", Monnam(mtmp)); u.mh += tmp / 2; if (u.mhmax < u.mh) u.mhmax = u.mh; if (u.mhmax > ((youmonst.data->mlevel + 1) * 8)) (void) split_mon(&youmonst, mtmp); break; case AD_STUN: /* Yellow mold */ if (!mtmp->mstun) { mtmp->mstun = 1; pline("%s %s.", Monnam(mtmp), makeplural(stagger(mtmp->data, "stagger"))); } tmp = 0; break; case AD_FIRE: /* Red mold */ if (resists_fire(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("%s is mildly warm.", Monnam(mtmp)); golemeffects(mtmp, AD_FIRE, tmp); tmp = 0; break; } pline("%s is suddenly very hot!", Monnam(mtmp)); break; case AD_ELEC: if (resists_elec(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("%s is slightly tingled.", Monnam(mtmp)); golemeffects(mtmp, AD_ELEC, tmp); tmp = 0; break; } pline("%s is jolted with your electricity!", Monnam(mtmp)); break; default: tmp = 0; break; } else tmp = 0; assess_dmg: if ((mtmp->mhp -= tmp) <= 0) { pline("%s dies!", Monnam(mtmp)); xkilled(mtmp, 0); if (mtmp->mhp > 0) return 1; return 2; } return 1; } struct monst * cloneu() { register struct monst *mon; int mndx = monsndx(youmonst.data); if (u.mh <= 1) return (struct monst *) 0; if (mvitals[mndx].mvflags & G_EXTINCT) return (struct monst *) 0; mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT | MM_EDOG); if (!mon) return NULL; mon->mcloned = 1; mon = christen_monst(mon, plname); initedog(mon); mon->m_lev = youmonst.data->mlevel; mon->mhpmax = u.mhmax; mon->mhp = u.mh / 2; u.mh -= mon->mhp; context.botl = 1; return mon; } /*mhitu.c*/ nethack-3.6.0/src/minion.c0000664000076400007660000003315712625266203014376 0ustar paxedpaxed/* NetHack 3.6 minion.c $NHDT-Date: 1432512773 2015/05/25 00:12:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" void newemin(mtmp) struct monst *mtmp; { if (!mtmp->mextra) mtmp->mextra = newmextra(); if (!EMIN(mtmp)) { EMIN(mtmp) = (struct emin *) alloc(sizeof(struct emin)); (void) memset((genericptr_t) EMIN(mtmp), 0, sizeof(struct emin)); } } void free_emin(mtmp) struct monst *mtmp; { if (mtmp->mextra && EMIN(mtmp)) { free((genericptr_t) EMIN(mtmp)); EMIN(mtmp) = (struct emin *) 0; } mtmp->isminion = 0; } /* count the number of monsters on the level */ int monster_census(spotted) boolean spotted; /* seen|sensed vs all */ { struct monst *mtmp; int count = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (spotted && !canspotmon(mtmp)) continue; ++count; } return count; } /* mon summons a monster */ int msummon(mon) struct monst *mon; { struct permonst *ptr; int dtype = NON_PM, cnt = 0, result = 0, census; aligntyp atyp; struct monst *mtmp; if (mon) { ptr = mon->data; atyp = mon->ispriest ? EPRI(mon)->shralign : mon->isminion ? EMIN(mon)->min_align : (ptr->maligntyp == A_NONE) ? A_NONE : sgn(ptr->maligntyp); } else { ptr = &mons[PM_WIZARD_OF_YENDOR]; atyp = (ptr->maligntyp == A_NONE) ? A_NONE : sgn(ptr->maligntyp); } if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) { dtype = (!rn2(20)) ? dprince(atyp) : (!rn2(4)) ? dlord(atyp) : ndemon(atyp); cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1; } else if (is_dlord(ptr)) { dtype = (!rn2(50)) ? dprince(atyp) : (!rn2(20)) ? dlord(atyp) : ndemon(atyp); cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1; } else if (is_ndemon(ptr)) { dtype = (!rn2(20)) ? dlord(atyp) : (!rn2(6)) ? ndemon(atyp) : monsndx(ptr); cnt = 1; } else if (is_lminion(mon)) { dtype = (is_lord(ptr) && !rn2(20)) ? llord() : (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr); cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; } else if (ptr == &mons[PM_ANGEL]) { /* non-lawful angels can also summon */ if (!rn2(6)) { switch (atyp) { /* see summon_minion */ case A_NEUTRAL: dtype = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: dtype = ndemon(atyp); break; } } else { dtype = PM_ANGEL; } cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; } if (dtype == NON_PM) return 0; /* sanity checks */ if (cnt > 1 && (mons[dtype].geno & G_UNIQ)) cnt = 1; /* * If this daemon is unique and being re-summoned (the only way we * could get this far with an extinct dtype), try another. */ if (mvitals[dtype].mvflags & G_GONE) { dtype = ndemon(atyp); if (dtype == NON_PM) return 0; } /* some candidates can generate a group of monsters, so simple count of non-null makemon() result is not sufficient */ census = monster_census(FALSE); while (cnt > 0) { mtmp = makemon(&mons[dtype], u.ux, u.uy, MM_EMIN); if (mtmp) { result++; /* an angel's alignment should match the summoner */ if (dtype == PM_ANGEL) { mtmp->isminion = 1; EMIN(mtmp)->min_align = atyp; /* renegade if same alignment but not peaceful or peaceful but different alignment */ EMIN(mtmp)->renegade = (atyp != u.ualign.type) ^ !mtmp->mpeaceful; } } cnt--; } /* how many monsters exist now compared to before? */ if (result) result = monster_census(FALSE) - census; return result; } void summon_minion(alignment, talk) aligntyp alignment; boolean talk; { register struct monst *mon; int mnum; switch ((int) alignment) { case A_LAWFUL: mnum = lminion(); break; case A_NEUTRAL: mnum = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: mnum = ndemon(alignment); break; default: impossible("unaligned player?"); mnum = ndemon(A_NONE); break; } if (mnum == NON_PM) { mon = 0; } else if (mnum == PM_ANGEL) { mon = makemon(&mons[mnum], u.ux, u.uy, MM_EMIN); if (mon) { mon->isminion = 1; EMIN(mon)->min_align = alignment; EMIN(mon)->renegade = FALSE; } } else if (mnum != PM_SHOPKEEPER && mnum != PM_GUARD && mnum != PM_ALIGNED_PRIEST && mnum != PM_HIGH_PRIEST) { /* This was mons[mnum].pxlth == 0 but is this restriction appropriate or necessary now that the structures are separate? */ mon = makemon(&mons[mnum], u.ux, u.uy, MM_EMIN); if (mon) { mon->isminion = 1; EMIN(mon)->min_align = alignment; EMIN(mon)->renegade = FALSE; } } else { mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS); } if (mon) { if (talk) { pline_The("voice of %s booms:", align_gname(alignment)); verbalize("Thou shalt pay for thine indiscretion!"); if (!Blind) pline("%s appears before you.", Amonnam(mon)); mon->mstrategy &= ~STRAT_APPEARMSG; } mon->mpeaceful = FALSE; /* don't call set_malign(); player was naughty */ } } #define Athome (Inhell && (mtmp->cham == NON_PM)) /* returns 1 if it won't attack. */ int demon_talk(mtmp) register struct monst *mtmp; { long cash, demand, offer; if (uwep && uwep->oartifact == ART_EXCALIBUR) { pline("%s looks very angry.", Amonnam(mtmp)); mtmp->mpeaceful = mtmp->mtame = 0; set_malign(mtmp); newsym(mtmp->mx, mtmp->my); return 0; } if (is_fainted()) { reset_faint(); /* if fainted - wake up */ } else { stop_occupation(); if (multi > 0) { nomul(0); unmul((char *) 0); } } /* Slight advantage given. */ if (is_dprince(mtmp->data) && mtmp->minvis) { boolean wasunseen = !canspotmon(mtmp); mtmp->minvis = mtmp->perminvis = 0; if (wasunseen && canspotmon(mtmp)) { pline("%s appears before you.", Amonnam(mtmp)); mtmp->mstrategy &= ~STRAT_APPEARMSG; } newsym(mtmp->mx, mtmp->my); } if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */ pline("%s says, \"Good hunting, %s.\"", Amonnam(mtmp), flags.female ? "Sister" : "Brother"); if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); return (1); } cash = money_cnt(invent); demand = (cash * (rnd(80) + 20 * Athome)) / (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)))); if (!demand || multi < 0) { /* you have no gold or can't move */ mtmp->mpeaceful = 0; set_malign(mtmp); return 0; } else { /* make sure that the demand is unmeetable if the monster has the Amulet, preventing monster from being satisfied and removed from the game (along with said Amulet...) */ if (mon_has_amulet(mtmp)) demand = cash + (long) rn1(1000, 40); pline("%s demands %ld %s for safe passage.", Amonnam(mtmp), demand, currency(demand)); if ((offer = bribe(mtmp)) >= demand) { pline("%s vanishes, laughing about cowardly mortals.", Amonnam(mtmp)); } else if (offer > 0L && (long) rnd(40) > (demand - offer)) { pline("%s scowls at you menacingly, then vanishes.", Amonnam(mtmp)); } else { pline("%s gets angry...", Amonnam(mtmp)); mtmp->mpeaceful = 0; set_malign(mtmp); return 0; } } mongone(mtmp); return (1); } long bribe(mtmp) struct monst *mtmp; { char buf[BUFSZ]; long offer; long umoney = money_cnt(invent); getlin("How much will you offer?", buf); if (sscanf(buf, "%ld", &offer) != 1) offer = 0L; /*Michael Paddon -- fix for negative offer to monster*/ /*JAR880815 - */ if (offer < 0L) { You("try to shortchange %s, but fumble.", mon_nam(mtmp)); return 0L; } else if (offer == 0L) { You("refuse."); return 0L; } else if (offer >= umoney) { You("give %s all your gold.", mon_nam(mtmp)); offer = umoney; } else { You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer)); } (void) money2mon(mtmp, offer); context.botl = 1; return (offer); } int dprince(atyp) aligntyp atyp; { int tryct, pm; for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) { pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS); if (!(mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) return (pm); } return (dlord(atyp)); /* approximate */ } int dlord(atyp) aligntyp atyp; { int tryct, pm; for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) { pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX); if (!(mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) return (pm); } return (ndemon(atyp)); /* approximate */ } /* create lawful (good) lord */ int llord() { if (!(mvitals[PM_ARCHON].mvflags & G_GONE)) return (PM_ARCHON); return (lminion()); /* approximate */ } int lminion() { int tryct; struct permonst *ptr; for (tryct = 0; tryct < 20; tryct++) { ptr = mkclass(S_ANGEL, 0); if (ptr && !is_lord(ptr)) return (monsndx(ptr)); } return NON_PM; } int ndemon(atyp) aligntyp atyp; { int tryct; struct permonst *ptr; for (tryct = 0; tryct < 20; tryct++) { ptr = mkclass(S_DEMON, 0); if (ptr && is_ndemon(ptr) && (atyp == A_NONE || sgn(ptr->maligntyp) == sgn(atyp))) return (monsndx(ptr)); } return NON_PM; } /* guardian angel has been affected by conflict so is abandoning hero */ void lose_guardian_angel(mon) struct monst *mon; /* if null, angel hasn't been created yet */ { coord mm; int i; if (mon) { if (canspotmon(mon)) { if (!Deaf) { pline("%s rebukes you, saying:", Monnam(mon)); verbalize("Since you desire conflict, have some more!"); } else { pline("%s vanishes!", Monnam(mon)); } } mongone(mon); } /* create 2 to 4 hostile angels to replace the lost guardian */ for (i = rn1(3, 2); i > 0; --i) { mm.x = u.ux; mm.y = u.uy; if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y, FALSE); } } /* just entered the Astral Plane; receive tame guardian angel if worthy */ void gain_guardian_angel() { struct monst *mtmp; struct obj *otmp; coord mm; Hear_again(); /* attempt to cure any deafness now (divine message will be heard even if that fails) */ if (Conflict) { pline("A voice booms:"); verbalize("Thy desire for conflict shall be fulfilled!"); /* send in some hostile angels instead */ lose_guardian_angel((struct monst *) 0); } else if (u.ualign.record > 8) { /* fervent */ pline("A voice whispers:"); verbalize("Thou hast been worthy of me!"); mm.x = u.ux; mm.y = u.uy; if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]) && (mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y, TRUE)) != 0) { mtmp->mstrategy &= ~STRAT_APPEARMSG; if (!Blind) pline("An angel appears near you."); else You_feel("the presence of a friendly angel near you."); /* guardian angel -- the one case mtame doesn't * imply an edog structure, so we don't want to * call tamedog(). */ mtmp->mtame = 10; /* make him strong enough vs. endgame foes */ mtmp->m_lev = rn1(8, 15); mtmp->mhp = mtmp->mhpmax = d((int) mtmp->m_lev, 10) + 30 + rnd(30); if ((otmp = select_hwep(mtmp)) == 0) { otmp = mksobj(SILVER_SABER, FALSE, FALSE); if (mpickobj(mtmp, otmp)) panic("merged weapon?"); } bless(otmp); if (otmp->spe < 4) otmp->spe += rnd(4); if ((otmp = which_armor(mtmp, W_ARMS)) == 0 || otmp->otyp != SHIELD_OF_REFLECTION) { (void) mongets(mtmp, AMULET_OF_REFLECTION); m_dowear(mtmp, TRUE); } } } } /*minion.c*/ nethack-3.6.0/src/mklev.c0000664000076400007660000014223212624166366014226 0ustar paxedpaxed/* NetHack 3.6 mklev.c $NHDT-Date: 1446191876 2015/10/30 07:57:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */ /* croom->lx etc are schar (width <= int), so % arith ensures that */ /* conversion of result to int is reasonable */ STATIC_DCL void FDECL(mkfount, (int, struct mkroom *)); STATIC_DCL void FDECL(mksink, (struct mkroom *)); STATIC_DCL void FDECL(mkaltar, (struct mkroom *)); STATIC_DCL void FDECL(mkgrave, (struct mkroom *)); STATIC_DCL void NDECL(makevtele); STATIC_DCL void NDECL(clear_level_structures); STATIC_DCL void NDECL(makelevel); STATIC_DCL boolean FDECL(bydoor, (XCHAR_P, XCHAR_P)); STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *)); STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P)); STATIC_DCL boolean FDECL(place_niche, (struct mkroom *, int *, int *, int *)); STATIC_DCL void FDECL(makeniche, (int)); STATIC_DCL void NDECL(make_niches); STATIC_PTR int FDECL(CFDECLSPEC do_comp, (const genericptr, const genericptr)); STATIC_DCL void FDECL(dosdoor, (XCHAR_P, XCHAR_P, struct mkroom *, int)); STATIC_DCL void FDECL(join, (int, int, BOOLEAN_P)); STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *, int, int, int, int, BOOLEAN_P, SCHAR_P, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void NDECL(makerooms); STATIC_DCL void FDECL(finddpos, (coord *, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); STATIC_DCL void FDECL(mkinvpos, (XCHAR_P, XCHAR_P, int)); STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P, XCHAR_P)); #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE) #define init_vault() vault_x = -1 #define do_vault() (vault_x != -1) static xchar vault_x, vault_y; static boolean made_branch; /* used only during level creation */ /* Args must be (const genericptr) so that qsort will always be happy. */ STATIC_PTR int CFDECLSPEC do_comp(vx, vy) const genericptr vx; const genericptr vy; { #ifdef LINT /* lint complains about possible pointer alignment problems, but we know that vx and vy are always properly aligned. Hence, the following bogus definition: */ return (vx == vy) ? 0 : -1; #else register const struct mkroom *x, *y; x = (const struct mkroom *) vx; y = (const struct mkroom *) vy; if (x->lx < y->lx) return -1; return (x->lx > y->lx); #endif /* LINT */ } STATIC_OVL void finddpos(cc, xl, yl, xh, yh) coord *cc; xchar xl, yl, xh, yh; { register xchar x, y; x = rn1(xh - xl + 1, xl); y = rn1(yh - yl + 1, yl); if (okdoor(x, y)) goto gotit; for (x = xl; x <= xh; x++) for (y = yl; y <= yh; y++) if (okdoor(x, y)) goto gotit; for (x = xl; x <= xh; x++) for (y = yl; y <= yh; y++) if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) goto gotit; /* cannot find something reasonable -- strange */ x = xl; y = yh; gotit: cc->x = x; cc->y = y; return; } void sort_rooms() { #if defined(SYSV) || defined(DGUX) qsort((genericptr_t) rooms, (unsigned) nroom, sizeof(struct mkroom), do_comp); #else qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp); #endif } STATIC_OVL void do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room) register struct mkroom *croom; int lowx, lowy; register int hix, hiy; boolean lit; schar rtype; boolean special; boolean is_room; { register int x, y; struct rm *lev; /* locations might bump level edges in wall-less rooms */ /* add/subtract 1 to allow for edge locations */ if (!lowx) lowx++; if (!lowy) lowy++; if (hix >= COLNO - 1) hix = COLNO - 2; if (hiy >= ROWNO - 1) hiy = ROWNO - 2; if (lit) { for (x = lowx - 1; x <= hix + 1; x++) { lev = &levl[x][max(lowy - 1, 0)]; for (y = lowy - 1; y <= hiy + 1; y++) lev++->lit = 1; } croom->rlit = 1; } else croom->rlit = 0; croom->lx = lowx; croom->hx = hix; croom->ly = lowy; croom->hy = hiy; croom->rtype = rtype; croom->doorct = 0; /* if we're not making a vault, doorindex will still be 0 * if we are, we'll have problems adding niches to the previous room * unless fdoor is at least doorindex */ croom->fdoor = doorindex; croom->irregular = FALSE; croom->nsubrooms = 0; croom->sbrooms[0] = (struct mkroom *) 0; if (!special) { for (x = lowx - 1; x <= hix + 1; x++) for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) { levl[x][y].typ = HWALL; levl[x][y].horizontal = 1; /* For open/secret doors. */ } for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2)) for (y = lowy; y <= hiy; y++) { levl[x][y].typ = VWALL; levl[x][y].horizontal = 0; /* For open/secret doors. */ } for (x = lowx; x <= hix; x++) { lev = &levl[x][lowy]; for (y = lowy; y <= hiy; y++) lev++->typ = ROOM; } if (is_room) { levl[lowx - 1][lowy - 1].typ = TLCORNER; levl[hix + 1][lowy - 1].typ = TRCORNER; levl[lowx - 1][hiy + 1].typ = BLCORNER; levl[hix + 1][hiy + 1].typ = BRCORNER; } else { /* a subroom */ wallification(lowx - 1, lowy - 1, hix + 1, hiy + 1); } } } void add_room(lowx, lowy, hix, hiy, lit, rtype, special) int lowx, lowy, hix, hiy; boolean lit; schar rtype; boolean special; { register struct mkroom *croom; croom = &rooms[nroom]; do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, (boolean) TRUE); croom++; croom->hx = -1; nroom++; } void add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special) struct mkroom *proom; int lowx, lowy, hix, hiy; boolean lit; schar rtype; boolean special; { register struct mkroom *croom; croom = &subrooms[nsubroom]; do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, (boolean) FALSE); proom->sbrooms[proom->nsubrooms++] = croom; croom++; croom->hx = -1; nsubroom++; } STATIC_OVL void makerooms() { boolean tried_vault = FALSE; /* make rooms until satisfied */ /* rnd_rect() will returns 0 if no more rects are available... */ while (nroom < MAXNROFROOMS && rnd_rect()) { if (nroom >= (MAXNROFROOMS / 6) && rn2(2) && !tried_vault) { tried_vault = TRUE; if (create_vault()) { vault_x = rooms[nroom].lx; vault_y = rooms[nroom].ly; rooms[nroom].hx = -1; } } else if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1)) return; } return; } STATIC_OVL void join(a, b, nxcor) register int a, b; boolean nxcor; { coord cc, tt, org, dest; register xchar tx, ty, xx, yy; register struct mkroom *croom, *troom; register int dx, dy; croom = &rooms[a]; troom = &rooms[b]; /* find positions cc and tt for doors in croom and troom and direction for a corridor between them */ if (troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return; if (troom->lx > croom->hx) { dx = 1; dy = 0; xx = croom->hx + 1; tx = troom->lx - 1; finddpos(&cc, xx, croom->ly, xx, croom->hy); finddpos(&tt, tx, troom->ly, tx, troom->hy); } else if (troom->hy < croom->ly) { dy = -1; dx = 0; yy = croom->ly - 1; finddpos(&cc, croom->lx, yy, croom->hx, yy); ty = troom->hy + 1; finddpos(&tt, troom->lx, ty, troom->hx, ty); } else if (troom->hx < croom->lx) { dx = -1; dy = 0; xx = croom->lx - 1; tx = troom->hx + 1; finddpos(&cc, xx, croom->ly, xx, croom->hy); finddpos(&tt, tx, troom->ly, tx, troom->hy); } else { dy = 1; dx = 0; yy = croom->hy + 1; ty = troom->ly - 1; finddpos(&cc, croom->lx, yy, croom->hx, yy); finddpos(&tt, troom->lx, ty, troom->hx, ty); } xx = cc.x; yy = cc.y; tx = tt.x - dx; ty = tt.y - dy; if (nxcor && levl[xx + dx][yy + dy].typ) return; if (okdoor(xx, yy) || !nxcor) dodoor(xx, yy, croom); org.x = xx + dx; org.y = yy + dy; dest.x = tx; dest.y = ty; if (!dig_corridor(&org, &dest, nxcor, level.flags.arboreal ? ROOM : CORR, STONE)) return; /* we succeeded in digging the corridor */ if (okdoor(tt.x, tt.y) || !nxcor) dodoor(tt.x, tt.y, troom); if (smeq[a] < smeq[b]) smeq[b] = smeq[a]; else smeq[a] = smeq[b]; } void makecorridors() { int a, b, i; boolean any = TRUE; for (a = 0; a < nroom - 1; a++) { join(a, a + 1, FALSE); if (!rn2(50)) break; /* allow some randomness */ } for (a = 0; a < nroom - 2; a++) if (smeq[a] != smeq[a + 2]) join(a, a + 2, FALSE); for (a = 0; any && a < nroom; a++) { any = FALSE; for (b = 0; b < nroom; b++) if (smeq[a] != smeq[b]) { join(a, b, FALSE); any = TRUE; } } if (nroom > 2) for (i = rn2(nroom) + 4; i; i--) { a = rn2(nroom); b = rn2(nroom - 2); if (b >= a) b += 2; join(a, b, TRUE); } } void add_door(x, y, aroom) register int x, y; register struct mkroom *aroom; { register struct mkroom *broom; register int tmp; int i; if (aroom->doorct == 0) aroom->fdoor = doorindex; aroom->doorct++; for (tmp = doorindex; tmp > aroom->fdoor; tmp--) doors[tmp] = doors[tmp - 1]; for (i = 0; i < nroom; i++) { broom = &rooms[i]; if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor) broom->fdoor++; } for (i = 0; i < nsubroom; i++) { broom = &subrooms[i]; if (broom != aroom && broom->doorct && broom->fdoor >= aroom->fdoor) broom->fdoor++; } doorindex++; doors[aroom->fdoor].x = x; doors[aroom->fdoor].y = y; } STATIC_OVL void dosdoor(x, y, aroom, type) register xchar x, y; struct mkroom *aroom; int type; { boolean shdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE; if (!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */ type = DOOR; levl[x][y].typ = type; if (type == DOOR) { if (!rn2(3)) { /* is it a locked door, closed, or a doorway? */ if (!rn2(5)) levl[x][y].doormask = D_ISOPEN; else if (!rn2(6)) levl[x][y].doormask = D_LOCKED; else levl[x][y].doormask = D_CLOSED; if (levl[x][y].doormask != D_ISOPEN && !shdoor && level_difficulty() >= 5 && !rn2(25)) levl[x][y].doormask |= D_TRAPPED; } else { #ifdef STUPID if (shdoor) levl[x][y].doormask = D_ISOPEN; else levl[x][y].doormask = D_NODOOR; #else levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR); #endif } /* also done in roguecorr(); doing it here first prevents making mimics in place of trapped doors on rogue level */ if (Is_rogue_level(&u.uz)) levl[x][y].doormask = D_NODOOR; if (levl[x][y].doormask & D_TRAPPED) { struct monst *mtmp; if (level_difficulty() >= 9 && !rn2(5) && !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) && (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) && (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) { /* make a mimic instead */ levl[x][y].doormask = D_NODOOR; mtmp = makemon(mkclass(S_MIMIC, 0), x, y, NO_MM_FLAGS); if (mtmp) set_mimic_sym(mtmp); } } /* newsym(x,y); */ } else { /* SDOOR */ if (shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED; else levl[x][y].doormask = D_CLOSED; if (!shdoor && level_difficulty() >= 4 && !rn2(20)) levl[x][y].doormask |= D_TRAPPED; } add_door(x, y, aroom); } STATIC_OVL boolean place_niche(aroom, dy, xx, yy) register struct mkroom *aroom; int *dy, *xx, *yy; { coord dd; if (rn2(2)) { *dy = 1; finddpos(&dd, aroom->lx, aroom->hy + 1, aroom->hx, aroom->hy + 1); } else { *dy = -1; finddpos(&dd, aroom->lx, aroom->ly - 1, aroom->hx, aroom->ly - 1); } *xx = dd.x; *yy = dd.y; return (boolean) ((isok(*xx, *yy + *dy) && levl[*xx][*yy + *dy].typ == STONE) && (isok(*xx, *yy - *dy) && !IS_POOL(levl[*xx][*yy - *dy].typ) && !IS_FURNITURE(levl[*xx][*yy - *dy].typ))); } /* there should be one of these per trap, in the same order as trap.h */ static NEARDATA const char *trap_engravings[TRAPNUM] = { (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, /* 14..16: trap door, teleport, level-teleport */ "Vlad was here", "ad aerarium", "ad aerarium", (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, (char *) 0, }; STATIC_OVL void makeniche(trap_type) int trap_type; { register struct mkroom *aroom; struct rm *rm; int vct = 8; int dy, xx, yy; struct trap *ttmp; if (doorindex < DOORMAX) { while (vct--) { aroom = &rooms[rn2(nroom)]; if (aroom->rtype != OROOM) continue; /* not an ordinary room */ if (aroom->doorct == 1 && rn2(5)) continue; if (!place_niche(aroom, &dy, &xx, &yy)) continue; rm = &levl[xx][yy + dy]; if (trap_type || !rn2(4)) { rm->typ = SCORR; if (trap_type) { if ((trap_type == HOLE || trap_type == TRAPDOOR) && !Can_fall_thru(&u.uz)) trap_type = ROCKTRAP; ttmp = maketrap(xx, yy + dy, trap_type); if (ttmp) { if (trap_type != ROCKTRAP) ttmp->once = 1; if (trap_engravings[trap_type]) { make_engr_at(xx, yy - dy, trap_engravings[trap_type], 0L, DUST); wipe_engr_at(xx, yy - dy, 5, FALSE); /* age it a little */ } } } dosdoor(xx, yy, aroom, SDOOR); } else { rm->typ = CORR; if (rn2(7)) dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR); else { /* inaccessible niches occasionally have iron bars */ if (!rn2(5) && IS_WALL(levl[xx][yy].typ)) { levl[xx][yy].typ = IRONBARS; if (rn2(3)) (void) mkcorpstat(CORPSE, (struct monst *) 0, mkclass(S_HUMAN, 0), xx, yy + dy, TRUE); } if (!level.flags.noteleport) (void) mksobj_at(SCR_TELEPORTATION, xx, yy + dy, TRUE, FALSE); if (!rn2(3)) (void) mkobj_at(0, xx, yy + dy, TRUE); } } return; } } } STATIC_OVL void make_niches() { int ct = rnd((nroom >> 1) + 1), dep = depth(&u.uz); boolean ltptr = (!level.flags.noteleport && dep > 15), vamp = (dep > 5 && dep < 25); while (ct--) { if (ltptr && !rn2(6)) { ltptr = FALSE; makeniche(LEVEL_TELEP); } else if (vamp && !rn2(6)) { vamp = FALSE; makeniche(TRAPDOOR); } else makeniche(NO_TRAP); } } STATIC_OVL void makevtele() { makeniche(TELEP_TRAP); } /* clear out various globals that keep information on the current level. * some of this is only necessary for some types of levels (maze, normal, * special) but it's easier to put it all in one place than make sure * each type initializes what it needs to separately. */ STATIC_OVL void clear_level_structures() { static struct rm zerorm = { cmap_to_glyph(S_stone), 0, 0, 0, 0, 0, 0, 0, 0, 0 }; register int x, y; register struct rm *lev; for (x = 0; x < COLNO; x++) { lev = &levl[x][0]; for (y = 0; y < ROWNO; y++) { *lev++ = zerorm; /* * These used to be '#if MICROPORT_BUG', * with use of memset(0) for '#if !MICROPORT_BUG' below, * but memset is not appropriate for initializing pointers, * so do these level.objects[][] and level.monsters[][] * initializations unconditionally. */ level.objects[x][y] = (struct obj *) 0; level.monsters[x][y] = (struct monst *) 0; } } level.objlist = (struct obj *) 0; level.buriedobjlist = (struct obj *) 0; level.monlist = (struct monst *) 0; level.damagelist = (struct damage *) 0; level.bonesinfo = (struct cemetery *) 0; level.flags.nfountains = 0; level.flags.nsinks = 0; level.flags.has_shop = 0; level.flags.has_vault = 0; level.flags.has_zoo = 0; level.flags.has_court = 0; level.flags.has_morgue = level.flags.graveyard = 0; level.flags.has_beehive = 0; level.flags.has_barracks = 0; level.flags.has_temple = 0; level.flags.has_swamp = 0; level.flags.noteleport = 0; level.flags.hardfloor = 0; level.flags.nommap = 0; level.flags.hero_memory = 1; level.flags.shortsighted = 0; level.flags.sokoban_rules = 0; level.flags.is_maze_lev = 0; level.flags.is_cavernous_lev = 0; level.flags.arboreal = 0; level.flags.wizard_bones = 0; level.flags.corrmaze = 0; nroom = 0; rooms[0].hx = -1; nsubroom = 0; subrooms[0].hx = -1; doorindex = 0; init_rect(); init_vault(); xdnstair = ydnstair = xupstair = yupstair = 0; sstairs.sx = sstairs.sy = 0; xdnladder = ydnladder = xupladder = yupladder = 0; made_branch = FALSE; clear_regions(); } STATIC_OVL void makelevel() { register struct mkroom *croom, *troom; register int tryct; register int x, y; struct monst *tmonst; /* always put a web with a spider */ branch *branchp; int room_threshold; if (wiz1_level.dlevel == 0) init_dungeons(); oinit(); /* assign level dependent obj probabilities */ clear_level_structures(); { register s_level *slev = Is_special(&u.uz); /* check for special levels */ if (slev && !Is_rogue_level(&u.uz)) { makemaz(slev->proto); return; } else if (dungeons[u.uz.dnum].proto[0]) { makemaz(""); return; } else if (In_mines(&u.uz)) { makemaz("minefill"); return; } else if (In_quest(&u.uz)) { char fillname[9]; s_level *loc_lev; Sprintf(fillname, "%s-loca", urole.filecode); loc_lev = find_level(fillname); Sprintf(fillname, "%s-fil", urole.filecode); Strcat(fillname, (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b"); makemaz(fillname); return; } else if (In_hell(&u.uz) || (rn2(5) && u.uz.dnum == medusa_level.dnum && depth(&u.uz) > depth(&medusa_level))) { makemaz(""); return; } } /* otherwise, fall through - it's a "regular" level. */ if (Is_rogue_level(&u.uz)) { makeroguerooms(); makerogueghost(); } else makerooms(); sort_rooms(); /* construct stairs (up and down in different rooms if possible) */ croom = &rooms[rn2(nroom)]; if (!Is_botlevel(&u.uz)) mkstairs(somex(croom), somey(croom), 0, croom); /* down */ if (nroom > 1) { troom = croom; croom = &rooms[rn2(nroom - 1)]; if (croom == troom) croom++; } if (u.uz.dlevel != 1) { xchar sx, sy; do { sx = somex(croom); sy = somey(croom); } while (occupied(sx, sy)); mkstairs(sx, sy, 1, croom); /* up */ } branchp = Is_branchlev(&u.uz); /* possible dungeon branch */ room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed to allow a random special room */ if (Is_rogue_level(&u.uz)) goto skip0; makecorridors(); make_niches(); /* make a secret treasure vault, not connected to the rest */ if (do_vault()) { xchar w, h; debugpline0("trying to make a vault..."); w = 1; h = 1; if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) { fill_vault: add_room(vault_x, vault_y, vault_x + w, vault_y + h, TRUE, VAULT, FALSE); level.flags.has_vault = 1; ++room_threshold; fill_room(&rooms[nroom - 1], FALSE); mk_knox_portal(vault_x + w, vault_y + h); if (!level.flags.noteleport && !rn2(3)) makevtele(); } else if (rnd_rect() && create_vault()) { vault_x = rooms[nroom].lx; vault_y = rooms[nroom].ly; if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) goto fill_vault; else rooms[nroom].hx = -1; } } { register int u_depth = depth(&u.uz); if (wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else if (u_depth > 1 && u_depth < depth(&medusa_level) && nroom >= room_threshold && rn2(u_depth) < 3) mkroom(SHOPBASE); else if (u_depth > 4 && !rn2(6)) mkroom(COURT); else if (u_depth > 5 && !rn2(8) && !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL); else if (u_depth > 6 && !rn2(7)) mkroom(ZOO); else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE); else if (u_depth > 9 && !rn2(5) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE); else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE); else if (u_depth > 12 && !rn2(8) && antholemon()) mkroom(ANTHOLE); else if (u_depth > 14 && !rn2(4) && !(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS); else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP); else if (u_depth > 16 && !rn2(8) && !(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST); } skip0: /* Place multi-dungeon branch. */ place_branch(branchp, 0, 0); /* for each room: put things inside */ for (croom = rooms; croom->hx > 0; croom++) { if (croom->rtype != OROOM) continue; /* put a sleeping monster inside */ /* Note: monster may be on the stairs. This cannot be avoided: maybe the player fell through a trap door while a monster was on the stairs. Conclusion: we have to check for monsters on the stairs anyway. */ if (u.uhave.amulet || !rn2(3)) { x = somex(croom); y = somey(croom); tmonst = makemon((struct permonst *) 0, x, y, NO_MM_FLAGS); if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] && !occupied(x, y)) (void) maketrap(x, y, WEB); } /* put traps and mimics inside */ x = 8 - (level_difficulty() / 6); if (x <= 1) x = 2; while (!rn2(x)) mktrap(0, 0, croom, (coord *) 0); if (!rn2(3)) (void) mkgold(0L, somex(croom), somey(croom)); if (Is_rogue_level(&u.uz)) goto skip_nonrogue; if (!rn2(10)) mkfount(0, croom); if (!rn2(60)) mksink(croom); if (!rn2(60)) mkaltar(croom); x = 80 - (depth(&u.uz) * 2); if (x < 2) x = 2; if (!rn2(x)) mkgrave(croom); /* put statues inside */ if (!rn2(20)) (void) mkcorpstat(STATUE, (struct monst *) 0, (struct permonst *) 0, somex(croom), somey(croom), CORPSTAT_INIT); /* put box/chest inside; * 40% chance for at least 1 box, regardless of number * of rooms; about 5 - 7.5% for 2 boxes, least likely * when few rooms; chance for 3 or more is negligible. */ if (!rn2(nroom * 5 / 2)) (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, somex(croom), somey(croom), TRUE, FALSE); /* maybe make some graffiti */ if (!rn2(27 + 3 * abs(depth(&u.uz)))) { char buf[BUFSZ]; const char *mesg = random_engraving(buf); if (mesg) { do { x = somex(croom); y = somey(croom); } while (levl[x][y].typ != ROOM && !rn2(40)); if (!(IS_POOL(levl[x][y].typ) || IS_FURNITURE(levl[x][y].typ))) make_engr_at(x, y, mesg, 0L, MARK); } } skip_nonrogue: if (!rn2(3)) { (void) mkobj_at(0, somex(croom), somey(croom), TRUE); tryct = 0; while (!rn2(5)) { if (++tryct > 100) { impossible("tryct overflow4"); break; } (void) mkobj_at(0, somex(croom), somey(croom), TRUE); } } } } /* * Place deposits of minerals (gold and misc gems) in the stone * surrounding the rooms on the map. * Also place kelp in water. * mineralize(-1, -1, -1, -1, FALSE); => "default" behaviour */ void mineralize(kelp_pool, kelp_moat, goldprob, gemprob, skip_lvl_checks) int kelp_pool, kelp_moat, goldprob, gemprob; boolean skip_lvl_checks; { s_level *sp; struct obj *otmp; int x, y, cnt; if (kelp_pool < 0) kelp_pool = 10; if (kelp_moat < 0) kelp_moat = 30; /* Place kelp, except on the plane of water */ if (!skip_lvl_checks && In_endgame(&u.uz)) return; for (x = 2; x < (COLNO - 2); x++) for (y = 1; y < (ROWNO - 1); y++) if ((kelp_pool && levl[x][y].typ == POOL && !rn2(kelp_pool)) || (kelp_moat && levl[x][y].typ == MOAT && !rn2(kelp_moat))) (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE); /* determine if it is even allowed; almost all special levels are excluded */ if (!skip_lvl_checks && (In_hell(&u.uz) || In_V_tower(&u.uz) || Is_rogue_level(&u.uz) || level.flags.arboreal || ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz) && (!In_mines(&u.uz) || sp->flags.town)))) return; /* basic level-related probabilities */ if (goldprob < 0) goldprob = 20 + depth(&u.uz) / 3; if (gemprob < 0) gemprob = goldprob / 4; /* mines have ***MORE*** goodies - otherwise why mine? */ if (!skip_lvl_checks) { if (In_mines(&u.uz)) { goldprob *= 2; gemprob *= 3; } else if (In_quest(&u.uz)) { goldprob /= 4; gemprob /= 6; } } /* * Seed rock areas with gold and/or gems. * We use fairly low level object handling to avoid unnecessary * overhead from placing things in the floor chain prior to burial. */ for (x = 2; x < (COLNO - 2); x++) for (y = 1; y < (ROWNO - 1); y++) if (levl[x][y + 1].typ != STONE) { /* spot not eligible */ y += 2; /* next two spots aren't eligible either */ } else if (levl[x][y].typ != STONE) { /* this spot not eligible */ y += 1; /* next spot isn't eligible either */ } else if (!(levl[x][y].wall_info & W_NONDIGGABLE) && levl[x][y - 1].typ == STONE && levl[x + 1][y - 1].typ == STONE && levl[x - 1][y - 1].typ == STONE && levl[x + 1][y].typ == STONE && levl[x - 1][y].typ == STONE && levl[x + 1][y + 1].typ == STONE && levl[x - 1][y + 1].typ == STONE) { if (rn2(1000) < goldprob) { if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) { otmp->ox = x, otmp->oy = y; otmp->quan = 1L + rnd(goldprob * 3); otmp->owt = weight(otmp); if (!rn2(3)) add_to_buried(otmp); else place_object(otmp, x, y); } } if (rn2(1000) < gemprob) { for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--) if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) { if (otmp->otyp == ROCK) { dealloc_obj(otmp); /* discard it */ } else { otmp->ox = x, otmp->oy = y; if (!rn2(3)) add_to_buried(otmp); else place_object(otmp, x, y); } } } } } void mklev() { struct mkroom *croom; int ridx; init_mapseen(&u.uz); if (getbones()) return; in_mklev = TRUE; makelevel(); bound_digging(); mineralize(-1, -1, -1, -1, FALSE); in_mklev = FALSE; /* has_morgue gets cleared once morgue is entered; graveyard stays set (graveyard might already be set even when has_morgue is clear [see fixup_special()], so don't update it unconditionally) */ if (level.flags.has_morgue) level.flags.graveyard = 1; if (!level.flags.is_maze_lev) { for (croom = &rooms[0]; croom != &rooms[nroom]; croom++) #ifdef SPECIALIZATION topologize(croom, FALSE); #else topologize(croom); #endif } set_wall_state(); /* for many room types, rooms[].rtype is zeroed once the room has been entered; rooms[].orig_rtype always retains original rtype value */ for (ridx = 0; ridx < SIZE(rooms); ridx++) rooms[ridx].orig_rtype = rooms[ridx].rtype; } void #ifdef SPECIALIZATION topologize(croom, do_ordinary) struct mkroom *croom; boolean do_ordinary; #else topologize(croom) struct mkroom *croom; #endif { register int x, y, roomno = (int) ((croom - rooms) + ROOMOFFSET); int lowx = croom->lx, lowy = croom->ly; int hix = croom->hx, hiy = croom->hy; #ifdef SPECIALIZATION schar rtype = croom->rtype; #endif int subindex, nsubrooms = croom->nsubrooms; /* skip the room if already done; i.e. a shop handled out of order */ /* also skip if this is non-rectangular (it _must_ be done already) */ if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular) return; #ifdef SPECIALIZATION if (Is_rogue_level(&u.uz)) do_ordinary = TRUE; /* vision routine helper */ if ((rtype != OROOM) || do_ordinary) #endif { /* do innards first */ for (x = lowx; x <= hix; x++) for (y = lowy; y <= hiy; y++) #ifdef SPECIALIZATION if (rtype == OROOM) levl[x][y].roomno = NO_ROOM; else #endif levl[x][y].roomno = roomno; /* top and bottom edges */ for (x = lowx - 1; x <= hix + 1; x++) for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) { levl[x][y].edge = 1; if (levl[x][y].roomno) levl[x][y].roomno = SHARED; else levl[x][y].roomno = roomno; } /* sides */ for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2)) for (y = lowy; y <= hiy; y++) { levl[x][y].edge = 1; if (levl[x][y].roomno) levl[x][y].roomno = SHARED; else levl[x][y].roomno = roomno; } } /* subrooms */ for (subindex = 0; subindex < nsubrooms; subindex++) #ifdef SPECIALIZATION topologize(croom->sbrooms[subindex], (boolean) (rtype != OROOM)); #else topologize(croom->sbrooms[subindex]); #endif } /* Find an unused room for a branch location. */ STATIC_OVL struct mkroom * find_branch_room(mp) coord *mp; { struct mkroom *croom = 0; if (nroom == 0) { mazexy(mp); /* already verifies location */ } else { /* not perfect - there may be only one stairway */ if (nroom > 2) { int tryct = 0; do croom = &rooms[rn2(nroom)]; while ((croom == dnstairs_room || croom == upstairs_room || croom->rtype != OROOM) && (++tryct < 100)); } else croom = &rooms[rn2(nroom)]; do { if (!somexy(croom, mp)) impossible("Can't place branch!"); } while (occupied(mp->x, mp->y) || (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM)); } return croom; } /* Find the room for (x,y). Return null if not in a room. */ STATIC_OVL struct mkroom * pos_to_room(x, y) xchar x, y; { int i; struct mkroom *curr; for (curr = rooms, i = 0; i < nroom; curr++, i++) if (inside_room(curr, x, y)) return curr; ; return (struct mkroom *) 0; } /* If given a branch, randomly place a special stair or portal. */ void place_branch(br, x, y) branch *br; /* branch to place */ xchar x, y; /* location */ { coord m; d_level *dest; boolean make_stairs; struct mkroom *br_room; /* * Return immediately if there is no branch to make or we have * already made one. This routine can be called twice when * a special level is loaded that specifies an SSTAIR location * as a favored spot for a branch. */ if (!br || made_branch) return; if (!x) { /* find random coordinates for branch */ br_room = find_branch_room(&m); x = m.x; y = m.y; } else { br_room = pos_to_room(x, y); } if (on_level(&br->end1, &u.uz)) { /* we're on end1 */ make_stairs = br->type != BR_NO_END1; dest = &br->end2; } else { /* we're on end2 */ make_stairs = br->type != BR_NO_END2; dest = &br->end1; } if (br->type == BR_PORTAL) { mkportal(x, y, dest->dnum, dest->dlevel); } else if (make_stairs) { sstairs.sx = x; sstairs.sy = y; sstairs.up = (char) on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up; assign_level(&sstairs.tolev, dest); sstairs_room = br_room; levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN; levl[x][y].typ = STAIRS; } /* * Set made_branch to TRUE even if we didn't make a stairwell (i.e. * make_stairs is false) since there is currently only one branch * per level, if we failed once, we're going to fail again on the * next call. */ made_branch = TRUE; } STATIC_OVL boolean bydoor(x, y) register xchar x, y; { register int typ; if (isok(x + 1, y)) { typ = levl[x + 1][y].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } if (isok(x - 1, y)) { typ = levl[x - 1][y].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } if (isok(x, y + 1)) { typ = levl[x][y + 1].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } if (isok(x, y - 1)) { typ = levl[x][y - 1].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } return FALSE; } /* see whether it is allowable to create a door at [x,y] */ int okdoor(x, y) xchar x, y; { boolean near_door = bydoor(x, y); return ((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) && doorindex < DOORMAX && !near_door); } void dodoor(x, y, aroom) int x, y; struct mkroom *aroom; { if (doorindex >= DOORMAX) { impossible("DOORMAX exceeded?"); return; } dosdoor(x, y, aroom, rn2(8) ? DOOR : SDOOR); } boolean occupied(x, y) register xchar x, y; { return (boolean) (t_at(x, y) || IS_FURNITURE(levl[x][y].typ) || is_lava(x, y) || is_pool(x, y) || invocation_pos(x, y)); } /* make a trap somewhere (in croom if mazeflag = 0 && !tm) */ /* if tm != null, make trap at that location */ void mktrap(num, mazeflag, croom, tm) int num, mazeflag; struct mkroom *croom; coord *tm; { register int kind; coord m; /* no traps in pools */ if (tm && is_pool(tm->x, tm->y)) return; if (num > 0 && num < TRAPNUM) { kind = num; } else if (Is_rogue_level(&u.uz)) { switch (rn2(7)) { default: kind = BEAR_TRAP; break; /* 0 */ case 1: kind = ARROW_TRAP; break; case 2: kind = DART_TRAP; break; case 3: kind = TRAPDOOR; break; case 4: kind = PIT; break; case 5: kind = SLP_GAS_TRAP; break; case 6: kind = RUST_TRAP; break; } } else if (Inhell && !rn2(5)) { /* bias the frequency of fire traps in Gehennom */ kind = FIRE_TRAP; } else { unsigned lvl = level_difficulty(); do { kind = rnd(TRAPNUM - 1); /* reject "too hard" traps */ switch (kind) { case MAGIC_PORTAL: case VIBRATING_SQUARE: kind = NO_TRAP; break; case ROLLING_BOULDER_TRAP: case SLP_GAS_TRAP: if (lvl < 2) kind = NO_TRAP; break; case LEVEL_TELEP: if (lvl < 5 || level.flags.noteleport) kind = NO_TRAP; break; case SPIKED_PIT: if (lvl < 5) kind = NO_TRAP; break; case LANDMINE: if (lvl < 6) kind = NO_TRAP; break; case WEB: if (lvl < 7) kind = NO_TRAP; break; case STATUE_TRAP: case POLY_TRAP: if (lvl < 8) kind = NO_TRAP; break; case FIRE_TRAP: if (!Inhell) kind = NO_TRAP; break; case TELEP_TRAP: if (level.flags.noteleport) kind = NO_TRAP; break; case HOLE: /* make these much less often than other traps */ if (rn2(7)) kind = NO_TRAP; break; } } while (kind == NO_TRAP); } if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz)) kind = ROCKTRAP; if (tm) m = *tm; else { register int tryct = 0; boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT || kind == TRAPDOOR || kind == HOLE); do { if (++tryct > 200) return; if (mazeflag) mazexy(&m); else if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || (avoid_boulder && sobj_at(BOULDER, m.x, m.y))); } (void) maketrap(m.x, m.y, kind); if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y, NO_MM_FLAGS); } void mkstairs(x, y, up, croom) xchar x, y; char up; struct mkroom *croom; { if (!x) { impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y); return; } /* * We can't make a regular stair off an end of the dungeon. This * attempt can happen when a special level is placed at an end and * has an up or down stair specified in its description file. */ if ((dunlev(&u.uz) == 1 && up) || (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up)) return; if (up) { xupstair = x; yupstair = y; upstairs_room = croom; } else { xdnstair = x; ydnstair = y; dnstairs_room = croom; } levl[x][y].typ = STAIRS; levl[x][y].ladder = up ? LA_UP : LA_DOWN; } STATIC_OVL void mkfount(mazeflag, croom) int mazeflag; struct mkroom *croom; { coord m; register int tryct = 0; do { if (++tryct > 200) return; if (mazeflag) mazexy(&m); else if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put a fountain at m.x, m.y */ levl[m.x][m.y].typ = FOUNTAIN; /* Is it a "blessed" fountain? (affects drinking from fountain) */ if (!rn2(7)) levl[m.x][m.y].blessedftn = 1; level.flags.nfountains++; } STATIC_OVL void mksink(croom) struct mkroom *croom; { coord m; register int tryct = 0; do { if (++tryct > 200) return; if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put a sink at m.x, m.y */ levl[m.x][m.y].typ = SINK; level.flags.nsinks++; } STATIC_OVL void mkaltar(croom) struct mkroom *croom; { coord m; register int tryct = 0; aligntyp al; if (croom->rtype != OROOM) return; do { if (++tryct > 200) return; if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put an altar at m.x, m.y */ levl[m.x][m.y].typ = ALTAR; /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */ al = rn2((int) A_LAWFUL + 2) - 1; levl[m.x][m.y].altarmask = Align2amask(al); } static void mkgrave(croom) struct mkroom *croom; { coord m; register int tryct = 0; register struct obj *otmp; boolean dobell = !rn2(10); if (croom->rtype != OROOM) return; do { if (++tryct > 200) return; if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put a grave at m.x, m.y */ make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0); /* Possibly fill it with objects */ if (!rn2(3)) (void) mkgold(0L, m.x, m.y); for (tryct = rn2(5); tryct; tryct--) { otmp = mkobj(RANDOM_CLASS, TRUE); if (!otmp) return; curse(otmp); otmp->ox = m.x; otmp->oy = m.y; add_to_buried(otmp); } /* Leave a bell, in case we accidentally buried someone alive */ if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE); return; } /* maze levels have slightly different constraints from normal levels */ #define x_maze_min 2 #define y_maze_min 2 /* * Major level transmutation: add a set of stairs (to the Sanctum) after * an earthquake that leaves behind a a new topology, centered at inv_pos. * Assumes there are no rooms within the invocation area and that inv_pos * is not too close to the edge of the map. Also assume the hero can see, * which is guaranteed for normal play due to the fact that sight is needed * to read the Book of the Dead. */ void mkinvokearea() { int dist; xchar xmin = inv_pos.x, xmax = inv_pos.x; xchar ymin = inv_pos.y, ymax = inv_pos.y; register xchar i; pline_The("floor shakes violently under you!"); pline_The("walls around you begin to bend and crumble!"); display_nhwindow(WIN_MESSAGE, TRUE); /* any trap hero is stuck in will be going away now */ if (u.utrap) { u.utrap = 0; if (u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); } mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */ for (dist = 1; dist < 7; dist++) { xmin--; xmax++; /* top and bottom */ if (dist != 3) { /* the area is wider that it is high */ ymin--; ymax++; for (i = xmin + 1; i < xmax; i++) { mkinvpos(i, ymin, dist); mkinvpos(i, ymax, dist); } } /* left and right */ for (i = ymin; i <= ymax; i++) { mkinvpos(xmin, i, dist); mkinvpos(xmax, i, dist); } flush_screen(1); /* make sure the new glyphs shows up */ delay_output(); } You("are standing at the top of a stairwell leading down!"); mkstairs(u.ux, u.uy, 0, (struct mkroom *) 0); /* down */ newsym(u.ux, u.uy); vision_full_recalc = 1; /* everything changed */ } /* Change level topology. Boulders in the vicinity are eliminated. * Temporarily overrides vision in the name of a nice effect. */ STATIC_OVL void mkinvpos(x, y, dist) xchar x, y; int dist; { struct trap *ttmp; struct obj *otmp; boolean make_rocks; register struct rm *lev = &levl[x][y]; /* clip at existing map borders if necessary */ if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1, x_maze_max - 1, y_maze_max - 1)) { /* only outermost 2 columns and/or rows may be truncated due to edge */ if (dist < (7 - 2)) panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist); return; } /* clear traps */ if ((ttmp = t_at(x, y)) != 0) deltrap(ttmp); /* clear boulders; leave some rocks for non-{moat|trap} locations */ make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE; while ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (make_rocks) { fracture_rock(otmp); make_rocks = FALSE; /* don't bother with more rocks */ } else { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } } unblock_point(x, y); /* make sure vision knows this location is open */ /* fake out saved state */ lev->seenv = 0; lev->doormask = 0; if (dist < 6) lev->lit = TRUE; lev->waslit = TRUE; lev->horizontal = FALSE; /* short-circuit vision recalc */ viz_array[y][x] = (dist < 6) ? (IN_SIGHT | COULD_SEE) : COULD_SEE; switch (dist) { case 1: /* fire traps */ if (is_pool(x, y)) break; lev->typ = ROOM; ttmp = maketrap(x, y, FIRE_TRAP); if (ttmp) ttmp->tseen = TRUE; break; case 0: /* lit room locations */ case 2: case 3: case 6: /* unlit room locations */ lev->typ = ROOM; break; case 4: /* pools (aka a wide moat) */ case 5: lev->typ = MOAT; /* No kelp! */ break; default: impossible("mkinvpos called with dist %d", dist); break; } /* display new value of position; could have a monster/object on it */ newsym(x, y); } /* * The portal to Ludios is special. The entrance can only occur within a * vault in the main dungeon at a depth greater than 10. The Ludios branch * structure reflects this by having a bogus "source" dungeon: the value * of n_dgns (thus, Is_branchlev() will never find it). * * Ludios will remain isolated until the branch is corrected by this function. */ STATIC_OVL void mk_knox_portal(x, y) xchar x, y; { extern int n_dgns; /* from dungeon.c */ d_level *source; branch *br; schar u_depth; br = dungeon_branch("Fort Ludios"); if (on_level(&knox_level, &br->end1)) { source = &br->end2; } else { /* disallow Knox branch on a level with one branch already */ if (Is_branchlev(&u.uz)) return; source = &br->end1; } /* Already set or 2/3 chance of deferring until a later level. */ if (source->dnum < n_dgns || (rn2(3) && !wizard)) return; if (!(u.uz.dnum == oracle_level.dnum /* in main dungeon */ && !at_dgn_entrance("The Quest") /* but not Quest's entry */ && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */ && u_depth < depth(&medusa_level))) /* and above Medusa */ return; /* Adjust source to be current level and re-insert branch. */ *source = u.uz; insert_branch(br, TRUE); debugpline0("Made knox portal."); place_branch(br, x, y); } /*mklev.c*/ nethack-3.6.0/src/mkmap.c0000664000076400007660000003667612624166366014233 0ustar paxedpaxed/* NetHack 3.6 mkmap.c $NHDT-Date: 1432512767 2015/05/25 00:12:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "sp_lev.h" #define HEIGHT (ROWNO - 1) #define WIDTH (COLNO - 2) STATIC_DCL void FDECL(init_map, (SCHAR_P)); STATIC_DCL void FDECL(init_fill, (SCHAR_P, SCHAR_P)); STATIC_DCL schar FDECL(get_map, (int, int, SCHAR_P)); STATIC_DCL void FDECL(pass_one, (SCHAR_P, SCHAR_P)); STATIC_DCL void FDECL(pass_two, (SCHAR_P, SCHAR_P)); STATIC_DCL void FDECL(pass_three, (SCHAR_P, SCHAR_P)); STATIC_DCL void NDECL(wallify_map); STATIC_DCL void FDECL(join_map, (SCHAR_P, SCHAR_P)); STATIC_DCL void FDECL(finish_map, (SCHAR_P, SCHAR_P, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(remove_room, (unsigned)); void FDECL(mkmap, (lev_init *)); static char *new_locations; int min_rx, max_rx, min_ry, max_ry; /* rectangle bounds for regions */ static int n_loc_filled; STATIC_OVL void init_map(bg_typ) schar bg_typ; { register int i, j; for (i = 1; i < COLNO; i++) for (j = 0; j < ROWNO; j++) levl[i][j].typ = bg_typ; } STATIC_OVL void init_fill(bg_typ, fg_typ) schar bg_typ, fg_typ; { register int i, j; long limit, count; limit = (WIDTH * HEIGHT * 2) / 5; count = 0; while (count < limit) { i = rn1(WIDTH - 1, 2); j = rnd(HEIGHT - 1); if (levl[i][j].typ == bg_typ) { levl[i][j].typ = fg_typ; count++; } } } STATIC_OVL schar get_map(col, row, bg_typ) int col, row; schar bg_typ; { if (col <= 0 || row < 0 || col > WIDTH || row >= HEIGHT) return bg_typ; return levl[col][row].typ; } static int dirs[16] = { -1, -1 /**/, -1, 0 /**/, -1, 1 /**/, 0, -1 /**/, 0, 1 /**/, 1, -1 /**/, 1, 0 /**/, 1, 1 }; STATIC_OVL void pass_one(bg_typ, fg_typ) schar bg_typ, fg_typ; { register int i, j; short count, dr; for (i = 2; i <= WIDTH; i++) for (j = 1; j < HEIGHT; j++) { for (count = 0, dr = 0; dr < 8; dr++) if (get_map(i + dirs[dr * 2], j + dirs[(dr * 2) + 1], bg_typ) == fg_typ) count++; switch (count) { case 0: /* death */ case 1: case 2: levl[i][j].typ = bg_typ; break; case 5: case 6: case 7: case 8: levl[i][j].typ = fg_typ; break; default: break; } } } #define new_loc(i, j) *(new_locations + ((j) * (WIDTH + 1)) + (i)) STATIC_OVL void pass_two(bg_typ, fg_typ) schar bg_typ, fg_typ; { register int i, j; short count, dr; for (i = 2; i <= WIDTH; i++) for (j = 1; j < HEIGHT; j++) { for (count = 0, dr = 0; dr < 8; dr++) if (get_map(i + dirs[dr * 2], j + dirs[(dr * 2) + 1], bg_typ) == fg_typ) count++; if (count == 5) new_loc(i, j) = bg_typ; else new_loc(i, j) = get_map(i, j, bg_typ); } for (i = 2; i <= WIDTH; i++) for (j = 1; j < HEIGHT; j++) levl[i][j].typ = new_loc(i, j); } STATIC_OVL void pass_three(bg_typ, fg_typ) schar bg_typ, fg_typ; { register int i, j; short count, dr; for (i = 2; i <= WIDTH; i++) for (j = 1; j < HEIGHT; j++) { for (count = 0, dr = 0; dr < 8; dr++) if (get_map(i + dirs[dr * 2], j + dirs[(dr * 2) + 1], bg_typ) == fg_typ) count++; if (count < 3) new_loc(i, j) = bg_typ; else new_loc(i, j) = get_map(i, j, bg_typ); } for (i = 2; i <= WIDTH; i++) for (j = 1; j < HEIGHT; j++) levl[i][j].typ = new_loc(i, j); } /* * use a flooding algorithm to find all locations that should * have the same rm number as the current location. * if anyroom is TRUE, use IS_ROOM to check room membership instead of * exactly matching levl[sx][sy].typ and walls are included as well. */ void flood_fill_rm(sx, sy, rmno, lit, anyroom) int sx; register int sy; register int rmno; boolean lit; boolean anyroom; { register int i; int nx; schar fg_typ = levl[sx][sy].typ; /* back up to find leftmost uninitialized location */ while (sx > 0 && (anyroom ? IS_ROOM(levl[sx][sy].typ) : levl[sx][sy].typ == fg_typ) && (int) levl[sx][sy].roomno != rmno) sx--; sx++; /* compensate for extra decrement */ /* assume sx,sy is valid */ if (sx < min_rx) min_rx = sx; if (sy < min_ry) min_ry = sy; for (i = sx; i <= WIDTH && levl[i][sy].typ == fg_typ; i++) { levl[i][sy].roomno = rmno; levl[i][sy].lit = lit; if (anyroom) { /* add walls to room as well */ register int ii, jj; for (ii = (i == sx ? i - 1 : i); ii <= i + 1; ii++) for (jj = sy - 1; jj <= sy + 1; jj++) if (isok(ii, jj) && (IS_WALL(levl[ii][jj].typ) || IS_DOOR(levl[ii][jj].typ) || levl[ii][jj].typ == SDOOR)) { levl[ii][jj].edge = 1; if (lit) levl[ii][jj].lit = lit; if ((int) levl[ii][jj].roomno != rmno) levl[ii][jj].roomno = SHARED; } } n_loc_filled++; } nx = i; if (isok(sx, sy - 1)) { for (i = sx; i < nx; i++) if (levl[i][sy - 1].typ == fg_typ) { if ((int) levl[i][sy - 1].roomno != rmno) flood_fill_rm(i, sy - 1, rmno, lit, anyroom); } else { if ((i > sx || isok(i - 1, sy - 1)) && levl[i - 1][sy - 1].typ == fg_typ) { if ((int) levl[i - 1][sy - 1].roomno != rmno) flood_fill_rm(i - 1, sy - 1, rmno, lit, anyroom); } if ((i < nx - 1 || isok(i + 1, sy - 1)) && levl[i + 1][sy - 1].typ == fg_typ) { if ((int) levl[i + 1][sy - 1].roomno != rmno) flood_fill_rm(i + 1, sy - 1, rmno, lit, anyroom); } } } if (isok(sx, sy + 1)) { for (i = sx; i < nx; i++) if (levl[i][sy + 1].typ == fg_typ) { if ((int) levl[i][sy + 1].roomno != rmno) flood_fill_rm(i, sy + 1, rmno, lit, anyroom); } else { if ((i > sx || isok(i - 1, sy + 1)) && levl[i - 1][sy + 1].typ == fg_typ) { if ((int) levl[i - 1][sy + 1].roomno != rmno) flood_fill_rm(i - 1, sy + 1, rmno, lit, anyroom); } if ((i < nx - 1 || isok(i + 1, sy + 1)) && levl[i + 1][sy + 1].typ == fg_typ) { if ((int) levl[i + 1][sy + 1].roomno != rmno) flood_fill_rm(i + 1, sy + 1, rmno, lit, anyroom); } } } if (nx > max_rx) max_rx = nx - 1; /* nx is just past valid region */ if (sy > max_ry) max_ry = sy; } /* * If we have drawn a map without walls, this allows us to * auto-magically wallify it. Taken from lev_main.c. */ STATIC_OVL void wallify_map() { int x, y, xx, yy; for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (levl[x][y].typ == STONE) { for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++) if (isok(xx, yy) && levl[xx][yy].typ == ROOM) { if (yy != y) levl[x][y].typ = HWALL; else levl[x][y].typ = VWALL; } } } STATIC_OVL void join_map(bg_typ, fg_typ) schar bg_typ, fg_typ; { register struct mkroom *croom, *croom2; register int i, j; int sx, sy; coord sm, em; /* first, use flood filling to find all of the regions that need joining */ for (i = 2; i <= WIDTH; i++) for (j = 1; j < HEIGHT; j++) { if (levl[i][j].typ == fg_typ && levl[i][j].roomno == NO_ROOM) { min_rx = max_rx = i; min_ry = max_ry = j; n_loc_filled = 0; flood_fill_rm(i, j, nroom + ROOMOFFSET, FALSE, FALSE); if (n_loc_filled > 3) { add_room(min_rx, min_ry, max_rx, max_ry, FALSE, OROOM, TRUE); rooms[nroom - 1].irregular = TRUE; if (nroom >= (MAXNROFROOMS * 2)) goto joinm; } else { /* * it's a tiny hole; erase it from the map to avoid * having the player end up here with no way out. */ for (sx = min_rx; sx <= max_rx; sx++) for (sy = min_ry; sy <= max_ry; sy++) if ((int) levl[sx][sy].roomno == nroom + ROOMOFFSET) { levl[sx][sy].typ = bg_typ; levl[sx][sy].roomno = NO_ROOM; } } } } joinm: /* * Ok, now we can actually join the regions with fg_typ's. * The rooms are already sorted due to the previous loop, * so don't call sort_rooms(), which can screw up the roomno's * validity in the levl structure. */ for (croom = &rooms[0], croom2 = croom + 1; croom2 < &rooms[nroom];) { /* pick random starting and end locations for "corridor" */ if (!somexy(croom, &sm) || !somexy(croom2, &em)) { /* ack! -- the level is going to be busted */ /* arbitrarily pick centers of both rooms and hope for the best */ impossible("No start/end room loc in join_map."); sm.x = croom->lx + ((croom->hx - croom->lx) / 2); sm.y = croom->ly + ((croom->hy - croom->ly) / 2); em.x = croom2->lx + ((croom2->hx - croom2->lx) / 2); em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2); } (void) dig_corridor(&sm, &em, FALSE, fg_typ, bg_typ); /* choose next region to join */ /* only increment croom if croom and croom2 are non-overlapping */ if (croom2->lx > croom->hx || ((croom2->ly > croom->hy || croom2->hy < croom->ly) && rn2(3))) { croom = croom2; } croom2++; /* always increment the next room */ } } STATIC_OVL void finish_map(fg_typ, bg_typ, lit, walled, icedpools) schar fg_typ, bg_typ; boolean lit, walled, icedpools; { int i, j; if (walled) wallify_map(); if (lit) { for (i = 1; i < COLNO; i++) for (j = 0; j < ROWNO; j++) if ((!IS_ROCK(fg_typ) && levl[i][j].typ == fg_typ) || (!IS_ROCK(bg_typ) && levl[i][j].typ == bg_typ) || (bg_typ == TREE && levl[i][j].typ == bg_typ) || (walled && IS_WALL(levl[i][j].typ))) levl[i][j].lit = TRUE; for (i = 0; i < nroom; i++) rooms[i].rlit = 1; } /* light lava even if everything's otherwise unlit; ice might be frozen pool rather than frozen moat */ for (i = 1; i < COLNO; i++) for (j = 0; j < ROWNO; j++) { if (levl[i][j].typ == LAVAPOOL) levl[i][j].lit = TRUE; else if (levl[i][j].typ == ICE) levl[i][j].icedpool = icedpools ? ICED_POOL : ICED_MOAT; } } /* * When level processed by join_map is overlaid by a MAP, some rooms may no * longer be valid. All rooms in the region lx <= x < hx, ly <= y < hy are * removed. Rooms partially in the region are truncated. This function * must be called before the REGIONs or ROOMs of the map are processed, or * those rooms will be removed as well. Assumes roomno fields in the * region are already cleared, and roomno and irregular fields outside the * region are all set. */ void remove_rooms(lx, ly, hx, hy) int lx, ly, hx, hy; { int i; struct mkroom *croom; for (i = nroom - 1; i >= 0; --i) { croom = &rooms[i]; if (croom->hx < lx || croom->lx >= hx || croom->hy < ly || croom->ly >= hy) continue; /* no overlap */ if (croom->lx < lx || croom->hx >= hx || croom->ly < ly || croom->hy >= hy) { /* partial overlap */ /* TODO: ensure remaining parts of room are still joined */ if (!croom->irregular) impossible("regular room in joined map"); } else { /* total overlap, remove the room */ remove_room((unsigned) i); } } } /* * Remove roomno from the rooms array, decrementing nroom. Also updates * all level roomno values of affected higher numbered rooms. Assumes * level structure contents corresponding to roomno have already been reset. * Currently handles only the removal of rooms that have no subrooms. */ STATIC_OVL void remove_room(roomno) unsigned roomno; { struct mkroom *croom = &rooms[roomno]; struct mkroom *maxroom = &rooms[--nroom]; int i, j; unsigned oroomno; if (croom != maxroom) { /* since the order in the array only matters for making corridors, * copy the last room over the one being removed on the assumption * that corridors have already been dug. */ (void) memcpy((genericptr_t) croom, (genericptr_t) maxroom, sizeof(struct mkroom)); /* since maxroom moved, update affected level roomno values */ oroomno = nroom + ROOMOFFSET; roomno += ROOMOFFSET; for (i = croom->lx; i <= croom->hx; ++i) for (j = croom->ly; j <= croom->hy; ++j) { if (levl[i][j].roomno == oroomno) levl[i][j].roomno = roomno; } } maxroom->hx = -1; /* just like add_room */ } #define N_P1_ITER 1 /* tune map generation via this value */ #define N_P2_ITER 1 /* tune map generation via this value */ #define N_P3_ITER 2 /* tune map smoothing via this value */ void mkmap(init_lev) lev_init *init_lev; { schar bg_typ = init_lev->bg, fg_typ = init_lev->fg; boolean smooth = init_lev->smoothed, join = init_lev->joined; xchar lit = init_lev->lit, walled = init_lev->walled; int i; if (lit < 0) lit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? 1 : 0; new_locations = (char *) alloc((WIDTH + 1) * HEIGHT); init_map(bg_typ); init_fill(bg_typ, fg_typ); for (i = 0; i < N_P1_ITER; i++) pass_one(bg_typ, fg_typ); for (i = 0; i < N_P2_ITER; i++) pass_two(bg_typ, fg_typ); if (smooth) for (i = 0; i < N_P3_ITER; i++) pass_three(bg_typ, fg_typ); if (join) join_map(bg_typ, fg_typ); finish_map(fg_typ, bg_typ, (boolean) lit, (boolean) walled, init_lev->icedpools); /* a walled, joined level is cavernous, not mazelike -dlc */ if (walled && join) { level.flags.is_maze_lev = FALSE; level.flags.is_cavernous_lev = TRUE; } free(new_locations); } /*mkmap.c*/ nethack-3.6.0/src/mkmaze.c0000664000076400007660000013336312631241231014360 0ustar paxedpaxed/* NetHack 3.6 mkmaze.c $NHDT-Date: 1449269918 2015/12/04 22:58:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "sp_lev.h" #include "lev.h" /* save & restore info */ /* from sp_lev.c, for fixup_special() */ extern lev_region *lregions; extern int num_lregions; STATIC_DCL boolean FDECL(iswall, (int, int)); STATIC_DCL boolean FDECL(iswall_or_stone, (int, int)); STATIC_DCL boolean FDECL(is_solid, (int, int)); STATIC_DCL int FDECL(extend_spine, (int[3][3], int, int, int)); STATIC_DCL boolean FDECL(okay, (int, int, int)); STATIC_DCL void FDECL(maze0xy, (coord *)); STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, BOOLEAN_P, d_level *)); STATIC_DCL void NDECL(fixup_special); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); /* adjust a coordinate one step in the specified direction */ #define mz_move(X, Y, dir) \ do { \ switch (dir) { \ case 0: --(Y); break; \ case 1: (X)++; break; \ case 2: (Y)++; break; \ case 3: --(X); break; \ default: panic("mz_move: bad direction %d", dir); \ } \ } while (0) STATIC_OVL boolean iswall(x, y) int x, y; { register int type; if (!isok(x, y)) return FALSE; type = levl[x][y].typ; return (boolean) (IS_WALL(type) || IS_DOOR(type) || type == SDOOR || type == IRONBARS); } STATIC_OVL boolean iswall_or_stone(x, y) int x, y; { register int type; /* out of bounds = stone */ if (!isok(x, y)) return TRUE; type = levl[x][y].typ; return (boolean) (type == STONE || IS_WALL(type) || IS_DOOR(type) || type == SDOOR || type == IRONBARS); } /* return TRUE if out of bounds, wall or rock */ STATIC_OVL boolean is_solid(x, y) int x, y; { return (boolean) (!isok(x, y) || IS_STWALL(levl[x][y].typ)); } /* * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend * a wall spine in the (dx,dy) direction. Return 0 otherwise. * * To extend a wall spine in that direction, first there must be a wall there. * Then, extend a spine unless the current position is surrounded by walls * in the direction given by (dx,dy). E.g. if 'x' is our location, 'W' * a wall, '.' a room, 'a' anything (we don't care), and our direction is * (0,1) - South or down - then: * * a a a * W x W This would not extend a spine from x down * W W W (a corridor of walls is formed). * * a a a * W x W This would extend a spine from x down. * . W W */ STATIC_OVL int extend_spine(locale, wall_there, dx, dy) int locale[3][3]; int wall_there, dx, dy; { int spine, nx, ny; nx = 1 + dx; ny = 1 + dy; if (wall_there) { /* wall in that direction */ if (dx) { if (locale[1][0] && locale[1][2] /* EW are wall/stone */ && locale[nx][0] && locale[nx][2]) { /* diag are wall/stone */ spine = 0; } else { spine = 1; } } else { /* dy */ if (locale[0][1] && locale[2][1] /* NS are wall/stone */ && locale[0][ny] && locale[2][ny]) { /* diag are wall/stone */ spine = 0; } else { spine = 1; } } } else { spine = 0; } return spine; } /* * Wall cleanup. This function has two purposes: (1) remove walls that * are totally surrounded by stone - they are redundant. (2) correct * the types so that they extend and connect to each other. */ void wallification(x1, y1, x2, y2) int x1, y1, x2, y2; { uchar type; register int x, y; struct rm *lev; int bits; int locale[3][3]; /* rock or wall status surrounding positions */ /* * Value 0 represents a free-standing wall. It could be anything, * so even though this table says VWALL, we actually leave whatever * typ was there alone. */ static xchar spine_array[16] = { VWALL, HWALL, HWALL, HWALL, VWALL, TRCORNER, TLCORNER, TDWALL, VWALL, BRCORNER, BLCORNER, TUWALL, VWALL, TLWALL, TRWALL, CROSSWALL }; /* sanity check on incoming variables */ if (x1 < 0 || x2 >= COLNO || x1 > x2 || y1 < 0 || y2 >= ROWNO || y1 > y2) panic("wallification: bad bounds (%d,%d) to (%d,%d)", x1, y1, x2, y2); /* Step 1: change walls surrounded by rock to rock. */ for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { lev = &levl[x][y]; type = lev->typ; if (IS_WALL(type) && type != DBWALL) { if (is_solid(x - 1, y - 1) && is_solid(x - 1, y) && is_solid(x - 1, y + 1) && is_solid(x, y - 1) && is_solid(x, y + 1) && is_solid(x + 1, y - 1) && is_solid(x + 1, y) && is_solid(x + 1, y + 1)) lev->typ = STONE; } } /* * Step 2: set the correct wall type. We can't combine steps * 1 and 2 into a single sweep because we depend on knowing if * the surrounding positions are stone. */ for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { lev = &levl[x][y]; type = lev->typ; if (!(IS_WALL(type) && type != DBWALL)) continue; /* set the locations TRUE if rock or wall or out of bounds */ locale[0][0] = iswall_or_stone(x - 1, y - 1); locale[1][0] = iswall_or_stone(x, y - 1); locale[2][0] = iswall_or_stone(x + 1, y - 1); locale[0][1] = iswall_or_stone(x - 1, y); locale[2][1] = iswall_or_stone(x + 1, y); locale[0][2] = iswall_or_stone(x - 1, y + 1); locale[1][2] = iswall_or_stone(x, y + 1); locale[2][2] = iswall_or_stone(x + 1, y + 1); /* determine if wall should extend to each direction NSEW */ bits = (extend_spine(locale, iswall(x, y - 1), 0, -1) << 3) | (extend_spine(locale, iswall(x, y + 1), 0, 1) << 2) | (extend_spine(locale, iswall(x + 1, y), 1, 0) << 1) | extend_spine(locale, iswall(x - 1, y), -1, 0); /* don't change typ if wall is free-standing */ if (bits) lev->typ = spine_array[bits]; } } STATIC_OVL boolean okay(x, y, dir) int x, y; register int dir; { mz_move(x, y, dir); mz_move(x, y, dir); if (x < 3 || y < 3 || x > x_maze_max || y > y_maze_max || levl[x][y].typ != 0) return FALSE; return TRUE; } /* find random starting point for maze generation */ STATIC_OVL void maze0xy(cc) coord *cc; { cc->x = 3 + 2 * rn2((x_maze_max >> 1) - 1); cc->y = 3 + 2 * rn2((y_maze_max >> 1) - 1); return; } /* * Bad if: * pos is occupied OR * pos is inside restricted region (lx,ly,hx,hy) OR * NOT (pos is corridor and a maze level OR pos is a room OR pos is air) */ boolean bad_location(x, y, lx, ly, hx, hy) xchar x, y; xchar lx, ly, hx, hy; { return (boolean) (occupied(x, y) || within_bounded_area(x, y, lx, ly, hx, hy) || !((levl[x][y].typ == CORR && level.flags.is_maze_lev) || levl[x][y].typ == ROOM || levl[x][y].typ == AIR)); } /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) and place something (based on rtype) in that region */ void place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev) xchar lx, ly, hx, hy; xchar nlx, nly, nhx, nhy; xchar rtype; d_level *lev; { int trycnt; boolean oneshot; xchar x, y; if (!lx) { /* default to whole level */ /* * if there are rooms and this a branch, let place_branch choose * the branch location (to avoid putting branches in corridors). */ if (rtype == LR_BRANCH && nroom) { place_branch(Is_branchlev(&u.uz), 0, 0); return; } lx = 1; hx = COLNO - 1; ly = 1; hy = ROWNO - 1; } /* first a probabilistic approach */ oneshot = (lx == hx && ly == hy); for (trycnt = 0; trycnt < 200; trycnt++) { x = rn1((hx - lx) + 1, lx); y = rn1((hy - ly) + 1, ly); if (put_lregion_here(x, y, nlx, nly, nhx, nhy, rtype, oneshot, lev)) return; } /* then a deterministic one */ oneshot = TRUE; for (x = lx; x <= hx; x++) for (y = ly; y <= hy; y++) if (put_lregion_here(x, y, nlx, nly, nhx, nhy, rtype, oneshot, lev)) return; impossible("Couldn't place lregion type %d!", rtype); } STATIC_OVL boolean put_lregion_here(x, y, nlx, nly, nhx, nhy, rtype, oneshot, lev) xchar x, y; xchar nlx, nly, nhx, nhy; xchar rtype; boolean oneshot; d_level *lev; { if (bad_location(x, y, nlx, nly, nhx, nhy)) { if (!oneshot) { return FALSE; /* caller should try again */ } else { /* Must make do with the only location possible; avoid failure due to a misplaced trap. It might still fail if there's a dungeon feature here. */ struct trap *t = t_at(x, y); if (t && t->ttyp != MAGIC_PORTAL && t->ttyp != VIBRATING_SQUARE) deltrap(t); if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE; } } switch (rtype) { case LR_TELE: case LR_UPTELE: case LR_DOWNTELE: /* "something" means the player in this case */ if (MON_AT(x, y)) { /* move the monster if no choice, or just try again */ if (oneshot) (void) rloc(m_at(x, y), FALSE); else return FALSE; } u_on_newpos(x, y); break; case LR_PORTAL: mkportal(x, y, lev->dnum, lev->dlevel); break; case LR_DOWNSTAIR: case LR_UPSTAIR: mkstairs(x, y, (char) rtype, (struct mkroom *) 0); break; case LR_BRANCH: place_branch(Is_branchlev(&u.uz), x, y); break; } return TRUE; } static boolean was_waterlevel; /* ugh... this shouldn't be needed */ /* this is special stuff that the level compiler cannot (yet) handle */ STATIC_OVL void fixup_special() { register lev_region *r = lregions; struct d_level lev; register int x, y; struct mkroom *croom; boolean added_branch = FALSE; if (was_waterlevel) { was_waterlevel = FALSE; u.uinwater = 0; unsetup_waterlevel(); } if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) { level.flags.hero_memory = 0; was_waterlevel = TRUE; /* water level is an odd beast - it has to be set up before calling place_lregions etc. */ setup_waterlevel(); } for (x = 0; x < num_lregions; x++, r++) { switch (r->rtype) { case LR_BRANCH: added_branch = TRUE; goto place_it; case LR_PORTAL: if (*r->rname.str >= '0' && *r->rname.str <= '9') { /* "chutes and ladders" */ lev = u.uz; lev.dlevel = atoi(r->rname.str); } else { s_level *sp = find_level(r->rname.str); lev = sp->dlevel; } /* fall into... */ case LR_UPSTAIR: case LR_DOWNSTAIR: place_it: place_lregion(r->inarea.x1, r->inarea.y1, r->inarea.x2, r->inarea.y2, r->delarea.x1, r->delarea.y1, r->delarea.x2, r->delarea.y2, r->rtype, &lev); break; case LR_TELE: case LR_UPTELE: case LR_DOWNTELE: /* save the region outlines for goto_level() */ if (r->rtype == LR_TELE || r->rtype == LR_UPTELE) { updest.lx = r->inarea.x1; updest.ly = r->inarea.y1; updest.hx = r->inarea.x2; updest.hy = r->inarea.y2; updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1; updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2; } if (r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) { dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1; dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2; dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1; dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2; } /* place_lregion gets called from goto_level() */ break; } if (r->rname.str) free((genericptr_t) r->rname.str), r->rname.str = 0; } /* place dungeon branch if not placed above */ if (!added_branch && Is_branchlev(&u.uz)) { place_lregion(0, 0, 0, 0, 0, 0, 0, 0, LR_BRANCH, (d_level *) 0); } /* Still need to add some stuff to level file */ if (Is_medusa_level(&u.uz)) { struct obj *otmp; int tryct; croom = &rooms[0]; /* only one room on the medusa level */ for (tryct = rnd(4); tryct; tryct--) { x = somex(croom); y = somey(croom); if (goodpos(x, y, (struct monst *) 0, 0)) { otmp = mk_tt_object(STATUE, x, y); while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) || pm_resistance(&mons[otmp->corpsenm], MR_STONE))) { /* set_corpsenm() handles weight too */ set_corpsenm(otmp, rndmonnum()); } } } if (rn2(2)) otmp = mk_tt_object(STATUE, somex(croom), somey(croom)); else /* Medusa statues don't contain books */ otmp = mkcorpstat(STATUE, (struct monst *) 0, (struct permonst *) 0, somex(croom), somey(croom), CORPSTAT_NONE); if (otmp) { while (pm_resistance(&mons[otmp->corpsenm], MR_STONE) || poly_when_stoned(&mons[otmp->corpsenm])) { /* set_corpsenm() handles weight too */ set_corpsenm(otmp, rndmonnum()); } } } else if (Is_wiz1_level(&u.uz)) { croom = search_special(MORGUE); create_secret_door(croom, W_SOUTH | W_EAST | W_WEST); } else if (Is_knox(&u.uz)) { /* using an unfilled morgue for rm id */ croom = search_special(MORGUE); /* avoid inappropriate morgue-related messages */ level.flags.graveyard = level.flags.has_morgue = 0; croom->rtype = OROOM; /* perhaps it should be set to VAULT? */ /* stock the main vault */ for (x = croom->lx; x <= croom->hx; x++) for (y = croom->ly; y <= croom->hy; y++) { (void) mkgold((long) rn1(300, 600), x, y); if (!rn2(3) && !is_pool(x, y)) (void) maketrap(x, y, rn2(3) ? LANDMINE : SPIKED_PIT); } } else if (Role_if(PM_PRIEST) && In_quest(&u.uz)) { /* less chance for undead corpses (lured from lower morgues) */ level.flags.graveyard = 1; } else if (Is_stronghold(&u.uz)) { level.flags.graveyard = 1; } else if (Is_sanctum(&u.uz)) { croom = search_special(TEMPLE); create_secret_door(croom, W_ANY); } else if (on_level(&u.uz, &orcus_level)) { register struct monst *mtmp, *mtmp2; /* it's a ghost town, get rid of shopkeepers */ for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (mtmp->isshk) mongone(mtmp); } } if (lregions) free((genericptr_t) lregions), lregions = 0; num_lregions = 0; } void makemaz(s) register const char *s; { int x, y; char protofile[20]; s_level *sp = Is_special(&u.uz); coord mm; if (*s) { if (sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s, rnd((int) sp->rndlevs)); else Strcpy(protofile, s); } else if (*(dungeons[u.uz.dnum].proto)) { if (dunlevs_in_dungeon(&u.uz) > 1) { if (sp && sp->rndlevs) Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto, dunlev(&u.uz), rnd((int) sp->rndlevs)); else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto, dunlev(&u.uz)); } else if (sp && sp->rndlevs) { Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto, rnd((int) sp->rndlevs)); } else Strcpy(protofile, dungeons[u.uz.dnum].proto); } else Strcpy(protofile, ""); /* SPLEVTYPE format is "level-choice,level-choice"... */ if (wizard && *protofile && sp && sp->rndlevs) { char *ep = getenv("SPLEVTYPE"); /* not nh_getenv */ if (ep) { /* rindex always succeeds due to code in prior block */ int len = (int) ((rindex(protofile, '-') - protofile) + 1); while (ep && *ep) { if (!strncmp(ep, protofile, len)) { int pick = atoi(ep + len); /* use choice only if valid */ if (pick > 0 && pick <= (int) sp->rndlevs) Sprintf(protofile + len, "%d", pick); break; } else { ep = index(ep, ','); if (ep) ++ep; } } } } if (*protofile) { Strcat(protofile, LEV_EXT); if (load_special(protofile)) { fixup_special(); /* some levels can end up with monsters on dead mon list, including light source monsters */ dmonsfree(); return; /* no mazification right now */ } impossible("Couldn't load \"%s\" - making a maze.", protofile); } level.flags.is_maze_lev = TRUE; level.flags.corrmaze = !rn2(3); if (level.flags.corrmaze) for (x = 2; x < x_maze_max; x++) for (y = 2; y < y_maze_max; y++) levl[x][y].typ = STONE; else for (x = 2; x <= x_maze_max; x++) for (y = 2; y <= y_maze_max; y++) levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL; maze0xy(&mm); walkfrom((int) mm.x, (int) mm.y, 0); /* put a boulder at the maze center */ (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE, FALSE); if (!level.flags.corrmaze) wallification(2, 2, x_maze_max, y_maze_max); mazexy(&mm); mkstairs(mm.x, mm.y, 1, (struct mkroom *) 0); /* up */ if (!Invocation_lev(&u.uz)) { mazexy(&mm); mkstairs(mm.x, mm.y, 0, (struct mkroom *) 0); /* down */ } else { /* choose "vibrating square" location */ #define x_maze_min 2 #define y_maze_min 2 /* * Pick a position where the stairs down to Moloch's Sanctum * level will ultimately be created. At that time, an area * will be altered: walls removed, moat and traps generated, * boulders destroyed. The position picked here must ensure * that that invocation area won't extend off the map. * * We actually allow up to 2 squares around the usual edge of * the area to get truncated; see mkinvokearea(mklev.c). */ #define INVPOS_X_MARGIN (6 - 2) #define INVPOS_Y_MARGIN (5 - 2) #define INVPOS_DISTANCE 11 int x_range = x_maze_max - x_maze_min - 2 * INVPOS_X_MARGIN - 1, y_range = y_maze_max - y_maze_min - 2 * INVPOS_Y_MARGIN - 1; if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN || (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE)) { debugpline2("inv_pos: maze is too small! (%d x %d)", x_maze_max, y_maze_max); } inv_pos.x = inv_pos.y = 0; /*{occupied() => invocation_pos()}*/ do { x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1); y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1); /* we don't want it to be too near the stairs, nor to be on a spot that's already in use (wall|trap) */ } while (x == xupstair || y == yupstair /*(direct line)*/ || abs(x - xupstair) == abs(y - yupstair) || distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE || !SPACE_POS(levl[x][y].typ) || occupied(x, y)); inv_pos.x = x; inv_pos.y = y; maketrap(inv_pos.x, inv_pos.y, VIBRATING_SQUARE); #undef INVPOS_X_MARGIN #undef INVPOS_Y_MARGIN #undef INVPOS_DISTANCE #undef x_maze_min #undef y_maze_min } /* place branch stair or portal */ place_branch(Is_branchlev(&u.uz), 0, 0); for (x = rn1(8, 11); x; x--) { mazexy(&mm); (void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE); } for (x = rn1(10, 2); x; x--) { mazexy(&mm); (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE); } for (x = rn2(3); x; x--) { mazexy(&mm); (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS); } for (x = rn1(5, 7); x; x--) { mazexy(&mm); (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS); } for (x = rn1(6, 7); x; x--) { mazexy(&mm); (void) mkgold(0L, mm.x, mm.y); } for (x = rn1(6, 7); x; x--) mktrap(0, 1, (struct mkroom *) 0, (coord *) 0); } #ifdef MICRO /* Make the mazewalk iterative by faking a stack. This is needed to * ensure the mazewalk is successful in the limited stack space of * the program. This iterative version uses the minimum amount of stack * that is totally safe. */ void walkfrom(x, y, typ) int x, y; schar typ; { #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */ char mazex[CELLS + 1], mazey[CELLS + 1]; /* char's are OK */ int q, a, dir, pos; int dirs[4]; if (!typ) { if (level.flags.corrmaze) typ = CORR; else typ = ROOM; } pos = 1; mazex[pos] = (char) x; mazey[pos] = (char) y; while (pos) { x = (int) mazex[pos]; y = (int) mazey[pos]; if (!IS_DOOR(levl[x][y].typ)) { /* might still be on edge of MAP, so don't overwrite */ levl[x][y].typ = typ; levl[x][y].flags = 0; } q = 0; for (a = 0; a < 4; a++) if (okay(x, y, a)) dirs[q++] = a; if (!q) pos--; else { dir = dirs[rn2(q)]; mz_move(x, y, dir); levl[x][y].typ = typ; mz_move(x, y, dir); pos++; if (pos > CELLS) panic("Overflow in walkfrom"); mazex[pos] = (char) x; mazey[pos] = (char) y; } } } #else /* !MICRO */ void walkfrom(x, y, typ) int x, y; schar typ; { register int q, a, dir; int dirs[4]; if (!typ) { if (level.flags.corrmaze) typ = CORR; else typ = ROOM; } if (!IS_DOOR(levl[x][y].typ)) { /* might still be on edge of MAP, so don't overwrite */ levl[x][y].typ = typ; levl[x][y].flags = 0; } while (1) { q = 0; for (a = 0; a < 4; a++) if (okay(x, y, a)) dirs[q++] = a; if (!q) return; dir = dirs[rn2(q)]; mz_move(x, y, dir); levl[x][y].typ = typ; mz_move(x, y, dir); walkfrom(x, y, typ); } } #endif /* ?MICRO */ /* find random point in generated corridors, so we don't create items in moats, bunkers, or walls */ void mazexy(cc) coord *cc; { int cpt = 0; do { cc->x = 3 + 2 * rn2((x_maze_max >> 1) - 1); cc->y = 3 + 2 * rn2((y_maze_max >> 1) - 1); cpt++; } while (cpt < 100 && levl[cc->x][cc->y].typ != (level.flags.corrmaze ? CORR : ROOM)); if (cpt >= 100) { register int x, y; /* last try */ for (x = 0; x < (x_maze_max >> 1) - 1; x++) for (y = 0; y < (y_maze_max >> 1) - 1; y++) { cc->x = 3 + 2 * x; cc->y = 3 + 2 * y; if (levl[cc->x][cc->y].typ == (level.flags.corrmaze ? CORR : ROOM)) return; } panic("mazexy: can't find a place!"); } return; } /* put a non-diggable boundary around the initial portion of a level map. * assumes that no level will initially put things beyond the isok() range. * * we can't bound unconditionally on the last line with something in it, * because that something might be a niche which was already reachable, * so the boundary would be breached * * we can't bound unconditionally on one beyond the last line, because * that provides a window of abuse for wallified special levels */ void bound_digging() { register int x, y; register unsigned typ; register struct rm *lev; boolean found, nonwall; int xmin, xmax, ymin, ymax; if (Is_earthlevel(&u.uz)) return; /* everything diggable here */ found = nonwall = FALSE; for (xmin = 0; !found && xmin <= COLNO; xmin++) { lev = &levl[xmin][0]; for (y = 0; y <= ROWNO - 1; y++, lev++) { typ = lev->typ; if (typ != STONE) { found = TRUE; if (!IS_WALL(typ)) nonwall = TRUE; } } } xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; if (xmin < 0) xmin = 0; found = nonwall = FALSE; for (xmax = COLNO - 1; !found && xmax >= 0; xmax--) { lev = &levl[xmax][0]; for (y = 0; y <= ROWNO - 1; y++, lev++) { typ = lev->typ; if (typ != STONE) { found = TRUE; if (!IS_WALL(typ)) nonwall = TRUE; } } } xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; if (xmax >= COLNO) xmax = COLNO - 1; found = nonwall = FALSE; for (ymin = 0; !found && ymin <= ROWNO; ymin++) { lev = &levl[xmin][ymin]; for (x = xmin; x <= xmax; x++, lev += ROWNO) { typ = lev->typ; if (typ != STONE) { found = TRUE; if (!IS_WALL(typ)) nonwall = TRUE; } } } ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; found = nonwall = FALSE; for (ymax = ROWNO - 1; !found && ymax >= 0; ymax--) { lev = &levl[xmin][ymax]; for (x = xmin; x <= xmax; x++, lev += ROWNO) { typ = lev->typ; if (typ != STONE) { found = TRUE; if (!IS_WALL(typ)) nonwall = TRUE; } } } ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) { #ifdef DCC30_BUG lev = &levl[x][y]; lev->wall_info |= W_NONDIGGABLE; #else levl[x][y].wall_info |= W_NONDIGGABLE; #endif } } void mkportal(x, y, todnum, todlevel) xchar x, y, todnum, todlevel; { /* a portal "trap" must be matched by a portal in the destination dungeon/dlevel */ struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL); if (!ttmp) { impossible("portal on top of portal??"); return; } debugpline4("mkportal: at <%d,%d>, to %s, level %d", x, y, dungeons[todnum].dname, todlevel); ttmp->dst.dnum = todnum; ttmp->dst.dlevel = todlevel; return; } void fumaroles() { xchar n; boolean snd = FALSE, loud = FALSE; for (n = rn2(3) + 2; n; n--) { xchar x = rn1(COLNO - 4, 3); xchar y = rn1(ROWNO - 4, 3); if (levl[x][y].typ == LAVAPOOL) { NhRegion *r = create_gas_cloud(x, y, 4 + rn2(5), rn1(10, 5)); clear_heros_fault(r); snd = TRUE; if (distu(x, y) < 15) loud = TRUE; } } if (snd && !Deaf) Norep("You hear a %swhoosh!", loud ? "loud " : ""); } /* * Special waterlevel stuff in endgame (TH). * * Some of these functions would probably logically belong to some * other source files, but they are all so nicely encapsulated here. */ #ifdef DEBUG /* to ease the work of debuggers at this stage */ #define register #endif #define CONS_OBJ 0 #define CONS_MON 1 #define CONS_HERO 2 #define CONS_TRAP 3 static struct bubble *bbubbles, *ebubbles; static struct trap *wportal; static int xmin, ymin, xmax, ymax; /* level boundaries */ /* bubble movement boundaries */ #define bxmin (xmin + 1) #define bymin (ymin + 1) #define bxmax (xmax - 1) #define bymax (ymax - 1) STATIC_DCL void NDECL(set_wportal); STATIC_DCL void FDECL(mk_bubble, (int, int, int)); STATIC_DCL void FDECL(mv_bubble, (struct bubble *, int, int, BOOLEAN_P)); void movebubbles() { static boolean up; register struct bubble *b; register int x, y, i, j; struct trap *btrap; static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0, 0 }; static const struct rm air_pos = { cmap_to_glyph(S_cloud), AIR, 0, 0, 0, 1, 0, 0, 0, 0 }; /* set up the portal the first time bubbles are moved */ if (!wportal) set_wportal(); vision_recalc(2); if (Is_waterlevel(&u.uz)) { /* keep attached ball&chain separate from bubble objects */ if (Punished) unplacebc(); /* * Pick up everything inside of a bubble then fill all bubble * locations. */ for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { if (b->cons) panic("movebubbles: cons != null"); for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) if (b->bm[j + 2] & (1 << i)) { if (!isok(x, y)) { impossible("movebubbles: bad pos (%d,%d)", x, y); continue; } /* pick up objects, monsters, hero, and traps */ if (OBJ_AT(x, y)) { struct obj *olist = (struct obj *) 0, *otmp; struct container *cons = (struct container *) alloc( sizeof(struct container)); while ((otmp = level.objects[x][y]) != 0) { remove_object(otmp); otmp->ox = otmp->oy = 0; otmp->nexthere = olist; olist = otmp; } cons->x = x; cons->y = y; cons->what = CONS_OBJ; cons->list = (genericptr_t) olist; cons->next = b->cons; b->cons = cons; } if (MON_AT(x, y)) { struct monst *mon = m_at(x, y); struct container *cons = (struct container *) alloc( sizeof(struct container)); cons->x = x; cons->y = y; cons->what = CONS_MON; cons->list = (genericptr_t) mon; cons->next = b->cons; b->cons = cons; if (mon->wormno) remove_worm(mon); else remove_monster(x, y); newsym(x, y); /* clean up old position */ mon->mx = mon->my = 0; } if (!u.uswallow && x == u.ux && y == u.uy) { struct container *cons = (struct container *) alloc( sizeof(struct container)); cons->x = x; cons->y = y; cons->what = CONS_HERO; cons->list = (genericptr_t) 0; cons->next = b->cons; b->cons = cons; } if ((btrap = t_at(x, y)) != 0) { struct container *cons = (struct container *) alloc( sizeof(struct container)); cons->x = x; cons->y = y; cons->what = CONS_TRAP; cons->list = (genericptr_t) btrap; cons->next = b->cons; b->cons = cons; } levl[x][y] = water_pos; block_point(x, y); } } } else if (Is_airlevel(&u.uz)) { for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { levl[x][y] = air_pos; unblock_point(x, y); } } /* * Every second time traverse down. This is because otherwise * all the junk that changes owners when bubbles overlap * would eventually end up in the last bubble in the chain. */ up = !up; for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { register int rx = rn2(3), ry = rn2(3); mv_bubble(b, b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)), b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)), FALSE); } /* put attached ball&chain back */ if (Is_waterlevel(&u.uz) && Punished) placebc(); vision_full_recalc = 1; } /* when moving in water, possibly (1 in 3) alter the intended destination */ void water_friction() { register int x, y, dx, dy; register boolean eff = FALSE; if (Swimming && rn2(4)) return; /* natural swimmers have advantage */ if (u.dx && !rn2(!u.dy ? 3 : 6)) { /* 1/3 chance or half that */ /* cancel delta x and choose an arbitrary delta y value */ x = u.ux; do { dy = rn2(3) - 1; /* -1, 0, 1 */ y = u.uy + dy; } while (dy && (!isok(x, y) || !is_pool(x, y))); u.dx = 0; u.dy = dy; eff = TRUE; } else if (u.dy && !rn2(!u.dx ? 3 : 5)) { /* 1/3 or 1/5*(5/6) */ /* cancel delta y and choose an arbitrary delta x value */ y = u.uy; do { dx = rn2(3) - 1; /* -1 .. 1 */ x = u.ux + dx; } while (dx && (!isok(x, y) || !is_pool(x, y))); u.dy = 0; u.dx = dx; eff = TRUE; } if (eff) pline("Water turbulence affects your movements."); } void save_waterlevel(fd, mode) int fd, mode; { register struct bubble *b; if (!Is_waterlevel(&u.uz) && !Is_airlevel(&u.uz)) return; if (perform_bwrite(mode)) { int n = 0; for (b = bbubbles; b; b = b->next) ++n; bwrite(fd, (genericptr_t) &n, sizeof(int)); bwrite(fd, (genericptr_t) &xmin, sizeof(int)); bwrite(fd, (genericptr_t) &ymin, sizeof(int)); bwrite(fd, (genericptr_t) &xmax, sizeof(int)); bwrite(fd, (genericptr_t) &ymax, sizeof(int)); for (b = bbubbles; b; b = b->next) bwrite(fd, (genericptr_t) b, sizeof(struct bubble)); } if (release_data(mode)) unsetup_waterlevel(); } void restore_waterlevel(fd) register int fd; { register struct bubble *b = (struct bubble *) 0, *btmp; register int i; int n; if (!Is_waterlevel(&u.uz) && !Is_airlevel(&u.uz)) return; set_wportal(); mread(fd, (genericptr_t) &n, sizeof(int)); mread(fd, (genericptr_t) &xmin, sizeof(int)); mread(fd, (genericptr_t) &ymin, sizeof(int)); mread(fd, (genericptr_t) &xmax, sizeof(int)); mread(fd, (genericptr_t) &ymax, sizeof(int)); for (i = 0; i < n; i++) { btmp = b; b = (struct bubble *) alloc(sizeof(struct bubble)); mread(fd, (genericptr_t) b, sizeof(struct bubble)); if (bbubbles) { btmp->next = b; b->prev = btmp; } else { bbubbles = b; b->prev = (struct bubble *) 0; } mv_bubble(b, 0, 0, TRUE); } ebubbles = b; b->next = (struct bubble *) 0; was_waterlevel = TRUE; } const char * waterbody_name(x, y) xchar x, y; { register struct rm *lev; schar ltyp; if (!isok(x, y)) return "drink"; /* should never happen */ lev = &levl[x][y]; ltyp = lev->typ; if (ltyp == DRAWBRIDGE_UP) ltyp = db_under_typ(lev->drawbridgemask); if (ltyp == LAVAPOOL) return "lava"; else if (ltyp == ICE) return "ice"; else if (ltyp == POOL) return "pool of water"; else if (ltyp == WATER || Is_waterlevel(&u.uz)) ; /* fall through to default return value */ else if (Is_juiblex_level(&u.uz)) return "swamp"; else if (ltyp == MOAT && !Is_medusa_level(&u.uz)) return "moat"; return "water"; } STATIC_OVL void set_wportal() { /* there better be only one magic portal on water level... */ for (wportal = ftrap; wportal; wportal = wportal->ntrap) if (wportal->ttyp == MAGIC_PORTAL) return; impossible("set_wportal(): no portal!"); } STATIC_OVL void setup_waterlevel() { register int x, y; register int xskip, yskip; register int water_glyph = cmap_to_glyph(S_water); register int air_glyph = cmap_to_glyph(S_air); /* ouch, hardcoded... */ xmin = 3; ymin = 1; xmax = 78; ymax = 20; /* set hero's memory to water */ for (x = xmin; x <= xmax; x++) for (y = ymin; y <= ymax; y++) levl[x][y].glyph = Is_waterlevel(&u.uz) ? water_glyph : air_glyph; /* make bubbles */ if (Is_waterlevel(&u.uz)) { xskip = 10 + rn2(10); yskip = 4 + rn2(4); } else { xskip = 6 + rn2(4); yskip = 3 + rn2(3); } for (x = bxmin; x <= bxmax; x += xskip) for (y = bymin; y <= bymax; y += yskip) mk_bubble(x, y, rn2(7)); } STATIC_OVL void unsetup_waterlevel() { register struct bubble *b, *bb; /* free bubbles */ for (b = bbubbles; b; b = bb) { bb = b->next; free((genericptr_t) b); } bbubbles = ebubbles = (struct bubble *) 0; } STATIC_OVL void mk_bubble(x, y, n) register int x, y, n; { /* * These bit masks make visually pleasing bubbles on a normal aspect * 25x80 terminal, which naturally results in them being mathematically * anything but symmetric. For this reason they cannot be computed * in situ, either. The first two elements tell the dimensions of * the bubble's bounding box. */ static uchar bm2[] = { 2, 1, 0x3 }, bm3[] = { 3, 2, 0x7, 0x7 }, bm4[] = { 4, 3, 0x6, 0xf, 0x6 }, bm5[] = { 5, 3, 0xe, 0x1f, 0xe }, bm6[] = { 6, 4, 0x1e, 0x3f, 0x3f, 0x1e }, bm7[] = { 7, 4, 0x3e, 0x7f, 0x7f, 0x3e }, bm8[] = { 8, 4, 0x7e, 0xff, 0xff, 0x7e }, *bmask[] = { bm2, bm3, bm4, bm5, bm6, bm7, bm8 }; register struct bubble *b; if (x >= bxmax || y >= bymax) return; if (n >= SIZE(bmask)) { impossible("n too large (mk_bubble)"); n = SIZE(bmask) - 1; } if (bmask[n][1] > MAX_BMASK) { panic("bmask size is larger than MAX_BMASK"); } b = (struct bubble *) alloc(sizeof(struct bubble)); if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1; if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1; b->x = x; b->y = y; b->dx = 1 - rn2(3); b->dy = 1 - rn2(3); /* y dimension is the length of bitmap data - see bmask above */ (void) memcpy((genericptr_t) b->bm, (genericptr_t) bmask[n], (bmask[n][1] + 2) * sizeof(b->bm[0])); b->cons = 0; if (!bbubbles) bbubbles = b; if (ebubbles) { ebubbles->next = b; b->prev = ebubbles; } else b->prev = (struct bubble *) 0; b->next = (struct bubble *) 0; ebubbles = b; mv_bubble(b, 0, 0, TRUE); } /* * The player, the portal and all other objects and monsters * float along with their associated bubbles. Bubbles may overlap * freely, and the contents may get associated with other bubbles in * the process. Bubbles are "sticky", meaning that if the player is * in the immediate neighborhood of one, he/she may get sucked inside. * This property also makes leaving a bubble slightly difficult. */ STATIC_OVL void mv_bubble(b, dx, dy, ini) register struct bubble *b; register int dx, dy; register boolean ini; { register int x, y, i, j, colli = 0; struct container *cons, *ctemp; /* clouds move slowly */ if (!Is_airlevel(&u.uz) || !rn2(6)) { /* move bubble */ if (dx < -1 || dx > 1 || dy < -1 || dy > 1) { /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */ dx = sgn(dx); dy = sgn(dy); } /* * collision with level borders? * 1 = horizontal border, 2 = vertical, 3 = corner */ if (b->x <= bxmin) colli |= 2; if (b->y <= bymin) colli |= 1; if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2; if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1; if (b->x < bxmin) { pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin); b->x = bxmin; } if (b->y < bymin) { pline("bubble ymin: y = %d, ymin = %d", b->y, bymin); b->y = bymin; } if ((int) (b->x + b->bm[0] - 1) > bxmax) { pline("bubble xmax: x = %d, xmax = %d", b->x + b->bm[0] - 1, bxmax); b->x = bxmax - b->bm[0] + 1; } if ((int) (b->y + b->bm[1] - 1) > bymax) { pline("bubble ymax: y = %d, ymax = %d", b->y + b->bm[1] - 1, bymax); b->y = bymax - b->bm[1] + 1; } /* bounce if we're trying to move off the border */ if (b->x == bxmin && dx < 0) dx = -dx; if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx; if (b->y == bymin && dy < 0) dy = -dy; if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy; b->x += dx; b->y += dy; } /* draw the bubbles */ for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) if (b->bm[j + 2] & (1 << i)) { if (Is_waterlevel(&u.uz)) { levl[x][y].typ = AIR; levl[x][y].lit = 1; unblock_point(x, y); } else if (Is_airlevel(&u.uz)) { levl[x][y].typ = CLOUD; levl[x][y].lit = 1; block_point(x, y); } } if (Is_waterlevel(&u.uz)) { /* replace contents of bubble */ for (cons = b->cons; cons; cons = ctemp) { ctemp = cons->next; cons->x += dx; cons->y += dy; switch (cons->what) { case CONS_OBJ: { struct obj *olist, *otmp; for (olist = (struct obj *) cons->list; olist; olist = otmp) { otmp = olist->nexthere; place_object(olist, cons->x, cons->y); } break; } case CONS_MON: { struct monst *mon = (struct monst *) cons->list; (void) mnearto(mon, cons->x, cons->y, TRUE); break; } case CONS_HERO: { int ux0 = u.ux, uy0 = u.uy; /* change u.ux0 and u.uy0? */ u.ux = cons->x; u.uy = cons->y; newsym(ux0, uy0); /* clean up old position */ if (MON_AT(cons->x, cons->y)) { mnexto(m_at(cons->x, cons->y)); } break; } case CONS_TRAP: { struct trap *btrap = (struct trap *) cons->list; btrap->tx = cons->x; btrap->ty = cons->y; break; } default: impossible("mv_bubble: unknown bubble contents"); break; } free((genericptr_t) cons); } b->cons = 0; } /* boing? */ switch (colli) { case 1: b->dy = -b->dy; break; case 3: b->dy = -b->dy; /* fall through */ case 2: b->dx = -b->dx; break; default: /* sometimes alter direction for fun anyway (higher probability for stationary bubbles) */ if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) { b->dx = 1 - rn2(3); b->dy = 1 - rn2(3); } } } /*mkmaze.c*/ nethack-3.6.0/src/mkobj.c0000664000076400007660000024640412624166366014220 0ustar paxedpaxed/* NetHack 3.6 mkobj.c $NHDT-Date: 1447475943 2015/11/14 04:39:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.113 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL void FDECL(mkbox_cnts, (struct obj *)); STATIC_DCL void FDECL(maybe_adjust_light, (struct obj *, int)); STATIC_DCL void FDECL(obj_timer_checks, (struct obj *, XCHAR_P, XCHAR_P, int)); STATIC_DCL void FDECL(container_weight, (struct obj *)); STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *)); STATIC_DCL void FDECL(objlist_sanity, (struct obj *, int, const char *)); STATIC_DCL void FDECL(mon_obj_sanity, (struct monst *, const char *)); STATIC_DCL const char *FDECL(where_name, (struct obj *)); STATIC_DCL void FDECL(insane_object, (struct obj *, const char *, const char *, struct monst *)); STATIC_DCL void FDECL(check_contained, (struct obj *, const char *)); STATIC_DCL void FDECL(sanity_check_worn, (struct obj *)); struct icp { int iprob; /* probability of an item type */ char iclass; /* item class */ }; static const struct icp mkobjprobs[] = { { 10, WEAPON_CLASS }, { 10, ARMOR_CLASS }, { 20, FOOD_CLASS }, { 8, TOOL_CLASS }, { 8, GEM_CLASS }, { 16, POTION_CLASS }, { 16, SCROLL_CLASS }, { 4, SPBOOK_CLASS }, { 4, WAND_CLASS }, { 3, RING_CLASS }, { 1, AMULET_CLASS } }; static const struct icp boxiprobs[] = { { 18, GEM_CLASS }, { 15, FOOD_CLASS }, { 18, POTION_CLASS }, { 18, SCROLL_CLASS }, { 12, SPBOOK_CLASS }, { 7, COIN_CLASS }, { 6, WAND_CLASS }, { 5, RING_CLASS }, { 1, AMULET_CLASS } }; static const struct icp rogueprobs[] = { { 12, WEAPON_CLASS }, { 12, ARMOR_CLASS }, { 22, FOOD_CLASS }, { 22, POTION_CLASS }, { 22, SCROLL_CLASS }, { 5, WAND_CLASS }, { 5, RING_CLASS } }; static const struct icp hellprobs[] = { { 20, WEAPON_CLASS }, { 20, ARMOR_CLASS }, { 16, FOOD_CLASS }, { 12, TOOL_CLASS }, { 10, GEM_CLASS }, { 1, POTION_CLASS }, { 1, SCROLL_CLASS }, { 8, WAND_CLASS }, { 8, RING_CLASS }, { 4, AMULET_CLASS } }; struct oextra * newoextra() { struct oextra *oextra; oextra = (struct oextra *) alloc(sizeof(struct oextra)); oextra->oname = 0; oextra->omonst = 0; oextra->omid = 0; oextra->olong = 0; oextra->omailcmd = 0; return oextra; } void dealloc_oextra(o) struct obj *o; { struct oextra *x = o->oextra; if (x) { if (x->oname) free((genericptr_t) x->oname); if (x->omonst) free_omonst(o); /* 'o' rather than 'x' */ if (x->omid) free((genericptr_t) x->omid); if (x->olong) free((genericptr_t) x->olong); if (x->omailcmd) free((genericptr_t) x->omailcmd); free((genericptr_t) x); o->oextra = (struct oextra *) 0; } } void newomonst(otmp) struct obj *otmp; { if (!otmp->oextra) otmp->oextra = newoextra(); if (!OMONST(otmp)) { struct monst *m = newmonst(); /* newmonst() allocates memory but doesn't initialize anything */ (void) memset((genericptr_t) m, 0, sizeof (struct monst)); m->mextra = (struct mextra *) 0; m->nmon = (struct monst *) 0; OMONST(otmp) = m; } } void free_omonst(otmp) struct obj *otmp; { if (otmp->oextra) { struct monst *m = OMONST(otmp); if (m) { if (m->mextra) dealloc_mextra(m); free((genericptr_t) m); OMONST(otmp) = (struct monst *) 0; } } } void newomid(otmp) struct obj *otmp; { if (!otmp->oextra) otmp->oextra = newoextra(); if (!OMID(otmp)) { OMID(otmp) = (unsigned *) alloc(sizeof (unsigned)); (void) memset((genericptr_t) OMID(otmp), 0, sizeof (unsigned)); } } void free_omid(otmp) struct obj *otmp; { if (otmp->oextra && OMID(otmp)) { free((genericptr_t) OMID(otmp)); OMID(otmp) = (unsigned *) 0; } } void newolong(otmp) struct obj *otmp; { if (!otmp->oextra) otmp->oextra = newoextra(); if (!OLONG(otmp)) { OLONG(otmp) = (long *) alloc(sizeof (long)); (void) memset((genericptr_t) OLONG(otmp), 0, sizeof (long)); } } void free_olong(otmp) struct obj *otmp; { if (otmp->oextra && OLONG(otmp)) { free((genericptr_t) OLONG(otmp)); OLONG(otmp) = (long *) 0; } } void new_omailcmd(otmp, response_cmd) struct obj *otmp; const char *response_cmd; { if (!otmp->oextra) otmp->oextra = newoextra(); if (OMAILCMD(otmp)) free_omailcmd(otmp); OMAILCMD(otmp) = dupstr(response_cmd); } void free_omailcmd(otmp) struct obj *otmp; { if (otmp->oextra && OMAILCMD(otmp)) { free((genericptr_t) OMAILCMD(otmp)); OMAILCMD(otmp) = (char *) 0; } } struct obj * mkobj_at(let, x, y, artif) char let; int x, y; boolean artif; { struct obj *otmp; otmp = mkobj(let, artif); place_object(otmp, x, y); return otmp; } struct obj * mksobj_at(otyp, x, y, init, artif) int otyp, x, y; boolean init, artif; { struct obj *otmp; otmp = mksobj(otyp, init, artif); place_object(otmp, x, y); return otmp; } struct obj * mkobj(oclass, artif) char oclass; boolean artif; { int tprob, i, prob = rnd(1000); if (oclass == RANDOM_CLASS) { const struct icp *iprobs = Is_rogue_level(&u.uz) ? (const struct icp *) rogueprobs : Inhell ? (const struct icp *) hellprobs : (const struct icp *) mkobjprobs; for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++) ; oclass = iprobs->iclass; } i = bases[(int) oclass]; while ((prob -= objects[i].oc_prob) > 0) i++; if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) panic("probtype error, oclass=%d i=%d", (int) oclass, i); return mksobj(i, TRUE, artif); } STATIC_OVL void mkbox_cnts(box) struct obj *box; { register int n; register struct obj *otmp; box->cobj = (struct obj *) 0; switch (box->otyp) { case ICE_BOX: n = 20; break; case CHEST: n = 5; break; case LARGE_BOX: n = 3; break; case SACK: case OILSKIN_SACK: /* initial inventory: sack starts out empty */ if (moves <= 1 && !in_mklev) { n = 0; break; } /*else FALLTHRU*/ case BAG_OF_HOLDING: n = 1; break; default: n = 0; break; } for (n = rn2(n + 1); n > 0; n--) { if (box->otyp == ICE_BOX) { if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue; /* Note: setting age to 0 is correct. Age has a different * from usual meaning for objects stored in ice boxes. -KAA */ otmp->age = 0L; if (otmp->timed) { (void) stop_timer(ROT_CORPSE, obj_to_any(otmp)); (void) stop_timer(REVIVE_MON, obj_to_any(otmp)); } } else { register int tprob; const struct icp *iprobs = boxiprobs; for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++) ; if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue; /* handle a couple of special cases */ if (otmp->oclass == COIN_CLASS) { /* 2.5 x level's usual amount; weight adjusted below */ otmp->quan = (long) (rnd(level_difficulty() + 2) * rnd(75)); otmp->owt = weight(otmp); } else while (otmp->otyp == ROCK) { otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE); if (otmp->quan > 2L) otmp->quan = 1L; otmp->owt = weight(otmp); } if (box->otyp == BAG_OF_HOLDING) { if (Is_mbag(otmp)) { otmp->otyp = SACK; otmp->spe = 0; otmp->owt = weight(otmp); } else while (otmp->otyp == WAN_CANCELLATION) otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); } } (void) add_to_container(box, otmp); } } /* select a random, common monster type */ int rndmonnum() { register struct permonst *ptr; register int i; unsigned short excludeflags; /* Plan A: get a level-appropriate common monster */ ptr = rndmonst(); if (ptr) return monsndx(ptr); /* Plan B: get any common monster */ excludeflags = G_UNIQ | G_NOGEN | (Inhell ? G_NOHELL : G_HELL); do { i = rn1(SPECIAL_PM - LOW_PM, LOW_PM); ptr = &mons[i]; } while ((ptr->geno & excludeflags) != 0); return i; } void copy_oextra(obj2, obj1) struct obj *obj2, *obj1; { if (!obj2 || !obj1 || !obj1->oextra) return; if (!obj2->oextra) obj2->oextra = newoextra(); if (has_oname(obj1)) oname(obj2, ONAME(obj1)); if (has_omonst(obj1)) { if (!OMONST(obj2)) newomonst(obj2); (void) memcpy((genericptr_t) OMONST(obj2), (genericptr_t) OMONST(obj1), sizeof(struct monst)); OMONST(obj2)->mextra = (struct mextra *) 0; OMONST(obj2)->nmon = (struct monst *) 0; #if 0 OMONST(obj2)->m_id = context.ident++; if (OMONST(obj2)->m_id) /* ident overflowed */ OMONST(obj2)->m_id = context.ident++; #endif if (OMONST(obj1)->mextra) copy_mextra(OMONST(obj2), OMONST(obj1)); } if (has_omid(obj1)) { if (!OMID(obj2)) newomid(obj2); (void) memcpy((genericptr_t) OMID(obj2), (genericptr_t) OMID(obj1), sizeof(unsigned)); } if (has_olong(obj1)) { if (!OLONG(obj2)) newolong(obj2); (void) memcpy((genericptr_t) OLONG(obj2), (genericptr_t) OLONG(obj1), sizeof(long)); } if (has_omailcmd(obj1)) { new_omailcmd(obj2, OMAILCMD(obj1)); } } /* * Split obj so that it gets size gets reduced by num. The quantity num is * put in the object structure delivered by this call. The returned object * has its wornmask cleared and is positioned just following the original * in the nobj chain (and nexthere chain when on the floor). */ struct obj * splitobj(obj, num) struct obj *obj; long num; { struct obj *otmp; if (obj->cobj || num <= 0L || obj->quan <= num) panic("splitobj"); /* can't split containers */ otmp = newobj(); *otmp = *obj; /* copies whole structure */ otmp->oextra = (struct oextra *) 0; otmp->o_id = context.ident++; if (!otmp->o_id) otmp->o_id = context.ident++; /* ident overflowed */ otmp->timed = 0; /* not timed, yet */ otmp->lamplit = 0; /* ditto */ otmp->owornmask = 0L; /* new object isn't worn */ obj->quan -= num; obj->owt = weight(obj); otmp->quan = num; otmp->owt = weight(otmp); /* -= obj->owt ? */ context.objsplit.parent_oid = obj->o_id; context.objsplit.child_oid = otmp->o_id; obj->nobj = otmp; /* Only set nexthere when on the floor, nexthere is also used */ /* as a back pointer to the container object when contained. */ if (obj->where == OBJ_FLOOR) obj->nexthere = otmp; copy_oextra(otmp, obj); if (has_omid(otmp)) free_omid(otmp); /* only one association with m_id*/ if (obj->unpaid) splitbill(obj, otmp); if (obj->timed) obj_split_timers(obj, otmp); if (obj_sheds_light(obj)) obj_split_light_source(obj, otmp); return otmp; } /* try to find the stack obj was split from, then merge them back together; returns the combined object if unsplit is successful, null otherwise */ struct obj * unsplitobj(obj) struct obj *obj; { unsigned target_oid = 0; struct obj *oparent = 0, *ochild = 0, *list = 0; /* * We don't operate on floor objects (we're following o->nobj rather * than o->nexthere), on free objects (don't know which list to use when * looking for obj's parent or child), on bill objects (too complicated, * not needed), or on buried or migrating objects (not needed). * [This could be improved, but at present additional generality isn't * necessary.] */ switch (obj->where) { case OBJ_FREE: case OBJ_FLOOR: case OBJ_ONBILL: case OBJ_MIGRATING: case OBJ_BURIED: default: return (struct obj *) 0; case OBJ_INVENT: list = invent; break; case OBJ_MINVENT: list = obj->ocarry->minvent; break; case OBJ_CONTAINED: list = obj->ocontainer->cobj; break; } /* first try the expected case; obj is split from another stack */ if (obj->o_id == context.objsplit.child_oid) { /* parent probably precedes child and will require list traversal */ ochild = obj; target_oid = context.objsplit.parent_oid; if (obj->nobj && obj->nobj->o_id == target_oid) oparent = obj->nobj; } else if (obj->o_id == context.objsplit.parent_oid) { /* alternate scenario: another stack was split from obj; child probably follows parent and will be found here */ oparent = obj; target_oid = context.objsplit.child_oid; if (obj->nobj && obj->nobj->o_id == target_oid) ochild = obj->nobj; } /* if we have only half the split, scan obj's list to find other half */ if (ochild && !oparent) { /* expected case */ for (obj = list; obj; obj = obj->nobj) if (obj->o_id == target_oid) { oparent = obj; break; } } else if (oparent && !ochild) { /* alternate scenario */ for (obj = list; obj; obj = obj->nobj) if (obj->o_id == target_oid) { ochild = obj; break; } } /* if we have both parent and child, try to merge them; if successful, return the combined stack, otherwise return null */ return (oparent && ochild && merged(&oparent, &ochild)) ? oparent : 0; } /* reset splitobj()/unsplitobj() context */ void clear_splitobjs() { context.objsplit.parent_oid = context.objsplit.child_oid = 0; } /* * Insert otmp right after obj in whatever chain(s) it is on. Then extract * obj from the chain(s). This function does a literal swap. It is up to * the caller to provide a valid context for the swap. When done, obj will * still exist, but not on any chain. * * Note: Don't use use obj_extract_self() -- we are doing an in-place swap, * not actually moving something. */ void replace_object(obj, otmp) struct obj *obj; struct obj *otmp; { otmp->where = obj->where; switch (obj->where) { case OBJ_FREE: /* do nothing */ break; case OBJ_INVENT: otmp->nobj = obj->nobj; obj->nobj = otmp; extract_nobj(obj, &invent); break; case OBJ_CONTAINED: otmp->nobj = obj->nobj; otmp->ocontainer = obj->ocontainer; obj->nobj = otmp; extract_nobj(obj, &obj->ocontainer->cobj); break; case OBJ_MINVENT: otmp->nobj = obj->nobj; otmp->ocarry = obj->ocarry; obj->nobj = otmp; extract_nobj(obj, &obj->ocarry->minvent); break; case OBJ_FLOOR: otmp->nobj = obj->nobj; otmp->nexthere = obj->nexthere; otmp->ox = obj->ox; otmp->oy = obj->oy; obj->nobj = otmp; obj->nexthere = otmp; extract_nobj(obj, &fobj); extract_nexthere(obj, &level.objects[obj->ox][obj->oy]); break; default: panic("replace_object: obj position"); break; } } /* * Create a dummy duplicate to put on shop bill. The duplicate exists * only in the billobjs chain. This function is used when a shop object * is being altered, and a copy of the original is needed for billing * purposes. For example, when eating, where an interruption will yield * an object which is different from what it started out as; the "I x" * command needs to display the original object. * * The caller is responsible for checking otmp->unpaid and * costly_spot(u.ux, u.uy). This function will make otmp no charge. * * Note that check_unpaid_usage() should be used instead for partial * usage of an object. */ void bill_dummy_object(otmp) register struct obj *otmp; { register struct obj *dummy; long cost = 0L; if (otmp->unpaid) { cost = unpaid_cost(otmp, FALSE); subfrombill(otmp, shop_keeper(*u.ushops)); } dummy = newobj(); *dummy = *otmp; dummy->oextra = (struct oextra *) 0; dummy->where = OBJ_FREE; dummy->o_id = context.ident++; if (!dummy->o_id) dummy->o_id = context.ident++; /* ident overflowed */ dummy->timed = 0; copy_oextra(dummy, otmp); if (has_omid(dummy)) free_omid(dummy); /* only one association with m_id*/ if (Is_candle(dummy)) dummy->lamplit = 0; dummy->owornmask = 0L; /* dummy object is not worn */ addtobill(dummy, FALSE, TRUE, TRUE); if (cost) alter_cost(dummy, -cost); /* no_charge is only valid for some locations */ otmp->no_charge = (otmp->where == OBJ_FLOOR || otmp->where == OBJ_CONTAINED) ? 1 : 0; otmp->unpaid = 0; return; } /* alteration types; must match COST_xxx macros in hack.h */ static const char *const alteration_verbs[] = { "cancel", "drain", "uncharge", "unbless", "uncurse", "disenchant", "degrade", "dilute", "erase", "burn", "neutralize", "destroy", "splatter", "bite", "open", "break the lock on", "rust", "rot", "tarnish" }; /* possibly bill for an object which the player has just modified */ void costly_alteration(obj, alter_type) struct obj *obj; int alter_type; { xchar ox, oy; char objroom; boolean set_bknown; const char *those, *them; struct monst *shkp = 0; if (alter_type < 0 || alter_type >= SIZE(alteration_verbs)) { impossible("invalid alteration type (%d)", alter_type); alter_type = 0; } ox = oy = 0; /* lint suppression */ objroom = '\0'; /* ditto */ if (carried(obj) || obj->where == OBJ_FREE) { /* OBJ_FREE catches obj_no_longer_held()'s transformation of crysknife back into worm tooth; the object has been removed from inventory but not necessarily placed at its new location yet--the unpaid flag will still be set if this item is owned by a shop */ if (!obj->unpaid) return; } else { /* this get_obj_location shouldn't fail, but if it does, use hero's location */ if (!get_obj_location(obj, &ox, &oy, CONTAINED_TOO)) ox = u.ux, oy = u.uy; if (!costly_spot(ox, oy)) return; objroom = *in_rooms(ox, oy, SHOPBASE); /* if no shop cares about it, we're done */ if (!billable(&shkp, obj, objroom, FALSE)) return; } if (obj->quan == 1L) those = "that", them = "it"; else those = "those", them = "them"; /* when shopkeeper describes the object as being uncursed or unblessed hero will know that it is now uncursed; will also make the feedback from `I x' after bill_dummy_object() be more specific for this item */ set_bknown = (alter_type == COST_UNCURS || alter_type == COST_UNBLSS); switch (obj->where) { case OBJ_FREE: /* obj_no_longer_held() */ case OBJ_INVENT: if (set_bknown) obj->bknown = 1; verbalize("You %s %s %s, you pay for %s!", alteration_verbs[alter_type], those, simpleonames(obj), them); bill_dummy_object(obj); break; case OBJ_FLOOR: if (set_bknown) obj->bknown = 1; if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) { verbalize("You %s %s, you pay for %s!", alteration_verbs[alter_type], those, them); bill_dummy_object(obj); } else { (void) stolen_value(obj, ox, oy, FALSE, FALSE); } break; } } static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0 }; struct obj * mksobj(otyp, init, artif) int otyp; boolean init; boolean artif; { int mndx, tryct; struct obj *otmp; char let = objects[otyp].oc_class; otmp = newobj(); *otmp = zeroobj; otmp->age = monstermoves; otmp->o_id = context.ident++; if (!otmp->o_id) otmp->o_id = context.ident++; /* ident overflowed */ otmp->quan = 1L; otmp->oclass = let; otmp->otyp = otyp; otmp->where = OBJ_FREE; otmp->dknown = index(dknowns, let) ? 0 : 1; if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) || otmp->otyp == SHIELD_OF_REFLECTION) otmp->dknown = 0; if (!objects[otmp->otyp].oc_uses_known) otmp->known = 1; otmp->lknown = 0; otmp->cknown = 0; otmp->corpsenm = NON_PM; if (init) switch (let) { case WEAPON_CLASS: otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L; if (!rn2(11)) { otmp->spe = rne(3); otmp->blessed = rn2(2); } else if (!rn2(10)) { curse(otmp); otmp->spe = -rne(3); } else blessorcurse(otmp, 10); if (is_poisonable(otmp) && !rn2(100)) otmp->opoisoned = 1; if (artif && !rn2(20)) otmp = mk_artifact(otmp, (aligntyp) A_NONE); break; case FOOD_CLASS: otmp->oeaten = 0; switch (otmp->otyp) { case CORPSE: /* possibly overridden by mkcorpstat() */ tryct = 50; do otmp->corpsenm = undead_to_corpse(rndmonnum()); while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0)); if (tryct == 0) { /* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on this level; let's create an adventurer's corpse instead, then */ otmp->corpsenm = PM_HUMAN; } /* timer set below */ break; case EGG: otmp->corpsenm = NON_PM; /* generic egg */ if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) { mndx = can_be_hatched(rndmonnum()); if (mndx != NON_PM && !dead_species(mndx, TRUE)) { otmp->corpsenm = mndx; /* typed egg */ break; } } /* timer set below */ break; case TIN: otmp->corpsenm = NON_PM; /* empty (so far) */ if (!rn2(6)) set_tin_variety(otmp, SPINACH_TIN); else for (tryct = 200; tryct > 0; --tryct) { mndx = undead_to_corpse(rndmonnum()); if (mons[mndx].cnutrit && !(mvitals[mndx].mvflags & G_NOCORPSE)) { otmp->corpsenm = mndx; set_tin_variety(otmp, RANDOM_TIN); break; } } blessorcurse(otmp, 10); break; case SLIME_MOLD: otmp->spe = context.current_fruit; flags.made_fruit = TRUE; break; case KELP_FROND: otmp->quan = (long) rnd(2); break; } if (Is_pudding(otmp)) { otmp->globby = 1; otmp->known = otmp->bknown = otmp->rknown = otmp->dknown = 1; otmp->corpsenm = PM_GRAY_OOZE + (otmp->otyp - GLOB_OF_GRAY_OOZE); /* this ensures that they don't fail merging because of * BUC status or other irrelevancies */ } else { if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING && otmp->otyp != KELP_FROND && !rn2(6)) { otmp->quan = 2L; } } break; case GEM_CLASS: otmp->corpsenm = 0; /* LOADSTONE hack */ if (otmp->otyp == LOADSTONE) curse(otmp); else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6, 6); else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L; else otmp->quan = 1L; break; case TOOL_CLASS: switch (otmp->otyp) { case TALLOW_CANDLE: case WAX_CANDLE: otmp->spe = 1; otmp->age = 20L * /* 400 or 200 */ (long) objects[otmp->otyp].oc_cost; otmp->lamplit = 0; otmp->quan = 1L + (long) (rn2(2) ? rn2(7) : 0); blessorcurse(otmp, 5); break; case BRASS_LANTERN: case OIL_LAMP: otmp->spe = 1; otmp->age = (long) rn1(500, 1000); otmp->lamplit = 0; blessorcurse(otmp, 5); break; case MAGIC_LAMP: otmp->spe = 1; otmp->lamplit = 0; blessorcurse(otmp, 2); break; case CHEST: case LARGE_BOX: otmp->olocked = !!(rn2(5)); otmp->otrapped = !(rn2(10)); case ICE_BOX: case SACK: case OILSKIN_SACK: case BAG_OF_HOLDING: mkbox_cnts(otmp); break; case LEASH: otmp->leashmon = 0; break; case EXPENSIVE_CAMERA: case TINNING_KIT: case MAGIC_MARKER: otmp->spe = rn1(70, 30); break; case CAN_OF_GREASE: otmp->spe = rnd(25); blessorcurse(otmp, 10); break; case CRYSTAL_BALL: otmp->spe = rnd(5); blessorcurse(otmp, 2); break; case HORN_OF_PLENTY: case BAG_OF_TRICKS: otmp->spe = rnd(20); break; case FIGURINE: { int tryct2 = 0; do otmp->corpsenm = rndmonnum(); while (is_human(&mons[otmp->corpsenm]) && tryct2++ < 30); blessorcurse(otmp, 4); break; } case BELL_OF_OPENING: otmp->spe = 3; break; case MAGIC_FLUTE: case MAGIC_HARP: case FROST_HORN: case FIRE_HORN: case DRUM_OF_EARTHQUAKE: otmp->spe = rn1(5, 4); break; } break; case AMULET_CLASS: if (otmp->otyp == AMULET_OF_YENDOR) context.made_amulet = TRUE; if (rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == AMULET_OF_CHANGE || otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) { curse(otmp); } else blessorcurse(otmp, 10); case VENOM_CLASS: case CHAIN_CLASS: case BALL_CLASS: break; case POTION_CLASS: otmp->fromsink = 0; if (otmp->otyp == POT_OIL) otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ /* fall through */ case SCROLL_CLASS: #ifdef MAIL if (otmp->otyp != SCR_MAIL) #endif blessorcurse(otmp, 4); break; case SPBOOK_CLASS: otmp->spestudied = 0; blessorcurse(otmp, 17); break; case ARMOR_CLASS: if (rn2(10) && (otmp->otyp == FUMBLE_BOOTS || otmp->otyp == LEVITATION_BOOTS || otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT || otmp->otyp == GAUNTLETS_OF_FUMBLING || !rn2(11))) { curse(otmp); otmp->spe = -rne(3); } else if (!rn2(10)) { otmp->blessed = rn2(2); otmp->spe = rne(3); } else blessorcurse(otmp, 10); if (artif && !rn2(40)) otmp = mk_artifact(otmp, (aligntyp) A_NONE); /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && (moves <= 1 || In_quest(&u.uz))) { #ifdef UNIXPC /* optimizer bitfield bug */ otmp->oerodeproof = 1; otmp->rknown = 1; #else otmp->oerodeproof = otmp->rknown = 1; #endif } break; case WAND_CLASS: if (otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else otmp->spe = rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); blessorcurse(otmp, 17); otmp->recharged = 0; /* used to control recharging */ break; case RING_CLASS: if (objects[otmp->otyp].oc_charged) { blessorcurse(otmp, 3); if (rn2(10)) { if (rn2(10) && bcsign(otmp)) otmp->spe = bcsign(otmp) * rne(3); else otmp->spe = rn2(2) ? rne(3) : -rne(3); } /* make useless +0 rings much less common */ if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3); /* negative rings are usually cursed */ if (otmp->spe < 0 && rn2(5)) curse(otmp); } else if (rn2(10) && (otmp->otyp == RIN_TELEPORTATION || otmp->otyp == RIN_POLYMORPH || otmp->otyp == RIN_AGGRAVATE_MONSTER || otmp->otyp == RIN_HUNGER || !rn2(9))) { curse(otmp); } break; case ROCK_CLASS: switch (otmp->otyp) { case STATUE: /* possibly overridden by mkcorpstat() */ otmp->corpsenm = rndmonnum(); if (!verysmall(&mons[otmp->corpsenm]) && rn2(level_difficulty() / 2 + 10) > 10) (void) add_to_container(otmp, mkobj(SPBOOK_CLASS, FALSE)); } break; case COIN_CLASS: break; /* do nothing */ default: impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, objects[otmp->otyp].oc_class); return (struct obj *) 0; } /* some things must get done (corpsenm, timers) even if init = 0 */ switch (otmp->otyp) { case CORPSE: if (otmp->corpsenm == NON_PM) { otmp->corpsenm = undead_to_corpse(rndmonnum()); if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE)) otmp->corpsenm = urole.malenum; } /*FALLTHRU*/ case STATUE: case FIGURINE: if (otmp->corpsenm == NON_PM) otmp->corpsenm = rndmonnum(); /*FALLTHRU*/ case EGG: /* case TIN: */ set_corpsenm(otmp, otmp->corpsenm); break; case SPE_NOVEL: otmp->novelidx = -1; /* "none of the above"; will be changed */ otmp = oname(otmp, noveltitle(&otmp->novelidx)); break; } /* unique objects may have an associated artifact entry */ if (objects[otyp].oc_unique && !otmp->oartifact) otmp = mk_artifact(otmp, (aligntyp) A_NONE); otmp->owt = weight(otmp); return otmp; } /* * Several areas of the code made direct reassignments * to obj->corpsenm. Because some special handling is * required in certain cases, place that handling here * and call this routine in place of the direct assignment. * * If the object was a lizard or lichen corpse: * - ensure that you don't end up with some * other corpse type which has no rot-away timer. * * If the object was a troll corpse: * - ensure that you don't end up with some other * corpse type which resurrects from the dead. * * Re-calculates the weight of figurines and corpses to suit the * new species. * * Existing timeout value for egg hatch is preserved. * */ void set_corpsenm(obj, id) struct obj *obj; int id; { long when = 0L; if (obj->timed) { if (obj->otyp == EGG) when = stop_timer(HATCH_EGG, obj_to_any(obj)); else { when = 0L; obj_stop_timers(obj); /* corpse or figurine */ } } obj->corpsenm = id; switch (obj->otyp) { case CORPSE: start_corpse_timeout(obj); obj->owt = weight(obj); break; case FIGURINE: if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE) && (carried(obj) || mcarried(obj))) attach_fig_transform_timeout(obj); obj->owt = weight(obj); break; case EGG: if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)) attach_egg_hatch_timeout(obj, when); break; default: /* tin, etc. */ obj->owt = weight(obj); break; } } /* * Start a corpse decay or revive timer. * This takes the age of the corpse into consideration as of 3.4.0. */ void start_corpse_timeout(body) struct obj *body; { long when; /* rot away when this old */ long corpse_age; /* age of corpse */ int rot_adjust; short action; #define TAINT_AGE (50L) /* age when corpses go bad */ #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */ #define ROT_AGE (250L) /* age when corpses rot away */ /* lizards and lichen don't rot or revive */ if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return; action = ROT_CORPSE; /* default action: rot away */ rot_adjust = in_mklev ? 25 : 10; /* give some variation */ corpse_age = monstermoves - body->age; if (corpse_age > ROT_AGE) when = rot_adjust; else when = ROT_AGE - corpse_age; when += (long) (rnz(rot_adjust) - rot_adjust); if (is_rider(&mons[body->corpsenm])) { /* * Riders always revive. They have a 1/3 chance per turn * of reviving after 12 turns. Always revive by 500. */ action = REVIVE_MON; for (when = 12L; when < 500L; when++) if (!rn2(3)) break; } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) { long age; for (age = 2; age <= TAINT_AGE; age++) if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */ action = REVIVE_MON; when = age; break; } } if (body->norevive) body->norevive = 0; (void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body)); } STATIC_OVL void maybe_adjust_light(obj, old_range) struct obj *obj; int old_range; { char buf[BUFSZ]; xchar ox, oy; int new_range = arti_light_radius(obj), delta = new_range - old_range; /* radius of light emitting artifact varies by curse/bless state so will change after blessing or cursing */ if (delta) { obj_adjust_light_radius(obj, new_range); /* simplifying assumptions: hero is wielding this object; artifacts have to be in use to emit light and monsters' gear won't change bless or curse state */ if (!Blind && get_obj_location(obj, &ox, &oy, 0)) { *buf = '\0'; if (iflags.last_msg == PLNMSG_OBJ_GLOWS) /* we just saw "The glows ." from dipping */ Strcpy(buf, (obj->quan == 1L) ? "It" : "They"); else if (carried(obj) || cansee(ox, oy)) Strcpy(buf, Yname2(obj)); if (*buf) { /* initial activation says "dimly" if cursed, "brightly" if uncursed, and "brilliantly" if blessed; when changing intensity, using "less brightly" is straightforward for dimming, but we need "brighter" rather than "more brightly" for brightening; ugh */ pline("%s %s %s%s.", buf, otense(obj, "shine"), (abs(delta) > 1) ? "much " : "", (delta > 0) ? "brighter" : "less brightly"); } } } } /* * bless(), curse(), unbless(), uncurse() -- any relevant message * about glowing amber/black/&c should be delivered prior to calling * these routines to make the actual curse/bless state change. */ void bless(otmp) register struct obj *otmp; { int old_light = 0; if (otmp->oclass == COIN_CLASS) return; if (otmp->lamplit) old_light = arti_light_radius(otmp); otmp->cursed = 0; otmp->blessed = 1; if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE && otmp->timed) (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp)); if (otmp->lamplit) maybe_adjust_light(otmp, old_light); return; } void unbless(otmp) register struct obj *otmp; { int old_light = 0; if (otmp->lamplit) old_light = arti_light_radius(otmp); otmp->blessed = 0; if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); if (otmp->lamplit) maybe_adjust_light(otmp, old_light); } void curse(otmp) register struct obj *otmp; { int old_light = 0; if (otmp->oclass == COIN_CLASS) return; if (otmp->lamplit) old_light = arti_light_radius(otmp); otmp->blessed = 0; otmp->cursed = 1; /* welded two-handed weapon interferes with some armor removal */ if (otmp == uwep && bimanual(uwep)) reset_remarm(); /* rules at top of wield.c state that twoweapon cannot be done with cursed alternate weapon */ if (otmp == uswapwep && u.twoweap) drop_uswapwep(); /* some cursed items need immediate updating */ if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE) { if (otmp->corpsenm != NON_PM && !dead_species(otmp->corpsenm, TRUE) && (carried(otmp) || mcarried(otmp))) attach_fig_transform_timeout(otmp); } if (otmp->lamplit) maybe_adjust_light(otmp, old_light); return; } void uncurse(otmp) register struct obj *otmp; { int old_light = 0; if (otmp->lamplit) old_light = arti_light_radius(otmp); otmp->cursed = 0; if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE && otmp->timed) (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp)); if (otmp->lamplit) maybe_adjust_light(otmp, old_light); return; } void blessorcurse(otmp, chance) register struct obj *otmp; register int chance; { if (otmp->blessed || otmp->cursed) return; if (!rn2(chance)) { if (!rn2(2)) { curse(otmp); } else { bless(otmp); } } return; } int bcsign(otmp) register struct obj *otmp; { return (!!otmp->blessed - !!otmp->cursed); } /* * Calculate the weight of the given object. This will recursively follow * and calculate the weight of any containers. * * Note: It is possible to end up with an incorrect weight if some part * of the code messes with a contained object and doesn't update the * container's weight. */ int weight(obj) register struct obj *obj; { int wt = objects[obj->otyp].oc_weight; if (SchroedingersBox(obj)) wt += mons[PM_HOUSECAT].cwt; if (Is_container(obj) || obj->otyp == STATUE) { struct obj *contents; register int cwt = 0; if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM) wt = (int) obj->quan * ((int) mons[obj->corpsenm].cwt * 3 / 2); for (contents = obj->cobj; contents; contents = contents->nobj) cwt += weight(contents); /* * The weight of bags of holding is calculated as the weight * of the bag plus the weight of the bag's contents modified * as follows: * * Bag status Weight of contents * ---------- ------------------ * cursed 2x * blessed x/4 [rounded up: (x+3)/4] * otherwise x/2 [rounded up: (x+1)/2] * * The macro DELTA_CWT in pickup.c also implements these * weight equations. */ if (obj->otyp == BAG_OF_HOLDING) cwt = obj->cursed ? (cwt * 2) : obj->blessed ? ((cwt + 3) / 4) : ((cwt + 1) / 2); return wt + cwt; } if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) { long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt; wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int) long_wt; if (obj->oeaten) wt = eaten_stat(wt, obj); return wt; } else if (obj->oclass == FOOD_CLASS && obj->oeaten) { return eaten_stat((int) obj->quan * wt, obj); } else if (obj->oclass == COIN_CLASS) { return (int) ((obj->quan + 50L) / 100L); } else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) { return (int) obj->owt; /* kludge for "very" heavy iron ball */ } return (wt ? wt * (int) obj->quan : ((int) obj->quan + 1) >> 1); } static int treefruits[] = { APPLE, ORANGE, PEAR, BANANA, EUCALYPTUS_LEAF }; struct obj * rnd_treefruit_at(x, y) int x, y; { return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE); } struct obj * mkgold(amount, x, y) long amount; int x, y; { register struct obj *gold = g_at(x, y); if (amount <= 0L) amount = (long) (1 + rnd(level_difficulty() + 2) * rnd(30)); if (gold) { gold->quan += amount; } else { gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE); gold->quan = amount; } gold->owt = weight(gold); return gold; } /* return TRUE if the corpse has special timing */ #define special_corpse(num) \ (((num) == PM_LIZARD) || ((num) == PM_LICHEN) || (is_rider(&mons[num])) \ || (mons[num].mlet == S_TROLL)) /* * OEXTRA note: Passing mtmp causes mtraits to be saved * even if ptr passed as well, but ptr is always used for * the corpse type (corpsenm). That allows the corpse type * to be different from the original monster, * i.e. vampire -> human corpse * yet still allow restoration of the original monster upon * resurrection. */ struct obj * mkcorpstat(objtype, mtmp, ptr, x, y, corpstatflags) int objtype; /* CORPSE or STATUE */ struct monst *mtmp; struct permonst *ptr; int x, y; unsigned corpstatflags; { register struct obj *otmp; boolean init = ((corpstatflags & CORPSTAT_INIT) != 0); if (objtype != CORPSE && objtype != STATUE) impossible("making corpstat type %d", objtype); if (x == 0 && y == 0) { /* special case - random placement */ otmp = mksobj(objtype, init, FALSE); if (otmp) (void) rloco(otmp); } else otmp = mksobj_at(objtype, x, y, init, FALSE); if (otmp) { if (mtmp) { struct obj *otmp2; if (!ptr) ptr = mtmp->data; /* save_mtraits frees original data pointed to by otmp */ otmp2 = save_mtraits(otmp, mtmp); if (otmp2) otmp = otmp2; } /* use the corpse or statue produced by mksobj() as-is unless `ptr' is non-null */ if (ptr) { int old_corpsenm = otmp->corpsenm; otmp->corpsenm = monsndx(ptr); otmp->owt = weight(otmp); if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm) || special_corpse(otmp->corpsenm))) { obj_stop_timers(otmp); start_corpse_timeout(otmp); } } } return otmp; } /* * Return the type of monster that this corpse will * revive as, even if it has a monster structure * attached to it. In that case, you can't just * use obj->corpsenm, because the stored monster * type can, and often is, different. * The return value is an index into mons[]. */ int corpse_revive_type(obj) struct obj *obj; { int revivetype; struct monst *mtmp; if (has_omonst(obj) && ((mtmp = get_mtraits(obj, FALSE)) != (struct monst *) 0)) { /* mtmp is a temporary pointer to a monster's stored attributes, not a real monster */ revivetype = mtmp->mnum; } else revivetype = obj->corpsenm; return revivetype; } /* * Attach a monster id to an object, to provide * a lasting association between the two. */ struct obj * obj_attach_mid(obj, mid) struct obj *obj; unsigned mid; { if (!mid || !obj) return (struct obj *) 0; newomid(obj); *OMID(obj) = mid; return obj; } static struct obj * save_mtraits(obj, mtmp) struct obj *obj; struct monst *mtmp; { if (mtmp->ispriest) forget_temple_entry(mtmp); /* EPRI() */ if (!has_omonst(obj)) newomonst(obj); if (has_omonst(obj)) { struct monst *mtmp2 = OMONST(obj); *mtmp2 = *mtmp; mtmp2->mextra = (struct mextra *) 0; if (mtmp->data) mtmp2->mnum = monsndx(mtmp->data); /* invalidate pointers */ /* m_id is needed to know if this is a revived quest leader */ /* but m_id must be cleared when loading bones */ mtmp2->nmon = (struct monst *) 0; mtmp2->data = (struct permonst *) 0; mtmp2->minvent = (struct obj *) 0; if (mtmp->mextra) copy_mextra(mtmp2, mtmp); } return obj; } /* returns a pointer to a new monst structure based on * the one contained within the obj. */ struct monst * get_mtraits(obj, copyof) struct obj *obj; boolean copyof; { struct monst *mtmp = (struct monst *) 0; struct monst *mnew = (struct monst *) 0; if (has_omonst(obj)) mtmp = OMONST(obj); if (mtmp) { if (copyof) { mnew = newmonst(); *mnew = *mtmp; mnew->mextra = (struct mextra *) 0; if (mtmp->mextra) copy_mextra(mnew, mtmp); } else { /* Never insert this returned pointer into mon chains! */ mnew = mtmp; } } return mnew; } /* make an object named after someone listed in the scoreboard file */ struct obj * mk_tt_object(objtype, x, y) int objtype; /* CORPSE or STATUE */ register int x, y; { register struct obj *otmp, *otmp2; boolean initialize_it; /* player statues never contain books */ initialize_it = (objtype != STATUE); if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) { /* tt_oname will return null if the scoreboard is empty */ if ((otmp2 = tt_oname(otmp)) != 0) otmp = otmp2; } return otmp; } /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */ struct obj * mk_named_object(objtype, ptr, x, y, nm) int objtype; /* CORPSE or STATUE */ struct permonst *ptr; int x, y; const char *nm; { struct obj *otmp; unsigned corpstatflags = (objtype != STATUE) ? CORPSTAT_INIT : CORPSTAT_NONE; otmp = mkcorpstat(objtype, (struct monst *) 0, ptr, x, y, corpstatflags); if (nm) otmp = oname(otmp, nm); return otmp; } boolean is_flammable(otmp) register struct obj *otmp; { int otyp = otmp->otyp; int omat = objects[otyp].oc_material; /* Candles can be burned, but they're not flammable in the sense that * they can't get fire damage and it makes no sense for them to be * fireproofed. */ if (Is_candle(otmp)) return FALSE; if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE) return FALSE; return (boolean) ((omat <= WOOD && omat != LIQUID) || omat == PLASTIC); } boolean is_rottable(otmp) register struct obj *otmp; { int otyp = otmp->otyp; return (boolean) (objects[otyp].oc_material <= WOOD && objects[otyp].oc_material != LIQUID); } /* * These routines maintain the single-linked lists headed in level.objects[][] * and threaded through the nexthere fields in the object-instance structure. */ /* put the object at the given location */ void place_object(otmp, x, y) register struct obj *otmp; int x, y; { register struct obj *otmp2 = level.objects[x][y]; if (otmp->where != OBJ_FREE) panic("place_object: obj not free"); obj_no_longer_held(otmp); /* (could bypass this vision update if there is already a boulder here) */ if (otmp->otyp == BOULDER) block_point(x, y); /* vision */ /* obj goes under boulders */ if (otmp2 && (otmp2->otyp == BOULDER)) { otmp->nexthere = otmp2->nexthere; otmp2->nexthere = otmp; } else { otmp->nexthere = otmp2; level.objects[x][y] = otmp; } /* set the new object's location */ otmp->ox = x; otmp->oy = y; otmp->where = OBJ_FLOOR; /* add to floor chain */ otmp->nobj = fobj; fobj = otmp; if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } #define ROT_ICE_ADJUSTMENT 2 /* rotting on ice takes 2 times as long */ /* If ice was affecting any objects correct that now * Also used for starting ice effects too. [zap.c] */ void obj_ice_effects(x, y, do_buried) int x, y; boolean do_buried; { struct obj *otmp; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } if (do_buried) { for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) { if (otmp->ox == x && otmp->oy == y) { if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } } } } /* * Returns an obj->age for a corpse object on ice, that would be the * actual obj->age if the corpse had just been lifted from the ice. * This is useful when just using obj->age in a check or calculation because * rot timers pertaining to the object don't have to be stopped and * restarted etc. */ long peek_at_iced_corpse_age(otmp) struct obj *otmp; { long age, retval = otmp->age; if (otmp->otyp == CORPSE && otmp->on_ice) { /* Adjust the age; must be same as obj_timer_checks() for off ice*/ age = monstermoves - otmp->age; retval += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT; debugpline3( "The %s age has ice modifications: otmp->age = %ld, returning %ld.", s_suffix(doname(otmp)), otmp->age, retval); debugpline1("Effective age of corpse: %ld.", monstermoves - retval); } return retval; } STATIC_OVL void obj_timer_checks(otmp, x, y, force) struct obj *otmp; xchar x, y; int force; /* 0 = no force so do checks, <0 = force off, >0 force on */ { long tleft = 0L; short action = ROT_CORPSE; boolean restart_timer = FALSE; boolean on_floor = (otmp->where == OBJ_FLOOR); boolean buried = (otmp->where == OBJ_BURIED); /* Check for corpses just placed on or in ice */ if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x, y)) { tleft = stop_timer(action, obj_to_any(otmp)); if (tleft == 0L) { action = REVIVE_MON; tleft = stop_timer(action, obj_to_any(otmp)); } if (tleft != 0L) { long age; /* mark the corpse as being on ice */ otmp->on_ice = 1; debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x, y); /* Adjust the time remaining */ tleft *= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age; time spent off ice needs to be multiplied by the ice adjustment and subtracted from the age so that later calculations behave as if it had been on ice during that time (longwinded way of saying this is the inverse of removing it from the ice and of peeking at its age). */ age = monstermoves - otmp->age; otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT); } /* Check for corpses coming off ice */ } else if (force < 0 || (otmp->otyp == CORPSE && otmp->on_ice && !((on_floor || buried) && is_ice(x, y)))) { tleft = stop_timer(action, obj_to_any(otmp)); if (tleft == 0L) { action = REVIVE_MON; tleft = stop_timer(action, obj_to_any(otmp)); } if (tleft != 0L) { long age; otmp->on_ice = 0; debugpline3("%s is no longer on ice at <%d,%d>.", The(xname(otmp)), x, y); /* Adjust the remaining time */ tleft /= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age */ age = monstermoves - otmp->age; otmp->age += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT; } } /* now re-start the timer with the appropriate modifications */ if (restart_timer) (void) start_timer(tleft, TIMER_OBJECT, action, obj_to_any(otmp)); } #undef ROT_ICE_ADJUSTMENT void remove_object(otmp) register struct obj *otmp; { xchar x = otmp->ox; xchar y = otmp->oy; if (otmp->where != OBJ_FLOOR) panic("remove_object: obj not on floor"); extract_nexthere(otmp, &level.objects[x][y]); extract_nobj(otmp, &fobj); /* update vision iff this was the only boulder at its spot */ if (otmp->otyp == BOULDER && !sobj_at(BOULDER, x, y)) unblock_point(x, y); /* vision */ if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } /* throw away all of a monster's inventory */ void discard_minvent(mtmp) struct monst *mtmp; { struct obj *otmp, *mwep = MON_WEP(mtmp); boolean keeping_mon = (mtmp->mhp > 0); while ((otmp = mtmp->minvent) != 0) { /* this has now become very similar to m_useupall()... */ obj_extract_self(otmp); if (otmp->owornmask) { if (keeping_mon) { if (otmp == mwep) mwepgone(mtmp), mwep = 0; mtmp->misc_worn_check &= ~otmp->owornmask; update_mon_intrinsics(mtmp, otmp, FALSE, TRUE); } otmp->owornmask = 0L; /* obfree() expects this */ } obfree(otmp, (struct obj *) 0); /* dealloc_obj() isn't sufficient */ } } /* * Free obj from whatever list it is on in preparation for deleting it * or moving it elsewhere; obj->where will end up set to OBJ_FREE. * Doesn't handle unwearing of objects in hero's or monsters' inventories. * * Object positions: * OBJ_FREE not on any list * OBJ_FLOOR fobj, level.locations[][] chains (use remove_object) * OBJ_CONTAINED cobj chain of container object * OBJ_INVENT hero's invent chain (use freeinv) * OBJ_MINVENT monster's invent chain * OBJ_MIGRATING migrating chain * OBJ_BURIED level.buriedobjs chain * OBJ_ONBILL on billobjs chain */ void obj_extract_self(obj) struct obj *obj; { switch (obj->where) { case OBJ_FREE: break; case OBJ_FLOOR: remove_object(obj); break; case OBJ_CONTAINED: extract_nobj(obj, &obj->ocontainer->cobj); container_weight(obj->ocontainer); break; case OBJ_INVENT: freeinv(obj); break; case OBJ_MINVENT: extract_nobj(obj, &obj->ocarry->minvent); break; case OBJ_MIGRATING: extract_nobj(obj, &migrating_objs); break; case OBJ_BURIED: extract_nobj(obj, &level.buriedobjlist); break; case OBJ_ONBILL: extract_nobj(obj, &billobjs); break; default: panic("obj_extract_self"); break; } } /* Extract the given object from the chain, following nobj chain. */ void extract_nobj(obj, head_ptr) struct obj *obj, **head_ptr; { struct obj *curr, *prev; curr = *head_ptr; for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) { if (curr == obj) { if (prev) prev->nobj = curr->nobj; else *head_ptr = curr->nobj; break; } } if (!curr) panic("extract_nobj: object lost"); obj->where = OBJ_FREE; obj->nobj = NULL; } /* * Extract the given object from the chain, following nexthere chain. * * This does not set obj->where, this function is expected to be called * in tandem with extract_nobj, which does set it. */ void extract_nexthere(obj, head_ptr) struct obj *obj, **head_ptr; { struct obj *curr, *prev; curr = *head_ptr; for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) { if (curr == obj) { if (prev) prev->nexthere = curr->nexthere; else *head_ptr = curr->nexthere; break; } } if (!curr) panic("extract_nexthere: object lost"); } /* * Add obj to mon's inventory. If obj is able to merge with something already * in the inventory, then the passed obj is deleted and 1 is returned. * Otherwise 0 is returned. */ int add_to_minv(mon, obj) struct monst *mon; struct obj *obj; { struct obj *otmp; if (obj->where != OBJ_FREE) panic("add_to_minv: obj not free"); /* merge if possible */ for (otmp = mon->minvent; otmp; otmp = otmp->nobj) if (merged(&otmp, &obj)) return 1; /* obj merged and then free'd */ /* else insert; don't bother forcing it to end of chain */ obj->where = OBJ_MINVENT; obj->ocarry = mon; obj->nobj = mon->minvent; mon->minvent = obj; return 0; /* obj on mon's inventory chain */ } /* * Add obj to container, make sure obj is "free". Returns (merged) obj. * The input obj may be deleted in the process. */ struct obj * add_to_container(container, obj) struct obj *container, *obj; { struct obj *otmp; if (obj->where != OBJ_FREE) panic("add_to_container: obj not free"); if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT) obj_no_longer_held(obj); /* merge if possible */ for (otmp = container->cobj; otmp; otmp = otmp->nobj) if (merged(&otmp, &obj)) return otmp; obj->where = OBJ_CONTAINED; obj->ocontainer = container; obj->nobj = container->cobj; container->cobj = obj; return obj; } void add_to_migration(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("add_to_migration: obj not free"); obj->where = OBJ_MIGRATING; obj->nobj = migrating_objs; migrating_objs = obj; } void add_to_buried(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("add_to_buried: obj not free"); obj->where = OBJ_BURIED; obj->nobj = level.buriedobjlist; level.buriedobjlist = obj; } /* Recalculate the weight of this container and all of _its_ containers. */ STATIC_OVL void container_weight(container) struct obj *container; { container->owt = weight(container); if (container->where == OBJ_CONTAINED) container_weight(container->ocontainer); /* else if (container->where == OBJ_INVENT) recalculate load delay here ??? */ } /* * Deallocate the object. _All_ objects should be run through here for * them to be deallocated. */ void dealloc_obj(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("dealloc_obj: obj not free"); if (obj->nobj) panic("dealloc_obj with nobj"); if (obj->cobj) panic("dealloc_obj with cobj"); /* free up any timers attached to the object */ if (obj->timed) obj_stop_timers(obj); /* * Free up any light sources attached to the object. * * We may want to just call del_light_source() without any * checks (requires a code change there). Otherwise this * list must track all objects that can have a light source * attached to it (and also requires lamplit to be set). */ if (obj_sheds_light(obj)) del_light_source(LS_OBJECT, obj_to_any(obj)); if (obj == thrownobj) thrownobj = 0; if (obj == kickedobj) kickedobj = 0; if (obj->oextra) dealloc_oextra(obj); free((genericptr_t) obj); } /* create an object from a horn of plenty; mirrors bagotricks(makemon.c) */ int hornoplenty(horn, tipping) struct obj *horn; boolean tipping; /* caller emptying entire contents; affects shop handling */ { int objcount = 0; if (!horn || horn->otyp != HORN_OF_PLENTY) { impossible("bad horn o' plenty"); } else if (horn->spe < 1) { pline1(nothing_happens); } else { struct obj *obj; const char *what; consume_obj_charge(horn, !tipping); if (!rn2(13)) { obj = mkobj(POTION_CLASS, FALSE); if (objects[obj->otyp].oc_magic) do { obj->otyp = rnd_class(POT_BOOZE, POT_WATER); } while (obj->otyp == POT_SICKNESS); what = (obj->quan > 1L) ? "Some potions" : "A potion"; } else { obj = mkobj(FOOD_CLASS, FALSE); if (obj->otyp == FOOD_RATION && !rn2(7)) obj->otyp = LUMP_OF_ROYAL_JELLY; what = "Some food"; } ++objcount; pline("%s %s out.", what, vtense(what, "spill")); obj->blessed = horn->blessed; obj->cursed = horn->cursed; obj->owt = weight(obj); /* using a shop's horn of plenty entails a usage fee and also confers ownership of the created item to the shopkeeper */ if (horn->unpaid) addtobill(obj, FALSE, FALSE, tipping); /* if it ended up on bill, we don't want "(unpaid, N zorkids)" being included in its formatted name during next message */ iflags.suppress_price++; if (!tipping) { obj = hold_another_object( obj, u.uswallow ? "Oops! %s out of your reach!" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || levl[u.ux][u.uy].typ < IRONBARS || levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" : "Oops! %s to the floor!", The(aobjnam(obj, "slip")), (const char *) 0); } else { /* assumes this is taking place at hero's location */ if (!can_reach_floor(TRUE)) { hitfloor(obj); /* does altar check, message, drop */ } else { if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); /* does its own drop message */ else pline("%s %s to the %s.", Doname2(obj), otense(obj, "drop"), surface(u.ux, u.uy)); dropy(obj); } } iflags.suppress_price--; if (horn->dknown) makeknown(HORN_OF_PLENTY); } return objcount; } /* support for wizard-mode's `sanity_check' option */ static const char NEARDATA /* pline formats for insane_object() */ ofmt0[] = "%s obj %s %s: %s", ofmt3[] = "%s [not null] %s %s: %s", /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */ mfmt1[] = "%s obj %s %s (%s)", mfmt2[] = "%s obj %s %s (%s) *not*"; /* Check all object lists for consistency. */ void obj_sanity_check() { int x, y; struct obj *obj; objlist_sanity(fobj, OBJ_FLOOR, "floor sanity"); /* check that the map's record of floor objects is consistent; those objects should have already been sanity checked via the floor list so container contents are skipped here */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) for (obj = level.objects[x][y]; obj; obj = obj->nexthere) { /* should match ; <0,*> should always be empty */ if (obj->where != OBJ_FLOOR || x == 0 || obj->ox != x || obj->oy != y) { char at_fmt[BUFSZ]; Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", x, y, obj->ox, obj->oy); insane_object(obj, at_fmt, "location sanity", (struct monst *) 0); } } objlist_sanity(invent, OBJ_INVENT, "invent sanity"); objlist_sanity(migrating_objs, OBJ_MIGRATING, "migrating sanity"); objlist_sanity(level.buriedobjlist, OBJ_BURIED, "buried sanity"); objlist_sanity(billobjs, OBJ_ONBILL, "bill sanity"); mon_obj_sanity(fmon, "minvent sanity"); mon_obj_sanity(migrating_mons, "migrating minvent sanity"); /* monsters temporarily in transit; they should have arrived with hero by the time we get called */ if (mydogs) { pline("mydogs sanity [not empty]"); mon_obj_sanity(mydogs, "mydogs minvent sanity"); } /* objects temporarily freed from invent/floor lists; they should have arrived somewhere by the time we get called */ if (thrownobj) insane_object(thrownobj, ofmt3, "thrownobj sanity", (struct monst *) 0); if (kickedobj) insane_object(kickedobj, ofmt3, "kickedobj sanity", (struct monst *) 0); /* [how about current_wand too?] */ } /* sanity check for objects on specified list (fobj, &c) */ STATIC_OVL void objlist_sanity(objlist, wheretype, mesg) struct obj *objlist; int wheretype; const char *mesg; { struct obj *obj; for (obj = objlist; obj; obj = obj->nobj) { if (obj->where != wheretype) insane_object(obj, ofmt0, mesg, (struct monst *) 0); if (Has_contents(obj)) { if (wheretype == OBJ_ONBILL) /* containers on shop bill should always be empty */ insane_object(obj, "%s obj contains something! %s %s: %s", mesg, (struct monst *) 0); check_contained(obj, mesg); } if (obj->owornmask) { char maskbuf[40]; boolean bc_ok = FALSE; switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: sanity_check_worn(obj); break; case OBJ_MIGRATING: /* migrating objects overload the owornmask field with a destination code; skip attempt to check it */ break; case OBJ_FLOOR: /* note: ball and chain can also be OBJ_FREE, but not across turns so this sanity check shouldn't encounter that */ bc_ok = TRUE; /*FALLTHRU*/ default: if ((obj != uchain && obj != uball) || !bc_ok) { /* discovered an object not in inventory which erroneously has worn mask set */ Sprintf(maskbuf, "worn mask 0x%08lx", obj->owornmask); insane_object(obj, ofmt0, maskbuf, (struct monst *) 0); } break; } } } } /* sanity check for objects carried by all monsters in specified list */ STATIC_OVL void mon_obj_sanity(monlist, mesg) struct monst *monlist; const char *mesg; { struct monst *mon; struct obj *obj, *mwep; for (mon = monlist; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; mwep = MON_WEP(mon); if (mwep) { if (!mcarried(mwep)) insane_object(mwep, mfmt1, mesg, mon); if (mwep->ocarry != mon) insane_object(mwep, mfmt2, mesg, mon); } for (obj = mon->minvent; obj; obj = obj->nobj) { if (obj->where != OBJ_MINVENT) insane_object(obj, mfmt1, mesg, mon); if (obj->ocarry != mon) insane_object(obj, mfmt2, mesg, mon); check_contained(obj, mesg); } } } /* This must stay consistent with the defines in obj.h. */ static const char *obj_state_names[NOBJ_STATES] = { "free", "floor", "contained", "invent", "minvent", "migrating", "buried", "onbill" }; STATIC_OVL const char * where_name(obj) struct obj *obj; { static char unknown[32]; /* big enough to handle rogue 64-bit int */ int where; if (!obj) return "nowhere"; where = obj->where; if (where < 0 || where >= NOBJ_STATES || !obj_state_names[where]) { Sprintf(unknown, "unknown[%d]", where); return unknown; } return obj_state_names[where]; } STATIC_OVL void insane_object(obj, fmt, mesg, mon) struct obj *obj; const char *fmt, *mesg; struct monst *mon; { const char *objnm, *monnm; char altfmt[BUFSZ]; objnm = monnm = "null!"; if (obj) { iflags.override_ID++; objnm = doname(obj); iflags.override_ID--; } if (mon || (strstri(mesg, "minvent") && !strstri(mesg, "contained"))) { Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)"); if (mon) monnm = x_monnam(mon, ARTICLE_A, (char *) 0, EXACT_NAME, TRUE); pline(altfmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj), objnm, fmt_ptr((genericptr_t) mon), monnm); } else { pline(fmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj), objnm); } } /* obj sanity check: check objects inside container */ STATIC_OVL void check_contained(container, mesg) struct obj *container; const char *mesg; { struct obj *obj; /* big enough to work with, not too big to blow out stack in recursion */ char mesgbuf[40], nestedmesg[120]; if (!Has_contents(container)) return; /* change "invent sanity" to "contained invent sanity" but leave "nested contained invent sanity" as is */ if (!strstri(mesg, "contained")) mesg = strcat(strcpy(mesgbuf, "contained "), mesg); for (obj = container->cobj; obj; obj = obj->nobj) { /* catch direct cycle to avoid unbounded recursion */ if (obj == container) panic("failed sanity check: container holds itself"); if (obj->where != OBJ_CONTAINED) insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *) 0); else if (obj->ocontainer != container) pline("%s obj %s in container %s, not %s", mesg, fmt_ptr((genericptr_t) obj), fmt_ptr((genericptr_t) obj->ocontainer), fmt_ptr((genericptr_t) container)); if (Has_contents(obj)) { /* catch most likely indirect cycle; we won't notice if parent is present when something comes before it, or notice more deeply embedded cycles (grandparent, &c) */ if (obj->cobj == container) panic("failed sanity check: container holds its parent"); /* change "contained... sanity" to "nested contained... sanity" and "nested contained..." to "nested nested contained..." */ Strcpy(nestedmesg, "nested "); copynchars(eos(nestedmesg), mesg, (int) sizeof nestedmesg - (int) strlen(nestedmesg) - 1); /* recursively check contents */ check_contained(obj, nestedmesg); } } } /* check an object in hero's or monster's inventory which has worn mask set */ STATIC_OVL void sanity_check_worn(obj) struct obj *obj; { #if defined(BETA) || defined(DEBUG) static unsigned long wearbits[] = { W_ARM, W_ARMC, W_ARMH, W_ARMS, W_ARMG, W_ARMF, W_ARMU, W_WEP, W_QUIVER, W_SWAPWEP, W_AMUL, W_RINGL, W_RINGR, W_TOOL, W_SADDLE, W_BALL, W_CHAIN, 0 /* [W_ART,W_ARTI are property bits for items which aren't worn] */ }; char maskbuf[60]; const char *what; unsigned long owornmask, allmask = 0L; boolean embedded = FALSE; int i, n = 0; /* use owornmask for testing and bit twiddling, but use original obj->owornmask for printing */ owornmask = obj->owornmask; /* figure out how many bits are set, and also which are viable */ for (i = 0; wearbits[i]; ++i) { if ((owornmask & wearbits[i]) != 0L) ++n; allmask |= wearbits[i]; } if (obj == uskin) { /* embedded dragon scales have an extra bit set; make sure it's set, then suppress it */ embedded = TRUE; if ((owornmask & (W_ARM | I_SPECIAL)) == (W_ARM | I_SPECIAL)) owornmask &= ~I_SPECIAL; else n = 0, owornmask = ~0; /* force insane_object("bogus") below */ } if (n == 2 && carried(obj) && obj == uball && (owornmask & W_BALL) != 0L && (owornmask & W_WEAPON) != 0L) { /* chained ball can be wielded/alt-wielded/quivered; if so, pretend it's not chained in order to check the weapon pointer (we've already verified the ball pointer by successfully passing the if-condition to get here...) */ owornmask &= ~W_BALL; n = 1; } if (n > 1) { /* multiple bits set */ Sprintf(maskbuf, "worn mask (multiple) 0x%08lx", obj->owornmask); insane_object(obj, ofmt0, maskbuf, (struct monst *) 0); } if ((owornmask & ~allmask) != 0L || (carried(obj) && (owornmask & W_SADDLE) != 0L)) { /* non-wearable bit(s) set */ Sprintf(maskbuf, "worn mask (bogus)) 0x%08lx", obj->owornmask); insane_object(obj, ofmt0, maskbuf, (struct monst *) 0); } if (n == 1 && (carried(obj) || (owornmask & (W_BALL | W_CHAIN)) != 0L)) { what = 0; /* verify that obj in hero's invent (or ball/chain elsewhere) with owornmask of W_foo is the object pointed to by ufoo */ switch (owornmask) { case W_ARM: if (obj != (embedded ? uskin : uarm)) what = embedded ? "skin" : "suit"; break; case W_ARMC: if (obj != uarmc) what = "cloak"; break; case W_ARMH: if (obj != uarmh) what = "helm"; break; case W_ARMS: if (obj != uarms) what = "shield"; break; case W_ARMG: if (obj != uarmg) what = "gloves"; break; case W_ARMF: if (obj != uarmf) what = "boots"; break; case W_ARMU: if (obj != uarmu) what = "shirt"; break; case W_WEP: if (obj != uwep) what = "primary weapon"; break; case W_QUIVER: if (obj != uquiver) what = "quiver"; break; case W_SWAPWEP: if (obj != uswapwep) what = u.twoweap ? "secondary weapon" : "alternate weapon"; break; case W_AMUL: if (obj != uamul) what = "amulet"; break; case W_RINGL: if (obj != uleft) what = "left ring"; break; case W_RINGR: if (obj != uright) what = "right ring"; break; case W_TOOL: if (obj != ublindf) what = "blindfold"; break; /* case W_SADDLE: */ case W_BALL: if (obj != uball) what = "ball"; break; case W_CHAIN: if (obj != uchain) what = "chain"; break; default: break; } if (what) { Sprintf(maskbuf, "worn mask 0x%08lx != %s", obj->owornmask, what); insane_object(obj, ofmt0, maskbuf, (struct monst *) 0); } } if (n == 1 && (carried(obj) || (owornmask & (W_BALL | W_CHAIN)) != 0L || mcarried(obj))) { /* check for items worn in invalid slots; practically anything can be wielded/alt-wielded/quivered, so tests on those are limited */ what = 0; if (owornmask & W_ARMOR) { if (obj->oclass != ARMOR_CLASS) what = "armor"; /* 3.6: dragon scale mail reverts to dragon scales when becoming embedded in poly'd hero's skin */ if (embedded && !Is_dragon_scales(obj)) what = "skin"; } else if (owornmask & W_WEAPON) { /* monsters don't maintain alternate weapon or quiver */ if (mcarried(obj) && (owornmask & (W_SWAPWEP | W_QUIVER)) != 0L) what = (owornmask & W_SWAPWEP) != 0L ? "monst alt weapon?" : "monst quiver?"; /* hero can quiver gold but not wield it (hence not alt-wield it either); also catches monster wielding gold */ else if (obj->oclass == COIN_CLASS && (owornmask & (W_WEP | W_SWAPWEP)) != 0L) what = (owornmask & W_WEP) != 0L ? "weapon" : "alt weapon"; } else if (owornmask & W_AMUL) { if (obj->oclass != AMULET_CLASS) what = "amulet"; } else if (owornmask & W_RING) { if (obj->oclass != RING_CLASS && obj->otyp != MEAT_RING) what = "ring"; } else if (owornmask & W_TOOL) { if (obj->otyp != BLINDFOLD && obj->otyp != TOWEL && obj->otyp != LENSES) what = "blindfold"; } else if (owornmask & W_BALL) { if (obj->oclass != BALL_CLASS) what = "chained ball"; } else if (owornmask & W_CHAIN) { if (obj->oclass != CHAIN_CLASS) what = "chain"; } else if (owornmask & W_SADDLE) { if (obj->otyp != SADDLE) what = "saddle"; } if (what) { char oclassname[30]; struct monst *mon = mcarried(obj) ? obj->ocarry : 0; /* if we've found a potion worn in the amulet slot, this yields "worn (potion amulet)" */ Strcpy(oclassname, def_oc_syms[(uchar) obj->oclass].name); Sprintf(maskbuf, "worn (%s %s)", makesingular(oclassname), what); insane_object(obj, ofmt0, maskbuf, mon); } } #else /* not (BETA || DEBUG) */ /* dummy use of obj to avoid "arg not used" complaint */ if (!obj) insane_object(obj, ofmt0, "", (struct monst *) 0); #endif } /* * wrapper to make "near this object" convenient */ struct obj * obj_nexto(otmp) struct obj *otmp; { struct obj *otmp2 = (struct obj *) 0; if (otmp) { otmp2 = obj_nexto_xy(otmp->otyp, otmp->ox, otmp->oy, otmp->o_id); } else { impossible("obj_nexto: wasn't given an object to check"); } return otmp2; } /* * looks for objects of a particular type next to x, y * skips over oid if found (lets us avoid ourselves if * we're looking for a second type of an existing object) * * TODO: return a list of all objects near us so we can more * reliably predict which one we want to 'find' first */ struct obj * obj_nexto_xy(otyp, x, y, oid) int otyp, x, y; unsigned oid; { struct obj *otmp; int fx, fy, ex, ey; short dx, dy; /* check under our "feet" first */ otmp = sobj_at(otyp, x, y); while (otmp) { /* don't be clever and find ourselves */ if (otmp->o_id != oid) { return otmp; } otmp = nxtobj(otmp, otyp, TRUE); } /* search in a random order */ dx = (rn2(2) ? -1 : 1); dy = (rn2(2) ? -1 : 1); ex = x - dx; ey = y - dy; for (fx = ex; abs(fx - ex) < 3; fx += dx) { for (fy = ey; abs(fy - ey) < 3; fy += dy) { /* 0, 0 was checked above */ if (isok(fx, fy) && (fx != x || fy != y)) { if ((otmp = sobj_at(otyp, fx, fy)) != 0) { return otmp; } } } } return (struct obj *) 0; } /* * Causes one object to absorb another, increasing * weight accordingly. Frees obj2; obj1 remains and * is returned. */ struct obj * obj_absorb(obj1, obj2) struct obj **obj1, **obj2; { struct obj *otmp1 = (struct obj *) 0, *otmp2 = (struct obj *) 0; int extrawt = 0; /* don't let people dumb it up */ if (obj1 && obj2) { otmp1 = *obj1; otmp2 = *obj2; if (otmp1 && otmp2) { extrawt = otmp2->oeaten ? otmp2->oeaten : otmp2->owt; otmp1->owt += extrawt; otmp1->oeaten += otmp1->oeaten ? extrawt : 0; otmp1->quan = 1; obj_extract_self(otmp2); newsym(otmp2->ox, otmp2->oy); /* in case of floor */ dealloc_obj(otmp2); *obj2 = (struct obj *) 0; return otmp1; } } impossible("obj_absorb: not called with two actual objects"); return (struct obj *) 0; } /* * Causes the heavier object to absorb the lighter object; * wrapper for obj_absorb so that floor_effects works more * cleanly (since we don't know which we want to stay around) */ struct obj * obj_meld(obj1, obj2) struct obj **obj1, **obj2; { struct obj *otmp1 = (struct obj *) 0, *otmp2 = (struct obj *) 0; if (obj1 && obj2) { otmp1 = *obj1; otmp2 = *obj2; if (otmp1 && otmp2) { if (otmp1->owt > otmp2->owt || rn2(2)) { return obj_absorb(obj1, obj2); } return obj_absorb(obj2, obj1); } } impossible("obj_meld: not called with two actual objects"); return (struct obj *) 0; } /*mkobj.c*/ nethack-3.6.0/src/mkroom.c0000664000076400007660000006376612622262031014412 0ustar paxedpaxed/* NetHack 3.6 mkroom.c $NHDT-Date: 1446887530 2015/11/07 09:12:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * Entry points: * mkroom() -- make and stock a room of a given type * nexttodoor() -- return TRUE if adjacent to a door * has_dnstairs() -- return TRUE if given room has a down staircase * has_upstairs() -- return TRUE if given room has an up staircase * courtmon() -- generate a court monster * save_rooms() -- save rooms into file fd * rest_rooms() -- restore rooms from file fd * cmap_to_type() -- convert S_xxx symbol to XXX topology code */ #include "hack.h" STATIC_DCL boolean FDECL(isbig, (struct mkroom *)); STATIC_DCL struct mkroom *FDECL(pick_room, (BOOLEAN_P)); STATIC_DCL void NDECL(mkshop), FDECL(mkzoo, (int)), NDECL(mkswamp); STATIC_DCL void NDECL(mktemple); STATIC_DCL coord *FDECL(shrine_pos, (int)); STATIC_DCL struct permonst *NDECL(morguemon); STATIC_DCL struct permonst *NDECL(squadmon); STATIC_DCL void FDECL(save_room, (int, struct mkroom *)); STATIC_DCL void FDECL(rest_room, (int, struct mkroom *)); #define sq(x) ((x) * (x)) extern const struct shclass shtypes[]; /* defined in shknam.c */ STATIC_OVL boolean isbig(sroom) register struct mkroom *sroom; { register int area = (sroom->hx - sroom->lx + 1) * (sroom->hy - sroom->ly + 1); return (boolean) (area > 20); } /* make and stock a room of a given type */ void mkroom(roomtype) int roomtype; { if (roomtype >= SHOPBASE) mkshop(); /* someday, we should be able to specify shop type */ else switch (roomtype) { case COURT: mkzoo(COURT); break; case ZOO: mkzoo(ZOO); break; case BEEHIVE: mkzoo(BEEHIVE); break; case MORGUE: mkzoo(MORGUE); break; case BARRACKS: mkzoo(BARRACKS); break; case SWAMP: mkswamp(); break; case TEMPLE: mktemple(); break; case LEPREHALL: mkzoo(LEPREHALL); break; case COCKNEST: mkzoo(COCKNEST); break; case ANTHOLE: mkzoo(ANTHOLE); break; default: impossible("Tried to make a room of type %d.", roomtype); } } STATIC_OVL void mkshop() { register struct mkroom *sroom; int i = -1; char *ep = (char *) 0; /* (init == lint suppression) */ /* first determine shoptype */ if (wizard) { #ifndef MAC ep = nh_getenv("SHOPTYPE"); if (ep) { if (*ep == 'z' || *ep == 'Z') { mkzoo(ZOO); return; } if (*ep == 'm' || *ep == 'M') { mkzoo(MORGUE); return; } if (*ep == 'b' || *ep == 'B') { mkzoo(BEEHIVE); return; } if (*ep == 't' || *ep == 'T' || *ep == '\\') { mkzoo(COURT); return; } if (*ep == 's' || *ep == 'S') { mkzoo(BARRACKS); return; } if (*ep == 'a' || *ep == 'A') { mkzoo(ANTHOLE); return; } if (*ep == 'c' || *ep == 'C') { mkzoo(COCKNEST); return; } if (*ep == 'l' || *ep == 'L') { mkzoo(LEPREHALL); return; } if (*ep == '_') { mktemple(); return; } if (*ep == '}') { mkswamp(); return; } for (i = 0; shtypes[i].name; i++) if (*ep == def_oc_syms[(int) shtypes[i].symb].sym) goto gottype; if (*ep == 'g' || *ep == 'G') i = 0; else if (*ep == 'v' || *ep == 'V') i = FODDERSHOP - SHOPBASE; /* veggy food */ else i = -1; } #endif } #ifndef MAC gottype: #endif for (sroom = &rooms[0];; sroom++) { if (sroom->hx < 0) return; if (sroom - rooms >= nroom) { pline("rooms not closed by -1?"); return; } if (sroom->rtype != OROOM) continue; if (has_dnstairs(sroom) || has_upstairs(sroom)) continue; if ((wizard && ep && sroom->doorct != 0) || sroom->doorct == 1) break; } if (!sroom->rlit) { int x, y; for (x = sroom->lx - 1; x <= sroom->hx + 1; x++) for (y = sroom->ly - 1; y <= sroom->hy + 1; y++) levl[x][y].lit = 1; sroom->rlit = 1; } if (i < 0) { /* shoptype not yet determined */ register int j; /* pick a shop type at random */ for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++) continue; /* big rooms cannot be wand or book shops, * - so make them general stores */ if (isbig(sroom) && (shtypes[i].symb == WAND_CLASS || shtypes[i].symb == SPBOOK_CLASS)) i = 0; } sroom->rtype = SHOPBASE + i; /* set room bits before stocking the shop */ #ifdef SPECIALIZATION topologize(sroom, FALSE); /* doesn't matter - this is a special room */ #else topologize(sroom); #endif /* stock the room with a shopkeeper and artifacts */ stock_room(i, sroom); } /* pick an unused room, preferably with only one door */ STATIC_OVL struct mkroom * pick_room(strict) register boolean strict; { register struct mkroom *sroom; register int i = nroom; for (sroom = &rooms[rn2(nroom)]; i--; sroom++) { if (sroom == &rooms[nroom]) sroom = &rooms[0]; if (sroom->hx < 0) return (struct mkroom *) 0; if (sroom->rtype != OROOM) continue; if (!strict) { if (has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3))) continue; } else if (has_upstairs(sroom) || has_dnstairs(sroom)) continue; if (sroom->doorct == 1 || !rn2(5) || wizard) return sroom; } return (struct mkroom *) 0; } STATIC_OVL void mkzoo(type) int type; { register struct mkroom *sroom; if ((sroom = pick_room(FALSE)) != 0) { sroom->rtype = type; fill_zoo(sroom); } } void fill_zoo(sroom) struct mkroom *sroom; { struct monst *mon; register int sx, sy, i; int sh, tx = 0, ty = 0, goldlim = 0, type = sroom->rtype; int rmno = (int) ((sroom - rooms) + ROOMOFFSET); coord mm; sh = sroom->fdoor; switch (type) { case COURT: if (level.flags.is_maze_lev) { for (tx = sroom->lx; tx <= sroom->hx; tx++) for (ty = sroom->ly; ty <= sroom->hy; ty++) if (IS_THRONE(levl[tx][ty].typ)) goto throne_placed; } i = 100; do { /* don't place throne on top of stairs */ (void) somexy(sroom, &mm); tx = mm.x; ty = mm.y; } while (occupied((xchar) tx, (xchar) ty) && --i > 0); throne_placed: /* TODO: try to ensure the enthroned monster is an M2_PRINCE */ break; case BEEHIVE: tx = sroom->lx + (sroom->hx - sroom->lx + 1) / 2; ty = sroom->ly + (sroom->hy - sroom->ly + 1) / 2; if (sroom->irregular) { /* center might not be valid, so put queen elsewhere */ if ((int) levl[tx][ty].roomno != rmno || levl[tx][ty].edge) { (void) somexy(sroom, &mm); tx = mm.x; ty = mm.y; } } break; case ZOO: case LEPREHALL: goldlim = 500 * level_difficulty(); break; } for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) { if (sroom->irregular) { if ((int) levl[sx][sy].roomno != rmno || levl[sx][sy].edge || (sroom->doorct && distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)) continue; } else if (!SPACE_POS(levl[sx][sy].typ) || (sroom->doorct && ((sx == sroom->lx && doors[sh].x == sx - 1) || (sx == sroom->hx && doors[sh].x == sx + 1) || (sy == sroom->ly && doors[sh].y == sy - 1) || (sy == sroom->hy && doors[sh].y == sy + 1)))) continue; /* don't place monster on explicitly placed throne */ if (type == COURT && IS_THRONE(levl[sx][sy].typ)) continue; mon = makemon((type == COURT) ? courtmon() : (type == BARRACKS) ? squadmon() : (type == MORGUE) ? morguemon() : (type == BEEHIVE) ? (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] : &mons[PM_KILLER_BEE]) : (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] : (type == COCKNEST) ? &mons[PM_COCKATRICE] : (type == ANTHOLE) ? antholemon() : (struct permonst *) 0, sx, sy, NO_MM_FLAGS); if (mon) { mon->msleeping = 1; if (type == COURT && mon->mpeaceful) { mon->mpeaceful = 0; set_malign(mon); } } switch (type) { case ZOO: case LEPREHALL: if (sroom->doorct) { int distval = dist2(sx, sy, doors[sh].x, doors[sh].y); i = sq(distval); } else i = goldlim; if (i >= goldlim) i = 5 * level_difficulty(); goldlim -= i; (void) mkgold((long) rn1(i, 10), sx, sy); break; case MORGUE: if (!rn2(5)) (void) mk_tt_object(CORPSE, sx, sy); if (!rn2(10)) /* lots of treasure buried with dead */ (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy, TRUE, FALSE); if (!rn2(5)) make_grave(sx, sy, (char *) 0); break; case BEEHIVE: if (!rn2(3)) (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE, FALSE); break; case BARRACKS: if (!rn2(20)) /* the payroll and some loot */ (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy, TRUE, FALSE); break; case COCKNEST: if (!rn2(3)) { struct obj *sobj = mk_tt_object(STATUE, sx, sy); if (sobj) { for (i = rn2(5); i; i--) (void) add_to_container( sobj, mkobj(RANDOM_CLASS, FALSE)); sobj->owt = weight(sobj); } } break; case ANTHOLE: if (!rn2(3)) (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE); break; } } switch (type) { case COURT: { struct obj *chest; levl[tx][ty].typ = THRONE; (void) somexy(sroom, &mm); (void) mkgold((long) rn1(50 * level_difficulty(), 10), mm.x, mm.y); /* the royal coffers */ chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE); chest->spe = 2; /* so it can be found later */ level.flags.has_court = 1; break; } case BARRACKS: level.flags.has_barracks = 1; break; case ZOO: level.flags.has_zoo = 1; break; case MORGUE: level.flags.has_morgue = 1; break; case SWAMP: level.flags.has_swamp = 1; break; case BEEHIVE: level.flags.has_beehive = 1; break; } } /* make a swarm of undead around mm */ void mkundead(mm, revive_corpses, mm_flags) coord *mm; boolean revive_corpses; int mm_flags; { int cnt = (level_difficulty() + 1) / 10 + rnd(5); struct permonst *mdat; struct obj *otmp; coord cc; while (cnt--) { mdat = morguemon(); if (mdat && enexto(&cc, mm->x, mm->y, mdat) && (!revive_corpses || !(otmp = sobj_at(CORPSE, cc.x, cc.y)) || !revive(otmp, FALSE))) (void) makemon(mdat, cc.x, cc.y, mm_flags); } level.flags.graveyard = TRUE; /* reduced chance for undead corpse */ } STATIC_OVL struct permonst * morguemon() { register int i = rn2(100), hd = rn2(level_difficulty()); if (hd > 10 && i < 10) { if (Inhell || In_endgame(&u.uz)) { return mkclass(S_DEMON, 0); } else { int ndemon_res = ndemon(A_NONE); if (ndemon_res != NON_PM) return &mons[ndemon_res]; /* else do what? As is, it will drop to ghost/wraith/zombie */ } } if (hd > 8 && i > 85) return mkclass(S_VAMPIRE, 0); return ((i < 20) ? &mons[PM_GHOST] : (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE, 0)); } struct permonst * antholemon() { int mtyp, indx, trycnt = 0; /* casts are for dealing with time_t */ indx = (int) ((long) ubirthday % 3L); indx += level_difficulty(); /* Same monsters within a level, different ones between levels */ do { switch ((indx + trycnt) % 3) { case 0: mtyp = PM_SOLDIER_ANT; break; case 1: mtyp = PM_FIRE_ANT; break; default: mtyp = PM_GIANT_ANT; break; } /* try again if chosen type has been genocided or used up */ } while (++trycnt < 3 && (mvitals[mtyp].mvflags & G_GONE)); return ((mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *) 0 : &mons[mtyp]); } STATIC_OVL void mkswamp() /* Michiel Huisjes & Fred de Wilde */ { register struct mkroom *sroom; register int sx, sy, i, eelct = 0; for (i = 0; i < 5; i++) { /* turn up to 5 rooms swampy */ sroom = &rooms[rn2(nroom)]; if (sroom->hx < 0 || sroom->rtype != OROOM || has_upstairs(sroom) || has_dnstairs(sroom)) continue; /* satisfied; make a swamp */ sroom->rtype = SWAMP; for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) if (!OBJ_AT(sx, sy) && !MON_AT(sx, sy) && !t_at(sx, sy) && !nexttodoor(sx, sy)) { if ((sx + sy) % 2) { levl[sx][sy].typ = POOL; if (!eelct || !rn2(4)) { /* mkclass() won't do, as we might get kraken */ (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL] : rn2(2) ? &mons[PM_PIRANHA] : &mons[PM_ELECTRIC_EEL], sx, sy, NO_MM_FLAGS); eelct++; } } else if (!rn2(4)) /* swamps tend to be moldy */ (void) makemon(mkclass(S_FUNGUS, 0), sx, sy, NO_MM_FLAGS); } level.flags.has_swamp = 1; } } STATIC_OVL coord * shrine_pos(roomno) int roomno; { static coord buf; int delta; struct mkroom *troom = &rooms[roomno - ROOMOFFSET]; /* if width and height are odd, placement will be the exact center; if either or both are even, center point is a hypothetical spot between map locations and placement will be adjacent to that */ delta = troom->hx - troom->lx; buf.x = troom->lx + delta / 2; if ((delta % 2) && rn2(2)) buf.x++; delta = troom->hy - troom->ly; buf.y = troom->ly + delta / 2; if ((delta % 2) && rn2(2)) buf.y++; return &buf; } STATIC_OVL void mktemple() { register struct mkroom *sroom; coord *shrine_spot; register struct rm *lev; if (!(sroom = pick_room(TRUE))) return; /* set up Priest and shrine */ sroom->rtype = TEMPLE; /* * In temples, shrines are blessed altars * located in the center of the room */ shrine_spot = shrine_pos((int) ((sroom - rooms) + ROOMOFFSET)); lev = &levl[shrine_spot->x][shrine_spot->y]; lev->typ = ALTAR; lev->altarmask = induced_align(80); priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE); lev->altarmask |= AM_SHRINE; level.flags.has_temple = 1; } boolean nexttodoor(sx, sy) register int sx, sy; { register int dx, dy; register struct rm *lev; for (dx = -1; dx <= 1; dx++) for (dy = -1; dy <= 1; dy++) { if (!isok(sx + dx, sy + dy)) continue; lev = &levl[sx + dx][sy + dy]; if (IS_DOOR(lev->typ) || lev->typ == SDOOR) return TRUE; } return FALSE; } boolean has_dnstairs(sroom) register struct mkroom *sroom; { if (sroom == dnstairs_room) return TRUE; if (sstairs.sx && !sstairs.up) return (boolean) (sroom == sstairs_room); return FALSE; } boolean has_upstairs(sroom) register struct mkroom *sroom; { if (sroom == upstairs_room) return TRUE; if (sstairs.sx && sstairs.up) return (boolean) (sroom == sstairs_room); return FALSE; } int somex(croom) register struct mkroom *croom; { return rn1(croom->hx - croom->lx + 1, croom->lx); } int somey(croom) register struct mkroom *croom; { return rn1(croom->hy - croom->ly + 1, croom->ly); } boolean inside_room(croom, x, y) struct mkroom *croom; xchar x, y; { return (boolean) (x >= croom->lx - 1 && x <= croom->hx + 1 && y >= croom->ly - 1 && y <= croom->hy + 1); } boolean somexy(croom, c) struct mkroom *croom; coord *c; { int try_cnt = 0; int i; if (croom->irregular) { i = (int) ((croom - rooms) + ROOMOFFSET); while (try_cnt++ < 100) { c->x = somex(croom); c->y = somey(croom); if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i) return TRUE; } /* try harder; exhaustively search until one is found */ for (c->x = croom->lx; c->x <= croom->hx; c->x++) for (c->y = croom->ly; c->y <= croom->hy; c->y++) if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i) return TRUE; return FALSE; } if (!croom->nsubrooms) { c->x = somex(croom); c->y = somey(croom); return TRUE; } /* Check that coords doesn't fall into a subroom or into a wall */ while (try_cnt++ < 100) { c->x = somex(croom); c->y = somey(croom); if (IS_WALL(levl[c->x][c->y].typ)) continue; for (i = 0; i < croom->nsubrooms; i++) if (inside_room(croom->sbrooms[i], c->x, c->y)) goto you_lose; break; you_lose: ; } if (try_cnt >= 100) return FALSE; return TRUE; } /* * Search for a special room given its type (zoo, court, etc...) * Special values : * - ANY_SHOP * - ANY_TYPE */ struct mkroom * search_special(type) schar type; { register struct mkroom *croom; for (croom = &rooms[0]; croom->hx >= 0; croom++) if ((type == ANY_TYPE && croom->rtype != OROOM) || (type == ANY_SHOP && croom->rtype >= SHOPBASE) || croom->rtype == type) return croom; for (croom = &subrooms[0]; croom->hx >= 0; croom++) if ((type == ANY_TYPE && croom->rtype != OROOM) || (type == ANY_SHOP && croom->rtype >= SHOPBASE) || croom->rtype == type) return croom; return (struct mkroom *) 0; } struct permonst * courtmon() { int i = rn2(60) + rn2(3 * level_difficulty()); if (i > 100) return mkclass(S_DRAGON, 0); else if (i > 95) return mkclass(S_GIANT, 0); else if (i > 85) return mkclass(S_TROLL, 0); else if (i > 75) return mkclass(S_CENTAUR, 0); else if (i > 60) return mkclass(S_ORC, 0); else if (i > 45) return &mons[PM_BUGBEAR]; else if (i > 30) return &mons[PM_HOBGOBLIN]; else if (i > 15) return mkclass(S_GNOME, 0); else return mkclass(S_KOBOLD, 0); } #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1) static struct { unsigned pm; unsigned prob; } squadprob[NSTYPES] = { { PM_SOLDIER, 80 }, { PM_SERGEANT, 15 }, { PM_LIEUTENANT, 4 }, { PM_CAPTAIN, 1 } }; /* return soldier types. */ STATIC_OVL struct permonst * squadmon() { int sel_prob, i, cpro, mndx; sel_prob = rnd(80 + level_difficulty()); cpro = 0; for (i = 0; i < NSTYPES; i++) { cpro += squadprob[i].prob; if (cpro > sel_prob) { mndx = squadprob[i].pm; goto gotone; } } mndx = squadprob[rn2(NSTYPES)].pm; gotone: if (!(mvitals[mndx].mvflags & G_GONE)) return &mons[mndx]; else return (struct permonst *) 0; } /* * save_room : A recursive function that saves a room and its subrooms * (if any). */ STATIC_OVL void save_room(fd, r) int fd; struct mkroom *r; { short i; /* * Well, I really should write only useful information instead * of writing the whole structure. That is I should not write * the subrooms pointers, but who cares ? */ bwrite(fd, (genericptr_t) r, sizeof (struct mkroom)); for (i = 0; i < r->nsubrooms; i++) save_room(fd, r->sbrooms[i]); } /* * save_rooms : Save all the rooms on disk! */ void save_rooms(fd) int fd; { short i; /* First, write the number of rooms */ bwrite(fd, (genericptr_t) &nroom, sizeof(nroom)); for (i = 0; i < nroom; i++) save_room(fd, &rooms[i]); } STATIC_OVL void rest_room(fd, r) int fd; struct mkroom *r; { short i; mread(fd, (genericptr_t) r, sizeof(struct mkroom)); for (i = 0; i < r->nsubrooms; i++) { r->sbrooms[i] = &subrooms[nsubroom]; rest_room(fd, &subrooms[nsubroom]); subrooms[nsubroom++].resident = (struct monst *) 0; } } /* * rest_rooms : That's for restoring rooms. Read the rooms structure from * the disk. */ void rest_rooms(fd) int fd; { short i; mread(fd, (genericptr_t) &nroom, sizeof(nroom)); nsubroom = 0; for (i = 0; i < nroom; i++) { rest_room(fd, &rooms[i]); rooms[i].resident = (struct monst *) 0; } rooms[nroom].hx = -1; /* restore ending flags */ subrooms[nsubroom].hx = -1; } /* convert a display symbol for terrain into topology type; used for remembered terrain when mimics pose as furniture */ int cmap_to_type(sym) int sym; { int typ = STONE; /* catchall */ switch (sym) { case S_stone: typ = STONE; break; case S_vwall: typ = VWALL; break; case S_hwall: typ = HWALL; break; case S_tlcorn: typ = TLCORNER; break; case S_trcorn: typ = TRCORNER; break; case S_blcorn: typ = BLCORNER; break; case S_brcorn: typ = BRCORNER; break; case S_crwall: typ = CROSSWALL; break; case S_tuwall: typ = TUWALL; break; case S_tdwall: typ = TDWALL; break; case S_tlwall: typ = TLWALL; break; case S_trwall: typ = TRWALL; break; case S_ndoor: /* no door (empty doorway) */ case S_vodoor: /* open door in vertical wall */ case S_hodoor: /* open door in horizontal wall */ case S_vcdoor: /* closed door in vertical wall */ case S_hcdoor: typ = DOOR; break; case S_bars: typ = IRONBARS; break; case S_tree: typ = TREE; break; case S_room: typ = ROOM; break; case S_corr: case S_litcorr: typ = CORR; break; case S_upstair: case S_dnstair: typ = STAIRS; break; case S_upladder: case S_dnladder: typ = LADDER; break; case S_altar: typ = ALTAR; break; case S_grave: typ = GRAVE; break; case S_throne: typ = THRONE; break; case S_sink: typ = SINK; break; case S_fountain: typ = FOUNTAIN; break; case S_pool: typ = POOL; break; case S_ice: typ = ICE; break; case S_lava: typ = LAVAPOOL; break; case S_vodbridge: /* open drawbridge spanning north/south */ case S_hodbridge: typ = DRAWBRIDGE_DOWN; break; /* east/west */ case S_vcdbridge: /* closed drawbridge in vertical wall */ case S_hcdbridge: typ = DBWALL; break; case S_air: typ = AIR; break; case S_cloud: typ = CLOUD; break; case S_water: typ = WATER; break; default: break; /* not a cmap symbol? */ } return typ; } /*mkroom.c*/ nethack-3.6.0/src/mon.c0000664000076400007660000035417512631241231013673 0ustar paxedpaxed/* NetHack 3.6 mon.c $NHDT-Date: 1449269918 2015/12/04 22:58:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.199 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* If you're using precompiled headers, you don't want this either */ #ifdef MICROPORT_BUG #define MKROOM_H #endif #include "hack.h" #include "mfndpos.h" #include STATIC_VAR boolean vamp_rise_msg; STATIC_DCL void FDECL(sanity_check_single_mon, (struct monst *, const char *)); STATIC_DCL boolean FDECL(restrap, (struct monst *)); STATIC_DCL long FDECL(mm_aggression, (struct monst *, struct monst *)); STATIC_DCL long FDECL(mm_displacement, (struct monst *, struct monst *)); STATIC_DCL int NDECL(pick_animal); STATIC_DCL void FDECL(kill_eggs, (struct obj *)); STATIC_DCL int FDECL(pickvampshape, (struct monst *)); STATIC_DCL boolean FDECL(isspecmon, (struct monst *)); STATIC_DCL boolean FDECL(validspecmon, (struct monst *, int)); STATIC_DCL boolean FDECL(validvamp, (struct monst *, int *, int)); STATIC_DCL struct permonst *FDECL(accept_newcham_form, (int)); STATIC_DCL struct obj *FDECL(make_corpse, (struct monst *, unsigned)); STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *)); STATIC_DCL void FDECL(lifesaved_monster, (struct monst *)); #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ (Is_rogue_level(&u.uz) \ || (level.flags.graveyard && is_undead(mdat) && rn2(3))) #if 0 /* part of the original warning code which was replaced in 3.3.1 */ const char *warnings[] = { "white", "pink", "red", "ruby", "purple", "black" }; #endif /* 0 */ void sanity_check_single_mon(mtmp, msg) struct monst *mtmp; const char *msg; { if (DEADMONSTER(mtmp)) return; if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS]) impossible("illegal mon data (%s)", msg); } void mon_sanity_check() { int x,y; struct monst *mtmp = fmon; while (mtmp) { sanity_check_single_mon(mtmp, "fmon"); mtmp = mtmp->nmon; } for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if ((mtmp = m_at(x,y)) != 0) sanity_check_single_mon(mtmp, "m_at"); mtmp = migrating_mons; while (mtmp) { sanity_check_single_mon(mtmp, "migr"); mtmp = mtmp->nmon; } } /* convert the monster index of an undead to its living counterpart */ int undead_to_corpse(mndx) int mndx; { switch (mndx) { case PM_KOBOLD_ZOMBIE: case PM_KOBOLD_MUMMY: mndx = PM_KOBOLD; break; case PM_DWARF_ZOMBIE: case PM_DWARF_MUMMY: mndx = PM_DWARF; break; case PM_GNOME_ZOMBIE: case PM_GNOME_MUMMY: mndx = PM_GNOME; break; case PM_ORC_ZOMBIE: case PM_ORC_MUMMY: mndx = PM_ORC; break; case PM_ELF_ZOMBIE: case PM_ELF_MUMMY: mndx = PM_ELF; break; case PM_VAMPIRE: case PM_VAMPIRE_LORD: #if 0 /* DEFERRED */ case PM_VAMPIRE_MAGE: #endif case PM_HUMAN_ZOMBIE: case PM_HUMAN_MUMMY: mndx = PM_HUMAN; break; case PM_GIANT_ZOMBIE: case PM_GIANT_MUMMY: mndx = PM_GIANT; break; case PM_ETTIN_ZOMBIE: case PM_ETTIN_MUMMY: mndx = PM_ETTIN; break; default: break; } return mndx; } /* Convert the monster index of some monsters (such as quest guardians) * to their generic species type. * * Return associated character class monster, rather than species * if mode is 1. */ int genus(mndx, mode) int mndx, mode; { switch (mndx) { /* Quest guardians */ case PM_STUDENT: mndx = mode ? PM_ARCHEOLOGIST : PM_HUMAN; break; case PM_CHIEFTAIN: mndx = mode ? PM_BARBARIAN : PM_HUMAN; break; case PM_NEANDERTHAL: mndx = mode ? PM_CAVEMAN : PM_HUMAN; break; case PM_ATTENDANT: mndx = mode ? PM_HEALER : PM_HUMAN; break; case PM_PAGE: mndx = mode ? PM_KNIGHT : PM_HUMAN; break; case PM_ABBOT: mndx = mode ? PM_MONK : PM_HUMAN; break; case PM_ACOLYTE: mndx = mode ? PM_PRIEST : PM_HUMAN; break; case PM_HUNTER: mndx = mode ? PM_RANGER : PM_HUMAN; break; case PM_THUG: mndx = mode ? PM_ROGUE : PM_HUMAN; break; case PM_ROSHI: mndx = mode ? PM_SAMURAI : PM_HUMAN; break; case PM_GUIDE: mndx = mode ? PM_TOURIST : PM_HUMAN; break; case PM_APPRENTICE: mndx = mode ? PM_WIZARD : PM_HUMAN; break; case PM_WARRIOR: mndx = mode ? PM_VALKYRIE : PM_HUMAN; break; default: if (mndx >= LOW_PM && mndx < NUMMONS) { struct permonst *ptr = &mons[mndx]; if (is_human(ptr)) mndx = PM_HUMAN; else if (is_elf(ptr)) mndx = PM_ELF; else if (is_dwarf(ptr)) mndx = PM_DWARF; else if (is_gnome(ptr)) mndx = PM_GNOME; else if (is_orc(ptr)) mndx = PM_ORC; } break; } return mndx; } /* return monster index if chameleon, or NON_PM if not */ int pm_to_cham(mndx) int mndx; { int mcham = NON_PM; /* * As of 3.6.0 we just check M2_SHAPESHIFTER instead of having a * big switch statement with hardcoded shapeshifter types here. */ if (mndx >= LOW_PM && is_shapeshifter(&mons[mndx])) mcham = mndx; return mcham; } /* for deciding whether corpse will carry along full monster data */ #define KEEPTRAITS(mon) \ ((mon)->isshk || (mon)->mtame || unique_corpstat((mon)->data) \ || is_reviver((mon)->data) \ /* normally quest leader will be unique, */ \ /* but he or she might have been polymorphed */ \ || (mon)->m_id == quest_status.leader_m_id \ /* special cancellation handling for these */ \ || (dmgtype((mon)->data, AD_SEDU) || dmgtype((mon)->data, AD_SSEX))) /* Creates a monster corpse, a "special" corpse, or nothing if it doesn't * leave corpses. Monsters which leave "special" corpses should have * G_NOCORPSE set in order to prevent wishing for one, finding tins of one, * etc.... */ STATIC_OVL struct obj * make_corpse(mtmp, corpseflags) register struct monst *mtmp; unsigned corpseflags; { register struct permonst *mdat = mtmp->data; int num; struct obj *obj = (struct obj *) 0; struct obj *otmp = (struct obj *) 0; int x = mtmp->mx, y = mtmp->my; int mndx = monsndx(mdat); unsigned corpstatflags = corpseflags; boolean burythem = ((corpstatflags & CORPSTAT_BURIED) != 0); switch (mndx) { case PM_GRAY_DRAGON: case PM_SILVER_DRAGON: #if 0 /* DEFERRED */ case PM_SHIMMERING_DRAGON: #endif case PM_RED_DRAGON: case PM_ORANGE_DRAGON: case PM_WHITE_DRAGON: case PM_BLACK_DRAGON: case PM_BLUE_DRAGON: case PM_GREEN_DRAGON: case PM_YELLOW_DRAGON: /* Make dragon scales. This assumes that the order of the dragons is the same as the order of the scales. */ if (!rn2(mtmp->mrevived ? 20 : 3)) { num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON; obj = mksobj_at(num, x, y, FALSE, FALSE); obj->spe = 0; obj->cursed = obj->blessed = FALSE; } goto default_1; case PM_WHITE_UNICORN: case PM_GRAY_UNICORN: case PM_BLACK_UNICORN: if (mtmp->mrevived && rn2(2)) { if (canseemon(mtmp)) pline("%s recently regrown horn crumbles to dust.", s_suffix(Monnam(mtmp))); } else { obj = mksobj_at(UNICORN_HORN, x, y, TRUE, FALSE); if (obj && mtmp->mrevived) obj->degraded_horn = 1; } goto default_1; case PM_LONG_WORM: (void) mksobj_at(WORM_TOOTH, x, y, TRUE, FALSE); goto default_1; case PM_VAMPIRE: case PM_VAMPIRE_LORD: /* include mtmp in the mkcorpstat() call */ num = undead_to_corpse(mndx); corpstatflags |= CORPSTAT_INIT; obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); obj->age -= 100; /* this is an *OLD* corpse */ break; case PM_KOBOLD_MUMMY: case PM_DWARF_MUMMY: case PM_GNOME_MUMMY: case PM_ORC_MUMMY: case PM_ELF_MUMMY: case PM_HUMAN_MUMMY: case PM_GIANT_MUMMY: case PM_ETTIN_MUMMY: case PM_KOBOLD_ZOMBIE: case PM_DWARF_ZOMBIE: case PM_GNOME_ZOMBIE: case PM_ORC_ZOMBIE: case PM_ELF_ZOMBIE: case PM_HUMAN_ZOMBIE: case PM_GIANT_ZOMBIE: case PM_ETTIN_ZOMBIE: num = undead_to_corpse(mndx); corpstatflags |= CORPSTAT_INIT; obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, corpstatflags); obj->age -= 100; /* this is an *OLD* corpse */ break; case PM_IRON_GOLEM: num = d(2, 6); while (num--) obj = mksobj_at(IRON_CHAIN, x, y, TRUE, FALSE); free_mname(mtmp); /* don't christen obj */ break; case PM_GLASS_GOLEM: num = d(2, 4); /* very low chance of creating all glass gems */ while (num--) obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE, FALSE); free_mname(mtmp); break; case PM_CLAY_GOLEM: obj = mksobj_at(ROCK, x, y, FALSE, FALSE); obj->quan = (long) (rn2(20) + 50); obj->owt = weight(obj); free_mname(mtmp); break; case PM_STONE_GOLEM: corpstatflags &= ~CORPSTAT_INIT; obj = mkcorpstat(STATUE, (struct monst *) 0, mdat, x, y, corpstatflags); break; case PM_WOOD_GOLEM: num = d(2, 4); while (num--) { obj = mksobj_at(QUARTERSTAFF, x, y, TRUE, FALSE); } free_mname(mtmp); break; case PM_LEATHER_GOLEM: num = d(2, 4); while (num--) obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE, FALSE); free_mname(mtmp); break; case PM_GOLD_GOLEM: /* Good luck gives more coins */ obj = mkgold((long) (200 - rnl(101)), x, y); free_mname(mtmp); break; case PM_PAPER_GOLEM: num = rnd(4); while (num--) obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE); free_mname(mtmp); break; /* expired puddings will congeal into a large blob; like dragons, relies on the order remaining consistent */ case PM_GRAY_OOZE: case PM_BROWN_PUDDING: case PM_GREEN_SLIME: case PM_BLACK_PUDDING: /* we have to do this here because most other places expect there to be an object coming back; not this one */ obj = mksobj_at(GLOB_OF_BLACK_PUDDING - (PM_BLACK_PUDDING - mndx), x, y, TRUE, FALSE); while (obj && (otmp = obj_nexto(obj)) != (struct obj *) 0) { pudding_merge_message(obj, otmp); obj = obj_meld(&obj, &otmp); } free_mname(mtmp); return obj; break; default_1: default: if (mvitals[mndx].mvflags & G_NOCORPSE) { return (struct obj *) 0; } else { corpstatflags |= CORPSTAT_INIT; /* preserve the unique traits of some creatures */ obj = mkcorpstat(CORPSE, KEEPTRAITS(mtmp) ? mtmp : 0, mdat, x, y, corpstatflags); if (burythem) { boolean dealloc; (void) bury_an_obj(obj, &dealloc); newsym(x, y); return dealloc ? (struct obj *) 0 : obj; } } break; } /* All special cases should precede the G_NOCORPSE check */ if (!obj) return NULL; /* if polymorph or undead turning has killed this monster, prevent the same attack beam from hitting its corpse */ if (context.bypasses) bypass_obj(obj); if (has_mname(mtmp)) obj = oname(obj, MNAME(mtmp)); /* Avoid "It was hidden under a green mold corpse!" * during Blind combat. An unseen monster referred to as "it" * could be killed and leave a corpse. If a hider then hid * underneath it, you could be told the corpse type of a * monster that you never knew was there without this. * The code in hitmu() substitutes the word "something" * if the corpses obj->dknown is 0. */ if (Blind && !sensemon(mtmp)) obj->dknown = 0; stackobj(obj); newsym(x, y); return obj; } /* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */ int minliquid(mtmp) register struct monst *mtmp; { boolean inpool, inlava, infountain; /* [what about ceiling clingers?] */ inpool = (is_pool(mtmp->mx, mtmp->my) && !(is_flyer(mtmp->data) || is_floater(mtmp->data))); inlava = (is_lava(mtmp->mx, mtmp->my) && !(is_flyer(mtmp->data) || is_floater(mtmp->data))); infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ); /* Flying and levitation keeps our steed out of the liquid */ /* (but not water-walking or swimming) */ if (mtmp == u.usteed && (Flying || Levitation)) return 0; /* Gremlin multiplying won't go on forever since the hit points * keep going down, and when it gets to 1 hit point the clone * function will fail. */ if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) { if (split_mon(mtmp, (struct monst *) 0)) dryup(mtmp->mx, mtmp->my, FALSE); if (inpool) water_damage_chain(mtmp->minvent, FALSE); return 0; } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) { int dam = d(2, 6); if (cansee(mtmp->mx, mtmp->my)) pline("%s rusts.", Monnam(mtmp)); mtmp->mhp -= dam; if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; if (mtmp->mhp < 1) { mondead(mtmp); if (mtmp->mhp < 1) return 1; } water_damage_chain(mtmp->minvent, FALSE); return 0; } if (inlava) { /* * Lava effects much as water effects. Lava likers are able to * protect their stuff. Fire resistant monsters can only protect * themselves --ALI */ if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) { if (!resists_fire(mtmp)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s %s.", Monnam(mtmp), mtmp->data == &mons[PM_WATER_ELEMENTAL] ? "boils away" : "burns to a crisp"); mondead(mtmp); } else { if (--mtmp->mhp < 1) { if (cansee(mtmp->mx, mtmp->my)) pline("%s surrenders to the fire.", Monnam(mtmp)); mondead(mtmp); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s burns slightly.", Monnam(mtmp)); } if (mtmp->mhp > 0) { (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, mtmp->mx, mtmp->my); (void) rloc(mtmp, FALSE); return 0; } return 1; } } else if (inpool) { /* Most monsters drown in pools. flooreffects() will take care of * water damage to dead monsters' inventory, but survivors need to * be handled here. Swimmers are able to protect their stuff... */ if (!is_clinger(mtmp->data) && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { if (cansee(mtmp->mx, mtmp->my)) { pline("%s drowns.", Monnam(mtmp)); } if (u.ustuck && u.uswallow && u.ustuck == mtmp) { /* This can happen after a purple worm plucks you off a flying steed while you are over water. */ pline("%s sinks as water rushes in and flushes you out.", Monnam(mtmp)); } mondead(mtmp); if (mtmp->mhp > 0) { water_damage_chain(mtmp->minvent, FALSE); (void) rloc(mtmp, FALSE); return 0; } return 1; } } else { /* but eels have a difficult time outside */ if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) { /* as mhp gets lower, the rate of further loss slows down */ if (mtmp->mhp > 1 && rn2(mtmp->mhp) > rn2(8)) mtmp->mhp--; monflee(mtmp, 2, FALSE, FALSE); } } return 0; } int mcalcmove(mon) struct monst *mon; { int mmove = mon->data->mmove; /* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0; * MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op; * both adjustments have negligible effect on higher speeds. */ if (mon->mspeed == MSLOW) mmove = (2 * mmove + 1) / 3; else if (mon->mspeed == MFAST) mmove = (4 * mmove + 2) / 3; if (mon == u.usteed) { if (u.ugallop && context.mv) { /* average movement is 1.50 times normal */ mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; } } else if (mmove) { /* vary movement points allocated to slightly reduce predictability; random increment (avg +2) exceeds random decrement (avg +1) by a small amount; normal speed monsters will occasionally get an extra move and slow ones won't be quite as slow */ mmove += rn2(5) - rn2(3); /* + 0..4 - 0..2, average net +1 */ if (mmove < 1) mmove = 1; } return mmove; } /* actions that happen once per ``turn'', regardless of each individual monster's metabolism; some of these might need to be reclassified to occur more in proportion with movement rate */ void mcalcdistress() { struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; /* must check non-moving monsters once/turn in case * they managed to end up in liquid */ if (mtmp->data->mmove == 0) { if (vision_full_recalc) vision_recalc(0); if (minliquid(mtmp)) continue; } /* regenerate hit points */ mon_regen(mtmp, FALSE); /* possibly polymorph shapechangers and lycanthropes */ if (mtmp->cham >= LOW_PM) { if (is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE) decide_to_shapeshift(mtmp, 0); else if (!rn2(6)) (void) newcham(mtmp, (struct permonst *) 0, FALSE, FALSE); } were_change(mtmp); /* gradually time out temporary problems */ if (mtmp->mblinded && !--mtmp->mblinded) mtmp->mcansee = 1; if (mtmp->mfrozen && !--mtmp->mfrozen) mtmp->mcanmove = 1; if (mtmp->mfleetim && !--mtmp->mfleetim) mtmp->mflee = 0; /* FIXME: mtmp->mlstmv ought to be updated here */ } } int movemon() { register struct monst *mtmp, *nmtmp; register boolean somebody_can_move = FALSE; /* * Some of you may remember the former assertion here that * because of deaths and other actions, a simple one-pass * algorithm wasn't possible for movemon. Deaths are no longer * removed to the separate list fdmon; they are simply left in * the chain with hit points <= 0, to be cleaned up at the end * of the pass. * * The only other actions which cause monsters to be removed from * the chain are level migrations and losedogs(). I believe losedogs() * is a cleanup routine not associated with monster movements, and * monsters can only affect level migrations on themselves, not others * (hence the fetching of nmon before moving the monster). Currently, * monsters can jump into traps, read cursed scrolls of teleportation, * and drink cursed potions of raise level to change levels. These are * all reflexive at this point. Should one monster be able to level * teleport another, this scheme would have problems. */ for (mtmp = fmon; mtmp; mtmp = nmtmp) { /* end monster movement early if hero is flagged to leave the level */ if (u.utotype #ifdef SAFERHANGUP /* or if the program has lost contact with the user */ || program_state.done_hup #endif ) { somebody_can_move = FALSE; break; } nmtmp = mtmp->nmon; /* one dead monster needs to perform a move after death: vault guard whose temporary corridor is still on the map */ if (mtmp->isgd && !mtmp->mx && mtmp->mhp <= 0) (void) gd_move(mtmp); if (DEADMONSTER(mtmp)) continue; /* Find a monster that we have not treated yet. */ if (mtmp->movement < NORMAL_SPEED) continue; mtmp->movement -= NORMAL_SPEED; if (mtmp->movement >= NORMAL_SPEED) somebody_can_move = TRUE; if (vision_full_recalc) vision_recalc(0); /* vision! */ /* reset obj bypasses before next monster moves */ if (context.bypasses) clear_bypasses(); clear_splitobjs(); if (minliquid(mtmp)) continue; if (is_hider(mtmp->data)) { /* unwatched mimics and piercers may hide again [MRS] */ if (restrap(mtmp)) continue; if (mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) continue; if (mtmp->mundetected) continue; } else if (mtmp->data->mlet == S_EEL && !mtmp->mundetected && (mtmp->mflee || distu(mtmp->mx, mtmp->my) > 2) && !canseemon(mtmp) && !rn2(4)) { /* some eels end up stuck in isolated pools, where they can't--or at least won't--move, so they never reach their post-move chance to re-hide */ if (hideunder(mtmp)) continue; } /* continue if the monster died fighting */ if (Conflict && !mtmp->iswiz && mtmp->mcansee) { /* Note: * Conflict does not take effect in the first round. * Therefore, A monster when stepping into the area will * get to swing at you. * * The call to fightm() must be _last_. The monster might * have died if it returns 1. */ if (couldsee(mtmp->mx, mtmp->my) && (distu(mtmp->mx, mtmp->my) <= BOLT_LIM * BOLT_LIM) && fightm(mtmp)) continue; /* mon might have died */ } if (dochugw(mtmp)) /* otherwise just move the monster */ continue; } if (any_light_source()) vision_full_recalc = 1; /* in case a mon moved with a light source */ /* reset obj bypasses after last monster has moved */ if (context.bypasses) clear_bypasses(); clear_splitobjs(); /* remove dead monsters; dead vault guard will be left at <0,0> if temporary corridor out of vault hasn't been removed yet */ dmonsfree(); /* a monster may have levteleported player -dlc */ if (u.utotype) { deferred_goto(); /* changed levels, so these monsters are dormant */ somebody_can_move = FALSE; } return somebody_can_move; } #define mstoning(obj) \ (ofood(obj) && (touch_petrifies(&mons[(obj)->corpsenm]) \ || (obj)->corpsenm == PM_MEDUSA)) /* * Maybe eat a metallic object (not just gold). * Return value: 0 => nothing happened, 1 => monster ate something, * 2 => monster died (it must have grown into a genocided form, but * that can't happen at present because nothing which eats objects * has young and old forms). */ int meatmetal(mtmp) register struct monst *mtmp; { register struct obj *otmp; struct permonst *ptr; int poly, grow, heal, mstone; /* If a pet, eating is handled separately, in dog.c */ if (mtmp->mtame) return 0; /* Eats topmost metal object if it is there */ for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp->nexthere) { /* Don't eat indigestible/choking/inappropriate objects */ if ((mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) || (otmp->otyp == AMULET_OF_STRANGULATION) || (otmp->otyp == RIN_SLOW_DIGESTION)) continue; if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && touch_artifact(otmp, mtmp)) { if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { if (canseemon(mtmp) && flags.verbose) { pline("%s eats %s!", Monnam(mtmp), distant_name(otmp, doname)); } /* The object's rustproofing is gone now */ otmp->oerodeproof = 0; mtmp->mstun = 1; if (canseemon(mtmp) && flags.verbose) { pline("%s spits %s out in disgust!", Monnam(mtmp), distant_name(otmp, doname)); } } else { if (cansee(mtmp->mx, mtmp->my) && flags.verbose) pline("%s eats %s!", Monnam(mtmp), distant_name(otmp, doname)); else if (flags.verbose) You_hear("a crunching sound."); mtmp->meating = otmp->owt / 2 + 1; /* Heal up to the object's weight in hp */ if (mtmp->mhp < mtmp->mhpmax) { mtmp->mhp += objects[otmp->otyp].oc_weight; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; } if (otmp == uball) { unpunish(); delobj(otmp); } else if (otmp == uchain) { unpunish(); /* frees uchain */ } else { poly = polyfodder(otmp); grow = mlevelgain(otmp); heal = mhealup(otmp); mstone = mstoning(otmp); delobj(otmp); ptr = mtmp->data; if (poly) { if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE)) ptr = mtmp->data; } else if (grow) { ptr = grow_up(mtmp, (struct monst *) 0); } else if (mstone) { if (poly_when_stoned(ptr)) { mon_to_stone(mtmp); ptr = mtmp->data; } else if (!resists_ston(mtmp)) { if (canseemon(mtmp)) pline("%s turns to stone!", Monnam(mtmp)); monstone(mtmp); ptr = (struct permonst *) 0; } } else if (heal) { mtmp->mhp = mtmp->mhpmax; } if (!ptr) return 2; /* it died */ } /* Left behind a pile? */ if (rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); newsym(mtmp->mx, mtmp->my); return 1; } } } return 0; } /* monster eats a pile of objects */ int meatobj(mtmp) /* for gelatinous cubes */ struct monst *mtmp; { register struct obj *otmp, *otmp2; struct permonst *ptr, *original_ptr = mtmp->data; int poly, grow, heal, count = 0, ecount = 0; char buf[BUFSZ]; buf[0] = '\0'; /* If a pet, eating is handled separately, in dog.c */ if (mtmp->mtame) return 0; /* eat organic objects, including cloth and wood, if present; engulf others, except huge rocks and metal attached to player [despite comment at top, doesn't assume that eater is a g.cube] */ for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; /* touch sensitive items */ if (otmp->otyp == CORPSE && is_rider(&mons[otmp->corpsenm])) { /* Rider corpse isn't just inedible; can't engulf it either */ (void) revive_corpse(otmp); /* untouchable (or inaccessible) items */ } else if ((otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !resists_ston(mtmp)) /* don't engulf boulders and statues or ball&chain */ || otmp->oclass == ROCK_CLASS || otmp == uball || otmp == uchain) { /* do nothing--neither eaten nor engulfed */ continue; /* inedible items -- engulf these */ } else if (!is_organic(otmp) || obj_resists(otmp, 5, 95) || !touch_artifact(otmp, mtmp) /* redundant due to non-organic composition but included for emphasis */ || (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == RIN_SLOW_DIGESTION) /* cockatrice corpses handled above; this touch_petrifies() check catches eggs */ || ((otmp->otyp == CORPSE || otmp->otyp == EGG) && ((touch_petrifies(&mons[otmp->corpsenm]) && !resists_ston(mtmp)) || (otmp->corpsenm == PM_GREEN_SLIME && !slimeproof(mtmp->data))))) { /* engulf */ ++ecount; if (ecount == 1) Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), distant_name(otmp, doname)); else if (ecount == 2) Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); obj_extract_self(otmp); (void) mpickobj(mtmp, otmp); /* slurp */ /* lastly, edible items; yum! */ } else { /* devour */ ++count; if (cansee(mtmp->mx, mtmp->my) && flags.verbose) pline("%s eats %s!", Monnam(mtmp), distant_name(otmp, doname)); else if (flags.verbose) You_hear("a slurping sound."); /* Heal up to the object's weight in hp */ if (mtmp->mhp < mtmp->mhpmax) { mtmp->mhp += objects[otmp->otyp].oc_weight; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; } if (Has_contents(otmp)) { register struct obj *otmp3; /* contents of eaten containers become engulfed; this is arbitrary, but otherwise g.cubes are too powerful */ while ((otmp3 = otmp->cobj) != 0) { obj_extract_self(otmp3); if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) { otmp3->age = monstermoves - otmp3->age; start_corpse_timeout(otmp3); } (void) mpickobj(mtmp, otmp3); } } poly = polyfodder(otmp); grow = mlevelgain(otmp); heal = mhealup(otmp); delobj(otmp); /* munch */ ptr = mtmp->data; if (poly) { if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE)) ptr = mtmp->data; } else if (grow) { ptr = grow_up(mtmp, (struct monst *) 0); } else if (heal) { mtmp->mhp = mtmp->mhpmax; } /* in case it polymorphed or died */ if (ptr != original_ptr) return !ptr ? 2 : 1; } /* Engulf & devour is instant, so don't set meating */ if (mtmp->minvis) newsym(mtmp->mx, mtmp->my); } if (ecount > 0) { if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0]) pline1(buf); else if (flags.verbose) You_hear("%s slurping sound%s.", (ecount == 1) ? "a" : "several", plur(ecount)); } return (count > 0 || ecount > 0) ? 1 : 0; } void mpickgold(mtmp) register struct monst *mtmp; { register struct obj *gold; int mat_idx; if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) { mat_idx = objects[gold->otyp].oc_material; obj_extract_self(gold); add_to_minv(mtmp, gold); if (cansee(mtmp->mx, mtmp->my)) { if (flags.verbose && !mtmp->isgd) pline("%s picks up some %s.", Monnam(mtmp), mat_idx == GOLD ? "gold" : "money"); newsym(mtmp->mx, mtmp->my); } } } boolean mpickstuff(mtmp, str) register struct monst *mtmp; register const char *str; { register struct obj *otmp, *otmp2, *otmp3; int carryamt = 0; /* prevent shopkeepers from leaving the door of their shop */ if (mtmp->isshk && inhishop(mtmp)) return FALSE; for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; /* Nymphs take everything. Most monsters don't pick up corpses. */ if (!str ? searches_for_item(mtmp, otmp) : !!(index(str, otmp->oclass))) { if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH /* let a handful of corpse types thru to can_carry() */ && !touch_petrifies(&mons[otmp->corpsenm]) && otmp->corpsenm != PM_LIZARD && !acidic(&mons[otmp->corpsenm])) continue; if (!touch_artifact(otmp, mtmp)) continue; carryamt = can_carry(mtmp, otmp); if (carryamt == 0) continue; if (is_pool(mtmp->mx, mtmp->my)) continue; /* handle cases where the critter can only get some */ otmp3 = otmp; if (carryamt != otmp->quan) { otmp3 = splitobj(otmp, carryamt); } if (cansee(mtmp->mx, mtmp->my) && flags.verbose) pline("%s picks up %s.", Monnam(mtmp), (distu(mtmp->mx, mtmp->my) <= 5) ? doname(otmp3) : distant_name(otmp3, doname)); obj_extract_self(otmp3); /* remove from floor */ (void) mpickobj(mtmp, otmp3); /* may merge and free otmp3 */ m_dowear(mtmp, FALSE); newsym(mtmp->mx, mtmp->my); return TRUE; /* pick only one object */ } } return FALSE; } int curr_mon_load(mtmp) struct monst *mtmp; { int curload = 0; struct obj *obj; for (obj = mtmp->minvent; obj; obj = obj->nobj) { if (obj->otyp != BOULDER || !throws_rocks(mtmp->data)) curload += obj->owt; } return curload; } int max_mon_load(mtmp) struct monst *mtmp; { long maxload; /* Base monster carrying capacity is equal to human maximum * carrying capacity, or half human maximum if not strong. * (for a polymorphed player, the value used would be the * non-polymorphed carrying capacity instead of max/half max). * This is then modified by the ratio between the monster weights * and human weights. Corpseless monsters are given a capacity * proportional to their size instead of weight. */ if (!mtmp->data->cwt) maxload = (MAX_CARR_CAP * (long) mtmp->data->msize) / MZ_HUMAN; else if (!strongmonst(mtmp->data) || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN))) maxload = (MAX_CARR_CAP * (long) mtmp->data->cwt) / WT_HUMAN; else maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/ if (!strongmonst(mtmp->data)) maxload /= 2; if (maxload < 1) maxload = 1; return (int) maxload; } /* for restricting monsters' object-pickup. * * to support the new pet behavior, this now returns the max # of objects * that a given monster could pick up from a pile. frequently this will be * otmp->quan, but special cases for 'only one' now exist so. * * this will probably cause very amusing behavior with pets and gold coins. * * TODO: allow picking up 2-N objects from a pile of N based on weight. * Change from 'int' to 'long' to accomate big stacks of gold. * Right now we fake it by reporting a partial quantity, but the * likesgold handling m_move results in picking up the whole stack. */ int can_carry(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { int iquan, otyp = otmp->otyp, newload = otmp->owt; struct permonst *mdat = mtmp->data; short nattk = 0; if (notake(mdat)) return 0; /* can't carry anything */ if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp)) return 0; if (otyp == CORPSE && is_rider(&mons[otmp->corpsenm])) return 0; if (objects[otyp].oc_material == SILVER && mon_hates_silver(mtmp) && (otyp != BELL_OF_OPENING || !is_covetous(mdat))) return 0; /* hostile monsters who like gold will pick up the whole stack; tame mosnters with hands will pick up the partial stack */ iquan = (otmp->quan > (long) LARGEST_INT) ? 20000 + rn2(LARGEST_INT - 20000 + 1) : (int) otmp->quan; /* monsters without hands can't pick up multiple objects at once * unless they have an engulfing attack * * ...dragons, of course, can always carry gold pieces and gems somehow */ if (iquan > 1) { boolean glomper = FALSE; if (mtmp->data->mlet == S_DRAGON && (otmp->oclass == COIN_CLASS || otmp->oclass == GEM_CLASS)) glomper = TRUE; else for (nattk = 0; nattk < NATTK; nattk++) if (mtmp->data->mattk[nattk].aatyp == AT_ENGL) { glomper = TRUE; break; } if ((mtmp->data->mflags1 & M1_NOHANDS) && !glomper) return 1; } /* steeds don't pick up stuff (to avoid shop abuse) */ if (mtmp == u.usteed) return 0; if (mtmp->isshk) return iquan; /* no limit */ if (mtmp->mpeaceful && !mtmp->mtame) return 0; /* otherwise players might find themselves obligated to violate * their alignment if the monster takes something they need */ /* special--boulder throwers carry unlimited amounts of boulders */ if (throws_rocks(mdat) && otyp == BOULDER) return iquan; /* nymphs deal in stolen merchandise, but not boulders or statues */ if (mdat->mlet == S_NYMPH) return (otmp->oclass == ROCK_CLASS) ? 0 : iquan; if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return 0; return iquan; } /* return number of acceptable neighbour positions */ int mfndpos(mon, poss, info, flag) struct monst *mon; coord *poss; /* coord poss[9] */ long *info; /* long info[9] */ long flag; { struct permonst *mdat = mon->data; register struct trap *ttmp; xchar x, y, nx, ny; int cnt = 0; uchar ntyp; uchar nowtyp; boolean wantpool, poolok, lavaok, nodiag; boolean rockok = FALSE, treeok = FALSE, thrudoor; int maxx, maxy; x = mon->mx; y = mon->my; nowtyp = levl[x][y].typ; nodiag = NODIAG(mdat - mons); wantpool = mdat->mlet == S_EEL; poolok = (is_flyer(mdat) || is_clinger(mdat) || (is_swimmer(mdat) && !wantpool)); lavaok = (is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat)); thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L); if (flag & ALLOW_DIG) { struct obj *mw_tmp; /* need to be specific about what can currently be dug */ if (!needspick(mdat)) { rockok = treeok = TRUE; } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED) { rockok = is_pick(mw_tmp); treeok = is_axe(mw_tmp); } else { rockok = (m_carrying(mon, PICK_AXE) || (m_carrying(mon, DWARVISH_MATTOCK) && !which_armor(mon, W_ARMS))); treeok = (m_carrying(mon, AXE) || (m_carrying(mon, BATTLE_AXE) && !which_armor(mon, W_ARMS))); } if (rockok || treeok) thrudoor = TRUE; } nexttry: /* eels prefer the water, but if there is no water nearby, they will crawl over land */ if (mon->mconf) { flag |= ALLOW_ALL; flag &= ~NOTONL; } if (!mon->mcansee) flag |= ALLOW_SSM; maxx = min(x + 1, COLNO - 1); maxy = min(y + 1, ROWNO - 1); for (nx = max(1, x - 1); nx <= maxx; nx++) for (ny = max(0, y - 1); ny <= maxy; ny++) { if (nx == x && ny == y) continue; ntyp = levl[nx][ny].typ; if (IS_ROCK(ntyp) && !((flag & ALLOW_WALL) && may_passwall(nx, ny)) && !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx, ny))) continue; /* KMH -- Added iron bars */ if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue; if (IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) && (((levl[nx][ny].doormask & D_CLOSED) && !(flag & OPENDOOR)) || ((levl[nx][ny].doormask & D_LOCKED) && !(flag & UNLOCKDOOR))) && !thrudoor) continue; /* first diagonal checks (tight squeezes handled below) */ if (nx != x && ny != y && (nodiag || (IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) || (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)) || ((IS_DOOR(nowtyp) || IS_DOOR(ntyp)) && Is_rogue_level(&u.uz)) /* mustn't pass between adjacent long worm segments, but can attack that way */ || (m_at(x, ny) && m_at(nx, y) && worm_cross(x, y, nx, ny) && !m_at(nx, ny) && (nx != u.ux || ny != u.uy)))) continue; if ((is_pool(nx, ny) == wantpool || poolok) && (lavaok || !is_lava(nx, ny))) { int dispx, dispy; boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat))); boolean checkobj = OBJ_AT(nx, ny); /* Displacement also displaces the Elbereth/scare monster, * as long as you are visible. */ if (Displaced && monseeu && mon->mux == nx && mon->muy == ny) { dispx = u.ux; dispy = u.uy; } else { dispx = nx; dispy = ny; } info[cnt] = 0; if (onscary(dispx, dispy, mon)) { if (!(flag & ALLOW_SSM)) continue; info[cnt] |= ALLOW_SSM; } if ((nx == u.ux && ny == u.uy) || (nx == mon->mux && ny == mon->muy)) { if (nx == u.ux && ny == u.uy) { /* If it's right next to you, it found you, * displaced or no. We must set mux and muy * right now, so when we return we can tell * that the ALLOW_U means to attack _you_ and * not the image. */ mon->mux = u.ux; mon->muy = u.uy; } if (!(flag & ALLOW_U)) continue; info[cnt] |= ALLOW_U; } else { if (MON_AT(nx, ny)) { struct monst *mtmp2 = m_at(nx, ny); long mmflag = flag | mm_aggression(mon, mtmp2); if (mmflag & ALLOW_M) { info[cnt] |= ALLOW_M; if (mtmp2->mtame) { if (!(mmflag & ALLOW_TM)) continue; info[cnt] |= ALLOW_TM; } } else { mmflag = flag | mm_displacement(mon, mtmp2); if (!(mmflag & ALLOW_MDISP)) continue; info[cnt] |= ALLOW_MDISP; } } /* Note: ALLOW_SANCT only prevents movement, not attack, into a temple. */ if (level.flags.has_temple && *in_rooms(nx, ny, TEMPLE) && !*in_rooms(x, y, TEMPLE) && in_your_sanctuary((struct monst *) 0, nx, ny)) { if (!(flag & ALLOW_SANCT)) continue; info[cnt] |= ALLOW_SANCT; } } if (checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) { if (flag & NOGARLIC) continue; info[cnt] |= NOGARLIC; } if (checkobj && sobj_at(BOULDER, nx, ny)) { if (!(flag & ALLOW_ROCK)) continue; info[cnt] |= ALLOW_ROCK; } if (monseeu && onlineu(nx, ny)) { if (flag & NOTONL) continue; info[cnt] |= NOTONL; } /* check for diagonal tight squeeze */ if (nx != x && ny != y && bad_rock(mdat, x, ny) && bad_rock(mdat, nx, y) && cant_squeeze_thru(mon)) continue; /* The monster avoids a particular type of trap if it's * familiar with the trap type. Pets get ALLOW_TRAPS * and checking is done in dogmove.c. In either case, * "harmless" traps are neither avoided nor marked in info[]. */ if ((ttmp = t_at(nx, ny)) != 0) { if (ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) { impossible( "A monster looked at a very strange trap of type %d.", ttmp->ttyp); continue; } if ((ttmp->ttyp != RUST_TRAP || mdat == &mons[PM_IRON_GOLEM]) && ttmp->ttyp != STATUE_TRAP && ((ttmp->ttyp != PIT && ttmp->ttyp != SPIKED_PIT && ttmp->ttyp != TRAPDOOR && ttmp->ttyp != HOLE) || (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) || Sokoban) && (ttmp->ttyp != SLP_GAS_TRAP || !resists_sleep(mon)) && (ttmp->ttyp != BEAR_TRAP || (mdat->msize > MZ_SMALL && !amorphous(mdat) && !is_flyer(mdat) && !is_floater(mdat) && !is_whirly(mdat) && !unsolid(mdat))) && (ttmp->ttyp != FIRE_TRAP || !resists_fire(mon)) && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat)) && (ttmp->ttyp != WEB || (!amorphous(mdat) && !webmaker(mdat))) && (ttmp->ttyp != ANTI_MAGIC || !resists_magm(mon))) { if (!(flag & ALLOW_TRAPS)) { if (mon->mtrapseen & (1L << (ttmp->ttyp - 1))) continue; } info[cnt] |= ALLOW_TRAPS; } } poss[cnt].x = nx; poss[cnt].y = ny; cnt++; } } if (!cnt && wantpool && !is_pool(x, y)) { wantpool = FALSE; goto nexttry; } return cnt; } /* Monster against monster special attacks; for the specified monster combinations, this allows one monster to attack another adjacent one in the absence of Conflict. There is no provision for targetting other monsters; just hand to hand fighting when they happen to be next to each other. */ STATIC_OVL long mm_aggression(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ *mdef; /* another monster which is next to it */ { /* supposedly purple worms are attracted to shrieking because they like to eat shriekers, so attack the latter when feasible */ if (magr->data == &mons[PM_PURPLE_WORM] && mdef->data == &mons[PM_SHRIEKER]) return ALLOW_M | ALLOW_TM; /* Various other combinations such as dog vs cat, cat vs rat, and elf vs orc have been suggested. For the time being we don't support those. */ return 0L; } /* Monster displacing another monster out of the way */ STATIC_OVL long mm_displacement(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ *mdef; /* another monster which is next to it */ { struct permonst *pa = magr->data, *pd = mdef->data; /* if attacker can't barge through, there's nothing to do; or if defender can barge through too, don't let attacker do so, otherwise they might just end up swapping places again when defender gets its chance to move */ if ((pa->mflags3 & M3_DISPLACES) != 0 && (pd->mflags3 & M3_DISPLACES) == 0 /* no displacing grid bugs diagonally */ && !(magr->mx != mdef->mx && magr->my != mdef->my && NODIAG(monsndx(pd))) /* no displacing trapped monsters or multi-location longworms */ && !mdef->mtrapped && (!mdef->wormno || !count_wsegs(mdef)) /* riders can move anything; others, same size or smaller only */ && (is_rider(pa) || pa->msize >= pd->msize)) return ALLOW_MDISP; return 0L; } /* Is the square close enough for the monster to move or attack into? */ boolean monnear(mon, x, y) struct monst *mon; int x, y; { int distance = dist2(mon->mx, mon->my, x, y); if (distance == 2 && NODIAG(mon->data - mons)) return 0; return (boolean) (distance < 3); } /* really free dead monsters */ void dmonsfree() { struct monst **mtmp, *freetmp; int count = 0; for (mtmp = &fmon; *mtmp;) { freetmp = *mtmp; if (freetmp->mhp <= 0 && !freetmp->isgd) { *mtmp = freetmp->nmon; freetmp->nmon = NULL; dealloc_monst(freetmp); count++; } else mtmp = &(freetmp->nmon); } if (count != iflags.purge_monsters) impossible("dmonsfree: %d removed doesn't match %d pending", count, iflags.purge_monsters); iflags.purge_monsters = 0; } /* called when monster is moved to larger structure */ void replmon(mtmp, mtmp2) struct monst *mtmp, *mtmp2; { struct obj *otmp; /* transfer the monster's inventory */ for (otmp = mtmp2->minvent; otmp; otmp = otmp->nobj) { if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp) impossible("replmon: minvent inconsistency"); otmp->ocarry = mtmp2; } mtmp->minvent = 0; /* remove the old monster from the map and from `fmon' list */ relmon(mtmp, (struct monst **) 0); /* finish adding its replacement */ if (mtmp != u.usteed) /* don't place steed onto the map */ place_monster(mtmp2, mtmp2->mx, mtmp2->my); if (mtmp2->wormno) /* update level.monsters[wseg->wx][wseg->wy] */ place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */ if (emits_light(mtmp2->data)) { /* since this is so rare, we don't have any `mon_move_light_source' */ new_light_source(mtmp2->mx, mtmp2->my, emits_light(mtmp2->data), LS_MONSTER, monst_to_any(mtmp2)); /* here we rely on fact that `mtmp' hasn't actually been deleted */ del_light_source(LS_MONSTER, monst_to_any(mtmp)); } mtmp2->nmon = fmon; fmon = mtmp2; if (u.ustuck == mtmp) u.ustuck = mtmp2; if (u.usteed == mtmp) u.usteed = mtmp2; if (mtmp2->isshk) replshk(mtmp, mtmp2); /* discard the old monster */ dealloc_monst(mtmp); } /* release mon from the display and the map's monster list, maybe transfer it to one of the other monster lists */ void relmon(mon, monst_list) struct monst *mon; struct monst **monst_list; /* &migrating_mons or &mydogs or null */ { struct monst *mtmp; boolean unhide = (monst_list != 0); int mx = mon->mx, my = mon->my; if (!fmon) panic("relmon: no fmon available."); if (unhide) { /* can't remain hidden across level changes (exception: wizard clone can continue imitating some other monster form); also, might be imitating a boulder so need line-of-sight unblocking */ mon->mundetected = 0; if (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER) seemimic(mon); } remove_monster(mx, my); if (mon == fmon) { fmon = fmon->nmon; } else { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->nmon == mon) break; if (mtmp) mtmp->nmon = mon->nmon; else panic("relmon: mon not in list."); } if (unhide) { newsym(mx, my); /* insert into mydogs or migrating_mons */ mon->nmon = *monst_list; *monst_list = mon; } else { /* orphan has no next monster */ mon->nmon = 0; } } void copy_mextra(mtmp2, mtmp1) struct monst *mtmp2, *mtmp1; { if (!mtmp2 || !mtmp1 || !mtmp1->mextra) return; if (!mtmp2->mextra) mtmp2->mextra = newmextra(); if (MNAME(mtmp1)) { new_mname(mtmp2, (int) strlen(MNAME(mtmp1)) + 1); Strcpy(MNAME(mtmp2), MNAME(mtmp1)); } if (EGD(mtmp1)) { if (!EGD(mtmp2)) newegd(mtmp2); (void) memcpy((genericptr_t) EGD(mtmp2), (genericptr_t) EGD(mtmp1), sizeof (struct egd)); } if (EPRI(mtmp1)) { if (!EPRI(mtmp2)) newepri(mtmp2); (void) memcpy((genericptr_t) EPRI(mtmp2), (genericptr_t) EPRI(mtmp1), sizeof (struct epri)); } if (ESHK(mtmp1)) { if (!ESHK(mtmp2)) neweshk(mtmp2); (void) memcpy((genericptr_t) ESHK(mtmp2), (genericptr_t) ESHK(mtmp1), sizeof (struct eshk)); } if (EMIN(mtmp1)) { if (!EMIN(mtmp2)) newemin(mtmp2); (void) memcpy((genericptr_t) EMIN(mtmp2), (genericptr_t) EMIN(mtmp1), sizeof (struct emin)); } if (EDOG(mtmp1)) { if (!EDOG(mtmp2)) newedog(mtmp2); (void) memcpy((genericptr_t) EDOG(mtmp2), (genericptr_t) EDOG(mtmp1), sizeof (struct edog)); } if (has_mcorpsenm(mtmp1)) MCORPSENM(mtmp2) = MCORPSENM(mtmp1); } void dealloc_mextra(m) struct monst *m; { struct mextra *x = m->mextra; if (x) { if (x->mname) free((genericptr_t) x->mname); if (x->egd) free((genericptr_t) x->egd); if (x->epri) free((genericptr_t) x->epri); if (x->eshk) free((genericptr_t) x->eshk); if (x->emin) free((genericptr_t) x->emin); if (x->edog) free((genericptr_t) x->edog); /* [no action needed for x->mcorpsenm] */ free((genericptr_t) x); m->mextra = (struct mextra *) 0; } } void dealloc_monst(mon) struct monst *mon; { if (mon->nmon) panic("dealloc_monst with nmon"); if (mon->mextra) dealloc_mextra(mon); free((genericptr_t) mon); } /* remove effects of mtmp from other data structures */ STATIC_OVL void m_detach(mtmp, mptr) struct monst *mtmp; struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ { if (mtmp == context.polearm.hitmon) context.polearm.hitmon = 0; if (mtmp->mleashed) m_unleash(mtmp, FALSE); /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ mtmp->mtrapped = 0; mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ relobj(mtmp, 0, FALSE); remove_monster(mtmp->mx, mtmp->my); if (emits_light(mptr)) del_light_source(LS_MONSTER, monst_to_any(mtmp)); newsym(mtmp->mx, mtmp->my); unstuck(mtmp); fill_pit(mtmp->mx, mtmp->my); if (mtmp->isshk) shkgone(mtmp); if (mtmp->wormno) wormgone(mtmp); iflags.purge_monsters++; } /* find the worn amulet of life saving which will save a monster */ struct obj * mlifesaver(mon) struct monst *mon; { if (!nonliving(mon->data) || is_vampshifter(mon)) { struct obj *otmp = which_armor(mon, W_AMUL); if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) return otmp; } return (struct obj *) 0; } STATIC_OVL void lifesaved_monster(mtmp) struct monst *mtmp; { boolean surviver; struct obj *lifesave = mlifesaver(mtmp); if (lifesave) { /* not canseemon; amulets are on the head, so you don't want * to show this for a long worm with only a tail visible. * Nor do you check invisibility, because glowing and * disintegrating amulets are always visible. */ if (cansee(mtmp->mx, mtmp->my)) { pline("But wait..."); pline("%s medallion begins to glow!", s_suffix(Monnam(mtmp))); makeknown(AMULET_OF_LIFE_SAVING); /* amulet is visible, but monster might not be */ if (canseemon(mtmp)) { if (attacktype(mtmp->data, AT_EXPL) || attacktype(mtmp->data, AT_BOOM)) pline("%s reconstitutes!", Monnam(mtmp)); else pline("%s looks much better!", Monnam(mtmp)); } pline_The("medallion crumbles to dust!"); } m_useup(mtmp, lifesave); surviver = !(mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); mtmp->mcanmove = 1; mtmp->mfrozen = 0; if (mtmp->mtame && !mtmp->isminion) { wary_dog(mtmp, !surviver); } if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; mtmp->mhp = mtmp->mhpmax; if (surviver) return; /* genocided monster can't be life-saved */ if (cansee(mtmp->mx, mtmp->my)) pline("Unfortunately, %s is still genocided...", mon_nam(mtmp)); } mtmp->mhp = 0; } void mondead(mtmp) register struct monst *mtmp; { struct permonst *mptr; int tmp; lifesaved_monster(mtmp); if (mtmp->mhp > 0) return; if (is_vampshifter(mtmp)) { int mndx = mtmp->cham; int x = mtmp->mx, y = mtmp->my; /* this only happens if shapeshifted */ if (mndx >= LOW_PM && mndx != monsndx(mtmp->data)) { char buf[BUFSZ]; boolean in_door = (amorphous(mtmp->data) && closed_door(mtmp->mx, mtmp->my)), /* alternate message phrasing for some monster types */ spec_mon = (nonliving(mtmp->data) || noncorporeal(mtmp->data) || amorphous(mtmp->data)); /* construct a format string before transformation */ Sprintf(buf, "The %s%s suddenly %s and rises as %%s!", spec_mon ? "" : "seemingly dead ", x_monnam(mtmp, ARTICLE_NONE, (char *) 0, SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION | SUPPRESS_INVISIBLE | SUPPRESS_IT, FALSE), spec_mon ? "reconstitutes" : "transforms"); mtmp->mcanmove = 1; mtmp->mfrozen = 0; if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; mtmp->mhp = mtmp->mhpmax; /* this can happen if previously a fog cloud */ if (u.uswallow && (mtmp == u.ustuck)) expels(mtmp, mtmp->data, FALSE); if (in_door) { coord new_xy; if (enexto(&new_xy, mtmp->mx, mtmp->my, &mons[mndx])) { rloc_to(mtmp, new_xy.x, new_xy.y); } } newcham(mtmp, &mons[mndx], FALSE, FALSE); if (mtmp->data == &mons[mndx]) mtmp->cham = NON_PM; else mtmp->cham = mndx; if (canspotmon(mtmp)) { pline(buf, a_monnam(mtmp)); vamp_rise_msg = TRUE; } newsym(x, y); return; } } /* dead vault guard is actually kept at coordinate <0,0> until his temporary corridor to/from the vault has been removed; need to do this after life-saving and before m_detach() */ if (mtmp->isgd && !grddead(mtmp)) return; /* Player is thrown from his steed when it dies */ if (mtmp == u.usteed) dismount_steed(DISMOUNT_GENERIC); mptr = mtmp->data; /* save this for m_detach() */ /* restore chameleon, lycanthropes to true form at death */ if (mtmp->cham >= LOW_PM) { set_mon_data(mtmp, &mons[mtmp->cham], -1); mtmp->cham = NON_PM; } else if (mtmp->data == &mons[PM_WEREJACKAL]) set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1); else if (mtmp->data == &mons[PM_WEREWOLF]) set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1); else if (mtmp->data == &mons[PM_WERERAT]) set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1); /* if MAXMONNO monsters of a given type have died, and it * can be done, extinguish that monster. * * mvitals[].died does double duty as total number of dead monsters * and as experience factor for the player killing more monsters. * this means that a dragon dying by other means reduces the * experience the player gets for killing a dragon directly; this * is probably not too bad, since the player likely finagled the * first dead dragon via ring of conflict or pets, and extinguishing * based on only player kills probably opens more avenues of abuse * for rings of conflict and such. */ tmp = monsndx(mtmp->data); if (mvitals[tmp].died < 255) mvitals[tmp].died++; /* if it's a (possibly polymorphed) quest leader, mark him as dead */ if (mtmp->m_id == quest_status.leader_m_id) quest_status.leader_is_dead = TRUE; #ifdef MAIL /* if the mail daemon dies, no more mail delivery. -3. */ if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD; #endif if (mtmp->data->mlet == S_KOP) { /* Dead Kops may come back. */ switch (rnd(5)) { case 1: /* returns near the stairs */ (void) makemon(mtmp->data, xdnstair, ydnstair, NO_MM_FLAGS); break; case 2: /* randomly */ (void) makemon(mtmp->data, 0, 0, NO_MM_FLAGS); break; default: break; } } if (mtmp->iswiz) wizdead(); if (mtmp->data->msound == MS_NEMESIS) nemdead(); if (mtmp->data == &mons[PM_MEDUSA]) u.uachieve.killed_medusa = 1; if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) unmap_object(mtmp->mx, mtmp->my); m_detach(mtmp, mptr); } /* TRUE if corpse might be dropped, magr may die if mon was swallowed */ boolean corpse_chance(mon, magr, was_swallowed) struct monst *mon; struct monst *magr; /* killer, if swallowed */ boolean was_swallowed; /* digestion */ { struct permonst *mdat = mon->data; int i, tmp; if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) { if (cansee(mon->mx, mon->my) && !was_swallowed) pline("%s body crumbles into dust.", s_suffix(Monnam(mon))); return FALSE; } /* Gas spores always explode upon death */ for (i = 0; i < NATTK; i++) { if (mdat->mattk[i].aatyp == AT_BOOM) { if (mdat->mattk[i].damn) tmp = d((int) mdat->mattk[i].damn, (int) mdat->mattk[i].damd); else if (mdat->mattk[i].damd) tmp = d((int) mdat->mlevel + 1, (int) mdat->mattk[i].damd); else tmp = 0; if (was_swallowed && magr) { if (magr == &youmonst) { There("is an explosion in your %s!", body_part(STOMACH)); Sprintf(killer.name, "%s explosion", s_suffix(mdat->mname)); losehp(Maybe_Half_Phys(tmp), killer.name, KILLED_BY_AN); } else { You_hear("an explosion."); magr->mhp -= tmp; if (magr->mhp < 1) mondied(magr); if (magr->mhp < 1) { /* maybe lifesaved */ if (canspotmon(magr)) pline("%s rips open!", Monnam(magr)); } else if (canseemon(magr)) pline("%s seems to have indigestion.", Monnam(magr)); } return FALSE; } Sprintf(killer.name, "%s explosion", s_suffix(mdat->mname)); killer.format = KILLED_BY_AN; explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE, EXPL_NOXIOUS); return FALSE; } } /* must duplicate this below check in xkilled() since it results in * creating no objects as well as no corpse */ if (LEVEL_SPECIFIC_NOCORPSE(mdat)) return FALSE; if (((bigmonst(mdat) || mdat == &mons[PM_LIZARD]) && !mon->mcloned) || is_golem(mdat) || is_mplayer(mdat) || is_rider(mdat)) return TRUE; tmp = 2 + ((mdat->geno & G_FREQ) < 2) + verysmall(mdat); return (boolean) !rn2(tmp); } /* drop (perhaps) a cadaver and remove monster */ void mondied(mdef) register struct monst *mdef; { mondead(mdef); if (mdef->mhp > 0) return; /* lifesaved */ if (corpse_chance(mdef, (struct monst *) 0, FALSE) && (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my))) (void) make_corpse(mdef, CORPSTAT_NONE); } /* monster disappears, not dies */ void mongone(mdef) struct monst *mdef; { mdef->mhp = 0; /* can skip some inventory bookkeeping */ /* dead vault guard is actually kept at coordinate <0,0> until his temporary corridor to/from the vault has been removed */ if (mdef->isgd && !grddead(mdef)) return; /* hero is thrown from his steed when it disappears */ if (mdef == u.usteed) dismount_steed(DISMOUNT_GENERIC); /* drop special items like the Amulet so that a dismissed Kop or nurse can't remove them from the game */ mdrop_special_objs(mdef); /* release rest of monster's inventory--it is removed from game */ discard_minvent(mdef); m_detach(mdef, mdef->data); } /* drop a statue or rock and remove monster */ void monstone(mdef) struct monst *mdef; { struct obj *otmp, *obj, *oldminvent; xchar x = mdef->mx, y = mdef->my; boolean wasinside = FALSE; /* we have to make the statue before calling mondead, to be able to * put inventory in it, and we have to check for lifesaving before * making the statue.... */ lifesaved_monster(mdef); if (mdef->mhp > 0) return; mdef->mtrapped = 0; /* (see m_detach) */ if ((int) mdef->data->msize > MZ_TINY || !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) { oldminvent = 0; /* some objects may end up outside the statue */ while ((obj = mdef->minvent) != 0) { obj_extract_self(obj); if (obj->owornmask) update_mon_intrinsics(mdef, obj, FALSE, TRUE); obj_no_longer_held(obj); if (obj->owornmask & W_WEP) setmnotwielded(mdef, obj); obj->owornmask = 0L; if (obj->otyp == BOULDER #if 0 /* monsters don't carry statues */ || (obj->otyp == STATUE && mons[obj->corpsenm].msize >= mdef->data->msize) #endif /* invocation tools resist even with 0% resistance */ || obj_resists(obj, 0, 0)) { if (flooreffects(obj, x, y, "fall")) continue; place_object(obj, x, y); } else { if (obj->lamplit) end_burn(obj, TRUE); obj->nobj = oldminvent; oldminvent = obj; } } /* defer statue creation until after inventory removal so that saved monster traits won't retain any stale item-conferred attributes */ otmp = mkcorpstat(STATUE, mdef, mdef->data, x, y, CORPSTAT_NONE); if (has_mname(mdef)) otmp = oname(otmp, MNAME(mdef)); while ((obj = oldminvent) != 0) { oldminvent = obj->nobj; (void) add_to_container(otmp, obj); } /* Archeologists should not break unique statues */ if (mdef->data->geno & G_UNIQ) otmp->spe = 1; otmp->owt = weight(otmp); } else otmp = mksobj_at(ROCK, x, y, TRUE, FALSE); stackobj(otmp); /* mondead() already does this, but we must do it before the newsym */ if (glyph_is_invisible(levl[x][y].glyph)) unmap_object(x, y); if (cansee(x, y)) newsym(x, y); /* We don't currently trap the hero in the statue in this case but we * could */ if (u.uswallow && u.ustuck == mdef) wasinside = TRUE; mondead(mdef); if (wasinside) { if (is_animal(mdef->data)) You("%s through an opening in the new %s.", locomotion(youmonst.data, "jump"), xname(otmp)); } } /* another monster has killed the monster mdef */ void monkilled(mdef, fltxt, how) struct monst *mdef; const char *fltxt; int how; { boolean be_sad = FALSE; /* true if unseen pet is killed */ if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my)) && fltxt) pline("%s is %s%s%s!", Monnam(mdef), nonliving(mdef->data) ? "destroyed" : "killed", *fltxt ? " by the " : "", fltxt); else be_sad = (mdef->mtame != 0); /* no corpses if digested or disintegrated */ if (how == AD_DGST || how == -AD_RBRE) mondead(mdef); else mondied(mdef); if (be_sad && mdef->mhp <= 0) You("have a sad feeling for a moment, then it passes."); } void unstuck(mtmp) struct monst *mtmp; { if (u.ustuck == mtmp) { if (u.uswallow) { u.ux = mtmp->mx; u.uy = mtmp->my; u.uswallow = 0; u.uswldtim = 0; if (Punished && uchain->where != OBJ_FLOOR) placebc(); vision_full_recalc = 1; docrt(); } u.ustuck = 0; } } void killed(mtmp) struct monst *mtmp; { xkilled(mtmp, 1); } /* the player has killed the monster mtmp */ void xkilled(mtmp, dest) struct monst *mtmp; int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't drop corpse either; dest==3, message but no corpse */ { int tmp, mndx, x = mtmp->mx, y = mtmp->my; struct permonst *mdat; struct obj *otmp; struct trap *t; boolean wasinside = u.uswallow && (u.ustuck == mtmp); boolean burycorpse = FALSE; /* KMH, conduct */ u.uconduct.killer++; if (dest & 1) { const char *verb = nonliving(mtmp->data) ? "destroy" : "kill"; if (!wasinside && !canspotmon(mtmp)) You("%s it!", verb); else { You("%s %s!", verb, !mtmp->mtame ? mon_nam(mtmp) : x_monnam(mtmp, (has_mname(mtmp)) ? ARTICLE_NONE : ARTICLE_THE, "poor", (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE)); } } if (mtmp->mtrapped && (t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { if (sobj_at(BOULDER, x, y)) dest |= 2; /* * Prevent corpses/treasure being created "on top" * of the boulder that is about to fall in. This is * out of order, but cannot be helped unless this * whole routine is rearranged. */ if (m_carrying(mtmp, BOULDER)) burycorpse = TRUE; } /* your pet knows who just killed it...watch out */ if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1; if (wasinside && thrownobj && thrownobj != uball) { /* thrown object has killed hero's engulfer; add it to mon's inventory now so that it will be placed with mon's other stuff prior to lookhere/autopickup when hero is expelled below (as a side-effect, this missile has immunity from being consumed [for this shot/throw only]) */ mpickobj(mtmp, thrownobj); /* let throwing code know that missile has been disposed of */ thrownobj = 0; } vamp_rise_msg = FALSE; /* might get set in mondead() */ /* dispose of monster and make cadaver */ if (stoned) monstone(mtmp); else mondead(mtmp); if (mtmp->mhp > 0) { /* monster lifesaved */ /* Cannot put the non-visible lifesaving message in * lifesaved_monster() since the message appears only when you * kill it (as opposed to visible lifesaving which always * appears). */ stoned = FALSE; if (!cansee(x, y) && !vamp_rise_msg) pline("Maybe not..."); return; } mdat = mtmp->data; /* note: mondead can change mtmp->data */ mndx = monsndx(mdat); if (stoned) { stoned = FALSE; goto cleanup; } if ((dest & 2) || LEVEL_SPECIFIC_NOCORPSE(mdat)) goto cleanup; #ifdef MAIL if (mdat == &mons[PM_MAIL_DAEMON]) { stackobj(mksobj_at(SCR_MAIL, x, y, FALSE, FALSE)); } #endif if (accessible(x, y) || is_pool(x, y)) { struct obj *cadaver; int otyp; /* illogical but traditional "treasure drop" */ if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE) /* no extra item from swallower or steed */ && (x != u.ux || y != u.uy) /* no extra item from kops--too easy to abuse */ && mdat->mlet != S_KOP /* no items from cloned monsters */ && !mtmp->mcloned) { otmp = mkobj(RANDOM_CLASS, TRUE); /* don't create large objects from small monsters */ otyp = otmp->otyp; if (mdat->msize < MZ_HUMAN && otyp != FIGURINE /* oc_big is also oc_bimanual and oc_bulky */ && (otmp->owt > 30 || objects[otyp].oc_big)) { delobj(otmp); } else if (!flooreffects(otmp, x, y, (dest & 1) ? "fall" : "")) { place_object(otmp, x, y); stackobj(otmp); } } /* corpse--none if hero was inside the monster */ if (!wasinside && corpse_chance(mtmp, (struct monst *) 0, FALSE)) { cadaver = make_corpse(mtmp, burycorpse ? CORPSTAT_BURIED : CORPSTAT_NONE); if (burycorpse && cadaver && cansee(x, y) && !mtmp->minvis && cadaver->where == OBJ_BURIED && (dest & 1)) { pline("%s corpse ends up buried.", s_suffix(Monnam(mtmp))); } } } if (wasinside) spoteffects(TRUE); /* poor man's expels() */ /* monster is gone, corpse or other object might now be visible */ newsym(x, y); cleanup: /* punish bad behaviour */ if (is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) && (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) && u.ualign.type != A_CHAOTIC) { HTelepat &= ~INTRINSIC; change_luck(-2); You("murderer!"); if (Blind && !Blind_telepat) see_monsters(); /* Can't sense monsters any more. */ } if ((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1); if (is_unicorn(mdat) && sgn(u.ualign.type) == sgn(mdat->maligntyp)) { change_luck(-5); You_feel("guilty..."); } /* give experience points */ tmp = experience(mtmp, (int) mvitals[mndx].died); more_experienced(tmp, 0); newexplevel(); /* will decide if you go up */ /* adjust alignment points */ if (mtmp->m_id == quest_status.leader_m_id) { /* REAL BAD! */ adjalign(-(u.ualign.record + (int) ALIGNLIM / 2)); pline("That was %sa bad idea...", u.uevent.qcompleted ? "probably " : ""); } else if (mdat->msound == MS_NEMESIS) { /* Real good! */ adjalign((int) (ALIGNLIM / 4)); } else if (mdat->msound == MS_GUARDIAN) { /* Bad */ adjalign(-(int) (ALIGNLIM / 8)); if (!Hallucination) pline("That was probably a bad idea..."); else pline("Whoopsie-daisy!"); } else if (mtmp->ispriest) { adjalign((p_coaligned(mtmp)) ? -2 : 2); /* cancel divine protection for killing your priest */ if (p_coaligned(mtmp)) u.ublessed = 0; if (mdat->maligntyp == A_NONE) adjalign((int) (ALIGNLIM / 4)); /* BIG bonus */ } else if (mtmp->mtame) { adjalign(-15); /* bad!! */ /* your god is mighty displeased... */ if (!Hallucination) You_hear("the rumble of distant thunder..."); else You_hear("the studio audience applaud!"); } else if (mtmp->mpeaceful) adjalign(-5); /* malign was already adjusted for u.ualign.type and randomization */ adjalign(mtmp->malign); } /* changes the monster into a stone monster of the same type this should only be called when poly_when_stoned() is true */ void mon_to_stone(mtmp) struct monst *mtmp; { if (mtmp->data->mlet == S_GOLEM) { /* it's a golem, and not a stone golem */ if (canseemon(mtmp)) pline("%s solidifies...", Monnam(mtmp)); if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) { if (canseemon(mtmp)) pline("Now it's %s.", an(mtmp->data->mname)); } else { if (canseemon(mtmp)) pline("... and returns to normal."); } } else impossible("Can't polystone %s!", a_monnam(mtmp)); } /* make monster mtmp next to you (if possible); might place monst on far side of a wall or boulder */ void mnexto(mtmp) struct monst *mtmp; { coord mm; boolean couldspot = canspotmon(mtmp); if (mtmp == u.usteed) { /* Keep your steed in sync with you instead */ mtmp->mx = u.ux; mtmp->my = u.uy; return; } if (!enexto(&mm, u.ux, u.uy, mtmp->data)) return; rloc_to(mtmp, mm.x, mm.y); if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) { mtmp->mstrategy &= ~STRAT_APPEARMSG; /* one chance only */ if (!couldspot && canspotmon(mtmp)) pline("%s suddenly %s!", Amonnam(mtmp), !Blind ? "appears" : "arrives"); } return; } /* like mnexto() but requires destination to be directly accessible */ void maybe_mnexto(mtmp) struct monst *mtmp; { coord mm; struct permonst *ptr = mtmp->data; boolean diagok = !NODIAG(ptr - mons); int tryct = 20; do { if (!enexto(&mm, u.ux, u.uy, ptr)) return; if (couldsee(mm.x, mm.y) /* don't move grid bugs diagonally */ && (diagok || mm.x == mtmp->mx || mm.y == mtmp->my)) { rloc_to(mtmp, mm.x, mm.y); return; } } while (--tryct > 0); } /* mnearto() * Put monster near (or at) location if possible. * Returns: * 1 - if a monster was moved from x, y to put mtmp at x, y. * 0 - in most cases. */ boolean mnearto(mtmp, x, y, move_other) register struct monst *mtmp; xchar x, y; boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ { struct monst *othermon = (struct monst *) 0; xchar newx, newy; coord mm; if (mtmp->mx == x && mtmp->my == y) return FALSE; if (move_other && (othermon = m_at(x, y)) != 0) { if (othermon->wormno) remove_worm(othermon); else remove_monster(x, y); } newx = x; newy = y; if (!goodpos(newx, newy, mtmp, 0)) { /* Actually we have real problems if enexto ever fails. * Migrating_mons that need to be placed will cause * no end of trouble. */ if (!enexto(&mm, newx, newy, mtmp->data)) return FALSE; newx = mm.x; newy = mm.y; } rloc_to(mtmp, newx, newy); if (move_other && othermon) { xchar oldx = othermon->mx, oldy = othermon->my; othermon->mx = othermon->my = 0; (void) mnearto(othermon, x, y, FALSE); if (othermon->mx == 0 && othermon->my == 0) { /* reloc failed, dump monster into "limbo" (aka migrate to current level) */ othermon->mx = oldx; othermon->my = oldy; mdrop_special_objs(othermon); migrate_to_level(othermon, ledger_no(&u.uz), MIGR_APPROX_XY, NULL); } } return FALSE; } /* monster responds to player action; not the same as a passive attack; assumes reason for response has been tested, and response _must_ be made */ void m_respond(mtmp) struct monst *mtmp; { if (mtmp->data->msound == MS_SHRIEK) { if (!Deaf) { pline("%s shrieks.", Monnam(mtmp)); stop_occupation(); } if (!rn2(10)) { if (!rn2(13)) (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS); else (void) makemon((struct permonst *) 0, 0, 0, NO_MM_FLAGS); } aggravate(); } if (mtmp->data == &mons[PM_MEDUSA]) { register int i; for (i = 0; i < NATTK; i++) if (mtmp->data->mattk[i].aatyp == AT_GAZE) { (void) gazemu(mtmp, &mtmp->data->mattk[i]); break; } } } void setmangry(mtmp) struct monst *mtmp; { mtmp->mstrategy &= ~STRAT_WAITMASK; if (!mtmp->mpeaceful) return; if (mtmp->mtame) return; mtmp->mpeaceful = 0; if (mtmp->ispriest) { if (p_coaligned(mtmp)) adjalign(-5); /* very bad */ else adjalign(2); } else adjalign(-1); /* attacking peaceful monsters is bad */ if (couldsee(mtmp->mx, mtmp->my)) { if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd) pline("%s gets angry!", Monnam(mtmp)); else if (flags.verbose && !Deaf) growl(mtmp); } /* attacking your own quest leader will anger his or her guardians */ if (!context.mon_moving /* should always be the case here */ && mtmp->data == &mons[quest_info(MS_LEADER)]) { struct monst *mon; struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)]; int got_mad = 0; /* guardians will sense this attack even if they can't see it */ for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; if (mon->data == q_guardian && mon->mpeaceful) { mon->mpeaceful = 0; if (canseemon(mon)) ++got_mad; } } if (got_mad && !Hallucination) pline_The("%s appear%s to be angry too...", got_mad == 1 ? q_guardian->mname : makeplural(q_guardian->mname), got_mad == 1 ? "s" : ""); } } /* wake up a monster, usually making it angry in the process */ void wakeup(mtmp) register struct monst *mtmp; { mtmp->msleeping = 0; finish_meating(mtmp); setmangry(mtmp); if (mtmp->m_ap_type) { seemimic(mtmp); } else if (context.forcefight && !context.mon_moving && mtmp->mundetected) { mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); } } /* Wake up nearby monsters without angering them. */ void wake_nearby() { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (distu(mtmp->mx, mtmp->my) < u.ulevel * 20) { mtmp->msleeping = 0; if (!unique_corpstat(mtmp->data)) mtmp->mstrategy &= ~STRAT_WAITMASK; if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->whistletime = moves; } } } /* Wake up monsters near some particular location. */ void wake_nearto(x, y, distance) register int x, y, distance; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (distance == 0 || dist2(mtmp->mx, mtmp->my, x, y) < distance) { mtmp->msleeping = 0; if (!unique_corpstat(mtmp->data)) mtmp->mstrategy &= ~STRAT_WAITMASK; } } } /* NOTE: we must check for mimicry before calling this routine */ void seemimic(mtmp) register struct monst *mtmp; { boolean is_blocker_appear = (is_door_mappear(mtmp) || is_obj_mappear(mtmp, BOULDER)); if (has_mcorpsenm(mtmp)) freemcorpsenm(mtmp); mtmp->m_ap_type = M_AP_NOTHING; mtmp->mappearance = 0; /* * Discovered mimics don't block light. */ if (is_blocker_appear && !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my])) unblock_point(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); } /* force all chameleons to become normal */ void rescham() { register struct monst *mtmp; int mcham; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mcham = (int) mtmp->cham; if (mcham >= LOW_PM) { (void) newcham(mtmp, &mons[mcham], FALSE, FALSE); mtmp->cham = NON_PM; } if (is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) new_were(mtmp); if (mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) { seemimic(mtmp); /* we pretend that the mimic doesn't know that it has been unmasked */ mtmp->msleeping = 1; } } } /* Let the chameleons change again -dgk */ void restartcham() { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mtmp->cham = pm_to_cham(monsndx(mtmp->data)); if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && cansee(mtmp->mx, mtmp->my)) { set_mimic_sym(mtmp); newsym(mtmp->mx, mtmp->my); } } } /* called when restoring a monster from a saved level; protection against shape-changing might be different now than it was at the time the level was saved. */ void restore_cham(mon) struct monst *mon; { int mcham; if (Protection_from_shape_changers) { mcham = (int) mon->cham; if (mcham >= LOW_PM) { mon->cham = NON_PM; (void) newcham(mon, &mons[mcham], FALSE, FALSE); } else if (is_were(mon->data) && !is_human(mon->data)) { new_were(mon); } } else if (mon->cham == NON_PM) { mon->cham = pm_to_cham(monsndx(mon->data)); } } /* unwatched hiders may hide again; if so, returns True */ STATIC_OVL boolean restrap(mtmp) register struct monst *mtmp; { struct trap *t; if (mtmp->mcan || mtmp->m_ap_type || cansee(mtmp->mx, mtmp->my) || rn2(3) || mtmp == u.ustuck /* can't hide while trapped except in pits */ || (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0 && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) || (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2)) return FALSE; if (mtmp->data->mlet == S_MIMIC) { set_mimic_sym(mtmp); return TRUE; } else if (levl[mtmp->mx][mtmp->my].typ == ROOM) { mtmp->mundetected = 1; return TRUE; } return FALSE; } /* monster/hero tries to hide under something at the current location */ boolean hideunder(mtmp) struct monst *mtmp; { struct trap *t; boolean undetected = FALSE, is_u = (mtmp == &youmonst); xchar x = is_u ? u.ux : mtmp->mx, y = is_u ? u.uy : mtmp->my; if (mtmp == u.ustuck) { ; /* can't hide if holding you or held by you */ } else if (is_u ? (u.utrap && u.utraptype != TT_PIT) : (mtmp->mtrapped && (t = t_at(x, y)) != 0 && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { ; /* can't hide while stuck in a non-pit trap */ } else if (mtmp->data->mlet == S_EEL) { undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz)); } else if (hides_under(mtmp->data) && OBJ_AT(x, y)) { struct obj *otmp = level.objects[x][y]; /* most monsters won't hide under cockatrice corpse */ if (otmp->nexthere || otmp->otyp != CORPSE || (mtmp == &youmonst ? Stone_resistance : resists_ston(mtmp)) || !touch_petrifies(&mons[otmp->corpsenm])) undetected = TRUE; } if (is_u) u.uundetected = undetected; else mtmp->mundetected = undetected; return undetected; } /* called when returning to a previously visited level */ void hide_monst(mon) struct monst *mon; { boolean hider_under = hides_under(mon->data) || mon->data->mlet == S_EEL; if ((is_hider(mon->data) || hider_under) && !(mon->mundetected || mon->m_ap_type)) { xchar x = mon->mx, y = mon->my; char save_viz = viz_array[y][x]; /* override vision, forcing hero to be unable to see monster's spot */ viz_array[y][x] &= ~(IN_SIGHT | COULD_SEE); if (is_hider(mon->data)) (void) restrap(mon); /* try again if mimic missed its 1/3 chance to hide */ if (mon->data->mlet == S_MIMIC && !mon->m_ap_type) (void) restrap(mon); if (hider_under) (void) hideunder(mon); viz_array[y][x] = save_viz; } } static short *animal_list = 0; /* list of PM values for animal monsters */ static int animal_list_count; void mon_animal_list(construct) boolean construct; { if (construct) { short animal_temp[SPECIAL_PM]; int i, n; /* if (animal_list) impossible("animal_list already exists"); */ for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++) if (is_animal(&mons[i])) animal_temp[n++] = i; /* if (n == 0) animal_temp[n++] = NON_PM; */ animal_list = (short *) alloc(n * sizeof *animal_list); (void) memcpy((genericptr_t) animal_list, (genericptr_t) animal_temp, n * sizeof *animal_list); animal_list_count = n; } else { /* release */ if (animal_list) free((genericptr_t) animal_list), animal_list = 0; animal_list_count = 0; } } STATIC_OVL int pick_animal() { int res; if (!animal_list) mon_animal_list(TRUE); res = animal_list[rn2(animal_list_count)]; /* rogue level should use monsters represented by uppercase letters only, but since chameleons aren't generated there (not uppercase!) we don't perform a lot of retries */ if (Is_rogue_level(&u.uz) && !isupper((uchar) mons[res].mlet)) res = animal_list[rn2(animal_list_count)]; return res; } void decide_to_shapeshift(mon, shiftflags) struct monst *mon; int shiftflags; { struct permonst *ptr; unsigned was_female = mon->female; boolean msg = FALSE; if ((shiftflags & SHIFT_MSG) || ((shiftflags & SHIFT_SEENMSG) && sensemon(mon))) msg = TRUE; if (is_vampshifter(mon)) { /* The vampire has to be in good health (mhp) to maintain * its shifted form. * * If we're shifted and getting low on hp, maybe shift back. * If we're not already shifted and in good health, maybe shift. */ if ((mon->mhp <= mon->mhpmax / 6) && rn2(4) && (mon->cham >= LOW_PM)) (void) newcham(mon, &mons[mon->cham], FALSE, msg); } else if (mon->data->mlet == S_VAMPIRE && mon->cham == NON_PM && !rn2(6) && (mon->mhp > mon->mhpmax - ((mon->mhpmax / 10) + 1))) { (void) newcham(mon, (struct permonst *) 0, FALSE, msg); } /* override the 10% chance for sex change */ ptr = mon->data; if (!is_male(ptr) && !is_female(ptr) && !is_neuter(ptr)) mon->female = was_female; } STATIC_OVL int pickvampshape(mon) struct monst *mon; { int mndx = mon->cham; /* avoid picking monsters with lowercase display symbols ('d' for wolf and 'v' for fog cloud) on rogue level*/ boolean uppercase_only = Is_rogue_level(&u.uz); switch (mndx) { case PM_VLAD_THE_IMPALER: /* ensure Vlad can keep carrying the Candelabrum */ if (mon_has_special(mon)) break; /* leave mndx as is */ /*FALLTHRU*/ case PM_VAMPIRE_LORD: /* vampire lord or Vlad can become wolf */ if (!rn2(10) && !uppercase_only) { mndx = PM_WOLF; break; } /*FALLTHRU*/ case PM_VAMPIRE: /* any vampire can become fog or bat */ mndx = (!rn2(4) && !uppercase_only) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; break; } return mndx; } /* nonshapechangers who warrant special polymorph handling */ STATIC_OVL boolean isspecmon(mon) struct monst *mon; { return (mon->isshk || mon->ispriest || mon->isgd || mon->m_id == quest_status.leader_m_id); } /* restrict certain special monsters (shopkeepers, aligned priests, vault guards) to forms that allow them to behave sensibly (catching gold, speaking?) so that they don't need too much extra code */ STATIC_OVL boolean validspecmon(mon, mndx) struct monst *mon; int mndx; { if (mndx == NON_PM) return TRUE; /* caller wants random */ if (!accept_newcham_form(mndx)) return FALSE; /* geno'd or !polyok */ if (isspecmon(mon)) { struct permonst *ptr = &mons[mndx]; /* reject notake because object manipulation is expected and nohead because speech capability is expected */ if (notake(ptr) || !has_head(ptr)) return FALSE; /* [should we check ptr->msound here too?] */ } return TRUE; /* potential new form is ok */ } /* prevent wizard mode user from specifying invalid vampshifter shape */ STATIC_OVL boolean validvamp(mon, mndx_p, monclass) struct monst *mon; int *mndx_p, monclass; { /* simplify caller's usage */ if (!is_vampshifter(mon)) return validspecmon(mon, *mndx_p); if (*mndx_p == PM_VAMPIRE || *mndx_p == PM_VAMPIRE_LORD || *mndx_p == PM_VLAD_THE_IMPALER) { /* player picked some type of vampire; use mon's self */ *mndx_p = mon->cham; return TRUE; } if (mon->cham == PM_VLAD_THE_IMPALER && mon_has_special(mon)) { /* Vlad with Candelabrum; override choice, then accept it */ *mndx_p = PM_VLAD_THE_IMPALER; return TRUE; } /* basic vampires can't become wolves; any can become fog or bat (we don't enforce upper-case only for rogue level here) */ if (*mndx_p == PM_WOLF) return (boolean) (mon->cham != PM_VAMPIRE); if (*mndx_p == PM_FOG_CLOUD || *mndx_p == PM_VAMPIRE_BAT) return TRUE; /* if we get here, specific type was no good; try by class */ switch (monclass) { case S_VAMPIRE: *mndx_p = mon->cham; break; case S_BAT: *mndx_p = PM_VAMPIRE_BAT; break; case S_VORTEX: *mndx_p = PM_FOG_CLOUD; break; case S_DOG: if (mon->cham != PM_VAMPIRE) { *mndx_p = PM_WOLF; break; } /*FALLTHRU*/ default: *mndx_p = NON_PM; break; } return (boolean) (*mndx_p != NON_PM); } int select_newcham_form(mon) struct monst *mon; { int mndx = NON_PM, tryct; switch (mon->cham) { case PM_SANDESTIN: if (rn2(7)) mndx = pick_nasty(); break; case PM_DOPPELGANGER: if (!rn2(7)) { mndx = pick_nasty(); } else if (rn2(3)) { /* role monsters */ mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, PM_ARCHEOLOGIST); } else if (!rn2(3)) { /* quest guardians */ mndx = rn1(PM_APPRENTICE - PM_STUDENT + 1, PM_STUDENT); /* avoid own role's guardian */ if (mndx == urole.guardnum) mndx = NON_PM; } else { /* general humanoids */ tryct = 5; do { mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); if (humanoid(&mons[mndx]) && polyok(&mons[mndx])) break; } while (--tryct > 0); if (!tryct) mndx = NON_PM; } break; case PM_CHAMELEON: if (!rn2(3)) mndx = pick_animal(); break; case PM_VLAD_THE_IMPALER: case PM_VAMPIRE_LORD: case PM_VAMPIRE: mndx = pickvampshape(mon); break; case NON_PM: /* ordinary */ { struct obj *m_armr = which_armor(mon, W_ARM); if (m_armr && Is_dragon_scales(m_armr)) mndx = (int) (Dragon_scales_to_pm(m_armr) - mons); else if (m_armr && Is_dragon_mail(m_armr)) mndx = (int) (Dragon_mail_to_pm(m_armr) - mons); } break; } /* for debugging: allow control of polymorphed monster */ if (wizard && iflags.mon_polycontrol) { char pprompt[BUFSZ], buf[BUFSZ]; int monclass; Sprintf(pprompt, "Change %s @ <%d,%d> into what kind of monster?", noit_mon_nam(mon), (int) mon->mx, (int) mon->my); tryct = 5; do { monclass = 0; getlin(pprompt, buf); mungspaces(buf); /* for ESC, take form selected above (might be NON_PM) */ if (*buf == '\033') break; /* for "*", use NON_PM to pick an arbitrary shape below */ if (!strcmp(buf, "*") || !strcmp(buf, "random")) { mndx = NON_PM; break; } mndx = name_to_mon(buf); if (mndx == NON_PM) { /* didn't get a type, so check whether it's a class (single letter or text match with def_monsyms[]) */ monclass = name_to_monclass(buf, &mndx); if (monclass && mndx == NON_PM) mndx = mkclass_poly(monclass); } if (mndx >= LOW_PM) { /* got a specific type of monster; use it if we can */ if (validvamp(mon, &mndx, monclass)) break; /* can't; revert to random in case we exhaust tryct */ mndx = NON_PM; } pline("It can't become that."); } while (--tryct > 0); if (!tryct) pline1(thats_enough_tries); if (is_vampshifter(mon) && !validvamp(mon, &mndx, monclass)) mndx = pickvampshape(mon); /* don't resort to arbitrary */ } /* if no form was specified above, pick one at random now */ if (mndx == NON_PM) { tryct = 50; do { mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); } while (--tryct > 0 && !validspecmon(mon, mndx) /* try harder to select uppercase monster on rogue level */ && (tryct > 40 && Is_rogue_level(&u.uz) && !isupper((uchar) mons[mndx].mlet))); } return mndx; } /* this used to be inline within newcham() but monpolycontrol needs it too */ STATIC_OVL struct permonst * accept_newcham_form(mndx) int mndx; { struct permonst *mdat; if (mndx == NON_PM) return 0; mdat = &mons[mndx]; if ((mvitals[mndx].mvflags & G_GENOD) != 0) return 0; if (is_placeholder(mdat)) return 0; /* select_newcham_form() might deliberately pick a player character type (random selection never does) which polyok() rejects, so we need a special case here */ if (is_mplayer(mdat)) return mdat; /* polyok() rules out M2_PNAME, M2_WERE, and all humans except Kops */ return polyok(mdat) ? mdat : 0; } void mgender_from_permonst(mtmp, mdat) struct monst *mtmp; struct permonst *mdat; { if (is_male(mdat)) { if (mtmp->female) mtmp->female = FALSE; } else if (is_female(mdat)) { if (!mtmp->female) mtmp->female = TRUE; } else if (!is_neuter(mdat)) { if (!rn2(10)) mtmp->female = !mtmp->female; } } /* make a chameleon take on another shape, or a polymorph target (possibly self-inflicted) become a different monster; returns 1 if it actually changes form */ int newcham(mtmp, mdat, polyspot, msg) struct monst *mtmp; struct permonst *mdat; boolean polyspot; /* change is the result of wand or spell of polymorph */ boolean msg; /* "The oldmon turns into a newmon!" */ { int hpn, hpd; int mndx, tryct; struct permonst *olddata = mtmp->data; char oldname[BUFSZ], newname[BUFSZ]; /* Riders are immune to polymorph and green slime */ if (is_rider(mtmp->data)) return 0; if (msg) { /* like Monnam() but never mention saddle */ Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE)); oldname[0] = highc(oldname[0]); } /* mdat = 0 -> caller wants a random monster shape */ if (mdat == 0) { /* select_newcham_form() loops when resorting to random but it doesn't always pick that so we still retry here too */ tryct = 20; do { mndx = select_newcham_form(mtmp); mdat = accept_newcham_form(mndx); /* for the first several tries we require upper-case on the rogue level (after that, we take whatever we get) */ if (tryct > 15 && Is_rogue_level(&u.uz) && mdat && !isupper((uchar) mdat->mlet)) mdat = 0; if (mdat) break; } while (--tryct > 0); if (!tryct) return 0; } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD) return 0; /* passed in mdat is genocided */ mgender_from_permonst(mtmp, mdat); if (In_endgame(&u.uz) && is_mplayer(olddata) && has_mname(mtmp)) { /* mplayers start out as "Foo the Bar", but some of the * titles are inappropriate when polymorphed, particularly * into the opposite sex. players don't use ranks when * polymorphed, so dropping the rank for mplayers seems * reasonable. */ char *p = index(MNAME(mtmp), ' '); if (p) *p = '\0'; } if (mdat == mtmp->data) return 0; /* still the same monster */ if (mtmp->wormno) { /* throw tail away */ wormgone(mtmp); place_monster(mtmp, mtmp->mx, mtmp->my); } if (mtmp->m_ap_type && mdat->mlet != S_MIMIC) seemimic(mtmp); /* revert to normal monster */ /* (this code used to try to adjust the monster's health based on a normal one of its type but there are too many special cases which need to handled in order to do that correctly, so just give the new form the same proportion of HP as its old one had) */ hpn = mtmp->mhp; hpd = mtmp->mhpmax; /* set level and hit points */ newmonhp(mtmp, monsndx(mdat)); /* new hp: same fraction of max as before */ #ifndef LINT mtmp->mhp = (int) (((long) hpn * (long) mtmp->mhp) / (long) hpd); #endif /* sanity check (potential overflow) */ if (mtmp->mhp < 0 || mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; /* unlikely but not impossible; a 1HD creature with 1HP that changes into a 0HD creature will require this statement */ if (!mtmp->mhp) mtmp->mhp = 1; /* take on the new form... */ set_mon_data(mtmp, mdat, 0); if (emits_light(olddata) != emits_light(mtmp->data)) { /* used to give light, now doesn't, or vice versa, or light's range has changed */ if (emits_light(olddata)) del_light_source(LS_MONSTER, monst_to_any(mtmp)); if (emits_light(mtmp->data)) new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data), LS_MONSTER, monst_to_any(mtmp)); } if (!mtmp->perminvis || pm_invisible(olddata)) mtmp->perminvis = pm_invisible(mdat); mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis; if (mtmp->mundetected) (void) hideunder(mtmp); if (u.ustuck == mtmp) { if (u.uswallow) { if (!attacktype(mdat, AT_ENGL)) { /* Does mdat care? */ if (!noncorporeal(mdat) && !amorphous(mdat) && !is_whirly(mdat) && (mdat != &mons[PM_YELLOW_LIGHT])) { You("break out of %s%s!", mon_nam(mtmp), (is_animal(mdat) ? "'s stomach" : "")); mtmp->mhp = 1; /* almost dead */ } expels(mtmp, olddata, FALSE); } else { /* update swallow glyphs for new monster */ swallowed(0); } } else if (!sticks(mdat) && !sticks(youmonst.data)) unstuck(mtmp); } #ifndef DCC30_BUG if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) { #else /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the * same expression. */ if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) { #endif /* we can now create worms with tails - 11/91 */ initworm(mtmp, rn2(5)); if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my); } newsym(mtmp->mx, mtmp->my); if (msg) { char *save_mname = 0; if (has_mname(mtmp)) { save_mname = MNAME(mtmp); MNAME(mtmp) = (char *) 0; } Strcpy(newname, (mdat == &mons[PM_GREEN_SLIME]) ? "slime" : x_monnam(mtmp, ARTICLE_A, (char *) 0, SUPPRESS_SADDLE, FALSE)); if (!strcmpi(oldname, "it") && !strcmpi(newname, "it")) (void) usmellmon(mdat); else pline("%s turns into %s!", oldname, newname); if (save_mname) MNAME(mtmp) = save_mname; } possibly_unwield(mtmp, polyspot); /* might lose use of weapon */ mon_break_armor(mtmp, polyspot); if (!(mtmp->misc_worn_check & W_ARMG)) mselftouch(mtmp, "No longer petrify-resistant, ", !context.mon_moving); m_dowear(mtmp, FALSE); /* This ought to re-test can_carry() on each item in the inventory * rather than just checking ex-giants & boulders, but that'd be * pretty expensive to perform. If implemented, then perhaps * minvent should be sorted in order to drop heaviest items first. */ /* former giants can't continue carrying boulders */ if (mtmp->minvent && !throws_rocks(mdat)) { register struct obj *otmp, *otmp2; for (otmp = mtmp->minvent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->otyp == BOULDER) { /* this keeps otmp from being polymorphed in the same zap that the monster that held it is polymorphed */ if (polyspot) bypass_obj(otmp); obj_extract_self(otmp); /* probably ought to give some "drop" message here */ if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue; place_object(otmp, mtmp->mx, mtmp->my); } } } return 1; } /* sometimes an egg will be special */ #define BREEDER_EGG (!rn2(77)) /* * Determine if the given monster number can be hatched from an egg. * Return the monster number to use as the egg's corpsenm. Return * NON_PM if the given monster can't be hatched. */ int can_be_hatched(mnum) int mnum; { /* ranger quest nemesis has the oviparous bit set, making it be possible to wish for eggs of that unique monster; turn such into ordinary eggs rather than forbidding them outright */ if (mnum == PM_SCORPIUS) mnum = PM_SCORPION; mnum = little_to_big(mnum); /* * Queen bees lay killer bee eggs (usually), but killer bees don't * grow into queen bees. Ditto for [winged-]gargoyles. */ if (mnum == PM_KILLER_BEE || mnum == PM_GARGOYLE || (lays_eggs(&mons[mnum]) && (BREEDER_EGG || (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE)))) return mnum; return NON_PM; } /* type of egg laid by #sit; usually matches parent */ int egg_type_from_parent(mnum, force_ordinary) int mnum; /* parent monster; caller must handle lays_eggs() check */ boolean force_ordinary; { if (force_ordinary || !BREEDER_EGG) { if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE; else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE; } return mnum; } /* decide whether an egg of the indicated monster type is viable; also used to determine whether an egg or tin can be created... */ boolean dead_species(m_idx, egg) int m_idx; boolean egg; { int alt_idx; /* generic eggs are unhatchable and have corpsenm of NON_PM */ if (m_idx < LOW_PM) return TRUE; /* * For monsters with both baby and adult forms, genociding either * form kills all eggs of that monster. Monsters with more than * two forms (small->large->giant mimics) are more or less ignored; * fortunately, none of them have eggs. Species extinction due to * overpopulation does not kill eggs. */ alt_idx = egg ? big_to_little(m_idx) : m_idx; return (boolean) ((mvitals[m_idx].mvflags & G_GENOD) != 0 || (mvitals[alt_idx].mvflags & G_GENOD) != 0); } /* kill off any eggs of genocided monsters */ STATIC_OVL void kill_eggs(obj_list) struct obj *obj_list; { struct obj *otmp; for (otmp = obj_list; otmp; otmp = otmp->nobj) if (otmp->otyp == EGG) { if (dead_species(otmp->corpsenm, TRUE)) { /* * It seems we could also just catch this when * it attempted to hatch, so we wouldn't have to * search all of the objlists.. or stop all * hatch timers based on a corpsenm. */ kill_egg(otmp); } #if 0 /* not used */ } else if (otmp->otyp == TIN) { if (dead_species(otmp->corpsenm, FALSE)) otmp->corpsenm = NON_PM; /* empty tin */ } else if (otmp->otyp == CORPSE) { if (dead_species(otmp->corpsenm, FALSE)) ; /* not yet implemented... */ #endif } else if (Has_contents(otmp)) { kill_eggs(otmp->cobj); } } /* kill all members of genocided species */ void kill_genocided_monsters() { struct monst *mtmp, *mtmp2; boolean kill_cham; int mndx; /* * Called during genocide, and again upon level change. The latter * catches up with any migrating monsters as they finally arrive at * their intended destinations, so possessions get deposited there. * * Chameleon handling: * 1) if chameleons have been genocided, destroy them * regardless of current form; * 2) otherwise, force every chameleon which is imitating * any genocided species to take on a new form. */ for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; mndx = monsndx(mtmp->data); kill_cham = (mtmp->cham >= LOW_PM && (mvitals[mtmp->cham].mvflags & G_GENOD)); if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham) { if (mtmp->cham >= LOW_PM && !kill_cham) (void) newcham(mtmp, (struct permonst *) 0, FALSE, FALSE); else mondead(mtmp); } if (mtmp->minvent) kill_eggs(mtmp->minvent); } kill_eggs(invent); kill_eggs(fobj); kill_eggs(migrating_objs); kill_eggs(level.buriedobjlist); } void golemeffects(mon, damtype, dam) register struct monst *mon; int damtype, dam; { int heal = 0, slow = 0; if (mon->data == &mons[PM_FLESH_GOLEM]) { if (damtype == AD_ELEC) heal = (dam + 5) / 6; else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1; } else if (mon->data == &mons[PM_IRON_GOLEM]) { if (damtype == AD_ELEC) slow = 1; else if (damtype == AD_FIRE) heal = dam; } else { return; } if (slow) { if (mon->mspeed != MSLOW) mon_adjust_speed(mon, -1, (struct obj *) 0); } if (heal) { if (mon->mhp < mon->mhpmax) { mon->mhp += heal; if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (cansee(mon->mx, mon->my)) pline("%s seems healthier.", Monnam(mon)); } } } boolean angry_guards(silent) boolean silent; { struct monst *mtmp; int ct = 0, nct = 0, sct = 0, slct = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data) && mtmp->mpeaceful) { ct++; if (cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) { if (distu(mtmp->mx, mtmp->my) == 2) nct++; else sct++; } if (mtmp->msleeping || mtmp->mfrozen) { slct++; mtmp->msleeping = mtmp->mfrozen = 0; } mtmp->mpeaceful = 0; } } if (ct) { if (!silent) { /* do we want pline msgs? */ if (slct) pline_The("guard%s wake%s up!", slct > 1 ? "s" : "", slct == 1 ? "s" : ""); if (nct || sct) { if (nct) pline_The("guard%s get%s angry!", nct == 1 ? "" : "s", nct == 1 ? "s" : ""); else if (!Blind) You_see("%sangry guard%s approaching!", sct == 1 ? "an " : "", sct > 1 ? "s" : ""); } else You_hear("the shrill sound of a guard's whistle."); } return TRUE; } return FALSE; } void pacify_guards() { struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data)) mtmp->mpeaceful = 1; } } void mimic_hit_msg(mtmp, otyp) struct monst *mtmp; short otyp; { short ap = mtmp->mappearance; switch (mtmp->m_ap_type) { case M_AP_NOTHING: case M_AP_FURNITURE: case M_AP_MONSTER: break; case M_AP_OBJECT: if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) { pline("%s seems a more vivid %s than before.", The(simple_typename(ap)), c_obj_colors[objects[ap].oc_color]); } break; } } boolean usmellmon(mdat) struct permonst *mdat; { int mndx; boolean nonspecific = FALSE; boolean msg_given = FALSE; if (mdat) { if (!olfaction(youmonst.data)) return FALSE; mndx = monsndx(mdat); switch (mndx) { case PM_ROTHE: case PM_MINOTAUR: You("notice a bovine smell."); msg_given = TRUE; break; case PM_CAVEMAN: case PM_CAVEWOMAN: case PM_BARBARIAN: case PM_NEANDERTHAL: You("smell body odor."); msg_given = TRUE; break; /* case PM_PESTILENCE: case PM_FAMINE: case PM_DEATH: break; */ case PM_HORNED_DEVIL: case PM_BALROG: case PM_ASMODEUS: case PM_DISPATER: case PM_YEENOGHU: case PM_ORCUS: break; case PM_HUMAN_WEREJACKAL: case PM_HUMAN_WERERAT: case PM_HUMAN_WEREWOLF: case PM_WEREJACKAL: case PM_WERERAT: case PM_WEREWOLF: case PM_OWLBEAR: You("detect an odor reminiscent of an animal's den."); msg_given = TRUE; break; /* case PM_PURPLE_WORM: break; */ case PM_STEAM_VORTEX: You("smell steam."); msg_given = TRUE; break; case PM_GREEN_SLIME: pline("%s stinks.", Something); msg_given = TRUE; break; case PM_VIOLET_FUNGUS: case PM_SHRIEKER: You("smell mushrooms."); msg_given = TRUE; break; /* These are here to avoid triggering the nonspecific treatment through the default case below*/ case PM_WHITE_UNICORN: case PM_GRAY_UNICORN: case PM_BLACK_UNICORN: case PM_JELLYFISH: break; default: nonspecific = TRUE; break; } if (nonspecific) switch (mdat->mlet) { case S_DOG: You("notice a dog smell."); msg_given = TRUE; break; case S_DRAGON: You("smell a dragon!"); msg_given = TRUE; break; case S_FUNGUS: pline("%s smells moldy.", Something); msg_given = TRUE; break; case S_UNICORN: You("detect a%s odor reminiscent of a stable.", (mndx == PM_PONY) ? "n" : " strong"); msg_given = TRUE; break; case S_ZOMBIE: You("smell rotting flesh."); msg_given = TRUE; break; case S_EEL: You("smell fish."); msg_given = TRUE; break; case S_ORC: if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) You("notice an attractive smell."); else pline("A foul stench makes you feel a little nauseated."); msg_given = TRUE; break; default: break; } } return msg_given ? TRUE : FALSE; } /*mon.c*/ nethack-3.6.0/src/mondata.c0000664000076400007660000010676712616314177014544 0ustar paxedpaxed/* NetHack 3.6 mondata.c $NHDT-Date: 1446604115 2015/11/04 02:28:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.58 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* These routines provide basic data for any type of monster. */ /* set up an individual monster's base type (initial creation, shapechange) */ void set_mon_data(mon, ptr, flag) struct monst *mon; struct permonst *ptr; int flag; { mon->data = ptr; if (flag == -1) return; /* "don't care" */ if (flag == 1) mon->mintrinsics |= (ptr->mresists & 0x00FF); else mon->mintrinsics = (ptr->mresists & 0x00FF); return; } /* does monster-type have any attack for a specific type of damage? */ struct attack * attacktype_fordmg(ptr, atyp, dtyp) struct permonst *ptr; int atyp, dtyp; { struct attack *a; for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++) if (a->aatyp == atyp && (dtyp == AD_ANY || a->adtyp == dtyp)) return a; return (struct attack *) 0; } /* does monster-type have a particular type of attack */ boolean attacktype(ptr, atyp) struct permonst *ptr; int atyp; { return attacktype_fordmg(ptr, atyp, AD_ANY) ? TRUE : FALSE; } /* returns True if monster doesn't attack, False if it does */ boolean noattacks(ptr) struct permonst *ptr; { int i; struct attack *mattk = ptr->mattk; for (i = 0; i < NATTK; i++) { /* AT_BOOM "passive attack" (gas spore's explosion upon death) isn't an attack as far as our callers are concerned */ if (mattk[i].aatyp == AT_BOOM) continue; if (mattk[i].aatyp) return FALSE; } return TRUE; } /* does monster-type transform into something else when petrified? */ boolean poly_when_stoned(ptr) struct permonst *ptr; { /* non-stone golems turn into stone golems unless latter is genocided */ return (boolean) (is_golem(ptr) && ptr != &mons[PM_STONE_GOLEM] && !(mvitals[PM_STONE_GOLEM].mvflags & G_GENOD)); /* allow G_EXTINCT */ } /* returns True if monster is drain-life resistant */ boolean resists_drli(mon) struct monst *mon; { struct permonst *ptr = mon->data; struct obj *wep; if (is_undead(ptr) || is_demon(ptr) || is_were(ptr) /* is_were() doesn't handle hero in human form */ || (mon == &youmonst && u.ulycn >= LOW_PM) || ptr == &mons[PM_DEATH] || is_vampshifter(mon)) return TRUE; wep = (mon == &youmonst) ? uwep : MON_WEP(mon); return (boolean) (wep && wep->oartifact && defends(AD_DRLI, wep)); } /* True if monster is magic-missile (actually, general magic) resistant */ boolean resists_magm(mon) struct monst *mon; { struct permonst *ptr = mon->data; boolean is_you = (mon == &youmonst); long slotmask; struct obj *o; /* as of 3.2.0: gray dragons, Angels, Oracle, Yeenoghu */ if (dmgtype(ptr, AD_MAGM) || ptr == &mons[PM_BABY_GRAY_DRAGON] || dmgtype(ptr, AD_RBRE)) /* Chromatic Dragon */ return TRUE; /* check for magic resistance granted by wielded weapon */ o = is_you ? uwep : MON_WEP(mon); if (o && o->oartifact && defends(AD_MAGM, o)) return TRUE; /* check for magic resistance granted by worn or carried items */ o = is_you ? invent : mon->minvent; slotmask = W_ARMOR | W_ACCESSORY; if (!is_you /* assumes monsters don't wield non-weapons */ || (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))) slotmask |= W_WEP; if (is_you && u.twoweap) slotmask |= W_SWAPWEP; for (; o; o = o->nobj) if (((o->owornmask & slotmask) != 0L && objects[o->otyp].oc_oprop == ANTIMAGIC) || (o->oartifact && defends_when_carried(AD_MAGM, o))) return TRUE; return FALSE; } /* True iff monster is resistant to light-induced blindness */ boolean resists_blnd(mon) struct monst *mon; { struct permonst *ptr = mon->data; boolean is_you = (mon == &youmonst); long slotmask; struct obj *o; if (is_you ? (Blind || Unaware) : (mon->mblinded || !mon->mcansee || !haseyes(ptr) /* BUG: temporary sleep sets mfrozen, but since paralysis does too, we can't check it */ || mon->msleeping)) return TRUE; /* yellow light, Archon; !dust vortex, !cobra, !raven */ if (dmgtype_fromattack(ptr, AD_BLND, AT_EXPL) || dmgtype_fromattack(ptr, AD_BLND, AT_GAZE)) return TRUE; o = is_you ? uwep : MON_WEP(mon); if (o && o->oartifact && defends(AD_BLND, o)) return TRUE; o = is_you ? invent : mon->minvent; slotmask = W_ARMOR | W_ACCESSORY; if (!is_you /* assumes monsters don't wield non-weapons */ || (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))) slotmask |= W_WEP; if (is_you && u.twoweap) slotmask |= W_SWAPWEP; for (; o; o = o->nobj) if (((o->owornmask & slotmask) != 0L && objects[o->otyp].oc_oprop == BLINDED) || (o->oartifact && defends_when_carried(AD_BLND, o))) return TRUE; return FALSE; } /* True iff monster can be blinded by the given attack; note: may return True when mdef is blind (e.g. new cream-pie attack) */ boolean can_blnd(magr, mdef, aatyp, obj) struct monst *magr; /* NULL == no specific aggressor */ struct monst *mdef; uchar aatyp; struct obj *obj; /* aatyp == AT_WEAP, AT_SPIT */ { boolean is_you = (mdef == &youmonst); boolean check_visor = FALSE; struct obj *o; const char *s; /* no eyes protect against all attacks for now */ if (!haseyes(mdef->data)) return FALSE; switch (aatyp) { case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_MAGC: case AT_BREA: /* assumed to be lightning */ /* light-based attacks may be cancelled or resisted */ if (magr && magr->mcan) return FALSE; return !resists_blnd(mdef); case AT_WEAP: case AT_SPIT: case AT_NONE: /* an object is used (thrown/spit/other) */ if (obj && (obj->otyp == CREAM_PIE)) { if (is_you && Blindfolded) return FALSE; } else if (obj && (obj->otyp == BLINDING_VENOM)) { /* all ublindf, including LENSES, protect, cream-pies too */ if (is_you && (ublindf || u.ucreamed)) return FALSE; check_visor = TRUE; } else if (obj && (obj->otyp == POT_BLINDNESS)) { return TRUE; /* no defense */ } else return FALSE; /* other objects cannot cause blindness yet */ if ((magr == &youmonst) && u.uswallow) return FALSE; /* can't affect eyes while inside monster */ break; case AT_ENGL: if (is_you && (Blindfolded || Unaware || u.ucreamed)) return FALSE; if (!is_you && mdef->msleeping) return FALSE; break; case AT_CLAW: /* e.g. raven: all ublindf, including LENSES, protect */ if (is_you && ublindf) return FALSE; if ((magr == &youmonst) && u.uswallow) return FALSE; /* can't affect eyes while inside monster */ check_visor = TRUE; break; case AT_TUCH: case AT_STNG: /* some physical, blind-inducing attacks can be cancelled */ if (magr && magr->mcan) return FALSE; break; default: break; } /* check if wearing a visor (only checked if visor might help) */ if (check_visor) { o = (mdef == &youmonst) ? invent : mdef->minvent; for (; o; o = o->nobj) if ((o->owornmask & W_ARMH) && (s = OBJ_DESCR(objects[o->otyp])) != (char *) 0 && !strcmp(s, "visored helmet")) return FALSE; } return TRUE; } /* returns True if monster can attack at range */ boolean ranged_attk(ptr) struct permonst *ptr; { register int i, atyp; long atk_mask = (1L << AT_BREA) | (1L << AT_SPIT) | (1L << AT_GAZE); /* was: (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) * || attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) * || attacktype(ptr, AT_MAGC)); * but that's too slow -dlc */ for (i = 0; i < NATTK; i++) { atyp = ptr->mattk[i].aatyp; if (atyp >= AT_WEAP) return TRUE; /* assert(atyp < 32); */ if ((atk_mask & (1L << atyp)) != 0L) return TRUE; } return FALSE; } /* True if specific monster is especially affected by silver weapons */ boolean mon_hates_silver(mon) struct monst *mon; { return (boolean) (is_vampshifter(mon) || hates_silver(mon->data)); } /* True if monster-type is especially affected by silver weapons */ boolean hates_silver(ptr) register struct permonst *ptr; { return (boolean) (is_were(ptr) || ptr->mlet == S_VAMPIRE || is_demon(ptr) || ptr == &mons[PM_SHADE] || (ptr->mlet == S_IMP && ptr != &mons[PM_TENGU])); } /* True iff the type of monster pass through iron bars */ boolean passes_bars(mptr) struct permonst *mptr; { return (boolean) (passes_walls(mptr) || amorphous(mptr) || unsolid(mptr) || is_whirly(mptr) || verysmall(mptr) || dmgtype(mptr, AD_CORR) || dmgtype(mptr, AD_RUST) || (slithy(mptr) && !bigmonst(mptr))); } /* returns True if monster can blow (whistle, etc) */ boolean can_blow(mtmp) register struct monst *mtmp; { if ((is_silent(mtmp->data) || mtmp->data->msound == MS_BUZZ) && (breathless(mtmp->data) || verysmall(mtmp->data) || !has_head(mtmp->data) || mtmp->data->mlet == S_EEL)) return FALSE; if ((mtmp == &youmonst) && Strangled) return FALSE; return TRUE; } /* True if mon is vulnerable to strangulation */ boolean can_be_strangled(mon) struct monst *mon; { struct obj *mamul; boolean nonbreathing, nobrainer; /* For amulet of strangulation support: here we're considering strangulation to be loss of blood flow to the brain due to constriction of the arteries in the neck, so all headless creatures are immune (no neck) as are mindless creatures who don't need to breathe (brain, if any, doesn't care). Mindless creatures who do need to breath are vulnerable, as are non-breathing creatures which have higher brain function. */ if (!has_head(mon->data)) return FALSE; if (mon == &youmonst) { /* hero can't be mindless but poly'ing into mindless form can confer strangulation protection */ nobrainer = mindless(youmonst.data); nonbreathing = Breathless; } else { nobrainer = mindless(mon->data); /* monsters don't wear amulets of magical breathing, so second part doesn't achieve anything useful... */ nonbreathing = (breathless(mon->data) || ((mamul = which_armor(mon, W_AMUL)) != 0 && (mamul->otyp == AMULET_OF_MAGICAL_BREATHING))); } return (boolean) (!nobrainer || !nonbreathing); } /* returns True if monster can track well */ boolean can_track(ptr) register struct permonst *ptr; { if (uwep && uwep->oartifact == ART_EXCALIBUR) return TRUE; else return (boolean) haseyes(ptr); } /* creature will slide out of armor */ boolean sliparm(ptr) register struct permonst *ptr; { return (boolean) (is_whirly(ptr) || ptr->msize <= MZ_SMALL || noncorporeal(ptr)); } /* creature will break out of armor */ boolean breakarm(ptr) register struct permonst *ptr; { if (sliparm(ptr)) return FALSE; return (boolean) (bigmonst(ptr) || (ptr->msize > MZ_SMALL && !humanoid(ptr)) /* special cases of humanoids that cannot wear suits */ || ptr == &mons[PM_MARILITH] || ptr == &mons[PM_WINGED_GARGOYLE]); } /* creature sticks other creatures it hits */ boolean sticks(ptr) register struct permonst *ptr; { return (boolean) (dmgtype(ptr, AD_STCK) || dmgtype(ptr, AD_WRAP) || attacktype(ptr, AT_HUGS)); } /* some monster-types can't vomit */ boolean cantvomit(ptr) struct permonst *ptr; { /* rats and mice are incapable of vomiting; which other creatures have the same limitation? */ if (ptr->mlet == S_RODENT && ptr != &mons[PM_ROCK_MOLE] && ptr != &mons[PM_WOODCHUCK]) return TRUE; return FALSE; } /* number of horns this type of monster has on its head */ int num_horns(ptr) struct permonst *ptr; { switch (monsndx(ptr)) { case PM_HORNED_DEVIL: /* ? "more than one" */ case PM_MINOTAUR: case PM_ASMODEUS: case PM_BALROG: return 2; case PM_WHITE_UNICORN: case PM_GRAY_UNICORN: case PM_BLACK_UNICORN: case PM_KI_RIN: return 1; default: break; } return 0; } /* does monster-type deal out a particular type of damage from a particular type of attack? */ struct attack * dmgtype_fromattack(ptr, dtyp, atyp) struct permonst *ptr; int dtyp, atyp; { struct attack *a; for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++) if (a->adtyp == dtyp && (atyp == AT_ANY || a->aatyp == atyp)) return a; return (struct attack *) 0; } /* does monster-type deal out a particular type of damage from any attack */ boolean dmgtype(ptr, dtyp) struct permonst *ptr; int dtyp; { return dmgtype_fromattack(ptr, dtyp, AT_ANY) ? TRUE : FALSE; } /* returns the maximum damage a defender can do to the attacker via a passive defense */ int max_passive_dmg(mdef, magr) register struct monst *mdef, *magr; { int i, dmg = 0, multi2 = 0; uchar adtyp; /* each attack by magr can result in passive damage */ for (i = 0; i < NATTK; i++) switch (magr->data->mattk[i].aatyp) { case AT_CLAW: case AT_BITE: case AT_KICK: case AT_BUTT: case AT_TUCH: case AT_STNG: case AT_HUGS: case AT_ENGL: case AT_TENT: case AT_WEAP: multi2++; break; default: break; } for (i = 0; i < NATTK; i++) if (mdef->data->mattk[i].aatyp == AT_NONE || mdef->data->mattk[i].aatyp == AT_BOOM) { adtyp = mdef->data->mattk[i].adtyp; if ((adtyp == AD_ACID && !resists_acid(magr)) || (adtyp == AD_COLD && !resists_cold(magr)) || (adtyp == AD_FIRE && !resists_fire(magr)) || (adtyp == AD_ELEC && !resists_elec(magr)) || adtyp == AD_PHYS) { dmg = mdef->data->mattk[i].damn; if (!dmg) dmg = mdef->data->mlevel + 1; dmg *= mdef->data->mattk[i].damd; } else dmg = 0; return dmg * multi2; } return 0; } /* determine whether two monster types are from the same species */ boolean same_race(pm1, pm2) struct permonst *pm1, *pm2; { char let1 = pm1->mlet, let2 = pm2->mlet; if (pm1 == pm2) return TRUE; /* exact match */ /* player races have their own predicates */ if (is_human(pm1)) return is_human(pm2); if (is_elf(pm1)) return is_elf(pm2); if (is_dwarf(pm1)) return is_dwarf(pm2); if (is_gnome(pm1)) return is_gnome(pm2); if (is_orc(pm1)) return is_orc(pm2); /* other creatures are less precise */ if (is_giant(pm1)) return is_giant(pm2); /* open to quibbling here */ if (is_golem(pm1)) return is_golem(pm2); /* even moreso... */ if (is_mind_flayer(pm1)) return is_mind_flayer(pm2); if (let1 == S_KOBOLD || pm1 == &mons[PM_KOBOLD_ZOMBIE] || pm1 == &mons[PM_KOBOLD_MUMMY]) return (let2 == S_KOBOLD || pm2 == &mons[PM_KOBOLD_ZOMBIE] || pm2 == &mons[PM_KOBOLD_MUMMY]); if (let1 == S_OGRE) return (let2 == S_OGRE); if (let1 == S_NYMPH) return (let2 == S_NYMPH); if (let1 == S_CENTAUR) return (let2 == S_CENTAUR); if (is_unicorn(pm1)) return is_unicorn(pm2); if (let1 == S_DRAGON) return (let2 == S_DRAGON); if (let1 == S_NAGA) return (let2 == S_NAGA); /* other critters get steadily messier */ if (is_rider(pm1)) return is_rider(pm2); /* debatable */ if (is_minion(pm1)) return is_minion(pm2); /* [needs work?] */ /* tengu don't match imps (first test handled case of both being tengu) */ if (pm1 == &mons[PM_TENGU] || pm2 == &mons[PM_TENGU]) return FALSE; if (let1 == S_IMP) return (let2 == S_IMP); /* and minor demons (imps) don't match major demons */ else if (let2 == S_IMP) return FALSE; if (is_demon(pm1)) return is_demon(pm2); if (is_undead(pm1)) { if (let1 == S_ZOMBIE) return (let2 == S_ZOMBIE); if (let1 == S_MUMMY) return (let2 == S_MUMMY); if (let1 == S_VAMPIRE) return (let2 == S_VAMPIRE); if (let1 == S_LICH) return (let2 == S_LICH); if (let1 == S_WRAITH) return (let2 == S_WRAITH); if (let1 == S_GHOST) return (let2 == S_GHOST); } else if (is_undead(pm2)) return FALSE; /* check for monsters which grow into more mature forms */ if (let1 == let2) { int m1 = monsndx(pm1), m2 = monsndx(pm2), prv, nxt; /* we know m1 != m2 (very first check above); test all smaller forms of m1 against m2, then all larger ones; don't need to make the corresponding tests for variants of m2 against m1 */ for (prv = m1, nxt = big_to_little(m1); nxt != prv; prv = nxt, nxt = big_to_little(nxt)) if (nxt == m2) return TRUE; for (prv = m1, nxt = little_to_big(m1); nxt != prv; prv = nxt, nxt = little_to_big(nxt)) if (nxt == m2) return TRUE; } /* not caught by little/big handling */ if (pm1 == &mons[PM_GARGOYLE] || pm1 == &mons[PM_WINGED_GARGOYLE]) return (pm2 == &mons[PM_GARGOYLE] || pm2 == &mons[PM_WINGED_GARGOYLE]); if (pm1 == &mons[PM_KILLER_BEE] || pm1 == &mons[PM_QUEEN_BEE]) return (pm2 == &mons[PM_KILLER_BEE] || pm2 == &mons[PM_QUEEN_BEE]); if (is_longworm(pm1)) return is_longworm(pm2); /* handles tail */ /* [currently there's no reason to bother matching up assorted bugs and blobs with their closest variants] */ /* didn't match */ return FALSE; } /* return an index into the mons array */ int monsndx(ptr) struct permonst *ptr; { register int i; i = (int) (ptr - &mons[0]); if (i < LOW_PM || i >= NUMMONS) { panic("monsndx - could not index monster (%s)", fmt_ptr((genericptr_t) ptr)); return NON_PM; /* will not get here */ } return i; } /* for handling alternate spellings */ struct alt_spl { const char *name; short pm_val; }; /* figure out what type of monster a user-supplied string is specifying */ int name_to_mon(in_str) const char *in_str; { /* Be careful. We must check the entire string in case it was * something such as "ettin zombie corpse". The calling routine * doesn't know about the "corpse" until the monster name has * already been taken off the front, so we have to be able to * read the name with extraneous stuff such as "corpse" stuck on * the end. * This causes a problem for names which prefix other names such * as "ettin" on "ettin zombie". In this case we want the _longest_ * name which exists. * This also permits plurals created by adding suffixes such as 's' * or 'es'. Other plurals must still be handled explicitly. */ register int i; register int mntmp = NON_PM; register char *s, *str, *term; char buf[BUFSZ]; int len, slen; str = strcpy(buf, in_str); if (!strncmp(str, "a ", 2)) str += 2; else if (!strncmp(str, "an ", 3)) str += 3; else if (!strncmp(str, "the ", 4)) str += 4; slen = strlen(str); term = str + slen; if ((s = strstri(str, "vortices")) != 0) Strcpy(s + 4, "ex"); /* be careful with "ies"; "priest", "zombies" */ else if (slen > 3 && !strcmpi(term - 3, "ies") && (slen < 7 || strcmpi(term - 7, "zombies"))) Strcpy(term - 3, "y"); /* luckily no monster names end in fe or ve with ves plurals */ else if (slen > 3 && !strcmpi(term - 3, "ves")) Strcpy(term - 3, "f"); slen = strlen(str); /* length possibly needs recomputing */ { static const struct alt_spl names[] = { /* Alternate spellings */ { "grey dragon", PM_GRAY_DRAGON }, { "baby grey dragon", PM_BABY_GRAY_DRAGON }, { "grey unicorn", PM_GRAY_UNICORN }, { "grey ooze", PM_GRAY_OOZE }, { "gray-elf", PM_GREY_ELF }, { "mindflayer", PM_MIND_FLAYER }, { "master mindflayer", PM_MASTER_MIND_FLAYER }, /* More alternates; priest and priestess are separate monster types but that isn't the case for {aligned,high} priests */ { "aligned priestess", PM_ALIGNED_PRIEST }, { "high priestess", PM_HIGH_PRIEST }, /* Inappropriate singularization by -ves check above */ { "master of thief", PM_MASTER_OF_THIEVES }, /* Potential misspellings where we want to avoid falling back to the rank title prefix (input has been singularized) */ { "master thief", PM_MASTER_OF_THIEVES }, { "master of assassin", PM_MASTER_ASSASSIN }, /* Outdated names */ { "invisible stalker", PM_STALKER }, { "high-elf", PM_ELVENKING }, /* PM_HIGH_ELF is obsolete */ { "halfling", PM_HOBBIT }, /* potential guess for polyself */ /* Hyphenated names */ { "ki rin", PM_KI_RIN }, { "uruk hai", PM_URUK_HAI }, { "orc captain", PM_ORC_CAPTAIN }, { "woodland elf", PM_WOODLAND_ELF }, { "green elf", PM_GREEN_ELF }, { "grey elf", PM_GREY_ELF }, { "gray elf", PM_GREY_ELF }, { "elf lord", PM_ELF_LORD }, { "olog hai", PM_OLOG_HAI }, { "arch lich", PM_ARCH_LICH }, /* Some irregular plurals */ { "incubi", PM_INCUBUS }, { "succubi", PM_SUCCUBUS }, { "violet fungi", PM_VIOLET_FUNGUS }, { "homunculi", PM_HOMUNCULUS }, { "baluchitheria", PM_BALUCHITHERIUM }, { "lurkers above", PM_LURKER_ABOVE }, { "cavemen", PM_CAVEMAN }, { "cavewomen", PM_CAVEWOMAN }, { "djinn", PM_DJINNI }, { "mumakil", PM_MUMAK }, { "erinyes", PM_ERINYS }, /* end of list */ { 0, NON_PM } }; register const struct alt_spl *namep; for (namep = names; namep->name; namep++) if (!strncmpi(str, namep->name, (int) strlen(namep->name))) return namep->pm_val; } for (len = 0, i = LOW_PM; i < NUMMONS; i++) { register int m_i_len = strlen(mons[i].mname); if (m_i_len > len && !strncmpi(mons[i].mname, str, m_i_len)) { if (m_i_len == slen) { return i; /* exact match */ } else if (slen > m_i_len && (str[m_i_len] == ' ' || !strcmpi(&str[m_i_len], "s") || !strncmpi(&str[m_i_len], "s ", 2) || !strcmpi(&str[m_i_len], "'") || !strncmpi(&str[m_i_len], "' ", 2) || !strcmpi(&str[m_i_len], "'s") || !strncmpi(&str[m_i_len], "'s ", 3) || !strcmpi(&str[m_i_len], "es") || !strncmpi(&str[m_i_len], "es ", 3))) { mntmp = i; len = m_i_len; } } } if (mntmp == NON_PM) mntmp = title_to_mon(str, (int *) 0, (int *) 0); return mntmp; } /* monster class from user input; used for genocide and controlled polymorph; returns 0 rather than MAXMCLASSES if no match is found */ int name_to_monclass(in_str, mndx_p) const char *in_str; int *mndx_p; { /* Single letters are matched against def_monsyms[].sym; words or phrases are first matched against def_monsyms[].explain to check class description; if not found there, then against mons[].mname to test individual monster types. Input can be a substring of the full description or mname, but to be accepted, such partial matches must start at beginning of a word. Some class descriptions include "foo or bar" and "foo or other foo" so we don't want to accept "or", "other", "or other" there. */ static NEARDATA const char *const falsematch[] = { /* multiple-letter input which matches any of these gets rejected */ "an", "the", "or", "other", "or other", 0 }; /* positive pm_val => specific monster; negative => class */ static NEARDATA const struct alt_spl truematch[] = { /* "long worm" won't match "worm" class but would accidentally match "long worm tail" class before the comparison with monster types */ { "long worm", PM_LONG_WORM }, /* matches wrong--or at least suboptimal--class */ { "demon", -S_DEMON }, /* hits "imp or minor demon" */ /* matches specific monster (overly restrictive) */ { "devil", -S_DEMON }, /* always "horned devil" */ /* some plausible guesses which need help */ { "bug", -S_XAN }, /* would match bugbear... */ { "fish", -S_EEL }, /* wouldn't match anything */ /* end of list */ { 0, NON_PM } }; const char *p, *x; int i; if (mndx_p) *mndx_p = NON_PM; /* haven't [yet] matched a specific type */ if (!in_str || !in_str[0]) { /* empty input */ return 0; } else if (!in_str[1]) { /* single character */ i = def_char_to_monclass(*in_str); if (i == S_MIMIC_DEF) { /* ']' -> 'm' */ i = S_MIMIC; } else if (i == S_WORM_TAIL) { /* '~' -> 'w' */ i = S_WORM; if (mndx_p) *mndx_p = PM_LONG_WORM; } else if (i == MAXMCLASSES) /* maybe 'I' */ i = (*in_str == DEF_INVISIBLE) ? S_invisible : 0; return i; } else { /* multiple characters */ in_str = makesingular(in_str); /* check for special cases */ for (i = 0; falsematch[i]; i++) if (!strcmpi(in_str, falsematch[i])) return 0; for (i = 0; truematch[i].name; i++) if (!strcmpi(in_str, truematch[i].name)) { i = truematch[i].pm_val; if (i < 0) return -i; /* class */ if (mndx_p) *mndx_p = i; /* monster */ return mons[i].mlet; } /* check monster class descriptions */ for (i = 1; i < MAXMCLASSES; i++) { x = def_monsyms[i].explain; if ((p = strstri(x, in_str)) != 0 && (p == x || *(p - 1) == ' ')) return i; } /* check individual species names; not as thorough as mon_to_name() but our caller can call that directly if desired */ for (i = LOW_PM; i < NUMMONS; i++) { x = mons[i].mname; if ((p = strstri(x, in_str)) != 0 && (p == x || *(p - 1) == ' ')) { if (mndx_p) *mndx_p = i; return mons[i].mlet; } } } return 0; } /* returns 3 values (0=male, 1=female, 2=none) */ int gender(mtmp) register struct monst *mtmp; { if (is_neuter(mtmp->data)) return 2; return mtmp->female; } /* Like gender(), but lower animals and such are still "it". This is the one we want to use when printing messages. */ int pronoun_gender(mtmp) register struct monst *mtmp; { if (is_neuter(mtmp->data) || !canspotmon(mtmp)) return 2; return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) || type_is_pname(mtmp->data)) ? (int) mtmp->female : 2; } /* used for nearby monsters when you go to another level */ boolean levl_follower(mtmp) struct monst *mtmp; { if (mtmp == u.usteed) return TRUE; /* Wizard with Amulet won't bother trying to follow across levels */ if (mtmp->iswiz && mon_has_amulet(mtmp)) return FALSE; /* some monsters will follow even while intending to flee from you */ if (mtmp->mtame || mtmp->iswiz || is_fshk(mtmp)) return TRUE; /* stalking types follow, but won't when fleeing unless you hold the Amulet */ return (boolean) ((mtmp->data->mflags2 & M2_STALK) && (!mtmp->mflee || u.uhave.amulet)); } static const short grownups[][2] = { { PM_CHICKATRICE, PM_COCKATRICE }, { PM_LITTLE_DOG, PM_DOG }, { PM_DOG, PM_LARGE_DOG }, { PM_HELL_HOUND_PUP, PM_HELL_HOUND }, { PM_WINTER_WOLF_CUB, PM_WINTER_WOLF }, { PM_KITTEN, PM_HOUSECAT }, { PM_HOUSECAT, PM_LARGE_CAT }, { PM_PONY, PM_HORSE }, { PM_HORSE, PM_WARHORSE }, { PM_KOBOLD, PM_LARGE_KOBOLD }, { PM_LARGE_KOBOLD, PM_KOBOLD_LORD }, { PM_GNOME, PM_GNOME_LORD }, { PM_GNOME_LORD, PM_GNOME_KING }, { PM_DWARF, PM_DWARF_LORD }, { PM_DWARF_LORD, PM_DWARF_KING }, { PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER }, { PM_ORC, PM_ORC_CAPTAIN }, { PM_HILL_ORC, PM_ORC_CAPTAIN }, { PM_MORDOR_ORC, PM_ORC_CAPTAIN }, { PM_URUK_HAI, PM_ORC_CAPTAIN }, { PM_SEWER_RAT, PM_GIANT_RAT }, { PM_CAVE_SPIDER, PM_GIANT_SPIDER }, { PM_OGRE, PM_OGRE_LORD }, { PM_OGRE_LORD, PM_OGRE_KING }, { PM_ELF, PM_ELF_LORD }, { PM_WOODLAND_ELF, PM_ELF_LORD }, { PM_GREEN_ELF, PM_ELF_LORD }, { PM_GREY_ELF, PM_ELF_LORD }, { PM_ELF_LORD, PM_ELVENKING }, { PM_LICH, PM_DEMILICH }, { PM_DEMILICH, PM_MASTER_LICH }, { PM_MASTER_LICH, PM_ARCH_LICH }, { PM_VAMPIRE, PM_VAMPIRE_LORD }, { PM_BAT, PM_GIANT_BAT }, { PM_BABY_GRAY_DRAGON, PM_GRAY_DRAGON }, { PM_BABY_SILVER_DRAGON, PM_SILVER_DRAGON }, #if 0 /* DEFERRED */ {PM_BABY_SHIMMERING_DRAGON, PM_SHIMMERING_DRAGON}, #endif { PM_BABY_RED_DRAGON, PM_RED_DRAGON }, { PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON }, { PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON }, { PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON }, { PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON }, { PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON }, { PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON }, { PM_RED_NAGA_HATCHLING, PM_RED_NAGA }, { PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA }, { PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA }, { PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA }, { PM_SMALL_MIMIC, PM_LARGE_MIMIC }, { PM_LARGE_MIMIC, PM_GIANT_MIMIC }, { PM_BABY_LONG_WORM, PM_LONG_WORM }, { PM_BABY_PURPLE_WORM, PM_PURPLE_WORM }, { PM_BABY_CROCODILE, PM_CROCODILE }, { PM_SOLDIER, PM_SERGEANT }, { PM_SERGEANT, PM_LIEUTENANT }, { PM_LIEUTENANT, PM_CAPTAIN }, { PM_WATCHMAN, PM_WATCH_CAPTAIN }, { PM_ALIGNED_PRIEST, PM_HIGH_PRIEST }, { PM_STUDENT, PM_ARCHEOLOGIST }, { PM_ATTENDANT, PM_HEALER }, { PM_PAGE, PM_KNIGHT }, { PM_ACOLYTE, PM_PRIEST }, { PM_APPRENTICE, PM_WIZARD }, { PM_MANES, PM_LEMURE }, { PM_KEYSTONE_KOP, PM_KOP_SERGEANT }, { PM_KOP_SERGEANT, PM_KOP_LIEUTENANT }, { PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN }, { NON_PM, NON_PM } }; int little_to_big(montype) int montype; { register int i; for (i = 0; grownups[i][0] >= LOW_PM; i++) if (montype == grownups[i][0]) { montype = grownups[i][1]; break; } return montype; } int big_to_little(montype) int montype; { register int i; for (i = 0; grownups[i][0] >= LOW_PM; i++) if (montype == grownups[i][1]) { montype = grownups[i][0]; break; } return montype; } /* * Return the permonst ptr for the race of the monster. * Returns correct pointer for non-polymorphed and polymorphed * player. It does not return a pointer to player role character. */ const struct permonst * raceptr(mtmp) struct monst *mtmp; { if (mtmp == &youmonst && !Upolyd) return &mons[urace.malenum]; else return mtmp->data; } static const char *levitate[4] = { "float", "Float", "wobble", "Wobble" }; static const char *flys[4] = { "fly", "Fly", "flutter", "Flutter" }; static const char *flyl[4] = { "fly", "Fly", "stagger", "Stagger" }; static const char *slither[4] = { "slither", "Slither", "falter", "Falter" }; static const char *ooze[4] = { "ooze", "Ooze", "tremble", "Tremble" }; static const char *immobile[4] = { "wiggle", "Wiggle", "pulsate", "Pulsate" }; static const char *crawl[4] = { "crawl", "Crawl", "falter", "Falter" }; const char * locomotion(ptr, def) const struct permonst *ptr; const char *def; { int capitalize = (*def == highc(*def)); return (is_floater(ptr) ? levitate[capitalize] : (is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] : (is_flyer(ptr) && ptr->msize > MZ_SMALL) ? flyl[capitalize] : slithy(ptr) ? slither[capitalize] : amorphous(ptr) ? ooze[capitalize] : !ptr->mmove ? immobile[capitalize] : nolimbs(ptr) ? crawl[capitalize] : def); } const char * stagger(ptr, def) const struct permonst *ptr; const char *def; { int capitalize = 2 + (*def == highc(*def)); return (is_floater(ptr) ? levitate[capitalize] : (is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] : (is_flyer(ptr) && ptr->msize > MZ_SMALL) ? flyl[capitalize] : slithy(ptr) ? slither[capitalize] : amorphous(ptr) ? ooze[capitalize] : !ptr->mmove ? immobile[capitalize] : nolimbs(ptr) ? crawl[capitalize] : def); } /* return phrase describing the effect of fire attack on a type of monster */ const char * on_fire(mptr, mattk) struct permonst *mptr; struct attack *mattk; { const char *what; switch (monsndx(mptr)) { case PM_FLAMING_SPHERE: case PM_FIRE_VORTEX: case PM_FIRE_ELEMENTAL: case PM_SALAMANDER: what = "already on fire"; break; case PM_WATER_ELEMENTAL: case PM_FOG_CLOUD: case PM_STEAM_VORTEX: what = "boiling"; break; case PM_ICE_VORTEX: case PM_GLASS_GOLEM: what = "melting"; break; case PM_STONE_GOLEM: case PM_CLAY_GOLEM: case PM_GOLD_GOLEM: case PM_AIR_ELEMENTAL: case PM_EARTH_ELEMENTAL: case PM_DUST_VORTEX: case PM_ENERGY_VORTEX: what = "heating up"; break; default: what = (mattk->aatyp == AT_HUGS) ? "being roasted" : "on fire"; break; } return what; } /* * Returns: * True if monster is presumed to have a sense of smell. * False if monster definitely does not have a sense of smell. * * Do not base this on presence of a head or nose, since many * creatures sense smells other ways (feelers, forked-tongues, etc.) * We're assuming all insects can smell at a distance too. */ boolean olfaction(mdat) struct permonst *mdat; { if (is_golem(mdat) || mdat->mlet == S_EYE /* spheres */ || mdat->mlet == S_JELLY || mdat->mlet == S_PUDDING || mdat->mlet == S_BLOB || mdat->mlet == S_VORTEX || mdat->mlet == S_ELEMENTAL || mdat->mlet == S_FUNGUS /* mushrooms and fungi */ || mdat->mlet == S_LIGHT) return FALSE; return TRUE; } /*mondata.c*/ nethack-3.6.0/src/monmove.c0000664000076400007660000015745412617122742014574 0ustar paxedpaxed/* NetHack 3.6 monmove.c $NHDT-Date: 1446808446 2015/11/06 11:14:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.78 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" #include "artifact.h" extern boolean notonhead; STATIC_DCL void FDECL(watch_on_duty, (struct monst *)); STATIC_DCL int FDECL(disturb, (struct monst *)); STATIC_DCL void FDECL(release_hero, (struct monst *)); STATIC_DCL void FDECL(distfleeck, (struct monst *, int *, int *, int *)); STATIC_DCL int FDECL(m_arrival, (struct monst *)); STATIC_DCL boolean FDECL(stuff_prevents_passage, (struct monst *)); STATIC_DCL int FDECL(vamp_shift, (struct monst *, struct permonst *)); /* True if mtmp died */ boolean mb_trapped(mtmp) struct monst *mtmp; { if (flags.verbose) { if (cansee(mtmp->mx, mtmp->my) && !Unaware) pline("KABOOM!! You see a door explode."); else if (!Deaf) You_hear("a distant explosion."); } wake_nearto(mtmp->mx, mtmp->my, 7 * 7); mtmp->mstun = 1; mtmp->mhp -= rnd(15); if (mtmp->mhp <= 0) { mondied(mtmp); if (mtmp->mhp > 0) /* lifesaved */ return FALSE; else return TRUE; } return FALSE; } /* check whether a monster is carrying a locking/unlocking tool */ boolean monhaskey(mon, for_unlocking) struct monst *mon; boolean for_unlocking; /* true => credit card ok, false => not ok */ { if (for_unlocking && m_carrying(mon, CREDIT_CARD)) return TRUE; return m_carrying(mon, SKELETON_KEY) || m_carrying(mon, LOCK_PICK); } void mon_yells(mon, shout) struct monst *mon; const char *shout; { if (canspotmon(mon)) pline("%s yells:", Amonnam(mon)); else You_hear("someone yell:"); verbalize1(shout); } STATIC_OVL void watch_on_duty(mtmp) register struct monst *mtmp; { int x, y; if (mtmp->mpeaceful && in_town(u.ux + u.dx, u.uy + u.dy) && mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) { if (picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_LOCKED)) { if (couldsee(mtmp->mx, mtmp->my)) { if (levl[x][y].looted & D_WARNED) { mon_yells(mtmp, "Halt, thief! You're under arrest!"); (void) angry_guards(!!Deaf); } else { mon_yells(mtmp, "Hey, stop picking that lock!"); levl[x][y].looted |= D_WARNED; } stop_occupation(); } } else if (is_digging()) { /* chewing, wand/spell of digging are checked elsewhere */ watch_dig(mtmp, context.digging.pos.x, context.digging.pos.y, FALSE); } } } int dochugw(mtmp) register struct monst *mtmp; { int x = mtmp->mx, y = mtmp->my; boolean already_saw_mon = !occupation ? 0 : canspotmon(mtmp); int rd = dochug(mtmp); /* a similar check is in monster_nearby() in hack.c */ /* check whether hero notices monster and stops current activity */ if (occupation && !rd && !Confusion && (!mtmp->mpeaceful || Hallucination) /* it's close enough to be a threat */ && distu(x, y) <= (BOLT_LIM + 1) * (BOLT_LIM + 1) /* and either couldn't see it before, or it was too far away */ && (!already_saw_mon || !couldsee(x, y) || distu(x, y) > (BOLT_LIM + 1) * (BOLT_LIM + 1)) /* can see it now, or sense it and would normally see it */ && (canseemon(mtmp) || (sensemon(mtmp) && couldsee(x, y))) && mtmp->mcanmove && !noattacks(mtmp->data) && !onscary(u.ux, u.uy, mtmp)) stop_occupation(); return rd; } boolean onscary(x, y, mtmp) int x, y; struct monst *mtmp; { boolean epresent = sengr_at("Elbereth", x, y, TRUE); /* creatures who are directly resistant to magical scaring: * Rodney, lawful minions, angels, the Riders */ if (mtmp->iswiz || is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] || is_rider(mtmp->data)) return FALSE; /* should this still be true for defiled/molochian altars? */ if (IS_ALTAR(levl[x][y].typ) && (mtmp->data->mlet == S_VAMPIRE || is_vampshifter(mtmp))) return TRUE; /* the scare monster scroll doesn't have any of the below * restrictions, being its own source of power */ if (sobj_at(SCR_SCARE_MONSTER, x, y)) return TRUE; /* creatures who don't (or can't) fear a written Elbereth: * all the above plus shopkeepers, guards, blind or * peaceful monsters, humans, and minotaurs. * * if the player isn't actually on the square OR the player's image * isn't displaced to the square, no protection is being granted * * Elbereth doesn't work in Gehennom, the Elemental Planes, or the * Astral Plane; the influence of the Valar only reaches so far. */ return (epresent && ((u.ux == x && u.uy == y) || (Displaced && mtmp->mux == x && mtmp->muy == y)) && !(mtmp->isshk || mtmp->isgd || !mtmp->mcansee || mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN || mtmp->data == &mons[PM_MINOTAUR] || Inhell || In_endgame(&u.uz))); } /* regenerate lost hit points */ void mon_regen(mon, digest_meal) struct monst *mon; boolean digest_meal; { if (mon->mhp < mon->mhpmax && (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++; if (mon->mspec_used) mon->mspec_used--; if (digest_meal) { if (mon->meating) { mon->meating--; if (mon->meating <= 0) finish_meating(mon); } } } /* * Possibly awaken the given monster. Return a 1 if the monster has been * jolted awake. */ STATIC_OVL int disturb(mtmp) register struct monst *mtmp; { /* * + Ettins are hard to surprise. * + Nymphs, jabberwocks, and leprechauns do not easily wake up. * * Wake up if: * in direct LOS AND * within 10 squares AND * not stealthy or (mon is an ettin and 9/10) AND * (mon is not a nymph, jabberwock, or leprechaun) or 1/50 AND * Aggravate or mon is (dog or human) or * (1/7 and mon is not mimicing furniture or object) */ if (couldsee(mtmp->mx, mtmp->my) && distu(mtmp->mx, mtmp->my) <= 100 && (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) && (!(mtmp->data->mlet == S_NYMPH || mtmp->data == &mons[PM_JABBERWOCK] #if 0 /* DEFERRED */ || mtmp->data == &mons[PM_VORPAL_JABBERWOCK] #endif || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) && (Aggravate_monster || (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_HUMAN) || (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT))) { mtmp->msleeping = 0; return 1; } return 0; } /* ungrab/expel held/swallowed hero */ STATIC_OVL void release_hero(mon) struct monst *mon; { if (mon == u.ustuck) { if (u.uswallow) { expels(mon, mon->data, TRUE); } else if (!sticks(youmonst.data)) { unstuck(mon); /* let go */ You("get released!"); } } } /* monster begins fleeing for the specified time, 0 means untimed flee * if first, only adds fleetime if monster isn't already fleeing * if fleemsg, prints a message about new flight, otherwise, caller should */ void monflee(mtmp, fleetime, first, fleemsg) struct monst *mtmp; int fleetime; boolean first; boolean fleemsg; { /* shouldn't happen; maybe warrants impossible()? */ if (DEADMONSTER(mtmp)) return; if (mtmp == u.ustuck) release_hero(mtmp); /* expels/unstuck */ if (!first || !mtmp->mflee) { /* don't lose untimed scare */ if (!fleetime) mtmp->mfleetim = 0; else if (!mtmp->mflee || mtmp->mfleetim) { fleetime += (int) mtmp->mfleetim; /* ensure monster flees long enough to visibly stop fighting */ if (fleetime == 1) fleetime++; mtmp->mfleetim = (unsigned) min(fleetime, 127); } if (!mtmp->mflee && fleemsg && canseemon(mtmp) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) { /* unfortunately we can't distinguish between temporary sleep and temporary paralysis, so both conditions receive the same alternate message */ if (!mtmp->mcanmove || !mtmp->data->mmove) pline("%s seems to flinch.", Adjmonnam(mtmp, "immobile")); else pline("%s turns to flee.", Monnam(mtmp)); } mtmp->mflee = 1; } } STATIC_OVL void distfleeck(mtmp, inrange, nearby, scared) register struct monst *mtmp; int *inrange, *nearby, *scared; { int seescaryx, seescaryy; boolean sawscary = FALSE; *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= (BOLT_LIM * BOLT_LIM)); *nearby = *inrange && monnear(mtmp, mtmp->mux, mtmp->muy); /* Note: if your image is displaced, the monster sees the Elbereth * at your displaced position, thus never attacking your displaced * position, but possibly attacking you by accident. If you are * invisible, it sees the Elbereth at your real position, thus never * running into you by accident but possibly attacking the spot * where it guesses you are. */ if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { seescaryx = mtmp->mux; seescaryy = mtmp->muy; } else { seescaryx = u.ux; seescaryy = u.uy; } sawscary = onscary(seescaryx, seescaryy, mtmp); if (*nearby && (sawscary || (!mtmp->mpeaceful && in_your_sanctuary(mtmp, 0, 0)))) { *scared = 1; monflee(mtmp, rnd(rn2(7) ? 10 : 100), TRUE, TRUE); /* magical protection won't last forever, so there'll be a * chance of the magic being used up regardless of type */ if (sawscary) { wipe_engr_at(seescaryx, seescaryy, 1, TRUE); } } else *scared = 0; } /* perform a special one-time action for a monster; returns -1 if nothing special happened, 0 if monster uses up its turn, 1 if monster is killed */ STATIC_OVL int m_arrival(mon) struct monst *mon; { mon->mstrategy &= ~STRAT_ARRIVE; /* always reset */ return -1; } /* returns 1 if monster died moving, 0 otherwise */ /* The whole dochugw/m_move/distfleeck/mfndpos section is serious spaghetti * code. --KAA */ int dochug(mtmp) register struct monst *mtmp; { register struct permonst *mdat; register int tmp = 0; int inrange, nearby, scared; /* Pre-movement adjustments */ mdat = mtmp->data; if (mtmp->mstrategy & STRAT_ARRIVE) { int res = m_arrival(mtmp); if (res >= 0) return res; } /* check for waitmask status change */ if ((mtmp->mstrategy & STRAT_WAITFORU) && (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax)) mtmp->mstrategy &= ~STRAT_WAITFORU; /* update quest status flags */ quest_stat_check(mtmp); if (!mtmp->mcanmove || (mtmp->mstrategy & STRAT_WAITMASK)) { if (Hallucination) newsym(mtmp->mx, mtmp->my); if (mtmp->mcanmove && (mtmp->mstrategy & STRAT_CLOSE) && !mtmp->msleeping && monnear(mtmp, u.ux, u.uy)) quest_talk(mtmp); /* give the leaders a chance to speak */ return 0; /* other frozen monsters can't do anything */ } /* there is a chance we will wake it */ if (mtmp->msleeping && !disturb(mtmp)) { if (Hallucination) newsym(mtmp->mx, mtmp->my); return 0; } /* not frozen or sleeping: wipe out texts written in the dust */ wipe_engr_at(mtmp->mx, mtmp->my, 1, FALSE); /* confused monsters get unconfused with small probability */ if (mtmp->mconf && !rn2(50)) mtmp->mconf = 0; /* stunned monsters get un-stunned with larger probability */ if (mtmp->mstun && !rn2(10)) mtmp->mstun = 0; /* some monsters teleport */ if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz && !level.flags.noteleport) { (void) rloc(mtmp, TRUE); return 0; } if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1)) m_respond(mtmp); if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) m_respond(mtmp); if (mtmp->mhp <= 0) return 1; /* m_respond gaze can kill medusa */ /* fleeing monsters might regain courage */ if (mtmp->mflee && !mtmp->mfleetim && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0; /* cease conflict-induced swallow/grab if conflict has ended */ if (mtmp == u.ustuck && mtmp->mpeaceful && !mtmp->mconf && !Conflict) { release_hero(mtmp); return 0; /* uses up monster's turn */ } set_apparxy(mtmp); /* Must be done after you move and before the monster does. The * set_apparxy() call in m_move() doesn't suffice since the variables * inrange, etc. all depend on stuff set by set_apparxy(). */ /* Monsters that want to acquire things */ /* may teleport, so do it before inrange is set */ if (is_covetous(mdat)) (void) tactics(mtmp); /* check distance and scariness of attacks */ distfleeck(mtmp, &inrange, &nearby, &scared); if (find_defensive(mtmp)) { if (use_defensive(mtmp) != 0) return 1; } else if (find_misc(mtmp)) { if (use_misc(mtmp) != 0) return 1; } /* Demonic Blackmail! */ if (nearby && mdat->msound == MS_BRIBE && mtmp->mpeaceful && !mtmp->mtame && !u.uswallow) { if (mtmp->mux != u.ux || mtmp->muy != u.uy) { pline("%s whispers at thin air.", cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It"); if (is_demon(youmonst.data)) { /* "Good hunting, brother" */ if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); } else { mtmp->minvis = mtmp->perminvis = 0; /* Why? For the same reason in real demon talk */ pline("%s gets angry!", Amonnam(mtmp)); mtmp->mpeaceful = 0; set_malign(mtmp); /* since no way is an image going to pay it off */ } } else if (demon_talk(mtmp)) return 1; /* you paid it off */ } /* the watch will look around and see if you are up to no good :-) */ if (is_watch(mdat)) { watch_on_duty(mtmp); } else if (is_mind_flayer(mdat) && !rn2(20)) { struct monst *m2, *nmon = (struct monst *) 0; if (canseemon(mtmp)) pline("%s concentrates.", Monnam(mtmp)); if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) { You("sense a faint wave of psychic energy."); goto toofar; } pline("A wave of psychic energy pours over you!"); if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) { pline("It feels quite soothing."); } else if (!u.uinvulnerable) { register boolean m_sen = sensemon(mtmp); if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) { int dmg; pline("It locks on to your %s!", m_sen ? "telepathy" : Blind_telepat ? "latent telepathy" : "mind"); dmg = rnd(15); if (Half_spell_damage) dmg = (dmg + 1) / 2; losehp(dmg, "psychic blast", KILLED_BY_AN); } } for (m2 = fmon; m2; m2 = nmon) { nmon = m2->nmon; if (DEADMONSTER(m2)) continue; if (m2->mpeaceful == mtmp->mpeaceful) continue; if (mindless(m2->data)) continue; if (m2 == mtmp) continue; if ((telepathic(m2->data) && (rn2(2) || m2->mblinded)) || !rn2(10)) { if (cansee(m2->mx, m2->my)) pline("It locks on to %s.", mon_nam(m2)); m2->mhp -= rnd(15); if (m2->mhp <= 0) monkilled(m2, "", AD_DRIN); else m2->msleeping = 0; } } } toofar: /* If monster is nearby you, and has to wield a weapon, do so. This * costs the monster a move, of course. */ if ((!mtmp->mpeaceful || Conflict) && inrange && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8 && attacktype(mdat, AT_WEAP)) { struct obj *mw_tmp; /* The scared check is necessary. Otherwise a monster that is * one square near the player but fleeing into a wall would keep * switching between pick-axe and weapon. If monster is stuck * in a trap, prefer ranged weapon (wielding is done in thrwmu). * This may cost the monster an attack, but keeps the monster * from switching back and forth if carrying both. */ mw_tmp = MON_WEP(mtmp); if (!(scared && mw_tmp && is_pick(mw_tmp)) && mtmp->weapon_check == NEED_WEAPON && !(mtmp->mtrapped && !nearby && select_rwep(mtmp))) { mtmp->weapon_check = NEED_HTH_WEAPON; if (mon_wield_item(mtmp) != 0) return 0; } } /* Now the actual movement phase */ if (!nearby || mtmp->mflee || scared || mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || (mdat->mlet == S_LEPRECHAUN && !findgold(invent) && (findgold(mtmp->minvent) || rn2(2))) || (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) || (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) { /* Possibly cast an undirected spell if not attacking you */ /* note that most of the time castmu() will pick a directed spell and do nothing, so the monster moves normally */ /* arbitrary distance restriction to keep monster far away from you from having cast dozens of sticks-to-snakes or similar spells by the time you reach it */ if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 49 && !mtmp->mspec_used) { struct attack *a; for (a = &mdat->mattk[0]; a < &mdat->mattk[NATTK]; a++) { if (a->aatyp == AT_MAGC && (a->adtyp == AD_SPEL || a->adtyp == AD_CLRC)) { if (castmu(mtmp, a, FALSE, FALSE)) { tmp = 3; break; } } } } tmp = m_move(mtmp, 0); if (tmp != 2) distfleeck(mtmp, &inrange, &nearby, &scared); /* recalc */ switch (tmp) { /* for pets, cases 0 and 3 are equivalent */ case 0: /* no movement, but it can still attack you */ case 3: /* absolutely no movement */ /* vault guard might have vanished */ if (mtmp->isgd && (mtmp->mhp < 1 || !mtmp->mx == 0)) return 1; /* behave as if it died */ /* During hallucination, monster appearance should * still change - even if it doesn't move. */ if (Hallucination) newsym(mtmp->mx, mtmp->my); break; case 1: /* monster moved */ /* Maybe it stepped on a trap and fell asleep... */ if (mtmp->msleeping || !mtmp->mcanmove) return 0; /* Monsters can move and then shoot on same turn; our hero can't. Is that fair? */ if (!nearby && (ranged_attk(mdat) || find_offensive(mtmp))) break; /* engulfer/grabber checks */ if (mtmp == u.ustuck) { /* a monster that's digesting you can move at the * same time -dlc */ if (u.uswallow) return mattacku(mtmp); /* if confused grabber has wandered off, let go */ if (distu(mtmp->mx, mtmp->my) > 2) unstuck(mtmp); } return 0; case 2: /* monster died */ return 1; } } /* Now, attack the player if possible - one attack set per monst */ if (!mtmp->mpeaceful || (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) { if (inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3) if (mattacku(mtmp)) return 1; /* monster died (e.g. exploded) */ if (mtmp->wormno) wormhitu(mtmp); } /* special speeches for quest monsters */ if (!mtmp->msleeping && mtmp->mcanmove && nearby) quest_talk(mtmp); /* extra emotional attack for vile monsters */ if (inrange && mtmp->data->msound == MS_CUSS && !mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my) && !mtmp->minvis && !rn2(5)) cuss(mtmp); return (tmp == 2); } static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 }; static NEARDATA const char magical[] = { AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, SPBOOK_CLASS, 0 }; static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 }; static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 }; static NEARDATA const char gem_class[] = { GEM_CLASS, 0 }; boolean itsstuck(mtmp) register struct monst *mtmp; { if (sticks(youmonst.data) && mtmp == u.ustuck && !u.uswallow) { pline("%s cannot escape from you!", Monnam(mtmp)); return TRUE; } return FALSE; } /* * should_displace() * * Displacement of another monster is a last resort and only * used on approach. If there are better ways to get to target, * those should be used instead. This function does that evaluation. */ boolean should_displace(mtmp, poss, info, cnt, gx, gy) struct monst *mtmp; coord *poss; /* coord poss[9] */ long *info; /* long info[9] */ int cnt; xchar gx, gy; { int shortest_with_displacing = -1; int shortest_without_displacing = -1; int count_without_displacing = 0; register int i, nx, ny; int ndist; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; ndist = dist2(nx, ny, gx, gy); if (MON_AT(nx, ny) && (info[i] & ALLOW_MDISP) && !(info[i] & ALLOW_M) && !undesirable_disp(mtmp, nx, ny)) { if (shortest_with_displacing == -1 || (ndist < shortest_with_displacing)) shortest_with_displacing = ndist; } else { if ((shortest_without_displacing == -1) || (ndist < shortest_without_displacing)) shortest_without_displacing = ndist; count_without_displacing++; } } if (shortest_with_displacing > -1 && (shortest_with_displacing < shortest_without_displacing || !count_without_displacing)) return TRUE; return FALSE; } /* Return values: * 0: did not move, but can still attack and do other stuff. * 1: moved, possibly can attack. * 2: monster died. * 3: did not move, and can't do anything else either. */ int m_move(mtmp, after) register struct monst *mtmp; register int after; { register int appr; xchar gx, gy, nix, niy, chcnt; int chi; /* could be schar except for stupid Sun-2 compiler */ boolean likegold = 0, likegems = 0, likeobjs = 0, likemagic = 0, conceals = 0; boolean likerock = 0, can_tunnel = 0; boolean can_open = 0, can_unlock = 0, doorbuster = 0; boolean uses_items = 0, setlikes = 0; boolean avoid = FALSE; boolean better_with_displacing = FALSE; struct permonst *ptr; struct monst *mtoo; schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */ long info[9]; long flag; int omx = mtmp->mx, omy = mtmp->my; struct obj *mw_tmp; if (mtmp->mtrapped) { int i = mintrap(mtmp); if (i >= 2) { newsym(mtmp->mx, mtmp->my); return 2; } /* it died */ if (i == 1) return 0; /* still in trap, so didn't move */ } ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */ if (mtmp->meating) { mtmp->meating--; if (mtmp->meating <= 0) finish_meating(mtmp); return 3; /* still eating */ } if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10)) return 0; /* do not leave hiding place */ set_apparxy(mtmp); /* where does mtmp think you are? */ /* Not necessary if m_move called from this file, but necessary in * other calls of m_move (ex. leprechauns dodging) */ if (!Is_rogue_level(&u.uz)) can_tunnel = tunnels(ptr); can_open = !(nohands(ptr) || verysmall(ptr)); can_unlock = ((can_open && monhaskey(mtmp, TRUE)) || mtmp->iswiz || is_rider(ptr)); doorbuster = is_giant(ptr); if (mtmp->wormno) goto not_special; /* my dog gets special treatment */ if (mtmp->mtame) { mmoved = dog_move(mtmp, after); goto postmov; } /* likewise for shopkeeper */ if (mtmp->isshk) { mmoved = shk_move(mtmp); if (mmoved == -2) return 2; if (mmoved >= 0) goto postmov; mmoved = 0; /* follow player outside shop */ } /* and for the guard */ if (mtmp->isgd) { mmoved = gd_move(mtmp); if (mmoved == -2) return 2; if (mmoved >= 0) goto postmov; mmoved = 0; } /* and the acquisitive monsters get special treatment */ if (is_covetous(ptr)) { xchar tx = STRAT_GOALX(mtmp->mstrategy), ty = STRAT_GOALY(mtmp->mstrategy); struct monst *intruder = m_at(tx, ty); /* * if there's a monster on the object or in possession of it, * attack it. */ if ((dist2(mtmp->mx, mtmp->my, tx, ty) < 2) && intruder && (intruder != mtmp)) { notonhead = (intruder->mx != tx || intruder->my != ty); if (mattackm(mtmp, intruder) == 2) return 2; mmoved = 1; } else mmoved = 0; goto postmov; } /* and for the priest */ if (mtmp->ispriest) { mmoved = pri_move(mtmp); if (mmoved == -2) return 2; if (mmoved >= 0) goto postmov; mmoved = 0; } #ifdef MAIL if (ptr == &mons[PM_MAIL_DAEMON]) { if (!Deaf && canseemon(mtmp)) verbalize("I'm late!"); mongone(mtmp); return 2; } #endif /* teleport if that lies in our nature */ if (ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan && !tele_restrict(mtmp)) { if (mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2)) (void) rloc(mtmp, TRUE); else mnexto(mtmp); mmoved = 1; goto postmov; } not_special: if (u.uswallow && !mtmp->mflee && u.ustuck != mtmp) return 1; omx = mtmp->mx; omy = mtmp->my; gx = mtmp->mux; gy = mtmp->muy; appr = mtmp->mflee ? -1 : 1; if (mtmp->mconf || (u.uswallow && mtmp == u.ustuck)) { appr = 0; } else { struct obj *lepgold, *ygold; boolean should_see = (couldsee(omx, omy) && (levl[gx][gy].lit || !levl[omx][omy].lit) && (dist2(omx, omy, gx, gy) <= 36)); if (!mtmp->mcansee || (should_see && Invis && !perceives(ptr) && rn2(11)) || is_obj_mappear(&youmonst,STRANGE_OBJECT) || u.uundetected || (is_obj_mappear(&youmonst,GOLD_PIECE) && !likes_gold(ptr)) || (mtmp->mpeaceful && !mtmp->isshk) /* allow shks to follow */ || ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT || ptr->mlet == S_LIGHT) && !rn2(3))) appr = 0; if (monsndx(ptr) == PM_LEPRECHAUN && (appr == 1) && ((lepgold = findgold(mtmp->minvent)) && (lepgold->quan > ((ygold = findgold(invent)) ? ygold->quan : 0L)))) appr = -1; if (!should_see && can_track(ptr)) { register coord *cp; cp = gettrack(omx, omy); if (cp) { gx = cp->x; gy = cp->y; } } } if ((!mtmp->mpeaceful || !rn2(10)) && (!Is_rogue_level(&u.uz))) { boolean in_line = (lined_up(mtmp) && (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= (throws_rocks(youmonst.data) ? 20 : ACURRSTR / 2 + 1))); if (appr != 1 || !in_line) { /* Monsters in combat won't pick stuff up, avoiding the * situation where you toss arrows at it and it has nothing * better to do than pick the arrows up. */ register int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); /* look for gold or jewels nearby */ likegold = (likes_gold(ptr) && pctload < 95); likegems = (likes_gems(ptr) && pctload < 85); uses_items = (!mindless(ptr) && !is_animal(ptr) && pctload < 75); likeobjs = (likes_objs(ptr) && pctload < 75); likemagic = (likes_magic(ptr) && pctload < 85); likerock = (throws_rocks(ptr) && pctload < 50 && !Sokoban); conceals = hides_under(ptr); setlikes = TRUE; } } #define SQSRCHRADIUS 5 { register int minr = SQSRCHRADIUS; /* not too far away */ register struct obj *otmp; register int xx, yy; int oomx, oomy, lmx, lmy; /* cut down the search radius if it thinks character is closer. */ if (distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS && !mtmp->mpeaceful) minr--; /* guards shouldn't get too distracted */ if (!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1; if ((likegold || likegems || likeobjs || likemagic || likerock || conceals) && (!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) { look_for_obj: oomx = min(COLNO - 1, omx + minr); oomy = min(ROWNO - 1, omy + minr); lmx = max(1, omx - minr); lmy = max(0, omy - minr); for (otmp = fobj; otmp; otmp = otmp->nobj) { /* monsters may pick rocks up, but won't go out of their way to grab them; this might hamper sling wielders, but it cuts down on move overhead by filtering out most common item */ if (otmp->otyp == ROCK) continue; xx = otmp->ox; yy = otmp->oy; /* Nymphs take everything. Most other creatures should not * pick up corpses except as a special case like in * searches_for_item(). We need to do this check in * mpickstuff() as well. */ if (xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) { /* don't get stuck circling around an object that's underneath an immobile or hidden monster; paralysis victims excluded */ if ((mtoo = m_at(xx, yy)) != 0 && (mtoo->msleeping || mtoo->mundetected || (mtoo->mappearance && !mtoo->iswiz) || !mtoo->data->mmove)) continue; if (((likegold && otmp->oclass == COIN_CLASS) || (likeobjs && index(practical, otmp->oclass) && (otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH && !is_rider(&mons[otmp->corpsenm])))) || (likemagic && index(magical, otmp->oclass)) || (uses_items && searches_for_item(mtmp, otmp)) || (likerock && otmp->otyp == BOULDER) || (likegems && otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material != MINERAL) || (conceals && !cansee(otmp->ox, otmp->oy)) || (ptr == &mons[PM_GELATINOUS_CUBE] && !index(indigestion, otmp->oclass) && !(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))) && touch_artifact(otmp, mtmp)) { if (can_carry(mtmp, otmp) > 0 && (throws_rocks(ptr) || !sobj_at(BOULDER, xx, yy)) && (!is_unicorn(ptr) || objects[otmp->otyp].oc_material == GEMSTONE) /* Don't get stuck circling an Elbereth */ && !onscary(xx, yy, mtmp)) { minr = distmin(omx, omy, xx, yy); oomx = min(COLNO - 1, omx + minr); oomy = min(ROWNO - 1, omy + minr); lmx = max(1, omx - minr); lmy = max(0, omy - minr); gx = otmp->ox; gy = otmp->oy; if (gx == omx && gy == omy) { mmoved = 3; /* actually unnecessary */ goto postmov; } } } } } } else if (likegold) { /* don't try to pick up anything else, but use the same loop */ uses_items = 0; likegems = likeobjs = likemagic = likerock = conceals = 0; goto look_for_obj; } if (minr < SQSRCHRADIUS && appr == -1) { if (distmin(omx, omy, mtmp->mux, mtmp->muy) <= 3) { gx = mtmp->mux; gy = mtmp->muy; } else appr = 1; } } /* don't tunnel if hostile and close enough to prefer a weapon */ if (can_tunnel && needspick(ptr) && ((!mtmp->mpeaceful || Conflict) && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8)) can_tunnel = FALSE; nix = omx; niy = omy; flag = 0L; if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) flag |= (ALLOW_SANCT | ALLOW_SSM); else flag |= ALLOW_U; if (is_minion(ptr) || is_rider(ptr)) flag |= ALLOW_SANCT; /* unicorn may not be able to avoid hero on a noteleport level */ if (is_unicorn(ptr) && !level.flags.noteleport) flag |= NOTONL; if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK); if (passes_bars(ptr)) flag |= ALLOW_BARS; if (can_tunnel) flag |= ALLOW_DIG; if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM; if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC; if (is_vampshifter(mtmp)) flag |= NOGARLIC; if (throws_rocks(ptr)) flag |= ALLOW_ROCK; if (can_open) flag |= OPENDOOR; if (can_unlock) flag |= UNLOCKDOOR; if (doorbuster) flag |= BUSTDOOR; { register int i, j, nx, ny, nearer; int jcnt, cnt; int ndist, nidist; register coord *mtrk; coord poss[9]; cnt = mfndpos(mtmp, poss, info, flag); chcnt = 0; jcnt = min(MTSZ, cnt - 1); chi = -1; nidist = dist2(nix, niy, gx, gy); /* allow monsters be shortsighted on some levels for balance */ if (!mtmp->mpeaceful && level.flags.shortsighted && nidist > (couldsee(nix, niy) ? 144 : 36) && appr == 1) appr = 0; if (is_unicorn(ptr) && level.flags.noteleport) { /* on noteleport levels, perhaps we cannot avoid hero */ for (i = 0; i < cnt; i++) if (!(info[i] & NOTONL)) avoid = TRUE; } better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy); for (i = 0; i < cnt; i++) { if (avoid && (info[i] & NOTONL)) continue; nx = poss[i].x; ny = poss[i].y; if (MON_AT(nx, ny) && (info[i] & ALLOW_MDISP) && !(info[i] & ALLOW_M) && !better_with_displacing) continue; if (appr != 0) { mtrk = &mtmp->mtrack[0]; for (j = 0; j < jcnt; mtrk++, j++) if (nx == mtrk->x && ny == mtrk->y) if (rn2(4 * (cnt - j))) goto nxti; } nearer = ((ndist = dist2(nx, ny, gx, gy)) < nidist); if ((appr == 1 && nearer) || (appr == -1 && !nearer) || (!appr && !rn2(++chcnt)) || !mmoved) { nix = nx; niy = ny; nidist = ndist; chi = i; mmoved = 1; } nxti: ; } } if (mmoved) { register int j; if (mmoved == 1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp)) return 3; if (mmoved == 1 && can_tunnel && needspick(ptr) && ((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy)) || closed_door(nix, niy))) { if (closed_door(nix, niy)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_PICK_OR_AXE; } else if (IS_TREE(levl[nix][niy].typ)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_AXE; } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { mtmp->weapon_check = NEED_PICK_AXE; } if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) return 3; } /* If ALLOW_U is set, either it's trying to attack you, or it * thinks it is. In either case, attack this spot in preference to * all others. */ /* Actually, this whole section of code doesn't work as you'd expect. * Most attacks are handled in dochug(). It calls distfleeck(), which * among other things sets nearby if the monster is near you--and if * nearby is set, we never call m_move unless it is a special case * (confused, stun, etc.) The effect is that this ALLOW_U (and * mfndpos) has no effect for normal attacks, though it lets a * confused monster attack you by accident. */ if (info[chi] & ALLOW_U) { nix = mtmp->mux; niy = mtmp->muy; } if (nix == u.ux && niy == u.uy) { mtmp->mux = u.ux; mtmp->muy = u.uy; return 0; } /* The monster may attack another based on 1 of 2 conditions: * 1 - It may be confused. * 2 - It may mistake the monster for your (displaced) image. * Pets get taken care of above and shouldn't reach this code. * Conflict gets handled even farther away (movemon()). */ if ((info[chi] & ALLOW_M) || (nix == mtmp->mux && niy == mtmp->muy)) { struct monst *mtmp2; int mstatus; mtmp2 = m_at(nix, niy); notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my); /* note: mstatus returns 0 if mtmp2 is nonexistent */ mstatus = mattackm(mtmp, mtmp2); if (mstatus & MM_AGR_DIED) /* aggressor died */ return 2; if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4) && mtmp2->movement >= NORMAL_SPEED) { mtmp2->movement -= NORMAL_SPEED; notonhead = 0; mstatus = mattackm(mtmp2, mtmp); /* return attack */ if (mstatus & MM_DEF_DIED) return 2; } return 3; } if ((info[chi] & ALLOW_MDISP)) { struct monst *mtmp2; int mstatus; mtmp2 = m_at(nix, niy); mstatus = mdisplacem(mtmp, mtmp2, FALSE); if ((mstatus & MM_AGR_DIED) || (mstatus & MM_DEF_DIED)) return 2; if (mstatus & MM_HIT) return 1; return 3; } if (!m_in_out_region(mtmp, nix, niy)) return 3; remove_monster(omx, omy); place_monster(mtmp, nix, niy); for (j = MTSZ - 1; j > 0; j--) mtmp->mtrack[j] = mtmp->mtrack[j - 1]; mtmp->mtrack[0].x = omx; mtmp->mtrack[0].y = omy; /* Place a segment at the old position. */ if (mtmp->wormno) worm_move(mtmp); } else { if (is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) { (void) rloc(mtmp, TRUE); return 1; } if (mtmp->wormno) worm_nomove(mtmp); } postmov: if (mmoved == 1 || mmoved == 3) { boolean canseeit = cansee(mtmp->mx, mtmp->my); if (mmoved == 1) { newsym(omx, omy); /* update the old position */ if (mintrap(mtmp) >= 2) { if (mtmp->mx) newsym(mtmp->mx, mtmp->my); return 2; /* it died */ } ptr = mtmp->data; /* open a door, or crash through it, if you can */ if (IS_DOOR(levl[mtmp->mx][mtmp->my].typ) && !passes_walls(ptr) /* doesn't need to open doors */ && !can_tunnel) { /* taken care of below */ struct rm *here = &levl[mtmp->mx][mtmp->my]; boolean btrapped = (here->doormask & D_TRAPPED), observeit = canseeit && canspotmon(mtmp); if (here->doormask & (D_LOCKED | D_CLOSED) && (amorphous(ptr) || (!amorphous(ptr) && can_fog(mtmp) && vamp_shift(mtmp, &mons[PM_FOG_CLOUD])))) { if (flags.verbose && canseemon(mtmp)) pline("%s %s under the door.", Monnam(mtmp), (ptr == &mons[PM_FOG_CLOUD] || ptr == &mons[PM_YELLOW_LIGHT]) ? "flows" : "oozes"); } else if (here->doormask & D_LOCKED && can_unlock) { if (btrapped) { here->doormask = D_NODOOR; newsym(mtmp->mx, mtmp->my); unblock_point(mtmp->mx, mtmp->my); /* vision */ if (mb_trapped(mtmp)) return 2; } else { if (flags.verbose) { if (observeit) pline("%s unlocks and opens a door.", Monnam(mtmp)); else if (canseeit) You_see("a door unlock and open."); else if (!Deaf) You_hear("a door unlock and open."); } here->doormask = D_ISOPEN; /* newsym(mtmp->mx, mtmp->my); */ unblock_point(mtmp->mx, mtmp->my); /* vision */ } } else if (here->doormask == D_CLOSED && can_open) { if (btrapped) { here->doormask = D_NODOOR; newsym(mtmp->mx, mtmp->my); unblock_point(mtmp->mx, mtmp->my); /* vision */ if (mb_trapped(mtmp)) return 2; } else { if (flags.verbose) { if (observeit) pline("%s opens a door.", Monnam(mtmp)); else if (canseeit) You_see("a door open."); else if (!Deaf) You_hear("a door open."); } here->doormask = D_ISOPEN; /* newsym(mtmp->mx, mtmp->my); */ /* done below */ unblock_point(mtmp->mx, mtmp->my); /* vision */ } } else if (here->doormask & (D_LOCKED | D_CLOSED)) { /* mfndpos guarantees this must be a doorbuster */ if (btrapped) { here->doormask = D_NODOOR; newsym(mtmp->mx, mtmp->my); unblock_point(mtmp->mx, mtmp->my); /* vision */ if (mb_trapped(mtmp)) return 2; } else { if (flags.verbose) { if (observeit) pline("%s smashes down a door.", Monnam(mtmp)); else if (canseeit) You_see("a door crash open."); else if (!Deaf) You_hear("a door crash open."); } if (here->doormask & D_LOCKED && !rn2(2)) here->doormask = D_NODOOR; else here->doormask = D_BROKEN; /* newsym(mtmp->mx, mtmp->my); */ /* done below */ unblock_point(mtmp->mx, mtmp->my); /* vision */ } /* if it's a shop door, schedule repair */ if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); } } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) { if (may_dig(mtmp->mx, mtmp->my) && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR))) { if (canseemon(mtmp)) pline("%s eats through the iron bars.", Monnam(mtmp)); dissolve_bars(mtmp->mx, mtmp->my); return 3; } else if (flags.verbose && canseemon(mtmp)) Norep("%s %s %s the iron bars.", Monnam(mtmp), /* pluralization fakes verb conjugation */ makeplural(locomotion(ptr, "pass")), passes_walls(ptr) ? "through" : "between"); } /* possibly dig */ if (can_tunnel && mdig_tunnel(mtmp)) return 2; /* mon died (position already updated) */ /* set also in domove(), hack.c */ if (u.uswallow && mtmp == u.ustuck && (mtmp->mx != omx || mtmp->my != omy)) { /* If the monster moved, then update */ u.ux0 = u.ux; u.uy0 = u.uy; u.ux = mtmp->mx; u.uy = mtmp->my; swallowed(0); } else newsym(mtmp->mx, mtmp->my); } if (OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) { /* recompute the likes tests, in case we polymorphed * or if the "likegold" case got taken above */ if (setlikes) { int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); /* look for gold or jewels nearby */ likegold = (likes_gold(ptr) && pctload < 95); likegems = (likes_gems(ptr) && pctload < 85); uses_items = (!mindless(ptr) && !is_animal(ptr) && pctload < 75); likeobjs = (likes_objs(ptr) && pctload < 75); likemagic = (likes_magic(ptr) && pctload < 85); likerock = (throws_rocks(ptr) && pctload < 50 && !Sokoban); conceals = hides_under(ptr); } /* Maybe a rock mole just ate some metal object */ if (metallivorous(ptr)) { if (meatmetal(mtmp) == 2) return 2; /* it died */ } if (g_at(mtmp->mx, mtmp->my) && likegold) mpickgold(mtmp); /* Maybe a cube ate just about anything */ if (ptr == &mons[PM_GELATINOUS_CUBE]) { if (meatobj(mtmp) == 2) return 2; /* it died */ } if (!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) { boolean picked = FALSE; if (likeobjs) picked |= mpickstuff(mtmp, practical); if (likemagic) picked |= mpickstuff(mtmp, magical); if (likerock) picked |= mpickstuff(mtmp, boulder_class); if (likegems) picked |= mpickstuff(mtmp, gem_class); if (uses_items) picked |= mpickstuff(mtmp, (char *) 0); if (picked) mmoved = 3; } if (mtmp->minvis) { newsym(mtmp->mx, mtmp->my); if (mtmp->wormno) see_wsegs(mtmp); } } if (hides_under(ptr) || ptr->mlet == S_EEL) { /* Always set--or reset--mundetected if it's already hidden (just in case the object it was hiding under went away); usually set mundetected unless monster can't move. */ if (mtmp->mundetected || (mtmp->mcanmove && !mtmp->msleeping && rn2(5))) (void) hideunder(mtmp); newsym(mtmp->mx, mtmp->my); } if (mtmp->isshk) { after_shk_move(mtmp); } } return mmoved; } void dissolve_bars(x, y) register int x, y; { levl[x][y].typ = (Is_special(&u.uz) || *in_rooms(x, y, 0)) ? ROOM : CORR; newsym(x, y); } boolean closed_door(x, y) register int x, y; { return (boolean) (IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & (D_LOCKED | D_CLOSED))); } boolean accessible(x, y) register int x, y; { int levtyp = levl[x][y].typ; /* use underlying terrain in front of closed drawbridge */ if (levtyp == DRAWBRIDGE_UP) levtyp = db_under_typ(levl[x][y].drawbridgemask); return (boolean) (ACCESSIBLE(levtyp) && !closed_door(x, y)); } /* decide where the monster thinks you are standing */ void set_apparxy(mtmp) register struct monst *mtmp; { boolean notseen, gotu; register int disp, mx = mtmp->mux, my = mtmp->muy; long umoney = money_cnt(invent); /* * do cheapest and/or most likely tests first */ /* pet knows your smell; grabber still has hold of you */ if (mtmp->mtame || mtmp == u.ustuck) goto found_you; /* monsters which know where you are don't suddenly forget, if you haven't moved away */ if (mx == u.ux && my == u.uy) goto found_you; notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data))); /* add cases as required. eg. Displacement ... */ if (notseen || Underwater) { /* Xorns can smell quantities of valuable metal like that in solid gold coins, treat as seen */ if ((mtmp->data == &mons[PM_XORN]) && umoney && !Underwater) disp = 0; else disp = 1; } else if (Displaced) { disp = couldsee(mx, my) ? 2 : 1; } else disp = 0; if (!disp) goto found_you; /* without something like the following, invisibility and displacement are too powerful */ gotu = notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE; if (!gotu) { register int try_cnt = 0; do { if (++try_cnt > 200) goto found_you; /* punt */ mx = u.ux - disp + rn2(2 * disp + 1); my = u.uy - disp + rn2(2 * disp + 1); } while (!isok(mx, my) || (disp != 2 && mx == mtmp->mx && my == mtmp->my) || ((mx != u.ux || my != u.uy) && !passes_walls(mtmp->data) && !(accessible(mx, my) || (closed_door(mx, my) && (can_ooze(mtmp) || can_fog(mtmp))))) || !couldsee(mx, my)); } else { found_you: mx = u.ux; my = u.uy; } mtmp->mux = mx; mtmp->muy = my; } /* * mon-to-mon displacement is a deliberate "get out of my way" act, * not an accidental bump, so we don't consider mstun or mconf in * undesired_disp(). * * We do consider many other things about the target and its * location however. */ boolean undesirable_disp(mtmp, x, y) struct monst *mtmp; xchar x, y; { boolean is_pet = (mtmp && mtmp->mtame && !mtmp->isminion); struct trap *trap = t_at(x, y); if (is_pet) { /* Pets avoid a trap if you've seen it usually. */ if (trap && trap->tseen && rn2(40)) return TRUE; /* Pets avoid cursed locations */ if (cursed_object_at(x, y)) return TRUE; /* Monsters avoid a trap if they've seen that type before */ } else if (trap && rn2(40) && (mtmp->mtrapseen & (1 << (trap->ttyp - 1))) != 0) { return TRUE; } return FALSE; } /* * Inventory prevents passage under door. * Used by can_ooze() and can_fog(). */ STATIC_OVL boolean stuff_prevents_passage(mtmp) struct monst *mtmp; { struct obj *chain, *obj; if (mtmp == &youmonst) { chain = invent; } else { chain = mtmp->minvent; } for (obj = chain; obj; obj = obj->nobj) { int typ = obj->otyp; if (typ == COIN_CLASS && obj->quan > 100L) return TRUE; if (obj->oclass != GEM_CLASS && !(typ >= ARROW && typ <= BOOMERANG) && !(typ >= DAGGER && typ <= CRYSKNIFE) && typ != SLING && !is_cloak(obj) && typ != FEDORA && !is_gloves(obj) && typ != LEATHER_JACKET && typ != CREDIT_CARD && !is_shirt(obj) && !(typ == CORPSE && verysmall(&mons[obj->corpsenm])) && typ != FORTUNE_COOKIE && typ != CANDY_BAR && typ != PANCAKE && typ != LEMBAS_WAFER && typ != LUMP_OF_ROYAL_JELLY && obj->oclass != AMULET_CLASS && obj->oclass != RING_CLASS && obj->oclass != VENOM_CLASS && typ != SACK && typ != BAG_OF_HOLDING && typ != BAG_OF_TRICKS && !Is_candle(obj) && typ != OILSKIN_SACK && typ != LEASH && typ != STETHOSCOPE && typ != BLINDFOLD && typ != TOWEL && typ != TIN_WHISTLE && typ != MAGIC_WHISTLE && typ != MAGIC_MARKER && typ != TIN_OPENER && typ != SKELETON_KEY && typ != LOCK_PICK) return TRUE; if (Is_container(obj) && obj->cobj) return TRUE; } return FALSE; } boolean can_ooze(mtmp) struct monst *mtmp; { if (!amorphous(mtmp->data) || stuff_prevents_passage(mtmp)) return FALSE; return TRUE; } /* monster can change form into a fog if necessary */ boolean can_fog(mtmp) struct monst *mtmp; { if ((is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE) && !Protection_from_shape_changers && !stuff_prevents_passage(mtmp)) return TRUE; return FALSE; } STATIC_OVL int vamp_shift(mon, ptr) struct monst *mon; struct permonst *ptr; { int reslt = 0; if (mon->cham >= LOW_PM) { if (ptr == &mons[mon->cham]) mon->cham = NON_PM; reslt = newcham(mon, ptr, FALSE, FALSE); } else if (mon->cham == NON_PM && ptr != mon->data) { mon->cham = monsndx(mon->data); reslt = newcham(mon, ptr, FALSE, FALSE); } return reslt; } /*monmove.c*/ nethack-3.6.0/src/monst.c0000664000076400007660000051243512620076764014254 0ustar paxedpaxed/* NetHack 3.6 monst.c $NHDT-Date: 1445556875 2015/10/22 23:34:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.53 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "permonst.h" #include "monsym.h" #define NO_ATTK \ { \ 0, 0, 0, 0 \ } #define WT_ELF 800 #define WT_DRAGON 4500 #ifdef C #undef C #endif #ifdef TEXTCOLOR #include "color.h" #define C(color) color #define HI_DOMESTIC CLR_WHITE /* use for player + friendlies */ #define HI_LORD CLR_MAGENTA #else #define C(color) #endif void NDECL(monst_init); /* * Entry Format: (from permonst.h) * * name, symbol (S_* defines), * difficulty level, move rate, armor class, magic resistance, * alignment, creation/geno flags (G_* defines), * 6 * attack structs ( type , damage-type, # dice, # sides ), * weight (WT_* defines), nutritional value, extension length, * sounds made (MS_* defines), physical size (MZ_* defines), * resistances, resistances conferred (both MR_* defines), * 3 * flag bitmaps (M1_*, M2_*, and M3_* defines respectively) * symbol color (C(x) macro) */ #define MON(nam, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, col) \ { \ nam, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, C(col) \ } /* LVL() and SIZ() collect several fields to cut down on # of args for MON() */ #define LVL(lvl, mov, ac, mr, aln) lvl, mov, ac, mr, aln #define SIZ(wt, nut, snd, siz) wt, nut, snd, siz /* ATTK() and A() are to avoid braces and commas within args to MON() */ #define ATTK(at, ad, n, d) \ { \ at, ad, n, d \ } #define A(a1, a2, a3, a4, a5, a6) \ { \ a1, a2, a3, a4, a5, a6 \ } /* * Rule #1: monsters of a given class are contiguous in the * mons[] array. * * Rule #2: monsters of a given class are presented in ascending * order of strength. * * Rule #3: monster frequency is included in the geno mask; * the frequency can be from 0 to 7. 0's will also * be skipped during generation. * * Rule #4: monster subclasses (e.g. giants) should be kept * together, unless it violates Rule 2. NOGEN monsters * won't violate Rule 2. * * Guidelines for color assignment: * * * Use the same color for all `growth stages' of a monster (ex. * little dog/big dog, baby naga/full-grown naga. * * * Use colors given in names wherever possible. If the class has `real' * members with strong color associations, use those. * * * Favor `cool' colors for cold-resistant monsters, `warm' ones for * fire-resistant ones. * * * Try to reserve purple (magenta) for powerful `ruler' monsters (queen * bee, kobold lord, &c.). * * * Subject to all these constraints, try to use color to make as many * distinctions as the / command (that is, within a monster letter * distinct names should map to distinct colors). * * The aim in assigning colors is to be consistent enough so a player can * become `intuitive' about them, deducing some or all of these rules * unconsciously. Use your common sense. */ #ifndef SPLITMON_2 NEARDATA struct permonst mons[] = { /* * ants */ MON("giant ant", S_ANT, LVL(2, 18, 3, 0, 0), (G_GENO | G_SGROUP | 3), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_TINY), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("killer bee", S_ANT, LVL(1, 18, -1, 0, 0), (G_GENO | G_LGROUP | 2), A(ATTK(AT_STNG, AD_DRST, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1, 5, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL | M1_FLY | M1_NOHANDS | M1_POIS, M2_HOSTILE | M2_FEMALE, 0, CLR_YELLOW), MON("soldier ant", S_ANT, LVL(3, 18, 3, 0, 0), (G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 5, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_BLUE), MON("fire ant", S_ANT, LVL(3, 18, 3, 10, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_FIRE, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 10, MS_SILENT, MZ_TINY), MR_FIRE, MR_FIRE, M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("giant beetle", S_ANT, LVL(5, 6, 4, 0, 0), (G_GENO | 3), A(ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON, M1_ANIMAL | M1_NOHANDS | M1_POIS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_BLACK), MON("queen bee", S_ANT, LVL(9, 24, -4, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_STNG, AD_DRST, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1, 5, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL | M1_FLY | M1_NOHANDS | M1_OVIPAROUS | M1_POIS, M2_HOSTILE | M2_FEMALE | M2_PRINCE, 0, HI_LORD), /* * blobs */ MON("acid blob", S_BLOB, LVL(1, 3, 8, 0, 0), (G_GENO | 2), A(ATTK(AT_NONE, AD_ACID, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 10, MS_SILENT, MZ_TINY), MR_SLEEP | MR_POISON | MR_ACID | MR_STONE, MR_STONE, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_ACID, M2_WANDER | M2_NEUTER, 0, CLR_GREEN), MON("quivering blob", S_BLOB, LVL(5, 1, 8, 0, 0), (G_GENO | 2), A(ATTK(AT_TUCH, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 100, MS_SILENT, MZ_SMALL), MR_SLEEP | MR_POISON, MR_POISON, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, M2_WANDER | M2_HOSTILE | M2_NEUTER, 0, CLR_WHITE), MON("gelatinous cube", S_BLOB, LVL(6, 6, 8, 0, 0), (G_GENO | 2), A(ATTK(AT_TUCH, AD_PLYS, 2, 4), ATTK(AT_NONE, AD_PLYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 150, MS_SILENT, MZ_LARGE), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON | MR_ACID | MR_STONE, MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_OMNIVORE | M1_ACID, M2_WANDER | M2_HOSTILE | M2_NEUTER, 0, CLR_CYAN), /* * cockatrice */ MON("chickatrice", S_COCKATRICE, LVL(4, 4, 8, 30, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 2), ATTK(AT_TUCH, AD_STON, 0, 0), ATTK(AT_NONE, AD_STON, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_HISS, MZ_TINY), MR_POISON | MR_STONE, MR_POISON | MR_STONE, M1_ANIMAL | M1_NOHANDS | M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("cockatrice", S_COCKATRICE, LVL(5, 6, 6, 30, 0), (G_GENO | 5), A(ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_TUCH, AD_STON, 0, 0), ATTK(AT_NONE, AD_STON, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_HISS, MZ_SMALL), MR_POISON | MR_STONE, MR_POISON | MR_STONE, M1_ANIMAL | M1_NOHANDS | M1_OMNIVORE | M1_OVIPAROUS, M2_HOSTILE, M3_INFRAVISIBLE, CLR_YELLOW), MON("pyrolisk", S_COCKATRICE, LVL(6, 6, 6, 30, 0), (G_GENO | 1), A(ATTK(AT_GAZE, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_HISS, MZ_SMALL), MR_POISON | MR_FIRE, MR_POISON | MR_FIRE, M1_ANIMAL | M1_NOHANDS | M1_OMNIVORE | M1_OVIPAROUS, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), /* * dogs & other canines */ MON("jackal", S_DOG, LVL(0, 12, 7, 0, 0), (G_GENO | G_SGROUP | 3), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("fox", S_DOG, LVL(0, 15, 7, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("coyote", S_DOG, LVL(1, 12, 7, 0, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("werejackal", S_DOG, LVL(2, 12, 7, 10, -7), (G_NOGEN | G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, MS_BARK, MZ_SMALL), MR_POISON, 0, M1_NOHANDS | M1_POIS | M1_REGEN | M1_CARNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("little dog", S_DOG, LVL(2, 18, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 150, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("dingo", S_DOG, LVL(4, 16, 5, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 200, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_YELLOW), MON("dog", S_DOG, LVL(4, 16, 5, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 200, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("large dog", S_DOG, LVL(6, 15, 4, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 250, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_STRONG | M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("wolf", S_DOG, LVL(5, 12, 4, 0, 0), (G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("werewolf", S_DOG, LVL(5, 12, 4, 20, -7), (G_NOGEN | G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, MS_BARK, MZ_MEDIUM), MR_POISON, 0, M1_NOHANDS | M1_POIS | M1_REGEN | M1_CARNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("winter wolf cub", S_DOG, LVL(5, 12, 4, 0, -5), (G_NOHELL | G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 8), ATTK(AT_BREA, AD_COLD, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(250, 200, MS_BARK, MZ_SMALL), MR_COLD, MR_COLD, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_CYAN), MON("warg", S_DOG, LVL(7, 12, 4, 0, -5), (G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 350, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("winter wolf", S_DOG, LVL(7, 12, 4, 20, 0), (G_NOHELL | G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_COLD, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 300, MS_BARK, MZ_LARGE), MR_COLD, MR_COLD, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, 0, CLR_CYAN), MON("hell hound pup", S_DOG, LVL(7, 12, 4, 20, -5), (G_HELL | G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, MS_BARK, MZ_SMALL), MR_FIRE, MR_FIRE, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("hell hound", S_DOG, LVL(12, 14, 2, 20, 0), (G_HELL | G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BREA, AD_FIRE, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_BARK, MZ_MEDIUM), MR_FIRE, MR_FIRE, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_RED), #ifdef CHARON MON("Cerberus", S_DOG, LVL(12, 10, 2, 20, -7), (G_NOGEN | G_UNIQ | G_HELL), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 350, MS_BARK, MZ_LARGE), MR_FIRE, MR_FIRE, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_NOPOLY | M2_HOSTILE | M2_STRONG | M2_PNAME | M2_MALE, M3_INFRAVISIBLE, CLR_RED), #endif /* * eyes */ MON("gas spore", S_EYE, LVL(1, 3, 10, 0, 0), (G_NOCORPSE | G_GENO | 1), A(ATTK(AT_BOOM, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_SMALL), 0, 0, M1_FLY | M1_BREATHLESS | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, M2_HOSTILE | M2_NEUTER, 0, CLR_GRAY), MON("floating eye", S_EYE, LVL(2, 1, 9, 10, 0), (G_GENO | 5), A(ATTK(AT_NONE, AD_PLYS, 0, 70), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_SMALL), 0, 0, M1_FLY | M1_AMPHIBIOUS | M1_NOLIMBS | M1_NOHEAD | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_BLUE), MON("freezing sphere", S_EYE, LVL(6, 13, 4, 0, 0), (G_NOCORPSE | G_NOHELL | G_GENO | 2), A(ATTK(AT_EXPL, AD_COLD, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_SMALL), MR_COLD, MR_COLD, M1_FLY | M1_BREATHLESS | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_WHITE), MON("flaming sphere", S_EYE, LVL(6, 13, 4, 0, 0), (G_NOCORPSE | G_GENO | 2), A(ATTK(AT_EXPL, AD_FIRE, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_SMALL), MR_FIRE, MR_FIRE, M1_FLY | M1_BREATHLESS | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_RED), MON("shocking sphere", S_EYE, LVL(6, 13, 4, 0, 0), (G_NOCORPSE | G_GENO | 2), A(ATTK(AT_EXPL, AD_ELEC, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, MS_SILENT, MZ_SMALL), MR_ELEC, MR_ELEC, M1_FLY | M1_BREATHLESS | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, HI_ZAP), #if 0 /* not yet implemented */ MON("beholder", S_EYE, LVL(6, 3, 4, 0, -10), (G_GENO | 2), A(ATTK(AT_GAZE, AD_SLOW, 0, 0), ATTK(AT_GAZE, AD_SLEE, 2,25), ATTK(AT_GAZE, AD_DISN, 0, 0), ATTK(AT_GAZE, AD_STON, 0, 0), ATTK(AT_GAZE, AD_CNCL, 2, 4), ATTK(AT_BITE, AD_PHYS, 2, 4)), SIZ(10, 10, MS_SILENT, MZ_SMALL), MR_COLD, 0, M1_FLY | M1_BREATHLESS | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, M2_NOPOLY | M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_BROWN), #endif /* * felines */ MON("kitten", S_FELINE, LVL(2, 18, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 150, MS_MEW, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_WANDER | M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("housecat", S_FELINE, LVL(4, 16, 5, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, MS_MEW, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("jaguar", S_FELINE, LVL(4, 15, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("lynx", S_FELINE, LVL(5, 15, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_GROWL, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN), MON("panther", S_FELINE, LVL(5, 15, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK), MON("large cat", S_FELINE, LVL(6, 15, 4, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(250, 250, MS_MEW, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_STRONG | M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("tiger", S_FELINE, LVL(6, 12, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_YELLOW), /* * gremlins and gargoyles */ MON("gremlin", S_GREMLIN, LVL(5, 12, 2, 25, -9), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_CURS, 0, 0), NO_ATTK, NO_ATTK), SIZ(100, 20, MS_LAUGH, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM | M1_HUMANOID | M1_POIS, M2_STALK, M3_INFRAVISIBLE, CLR_GREEN), MON("gargoyle", S_GREMLIN, LVL(6, 10, -4, 0, -9), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 200, MS_GRUNT, MZ_HUMAN), MR_STONE, MR_STONE, M1_HUMANOID | M1_THICK_HIDE | M1_BREATHLESS, M2_HOSTILE | M2_STRONG, 0, CLR_BROWN), MON("winged gargoyle", S_GREMLIN, LVL(9, 15, -2, 0, -12), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 300, MS_GRUNT, MZ_HUMAN), MR_STONE, MR_STONE, M1_FLY | M1_HUMANOID | M1_THICK_HIDE | M1_BREATHLESS | M1_OVIPAROUS, M2_LORD | M2_HOSTILE | M2_STRONG | M2_MAGIC, 0, HI_LORD), /* * humanoids */ MON("hobbit", S_HUMANOID, LVL(1, 9, 10, 0, 6), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 200, MS_HUMANOID, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GREEN), MON("dwarf", S_HUMANOID, LVL(2, 6, 10, 10, 4), (G_GENO | 3), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_DWARF | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("bugbear", S_HUMANOID, LVL(3, 9, 5, 0, -6), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1250, 250, MS_GROWL, MZ_LARGE), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("dwarf lord", S_HUMANOID, LVL(4, 6, 10, 10, 5), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, M2_DWARF | M2_STRONG | M2_LORD | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), MON("dwarf king", S_HUMANOID, LVL(6, 6, 10, 20, 6), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, M2_DWARF | M2_STRONG | M2_PRINCE | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("mind flayer", S_HUMANOID, LVL(9, 12, 5, 90, -8), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), NO_ATTK, NO_ATTK), SIZ(1450, 400, MS_HISS, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_FLY | M1_SEE_INVIS | M1_OMNIVORE, M2_HOSTILE | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_MAGENTA), MON("master mind flayer", S_HUMANOID, LVL(13, 12, 0, 90, -8), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1)), SIZ(1450, 400, MS_HISS, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_FLY | M1_SEE_INVIS | M1_OMNIVORE, M2_HOSTILE | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_MAGENTA), /* * imps & other minor demons/devils */ MON("manes", S_IMP, LVL(1, 3, 7, 0, -7), (G_GENO | G_LGROUP | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, MS_SILENT, MZ_SMALL), MR_SLEEP | MR_POISON, 0, M1_POIS, M2_HOSTILE | M2_STALK, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("homunculus", S_IMP, LVL(2, 12, 6, 10, -7), (G_GENO | 2), A(ATTK(AT_BITE, AD_SLEE, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 100, MS_SILENT, MZ_TINY), MR_SLEEP | MR_POISON, MR_SLEEP | MR_POISON, M1_FLY | M1_POIS, M2_STALK, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GREEN), MON("imp", S_IMP, LVL(3, 12, 2, 20, -7), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 10, MS_CUSS, MZ_TINY), 0, 0, M1_REGEN, M2_WANDER | M2_STALK, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("lemure", S_IMP, LVL(3, 3, 7, 0, -7), (G_HELL | G_GENO | G_LGROUP | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 100, MS_SILENT, MZ_MEDIUM), MR_SLEEP | MR_POISON, MR_SLEEP, M1_POIS | M1_REGEN, M2_HOSTILE | M2_WANDER | M2_STALK | M2_NEUTER, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("quasit", S_IMP, LVL(3, 15, 2, 20, -7), (G_GENO | 2), A(ATTK(AT_CLAW, AD_DRDX, 1, 2), ATTK(AT_CLAW, AD_DRDX, 1, 2), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_REGEN, M2_STALK, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), MON("tengu", S_IMP, LVL(6, 13, 5, 30, 7), (G_GENO | 3), A(ATTK(AT_BITE, AD_PHYS, 1, 7), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 200, MS_SQAWK, MZ_SMALL), MR_POISON, MR_POISON, M1_TPORT | M1_TPORT_CNTRL, M2_STALK, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_CYAN), /* * jellies */ MON("blue jelly", S_JELLY, LVL(4, 0, 8, 10, 0), (G_GENO | 2), A(ATTK(AT_NONE, AD_COLD, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 20, MS_SILENT, MZ_MEDIUM), MR_COLD | MR_POISON, MR_COLD | MR_POISON, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_BLUE), MON("spotted jelly", S_JELLY, LVL(5, 0, 8, 10, 0), (G_GENO | 1), A(ATTK(AT_NONE, AD_ACID, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 20, MS_SILENT, MZ_MEDIUM), MR_ACID | MR_STONE, 0, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_ACID | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_GREEN), MON("ochre jelly", S_JELLY, LVL(6, 3, 8, 20, 0), (G_GENO | 2), A(ATTK(AT_ENGL, AD_ACID, 3, 6), ATTK(AT_NONE, AD_ACID, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 20, MS_SILENT, MZ_MEDIUM), MR_ACID | MR_STONE, 0, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_ACID | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_BROWN), /* * kobolds */ MON("kobold", S_KOBOLD, LVL(0, 6, 10, 0, -2), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 100, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_HOSTILE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("large kobold", S_KOBOLD, LVL(1, 6, 10, 0, -3), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 150, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_HOSTILE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("kobold lord", S_KOBOLD, LVL(2, 6, 10, 0, -4), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 200, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_HOSTILE | M2_LORD | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("kobold shaman", S_KOBOLD, LVL(2, 6, 6, 10, -4), (G_GENO | 1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 150, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_HOSTILE | M2_MAGIC, M3_INFRAVISIBLE | M3_INFRAVISION, HI_ZAP), /* * leprechauns */ MON("leprechaun", S_LEPRECHAUN, LVL(5, 15, 8, 20, 0), (G_GENO | 4), A(ATTK(AT_CLAW, AD_SGLD, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 30, MS_LAUGH, MZ_TINY), 0, 0, M1_HUMANOID | M1_TPORT, M2_HOSTILE | M2_GREEDY, M3_INFRAVISIBLE, CLR_GREEN), /* * mimics */ MON("small mimic", S_MIMIC, LVL(7, 3, 7, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 200, MS_SILENT, MZ_MEDIUM), MR_ACID, 0, M1_BREATHLESS | M1_AMORPHOUS | M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOHEAD | M1_NOLIMBS | M1_THICK_HIDE | M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("large mimic", S_MIMIC, LVL(8, 3, 7, 10, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_STCK, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 400, MS_SILENT, MZ_LARGE), MR_ACID, 0, M1_CLING | M1_BREATHLESS | M1_AMORPHOUS | M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOHEAD | M1_NOLIMBS | M1_THICK_HIDE | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, 0, CLR_RED), MON("giant mimic", S_MIMIC, LVL(9, 3, 7, 20, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_STCK, 3, 6), ATTK(AT_CLAW, AD_STCK, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 500, MS_SILENT, MZ_LARGE), MR_ACID, 0, M1_CLING | M1_BREATHLESS | M1_AMORPHOUS | M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOHEAD | M1_NOLIMBS | M1_THICK_HIDE | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, 0, HI_LORD), /* * nymphs */ MON("wood nymph", S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT, M2_HOSTILE | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), MON("water nymph", S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT | M1_SWIM, M2_HOSTILE | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("mountain nymph", S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT, M2_HOSTILE | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, CLR_BROWN), /* * orcs */ MON("goblin", S_ORC, LVL(0, 6, 10, 0, -3), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 100, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), MON("hobgoblin", S_ORC, LVL(1, 9, 10, 0, -4), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 200, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), /* plain "orc" for zombie corpses only; not created at random */ MON("orc", S_ORC, LVL(1, 9, 10, 0, -3), (G_GENO | G_NOGEN | G_LGROUP), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 150, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_ORC | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("hill orc", S_ORC, LVL(2, 9, 10, 0, -4), (G_GENO | G_LGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 200, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_YELLOW), MON("Mordor orc", S_ORC, LVL(3, 5, 10, 0, -5), (G_GENO | G_LGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 200, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), MON("Uruk-hai", S_ORC, LVL(3, 7, 10, 0, -4), (G_GENO | G_LGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLACK), MON("orc shaman", S_ORC, LVL(3, 9, 5, 10, -5), (G_GENO | 1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 300, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_MAGIC, M3_INFRAVISIBLE | M3_INFRAVISION, HI_ZAP), MON("orc-captain", S_ORC, LVL(5, 5, 10, 0, -5), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1350, 350, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_ORC | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), /* * piercers */ MON("rock piercer", S_PIERCER, LVL(3, 1, 3, 0, 0), (G_GENO | 4), A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, MS_SILENT, MZ_SMALL), 0, 0, M1_CLING | M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOLIMBS | M1_CARNIVORE | M1_NOTAKE, M2_HOSTILE, 0, CLR_GRAY), MON("iron piercer", S_PIERCER, LVL(5, 1, 0, 0, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 300, MS_SILENT, MZ_MEDIUM), 0, 0, M1_CLING | M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOLIMBS | M1_CARNIVORE | M1_NOTAKE, M2_HOSTILE, 0, CLR_CYAN), MON("glass piercer", S_PIERCER, LVL(7, 1, 0, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 300, MS_SILENT, MZ_MEDIUM), MR_ACID, 0, M1_CLING | M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOLIMBS | M1_CARNIVORE | M1_NOTAKE, M2_HOSTILE, 0, CLR_WHITE), /* * quadrupeds */ MON("rothe", S_QUADRUPED, LVL(2, 9, 7, 0, 0), (G_GENO | G_SGROUP | 4), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 100, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("mumak", S_QUADRUPED, LVL(5, 9, 0, 0, -2), (G_GENO | 1), A(ATTK(AT_BUTT, AD_PHYS, 4, 12), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 500, MS_ROAR, MZ_LARGE), 0, 0, M1_ANIMAL | M1_THICK_HIDE | M1_NOHANDS | M1_HERBIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), MON("leocrotta", S_QUADRUPED, LVL(6, 18, 4, 10, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 500, MS_IMITATE, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_OMNIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_RED), MON("wumpus", S_QUADRUPED, LVL(8, 3, 2, 10, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 500, MS_BURBLE, MZ_LARGE), 0, 0, M1_CLING | M1_ANIMAL | M1_NOHANDS | M1_OMNIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_CYAN), MON("titanothere", S_QUADRUPED, LVL(12, 12, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2650, 650, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_THICK_HIDE | M1_NOHANDS | M1_HERBIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), MON("baluchitherium", S_QUADRUPED, LVL(14, 12, 5, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 5, 4), ATTK(AT_CLAW, AD_PHYS, 5, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(3800, 800, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_THICK_HIDE | M1_NOHANDS | M1_HERBIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), MON("mastodon", S_QUADRUPED, LVL(20, 12, 5, 0, 0), (G_GENO | 1), A(ATTK(AT_BUTT, AD_PHYS, 4, 8), ATTK(AT_BUTT, AD_PHYS, 4, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(3800, 800, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_THICK_HIDE | M1_NOHANDS | M1_HERBIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_BLACK), /* * rodents */ MON("sewer rat", S_RODENT, LVL(0, 12, 7, 0, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 12, MS_SQEEK, MZ_TINY), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("giant rat", S_RODENT, LVL(1, 10, 7, 0, 0), (G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_SQEEK, MZ_TINY), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("rabid rat", S_RODENT, LVL(2, 12, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_DRCO, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 5, MS_SQEEK, MZ_TINY), MR_POISON, 0, M1_ANIMAL | M1_NOHANDS | M1_POIS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("wererat", S_RODENT, LVL(2, 12, 6, 10, -7), (G_NOGEN | G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(40, 30, MS_SQEEK, MZ_TINY), MR_POISON, 0, M1_NOHANDS | M1_POIS | M1_REGEN | M1_CARNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("rock mole", S_RODENT, LVL(3, 3, 0, 20, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_SILENT, MZ_SMALL), 0, 0, M1_TUNNEL | M1_ANIMAL | M1_NOHANDS | M1_METALLIVORE, M2_HOSTILE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY), MON("woodchuck", S_RODENT, LVL(3, 3, 0, 20, 0), (G_NOGEN | G_GENO), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_SILENT, MZ_SMALL), 0, 0, M1_TUNNEL /*LOGGING*/ | M1_ANIMAL | M1_NOHANDS | M1_SWIM | M1_HERBIVORE, /* In reality, they tunnel instead of cutting lumber. Oh, well. */ M2_WANDER | M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), /* * spiders & scorpions (keep webmaker() in sync if new critters are added) */ MON("cave spider", S_SPIDER, LVL(1, 12, 3, 0, 0), (G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 50, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, M1_CONCEAL | M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_GRAY), MON("centipede", S_SPIDER, LVL(2, 4, 3, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_DRST, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 50, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, M1_CONCEAL | M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_YELLOW), MON("giant spider", S_SPIDER, LVL(5, 15, 4, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON, M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, 0, CLR_MAGENTA), MON("scorpion", S_SPIDER, LVL(5, 15, 3, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_STNG, AD_DRST, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 100, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_CONCEAL | M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_RED), /* * trappers, lurkers, &c */ MON("lurker above", S_TRAPPER, LVL(10, 3, 3, 0, 0), (G_GENO | 2), A(ATTK(AT_ENGL, AD_DGST, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 350, MS_SILENT, MZ_HUGE), 0, 0, M1_HIDE | M1_FLY | M1_ANIMAL | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_CARNIVORE, M2_HOSTILE | M2_STALK | M2_STRONG, 0, CLR_GRAY), MON("trapper", S_TRAPPER, LVL(12, 3, 3, 0, 0), (G_GENO | 2), A(ATTK(AT_ENGL, AD_DGST, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 350, MS_SILENT, MZ_HUGE), 0, 0, M1_HIDE | M1_ANIMAL | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_CARNIVORE, M2_HOSTILE | M2_STALK | M2_STRONG, 0, CLR_GREEN), /* * unicorns and horses */ MON("pony", S_UNICORN, LVL(3, 16, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_KICK, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 250, MS_NEIGH, MZ_MEDIUM), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_HERBIVORE, M2_WANDER | M2_STRONG | M2_DOMESTIC, M3_INFRAVISIBLE, CLR_BROWN), MON("white unicorn", S_UNICORN, LVL(4, 24, 2, 70, 7), (G_GENO | 2), A(ATTK(AT_BUTT, AD_PHYS, 1, 12), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON, M1_NOHANDS | M1_HERBIVORE, M2_WANDER | M2_STRONG | M2_JEWELS, M3_INFRAVISIBLE, CLR_WHITE), MON("gray unicorn", S_UNICORN, LVL(4, 24, 2, 70, 0), (G_GENO | 1), A(ATTK(AT_BUTT, AD_PHYS, 1, 12), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON, M1_NOHANDS | M1_HERBIVORE, M2_WANDER | M2_STRONG | M2_JEWELS, M3_INFRAVISIBLE, CLR_GRAY), MON("black unicorn", S_UNICORN, LVL(4, 24, 2, 70, -7), (G_GENO | 1), A(ATTK(AT_BUTT, AD_PHYS, 1, 12), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON, M1_NOHANDS | M1_HERBIVORE, M2_WANDER | M2_STRONG | M2_JEWELS, M3_INFRAVISIBLE, CLR_BLACK), MON("horse", S_UNICORN, LVL(5, 20, 5, 0, 0), (G_GENO | 2), A(ATTK(AT_KICK, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 300, MS_NEIGH, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_HERBIVORE, M2_WANDER | M2_STRONG | M2_DOMESTIC, M3_INFRAVISIBLE, CLR_BROWN), MON("warhorse", S_UNICORN, LVL(7, 24, 4, 0, 0), (G_GENO | 2), A(ATTK(AT_KICK, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1800, 350, MS_NEIGH, MZ_LARGE), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_HERBIVORE, M2_WANDER | M2_STRONG | M2_DOMESTIC, M3_INFRAVISIBLE, CLR_BROWN), /* * vortices */ MON("fog cloud", S_VORTEX, LVL(3, 1, 0, 0, 0), (G_GENO | G_NOCORPSE | 2), A(ATTK(AT_ENGL, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_AMORPHOUS | M1_UNSOLID, M2_HOSTILE | M2_NEUTER, 0, CLR_GRAY), MON("dust vortex", S_VORTEX, LVL(4, 20, 2, 30, 0), (G_GENO | G_NOCORPSE | 2), A(ATTK(AT_ENGL, AD_BLND, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, M2_HOSTILE | M2_NEUTER, 0, CLR_BROWN), MON("ice vortex", S_VORTEX, LVL(5, 20, 2, 30, 0), (G_NOHELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_COLD, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_COLD | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_CYAN), MON("energy vortex", S_VORTEX, LVL(6, 20, 2, 30, 0), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_ELEC, 1, 6), ATTK(AT_ENGL, AD_DREN, 4, 6), ATTK(AT_NONE, AD_ELEC, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_ELEC | MR_SLEEP | MR_DISINT | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID, M2_HOSTILE | M2_NEUTER, 0, HI_ZAP), MON("steam vortex", S_VORTEX, LVL(7, 22, 2, 30, 0), (G_HELL | G_GENO | G_NOCORPSE | 2), A(ATTK(AT_ENGL, AD_FIRE, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_BLUE), MON("fire vortex", S_VORTEX, LVL(8, 22, 2, 30, 0), (G_HELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_FIRE, 1, 10), ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW), /* * worms */ MON("baby long worm", S_WORM, LVL(5, 3, 5, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 250, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE | M1_NOTAKE, M2_HOSTILE, 0, CLR_BROWN), MON("baby purple worm", S_WORM, LVL(8, 3, 5, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 250, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_MAGENTA), MON("long worm", S_WORM, LVL(9, 3, 5, 10, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_SILENT, MZ_GIGANTIC), 0, 0, M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_OVIPAROUS | M1_CARNIVORE | M1_NOTAKE, M2_HOSTILE | M2_STRONG | M2_NASTY, 0, CLR_BROWN), MON("purple worm", S_WORM, LVL(15, 9, 6, 20, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 2, 8), ATTK(AT_ENGL, AD_DGST, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2700, 700, MS_SILENT, MZ_GIGANTIC), 0, 0, M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY, 0, CLR_MAGENTA), /* * xan, &c */ MON("grid bug", S_XAN, LVL(0, 12, 9, 0, 0), (G_GENO | G_SGROUP | G_NOCORPSE | 3), A(ATTK(AT_BITE, AD_ELEC, 1, 1), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(15, 10, MS_BUZZ, MZ_TINY), MR_ELEC | MR_POISON, 0, M1_ANIMAL, M2_HOSTILE, M3_INFRAVISIBLE, CLR_MAGENTA), MON("xan", S_XAN, LVL(7, 18, -4, 0, 0), (G_GENO | 3), A(ATTK(AT_STNG, AD_LEGS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 300, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_POIS, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), /* * lights */ MON("yellow light", S_LIGHT, LVL(3, 15, 0, 0, 0), (G_NOCORPSE | G_GENO | 4), A(ATTK(AT_EXPL, AD_BLND, 10, 20), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_SMALL), MR_FIRE | MR_COLD | MR_ELEC | MR_DISINT | MR_SLEEP | MR_POISON | MR_ACID | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW), MON("black light", S_LIGHT, LVL(5, 15, 0, 0, 0), (G_NOCORPSE | G_GENO | 2), A(ATTK(AT_EXPL, AD_HALU, 10, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_SMALL), MR_FIRE | MR_COLD | MR_ELEC | MR_DISINT | MR_SLEEP | MR_POISON | MR_ACID | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID | M1_SEE_INVIS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_BLACK), /* * zruty */ MON("zruty", S_ZRUTY, LVL(9, 8, 3, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 600, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), /* * Angels and other lawful minions */ MON("couatl", S_ANGEL, LVL(8, 10, 5, 30, 7), (G_NOHELL | G_SGROUP | G_NOCORPSE | 1), A(ATTK(AT_BITE, AD_DRST, 2, 4), ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_HUGS, AD_WRAP, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 400, MS_HISS, MZ_LARGE), MR_POISON, 0, M1_FLY | M1_NOHANDS | M1_SLITHY | M1_POIS, M2_MINION | M2_STALK | M2_STRONG | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GREEN), MON("Aleax", S_ANGEL, LVL(10, 8, 0, 30, 7), (G_NOHELL | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_IMITATE, MZ_HUMAN), MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_HUMANOID | M1_SEE_INVIS, M2_MINION | M2_STALK | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_YELLOW), /* Angels start with the emin extension attached, and usually have the isminion flag set; however, non-minion Angels can be tamed and will switch to edog (guardian Angel is handled specially and always sticks with emin) */ MON("Angel", S_ANGEL, LVL(14, 10, -4, 55, 12), (G_NOHELL | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_MAGM, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_CUSS, MZ_HUMAN), MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_FLY | M1_HUMANOID | M1_SEE_INVIS, M2_NOPOLY | M2_MINION | M2_STALK | M2_STRONG | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_WHITE), MON("ki-rin", S_ANGEL, LVL(16, 18, -5, 90, 15), (G_NOHELL | G_NOCORPSE | 1), A(ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_BUTT, AD_PHYS, 3, 6), ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEIGH, MZ_LARGE), 0, 0, M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_SEE_INVIS, M2_NOPOLY | M2_MINION | M2_STALK | M2_STRONG | M2_NASTY | M2_LORD, M3_INFRAVISIBLE | M3_INFRAVISION, HI_GOLD), MON("Archon", S_ANGEL, LVL(19, 16, -6, 80, 15), (G_NOHELL | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_GAZE, AD_BLND, 2, 6), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_MAGC, AD_SPEL, 4, 6), NO_ATTK), SIZ(WT_HUMAN, 400, MS_CUSS, MZ_LARGE), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_FLY | M1_HUMANOID | M1_SEE_INVIS | M1_REGEN, M2_NOPOLY | M2_MINION | M2_STALK | M2_STRONG | M2_NASTY | M2_LORD | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), /* * Bats */ MON("bat", S_BAT, LVL(0, 22, 8, 0, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 20, MS_SQEEK, MZ_TINY), 0, 0, M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_WANDER, M3_INFRAVISIBLE, CLR_BROWN), MON("giant bat", S_BAT, LVL(2, 22, 7, 0, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_SQEEK, MZ_SMALL), 0, 0, M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_WANDER | M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("raven", S_BAT, LVL(4, 20, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_BLND, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(40, 20, MS_SQAWK, MZ_SMALL), 0, 0, M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_WANDER | M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK), MON("vampire bat", S_BAT, LVL(5, 20, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRST, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 20, MS_SQEEK, MZ_SMALL), MR_SLEEP | MR_POISON, 0, M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_POIS | M1_REGEN | M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK), /* * Centaurs */ MON("plains centaur", S_CENTAUR, LVL(4, 18, 4, 0, 0), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 500, MS_HUMANOID, MZ_LARGE), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_GREEDY | M2_COLLECT, M3_INFRAVISIBLE, CLR_BROWN), MON("forest centaur", S_CENTAUR, LVL(5, 18, 3, 10, -1), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2550, 600, MS_HUMANOID, MZ_LARGE), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_GREEDY | M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), MON("mountain centaur", S_CENTAUR, LVL(6, 20, 2, 10, -3), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 10), ATTK(AT_KICK, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2550, 500, MS_HUMANOID, MZ_LARGE), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_GREEDY | M2_COLLECT, M3_INFRAVISIBLE, CLR_CYAN), /* * Dragons */ /* The order of the dragons is VERY IMPORTANT. Quite a few * pieces of code depend on gray being first and yellow being last. * The code also depends on the *order* being the same as that for * dragon scale mail and dragon scales in objects.c. Baby dragons * cannot confer intrinsics, to avoid polyself/egg abuse. * * As reptiles, dragons are cold-blooded and thus aren't seen * with infravision. Red dragons are the exception. */ MON("baby gray dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_GRAY), MON("baby silver dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, DRAGON_SILVER), #if 0 /* DEFERRED */ MON("baby shimmering dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_CYAN), #endif MON("baby red dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_FIRE, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, M3_INFRAVISIBLE, CLR_RED), MON("baby white dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_COLD, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_WHITE), MON("baby orange dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_SLEEP, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_ORANGE), MON("baby black dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_DISINT, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_BLACK), MON("baby blue dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_ELEC, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_BLUE), MON("baby green dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_POISON, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE | M1_POIS, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_GREEN), MON("baby yellow dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_ACID | MR_STONE, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE | M1_ACID, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, CLR_YELLOW), MON("gray dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO | 1), A(ATTK(AT_BREA, AD_MAGM, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_GRAY), MON("silver dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO | 1), A(ATTK(AT_BREA, AD_COLD, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_COLD, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, DRAGON_SILVER), #if 0 /* DEFERRED */ MON("shimmering dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO | 1), A(ATTK(AT_BREA, AD_MAGM, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_CYAN), #endif MON("red dragon", S_DRAGON, LVL(15, 9, -1, 20, -4), (G_GENO | 1), A(ATTK(AT_BREA, AD_FIRE, 6, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_FIRE, MR_FIRE, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, M3_INFRAVISIBLE, CLR_RED), MON("white dragon", S_DRAGON, LVL(15, 9, -1, 20, -5), (G_GENO | 1), A(ATTK(AT_BREA, AD_COLD, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_COLD, MR_COLD, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_WHITE), MON("orange dragon", S_DRAGON, LVL(15, 9, -1, 20, 5), (G_GENO | 1), A(ATTK(AT_BREA, AD_SLEE, 4, 25), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_SLEEP, MR_SLEEP, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_ORANGE), MON("black dragon", S_DRAGON, LVL(15, 9, -1, 20, -6), (G_GENO | 1), A(ATTK(AT_BREA, AD_DISN, 4, 10), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_DISINT, MR_DISINT, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_BLACK), MON("blue dragon", S_DRAGON, LVL(15, 9, -1, 20, -7), (G_GENO | 1), A(ATTK(AT_BREA, AD_ELEC, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_ELEC, MR_ELEC, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_BLUE), MON("green dragon", S_DRAGON, LVL(15, 9, -1, 20, 6), (G_GENO | 1), A(ATTK(AT_BREA, AD_DRST, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_POISON, MR_POISON, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE | M1_POIS, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_GREEN), MON("yellow dragon", S_DRAGON, LVL(15, 9, -1, 20, 7), (G_GENO | 1), A(ATTK(AT_BREA, AD_ACID, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, MS_ROAR, MZ_GIGANTIC), MR_ACID | MR_STONE, MR_STONE, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_SEE_INVIS | M1_OVIPAROUS | M1_CARNIVORE | M1_ACID, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, 0, CLR_YELLOW), /* * Elementals */ MON("stalker", S_ELEMENTAL, LVL(8, 12, 3, 0, 0), (G_GENO | 3), A(ATTK(AT_CLAW, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 400, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_FLY | M1_SEE_INVIS, M2_WANDER | M2_STALK | M2_HOSTILE | M2_STRONG, M3_INFRAVISION, CLR_WHITE), MON("air elemental", S_ELEMENTAL, LVL(8, 36, 2, 30, 0), (G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_POISON | MR_STONE, 0, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_BREATHLESS | M1_UNSOLID | M1_FLY, M2_STRONG | M2_NEUTER, 0, CLR_CYAN), MON("fire elemental", S_ELEMENTAL, LVL(8, 12, 2, 30, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_FIRE, 3, 6), ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_POISON | MR_STONE, 0, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_BREATHLESS | M1_UNSOLID | M1_FLY | M1_NOTAKE, M2_STRONG | M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW), MON("earth elemental", S_ELEMENTAL, LVL(8, 6, 2, 30, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_COLD | MR_POISON | MR_STONE, 0, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_BREATHLESS | M1_WALLWALK | M1_THICK_HIDE, M2_STRONG | M2_NEUTER, 0, CLR_BROWN), MON("water elemental", S_ELEMENTAL, LVL(8, 6, 2, 30, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 5, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 0, MS_SILENT, MZ_HUGE), MR_POISON | MR_STONE, 0, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_BREATHLESS | M1_UNSOLID | M1_AMPHIBIOUS | M1_SWIM, M2_STRONG | M2_NEUTER, 0, CLR_BLUE), /* * Fungi */ MON("lichen", S_FUNGUS, LVL(0, 1, 9, 0, 0), (G_GENO | 4), A(ATTK(AT_TUCH, AD_STCK, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 200, MS_SILENT, MZ_SMALL), 0, 0, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_BRIGHT_GREEN), MON("brown mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO | 1), A(ATTK(AT_NONE, AD_COLD, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, MS_SILENT, MZ_SMALL), MR_COLD | MR_POISON, MR_COLD | MR_POISON, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_BROWN), MON("yellow mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO | 2), A(ATTK(AT_NONE, AD_STUN, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_POIS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_YELLOW), MON("green mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO | 1), A(ATTK(AT_NONE, AD_ACID, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, MS_SILENT, MZ_SMALL), MR_ACID | MR_STONE, MR_STONE, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_ACID | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_GREEN), MON("red mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO | 1), A(ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, MS_SILENT, MZ_SMALL), MR_FIRE | MR_POISON, MR_FIRE | MR_POISON, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, M3_INFRAVISIBLE, CLR_RED), MON("shrieker", S_FUNGUS, LVL(3, 1, 7, 0, 0), (G_GENO | 1), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, MS_SHRIEK, MZ_SMALL), MR_POISON, MR_POISON, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_MAGENTA), MON("violet fungus", S_FUNGUS, LVL(3, 1, 7, 0, 0), (G_GENO | 2), A(ATTK(AT_TUCH, AD_PHYS, 1, 4), ATTK(AT_TUCH, AD_STCK, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, M2_HOSTILE | M2_NEUTER, 0, CLR_MAGENTA), /* * Gnomes */ MON("gnome", S_GNOME, LVL(1, 6, 10, 4, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 100, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_GNOME | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("gnome lord", S_GNOME, LVL(3, 8, 10, 4, 0), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 120, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_GNOME | M2_LORD | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), MON("gnomish wizard", S_GNOME, LVL(3, 10, 4, 10, 0), (G_GENO | 1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 120, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_GNOME | M2_MAGIC, M3_INFRAVISIBLE | M3_INFRAVISION, HI_ZAP), MON("gnome king", S_GNOME, LVL(5, 10, 10, 20, 0), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 150, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_GNOME | M2_PRINCE | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), #ifdef SPLITMON_1 }; #endif #endif /* !SPLITMON_2 */ /* horrible kludge alert: * This is a compiler-specific kludge to allow the compilation of monst.o in * two pieces, by defining first SPLITMON_1 and then SPLITMON_2. The * resulting assembler files (monst1.s and monst2.s) are then run through * sed to change local symbols, concatenated together, and assembled to * produce monst.o. THIS ONLY WORKS WITH THE ATARI GCC, and should only * be done if you don't have enough memory to compile monst.o the "normal" * way. --ERS */ #ifndef SPLITMON_1 #ifdef SPLITMON_2 struct permonst _mons2[] = { #endif /* * giant Humanoids */ MON("giant", S_GIANT, LVL(6, 6, 0, 0, 2), (G_GENO | G_NOGEN | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("stone giant", S_GIANT, LVL(6, 6, 0, 0, 2), (G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), MON("hill giant", S_GIANT, LVL(8, 10, 6, 0, -2), (G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2200, 700, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_CYAN), MON("fire giant", S_GIANT, LVL(9, 12, 4, 5, 2), (G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, MS_BOAST, MZ_HUGE), MR_FIRE, MR_FIRE, M1_HUMANOID | M1_CARNIVORE, M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_YELLOW), MON("frost giant", S_GIANT, LVL(10, 12, 3, 10, -3), (G_NOHELL | G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, MS_BOAST, MZ_HUGE), MR_COLD, MR_COLD, M1_HUMANOID | M1_CARNIVORE, M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_WHITE), MON("ettin", S_GIANT, LVL(10, 12, 3, 0, 0), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_WEAP, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 500, MS_GRUNT, MZ_HUGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("storm giant", S_GIANT, LVL(16, 12, 3, 10, -3), (G_GENO | G_SGROUP | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, MS_BOAST, MZ_HUGE), MR_ELEC, MR_ELEC, M1_HUMANOID | M1_CARNIVORE, M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_JEWELS, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), MON("titan", S_GIANT, LVL(16, 18, -3, 70, 9), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2300, 900, MS_SPELL, MZ_HUGE), 0, 0, M1_FLY | M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_ROCKTHROW | M2_NASTY | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_MAGENTA), MON("minotaur", S_GIANT, LVL(15, 15, 6, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_CLAW, AD_PHYS, 3, 10), ATTK(AT_CLAW, AD_PHYS, 3, 10), ATTK(AT_BUTT, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 700, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), /* 'I' is a visual marker for all invisible monsters and must be unused */ /* * Jabberwock */ /* the illustration from _Through_the_Looking_Glass_ depicts hands as well as wings */ MON("jabberwock", S_JABBERWOCK, LVL(15, 12, -2, 50, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 10), ATTK(AT_BITE, AD_PHYS, 2, 10), ATTK(AT_CLAW, AD_PHYS, 2, 10), ATTK(AT_CLAW, AD_PHYS, 2, 10), NO_ATTK, NO_ATTK), SIZ(1300, 600, MS_BURBLE, MZ_LARGE), 0, 0, M1_ANIMAL | M1_FLY | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE, CLR_ORANGE), #if 0 /* DEFERRED */ MON("vorpal jabberwock", S_JABBERWOCK, LVL(20, 12, -2, 50, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 3, 10), ATTK(AT_BITE, AD_PHYS, 3, 10), ATTK(AT_CLAW, AD_PHYS, 3, 10), ATTK(AT_CLAW, AD_PHYS, 3, 10), NO_ATTK, NO_ATTK), SIZ(1300, 600, MS_BURBLE, MZ_LARGE), 0, 0, M1_ANIMAL | M1_FLY | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE, HI_LORD), #endif /* * Kops */ MON("Keystone Kop", S_KOP, LVL(1, 6, 10, 10, 9), (G_GENO | G_LGROUP | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN | M2_WANDER | M2_HOSTILE | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("Kop Sergeant", S_KOP, LVL(2, 8, 10, 10, 10), (G_GENO | G_SGROUP | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN | M2_WANDER | M2_HOSTILE | M2_STRONG | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("Kop Lieutenant", S_KOP, LVL(3, 10, 10, 20, 11), (G_GENO | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN | M2_WANDER | M2_HOSTILE | M2_STRONG | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE, CLR_CYAN), MON("Kop Kaptain", S_KOP, LVL(4, 12, 10, 20, 12), (G_GENO | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN | M2_WANDER | M2_HOSTILE | M2_STRONG | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE, HI_LORD), /* * Liches */ MON("lich", S_LICH, LVL(11, 6, 0, 30, -9), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_TUCH, AD_COLD, 1, 10), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, MS_MUMBLE, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, MR_COLD, M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_HOSTILE | M2_MAGIC, M3_INFRAVISION, CLR_BROWN), MON("demilich", S_LICH, LVL(14, 9, -2, 60, -12), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_TUCH, AD_COLD, 3, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, MS_MUMBLE, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, MR_COLD, M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_HOSTILE | M2_MAGIC, M3_INFRAVISION, CLR_RED), MON("master lich", S_LICH, LVL(17, 9, -4, 90, -15), (G_HELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_TUCH, AD_COLD, 3, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, MS_MUMBLE, MZ_HUMAN), MR_FIRE | MR_COLD | MR_SLEEP | MR_POISON, MR_FIRE | MR_COLD, M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_HOSTILE | M2_MAGIC, M3_WANTSBOOK | M3_INFRAVISION, HI_LORD), MON("arch-lich", S_LICH, LVL(25, 9, -6, 90, -15), (G_HELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_TUCH, AD_COLD, 5, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, MS_MUMBLE, MZ_HUMAN), MR_FIRE | MR_COLD | MR_SLEEP | MR_ELEC | MR_POISON, MR_FIRE | MR_COLD, M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_HOSTILE | M2_MAGIC, M3_WANTSBOOK | M3_INFRAVISION, HI_LORD), /* * Mummies */ MON("kobold mummy", S_MUMMY, LVL(3, 8, 6, 20, -2), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 50, MS_SILENT, MZ_SMALL), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE, M3_INFRAVISION, CLR_BROWN), MON("gnome mummy", S_MUMMY, LVL(4, 10, 6, 20, -3), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 50, MS_SILENT, MZ_SMALL), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE | M2_GNOME, M3_INFRAVISION, CLR_RED), MON("orc mummy", S_MUMMY, LVL(5, 10, 5, 20, -4), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 75, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE | M2_ORC | M2_GREEDY | M2_JEWELS, M3_INFRAVISION, CLR_GRAY), MON("dwarf mummy", S_MUMMY, LVL(5, 10, 5, 20, -4), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 150, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE | M2_DWARF | M2_GREEDY | M2_JEWELS, M3_INFRAVISION, CLR_RED), MON("elf mummy", S_MUMMY, LVL(6, 12, 4, 30, -5), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 175, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE | M2_ELF, M3_INFRAVISION, CLR_GREEN), MON("human mummy", S_MUMMY, LVL(6, 12, 4, 30, -5), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE, M3_INFRAVISION, CLR_GRAY), MON("ettin mummy", S_MUMMY, LVL(7, 12, 4, 30, -6), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 250, MS_SILENT, MZ_HUGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE | M2_STRONG, M3_INFRAVISION, CLR_BLUE), MON("giant mummy", S_MUMMY, LVL(8, 14, 3, 30, -7), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2050, 375, MS_SILENT, MZ_HUGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_HOSTILE | M2_GIANT | M2_STRONG | M2_JEWELS, M3_INFRAVISION, CLR_CYAN), /* * Nagas */ MON("red naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, MS_MUMBLE, MZ_LARGE), MR_FIRE | MR_POISON, MR_FIRE | MR_POISON, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_NOTAKE | M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_RED), MON("black naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, MS_MUMBLE, MZ_LARGE), MR_POISON | MR_ACID | MR_STONE, MR_POISON | MR_STONE, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_ACID | M1_NOTAKE | M1_CARNIVORE, M2_STRONG, 0, CLR_BLACK), MON("golden naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, MS_MUMBLE, MZ_LARGE), MR_POISON, MR_POISON, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_NOTAKE | M1_OMNIVORE, M2_STRONG, 0, HI_GOLD), MON("guardian naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, MS_MUMBLE, MZ_LARGE), MR_POISON, MR_POISON, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_NOTAKE | M1_OMNIVORE, M2_STRONG, 0, CLR_GREEN), MON("red naga", S_NAGA, LVL(6, 12, 4, 0, -4), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BREA, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, MS_MUMBLE, MZ_HUGE), MR_FIRE | MR_POISON, MR_FIRE | MR_POISON, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_OVIPAROUS | M1_NOTAKE | M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_RED), MON("black naga", S_NAGA, LVL(8, 14, 2, 10, 4), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_SPIT, AD_ACID, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, MS_MUMBLE, MZ_HUGE), MR_POISON | MR_ACID | MR_STONE, MR_POISON | MR_STONE, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_OVIPAROUS | M1_ACID | M1_NOTAKE | M1_CARNIVORE, M2_STRONG, 0, CLR_BLACK), MON("golden naga", S_NAGA, LVL(10, 14, 2, 70, 5), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_MAGC, AD_SPEL, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, MS_MUMBLE, MZ_HUGE), MR_POISON, MR_POISON, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_OVIPAROUS | M1_NOTAKE | M1_OMNIVORE, M2_STRONG, 0, HI_GOLD), MON("guardian naga", S_NAGA, LVL(12, 16, 0, 50, 7), (G_GENO | 1), A(ATTK(AT_BITE, AD_PLYS, 1, 6), ATTK(AT_SPIT, AD_DRST, 1, 6), ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, MS_MUMBLE, MZ_HUGE), MR_POISON, MR_POISON, M1_NOLIMBS | M1_SLITHY | M1_THICK_HIDE | M1_OVIPAROUS | M1_POIS | M1_NOTAKE | M1_OMNIVORE, M2_STRONG, 0, CLR_GREEN), /* * Ogres */ MON("ogre", S_OGRE, LVL(5, 10, 5, 0, -3), (G_SGROUP | G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1600, 500, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("ogre lord", S_OGRE, LVL(7, 12, 3, 30, -5), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 700, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_STRONG | M2_LORD | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("ogre king", S_OGRE, LVL(9, 14, 4, 60, -7), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 3, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 750, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_STRONG | M2_PRINCE | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), /* * Puddings * * must be in the same order as the pudding globs in objects.c */ MON("gray ooze", S_PUDDING, LVL(3, 1, 8, 0, 0), (G_GENO | G_NOCORPSE | 2), A(ATTK(AT_BITE, AD_RUST, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, MS_SILENT, MZ_MEDIUM), MR_FIRE | MR_COLD | MR_POISON | MR_ACID | MR_STONE, MR_FIRE | MR_COLD | MR_POISON, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_OMNIVORE | M1_ACID, M2_HOSTILE | M2_NEUTER, 0, CLR_GRAY), MON("brown pudding", S_PUDDING, LVL(5, 3, 8, 0, 0), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_BITE, AD_DCAY, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, MS_SILENT, MZ_MEDIUM), MR_COLD | MR_ELEC | MR_POISON | MR_ACID | MR_STONE, MR_COLD | MR_ELEC | MR_POISON, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_OMNIVORE | M1_ACID, M2_HOSTILE | M2_NEUTER, 0, CLR_BROWN), MON("green slime", S_PUDDING, LVL(6, 6, 6, 0, 0), (G_HELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_TUCH, AD_SLIM, 1, 4), ATTK(AT_NONE, AD_SLIM, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 150, MS_SILENT, MZ_LARGE), MR_COLD | MR_ELEC | MR_POISON | MR_ACID | MR_STONE, 0, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_OMNIVORE | M1_ACID | M1_POIS, M2_HOSTILE | M2_NEUTER, 0, CLR_GREEN), MON("black pudding", S_PUDDING, LVL(10, 6, 6, 0, 0), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_BITE, AD_CORR, 3, 8), ATTK(AT_NONE, AD_CORR, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 250, MS_SILENT, MZ_LARGE), MR_COLD | MR_ELEC | MR_POISON | MR_ACID | MR_STONE, MR_COLD | MR_ELEC | MR_POISON, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_OMNIVORE | M1_ACID, M2_HOSTILE | M2_NEUTER, 0, CLR_BLACK), /* * Quantum mechanics */ MON("quantum mechanic", S_QUANTMECH, LVL(7, 12, 3, 10, 0), (G_GENO | 3), A(ATTK(AT_CLAW, AD_TLPT, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 20, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE | M1_POIS | M1_TPORT, M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN), /* * Rust monster or disenchanter */ MON("rust monster", S_RUSTMONST, LVL(5, 18, 2, 0, 0), (G_GENO | 2), A(ATTK(AT_TUCH, AD_RUST, 0, 0), ATTK(AT_TUCH, AD_RUST, 0, 0), ATTK(AT_NONE, AD_RUST, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 250, MS_SILENT, MZ_MEDIUM), 0, 0, M1_SWIM | M1_ANIMAL | M1_NOHANDS | M1_METALLIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("disenchanter", S_RUSTMONST, LVL(12, 12, -10, 0, -3), (G_HELL | G_GENO | 2), A(ATTK(AT_CLAW, AD_ENCH, 4, 4), ATTK(AT_NONE, AD_ENCH, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 200, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLUE), /* * Snakes */ MON("garter snake", S_SNAKE, LVL(1, 8, 8, 0, 0), (G_LGROUP | G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 60, MS_HISS, MZ_TINY), 0, 0, M1_SWIM | M1_CONCEAL | M1_NOLIMBS | M1_ANIMAL | M1_SLITHY | M1_OVIPAROUS | M1_CARNIVORE | M1_NOTAKE, 0, 0, CLR_GREEN), MON("snake", S_SNAKE, LVL(4, 15, 3, 0, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_DRST, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 80, MS_HISS, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM | M1_CONCEAL | M1_NOLIMBS | M1_ANIMAL | M1_SLITHY | M1_POIS | M1_OVIPAROUS | M1_CARNIVORE | M1_NOTAKE, M2_HOSTILE, 0, CLR_BROWN), MON("water moccasin", S_SNAKE, LVL(4, 15, 3, 0, 0), (G_GENO | G_NOGEN | G_LGROUP), A(ATTK(AT_BITE, AD_DRST, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 80, MS_HISS, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM | M1_CONCEAL | M1_NOLIMBS | M1_ANIMAL | M1_SLITHY | M1_POIS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE, 0, CLR_RED), MON("python", S_SNAKE, LVL(6, 3, 5, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 1, 4), ATTK(AT_TUCH, AD_PHYS, 0, 0), ATTK(AT_HUGS, AD_WRAP, 1, 4), ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK), SIZ(250, 100, MS_HISS, MZ_LARGE), 0, 0, M1_SWIM | M1_NOLIMBS | M1_ANIMAL | M1_SLITHY | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE | M2_STRONG, M3_INFRAVISION, CLR_MAGENTA), MON("pit viper", S_SNAKE, LVL(6, 15, 2, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_DRST, 1, 4), ATTK(AT_BITE, AD_DRST, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 60, MS_HISS, MZ_MEDIUM), MR_POISON, MR_POISON, M1_SWIM | M1_CONCEAL | M1_NOLIMBS | M1_ANIMAL | M1_SLITHY | M1_POIS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE, M3_INFRAVISION, CLR_BLUE), MON("cobra", S_SNAKE, LVL(6, 18, 2, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_DRST, 2, 4), ATTK(AT_SPIT, AD_BLND, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(250, 100, MS_HISS, MZ_MEDIUM), MR_POISON, MR_POISON, M1_SWIM | M1_CONCEAL | M1_NOLIMBS | M1_ANIMAL | M1_SLITHY | M1_POIS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE, 0, CLR_BLUE), /* * Trolls */ MON("troll", S_TROLL, LVL(7, 12, 4, 0, -3), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_CLAW, AD_PHYS, 4, 2), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 350, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_REGEN | M1_CARNIVORE, M2_STRONG | M2_STALK | M2_HOSTILE, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("ice troll", S_TROLL, LVL(9, 10, 2, 20, -3), (G_NOHELL | G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_COLD, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 300, MS_GRUNT, MZ_LARGE), MR_COLD, MR_COLD, M1_HUMANOID | M1_REGEN | M1_CARNIVORE, M2_STRONG | M2_STALK | M2_HOSTILE, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_WHITE), MON("rock troll", S_TROLL, LVL(9, 12, 0, 0, -3), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 300, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_REGEN | M1_CARNIVORE, M2_STRONG | M2_STALK | M2_HOSTILE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_CYAN), MON("water troll", S_TROLL, LVL(11, 14, 4, 40, -3), (G_NOGEN | G_GENO), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 350, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_REGEN | M1_CARNIVORE | M1_SWIM, M2_STRONG | M2_STALK | M2_HOSTILE, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), MON("Olog-hai", S_TROLL, LVL(13, 12, -4, 0, -7), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 400, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_REGEN | M1_CARNIVORE, M2_STRONG | M2_STALK | M2_HOSTILE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), /* * Umber hulk */ MON("umber hulk", S_UMBER, LVL(9, 6, 2, 25, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_BITE, AD_PHYS, 2, 5), ATTK(AT_GAZE, AD_CONF, 0, 0), NO_ATTK, NO_ATTK), SIZ(1200, 500, MS_SILENT, MZ_LARGE), 0, 0, M1_TUNNEL | M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), /* * Vampires */ MON("vampire", S_VAMPIRE, LVL(10, 12, 1, 25, -8), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRLI, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP | MR_POISON, 0, M1_FLY | M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_SHAPESHIFTER, M3_INFRAVISIBLE, CLR_RED), MON("vampire lord", S_VAMPIRE, LVL(12, 14, 0, 50, -9), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_DRLI, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP | MR_POISON, 0, M1_FLY | M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_LORD | M2_MALE | M2_SHAPESHIFTER, M3_INFRAVISIBLE, CLR_BLUE), #if 0 /* DEFERRED */ MON("vampire mage", S_VAMPIRE, LVL(20, 14, -4, 50, -9), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_DRLI, 2, 8), ATTK(AT_BITE, AD_DRLI, 1, 8), ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP | MR_POISON, 0, M1_FLY | M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_LORD | M2_MALE | M2_MAGIC | M2_SHAPESHIFTER, M3_INFRAVISIBLE, HI_ZAP), #endif MON("Vlad the Impaler", S_VAMPIRE, LVL(14, 18, -3, 80, -10), (G_NOGEN | G_NOCORPSE | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_DRLI, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP | MR_POISON, 0, M1_FLY | M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_NOPOLY | M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_PNAME | M2_STRONG | M2_NASTY | M2_PRINCE | M2_MALE | M2_SHAPESHIFTER, M3_WAITFORU | M3_WANTSCAND | M3_INFRAVISIBLE, HI_LORD), /* * Wraiths */ MON("barrow wight", S_WRAITH, LVL(3, 12, 5, 5, -3), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_DRLI, 0, 0), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 0, MS_SPELL, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_HUMANOID, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_COLLECT, 0, CLR_GRAY), MON("wraith", S_WRAITH, LVL(6, 12, 4, 15, -6), (G_GENO | 2), A(ATTK(AT_TUCH, AD_DRLI, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_BREATHLESS | M1_FLY | M1_HUMANOID | M1_UNSOLID, M2_UNDEAD | M2_STALK | M2_HOSTILE, 0, CLR_BLACK), MON("Nazgul", S_WRAITH, LVL(13, 12, 0, 25, -17), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_DRLI, 1, 4), ATTK(AT_BREA, AD_SLEE, 2, 25), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 0, MS_SPELL, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_HUMANOID, M2_NOPOLY | M2_UNDEAD | M2_STALK | M2_STRONG | M2_HOSTILE | M2_MALE | M2_COLLECT, 0, HI_LORD), /* * Xorn */ MON("xorn", S_XORN, LVL(8, 9, -2, 20, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK), SIZ(1200, 700, MS_ROAR, MZ_MEDIUM), MR_FIRE | MR_COLD | MR_STONE, MR_STONE, M1_BREATHLESS | M1_WALLWALK | M1_THICK_HIDE | M1_METALLIVORE, M2_HOSTILE | M2_STRONG, 0, CLR_BROWN), /* * Apelike beasts */ MON("monkey", S_YETI, LVL(2, 12, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 50, MS_GROWL, MZ_SMALL), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY), MON("ape", S_YETI, LVL(4, 12, 6, 0, 0), (G_GENO | G_SGROUP | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1100, 500, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), MON("owlbear", S_YETI, LVL(5, 12, 5, 0, 0), (G_GENO | 3), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_HUGS, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 700, MS_ROAR, MZ_LARGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_NASTY, M3_INFRAVISIBLE, CLR_BROWN), MON("yeti", S_YETI, LVL(5, 15, 6, 0, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1600, 700, MS_GROWL, MZ_LARGE), MR_COLD, MR_COLD, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_WHITE), MON("carnivorous ape", S_YETI, LVL(6, 12, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_HUGS, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1250, 550, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_BLACK), MON("sasquatch", S_YETI, LVL(7, 15, 6, 0, 2), (G_GENO | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1550, 750, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL | M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), /* * Zombies */ MON("kobold zombie", S_ZOMBIE, LVL(0, 6, 10, 0, -2), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 50, MS_SILENT, MZ_SMALL), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_STALK | M2_HOSTILE, M3_INFRAVISION, CLR_BROWN), MON("gnome zombie", S_ZOMBIE, LVL(1, 6, 10, 0, -2), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 50, MS_SILENT, MZ_SMALL), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_GNOME, M3_INFRAVISION, CLR_BROWN), MON("orc zombie", S_ZOMBIE, LVL(2, 6, 9, 0, -3), (G_GENO | G_SGROUP | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 75, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_ORC, M3_INFRAVISION, CLR_GRAY), MON("dwarf zombie", S_ZOMBIE, LVL(2, 6, 9, 0, -3), (G_GENO | G_SGROUP | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 150, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_DWARF, M3_INFRAVISION, CLR_RED), MON("elf zombie", S_ZOMBIE, LVL(3, 6, 9, 0, -3), (G_GENO | G_SGROUP | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 7), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 175, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_ELF, M3_INFRAVISION, CLR_GREEN), MON("human zombie", S_ZOMBIE, LVL(4, 6, 8, 0, -3), (G_GENO | G_SGROUP | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_UNDEAD | M2_STALK | M2_HOSTILE, M3_INFRAVISION, HI_DOMESTIC), MON("ettin zombie", S_ZOMBIE, LVL(6, 8, 6, 0, -4), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 10), ATTK(AT_CLAW, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 250, MS_SILENT, MZ_HUGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_STRONG, M3_INFRAVISION, CLR_BLUE), MON("ghoul", S_ZOMBIE, LVL(3, 6, 10, 0, -2), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PLYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 50, MS_SILENT, MZ_SMALL), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_UNDEAD | M2_WANDER | M2_HOSTILE, M3_INFRAVISION, CLR_BLACK), MON("giant zombie", S_ZOMBIE, LVL(8, 8, 6, 0, -4), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2050, 375, MS_SILENT, MZ_HUGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_GIANT | M2_STRONG, M3_INFRAVISION, CLR_CYAN), MON("skeleton", S_ZOMBIE, LVL(12, 8, 4, 0, 0), (G_NOCORPSE | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_TUCH, AD_SLOW, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 5, MS_BONES, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE, M2_UNDEAD | M2_WANDER | M2_HOSTILE | M2_STRONG | M2_COLLECT | M2_NASTY, M3_INFRAVISION, CLR_WHITE), /* * golems */ MON("straw golem", S_GOLEM, LVL(3, 12, 10, 0, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 0, MS_SILENT, MZ_LARGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_HOSTILE | M2_NEUTER, 0, CLR_YELLOW), MON("paper golem", S_GOLEM, LVL(3, 12, 10, 0, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 0, MS_SILENT, MZ_LARGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_HOSTILE | M2_NEUTER, 0, HI_PAPER), MON("rope golem", S_GOLEM, LVL(4, 9, 8, 0, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_HUGS, AD_PHYS, 6, 1), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 0, MS_SILENT, MZ_LARGE), MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_HOSTILE | M2_NEUTER, 0, CLR_BROWN), MON("gold golem", S_GOLEM, LVL(5, 9, 6, 0, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 2, 3), ATTK(AT_CLAW, AD_PHYS, 2, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 0, MS_SILENT, MZ_LARGE), MR_SLEEP | MR_POISON | MR_ACID, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE, M2_HOSTILE | M2_NEUTER, 0, HI_GOLD), MON("leather golem", S_GOLEM, LVL(6, 6, 6, 0, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 0, MS_SILENT, MZ_LARGE), MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_HOSTILE | M2_NEUTER, 0, HI_LEATHER), MON("wood golem", S_GOLEM, LVL(7, 3, 4, 0, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 0, MS_SILENT, MZ_LARGE), MR_COLD | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE, M2_HOSTILE | M2_NEUTER, 0, HI_WOOD), MON("flesh golem", S_GOLEM, LVL(9, 8, 9, 30, 0), (1), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1400, 600, MS_SILENT, MZ_LARGE), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON, MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID, M2_HOSTILE | M2_STRONG, 0, CLR_RED), MON("clay golem", S_GOLEM, LVL(11, 7, 7, 40, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 3, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1550, 0, MS_SILENT, MZ_LARGE), MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE, M2_HOSTILE | M2_STRONG, 0, CLR_BROWN), MON("stone golem", S_GOLEM, LVL(14, 6, 5, 50, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 3, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1900, 0, MS_SILENT, MZ_LARGE), MR_SLEEP | MR_POISON | MR_STONE, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE, M2_HOSTILE | M2_STRONG, 0, CLR_GRAY), MON("glass golem", S_GOLEM, LVL(16, 6, 1, 50, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1800, 0, MS_SILENT, MZ_LARGE), MR_SLEEP | MR_POISON | MR_ACID, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE, M2_HOSTILE | M2_STRONG, 0, CLR_CYAN), MON("iron golem", S_GOLEM, LVL(18, 6, 3, 60, 0), (G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_BREA, AD_DRST, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2000, 0, MS_SILENT, MZ_LARGE), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_BREATHLESS | M1_MINDLESS | M1_HUMANOID | M1_THICK_HIDE | M1_POIS, M2_HOSTILE | M2_STRONG | M2_COLLECT, 0, HI_METAL), /* * humans, including elves and were-critters */ MON("human", S_HUMAN, LVL(0, 12, 10, 0, 0), G_NOGEN, /* for corpses */ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("wererat", S_HUMAN, LVL(2, 12, 10, 10, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_WERE, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_REGEN | M1_OMNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE | M2_HUMAN | M2_COLLECT, M3_INFRAVISIBLE, CLR_BROWN), MON("werejackal", S_HUMAN, LVL(2, 12, 10, 10, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_WERE, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_REGEN | M1_OMNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE | M2_HUMAN | M2_COLLECT, M3_INFRAVISIBLE, CLR_RED), MON("werewolf", S_HUMAN, LVL(5, 12, 10, 20, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_WERE, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_REGEN | M1_OMNIVORE, M2_NOPOLY | M2_WERE | M2_HOSTILE | M2_HUMAN | M2_COLLECT, M3_INFRAVISIBLE, CLR_ORANGE), MON("elf", S_HUMAN, LVL(10, 12, 10, 2, -3), G_NOGEN, /* for corpses */ A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_NOPOLY | M2_ELF | M2_STRONG | M2_COLLECT, M3_INFRAVISION | M3_INFRAVISIBLE, HI_DOMESTIC), MON("Woodland-elf", S_HUMAN, LVL(4, 12, 10, 10, -5), (G_GENO | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_ELF | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GREEN), MON("Green-elf", S_HUMAN, LVL(5, 12, 10, 10, -6), (G_GENO | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_ELF | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BRIGHT_GREEN), MON("Grey-elf", S_HUMAN, LVL(6, 12, 10, 10, -7), (G_GENO | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_ELF | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), MON("elf-lord", S_HUMAN, LVL(8, 12, 10, 20, -9), (G_GENO | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_ELF | M2_STRONG | M2_LORD | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BRIGHT_BLUE), MON("Elvenking", S_HUMAN, LVL(9, 12, 10, 25, -10), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_ELF | M2_STRONG | M2_PRINCE | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("doppelganger", S_HUMAN, LVL(9, 12, 5, 20, 0), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_IMITATE, MZ_HUMAN), MR_SLEEP, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_HOSTILE | M2_STRONG | M2_COLLECT | M2_SHAPESHIFTER, M3_INFRAVISIBLE, HI_DOMESTIC), MON("shopkeeper", S_HUMAN, LVL(12, 18, 0, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SELL, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("guard", S_HUMAN, LVL(12, 12, 10, 40, 10), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARD, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("prisoner", S_HUMAN, LVL(12, 12, 10, 0, 0), G_NOGEN, /* for special levels */ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_DJINNI, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE | M3_CLOSE, HI_DOMESTIC), MON("Oracle", S_HUMAN, LVL(12, 0, 0, 50, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_NONE, AD_MAGM, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_ORACLE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_FEMALE, M3_INFRAVISIBLE, HI_ZAP), /* aligned priests always have the epri extension attached; individual instantiations should always have either ispriest or isminion set */ MON("aligned priest", S_HUMAN, LVL(12, 12, 10, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_PRIEST, MZ_HUMAN), MR_ELEC, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_LORD | M2_PEACEFUL | M2_COLLECT, M3_INFRAVISIBLE, CLR_WHITE), /* high priests always have epri and always have ispriest set */ MON("high priest", S_HUMAN, LVL(25, 15, 7, 70, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_PRIEST, MZ_HUMAN), MR_FIRE | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MINION | M2_PRINCE | M2_NASTY | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, CLR_WHITE), MON("soldier", S_HUMAN, LVL(6, 10, 10, 0, -2), (G_SGROUP | G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_STALK | M2_HOSTILE | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY), MON("sergeant", S_HUMAN, LVL(8, 10, 10, 5, -3), (G_SGROUP | G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_STALK | M2_HOSTILE | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_RED), MON("nurse", S_HUMAN, LVL(11, 6, 0, 0, 0), (G_GENO | 3), A(ATTK(AT_CLAW, AD_HEAL, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NURSE, MZ_HUMAN), MR_POISON, MR_POISON, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_HOSTILE, M3_INFRAVISIBLE, HI_DOMESTIC), MON("lieutenant", S_HUMAN, LVL(10, 10, 10, 15, -4), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_WEAP, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_STALK | M2_HOSTILE | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), MON("captain", S_HUMAN, LVL(12, 10, 10, 15, -5), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_STALK | M2_HOSTILE | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), /* Keep these separate - some of the mkroom code assumes that * all the soldiers are contiguous. */ MON("watchman", S_HUMAN, LVL(6, 10, 10, 0, -2), (G_SGROUP | G_NOGEN | G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_STALK | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY), MON("watch captain", S_HUMAN, LVL(10, 10, 10, 15, -4), (G_NOGEN | G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_WEAP, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_MERC | M2_STALK | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), /* Unique humans not tied to quests. */ MON("Medusa", S_HUMAN, LVL(20, 12, 2, 50, -15), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_GAZE, AD_STON, 0, 0), ATTK(AT_BITE, AD_DRST, 1, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HISS, MZ_LARGE), MR_POISON | MR_STONE, MR_POISON | MR_STONE, M1_FLY | M1_SWIM | M1_AMPHIBIOUS | M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_NOPOLY | M2_HOSTILE | M2_STRONG | M2_PNAME | M2_FEMALE, M3_WAITFORU | M3_INFRAVISIBLE, CLR_BRIGHT_GREEN), MON("Wizard of Yendor", S_HUMAN, LVL(30, 12, -8, 100, A_NONE), (G_NOGEN | G_UNIQ), A(ATTK(AT_CLAW, AD_SAMU, 2, 12), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_CUSS, MZ_HUMAN), MR_FIRE | MR_POISON, MR_FIRE | MR_POISON, M1_FLY | M1_BREATHLESS | M1_HUMANOID | M1_REGEN | M1_SEE_INVIS | M1_TPORT | M1_TPORT_CNTRL | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_PRINCE | M2_MALE | M2_MAGIC, M3_COVETOUS | M3_WAITFORU | M3_INFRAVISIBLE, HI_LORD), MON("Croesus", S_HUMAN, LVL(20, 15, 0, 40, 15), (G_UNIQ | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARD, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_PNAME | M2_PRINCE | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, HI_LORD), #ifdef CHARON MON("Charon", S_HUMAN, LVL(76, 18, -5, 120, 0), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_TUCH, AD_PLYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_FERRY, MZ_HUMAN), MR_FIRE | MR_COLD | MR_POISON | MR_STONE, 0, M1_BREATHLESS | M1_SEE_INVIS | M1_HUMANOID, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_PNAME | M2_MALE | M2_GREEDY | M2_COLLECT, M3_INFRAVISIBLE, CLR_WHITE), #endif /* * ghosts */ MON("ghost", S_GHOST, LVL(10, 3, -5, 50, -5), (G_NOCORPSE | G_NOGEN), A(ATTK(AT_TUCH, AD_PHYS, 1, 1), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 0, MS_SILENT, MZ_HUMAN), MR_COLD | MR_DISINT | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_WALLWALK | M1_HUMANOID | M1_UNSOLID, M2_NOPOLY | M2_UNDEAD | M2_STALK | M2_HOSTILE, M3_INFRAVISION, CLR_GRAY), MON("shade", S_GHOST, LVL(12, 10, 10, 0, 0), (G_NOCORPSE | G_NOGEN), A(ATTK(AT_TUCH, AD_PLYS, 2, 6), ATTK(AT_TUCH, AD_SLOW, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 0, MS_WAIL, MZ_HUMAN), MR_COLD | MR_DISINT | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_WALLWALK | M1_HUMANOID | M1_UNSOLID | M1_SEE_INVIS, M2_NOPOLY | M2_UNDEAD | M2_WANDER | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISION, CLR_BLACK), /* * (major) demons */ MON("water demon", S_DEMON, LVL(8, 12, -4, 30, -7), (G_NOCORPSE | G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_DJINNI, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_SWIM, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BLUE), /* standard demons & devils */ #define SEDUCTION_ATTACKS_YES \ A(ATTK(AT_BITE, AD_SSEX, 0, 0), ATTK(AT_CLAW, AD_PHYS, 1, 3), \ ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK) #define SEDUCTION_ATTACKS_NO \ A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), \ ATTK(AT_BITE, AD_DRLI, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK) MON("succubus", S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE | 1), SEDUCTION_ATTACKS_YES, SIZ(WT_HUMAN, 400, MS_SEDUCE, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_FLY | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_FEMALE, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), MON("horned devil", S_DEMON, LVL(6, 9, -5, 50, 11), (G_HELL | G_NOCORPSE | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 2, 3), ATTK(AT_STNG, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_POIS | M1_THICK_HIDE, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BROWN), MON("incubus", S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE | 1), SEDUCTION_ATTACKS_YES, SIZ(WT_HUMAN, 400, MS_SEDUCE, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_FLY | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_MALE, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), /* Used by AD&D for a type of demon, originally one of the Furies */ /* and spelled this way */ MON("erinys", S_DEMON, LVL(7, 12, 2, 30, 10), (G_HELL | G_NOCORPSE | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("barbed devil", S_DEMON, LVL(8, 12, 0, 35, 8), (G_HELL | G_NOCORPSE | G_SGROUP | 2), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_POIS | M1_THICK_HIDE, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("marilith", S_DEMON, LVL(7, 12, -6, 80, -12), (G_HELL | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4)), SIZ(WT_HUMAN, 400, MS_CUSS, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_SLITHY | M1_SEE_INVIS | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("vrock", S_DEMON, LVL(8, 12, 0, 50, -9), (G_HELL | G_NOCORPSE | G_SGROUP | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("hezrou", S_DEMON, LVL(9, 6, -2, 55, -10), (G_HELL | G_NOCORPSE | G_SGROUP | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("bone devil", S_DEMON, LVL(9, 15, -1, 40, -9), (G_HELL | G_NOCORPSE | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), MON("ice devil", S_DEMON, LVL(11, 6, -4, 55, -12), (G_HELL | G_NOCORPSE | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_COLD, 3, 4), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_LARGE), MR_FIRE | MR_COLD | MR_POISON, 0, M1_SEE_INVIS | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_WHITE), MON("nalfeshnee", S_DEMON, LVL(11, 9, -1, 65, -11), (G_HELL | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SPELL, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("pit fiend", S_DEMON, LVL(13, 6, -3, 65, -13), (G_HELL | G_NOCORPSE | 2), A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GROWL, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_SEE_INVIS | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), MON("sandestin", S_DEMON, LVL(13, 12, 4, 60, -5), (G_HELL | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 400, MS_CUSS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID, M2_NOPOLY | M2_STALK | M2_STRONG | M2_COLLECT | M2_SHAPESHIFTER, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_GRAY), MON("balrog", S_DEMON, LVL(16, 5, -2, 75, -14), (G_HELL | G_NOCORPSE | 1), A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_POIS, M2_DEMON | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_RED), /* Named demon lords & princes plus Arch-Devils. * (their order matters; see minion.c) */ MON("Juiblex", S_DEMON, LVL(50, 3, -7, 65, -15), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_ENGL, AD_DISE, 4, 10), ATTK(AT_SPIT, AD_ACID, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 0, MS_GURGLE, MZ_LARGE), MR_FIRE | MR_POISON | MR_ACID | MR_STONE, 0, M1_AMPHIBIOUS | M1_AMORPHOUS | M1_NOHEAD | M1_FLY | M1_SEE_INVIS | M1_ACID | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_LORD | M2_MALE, M3_WAITFORU | M3_WANTSAMUL | M3_INFRAVISION, CLR_BRIGHT_GREEN), MON("Yeenoghu", S_DEMON, LVL(56, 18, -5, 80, -15), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_WEAP, AD_CONF, 2, 8), ATTK(AT_CLAW, AD_PLYS, 1, 6), ATTK(AT_MAGC, AD_MAGM, 2, 6), NO_ATTK, NO_ATTK), SIZ(900, 500, MS_ORC, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_LORD | M2_MALE | M2_COLLECT, M3_WANTSAMUL | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("Orcus", S_DEMON, LVL(66, 9, -6, 85, -20), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_MAGC, AD_SPEL, 8, 6), ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK), SIZ(1500, 500, MS_ORC, MZ_HUGE), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_PRINCE | M2_MALE | M2_COLLECT, M3_WAITFORU | M3_WANTSBOOK | M3_WANTSAMUL | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("Geryon", S_DEMON, LVL(72, 3, -3, 75, 15), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_BRIBE, MZ_HUGE), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_POIS | M1_SLITHY, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_PRINCE | M2_MALE, M3_WANTSAMUL | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("Dispater", S_DEMON, LVL(78, 15, -2, 80, 15), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 6, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_BRIBE, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_POIS | M1_HUMANOID, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_PRINCE | M2_MALE | M2_COLLECT, M3_WANTSAMUL | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("Baalzebub", S_DEMON, LVL(89, 9, -5, 85, 20), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_BITE, AD_DRST, 2, 6), ATTK(AT_GAZE, AD_STUN, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_BRIBE, MZ_LARGE), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_PRINCE | M2_MALE, M3_WANTSAMUL | M3_WAITFORU | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("Asmodeus", S_DEMON, LVL(105, 12, -7, 90, 20), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 4, 4), ATTK(AT_MAGC, AD_COLD, 6, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_BRIBE, MZ_HUGE), MR_FIRE | MR_COLD | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_HUMANOID | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_STRONG | M2_NASTY | M2_PRINCE | M2_MALE, M3_WANTSAMUL | M3_WAITFORU | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), MON("Demogorgon", S_DEMON, LVL(106, 15, -8, 95, -20), (G_HELL | G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_MAGC, AD_SPEL, 8, 6), ATTK(AT_STNG, AD_DRLI, 1, 4), ATTK(AT_CLAW, AD_DISE, 1, 6), ATTK(AT_CLAW, AD_DISE, 1, 6), NO_ATTK, NO_ATTK), SIZ(1500, 500, MS_GROWL, MZ_HUGE), MR_FIRE | MR_POISON, 0, M1_FLY | M1_SEE_INVIS | M1_NOHANDS | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_PNAME | M2_NASTY | M2_PRINCE | M2_MALE, M3_WANTSAMUL | M3_INFRAVISIBLE | M3_INFRAVISION, HI_LORD), /* Riders -- the Four Horsemen of the Apocalypse ("War" == player) */ MON("Death", S_DEMON, LVL(30, 12, -5, 100, 0), (G_UNIQ | G_NOGEN), A(ATTK(AT_TUCH, AD_DETH, 8, 8), ATTK(AT_TUCH, AD_DETH, 8, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 1, MS_RIDER, MZ_HUMAN), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_HUMANOID | M1_REGEN | M1_SEE_INVIS | M1_TPORT_CNTRL, M2_NOPOLY | M2_STALK | M2_HOSTILE | M2_PNAME | M2_STRONG | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION | M3_DISPLACES, HI_LORD), MON("Pestilence", S_DEMON, LVL(30, 12, -5, 100, 0), (G_UNIQ | G_NOGEN), A(ATTK(AT_TUCH, AD_PEST, 8, 8), ATTK(AT_TUCH, AD_PEST, 8, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 1, MS_RIDER, MZ_HUMAN), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_HUMANOID | M1_REGEN | M1_SEE_INVIS | M1_TPORT_CNTRL, M2_NOPOLY | M2_STALK | M2_HOSTILE | M2_PNAME | M2_STRONG | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION | M3_DISPLACES, HI_LORD), MON("Famine", S_DEMON, LVL(30, 12, -5, 100, 0), (G_UNIQ | G_NOGEN), A(ATTK(AT_TUCH, AD_FAMN, 8, 8), ATTK(AT_TUCH, AD_FAMN, 8, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 1, MS_RIDER, MZ_HUMAN), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_HUMANOID | M1_REGEN | M1_SEE_INVIS | M1_TPORT_CNTRL, M2_NOPOLY | M2_STALK | M2_HOSTILE | M2_PNAME | M2_STRONG | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION | M3_DISPLACES, HI_LORD), /* other demons */ #ifdef MAIL MON("mail daemon", S_DEMON, LVL(56, 24, 10, 127, 0), (G_NOGEN | G_NOCORPSE), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_SILENT, MZ_HUMAN), MR_FIRE | MR_COLD | MR_ELEC | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_SWIM | M1_BREATHLESS | M1_SEE_INVIS | M1_HUMANOID | M1_POIS, M2_NOPOLY | M2_STALK | M2_PEACEFUL, M3_INFRAVISIBLE | M3_INFRAVISION, CLR_BRIGHT_BLUE), #endif MON("djinni", S_DEMON, LVL(7, 12, 4, 30, 0), (G_NOGEN | G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 400, MS_DJINNI, MZ_HUMAN), MR_POISON | MR_STONE, 0, M1_HUMANOID | M1_FLY | M1_POIS, M2_NOPOLY | M2_STALK | M2_COLLECT, M3_INFRAVISIBLE, CLR_YELLOW), /* * sea monsters */ MON("jellyfish", S_EEL, LVL(3, 3, 6, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_STNG, AD_DRST, 3, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(80, 20, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM | M1_AMPHIBIOUS | M1_SLITHY | M1_NOLIMBS | M1_NOHEAD | M1_NOTAKE | M1_POIS, M2_HOSTILE, 0, CLR_BLUE), MON("piranha", S_EEL, LVL(5, 12, 4, 0, 0), (G_GENO | G_NOGEN | G_SGROUP), A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 30, MS_SILENT, MZ_SMALL), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE, 0, CLR_RED), MON("shark", S_EEL, LVL(7, 12, 2, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_BITE, AD_PHYS, 5, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 350, MS_SILENT, MZ_LARGE), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE | M1_OVIPAROUS | M1_THICK_HIDE | M1_NOTAKE, M2_HOSTILE, 0, CLR_GRAY), MON("giant eel", S_EEL, LVL(5, 9, -1, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_TUCH, AD_WRAP, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 250, MS_SILENT, MZ_HUGE), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN), MON("electric eel", S_EEL, LVL(7, 10, -3, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_BITE, AD_ELEC, 4, 6), ATTK(AT_TUCH, AD_WRAP, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 250, MS_SILENT, MZ_HUGE), MR_ELEC, MR_ELEC, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BRIGHT_BLUE), MON("kraken", S_EEL, LVL(20, 3, 6, 0, -3), (G_GENO | G_NOGEN), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_HUGS, AD_WRAP, 2, 6), ATTK(AT_BITE, AD_PHYS, 5, 4), NO_ATTK, NO_ATTK), SIZ(1800, 1000, MS_SILENT, MZ_HUGE), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_NOPOLY | M2_HOSTILE | M2_STRONG, M3_INFRAVISIBLE, CLR_RED), /* * lizards, &c */ MON("newt", S_LIZARD, LVL(0, 6, 8, 0, 0), (G_GENO | 5), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 20, MS_SILENT, MZ_TINY), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_YELLOW), MON("gecko", S_LIZARD, LVL(1, 6, 8, 0, 0), (G_GENO | 5), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 20, MS_SQEEK, MZ_TINY), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_GREEN), MON("iguana", S_LIZARD, LVL(2, 6, 7, 0, 0), (G_GENO | 5), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, MS_SILENT, MZ_TINY), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("baby crocodile", S_LIZARD, LVL(3, 6, 7, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, MS_SILENT, MZ_MEDIUM), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("lizard", S_LIZARD, LVL(5, 6, 6, 10, 0), (G_GENO | 5), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 40, MS_SILENT, MZ_TINY), MR_STONE, MR_STONE, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, 0, CLR_GREEN), MON("chameleon", S_LIZARD, LVL(6, 5, 6, 10, 0), (G_GENO | 2), A(ATTK(AT_BITE, AD_PHYS, 4, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, MS_SILENT, MZ_TINY), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_NOPOLY | M2_HOSTILE | M2_SHAPESHIFTER, 0, CLR_BROWN), MON("crocodile", S_LIZARD, LVL(6, 9, 5, 0, 0), (G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 4, 2), ATTK(AT_CLAW, AD_PHYS, 1, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_SILENT, MZ_LARGE), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_THICK_HIDE | M1_NOHANDS | M1_OVIPAROUS | M1_CARNIVORE, M2_STRONG | M2_HOSTILE, 0, CLR_BROWN), MON("salamander", S_LIZARD, LVL(8, 12, -1, 0, -9), (G_HELL | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_TUCH, AD_FIRE, 1, 6), ATTK(AT_HUGS, AD_PHYS, 2, 6), ATTK(AT_HUGS, AD_FIRE, 3, 6), NO_ATTK, NO_ATTK), SIZ(1500, 400, MS_MUMBLE, MZ_HUMAN), MR_SLEEP | MR_FIRE, MR_FIRE, M1_HUMANOID | M1_SLITHY | M1_THICK_HIDE | M1_POIS, M2_STALK | M2_HOSTILE | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, CLR_ORANGE), /* * dummy monster needed for visual interface */ /* (marking it unique prevents figurines) */ MON("long worm tail", S_WORM_TAIL, LVL(0, 0, 0, 0, 0), (G_NOGEN | G_NOCORPSE | G_UNIQ), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, 0), 0, 0, 0L, M2_NOPOLY, 0, CLR_BROWN), /* Note: * Worm tail must be between the normal monsters and the special * quest & pseudo-character ones because an optimization in the * random monster selection code assumes everything beyond here * has the G_NOGEN and M2_NOPOLY attributes. */ /* * character classes */ MON("archeologist", S_HUMAN, LVL(10, 12, 10, 1, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TUNNEL | M1_NEEDPICK | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("barbarian", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("caveman", S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("cavewoman", S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("healer", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("knight", S_HUMAN, LVL(10, 12, 10, 1, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("monk", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_KICK, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_HERBIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT | M2_MALE, M3_INFRAVISIBLE, HI_DOMESTIC), MON("priest", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_MALE | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("priestess", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("ranger", S_HUMAN, LVL(10, 12, 10, 2, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("rogue", S_HUMAN, LVL(10, 12, 10, 1, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("samurai", S_HUMAN, LVL(10, 12, 10, 1, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("tourist", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("valkyrie", S_HUMAN, LVL(10, 12, 10, 1, -1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), MR_COLD, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("wizard", S_HUMAN, LVL(10, 12, 10, 3, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), /* * quest leaders */ MON("Lord Carnarvon", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("Pelias", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("Shaman Karnov", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), #if 0 /* OBSOLETE */ /* Two for elves - one of each sex. */ MON("Earendil", S_HUMAN, LVL(20, 12, 0, 50, -20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_LEADER, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_ELF | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, HI_LORD), MON("Elwing", S_HUMAN, LVL(20, 12, 0, 50, -20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_LEADER, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_ELF | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_FEMALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, HI_LORD), #endif MON("Hippocrates", S_HUMAN, LVL(20, 12, 0, 40, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("King Arthur", S_HUMAN, LVL(20, 12, 0, 40, 20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("Grand Master", S_HUMAN, LVL(25, 12, 0, 70, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_FIRE | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_HUMANOID | M1_SEE_INVIS | M1_HERBIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_NASTY | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, CLR_BLACK), MON("Arch Priest", S_HUMAN, LVL(25, 12, 7, 70, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_FIRE | MR_ELEC | MR_SLEEP | MR_POISON, 0, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, CLR_WHITE), MON("Orion", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2200, 700, MS_LEADER, MZ_HUGE), 0, 0, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS | M1_SWIM | M1_AMPHIBIOUS, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, HI_LORD), /* Note: Master of Thieves is also the Tourist's nemesis. */ MON("Master of Thieves", S_HUMAN, LVL(20, 12, 0, 30, -20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("Lord Sato", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("Twoflower", S_HUMAN, LVL(20, 12, 10, 20, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_DOMESTIC), MON("Norn", S_HUMAN, LVL(20, 12, 0, 80, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1800, 550, MS_LEADER, MZ_HUGE), MR_COLD, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_FEMALE | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, HI_LORD), MON("Neferet the Green", S_HUMAN, LVL(20, 12, 0, 60, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_FEMALE | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC, M3_CLOSE | M3_INFRAVISIBLE, CLR_GREEN), /* * quest nemeses */ MON("Minion of Huhetotl", S_DEMON, LVL(16, 12, -2, 75, -14), (G_NOCORPSE | G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_LARGE), MR_FIRE | MR_POISON | MR_STONE, 0, M1_FLY | M1_SEE_INVIS | M1_POIS, M2_NOPOLY | M2_DEMON | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_COLLECT, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISION | M3_INFRAVISIBLE, CLR_RED), MON("Thoth Amon", S_HUMAN, LVL(16, 12, 0, 10, -14), (G_NOGEN | G_UNIQ | G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_HUMAN), MR_POISON | MR_STONE, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_STRONG | M2_MALE | M2_STALK | M2_HOSTILE | M2_NASTY | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, HI_LORD), /* Multi-headed, possessing the breath attacks of all the other dragons * (selected at random when attacking). */ MON("Chromatic Dragon", S_DRAGON, LVL(16, 12, 0, 30, -14), (G_NOGEN | G_UNIQ), A(ATTK(AT_BREA, AD_RBRE, 6, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 8), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_STNG, AD_PHYS, 1, 6)), SIZ(WT_DRAGON, 1700, MS_NEMESIS, MZ_GIGANTIC), MR_FIRE | MR_COLD | MR_SLEEP | MR_DISINT | MR_ELEC | MR_POISON | MR_ACID | MR_STONE, MR_FIRE | MR_COLD | MR_SLEEP | MR_DISINT | MR_ELEC | MR_POISON | MR_STONE, M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE | M1_SEE_INVIS | M1_POIS, M2_NOPOLY | M2_HOSTILE | M2_FEMALE | M2_STALK | M2_STRONG | M2_NASTY | M2_GREEDY | M2_JEWELS | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, HI_LORD), #if 0 /* OBSOLETE */ MON("Goblin King", S_ORC, LVL(15, 12, 10, 0, -15), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 350, MS_NEMESIS, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_ORC | M2_HOSTILE | M2_STRONG | M2_STALK | M2_NASTY | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISION | M3_INFRAVISIBLE, HI_LORD), #endif MON("Cyclops", S_GIANT, LVL(18, 12, 0, 0, -15), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1900, 700, MS_NEMESIS, MZ_HUGE), MR_STONE, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_GIANT | M2_STRONG | M2_ROCKTHROW | M2_STALK | M2_HOSTILE | M2_NASTY | M2_MALE | M2_JEWELS | M2_COLLECT, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISION | M3_INFRAVISIBLE, CLR_GRAY), MON("Ixoth", S_DRAGON, LVL(15, 12, -1, 20, -14), (G_NOGEN | G_UNIQ), A(ATTK(AT_BREA, AD_FIRE, 8, 6), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK), SIZ(WT_DRAGON, 1600, MS_NEMESIS, MZ_GIGANTIC), MR_FIRE | MR_STONE, MR_FIRE, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE | M1_SEE_INVIS, M2_NOPOLY | M2_MALE | M2_PNAME | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_STALK | M2_GREEDY | M2_JEWELS | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, CLR_RED), MON("Master Kaen", S_HUMAN, LVL(25, 12, -10, 10, -20), (G_NOGEN | G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_MAGC, AD_CLRC, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_HUMAN), MR_POISON | MR_STONE, MR_POISON, M1_HUMANOID | M1_HERBIVORE | M1_SEE_INVIS, M2_NOPOLY | M2_HUMAN | M2_MALE | M2_PNAME | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_STALK | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, HI_LORD), MON("Nalzok", S_DEMON, LVL(16, 12, -2, 85, -127), (G_NOGEN | G_UNIQ | G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_LARGE), MR_FIRE | MR_POISON | MR_STONE, 0, M1_FLY | M1_SEE_INVIS | M1_POIS, M2_NOPOLY | M2_DEMON | M2_MALE | M2_PNAME | M2_HOSTILE | M2_STRONG | M2_STALK | M2_NASTY | M2_COLLECT, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISION | M3_INFRAVISIBLE, CLR_RED), MON("Scorpius", S_SPIDER, LVL(15, 12, 10, 0, -15), (G_NOGEN | G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6), ATTK(AT_STNG, AD_DISE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 350, MS_NEMESIS, MZ_HUMAN), MR_POISON | MR_STONE, MR_POISON, M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, M2_NOPOLY | M2_MALE | M2_PNAME | M2_HOSTILE | M2_STRONG | M2_STALK | M2_NASTY | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU, HI_LORD), MON("Master Assassin", S_HUMAN, LVL(15, 12, 0, 30, 18), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_DRST, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_MALE | M2_HOSTILE | M2_STALK | M2_NASTY | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, HI_LORD), /* A renegade daimyo who led a 13 year civil war against the shogun * of his time. */ MON("Ashikaga Takauji", S_HUMAN, LVL(15, 12, 0, 40, -13), (G_NOGEN | G_UNIQ | G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_HOSTILE | M2_STRONG | M2_STALK | M2_NASTY | M2_MALE | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, HI_LORD), /* * Note: the Master of Thieves was defined above. */ MON("Lord Surtur", S_GIANT, LVL(15, 12, 2, 50, 12), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 10), ATTK(AT_WEAP, AD_PHYS, 2, 10), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 850, MS_NEMESIS, MZ_HUGE), MR_FIRE | MR_STONE, MR_FIRE, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_GIANT | M2_MALE | M2_PNAME | M2_HOSTILE | M2_STALK | M2_STRONG | M2_NASTY | M2_ROCKTHROW | M2_JEWELS | M2_COLLECT, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISION | M3_INFRAVISIBLE, HI_LORD), MON("Dark One", S_HUMAN, LVL(15, 12, 0, 80, -10), (G_NOGEN | G_UNIQ | G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_SAMU, 1, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_HOSTILE | M2_STALK | M2_NASTY | M2_COLLECT | M2_MAGIC, M3_WANTSARTI | M3_WAITFORU | M3_INFRAVISIBLE, CLR_BLACK), /* * quest "guardians" */ MON("student", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("chieftain", S_HUMAN, LVL(5, 12, 10, 10, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("neanderthal", S_HUMAN, LVL(5, 12, 10, 10, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), #if 0 /* OBSOLETE */ MON("High-elf", S_HUMAN, LVL(5, 12, 10, 10, -7), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_GUARDIAN, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_ELF | M2_PEACEFUL | M2_COLLECT, M3_INFRAVISION | M3_INFRAVISIBLE, HI_DOMESTIC), #endif MON("attendant", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("page", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("abbot", S_HUMAN, LVL(5, 12, 10, 20, 0), G_NOGEN, A(ATTK(AT_CLAW, AD_PHYS, 8, 2), ATTK(AT_KICK, AD_STUN, 3, 2), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_HERBIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("acolyte", S_HUMAN, LVL(5, 12, 10, 20, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("hunter", S_HUMAN, LVL(5, 12, 10, 10, -7), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_SEE_INVIS | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISION | M3_INFRAVISIBLE, HI_DOMESTIC), MON("thug", S_HUMAN, LVL(5, 12, 10, 10, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_GREEDY | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("ninja", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_HOSTILE | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("roshi", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("guide", S_HUMAN, LVL(5, 12, 10, 20, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("warrior", S_HUMAN, LVL(5, 12, 10, 10, -1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_FEMALE, M3_INFRAVISIBLE, HI_DOMESTIC), MON("apprentice", S_HUMAN, LVL(5, 12, 10, 30, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), /* * array terminator */ MON("", 0, LVL(0, 0, 0, 0, 0), (0), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, 0), 0, 0, 0L, 0L, 0, 0) }; #endif /* !SPLITMON_1 */ #ifndef SPLITMON_1 /* dummy routine used to force linkage */ void monst_init() { return; } struct attack sa_yes[NATTK] = SEDUCTION_ATTACKS_YES; struct attack sa_no[NATTK] = SEDUCTION_ATTACKS_NO; #endif /*monst.c*/ nethack-3.6.0/src/mplayer.c0000664000076400007660000002743212617413107014553 0ustar paxedpaxed/* NetHack 3.6 mplayer.c $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) Izchak Miller, 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL const char *NDECL(dev_name); STATIC_DCL void FDECL(get_mplname, (struct monst *, char *)); STATIC_DCL void FDECL(mk_mplayer_armor, (struct monst *, SHORT_P)); /* These are the names of those who * contributed to the development of NetHack 3.2/3.3/3.4/3.6. * * Keep in alphabetical order within teams. * Same first name is entered once within each team. */ static const char *developers[] = { /* devteam */ "Dave", "Dean", "Eric", "Izchak", "Janet", "Jessie", "Ken", "Kevin", "Michael", "Mike", "Pat", "Paul", "Steve", "Timo", "Warwick", /* PC team */ "Bill", "Eric", "Keizo", "Ken", "Kevin", "Michael", "Mike", "Paul", "Stephen", "Steve", "Timo", "Yitzhak", /* Amiga team */ "Andy", "Gregg", "Janne", "Keni", "Mike", "Olaf", "Richard", /* Mac team */ "Andy", "Chris", "Dean", "Jon", "Jonathan", "Kevin", "Wang", /* Atari team */ "Eric", "Marvin", "Warwick", /* NT team */ "Alex", "Dion", "Michael", /* OS/2 team */ "Helge", "Ron", "Timo", /* VMS team */ "Joshua", "Pat", "" }; /* return a randomly chosen developer name */ STATIC_OVL const char * dev_name() { register int i, m = 0, n = SIZE(developers); register struct monst *mtmp; register boolean match; do { match = FALSE; i = rn2(n); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (!is_mplayer(mtmp->data)) continue; if (!strncmp(developers[i], (has_mname(mtmp)) ? MNAME(mtmp) : "", strlen(developers[i]))) { match = TRUE; break; } } m++; } while (match && m < 100); /* m for insurance */ if (match) return (const char *) 0; return (developers[i]); } STATIC_OVL void get_mplname(mtmp, nam) register struct monst *mtmp; char *nam; { boolean fmlkind = is_female(mtmp->data); const char *devnam; devnam = dev_name(); if (!devnam) Strcpy(nam, fmlkind ? "Eve" : "Adam"); else if (fmlkind && !!strcmp(devnam, "Janet")) Strcpy(nam, rn2(2) ? "Maud" : "Eve"); else Strcpy(nam, devnam); if (fmlkind || !strcmp(nam, "Janet")) mtmp->female = 1; else mtmp->female = 0; Strcat(nam, " the "); Strcat(nam, rank_of((int) mtmp->m_lev, monsndx(mtmp->data), (boolean) mtmp->female)); } STATIC_OVL void mk_mplayer_armor(mon, typ) struct monst *mon; short typ; { struct obj *obj; if (typ == STRANGE_OBJECT) return; obj = mksobj(typ, FALSE, FALSE); if (!rn2(3)) obj->oerodeproof = 1; if (!rn2(3)) curse(obj); if (!rn2(3)) bless(obj); /* Most players who get to the endgame who have cursed equipment * have it because the wizard or other monsters cursed it, so its * chances of having plusses is the same as usual.... */ obj->spe = rn2(10) ? (rn2(3) ? rn2(5) : rn1(4, 4)) : -rnd(3); (void) mpickobj(mon, obj); } struct monst * mk_mplayer(ptr, x, y, special) register struct permonst *ptr; xchar x, y; register boolean special; { register struct monst *mtmp; char nam[PL_NSIZ]; if (!is_mplayer(ptr)) return ((struct monst *) 0); if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */ if (!In_endgame(&u.uz)) special = FALSE; if ((mtmp = makemon(ptr, x, y, NO_MM_FLAGS)) != 0) { short weapon = rn2(2) ? LONG_SWORD : rnd_class(SPEAR, BULLWHIP); short armor = rnd_class(GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL); short cloak = !rn2(8) ? STRANGE_OBJECT : rnd_class(OILSKIN_CLOAK, CLOAK_OF_DISPLACEMENT); short helm = !rn2(8) ? STRANGE_OBJECT : rnd_class(ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY); short shield = !rn2(8) ? STRANGE_OBJECT : rnd_class(ELVEN_SHIELD, SHIELD_OF_REFLECTION); int quan; struct obj *otmp; mtmp->m_lev = (special ? rn1(16, 15) : rnd(16)); mtmp->mhp = mtmp->mhpmax = d((int) mtmp->m_lev, 10) + (special ? (30 + rnd(30)) : 30); if (special) { get_mplname(mtmp, nam); mtmp = christen_monst(mtmp, nam); /* that's why they are "stuck" in the endgame :-) */ (void) mongets(mtmp, FAKE_AMULET_OF_YENDOR); } mtmp->mpeaceful = 0; set_malign(mtmp); /* peaceful may have changed again */ switch (monsndx(ptr)) { case PM_ARCHEOLOGIST: if (rn2(2)) weapon = BULLWHIP; break; case PM_BARBARIAN: if (rn2(2)) { weapon = rn2(2) ? TWO_HANDED_SWORD : BATTLE_AXE; shield = STRANGE_OBJECT; } if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT; break; case PM_CAVEMAN: case PM_CAVEWOMAN: if (rn2(4)) weapon = MACE; else if (rn2(2)) weapon = CLUB; if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT; break; case PM_HEALER: if (rn2(4)) weapon = QUARTERSTAFF; else if (rn2(2)) weapon = rn2(2) ? UNICORN_HORN : SCALPEL; if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY; if (rn2(2)) shield = STRANGE_OBJECT; break; case PM_KNIGHT: if (rn2(4)) weapon = LONG_SWORD; if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); break; case PM_MONK: weapon = !rn2(3) ? SHURIKEN : STRANGE_OBJECT; armor = STRANGE_OBJECT; cloak = ROBE; if (rn2(2)) shield = STRANGE_OBJECT; break; case PM_PRIEST: case PM_PRIESTESS: if (rn2(2)) weapon = MACE; if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); if (rn2(4)) cloak = ROBE; if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY; if (rn2(2)) shield = STRANGE_OBJECT; break; case PM_RANGER: if (rn2(2)) weapon = ELVEN_DAGGER; break; case PM_ROGUE: if (rn2(2)) weapon = rn2(2) ? SHORT_SWORD : ORCISH_DAGGER; break; case PM_SAMURAI: if (rn2(2)) weapon = KATANA; break; case PM_TOURIST: /* Defaults are just fine */ break; case PM_VALKYRIE: if (rn2(2)) weapon = WAR_HAMMER; if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); break; case PM_WIZARD: if (rn2(4)) weapon = rn2(2) ? QUARTERSTAFF : ATHAME; if (rn2(2)) { armor = rn2(2) ? BLACK_DRAGON_SCALE_MAIL : SILVER_DRAGON_SCALE_MAIL; cloak = CLOAK_OF_MAGIC_RESISTANCE; } if (rn2(4)) helm = HELM_OF_BRILLIANCE; shield = STRANGE_OBJECT; break; default: impossible("bad mplayer monster"); weapon = 0; break; } if (weapon != STRANGE_OBJECT) { otmp = mksobj(weapon, TRUE, FALSE); otmp->spe = (special ? rn1(5, 4) : rn2(4)); if (!rn2(3)) otmp->oerodeproof = 1; else if (!rn2(2)) otmp->greased = 1; if (special && rn2(2)) otmp = mk_artifact(otmp, A_NONE); /* usually increase stack size if stackable weapon */ if (objects[otmp->otyp].oc_merge && !otmp->oartifact) otmp->quan += (long) rn2(is_spear(otmp) ? 4 : 8); /* mplayers knew better than to overenchant Magicbane */ if (otmp->oartifact == ART_MAGICBANE) otmp->spe = rnd(4); (void) mpickobj(mtmp, otmp); } if (special) { if (!rn2(10)) (void) mongets(mtmp, rn2(3) ? LUCKSTONE : LOADSTONE); mk_mplayer_armor(mtmp, armor); mk_mplayer_armor(mtmp, cloak); mk_mplayer_armor(mtmp, helm); mk_mplayer_armor(mtmp, shield); if (rn2(8)) mk_mplayer_armor( mtmp, rnd_class(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY)); if (rn2(8)) mk_mplayer_armor(mtmp, rnd_class(LOW_BOOTS, LEVITATION_BOOTS)); m_dowear(mtmp, TRUE); quan = rn2(3) ? rn2(3) : rn2(16); while (quan--) (void) mongets(mtmp, rnd_class(DILITHIUM_CRYSTAL, JADE)); /* To get the gold "right" would mean a player can double his */ /* gold supply by killing one mplayer. Not good. */ mkmonmoney(mtmp, rn2(1000)); quan = rn2(10); while (quan--) (void) mpickobj(mtmp, mkobj(RANDOM_CLASS, FALSE)); } quan = rnd(3); while (quan--) (void) mongets(mtmp, rnd_offensive_item(mtmp)); quan = rnd(3); while (quan--) (void) mongets(mtmp, rnd_defensive_item(mtmp)); quan = rnd(3); while (quan--) (void) mongets(mtmp, rnd_misc_item(mtmp)); } return (mtmp); } /* create the indicated number (num) of monster-players, * randomly chosen, and in randomly chosen (free) locations * on the level. If "special", the size of num should not * be bigger than the number of _non-repeated_ names in the * developers array, otherwise a bunch of Adams and Eves will * fill up the overflow. */ void create_mplayers(num, special) register int num; boolean special; { int pm, x, y; struct monst fakemon; while (num) { int tryct = 0; /* roll for character class */ pm = PM_ARCHEOLOGIST + rn2(PM_WIZARD - PM_ARCHEOLOGIST + 1); fakemon.data = &mons[pm]; /* roll for an available location */ do { x = rn1(COLNO - 4, 2); y = rnd(ROWNO - 2); } while (!goodpos(x, y, &fakemon, 0) && tryct++ <= 50); /* if pos not found in 50 tries, don't bother to continue */ if (tryct > 50) return; (void) mk_mplayer(&mons[pm], (xchar) x, (xchar) y, special); num--; } } void mplayer_talk(mtmp) register struct monst *mtmp; { static const char *same_class_msg[3] = { "I can't win, and neither will you!", "You don't deserve to win!", "Mine should be the honor, not yours!", }, *other_class_msg[3] = { "The low-life wants to talk, eh?", "Fight, scum!", "Here is what I have to say!", }; if (mtmp->mpeaceful) return; /* will drop to humanoid talk */ pline("Talk? -- %s", (mtmp->data == &mons[urole.malenum] || mtmp->data == &mons[urole.femalenum]) ? same_class_msg[rn2(3)] : other_class_msg[rn2(3)]); } /*mplayer.c*/ nethack-3.6.0/src/mthrowu.c0000664000076400007660000007453612617413107014616 0ustar paxedpaxed/* NetHack 3.6 mthrowu.c $NHDT-Date: 1446887531 2015/11/07 09:12:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int)); #define URETREATING(x, y) \ (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y)) #define POLE_LIM 5 /* How far monsters can use pole-weapons */ /* * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h. */ STATIC_OVL NEARDATA const char *breathwep[] = { "fragments", "fire", "frost", "sleep gas", "a disintegration blast", "lightning", "poison gas", "acid", "strange breath #8", "strange breath #9" }; extern boolean notonhead; /* for long worms */ /* hero is hit by something other than a monster */ int thitu(tlev, dam, obj, name) int tlev, dam; struct obj *obj; const char *name; /* if null, then format `obj' */ { const char *onm, *knm; boolean is_acid; int kprefix = KILLED_BY_AN; char onmbuf[BUFSZ], knmbuf[BUFSZ]; if (!name) { if (!obj) panic("thitu: name & obj both null?"); name = strcpy(onmbuf, (obj->quan > 1L) ? doname(obj) : mshot_xname(obj)); knm = strcpy(knmbuf, killer_xname(obj)); kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */ } else { knm = name; /* [perhaps ought to check for plural here to] */ if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3) || !strncmpi(name, "a ", 2)) kprefix = KILLED_BY; } onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L) ? name : an(name); is_acid = (obj && obj->otyp == ACID_VENOM); if (u.uac + tlev <= rnd(20)) { if (Blind || !flags.verbose) pline("It misses."); else You("are almost hit by %s.", onm); return 0; } else { if (Blind || !flags.verbose) You("are hit%s", exclam(dam)); else You("are hit by %s%s", onm, exclam(dam)); if (obj && objects[obj->otyp].oc_material == SILVER && Hate_silver) { /* extra damage already applied by dmgval() */ pline_The("silver sears your flesh!"); exercise(A_CON, FALSE); } if (is_acid && Acid_resistance) pline("It doesn't seem to hurt you."); else { if (is_acid) pline("It burns!"); losehp(dam, knm, kprefix); /* acid damage */ exercise(A_STR, FALSE); } return 1; } } /* Be sure this corresponds with what happens to player-thrown objects in * dothrow.c (for consistency). --KAA * Returns 0 if object still exists (not destroyed). */ STATIC_OVL int drop_throw(obj, ohit, x, y) register struct obj *obj; boolean ohit; int x, y; { int retvalu = 1; int create; struct monst *mtmp; struct trap *t; if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS || (ohit && obj->otyp == EGG)) create = 0; else if (ohit && (is_multigen(obj) || obj->otyp == ROCK)) create = !rn2(3); else create = 1; if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && (t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))) { int objgone = 0; if (down_gate(x, y) != -1) objgone = ship_object(obj, x, y, FALSE); if (!objgone) { if (!flooreffects(obj, x, y, "fall")) { /* don't double-dip on damage */ place_object(obj, x, y); if (!mtmp && x == u.ux && y == u.uy) mtmp = &youmonst; if (mtmp && ohit) passive_obj(mtmp, obj, (struct attack *) 0); stackobj(obj); retvalu = 0; } } } else obfree(obj, (struct obj *) 0); return retvalu; } /* an object launched by someone/thing other than player attacks a monster; return 1 if the object has stopped moving (hit or its range used up) */ int ohitmon(mtmp, otmp, range, verbose) struct monst *mtmp; /* accidental target, located at */ struct obj *otmp; /* missile; might be destroyed by drop_throw */ int range; /* how much farther will object travel if it misses; use -1 to signify to keep going even after hit, unless it's gone (used for rolling_boulder_traps) */ boolean verbose; /* give message(s) even when you can't see what happened */ { int damage, tmp; boolean vis, ismimic; int objgone = 1; notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my); ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER; vis = cansee(bhitpos.x, bhitpos.y); tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE); if (tmp < rnd(20)) { if (!ismimic) { if (vis) miss(distant_name(otmp, mshot_xname), mtmp); else if (verbose) pline("It is missed."); } if (!range) { /* Last position; object drops */ (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my); return 1; } } else if (otmp->oclass == POTION_CLASS) { if (ismimic) seemimic(mtmp); mtmp->msleeping = 0; if (vis) otmp->dknown = 1; potionhit(mtmp, otmp, FALSE); return 1; } else { damage = dmgval(otmp, mtmp); if (otmp->otyp == ACID_VENOM && resists_acid(mtmp)) damage = 0; if (ismimic) seemimic(mtmp); mtmp->msleeping = 0; if (vis) hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage)); else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage)); if (otmp->opoisoned && is_poisonable(otmp)) { if (resists_poison(mtmp)) { if (vis) pline_The("poison doesn't seem to affect %s.", mon_nam(mtmp)); } else { if (rn2(30)) { damage += rnd(6); } else { if (vis) pline_The("poison was deadly..."); damage = mtmp->mhp; } } } if (objects[otmp->otyp].oc_material == SILVER && mon_hates_silver(mtmp)) { if (vis) pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp))); else if (verbose) pline("Its flesh is seared!"); } if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) { if (resists_acid(mtmp)) { if (vis || verbose) pline("%s is unaffected.", Monnam(mtmp)); damage = 0; } else { if (vis) pline_The("acid burns %s!", mon_nam(mtmp)); else if (verbose) pline("It is burned!"); } } mtmp->mhp -= damage; if (mtmp->mhp < 1) { if (vis || verbose) pline("%s is %s!", Monnam(mtmp), (nonliving(mtmp->data) || is_vampshifter(mtmp) || !canspotmon(mtmp)) ? "destroyed" : "killed"); /* don't blame hero for unknown rolling boulder trap */ if (!context.mon_moving && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped)) xkilled(mtmp, 0); else mondied(mtmp); } if (can_blnd((struct monst *) 0, mtmp, (uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), otmp)) { if (vis && mtmp->mcansee) pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp))); mtmp->mcansee = 0; tmp = (int) mtmp->mblinded + rnd(25) + 20; if (tmp > 127) tmp = 127; mtmp->mblinded = tmp; } objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y); if (!objgone && range == -1) { /* special case */ obj_extract_self(otmp); /* free it for motion again */ return 0; } return 1; } return 0; } void m_throw(mon, x, y, dx, dy, range, obj) struct monst *mon; /* launching monster */ int x, y, dx, dy, range; /* launch point, direction, and range */ struct obj *obj; /* missile (or stack providing it) */ { struct monst *mtmp; struct obj *singleobj; char sym = obj->oclass; int hitu, oldumort, blindinc = 0; bhitpos.x = x; bhitpos.y = y; notonhead = FALSE; /* reset potentially stale value */ if (obj->quan == 1L) { /* * Remove object from minvent. This cannot be done later on; * what if the player dies before then, leaving the monster * with 0 daggers? (This caused the infamous 2^32-1 orcish * dagger bug). * * VENOM is not in minvent - it should already be OBJ_FREE. * The extract below does nothing. */ /* not possibly_unwield, which checks the object's */ /* location, not its existence */ if (MON_WEP(mon) == obj) setmnotwielded(mon, obj); obj_extract_self(obj); singleobj = obj; obj = (struct obj *) 0; } else { singleobj = splitobj(obj, 1L); obj_extract_self(singleobj); } singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */ if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) { if (canseemon(mon) && flags.verbose) { if (is_ammo(singleobj)) pline("%s misfires!", Monnam(mon)); else pline("%s as %s throws it!", Tobjnam(singleobj, "slip"), mon_nam(mon)); } dx = rn2(3) - 1; dy = rn2(3) - 1; /* check validity of new direction */ if (!dx && !dy) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } } /* pre-check for doors, walls and boundaries. Also need to pre-check for bars regardless of direction; the random chance for small objects hitting bars is skipped when reaching them at point blank range */ if (!isok(bhitpos.x + dx, bhitpos.y + dy) || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) || closed_door(bhitpos.x + dx, bhitpos.y + dy) || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS && hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } /* Note: drop_throw may destroy singleobj. Since obj must be destroyed * early to avoid the dagger bug, anyone who modifies this code should * be careful not to use either one after it's been freed. */ if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); while (range-- > 0) { /* Actually the loop is always exited by break */ bhitpos.x += dx; bhitpos.y += dy; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (ohitmon(mtmp, singleobj, range, TRUE)) break; } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (multi) nomul(0); if (singleobj->oclass == GEM_CLASS && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */ && is_unicorn(youmonst.data)) { if (singleobj->otyp > LAST_GEM) { You("catch the %s.", xname(singleobj)); You("are not interested in %s junk.", s_suffix(mon_nam(mon))); makeknown(singleobj->otyp); dropy(singleobj); } else { You( "accept %s gift in the spirit in which it was intended.", s_suffix(mon_nam(mon))); (void) hold_another_object( singleobj, "You catch, but drop, %s.", xname(singleobj), "You catch:"); } break; } if (singleobj->oclass == POTION_CLASS) { if (!Blind) singleobj->dknown = 1; potionhit(&youmonst, singleobj, FALSE); break; } oldumort = u.umortality; switch (singleobj->otyp) { int dam, hitv; case EGG: if (!touch_petrifies(&mons[singleobj->corpsenm])) { impossible("monster throwing egg type %d", singleobj->corpsenm); hitu = 0; break; } /* fall through */ case CREAM_PIE: case BLINDING_VENOM: hitu = thitu(8, 0, singleobj, (char *) 0); break; default: dam = dmgval(singleobj, &youmonst); hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my); if (hitv < -4) hitv = -4; if (is_elf(mon->data) && objects[singleobj->otyp].oc_skill == P_BOW) { hitv++; if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW) hitv++; if (singleobj->otyp == ELVEN_ARROW) dam++; } if (bigmonst(youmonst.data)) hitv++; hitv += 8 + singleobj->spe; if (dam < 1) dam = 1; hitu = thitu(hitv, dam, singleobj, (char *) 0); } if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) { char onmbuf[BUFSZ], knmbuf[BUFSZ]; Strcpy(onmbuf, xname(singleobj)); Strcpy(knmbuf, killer_xname(singleobj)); poisoned(onmbuf, A_STR, knmbuf, /* if damage triggered life-saving, poison is limited to attrib loss */ (u.umortality > oldumort) ? 0 : 10, TRUE); } if (hitu && can_blnd((struct monst *) 0, &youmonst, (uchar) (singleobj->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), singleobj)) { blindinc = rnd(25); if (singleobj->otyp == CREAM_PIE) { if (!Blind) pline("Yecch! You've been creamed."); else pline("There's %s sticky all over your %s.", something, body_part(FACE)); } else if (singleobj->otyp == BLINDING_VENOM) { const char *eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); /* venom in the eyes */ if (!Blind) pline_The("venom blinds you."); else Your("%s %s.", eyes, vtense(eyes, "sting")); } } if (hitu && singleobj->otyp == EGG) { if (!Stoned && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { make_stoned(5L, (char *) 0, KILLED_BY, ""); } } stop_occupation(); if (hitu || !range) { (void) drop_throw(singleobj, hitu, u.ux, u.uy); break; } } if (!range /* reached end of path */ /* missile hits edge of screen */ || !isok(bhitpos.x + dx, bhitpos.y + dy) /* missile hits the wall */ || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) /* missile hit closed door */ || closed_door(bhitpos.x + dx, bhitpos.y + dy) /* missile might hit iron bars */ || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS && hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0)) /* Thrown objects "sink" */ || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) { if (singleobj) /* hits_bars might have destroyed it */ (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); break; } tmp_at(bhitpos.x, bhitpos.y); delay_output(); } tmp_at(bhitpos.x, bhitpos.y); delay_output(); tmp_at(DISP_END, 0); if (blindinc) { u.ucreamed += blindinc; make_blinded(Blinded + (long) blindinc, FALSE); if (!Blind) Your1(vision_clears); } } /* remove an entire item from a monster's inventory; destroy that item */ void m_useupall(mon, obj) struct monst *mon; struct obj *obj; { obj_extract_self(obj); if (obj->owornmask) { if (obj == MON_WEP(mon)) mwepgone(mon); mon->misc_worn_check &= ~obj->owornmask; update_mon_intrinsics(mon, obj, FALSE, FALSE); obj->owornmask = 0L; } obfree(obj, (struct obj *) 0); } /* remove one instance of an item from a monster's inventory */ void m_useup(mon, obj) struct monst *mon; struct obj *obj; { if (obj->quan > 1L) { obj->quan--; obj->owt = weight(obj); } else { m_useupall(mon, obj); } } /* monster attempts ranged weapon attack against player */ void thrwmu(mtmp) struct monst *mtmp; { struct obj *otmp, *mwep; xchar x, y; int multishot; const char *onm; /* Rearranged beginning so monsters can use polearms not in a line */ if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { mtmp->weapon_check = NEED_RANGED_WEAPON; /* mon_wield_item resets weapon_check as appropriate */ if (mon_wield_item(mtmp) != 0) return; } /* Pick a weapon */ otmp = select_rwep(mtmp); if (!otmp) return; if (is_pole(otmp)) { int dam, hitv; if (otmp != MON_WEP(mtmp)) return; /* polearm must be wielded */ if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM || !couldsee(mtmp->mx, mtmp->my)) return; /* Out of range, or intervening wall */ if (canseemon(mtmp)) { onm = xname(otmp); pline("%s thrusts %s.", Monnam(mtmp), obj_is_pname(otmp) ? the(onm) : an(onm)); } dam = dmgval(otmp, &youmonst); hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my); if (hitv < -4) hitv = -4; if (bigmonst(youmonst.data)) hitv++; hitv += 8 + otmp->spe; if (dam < 1) dam = 1; (void) thitu(hitv, dam, otmp, (char *) 0); stop_occupation(); return; } x = mtmp->mx; y = mtmp->my; /* If you are coming toward the monster, the monster * should try to soften you up with missiles. If you are * going away, you are probably hurt or running. Give * chase, but if you are getting too far away, throw. */ if (!lined_up(mtmp) || (URETREATING(x, y) && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy)))) return; mwep = MON_WEP(mtmp); /* wielded weapon */ /* Multishot calculations */ multishot = 1; if (otmp->quan > 1L /* no point checking if there's only 1 */ /* ammo requires corresponding launcher be wielded */ && (is_ammo(otmp) ? matching_launcher(otmp, mwep) /* otherwise any stackable (non-ammo) weapon */ : otmp->oclass == WEAPON_CLASS) && !mtmp->mconf) { int skill = (int) objects[otmp->otyp].oc_skill; /* Assumes lords are skilled, princes are expert */ if (is_prince(mtmp->data)) multishot += 2; else if (is_lord(mtmp->data)) multishot++; /* fake players treated as skilled (regardless of role limits) */ else if (is_mplayer(mtmp->data)) multishot++; /* class bonus */ switch (monsndx(mtmp->data)) { case PM_MONK: if (skill == -P_SHURIKEN) multishot++; break; case PM_RANGER: multishot++; break; case PM_ROGUE: if (skill == P_DAGGER) multishot++; break; case PM_NINJA: if (skill == -P_SHURIKEN || skill == -P_DART) multishot++; /*FALLTHRU*/ case PM_SAMURAI: if (otmp->otyp == YA && mwep && mwep->otyp == YUMI) multishot++; break; default: break; } /* racial bonus */ if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep && mwep->otyp == ELVEN_BOW) || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep && mwep->otyp == ORCISH_BOW)) multishot++; multishot = rnd(multishot); if ((long) multishot > otmp->quan) multishot = (int) otmp->quan; } if (canseemon(mtmp)) { char onmbuf[BUFSZ]; if (multishot > 1) { /* "N arrows"; multishot > 1 implies otmp->quan > 1, so xname()'s result will already be pluralized */ Sprintf(onmbuf, "%d %s", multishot, xname(otmp)); onm = onmbuf; } else { /* "an arrow" */ onm = singular(otmp, xname); onm = obj_is_pname(otmp) ? the(onm) : an(onm); } m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE; pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm); m_shot.o = otmp->otyp; } else { m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */ } m_shot.n = multishot; for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) { m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp); /* conceptually all N missiles are in flight at once, but if mtmp gets killed (shot kills adjacent gas spore and triggers explosion, perhaps), inventory will be dropped and otmp might go away via merging into another stack */ if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) { /* cancel pending shots (ought to give a message here since we gave one above about throwing/shooting N missiles) */ break; /* endmultishot(FALSE); */ } } m_shot.n = m_shot.i = 0; m_shot.o = STRANGE_OBJECT; m_shot.s = FALSE; nomul(0); } /* monster spits substance at you */ int spitmu(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { struct obj *otmp; if (mtmp->mcan) { if (!Deaf) pline("A dry rattle comes from %s throat.", s_suffix(mon_nam(mtmp))); return 0; } if (lined_up(mtmp)) { switch (mattk->adtyp) { case AD_BLND: case AD_DRST: otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); break; default: impossible("bad attack type in spitmu"); /* fall through */ case AD_ACID: otmp = mksobj(ACID_VENOM, TRUE, FALSE); break; } if (!rn2(BOLT_LIM - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) { if (canseemon(mtmp)) pline("%s spits venom!", Monnam(mtmp)); m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp); nomul(0); return 0; } else { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } } return 0; } /* monster breathes at you (ranged) */ int breamu(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { /* if new breath types are added, change AD_ACID to max type */ int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp; if (lined_up(mtmp)) { if (mtmp->mcan) { if (!Deaf) { if (canseemon(mtmp)) pline("%s coughs.", Monnam(mtmp)); else You_hear("a cough."); } return 0; } if (!mtmp->mspec_used && rn2(3)) { if ((typ >= AD_MAGM) && (typ <= AD_ACID)) { if (canseemon(mtmp)) pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]); buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); nomul(0); /* breath runs out sometimes. Also, give monster some * cunning; don't breath if the player fell asleep. */ if (!rn2(3)) mtmp->mspec_used = 10 + rn2(20); if (typ == AD_SLEE && !Sleep_resistance) mtmp->mspec_used += rnd(20); } else impossible("Breath weapon %d used", typ - 1); } } return 1; } boolean linedup(ax, ay, bx, by, boulderhandling) register xchar ax, ay, bx, by; int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */ { int dx, dy, boulderspots; /* These two values are set for use after successful return. */ tbx = ax - bx; tby = ay - by; /* sometimes displacement makes a monster think that you're at its own location; prevent it from throwing and zapping in that case */ if (!tbx && !tby) return FALSE; if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */ && distmin(tbx, tby, 0, 0) < BOLT_LIM) { if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by) : clear_path(ax, ay, bx, by)) return TRUE; /* don't have line of sight, but might still be lined up if that lack of sight is due solely to boulders */ if (boulderhandling == 0) return FALSE; dx = sgn(ax - bx), dy = sgn(ay - by); boulderspots = 0; do { /* is guaranteed to eventually converge with */ bx += dx, by += dy; if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by)) return FALSE; if (sobj_at(BOULDER, bx, by)) ++boulderspots; } while (bx != ax || by != ay); /* reached target position without encountering obstacle */ if (boulderhandling == 1 || rn2(2 + boulderspots) < 2) return TRUE; } return FALSE; } /* is mtmp in position to use ranged attack? */ boolean lined_up(mtmp) register struct monst *mtmp; { boolean ignore_boulders; /* hero concealment usually trumps monst awareness of being lined up */ if (Upolyd && rn2(25) && (u.uundetected || (youmonst.m_ap_type != M_AP_NOTHING && youmonst.m_ap_type != M_AP_MONSTER))) return FALSE; ignore_boulders = (throws_rocks(mtmp->data) || m_carrying(mtmp, WAN_STRIKING)); return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my, ignore_boulders ? 1 : 2); } /* check if a monster is carrying a particular item */ struct obj * m_carrying(mtmp, type) struct monst *mtmp; int type; { register struct obj *otmp; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->otyp == type) return otmp; return (struct obj *) 0; } /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */ boolean hits_bars(obj_p, x, y, always_hit, whodidit) struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */ int x, y; int always_hit; /* caller can force a hit for items which would fit through */ int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ { struct obj *otmp = *obj_p; int obj_type = otmp->otyp; boolean hits = always_hit; if (!hits) switch (otmp->oclass) { case WEAPON_CLASS: { int oskill = objects[obj_type].oc_skill; hits = (oskill != -P_BOW && oskill != -P_CROSSBOW && oskill != -P_DART && oskill != -P_SHURIKEN && oskill != P_SPEAR && oskill != P_KNIFE); /* but not dagger */ break; } case ARMOR_CLASS: hits = (objects[obj_type].oc_armcat != ARM_GLOVES); break; case TOOL_CLASS: hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE && obj_type != WAX_CANDLE && obj_type != LENSES && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE); break; case ROCK_CLASS: /* includes boulder */ if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; break; case FOOD_CLASS: if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; else hits = (obj_type == MEAT_STICK || obj_type == HUGE_CHUNK_OF_MEAT); break; case SPBOOK_CLASS: case WAND_CLASS: case BALL_CLASS: case CHAIN_CLASS: hits = TRUE; break; default: break; } if (hits && whodidit != -1) { if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y)) *obj_p = otmp = 0; /* object is now gone */ /* breakage makes its own noises */ else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) pline("Whang!"); else if (otmp->oclass == COIN_CLASS || objects[obj_type].oc_material == GOLD || objects[obj_type].oc_material == SILVER) pline("Clink!"); else pline("Clonk!"); } return hits; } /*mthrowu.c*/ nethack-3.6.0/src/muse.c0000664000076400007660000024766712623532454014075 0ustar paxedpaxed/* NetHack 3.6 muse.c $NHDT-Date: 1447987786 2015/11/20 02:49:46 $ $NHDT-Branch: master $:$NHDT-Revision: 1.68 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ /* * Monster item usage routines. */ #include "hack.h" extern const int monstr[]; boolean m_using = FALSE; /* Let monsters use magic items. Arbitrary assumptions: Monsters only use * scrolls when they can see, monsters know when wands have 0 charges, * monsters cannot recognize if items are cursed are not, monsters which * are confused don't know not to read scrolls, etc.... */ STATIC_DCL struct permonst *FDECL(muse_newcham_mon, (struct monst *)); STATIC_DCL int FDECL(precheck, (struct monst *, struct obj *)); STATIC_DCL void FDECL(mzapmsg, (struct monst *, struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(mreadmsg, (struct monst *, struct obj *)); STATIC_DCL void FDECL(mquaffmsg, (struct monst *, struct obj *)); STATIC_PTR int FDECL(mbhitm, (struct monst *, struct obj *)); STATIC_DCL void FDECL(mbhit, (struct monst *, int, int FDECL((*), (MONST_P, OBJ_P)), int FDECL((*), (OBJ_P, OBJ_P)), struct obj *)); STATIC_DCL void FDECL(you_aggravate, (struct monst *)); STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(cures_stoning, (struct monst *, struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(mcould_eat_tin, (struct monst *)); STATIC_DCL boolean FDECL(muse_unslime, (struct monst *, struct obj *, BOOLEAN_P)); STATIC_DCL int FDECL(cures_sliming, (struct monst *, struct obj *)); STATIC_DCL boolean FDECL(green_mon, (struct monst *)); static struct musable { struct obj *offensive; struct obj *defensive; struct obj *misc; int has_offense, has_defense, has_misc; /* =0, no capability; otherwise, different numbers. * If it's an object, the object is also set (it's 0 otherwise). */ } m; static int trapx, trapy; static boolean zap_oseen; /* for wands which use mbhitm and are zapped at * players. We usually want an oseen local to * the function, but this is impossible since the * function mbhitm has to be compatible with the * normal zap routines, and those routines don't * remember who zapped the wand. */ /* Any preliminary checks which may result in the monster being unable to use * the item. Returns 0 if nothing happened, 2 if the monster can't do * anything (i.e. it teleported) and 1 if it's dead. */ STATIC_OVL int precheck(mon, obj) struct monst *mon; struct obj *obj; { boolean vis; if (!obj) return 0; vis = cansee(mon->mx, mon->my); if (obj->oclass == POTION_CLASS) { coord cc; static const char *empty = "The potion turns out to be empty."; const char *potion_descr; struct monst *mtmp; potion_descr = OBJ_DESCR(objects[obj->otyp]); if (potion_descr && !strcmp(potion_descr, "milky")) { if (!(mvitals[PM_GHOST].mvflags & G_GONE) && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_GHOST].born))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) return 0; mquaffmsg(mon, obj); m_useup(mon, obj); mtmp = makemon(&mons[PM_GHOST], cc.x, cc.y, NO_MM_FLAGS); if (!mtmp) { if (vis) pline1(empty); } else { if (vis) { pline( "As %s opens the bottle, an enormous %s emerges!", mon_nam(mon), Hallucination ? rndmonnam(NULL) : (const char *) "ghost"); pline("%s is frightened to death, and unable to move.", Monnam(mon)); } paralyze_monst(mon, 3); } return 2; } } if (potion_descr && !strcmp(potion_descr, "smoky") && !(mvitals[PM_DJINNI].mvflags & G_GONE) && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_DJINNI].born))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) return 0; mquaffmsg(mon, obj); m_useup(mon, obj); mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS); if (!mtmp) { if (vis) pline1(empty); } else { if (vis) pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp)); pline("%s speaks.", vis ? Monnam(mtmp) : Something); /* I suspect few players will be upset that monsters */ /* can't wish for wands of death here.... */ if (rn2(2)) { verbalize("You freed me!"); mtmp->mpeaceful = 1; set_malign(mtmp); } else { verbalize("It is about time."); if (vis) pline("%s vanishes.", Monnam(mtmp)); mongone(mtmp); } } return 2; } } if (obj->oclass == WAND_CLASS && obj->cursed && !rn2(WAND_BACKFIRE_CHANCE)) { int dam = d(obj->spe + 2, 6); if (!Deaf) { if (vis) pline("%s zaps %s, which suddenly explodes!", Monnam(mon), an(xname(obj))); else You_hear("a zap and an explosion in the distance."); } m_useup(mon, obj); if (mon->mhp <= dam) { monkilled(mon, "", AD_RBRE); return 1; } else mon->mhp -= dam; m.has_defense = m.has_offense = m.has_misc = 0; /* Only one needed to be set to 0 but the others are harmless */ } return 0; } STATIC_OVL void mzapmsg(mtmp, otmp, self) struct monst *mtmp; struct obj *otmp; boolean self; { if (!canseemon(mtmp)) { if (!Deaf) You_hear("a %s zap.", (distu(mtmp->mx, mtmp->my) <= (BOLT_LIM + 1) * (BOLT_LIM + 1)) ? "nearby" : "distant"); } else if (self) { pline("%s zaps %sself with %s!", Monnam(mtmp), mhim(mtmp), doname(otmp)); } else { pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp))); stop_occupation(); } } STATIC_OVL void mreadmsg(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { boolean vismon = canseemon(mtmp); char onambuf[BUFSZ]; short saverole; unsigned savebknown; if (!vismon && Deaf) return; /* no feedback */ otmp->dknown = 1; /* seeing or hearing it read reveals its label */ /* shouldn't be able to hear curse/bless status of unseen scrolls; for priest characters, bknown will always be set during naming */ savebknown = otmp->bknown; saverole = Role_switch; if (!vismon) { otmp->bknown = 0; if (Role_if(PM_PRIEST)) Role_switch = 0; } Strcpy(onambuf, singular(otmp, doname)); Role_switch = saverole; otmp->bknown = savebknown; if (vismon) pline("%s reads %s!", Monnam(mtmp), onambuf); else You_hear("%s reading %s.", x_monnam(mtmp, ARTICLE_A, (char *) 0, (SUPPRESS_IT | SUPPRESS_INVISIBLE | SUPPRESS_SADDLE), FALSE), onambuf); if (mtmp->mconf) pline("Being confused, %s mispronounces the magic words...", vismon ? mon_nam(mtmp) : mhe(mtmp)); } STATIC_OVL void mquaffmsg(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { if (canseemon(mtmp)) { otmp->dknown = 1; pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname)); } else if (!Deaf) You_hear("a chugging sound."); } /* Defines for various types of stuff. The order in which monsters prefer * to use them is determined by the order of the code logic, not the * numerical order in which they are defined. */ #define MUSE_SCR_TELEPORTATION 1 #define MUSE_WAN_TELEPORTATION_SELF 2 #define MUSE_POT_HEALING 3 #define MUSE_POT_EXTRA_HEALING 4 #define MUSE_WAN_DIGGING 5 #define MUSE_TRAPDOOR 6 #define MUSE_TELEPORT_TRAP 7 #define MUSE_UPSTAIRS 8 #define MUSE_DOWNSTAIRS 9 #define MUSE_WAN_CREATE_MONSTER 10 #define MUSE_SCR_CREATE_MONSTER 11 #define MUSE_UP_LADDER 12 #define MUSE_DN_LADDER 13 #define MUSE_SSTAIRS 14 #define MUSE_WAN_TELEPORTATION 15 #define MUSE_BUGLE 16 #define MUSE_UNICORN_HORN 17 #define MUSE_POT_FULL_HEALING 18 #define MUSE_LIZARD_CORPSE 19 /* #define MUSE_INNATE_TPT 9999 * We cannot use this. Since monsters get unlimited teleportation, if they * were allowed to teleport at will you could never catch them. Instead, * assume they only teleport at random times, despite the inconsistency * that if you polymorph into one you teleport at will. */ /* Select a defensive item/action for a monster. Returns TRUE iff one is found. */ boolean find_defensive(mtmp) struct monst *mtmp; { register struct obj *obj = 0; struct trap *t; int x = mtmp->mx, y = mtmp->my; boolean stuck = (mtmp == u.ustuck); boolean immobile = (mtmp->data->mmove == 0); int fraction; if (is_animal(mtmp->data) || mindless(mtmp->data)) return FALSE; if (dist2(x, y, mtmp->mux, mtmp->muy) > 25) return FALSE; if (u.uswallow && stuck) return FALSE; m.defensive = (struct obj *) 0; m.has_defense = 0; /* since unicorn horns don't get used up, the monster would look * silly trying to use the same cursed horn round after round */ if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) { if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) { for (obj = mtmp->minvent; obj; obj = obj->nobj) if (obj->otyp == UNICORN_HORN && !obj->cursed) break; } if (obj || is_unicorn(mtmp->data)) { m.defensive = obj; m.has_defense = MUSE_UNICORN_HORN; return TRUE; } } if (mtmp->mconf || mtmp->mstun) { struct obj *liztin = 0; for (obj = mtmp->minvent; obj; obj = obj->nobj) { if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) { m.defensive = obj; m.has_defense = MUSE_LIZARD_CORPSE; return TRUE; } else if (obj->otyp == TIN && obj->corpsenm == PM_LIZARD) { liztin = obj; } } /* confused or stunned monster might not be able to open tin */ if (liztin && mcould_eat_tin(mtmp) && rn2(3)) { m.defensive = liztin; /* tin and corpse ultimately end up being handled the same */ m.has_defense = MUSE_LIZARD_CORPSE; return TRUE; } } /* It so happens there are two unrelated cases when we might want to * check specifically for healing alone. The first is when the monster * is blind (healing cures blindness). The second is when the monster * is peaceful; then we don't want to flee the player, and by * coincidence healing is all there is that doesn't involve fleeing. * These would be hard to combine because of the control flow. * Pestilence won't use healing even when blind. */ if (!mtmp->mcansee && !nohands(mtmp->data) && mtmp->data != &mons[PM_PESTILENCE]) { if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_EXTRA_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_HEALING; return TRUE; } } fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3; if (mtmp->mhp >= mtmp->mhpmax || (mtmp->mhp >= 10 && mtmp->mhp * fraction >= mtmp->mhpmax)) return FALSE; if (mtmp->mpeaceful) { if (!nohands(mtmp->data)) { if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_EXTRA_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_HEALING; return TRUE; } } return FALSE; } if (stuck || immobile) { ; /* fleeing by stairs or traps is not possible */ } else if (levl[x][y].typ == STAIRS) { if (x == xdnstair && y == ydnstair) { if (!is_floater(mtmp->data)) m.has_defense = MUSE_DOWNSTAIRS; } else if (x == xupstair && y == yupstair) { /* don't let monster leave the dungeon with the Amulet */ if (ledger_no(&u.uz) != 1) m.has_defense = MUSE_UPSTAIRS; } else if (sstairs.sx && x == sstairs.sx && y == sstairs.sy) { if (sstairs.up || !is_floater(mtmp->data)) m.has_defense = MUSE_SSTAIRS; } } else if (levl[x][y].typ == LADDER) { if (x == xupladder && y == yupladder) { m.has_defense = MUSE_UP_LADDER; } else if (x == xdnladder && y == ydnladder) { if (!is_floater(mtmp->data)) m.has_defense = MUSE_DN_LADDER; } else if (sstairs.sx && x == sstairs.sx && y == sstairs.sy) { if (sstairs.up || !is_floater(mtmp->data)) m.has_defense = MUSE_SSTAIRS; } } else { /* Note: trap doors take precedence over teleport traps. */ int xx, yy, i, locs[10][2]; boolean ignore_boulders = (verysmall(mtmp->data) || throws_rocks(mtmp->data) || passes_walls(mtmp->data)), diag_ok = !NODIAG(monsndx(mtmp->data)); for (i = 0; i < 10; ++i) /* 10: 9 spots plus sentinel */ locs[i][0] = locs[i][1] = 0; /* collect viable spots; monster's comes first */ locs[0][0] = x, locs[0][1] = y; i = 1; for (xx = x - 1; xx <= x + 1; xx++) for (yy = y - 1; yy <= y + 1; yy++) if (isok(xx, yy) && (xx != x || yy != y)) { locs[i][0] = xx, locs[i][1] = yy; ++i; } /* look for a suitable trap among the viable spots */ for (i = 0; i < 10; ++i) { xx = locs[i][0], yy = locs[i][1]; if (!xx) break; /* we've run out of spots */ /* skip if it's hero's location or a diagonal spot and monster can't move diagonally or some other monster is there */ if ((xx == u.ux && yy == u.uy) || (xx != x && yy != y && !diag_ok) || (level.monsters[xx][yy] && !(xx == x && yy == y))) continue; /* skip if there's no trap or can't/won't move onto trap */ if ((t = t_at(xx, yy)) == 0 || (!ignore_boulders && sobj_at(BOULDER, xx, yy)) || onscary(xx, yy, mtmp)) continue; /* use trap if it's the correct type */ if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE) && !is_floater(mtmp->data) && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest && Can_fall_thru(&u.uz)) { trapx = xx; trapy = yy; m.has_defense = MUSE_TRAPDOOR; break; /* no need to look at any other spots */ } else if (t->ttyp == TELEP_TRAP) { trapx = xx; trapy = yy; m.has_defense = MUSE_TELEPORT_TRAP; } } } if (nohands(mtmp->data)) /* can't use objects */ goto botm; if (is_mercenary(mtmp->data) && (obj = m_carrying(mtmp, BUGLE)) != 0) { int xx, yy; struct monst *mon; /* Distance is arbitrary. What we really want to do is * have the soldier play the bugle when it sees or * remembers soldiers nearby... */ for (xx = x - 3; xx <= x + 3; xx++) { for (yy = y - 3; yy <= y + 3; yy++) { if (!isok(xx, yy) || (xx == x && yy == y)) continue; if ((mon = m_at(xx, yy)) != 0 && is_mercenary(mon->data) && mon->data != &mons[PM_GUARD] && (mon->msleeping || !mon->mcanmove)) { m.defensive = obj; m.has_defense = MUSE_BUGLE; goto toot; /* double break */ } } } toot: ; } /* use immediate physical escape prior to attempting magic */ if (m.has_defense) /* stairs, trap door or tele-trap, bugle alert */ goto botm; /* kludge to cut down on trap destruction (particularly portals) */ t = t_at(x, y); if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == WEB || t->ttyp == BEAR_TRAP)) t = 0; /* ok for monster to dig here */ #define nomore(x) if (m.has_defense == x) continue; /* selection could be improved by collecting all possibilities into an array and then picking one at random */ for (obj = mtmp->minvent; obj; obj = obj->nobj) { /* don't always use the same selection pattern */ if (m.has_defense && !rn2(3)) break; /* nomore(MUSE_WAN_DIGGING); */ if (m.has_defense == MUSE_WAN_DIGGING) break; if (obj->otyp == WAN_DIGGING && obj->spe > 0 && !stuck && !t && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest && !is_floater(mtmp->data) /* monsters digging in Sokoban can ruin things */ && !Sokoban /* digging wouldn't be effective; assume they know that */ && !(levl[x][y].wall_info & W_NONDIGGABLE) && !(Is_botlevel(&u.uz) || In_endgame(&u.uz)) && !(is_ice(x, y) || is_pool(x, y) || is_lava(x, y)) && !(mtmp->data == &mons[PM_VLAD_THE_IMPALER] && In_V_tower(&u.uz))) { m.defensive = obj; m.has_defense = MUSE_WAN_DIGGING; } nomore(MUSE_WAN_TELEPORTATION_SELF); nomore(MUSE_WAN_TELEPORTATION); if (obj->otyp == WAN_TELEPORTATION && obj->spe > 0) { /* use the TELEP_TRAP bit to determine if they know * about noteleport on this level or not. Avoids * ineffective re-use of teleportation. This does * mean if the monster leaves the level, they'll know * about teleport traps. */ if (!level.flags.noteleport || !(mtmp->mtrapseen & (1 << (TELEP_TRAP - 1)))) { m.defensive = obj; m.has_defense = (mon_has_amulet(mtmp)) ? MUSE_WAN_TELEPORTATION : MUSE_WAN_TELEPORTATION_SELF; } } nomore(MUSE_SCR_TELEPORTATION); if (obj->otyp == SCR_TELEPORTATION && mtmp->mcansee && haseyes(mtmp->data) && (!obj->cursed || (!(mtmp->isshk && inhishop(mtmp)) && !mtmp->isgd && !mtmp->ispriest))) { /* see WAN_TELEPORTATION case above */ if (!level.flags.noteleport || !(mtmp->mtrapseen & (1 << (TELEP_TRAP - 1)))) { m.defensive = obj; m.has_defense = MUSE_SCR_TELEPORTATION; } } if (mtmp->data != &mons[PM_PESTILENCE]) { nomore(MUSE_POT_FULL_HEALING); if (obj->otyp == POT_FULL_HEALING) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; } nomore(MUSE_POT_EXTRA_HEALING); if (obj->otyp == POT_EXTRA_HEALING) { m.defensive = obj; m.has_defense = MUSE_POT_EXTRA_HEALING; } nomore(MUSE_WAN_CREATE_MONSTER); if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) { m.defensive = obj; m.has_defense = MUSE_WAN_CREATE_MONSTER; } nomore(MUSE_POT_HEALING); if (obj->otyp == POT_HEALING) { m.defensive = obj; m.has_defense = MUSE_POT_HEALING; } } else { /* Pestilence */ nomore(MUSE_POT_FULL_HEALING); if (obj->otyp == POT_SICKNESS) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; } nomore(MUSE_WAN_CREATE_MONSTER); if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) { m.defensive = obj; m.has_defense = MUSE_WAN_CREATE_MONSTER; } } nomore(MUSE_SCR_CREATE_MONSTER); if (obj->otyp == SCR_CREATE_MONSTER) { m.defensive = obj; m.has_defense = MUSE_SCR_CREATE_MONSTER; } } botm: return (boolean) !!m.has_defense; #undef nomore } /* Perform a defensive action for a monster. Must be called immediately * after find_defensive(). Return values are 0: did something, 1: died, * 2: did something and can't attack again (i.e. teleported). */ int use_defensive(mtmp) struct monst *mtmp; { int i, fleetim, how = 0; struct obj *otmp = m.defensive; boolean vis, vismon, oseen; const char *mcsa = "%s can see again."; if ((i = precheck(mtmp, otmp)) != 0) return i; vis = cansee(mtmp->mx, mtmp->my); vismon = canseemon(mtmp); oseen = otmp && vismon; /* when using defensive choice to run away, we want monster to avoid rushing right straight back; don't override if already scared */ fleetim = !mtmp->mflee ? (33 - (30 * mtmp->mhp / mtmp->mhpmax)) : 0; #define m_flee(m) \ if (fleetim && !m->iswiz) { \ monflee(m, fleetim, FALSE, FALSE); \ } switch (m.has_defense) { case MUSE_UNICORN_HORN: if (vismon) { if (otmp) pline("%s uses a unicorn horn!", Monnam(mtmp)); else pline_The("tip of %s's horn glows!", mon_nam(mtmp)); } if (!mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } else if (mtmp->mconf || mtmp->mstun) { mtmp->mconf = mtmp->mstun = 0; if (vismon) pline("%s seems steadier now.", Monnam(mtmp)); } else impossible("No need for unicorn horn?"); return 2; case MUSE_BUGLE: if (vismon) pline("%s plays %s!", Monnam(mtmp), doname(otmp)); else if (!Deaf) You_hear("a bugle playing reveille!"); awaken_soldiers(mtmp); return 2; case MUSE_WAN_TELEPORTATION_SELF: if ((mtmp->isshk && inhishop(mtmp)) || mtmp->isgd || mtmp->ispriest) return 2; m_flee(mtmp); mzapmsg(mtmp, otmp, TRUE); otmp->spe--; how = WAN_TELEPORTATION; mon_tele: if (tele_restrict(mtmp)) { /* mysterious force... */ if (vismon && how) /* mentions 'teleport' */ makeknown(how); /* monster learns that teleportation isn't useful here */ if (level.flags.noteleport) mtmp->mtrapseen |= (1 << (TELEP_TRAP - 1)); return 2; } if ((mon_has_amulet(mtmp) || On_W_tower_level(&u.uz)) && !rn2(3)) { if (vismon) pline("%s seems disoriented for a moment.", Monnam(mtmp)); return 2; } if (oseen && how) makeknown(how); (void) rloc(mtmp, TRUE); return 2; case MUSE_WAN_TELEPORTATION: zap_oseen = oseen; mzapmsg(mtmp, otmp, FALSE); otmp->spe--; m_using = TRUE; mbhit(mtmp, rn1(8, 6), mbhitm, bhito, otmp); /* monster learns that teleportation isn't useful here */ if (level.flags.noteleport) mtmp->mtrapseen |= (1 << (TELEP_TRAP - 1)); m_using = FALSE; return 2; case MUSE_SCR_TELEPORTATION: { int obj_is_cursed = otmp->cursed; if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) return 2; m_flee(mtmp); mreadmsg(mtmp, otmp); m_useup(mtmp, otmp); /* otmp might be free'ed */ how = SCR_TELEPORTATION; if (obj_is_cursed || mtmp->mconf) { int nlev; d_level flev; if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (vismon) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 2; } nlev = random_teleport_level(); if (nlev == depth(&u.uz)) { if (vismon) pline("%s shudders for a moment.", Monnam(mtmp)); return 2; } get_level(&flev, nlev); migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, (coord *) 0); if (oseen) makeknown(SCR_TELEPORTATION); } else goto mon_tele; return 2; } case MUSE_WAN_DIGGING: { struct trap *ttmp; m_flee(mtmp); mzapmsg(mtmp, otmp, FALSE); otmp->spe--; if (oseen) makeknown(WAN_DIGGING); if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ) || IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ) || (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0) || (sstairs.sx && sstairs.sx == mtmp->mx && sstairs.sy == mtmp->my)) { pline_The("digging ray is ineffective."); return 2; } if (!Can_dig_down(&u.uz) && !levl[mtmp->mx][mtmp->my].candig) { if (canseemon(mtmp)) pline_The("%s here is too hard to dig in.", surface(mtmp->mx, mtmp->my)); return 2; } ttmp = maketrap(mtmp->mx, mtmp->my, HOLE); if (!ttmp) return 2; seetrap(ttmp); if (vis) { pline("%s has made a hole in the %s.", Monnam(mtmp), surface(mtmp->mx, mtmp->my)); pline("%s %s through...", Monnam(mtmp), is_flyer(mtmp->data) ? "dives" : "falls"); } else if (!Deaf) You_hear("%s crash through the %s.", something, surface(mtmp->mx, mtmp->my)); /* we made sure that there is a level for mtmp to go to */ migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM, (coord *) 0); return 2; } case MUSE_WAN_CREATE_MONSTER: { coord cc; /* pm: 0 => random, eel => aquatic, croc => amphibious */ struct permonst *pm = !is_pool(mtmp->mx, mtmp->my) ? 0 : &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE]; struct monst *mon; if (!enexto(&cc, mtmp->mx, mtmp->my, pm)) return 0; mzapmsg(mtmp, otmp, FALSE); otmp->spe--; mon = makemon((struct permonst *) 0, cc.x, cc.y, NO_MM_FLAGS); if (mon && canspotmon(mon) && oseen) makeknown(WAN_CREATE_MONSTER); return 2; } case MUSE_SCR_CREATE_MONSTER: { coord cc; struct permonst *pm = 0, *fish = 0; int cnt = 1; struct monst *mon; boolean known = FALSE; if (!rn2(73)) cnt += rnd(4); if (mtmp->mconf || otmp->cursed) cnt += 12; if (mtmp->mconf) pm = fish = &mons[PM_ACID_BLOB]; else if (is_pool(mtmp->mx, mtmp->my)) fish = &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE]; mreadmsg(mtmp, otmp); while (cnt--) { /* `fish' potentially gives bias towards water locations; `pm' is what to actually create (0 => random) */ if (!enexto(&cc, mtmp->mx, mtmp->my, fish)) break; mon = makemon(pm, cc.x, cc.y, NO_MM_FLAGS); if (mon && canspotmon(mon)) known = TRUE; } /* The only case where we don't use oseen. For wands, you * have to be able to see the monster zap the wand to know * what type it is. For teleport scrolls, you have to see * the monster to know it teleported. */ if (known) makeknown(SCR_CREATE_MONSTER); else if (!objects[SCR_CREATE_MONSTER].oc_name_known && !objects[SCR_CREATE_MONSTER].oc_uname) docall(otmp); m_useup(mtmp, otmp); return 2; } case MUSE_TRAPDOOR: /* trap doors on "bottom" levels of dungeons are rock-drop * trap doors, not holes in the floor. We check here for * safety. */ if (Is_botlevel(&u.uz)) return 0; m_flee(mtmp); if (vis) { struct trap *t = t_at(trapx, trapy); pline("%s %s into a %s!", Monnam(mtmp), makeplural(locomotion(mtmp->data, "jump")), t->ttyp == TRAPDOOR ? "trap door" : "hole"); if (levl[trapx][trapy].typ == SCORR) { levl[trapx][trapy].typ = CORR; unblock_point(trapx, trapy); } seetrap(t_at(trapx, trapy)); } /* don't use rloc_to() because worm tails must "move" */ remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); /* update old location */ place_monster(mtmp, trapx, trapy); if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM, (coord *) 0); return 2; case MUSE_UPSTAIRS: /* Monsters without amulets escape the dungeon and are * gone for good when they leave up the up stairs. * Monsters with amulets would reach the endlevel, * which we cannot allow since that would leave the * player stranded. */ if (ledger_no(&u.uz) == 1) { if (mon_has_special(mtmp)) return 0; if (vismon) pline("%s escapes the dungeon!", Monnam(mtmp)); mongone(mtmp); return 2; } m_flee(mtmp); if (Inhell && mon_has_amulet(mtmp) && !rn2(4) && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) { if (vismon) pline( "As %s climbs the stairs, a mysterious force momentarily surrounds %s...", mon_nam(mtmp), mhim(mtmp)); /* simpler than for the player; this will usually be the Wizard and he'll immediately go right to the upstairs, so there's not much point in having any chance for a random position on the current level */ migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM, (coord *) 0); } else { if (vismon) pline("%s escapes upstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_STAIRS_DOWN, (coord *) 0); } return 2; case MUSE_DOWNSTAIRS: m_flee(mtmp); if (vismon) pline("%s escapes downstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_STAIRS_UP, (coord *) 0); return 2; case MUSE_UP_LADDER: m_flee(mtmp); if (vismon) pline("%s escapes up the ladder!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_LADDER_DOWN, (coord *) 0); return 2; case MUSE_DN_LADDER: m_flee(mtmp); if (vismon) pline("%s escapes down the ladder!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_LADDER_UP, (coord *) 0); return 2; case MUSE_SSTAIRS: m_flee(mtmp); if (vismon) pline("%s escapes %sstairs!", Monnam(mtmp), sstairs.up ? "up" : "down"); /* going from the Valley to Castle (Stronghold) has no sstairs to target, but having sstairs. == <0,0> will work the same as specifying MIGR_RANDOM when mon_arrive() eventually places the monster, so we can use MIGR_SSTAIRS unconditionally */ migrate_to_level(mtmp, ledger_no(&sstairs.tolev), MIGR_SSTAIRS, (coord *) 0); return 2; case MUSE_TELEPORT_TRAP: m_flee(mtmp); if (vis) { pline("%s %s onto a teleport trap!", Monnam(mtmp), makeplural(locomotion(mtmp->data, "jump"))); seetrap(t_at(trapx, trapy)); } /* don't use rloc_to() because worm tails must "move" */ remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); /* update old location */ place_monster(mtmp, trapx, trapy); if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); goto mon_tele; case MUSE_POT_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 4); mtmp->mhp += i; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = ++mtmp->mhpmax; if (!otmp->cursed && !mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } if (vismon) pline("%s looks better.", Monnam(mtmp)); if (oseen) makeknown(POT_HEALING); m_useup(mtmp, otmp); return 2; case MUSE_POT_EXTRA_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 8); mtmp->mhp += i; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2)); if (!mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } if (vismon) pline("%s looks much better.", Monnam(mtmp)); if (oseen) makeknown(POT_EXTRA_HEALING); m_useup(mtmp, otmp); return 2; case MUSE_POT_FULL_HEALING: mquaffmsg(mtmp, otmp); if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */ mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4)); if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } if (vismon) pline("%s looks completely healed.", Monnam(mtmp)); if (oseen) makeknown(otmp->otyp); m_useup(mtmp, otmp); return 2; case MUSE_LIZARD_CORPSE: /* not actually called for its unstoning effect */ mon_consume_unstone(mtmp, otmp, FALSE, FALSE); return 2; case 0: return 0; /* i.e. an exploded wand */ default: impossible("%s wanted to perform action %d?", Monnam(mtmp), m.has_defense); break; } return 0; #undef m_flee } int rnd_defensive_item(mtmp) struct monst *mtmp; { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; int trycnt = 0; if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST || pm->mlet == S_KOP) return 0; try_again: switch (rn2(8 + (difficulty > 3) + (difficulty > 6) + (difficulty > 8))) { case 6: case 9: if (level.flags.noteleport && ++trycnt < 2) goto try_again; if (!rn2(3)) return WAN_TELEPORTATION; /* else FALLTHRU */ case 0: case 1: return SCR_TELEPORTATION; case 8: case 10: if (!rn2(3)) return WAN_CREATE_MONSTER; /* else FALLTHRU */ case 2: return SCR_CREATE_MONSTER; case 3: return POT_HEALING; case 4: return POT_EXTRA_HEALING; case 5: return (mtmp->data != &mons[PM_PESTILENCE]) ? POT_FULL_HEALING : POT_SICKNESS; case 7: if (is_floater(pm) || mtmp->isshk || mtmp->isgd || mtmp->ispriest) return 0; else return WAN_DIGGING; } /*NOTREACHED*/ return 0; } #define MUSE_WAN_DEATH 1 #define MUSE_WAN_SLEEP 2 #define MUSE_WAN_FIRE 3 #define MUSE_WAN_COLD 4 #define MUSE_WAN_LIGHTNING 5 #define MUSE_WAN_MAGIC_MISSILE 6 #define MUSE_WAN_STRIKING 7 #define MUSE_SCR_FIRE 8 #define MUSE_POT_PARALYSIS 9 #define MUSE_POT_BLINDNESS 10 #define MUSE_POT_CONFUSION 11 #define MUSE_FROST_HORN 12 #define MUSE_FIRE_HORN 13 #define MUSE_POT_ACID 14 /*#define MUSE_WAN_TELEPORTATION 15*/ #define MUSE_POT_SLEEPING 16 #define MUSE_SCR_EARTH 17 /* Select an offensive item/action for a monster. Returns TRUE iff one is * found. */ boolean find_offensive(mtmp) struct monst *mtmp; { register struct obj *obj; boolean reflection_skip = (Reflecting && rn2(2)); struct obj *helmet = which_armor(mtmp, W_ARMH); m.offensive = (struct obj *) 0; m.has_offense = 0; if (mtmp->mpeaceful || is_animal(mtmp->data) || mindless(mtmp->data) || nohands(mtmp->data)) return FALSE; if (u.uswallow) return FALSE; if (in_your_sanctuary(mtmp, 0, 0)) return FALSE; if (dmgtype(mtmp->data, AD_HEAL) && !uwep && !uarmu && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) return FALSE; /* all offensive items require orthogonal or diagonal targetting */ if (!lined_up(mtmp)) return FALSE; #define nomore(x) if (m.has_offense == x) continue; /* this picks the last viable item rather than prioritizing choices */ for (obj = mtmp->minvent; obj; obj = obj->nobj) { if (!reflection_skip) { nomore(MUSE_WAN_DEATH); if (obj->otyp == WAN_DEATH && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_DEATH; } nomore(MUSE_WAN_SLEEP); if (obj->otyp == WAN_SLEEP && obj->spe > 0 && multi >= 0) { m.offensive = obj; m.has_offense = MUSE_WAN_SLEEP; } nomore(MUSE_WAN_FIRE); if (obj->otyp == WAN_FIRE && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_FIRE; } nomore(MUSE_FIRE_HORN); if (obj->otyp == FIRE_HORN && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_FIRE_HORN; } nomore(MUSE_WAN_COLD); if (obj->otyp == WAN_COLD && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_COLD; } nomore(MUSE_FROST_HORN); if (obj->otyp == FROST_HORN && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_FROST_HORN; } nomore(MUSE_WAN_LIGHTNING); if (obj->otyp == WAN_LIGHTNING && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_LIGHTNING; } nomore(MUSE_WAN_MAGIC_MISSILE); if (obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_MAGIC_MISSILE; } } nomore(MUSE_WAN_STRIKING); if (obj->otyp == WAN_STRIKING && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_STRIKING; } nomore(MUSE_POT_PARALYSIS); if (obj->otyp == POT_PARALYSIS && multi >= 0) { m.offensive = obj; m.has_offense = MUSE_POT_PARALYSIS; } nomore(MUSE_POT_BLINDNESS); if (obj->otyp == POT_BLINDNESS && !attacktype(mtmp->data, AT_GAZE)) { m.offensive = obj; m.has_offense = MUSE_POT_BLINDNESS; } nomore(MUSE_POT_CONFUSION); if (obj->otyp == POT_CONFUSION) { m.offensive = obj; m.has_offense = MUSE_POT_CONFUSION; } nomore(MUSE_POT_SLEEPING); if (obj->otyp == POT_SLEEPING) { m.offensive = obj; m.has_offense = MUSE_POT_SLEEPING; } nomore(MUSE_POT_ACID); if (obj->otyp == POT_ACID) { m.offensive = obj; m.has_offense = MUSE_POT_ACID; } /* we can safely put this scroll here since the locations that * are in a 1 square radius are a subset of the locations that * are in wand or throwing range (in other words, always lined_up()) */ nomore(MUSE_SCR_EARTH); if (obj->otyp == SCR_EARTH && ((helmet && is_metallic(helmet)) || mtmp->mconf || amorphous(mtmp->data) || passes_walls(mtmp->data) || noncorporeal(mtmp->data) || unsolid(mtmp->data) || !rn2(10)) && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2 && mtmp->mcansee && haseyes(mtmp->data) && !Is_rogue_level(&u.uz) && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { m.offensive = obj; m.has_offense = MUSE_SCR_EARTH; } #if 0 nomore(MUSE_SCR_FIRE); if (obj->otyp == SCR_FIRE && resists_fire(mtmp) && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2 && mtmp->mcansee && haseyes(mtmp->data)) { m.offensive = obj; m.has_offense = MUSE_SCR_FIRE; } #endif /* 0 */ } return (boolean) !!m.has_offense; #undef nomore } STATIC_PTR int mbhitm(mtmp, otmp) register struct monst *mtmp; register struct obj *otmp; { int tmp; boolean reveal_invis = FALSE; if (mtmp != &youmonst) { mtmp->msleeping = 0; if (mtmp->m_ap_type) seemimic(mtmp); } switch (otmp->otyp) { case WAN_STRIKING: reveal_invis = TRUE; if (mtmp == &youmonst) { if (zap_oseen) makeknown(WAN_STRIKING); if (Antimagic) { shieldeff(u.ux, u.uy); pline("Boing!"); } else if (rnd(20) < 10 + u.uac) { pline_The("wand hits you!"); tmp = d(2, 12); if (Half_spell_damage) tmp = (tmp + 1) / 2; losehp(tmp, "wand", KILLED_BY_AN); } else pline_The("wand misses you."); stop_occupation(); nomul(0); } else if (resists_magm(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("Boing!"); } else if (rnd(20) < 10 + find_mac(mtmp)) { tmp = d(2, 12); hit("wand", mtmp, exclam(tmp)); (void) resist(mtmp, otmp->oclass, tmp, TELL); if (cansee(mtmp->mx, mtmp->my) && zap_oseen) makeknown(WAN_STRIKING); } else { miss("wand", mtmp); if (cansee(mtmp->mx, mtmp->my) && zap_oseen) makeknown(WAN_STRIKING); } break; case WAN_TELEPORTATION: if (mtmp == &youmonst) { if (zap_oseen) makeknown(WAN_TELEPORTATION); tele(); } else { /* for consistency with zap.c, don't identify */ if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s resists the magic!", Monnam(mtmp)); } else if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); } break; case WAN_CANCELLATION: case SPE_CANCELLATION: (void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE); break; } if (reveal_invis) { if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } return 0; } /* A modified bhit() for monsters. Based on bhit() in zap.c. Unlike * buzz(), bhit() doesn't take into account the possibility of a monster * zapping you, so we need a special function for it. (Unless someone wants * to merge the two functions...) */ STATIC_OVL void mbhit(mon, range, fhitm, fhito, obj) struct monst *mon; /* monster shooting the wand */ register int range; /* direction and range */ int FDECL((*fhitm), (MONST_P, OBJ_P)); int FDECL((*fhito), (OBJ_P, OBJ_P)); /* fns called when mon/obj hit */ struct obj *obj; /* 2nd arg to fhitm/fhito */ { register struct monst *mtmp; register struct obj *otmp; register uchar typ; int ddx, ddy; bhitpos.x = mon->mx; bhitpos.y = mon->my; ddx = sgn(mon->mux - mon->mx); ddy = sgn(mon->muy - mon->my); while (range-- > 0) { int x, y; bhitpos.x += ddx; bhitpos.y += ddy; x = bhitpos.x; y = bhitpos.y; if (!isok(x, y)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (find_drawbridge(&x, &y)) switch (obj->otyp) { case WAN_STRIKING: destroy_drawbridge(x, y); } if (bhitpos.x == u.ux && bhitpos.y == u.uy) { (*fhitm)(&youmonst, obj); range -= 3; } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); (*fhitm)(mtmp, obj); range -= 3; } /* modified by GAN to hit all objects */ if (fhito) { int hitanything = 0; register struct obj *next_obj; for (otmp = level.objects[bhitpos.x][bhitpos.y]; otmp; otmp = next_obj) { /* Fix for polymorph bug, Tim Wright */ next_obj = otmp->nexthere; hitanything += (*fhito)(otmp, obj); } if (hitanything) range--; } typ = levl[bhitpos.x][bhitpos.y].typ; if (IS_DOOR(typ) || typ == SDOOR) { switch (obj->otyp) { /* note: monsters don't use opening or locking magic at present, but keep these as placeholders */ case WAN_OPENING: case WAN_LOCKING: case WAN_STRIKING: if (doorlock(obj, bhitpos.x, bhitpos.y)) { if (zap_oseen) makeknown(obj->otyp); /* if a shop door gets broken, add it to the shk's fix list (no cost to player) */ if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) add_damage(bhitpos.x, bhitpos.y, 0L); } break; } } if (!ZAP_POS(typ) || (IS_DOOR(typ) && (levl[bhitpos.x][bhitpos.y].doormask & (D_LOCKED | D_CLOSED)))) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } } } /* Perform an offensive action for a monster. Must be called immediately * after find_offensive(). Return values are same as use_defensive(). */ int use_offensive(mtmp) struct monst *mtmp; { int i; struct obj *otmp = m.offensive; boolean oseen; /* offensive potions are not drunk, they're thrown */ if (otmp->oclass != POTION_CLASS && (i = precheck(mtmp, otmp)) != 0) return i; oseen = otmp && canseemon(mtmp); switch (m.has_offense) { case MUSE_WAN_DEATH: case MUSE_WAN_SLEEP: case MUSE_WAN_FIRE: case MUSE_WAN_COLD: case MUSE_WAN_LIGHTNING: case MUSE_WAN_MAGIC_MISSILE: mzapmsg(mtmp, otmp, FALSE); otmp->spe--; if (oseen) makeknown(otmp->otyp); m_using = TRUE; buzz((int) (-30 - (otmp->otyp - WAN_MAGIC_MISSILE)), (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my)); m_using = FALSE; return (mtmp->mhp <= 0) ? 1 : 2; case MUSE_FIRE_HORN: case MUSE_FROST_HORN: if (oseen) { makeknown(otmp->otyp); pline("%s plays a %s!", Monnam(mtmp), xname(otmp)); } else You_hear("a horn being played."); otmp->spe--; m_using = TRUE; buzz(-30 - ((otmp->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1), rn1(6, 6), mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my)); m_using = FALSE; return (mtmp->mhp <= 0) ? 1 : 2; case MUSE_WAN_TELEPORTATION: case MUSE_WAN_STRIKING: zap_oseen = oseen; mzapmsg(mtmp, otmp, FALSE); otmp->spe--; m_using = TRUE; mbhit(mtmp, rn1(8, 6), mbhitm, bhito, otmp); m_using = FALSE; return 2; case MUSE_SCR_EARTH: { /* TODO: handle steeds */ register int x, y; /* don't use monster fields after killing it */ boolean confused = (mtmp->mconf ? TRUE : FALSE); int mmx = mtmp->mx, mmy = mtmp->my; boolean is_cursed = otmp->cursed; mreadmsg(mtmp, otmp); /* Identify the scroll */ if (canspotmon(mtmp)) { pline_The("%s rumbles %s %s!", ceiling(mtmp->mx, mtmp->my), otmp->blessed ? "around" : "above", mon_nam(mtmp)); if (oseen) makeknown(otmp->otyp); } else if (cansee(mtmp->mx, mtmp->my)) { pline_The("%s rumbles in the middle of nowhere!", ceiling(mtmp->mx, mtmp->my)); if (mtmp->minvis) map_invisible(mtmp->mx, mtmp->my); if (oseen) makeknown(otmp->otyp); } /* Loop through the surrounding squares */ for (x = mmx - 1; x <= mmx + 1; x++) { for (y = mmy - 1; y <= mmy + 1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (((x == mmx) && (y == mmy)) ? !otmp->blessed : !otmp->cursed) && (x != u.ux || y != u.uy)) { (void) drop_boulder_on_monster(x, y, confused, FALSE); } } } m_useup(mtmp, otmp); /* Attack the player */ if (distmin(mmx, mmy, u.ux, u.uy) == 1 && !is_cursed) { drop_boulder_on_player(confused, !is_cursed, FALSE, TRUE); } return (mtmp->mhp <= 0) ? 1 : 2; } #if 0 case MUSE_SCR_FIRE: { boolean vis = cansee(mtmp->mx, mtmp->my); mreadmsg(mtmp, otmp); if (mtmp->mconf) { if (vis) pline("Oh, what a pretty fire!"); } else { struct monst *mtmp2; int num; if (vis) pline_The("scroll erupts in a tower of flame!"); shieldeff(mtmp->mx, mtmp->my); pline("%s is uninjured.", Monnam(mtmp)); (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); num = (2 * (rn1(3, 3) + 2 * bcsign(otmp)) + 1) / 3; if (Fire_resistance) You("are not harmed."); burn_away_slime(); if (Half_spell_damage) num = (num + 1) / 2; else losehp(num, "scroll of fire", KILLED_BY_AN); for (mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) { if (DEADMONSTER(mtmp2)) continue; if (mtmp == mtmp2) continue; if (dist2(mtmp2->mx, mtmp2->my, mtmp->mx, mtmp->my) < 3) { if (resists_fire(mtmp2)) continue; mtmp2->mhp -= num; if (resists_cold(mtmp2)) mtmp2->mhp -= 3 * num; if (mtmp2->mhp < 1) { mondied(mtmp2); break; } } } } return 2; } #endif /* 0 */ case MUSE_POT_PARALYSIS: case MUSE_POT_BLINDNESS: case MUSE_POT_CONFUSION: case MUSE_POT_SLEEPING: case MUSE_POT_ACID: /* Note: this setting of dknown doesn't suffice. A monster * which is out of sight might throw and it hits something _in_ * sight, a problem not existing with wands because wand rays * are not objects. Also set dknown in mthrowu.c. */ if (cansee(mtmp->mx, mtmp->my)) { otmp->dknown = 1; pline("%s hurls %s!", Monnam(mtmp), singular(otmp, doname)); } m_throw(mtmp, mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my), distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp); return 2; case 0: return 0; /* i.e. an exploded wand */ default: impossible("%s wanted to perform action %d?", Monnam(mtmp), m.has_offense); break; } return 0; } int rnd_offensive_item(mtmp) struct monst *mtmp; { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST || pm->mlet == S_KOP) return 0; if (difficulty > 7 && !rn2(35)) return WAN_DEATH; switch (rn2(9 - (difficulty < 4) + 4 * (difficulty > 6))) { case 0: { struct obj *helmet = which_armor(mtmp, W_ARMH); if ((helmet && is_metallic(helmet)) || amorphous(pm) || passes_walls(pm) || noncorporeal(pm) || unsolid(pm)) return SCR_EARTH; } /* fall through */ case 1: return WAN_STRIKING; case 2: return POT_ACID; case 3: return POT_CONFUSION; case 4: return POT_BLINDNESS; case 5: return POT_SLEEPING; case 6: return POT_PARALYSIS; case 7: case 8: return WAN_MAGIC_MISSILE; case 9: return WAN_SLEEP; case 10: return WAN_FIRE; case 11: return WAN_COLD; case 12: return WAN_LIGHTNING; } /*NOTREACHED*/ return 0; } #define MUSE_POT_GAIN_LEVEL 1 #define MUSE_WAN_MAKE_INVISIBLE 2 #define MUSE_POT_INVISIBILITY 3 #define MUSE_POLY_TRAP 4 #define MUSE_WAN_POLYMORPH 5 #define MUSE_POT_SPEED 6 #define MUSE_WAN_SPEED_MONSTER 7 #define MUSE_BULLWHIP 8 #define MUSE_POT_POLYMORPH 9 boolean find_misc(mtmp) struct monst *mtmp; { register struct obj *obj; struct permonst *mdat = mtmp->data; int x = mtmp->mx, y = mtmp->my; struct trap *t; int xx, yy, pmidx = NON_PM; boolean immobile = (mdat->mmove == 0); boolean stuck = (mtmp == u.ustuck); m.misc = (struct obj *) 0; m.has_misc = 0; if (is_animal(mdat) || mindless(mdat)) return 0; if (u.uswallow && stuck) return FALSE; /* We arbitrarily limit to times when a player is nearby for the * same reason as Junior Pac-Man doesn't have energizers eaten until * you can see them... */ if (dist2(x, y, mtmp->mux, mtmp->muy) > 36) return FALSE; if (!stuck && !immobile && (mtmp->cham == NON_PM) && monstr[(pmidx = monsndx(mdat))] < 6) { boolean ignore_boulders = (verysmall(mdat) || throws_rocks(mdat) || passes_walls(mdat)), diag_ok = !NODIAG(pmidx); for (xx = x - 1; xx <= x + 1; xx++) for (yy = y - 1; yy <= y + 1; yy++) if (isok(xx, yy) && (xx != u.ux || yy != u.uy) && (diag_ok || xx == x || yy == y) && ((xx == x && yy == y) || !level.monsters[xx][yy])) if ((t = t_at(xx, yy)) != 0 && (ignore_boulders || !sobj_at(BOULDER, xx, yy)) && !onscary(xx, yy, mtmp)) { /* use trap if it's the correct type */ if (t->ttyp == POLY_TRAP) { trapx = xx; trapy = yy; m.has_misc = MUSE_POLY_TRAP; return TRUE; } } } if (nohands(mdat)) return 0; #define nomore(x) if (m.has_misc == x) continue /* * [bug?] Choice of item is not prioritized; the last viable one * in the monster's inventory will be chosen. * 'nomore()' is nearly worthless because it only screens checking * of duplicates when there is no alternate type in between them. */ for (obj = mtmp->minvent; obj; obj = obj->nobj) { /* Monsters shouldn't recognize cursed items; this kludge is necessary to prevent serious problems though... */ if (obj->otyp == POT_GAIN_LEVEL && (!obj->cursed || (!mtmp->isgd && !mtmp->isshk && !mtmp->ispriest))) { m.misc = obj; m.has_misc = MUSE_POT_GAIN_LEVEL; } nomore(MUSE_BULLWHIP); if (obj->otyp == BULLWHIP && !mtmp->mpeaceful /* the random test prevents whip-wielding monster from attempting disarm every turn */ && uwep && !rn2(5) && obj == MON_WEP(mtmp) /* hero's location must be known and adjacent */ && mtmp->mux == u.ux && mtmp->muy == u.uy && distu(mtmp->mx, mtmp->my) <= 2 /* don't bother if it can't work (this doesn't prevent cursed weapons from being targetted) */ && (canletgo(uwep, "") || (u.twoweap && canletgo(uswapwep, "")))) { m.misc = obj; m.has_misc = MUSE_BULLWHIP; } /* Note: peaceful/tame monsters won't make themselves * invisible unless you can see them. Not really right, but... */ nomore(MUSE_WAN_MAKE_INVISIBLE); if (obj->otyp == WAN_MAKE_INVISIBLE && obj->spe > 0 && !mtmp->minvis && !mtmp->invis_blkd && (!mtmp->mpeaceful || See_invisible) && (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) { m.misc = obj; m.has_misc = MUSE_WAN_MAKE_INVISIBLE; } nomore(MUSE_POT_INVISIBILITY); if (obj->otyp == POT_INVISIBILITY && !mtmp->minvis && !mtmp->invis_blkd && (!mtmp->mpeaceful || See_invisible) && (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) { m.misc = obj; m.has_misc = MUSE_POT_INVISIBILITY; } nomore(MUSE_WAN_SPEED_MONSTER); if (obj->otyp == WAN_SPEED_MONSTER && obj->spe > 0 && mtmp->mspeed != MFAST && !mtmp->isgd) { m.misc = obj; m.has_misc = MUSE_WAN_SPEED_MONSTER; } nomore(MUSE_POT_SPEED); if (obj->otyp == POT_SPEED && mtmp->mspeed != MFAST && !mtmp->isgd) { m.misc = obj; m.has_misc = MUSE_POT_SPEED; } nomore(MUSE_WAN_POLYMORPH); if (obj->otyp == WAN_POLYMORPH && obj->spe > 0 && (mtmp->cham == NON_PM) && monstr[monsndx(mdat)] < 6) { m.misc = obj; m.has_misc = MUSE_WAN_POLYMORPH; } nomore(MUSE_POT_POLYMORPH); if (obj->otyp == POT_POLYMORPH && (mtmp->cham == NON_PM) && monstr[monsndx(mdat)] < 6) { m.misc = obj; m.has_misc = MUSE_POT_POLYMORPH; } } return (boolean) !!m.has_misc; #undef nomore } /* type of monster to polymorph into; defaults to one suitable for the current level rather than the totally arbitrary choice of newcham() */ static struct permonst * muse_newcham_mon(mon) struct monst *mon; { struct obj *m_armr; if ((m_armr = which_armor(mon, W_ARM)) != 0) { if (Is_dragon_scales(m_armr)) return Dragon_scales_to_pm(m_armr); else if (Is_dragon_mail(m_armr)) return Dragon_mail_to_pm(m_armr); } return rndmonst(); } int use_misc(mtmp) struct monst *mtmp; { int i; struct obj *otmp = m.misc; boolean vis, vismon, oseen; char nambuf[BUFSZ]; if ((i = precheck(mtmp, otmp)) != 0) return i; vis = cansee(mtmp->mx, mtmp->my); vismon = canseemon(mtmp); oseen = otmp && vismon; switch (m.has_misc) { case MUSE_POT_GAIN_LEVEL: mquaffmsg(mtmp, otmp); if (otmp->cursed) { if (Can_rise_up(mtmp->mx, mtmp->my, &u.uz)) { register int tolev = depth(&u.uz) - 1; d_level tolevel; get_level(&tolevel, tolev); /* insurance against future changes... */ if (on_level(&tolevel, &u.uz)) goto skipmsg; if (vismon) { pline("%s rises up, through the %s!", Monnam(mtmp), ceiling(mtmp->mx, mtmp->my)); if (!objects[POT_GAIN_LEVEL].oc_name_known && !objects[POT_GAIN_LEVEL].oc_uname) docall(otmp); } m_useup(mtmp, otmp); migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *) 0); return 2; } else { skipmsg: if (vismon) { pline("%s looks uneasy.", Monnam(mtmp)); if (!objects[POT_GAIN_LEVEL].oc_name_known && !objects[POT_GAIN_LEVEL].oc_uname) docall(otmp); } m_useup(mtmp, otmp); return 2; } } if (vismon) pline("%s seems more experienced.", Monnam(mtmp)); if (oseen) makeknown(POT_GAIN_LEVEL); m_useup(mtmp, otmp); if (!grow_up(mtmp, (struct monst *) 0)) return 1; /* grew into genocided monster */ return 2; case MUSE_WAN_MAKE_INVISIBLE: case MUSE_POT_INVISIBILITY: if (otmp->otyp == WAN_MAKE_INVISIBLE) { mzapmsg(mtmp, otmp, TRUE); otmp->spe--; } else mquaffmsg(mtmp, otmp); /* format monster's name before altering its visibility */ Strcpy(nambuf, mon_nam(mtmp)); mon_set_minvis(mtmp); if (vismon && mtmp->minvis) { /* was seen, now invisible */ if (canspotmon(mtmp)) pline("%s body takes on a %s transparency.", upstart(s_suffix(nambuf)), Hallucination ? "normal" : "strange"); else pline("Suddenly you cannot see %s.", nambuf); if (oseen) makeknown(otmp->otyp); } if (otmp->otyp == POT_INVISIBILITY) { if (otmp->cursed) you_aggravate(mtmp); m_useup(mtmp, otmp); } return 2; case MUSE_WAN_SPEED_MONSTER: mzapmsg(mtmp, otmp, TRUE); otmp->spe--; mon_adjust_speed(mtmp, 1, otmp); return 2; case MUSE_POT_SPEED: mquaffmsg(mtmp, otmp); /* note difference in potion effect due to substantially different methods of maintaining speed ratings: player's character becomes "very fast" temporarily; monster becomes "one stage faster" permanently */ mon_adjust_speed(mtmp, 1, otmp); m_useup(mtmp, otmp); return 2; case MUSE_WAN_POLYMORPH: mzapmsg(mtmp, otmp, TRUE); otmp->spe--; (void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE, FALSE); if (oseen) makeknown(WAN_POLYMORPH); return 2; case MUSE_POT_POLYMORPH: mquaffmsg(mtmp, otmp); if (vismon) pline("%s suddenly mutates!", Monnam(mtmp)); (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE); if (oseen) makeknown(POT_POLYMORPH); m_useup(mtmp, otmp); return 2; case MUSE_POLY_TRAP: if (vismon) pline("%s deliberately %s onto a polymorph trap!", Monnam(mtmp), makeplural(locomotion(mtmp->data, "jump"))); if (vis) seetrap(t_at(trapx, trapy)); /* don't use rloc() due to worms */ remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); place_monster(mtmp, trapx, trapy); if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); (void) newcham(mtmp, (struct permonst *) 0, FALSE, FALSE); return 2; case MUSE_BULLWHIP: /* attempt to disarm hero */ { const char *The_whip = vismon ? "The bullwhip" : "A whip"; int where_to = rn2(4); struct obj *obj = uwep; const char *hand; char the_weapon[BUFSZ]; if (!obj || !canletgo(obj, "") || (u.twoweap && canletgo(uswapwep, "") && rn2(2))) obj = uswapwep; if (!obj) break; /* shouldn't happen after find_misc() */ Strcpy(the_weapon, the(xname(obj))); hand = body_part(HAND); if (bimanual(obj)) hand = makeplural(hand); if (vismon) pline("%s flicks a bullwhip towards your %s!", Monnam(mtmp), hand); if (obj->otyp == HEAVY_IRON_BALL) { pline("%s fails to wrap around %s.", The_whip, the_weapon); return 1; } pline("%s wraps around %s you're wielding!", The_whip, the_weapon); if (welded(obj)) { pline("%s welded to your %s%c", !is_plural(obj) ? "It is" : "They are", hand, !obj->bknown ? '!' : '.'); /* obj->bknown = 1; */ /* welded() takes care of this */ where_to = 0; } if (!where_to) { pline_The("whip slips free."); /* not `The_whip' */ return 1; } else if (where_to == 3 && mon_hates_silver(mtmp) && objects[obj->otyp].oc_material == SILVER) { /* this monster won't want to catch a silver weapon; drop it at hero's feet instead */ where_to = 2; } remove_worn_item(obj, FALSE); freeinv(obj); switch (where_to) { case 1: /* onto floor beneath mon */ pline("%s yanks %s from your %s!", Monnam(mtmp), the_weapon, hand); place_object(obj, mtmp->mx, mtmp->my); break; case 2: /* onto floor beneath you */ pline("%s yanks %s to the %s!", Monnam(mtmp), the_weapon, surface(u.ux, u.uy)); dropy(obj); break; case 3: /* into mon's inventory */ pline("%s snatches %s!", Monnam(mtmp), the_weapon); (void) mpickobj(mtmp, obj); break; } return 1; } return 0; case 0: return 0; /* i.e. an exploded wand */ default: impossible("%s wanted to perform action %d?", Monnam(mtmp), m.has_misc); break; } return 0; } STATIC_OVL void you_aggravate(mtmp) struct monst *mtmp; { pline("For some reason, %s presence is known to you.", s_suffix(noit_mon_nam(mtmp))); cls(); #ifdef CLIPPING cliparound(mtmp->mx, mtmp->my); #endif show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp)); display_self(); You_feel("aggravated at %s.", noit_mon_nam(mtmp)); display_nhwindow(WIN_MAP, TRUE); docrt(); if (unconscious()) { multi = -1; nomovemsg = "Aggravated, you are jolted into full consciousness."; } newsym(mtmp->mx, mtmp->my); if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); } int rnd_misc_item(mtmp) struct monst *mtmp; { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST || pm->mlet == S_KOP) return 0; /* Unlike other rnd_item functions, we only allow _weak_ monsters * to have this item; after all, the item will be used to strengthen * the monster and strong monsters won't use it at all... */ if (difficulty < 6 && !rn2(30)) return rn2(6) ? POT_POLYMORPH : WAN_POLYMORPH; if (!rn2(40) && !nonliving(pm) && !is_vampshifter(mtmp)) return AMULET_OF_LIFE_SAVING; switch (rn2(3)) { case 0: if (mtmp->isgd) return 0; return rn2(6) ? POT_SPEED : WAN_SPEED_MONSTER; case 1: if (mtmp->mpeaceful && !See_invisible) return 0; return rn2(6) ? POT_INVISIBILITY : WAN_MAKE_INVISIBLE; case 2: return POT_GAIN_LEVEL; } /*NOTREACHED*/ return 0; } boolean searches_for_item(mon, obj) struct monst *mon; struct obj *obj; { int typ = obj->otyp; if (is_animal(mon->data) || mindless(mon->data) || mon->data == &mons[PM_GHOST]) /* don't loot bones piles */ return FALSE; if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY) return (boolean) (!mon->minvis && !mon->invis_blkd && !attacktype(mon->data, AT_GAZE)); if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED) return (boolean) (mon->mspeed != MFAST); switch (obj->oclass) { case WAND_CLASS: if (obj->spe <= 0) return FALSE; if (typ == WAN_DIGGING) return (boolean) !is_floater(mon->data); if (typ == WAN_POLYMORPH) return (boolean) (monstr[monsndx(mon->data)] < 6); if (objects[typ].oc_dir == RAY || typ == WAN_STRIKING || typ == WAN_TELEPORTATION || typ == WAN_CREATE_MONSTER) return TRUE; break; case POTION_CLASS: if (typ == POT_HEALING || typ == POT_EXTRA_HEALING || typ == POT_FULL_HEALING || typ == POT_POLYMORPH || typ == POT_GAIN_LEVEL || typ == POT_PARALYSIS || typ == POT_SLEEPING || typ == POT_ACID || typ == POT_CONFUSION) return TRUE; if (typ == POT_BLINDNESS && !attacktype(mon->data, AT_GAZE)) return TRUE; break; case SCROLL_CLASS: if (typ == SCR_TELEPORTATION || typ == SCR_CREATE_MONSTER || typ == SCR_EARTH || typ == SCR_FIRE) return TRUE; break; case AMULET_CLASS: if (typ == AMULET_OF_LIFE_SAVING) return (boolean) !(nonliving(mon->data) || is_vampshifter(mon)); if (typ == AMULET_OF_REFLECTION) return TRUE; break; case TOOL_CLASS: if (typ == PICK_AXE) return (boolean) needspick(mon->data); if (typ == UNICORN_HORN) return (boolean) (!obj->cursed && !is_unicorn(mon->data)); if (typ == FROST_HORN || typ == FIRE_HORN) return (obj->spe > 0); break; case FOOD_CLASS: if (typ == CORPSE) return (boolean) (((mon->misc_worn_check & W_ARMG) != 0L && touch_petrifies(&mons[obj->corpsenm])) || (!resists_ston(mon) && cures_stoning(mon, obj, FALSE))); if (typ == TIN) return (boolean) (mcould_eat_tin(mon) && (!resists_ston(mon) && cures_stoning(mon, obj, TRUE))); if (typ == EGG) return (boolean) touch_petrifies(&mons[obj->corpsenm]); break; default: break; } return FALSE; } boolean mon_reflects(mon, str) struct monst *mon; const char *str; { struct obj *orefl = which_armor(mon, W_ARMS); if (orefl && orefl->otyp == SHIELD_OF_REFLECTION) { if (str) { pline(str, s_suffix(mon_nam(mon)), "shield"); makeknown(SHIELD_OF_REFLECTION); } return TRUE; } else if (arti_reflects(MON_WEP(mon))) { /* due to wielded artifact weapon */ if (str) pline(str, s_suffix(mon_nam(mon)), "weapon"); return TRUE; } else if ((orefl = which_armor(mon, W_AMUL)) && orefl->otyp == AMULET_OF_REFLECTION) { if (str) { pline(str, s_suffix(mon_nam(mon)), "amulet"); makeknown(AMULET_OF_REFLECTION); } return TRUE; } else if ((orefl = which_armor(mon, W_ARM)) && (orefl->otyp == SILVER_DRAGON_SCALES || orefl->otyp == SILVER_DRAGON_SCALE_MAIL)) { if (str) pline(str, s_suffix(mon_nam(mon)), "armor"); return TRUE; } else if (mon->data == &mons[PM_SILVER_DRAGON] || mon->data == &mons[PM_CHROMATIC_DRAGON]) { /* Silver dragons only reflect when mature; babies do not */ if (str) pline(str, s_suffix(mon_nam(mon)), "scales"); return TRUE; } return FALSE; } boolean ureflects(fmt, str) const char *fmt, *str; { /* Check from outermost to innermost objects */ if (EReflecting & W_ARMS) { if (fmt && str) { pline(fmt, str, "shield"); makeknown(SHIELD_OF_REFLECTION); } return TRUE; } else if (EReflecting & W_WEP) { /* Due to wielded artifact weapon */ if (fmt && str) pline(fmt, str, "weapon"); return TRUE; } else if (EReflecting & W_AMUL) { if (fmt && str) { pline(fmt, str, "medallion"); makeknown(AMULET_OF_REFLECTION); } return TRUE; } else if (EReflecting & W_ARM) { if (fmt && str) pline(fmt, str, uskin ? "luster" : "armor"); return TRUE; } else if (youmonst.data == &mons[PM_SILVER_DRAGON]) { if (fmt && str) pline(fmt, str, "scales"); return TRUE; } return FALSE; } /* TRUE if the monster ate something */ boolean munstone(mon, by_you) struct monst *mon; boolean by_you; { struct obj *obj; boolean tinok; if (resists_ston(mon)) return FALSE; if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE; mon->mstrategy &= ~STRAT_WAITFORU; tinok = mcould_eat_tin(mon); for (obj = mon->minvent; obj; obj = obj->nobj) { if (cures_stoning(mon, obj, tinok)) { mon_consume_unstone(mon, obj, by_you, TRUE); return TRUE; } } return FALSE; } STATIC_OVL void mon_consume_unstone(mon, obj, by_you, stoning) struct monst *mon; struct obj *obj; boolean by_you; boolean stoning; { boolean vis = canseemon(mon), tinned = obj->otyp == TIN, food = obj->otyp == CORPSE || tinned, acid = obj->otyp == POT_ACID || (food && acidic(&mons[obj->corpsenm])), lizard = food && obj->corpsenm == PM_LIZARD; int nutrit = food ? dog_nutrition(mon, obj) : 0; /* also sets meating */ /* give a " is slowing down" message and also remove intrinsic speed (comparable to similar effect on the hero) */ if (stoning) mon_adjust_speed(mon, -3, (struct obj *) 0); if (vis) { long save_quan = obj->quan; obj->quan = 1L; pline("%s %s %s.", Monnam(mon), (obj->oclass == POTION_CLASS) ? "quaffs" : (obj->otyp == TIN) ? "opens and eats the contents of" : "eats", distant_name(obj, doname)); obj->quan = save_quan; } else if (!Deaf) You_hear("%s.", (obj->oclass == POTION_CLASS) ? "drinking" : "chewing"); m_useup(mon, obj); /* obj is now gone */ if (acid && !tinned && !resists_acid(mon)) { mon->mhp -= rnd(15); if (vis) pline("%s has a very bad case of stomach acid.", Monnam(mon)); if (mon->mhp <= 0) { pline("%s dies!", Monnam(mon)); if (by_you) xkilled(mon, 0); else mondead(mon); return; } } if (stoning && vis) { if (Hallucination) pline("What a pity - %s just ruined a future piece of art!", mon_nam(mon)); else pline("%s seems limber!", Monnam(mon)); } if (lizard && (mon->mconf || mon->mstun)) { mon->mconf = 0; mon->mstun = 0; if (vis && !is_bat(mon->data) && mon->data != &mons[PM_STALKER]) pline("%s seems steadier now.", Monnam(mon)); } if (mon->mtame && !mon->isminion && nutrit > 0) { struct edog *edog = EDOG(mon); if (edog->hungrytime < monstermoves) edog->hungrytime = monstermoves; edog->hungrytime += nutrit; mon->mconf = 0; } /* use up monster's next move */ mon->movement -= NORMAL_SPEED; mon->mlstmv = monstermoves; } /* decide whether obj can cure petrification; also used when picking up */ STATIC_OVL boolean cures_stoning(mon, obj, tinok) struct monst *mon; struct obj *obj; boolean tinok; { if (obj->otyp == POT_ACID) return TRUE; if (obj->otyp != CORPSE && (obj->otyp != TIN || !tinok)) return FALSE; /* corpse, or tin that mon can open */ return (boolean) (obj->corpsenm == PM_LIZARD || (acidic(&mons[obj->corpsenm]) && (obj->corpsenm != PM_GREEN_SLIME || slimeproof(mon->data)))); } STATIC_OVL boolean mcould_eat_tin(mon) struct monst *mon; { struct obj *obj, *mwep; boolean welded_wep; /* monkeys who manage to steal tins can't open and eat them even if they happen to also have the appropriate tool */ if (is_animal(mon->data)) return FALSE; mwep = MON_WEP(mon); welded_wep = mwep && mwelded(mwep); /* this is different from the player; tin opener or dagger doesn't have to be wielded, and knife can be used instead of dagger */ for (obj = mon->minvent; obj; obj = obj->nobj) { /* if stuck with a cursed weapon, don't check rest of inventory */ if (welded_wep && obj != mwep) continue; if (obj->otyp == TIN_OPENER || (obj->oclass == WEAPON_CLASS && (objects[obj->otyp].oc_skill == P_DAGGER || objects[obj->otyp].oc_skill == P_KNIFE))) return TRUE; } return FALSE; } /* TRUE if monster does something to avoid turning into green slime */ boolean munslime(mon, by_you) struct monst *mon; boolean by_you; { struct obj *obj, odummy; /* * muse_unslime() gives "mon starts turning green", "mon zaps * itself with a wand of fire", and "mon's slime burns away" * messages. Monsters who don't get any chance at that just have * (via our caller) newcham()'s "mon turns into slime" feedback. */ if (slimeproof(mon->data)) return FALSE; if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE; mon->mstrategy &= ~STRAT_WAITFORU; /* if monster can breathe fire, do so upon self; a monster who deals fire damage by biting, clawing, gazing, and especially exploding isn't able to cure itself of green slime with its own attack [possible extension: monst capable of casting high level clerical spells could toss pillar of fire at self--probably too suicidal] */ if (!mon->mcan && !mon->mspec_used && attacktype_fordmg(mon->data, AT_BREA, AD_FIRE)) { odummy = zeroobj; /* otyp == STRANGE_OBJECT */ return muse_unslime(mon, &odummy, by_you); } for (obj = mon->minvent; obj; obj = obj->nobj) if (cures_sliming(mon, obj)) return muse_unslime(mon, obj, by_you); /* TODO: check for and move onto an adjacent fire trap */ return FALSE; } /* mon uses an item--selected by caller--to burn away incipient slime */ STATIC_OVL boolean muse_unslime(mon, obj, by_you) struct monst *mon; struct obj *obj; boolean by_you; /* true: if mon kills itself, hero gets credit/blame */ { struct obj *odummyp; int otyp = obj->otyp, dmg; boolean vis = canseemon(mon), res = TRUE; if (vis) pline("%s starts turning %s.", Monnam(mon), green_mon(mon) ? "into ooze" : hcolor(NH_GREEN)); /* -4 => sliming, causes quiet loss of enhanced speed */ mon_adjust_speed(mon, -4, (struct obj *) 0); if (otyp == STRANGE_OBJECT) { /* monster is using fire breath on self */ if (vis) pline("%s breathes fire on %sself.", Monnam(mon), mhim(mon)); if (!rn2(3)) mon->mspec_used = rn1(10, 5); /* -21 => monster's fire breath; 1 => # of damage dice */ (void) zhitm(mon, by_you ? 21 : -21, 1, &odummyp); } else if (otyp == SCR_FIRE) { mreadmsg(mon, obj); if (mon->mconf) { if (cansee(mon->mx, mon->my)) pline("Oh, what a pretty fire!"); if (vis && !objects[otyp].oc_name_known && !objects[otyp].oc_uname) docall(obj); m_useup(mon, obj); /* after docall() */ vis = FALSE; /* skip makeknown() below */ res = FALSE; /* failed to cure sliming */ } else { m_useup(mon, obj); /* before explode() */ dmg = (2 * (rn1(3, 3) + 2 * bcsign(obj)) + 1) / 3; /* -11 => monster's fireball */ explode(mon->mx, mon->my, -11, dmg, SCROLL_CLASS, /* by_you: override -11 for mon but not others */ by_you ? -EXPL_FIERY : EXPL_FIERY); } } else { /* wand/horn of fire w/ positive charge count */ mzapmsg(mon, obj, TRUE); obj->spe--; /* -1 => monster's wand of fire; 2 => # of damage dice */ (void) zhitm(mon, by_you ? 1 : -1, 2, &odummyp); } if (vis) { if (res && mon->mhp > 0) pline("%s slime is burned away!", s_suffix(Monnam(mon))); if (otyp != STRANGE_OBJECT) makeknown(otyp); } /* use up monster's next move */ mon->movement -= NORMAL_SPEED; mon->mlstmv = monstermoves; return res; } /* decide whether obj can be used to cure green slime */ STATIC_OVL int cures_sliming(mon, obj) struct monst *mon; struct obj *obj; { /* scroll of fire, non-empty wand or horn of fire */ if (obj->otyp == SCR_FIRE) return (haseyes(mon->data) && mon->mcansee); /* hero doesn't need hands or even limbs to zap, so mon doesn't either */ return ((obj->otyp == WAN_FIRE || obj->otyp == FIRE_HORN) && obj->spe > 0); } /* TRUE if monster appears to be green; for active TEXTCOLOR, we go by the display color, otherwise we just pick things that seem plausibly green (which doesn't necessarily match the TEXTCOLOR categorization) */ STATIC_OVL boolean green_mon(mon) struct monst *mon; { struct permonst *ptr = mon->data; if (Hallucination) return FALSE; #ifdef TEXTCOLOR if (iflags.use_color) return (ptr->mcolor == CLR_GREEN || ptr->mcolor == CLR_BRIGHT_GREEN); #endif /* approximation */ if (strstri(ptr->mname, "green")) return TRUE; switch (monsndx(ptr)) { case PM_FOREST_CENTAUR: case PM_GARTER_SNAKE: case PM_GECKO: case PM_GREMLIN: case PM_HOMUNCULUS: case PM_JUIBLEX: case PM_LEPRECHAUN: case PM_LICHEN: case PM_LIZARD: case PM_WOOD_NYMPH: return TRUE; default: if (is_elf(ptr) && !is_prince(ptr) && !is_lord(ptr) && ptr != &mons[PM_GREY_ELF]) return TRUE; break; } return FALSE; } /*muse.c*/ nethack-3.6.0/src/music.c0000664000076400007660000007336712617122742014234 0ustar paxedpaxed/* NetHack 3.6 music.c $NHDT-Date: 1446808448 2015/11/06 11:14:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the different functions designed to manipulate the * musical instruments and their various effects. * * Actually the list of instruments / effects is : * * (wooden) flute may calm snakes if player has enough dexterity * magic flute may put monsters to sleep: area of effect depends * on player level. * (tooled) horn Will awaken monsters: area of effect depends on * player level. May also scare monsters. * fire horn Acts like a wand of fire. * frost horn Acts like a wand of cold. * bugle Will awaken soldiers (if any): area of effect depends * on player level. * (wooden) harp May calm nymph if player has enough dexterity. * magic harp Charm monsters: area of effect depends on player * level. * (leather) drum Will awaken monsters like the horn. * drum of earthquake Will initiate an earthquake whose intensity depends * on player level. That is, it creates random pits * called here chasms. */ #include "hack.h" STATIC_DCL void FDECL(awaken_monsters, (int)); STATIC_DCL void FDECL(put_monsters_to_sleep, (int)); STATIC_DCL void FDECL(charm_snakes, (int)); STATIC_DCL void FDECL(calm_nymphs, (int)); STATIC_DCL void FDECL(charm_monsters, (int)); STATIC_DCL void FDECL(do_earthquake, (int)); STATIC_DCL int FDECL(do_improvisation, (struct obj *)); #ifdef UNIX386MUSIC STATIC_DCL int NDECL(atconsole); STATIC_DCL void FDECL(speaker, (struct obj *, char *)); #endif #ifdef VPIX_MUSIC extern int sco_flag_console; /* will need changing if not _M_UNIX */ STATIC_DCL void NDECL(playinit); STATIC_DCL void FDECL(playstring, (char *, size_t)); STATIC_DCL void FDECL(speaker, (struct obj *, char *)); #endif #ifdef PCMUSIC void FDECL(pc_speaker, (struct obj *, char *)); #endif #ifdef AMIGA void FDECL(amii_speaker, (struct obj *, char *, int)); #endif /* * Wake every monster in range... */ STATIC_OVL void awaken_monsters(distance) int distance; { register struct monst *mtmp; register int distm; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((distm = distu(mtmp->mx, mtmp->my)) < distance) { mtmp->msleeping = 0; mtmp->mcanmove = 1; mtmp->mfrozen = 0; /* may scare some monsters -- waiting monsters excluded */ if (!unique_corpstat(mtmp->data) && (mtmp->mstrategy & STRAT_WAITMASK) != 0) mtmp->mstrategy &= ~STRAT_WAITMASK; else if (distm < distance / 3 && !resist(mtmp, TOOL_CLASS, 0, NOTELL)) monflee(mtmp, 0, FALSE, TRUE); } } } /* * Make monsters fall asleep. Note that they may resist the spell. */ STATIC_OVL void put_monsters_to_sleep(distance) int distance; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (distu(mtmp->mx, mtmp->my) < distance && sleep_monst(mtmp, d(10, 10), TOOL_CLASS)) { mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */ slept_monst(mtmp); } } } /* * Charm snakes in range. Note that the snakes are NOT tamed. */ STATIC_OVL void charm_snakes(distance) int distance; { register struct monst *mtmp; int could_see_mon, was_peaceful; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->data->mlet == S_SNAKE && mtmp->mcanmove && distu(mtmp->mx, mtmp->my) < distance) { was_peaceful = mtmp->mpeaceful; mtmp->mpeaceful = 1; mtmp->mavenge = 0; mtmp->mstrategy &= ~STRAT_WAITMASK; could_see_mon = canseemon(mtmp); mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); if (canseemon(mtmp)) { if (!could_see_mon) You("notice %s, swaying with the music.", a_monnam(mtmp)); else pline("%s freezes, then sways with the music%s.", Monnam(mtmp), was_peaceful ? "" : ", and now seems quieter"); } } } } /* * Calm nymphs in range. */ STATIC_OVL void calm_nymphs(distance) int distance; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->data->mlet == S_NYMPH && mtmp->mcanmove && distu(mtmp->mx, mtmp->my) < distance) { mtmp->msleeping = 0; mtmp->mpeaceful = 1; mtmp->mavenge = 0; mtmp->mstrategy &= ~STRAT_WAITMASK; if (canseemon(mtmp)) pline( "%s listens cheerfully to the music, then seems quieter.", Monnam(mtmp)); } } } /* Awake soldiers anywhere the level (and any nearby monster). */ void awaken_soldiers(bugler) struct monst *bugler; /* monster that played instrument */ { register struct monst *mtmp; int distance, distm; /* distance of affected non-soldier monsters to bugler */ distance = ((bugler == &youmonst) ? u.ulevel : bugler->data->mlevel) * 30; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) { mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0; mtmp->mcanmove = 1; mtmp->mstrategy &= ~STRAT_WAITMASK; if (canseemon(mtmp)) pline("%s is now ready for battle!", Monnam(mtmp)); else Norep("You hear the rattle of battle gear being readied."); } else if ((distm = ((bugler == &youmonst) ? distu(mtmp->mx, mtmp->my) : dist2(bugler->mx, bugler->my, mtmp->mx, mtmp->my))) < distance) { mtmp->msleeping = 0; mtmp->mcanmove = 1; mtmp->mfrozen = 0; /* may scare some monsters -- waiting monsters excluded */ if (!unique_corpstat(mtmp->data) && (mtmp->mstrategy & STRAT_WAITMASK) != 0) mtmp->mstrategy &= ~STRAT_WAITMASK; else if (distm < distance / 3 && !resist(mtmp, TOOL_CLASS, 0, NOTELL)) monflee(mtmp, 0, FALSE, TRUE); } } } /* Charm monsters in range. Note that they may resist the spell. * If swallowed, range is reduced to 0. */ STATIC_OVL void charm_monsters(distance) int distance; { struct monst *mtmp, *mtmp2; if (u.uswallow) { if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL)) (void) tamedog(u.ustuck, (struct obj *) 0); } else { for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (distu(mtmp->mx, mtmp->my) <= distance) { if (!resist(mtmp, TOOL_CLASS, 0, NOTELL)) (void) tamedog(mtmp, (struct obj *) 0); } } } } /* Generate earthquake :-) of desired force. * That is: create random chasms (pits). */ STATIC_OVL void do_earthquake(force) int force; { register int x, y; struct monst *mtmp; struct obj *otmp; struct trap *chasm, *trap_at_u = t_at(u.ux, u.uy); int start_x, start_y, end_x, end_y; schar filltype; unsigned tu_pit = 0; if (trap_at_u) tu_pit = (trap_at_u->ttyp == PIT || trap_at_u->ttyp == SPIKED_PIT); start_x = u.ux - (force * 2); start_y = u.uy - (force * 2); end_x = u.ux + (force * 2); end_y = u.uy + (force * 2); if (start_x < 1) start_x = 1; if (start_y < 1) start_y = 1; if (end_x >= COLNO) end_x = COLNO - 1; if (end_y >= ROWNO) end_y = ROWNO - 1; for (x = start_x; x <= end_x; x++) for (y = start_y; y <= end_y; y++) { if ((mtmp = m_at(x, y)) != 0) { wakeup(mtmp); /* peaceful monster will become hostile */ if (mtmp->mundetected && is_hider(mtmp->data)) { mtmp->mundetected = 0; if (cansee(x, y)) pline("%s is shaken loose from the ceiling!", Amonnam(mtmp)); else You_hear("a thumping sound."); if (x == u.ux && y == u.uy) You("easily dodge the falling %s.", mon_nam(mtmp)); newsym(x, y); } } if (!rn2(14 - force)) switch (levl[x][y].typ) { case FOUNTAIN: /* Make the fountain disappear */ if (cansee(x, y)) pline_The("fountain falls into a chasm."); goto do_pit; case SINK: if (cansee(x, y)) pline_The("kitchen sink falls into a chasm."); goto do_pit; case ALTAR: if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break; if (cansee(x, y)) pline_The("altar falls into a chasm."); goto do_pit; case GRAVE: if (cansee(x, y)) pline_The("headstone topples into a chasm."); goto do_pit; case THRONE: if (cansee(x, y)) pline_The("throne falls into a chasm."); /* Falls into next case */ case ROOM: case CORR: /* Try to make a pit */ do_pit: chasm = maketrap(x, y, PIT); if (!chasm) break; /* no pit if portal at that location */ chasm->tseen = 1; levl[x][y].doormask = 0; /* * Let liquid flow into the newly created chasm. * Adjust corresponding code in apply.c for * exploding wand of digging if you alter this sequence. */ filltype = fillholetyp(x, y, FALSE); if (filltype != ROOM) { levl[x][y].typ = filltype; liquid_flow(x, y, filltype, chasm, (char *) 0); } mtmp = m_at(x, y); if ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x, y)) pline("KADOOM! The boulder falls into a chasm%s!", ((x == u.ux) && (y == u.uy)) ? " below you" : ""); if (mtmp) mtmp->mtrapped = 0; obj_extract_self(otmp); (void) flooreffects(otmp, x, y, ""); break; } /* We have to check whether monsters or player falls in a chasm... */ if (mtmp) { if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) { boolean m_already_trapped = mtmp->mtrapped; mtmp->mtrapped = 1; if (!m_already_trapped) { /* suppress messages */ if (cansee(x, y)) pline("%s falls into a chasm!", Monnam(mtmp)); else if (humanoid(mtmp->data)) You_hear("a scream!"); } /* Falling is okay for falling down within a pit from jostling too */ mselftouch(mtmp, "Falling, ", TRUE); if (mtmp->mhp > 0) if ((mtmp->mhp -= rnd(m_already_trapped ? 4 : 6)) <= 0) { if (!cansee(x, y)) pline("It is destroyed!"); else { You("destroy %s!", mtmp->mtame ? x_monnam( mtmp, ARTICLE_THE, "poor", (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE) : mon_nam(mtmp)); } xkilled(mtmp, 0); } } } else if (x == u.ux && y == u.uy) { if (Levitation || Flying || is_clinger(youmonst.data)) { if (!tu_pit) { /* no pit here previously */ pline("A chasm opens up under you!"); You("don't fall in!"); } } else if (!tu_pit || !u.utrap || (u.utrap && u.utraptype != TT_PIT)) { /* no pit here previously, or you were not in it even it there was */ You("fall into a chasm!"); u.utrap = rn1(6, 2); u.utraptype = TT_PIT; losehp(Maybe_Half_Phys(rnd(6)), "fell into a chasm", NO_KILLER_PREFIX); selftouch("Falling, you"); } else if (u.utrap && u.utraptype == TT_PIT) { boolean keepfooting = ((Fumbling && !rn2(5)) || (!rnl(Role_if(PM_ARCHEOLOGIST) ? 3 : 9)) || ((ACURR(A_DEX) > 7) && rn2(5))); You("are jostled around violently!"); u.utrap = rn1(6, 2); u.utraptype = TT_PIT; /* superfluous */ losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)), "hurt in a chasm", NO_KILLER_PREFIX); if (keepfooting) exercise(A_DEX, TRUE); else selftouch( (Upolyd && (slithy(youmonst.data) || nolimbs(youmonst.data))) ? "Shaken, you" : "Falling down, you"); } } else newsym(x, y); break; case DOOR: /* Make the door collapse */ if (levl[x][y].doormask == D_NODOOR) goto do_pit; if (cansee(x, y)) pline_The("door collapses."); if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); levl[x][y].doormask = D_NODOOR; unblock_point(x, y); newsym(x, y); break; } } } /* * The player is trying to extract something from his/her instrument. */ STATIC_OVL int do_improvisation(instr) struct obj *instr; { int damage, do_spec = !Confusion; #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined(PCMUSIC) struct obj itmp; itmp = *instr; itmp.oextra = (struct oextra *) 0; /* ok on this copy as instr maintains the ptr to free at some point if there is one */ /* if won't yield special effect, make sound of mundane counterpart */ if (!do_spec || instr->spe <= 0) while (objects[itmp.otyp].oc_magic) itmp.otyp -= 1; #ifdef MAC mac_speaker(&itmp, "C"); #endif #ifdef AMIGA amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME); #endif #ifdef VPIX_MUSIC if (sco_flag_console) speaker(&itmp, "C"); #endif #ifdef PCMUSIC pc_speaker(&itmp, "C"); #endif #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */ if (!do_spec) pline("What you produce is quite far from music..."); else You("start playing %s.", the(xname(instr))); switch (instr->otyp) { case MAGIC_FLUTE: /* Make monster fall asleep */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); You("produce %s music.", Hallucination ? "piped" : "soft"); put_monsters_to_sleep(u.ulevel * 5); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_FLUTE: /* May charm snakes */ do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25); pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot")); if (do_spec) charm_snakes(u.ulevel * 3); exercise(A_DEX, TRUE); break; case FIRE_HORN: /* Idem wand of fire */ case FROST_HORN: /* Idem wand of cold */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); if (!getdir((char *) 0)) { pline("%s.", Tobjnam(instr, "vibrate")); break; } else if (!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(instr, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "using a magical horn on %sself", uhim()); losehp(damage, buf, KILLED_BY); /* fire or frost damage */ } } else { buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1, rn1(6, 6), u.ux, u.uy, u.dx, u.dy); } makeknown(instr->otyp); break; } /* else FALLTHRU */ case TOOLED_HORN: /* Awaken or scare monsters */ You("produce a frightful, grave sound."); awaken_monsters(u.ulevel * 30); exercise(A_WIS, FALSE); break; case BUGLE: /* Awaken & attract soldiers */ You("extract a loud noise from %s.", the(xname(instr))); awaken_soldiers(&youmonst); exercise(A_WIS, FALSE); break; case MAGIC_HARP: /* Charm monsters */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline("%s very attractive music.", Tobjnam(instr, "produce")); charm_monsters((u.ulevel - 1) / 3 + 1); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_HARP: /* May calm Nymph */ do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25); pline("%s %s.", The(xname(instr)), do_spec ? "produces a lilting melody" : "twangs"); if (do_spec) calm_nymphs(u.ulevel * 3); exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); You("produce a heavy, thunderous rolling!"); pline_The("entire dungeon is shaking around you!"); do_earthquake((u.ulevel - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(ROWNO * COLNO); makeknown(DRUM_OF_EARTHQUAKE); break; } /* else FALLTHRU */ case LEATHER_DRUM: /* Awaken monsters */ You("beat a deafening row!"); awaken_monsters(u.ulevel * 40); incr_itimeout(&HDeaf, rn1(20, 30)); exercise(A_WIS, FALSE); break; default: impossible("What a weird instrument (%d)!", instr->otyp); break; } return 2; /* That takes time */ } /* * So you want music... */ int do_play_instrument(instr) struct obj *instr; { char buf[BUFSZ], c = 'y'; char *s; int x, y; boolean ok; if (Underwater) { You_cant("play music underwater!"); return 0; } else if ((instr->otyp == WOODEN_FLUTE || instr->otyp == MAGIC_FLUTE || instr->otyp == TOOLED_HORN || instr->otyp == FROST_HORN || instr->otyp == FIRE_HORN || instr->otyp == BUGLE) && !can_blow(&youmonst)) { You("are incapable of playing %s.", the(distant_name(instr, xname))); return 0; } if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) { c = ynq("Improvise?"); if (c == 'q') goto nevermind; } if (c == 'n') { if (u.uevent.uheard_tune == 2) c = ynq("Play the passtune?"); if (c == 'q') { goto nevermind; } else if (c == 'y') { Strcpy(buf, tune); } else { getlin("What tune are you playing? [5 notes, A-G]", buf); (void) mungspaces(buf); if (*buf == '\033') goto nevermind; /* convert to uppercase and change any "H" to the expected "B" */ for (s = buf; *s; s++) { #ifndef AMIGA *s = highc(*s); #else /* The AMIGA supports two octaves of notes */ if (*s == 'h') *s = 'b'; #endif if (*s == 'H') *s = 'B'; } } You("extract a strange sound from %s!", the(xname(instr))); #ifdef UNIX386MUSIC /* if user is at the console, play through the console speaker */ if (atconsole()) speaker(instr, buf); #endif #ifdef VPIX_MUSIC if (sco_flag_console) speaker(instr, buf); #endif #ifdef MAC mac_speaker(instr, buf); #endif #ifdef PCMUSIC pc_speaker(instr, buf); #endif #ifdef AMIGA { char nbuf[20]; int i; for (i = 0; buf[i] && i < 5; ++i) { nbuf[i * 2] = buf[i]; nbuf[(i * 2) + 1] = 'h'; } nbuf[i * 2] = 0; amii_speaker(instr, nbuf, AMII_OKAY_VOLUME); } #endif /* Check if there was the Stronghold drawbridge near * and if the tune conforms to what we're waiting for. */ if (Is_stronghold(&u.uz)) { exercise(A_WIS, TRUE); /* just for trying */ if (!strcmp(buf, tune)) { /* Search for the drawbridge */ for (y = u.uy - 1; y <= u.uy + 1; y++) for (x = u.ux - 1; x <= u.ux + 1; x++) if (isok(x, y)) if (find_drawbridge(&x, &y)) { u.uevent.uheard_tune = 2; /* tune now fully known */ if (levl[x][y].typ == DRAWBRIDGE_DOWN) close_drawbridge(x, y); else open_drawbridge(x, y); return 1; } } else if (!Deaf) { if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1; /* Okay, it wasn't the right tune, but perhaps * we can give the player some hints like in the * Mastermind game */ ok = FALSE; for (y = u.uy - 1; y <= u.uy + 1 && !ok; y++) for (x = u.ux - 1; x <= u.ux + 1 && !ok; x++) if (isok(x, y)) if (IS_DRAWBRIDGE(levl[x][y].typ) || is_drawbridge_wall(x, y) >= 0) ok = TRUE; if (ok) { /* There is a drawbridge near */ int tumblers, gears; boolean matched[5]; tumblers = gears = 0; for (x = 0; x < 5; x++) matched[x] = FALSE; for (x = 0; x < (int) strlen(buf); x++) if (x < 5) { if (buf[x] == tune[x]) { gears++; matched[x] = TRUE; } else for (y = 0; y < 5; y++) if (!matched[y] && buf[x] == tune[y] && buf[y] != tune[y]) { tumblers++; matched[y] = TRUE; break; } } if (tumblers) if (gears) You_hear("%d tumbler%s click and %d gear%s turn.", tumblers, plur(tumblers), gears, plur(gears)); else You_hear("%d tumbler%s click.", tumblers, plur(tumblers)); else if (gears) { You_hear("%d gear%s turn.", gears, plur(gears)); /* could only get `gears == 5' by playing five correct notes followed by excess; otherwise, tune would have matched above */ if (gears == 5) u.uevent.uheard_tune = 2; } } } } return 1; } else return do_improvisation(instr); nevermind: pline1(Never_mind); return 0; } #ifdef UNIX386MUSIC /* * Play audible music on the machine's speaker if appropriate. */ STATIC_OVL int atconsole() { /* * Kluge alert: This code assumes that your [34]86 has no X terminals * attached and that the console tty type is AT386 (this is always true * under AT&T UNIX for these boxen). The theory here is that your remote * ttys will have terminal type `ansi' or something else other than * `AT386' or `xterm'. We'd like to do better than this, but testing * to see if we're running on the console physical terminal is quite * difficult given the presence of virtual consoles and other modern * UNIX impedimenta... */ char *termtype = nh_getenv("TERM"); return (!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm")); } STATIC_OVL void speaker(instr, buf) struct obj *instr; char *buf; { /* * For this to work, you need to have installed the PD speaker-control * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com) * posted to comp.sources.unix in Feb 1990. A copy should be included * with your nethack distribution. */ int fd; if ((fd = open("/dev/speaker", 1)) != -1) { /* send a prefix to modify instrumental `timbre' */ switch (instr->otyp) { case WOODEN_FLUTE: case MAGIC_FLUTE: (void) write(fd, ">ol", 1); /* up one octave & lock */ break; case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: (void) write(fd, "< #include #include #else #define KIOC ('K' << 8) #define KDMKTONE (KIOC | 8) #endif #define noDEBUG /* emit tone of frequency hz for given number of ticks */ STATIC_OVL void tone(hz, ticks) unsigned int hz, ticks; { ioctl(0, KDMKTONE, hz | ((ticks * 10) << 16)); #ifdef DEBUG printf("TONE: %6d %6d\n", hz, ticks * 10); #endif nap(ticks * 10); } /* rest for given number of ticks */ STATIC_OVL void rest(ticks) int ticks; { nap(ticks * 10); #ifdef DEBUG printf("REST: %6d\n", ticks * 10); #endif } #include "interp.c" /* from snd86unx.shr */ STATIC_OVL void speaker(instr, buf) struct obj *instr; char *buf; { /* emit a prefix to modify instrumental `timbre' */ playinit(); switch (instr->otyp) { case WOODEN_FLUTE: case MAGIC_FLUTE: playstring(">ol", 1); /* up one octave & lock */ break; case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: playstring("< maxledgerno()) ? maxledgerno() : ledger_no(dlev); else lev = 0; first = bases[GEM_CLASS]; for (j = 0; j < 9 - lev / 3; j++) objects[first + j].oc_prob = 0; first += j; if (first > LAST_GEM || objects[first].oc_class != GEM_CLASS || OBJ_NAME(objects[first]) == (char *) 0) { raw_printf("Not enough gems? - first=%d j=%d LAST_GEM=%d", first, j, LAST_GEM); wait_synch(); } for (j = first; j <= LAST_GEM; j++) objects[j].oc_prob = (171 + j - first) / (LAST_GEM + 1 - first); } /* shuffle descriptions on objects o_low to o_high */ STATIC_OVL void shuffle(o_low, o_high, domaterial) int o_low, o_high; boolean domaterial; { int i, j, num_to_shuffle; short sw; int color; for (num_to_shuffle = 0, j = o_low; j <= o_high; j++) if (!objects[j].oc_name_known) num_to_shuffle++; if (num_to_shuffle < 2) return; for (j = o_low; j <= o_high; j++) { if (objects[j].oc_name_known) continue; do i = j + rn2(o_high - j + 1); while (objects[i].oc_name_known); sw = objects[j].oc_descr_idx; objects[j].oc_descr_idx = objects[i].oc_descr_idx; objects[i].oc_descr_idx = sw; sw = objects[j].oc_tough; objects[j].oc_tough = objects[i].oc_tough; objects[i].oc_tough = sw; color = objects[j].oc_color; objects[j].oc_color = objects[i].oc_color; objects[i].oc_color = color; /* shuffle material */ if (domaterial) { sw = objects[j].oc_material; objects[j].oc_material = objects[i].oc_material; objects[i].oc_material = sw; } } } void init_objects() { register int i, first, last, sum; register char oclass; #ifdef TEXTCOLOR #define COPY_OBJ_DESCR(o_dst, o_src) \ o_dst.oc_descr_idx = o_src.oc_descr_idx, o_dst.oc_color = o_src.oc_color #else #define COPY_OBJ_DESCR(o_dst, o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx #endif /* bug fix to prevent "initialization error" abort on Intel Xenix. * reported by mikew@semike */ for (i = 0; i < MAXOCLASSES; i++) bases[i] = 0; /* initialize object descriptions */ for (i = 0; i < NUM_OBJECTS; i++) objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init base; if probs given check that they add up to 1000, otherwise compute probs */ first = 0; while (first < NUM_OBJECTS) { oclass = objects[first].oc_class; last = first + 1; while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++; bases[(int) oclass] = first; if (oclass == GEM_CLASS) { setgemprobs((d_level *) 0); if (rn2(2)) { /* change turquoise from green to blue? */ COPY_OBJ_DESCR(objects[TURQUOISE], objects[SAPPHIRE]); } if (rn2(2)) { /* change aquamarine from green to blue? */ COPY_OBJ_DESCR(objects[AQUAMARINE], objects[SAPPHIRE]); } switch (rn2(4)) { /* change fluorite from violet? */ case 0: break; case 1: /* blue */ COPY_OBJ_DESCR(objects[FLUORITE], objects[SAPPHIRE]); break; case 2: /* white */ COPY_OBJ_DESCR(objects[FLUORITE], objects[DIAMOND]); break; case 3: /* green */ COPY_OBJ_DESCR(objects[FLUORITE], objects[EMERALD]); break; } } check: sum = 0; for (i = first; i < last; i++) sum += objects[i].oc_prob; if (sum == 0) { for (i = first; i < last; i++) objects[i].oc_prob = (1000 + i - first) / (last - first); goto check; } if (sum != 1000) error("init-prob error for class %d (%d%%)", oclass, sum); first = last; } /* shuffle descriptions */ shuffle_all(); #ifdef USE_TILES shuffle_tiles(); #endif objects[WAN_NOTHING].oc_dir = rn2(2) ? NODIR : IMMEDIATE; } /* retrieve the range of objects that otyp shares descriptions with */ void obj_shuffle_range(otyp, lo_p, hi_p) int otyp; /* input: representative item */ int *lo_p, *hi_p; /* output: range that item belongs among */ { int i, ocls = objects[otyp].oc_class; /* default is just the object itself */ *lo_p = *hi_p = otyp; switch (ocls) { case ARMOR_CLASS: if (otyp >= HELMET && otyp <= HELM_OF_TELEPATHY) *lo_p = HELMET, *hi_p = HELM_OF_TELEPATHY; else if (otyp >= LEATHER_GLOVES && otyp <= GAUNTLETS_OF_DEXTERITY) *lo_p = LEATHER_GLOVES, *hi_p = GAUNTLETS_OF_DEXTERITY; else if (otyp >= CLOAK_OF_PROTECTION && otyp <= CLOAK_OF_DISPLACEMENT) *lo_p = CLOAK_OF_PROTECTION, *hi_p = CLOAK_OF_DISPLACEMENT; else if (otyp >= SPEED_BOOTS && otyp <= LEVITATION_BOOTS) *lo_p = SPEED_BOOTS, *hi_p = LEVITATION_BOOTS; break; case POTION_CLASS: /* potion of water has the only fixed description */ *lo_p = bases[POTION_CLASS]; *hi_p = POT_WATER - 1; break; case AMULET_CLASS: case SCROLL_CLASS: case SPBOOK_CLASS: /* exclude non-magic types and also unique ones */ *lo_p = bases[ocls]; for (i = *lo_p; objects[i].oc_class == ocls; i++) if (objects[i].oc_unique || !objects[i].oc_magic) break; *hi_p = i - 1; break; case RING_CLASS: case WAND_CLASS: case VENOM_CLASS: /* entire class */ *lo_p = bases[ocls]; for (i = *lo_p; objects[i].oc_class == ocls; i++) continue; *hi_p = i - 1; break; } /* artifact checking might ask about item which isn't part of any range but fell within the classes that do have ranges specified above */ if (otyp < *lo_p || otyp > *hi_p) *lo_p = *hi_p = otyp; return; } /* randomize object descriptions */ STATIC_OVL void shuffle_all() { /* entire classes; obj_shuffle_range() handles their exceptions */ static char shuffle_classes[] = { AMULET_CLASS, POTION_CLASS, RING_CLASS, SCROLL_CLASS, SPBOOK_CLASS, WAND_CLASS, VENOM_CLASS, }; /* sub-class type ranges (one item from each group) */ static short shuffle_types[] = { HELMET, LEATHER_GLOVES, CLOAK_OF_PROTECTION, SPEED_BOOTS, }; int first, last, idx; /* do whole classes (amulets, &c) */ for (idx = 0; idx < SIZE(shuffle_classes); idx++) { obj_shuffle_range(bases[(int) shuffle_classes[idx]], &first, &last); shuffle(first, last, TRUE); } /* do type ranges (helms, &c) */ for (idx = 0; idx < SIZE(shuffle_types); idx++) { obj_shuffle_range(shuffle_types[idx], &first, &last); shuffle(first, last, FALSE); } return; } /* find the object index for snow boots; used [once] by slippery ice code */ int find_skates() { register int i; register const char *s; for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++) if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots")) return i; impossible("snow boots not found?"); return -1; /* not 0, or caller would try again each move */ } /* level dependent initialization */ void oinit() { setgemprobs(&u.uz); } void savenames(fd, mode) int fd, mode; { register int i; unsigned int len; if (perform_bwrite(mode)) { bwrite(fd, (genericptr_t) bases, sizeof bases); bwrite(fd, (genericptr_t) disco, sizeof disco); bwrite(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS); } /* as long as we use only one version of Hack we need not save oc_name and oc_descr, but we must save oc_uname for all objects */ for (i = 0; i < NUM_OBJECTS; i++) if (objects[i].oc_uname) { if (perform_bwrite(mode)) { len = strlen(objects[i].oc_uname) + 1; bwrite(fd, (genericptr_t) &len, sizeof len); bwrite(fd, (genericptr_t) objects[i].oc_uname, len); } if (release_data(mode)) { free((genericptr_t) objects[i].oc_uname); objects[i].oc_uname = 0; } } } void restnames(fd) register int fd; { register int i; unsigned int len; mread(fd, (genericptr_t) bases, sizeof bases); mread(fd, (genericptr_t) disco, sizeof disco); mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS); for (i = 0; i < NUM_OBJECTS; i++) if (objects[i].oc_uname) { mread(fd, (genericptr_t) &len, sizeof len); objects[i].oc_uname = (char *) alloc(len); mread(fd, (genericptr_t) objects[i].oc_uname, len); } #ifdef USE_TILES shuffle_tiles(); #endif } void discover_object(oindx, mark_as_known, credit_hero) register int oindx; boolean mark_as_known; boolean credit_hero; { if (!objects[oindx].oc_name_known) { register int dindx, acls = objects[oindx].oc_class; /* Loop thru disco[] 'til we find the target (which may have been uname'd) or the next open slot; one or the other will be found before we reach the next class... */ for (dindx = bases[acls]; disco[dindx] != 0; dindx++) if (disco[dindx] == oindx) break; disco[dindx] = oindx; if (mark_as_known) { objects[oindx].oc_name_known = 1; if (credit_hero) exercise(A_WIS, TRUE); } if (moves > 1L) update_inventory(); } } /* if a class name has been cleared, we may need to purge it from disco[] */ void undiscover_object(oindx) register int oindx; { if (!objects[oindx].oc_name_known) { register int dindx, acls = objects[oindx].oc_class; register boolean found = FALSE; /* find the object; shift those behind it forward one slot */ for (dindx = bases[acls]; dindx < NUM_OBJECTS && disco[dindx] != 0 && objects[dindx].oc_class == acls; dindx++) if (found) disco[dindx - 1] = disco[dindx]; else if (disco[dindx] == oindx) found = TRUE; /* clear last slot */ if (found) disco[dindx - 1] = 0; else impossible("named object not in disco"); update_inventory(); } } STATIC_OVL boolean interesting_to_discover(i) register int i; { /* Pre-discovered objects are now printed with a '*' */ return (boolean) (objects[i].oc_uname != (char *) 0 || (objects[i].oc_name_known && OBJ_DESCR(objects[i]) != (char *) 0)); } /* items that should stand out once they're known */ static short uniq_objs[] = { AMULET_OF_YENDOR, SPE_BOOK_OF_THE_DEAD, CANDELABRUM_OF_INVOCATION, BELL_OF_OPENING, }; /* the '\' command - show discovered object types */ int dodiscovered() /* free after Robert Viduya */ { register int i, dis; int ct = 0; char *s, oclass, prev_class, classes[MAXOCLASSES], buf[BUFSZ]; winid tmpwin; tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, "Discoveries"); putstr(tmpwin, 0, ""); /* gather "unique objects" into a pseudo-class; note that they'll also be displayed individually within their regular class */ for (i = dis = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { if (!dis++) putstr(tmpwin, iflags.menu_headings, "Unique items"); Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); ++ct; } /* display any known artifacts as another pseudo-class */ ct += disp_artifact_discoveries(tmpwin); /* several classes are omitted from packorder; one is of interest here */ Strcpy(classes, flags.inv_order); if (!index(classes, VENOM_CLASS)) { s = eos(classes); *s++ = VENOM_CLASS; *s = '\0'; } for (s = classes; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ for (i = bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) { ct++; if (oclass != prev_class) { putstr(tmpwin, iflags.menu_headings, let_to_name(oclass, FALSE, FALSE)); prev_class = oclass; } Sprintf(buf, "%s %s", (objects[dis].oc_pre_discovered ? "*" : " "), obj_typename(dis)); putstr(tmpwin, 0, buf); } } } if (ct == 0) { You("haven't discovered anything yet..."); } else display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); return 0; } /* lower case let_to_name() output, which differs from def_oc_syms[].name */ STATIC_OVL char * oclass_to_name(oclass, buf) char oclass; char *buf; { char *s; Strcpy(buf, let_to_name(oclass, FALSE, FALSE)); for (s = buf; *s; ++s) *s = lowc(*s); return buf; } /* the '`' command - show discovered object types for one class */ int doclassdisco() { static NEARDATA const char prompt[] = "View discoveries for which sort of objects?", havent_discovered_any[] = "haven't discovered any %s yet.", unique_items[] = "unique items", artifact_items[] = "artifacts"; char *s, c, oclass, menulet, allclasses[MAXOCLASSES], discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ]; int i, ct, dis, xtras; boolean traditional; winid tmpwin; anything any; menu_item *pick_list = 0; discosyms[0] = '\0'; traditional = (flags.menu_style == MENU_TRADITIONAL || flags.menu_style == MENU_COMBINATION); tmpwin = !traditional ? create_nhwindow(NHW_MENU) : WIN_ERR; any = zeroany; menulet = 'a'; /* check whether we've discovered any unique objects */ for (i = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { Strcat(discosyms, "u"); if (!traditional) { any.a_int = 'u'; add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE, unique_items, MENU_UNSELECTED); } break; } /* check whether we've discovered any artifacts */ if (disp_artifact_discoveries(WIN_ERR) > 0) { Strcat(discosyms, "a"); if (!traditional) { any.a_int = 'a'; add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE, artifact_items, MENU_UNSELECTED); } } /* collect classes with discoveries, in packorder ordering; several classes are omitted from packorder and one is of interest here */ Strcpy(allclasses, flags.inv_order); if (!index(allclasses, VENOM_CLASS)) Sprintf(eos(allclasses), "%c", VENOM_CLASS); /* construct discosyms[] */ for (s = allclasses; *s; ++s) { oclass = *s; c = def_oc_syms[(int) oclass].sym; for (i = bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) { if (!index(discosyms, c)) { Sprintf(eos(discosyms), "%c", c); if (!traditional) { any.a_int = c; add_menu(tmpwin, NO_GLYPH, &any, menulet++, c, ATR_NONE, oclass_to_name(oclass, buf), MENU_UNSELECTED); } } } } /* there might not be anything for us to do... */ if (!discosyms[0]) { You(havent_discovered_any, "items"); if (tmpwin != WIN_ERR) destroy_nhwindow(tmpwin); return 0; } /* have player choose a class */ c = '\0'; /* class not chosen yet */ if (traditional) { /* we'll prompt even if there's only one viable class; we add all nonviable classes as unseen acceptable choices so player can ask for discoveries of any class whether it has discoveries or not */ for (s = allclasses, xtras = 0; *s; ++s) { c = def_oc_syms[(int) *s].sym; if (!index(discosyms, c)) { if (!xtras++) Sprintf(eos(discosyms), "%c", '\033'); Sprintf(eos(discosyms), "%c", c); } } /* get the class (via its symbol character) */ c = yn_function(prompt, discosyms, '\0'); savech(c); if (!c) clear_nhwindow(WIN_MESSAGE); } else { /* menustyle:full or menustyle:partial */ if (!discosyms[1] && flags.menu_style == MENU_PARTIAL) { /* only one class; menustyle:partial normally jumps past class filtering straight to final menu so skip class filter here */ c = discosyms[0]; } else { /* more than one choice, or menustyle:full which normally has an intermediate class selection menu before the final menu */ end_menu(tmpwin, prompt); i = select_menu(tmpwin, PICK_ONE, &pick_list); if (i > 0) { c = pick_list[0].item.a_int; free((genericptr_t) pick_list); } /* else c stays 0 */ } destroy_nhwindow(tmpwin); } if (!c) return 0; /* player declined to make a selection */ /* * show discoveries for object class c */ tmpwin = create_nhwindow(NHW_MENU); ct = 0; switch (c) { case 'u': putstr(tmpwin, iflags.menu_headings, upstart(strcpy(buf, unique_items))); for (i = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); ++ct; } if (!ct) You(havent_discovered_any, unique_items); break; case 'a': /* disp_artifact_discoveries() includes a header */ ct = disp_artifact_discoveries(tmpwin); if (!ct) You(havent_discovered_any, artifact_items); break; default: oclass = def_char_to_objclass(c); Sprintf(buf, "Discovered %s", let_to_name(oclass, FALSE, FALSE)); putstr(tmpwin, iflags.menu_headings, buf); for (i = bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) { if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) { Sprintf(buf, "%s %s", objects[dis].oc_pre_discovered ? "*" : " ", obj_typename(dis)); putstr(tmpwin, 0, buf); ++ct; } } if (!ct) You(havent_discovered_any, oclass_to_name(oclass, buf)); break; } if (ct) display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); return 0; } /* put up nameable subset of discoveries list as a menu */ void rename_disco() { register int i, dis; int ct = 0, mn = 0, sl; char *s, oclass, prev_class; winid tmpwin; anything any; menu_item *selected = 0; any = zeroany; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); /* * Skip the "unique objects" section (each will appear within its * regular class if it is nameable) and the artifacts section. * We assume that classes omitted from packorder aren't nameable * so we skip venom too. */ /* for each class, show discoveries in that class */ for (s = flags.inv_order; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ for (i = bases[(int) oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { dis = disco[i]; if (!dis || !interesting_to_discover(dis)) continue; ct++; if (!objtyp_is_callable(dis)) continue; mn++; if (oclass != prev_class) { any.a_int = 0; add_menu(tmpwin, NO_GLYPH, &any, ' ', iflags.menu_headings, ATR_NONE, let_to_name(oclass, FALSE, FALSE), MENU_UNSELECTED); prev_class = oclass; } any.a_int = dis; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, obj_typename(dis), MENU_UNSELECTED); } } if (ct == 0) { You("haven't discovered anything yet..."); } else if (mn == 0) { pline("None of your discoveries can be assigned names..."); } else { end_menu(tmpwin, "Pick an object type to name"); dis = STRANGE_OBJECT; sl = select_menu(tmpwin, PICK_ONE, &selected); if (sl > 0) { dis = selected[0].item.a_int; free((genericptr_t) selected); } if (dis != STRANGE_OBJECT) { struct obj odummy; odummy = zeroobj; odummy.otyp = dis; odummy.oclass = objects[dis].oc_class; odummy.quan = 1L; odummy.known = !objects[dis].oc_uses_known; odummy.dknown = 1; docall(&odummy); } } destroy_nhwindow(tmpwin); return; } /*o_init.c*/ nethack-3.6.0/src/objects.c0000664000076400007660000016252512621041001014517 0ustar paxedpaxed/* NetHack 3.6 objects.c $NHDT-Date: 1447313395 2015/11/12 07:29:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Mike Threepoint, 1989. */ /* NetHack may be freely redistributed. See license for details. */ /* * The data in this file is processed twice, to construct two arrays. * On the first pass, only object name and object description matter. * On the second pass, all object-class fields except those two matter. * 2nd pass is a recursive inclusion of this file, not a 2nd compilation. * The name/description array is also used by makedefs and lev_comp. * * #ifndef OBJECTS_PASS_2_ * # define OBJECT(name,desc,foo,bar,glorkum) name,desc * struct objdescr obj_descr[] = * #else * # define OBJECT(name,desc,foo,bar,glorkum) foo,bar,glorkum * struct objclass objects[] = * #endif * { * { OBJECT("strange object",NULL, 1,2,3) }, * { OBJECT("arrow","pointy stick", 4,5,6) }, * ... * { OBJECT(NULL,NULL, 0,0,0) } * }; * #define OBJECTS_PASS_2_ * #include "objects.c" */ /* *INDENT-OFF* */ /* clang-format off */ #ifndef OBJECTS_PASS_2_ /* first pass */ struct monst { struct monst *dummy; }; /* lint: struct obj's union */ #include "config.h" #include "obj.h" #include "objclass.h" #include "prop.h" #include "skills.h" #else /* !OBJECTS_PASS_2_ */ /* second pass */ #include "color.h" #define COLOR_FIELD(X) X, #endif /* !OBJECTS_PASS_2_ */ /* objects have symbols: ) [ = " ( % ! ? + / $ * ` 0 _ . */ /* * Note: OBJ() and BITS() macros are used to avoid exceeding argument * limits imposed by some compilers. The ctnr field of BITS currently * does not map into struct objclass, and is ignored in the expansion. * The 0 in the expansion corresponds to oc_pre_discovered, which is * set at run-time during role-specific character initialization. */ #ifndef OBJECTS_PASS_2_ /* first pass -- object descriptive text */ #define OBJ(name,desc) name, desc #define OBJECT(obj,bits,prp,sym,prob,dly,wt, \ cost,sdam,ldam,oc1,oc2,nut,color) { obj } #define None (char *) 0 /* less visual distraction for 'no description' */ NEARDATA struct objdescr obj_descr[] = #else /* second pass -- object definitions */ #define BITS(nmkn,mrg,uskn,ctnr,mgc,chrg,uniq,nwsh,big,tuf,dir,sub,mtrl) \ nmkn,mrg,uskn,0,mgc,chrg,uniq,nwsh,big,tuf,dir,mtrl,sub /*SCO cpp fodder*/ #define OBJECT(obj,bits,prp,sym,prob,dly,wt,cost,sdam,ldam,oc1,oc2,nut,color) \ { 0, 0, (char *) 0, bits, prp, sym, dly, COLOR_FIELD(color) prob, wt, \ cost, sdam, ldam, oc1, oc2, nut } #ifndef lint #define HARDGEM(n) (n >= 8) #else #define HARDGEM(n) (0) #endif NEARDATA struct objclass objects[] = #endif { /* dummy object[0] -- description [2nd arg] *must* be NULL */ OBJECT(OBJ("strange object", None), BITS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, P_NONE, 0), 0, ILLOBJ_CLASS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* weapons ... */ #define WEAPON(name,desc,kn,mg,bi,prob,wt, \ cost,sdam,ldam,hitbon,typ,sub,metal,color) \ OBJECT(OBJ(name,desc), \ BITS(kn, mg, 1, 0, 0, 1, 0, 0, bi, 0, typ, sub, metal), \ 0, WEAPON_CLASS, prob, 0, wt, \ cost, sdam, ldam, hitbon, 0, wt, color) #define PROJECTILE(name,desc,kn,prob,wt, \ cost,sdam,ldam,hitbon,metal,sub,color) \ OBJECT(OBJ(name,desc), \ BITS(kn, 1, 1, 0, 0, 1, 0, 0, 0, 0, PIERCE, sub, metal), \ 0, WEAPON_CLASS, prob, 0, wt, \ cost, sdam, ldam, hitbon, 0, wt, color) #define BOW(name,desc,kn,prob,wt,cost,hitbon,metal,sub,color) \ OBJECT(OBJ(name,desc), \ BITS(kn, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, sub, metal), \ 0, WEAPON_CLASS, prob, 0, wt, \ cost, 2, 2, hitbon, 0, wt, color) /* Note: for weapons that don't do an even die of damage (ex. 2-7 or 3-18) the extra damage is added on in weapon.c, not here! */ #define P PIERCE #define S SLASH #define B WHACK /* missiles; materiel reflects the arrowhead, not the shaft */ PROJECTILE("arrow", None, 1, 55, 1, 2, 6, 6, 0, IRON, -P_BOW, HI_METAL), PROJECTILE("elven arrow", "runed arrow", 0, 20, 1, 2, 7, 6, 0, WOOD, -P_BOW, HI_WOOD), PROJECTILE("orcish arrow", "crude arrow", 0, 20, 1, 2, 5, 6, 0, IRON, -P_BOW, CLR_BLACK), PROJECTILE("silver arrow", None, 1, 12, 1, 5, 6, 6, 0, SILVER, -P_BOW, HI_SILVER), PROJECTILE("ya", "bamboo arrow", 0, 15, 1, 4, 7, 7, 1, METAL, -P_BOW, HI_METAL), PROJECTILE("crossbow bolt", None, 1, 55, 1, 2, 4, 6, 0, IRON, -P_CROSSBOW, HI_METAL), /* missiles that don't use a launcher */ WEAPON("dart", None, 1, 1, 0, 60, 1, 2, 3, 2, 0, P, -P_DART, IRON, HI_METAL), WEAPON("shuriken", "throwing star", 0, 1, 0, 35, 1, 5, 8, 6, 2, P, -P_SHURIKEN, IRON, HI_METAL), WEAPON("boomerang", None, 1, 1, 0, 15, 5, 20, 9, 9, 0, 0, -P_BOOMERANG, WOOD, HI_WOOD), /* spears [note: javelin used to have a separate skill from spears, because the latter are primarily stabbing weapons rather than throwing ones; but for playability, they've been merged together under spear skill and spears can now be thrown like javelins] */ WEAPON("spear", None, 1, 1, 0, 50, 30, 3, 6, 8, 0, P, P_SPEAR, IRON, HI_METAL), WEAPON("elven spear", "runed spear", 0, 1, 0, 10, 30, 3, 7, 8, 0, P, P_SPEAR, WOOD, HI_WOOD), WEAPON("orcish spear", "crude spear", 0, 1, 0, 13, 30, 3, 5, 8, 0, P, P_SPEAR, IRON, CLR_BLACK), WEAPON("dwarvish spear", "stout spear", 0, 1, 0, 12, 35, 3, 8, 8, 0, P, P_SPEAR, IRON, HI_METAL), WEAPON("silver spear", None, 1, 1, 0, 2, 36, 40, 6, 8, 0, P, P_SPEAR, SILVER, HI_SILVER), WEAPON("javelin", "throwing spear", 0, 1, 0, 10, 20, 3, 6, 6, 0, P, P_SPEAR, IRON, HI_METAL), /* spearish; doesn't stack, not intended to be thrown */ WEAPON("trident", None, 1, 0, 0, 8, 25, 5, 6, 4, 0, P, P_TRIDENT, IRON, HI_METAL), /* +1 small, +2d4 large */ /* blades; all stack */ WEAPON("dagger", None, 1, 1, 0, 30, 10, 4, 4, 3, 2, P, P_DAGGER, IRON, HI_METAL), WEAPON("elven dagger", "runed dagger", 0, 1, 0, 10, 10, 4, 5, 3, 2, P, P_DAGGER, WOOD, HI_WOOD), WEAPON("orcish dagger", "crude dagger", 0, 1, 0, 12, 10, 4, 3, 3, 2, P, P_DAGGER, IRON, CLR_BLACK), WEAPON("silver dagger", None, 1, 1, 0, 3, 12, 40, 4, 3, 2, P, P_DAGGER, SILVER, HI_SILVER), WEAPON("athame", None, 1, 1, 0, 0, 10, 4, 4, 3, 2, S, P_DAGGER, IRON, HI_METAL), WEAPON("scalpel", None, 1, 1, 0, 0, 5, 6, 3, 3, 2, S, P_KNIFE, METAL, HI_METAL), WEAPON("knife", None, 1, 1, 0, 20, 5, 4, 3, 2, 0, P|S, P_KNIFE, IRON, HI_METAL), WEAPON("stiletto", None, 1, 1, 0, 5, 5, 4, 3, 2, 0, P|S, P_KNIFE, IRON, HI_METAL), /* 3.6: worm teeth and crysknives now stack; when a stack of teeth is enchanted at once, they fuse into one crysknife; when a stack of crysknives drops, the whole stack reverts to teeth */ WEAPON("worm tooth", None, 1, 1, 0, 0, 20, 2, 2, 2, 0, 0, P_KNIFE, 0, CLR_WHITE), WEAPON("crysknife", None, 1, 1, 0, 0, 20, 100, 10, 10, 3, P, P_KNIFE, MINERAL, CLR_WHITE), /* axes */ WEAPON("axe", None, 1, 0, 0, 40, 60, 8, 6, 4, 0, S, P_AXE, IRON, HI_METAL), WEAPON("battle-axe", "double-headed axe", /* "double-bitted"? */ 0, 0, 1, 10, 120, 40, 8, 6, 0, S, P_AXE, IRON, HI_METAL), /* swords */ WEAPON("short sword", None, 1, 0, 0, 8, 30, 10, 6, 8, 0, P, P_SHORT_SWORD, IRON, HI_METAL), WEAPON("elven short sword", "runed short sword", 0, 0, 0, 2, 30, 10, 8, 8, 0, P, P_SHORT_SWORD, WOOD, HI_WOOD), WEAPON("orcish short sword", "crude short sword", 0, 0, 0, 3, 30, 10, 5, 8, 0, P, P_SHORT_SWORD, IRON, CLR_BLACK), WEAPON("dwarvish short sword", "broad short sword", 0, 0, 0, 2, 30, 10, 7, 8, 0, P, P_SHORT_SWORD, IRON, HI_METAL), WEAPON("scimitar", "curved sword", 0, 0, 0, 15, 40, 15, 8, 8, 0, S, P_SCIMITAR, IRON, HI_METAL), WEAPON("silver saber", None, 1, 0, 0, 6, 40, 75, 8, 8, 0, S, P_SABER, SILVER, HI_SILVER), WEAPON("broadsword", None, 1, 0, 0, 8, 70, 10, 4, 6, 0, S, P_BROAD_SWORD, IRON, HI_METAL), /* +d4 small, +1 large */ WEAPON("elven broadsword", "runed broadsword", 0, 0, 0, 4, 70, 10, 6, 6, 0, S, P_BROAD_SWORD, WOOD, HI_WOOD), /* +d4 small, +1 large */ WEAPON("long sword", None, 1, 0, 0, 50, 40, 15, 8, 12, 0, S, P_LONG_SWORD, IRON, HI_METAL), WEAPON("two-handed sword", None, 1, 0, 1, 22, 150, 50, 12, 6, 0, S, P_TWO_HANDED_SWORD, IRON, HI_METAL), /* +2d6 large */ WEAPON("katana", "samurai sword", 0, 0, 0, 4, 40, 80, 10, 12, 1, S, P_LONG_SWORD, IRON, HI_METAL), /* special swords set up for artifacts */ WEAPON("tsurugi", "long samurai sword", 0, 0, 1, 0, 60, 500, 16, 8, 2, S, P_TWO_HANDED_SWORD, METAL, HI_METAL), /* +2d6 large */ WEAPON("runesword", "runed broadsword", 0, 0, 0, 0, 40, 300, 4, 6, 0, S, P_BROAD_SWORD, IRON, CLR_BLACK), /* +d4 small, +1 large; Stormbringer: +5d2 +d8 from level drain */ /* polearms */ /* spear-type */ WEAPON("partisan", "vulgar polearm", 0, 0, 1, 5, 80, 10, 6, 6, 0, P, P_POLEARMS, IRON, HI_METAL), /* +1 large */ WEAPON("ranseur", "hilted polearm", 0, 0, 1, 5, 50, 6, 4, 4, 0, P, P_POLEARMS, IRON, HI_METAL), /* +d4 both */ WEAPON("spetum", "forked polearm", 0, 0, 1, 5, 50, 5, 6, 6, 0, P, P_POLEARMS, IRON, HI_METAL), /* +1 small, +d6 large */ WEAPON("glaive", "single-edged polearm", 0, 0, 1, 8, 75, 6, 6, 10, 0, S, P_POLEARMS, IRON, HI_METAL), WEAPON("lance", None, 1, 0, 0, 4, 180, 10, 6, 8, 0, P, P_LANCE, IRON, HI_METAL), /* +2d10 when jousting with lance as primary weapon */ /* axe-type */ WEAPON("halberd", "angled poleaxe", 0, 0, 1, 8, 150, 10, 10, 6, 0, P|S, P_POLEARMS, IRON, HI_METAL), /* +1d6 large */ WEAPON("bardiche", "long poleaxe", 0, 0, 1, 4, 120, 7, 4, 4, 0, S, P_POLEARMS, IRON, HI_METAL), /* +1d4 small, +2d4 large */ WEAPON("voulge", "pole cleaver", 0, 0, 1, 4, 125, 5, 4, 4, 0, S, P_POLEARMS, IRON, HI_METAL), /* +d4 both */ WEAPON("dwarvish mattock", "broad pick", 0, 0, 1, 13, 120, 50, 12, 8, -1, B, P_PICK_AXE, IRON, HI_METAL), /* curved/hooked */ WEAPON("fauchard", "pole sickle", 0, 0, 1, 6, 60, 5, 6, 8, 0, P|S, P_POLEARMS, IRON, HI_METAL), WEAPON("guisarme", "pruning hook", 0, 0, 1, 6, 80, 5, 4, 8, 0, S, P_POLEARMS, IRON, HI_METAL), /* +1d4 small */ WEAPON("bill-guisarme", "hooked polearm", 0, 0, 1, 4, 120, 7, 4, 10, 0, P|S, P_POLEARMS, IRON, HI_METAL), /* +1d4 small */ /* other */ WEAPON("lucern hammer", "pronged polearm", 0, 0, 1, 5, 150, 7, 4, 6, 0, B|P, P_POLEARMS, IRON, HI_METAL), /* +1d4 small */ WEAPON("bec de corbin", "beaked polearm", 0, 0, 1, 4, 100, 8, 8, 6, 0, B|P, P_POLEARMS, IRON, HI_METAL), /* bludgeons */ WEAPON("mace", None, 1, 0, 0, 40, 30, 5, 6, 6, 0, B, P_MACE, IRON, HI_METAL), /* +1 small */ WEAPON("morning star", None, 1, 0, 0, 12, 120, 10, 4, 6, 0, B, P_MORNING_STAR, IRON, HI_METAL), /* +d4 small, +1 large */ WEAPON("war hammer", None, 1, 0, 0, 15, 50, 5, 4, 4, 0, B, P_HAMMER, IRON, HI_METAL), /* +1 small */ WEAPON("club", None, 1, 0, 0, 12, 30, 3, 6, 3, 0, B, P_CLUB, WOOD, HI_WOOD), WEAPON("rubber hose", None, 1, 0, 0, 0, 20, 3, 4, 3, 0, B, P_WHIP, PLASTIC, CLR_BROWN), WEAPON("quarterstaff", "staff", 0, 0, 1, 11, 40, 5, 6, 6, 0, B, P_QUARTERSTAFF, WOOD, HI_WOOD), /* two-piece */ WEAPON("aklys", "thonged club", 0, 0, 0, 8, 15, 4, 6, 3, 0, B, P_CLUB, IRON, HI_METAL), WEAPON("flail", None, 1, 0, 0, 40, 15, 4, 6, 4, 0, B, P_FLAIL, IRON, HI_METAL), /* +1 small, +1d4 large */ /* misc */ WEAPON("bullwhip", None, 1, 0, 0, 2, 20, 4, 2, 1, 0, 0, P_WHIP, LEATHER, CLR_BROWN), /* bows */ BOW("bow", None, 1, 24, 30, 60, 0, WOOD, P_BOW, HI_WOOD), BOW("elven bow", "runed bow", 0, 12, 30, 60, 0, WOOD, P_BOW, HI_WOOD), BOW("orcish bow", "crude bow", 0, 12, 30, 60, 0, WOOD, P_BOW, CLR_BLACK), BOW("yumi", "long bow", 0, 0, 30, 60, 0, WOOD, P_BOW, HI_WOOD), BOW("sling", None, 1, 40, 3, 20, 0, LEATHER, P_SLING, HI_LEATHER), BOW("crossbow", None, 1, 45, 50, 40, 0, WOOD, P_CROSSBOW, HI_WOOD), #undef P #undef S #undef B #undef WEAPON #undef PROJECTILE #undef BOW /* armor ... */ /* IRON denotes ferrous metals, including steel. * Only IRON weapons and armor can rust. * Only COPPER (including brass) corrodes. * Some creatures are vulnerable to SILVER. */ #define ARMOR(name,desc,kn,mgc,blk,power,prob,delay,wt, \ cost,ac,can,sub,metal,c) \ OBJECT(OBJ(name, desc), \ BITS(kn, 0, 1, 0, mgc, 1, 0, 0, blk, 0, 0, sub, metal), \ power, ARMOR_CLASS, prob, delay, wt, \ cost, 0, 0, 10 - ac, can, wt, c) #define HELM(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name, desc, kn, mgc, 0, power, prob, delay, wt, \ cost, ac, can, ARM_HELM, metal, c) #define CLOAK(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name, desc, kn, mgc, 0, power, prob, delay, wt, \ cost, ac, can, ARM_CLOAK, metal, c) #define SHIELD(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name, desc, kn, mgc, blk, power, prob, delay, wt, \ cost, ac, can, ARM_SHIELD, metal, c) #define GLOVES(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name, desc, kn, mgc, 0, power, prob, delay, wt, \ cost, ac, can, ARM_GLOVES, metal, c) #define BOOTS(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name, desc, kn, mgc, 0, power, prob, delay, wt, \ cost, ac, can, ARM_BOOTS, metal, c) /* helmets */ HELM("elven leather helm", "leather hat", 0, 0, 0, 6, 1, 3, 8, 9, 0, LEATHER, HI_LEATHER), HELM("orcish helm", "iron skull cap", 0, 0, 0, 6, 1, 30, 10, 9, 0, IRON, CLR_BLACK), HELM("dwarvish iron helm", "hard hat", 0, 0, 0, 6, 1, 40, 20, 8, 0, IRON, HI_METAL), HELM("fedora", None, 1, 0, 0, 0, 0, 3, 1, 10, 0, CLOTH, CLR_BROWN), HELM("cornuthaum", "conical hat", 0, 1, CLAIRVOYANT, 3, 1, 4, 80, 10, 1, CLOTH, CLR_BLUE), /* name coined by devteam; confers clairvoyance for wizards, blocks clairvoyance if worn by role other than wizard */ HELM("dunce cap", "conical hat", 0, 1, 0, 3, 1, 4, 1, 10, 0, CLOTH, CLR_BLUE), HELM("dented pot", None, 1, 0, 0, 2, 0, 10, 8, 9, 0, IRON, CLR_BLACK), /* with shuffled appearances... */ HELM("helmet", "plumed helmet", 0, 0, 0, 10, 1, 30, 10, 9, 0, IRON, HI_METAL), HELM("helm of brilliance", "etched helmet", 0, 1, 0, 6, 1, 50, 50, 9, 0, IRON, CLR_GREEN), HELM("helm of opposite alignment", "crested helmet", 0, 1, 0, 6, 1, 50, 50, 9, 0, IRON, HI_METAL), HELM("helm of telepathy", "visored helmet", 0, 1, TELEPAT, 2, 1, 50, 50, 9, 0, IRON, HI_METAL), /* suits of armor */ /* * There is code in polyself.c that assumes (1) and (2). * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2). * (1) The dragon scale mails and the dragon scales are together. * (2) That the order of the dragon scale mail and dragon scales * is the the same as order of dragons defined in monst.c. */ #define DRGN_ARMR(name,mgc,power,cost,ac,color) \ ARMOR(name, None, 1, mgc, 1, power, 0, 5, 40, \ cost, ac, 0, ARM_SUIT, DRAGON_HIDE, color) /* 3.4.1: dragon scale mail reclassified as "magic" since magic is needed to create them */ DRGN_ARMR("gray dragon scale mail", 1, ANTIMAGIC, 1200, 1, CLR_GRAY), DRGN_ARMR("silver dragon scale mail", 1, REFLECTING, 1200, 1, DRAGON_SILVER), #if 0 /* DEFERRED */ DRGN_ARMR("shimmering dragon scale mail", 1, DISPLACED, 1200, 1, CLR_CYAN), #endif DRGN_ARMR("red dragon scale mail", 1, FIRE_RES, 900, 1, CLR_RED), DRGN_ARMR("white dragon scale mail", 1, COLD_RES, 900, 1, CLR_WHITE), DRGN_ARMR("orange dragon scale mail", 1, SLEEP_RES, 900, 1, CLR_ORANGE), DRGN_ARMR("black dragon scale mail", 1, DISINT_RES, 1200, 1, CLR_BLACK), DRGN_ARMR("blue dragon scale mail", 1, SHOCK_RES, 900, 1, CLR_BLUE), DRGN_ARMR("green dragon scale mail", 1, POISON_RES, 900, 1, CLR_GREEN), DRGN_ARMR("yellow dragon scale mail", 1, ACID_RES, 900, 1, CLR_YELLOW), /* For now, only dragons leave these. */ /* 3.4.1: dragon scales left classified as "non-magic"; they confer magical properties but are produced "naturally" */ DRGN_ARMR("gray dragon scales", 0, ANTIMAGIC, 700, 7, CLR_GRAY), DRGN_ARMR("silver dragon scales", 0, REFLECTING, 700, 7, DRAGON_SILVER), #if 0 /* DEFERRED */ DRGN_ARMR("shimmering dragon scales", 0, DISPLACED, 700, 7, CLR_CYAN), #endif DRGN_ARMR("red dragon scales", 0, FIRE_RES, 500, 7, CLR_RED), DRGN_ARMR("white dragon scales", 0, COLD_RES, 500, 7, CLR_WHITE), DRGN_ARMR("orange dragon scales", 0, SLEEP_RES, 500, 7, CLR_ORANGE), DRGN_ARMR("black dragon scales", 0, DISINT_RES, 700, 7, CLR_BLACK), DRGN_ARMR("blue dragon scales", 0, SHOCK_RES, 500, 7, CLR_BLUE), DRGN_ARMR("green dragon scales", 0, POISON_RES, 500, 7, CLR_GREEN), DRGN_ARMR("yellow dragon scales", 0, ACID_RES, 500, 7, CLR_YELLOW), #undef DRGN_ARMR /* other suits */ ARMOR("plate mail", None, 1, 0, 1, 0, 44, 5, 450, 600, 3, 2, ARM_SUIT, IRON, HI_METAL), ARMOR("crystal plate mail", None, 1, 0, 1, 0, 10, 5, 450, 820, 3, 2, ARM_SUIT, GLASS, CLR_WHITE), ARMOR("bronze plate mail", None, 1, 0, 1, 0, 25, 5, 450, 400, 4, 1, ARM_SUIT, COPPER, HI_COPPER), ARMOR("splint mail", None, 1, 0, 1, 0, 62, 5, 400, 80, 4, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("banded mail", None, 1, 0, 1, 0, 72, 5, 350, 90, 4, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("dwarvish mithril-coat", None, 1, 0, 0, 0, 10, 1, 150, 240, 4, 2, ARM_SUIT, MITHRIL, HI_SILVER), ARMOR("elven mithril-coat", None, 1, 0, 0, 0, 15, 1, 150, 240, 5, 2, ARM_SUIT, MITHRIL, HI_SILVER), ARMOR("chain mail", None, 1, 0, 0, 0, 72, 5, 300, 75, 5, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("orcish chain mail", "crude chain mail", 0, 0, 0, 0, 20, 5, 300, 75, 6, 1, ARM_SUIT, IRON, CLR_BLACK), ARMOR("scale mail", None, 1, 0, 0, 0, 72, 5, 250, 45, 6, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("studded leather armor", None, 1, 0, 0, 0, 72, 3, 200, 15, 7, 1, ARM_SUIT, LEATHER, HI_LEATHER), ARMOR("ring mail", None, 1, 0, 0, 0, 72, 5, 250, 100, 7, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("orcish ring mail", "crude ring mail", 0, 0, 0, 0, 20, 5, 250, 80, 8, 1, ARM_SUIT, IRON, CLR_BLACK), ARMOR("leather armor", None, 1, 0, 0, 0, 82, 3, 150, 5, 8, 1, ARM_SUIT, LEATHER, HI_LEATHER), ARMOR("leather jacket", None, 1, 0, 0, 0, 12, 0, 30, 10, 9, 0, ARM_SUIT, LEATHER, CLR_BLACK), /* shirts */ ARMOR("Hawaiian shirt", None, 1, 0, 0, 0, 8, 0, 5, 3, 10, 0, ARM_SHIRT, CLOTH, CLR_MAGENTA), ARMOR("T-shirt", None, 1, 0, 0, 0, 2, 0, 5, 2, 10, 0, ARM_SHIRT, CLOTH, CLR_WHITE), /* cloaks */ CLOAK("mummy wrapping", None, 1, 0, 0, 0, 0, 3, 2, 10, 1, CLOTH, CLR_GRAY), /* worn mummy wrapping blocks invisibility */ CLOAK("elven cloak", "faded pall", 0, 1, STEALTH, 8, 0, 10, 60, 9, 1, CLOTH, CLR_BLACK), CLOAK("orcish cloak", "coarse mantelet", 0, 0, 0, 8, 0, 10, 40, 10, 1, CLOTH, CLR_BLACK), CLOAK("dwarvish cloak", "hooded cloak", 0, 0, 0, 8, 0, 10, 50, 10, 1, CLOTH, HI_CLOTH), CLOAK("oilskin cloak", "slippery cloak", 0, 0, 0, 8, 0, 10, 50, 9, 2, CLOTH, HI_CLOTH), CLOAK("robe", None, 1, 1, 0, 3, 0, 15, 50, 8, 2, CLOTH, CLR_RED), /* robe was adopted from slash'em, where it's worn as a suit rather than as a cloak and there are several variations */ CLOAK("alchemy smock", "apron", 0, 1, POISON_RES, 9, 0, 10, 50, 9, 1, CLOTH, CLR_WHITE), CLOAK("leather cloak", None, 1, 0, 0, 8, 0, 15, 40, 9, 1, LEATHER, CLR_BROWN), /* with shuffled appearances... */ CLOAK("cloak of protection", "tattered cape", 0, 1, PROTECTION, 9, 0, 10, 50, 7, 3, CLOTH, HI_CLOTH), /* cloak of protection is now the only item conferring MC 3 */ CLOAK("cloak of invisibility", "opera cloak", 0, 1, INVIS, 10, 0, 10, 60, 9, 1, CLOTH, CLR_BRIGHT_MAGENTA), CLOAK("cloak of magic resistance", "ornamental cope", 0, 1, ANTIMAGIC, 2, 0, 10, 60, 9, 1, CLOTH, CLR_WHITE), /* 'cope' is not a spelling mistake... leave it be */ CLOAK("cloak of displacement", "piece of cloth", 0, 1, DISPLACED, 10, 0, 10, 50, 9, 1, CLOTH, HI_CLOTH), /* shields */ SHIELD("small shield", None, 1, 0, 0, 0, 6, 0, 30, 3, 9, 0, WOOD, HI_WOOD), SHIELD("elven shield", "blue and green shield", 0, 0, 0, 0, 2, 0, 40, 7, 8, 0, WOOD, CLR_GREEN), SHIELD("Uruk-hai shield", "white-handed shield", 0, 0, 0, 0, 2, 0, 50, 7, 9, 0, IRON, HI_METAL), SHIELD("orcish shield", "red-eyed shield", 0, 0, 0, 0, 2, 0, 50, 7, 9, 0, IRON, CLR_RED), SHIELD("large shield", None, 1, 0, 1, 0, 7, 0, 100, 10, 8, 0, IRON, HI_METAL), SHIELD("dwarvish roundshield", "large round shield", 0, 0, 0, 0, 4, 0, 100, 10, 8, 0, IRON, HI_METAL), SHIELD("shield of reflection", "polished silver shield", 0, 1, 0, REFLECTING, 3, 0, 50, 50, 8, 0, SILVER, HI_SILVER), /* gloves */ /* These have their color but not material shuffled, so the IRON must * stay CLR_BROWN (== HI_LEATHER) even though it's normally either * HI_METAL or CLR_BLACK. All have shuffled descriptions. */ GLOVES("leather gloves", "old gloves", 0, 0, 0, 16, 1, 10, 8, 9, 0, LEATHER, HI_LEATHER), GLOVES("gauntlets of fumbling", "padded gloves", 0, 1, FUMBLING, 8, 1, 10, 50, 9, 0, LEATHER, HI_LEATHER), GLOVES("gauntlets of power", "riding gloves", 0, 1, 0, 8, 1, 30, 50, 9, 0, IRON, CLR_BROWN), GLOVES("gauntlets of dexterity", "fencing gloves", 0, 1, 0, 8, 1, 10, 50, 9, 0, LEATHER, HI_LEATHER), /* boots */ BOOTS("low boots", "walking shoes", 0, 0, 0, 25, 2, 10, 8, 9, 0, LEATHER, HI_LEATHER), BOOTS("iron shoes", "hard shoes", 0, 0, 0, 7, 2, 50, 16, 8, 0, IRON, HI_METAL), BOOTS("high boots", "jackboots", 0, 0, 0, 15, 2, 20, 12, 8, 0, LEATHER, HI_LEATHER), /* with shuffled appearances... */ BOOTS("speed boots", "combat boots", 0, 1, FAST, 12, 2, 20, 50, 9, 0, LEATHER, HI_LEATHER), BOOTS("water walking boots", "jungle boots", 0, 1, WWALKING, 12, 2, 15, 50, 9, 0, LEATHER, HI_LEATHER), BOOTS("jumping boots", "hiking boots", 0, 1, JUMPING, 12, 2, 20, 50, 9, 0, LEATHER, HI_LEATHER), BOOTS("elven boots", "mud boots", 0, 1, STEALTH, 12, 2, 15, 8, 9, 0, LEATHER, HI_LEATHER), BOOTS("kicking boots", "buckled boots", 0, 1, 0, 12, 2, 50, 8, 9, 0, IRON, CLR_BROWN), /* CLR_BROWN for same reason as gauntlets of power */ BOOTS("fumble boots", "riding boots", 0, 1, FUMBLING, 12, 2, 20, 30, 9, 0, LEATHER, HI_LEATHER), BOOTS("levitation boots", "snow boots", 0, 1, LEVITATION, 12, 2, 15, 30, 9, 0, LEATHER, HI_LEATHER), #undef HELM #undef CLOAK #undef SHIELD #undef GLOVES #undef BOOTS #undef ARMOR /* rings ... */ #define RING(name,stone,power,cost,mgc,spec,mohs,metal,color) \ OBJECT(OBJ(name, stone), \ BITS(0, 0, spec, 0, mgc, spec, 0, 0, 0, \ HARDGEM(mohs), 0, P_NONE, metal), \ power, RING_CLASS, 0, 0, 3, cost, 0, 0, 0, 0, 15, color) RING("adornment", "wooden", ADORNED, 100, 1, 1, 2, WOOD, HI_WOOD), RING("gain strength", "granite", 0, 150, 1, 1, 7, MINERAL, HI_MINERAL), RING("gain constitution", "opal", 0, 150, 1, 1, 7, MINERAL, HI_MINERAL), RING("increase accuracy", "clay", 0, 150, 1, 1, 4, MINERAL, CLR_RED), RING("increase damage", "coral", 0, 150, 1, 1, 4, MINERAL, CLR_ORANGE), RING("protection", "black onyx", PROTECTION, 100, 1, 1, 7, MINERAL, CLR_BLACK), /* 'PROTECTION' intrinsic enhances MC from worn armor by +1, regardless of ring's enchantment; wearing a second ring of protection (or even one ring of protection combined with cloak of protection) doesn't give a second MC boost */ RING("regeneration", "moonstone", REGENERATION, 200, 1, 0, 6, MINERAL, HI_MINERAL), RING("searching", "tiger eye", SEARCHING, 200, 1, 0, 6, GEMSTONE, CLR_BROWN), RING("stealth", "jade", STEALTH, 100, 1, 0, 6, GEMSTONE, CLR_GREEN), RING("sustain ability", "bronze", FIXED_ABIL, 100, 1, 0, 4, COPPER, HI_COPPER), RING("levitation", "agate", LEVITATION, 200, 1, 0, 7, GEMSTONE, CLR_RED), RING("hunger", "topaz", HUNGER, 100, 1, 0, 8, GEMSTONE, CLR_CYAN), RING("aggravate monster", "sapphire", AGGRAVATE_MONSTER, 150, 1, 0, 9, GEMSTONE, CLR_BLUE), RING("conflict", "ruby", CONFLICT, 300, 1, 0, 9, GEMSTONE, CLR_RED), RING("warning", "diamond", WARNING, 100, 1, 0, 10, GEMSTONE, CLR_WHITE), RING("poison resistance", "pearl", POISON_RES, 150, 1, 0, 4, BONE, CLR_WHITE), RING("fire resistance", "iron", FIRE_RES, 200, 1, 0, 5, IRON, HI_METAL), RING("cold resistance", "brass", COLD_RES, 150, 1, 0, 4, COPPER, HI_COPPER), RING("shock resistance", "copper", SHOCK_RES, 150, 1, 0, 3, COPPER, HI_COPPER), RING("free action", "twisted", FREE_ACTION, 200, 1, 0, 6, IRON, HI_METAL), RING("slow digestion", "steel", SLOW_DIGESTION, 200, 1, 0, 8, IRON, HI_METAL), RING("teleportation", "silver", TELEPORT, 200, 1, 0, 3, SILVER, HI_SILVER), RING("teleport control", "gold", TELEPORT_CONTROL, 300, 1, 0, 3, GOLD, HI_GOLD), RING("polymorph", "ivory", POLYMORPH, 300, 1, 0, 4, BONE, CLR_WHITE), RING("polymorph control", "emerald", POLYMORPH_CONTROL, 300, 1, 0, 8, GEMSTONE, CLR_BRIGHT_GREEN), RING("invisibility", "wire", INVIS, 150, 1, 0, 5, IRON, HI_METAL), RING("see invisible", "engagement", SEE_INVIS, 150, 1, 0, 5, IRON, HI_METAL), RING("protection from shape changers", "shiny", PROT_FROM_SHAPE_CHANGERS, 100, 1, 0, 5, IRON, CLR_BRIGHT_CYAN), #undef RING /* amulets ... - THE Amulet comes last because it is special */ #define AMULET(name,desc,power,prob) \ OBJECT(OBJ(name, desc), \ BITS(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, P_NONE, IRON), \ power, AMULET_CLASS, prob, 0, 20, 150, 0, 0, 0, 0, 20, HI_METAL) AMULET("amulet of ESP", "circular", TELEPAT, 175), AMULET("amulet of life saving", "spherical", LIFESAVED, 75), AMULET("amulet of strangulation", "oval", STRANGLED, 135), AMULET("amulet of restful sleep", "triangular", SLEEPY, 135), AMULET("amulet versus poison", "pyramidal", POISON_RES, 165), AMULET("amulet of change", "square", 0, 130), AMULET("amulet of unchanging", "concave", UNCHANGING, 45), AMULET("amulet of reflection", "hexagonal", REFLECTING, 75), AMULET("amulet of magical breathing", "octagonal", MAGICAL_BREATHING, 65), /* fixed descriptions; description duplication is deliberate; * fake one must come before real one because selection for * description shuffling stops when a non-magic amulet is encountered */ OBJECT(OBJ("cheap plastic imitation of the Amulet of Yendor", "Amulet of Yendor"), BITS(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, PLASTIC), 0, AMULET_CLASS, 0, 0, 20, 0, 0, 0, 0, 0, 1, HI_METAL), OBJECT(OBJ("Amulet of Yendor", /* note: description == name */ "Amulet of Yendor"), BITS(0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, MITHRIL), 0, AMULET_CLASS, 0, 0, 20, 30000, 0, 0, 0, 0, 20, HI_METAL), #undef AMULET /* tools ... */ /* tools with weapon characteristics come last */ #define TOOL(name,desc,kn,mrg,mgc,chg,prob,wt,cost,mat,color) \ OBJECT(OBJ(name, desc), \ BITS(kn, mrg, chg, 0, mgc, chg, 0, 0, 0, 0, 0, P_NONE, mat), \ 0, TOOL_CLASS, prob, 0, wt, cost, 0, 0, 0, 0, wt, color) #define CONTAINER(name,desc,kn,mgc,chg,prob,wt,cost,mat,color) \ OBJECT(OBJ(name, desc), \ BITS(kn, 0, chg, 1, mgc, chg, 0, 0, 0, 0, 0, P_NONE, mat), \ 0, TOOL_CLASS, prob, 0, wt, cost, 0, 0, 0, 0, wt, color) #define WEPTOOL(name,desc,kn,mgc,bi,prob,wt,cost,sdam,ldam,hitbon,sub,mat,clr)\ OBJECT(OBJ(name, desc), \ BITS(kn, 0, 1, 0, mgc, 1, 0, 0, bi, 0, hitbon, sub, mat), \ 0, TOOL_CLASS, prob, 0, wt, cost, sdam, ldam, hitbon, 0, wt, clr) /* containers */ CONTAINER("large box", None, 1, 0, 0, 40, 350, 8, WOOD, HI_WOOD), CONTAINER("chest", None, 1, 0, 0, 35, 600, 16, WOOD, HI_WOOD), CONTAINER("ice box", None, 1, 0, 0, 5, 900, 42, PLASTIC, CLR_WHITE), CONTAINER("sack", "bag", 0, 0, 0, 35, 15, 2, CLOTH, HI_CLOTH), CONTAINER("oilskin sack", "bag", 0, 0, 0, 5, 15, 100, CLOTH, HI_CLOTH), CONTAINER("bag of holding", "bag", 0, 1, 0, 20, 15, 100, CLOTH, HI_CLOTH), CONTAINER("bag of tricks", "bag", 0, 1, 1, 20, 15, 100, CLOTH, HI_CLOTH), #undef CONTAINER /* lock opening tools */ TOOL("skeleton key", "key", 0, 0, 0, 0, 80, 3, 10, IRON, HI_METAL), TOOL("lock pick", None, 1, 0, 0, 0, 60, 4, 20, IRON, HI_METAL), TOOL("credit card", None, 1, 0, 0, 0, 15, 1, 10, PLASTIC, CLR_WHITE), /* light sources */ TOOL("tallow candle", "candle", 0, 1, 0, 0, 20, 2, 10, WAX, CLR_WHITE), TOOL("wax candle", "candle", 0, 1, 0, 0, 5, 2, 20, WAX, CLR_WHITE), TOOL("brass lantern", None, 1, 0, 0, 0, 30, 30, 12, COPPER, CLR_YELLOW), TOOL("oil lamp", "lamp", 0, 0, 0, 0, 45, 20, 10, COPPER, CLR_YELLOW), TOOL("magic lamp", "lamp", 0, 0, 1, 0, 15, 20, 50, COPPER, CLR_YELLOW), /* other tools */ TOOL("expensive camera", None, 1, 0, 0, 1, 15, 12,200, PLASTIC, CLR_BLACK), TOOL("mirror", "looking glass", 0, 0, 0, 0, 45, 13, 10, GLASS, HI_SILVER), TOOL("crystal ball", "glass orb", 0, 0, 1, 1, 15,150, 60, GLASS, HI_GLASS), TOOL("lenses", None, 1, 0, 0, 0, 5, 3, 80, GLASS, HI_GLASS), TOOL("blindfold", None, 1, 0, 0, 0, 50, 2, 20, CLOTH, CLR_BLACK), TOOL("towel", None, 1, 0, 0, 0, 50, 2, 50, CLOTH, CLR_MAGENTA), TOOL("saddle", None, 1, 0, 0, 0, 5,200,150, LEATHER, HI_LEATHER), TOOL("leash", None, 1, 0, 0, 0, 65, 12, 20, LEATHER, HI_LEATHER), TOOL("stethoscope", None, 1, 0, 0, 0, 25, 4, 75, IRON, HI_METAL), TOOL("tinning kit", None, 1, 0, 0, 1, 15,100, 30, IRON, HI_METAL), TOOL("tin opener", None, 1, 0, 0, 0, 35, 4, 30, IRON, HI_METAL), TOOL("can of grease", None, 1, 0, 0, 1, 15, 15, 20, IRON, HI_METAL), TOOL("figurine", None, 1, 0, 1, 0, 25, 50, 80, MINERAL, HI_MINERAL), /* monster type specified by obj->corpsenm */ TOOL("magic marker", None, 1, 0, 1, 1, 15, 2, 50, PLASTIC, CLR_RED), /* traps */ TOOL("land mine", None, 1, 0, 0, 0, 0, 300,180, IRON, CLR_RED), TOOL("beartrap", None, 1, 0, 0, 0, 0, 200, 60, IRON, HI_METAL), /* instruments; "If tin whistles are made out of tin, what do they make foghorns out of?" */ TOOL("tin whistle", "whistle", 0, 0, 0, 0,100, 3, 10, METAL, HI_METAL), TOOL("magic whistle", "whistle", 0, 0, 1, 0, 30, 3, 10, METAL, HI_METAL), TOOL("wooden flute", "flute", 0, 0, 0, 0, 4, 5, 12, WOOD, HI_WOOD), TOOL("magic flute", "flute", 0, 0, 1, 1, 2, 5, 36, WOOD, HI_WOOD), TOOL("tooled horn", "horn", 0, 0, 0, 0, 5, 18, 15, BONE, CLR_WHITE), TOOL("frost horn", "horn", 0, 0, 1, 1, 2, 18, 50, BONE, CLR_WHITE), TOOL("fire horn", "horn", 0, 0, 1, 1, 2, 18, 50, BONE, CLR_WHITE), TOOL("horn of plenty", "horn", 0, 0, 1, 1, 2, 18, 50, BONE, CLR_WHITE), /* horn, but not an instrument */ TOOL("wooden harp", "harp", 0, 0, 0, 0, 4, 30, 50, WOOD, HI_WOOD), TOOL("magic harp", "harp", 0, 0, 1, 1, 2, 30, 50, WOOD, HI_WOOD), TOOL("bell", None, 1, 0, 0, 0, 2, 30, 50, COPPER, HI_COPPER), TOOL("bugle", None, 1, 0, 0, 0, 4, 10, 15, COPPER, HI_COPPER), TOOL("leather drum", "drum", 0, 0, 0, 0, 4, 25, 25, LEATHER, HI_LEATHER), TOOL("drum of earthquake","drum", 0, 0, 1, 1, 2, 25, 25, LEATHER, HI_LEATHER), /* tools useful as weapons */ WEPTOOL("pick-axe", None, 1, 0, 0, 20, 100, 50, 6, 3, WHACK, P_PICK_AXE, IRON, HI_METAL), WEPTOOL("grappling hook", "iron hook", 0, 0, 0, 5, 30, 50, 2, 6, WHACK, P_FLAIL, IRON, HI_METAL), WEPTOOL("unicorn horn", None, 1, 1, 1, 0, 20, 100, 12, 12, PIERCE, P_UNICORN_HORN, BONE, CLR_WHITE), /* 3.4.1: unicorn horn left classified as "magic" */ /* two unique tools; * not artifacts, despite the comment which used to be here */ OBJECT(OBJ("Candelabrum of Invocation", "candelabrum"), BITS(0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, P_NONE, GOLD), 0, TOOL_CLASS, 0, 0, 10, 5000, 0, 0, 0, 0, 200, HI_GOLD), OBJECT(OBJ("Bell of Opening", "silver bell"), BITS(0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, P_NONE, SILVER), 0, TOOL_CLASS, 0, 0, 10, 5000, 0, 0, 0, 0, 50, HI_SILVER), #undef TOOL #undef WEPTOOL /* Comestibles ... */ #define FOOD(name, prob, delay, wt, unk, tin, nutrition, color) \ OBJECT(OBJ(name, None), \ BITS(1, 1, unk, 0, 0, 0, 0, 0, 0, 0, 0, P_NONE, tin), 0, \ FOOD_CLASS, prob, delay, wt, nutrition / 20 + 5, 0, 0, 0, 0, \ nutrition, color) /* All types of food (except tins & corpses) must have a delay of at least 1. * Delay on corpses is computed and is weight dependant. * Domestic pets prefer tripe rations above all others. * Fortune cookies can be read, using them up without ingesting them. * Carrots improve your vision. * +0 tins contain monster meat. * +1 tins (of spinach) make you stronger (like Popeye). * Meatballs/sticks/rings are only created from objects via stone to flesh. */ /* meat */ FOOD("tripe ration", 140, 2, 10, 0, FLESH, 200, CLR_BROWN), FOOD("corpse", 0, 1, 0, 0, FLESH, 0, CLR_BROWN), FOOD("egg", 85, 1, 1, 1, FLESH, 80, CLR_WHITE), FOOD("meatball", 0, 1, 1, 0, FLESH, 5, CLR_BROWN), FOOD("meat stick", 0, 1, 1, 0, FLESH, 5, CLR_BROWN), FOOD("huge chunk of meat", 0, 20,400, 0, FLESH,2000, CLR_BROWN), /* special case because it's not mergable */ OBJECT(OBJ("meat ring", None), BITS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FLESH), 0, FOOD_CLASS, 0, 1, 5, 1, 0, 0, 0, 0, 5, CLR_BROWN), /* pudding 'corpses' will turn into these and combine; must be in same order as the pudding monsters */ FOOD("glob of gray ooze", 0, 2, 20, 0, FLESH, 20, CLR_GRAY), FOOD("glob of brown pudding", 0, 2, 20, 0, FLESH, 20, CLR_BROWN), FOOD("glob of green slime", 0, 2, 20, 0, FLESH, 20, CLR_GREEN), FOOD("glob of black pudding", 0, 2, 20, 0, FLESH, 20, CLR_BLACK), /* fruits & veggies */ FOOD("kelp frond", 0, 1, 1, 0, VEGGY, 30, CLR_GREEN), FOOD("eucalyptus leaf", 3, 1, 1, 0, VEGGY, 30, CLR_GREEN), FOOD("apple", 15, 1, 2, 0, VEGGY, 50, CLR_RED), FOOD("orange", 10, 1, 2, 0, VEGGY, 80, CLR_ORANGE), FOOD("pear", 10, 1, 2, 0, VEGGY, 50, CLR_BRIGHT_GREEN), FOOD("melon", 10, 1, 5, 0, VEGGY, 100, CLR_BRIGHT_GREEN), FOOD("banana", 10, 1, 2, 0, VEGGY, 80, CLR_YELLOW), FOOD("carrot", 15, 1, 2, 0, VEGGY, 50, CLR_ORANGE), FOOD("sprig of wolfsbane", 7, 1, 1, 0, VEGGY, 40, CLR_GREEN), FOOD("clove of garlic", 7, 1, 1, 0, VEGGY, 40, CLR_WHITE), /* name of slime mold is changed based on player's OPTION=fruit:something and bones data might have differently named ones from prior games */ FOOD("slime mold", 75, 1, 5, 0, VEGGY, 250, HI_ORGANIC), /* people food */ FOOD("lump of royal jelly", 0, 1, 2, 0, VEGGY, 200, CLR_YELLOW), FOOD("cream pie", 25, 1, 10, 0, VEGGY, 100, CLR_WHITE), FOOD("candy bar", 13, 1, 2, 0, VEGGY, 100, CLR_BROWN), FOOD("fortune cookie", 55, 1, 1, 0, VEGGY, 40, CLR_YELLOW), FOOD("pancake", 25, 2, 2, 0, VEGGY, 200, CLR_YELLOW), FOOD("lembas wafer", 20, 2, 5, 0, VEGGY, 800, CLR_WHITE), FOOD("cram ration", 20, 3, 15, 0, VEGGY, 600, HI_ORGANIC), FOOD("food ration", 380, 5, 20, 0, VEGGY, 800, HI_ORGANIC), FOOD("K-ration", 0, 1, 10, 0, VEGGY, 400, HI_ORGANIC), FOOD("C-ration", 0, 1, 10, 0, VEGGY, 300, HI_ORGANIC), /* tins have type specified by obj->spe (+1 for spinach, other implies flesh; negative specifies preparation method {homemade,boiled,&c}) and by obj->corpsenm (type of monster flesh) */ FOOD("tin", 75, 0, 10, 1, METAL, 0, HI_METAL), #undef FOOD /* potions ... */ #define POTION(name,desc,mgc,power,prob,cost,color) \ OBJECT(OBJ(name, desc), \ BITS(0, 1, 0, 0, mgc, 0, 0, 0, 0, 0, 0, P_NONE, GLASS), \ power, POTION_CLASS, prob, 0, 20, cost, 0, 0, 0, 0, 10, color) POTION("gain ability", "ruby", 1, 0, 42, 300, CLR_RED), POTION("restore ability", "pink", 1, 0, 40, 100, CLR_BRIGHT_MAGENTA), POTION("confusion", "orange", 1, CONFUSION, 42, 100, CLR_ORANGE), POTION("blindness", "yellow", 1, BLINDED, 40, 150, CLR_YELLOW), POTION("paralysis", "emerald", 1, 0, 42, 300, CLR_BRIGHT_GREEN), POTION("speed", "dark green", 1, FAST, 42, 200, CLR_GREEN), POTION("levitation", "cyan", 1, LEVITATION, 42, 200, CLR_CYAN), POTION("hallucination", "sky blue", 1, HALLUC, 40, 100, CLR_CYAN), POTION("invisibility", "brilliant blue", 1, INVIS, 40, 150, CLR_BRIGHT_BLUE), POTION("see invisible", "magenta", 1, SEE_INVIS, 42, 50, CLR_MAGENTA), POTION("healing", "purple-red", 1, 0, 57, 100, CLR_MAGENTA), POTION("extra healing", "puce", 1, 0, 47, 100, CLR_RED), POTION("gain level", "milky", 1, 0, 20, 300, CLR_WHITE), POTION("enlightenment", "swirly", 1, 0, 20, 200, CLR_BROWN), POTION("monster detection", "bubbly", 1, 0, 40, 150, CLR_WHITE), POTION("object detection", "smoky", 1, 0, 42, 150, CLR_GRAY), POTION("gain energy", "cloudy", 1, 0, 42, 150, CLR_WHITE), POTION("sleeping", "effervescent", 1, 0, 42, 100, CLR_GRAY), POTION("full healing", "black", 1, 0, 10, 200, CLR_BLACK), POTION("polymorph", "golden", 1, 0, 10, 200, CLR_YELLOW), POTION("booze", "brown", 0, 0, 42, 50, CLR_BROWN), POTION("sickness", "fizzy", 0, 0, 42, 50, CLR_CYAN), POTION("fruit juice", "dark", 0, 0, 42, 50, CLR_BLACK), POTION("acid", "white", 0, 0, 10, 250, CLR_WHITE), POTION("oil", "murky", 0, 0, 30, 250, CLR_BROWN), /* fixed description */ POTION("water", "clear", 0, 0, 92, 100, CLR_CYAN), #undef POTION /* scrolls ... */ #define SCROLL(name,text,mgc,prob,cost) \ OBJECT(OBJ(name, text), \ BITS(0, 1, 0, 0, mgc, 0, 0, 0, 0, 0, 0, P_NONE, PAPER), \ 0, SCROLL_CLASS, prob, 0, 5, cost, 0, 0, 0, 0, 6, HI_PAPER) SCROLL("enchant armor", "ZELGO MER", 1, 63, 80), SCROLL("destroy armor", "JUYED AWK YACC", 1, 45, 100), SCROLL("confuse monster", "NR 9", 1, 53, 100), SCROLL("scare monster", "XIXAXA XOXAXA XUXAXA", 1, 35, 100), SCROLL("remove curse", "PRATYAVAYAH", 1, 65, 80), SCROLL("enchant weapon", "DAIYEN FOOELS", 1, 80, 60), SCROLL("create monster", "LEP GEX VEN ZEA", 1, 45, 200), SCROLL("taming", "PRIRUTSENIE", 1, 15, 200), SCROLL("genocide", "ELBIB YLOH", 1, 15, 300), SCROLL("light", "VERR YED HORRE", 1, 90, 50), SCROLL("teleportation", "VENZAR BORGAVVE", 1, 55, 100), SCROLL("gold detection", "THARR", 1, 33, 100), SCROLL("food detection", "YUM YUM", 1, 25, 100), SCROLL("identify", "KERNOD WEL", 1, 180, 20), SCROLL("magic mapping", "ELAM EBOW", 1, 45, 100), SCROLL("amnesia", "DUAM XNAHT", 1, 35, 200), SCROLL("fire", "ANDOVA BEGARIN", 1, 30, 100), SCROLL("earth", "KIRJE", 1, 18, 200), SCROLL("punishment", "VE FORBRYDERNE", 1, 15, 300), SCROLL("charging", "HACKEM MUCHE", 1, 15, 300), SCROLL("stinking cloud", "VELOX NEB", 1, 15, 300), /* Extra descriptions, shuffled into use at start of new game. * Code in win/share/tilemap.c depends on SCR_STINKING_CLOUD preceding * these and on how many of them there are. If a real scroll gets added * after stinking cloud or the number of extra descriptions changes, * tilemap.c must be modified to match. */ SCROLL(None, "FOOBIE BLETCH", 1, 0, 100), SCROLL(None, "TEMOV", 1, 0, 100), SCROLL(None, "GARVEN DEH", 1, 0, 100), SCROLL(None, "READ ME", 1, 0, 100), SCROLL(None, "ETAOIN SHRDLU", 1, 0, 100), SCROLL(None, "LOREM IPSUM", 1, 0, 100), SCROLL(None, "FNORD", 1, 0, 100), /* Illuminati */ SCROLL(None, "KO BATE", 1, 0, 100), /* Kurd Lasswitz */ SCROLL(None, "ABRA KA DABRA", 1, 0, 100), /* traditional incantation */ SCROLL(None, "ASHPD SODALG", 1, 0, 100), /* Portal */ SCROLL(None, "ZLORFIK", 1, 0, 100), /* Zak McKracken */ SCROLL(None, "GNIK SISI VLE", 1, 0, 100), /* Zak McKracken */ SCROLL(None, "HAPAX LEGOMENON", 1, 0, 100), SCROLL(None, "EIRIS SAZUN IDISI", 1, 0, 100), /* Merseburg Incantations */ SCROLL(None, "PHOL ENDE WODAN", 1, 0, 100), /* Merseburg Incantations */ SCROLL(None, "GHOTI", 1, 0, 100), /* pronounced as 'fish', George Bernard Shaw */ SCROLL(None, "MAPIRO MAHAMA DIROMAT", 1, 0, 100), /* Wizardry */ SCROLL(None, "VAS CORP BET MANI", 1, 0, 100), /* Ultima */ SCROLL(None, "XOR OTA", 1, 0, 100), /* Aarne Haapakoski */ SCROLL(None, "STRC PRST SKRZ KRK", 1, 0, 100), /* Czech and Slovak tongue-twister */ /* These must come last because they have special fixed descriptions. */ #ifdef MAIL SCROLL("mail", "stamped", 0, 0, 0), #endif SCROLL("blank paper", "unlabeled", 0, 28, 60), #undef SCROLL /* spellbooks ... */ /* expanding beyond 52 spells would require changes in spellcasting or imposition of a limit on number of spells hero can know because they are currently assigned successive letters, a-zA-Z, when learned */ #define SPELL(name,desc,sub,prob,delay,level,mgc,dir,color) \ OBJECT(OBJ(name, desc), \ BITS(0, 0, 0, 0, mgc, 0, 0, 0, 0, 0, dir, sub, PAPER), \ 0, SPBOOK_CLASS, prob, delay, 50, level * 100, \ 0, 0, 0, level, 20, color) SPELL("dig", "parchment", P_MATTER_SPELL, 20, 6, 5, 1, RAY, HI_PAPER), SPELL("magic missile", "vellum", P_ATTACK_SPELL, 45, 2, 2, 1, RAY, HI_PAPER), SPELL("fireball", "ragged", P_ATTACK_SPELL, 20, 4, 4, 1, RAY, HI_PAPER), SPELL("cone of cold", "dog eared", P_ATTACK_SPELL, 10, 7, 4, 1, RAY, HI_PAPER), SPELL("sleep", "mottled", P_ENCHANTMENT_SPELL, 50, 1, 1, 1, RAY, HI_PAPER), SPELL("finger of death", "stained", P_ATTACK_SPELL, 5, 10, 7, 1, RAY, HI_PAPER), SPELL("light", "cloth", P_DIVINATION_SPELL, 45, 1, 1, 1, NODIR, HI_CLOTH), SPELL("detect monsters", "leathery", P_DIVINATION_SPELL, 43, 1, 1, 1, NODIR, HI_LEATHER), SPELL("healing", "white", P_HEALING_SPELL, 40, 2, 1, 1, IMMEDIATE, CLR_WHITE), SPELL("knock", "pink", P_MATTER_SPELL, 35, 1, 1, 1, IMMEDIATE, CLR_BRIGHT_MAGENTA), SPELL("force bolt", "red", P_ATTACK_SPELL, 35, 2, 1, 1, IMMEDIATE, CLR_RED), SPELL("confuse monster", "orange", P_ENCHANTMENT_SPELL, 30, 2, 2, 1, IMMEDIATE, CLR_ORANGE), SPELL("cure blindness", "yellow", P_HEALING_SPELL, 25, 2, 2, 1, IMMEDIATE, CLR_YELLOW), SPELL("drain life", "velvet", P_ATTACK_SPELL, 10, 2, 2, 1, IMMEDIATE, CLR_MAGENTA), SPELL("slow monster", "light green", P_ENCHANTMENT_SPELL, 30, 2, 2, 1, IMMEDIATE, CLR_BRIGHT_GREEN), SPELL("wizard lock", "dark green", P_MATTER_SPELL, 30, 3, 2, 1, IMMEDIATE, CLR_GREEN), SPELL("create monster", "turquoise", P_CLERIC_SPELL, 35, 3, 2, 1, NODIR, CLR_BRIGHT_CYAN), SPELL("detect food", "cyan", P_DIVINATION_SPELL, 30, 3, 2, 1, NODIR, CLR_CYAN), SPELL("cause fear", "light blue", P_ENCHANTMENT_SPELL, 25, 3, 3, 1, NODIR, CLR_BRIGHT_BLUE), SPELL("clairvoyance", "dark blue", P_DIVINATION_SPELL, 15, 3, 3, 1, NODIR, CLR_BLUE), SPELL("cure sickness", "indigo", P_HEALING_SPELL, 32, 3, 3, 1, NODIR, CLR_BLUE), SPELL("charm monster", "magenta", P_ENCHANTMENT_SPELL, 20, 3, 3, 1, IMMEDIATE, CLR_MAGENTA), SPELL("haste self", "purple", P_ESCAPE_SPELL, 33, 4, 3, 1, NODIR, CLR_MAGENTA), SPELL("detect unseen", "violet", P_DIVINATION_SPELL, 20, 4, 3, 1, NODIR, CLR_MAGENTA), SPELL("levitation", "tan", P_ESCAPE_SPELL, 20, 4, 4, 1, NODIR, CLR_BROWN), SPELL("extra healing", "plaid", P_HEALING_SPELL, 27, 5, 3, 1, IMMEDIATE, CLR_GREEN), SPELL("restore ability", "light brown", P_HEALING_SPELL, 25, 5, 4, 1, NODIR, CLR_BROWN), SPELL("invisibility", "dark brown", P_ESCAPE_SPELL, 25, 5, 4, 1, NODIR, CLR_BROWN), SPELL("detect treasure", "gray", P_DIVINATION_SPELL, 20, 5, 4, 1, NODIR, CLR_GRAY), SPELL("remove curse", "wrinkled", P_CLERIC_SPELL, 25, 5, 3, 1, NODIR, HI_PAPER), SPELL("magic mapping", "dusty", P_DIVINATION_SPELL, 18, 7, 5, 1, NODIR, HI_PAPER), SPELL("identify", "bronze", P_DIVINATION_SPELL, 20, 6, 3, 1, NODIR, HI_COPPER), SPELL("turn undead", "copper", P_CLERIC_SPELL, 16, 8, 6, 1, IMMEDIATE, HI_COPPER), SPELL("polymorph", "silver", P_MATTER_SPELL, 10, 8, 6, 1, IMMEDIATE, HI_SILVER), SPELL("teleport away", "gold", P_ESCAPE_SPELL, 15, 6, 6, 1, IMMEDIATE, HI_GOLD), SPELL("create familiar", "glittering", P_CLERIC_SPELL, 10, 7, 6, 1, NODIR, CLR_WHITE), SPELL("cancellation", "shining", P_MATTER_SPELL, 15, 8, 7, 1, IMMEDIATE, CLR_WHITE), SPELL("protection", "dull", P_CLERIC_SPELL, 18, 3, 1, 1, NODIR, HI_PAPER), SPELL("jumping", "thin", P_ESCAPE_SPELL, 20, 3, 1, 1, IMMEDIATE, HI_PAPER), SPELL("stone to flesh", "thick", P_HEALING_SPELL, 15, 1, 3, 1, IMMEDIATE, HI_PAPER), #if 0 /* DEFERRED */ /* from slash'em, create a tame critter which explodes when attacking, damaging adjacent creatures--friend or foe--and dying in the process */ SPELL("flame sphere", "canvas", P_MATTER_SPELL, 20, 2, 1, 1, NODIR, CLR_BROWN), SPELL("freeze sphere", "hardcover", P_MATTER_SPELL, 20, 2, 1, 1, NODIR, CLR_BROWN), #endif /* books with fixed descriptions */ SPELL("blank paper", "plain", P_NONE, 18, 0, 0, 0, 0, HI_PAPER), /* tribute book for 3.6 */ OBJECT(OBJ("novel", "paperback"), BITS(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, P_NONE, HI_PAPER), 0, SPBOOK_CLASS, 0, 0, 0, 20, 0, 0, 0, 1, 20, CLR_BRIGHT_BLUE), /* a special, one of a kind, spellbook */ OBJECT(OBJ("Book of the Dead", "papyrus"), BITS(0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, P_NONE, PAPER), 0, SPBOOK_CLASS, 0, 0, 20, 10000, 0, 0, 0, 7, 20, HI_PAPER), #undef SPELL /* wands ... */ #define WAND(name,typ,prob,cost,mgc,dir,metal,color) \ OBJECT(OBJ(name, typ), \ BITS(0, 0, 1, 0, mgc, 1, 0, 0, 0, 0, dir, P_NONE, metal), \ 0, WAND_CLASS, prob, 0, 7, cost, 0, 0, 0, 0, 30, color) WAND("light", "glass", 95, 100, 1, NODIR, GLASS, HI_GLASS), WAND("secret door detection", "balsa", 50, 150, 1, NODIR, WOOD, HI_WOOD), WAND("enlightenment", "crystal", 15, 150, 1, NODIR, GLASS, HI_GLASS), WAND("create monster", "maple", 45, 200, 1, NODIR, WOOD, HI_WOOD), WAND("wishing", "pine", 5, 500, 1, NODIR, WOOD, HI_WOOD), WAND("nothing", "oak", 25, 100, 0, IMMEDIATE, WOOD, HI_WOOD), WAND("striking", "ebony", 75, 150, 1, IMMEDIATE, WOOD, HI_WOOD), WAND("make invisible", "marble", 45, 150, 1, IMMEDIATE, MINERAL, HI_MINERAL), WAND("slow monster", "tin", 50, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("speed monster", "brass", 50, 150, 1, IMMEDIATE, COPPER, HI_COPPER), WAND("undead turning", "copper", 50, 150, 1, IMMEDIATE, COPPER, HI_COPPER), WAND("polymorph", "silver", 45, 200, 1, IMMEDIATE, SILVER, HI_SILVER), WAND("cancellation", "platinum", 45, 200, 1, IMMEDIATE, PLATINUM, CLR_WHITE), WAND("teleportation", "iridium", 45, 200, 1, IMMEDIATE, METAL, CLR_BRIGHT_CYAN), WAND("opening", "zinc", 25, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("locking", "aluminum", 25, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("probing", "uranium", 30, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("digging", "iron", 55, 150, 1, RAY, IRON, HI_METAL), WAND("magic missile", "steel", 50, 150, 1, RAY, IRON, HI_METAL), WAND("fire", "hexagonal", 40, 175, 1, RAY, IRON, HI_METAL), WAND("cold", "short", 40, 175, 1, RAY, IRON, HI_METAL), WAND("sleep", "runed", 50, 175, 1, RAY, IRON, HI_METAL), WAND("death", "long", 5, 500, 1, RAY, IRON, HI_METAL), WAND("lightning", "curved", 40, 175, 1, RAY, IRON, HI_METAL), /* extra descriptions, shuffled into use at start of new game */ WAND(None, "forked", 0, 150, 1, 0, WOOD, HI_WOOD), WAND(None, "spiked", 0, 150, 1, 0, IRON, HI_METAL), WAND(None, "jeweled", 0, 150, 1, 0, IRON, HI_MINERAL), #undef WAND /* coins ... - so far, gold is all there is */ #define COIN(name,prob,metal,worth) \ OBJECT(OBJ(name, None), \ BITS(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, P_NONE, metal), \ 0, COIN_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD) COIN("gold piece", 1000, GOLD, 1), #undef COIN /* gems ... - includes stones and rocks but not boulders */ #define GEM(name,desc,prob,wt,gval,nutr,mohs,glass,color) \ OBJECT(OBJ(name, desc), \ BITS(0, 1, 0, 0, 0, 0, 0, 0, 0, \ HARDGEM(mohs), 0, -P_SLING, glass), \ 0, GEM_CLASS, prob, 0, 1, gval, 3, 3, 0, 0, nutr, color) #define ROCK(name,desc,kn,prob,wt,gval,sdam,ldam,mgc,nutr,mohs,glass,color) \ OBJECT(OBJ(name, desc), \ BITS(kn, 1, 0, 0, mgc, 0, 0, 0, 0, \ HARDGEM(mohs), 0, -P_SLING, glass), \ 0, GEM_CLASS, prob, 0, wt, gval, sdam, ldam, 0, 0, nutr, color) GEM("dilithium crystal", "white", 2, 1, 4500, 15, 5, GEMSTONE, CLR_WHITE), GEM("diamond", "white", 3, 1, 4000, 15, 10, GEMSTONE, CLR_WHITE), GEM("ruby", "red", 4, 1, 3500, 15, 9, GEMSTONE, CLR_RED), GEM("jacinth", "orange", 3, 1, 3250, 15, 9, GEMSTONE, CLR_ORANGE), GEM("sapphire", "blue", 4, 1, 3000, 15, 9, GEMSTONE, CLR_BLUE), GEM("black opal", "black", 3, 1, 2500, 15, 8, GEMSTONE, CLR_BLACK), GEM("emerald", "green", 5, 1, 2500, 15, 8, GEMSTONE, CLR_GREEN), GEM("turquoise", "green", 6, 1, 2000, 15, 6, GEMSTONE, CLR_GREEN), GEM("citrine", "yellow", 4, 1, 1500, 15, 6, GEMSTONE, CLR_YELLOW), GEM("aquamarine", "green", 6, 1, 1500, 15, 8, GEMSTONE, CLR_GREEN), GEM("amber", "yellowish brown", 8, 1, 1000, 15, 2, GEMSTONE, CLR_BROWN), GEM("topaz", "yellowish brown", 10, 1, 900, 15, 8, GEMSTONE, CLR_BROWN), GEM("jet", "black", 6, 1, 850, 15, 7, GEMSTONE, CLR_BLACK), GEM("opal", "white", 12, 1, 800, 15, 6, GEMSTONE, CLR_WHITE), GEM("chrysoberyl", "yellow", 8, 1, 700, 15, 5, GEMSTONE, CLR_YELLOW), GEM("garnet", "red", 12, 1, 700, 15, 7, GEMSTONE, CLR_RED), GEM("amethyst", "violet", 14, 1, 600, 15, 7, GEMSTONE, CLR_MAGENTA), GEM("jasper", "red", 15, 1, 500, 15, 7, GEMSTONE, CLR_RED), GEM("fluorite", "violet", 15, 1, 400, 15, 4, GEMSTONE, CLR_MAGENTA), GEM("obsidian", "black", 9, 1, 200, 15, 6, GEMSTONE, CLR_BLACK), GEM("agate", "orange", 12, 1, 200, 15, 6, GEMSTONE, CLR_ORANGE), GEM("jade", "green", 10, 1, 300, 15, 6, GEMSTONE, CLR_GREEN), GEM("worthless piece of white glass", "white", 77, 1, 0, 6, 5, GLASS, CLR_WHITE), GEM("worthless piece of blue glass", "blue", 77, 1, 0, 6, 5, GLASS, CLR_BLUE), GEM("worthless piece of red glass", "red", 77, 1, 0, 6, 5, GLASS, CLR_RED), GEM("worthless piece of yellowish brown glass", "yellowish brown", 77, 1, 0, 6, 5, GLASS, CLR_BROWN), GEM("worthless piece of orange glass", "orange", 76, 1, 0, 6, 5, GLASS, CLR_ORANGE), GEM("worthless piece of yellow glass", "yellow", 77, 1, 0, 6, 5, GLASS, CLR_YELLOW), GEM("worthless piece of black glass", "black", 76, 1, 0, 6, 5, GLASS, CLR_BLACK), GEM("worthless piece of green glass", "green", 77, 1, 0, 6, 5, GLASS, CLR_GREEN), GEM("worthless piece of violet glass", "violet", 77, 1, 0, 6, 5, GLASS, CLR_MAGENTA), /* Placement note: there is a wishable subrange for * "gray stones" in the o_ranges[] array in objnam.c * that is currently everything between luckstones and flint * (inclusive). */ ROCK("luckstone", "gray", 0, 10, 10, 60, 3, 3, 1, 10, 7, MINERAL, CLR_GRAY), ROCK("loadstone", "gray", 0, 10, 500, 1, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY), ROCK("touchstone", "gray", 0, 8, 10, 45, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY), ROCK("flint", "gray", 0, 10, 10, 1, 6, 6, 0, 10, 7, MINERAL, CLR_GRAY), ROCK("rock", None, 1, 100, 10, 0, 3, 3, 0, 10, 7, MINERAL, CLR_GRAY), #undef GEM #undef ROCK /* miscellaneous ... */ /* Note: boulders and rocks are not normally created at random; the * probabilities only come into effect when you try to polymorph them. * Boulders weigh more than MAX_CARR_CAP; statues use corpsenm to take * on a specific type and may act as containers (both affect weight). */ OBJECT(OBJ("boulder", None), BITS(1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, P_NONE, MINERAL), 0, ROCK_CLASS, 100, 0, 6000, 0, 20, 20, 0, 0, 2000, HI_MINERAL), OBJECT(OBJ("statue", None), BITS(1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, P_NONE, MINERAL), 0, ROCK_CLASS, 900, 0, 2500, 0, 20, 20, 0, 0, 2500, CLR_WHITE), OBJECT(OBJ("heavy iron ball", None), BITS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, WHACK, P_NONE, IRON), 0, BALL_CLASS, 1000, 0, 480, 10, 25, 25, 0, 0, 200, HI_METAL), /* +d4 when "very heavy" */ OBJECT(OBJ("iron chain", None), BITS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, WHACK, P_NONE, IRON), 0, CHAIN_CLASS, 1000, 0, 120, 0, 4, 4, 0, 0, 200, HI_METAL), /* +1 both l & s */ /* Venom is normally a transitory missile (spit by various creatures) * but can be wished for in wizard mode so could occur in bones data. */ OBJECT(OBJ("blinding venom", "splash of venom"), BITS(0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, P_NONE, LIQUID), 0, VENOM_CLASS, 500, 0, 1, 0, 0, 0, 0, 0, 0, HI_ORGANIC), OBJECT(OBJ("acid venom", "splash of venom"), BITS(0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, P_NONE, LIQUID), 0, VENOM_CLASS, 500, 0, 1, 0, 6, 6, 0, 0, 0, HI_ORGANIC), /* +d6 small or large */ /* fencepost, the deadly Array Terminator -- name [1st arg] *must* be NULL */ OBJECT(OBJ(None, None), BITS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, P_NONE, 0), 0, ILLOBJ_CLASS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }; /* objects[] */ #ifndef OBJECTS_PASS_2_ /* perform recursive compilation for second structure */ #undef OBJ #undef OBJECT #define OBJECTS_PASS_2_ #include "objects.c" /* clang-format on */ /* *INDENT-ON* */ void NDECL(objects_init); /* dummy routine used to force linkage */ void objects_init() { return; } #endif /* !OBJECTS_PASS_2_ */ /*objects.c*/ nethack-3.6.0/src/objnam.c0000664000076400007660000036206212623064115014347 0ustar paxedpaxed/* NetHack 3.6 objnam.c $NHDT-Date: 1447490776 2015/11/14 08:46:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.154 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */ #define PREFIX 80 /* (56) */ #define SCHAR_LIM 127 #define NUMOBUF 12 STATIC_DCL char *FDECL(strprepend, (char *, const char *)); STATIC_DCL short FDECL(rnd_otyp_by_wpnskill, (SCHAR_P)); STATIC_DCL boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P)); STATIC_DCL char *NDECL(nextobuf); STATIC_DCL void FDECL(releaseobuf, (char *)); STATIC_DCL char *FDECL(minimal_xname, (struct obj *)); STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *)); STATIC_DCL boolean FDECL(singplur_lookup, (char *, char *, BOOLEAN_P, const char *const *)); STATIC_DCL char *FDECL(singplur_compound, (char *)); STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned)); struct Jitem { int item; const char *name; }; #define BSTRCMPI(base, ptr, str) ((ptr) < base || strcmpi((ptr), str)) #define BSTRNCMPI(base, ptr, str, num) \ ((ptr) < base || strncmpi((ptr), str, num)) #define Strcasecpy(dst, src) (void) strcasecpy(dst, src) /* true for gems/rocks that should have " stone" appended to their names */ #define GemStone(typ) \ (typ == FLINT \ || (objects[typ].oc_material == GEMSTONE \ && (typ != DILITHIUM_CRYSTAL && typ != RUBY && typ != DIAMOND \ && typ != SAPPHIRE && typ != BLACK_OPAL && typ != EMERALD \ && typ != OPAL))) STATIC_OVL struct Jitem Japanese_items[] = { { SHORT_SWORD, "wakizashi" }, { BROADSWORD, "ninja-to" }, { FLAIL, "nunchaku" }, { GLAIVE, "naginata" }, { LOCK_PICK, "osaku" }, { WOODEN_HARP, "koto" }, { KNIFE, "shito" }, { PLATE_MAIL, "tanko" }, { HELMET, "kabuto" }, { LEATHER_GLOVES, "yugake" }, { FOOD_RATION, "gunyoki" }, { POT_BOOZE, "sake" }, { 0, "" } }; STATIC_DCL const char *FDECL(Japanese_item_name, (int i)); STATIC_OVL char * strprepend(s, pref) register char *s; register const char *pref; { register int i = (int) strlen(pref); if (i > PREFIX) { impossible("PREFIX too short (for %d).", i); return s; } s -= i; (void) strncpy(s, pref, i); /* do not copy trailing 0 */ return s; } /* manage a pool of BUFSZ buffers, so callers don't have to */ static char NEARDATA obufs[NUMOBUF][BUFSZ]; static int obufidx = 0; STATIC_OVL char * nextobuf() { obufidx = (obufidx + 1) % NUMOBUF; return obufs[obufidx]; } /* put the most recently allocated buffer back if possible */ STATIC_OVL void releaseobuf(bufp) char *bufp; { /* caller may not know whether bufp is the most recently allocated buffer; if it isn't, do nothing */ if (bufp == obufs[obufidx]) obufidx = (obufidx - 1 + NUMOBUF) % NUMOBUF; } char * obj_typename(otyp) register int otyp; { char *buf = nextobuf(); register struct objclass *ocl = &objects[otyp]; register const char *actualn = OBJ_NAME(*ocl); register const char *dn = OBJ_DESCR(*ocl); register const char *un = ocl->oc_uname; register int nn = ocl->oc_name_known; if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp)) actualn = Japanese_item_name(otyp); switch (ocl->oc_class) { case COIN_CLASS: Strcpy(buf, "coin"); break; case POTION_CLASS: Strcpy(buf, "potion"); break; case SCROLL_CLASS: Strcpy(buf, "scroll"); break; case WAND_CLASS: Strcpy(buf, "wand"); break; case SPBOOK_CLASS: Strcpy(buf, "spellbook"); break; case RING_CLASS: Strcpy(buf, "ring"); break; case AMULET_CLASS: if (nn) Strcpy(buf, actualn); else Strcpy(buf, "amulet"); if (un) Sprintf(eos(buf), " called %s", un); if (dn) Sprintf(eos(buf), " (%s)", dn); return buf; default: if (nn) { Strcpy(buf, actualn); if (GemStone(otyp)) Strcat(buf, " stone"); if (un) Sprintf(eos(buf), " called %s", un); if (dn) Sprintf(eos(buf), " (%s)", dn); } else { Strcpy(buf, dn ? dn : actualn); if (ocl->oc_class == GEM_CLASS) Strcat(buf, (ocl->oc_material == MINERAL) ? " stone" : " gem"); if (un) Sprintf(eos(buf), " called %s", un); } return buf; } /* here for ring/scroll/potion/wand */ if (nn) { if (ocl->oc_unique) Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */ else Sprintf(eos(buf), " of %s", actualn); } if (un) Sprintf(eos(buf), " called %s", un); if (dn) Sprintf(eos(buf), " (%s)", dn); return buf; } /* less verbose result than obj_typename(); either the actual name or the description (but not both); user-assigned name is ignored */ char * simple_typename(otyp) int otyp; { char *bufp, *pp, *save_uname = objects[otyp].oc_uname; objects[otyp].oc_uname = 0; /* suppress any name given by user */ bufp = obj_typename(otyp); objects[otyp].oc_uname = save_uname; if ((pp = strstri(bufp, " (")) != 0) *pp = '\0'; /* strip the appended description */ return bufp; } boolean obj_is_pname(obj) struct obj *obj; { if (!obj->oartifact || !has_oname(obj)) return FALSE; if (!program_state.gameover && !iflags.override_ID) { if (not_fully_identified(obj)) return FALSE; } return TRUE; } /* Give the name of an object seen at a distance. Unlike xname/doname, * we don't want to set dknown if it's not set already. The kludge used is * to temporarily set Blind so that xname() skips the dknown setting. This * assumes that we don't want to do this too often; if this function becomes * frequently used, it'd probably be better to pass a parameter to xname() * or doname() instead. */ char * distant_name(obj, func) struct obj *obj; char *FDECL((*func), (OBJ_P)); { char *str; long save_Blinded = Blinded; Blinded = 1; str = (*func)(obj); Blinded = save_Blinded; return str; } /* convert player specified fruit name into corresponding fruit juice name ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */ char * fruitname(juice) boolean juice; /* whether or not to append " juice" to the name */ { char *buf = nextobuf(); const char *fruit_nam = strstri(pl_fruit, " of "); if (fruit_nam) fruit_nam += 4; /* skip past " of " */ else fruit_nam = pl_fruit; /* use it as is */ Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : ""); return buf; } char * xname(obj) struct obj *obj; { return xname_flags(obj, CXN_NORMAL); } char * xname_flags(obj, cxn_flags) register struct obj *obj; unsigned cxn_flags; /* bitmask of CXN_xxx values */ { register char *buf; register int typ = obj->otyp; register struct objclass *ocl = &objects[typ]; int nn = ocl->oc_name_known, omndx = obj->corpsenm; const char *actualn = OBJ_NAME(*ocl); const char *dn = OBJ_DESCR(*ocl); const char *un = ocl->oc_uname; boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR); boolean known, dknown, bknown; buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) actualn = Japanese_item_name(typ); buf[0] = '\0'; /* * clean up known when it's tied to oc_name_known, eg after AD_DRIN * This is only required for unique objects since the article * printed for the object is tied to the combination of the two * and printing the wrong article gives away information. */ if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; if (!Blind) obj->dknown = TRUE; if (Role_if(PM_PRIEST)) obj->bknown = TRUE; if (iflags.override_ID) { known = dknown = bknown = TRUE; nn = 1; } else { known = obj->known; dknown = obj->dknown; bknown = obj->bknown; } if (obj_is_pname(obj)) goto nameit; switch (obj->oclass) { case AMULET_CLASS: if (!dknown) Strcpy(buf, "amulet"); else if (typ == AMULET_OF_YENDOR || typ == FAKE_AMULET_OF_YENDOR) /* each must be identified individually */ Strcpy(buf, known ? actualn : dn); else if (nn) Strcpy(buf, actualn); else if (un) Sprintf(buf, "amulet called %s", un); else Sprintf(buf, "%s amulet", dn); break; case WEAPON_CLASS: if (is_poisonable(obj) && obj->opoisoned) Strcpy(buf, "poisoned "); case VENOM_CLASS: case TOOL_CLASS: if (typ == LENSES) Strcpy(buf, "pair of "); else if (is_wet_towel(obj)) Strcpy(buf, (obj->spe < 3) ? "moist " : "wet "); if (!dknown) Strcat(buf, dn ? dn : actualn); else if (nn) Strcat(buf, actualn); else if (un) { Strcat(buf, dn ? dn : actualn); Strcat(buf, " called "); Strcat(buf, un); } else Strcat(buf, dn ? dn : actualn); /* If we use an() here we'd have to remember never to use */ /* it whenever calling doname() or xname(). */ if (typ == FIGURINE && omndx != NON_PM) { Sprintf(eos(buf), " of a%s %s", index(vowels, *mons[omndx].mname) ? "n" : "", mons[omndx].mname); } else if (is_wet_towel(obj)) { if (wizard) Sprintf(eos(buf), " (%d)", obj->spe); } break; case ARMOR_CLASS: /* depends on order of the dragon scales objects */ if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) { Sprintf(buf, "set of %s", actualn); break; } if (is_boots(obj) || is_gloves(obj)) Strcpy(buf, "pair of "); if (obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD && !dknown) { Strcpy(buf, "shield"); break; } if (obj->otyp == SHIELD_OF_REFLECTION && !dknown) { Strcpy(buf, "smooth shield"); break; } if (nn) Strcat(buf, actualn); else if (un) { if (is_boots(obj)) Strcat(buf, "boots"); else if (is_gloves(obj)) Strcat(buf, "gloves"); else if (is_cloak(obj)) Strcpy(buf, "cloak"); else if (is_helmet(obj)) Strcpy(buf, "helmet"); else if (is_shield(obj)) Strcpy(buf, "shield"); else Strcpy(buf, "armor"); Strcat(buf, " called "); Strcat(buf, un); } else Strcat(buf, dn); break; case FOOD_CLASS: if (typ == SLIME_MOLD) { register struct fruit *f; for (f = ffruit; f; f = f->nextf) { if (f->fid == obj->spe) { Strcpy(buf, f->fname); break; } } if (!f) { impossible("Bad fruit #%d?", obj->spe); Strcpy(buf, "fruit"); } else if (pluralize) { /* ick; already pluralized fruit names are allowed--we want to try to avoid adding a redundant plural suffix */ Strcpy(buf, makeplural(makesingular(buf))); pluralize = FALSE; } break; } if (Is_pudding(obj)) { Sprintf(buf, "%s%s", (obj->owt < 100) ? "small " : (obj->owt > 500) ? "very large " : (obj->owt > 300) ? "large " : "", actualn); break; } Strcpy(buf, actualn); if (typ == TIN && known) tin_details(obj, omndx, buf); break; case COIN_CLASS: case CHAIN_CLASS: Strcpy(buf, actualn); break; case ROCK_CLASS: if (typ == STATUE && omndx != NON_PM) Sprintf(buf, "%s%s of %s%s", (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) ? "historic " : "", actualn, type_is_pname(&mons[omndx]) ? "" : the_unique_pm(&mons[omndx]) ? "the " : index(vowels, *mons[omndx].mname) ? "an " : "a ", mons[omndx].mname); else Strcpy(buf, actualn); break; case BALL_CLASS: Sprintf(buf, "%sheavy iron ball", (obj->owt > ocl->oc_weight) ? "very " : ""); break; case POTION_CLASS: if (dknown && obj->odiluted) Strcpy(buf, "diluted "); if (nn || un || !dknown) { Strcat(buf, "potion"); if (!dknown) break; if (nn) { Strcat(buf, " of "); if (typ == POT_WATER && bknown && (obj->blessed || obj->cursed)) { Strcat(buf, obj->blessed ? "holy " : "unholy "); } Strcat(buf, actualn); } else { Strcat(buf, " called "); Strcat(buf, un); } } else { Strcat(buf, dn); Strcat(buf, " potion"); } break; case SCROLL_CLASS: Strcpy(buf, "scroll"); if (!dknown) break; if (nn) { Strcat(buf, " of "); Strcat(buf, actualn); } else if (un) { Strcat(buf, " called "); Strcat(buf, un); } else if (ocl->oc_magic) { Strcat(buf, " labeled "); Strcat(buf, dn); } else { Strcpy(buf, dn); Strcat(buf, " scroll"); } break; case WAND_CLASS: if (!dknown) Strcpy(buf, "wand"); else if (nn) Sprintf(buf, "wand of %s", actualn); else if (un) Sprintf(buf, "wand called %s", un); else Sprintf(buf, "%s wand", dn); break; case SPBOOK_CLASS: if (typ == SPE_NOVEL) { /* 3.6 tribute */ if (!dknown) Strcpy(buf, "book"); else if (nn) Strcpy(buf, actualn); else if (un) Sprintf(buf, "novel called %s", un); else Sprintf(buf, "%s book", dn); break; /* end of tribute */ } else if (!dknown) { Strcpy(buf, "spellbook"); } else if (nn) { if (typ != SPE_BOOK_OF_THE_DEAD) Strcpy(buf, "spellbook of "); Strcat(buf, actualn); } else if (un) { Sprintf(buf, "spellbook called %s", un); } else Sprintf(buf, "%s spellbook", dn); break; case RING_CLASS: if (!dknown) Strcpy(buf, "ring"); else if (nn) Sprintf(buf, "ring of %s", actualn); else if (un) Sprintf(buf, "ring called %s", un); else Sprintf(buf, "%s ring", dn); break; case GEM_CLASS: { const char *rock = (ocl->oc_material == MINERAL) ? "stone" : "gem"; if (!dknown) { Strcpy(buf, rock); } else if (!nn) { if (un) Sprintf(buf, "%s called %s", rock, un); else Sprintf(buf, "%s %s", dn, rock); } else { Strcpy(buf, actualn); if (GemStone(typ)) Strcat(buf, " stone"); } break; } default: Sprintf(buf, "glorkum %d %d %d", obj->oclass, typ, obj->spe); } if (pluralize) Strcpy(buf, makeplural(buf)); if (obj->otyp == T_SHIRT && program_state.gameover) { char tmpbuf[BUFSZ]; Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf)); } if (has_oname(obj) && dknown) { Strcat(buf, " named "); nameit: Strcat(buf, ONAME(obj)); } if (!strncmpi(buf, "the ", 4)) buf += 4; return buf; } /* similar to simple_typename but minimal_xname operates on a particular object rather than its general type; it formats the most basic info: potion -- if description not known brown potion -- if oc_name_known not set potion of object detection -- if discovered */ static char * minimal_xname(obj) struct obj *obj; { char *bufp; struct obj bareobj; struct objclass saveobcls; int otyp = obj->otyp; /* suppress user-supplied name */ saveobcls.oc_uname = objects[otyp].oc_uname; objects[otyp].oc_uname = 0; /* suppress actual name if object's description is unknown */ saveobcls.oc_name_known = objects[otyp].oc_name_known; if (!obj->dknown) objects[otyp].oc_name_known = 0; /* caveat: this makes a lot of assumptions about which fields are required in order for xname() to yield a sensible result */ bareobj = zeroobj; bareobj.otyp = otyp; bareobj.oclass = obj->oclass; bareobj.dknown = obj->dknown; /* suppress known except for amulets (needed for fakes and real A-of-Y) */ bareobj.known = (obj->oclass == AMULET_CLASS) ? obj->known /* default is "on" for types which don't use it */ : !objects[otyp].oc_uses_known; bareobj.quan = 1L; /* don't want plural */ bareobj.corpsenm = NON_PM; /* suppress statue and figurine details */ /* but suppressing fruit details leads to "bad fruit #0" [perhaps we should force "slime mold" rather than use xname?] */ if (obj->otyp == SLIME_MOLD) bareobj.spe = obj->spe; bufp = distant_name(&bareobj, xname); /* xname(&bareobj) */ if (!strncmp(bufp, "uncursed ", 9)) bufp += 9; /* Role_if(PM_PRIEST) */ objects[otyp].oc_uname = saveobcls.oc_uname; objects[otyp].oc_name_known = saveobcls.oc_name_known; return bufp; } /* xname() output augmented for multishot missile feedback */ char * mshot_xname(obj) struct obj *obj; { char tmpbuf[BUFSZ]; char *onm = xname(obj); if (m_shot.n > 1 && m_shot.o == obj->otyp) { /* "the Nth arrow"; value will eventually be passed to an() or The(), both of which correctly handle this "the " prefix */ Sprintf(tmpbuf, "the %d%s ", m_shot.i, ordin(m_shot.i)); onm = strprepend(onm, tmpbuf); } return onm; } /* used for naming "the unique_item" instead of "a unique_item" */ boolean the_unique_obj(obj) struct obj *obj; { boolean known = (obj->known || iflags.override_ID); if (!obj->dknown && !iflags.override_ID) return FALSE; else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !known) return TRUE; /* lie */ else return (boolean) (objects[obj->otyp].oc_unique && (known || obj->otyp == AMULET_OF_YENDOR)); } /* should monster type be prefixed with "the"? (mostly used for corpses) */ boolean the_unique_pm(ptr) struct permonst *ptr; { boolean uniq; /* even though monsters with personal names are unique, we want to describe them as "Name" rather than "the Name" */ if (type_is_pname(ptr)) return FALSE; uniq = (ptr->geno & G_UNIQ) ? TRUE : FALSE; /* high priest is unique if it includes "of ", otherwise not (caller needs to handle the 1st possibility; we assume the 2nd); worm tail should be irrelevant but is included for completeness */ if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL]) uniq = FALSE; /* Wizard no longer needs this; he's flagged as unique these days */ if (ptr == &mons[PM_WIZARD_OF_YENDOR]) uniq = TRUE; return uniq; } STATIC_OVL void add_erosion_words(obj, prefix) struct obj *obj; char *prefix; { boolean iscrys = (obj->otyp == CRYSKNIFE); boolean rknown; rknown = (iflags.override_ID == 0) ? obj->rknown : TRUE; if (!is_damageable(obj) && !iscrys) return; /* The only cases where any of these bits do double duty are for * rotted food and diluted potions, which are all not is_damageable(). */ if (obj->oeroded && !iscrys) { switch (obj->oeroded) { case 2: Strcat(prefix, "very "); break; case 3: Strcat(prefix, "thoroughly "); break; } Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt "); } if (obj->oeroded2 && !iscrys) { switch (obj->oeroded2) { case 2: Strcat(prefix, "very "); break; case 3: Strcat(prefix, "thoroughly "); break; } Strcat(prefix, is_corrodeable(obj) ? "corroded " : "rotted "); } if (rknown && obj->oerodeproof) Strcat(prefix, iscrys ? "fixed " : is_rustprone(obj) ? "rustproof " : is_corrodeable(obj) ? "corrodeproof " /* "stainless"? */ : is_flammable(obj) ? "fireproof " : ""); } static char * doname_base(obj, with_price) register struct obj *obj; boolean with_price; { boolean ispoisoned = FALSE; boolean known, cknown, bknown, lknown; int omndx = obj->corpsenm; char prefix[PREFIX]; char tmpbuf[PREFIX + 1]; /* for when we have to add something at the start of prefix instead of the end (Strcat is used on the end) */ register char *bp = xname(obj); if (iflags.override_ID) { known = cknown = bknown = lknown = TRUE; } else { known = obj->known; cknown = obj->cknown; bknown = obj->bknown; lknown = obj->lknown; } /* When using xname, we want "poisoned arrow", and when using * doname, we want "poisoned +0 arrow". This kludge is about the only * way to do it, at least until someone overhauls xname() and doname(), * combining both into one function taking a parameter. */ /* must check opoisoned--someone can have a weirdly-named fruit */ if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) { bp += 9; ispoisoned = TRUE; } if (obj->quan != 1L) { Sprintf(prefix, "%ld ", obj->quan); } else if (obj->otyp == CORPSE) { /* skip article prefix for corpses [else corpse_xname() would have to be taught how to strip it off again] */ *prefix = '\0'; } else if (obj_is_pname(obj) || the_unique_obj(obj)) { if (!strncmpi(bp, "the ", 4)) bp += 4; Strcpy(prefix, "the "); } else { Strcpy(prefix, "a "); } /* "empty" goes at the beginning, but item count goes at the end */ if (cknown /* bag of tricks: include "empty" prefix if it's known to be empty but its precise number of charges isn't known (when that is known, suffix of "(n:0)" will be appended, making the prefix be redundant; note that 'known' flag isn't set when emptiness gets discovered because then charging magic would yield known number of new charges) */ && (obj->otyp == BAG_OF_TRICKS ? (obj->spe == 0 && !obj->known) /* not bag of tricks: empty if container which has no contents */ : (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj))) Strcat(prefix, "empty "); if (bknown && obj->oclass != COIN_CLASS && (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known || (!obj->cursed && !obj->blessed))) { /* allow 'blessed clear potion' if we don't know it's holy water; * always allow "uncursed potion of water" */ if (obj->cursed) Strcat(prefix, "cursed "); else if (obj->blessed) Strcat(prefix, "blessed "); else if (!iflags.implicit_uncursed /* For most items with charges or +/-, if you know how many * charges are left or what the +/- is, then you must have * totally identified the item, so "uncursed" is unnecessary, * because an identified object not described as "blessed" or * "cursed" must be uncursed. * * If the charges or +/- is not known, "uncursed" must be * printed to avoid ambiguity between an item whose curse * status is unknown, and an item known to be uncursed. */ || ((!known || !objects[obj->otyp].oc_charged || obj->oclass == ARMOR_CLASS || obj->oclass == RING_CLASS) #ifdef MAIL && obj->otyp != SCR_MAIL #endif && obj->otyp != FAKE_AMULET_OF_YENDOR && obj->otyp != AMULET_OF_YENDOR && !Role_if(PM_PRIEST))) Strcat(prefix, "uncursed "); } if (lknown && Is_box(obj)) { if (obj->obroken) Strcat(prefix, "unlockable "); else if (obj->olocked) Strcat(prefix, "locked "); else Strcat(prefix, "unlocked "); } if (obj->greased) Strcat(prefix, "greased "); if (cknown && Has_contents(obj)) { /* we count all objects (obj->quantity); perhaps we should count separate stacks instead (or even introduce a user preference option to choose between the two alternatives) since it's somewhat odd so see "containing 1002 items" when there are 2 scrolls plus 1000 gold pieces */ long itemcount = count_contents(obj, FALSE, FALSE, TRUE); Sprintf(eos(bp), " containing %ld item%s", itemcount, plur(itemcount)); } switch (obj->oclass) { case AMULET_CLASS: if (obj->owornmask & W_AMUL) Strcat(bp, " (being worn)"); break; case WEAPON_CLASS: if (ispoisoned) Strcat(prefix, "poisoned "); plus: add_erosion_words(obj, prefix); if (known) { Strcat(prefix, sitoa(obj->spe)); Strcat(prefix, " "); } break; case ARMOR_CLASS: if (obj->owornmask & W_ARMOR) Strcat(bp, (obj == uskin) ? " (embedded in your skin)" : " (being worn)"); goto plus; case TOOL_CLASS: /* weptools already get this done when we go to the +n code */ if (!is_weptool(obj)) add_erosion_words(obj, prefix); if (obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) { Strcat(bp, " (being worn)"); break; } if (obj->otyp == LEASH && obj->leashmon != 0) { Strcat(bp, " (in use)"); break; } if (is_weptool(obj)) goto plus; if (obj->otyp == CANDELABRUM_OF_INVOCATION) { if (!obj->spe) Strcpy(tmpbuf, "no"); else Sprintf(tmpbuf, "%d", obj->spe); Sprintf(eos(bp), " (%s candle%s%s)", tmpbuf, plur(obj->spe), !obj->lamplit ? " attached" : ", lit"); break; } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN || Is_candle(obj)) { if (Is_candle(obj) && obj->age < 20L * (long) objects[obj->otyp].oc_cost) Strcat(prefix, "partly used "); if (obj->lamplit) Strcat(bp, " (lit)"); break; } if (objects[obj->otyp].oc_charged) goto charges; break; case WAND_CLASS: add_erosion_words(obj, prefix); charges: if (known) Sprintf(eos(bp), " (%d:%d)", (int) obj->recharged, obj->spe); break; case POTION_CLASS: if (obj->otyp == POT_OIL && obj->lamplit) Strcat(bp, " (lit)"); break; case RING_CLASS: add_erosion_words(obj, prefix); ring: if (obj->owornmask & W_RINGR) Strcat(bp, " (on right "); if (obj->owornmask & W_RINGL) Strcat(bp, " (on left "); if (obj->owornmask & W_RING) { Strcat(bp, body_part(HAND)); Strcat(bp, ")"); } if (known && objects[obj->otyp].oc_charged) { Strcat(prefix, sitoa(obj->spe)); Strcat(prefix, " "); } break; case FOOD_CLASS: if (obj->oeaten) Strcat(prefix, "partly eaten "); if (obj->otyp == CORPSE) { Sprintf(prefix, "%s ", corpse_xname(obj, prefix, CXN_ARTICLE | CXN_NOCORPSE)); } else if (obj->otyp == EGG) { #if 0 /* corpses don't tell if they're stale either */ if (known && stale_egg(obj)) Strcat(prefix, "stale "); #endif if (omndx >= LOW_PM && (known || (mvitals[omndx].mvflags & MV_KNOWS_EGG))) { Strcat(prefix, mons[omndx].mname); Strcat(prefix, " "); if (obj->spe) Strcat(bp, " (laid by you)"); } } if (obj->otyp == MEAT_RING) goto ring; break; case BALL_CLASS: case CHAIN_CLASS: add_erosion_words(obj, prefix); if (obj->owornmask & W_BALL) Strcat(bp, " (chained to you)"); break; } if ((obj->owornmask & W_WEP) && !mrg_to_wielded) { if (obj->quan != 1L) { Strcat(bp, " (wielded)"); } else { const char *hand_s = body_part(HAND); if (bimanual(obj)) hand_s = makeplural(hand_s); Sprintf(eos(bp), " (weapon in %s)", hand_s); if (warn_obj_cnt && obj == uwep && (EWarn_of_mon & W_WEP) != 0L) { /* presumably can be felt when blind */ Strcat(bp, " (glowing"); if (!Blind) Sprintf(eos(bp), " %s", glow_color(obj->oartifact)); Strcat(bp, ")"); } } } if (obj->owornmask & W_SWAPWEP) { if (u.twoweap) Sprintf(eos(bp), " (wielded in other %s)", body_part(HAND)); else Strcat(bp, " (alternate weapon; not wielded)"); } if (obj->owornmask & W_QUIVER) { switch (obj->oclass) { case WEAPON_CLASS: if (is_ammo(obj)) { if (objects[obj->otyp].oc_skill == -P_BOW) { /* Ammo for a bow */ Strcat(bp, " (in quiver)"); break; } else { /* Ammo not for a bow */ Strcat(bp, " (in quiver pouch)"); break; } } else { /* Weapons not considered ammo */ Strcat(bp, " (at the ready)"); break; } /* Small things and ammo not for a bow */ case RING_CLASS: case AMULET_CLASS: case WAND_CLASS: case COIN_CLASS: case GEM_CLASS: Strcat(bp, " (in quiver pouch)"); break; default: /* odd things */ Strcat(bp, " (at the ready)"); } } if (!iflags.suppress_price && is_unpaid(obj)) { long quotedprice = unpaid_cost(obj, TRUE); Sprintf(eos(bp), " (%s, %ld %s)", obj->unpaid ? "unpaid" : "contents", quotedprice, currency(quotedprice)); } else if (with_price) { long price = get_cost_of_shop_item(obj); if (price > 0) Sprintf(eos(bp), " (%ld %s)", price, currency(price)); } if (!strncmp(prefix, "a ", 2) && index(vowels, *(prefix + 2) ? *(prefix + 2) : *bp) && (*(prefix + 2) || (strncmp(bp, "uranium", 7) && strncmp(bp, "unicorn", 7) && strncmp(bp, "eucalyptus", 10)))) { Strcpy(tmpbuf, prefix); Strcpy(prefix, "an "); Strcpy(prefix + 3, tmpbuf + 2); } /* show weight for items (debug tourist info) * aum is stolen from Crawl's "Arbitrary Unit of Measure" */ if (wizard) { Sprintf(eos(bp), " (%d aum)", obj->owt); } bp = strprepend(bp, prefix); return bp; } char * doname(obj) register struct obj *obj; { return doname_base(obj, FALSE); } /* Name of object including price. */ char * doname_with_price(obj) register struct obj *obj; { return doname_base(obj, TRUE); } /* used from invent.c */ boolean not_fully_identified(otmp) register struct obj *otmp; { /* gold doesn't have any interesting attributes [yet?] */ if (otmp->oclass == COIN_CLASS) return FALSE; /* always fully ID'd */ /* check fundamental ID hallmarks first */ if (!otmp->known || !otmp->dknown #ifdef MAIL || (!otmp->bknown && otmp->otyp != SCR_MAIL) #else || !otmp->bknown #endif || !objects[otmp->otyp].oc_name_known) return TRUE; if ((!otmp->cknown && (Is_container(otmp) || otmp->otyp == STATUE)) || (!otmp->lknown && Is_box(otmp))) return TRUE; if (otmp->oartifact && undiscovered_artifact(otmp->oartifact)) return TRUE; /* otmp->rknown is the only item of interest if we reach here */ /* * Note: if a revision ever allows scrolls to become fireproof or * rings to become shockproof, this checking will need to be revised. * `rknown' ID only matters if xname() will provide the info about it. */ if (otmp->rknown || (otmp->oclass != ARMOR_CLASS && otmp->oclass != WEAPON_CLASS && !is_weptool(otmp) /* (redundant) */ && otmp->oclass != BALL_CLASS)) /* (useless) */ return FALSE; else /* lack of `rknown' only matters for vulnerable objects */ return (boolean) (is_rustprone(otmp) || is_corrodeable(otmp) || is_flammable(otmp)); } char * corpse_xname(otmp, adjective, cxn_flags) struct obj *otmp; const char *adjective; unsigned cxn_flags; /* bitmask of CXN_xxx values */ { char *nambuf = nextobuf(); int omndx = otmp->corpsenm; boolean ignore_quan = (cxn_flags & CXN_SINGULAR) != 0, /* suppress "the" from "the unique monster corpse" */ no_prefix = (cxn_flags & CXN_NO_PFX) != 0, /* include "the" for "the woodchuck corpse */ the_prefix = (cxn_flags & CXN_PFX_THE) != 0, /* include "an" for "an ogre corpse */ any_prefix = (cxn_flags & CXN_ARTICLE) != 0, /* leave off suffix (do_name() appends "corpse" itself) */ omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, possessive = FALSE; const char *mname; if (omndx == NON_PM) { /* paranoia */ mname = "thing"; /* [Possible enhancement: check whether corpse has monster traits attached in order to use priestname() for priests and minions.] */ } else if (omndx == PM_ALIGNED_PRIEST) { /* avoid "aligned priest"; it just exposes internal details */ mname = "priest"; } else { mname = mons[omndx].mname; if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) { mname = s_suffix(mname); possessive = TRUE; /* don't precede personal name like "Medusa" with an article */ if (type_is_pname(&mons[omndx])) no_prefix = TRUE; /* always precede non-personal unique monster name like "Oracle" with "the" unless explicitly overridden */ else if (the_unique_pm(&mons[omndx]) && !no_prefix) the_prefix = TRUE; } } if (no_prefix) the_prefix = any_prefix = FALSE; else if (the_prefix) any_prefix = FALSE; /* mutually exclusive */ *nambuf = '\0'; /* can't use the() the way we use an() below because any capitalized Name causes it to assume a personal name and return Name as-is; that's usually the behavior wanted, but here we need to force "the" to precede capitalized unique monsters (pnames are handled above) */ if (the_prefix) Strcat(nambuf, "the "); if (!adjective || !*adjective) { /* normal case: newt corpse */ Strcat(nambuf, mname); } else { /* adjective positioning depends upon format of monster name */ if (possessive) /* Medusa's cursed partly eaten corpse */ Sprintf(eos(nambuf), "%s %s", mname, adjective); else /* cursed partly eaten troll corpse */ Sprintf(eos(nambuf), "%s %s", adjective, mname); /* in case adjective has a trailing space, squeeze it out */ mungspaces(nambuf); /* doname() might include a count in the adjective argument; if so, don't prepend an article */ if (digit(*adjective)) any_prefix = FALSE; } if (!omit_corpse) { Strcat(nambuf, " corpse"); /* makeplural(nambuf) => append "s" to "corpse" */ if (otmp->quan > 1L && !ignore_quan) { Strcat(nambuf, "s"); any_prefix = FALSE; /* avoid "a newt corpses" */ } } /* it's safe to overwrite our nambuf after an() has copied its old value into another buffer */ if (any_prefix) Strcpy(nambuf, an(nambuf)); return nambuf; } /* xname doesn't include monster type for "corpse"; cxname does */ char * cxname(obj) struct obj *obj; { if (obj->otyp == CORPSE) return corpse_xname(obj, (const char *) 0, CXN_NORMAL); return xname(obj); } /* like cxname, but ignores quantity */ char * cxname_singular(obj) struct obj *obj; { if (obj->otyp == CORPSE) return corpse_xname(obj, (const char *) 0, CXN_SINGULAR); return xname_flags(obj, CXN_SINGULAR); } /* treat an object as fully ID'd when it might be used as reason for death */ char * killer_xname(obj) struct obj *obj; { struct obj save_obj; unsigned save_ocknown; char *buf, *save_ocuname, *save_oname = (char *) 0; /* bypass object twiddling for artifacts */ if (obj->oartifact) return bare_artifactname(obj); /* remember original settings for core of the object; oextra structs other than oname don't matter here--since they aren't modified they don't need to be saved and restored */ save_obj = *obj; if (has_oname(obj)) save_oname = ONAME(obj); /* killer name should be more specific than general xname; however, exact info like blessed/cursed and rustproof makes things be too verbose */ obj->known = obj->dknown = 1; obj->bknown = obj->rknown = obj->greased = 0; /* if character is a priest[ess], bknown will get toggled back on */ if (obj->otyp != POT_WATER) obj->blessed = obj->cursed = 0; else obj->bknown = 1; /* describe holy/unholy water as such */ /* "killed by poisoned " would be misleading when poison is not the cause of death and "poisoned by poisoned " would be redundant when it is, so suppress "poisoned" prefix */ obj->opoisoned = 0; /* strip user-supplied name; artifacts keep theirs */ if (!obj->oartifact && save_oname) ONAME(obj) = (char *) 0; /* temporarily identify the type of object */ save_ocknown = objects[obj->otyp].oc_name_known; objects[obj->otyp].oc_name_known = 1; save_ocuname = objects[obj->otyp].oc_uname; objects[obj->otyp].oc_uname = 0; /* avoid "foo called bar" */ /* format the object */ if (obj->otyp == CORPSE) { buf = nextobuf(); Strcpy(buf, corpse_xname(obj, (const char *) 0, CXN_NORMAL)); } else if (obj->otyp == SLIME_MOLD) { /* concession to "most unique deaths competition" in the annual devnull tournament, suppress player supplied fruit names because those can be used to fake other objects and dungeon features */ buf = nextobuf(); Sprintf(buf, "deadly slime mold%s", plur(obj->quan)); } else { buf = xname(obj); } /* apply an article if appropriate; caller should always use KILLED_BY */ if (obj->quan == 1L && !strstri(buf, "'s ") && !strstri(buf, "s' ")) buf = (obj_is_pname(obj) || the_unique_obj(obj)) ? the(buf) : an(buf); objects[obj->otyp].oc_name_known = save_ocknown; objects[obj->otyp].oc_uname = save_ocuname; *obj = save_obj; /* restore object's core settings */ if (!obj->oartifact && save_oname) ONAME(obj) = save_oname; return buf; } /* xname,doname,&c with long results reformatted to omit some stuff */ char * short_oname(obj, func, altfunc, lenlimit) struct obj *obj; char *FDECL((*func), (OBJ_P)), /* main formatting routine */ *FDECL((*altfunc), (OBJ_P)); /* alternate for shortest result */ unsigned lenlimit; { struct obj save_obj; char unamebuf[12], onamebuf[12], *save_oname, *save_uname, *outbuf; outbuf = (*func)(obj); if ((unsigned) strlen(outbuf) <= lenlimit) return outbuf; /* shorten called string to fairly small amount */ save_uname = objects[obj->otyp].oc_uname; if (save_uname && strlen(save_uname) >= sizeof unamebuf) { (void) strncpy(unamebuf, save_uname, sizeof unamebuf - 4); Strcpy(unamebuf + sizeof unamebuf - 4, "..."); objects[obj->otyp].oc_uname = unamebuf; releaseobuf(outbuf); outbuf = (*func)(obj); objects[obj->otyp].oc_uname = save_uname; /* restore called string */ if ((unsigned) strlen(outbuf) <= lenlimit) return outbuf; } /* shorten named string to fairly small amount */ save_oname = has_oname(obj) ? ONAME(obj) : 0; if (save_oname && strlen(save_oname) >= sizeof onamebuf) { (void) strncpy(onamebuf, save_oname, sizeof onamebuf - 4); Strcpy(onamebuf + sizeof onamebuf - 4, "..."); ONAME(obj) = onamebuf; releaseobuf(outbuf); outbuf = (*func)(obj); ONAME(obj) = save_oname; /* restore named string */ if ((unsigned) strlen(outbuf) <= lenlimit) return outbuf; } /* shorten both called and named strings; unamebuf and onamebuf have both already been populated */ if (save_uname && strlen(save_uname) >= sizeof unamebuf && save_oname && strlen(save_oname) >= sizeof onamebuf) { objects[obj->otyp].oc_uname = unamebuf; ONAME(obj) = onamebuf; releaseobuf(outbuf); outbuf = (*func)(obj); if ((unsigned) strlen(outbuf) <= lenlimit) { objects[obj->otyp].oc_uname = save_uname; ONAME(obj) = save_oname; return outbuf; } } /* still long; strip several name-lengthening attributes; called and named strings are still in truncated form */ save_obj = *obj; obj->bknown = obj->rknown = obj->greased = 0; obj->oeroded = obj->oeroded2 = 0; releaseobuf(outbuf); outbuf = (*func)(obj); if (altfunc && (unsigned) strlen(outbuf) > lenlimit) { /* still long; use the alternate function (usually one of the jackets around minimal_xname()) */ releaseobuf(outbuf); outbuf = (*altfunc)(obj); } /* restore the object */ *obj = save_obj; if (save_oname) ONAME(obj) = save_oname; if (save_uname) objects[obj->otyp].oc_uname = save_uname; /* use whatever we've got, whether it's too long or not */ return outbuf; } /* * Used if only one of a collection of objects is named (e.g. in eat.c). */ const char * singular(otmp, func) register struct obj *otmp; char *FDECL((*func), (OBJ_P)); { long savequan; char *nam; /* using xname for corpses does not give the monster type */ if (otmp->otyp == CORPSE && func == xname) func = cxname; savequan = otmp->quan; otmp->quan = 1L; nam = (*func)(otmp); otmp->quan = savequan; return nam; } char * an(str) register const char *str; { char *buf = nextobuf(); buf[0] = '\0'; if (strncmpi(str, "the ", 4) && strcmp(str, "molten lava") && strcmp(str, "iron bars") && strcmp(str, "ice")) { if (index(vowels, *str) && strncmp(str, "one-", 4) && strncmp(str, "useful", 6) && strncmp(str, "unicorn", 7) && strncmp(str, "uranium", 7) && strncmp(str, "eucalyptus", 10)) Strcpy(buf, "an "); else Strcpy(buf, "a "); } Strcat(buf, str); return buf; } char * An(str) const char *str; { char *tmp = an(str); *tmp = highc(*tmp); return tmp; } /* * Prepend "the" if necessary; assumes str is a subject derived from xname. * Use type_is_pname() for monster names, not the(). the() is idempotent. */ char * the(str) const char *str; { char *buf = nextobuf(); boolean insert_the = FALSE; if (!strncmpi(str, "the ", 4)) { buf[0] = lowc(*str); Strcpy(&buf[1], str + 1); return buf; } else if (*str < 'A' || *str > 'Z') { /* not a proper name, needs an article */ insert_the = TRUE; } else { /* Probably a proper name, might not need an article */ register char *tmp, *named, *called; int l; /* some objects have capitalized adjectives in their names */ if (((tmp = rindex(str, ' ')) != 0 || (tmp = rindex(str, '-')) != 0) && (tmp[1] < 'A' || tmp[1] > 'Z')) { insert_the = TRUE; } else if (tmp && index(str, ' ') < tmp) { /* has spaces */ /* it needs an article if the name contains "of" */ tmp = strstri(str, " of "); named = strstri(str, " named "); called = strstri(str, " called "); if (called && (!named || called < named)) named = called; if (tmp && (!named || tmp < named)) /* found an "of" */ insert_the = TRUE; /* stupid special case: lacks "of" but needs "the" */ else if (!named && (l = strlen(str)) >= 31 && !strcmp(&str[l - 31], "Platinum Yendorian Express Card")) insert_the = TRUE; } } if (insert_the) Strcpy(buf, "the "); else buf[0] = '\0'; Strcat(buf, str); return buf; } char * The(str) const char *str; { char *tmp = the(str); *tmp = highc(*tmp); return tmp; } /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */ char * aobjnam(otmp, verb) struct obj *otmp; const char *verb; { char prefix[PREFIX]; char *bp = cxname(otmp); if (otmp->quan != 1L) { Sprintf(prefix, "%ld ", otmp->quan); bp = strprepend(bp, prefix); } if (verb) { Strcat(bp, " "); Strcat(bp, otense(otmp, verb)); } return bp; } /* combine yname and aobjnam eg "your count cxname(otmp)" */ char * yobjnam(obj, verb) struct obj *obj; const char *verb; { char *s = aobjnam(obj, verb); /* leave off "your" for most of your artifacts, but prepend * "your" for unique objects and "foo of bar" quest artifacts */ if (!carried(obj) || !obj_is_pname(obj) || obj->oartifact >= ART_ORB_OF_DETECTION) { char *outbuf = shk_your(nextobuf(), obj); int space_left = BUFSZ - 1 - strlen(outbuf); s = strncat(outbuf, s, space_left); } return s; } /* combine Yname2 and aobjnam eg "Your count cxname(otmp)" */ char * Yobjnam2(obj, verb) struct obj *obj; const char *verb; { register char *s = yobjnam(obj, verb); *s = highc(*s); return s; } /* like aobjnam, but prepend "The", not count, and use xname */ char * Tobjnam(otmp, verb) struct obj *otmp; const char *verb; { char *bp = The(xname(otmp)); if (verb) { Strcat(bp, " "); Strcat(bp, otense(otmp, verb)); } return bp; } /* capitalized variant of doname() */ char * Doname2(obj) struct obj *obj; { char *s = doname(obj); *s = highc(*s); return s; } /* returns "[your ]xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */ char * yname(obj) struct obj *obj; { char *s = cxname(obj); /* leave off "your" for most of your artifacts, but prepend * "your" for unique objects and "foo of bar" quest artifacts */ if (!carried(obj) || !obj_is_pname(obj) || obj->oartifact >= ART_ORB_OF_DETECTION) { char *outbuf = shk_your(nextobuf(), obj); int space_left = BUFSZ - 1 - strlen(outbuf); s = strncat(outbuf, s, space_left); } return s; } /* capitalized variant of yname() */ char * Yname2(obj) struct obj *obj; { char *s = yname(obj); *s = highc(*s); return s; } /* returns "your minimal_xname(obj)" * or "Foobar's minimal_xname(obj)" * or "the minimal_xname(obj)" */ char * ysimple_name(obj) struct obj *obj; { char *outbuf = nextobuf(); char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */ int space_left = BUFSZ - 1 - strlen(s); return strncat(s, minimal_xname(obj), space_left); } /* capitalized variant of ysimple_name() */ char * Ysimple_name2(obj) struct obj *obj; { char *s = ysimple_name(obj); *s = highc(*s); return s; } /* "scroll" or "scrolls" */ char * simpleonames(obj) struct obj *obj; { char *simpleoname = minimal_xname(obj); if (obj->quan != 1L) simpleoname = makeplural(simpleoname); return simpleoname; } /* "a scroll" or "scrolls"; "a silver bell" or "the Bell of Opening" */ char * ansimpleoname(obj) struct obj *obj; { char *simpleoname = simpleonames(obj); int otyp = obj->otyp; /* prefix with "the" if a unique item, or a fake one imitating same, has been formatted with its actual name (we let typename() handle any `known' and `dknown' checking necessary) */ if (otyp == FAKE_AMULET_OF_YENDOR) otyp = AMULET_OF_YENDOR; if (objects[otyp].oc_unique && !strcmp(simpleoname, OBJ_NAME(objects[otyp]))) return the(simpleoname); /* simpleoname is singular if quan==1, plural otherwise */ if (obj->quan == 1L) simpleoname = an(simpleoname); return simpleoname; } /* "the scroll" or "the scrolls" */ char * thesimpleoname(obj) struct obj *obj; { char *simpleoname = simpleonames(obj); return the(simpleoname); } /* artifact's name without any object type or known/dknown/&c feedback */ char * bare_artifactname(obj) struct obj *obj; { char *outbuf; if (obj->oartifact) { outbuf = nextobuf(); Strcpy(outbuf, artiname(obj->oartifact)); if (!strncmp(outbuf, "The ", 4)) outbuf[0] = lowc(outbuf[0]); } else { outbuf = xname(obj); } return outbuf; } static const char *wrp[] = { "wand", "ring", "potion", "scroll", "gem", "amulet", "spellbook", "spell book", /* for non-specific wishes */ "weapon", "armor", "tool", "food", "comestible", }; static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS, WEAPON_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS, FOOD_CLASS }; /* return form of the verb (input plural) if xname(otmp) were the subject */ char * otense(otmp, verb) struct obj *otmp; const char *verb; { char *buf; /* * verb is given in plural (without trailing s). Return as input * if the result of xname(otmp) would be plural. Don't bother * recomputing xname(otmp) at this time. */ if (!is_plural(otmp)) return vtense((char *) 0, verb); buf = nextobuf(); Strcpy(buf, verb); return buf; } /* various singular words that vtense would otherwise categorize as plural; also used by makesingular() to catch some special cases */ static const char *const special_subjs[] = { "erinys", "manes", /* this one is ambiguous */ "Cyclops", "Hippocrates", "Pelias", "aklys", "amnesia", "detect monsters", "paralysis", "shape changers", "nemesis", 0 /* note: "detect monsters" and "shape changers" are normally caught via "(s) of ", but they can be wished for using the shorter form, so we include them here to accommodate usage by makesingular during wishing */ }; /* return form of the verb (input plural) for present tense 3rd person subj */ char * vtense(subj, verb) register const char *subj; register const char *verb; { char *buf = nextobuf(), *bspot; int len, ltmp; const char *sp, *spot; const char *const *spec; /* * verb is given in plural (without trailing s). Return as input * if subj appears to be plural. Add special cases as necessary. * Many hard cases can already be handled by using otense() instead. * If this gets much bigger, consider decomposing makeplural. * Note: monster names are not expected here (except before corpse). * * Special case: allow null sobj to get the singular 3rd person * present tense form so we don't duplicate this code elsewhere. */ if (subj) { if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3)) goto sing; spot = (const char *) 0; for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) { if (!strncmpi(sp, " of ", 4) || !strncmpi(sp, " from ", 6) || !strncmpi(sp, " called ", 8) || !strncmpi(sp, " named ", 7) || !strncmpi(sp, " labeled ", 9)) { if (sp != subj) spot = sp - 1; break; } } len = (int) strlen(subj); if (!spot) spot = subj + len - 1; /* * plural: anything that ends in 's', but not '*us' or '*ss'. * Guess at a few other special cases that makeplural creates. */ if ((lowc(*spot) == 's' && spot != subj && !index("us", lowc(*(spot - 1)))) || !BSTRNCMPI(subj, spot - 3, "eeth", 4) || !BSTRNCMPI(subj, spot - 3, "feet", 4) || !BSTRNCMPI(subj, spot - 1, "ia", 2) || !BSTRNCMPI(subj, spot - 1, "ae", 2)) { /* check for special cases to avoid false matches */ len = (int) (spot - subj) + 1; for (spec = special_subjs; *spec; spec++) { ltmp = strlen(*spec); if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing; /* also check for to catch things like "the invisible erinys" */ if (len > ltmp && *(spot - ltmp) == ' ' && !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing; } return strcpy(buf, verb); } /* * 3rd person plural doesn't end in telltale 's'; * 2nd person singular behaves as if plural. */ if (!strcmpi(subj, "they") || !strcmpi(subj, "you")) return strcpy(buf, verb); } sing: Strcpy(buf, verb); len = (int) strlen(buf); bspot = buf + len - 1; if (!strcmpi(buf, "are")) { Strcasecpy(buf, "is"); } else if (!strcmpi(buf, "have")) { Strcasecpy(bspot - 1, "s"); } else if (index("zxs", lowc(*bspot)) || (len >= 2 && lowc(*bspot) == 'h' && index("cs", lowc(*(bspot - 1)))) || (len == 2 && lowc(*bspot) == 'o')) { /* Ends in z, x, s, ch, sh; add an "es" */ Strcasecpy(bspot + 1, "es"); } else if (lowc(*bspot) == 'y' && !index(vowels, lowc(*(bspot - 1)))) { /* like "y" case in makeplural */ Strcasecpy(bspot, "ies"); } else { Strcasecpy(bspot + 1, "s"); } return buf; } struct sing_plur { const char *sing, *plur; }; /* word pairs that don't fit into formula-based transformations; also some suffices which have very few--often one--matches or which aren't systematically reversible (knives, staves) */ static struct sing_plur one_off[] = { { "child", "children" }, /* (for wise guys who give their food funny names) */ { "cubus", "cubi" }, /* in-/suc-cubus */ { "culus", "culi" }, /* homunculus */ { "djinni", "djinn" }, { "erinys", "erinyes" }, { "foot", "feet" }, { "fungus", "fungi" }, { "knife", "knives" }, { "labrum", "labra" }, /* candelabrum */ { "louse", "lice" }, { "mouse", "mice" }, { "mumak", "mumakil" }, { "nemesis", "nemeses" }, { "rtex", "rtices" }, /* vortex */ { "tooth", "teeth" }, { "staff", "staves" }, { 0, 0 } }; static const char *const as_is[] = { /* makesingular() leaves these plural due to how they're used */ "boots", "shoes", "gloves", "lenses", "scales", "eyes", "gauntlets", "iron bars", /* both singular and plural are spelled the same */ "deer", "fish", "tuna", "yaki", "-hai", "krill", "manes", "ninja", "sheep", "ronin", "roshi", "shito", "tengu", "ki-rin", "Nazgul", "gunyoki", "piranha", "samurai", "shuriken", 0, /* Note: "fish" and "piranha" are collective plurals, suitable for "wiped out all ". For "3 ", they should be "fishes" and "piranhas" instead. We settle for collective variant instead of attempting to support both. */ }; /* singularize/pluralize decisions common to both makesingular & makeplural */ STATIC_OVL boolean singplur_lookup(basestr, endstring, to_plural, alt_as_is) char *basestr, *endstring; /* base string, pointer to eos(string) */ boolean to_plural; /* true => makeplural, false => makesingular */ const char *const *alt_as_is; /* another set like as_is[] */ { const struct sing_plur *sp; const char *same, *other, *const *as; int al; for (as = as_is; *as; ++as) { al = (int) strlen(*as); if (!BSTRCMPI(basestr, endstring - al, *as)) return TRUE; } if (alt_as_is) { for (as = alt_as_is; *as; ++as) { al = (int) strlen(*as); if (!BSTRCMPI(basestr, endstring - al, *as)) return TRUE; } } for (sp = one_off; sp->sing; sp++) { /* check whether endstring already matches */ same = to_plural ? sp->plur : sp->sing; al = (int) strlen(same); if (!BSTRCMPI(basestr, endstring - al, same)) return TRUE; /* use as-is */ /* check whether it matches the inverse; if so, transform it */ other = to_plural ? sp->sing : sp->plur; al = (int) strlen(other); if (!BSTRCMPI(basestr, endstring - al, other)) { Strcasecpy(endstring - al, same); return TRUE; /* one_off[] transformation */ } } return FALSE; } /* searches for common compounds, ex. lump of royal jelly */ STATIC_OVL char * singplur_compound(str) char *str; { /* if new entries are added, be sure to keep compound_start[] in sync */ static const char *const compounds[] = { " of ", " labeled ", " called ", " named ", " above", /* lurkers above */ " versus ", " from ", " in ", " on ", " a la ", " with", /* " with "? */ " de ", " d'", " du ", "-in-", "-at-", 0 }, /* list of first characters for all compounds[] entries */ compound_start[] = " -"; const char *const *cmpd; char *p; for (p = str; *p; ++p) { /* substring starting at p can only match if *p is found within compound_start[] */ if (!index(compound_start, *p)) continue; /* check current substring against all words in the compound[] list */ for (cmpd = compounds; *cmpd; ++cmpd) if (!strncmpi(p, *cmpd, (int) strlen(*cmpd))) return p; } /* wasn't recognized as a compound phrase */ return 0; } /* Plural routine; chiefly used for user-defined fruits. We have to try to * account for everything reasonable the player has; something unreasonable * can still break the code. However, it's still a lot more accurate than * "just add an s at the end", which Rogue uses... * * Also used for plural monster names ("Wiped out all homunculi." or the * vanquished monsters list) and body parts. A lot of unique monsters have * names which get mangled by makeplural and/or makesingular. They're not * genocidable, and vanquished-mon handling does its own special casing * (for uniques who've been revived and re-killed), so we don't bother * trying to get those right here. * * Also misused by muse.c to convert 1st person present verbs to 2nd person. * 3.6.0: made case-insensitive. */ char * makeplural(oldstr) const char *oldstr; { register char *spot; char lo_c, *str = nextobuf(); const char *excess = (char *) 0; int len; if (oldstr) while (*oldstr == ' ') oldstr++; if (!oldstr || !*oldstr) { impossible("plural of null?"); Strcpy(str, "s"); return str; } Strcpy(str, oldstr); /* * Skip changing "pair of" to "pairs of". According to Webster, usual * English usage is use pairs for humans, e.g. 3 pairs of dancers, * and pair for objects and non-humans, e.g. 3 pair of boots. We don't * refer to pairs of humans in this game so just skip to the bottom. */ if (!strncmpi(str, "pair of ", 8)) goto bottom; /* look for "foo of bar" so that we can focus on "foo" */ if ((spot = singplur_compound(str)) != 0) { excess = oldstr + (int) (spot - str); *spot = '\0'; } else spot = eos(str); spot--; while (spot > str && *spot == ' ') spot--; /* Strip blanks from end */ *(spot + 1) = 0; /* Now spot is the last character of the string */ len = strlen(str); /* Single letters */ if (len == 1 || !letter(*spot)) { Strcpy(spot + 1, "'s"); goto bottom; } /* dispense with some words which don't need pluralization */ { static const char *const already_plural[] = { "ae", /* algae, larvae, &c */ "men", /* also catches women, watchmen */ "matzot", 0, }; /* spot+1: synch up with makesingular's usage */ if (singplur_lookup(str, spot + 1, TRUE, already_plural)) goto bottom; /* more of same, but not suitable for blanket loop checking */ if ((len == 2 && !strcmpi(str, "ya")) || (len >= 3 && !strcmpi(spot - 2, " ya"))) goto bottom; } /* man/men ("Wiped out all cavemen.") */ if (len >= 3 && !strcmpi(spot - 2, "man") /* exclude shamans and humans */ && (len < 6 || strcmpi(spot - 5, "shaman")) && (len < 5 || strcmpi(spot - 4, "human"))) { Strcasecpy(spot - 1, "en"); goto bottom; } if (lowc(*spot) == 'f') { /* (staff handled via one_off[]) */ lo_c = lowc(*(spot - 1)); if (len >= 3 && !strcmpi(spot - 2, "erf")) { /* avoid "nerf" -> "nerves", "serf" -> "serves" */ ; /* fall through to default (append 's') */ } else if (index("lr", lo_c) || index(vowels, lo_c)) { /* [aeioulr]f to [aeioulr]ves */ Strcasecpy(spot, "ves"); goto bottom; } } /* ium/ia (mycelia, baluchitheria) */ if (len >= 3 && !strcmpi(spot - 2, "ium")) { Strcasecpy(spot - 2, "ia"); goto bottom; } /* algae, larvae, hyphae (another fungus part) */ if ((len >= 4 && !strcmpi(spot - 3, "alga")) || (len >= 5 && (!strcmpi(spot - 4, "hypha") || !strcmpi(spot - 4, "larva"))) || (len >= 6 && !strcmpi(spot - 5, "amoeba")) || (len >= 8 && (!strcmpi(spot - 7, "vertebra")))) { /* a to ae */ Strcasecpy(spot + 1, "e"); goto bottom; } /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */ if (len > 3 && !strcmpi(spot - 1, "us") && !((len >= 5 && !strcmpi(spot - 4, "lotus")) || (len >= 6 && !strcmpi(spot - 5, "wumpus")))) { Strcasecpy(spot - 1, "i"); goto bottom; } /* sis/ses (nemesis) */ if (len >= 3 && !strcmpi(spot - 2, "sis")) { Strcasecpy(spot - 1, "es"); goto bottom; } /* matzoh/matzot, possible food name */ if (len >= 6 && (!strcmpi(spot - 5, "matzoh") || !strcmpi(spot - 5, "matzah"))) { Strcasecpy(spot - 1, "ot"); /* oh/ah -> ot */ goto bottom; } if (len >= 5 && (!strcmpi(spot - 4, "matzo") || !strcmpi(spot - 4, "matza"))) { Strcasecpy(spot, "ot"); /* o/a -> ot */ goto bottom; } /* note: -eau/-eaux (gateau, bordeau...) */ /* note: ox/oxen, VAX/VAXen, goose/geese */ lo_c = lowc(*spot); /* Ends in z, x, s, ch, sh; add an "es" */ if (index("zxs", lo_c) || (len >= 2 && lo_c == 'h' && index("cs", lowc(*(spot - 1)))) /* Kludge to get "tomatoes" and "potatoes" right */ || (len >= 4 && !strcmpi(spot - 2, "ato")) || (len >= 5 && !strcmpi(spot - 4, "dingo"))) { Strcasecpy(spot + 1, "es"); /* append es */ goto bottom; } /* Ends in y preceded by consonant (note: also "qu") change to "ies" */ if (lo_c == 'y' && !index(vowels, lowc(*(spot - 1)))) { Strcasecpy(spot, "ies"); /* y -> ies */ goto bottom; } /* Default: append an 's' */ Strcasecpy(spot + 1, "s"); bottom: if (excess) Strcat(str, excess); return str; } /* * Singularize a string the user typed in; this helps reduce the complexity * of readobjnam, and is also used in pager.c to singularize the string * for which help is sought. * * "Manes" is ambiguous: monster type (keep s), or horse body part (drop s)? * Its inclusion in as_is[]/special_subj[] makes it get treated as the former. * * A lot of unique monsters have names ending in s; plural, or singular * from plural, doesn't make much sense for them so we don't bother trying. * 3.6.0: made case-insensitive. */ char * makesingular(oldstr) const char *oldstr; { register char *p, *bp; const char *excess = 0; char *str = nextobuf(); if (oldstr) while (*oldstr == ' ') oldstr++; if (!oldstr || !*oldstr) { impossible("singular of null?"); str[0] = '\0'; return str; } bp = strcpy(str, oldstr); /* check for "foo of bar" so that we can focus on "foo" */ if ((p = singplur_compound(bp)) != 0) { excess = oldstr + (int) (p - bp); *p = '\0'; } else p = eos(bp); /* dispense with some words which don't need singularization */ if (singplur_lookup(bp, p, FALSE, special_subjs)) goto bottom; /* remove -s or -es (boxes) or -ies (rubies) */ if (p >= bp + 1 && lowc(p[-1]) == 's') { if (p >= bp + 2 && lowc(p[-2]) == 'e') { if (p >= bp + 3 && lowc(p[-3]) == 'i') { /* "ies" */ if (!BSTRCMPI(bp, p - 7, "cookies") || !BSTRCMPI(bp, p - 4, "pies") || !BSTRCMPI(bp, p - 5, "mbies") /* zombie */ || !BSTRCMPI(bp, p - 5, "yries")) /* valkyrie */ goto mins; Strcasecpy(p - 3, "y"); /* ies -> y */ goto bottom; } /* wolves, but f to ves isn't fully reversible */ if (p - 4 >= bp && (index("lr", lowc(*(p - 4))) || index(vowels, lowc(*(p - 4)))) && !BSTRCMPI(bp, p - 3, "ves")) { if (!BSTRCMPI(bp, p - 6, "cloves") || !BSTRCMPI(bp, p - 6, "nerves")) goto mins; Strcasecpy(p - 3, "f"); /* ves -> f */ goto bottom; } /* note: nurses, axes but boxes, wumpuses */ if (!BSTRCMPI(bp, p - 4, "eses") || !BSTRCMPI(bp, p - 4, "oxes") /* boxes, foxes */ || !BSTRCMPI(bp, p - 4, "nxes") /* lynxes */ || !BSTRCMPI(bp, p - 4, "ches") || !BSTRCMPI(bp, p - 4, "uses") /* lotuses */ || !BSTRCMPI(bp, p - 4, "sses") /* priestesses */ || !BSTRCMPI(bp, p - 5, "atoes") /* tomatoes */ || !BSTRCMPI(bp, p - 7, "dingoes") || !BSTRCMPI(bp, p - 7, "Aleaxes")) { *(p - 2) = '\0'; /* drop es */ goto bottom; } /* else fall through to mins */ /* ends in 's' but not 'es' */ } else if (!BSTRCMPI(bp, p - 2, "us")) { /* lotus, fungus... */ if (BSTRCMPI(bp, p - 6, "tengus") /* but not these... */ && BSTRCMPI(bp, p - 7, "hezrous")) goto bottom; } else if (!BSTRCMPI(bp, p - 2, "ss") || !BSTRCMPI(bp, p - 5, " lens") || (p - 4 == bp && !strcmpi(p - 4, "lens"))) { goto bottom; } mins: *(p - 1) = '\0'; /* drop s */ } else { /* input doesn't end in 's' */ if (!BSTRCMPI(bp, p - 3, "men")) { Strcasecpy(p - 2, "an"); goto bottom; } /* matzot -> matzo, algae -> alga */ if (!BSTRCMPI(bp, p - 6, "matzot") || !BSTRCMPI(bp, p - 2, "ae")) { *(p - 1) = '\0'; /* drop t/e */ goto bottom; } /* balactheria -> balactherium */ if (p - 4 >= bp && !strcmpi(p - 2, "ia") && index("lr", lowc(*(p - 3))) && lowc(*(p - 4)) == 'e') { Strcasecpy(p - 1, "um"); /* a -> um */ } /* here we cannot find the plural suffix */ } bottom: /* if we stripped off a suffix (" of bar" from "foo of bar"), put it back now [strcat() isn't actually 100% safe here...] */ if (excess) Strcat(bp, excess); return bp; } /* compare user string against object name string using fuzzy matching */ STATIC_OVL boolean wishymatch(u_str, o_str, retry_inverted) const char *u_str; /* from user, so might be variant spelling */ const char *o_str; /* from objects[], so is in canonical form */ boolean retry_inverted; /* optional extra "of" handling */ { static NEARDATA const char detect_SP[] = "detect ", SP_detection[] = " detection"; char *p, buf[BUFSZ]; /* ignore spaces & hyphens and upper/lower case when comparing */ if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE; if (retry_inverted) { const char *u_of, *o_of; /* when just one of the strings is in the form "foo of bar", convert it into "bar foo" and perform another comparison */ u_of = strstri(u_str, " of "); o_of = strstri(o_str, " of "); if (u_of && !o_of) { Strcpy(buf, u_of + 4); p = eos(strcat(buf, " ")); while (u_str < u_of) *p++ = *u_str++; *p = '\0'; return fuzzymatch(buf, o_str, " -", TRUE); } else if (o_of && !u_of) { Strcpy(buf, o_of + 4); p = eos(strcat(buf, " ")); while (o_str < o_of) *p++ = *o_str++; *p = '\0'; return fuzzymatch(u_str, buf, " -", TRUE); } } /* [note: if something like "elven speed boots" ever gets added, these special cases should be changed to call wishymatch() recursively in order to get the "of" inversion handling] */ if (!strncmp(o_str, "dwarvish ", 9)) { if (!strncmpi(u_str, "dwarven ", 8)) return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE); } else if (!strncmp(o_str, "elven ", 6)) { if (!strncmpi(u_str, "elvish ", 7)) return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE); else if (!strncmpi(u_str, "elfin ", 6)) return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE); } else if (!strncmp(o_str, detect_SP, sizeof detect_SP - 1)) { /* check for "detect " vs " detection" */ if ((p = strstri(u_str, SP_detection)) != 0 && !*(p + sizeof SP_detection - 1)) { /* convert " detection" into "detect " */ *p = '\0'; Strcat(strcpy(buf, detect_SP), u_str); /* "detect monster" -> "detect monsters" */ if (!strcmpi(u_str, "monster")) Strcat(buf, "s"); *p = ' '; return fuzzymatch(buf, o_str, " -", TRUE); } } else if (strstri(o_str, SP_detection)) { /* and the inverse, " detection" vs "detect " */ if (!strncmpi(u_str, detect_SP, sizeof detect_SP - 1)) { /* convert "detect s" into " detection" */ p = makesingular(u_str + sizeof detect_SP - 1); Strcat(strcpy(buf, p), SP_detection); /* caller may be looping through objects[], so avoid churning through all the obufs */ releaseobuf(p); return fuzzymatch(buf, o_str, " -", TRUE); } } else if (strstri(o_str, "ability")) { /* when presented with "foo of bar", makesingular() used to singularize both foo & bar, but now only does so for foo */ /* catch "{potion(s),ring} of {gain,restore,sustain} abilities" */ if ((p = strstri(u_str, "abilities")) != 0 && !*(p + sizeof "abilities" - 1)) { (void) strncpy(buf, u_str, (unsigned) (p - u_str)); Strcpy(buf + (p - u_str), "ability"); return fuzzymatch(buf, o_str, " -", TRUE); } } else if (!strcmp(o_str, "aluminum")) { /* this special case doesn't really fit anywhere else... */ /* (note that " wand" will have been stripped off by now) */ if (!strcmpi(u_str, "aluminium")) return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE); } return FALSE; } struct o_range { const char *name, oclass; int f_o_range, l_o_range; }; /* wishable subranges of objects */ STATIC_OVL NEARDATA const struct o_range o_ranges[] = { { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS }, { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP }, { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE }, { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY }, { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION }, { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP }, { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY }, { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS }, { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES }, { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT }, { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT }, { "dragon scales", ARMOR_CLASS, GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES }, { "dragon scale mail", ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL }, { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA }, { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM }, { "gray stone", GEM_CLASS, LUCKSTONE, FLINT }, { "grey stone", GEM_CLASS, LUCKSTONE, FLINT }, }; /* alternate spellings; if the difference is only the presence or absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe" vs "pick-axe") then there is no need for inclusion in this list; likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */ struct alt_spellings { const char *sp; int ob; } spellings[] = { { "pickax", PICK_AXE }, { "whip", BULLWHIP }, { "saber", SILVER_SABER }, { "silver sabre", SILVER_SABER }, { "smooth shield", SHIELD_OF_REFLECTION }, { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL }, { "grey dragon scales", GRAY_DRAGON_SCALES }, { "iron ball", HEAVY_IRON_BALL }, { "lantern", BRASS_LANTERN }, { "mattock", DWARVISH_MATTOCK }, { "amulet of poison resistance", AMULET_VERSUS_POISON }, { "potion of sleep", POT_SLEEPING }, { "stone", ROCK }, { "camera", EXPENSIVE_CAMERA }, { "tee shirt", T_SHIRT }, { "can", TIN }, { "can opener", TIN_OPENER }, { "kelp", KELP_FROND }, { "eucalyptus", EUCALYPTUS_LEAF }, { "royal jelly", LUMP_OF_ROYAL_JELLY }, { "lembas", LEMBAS_WAFER }, { "marker", MAGIC_MARKER }, { "hook", GRAPPLING_HOOK }, { "grappling iron", GRAPPLING_HOOK }, { "grapnel", GRAPPLING_HOOK }, { "grapple", GRAPPLING_HOOK }, /* normally we wouldn't have to worry about unnecessary , but " stone" will get stripped off, preventing a wishymatch; that actually lets "flint stone" be a match, so we also accept bogus "flintstone" */ { "luck stone", LUCKSTONE }, { "load stone", LOADSTONE }, { "touch stone", TOUCHSTONE }, { "flintstone", FLINT }, { (const char *) 0, 0 }, }; short rnd_otyp_by_wpnskill(skill) schar skill; { int i, n = 0; short otyp = STRANGE_OBJECT; for (i = bases[WEAPON_CLASS]; i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++) if (objects[i].oc_skill == skill) { n++; otyp = i; } if (n > 0) { n = rn2(n); for (i = bases[WEAPON_CLASS]; i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++) if (objects[i].oc_skill == skill) if (--n < 0) return i; } return otyp; } /* * Return something wished for. Specifying a null pointer for * the user request string results in a random object. Otherwise, * if asking explicitly for "nothing" (or "nil") return no_wish; * if not an object return &zeroobj; if an error (no matching object), * return null. */ struct obj * readobjnam(bp, no_wish) register char *bp; struct obj *no_wish; { register char *p; register int i; register struct obj *otmp; int cnt, spe, spesgn, typ, very, rechrg; int blessed, uncursed, iscursed, ispoisoned, isgreased; int eroded, eroded2, erodeproof; int halfeaten, mntmp, contents; int islit, unlabeled, ishistoric, isdiluted, trapped; int tmp, tinv, tvariety; int wetness; struct fruit *f; int ftype = context.current_fruit; char fruitbuf[BUFSZ]; /* Fruits may not mess up the ability to wish for real objects (since * you can leave a fruit in a bones file and it will be added to * another person's game), so they must be checked for last, after * stripping all the possible prefixes and seeing if there's a real * name in there. So we have to save the full original name. However, * it's still possible to do things like "uncursed burnt Alaska", * or worse yet, "2 burned 5 course meals", so we need to loop to * strip off the prefixes again, this time stripping only the ones * possible on food. * We could get even more detailed so as to allow food names with * prefixes that _are_ possible on food, so you could wish for * "2 3 alarm chilis". Currently this isn't allowed; options.c * automatically sticks 'candied' in front of such names. */ char oclass; char *un, *dn, *actualn; const char *name = 0; cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed = ispoisoned = isgreased = eroded = eroded2 = erodeproof = halfeaten = islit = unlabeled = ishistoric = isdiluted = trapped = 0; tvariety = RANDOM_TIN; mntmp = NON_PM; #define UNDEFINED 0 #define EMPTY 1 #define SPINACH 2 contents = UNDEFINED; oclass = 0; actualn = dn = un = 0; wetness = 0; if (!bp) goto any; /* first, remove extra whitespace they may have typed */ (void) mungspaces(bp); /* allow wishing for "nothing" to preserve wishless conduct... [now requires "wand of nothing" if that's what was really wanted] */ if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") || !strcmpi(bp, "none")) return no_wish; /* save the [nearly] unmodified choice string */ Strcpy(fruitbuf, bp); for (;;) { register int l; if (!bp || !*bp) goto any; if (!strncmpi(bp, "an ", l = 3) || !strncmpi(bp, "a ", l = 2)) { cnt = 1; } else if (!strncmpi(bp, "the ", l = 4)) { ; /* just increment `bp' by `l' below */ } else if (!cnt && digit(*bp) && strcmp(bp, "0")) { cnt = atoi(bp); while (digit(*bp)) bp++; while (*bp == ' ') bp++; l = 0; } else if (*bp == '+' || *bp == '-') { spesgn = (*bp++ == '+') ? 1 : -1; spe = atoi(bp); while (digit(*bp)) bp++; while (*bp == ' ') bp++; l = 0; } else if (!strncmpi(bp, "blessed ", l = 8) || !strncmpi(bp, "holy ", l = 5)) { blessed = 1; } else if (!strncmpi(bp, "moist ", l = 6) || !strncmpi(bp, "wet ", l = 4)) { if (!strncmpi(bp, "wet ", 4)) wetness = rn2(3) + 3; else wetness = rnd(2); } else if (!strncmpi(bp, "cursed ", l = 7) || !strncmpi(bp, "unholy ", l = 7)) { iscursed = 1; } else if (!strncmpi(bp, "uncursed ", l = 9)) { uncursed = 1; } else if (!strncmpi(bp, "rustproof ", l = 10) || !strncmpi(bp, "erodeproof ", l = 11) || !strncmpi(bp, "corrodeproof ", l = 13) || !strncmpi(bp, "fixed ", l = 6) || !strncmpi(bp, "fireproof ", l = 10) || !strncmpi(bp, "rotproof ", l = 9)) { erodeproof = 1; } else if (!strncmpi(bp, "lit ", l = 4) || !strncmpi(bp, "burning ", l = 8)) { islit = 1; } else if (!strncmpi(bp, "unlit ", l = 6) || !strncmpi(bp, "extinguished ", l = 13)) { islit = 0; /* "unlabeled" and "blank" are synonymous */ } else if (!strncmpi(bp, "unlabeled ", l = 10) || !strncmpi(bp, "unlabelled ", l = 11) || !strncmpi(bp, "blank ", l = 6)) { unlabeled = 1; } else if (!strncmpi(bp, "poisoned ", l = 9)) { ispoisoned = 1; /* "trapped" recognized but not honored outside wizard mode */ } else if (!strncmpi(bp, "trapped ", l = 8)) { trapped = 0; /* undo any previous "untrapped" */ if (wizard) trapped = 1; } else if (!strncmpi(bp, "untrapped ", l = 10)) { trapped = 2; /* not trapped */ } else if (!strncmpi(bp, "greased ", l = 8)) { isgreased = 1; } else if (!strncmpi(bp, "very ", l = 5)) { /* very rusted very heavy iron ball */ very = 1; } else if (!strncmpi(bp, "thoroughly ", l = 11)) { very = 2; } else if (!strncmpi(bp, "rusty ", l = 6) || !strncmpi(bp, "rusted ", l = 7) || !strncmpi(bp, "burnt ", l = 6) || !strncmpi(bp, "burned ", l = 7)) { eroded = 1 + very; very = 0; } else if (!strncmpi(bp, "corroded ", l = 9) || !strncmpi(bp, "rotted ", l = 7)) { eroded2 = 1 + very; very = 0; } else if (!strncmpi(bp, "partly eaten ", l = 13) || !strncmpi(bp, "partially eaten ", l = 16)) { halfeaten = 1; } else if (!strncmpi(bp, "historic ", l = 9)) { ishistoric = 1; } else if (!strncmpi(bp, "diluted ", l = 8)) { isdiluted = 1; } else if (!strncmpi(bp, "empty ", l = 6)) { contents = EMPTY; } else break; bp += l; } if (!cnt) cnt = 1; /* %% what with "gems" etc. ? */ if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) { boolean keeptrailingchars = TRUE; p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */ ++p; /* advance past '(' */ if (!strncmpi(p, "lit)", 4)) { islit = 1; p += 4 - 1; /* point at ')' */ } else { spe = atoi(p); while (digit(*p)) p++; if (*p == ':') { p++; rechrg = spe; spe = atoi(p); while (digit(*p)) p++; } if (*p != ')') { spe = rechrg = 0; /* mis-matched parentheses; rest of string will be ignored * [probably we should restore everything back to '(' * instead since it might be part of "named ..."] */ keeptrailingchars = FALSE; } else { spesgn = 1; } } if (keeptrailingchars) { char *pp = eos(bp); /* 'pp' points at 'pb's terminating '\0', 'p' points at ')' and will be incremented past it */ do { *pp++ = *++p; } while (*p); } } /* * otmp->spe is type schar, so we don't want spe to be any bigger or * smaller. Also, spe should always be positive --some cheaters may * try to confuse atoi(). */ if (spe < 0) { spesgn = -1; /* cheaters get what they deserve */ spe = abs(spe); } if (spe > SCHAR_LIM) spe = SCHAR_LIM; if (rechrg < 0 || rechrg > 7) rechrg = 7; /* recharge_limit */ /* now we have the actual name, as delivered by xname, say * green potions called whisky * scrolls labeled "QWERTY" * egg * fortune cookies * very heavy iron ball named hoei * wand of wishing * elven cloak */ if ((p = strstri(bp, " named ")) != 0) { *p = 0; name = p + 7; } if ((p = strstri(bp, " called ")) != 0) { *p = 0; un = p + 8; /* "helmet called telepathy" is not "helmet" (a specific type) * "shield called reflection" is not "shield" (a general type) */ for (i = 0; i < SIZE(o_ranges); i++) if (!strcmpi(bp, o_ranges[i].name)) { oclass = o_ranges[i].oclass; goto srch; } } if ((p = strstri(bp, " labeled ")) != 0) { *p = 0; dn = p + 9; } else if ((p = strstri(bp, " labelled ")) != 0) { *p = 0; dn = p + 10; } if ((p = strstri(bp, " of spinach")) != 0) { *p = 0; contents = SPINACH; } /* Skip over "pair of ", "pairs of", "set of" and "sets of". Accept "3 pair of boots" as well as "3 pairs of boots". It is valid English either way. See makeplural() for more on pair/pairs. We should only double count if the object in question is not referred to as a "pair of". E.g. We should double if the player types "pair of spears", but not if the player types "pair of lenses". Luckily (?) all objects that are referred to as pairs -- boots, gloves, and lenses -- are also not mergable, so cnt is ignored anyway. */ if (!strncmpi(bp, "pair of ", 8)) { bp += 8; cnt *= 2; } else if (cnt > 1 && !strncmpi(bp, "pairs of ", 9)) { bp += 9; cnt *= 2; } else if (!strncmpi(bp, "set of ", 7)) { bp += 7; } else if (!strncmpi(bp, "sets of ", 8)) { bp += 8; } /* intercept pudding globs here; they're a valid wish target, * but we need them to not get treated like a corpse. * * also don't let player wish for multiple globs. */ if ((p = strstri(bp, "glob of ")) != 0 || (p = strstri(bp, "globs of ")) != 0) { int globoffset = (*(p + 4) == 's') ? 9 : 8; if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE && mntmp <= PM_BLACK_PUDDING) { mntmp = NON_PM; /* lie to ourselves */ cnt = 0; /* force only one */ } } else { /* * Find corpse type using "of" (figurine of an orc, tin of orc meat) * Don't check if it's a wand or spellbook. * (avoid "wand/finger of death" confusion). */ if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ") && !strstri(bp, "finger ")) { if (((p = strstri(bp, "tin of ")) != 0) && (tmp = tin_variety_txt(p + 7, &tinv)) && (mntmp = name_to_mon(p + 7 + tmp)) >= LOW_PM) { *(p + 3) = 0; tvariety = tinv; } else if ((p = strstri(bp, " of ")) != 0 && (mntmp = name_to_mon(p + 4)) >= LOW_PM) *p = 0; } } /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */ if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */ if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */ if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */ if (strncmpi(bp, "master key", 10)) /* not the "master" rank */ if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */ if (mntmp < LOW_PM && strlen(bp) > 2 && (mntmp = name_to_mon(bp)) >= LOW_PM) { int mntmptoo, mntmplen; /* double check for rank title */ char *obp = bp; mntmptoo = title_to_mon(bp, (int *) 0, &mntmplen); bp += mntmp != mntmptoo ? (int) strlen(mons[mntmp].mname) : mntmplen; if (*bp == ' ') bp++; else if (!strncmpi(bp, "s ", 2)) bp += 2; else if (!strncmpi(bp, "es ", 3)) bp += 3; else if (!*bp && !actualn && !dn && !un && !oclass) { /* no referent; they don't really mean a * monster type */ bp = obp; mntmp = NON_PM; } } /* first change to singular if necessary */ if (*bp) { char *sng = makesingular(bp); if (strcmp(bp, sng)) { if (cnt == 1) cnt = 2; Strcpy(bp, sng); } } /* Alternate spellings (pick-ax, silver sabre, &c) */ { struct alt_spellings *as = spellings; while (as->sp) { if (fuzzymatch(bp, as->sp, " -", TRUE)) { typ = as->ob; goto typfnd; } as++; } /* can't use spellings list for this one due to shuffling */ if (!strncmpi(bp, "grey spell", 10)) *(bp + 2) = 'a'; if ((p = strstri(bp, "armour")) != 0) { /* skip past "armo", then copy remainder beyond "u" */ p += 4; while ((*p = *(p + 1)) != '\0') ++p; /* self terminating */ } } /* dragon scales - assumes order of dragons */ if (!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) { typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON; mntmp = NON_PM; /* no monster */ goto typfnd; } p = eos(bp); if (!BSTRCMPI(bp, p - 10, "holy water")) { typ = POT_WATER; if ((p - bp) >= 12 && *(p - 12) == 'u') iscursed = 1; /* unholy water */ else blessed = 1; goto typfnd; } if (unlabeled && !BSTRCMPI(bp, p - 6, "scroll")) { typ = SCR_BLANK_PAPER; goto typfnd; } if (unlabeled && !BSTRCMPI(bp, p - 9, "spellbook")) { typ = SPE_BLANK_PAPER; goto typfnd; } /* * NOTE: Gold pieces are handled as objects nowadays, and therefore * this section should probably be reconsidered as well as the entire * gold/money concept. Maybe we want to add other monetary units as * well in the future. (TH) */ if (!BSTRCMPI(bp, p - 10, "gold piece") || !BSTRCMPI(bp, p - 7, "zorkmid") || !strcmpi(bp, "gold") || !strcmpi(bp, "money") || !strcmpi(bp, "coin") || *bp == GOLD_SYM) { if (cnt > 5000 && !wizard) cnt = 5000; else if (cnt < 1) cnt = 1; otmp = mksobj(GOLD_PIECE, FALSE, FALSE); otmp->quan = (long) cnt; otmp->owt = weight(otmp); context.botl = 1; return otmp; } /* check for single character object class code ("/" for wand, &c) */ if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) { oclass = i; goto any; } /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */ /* false hits on, e.g., rings for "ring mail". */ if (strncmpi(bp, "enchant ", 8) && strncmpi(bp, "destroy ", 8) && strncmpi(bp, "detect food", 11) && strncmpi(bp, "food detection", 14) && strncmpi(bp, "ring mail", 9) && strncmpi(bp, "studded leather armor", 21) && strncmpi(bp, "leather armor", 13) && strncmpi(bp, "tooled horn", 11) && strncmpi(bp, "food ration", 11) && strncmpi(bp, "meat ring", 9)) for (i = 0; i < (int) (sizeof wrpsym); i++) { register int j = strlen(wrp[i]); if (!strncmpi(bp, wrp[i], j)) { oclass = wrpsym[i]; if (oclass != AMULET_CLASS) { bp += j; if (!strncmpi(bp, " of ", 4)) actualn = bp + 4; /* else if(*bp) ?? */ } else actualn = bp; goto srch; } if (!BSTRCMPI(bp, p - j, wrp[i])) { oclass = wrpsym[i]; p -= j; *p = 0; if (p > bp && p[-1] == ' ') p[-1] = 0; actualn = dn = bp; goto srch; } } /* Wishing in wizard mode can create traps and furniture. * Part I: distinguish between trap and object for the two * types of traps which have corresponding objects: bear trap * and land mine. "beartrap" (object) and "bear trap" (trap) * have a difference in spelling which we used to exploit by * adding a special case in wishymatch(), but "land mine" is * spelled the same either way so needs different handing. * Since we need something else for land mine, we've dropped * the bear trap hack so that both are handled exactly the * same. To get an armed trap instead of a disarmed object, * the player can prefix either the object name or the trap * name with "trapped " (which ordinarily applies to chests * and tins), or append something--anything at all except for * " object", but " trap" is suggested--to either the trap * name or the object name. */ if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) { boolean beartrap = (lowc(*bp) == 'b'); char *zp = bp + 4; /* skip "bear"/"land" */ if (*zp == ' ') ++zp; /* embedded space is optional */ if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) { zp += 4; if (trapped == 2 || !strcmpi(zp, " object")) { /* "untrapped " or " object" */ typ = beartrap ? BEARTRAP : LAND_MINE; goto typfnd; } else if (trapped == 1 || *zp != '\0') { /* "trapped " or " trap" (actually "*") */ int idx = trap_to_defsym(beartrap ? BEAR_TRAP : LANDMINE); /* use canonical trap spelling, skip object matching */ Strcpy(bp, defsyms[idx].explanation); goto wiztrap; } /* [no prefix or suffix; we're going to end up matching the object name and getting a disarmed trap object] */ } } retry: /* "grey stone" check must be before general "stone" */ for (i = 0; i < SIZE(o_ranges); i++) if (!strcmpi(bp, o_ranges[i].name)) { typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range); goto typfnd; } if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) { p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0'; oclass = GEM_CLASS; dn = actualn = bp; goto srch; } else if (!strcmpi(bp, "looking glass")) { ; /* avoid false hit on "* glass" */ } else if (!BSTRCMPI(bp, p - 6, " glass") || !strcmpi(bp, "glass")) { register char *g = bp; if (strstri(g, "broken")) return (struct obj *) 0; if (!strncmpi(g, "worthless ", 10)) g += 10; if (!strncmpi(g, "piece of ", 9)) g += 9; if (!strncmpi(g, "colored ", 8)) g += 8; else if (!strncmpi(g, "coloured ", 9)) g += 9; if (!strcmpi(g, "glass")) { /* choose random color */ /* 9 different kinds */ typ = LAST_GEM + rnd(9); if (objects[typ].oc_class == GEM_CLASS) goto typfnd; else typ = 0; /* somebody changed objects[]? punt */ } else { /* try to construct canonical form */ char tbuf[BUFSZ]; Strcpy(tbuf, "worthless piece of "); Strcat(tbuf, g); /* assume it starts with the color */ Strcpy(bp, tbuf); } } actualn = bp; if (!dn) dn = actualn; /* ex. "skull cap" */ srch: /* check real names of gems first */ if (!oclass && actualn) { for (i = bases[GEM_CLASS]; i <= LAST_GEM; i++) { register const char *zn; if ((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) { typ = i; goto typfnd; } } } i = oclass ? bases[(int) oclass] : 1; while (i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)) { register const char *zn; if (actualn && (zn = OBJ_NAME(objects[i])) != 0 && wishymatch(actualn, zn, TRUE)) { typ = i; goto typfnd; } if (dn && (zn = OBJ_DESCR(objects[i])) != 0 && wishymatch(dn, zn, FALSE)) { /* don't match extra descriptions (w/o real name) */ if (!OBJ_NAME(objects[i])) return (struct obj *) 0; typ = i; goto typfnd; } if (un && (zn = objects[i].oc_uname) != 0 && wishymatch(un, zn, FALSE)) { typ = i; goto typfnd; } i++; } if (actualn) { struct Jitem *j = Japanese_items; while (j->item) { if (actualn && !strcmpi(actualn, j->name)) { typ = j->item; goto typfnd; } j++; } } /* if we've stripped off "armor" and failed to match anything in objects[], append "mail" and try again to catch misnamed requests like "plate armor" and "yellow dragon scale armor" */ if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) { /* modifying bp's string is ok; we're about to resort to random armor if this also fails to match anything */ Strcat(bp, " mail"); goto retry; } if (!strcmpi(bp, "spinach")) { contents = SPINACH; typ = TIN; goto typfnd; } /* Note: not strcmpi. 2 fruits, one capital, one not, are possible. Also not strncmp. We used to ignore trailing text with it, but that resulted in "grapefruit" matching "grape" if the latter came earlier than the former in the fruit list. */ { char *fp; int l, cntf; int blessedf, iscursedf, uncursedf, halfeatenf; blessedf = iscursedf = uncursedf = halfeatenf = 0; cntf = 0; fp = fruitbuf; for (;;) { if (!fp || !*fp) break; if (!strncmpi(fp, "an ", l = 3) || !strncmpi(fp, "a ", l = 2)) { cntf = 1; } else if (!cntf && digit(*fp)) { cntf = atoi(fp); while (digit(*fp)) fp++; while (*fp == ' ') fp++; l = 0; } else if (!strncmpi(fp, "blessed ", l = 8)) { blessedf = 1; } else if (!strncmpi(fp, "cursed ", l = 7)) { iscursedf = 1; } else if (!strncmpi(fp, "uncursed ", l = 9)) { uncursedf = 1; } else if (!strncmpi(fp, "partly eaten ", l = 13) || !strncmpi(fp, "partially eaten ", l = 16)) { halfeatenf = 1; } else break; fp += l; } for (f = ffruit; f; f = f->nextf) { /* match type: 0=none, 1=exact, 2=singular, 3=plural */ int ftyp = 0; if (!strcmp(fp, f->fname)) ftyp = 1; else if (!strcmp(fp, makesingular(f->fname))) ftyp = 2; else if (!strcmp(fp, makeplural(f->fname))) ftyp = 3; if (ftyp) { typ = SLIME_MOLD; blessed = blessedf; iscursed = iscursedf; uncursed = uncursedf; halfeaten = halfeatenf; /* adjust count if user explicitly asked for singular amount (can't happen unless fruit has been given an already pluralized name) or for plural amount */ if (ftyp == 2 && !cntf) cntf = 1; else if (ftyp == 3 && !cntf) cntf = 2; cnt = cntf; ftype = f->fid; goto typfnd; } } } if (!oclass && actualn) { short objtyp; /* Perhaps it's an artifact specified by name, not type */ name = artifact_name(actualn, &objtyp); if (name) { typ = objtyp; goto typfnd; } } /* Let wizards wish for traps and furniture. * Must come after objects check so wizards can still wish for * trap objects like beartraps. * Disallow such topology tweaks for WIZKIT startup wishes. */ wiztrap: if (wizard && !program_state.wizkit_wishing) { struct rm *lev; int trap, x = u.ux, y = u.uy; for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) { struct trap *t; const char *tname; tname = defsyms[trap_to_defsym(trap)].explanation; if (strncmpi(tname, bp, strlen(tname))) continue; /* found it; avoid stupid mistakes */ if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz)) trap = ROCKTRAP; if ((t = maketrap(x, y, trap)) != 0) { trap = t->ttyp; tname = defsyms[trap_to_defsym(trap)].explanation; pline("%s%s.", An(tname), (trap != MAGIC_PORTAL) ? "" : " to nowhere"); } else pline("Creation of %s failed.", an(tname)); return &zeroobj; } /* furniture and terrain */ lev = &levl[x][y]; p = eos(bp); if (!BSTRCMPI(bp, p - 8, "fountain")) { lev->typ = FOUNTAIN; level.flags.nfountains++; if (!strncmpi(bp, "magic ", 6)) lev->blessedftn = 1; pline("A %sfountain.", lev->blessedftn ? "magic " : ""); newsym(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 6, "throne")) { lev->typ = THRONE; pline("A throne."); newsym(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 4, "sink")) { lev->typ = SINK; level.flags.nsinks++; pline("A sink."); newsym(x, y); return &zeroobj; } /* ("water" matches "potion of water" rather than terrain) */ if (!BSTRCMPI(bp, p - 4, "pool") || !BSTRCMPI(bp, p - 4, "moat")) { lev->typ = !BSTRCMPI(bp, p - 4, "pool") ? POOL : MOAT; del_engr_at(x, y); pline("A %s.", (lev->typ == POOL) ? "pool" : "moat"); /* Must manually make kelp! */ water_damage_chain(level.objects[x][y], TRUE); newsym(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 4, "lava")) { /* also matches "molten lava" */ lev->typ = LAVAPOOL; del_engr_at(x, y); pline("A pool of molten lava."); if (!(Levitation || Flying)) (void) lava_effects(); newsym(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 5, "altar")) { aligntyp al; lev->typ = ALTAR; if (!strncmpi(bp, "chaotic ", 8)) al = A_CHAOTIC; else if (!strncmpi(bp, "neutral ", 8)) al = A_NEUTRAL; else if (!strncmpi(bp, "lawful ", 7)) al = A_LAWFUL; else if (!strncmpi(bp, "unaligned ", 10)) al = A_NONE; else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */ al = (!rn2(6)) ? A_NONE : rn2((int) A_LAWFUL + 2) - 1; lev->altarmask = Align2amask(al); pline("%s altar.", An(align_str(al))); newsym(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 5, "grave") || !BSTRCMPI(bp, p - 9, "headstone")) { make_grave(x, y, (char *) 0); pline("%s.", IS_GRAVE(lev->typ) ? "A grave" : "Can't place a grave here"); newsym(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 4, "tree")) { lev->typ = TREE; pline("A tree."); newsym(x, y); block_point(x, y); return &zeroobj; } if (!BSTRCMPI(bp, p - 4, "bars")) { lev->typ = IRONBARS; pline("Iron bars."); newsym(x, y); return &zeroobj; } } if (!oclass && !typ) { if (!strncmpi(bp, "polearm", 7)) { typ = rnd_otyp_by_wpnskill(P_POLEARMS); goto typfnd; } else if (!strncmpi(bp, "hammer", 6)) { typ = rnd_otyp_by_wpnskill(P_HAMMER); goto typfnd; } } if (!oclass) return ((struct obj *) 0); any: if (!oclass) oclass = wrpsym[rn2((int) sizeof(wrpsym))]; typfnd: if (typ) oclass = objects[typ].oc_class; /* handle some objects that are only allowed in wizard mode */ if (typ && !wizard) { switch (typ) { case AMULET_OF_YENDOR: typ = FAKE_AMULET_OF_YENDOR; break; case CANDELABRUM_OF_INVOCATION: typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE); break; case BELL_OF_OPENING: typ = BELL; break; case SPE_BOOK_OF_THE_DEAD: typ = SPE_BLANK_PAPER; break; case MAGIC_LAMP: typ = OIL_LAMP; break; default: /* catch any other non-wishable objects (venom) */ if (objects[typ].oc_nowish) return (struct obj *) 0; break; } } /* * Create the object, then fine-tune it. */ otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE); typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */ if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN || Is_candle(otmp) || typ == POT_OIL)) { place_object(otmp, u.ux, u.uy); /* make it viable light source */ begin_burn(otmp, FALSE); obj_extract_self(otmp); /* now release it for caller's use */ } /* if player specified a reasonable count, maybe honor it */ if (cnt > 0 && objects[typ].oc_merge && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp)) || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp)) || typ == ROCK || is_missile(otmp))))) otmp->quan = (long) cnt; if (oclass == VENOM_CLASS) otmp->spe = 1; if (spesgn == 0) { spe = otmp->spe; } else if (wizard) { ; /* no alteration to spe */ } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS || is_weptool(otmp) || (oclass == RING_CLASS && objects[typ].oc_charged)) { if (spe > rnd(5) && spe > otmp->spe) spe = 0; if (spe > 2 && Luck < 0) spesgn = -1; } else { if (oclass == WAND_CLASS) { if (spe > 1 && spesgn == -1) spe = 1; } else { if (spe > 0 && spesgn == -1) spe = 0; } if (spe > otmp->spe) spe = otmp->spe; } if (spesgn == -1) spe = -spe; /* set otmp->spe. This may, or may not, use spe... */ switch (typ) { case TIN: if (contents == EMPTY) { otmp->corpsenm = NON_PM; otmp->spe = 0; } else if (contents == SPINACH) { otmp->corpsenm = NON_PM; otmp->spe = 1; } break; case TOWEL: if (wetness) otmp->spe = wetness; break; case SLIME_MOLD: otmp->spe = ftype; /* Fall through */ case SKELETON_KEY: case CHEST: case LARGE_BOX: case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE: /* otmp->cobj already done in mksobj() */ break; #ifdef MAIL case SCR_MAIL: otmp->spe = 1; break; #endif case WAN_WISHING: if (!wizard) { otmp->spe = (rn2(10) ? -1 : 0); break; } /* fall through, if wizard */ default: otmp->spe = spe; } /* set otmp->corpsenm or dragon scale [mail] */ if (mntmp >= LOW_PM) { if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM; switch (typ) { case TIN: otmp->spe = 0; /* No spinach */ if (dead_species(mntmp, FALSE)) { otmp->corpsenm = NON_PM; /* it's empty */ } else if (!(mons[mntmp].geno & G_UNIQ) && !(mvitals[mntmp].mvflags & G_NOCORPSE) && mons[mntmp].cnutrit != 0) { otmp->corpsenm = mntmp; } break; case CORPSE: if (!(mons[mntmp].geno & G_UNIQ) && !(mvitals[mntmp].mvflags & G_NOCORPSE)) { if (mons[mntmp].msound == MS_GUARDIAN) mntmp = genus(mntmp, 1); set_corpsenm(otmp, mntmp); } break; case FIGURINE: if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp]) #ifdef MAIL && mntmp != PM_MAIL_DAEMON #endif ) otmp->corpsenm = mntmp; break; case EGG: mntmp = can_be_hatched(mntmp); /* this also sets hatch timer if appropriate */ set_corpsenm(otmp, mntmp); break; case STATUE: otmp->corpsenm = mntmp; if (Has_contents(otmp) && verysmall(&mons[mntmp])) delete_contents(otmp); /* no spellbook */ otmp->spe = ishistoric ? STATUE_HISTORIC : 0; break; case SCALE_MAIL: /* Dragon mail - depends on the order of objects & dragons. */ if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON; break; } } /* set blessed/cursed -- setting the fields directly is safe * since weight() is called below and addinv() will take care * of luck */ if (iscursed) { curse(otmp); } else if (uncursed) { otmp->blessed = 0; otmp->cursed = (Luck < 0 && !wizard); } else if (blessed) { otmp->blessed = (Luck >= 0 || wizard); otmp->cursed = (Luck < 0 && !wizard); } else if (spesgn < 0) { curse(otmp); } /* set eroded */ if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) { if (eroded && (is_flammable(otmp) || is_rustprone(otmp))) otmp->oeroded = eroded; if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp))) otmp->oeroded2 = eroded2; /* set erodeproof */ if (erodeproof && !eroded && !eroded2) otmp->oerodeproof = (Luck >= 0 || wizard); } /* set otmp->recharged */ if (oclass == WAND_CLASS) { /* prevent wishing abuse */ if (otmp->otyp == WAN_WISHING && !wizard) rechrg = 1; otmp->recharged = (unsigned) rechrg; } /* set poisoned */ if (ispoisoned) { if (is_poisonable(otmp)) otmp->opoisoned = (Luck >= 0); else if (oclass == FOOD_CLASS) /* try to taint by making it as old as possible */ otmp->age = 1L; } /* and [un]trapped */ if (trapped) { if (Is_box(otmp) || typ == TIN) otmp->otrapped = (trapped == 1); } if (isgreased) otmp->greased = 1; if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER) otmp->odiluted = 1; /* set tin variety */ if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard)) set_tin_variety(otmp, tvariety); if (name) { const char *aname; short objtyp; /* an artifact name might need capitalization fixing */ aname = artifact_name(name, &objtyp); if (aname && objtyp == otmp->otyp) name = aname; /* 3.6.0 tribute - fix up novel */ if (otmp->otyp == SPE_NOVEL) { const char *novelname; novelname = lookup_novel(name, &otmp->novelidx); if (novelname) name = novelname; } otmp = oname(otmp, name); if (otmp->oartifact) { otmp->quan = 1L; u.uconduct.wisharti++; /* KMH, conduct */ } } /* more wishing abuse: don't allow wishing for certain artifacts */ /* and make them pay; charge them for the wish anyway! */ if ((is_quest_artifact(otmp) || (otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) { artifact_exists(otmp, safe_oname(otmp), FALSE); obfree(otmp, (struct obj *) 0); otmp = &zeroobj; pline("For a moment, you feel %s in your %s, but it disappears!", something, makeplural(body_part(HAND))); } if (halfeaten && otmp->oclass == FOOD_CLASS) { if (otmp->otyp == CORPSE) otmp->oeaten = mons[otmp->corpsenm].cnutrit; else otmp->oeaten = objects[otmp->otyp].oc_nutrition; /* (do this adjustment before setting up object's weight) */ consume_oeaten(otmp, 1); } otmp->owt = weight(otmp); if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160; return otmp; } int rnd_class(first, last) int first, last; { int i, x, sum = 0; if (first == last) return first; for (i = first; i <= last; i++) sum += objects[i].oc_prob; if (!sum) /* all zero */ return first + rn2(last - first + 1); x = rnd(sum); for (i = first; i <= last; i++) if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0) return i; return 0; } STATIC_OVL const char * Japanese_item_name(i) int i; { struct Jitem *j = Japanese_items; while (j->item) { if (i == j->item) return j->name; j++; } return (const char *) 0; } const char * suit_simple_name(suit) struct obj *suit; { const char *suitnm, *esuitp; if (Is_dragon_mail(suit)) return "dragon mail"; /* dragon scale mail */ else if (Is_dragon_scales(suit)) return "dragon scales"; suitnm = OBJ_NAME(objects[suit->otyp]); esuitp = eos((char *) suitnm); if (strlen(suitnm) > 5 && !strcmp(esuitp - 5, " mail")) return "mail"; /* most suits fall into this category */ else if (strlen(suitnm) > 7 && !strcmp(esuitp - 7, " jacket")) return "jacket"; /* leather jacket */ /* suit is lame but armor is ambiguous and body armor is absurd */ return "suit"; } const char * cloak_simple_name(cloak) struct obj *cloak; { if (cloak) { switch (cloak->otyp) { case ROBE: return "robe"; case MUMMY_WRAPPING: return "wrapping"; case ALCHEMY_SMOCK: return (objects[cloak->otyp].oc_name_known && cloak->dknown) ? "smock" : "apron"; default: break; } } return "cloak"; } /* helm vs hat for messages */ const char * helm_simple_name(helmet) struct obj *helmet; { /* * There is some wiggle room here; the result has been chosen * for consistency with the "protected by hard helmet" messages * given for various bonks on the head: headgear that provides * such protection is a "helm", that which doesn't is a "hat". * * elven leather helm / leather hat -> hat * dwarvish iron helm / hard hat -> helm * The rest are completely straightforward: * fedora, cornuthaum, dunce cap -> hat * all other types of helmets -> helm */ return (helmet && !is_metallic(helmet)) ? "hat" : "helm"; } const char * mimic_obj_name(mtmp) struct monst *mtmp; { if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) { int idx = objects[mtmp->mappearance].oc_descr_idx; if (mtmp->mappearance == GOLD_PIECE) return "gold"; return obj_descr[idx].oc_name; } return "whatcha-may-callit"; } /* * Construct a query prompt string, based around an object name, which is * guaranteed to fit within [QBUFSZ]. Takes an optional prefix, three * choices for filling in the middle (two object formatting functions and a * last resort literal which should be very short), and an optional suffix. */ char * safe_qbuf(qbuf, qprefix, qsuffix, obj, func, altfunc, lastR) char *qbuf; /* output buffer */ const char *qprefix, *qsuffix; struct obj *obj; char *FDECL((*func), (OBJ_P)), *FDECL((*altfunc), (OBJ_P)); const char *lastR; { char *bufp, *endp; /* convert size_t (or int for ancient systems) to ordinary unsigned */ unsigned len, lenlimit, len_qpfx = (unsigned) (qprefix ? strlen(qprefix) : 0), len_qsfx = (unsigned) (qsuffix ? strlen(qsuffix) : 0), len_lastR = (unsigned) strlen(lastR); lenlimit = QBUFSZ - 1; endp = qbuf + lenlimit; /* sanity check, aimed mainly at paniclog (it's conceivable for the result of short_oname() to be shorter than the length of the last resort string, but we ignore that possibility here) */ if (len_qpfx > lenlimit) impossible("safe_qbuf: prefix too long (%u characters).", len_qpfx); else if (len_qpfx + len_qsfx > lenlimit) impossible("safe_qbuf: suffix too long (%u + %u characters).", len_qpfx, len_qsfx); else if (len_qpfx + len_lastR + len_qsfx > lenlimit) impossible("safe_qbuf: filler too long (%u + %u + %u characters).", len_qpfx, len_lastR, len_qsfx); /* the output buffer might be the same as the prefix if caller has already partially filled it */ if (qbuf == qprefix) { /* prefix is already in the buffer */ *endp = '\0'; } else if (qprefix) { /* put prefix into the buffer */ (void) strncpy(qbuf, qprefix, lenlimit); *endp = '\0'; } else { /* no prefix; output buffer starts out empty */ qbuf[0] = '\0'; } len = (unsigned) strlen(qbuf); if (len + len_lastR + len_qsfx > lenlimit) { /* too long; skip formatting, last resort output is truncated */ if (len < lenlimit) { (void) strncpy(&qbuf[len], lastR, lenlimit - len); *endp = '\0'; len = (unsigned) strlen(qbuf); if (qsuffix && len < lenlimit) { (void) strncpy(&qbuf[len], qsuffix, lenlimit - len); *endp = '\0'; /* len = (unsigned) strlen(qbuf); */ } } } else { /* suffix and last resort are guaranteed to fit */ len += len_qsfx; /* include the pending suffix */ /* format the object */ bufp = short_oname(obj, func, altfunc, lenlimit - len); if (len + strlen(bufp) <= lenlimit) Strcat(qbuf, bufp); /* formatted name fits */ else Strcat(qbuf, lastR); /* use last resort */ releaseobuf(bufp); if (qsuffix) Strcat(qbuf, qsuffix); } /* assert( strlen(qbuf) < QBUFSZ ); */ return qbuf; } /*objnam.c*/ nethack-3.6.0/src/options.c0000664000076400007660000057311012624522452014576 0ustar paxedpaxed/* NetHack 3.6 options.c $NHDT-Date: 1448241657 2015/11/23 01:20:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.243 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */ #include "config.h" #include "objclass.h" #include "flag.h" NEARDATA struct flag flags; /* provide linkage */ #ifdef SYSFLAGS NEARDATA struct sysflag sysflags; /* provide linkage */ #endif NEARDATA struct instance_flags iflags; /* provide linkage */ #define static #else #include "hack.h" #include "tcap.h" #include #endif #define BACKWARD_COMPAT #define WINTYPELEN 16 #ifdef DEFAULT_WC_TILED_MAP #define PREFER_TILED TRUE #else #define PREFER_TILED FALSE #endif #define MESSAGE_OPTION 1 #define STATUS_OPTION 2 #define MAP_OPTION 3 #define MENU_OPTION 4 #define TEXT_OPTION 5 #define PILE_LIMIT_DFLT 5 /* * NOTE: If you add (or delete) an option, please update the short * options help (option_help()), the long options help (dat/opthelp), * and the current options setting display function (doset()), * and also the Guidebooks. * * The order matters. If an option is a an initial substring of another * option (e.g. time and timed_delay) the shorter one must come first. */ static struct Bool_Opt { const char *name; boolean *addr, initvalue; int optflags; } boolopt[] = { { "acoustics", &flags.acoustics, TRUE, SET_IN_GAME }, #if defined(SYSFLAGS) && defined(AMIGA) /* Amiga altmeta causes Alt+key to be converted into Meta+key by low level nethack code; on by default, can be toggled off if Alt+key is needed for some ASCII chars on non-ASCII keyboard */ { "altmeta", &sysflags.altmeta, TRUE, DISP_IN_GAME }, #else #ifdef ALTMETA /* non-Amiga altmeta causes nethack's top level command loop to treat two character sequence "ESC c" as M-c, for terminals or emulators which send "ESC c" when Alt+c is pressed; off by default, enabling this can potentially make trouble if user types ESC when nethack is honoring this conversion request (primarily after starting a count prefix prior to a command and then deciding to cancel it) */ { "altmeta", &iflags.altmeta, FALSE, SET_IN_GAME }, #else { "altmeta", (boolean *) 0, TRUE, DISP_IN_GAME }, #endif #endif { "ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME }, /*WC*/ #if defined(SYSFLAGS) && defined(MFLOPPY) { "asksavedisk", &sysflags.asksavedisk, FALSE, SET_IN_GAME }, #else { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "autodig", &flags.autodig, FALSE, SET_IN_GAME }, { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME }, { "autopickup", &flags.pickup, TRUE, SET_IN_GAME }, { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME }, #if defined(MICRO) && !defined(AMIGA) { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE }, #else { "BIOS", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "blind", &u.uroleplay.blind, FALSE, DISP_IN_GAME }, { "bones", &flags.bones, TRUE, SET_IN_FILE }, #ifdef INSURANCE { "checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME }, #else { "checkpoint", (boolean *) 0, FALSE, SET_IN_FILE }, #endif #ifdef MFLOPPY { "checkspace", &iflags.checkspace, TRUE, SET_IN_GAME }, #else { "checkspace", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "clicklook", &iflags.clicklook, FALSE, SET_IN_GAME }, { "cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME }, #if defined(MICRO) || defined(WIN32) { "color", &iflags.wc_color, TRUE, SET_IN_GAME }, /*WC*/ #else /* systems that support multiple terminals, many monochrome */ { "color", &iflags.wc_color, FALSE, SET_IN_GAME }, /*WC*/ #endif { "confirm", &flags.confirm, TRUE, SET_IN_GAME }, { "dark_room", &flags.dark_room, TRUE, SET_IN_GAME }, { "eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME }, /*WC*/ #ifdef TTY_GRAPHICS { "extmenu", &iflags.extmenu, FALSE, SET_IN_GAME }, #else { "extmenu", (boolean *) 0, FALSE, SET_IN_FILE }, #endif #ifdef OPT_DISPMAP { "fast_map", &flags.fast_map, TRUE, SET_IN_GAME }, #else { "fast_map", (boolean *) 0, TRUE, SET_IN_FILE }, #endif { "female", &flags.female, FALSE, DISP_IN_GAME }, { "fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME }, #if defined(SYSFLAGS) && defined(AMIFLUSH) { "flush", &sysflags.amiflush, FALSE, SET_IN_GAME }, #else { "flush", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE }, { "help", &flags.help, TRUE, SET_IN_GAME }, { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/ { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME }, #ifndef MAC { "ignintr", &flags.ignintr, FALSE, SET_IN_GAME }, #else { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME }, { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */ { "legacy", &flags.legacy, TRUE, DISP_IN_GAME }, { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME }, { "lootabc", &flags.lootabc, FALSE, SET_IN_GAME }, #ifdef MAIL { "mail", &flags.biff, TRUE, SET_IN_GAME }, #else { "mail", (boolean *) 0, TRUE, SET_IN_FILE }, #endif { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME }, { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME }, /* for menu debugging only*/ { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME }, { "menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME }, { "mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME }, /*WC*/ #ifdef NEWS { "news", &iflags.news, TRUE, DISP_IN_GAME }, #else { "news", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "nudist", &u.uroleplay.nudist, FALSE, DISP_IN_GAME }, { "null", &flags.null, TRUE, SET_IN_GAME }, #if defined(SYSFLAGS) && defined(MAC) { "page_wait", &sysflags.page_wait, TRUE, SET_IN_GAME }, #else { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME }, { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME }, { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME }, /*WC*/ { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/ { "pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME }, #if defined(MICRO) && !defined(AMIGA) { "rawio", &iflags.rawio, FALSE, DISP_IN_GAME }, #else { "rawio", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME }, #ifdef RLECOMP { "rlecomp", &iflags.rlecomp, #if defined(COMPRESS) || defined(ZLIB_COMP) FALSE, #else TRUE, #endif DISP_IN_GAME }, #endif { "safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME }, { "sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME }, { "selectsaved", &iflags.wc2_selectsaved, TRUE, DISP_IN_GAME }, /*WC*/ { "showexp", &flags.showexp, FALSE, SET_IN_GAME }, { "showrace", &flags.showrace, FALSE, SET_IN_GAME }, #ifdef SCORE_ON_BOTL { "showscore", &flags.showscore, FALSE, SET_IN_GAME }, #else { "showscore", (boolean *) 0, FALSE, SET_IN_FILE }, #endif { "silent", &flags.silent, TRUE, SET_IN_GAME }, { "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE }, { "sortpack", &flags.sortpack, TRUE, SET_IN_GAME }, { "sparkle", &flags.sparkle, TRUE, SET_IN_GAME }, { "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/ { "standout", &flags.standout, FALSE, SET_IN_GAME }, #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES) { "statushilites", &iflags.use_status_hilites, TRUE, SET_IN_GAME }, #else { "statushilites", &iflags.use_status_hilites, FALSE, DISP_IN_GAME }, #endif { "tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME }, /*WC*/ { "time", &flags.time, FALSE, SET_IN_GAME }, #ifdef TIMED_DELAY { "timed_delay", &flags.nap, TRUE, SET_IN_GAME }, #else { "timed_delay", (boolean *) 0, FALSE, SET_IN_GAME }, #endif { "tombstone", &flags.tombstone, TRUE, SET_IN_GAME }, { "toptenwin", &iflags.toptenwin, FALSE, SET_IN_GAME }, { "travel", &flags.travelcmd, TRUE, SET_IN_GAME }, { "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE }, #ifdef WIN32 { "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/ #else { "use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME }, /*WC*/ #endif { "verbose", &flags.verbose, TRUE, SET_IN_GAME }, { "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME }, #ifdef ZEROCOMP { "zerocomp", &iflags.zerocomp, #if defined(COMPRESS) || defined(ZLIB_COMP) FALSE, #else TRUE, #endif DISP_IN_GAME }, #endif { (char *) 0, (boolean *) 0, FALSE, 0 } }; /* compound options, for option_help() and external programs like Amiga * frontend */ static struct Comp_Opt { const char *name, *descr; int size; /* for frontends and such allocating space -- * usually allowed size of data in game, but * occasionally maximum reasonable size for * typing when game maintains information in * a different format */ int optflags; } compopt[] = { { "align", "your starting alignment (lawful, neutral, or chaotic)", 8, DISP_IN_GAME }, { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/ { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/ { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME }, #ifdef BACKWARD_COMPAT { "boulder", "deprecated (use S_boulder in sym file instead)", 1, SET_IN_FILE }, #endif { "catname", "the name of your (first) cat (e.g., catname:Tabby)", PL_PSIZ, DISP_IN_GAME }, { "disclose", "the kinds of information to disclose at end of game", sizeof(flags.end_disclose) * 2, SET_IN_GAME }, { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ, DISP_IN_GAME }, { "dungeon", "the symbols to use in drawing the dungeon map", MAXDCHARS + 1, SET_IN_FILE }, { "effects", "the symbols to use in drawing special effects", MAXECHARS + 1, SET_IN_FILE }, { "font_map", "the font to use in the map window", 40, DISP_IN_GAME }, /*WC*/ { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/ { "font_message", "the font to use in the message window", 40, DISP_IN_GAME }, /*WC*/ { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/ { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/ { "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/ { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME }, { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME }, { "horsename", "the name of your (first) horse (e.g., horsename:Silver)", PL_PSIZ, DISP_IN_GAME }, { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/ { "menustyle", "user interface for object selection", MENUTYPELEN, SET_IN_GAME }, { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE }, { "menu_deselect_page", "deselect all items on this page of a menu", 4, SET_IN_FILE }, { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE }, { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME }, { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE }, { "menu_invert_page", "invert all items on this page of a menu", 4, SET_IN_FILE }, { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE }, { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE }, { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE }, { "menu_search", "search for a menu item", 4, SET_IN_FILE }, { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE }, { "menu_select_page", "select all items on this page of a menu", 4, SET_IN_FILE }, { "monsters", "the symbols to use for monsters", MAXMCLASSES, SET_IN_FILE }, { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME }, #ifdef TTY_GRAPHICS { "msg_window", "the type of message window required", 1, SET_IN_GAME }, #else { "msg_window", "the type of message window required", 1, SET_IN_FILE }, #endif { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ, DISP_IN_GAME }, { "number_pad", "use the number pad for movement", 1, SET_IN_GAME }, { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE }, { "packorder", "the inventory order of the items in your pack", MAXOCLASSES, SET_IN_GAME }, #ifdef CHANGE_COLOR { "palette", #ifndef WIN32 "palette (00c/880/-fff is blue/yellow/reverse white)", 15, SET_IN_GAME }, #else "palette (adjust an RGB color in palette (color-R-G-B)", 15, SET_IN_FILE }, #endif #if defined(MAC) { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE }, #endif #endif { "paranoid_confirmation", "extra prompting in certain situations", 28, SET_IN_GAME }, { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME }, { "pickup_burden", "maximum burden picked up before prompt", 20, SET_IN_GAME }, { "pickup_types", "types of objects to pick up automatically", MAXOCLASSES, SET_IN_GAME }, { "pile_limit", "threshold for \"there are many objects here\"", 24, SET_IN_GAME }, { "playmode", "normal play, non-scoring explore mode, or debug mode", 8, DISP_IN_GAME }, { "player_selection", "choose character via dialog or prompts", 12, DISP_IN_GAME }, { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ, DISP_IN_GAME }, { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ, DISP_IN_GAME }, { "runmode", "display frequency when `running' or `travelling'", sizeof "teleport", SET_IN_GAME }, { "scores", "the parts of the score list you wish to see", 32, SET_IN_GAME }, { "scroll_amount", "amount to scroll map when scroll_margin is reached", 20, DISP_IN_GAME }, /*WC*/ { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/ { "sortloot", "sort object selection lists by description", 4, SET_IN_GAME }, #ifdef MSDOS { "soundcard", "type of sound card to use", 20, SET_IN_FILE }, #endif { "symset", "load a set of display symbols from the symbols file", 70, SET_IN_GAME }, { "roguesymset", "load a set of rogue display symbols from the symbols file", 70, SET_IN_GAME }, { "suppress_alert", "suppress alerts about version-specific features", 8, SET_IN_GAME }, { "tile_width", "width of tiles", 20, DISP_IN_GAME }, /*WC*/ { "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/ { "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/ { "traps", "the symbols to use in drawing traps", MAXTCHARS + 1, SET_IN_FILE }, { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/ #ifdef MSDOS { "video", "method of video updating", 20, SET_IN_FILE }, #endif #ifdef VIDEOSHADES { "videocolors", "color mappings for internal screen routines", 40, DISP_IN_GAME }, { "videoshades", "gray shades to map to black/gray/white", 32, DISP_IN_GAME }, #endif #ifdef WIN32 { "subkeyvalue", "override keystroke value", 7, SET_IN_FILE }, #endif { "windowcolors", "the foreground/background colors of windows", /*WC*/ 80, DISP_IN_GAME }, { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME }, #ifdef WINCHAIN { "windowchain", "window processor to use", WINTYPELEN, SET_IN_SYS }, #endif #ifdef BACKWARD_COMPAT { "DECgraphics", "load DECGraphics display symbols", 70, SET_IN_FILE }, { "IBMgraphics", "load IBMGraphics display symbols", 70, SET_IN_FILE }, #ifdef MAC_GRAPHICS_ENV { "Macgraphics", "load MACGraphics display symbols", 70, SET_IN_FILE }, #endif #endif { (char *) 0, (char *) 0, 0, 0 } }; #ifdef OPTION_LISTS_ONLY #undef static #else /* use rest of file */ extern struct symparse loadsyms[]; static boolean need_redraw; /* for doset() */ #if defined(TOS) && defined(TEXTCOLOR) extern boolean colors_changed; /* in tos.c */ #endif #ifdef VIDEOSHADES extern char *shade[3]; /* in sys/msdos/video.c */ extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */ #endif static char def_inv_order[MAXOCLASSES] = { COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0, }; /* * Default menu manipulation command accelerators. These may _not_ be: * * + a number - reserved for counts * + an upper or lower case US ASCII letter - used for accelerators * + ESC - reserved for escaping the menu * + NULL, CR or LF - reserved for commiting the selection(s). NULL * is kind of odd, but the tty's xwaitforspace() will return it if * someone hits a . * + a default object class symbol - used for object class accelerators * * Standard letters (for now) are: * * < back 1 page * > forward 1 page * ^ first page * | last page * : search * * page all * , select . * \ deselect - * ~ invert @ * * The command name list is duplicated in the compopt array. */ typedef struct { const char *name; char cmd; } menu_cmd_t; #define NUM_MENU_CMDS 11 static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = { /* 0*/ { "menu_first_page", MENU_FIRST_PAGE }, { "menu_last_page", MENU_LAST_PAGE }, { "menu_next_page", MENU_NEXT_PAGE }, { "menu_previous_page", MENU_PREVIOUS_PAGE }, { "menu_select_all", MENU_SELECT_ALL }, /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL }, { "menu_invert_all", MENU_INVERT_ALL }, { "menu_select_page", MENU_SELECT_PAGE }, { "menu_deselect_page", MENU_UNSELECT_PAGE }, { "menu_invert_page", MENU_INVERT_PAGE }, /*10*/ { "menu_search", MENU_SEARCH }, }; /* * Allow the user to map incoming characters to various menu commands. * The accelerator list must be a valid C string. */ #define MAX_MENU_MAPPED_CMDS 32 /* some number */ char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */ static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1]; static short n_menu_mapped = 0; static boolean initial, from_file; STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int)); STATIC_DCL void FDECL(nmcpy, (char *, const char *, int)); STATIC_DCL void FDECL(escapes, (const char *, char *)); STATIC_DCL void FDECL(rejectoption, (const char *)); STATIC_DCL void FDECL(badoption, (const char *)); STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P)); STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P)); STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P)); STATIC_DCL int FDECL(change_inv_order, (char *)); STATIC_DCL void FDECL(oc_to_str, (char *, char *)); STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *)); STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *)); STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(warning_opts, (char *, const char *)); STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int)); STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int)); STATIC_OVL void FDECL(wc_set_font_name, (int, char *)); STATIC_OVL int FDECL(wc_set_window_colors, (char *)); STATIC_OVL boolean FDECL(is_wc_option, (const char *)); STATIC_OVL boolean FDECL(wc_supported, (const char *)); STATIC_OVL boolean FDECL(is_wc2_option, (const char *)); STATIC_OVL boolean FDECL(wc2_supported, (const char *)); STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *)); STATIC_OVL int FDECL(count_ape_maps, (int *, int *)); STATIC_DCL const char *FDECL(attr2attrname, (int)); STATIC_DCL int NDECL(query_color); STATIC_DCL int NDECL(query_msgtype); STATIC_DCL int FDECL(query_attr, (const char *)); STATIC_DCL const char * FDECL(msgtype2name, (int)); STATIC_DCL boolean FDECL(msgtype_add, (int, char *)); STATIC_DCL void FDECL(free_one_msgtype, (int)); STATIC_DCL int NDECL(msgtype_count); STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int)); STATIC_DCL void FDECL(free_one_menu_coloring, (int)); STATIC_DCL int NDECL(count_menucolors); STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int)); void reglyph_darkroom() { xchar x, y; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { struct rm *lev = &levl[x][y]; if (!flags.dark_room || !iflags.use_color || Is_rogue_level(&u.uz)) { if (lev->glyph == cmap_to_glyph(S_darkroom)) lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : cmap_to_glyph(S_stone); } else { if (lev->glyph == cmap_to_glyph(S_room) && lev->seenv && lev->waslit && !cansee(x, y)) lev->glyph = cmap_to_glyph(S_darkroom); else if (lev->glyph == cmap_to_glyph(S_stone) && lev->typ == ROOM && lev->seenv && !cansee(x, y)) lev->glyph = cmap_to_glyph(S_darkroom); } } if (flags.dark_room && iflags.use_color) showsyms[S_darkroom] = showsyms[S_room]; else showsyms[S_darkroom] = showsyms[S_stone]; } /* check whether a user-supplied option string is a proper leading substring of a particular option name; option string might have a colon or equals sign and arbitrary value appended to it */ boolean match_optname(user_string, opt_name, min_length, val_allowed) const char *user_string, *opt_name; int min_length; boolean val_allowed; { int len = (int) strlen(user_string); if (val_allowed) { const char *p = index(user_string, ':'), *q = index(user_string, '='); if (!p || (q && q < p)) p = q; while (p && p > user_string && isspace((uchar) * (p - 1))) p--; if (p) len = (int) (p - user_string); } return (boolean) (len >= min_length && !strncmpi(opt_name, user_string, len)); } /* most environment variables will eventually be printed in an error * message if they don't work, and most error message paths go through * BUFSZ buffers, which could be overflowed by a maliciously long * environment variable. If a variable can legitimately be long, or * if it's put in a smaller buffer, the responsible code will have to * bounds-check itself. */ char * nh_getenv(ev) const char *ev; { char *getev = getenv(ev); if (getev && strlen(getev) <= (BUFSZ / 2)) return getev; else return (char *) 0; } /* process options, possibly including SYSCF */ void initoptions() { initoptions_init(); #ifdef SYSCF /* someday there may be other SYSCF alternatives besides text file */ #ifdef SYSCF_FILE /* If SYSCF_FILE is specified, it _must_ exist... */ assure_syscf_file(); /* ... and _must_ parse correctly. */ if (!read_config_file(SYSCF_FILE, SET_IN_SYS)) { raw_printf("Error(s) found in SYSCF_FILE, quitting."); terminate(EXIT_FAILURE); } /* * TODO [maybe]: parse the sysopt entries which are space-separated * lists of usernames into arrays with one name per element. */ #endif #endif initoptions_finish(); } void initoptions_init() { #if defined(UNIX) || defined(VMS) char *opts; #endif int i; /* set up the command parsing */ reset_commands(TRUE); /* init */ /* initialize the random number generator */ setrandom(); /* for detection of configfile options specified multiple times */ iflags.opt_booldup = iflags.opt_compdup = (int *) 0; for (i = 0; boolopt[i].name; i++) { if (boolopt[i].addr) *(boolopt[i].addr) = boolopt[i].initvalue; } #if defined(COMPRESS) || defined(ZLIB_COMP) set_savepref("externalcomp"); set_restpref("externalcomp"); #ifdef RLECOMP set_savepref("!rlecomp"); set_restpref("!rlecomp"); #endif #else #ifdef ZEROCOMP set_savepref("zerocomp"); set_restpref("zerocomp"); #endif #ifdef RLECOMP set_savepref("rlecomp"); set_restpref("rlecomp"); #endif #endif #ifdef SYSFLAGS Strcpy(sysflags.sysflagsid, "sysflags"); sysflags.sysflagsid[9] = (char) sizeof(struct sysflag); #endif flags.end_own = FALSE; flags.end_top = 3; flags.end_around = 2; flags.paranoia_bits = PARANOID_PRAY; /* old prayconfirm=TRUE */ flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */ flags.runmode = RUN_LEAP; iflags.msg_history = 20; #ifdef TTY_GRAPHICS iflags.prevmsg_window = 's'; #endif iflags.menu_headings = ATR_INVERSE; /* hero's role, race, &c haven't been chosen yet */ flags.initrole = flags.initrace = flags.initgend = flags.initalign = ROLE_NONE; /* Set the default monster and object class symbols. */ init_symbols(); for (i = 0; i < WARNCOUNT; i++) warnsyms[i] = def_warnsyms[i].sym; iflags.bouldersym = 0; iflags.travelcc.x = iflags.travelcc.y = -1; /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */ (void) memcpy((genericptr_t) flags.inv_order, (genericptr_t) def_inv_order, sizeof flags.inv_order); flags.pickup_types[0] = '\0'; flags.pickup_burden = MOD_ENCUMBER; flags.sortloot = 'l'; /* sort only loot by default */ for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO; switch_symbols(FALSE); /* set default characters */ #if defined(UNIX) && defined(TTY_GRAPHICS) /* * Set defaults for some options depending on what we can * detect about the environment's capabilities. * This has to be done after the global initialization above * and before reading user-specific initialization via * config file/environment variable below. */ /* this detects the IBM-compatible console on most 386 boxes */ if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) { if (!symset[PRIMARY].name) load_symset("IBMGraphics", PRIMARY); if (!symset[ROGUESET].name) load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); #ifdef TEXTCOLOR iflags.use_color = TRUE; #endif } #endif /* UNIX && TTY_GRAPHICS */ #if defined(UNIX) || defined(VMS) #ifdef TTY_GRAPHICS /* detect whether a "vt" terminal can handle alternate charsets */ if ((opts = nh_getenv("TERM")) /* [could also check "xterm" which emulates vtXXX by default] */ && !strncmpi(opts, "vt", 2) && AS && AE && index(AS, '\016') && index(AE, '\017')) { if (!symset[PRIMARY].name) load_symset("DECGraphics", PRIMARY); switch_symbols(TRUE); } #endif #endif /* UNIX || VMS */ #ifdef MAC_GRAPHICS_ENV if (!symset[PRIMARY].name) load_symset("MACGraphics", PRIMARY); switch_symbols(TRUE); #endif /* MAC_GRAPHICS_ENV */ flags.menu_style = MENU_FULL; /* since this is done before init_objects(), do partial init here */ objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); } void initoptions_finish() { #ifndef MAC char *opts = getenv("NETHACKOPTIONS"); if (!opts) opts = getenv("HACKOPTIONS"); if (opts) { if (*opts == '/' || *opts == '\\' || *opts == '@') { if (*opts == '@') opts++; /* @filename */ /* looks like a filename */ if (strlen(opts) < BUFSZ / 2) read_config_file(opts, SET_IN_FILE); } else { read_config_file((char *) 0, SET_IN_FILE); /* let the total length of options be long; * parseoptions() will check each individually */ parseoptions(opts, TRUE, FALSE); } } else #endif read_config_file((char *) 0, SET_IN_FILE); (void) fruitadd(pl_fruit, (struct fruit *) 0); /* * Remove "slime mold" from list of object names. This will * prevent it from being wished unless it's actually present * as a named (or default) fruit. Wishing for "fruit" will * result in the player's preferred fruit [better than "\033"]. */ obj_descr[SLIME_MOLD].oc_name = "fruit"; if (iflags.bouldersym) update_bouldersym(); reglyph_darkroom(); return; } STATIC_OVL void nmcpy(dest, src, maxlen) char *dest; const char *src; int maxlen; { int count; for (count = 1; count < maxlen; count++) { if (*src == ',' || *src == '\0') break; /*exit on \0 terminator*/ *dest++ = *src++; } *dest = 0; } /* * escapes(): escape expansion for showsyms. C-style escapes understood * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). * The ^-prefix for control characters is also understood, and \[mM] * has the effect of 'meta'-ing the value which follows (so that the * alternate character set will be enabled). * * For 3.4.3 and earlier, input ending with "\M", backslash, or caret * prior to terminating '\0' would pull that '\0' into the output and then * keep processing past it, potentially overflowing the output buffer. * Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the * output and stop there; trailing \M will fall through to \ and * yield 'M', then stop. Any \X or \O followed by something other than * an appropriate digit will also fall through to \ and yield 'X' * or 'O', plus stop if the non-digit is end-of-string. */ STATIC_OVL void escapes(cp, tp) const char *cp; char *tp; { static NEARDATA const char oct[] = "01234567", dec[] = "0123456789", hex[] = "00112233445566778899aAbBcCdDeEfF"; const char *dp; int cval, meta, dcount; while (*cp) { /* \M has to be followed by something to do meta conversion, otherwise it will just be \M which ultimately yields 'M' */ meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]); if (meta) cp += 2; cval = dcount = 0; /* for decimal, octal, hexadecimal cases */ if ((*cp != '\\' && *cp != '^') || !cp[1]) { /* simple character, or nothing left for \ or ^ to escape */ cval = *cp++; } else if (*cp == '^') { /* expand control-character syntax */ cval = (*++cp & 0x1f); ++cp; /* remaining cases are all for backslash and we know cp[1] is not * \0 */ } else if (index(dec, cp[1])) { ++cp; /* move past backslash to first digit */ do { cval = (cval * 10) + (*cp - '0'); } while (*++cp && index(dec, *cp) && ++dcount < 3); } else if ((cp[1] == 'o' || cp[1] == 'O') && cp[2] && index(oct, cp[2])) { cp += 2; /* move past backslash and 'O' */ do { cval = (cval * 8) + (*cp - '0'); } while (*++cp && index(oct, *cp) && ++dcount < 3); } else if ((cp[1] == 'x' || cp[1] == 'X') && cp[2] && (dp = index(hex, cp[2])) != 0) { cp += 2; /* move past backslash and 'X' */ do { cval = (cval * 16) + ((int) (dp - hex) / 2); } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2); } else { /* C-style character escapes */ switch (*++cp) { case '\\': cval = '\\'; break; case 'n': cval = '\n'; break; case 't': cval = '\t'; break; case 'b': cval = '\b'; break; case 'r': cval = '\r'; break; default: cval = *cp; } ++cp; } if (meta) cval |= 0x80; *tp++ = (char) cval; } *tp = '\0'; } STATIC_OVL void rejectoption(optname) const char *optname; { #ifdef MICRO pline("\"%s\" settable only from %s.", optname, lastconfigfile); #else pline("%s can be set only from NETHACKOPTIONS or %s.", optname, lastconfigfile); #endif } STATIC_OVL void badoption(opts) const char *opts; { if (!initial) { if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1)) option_help(); else pline("Bad syntax: %s. Enter \"?g\" for help.", opts); return; } #ifdef MAC else return; #endif if (from_file) raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", lastconfigfile, #ifdef WIN32 "\n", #else "", #endif opts); else raw_printf("Bad syntax in NETHACKOPTIONS: %s%s.\n", #ifdef WIN32 "\n", #else "", #endif opts); wait_synch(); } STATIC_OVL char * string_for_opt(opts, val_optional) char *opts; boolean val_optional; { char *colon, *equals; colon = index(opts, ':'); equals = index(opts, '='); if (!colon || (equals && equals < colon)) colon = equals; if (!colon || !*++colon) { if (!val_optional) badoption(opts); return (char *) 0; } return colon; } STATIC_OVL char * string_for_env_opt(optname, opts, val_optional) const char *optname; char *opts; boolean val_optional; { if (!initial) { rejectoption(optname); return (char *) 0; } return string_for_opt(opts, val_optional); } STATIC_OVL void bad_negation(optname, with_parameter) const char *optname; boolean with_parameter; { pline_The("%s option may not %sbe negated.", optname, with_parameter ? "both have a value and " : ""); } /* * Change the inventory order, using the given string as the new order. * Missing characters in the new order are filled in at the end from * the current inv_order, except for gold, which is forced to be first * if not explicitly present. * * This routine returns 1 unless there is a duplicate or bad char in * the string. */ STATIC_OVL int change_inv_order(op) char *op; { int oc_sym, num; char *sp, buf[BUFSZ]; num = 0; /* !!!! probably unnecessary with gold as normal inventory */ for (sp = op; *sp; sp++) { oc_sym = def_char_to_objclass(*sp); /* reject bad or duplicate entries */ if (oc_sym == MAXOCLASSES || oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS || !index(flags.inv_order, oc_sym) || index(sp + 1, *sp)) return 0; /* retain good ones */ buf[num++] = (char) oc_sym; } buf[num] = '\0'; /* fill in any omitted classes, using previous ordering */ for (sp = flags.inv_order; *sp; sp++) if (!index(buf, *sp)) { buf[num++] = *sp; buf[num] = '\0'; /* explicitly terminate for next index() */ } Strcpy(flags.inv_order, buf); return 1; } STATIC_OVL void warning_opts(opts, optype) register char *opts; const char *optype; { uchar translate[WARNCOUNT]; int length, i; if (!(opts = string_for_env_opt(optype, opts, FALSE))) return; escapes(opts, opts); length = (int) strlen(opts); /* match the form obtained from PC configuration files */ for (i = 0; i < WARNCOUNT; i++) translate[i] = (i >= length) ? 0 : opts[i] ? (uchar) opts[i] : def_warnsyms[i].sym; assign_warnings(translate); } void assign_warnings(graph_chars) register uchar *graph_chars; { int i; for (i = 0; i < WARNCOUNT; i++) if (graph_chars[i]) warnsyms[i] = graph_chars[i]; } STATIC_OVL int feature_alert_opts(op, optn) char *op; const char *optn; { char buf[BUFSZ]; boolean rejectver = FALSE; unsigned long fnv = get_feature_notice_ver(op); /* version.c */ if (fnv == 0L) return 0; if (fnv > get_current_feature_ver()) rejectver = TRUE; else flags.suppress_alert = fnv; if (rejectver) { if (!initial) { You_cant("disable new feature alerts for future versions."); } else { Sprintf(buf, "\n%s=%s Invalid reference to a future version ignored", optn, op); badoption(buf); } return 0; } if (!initial) { Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH); pline( "Feature change alerts disabled for NetHack %s features and prior.", buf); } return 1; } void set_duplicate_opt_detection(on_or_off) int on_or_off; { int k, *optptr; if (on_or_off != 0) { /*-- ON --*/ if (iflags.opt_booldup) impossible("iflags.opt_booldup already on (memory leak)"); iflags.opt_booldup = (int *) alloc(SIZE(boolopt) * sizeof(int)); optptr = iflags.opt_booldup; for (k = 0; k < SIZE(boolopt); ++k) *optptr++ = 0; if (iflags.opt_compdup) impossible("iflags.opt_compdup already on (memory leak)"); iflags.opt_compdup = (int *) alloc(SIZE(compopt) * sizeof(int)); optptr = iflags.opt_compdup; for (k = 0; k < SIZE(compopt); ++k) *optptr++ = 0; } else { /*-- OFF --*/ if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup); iflags.opt_booldup = (int *) 0; if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup); iflags.opt_compdup = (int *) 0; } } STATIC_OVL boolean duplicate_opt_detection(opts, iscompound) const char *opts; int iscompound; /* 0 == boolean option, 1 == compound */ { int i, *optptr; if (!iscompound && iflags.opt_booldup && initial && from_file) { for (i = 0; boolopt[i].name; i++) { if (match_optname(opts, boolopt[i].name, 3, FALSE)) { optptr = iflags.opt_booldup + i; *optptr += 1; if (*optptr > 1) return TRUE; else return FALSE; } } } else if (iscompound && iflags.opt_compdup && initial && from_file) { for (i = 0; compopt[i].name; i++) { if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) { optptr = iflags.opt_compdup + i; *optptr += 1; if (*optptr > 1) return TRUE; else return FALSE; } } } return FALSE; } STATIC_OVL void complain_about_duplicate(opts, iscompound) const char *opts; int iscompound; /* 0 == boolean option, 1 == compound */ { #ifdef MAC /* the Mac has trouble dealing with the output of messages while * processing the config file. That should get fixed one day. * For now just return. */ #else /* !MAC */ raw_printf("\nWarning - %s option specified multiple times: %s.\n", iscompound ? "compound" : "boolean", opts); wait_synch(); #endif /* ?MAC */ return; } /* paranoia[] - used by parseoptions() and special_handling() */ STATIC_VAR const struct paranoia_opts { int flagmask; /* which paranoid option */ const char *argname; /* primary name */ int argMinLen; /* minimum number of letters to match */ const char *synonym; /* alternate name (optional) */ int synMinLen; const char *explain; /* for interactive menu */ } paranoia[] = { /* there are some initial-letter conflicts: "a"ttack vs "a"ll, "attack" takes precedence and "all" isn't present in the interactive menu, and "d"ie vs "d"eath, synonyms for each other so doesn't matter; (also "p"ray vs "P"aranoia, "pray" takes precedence since "Paranoia" is just a synonym for "Confirm") */ { PARANOID_CONFIRM, "Confirm", 1, "Paranoia", 2, "for \"yes\" confirmations, require \"no\" to reject" }, { PARANOID_QUIT, "quit", 1, "explore", 1, "yes vs y to quit or to enter explore mode" }, { PARANOID_DIE, "die", 1, "death", 2, "yes vs y to die (explore mode or debug mode)" }, { PARANOID_BONES, "bones", 1, 0, 0, "yes vs y to save bones data when dying in debug mode" }, { PARANOID_HIT, "attack", 1, "hit", 1, "yes vs y to attack a peaceful monster" }, { PARANOID_PRAY, "pray", 1, 0, 0, "y to pray (supersedes old \"prayconfirm\" option)" }, { PARANOID_REMOVE, "Remove", 1, "Takeoff", 1, "always pick from inventory for Remove and Takeoff" }, { PARANOID_BREAKWAND, "wand", 1, "breakwand", 2, "yes vs y to break a wand" }, /* for config file parsing; interactive menu skips these */ { 0, "none", 4, 0, 0, 0 }, /* require full word match */ { ~0, "all", 3, 0, 0, 0 }, /* ditto */ }; extern struct menucoloring *menu_colorings; static const struct { const char *name; const int color; } colornames[] = { { "black", CLR_BLACK }, { "red", CLR_RED }, { "green", CLR_GREEN }, { "brown", CLR_BROWN }, { "blue", CLR_BLUE }, { "magenta", CLR_MAGENTA }, { "cyan", CLR_CYAN }, { "gray", CLR_GRAY }, { "grey", CLR_GRAY }, { "orange", CLR_ORANGE }, { "light green", CLR_BRIGHT_GREEN }, { "yellow", CLR_YELLOW }, { "light blue", CLR_BRIGHT_BLUE }, { "light magenta", CLR_BRIGHT_MAGENTA }, { "light cyan", CLR_BRIGHT_CYAN }, { "white", CLR_WHITE } }; static const struct { const char *name; const int attr; } attrnames[] = { { "none", ATR_NONE }, { "bold", ATR_BOLD }, { "dim", ATR_DIM }, { "underline", ATR_ULINE }, { "blink", ATR_BLINK }, { "inverse", ATR_INVERSE } }; const char * clr2colorname(clr) int clr; { int i; for (i = 0; i < SIZE(colornames); i++) if (colornames[i].color == clr) return colornames[i].name; return (char *) 0; } const char * attr2attrname(attr) int attr; { int i; for (i = 0; i < SIZE(attrnames); i++) if (attrnames[i].attr == attr) return attrnames[i].name; return (char *) 0; } int query_color() { winid tmpwin; anything any; int i, pick_cnt; menu_item *picks = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(colornames); i++) { if (!strcmp(colornames[i].name, "grey")) continue; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name, MENU_UNSELECTED); } end_menu(tmpwin, "Pick a color"); pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); destroy_nhwindow(tmpwin); if (pick_cnt > 0) { i = colornames[picks->item.a_int - 1].color; free((genericptr_t) picks); return i; } return -1; } int query_attr(prompt) const char *prompt; { winid tmpwin; anything any; int i, pick_cnt; menu_item *picks = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(attrnames); i++) { any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr, attrnames[i].name, MENU_UNSELECTED); } end_menu(tmpwin, prompt ? prompt : "Pick an attribute"); pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); destroy_nhwindow(tmpwin); if (pick_cnt > 0) { i = attrnames[picks->item.a_int - 1].attr; free((genericptr_t) picks); return i; } return -1; } static const struct { const char *name; const xchar msgtyp; const char *descr; } msgtype_names[] = { { "show", MSGTYP_NORMAL, "Show message normally" }, { "hide", MSGTYP_NOSHOW, "Hide message" }, { "noshow", MSGTYP_NOSHOW, NULL }, { "stop", MSGTYP_STOP, "Prompt for more after the message" }, { "more", MSGTYP_STOP, NULL }, { "norep", MSGTYP_NOREP, "Do not repeat the message" } }; const char * msgtype2name(typ) int typ; { int i; for (i = 0; i < SIZE(msgtype_names); i++) if (msgtype_names[i].descr && msgtype_names[i].msgtyp == typ) return msgtype_names[i].name; return (char *) 0; } int query_msgtype() { winid tmpwin; anything any; int i, pick_cnt; menu_item *picks = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(msgtype_names); i++) if (msgtype_names[i].descr) { any.a_int = msgtype_names[i].msgtyp + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, msgtype_names[i].descr, MENU_UNSELECTED); } end_menu(tmpwin, "How to show the message"); pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); destroy_nhwindow(tmpwin); if (pick_cnt > 0) { i = picks->item.a_int - 1; free((genericptr_t) picks); return i; } return -1; } boolean msgtype_add(typ, pattern) int typ; char *pattern; { struct plinemsg_type *tmp = (struct plinemsg_type *) alloc(sizeof (struct plinemsg_type)); if (!tmp) return FALSE; tmp->msgtype = typ; tmp->regex = regex_init(); if (!regex_compile(pattern, tmp->regex)) { static const char *re_error = "MSGTYPE regex error"; if (!iflags.window_inited) raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->regex)); else pline("%s: %s", re_error, regex_error_desc(tmp->regex)); wait_synch(); regex_free(tmp->regex); free((genericptr_t) tmp); return FALSE; } tmp->pattern = dupstr(pattern); tmp->next = plinemsg_types; plinemsg_types = tmp; return TRUE; } void msgtype_free() { struct plinemsg_type *tmp, *tmp2 = 0; for (tmp = plinemsg_types; tmp; tmp = tmp2) { tmp2 = tmp->next; free((genericptr_t) tmp->pattern); regex_free(tmp->regex); free((genericptr_t) tmp); } plinemsg_types = (struct plinemsg_type *) 0; } void free_one_msgtype(idx) int idx; /* 0 .. */ { struct plinemsg_type *tmp = plinemsg_types; struct plinemsg_type *prev = NULL; while (tmp) { if (idx == 0) { struct plinemsg_type *next = tmp->next; regex_free(tmp->regex); free((genericptr_t) tmp->pattern); free((genericptr_t) tmp); if (prev) prev->next = next; else plinemsg_types = next; return; } idx--; prev = tmp; tmp = tmp->next; } } int msgtype_type(msg) const char *msg; { struct plinemsg_type *tmp = plinemsg_types; while (tmp) { if (regex_match(msg, tmp->regex)) return tmp->msgtype; tmp = tmp->next; } return MSGTYP_NORMAL; } int msgtype_count() { int c = 0; struct plinemsg_type *tmp = plinemsg_types; while (tmp) { c++; tmp = tmp->next; } return c; } boolean msgtype_parse_add(str) char *str; { char pattern[256]; char msgtype[11]; if (sscanf(str, "%10s \"%255[^\"]\"", msgtype, pattern) == 2) { int typ = -1; int i; for (i = 0; i < SIZE(msgtype_names); i++) if (!strncmpi(msgtype_names[i].name, msgtype, strlen(msgtype))) { typ = msgtype_names[i].msgtyp; break; } if (typ != -1) return msgtype_add(typ, pattern); } return FALSE; } boolean add_menu_coloring_parsed(str, c, a) char *str; int c, a; { static const char re_error[] = "Menucolor regex error"; struct menucoloring *tmp; if (!str) return FALSE; tmp = (struct menucoloring *) alloc(sizeof (struct menucoloring)); tmp->match = regex_init(); if (!regex_compile(str, tmp->match)) { if (!iflags.window_inited) raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->match)); else pline("%s: %s", re_error, regex_error_desc(tmp->match)); wait_synch(); regex_free(tmp->match); free(tmp); return FALSE; } else { tmp->next = menu_colorings; tmp->origstr = dupstr(str); tmp->color = c; tmp->attr = a; menu_colorings = tmp; return TRUE; } } /* parse '"regex_string"=color&attr' and add it to menucoloring */ boolean add_menu_coloring(str) char *str; { int i, c = NO_COLOR, a = ATR_NONE; char *tmps, *cs, *amp; if (!str || (cs = index(str, '=')) == 0) return FALSE; tmps = cs + 1; /* advance past '=' */ mungspaces(tmps); if ((amp = index(tmps, '&')) != 0) *amp = '\0'; /* allow "lightblue", "light blue", and "light-blue" to match "light blue" (also junk like "_l i-gh_t---b l u e" but we won't worry about that); also copes with trailing space; mungspaces removed any leading space */ for (i = 0; i < SIZE(colornames); i++) if (fuzzymatch(tmps, colornames[i].name, " -_", TRUE)) { c = colornames[i].color; break; } if (i == SIZE(colornames) && (*tmps >= '0' && *tmps <= '9')) c = atoi(tmps); if (c > 15) return FALSE; if (amp) { tmps = amp + 1; /* advance past '&' */ /* unlike colors, none of he attribute names has any embedded spaces, but use of fuzzymatch() allows us ignore the presence of leading and/or trailing (and also embedded) spaces in the user's string; dash and underscore skipping could be omitted but does no harm */ for (i = 0; i < SIZE(attrnames); i++) if (fuzzymatch(tmps, attrnames[i].name, " -_", TRUE)) { a = attrnames[i].attr; break; } if (i == SIZE(attrnames) && (*tmps >= '0' && *tmps <= '9')) a = atoi(tmps); } /* the regexp portion here has not been condensed by mungspaces() */ *cs = '\0'; tmps = str; if (*tmps == '"' || *tmps == '\'') { cs--; while (isspace((uchar) *cs)) cs--; if (*cs == *tmps) { *cs = '\0'; tmps++; } } return add_menu_coloring_parsed(tmps, c, a); } boolean get_menu_coloring(str, color, attr) char *str; int *color, *attr; { struct menucoloring *tmpmc; if (iflags.use_menu_color) for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next) if (regex_match(str, tmpmc->match)) { *color = tmpmc->color; *attr = tmpmc->attr; return TRUE; } return FALSE; } void free_menu_coloring() { struct menucoloring *tmp = menu_colorings; while (tmp) { struct menucoloring *tmp2 = tmp->next; regex_free(tmp->match); free((genericptr_t) tmp->origstr); free((genericptr_t) tmp); tmp = tmp2; } } void free_one_menu_coloring(idx) int idx; /* 0 .. */ { struct menucoloring *tmp = menu_colorings; struct menucoloring *prev = NULL; while (tmp) { if (idx == 0) { struct menucoloring *next = tmp->next; regex_free(tmp->match); free((genericptr_t) tmp->origstr); free((genericptr_t) tmp); if (prev) prev->next = next; else menu_colorings = next; return; } idx--; prev = tmp; tmp = tmp->next; } } int count_menucolors() { int count = 0; struct menucoloring *tmp = menu_colorings; while (tmp) { count++; tmp = tmp->next; } return count; } void parseoptions(opts, tinitial, tfrom_file) register char *opts; boolean tinitial, tfrom_file; { register char *op; unsigned num; boolean negated, val_negated, duplicate; int i; const char *fullname; initial = tinitial; from_file = tfrom_file; if ((op = index(opts, ',')) != 0) { *op++ = 0; parseoptions(op, initial, from_file); } if (strlen(opts) > BUFSZ / 2) { badoption("option too long"); return; } /* strip leading and trailing white space */ while (isspace((uchar) *opts)) opts++; op = eos(opts); while (--op >= opts && isspace((uchar) *op)) *op = '\0'; if (!*opts) return; negated = FALSE; while ((*opts == '!') || !strncmpi(opts, "no", 2)) { if (*opts == '!') opts++; else opts += 2; negated = !negated; } /* variant spelling */ if (match_optname(opts, "colour", 5, FALSE)) Strcpy(opts, "color"); /* fortunately this isn't longer */ /* special boolean options */ if (match_optname(opts, "female", 3, FALSE)) { if (duplicate_opt_detection(opts, 0)) complain_about_duplicate(opts, 0); if (!initial && flags.female == negated) pline("That is not anatomically possible."); else flags.initgend = flags.female = !negated; return; } if (match_optname(opts, "male", 4, FALSE)) { if (duplicate_opt_detection(opts, 0)) complain_about_duplicate(opts, 0); if (!initial && flags.female != negated) pline("That is not anatomically possible."); else flags.initgend = flags.female = negated; return; } #if defined(MICRO) && !defined(AMIGA) /* included for compatibility with old NetHack.cnf files */ if (match_optname(opts, "IBM_", 4, FALSE)) { iflags.BIOS = !negated; return; } #endif /* MICRO */ /* compound options */ /* This first batch can be duplicated if their values are negated */ /* align:string */ fullname = "align"; if (match_optname(opts, fullname, sizeof("align") - 1, TRUE)) { if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { val_negated = FALSE; while ((*op == '!') || !strncmpi(op, "no", 2)) { if (*op == '!') op++; else op += 2; val_negated = !val_negated; } if (val_negated) { if (!setrolefilter(op)) badoption(opts); } else { if (duplicate_opt_detection(opts, 1)) complain_about_duplicate(opts, 1); if ((flags.initalign = str2align(op)) == ROLE_NONE) badoption(opts); } } return; } /* role:string or character:string */ fullname = "role"; if (match_optname(opts, fullname, 4, TRUE) || match_optname(opts, (fullname = "character"), 4, TRUE)) { if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { val_negated = FALSE; while ((*op == '!') || !strncmpi(op, "no", 2)) { if (*op == '!') op++; else op += 2; val_negated = !val_negated; } if (val_negated) { if (!setrolefilter(op)) badoption(opts); } else { if (duplicate_opt_detection(opts, 1)) complain_about_duplicate(opts, 1); if ((flags.initrole = str2role(op)) == ROLE_NONE) badoption(opts); else /* Backwards compatibility */ nmcpy(pl_character, op, PL_NSIZ); } } return; } /* race:string */ fullname = "race"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { val_negated = FALSE; while ((*op == '!') || !strncmpi(op, "no", 2)) { if (*op == '!') op++; else op += 2; val_negated = !val_negated; } if (val_negated) { if (!setrolefilter(op)) badoption(opts); } else { if (duplicate_opt_detection(opts, 1)) complain_about_duplicate(opts, 1); if ((flags.initrace = str2race(op)) == ROLE_NONE) badoption(opts); else /* Backwards compatibility */ pl_race = *op; } } return; } /* gender:string */ fullname = "gender"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { val_negated = FALSE; while ((*op == '!') || !strncmpi(op, "no", 2)) { if (*op == '!') op++; else op += 2; val_negated = !val_negated; } if (val_negated) { if (!setrolefilter(op)) badoption(opts); } else { if (duplicate_opt_detection(opts, 1)) complain_about_duplicate(opts, 1); if ((flags.initgend = str2gend(op)) == ROLE_NONE) badoption(opts); else flags.female = flags.initgend; } } return; } /* We always check for duplicates on the remaining compound options, although individual option processing can choose to complain or not */ duplicate = duplicate_opt_detection(opts, 1); /* 1 means check compounds */ fullname = "pettype"; if (match_optname(opts, fullname, 3, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if ((op = string_for_env_opt(fullname, opts, negated)) != 0) { if (negated) bad_negation(fullname, TRUE); else switch (lowc(*op)) { case 'd': /* dog */ preferred_pet = 'd'; break; case 'c': /* cat */ case 'f': /* feline */ preferred_pet = 'c'; break; case 'h': /* horse */ case 'q': /* quadruped */ /* avoids giving "unrecognized type of pet" but pet_type(dog.c) won't actually honor this */ preferred_pet = 'h'; break; case 'n': /* no pet */ preferred_pet = 'n'; break; case '*': /* random */ preferred_pet = '\0'; break; default: pline("Unrecognized pet type '%s'.", op); break; } } else if (negated) preferred_pet = 'n'; return; } fullname = "catname"; if (match_optname(opts, fullname, 3, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(catname, op, PL_PSIZ); sanitize_name(catname); return; } fullname = "dogname"; if (match_optname(opts, fullname, 3, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(dogname, op, PL_PSIZ); sanitize_name(dogname); return; } fullname = "horsename"; if (match_optname(opts, fullname, 5, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(horsename, op, PL_PSIZ); sanitize_name(horsename); return; } fullname = "number_pad"; if (match_optname(opts, fullname, 10, TRUE)) { boolean compat = (strlen(opts) <= 10); if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, (compat || !initial)); if (!op) { if (compat || negated || initial) { /* for backwards compatibility, "number_pad" without a value is a synonym for number_pad:1 */ iflags.num_pad = !negated; iflags.num_pad_mode = 0; } } else if (negated) { bad_negation("number_pad", TRUE); return; } else { int mode = atoi(op); if (mode < -1 || mode > 4 || (mode == 0 && *op != '0')) { badoption(opts); return; } else if (mode <= 0) { iflags.num_pad = FALSE; /* German keyboard; y and z keys swapped */ iflags.num_pad_mode = (mode < 0); /* 0 or 1 */ } else { /* mode > 0 */ iflags.num_pad = TRUE; iflags.num_pad_mode = 0; /* PC Hack / MSDOS compatibility */ if (mode == 2 || mode == 4) iflags.num_pad_mode |= 1; /* phone keypad layout */ if (mode == 3 || mode == 4) iflags.num_pad_mode |= 2; } } reset_commands(FALSE); number_pad(iflags.num_pad ? 1 : 0); return; } fullname = "roguesymset"; if (match_optname(opts, fullname, 7, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_opt(opts, FALSE)) != 0) { symset[ROGUESET].name = dupstr(op); if (!read_sym_file(ROGUESET)) { clear_symsetentry(ROGUESET, TRUE); raw_printf("Unable to load symbol set \"%s\" from \"%s\".", op, SYMBOLS); wait_synch(); } else { if (!initial && Is_rogue_level(&u.uz)) assign_graphics(ROGUESET); need_redraw = TRUE; } } return; } fullname = "symset"; if (match_optname(opts, fullname, 6, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_opt(opts, FALSE)) != 0) { symset[PRIMARY].name = dupstr(op); if (!read_sym_file(PRIMARY)) { clear_symsetentry(PRIMARY, TRUE); raw_printf("Unable to load symbol set \"%s\" from \"%s\".", op, SYMBOLS); wait_synch(); } else { switch_symbols(TRUE); need_redraw = TRUE; } } return; } fullname = "runmode"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { flags.runmode = RUN_TPORT; } else if ((op = string_for_opt(opts, FALSE)) != 0) { if (!strncmpi(op, "teleport", strlen(op))) flags.runmode = RUN_TPORT; else if (!strncmpi(op, "run", strlen(op))) flags.runmode = RUN_LEAP; else if (!strncmpi(op, "walk", strlen(op))) flags.runmode = RUN_STEP; else if (!strncmpi(op, "crawl", strlen(op))) flags.runmode = RUN_CRAWL; else badoption(opts); } return; } /* menucolor:"regex_string"=color */ fullname = "menucolor"; if (match_optname(opts, fullname, 9, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) if (!add_menu_coloring(op)) badoption(opts); return; } fullname = "msghistory"; if (match_optname(opts, fullname, 3, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_env_opt(fullname, opts, negated); if ((negated && !op) || (!negated && op)) { iflags.msg_history = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } fullname = "msg_window"; /* msg_window:single, combo, full or reversed */ if (match_optname(opts, fullname, 4, TRUE)) { /* allow option to be silently ignored by non-tty ports */ #ifdef TTY_GRAPHICS int tmp; if (duplicate) complain_about_duplicate(opts, 1); if (!(op = string_for_opt(opts, TRUE))) { tmp = negated ? 's' : 'f'; } else { if (negated) { bad_negation(fullname, TRUE); return; } tmp = tolower(*op); } switch (tmp) { case 's': /* single message history cycle (default if negated) */ iflags.prevmsg_window = 's'; break; case 'c': /* combination: two singles, then full page reversed */ iflags.prevmsg_window = 'c'; break; case 'f': /* full page (default if no opts) */ iflags.prevmsg_window = 'f'; break; case 'r': /* full page (reversed) */ iflags.prevmsg_window = 'r'; break; default: badoption(opts); } #endif return; } /* WINCAP * setting font options */ fullname = "font"; if (!strncmpi(opts, fullname, 4)) { int opttype = -1; char *fontopts = opts + 4; if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4)) opttype = MAP_OPTION; else if (!strncmpi(fontopts, "message", 7) || !strncmpi(fontopts, "_message", 8)) opttype = MESSAGE_OPTION; else if (!strncmpi(fontopts, "text", 4) || !strncmpi(fontopts, "_text", 5)) opttype = TEXT_OPTION; else if (!strncmpi(fontopts, "menu", 4) || !strncmpi(fontopts, "_menu", 5)) opttype = MENU_OPTION; else if (!strncmpi(fontopts, "status", 6) || !strncmpi(fontopts, "_status", 7)) opttype = STATUS_OPTION; else if (!strncmpi(fontopts, "_size", 5)) { if (!strncmpi(fontopts, "_size_map", 8)) opttype = MAP_OPTION; else if (!strncmpi(fontopts, "_size_message", 12)) opttype = MESSAGE_OPTION; else if (!strncmpi(fontopts, "_size_text", 9)) opttype = TEXT_OPTION; else if (!strncmpi(fontopts, "_size_menu", 9)) opttype = MENU_OPTION; else if (!strncmpi(fontopts, "_size_status", 11)) opttype = STATUS_OPTION; else { badoption(opts); return; } if (duplicate) complain_about_duplicate(opts, 1); if (opttype > 0 && !negated && (op = string_for_opt(opts, FALSE)) != 0) { switch (opttype) { case MAP_OPTION: iflags.wc_fontsiz_map = atoi(op); break; case MESSAGE_OPTION: iflags.wc_fontsiz_message = atoi(op); break; case TEXT_OPTION: iflags.wc_fontsiz_text = atoi(op); break; case MENU_OPTION: iflags.wc_fontsiz_menu = atoi(op); break; case STATUS_OPTION: iflags.wc_fontsiz_status = atoi(op); break; } } return; } else { badoption(opts); } if (opttype > 0 && (op = string_for_opt(opts, FALSE)) != 0) { wc_set_font_name(opttype, op); #ifdef MAC set_font_name(opttype, op); #endif return; } else if (negated) bad_negation(fullname, TRUE); return; } #ifdef CHANGE_COLOR if (match_optname(opts, "palette", 3, TRUE) #ifdef MAC || match_optname(opts, "hicolor", 3, TRUE) #endif ) { int color_number, color_incr; #ifndef WIN32 if (duplicate) complain_about_duplicate(opts, 1); #endif #ifdef MAC if (match_optname(opts, "hicolor", 3, TRUE)) { if (negated) { bad_negation("hicolor", FALSE); return; } color_number = CLR_MAX + 4; /* HARDCODED inverse number */ color_incr = -1; } else { #endif if (negated) { bad_negation("palette", FALSE); return; } color_number = 0; color_incr = 1; #ifdef MAC } #endif #ifdef WIN32 op = string_for_opt(opts, TRUE); if (!alternative_palette(op)) badoption(opts); #else if ((op = string_for_opt(opts, FALSE)) != (char *) 0) { char *pt = op; int cnt, tmp, reverse; long rgb; while (*pt && color_number >= 0) { cnt = 3; rgb = 0L; if (*pt == '-') { reverse = 1; pt++; } else { reverse = 0; } while (cnt-- > 0) { if (*pt && *pt != '/') { #ifdef AMIGA rgb <<= 4; #else rgb <<= 8; #endif tmp = *(pt++); if (isalpha(tmp)) { tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */ } else { tmp &= 0xf; /* Digits in ASCII too... */ } #ifndef AMIGA /* Add an extra so we fill f -> ff and 0 -> 00 */ rgb += tmp << 4; #endif rgb += tmp; } } if (*pt == '/') { pt++; } change_color(color_number, rgb, reverse); color_number += color_incr; } } #endif /* !WIN32 */ if (!initial) { need_redraw = TRUE; } return; } #endif /* CHANGE_COLOR */ if (match_optname(opts, "fruit", 2, TRUE)) { struct fruit *forig = 0; char empty_str = '\0'; if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (negated) { if (op) { bad_negation("fruit", TRUE); return; } op = &empty_str; goto goodfruit; } if (!op) return; if (!initial) { struct fruit *f; num = 0; for (f = ffruit; f; f = f->nextf) { if (!strcmp(op, f->fname)) break; num++; } if (!flags.made_fruit) { for (forig = ffruit; forig; forig = forig->nextf) { if (!strcmp(pl_fruit, forig->fname)) { break; } } } if (!forig && num >= 100) { pline("Doing that so many times isn't very fruitful."); return; } } goodfruit: nmcpy(pl_fruit, op, PL_FSIZ); sanitize_name(pl_fruit); /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */ if (!*pl_fruit) nmcpy(pl_fruit, "slime mold", PL_FSIZ); if (!initial) { (void) fruitadd(pl_fruit, forig); pline("Fruit is now \"%s\".", pl_fruit); } /* If initial, then initoptions is allowed to do it instead * of here (initoptions always has to do it even if there's * no fruit option at all. Also, we don't want people * setting multiple fruits in their options.) */ return; } fullname = "warnings"; if (match_optname(opts, fullname, 5, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) bad_negation(fullname, FALSE); else warning_opts(opts, fullname); return; } #ifdef BACKWARD_COMPAT /* boulder:symbol */ fullname = "boulder"; if (match_optname(opts, fullname, 7, TRUE)) { int clash = 0; if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } /* if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */ if (!(opts = string_for_opt(opts, FALSE))) return; escapes(opts, opts); if (def_char_to_monclass(opts[0]) != MAXMCLASSES) clash = 1; else if (opts[0] >= '1' && opts[0] <= '5') clash = 2; if (clash) { /* symbol chosen matches a used monster or warning symbol which is not good - reject it*/ pline( "Badoption - boulder symbol '%c' conflicts with a %s symbol.", opts[0], (clash == 1) ? "monster" : "warning"); } else { /* * Override the default boulder symbol. */ iflags.bouldersym = (uchar) opts[0]; } if (!initial) need_redraw = TRUE; return; } #endif /* name:string */ fullname = "name"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(plname, op, PL_NSIZ); return; } /* altkeyhandler:string */ fullname = "altkeyhandler"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_opt(opts, negated)) != 0) { #ifdef WIN32 (void) strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5); load_keyboard_handler(); #endif } return; } /* WINCAP * align_status:[left|top|right|bottom] */ fullname = "align_status"; if (match_optname(opts, fullname, sizeof("align_status") - 1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi(op, "left", sizeof("left") - 1)) iflags.wc_align_status = ALIGN_LEFT; else if (!strncmpi(op, "top", sizeof("top") - 1)) iflags.wc_align_status = ALIGN_TOP; else if (!strncmpi(op, "right", sizeof("right") - 1)) iflags.wc_align_status = ALIGN_RIGHT; else if (!strncmpi(op, "bottom", sizeof("bottom") - 1)) iflags.wc_align_status = ALIGN_BOTTOM; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * align_message:[left|top|right|bottom] */ fullname = "align_message"; if (match_optname(opts, fullname, sizeof("align_message") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi(op, "left", sizeof("left") - 1)) iflags.wc_align_message = ALIGN_LEFT; else if (!strncmpi(op, "top", sizeof("top") - 1)) iflags.wc_align_message = ALIGN_TOP; else if (!strncmpi(op, "right", sizeof("right") - 1)) iflags.wc_align_message = ALIGN_RIGHT; else if (!strncmpi(op, "bottom", sizeof("bottom") - 1)) iflags.wc_align_message = ALIGN_BOTTOM; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* the order to list the pack */ fullname = "packorder"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if (!(op = string_for_opt(opts, FALSE))) return; if (!change_inv_order(op)) badoption(opts); return; } /* user can change required response for some prompts (quit, die, hit), or add an extra prompt (pray, Remove) that isn't ordinarily there */ fullname = "paranoid_confirmation"; if (match_optname(opts, fullname, 8, TRUE)) { /* at present we don't complain about duplicates for this option, but we do throw away the old settings whenever we process a new one [clearing old flags is essential for handling default paranoid_confirm:pray sanely] */ flags.paranoia_bits = 0; /* clear all */ if (negated) { flags.paranoia_bits = 0; /* [now redundant...] */ } else if ((op = string_for_opt(opts, TRUE)) != 0) { char *pp, buf[BUFSZ]; op = mungspaces(strcpy(buf, op)); for (;;) { /* We're looking to parse "paranoid_confirm:whichone wheretwo whothree" and "paranoid_confirm:" prefix has already been stripped off by the time we get here */ pp = index(op, ' '); if (pp) *pp = '\0'; /* we aren't matching option names but match_optname does what we want once we've broken the space delimited aggregate into separate tokens */ for (i = 0; i < SIZE(paranoia); ++i) { if (match_optname(op, paranoia[i].argname, paranoia[i].argMinLen, FALSE) || (paranoia[i].synonym && match_optname(op, paranoia[i].synonym, paranoia[i].synMinLen, FALSE))) { if (paranoia[i].flagmask) flags.paranoia_bits |= paranoia[i].flagmask; else /* 0 == "none", so clear all */ flags.paranoia_bits = 0; break; } } if (i == SIZE(paranoia)) { /* didn't match anything, so arg is bad; any flags already set will stay set */ badoption(opts); break; } /* move on to next token */ if (pp) op = pp + 1; else break; /* no next token */ } /* for(;;) */ } return; } /* accept deprecated boolean; superseded by paranoid_confirm:pray */ fullname = "prayconfirm"; if (match_optname(opts, fullname, 4, FALSE)) { if (negated) flags.paranoia_bits &= ~PARANOID_PRAY; else flags.paranoia_bits |= PARANOID_PRAY; return; } /* maximum burden picked up before prompt (Warren Cheung) */ fullname = "pickup_burden"; if (match_optname(opts, fullname, 8, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { switch (tolower(*op)) { /* Unencumbered */ case 'u': flags.pickup_burden = UNENCUMBERED; break; /* Burdened (slight encumbrance) */ case 'b': flags.pickup_burden = SLT_ENCUMBER; break; /* streSsed (moderate encumbrance) */ case 's': flags.pickup_burden = MOD_ENCUMBER; break; /* straiNed (heavy encumbrance) */ case 'n': flags.pickup_burden = HVY_ENCUMBER; break; /* OverTaxed (extreme encumbrance) */ case 'o': case 't': flags.pickup_burden = EXT_ENCUMBER; break; /* overLoaded */ case 'l': flags.pickup_burden = OVERLOADED; break; default: badoption(opts); } } return; } /* types of objects to pick up automatically */ if (match_optname(opts, "pickup_types", 8, TRUE)) { char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], qbuf[QBUFSZ], abuf[BUFSZ]; int oc_sym; boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu; if (duplicate) complain_about_duplicate(opts, 1); oc_to_str(flags.pickup_types, tbuf); flags.pickup_types[0] = '\0'; /* all */ op = string_for_opt(opts, (compat || !initial)); if (!op) { if (compat || negated || initial) { /* for backwards compatibility, "pickup" without a value is a synonym for autopickup of all types (and during initialization, we can't prompt yet) */ flags.pickup = !negated; return; } oc_to_str(flags.inv_order, ocl); use_menu = TRUE; if (flags.menu_style == MENU_TRADITIONAL || flags.menu_style == MENU_COMBINATION) { use_menu = FALSE; Sprintf(qbuf, "New pickup_types: [%s am] (%s)", ocl, *tbuf ? tbuf : "all"); getlin(qbuf, abuf); op = mungspaces(abuf); if (abuf[0] == '\0' || abuf[0] == '\033') op = tbuf; /* restore */ else if (abuf[0] == 'm') use_menu = TRUE; } if (use_menu) { (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE, ocl, tbuf); op = tbuf; } } if (negated) { bad_negation("pickup_types", TRUE); return; } while (*op == ' ') op++; if (*op != 'a' && *op != 'A') { num = 0; while (*op) { oc_sym = def_char_to_objclass(*op); /* make sure all are valid obj symbols occurring once */ if (oc_sym != MAXOCLASSES && !index(flags.pickup_types, oc_sym)) { flags.pickup_types[num] = (char) oc_sym; flags.pickup_types[++num] = '\0'; } else badopt = TRUE; op++; } if (badopt) badoption(opts); } return; } /* pile limit: when walking over objects, number which triggers "there are several/many objects here" instead of listing them */ fullname = "pile_limit"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) flags.pile_limit = negated ? 0 : atoi(op); else if (negated) bad_negation(fullname, TRUE); else /* !op */ flags.pile_limit = PILE_LIMIT_DFLT; /* sanity check */ if (flags.pile_limit < 0) flags.pile_limit = PILE_LIMIT_DFLT; return; } /* play mode: normal, explore/discovery, or debug/wizard */ fullname = "playmode"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) bad_negation(fullname, FALSE); if (duplicate || negated) return; op = string_for_opt(opts, TRUE); if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) { wizard = discover = FALSE; } else if (!strncmpi(op, "explore", 6) || !strncmpi(op, "discovery", 6)) { wizard = FALSE, discover = TRUE; } else if (!strncmpi(op, "debug", 5) || !strncmpi(op, "wizard", 6)) { wizard = TRUE, discover = FALSE; } else { raw_printf("Invalid value for \"%s\":%s.", fullname, op); } return; } /* WINCAP * player_selection: dialog | prompts */ fullname = "player_selection"; if (match_optname(opts, fullname, sizeof("player_selection") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi(op, "dialog", sizeof("dialog") - 1)) iflags.wc_player_selection = VIA_DIALOG; else if (!strncmpi(op, "prompt", sizeof("prompt") - 1)) iflags.wc_player_selection = VIA_PROMPTS; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* things to disclose at end of game */ if (match_optname(opts, "disclose", 7, TRUE)) { /* * The order that the end_disclose options are stored: * inventory, attribs, vanquished, genocided, * conduct, overview. * There is an array in flags: * end_disclose[NUM_DISCLOSURE_OPT]; * with option settings for the each of the following: * iagvc [see disclosure_options in decl.c]: * Legal setting values in that array are: * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask * * Those setting values can be used in the option * string as a prefix to get the desired behaviour. * * For backward compatibility, no prefix is required, * and the presence of a i,a,g,v, or c without a prefix * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT. */ boolean badopt = FALSE; int idx, prefix_val; if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, TRUE); if (op && negated) { bad_negation("disclose", TRUE); return; } /* "disclose" without a value means "all with prompting" and negated means "none without prompting" */ if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) { if (op && !strcmpi(op, "none")) negated = TRUE; for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++) flags.end_disclose[num] = negated ? DISCLOSE_NO_WITHOUT_PROMPT : DISCLOSE_PROMPT_DEFAULT_YES; return; } num = 0; prefix_val = -1; while (*op && num < sizeof flags.end_disclose - 1) { static char valid_settings[] = { DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO, DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT, '\0' }; register char c, *dop; c = lowc(*op); if (c == 'k') c = 'v'; /* killed -> vanquished */ if (c == 'd') c = 'o'; /* dungeon -> overview */ dop = index(disclosure_options, c); if (dop) { idx = (int) (dop - disclosure_options); if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) { impossible("bad disclosure index %d %c", idx, c); continue; } if (prefix_val != -1) { flags.end_disclose[idx] = prefix_val; prefix_val = -1; } else flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT; } else if (index(valid_settings, c)) { prefix_val = c; } else if (c == ' ') { ; /* do nothing */ } else badopt = TRUE; op++; } if (badopt) badoption(opts); return; } /* scores:5t[op] 5a[round] o[wn] */ if (match_optname(opts, "scores", 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation("scores", FALSE); return; } if (!(op = string_for_opt(opts, FALSE))) return; while (*op) { int inum = 1; if (digit(*op)) { inum = atoi(op); while (digit(*op)) op++; } else if (*op == '!') { negated = !negated; op++; } while (*op == ' ') op++; switch (*op) { case 't': case 'T': flags.end_top = inum; break; case 'a': case 'A': flags.end_around = inum; break; case 'o': case 'O': flags.end_own = !negated; break; default: badoption(opts); return; } while (letter(*++op) || *op == ' ') continue; if (*op == '/') op++; } return; } fullname = "sortloot"; if (match_optname(opts, fullname, 4, TRUE)) { op = string_for_env_opt(fullname, opts, FALSE); if (op) { switch (tolower(*op)) { case 'n': case 'l': case 'f': flags.sortloot = tolower(*op); break; default: badoption(opts); return; } } return; } fullname = "suppress_alert"; if (match_optname(opts, fullname, 4, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (negated) bad_negation(fullname, FALSE); else if (op) (void) feature_alert_opts(op, fullname); return; } #ifdef VIDEOSHADES /* videocolors:string */ fullname = "videocolors"; if (match_optname(opts, fullname, 6, TRUE) || match_optname(opts, "videocolours", 10, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_videocolors(opts)) badoption(opts); return; } /* videoshades:string */ fullname = "videoshades"; if (match_optname(opts, fullname, 6, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_videoshades(opts)) badoption(opts); return; } #endif /* VIDEOSHADES */ #ifdef MSDOS #ifdef NO_TERMS /* video:string -- must be after longer tests */ fullname = "video"; if (match_optname(opts, fullname, 5, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_video(opts)) badoption(opts); return; } #endif /* NO_TERMS */ /* soundcard:string -- careful not to match boolean 'sound' */ fullname = "soundcard"; if (match_optname(opts, fullname, 6, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_soundcard(opts)) badoption(opts); return; } #endif /* MSDOS */ /* WINCAP * * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12| * ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */ fullname = "map_mode"; if (match_optname(opts, fullname, sizeof("map_mode") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi(op, "tiles", sizeof("tiles") - 1)) iflags.wc_map_mode = MAP_MODE_TILES; else if (!strncmpi(op, "ascii4x6", sizeof("ascii4x6") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII4x6; else if (!strncmpi(op, "ascii6x8", sizeof("ascii6x8") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII6x8; else if (!strncmpi(op, "ascii8x8", sizeof("ascii8x8") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII8x8; else if (!strncmpi(op, "ascii16x8", sizeof("ascii16x8") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII16x8; else if (!strncmpi(op, "ascii7x12", sizeof("ascii7x12") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII7x12; else if (!strncmpi(op, "ascii8x12", sizeof("ascii8x12") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII8x12; else if (!strncmpi(op, "ascii16x12", sizeof("ascii16x12") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII16x12; else if (!strncmpi(op, "ascii12x16", sizeof("ascii12x16") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII12x16; else if (!strncmpi(op, "ascii10x18", sizeof("ascii10x18") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII10x18; else if (!strncmpi(op, "fit_to_screen", sizeof("fit_to_screen") - 1)) iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * scroll_amount:nn */ fullname = "scroll_amount"; if (match_optname(opts, fullname, sizeof("scroll_amount") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_scroll_amount = negated ? 1 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * scroll_margin:nn */ fullname = "scroll_margin"; if (match_optname(opts, fullname, sizeof("scroll_margin") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_scroll_margin = negated ? 5 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } fullname = "subkeyvalue"; if (match_optname(opts, fullname, 5, TRUE)) { /* no duplicate complaint here */ if (negated) { bad_negation(fullname, FALSE); } else { #if defined(WIN32) op = string_for_opt(opts, 0); map_subkeyvalue(op); #endif } return; } /* WINCAP * tile_width:nn */ fullname = "tile_width"; if (match_optname(opts, fullname, sizeof("tile_width") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_tile_width = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * tile_file:name */ fullname = "tile_file"; if (match_optname(opts, fullname, sizeof("tile_file") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if ((op = string_for_opt(opts, FALSE)) != 0) { if (iflags.wc_tile_file) free(iflags.wc_tile_file); iflags.wc_tile_file = (char *) alloc(strlen(op) + 1); Strcpy(iflags.wc_tile_file, op); } return; } /* WINCAP * tile_height:nn */ fullname = "tile_height"; if (match_optname(opts, fullname, sizeof("tile_height") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_tile_height = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * vary_msgcount:nn */ fullname = "vary_msgcount"; if (match_optname(opts, fullname, sizeof("vary_msgcount") - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_vary_msgcount = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } fullname = "windowtype"; if (match_optname(opts, fullname, 3, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { char buf[WINTYPELEN]; nmcpy(buf, op, WINTYPELEN); choose_windows(buf); } return; } #ifdef WINCHAIN fullname = "windowchain"; if (match_optname(opts, fullname, 3, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { char buf[WINTYPELEN]; nmcpy(buf, op, WINTYPELEN); addto_windowchain(buf); } return; } #endif /* WINCAP * setting window colors * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd */ fullname = "windowcolors"; if (match_optname(opts, fullname, 7, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if ((op = string_for_opt(opts, FALSE)) != 0) { if (!wc_set_window_colors(op)) badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* menustyle:traditional or combination or full or partial */ if (match_optname(opts, "menustyle", 4, TRUE)) { int tmp; boolean val_required = (strlen(opts) > 5 && !negated); if (duplicate) complain_about_duplicate(opts, 1); if (!(op = string_for_opt(opts, !val_required))) { if (val_required) return; /* string_for_opt gave feedback */ tmp = negated ? 'n' : 'f'; } else { tmp = tolower(*op); } switch (tmp) { case 'n': /* none */ case 't': /* traditional */ flags.menu_style = MENU_TRADITIONAL; break; case 'c': /* combo: trad.class sel+menu */ flags.menu_style = MENU_COMBINATION; break; case 'p': /* partial: no class menu */ flags.menu_style = MENU_PARTIAL; break; case 'f': /* full: class menu + menu */ flags.menu_style = MENU_FULL; break; default: badoption(opts); } return; } fullname = "menu_headings"; if (match_optname(opts, fullname, 12, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } for (i = 0; i < SIZE(attrnames); i++) if (!strcmpi(opts, attrnames[i].name)) { iflags.menu_headings = attrnames[i].attr; return; } badoption(opts); return; } /* check for menu command mapping */ for (i = 0; i < NUM_MENU_CMDS; i++) { fullname = default_menu_cmd_info[i].name; if (duplicate) complain_about_duplicate(opts, 1); if (match_optname(opts, fullname, (int) strlen(fullname), TRUE)) { if (negated) { bad_negation(fullname, FALSE); } else if ((op = string_for_opt(opts, FALSE)) != 0) { int j; char c, op_buf[BUFSZ]; boolean isbad = FALSE; escapes(op, op_buf); c = *op_buf; if (c == 0 || c == '\r' || c == '\n' || c == '\033' || c == ' ' || digit(c) || (letter(c) && c != '@')) isbad = TRUE; else /* reject default object class symbols */ for (j = 1; j < MAXOCLASSES; j++) if (c == def_oc_syms[i].sym) { isbad = TRUE; break; } if (isbad) badoption(opts); else add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd); } return; } } #if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES) /* hilite fields in status prompt */ if (match_optname(opts, "hilite_status", 13, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, TRUE); if (op && negated) { clear_status_hilites(tfrom_file); return; } else if (!op) { /* a value is mandatory */ badoption(opts); return; } if (!set_status_hilites(op, tfrom_file)) badoption(opts); return; } #endif #if defined(BACKWARD_COMPAT) fullname = "DECgraphics"; if (match_optname(opts, fullname, 3, TRUE)) { boolean badflag = FALSE; if (duplicate) complain_about_duplicate(opts, 1); if (!negated) { /* There is no rogue level DECgraphics-specific set */ if (symset[PRIMARY].name) { badflag = TRUE; } else { symset[PRIMARY].name = dupstr(fullname); if (!read_sym_file(PRIMARY)) { badflag = TRUE; clear_symsetentry(PRIMARY, TRUE); } else switch_symbols(TRUE); } if (badflag) { pline("Failure to load symbol set %s.", fullname); wait_synch(); } } return; } fullname = "IBMgraphics"; if (match_optname(opts, fullname, 3, TRUE)) { const char *sym_name = fullname; boolean badflag = FALSE; if (duplicate) complain_about_duplicate(opts, 1); if (!negated) { for (i = 0; i < NUM_GRAPHICS; ++i) { if (symset[i].name) { badflag = TRUE; } else { if (i == ROGUESET) sym_name = "RogueIBM"; symset[i].name = dupstr(sym_name); if (!read_sym_file(i)) { badflag = TRUE; clear_symsetentry(i, TRUE); break; } } } if (badflag) { pline("Failure to load symbol set %s.", sym_name); wait_synch(); } else { switch_symbols(TRUE); if (!initial && Is_rogue_level(&u.uz)) assign_graphics(ROGUESET); } } return; } #endif #ifdef MAC_GRAPHICS_ENV fullname = "MACgraphics"; if (match_optname(opts, fullname, 3, TRUE)) { boolean badflag = FALSE; if (duplicate) complain_about_duplicate(opts, 1); if (!negated) { if (symset[PRIMARY].name) { badflag = TRUE; } else { symset[PRIMARY].name = dupstr(fullname); if (!read_sym_file(PRIMARY)) { badflag = TRUE; clear_symsetentry(PRIMARY, TRUE); } } if (badflag) { pline("Failure to load symbol set %s.", fullname); wait_synch(); } else { switch_symbols(TRUE); if (!initial && Is_rogue_level(&u.uz)) assign_graphics(ROGUESET); } } return; } #endif /* OK, if we still haven't recognized the option, check the boolean * options list */ for (i = 0; boolopt[i].name; i++) { if (match_optname(opts, boolopt[i].name, 3, FALSE)) { /* options that don't exist */ if (!boolopt[i].addr) { if (!initial && !negated) pline_The("\"%s\" option is not available.", boolopt[i].name); return; } /* options that must come from config file */ if (!initial && (boolopt[i].optflags == SET_IN_FILE)) { rejectoption(boolopt[i].name); return; } *(boolopt[i].addr) = !negated; /* 0 means boolean opts */ if (duplicate_opt_detection(boolopt[i].name, 0)) complain_about_duplicate(boolopt[i].name, 0); #ifdef RLECOMP if ((boolopt[i].addr) == &iflags.rlecomp) { if (*boolopt[i].addr) set_savepref("rlecomp"); else set_savepref("!rlecomp"); } #endif #ifdef ZEROCOMP if ((boolopt[i].addr) == &iflags.zerocomp) { if (*boolopt[i].addr) set_savepref("zerocomp"); else set_savepref("externalcomp"); } #endif /* only do processing below if setting with doset() */ if (initial) return; if ((boolopt[i].addr) == &flags.time || (boolopt[i].addr) == &flags.showexp #ifdef SCORE_ON_BOTL || (boolopt[i].addr) == &flags.showscore #endif ) { #ifdef STATUS_VIA_WINDOWPORT status_initialize(REASSESS_ONLY); #endif context.botl = TRUE; } else if ((boolopt[i].addr) == &flags.invlet_constant) { if (flags.invlet_constant) reassign(); } else if (((boolopt[i].addr) == &flags.lit_corridor) || ((boolopt[i].addr) == &flags.dark_room)) { /* * All corridor squares seen via night vision or * candles & lamps change. Update them by calling * newsym() on them. Don't do this if we are * initializing the options --- the vision system * isn't set up yet. */ vision_recalc(2); /* shut down vision */ vision_full_recalc = 1; /* delayed recalc */ if (iflags.use_color) need_redraw = TRUE; /* darkroom refresh */ } else if ((boolopt[i].addr) == &iflags.use_inverse || (boolopt[i].addr) == &flags.showrace || (boolopt[i].addr) == &iflags.hilite_pet) { need_redraw = TRUE; #ifdef TEXTCOLOR } else if ((boolopt[i].addr) == &iflags.use_color) { need_redraw = TRUE; #ifdef TOS if ((boolopt[i].addr) == &iflags.use_color && iflags.BIOS) { if (colors_changed) restore_colors(); else set_colors(); } #endif #endif /* TEXTCOLOR */ } return; } } /* out of valid options */ badoption(opts); } static NEARDATA const char *menutype[] = { "traditional", "combination", "full", "partial" }; static NEARDATA const char *burdentype[] = { "unencumbered", "burdened", "stressed", "strained", "overtaxed", "overloaded" }; static NEARDATA const char *runmodes[] = { "teleport", "run", "walk", "crawl" }; static NEARDATA const char *sortltype[] = { "none", "loot", "full" }; /* * Convert the given string of object classes to a string of default object * symbols. */ STATIC_OVL void oc_to_str(src, dest) char *src, *dest; { int i; while ((i = (int) *src++) != 0) { if (i < 0 || i >= MAXOCLASSES) impossible("oc_to_str: illegal object class %d", i); else *dest++ = def_oc_syms[i].sym; } *dest = '\0'; } /* * Add the given mapping to the menu command map list. Always keep the * maps valid C strings. */ void add_menu_cmd_alias(from_ch, to_ch) char from_ch, to_ch; { if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) { pline("out of menu map space."); } else { mapped_menu_cmds[n_menu_mapped] = from_ch; mapped_menu_op[n_menu_mapped] = to_ch; n_menu_mapped++; mapped_menu_cmds[n_menu_mapped] = 0; mapped_menu_op[n_menu_mapped] = 0; } } /* * Map the given character to its corresponding menu command. If it * doesn't match anything, just return the original. */ char map_menu_cmd(ch) char ch; { char *found = index(mapped_menu_cmds, ch); if (found) { int idx = (int) (found - mapped_menu_cmds); ch = mapped_menu_op[idx]; } return ch; } #if defined(MICRO) || defined(MAC) || defined(WIN32) #define OPTIONS_HEADING "OPTIONS" #else #define OPTIONS_HEADING "NETHACKOPTIONS" #endif static char fmtstr_doset_add_menu[] = "%s%-15s [%s] "; static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]"; STATIC_OVL void doset_add_menu(win, option, indexoffset) winid win; /* window to add to */ const char *option; /* option name */ int indexoffset; /* value to add to index in compopt[], or zero if option cannot be changed */ { const char *value = "unknown"; /* current value */ char buf[BUFSZ], buf2[BUFSZ]; anything any; int i; any = zeroany; if (indexoffset == 0) { any.a_int = 0; value = get_compopt_value(option, buf2); } else { for (i = 0; compopt[i].name; i++) if (strcmp(option, compopt[i].name) == 0) break; if (compopt[i].name) { any.a_int = i + 1 + indexoffset; value = get_compopt_value(option, buf2); } else { /* We are trying to add an option not found in compopt[]. This is almost certainly bad, but we'll let it through anyway (with a zero value, so it can't be selected). */ any.a_int = 0; } } /* " " replaces "a - " -- assumes menus follow that style */ if (!iflags.menu_tab_sep) Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option, value); else Sprintf(buf, fmtstr_doset_add_menu_tab, option, value); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } /* Changing options via menu by Per Liboriussen */ int doset() { char buf[BUFSZ], buf2[BUFSZ]; int i = 0, pass, boolcount, pick_cnt, pick_idx, opt_indx; boolean *bool_p; winid tmpwin; anything any; menu_item *pick_list; int indexoffset, startpass, endpass; boolean setinitial = FALSE, fromfile = FALSE; int biggest_name = 0; const char *n_currently_set = "(%d currently set)"; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Booleans (selecting will toggle value):", MENU_UNSELECTED); any.a_int = 0; /* first list any other non-modifiable booleans, then modifiable ones */ for (pass = 0; pass <= 1; pass++) for (i = 0; boolopt[i].name; i++) if ((bool_p = boolopt[i].addr) != 0 && ((boolopt[i].optflags == DISP_IN_GAME && pass == 0) || (boolopt[i].optflags == SET_IN_GAME && pass == 1))) { if (bool_p == &flags.female) continue; /* obsolete */ if (bool_p == &iflags.sanity_check && !wizard) continue; if (bool_p == &iflags.menu_tab_sep && !wizard) continue; if (is_wc_option(boolopt[i].name) && !wc_supported(boolopt[i].name)) continue; if (is_wc2_option(boolopt[i].name) && !wc2_supported(boolopt[i].name)) continue; any.a_int = (pass == 0) ? 0 : i + 1; if (!iflags.menu_tab_sep) Sprintf(buf, "%s%-17s [%s]", pass == 0 ? " " : "", boolopt[i].name, *bool_p ? "true" : "false"); else Sprintf(buf, "%s\t[%s]", boolopt[i].name, *bool_p ? "true" : "false"); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } boolcount = i; indexoffset = boolcount; any = zeroany; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Compounds (selecting will prompt for new value):", MENU_UNSELECTED); #ifdef notyet /* SYSCF */ /* XXX I think this is still fragile. Fixing initial/from_file and/or changing the SET_* etc to bitmaps will let me make this better. */ if (wizard) startpass = SET_IN_SYS; else #endif startpass = DISP_IN_GAME; endpass = SET_IN_GAME; /* spin through the options to find the biggest name and adjust the format string accordingly if needed */ biggest_name = 0; for (i = 0; compopt[i].name; i++) if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass && strlen(compopt[i].name) > (unsigned) biggest_name) biggest_name = (int) strlen(compopt[i].name); if (biggest_name > 30) biggest_name = 30; if (!iflags.menu_tab_sep) Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name); /* deliberately put `playmode', `name', `role', `race', `gender' first (also alignment if anything ever comes before it in compopt[]) */ doset_add_menu(tmpwin, "playmode", 0); doset_add_menu(tmpwin, "name", 0); doset_add_menu(tmpwin, "role", 0); doset_add_menu(tmpwin, "race", 0); doset_add_menu(tmpwin, "gender", 0); for (pass = startpass; pass <= endpass; pass++) for (i = 0; compopt[i].name; i++) if (compopt[i].optflags == pass) { if (!strcmp(compopt[i].name, "playmode") || !strcmp(compopt[i].name, "name") || !strcmp(compopt[i].name, "role") || !strcmp(compopt[i].name, "race") || !strcmp(compopt[i].name, "gender")) continue; else if (is_wc_option(compopt[i].name) && !wc_supported(compopt[i].name)) continue; else if (is_wc2_option(compopt[i].name) && !wc2_supported(compopt[i].name)) continue; else doset_add_menu(tmpwin, compopt[i].name, (pass == DISP_IN_GAME) ? 0 : indexoffset); } any.a_int = -4; Sprintf(buf2, n_currently_set, msgtype_count()); Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", "message types", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); any.a_int = -3; Sprintf(buf2, n_currently_set, count_menucolors()); Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", "menucolors", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); #ifdef STATUS_VIA_WINDOWPORT #ifdef STATUS_HILITES any.a_int = -2; get_status_hilites(buf2, 60); if (!*buf2) Sprintf(buf2, "%s", "(none)"); if (!iflags.menu_tab_sep) Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", "status_hilites", buf2); else Sprintf(buf, fmtstr_doset_add_menu_tab, "status_hilites", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); #endif #endif any.a_int = -1; Sprintf(buf2, n_currently_set, count_ape_maps((int *) 0, (int *) 0)); Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", "autopickup exceptions", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); #ifdef PREFIXES_IN_USE any = zeroany; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Variable playground locations:", MENU_UNSELECTED); for (i = 0; i < PREFIX_COUNT; i++) doset_add_menu(tmpwin, fqn_prefix_names[i], 0); #endif end_menu(tmpwin, "Set what options?"); need_redraw = FALSE; if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) { /* * Walk down the selection list and either invert the booleans * or prompt for new values. In most cases, call parseoptions() * to take care of options that require special attention, like * redraws. */ for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_indx = pick_list[pick_idx].item.a_int - 1; if (opt_indx == -2) { /* -2 due to -1 offset for select_menu() */ (void) special_handling("autopickup_exception", setinitial, fromfile); #ifdef STATUS_VIA_WINDOWPORT #ifdef STATUS_HILITES } else if (opt_indx == -3) { /* -3 due to -1 offset for select_menu() */ if (!status_hilite_menu()) { pline("Bad status hilite(s) specified."); } else { if (wc2_supported("status_hilites")) preference_update("status_hilites"); } #endif #endif } else if (opt_indx == -4) { (void) special_handling("menucolors", setinitial, fromfile); } else if (opt_indx == -5) { (void) special_handling("msgtype", setinitial, fromfile); } else if (opt_indx < boolcount) { /* boolean option */ Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "", boolopt[opt_indx].name); parseoptions(buf, setinitial, fromfile); if (wc_supported(boolopt[opt_indx].name) || wc2_supported(boolopt[opt_indx].name)) preference_update(boolopt[opt_indx].name); } else { /* compound option */ opt_indx -= boolcount; if (!special_handling(compopt[opt_indx].name, setinitial, fromfile)) { Sprintf(buf, "Set %s to what?", compopt[opt_indx].name); getlin(buf, buf2); if (buf2[0] == '\033') continue; Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2); /* pass the buck */ parseoptions(buf, setinitial, fromfile); } if (wc_supported(compopt[opt_indx].name) || wc2_supported(compopt[opt_indx].name)) preference_update(compopt[opt_indx].name); } } free((genericptr_t) pick_list); pick_list = (menu_item *) 0; } destroy_nhwindow(tmpwin); if (need_redraw) { reglyph_darkroom(); (void) doredraw(); } return 0; } int handle_add_list_remove(optname, numtotal) const char *optname; int numtotal; { winid tmpwin; anything any; int i, pick_cnt, pick_idx, opt_idx; menu_item *pick_list = (menu_item *) 0; static const struct action { char letr; const char *desc; } action_titles[] = { { 'a', "add new %s" }, /* [0] */ { 'l', "list %s" }, /* [1] */ { 'r', "remove existing %s" }, /* [2] */ { 'x', "exit this menu" }, /* [3] */ }; opt_idx = 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(action_titles); i++) { char tmpbuf[BUFSZ]; any.a_int++; /* omit list and remove if there aren't any yet */ if (!numtotal && (i == 1 || i == 2)) continue; Sprintf(tmpbuf, action_titles[i].desc, (i == 1) ? makeplural(optname) : optname); add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE, tmpbuf, #if 0 /* this ought to work but doesn't... */ (action_titles[i].letr == 'x') ? MENU_SELECTED : #endif MENU_UNSELECTED); } end_menu(tmpwin, "Do what?"); if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_idx = pick_list[pick_idx].item.a_int - 1; } free((genericptr_t) pick_list); pick_list = (menu_item *) 0; } destroy_nhwindow(tmpwin); if (pick_cnt < 1) opt_idx = 3; /* none selected, exit menu */ return opt_idx; } struct symsetentry *symset_list = 0; /* files.c will populate this with list of available sets */ STATIC_OVL boolean special_handling(optname, setinitial, setfromfile) const char *optname; boolean setinitial, setfromfile; { winid tmpwin; anything any; int i; char buf[BUFSZ]; /* Special handling of menustyle, pickup_burden, pickup_types, * disclose, runmode, msg_window, menu_headings, sortloot, * and number_pad options. * Also takes care of interactive autopickup_exception_handling changes. */ if (!strcmp("menustyle", optname)) { const char *style_name; menu_item *style_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(menutype); i++) { style_name = menutype[i]; /* note: separate `style_name' variable used to avoid an optimizer bug in VAX C V2.3 */ any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE, style_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select menustyle:"); if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) { flags.menu_style = style_pick->item.a_int - 1; free((genericptr_t) style_pick); } destroy_nhwindow(tmpwin); } else if (!strcmp("paranoid_confirmation", optname)) { menu_item *paranoia_picks = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; paranoia[i].flagmask != 0; ++i) { if (paranoia[i].flagmask == PARANOID_BONES && !wizard) continue; any.a_int = paranoia[i].flagmask; add_menu(tmpwin, NO_GLYPH, &any, *paranoia[i].argname, 0, ATR_NONE, paranoia[i].explain, (flags.paranoia_bits & paranoia[i].flagmask) ? MENU_SELECTED : MENU_UNSELECTED); } end_menu(tmpwin, "Actions requiring extra confirmation:"); i = select_menu(tmpwin, PICK_ANY, ¶noia_picks); if (i >= 0) { /* player didn't cancel; we reset all the paranoia options here even if there were no items picked, since user could have toggled off preselected ones to end up with 0 */ flags.paranoia_bits = 0; if (i > 0) { /* at least 1 item set, either preselected or newly picked */ while (--i >= 0) flags.paranoia_bits |= paranoia_picks[i].item.a_int; free((genericptr_t) paranoia_picks); } } destroy_nhwindow(tmpwin); } else if (!strcmp("pickup_burden", optname)) { const char *burden_name, *burden_letters = "ubsntl"; menu_item *burden_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(burdentype); i++) { burden_name = burdentype[i]; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE, burden_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select encumbrance level:"); if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) { flags.pickup_burden = burden_pick->item.a_int - 1; free((genericptr_t) burden_pick); } destroy_nhwindow(tmpwin); } else if (!strcmp("pickup_types", optname)) { /* parseoptions will prompt for the list of types */ parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile); } else if (!strcmp("disclose", optname)) { /* order of disclose_names[] must correspond to disclosure_options in decl.c */ static const char *disclosure_names[] = { "inventory", "attributes", "vanquished", "genocides", "conduct", "overview", }; int disc_cat[NUM_DISCLOSURE_OPTIONS]; int pick_cnt, pick_idx, opt_idx; menu_item *disclosure_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) { Sprintf(buf, "%-12s[%c%c]", disclosure_names[i], flags.end_disclose[i], disclosure_options[i]); any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0, ATR_NONE, buf, MENU_UNSELECTED); disc_cat[i] = 0; } end_menu(tmpwin, "Change which disclosure options categories:"); pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_pick); if (pick_cnt > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_idx = disclosure_pick[pick_idx].item.a_int - 1; disc_cat[opt_idx] = 1; } free((genericptr_t) disclosure_pick); disclosure_pick = (menu_item *) 0; } destroy_nhwindow(tmpwin); for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) { if (disc_cat[i]) { Sprintf(buf, "Disclosure options for %s:", disclosure_names[i]); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; /* 'y','n',and '+' work as alternate selectors; '-' doesn't */ any.a_char = DISCLOSE_NO_WITHOUT_PROMPT; add_menu(tmpwin, NO_GLYPH, &any, 'a', any.a_char, ATR_NONE, "Never disclose, without prompting", MENU_UNSELECTED); any.a_char = DISCLOSE_YES_WITHOUT_PROMPT; add_menu(tmpwin, NO_GLYPH, &any, 'b', any.a_char, ATR_NONE, "Always disclose, without prompting", MENU_UNSELECTED); any.a_char = DISCLOSE_PROMPT_DEFAULT_NO; add_menu(tmpwin, NO_GLYPH, &any, 'c', any.a_char, ATR_NONE, "Prompt, with default answer of \"No\"", MENU_UNSELECTED); any.a_char = DISCLOSE_PROMPT_DEFAULT_YES; add_menu(tmpwin, NO_GLYPH, &any, 'd', any.a_char, ATR_NONE, "Prompt, with default answer of \"Yes\"", MENU_UNSELECTED); end_menu(tmpwin, buf); if (select_menu(tmpwin, PICK_ONE, &disclosure_pick) > 0) { flags.end_disclose[i] = disclosure_pick->item.a_char; free((genericptr_t) disclosure_pick); } destroy_nhwindow(tmpwin); } } } else if (!strcmp("runmode", optname)) { const char *mode_name; menu_item *mode_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(runmodes); i++) { mode_name = runmodes[i]; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE, mode_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select run/travel display mode:"); if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { flags.runmode = mode_pick->item.a_int - 1; free((genericptr_t) mode_pick); } destroy_nhwindow(tmpwin); } else if (!strcmp("msg_window", optname)) { #ifdef TTY_GRAPHICS /* by Christian W. Cooper */ menu_item *window_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; any.a_char = 's'; add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE, "single", MENU_UNSELECTED); any.a_char = 'c'; add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE, "combination", MENU_UNSELECTED); any.a_char = 'f'; add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full", MENU_UNSELECTED); any.a_char = 'r'; add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed", MENU_UNSELECTED); end_menu(tmpwin, "Select message history display type:"); if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { iflags.prevmsg_window = window_pick->item.a_char; free((genericptr_t) window_pick); } destroy_nhwindow(tmpwin); #endif } else if (!strcmp("sortloot", optname)) { const char *sortl_name; menu_item *sortl_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(sortltype); i++) { sortl_name = sortltype[i]; any.a_char = *sortl_name; add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE, sortl_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select loot sorting type:"); if (select_menu(tmpwin, PICK_ONE, &sortl_pick) > 0) { flags.sortloot = sortl_pick->item.a_char; free((genericptr_t) sortl_pick); } destroy_nhwindow(tmpwin); } else if (!strcmp("align_message", optname) || !strcmp("align_status", optname)) { menu_item *window_pick = (menu_item *) 0; char abuf[BUFSZ]; boolean msg = (*(optname + 6) == 'm'); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; any.a_int = ALIGN_TOP; add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top", MENU_UNSELECTED); any.a_int = ALIGN_BOTTOM; add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom", MENU_UNSELECTED); any.a_int = ALIGN_LEFT; add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left", MENU_UNSELECTED); any.a_int = ALIGN_RIGHT; add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right", MENU_UNSELECTED); Sprintf(abuf, "Select %s window placement relative to the map:", msg ? "message" : "status"); end_menu(tmpwin, abuf); if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { if (msg) iflags.wc_align_message = window_pick->item.a_int; else iflags.wc_align_status = window_pick->item.a_int; free((genericptr_t) window_pick); } destroy_nhwindow(tmpwin); } else if (!strcmp("number_pad", optname)) { static const char *npchoices[] = { " 0 (off)", " 1 (on)", " 2 (on, MSDOS compatible)", " 3 (on, phone-style digit layout)", " 4 (on, phone-style layout, MSDOS compatible)", "-1 (off, 'z' to move upper-left, 'y' to zap wands)" }; menu_item *mode_pick = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(npchoices); i++) { any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE, npchoices[i], MENU_UNSELECTED); } end_menu(tmpwin, "Select number_pad mode:"); if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { switch (mode_pick->item.a_int - 1) { case 0: iflags.num_pad = FALSE; iflags.num_pad_mode = 0; break; case 1: iflags.num_pad = TRUE; iflags.num_pad_mode = 0; break; case 2: iflags.num_pad = TRUE; iflags.num_pad_mode = 1; break; case 3: iflags.num_pad = TRUE; iflags.num_pad_mode = 2; break; case 4: iflags.num_pad = TRUE; iflags.num_pad_mode = 3; break; /* last menu choice: number_pad == -1 */ case 5: iflags.num_pad = FALSE; iflags.num_pad_mode = 1; break; } reset_commands(FALSE); number_pad(iflags.num_pad ? 1 : 0); free((genericptr_t) mode_pick); } destroy_nhwindow(tmpwin); } else if (!strcmp("menu_headings", optname)) { int mhattr = query_attr("How to highlight menu headings:"); if (mhattr != -1) iflags.menu_headings = mhattr; } else if (!strcmp("msgtype", optname)) { int opt_idx, nmt, mttyp; char mtbuf[BUFSZ]; msgtypes_again: nmt = msgtype_count(); opt_idx = handle_add_list_remove("message type", nmt); if (opt_idx == 3) { ; /* done--fall through to function exit */ } else if (opt_idx == 0) { /* add new */ getlin("What new message pattern?", mtbuf); if (*mtbuf == '\033' || !*mtbuf) goto msgtypes_again; mttyp = query_msgtype(); if (mttyp == -1) goto msgtypes_again; if (!msgtype_add(mttyp, mtbuf)) { pline("Error adding the message type."); wait_synch(); goto msgtypes_again; } } else { /* list or remove */ int pick_idx, pick_cnt; int mt_idx; menu_item *pick_list = (menu_item *) 0; struct plinemsg_type *tmp = plinemsg_types; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; mt_idx = 0; while (tmp) { const char *mtype = msgtype2name(tmp->msgtype); any.a_int = ++mt_idx; Sprintf(mtbuf, "%-5s \"%s\"", mtype, tmp->pattern); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf, MENU_UNSELECTED); tmp = tmp->next; } Sprintf(mtbuf, "%s message types", (opt_idx == 1) ? "List of" : "Remove which"); end_menu(tmpwin, mtbuf); pick_cnt = select_menu(tmpwin, (opt_idx == 1) ? PICK_NONE : PICK_ANY, &pick_list); if (pick_cnt > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) free_one_msgtype(pick_list[pick_idx].item.a_int - 1 - pick_idx); free((genericptr_t) pick_list), pick_list = (menu_item *) 0; } destroy_nhwindow(tmpwin); if (pick_cnt >= 0) goto msgtypes_again; } } else if (!strcmp("menucolors", optname)) { int opt_idx, nmc, mcclr, mcattr; char mcbuf[BUFSZ]; menucolors_again: nmc = count_menucolors(); opt_idx = handle_add_list_remove("menucolor", nmc); if (opt_idx == 3) { ; /* done--fall through to function exit */ } else if (opt_idx == 0) { /* add new */ getlin("What new menucolor pattern?", mcbuf); if (*mcbuf == '\033' || !*mcbuf) goto menucolors_again; mcclr = query_color(); if (mcclr == -1) goto menucolors_again; mcattr = query_attr(NULL); if (mcattr == -1) goto menucolors_again; if (!add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) { pline("Error adding the menu color."); wait_synch(); goto menucolors_again; } } else { /* list or remove */ int pick_idx, pick_cnt; int mc_idx; menu_item *pick_list = (menu_item *) 0; struct menucoloring *tmp = menu_colorings; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; mc_idx = 0; while (tmp) { const char *sattr = attr2attrname(tmp->attr); const char *sclr = clr2colorname(tmp->color); any.a_int = (++mc_idx); Sprintf(mcbuf, "\"%s\"=%s%s%s", tmp->origstr, sclr, (tmp->attr != ATR_NONE) ? " & " : "", (tmp->attr != ATR_NONE) ? sattr : ""); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf, MENU_UNSELECTED); tmp = tmp->next; } Sprintf(mcbuf, "%s menu colors", (opt_idx == 1) ? "List of" : "Remove which"); end_menu(tmpwin, mcbuf); pick_cnt = select_menu(tmpwin, (opt_idx == 1) ? PICK_NONE : PICK_ANY, &pick_list); if (pick_cnt > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) free_one_menu_coloring(pick_list[pick_idx].item.a_int - 1 - pick_idx); free((genericptr_t) pick_list), pick_list = (menu_item *) 0; } destroy_nhwindow(tmpwin); if (pick_cnt >= 0) goto menucolors_again; } } else if (!strcmp("autopickup_exception", optname)) { int opt_idx, pass, totalapes = 0, numapes[2] = { 0, 0 }; char apebuf[1 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */ struct autopickup_exception *ape; ape_again: totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]); opt_idx = handle_add_list_remove("autopickup exception", totalapes); if (opt_idx == 3) { ; /* done--fall through to function exit */ } else if (opt_idx == 0) { /* add new */ getlin("What new autopickup exception pattern?", &apebuf[1]); mungspaces(&apebuf[1]); /* regularize whitespace */ if (apebuf[1] == '\033') { ; /* fall through to function exit */ } else { if (apebuf[1]) { apebuf[0] = '\"'; /* guarantee room for \" prefix and \"\0 suffix; -2 is good enough for apebuf[] but -3 makes sure the whole thing fits within normal BUFSZ */ apebuf[sizeof apebuf - 3] = '\0'; Strcat(apebuf, "\""); add_autopickup_exception(apebuf); } goto ape_again; } } else { /* list or remove */ int pick_idx, pick_cnt; menu_item *pick_list = (menu_item *) 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { if (numapes[pass] == 0) continue; ape = iflags.autopickup_exceptions[pass]; any = zeroany; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, (pass == 0) ? "Never pickup" : "Always pickup", MENU_UNSELECTED); for (i = 0; i < numapes[pass] && ape; i++) { any.a_void = (opt_idx == 1) ? 0 : ape; Sprintf(apebuf, "\"%s\"", ape->pattern); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf, MENU_UNSELECTED); ape = ape->next; } } Sprintf(apebuf, "%s autopickup exceptions", (opt_idx == 1) ? "List of" : "Remove which"); end_menu(tmpwin, apebuf); pick_cnt = select_menu(tmpwin, (opt_idx == 1) ? PICK_NONE : PICK_ANY, &pick_list); if (pick_cnt > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) remove_autopickup_exception( (struct autopickup_exception *) pick_list[pick_idx].item.a_void); free((genericptr_t) pick_list), pick_list = (menu_item *) 0; } destroy_nhwindow(tmpwin); if (pick_cnt >= 0) goto ape_again; } } else if (!strcmp("symset", optname) || !strcmp("roguesymset", optname)) { menu_item *symset_pick = (menu_item *) 0; boolean primaryflag = (*optname == 's'), rogueflag = (*optname == 'r'), ready_to_switch = FALSE, nothing_to_do = FALSE; char *symset_name, fmtstr[20]; struct symsetentry *sl; int res, which_set, setcount = 0, chosen = -2; if (rogueflag) which_set = ROGUESET; else which_set = PRIMARY; /* clear symset[].name as a flag to read_sym_file() to build list */ symset_name = symset[which_set].name; symset[which_set].name = (char *) 0; symset_list = (struct symsetentry *) 0; res = read_sym_file(which_set); if (res && symset_list) { char symsetchoice[BUFSZ]; int let = 'a', biggest = 0, thissize = 0; sl = symset_list; while (sl) { /* check restrictions */ if ((!rogueflag && sl->rogue) || (!primaryflag && sl->primary)) { sl = sl->next; continue; } setcount++; /* find biggest name */ if (sl->name) thissize = strlen(sl->name); if (thissize > biggest) biggest = thissize; sl = sl->next; } if (!setcount) { pline("There are no appropriate %ssymbol sets available.", (rogueflag) ? "rogue level " : (primaryflag) ? "primary " : ""); return TRUE; } Sprintf(fmtstr, "%%-%ds %%s", biggest + 5); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; any.a_int = 1; add_menu(tmpwin, NO_GLYPH, &any, let++, 0, ATR_NONE, "Default Symbols", MENU_UNSELECTED); sl = symset_list; while (sl) { /* check restrictions */ if ((!rogueflag && sl->rogue) || (!primaryflag && sl->primary)) { sl = sl->next; continue; } if (sl->name) { any.a_int = sl->idx + 2; Sprintf(symsetchoice, fmtstr, sl->name, sl->desc ? sl->desc : ""); add_menu(tmpwin, NO_GLYPH, &any, let, 0, ATR_NONE, symsetchoice, MENU_UNSELECTED); if (let == 'z') let = 'A'; else let++; } sl = sl->next; } end_menu(tmpwin, "Select symbol set:"); if (select_menu(tmpwin, PICK_ONE, &symset_pick) > 0) { chosen = symset_pick->item.a_int - 2; free((genericptr_t) symset_pick); } destroy_nhwindow(tmpwin); if (chosen > -1) { /* chose an actual symset name from file */ sl = symset_list; while (sl) { if (sl->idx == chosen) { if (symset_name) { free((genericptr_t) symset_name); symset_name = (char *) 0; } /* free the now stale attributes */ clear_symsetentry(which_set, TRUE); /* transfer only the name of the symbol set */ symset[which_set].name = dupstr(sl->name); ready_to_switch = TRUE; break; } sl = sl->next; } } else if (chosen == -1) { /* explicit selection of defaults */ /* free the now stale symset attributes */ if (symset_name) { free((genericptr_t) symset_name); symset_name = (char *) 0; } clear_symsetentry(which_set, TRUE); } else nothing_to_do = TRUE; } else if (!res) { /* The symbols file could not be accessed */ pline("Unable to access \"%s\" file.", SYMBOLS); return TRUE; } else if (!symset_list) { /* The symbols file was empty */ pline("There were no symbol sets found in \"%s\".", SYMBOLS); return TRUE; } /* clean up */ while (symset_list) { sl = symset_list; if (sl->name) free((genericptr_t) sl->name); sl->name = (char *) 0; if (sl->desc) free((genericptr_t) sl->desc); sl->desc = (char *) 0; symset_list = sl->next; free((genericptr_t) sl); } if (nothing_to_do) return TRUE; if (!symset[which_set].name && symset_name) symset[which_set].name = symset_name; /* not dupstr() here */ /* Set default symbols and clear the handling value */ if (rogueflag) init_r_symbols(); else init_l_symbols(); if (symset[which_set].name) { if (read_sym_file(which_set)) { ready_to_switch = TRUE; } else { clear_symsetentry(which_set, TRUE); return TRUE; } } if (ready_to_switch) switch_symbols(TRUE); if (Is_rogue_level(&u.uz)) { if (rogueflag) assign_graphics(ROGUESET); } else if (!rogueflag) assign_graphics(PRIMARY); need_redraw = TRUE; return TRUE; } else { /* didn't match any of the special options */ return FALSE; } return TRUE; } #define rolestring(val, array, field) \ ((val >= 0) ? array[val].field : (val == ROLE_RANDOM) ? randomrole : none) /* This is ugly. We have all the option names in the compopt[] array, but we need to look at each option individually to get the value. */ STATIC_OVL const char * get_compopt_value(optname, buf) const char *optname; char *buf; { char ocl[MAXOCLASSES + 1]; static const char none[] = "(none)", randomrole[] = "random", to_be_done[] = "(to be done)", defopt[] = "default", defbrief[] = "def"; int i; buf[0] = '\0'; if (!strcmp(optname, "align_message")) Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP ? "top" : iflags.wc_align_message == ALIGN_LEFT ? "left" : iflags.wc_align_message == ALIGN_BOTTOM ? "bottom" : iflags.wc_align_message == ALIGN_RIGHT ? "right" : defopt); else if (!strcmp(optname, "align_status")) Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP ? "top" : iflags.wc_align_status == ALIGN_LEFT ? "left" : iflags.wc_align_status == ALIGN_BOTTOM ? "bottom" : iflags.wc_align_status == ALIGN_RIGHT ? "right" : defopt); else if (!strcmp(optname, "align")) Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj)); #ifdef WIN32 else if (!strcmp(optname, "altkeyhandler")) Sprintf(buf, "%s", iflags.altkeyhandler[0] ? iflags.altkeyhandler : "default"); #endif #ifdef BACKWARD_COMPAT else if (!strcmp(optname, "boulder")) Sprintf(buf, "%c", iflags.bouldersym ? iflags.bouldersym : showsyms[(int) objects[BOULDER].oc_class + SYM_OFF_O]); #endif else if (!strcmp(optname, "catname")) Sprintf(buf, "%s", catname[0] ? catname : none); else if (!strcmp(optname, "disclose")) for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) { if (i) (void) strkitten(buf, ' '); (void) strkitten(buf, flags.end_disclose[i]); (void) strkitten(buf, disclosure_options[i]); } else if (!strcmp(optname, "dogname")) Sprintf(buf, "%s", dogname[0] ? dogname : none); else if (!strcmp(optname, "dungeon")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "effects")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "font_map")) Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt); else if (!strcmp(optname, "font_message")) Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt); else if (!strcmp(optname, "font_status")) Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt); else if (!strcmp(optname, "font_menu")) Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt); else if (!strcmp(optname, "font_text")) Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt); else if (!strcmp(optname, "font_size_map")) { if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_message")) { if (iflags.wc_fontsiz_message) Sprintf(buf, "%d", iflags.wc_fontsiz_message); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_status")) { if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_menu")) { if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_text")) { if (iflags.wc_fontsiz_text) Sprintf(buf, "%d", iflags.wc_fontsiz_text); else Strcpy(buf, defopt); } else if (!strcmp(optname, "fruit")) Sprintf(buf, "%s", pl_fruit); else if (!strcmp(optname, "gender")) Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj)); else if (!strcmp(optname, "horsename")) Sprintf(buf, "%s", horsename[0] ? horsename : none); else if (!strcmp(optname, "map_mode")) Sprintf(buf, "%s", iflags.wc_map_mode == MAP_MODE_TILES ? "tiles" : iflags.wc_map_mode == MAP_MODE_ASCII4x6 ? "ascii4x6" : iflags.wc_map_mode == MAP_MODE_ASCII6x8 ? "ascii6x8" : iflags.wc_map_mode == MAP_MODE_ASCII8x8 ? "ascii8x8" : iflags.wc_map_mode == MAP_MODE_ASCII16x8 ? "ascii16x8" : iflags.wc_map_mode == MAP_MODE_ASCII7x12 ? "ascii7x12" : iflags.wc_map_mode == MAP_MODE_ASCII8x12 ? "ascii8x12" : iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" : iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" : iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" : iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ? "fit_to_screen" : defopt); else if (!strcmp(optname, "menustyle")) Sprintf(buf, "%s", menutype[(int) flags.menu_style]); else if (!strcmp(optname, "menu_deselect_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_deselect_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_first_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_invert_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_headings")) Sprintf(buf, "%s", attr2attrname(iflags.menu_headings)); else if (!strcmp(optname, "menu_invert_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_last_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_next_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_previous_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_search")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_select_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_select_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "monsters")) { Sprintf(buf, "%s", to_be_done); } else if (!strcmp(optname, "msghistory")) { Sprintf(buf, "%u", iflags.msg_history); #ifdef TTY_GRAPHICS } else if (!strcmp(optname, "msg_window")) { Sprintf(buf, "%s", (iflags.prevmsg_window == 's') ? "single" : (iflags.prevmsg_window == 'c') ? "combination" : (iflags.prevmsg_window == 'f') ? "full" : "reversed"); #endif } else if (!strcmp(optname, "name")) { Sprintf(buf, "%s", plname); } else if (!strcmp(optname, "number_pad")) { static const char *numpadmodes[] = { "0=off", "1=on", "2=on, MSDOS compatible", "3=on, phone-style layout", "4=on, phone layout, MSDOS compatible", "-1=off, y & z swapped", /*[5]*/ }; int indx = Cmd.num_pad ? (Cmd.phone_layout ? (Cmd.pcHack_compat ? 4 : 3) : (Cmd.pcHack_compat ? 2 : 1)) : Cmd.swap_yz ? 5 : 0; Strcpy(buf, numpadmodes[indx]); } else if (!strcmp(optname, "objects")) { Sprintf(buf, "%s", to_be_done); } else if (!strcmp(optname, "packorder")) { oc_to_str(flags.inv_order, ocl); Sprintf(buf, "%s", ocl); #ifdef CHANGE_COLOR } else if (!strcmp(optname, "palette")) { Sprintf(buf, "%s", get_color_string()); #endif } else if (!strcmp(optname, "paranoid_confirmation")) { char tmpbuf[QBUFSZ]; tmpbuf[0] = '\0'; if (ParanoidConfirm) Strcat(tmpbuf, " Confirm"); if (ParanoidQuit) Strcat(tmpbuf, " quit"); if (ParanoidDie) Strcat(tmpbuf, " die"); if (ParanoidBones) Strcat(tmpbuf, " bones"); if (ParanoidHit) Strcat(tmpbuf, " attack"); if (ParanoidPray) Strcat(tmpbuf, " pray"); if (ParanoidRemove) Strcat(tmpbuf, " Remove"); Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none"); } else if (!strcmp(optname, "pettype")) { Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" : (preferred_pet == 'd') ? "dog" : (preferred_pet == 'h') ? "horse" : (preferred_pet == 'n') ? "none" : "random"); } else if (!strcmp(optname, "pickup_burden")) { Sprintf(buf, "%s", burdentype[flags.pickup_burden]); } else if (!strcmp(optname, "pickup_types")) { oc_to_str(flags.pickup_types, ocl); Sprintf(buf, "%s", ocl[0] ? ocl : "all"); } else if (!strcmp(optname, "pile_limit")) { Sprintf(buf, "%d", flags.pile_limit); } else if (!strcmp(optname, "playmode")) { Strcpy(buf, wizard ? "debug" : discover ? "explore" : "normal"); } else if (!strcmp(optname, "race")) { Sprintf(buf, "%s", rolestring(flags.initrace, races, noun)); } else if (!strcmp(optname, "roguesymset")) { Sprintf(buf, "%s", symset[ROGUESET].name ? symset[ROGUESET].name : "default"); if (currentgraphics == ROGUESET && symset[ROGUESET].name) Strcat(buf, ", active"); } else if (!strcmp(optname, "role")) { Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m)); } else if (!strcmp(optname, "runmode")) { Sprintf(buf, "%s", runmodes[flags.runmode]); } else if (!strcmp(optname, "scores")) { Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, flags.end_own ? "/own" : ""); } else if (!strcmp(optname, "scroll_amount")) { if (iflags.wc_scroll_amount) Sprintf(buf, "%d", iflags.wc_scroll_amount); else Strcpy(buf, defopt); } else if (!strcmp(optname, "scroll_margin")) { if (iflags.wc_scroll_margin) Sprintf(buf, "%d", iflags.wc_scroll_margin); else Strcpy(buf, defopt); } else if (!strcmp(optname, "sortloot")) { for (i = 0; i < SIZE(sortltype); i++) if (flags.sortloot == sortltype[i][0]) { Strcpy(buf, sortltype[i]); break; } } else if (!strcmp(optname, "player_selection")) { Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog"); #ifdef MSDOS } else if (!strcmp(optname, "soundcard")) { Sprintf(buf, "%s", to_be_done); #endif } else if (!strcmp(optname, "suppress_alert")) { if (flags.suppress_alert == 0L) Strcpy(buf, none); else Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH); } else if (!strcmp(optname, "symset")) { Sprintf(buf, "%s", symset[PRIMARY].name ? symset[PRIMARY].name : "default"); if (currentgraphics == PRIMARY && symset[PRIMARY].name) Strcat(buf, ", active"); } else if (!strcmp(optname, "tile_file")) { Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt); } else if (!strcmp(optname, "tile_height")) { if (iflags.wc_tile_height) Sprintf(buf, "%d", iflags.wc_tile_height); else Strcpy(buf, defopt); } else if (!strcmp(optname, "tile_width")) { if (iflags.wc_tile_width) Sprintf(buf, "%d", iflags.wc_tile_width); else Strcpy(buf, defopt); } else if (!strcmp(optname, "traps")) { Sprintf(buf, "%s", to_be_done); } else if (!strcmp(optname, "vary_msgcount")) { if (iflags.wc_vary_msgcount) Sprintf(buf, "%d", iflags.wc_vary_msgcount); else Strcpy(buf, defopt); #ifdef MSDOS } else if (!strcmp(optname, "video")) { Sprintf(buf, "%s", to_be_done); #endif #ifdef VIDEOSHADES } else if (!strcmp(optname, "videoshades")) { Sprintf(buf, "%s-%s-%s", shade[0], shade[1], shade[2]); } else if (!strcmp(optname, "videocolors")) { Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", ttycolors[CLR_RED], ttycolors[CLR_GREEN], ttycolors[CLR_BROWN], ttycolors[CLR_BLUE], ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN], ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN], ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE], ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]); #endif /* VIDEOSHADES */ } else if (!strcmp(optname, "windowtype")) { Sprintf(buf, "%s", windowprocs.name); } else if (!strcmp(optname, "windowcolors")) { Sprintf( buf, "%s/%s %s/%s %s/%s %s/%s", iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief, iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief, iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief, iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief, iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief, iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief, iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief, iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief); #ifdef PREFIXES_IN_USE } else { for (i = 0; i < PREFIX_COUNT; ++i) if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i]) Sprintf(buf, "%s", fqn_prefix[i]); #endif } if (buf[0]) return buf; else return "unknown"; } int dotogglepickup() { char buf[BUFSZ], ocl[MAXOCLASSES + 1]; flags.pickup = !flags.pickup; if (flags.pickup) { oc_to_str(flags.pickup_types, ocl); Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all", (iflags.autopickup_exceptions[AP_LEAVE] || iflags.autopickup_exceptions[AP_GRAB]) ? ((count_ape_maps((int *) 0, (int *) 0) == 1) ? ", with one exception" : ", with some exceptions") : ""); } else { Strcpy(buf, "OFF"); } pline("Autopickup: %s.", buf); return 0; } int add_autopickup_exception(mapping) const char *mapping; { struct autopickup_exception *ape, **apehead; char text[256], *text2; boolean grab = FALSE; if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) { text2 = &text[0]; if (*text2 == '<') { /* force autopickup */ grab = TRUE; ++text2; } else if (*text2 == '>') { /* default - Do not pickup */ grab = FALSE; ++text2; } apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] : &iflags.autopickup_exceptions[AP_LEAVE]; ape = (struct autopickup_exception *) alloc( sizeof (struct autopickup_exception)); ape->regex = regex_init(); if (!regex_compile(text2, ape->regex)) { raw_print("regex error in AUTOPICKUP_EXCEPTION"); regex_free(ape->regex); free((genericptr_t) ape); return 0; } ape->pattern = (char *) alloc(strlen(text2) + 1); strcpy(ape->pattern, text2); ape->grab = grab; ape->next = *apehead; *apehead = ape; } else { raw_print("syntax error in AUTOPICKUP_EXCEPTION"); return 0; } return 1; } STATIC_OVL void remove_autopickup_exception(whichape) struct autopickup_exception *whichape; { struct autopickup_exception *ape, *prev = 0; int chain = whichape->grab ? AP_GRAB : AP_LEAVE; for (ape = iflags.autopickup_exceptions[chain]; ape;) { if (ape == whichape) { struct autopickup_exception *freeape = ape; ape = ape->next; if (prev) prev->next = ape; else iflags.autopickup_exceptions[chain] = ape; regex_free(freeape->regex); free((genericptr_t) freeape->pattern); free((genericptr_t) freeape); } else { prev = ape; ape = ape->next; } } } STATIC_OVL int count_ape_maps(leave, grab) int *leave, *grab; { struct autopickup_exception *ape; int pass, totalapes, numapes[2] = { 0, 0 }; for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { ape = iflags.autopickup_exceptions[pass]; while (ape) { ape = ape->next; numapes[pass]++; } } totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB]; if (leave) *leave = numapes[AP_LEAVE]; if (grab) *grab = numapes[AP_GRAB]; return totalapes; } void free_autopickup_exceptions() { struct autopickup_exception *ape; int pass; for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { while ((ape = iflags.autopickup_exceptions[pass]) != 0) { regex_free(ape->regex); free((genericptr_t) ape->pattern); iflags.autopickup_exceptions[pass] = ape->next; free((genericptr_t) ape); } } } /* bundle some common usage into one easy-to-use routine */ int load_symset(s, which_set) const char *s; int which_set; { clear_symsetentry(which_set, TRUE); if (symset[which_set].name) free((genericptr_t) symset[which_set].name); symset[which_set].name = dupstr(s); if (read_sym_file(which_set)) { switch_symbols(TRUE); } else { clear_symsetentry(which_set, TRUE); return 0; } return 1; } void free_symsets() { clear_symsetentry(PRIMARY, TRUE); clear_symsetentry(ROGUESET, TRUE); /* symset_list is cleaned up as soon as it's used, so we shouldn't have to anything about it here */ /* assert( symset_list == NULL ); */ } /* Parse the value of a SYMBOLS line from a config file */ void parsesymbols(opts) register char *opts; { int val; char *op, *symname, *strval; struct symparse *symp; if ((op = index(opts, ',')) != 0) { *op++ = 0; parsesymbols(op); } /* S_sample:string */ symname = opts; strval = index(opts, ':'); if (!strval) strval = index(opts, '='); if (!strval) return; *strval++ = '\0'; /* strip leading and trailing white space from symname and strval */ mungspaces(symname); mungspaces(strval); symp = match_sym(symname); if (!symp) return; if (symp->range && symp->range != SYM_CONTROL) { val = sym_val(strval); update_l_symset(symp, val); } } struct symparse * match_sym(buf) char *buf; { size_t len = strlen(buf); const char *p = index(buf, ':'), *q = index(buf, '='); struct symparse *sp = loadsyms; if (!p || (q && q < p)) p = q; if (p) { /* note: there will be at most one space before the '=' because caller has condensed buf[] with mungspaces() */ if (p > buf && p[-1] == ' ') p--; len = (int) (p - buf); } while (sp->range) { if ((len >= strlen(sp->name)) && !strncmpi(buf, sp->name, len)) return sp; sp++; } return (struct symparse *) 0; } int sym_val(strval) char *strval; { char buf[QBUFSZ]; buf[0] = '\0'; escapes(strval, buf); return (int) *buf; } /* data for option_help() */ static const char *opt_intro[] = { "", " NetHack Options Help:", "", #define CONFIG_SLOT 3 /* fill in next value at run-time */ (char *) 0, #if !defined(MICRO) && !defined(MAC) "or use `NETHACKOPTIONS=\"\"' in your environment", #endif "( is a list of options separated by commas)", #ifdef VMS "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"", #endif "or press \"O\" while playing and use the menu.", "", "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", (char *) 0 }; static const char *opt_epilog[] = { "", "Some of the options can be set only before the game is started; those", "items will not be selectable in the 'O' command's menu.", (char *) 0 }; void option_help() { char buf[BUFSZ], buf2[BUFSZ]; register int i; winid datawin; datawin = create_nhwindow(NHW_TEXT); Sprintf(buf, "Set options as OPTIONS= in %s", lastconfigfile); opt_intro[CONFIG_SLOT] = (const char *) buf; for (i = 0; opt_intro[i]; i++) putstr(datawin, 0, opt_intro[i]); /* Boolean options */ for (i = 0; boolopt[i].name; i++) { if (boolopt[i].addr) { if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue; if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue; next_opt(datawin, boolopt[i].name); } } next_opt(datawin, ""); /* Compound options */ putstr(datawin, 0, "Compound options:"); for (i = 0; compopt[i].name; i++) { Sprintf(buf2, "`%s'", compopt[i].name); Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr, compopt[i + 1].name ? ',' : '.'); putstr(datawin, 0, buf); } for (i = 0; opt_epilog[i]; i++) putstr(datawin, 0, opt_epilog[i]); display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); return; } /* * prints the next boolean option, on the same line if possible, on a new * line if not. End with next_opt(""). */ void next_opt(datawin, str) winid datawin; const char *str; { static char *buf = 0; int i; char *s; if (!buf) *(buf = (char *) alloc(BUFSZ)) = '\0'; if (!*str) { s = eos(buf); if (s > &buf[1] && s[-2] == ',') Strcpy(s - 2, "."); /* replace last ", " */ i = COLNO; /* (greater than COLNO - 2) */ } else { i = strlen(buf) + strlen(str) + 2; } if (i > COLNO - 2) { /* rule of thumb */ putstr(datawin, 0, buf); buf[0] = 0; } if (*str) { Strcat(buf, str); Strcat(buf, ", "); } else { putstr(datawin, 0, str); free((genericptr_t) buf), buf = 0; } return; } /* Returns the fid of the fruit type; if that type already exists, it * returns the fid of that one; if it does not exist, it adds a new fruit * type to the chain and returns the new one. * If replace_fruit is sent in, replace the fruit in the chain rather than * adding a new entry--for user specified fruits only. */ int fruitadd(str, replace_fruit) char *str; struct fruit *replace_fruit; { register int i; register struct fruit *f; int highest_fruit_id = 0; char buf[PL_FSIZ], altname[PL_FSIZ]; boolean user_specified = (str == pl_fruit); /* if not user-specified, then it's a fruit name for a fruit on * a bones level... */ /* Note: every fruit has an id (kept in obj->spe) of at least 1; * 0 is an error. */ if (user_specified) { boolean found = FALSE, numeric = FALSE; /* force fruit to be singular; this handling is not needed--or wanted--for fruits from bones because they already received it in their original game */ nmcpy(pl_fruit, makesingular(str), PL_FSIZ); /* assert( str == pl_fruit ); */ /* disallow naming after other foods (since it'd be impossible * to tell the difference) */ for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) { if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { found = TRUE; break; } } { char *c; c = pl_fruit; for (c = pl_fruit; *c >= '0' && *c <= '9'; c++) ; if (isspace((uchar) *c) || *c == 0) numeric = TRUE; } if (found || numeric || !strncmp(str, "cursed ", 7) || !strncmp(str, "uncursed ", 9) || !strncmp(str, "blessed ", 8) || !strncmp(str, "partly eaten ", 13) || (!strncmp(str, "tin of ", 7) && (!strcmp(str + 7, "spinach") || name_to_mon(str + 7) >= LOW_PM)) || !strcmp(str, "empty tin") || ((str_end_is(str, " corpse") || str_end_is(str, " egg")) && name_to_mon(str) >= LOW_PM)) { Strcpy(buf, pl_fruit); Strcpy(pl_fruit, "candied "); nmcpy(pl_fruit + 8, buf, PL_FSIZ - 8); } *altname = '\0'; /* This flag indicates that a fruit has been made since the * last time the user set the fruit. If it hasn't, we can * safely overwrite the current fruit, preventing the user from * setting many fruits in a row and overflowing. * Possible expansion: check for specific fruit IDs, not for * any fruit. */ flags.made_fruit = FALSE; if (replace_fruit) { for (f = ffruit; f; f = f->nextf) { if (f == replace_fruit) { copynchars(f->fname, str, PL_FSIZ - 1); goto nonew; } } } } else { /* not user_supplied, so assumed to be from bones */ copynchars(altname, str, PL_FSIZ - 1); sanitize_name(altname); flags.made_fruit = TRUE; /* for safety. Any fruit name added from a bones level should exist anyway. */ } for (f = ffruit; f; f = f->nextf) { if (f->fid > highest_fruit_id) highest_fruit_id = f->fid; if (!strncmp(str, f->fname, PL_FSIZ - 1) || (*altname && !strcmp(altname, f->fname))) goto nonew; } /* if adding another fruit would overflow spe, use a random fruit instead... we've got a lot to choose from. current_fruit remains as is. */ if (highest_fruit_id >= 127) return rnd(127); f = newfruit(); copynchars(f->fname, *altname ? altname : str, PL_FSIZ - 1); f->fid = ++highest_fruit_id; /* we used to go out of our way to add it at the end of the list, but the order is arbitrary so use simpler insertion at start */ f->nextf = ffruit; ffruit = f; nonew: if (user_specified) context.current_fruit = f->fid; return f->fid; } /* * This is a somewhat generic menu for taking a list of NetHack style * class choices and presenting them via a description * rather than the traditional NetHack characters. * (Benefits users whose first exposure to NetHack is via tiles). * * prompt * The title at the top of the menu. * * category: 0 = monster class * 1 = object class * * way * FALSE = PICK_ONE, TRUE = PICK_ANY * * class_list * a null terminated string containing the list of choices. * * class_selection * a null terminated string containing the selected characters. * * Returns number selected. */ int choose_classes_menu(prompt, category, way, class_list, class_select) const char *prompt; int category; boolean way; char *class_list; char *class_select; { menu_item *pick_list = (menu_item *) 0; winid win; anything any; char buf[BUFSZ]; int i, n; int ret; int next_accelerator, accelerator; if (class_list == (char *) 0 || class_select == (char *) 0) return 0; accelerator = 0; next_accelerator = 'a'; any = zeroany; win = create_nhwindow(NHW_MENU); start_menu(win); while (*class_list) { const char *text; boolean selected; text = (char *) 0; selected = FALSE; switch (category) { case 0: text = def_monsyms[def_char_to_monclass(*class_list)].explain; accelerator = *class_list; Sprintf(buf, "%s", text); break; case 1: text = def_oc_syms[def_char_to_objclass(*class_list)].explain; accelerator = next_accelerator; Sprintf(buf, "%c %s", *class_list, text); break; default: impossible("choose_classes_menu: invalid category %d", category); } if (way && *class_select) { /* Selections there already */ if (index(class_select, *class_list)) { selected = TRUE; } } any.a_int = *class_list; add_menu(win, NO_GLYPH, &any, accelerator, category ? *class_list : 0, ATR_NONE, buf, selected); ++class_list; if (category > 0) { ++next_accelerator; if (next_accelerator == ('z' + 1)) next_accelerator = 'A'; if (next_accelerator == ('Z' + 1)) break; } } end_menu(win, prompt); n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list); destroy_nhwindow(win); if (n > 0) { for (i = 0; i < n; ++i) *class_select++ = (char) pick_list[i].item.a_int; free((genericptr_t) pick_list); ret = n; } else if (n == -1) { class_select = eos(class_select); ret = -1; } else ret = 0; *class_select = '\0'; return ret; } struct wc_Opt wc_options[] = { { "ascii_map", WC_ASCII_MAP }, { "color", WC_COLOR }, { "eight_bit_tty", WC_EIGHT_BIT_IN }, { "hilite_pet", WC_HILITE_PET }, { "popup_dialog", WC_POPUP_DIALOG }, { "player_selection", WC_PLAYER_SELECTION }, { "preload_tiles", WC_PRELOAD_TILES }, { "tiled_map", WC_TILED_MAP }, { "tile_file", WC_TILE_FILE }, { "tile_width", WC_TILE_WIDTH }, { "tile_height", WC_TILE_HEIGHT }, { "use_inverse", WC_INVERSE }, { "align_message", WC_ALIGN_MESSAGE }, { "align_status", WC_ALIGN_STATUS }, { "font_map", WC_FONT_MAP }, { "font_menu", WC_FONT_MENU }, { "font_message", WC_FONT_MESSAGE }, #if 0 {"perm_invent", WC_PERM_INVENT}, #endif { "font_size_map", WC_FONTSIZ_MAP }, { "font_size_menu", WC_FONTSIZ_MENU }, { "font_size_message", WC_FONTSIZ_MESSAGE }, { "font_size_status", WC_FONTSIZ_STATUS }, { "font_size_text", WC_FONTSIZ_TEXT }, { "font_status", WC_FONT_STATUS }, { "font_text", WC_FONT_TEXT }, { "map_mode", WC_MAP_MODE }, { "scroll_amount", WC_SCROLL_AMOUNT }, { "scroll_margin", WC_SCROLL_MARGIN }, { "splash_screen", WC_SPLASH_SCREEN }, { "vary_msgcount", WC_VARY_MSGCOUNT }, { "windowcolors", WC_WINDOWCOLORS }, { "mouse_support", WC_MOUSE_SUPPORT }, { (char *) 0, 0L } }; struct wc_Opt wc2_options[] = { { "fullscreen", WC2_FULLSCREEN }, { "softkeyboard", WC2_SOFTKEYBOARD }, { "wraptext", WC2_WRAPTEXT }, { "use_darkgray", WC2_DARKGRAY }, #ifdef STATUS_VIA_WINDOWPORT { "hilite_status", WC2_HILITE_STATUS }, #endif { (char *) 0, 0L } }; /* * If a port wants to change or ensure that the SET_IN_SYS, * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is * correct (for controlling its display in the option menu) call * set_option_mod_status() * with the appropriate second argument. */ void set_option_mod_status(optnam, status) const char *optnam; int status; { int k; if (SET__IS_VALUE_VALID(status)) { impossible("set_option_mod_status: status out of range %d.", status); return; } for (k = 0; boolopt[k].name; k++) { if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) { boolopt[k].optflags = status; return; } } for (k = 0; compopt[k].name; k++) { if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) { compopt[k].optflags = status; return; } } } /* * You can set several wc_options in one call to * set_wc_option_mod_status() by setting * the appropriate bits for each option that you * are setting in the optmask argument * prior to calling. * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, * SET_IN_GAME); */ void set_wc_option_mod_status(optmask, status) unsigned long optmask; int status; { int k = 0; if (SET__IS_VALUE_VALID(status)) { impossible("set_wc_option_mod_status: status out of range %d.", status); return; } while (wc_options[k].wc_name) { if (optmask & wc_options[k].wc_bit) { set_option_mod_status(wc_options[k].wc_name, status); } k++; } } STATIC_OVL boolean is_wc_option(optnam) const char *optnam; { int k = 0; while (wc_options[k].wc_name) { if (strcmp(wc_options[k].wc_name, optnam) == 0) return TRUE; k++; } return FALSE; } STATIC_OVL boolean wc_supported(optnam) const char *optnam; { int k = 0; while (wc_options[k].wc_name) { if (!strcmp(wc_options[k].wc_name, optnam) && (windowprocs.wincap & wc_options[k].wc_bit)) return TRUE; k++; } return FALSE; } /* * You can set several wc2_options in one call to * set_wc2_option_mod_status() by setting * the appropriate bits for each option that you * are setting in the optmask argument * prior to calling. * example: * set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, * SET_IN_FILE); */ void set_wc2_option_mod_status(optmask, status) unsigned long optmask; int status; { int k = 0; if (SET__IS_VALUE_VALID(status)) { impossible("set_wc2_option_mod_status: status out of range %d.", status); return; } while (wc2_options[k].wc_name) { if (optmask & wc2_options[k].wc_bit) { set_option_mod_status(wc2_options[k].wc_name, status); } k++; } } STATIC_OVL boolean is_wc2_option(optnam) const char *optnam; { int k = 0; while (wc2_options[k].wc_name) { if (strcmp(wc2_options[k].wc_name, optnam) == 0) return TRUE; k++; } return FALSE; } STATIC_OVL boolean wc2_supported(optnam) const char *optnam; { int k = 0; while (wc2_options[k].wc_name) { if (!strcmp(wc2_options[k].wc_name, optnam) && (windowprocs.wincap2 & wc2_options[k].wc_bit)) return TRUE; k++; } return FALSE; } STATIC_OVL void wc_set_font_name(opttype, fontname) int opttype; char *fontname; { char **fn = (char **) 0; if (!fontname) return; switch (opttype) { case MAP_OPTION: fn = &iflags.wc_font_map; break; case MESSAGE_OPTION: fn = &iflags.wc_font_message; break; case TEXT_OPTION: fn = &iflags.wc_font_text; break; case MENU_OPTION: fn = &iflags.wc_font_menu; break; case STATUS_OPTION: fn = &iflags.wc_font_status; break; default: return; } if (fn) { if (*fn) free((genericptr_t) *fn); *fn = dupstr(fontname); } return; } STATIC_OVL int wc_set_window_colors(op) char *op; { /* syntax: * menu white/black message green/yellow status white/blue text * white/black */ int j; char buf[BUFSZ]; char *wn, *tfg, *tbg, *newop; static const char *wnames[] = { "menu", "message", "status", "text" }; static const char *shortnames[] = { "mnu", "msg", "sts", "txt" }; static char **fgp[] = { &iflags.wc_foregrnd_menu, &iflags.wc_foregrnd_message, &iflags.wc_foregrnd_status, &iflags.wc_foregrnd_text }; static char **bgp[] = { &iflags.wc_backgrnd_menu, &iflags.wc_backgrnd_message, &iflags.wc_backgrnd_status, &iflags.wc_backgrnd_text }; Strcpy(buf, op); newop = mungspaces(buf); while (newop && *newop) { wn = tfg = tbg = (char *) 0; /* until first non-space in case there's leading spaces - before * colorname*/ if (*newop == ' ') newop++; if (*newop) wn = newop; else return 0; /* until first space - colorname*/ while (*newop && *newop != ' ') newop++; if (*newop) *newop = '\0'; else return 0; newop++; /* until first non-space - before foreground*/ if (*newop == ' ') newop++; if (*newop) tfg = newop; else return 0; /* until slash - foreground */ while (*newop && *newop != '/') newop++; if (*newop) *newop = '\0'; else return 0; newop++; /* until first non-space (in case there's leading space after slash) - * before background */ if (*newop == ' ') newop++; if (*newop) tbg = newop; else return 0; /* until first space - background */ while (*newop && *newop != ' ') newop++; if (*newop) *newop++ = '\0'; for (j = 0; j < 4; ++j) { if (!strcmpi(wn, wnames[j]) || !strcmpi(wn, shortnames[j])) { if (tfg && !strstri(tfg, " ")) { if (*fgp[j]) free((genericptr_t) *fgp[j]); *fgp[j] = dupstr(tfg); } if (tbg && !strstri(tbg, " ")) { if (*bgp[j]) free((genericptr_t) *bgp[j]); *bgp[j] = dupstr(tbg); } break; } } } return 1; } /* set up for wizard mode if player or save file has requested to it; called from port-specific startup code to handle `nethack -D' or OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if restoring a game which was saved in wizard mode */ void set_playmode() { if (wizard) { if (authorize_wizard_mode()) Strcpy(plname, "wizard"); else wizard = FALSE; /* not allowed or not available */ /* force explore mode if we didn't make it into wizard mode */ discover = !wizard; iflags.deferred_X = FALSE; } /* don't need to do anything special for explore mode or normal play */ } #endif /* OPTION_LISTS_ONLY */ /*options.c*/ nethack-3.6.0/src/pager.c0000664000076400007660000013120512625515645014203 0ustar paxedpaxed/* NetHack 3.6 pager.c $NHDT-Date: 1448482543 2015/11/25 20:15:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.86 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file contains the command routines dowhatis() and dohelp() and */ /* a few other help related facilities */ #include "hack.h" #include "dlb.h" STATIC_DCL boolean FDECL(is_swallow_sym, (int)); STATIC_DCL int FDECL(append_str, (char *, const char *)); STATIC_DCL void FDECL(look_at_object, (char *, int, int, int)); STATIC_DCL void FDECL(look_at_monster, (char *, char *, struct monst *, int, int)); STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *)); STATIC_DCL void FDECL(checkfile, (char *, struct permonst *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P)); STATIC_DCL boolean FDECL(help_menu, (int *)); STATIC_DCL void NDECL(docontact); #ifdef PORT_HELP extern void NDECL(port_help); #endif /* Returns "true" for characters that could represent a monster's stomach. */ STATIC_OVL boolean is_swallow_sym(c) int c; { int i; for (i = S_sw_tl; i <= S_sw_br; i++) if ((int) showsyms[i] == c) return TRUE; return FALSE; } /* * Append new_str to the end of buf if new_str doesn't already exist as * a substring of buf. Return 1 if the string was appended, 0 otherwise. * It is expected that buf is of size BUFSZ. */ STATIC_OVL int append_str(buf, new_str) char *buf; const char *new_str; { int space_left; /* space remaining in buf */ if (strstri(buf, new_str)) return 0; space_left = BUFSZ - strlen(buf) - 1; (void) strncat(buf, " or ", space_left); (void) strncat(buf, new_str, space_left - 4); return 1; } /* shared by monster probing (via query_objlist!) as well as lookat() */ char * self_lookat(outbuf) char *outbuf; { char race[QBUFSZ]; /* include race with role unless polymorphed */ race[0] = '\0'; if (!Upolyd) Sprintf(race, "%s ", urace.adj); Sprintf(outbuf, "%s%s%s called %s", /* being blinded may hide invisibility from self */ (Invis && (senseself() || !Blind)) ? "invisible " : "", race, mons[u.umonnum].mname, plname); if (u.usteed) Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed)); return outbuf; } /* extracted from lookat(); also used by namefloorobj() */ boolean object_from_map(glyph, x, y, obj_p) int glyph, x, y; struct obj **obj_p; { boolean fakeobj = FALSE; struct monst *mtmp; struct obj *otmp = vobj_at(x, y); int glyphotyp = glyph_to_obj(glyph); *obj_p = (struct obj *) 0; /* there might be a mimic here posing as an object */ mtmp = m_at(x, y); if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp)) otmp = 0; else mtmp = 0; if (!otmp || otmp->otyp != glyphotyp) { /* this used to exclude STRANGE_OBJECT; now caller deals with it */ otmp = mksobj(glyphotyp, FALSE, FALSE); if (!otmp) return FALSE; fakeobj = TRUE; if (otmp->oclass == COIN_CLASS) otmp->quan = 2L; /* to force pluralization */ else if (otmp->otyp == SLIME_MOLD) otmp->spe = context.current_fruit; /* give it a type */ if (mtmp && has_mcorpsenm(mtmp)) /* mimic as corpse/statue */ otmp->corpsenm = MCORPSENM(mtmp); } /* if located at adjacent spot, mark it as having been seen up close */ if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination) otmp->dknown = 1; *obj_p = otmp; return fakeobj; /* when True, caller needs to dealloc *obj_p */ } STATIC_OVL void look_at_object(buf, x, y, glyph) char *buf; /* output buffer */ int x, y, glyph; { struct obj *otmp = 0; boolean fakeobj = object_from_map(glyph, x, y, &otmp); if (otmp) { Strcpy(buf, (otmp->otyp != STRANGE_OBJECT) ? distant_name(otmp, xname) : obj_descr[STRANGE_OBJECT].oc_name); if (fakeobj) dealloc_obj(otmp), otmp = 0; } else Strcpy(buf, something); /* sanity precaution */ if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) Strcat(buf, " embedded in stone"); else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR) Strcat(buf, " embedded in a wall"); else if (closed_door(x, y)) Strcat(buf, " embedded in a door"); else if (is_pool(x, y)) Strcat(buf, " in water"); else if (is_lava(x, y)) Strcat(buf, " in molten lava"); /* [can this ever happen?] */ return; } STATIC_OVL void look_at_monster(buf, monbuf, mtmp, x, y) char *buf, *monbuf; /* buf: output, monbuf: optional output */ struct monst *mtmp; int x, y; { char *name, monnambuf[BUFSZ]; boolean accurate = !Hallucination; if (mtmp->data == &mons[PM_COYOTE] && accurate) name = coyotename(mtmp, monnambuf); else name = distant_monnam(mtmp, ARTICLE_NONE, monnambuf); Sprintf(buf, "%s%s%s", (mtmp->mx != x || mtmp->my != y) ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ") : "", (mtmp->mtame && accurate) ? "tame " : (mtmp->mpeaceful && accurate) ? "peaceful " : "", name); if (u.ustuck == mtmp) Strcat(buf, (Upolyd && sticks(youmonst.data)) ? ", being held" : ", holding you"); if (mtmp->mleashed) Strcat(buf, ", leashed to you"); if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) { struct trap *t = t_at(mtmp->mx, mtmp->my); int tt = t ? t->ttyp : NO_TRAP; /* newsym lets you know of the trap, so mention it here */ if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB) Sprintf(eos(buf), ", trapped in %s", an(defsyms[trap_to_defsym(tt)].explanation)); } if (monbuf) { unsigned how_seen = howmonseen(mtmp); monbuf[0] = '\0'; if (how_seen != 0 && how_seen != MONSEEN_NORMAL) { if (how_seen & MONSEEN_NORMAL) { Strcat(monbuf, "normal vision"); how_seen &= ~MONSEEN_NORMAL; /* how_seen can't be 0 yet... */ if (how_seen) Strcat(monbuf, ", "); } if (how_seen & MONSEEN_SEEINVIS) { Strcat(monbuf, "see invisible"); how_seen &= ~MONSEEN_SEEINVIS; if (how_seen) Strcat(monbuf, ", "); } if (how_seen & MONSEEN_INFRAVIS) { Strcat(monbuf, "infravision"); how_seen &= ~MONSEEN_INFRAVIS; if (how_seen) Strcat(monbuf, ", "); } if (how_seen & MONSEEN_TELEPAT) { Strcat(monbuf, "telepathy"); how_seen &= ~MONSEEN_TELEPAT; if (how_seen) Strcat(monbuf, ", "); } if (how_seen & MONSEEN_XRAYVIS) { /* Eyes of the Overworld */ Strcat(monbuf, "astral vision"); how_seen &= ~MONSEEN_XRAYVIS; if (how_seen) Strcat(monbuf, ", "); } if (how_seen & MONSEEN_DETECT) { Strcat(monbuf, "monster detection"); how_seen &= ~MONSEEN_DETECT; if (how_seen) Strcat(monbuf, ", "); } if (how_seen & MONSEEN_WARNMON) { if (Hallucination) Strcat(monbuf, "paranoid delusion"); else Sprintf(eos(monbuf), "warned of %s", makeplural(mtmp->data->mname)); how_seen &= ~MONSEEN_WARNMON; if (how_seen) Strcat(monbuf, ", "); } /* should have used up all the how_seen bits by now */ if (how_seen) { impossible("lookat: unknown method of seeing monster"); Sprintf(eos(monbuf), "(%u)", how_seen); } } /* seen by something other than normal vision */ } /* monbuf is non-null */ } /* * Return the name of the glyph found at (x,y). * If not hallucinating and the glyph is a monster, also monster data. */ STATIC_OVL struct permonst * lookat(x, y, buf, monbuf) int x, y; char *buf, *monbuf; { struct monst *mtmp = (struct monst *) 0; struct permonst *pm = (struct permonst *) 0; int glyph; buf[0] = monbuf[0] = '\0'; glyph = glyph_at(x, y); if (u.ux == x && u.uy == y && canspotself()) { /* fill in buf[] */ (void) self_lookat(buf); /* file lookup can't distinguish between "gnomish wizard" monster and correspondingly named player character, always picking the former; force it to find the general "wizard" entry instead */ if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd) pm = &mons[PM_WIZARD]; /* When you see yourself normally, no explanation is appended (even if you could also see yourself via other means). Sensing self while blind or swallowed is treated as if it were by normal vision (cf canseeself()). */ if ((Invisible || u.uundetected) && !Blind && !u.uswallow) { unsigned how = 0; if (Infravision) how |= 1; if (Unblind_telepat) how |= 2; if (Detect_monsters) how |= 4; if (how) Sprintf( eos(buf), " [seen: %s%s%s%s%s]", (how & 1) ? "infravision" : "", /* add comma if telep and infrav */ ((how & 3) > 2) ? ", " : "", (how & 2) ? "telepathy" : "", /* add comma if detect and (infrav or telep or both) */ ((how & 7) > 4) ? ", " : "", (how & 4) ? "monster detection" : ""); } } else if (u.uswallow) { /* all locations when swallowed other than the hero are the monster */ Sprintf(buf, "interior of %s", Blind ? "a monster" : a_monnam(u.ustuck)); pm = u.ustuck->data; } else if (glyph_is_monster(glyph)) { bhitpos.x = x; bhitpos.y = y; if ((mtmp = m_at(x, y)) != 0) { look_at_monster(buf, monbuf, mtmp, x, y); pm = mtmp->data; } } else if (glyph_is_object(glyph)) { look_at_object(buf, x, y, glyph); /* fill in buf[] */ } else if (glyph_is_trap(glyph)) { int tnum = what_trap(glyph_to_trap(glyph)); Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation); } else if (!glyph_is_cmap(glyph)) { Strcpy(buf, "unexplored area"); } else switch (glyph_to_cmap(glyph)) { case S_altar: Sprintf(buf, "%s %saltar", /* like endgame high priests, endgame high altars are only recognizable when immediately adjacent */ (Is_astralevel(&u.uz) && distu(x, y) > 2) ? "aligned" : align_str( Amask2align(levl[x][y].altarmask & ~AM_SHRINE)), ((levl[x][y].altarmask & AM_SHRINE) && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) ? "high " : ""); break; case S_ndoor: if (is_drawbridge_wall(x, y) >= 0) Strcpy(buf, "open drawbridge portcullis"); else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN) Strcpy(buf, "broken door"); else Strcpy(buf, "doorway"); break; case S_cloud: Strcpy(buf, Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud"); break; case S_stone: if (!levl[x][y].seenv) { Strcpy(buf, "unexplored"); break; } else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) { Strcpy(buf, "stone"); break; } /*else FALLTHRU*/ default: Strcpy(buf, defsyms[glyph_to_cmap(glyph)].explanation); break; } return (pm && !Hallucination) ? pm : (struct permonst *) 0; } /* * Look in the "data" file for more info. Called if the user typed in the * whole name (user_typed_name == TRUE), or we've found a possible match * with a character/glyph and flags.help is TRUE. * * NOTE: when (user_typed_name == FALSE), inp is considered read-only and * must not be changed directly, e.g. via lcase(). We want to force * lcase() for data.base lookup so that we can have a clean key. * Therefore, we create a copy of inp _just_ for data.base lookup. */ STATIC_OVL void checkfile(inp, pm, user_typed_name, without_asking) char *inp; struct permonst *pm; boolean user_typed_name, without_asking; { dlb *fp; char buf[BUFSZ], newstr[BUFSZ]; char *ep, *dbase_str; unsigned long txt_offset = 0L; int chk_skip; boolean found_in_file = FALSE, skipping_entry = FALSE; winid datawin = WIN_ERR; fp = dlb_fopen(DATAFILE, "r"); if (!fp) { pline("Cannot open data file!"); return; } /* * If someone passed us garbage, prevent fault. */ if (!inp || (inp && strlen(inp) > (BUFSZ - 1))) { pline("bad do_look buffer passed!"); return; } /* To prevent the need for entries in data.base like *ngel to account * for Angel and angel, make the lookup string the same for both * user_typed_name and picked name. */ if (pm != (struct permonst *) 0 && !user_typed_name) dbase_str = strcpy(newstr, pm->mname); else dbase_str = strcpy(newstr, inp); (void) lcase(dbase_str); if (!strncmp(dbase_str, "interior of ", 12)) dbase_str += 12; if (!strncmp(dbase_str, "a ", 2)) dbase_str += 2; else if (!strncmp(dbase_str, "an ", 3)) dbase_str += 3; else if (!strncmp(dbase_str, "the ", 4)) dbase_str += 4; if (!strncmp(dbase_str, "tame ", 5)) dbase_str += 5; else if (!strncmp(dbase_str, "peaceful ", 9)) dbase_str += 9; if (!strncmp(dbase_str, "invisible ", 10)) dbase_str += 10; if (!strncmp(dbase_str, "saddled ", 8)) dbase_str += 8; if (!strncmp(dbase_str, "statue of ", 10)) dbase_str[6] = '\0'; else if (!strncmp(dbase_str, "figurine of ", 12)) dbase_str[8] = '\0'; /* Make sure the name is non-empty. */ if (*dbase_str) { /* adjust the input to remove "named " and convert to lower case */ char *alt = 0; /* alternate description */ if ((ep = strstri(dbase_str, " named ")) != 0) alt = ep + 7; else ep = strstri(dbase_str, " called "); if (!ep) ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) *ep = '\0'; /* * If the object is named, then the name is the alternate description; * otherwise, the result of makesingular() applied to the name is. * This * isn't strictly optimal, but named objects of interest to the user * will usually be found under their name, rather than under their * object type, so looking for a singular form is pointless. */ if (!alt) alt = makesingular(dbase_str); /* skip first record; read second */ txt_offset = 0L; if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) { impossible("can't read 'data' file"); (void) dlb_fclose(fp); return; } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset == 0L) goto bad_data_file; /* look for the appropriate entry */ while (dlb_fgets(buf, BUFSZ, fp)) { if (*buf == '.') break; /* we passed last entry without success */ if (digit(*buf)) { /* a number indicates the end of current entry */ skipping_entry = FALSE; } else if (!skipping_entry) { if (!(ep = index(buf, '\n'))) goto bad_data_file; *ep = 0; /* if we match a key that begins with "~", skip this entry */ chk_skip = (*buf == '~') ? 1 : 0; if (pmatch(&buf[chk_skip], dbase_str) || (alt && pmatch(&buf[chk_skip], alt))) { if (chk_skip) { skipping_entry = TRUE; continue; } else { found_in_file = TRUE; break; } } } } } if (found_in_file) { long entry_offset; int entry_count; int i; /* skip over other possible matches for the info */ do { if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; } while (!digit(*buf)); if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) { bad_data_file: impossible("'data' file in wrong format or corrupted"); /* window will exist if we came here from below via 'goto' */ if (datawin != WIN_ERR) destroy_nhwindow(datawin); (void) dlb_fclose(fp); return; } if (user_typed_name || without_asking || yn("More info?") == 'y') { if (dlb_fseek(fp, (long) txt_offset + entry_offset, SEEK_SET) < 0) { pline("? Seek error on 'data' file!"); (void) dlb_fclose(fp); return; } datawin = create_nhwindow(NHW_MENU); for (i = 0; i < entry_count; i++) { if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; if ((ep = index(buf, '\n')) != 0) *ep = 0; if (index(buf + 1, '\t') != 0) (void) tabexpand(buf + 1); putstr(datawin, 0, buf + 1); } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); } } else if (user_typed_name) pline("I don't have any information on those things."); (void) dlb_fclose(fp); } int do_screen_description(cc, looked, sym, out_str, firstmatch) coord cc; boolean looked; int sym; char *out_str; const char **firstmatch; { boolean need_to_look = FALSE; int glyph = NO_GLYPH; static char look_buf[BUFSZ]; char prefix[BUFSZ]; int found = 0; /* count of matching syms found */ int i, alt_i; int skipped_venom = 0; boolean hit_trap; const char *x_str; static const char *mon_interior = "the interior of a monster"; if (looked) { int oc; unsigned os; glyph = glyph_at(cc.x, cc.y); /* Convert glyph at selected position to a symbol for use below. */ (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y); Sprintf(prefix, "%s ", encglyph(glyph)); } else Sprintf(prefix, "%c ", sym); /* * Check all the possibilities, saving all explanations in a buffer. * When all have been checked then the string is printed. */ /* * Special case: if identifying from the screen, and we're swallowed, * and looking at something other than our own symbol, then just say * "the interior of a monster". */ if (u.uswallow && looked && (is_swallow_sym(sym) || (int) showsyms[S_stone] == sym)) { if (!found) { Sprintf(out_str, "%s%s", prefix, mon_interior); *firstmatch = mon_interior; } else { found += append_str(out_str, mon_interior); } need_to_look = TRUE; goto didlook; } /* Check for monsters */ for (i = 0; i < MAXMCLASSES; i++) { if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym) && def_monsyms[i].explain) { need_to_look = TRUE; if (!found) { Sprintf(out_str, "%s%s", prefix, an(def_monsyms[i].explain)); *firstmatch = def_monsyms[i].explain; found++; } else { found += append_str(out_str, an(def_monsyms[i].explain)); } } } /* handle '@' as a special case if it refers to you and you're playing a character which isn't normally displayed by that symbol; firstmatch is assumed to already be set for '@' */ if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M] && cc.x == u.ux && cc.y == u.uy) : (sym == def_monsyms[S_HUMAN].sym && !flags.showrace)) && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd) found += append_str(out_str, "you"); /* tack on "or you" */ /* Now check for objects */ for (i = 1; i < MAXOCLASSES; i++) { if (sym == (looked ? showsyms[i + SYM_OFF_O] : def_oc_syms[i].sym)) { need_to_look = TRUE; if (looked && i == VENOM_CLASS) { skipped_venom++; continue; } if (!found) { Sprintf(out_str, "%s%s", prefix, an(def_oc_syms[i].explain)); *firstmatch = def_oc_syms[i].explain; found++; } else { found += append_str(out_str, an(def_oc_syms[i].explain)); } } } if (sym == DEF_INVISIBLE) { if (!found) { Sprintf(out_str, "%s%s", prefix, an(invisexplain)); *firstmatch = invisexplain; found++; } else { found += append_str(out_str, an(invisexplain)); } } #define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap) #define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge) /* Now check for graphics symbols */ alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1); for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) { /* when sym is the default background character, we process i == 0 three times: unexplored, stone, dark part of a room */ if (alt_i < 2) { x_str = !alt_i++ ? "unexplored" : "stone"; i = 0; /* for second iteration, undo loop increment */ /* alt_i is now 1 or 2 */ } else { if (alt_i++ == 2) i = 0; /* undo loop increment */ x_str = defsyms[i].explanation; /* alt_i is now 3 or more and no longer of interest */ } if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) { /* avoid "an unexplored", "an stone", "an air", "a water", "a floor of a room", "a dark part of a room"; article==2 => "the", 1 => "an", 0 => (none) */ int article = strstri(x_str, " of a room") ? 2 : !(alt_i <= 2 || strcmp(x_str, "air") == 0 || strcmp(x_str, "water") == 0); if (!found) { if (is_cmap_trap(i)) { Sprintf(out_str, "%sa trap", prefix); hit_trap = TRUE; } else { Sprintf(out_str, "%s%s", prefix, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); } *firstmatch = x_str; found++; } else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) && !(found >= 3 && is_cmap_drawbridge(i)) /* don't mention vibrating square outside of Gehennom unless this happens to be one (hallucination?) */ && (i != S_vibrating_square || Inhell || (looked && glyph_is_trap(glyph) && glyph_to_trap(glyph) == VIBRATING_SQUARE))) { found += append_str(out_str, (article == 2) ? the(x_str) : (article == 1) ? an(x_str) : x_str); if (is_cmap_trap(i)) hit_trap = TRUE; } if (i == S_altar || is_cmap_trap(i)) need_to_look = TRUE; } } /* Now check for warning symbols */ for (i = 1; i < WARNCOUNT; i++) { x_str = def_warnsyms[i].explanation; if (sym == (looked ? warnsyms[i] : def_warnsyms[i].sym)) { if (!found) { Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation); *firstmatch = def_warnsyms[i].explanation; found++; } else { found += append_str(out_str, def_warnsyms[i].explanation); } /* Kludge: warning trumps boulders on the display. Reveal the boulder too or player can get confused */ if (looked && sobj_at(BOULDER, cc.x, cc.y)) Strcat(out_str, " co-located with a boulder"); break; /* out of for loop*/ } } /* if we ignored venom and list turned out to be short, put it back */ if (skipped_venom && found < 2) { x_str = def_oc_syms[VENOM_CLASS].explain; if (!found) { Sprintf(out_str, "%s%s", prefix, an(x_str)); *firstmatch = x_str; found++; } else { found += append_str(out_str, an(x_str)); } } /* handle optional boulder symbol as a special case */ if (iflags.bouldersym && sym == iflags.bouldersym) { if (!found) { *firstmatch = "boulder"; Sprintf(out_str, "%s%s", prefix, an(*firstmatch)); found++; } else { found += append_str(out_str, "boulder"); } } /* * If we are looking at the screen, follow multiple possibilities or * an ambiguous explanation by something more detailed. */ didlook: if (looked) { if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ]; (void) lookat(cc.x, cc.y, look_buf, monbuf); *firstmatch = look_buf; if (*(*firstmatch)) { Sprintf(temp_buf, " (%s)", *firstmatch); (void) strncat(out_str, temp_buf, BUFSZ - strlen(out_str) - 1); found = 1; /* we have something to look up */ } if (monbuf[0]) { Sprintf(temp_buf, " [seen: %s]", monbuf); (void) strncat(out_str, temp_buf, BUFSZ - strlen(out_str) - 1); } } } return found; } /* getpos() return values */ #define LOOK_TRADITIONAL 0 /* '.' -- ask about "more info?" */ #define LOOK_QUICK 1 /* ',' -- skip "more info?" */ #define LOOK_ONCE 2 /* ';' -- skip and stop looping */ #define LOOK_VERBOSE 3 /* ':' -- show more info w/o asking */ /* also used by getpos hack in do_name.c */ const char what_is_an_unknown_object[] = "an unknown object"; int do_look(mode, click_cc) int mode; coord *click_cc; { boolean quick = (mode == 1); /* use cursor; don't search for "more info" */ boolean clicklook = (mode == 2); /* right mouse-click method */ char out_str[BUFSZ]; const char *firstmatch = 0; struct permonst *pm = 0; int i = '\0', ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ coord cc; /* screen pos of unknown glyph */ boolean save_verbose; /* saved value of flags.verbose */ boolean from_screen; /* question from the screen */ if (!clicklook) { if (quick) { from_screen = TRUE; /* yes, we want to use the cursor */ i = 'y'; } if (i != 'y') { menu_item *pick_list = (menu_item *) 0; winid win; anything any; any = zeroany; win = create_nhwindow(NHW_MENU); start_menu(win); any.a_char = '/'; /* 'y' and 'n' to keep backwards compatibility with previous versions: "Specify unknown object by cursor?" */ add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 'y', ATR_NONE, "something on the map", MENU_UNSELECTED); any.a_char = 'i'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, "something you're carrying", MENU_UNSELECTED); any.a_char = '?'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE, "something else (by symbol or name)", MENU_UNSELECTED); if (!u.uswallow && !Hallucination) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); /* these options work sensibly for the swallowed case, but there's no reason for the player to use them then; objects work fine when hallucinating, but screen symbol/monster class letter doesn't match up with bogus monster type, so suppress when hallucinating */ any.a_char = 'm'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, "nearby monsters", MENU_UNSELECTED); any.a_char = 'M'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, "all monsters shown on map", MENU_UNSELECTED); any.a_char = 'o'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, "nearby objects", MENU_UNSELECTED); any.a_char = 'O'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 0, ATR_NONE, "all objects shown on map", MENU_UNSELECTED); } end_menu(win, "What do you want to look at:"); if (select_menu(win, PICK_ONE, &pick_list) > 0) { i = pick_list->item.a_char; free((genericptr_t) pick_list); } destroy_nhwindow(win); } switch (i) { default: case 'q': return 0; case 'y': case '/': from_screen = TRUE; sym = 0; cc.x = u.ux; cc.y = u.uy; break; case 'i': { char invlet; struct obj *invobj; invlet = display_inventory((const char *) 0, TRUE); if (!invlet || invlet == '\033') return 0; *out_str = '\0'; for (invobj = invent; invobj; invobj = invobj->nobj) if (invobj->invlet == invlet) { strcpy(out_str, singular(invobj, xname)); break; } if (*out_str) checkfile(out_str, pm, TRUE, TRUE); return 0; } case '?': from_screen = FALSE; getlin("Specify what? (type the word)", out_str); if (out_str[0] == '\0' || out_str[0] == '\033') return 0; if (out_str[1]) { /* user typed in a complete string */ checkfile(out_str, pm, TRUE, TRUE); return 0; } sym = out_str[0]; break; case 'm': look_all(TRUE, TRUE); /* list nearby monsters */ return 0; case 'M': look_all(FALSE, TRUE); /* list all monsters */ return 0; case 'o': look_all(TRUE, FALSE); /* list nearby objects */ return 0; case 'O': look_all(FALSE, FALSE); /* list all objects */ return 0; } } else { /* clicklook */ cc.x = click_cc->x; cc.y = click_cc->y; sym = 0; from_screen = FALSE; } /* Save the verbose flag, we change it later. */ save_verbose = flags.verbose; flags.verbose = flags.verbose && !quick; /* * The user typed one letter, or we're identifying from the screen. */ do { /* Reset some variables. */ pm = (struct permonst *) 0; found = 0; out_str[0] = '\0'; if (from_screen || clicklook) { if (from_screen) { if (flags.verbose) pline("Please move the cursor to %s.", what_is_an_unknown_object); else pline("Pick an object."); ans = getpos(&cc, quick, what_is_an_unknown_object); if (ans < 0 || cc.x < 0) { flags.verbose = save_verbose; return 0; /* done */ } flags.verbose = FALSE; /* only print long question once */ } } found = do_screen_description(cc, (from_screen || clicklook), sym, out_str, &firstmatch); /* Finally, print out our explanation. */ if (found) { /* Used putmixed() because there may be an encoded glyph present */ putmixed(WIN_MESSAGE, 0, out_str); /* check the data file for information about this thing */ if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick)) && !clicklook) { char temp_buf[BUFSZ]; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, (boolean) (ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook); flags.verbose = save_verbose; return 0; } STATIC_OVL void look_all(nearby, do_mons) boolean nearby; /* True => within BOLTLIM, False => entire map */ boolean do_mons; /* True => monsters, False => objects */ { winid win; int x, y, lo_x, lo_y, hi_x, hi_y, glyph, count = 0; char buf[BUFSZ], outbuf[BUFSZ], coordbuf[12], fmt[12]; /* "%02d,%02d" */ /* row,column orientation rather than cartesian x,y */ Sprintf(fmt, "%%%sd,%%%sd", (ROWNO <= 100) ? "02" : (ROWNO <= 1000) ? "03" : "", (COLNO <= 100) ? "02" : (COLNO <= 1000) ? "03" : ""); win = create_nhwindow(NHW_TEXT); lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0; lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1; hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1; hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1; for (y = lo_y; y <= hi_y; y++) { for (x = lo_x; x <= hi_x; x++) { buf[0] = '\0'; glyph = glyph_at(x, y); if (do_mons) { if (glyph_is_monster(glyph)) { struct monst *mtmp; bhitpos.x = x; /* [is this actually necessary?] */ bhitpos.y = y; if (x == u.ux && y == u.uy && canspotself()) { (void) self_lookat(buf); ++count; } else if ((mtmp = m_at(x, y)) != 0) { look_at_monster(buf, (char *) 0, mtmp, x, y); ++count; } } else if (glyph_is_invisible(glyph)) { /* remembered, unseen, creature */ Strcpy(buf, invisexplain); ++count; } else if (glyph_is_warning(glyph)) { int warnindx = glyph_to_warning(glyph); Strcpy(buf, def_warnsyms[warnindx].explanation); ++count; } } else { /* !do_mons */ if (glyph_is_object(glyph)) { look_at_object(buf, x, y, glyph); ++count; } } if (*buf) { if (count == 1) { char which[12]; Strcpy(which, do_mons ? "monsters" : "objects"); if (nearby) { Sprintf(coordbuf, fmt, u.uy, u.ux); Sprintf(outbuf, "%s currently shown near %s:", upstart(which), coordbuf); } else Sprintf(outbuf, "All %s currently shown on the map:", which); putstr(win, 0, outbuf); putstr(win, 0, ""); } Sprintf(coordbuf, fmt, y, x); /* prefix: "C row,column " */ Sprintf(outbuf, "%s %s ", encglyph(glyph), coordbuf); /* guard against potential overflow */ buf[sizeof buf - 1 - strlen(outbuf)] = '\0'; Strcat(outbuf, buf); putmixed(win, 0, outbuf); } } } if (count) display_nhwindow(win, TRUE); else pline("No %s are currently shown %s.", do_mons ? "monsters" : "objects", nearby ? "nearby" : "on the map"); destroy_nhwindow(win); } /* the '/' command */ int dowhatis() { return do_look(0, (coord *) 0); } /* the ';' command */ int doquickwhatis() { return do_look(1, (coord *) 0); } /* the '^' command */ int doidtrap() { register struct trap *trap; int x, y, tt; if (!getdir("^")) return 0; x = u.ux + u.dx; y = u.uy + u.dy; for (trap = ftrap; trap; trap = trap->ntrap) if (trap->tx == x && trap->ty == y) { if (!trap->tseen) break; tt = trap->ttyp; if (u.dz) { if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE) : tt == ROCKTRAP) break; } tt = what_trap(tt); pline("That is %s%s%s.", an(defsyms[trap_to_defsym(tt)].explanation), !trap->madeby_u ? "" : (tt == WEB) ? " woven" /* trap doors & spiked pits can't be made by player, and should be considered at least as much "set" as "dug" anyway */ : (tt == HOLE || tt == PIT) ? " dug" : " set", !trap->madeby_u ? "" : " by you"); return 0; } pline("I can't see a trap there."); return 0; } char * dowhatdoes_core(q, cbuf) char q; char *cbuf; { dlb *fp; char bufr[BUFSZ]; register char *buf = &bufr[6], *ep, ctrl, meta; fp = dlb_fopen(CMDHELPFILE, "r"); if (!fp) { pline("Cannot open data file!"); return 0; } ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); meta = ((0x80 & q) ? (0x7f & q) : 0); while (dlb_fgets(buf, BUFSZ - 6, fp)) { if ((ctrl && *buf == '^' && *(buf + 1) == ctrl) || (meta && *buf == 'M' && *(buf + 1) == '-' && *(buf + 2) == meta) || *buf == q) { ep = index(buf, '\n'); if (ep) *ep = 0; if (ctrl && buf[2] == '\t') { buf = bufr + 1; (void) strncpy(buf, "^? ", 8); buf[1] = ctrl; } else if (meta && buf[3] == '\t') { buf = bufr + 2; (void) strncpy(buf, "M-? ", 8); buf[2] = meta; } else if (buf[1] == '\t') { buf = bufr; buf[0] = q; (void) strncpy(buf + 1, " ", 7); } (void) dlb_fclose(fp); Strcpy(cbuf, buf); return cbuf; } } (void) dlb_fclose(fp); return (char *) 0; } int dowhatdoes() { char bufr[BUFSZ]; char q, *reslt; #if defined(UNIX) || defined(VMS) introff(); #endif q = yn_function("What command?", (char *) 0, '\0'); #if defined(UNIX) || defined(VMS) intron(); #endif reslt = dowhatdoes_core(q, bufr); if (reslt) pline1(reslt); else pline("I've never heard of such commands."); return 0; } void docontact() { winid cwin = create_nhwindow(NHW_TEXT); char buf[BUFSZ]; if (sysopt.support) { /*XXX overflow possibilities*/ Sprintf(buf, "To contact local support, %s", sysopt.support); putstr(cwin, 0, buf); putstr(cwin, 0, ""); } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */ Sprintf(buf, "To contact local support, contact %s.", sysopt.fmtd_wizard_list); putstr(cwin, 0, buf); putstr(cwin, 0, ""); } putstr(cwin, 0, "To contact the NetHack development team directly,"); /*XXX overflow possibilities*/ Sprintf(buf, "see the 'Contact' form on our website or email <%s>.", DEVTEAM_EMAIL); putstr(cwin, 0, buf); putstr(cwin, 0, ""); putstr(cwin, 0, "For more information on NetHack, or to report a bug,"); Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL); putstr(cwin, 0, buf); display_nhwindow(cwin, FALSE); destroy_nhwindow(cwin); } /* data for help_menu() */ static const char *help_menu_items[] = { /* 0*/ "About NetHack (version information).", /* 1*/ "Long description of the game and commands.", /* 2*/ "List of game commands.", /* 3*/ "Concise history of NetHack.", /* 4*/ "Info on a character in the game display.", /* 5*/ "Info on what a given key does.", /* 6*/ "List of game options.", /* 7*/ "Longer explanation of game options.", /* 8*/ "List of extended commands.", /* 9*/ "The NetHack license.", /* 10*/ "Support information.", #ifdef PORT_HELP "%s-specific help and commands.", #define PORT_HELP_ID 100 #define WIZHLP_SLOT 12 #else #define WIZHLP_SLOT 11 #endif "List of wizard-mode commands.", "", (char *) 0 }; STATIC_OVL boolean help_menu(sel) int *sel; { winid tmpwin = create_nhwindow(NHW_MENU); #ifdef PORT_HELP char helpbuf[QBUFSZ]; #endif int i, n; menu_item *selected; anything any; any = zeroany; /* zero all bits */ start_menu(tmpwin); if (!wizard) help_menu_items[WIZHLP_SLOT] = "", help_menu_items[WIZHLP_SLOT + 1] = (char *) 0; for (i = 0; help_menu_items[i]; i++) #ifdef PORT_HELP /* port-specific line has a %s in it for the PORT_ID */ if (help_menu_items[i][0] == '%') { Sprintf(helpbuf, help_menu_items[i], PORT_ID); any.a_int = PORT_HELP_ID + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, helpbuf, MENU_UNSELECTED); } else #endif { any.a_int = (*help_menu_items[i]) ? i + 1 : 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, help_menu_items[i], MENU_UNSELECTED); } end_menu(tmpwin, "Select one item:"); n = select_menu(tmpwin, PICK_ONE, &selected); destroy_nhwindow(tmpwin); if (n > 0) { *sel = selected[0].item.a_int - 1; free((genericptr_t) selected); return TRUE; } return FALSE; } /* the '?' command */ int dohelp() { int sel = 0; if (help_menu(&sel)) { switch (sel) { case 0: (void) doextversion(); break; case 1: display_file(HELP, TRUE); break; case 2: display_file(SHELP, TRUE); break; case 3: (void) dohistory(); break; case 4: (void) dowhatis(); break; case 5: (void) dowhatdoes(); break; case 6: option_help(); break; case 7: display_file(OPTIONFILE, TRUE); break; case 8: (void) doextlist(); break; case 9: display_file(LICENSE, TRUE); break; case 10: (void) docontact(); break; #ifdef PORT_HELP case PORT_HELP_ID: port_help(); break; #endif default: /* handle slot 11 or 12 */ display_file(DEBUGHELP, TRUE); break; } } return 0; } /* the 'V' command; also a choice for '?' */ int dohistory() { display_file(HISTORY, TRUE); return 0; } /*pager.c*/ nethack-3.6.0/src/pickup.c0000664000076400007660000031027012625025050014363 0ustar paxedpaxed/* NetHack 3.6 pickup.c $NHDT-Date: 1445556881 2015/10/22 23:34:41 $ $NHDT-Branch: master $:$NHDT-Revision: 1.162 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * Contains code for picking objects up, and container use. */ #include "hack.h" #define CONTAINED_SYM '>' /* from invent.c */ STATIC_DCL void FDECL(simple_look, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(query_classes, (char *, boolean *, boolean *, const char *, struct obj *, BOOLEAN_P, int *)); STATIC_DCL boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(check_here, (BOOLEAN_P)); STATIC_DCL boolean FDECL(n_or_more, (struct obj *)); STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *)); #if 0 /* not used */ STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *)); #endif STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **)); STATIC_DCL int FDECL(count_categories, (struct obj *, int)); STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long, BOOLEAN_P, int *, int *)); STATIC_DCL int FDECL(lift_object, (struct obj *, struct obj *, long *, BOOLEAN_P)); STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *, int)); STATIC_PTR int FDECL(in_container, (struct obj *)); STATIC_PTR int FDECL(out_container, (struct obj *)); STATIC_DCL long FDECL(mbag_item_gone, (int, struct obj *)); STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *)); STATIC_DCL void NDECL(explain_container_prompt); STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P)); STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P)); STATIC_DCL char FDECL(in_or_out_menu, (const char *, struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); STATIC_DCL boolean FDECL(able_to_loot, (int, int, BOOLEAN_P)); STATIC_DCL boolean NDECL(reverse_loot); STATIC_DCL boolean FDECL(mon_beside, (int, int)); STATIC_DCL int FDECL(do_loot_cont, (struct obj **)); STATIC_DCL void FDECL(tipcontainer, (struct obj *)); /* define for query_objlist() and autopickup() */ #define FOLLOW(curr, flags) \ (((flags) &BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj) /* * How much the weight of the given container will change when the given * object is removed from it. This calculation must match the one used * by weight() in mkobj.c. */ #define DELTA_CWT(cont, obj) \ ((cont)->cursed ? (obj)->owt * 2 : (cont)->blessed \ ? ((obj)->owt + 3) / 4 \ : ((obj)->owt + 1) / 2) #define GOLD_WT(n) (((n) + 50L) / 100L) /* if you can figure this out, give yourself a hearty pat on the back... */ #define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L) /* A variable set in use_container(), to be used by the callback routines */ /* in_container() and out_container() from askchain() and use_container(). */ /* Also used by menu_loot() and container_gone(). */ static NEARDATA struct obj *current_container; #define Icebox (current_container->otyp == ICE_BOX) static const char moderateloadmsg[] = "You have a little trouble lifting"; static const char nearloadmsg[] = "You have much trouble lifting"; static const char overloadmsg[] = "You have extreme difficulty lifting"; /* BUG: this lets you look at cockatrice corpses while blind without touching them */ /* much simpler version of the look-here code; used by query_classes() */ STATIC_OVL void simple_look(otmp, here) struct obj *otmp; /* list of objects */ boolean here; /* flag for type of obj list linkage */ { /* Neither of the first two cases is expected to happen, since * we're only called after multiple classes of objects have been * detected, hence multiple objects must be present. */ if (!otmp) { impossible("simple_look(null)"); } else if (!(here ? otmp->nexthere : otmp->nobj)) { pline1(doname(otmp)); } else { winid tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, ""); do { putstr(tmpwin, 0, doname(otmp)); otmp = here ? otmp->nexthere : otmp->nobj; } while (otmp); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } } int collect_obj_classes(ilets, otmp, here, filter, itemcount) char ilets[]; register struct obj *otmp; boolean here; boolean FDECL((*filter), (OBJ_P)); int *itemcount; { register int iletct = 0; register char c; *itemcount = 0; ilets[iletct] = '\0'; /* terminate ilets so that index() will work */ while (otmp) { c = def_oc_syms[(int) otmp->oclass].sym; if (!index(ilets, c) && (!filter || (*filter)(otmp))) ilets[iletct++] = c, ilets[iletct] = '\0'; *itemcount += 1; otmp = here ? otmp->nexthere : otmp->nobj; } return iletct; } /* * Suppose some '?' and '!' objects are present, but '/' objects aren't: * "a" picks all items without further prompting; * "A" steps through all items, asking one by one; * "?" steps through '?' items, asking, and ignores '!' ones; * "/" becomes 'A', since no '/' present; * "?a" or "a?" picks all '?' without further prompting; * "/a" or "a/" becomes 'A' since there aren't any '/' * (bug fix: 3.1.0 thru 3.1.3 treated it as "a"); * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/' * (ie, treated as if it had just been "?a"). */ STATIC_OVL boolean query_classes(oclasses, one_at_a_time, everything, action, objs, here, menu_on_demand) char oclasses[]; boolean *one_at_a_time, *everything; const char *action; struct obj *objs; boolean here; int *menu_on_demand; { char ilets[30], inbuf[BUFSZ]; /* FIXME: hardcoded ilets[] length */ int iletct, oclassct; boolean not_everything; char qbuf[QBUFSZ]; boolean m_seen; int itemcount; oclasses[oclassct = 0] = '\0'; *one_at_a_time = *everything = m_seen = FALSE; iletct = collect_obj_classes(ilets, objs, here, (boolean FDECL((*), (OBJ_P))) 0, &itemcount); if (iletct == 0) { return FALSE; } else if (iletct == 1) { oclasses[0] = def_char_to_objclass(ilets[0]); oclasses[1] = '\0'; if (itemcount && menu_on_demand) { ilets[iletct++] = 'm'; *menu_on_demand = 0; ilets[iletct] = '\0'; } } else { /* more than one choice available */ const char *where = 0; register char sym, oc_of_sym, *p; /* additional choices */ ilets[iletct++] = ' '; ilets[iletct++] = 'a'; ilets[iletct++] = 'A'; ilets[iletct++] = (objs == invent ? 'i' : ':'); if (menu_on_demand) { ilets[iletct++] = 'm'; *menu_on_demand = 0; } ilets[iletct] = '\0'; ask_again: oclasses[oclassct = 0] = '\0'; *one_at_a_time = *everything = FALSE; not_everything = FALSE; Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", action, ilets); getlin(qbuf, inbuf); if (*inbuf == '\033') return FALSE; for (p = inbuf; (sym = *p++);) { /* new A function (selective all) added by GAN 01/09/87 */ if (sym == ' ') continue; else if (sym == 'A') *one_at_a_time = TRUE; else if (sym == 'a') *everything = TRUE; else if (sym == ':') { simple_look(objs, here); /* dumb if objs==invent */ /* if we just scanned the contents of a container then mark it as having known contents */ if (objs->where == OBJ_CONTAINED) objs->ocontainer->cknown = 1; goto ask_again; } else if (sym == 'i') { (void) display_inventory((char *) 0, TRUE); goto ask_again; } else if (sym == 'm') { m_seen = TRUE; } else { oc_of_sym = def_char_to_objclass(sym); if (index(ilets, sym)) { add_valid_menu_class(oc_of_sym); oclasses[oclassct++] = oc_of_sym; oclasses[oclassct] = '\0'; } else { if (!where) where = !strcmp(action, "pick up") ? "here" : !strcmp(action, "take out") ? "inside" : ""; if (*where) There("are no %c's %s.", sym, where); else You("have no %c's.", sym); not_everything = TRUE; } } } if (m_seen && menu_on_demand) { *menu_on_demand = (*everything || !oclassct) ? -2 : -3; return FALSE; } if (!oclassct && (!*everything || not_everything)) { /* didn't pick anything, or tried to pick something that's not present */ *one_at_a_time = TRUE; /* force 'A' */ *everything = FALSE; /* inhibit 'a' */ } } return TRUE; } /* check whether hero is bare-handedly touching a cockatrice corpse */ STATIC_OVL boolean fatal_corpse_mistake(obj, remotely) struct obj *obj; boolean remotely; { if (uarmg || remotely || obj->otyp != CORPSE || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance) return FALSE; if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) { display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */ return FALSE; } pline("Touching %s is a fatal mistake.", corpse_xname(obj, (const char *) 0, CXN_SINGULAR | CXN_ARTICLE)); instapetrify(killer_xname(obj)); return TRUE; } /* attempting to manipulate a Rider's corpse triggers its revival */ boolean rider_corpse_revival(obj, remotely) struct obj *obj; boolean remotely; { if (!obj || obj->otyp != CORPSE || !is_rider(&mons[obj->corpsenm])) return FALSE; pline("At your %s, the corpse suddenly moves...", remotely ? "attempted acquisition" : "touch"); (void) revive_corpse(obj); exercise(A_WIS, FALSE); return TRUE; } /* look at the objects at our location, unless there are too many of them */ STATIC_OVL void check_here(picked_some) boolean picked_some; { register struct obj *obj; register int ct = 0; /* count the objects here */ for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) { if (obj != uchain) ct++; } /* If there are objects here, take a look. */ if (ct) { if (context.run) nomul(0); flush_screen(1); (void) look_here(ct, picked_some); } else { read_engr_at(u.ux, u.uy); } } /* Value set by query_objlist() for n_or_more(). */ static long val_for_n_or_more; /* query_objlist callback: return TRUE if obj's count is >= reference value */ STATIC_OVL boolean n_or_more(obj) struct obj *obj; { if (obj == uchain) return FALSE; return (boolean) (obj->quan >= val_for_n_or_more); } /* list of valid menu classes for query_objlist() and allow_category callback (with room for all object classes, 'u'npaid, BUCX, and terminator) */ static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1]; static boolean class_filter, bucx_filter, shop_filter; void add_valid_menu_class(c) int c; { static int vmc_count = 0; if (c == 0) { /* reset */ vmc_count = 0; class_filter = bucx_filter = shop_filter = FALSE; } else { valid_menu_classes[vmc_count++] = (char) c; /* categorize the new class */ switch (c) { case 'B': case 'U': case 'C': /*FALLTHRU*/ case 'X': bucx_filter = TRUE; break; case 'u': shop_filter = TRUE; break; default: class_filter = TRUE; break; } } valid_menu_classes[vmc_count] = '\0'; } /* query_objlist callback: return TRUE if not uchain */ STATIC_OVL boolean all_but_uchain(obj) struct obj *obj; { return (boolean) (obj != uchain); } /* query_objlist callback: return TRUE */ /*ARGUSED*/ boolean allow_all(obj) struct obj *obj UNUSED; { return TRUE; } boolean allow_category(obj) struct obj *obj; { /* unpaid and BUC checks don't apply to coins */ if (obj->oclass == COIN_CLASS) return index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE; if (Role_if(PM_PRIEST)) obj->bknown = TRUE; /* * There are three types of filters possible and the first and * third can have more than one entry: * 1) object class (armor, potion, &c); * 2) unpaid shop item; * 3) bless/curse state (blessed, uncursed, cursed, BUC-unknown). * When only one type is present, the situation is simple: * to be accepted, obj's status must match one of the entries. * When more than one type is present, the obj will now only * be accepted when it matches one entry of each type. * So ?!B will accept blessed scrolls or potions, and [u will * accept unpaid armor. (In 3.4.3, an object was accepted by * this filter if it met any entry of any type, so ?!B resulted * in accepting all scrolls and potions regardless of bless/curse * state plus all blessed non-scroll, non-potion objects.) */ /* if class is expected but obj's class is not in the list, reject */ if (class_filter && !index(valid_menu_classes, obj->oclass)) return FALSE; /* if unpaid is expected and obj isn't unpaid, reject (treat a container holding any unpaid object as unpaid even if isn't unpaid itself) */ if (shop_filter && !obj->unpaid && !(Has_contents(obj) && count_unpaid(obj->cobj) > 0)) return FALSE; /* check for particular bless/curse state */ if (bucx_filter) { /* first categorize this object's bless/curse state */ char bucx = !obj->bknown ? 'X' : obj->blessed ? 'B' : obj->cursed ? 'C' : 'U'; /* if its category is not in the list, reject */ if (!index(valid_menu_classes, bucx)) return FALSE; } /* obj didn't fail any of the filter checks, so accept */ return TRUE; } #if 0 /* not used */ /* query_objlist callback: return TRUE if valid category (class), no uchain */ STATIC_OVL boolean allow_cat_no_uchain(obj) struct obj *obj; { if (obj != uchain && ((index(valid_menu_classes,'u') && obj->unpaid) || index(valid_menu_classes, obj->oclass))) return TRUE; else return FALSE; } #endif /* query_objlist callback: return TRUE if valid class and worn */ boolean is_worn_by_type(otmp) register struct obj *otmp; { return (boolean) (!!(otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)) && index(valid_menu_classes, otmp->oclass) != 0); } /* * Have the hero pick things from the ground * or a monster's inventory if swallowed. * * Arg what: * >0 autopickup * =0 interactive * <0 pickup count of something * * Returns 1 if tried to pick something up, whether * or not it succeeded. */ int pickup(what) int what; /* should be a long */ { int i, n, res, count, n_tried = 0, n_picked = 0; menu_item *pick_list = (menu_item *) 0; boolean autopickup = what > 0; struct obj *objchain; int traverse_how; /* we might have arrived here while fainted or sleeping, via random teleport or levitation timeout; if so, skip check_here and read_engr_at in addition to bypassing autopickup itself [probably ought to check whether hero is using a cockatrice corpse for a pillow here... (also at initial faint/sleep)] */ if (autopickup && multi < 0 && unconscious()) return 0; if (what < 0) /* pick N of something */ count = -what; else /* pick anything */ count = 0; if (!u.uswallow) { struct trap *ttmp = t_at(u.ux, u.uy); /* no auto-pick if no-pick move, nothing there, or in a pool */ if (autopickup && (context.nopick || !OBJ_AT(u.ux, u.uy) || (is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) { read_engr_at(u.ux, u.uy); return 0; } /* no pickup if levitating & not on air or water level */ if (!can_reach_floor(TRUE)) { if ((multi && !context.run) || (autopickup && !flags.pickup) || (ttmp && uteetering_at_seen_pit(ttmp))) read_engr_at(u.ux, u.uy); return 0; } /* multi && !context.run means they are in the middle of some other * action, or possibly paralyzed, sleeping, etc.... and they just * teleported onto the object. They shouldn't pick it up. */ if ((multi && !context.run) || (autopickup && !flags.pickup)) { check_here(FALSE); return 0; } if (notake(youmonst.data)) { if (!autopickup) You("are physically incapable of picking anything up."); else check_here(FALSE); return 0; } /* if there's anything here, stop running */ if (OBJ_AT(u.ux, u.uy) && context.run && context.run != 8 && !context.nopick) nomul(0); } add_valid_menu_class(0); /* reset */ if (!u.uswallow) { objchain = level.objects[u.ux][u.uy]; traverse_how = BY_NEXTHERE; } else { objchain = u.ustuck->minvent; traverse_how = 0; /* nobj */ } /* * Start the actual pickup process. This is split into two main * sections, the newer menu and the older "traditional" methods. * Automatic pickup has been split into its own menu-style routine * to make things less confusing. */ if (autopickup) { n = autopick(objchain, traverse_how, &pick_list); goto menu_pickup; } if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) { /* use menus exclusively */ if (count) { /* looking for N of something */ char buf[QBUFSZ]; Sprintf(buf, "Pick %d of what?", count); val_for_n_or_more = count; /* set up callback selector */ n = query_objlist(buf, objchain, traverse_how | AUTOSELECT_SINGLE | INVORDER_SORT, &pick_list, PICK_ONE, n_or_more); /* correct counts, if any given */ for (i = 0; i < n; i++) pick_list[i].count = count; } else { n = query_objlist("Pick up what?", objchain, traverse_how | AUTOSELECT_SINGLE | INVORDER_SORT | FEEL_COCKATRICE, &pick_list, PICK_ANY, all_but_uchain); } menu_pickup: n_tried = n; for (n_picked = i = 0; i < n; i++) { res = pickup_object(pick_list[i].item.a_obj, pick_list[i].count, FALSE); if (res < 0) break; /* can't continue */ n_picked += res; } if (pick_list) free((genericptr_t) pick_list); } else { /* old style interface */ int ct = 0; long lcount; boolean all_of_a_type, selective; char oclasses[MAXOCLASSES]; struct obj *obj, *obj2; oclasses[0] = '\0'; /* types to consider (empty for all) */ all_of_a_type = TRUE; /* take all of considered types */ selective = FALSE; /* ask for each item */ /* check for more than one object */ for (obj = objchain; obj; obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj) ct++; if (ct == 1 && count) { /* if only one thing, then pick it */ obj = objchain; lcount = min(obj->quan, (long) count); n_tried++; if (pickup_object(obj, lcount, FALSE) > 0) n_picked++; /* picked something */ goto end_query; } else if (ct >= 2) { int via_menu = 0; There("are %s objects here.", (ct <= 10) ? "several" : "many"); if (!query_classes(oclasses, &selective, &all_of_a_type, "pick up", objchain, traverse_how == BY_NEXTHERE, &via_menu)) { if (!via_menu) return 0; n = query_objlist( "Pick up what?", objchain, traverse_how | (selective ? 0 : INVORDER_SORT), &pick_list, PICK_ANY, via_menu == -2 ? allow_all : allow_category); goto menu_pickup; } } for (obj = objchain; obj; obj = obj2) { if (traverse_how == BY_NEXTHERE) obj2 = obj->nexthere; /* perhaps obj will be picked up */ else obj2 = obj->nobj; lcount = -1L; if (!selective && oclasses[0] && !index(oclasses, obj->oclass)) continue; if (!all_of_a_type) { char qbuf[BUFSZ]; (void) safe_qbuf(qbuf, "Pick up ", "?", obj, doname, ansimpleoname, something); switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) { case 'q': goto end_query; /* out 2 levels */ case 'n': continue; case 'a': all_of_a_type = TRUE; if (selective) { selective = FALSE; oclasses[0] = obj->oclass; oclasses[1] = '\0'; } break; case '#': /* count was entered */ if (!yn_number) continue; /* 0 count => No */ lcount = (long) yn_number; if (lcount > obj->quan) lcount = obj->quan; /* fall thru */ default: /* 'y' */ break; } } if (lcount == -1L) lcount = obj->quan; n_tried++; if ((res = pickup_object(obj, lcount, FALSE)) < 0) break; n_picked += res; } end_query: ; /* semicolon needed by brain-damaged compilers */ } if (!u.uswallow) { if (hides_under(youmonst.data)) (void) hideunder(&youmonst); /* position may need updating (invisible hero) */ if (n_picked) newsym(u.ux, u.uy); /* check if there's anything else here after auto-pickup is done */ if (autopickup) check_here(n_picked > 0); } return (n_tried > 0); } boolean is_autopickup_exception(obj, grab) struct obj *obj; boolean grab; /* forced pickup, rather than forced leave behind? */ { /* * Does the text description of this match an exception? */ char *objdesc = makesingular(doname(obj)); struct autopickup_exception *ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB] : iflags.autopickup_exceptions[AP_LEAVE]; while (ape) { if (regex_match(objdesc, ape->regex)) return TRUE; ape = ape->next; } return FALSE; } /* * Pick from the given list using flags.pickup_types. Return the number * of items picked (not counts). Create an array that returns pointers * and counts of the items to be picked up. If the number of items * picked is zero, the pickup list is left alone. The caller of this * function must free the pickup list. */ STATIC_OVL int autopick(olist, follow, pick_list) struct obj *olist; /* the object list */ int follow; /* how to follow the object list */ menu_item **pick_list; /* list of objects and counts to pick up */ { menu_item *pi; /* pick item */ struct obj *curr; int n; boolean pickit; const char *otypes = flags.pickup_types; /* first count the number of eligible items */ for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) { pickit = (!*otypes || index(otypes, curr->oclass)); /* check for "always pick up */ if (!pickit) pickit = is_autopickup_exception(curr, TRUE); /* then for "never pick up */ if (pickit) pickit = !is_autopickup_exception(curr, FALSE); /* pickup_thrown overrides pickup_types and exceptions */ if (!pickit) pickit = (flags.pickup_thrown && curr->was_thrown); /* finally, do we count this object? */ if (pickit) ++n; } if (n) { *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n); for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) { pickit = (!*otypes || index(otypes, curr->oclass)); if (!pickit) pickit = is_autopickup_exception(curr, TRUE); if (pickit) pickit = !is_autopickup_exception(curr, FALSE); if (!pickit) pickit = (flags.pickup_thrown && curr->was_thrown); if (pickit) { pi[n].item.a_obj = curr; pi[n].count = curr->quan; n++; } } } return n; } /* * Put up a menu using the given object list. Only those objects on the * list that meet the approval of the allow function are displayed. Return * a count of the number of items selected, as well as an allocated array of * menu_items, containing pointers to the objects selected and counts. The * returned counts are guaranteed to be in bounds and non-zero. * * Query flags: * BY_NEXTHERE - Follow object list via nexthere instead of nobj. * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just * use it. * USE_INVLET - Use object's invlet. * INVORDER_SORT - Use hero's pack order. * INCLUDE_HERO - Showing engulfer's invent; show hero too. * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow". * SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to * pick nothing. */ int query_objlist(qstr, olist, qflags, pick_list, how, allow) const char *qstr; /* query string */ struct obj *olist; /* the list to pick from */ int qflags; /* options to control the query */ menu_item **pick_list; /* return list of items picked */ int how; /* type of query */ boolean FDECL((*allow), (OBJ_P)); /* allow function */ { int i, n, actualn; winid win; struct obj *curr, *last, fake_hero_object; struct obj **oarray; char *pack; anything any; boolean printed_type_name, sorted = (qflags & INVORDER_SORT) != 0, engulfer = (qflags & INCLUDE_HERO) != 0; *pick_list = (menu_item *) 0; if (!olist && !engulfer) return 0; /* count the number of items allowed */ for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags)) if ((*allow)(curr)) { last = curr; n++; } actualn = n; if (engulfer) { ++n; /* don't autoselect swallowed hero if it's the only choice */ qflags &= ~AUTOSELECT_SINGLE; } if (n == 0) /* nothing to pick here */ return (qflags & SIGNAL_NOMENU) ? -1 : 0; if (n == 1 && (qflags & AUTOSELECT_SINGLE)) { *pick_list = (menu_item *) alloc(sizeof(menu_item)); (*pick_list)->item.a_obj = last; (*pick_list)->count = last->quan; return 1; } oarray = objarr_init(actualn); /* Add objects to the array */ i = 0; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if ((*allow)(curr)) { objarr_set(curr, i++, oarray, (flags.sortloot == 'f' || (flags.sortloot == 'l' && !(qflags & USE_INVLET)))); } } win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* * Run through the list and add the objects to the menu. If * INVORDER_SORT is set, we'll run through the list once for * each type so we can group them. The allow function will only * be called once per object in the list. */ pack = flags.inv_order; do { printed_type_name = FALSE; for (i = 0; i < actualn; i++) { curr = oarray[i]; if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE && will_feel_cockatrice(curr, FALSE)) { destroy_nhwindow(win); /* stop the menu and revert */ (void) look_here(0, FALSE); return 0; } if ((!sorted || curr->oclass == *pack) && (*allow)(curr)) { /* if sorting, print type name (once only) */ if (sorted && !printed_type_name) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, let_to_name(*pack, FALSE, (how != PICK_NONE) && iflags.menu_head_objsym), MENU_UNSELECTED); printed_type_name = TRUE; } any.a_obj = curr; add_menu(win, obj_to_glyph(curr), &any, (qflags & USE_INVLET) ? curr->invlet : 0, def_oc_syms[(int) objects[curr->otyp].oc_class].sym, ATR_NONE, doname_with_price(curr), MENU_UNSELECTED); } } pack++; } while (sorted && *pack); free(oarray); if (engulfer) { char buf[BUFSZ]; any = zeroany; if (sorted && n > 1) { Sprintf(buf, "%s Creatures", is_animal(u.ustuck->data) ? "Swallowed" : "Engulfed"); add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED); } fake_hero_object = zeroobj; fake_hero_object.quan = 1L; /* not strictly necessary... */ any.a_obj = &fake_hero_object; add_menu(win, mon_to_glyph(&youmonst), &any, /* fake inventory letter, no group accelerator */ CONTAINED_SYM, 0, ATR_NONE, an(self_lookat(buf)), MENU_UNSELECTED); } end_menu(win, qstr); n = select_menu(win, how, pick_list); destroy_nhwindow(win); if (n > 0) { menu_item *mi; int k; /* fix up counts: -1 means no count used => pick all; if fake_hero_object was picked, discard that choice */ for (i = k = 0, mi = *pick_list; i < n; i++, mi++) { if (mi->item.a_obj == &fake_hero_object) continue; if (mi->count == -1L || mi->count > mi->item.a_obj->quan) mi->count = mi->item.a_obj->quan; if (k < i) (*pick_list)[k] = *mi; ++k; } if (!k) { /* fake_hero was only choice so discard whole list */ free((genericptr_t) *pick_list); *pick_list = 0; n = 0; } else if (k < n) { /* other stuff plus fake_hero; last slot is now unused */ (*pick_list)[k].item = zeroany; (*pick_list)[k].count = 0L; n = k; } } else if (n < 0) { /* -1 is used for SIGNAL_NOMENU, so callers don't expect it to indicate that the player declined to make a choice */ n = (qflags & SIGNAL_ESCAPE) ? -2 : 0; } return n; } /* * allow menu-based category (class) selection (for Drop,take off etc.) * */ int query_category(qstr, olist, qflags, pick_list, how) const char *qstr; /* query string */ struct obj *olist; /* the list to pick from */ int qflags; /* behaviour modification flags */ menu_item **pick_list; /* return list of items picked */ int how; /* type of query */ { int n; winid win; struct obj *curr; char *pack; anything any; boolean collected_type_name; char invlet; int ccount; boolean do_unpaid = FALSE; boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE, do_buc_unknown = FALSE; int num_buc_types = 0; *pick_list = (menu_item *) 0; if (!olist) return 0; if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) do_unpaid = TRUE; if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) { do_blessed = TRUE; num_buc_types++; } if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) { do_cursed = TRUE; num_buc_types++; } if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) { do_uncursed = TRUE; num_buc_types++; } if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) { do_buc_unknown = TRUE; num_buc_types++; } ccount = count_categories(olist, qflags); /* no point in actually showing a menu for a single category */ if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) { for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if ((qflags & WORN_TYPES) && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON))) continue; break; } if (curr) { *pick_list = (menu_item *) alloc(sizeof(menu_item)); (*pick_list)->item.a_int = curr->oclass; return 1; } else { debugpline0("query_category: no single object match"); } return 0; } win = create_nhwindow(NHW_MENU); start_menu(win); pack = flags.inv_order; if ((qflags & ALL_TYPES) && (ccount > 1)) { invlet = 'a'; any = zeroany; any.a_int = ALL_TYPES_SELECTED; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, (qflags & WORN_TYPES) ? "All worn types" : "All types", MENU_UNSELECTED); invlet = 'b'; } else invlet = 'a'; do { collected_type_name = FALSE; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if (curr->oclass == *pack) { if ((qflags & WORN_TYPES) && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON))) continue; if (!collected_type_name) { any = zeroany; any.a_int = curr->oclass; add_menu( win, NO_GLYPH, &any, invlet++, def_oc_syms[(int) objects[curr->otyp].oc_class].sym, ATR_NONE, let_to_name(*pack, FALSE, (how != PICK_NONE) && iflags.menu_head_objsym), MENU_UNSELECTED); collected_type_name = TRUE; } } } pack++; if (invlet >= 'u') { impossible("query_category: too many categories"); return 0; } } while (*pack); /* unpaid items if there are any */ if (do_unpaid) { invlet = 'u'; any = zeroany; any.a_int = 'u'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items", MENU_UNSELECTED); } /* billed items: checked by caller, so always include if BILLED_TYPES */ if (qflags & BILLED_TYPES) { invlet = 'x'; any = zeroany; any.a_int = 'x'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items already used up", MENU_UNSELECTED); } if (qflags & CHOOSE_ALL) { invlet = 'A'; any = zeroany; any.a_int = 'A'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, (qflags & WORN_TYPES) ? "Auto-select every item being worn" : "Auto-select every item", MENU_UNSELECTED); } /* items with b/u/c/unknown if there are any */ if (do_blessed) { invlet = 'B'; any = zeroany; any.a_int = 'B'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items known to be Blessed", MENU_UNSELECTED); } if (do_cursed) { invlet = 'C'; any = zeroany; any.a_int = 'C'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items known to be Cursed", MENU_UNSELECTED); } if (do_uncursed) { invlet = 'U'; any = zeroany; any.a_int = 'U'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items known to be Uncursed", MENU_UNSELECTED); } if (do_buc_unknown) { invlet = 'X'; any = zeroany; any.a_int = 'X'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items of unknown B/C/U status", MENU_UNSELECTED); } end_menu(win, qstr); n = select_menu(win, how, pick_list); destroy_nhwindow(win); if (n < 0) n = 0; /* caller's don't expect -1 */ return n; } STATIC_OVL int count_categories(olist, qflags) struct obj *olist; int qflags; { char *pack; boolean counted_category; int ccount = 0; struct obj *curr; pack = flags.inv_order; do { counted_category = FALSE; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if (curr->oclass == *pack) { if ((qflags & WORN_TYPES) && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON))) continue; if (!counted_category) { ccount++; counted_category = TRUE; } } } pack++; } while (*pack); return ccount; } /* could we carry `obj'? if not, could we carry some of it/them? */ STATIC_OVL long carry_count(obj, container, count, telekinesis, wt_before, wt_after) struct obj *obj, *container; /* object to pick up, bag it's coming out of */ long count; boolean telekinesis; int *wt_before, *wt_after; { boolean adjust_wt = container && carried(container), is_gold = obj->oclass == COIN_CLASS; int wt, iw, ow, oow; long qq, savequan, umoney; unsigned saveowt; const char *verb, *prefx1, *prefx2, *suffx; char obj_nambuf[BUFSZ], where[BUFSZ]; savequan = obj->quan; saveowt = obj->owt; umoney = money_cnt(invent); iw = max_capacity(); if (count != savequan) { obj->quan = count; obj->owt = (unsigned) weight(obj); } wt = iw + (int) obj->owt; if (adjust_wt) wt -= (container->otyp == BAG_OF_HOLDING) ? (int) DELTA_CWT(container, obj) : (int) obj->owt; /* This will go with silver+copper & new gold weight */ if (is_gold) /* merged gold might affect cumulative weight */ wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count)); if (count != savequan) { obj->quan = savequan; obj->owt = saveowt; } *wt_before = iw; *wt_after = wt; if (wt < 0) return count; /* see how many we can lift */ if (is_gold) { iw -= (int) GOLD_WT(umoney); if (!adjust_wt) { qq = GOLD_CAPACITY((long) iw, umoney); } else { oow = 0; qq = 50L - (umoney % 100L) - 1L; if (qq < 0L) qq += 100L; for (; qq <= count; qq += 100L) { obj->quan = qq; obj->owt = (unsigned) GOLD_WT(qq); ow = (int) GOLD_WT(umoney + qq); ow -= (container->otyp == BAG_OF_HOLDING) ? (int) DELTA_CWT(container, obj) : (int) obj->owt; if (iw + ow >= 0) break; oow = ow; } iw -= oow; qq -= 100L; } if (qq < 0L) qq = 0L; else if (qq > count) qq = count; wt = iw + (int) GOLD_WT(umoney + qq); } else if (count > 1 || count < obj->quan) { /* * Ugh. Calc num to lift by changing the quan of of the * object and calling weight. * * This works for containers only because containers * don't merge. -dean */ for (qq = 1L; qq <= count; qq++) { obj->quan = qq; obj->owt = (unsigned) (ow = weight(obj)); if (adjust_wt) ow -= (container->otyp == BAG_OF_HOLDING) ? (int) DELTA_CWT(container, obj) : (int) obj->owt; if (iw + ow >= 0) break; wt = iw + ow; } --qq; } else { /* there's only one, and we can't lift it */ qq = 0L; } obj->quan = savequan; obj->owt = saveowt; if (qq < count) { /* some message will be given */ Strcpy(obj_nambuf, doname(obj)); if (container) { Sprintf(where, "in %s", the(xname(container))); verb = "carry"; } else { Strcpy(where, "lying here"); verb = telekinesis ? "acquire" : "lift"; } } else { /* lint suppression */ *obj_nambuf = *where = '\0'; verb = ""; } /* we can carry qq of them */ if (qq > 0) { if (qq < count) You("can only %s %s of the %s %s.", verb, (qq == 1L) ? "one" : "some", obj_nambuf, where); *wt_after = wt; return qq; } if (!container) Strcpy(where, "here"); /* slightly shorter form */ if (invent || umoney) { prefx1 = "you cannot "; prefx2 = ""; suffx = " any more"; } else { prefx1 = (obj->quan == 1L) ? "it " : "even one "; prefx2 = "is too heavy for you to "; suffx = ""; } There("%s %s %s, but %s%s%s%s.", otense(obj, "are"), obj_nambuf, where, prefx1, prefx2, verb, suffx); /* *wt_after = iw; */ return 0L; } /* determine whether character is able and player is willing to carry `obj' */ STATIC_OVL int lift_object(obj, container, cnt_p, telekinesis) struct obj *obj, *container; /* object to pick up, bag it's coming out of */ long *cnt_p; boolean telekinesis; { int result, old_wt, new_wt, prev_encumbr, next_encumbr; if (obj->otyp == BOULDER && Sokoban) { You("cannot get your %s around this %s.", body_part(HAND), xname(obj)); return -1; } /* override weight consideration for loadstone picked up by anybody and for boulder picked up by hero poly'd into a giant; override availability of open inventory slot iff not already carrying one */ if (obj->otyp == LOADSTONE || (obj->otyp == BOULDER && throws_rocks(youmonst.data))) { if (inv_cnt(FALSE) < 52 || !carrying(obj->otyp) || merge_choice(invent, obj)) return 1; /* lift regardless of current situation */ /* if we reach here, we're out of slots and already have at least one of these, so treat this one more like a normal item */ You("are carrying too much stuff to pick up %s %s.", (obj->quan == 1L) ? "another" : "more", simpleonames(obj)); return -1; } *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt); if (*cnt_p < 1L) { result = -1; /* nothing lifted */ } else if (obj->oclass != COIN_CLASS /* [exception for gold coins will have to change if silver/copper ones ever get implemented] */ && inv_cnt(FALSE) >= 52 && !merge_choice(invent, obj)) { Your("knapsack cannot accommodate any more items."); result = -1; /* nothing lifted */ } else { result = 1; prev_encumbr = near_capacity(); if (prev_encumbr < flags.pickup_burden) prev_encumbr = flags.pickup_burden; next_encumbr = calc_capacity(new_wt - old_wt); if (next_encumbr > prev_encumbr) { if (telekinesis) { result = 0; /* don't lift */ } else { char qbuf[BUFSZ]; long savequan = obj->quan; obj->quan = *cnt_p; Strcpy(qbuf, (next_encumbr > HVY_ENCUMBER) ? overloadmsg : (next_encumbr > MOD_ENCUMBER) ? nearloadmsg : moderateloadmsg); if (container) (void) strsubst(qbuf, "lifting", "removing"); Strcat(qbuf, " "); (void) safe_qbuf(qbuf, qbuf, ". Continue?", obj, doname, ansimpleoname, something); obj->quan = savequan; switch (ynq(qbuf)) { case 'q': result = -1; break; case 'n': result = 0; break; default: break; /* 'y' => result == 1 */ } clear_nhwindow(WIN_MESSAGE); } } } if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container) obj->spe = 0; return result; } /* * Pick up of obj from the ground and add it to the hero's inventory. * Returns -1 if caller should break out of its loop, 0 if nothing picked * up, 1 if otherwise. */ int pickup_object(obj, count, telekinesis) struct obj *obj; long count; boolean telekinesis; /* not picking it up directly by hand */ { int res, nearload; if (obj->quan < count) { impossible("pickup_object: count %ld > quan %ld?", count, obj->quan); return 0; } /* In case of auto-pickup, where we haven't had a chance to look at it yet; affects docall(SCR_SCARE_MONSTER). */ if (!Blind) obj->dknown = 1; if (obj == uchain) { /* do not pick up attached chain */ return 0; } else if (obj->oartifact && !touch_artifact(obj, &youmonst)) { return 0; } else if (obj->otyp == CORPSE) { if (fatal_corpse_mistake(obj, telekinesis) || rider_corpse_revival(obj, telekinesis)) return -1; } else if (obj->otyp == SCR_SCARE_MONSTER) { if (obj->blessed) obj->blessed = 0; else if (!obj->spe && !obj->cursed) obj->spe = 1; else { pline_The("scroll%s %s to dust as you %s %s up.", plur(obj->quan), otense(obj, "turn"), telekinesis ? "raise" : "pick", (obj->quan == 1L) ? "it" : "them"); if (!(objects[SCR_SCARE_MONSTER].oc_name_known) && !(objects[SCR_SCARE_MONSTER].oc_uname)) docall(obj); useupf(obj, obj->quan); return 1; /* tried to pick something up and failed, but don't want to terminate pickup loop yet */ } } if ((res = lift_object(obj, (struct obj *) 0, &count, telekinesis)) <= 0) return res; /* Whats left of the special case for gold :-) */ if (obj->oclass == COIN_CLASS) context.botl = 1; if (obj->quan != count && obj->otyp != LOADSTONE) obj = splitobj(obj, count); obj = pick_obj(obj); if (uwep && uwep == obj) mrg_to_wielded = TRUE; nearload = near_capacity(); prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, obj, count); mrg_to_wielded = FALSE; return 1; } /* * Do the actual work of picking otmp from the floor or monster's interior * and putting it in the hero's inventory. Take care of billing. Return a * pointer to the object where otmp ends up. This may be different * from otmp because of merging. */ struct obj * pick_obj(otmp) struct obj *otmp; { obj_extract_self(otmp); if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) { char saveushops[5], fakeshop[2]; /* addtobill cares about your location rather than the object's; usually they'll be the same, but not when using telekinesis (if ever implemented) or a grappling hook */ Strcpy(saveushops, u.ushops); fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE); fakeshop[1] = '\0'; Strcpy(u.ushops, fakeshop); /* sets obj->unpaid if necessary */ addtobill(otmp, TRUE, FALSE, FALSE); Strcpy(u.ushops, saveushops); /* if you're outside the shop, make shk notice */ if (!index(u.ushops, *fakeshop)) remote_burglary(otmp->ox, otmp->oy); } newsym(otmp->ox, otmp->oy); return addinv(otmp); /* might merge it with other objects */ } /* * prints a message if encumbrance changed since the last check and * returns the new encumbrance value (from near_capacity()). */ int encumber_msg() { static int oldcap = UNENCUMBERED; int newcap = near_capacity(); if (oldcap < newcap) { switch (newcap) { case 1: Your("movements are slowed slightly because of your load."); break; case 2: You("rebalance your load. Movement is difficult."); break; case 3: You("%s under your heavy load. Movement is very hard.", stagger(youmonst.data, "stagger")); break; default: You("%s move a handspan with this load!", newcap == 4 ? "can barely" : "can't even"); break; } context.botl = 1; } else if (oldcap > newcap) { switch (newcap) { case 0: Your("movements are now unencumbered."); break; case 1: Your("movements are only slowed slightly by your load."); break; case 2: You("rebalance your load. Movement is still difficult."); break; case 3: You("%s under your load. Movement is still very hard.", stagger(youmonst.data, "stagger")); break; } context.botl = 1; } oldcap = newcap; return newcap; } /* Is there a container at x,y. Optional: return count of containers at x,y */ STATIC_OVL int container_at(x, y, countem) int x, y; boolean countem; { struct obj *cobj, *nobj; int container_count = 0; for (cobj = level.objects[x][y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (Is_container(cobj)) { container_count++; if (!countem) break; } } return container_count; } STATIC_OVL boolean able_to_loot(x, y, looting) int x, y; boolean looting; /* loot vs tip */ { const char *verb = looting ? "loot" : "tip"; if (!can_reach_floor(TRUE)) { if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) rider_cant_reach(); /* not skilled enough to reach */ else cant_reach_floor(x, y, FALSE, TRUE); return FALSE; } else if ((is_pool(x, y) && (looting || !Underwater)) || is_lava(x, y)) { /* at present, can't loot in water even when Underwater; can tip underwater, but not when over--or stuck in--lava */ You("cannot %s things that are deep in the %s.", verb, is_lava(x, y) ? "lava" : "water"); return FALSE; } else if (nolimbs(youmonst.data)) { pline("Without limbs, you cannot %s anything.", verb); return FALSE; } else if (looting && !freehand()) { pline("Without a free %s, you cannot loot anything.", body_part(HAND)); return FALSE; } return TRUE; } STATIC_OVL boolean mon_beside(x, y) int x, y; { int i, j, nx, ny; for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { nx = x + i; ny = y + j; if (isok(nx, ny) && MON_AT(nx, ny)) return TRUE; } return FALSE; } int do_loot_cont(cobjp) struct obj **cobjp; { struct obj *cobj = *cobjp; if (!cobj) return 0; if (cobj->olocked) { pline("%s locked.", cobj->lknown ? "It is" : "Hmmm, it turns out to be"); cobj->lknown = 1; return 0; } cobj->lknown = 1; if (cobj->otyp == BAG_OF_TRICKS) { int tmp; You("carefully open the bag..."); pline("It develops a huge set of teeth and bites you!"); tmp = rnd(10); losehp(Maybe_Half_Phys(tmp), "carnivorous bag", KILLED_BY_AN); makeknown(BAG_OF_TRICKS); return 1; } You("%sopen %s...", (!cobj->cknown || !cobj->lknown) ? "carefully " : "", the(xname(cobj))); return use_container(cobjp, 0); } /* loot a container on the floor or loot saddle from mon. */ int doloot() { struct obj *cobj, *nobj; register int c = -1; int timepassed = 0; coord cc; boolean underfoot = TRUE; const char *dont_find_anything = "don't find anything"; struct monst *mtmp; char qbuf[BUFSZ]; int prev_inquiry = 0; boolean prev_loot = FALSE; int num_conts; if (check_capacity((char *) 0)) { /* "Can't do that while carrying so much stuff." */ return 0; } if (nohands(youmonst.data)) { You("have no hands!"); /* not `body_part(HAND)' */ return 0; } if (Confusion) { if (rn2(6) && reverse_loot()) return 1; if (rn2(2)) { pline("Being confused, you find nothing to loot."); return 1; /* costs a turn */ } /* else fallthrough to normal looting */ } cc.x = u.ux; cc.y = u.uy; lootcont: if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) { boolean anyfound = FALSE; if (!able_to_loot(cc.x, cc.y, TRUE)) return 0; if (num_conts > 1) { /* use a menu to loot many containers */ int n, i; winid win; anything any; menu_item *pick_list = NULL; any.a_void = 0; win = create_nhwindow(NHW_MENU); start_menu(win); for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = cobj->nexthere) if (Is_container(cobj)) { any.a_obj = cobj; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, doname(cobj), MENU_UNSELECTED); } end_menu(win, "Loot which containers?"); n = select_menu(win, PICK_ANY, &pick_list); destroy_nhwindow(win); if (n > 0) { for (i = 0; i < n; i++) { timepassed |= do_loot_cont(&pick_list[i].item.a_obj); if (multi < 0 || !pick_list[i].item.a_obj) { free((genericptr_t) pick_list); return 1; } } } if (pick_list) free((genericptr_t) pick_list); if (n != 0) c = 'y'; } else { for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (Is_container(cobj)) { c = ynq(safe_qbuf(qbuf, "There is ", " here, loot it?", cobj, doname, ansimpleoname, "a container")); if (c == 'q') return timepassed; if (c == 'n') continue; anyfound = TRUE; timepassed |= do_loot_cont(&cobj); /* might have triggered chest trap or magic bag explosion */ if (multi < 0 || !cobj) return 1; } } if (anyfound) c = 'y'; } } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) { You("need to dig up the grave to effectively loot it..."); } /* * 3.3.1 introduced directional looting for some things. */ if (c != 'y' && mon_beside(u.ux, u.uy)) { if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location", u.ux, u.uy, &cc)) return 0; if (cc.x == u.ux && cc.y == u.uy) { underfoot = TRUE; if (container_at(cc.x, cc.y, FALSE)) goto lootcont; } else underfoot = FALSE; if (u.dz < 0) { You("%s to loot on the %s.", dont_find_anything, ceiling(cc.x, cc.y)); timepassed = 1; return timepassed; } mtmp = m_at(cc.x, cc.y); if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot); /* always use a turn when choosing a direction is impaired, even if you've successfully targetted a saddled creature and then answered "no" to the "remove its saddle?" prompt */ if (Confusion || Stunned) timepassed = 1; /* Preserve pre-3.3.1 behaviour for containers. * Adjust this if-block to allow container looting * from one square away to change that in the future. */ if (!underfoot) { if (container_at(cc.x, cc.y, FALSE)) { if (mtmp) { You_cant("loot anything %sthere with %s in the way.", prev_inquiry ? "else " : "", mon_nam(mtmp)); return timepassed; } else { You("have to be at a container to loot it."); } } else { You("%s %sthere to loot.", dont_find_anything, (prev_inquiry || prev_loot) ? "else " : ""); return timepassed; } } } else if (c != 'y' && c != 'n') { You("%s %s to loot.", dont_find_anything, underfoot ? "here" : "there"); } return timepassed; } /* called when attempting to #loot while confused */ STATIC_OVL boolean reverse_loot() { struct obj *goldob = 0, *coffers, *otmp, boxdummy; struct monst *mon; long contribution; int n, x = u.ux, y = u.uy; if (!rn2(3)) { /* n objects: 1/(n+1) chance per object plus 1/(n+1) to fall off end */ for (n = inv_cnt(TRUE), otmp = invent; otmp; --n, otmp = otmp->nobj) if (!rn2(n + 1)) { prinv("You find old loot:", otmp, 0L); return TRUE; } return FALSE; } /* find a money object to mess with */ for (goldob = invent; goldob; goldob = goldob->nobj) if (goldob->oclass == COIN_CLASS) { contribution = ((long) rnd(5) * goldob->quan + 4L) / 5L; if (contribution < goldob->quan) goldob = splitobj(goldob, contribution); break; } if (!goldob) return FALSE; if (!IS_THRONE(levl[x][y].typ)) { dropx(goldob); /* the dropped gold might have fallen to lower level */ if (g_at(x, y)) pline("Ok, now there is loot here."); } else { /* find original coffers chest if present, otherwise use nearest one */ otmp = 0; for (coffers = fobj; coffers; coffers = coffers->nobj) if (coffers->otyp == CHEST) { if (coffers->spe == 2) break; /* a throne room chest */ if (!otmp || distu(coffers->ox, coffers->oy) < distu(otmp->ox, otmp->oy)) otmp = coffers; /* remember closest ordinary chest */ } if (!coffers) coffers = otmp; if (coffers) { verbalize("Thank you for your contribution to reduce the debt."); freeinv(goldob); (void) add_to_container(coffers, goldob); coffers->owt = weight(coffers); coffers->cknown = 0; if (!coffers->olocked) { boxdummy = zeroobj, boxdummy.otyp = SPE_WIZARD_LOCK; (void) boxlock(coffers, &boxdummy); } } else if (levl[x][y].looted != T_LOOTED && (mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) { freeinv(goldob); add_to_minv(mon, goldob); pline("The exchequer accepts your contribution."); if (!rn2(10)) levl[x][y].looted = T_LOOTED; } else { You("drop %s.", doname(goldob)); dropx(goldob); } } return TRUE; } /* loot_mon() returns amount of time passed. */ int loot_mon(mtmp, passed_info, prev_loot) struct monst *mtmp; int *passed_info; boolean *prev_loot; { int c = -1; int timepassed = 0; struct obj *otmp; char qbuf[QBUFSZ]; /* 3.3.1 introduced the ability to remove saddle from a steed */ /* *passed_info is set to TRUE if a loot query was given. */ /* *prev_loot is set to TRUE if something was actually acquired in here. */ if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) { long unwornmask; if (passed_info) *passed_info = 1; Sprintf( qbuf, "Do you want to remove the saddle from %s?", x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE)); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { if (nolimbs(youmonst.data)) { You_cant("do that without limbs."); /* not body_part(HAND) */ return 0; } if (otmp->cursed) { You("can't. The saddle seems to be stuck to %s.", x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE)); /* the attempt costs you time */ return 1; } obj_extract_self(otmp); if ((unwornmask = otmp->owornmask) != 0L) { mtmp->misc_worn_check &= ~unwornmask; otmp->owornmask = 0L; update_mon_intrinsics(mtmp, otmp, FALSE, FALSE); } otmp = hold_another_object(otmp, "You drop %s!", doname(otmp), (const char *) 0); timepassed = rnd(3); if (prev_loot) *prev_loot = TRUE; } else if (c == 'q') { return 0; } } /* 3.4.0 introduced the ability to pick things up from within swallower's * stomach */ if (u.uswallow) { int count = passed_info ? *passed_info : 0; timepassed = pickup(count); } return timepassed; } /* * Decide whether an object being placed into a magic bag will cause * it to explode. If the object is a bag itself, check recursively. */ STATIC_OVL boolean mbag_explodes(obj, depthin) struct obj *obj; int depthin; { /* these won't cause an explosion when they're empty */ if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) && obj->spe <= 0) return FALSE; /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */ if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) && (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin)) return TRUE; else if (Has_contents(obj)) { struct obj *otmp; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (mbag_explodes(otmp, depthin + 1)) return TRUE; } return FALSE; } /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */ STATIC_PTR int in_container(obj) register struct obj *obj; { boolean floor_container = !carried(current_container); boolean was_unpaid = FALSE; char buf[BUFSZ]; if (!current_container) { impossible(" no current_container?"); return 0; } else if (obj == uball || obj == uchain) { You("must be kidding."); return 0; } else if (obj == current_container) { pline("That would be an interesting topological exercise."); return 0; } else if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) { Norep("You cannot %s %s you are wearing.", Icebox ? "refrigerate" : "stash", something); return 0; } else if ((obj->otyp == LOADSTONE) && obj->cursed) { obj->bknown = 1; pline_The("stone%s won't leave your person.", plur(obj->quan)); return 0; } else if (obj->otyp == AMULET_OF_YENDOR || obj->otyp == CANDELABRUM_OF_INVOCATION || obj->otyp == BELL_OF_OPENING || obj->otyp == SPE_BOOK_OF_THE_DEAD) { /* Prohibit Amulets in containers; if you allow it, monsters can't * steal them. It also becomes a pain to check to see if someone * has the Amulet. Ditto for the Candelabrum, the Bell and the Book. */ pline("%s cannot be confined in such trappings.", The(xname(obj))); return 0; } else if (obj->otyp == LEASH && obj->leashmon != 0) { pline("%s attached to your pet.", Tobjnam(obj, "are")); return 0; } else if (obj == uwep) { if (welded(obj)) { weldmsg(obj); return 0; } setuwep((struct obj *) 0); if (uwep) return 0; /* unwielded, died, rewielded */ } else if (obj == uswapwep) { setuswapwep((struct obj *) 0); if (uswapwep) return 0; /* unwielded, died, rewielded */ } else if (obj == uquiver) { setuqwep((struct obj *) 0); if (uquiver) return 0; /* unwielded, died, rewielded */ } if (fatal_corpse_mistake(obj, FALSE)) return -1; /* boxes, boulders, and big statues can't fit into any container */ if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER || (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) { /* * xname() uses a static result array. Save obj's name * before current_container's name is computed. Don't * use the result of strcpy() within You() --- the order * of evaluation of the parameters is undefined. */ Strcpy(buf, the(xname(obj))); You("cannot fit %s into %s.", buf, the(xname(current_container))); return 0; } freeinv(obj); if (obj_is_burning(obj)) /* this used to be part of freeinv() */ (void) snuff_lit(obj); if (floor_container && costly_spot(u.ux, u.uy)) { if (current_container->no_charge && !obj->unpaid) { /* don't sell when putting the item into your own container */ obj->no_charge = 1; } else if (obj->oclass != COIN_CLASS) { /* sellobj() will take an unpaid item off the shop bill * note: coins are handled later */ was_unpaid = obj->unpaid ? TRUE : FALSE; sellobj_state(SELL_DELIBERATE); sellobj(obj, u.ux, u.uy); sellobj_state(SELL_NORMAL); } } if (Icebox && !age_is_relative(obj)) { obj->age = monstermoves - obj->age; /* actual age */ /* stop any corpse timeouts when frozen */ if (obj->otyp == CORPSE && obj->timed) { long rot_alarm = stop_timer(ROT_CORPSE, obj_to_any(obj)); (void) stop_timer(REVIVE_MON, obj_to_any(obj)); /* mark a non-reviving corpse as such */ if (rot_alarm) obj->norevive = 1; } } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { /* explicitly mention what item is triggering the explosion */ pline("As you put %s inside, you are blasted by a magical explosion!", doname(obj)); /* did not actually insert obj yet */ if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE); obfree(obj, (struct obj *) 0); delete_contents(current_container); if (!floor_container) useup(current_container); else if (obj_here(current_container, u.ux, u.uy)) useupf(current_container, current_container->quan); else panic("in_container: bag not found."); losehp(d(6, 6), "magical explosion", KILLED_BY_AN); current_container = 0; /* baggone = TRUE; */ } if (current_container) { Strcpy(buf, the(xname(current_container))); You("put %s into %s.", doname(obj), buf); /* gold in container always needs to be added to credit */ if (floor_container && obj->oclass == COIN_CLASS) sellobj(obj, current_container->ox, current_container->oy); (void) add_to_container(current_container, obj); current_container->owt = weight(current_container); } /* gold needs this, and freeinv() many lines above may cause * the encumbrance to disappear from the status, so just always * update status immediately. */ bot(); return (current_container ? 1 : -1); } int ck_bag(obj) struct obj *obj; { return current_container && obj != current_container; } /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */ STATIC_PTR int out_container(obj) register struct obj *obj; { register struct obj *otmp; boolean is_gold = (obj->oclass == COIN_CLASS); int res, loadlev; long count; if (!current_container) { impossible(" no current_container?"); return -1; } else if (is_gold) { obj->owt = weight(obj); } if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 0; if (fatal_corpse_mistake(obj, FALSE)) return -1; count = obj->quan; if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0) return res; if (obj->quan != count && obj->otyp != LOADSTONE) obj = splitobj(obj, count); /* Remove the object from the list. */ obj_extract_self(obj); current_container->owt = weight(current_container); if (Icebox && !age_is_relative(obj)) { obj->age = monstermoves - obj->age; /* actual age */ if (obj->otyp == CORPSE) start_corpse_timeout(obj); } /* simulated point of time */ if (!obj->unpaid && !carried(current_container) && costly_spot(current_container->ox, current_container->oy)) { obj->ox = current_container->ox; obj->oy = current_container->oy; addtobill(obj, FALSE, FALSE, FALSE); } if (is_pick(obj)) pick_pick(obj); /* shopkeeper feedback */ otmp = addinv(obj); loadlev = near_capacity(); prinv(loadlev ? (loadlev < MOD_ENCUMBER ? "You have a little trouble removing" : "You have much trouble removing") : (char *) 0, otmp, count); if (is_gold) { bot(); /* update character's gold piece count immediately */ } return 1; } /* an object inside a cursed bag of holding is being destroyed */ STATIC_OVL long mbag_item_gone(held, item) int held; struct obj *item; { struct monst *shkp; long loss = 0L; if (item->dknown) pline("%s %s vanished!", Doname2(item), otense(item, "have")); else You("%s %s disappear!", Blind ? "notice" : "see", doname(item)); if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) { if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy)) loss = stolen_value(item, u.ux, u.uy, (boolean) shkp->mpeaceful, TRUE); } obfree(item, (struct obj *) 0); return loss; } STATIC_OVL void observe_quantum_cat(box) struct obj *box; { static NEARDATA const char sc[] = "Schroedinger's Cat"; struct obj *deadcat; struct monst *livecat; xchar ox, oy; box->spe = 0; /* box->owt will be updated below */ if (get_obj_location(box, &ox, &oy, 0)) box->ox = ox, box->oy = oy; /* in case it's being carried */ /* this isn't really right, since any form of observation (telepathic or monster/object/food detection) ought to force the determination of alive vs dead state; but basing it just on opening the box is much simpler to cope with */ livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT) : 0; if (livecat) { livecat->mpeaceful = 1; set_malign(livecat); if (!canspotmon(livecat)) You("think %s brushed your %s.", something, body_part(FOOT)); else pline("%s inside the box is still alive!", Monnam(livecat)); (void) christen_monst(livecat, sc); } else { deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT], box->ox, box->oy, sc); if (deadcat) { obj_extract_self(deadcat); (void) add_to_container(box, deadcat); } pline_The("%s inside the box is dead!", Hallucination ? rndmonnam(NULL) : "housecat"); } box->owt = weight(box); return; } #undef Icebox /* used by askchain() to check for magic bag explosion */ boolean container_gone(fn) int FDECL((*fn), (OBJ_P)); { /* result is only meaningful while use_container() is executing */ return ((fn == in_container || fn == out_container) && !current_container); } STATIC_OVL void explain_container_prompt() { static const char *const explaintext[] = { "Container actions:", "", " : -- Look: examine contents", " o -- Out: take things out", " i -- In: put things in", " b -- Both: first take things out, then put things in", " r -- Reversed: put things in, then take things out", " s -- Stash: put one item in", " q -- Quit: do nothing", " ? -- Help: display this text.", "", 0 }; const char *const *txtpp; winid win; /* "Do what with ? [:oibrsq or ?] (q)" */ if ((win = create_nhwindow(NHW_TEXT)) != WIN_ERR) { for (txtpp = explaintext; *txtpp; ++txtpp) putstr(win, 0, *txtpp); display_nhwindow(win, FALSE); destroy_nhwindow(win); } } boolean u_handsy() { if (nohands(youmonst.data)) { You("have no hands!"); /* not `body_part(HAND)' */ return FALSE; } else if (!freehand()) { You("have no free %s.", body_part(HAND)); return FALSE; } return TRUE; } static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; int use_container(objp, held) struct obj **objp; int held; { struct obj *curr, *otmp, *obj = *objp; boolean quantum_cat, cursed_mbag, loot_out, loot_in, loot_in_first, stash_one, inokay, outokay, outmaybe; char c, emptymsg[BUFSZ], qbuf[QBUFSZ], pbuf[QBUFSZ], xbuf[QBUFSZ]; int used = 0; emptymsg[0] = '\0'; if (!u_handsy()) return 0; if (obj->olocked) { pline("%s locked.", Tobjnam(obj, "are")); if (held) You("must put it down to unlock."); obj->lknown = 1; return 0; } else if (obj->otrapped) { if (held) You("open %s...", the(xname(obj))); obj->lknown = 1; (void) chest_trap(obj, HAND, FALSE); /* even if the trap fails, you've used up this turn */ if (multi >= 0) { /* in case we didn't become paralyzed */ nomul(-1); multi_reason = "opening a container"; nomovemsg = ""; } return 1; } obj->lknown = 1; current_container = obj; /* for use by in/out_container */ /* from here on out, all early returns go through containerdone */ /* check for Schroedinger's Cat */ quantum_cat = SchroedingersBox(current_container); if (quantum_cat) { observe_quantum_cat(current_container); used = 1; } /* sometimes toss objects if a cursed magic bag */ cursed_mbag = (Is_mbag(current_container) && current_container->cursed && Has_contents(current_container)); if (cursed_mbag) { long loss = 0L; for (curr = current_container->cobj; curr; curr = otmp) { otmp = curr->nobj; if (!rn2(13)) { obj_extract_self(curr); loss += mbag_item_gone(held, curr); used = 1; } } if (loss) You("owe %ld %s for lost merchandise.", loss, currency(loss)); current_container->owt = weight(current_container); } inokay = (invent != 0 && !(invent == current_container && !current_container->nobj)); outokay = Has_contents(current_container); if (!outokay) /* preformat the empty-container message */ Sprintf(emptymsg, "%s is %sempty.", Ysimple_name2(current_container), (quantum_cat || cursed_mbag) ? "now " : ""); /* * What-to-do prompt's list of possible actions: * always include the look-inside choice (':'); * include the take-out choice ('o') if container * has anything in it or if player doesn't yet know * that it's empty (latter can change on subsequent * iterations if player picks ':' response); * include the put-in choices ('i','s') if hero * carries any inventory (including gold); * include do-both when 'o' is available, even if * inventory is empty--taking out could alter that; * include do-both-reversed when 'i' is available, * even if container is empty--for similar reason; * always include the quit choice ('q'). * include the help choice (" or ?") if `cmdassist' * run-time option is set; * (Player can pick any of (o,i,b,r,s,?) even when * they're not listed among the available actions.) * * Do what with ? [:oibrsq or ?] (q) * or * is empty. Do what with it? [:irsq or ?] */ for (;;) { /* repeats if '?' or ":' gets chosen */ outmaybe = (outokay || !current_container->cknown); if (!outmaybe) (void) safe_qbuf(qbuf, (char *) 0, " is empty. Do what with it?", current_container, Yname2, Ysimple_name2, "This"); else (void) safe_qbuf(qbuf, "Do what with ", "?", current_container, yname, ysimple_name, "it"); /* ask player about what to do with this container */ if (flags.menu_style == MENU_FULL) { if (!inokay && !outmaybe) { /* nothing to take out, nothing to put in; trying to do both will yield proper feedback */ c = 'b'; } else { c = in_or_out_menu(qbuf, current_container, outmaybe, inokay, (used != 0)); } } else { /* TRADITIONAL, COMBINATION, or PARTIAL */ xbuf[0] = '\0'; /* list of extra acceptable responses */ Strcpy(pbuf, ":"); /* look inside */ Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */ Strcat(inokay ? pbuf : xbuf, "i"); /* put in */ Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */ Strcat(inokay ? pbuf : xbuf, "rs"); /* reversed, stash */ Strcat(pbuf, "q"); /* quit */ if (iflags.cmdassist) Strcat(pbuf, " or ?"); /* help */ else Strcat(xbuf, "?"); if (*xbuf) Strcat(strcat(pbuf, "\033"), xbuf); c = yn_function(qbuf, pbuf, 'q'); } /* FULL vs other modes */ if (c == '?') { explain_container_prompt(); } else if (c == ':') { /* note: will set obj->cknown */ if (!current_container->cknown) used = 1; /* gaining info */ container_contents(current_container, FALSE, FALSE, TRUE); } else break; } /* loop until something other than '?' or ':' is picked */ if (c == 'q') /* [not strictly needed; falling through works] */ goto containerdone; loot_out = (c == 'o' || c == 'b' || c == 'r'); loot_in = (c == 'i' || c == 'b' || c == 'r'); loot_in_first = (c == 'r'); /* both, reversed */ stash_one = (c == 's'); /* out-only or out before in */ if (loot_out && !loot_in_first) { if (!Has_contents(current_container)) { pline1(emptymsg); /* is empty. */ if (!current_container->cknown) used = 1; current_container->cknown = 1; } else { add_valid_menu_class(0); /* reset */ if (flags.menu_style == MENU_TRADITIONAL) used |= traditional_loot(FALSE); else used |= (menu_loot(0, FALSE) > 0); } } if ((loot_in || stash_one) && (!invent || (invent == current_container && !invent->nobj))) { You("don't have anything%s to %s.", invent ? " else" : "", stash_one ? "stash" : "put in"); loot_in = stash_one = FALSE; } /* * Gone: being nice about only selecting food if we know we are * putting things in an ice chest. */ if (loot_in) { add_valid_menu_class(0); /* reset */ if (flags.menu_style == MENU_TRADITIONAL) used |= traditional_loot(TRUE); else used |= (menu_loot(0, TRUE) > 0); } else if (stash_one) { /* put one item into container */ if ((otmp = getobj(stashable, "stash")) != 0) { if (in_container(otmp)) { used = 1; } else { /* couldn't put selected item into container for some reason; might need to undo splitobj() */ for (curr = invent; curr; curr = curr->nobj) if (curr->nobj == otmp) break; if (curr && curr->invlet == otmp->invlet) (void) merged(&curr, &otmp); } } } /* putting something in might have triggered magic bag explosion */ if (!current_container) loot_out = FALSE; /* out after in */ if (loot_out && loot_in_first) { if (!Has_contents(current_container)) { pline1(emptymsg); /* is empty. */ if (!current_container->cknown) used = 1; current_container->cknown = 1; } else { add_valid_menu_class(0); /* reset */ if (flags.menu_style == MENU_TRADITIONAL) used |= traditional_loot(FALSE); else used |= (menu_loot(0, FALSE) > 0); } } containerdone: if (used) { /* Not completely correct; if we put something in without knowing whatever was already inside, now we suddenly do. That can't be helped unless we want to track things item by item and then deal with containers whose contents are "partly known". */ if (current_container) current_container->cknown = 1; update_inventory(); } *objp = current_container; /* might have become null */ current_container = 0; /* avoid hanging on to stale pointer */ return used; } /* loot current_container (take things out or put things in), by prompting */ STATIC_OVL int traditional_loot(put_in) boolean put_in; { int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P)); struct obj **objlist; char selection[MAXOCLASSES + 1]; const char *action; boolean one_by_one, allflag; int used = 0, menu_on_request = 0; if (put_in) { action = "put in"; objlist = &invent; actionfunc = in_container; checkfunc = ck_bag; } else { action = "take out"; objlist = &(current_container->cobj); actionfunc = out_container; checkfunc = (int FDECL((*), (OBJ_P))) 0; } if (query_classes(selection, &one_by_one, &allflag, action, *objlist, FALSE, &menu_on_request)) { if (askchain(objlist, (one_by_one ? (char *) 0 : selection), allflag, actionfunc, checkfunc, 0, action)) used = 1; } else if (menu_on_request < 0) { used = (menu_loot(menu_on_request, put_in) > 0); } return used; } /* loot current_container (take things out or put things in), using a menu */ STATIC_OVL int menu_loot(retry, put_in) int retry; boolean put_in; { int n, i, n_looted = 0; boolean all_categories = TRUE, loot_everything = FALSE; char buf[BUFSZ]; const char *action = put_in ? "Put in" : "Take out"; struct obj *otmp, *otmp2; menu_item *pick_list; int mflags, res; long count; if (retry) { all_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { all_categories = FALSE; Sprintf(buf, "%s what type of objects?", action); mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN : ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN; n = query_category(buf, put_in ? invent : current_container->cobj, mflags, &pick_list, PICK_ANY); if (!n) return 0; for (i = 0; i < n; i++) { if (pick_list[i].item.a_int == 'A') loot_everything = TRUE; else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_categories = TRUE; else add_valid_menu_class(pick_list[i].item.a_int); } free((genericptr_t) pick_list); } if (loot_everything) { current_container->cknown = 1; for (otmp = current_container->cobj; otmp; otmp = otmp2) { otmp2 = otmp->nobj; res = out_container(otmp); if (res < 0) break; } } else { mflags = INVORDER_SORT; if (put_in && flags.invlet_constant) mflags |= USE_INVLET; if (!put_in) current_container->cknown = 1; Sprintf(buf, "%s what?", action); n = query_objlist(buf, put_in ? invent : current_container->cobj, mflags, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n) { n_looted = n; for (i = 0; i < n; i++) { otmp = pick_list[i].item.a_obj; count = pick_list[i].count; if (count > 0 && count < otmp->quan) { otmp = splitobj(otmp, count); /* special split case also handled by askchain() */ } res = put_in ? in_container(otmp) : out_container(otmp); if (res < 0) { if (!current_container) { /* otmp caused current_container to explode; both are now gone */ otmp = 0; /* and break loop */ } else if (otmp && otmp != pick_list[i].item.a_obj) { /* split occurred, merge again */ (void) merged(&pick_list[i].item.a_obj, &otmp); } break; } } free((genericptr_t) pick_list); } } return n_looted; } STATIC_OVL char in_or_out_menu(prompt, obj, outokay, inokay, alreadyused) const char *prompt; struct obj *obj; boolean outokay, inokay, alreadyused; { /* underscore is not a choice; it's used to skip element [0] */ static const char lootchars[] = "_:oibrsq", abc_chars[] = "_:abcdeq"; winid win; anything any; menu_item *pick_list; char buf[BUFSZ]; int n; const char *menuselector = flags.lootabc ? abc_chars : lootchars; any = zeroany; win = create_nhwindow(NHW_MENU); start_menu(win); any.a_int = 1; /* ':' */ Sprintf(buf, "Look inside %s", thesimpleoname(obj)); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_UNSELECTED); if (outokay) { any.a_int = 2; /* 'o' */ Sprintf(buf, "take %s out", something); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_UNSELECTED); } if (inokay) { any.a_int = 3; /* 'i' */ Sprintf(buf, "put %s in", something); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_UNSELECTED); } if (outokay) { any.a_int = 4; /* 'b' */ Sprintf(buf, "%stake out, then put in", inokay ? "both; " : ""); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_UNSELECTED); } if (inokay) { any.a_int = 5; /* 'r' */ Sprintf(buf, "%sput in, then take out", outokay ? "both reversed; " : ""); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_UNSELECTED); any.a_int = 6; /* 's' */ Sprintf(buf, "stash one item into %s", thesimpleoname(obj)); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_UNSELECTED); } any.a_int = 7; /* 'q' */ Strcpy(buf, alreadyused ? "done" : "do nothing"); add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf, MENU_SELECTED); end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n > 0) { n = pick_list[0].item.a_int; free((genericptr_t) pick_list); return lootchars[n]; /* :,o,i,b,r,s,q */ } return 'q'; /* quit */ } static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 }; /* #tip command -- empty container contents onto floor */ int dotip() { struct obj *cobj, *nobj; coord cc; int boxes; char c, buf[BUFSZ], qbuf[BUFSZ]; const char *spillage = 0; /* * doesn't require free hands; * limbs are needed to tip floor containers */ /* at present, can only tip things at current spot, not adjacent ones */ cc.x = u.ux, cc.y = u.uy; /* check floor container(s) first; at most one will be accessed */ if ((boxes = container_at(cc.x, cc.y, TRUE)) > 0) { Sprintf(buf, "You can't tip %s while carrying so much.", !flags.verbose ? "a container" : (boxes > 1) ? "one" : "it"); if (!check_capacity(buf) && able_to_loot(cc.x, cc.y, FALSE)) { if (boxes > 1 && (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested)) { /* use menu to pick a container to tip */ int n, i; winid win; anything any; menu_item *pick_list = NULL; struct obj dummyobj, *otmp; any = zeroany; win = create_nhwindow(NHW_MENU); start_menu(win); for (cobj = level.objects[cc.x][cc.y], i = 0; cobj; cobj = cobj->nexthere) if (Is_container(cobj)) { ++i; any.a_obj = cobj; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, doname(cobj), MENU_UNSELECTED); } if (invent) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); any.a_obj = &dummyobj; /* use 'i' for inventory unless there are so many containers that it's already being used */ i = (i <= 'i' - 'a' && !flags.lootabc) ? 'i' : 0; add_menu(win, NO_GLYPH, &any, i, 0, ATR_NONE, "tip something being carried", MENU_SELECTED); } end_menu(win, "Tip which container?"); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); /* * Deal with quirk of preselected item in pick-one menu: * n == 0 => picked preselected entry, toggling it off; * n == 1 => accepted preselected choice via SPACE or RETURN; * n == 2 => picked something other than preselected entry; * n == -1 => cancelled via ESC; */ otmp = (n <= 0) ? (struct obj *) 0 : pick_list[0].item.a_obj; if (n > 1 && otmp == &dummyobj) otmp = pick_list[1].item.a_obj; if (pick_list) free((genericptr_t) pick_list); if (otmp && otmp != &dummyobj) { tipcontainer(otmp); return 1; } if (n == -1) return 0; /* else pick-from-invent below */ } else { for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (!Is_container(cobj)) continue; c = ynq(safe_qbuf(qbuf, "There is ", " here, tip it?", cobj, doname, ansimpleoname, "container")); if (c == 'q') return 0; if (c == 'n') continue; tipcontainer(cobj); /* can only tip one container at a time */ return 1; } } } } /* either no floor container(s) or couldn't tip one or didn't tip any */ cobj = getobj(tippables, "tip"); if (!cobj) return 0; /* normal case */ if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) { tipcontainer(cobj); return 1; } /* assorted other cases */ if (Is_candle(cobj) && cobj->lamplit) { /* note "wax" even for tallow candles to avoid giving away info */ spillage = "wax"; } else if ((cobj->otyp == POT_OIL && cobj->lamplit) || (cobj->otyp == OIL_LAMP && cobj->age != 0L) || (cobj->otyp == MAGIC_LAMP && cobj->spe != 0)) { spillage = "oil"; /* todo: reduce potion's remaining burn timer or oil lamp's fuel */ } else if (cobj->otyp == CAN_OF_GREASE && cobj->spe > 0) { /* charged consumed below */ spillage = "grease"; } else if (cobj->otyp == FOOD_RATION || cobj->otyp == CRAM_RATION || cobj->otyp == LEMBAS_WAFER) { spillage = "crumbs"; } else if (cobj->oclass == VENOM_CLASS) { spillage = "venom"; } if (spillage) { buf[0] = '\0'; if (is_pool(u.ux, u.uy)) Sprintf(buf, " and gradually %s", vtense(spillage, "dissipate")); else if (is_lava(u.ux, u.uy)) Sprintf(buf, " and immediately %s away", vtense(spillage, "burn")); pline("Some %s %s onto the %s%s.", spillage, vtense(spillage, "spill"), surface(u.ux, u.uy), buf); /* shop usage message comes after the spill message */ if (cobj->otyp == CAN_OF_GREASE && cobj->spe > 0) { consume_obj_charge(cobj, TRUE); } /* something [useless] happened */ return 1; } /* anything not covered yet */ if (cobj->oclass == POTION_CLASS) /* can't pour potions... */ pline_The("%s %s securely sealed.", xname(cobj), otense(cobj, "are")); else if (cobj->otyp == STATUE) pline("Nothing interesting happens."); else pline1(nothing_happens); return 0; } STATIC_OVL void tipcontainer(box) struct obj *box; /* or bag */ { xchar ox = u.ux, oy = u.uy; /* #tip only works at hero's location */ boolean empty_it = FALSE, /* Shop handling: can't rely on the container's own unpaid or no_charge status because contents might differ with it. A carried container's contents will be flagged as unpaid or not, as appropriate, and need no special handling here. Items owned by the hero get sold to the shop without confirmation as with other uncontrolled drops. A floor container's contents will be marked no_charge if owned by hero, otherwise they're owned by the shop. By passing the contents through shop billing, they end up getting treated the same as in the carried case. We do so one item at a time instead of doing whole container at once to reduce the chance of exhausting shk's billing capacity. */ maybeshopgoods = !carried(box) && costly_spot(ox, oy); /* caveat: this assumes that cknown, lknown, olocked, and otrapped fields haven't been overloaded to mean something special for the non-standard "container" horn of plenty */ box->lknown = 1; if (box->olocked) { pline("It's locked."); } else if (box->otrapped) { /* we're not reaching inside but we're still handling it... */ (void) chest_trap(box, HAND, FALSE); /* even if the trap fails, you've used up this turn */ if (multi >= 0) { /* in case we didn't become paralyzed */ nomul(-1); multi_reason = "tipping a container"; nomovemsg = ""; } } else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) { boolean bag = box->otyp == BAG_OF_TRICKS; int old_spe = box->spe, seen = 0; if (maybeshopgoods && !box->no_charge) addtobill(box, FALSE, FALSE, TRUE); /* apply this bag/horn until empty or monster/object creation fails (if the latter occurs, force the former...) */ do { if (!(bag ? bagotricks(box, TRUE, &seen) : hornoplenty(box, TRUE))) break; } while (box->spe > 0); if (box->spe < old_spe) { if (bag) pline((seen == 0) ? "Nothing seems to happen." : (seen == 1) ? "A monster appears." : "Monsters appear!"); /* check_unpaid wants to see a non-zero charge count */ box->spe = old_spe; check_unpaid_usage(box, TRUE); box->spe = 0; /* empty */ box->cknown = 1; } if (maybeshopgoods && !box->no_charge) subfrombill(box, shop_keeper(*in_rooms(ox, oy, SHOPBASE))); } else if (SchroedingersBox(box)) { char yourbuf[BUFSZ]; observe_quantum_cat(box); if (!Has_contents(box)) /* evidently a live cat came out */ /* container type of "large box" is inferred */ pline("%sbox is now empty.", Shk_Your(yourbuf, box)); else /* holds cat corpse or other random stuff */ empty_it = TRUE; box->cknown = 1; } else if (!Has_contents(box)) { box->cknown = 1; pline("It's empty."); } else { empty_it = TRUE; } if (empty_it) { struct obj *otmp, *nobj; boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE), altarizing = IS_ALTAR(levl[ox][oy].typ), cursed_mbag = (Is_mbag(box) && box->cursed); int held = carried(box); long loss = 0L; if (u.uswallow) highdrop = altarizing = FALSE; box->cknown = 1; pline("%s out%c", box->cobj->nobj ? "Objects spill" : "An object spills", !(highdrop || altarizing) ? ':' : '.'); for (otmp = box->cobj; otmp; otmp = nobj) { nobj = otmp->nobj; obj_extract_self(otmp); if (cursed_mbag && !rn2(13)) { loss += mbag_item_gone(held, otmp); /* abbreviated drop format is no longer appropriate */ verbose = TRUE; continue; } if (maybeshopgoods) { addtobill(otmp, FALSE, FALSE, TRUE); iflags.suppress_price++; /* doname formatting */ } if (highdrop) { /* might break or fall down stairs; handles altars itself */ hitfloor(otmp); } else { if (altarizing) doaltarobj(otmp); else if (verbose) pline("%s %s to the %s.", Doname2(otmp), otense(otmp, "drop"), surface(ox, oy)); else pline("%s%c", doname(otmp), nobj ? ',' : '.'); dropy(otmp); } if (maybeshopgoods) iflags.suppress_price--; /* reset */ } if (loss) /* magic bag lost some shop goods */ You("owe %ld %s for lost merchandise.", loss, currency(loss)); box->owt = weight(box); /* mbag_item_gone() doesn't update this */ if (held) (void) encumber_msg(); } } /*pickup.c*/ nethack-3.6.0/src/pline.c0000664000076400007660000004107012606706527014214 0ustar paxedpaxed/* NetHack 3.6 pline.c $NHDT-Date: 1432512770 2015/05/25 00:12:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \ */ #include "hack.h" static boolean no_repeat = FALSE; static char prevmsg[BUFSZ]; static char *FDECL(You_buf, (int)); /*VARARGS1*/ /* Note that these declarations rely on knowledge of the internals * of the variable argument handling stuff in "tradstdc.h" */ #if defined(USE_STDARG) || defined(USE_VARARGS) static void FDECL(vpline, (const char *, va_list)); void pline VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, char *); vpline(line, VA_ARGS); VA_END(); } # ifdef USE_STDARG static void vpline(const char *line, va_list the_args) # else static void vpline(line, the_args) const char *line; va_list the_args; # endif #else /* USE_STDARG | USE_VARARG */ # define vpline pline void pline VA_DECL(const char *, line) #endif /* USE_STDARG | USE_VARARG */ { /* start of vpline() or of nested block in USE_OLDARG's pline() */ char pbuf[3 * BUFSZ]; int ln; xchar msgtyp; /* Do NOT use VA_START and VA_END in here... see above */ if (!line || !*line) return; #ifdef HANGUPHANDLING if (program_state.done_hup) return; #endif if (program_state.wizkit_wishing) return; if (index(line, '%')) { Vsprintf(pbuf, line, VA_ARGS); line = pbuf; } if ((ln = (int) strlen(line)) > BUFSZ - 1) { if (line != pbuf) /* no '%' was present */ (void) strncpy(pbuf, line, BUFSZ - 1); /* caveat: unterminated */ /* truncate, preserving the final 3 characters: "___ extremely long text" -> "___ extremely l...ext" (this may be suboptimal if overflow is less than 3) */ (void) strncpy(pbuf + BUFSZ - 1 - 6, "...", 3); /* avoid strncpy; buffers could overlap if excess is small */ pbuf[BUFSZ - 1 - 3] = line[ln - 3]; pbuf[BUFSZ - 1 - 2] = line[ln - 2]; pbuf[BUFSZ - 1 - 1] = line[ln - 1]; pbuf[BUFSZ - 1] = '\0'; line = pbuf; } if (!iflags.window_inited) { raw_print(line); iflags.last_msg = PLNMSG_UNKNOWN; return; } #ifndef MAC if (no_repeat && !strcmp(line, toplines)) return; #endif /* MAC */ if (vision_full_recalc) vision_recalc(0); if (u.ux) flush_screen(1); /* %% */ msgtyp = msgtype_type(line); if (msgtyp == MSGTYP_NOSHOW) return; if (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg)) return; putstr(WIN_MESSAGE, 0, line); /* this gets cleared after every pline message */ iflags.last_msg = PLNMSG_UNKNOWN; strncpy(prevmsg, line, BUFSZ); if (msgtyp == MSGTYP_STOP) display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */ #if !(defined(USE_STDARG) || defined(USE_VARARGS)) /* provide closing brace for the nested block which immediately follows USE_OLDARGS's VA_DECL() */ VA_END(); #endif } /*VARARGS1*/ void Norep VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, const char *); no_repeat = TRUE; vpline(line, VA_ARGS); no_repeat = FALSE; VA_END(); return; } /* work buffer for You(), &c and verbalize() */ static char *you_buf = 0; static int you_buf_siz = 0; static char * You_buf(siz) int siz; { if (siz > you_buf_siz) { if (you_buf) free((genericptr_t) you_buf); you_buf_siz = siz + 10; you_buf = (char *) alloc((unsigned) you_buf_siz); } return you_buf; } void free_youbuf() { if (you_buf) free((genericptr_t) you_buf), you_buf = (char *) 0; you_buf_siz = 0; } /* `prefix' must be a string literal, not a pointer */ #define YouPrefix(pointer, prefix, text) \ Strcpy((pointer = You_buf((int) (strlen(text) + sizeof prefix))), prefix) #define YouMessage(pointer, prefix, text) \ strcat((YouPrefix(pointer, prefix, text), pointer), text) /*VARARGS1*/ void You VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "You ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void Your VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "Your ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_feel VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); if (Unaware) YouPrefix(tmp, "You dream that you feel ", line); else YouPrefix(tmp, "You feel ", line); vpline(strcat(tmp, line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_cant VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "You can't ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void pline_The VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "The ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void There VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "There ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_hear VA_DECL(const char *, line) { char *tmp; if (Deaf || !flags.acoustics) return; VA_START(line); VA_INIT(line, const char *); if (Underwater) YouPrefix(tmp, "You barely hear ", line); else if (Unaware) YouPrefix(tmp, "You dream that you hear ", line); else YouPrefix(tmp, "You hear ", line); vpline(strcat(tmp, line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_see VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); if (Unaware) YouPrefix(tmp, "You dream that you see ", line); else if (Blind) /* caller should have caught this... */ YouPrefix(tmp, "You sense ", line); else YouPrefix(tmp, "You see ", line); vpline(strcat(tmp, line), VA_ARGS); VA_END(); } /* Print a message inside double-quotes. * The caller is responsible for checking deafness. * Gods can speak directly to you in spite of deafness. */ /*VARARGS1*/ void verbalize VA_DECL(const char *, line) { char *tmp; VA_START(line); VA_INIT(line, const char *); tmp = You_buf((int) strlen(line) + sizeof "\"\""); Strcpy(tmp, "\""); Strcat(tmp, line); Strcat(tmp, "\""); vpline(tmp, VA_ARGS); VA_END(); } /*VARARGS1*/ /* Note that these declarations rely on knowledge of the internals * of the variable argument handling stuff in "tradstdc.h" */ #if defined(USE_STDARG) || defined(USE_VARARGS) static void FDECL(vraw_printf, (const char *, va_list)); void raw_printf VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, char *); vraw_printf(line, VA_ARGS); VA_END(); } # ifdef USE_STDARG static void vraw_printf(const char *line, va_list the_args) # else static void vraw_printf(line, the_args) const char *line; va_list the_args; # endif #else /* USE_STDARG | USE_VARARG */ void raw_printf VA_DECL(const char *, line) #endif { char pbuf[3 * BUFSZ]; int ln; /* Do NOT use VA_START and VA_END in here... see above */ if (index(line, '%')) { Vsprintf(pbuf, line, VA_ARGS); line = pbuf; } if ((ln = (int) strlen(line)) > BUFSZ - 1) { if (line != pbuf) line = strncpy(pbuf, line, BUFSZ - 1); /* unlike pline, we don't futz around to keep last few chars */ pbuf[BUFSZ - 1] = '\0'; /* terminate strncpy or truncate vsprintf */ } raw_print(line); #if !(defined(USE_STDARG) || defined(USE_VARARGS)) VA_END(); /* (see vpline) */ #endif } /*VARARGS1*/ void impossible VA_DECL(const char *, s) { char pbuf[2 * BUFSZ]; VA_START(s); VA_INIT(s, const char *); if (program_state.in_impossible) panic("impossible called impossible"); program_state.in_impossible = 1; Vsprintf(pbuf, s, VA_ARGS); pbuf[BUFSZ - 1] = '\0'; /* sanity */ paniclog("impossible", pbuf); pline("%s", pbuf); pline("Program in disorder - perhaps you'd better #quit."); program_state.in_impossible = 0; VA_END(); } const char * align_str(alignment) aligntyp alignment; { switch ((int) alignment) { case A_CHAOTIC: return "chaotic"; case A_NEUTRAL: return "neutral"; case A_LAWFUL: return "lawful"; case A_NONE: return "unaligned"; } return "unknown"; } void mstatusline(mtmp) register struct monst *mtmp; { aligntyp alignment = mon_aligntyp(mtmp); char info[BUFSZ], monnambuf[BUFSZ]; info[0] = 0; if (mtmp->mtame) { Strcat(info, ", tame"); if (wizard) { Sprintf(eos(info), " (%d", mtmp->mtame); if (!mtmp->isminion) Sprintf(eos(info), "; hungry %ld; apport %d", EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport); Strcat(info, ")"); } } else if (mtmp->mpeaceful) Strcat(info, ", peaceful"); if (mtmp->cham >= LOW_PM && mtmp->data != &mons[mtmp->cham]) /* don't reveal the innate form (chameleon, vampire, &c), just expose the fact that this current form isn't it */ Strcat(info, ", shapechanger"); /* pets eating mimic corpses mimic while eating, so this comes first */ if (mtmp->meating) Strcat(info, ", eating"); /* a stethoscope exposes mimic before getting here so this won't be relevant for it, but wand of probing doesn't */ if (mtmp->m_ap_type) Sprintf(eos(info), ", mimicking %s", (mtmp->m_ap_type == M_AP_FURNITURE) ? an(defsyms[mtmp->mappearance].explanation) : (mtmp->m_ap_type == M_AP_OBJECT) ? ((mtmp->mappearance == GOLD_PIECE) ? "gold" : an(simple_typename(mtmp->mappearance))) : (mtmp->m_ap_type == M_AP_MONSTER) ? an(mons[mtmp->mappearance].mname) : something); /* impossible... */ if (mtmp->mcan) Strcat(info, ", cancelled"); if (mtmp->mconf) Strcat(info, ", confused"); if (mtmp->mblinded || !mtmp->mcansee) Strcat(info, ", blind"); if (mtmp->mstun) Strcat(info, ", stunned"); if (mtmp->msleeping) Strcat(info, ", asleep"); #if 0 /* unfortunately mfrozen covers temporary sleep and being busy \ (donning armor, for instance) as well as paralysis */ else if (mtmp->mfrozen) Strcat(info, ", paralyzed"); #else else if (mtmp->mfrozen || !mtmp->mcanmove) Strcat(info, ", can't move"); #endif /* [arbitrary reason why it isn't moving] */ else if (mtmp->mstrategy & STRAT_WAITMASK) Strcat(info, ", meditating"); if (mtmp->mflee) Strcat(info, ", scared"); if (mtmp->mtrapped) Strcat(info, ", trapped"); if (mtmp->mspeed) Strcat(info, mtmp->mspeed == MFAST ? ", fast" : mtmp->mspeed == MSLOW ? ", slow" : ", ???? speed"); if (mtmp->mundetected) Strcat(info, ", concealed"); if (mtmp->minvis) Strcat(info, ", invisible"); if (mtmp == u.ustuck) Strcat(info, sticks(youmonst.data) ? ", held by you" : !u.uswallow ? ", holding you" : attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_DGST) ? ", digesting you" : is_animal(u.ustuck->data) ? ", swallowing you" : ", engulfing you"); if (mtmp == u.usteed) Strcat(info, ", carrying you"); /* avoid "Status of the invisible newt ..., invisible" */ /* and unlike a normal mon_nam, use "saddled" even if it has a name */ Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0, (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE)); pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", monnambuf, align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax, find_mac(mtmp), info); } void ustatusline() { char info[BUFSZ]; info[0] = '\0'; if (Sick) { Strcat(info, ", dying from"); if (u.usick_type & SICK_VOMITABLE) Strcat(info, " food poisoning"); if (u.usick_type & SICK_NONVOMITABLE) { if (u.usick_type & SICK_VOMITABLE) Strcat(info, " and"); Strcat(info, " illness"); } } if (Stoned) Strcat(info, ", solidifying"); if (Slimed) Strcat(info, ", becoming slimy"); if (Strangled) Strcat(info, ", being strangled"); if (Vomiting) Strcat(info, ", nauseated"); /* !"nauseous" */ if (Confusion) Strcat(info, ", confused"); if (Blind) { Strcat(info, ", blind"); if (u.ucreamed) { if ((long) u.ucreamed < Blinded || Blindfolded || !haseyes(youmonst.data)) Strcat(info, ", cover"); Strcat(info, "ed by sticky goop"); } /* note: "goop" == "glop"; variation is intentional */ } if (Stunned) Strcat(info, ", stunned"); if (!u.usteed && Wounded_legs) { const char *what = body_part(LEG); if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES) what = makeplural(what); Sprintf(eos(info), ", injured %s", what); } if (Glib) Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND))); if (u.utrap) Strcat(info, ", trapped"); if (Fast) Strcat(info, Very_fast ? ", very fast" : ", fast"); if (u.uundetected) Strcat(info, ", concealed"); if (Invis) Strcat(info, ", invisible"); if (u.ustuck) { if (sticks(youmonst.data)) Strcat(info, ", holding "); else Strcat(info, ", held by "); Strcat(info, mon_nam(u.ustuck)); } pline("Status of %s (%s%s): Level %d HP %d(%d) AC %d%s.", plname, (u.ualign.record >= 20) ? "piously " : (u.ualign.record > 13) ? "devoutly " : (u.ualign.record > 8) ? "fervently " : (u.ualign.record > 3) ? "stridently " : (u.ualign.record == 3) ? "" : (u.ualign.record >= 1) ? "haltingly " : (u.ualign.record == 0) ? "nominally " : "insufficiently ", align_str(u.ualign.type), Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp, Upolyd ? u.mhmax : u.uhpmax, u.uac, info); } void self_invis_message() { pline("%s %s.", Hallucination ? "Far out, man! You" : "Gee! All of a sudden, you", See_invisible ? "can see right through yourself" : "can't see yourself"); } void pudding_merge_message(otmp, otmp2) struct obj *otmp; struct obj *otmp2; { boolean visible = cansee(otmp->ox, otmp->oy) || cansee(otmp2->ox, otmp2->oy); boolean onfloor = otmp->where == OBJ_FLOOR || otmp2->where == OBJ_FLOOR; boolean inpack = carried(otmp) || carried(otmp2); /* the player will know something happened inside his own inventory */ if ((!Blind && visible) || inpack) { if (Hallucination) { if (onfloor) { You_see("parts of the floor melting!"); } else if (inpack) { Your("pack reaches out and grabs something!"); } /* even though we can see where they should be, * they'll be out of our view (minvent or container) * so don't actually show anything */ } else if (onfloor || inpack) { pline("The %s coalesce%s.", makeplural(obj_typename(otmp->otyp)), inpack ? " inside your pack" : ""); } } else { You_hear("a faint sloshing sound."); } } /*pline.c*/ nethack-3.6.0/src/polyself.c0000664000076400007660000017276012625515645014755 0ustar paxedpaxed/* NetHack 3.6 polyself.c $NHDT-Date: 1448496566 2015/11/26 00:09:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.104 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ /* * Polymorph self routine. * * Note: the light source handling code assumes that both youmonst.m_id * and youmonst.mx will always remain 0 when it handles the case of the * player polymorphed into a light-emitting monster. * * Transformation sequences: * /-> polymon poly into monster form * polyself = * \-> newman -> polyman fail to poly, get human form * * rehumanize -> polyman return to original form * * polymon (called directly) usually golem petrification */ #include "hack.h" STATIC_DCL void FDECL(check_strangling, (BOOLEAN_P)); STATIC_DCL void FDECL(polyman, (const char *, const char *)); STATIC_DCL void NDECL(break_armor); STATIC_DCL void FDECL(drop_weapon, (int)); STATIC_DCL void NDECL(uunstick); STATIC_DCL int FDECL(armor_to_dragon, (int)); STATIC_DCL void NDECL(newman); STATIC_DCL boolean FDECL(polysense, (struct permonst *)); STATIC_VAR const char no_longer_petrify_resistant[] = "No longer petrify-resistant, you"; /* controls whether taking on new form or becoming new man can also change sex (ought to be an arg to polymon() and newman() instead) */ STATIC_VAR int sex_change_ok = 0; /* update the youmonst.data structure pointer and intrinsics */ void set_uasmon() { struct permonst *mdat = &mons[u.umonnum]; set_mon_data(&youmonst, mdat, 0); #define PROPSET(PropIndx, ON) \ do { \ if (ON) \ u.uprops[PropIndx].intrinsic |= FROMFORM; \ else \ u.uprops[PropIndx].intrinsic &= ~FROMFORM; \ } while (0) PROPSET(FIRE_RES, resists_fire(&youmonst)); PROPSET(COLD_RES, resists_cold(&youmonst)); PROPSET(SLEEP_RES, resists_sleep(&youmonst)); PROPSET(DISINT_RES, resists_disint(&youmonst)); PROPSET(SHOCK_RES, resists_elec(&youmonst)); PROPSET(POISON_RES, resists_poison(&youmonst)); PROPSET(ACID_RES, resists_acid(&youmonst)); PROPSET(STONE_RES, resists_ston(&youmonst)); { /* resists_drli() takes wielded weapon into account; suppress it */ struct obj *save_uwep = uwep; uwep = 0; PROPSET(DRAIN_RES, resists_drli(&youmonst)); uwep = save_uwep; } /* resists_magm() takes wielded, worn, and carried equipment into into account; cheat and duplicate its monster-specific part */ PROPSET(ANTIMAGIC, (dmgtype(mdat, AD_MAGM) || mdat == &mons[PM_BABY_GRAY_DRAGON] || dmgtype(mdat, AD_RBRE))); PROPSET(SICK_RES, (mdat->mlet == S_FUNGUS || mdat == &mons[PM_GHOUL])); PROPSET(STUNNED, (mdat == &mons[PM_STALKER] || is_bat(mdat))); PROPSET(HALLUC_RES, dmgtype(mdat, AD_HALU)); PROPSET(SEE_INVIS, perceives(mdat)); PROPSET(TELEPAT, telepathic(mdat)); PROPSET(INFRAVISION, infravision(mdat)); PROPSET(INVIS, pm_invisible(mdat)); PROPSET(TELEPORT, can_teleport(mdat)); PROPSET(TELEPORT_CONTROL, control_teleport(mdat)); PROPSET(LEVITATION, is_floater(mdat)); PROPSET(FLYING, is_flyer(mdat)); PROPSET(SWIMMING, is_swimmer(mdat)); /* [don't touch MAGICAL_BREATHING here; both Amphibious and Breathless key off of it but include different monster forms...] */ PROPSET(PASSES_WALLS, passes_walls(mdat)); PROPSET(REGENERATION, regenerates(mdat)); PROPSET(REFLECTING, (mdat == &mons[PM_SILVER_DRAGON])); float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ #undef PROPSET #ifdef STATUS_VIA_WINDOWPORT status_initialize(REASSESS_ONLY); #endif } /* Levitation overrides Flying; set or clear BFlying|I_SPECIAL */ void float_vs_flight() { /* floating overrides flight; normally float_up() and float_down() handle this, but sometimes they're skipped */ if (HLevitation || ELevitation) BFlying |= I_SPECIAL; else BFlying &= ~I_SPECIAL; } /* for changing into form that's immune to strangulation */ STATIC_OVL void check_strangling(on) boolean on; { /* on -- maybe resume strangling */ if (on) { /* when Strangled is already set, polymorphing from one vulnerable form into another causes the counter to be reset */ if (uamul && uamul->otyp == AMULET_OF_STRANGULATION && can_be_strangled(&youmonst)) { Your("%s %s your %s!", simpleonames(uamul), Strangled ? "still constricts" : "begins constricting", body_part(NECK)); /* "throat" */ Strangled = 6L; makeknown(AMULET_OF_STRANGULATION); } /* off -- maybe block strangling */ } else { if (Strangled && !can_be_strangled(&youmonst)) { Strangled = 0L; You("are no longer being strangled."); } } } /* make a (new) human out of the player */ STATIC_OVL void polyman(fmt, arg) const char *fmt, *arg; { boolean sticky = (sticks(youmonst.data) && u.ustuck && !u.uswallow), was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT); boolean was_blind = !!Blind; if (Upolyd) { u.acurr = u.macurr; /* restore old attribs */ u.amax = u.mamax; u.umonnum = u.umonster; flags.female = u.mfemale; } set_uasmon(); u.mh = u.mhmax = 0; u.mtimedone = 0; skinback(FALSE); u.uundetected = 0; if (sticky) uunstick(); find_ac(); if (was_mimicking) { if (multi < 0) unmul(""); youmonst.m_ap_type = M_AP_NOTHING; } newsym(u.ux, u.uy); You(fmt, arg); /* check whether player foolishly genocided self while poly'd */ if ((mvitals[urole.malenum].mvflags & G_GENOD) || (urole.femalenum != NON_PM && (mvitals[urole.femalenum].mvflags & G_GENOD)) || (mvitals[urace.malenum].mvflags & G_GENOD) || (urace.femalenum != NON_PM && (mvitals[urace.femalenum].mvflags & G_GENOD))) { /* intervening activity might have clobbered genocide info */ struct kinfo *kptr = find_delayed_killer(POLYMORPH); if (kptr != (struct kinfo *) 0 && kptr->name[0]) { killer.format = kptr->format; Strcpy(killer.name, kptr->name); } else { killer.format = KILLED_BY; Strcpy(killer.name, "self-genocide"); } dealloc_killer(kptr); done(GENOCIDED); } if (u.twoweap && !could_twoweap(youmonst.data)) untwoweapon(); if (u.utraptype == TT_PIT && u.utrap) { u.utrap = rn1(6, 2); /* time to escape resets */ } if (was_blind && !Blind) { /* reverting from eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } check_strangling(TRUE); if (!Levitation && !u.ustuck && is_pool_or_lava(u.ux, u.uy)) spoteffects(TRUE); see_monsters(); } void change_sex() { /* setting u.umonster for caveman/cavewoman or priest/priestess swap unintentionally makes `Upolyd' appear to be true */ boolean already_polyd = (boolean) Upolyd; /* Some monsters are always of one sex and their sex can't be changed; * Succubi/incubi can change, but are handled below. * * !already_polyd check necessary because is_male() and is_female() * are true if the player is a priest/priestess. */ if (!already_polyd || (!is_male(youmonst.data) && !is_female(youmonst.data) && !is_neuter(youmonst.data))) flags.female = !flags.female; if (already_polyd) /* poly'd: also change saved sex */ u.mfemale = !u.mfemale; max_rank_sz(); /* [this appears to be superfluous] */ if ((already_polyd ? u.mfemale : flags.female) && urole.name.f) Strcpy(pl_character, urole.name.f); else Strcpy(pl_character, urole.name.m); u.umonster = ((already_polyd ? u.mfemale : flags.female) && urole.femalenum != NON_PM) ? urole.femalenum : urole.malenum; if (!already_polyd) { u.umonnum = u.umonster; } else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) { flags.female = !flags.female; /* change monster type to match new sex */ u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS; set_uasmon(); } } STATIC_OVL void newman() { int i, oldlvl, newlvl, hpmax, enmax; oldlvl = u.ulevel; newlvl = oldlvl + rn1(5, -2); /* new = old + {-2,-1,0,+1,+2} */ if (newlvl > 127 || newlvl < 1) { /* level went below 0? */ goto dead; /* old level is still intact (in case of lifesaving) */ } if (newlvl > MAXULEV) newlvl = MAXULEV; /* If your level goes down, your peak level goes down by the same amount so that you can't simply use blessed full healing to undo the decrease. But if your level goes up, your peak level does *not* undergo the same adjustment; you might end up losing out on the chance to regain some levels previously lost to other causes. */ if (newlvl < oldlvl) u.ulevelmax -= (oldlvl - newlvl); if (u.ulevelmax < newlvl) u.ulevelmax = newlvl; u.ulevel = newlvl; if (sex_change_ok && !rn2(10)) change_sex(); adjabil(oldlvl, (int) u.ulevel); reset_rndmonst(NON_PM); /* new monster generation criteria */ /* random experience points for the new experience level */ u.uexp = rndexp(FALSE); /* set up new attribute points (particularly Con) */ redist_attr(); /* * New hit points: * remove level-gain based HP from any extra HP accumulated * (the "extra" might actually be negative); * modify the extra, retaining {80%, 90%, 100%, or 110%}; * add in newly generated set of level-gain HP. * * (This used to calculate new HP in direct proportion to old HP, * but that was subject to abuse: accumulate a large amount of * extra HP, drain level down to 1, then polyself to level 2 or 3 * [lifesaving capability needed to handle level 0 and -1 cases] * and the extra got multiplied by 2 or 3. Repeat the level * drain and polyself steps until out of lifesaving capability.) */ hpmax = u.uhpmax; for (i = 0; i < oldlvl; i++) hpmax -= (int) u.uhpinc[i]; /* hpmax * rn1(4,8) / 10; 0.95*hpmax on average */ hpmax = rounddiv((long) hpmax * (long) rn1(4, 8), 10); for (i = 0; (u.ulevel = i) < newlvl; i++) hpmax += newhp(); if (hpmax < u.ulevel) hpmax = u.ulevel; /* min of 1 HP per level */ /* retain same proportion for current HP; u.uhp * hpmax / u.uhpmax */ u.uhp = rounddiv((long) u.uhp * (long) hpmax, u.uhpmax); u.uhpmax = hpmax; /* * Do the same for spell power. */ enmax = u.uenmax; for (i = 0; i < oldlvl; i++) enmax -= (int) u.ueninc[i]; enmax = rounddiv((long) enmax * (long) rn1(4, 8), 10); for (i = 0; (u.ulevel = i) < newlvl; i++) enmax += newpw(); if (enmax < u.ulevel) enmax = u.ulevel; u.uen = rounddiv((long) u.uen * (long) enmax, ((u.uenmax < 1) ? 1 : u.uenmax)); u.uenmax = enmax; /* [should alignment record be tweaked too?] */ u.uhunger = rn1(500, 500); if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL); if (Stoned) make_stoned(0L, (char *) 0, 0, (char *) 0); if (u.uhp <= 0) { if (Polymorph_control) { /* even when Stunned || Unaware */ if (u.uhp <= 0) u.uhp = 1; } else { dead: /* we come directly here if their experience level went to 0 or less */ Your("new form doesn't seem healthy enough to survive."); killer.format = KILLED_BY_AN; Strcpy(killer.name, "unsuccessful polymorph"); done(DIED); newuhs(FALSE); (void) polysense(youmonst.data); return; /* lifesaved */ } } newuhs(FALSE); polyman("feel like a new %s!", /* use saved gender we're about to revert to, not current */ (u.mfemale && urace.individual.f) ? urace.individual.f : (urace.individual.m) ? urace.individual.m : urace.noun); if (Slimed) { Your("body transforms, but there is still slime on you."); make_slimed(10L, (const char *) 0); } (void) polysense(youmonst.data); context.botl = 1; see_monsters(); (void) encumber_msg(); retouch_equipment(2); if (!uarmg) selftouch(no_longer_petrify_resistant); } void polyself(psflags) int psflags; { char buf[BUFSZ]; int old_light, new_light, mntmp, class, tryct; boolean forcecontrol = (psflags == 1), monsterpoly = (psflags == 2), draconian = (uarm && Is_dragon_armor(uarm)), iswere = (u.ulycn >= LOW_PM), isvamp = is_vampire(youmonst.data), controllable_poly = Polymorph_control && !(Stunned || Unaware); if (Unchanging) { pline("You fail to transform!"); return; } /* being Stunned|Unaware doesn't negate this aspect of Poly_control */ if (!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) { if (rn2(20) > ACURR(A_CON)) { You1(shudder_for_moment); losehp(rnd(30), "system shock", KILLED_BY_AN); exercise(A_CON, FALSE); return; } } old_light = emits_light(youmonst.data); mntmp = NON_PM; if (monsterpoly && isvamp) goto do_vampyr; if (controllable_poly || forcecontrol) { tryct = 5; do { mntmp = NON_PM; getlin("Become what kind of monster? [type the name]", buf); (void) mungspaces(buf); if (*buf == '\033') { /* user is cancelling controlled poly */ if (forcecontrol) { /* wizard mode #polyself */ pline1(Never_mind); return; } Strcpy(buf, "*"); /* resort to random */ } if (!strcmp(buf, "*") || !strcmp(buf, "random")) { /* explicitly requesting random result */ tryct = 0; /* will skip thats_enough_tries */ continue; /* end do-while(--tryct > 0) loop */ } class = 0; mntmp = name_to_mon(buf); if (mntmp < LOW_PM) { by_class: class = name_to_monclass(buf, &mntmp); if (class && mntmp == NON_PM) mntmp = mkclass_poly(class); } if (mntmp < LOW_PM) { if (!class) pline("I've never heard of such monsters."); else You_cant("polymorph into any of those."); } else if (iswere && (were_beastie(mntmp) == u.ulycn || mntmp == counter_were(u.ulycn) || (Upolyd && mntmp == PM_HUMAN))) { goto do_shift; /* Note: humans are illegal as monsters, but an * illegal monster forces newman(), which is what we * want if they specified a human.... */ } else if (!polyok(&mons[mntmp]) && !(mntmp == PM_HUMAN || your_race(&mons[mntmp]) || mntmp == urole.malenum || mntmp == urole.femalenum)) { const char *pm_name; /* mkclass_poly() can pick a !polyok() candidate; if so, usually try again */ if (class) { if (rn2(3) || --tryct > 0) goto by_class; /* no retries left; put one back on counter so that end of loop decrement will yield 0 and trigger thats_enough_tries message */ ++tryct; } pm_name = mons[mntmp].mname; if (the_unique_pm(&mons[mntmp])) pm_name = the(pm_name); else if (!type_is_pname(&mons[mntmp])) pm_name = an(pm_name); You_cant("polymorph into %s.", pm_name); } else break; } while (--tryct > 0); if (!tryct) pline1(thats_enough_tries); /* allow skin merging, even when polymorph is controlled */ if (draconian && (tryct <= 0 || mntmp == armor_to_dragon(uarm->otyp))) goto do_merge; if (isvamp && (tryct <= 0 || mntmp == PM_WOLF || mntmp == PM_FOG_CLOUD || is_bat(&mons[mntmp]))) goto do_vampyr; } else if (draconian || iswere || isvamp) { /* special changes that don't require polyok() */ if (draconian) { do_merge: mntmp = armor_to_dragon(uarm->otyp); if (!(mvitals[mntmp].mvflags & G_GENOD)) { /* allow G_EXTINCT */ if (Is_dragon_scales(uarm)) { /* dragon scales remain intact as uskin */ You("merge with your scaly armor."); } else { /* dragon scale mail */ /* d.scale mail first reverts to scales */ char *p, *dsmail; /* similar to noarmor(invent.c), shorten to " scale mail" */ dsmail = strcpy(buf, simpleonames(uarm)); if ((p = strstri(dsmail, " dragon ")) != 0) while ((p[1] = p[8]) != '\0') ++p; /* tricky phrasing; dragon scale mail is singular, dragon scales are plural */ Your("%s reverts to scales as you merge with them.", dsmail); /* uarm->spe enchantment remains unchanged; re-converting scales to mail poses risk of evaporation due to over enchanting */ uarm->otyp += GRAY_DRAGON_SCALES - GRAY_DRAGON_SCALE_MAIL; uarm->dknown = 1; context.botl = 1; /* AC is changing */ } uskin = uarm; uarm = (struct obj *) 0; /* save/restore hack */ uskin->owornmask |= I_SPECIAL; update_inventory(); } } else if (iswere) { do_shift: if (Upolyd && were_beastie(mntmp) != u.ulycn) mntmp = PM_HUMAN; /* Illegal; force newman() */ else mntmp = u.ulycn; } else if (isvamp) { do_vampyr: if (mntmp < LOW_PM || (mons[mntmp].geno & G_UNIQ)) mntmp = (youmonst.data != &mons[PM_VAMPIRE] && !rn2(10)) ? PM_WOLF : !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; if (controllable_poly) { Sprintf(buf, "Become %s?", an(mons[mntmp].mname)); if (yn(buf) != 'y') return; } } /* if polymon fails, "you feel" message has been given so don't follow up with another polymon or newman; sex_change_ok left disabled here */ if (mntmp == PM_HUMAN) newman(); /* werecritter */ else (void) polymon(mntmp); goto made_change; /* maybe not, but this is right anyway */ } if (mntmp < LOW_PM) { tryct = 200; do { /* randomly pick an "ordinary" monster */ mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM); if (polyok(&mons[mntmp]) && !is_placeholder(&mons[mntmp])) break; } while (--tryct > 0); } /* The below polyok() fails either if everything is genocided, or if * we deliberately chose something illegal to force newman(). */ sex_change_ok++; if (!polyok(&mons[mntmp]) || (!forcecontrol && !rn2(5)) || your_race(&mons[mntmp])) { newman(); } else { (void) polymon(mntmp); } sex_change_ok--; /* reset */ made_change: new_light = emits_light(youmonst.data); if (old_light != new_light) { if (old_light) del_light_source(LS_MONSTER, monst_to_any(&youmonst)); if (new_light == 1) ++new_light; /* otherwise it's undetectable */ if (new_light) new_light_source(u.ux, u.uy, new_light, LS_MONSTER, monst_to_any(&youmonst)); } } /* (try to) make a mntmp monster out of the player; returns 1 if polymorph successful */ int polymon(mntmp) int mntmp; { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_blind = !!Blind, dochange = FALSE; int mlvl; if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ You_feel("rather %s-ish.", mons[mntmp].mname); exercise(A_WIS, TRUE); return 0; } /* KMH, conduct */ u.uconduct.polyselfs++; /* exercise used to be at the very end but only Wis was affected there since the polymorph was always in effect by then */ exercise(A_CON, FALSE); exercise(A_WIS, TRUE); if (!Upolyd) { /* Human to monster; save human stats */ u.macurr = u.acurr; u.mamax = u.amax; u.mfemale = flags.female; } else { /* Monster to monster; restore human stats, to be * immediately changed to provide stats for the new monster */ u.acurr = u.macurr; u.amax = u.mamax; flags.female = u.mfemale; } /* if stuck mimicking gold, stop immediately */ if (multi < 0 && youmonst.m_ap_type == M_AP_OBJECT && youmonst.data->mlet != S_MIMIC) unmul(""); /* if becoming a non-mimic, stop mimicking anything */ if (mons[mntmp].mlet != S_MIMIC) { /* as in polyman() */ youmonst.m_ap_type = M_AP_NOTHING; } if (is_male(&mons[mntmp])) { if (flags.female) dochange = TRUE; } else if (is_female(&mons[mntmp])) { if (!flags.female) dochange = TRUE; } else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) { if (sex_change_ok && !rn2(10)) dochange = TRUE; } if (dochange) { flags.female = !flags.female; You("%s %s%s!", (u.umonnum != mntmp) ? "turn into a" : "feel like a new", (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" : flags.female ? "female " : "male ", mons[mntmp].mname); } else { if (u.umonnum != mntmp) You("turn into %s!", an(mons[mntmp].mname)); else You_feel("like a new %s!", mons[mntmp].mname); } if (Stoned && poly_when_stoned(&mons[mntmp])) { /* poly_when_stoned already checked stone golem genocide */ mntmp = PM_STONE_GOLEM; make_stoned(0L, "You turn to stone!", 0, (char *) 0); } u.mtimedone = rn1(500, 500); u.umonnum = mntmp; set_uasmon(); /* New stats for monster, to last only as long as polymorphed. * Currently only strength gets changed. */ if (strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100); if (Stone_resistance && Stoned) { /* parnes@eniac.seas.upenn.edu */ make_stoned(0L, "You no longer seem to be petrifying.", 0, (char *) 0); } if (Sick_resistance && Sick) { make_sick(0L, (char *) 0, FALSE, SICK_ALL); You("no longer feel sick."); } if (Slimed) { if (flaming(youmonst.data)) { make_slimed(0L, "The slime burns away!"); } else if (mntmp == PM_GREEN_SLIME) { /* do it silently */ make_slimed(0L, (char *) 0); } } check_strangling(FALSE); /* maybe stop strangling */ if (nohands(youmonst.data)) Glib = 0; /* mlvl = adj_lev(&mons[mntmp]); * We can't do the above, since there's no such thing as an * "experience level of you as a monster" for a polymorphed character. */ mlvl = (int) mons[mntmp].mlevel; if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) { u.mhmax = In_endgame(&u.uz) ? (8 * mlvl) : (4 * mlvl + d(mlvl, 4)); } else if (is_golem(youmonst.data)) { u.mhmax = golemhp(mntmp); } else { if (!mlvl) u.mhmax = rnd(4); else u.mhmax = d(mlvl, 8); if (is_home_elemental(&mons[mntmp])) u.mhmax *= 3; } u.mh = u.mhmax; if (u.ulevel < mlvl) { /* Low level characters can't become high level monsters for long */ #ifdef DUMB /* DRS/NS 2.2.6 messes up -- Peter Kendell */ int mtd = u.mtimedone, ulv = u.ulevel; u.mtimedone = mtd * ulv / mlvl; #else u.mtimedone = u.mtimedone * u.ulevel / mlvl; #endif } if (uskin && mntmp != armor_to_dragon(uskin->otyp)) skinback(FALSE); break_armor(); drop_weapon(1); (void) hideunder(&youmonst); if (u.utraptype == TT_PIT && u.utrap) { u.utrap = rn1(6, 2); /* time to escape resets */ } if (was_blind && !Blind) { /* previous form was eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } newsym(u.ux, u.uy); /* Change symbol */ if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0; else if (sticky && !sticks(youmonst.data)) uunstick(); if (u.usteed) { if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; pline("%s touch %s.", no_longer_petrify_resistant, mon_nam(u.usteed)); Sprintf(buf, "riding %s", an(u.usteed->data->mname)); instapetrify(buf); } if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY); } if (flags.verbose) { static const char use_thec[] = "Use the command #%s to %s."; static const char monsterc[] = "monster"; if (can_breathe(youmonst.data)) pline(use_thec, monsterc, "use your breath weapon"); if (attacktype(youmonst.data, AT_SPIT)) pline(use_thec, monsterc, "spit venom"); if (youmonst.data->mlet == S_NYMPH) pline(use_thec, monsterc, "remove an iron ball"); if (attacktype(youmonst.data, AT_GAZE)) pline(use_thec, monsterc, "gaze at monsters"); if (is_hider(youmonst.data)) pline(use_thec, monsterc, "hide"); if (is_were(youmonst.data)) pline(use_thec, monsterc, "summon help"); if (webmaker(youmonst.data)) pline(use_thec, monsterc, "spin a web"); if (u.umonnum == PM_GREMLIN) pline(use_thec, monsterc, "multiply in a fountain"); if (is_unicorn(youmonst.data)) pline(use_thec, monsterc, "use your horn"); if (is_mind_flayer(youmonst.data)) pline(use_thec, monsterc, "emit a mental blast"); if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */ pline(use_thec, monsterc, "shriek"); if (is_vampire(youmonst.data)) pline(use_thec, monsterc, "change shape"); if (lays_eggs(youmonst.data) && flags.female) pline(use_thec, "sit", "lay an egg"); } /* you now know what an egg of your type looks like */ if (lays_eggs(youmonst.data)) { learn_egg_type(u.umonnum); /* make queen bees recognize killer bee eggs */ learn_egg_type(egg_type_from_parent(u.umonnum, TRUE)); } find_ac(); if ((!Levitation && !u.ustuck && !Flying && is_pool_or_lava(u.ux, u.uy)) || (Underwater && !Swimming)) spoteffects(TRUE); if (Passes_walls && u.utrap && (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL)) { u.utrap = 0; if (u.utraptype == TT_INFLOOR) pline_The("rock seems to no longer trap you."); else { pline_The("buried ball is no longer bound to you."); buried_ball_to_freedom(); } } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) { u.utrap = 0; pline_The("lava now feels soothing."); } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (Punished) { You("slip out of the iron chain."); unpunish(); } else if (u.utrap && u.utraptype == TT_BURIEDBALL) { You("slip free of the buried ball and chain."); buried_ball_to_freedom(); } } if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) && (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) || (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) { You("are no longer stuck in the %s.", u.utraptype == TT_WEB ? "web" : "bear trap"); /* probably should burn webs too if PM_FIRE_ELEMENTAL */ u.utrap = 0; } if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) { You("orient yourself on the web."); u.utrap = 0; } check_strangling(TRUE); /* maybe start strangling */ (void) polysense(youmonst.data); context.botl = 1; vision_full_recalc = 1; see_monsters(); (void) encumber_msg(); retouch_equipment(2); /* this might trigger a recursive call to polymon() [stone golem wielding cockatrice corpse and hit by stone-to-flesh, becomes flesh golem above, now gets transformed back into stone golem] */ if (!uarmg) selftouch(no_longer_petrify_resistant); return 1; } STATIC_OVL void break_armor() { register struct obj *otmp; if (breakarm(youmonst.data)) { if ((otmp = uarm) != 0) { if (donning(otmp)) cancel_don(); You("break out of your armor!"); exercise(A_STR, FALSE); (void) Armor_gone(); useup(otmp); } if ((otmp = uarmc) != 0) { if (otmp->oartifact) { Your("%s falls off!", cloak_simple_name(otmp)); (void) Cloak_off(); dropx(otmp); } else { Your("%s tears apart!", cloak_simple_name(otmp)); (void) Cloak_off(); useup(otmp); } } if (uarmu) { Your("shirt rips to shreds!"); useup(uarmu); } } else if (sliparm(youmonst.data)) { if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) { if (donning(otmp)) cancel_don(); Your("armor falls around you!"); (void) Armor_gone(); dropx(otmp); } if ((otmp = uarmc) != 0) { if (is_whirly(youmonst.data)) Your("%s falls, unsupported!", cloak_simple_name(otmp)); else You("shrink out of your %s!", cloak_simple_name(otmp)); (void) Cloak_off(); dropx(otmp); } if ((otmp = uarmu) != 0) { if (is_whirly(youmonst.data)) You("seep right through your shirt!"); else You("become much too small for your shirt!"); setworn((struct obj *) 0, otmp->owornmask & W_ARMU); dropx(otmp); } } if (has_horns(youmonst.data)) { if ((otmp = uarmh) != 0) { if (is_flimsy(otmp) && !donning(otmp)) { char hornbuf[BUFSZ]; /* Future possibilities: This could damage/destroy helmet */ Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data))); Your("%s %s through %s.", hornbuf, vtense(hornbuf, "pierce"), yname(otmp)); } else { if (donning(otmp)) cancel_don(); Your("%s falls to the %s!", helm_simple_name(otmp), surface(u.ux, u.uy)); (void) Helmet_off(); dropx(otmp); } } } if (nohands(youmonst.data) || verysmall(youmonst.data)) { if ((otmp = uarmg) != 0) { if (donning(otmp)) cancel_don(); /* Drop weapon along with gloves */ You("drop your gloves%s!", uwep ? " and weapon" : ""); drop_weapon(0); (void) Gloves_off(); dropx(otmp); } if ((otmp = uarms) != 0) { You("can no longer hold your shield!"); (void) Shield_off(); dropx(otmp); } if ((otmp = uarmh) != 0) { if (donning(otmp)) cancel_don(); Your("%s falls to the %s!", helm_simple_name(otmp), surface(u.ux, u.uy)); (void) Helmet_off(); dropx(otmp); } } if (nohands(youmonst.data) || verysmall(youmonst.data) || slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) { if ((otmp = uarmf) != 0) { if (donning(otmp)) cancel_don(); if (is_whirly(youmonst.data)) Your("boots fall away!"); else Your("boots %s off your feet!", verysmall(youmonst.data) ? "slide" : "are pushed"); (void) Boots_off(); dropx(otmp); } } } STATIC_OVL void drop_weapon(alone) int alone; { struct obj *otmp; const char *what, *which, *whichtoo; boolean candropwep, candropswapwep; if (uwep) { /* !alone check below is currently superfluous but in the * future it might not be so if there are monsters which cannot * wear gloves but can wield weapons */ if (!alone || cantwield(youmonst.data)) { candropwep = canletgo(uwep, ""); candropswapwep = !u.twoweap || canletgo(uswapwep, ""); if (alone) { what = (candropwep && candropswapwep) ? "drop" : "release"; which = is_sword(uwep) ? "sword" : weapon_descr(uwep); if (u.twoweap) { whichtoo = is_sword(uswapwep) ? "sword" : weapon_descr(uswapwep); if (strcmp(which, whichtoo)) which = "weapon"; } if (uwep->quan != 1L || u.twoweap) which = makeplural(which); You("find you must %s %s %s!", what, the_your[!!strncmp(which, "corpse", 6)], which); } if (u.twoweap) { otmp = uswapwep; uswapwepgone(); if (candropswapwep) dropx(otmp); } otmp = uwep; uwepgone(); if (candropwep) dropx(otmp); update_inventory(); } else if (!could_twoweap(youmonst.data)) { untwoweapon(); } } } void rehumanize() { /* You can't revert back while unchanging */ if (Unchanging && (u.mh < 1)) { killer.format = NO_KILLER_PREFIX; Strcpy(killer.name, "killed while stuck in creature form"); done(DIED); } if (emits_light(youmonst.data)) del_light_source(LS_MONSTER, monst_to_any(&youmonst)); polyman("return to %s form!", urace.adj); if (u.uhp < 1) { /* can only happen if some bit of code reduces u.uhp instead of u.mh while poly'd */ Your("old form was not healthy enough to survive."); Sprintf(killer.name, "reverting to unhealthy %s form", urace.adj); killer.format = KILLED_BY; done(DIED); } nomul(0); context.botl = 1; vision_full_recalc = 1; (void) encumber_msg(); retouch_equipment(2); if (!uarmg) selftouch(no_longer_petrify_resistant); } int dobreathe() { struct attack *mattk; if (Strangled) { You_cant("breathe. Sorry."); return 0; } if (u.uen < 15) { You("don't have enough energy to breathe!"); return 0; } u.uen -= 15; context.botl = 1; if (!getdir((char *) 0)) return 0; mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY); if (!mattk) impossible("bad breath attack?"); /* mouthwash needed... */ else if (!u.dx && !u.dy && !u.dz) ubreatheu(mattk); else buzz((int) (20 + mattk->adtyp - 1), (int) mattk->damn, u.ux, u.uy, u.dx, u.dy); return 1; } int dospit() { struct obj *otmp; struct attack *mattk; if (!getdir((char *) 0)) return 0; mattk = attacktype_fordmg(youmonst.data, AT_SPIT, AD_ANY); if (!mattk) { impossible("bad spit attack?"); } else { switch (mattk->adtyp) { case AD_BLND: case AD_DRST: otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); break; default: impossible("bad attack type in dospit"); /* fall through */ case AD_ACID: otmp = mksobj(ACID_VENOM, TRUE, FALSE); break; } otmp->spe = 1; /* to indicate it's yours */ throwit(otmp, 0L, FALSE); } return 1; } int doremove() { if (!Punished) { if (u.utrap && u.utraptype == TT_BURIEDBALL) { pline_The("ball and chain are buried firmly in the %s.", surface(u.ux, u.uy)); return 0; } You("are not chained to anything!"); return 0; } unpunish(); return 1; } int dospinweb() { register struct trap *ttmp = t_at(u.ux, u.uy); if (Levitation || Is_airlevel(&u.uz) || Underwater || Is_waterlevel(&u.uz)) { You("must be on the ground to spin a web."); return 0; } if (u.uswallow) { You("release web fluid inside %s.", mon_nam(u.ustuck)); if (is_animal(u.ustuck->data)) { expels(u.ustuck, u.ustuck->data, TRUE); return 0; } if (is_whirly(u.ustuck->data)) { int i; for (i = 0; i < NATTK; i++) if (u.ustuck->data->mattk[i].aatyp == AT_ENGL) break; if (i == NATTK) impossible("Swallower has no engulfing attack?"); else { char sweep[30]; sweep[0] = '\0'; switch (u.ustuck->data->mattk[i].adtyp) { case AD_FIRE: Strcpy(sweep, "ignites and "); break; case AD_ELEC: Strcpy(sweep, "fries and "); break; case AD_COLD: Strcpy(sweep, "freezes, shatters and "); break; } pline_The("web %sis swept away!", sweep); } return 0; } /* default: a nasty jelly-like creature */ pline_The("web dissolves into %s.", mon_nam(u.ustuck)); return 0; } if (u.utrap) { You("cannot spin webs while stuck in a trap."); return 0; } exercise(A_DEX, TRUE); if (ttmp) { switch (ttmp->ttyp) { case PIT: case SPIKED_PIT: You("spin a web, covering up the pit."); deltrap(ttmp); bury_objs(u.ux, u.uy); newsym(u.ux, u.uy); return 1; case SQKY_BOARD: pline_The("squeaky board is muffled."); deltrap(ttmp); newsym(u.ux, u.uy); return 1; case TELEP_TRAP: case LEVEL_TELEP: case MAGIC_PORTAL: case VIBRATING_SQUARE: Your("webbing vanishes!"); return 0; case WEB: You("make the web thicker."); return 1; case HOLE: case TRAPDOOR: You("web over the %s.", (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole"); deltrap(ttmp); newsym(u.ux, u.uy); return 1; case ROLLING_BOULDER_TRAP: You("spin a web, jamming the trigger."); deltrap(ttmp); newsym(u.ux, u.uy); return 1; case ARROW_TRAP: case DART_TRAP: case BEAR_TRAP: case ROCKTRAP: case FIRE_TRAP: case LANDMINE: case SLP_GAS_TRAP: case RUST_TRAP: case MAGIC_TRAP: case ANTI_MAGIC: case POLY_TRAP: You("have triggered a trap!"); dotrap(ttmp, 0); return 1; default: impossible("Webbing over trap type %d?", ttmp->ttyp); return 0; } } else if (On_stairs(u.ux, u.uy)) { /* cop out: don't let them hide the stairs */ Your("web fails to impede access to the %s.", (levl[u.ux][u.uy].typ == STAIRS) ? "stairs" : "ladder"); return 1; } ttmp = maketrap(u.ux, u.uy, WEB); if (ttmp) { ttmp->madeby_u = 1; feeltrap(ttmp); } return 1; } int dosummon() { int placeholder; if (u.uen < 10) { You("lack the energy to send forth a call for help!"); return 0; } u.uen -= 10; context.botl = 1; You("call upon your brethren for help!"); exercise(A_WIS, TRUE); if (!were_summon(youmonst.data, TRUE, &placeholder, (char *) 0)) pline("But none arrive."); return 1; } int dogaze() { register struct monst *mtmp; int looked = 0; char qbuf[QBUFSZ]; int i; uchar adtyp = 0; for (i = 0; i < NATTK; i++) { if (youmonst.data->mattk[i].aatyp == AT_GAZE) { adtyp = youmonst.data->mattk[i].adtyp; break; } } if (adtyp != AD_CONF && adtyp != AD_FIRE) { impossible("gaze attack %d?", adtyp); return 0; } if (Blind) { You_cant("see anything to gaze at."); return 0; } else if (Hallucination) { You_cant("gaze at anything you can see."); return 0; } if (u.uen < 15) { You("lack the energy to use your special gaze!"); return 0; } u.uen -= 15; context.botl = 1; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) { looked++; if (Invis && !perceives(mtmp->data)) { pline("%s seems not to notice your gaze.", Monnam(mtmp)); } else if (mtmp->minvis && !See_invisible) { You_cant("see where to gaze at %s.", Monnam(mtmp)); } else if (mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) { looked--; continue; } else if (flags.safe_dog && mtmp->mtame && !Confusion) { You("avoid gazing at %s.", y_monnam(mtmp)); } else { if (flags.confirm && mtmp->mpeaceful && !Confusion) { Sprintf(qbuf, "Really %s %s?", (adtyp == AD_CONF) ? "confuse" : "attack", mon_nam(mtmp)); if (yn(qbuf) != 'y') continue; setmangry(mtmp); } if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping || !mtmp->mcansee || !haseyes(mtmp->data)) { looked--; continue; } /* No reflection check for consistency with when a monster * gazes at *you*--only medusa gaze gets reflected then. */ if (adtyp == AD_CONF) { if (!mtmp->mconf) Your("gaze confuses %s!", mon_nam(mtmp)); else pline("%s is getting more and more confused.", Monnam(mtmp)); mtmp->mconf = 1; } else if (adtyp == AD_FIRE) { int dmg = d(2, 6), lev = (int) u.ulevel; You("attack %s with a fiery gaze!", mon_nam(mtmp)); if (resists_fire(mtmp)) { pline_The("fire doesn't burn %s!", mon_nam(mtmp)); dmg = 0; } if (lev > rn2(20)) (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); if (lev > rn2(20)) (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); if (lev > rn2(25)) (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); if (dmg) mtmp->mhp -= dmg; if (mtmp->mhp <= 0) killed(mtmp); } /* For consistency with passive() in uhitm.c, this only * affects you if the monster is still alive. */ if (DEADMONSTER(mtmp)) continue; if (mtmp->data == &mons[PM_FLOATING_EYE] && !mtmp->mcan) { if (!Free_action) { You("are frozen by %s gaze!", s_suffix(mon_nam(mtmp))); nomul((u.ulevel > 6 || rn2(4)) ? -d((int) mtmp->m_lev + 1, (int) mtmp->data->mattk[0].damd) : -200); multi_reason = "frozen by a monster's gaze"; nomovemsg = 0; return 1; } else You("stiffen momentarily under %s gaze.", s_suffix(mon_nam(mtmp))); } /* Technically this one shouldn't affect you at all because * the Medusa gaze is an active monster attack that only * works on the monster's turn, but for it to *not* have an * effect would be too weird. */ if (mtmp->data == &mons[PM_MEDUSA] && !mtmp->mcan) { pline("Gazing at the awake %s is not a very good idea.", l_monnam(mtmp)); /* as if gazing at a sleeping anything is fruitful... */ You("turn to stone..."); killer.format = KILLED_BY; Strcpy(killer.name, "deliberately meeting Medusa's gaze"); done(STONING); } } } } if (!looked) You("gaze at no place in particular."); return 1; } int dohide() { boolean ismimic = youmonst.data->mlet == S_MIMIC, on_ceiling = is_clinger(youmonst.data) || Flying; /* can't hide while being held (or holding) or while trapped (except for floor hiders [trapper or mimic] in pits) */ if (u.ustuck || (u.utrap && (u.utraptype != TT_PIT || on_ceiling))) { You_cant("hide while you're %s.", !u.ustuck ? "trapped" : !sticks(youmonst.data) ? "being held" : humanoid(u.ustuck->data) ? "holding someone" : "holding that creature"); if (u.uundetected || (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) { u.uundetected = 0; youmonst.m_ap_type = M_AP_NOTHING; newsym(u.ux, u.uy); } return 0; } /* note: the eel and hides_under cases are hypothetical; such critters aren't offered the option of hiding via #monster */ if (youmonst.data->mlet == S_EEL && !is_pool(u.ux, u.uy)) { if (IS_FOUNTAIN(levl[u.ux][u.uy].typ)) The("fountain is not deep enough to hide in."); else There("is no water to hide in here."); u.uundetected = 0; return 0; } if (hides_under(youmonst.data) && !level.objects[u.ux][u.uy]) { There("is nothing to hide under here."); u.uundetected = 0; return 0; } /* Planes of Air and Water */ if (on_ceiling && !has_ceiling(&u.uz)) { There("is nowhere to hide above you."); u.uundetected = 0; return 0; } if ((is_hider(youmonst.data) && !Flying) /* floor hider */ && (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))) { There("is nowhere to hide beneath you."); u.uundetected = 0; return 0; } /* TODO? inhibit floor hiding at furniture locations, or * else make youhiding() give smarter messages at such spots. */ if (u.uundetected || (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) { youhiding(FALSE, 1); /* "you are already hiding" */ return 0; } if (ismimic) { /* should bring up a dialog "what would you like to imitate?" */ youmonst.m_ap_type = M_AP_OBJECT; youmonst.mappearance = STRANGE_OBJECT; } else u.uundetected = 1; newsym(u.ux, u.uy); youhiding(FALSE, 0); /* "you are now hiding" */ return 1; } int dopoly() { struct permonst *savedat = youmonst.data; if (is_vampire(youmonst.data)) { polyself(2); if (savedat != youmonst.data) { You("transform into %s.", an(youmonst.data->mname)); newsym(u.ux, u.uy); } } return 1; } int domindblast() { struct monst *mtmp, *nmon; if (u.uen < 10) { You("concentrate but lack the energy to maintain doing so."); return 0; } u.uen -= 10; context.botl = 1; You("concentrate."); pline("A wave of psychic energy pours out."); for (mtmp = fmon; mtmp; mtmp = nmon) { int u_sen; nmon = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) continue; if (mtmp->mpeaceful) continue; u_sen = telepathic(mtmp->data) && !mtmp->mcansee; if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) { You("lock in on %s %s.", s_suffix(mon_nam(mtmp)), u_sen ? "telepathy" : telepathic(mtmp->data) ? "latent telepathy" : "mind"); mtmp->mhp -= rnd(15); if (mtmp->mhp <= 0) killed(mtmp); } } return 1; } STATIC_OVL void uunstick() { pline("%s is no longer in your clutches.", Monnam(u.ustuck)); u.ustuck = 0; } void skinback(silently) boolean silently; { if (uskin) { if (!silently) Your("skin returns to its original form."); uarm = uskin; uskin = (struct obj *) 0; /* undo save/restore hack */ uarm->owornmask &= ~I_SPECIAL; } } const char * mbodypart(mon, part) struct monst *mon; int part; { static NEARDATA const char *humanoid_parts[] = { "arm", "eye", "face", "finger", "fingertip", "foot", "hand", "handed", "head", "leg", "light headed", "neck", "spine", "toe", "hair", "blood", "lung", "nose", "stomach" }, *jelly_parts[] = { "pseudopod", "dark spot", "front", "pseudopod extension", "pseudopod extremity", "pseudopod root", "grasp", "grasped", "cerebral area", "lower pseudopod", "viscous", "middle", "surface", "pseudopod extremity", "ripples", "juices", "surface", "sensor", "stomach" }, *animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip", "rear claw", "foreclaw", "clawed", "head", "rear limb", "light headed", "neck", "spine", "rear claw tip", "fur", "blood", "lung", "nose", "stomach" }, *bird_parts[] = { "wing", "eye", "face", "wing", "wing tip", "foot", "wing", "winged", "head", "leg", "light headed", "neck", "spine", "toe", "feathers", "blood", "lung", "bill", "stomach" }, *horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip", "rear hoof", "forehoof", "hooved", "head", "rear leg", "light headed", "neck", "backbone", "rear hoof tip", "mane", "blood", "lung", "nose", "stomach" }, *sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle", "tentacle tip", "lower appendage", "tentacle", "tentacled", "body", "lower tentacle", "rotational", "equator", "body", "lower tentacle tip", "cilia", "life force", "retina", "olfactory nerve", "interior" }, *fungus_parts[] = { "mycelium", "visual area", "front", "hypha", "hypha", "root", "strand", "stranded", "cap area", "rhizome", "sporulated", "stalk", "root", "rhizome tip", "spores", "juices", "gill", "gill", "interior" }, *vortex_parts[] = { "region", "eye", "front", "minor current", "minor current", "lower current", "swirl", "swirled", "central core", "lower current", "addled", "center", "currents", "edge", "currents", "life force", "center", "leading edge", "interior" }, *snake_parts[] = { "vestigial limb", "eye", "face", "large scale", "large scale tip", "rear region", "scale gap", "scale gapped", "head", "rear region", "light headed", "neck", "length", "rear scale", "scales", "blood", "lung", "forked tongue", "stomach" }, *worm_parts[] = { "anterior segment", "light sensitive cell", "clitellum", "setae", "setae", "posterior segment", "segment", "segmented", "anterior segment", "posterior", "over stretched", "clitellum", "length", "posterior setae", "setae", "blood", "skin", "prostomium", "stomach" }, *fish_parts[] = { "fin", "eye", "premaxillary", "pelvic axillary", "pelvic fin", "anal fin", "pectoral fin", "finned", "head", "peduncle", "played out", "gills", "dorsal fin", "caudal fin", "scales", "blood", "gill", "nostril", "stomach" }; /* claw attacks are overloaded in mons[]; most humanoids with such attacks should still reference hands rather than claws */ static const char not_claws[] = { S_HUMAN, S_MUMMY, S_ZOMBIE, S_ANGEL, S_NYMPH, S_LEPRECHAUN, S_QUANTMECH, S_VAMPIRE, S_ORC, S_GIANT, /* quest nemeses */ '\0' /* string terminator; assert( S_xxx != 0 ); */ }; struct permonst *mptr = mon->data; /* some special cases */ if (mptr->mlet == S_DOG || mptr->mlet == S_FELINE || mptr->mlet == S_RODENT || mptr == &mons[PM_OWLBEAR]) { switch (part) { case HAND: return "paw"; case HANDED: return "pawed"; case FOOT: return "rear paw"; case ARM: case LEG: return horse_parts[part]; /* "foreleg", "rear leg" */ default: break; /* for other parts, use animal_parts[] below */ } } else if (mptr->mlet == S_YETI) { /* excl. owlbear due to 'if' above */ /* opposable thumbs, hence "hands", "arms", "legs", &c */ return humanoid_parts[part]; /* yeti/sasquatch, monkey/ape */ } if ((part == HAND || part == HANDED) && (humanoid(mptr) && attacktype(mptr, AT_CLAW) && !index(not_claws, mptr->mlet) && mptr != &mons[PM_STONE_GOLEM] && mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS])) return (part == HAND) ? "claw" : "clawed"; if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON]) && part == NOSE) return "trunk"; if (mptr == &mons[PM_SHARK] && part == HAIR) return "skin"; /* sharks don't have scales */ if ((mptr == &mons[PM_JELLYFISH] || mptr == &mons[PM_KRAKEN]) && (part == ARM || part == FINGER || part == HAND || part == FOOT || part == TOE)) return "tentacle"; if (mptr == &mons[PM_FLOATING_EYE] && part == EYE) return "cornea"; if (humanoid(mptr) && (part == ARM || part == FINGER || part == FINGERTIP || part == HAND || part == HANDED)) return humanoid_parts[part]; if (mptr == &mons[PM_RAVEN]) return bird_parts[part]; if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN || (mptr == &mons[PM_ROTHE] && part != HAIR)) return horse_parts[part]; if (mptr->mlet == S_LIGHT) { if (part == HANDED) return "rayed"; else if (part == ARM || part == FINGER || part == FINGERTIP || part == HAND) return "ray"; else return "beam"; } if (mptr == &mons[PM_STALKER] && part == HEAD) return "head"; if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH]) return fish_parts[part]; if (mptr->mlet == S_WORM) return worm_parts[part]; if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR)) return snake_parts[part]; if (mptr->mlet == S_EYE) return sphere_parts[part]; if (mptr->mlet == S_JELLY || mptr->mlet == S_PUDDING || mptr->mlet == S_BLOB || mptr == &mons[PM_JELLYFISH]) return jelly_parts[part]; if (mptr->mlet == S_VORTEX || mptr->mlet == S_ELEMENTAL) return vortex_parts[part]; if (mptr->mlet == S_FUNGUS) return fungus_parts[part]; if (humanoid(mptr)) return humanoid_parts[part]; return animal_parts[part]; } const char * body_part(part) int part; { return mbodypart(&youmonst, part); } int poly_gender() { /* Returns gender of polymorphed player; * 0/1=same meaning as flags.female, 2=none. */ if (is_neuter(youmonst.data) || !humanoid(youmonst.data)) return 2; return flags.female; } void ugolemeffects(damtype, dam) int damtype, dam; { int heal = 0; /* We won't bother with "slow"/"haste" since players do not * have a monster-specific slow/haste so there is no way to * restore the old velocity once they are back to human. */ if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM) return; switch (damtype) { case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM) heal = (dam + 5) / 6; /* Approx 1 per die */ break; case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM) heal = dam; break; } if (heal && (u.mh < u.mhmax)) { u.mh += heal; if (u.mh > u.mhmax) u.mh = u.mhmax; context.botl = 1; pline("Strangely, you feel better than before."); exercise(A_STR, TRUE); } } STATIC_OVL int armor_to_dragon(atyp) int atyp; { switch (atyp) { case GRAY_DRAGON_SCALE_MAIL: case GRAY_DRAGON_SCALES: return PM_GRAY_DRAGON; case SILVER_DRAGON_SCALE_MAIL: case SILVER_DRAGON_SCALES: return PM_SILVER_DRAGON; #if 0 /* DEFERRED */ case SHIMMERING_DRAGON_SCALE_MAIL: case SHIMMERING_DRAGON_SCALES: return PM_SHIMMERING_DRAGON; #endif case RED_DRAGON_SCALE_MAIL: case RED_DRAGON_SCALES: return PM_RED_DRAGON; case ORANGE_DRAGON_SCALE_MAIL: case ORANGE_DRAGON_SCALES: return PM_ORANGE_DRAGON; case WHITE_DRAGON_SCALE_MAIL: case WHITE_DRAGON_SCALES: return PM_WHITE_DRAGON; case BLACK_DRAGON_SCALE_MAIL: case BLACK_DRAGON_SCALES: return PM_BLACK_DRAGON; case BLUE_DRAGON_SCALE_MAIL: case BLUE_DRAGON_SCALES: return PM_BLUE_DRAGON; case GREEN_DRAGON_SCALE_MAIL: case GREEN_DRAGON_SCALES: return PM_GREEN_DRAGON; case YELLOW_DRAGON_SCALE_MAIL: case YELLOW_DRAGON_SCALES: return PM_YELLOW_DRAGON; default: return -1; } } /* * Some species have awareness of other species */ static boolean polysense(mptr) struct permonst *mptr; { short warnidx = 0; context.warntype.speciesidx = 0; context.warntype.species = 0; context.warntype.polyd = 0; switch (monsndx(mptr)) { case PM_PURPLE_WORM: warnidx = PM_SHRIEKER; break; case PM_VAMPIRE: case PM_VAMPIRE_LORD: context.warntype.polyd = M2_HUMAN | M2_ELF; HWarn_of_mon |= FROMRACE; return TRUE; } if (warnidx) { context.warntype.speciesidx = warnidx; context.warntype.species = &mons[warnidx]; HWarn_of_mon |= FROMRACE; return TRUE; } context.warntype.speciesidx = 0; context.warntype.species = 0; HWarn_of_mon &= ~FROMRACE; return FALSE; } /*polyself.c*/ nethack-3.6.0/src/potion.c0000664000076400007660000021701512617413107014410 0ustar paxedpaxed/* NetHack 3.6 potion.c $NHDT-Date: 1446861768 2015/11/07 02:02:48 $ $NHDT-Branch: master $:$NHDT-Revision: 1.121 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" boolean notonhead = FALSE; static NEARDATA int nothing, unkn; static NEARDATA const char beverages[] = { POTION_CLASS, 0 }; STATIC_DCL long FDECL(itimeout, (long)); STATIC_DCL long FDECL(itimeout_incr, (long, int)); STATIC_DCL void NDECL(ghost_from_bottle); STATIC_DCL boolean FDECL(H2Opotion_dip, (struct obj *, struct obj *, BOOLEAN_P, const char *)); STATIC_DCL short FDECL(mixtype, (struct obj *, struct obj *)); /* force `val' to be within valid range for intrinsic timeout value */ STATIC_OVL long itimeout(val) long val; { if (val >= TIMEOUT) val = TIMEOUT; else if (val < 1) val = 0; return val; } /* increment `old' by `incr' and force result to be valid intrinsic timeout */ STATIC_OVL long itimeout_incr(old, incr) long old; int incr; { return itimeout((old & TIMEOUT) + (long) incr); } /* set the timeout field of intrinsic `which' */ void set_itimeout(which, val) long *which, val; { *which &= ~TIMEOUT; *which |= itimeout(val); } /* increment the timeout field of intrinsic `which' */ void incr_itimeout(which, incr) long *which; int incr; { set_itimeout(which, itimeout_incr(*which, incr)); } void make_confused(xtime, talk) long xtime; boolean talk; { long old = HConfusion; if (Unaware) talk = FALSE; if (!xtime && old) { if (talk) You_feel("less %s now.", Hallucination ? "trippy" : "confused"); } if ((xtime && !old) || (!xtime && old)) context.botl = TRUE; set_itimeout(&HConfusion, xtime); } void make_stunned(xtime, talk) long xtime; boolean talk; { long old = HStun; if (Unaware) talk = FALSE; if (!xtime && old) { if (talk) You_feel("%s now.", Hallucination ? "less wobbly" : "a bit steadier"); } if (xtime && !old) { if (talk) { if (u.usteed) You("wobble in the saddle."); else You("%s...", stagger(youmonst.data, "stagger")); } } if ((!xtime && old) || (xtime && !old)) context.botl = TRUE; set_itimeout(&HStun, xtime); } void make_sick(xtime, cause, talk, type) long xtime; const char *cause; /* sickness cause */ boolean talk; int type; { long old = Sick; #if 0 if (Unaware) talk = FALSE; #endif if (xtime > 0L) { if (Sick_resistance) return; if (!old) { /* newly sick */ You_feel("deathly sick."); } else { /* already sick */ if (talk) You_feel("%s worse.", xtime <= Sick / 2L ? "much" : "even"); } set_itimeout(&Sick, xtime); u.usick_type |= type; context.botl = TRUE; } else if (old && (type & u.usick_type)) { /* was sick, now not */ u.usick_type &= ~type; if (u.usick_type) { /* only partly cured */ if (talk) You_feel("somewhat better."); set_itimeout(&Sick, Sick * 2); /* approximation */ } else { if (talk) You_feel("cured. What a relief!"); Sick = 0L; /* set_itimeout(&Sick, 0L) */ } context.botl = TRUE; } if (Sick) { exercise(A_CON, FALSE); delayed_killer(SICK, KILLED_BY_AN, cause); } else dealloc_killer(find_delayed_killer(SICK)); } void make_slimed(xtime, msg) long xtime; const char *msg; { long old = Slimed; #if 0 if (Unaware) msg = 0; #endif if ((!xtime && old) || (xtime && !old)) { if (msg) pline1(msg); context.botl = 1; } set_itimeout(&Slimed, xtime); if (!Slimed) dealloc_killer(find_delayed_killer(SLIMED)); } /* start or stop petrification */ void make_stoned(xtime, msg, killedby, killername) long xtime; const char *msg; int killedby; const char *killername; { long old = Stoned; #if 0 if (Unaware) msg = 0; #endif if ((!xtime && old) || (xtime && !old)) { if (msg) pline1(msg); /* context.botl = 1; --- Stoned is not a status line item */ } set_itimeout(&Stoned, xtime); if (!Stoned) dealloc_killer(find_delayed_killer(STONED)); else if (!old) delayed_killer(STONED, killedby, killername); } void make_vomiting(xtime, talk) long xtime; boolean talk; { long old = Vomiting; if (Unaware) talk = FALSE; if (!xtime && old) if (talk) You_feel("much less nauseated now."); set_itimeout(&Vomiting, xtime); } static const char vismsg[] = "vision seems to %s for a moment but is %s now."; static const char eyemsg[] = "%s momentarily %s."; void make_blinded(xtime, talk) long xtime; boolean talk; { long old = Blinded; boolean u_could_see, can_see_now; const char *eyes; /* we need to probe ahead in case the Eyes of the Overworld are or will be overriding blindness */ u_could_see = !Blind; Blinded = xtime ? 1L : 0L; can_see_now = !Blind; Blinded = old; /* restore */ if (Unaware) talk = FALSE; if (can_see_now && !u_could_see) { /* regaining sight */ if (talk) { if (Hallucination) pline("Far out! Everything is all cosmic again!"); else You("can see again."); } } else if (old && !xtime) { /* clearing temporary blindness without toggling blindness */ if (talk) { if (!haseyes(youmonst.data)) { strange_feeling((struct obj *) 0, (char *) 0); } else if (Blindfolded) { eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); Your(eyemsg, eyes, vtense(eyes, "itch")); } else { /* Eyes of the Overworld */ Your(vismsg, "brighten", Hallucination ? "sadder" : "normal"); } } } if (u_could_see && !can_see_now) { /* losing sight */ if (talk) { if (Hallucination) pline("Oh, bummer! Everything is dark! Help!"); else pline("A cloud of darkness falls upon you."); } /* Before the hero goes blind, set the ball&chain variables. */ if (Punished) set_bc(0); } else if (!old && xtime) { /* setting temporary blindness without toggling blindness */ if (talk) { if (!haseyes(youmonst.data)) { strange_feeling((struct obj *) 0, (char *) 0); } else if (Blindfolded) { eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); Your(eyemsg, eyes, vtense(eyes, "twitch")); } else { /* Eyes of the Overworld */ Your(vismsg, "dim", Hallucination ? "happier" : "normal"); } } } set_itimeout(&Blinded, xtime); if (u_could_see ^ can_see_now) { /* one or the other but not both */ context.botl = 1; vision_full_recalc = 1; /* blindness just got toggled */ /* this vision recalculation used to be deferred until moveloop(), but that made it possible for vision irregularities to occur (cited case was force bolt hitting adjacent potion of blindness and then a secret door; hero was blinded by vapors but then got the message "a door appears in the wall") */ vision_recalc(0); if (Blind_telepat || Infravision) see_monsters(); /* avoid either of the sequences "Sting starts glowing", [become blind], "Sting stops quivering" or "Sting starts quivering", [regain sight], "Sting stops glowing" by giving "Sting is quivering" when becoming blind or "Sting is glowing" when regaining sight so that the eventual "stops" message matches */ if (warn_obj_cnt && uwep && (EWarn_of_mon & W_WEP) != 0L) Sting_effects(-1); /* update dknown flag for inventory picked up while blind */ if (can_see_now) learn_unseen_invent(); } } boolean make_hallucinated(xtime, talk, mask) long xtime; /* nonzero if this is an attempt to turn on hallucination */ boolean talk; long mask; /* nonzero if resistance status should change by mask */ { long old = HHallucination; boolean changed = 0; const char *message, *verb; if (Unaware) talk = FALSE; message = (!xtime) ? "Everything %s SO boring now." : "Oh wow! Everything %s so cosmic!"; verb = (!Blind) ? "looks" : "feels"; if (mask) { if (HHallucination) changed = TRUE; if (!xtime) EHalluc_resistance |= mask; else EHalluc_resistance &= ~mask; } else { if (!EHalluc_resistance && (!!HHallucination != !!xtime)) changed = TRUE; set_itimeout(&HHallucination, xtime); /* clearing temporary hallucination without toggling vision */ if (!changed && !HHallucination && old && talk) { if (!haseyes(youmonst.data)) { strange_feeling((struct obj *) 0, (char *) 0); } else if (Blind) { const char *eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); Your(eyemsg, eyes, vtense(eyes, "itch")); } else { /* Grayswandir */ Your(vismsg, "flatten", "normal"); } } } if (changed) { /* in case we're mimicking an orange (hallucinatory form of mimicking gold) update the mimicking's-over message */ if (!Hallucination) eatmupdate(); if (u.uswallow) { swallowed(0); /* redraw swallow display */ } else { /* The see_* routines should be called *before* the pline. */ see_monsters(); see_objects(); see_traps(); } /* for perm_inv and anything similar (eg. Qt windowport's equipped items display) */ update_inventory(); context.botl = 1; if (talk) pline(message, verb); } return changed; } void make_deaf(xtime, talk) long xtime; boolean talk; { long old = HDeaf; boolean toggled = FALSE; if (Unaware) talk = FALSE; if (!xtime && old) { if (talk) You("can hear again."); toggled = TRUE; } else if (xtime && !old) { if (talk) You("are unable to hear anything."); toggled = TRUE; } /* deafness isn't presently shown on status line, but request a status update in case that changes someday */ if (toggled) context.botl = TRUE; set_itimeout(&HDeaf, xtime); } STATIC_OVL void ghost_from_bottle() { struct monst *mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS); if (!mtmp) { pline("This bottle turns out to be empty."); return; } if (Blind) { pline("As you open the bottle, %s emerges.", something); return; } pline("As you open the bottle, an enormous %s emerges!", Hallucination ? rndmonnam(NULL) : (const char *) "ghost"); if (flags.verbose) You("are frightened to death, and unable to move."); nomul(-3); multi_reason = "being frightened to death"; nomovemsg = "You regain your composure."; } /* "Quaffing is like drinking, except you spill more." - Terry Pratchett */ int dodrink() { register struct obj *otmp; const char *potion_descr; if (Strangled) { pline("If you can't breathe air, how can you drink liquid?"); return 0; } /* Is there a fountain to drink from here? */ if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) /* not as low as floor level but similar restrictions apply */ && can_reach_floor(FALSE)) { if (yn("Drink from the fountain?") == 'y') { drinkfountain(); return 1; } } /* Or a kitchen sink? */ if (IS_SINK(levl[u.ux][u.uy].typ) /* not as low as floor level but similar restrictions apply */ && can_reach_floor(FALSE)) { if (yn("Drink from the sink?") == 'y') { drinksink(); return 1; } } /* Or are you surrounded by water? */ if (Underwater && !u.uswallow) { if (yn("Drink the water around you?") == 'y') { pline("Do you know what lives in this water?"); return 1; } } otmp = getobj(beverages, "drink"); if (!otmp) return 0; /* quan > 1 used to be left to useup(), but we need to force the current potion to be unworn, and don't want to do that for the entire stack when starting with more than 1. [Drinking a wielded potion of polymorph can trigger a shape change which causes hero's weapon to be dropped. In 3.4.x, that led to an "object lost" panic since subsequent useup() was no longer dealing with an inventory item. Unwearing the current potion is intended to keep it in inventory.] */ if (otmp->quan > 1L) { otmp = splitobj(otmp, 1L); otmp->owornmask = 0L; /* rest of original stuck unaffected */ } else if (otmp->owornmask) { remove_worn_item(otmp, FALSE); } otmp->in_use = TRUE; /* you've opened the stopper */ potion_descr = OBJ_DESCR(objects[otmp->otyp]); if (potion_descr) { if (!strcmp(potion_descr, "milky") && !(mvitals[PM_GHOST].mvflags & G_GONE) && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_GHOST].born))) { ghost_from_bottle(); useup(otmp); return 1; } else if (!strcmp(potion_descr, "smoky") && !(mvitals[PM_DJINNI].mvflags & G_GONE) && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_DJINNI].born))) { djinni_from_bottle(otmp); useup(otmp); return 1; } } return dopotion(otmp); } int dopotion(otmp) register struct obj *otmp; { int retval; otmp->in_use = TRUE; nothing = unkn = 0; if ((retval = peffects(otmp)) >= 0) return retval; if (nothing) { unkn++; You("have a %s feeling for a moment, then it passes.", Hallucination ? "normal" : "peculiar"); } if (otmp->dknown && !objects[otmp->otyp].oc_name_known) { if (!unkn) { makeknown(otmp->otyp); more_experienced(0, 10); } else if (!objects[otmp->otyp].oc_uname) docall(otmp); } useup(otmp); return 1; } int peffects(otmp) register struct obj *otmp; { register int i, ii, lim; switch (otmp->otyp) { case POT_RESTORE_ABILITY: case SPE_RESTORE_ABILITY: unkn++; if (otmp->cursed) { pline("Ulch! This makes you feel mediocre!"); break; } else { /* unlike unicorn horn, overrides Fixed_abil */ pline("Wow! This makes you feel %s!", (otmp->blessed) ? (unfixable_trouble_count(FALSE) ? "better" : "great") : "good"); i = rn2(A_MAX); /* start at a random point */ for (ii = 0; ii < A_MAX; ii++) { lim = AMAX(i); if (i == A_STR && u.uhs >= 3) --lim; /* WEAK */ if (ABASE(i) < lim) { ABASE(i) = lim; context.botl = 1; /* only first found if not blessed */ if (!otmp->blessed) break; } if (++i >= A_MAX) i = 0; } } break; case POT_HALLUCINATION: if (Hallucination || Halluc_resistance) nothing++; (void) make_hallucinated( itimeout_incr(HHallucination, rn1(200, 600 - 300 * bcsign(otmp))), TRUE, 0L); break; case POT_WATER: if (!otmp->blessed && !otmp->cursed) { pline("This tastes like water."); u.uhunger += rnd(10); newuhs(FALSE); break; } unkn++; if (is_undead(youmonst.data) || is_demon(youmonst.data) || u.ualign.type == A_CHAOTIC) { if (otmp->blessed) { pline("This burns like acid!"); exercise(A_CON, FALSE); if (u.ulycn >= LOW_PM) { Your("affinity to %s disappears!", makeplural(mons[u.ulycn].mname)); if (youmonst.data == &mons[u.ulycn]) you_unwere(FALSE); u.ulycn = NON_PM; /* cure lycanthropy */ } losehp(Maybe_Half_Phys(d(2, 6)), "potion of holy water", KILLED_BY_AN); } else if (otmp->cursed) { You_feel("quite proud of yourself."); healup(d(2, 6), 0, 0, 0); if (u.ulycn >= LOW_PM && !Upolyd) you_were(); exercise(A_CON, TRUE); } } else { if (otmp->blessed) { You_feel("full of awe."); make_sick(0L, (char *) 0, TRUE, SICK_ALL); exercise(A_WIS, TRUE); exercise(A_CON, TRUE); if (u.ulycn >= LOW_PM) you_unwere(TRUE); /* "Purified" */ /* make_confused(0L, TRUE); */ } else { if (u.ualign.type == A_LAWFUL) { pline("This burns like acid!"); losehp(Maybe_Half_Phys(d(2, 6)), "potion of unholy water", KILLED_BY_AN); } else You_feel("full of dread."); if (u.ulycn >= LOW_PM && !Upolyd) you_were(); exercise(A_CON, FALSE); } } break; case POT_BOOZE: unkn++; pline("Ooph! This tastes like %s%s!", otmp->odiluted ? "watered down " : "", Hallucination ? "dandelion wine" : "liquid fire"); if (!otmp->blessed) make_confused(itimeout_incr(HConfusion, d(3, 8)), FALSE); /* the whiskey makes us feel better */ if (!otmp->odiluted) healup(1, 0, FALSE, FALSE); u.uhunger += 10 * (2 + bcsign(otmp)); newuhs(FALSE); exercise(A_WIS, FALSE); if (otmp->cursed) { You("pass out."); multi = -rnd(15); nomovemsg = "You awake with a headache."; } break; case POT_ENLIGHTENMENT: if (otmp->cursed) { unkn++; You("have an uneasy feeling..."); exercise(A_WIS, FALSE); } else { if (otmp->blessed) { (void) adjattrib(A_INT, 1, FALSE); (void) adjattrib(A_WIS, 1, FALSE); } You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); pline_The("feeling subsides."); exercise(A_WIS, TRUE); } break; case SPE_INVISIBILITY: /* spell cannot penetrate mummy wrapping */ if (BInvis && uarmc->otyp == MUMMY_WRAPPING) { You_feel("rather itchy under %s.", yname(uarmc)); break; } /* FALLTHRU */ case POT_INVISIBILITY: if (Invis || Blind || BInvis) { nothing++; } else { self_invis_message(); } if (otmp->blessed) HInvis |= FROMOUTSIDE; else incr_itimeout(&HInvis, rn1(15, 31)); newsym(u.ux, u.uy); /* update position */ if (otmp->cursed) { pline("For some reason, you feel your presence is known."); aggravate(); } break; case POT_SEE_INVISIBLE: /* tastes like fruit juice in Rogue */ case POT_FRUIT_JUICE: { int msg = Invisible && !Blind; unkn++; if (otmp->cursed) pline("Yecch! This tastes %s.", Hallucination ? "overripe" : "rotten"); else pline( Hallucination ? "This tastes like 10%% real %s%s all-natural beverage." : "This tastes like %s%s.", otmp->odiluted ? "reconstituted " : "", fruitname(TRUE)); if (otmp->otyp == POT_FRUIT_JUICE) { u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp)); newuhs(FALSE); break; } if (!otmp->cursed) { /* Tell them they can see again immediately, which * will help them identify the potion... */ make_blinded(0L, TRUE); } if (otmp->blessed) HSee_invisible |= FROMOUTSIDE; else incr_itimeout(&HSee_invisible, rn1(100, 750)); set_mimic_blocking(); /* do special mimic handling */ see_monsters(); /* see invisible monsters */ newsym(u.ux, u.uy); /* see yourself! */ if (msg && !Blind) { /* Blind possible if polymorphed */ You("can see through yourself, but you are visible!"); unkn--; } break; } case POT_PARALYSIS: if (Free_action) { You("stiffen momentarily."); } else { if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) You("are motionlessly suspended."); else if (u.usteed) You("are frozen in place!"); else Your("%s are frozen to the %s!", makeplural(body_part(FOOT)), surface(u.ux, u.uy)); nomul(-(rn1(10, 25 - 12 * bcsign(otmp)))); multi_reason = "frozen by a potion"; nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } break; case POT_SLEEPING: if (Sleep_resistance || Free_action) { You("yawn."); } else { You("suddenly fall asleep!"); fall_asleep(-rn1(10, 25 - 12 * bcsign(otmp)), TRUE); } break; case POT_MONSTER_DETECTION: case SPE_DETECT_MONSTERS: if (otmp->blessed) { int x, y; if (Detect_monsters) nothing++; unkn++; /* after a while, repeated uses become less effective */ if ((HDetect_monsters & TIMEOUT) >= 300L) i = 1; else i = rn1(40, 21); incr_itimeout(&HDetect_monsters, i); for (x = 1; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { if (levl[x][y].glyph == GLYPH_INVISIBLE) { unmap_object(x, y); newsym(x, y); } if (MON_AT(x, y)) unkn = 0; } } see_monsters(); if (unkn) You_feel("lonely."); break; } if (monster_detect(otmp, 0)) return 1; /* nothing detected */ exercise(A_WIS, TRUE); break; case POT_OBJECT_DETECTION: case SPE_DETECT_TREASURE: if (object_detect(otmp, 0)) return 1; /* nothing detected */ exercise(A_WIS, TRUE); break; case POT_SICKNESS: pline("Yecch! This stuff tastes like poison."); if (otmp->blessed) { pline("(But in fact it was mildly stale %s.)", fruitname(TRUE)); if (!Role_if(PM_HEALER)) { /* NB: blessed otmp->fromsink is not possible */ losehp(1, "mildly contaminated potion", KILLED_BY_AN); } } else { if (Poison_resistance) pline("(But in fact it was biologically contaminated %s.)", fruitname(TRUE)); if (Role_if(PM_HEALER)) { pline("Fortunately, you have been immunized."); } else { char contaminant[BUFSZ]; int typ = rn2(A_MAX); Sprintf(contaminant, "%s%s", (Poison_resistance) ? "mildly " : "", (otmp->fromsink) ? "contaminated tap water" : "contaminated potion"); if (!Fixed_abil) { poisontell(typ, FALSE); (void) adjattrib(typ, Poison_resistance ? -1 : -rn1(4, 3), 1); } if (!Poison_resistance) { if (otmp->fromsink) losehp(rnd(10) + 5 * !!(otmp->cursed), contaminant, KILLED_BY); else losehp(rnd(10) + 5 * !!(otmp->cursed), contaminant, KILLED_BY_AN); } else { /* rnd loss is so that unblessed poorer than blessed */ losehp(1 + rn2(2), contaminant, (otmp->fromsink) ? KILLED_BY : KILLED_BY_AN); } exercise(A_CON, FALSE); } } if (Hallucination) { You("are shocked back to your senses!"); (void) make_hallucinated(0L, FALSE, 0L); } break; case POT_CONFUSION: if (!Confusion) { if (Hallucination) { pline("What a trippy feeling!"); unkn++; } else pline("Huh, What? Where am I?"); } else nothing++; make_confused(itimeout_incr(HConfusion, rn1(7, 16 - 8 * bcsign(otmp))), FALSE); break; case POT_GAIN_ABILITY: if (otmp->cursed) { pline("Ulch! That potion tasted foul!"); unkn++; } else if (Fixed_abil) { nothing++; } else { /* If blessed, increase all; if not, try up to */ int itmp; /* 6 times to find one which can be increased. */ i = -1; /* increment to 0 */ for (ii = A_MAX; ii > 0; ii--) { i = (otmp->blessed ? i + 1 : rn2(A_MAX)); /* only give "your X is already as high as it can get" message on last attempt (except blessed potions) */ itmp = (otmp->blessed || ii == 1) ? 0 : -1; if (adjattrib(i, 1, itmp) && !otmp->blessed) break; } } break; case POT_SPEED: if (Wounded_legs && !otmp->cursed && !u.usteed) { /* heal_legs() would heal steeds legs */ heal_legs(); unkn++; break; } /* FALLTHRU */ case SPE_HASTE_SELF: if (!Very_fast) { /* wwf@doe.carleton.ca */ You("are suddenly moving %sfaster.", Fast ? "" : "much "); } else { Your("%s get new energy.", makeplural(body_part(LEG))); unkn++; } exercise(A_DEX, TRUE); incr_itimeout(&HFast, rn1(10, 100 + 60 * bcsign(otmp))); break; case POT_BLINDNESS: if (Blind) nothing++; make_blinded(itimeout_incr(Blinded, rn1(200, 250 - 125 * bcsign(otmp))), (boolean) !Blind); break; case POT_GAIN_LEVEL: if (otmp->cursed) { unkn++; /* they went up a level */ if ((ledger_no(&u.uz) == 1 && u.uhave.amulet) || Can_rise_up(u.ux, u.uy, &u.uz)) { const char *riseup = "rise up, through the %s!"; if (ledger_no(&u.uz) == 1) { You(riseup, ceiling(u.ux, u.uy)); goto_level(&earth_level, FALSE, FALSE, FALSE); } else { register int newlev = depth(&u.uz) - 1; d_level newlevel; get_level(&newlevel, newlev); if (on_level(&newlevel, &u.uz)) { pline("It tasted bad."); break; } else You(riseup, ceiling(u.ux, u.uy)); goto_level(&newlevel, FALSE, FALSE, FALSE); } } else You("have an uneasy feeling."); break; } pluslvl(FALSE); /* blessed potions place you at a random spot in the middle of the new level instead of the low point */ if (otmp->blessed) u.uexp = rndexp(TRUE); break; case POT_HEALING: You_feel("better."); healup(d(6 + 2 * bcsign(otmp), 4), !otmp->cursed ? 1 : 0, !!otmp->blessed, !otmp->cursed); exercise(A_CON, TRUE); break; case POT_EXTRA_HEALING: You_feel("much better."); healup(d(6 + 2 * bcsign(otmp), 8), otmp->blessed ? 5 : !otmp->cursed ? 2 : 0, !otmp->cursed, TRUE); (void) make_hallucinated(0L, TRUE, 0L); exercise(A_CON, TRUE); exercise(A_STR, TRUE); break; case POT_FULL_HEALING: You_feel("completely healed."); healup(400, 4 + 4 * bcsign(otmp), !otmp->cursed, TRUE); /* Restore one lost level if blessed */ if (otmp->blessed && u.ulevel < u.ulevelmax) { /* when multiple levels have been lost, drinking multiple potions will only get half of them back */ u.ulevelmax -= 1; pluslvl(FALSE); } (void) make_hallucinated(0L, TRUE, 0L); exercise(A_STR, TRUE); exercise(A_CON, TRUE); break; case POT_LEVITATION: case SPE_LEVITATION: if (otmp->cursed) HLevitation &= ~I_SPECIAL; if (!Levitation && !BLevitation) { /* kludge to ensure proper operation of float_up() */ set_itimeout(&HLevitation, 1L); float_up(); /* reverse kludge */ set_itimeout(&HLevitation, 0L); if (otmp->cursed) { if ((u.ux == xupstair && u.uy == yupstair) || (sstairs.up && u.ux == sstairs.sx && u.uy == sstairs.sy) || (xupladder && u.ux == xupladder && u.uy == yupladder)) { (void) doup(); } else if (has_ceiling(&u.uz)) { int dmg = uarmh ? 1 : rnd(10); You("hit your %s on the %s.", body_part(HEAD), ceiling(u.ux, u.uy)); losehp(Maybe_Half_Phys(dmg), "colliding with the ceiling", KILLED_BY); } } /*cursed*/ } else nothing++; if (otmp->blessed) { incr_itimeout(&HLevitation, rn1(50, 250)); HLevitation |= I_SPECIAL; } else incr_itimeout(&HLevitation, rn1(140, 10)); if (Levitation) spoteffects(FALSE); /* for sinks */ float_vs_flight(); break; case POT_GAIN_ENERGY: { /* M. Stephenson */ int num; if (otmp->cursed) You_feel("lackluster."); else pline("Magical energies course through your body."); /* old: num = rnd(5) + 5 * otmp->blessed + 1; * blessed: +7..11 max & current (+9 avg) * uncursed: +2.. 6 max & current (+4 avg) * cursed: -2.. 6 max & current (-4 avg) * new: (3.6.0) * blessed: +3..18 max (+10.5 avg), +9..54 current (+31.5 avg) * uncursed: +2..12 max (+ 7 avg), +6..36 current (+21 avg) * cursed: -1.. 6 max (- 3.5 avg), -3..18 current (-10.5 avg) */ num = d(otmp->blessed ? 3 : !otmp->cursed ? 2 : 1, 6); if (otmp->cursed) num = -num; /* subtract instead of add when cursed */ u.uenmax += num; if (u.uenmax <= 0) u.uenmax = 0; u.uen += 3 * num; if (u.uen > u.uenmax) u.uen = u.uenmax; else if (u.uen <= 0) u.uen = 0; context.botl = 1; exercise(A_WIS, TRUE); break; } case POT_OIL: { /* P. Winner */ boolean good_for_you = FALSE; if (otmp->lamplit) { if (likes_fire(youmonst.data)) { pline("Ahh, a refreshing drink."); good_for_you = TRUE; } else { You("burn your %s.", body_part(FACE)); /* fire damage */ losehp(d(Fire_resistance ? 1 : 3, 4), "burning potion of oil", KILLED_BY_AN); } } else if (otmp->cursed) pline("This tastes like castor oil."); else pline("That was smooth!"); exercise(A_WIS, good_for_you); break; } case POT_ACID: if (Acid_resistance) { /* Not necessarily a creature who _likes_ acid */ pline("This tastes %s.", Hallucination ? "tangy" : "sour"); } else { int dmg; pline("This burns%s!", otmp->blessed ? " a little" : otmp->cursed ? " a lot" : " like acid"); dmg = d(otmp->cursed ? 2 : 1, otmp->blessed ? 4 : 8); losehp(Maybe_Half_Phys(dmg), "potion of acid", KILLED_BY_AN); exercise(A_CON, FALSE); } if (Stoned) fix_petrification(); unkn++; /* holy/unholy water can burn like acid too */ break; case POT_POLYMORPH: You_feel("a little %s.", Hallucination ? "normal" : "strange"); if (!Unchanging) polyself(0); break; default: impossible("What a funny potion! (%u)", otmp->otyp); return 0; } return -1; } void healup(nhp, nxtra, curesick, cureblind) int nhp, nxtra; register boolean curesick, cureblind; { if (nhp) { if (Upolyd) { u.mh += nhp; if (u.mh > u.mhmax) u.mh = (u.mhmax += nxtra); } else { u.uhp += nhp; if (u.uhp > u.uhpmax) u.uhp = (u.uhpmax += nxtra); } } if (cureblind) make_blinded(0L, TRUE); if (curesick) { make_vomiting(0L, TRUE); make_sick(0L, (char *) 0, TRUE, SICK_ALL); } context.botl = 1; return; } void strange_feeling(obj, txt) struct obj *obj; const char *txt; { if (flags.beginner || !txt) You("have a %s feeling for a moment, then it passes.", Hallucination ? "normal" : "strange"); else pline1(txt); if (!obj) /* e.g., crystal ball finds no traps */ return; if (obj->dknown && !objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) docall(obj); useup(obj); } const char *bottlenames[] = { "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial" }; const char * bottlename() { return bottlenames[rn2(SIZE(bottlenames))]; } /* handle item dipped into water potion or steed saddle splashed by same */ STATIC_OVL boolean H2Opotion_dip(potion, targobj, useeit, objphrase) struct obj *potion, *targobj; boolean useeit; const char *objphrase; /* "Your widget glows" or "Steed's saddle glows" */ { void FDECL((*func), (OBJ_P)) = 0; const char *glowcolor = 0; #define COST_alter (-2) #define COST_none (-1) int costchange = COST_none; boolean altfmt = FALSE, res = FALSE; if (!potion || potion->otyp != POT_WATER) return FALSE; if (potion->blessed) { if (targobj->cursed) { func = uncurse; glowcolor = NH_AMBER; costchange = COST_UNCURS; } else if (!targobj->blessed) { func = bless; glowcolor = NH_LIGHT_BLUE; costchange = COST_alter; altfmt = TRUE; /* "with a aura" */ } } else if (potion->cursed) { if (targobj->blessed) { func = unbless; glowcolor = "brown"; costchange = COST_UNBLSS; } else if (!targobj->cursed) { func = curse; glowcolor = NH_BLACK; costchange = COST_alter; altfmt = TRUE; } } else { /* dipping into uncursed water; carried() check skips steed saddle */ if (carried(targobj)) { if (water_damage(targobj, 0, TRUE) != ER_NOTHING) res = TRUE; } } if (func) { /* give feedback before altering the target object; this used to set obj->bknown even when not seeing the effect; now hero has to see the glow, and bknown is cleared instead of set if perception is distorted */ if (useeit) { glowcolor = hcolor(glowcolor); if (altfmt) pline("%s with %s aura.", objphrase, an(glowcolor)); else pline("%s %s.", objphrase, glowcolor); iflags.last_msg = PLNMSG_OBJ_GLOWS; targobj->bknown = !Hallucination; } /* potions of water are the only shop goods whose price depends on their curse/bless state */ if (targobj->unpaid && targobj->otyp == POT_WATER) { if (costchange == COST_alter) /* added blessing or cursing; update shop bill to reflect item's new higher price */ alter_cost(targobj, 0L); else if (costchange != COST_none) /* removed blessing or cursing; you degraded it, now you'll have to buy it... */ costly_alteration(targobj, costchange); } /* finally, change curse/bless state */ (*func)(targobj); res = TRUE; } return res; } void potionhit(mon, obj, your_fault) register struct monst *mon; register struct obj *obj; boolean your_fault; { const char *botlnam = bottlename(); boolean isyou = (mon == &youmonst); int distance; struct obj *saddle = (struct obj *) 0; boolean hit_saddle = FALSE; if (isyou) { distance = 0; pline_The("%s crashes on your %s and breaks into shards.", botlnam, body_part(HEAD)); losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN); } else { /* sometimes it hits the saddle */ if (((mon->misc_worn_check & W_SADDLE) && (saddle = which_armor(mon, W_SADDLE))) && (!rn2(10) || (obj->otyp == POT_WATER && ((rnl(10) > 7 && obj->cursed) || (rnl(10) < 4 && obj->blessed) || !rn2(3))))) hit_saddle = TRUE; distance = distu(mon->mx, mon->my); if (!cansee(mon->mx, mon->my)) pline("Crash!"); else { char *mnam = mon_nam(mon); char buf[BUFSZ]; if (hit_saddle && saddle) { Sprintf(buf, "%s saddle", s_suffix(x_monnam(mon, ARTICLE_THE, (char *) 0, (SUPPRESS_IT | SUPPRESS_SADDLE), FALSE))); } else if (has_head(mon->data)) { Sprintf(buf, "%s %s", s_suffix(mnam), (notonhead ? "body" : "head")); } else { Strcpy(buf, mnam); } pline_The("%s crashes on %s and breaks into shards.", botlnam, buf); } if (rn2(5) && mon->mhp > 1 && !hit_saddle) mon->mhp--; } /* oil doesn't instantly evaporate; Neither does a saddle hit */ if (obj->otyp != POT_OIL && !hit_saddle && cansee(mon->mx, mon->my)) pline("%s.", Tobjnam(obj, "evaporate")); if (isyou) { switch (obj->otyp) { case POT_OIL: if (obj->lamplit) explode_oil(obj, u.ux, u.uy); break; case POT_POLYMORPH: You_feel("a little %s.", Hallucination ? "normal" : "strange"); if (!Unchanging && !Antimagic) polyself(0); break; case POT_ACID: if (!Acid_resistance) { int dmg; pline("This burns%s!", obj->blessed ? " a little" : obj->cursed ? " a lot" : ""); dmg = d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8); losehp(Maybe_Half_Phys(dmg), "potion of acid", KILLED_BY_AN); } break; } } else if (hit_saddle && saddle) { char *mnam, buf[BUFSZ], saddle_glows[BUFSZ]; boolean affected = FALSE; boolean useeit = !Blind && canseemon(mon) && cansee(mon->mx, mon->my); mnam = x_monnam(mon, ARTICLE_THE, (char *) 0, (SUPPRESS_IT | SUPPRESS_SADDLE), FALSE); Sprintf(buf, "%s", upstart(s_suffix(mnam))); switch (obj->otyp) { case POT_WATER: Sprintf(saddle_glows, "%s %s", buf, aobjnam(saddle, "glow")); affected = H2Opotion_dip(obj, saddle, useeit, saddle_glows); break; case POT_POLYMORPH: /* Do we allow the saddle to polymorph? */ break; } if (useeit && !affected) pline("%s %s wet.", buf, aobjnam(saddle, "get")); } else { boolean angermon = TRUE; if (!your_fault) angermon = FALSE; switch (obj->otyp) { case POT_HEALING: case POT_EXTRA_HEALING: case POT_FULL_HEALING: if (mon->data == &mons[PM_PESTILENCE]) goto do_illness; /*FALLTHRU*/ case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: do_healing: angermon = FALSE; if (mon->mhp < mon->mhpmax) { mon->mhp = mon->mhpmax; if (canseemon(mon)) pline("%s looks sound and hale again.", Monnam(mon)); } break; case POT_SICKNESS: if (mon->data == &mons[PM_PESTILENCE]) goto do_healing; if (dmgtype(mon->data, AD_DISE) /* won't happen, see prior goto */ || dmgtype(mon->data, AD_PEST) /* most common case */ || resists_poison(mon)) { if (canseemon(mon)) pline("%s looks unharmed.", Monnam(mon)); break; } do_illness: if ((mon->mhpmax > 3) && !resist(mon, POTION_CLASS, 0, NOTELL)) mon->mhpmax /= 2; if ((mon->mhp > 2) && !resist(mon, POTION_CLASS, 0, NOTELL)) mon->mhp /= 2; if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (canseemon(mon)) pline("%s looks rather ill.", Monnam(mon)); break; case POT_CONFUSION: case POT_BOOZE: if (!resist(mon, POTION_CLASS, 0, NOTELL)) mon->mconf = TRUE; break; case POT_INVISIBILITY: angermon = FALSE; mon_set_minvis(mon); break; case POT_SLEEPING: /* wakeup() doesn't rouse victims of temporary sleep */ if (sleep_monst(mon, rnd(12), POTION_CLASS)) { pline("%s falls asleep.", Monnam(mon)); slept_monst(mon); } break; case POT_PARALYSIS: if (mon->mcanmove) { /* really should be rnd(5) for consistency with players * breathing potions, but... */ paralyze_monst(mon, rnd(25)); } break; case POT_SPEED: angermon = FALSE; mon_adjust_speed(mon, 1, obj); break; case POT_BLINDNESS: if (haseyes(mon->data)) { register int btmp = 64 + rn2(32) + rn2(32) * !resist(mon, POTION_CLASS, 0, NOTELL); btmp += mon->mblinded; mon->mblinded = min(btmp, 127); mon->mcansee = 0; } break; case POT_WATER: if (is_undead(mon->data) || is_demon(mon->data) || is_were(mon->data) || is_vampshifter(mon)) { if (obj->blessed) { pline("%s %s in pain!", Monnam(mon), is_silent(mon->data) ? "writhes" : "shrieks"); if (!is_silent(mon->data)) wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10); mon->mhp -= d(2, 6); /* should only be by you */ if (mon->mhp < 1) killed(mon); else if (is_were(mon->data) && !is_human(mon->data)) new_were(mon); /* revert to human */ } else if (obj->cursed) { angermon = FALSE; if (canseemon(mon)) pline("%s looks healthier.", Monnam(mon)); mon->mhp += d(2, 6); if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (is_were(mon->data) && is_human(mon->data) && !Protection_from_shape_changers) new_were(mon); /* transform into beast */ } } else if (mon->data == &mons[PM_GREMLIN]) { angermon = FALSE; (void) split_mon(mon, (struct monst *) 0); } else if (mon->data == &mons[PM_IRON_GOLEM]) { if (canseemon(mon)) pline("%s rusts.", Monnam(mon)); mon->mhp -= d(1, 6); /* should only be by you */ if (mon->mhp < 1) killed(mon); } break; case POT_OIL: if (obj->lamplit) explode_oil(obj, mon->mx, mon->my); break; case POT_ACID: if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) { pline("%s %s in pain!", Monnam(mon), is_silent(mon->data) ? "writhes" : "shrieks"); if (!is_silent(mon->data)) wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10); mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8); if (mon->mhp < 1) { if (your_fault) killed(mon); else monkilled(mon, "", AD_ACID); } } break; case POT_POLYMORPH: (void) bhitm(mon, obj); break; /* case POT_GAIN_LEVEL: case POT_LEVITATION: case POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case POT_OBJECT_DETECTION: break; */ } if (angermon) wakeup(mon); else mon->msleeping = 0; } /* Note: potionbreathe() does its own docall() */ if ((distance == 0 || ((distance < 3) && rn2(5))) && (!breathless(youmonst.data) || haseyes(youmonst.data))) potionbreathe(obj); else if (obj->dknown && !objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname && cansee(mon->mx, mon->my)) docall(obj); if (*u.ushops && obj->unpaid) { struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); if (shkp) (void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful, FALSE); else obj->unpaid = 0; } obfree(obj, (struct obj *) 0); } /* vapors are inhaled or get in your eyes */ void potionbreathe(obj) register struct obj *obj; { register int i, ii, isdone, kn = 0; switch (obj->otyp) { case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: if (obj->cursed) { if (!breathless(youmonst.data)) pline("Ulch! That potion smells terrible!"); else if (haseyes(youmonst.data)) { const char *eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); Your("%s %s!", eyes, vtense(eyes, "sting")); } break; } else { i = rn2(A_MAX); /* start at a random point */ for (isdone = ii = 0; !isdone && ii < A_MAX; ii++) { if (ABASE(i) < AMAX(i)) { ABASE(i)++; /* only first found if not blessed */ isdone = !(obj->blessed); context.botl = 1; } if (++i >= A_MAX) i = 0; } } break; case POT_FULL_HEALING: if (Upolyd && u.mh < u.mhmax) u.mh++, context.botl = 1; if (u.uhp < u.uhpmax) u.uhp++, context.botl = 1; /*FALLTHRU*/ case POT_EXTRA_HEALING: if (Upolyd && u.mh < u.mhmax) u.mh++, context.botl = 1; if (u.uhp < u.uhpmax) u.uhp++, context.botl = 1; /*FALLTHRU*/ case POT_HEALING: if (Upolyd && u.mh < u.mhmax) u.mh++, context.botl = 1; if (u.uhp < u.uhpmax) u.uhp++, context.botl = 1; exercise(A_CON, TRUE); break; case POT_SICKNESS: if (!Role_if(PM_HEALER)) { if (Upolyd) { if (u.mh <= 5) u.mh = 1; else u.mh -= 5; } else { if (u.uhp <= 5) u.uhp = 1; else u.uhp -= 5; } context.botl = 1; exercise(A_CON, FALSE); } break; case POT_HALLUCINATION: You("have a momentary vision."); break; case POT_CONFUSION: case POT_BOOZE: if (!Confusion) You_feel("somewhat dizzy."); make_confused(itimeout_incr(HConfusion, rnd(5)), FALSE); break; case POT_INVISIBILITY: if (!Blind && !Invis) { kn++; pline("For an instant you %s!", See_invisible ? "could see right through yourself" : "couldn't see yourself"); } break; case POT_PARALYSIS: kn++; if (!Free_action) { pline("%s seems to be holding you.", Something); nomul(-rnd(5)); multi_reason = "frozen by a potion"; nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } else You("stiffen momentarily."); break; case POT_SLEEPING: kn++; if (!Free_action && !Sleep_resistance) { You_feel("rather tired."); nomul(-rnd(5)); multi_reason = "sleeping off a magical draught"; nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } else You("yawn."); break; case POT_SPEED: if (!Fast) Your("knees seem more flexible now."); incr_itimeout(&HFast, rnd(5)); exercise(A_DEX, TRUE); break; case POT_BLINDNESS: if (!Blind && !Unaware) { kn++; pline("It suddenly gets dark."); } make_blinded(itimeout_incr(Blinded, rnd(5)), FALSE); if (!Blind && !Unaware) Your1(vision_clears); break; case POT_WATER: if (u.umonnum == PM_GREMLIN) { (void) split_mon(&youmonst, (struct monst *) 0); } else if (u.ulycn >= LOW_PM) { /* vapor from [un]holy water will trigger transformation but won't cure lycanthropy */ if (obj->blessed && youmonst.data == &mons[u.ulycn]) you_unwere(FALSE); else if (obj->cursed && !Upolyd) you_were(); } break; case POT_ACID: case POT_POLYMORPH: exercise(A_CON, FALSE); break; /* case POT_GAIN_LEVEL: case POT_LEVITATION: case POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case POT_OBJECT_DETECTION: case POT_OIL: break; */ } /* note: no obfree() */ if (obj->dknown) { if (kn) makeknown(obj->otyp); else if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) docall(obj); } } /* returns the potion type when o1 is dipped in o2 */ STATIC_OVL short mixtype(o1, o2) register struct obj *o1, *o2; { /* cut down on the number of cases below */ if (o1->oclass == POTION_CLASS && (o2->otyp == POT_GAIN_LEVEL || o2->otyp == POT_GAIN_ENERGY || o2->otyp == POT_HEALING || o2->otyp == POT_EXTRA_HEALING || o2->otyp == POT_FULL_HEALING || o2->otyp == POT_ENLIGHTENMENT || o2->otyp == POT_FRUIT_JUICE)) { struct obj *swp; swp = o1; o1 = o2; o2 = swp; } switch (o1->otyp) { case POT_HEALING: switch (o2->otyp) { case POT_SPEED: case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_EXTRA_HEALING; } case POT_EXTRA_HEALING: switch (o2->otyp) { case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_FULL_HEALING; } case POT_FULL_HEALING: switch (o2->otyp) { case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_GAIN_ABILITY; } case UNICORN_HORN: switch (o2->otyp) { case POT_SICKNESS: return POT_FRUIT_JUICE; case POT_HALLUCINATION: case POT_BLINDNESS: case POT_CONFUSION: return POT_WATER; } break; case AMETHYST: /* "a-methyst" == "not intoxicated" */ if (o2->otyp == POT_BOOZE) return POT_FRUIT_JUICE; break; case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: switch (o2->otyp) { case POT_CONFUSION: return (rn2(3) ? POT_BOOZE : POT_ENLIGHTENMENT); case POT_HEALING: return POT_EXTRA_HEALING; case POT_EXTRA_HEALING: return POT_FULL_HEALING; case POT_FULL_HEALING: return POT_GAIN_ABILITY; case POT_FRUIT_JUICE: return POT_SEE_INVISIBLE; case POT_BOOZE: return POT_HALLUCINATION; } break; case POT_FRUIT_JUICE: switch (o2->otyp) { case POT_SICKNESS: return POT_SICKNESS; case POT_SPEED: return POT_BOOZE; case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_SEE_INVISIBLE; } break; case POT_ENLIGHTENMENT: switch (o2->otyp) { case POT_LEVITATION: if (rn2(3)) return POT_GAIN_LEVEL; break; case POT_FRUIT_JUICE: return POT_BOOZE; case POT_BOOZE: return POT_CONFUSION; } break; } return 0; } /* #dip command */ int dodip() { register struct obj *potion, *obj; struct obj *singlepotion; uchar here; char allowall[2]; short mixture; char qbuf[QBUFSZ], qtoo[QBUFSZ]; allowall[0] = ALL_CLASSES; allowall[1] = '\0'; if (!(obj = getobj(allowall, "dip"))) return 0; if (inaccessible_equipment(obj, "dip", FALSE)) return 0; Sprintf(qbuf, "dip %s into", thesimpleoname(obj)); here = levl[u.ux][u.uy].typ; /* Is there a fountain to dip into here? */ if (IS_FOUNTAIN(here)) { /* "Dip into the fountain?" */ Sprintf(qtoo, "%s the fountain?", qbuf); if (yn(upstart(qtoo)) == 'y') { dipfountain(obj); return 1; } } else if (is_pool(u.ux, u.uy)) { const char *pooltype = waterbody_name(u.ux, u.uy); /* "Dip into the {pool, moat, &c}?" */ Sprintf(qtoo, "%s the %s?", qbuf, pooltype); if (yn(upstart(qtoo)) == 'y') { if (Levitation) { floating_above(pooltype); } else if (u.usteed && !is_swimmer(u.usteed->data) && P_SKILL(P_RIDING) < P_BASIC) { rider_cant_reach(); /* not skilled enough to reach */ } else { if (obj->otyp == POT_ACID) obj->in_use = 1; if (water_damage(obj, 0, TRUE) != ER_DESTROYED && obj->in_use) useup(obj); } return 1; } } /* "What do you want to dip into?" */ potion = getobj(beverages, qbuf); /* "dip into" */ if (!potion) return 0; if (potion == obj && potion->quan == 1L) { pline("That is a potion bottle, not a Klein bottle!"); return 0; } potion->in_use = TRUE; /* assume it will be used up */ if (potion->otyp == POT_WATER) { boolean useeit = !Blind || (obj == ublindf && Blindfolded_only); const char *obj_glows = Yobjnam2(obj, "glow"); if (H2Opotion_dip(potion, obj, useeit, obj_glows)) goto poof; } else if (obj->otyp == POT_POLYMORPH || potion->otyp == POT_POLYMORPH) { /* some objects can't be polymorphed */ if (obj->otyp == potion->otyp /* both POT_POLY */ || obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH || obj == uball || obj == uskin || obj_resists(obj->otyp == POT_POLYMORPH ? potion : obj, 5, 95)) { pline1(nothing_happens); } else { boolean was_wep, was_swapwep, was_quiver; short save_otyp = obj->otyp; /* KMH, conduct */ u.uconduct.polypiles++; was_wep = (obj == uwep); was_swapwep = (obj == uswapwep); was_quiver = (obj == uquiver); obj = poly_obj(obj, STRANGE_OBJECT); if (was_wep) setuwep(obj); else if (was_swapwep) setuswapwep(obj); else if (was_quiver) setuqwep(obj); if (obj->otyp != save_otyp) { makeknown(POT_POLYMORPH); useup(potion); prinv((char *) 0, obj, 0L); return 1; } else { pline("Nothing seems to happen."); goto poof; } } potion->in_use = FALSE; /* didn't go poof */ return 1; } else if (obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) { long amt = obj->quan; Strcpy(qbuf, "The"); if (amt > (objects[potion->otyp].oc_magic ? 2L : 9L)) { /* trying to dip multiple potions will usually affect only a subset; pick an amount between 2 and min(N,9), inclusive */ amt -= 1L; do { amt = (long) rnd((int) amt); } while (amt >= 9L); amt += 1L; if (amt < obj->quan) { obj = splitobj(obj, amt); Sprintf(qbuf, "%ld of the", obj->quan); } } /* [N of] the {obj(s)} mix(es) with [one of] {the potion}... */ pline("%s %s %s with %s%s...", qbuf, simpleonames(obj), otense(obj, "mix"), (potion->quan > 1L) ? "one of " : "", thesimpleoname(potion)); /* Mixing potions is dangerous... KMH, balance patch -- acid is particularly unstable */ if (obj->cursed || obj->otyp == POT_ACID || !rn2(10)) { /* it would be better to use up the whole stack in advance of the message, but we can't because we need to keep it around for potionbreathe() [and we can't set obj->in_use to 'amt' because that's not implemented] */ obj->in_use = 1; pline("BOOM! They explode!"); wake_nearto(u.ux, u.uy, (BOLT_LIM + 1) * (BOLT_LIM + 1)); exercise(A_STR, FALSE); if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(obj); useupall(obj); useup(potion); losehp((int) (amt + rnd(9)), /* not physical damage */ "alchemic blast", KILLED_BY_AN); return 1; } obj->blessed = obj->cursed = obj->bknown = 0; if (Blind || Hallucination) obj->dknown = 0; if ((mixture = mixtype(obj, potion)) != 0) { obj->otyp = mixture; } else { switch (obj->odiluted ? 1 : rnd(8)) { case 1: obj->otyp = POT_WATER; break; case 2: case 3: obj->otyp = POT_SICKNESS; break; case 4: { struct obj *otmp = mkobj(POTION_CLASS, FALSE); obj->otyp = otmp->otyp; obfree(otmp, (struct obj *) 0); break; } default: useupall(obj); useup(potion); if (!Blind) pline_The("mixture glows brightly and evaporates."); return 1; } } obj->odiluted = (obj->otyp != POT_WATER); if (obj->otyp == POT_WATER && !Hallucination) { pline_The("mixture bubbles%s.", Blind ? "" : ", then clears"); } else if (!Blind) { pline_The("mixture looks %s.", hcolor(OBJ_DESCR(objects[obj->otyp]))); } useup(potion); /* this is required when 'obj' was split off from a bigger stack, so that 'obj' will now be assigned its own inventory slot; it has a side-effect of merging 'obj' into another compatible stack if there is one, so we do it even when no split has been made in order to get the merge result for both cases; as a consequence, mixing while Fumbling drops the mixture */ freeinv(obj); (void) hold_another_object(obj, "You drop %s!", doname(obj), (const char *) 0); return 1; } if (potion->otyp == POT_ACID && obj->otyp == CORPSE && obj->corpsenm == PM_LICHEN && !Blind) { pline("%s %s %s around the edges.", The(cxname(obj)), otense(obj, "turn"), potion->odiluted ? hcolor(NH_ORANGE) : hcolor(NH_RED)); potion->in_use = FALSE; /* didn't go poof */ return 1; } if (potion->otyp == POT_WATER && obj->otyp == TOWEL) { pline_The("towel soaks it up!"); /* wetting towel already done via water_damage() in H2Opotion_dip */ goto poof; } if (is_poisonable(obj)) { if (potion->otyp == POT_SICKNESS && !obj->opoisoned) { char buf[BUFSZ]; if (potion->quan > 1L) Sprintf(buf, "One of %s", the(xname(potion))); else Strcpy(buf, The(xname(potion))); pline("%s forms a coating on %s.", buf, the(xname(obj))); obj->opoisoned = TRUE; goto poof; } else if (obj->opoisoned && (potion->otyp == POT_HEALING || potion->otyp == POT_EXTRA_HEALING || potion->otyp == POT_FULL_HEALING)) { pline("A coating wears off %s.", the(xname(obj))); obj->opoisoned = 0; goto poof; } } if (potion->otyp == POT_ACID) { if (erode_obj(obj, 0, ERODE_CORRODE, EF_GREASE) != ER_NOTHING) goto poof; } if (potion->otyp == POT_OIL) { boolean wisx = FALSE; if (potion->lamplit) { /* burning */ fire_damage(obj, TRUE, u.ux, u.uy); } else if (potion->cursed) { pline_The("potion spills and covers your %s with oil.", makeplural(body_part(FINGER))); incr_itimeout(&Glib, d(2, 10)); } else if (obj->oclass != WEAPON_CLASS && !is_weptool(obj)) { /* the following cases apply only to weapons */ goto more_dips; /* Oil removes rust and corrosion, but doesn't unburn. * Arrows, etc are classed as metallic due to arrowhead * material, but dipping in oil shouldn't repair them. */ } else if ((!is_rustprone(obj) && !is_corrodeable(obj)) || is_ammo(obj) || (!obj->oeroded && !obj->oeroded2)) { /* uses up potion, doesn't set obj->greased */ pline("%s %s with an oily sheen.", Yname2(obj), otense(obj, "gleam")); } else { pline("%s %s less %s.", Yname2(obj), otense(obj, "are"), (obj->oeroded && obj->oeroded2) ? "corroded and rusty" : obj->oeroded ? "rusty" : "corroded"); if (obj->oeroded > 0) obj->oeroded--; if (obj->oeroded2 > 0) obj->oeroded2--; wisx = TRUE; } exercise(A_WIS, wisx); makeknown(potion->otyp); useup(potion); return 1; } more_dips: /* Allow filling of MAGIC_LAMPs to prevent identification by player */ if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP) && (potion->otyp == POT_OIL)) { /* Turn off engine before fueling, turn off fuel too :-) */ if (obj->lamplit || potion->lamplit) { useup(potion); explode(u.ux, u.uy, 11, d(6, 6), 0, EXPL_FIERY); exercise(A_WIS, FALSE); return 1; } /* Adding oil to an empty magic lamp renders it into an oil lamp */ if ((obj->otyp == MAGIC_LAMP) && obj->spe == 0) { obj->otyp = OIL_LAMP; obj->age = 0; } if (obj->age > 1000L) { pline("%s %s full.", Yname2(obj), otense(obj, "are")); potion->in_use = FALSE; /* didn't go poof */ } else { You("fill %s with oil.", yname(obj)); check_unpaid(potion); /* Yendorian Fuel Tax */ obj->age += 2 * potion->age; /* burns more efficiently */ if (obj->age > 1500L) obj->age = 1500L; useup(potion); exercise(A_WIS, TRUE); } makeknown(POT_OIL); obj->spe = 1; update_inventory(); return 1; } potion->in_use = FALSE; /* didn't go poof */ if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST) && (mixture = mixtype(obj, potion)) != 0) { char oldbuf[BUFSZ], newbuf[BUFSZ]; short old_otyp = potion->otyp; boolean old_dknown = FALSE; boolean more_than_one = potion->quan > 1L; oldbuf[0] = '\0'; if (potion->dknown) { old_dknown = TRUE; Sprintf(oldbuf, "%s ", hcolor(OBJ_DESCR(objects[potion->otyp]))); } /* with multiple merged potions, split off one and just clear it */ if (potion->quan > 1L) { singlepotion = splitobj(potion, 1L); } else singlepotion = potion; costly_alteration(singlepotion, COST_NUTRLZ); singlepotion->otyp = mixture; singlepotion->blessed = 0; if (mixture == POT_WATER) singlepotion->cursed = singlepotion->odiluted = 0; else singlepotion->cursed = obj->cursed; /* odiluted left as-is */ singlepotion->bknown = FALSE; if (Blind) { singlepotion->dknown = FALSE; } else { singlepotion->dknown = !Hallucination; if (mixture == POT_WATER && singlepotion->dknown) Sprintf(newbuf, "clears"); else Sprintf(newbuf, "turns %s", hcolor(OBJ_DESCR(objects[mixture]))); pline_The("%spotion%s %s.", oldbuf, more_than_one ? " that you dipped into" : "", newbuf); if (!objects[old_otyp].oc_uname && !objects[old_otyp].oc_name_known && old_dknown) { struct obj fakeobj; fakeobj = zeroobj; fakeobj.dknown = 1; fakeobj.otyp = old_otyp; fakeobj.oclass = POTION_CLASS; docall(&fakeobj); } } obj_extract_self(singlepotion); singlepotion = hold_another_object(singlepotion, "You juggle and drop %s!", doname(singlepotion), (const char *) 0); update_inventory(); return 1; } pline("Interesting..."); return 1; poof: if (!objects[potion->otyp].oc_name_known && !objects[potion->otyp].oc_uname) docall(potion); useup(potion); return 1; } /* *monp grants a wish and then leaves the game */ void mongrantswish(monp) struct monst **monp; { struct monst *mon = *monp; int mx = mon->mx, my = mon->my, glyph = glyph_at(mx, my); /* remove the monster first in case wish proves to be fatal (blasted by artifact), to keep it out of resulting bones file */ mongone(mon); *monp = 0; /* inform caller that monster is gone */ /* hide that removal from player--map is visible during wish prompt */ tmp_at(DISP_ALWAYS, glyph); tmp_at(mx, my); /* grant the wish */ makewish(); /* clean up */ tmp_at(DISP_END, 0); } void djinni_from_bottle(obj) struct obj *obj; { struct monst *mtmp; int chance; if (!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))) { pline("It turns out to be empty."); return; } if (!Blind) { pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp)); pline("%s speaks.", Monnam(mtmp)); } else { You("smell acrid fumes."); pline("%s speaks.", Something); } chance = rn2(5); if (obj->blessed) chance = (chance == 4) ? rnd(4) : 0; else if (obj->cursed) chance = (chance == 0) ? rn2(4) : 4; /* 0,1,2,3,4: b=80%,5,5,5,5; nc=20%,20,20,20,20; c=5%,5,5,5,80 */ switch (chance) { case 0: verbalize("I am in your debt. I will grant one wish!"); /* give a wish and discard the monster (mtmp set to null) */ mongrantswish(&mtmp); break; case 1: verbalize("Thank you for freeing me!"); (void) tamedog(mtmp, (struct obj *) 0); break; case 2: verbalize("You freed me!"); mtmp->mpeaceful = TRUE; set_malign(mtmp); break; case 3: verbalize("It is about time!"); if (canspotmon(mtmp)) pline("%s vanishes.", Monnam(mtmp)); mongone(mtmp); break; default: verbalize("You disturbed me, fool!"); mtmp->mpeaceful = FALSE; set_malign(mtmp); break; } } /* clone a gremlin or mold (2nd arg non-null implies heat as the trigger); hit points are cut in half (odd HP stays with original) */ struct monst * split_mon(mon, mtmp) struct monst *mon, /* monster being split */ *mtmp; /* optional attacker whose heat triggered it */ { struct monst *mtmp2; char reason[BUFSZ]; reason[0] = '\0'; if (mtmp) Sprintf(reason, " from %s heat", (mtmp == &youmonst) ? the_your[1] : (const char *) s_suffix(mon_nam(mtmp))); if (mon == &youmonst) { mtmp2 = cloneu(); if (mtmp2) { mtmp2->mhpmax = u.mhmax / 2; u.mhmax -= mtmp2->mhpmax; context.botl = 1; You("multiply%s!", reason); } } else { mtmp2 = clone_mon(mon, 0, 0); if (mtmp2) { mtmp2->mhpmax = mon->mhpmax / 2; mon->mhpmax -= mtmp2->mhpmax; if (canspotmon(mon)) pline("%s multiplies%s!", Monnam(mon), reason); } } return mtmp2; } /*potion.c*/ nethack-3.6.0/src/pray.c0000664000076400007660000022312612623162643014056 0ustar paxedpaxed/* NetHack 3.6 pray.c $NHDT-Date: 1446854232 2015/11/06 23:57:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(prayer_done); STATIC_DCL struct obj *NDECL(worst_cursed_item); STATIC_DCL int NDECL(in_trouble); STATIC_DCL void FDECL(fix_worst_trouble, (int)); STATIC_DCL void FDECL(angrygods, (ALIGNTYP_P)); STATIC_DCL void FDECL(at_your_feet, (const char *)); STATIC_DCL void NDECL(gcrownu); STATIC_DCL void FDECL(pleased, (ALIGNTYP_P)); STATIC_DCL void FDECL(godvoice, (ALIGNTYP_P, const char *)); STATIC_DCL void FDECL(god_zaps_you, (ALIGNTYP_P)); STATIC_DCL void FDECL(fry_by_god, (ALIGNTYP_P, BOOLEAN_P)); STATIC_DCL void FDECL(gods_angry, (ALIGNTYP_P)); STATIC_DCL void FDECL(gods_upset, (ALIGNTYP_P)); STATIC_DCL void FDECL(consume_offering, (struct obj *)); STATIC_DCL boolean FDECL(water_prayer, (BOOLEAN_P)); STATIC_DCL boolean FDECL(blocked_boulder, (int, int)); /* simplify a few tests */ #define Cursed_obj(obj, typ) ((obj) && (obj)->otyp == (typ) && (obj)->cursed) /* * Logic behind deities and altars and such: * + prayers are made to your god if not on an altar, and to the altar's god * if you are on an altar * + If possible, your god answers all prayers, which is why bad things happen * if you try to pray on another god's altar * + sacrifices work basically the same way, but the other god may decide to * accept your allegiance, after which they are your god. If rejected, * your god takes over with your punishment. * + if you're in Gehennom, all messages come from Moloch */ /* * Moloch, who dwells in Gehennom, is the "renegade" cruel god * responsible for the theft of the Amulet from Marduk, the Creator. * Moloch is unaligned. */ static const char *Moloch = "Moloch"; static const char *godvoices[] = { "booms out", "thunders", "rings out", "booms", }; /* values calculated when prayer starts, and used when completed */ static aligntyp p_aligntyp; static int p_trouble; static int p_type; /* (-1)-3: (-1)=really naughty, 3=really good */ #define PIOUS 20 #define DEVOUT 14 #define FERVENT 9 #define STRIDENT 4 /* * The actual trouble priority is determined by the order of the * checks performed in in_trouble() rather than by these numeric * values, so keep that code and these values synchronized in * order to have the values be meaningful. */ #define TROUBLE_STONED 14 #define TROUBLE_SLIMED 13 #define TROUBLE_STRANGLED 12 #define TROUBLE_LAVA 11 #define TROUBLE_SICK 10 #define TROUBLE_STARVING 9 #define TROUBLE_REGION 8 /* stinking cloud */ #define TROUBLE_HIT 7 #define TROUBLE_LYCANTHROPE 6 #define TROUBLE_COLLAPSING 5 #define TROUBLE_STUCK_IN_WALL 4 #define TROUBLE_CURSED_LEVITATION 3 #define TROUBLE_UNUSEABLE_HANDS 2 #define TROUBLE_CURSED_BLINDFOLD 1 #define TROUBLE_PUNISHED (-1) #define TROUBLE_FUMBLING (-2) #define TROUBLE_CURSED_ITEMS (-3) #define TROUBLE_SADDLE (-4) #define TROUBLE_BLIND (-5) #define TROUBLE_POISONED (-6) #define TROUBLE_WOUNDED_LEGS (-7) #define TROUBLE_HUNGRY (-8) #define TROUBLE_STUNNED (-9) #define TROUBLE_CONFUSED (-10) #define TROUBLE_HALLUCINATION (-11) #define ugod_is_angry() (u.ualign.record < 0) #define on_altar() IS_ALTAR(levl[u.ux][u.uy].typ) #define on_shrine() ((levl[u.ux][u.uy].altarmask & AM_SHRINE) != 0) #define a_align(x, y) ((aligntyp) Amask2align(levl[x][y].altarmask & AM_MASK)) /* critically low hit points if hp <= 5 or hp <= maxhp/N for some N */ boolean critically_low_hp(only_if_injured) boolean only_if_injured; /* determines whether maxhp <= 5 matters */ { int divisor, hplim, curhp = Upolyd ? u.mh : u.uhp, maxhp = Upolyd ? u.mhmax : u.uhpmax; if (only_if_injured && !(curhp < maxhp)) return FALSE; /* if maxhp is extremely high, use lower threshold for the division test (golden glow cuts off at 11+5*lvl, nurse interaction at 25*lvl; this ought to use monster hit dice--and a smaller multiplier--rather than ulevel when polymorphed, but polyself doesn't maintain that) */ hplim = 15 * u.ulevel; if (maxhp > hplim) maxhp = hplim; /* 7 used to be the unconditional divisor */ switch (xlev_to_rank(u.ulevel)) { /* maps 1..30 into 0..8 */ case 0: case 1: divisor = 5; break; /* explvl 1 to 5 */ case 2: case 3: divisor = 6; break; /* explvl 6 to 13 */ case 4: case 5: divisor = 7; break; /* explvl 14 to 21 */ case 6: case 7: divisor = 8; break; /* explvl 22 to 29 */ default: divisor = 9; break; /* explvl 30+ */ } /* 5 is a magic number in TROUBLE_HIT handling below */ return (boolean) (curhp <= 5 || curhp * divisor <= maxhp); } /* * Return 0 if nothing particular seems wrong, positive numbers for * serious trouble, and negative numbers for comparative annoyances. * This returns the worst problem. There may be others, and the gods * may fix more than one. * * This could get as bizarre as noting surrounding opponents, (or * hostile dogs), but that's really hard. * * We could force rehumanize of polyselfed people, but we can't tell * unintentional shape changes from the other kind. Oh well. * 3.4.2: make an exception if polymorphed into a form which lacks * hands; that's a case where the ramifications override this doubt. */ STATIC_OVL int in_trouble() { struct obj *otmp; int i, j, count = 0; /* * major troubles */ if (Stoned) return TROUBLE_STONED; if (Slimed) return TROUBLE_SLIMED; if (Strangled) return TROUBLE_STRANGLED; if (u.utrap && u.utraptype == TT_LAVA) return TROUBLE_LAVA; if (Sick) return TROUBLE_SICK; if (u.uhs >= WEAK) return TROUBLE_STARVING; if (region_danger()) return TROUBLE_REGION; if (critically_low_hp(FALSE)) return TROUBLE_HIT; if (u.ulycn >= LOW_PM) return TROUBLE_LYCANTHROPE; if (near_capacity() >= EXT_ENCUMBER && AMAX(A_STR) - ABASE(A_STR) > 3) return TROUBLE_COLLAPSING; for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { if (!i && !j) continue; if (!isok(u.ux + i, u.uy + j) || IS_ROCK(levl[u.ux + i][u.uy + j].typ) || (blocked_boulder(i, j) && !throws_rocks(youmonst.data))) count++; } if (count == 8 && !Passes_walls) return TROUBLE_STUCK_IN_WALL; if (Cursed_obj(uarmf, LEVITATION_BOOTS) || stuck_ring(uleft, RIN_LEVITATION) || stuck_ring(uright, RIN_LEVITATION)) return TROUBLE_CURSED_LEVITATION; if (nohands(youmonst.data) || !freehand()) { /* for bag/box access [cf use_container()]... make sure it's a case that we know how to handle; otherwise "fix all troubles" would get stuck in a loop */ if (welded(uwep)) return TROUBLE_UNUSEABLE_HANDS; if (Upolyd && nohands(youmonst.data) && (!Unchanging || ((otmp = unchanger()) != 0 && otmp->cursed))) return TROUBLE_UNUSEABLE_HANDS; } if (Blindfolded && ublindf->cursed) return TROUBLE_CURSED_BLINDFOLD; /* * minor troubles */ if (Punished || (u.utrap && u.utraptype == TT_BURIEDBALL)) return TROUBLE_PUNISHED; if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) || Cursed_obj(uarmf, FUMBLE_BOOTS)) return TROUBLE_FUMBLING; if (worst_cursed_item()) return TROUBLE_CURSED_ITEMS; if (u.usteed) { /* can't voluntarily dismount from a cursed saddle */ otmp = which_armor(u.usteed, W_SADDLE); if (Cursed_obj(otmp, SADDLE)) return TROUBLE_SADDLE; } if (Blinded > 1 && haseyes(youmonst.data) && (!u.uswallow || !attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))) return TROUBLE_BLIND; for (i = 0; i < A_MAX; i++) if (ABASE(i) < AMAX(i)) return TROUBLE_POISONED; if (Wounded_legs && !u.usteed) return TROUBLE_WOUNDED_LEGS; if (u.uhs >= HUNGRY) return TROUBLE_HUNGRY; if (HStun & TIMEOUT) return TROUBLE_STUNNED; if (HConfusion & TIMEOUT) return TROUBLE_CONFUSED; if (HHallucination & TIMEOUT) return TROUBLE_HALLUCINATION; return 0; } /* select an item for TROUBLE_CURSED_ITEMS */ STATIC_OVL struct obj * worst_cursed_item() { register struct obj *otmp; /* if strained or worse, check for loadstone first */ if (near_capacity() >= HVY_ENCUMBER) { for (otmp = invent; otmp; otmp = otmp->nobj) if (Cursed_obj(otmp, LOADSTONE)) return otmp; } /* weapon takes precedence if it is interfering with taking off a ring or putting on a shield */ if (welded(uwep) && (uright || bimanual(uwep))) { /* weapon */ otmp = uwep; /* gloves come next, due to rings */ } else if (uarmg && uarmg->cursed) { /* gloves */ otmp = uarmg; /* then shield due to two handed weapons and spells */ } else if (uarms && uarms->cursed) { /* shield */ otmp = uarms; /* then cloak due to body armor */ } else if (uarmc && uarmc->cursed) { /* cloak */ otmp = uarmc; } else if (uarm && uarm->cursed) { /* suit */ otmp = uarm; } else if (uarmh && uarmh->cursed) { /* helmet */ otmp = uarmh; } else if (uarmf && uarmf->cursed) { /* boots */ otmp = uarmf; } else if (uarmu && uarmu->cursed) { /* shirt */ otmp = uarmu; } else if (uamul && uamul->cursed) { /* amulet */ otmp = uamul; } else if (uleft && uleft->cursed) { /* left ring */ otmp = uleft; } else if (uright && uright->cursed) { /* right ring */ otmp = uright; } else if (ublindf && ublindf->cursed) { /* eyewear */ otmp = ublindf; /* must be non-blinding lenses */ /* if weapon wasn't handled above, do it now */ } else if (welded(uwep)) { /* weapon */ otmp = uwep; /* active secondary weapon even though it isn't welded */ } else if (uswapwep && uswapwep->cursed && u.twoweap) { otmp = uswapwep; /* all worn items ought to be handled by now */ } else { for (otmp = invent; otmp; otmp = otmp->nobj) { if (!otmp->cursed) continue; if (otmp->otyp == LOADSTONE || confers_luck(otmp)) break; } } return otmp; } STATIC_OVL void fix_worst_trouble(trouble) int trouble; { int i; struct obj *otmp = 0; const char *what = (const char *) 0; static NEARDATA const char leftglow[] = "Your left ring softly glows", rightglow[] = "Your right ring softly glows"; switch (trouble) { case TROUBLE_STONED: make_stoned(0L, "You feel more limber.", 0, (char *) 0); break; case TROUBLE_SLIMED: make_slimed(0L, "The slime disappears."); break; case TROUBLE_STRANGLED: if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) { Your("amulet vanishes!"); useup(uamul); } You("can breathe again."); Strangled = 0; context.botl = 1; break; case TROUBLE_LAVA: You("are back on solid ground."); /* teleport should always succeed, but if not, * just untrap them. */ if (!safe_teleds(FALSE)) u.utrap = 0; break; case TROUBLE_STARVING: losestr(-1); /*FALLTHRU*/ case TROUBLE_HUNGRY: Your("%s feels content.", body_part(STOMACH)); init_uhunger(); context.botl = 1; break; case TROUBLE_SICK: You_feel("better."); make_sick(0L, (char *) 0, FALSE, SICK_ALL); break; case TROUBLE_REGION: /* stinking cloud, with hero vulnerable to HP loss */ region_safety(); break; case TROUBLE_HIT: /* "fix all troubles" will keep trying if hero has 5 or less hit points, so make sure they're always boosted to be more than that */ You_feel("much better."); if (Upolyd) { u.mhmax += rnd(5); if (u.mhmax <= 5) u.mhmax = 5 + 1; u.mh = u.mhmax; } if (u.uhpmax < u.ulevel * 5 + 11) u.uhpmax += rnd(5); if (u.uhpmax <= 5) u.uhpmax = 5 + 1; u.uhp = u.uhpmax; context.botl = 1; break; case TROUBLE_COLLAPSING: /* override Fixed_abil; uncurse that if feasible */ You_feel("%sstronger.", (AMAX(A_STR) - ABASE(A_STR) > 6) ? "much " : ""); ABASE(A_STR) = AMAX(A_STR); context.botl = 1; if (Fixed_abil) { if ((otmp = stuck_ring(uleft, RIN_SUSTAIN_ABILITY)) != 0) { if (otmp == uleft) what = leftglow; } else if ((otmp = stuck_ring(uright, RIN_SUSTAIN_ABILITY)) != 0) { if (otmp == uright) what = rightglow; } if (otmp) goto decurse; } break; case TROUBLE_STUCK_IN_WALL: Your("surroundings change."); /* no control, but works on no-teleport levels */ (void) safe_teleds(FALSE); break; case TROUBLE_CURSED_LEVITATION: if (Cursed_obj(uarmf, LEVITATION_BOOTS)) { otmp = uarmf; } else if ((otmp = stuck_ring(uleft, RIN_LEVITATION)) != 0) { if (otmp == uleft) what = leftglow; } else if ((otmp = stuck_ring(uright, RIN_LEVITATION)) != 0) { if (otmp == uright) what = rightglow; } goto decurse; case TROUBLE_UNUSEABLE_HANDS: if (welded(uwep)) { otmp = uwep; goto decurse; } if (Upolyd && nohands(youmonst.data)) { if (!Unchanging) { Your("shape becomes uncertain."); rehumanize(); /* "You return to {normal} form." */ } else if ((otmp = unchanger()) != 0 && otmp->cursed) { /* otmp is an amulet of unchanging */ goto decurse; } } if (nohands(youmonst.data) || !freehand()) impossible("fix_worst_trouble: couldn't cure hands."); break; case TROUBLE_CURSED_BLINDFOLD: otmp = ublindf; goto decurse; case TROUBLE_LYCANTHROPE: you_unwere(TRUE); break; /* */ case TROUBLE_PUNISHED: Your("chain disappears."); if (u.utrap && u.utraptype == TT_BURIEDBALL) buried_ball_to_freedom(); else unpunish(); break; case TROUBLE_FUMBLING: if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING)) otmp = uarmg; else if (Cursed_obj(uarmf, FUMBLE_BOOTS)) otmp = uarmf; goto decurse; /*NOTREACHED*/ break; case TROUBLE_CURSED_ITEMS: otmp = worst_cursed_item(); if (otmp == uright) what = rightglow; else if (otmp == uleft) what = leftglow; decurse: if (!otmp) { impossible("fix_worst_trouble: nothing to uncurse."); return; } if (!Blind || (otmp == ublindf && Blindfolded_only)) { pline("%s %s.", what ? what : (const char *) Yobjnam2(otmp, "softly glow"), hcolor(NH_AMBER)); iflags.last_msg = PLNMSG_OBJ_GLOWS; otmp->bknown = TRUE; } uncurse(otmp); update_inventory(); break; case TROUBLE_POISONED: /* override Fixed_abil; ignore items which confer that */ if (Hallucination) pline("There's a tiger in your tank."); else You_feel("in good health again."); for (i = 0; i < A_MAX; i++) { if (ABASE(i) < AMAX(i)) { ABASE(i) = AMAX(i); context.botl = 1; } } (void) encumber_msg(); break; case TROUBLE_BLIND: { const char *eyes = body_part(EYE); if (eyecount(youmonst.data) != 1) eyes = makeplural(eyes); Your("%s %s better.", eyes, vtense(eyes, "feel")); u.ucreamed = 0; make_blinded(0L, FALSE); break; } case TROUBLE_WOUNDED_LEGS: heal_legs(); break; case TROUBLE_STUNNED: make_stunned(0L, TRUE); break; case TROUBLE_CONFUSED: make_confused(0L, TRUE); break; case TROUBLE_HALLUCINATION: pline("Looks like you are back in Kansas."); (void) make_hallucinated(0L, FALSE, 0L); break; case TROUBLE_SADDLE: otmp = which_armor(u.usteed, W_SADDLE); if (!Blind) { pline("%s %s.", Yobjnam2(otmp, "softly glow"), hcolor(NH_AMBER)); otmp->bknown = TRUE; } uncurse(otmp); break; } } /* "I am sometimes shocked by... the nuns who never take a bath without * wearing a bathrobe all the time. When asked why, since no man can see * them, * they reply 'Oh, but you forget the good God'. Apparently they conceive of * the Deity as a Peeping Tom, whose omnipotence enables Him to see through * bathroom walls, but who is foiled by bathrobes." --Bertrand Russell, 1943 * Divine wrath, dungeon walls, and armor follow the same principle. */ STATIC_OVL void god_zaps_you(resp_god) aligntyp resp_god; { if (u.uswallow) { pline( "Suddenly a bolt of lightning comes down at you from the heavens!"); pline("It strikes %s!", mon_nam(u.ustuck)); if (!resists_elec(u.ustuck)) { pline("%s fries to a crisp!", Monnam(u.ustuck)); /* Yup, you get experience. It takes guts to successfully * pull off this trick on your god, anyway. */ xkilled(u.ustuck, 0); } else pline("%s seems unaffected.", Monnam(u.ustuck)); } else { pline("Suddenly, a bolt of lightning strikes you!"); if (Reflecting) { shieldeff(u.ux, u.uy); if (Blind) pline("For some reason you're unaffected."); else (void) ureflects("%s reflects from your %s.", "It"); } else if (Shock_resistance) { shieldeff(u.ux, u.uy); pline("It seems not to affect you."); } else fry_by_god(resp_god, FALSE); } pline("%s is not deterred...", align_gname(resp_god)); if (u.uswallow) { pline("A wide-angle disintegration beam aimed at you hits %s!", mon_nam(u.ustuck)); if (!resists_disint(u.ustuck)) { pline("%s disintegrates into a pile of dust!", Monnam(u.ustuck)); xkilled(u.ustuck, 2); /* no corpse */ } else pline("%s seems unaffected.", Monnam(u.ustuck)); } else { pline("A wide-angle disintegration beam hits you!"); /* disintegrate shield and body armor before disintegrating * the impudent mortal, like black dragon breath -3. */ if (uarms && !(EReflecting & W_ARMS) && !(EDisint_resistance & W_ARMS)) (void) destroy_arm(uarms); if (uarmc && !(EReflecting & W_ARMC) && !(EDisint_resistance & W_ARMC)) (void) destroy_arm(uarmc); if (uarm && !(EReflecting & W_ARM) && !(EDisint_resistance & W_ARM) && !uarmc) (void) destroy_arm(uarm); if (uarmu && !uarm && !uarmc) (void) destroy_arm(uarmu); if (!Disint_resistance) fry_by_god(resp_god, TRUE); else { You("bask in its %s glow for a minute...", NH_BLACK); godvoice(resp_god, "I believe it not!"); } if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) { /* one more try for high altars */ verbalize("Thou cannot escape my wrath, mortal!"); summon_minion(resp_god, FALSE); summon_minion(resp_god, FALSE); summon_minion(resp_god, FALSE); verbalize("Destroy %s, my servants!", uhim()); } } } STATIC_OVL void fry_by_god(resp_god, via_disintegration) aligntyp resp_god; boolean via_disintegration; { You("%s!", !via_disintegration ? "fry to a crisp" : "disintegrate into a pile of dust"); killer.format = KILLED_BY; Sprintf(killer.name, "the wrath of %s", align_gname(resp_god)); done(DIED); } STATIC_OVL void angrygods(resp_god) aligntyp resp_god; { int maxanger; if (Inhell) resp_god = A_NONE; u.ublessed = 0; /* changed from tmp = u.ugangr + abs (u.uluck) -- rph */ /* added test for alignment diff -dlc */ if (resp_god != u.ualign.type) maxanger = u.ualign.record / 2 + (Luck > 0 ? -Luck / 3 : -Luck); else maxanger = 3 * u.ugangr + ((Luck > 0 || u.ualign.record >= STRIDENT) ? -Luck / 3 : -Luck); if (maxanger < 1) maxanger = 1; /* possible if bad align & good luck */ else if (maxanger > 15) maxanger = 15; /* be reasonable */ switch (rn2(maxanger)) { case 0: case 1: You_feel("that %s is %s.", align_gname(resp_god), Hallucination ? "bummed" : "displeased"); break; case 2: case 3: godvoice(resp_god, (char *) 0); pline("\"Thou %s, %s.\"", (ugod_is_angry() && resp_god == u.ualign.type) ? "hast strayed from the path" : "art arrogant", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); verbalize("Thou must relearn thy lessons!"); (void) adjattrib(A_WIS, -1, FALSE); losexp((char *) 0); break; case 6: if (!Punished) { gods_angry(resp_god); punish((struct obj *) 0); break; } /* else fall thru */ case 4: case 5: gods_angry(resp_god); if (!Blind && !Antimagic) pline("%s glow surrounds you.", An(hcolor(NH_BLACK))); rndcurse(); break; case 7: case 8: godvoice(resp_god, (char *) 0); verbalize("Thou durst %s me?", (on_altar() && (a_align(u.ux, u.uy) != resp_god)) ? "scorn" : "call upon"); pline("\"Then die, %s!\"", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); summon_minion(resp_god, FALSE); break; default: gods_angry(resp_god); god_zaps_you(resp_god); break; } u.ublesscnt = rnz(300); return; } /* helper to print "str appears at your feet", or appropriate */ static void at_your_feet(str) const char *str; { if (Blind) str = Something; if (u.uswallow) { /* barrier between you and the floor */ pline("%s %s into %s %s.", str, vtense(str, "drop"), s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); } else { pline("%s %s %s your %s!", str, Blind ? "lands" : vtense(str, "appear"), Levitation ? "beneath" : "at", makeplural(body_part(FOOT))); } } STATIC_OVL void gcrownu() { struct obj *obj; boolean already_exists, in_hand; short class_gift; int sp_no; #define ok_wep(o) ((o) && ((o)->oclass == WEAPON_CLASS || is_weptool(o))) HSee_invisible |= FROMOUTSIDE; HFire_resistance |= FROMOUTSIDE; HCold_resistance |= FROMOUTSIDE; HShock_resistance |= FROMOUTSIDE; HSleep_resistance |= FROMOUTSIDE; HPoison_resistance |= FROMOUTSIDE; godvoice(u.ualign.type, (char *) 0); obj = ok_wep(uwep) ? uwep : 0; already_exists = in_hand = FALSE; /* lint suppression */ switch (u.ualign.type) { case A_LAWFUL: u.uevent.uhand_of_elbereth = 1; verbalize("I crown thee... The Hand of Elbereth!"); break; case A_NEUTRAL: u.uevent.uhand_of_elbereth = 2; in_hand = (uwep && uwep->oartifact == ART_VORPAL_BLADE); already_exists = exist_artifact(LONG_SWORD, artiname(ART_VORPAL_BLADE)); verbalize("Thou shalt be my Envoy of Balance!"); break; case A_CHAOTIC: u.uevent.uhand_of_elbereth = 3; in_hand = (uwep && uwep->oartifact == ART_STORMBRINGER); already_exists = exist_artifact(RUNESWORD, artiname(ART_STORMBRINGER)); verbalize("Thou art chosen to %s for My Glory!", already_exists && !in_hand ? "take lives" : "steal souls"); break; } class_gift = STRANGE_OBJECT; /* 3.3.[01] had this in the A_NEUTRAL case below, preventing chaotic wizards from receiving a spellbook */ if (Role_if(PM_WIZARD) && (!uwep || (uwep->oartifact != ART_VORPAL_BLADE && uwep->oartifact != ART_STORMBRINGER)) && !carrying(SPE_FINGER_OF_DEATH)) { class_gift = SPE_FINGER_OF_DEATH; make_splbk: obj = mksobj(class_gift, TRUE, FALSE); bless(obj); obj->bknown = TRUE; at_your_feet("A spellbook"); dropy(obj); u.ugifts++; /* when getting a new book for known spell, enhance currently wielded weapon rather than the book */ for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == class_gift) { if (ok_wep(uwep)) obj = uwep; /* to be blessed,&c */ break; } } else if (Role_if(PM_MONK) && (!uwep || !uwep->oartifact) && !carrying(SPE_RESTORE_ABILITY)) { /* monks rarely wield a weapon */ class_gift = SPE_RESTORE_ABILITY; goto make_splbk; } switch (u.ualign.type) { case A_LAWFUL: if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (obj && obj->otyp == LONG_SWORD && !obj->oartifact) { if (!Blind) Your("sword shines brightly for a moment."); obj = oname(obj, artiname(ART_EXCALIBUR)); if (obj && obj->oartifact == ART_EXCALIBUR) u.ugifts++; } /* acquire Excalibur's skill regardless of weapon or gift */ unrestrict_weapon_skill(P_LONG_SWORD); if (obj && obj->oartifact == ART_EXCALIBUR) discover_artifact(ART_EXCALIBUR); break; case A_NEUTRAL: if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (obj && in_hand) { Your("%s goes snicker-snack!", xname(obj)); obj->dknown = TRUE; } else if (!already_exists) { obj = mksobj(LONG_SWORD, FALSE, FALSE); obj = oname(obj, artiname(ART_VORPAL_BLADE)); obj->spe = 1; at_your_feet("A sword"); dropy(obj); u.ugifts++; } /* acquire Vorpal Blade's skill regardless of weapon or gift */ unrestrict_weapon_skill(P_LONG_SWORD); if (obj && obj->oartifact == ART_VORPAL_BLADE) discover_artifact(ART_VORPAL_BLADE); break; case A_CHAOTIC: { char swordbuf[BUFSZ]; Sprintf(swordbuf, "%s sword", hcolor(NH_BLACK)); if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (obj && in_hand) { Your("%s hums ominously!", swordbuf); obj->dknown = TRUE; } else if (!already_exists) { obj = mksobj(RUNESWORD, FALSE, FALSE); obj = oname(obj, artiname(ART_STORMBRINGER)); obj->spe = 1; at_your_feet(An(swordbuf)); dropy(obj); u.ugifts++; } /* acquire Stormbringer's skill regardless of weapon or gift */ unrestrict_weapon_skill(P_BROAD_SWORD); if (obj && obj->oartifact == ART_STORMBRINGER) discover_artifact(ART_STORMBRINGER); break; } default: obj = 0; /* lint */ break; } /* enhance weapon regardless of alignment or artifact status */ if (ok_wep(obj)) { bless(obj); obj->oeroded = obj->oeroded2 = 0; obj->oerodeproof = TRUE; obj->bknown = obj->rknown = TRUE; if (obj->spe < 1) obj->spe = 1; /* acquire skill in this weapon */ unrestrict_weapon_skill(weapon_type(obj)); } else if (class_gift == STRANGE_OBJECT) { /* opportunity knocked, but there was nobody home... */ You_feel("unworthy."); } update_inventory(); /* lastly, confer an extra skill slot/credit beyond the up-to-29 you can get from gaining experience levels */ add_weapon_skill(1); return; } STATIC_OVL void pleased(g_align) aligntyp g_align; { /* don't use p_trouble, worst trouble may get fixed while praying */ int trouble = in_trouble(); /* what's your worst difficulty? */ int pat_on_head = 0, kick_on_butt; You_feel("that %s is %s.", align_gname(g_align), (u.ualign.record >= DEVOUT) ? Hallucination ? "pleased as punch" : "well-pleased" : (u.ualign.record >= STRIDENT) ? Hallucination ? "ticklish" : "pleased" : Hallucination ? "full" : "satisfied"); /* not your deity */ if (on_altar() && p_aligntyp != u.ualign.type) { adjalign(-1); return; } else if (u.ualign.record < 2 && trouble <= 0) adjalign(1); /* * Depending on your luck & align level, the god you prayed to will: * - fix your worst problem if it's major; * - fix all your major problems; * - fix your worst problem if it's minor; * - fix all of your problems; * - do you a gratuitous favor. * * If you make it to the the last category, you roll randomly again * to see what they do for you. * * If your luck is at least 0, then you are guaranteed rescued from * your worst major problem. */ if (!trouble && u.ualign.record >= DEVOUT) { /* if hero was in trouble, but got better, no special favor */ if (p_trouble == 0) pat_on_head = 1; } else { int action, prayer_luck; int tryct = 0; /* Negative luck is normally impossible here (can_pray() forces prayer failure in that situation), but it's possible for Luck to drop during the period of prayer occupation and become negative by the time we get here. [Reported case was lawful character whose stinking cloud caused a delayed killing of a peaceful human, triggering the "murderer" penalty while successful prayer was in progress. It could also happen due to inconvenient timing on Friday 13th, but the magnitude there (-1) isn't big enough to cause trouble.] We don't bother remembering start-of-prayer luck, just make sure it's at least -1 so that Luck+2 is big enough to avoid a divide by zero crash when generating a random number. */ prayer_luck = max(Luck, -1); /* => (prayer_luck + 2 > 0) */ action = rn1(prayer_luck + (on_altar() ? 3 + on_shrine() : 2), 1); if (!on_altar()) action = min(action, 3); if (u.ualign.record < STRIDENT) action = (u.ualign.record > 0 || !rnl(2)) ? 1 : 0; switch (min(action, 5)) { case 5: pat_on_head = 1; case 4: do fix_worst_trouble(trouble); while ((trouble = in_trouble()) != 0); break; case 3: fix_worst_trouble(trouble); case 2: /* arbitrary number of tries */ while ((trouble = in_trouble()) > 0 && (++tryct < 10)) fix_worst_trouble(trouble); break; case 1: if (trouble > 0) fix_worst_trouble(trouble); case 0: break; /* your god blows you off, too bad */ } } /* note: can't get pat_on_head unless all troubles have just been fixed or there were no troubles to begin with; hallucination won't be in effect so special handling for it is superfluous */ if (pat_on_head) switch (rn2((Luck + 6) >> 1)) { case 0: break; case 1: if (uwep && (welded(uwep) || uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) { char repair_buf[BUFSZ]; *repair_buf = '\0'; if (uwep->oeroded || uwep->oeroded2) Sprintf(repair_buf, " and %s now as good as new", otense(uwep, "are")); if (uwep->cursed) { if (!Blind) { pline("%s %s%s.", Yobjnam2(uwep, "softly glow"), hcolor(NH_AMBER), repair_buf); iflags.last_msg = PLNMSG_OBJ_GLOWS; } else You_feel("the power of %s over %s.", u_gname(), yname(uwep)); uncurse(uwep); uwep->bknown = TRUE; *repair_buf = '\0'; } else if (!uwep->blessed) { if (!Blind) { pline("%s with %s aura%s.", Yobjnam2(uwep, "softly glow"), an(hcolor(NH_LIGHT_BLUE)), repair_buf); iflags.last_msg = PLNMSG_OBJ_GLOWS; } else You_feel("the blessing of %s over %s.", u_gname(), yname(uwep)); bless(uwep); uwep->bknown = TRUE; *repair_buf = '\0'; } /* fix any rust/burn/rot damage, but don't protect against future damage */ if (uwep->oeroded || uwep->oeroded2) { uwep->oeroded = uwep->oeroded2 = 0; /* only give this message if we didn't just bless or uncurse (which has already given a message) */ if (*repair_buf) pline("%s as good as new!", Yobjnam2(uwep, Blind ? "feel" : "look")); } update_inventory(); } break; case 3: /* takes 2 hints to get the music to enter the stronghold; skip if you've solved it via mastermind or destroyed the drawbridge (both set uopened_dbridge) or if you've already travelled past the Valley of the Dead (gehennom_entered) */ if (!u.uevent.uopened_dbridge && !u.uevent.gehennom_entered) { if (u.uevent.uheard_tune < 1) { godvoice(g_align, (char *) 0); verbalize("Hark, %s!", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); verbalize( "To enter the castle, thou must play the right tune!"); u.uevent.uheard_tune++; break; } else if (u.uevent.uheard_tune < 2) { You_hear("a divine music..."); pline("It sounds like: \"%s\".", tune); u.uevent.uheard_tune++; break; } } /* Otherwise, falls into next case */ case 2: if (!Blind) You("are surrounded by %s glow.", an(hcolor(NH_GOLDEN))); /* if any levels have been lost (and not yet regained), treat this effect like blessed full healing */ if (u.ulevel < u.ulevelmax) { u.ulevelmax -= 1; /* see potion.c */ pluslvl(FALSE); } else { u.uhpmax += 5; if (Upolyd) u.mhmax += 5; } u.uhp = u.uhpmax; if (Upolyd) u.mh = u.mhmax; ABASE(A_STR) = AMAX(A_STR); if (u.uhunger < 900) init_uhunger(); if (u.uluck < 0) u.uluck = 0; make_blinded(0L, TRUE); context.botl = 1; break; case 4: { register struct obj *otmp; int any = 0; if (Blind) You_feel("the power of %s.", u_gname()); else You("are surrounded by %s aura.", an(hcolor(NH_LIGHT_BLUE))); for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->cursed) { if (!Blind) { pline("%s %s.", Yobjnam2(otmp, "softly glow"), hcolor(NH_AMBER)); iflags.last_msg = PLNMSG_OBJ_GLOWS; otmp->bknown = TRUE; ++any; } uncurse(otmp); } } if (any) update_inventory(); break; } case 5: { static NEARDATA const char msg[] = "\"and thus I grant thee the gift of %s!\""; godvoice(u.ualign.type, "Thou hast pleased me with thy progress,"); if (!(HTelepat & INTRINSIC)) { HTelepat |= FROMOUTSIDE; pline(msg, "Telepathy"); if (Blind) see_monsters(); } else if (!(HFast & INTRINSIC)) { HFast |= FROMOUTSIDE; pline(msg, "Speed"); } else if (!(HStealth & INTRINSIC)) { HStealth |= FROMOUTSIDE; pline(msg, "Stealth"); } else { if (!(HProtection & INTRINSIC)) { HProtection |= FROMOUTSIDE; if (!u.ublessed) u.ublessed = rn1(3, 2); } else u.ublessed++; pline(msg, "my protection"); } verbalize("Use it wisely in my name!"); break; } case 7: case 8: if (u.ualign.record >= PIOUS && !u.uevent.uhand_of_elbereth) { gcrownu(); break; } /* else FALLTHRU */ case 6: { struct obj *otmp; int sp_no, trycnt = u.ulevel + 1; /* not yet known spells given preference over already known ones */ /* Also, try to grant a spell for which there is a skill slot */ otmp = mkobj(SPBOOK_CLASS, TRUE); while (--trycnt > 0) { if (otmp->otyp != SPE_BLANK_PAPER) { for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == otmp->otyp) break; if (sp_no == MAXSPELL && !P_RESTRICTED(spell_skilltype(otmp->otyp))) break; /* usable, but not yet known */ } else { if (!objects[SPE_BLANK_PAPER].oc_name_known || carrying(MAGIC_MARKER)) break; } otmp->otyp = rnd_class(bases[SPBOOK_CLASS], SPE_BLANK_PAPER); } bless(otmp); at_your_feet("A spellbook"); place_object(otmp, u.ux, u.uy); newsym(u.ux, u.uy); break; } default: impossible("Confused deity!"); break; } u.ublesscnt = rnz(350); kick_on_butt = u.uevent.udemigod ? 1 : 0; if (u.uevent.uhand_of_elbereth) kick_on_butt++; if (kick_on_butt) u.ublesscnt += kick_on_butt * rnz(1000); return; } /* either blesses or curses water on the altar, * returns true if it found any water here. */ STATIC_OVL boolean water_prayer(bless_water) boolean bless_water; { register struct obj *otmp; register long changed = 0; boolean other = FALSE, bc_known = !(Blind || Hallucination); for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { /* turn water into (un)holy water */ if (otmp->otyp == POT_WATER && (bless_water ? !otmp->blessed : !otmp->cursed)) { otmp->blessed = bless_water; otmp->cursed = !bless_water; otmp->bknown = bc_known; changed += otmp->quan; } else if (otmp->oclass == POTION_CLASS) other = TRUE; } if (!Blind && changed) { pline("%s potion%s on the altar glow%s %s for a moment.", ((other && changed > 1L) ? "Some of the" : (other ? "One of the" : "The")), ((other || changed > 1L) ? "s" : ""), (changed > 1L ? "" : "s"), (bless_water ? hcolor(NH_LIGHT_BLUE) : hcolor(NH_BLACK))); } return (boolean) (changed > 0L); } STATIC_OVL void godvoice(g_align, words) aligntyp g_align; const char *words; { const char *quot = ""; if (words) quot = "\""; else words = ""; pline_The("voice of %s %s: %s%s%s", align_gname(g_align), godvoices[rn2(SIZE(godvoices))], quot, words, quot); } STATIC_OVL void gods_angry(g_align) aligntyp g_align; { godvoice(g_align, "Thou hast angered me."); } /* The g_align god is upset with you. */ STATIC_OVL void gods_upset(g_align) aligntyp g_align; { if (g_align == u.ualign.type) u.ugangr++; else if (u.ugangr) u.ugangr--; angrygods(g_align); } STATIC_OVL void consume_offering(otmp) register struct obj *otmp; { if (Hallucination) switch (rn2(3)) { case 0: Your("sacrifice sprouts wings and a propeller and roars away!"); break; case 1: Your("sacrifice puffs up, swelling bigger and bigger, and pops!"); break; case 2: Your( "sacrifice collapses into a cloud of dancing particles and fades away!"); break; } else if (Blind && u.ualign.type == A_LAWFUL) Your("sacrifice disappears!"); else Your("sacrifice is consumed in a %s!", u.ualign.type == A_LAWFUL ? "flash of light" : "burst of flame"); if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); exercise(A_WIS, TRUE); } int dosacrifice() { static NEARDATA const char cloud_of_smoke[] = "A cloud of %s smoke surrounds you..."; register struct obj *otmp; int value = 0, pm; boolean highaltar; aligntyp altaralign = a_align(u.ux, u.uy); if (!on_altar() || u.uswallow) { You("are not standing on an altar."); return 0; } highaltar = ((Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) && (levl[u.ux][u.uy].altarmask & AM_SHRINE)); otmp = floorfood("sacrifice", 1); if (!otmp) return 0; /* * Was based on nutritional value and aging behavior (< 50 moves). * Sacrificing a food ration got you max luck instantly, making the * gods as easy to please as an angry dog! * * Now only accepts corpses, based on the game's evaluation of their * toughness. Human and pet sacrifice, as well as sacrificing unicorns * of your alignment, is strongly discouraged. */ #define MAXVALUE 24 /* Highest corpse value (besides Wiz) */ if (otmp->otyp == CORPSE) { register struct permonst *ptr = &mons[otmp->corpsenm]; struct monst *mtmp; extern const int monstr[]; /* KMH, conduct */ u.uconduct.gnostic++; /* you're handling this corpse, even if it was killed upon the altar */ feel_cockatrice(otmp, TRUE); if (rider_corpse_revival(otmp, FALSE)) return 1; if (otmp->corpsenm == PM_ACID_BLOB || (monstermoves <= peek_at_iced_corpse_age(otmp) + 50)) { value = monstr[otmp->corpsenm] + 1; if (otmp->oeaten) value = eaten_stat(value, otmp); } if (your_race(ptr)) { if (is_demon(youmonst.data)) { You("find the idea very satisfying."); exercise(A_WIS, TRUE); } else if (u.ualign.type != A_CHAOTIC) { pline("You'll regret this infamous offense!"); exercise(A_WIS, FALSE); } if (highaltar && (altaralign != A_CHAOTIC || u.ualign.type != A_CHAOTIC)) { goto desecrate_high_altar; } else if (altaralign != A_CHAOTIC && altaralign != A_NONE) { /* curse the lawful/neutral altar */ pline_The("altar is stained with %s blood.", urace.adj); levl[u.ux][u.uy].altarmask = AM_CHAOTIC; angry_priest(); } else { struct monst *dmon; const char *demonless_msg; /* Human sacrifice on a chaotic or unaligned altar */ /* is equivalent to demon summoning */ if (altaralign == A_CHAOTIC && u.ualign.type != A_CHAOTIC) { pline( "The blood floods the altar, which vanishes in %s cloud!", an(hcolor(NH_BLACK))); levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].altarmask = 0; newsym(u.ux, u.uy); angry_priest(); demonless_msg = "cloud dissipates"; } else { /* either you're chaotic or altar is Moloch's or both */ pline_The("blood covers the altar!"); change_luck(altaralign == A_NONE ? -2 : 2); demonless_msg = "blood coagulates"; } if ((pm = dlord(altaralign)) != NON_PM && (dmon = makemon(&mons[pm], u.ux, u.uy, NO_MM_FLAGS)) != 0) { char dbuf[BUFSZ]; Strcpy(dbuf, a_monnam(dmon)); if (!strcmpi(dbuf, "it")) Strcpy(dbuf, "something dreadful"); else dmon->mstrategy &= ~STRAT_APPEARMSG; You("have summoned %s!", dbuf); if (sgn(u.ualign.type) == sgn(dmon->data->maligntyp)) dmon->mpeaceful = TRUE; You("are terrified, and unable to move."); nomul(-3); multi_reason = "being terrified of a demon"; nomovemsg = 0; } else pline_The("%s.", demonless_msg); } if (u.ualign.type != A_CHAOTIC) { adjalign(-5); u.ugangr += 3; (void) adjattrib(A_WIS, -1, TRUE); if (!Inhell) angrygods(u.ualign.type); change_luck(-5); } else adjalign(5); if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); return 1; } else if (has_omonst(otmp) && (mtmp = get_mtraits(otmp, FALSE)) != 0 && mtmp->mtame) { /* mtmp is a temporary pointer to a tame monster's attributes, * not a real monster */ pline("So this is how you repay loyalty?"); adjalign(-3); value = -1; HAggravate_monster |= FROMOUTSIDE; } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ if (u.ualign.type != A_CHAOTIC) value += 1; } else if (is_unicorn(ptr)) { int unicalign = sgn(ptr->maligntyp); if (unicalign == altaralign) { /* When same as altar, always a very bad action. */ pline("Such an action is an insult to %s!", (unicalign == A_CHAOTIC) ? "chaos" : unicalign ? "law" : "balance"); (void) adjattrib(A_WIS, -1, TRUE); value = -5; } else if (u.ualign.type == altaralign) { /* When different from altar, and altar is same as yours, * it's a very good action. */ if (u.ualign.record < ALIGNLIM) You_feel("appropriately %s.", align_str(u.ualign.type)); else You_feel("you are thoroughly on the right path."); adjalign(5); value += 3; } else if (unicalign == u.ualign.type) { /* When sacrificing unicorn of your alignment to altar not of * your alignment, your god gets angry and it's a conversion. */ u.ualign.record = -1; value = 1; } else { /* Otherwise, unicorn's alignment is different from yours * and different from the altar's. It's an ordinary (well, * with a bonus) sacrifice on a cross-aligned altar. */ value += 3; } } } /* corpse */ if (otmp->otyp == AMULET_OF_YENDOR) { if (!highaltar) { too_soon: if (altaralign == A_NONE && Inhell) /* hero has left Moloch's Sanctum so is in the process of getting away with the Amulet (outside of Gehennom, fall through to the "ashamed" feedback) */ gods_upset(A_NONE); else You_feel("%s.", Hallucination ? "homesick" /* if on track, give a big hint */ : (altaralign == u.ualign.type) ? "an urge to return to the surface" /* else headed towards celestial disgrace */ : "ashamed"); return 1; } else { /* The final Test. Did you win? */ if (uamul == otmp) Amulet_off(); u.uevent.ascended = 1; if (carried(otmp)) useup(otmp); /* well, it's gone now */ else useupf(otmp, 1L); You("offer the Amulet of Yendor to %s...", a_gname()); if (altaralign == A_NONE) { /* Moloch's high altar */ if (u.ualign.record > -99) u.ualign.record = -99; /*[apparently shrug/snarl can be sensed without being seen]*/ pline("%s shrugs and retains dominion over %s,", Moloch, u_gname()); pline("then mercilessly snuffs out your life."); Sprintf(killer.name, "%s indifference", s_suffix(Moloch)); killer.format = KILLED_BY; done(DIED); /* life-saved (or declined to die in wizard/explore mode) */ pline("%s snarls and tries again...", Moloch); fry_by_god(A_NONE, TRUE); /* wrath of Moloch */ /* declined to die in wizard or explore mode */ pline(cloud_of_smoke, hcolor(NH_BLACK)); done(ESCAPED); } else if (u.ualign.type != altaralign) { /* And the opposing team picks you up and carries you off on their shoulders */ adjalign(-99); pline("%s accepts your gift, and gains dominion over %s...", a_gname(), u_gname()); pline("%s is enraged...", u_gname()); pline("Fortunately, %s permits you to live...", a_gname()); pline(cloud_of_smoke, hcolor(NH_ORANGE)); done(ESCAPED); } else { /* super big win */ adjalign(10); u.uachieve.ascended = 1; pline( "An invisible choir sings, and you are bathed in radiance..."); godvoice(altaralign, "Congratulations, mortal!"); display_nhwindow(WIN_MESSAGE, FALSE); verbalize( "In return for thy service, I grant thee the gift of Immortality!"); You("ascend to the status of Demigod%s...", flags.female ? "dess" : ""); done(ASCENDED); } } } /* real Amulet */ if (otmp->otyp == FAKE_AMULET_OF_YENDOR) { if (!highaltar && !otmp->known) goto too_soon; You_hear("a nearby thunderclap."); if (!otmp->known) { You("realize you have made a %s.", Hallucination ? "boo-boo" : "mistake"); otmp->known = TRUE; change_luck(-1); return 1; } else { /* don't you dare try to fool the gods */ if (Deaf) pline("Oh, no."); /* didn't hear thunderclap */ change_luck(-3); adjalign(-1); u.ugangr += 3; value = -3; } } /* fake Amulet */ if (value == 0) { pline1(nothing_happens); return 1; } if (altaralign != u.ualign.type && highaltar) { desecrate_high_altar: /* * REAL BAD NEWS!!! High altars cannot be converted. Even an attempt * gets the god who owns it truly pissed off. */ You_feel("the air around you grow charged..."); pline("Suddenly, you realize that %s has noticed you...", a_gname()); godvoice(altaralign, "So, mortal! You dare desecrate my High Temple!"); /* Throw everything we have at the player */ god_zaps_you(altaralign); } else if (value < 0) { /* I don't think the gods are gonna like this... */ gods_upset(altaralign); } else { int saved_anger = u.ugangr; int saved_cnt = u.ublesscnt; int saved_luck = u.uluck; /* Sacrificing at an altar of a different alignment */ if (u.ualign.type != altaralign) { /* Is this a conversion ? */ /* An unaligned altar in Gehennom will always elicit rejection. */ if (ugod_is_angry() || (altaralign == A_NONE && Inhell)) { if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL] && altaralign != A_NONE) { You("have a strong feeling that %s is angry...", u_gname()); consume_offering(otmp); pline("%s accepts your allegiance.", a_gname()); uchangealign(altaralign, 0); /* Beware, Conversion is costly */ change_luck(-3); u.ublesscnt += 300; } else { u.ugangr += 3; adjalign(-5); pline("%s rejects your sacrifice!", a_gname()); godvoice(altaralign, "Suffer, infidel!"); change_luck(-5); (void) adjattrib(A_WIS, -2, TRUE); if (!Inhell) angrygods(u.ualign.type); } return 1; } else { consume_offering(otmp); You("sense a conflict between %s and %s.", u_gname(), a_gname()); if (rn2(8 + u.ulevel) > 5) { struct monst *pri; You_feel("the power of %s increase.", u_gname()); exercise(A_WIS, TRUE); change_luck(1); /* Yes, this is supposed to be &=, not |= */ levl[u.ux][u.uy].altarmask &= AM_SHRINE; /* the following accommodates stupid compilers */ levl[u.ux][u.uy].altarmask = levl[u.ux][u.uy].altarmask | (Align2amask(u.ualign.type)); if (!Blind) pline_The("altar glows %s.", hcolor((u.ualign.type == A_LAWFUL) ? NH_WHITE : u.ualign.type ? NH_BLACK : (const char *) "gray")); if (rnl(u.ulevel) > 6 && u.ualign.record > 0 && rnd(u.ualign.record) > (3 * ALIGNLIM) / 4) summon_minion(altaralign, TRUE); /* anger priest; test handles bones files */ if ((pri = findpriest(temple_occupied(u.urooms))) && !p_coaligned(pri)) angry_priest(); } else { pline("Unluckily, you feel the power of %s decrease.", u_gname()); change_luck(-1); exercise(A_WIS, FALSE); if (rnl(u.ulevel) > 6 && u.ualign.record > 0 && rnd(u.ualign.record) > (7 * ALIGNLIM) / 8) summon_minion(altaralign, TRUE); } return 1; } } consume_offering(otmp); /* OK, you get brownie points. */ if (u.ugangr) { u.ugangr -= ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3)) / MAXVALUE); if (u.ugangr < 0) u.ugangr = 0; if (u.ugangr != saved_anger) { if (u.ugangr) { pline("%s seems %s.", u_gname(), Hallucination ? "groovy" : "slightly mollified"); if ((int) u.uluck < 0) change_luck(1); } else { pline("%s seems %s.", u_gname(), Hallucination ? "cosmic (not a new fact)" : "mollified"); if ((int) u.uluck < 0) u.uluck = 0; } } else { /* not satisfied yet */ if (Hallucination) pline_The("gods seem tall."); else You("have a feeling of inadequacy."); } } else if (ugod_is_angry()) { if (value > MAXVALUE) value = MAXVALUE; if (value > -u.ualign.record) value = -u.ualign.record; adjalign(value); You_feel("partially absolved."); } else if (u.ublesscnt > 0) { u.ublesscnt -= ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300)) / MAXVALUE); if (u.ublesscnt < 0) u.ublesscnt = 0; if (u.ublesscnt != saved_cnt) { if (u.ublesscnt) { if (Hallucination) You("realize that the gods are not like you and I."); else You("have a hopeful feeling."); if ((int) u.uluck < 0) change_luck(1); } else { if (Hallucination) pline("Overall, there is a smell of fried onions."); else You("have a feeling of reconciliation."); if ((int) u.uluck < 0) u.uluck = 0; } } } else { int nartifacts = nartifact_exist(); /* you were already in pretty good standing */ /* The player can gain an artifact */ /* The chance goes down as the number of artifacts goes up */ if (u.ulevel > 2 && u.uluck >= 0 && !rn2(10 + (2 * u.ugifts * nartifacts))) { otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy)); if (otmp) { if (otmp->spe < 0) otmp->spe = 0; if (otmp->cursed) uncurse(otmp); otmp->oerodeproof = TRUE; at_your_feet("An object"); dropy(otmp); godvoice(u.ualign.type, "Use my gift wisely!"); u.ugifts++; u.ublesscnt = rnz(300 + (50 * nartifacts)); exercise(A_WIS, TRUE); /* make sure we can use this weapon */ unrestrict_weapon_skill(weapon_type(otmp)); if (!Hallucination && !Blind) { otmp->dknown = 1; makeknown(otmp->otyp); discover_artifact(otmp->oartifact); } return 1; } } change_luck((value * LUCKMAX) / (MAXVALUE * 2)); if ((int) u.uluck < 0) u.uluck = 0; if (u.uluck != saved_luck) { if (Blind) You("think %s brushed your %s.", something, body_part(FOOT)); else You(Hallucination ? "see crabgrass at your %s. A funny thing in a dungeon." : "glimpse a four-leaf clover at your %s.", makeplural(body_part(FOOT))); } } } return 1; } /* determine prayer results in advance; also used for enlightenment */ boolean can_pray(praying) boolean praying; /* false means no messages should be given */ { int alignment; p_aligntyp = on_altar() ? a_align(u.ux, u.uy) : u.ualign.type; p_trouble = in_trouble(); if (is_demon(youmonst.data) && (p_aligntyp != A_CHAOTIC)) { if (praying) pline_The("very idea of praying to a %s god is repugnant to you.", p_aligntyp ? "lawful" : "neutral"); return FALSE; } if (praying) You("begin praying to %s.", align_gname(p_aligntyp)); if (u.ualign.type && u.ualign.type == -p_aligntyp) alignment = -u.ualign.record; /* Opposite alignment altar */ else if (u.ualign.type != p_aligntyp) alignment = u.ualign.record / 2; /* Different alignment altar */ else alignment = u.ualign.record; if ((p_trouble > 0) ? (u.ublesscnt > 200) /* big trouble */ : (p_trouble < 0) ? (u.ublesscnt > 100) /* minor difficulties */ : (u.ublesscnt > 0)) /* not in trouble */ p_type = 0; /* too soon... */ else if ((int) Luck < 0 || u.ugangr || alignment < 0) p_type = 1; /* too naughty... */ else /* alignment >= 0 */ { if (on_altar() && u.ualign.type != p_aligntyp) p_type = 2; else p_type = 3; } if (is_undead(youmonst.data) && !Inhell && (p_aligntyp == A_LAWFUL || (p_aligntyp == A_NEUTRAL && !rn2(10)))) p_type = -1; /* Note: when !praying, the random factor for neutrals makes the return value a non-deterministic approximation for enlightenment. This case should be uncommon enough to live with... */ return !praying ? (boolean) (p_type == 3 && !Inhell) : TRUE; } /* #pray commmand */ int dopray() { /* Confirm accidental slips of Alt-P */ if (ParanoidPray && yn("Are you sure you want to pray?") != 'y') return 0; u.uconduct.gnostic++; /* set up p_type and p_alignment */ if (!can_pray(TRUE)) return 0; if (wizard && p_type >= 0) { if (yn("Force the gods to be pleased?") == 'y') { u.ublesscnt = 0; if (u.uluck < 0) u.uluck = 0; if (u.ualign.record <= 0) u.ualign.record = 1; u.ugangr = 0; if (p_type < 2) p_type = 3; } } nomul(-3); multi_reason = "praying"; nomovemsg = "You finish your prayer."; afternmv = prayer_done; if (p_type == 3 && !Inhell) { /* if you've been true to your god you can't die while you pray */ if (!Blind) You("are surrounded by a shimmering light."); u.uinvulnerable = TRUE; } return 1; } STATIC_PTR int prayer_done() /* M. Stephenson (1.0.3b) */ { aligntyp alignment = p_aligntyp; u.uinvulnerable = FALSE; if (p_type == -1) { godvoice(alignment, (alignment == A_LAWFUL) ? "Vile creature, thou durst call upon me?" : "Walk no more, perversion of nature!"); You_feel("like you are falling apart."); /* KMH -- Gods have mastery over unchanging */ rehumanize(); /* no Half_physical_damage adjustment here */ losehp(rnd(20), "residual undead turning effect", KILLED_BY_AN); exercise(A_CON, FALSE); return 1; } if (Inhell) { pline("Since you are in Gehennom, %s won't help you.", align_gname(alignment)); /* haltingly aligned is least likely to anger */ if (u.ualign.record <= 0 || rnl(u.ualign.record)) angrygods(u.ualign.type); return 0; } if (p_type == 0) { if (on_altar() && u.ualign.type != alignment) (void) water_prayer(FALSE); u.ublesscnt += rnz(250); change_luck(-3); gods_upset(u.ualign.type); } else if (p_type == 1) { if (on_altar() && u.ualign.type != alignment) (void) water_prayer(FALSE); angrygods(u.ualign.type); /* naughty */ } else if (p_type == 2) { if (water_prayer(FALSE)) { /* attempted water prayer on a non-coaligned altar */ u.ublesscnt += rnz(250); change_luck(-3); gods_upset(u.ualign.type); } else pleased(alignment); } else { /* coaligned */ if (on_altar()) (void) water_prayer(TRUE); pleased(alignment); /* nice */ } return 1; } /* #turn command */ int doturn() { /* Knights & Priest(esse)s only please */ struct monst *mtmp, *mtmp2; int once, range, xlev; if (!Role_if(PM_PRIEST) && !Role_if(PM_KNIGHT)) { /* Try to use the "turn undead" spell. * * This used to be based on whether hero knows the name of the * turn undead spellbook, but it's possible to know--and be able * to cast--the spell while having lost the book ID to amnesia. * (It also used to tell spelleffects() to cast at self?) */ int sp_no; for (sp_no = 0; sp_no < MAXSPELL; ++sp_no) { if (spl_book[sp_no].sp_id == NO_SPELL) break; else if (spl_book[sp_no].sp_id == SPE_TURN_UNDEAD) return spelleffects(sp_no, FALSE); } You("don't know how to turn undead!"); return 0; } u.uconduct.gnostic++; if ((u.ualign.type != A_CHAOTIC && (is_demon(youmonst.data) || is_undead(youmonst.data))) || u.ugangr > 6) { /* "Die, mortal!" */ pline("For some reason, %s seems to ignore you.", u_gname()); aggravate(); exercise(A_WIS, FALSE); return 0; } if (Inhell) { pline("Since you are in Gehennom, %s won't help you.", u_gname()); aggravate(); return 0; } pline("Calling upon %s, you chant an arcane formula.", u_gname()); exercise(A_WIS, TRUE); /* note: does not perform unturn_dead() on victims' inventories */ range = BOLT_LIM + (u.ulevel / 5); /* 5 to 11 */ range *= range; once = 0; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (!cansee(mtmp->mx, mtmp->my) || distu(mtmp->mx, mtmp->my) > range) continue; if (!mtmp->mpeaceful && (is_undead(mtmp->data) || is_vampshifter(mtmp) || (is_demon(mtmp->data) && (u.ulevel > (MAXULEV / 2))))) { mtmp->msleeping = 0; if (Confusion) { if (!once++) pline("Unfortunately, your voice falters."); mtmp->mflee = 0; mtmp->mfrozen = 0; mtmp->mcanmove = 1; } else if (!resist(mtmp, '\0', 0, TELL)) { xlev = 6; switch (mtmp->data->mlet) { /* this is intentional, lichs are tougher than zombies. */ case S_LICH: xlev += 2; /*FALLTHRU*/ case S_GHOST: xlev += 2; /*FALLTHRU*/ case S_VAMPIRE: xlev += 2; /*FALLTHRU*/ case S_WRAITH: xlev += 2; /*FALLTHRU*/ case S_MUMMY: xlev += 2; /*FALLTHRU*/ case S_ZOMBIE: if (u.ulevel >= xlev && !resist(mtmp, '\0', 0, NOTELL)) { if (u.ualign.type == A_CHAOTIC) { mtmp->mpeaceful = 1; set_malign(mtmp); } else { /* damn them */ killed(mtmp); } break; } /* else flee */ /*FALLTHRU*/ default: monflee(mtmp, 0, FALSE, TRUE); break; } } } } nomul(-5); multi_reason = "trying to turn the monsters"; nomovemsg = You_can_move_again; return 1; } const char * a_gname() { return a_gname_at(u.ux, u.uy); } /* returns the name of an altar's deity */ const char * a_gname_at(x, y) xchar x, y; { if (!IS_ALTAR(levl[x][y].typ)) return (char *) 0; return align_gname(a_align(x, y)); } /* returns the name of the hero's deity */ const char * u_gname() { return align_gname(u.ualign.type); } const char * align_gname(alignment) aligntyp alignment; { const char *gnam; switch (alignment) { case A_NONE: gnam = Moloch; break; case A_LAWFUL: gnam = urole.lgod; break; case A_NEUTRAL: gnam = urole.ngod; break; case A_CHAOTIC: gnam = urole.cgod; break; default: impossible("unknown alignment."); gnam = "someone"; break; } if (*gnam == '_') ++gnam; return gnam; } static const char *hallu_gods[] = { "the Flying Spaghetti Monster", /* Church of the FSM */ "Eris", /* Discordianism */ "the Martians", /* every science fiction ever */ "Xom", /* Crawl */ "AnDoR dRaKoN", /* ADOM */ "the Central Bank of Yendor", /* economics */ "Tooth Fairy", /* real world(?) */ "Om", /* Discworld */ "Yawgmoth", /* Magic: the Gathering */ "Morgoth", /* LoTR */ "Cthulhu", /* Lovecraft */ "the Ori", /* Stargate */ "destiny", /* why not? */ "your Friend the Computer", /* Paranoia */ }; /* hallucination handling for priest/minion names: select a random god iff character is hallucinating */ const char * halu_gname(alignment) aligntyp alignment; { const char *gnam = NULL; int which; if (!Hallucination) return align_gname(alignment); /* The priest may not have initialized god names. If this is the * case, and we roll priest, we need to try again. */ do which = randrole(); while (!roles[which].lgod); switch (rn2(9)) { case 0: case 1: gnam = roles[which].lgod; break; case 2: case 3: gnam = roles[which].ngod; break; case 4: case 5: gnam = roles[which].cgod; break; case 6: case 7: gnam = hallu_gods[rn2(sizeof hallu_gods / sizeof *hallu_gods)]; break; case 8: gnam = Moloch; break; default: impossible("rn2 broken in halu_gname?!?"); } if (!gnam) { impossible("No random god name?"); gnam = "your Friend the Computer"; /* Paranoia */ } if (*gnam == '_') ++gnam; return gnam; } /* deity's title */ const char * align_gtitle(alignment) aligntyp alignment; { const char *gnam, *result = "god"; switch (alignment) { case A_LAWFUL: gnam = urole.lgod; break; case A_NEUTRAL: gnam = urole.ngod; break; case A_CHAOTIC: gnam = urole.cgod; break; default: gnam = 0; break; } if (gnam && *gnam == '_') result = "goddess"; return result; } void altar_wrath(x, y) register int x, y; { aligntyp altaralign = a_align(x, y); if (!strcmp(align_gname(altaralign), u_gname())) { godvoice(altaralign, "How darest thou desecrate my altar!"); (void) adjattrib(A_WIS, -1, FALSE); } else { pline("A voice (could it be %s?) whispers:", align_gname(altaralign)); verbalize("Thou shalt pay, infidel!"); change_luck(-1); } } /* assumes isok() at one space away, but not necessarily at two */ STATIC_OVL boolean blocked_boulder(dx, dy) int dx, dy; { register struct obj *otmp; long count = 0L; for (otmp = level.objects[u.ux + dx][u.uy + dy]; otmp; otmp = otmp->nexthere) { if (otmp->otyp == BOULDER) count += otmp->quan; } switch (count) { case 0: /* no boulders--not blocked */ return FALSE; case 1: /* possibly blocked depending on if it's pushable */ break; default: /* more than one boulder--blocked after they push the top one; don't force them to push it first to find out */ return TRUE; } if (!isok(u.ux + 2 * dx, u.uy + 2 * dy)) return TRUE; if (IS_ROCK(levl[u.ux + 2 * dx][u.uy + 2 * dy].typ)) return TRUE; if (sobj_at(BOULDER, u.ux + 2 * dx, u.uy + 2 * dy)) return TRUE; return FALSE; } /*pray.c*/ nethack-3.6.0/src/priest.c0000664000076400007660000006470412617413107014413 0ustar paxedpaxed/* NetHack 3.6 priest.c $NHDT-Date: 1446892452 2015/11/07 10:34:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.41 $ */ /* Copyright (c) Izchak Miller, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" /* these match the categorizations shown by enlightenment */ #define ALGN_SINNED (-4) /* worse than strayed (-1..-3) */ #define ALGN_PIOUS 14 /* better than fervent (9..13) */ STATIC_DCL boolean FDECL(histemple_at, (struct monst *, XCHAR_P, XCHAR_P)); STATIC_DCL boolean FDECL(has_shrine, (struct monst *)); void newepri(mtmp) struct monst *mtmp; { if (!mtmp->mextra) mtmp->mextra = newmextra(); if (!EPRI(mtmp)) { EPRI(mtmp) = (struct epri *) alloc(sizeof(struct epri)); (void) memset((genericptr_t) EPRI(mtmp), 0, sizeof(struct epri)); } } void free_epri(mtmp) struct monst *mtmp; { if (mtmp->mextra && EPRI(mtmp)) { free((genericptr_t) EPRI(mtmp)); EPRI(mtmp) = (struct epri *) 0; } mtmp->ispriest = 0; } /* * Move for priests and shopkeepers. Called from shk_move() and pri_move(). * Valid returns are 1: moved 0: didn't -1: let m_move do it -2: died. */ int move_special(mtmp, in_his_shop, appr, uondoor, avoid, omx, omy, gx, gy) register struct monst *mtmp; boolean in_his_shop; schar appr; boolean uondoor, avoid; register xchar omx, omy, gx, gy; { register xchar nx, ny, nix, niy; register schar i; schar chcnt, cnt; coord poss[9]; long info[9]; long allowflags; struct obj *ib = (struct obj *) 0; if (omx == gx && omy == gy) return 0; if (mtmp->mconf) { avoid = FALSE; appr = 0; } nix = omx; niy = omy; if (mtmp->isshk) allowflags = ALLOW_SSM; else allowflags = ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (monhaskey(mtmp, TRUE)) allowflags |= UNLOCKDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; cnt = mfndpos(mtmp, poss, info, allowflags); if (mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */ for (i = 0; i < cnt; i++) if (!(info[i] & NOTONL)) goto pick_move; avoid = FALSE; } #define GDIST(x, y) (dist2(x, y, gx, gy)) pick_move: chcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (IS_ROOM(levl[nx][ny].typ) || (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) { if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rn2(++chcnt)) || (appr && GDIST(nx, ny) < GDIST(nix, niy))) { nix = nx; niy = ny; } } } if (mtmp->ispriest && avoid && nix == omx && niy == omy && onlineu(omx, omy)) { /* might as well move closer as long it's going to stay * lined up */ avoid = FALSE; goto pick_move; } if (nix != omx || niy != omy) { remove_monster(omx, omy); place_monster(mtmp, nix, niy); newsym(nix, niy); if (mtmp->isshk && !in_his_shop && inhishop(mtmp)) check_special_room(FALSE); if (ib) { if (cansee(mtmp->mx, mtmp->my)) pline("%s picks up %s.", Monnam(mtmp), distant_name(ib, doname)); obj_extract_self(ib); (void) mpickobj(mtmp, ib); } return 1; } return 0; } char temple_occupied(array) register char *array; { register char *ptr; for (ptr = array; *ptr; ptr++) if (rooms[*ptr - ROOMOFFSET].rtype == TEMPLE) return *ptr; return '\0'; } STATIC_OVL boolean histemple_at(priest, x, y) register struct monst *priest; register xchar x, y; { return (boolean) (priest && priest->ispriest && (EPRI(priest)->shroom == *in_rooms(x, y, TEMPLE)) && on_level(&(EPRI(priest)->shrlevel), &u.uz)); } boolean inhistemple(priest) struct monst *priest; { /* make sure we have a priest */ if (!priest || !priest->ispriest) return FALSE; /* priest must be on right level and in right room */ if (!histemple_at(priest, priest->mx, priest->my)) return FALSE; /* temple room must still contain properly aligned altar */ return has_shrine(priest); } /* * pri_move: return 1: moved 0: didn't -1: let m_move do it -2: died */ int pri_move(priest) register struct monst *priest; { register xchar gx, gy, omx, omy; schar temple; boolean avoid = TRUE; omx = priest->mx; omy = priest->my; if (!histemple_at(priest, omx, omy)) return -1; temple = EPRI(priest)->shroom; gx = EPRI(priest)->shrpos.x; gy = EPRI(priest)->shrpos.y; gx += rn1(3, -1); /* mill around the altar */ gy += rn1(3, -1); if (!priest->mpeaceful || (Conflict && !resist(priest, RING_CLASS, 0, 0))) { if (monnear(priest, u.ux, u.uy)) { if (Displaced) Your("displaced image doesn't fool %s!", mon_nam(priest)); (void) mattacku(priest); return 0; } else if (index(u.urooms, temple)) { /* chase player if inside temple & can see him */ if (priest->mcansee && m_canseeu(priest)) { gx = u.ux; gy = u.uy; } avoid = FALSE; } } else if (Invis) avoid = FALSE; return move_special(priest, FALSE, TRUE, FALSE, avoid, omx, omy, gx, gy); } /* exclusively for mktemple() */ void priestini(lvl, sroom, sx, sy, sanctum) d_level *lvl; struct mkroom *sroom; int sx, sy; boolean sanctum; /* is it the seat of the high priest? */ { struct monst *priest; struct obj *otmp; int cnt; if (MON_AT(sx + 1, sy)) (void) rloc(m_at(sx + 1, sy), FALSE); /* insurance */ priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST], sx + 1, sy, MM_EPRI); if (priest) { EPRI(priest)->shroom = (schar) ((sroom - rooms) + ROOMOFFSET); EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask); EPRI(priest)->shrpos.x = sx; EPRI(priest)->shrpos.y = sy; assign_level(&(EPRI(priest)->shrlevel), lvl); priest->mtrapseen = ~0; /* traps are known */ priest->mpeaceful = 1; priest->ispriest = 1; priest->isminion = 0; priest->msleeping = 0; set_malign(priest); /* mpeaceful may have changed */ /* now his/her goodies... */ if (sanctum && EPRI(priest)->shralign == A_NONE && on_level(&sanctum_level, &u.uz)) { (void) mongets(priest, AMULET_OF_YENDOR); } /* 2 to 4 spellbooks */ for (cnt = rn1(3, 2); cnt > 0; --cnt) { (void) mpickobj(priest, mkobj(SPBOOK_CLASS, FALSE)); } /* robe [via makemon()] */ if (rn2(2) && (otmp = which_armor(priest, W_ARMC)) != 0) { if (p_coaligned(priest)) uncurse(otmp); else curse(otmp); } } } /* get a monster's alignment type without caller needing EPRI & EMIN */ aligntyp mon_aligntyp(mon) struct monst *mon; { aligntyp algn = mon->ispriest ? EPRI(mon)->shralign : mon->isminion ? EMIN(mon)->min_align : mon->data->maligntyp; if (algn == A_NONE) return A_NONE; /* negative but differs from chaotic */ return (algn > 0) ? A_LAWFUL : (algn < 0) ? A_CHAOTIC : A_NEUTRAL; } /* * Specially aligned monsters are named specially. * - aligned priests with ispriest and high priests have shrines * they retain ispriest and epri when polymorphed * - aligned priests without ispriest are roamers * they have isminion set and use emin rather than epri * - minions do not have ispriest but have isminion and emin * - caller needs to inhibit Hallucination if it wants to force * the true name even when under that influence */ char * priestname(mon, pname) register struct monst *mon; char *pname; /* caller-supplied output buffer */ { boolean do_hallu = Hallucination, aligned_priest = mon->data == &mons[PM_ALIGNED_PRIEST], high_priest = mon->data == &mons[PM_HIGH_PRIEST]; char whatcode = '\0'; const char *what = do_hallu ? rndmonnam(&whatcode) : mon->data->mname; if (!mon->ispriest && !mon->isminion) /* should never happen... */ return strcpy(pname, what); /* caller must be confused */ *pname = '\0'; if (!do_hallu || !bogon_is_pname(whatcode)) Strcat(pname, "the "); if (mon->minvis) Strcat(pname, "invisible "); if (mon->isminion && EMIN(mon)->renegade) Strcat(pname, "renegade "); if (mon->ispriest || aligned_priest) { /* high_priest implies ispriest */ if (!aligned_priest && !high_priest) { ; /* polymorphed priest; use ``what'' as is */ } else { if (high_priest) Strcat(pname, "high "); if (Hallucination) what = "poohbah"; else if (mon->female) what = "priestess"; else what = "priest"; } } else { if (mon->mtame && !strcmpi(what, "Angel")) Strcat(pname, "guardian "); } Strcat(pname, what); /* same as distant_monnam(), more or less... */ if (do_hallu || !high_priest || !Is_astralevel(&u.uz) || distu(mon->mx, mon->my) <= 2 || program_state.gameover) { Strcat(pname, " of "); Strcat(pname, halu_gname(mon_aligntyp(mon))); } return pname; } boolean p_coaligned(priest) struct monst *priest; { return (boolean) (u.ualign.type == mon_aligntyp(priest)); } STATIC_OVL boolean has_shrine(pri) struct monst *pri; { struct rm *lev; struct epri *epri_p; if (!pri || !pri->ispriest) return FALSE; epri_p = EPRI(pri); lev = &levl[epri_p->shrpos.x][epri_p->shrpos.y]; if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE)) return FALSE; return (boolean) (epri_p->shralign == (Amask2align(lev->altarmask & ~AM_SHRINE))); } struct monst * findpriest(roomno) char roomno; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->ispriest && (EPRI(mtmp)->shroom == roomno) && histemple_at(mtmp, mtmp->mx, mtmp->my)) return mtmp; } return (struct monst *) 0; } /* called from check_special_room() when the player enters the temple room */ void intemple(roomno) int roomno; { struct monst *priest, *mtmp; struct epri *epri_p; boolean shrined, sanctum, can_speak; long *this_time, *other_time; const char *msg1, *msg2; char buf[BUFSZ]; /* don't do anything if hero is already in the room */ if (temple_occupied(u.urooms0)) return; if ((priest = findpriest((char) roomno)) != 0) { /* tended */ epri_p = EPRI(priest); shrined = has_shrine(priest); sanctum = (priest->data == &mons[PM_HIGH_PRIEST] && (Is_sanctum(&u.uz) || In_endgame(&u.uz))); can_speak = (priest->mcanmove && !priest->msleeping); if (can_speak && !Deaf && moves >= epri_p->intone_time) { unsigned save_priest = priest->ispriest; /* don't reveal the altar's owner upon temple entry in the endgame; for the Sanctum, the next message names Moloch so suppress the "of Moloch" for him here too */ if (sanctum && !Hallucination) priest->ispriest = 0; pline("%s intones:", canseemon(priest) ? Monnam(priest) : "A nearby voice"); priest->ispriest = save_priest; epri_p->intone_time = moves + (long) d(10, 500); /* ~2505 */ /* make sure that we don't suppress entry message when we've just given its "priest intones" introduction */ epri_p->enter_time = 0L; } msg1 = msg2 = 0; if (sanctum && Is_sanctum(&u.uz)) { if (priest->mpeaceful) { /* first time inside */ msg1 = "Infidel, you have entered Moloch's Sanctum!"; msg2 = "Be gone!"; priest->mpeaceful = 0; /* became angry voluntarily; no penalty for attacking him */ set_malign(priest); } else { /* repeat visit, or attacked priest before entering */ msg1 = "You desecrate this place by your presence!"; } } else if (moves >= epri_p->enter_time) { Sprintf(buf, "Pilgrim, you enter a %s place!", !shrined ? "desecrated" : "sacred"); msg1 = buf; } if (msg1 && can_speak && !Deaf) { verbalize1(msg1); if (msg2) verbalize1(msg2); epri_p->enter_time = moves + (long) d(10, 100); /* ~505 */ } if (!sanctum) { if (!shrined || !p_coaligned(priest) || u.ualign.record <= ALGN_SINNED) { msg1 = "have a%s forbidding feeling..."; msg2 = (!shrined || !p_coaligned(priest)) ? "" : " strange"; this_time = &epri_p->hostile_time; other_time = &epri_p->peaceful_time; } else { msg1 = "experience %s sense of peace."; msg2 = (u.ualign.record >= ALGN_PIOUS) ? "a" : "an unusual"; this_time = &epri_p->peaceful_time; other_time = &epri_p->hostile_time; } /* give message if we haven't seen it recently or if alignment update has caused it to switch from forbidding to sense-of-peace or vice versa */ if (moves >= *this_time || *other_time >= *this_time) { You(msg1, msg2); *this_time = moves + (long) d(10, 20); /* ~55 */ /* avoid being tricked by the RNG: switch might have just happened and previous random threshold could be larger */ if (*this_time <= *other_time) *other_time = *this_time - 1L; } } /* recognize the Valley of the Dead and Moloch's Sanctum once hero has encountered the temple priest on those levels */ mapseen_temple(priest); } else { /* untended */ switch (rn2(4)) { case 0: You("have an eerie feeling..."); break; case 1: You_feel("like you are being watched."); break; case 2: pline("A shiver runs down your %s.", body_part(SPINE)); break; default: break; /* no message; unfortunately there's no EPRI(priest)->eerie_time available to make sure we give one the first time */ } if (!rn2(5) && (mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS)) != 0) { /* [TODO: alter this (at a minimum, by switching from an exclamation to a simple declaration) if hero has already killed enough ghosts.] */ if (canspotmon(mtmp)) pline("An enormous ghost appears next to you!"); else You("sense a presence close by!"); mtmp->mpeaceful = 0; set_malign(mtmp); if (flags.verbose) You("are frightened to death, and unable to move."); nomul(-3); multi_reason = "being terrified of a demon"; nomovemsg = "You regain your composure."; } } } /* reset the move counters used to limit temple entry feedback; leaving the level and then returning yields a fresh start */ void forget_temple_entry(priest) struct monst *priest; { struct epri *epri_p = priest->ispriest ? EPRI(priest) : 0; if (!epri_p) { impossible("attempting to manipulate shrine data for non-priest?"); return; } epri_p->intone_time = epri_p->enter_time = epri_p->peaceful_time = epri_p->hostile_time = 0L; } void priest_talk(priest) register struct monst *priest; { boolean coaligned = p_coaligned(priest); boolean strayed = (u.ualign.record < 0); /* KMH, conduct */ u.uconduct.gnostic++; if (priest->mflee || (!priest->ispriest && coaligned && strayed)) { pline("%s doesn't want anything to do with you!", Monnam(priest)); priest->mpeaceful = 0; return; } /* priests don't chat unless peaceful and in their own temple */ if (!inhistemple(priest) || !priest->mpeaceful || !priest->mcanmove || priest->msleeping) { static const char *cranky_msg[3] = { "Thou wouldst have words, eh? I'll give thee a word or two!", "Talk? Here is what I have to say!", "Pilgrim, I would speak no longer with thee." }; if (!priest->mcanmove || priest->msleeping) { pline("%s breaks out of %s reverie!", Monnam(priest), mhis(priest)); priest->mfrozen = priest->msleeping = 0; priest->mcanmove = 1; } priest->mpeaceful = 0; verbalize1(cranky_msg[rn2(3)]); return; } /* you desecrated the temple and now you want to chat? */ if (priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE) && !has_shrine(priest)) { verbalize( "Begone! Thou desecratest this holy place with thy presence."); priest->mpeaceful = 0; return; } if (!money_cnt(invent)) { if (coaligned && !strayed) { long pmoney = money_cnt(priest->minvent); if (pmoney > 0L) { /* Note: two bits is actually 25 cents. Hmm. */ pline("%s gives you %s for an ale.", Monnam(priest), (pmoney == 1L) ? "one bit" : "two bits"); money2u(priest, pmoney > 1L ? 2 : 1); } else pline("%s preaches the virtues of poverty.", Monnam(priest)); exercise(A_WIS, TRUE); } else pline("%s is not interested.", Monnam(priest)); return; } else { long offer; pline("%s asks you for a contribution for the temple.", Monnam(priest)); if ((offer = bribe(priest)) == 0) { verbalize("Thou shalt regret thine action!"); if (coaligned) adjalign(-1); } else if (offer < (u.ulevel * 200)) { if (money_cnt(invent) > (offer * 2L)) { verbalize("Cheapskate."); } else { verbalize("I thank thee for thy contribution."); /* give player some token */ exercise(A_WIS, TRUE); } } else if (offer < (u.ulevel * 400)) { verbalize("Thou art indeed a pious individual."); if (money_cnt(invent) < (offer * 2L)) { if (coaligned && u.ualign.record <= ALGN_SINNED) adjalign(1); verbalize("I bestow upon thee a blessing."); incr_itimeout(&HClairvoyant, rn1(500, 500)); } } else if (offer < (u.ulevel * 600) /* u.ublessed is only active when Protection is enabled via something other than worn gear (theft by gremlin clears the intrinsic but not its former magnitude, making it recoverable) */ && (!(HProtection & INTRINSIC) || (u.ublessed < 20 && (u.ublessed < 9 || !rn2(u.ublessed))))) { verbalize("Thy devotion has been rewarded."); if (!(HProtection & INTRINSIC)) { HProtection |= FROMOUTSIDE; if (!u.ublessed) u.ublessed = rn1(3, 2); } else u.ublessed++; } else { verbalize("Thy selfless generosity is deeply appreciated."); if (money_cnt(invent) < (offer * 2L) && coaligned) { if (strayed && (moves - u.ucleansed) > 5000L) { u.ualign.record = 0; /* cleanse thee */ u.ucleansed = moves; } else { adjalign(2); } } } } } struct monst * mk_roamer(ptr, alignment, x, y, peaceful) register struct permonst *ptr; aligntyp alignment; xchar x, y; boolean peaceful; { register struct monst *roamer; register boolean coaligned = (u.ualign.type == alignment); #if 0 /* this was due to permonst's pxlth field which is now gone */ if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) return (struct monst *) 0; #endif if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */ if (!(roamer = makemon(ptr, x, y, MM_ADJACENTOK | MM_EMIN))) return (struct monst *) 0; EMIN(roamer)->min_align = alignment; EMIN(roamer)->renegade = (coaligned && !peaceful); roamer->ispriest = 0; roamer->isminion = 1; roamer->mtrapseen = ~0; /* traps are known */ roamer->mpeaceful = peaceful; roamer->msleeping = 0; set_malign(roamer); /* peaceful may have changed */ /* MORE TO COME */ return roamer; } void reset_hostility(roamer) register struct monst *roamer; { if (!roamer->isminion) return; if (roamer->data != &mons[PM_ALIGNED_PRIEST] && roamer->data != &mons[PM_ANGEL]) return; if (EMIN(roamer)->min_align != u.ualign.type) { roamer->mpeaceful = roamer->mtame = 0; set_malign(roamer); } newsym(roamer->mx, roamer->my); } boolean in_your_sanctuary(mon, x, y) struct monst *mon; /* if non-null, overrides */ xchar x, y; { register char roomno; register struct monst *priest; if (mon) { if (is_minion(mon->data) || is_rider(mon->data)) return FALSE; x = mon->mx, y = mon->my; } if (u.ualign.record <= ALGN_SINNED) /* sinned or worse */ return FALSE; if ((roomno = temple_occupied(u.urooms)) == 0 || roomno != *in_rooms(x, y, TEMPLE)) return FALSE; if ((priest = findpriest(roomno)) == 0) return FALSE; return (boolean) (has_shrine(priest) && p_coaligned(priest) && priest->mpeaceful); } /* when attacking "priest" in his temple */ void ghod_hitsu(priest) struct monst *priest; { int x, y, ax, ay, roomno = (int) temple_occupied(u.urooms); struct mkroom *troom; if (!roomno || !has_shrine(priest)) return; ax = x = EPRI(priest)->shrpos.x; ay = y = EPRI(priest)->shrpos.y; troom = &rooms[roomno - ROOMOFFSET]; if ((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y, 1)) { if (IS_DOOR(levl[u.ux][u.uy].typ)) { if (u.ux == troom->lx - 1) { x = troom->hx; y = u.uy; } else if (u.ux == troom->hx + 1) { x = troom->lx; y = u.uy; } else if (u.uy == troom->ly - 1) { x = u.ux; y = troom->hy; } else if (u.uy == troom->hy + 1) { x = u.ux; y = troom->ly; } } else { switch (rn2(4)) { case 0: x = u.ux; y = troom->ly; break; case 1: x = u.ux; y = troom->hy; break; case 2: x = troom->lx; y = u.uy; break; default: x = troom->hx; y = u.uy; break; } } if (!linedup(u.ux, u.uy, x, y, 1)) return; } switch (rn2(3)) { case 0: pline("%s roars in anger: \"Thou shalt suffer!\"", a_gname_at(ax, ay)); break; case 1: pline("%s voice booms: \"How darest thou harm my servant!\"", s_suffix(a_gname_at(ax, ay))); break; default: pline("%s roars: \"Thou dost profane my shrine!\"", a_gname_at(ax, ay)); break; } buzz(-10 - (AD_ELEC - 1), 6, x, y, sgn(tbx), sgn(tby)); /* bolt of lightning */ exercise(A_WIS, FALSE); } void angry_priest() { register struct monst *priest; struct rm *lev; if ((priest = findpriest(temple_occupied(u.urooms))) != 0) { struct epri *eprip = EPRI(priest); wakeup(priest); /* * If the altar has been destroyed or converted, let the * priest run loose. * (When it's just a conversion and there happens to be * a fresh corpse nearby, the priest ought to have an * opportunity to try converting it back; maybe someday...) */ lev = &levl[eprip->shrpos.x][eprip->shrpos.y]; if (!IS_ALTAR(lev->typ) || ((aligntyp) Amask2align(lev->altarmask & AM_MASK) != eprip->shralign)) { if (!EMIN(priest)) newemin(priest); priest->ispriest = 0; /* now a roaming minion */ priest->isminion = 1; EMIN(priest)->min_align = eprip->shralign; EMIN(priest)->renegade = FALSE; /* discard priest's memory of his former shrine; if we ever implement the re-conversion mentioned above, this will need to be removed */ free_epri(priest); } } } /* * When saving bones, find priests that aren't on their shrine level, * and remove them. This avoids big problems when restoring bones. * [Perhaps we should convert them into roamers instead?] */ void clearpriests() { struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz)) mongone(mtmp); } } /* munge priest-specific structure when restoring -dlc */ void restpriest(mtmp, ghostly) register struct monst *mtmp; boolean ghostly; { if (u.uz.dlevel) { if (ghostly) assign_level(&(EPRI(mtmp)->shrlevel), &u.uz); } } /*priest.c*/ nethack-3.6.0/src/quest.c0000664000076400007660000002766512614623007014252 0ustar paxedpaxed/* NetHack 3.6 quest.c $NHDT-Date: 1446191878 2015/10/30 07:57:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */ /* Copyright 1991, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* quest dungeon branch routines. */ #include "quest.h" #include "qtext.h" #define Not_firsttime (on_level(&u.uz0, &u.uz)) #define Qstat(x) (quest_status.x) STATIC_DCL void NDECL(on_start); STATIC_DCL void NDECL(on_locate); STATIC_DCL void NDECL(on_goal); STATIC_DCL boolean NDECL(not_capable); STATIC_DCL int FDECL(is_pure, (BOOLEAN_P)); STATIC_DCL void FDECL(expulsion, (BOOLEAN_P)); STATIC_DCL void NDECL(chat_with_leader); STATIC_DCL void NDECL(chat_with_nemesis); STATIC_DCL void NDECL(chat_with_guardian); STATIC_DCL void FDECL(prisoner_speaks, (struct monst *)); STATIC_OVL void on_start() { if (!Qstat(first_start)) { qt_pager(QT_FIRSTTIME); Qstat(first_start) = TRUE; } else if ((u.uz0.dnum != u.uz.dnum) || (u.uz0.dlevel < u.uz.dlevel)) { if (Qstat(not_ready) <= 2) qt_pager(QT_NEXTTIME); else qt_pager(QT_OTHERTIME); } } STATIC_OVL void on_locate() { /* the locate messages are phrased in a manner such that they only make sense when arriving on the level from above */ boolean from_above = (u.uz0.dlevel < u.uz.dlevel); if (Qstat(killed_nemesis)) { return; } else if (!Qstat(first_locate)) { if (from_above) qt_pager(QT_FIRSTLOCATE); /* if we've arrived from below this will be a lie, but there won't be any point in delivering the message upon a return visit from above later since the level has now been seen */ Qstat(first_locate) = TRUE; } else { if (from_above) qt_pager(QT_NEXTLOCATE); } } STATIC_OVL void on_goal() { if (Qstat(killed_nemesis)) { return; } else if (!Qstat(made_goal)) { qt_pager(QT_FIRSTGOAL); Qstat(made_goal) = 1; } else { qt_pager(QT_NEXTGOAL); if (Qstat(made_goal) < 7) Qstat(made_goal)++; } } void onquest() { if (u.uevent.qcompleted || Not_firsttime) return; if (!Is_special(&u.uz)) return; if (Is_qstart(&u.uz)) on_start(); else if (Is_qlocate(&u.uz)) on_locate(); else if (Is_nemesis(&u.uz)) on_goal(); return; } void nemdead() { if (!Qstat(killed_nemesis)) { Qstat(killed_nemesis) = TRUE; qt_pager(QT_KILLEDNEM); } } void artitouch(obj) struct obj *obj; { if (!Qstat(touched_artifact)) { /* in case we haven't seen the item yet (ie, currently blinded), this quest message describes it by name so mark it as seen */ obj->dknown = 1; /* only give this message once */ Qstat(touched_artifact) = TRUE; qt_pager(QT_GOTIT); exercise(A_WIS, TRUE); } } /* external hook for do.c (level change check) */ boolean ok_to_quest() { return (boolean) ((Qstat(got_quest) || Qstat(got_thanks)) && is_pure(FALSE) > 0); } STATIC_OVL boolean not_capable() { return (boolean) (u.ulevel < MIN_QUEST_LEVEL); } STATIC_OVL int is_pure(talk) boolean talk; { int purity; aligntyp original_alignment = u.ualignbase[A_ORIGINAL]; if (wizard && talk) { if (u.ualign.type != original_alignment) { You("are currently %s instead of %s.", align_str(u.ualign.type), align_str(original_alignment)); } else if (u.ualignbase[A_CURRENT] != original_alignment) { You("have converted."); } else if (u.ualign.record < MIN_QUEST_ALIGN) { You("are currently %d and require %d.", u.ualign.record, MIN_QUEST_ALIGN); if (yn_function("adjust?", (char *) 0, 'y') == 'y') u.ualign.record = MIN_QUEST_ALIGN; } } purity = (u.ualign.record >= MIN_QUEST_ALIGN && u.ualign.type == original_alignment && u.ualignbase[A_CURRENT] == original_alignment) ? 1 : (u.ualignbase[A_CURRENT] != original_alignment) ? -1 : 0; return purity; } /* * Expel the player to the stairs on the parent of the quest dungeon. * * This assumes that the hero is currently _in_ the quest dungeon and that * there is a single branch to and from it. */ STATIC_OVL void expulsion(seal) boolean seal; { branch *br; d_level *dest; struct trap *t; int portal_flag; br = dungeon_branch("The Quest"); dest = (br->end1.dnum == u.uz.dnum) ? &br->end2 : &br->end1; portal_flag = u.uevent.qexpelled ? 0 /* returned via artifact? */ : !seal ? 1 : -1; schedule_goto(dest, FALSE, FALSE, portal_flag, (char *) 0, (char *) 0); if (seal) { /* remove the portal to the quest - sealing it off */ int reexpelled = u.uevent.qexpelled; u.uevent.qexpelled = 1; remdun_mapseen(quest_dnum); /* Delete the near portal now; the far (main dungeon side) portal will be deleted as part of arrival on that level. If monster movement is in progress, any who haven't moved yet will now miss out on a chance to wander through it... */ for (t = ftrap; t; t = t->ntrap) if (t->ttyp == MAGIC_PORTAL) break; if (t) deltrap(t); /* (display might be briefly out of sync) */ else if (!reexpelled) impossible("quest portal already gone?"); } } /* Either you've returned to quest leader while carrying the quest artifact or you've just thrown it to/at him or her. If quest completion text hasn't been given yet, give it now. Otherwise give another message about the character keeping the artifact and using the magic portal to return to the dungeon. */ void finish_quest(obj) struct obj *obj; /* quest artifact; possibly null if carrying Amulet */ { struct obj *otmp; if (u.uhave.amulet) { /* unlikely but not impossible */ qt_pager(QT_HASAMULET); /* leader IDs the real amulet but ignores any fakes */ if ((otmp = carrying(AMULET_OF_YENDOR)) != 0) fully_identify_obj(otmp); } else { qt_pager(!Qstat(got_thanks) ? QT_OFFEREDIT : QT_OFFEREDIT2); /* should have obtained bell during quest; if not, suggest returning for it now */ if ((otmp = carrying(BELL_OF_OPENING)) == 0) com_pager(5); } Qstat(got_thanks) = TRUE; if (obj) { u.uevent.qcompleted = 1; /* you did it! */ /* behave as if leader imparts sufficient info about the quest artifact */ fully_identify_obj(obj); update_inventory(); } } STATIC_OVL void chat_with_leader() { /* Rule 0: Cheater checks. */ if (u.uhave.questart && !Qstat(met_nemesis)) Qstat(cheater) = TRUE; /* It is possible for you to get the amulet without completing * the quest. If so, try to induce the player to quest. */ if (Qstat(got_thanks)) { /* Rule 1: You've gone back with/without the amulet. */ if (u.uhave.amulet) finish_quest((struct obj *) 0); /* Rule 2: You've gone back before going for the amulet. */ else qt_pager(QT_POSTHANKS); /* Rule 3: You've got the artifact and are back to return it. */ } else if (u.uhave.questart) { struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) if (is_quest_artifact(otmp)) break; finish_quest(otmp); /* Rule 4: You haven't got the artifact yet. */ } else if (Qstat(got_quest)) { qt_pager(rn1(10, QT_ENCOURAGE)); /* Rule 5: You aren't yet acceptable - or are you? */ } else { if (!Qstat(met_leader)) { qt_pager(QT_FIRSTLEADER); Qstat(met_leader) = TRUE; Qstat(not_ready) = 0; } else qt_pager(QT_NEXTLEADER); /* the quest leader might have passed through the portal into the regular dungeon; none of the remaining make sense there */ if (!on_level(&u.uz, &qstart_level)) return; if (not_capable()) { qt_pager(QT_BADLEVEL); exercise(A_WIS, TRUE); expulsion(FALSE); } else if (is_pure(TRUE) < 0) { com_pager(QT_BANISHED); expulsion(TRUE); } else if (is_pure(TRUE) == 0) { qt_pager(QT_BADALIGN); if (Qstat(not_ready) == MAX_QUEST_TRIES) { qt_pager(QT_LASTLEADER); expulsion(TRUE); } else { Qstat(not_ready)++; exercise(A_WIS, TRUE); expulsion(FALSE); } } else { /* You are worthy! */ qt_pager(QT_ASSIGNQUEST); exercise(A_WIS, TRUE); Qstat(got_quest) = TRUE; } } } void leader_speaks(mtmp) struct monst *mtmp; { /* maybe you attacked leader? */ if (!mtmp->mpeaceful) { Qstat(pissed_off) = TRUE; mtmp->mstrategy &= ~STRAT_WAITMASK; /* end the inaction */ } /* the quest leader might have passed through the portal into the regular dungeon; if so, mustn't perform "backwards expulsion" */ if (!on_level(&u.uz, &qstart_level)) return; if (Qstat(pissed_off)) { qt_pager(QT_LASTLEADER); expulsion(TRUE); } else chat_with_leader(); } STATIC_OVL void chat_with_nemesis() { /* The nemesis will do most of the talking, but... */ qt_pager(rn1(10, QT_DISCOURAGE)); if (!Qstat(met_nemesis)) Qstat(met_nemesis++); } void nemesis_speaks() { if (!Qstat(in_battle)) { if (u.uhave.questart) qt_pager(QT_NEMWANTSIT); else if (Qstat(made_goal) == 1 || !Qstat(met_nemesis)) qt_pager(QT_FIRSTNEMESIS); else if (Qstat(made_goal) < 4) qt_pager(QT_NEXTNEMESIS); else if (Qstat(made_goal) < 7) qt_pager(QT_OTHERNEMESIS); else if (!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE)); if (Qstat(made_goal) < 7) Qstat(made_goal)++; Qstat(met_nemesis) = TRUE; } else /* he will spit out random maledictions */ if (!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE)); } STATIC_OVL void chat_with_guardian() { /* These guys/gals really don't have much to say... */ if (u.uhave.questart && Qstat(killed_nemesis)) qt_pager(rn1(5, QT_GUARDTALK2)); else qt_pager(rn1(5, QT_GUARDTALK)); } STATIC_OVL void prisoner_speaks(mtmp) struct monst *mtmp; { if (mtmp->data == &mons[PM_PRISONER] && (mtmp->mstrategy & STRAT_WAITMASK)) { /* Awaken the prisoner */ if (canseemon(mtmp)) pline("%s speaks:", Monnam(mtmp)); verbalize("I'm finally free!"); mtmp->mstrategy &= ~STRAT_WAITMASK; mtmp->mpeaceful = 1; /* Your god is happy... */ adjalign(3); /* ...But the guards are not */ (void) angry_guards(FALSE); } return; } void quest_chat(mtmp) register struct monst *mtmp; { if (mtmp->m_id == Qstat(leader_m_id)) { chat_with_leader(); return; } switch (mtmp->data->msound) { case MS_NEMESIS: chat_with_nemesis(); break; case MS_GUARDIAN: chat_with_guardian(); break; default: impossible("quest_chat: Unknown quest character %s.", mon_nam(mtmp)); } } void quest_talk(mtmp) struct monst *mtmp; { if (mtmp->m_id == Qstat(leader_m_id)) { leader_speaks(mtmp); return; } switch (mtmp->data->msound) { case MS_NEMESIS: nemesis_speaks(); break; case MS_DJINNI: prisoner_speaks(mtmp); break; default: break; } } void quest_stat_check(mtmp) struct monst *mtmp; { if (mtmp->data->msound == MS_NEMESIS) Qstat(in_battle) = (mtmp->mcanmove && !mtmp->msleeping && monnear(mtmp, u.ux, u.uy)); } /*quest.c*/ nethack-3.6.0/src/questpgr.c0000664000076400007660000004055712625765105014766 0ustar paxedpaxed/* NetHack 3.6 questpgr.c $NHDT-Date: 1448541043 2015/11/26 12:30:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.36 $ */ /* Copyright 1991, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" /* quest-specific pager routines. */ #include "qtext.h" #define QTEXT_FILE "quest.dat" #ifdef TTY_GRAPHICS #include "wintty.h" #endif /* from sp_lev.c, for deliver_splev_message() */ extern char *lev_message; static void NDECL(dump_qtlist); static void FDECL(Fread, (genericptr_t, int, int, dlb *)); STATIC_DCL struct qtmsg *FDECL(construct_qtlist, (long)); STATIC_DCL const char *NDECL(intermed); STATIC_DCL const char *NDECL(neminame); STATIC_DCL const char *NDECL(guardname); STATIC_DCL const char *NDECL(homebase); STATIC_DCL void FDECL(qtext_pronoun, (CHAR_P, CHAR_P)); STATIC_DCL struct qtmsg *FDECL(msg_in, (struct qtmsg *, int)); STATIC_DCL void FDECL(convert_arg, (CHAR_P)); STATIC_DCL void FDECL(convert_line, (char *,char *)); STATIC_DCL void FDECL(deliver_by_pline, (struct qtmsg *)); STATIC_DCL void FDECL(deliver_by_window, (struct qtmsg *, int)); STATIC_DCL boolean FDECL(skip_pager, (BOOLEAN_P)); static char cvt_buf[64]; static struct qtlists qt_list; static dlb *msg_file; /* used by ldrname() and neminame(), then copied into cvt_buf */ static char nambuf[sizeof cvt_buf]; /* dump the character msg list to check appearance; build with DEBUG enabled and use DEBUGFILES=questpgr.c in sysconf file or environment */ static void dump_qtlist() { #ifdef DEBUG struct qtmsg *msg; if (!explicitdebug(__FILE__)) return; for (msg = qt_list.chrole; msg->msgnum > 0; msg++) { (void) dlb_fseek(msg_file, msg->offset, SEEK_SET); deliver_by_window(msg, NHW_MAP); } #endif /* DEBUG */ return; } static void Fread(ptr, size, nitems, stream) genericptr_t ptr; int size, nitems; dlb *stream; { int cnt; if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) { panic("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d", (size * nitems), (size * cnt)); } } STATIC_OVL struct qtmsg * construct_qtlist(hdr_offset) long hdr_offset; { struct qtmsg *msg_list; int n_msgs; (void) dlb_fseek(msg_file, hdr_offset, SEEK_SET); Fread(&n_msgs, sizeof(int), 1, msg_file); msg_list = (struct qtmsg *) alloc((unsigned) (n_msgs + 1) * sizeof (struct qtmsg)); /* * Load up the list. */ Fread((genericptr_t) msg_list, n_msgs * sizeof (struct qtmsg), 1, msg_file); msg_list[n_msgs].msgnum = -1; return msg_list; } void load_qtlist() { int n_classes, i; char qt_classes[N_HDR][LEN_HDR]; long qt_offsets[N_HDR]; msg_file = dlb_fopen(QTEXT_FILE, RDBMODE); if (!msg_file) panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE); /* * Read in the number of classes, then the ID's & offsets for * each header. */ Fread(&n_classes, sizeof (int), 1, msg_file); Fread(&qt_classes[0][0], sizeof (char) * LEN_HDR, n_classes, msg_file); Fread(qt_offsets, sizeof (long), n_classes, msg_file); /* * Now construct the message lists for quick reference later * on when we are actually paging the messages out. */ qt_list.common = qt_list.chrole = (struct qtmsg *) 0; for (i = 0; i < n_classes; i++) { if (!strncmp(COMMON_ID, qt_classes[i], LEN_HDR)) qt_list.common = construct_qtlist(qt_offsets[i]); else if (!strncmp(urole.filecode, qt_classes[i], LEN_HDR)) qt_list.chrole = construct_qtlist(qt_offsets[i]); #if 0 /* UNUSED but available */ else if (!strncmp(urace.filecode, qt_classes[i], LEN_HDR)) qt_list.chrace = construct_qtlist(qt_offsets[i]); #endif } if (!qt_list.common || !qt_list.chrole) impossible("load_qtlist: cannot load quest text."); dump_qtlist(); return; /* no ***DON'T*** close the msg_file */ } /* called at program exit */ void unload_qtlist() { if (msg_file) (void) dlb_fclose(msg_file), msg_file = 0; if (qt_list.common) free((genericptr_t) qt_list.common), qt_list.common = 0; if (qt_list.chrole) free((genericptr_t) qt_list.chrole), qt_list.chrole = 0; return; } short quest_info(typ) int typ; { switch (typ) { case 0: return urole.questarti; case MS_LEADER: return urole.ldrnum; case MS_NEMESIS: return urole.neminum; case MS_GUARDIAN: return urole.guardnum; default: impossible("quest_info(%d)", typ); } return 0; } /* return your role leader's name */ const char * ldrname() { int i = urole.ldrnum; Sprintf(nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ", mons[i].mname); return nambuf; } /* return your intermediate target string */ STATIC_OVL const char * intermed() { return urole.intermed; } boolean is_quest_artifact(otmp) struct obj *otmp; { return (boolean) (otmp->oartifact == urole.questarti); } /* return your role nemesis' name */ STATIC_OVL const char * neminame() { int i = urole.neminum; Sprintf(nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ", mons[i].mname); return nambuf; } STATIC_OVL const char * guardname() /* return your role leader's guard monster name */ { int i = urole.guardnum; return mons[i].mname; } STATIC_OVL const char * homebase() /* return your role leader's location */ { return urole.homebase; } /* replace deity, leader, nemesis, or artifact name with pronoun; overwrites cvt_buf[] */ STATIC_OVL void qtext_pronoun(who, which) char who, /* 'd' => deity, 'l' => leader, 'n' => nemesis, 'o' => artifact */ which; /* 'h'|'H'|'i'|'I'|'j'|'J' */ { const char *pnoun; int g; char lwhich = lowc(which); /* H,I,J -> h,i,j */ /* * Invalid subject (not d,l,n,o) yields neuter, singular result. * * For %o, treat all artifacts as neuter; some have plural names, * which genders[] doesn't handle; cvt_buf[] already contains name. */ if (who == 'o' && (strstri(cvt_buf, "Eyes ") || strcmpi(cvt_buf, makesingular(cvt_buf)))) { pnoun = (lwhich == 'h') ? "they" : (lwhich == 'i') ? "them" : (lwhich == 'j') ? "their" : "?"; } else { g = (who == 'd') ? quest_status.godgend : (who == 'l') ? quest_status.ldrgend : (who == 'n') ? quest_status.nemgend : 2; /* default to neuter */ pnoun = (lwhich == 'h') ? genders[g].he : (lwhich == 'i') ? genders[g].him : (lwhich == 'j') ? genders[g].his : "?"; } Strcpy(cvt_buf, pnoun); /* capitalize for H,I,J */ if (lwhich != which) cvt_buf[0] = highc(cvt_buf[0]); return; } STATIC_OVL struct qtmsg * msg_in(qtm_list, msgnum) struct qtmsg *qtm_list; int msgnum; { struct qtmsg *qt_msg; for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++) if (qt_msg->msgnum == msgnum) return qt_msg; return (struct qtmsg *) 0; } STATIC_OVL void convert_arg(c) char c; { register const char *str; switch (c) { case 'p': str = plname; break; case 'c': str = (flags.female && urole.name.f) ? urole.name.f : urole.name.m; break; case 'r': str = rank_of(u.ulevel, Role_switch, flags.female); break; case 'R': str = rank_of(MIN_QUEST_LEVEL, Role_switch, flags.female); break; case 's': str = (flags.female) ? "sister" : "brother"; break; case 'S': str = (flags.female) ? "daughter" : "son"; break; case 'l': str = ldrname(); break; case 'i': str = intermed(); break; case 'O': case 'o': str = the(artiname(urole.questarti)); if (c == 'O') { /* shorten "the Foo of Bar" to "the Foo" (buffer returned by the() is modifiable) */ char *p = strstri(str, " of "); if (p) *p = '\0'; } break; case 'n': str = neminame(); break; case 'g': str = guardname(); break; case 'G': str = align_gtitle(u.ualignbase[A_ORIGINAL]); break; case 'H': str = homebase(); break; case 'a': str = align_str(u.ualignbase[A_ORIGINAL]); break; case 'A': str = align_str(u.ualign.type); break; case 'd': str = align_gname(u.ualignbase[A_ORIGINAL]); break; case 'D': str = align_gname(A_LAWFUL); break; case 'C': str = "chaotic"; break; case 'N': str = "neutral"; break; case 'L': str = "lawful"; break; case 'x': str = Blind ? "sense" : "see"; break; case 'Z': str = dungeons[0].dname; break; case '%': str = "%"; break; default: str = ""; break; } Strcpy(cvt_buf, str); } STATIC_OVL void convert_line(in_line, out_line) char *in_line, *out_line; { char *c, *cc; char xbuf[BUFSZ]; cc = out_line; for (c = xcrypt(in_line, xbuf); *c; c++) { *cc = 0; switch (*c) { case '\r': case '\n': *(++cc) = 0; return; case '%': if (*(c + 1)) { convert_arg(*(++c)); switch (*(++c)) { /* insert "a"/"an" prefix */ case 'A': Strcat(cc, An(cvt_buf)); cc += strlen(cc); continue; /* for */ case 'a': Strcat(cc, an(cvt_buf)); cc += strlen(cc); continue; /* for */ /* capitalize */ case 'C': cvt_buf[0] = highc(cvt_buf[0]); break; /* replace name with pronoun; valid for %d, %l, %n, and %o */ case 'h': /* he/she */ case 'H': /* He/She */ case 'i': /* him/her */ case 'I': case 'j': /* his/her */ case 'J': if (index("dlno", lowc(*(c - 1)))) qtext_pronoun(*(c - 1), *c); else --c; /* default action */ break; /* pluralize */ case 'P': cvt_buf[0] = highc(cvt_buf[0]); case 'p': Strcpy(cvt_buf, makeplural(cvt_buf)); break; /* append possessive suffix */ case 'S': cvt_buf[0] = highc(cvt_buf[0]); case 's': Strcpy(cvt_buf, s_suffix(cvt_buf)); break; /* strip any "the" prefix */ case 't': if (!strncmpi(cvt_buf, "the ", 4)) { Strcat(cc, &cvt_buf[4]); cc += strlen(cc); continue; /* for */ } break; default: --c; /* undo switch increment */ break; } Strcat(cc, cvt_buf); cc += strlen(cvt_buf); break; } /* else fall through */ default: *cc++ = *c; break; } } if (cc > &out_line[BUFSZ-1]) panic("convert_line: overflow"); *cc = 0; return; } STATIC_OVL void deliver_by_pline(qt_msg) struct qtmsg *qt_msg; { long size; char in_line[BUFSZ], out_line[BUFSZ]; *in_line = '\0'; for (size = 0; size < qt_msg->size; size += (long) strlen(in_line)) { (void) dlb_fgets(in_line, sizeof in_line, msg_file); convert_line(in_line, out_line); pline("%s", out_line); } } STATIC_OVL void deliver_by_window(qt_msg, how) struct qtmsg *qt_msg; int how; { long size; char in_line[BUFSZ], out_line[BUFSZ]; boolean qtdump = (how == NHW_MAP); winid datawin = create_nhwindow(qtdump ? NHW_TEXT : how); #ifdef DEBUG if (qtdump) { char buf[BUFSZ]; /* when dumping quest messages at startup, all of them are passed to * deliver_by_window(), even if normally given to deliver_by_pline() */ Sprintf(buf, "msgnum: %d, delivery: %c", qt_msg->msgnum, qt_msg->delivery); putstr(datawin, 0, buf); putstr(datawin, 0, ""); } #endif for (size = 0; size < qt_msg->size; size += (long) strlen(in_line)) { (void) dlb_fgets(in_line, sizeof in_line, msg_file); convert_line(in_line, out_line); putstr(datawin, 0, out_line); } display_nhwindow(datawin, TRUE); destroy_nhwindow(datawin); /* block messages delivered by window aren't kept in message history but have a one-line summary which is put there for ^P recall */ *out_line = '\0'; if (qt_msg->summary_size) { (void) dlb_fgets(in_line, sizeof in_line, msg_file); convert_line(in_line, out_line); #ifdef BETA } else if (qt_msg->delivery == 'c') { /* skip for 'qtdump' of 'p' */ /* delivery 'c' and !summary_size, summary expected but not present; this doesn't prefix the number with role code vs 'general' but should be good enough for summary verification purposes */ Sprintf(out_line, "[missing block message summary for #%05d]", qt_msg->msgnum); #endif } if (*out_line) putmsghistory(out_line, FALSE); } boolean skip_pager(common) boolean common; { /* WIZKIT: suppress plot feedback if starting with quest artifact */ if (program_state.wizkit_wishing) return TRUE; if (!(common ? qt_list.common : qt_list.chrole)) { panic("%s: no %s quest text data available", common ? "com_pager" : "qt_pager", common ? "common" : "role-specific"); /*NOTREACHED*/ return TRUE; } return FALSE; } void com_pager(msgnum) int msgnum; { struct qtmsg *qt_msg; if (skip_pager(TRUE)) return; if (!(qt_msg = msg_in(qt_list.common, msgnum))) { impossible("com_pager: message %d not found.", msgnum); return; } (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET); if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg); else if (msgnum == 1) deliver_by_window(qt_msg, NHW_MENU); else deliver_by_window(qt_msg, NHW_TEXT); return; } void qt_pager(msgnum) int msgnum; { struct qtmsg *qt_msg; if (skip_pager(FALSE)) return; if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) { impossible("qt_pager: message %d not found.", msgnum); return; } (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET); if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11")) deliver_by_pline(qt_msg); else deliver_by_window(qt_msg, NHW_TEXT); return; } struct permonst * qt_montype() { int qpm; if (rn2(5)) { qpm = urole.enemy1num; if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD)) return &mons[qpm]; return mkclass(urole.enemy1sym, 0); } qpm = urole.enemy2num; if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD)) return &mons[qpm]; return mkclass(urole.enemy2sym, 0); } /* special levels can include a custom arrival message; display it */ void deliver_splev_message() { char *str, *nl, in_line[BUFSZ], out_line[BUFSZ]; /* there's no provision for delivering via window instead of pline */ if (lev_message) { /* lev_message can span multiple lines using embedded newline chars; any segments too long to fit within in_line[] will be truncated */ for (str = lev_message; *str; str = nl + 1) { /* copying will stop at newline if one is present */ copynchars(in_line, str, (int) (sizeof in_line) - 1); /* convert_line() expects encrypted input */ (void) xcrypt(in_line, in_line); convert_line(in_line, out_line); pline("%s", out_line); if ((nl = index(str, '\n')) == 0) break; /* done if no newline */ } free((genericptr_t) lev_message); lev_message = 0; } } /*questpgr.c*/ nethack-3.6.0/src/read.c0000664000076400007660000025066112626765533014034 0ustar paxedpaxed/* NetHack 3.6 read.c $NHDT-Date: 1448862378 2015/11/30 05:46:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.125 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #define Your_Own_Role(mndx) \ ((mndx) == urole.malenum \ || (urole.femalenum != NON_PM && (mndx) == urole.femalenum)) #define Your_Own_Race(mndx) \ ((mndx) == urace.malenum \ || (urace.femalenum != NON_PM && (mndx) == urace.femalenum)) boolean known; static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS, SPBOOK_CLASS, 0 }; static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 }; STATIC_DCL boolean FDECL(learnscrolltyp, (SHORT_P)); STATIC_DCL char * FDECL(erode_obj_text, (struct obj *, char *)); STATIC_DCL void NDECL(do_class_genocide); STATIC_DCL void FDECL(stripspe, (struct obj *)); STATIC_DCL void FDECL(p_glow1, (struct obj *)); STATIC_DCL void FDECL(p_glow2, (struct obj *, const char *)); STATIC_DCL void FDECL(randomize, (int *, int)); STATIC_DCL void FDECL(forget_single_object, (int)); STATIC_DCL void FDECL(forget, (int)); STATIC_DCL int FDECL(maybe_tame, (struct monst *, struct obj *)); STATIC_DCL boolean FDECL(is_valid_stinking_cloud_pos, (int, int, BOOLEAN_P)); STATIC_DCL void FDECL(display_stinking_cloud_positions, (int)); STATIC_PTR void FDECL(set_lit, (int, int, genericptr)); STATIC_OVL boolean learnscrolltyp(scrolltyp) short scrolltyp; { if (!objects[scrolltyp].oc_name_known) { makeknown(scrolltyp); more_experienced(0, 10); return TRUE; } else return FALSE; } /* also called from teleport.c for scroll of teleportation */ void learnscroll(sobj) struct obj *sobj; { /* it's implied that sobj->dknown is set; we couldn't be reading this scroll otherwise */ if (sobj->oclass != SPBOOK_CLASS) (void) learnscrolltyp(sobj->otyp); } char * erode_obj_text(otmp, buf) struct obj *otmp; char *buf; { int erosion = greatest_erosion(otmp); if (erosion) wipeout_text(buf, (int) (strlen(buf) * erosion / (2 * MAX_ERODE)), otmp->o_id ^ (unsigned) ubirthday); return buf; } char * tshirt_text(tshirt, buf) struct obj *tshirt; char *buf; { static const char *shirt_msgs[] = { /* Scott Bigham */ "I explored the Dungeons of Doom and all I got was this lousy T-shirt!", "Is that Mjollnir in your pocket or are you just happy to see me?", "It's not the size of your sword, it's how #enhance'd you are with it.", "Madame Elvira's House O' Succubi Lifetime Customer", "Madame Elvira's House O' Succubi Employee of the Month", "Ludios Vault Guards Do It In Small, Dark Rooms", "Yendor Military Soldiers Do It In Large Groups", "I survived Yendor Military Boot Camp", "Ludios Accounting School Intra-Mural Lacrosse Team", "Oracle(TM) Fountains 10th Annual Wet T-Shirt Contest", "Hey, black dragon! Disintegrate THIS!", "I'm With Stupid -->", "Don't blame me, I voted for Izchak!", "Don't Panic", /* HHGTTG */ "Furinkan High School Athletic Dept.", /* Ranma 1/2 */ "Hel-LOOO, Nurse!", /* Animaniacs */ "=^.^=", "100% goblin hair - do not wash", "Aberzombie and Fitch", "cK -- Cockatrice touches the Kop", "Don't ask me, I only adventure here", "Down with pants!", "d, your dog or a killer?", "FREE PUG AND NEWT!", "Go team ant!", "Got newt?", "Hello, my darlings!", /* Charlie Drake */ "Hey! Nymphs! Steal This T-Shirt!", "I <3 Dungeon of Doom", "I <3 Maud", "I am a Valkyrie. If you see me running, try to keep up.", "I am not a pack rat - I am a collector", "I bounced off a rubber tree", /* Monkey Island */ "Plunder Island Brimstone Beach Club", /* Monkey Island */ "If you can read this, I can hit you with my polearm", "I'm confused!", "I scored with the princess", "I want to live forever or die in the attempt.", "Lichen Park", "LOST IN THOUGHT - please send search party", "Meat is Mordor", "Minetown Better Business Bureau", "Minetown Watch", "Ms. Palm's House of Negotiable Affection -- A Very Reputable House Of Disrepute", "Protection Racketeer", "Real men love Crom", "Somebody stole my Mojo!", "The Hellhound Gang", "The Werewolves", "They Might Be Storm Giants", "Weapons don't kill people, I kill people", "White Zombie", "You're killing me!", "Anhur State University - Home of the Fighting Fire Ants!", "FREE HUGS", "Serial Ascender", "Real men are valkyries", "Young Men's Cavedigging Association", "Occupy Fort Ludios", "I couldn't afford this T-shirt so I stole it!", "Mind flayers suck", "I'm not wearing any pants", "Down with the living!", "Pudding farmer", "Vegetarian", "Hello, I'm War!", }; Strcpy(buf, shirt_msgs[tshirt->o_id % SIZE(shirt_msgs)]); return erode_obj_text(tshirt, buf); } char * apron_text(apron, buf) struct obj *apron; char *buf; { static const char *apron_msgs[] = { "Kiss the cook", "I'm making SCIENCE!", "Don't mess with the chef", "Don't make me poison you", "Gehennom's Kitchen", "Rat: The other white meat", "If you can't stand the heat, get out of Gehennom!", "If we weren't meant to eat animals, why are they made out of meat?", "If you don't like the food, I'll stab you", }; Strcpy(buf, apron_msgs[apron->o_id % SIZE(apron_msgs)]); return erode_obj_text(apron, buf); } int doread() { register struct obj *scroll; boolean confused, nodisappear; known = FALSE; if (check_capacity((char *) 0)) return 0; scroll = getobj(readable, "read"); if (!scroll) return 0; /* outrumor has its own blindness check */ if (scroll->otyp == FORTUNE_COOKIE) { if (flags.verbose) You("break up the cookie and throw away the pieces."); outrumor(bcsign(scroll), BY_COOKIE); if (!Blind) u.uconduct.literate++; useup(scroll); return 1; } else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) { char buf[BUFSZ]; if (Blind) { You_cant("feel any Braille writing."); return 0; } /* can't read shirt worn under suit (under cloak is ok though) */ if (scroll->otyp == T_SHIRT && uarm && scroll == uarmu) { pline("%s shirt is obscured by %s%s.", scroll->unpaid ? "That" : "Your", shk_your(buf, uarm), suit_simple_name(uarm)); return 0; } u.uconduct.literate++; if (flags.verbose) pline("It reads:"); pline("\"%s\"", (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf) : apron_text(scroll, buf)); return 1; } else if (scroll->otyp == CREDIT_CARD) { static const char *card_msgs[] = { "Leprechaun Gold Tru$t - Shamrock Card", "Magic Memory Vault Charge Card", "Larn National Bank", /* Larn */ "First Bank of Omega", /* Omega */ "Bank of Zork - Frobozz Magic Card", /* Zork */ "Ankh-Morpork Merchant's Guild Barter Card", "Ankh-Morpork Thieves' Guild Unlimited Transaction Card", "Ransmannsby Moneylenders Association", "Bank of Gehennom - 99% Interest Card", "Yendorian Express - Copper Card", "Yendorian Express - Silver Card", "Yendorian Express - Gold Card", "Yendorian Express - Mithril Card", "Yendorian Express - Platinum Card", /* must be last */ }; if (Blind) { You("feel the embossed numbers:"); } else { if (flags.verbose) pline("It reads:"); pline("\"%s\"", scroll->oartifact ? card_msgs[SIZE(card_msgs) - 1] : card_msgs[scroll->o_id % (SIZE(card_msgs) - 1)]); } /* Make a credit card number */ pline("\"%d0%d %d%d1 0%d%d0\"", ((scroll->o_id % 89) + 10), (scroll->o_id % 4), (((scroll->o_id * 499) % 899999) + 100000), (scroll->o_id % 10), (!(scroll->o_id % 3)), ((scroll->o_id * 7) % 10)); u.uconduct.literate++; return 1; } else if (scroll->otyp == CAN_OF_GREASE) { pline("This %s has no label.", singular(scroll, xname)); return 0; } else if (scroll->otyp == MAGIC_MARKER) { if (Blind) { You_cant("feel any Braille writing."); return 0; } if (flags.verbose) pline("It reads:"); pline("\"Magic Marker(TM) Red Ink Marker Pen. Water Soluble.\""); u.uconduct.literate++; return 1; } else if (scroll->oclass == COIN_CLASS) { if (Blind) You("feel the embossed words:"); else if (flags.verbose) You("read:"); pline("\"1 Zorkmid. 857 GUE. In Frobs We Trust.\""); u.uconduct.literate++; return 1; } else if (scroll->oartifact == ART_ORB_OF_FATE) { if (Blind) You("feel the engraved signature:"); else pline("It is signed:"); pline("\"Odin.\""); u.uconduct.literate++; return 1; } else if (scroll->otyp == CANDY_BAR) { static const char *wrapper_msgs[] = { "Apollo", /* Lost */ "Moon Crunchy", /* South Park */ "Snacky Cake", "Chocolate Nuggie", "The Small Bar", "Crispy Yum Yum", "Nilla Crunchie", "Berry Bar", "Choco Nummer", "Om-nom", /* Cat Macro */ "Fruity Oaty", /* Serenity */ "Wonka Bar" /* Charlie and the Chocolate Factory */ }; if (Blind) { You_cant("feel any Braille writing."); return 0; } pline("The wrapper reads: \"%s\"", wrapper_msgs[scroll->o_id % SIZE(wrapper_msgs)]); u.uconduct.literate++; return 1; } else if (scroll->oclass != SCROLL_CLASS && scroll->oclass != SPBOOK_CLASS) { pline(silly_thing_to, "read"); return 0; } else if (Blind && (scroll->otyp != SPE_BOOK_OF_THE_DEAD)) { const char *what = 0; if (scroll->oclass == SPBOOK_CLASS) what = "mystic runes"; else if (!scroll->dknown) what = "formula on the scroll"; if (what) { pline("Being blind, you cannot read the %s.", what); return 0; } } confused = (Confusion != 0); #ifdef MAIL if (scroll->otyp == SCR_MAIL) { confused = FALSE; /* override */ /* reading mail is a convenience for the player and takes place outside the game, so shouldn't affect gameplay; on the other hand, it starts by explicitly making the hero actively read something, which is pretty hard to simply ignore; as a compromise, if the player has maintained illiterate conduct so far, and this mail scroll didn't come from bones, ask for confirmation */ if (!u.uconduct.literate) { if (!scroll->spe && yn( "Reading mail will violate \"illiterate\" conduct. Read anyway?" ) != 'y') return 0; } } #endif /* Actions required to win the game aren't counted towards conduct */ /* Novel conduct is handled in read_tribute so exclude it too*/ if (scroll->otyp != SPE_BOOK_OF_THE_DEAD && scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER && scroll->otyp != SPE_NOVEL) u.uconduct.literate++; if (scroll->oclass == SPBOOK_CLASS) { return study_book(scroll); } scroll->in_use = TRUE; /* scroll, not spellbook, now being read */ if (scroll->otyp != SCR_BLANK_PAPER) { /* a few scroll feedback messages describe something happening to the scroll itself, so avoid "it disappears" for those */ nodisappear = (scroll->otyp == SCR_FIRE || (scroll->otyp == SCR_REMOVE_CURSE && scroll->cursed)); if (Blind) pline(nodisappear ? "You %s the formula on the scroll." : "As you %s the formula on it, the scroll disappears.", is_silent(youmonst.data) ? "cogitate" : "pronounce"); else pline(nodisappear ? "You read the scroll." : "As you read the scroll, it disappears."); if (confused) { if (Hallucination) pline("Being so trippy, you screw up..."); else pline("Being confused, you %s the magic words...", is_silent(youmonst.data) ? "misunderstand" : "mispronounce"); } } if (!seffects(scroll)) { if (!objects[scroll->otyp].oc_name_known) { if (known) learnscroll(scroll); else if (!objects[scroll->otyp].oc_uname) docall(scroll); } scroll->in_use = FALSE; if (scroll->otyp != SCR_BLANK_PAPER) useup(scroll); } return 1; } STATIC_OVL void stripspe(obj) register struct obj *obj; { if (obj->blessed || obj->spe <= 0) { pline1(nothing_happens); } else { /* order matters: message, shop handling, actual transformation */ pline("%s briefly.", Yobjnam2(obj, "vibrate")); costly_alteration(obj, COST_UNCHRG); obj->spe = 0; if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN) obj->age = 0; } } STATIC_OVL void p_glow1(otmp) register struct obj *otmp; { pline("%s briefly.", Yobjnam2(otmp, Blind ? "vibrate" : "glow")); } STATIC_OVL void p_glow2(otmp, color) register struct obj *otmp; register const char *color; { pline("%s%s%s for a moment.", Yobjnam2(otmp, Blind ? "vibrate" : "glow"), Blind ? "" : " ", Blind ? "" : hcolor(color)); } /* Is the object chargeable? For purposes of inventory display; it is possible to be able to charge things for which this returns FALSE. */ boolean is_chargeable(obj) struct obj *obj; { if (obj->oclass == WAND_CLASS) return TRUE; /* known && !oc_name_known is possible after amnesia/mind flayer */ if (obj->oclass == RING_CLASS) return (boolean) (objects[obj->otyp].oc_charged && (obj->known || (obj->dknown && objects[obj->otyp].oc_name_known))); if (is_weptool(obj)) /* specific check before general tools */ return FALSE; if (obj->oclass == TOOL_CLASS) return (boolean) objects[obj->otyp].oc_charged; return FALSE; /* why are weapons/armor considered charged anyway? */ } /* recharge an object; curse_bless is -1 if the recharging implement was cursed, +1 if blessed, 0 otherwise. */ void recharge(obj, curse_bless) struct obj *obj; int curse_bless; { register int n; boolean is_cursed, is_blessed; is_cursed = curse_bless < 0; is_blessed = curse_bless > 0; if (obj->oclass == WAND_CLASS) { int lim = (obj->otyp == WAN_WISHING) ? 3 : (objects[obj->otyp].oc_dir != NODIR) ? 8 : 15; /* undo any prior cancellation, even when is_cursed */ if (obj->spe == -1) obj->spe = 0; /* * Recharging might cause wands to explode. * v = number of previous recharges * v = percentage chance to explode on this attempt * v = cumulative odds for exploding * 0 : 0 0 * 1 : 0.29 0.29 * 2 : 2.33 2.62 * 3 : 7.87 10.28 * 4 : 18.66 27.02 * 5 : 36.44 53.62 * 6 : 62.97 82.83 * 7 : 100 100 */ n = (int) obj->recharged; if (n > 0 && (obj->otyp == WAN_WISHING || (n * n * n > rn2(7 * 7 * 7)))) { /* recharge_limit */ wand_explode(obj, rnd(lim)); return; } /* didn't explode, so increment the recharge count */ obj->recharged = (unsigned) (n + 1); /* now handle the actual recharging */ if (is_cursed) { stripspe(obj); } else { n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5); if (!is_blessed) n = rnd(n); if (obj->spe < n) obj->spe = n; else obj->spe++; if (obj->otyp == WAN_WISHING && obj->spe > 3) { wand_explode(obj, 1); return; } if (obj->spe >= lim) p_glow2(obj, NH_BLUE); else p_glow1(obj); #if 0 /*[shop price doesn't vary by charge count]*/ /* update shop bill to reflect new higher price */ if (obj->unpaid) alter_cost(obj, 0L); #endif } } else if (obj->oclass == RING_CLASS && objects[obj->otyp].oc_charged) { /* charging does not affect ring's curse/bless status */ int s = is_blessed ? rnd(3) : is_cursed ? -rnd(2) : 1; boolean is_on = (obj == uleft || obj == uright); /* destruction depends on current state, not adjustment */ if (obj->spe > rn2(7) || obj->spe <= -5) { pline("%s momentarily, then %s!", Yobjnam2(obj, "pulsate"), otense(obj, "explode")); if (is_on) Ring_gone(obj); s = rnd(3 * abs(obj->spe)); /* amount of damage */ useup(obj); losehp(Maybe_Half_Phys(s), "exploding ring", KILLED_BY_AN); } else { long mask = is_on ? (obj == uleft ? LEFT_RING : RIGHT_RING) : 0L; pline("%s spins %sclockwise for a moment.", Yname2(obj), s < 0 ? "counter" : ""); if (s < 0) costly_alteration(obj, COST_DECHNT); /* cause attributes and/or properties to be updated */ if (is_on) Ring_off(obj); obj->spe += s; /* update the ring while it's off */ if (is_on) setworn(obj, mask), Ring_on(obj); /* oartifact: if a touch-sensitive artifact ring is ever created the above will need to be revised */ /* update shop bill to reflect new higher price */ if (s > 0 && obj->unpaid) alter_cost(obj, 0L); } } else if (obj->oclass == TOOL_CLASS) { int rechrg = (int) obj->recharged; if (objects[obj->otyp].oc_charged) { /* tools don't have a limit, but the counter used does */ if (rechrg < 7) /* recharge_limit */ obj->recharged++; } switch (obj->otyp) { case BELL_OF_OPENING: if (is_cursed) stripspe(obj); else if (is_blessed) obj->spe += rnd(3); else obj->spe += 1; if (obj->spe > 5) obj->spe = 5; break; case MAGIC_MARKER: case TINNING_KIT: case EXPENSIVE_CAMERA: if (is_cursed) stripspe(obj); else if (rechrg && obj->otyp == MAGIC_MARKER) { /* previously recharged */ obj->recharged = 1; /* override increment done above */ if (obj->spe < 3) Your("marker seems permanently dried out."); else pline1(nothing_happens); } else if (is_blessed) { n = rn1(16, 15); /* 15..30 */ if (obj->spe + n <= 50) obj->spe = 50; else if (obj->spe + n <= 75) obj->spe = 75; else { int chrg = (int) obj->spe; if ((chrg + n) > 127) obj->spe = 127; else obj->spe += n; } p_glow2(obj, NH_BLUE); } else { n = rn1(11, 10); /* 10..20 */ if (obj->spe + n <= 50) obj->spe = 50; else { int chrg = (int) obj->spe; if ((chrg + n) > 127) obj->spe = 127; else obj->spe += n; } p_glow2(obj, NH_WHITE); } break; case OIL_LAMP: case BRASS_LANTERN: if (is_cursed) { stripspe(obj); if (obj->lamplit) { if (!Blind) pline("%s out!", Tobjnam(obj, "go")); end_burn(obj, TRUE); } } else if (is_blessed) { obj->spe = 1; obj->age = 1500; p_glow2(obj, NH_BLUE); } else { obj->spe = 1; obj->age += 750; if (obj->age > 1500) obj->age = 1500; p_glow1(obj); } break; case CRYSTAL_BALL: if (is_cursed) { stripspe(obj); } else if (is_blessed) { obj->spe = 6; p_glow2(obj, NH_BLUE); } else { if (obj->spe < 5) { obj->spe++; p_glow1(obj); } else pline1(nothing_happens); } break; case HORN_OF_PLENTY: case BAG_OF_TRICKS: case CAN_OF_GREASE: if (is_cursed) { stripspe(obj); } else if (is_blessed) { if (obj->spe <= 10) obj->spe += rn1(10, 6); else obj->spe += rn1(5, 6); if (obj->spe > 50) obj->spe = 50; p_glow2(obj, NH_BLUE); } else { obj->spe += rnd(5); if (obj->spe > 50) obj->spe = 50; p_glow1(obj); } break; case MAGIC_FLUTE: case MAGIC_HARP: case FROST_HORN: case FIRE_HORN: case DRUM_OF_EARTHQUAKE: if (is_cursed) { stripspe(obj); } else if (is_blessed) { obj->spe += d(2, 4); if (obj->spe > 20) obj->spe = 20; p_glow2(obj, NH_BLUE); } else { obj->spe += rnd(4); if (obj->spe > 20) obj->spe = 20; p_glow1(obj); } break; default: goto not_chargable; /*NOTREACHED*/ break; } /* switch */ } else { not_chargable: You("have a feeling of loss."); } } /* Forget known information about this object type. */ STATIC_OVL void forget_single_object(obj_id) int obj_id; { objects[obj_id].oc_name_known = 0; objects[obj_id].oc_pre_discovered = 0; /* a discovery when relearned */ if (objects[obj_id].oc_uname) { free((genericptr_t) objects[obj_id].oc_uname); objects[obj_id].oc_uname = 0; } undiscover_object(obj_id); /* after clearing oc_name_known */ /* clear & free object names from matching inventory items too? */ } #if 0 /* here if anyone wants it.... */ /* Forget everything known about a particular object class. */ STATIC_OVL void forget_objclass(oclass) int oclass; { int i; for (i = bases[oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) forget_single_object(i); } #endif /* randomize the given list of numbers 0 <= i < count */ STATIC_OVL void randomize(indices, count) int *indices; int count; { int i, iswap, temp; for (i = count - 1; i > 0; i--) { if ((iswap = rn2(i + 1)) == i) continue; temp = indices[i]; indices[i] = indices[iswap]; indices[iswap] = temp; } } /* Forget % of known objects. */ void forget_objects(percent) int percent; { int i, count; int indices[NUM_OBJECTS]; if (percent == 0) return; if (percent <= 0 || percent > 100) { impossible("forget_objects: bad percent %d", percent); return; } indices[0] = 0; /* lint suppression */ for (count = 0, i = 1; i < NUM_OBJECTS; i++) if (OBJ_DESCR(objects[i]) && (objects[i].oc_name_known || objects[i].oc_uname)) indices[count++] = i; if (count > 0) { randomize(indices, count); /* forget first % of randomized indices */ count = ((count * percent) + rn2(100)) / 100; for (i = 0; i < count; i++) forget_single_object(indices[i]); } } /* Forget some or all of map (depends on parameters). */ void forget_map(howmuch) int howmuch; { register int zx, zy; if (Sokoban) return; known = TRUE; for (zx = 0; zx < COLNO; zx++) for (zy = 0; zy < ROWNO; zy++) if (howmuch & ALL_MAP || rn2(7)) { /* Zonk all memory of this location. */ levl[zx][zy].seenv = 0; levl[zx][zy].waslit = 0; levl[zx][zy].glyph = cmap_to_glyph(S_stone); lastseentyp[zx][zy] = STONE; } /* forget overview data for this level */ forget_mapseen(ledger_no(&u.uz)); } /* Forget all traps on the level. */ void forget_traps() { register struct trap *trap; /* forget all traps (except the one the hero is in :-) */ for (trap = ftrap; trap; trap = trap->ntrap) if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE)) trap->tseen = 0; } /* * Forget given % of all levels that the hero has visited and not forgotten, * except this one. */ void forget_levels(percent) int percent; { int i, count; xchar maxl, this_lev; int indices[MAXLINFO]; if (percent == 0) return; if (percent <= 0 || percent > 100) { impossible("forget_levels: bad percent %d", percent); return; } this_lev = ledger_no(&u.uz); maxl = maxledgerno(); /* count & save indices of non-forgotten visited levels */ /* Sokoban levels are pre-mapped for the player, and should stay * so, or they become nearly impossible to solve. But try to * shift the forgetting elsewhere by fiddling with percent * instead of forgetting fewer levels. */ indices[0] = 0; /* lint suppression */ for (count = 0, i = 0; i <= maxl; i++) if ((level_info[i].flags & VISITED) && !(level_info[i].flags & FORGOTTEN) && i != this_lev) { if (ledger_to_dnum(i) == sokoban_dnum) percent += 2; else indices[count++] = i; } if (percent > 100) percent = 100; if (count > 0) { randomize(indices, count); /* forget first % of randomized indices */ count = ((count * percent) + 50) / 100; for (i = 0; i < count; i++) { level_info[indices[i]].flags |= FORGOTTEN; forget_mapseen(indices[i]); } } } /* * Forget some things (e.g. after reading a scroll of amnesia). When called, * the following are always forgotten: * - felt ball & chain * - traps * - part (6 out of 7) of the map * * Other things are subject to flags: * howmuch & ALL_MAP = forget whole map * howmuch & ALL_SPELLS = forget all spells */ STATIC_OVL void forget(howmuch) int howmuch; { if (Punished) u.bc_felt = 0; /* forget felt ball&chain */ forget_map(howmuch); forget_traps(); /* 1 in 3 chance of forgetting some levels */ if (!rn2(3)) forget_levels(rn2(25)); /* 1 in 3 chance of forgetting some objects */ if (!rn2(3)) forget_objects(rn2(25)); if (howmuch & ALL_SPELLS) losespells(); /* * Make sure that what was seen is restored correctly. To do this, * we need to go blind for an instant --- turn off the display, * then restart it. All this work is needed to correctly handle * walls which are stone on one side and wall on the other. Turning * off the seen bits above will make the wall revert to stone, but * there are cases where we don't want this to happen. The easiest * thing to do is to run it through the vision system again, which * is always correct. */ docrt(); /* this correctly will reset vision */ } /* monster is hit by scroll of taming's effect */ STATIC_OVL int maybe_tame(mtmp, sobj) struct monst *mtmp; struct obj *sobj; { int was_tame = mtmp->mtame; unsigned was_peaceful = mtmp->mpeaceful; if (sobj->cursed) { setmangry(mtmp); if (was_peaceful && !mtmp->mpeaceful) return -1; } else { if (mtmp->isshk) make_happy_shk(mtmp, FALSE); else if (!resist(mtmp, sobj->oclass, 0, NOTELL)) (void) tamedog(mtmp, (struct obj *) 0); if ((!was_peaceful && mtmp->mpeaceful) || (!was_tame && mtmp->mtame)) return 1; } return 0; } boolean is_valid_stinking_cloud_pos(x, y, showmsg) int x, y; boolean showmsg; { if (!cansee(x, y) || !ACCESSIBLE(levl[x][y].typ) || distu(x, y) >= 32) { if (showmsg) You("smell rotten eggs."); return FALSE; } return TRUE; } void display_stinking_cloud_positions(state) int state; { if (state == 0) { tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos)); } else if (state == 1) { int x, y, dx, dy; int dist = 6; for (dx = -dist; dx <= dist; dx++) for (dy = -dist; dy <= dist; dy++) { x = u.ux + dx; y = u.uy + dy; if (isok(x, y) && is_valid_stinking_cloud_pos(x, y, FALSE)) tmp_at(x, y); } } else { tmp_at(DISP_END, 0); } } /* scroll effects; return 1 if we use up the scroll and possibly make it become discovered, 0 if caller should take care of those side-effects */ int seffects(sobj) struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ { int cval, otyp = sobj->otyp; boolean confused = (Confusion != 0), sblessed = sobj->blessed, scursed = sobj->cursed, already_known, old_erodeproof, new_erodeproof; struct obj *otmp; if (objects[otyp].oc_magic) exercise(A_WIS, TRUE); /* just for trying */ already_known = (sobj->oclass == SPBOOK_CLASS /* spell */ || objects[otyp].oc_name_known); switch (otyp) { #ifdef MAIL case SCR_MAIL: known = TRUE; if (sobj->spe) pline( "This seems to be junk mail addressed to the finder of the Eye of Larn."); /* note to the puzzled: the game Larn actually sends you junk * mail if you win! */ else readmail(sobj); break; #endif case SCR_ENCHANT_ARMOR: { register schar s; boolean special_armor; boolean same_color; otmp = some_armor(&youmonst); if (!otmp) { strange_feeling(sobj, !Blind ? "Your skin glows then fades." : "Your skin feels warm for a moment."); sobj = 0; /* useup() in strange_feeling() */ exercise(A_CON, !scursed); exercise(A_STR, !scursed); break; } if (confused) { old_erodeproof = (otmp->oerodeproof != 0); new_erodeproof = !scursed; otmp->oerodeproof = 0; /* for messages */ if (Blind) { otmp->rknown = FALSE; pline("%s warm for a moment.", Yobjnam2(otmp, "feel")); } else { otmp->rknown = TRUE; pline("%s covered by a %s %s %s!", Yobjnam2(otmp, "are"), scursed ? "mottled" : "shimmering", hcolor(scursed ? NH_BLACK : NH_GOLDEN), scursed ? "glow" : (is_shield(otmp) ? "layer" : "shield")); } if (new_erodeproof && (otmp->oeroded || otmp->oeroded2)) { otmp->oeroded = otmp->oeroded2 = 0; pline("%s as good as new!", Yobjnam2(otmp, Blind ? "feel" : "look")); } if (old_erodeproof && !new_erodeproof) { /* restore old_erodeproof before shop charges */ otmp->oerodeproof = 1; costly_alteration(otmp, COST_DEGRD); } otmp->oerodeproof = new_erodeproof ? 1 : 0; break; } /* elven armor vibrates warningly when enchanted beyond a limit */ special_armor = is_elven_armor(otmp) || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM); if (scursed) same_color = (otmp->otyp == BLACK_DRAGON_SCALE_MAIL || otmp->otyp == BLACK_DRAGON_SCALES); else same_color = (otmp->otyp == SILVER_DRAGON_SCALE_MAIL || otmp->otyp == SILVER_DRAGON_SCALES || otmp->otyp == SHIELD_OF_REFLECTION); if (Blind) same_color = FALSE; /* KMH -- catch underflow */ s = scursed ? -otmp->spe : otmp->spe; if (s > (special_armor ? 5 : 3) && rn2(s)) { otmp->in_use = TRUE; pline("%s violently %s%s%s for a while, then %s.", Yname2(otmp), otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : "", (Blind || same_color) ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER), otense(otmp, "evaporate")); remove_worn_item(otmp, FALSE); useup(otmp); break; } s = scursed ? -1 : otmp->spe >= 9 ? (rn2(otmp->spe) == 0) : sblessed ? rnd(3 - otmp->spe / 3) : 1; if (s >= 0 && Is_dragon_scales(otmp)) { /* dragon scales get turned into dragon scale mail */ pline("%s merges and hardens!", Yname2(otmp)); setworn((struct obj *) 0, W_ARM); /* assumes same order */ otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES; if (sblessed) { otmp->spe++; if (!otmp->blessed) bless(otmp); } else if (otmp->cursed) uncurse(otmp); otmp->known = 1; setworn(otmp, W_ARM); if (otmp->unpaid) alter_cost(otmp, 0L); /* shop bill */ break; } pline("%s %s%s%s%s for a %s.", Yname2(otmp), s == 0 ? "violently " : "", otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : "", (Blind || same_color) ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER), (s * s > 1) ? "while" : "moment"); /* [this cost handling will need updating if shop pricing is ever changed to care about curse/bless status of armor] */ if (s < 0) costly_alteration(otmp, COST_DECHNT); if (scursed && !otmp->cursed) curse(otmp); else if (sblessed && !otmp->blessed) bless(otmp); if (s) { otmp->spe += s; adj_abon(otmp, s); known = otmp->known; /* update shop bill to reflect new higher price */ if (s > 0 && otmp->unpaid) alter_cost(otmp, 0L); } if ((otmp->spe > (special_armor ? 5 : 3)) && (special_armor || !rn2(7))) pline("%s %s.", Yobjnam2(otmp, "suddenly vibrate"), Blind ? "again" : "unexpectedly"); break; } case SCR_DESTROY_ARMOR: { otmp = some_armor(&youmonst); if (confused) { if (!otmp) { strange_feeling(sobj, "Your bones itch."); sobj = 0; /* useup() in strange_feeling() */ exercise(A_STR, FALSE); exercise(A_CON, FALSE); break; } old_erodeproof = (otmp->oerodeproof != 0); new_erodeproof = scursed; otmp->oerodeproof = 0; /* for messages */ p_glow2(otmp, NH_PURPLE); if (old_erodeproof && !new_erodeproof) { /* restore old_erodeproof before shop charges */ otmp->oerodeproof = 1; costly_alteration(otmp, COST_DEGRD); } otmp->oerodeproof = new_erodeproof ? 1 : 0; break; } if (!scursed || !otmp || !otmp->cursed) { if (!destroy_arm(otmp)) { strange_feeling(sobj, "Your skin itches."); sobj = 0; /* useup() in strange_feeling() */ exercise(A_STR, FALSE); exercise(A_CON, FALSE); break; } else known = TRUE; } else { /* armor and scroll both cursed */ pline("%s.", Yobjnam2(otmp, "vibrate")); if (otmp->spe >= -6) { otmp->spe += -1; adj_abon(otmp, -1); } make_stunned((HStun & TIMEOUT) + (long) rn1(10, 10), TRUE); } } break; case SCR_CONFUSE_MONSTER: case SPE_CONFUSE_MONSTER: if (youmonst.data->mlet != S_HUMAN || scursed) { if (!HConfusion) You_feel("confused."); make_confused(HConfusion + rnd(100), FALSE); } else if (confused) { if (!sblessed) { Your("%s begin to %s%s.", makeplural(body_part(HAND)), Blind ? "tingle" : "glow ", Blind ? "" : hcolor(NH_PURPLE)); make_confused(HConfusion + rnd(100), FALSE); } else { pline("A %s%s surrounds your %s.", Blind ? "" : hcolor(NH_RED), Blind ? "faint buzz" : " glow", body_part(HEAD)); make_confused(0L, TRUE); } } else { if (!sblessed) { Your("%s%s %s%s.", makeplural(body_part(HAND)), Blind ? "" : " begin to glow", Blind ? (const char *) "tingle" : hcolor(NH_RED), u.umconf ? " even more" : ""); u.umconf++; } else { if (Blind) Your("%s tingle %s sharply.", makeplural(body_part(HAND)), u.umconf ? "even more" : "very"); else Your("%s glow a%s brilliant %s.", makeplural(body_part(HAND)), u.umconf ? "n even more" : "", hcolor(NH_RED)); /* after a while, repeated uses become less effective */ if (u.umconf >= 40) u.umconf++; else u.umconf += rn1(8, 2); } } break; case SCR_SCARE_MONSTER: case SPE_CAUSE_FEAR: { register int ct = 0; register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (cansee(mtmp->mx, mtmp->my)) { if (confused || scursed) { mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0; mtmp->mcanmove = 1; } else if (!resist(mtmp, sobj->oclass, 0, NOTELL)) monflee(mtmp, 0, FALSE, FALSE); if (!mtmp->mtame) ct++; /* pets don't laugh at you */ } } if (otyp == SCR_SCARE_MONSTER || !ct) You_hear("%s %s.", (confused || scursed) ? "sad wailing" : "maniacal laughter", !ct ? "in the distance" : "close by"); break; } case SCR_BLANK_PAPER: if (Blind) You("don't remember there being any magic words on this scroll."); else pline("This scroll seems to be blank."); known = TRUE; break; case SCR_REMOVE_CURSE: case SPE_REMOVE_CURSE: { register struct obj *obj; You_feel(!Hallucination ? (!confused ? "like someone is helping you." : "like you need some help.") : (!confused ? "in touch with the Universal Oneness." : "the power of the Force against you!")); if (scursed) { pline_The("scroll disintegrates."); } else { for (obj = invent; obj; obj = obj->nobj) { long wornmask; /* gold isn't subject to cursing and blessing */ if (obj->oclass == COIN_CLASS) continue; wornmask = (obj->owornmask & ~(W_BALL | W_ART | W_ARTI)); if (wornmask && !sblessed) { /* handle a couple of special cases; we don't allow auxiliary weapon slots to be used to artificially increase number of worn items */ if (obj == uswapwep) { if (!u.twoweap) wornmask = 0L; } else if (obj == uquiver) { if (obj->oclass == WEAPON_CLASS) { /* mergeable weapon test covers ammo, missiles, spears, daggers & knives */ if (!objects[obj->otyp].oc_merge) wornmask = 0L; } else if (obj->oclass == GEM_CLASS) { /* possibly ought to check whether alternate weapon is a sling... */ if (!uslinging()) wornmask = 0L; } else { /* weptools don't merge and aren't reasonable quivered weapons */ wornmask = 0L; } } } if (sblessed || wornmask || obj->otyp == LOADSTONE || (obj->otyp == LEASH && obj->leashmon)) { /* water price varies by curse/bless status */ boolean shop_h2o = (obj->unpaid && obj->otyp == POT_WATER); if (confused) { blessorcurse(obj, 2); /* lose knowledge of this object's curse/bless state (even if it didn't actually change) */ obj->bknown = 0; /* blessorcurse() only affects uncursed items so no need to worry about price of water going down (hence no costly_alteration) */ if (shop_h2o && (obj->cursed || obj->blessed)) alter_cost(obj, 0L); /* price goes up */ } else if (obj->cursed) { if (shop_h2o) costly_alteration(obj, COST_UNCURS); uncurse(obj); } } } } if (Punished && !confused) unpunish(); if (u.utrap && u.utraptype == TT_BURIEDBALL) { buried_ball_to_freedom(); pline_The("clasp on your %s vanishes.", body_part(LEG)); } update_inventory(); break; } case SCR_CREATE_MONSTER: case SPE_CREATE_MONSTER: if (create_critters(1 + ((confused || scursed) ? 12 : 0) + ((sblessed || rn2(73)) ? 0 : rnd(4)), confused ? &mons[PM_ACID_BLOB] : (struct permonst *) 0, FALSE)) known = TRUE; /* no need to flush monsters; we ask for identification only if the * monsters are not visible */ break; case SCR_ENCHANT_WEAPON: if (confused && uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) { old_erodeproof = (uwep->oerodeproof != 0); new_erodeproof = !scursed; uwep->oerodeproof = 0; /* for messages */ if (Blind) { uwep->rknown = FALSE; Your("weapon feels warm for a moment."); } else { uwep->rknown = TRUE; pline("%s covered by a %s %s %s!", Yobjnam2(uwep, "are"), scursed ? "mottled" : "shimmering", hcolor(scursed ? NH_PURPLE : NH_GOLDEN), scursed ? "glow" : "shield"); } if (new_erodeproof && (uwep->oeroded || uwep->oeroded2)) { uwep->oeroded = uwep->oeroded2 = 0; pline("%s as good as new!", Yobjnam2(uwep, Blind ? "feel" : "look")); } if (old_erodeproof && !new_erodeproof) { /* restore old_erodeproof before shop charges */ uwep->oerodeproof = 1; costly_alteration(uwep, COST_DEGRD); } uwep->oerodeproof = new_erodeproof ? 1 : 0; break; } if (!chwepon(sobj, scursed ? -1 : !uwep ? 1 : (uwep->spe >= 9) ? !rn2(uwep->spe) : sblessed ? rnd(3 - uwep->spe / 3) : 1)) sobj = 0; /* nothing enchanted: strange_feeling -> useup */ break; case SCR_TAMING: case SPE_CHARM_MONSTER: { int candidates, res, results, vis_results; if (u.uswallow) { candidates = 1; results = vis_results = maybe_tame(u.ustuck, sobj); } else { int i, j, bd = confused ? 5 : 1; struct monst *mtmp; /* note: maybe_tame() can return either positive or negative values, but not both for the same scroll */ candidates = results = vis_results = 0; for (i = -bd; i <= bd; i++) for (j = -bd; j <= bd; j++) { if (!isok(u.ux + i, u.uy + j)) continue; if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0 || (!i && !j && (mtmp = u.usteed) != 0)) { ++candidates; res = maybe_tame(mtmp, sobj); results += res; if (canspotmon(mtmp)) vis_results += res; } } } if (!results) { pline("Nothing interesting %s.", !candidates ? "happens" : "seems to happen"); } else { pline_The("neighborhood %s %sfriendlier.", vis_results ? "is" : "seems", (results < 0) ? "un" : ""); if (vis_results > 0) known = TRUE; } } break; case SCR_GENOCIDE: if (!already_known) You("have found a scroll of genocide!"); known = TRUE; if (sblessed) do_class_genocide(); else do_genocide(!scursed | (2 * !!Confusion)); break; case SCR_LIGHT: if (!confused || rn2(5)) { if (!Blind) known = TRUE; litroom(!confused && !scursed, sobj); if (!confused && !scursed) { if (lightdamage(sobj, TRUE, 5)) known = TRUE; } } else { /* could be scroll of create monster, don't set known ...*/ (void) create_critters(1, !scursed ? &mons[PM_YELLOW_LIGHT] : &mons[PM_BLACK_LIGHT], TRUE); if (!objects[sobj->otyp].oc_uname) docall(sobj); } break; case SCR_TELEPORTATION: if (confused || scursed) { level_tele(); } else { known = scrolltele(sobj); } break; case SCR_GOLD_DETECTION: if ((confused || scursed) ? trap_detect(sobj) : gold_detect(sobj)) sobj = 0; /* failure: strange_feeling() -> useup() */ break; case SCR_FOOD_DETECTION: case SPE_DETECT_FOOD: if (food_detect(sobj)) sobj = 0; /* nothing detected: strange_feeling -> useup */ break; case SCR_IDENTIFY: /* known = TRUE; -- handled inline here */ /* use up the scroll first, before makeknown() performs a perm_invent update; also simplifies empty invent check */ useup(sobj); sobj = 0; /* it's gone */ if (confused) You("identify this as an identify scroll."); else if (!already_known || !invent) /* force feedback now if invent became empty after using up this scroll */ pline("This is an identify scroll."); if (!already_known) (void) learnscrolltyp(SCR_IDENTIFY); /*FALLTHRU*/ case SPE_IDENTIFY: cval = 1; if (sblessed || (!scursed && !rn2(5))) { cval = rn2(5); /* note: if cval==0, identify all items */ if (cval == 1 && sblessed && Luck > 0) ++cval; } if (invent && !confused) { identify_pack(cval, !already_known); } else if (otyp == SPE_IDENTIFY) { /* when casting a spell we know we're not confused, so inventory must be empty (another message has already been given above if reading a scroll) */ pline("You're not carrying anything to be identified."); } break; case SCR_CHARGING: if (confused) { if (scursed) { You_feel("discharged."); u.uen = 0; } else { You_feel("charged up!"); u.uen += d(sblessed ? 6 : 4, 4); if (u.uen > u.uenmax) /* if current energy is already at */ u.uenmax = u.uen; /* or near maximum, increase maximum */ else u.uen = u.uenmax; /* otherwise restore current to max */ } context.botl = 1; break; } /* known = TRUE; -- handled inline here */ if (!already_known) { pline("This is a charging scroll."); learnscroll(sobj); } /* use it up now to prevent it from showing in the getobj picklist because the "disappears" message was already delivered */ useup(sobj); sobj = 0; /* it's gone */ otmp = getobj(all_count, "charge"); if (otmp) recharge(otmp, scursed ? -1 : sblessed ? 1 : 0); break; case SCR_MAGIC_MAPPING: if (level.flags.nommap) { Your("mind is filled with crazy lines!"); if (Hallucination) pline("Wow! Modern art."); else Your("%s spins in bewilderment.", body_part(HEAD)); make_confused(HConfusion + rnd(30), FALSE); break; } if (sblessed) { register int x, y; for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (levl[x][y].typ == SDOOR) cvt_sdoor_to_door(&levl[x][y]); /* do_mapping() already reveals secret passages */ } known = TRUE; case SPE_MAGIC_MAPPING: if (level.flags.nommap) { Your("%s spins as %s blocks the spell!", body_part(HEAD), something); make_confused(HConfusion + rnd(30), FALSE); break; } pline("A map coalesces in your mind!"); cval = (scursed && !confused); if (cval) HConfusion = 1; /* to screw up map */ do_mapping(); if (cval) { HConfusion = 0; /* restore */ pline("Unfortunately, you can't grasp the details."); } break; case SCR_AMNESIA: known = TRUE; forget((!sblessed ? ALL_SPELLS : 0) | (!confused || scursed ? ALL_MAP : 0)); if (Hallucination) /* Ommmmmm! */ Your("mind releases itself from mundane concerns."); else if (!strncmpi(plname, "Maud", 4)) pline( "As your mind turns inward on itself, you forget everything else."); else if (rn2(2)) pline("Who was that Maud person anyway?"); else pline("Thinking of Maud you forget everything else."); exercise(A_WIS, FALSE); break; case SCR_FIRE: cval = bcsign(sobj); useup(sobj); sobj = 0; /* it's gone */ if (!already_known) (void) learnscrolltyp(SCR_FIRE); if (confused) { if (Fire_resistance) { shieldeff(u.ux, u.uy); if (!Blind) pline("Oh, look, what a pretty fire in your %s.", makeplural(body_part(HAND))); else You_feel("a pleasant warmth in your %s.", makeplural(body_part(HAND))); } else { pline_The("scroll catches fire and you burn your %s.", makeplural(body_part(HAND))); losehp(1, "scroll of fire", KILLED_BY_AN); } break; } if (Underwater) { pline_The("water around you vaporizes violently!"); } else { pline_The("scroll erupts in a tower of flame!"); iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */ burn_away_slime(); } explode(u.ux, u.uy, 11, (2 * (rn1(3, 3) + 2 * cval) + 1) / 3, SCROLL_CLASS, EXPL_FIERY); break; case SCR_EARTH: /* TODO: handle steeds */ if (!Is_rogue_level(&u.uz) && has_ceiling(&u.uz) && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { register int x, y; int nboulders = 0; /* Identify the scroll */ if (u.uswallow) You_hear("rumbling."); else pline_The("%s rumbles %s you!", ceiling(u.ux, u.uy), sblessed ? "around" : "above"); known = 1; sokoban_guilt(); /* Loop through the surrounding squares */ if (!scursed) for (x = u.ux - 1; x <= u.ux + 1; x++) { for (y = u.uy - 1; y <= u.uy + 1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (x != u.ux || y != u.uy)) { nboulders += drop_boulder_on_monster(x, y, confused, TRUE); } } } /* Attack the player */ if (!sblessed) { drop_boulder_on_player(confused, !scursed, TRUE, FALSE); } else if (!nboulders) pline("But nothing else happens."); } break; case SCR_PUNISHMENT: known = TRUE; if (confused || sblessed) { You_feel("guilty."); break; } punish(sobj); break; case SCR_STINKING_CLOUD: { coord cc; if (!already_known) You("have found a scroll of stinking cloud!"); known = TRUE; pline("Where do you want to center the %scloud?", already_known ? "stinking " : ""); cc.x = u.ux; cc.y = u.uy; getpos_sethilite(display_stinking_cloud_positions); if (getpos(&cc, TRUE, "the desired position") < 0) { pline1(Never_mind); break; } if (!is_valid_stinking_cloud_pos(cc.x, cc.y, TRUE)) break; (void) create_gas_cloud(cc.x, cc.y, 3 + bcsign(sobj), 8 + 4 * bcsign(sobj)); break; } default: impossible("What weird effect is this? (%u)", otyp); } return sobj ? 0 : 1; } void drop_boulder_on_player(confused, helmet_protects, byu, skip_uswallow) boolean confused, helmet_protects, byu, skip_uswallow; { int dmg; struct obj *otmp2; /* hit monster if swallowed */ if (u.uswallow && !skip_uswallow) { drop_boulder_on_monster(u.ux, u.uy, confused, byu); return; } otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE); if (!otmp2) return; otmp2->quan = confused ? rn1(5, 2) : 1; otmp2->owt = weight(otmp2); if (!amorphous(youmonst.data) && !Passes_walls && !noncorporeal(youmonst.data) && !unsolid(youmonst.data)) { You("are hit by %s!", doname(otmp2)); dmg = dmgval(otmp2, &youmonst) * otmp2->quan; if (uarmh && helmet_protects) { if (is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); if (dmg > 2) dmg = 2; } else if (flags.verbose) { pline("%s does not protect you.", Yname2(uarmh)); } } } else dmg = 0; /* Must be before the losehp(), for bones files */ if (!flooreffects(otmp2, u.ux, u.uy, "fall")) { place_object(otmp2, u.ux, u.uy); stackobj(otmp2); newsym(u.ux, u.uy); } if (dmg) losehp(Maybe_Half_Phys(dmg), "scroll of earth", KILLED_BY_AN); } boolean drop_boulder_on_monster(x, y, confused, byu) int x, y; boolean confused, byu; { register struct obj *otmp2; register struct monst *mtmp; /* Make the object(s) */ otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE); if (!otmp2) return FALSE; /* Shouldn't happen */ otmp2->quan = confused ? rn1(5, 2) : 1; otmp2->owt = weight(otmp2); /* Find the monster here (won't be player) */ mtmp = m_at(x, y); if (mtmp && !amorphous(mtmp->data) && !passes_walls(mtmp->data) && !noncorporeal(mtmp->data) && !unsolid(mtmp->data)) { struct obj *helmet = which_armor(mtmp, W_ARMH); int mdmg; if (cansee(mtmp->mx, mtmp->my)) { pline("%s is hit by %s!", Monnam(mtmp), doname(otmp2)); if (mtmp->minvis && !canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); } else if (u.uswallow && mtmp == u.ustuck) You_hear("something hit %s %s over your %s!", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH), body_part(HEAD)); mdmg = dmgval(otmp2, mtmp) * otmp2->quan; if (helmet) { if (is_metallic(helmet)) { if (canspotmon(mtmp)) pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp)); else if (!Deaf) You_hear("a clanging sound."); if (mdmg > 2) mdmg = 2; } else { if (canspotmon(mtmp)) pline("%s's %s does not protect %s.", Monnam(mtmp), xname(helmet), mhim(mtmp)); } } mtmp->mhp -= mdmg; if (mtmp->mhp <= 0) { if (byu) xkilled(mtmp, 1); else { pline("%s is killed.", Monnam(mtmp)); mondied(mtmp); } } } else if (u.uswallow && mtmp == u.ustuck) { obfree(otmp2, (struct obj *) 0); /* fall through to player */ drop_boulder_on_player(confused, TRUE, FALSE, TRUE); return 1; } /* Drop the rock/boulder to the floor */ if (!flooreffects(otmp2, x, y, "fall")) { place_object(otmp2, x, y); stackobj(otmp2); newsym(x, y); /* map the rock */ } return TRUE; } /* overcharging any wand or zapping/engraving cursed wand */ void wand_explode(obj, chg) struct obj *obj; int chg; /* recharging */ { const char *expl = !chg ? "suddenly" : "vibrates violently and"; int dmg, n, k; /* number of damage dice */ if (!chg) chg = 2; /* zap/engrave adjustment */ n = obj->spe + chg; if (n < 2) n = 2; /* arbitrary minimum */ /* size of damage dice */ switch (obj->otyp) { case WAN_WISHING: k = 12; break; case WAN_CANCELLATION: case WAN_DEATH: case WAN_POLYMORPH: case WAN_UNDEAD_TURNING: k = 10; break; case WAN_COLD: case WAN_FIRE: case WAN_LIGHTNING: case WAN_MAGIC_MISSILE: k = 8; break; case WAN_NOTHING: k = 4; break; default: k = 6; break; } /* inflict damage and destroy the wand */ dmg = d(n, k); obj->in_use = TRUE; /* in case losehp() is fatal (or --More--^C) */ pline("%s %s explodes!", Yname2(obj), expl); losehp(Maybe_Half_Phys(dmg), "exploding wand", KILLED_BY_AN); useup(obj); /* obscure side-effect */ exercise(A_STR, FALSE); } /* used to collect gremlins being hit by light so that they can be processed after vision for the entire lit area has been brought up to date */ struct litmon { struct monst *mon; struct litmon *nxt; }; STATIC_VAR struct litmon *gremlins = 0; /* * Low-level lit-field update routine. */ STATIC_PTR void set_lit(x, y, val) int x, y; genericptr_t val; { struct monst *mtmp; struct litmon *gremlin; if (val) { levl[x][y].lit = 1; if ((mtmp = m_at(x, y)) != 0 && mtmp->data == &mons[PM_GREMLIN]) { gremlin = (struct litmon *) alloc(sizeof *gremlin); gremlin->mon = mtmp; gremlin->nxt = gremlins; gremlins = gremlin; } } else { levl[x][y].lit = 0; snuff_light_source(x, y); } } void litroom(on, obj) register boolean on; struct obj *obj; { char is_lit; /* value is irrelevant; we use its address as a `not null' flag for set_lit() */ /* first produce the text (provided you're not blind) */ if (!on) { register struct obj *otmp; if (!Blind) { if (u.uswallow) { pline("It seems even darker in here than before."); } else { if (uwep && artifact_light(uwep) && uwep->lamplit) pline("Suddenly, the only light left comes from %s!", the(xname(uwep))); else You("are surrounded by darkness!"); } } /* the magic douses lamps, et al, too */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->lamplit) (void) snuff_lit(otmp); } else { /* on */ if (u.uswallow) { if (Blind) ; /* no feedback */ else if (is_animal(u.ustuck->data)) pline("%s %s is lit.", s_suffix(Monnam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); else if (is_whirly(u.ustuck->data)) pline("%s shines briefly.", Monnam(u.ustuck)); else pline("%s glistens.", Monnam(u.ustuck)); } else if (!Blind) pline("A lit field surrounds you!"); } /* No-op when swallowed or in water */ if (u.uswallow || Underwater || Is_waterlevel(&u.uz)) return; /* * If we are darkening the room and the hero is punished but not * blind, then we have to pick up and replace the ball and chain so * that we don't remember them if they are out of sight. */ if (Punished && !on && !Blind) move_bc(1, 0, uball->ox, uball->oy, uchain->ox, uchain->oy); if (Is_rogue_level(&u.uz)) { /* Can't use do_clear_area because MAX_RADIUS is too small */ /* rogue lighting must light the entire room */ int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; int rx, ry; if (rnum >= 0) { for (rx = rooms[rnum].lx - 1; rx <= rooms[rnum].hx + 1; rx++) for (ry = rooms[rnum].ly - 1; ry <= rooms[rnum].hy + 1; ry++) set_lit(rx, ry, (genericptr_t) (on ? &is_lit : (char *) 0)); rooms[rnum].rlit = on; } /* hallways remain dark on the rogue level */ } else do_clear_area(u.ux, u.uy, (obj && obj->oclass == SCROLL_CLASS && obj->blessed) ? 9 : 5, set_lit, (genericptr_t) (on ? &is_lit : (char *) 0)); /* * If we are not blind, then force a redraw on all positions in sight * by temporarily blinding the hero. The vision recalculation will * correctly update all previously seen positions *and* correctly * set the waslit bit [could be messed up from above]. */ if (!Blind) { vision_recalc(2); /* replace ball&chain */ if (Punished && !on) move_bc(0, 0, uball->ox, uball->oy, uchain->ox, uchain->oy); } vision_full_recalc = 1; /* delayed vision recalculation */ if (gremlins) { struct litmon *gremlin; /* can't delay vision recalc after all */ vision_recalc(0); /* after vision has been updated, monsters who are affected when hit by light can now be hit by it */ do { gremlin = gremlins; gremlins = gremlin->nxt; light_hits_gremlin(gremlin->mon, rnd(5)); free((genericptr_t) gremlin); } while (gremlins); } } STATIC_OVL void do_class_genocide() { int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0; char buf[BUFSZ]; boolean gameover = FALSE; /* true iff killed self */ for (j = 0;; j++) { if (j >= 5) { pline1(thats_enough_tries); return; } do { getlin("What class of monsters do you wish to genocide?", buf); (void) mungspaces(buf); } while (!*buf); /* choosing "none" preserves genocideless conduct */ if (*buf == '\033' || !strcmpi(buf, "none") || !strcmpi(buf, "nothing")) return; class = name_to_monclass(buf, (int *) 0); if (class == 0 && (i = name_to_mon(buf)) != NON_PM) class = mons[i].mlet; immunecnt = gonecnt = goodcnt = 0; for (i = LOW_PM; i < NUMMONS; i++) { if (mons[i].mlet == class) { if (!(mons[i].geno & G_GENO)) immunecnt++; else if (mvitals[i].mvflags & G_GENOD) gonecnt++; else goodcnt++; } } if (!goodcnt && class != mons[urole.malenum].mlet && class != mons[urace.malenum].mlet) { if (gonecnt) pline("All such monsters are already nonexistent."); else if (immunecnt || class == S_invisible) You("aren't permitted to genocide such monsters."); else if (wizard && buf[0] == '*') { register struct monst *mtmp, *mtmp2; gonecnt = 0; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; mongone(mtmp); gonecnt++; } pline("Eliminated %d monster%s.", gonecnt, plur(gonecnt)); return; } else pline("That %s does not represent any monster.", strlen(buf) == 1 ? "symbol" : "response"); continue; } for (i = LOW_PM; i < NUMMONS; i++) { if (mons[i].mlet == class) { char nam[BUFSZ]; Strcpy(nam, makeplural(mons[i].mname)); /* Although "genus" is Latin for race, the hero benefits * from both race and role; thus genocide affects either. */ if (Your_Own_Role(i) || Your_Own_Race(i) || ((mons[i].geno & G_GENO) && !(mvitals[i].mvflags & G_GENOD))) { /* This check must be first since player monsters might * have G_GENOD or !G_GENO. */ mvitals[i].mvflags |= (G_GENOD | G_NOCORPSE); reset_rndmonst(i); kill_genocided_monsters(); update_inventory(); /* eggs & tins */ pline("Wiped out all %s.", nam); if (Upolyd && i == u.umonnum) { u.mh = -1; if (Unchanging) { if (!feel_dead++) You("die."); /* finish genociding this class of monsters before ultimately dying */ gameover = TRUE; } else rehumanize(); } /* Self-genocide if it matches either your race or role. Assumption: male and female forms share same monster class. */ if (i == urole.malenum || i == urace.malenum) { u.uhp = -1; if (Upolyd) { if (!feel_dead++) You_feel("dead inside."); } else { if (!feel_dead++) You("die."); gameover = TRUE; } } } else if (mvitals[i].mvflags & G_GENOD) { if (!gameover) pline("All %s are already nonexistent.", nam); } else if (!gameover) { /* suppress feedback about quest beings except for those applicable to our own role */ if ((mons[i].msound != MS_LEADER || quest_info(MS_LEADER) == i) && (mons[i].msound != MS_NEMESIS || quest_info(MS_NEMESIS) == i) && (mons[i].msound != MS_GUARDIAN || quest_info(MS_GUARDIAN) == i) /* non-leader/nemesis/guardian role-specific monster */ && (i != PM_NINJA /* nuisance */ || Role_if(PM_SAMURAI))) { boolean named, uniq; named = type_is_pname(&mons[i]) ? TRUE : FALSE; uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE; /* one special case */ if (i == PM_HIGH_PRIEST) uniq = FALSE; You("aren't permitted to genocide %s%s.", (uniq && !named) ? "the " : "", (uniq || named) ? mons[i].mname : nam); } } } } if (gameover || u.uhp == -1) { killer.format = KILLED_BY_AN; Strcpy(killer.name, "scroll of genocide"); if (gameover) done(GENOCIDED); } return; } } #define REALLY 1 #define PLAYER 2 #define ONTHRONE 4 void do_genocide(how) int how; /* 0 = no genocide; create monsters (cursed scroll) */ /* 1 = normal genocide */ /* 3 = forced genocide of player */ /* 5 (4 | 1) = normal genocide from throne */ { char buf[BUFSZ]; register int i, killplayer = 0; register int mndx; register struct permonst *ptr; const char *which; if (how & PLAYER) { mndx = u.umonster; /* non-polymorphed mon num */ ptr = &mons[mndx]; Strcpy(buf, ptr->mname); killplayer++; } else { for (i = 0;; i++) { if (i >= 5) { pline1(thats_enough_tries); return; } getlin("What monster do you want to genocide? [type the name]", buf); (void) mungspaces(buf); /* choosing "none" preserves genocideless conduct */ if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) { /* ... but no free pass if cursed */ if (!(how & REALLY)) { ptr = rndmonst(); if (!ptr) return; /* no message, like normal case */ mndx = monsndx(ptr); break; /* remaining checks don't apply */ } else return; } mndx = name_to_mon(buf); if (mndx == NON_PM || (mvitals[mndx].mvflags & G_GENOD)) { pline("Such creatures %s exist in this world.", (mndx == NON_PM) ? "do not" : "no longer"); continue; } ptr = &mons[mndx]; /* Although "genus" is Latin for race, the hero benefits * from both race and role; thus genocide affects either. */ if (Your_Own_Role(mndx) || Your_Own_Race(mndx)) { killplayer++; break; } if (is_human(ptr)) adjalign(-sgn(u.ualign.type)); if (is_demon(ptr)) adjalign(sgn(u.ualign.type)); if (!(ptr->geno & G_GENO)) { if (!Deaf) { /* fixme: unconditional "caverns" will be silly in some * circumstances */ if (flags.verbose) pline( "A thunderous voice booms through the caverns:"); verbalize("No, mortal! That will not be done."); } continue; } /* KMH -- Unchanging prevents rehumanization */ if (Unchanging && ptr == youmonst.data) killplayer++; break; } } which = "all "; if (Hallucination) { if (Upolyd) Strcpy(buf, youmonst.data->mname); else { Strcpy(buf, (flags.female && urole.name.f) ? urole.name.f : urole.name.m); buf[0] = lowc(buf[0]); } } else { Strcpy(buf, ptr->mname); /* make sure we have standard singular */ if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST]) which = !type_is_pname(ptr) ? "the " : ""; } if (how & REALLY) { /* setting no-corpse affects wishing and random tin generation */ mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE); pline("Wiped out %s%s.", which, (*which != 'a') ? buf : makeplural(buf)); if (killplayer) { /* might need to wipe out dual role */ if (urole.femalenum != NON_PM && mndx == urole.malenum) mvitals[urole.femalenum].mvflags |= (G_GENOD | G_NOCORPSE); if (urole.femalenum != NON_PM && mndx == urole.femalenum) mvitals[urole.malenum].mvflags |= (G_GENOD | G_NOCORPSE); if (urace.femalenum != NON_PM && mndx == urace.malenum) mvitals[urace.femalenum].mvflags |= (G_GENOD | G_NOCORPSE); if (urace.femalenum != NON_PM && mndx == urace.femalenum) mvitals[urace.malenum].mvflags |= (G_GENOD | G_NOCORPSE); u.uhp = -1; if (how & PLAYER) { killer.format = KILLED_BY; Strcpy(killer.name, "genocidal confusion"); } else if (how & ONTHRONE) { /* player selected while on a throne */ killer.format = KILLED_BY_AN; Strcpy(killer.name, "imperious order"); } else { /* selected player deliberately, not confused */ killer.format = KILLED_BY_AN; Strcpy(killer.name, "scroll of genocide"); } /* Polymorphed characters will die as soon as they're rehumanized. */ /* KMH -- Unchanging prevents rehumanization */ if (Upolyd && ptr != youmonst.data) { delayed_killer(POLYMORPH, killer.format, killer.name); You_feel("dead inside."); } else done(GENOCIDED); } else if (ptr == youmonst.data) { rehumanize(); } reset_rndmonst(mndx); kill_genocided_monsters(); update_inventory(); /* in case identified eggs were affected */ } else { int cnt = 0, census = monster_census(FALSE); if (!(mons[mndx].geno & G_UNIQ) && !(mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT))) for (i = rn1(3, 4); i > 0; i--) { if (!makemon(ptr, u.ux, u.uy, NO_MINVENT)) break; /* couldn't make one */ ++cnt; if (mvitals[mndx].mvflags & G_EXTINCT) break; /* just made last one */ } if (cnt) { /* accumulated 'cnt' doesn't take groups into account; assume bringing in new mon(s) didn't remove any old ones */ cnt = monster_census(FALSE) - census; pline("Sent in %s%s.", (cnt > 1) ? "some " : "", (cnt > 1) ? makeplural(buf) : an(buf)); } else pline1(nothing_happens); } } void punish(sobj) struct obj *sobj; { struct obj *reuse_ball = (sobj && sobj->otyp == HEAVY_IRON_BALL) ? sobj : (struct obj *) 0; /* KMH -- Punishment is still okay when you are riding */ if (!reuse_ball) You("are being punished for your misbehavior!"); if (Punished) { Your("iron ball gets heavier."); uball->owt += 160 * (1 + sobj->cursed); return; } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (!reuse_ball) { pline("A ball and chain appears, then falls away."); dropy(mkobj(BALL_CLASS, TRUE)); } else { dropy(reuse_ball); } return; } setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN); if (!reuse_ball) setworn(mkobj(BALL_CLASS, TRUE), W_BALL); else setworn(reuse_ball, W_BALL); uball->spe = 1; /* special ball (see save) */ /* * Place ball & chain if not swallowed. If swallowed, the ball & * chain variables will be set at the next call to placebc(). */ if (!u.uswallow) { placebc(); if (Blind) set_bc(1); /* set up ball and chain variables */ newsym(u.ux, u.uy); /* see ball&chain if can't see self */ } } /* remove the ball and chain */ void unpunish() { struct obj *savechain = uchain; obj_extract_self(uchain); newsym(uchain->ox, uchain->oy); setworn((struct obj *) 0, W_CHAIN); dealloc_obj(savechain); uball->spe = 0; setworn((struct obj *) 0, W_BALL); } /* some creatures have special data structures that only make sense in their * normal locations -- if the player tries to create one elsewhere, or to * revive one, the disoriented creature becomes a zombie */ boolean cant_revive(mtype, revival, from_obj) int *mtype; boolean revival; struct obj *from_obj; { /* SHOPKEEPERS can be revived now */ if (*mtype == PM_GUARD || (*mtype == PM_SHOPKEEPER && !revival) || *mtype == PM_HIGH_PRIEST || *mtype == PM_ALIGNED_PRIEST || *mtype == PM_ANGEL) { *mtype = PM_HUMAN_ZOMBIE; return TRUE; } else if (*mtype == PM_LONG_WORM_TAIL) { /* for create_particular() */ *mtype = PM_LONG_WORM; return TRUE; } else if (unique_corpstat(&mons[*mtype]) && (!from_obj || !has_omonst(from_obj))) { /* unique corpses (from bones or wizard mode wish) or statues (bones or any wish) end up as shapechangers */ *mtype = PM_DOPPELGANGER; return TRUE; } return FALSE; } /* * Make a new monster with the type controlled by the user. * * Note: when creating a monster by class letter, specifying the * "strange object" (']') symbol produces a random monster rather * than a mimic. This behavior quirk is useful so don't "fix" it * (use 'm'--or "mimic"--to create a random mimic). * * Used in wizard mode only (for ^G command and for scroll or spell * of create monster). Once upon a time, an earlier incarnation of * this code was also used for the scroll/spell in explore mode. */ boolean create_particular() { char buf[BUFSZ], *bufp, monclass; int which, tryct, i, firstchoice = NON_PM; struct permonst *whichpm = NULL; struct monst *mtmp; boolean madeany = FALSE; boolean maketame, makepeaceful, makehostile; boolean randmonst = FALSE; tryct = 5; do { monclass = MAXMCLASSES; which = urole.malenum; /* an arbitrary index into mons[] */ maketame = makepeaceful = makehostile = FALSE; getlin("Create what kind of monster? [type the name or symbol]", buf); bufp = mungspaces(buf); if (*bufp == '\033') return FALSE; /* allow the initial disposition to be specified */ if (!strncmpi(bufp, "tame ", 5)) { bufp += 5; maketame = TRUE; } else if (!strncmpi(bufp, "peaceful ", 9)) { bufp += 9; makepeaceful = TRUE; } else if (!strncmpi(bufp, "hostile ", 8)) { bufp += 8; makehostile = TRUE; } /* decide whether a valid monster was chosen */ if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) { randmonst = TRUE; break; } which = name_to_mon(bufp); if (which >= LOW_PM) break; /* got one */ monclass = name_to_monclass(bufp, &which); if (which >= LOW_PM) { monclass = MAXMCLASSES; /* matters below */ break; } else if (monclass > 0) { which = urole.malenum; /* reset from NON_PM */ break; } /* no good; try again... */ pline("I've never heard of such monsters."); } while (--tryct > 0); if (!tryct) { pline1(thats_enough_tries); } else { if (!randmonst) { firstchoice = which; if (cant_revive(&which, FALSE, (struct obj *) 0)) { /* wizard mode can override handling of special monsters */ Sprintf(buf, "Creating %s instead; force %s?", mons[which].mname, mons[firstchoice].mname); if (yn(buf) == 'y') which = firstchoice; } whichpm = &mons[which]; } for (i = 0; i <= multi; i++) { if (monclass != MAXMCLASSES) whichpm = mkclass(monclass, 0); else if (randmonst) whichpm = rndmonst(); mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); if (!mtmp) { /* quit trying if creation failed and is going to repeat */ if (monclass == MAXMCLASSES && !randmonst) break; /* otherwise try again */ continue; } if (maketame) { (void) tamedog(mtmp, (struct obj *) 0); } else if (makepeaceful || makehostile) { mtmp->mtame = 0; /* sanity precaution */ mtmp->mpeaceful = makepeaceful ? 1 : 0; set_malign(mtmp); } madeany = TRUE; /* in case we got a doppelganger instead of what was asked for, make it start out looking like what was asked for */ if (mtmp->cham != NON_PM && firstchoice != NON_PM && mtmp->cham != firstchoice) (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE); } } return madeany; } /*read.c*/ nethack-3.6.0/src/rect.c0000664000076400007660000001000712536476415014040 0ustar paxedpaxed/* NetHack 3.6 rect.c $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) 1990 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" int FDECL(get_rect_ind, (NhRect *)); STATIC_DCL boolean FDECL(intersect, (NhRect *, NhRect *, NhRect *)); /* * In this file, we will handle the various rectangle functions we * need for room generation. */ #define MAXRECT 50 #define XLIM 4 #define YLIM 3 static NhRect rect[MAXRECT + 1]; static int rect_cnt; /* * Initialisation of internal structures. Should be called for every * new level to be build... */ void init_rect() { rect_cnt = 1; rect[0].lx = rect[0].ly = 0; rect[0].hx = COLNO - 1; rect[0].hy = ROWNO - 1; } /* * Search Index of one precise NhRect. * */ int get_rect_ind(r) NhRect *r; { register NhRect *rectp; register int lx, ly, hx, hy; register int i; lx = r->lx; ly = r->ly; hx = r->hx; hy = r->hy; for (i = 0, rectp = &rect[0]; i < rect_cnt; i++, rectp++) if (lx == rectp->lx && ly == rectp->ly && hx == rectp->hx && hy == rectp->hy) return i; return -1; } /* * Search a free rectangle that include the one given in arg */ NhRect * get_rect(r) NhRect *r; { register NhRect *rectp; register int lx, ly, hx, hy; register int i; lx = r->lx; ly = r->ly; hx = r->hx; hy = r->hy; for (i = 0, rectp = &rect[0]; i < rect_cnt; i++, rectp++) if (lx >= rectp->lx && ly >= rectp->ly && hx <= rectp->hx && hy <= rectp->hy) return rectp; return 0; } /* * Get some random NhRect from the list. */ NhRect * rnd_rect() { return rect_cnt > 0 ? &rect[rn2(rect_cnt)] : 0; } /* * Search intersection between two rectangles (r1 & r2). * return TRUE if intersection exist and put it in r3. * otherwise returns FALSE */ STATIC_OVL boolean intersect(r1, r2, r3) NhRect *r1, *r2, *r3; { if (r2->lx > r1->hx || r2->ly > r1->hy || r2->hx < r1->lx || r2->hy < r1->ly) return FALSE; r3->lx = (r2->lx > r1->lx ? r2->lx : r1->lx); r3->ly = (r2->ly > r1->ly ? r2->ly : r1->ly); r3->hx = (r2->hx > r1->hx ? r1->hx : r2->hx); r3->hy = (r2->hy > r1->hy ? r1->hy : r2->hy); if (r3->lx > r3->hx || r3->ly > r3->hy) return FALSE; return TRUE; } /* * Remove a rectangle from the list of free NhRect. */ void remove_rect(r) NhRect *r; { int ind; ind = get_rect_ind(r); if (ind >= 0) rect[ind] = rect[--rect_cnt]; } /* * Add a NhRect to the list. */ void add_rect(r) NhRect *r; { if (rect_cnt >= MAXRECT) { if (wizard) pline("MAXRECT may be too small."); return; } /* Check that this NhRect is not included in another one */ if (get_rect(r)) return; rect[rect_cnt] = *r; rect_cnt++; } /* * Okay, here we have two rectangles (r1 & r2). * r1 was already in the list and r2 is included in r1. * What we want is to allocate r2, that is split r1 into smaller rectangles * then remove it. */ void split_rects(r1, r2) NhRect *r1, *r2; { NhRect r, old_r; int i; old_r = *r1; remove_rect(r1); /* Walk down since rect_cnt & rect[] will change... */ for (i = rect_cnt - 1; i >= 0; i--) if (intersect(&rect[i], r2, &r)) split_rects(&rect[i], &r); if (r2->ly - old_r.ly - 1 > (old_r.hy < ROWNO - 1 ? 2 * YLIM : YLIM + 1) + 4) { r = old_r; r.hy = r2->ly - 2; add_rect(&r); } if (r2->lx - old_r.lx - 1 > (old_r.hx < COLNO - 1 ? 2 * XLIM : XLIM + 1) + 4) { r = old_r; r.hx = r2->lx - 2; add_rect(&r); } if (old_r.hy - r2->hy - 1 > (old_r.ly > 0 ? 2 * YLIM : YLIM + 1) + 4) { r = old_r; r.ly = r2->hy + 2; add_rect(&r); } if (old_r.hx - r2->hx - 1 > (old_r.lx > 0 ? 2 * XLIM : XLIM + 1) + 4) { r = old_r; r.lx = r2->hx + 2; add_rect(&r); } } /*rect.c*/ nethack-3.6.0/src/region.c0000664000076400007660000007662612617413107014376 0ustar paxedpaxed/* NetHack 3.6 region.c $NHDT-Date: 1446892454 2015/11/07 10:34:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.36 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" /* * This should really go into the level structure, but * I'll start here for ease. It *WILL* move into the level * structure eventually. */ static NhRegion **regions; static int n_regions = 0; static int max_regions = 0; #define NO_CALLBACK (-1) boolean FDECL(inside_gas_cloud, (genericptr, genericptr)); boolean FDECL(expire_gas_cloud, (genericptr, genericptr)); boolean FDECL(inside_rect, (NhRect *, int, int)); boolean FDECL(inside_region, (NhRegion *, int, int)); NhRegion *FDECL(create_region, (NhRect *, int)); void FDECL(add_rect_to_reg, (NhRegion *, NhRect *)); void FDECL(add_mon_to_reg, (NhRegion *, struct monst *)); void FDECL(remove_mon_from_reg, (NhRegion *, struct monst *)); boolean FDECL(mon_in_region, (NhRegion *, struct monst *)); #if 0 NhRegion *FDECL(clone_region, (NhRegion *)); #endif void FDECL(free_region, (NhRegion *)); void FDECL(add_region, (NhRegion *)); void FDECL(remove_region, (NhRegion *)); #if 0 void FDECL(replace_mon_regions, (struct monst *,struct monst *)); void FDECL(remove_mon_from_regions, (struct monst *)); NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, const char *,const char *)); boolean FDECL(enter_force_field, (genericptr,genericptr)); NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,long)); #endif STATIC_DCL void FDECL(reset_region_mids, (NhRegion *)); static callback_proc callbacks[] = { #define INSIDE_GAS_CLOUD 0 inside_gas_cloud, #define EXPIRE_GAS_CLOUD 1 expire_gas_cloud }; /* Should be inlined. */ boolean inside_rect(r, x, y) NhRect *r; int x, y; { return (boolean) (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy); } /* * Check if a point is inside a region. */ boolean inside_region(reg, x, y) NhRegion *reg; int x, y; { int i; if (reg == (NhRegion *) 0 || !inside_rect(&(reg->bounding_box), x, y)) return FALSE; for (i = 0; i < reg->nrects; i++) if (inside_rect(&(reg->rects[i]), x, y)) return TRUE; return FALSE; } /* * Create a region. It does not activate it. */ NhRegion * create_region(rects, nrect) NhRect *rects; int nrect; { int i; NhRegion *reg; reg = (NhRegion *) alloc(sizeof(NhRegion)); /* Determines bounding box */ if (nrect > 0) { reg->bounding_box = rects[0]; } else { reg->bounding_box.lx = 99; reg->bounding_box.ly = 99; reg->bounding_box.hx = 0; reg->bounding_box.hy = 0; } reg->nrects = nrect; reg->rects = nrect > 0 ? (NhRect *) alloc((sizeof(NhRect)) * nrect) : (NhRect *) 0; for (i = 0; i < nrect; i++) { if (rects[i].lx < reg->bounding_box.lx) reg->bounding_box.lx = rects[i].lx; if (rects[i].ly < reg->bounding_box.ly) reg->bounding_box.ly = rects[i].ly; if (rects[i].hx > reg->bounding_box.hx) reg->bounding_box.hx = rects[i].hx; if (rects[i].hy > reg->bounding_box.hy) reg->bounding_box.hy = rects[i].hy; reg->rects[i] = rects[i]; } reg->ttl = -1L; /* Defaults */ reg->attach_2_u = FALSE; reg->attach_2_m = 0; /* reg->attach_2_o = NULL; */ reg->enter_msg = (const char *) 0; reg->leave_msg = (const char *) 0; reg->expire_f = NO_CALLBACK; reg->enter_f = NO_CALLBACK; reg->can_enter_f = NO_CALLBACK; reg->leave_f = NO_CALLBACK; reg->can_leave_f = NO_CALLBACK; reg->inside_f = NO_CALLBACK; clear_hero_inside(reg); clear_heros_fault(reg); reg->n_monst = 0; reg->max_monst = 0; reg->monsters = (unsigned int *) 0; reg->arg = zeroany; return reg; } /* * Add rectangle to region. */ void add_rect_to_reg(reg, rect) NhRegion *reg; NhRect *rect; { NhRect *tmp_rect; tmp_rect = (NhRect *) alloc(sizeof(NhRect) * (reg->nrects + 1)); if (reg->nrects > 0) { (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects, (sizeof(NhRect) * reg->nrects)); free((genericptr_t) reg->rects); } tmp_rect[reg->nrects] = *rect; reg->nrects++; reg->rects = tmp_rect; /* Update bounding box if needed */ if (reg->bounding_box.lx > rect->lx) reg->bounding_box.lx = rect->lx; if (reg->bounding_box.ly > rect->ly) reg->bounding_box.ly = rect->ly; if (reg->bounding_box.hx < rect->hx) reg->bounding_box.hx = rect->hx; if (reg->bounding_box.hy < rect->hy) reg->bounding_box.hy = rect->hy; } /* * Add a monster to the region */ void add_mon_to_reg(reg, mon) NhRegion *reg; struct monst *mon; { int i; unsigned *tmp_m; if (reg->max_monst <= reg->n_monst) { tmp_m = (unsigned *) alloc(sizeof(unsigned) * (reg->max_monst + MONST_INC)); if (reg->max_monst > 0) { for (i = 0; i < reg->max_monst; i++) tmp_m[i] = reg->monsters[i]; free((genericptr_t) reg->monsters); } reg->monsters = tmp_m; reg->max_monst += MONST_INC; } reg->monsters[reg->n_monst++] = mon->m_id; } /* * Remove a monster from the region list (it left or died...) */ void remove_mon_from_reg(reg, mon) NhRegion *reg; struct monst *mon; { register int i; for (i = 0; i < reg->n_monst; i++) if (reg->monsters[i] == mon->m_id) { reg->n_monst--; reg->monsters[i] = reg->monsters[reg->n_monst]; return; } } /* * Check if a monster is inside the region. * It's probably quicker to check with the region internal list * than to check for coordinates. */ boolean mon_in_region(reg, mon) NhRegion *reg; struct monst *mon; { int i; for (i = 0; i < reg->n_monst; i++) if (reg->monsters[i] == mon->m_id) return TRUE; return FALSE; } #if 0 /* not yet used */ /* * Clone (make a standalone copy) the region. */ NhRegion * clone_region(reg) NhRegion *reg; { NhRegion *ret_reg; ret_reg = create_region(reg->rects, reg->nrects); ret_reg->ttl = reg->ttl; ret_reg->attach_2_u = reg->attach_2_u; ret_reg->attach_2_m = reg->attach_2_m; /* ret_reg->attach_2_o = reg->attach_2_o; */ ret_reg->expire_f = reg->expire_f; ret_reg->enter_f = reg->enter_f; ret_reg->can_enter_f = reg->can_enter_f; ret_reg->leave_f = reg->leave_f; ret_reg->can_leave_f = reg->can_leave_f; ret_reg->player_flags = reg->player_flags; /* set/clear_hero_inside,&c*/ ret_reg->n_monst = reg->n_monst; if (reg->n_monst > 0) { ret_reg->monsters = (unsigned int *) alloc((sizeof (unsigned)) * reg->n_monst); (void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters, sizeof (unsigned) * reg->n_monst); } else ret_reg->monsters = (unsigned int *) 0; return ret_reg; } #endif /*0*/ /* * Free mem from region. */ void free_region(reg) NhRegion *reg; { if (reg) { if (reg->rects) free((genericptr_t) reg->rects); if (reg->monsters) free((genericptr_t) reg->monsters); if (reg->enter_msg) free((genericptr_t) reg->enter_msg); if (reg->leave_msg) free((genericptr_t) reg->leave_msg); free((genericptr_t) reg); } } /* * Add a region to the list. * This actually activates the region. */ void add_region(reg) NhRegion *reg; { NhRegion **tmp_reg; int i, j; if (max_regions <= n_regions) { tmp_reg = regions; regions = (NhRegion **) alloc(sizeof(NhRegion *) * (max_regions + 10)); if (max_regions > 0) { (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg, max_regions * sizeof(NhRegion *)); free((genericptr_t) tmp_reg); } max_regions += 10; } regions[n_regions] = reg; n_regions++; /* Check for monsters inside the region */ for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++) for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) { /* Some regions can cross the level boundaries */ if (!isok(i, j)) continue; if (MON_AT(i, j) && inside_region(reg, i, j)) add_mon_to_reg(reg, level.monsters[i][j]); if (reg->visible && cansee(i, j)) newsym(i, j); } /* Check for player now... */ if (inside_region(reg, u.ux, u.uy)) set_hero_inside(reg); else clear_hero_inside(reg); } /* * Remove a region from the list & free it. */ void remove_region(reg) NhRegion *reg; { register int i, x, y; for (i = 0; i < n_regions; i++) if (regions[i] == reg) break; if (i == n_regions) return; /* Update screen if necessary */ reg->ttl = -2L; /* for visible_region_at */ if (reg->visible) for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) if (isok(x, y) && inside_region(reg, x, y) && cansee(x, y)) newsym(x, y); free_region(reg); regions[i] = regions[n_regions - 1]; regions[n_regions - 1] = (NhRegion *) 0; n_regions--; } /* * Remove all regions and clear all related data (This must be down * when changing level, for instance). */ void clear_regions() { register int i; for (i = 0; i < n_regions; i++) free_region(regions[i]); n_regions = 0; if (max_regions > 0) free((genericptr_t) regions); max_regions = 0; regions = (NhRegion **) 0; } /* * This function is called every turn. * It makes the regions age, if necessary and calls the appropriate * callbacks when needed. */ void run_regions() { register int i, j, k; int f_indx; /* End of life ? */ /* Do it backward because the array will be modified */ for (i = n_regions - 1; i >= 0; i--) { if (regions[i]->ttl == 0L) { if ((f_indx = regions[i]->expire_f) == NO_CALLBACK || (*callbacks[f_indx])(regions[i], (genericptr_t) 0)) remove_region(regions[i]); } } /* Process remaining regions */ for (i = 0; i < n_regions; i++) { /* Make the region age */ if (regions[i]->ttl > 0L) regions[i]->ttl--; /* Check if player is inside region */ f_indx = regions[i]->inside_f; if (f_indx != NO_CALLBACK && hero_inside(regions[i])) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); /* Check if any monster is inside region */ if (f_indx != NO_CALLBACK) { for (j = 0; j < regions[i]->n_monst; j++) { struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON); if (!mtmp || mtmp->mhp <= 0 || (*callbacks[f_indx])(regions[i], mtmp)) { /* The monster died, remove it from list */ k = (regions[i]->n_monst -= 1); regions[i]->monsters[j] = regions[i]->monsters[k]; regions[i]->monsters[k] = 0; --j; /* current slot has been reused; recheck it next */ } } } } } /* * check whether player enters/leaves one or more regions. */ boolean in_out_region(x, y) xchar x, y; { int i, f_indx; /* First check if we can do the move */ for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], x, y) && !hero_inside(regions[i]) && !regions[i]->attach_2_u) { if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) return FALSE; } else if (hero_inside(regions[i]) && !inside_region(regions[i], x, y) && !regions[i]->attach_2_u) { if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) return FALSE; } } /* Callbacks for the regions we do leave */ for (i = 0; i < n_regions; i++) if (hero_inside(regions[i]) && !regions[i]->attach_2_u && !inside_region(regions[i], x, y)) { clear_hero_inside(regions[i]); if (regions[i]->leave_msg != (const char *) 0) pline1(regions[i]->leave_msg); if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); } /* Callbacks for the regions we do enter */ for (i = 0; i < n_regions; i++) if (!hero_inside(regions[i]) && !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { set_hero_inside(regions[i]); if (regions[i]->enter_msg != (const char *) 0) pline1(regions[i]->enter_msg); if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); } return TRUE; } /* * check whether a monster enters/leaves one or more region. */ boolean m_in_out_region(mon, x, y) struct monst *mon; xchar x, y; { int i, f_indx; /* First check if we can do the move */ for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], x, y) && !mon_in_region(regions[i], mon) && regions[i]->attach_2_m != mon->m_id) { if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], mon)) return FALSE; } else if (mon_in_region(regions[i], mon) && !inside_region(regions[i], x, y) && regions[i]->attach_2_m != mon->m_id) { if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], mon)) return FALSE; } } /* Callbacks for the regions we do leave */ for (i = 0; i < n_regions; i++) if (mon_in_region(regions[i], mon) && regions[i]->attach_2_m != mon->m_id && !inside_region(regions[i], x, y)) { remove_mon_from_reg(regions[i], mon); if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], mon); } /* Callbacks for the regions we do enter */ for (i = 0; i < n_regions; i++) if (!hero_inside(regions[i]) && !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { add_mon_to_reg(regions[i], mon); if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], mon); } return TRUE; } /* * Checks player's regions after a teleport for instance. */ void update_player_regions() { register int i; for (i = 0; i < n_regions; i++) if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy)) set_hero_inside(regions[i]); else clear_hero_inside(regions[i]); } /* * Ditto for a specified monster. */ void update_monster_region(mon) struct monst *mon; { register int i; for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], mon->mx, mon->my)) { if (!mon_in_region(regions[i], mon)) add_mon_to_reg(regions[i], mon); } else { if (mon_in_region(regions[i], mon)) remove_mon_from_reg(regions[i], mon); } } } #if 0 /* not yet used */ /* * Change monster pointer in regions * This happens, for instance, when a monster grows and * need a new structure (internally that is). */ void replace_mon_regions(monold, monnew) struct monst *monold, *monnew; { register int i; for (i = 0; i < n_regions; i++) if (mon_in_region(regions[i], monold)) { remove_mon_from_reg(regions[i], monold); add_mon_to_reg(regions[i], monnew); } } /* * Remove monster from all regions it was in (ie monster just died) */ void remove_mon_from_regions(mon) struct monst *mon; { register int i; for (i = 0; i < n_regions; i++) if (mon_in_region(regions[i], mon)) remove_mon_from_reg(regions[i], mon); } #endif /*0*/ /* * Check if a spot is under a visible region (eg: gas cloud). * Returns NULL if not, otherwise returns region. */ NhRegion * visible_region_at(x, y) xchar x, y; { register int i; for (i = 0; i < n_regions; i++) if (inside_region(regions[i], x, y) && regions[i]->visible && regions[i]->ttl != -2L) return regions[i]; return (NhRegion *) 0; } void show_region(reg, x, y) NhRegion *reg; xchar x, y; { show_glyph(x, y, reg->glyph); } /** * save_regions : */ void save_regions(fd, mode) int fd; int mode; { int i, j; unsigned n; if (!perform_bwrite(mode)) goto skip_lots; bwrite(fd, (genericptr_t) &moves, sizeof(moves)); /* timestamp */ bwrite(fd, (genericptr_t) &n_regions, sizeof(n_regions)); for (i = 0; i < n_regions; i++) { bwrite(fd, (genericptr_t) ®ions[i]->bounding_box, sizeof(NhRect)); bwrite(fd, (genericptr_t) ®ions[i]->nrects, sizeof(short)); for (j = 0; j < regions[i]->nrects; j++) bwrite(fd, (genericptr_t) ®ions[i]->rects[j], sizeof(NhRect)); bwrite(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof(boolean)); n = 0; bwrite(fd, (genericptr_t) ®ions[i]->attach_2_m, sizeof(unsigned)); n = regions[i]->enter_msg != (const char *) 0 ? strlen(regions[i]->enter_msg) : 0; bwrite(fd, (genericptr_t) &n, sizeof n); if (n > 0) bwrite(fd, (genericptr_t) regions[i]->enter_msg, n); n = regions[i]->leave_msg != (const char *) 0 ? strlen(regions[i]->leave_msg) : 0; bwrite(fd, (genericptr_t) &n, sizeof n); if (n > 0) bwrite(fd, (genericptr_t) regions[i]->leave_msg, n); bwrite(fd, (genericptr_t) ®ions[i]->ttl, sizeof(long)); bwrite(fd, (genericptr_t) ®ions[i]->expire_f, sizeof(short)); bwrite(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof(short)); bwrite(fd, (genericptr_t) ®ions[i]->enter_f, sizeof(short)); bwrite(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof(short)); bwrite(fd, (genericptr_t) ®ions[i]->leave_f, sizeof(short)); bwrite(fd, (genericptr_t) ®ions[i]->inside_f, sizeof(short)); bwrite(fd, (genericptr_t) ®ions[i]->player_flags, sizeof(unsigned int)); bwrite(fd, (genericptr_t) ®ions[i]->n_monst, sizeof(short)); for (j = 0; j < regions[i]->n_monst; j++) bwrite(fd, (genericptr_t) ®ions[i]->monsters[j], sizeof(unsigned)); bwrite(fd, (genericptr_t) ®ions[i]->visible, sizeof(boolean)); bwrite(fd, (genericptr_t) ®ions[i]->glyph, sizeof(int)); bwrite(fd, (genericptr_t) ®ions[i]->arg, sizeof(anything)); } skip_lots: if (release_data(mode)) clear_regions(); } void rest_regions(fd, ghostly) int fd; boolean ghostly; /* If a bones file restore */ { int i, j; unsigned n; long tmstamp; char *msg_buf; clear_regions(); /* Just for security */ mread(fd, (genericptr_t) &tmstamp, sizeof(tmstamp)); if (ghostly) tmstamp = 0; else tmstamp = (moves - tmstamp); mread(fd, (genericptr_t) &n_regions, sizeof(n_regions)); max_regions = n_regions; if (n_regions > 0) regions = (NhRegion **) alloc(sizeof(NhRegion *) * n_regions); for (i = 0; i < n_regions; i++) { regions[i] = (NhRegion *) alloc(sizeof(NhRegion)); mread(fd, (genericptr_t) ®ions[i]->bounding_box, sizeof(NhRect)); mread(fd, (genericptr_t) ®ions[i]->nrects, sizeof(short)); if (regions[i]->nrects > 0) regions[i]->rects = (NhRect *) alloc(sizeof(NhRect) * regions[i]->nrects); for (j = 0; j < regions[i]->nrects; j++) mread(fd, (genericptr_t) ®ions[i]->rects[j], sizeof(NhRect)); mread(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof(boolean)); mread(fd, (genericptr_t) ®ions[i]->attach_2_m, sizeof(unsigned)); mread(fd, (genericptr_t) &n, sizeof n); if (n > 0) { msg_buf = (char *) alloc(n + 1); mread(fd, (genericptr_t) msg_buf, n); msg_buf[n] = '\0'; regions[i]->enter_msg = (const char *) msg_buf; } else regions[i]->enter_msg = (const char *) 0; mread(fd, (genericptr_t) &n, sizeof n); if (n > 0) { msg_buf = (char *) alloc(n + 1); mread(fd, (genericptr_t) msg_buf, n); msg_buf[n] = '\0'; regions[i]->leave_msg = (const char *) msg_buf; } else regions[i]->leave_msg = (const char *) 0; mread(fd, (genericptr_t) ®ions[i]->ttl, sizeof(long)); /* check for expired region */ if (regions[i]->ttl >= 0L) regions[i]->ttl = (regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0L; mread(fd, (genericptr_t) ®ions[i]->expire_f, sizeof(short)); mread(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof(short)); mread(fd, (genericptr_t) ®ions[i]->enter_f, sizeof(short)); mread(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof(short)); mread(fd, (genericptr_t) ®ions[i]->leave_f, sizeof(short)); mread(fd, (genericptr_t) ®ions[i]->inside_f, sizeof(short)); mread(fd, (genericptr_t) ®ions[i]->player_flags, sizeof(unsigned int)); if (ghostly) { /* settings pertained to old player */ clear_hero_inside(regions[i]); clear_heros_fault(regions[i]); } mread(fd, (genericptr_t) ®ions[i]->n_monst, sizeof(short)); if (regions[i]->n_monst > 0) regions[i]->monsters = (unsigned *) alloc(sizeof(unsigned) * regions[i]->n_monst); else regions[i]->monsters = (unsigned int *) 0; regions[i]->max_monst = regions[i]->n_monst; for (j = 0; j < regions[i]->n_monst; j++) mread(fd, (genericptr_t) ®ions[i]->monsters[j], sizeof(unsigned)); mread(fd, (genericptr_t) ®ions[i]->visible, sizeof(boolean)); mread(fd, (genericptr_t) ®ions[i]->glyph, sizeof(int)); mread(fd, (genericptr_t) ®ions[i]->arg, sizeof(anything)); } /* remove expired regions, do not trigger the expire_f callback (yet!); also update monster lists if this data is coming from a bones file */ for (i = n_regions - 1; i >= 0; i--) if (regions[i]->ttl == 0L) remove_region(regions[i]); else if (ghostly && regions[i]->n_monst > 0) reset_region_mids(regions[i]); } /* update monster IDs for region being loaded from bones; `ghostly' implied */ STATIC_OVL void reset_region_mids(reg) NhRegion *reg; { int i = 0, n = reg->n_monst; unsigned *mid_list = reg->monsters; while (i < n) if (!lookup_id_mapping(mid_list[i], &mid_list[i])) { /* shrink list to remove missing monster; order doesn't matter */ mid_list[i] = mid_list[--n]; } else { /* move on to next monster */ ++i; } reg->n_monst = n; return; } #if 0 /* not yet used */ /*--------------------------------------------------------------* * * * Create Region with just a message * * * *--------------------------------------------------------------*/ NhRegion * create_msg_region(x, y, w, h, msg_enter, msg_leave) xchar x, y; xchar w, h; const char *msg_enter; const char *msg_leave; { NhRect tmprect; NhRegion *reg = create_region((NhRect *) 0, 0); if (msg_enter) reg->enter_msg = dupstr(msg_enter); if (msg_leave) reg->leave_msg = dupstr(msg_leave); tmprect.lx = x; tmprect.ly = y; tmprect.hx = x + w; tmprect.hy = y + h; add_rect_to_reg(reg, &tmprect); reg->ttl = -1L; return reg; } /*--------------------------------------------------------------* * * * Force Field Related Cod * * (unused yet) * *--------------------------------------------------------------*/ boolean enter_force_field(p1, p2) genericptr_t p1; genericptr_t p2; { struct monst *mtmp; if (p2 == (genericptr_t) 0) { /* That means the player */ if (!Blind) You("bump into %s. Ouch!", Hallucination ? "an invisible tree" : "some kind of invisible wall"); else pline("Ouch!"); } else { mtmp = (struct monst *) p2; if (canseemon(mtmp)) pline("%s bumps into %s!", Monnam(mtmp), something); } return FALSE; } NhRegion * create_force_field(x, y, radius, ttl) xchar x, y; int radius; long ttl; { int i; NhRegion *ff; int nrect; NhRect tmprect; ff = create_region((NhRect *) 0, 0); nrect = radius; tmprect.lx = x; tmprect.hx = x; tmprect.ly = y - (radius - 1); tmprect.hy = y + (radius - 1); for (i = 0; i < nrect; i++) { add_rect_to_reg(ff, &tmprect); tmprect.lx--; tmprect.hx++; tmprect.ly++; tmprect.hy--; } ff->ttl = ttl; if (!in_mklev && !context.mon_moving) set_heros_fault(ff); /* assume player has created it */ /* ff->can_enter_f = enter_force_field; */ /* ff->can_leave_f = enter_force_field; */ add_region(ff); return ff; } #endif /*0*/ /*--------------------------------------------------------------* * * * Gas cloud related code * * * *--------------------------------------------------------------*/ /* * Here is an example of an expire function that may prolong * region life after some mods... */ /*ARGSUSED*/ boolean expire_gas_cloud(p1, p2) genericptr_t p1; genericptr_t p2 UNUSED; { NhRegion *reg; int damage; reg = (NhRegion *) p1; damage = reg->arg.a_int; /* If it was a thick cloud, it dissipates a little first */ if (damage >= 5) { damage /= 2; /* It dissipates, let's do less damage */ reg->arg = zeroany; reg->arg.a_int = damage; reg->ttl = 2L; /* Here's the trick : reset ttl */ return FALSE; /* THEN return FALSE, means "still there" */ } return TRUE; /* OK, it's gone, you can free it! */ } boolean inside_gas_cloud(p1, p2) genericptr_t p1; genericptr_t p2; { NhRegion *reg; struct monst *mtmp; int dam; reg = (NhRegion *) p1; dam = reg->arg.a_int; if (p2 == (genericptr_t) 0) { /* This means *YOU* Bozo! */ if (u.uinvulnerable || nonliving(youmonst.data) || Breathless) return FALSE; if (!Blind) { Your("%s sting.", makeplural(body_part(EYE))); make_blinded(1L, FALSE); } if (!Poison_resistance) { pline("%s is burning your %s!", Something, makeplural(body_part(LUNG))); You("cough and spit blood!"); losehp(Maybe_Half_Phys(rnd(dam) + 5), "gas cloud", KILLED_BY_AN); return FALSE; } else { You("cough!"); return FALSE; } } else { /* A monster is inside the cloud */ mtmp = (struct monst *) p2; /* Non living and non breathing monsters are not concerned */ if (!(nonliving(mtmp->data) || is_vampshifter(mtmp)) && !breathless(mtmp->data)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s coughs!", Monnam(mtmp)); if (heros_fault(reg)) setmangry(mtmp); if (haseyes(mtmp->data) && mtmp->mcansee) { mtmp->mblinded = 1; mtmp->mcansee = 0; } if (resists_poison(mtmp)) return FALSE; mtmp->mhp -= rnd(dam) + 5; if (mtmp->mhp <= 0) { if (heros_fault(reg)) killed(mtmp); else monkilled(mtmp, "gas cloud", AD_DRST); if (mtmp->mhp <= 0) { /* not lifesaved */ return TRUE; } } } } return FALSE; /* Monster is still alive */ } NhRegion * create_gas_cloud(x, y, radius, damage) xchar x, y; int radius; int damage; { NhRegion *cloud; int i, nrect; NhRect tmprect; cloud = create_region((NhRect *) 0, 0); nrect = radius; tmprect.lx = x; tmprect.hx = x; tmprect.ly = y - (radius - 1); tmprect.hy = y + (radius - 1); for (i = 0; i < nrect; i++) { add_rect_to_reg(cloud, &tmprect); tmprect.lx--; tmprect.hx++; tmprect.ly++; tmprect.hy--; } cloud->ttl = rn1(3, 4); if (!in_mklev && !context.mon_moving) set_heros_fault(cloud); /* assume player has created it */ cloud->inside_f = INSIDE_GAS_CLOUD; cloud->expire_f = EXPIRE_GAS_CLOUD; cloud->arg = zeroany; cloud->arg.a_int = damage; cloud->visible = TRUE; cloud->glyph = cmap_to_glyph(damage ? S_poisoncloud : S_cloud); add_region(cloud); return cloud; } /* for checking troubles during prayer; is hero at risk? */ boolean region_danger() { int i, f_indx, n = 0; for (i = 0; i < n_regions; i++) { /* only care about regions that hero is in */ if (!hero_inside(regions[i])) continue; f_indx = regions[i]->inside_f; /* the only type of region we understand is gas_cloud */ if (f_indx == INSIDE_GAS_CLOUD) { /* completely harmless if you don't need to breathe */ if (nonliving(youmonst.data) || Breathless) continue; /* minor inconvenience if you're poison resistant; not harmful enough to be a prayer-level trouble */ if (Poison_resistance) continue; ++n; } } return n ? TRUE : FALSE; } /* for fixing trouble at end of prayer; danger detected at start of prayer might have expired by now */ void region_safety() { NhRegion *r = 0; int i, f_indx, n = 0; for (i = 0; i < n_regions; i++) { /* only care about regions that hero is in */ if (!hero_inside(regions[i])) continue; f_indx = regions[i]->inside_f; /* the only type of region we understand is gas_cloud */ if (f_indx == INSIDE_GAS_CLOUD) { if (!n++ && regions[i]->ttl >= 0) r = regions[i]; } } if (n > 1 || (n == 1 && !r)) { /* multiple overlapping cloud regions or non-expiring one */ safe_teleds(FALSE); } else if (r) { remove_region(r); pline_The("gas cloud enveloping you dissipates."); } else { /* cloud dissipated on its own, so nothing needs to be done */ pline_The("gas cloud has dissipated."); } /* maybe cure blindness too */ if ((Blinded & TIMEOUT) == 1L) make_blinded(0L, TRUE); } /*region.c*/ nethack-3.6.0/src/restore.c0000664000076400007660000013512512617413107014564 0ustar paxedpaxed/* NetHack 3.6 restore.c $NHDT-Date: 1446892455 2015/11/07 10:34:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.101 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */ #if defined(MICRO) extern int dotcnt; /* shared with save */ extern int dotrow; /* shared with save */ #endif #ifdef USE_TILES extern void FDECL(substitute_tiles, (d_level *)); /* from tile.c */ #endif #ifdef ZEROCOMP STATIC_DCL void NDECL(zerocomp_minit); STATIC_DCL void FDECL(zerocomp_mread, (int, genericptr_t, unsigned int)); STATIC_DCL int NDECL(zerocomp_mgetc); #endif STATIC_DCL void NDECL(def_minit); STATIC_DCL void FDECL(def_mread, (int, genericptr_t, unsigned int)); STATIC_DCL void NDECL(find_lev_obj); STATIC_DCL void FDECL(restlevchn, (int)); STATIC_DCL void FDECL(restdamage, (int, BOOLEAN_P)); STATIC_DCL void FDECL(restobj, (int, struct obj *)); STATIC_DCL struct obj *FDECL(restobjchn, (int, BOOLEAN_P, BOOLEAN_P)); STATIC_OVL void FDECL(restmon, (int, struct monst *)); STATIC_DCL struct monst *FDECL(restmonchn, (int, BOOLEAN_P)); STATIC_DCL struct fruit *FDECL(loadfruitchn, (int)); STATIC_DCL void FDECL(freefruitchn, (struct fruit *)); STATIC_DCL void FDECL(ghostfruit, (struct obj *)); STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *)); STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int)); STATIC_DCL int FDECL(restlevelfile, (int, XCHAR_P)); STATIC_OVL void FDECL(restore_msghistory, (int)); STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P)); STATIC_DCL void FDECL(rest_levl, (int, BOOLEAN_P)); static struct restore_procs { const char *name; int mread_flags; void NDECL((*restore_minit)); void FDECL((*restore_mread), (int, genericptr_t, unsigned int)); void FDECL((*restore_bclose), (int)); } restoreprocs = { #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP)) "externalcomp", 0, def_minit, def_mread, def_bclose, #else "zerocomp", 0, zerocomp_minit, zerocomp_mread, zerocomp_bclose, #endif }; /* * Save a mapping of IDs from ghost levels to the current level. This * map is used by the timer routines when restoring ghost levels. */ #define N_PER_BUCKET 64 struct bucket { struct bucket *next; struct { unsigned gid; /* ghost ID */ unsigned nid; /* new ID */ } map[N_PER_BUCKET]; }; STATIC_DCL void NDECL(clear_id_mapping); STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned)); static int n_ids_mapped = 0; static struct bucket *id_map = 0; #ifdef AMII_GRAPHICS void FDECL(amii_setpens, (int)); /* use colors from save file */ extern int amii_numcolors; #endif #include "display.h" boolean restoring = FALSE; static NEARDATA struct fruit *oldfruit; static NEARDATA long omoves; #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE) /* Recalculate level.objects[x][y], since this info was not saved. */ STATIC_OVL void find_lev_obj() { register struct obj *fobjtmp = (struct obj *) 0; register struct obj *otmp; int x, y; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) level.objects[x][y] = (struct obj *) 0; /* * Reverse the entire fobj chain, which is necessary so that we can * place the objects in the proper order. Make all obj in chain * OBJ_FREE so place_object will work correctly. */ while ((otmp = fobj) != 0) { fobj = otmp->nobj; otmp->nobj = fobjtmp; otmp->where = OBJ_FREE; fobjtmp = otmp; } /* fobj should now be empty */ /* Set level.objects (as well as reversing the chain back again) */ while ((otmp = fobjtmp) != 0) { fobjtmp = otmp->nobj; place_object(otmp, otmp->ox, otmp->oy); } } /* Things that were marked "in_use" when the game was saved (ex. via the * infamous "HUP" cheat) get used up here. */ void inven_inuse(quietly) boolean quietly; { register struct obj *otmp, *otmp2; for (otmp = invent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->in_use) { if (!quietly) pline("Finishing off %s...", xname(otmp)); useup(otmp); } } } STATIC_OVL void restlevchn(fd) register int fd; { int cnt; s_level *tmplev, *x; sp_levchn = (s_level *) 0; mread(fd, (genericptr_t) &cnt, sizeof(int)); for (; cnt > 0; cnt--) { tmplev = (s_level *) alloc(sizeof(s_level)); mread(fd, (genericptr_t) tmplev, sizeof(s_level)); if (!sp_levchn) sp_levchn = tmplev; else { for (x = sp_levchn; x->next; x = x->next) ; x->next = tmplev; } tmplev->next = (s_level *) 0; } } STATIC_OVL void restdamage(fd, ghostly) int fd; boolean ghostly; { int counter; struct damage *tmp_dam; mread(fd, (genericptr_t) &counter, sizeof(counter)); if (!counter) return; tmp_dam = (struct damage *) alloc(sizeof(struct damage)); while (--counter >= 0) { char damaged_shops[5], *shp = (char *) 0; mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam)); if (ghostly) tmp_dam->when += (monstermoves - omoves); Strcpy(damaged_shops, in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE)); if (u.uz.dlevel) { /* when restoring, there are two passes over the current * level. the first time, u.uz isn't set, so neither is * shop_keeper(). just wait and process the damage on * the second pass. */ for (shp = damaged_shops; *shp; shp++) { struct monst *shkp = shop_keeper(*shp); if (shkp && inhishop(shkp) && repair_damage(shkp, tmp_dam, TRUE)) break; } } if (!shp || !*shp) { tmp_dam->next = level.damagelist; level.damagelist = tmp_dam; tmp_dam = (struct damage *) alloc(sizeof(*tmp_dam)); } } free((genericptr_t) tmp_dam); } /* restore one object */ STATIC_OVL void restobj(fd, otmp) int fd; struct obj *otmp; { int buflen; mread(fd, (genericptr_t) otmp, sizeof(struct obj)); /* next object pointers are invalid; otmp->cobj needs to be left as is--being non-null is key to restoring container contents */ otmp->nobj = otmp->nexthere = (struct obj *) 0; /* non-null oextra needs to be reconstructed */ if (otmp->oextra) { otmp->oextra = newoextra(); /* oname - object's name */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { /* includes terminating '\0' */ new_oname(otmp, buflen); mread(fd, (genericptr_t) ONAME(otmp), buflen); } /* omonst - corpse or statue might retain full monster details */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newomonst(otmp); /* this is actually a monst struct, so we can just defer to restmon() here */ restmon(fd, OMONST(otmp)); } /* omid - monster id number, connecting corpse to ghost */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newomid(otmp); mread(fd, (genericptr_t) OMID(otmp), buflen); } /* olong - temporary gold */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newolong(otmp); mread(fd, (genericptr_t) OLONG(otmp), buflen); } /* omailcmd - feedback mechanism for scroll of mail */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { char *omailcmd = (char *) alloc(buflen); mread(fd, (genericptr_t) omailcmd, buflen); new_omailcmd(otmp, omailcmd); free((genericptr_t) omailcmd); } } } STATIC_OVL struct obj * restobjchn(fd, ghostly, frozen) register int fd; boolean ghostly, frozen; { register struct obj *otmp, *otmp2 = 0; register struct obj *first = (struct obj *) 0; int buflen; while (1) { mread(fd, (genericptr_t) &buflen, sizeof buflen); if (buflen == -1) break; otmp = newobj(); restobj(fd, otmp); if (!first) first = otmp; else otmp2->nobj = otmp; if (ghostly) { unsigned nid = context.ident++; add_id_mapping(otmp->o_id, nid); otmp->o_id = nid; } if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp); /* Ghost levels get object age shifted from old player's clock * to new player's clock. Assumption: new player arrived * immediately after old player died. */ if (ghostly && !frozen && !age_is_relative(otmp)) otmp->age = monstermoves - omoves + otmp->age; /* get contents of a container or statue */ if (Has_contents(otmp)) { struct obj *otmp3; otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp)); /* restore container back pointers */ for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj) otmp3->ocontainer = otmp; } if (otmp->bypass) otmp->bypass = 0; if (!ghostly) { /* fix the pointers */ if (otmp->o_id == context.victual.o_id) context.victual.piece = otmp; if (otmp->o_id == context.tin.o_id) context.tin.tin = otmp; if (otmp->o_id == context.spbook.o_id) context.spbook.book = otmp; } otmp2 = otmp; } if (first && otmp2->nobj) { impossible("Restobjchn: error reading objchn."); otmp2->nobj = 0; } return first; } /* restore one monster */ STATIC_OVL void restmon(fd, mtmp) int fd; struct monst *mtmp; { int buflen; mread(fd, (genericptr_t) mtmp, sizeof(struct monst)); /* next monster pointer is invalid */ mtmp->nmon = (struct monst *) 0; /* non-null mextra needs to be reconstructed */ if (mtmp->mextra) { mtmp->mextra = newmextra(); /* mname - monster's name */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { /* includes terminating '\0' */ new_mname(mtmp, buflen); mread(fd, (genericptr_t) MNAME(mtmp), buflen); } /* egd - vault guard */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newegd(mtmp); mread(fd, (genericptr_t) EGD(mtmp), sizeof(struct egd)); } /* epri - temple priest */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newepri(mtmp); mread(fd, (genericptr_t) EPRI(mtmp), sizeof(struct epri)); } /* eshk - shopkeeper */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { neweshk(mtmp); mread(fd, (genericptr_t) ESHK(mtmp), sizeof(struct eshk)); } /* emin - minion */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newemin(mtmp); mread(fd, (genericptr_t) EMIN(mtmp), sizeof(struct emin)); } /* edog - pet */ mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { newedog(mtmp); mread(fd, (genericptr_t) EDOG(mtmp), sizeof(struct edog)); } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ mread(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp)); } /* mextra */ } STATIC_OVL struct monst * restmonchn(fd, ghostly) register int fd; boolean ghostly; { register struct monst *mtmp, *mtmp2 = 0; register struct monst *first = (struct monst *) 0; int offset, buflen; while (1) { mread(fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen == -1) break; mtmp = newmonst(); restmon(fd, mtmp); if (!first) first = mtmp; else mtmp2->nmon = mtmp; if (ghostly) { unsigned nid = context.ident++; add_id_mapping(mtmp->m_id, nid); mtmp->m_id = nid; } offset = mtmp->mnum; mtmp->data = &mons[offset]; if (ghostly) { int mndx = monsndx(mtmp->data); if (propagate(mndx, TRUE, ghostly) == 0) { /* cookie to trigger purge in getbones() */ mtmp->mhpmax = DEFUNCT_MONSTER; } } if (mtmp->minvent) { struct obj *obj; mtmp->minvent = restobjchn(fd, ghostly, FALSE); /* restore monster back pointer */ for (obj = mtmp->minvent; obj; obj = obj->nobj) obj->ocarry = mtmp; } if (mtmp->mw) { struct obj *obj; for (obj = mtmp->minvent; obj; obj = obj->nobj) if (obj->owornmask & W_WEP) break; if (obj) mtmp->mw = obj; else { MON_NOWEP(mtmp); impossible("bad monster weapon restore"); } } if (mtmp->isshk) restshk(mtmp, ghostly); if (mtmp->ispriest) restpriest(mtmp, ghostly); if (!ghostly) { if (mtmp->m_id == context.polearm.m_id) context.polearm.hitmon = mtmp; } mtmp2 = mtmp; } if (first && mtmp2->nmon) { impossible("Restmonchn: error reading monchn."); mtmp2->nmon = 0; } return first; } STATIC_OVL struct fruit * loadfruitchn(fd) int fd; { register struct fruit *flist, *fnext; flist = 0; while (fnext = newfruit(), mread(fd, (genericptr_t) fnext, sizeof *fnext), fnext->fid != 0) { fnext->nextf = flist; flist = fnext; } dealloc_fruit(fnext); return flist; } STATIC_OVL void freefruitchn(flist) register struct fruit *flist; { register struct fruit *fnext; while (flist) { fnext = flist->nextf; dealloc_fruit(flist); flist = fnext; } } STATIC_OVL void ghostfruit(otmp) register struct obj *otmp; { register struct fruit *oldf; for (oldf = oldfruit; oldf; oldf = oldf->nextf) if (oldf->fid == otmp->spe) break; if (!oldf) impossible("no old fruit?"); else otmp->spe = fruitadd(oldf->fname, (struct fruit *) 0); } #ifdef SYSCF #define SYSOPT_CHECK_SAVE_UID sysopt.check_save_uid #else #define SYSOPT_CHECK_SAVE_UID TRUE #endif STATIC_OVL boolean restgamestate(fd, stuckid, steedid) register int fd; unsigned int *stuckid, *steedid; { struct flag newgameflags; #ifdef SYSFLAGS struct sysflag newgamesysflags; #endif struct obj *otmp, *tmp_bc; char timebuf[15]; unsigned long uid; mread(fd, (genericptr_t) &uid, sizeof uid); if (SYSOPT_CHECK_SAVE_UID && uid != (unsigned long) getuid()) { /* strange ... */ /* for wizard mode, issue a reminder; for others, treat it as an attempt to cheat and refuse to restore this file */ pline("Saved game was not yours."); if (!wizard) return FALSE; } mread(fd, (genericptr_t) &context, sizeof(struct context_info)); if (context.warntype.speciesidx) context.warntype.species = &mons[context.warntype.speciesidx]; /* we want to be able to revert to command line/environment/config file option values instead of keeping old save file option values if partial restore fails and we resort to starting a new game */ newgameflags = flags; mread(fd, (genericptr_t) &flags, sizeof(struct flag)); /* wizard and discover are actually flags.debug and flags.explore; player might be overriding the save file values for them; in the discover case, we don't want to set that for a normal game until after the save file has been removed */ iflags.deferred_X = (newgameflags.explore && !discover); if (newgameflags.debug) { /* authorized by startup code; wizard mode exists and is allowed */ wizard = TRUE, discover = iflags.deferred_X = FALSE; } else if (wizard) { /* specified by save file; check authorization now */ set_playmode(); } #ifdef SYSFLAGS newgamesysflags = sysflags; mread(fd, (genericptr_t) &sysflags, sizeof(struct sysflag)); #endif role_init(); /* Reset the initial role, race, gender, and alignment */ #ifdef AMII_GRAPHICS amii_setpens(amii_numcolors); /* use colors from save file */ #endif mread(fd, (genericptr_t) &u, sizeof(struct you)); #define ReadTimebuf(foo) \ mread(fd, (genericptr_t) timebuf, 14); \ timebuf[14] = '\0'; \ foo = time_from_yyyymmddhhmmss(timebuf); ReadTimebuf(ubirthday); mread(fd, &urealtime.realtime, sizeof(urealtime.realtime)); ReadTimebuf(urealtime.restored); #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *) &urealtime.restored); #else (void) time(&urealtime.restored); #endif set_uasmon(); #ifdef CLIPPING cliparound(u.ux, u.uy); #endif if (u.uhp <= 0 && (!Upolyd || u.mh <= 0)) { u.ux = u.uy = 0; /* affects pline() [hence You()] */ You("were not healthy enough to survive restoration."); /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is * uninitialized, so we only have to set it and not the other stuff. */ wiz1_level.dlevel = 0; u.uz.dnum = 0; u.uz.dlevel = 1; /* revert to pre-restore option settings */ iflags.deferred_X = FALSE; flags = newgameflags; #ifdef SYSFLAGS sysflags = newgamesysflags; #endif return FALSE; } /* in case hangup save occurred in midst of level change */ assign_level(&u.uz0, &u.uz); /* this stuff comes after potential aborted restore attempts */ restore_killers(fd); restore_timers(fd, RANGE_GLOBAL, FALSE, 0L); restore_light_sources(fd); invent = restobjchn(fd, FALSE, FALSE); /* tmp_bc only gets set here if the ball & chain were orphaned because you were swallowed; otherwise they will be on the floor or in your inventory */ tmp_bc = restobjchn(fd, FALSE, FALSE); if (tmp_bc) { for (otmp = tmp_bc; otmp; otmp = otmp->nobj) { if (otmp->owornmask) setworn(otmp, otmp->owornmask); } if (!uball || !uchain) impossible("restgamestate: lost ball & chain"); } migrating_objs = restobjchn(fd, FALSE, FALSE); migrating_mons = restmonchn(fd, FALSE); mread(fd, (genericptr_t) mvitals, sizeof(mvitals)); /* * There are some things after this that can have unintended display * side-effects too early in the game. * Disable see_monsters() here, re-enable it at the top of moveloop() */ defer_see_monsters = TRUE; /* this comes after inventory has been loaded */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->owornmask) setworn(otmp, otmp->owornmask); /* reset weapon so that player will get a reminder about "bashing" during next fight when bare-handed or wielding an unconventional item; for pick-axe, we aren't able to distinguish between having applied or wielded it, so be conservative and assume the former */ otmp = uwep; /* `uwep' usually init'd by setworn() in loop above */ uwep = 0; /* clear it and have setuwep() reinit */ setuwep(otmp); /* (don't need any null check here) */ if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK) unweapon = TRUE; restore_dungeon(fd); restlevchn(fd); mread(fd, (genericptr_t) &moves, sizeof moves); mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves); mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); mread(fd, (genericptr_t) spl_book, sizeof(struct spell) * (MAXSPELL + 1)); restore_artifacts(fd); restore_oracles(fd); if (u.ustuck) mread(fd, (genericptr_t) stuckid, sizeof(*stuckid)); if (u.usteed) mread(fd, (genericptr_t) steedid, sizeof(*steedid)); mread(fd, (genericptr_t) pl_character, sizeof pl_character); mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */ ffruit = loadfruitchn(fd); restnames(fd); restore_waterlevel(fd); restore_msghistory(fd); /* must come after all mons & objs are restored */ relink_timers(FALSE); relink_light_sources(FALSE); return TRUE; } /* update game state pointers to those valid for the current level (so we * don't dereference a wild u.ustuck when saving the game state, for instance) */ STATIC_OVL void restlevelstate(stuckid, steedid) unsigned int stuckid, steedid; { register struct monst *mtmp; if (stuckid) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == stuckid) break; if (!mtmp) panic("Cannot find the monster ustuck."); u.ustuck = mtmp; } if (steedid) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == steedid) break; if (!mtmp) panic("Cannot find the monster usteed."); u.usteed = mtmp; remove_monster(mtmp->mx, mtmp->my); } } /*ARGSUSED*/ STATIC_OVL int restlevelfile(fd, ltmp) int fd; /* fd used in MFLOPPY only */ xchar ltmp; { int nfd; char whynot[BUFSZ]; #ifndef MFLOPPY nhUse(fd); #endif nfd = create_levelfile(ltmp, whynot); if (nfd < 0) { /* BUG: should suppress any attempt to write a panic save file if file creation is now failing... */ panic("restlevelfile: %s", whynot); } #ifdef MFLOPPY if (!savelev(nfd, ltmp, COUNT_SAVE)) { /* The savelev can't proceed because the size required * is greater than the available disk space. */ pline("Not enough space on `%s' to restore your game.", levels); /* Remove levels and bones that may have been created. */ (void) nhclose(nfd); #ifdef AMIGA clearlocks(); #else /* !AMIGA */ eraseall(levels, alllevels); eraseall(levels, allbones); /* Perhaps the person would like to play without a * RAMdisk. */ if (ramdisk) { /* PlaywoRAMdisk may not return, but if it does * it is certain that ramdisk will be 0. */ playwoRAMdisk(); /* Rewind save file and try again */ (void) lseek(fd, (off_t) 0, 0); (void) validate(fd, (char *) 0); /* skip version etc */ return dorecover(fd); /* 0 or 1 */ } #endif /* ?AMIGA */ pline("Be seeing you..."); terminate(EXIT_SUCCESS); } #endif /* MFLOPPY */ bufon(nfd); savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE); bclose(nfd); return 2; } int dorecover(fd) register int fd; { unsigned int stuckid = 0, steedid = 0; /* not a register */ xchar ltmp; int rtmp; struct obj *otmp; restoring = TRUE; get_plname_from_file(fd, plname); getlev(fd, 0, (xchar) 0, FALSE); if (!restgamestate(fd, &stuckid, &steedid)) { display_nhwindow(WIN_MESSAGE, TRUE); savelev(-1, 0, FREE_SAVE); /* discard current level */ (void) nhclose(fd); (void) delete_savefile(); restoring = FALSE; return 0; } restlevelstate(stuckid, steedid); #ifdef INSURANCE savestateinlock(); #endif rtmp = restlevelfile(fd, ledger_no(&u.uz)); if (rtmp < 2) return rtmp; /* dorecover called recursively */ /* these pointers won't be valid while we're processing the * other levels, but they'll be reset again by restlevelstate() * afterwards, and in the meantime at least u.usteed may mislead * place_monster() on other levels */ u.ustuck = (struct monst *) 0; u.usteed = (struct monst *) 0; #ifdef MICRO #ifdef AMII_GRAPHICS { extern struct window_procs amii_procs; if (windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) { extern winid WIN_BASE; clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */ } } #else clear_nhwindow(WIN_MAP); #endif clear_nhwindow(WIN_MESSAGE); You("return to level %d in %s%s.", depth(&u.uz), dungeons[u.uz.dnum].dname, flags.debug ? " while in debug mode" : flags.explore ? " while in explore mode" : ""); curs(WIN_MAP, 1, 1); dotcnt = 0; dotrow = 2; if (strncmpi("X11", windowprocs.name, 3)) putstr(WIN_MAP, 0, "Restoring:"); #endif restoreprocs.mread_flags = 1; /* return despite error */ while (1) { mread(fd, (genericptr_t) <mp, sizeof ltmp); if (restoreprocs.mread_flags == -1) break; getlev(fd, 0, ltmp, FALSE); #ifdef MICRO curs(WIN_MAP, 1 + dotcnt++, dotrow); if (dotcnt >= (COLNO - 1)) { dotrow++; dotcnt = 0; } if (strncmpi("X11", windowprocs.name, 3)) { putstr(WIN_MAP, 0, "."); } mark_synch(); #endif rtmp = restlevelfile(fd, ltmp); if (rtmp < 2) return rtmp; /* dorecover called recursively */ } restoreprocs.mread_flags = 0; #ifdef BSD (void) lseek(fd, 0L, 0); #else (void) lseek(fd, (off_t) 0, 0); #endif (void) validate(fd, (char *) 0); /* skip version and savefile info */ get_plname_from_file(fd, plname); getlev(fd, 0, (xchar) 0, FALSE); (void) nhclose(fd); /* Now set the restore settings to match the * settings used by the save file output routines */ reset_restpref(); restlevelstate(stuckid, steedid); program_state.something_worth_saving = 1; /* useful data now exists */ if (!wizard && !discover) (void) delete_savefile(); if (Is_rogue_level(&u.uz)) assign_graphics(ROGUESET); #ifdef USE_TILES substitute_tiles(&u.uz); #endif #ifdef MFLOPPY gameDiskPrompt(); #endif max_rank_sz(); /* to recompute mrank_sz (botl.c) */ /* take care of iron ball & chain */ for (otmp = fobj; otmp; otmp = otmp->nobj) if (otmp->owornmask) setworn(otmp, otmp->owornmask); /* in_use processing must be after: * + The inventory has been read so that freeinv() works. * + The current level has been restored so billing information * is available. */ inven_inuse(FALSE); load_qtlist(); /* re-load the quest text info */ /* Set up the vision internals, after levl[] data is loaded but before docrt(). */ reglyph_darkroom(); vision_reset(); vision_full_recalc = 1; /* recompute vision (not saved) */ run_timers(); /* expire all timers that have gone off while away */ docrt(); restoring = FALSE; clear_nhwindow(WIN_MESSAGE); /* Success! */ welcome(FALSE); check_special_room(FALSE); return 1; } void restcemetery(fd, cemeteryaddr) int fd; struct cemetery **cemeteryaddr; { struct cemetery *bonesinfo, **bonesaddr; int flag; mread(fd, (genericptr_t) &flag, sizeof flag); if (flag == 0) { bonesaddr = cemeteryaddr; do { bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo); mread(fd, (genericptr_t) bonesinfo, sizeof *bonesinfo); *bonesaddr = bonesinfo; bonesaddr = &(*bonesaddr)->next; } while (*bonesaddr); } else { *cemeteryaddr = 0; } } /*ARGSUSED*/ STATIC_OVL void rest_levl(fd, rlecomp) int fd; boolean rlecomp; { #ifdef RLECOMP short i, j; uchar len; struct rm r; if (rlecomp) { (void) memset((genericptr_t) &r, 0, sizeof(r)); i = 0; j = 0; len = 0; while (i < ROWNO) { while (j < COLNO) { if (len > 0) { levl[j][i] = r; len -= 1; j += 1; } else { mread(fd, (genericptr_t) &len, sizeof(uchar)); mread(fd, (genericptr_t) &r, sizeof(struct rm)); } } j = 0; i += 1; } return; } #else /* !RLECOMP */ nhUse(rlecomp); #endif /* ?RLECOMP */ mread(fd, (genericptr_t) levl, sizeof levl); } void trickery(reason) char *reason; { pline("Strange, this map is not as I remember it."); pline("Somebody is trying some trickery here..."); pline("This game is void."); Strcpy(killer.name, reason ? reason : ""); done(TRICKED); } void getlev(fd, pid, lev, ghostly) int fd, pid; xchar lev; boolean ghostly; { register struct trap *trap; register struct monst *mtmp; long elapsed; branch *br; int hpid; xchar dlvl; int x, y; #ifdef TOS short tlev; #endif if (ghostly) clear_id_mapping(); #if defined(MSDOS) || defined(OS2) setmode(fd, O_BINARY); #endif /* Load the old fruit info. We have to do it first, so the * information is available when restoring the objects. */ if (ghostly) oldfruit = loadfruitchn(fd); /* First some sanity checks */ mread(fd, (genericptr_t) &hpid, sizeof(hpid)); /* CHECK: This may prevent restoration */ #ifdef TOS mread(fd, (genericptr_t) &tlev, sizeof(tlev)); dlvl = tlev & 0x00ff; #else mread(fd, (genericptr_t) &dlvl, sizeof(dlvl)); #endif if ((pid && pid != hpid) || (lev && dlvl != lev)) { char trickbuf[BUFSZ]; if (pid && pid != hpid) Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!", hpid, pid); else Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev); if (wizard) pline1(trickbuf); trickery(trickbuf); } restcemetery(fd, &level.bonesinfo); rest_levl(fd, (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); mread(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp)); mread(fd, (genericptr_t) &omoves, sizeof(omoves)); elapsed = monstermoves - omoves; mread(fd, (genericptr_t) &upstair, sizeof(stairway)); mread(fd, (genericptr_t) &dnstair, sizeof(stairway)); mread(fd, (genericptr_t) &upladder, sizeof(stairway)); mread(fd, (genericptr_t) &dnladder, sizeof(stairway)); mread(fd, (genericptr_t) &sstairs, sizeof(stairway)); mread(fd, (genericptr_t) &updest, sizeof(dest_area)); mread(fd, (genericptr_t) &dndest, sizeof(dest_area)); mread(fd, (genericptr_t) &level.flags, sizeof(level.flags)); mread(fd, (genericptr_t) doors, sizeof(doors)); rest_rooms(fd); /* No joke :-) */ if (nroom) doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct; else doorindex = 0; restore_timers(fd, RANGE_LEVEL, ghostly, elapsed); restore_light_sources(fd); fmon = restmonchn(fd, ghostly); rest_worm(fd); /* restore worm information */ ftrap = 0; while (trap = newtrap(), mread(fd, (genericptr_t) trap, sizeof(struct trap)), trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */ trap->ntrap = ftrap; ftrap = trap; } dealloc_trap(trap); fobj = restobjchn(fd, ghostly, FALSE); find_lev_obj(); /* restobjchn()'s `frozen' argument probably ought to be a callback routine so that we can check for objects being buried under ice */ level.buriedobjlist = restobjchn(fd, ghostly, FALSE); billobjs = restobjchn(fd, ghostly, FALSE); rest_engravings(fd); /* reset level.monsters for new level */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) level.monsters[x][y] = (struct monst *) 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (mtmp->isshk) set_residency(mtmp, FALSE); place_monster(mtmp, mtmp->mx, mtmp->my); if (mtmp->wormno) place_wsegs(mtmp); /* regenerate monsters while on another level */ if (!u.uz.dlevel) continue; if (ghostly) { /* reset peaceful/malign relative to new character; shopkeepers will reset based on name */ if (!mtmp->isshk) mtmp->mpeaceful = (is_unicorn(mtmp->data) && sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)) ? TRUE : peace_minded(mtmp->data); set_malign(mtmp); } else if (elapsed > 0L) { mon_catchup_elapsed_time(mtmp, elapsed); } /* update shape-changers in case protection against them is different now than when the level was saved */ restore_cham(mtmp); /* give hiders a chance to hide before their next move */ if (ghostly || elapsed > (long) rnd(10)) hide_monst(mtmp); } restdamage(fd, ghostly); rest_regions(fd, ghostly); if (ghostly) { /* Now get rid of all the temp fruits... */ freefruitchn(oldfruit), oldfruit = 0; if (lev > ledger_no(&medusa_level) && lev < ledger_no(&stronghold_level) && xdnstair == 0) { coord cc; mazexy(&cc); xdnstair = cc.x; ydnstair = cc.y; levl[cc.x][cc.y].typ = STAIRS; } br = Is_branchlev(&u.uz); if (br && u.uz.dlevel == 1) { d_level ltmp; if (on_level(&u.uz, &br->end1)) assign_level(<mp, &br->end2); else assign_level(<mp, &br->end1); switch (br->type) { case BR_STAIR: case BR_NO_END1: case BR_NO_END2: /* OK to assign to sstairs if it's not used */ assign_level(&sstairs.tolev, <mp); break; case BR_PORTAL: /* max of 1 portal per level */ for (trap = ftrap; trap; trap = trap->ntrap) if (trap->ttyp == MAGIC_PORTAL) break; if (!trap) panic("getlev: need portal but none found"); assign_level(&trap->dst, <mp); break; } } else if (!br) { struct trap *ttmp = 0; /* Remove any dangling portals. */ for (trap = ftrap; trap; trap = ttmp) { ttmp = trap->ntrap; if (trap->ttyp == MAGIC_PORTAL) deltrap(trap); } } } /* must come after all mons & objs are restored */ relink_timers(ghostly); relink_light_sources(ghostly); reset_oattached_mids(ghostly); if (ghostly) clear_id_mapping(); } void get_plname_from_file(fd, plbuf) int fd; char *plbuf; { int pltmpsiz = 0; (void) read(fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz)); (void) read(fd, (genericptr_t) plbuf, pltmpsiz); return; } STATIC_OVL void restore_msghistory(fd) register int fd; { int msgsize, msgcount = 0; char msg[BUFSZ]; while (1) { mread(fd, (genericptr_t) &msgsize, sizeof(msgsize)); if (msgsize == -1) break; if (msgsize > (BUFSZ - 1)) panic("restore_msghistory: msg too big (%d)", msgsize); mread(fd, (genericptr_t) msg, msgsize); msg[msgsize] = '\0'; putmsghistory(msg, TRUE); ++msgcount; } if (msgcount) putmsghistory((char *) 0, TRUE); debugpline1("Read %d messages from savefile.", msgcount); } /* Clear all structures for object and monster ID mapping. */ STATIC_OVL void clear_id_mapping() { struct bucket *curr; while ((curr = id_map) != 0) { id_map = curr->next; free((genericptr_t) curr); } n_ids_mapped = 0; } /* Add a mapping to the ID map. */ STATIC_OVL void add_id_mapping(gid, nid) unsigned gid, nid; { int idx; idx = n_ids_mapped % N_PER_BUCKET; /* idx is zero on first time through, as well as when a new bucket is */ /* needed */ if (idx == 0) { struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket)); gnu->next = id_map; id_map = gnu; } id_map->map[idx].gid = gid; id_map->map[idx].nid = nid; n_ids_mapped++; } /* * Global routine to look up a mapping. If found, return TRUE and fill * in the new ID value. Otherwise, return false and return -1 in the new * ID. */ boolean lookup_id_mapping(gid, nidp) unsigned gid, *nidp; { int i; struct bucket *curr; if (n_ids_mapped) for (curr = id_map; curr; curr = curr->next) { /* first bucket might not be totally full */ if (curr == id_map) { i = n_ids_mapped % N_PER_BUCKET; if (i == 0) i = N_PER_BUCKET; } else i = N_PER_BUCKET; while (--i >= 0) if (gid == curr->map[i].gid) { *nidp = curr->map[i].nid; return TRUE; } } return FALSE; } STATIC_OVL void reset_oattached_mids(ghostly) boolean ghostly; { struct obj *otmp; unsigned oldid, nid; for (otmp = fobj; otmp; otmp = otmp->nobj) { if (ghostly && has_omonst(otmp)) { struct monst *mtmp = OMONST(otmp); mtmp->m_id = 0; mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */ } if (ghostly && has_omid(otmp)) { (void) memcpy((genericptr_t) &oldid, (genericptr_t) OMID(otmp), sizeof(oldid)); if (lookup_id_mapping(oldid, &nid)) (void) memcpy((genericptr_t) OMID(otmp), (genericptr_t) &nid, sizeof(nid)); else free_omid(otmp); } } } #ifdef SELECTSAVED /* put up a menu listing each character from this player's saved games; returns 1: use plname[], 0: new game, -1: quit */ int restore_menu(bannerwin) winid bannerwin; /* if not WIN_ERR, clear window and show copyright in menu */ { winid tmpwin; anything any; char **saved; menu_item *chosen_game = (menu_item *) 0; int k, clet, ch = 0; /* ch: 0 => new game */ *plname = '\0'; saved = get_saved_games(); /* array of character names */ if (saved && *saved) { tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; /* no selection */ if (bannerwin != WIN_ERR) { /* for tty; erase copyright notice and redo it in the menu */ clear_nhwindow(bannerwin); /* COPYRIGHT_BANNER_[ABCD] */ for (k = 1; k <= 4; ++k) add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, copyright_banner_line(k), MENU_UNSELECTED); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); } add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "Select one of your saved games", MENU_UNSELECTED); for (k = 0; saved[k]; ++k) { any.a_int = k + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, saved[k], MENU_UNSELECTED); } clet = (k <= 'n' - 'a') ? 'n' : 0; /* new game */ any.a_int = -1; /* not >= 0 */ add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE, "Start a new character", MENU_UNSELECTED); clet = (k + 1 <= 'q' - 'a') ? 'q' : 0; /* quit */ any.a_int = -2; add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE, "Never mind (quit)", MENU_SELECTED); /* no prompt on end_menu, as we've done our own at the top */ end_menu(tmpwin, (char *) 0); if (select_menu(tmpwin, PICK_ONE, &chosen_game) > 0) { ch = chosen_game->item.a_int; if (ch > 0) Strcpy(plname, saved[ch - 1]); else if (ch < 0) ++ch; /* -1 -> 0 (new game), -2 -> -1 (quit) */ free((genericptr_t) chosen_game); } else { ch = -1; /* quit menu without making a selection => quit */ } destroy_nhwindow(tmpwin); if (bannerwin != WIN_ERR) { /* for tty; clear the menu away and put subset of copyright back */ clear_nhwindow(bannerwin); /* COPYRIGHT_BANNER_A, preceding "Who are you?" prompt */ if (ch == 0) putstr(bannerwin, 0, copyright_banner_line(1)); } } free_saved_games(saved); return (ch > 0) ? 1 : ch; } #endif /* SELECTSAVED */ void minit() { (*restoreprocs.restore_minit)(); return; } void mread(fd, buf, len) register int fd; register genericptr_t buf; register unsigned int len; { (*restoreprocs.restore_mread)(fd, buf, len); return; } /* examine the version info and the savefile_info data that immediately follows it. Return 0 if it passed the checks. Return 1 if it failed the version check. Return 2 if it failed the savefile feature check. Return -1 if it failed for some unknown reason. */ int validate(fd, name) int fd; const char *name; { int rlen; struct savefile_info sfi; unsigned long compatible; boolean verbose = name ? TRUE : FALSE, reslt = FALSE; if (!(reslt = uptodate(fd, name))) return 1; rlen = read(fd, (genericptr_t) &sfi, sizeof sfi); minit(); /* ZEROCOMP */ if (rlen == 0) { if (verbose) { pline("File \"%s\" is empty during save file feature check?", name); wait_synch(); } return -1; } compatible = (sfi.sfi1 & sfcap.sfi1); if ((sfi.sfi1 & SFI1_ZEROCOMP) == SFI1_ZEROCOMP) { if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) { if (verbose) { pline("File \"%s\" has incompatible ZEROCOMP compression.", name); wait_synch(); } return 2; } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) { set_restpref("zerocomp"); } } if ((sfi.sfi1 & SFI1_EXTERNALCOMP) == SFI1_EXTERNALCOMP) { if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) { if (verbose) { pline("File \"%s\" lacks required internal compression.", name); wait_synch(); } return 2; } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) { set_restpref("externalcomp"); } } /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments */ if ((sfi.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP) { if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) { if (verbose) { pline("File \"%s\" has incompatible run-length compression.", name); wait_synch(); } return 2; } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) { set_restpref("rlecomp"); } } /* savefile does not have RLECOMP level location compression, so adjust */ else set_restpref("!rlecomp"); return 0; } void reset_restpref() { #ifdef ZEROCOMP if (iflags.zerocomp) set_restpref("zerocomp"); else #endif set_restpref("externalcomp"); #ifdef RLECOMP if (iflags.rlecomp) set_restpref("rlecomp"); else #endif set_restpref("!rlecomp"); } void set_restpref(suitename) const char *suitename; { if (!strcmpi(suitename, "externalcomp")) { restoreprocs.name = "externalcomp"; restoreprocs.restore_mread = def_mread; restoreprocs.restore_minit = def_minit; sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP; sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP; def_minit(); } if (!strcmpi(suitename, "!rlecomp")) { sfrestinfo.sfi1 &= ~SFI1_RLECOMP; } #ifdef ZEROCOMP if (!strcmpi(suitename, "zerocomp")) { restoreprocs.name = "zerocomp"; restoreprocs.restore_mread = zerocomp_mread; restoreprocs.restore_minit = zerocomp_minit; sfrestinfo.sfi1 |= SFI1_ZEROCOMP; sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP; zerocomp_minit(); } #endif #ifdef RLECOMP if (!strcmpi(suitename, "rlecomp")) { sfrestinfo.sfi1 |= SFI1_RLECOMP; } #endif } #ifdef ZEROCOMP #define RLESC '\0' /* Leading character for run of RLESC's */ #ifndef ZEROCOMP_BUFSIZ #define ZEROCOMP_BUFSIZ BUFSZ #endif static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ]; static NEARDATA unsigned short inbufp = 0; static NEARDATA unsigned short inbufsz = 0; static NEARDATA short inrunlength = -1; static NEARDATA int mreadfd; STATIC_OVL int zerocomp_mgetc() { if (inbufp >= inbufsz) { inbufsz = read(mreadfd, (genericptr_t) inbuf, sizeof inbuf); if (!inbufsz) { if (inbufp > sizeof inbuf) error("EOF on file #%d.\n", mreadfd); inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */ return -1; } inbufp = 0; } return inbuf[inbufp++]; } STATIC_OVL void zerocomp_minit() { inbufsz = 0; inbufp = 0; inrunlength = -1; } STATIC_OVL void zerocomp_mread(fd, buf, len) int fd; genericptr_t buf; register unsigned len; { /*register int readlen = 0;*/ if (fd < 0) error("Restore error; mread attempting to read file %d.", fd); mreadfd = fd; while (len--) { if (inrunlength > 0) { inrunlength--; *(*((char **) &buf))++ = '\0'; } else { register short ch = zerocomp_mgetc(); if (ch < 0) { restoreprocs.mread_flags = -1; return; } if ((*(*(char **) &buf)++ = (char) ch) == RLESC) { inrunlength = zerocomp_mgetc(); } } /*readlen++;*/ } } #endif /* ZEROCOMP */ STATIC_OVL void def_minit() { return; } STATIC_OVL void def_mread(fd, buf, len) register int fd; register genericptr_t buf; register unsigned int len; { register int rlen; #if defined(BSD) || defined(ULTRIX) #define readLenType int #else /* e.g. SYSV, __TURBOC__ */ #define readLenType unsigned #endif rlen = read(fd, buf, (readLenType) len); if ((readLenType) rlen != (readLenType) len) { if (restoreprocs.mread_flags == 1) { /* means "return anyway" */ restoreprocs.mread_flags = -1; return; } else { pline("Read %d instead of %u bytes.", rlen, len); if (restoring) { (void) nhclose(fd); (void) delete_savefile(); error("Error restoring old game."); } panic("Error reading level file."); } } } /*restore.c*/ nethack-3.6.0/src/rip.c0000664000076400007660000001232612563053246013674 0ustar paxedpaxed/* NetHack 3.6 rip.c $NHDT-Date: 1436753522 2015/07/13 02:12:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL void FDECL(center, (int, char *)); #if defined(TTY_GRAPHICS) || defined(X11_GRAPHICS) || defined(GEM_GRAPHICS) \ || defined(MSWIN_GRAPHICS) #define TEXT_TOMBSTONE #endif #if defined(mac) || defined(__BEOS__) || defined(WIN32_GRAPHICS) #ifndef TEXT_TOMBSTONE #define TEXT_TOMBSTONE #endif #endif #ifdef TEXT_TOMBSTONE #ifndef NH320_DEDICATION /* A normal tombstone for end of game display. */ static const char *rip_txt[] = { " ----------", " / \\", " / REST \\", " / IN \\", " / PEACE \\", " / \\", " | |", /* Name of player */ " | |", /* Amount of $ */ " | |", /* Type of death */ " | |", /* . */ " | |", /* . */ " | |", /* . */ " | 1001 |", /* Real year of death */ " *| * * * | *", " _________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______", 0 }; #define STONE_LINE_CENT 28 /* char[] element of center of stone face */ #else /* NH320_DEDICATION */ /* NetHack 3.2.x displayed a dual tombstone as a tribute to Izchak. */ static const char *rip_txt[] = { " ---------- ----------", " / \\ / \\", " / REST \\ / This \\", " / IN \\ / release of \\", " / PEACE \\ / NetHack is \\", " / \\ / dedicated to \\", " | | | the memory of |", " | | | |", " | | | Izchak Miller |", " | | | 1935 - 1994 |", " | | | |", " | | | Ascended |", " | 1001 | | |", " * | * * * | * * | * * * | *", " _____)/\\|\\__//(\\/(/\\)/\\//\\/|_)________)/|\\\\_/_/(\\/(/\\)/\\/\\/|_)____", 0 }; #define STONE_LINE_CENT 19 /* char[] element of center of stone face */ #endif /* NH320_DEDICATION */ #define STONE_LINE_LEN \ 16 /* # chars that fit on one line \ * (note 1 ' ' border) \ */ #define NAME_LINE 6 /* *char[] line # for player name */ #define GOLD_LINE 7 /* *char[] line # for amount of gold */ #define DEATH_LINE 8 /* *char[] line # for death description */ #define YEAR_LINE 12 /* *char[] line # for year */ static char **rip; STATIC_OVL void center(line, text) int line; char *text; { register char *ip, *op; ip = text; op = &rip[line][STONE_LINE_CENT - ((strlen(text) + 1) >> 1)]; while (*ip) *op++ = *ip++; } void genl_outrip(tmpwin, how, when) winid tmpwin; int how; time_t when; { register char **dp; register char *dpx; char buf[BUFSZ]; long year; register int x; int line; rip = dp = (char **) alloc(sizeof(rip_txt)); for (x = 0; rip_txt[x]; ++x) dp[x] = dupstr(rip_txt[x]); dp[x] = (char *) 0; /* Put name on stone */ Sprintf(buf, "%s", plname); buf[STONE_LINE_LEN] = 0; center(NAME_LINE, buf); /* Put $ on stone */ Sprintf(buf, "%ld Au", done_money); buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ center(GOLD_LINE, buf); /* Put together death description */ formatkiller(buf, sizeof buf, how); /* Put death type on stone */ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { register int i, i0; char tmpchar; if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if (dpx[i] == ' ') i0 = i; if (!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; center(line, dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx = &dpx[i0]; } else dpx = &dpx[i0 + 1]; } /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(buf, "%4ld", year); center(YEAR_LINE, buf); putstr(tmpwin, 0, ""); for (; *dp; dp++) putstr(tmpwin, 0, *dp); putstr(tmpwin, 0, ""); putstr(tmpwin, 0, ""); for (x = 0; rip_txt[x]; x++) { free((genericptr_t) rip[x]); } free((genericptr_t) rip); rip = 0; } #endif /* TEXT_TOMBSTONE */ /*rip.c*/ nethack-3.6.0/src/rnd.c0000664000076400007660000000631412625266776013702 0ustar paxedpaxed/* NetHack 3.6 rnd.c $NHDT-Date: 1446883921 2015/11/07 08:12:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* "Rand()"s definition is determined by [OS]conf.h */ #if defined(LINT) && defined(UNIX) /* rand() is long... */ extern int NDECL(rand); #define RND(x) (rand() % x) #else /* LINT */ #if defined(UNIX) || defined(RANDOM) #define RND(x) ((int) (Rand() % (long) (x))) #else /* Good luck: the bottom order bits are cyclic. */ #define RND(x) ((int) ((Rand() >> 3) % (x))) #endif #endif /* LINT */ /* 0 <= rn2(x) < x */ int rn2(x) register int x; { #ifdef BETA if (x <= 0) { impossible("rn2(%d) attempted", x); return 0; } x = RND(x); return x; #else return RND(x); #endif } /* 0 <= rnl(x) < x; sometimes subtracting Luck; good luck approaches 0, bad luck approaches (x-1) */ int rnl(x) register int x; { register int i, adjustment; #ifdef BETA if (x <= 0) { impossible("rnl(%d) attempted", x); return 0; } #endif adjustment = Luck; if (x <= 15) { /* for small ranges, use Luck/3 (rounded away from 0); also guard against architecture-specific differences of integer division involving negative values */ adjustment = (abs(adjustment) + 1) / 3 * sgn(adjustment); /* * 11..13 -> 4 * 8..10 -> 3 * 5.. 7 -> 2 * 2.. 4 -> 1 * -1,0,1 -> 0 (no adjustment) * -4..-2 -> -1 * -7..-5 -> -2 * -10..-8 -> -3 * -13..-11-> -4 */ } i = RND(x); if (adjustment && rn2(37 + abs(adjustment))) { i -= adjustment; if (i < 0) i = 0; else if (i >= x) i = x - 1; } return i; } /* 1 <= rnd(x) <= x */ int rnd(x) register int x; { #ifdef BETA if (x <= 0) { impossible("rnd(%d) attempted", x); return 1; } #endif x = RND(x) + 1; return x; } /* d(N,X) == NdX == dX+dX+...+dX N times; n <= d(n,x) <= (n*x) */ int d(n, x) register int n, x; { register int tmp = n; #ifdef BETA if (x < 0 || n < 0 || (x == 0 && n != 0)) { impossible("d(%d,%d) attempted", n, x); return 1; } #endif while (n--) tmp += RND(x); return tmp; /* Alea iacta est. -- J.C. */ } /* 1 <= rne(x) <= max(u.ulevel/3,5) */ int rne(x) register int x; { register int tmp, utmp; utmp = (u.ulevel < 15) ? 5 : u.ulevel / 3; tmp = 1; while (tmp < utmp && !rn2(x)) tmp++; return tmp; /* was: * tmp = 1; * while (!rn2(x)) * tmp++; * return min(tmp, (u.ulevel < 15) ? 5 : u.ulevel / 3); * which is clearer but less efficient and stands a vanishingly * small chance of overflowing tmp */ } /* rnz: everyone's favorite! */ int rnz(i) int i; { #ifdef LINT int x = i; int tmp = 1000; #else register long x = (long) i; register long tmp = 1000L; #endif tmp += rn2(1000); tmp *= rne(4); if (rn2(2)) { x *= tmp; x /= 1000; } else { x *= 1000; x /= tmp; } return (int) x; } /*rnd.c*/ nethack-3.6.0/src/role.c0000664000076400007660000017474312617413107014053 0ustar paxedpaxed/* NetHack 3.6 role.c $NHDT-Date: 1446861770 2015/11/07 02:02:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.34 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /*** Table of all roles ***/ /* According to AD&D, HD for some classes (ex. Wizard) should be smaller * (4-sided for wizards). But this is not AD&D, and using the AD&D * rule here produces an unplayable character. Thus I have used a minimum * of an 10-sided hit die for everything. Another AD&D change: wizards get * a minimum strength of 4 since without one you can't teleport or cast * spells. --KAA * * As the wizard has been updated (wizard patch 5 jun '96) their HD can be * brought closer into line with AD&D. This forces wizards to use magic more * and distance themselves from their attackers. --LSZ * * With the introduction of races, some hit points and energy * has been reallocated for each race. The values assigned * to the roles has been reduced by the amount allocated to * humans. --KMH * * God names use a leading underscore to flag goddesses. */ const struct Role roles[] = { { { "Archeologist", 0 }, { { "Digger", 0 }, { "Field Worker", 0 }, { "Investigator", 0 }, { "Exhumer", 0 }, { "Excavator", 0 }, { "Spelunker", 0 }, { "Speleologist", 0 }, { "Collector", 0 }, { "Curator", 0 } }, "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */ "Arc", "the College of Archeology", "the Tomb of the Toltec Kings", PM_ARCHEOLOGIST, NON_PM, NON_PM, PM_LORD_CARNARVON, PM_STUDENT, PM_MINION_OF_HUHETOTL, NON_PM, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY, ART_ORB_OF_DETECTION, MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 10, 10, 7, 7, 7 }, { 20, 20, 20, 10, 20, 10 }, /* Init Lower Higher */ { 11, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 14, /* Energy */ 10, 5, 0, 2, 10, A_INT, SPE_MAGIC_MAPPING, -4 }, { { "Barbarian", 0 }, { { "Plunderer", "Plunderess" }, { "Pillager", 0 }, { "Bandit", 0 }, { "Brigand", 0 }, { "Raider", 0 }, { "Reaver", 0 }, { "Slayer", 0 }, { "Chieftain", "Chieftainess" }, { "Conqueror", "Conqueress" } }, "Mitra", "Crom", "Set", /* Hyborian */ "Bar", "the Camp of the Duali Tribe", "the Duali Oasis", PM_BARBARIAN, NON_PM, NON_PM, PM_PELIAS, PM_CHIEFTAIN, PM_THOTH_AMON, PM_OGRE, PM_TROLL, S_OGRE, S_TROLL, ART_HEART_OF_AHRIMAN, MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 16, 7, 7, 15, 16, 6 }, { 30, 6, 7, 20, 30, 7 }, /* Init Lower Higher */ { 14, 0, 0, 10, 2, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 10, /* Energy */ 10, 14, 0, 0, 8, A_INT, SPE_HASTE_SELF, -4 }, { { "Caveman", "Cavewoman" }, { { "Troglodyte", 0 }, { "Aborigine", 0 }, { "Wanderer", 0 }, { "Vagrant", 0 }, { "Wayfarer", 0 }, { "Roamer", 0 }, { "Nomad", 0 }, { "Rover", 0 }, { "Pioneer", 0 } }, "Anu", "_Ishtar", "Anshar", /* Babylonian */ "Cav", "the Caves of the Ancestors", "the Dragon's Lair", PM_CAVEMAN, PM_CAVEWOMAN, PM_LITTLE_DOG, PM_SHAMAN_KARNOV, PM_NEANDERTHAL, PM_CHROMATIC_DRAGON, PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT, ART_SCEPTRE_OF_MIGHT, MH_HUMAN | MH_DWARF | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 10, 7, 7, 7, 8, 6 }, { 30, 6, 7, 20, 30, 7 }, /* Init Lower Higher */ { 14, 0, 0, 8, 2, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 10, /* Energy */ 0, 12, 0, 1, 8, A_INT, SPE_DIG, -4 }, { { "Healer", 0 }, { { "Rhizotomist", 0 }, { "Empiric", 0 }, { "Embalmer", 0 }, { "Dresser", 0 }, { "Medicus ossium", "Medica ossium" }, { "Herbalist", 0 }, { "Magister", "Magistra" }, { "Physician", 0 }, { "Chirurgeon", 0 } }, "_Athena", "Hermes", "Poseidon", /* Greek */ "Hea", "the Temple of Epidaurus", "the Temple of Coeus", PM_HEALER, NON_PM, NON_PM, PM_HIPPOCRATES, PM_ATTENDANT, PM_CYCLOPS, PM_GIANT_RAT, PM_SNAKE, S_RODENT, S_YETI, ART_STAFF_OF_AESCULAPIUS, MH_HUMAN | MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 7, 13, 7, 11, 16 }, { 15, 20, 20, 15, 25, 5 }, /* Init Lower Higher */ { 11, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 4, 0, 1, 0, 2 }, 20, /* Energy */ 10, 3, -3, 2, 10, A_WIS, SPE_CURE_SICKNESS, -4 }, { { "Knight", 0 }, { { "Gallant", 0 }, { "Esquire", 0 }, { "Bachelor", 0 }, { "Sergeant", 0 }, { "Knight", 0 }, { "Banneret", 0 }, { "Chevalier", "Chevaliere" }, { "Seignieur", "Dame" }, { "Paladin", 0 } }, "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */ "Kni", "Camelot Castle", "the Isle of Glass", PM_KNIGHT, NON_PM, PM_PONY, PM_KING_ARTHUR, PM_PAGE, PM_IXOTH, PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY, ART_MAGIC_MIRROR_OF_MERLIN, MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL, /* Str Int Wis Dex Con Cha */ { 13, 7, 14, 8, 10, 17 }, { 30, 15, 15, 10, 20, 10 }, /* Init Lower Higher */ { 14, 0, 0, 8, 2, 0 }, /* Hit points */ { 1, 4, 0, 1, 0, 2 }, 10, /* Energy */ 10, 8, -2, 0, 9, A_WIS, SPE_TURN_UNDEAD, -4 }, { { "Monk", 0 }, { { "Candidate", 0 }, { "Novice", 0 }, { "Initiate", 0 }, { "Student of Stones", 0 }, { "Student of Waters", 0 }, { "Student of Metals", 0 }, { "Student of Winds", 0 }, { "Student of Fire", 0 }, { "Master", 0 } }, "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */ "Mon", "the Monastery of Chan-Sune", "the Monastery of the Earth-Lord", PM_MONK, NON_PM, NON_PM, PM_GRAND_MASTER, PM_ABBOT, PM_MASTER_KAEN, PM_EARTH_ELEMENTAL, PM_XORN, S_ELEMENTAL, S_XORN, ART_EYES_OF_THE_OVERWORLD, MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 10, 7, 8, 8, 7, 7 }, { 25, 10, 20, 20, 15, 10 }, /* Init Lower Higher */ { 12, 0, 0, 8, 1, 0 }, /* Hit points */ { 2, 2, 0, 2, 0, 2 }, 10, /* Energy */ 10, 8, -2, 2, 20, A_WIS, SPE_RESTORE_ABILITY, -4 }, { { "Priest", "Priestess" }, { { "Aspirant", 0 }, { "Acolyte", 0 }, { "Adept", 0 }, { "Priest", "Priestess" }, { "Curate", 0 }, { "Canon", "Canoness" }, { "Lama", 0 }, { "Patriarch", "Matriarch" }, { "High Priest", "High Priestess" } }, 0, 0, 0, /* deities from a randomly chosen other role will be used */ "Pri", "the Great Temple", "the Temple of Nalzok", PM_PRIEST, PM_PRIESTESS, NON_PM, PM_ARCH_PRIEST, PM_ACOLYTE, PM_NALZOK, PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH, ART_MITRE_OF_HOLINESS, MH_HUMAN | MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 7, 10, 7, 7, 7 }, { 15, 10, 30, 15, 20, 10 }, /* Init Lower Higher */ { 12, 0, 0, 8, 1, 0 }, /* Hit points */ { 4, 3, 0, 2, 0, 2 }, 10, /* Energy */ 0, 3, -2, 2, 10, A_WIS, SPE_REMOVE_CURSE, -4 }, /* Note: Rogue precedes Ranger so that use of `-R' on the command line retains its traditional meaning. */ { { "Rogue", 0 }, { { "Footpad", 0 }, { "Cutpurse", 0 }, { "Rogue", 0 }, { "Pilferer", 0 }, { "Robber", 0 }, { "Burglar", 0 }, { "Filcher", 0 }, { "Magsman", "Magswoman" }, { "Thief", 0 } }, "Issek", "Mog", "Kos", /* Nehwon */ "Rog", "the Thieves' Guild Hall", "the Assassins' Guild Hall", PM_ROGUE, NON_PM, NON_PM, PM_MASTER_OF_THIEVES, PM_THUG, PM_MASTER_ASSASSIN, PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA, ART_MASTER_KEY_OF_THIEVERY, MH_HUMAN | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 7, 7, 10, 7, 6 }, { 20, 10, 10, 30, 20, 10 }, /* Init Lower Higher */ { 10, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 11, /* Energy */ 10, 8, 0, 1, 9, A_INT, SPE_DETECT_TREASURE, -4 }, { { "Ranger", 0 }, { #if 0 /* OBSOLETE */ {"Edhel", "Elleth"}, {"Edhel", "Elleth"}, /* elf-maid */ {"Ohtar", "Ohtie"}, /* warrior */ {"Kano", "Kanie"}, /* commander (Q.) ['a] educated guess, until further research- SAC */ {"Arandur"," Aranduriel"}, /* king's servant, minister (Q.) - guess */ {"Hir", "Hiril"}, /* lord, lady (S.) ['ir] */ {"Aredhel", "Arwen"}, /* noble elf, maiden (S.) */ {"Ernil", "Elentariel"}, /* prince (S.), elf-maiden (Q.) */ {"Elentar", "Elentari"}, /* Star-king, -queen (Q.) */ "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */ #endif { "Tenderfoot", 0 }, { "Lookout", 0 }, { "Trailblazer", 0 }, { "Reconnoiterer", "Reconnoiteress" }, { "Scout", 0 }, { "Arbalester", 0 }, /* One skilled at crossbows */ { "Archer", 0 }, { "Sharpshooter", 0 }, { "Marksman", "Markswoman" } }, "Mercury", "_Venus", "Mars", /* Roman/planets */ "Ran", "Orion's camp", "the cave of the wumpus", PM_RANGER, NON_PM, PM_LITTLE_DOG /* Orion & canis major */, PM_ORION, PM_HUNTER, PM_SCORPIUS, PM_FOREST_CENTAUR, PM_SCORPION, S_CENTAUR, S_SPIDER, ART_LONGBOW_OF_DIANA, MH_HUMAN | MH_ELF | MH_GNOME | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 13, 13, 13, 9, 13, 7 }, { 30, 10, 10, 20, 20, 10 }, /* Init Lower Higher */ { 13, 0, 0, 6, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 12, /* Energy */ 10, 9, 2, 1, 10, A_INT, SPE_INVISIBILITY, -4 }, { { "Samurai", 0 }, { { "Hatamoto", 0 }, /* Banner Knight */ { "Ronin", 0 }, /* no allegiance */ { "Ninja", "Kunoichi" }, /* secret society */ { "Joshu", 0 }, /* heads a castle */ { "Ryoshu", 0 }, /* has a territory */ { "Kokushu", 0 }, /* heads a province */ { "Daimyo", 0 }, /* a samurai lord */ { "Kuge", 0 }, /* Noble of the Court */ { "Shogun", 0 } }, /* supreme commander, warlord */ "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */ "Sam", "the Castle of the Taro Clan", "the Shogun's Castle", PM_SAMURAI, NON_PM, PM_LITTLE_DOG, PM_LORD_SATO, PM_ROSHI, PM_ASHIKAGA_TAKAUJI, PM_WOLF, PM_STALKER, S_DOG, S_ELEMENTAL, ART_TSURUGI_OF_MURAMASA, MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL, /* Str Int Wis Dex Con Cha */ { 10, 8, 7, 10, 17, 6 }, { 30, 10, 8, 30, 14, 8 }, /* Init Lower Higher */ { 13, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 11, /* Energy */ 10, 10, 0, 0, 8, A_INT, SPE_CLAIRVOYANCE, -4 }, { { "Tourist", 0 }, { { "Rambler", 0 }, { "Sightseer", 0 }, { "Excursionist", 0 }, { "Peregrinator", "Peregrinatrix" }, { "Traveler", 0 }, { "Journeyer", 0 }, { "Voyager", 0 }, { "Explorer", 0 }, { "Adventurer", 0 } }, "Blind Io", "_The Lady", "Offler", /* Discworld */ "Tou", "Ankh-Morpork", "the Thieves' Guild Hall", PM_TOURIST, NON_PM, NON_PM, PM_TWOFLOWER, PM_GUIDE, PM_MASTER_OF_THIEVES, PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR, ART_YENDORIAN_EXPRESS_CARD, MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 10, 6, 7, 7, 10 }, { 15, 10, 10, 15, 30, 20 }, /* Init Lower Higher */ { 8, 0, 0, 8, 0, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 14, /* Energy */ 0, 5, 1, 2, 10, A_INT, SPE_CHARM_MONSTER, -4 }, { { "Valkyrie", 0 }, { { "Stripling", 0 }, { "Skirmisher", 0 }, { "Fighter", 0 }, { "Man-at-arms", "Woman-at-arms" }, { "Warrior", 0 }, { "Swashbuckler", 0 }, { "Hero", "Heroine" }, { "Champion", 0 }, { "Lord", "Lady" } }, "Tyr", "Odin", "Loki", /* Norse */ "Val", "the Shrine of Destiny", "the cave of Surtur", PM_VALKYRIE, NON_PM, NON_PM /*PM_WINTER_WOLF_CUB*/, PM_NORN, PM_WARRIOR, PM_LORD_SURTUR, PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT, ART_ORB_OF_FATE, MH_HUMAN | MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 10, 7, 7, 7, 10, 7 }, { 30, 6, 7, 20, 30, 7 }, /* Init Lower Higher */ { 14, 0, 0, 8, 2, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 }, 10, /* Energy */ 0, 10, -2, 0, 9, A_WIS, SPE_CONE_OF_COLD, -4 }, { { "Wizard", 0 }, { { "Evoker", 0 }, { "Conjurer", 0 }, { "Thaumaturge", 0 }, { "Magician", 0 }, { "Enchanter", "Enchantress" }, { "Sorcerer", "Sorceress" }, { "Necromancer", 0 }, { "Wizard", 0 }, { "Mage", 0 } }, "Ptah", "Thoth", "Anhur", /* Egyptian */ "Wiz", "the Lonely Tower", "the Tower of Darkness", PM_WIZARD, NON_PM, PM_KITTEN, PM_NEFERET_THE_GREEN, PM_APPRENTICE, PM_DARK_ONE, PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH, ART_EYE_OF_THE_AETHIOPICA, MH_HUMAN | MH_ELF | MH_GNOME | MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 10, 7, 7, 7, 7 }, { 10, 30, 10, 20, 20, 10 }, /* Init Lower Higher */ { 10, 0, 0, 8, 1, 0 }, /* Hit points */ { 4, 3, 0, 2, 0, 3 }, 12, /* Energy */ 0, 1, 0, 3, 10, A_INT, SPE_MAGIC_MISSILE, -4 }, /* Array terminator */ { { 0, 0 } } }; /* The player's role, created at runtime from initial * choices. This may be munged in role_init(). */ struct Role urole = { { "Undefined", 0 }, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, "L", "N", "C", "Xxx", "home", "locate", NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, 0, 0, 0, 0, /* Str Int Wis Dex Con Cha */ { 7, 7, 7, 7, 7, 7 }, { 20, 15, 15, 20, 20, 10 }, /* Init Lower Higher */ { 10, 0, 0, 8, 1, 0 }, /* Hit points */ { 2, 0, 0, 2, 0, 3 }, 14, /* Energy */ 0, 10, 0, 0, 4, A_INT, 0, -3 }; /* Table of all races */ const struct Race races[] = { { "human", "human", "humanity", "Hum", { "man", "woman" }, PM_HUMAN, NON_PM, PM_HUMAN_MUMMY, PM_HUMAN_ZOMBIE, MH_HUMAN | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL | ROLE_NEUTRAL | ROLE_CHAOTIC, MH_HUMAN, 0, MH_GNOME | MH_ORC, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 18, 18, 18, 18, 18 }, /* Init Lower Higher */ { 2, 0, 0, 2, 1, 0 }, /* Hit points */ { 1, 0, 2, 0, 2, 0 } /* Energy */ }, { "elf", "elven", "elvenkind", "Elf", { 0, 0 }, PM_ELF, NON_PM, PM_ELF_MUMMY, PM_ELF_ZOMBIE, MH_ELF | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC, MH_ELF, MH_ELF, MH_ORC, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { 18, 20, 20, 18, 16, 18 }, /* Init Lower Higher */ { 1, 0, 0, 1, 1, 0 }, /* Hit points */ { 2, 0, 3, 0, 3, 0 } /* Energy */ }, { "dwarf", "dwarven", "dwarvenkind", "Dwa", { 0, 0 }, PM_DWARF, NON_PM, PM_DWARF_MUMMY, PM_DWARF_ZOMBIE, MH_DWARF | ROLE_MALE | ROLE_FEMALE | ROLE_LAWFUL, MH_DWARF, MH_DWARF | MH_GNOME, MH_ORC, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 16, 16, 20, 20, 16 }, /* Init Lower Higher */ { 4, 0, 0, 3, 2, 0 }, /* Hit points */ { 0, 0, 0, 0, 0, 0 } /* Energy */ }, { "gnome", "gnomish", "gnomehood", "Gno", { 0, 0 }, PM_GNOME, NON_PM, PM_GNOME_MUMMY, PM_GNOME_ZOMBIE, MH_GNOME | ROLE_MALE | ROLE_FEMALE | ROLE_NEUTRAL, MH_GNOME, MH_DWARF | MH_GNOME, MH_HUMAN, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(50), 19, 18, 18, 18, 18 }, /* Init Lower Higher */ { 1, 0, 0, 1, 0, 0 }, /* Hit points */ { 2, 0, 2, 0, 2, 0 } /* Energy */ }, { "orc", "orcish", "orcdom", "Orc", { 0, 0 }, PM_ORC, NON_PM, PM_ORC_MUMMY, PM_ORC_ZOMBIE, MH_ORC | ROLE_MALE | ROLE_FEMALE | ROLE_CHAOTIC, MH_ORC, 0, MH_HUMAN | MH_ELF | MH_DWARF, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(50), 16, 16, 18, 18, 16 }, /* Init Lower Higher */ { 1, 0, 0, 1, 0, 0 }, /* Hit points */ { 1, 0, 1, 0, 1, 0 } /* Energy */ }, /* Array terminator */ { 0, 0, 0, 0 } }; /* The player's race, created at runtime from initial * choices. This may be munged in role_init(). */ struct Race urace = { "something", "undefined", "something", "Xxx", { 0, 0 }, NON_PM, NON_PM, NON_PM, NON_PM, 0, 0, 0, 0, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 18, 18, 18, 18, 18 }, /* Init Lower Higher */ { 2, 0, 0, 2, 1, 0 }, /* Hit points */ { 1, 0, 2, 0, 2, 0 } /* Energy */ }; /* Table of all genders */ const struct Gender genders[] = { { "male", "he", "him", "his", "Mal", ROLE_MALE }, { "female", "she", "her", "her", "Fem", ROLE_FEMALE }, { "neuter", "it", "it", "its", "Ntr", ROLE_NEUTER } }; /* Table of all alignments */ const struct Align aligns[] = { { "law", "lawful", "Law", ROLE_LAWFUL, A_LAWFUL }, { "balance", "neutral", "Neu", ROLE_NEUTRAL, A_NEUTRAL }, { "chaos", "chaotic", "Cha", ROLE_CHAOTIC, A_CHAOTIC }, { "evil", "unaligned", "Una", 0, A_NONE } }; /* Filters */ static struct { boolean roles[SIZE(roles)]; short mask; } filter; STATIC_DCL int NDECL(randrole_filtered); STATIC_DCL char *FDECL(promptsep, (char *, int)); STATIC_DCL int FDECL(role_gendercount, (int)); STATIC_DCL int FDECL(race_alignmentcount, (int)); /* used by str2XXX() */ static char NEARDATA randomstr[] = "random"; boolean validrole(rolenum) int rolenum; { return (boolean) (rolenum >= 0 && rolenum < SIZE(roles) - 1); } int randrole() { return rn2(SIZE(roles) - 1); } STATIC_OVL int randrole_filtered() { int i, n = 0, set[SIZE(roles)]; /* this doesn't rule out impossible combinations but attempts to honor all the filter masks */ for (i = 0; i < SIZE(roles); ++i) if (ok_role(i, ROLE_NONE, ROLE_NONE, ROLE_NONE) && ok_race(i, ROLE_RANDOM, ROLE_NONE, ROLE_NONE) && ok_gend(i, ROLE_NONE, ROLE_RANDOM, ROLE_NONE) && ok_align(i, ROLE_NONE, ROLE_NONE, ROLE_RANDOM)) set[n++] = i; return n ? set[rn2(n)] : randrole(); } int str2role(str) const char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; roles[i].name.m; i++) { /* Does it match the male name? */ if (!strncmpi(str, roles[i].name.m, len)) return i; /* Or the female name? */ if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len)) return i; /* Or the filecode? */ if (!strcmpi(str, roles[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } boolean validrace(rolenum, racenum) int rolenum, racenum; { /* Assumes validrole */ return (boolean) (racenum >= 0 && racenum < SIZE(races) - 1 && (roles[rolenum].allow & races[racenum].allow & ROLE_RACEMASK)); } int randrace(rolenum) int rolenum; { int i, n = 0; /* Count the number of valid races */ for (i = 0; races[i].noun; i++) if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) n++; /* Pick a random race */ /* Use a factor of 100 in case of bad random number generators */ if (n) n = rn2(n * 100) / 100; for (i = 0; races[i].noun; i++) if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) { if (n) n--; else return i; } /* This role has no permitted races? */ return rn2(SIZE(races) - 1); } int str2race(str) const char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; races[i].noun; i++) { /* Does it match the noun? */ if (!strncmpi(str, races[i].noun, len)) return i; /* Or the filecode? */ if (!strcmpi(str, races[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } boolean validgend(rolenum, racenum, gendnum) int rolenum, racenum, gendnum; { /* Assumes validrole and validrace */ return (boolean) (gendnum >= 0 && gendnum < ROLE_GENDERS && (roles[rolenum].allow & races[racenum].allow & genders[gendnum].allow & ROLE_GENDMASK)); } int randgend(rolenum, racenum) int rolenum, racenum; { int i, n = 0; /* Count the number of valid genders */ for (i = 0; i < ROLE_GENDERS; i++) if (roles[rolenum].allow & races[racenum].allow & genders[i].allow & ROLE_GENDMASK) n++; /* Pick a random gender */ if (n) n = rn2(n); for (i = 0; i < ROLE_GENDERS; i++) if (roles[rolenum].allow & races[racenum].allow & genders[i].allow & ROLE_GENDMASK) { if (n) n--; else return i; } /* This role/race has no permitted genders? */ return rn2(ROLE_GENDERS); } int str2gend(str) const char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; i < ROLE_GENDERS; i++) { /* Does it match the adjective? */ if (!strncmpi(str, genders[i].adj, len)) return i; /* Or the filecode? */ if (!strcmpi(str, genders[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } boolean validalign(rolenum, racenum, alignnum) int rolenum, racenum, alignnum; { /* Assumes validrole and validrace */ return (boolean) (alignnum >= 0 && alignnum < ROLE_ALIGNS && (roles[rolenum].allow & races[racenum].allow & aligns[alignnum].allow & ROLE_ALIGNMASK)); } int randalign(rolenum, racenum) int rolenum, racenum; { int i, n = 0; /* Count the number of valid alignments */ for (i = 0; i < ROLE_ALIGNS; i++) if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow & ROLE_ALIGNMASK) n++; /* Pick a random alignment */ if (n) n = rn2(n); for (i = 0; i < ROLE_ALIGNS; i++) if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow & ROLE_ALIGNMASK) { if (n) n--; else return i; } /* This role/race has no permitted alignments? */ return rn2(ROLE_ALIGNS); } int str2align(str) const char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; i < ROLE_ALIGNS; i++) { /* Does it match the adjective? */ if (!strncmpi(str, aligns[i].adj, len)) return i; /* Or the filecode? */ if (!strcmpi(str, aligns[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */ boolean ok_role(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum, alignnum; { int i; short allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1) { if (filter.roles[rolenum]) return FALSE; allow = roles[rolenum].allow; if (racenum >= 0 && racenum < SIZE(races) - 1 && !(allow & races[racenum].allow & ROLE_RACEMASK)) return FALSE; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) return FALSE; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) return FALSE; return TRUE; } else { /* random; check whether any selection is possible */ for (i = 0; i < SIZE(roles) - 1; i++) { if (filter.roles[i]) continue; allow = roles[i].allow; if (racenum >= 0 && racenum < SIZE(races) - 1 && !(allow & races[racenum].allow & ROLE_RACEMASK)) continue; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) continue; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) continue; return TRUE; } return FALSE; } } /* pick a random role subject to any racenum/gendnum/alignnum constraints */ /* If pickhow == PICK_RIGID a role is returned only if there is */ /* a single possibility */ int pick_role(racenum, gendnum, alignnum, pickhow) int racenum, gendnum, alignnum, pickhow; { int i; int roles_ok = 0, set[SIZE(roles)]; for (i = 0; i < SIZE(roles) - 1; i++) { if (ok_role(i, racenum, gendnum, alignnum) && ok_race(i, (racenum >= 0) ? racenum : ROLE_RANDOM, gendnum, alignnum) && ok_gend(i, racenum, (gendnum >= 0) ? gendnum : ROLE_RANDOM, alignnum) && ok_race(i, racenum, gendnum, (alignnum >= 0) ? alignnum : ROLE_RANDOM)) set[roles_ok++] = i; } if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; return set[rn2(roles_ok)]; } /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */ boolean ok_race(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum, alignnum; { int i; short allow; if (racenum >= 0 && racenum < SIZE(races) - 1) { if (filter.mask & races[racenum].selfmask) return FALSE; allow = races[racenum].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_RACEMASK)) return FALSE; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) return FALSE; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) return FALSE; return TRUE; } else { /* random; check whether any selection is possible */ for (i = 0; i < SIZE(races) - 1; i++) { if (filter.mask & races[i].selfmask) continue; allow = races[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_RACEMASK)) continue; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) continue; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) continue; return TRUE; } return FALSE; } } /* pick a random race subject to any rolenum/gendnum/alignnum constraints */ /* If pickhow == PICK_RIGID a race is returned only if there is */ /* a single possibility */ int pick_race(rolenum, gendnum, alignnum, pickhow) int rolenum, gendnum, alignnum, pickhow; { int i; int races_ok = 0; for (i = 0; i < SIZE(races) - 1; i++) { if (ok_race(rolenum, i, gendnum, alignnum)) races_ok++; } if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; races_ok = rn2(races_ok); for (i = 0; i < SIZE(races) - 1; i++) { if (ok_race(rolenum, i, gendnum, alignnum)) { if (races_ok == 0) return i; else races_ok--; } } return ROLE_NONE; } /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */ /* gender and alignment are not comparable (and also not constrainable) */ boolean ok_gend(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum; int alignnum UNUSED; { int i; short allow; if (gendnum >= 0 && gendnum < ROLE_GENDERS) { if (filter.mask & genders[gendnum].allow) return FALSE; allow = genders[gendnum].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_GENDMASK)) return FALSE; if (racenum >= 0 && racenum < SIZE(races) - 1 && !(allow & races[racenum].allow & ROLE_GENDMASK)) return FALSE; return TRUE; } else { /* random; check whether any selection is possible */ for (i = 0; i < ROLE_GENDERS; i++) { if (filter.mask & genders[i].allow) continue; allow = genders[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_GENDMASK)) continue; if (racenum >= 0 && racenum < SIZE(races) - 1 && !(allow & races[racenum].allow & ROLE_GENDMASK)) continue; return TRUE; } return FALSE; } } /* pick a random gender subject to any rolenum/racenum/alignnum constraints */ /* gender and alignment are not comparable (and also not constrainable) */ /* If pickhow == PICK_RIGID a gender is returned only if there is */ /* a single possibility */ int pick_gend(rolenum, racenum, alignnum, pickhow) int rolenum, racenum, alignnum, pickhow; { int i; int gends_ok = 0; for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(rolenum, racenum, i, alignnum)) gends_ok++; } if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; gends_ok = rn2(gends_ok); for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(rolenum, racenum, i, alignnum)) { if (gends_ok == 0) return i; else gends_ok--; } } return ROLE_NONE; } /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */ /* alignment and gender are not comparable (and also not constrainable) */ boolean ok_align(rolenum, racenum, gendnum, alignnum) int rolenum, racenum; int gendnum UNUSED; int alignnum; { int i; short allow; if (alignnum >= 0 && alignnum < ROLE_ALIGNS) { if (filter.mask & aligns[alignnum].allow) return FALSE; allow = aligns[alignnum].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) return FALSE; if (racenum >= 0 && racenum < SIZE(races) - 1 && !(allow & races[racenum].allow & ROLE_ALIGNMASK)) return FALSE; return TRUE; } else { /* random; check whether any selection is possible */ for (i = 0; i < ROLE_ALIGNS; i++) { if (filter.mask & aligns[i].allow) return FALSE; allow = aligns[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) continue; if (racenum >= 0 && racenum < SIZE(races) - 1 && !(allow & races[racenum].allow & ROLE_ALIGNMASK)) continue; return TRUE; } return FALSE; } } /* pick a random alignment subject to any rolenum/racenum/gendnum constraints */ /* alignment and gender are not comparable (and also not constrainable) */ /* If pickhow == PICK_RIGID an alignment is returned only if there is */ /* a single possibility */ int pick_align(rolenum, racenum, gendnum, pickhow) int rolenum, racenum, gendnum, pickhow; { int i; int aligns_ok = 0; for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(rolenum, racenum, gendnum, i)) aligns_ok++; } if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; aligns_ok = rn2(aligns_ok); for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(rolenum, racenum, gendnum, i)) { if (aligns_ok == 0) return i; else aligns_ok--; } } return ROLE_NONE; } void rigid_role_checks() { /* Some roles are limited to a single race, alignment, or gender and * calling this routine prior to XXX_player_selection() will help * prevent an extraneous prompt that actually doesn't allow * you to choose anything further. Note the use of PICK_RIGID which * causes the pick_XX() routine to return a value only if there is one * single possible selection, otherwise it returns ROLE_NONE. * */ if (flags.initrole == ROLE_RANDOM) { /* If the role was explicitly specified as ROLE_RANDOM * via -uXXXX-@ then choose the role in here to narrow down * later choices. Pick a random role in this case. */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) flags.initrole = randrole_filtered(); } if (flags.initrole != ROLE_NONE) { if (flags.initrace == ROLE_NONE) flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RIGID); if (flags.initalign == ROLE_NONE) flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RIGID); if (flags.initgend == ROLE_NONE) flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RIGID); } } boolean setrolefilter(bufp) const char *bufp; { int i; boolean reslt = TRUE; if ((i = str2role(bufp)) != ROLE_NONE && i != ROLE_RANDOM) filter.roles[i] = TRUE; else if ((i = str2race(bufp)) != ROLE_NONE && i != ROLE_RANDOM) filter.mask |= races[i].selfmask; else if ((i = str2gend(bufp)) != ROLE_NONE && i != ROLE_RANDOM) filter.mask |= genders[i].allow; else if ((i = str2align(bufp)) != ROLE_NONE && i != ROLE_RANDOM) filter.mask |= aligns[i].allow; else reslt = FALSE; return reslt; } boolean gotrolefilter() { int i; if (filter.mask) return TRUE; for (i = 0; i < SIZE(roles); ++i) if (filter.roles[i]) return TRUE; return FALSE; } void clearrolefilter() { int i; for (i = 0; i < SIZE(roles); ++i) filter.roles[i] = FALSE; filter.mask = 0; } #define BP_ALIGN 0 #define BP_GEND 1 #define BP_RACE 2 #define BP_ROLE 3 #define NUM_BP 4 STATIC_VAR char pa[NUM_BP], post_attribs; STATIC_OVL char * promptsep(buf, num_post_attribs) char *buf; int num_post_attribs; { const char *conjuct = "and "; if (num_post_attribs > 1 && post_attribs < num_post_attribs && post_attribs > 1) Strcat(buf, ","); Strcat(buf, " "); --post_attribs; if (!post_attribs && num_post_attribs > 1) Strcat(buf, conjuct); return buf; } STATIC_OVL int role_gendercount(rolenum) int rolenum; { int gendcount = 0; if (validrole(rolenum)) { if (roles[rolenum].allow & ROLE_MALE) ++gendcount; if (roles[rolenum].allow & ROLE_FEMALE) ++gendcount; if (roles[rolenum].allow & ROLE_NEUTER) ++gendcount; } return gendcount; } STATIC_OVL int race_alignmentcount(racenum) int racenum; { int aligncount = 0; if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) { if (races[racenum].allow & ROLE_CHAOTIC) ++aligncount; if (races[racenum].allow & ROLE_LAWFUL) ++aligncount; if (races[racenum].allow & ROLE_NEUTRAL) ++aligncount; } return aligncount; } char * root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum) char *suppliedbuf; int buflen, rolenum, racenum, gendnum, alignnum; { int k, gendercount = 0, aligncount = 0; char buf[BUFSZ]; static char err_ret[] = " character's"; boolean donefirst = FALSE; if (!suppliedbuf || buflen < 1) return err_ret; /* initialize these static variables each time this is called */ post_attribs = 0; for (k = 0; k < NUM_BP; ++k) pa[k] = 0; buf[0] = '\0'; *suppliedbuf = '\0'; /* How many alignments are allowed for the desired race? */ if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) aligncount = race_alignmentcount(racenum); if (alignnum != ROLE_NONE && alignnum != ROLE_RANDOM && ok_align(rolenum, racenum, gendnum, alignnum)) { /* if race specified, and multiple choice of alignments for it */ if ((racenum >= 0) && (aligncount > 1)) { if (donefirst) Strcat(buf, " "); Strcat(buf, aligns[alignnum].adj); donefirst = TRUE; } else { if (donefirst) Strcat(buf, " "); Strcat(buf, aligns[alignnum].adj); donefirst = TRUE; } } else { /* in case we got here by failing the ok_align() test */ if (alignnum != ROLE_RANDOM) alignnum = ROLE_NONE; /* if alignment not specified, but race is specified and only one choice of alignment for that race then don't include it in the later list */ if ((((racenum != ROLE_NONE && racenum != ROLE_RANDOM) && ok_race(rolenum, racenum, gendnum, alignnum)) && (aligncount > 1)) || (racenum == ROLE_NONE || racenum == ROLE_RANDOM)) { pa[BP_ALIGN] = 1; post_attribs++; } } /* */ /* How many genders are allowed for the desired role? */ if (validrole(rolenum)) gendercount = role_gendercount(rolenum); if (gendnum != ROLE_NONE && gendnum != ROLE_RANDOM) { if (validrole(rolenum)) { /* if role specified, and multiple choice of genders for it, and name of role itself does not distinguish gender */ if ((rolenum != ROLE_NONE) && (gendercount > 1) && !roles[rolenum].name.f) { if (donefirst) Strcat(buf, " "); Strcat(buf, genders[gendnum].adj); donefirst = TRUE; } } else { if (donefirst) Strcat(buf, " "); Strcat(buf, genders[gendnum].adj); donefirst = TRUE; } } else { /* if gender not specified, but role is specified and only one choice of gender then don't include it in the later list */ if ((validrole(rolenum) && (gendercount > 1)) || !validrole(rolenum)) { pa[BP_GEND] = 1; post_attribs++; } } /* */ if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) { if (validrole(rolenum) && ok_race(rolenum, racenum, gendnum, alignnum)) { if (donefirst) Strcat(buf, " "); Strcat(buf, (rolenum == ROLE_NONE) ? races[racenum].noun : races[racenum].adj); donefirst = TRUE; } else if (!validrole(rolenum)) { if (donefirst) Strcat(buf, " "); Strcat(buf, races[racenum].noun); donefirst = TRUE; } else { pa[BP_RACE] = 1; post_attribs++; } } else { pa[BP_RACE] = 1; post_attribs++; } /* || */ if (validrole(rolenum)) { if (donefirst) Strcat(buf, " "); if (gendnum != ROLE_NONE) { if (gendnum == 1 && roles[rolenum].name.f) Strcat(buf, roles[rolenum].name.f); else Strcat(buf, roles[rolenum].name.m); } else { if (roles[rolenum].name.f) { Strcat(buf, roles[rolenum].name.m); Strcat(buf, "/"); Strcat(buf, roles[rolenum].name.f); } else Strcat(buf, roles[rolenum].name.m); } donefirst = TRUE; } else if (rolenum == ROLE_NONE) { pa[BP_ROLE] = 1; post_attribs++; } if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM) && !validrole(rolenum)) { if (donefirst) Strcat(buf, " "); Strcat(buf, "character"); donefirst = TRUE; } /* || * || */ if (buflen > (int) (strlen(buf) + 1)) { Strcpy(suppliedbuf, buf); return suppliedbuf; } else return err_ret; } char * build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum) char *buf; int buflen, rolenum, racenum, gendnum, alignnum; { const char *defprompt = "Shall I pick a character for you? [ynaq] "; int num_post_attribs = 0; char tmpbuf[BUFSZ], *p; if (buflen < QBUFSZ) return (char *) defprompt; Strcpy(tmpbuf, "Shall I pick "); if (racenum != ROLE_NONE || validrole(rolenum)) Strcat(tmpbuf, "your "); else { Strcat(tmpbuf, "a "); } /* */ (void) root_plselection_prompt(eos(tmpbuf), buflen - strlen(tmpbuf), rolenum, racenum, gendnum, alignnum); Sprintf(buf, "%s", s_suffix(tmpbuf)); /* don't bother splitting caveman/cavewoman or priest/priestess in order to apply possessive suffix to both halves, but do change "priest/priestess'" to "priest/priestess's" */ if ((p = strstri(buf, "priest/priestess'")) != 0 && p[sizeof "priest/priestess'" - sizeof ""] == '\0') strkitten(buf, 's'); /* buf should now be: * * || * || * * Now append the post attributes to it */ num_post_attribs = post_attribs; if (post_attribs) { if (pa[BP_RACE]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "race"); } if (pa[BP_ROLE]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "role"); } if (pa[BP_GEND]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "gender"); } if (pa[BP_ALIGN]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "alignment"); } } Strcat(buf, " for you? [ynaq] "); return buf; } #undef BP_ALIGN #undef BP_GEND #undef BP_RACE #undef BP_ROLE #undef NUM_BP void plnamesuffix() { char *sptr, *eptr; int i; #ifdef GENERIC_USERNAMES { /* some generic user names will be ignored in favor of prompting */ const char *uptr = GENERIC_USERNAMES; i = (int) strlen(plname); if ((sptr = strstri(uptr, plname)) != 0 && (sptr == uptr || sptr[-1] == ' ') && (sptr[i] == ' ' || sptr[i] == '\0')) *plname = '\0'; /* call askname() */ } #endif do { if (!*plname) askname(); /* fill plname[] if necessary */ /* Look for tokens delimited by '-' */ if ((eptr = index(plname, '-')) != (char *) 0) *eptr++ = '\0'; while (eptr) { /* Isolate the next token */ sptr = eptr; if ((eptr = index(sptr, '-')) != (char *) 0) *eptr++ = '\0'; /* Try to match it to something */ if ((i = str2role(sptr)) != ROLE_NONE) flags.initrole = i; else if ((i = str2race(sptr)) != ROLE_NONE) flags.initrace = i; else if ((i = str2gend(sptr)) != ROLE_NONE) flags.initgend = i; else if ((i = str2align(sptr)) != ROLE_NONE) flags.initalign = i; } } while (!*plname); /* commas in the plname confuse the record file, convert to spaces */ for (sptr = plname; *sptr; sptr++) { if (*sptr == ',') *sptr = ' '; } } /* show current settings for name, role, race, gender, and alignment in the specified window */ void role_selection_prolog(which, where) int which; winid where; { static const char NEARDATA choosing[] = " choosing now", not_yet[] = " not yet specified", rand_choice[] = " random"; char buf[BUFSZ]; int r, c, g, a, allowmask; r = flags.initrole; c = flags.initrace; g = flags.initgend; a = flags.initalign; if (r >= 0) { allowmask = roles[r].allow; if ((allowmask & ROLE_RACEMASK) == MH_HUMAN) c = 0; /* races[human] */ else if (c >= 0 && !(allowmask & ROLE_RACEMASK & races[c].allow)) c = ROLE_RANDOM; if ((allowmask & ROLE_GENDMASK) == ROLE_MALE) g = 0; /* role forces male (hypothetical) */ else if ((allowmask & ROLE_GENDMASK) == ROLE_FEMALE) g = 1; /* role forces female (valkyrie) */ if ((allowmask & ROLE_ALIGNMASK) == AM_LAWFUL) a = 0; /* aligns[lawful] */ else if ((allowmask & ROLE_ALIGNMASK) == AM_NEUTRAL) a = 1; /* aligns[neutral] */ else if ((allowmask & ROLE_ALIGNMASK) == AM_CHAOTIC) a = 2; /* alings[chaotic] */ } if (c >= 0) { allowmask = races[c].allow; if ((allowmask & ROLE_ALIGNMASK) == AM_LAWFUL) a = 0; /* aligns[lawful] */ else if ((allowmask & ROLE_ALIGNMASK) == AM_NEUTRAL) a = 1; /* aligns[neutral] */ else if ((allowmask & ROLE_ALIGNMASK) == AM_CHAOTIC) a = 2; /* alings[chaotic] */ /* [c never forces gender] */ } /* [g and a don't constrain anything sufficiently to narrow something done to a single choice] */ Sprintf(buf, "%12s ", "name:"); Strcat(buf, (which == RS_NAME) ? choosing : !*plname ? not_yet : plname); putstr(where, 0, buf); Sprintf(buf, "%12s ", "role:"); Strcat(buf, (which == RS_ROLE) ? choosing : (r == ROLE_NONE) ? not_yet : (r == ROLE_RANDOM) ? rand_choice : roles[r].name.m); if (r >= 0 && roles[r].name.f) { /* distinct female name [caveman/cavewoman, priest/priestess] */ if (g == 1) /* female specified; replace male role name with female one */ Sprintf(index(buf, ':'), ": %s", roles[r].name.f); else if (g < 0) /* gender unspecified; append slash and female role name */ Sprintf(eos(buf), "/%s", roles[r].name.f); } putstr(where, 0, buf); Sprintf(buf, "%12s ", "race:"); Strcat(buf, (which == RS_RACE) ? choosing : (c == ROLE_NONE) ? not_yet : (c == ROLE_RANDOM) ? rand_choice : races[c].noun); putstr(where, 0, buf); Sprintf(buf, "%12s ", "gender:"); Strcat(buf, (which == RS_GENDER) ? choosing : (g == ROLE_NONE) ? not_yet : (g == ROLE_RANDOM) ? rand_choice : genders[g].adj); putstr(where, 0, buf); Sprintf(buf, "%12s ", "alignment:"); Strcat(buf, (which == RS_ALGNMNT) ? choosing : (a == ROLE_NONE) ? not_yet : (a == ROLE_RANDOM) ? rand_choice : aligns[a].adj); putstr(where, 0, buf); } /* add a "pick alignment first"-type entry to the specified menu */ void role_menu_extra(which, where) int which; winid where; { static NEARDATA const char RS_menu_let[] = { '=', /* name */ '?', /* role */ '/', /* race */ '\"', /* gender */ '[', /* alignment */ }; anything any; char buf[BUFSZ]; const char *what = 0, *constrainer = 0, *forcedvalue = 0; int f = 0, r, c, g, a, i, allowmask; r = flags.initrole; c = flags.initrace; switch (which) { case RS_NAME: what = "name"; break; case RS_ROLE: what = "role"; f = r; for (i = 0; i < SIZE(roles); ++i) if (i != f && !filter.roles[i]) break; if (i == SIZE(roles)) { constrainer = "filter"; forcedvalue = "role"; } break; case RS_RACE: what = "race"; f = flags.initrace; c = ROLE_NONE; /* override player's setting */ if (r >= 0) { allowmask = roles[r].allow & ROLE_RACEMASK; if (allowmask == MH_HUMAN) c = 0; /* races[human] */ if (c >= 0) { constrainer = "role"; forcedvalue = races[c].noun; } else if (f >= 0 && (allowmask & ~filter.mask) == races[f].selfmask) { /* if there is only one race choice available due to user options disallowing others, race menu entry is disabled */ constrainer = "filter"; forcedvalue = "race"; } } break; case RS_GENDER: what = "gender"; f = flags.initgend; g = ROLE_NONE; if (r >= 0) { allowmask = roles[r].allow & ROLE_GENDMASK; if (allowmask == ROLE_MALE) g = 0; /* genders[male] */ else if (allowmask == ROLE_FEMALE) g = 1; /* genders[female] */ if (g >= 0) { constrainer = "role"; forcedvalue = genders[g].adj; } else if (f >= 0 && (allowmask & ~filter.mask) == genders[f].allow) { /* if there is only one gender choice available due to user options disallowing other, gender menu entry is disabled */ constrainer = "filter"; forcedvalue = "gender"; } } break; case RS_ALGNMNT: what = "alignment"; f = flags.initalign; a = ROLE_NONE; if (r >= 0) { allowmask = roles[r].allow & ROLE_ALIGNMASK; if (allowmask == AM_LAWFUL) a = 0; /* aligns[lawful] */ else if (allowmask == AM_NEUTRAL) a = 1; /* aligns[neutral] */ else if (allowmask == AM_CHAOTIC) a = 2; /* aligns[chaotic] */ if (a >= 0) constrainer = "role"; } if (c >= 0 && !constrainer) { allowmask = races[c].allow & ROLE_ALIGNMASK; if (allowmask == AM_LAWFUL) a = 0; /* aligns[lawful] */ else if (allowmask == AM_NEUTRAL) a = 1; /* aligns[neutral] */ else if (allowmask == AM_CHAOTIC) a = 2; /* aligns[chaotic] */ if (a >= 0) constrainer = "race"; } if (f >= 0 && !constrainer && (ROLE_ALIGNMASK & ~filter.mask) == aligns[f].allow) { /* if there is only one alignment choice available due to user options disallowing others, algn menu entry is disabled */ constrainer = "filter"; forcedvalue = "alignment"; } if (a >= 0) forcedvalue = aligns[a].adj; break; } any = zeroany; /* zero out all bits */ if (constrainer) { any.a_int = 0; /* use four spaces of padding to fake a grayed out menu choice */ Sprintf(buf, "%4s%s forces %s", "", constrainer, forcedvalue); add_menu(where, NO_GLYPH, &any, ' ', 0, ATR_NONE, buf, MENU_UNSELECTED); } else if (what) { any.a_int = RS_menu_arg(which); Sprintf(buf, "Pick%s %s first", (f >= 0) ? " another" : "", what); add_menu(where, NO_GLYPH, &any, RS_menu_let[which], 0, ATR_NONE, buf, MENU_UNSELECTED); } else if (which == RS_filter) { any.a_int = RS_menu_arg(RS_filter); add_menu(where, NO_GLYPH, &any, '~', 0, ATR_NONE, "Reset role/race/&c filtering", MENU_UNSELECTED); } else if (which == ROLE_RANDOM) { any.a_int = ROLE_RANDOM; add_menu(where, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); } else if (which == ROLE_NONE) { any.a_int = ROLE_NONE; add_menu(where, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); } else { impossible("role_menu_extra: bad arg (%d)", which); } } /* * Special setup modifications here: * * Unfortunately, this is going to have to be done * on each newgame or restore, because you lose the permonst mods * across a save/restore. :-) * * 1 - The Rogue Leader is the Tourist Nemesis. * 2 - Priests start with a random alignment - convert the leader and * guardians here. * 3 - Priests also get their of deities from a randomly chosen role. * 4 - [obsolete] Elves can have one of two different leaders, * but can't work it out here because it requires hacking the * level file data (see sp_lev.c). * * This code also replaces quest_init(). */ void role_init() { int alignmnt; struct permonst *pm; /* Strip the role letter out of the player name. * This is included for backwards compatibility. */ plnamesuffix(); /* Check for a valid role. Try flags.initrole first. */ if (!validrole(flags.initrole)) { /* Try the player letter second */ if ((flags.initrole = str2role(pl_character)) < 0) /* None specified; pick a random role */ flags.initrole = randrole_filtered(); } /* We now have a valid role index. Copy the role name back. */ /* This should become OBSOLETE */ Strcpy(pl_character, roles[flags.initrole].name.m); pl_character[PL_CSIZ - 1] = '\0'; /* Check for a valid race */ if (!validrace(flags.initrole, flags.initrace)) flags.initrace = randrace(flags.initrole); /* Check for a valid gender. If new game, check both initgend * and female. On restore, assume flags.female is correct. */ if (flags.pantheon == -1) { /* new game */ if (!validgend(flags.initrole, flags.initrace, flags.female)) flags.female = !flags.female; } if (!validgend(flags.initrole, flags.initrace, flags.initgend)) /* Note that there is no way to check for an unspecified gender. */ flags.initgend = flags.female; /* Check for a valid alignment */ if (!validalign(flags.initrole, flags.initrace, flags.initalign)) /* Pick a random alignment */ flags.initalign = randalign(flags.initrole, flags.initrace); alignmnt = aligns[flags.initalign].value; /* Initialize urole and urace */ urole = roles[flags.initrole]; urace = races[flags.initrace]; /* Fix up the quest leader */ if (urole.ldrnum != NON_PM) { pm = &mons[urole.ldrnum]; pm->msound = MS_LEADER; pm->mflags2 |= (M2_PEACEFUL); pm->mflags3 |= M3_CLOSE; pm->maligntyp = alignmnt * 3; /* if gender is random, we choose it now instead of waiting until the leader monster is created */ quest_status.ldrgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 : is_male(pm) ? 0 : (rn2(100) < 50); } /* Fix up the quest guardians */ if (urole.guardnum != NON_PM) { pm = &mons[urole.guardnum]; pm->mflags2 |= (M2_PEACEFUL); pm->maligntyp = alignmnt * 3; } /* Fix up the quest nemesis */ if (urole.neminum != NON_PM) { pm = &mons[urole.neminum]; pm->msound = MS_NEMESIS; pm->mflags2 &= ~(M2_PEACEFUL); pm->mflags2 |= (M2_NASTY | M2_STALK | M2_HOSTILE); pm->mflags3 &= ~(M3_CLOSE); pm->mflags3 |= M3_WANTSARTI | M3_WAITFORU; /* if gender is random, we choose it now instead of waiting until the nemesis monster is created */ quest_status.nemgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 : is_male(pm) ? 0 : (rn2(100) < 50); } /* Fix up the god names */ if (flags.pantheon == -1) { /* new game */ flags.pantheon = flags.initrole; /* use own gods */ while (!roles[flags.pantheon].lgod) /* unless they're missing */ flags.pantheon = randrole(); } if (!urole.lgod) { urole.lgod = roles[flags.pantheon].lgod; urole.ngod = roles[flags.pantheon].ngod; urole.cgod = roles[flags.pantheon].cgod; } /* 0 or 1; no gods are neuter, nor is gender randomized */ quest_status.godgend = !strcmpi(align_gtitle(alignmnt), "goddess"); /* Fix up infravision */ if (mons[urace.malenum].mflags3 & M3_INFRAVISION) { /* although an infravision intrinsic is possible, infravision * is purely a property of the physical race. This means that we * must put the infravision flag in the player's current race * (either that or have separate permonst entries for * elven/non-elven members of each class). The side effect is that * all NPCs of that class will have (probably bogus) infravision, * but since infravision has no effect for NPCs anyway we can * ignore this. */ mons[urole.malenum].mflags3 |= M3_INFRAVISION; if (urole.femalenum != NON_PM) mons[urole.femalenum].mflags3 |= M3_INFRAVISION; } /* Artifacts are fixed in hack_artifacts() */ /* Success! */ return; } const char * Hello(mtmp) struct monst *mtmp; { switch (Role_switch) { case PM_KNIGHT: return "Salutations"; /* Olde English */ case PM_SAMURAI: return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER]) ? "Irasshaimase" : "Konnichi wa"; /* Japanese */ case PM_TOURIST: return "Aloha"; /* Hawaiian */ case PM_VALKYRIE: return #ifdef MAIL (mtmp && mtmp->data == &mons[PM_MAIL_DAEMON]) ? "Hallo" : #endif "Velkommen"; /* Norse */ default: return "Hello"; } } const char * Goodbye() { switch (Role_switch) { case PM_KNIGHT: return "Fare thee well"; /* Olde English */ case PM_SAMURAI: return "Sayonara"; /* Japanese */ case PM_TOURIST: return "Aloha"; /* Hawaiian */ case PM_VALKYRIE: return "Farvel"; /* Norse */ default: return "Goodbye"; } } /* role.c */ nethack-3.6.0/src/rumors.c0000664000076400007660000004427712617413107014437 0ustar paxedpaxed/* NetHack 3.6 rumors.c $NHDT-Date: 1446713640 2015/11/05 08:54:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #include "dlb.h" /* [note: this comment is fairly old, but still accurate for 3.1] * Rumors have been entirely rewritten to speed up the access. This is * essential when working from floppies. Using fseek() the way that's done * here means rumors following longer rumors are output more often than those * following shorter rumors. Also, you may see the same rumor more than once * in a particular game (although the odds are highly against it), but * this also happens with real fortune cookies. -dgk */ /* 3.6 * The rumors file consists of a "do not edit" line, then a line containing * three sets of three counts (first two in decimal, third in hexadecimal). * The first set has the number of true rumors, the count in bytes for all * true rumors, and the file offset to the first one. The second set has * the same group of numbers for the false rumors. The third set has 0 for * count, 0 for size, and the file offset for end-of-file. The offset of * the first true rumor plus the size of the true rumors matches the offset * of the first false rumor. Likewise, the offset of the first false rumor * plus the size of the false rumors matches the offset for end-of-file. */ /* 3.1 [now obsolete for rumors but still accurate for oracles] * The rumors file consists of a "do not edit" line, a hexadecimal number * giving the number of bytes of useful/true rumors, followed by those * true rumors (one per line), followed by the useless/false/misleading/cute * rumors (also one per line). Number of bytes of untrue rumors is derived * via fseek(EOF)+ftell(). * * The oracles file consists of a "do not edit" comment, a decimal count N * and set of N+1 hexadecimal fseek offsets, followed by N multiple-line * records, separated by "---" lines. The first oracle is a special case, * and placed there by 'makedefs'. */ STATIC_DCL void FDECL(init_rumors, (dlb *)); STATIC_DCL void FDECL(init_oracles, (dlb *)); /* rumor size variables are signed so that value -1 can be used as a flag */ static long true_rumor_size = 0L, false_rumor_size; /* rumor start offsets are unsigned because they're handled via %lx format */ static unsigned long true_rumor_start, false_rumor_start; /* rumor end offsets are signed because they're compared with [dlb_]ftell() */ static long true_rumor_end, false_rumor_end; /* oracles are handled differently from rumors... */ static int oracle_flg = 0; /* -1=>don't use, 0=>need init, 1=>init done */ static unsigned oracle_cnt = 0; static unsigned long *oracle_loc = 0; STATIC_OVL void init_rumors(fp) dlb *fp; { static const char rumors_header[] = "%d,%ld,%lx;%d,%ld,%lx;0,0,%lx\n"; int true_count, false_count; /* in file but not used here */ unsigned long eof_offset; char line[BUFSZ]; (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment */ (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, rumors_header, &true_count, &true_rumor_size, &true_rumor_start, &false_count, &false_rumor_size, &false_rumor_start, &eof_offset) == 7 && true_rumor_size > 0L && false_rumor_size > 0L) { true_rumor_end = (long) true_rumor_start + true_rumor_size; /* assert( true_rumor_end == false_rumor_start ); */ false_rumor_end = (long) false_rumor_start + false_rumor_size; /* assert( false_rumor_end == eof_offset ); */ } else { true_rumor_size = -1L; /* init failed */ (void) dlb_fclose(fp); } } /* exclude_cookie is a hack used because we sometimes want to get rumors in a * context where messages such as "You swallowed the fortune!" that refer to * cookies should not appear. This has no effect for true rumors since none * of them contain such references anyway. */ char * getrumor(truth, rumor_buf, exclude_cookie) int truth; /* 1=true, -1=false, 0=either */ char *rumor_buf; boolean exclude_cookie; { dlb *rumors; long tidbit, beginning; char *endp, line[BUFSZ], xbuf[BUFSZ]; rumor_buf[0] = '\0'; if (true_rumor_size < 0L) /* we couldn't open RUMORFILE */ return rumor_buf; rumors = dlb_fopen(RUMORFILE, "r"); if (rumors) { int count = 0; int adjtruth; do { rumor_buf[0] = '\0'; if (true_rumor_size == 0L) { /* if this is 1st outrumor() */ init_rumors(rumors); if (true_rumor_size < 0L) { /* init failed */ Sprintf(rumor_buf, "Error reading \"%.80s\".", RUMORFILE); return rumor_buf; } } /* * input: 1 0 -1 * rn2 \ +1 2=T 1=T 0=F * adj./ +0 1=T 0=F -1=F */ switch (adjtruth = truth + rn2(2)) { case 2: /*(might let a bogus input arg sneak thru)*/ case 1: beginning = (long) true_rumor_start; tidbit = Rand() % true_rumor_size; break; case 0: /* once here, 0 => false rather than "either"*/ case -1: beginning = (long) false_rumor_start; tidbit = Rand() % false_rumor_size; break; default: impossible("strange truth value for rumor"); return strcpy(rumor_buf, "Oops..."); } (void) dlb_fseek(rumors, beginning + tidbit, SEEK_SET); (void) dlb_fgets(line, sizeof line, rumors); if (!dlb_fgets(line, sizeof line, rumors) || (adjtruth > 0 && dlb_ftell(rumors) > true_rumor_end)) { /* reached end of rumors -- go back to beginning */ (void) dlb_fseek(rumors, beginning, SEEK_SET); (void) dlb_fgets(line, sizeof line, rumors); } if ((endp = index(line, '\n')) != 0) *endp = 0; Strcat(rumor_buf, xcrypt(line, xbuf)); } while ( count++ < 50 && exclude_cookie && (strstri(rumor_buf, "fortune") || strstri(rumor_buf, "pity"))); (void) dlb_fclose(rumors); if (count >= 50) impossible("Can't find non-cookie rumor?"); else if (!in_mklev) /* avoid exercizing wisdom for graffiti */ exercise(A_WIS, (adjtruth > 0)); } else { pline("Can't open rumors file!"); true_rumor_size = -1; /* don't try to open it again */ } /* this is safe either way, so do it always since we can't get the definition * out of makedefs.c */ #define PAD_RUMORS_TO #ifdef PAD_RUMORS_TO /* remove padding */ { char *x = eos(rumor_buf) - 1; while (x > rumor_buf && *x == '_') x--; *++x = '\n'; *x = '\0'; } #endif return rumor_buf; } /* * test that the true/false rumor boundaries are valid. */ void rumor_check() { dlb *rumors; winid tmpwin; char *endp, line[BUFSZ], xbuf[BUFSZ], rumor_buf[BUFSZ]; if (true_rumor_size < 0L) { /* we couldn't open RUMORFILE */ no_rumors: pline("rumors not accessible."); return; } rumors = dlb_fopen(RUMORFILE, "r"); if (rumors) { long ftell_rumor_start = 0L; rumor_buf[0] = '\0'; if (true_rumor_size == 0L) { /* if this is 1st outrumor() */ init_rumors(rumors); if (true_rumor_size < 0L) goto no_rumors; /* init failed */ } tmpwin = create_nhwindow(NHW_TEXT); /* * reveal the values. */ Sprintf( rumor_buf, "T start=%06ld (%06lx), end=%06ld (%06lx), size=%06ld (%06lx)", (long) true_rumor_start, true_rumor_start, true_rumor_end, (unsigned long) true_rumor_end, true_rumor_size, (unsigned long) true_rumor_size); putstr(tmpwin, 0, rumor_buf); Sprintf( rumor_buf, "F start=%06ld (%06lx), end=%06ld (%06lx), size=%06ld (%06lx)", (long) false_rumor_start, false_rumor_start, false_rumor_end, (unsigned long) false_rumor_end, false_rumor_size, (unsigned long) false_rumor_size); putstr(tmpwin, 0, rumor_buf); /* * check the first rumor (start of true rumors) by * skipping the first two lines. * * Then seek to the start of the false rumors (based on * the value read in rumors, and display it. */ rumor_buf[0] = '\0'; (void) dlb_fseek(rumors, (long) true_rumor_start, SEEK_SET); ftell_rumor_start = dlb_ftell(rumors); (void) dlb_fgets(line, sizeof line, rumors); if ((endp = index(line, '\n')) != 0) *endp = 0; Sprintf(rumor_buf, "T %06ld %s", ftell_rumor_start, xcrypt(line, xbuf)); putstr(tmpwin, 0, rumor_buf); /* find last true rumor */ while (dlb_fgets(line, sizeof line, rumors) && dlb_ftell(rumors) < true_rumor_end) continue; if ((endp = index(line, '\n')) != 0) *endp = 0; Sprintf(rumor_buf, " %6s %s", "", xcrypt(line, xbuf)); putstr(tmpwin, 0, rumor_buf); rumor_buf[0] = '\0'; (void) dlb_fseek(rumors, (long) false_rumor_start, SEEK_SET); ftell_rumor_start = dlb_ftell(rumors); (void) dlb_fgets(line, sizeof line, rumors); if ((endp = index(line, '\n')) != 0) *endp = 0; Sprintf(rumor_buf, "F %06ld %s", ftell_rumor_start, xcrypt(line, xbuf)); putstr(tmpwin, 0, rumor_buf); /* find last false rumor */ while (dlb_fgets(line, sizeof line, rumors) && dlb_ftell(rumors) < false_rumor_end) continue; if ((endp = index(line, '\n')) != 0) *endp = 0; Sprintf(rumor_buf, " %6s %s", "", xcrypt(line, xbuf)); putstr(tmpwin, 0, rumor_buf); (void) dlb_fclose(rumors); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } else { impossible("Can't open rumors file!"); true_rumor_size = -1; /* don't try to open it again */ } } /* Gets a random line of text from file 'fname', and returns it. */ char * get_rnd_text(fname, buf) const char *fname; char *buf; { dlb *fh; buf[0] = '\0'; fh = dlb_fopen(fname, "r"); if (fh) { /* TODO: cache sizetxt, starttxt, endtxt. maybe cache file contents? */ long sizetxt = 0, starttxt = 0, endtxt = 0, tidbit = 0; char *endp, line[BUFSZ], xbuf[BUFSZ]; (void) dlb_fgets(line, sizeof line, fh); /* skip "don't edit" comment */ (void) dlb_fseek(fh, 0L, SEEK_CUR); starttxt = dlb_ftell(fh); (void) dlb_fseek(fh, 0L, SEEK_END); endtxt = dlb_ftell(fh); sizetxt = endtxt - starttxt; tidbit = Rand() % sizetxt; (void) dlb_fseek(fh, starttxt + tidbit, SEEK_SET); (void) dlb_fgets(line, sizeof line, fh); if (!dlb_fgets(line, sizeof line, fh)) { (void) dlb_fseek(fh, starttxt, SEEK_SET); (void) dlb_fgets(line, sizeof line, fh); } if ((endp = index(line, '\n')) != 0) *endp = 0; Strcat(buf, xcrypt(line, xbuf)); (void) dlb_fclose(fh); } else impossible("Can't open file %s!", fname); return buf; } void outrumor(truth, mechanism) int truth; /* 1=true, -1=false, 0=either */ int mechanism; { static const char fortune_msg[] = "This cookie has a scrap of paper inside."; const char *line; char buf[BUFSZ]; boolean reading = (mechanism == BY_COOKIE || mechanism == BY_PAPER); if (reading) { /* deal with various things that prevent reading */ if (is_fainted() && mechanism == BY_COOKIE) return; else if (Blind) { if (mechanism == BY_COOKIE) pline(fortune_msg); pline("What a pity that you cannot read it!"); return; } } line = getrumor(truth, buf, reading ? FALSE : TRUE); if (!*line) line = "NetHack rumors file closed for renovation."; switch (mechanism) { case BY_ORACLE: /* Oracle delivers the rumor */ pline("True to her word, the Oracle %ssays: ", (!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " : (rn2(2) ? "nonchalantly " : "")))); verbalize1(line); /* [WIS exercized by getrumor()] */ return; case BY_COOKIE: pline(fortune_msg); /* FALLTHRU */ case BY_PAPER: pline("It reads:"); break; } pline1(line); } STATIC_OVL void init_oracles(fp) dlb *fp; { register int i; char line[BUFSZ]; int cnt = 0; /* this assumes we're only called once */ (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment*/ (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) { oracle_cnt = (unsigned) cnt; oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long)); for (i = 0; i < cnt; i++) { (void) dlb_fgets(line, sizeof line, fp); (void) sscanf(line, "%5lx\n", &oracle_loc[i]); } } return; } void save_oracles(fd, mode) int fd, mode; { if (perform_bwrite(mode)) { bwrite(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt); if (oracle_cnt) bwrite(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof(long)); } if (release_data(mode)) { if (oracle_cnt) { free((genericptr_t) oracle_loc); oracle_loc = 0, oracle_cnt = 0, oracle_flg = 0; } } } void restore_oracles(fd) int fd; { mread(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt); if (oracle_cnt) { oracle_loc = (unsigned long *) alloc(oracle_cnt * sizeof(long)); mread(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof(long)); oracle_flg = 1; /* no need to call init_oracles() */ } } void outoracle(special, delphi) boolean special; boolean delphi; { char line[COLNO]; char *endp; dlb *oracles; int oracle_idx; char xbuf[BUFSZ]; /* early return if we couldn't open ORACLEFILE on previous attempt, or if all the oracularities are already exhausted */ if (oracle_flg < 0 || (oracle_flg > 0 && oracle_cnt == 0)) return; oracles = dlb_fopen(ORACLEFILE, "r"); if (oracles) { winid tmpwin; if (oracle_flg == 0) { /* if this is the first outoracle() */ init_oracles(oracles); oracle_flg = 1; if (oracle_cnt == 0) return; } /* oracle_loc[0] is the special oracle; oracle_loc[1..oracle_cnt-1] are normal ones */ if (oracle_cnt <= 1 && !special) return; /*(shouldn't happen)*/ oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1); (void) dlb_fseek(oracles, (long) oracle_loc[oracle_idx], SEEK_SET); if (!special) /* move offset of very last one into this slot */ oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt]; tmpwin = create_nhwindow(NHW_TEXT); if (delphi) putstr(tmpwin, 0, special ? "The Oracle scornfully takes all your money and says:" : "The Oracle meditates for a moment and then intones:"); else putstr(tmpwin, 0, "The message reads:"); putstr(tmpwin, 0, ""); while (dlb_fgets(line, COLNO, oracles) && strcmp(line, "---\n")) { if ((endp = index(line, '\n')) != 0) *endp = 0; putstr(tmpwin, 0, xcrypt(line, xbuf)); } display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); (void) dlb_fclose(oracles); } else { pline("Can't open oracles file!"); oracle_flg = -1; /* don't try to open it again */ } } int doconsult(oracl) struct monst *oracl; { long umoney; int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel; int add_xpts; char qbuf[QBUFSZ]; multi = 0; umoney = money_cnt(invent); if (!oracl) { There("is no one here to consult."); return 0; } else if (!oracl->mpeaceful) { pline("%s is in no mood for consultations.", Monnam(oracl)); return 0; } else if (!umoney) { You("have no money."); return 0; } Sprintf(qbuf, "\"Wilt thou settle for a minor consultation?\" (%d %s)", minor_cost, currency((long) minor_cost)); switch (ynq(qbuf)) { default: case 'q': return 0; case 'y': if (umoney < (long) minor_cost) { You("don't even have enough money for that!"); return 0; } u_pay = minor_cost; break; case 'n': if (umoney <= (long) minor_cost /* don't even ask */ || (oracle_cnt == 1 || oracle_flg < 0)) return 0; Sprintf(qbuf, "\"Then dost thou desire a major one?\" (%d %s)", major_cost, currency((long) major_cost)); if (yn(qbuf) != 'y') return 0; u_pay = (umoney < (long) major_cost) ? (int) umoney : major_cost; break; } money2mon(oracl, (long) u_pay); context.botl = 1; add_xpts = 0; /* first oracle of each type gives experience points */ if (u_pay == minor_cost) { outrumor(1, BY_ORACLE); if (!u.uevent.minor_oracle) add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10); /* 5 pts if very 1st, or 2 pts if major already done */ u.uevent.minor_oracle = TRUE; } else { boolean cheapskate = u_pay < major_cost; outoracle(cheapskate, TRUE); if (!cheapskate && !u.uevent.major_oracle) add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10); /* ~100 pts if very 1st, ~40 pts if minor already done */ u.uevent.major_oracle = TRUE; exercise(A_WIS, !cheapskate); } if (add_xpts) { more_experienced(add_xpts, u_pay / 50); newexplevel(); } return 1; } /*rumors.c*/ nethack-3.6.0/src/save.c0000664000076400007660000012374412625266712014052 0ustar paxedpaxed/* NetHack 3.6 save.c $NHDT-Date: 1448241784 2015/11/23 01:23:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.95 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #ifndef NO_SIGNAL #include #endif #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C) #include #endif #ifdef MFLOPPY long bytes_counted; static int count_only; #endif #ifdef MICRO int dotcnt, dotrow; /* also used in restore */ #endif STATIC_DCL void FDECL(savelevchn, (int, int)); STATIC_DCL void FDECL(savedamage, (int, int)); STATIC_DCL void FDECL(saveobj, (int, struct obj *)); STATIC_DCL void FDECL(saveobjchn, (int, struct obj *, int)); STATIC_DCL void FDECL(savemon, (int, struct monst *)); STATIC_DCL void FDECL(savemonchn, (int, struct monst *, int)); STATIC_DCL void FDECL(savetrapchn, (int, struct trap *, int)); STATIC_DCL void FDECL(savegamestate, (int, int)); STATIC_OVL void FDECL(save_msghistory, (int, int)); #ifdef MFLOPPY STATIC_DCL void FDECL(savelev0, (int, XCHAR_P, int)); STATIC_DCL boolean NDECL(swapout_oldest); STATIC_DCL void FDECL(copyfile, (char *, char *)); #endif /* MFLOPPY */ STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P)); STATIC_DCL void FDECL(def_bufon, (int)); STATIC_DCL void FDECL(def_bufoff, (int)); STATIC_DCL void FDECL(def_bflush, (int)); STATIC_DCL void FDECL(def_bwrite, (int, genericptr_t, unsigned int)); #ifdef ZEROCOMP STATIC_DCL void FDECL(zerocomp_bufon, (int)); STATIC_DCL void FDECL(zerocomp_bufoff, (int)); STATIC_DCL void FDECL(zerocomp_bflush, (int)); STATIC_DCL void FDECL(zerocomp_bwrite, (int, genericptr_t, unsigned int)); STATIC_DCL void FDECL(zerocomp_bputc, (int)); #endif static struct save_procs { const char *name; void FDECL((*save_bufon), (int)); void FDECL((*save_bufoff), (int)); void FDECL((*save_bflush), (int)); void FDECL((*save_bwrite), (int, genericptr_t, unsigned int)); void FDECL((*save_bclose), (int)); } saveprocs = { #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP)) "externalcomp", def_bufon, def_bufoff, def_bflush, def_bwrite, def_bclose, #else "zerocomp", zerocomp_bufon, zerocomp_bufoff, zerocomp_bflush, zerocomp_bwrite, zerocomp_bclose, #endif }; static long nulls[sizeof(struct trap) + sizeof(struct fruit)]; #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32) #define HUP if (!program_state.done_hup) #else #define HUP #endif /* need to preserve these during save to avoid accessing freed memory */ static unsigned ustuck_id = 0, usteed_id = 0; int dosave() { clear_nhwindow(WIN_MESSAGE); if (yn("Really save?") == 'n') { clear_nhwindow(WIN_MESSAGE); if (multi > 0) nomul(0); } else { clear_nhwindow(WIN_MESSAGE); pline("Saving..."); #if defined(UNIX) || defined(VMS) || defined(__EMX__) program_state.done_hup = 0; #endif if (dosave0()) { u.uhp = -1; /* universal game's over indicator */ /* make sure they see the Saving message */ display_nhwindow(WIN_MESSAGE, TRUE); exit_nhwindows("Be seeing you..."); terminate(EXIT_SUCCESS); } else (void) doredraw(); } return 0; } /* returns 1 if save successful */ int dosave0() { const char *fq_save; register int fd, ofd; xchar ltmp; d_level uz_save; char whynot[BUFSZ]; /* we may get here via hangup signal, in which case we want to fix up a few of things before saving so that they won't be restored in an improper state; these will be no-ops for normal save sequence */ u.uinvulnerable = 0; if (iflags.save_uinwater) u.uinwater = 1, iflags.save_uinwater = 0; if (iflags.save_uburied) u.uburied = 1, iflags.save_uburied = 0; if (!program_state.something_worth_saving || !SAVEF[0]) return 0; fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */ #if defined(UNIX) || defined(VMS) sethanguphandler((void FDECL((*), (int) )) SIG_IGN); #endif #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #if defined(MICRO) && defined(MFLOPPY) if (!saveDiskPrompt(0)) return 0; #endif HUP if (iflags.window_inited) { nh_uncompress(fq_save); fd = open_savefile(); if (fd > 0) { (void) nhclose(fd); clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (yn("Overwrite the old file?") == 'n') { nh_compress(fq_save); return 0; } } } HUP mark_synch(); /* flush any buffered screen output */ fd = create_savefile(); if (fd < 0) { HUP pline("Cannot open save file."); (void) delete_savefile(); /* ab@unido */ return 0; } vision_recalc(2); /* shut down vision to prevent problems in the event of an impossible() call */ /* undo date-dependent luck adjustments made at startup time */ if (flags.moonphase == FULL_MOON) /* ut-sally!fletcher */ change_luck(-1); /* and unido!ab */ if (flags.friday13) change_luck(1); if (iflags.window_inited) HUP clear_nhwindow(WIN_MESSAGE); #ifdef MICRO dotcnt = 0; dotrow = 2; curs(WIN_MAP, 1, 1); if (strncmpi("X11", windowprocs.name, 3)) putstr(WIN_MAP, 0, "Saving:"); #endif #ifdef MFLOPPY /* make sure there is enough disk space */ if (iflags.checkspace) { long fds, needed; savelev(fd, ledger_no(&u.uz), COUNT_SAVE); savegamestate(fd, COUNT_SAVE); needed = bytes_counted; for (ltmp = 1; ltmp <= maxledgerno(); ltmp++) if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where) needed += level_info[ltmp].size + (sizeof ltmp); fds = freediskspace(fq_save); if (needed > fds) { HUP { There("is insufficient space on SAVE disk."); pline("Require %ld bytes but only have %ld.", needed, fds); } flushout(); (void) nhclose(fd); (void) delete_savefile(); return 0; } co_false(); } #endif /* MFLOPPY */ store_version(fd); store_savefileinfo(fd); store_plname_in_file(fd); ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); usteed_id = (u.usteed ? u.usteed->m_id : 0); savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); savegamestate(fd, WRITE_SAVE | FREE_SAVE); /* While copying level files around, zero out u.uz to keep * parts of the restore code from completely initializing all * in-core data structures, since all we're doing is copying. * This also avoids at least one nasty core dump. */ uz_save = u.uz; u.uz.dnum = u.uz.dlevel = 0; /* these pointers are no longer valid, and at least u.usteed * may mislead place_monster() on other levels */ u.ustuck = (struct monst *) 0; u.usteed = (struct monst *) 0; for (ltmp = (xchar) 1; ltmp <= maxledgerno(); ltmp++) { if (ltmp == ledger_no(&uz_save)) continue; if (!(level_info[ltmp].flags & LFILE_EXISTS)) continue; #ifdef MICRO curs(WIN_MAP, 1 + dotcnt++, dotrow); if (dotcnt >= (COLNO - 1)) { dotrow++; dotcnt = 0; } if (strncmpi("X11", windowprocs.name, 3)) { putstr(WIN_MAP, 0, "."); } mark_synch(); #endif ofd = open_levelfile(ltmp, whynot); if (ofd < 0) { HUP pline1(whynot); (void) nhclose(fd); (void) delete_savefile(); HUP Strcpy(killer.name, whynot); HUP done(TRICKED); return 0; } minit(); /* ZEROCOMP */ getlev(ofd, hackpid, ltmp, FALSE); (void) nhclose(ofd); bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/ savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/ delete_levelfile(ltmp); } bclose(fd); u.uz = uz_save; /* get rid of current level --jgm */ delete_levelfile(ledger_no(&u.uz)); delete_levelfile(0); nh_compress(fq_save); /* this should probably come sooner... */ program_state.something_worth_saving = 0; return 1; } STATIC_OVL void savegamestate(fd, mode) register int fd, mode; { unsigned long uid; #ifdef MFLOPPY count_only = (mode & COUNT_SAVE); #endif uid = (unsigned long) getuid(); bwrite(fd, (genericptr_t) &uid, sizeof uid); bwrite(fd, (genericptr_t) &context, sizeof(struct context_info)); bwrite(fd, (genericptr_t) &flags, sizeof(struct flag)); #ifdef SYSFLAGS bwrite(fd, (genericptr_t) &sysflags, sizeof(struct sysflag)); #endif urealtime.realtime += (long) (getnow() - urealtime.restored); bwrite(fd, (genericptr_t) &u, sizeof(struct you)); bwrite(fd, yyyymmddhhmmss(ubirthday), 14); bwrite(fd, (genericptr_t) &urealtime.realtime, sizeof(urealtime.realtime)); bwrite(fd, yyyymmddhhmmss(urealtime.restored), 14); save_killers(fd, mode); /* must come before migrating_objs and migrating_mons are freed */ save_timers(fd, mode, RANGE_GLOBAL); save_light_sources(fd, mode, RANGE_GLOBAL); saveobjchn(fd, invent, mode); if (BALL_IN_MON) { /* prevent loss of ball & chain when swallowed */ uball->nobj = uchain; uchain->nobj = (struct obj *) 0; saveobjchn(fd, uball, mode); } else { saveobjchn(fd, (struct obj *) 0, mode); } saveobjchn(fd, migrating_objs, mode); savemonchn(fd, migrating_mons, mode); if (release_data(mode)) { invent = 0; migrating_objs = 0; migrating_mons = 0; } bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals)); save_dungeon(fd, (boolean) !!perform_bwrite(mode), (boolean) !!release_data(mode)); savelevchn(fd, mode); bwrite(fd, (genericptr_t) &moves, sizeof moves); bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves); bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); bwrite(fd, (genericptr_t) spl_book, sizeof(struct spell) * (MAXSPELL + 1)); save_artifacts(fd); save_oracles(fd, mode); if (ustuck_id) bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id); if (usteed_id) bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id); bwrite(fd, (genericptr_t) pl_character, sizeof pl_character); bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); savefruitchn(fd, mode); savenames(fd, mode); save_waterlevel(fd, mode); save_msghistory(fd, mode); bflush(fd); } boolean tricked_fileremoved(fd, whynot) int fd; char *whynot; { if (fd < 0) { pline1(whynot); pline("Probably someone removed it."); Strcpy(killer.name, whynot); done(TRICKED); return TRUE; } return FALSE; } #ifdef INSURANCE void savestateinlock() { int fd, hpid; static boolean havestate = TRUE; char whynot[BUFSZ]; /* When checkpointing is on, the full state needs to be written * on each checkpoint. When checkpointing is off, only the pid * needs to be in the level.0 file, so it does not need to be * constantly rewritten. When checkpointing is turned off during * a game, however, the file has to be rewritten once to truncate * it and avoid restoring from outdated information. * * Restricting havestate to this routine means that an additional * noop pid rewriting will take place on the first "checkpoint" after * the game is started or restored, if checkpointing is off. */ if (flags.ins_chkpt || havestate) { /* save the rest of the current game state in the lock file, * following the original int pid, the current level number, * and the current savefile name, which should not be subject * to any internal compression schemes since they must be * readable by an external utility */ fd = open_levelfile(0, whynot); if (tricked_fileremoved(fd, whynot)) return; (void) read(fd, (genericptr_t) &hpid, sizeof(hpid)); if (hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", hpid, hackpid); pline1(whynot); Strcpy(killer.name, whynot); done(TRICKED); } (void) nhclose(fd); fd = create_levelfile(0, whynot); if (fd < 0) { pline1(whynot); Strcpy(killer.name, whynot); done(TRICKED); return; } (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); if (flags.ins_chkpt) { int currlev = ledger_no(&u.uz); (void) write(fd, (genericptr_t) &currlev, sizeof(currlev)); save_savefile_name(fd); store_version(fd); store_savefileinfo(fd); store_plname_in_file(fd); ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); usteed_id = (u.usteed ? u.usteed->m_id : 0); savegamestate(fd, WRITE_SAVE); } bclose(fd); } havestate = flags.ins_chkpt; } #endif #ifdef MFLOPPY boolean savelev(fd, lev, mode) int fd; xchar lev; int mode; { if (mode & COUNT_SAVE) { bytes_counted = 0; savelev0(fd, lev, COUNT_SAVE); /* probably bytes_counted will be filled in again by an * immediately following WRITE_SAVE anyway, but we'll * leave it out of checkspace just in case */ if (iflags.checkspace) { while (bytes_counted > freediskspace(levels)) if (!swapout_oldest()) return FALSE; } } if (mode & (WRITE_SAVE | FREE_SAVE)) { bytes_counted = 0; savelev0(fd, lev, mode); } if (mode != FREE_SAVE) { level_info[lev].where = ACTIVE; level_info[lev].time = moves; level_info[lev].size = bytes_counted; } return TRUE; } STATIC_OVL void savelev0(fd, lev, mode) #else void savelev(fd, lev, mode) #endif int fd; xchar lev; int mode; { #ifdef TOS short tlev; #endif /* if we're tearing down the current level without saving anything (which happens upon entrance to the endgame or after an aborted restore attempt) then we don't want to do any actual I/O */ if (mode == FREE_SAVE) goto skip_lots; /* purge any dead monsters (necessary if we're starting a panic save rather than a normal one, or sometimes when changing levels without taking time -- e.g. create statue trap then immediately level teleport) */ if (iflags.purge_monsters) dmonsfree(); if (fd < 0) panic("Save on bad file!"); /* impossible */ #ifdef MFLOPPY count_only = (mode & COUNT_SAVE); #endif if (lev >= 0 && lev <= maxledgerno()) level_info[lev].flags |= VISITED; bwrite(fd, (genericptr_t) &hackpid, sizeof(hackpid)); #ifdef TOS tlev = lev; tlev &= 0x00ff; bwrite(fd, (genericptr_t) &tlev, sizeof(tlev)); #else bwrite(fd, (genericptr_t) &lev, sizeof(lev)); #endif savecemetery(fd, mode, &level.bonesinfo); savelevl(fd, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); bwrite(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp)); bwrite(fd, (genericptr_t) &monstermoves, sizeof(monstermoves)); bwrite(fd, (genericptr_t) &upstair, sizeof(stairway)); bwrite(fd, (genericptr_t) &dnstair, sizeof(stairway)); bwrite(fd, (genericptr_t) &upladder, sizeof(stairway)); bwrite(fd, (genericptr_t) &dnladder, sizeof(stairway)); bwrite(fd, (genericptr_t) &sstairs, sizeof(stairway)); bwrite(fd, (genericptr_t) &updest, sizeof(dest_area)); bwrite(fd, (genericptr_t) &dndest, sizeof(dest_area)); bwrite(fd, (genericptr_t) &level.flags, sizeof(level.flags)); bwrite(fd, (genericptr_t) doors, sizeof(doors)); save_rooms(fd); /* no dynamic memory to reclaim */ /* from here on out, saving also involves allocated memory cleanup */ skip_lots: /* this comes before the map, so need cleanup here if we skipped */ if (mode == FREE_SAVE) savecemetery(fd, mode, &level.bonesinfo); /* must be saved before mons, objs, and buried objs */ save_timers(fd, mode, RANGE_LEVEL); save_light_sources(fd, mode, RANGE_LEVEL); savemonchn(fd, fmon, mode); save_worm(fd, mode); /* save worm information */ savetrapchn(fd, ftrap, mode); saveobjchn(fd, fobj, mode); saveobjchn(fd, level.buriedobjlist, mode); saveobjchn(fd, billobjs, mode); if (release_data(mode)) { fmon = 0; ftrap = 0; fobj = 0; level.buriedobjlist = 0; billobjs = 0; /* level.bonesinfo = 0; -- handled by savecemetery() */ } save_engravings(fd, mode); savedamage(fd, mode); save_regions(fd, mode); if (mode != FREE_SAVE) bflush(fd); } STATIC_OVL void savelevl(fd, rlecomp) int fd; boolean rlecomp; { #ifdef RLECOMP struct rm *prm, *rgrm; int x, y; uchar match; if (rlecomp) { /* perform run-length encoding of rm structs */ rgrm = &levl[0][0]; /* start matching at first rm */ match = 0; for (y = 0; y < ROWNO; y++) { for (x = 0; x < COLNO; x++) { prm = &levl[x][y]; if (prm->glyph == rgrm->glyph && prm->typ == rgrm->typ && prm->seenv == rgrm->seenv && prm->horizontal == rgrm->horizontal && prm->flags == rgrm->flags && prm->lit == rgrm->lit && prm->waslit == rgrm->waslit && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge && prm->candig == rgrm->candig) { match++; if (match > 254) { match = 254; /* undo this match */ goto writeout; } } else { /* the run has been broken, * write out run-length encoding */ writeout: bwrite(fd, (genericptr_t) &match, sizeof(uchar)); bwrite(fd, (genericptr_t) rgrm, sizeof(struct rm)); /* start encoding again. we have at least 1 rm * in the next run, viz. this one. */ match = 1; rgrm = prm; } } } if (match > 0) { bwrite(fd, (genericptr_t) &match, sizeof(uchar)); bwrite(fd, (genericptr_t) rgrm, sizeof(struct rm)); } return; } #else /* !RLECOMP */ nhUse(rlecomp); #endif /* ?RLECOMP */ bwrite(fd, (genericptr_t) levl, sizeof levl); } /*ARGSUSED*/ void bufon(fd) int fd; { (*saveprocs.save_bufon)(fd); return; } /*ARGSUSED*/ void bufoff(fd) int fd; { (*saveprocs.save_bufoff)(fd); return; } /* flush run and buffer */ void bflush(fd) register int fd; { (*saveprocs.save_bflush)(fd); return; } void bwrite(fd, loc, num) int fd; genericptr_t loc; register unsigned num; { (*saveprocs.save_bwrite)(fd, loc, num); return; } void bclose(fd) int fd; { (*saveprocs.save_bclose)(fd); return; } static int bw_fd = -1; static FILE *bw_FILE = 0; static boolean buffering = FALSE; STATIC_OVL void def_bufon(fd) int fd; { #ifdef UNIX if (bw_fd != fd) { if (bw_fd >= 0) panic("double buffering unexpected"); bw_fd = fd; if ((bw_FILE = fdopen(fd, "w")) == 0) panic("buffering of file %d failed", fd); } #endif buffering = TRUE; } STATIC_OVL void def_bufoff(fd) int fd; { def_bflush(fd); buffering = FALSE; } STATIC_OVL void def_bflush(fd) int fd; { #ifdef UNIX if (fd == bw_fd) { if (fflush(bw_FILE) == EOF) panic("flush of savefile failed!"); } #endif return; } STATIC_OVL void def_bwrite(fd, loc, num) register int fd; register genericptr_t loc; register unsigned num; { boolean failed; #ifdef MFLOPPY bytes_counted += num; if (count_only) return; #endif #ifdef UNIX if (buffering) { if (fd != bw_fd) panic("unbuffered write to fd %d (!= %d)", fd, bw_fd); failed = (fwrite(loc, (int) num, 1, bw_FILE) != 1); } else #endif /* UNIX */ { /* lint wants 3rd arg of write to be an int; lint -p an unsigned */ #if defined(BSD) || defined(ULTRIX) || defined(WIN32) || defined(_MSC_VER) failed = ((long) write(fd, loc, (int) num) != (long) num); #else /* e.g. SYSV, __TURBOC__ */ failed = ((long) write(fd, loc, num) != (long) num); #endif } if (failed) { #if defined(UNIX) || defined(VMS) || defined(__EMX__) if (program_state.done_hup) terminate(EXIT_FAILURE); else #endif panic("cannot write %u bytes to file #%d", num, fd); } } void def_bclose(fd) int fd; { bufoff(fd); #ifdef UNIX if (fd == bw_fd) { (void) fclose(bw_FILE); bw_fd = -1; bw_FILE = 0; } else #endif (void) nhclose(fd); return; } #ifdef ZEROCOMP /* The runs of zero-run compression are flushed after the game state or a * level is written out. This adds a couple bytes to a save file, where * the runs could be mashed together, but it allows gluing together game * state and level files to form a save file, and it means the flushing * does not need to be specifically called for every other time a level * file is written out. */ #define RLESC '\0' /* Leading character for run of LRESC's */ #define flushoutrun(ln) (zerocomp_bputc(RLESC), zerocomp_bputc(ln), ln = -1) #ifndef ZEROCOMP_BUFSIZ #define ZEROCOMP_BUFSIZ BUFSZ #endif static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ]; static NEARDATA unsigned short outbufp = 0; static NEARDATA short outrunlength = -1; static NEARDATA int bwritefd; static NEARDATA boolean compressing = FALSE; /*dbg() { HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength); }*/ STATIC_OVL void zerocomp_bputc(c) int c; { #ifdef MFLOPPY bytes_counted++; if (count_only) return; #endif if (outbufp >= sizeof outbuf) { (void) write(bwritefd, outbuf, sizeof outbuf); outbufp = 0; } outbuf[outbufp++] = (unsigned char) c; } /*ARGSUSED*/ void STATIC_OVL zerocomp_bufon(fd) int fd; { compressing = TRUE; return; } /*ARGSUSED*/ STATIC_OVL void zerocomp_bufoff(fd) int fd; { if (outbufp) { outbufp = 0; panic("closing file with buffered data still unwritten"); } outrunlength = -1; compressing = FALSE; return; } /* flush run and buffer */ STATIC_OVL void zerocomp_bflush(fd) register int fd; { bwritefd = fd; if (outrunlength >= 0) { /* flush run */ flushoutrun(outrunlength); } #ifdef MFLOPPY if (count_only) outbufp = 0; #endif if (outbufp) { if (write(fd, outbuf, outbufp) != outbufp) { #if defined(UNIX) || defined(VMS) || defined(__EMX__) if (program_state.done_hup) terminate(EXIT_FAILURE); else #endif zerocomp_bclose(fd); /* panic (outbufp != 0) */ } outbufp = 0; } } STATIC_OVL void zerocomp_bwrite(fd, loc, num) int fd; genericptr_t loc; register unsigned num; { register unsigned char *bp = (unsigned char *) loc; if (!compressing) { #ifdef MFLOPPY bytes_counted += num; if (count_only) return; #endif if ((unsigned) write(fd, loc, num) != num) { #if defined(UNIX) || defined(VMS) || defined(__EMX__) if (program_state.done_hup) terminate(EXIT_FAILURE); else #endif panic("cannot write %u bytes to file #%d", num, fd); } } else { bwritefd = fd; for (; num; num--, bp++) { if (*bp == RLESC) { /* One more char in run */ if (++outrunlength == 0xFF) { flushoutrun(outrunlength); } } else { /* end of run */ if (outrunlength >= 0) { /* flush run */ flushoutrun(outrunlength); } zerocomp_bputc(*bp); } } } } void zerocomp_bclose(fd) int fd; { zerocomp_bufoff(fd); (void) nhclose(fd); return; } #endif /* ZEROCOMP */ STATIC_OVL void savelevchn(fd, mode) register int fd, mode; { s_level *tmplev, *tmplev2; int cnt = 0; for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &cnt, sizeof(int)); for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) { tmplev2 = tmplev->next; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) tmplev, sizeof(s_level)); if (release_data(mode)) free((genericptr_t) tmplev); } if (release_data(mode)) sp_levchn = 0; } /* used when saving a level and also when saving dungeon overview data */ void savecemetery(fd, mode, cemeteryaddr) int fd; int mode; struct cemetery **cemeteryaddr; { struct cemetery *thisbones, *nextbones; int flag; flag = *cemeteryaddr ? 0 : -1; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &flag, sizeof flag); nextbones = *cemeteryaddr; while ((thisbones = nextbones) != 0) { nextbones = thisbones->next; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) thisbones, sizeof *thisbones); if (release_data(mode)) free((genericptr_t) thisbones); } if (release_data(mode)) *cemeteryaddr = 0; } STATIC_OVL void savedamage(fd, mode) register int fd, mode; { register struct damage *damageptr, *tmp_dam; unsigned int xl = 0; damageptr = level.damagelist; for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) xl++; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &xl, sizeof(xl)); while (xl--) { if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr)); tmp_dam = damageptr; damageptr = damageptr->next; if (release_data(mode)) free((genericptr_t) tmp_dam); } if (release_data(mode)) level.damagelist = 0; } STATIC_OVL void saveobj(fd, otmp) int fd; struct obj *otmp; { int buflen, zerobuf = 0; buflen = sizeof(struct obj); bwrite(fd, (genericptr_t) &buflen, sizeof(int)); bwrite(fd, (genericptr_t) otmp, buflen); if (otmp->oextra) { if (ONAME(otmp)) buflen = strlen(ONAME(otmp)) + 1; else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof buflen); if (buflen > 0) bwrite(fd, (genericptr_t) ONAME(otmp), buflen); /* defer to savemon() for this one */ if (OMONST(otmp)) savemon(fd, OMONST(otmp)); else bwrite(fd, (genericptr_t) &zerobuf, sizeof zerobuf); if (OMID(otmp)) buflen = sizeof(unsigned); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof buflen); if (buflen > 0) bwrite(fd, (genericptr_t) OMID(otmp), buflen); if (OLONG(otmp)) buflen = sizeof(long); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof buflen); if (buflen > 0) bwrite(fd, (genericptr_t) OLONG(otmp), buflen); if (OMAILCMD(otmp)) buflen = strlen(OMAILCMD(otmp)) + 1; else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof buflen); if (buflen > 0) bwrite(fd, (genericptr_t) OMAILCMD(otmp), buflen); } } STATIC_OVL void saveobjchn(fd, otmp, mode) register int fd, mode; register struct obj *otmp; { register struct obj *otmp2; int minusone = -1; while (otmp) { otmp2 = otmp->nobj; if (perform_bwrite(mode)) { saveobj(fd, otmp); } if (Has_contents(otmp)) saveobjchn(fd, otmp->cobj, mode); if (release_data(mode)) { /* if (otmp->oclass == FOOD_CLASS) * food_disappears(otmp); */ /* * If these are on the floor, the discarding could * be because of a game save, or we could just be changing levels. * Always invalidate the pointer, but ensure that we have * the o_id in order to restore the pointer on reload. */ if (otmp == context.victual.piece) { /* Store the o_id of the victual if mismatched */ if (context.victual.o_id != otmp->o_id) context.victual.o_id = otmp->o_id; /* invalidate the pointer; on reload it will get restored */ context.victual.piece = (struct obj *) 0; } if (otmp == context.tin.tin) { /* Store the o_id of your tin */ if (context.tin.o_id != otmp->o_id) context.tin.o_id = otmp->o_id; /* invalidate the pointer; on reload it will get restored */ context.tin.tin = (struct obj *) 0; } /* if (otmp->oclass == SPBOOK_CLASS) * book_disappears(otmp); */ if (otmp == context.spbook.book) { /* Store the o_id of your spellbook */ if (context.spbook.o_id != otmp->o_id) context.spbook.o_id = otmp->o_id; /* invalidate the pointer; on reload it will get restored */ context.spbook.book = (struct obj *) 0; } otmp->where = OBJ_FREE; /* set to free so dealloc will work */ otmp->nobj = NULL; /* nobj saved into otmp2 */ otmp->cobj = NULL; /* contents handled above */ otmp->timed = 0; /* not timed any more */ otmp->lamplit = 0; /* caller handled lights */ dealloc_obj(otmp); } otmp = otmp2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &minusone, sizeof(int)); } STATIC_OVL void savemon(fd, mtmp) int fd; struct monst *mtmp; { int buflen; buflen = sizeof(struct monst); bwrite(fd, (genericptr_t) &buflen, sizeof(int)); bwrite(fd, (genericptr_t) mtmp, buflen); if (mtmp->mextra) { if (MNAME(mtmp)) buflen = strlen(MNAME(mtmp)) + 1; else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof buflen); if (buflen > 0) bwrite(fd, (genericptr_t) MNAME(mtmp), buflen); if (EGD(mtmp)) buflen = sizeof(struct egd); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof(int)); if (buflen > 0) bwrite(fd, (genericptr_t) EGD(mtmp), buflen); if (EPRI(mtmp)) buflen = sizeof(struct epri); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof(int)); if (buflen > 0) bwrite(fd, (genericptr_t) EPRI(mtmp), buflen); if (ESHK(mtmp)) buflen = sizeof(struct eshk); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof(int)); if (buflen > 0) bwrite(fd, (genericptr_t) ESHK(mtmp), buflen); if (EMIN(mtmp)) buflen = sizeof(struct emin); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof(int)); if (buflen > 0) bwrite(fd, (genericptr_t) EMIN(mtmp), buflen); if (EDOG(mtmp)) buflen = sizeof(struct edog); else buflen = 0; bwrite(fd, (genericptr_t) &buflen, sizeof(int)); if (buflen > 0) bwrite(fd, (genericptr_t) EDOG(mtmp), buflen); /* mcorpsenm is inline int rather than pointer to something, so doesn't need to be preceded by a length field */ bwrite(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp)); } } STATIC_OVL void savemonchn(fd, mtmp, mode) register int fd, mode; register struct monst *mtmp; { register struct monst *mtmp2; int minusone = -1; while (mtmp) { mtmp2 = mtmp->nmon; if (perform_bwrite(mode)) { mtmp->mnum = monsndx(mtmp->data); if (mtmp->ispriest) forget_temple_entry(mtmp); /* EPRI() */ savemon(fd, mtmp); } if (mtmp->minvent) saveobjchn(fd, mtmp->minvent, mode); if (release_data(mode)) { if (mtmp == context.polearm.hitmon) { context.polearm.m_id = mtmp->m_id; context.polearm.hitmon = NULL; } mtmp->nmon = NULL; /* nmon saved into mtmp2 */ dealloc_monst(mtmp); } mtmp = mtmp2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &minusone, sizeof(int)); } STATIC_OVL void savetrapchn(fd, trap, mode) register int fd, mode; register struct trap *trap; { register struct trap *trap2; while (trap) { trap2 = trap->ntrap; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) trap, sizeof(struct trap)); if (release_data(mode)) dealloc_trap(trap); trap = trap2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) nulls, sizeof(struct trap)); } /* save all the fruit names and ID's; this is used only in saving whole games * (not levels) and in saving bones levels. When saving a bones level, * we only want to save the fruits which exist on the bones level; the bones * level routine marks nonexistent fruits by making the fid negative. */ void savefruitchn(fd, mode) register int fd, mode; { register struct fruit *f2, *f1; f1 = ffruit; while (f1) { f2 = f1->nextf; if (f1->fid >= 0 && perform_bwrite(mode)) bwrite(fd, (genericptr_t) f1, sizeof(struct fruit)); if (release_data(mode)) dealloc_fruit(f1); f1 = f2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) nulls, sizeof(struct fruit)); if (release_data(mode)) ffruit = 0; } void store_plname_in_file(fd) int fd; { int plsiztmp = PL_NSIZ; bufoff(fd); /* bwrite() before bufon() uses plain write() */ bwrite(fd, (genericptr_t) &plsiztmp, sizeof(plsiztmp)); bwrite(fd, (genericptr_t) plname, plsiztmp); bufon(fd); return; } STATIC_OVL void save_msghistory(fd, mode) int fd, mode; { char *msg; int msgcount = 0, msglen; int minusone = -1; boolean init = TRUE; if (perform_bwrite(mode)) { /* ask window port for each message in sequence */ while ((msg = getmsghistory(init)) != 0) { init = FALSE; msglen = strlen(msg); /* sanity: truncate if necessary (shouldn't happen); no need to modify msg[] since terminator isn't written */ if (msglen > BUFSZ - 1) msglen = BUFSZ - 1; bwrite(fd, (genericptr_t) &msglen, sizeof(msglen)); bwrite(fd, (genericptr_t) msg, msglen); ++msgcount; } bwrite(fd, (genericptr_t) &minusone, sizeof(int)); } debugpline1("Stored %d messages into savefile.", msgcount); /* note: we don't attempt to handle release_data() here */ } void store_savefileinfo(fd) int fd; { /* sfcap (decl.c) describes the savefile feature capabilities * that are supported by this port/platform build. * * sfsaveinfo (decl.c) describes the savefile info that actually * gets written into the savefile, and is used to determine the * save file being written. * sfrestinfo (decl.c) describes the savefile info that is * being used to read the information from an existing savefile. * */ bufoff(fd); /* bwrite() before bufon() uses plain write() */ bwrite(fd, (genericptr_t) &sfsaveinfo, (unsigned) (sizeof sfsaveinfo)); bufon(fd); return; } void set_savepref(suitename) const char *suitename; { if (!strcmpi(suitename, "externalcomp")) { saveprocs.name = "externalcomp"; saveprocs.save_bufon = def_bufon; saveprocs.save_bufoff = def_bufoff; saveprocs.save_bflush = def_bflush; saveprocs.save_bwrite = def_bwrite; saveprocs.save_bclose = def_bclose; sfsaveinfo.sfi1 |= SFI1_EXTERNALCOMP; sfsaveinfo.sfi1 &= ~SFI1_ZEROCOMP; } if (!strcmpi(suitename, "!rlecomp")) { sfsaveinfo.sfi1 &= ~SFI1_RLECOMP; } #ifdef ZEROCOMP if (!strcmpi(suitename, "zerocomp")) { saveprocs.name = "zerocomp"; saveprocs.save_bufon = zerocomp_bufon; saveprocs.save_bufoff = zerocomp_bufoff; saveprocs.save_bflush = zerocomp_bflush; saveprocs.save_bwrite = zerocomp_bwrite; saveprocs.save_bclose = zerocomp_bclose; sfsaveinfo.sfi1 |= SFI1_ZEROCOMP; sfsaveinfo.sfi1 &= ~SFI1_EXTERNALCOMP; } #endif #ifdef RLECOMP if (!strcmpi(suitename, "rlecomp")) { sfsaveinfo.sfi1 |= SFI1_RLECOMP; } #endif } /* also called by prscore(); this probably belongs in dungeon.c... */ void free_dungeons() { #ifdef FREE_ALL_MEMORY savelevchn(0, FREE_SAVE); save_dungeon(0, FALSE, TRUE); #endif return; } void freedynamicdata() { unload_qtlist(); free_menu_coloring(); free_invbuf(); /* let_to_name (invent.c) */ free_youbuf(); /* You_buf,&c (pline.c) */ msgtype_free(); tmp_at(DISP_FREEMEM, 0); /* temporary display effects */ #ifdef FREE_ALL_MEMORY #define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0) #define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0) #define freetrapchn(X) (savetrapchn(0, X, FREE_SAVE), X = 0) #define freefruitchn() savefruitchn(0, FREE_SAVE) #define freenames() savenames(0, FREE_SAVE) #define free_killers() save_killers(0, FREE_SAVE) #define free_oracles() save_oracles(0, FREE_SAVE) #define free_waterlevel() save_waterlevel(0, FREE_SAVE) #define free_worm() save_worm(0, FREE_SAVE) #define free_timers(R) save_timers(0, FREE_SAVE, R) #define free_light_sources(R) save_light_sources(0, FREE_SAVE, R); #define free_engravings() save_engravings(0, FREE_SAVE) #define freedamage() savedamage(0, FREE_SAVE) #define free_animals() mon_animal_list(FALSE) /* move-specific data */ dmonsfree(); /* release dead monsters */ /* level-specific data */ free_timers(RANGE_LEVEL); free_light_sources(RANGE_LEVEL); clear_regions(); freemonchn(fmon); free_worm(); /* release worm segment information */ freetrapchn(ftrap); freeobjchn(fobj); freeobjchn(level.buriedobjlist); freeobjchn(billobjs); free_engravings(); freedamage(); /* game-state data */ free_killers(); free_timers(RANGE_GLOBAL); free_light_sources(RANGE_GLOBAL); freeobjchn(invent); freeobjchn(migrating_objs); freemonchn(migrating_mons); freemonchn(mydogs); /* ascension or dungeon escape */ /* freelevchn(); -- [folded into free_dungeons()] */ free_animals(); free_oracles(); freefruitchn(); freenames(); free_waterlevel(); free_dungeons(); /* some pointers in iflags */ if (iflags.wc_font_map) free(iflags.wc_font_map); if (iflags.wc_font_message) free(iflags.wc_font_message); if (iflags.wc_font_text) free(iflags.wc_font_text); if (iflags.wc_font_menu) free(iflags.wc_font_menu); if (iflags.wc_font_status) free(iflags.wc_font_status); if (iflags.wc_tile_file) free(iflags.wc_tile_file); free_autopickup_exceptions(); /* miscellaneous */ /* free_pickinv_cache(); -- now done from really_done()... */ free_symsets(); #endif /* FREE_ALL_MEMORY */ #ifdef STATUS_VIA_WINDOWPORT status_finish(); #endif /* last, because it frees data that might be used by panic() to provide feedback to the user; conceivably other freeing might trigger panic */ sysopt_release(); /* SYSCF strings */ return; } #ifdef MFLOPPY boolean swapin_file(lev) int lev; { char to[PATHLEN], from[PATHLEN]; Sprintf(from, "%s%s", permbones, alllevels); Sprintf(to, "%s%s", levels, alllevels); set_levelfile_name(from, lev); set_levelfile_name(to, lev); if (iflags.checkspace) { while (level_info[lev].size > freediskspace(to)) if (!swapout_oldest()) return FALSE; } if (wizard) { pline("Swapping in `%s'.", from); wait_synch(); } copyfile(from, to); (void) unlink(from); level_info[lev].where = ACTIVE; return TRUE; } STATIC_OVL boolean swapout_oldest() { char to[PATHLEN], from[PATHLEN]; int i, oldest; long oldtime; if (!ramdisk) return FALSE; for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++) if (level_info[i].where == ACTIVE && (!oldtime || level_info[i].time < oldtime)) { oldest = i; oldtime = level_info[i].time; } if (!oldest) return FALSE; Sprintf(from, "%s%s", levels, alllevels); Sprintf(to, "%s%s", permbones, alllevels); set_levelfile_name(from, oldest); set_levelfile_name(to, oldest); if (wizard) { pline("Swapping out `%s'.", from); wait_synch(); } copyfile(from, to); (void) unlink(from); level_info[oldest].where = SWAPPED; return TRUE; } STATIC_OVL void copyfile(from, to) char *from, *to; { #ifdef TOS if (_copyfile(from, to)) panic("Can't copy %s to %s", from, to); #else char buf[BUFSIZ]; /* this is system interaction, therefore * BUFSIZ instead of NetHack's BUFSZ */ int nfrom, nto, fdfrom, fdto; if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0) panic("Can't copy from %s !?", from); if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0) panic("Can't copy to %s", to); do { nfrom = read(fdfrom, buf, BUFSIZ); nto = write(fdto, buf, nfrom); if (nto != nfrom) panic("Copyfile failed!"); } while (nfrom == BUFSIZ); (void) nhclose(fdfrom); (void) nhclose(fdto); #endif /* TOS */ } /* see comment in bones.c */ void co_false() { count_only = FALSE; return; } #endif /* MFLOPPY */ /*save.c*/ nethack-3.6.0/src/shk.c0000664000076400007660000042423712617413107013673 0ustar paxedpaxed/* NetHack 3.6 shk.c $NHDT-Date: 1446854234 2015/11/06 23:57:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #define PAY_SOME 2 #define PAY_BUY 1 #define PAY_CANT 0 /* too poor */ #define PAY_SKIP (-1) #define PAY_BROKE (-2) STATIC_DCL void FDECL(makekops, (coord *)); STATIC_DCL void FDECL(call_kops, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P)); #define NOTANGRY(mon) ((mon)->mpeaceful) #define ANGRY(mon) (!NOTANGRY(mon)) #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE) #define muteshk(shkp) \ ((shkp)->msleeping || !(shkp)->mcanmove \ || (shkp)->data->msound <= MS_ANIMAL) extern const struct shclass shtypes[]; /* defined in shknam.c */ STATIC_VAR NEARDATA long int followmsg; /* last time of follow message */ STATIC_VAR const char and_its_contents[] = " and its contents"; STATIC_VAR const char the_contents_of[] = "the contents of "; STATIC_DCL void FDECL(append_honorific, (char *)); STATIC_DCL void FDECL(setpaid, (struct monst *)); STATIC_DCL long FDECL(addupbill, (struct monst *)); STATIC_DCL void FDECL(pacify_shk, (struct monst *)); STATIC_DCL struct bill_x *FDECL(onbill, (struct obj *, struct monst *, BOOLEAN_P)); STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P)); STATIC_DCL long FDECL(shop_debt, (struct eshk *)); STATIC_DCL char *FDECL(shk_owns, (char *, struct obj *)); STATIC_DCL char *FDECL(mon_owns, (char *, struct obj *)); STATIC_DCL void FDECL(clear_unpaid, (struct obj *)); STATIC_DCL long FDECL(check_credit, (long, struct monst *)); STATIC_DCL void FDECL(pay, (long, struct monst *)); STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *)); STATIC_DCL long FDECL(set_cost, (struct obj *, struct monst *)); STATIC_DCL const char *FDECL(shk_embellish, (struct obj *, long)); STATIC_DCL long FDECL(cost_per_charge, (struct monst *, struct obj *, BOOLEAN_P)); STATIC_DCL long FDECL(cheapest_item, (struct monst *)); STATIC_DCL int FDECL(dopayobj, (struct monst *, struct bill_x *, struct obj **, int, BOOLEAN_P)); STATIC_DCL long FDECL(stolen_container, (struct obj *, struct monst *, long, BOOLEAN_P)); STATIC_DCL long FDECL(getprice, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(shk_names_obj, (struct monst *, struct obj *, const char *, long, const char *)); STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *)); STATIC_DCL boolean FDECL(inherits, (struct monst *, int, int)); STATIC_DCL void FDECL(set_repo_loc, (struct monst *)); STATIC_DCL boolean NDECL(angry_shk_exists); STATIC_DCL void FDECL(rile_shk, (struct monst *)); STATIC_DCL void FDECL(rouse_shk, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(remove_damage, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(sub_one_frombill, (struct obj *, struct monst *)); STATIC_DCL void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P, struct monst *)); STATIC_DCL void FDECL(dropped_container, (struct obj *, struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(add_to_billobjs, (struct obj *)); STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P, struct monst *)); STATIC_DCL boolean FDECL(rob_shop, (struct monst *)); STATIC_DCL void FDECL(deserted_shop, (char *)); STATIC_DCL boolean FDECL(special_stock, (struct obj *, struct monst *, BOOLEAN_P)); STATIC_DCL const char *FDECL(cad, (BOOLEAN_P)); /* invariants: obj->unpaid iff onbill(obj) [unless bp->useup] obj->quan <= bp->bquan */ /* * Transfer money from inventory to monster when paying * shopkeepers, priests, oracle, succubus, and other demons. * Simple with only gold coins. * This routine will handle money changing when multiple * coin types is implemented, only appropriate * monsters will pay change. (Peaceful shopkeepers, priests * and the oracle try to maintain goodwill while selling * their wares or services. Angry monsters and all demons * will keep anything they get their hands on. * Returns the amount actually paid, so we can know * if the monster kept the change. */ long money2mon(mon, amount) struct monst *mon; long amount; { struct obj *ygold = findgold(invent); if (amount <= 0) { impossible("%s payment in money2mon!", amount ? "negative" : "zero"); return 0L; } if (!ygold || ygold->quan < amount) { impossible("Paying without %s money?", ygold ? "enough" : ""); return 0L; } if (ygold->quan > amount) ygold = splitobj(ygold, amount); else if (ygold->owornmask) remove_worn_item(ygold, FALSE); /* quiver */ freeinv(ygold); add_to_minv(mon, ygold); context.botl = 1; return amount; } /* * Transfer money from monster to inventory. * Used when the shopkeeper pay for items, and when * the priest gives you money for an ale. */ void money2u(mon, amount) struct monst *mon; long amount; { struct obj *mongold = findgold(mon->minvent); if (amount <= 0) { impossible("%s payment in money2u!", amount ? "negative" : "zero"); return; } if (!mongold || mongold->quan < amount) { impossible("%s paying without %s money?", a_monnam(mon), mongold ? "enough" : ""); return; } if (mongold->quan > amount) mongold = splitobj(mongold, amount); obj_extract_self(mongold); if (!merge_choice(invent, mongold) && inv_cnt(FALSE) >= 52) { You("have no room for the money!"); dropy(mongold); } else { addinv(mongold); context.botl = 1; } } STATIC_OVL struct monst * next_shkp(shkp, withbill) register struct monst *shkp; register boolean withbill; { for (; shkp; shkp = shkp->nmon) { if (DEADMONSTER(shkp)) continue; if (shkp->isshk && (ESHK(shkp)->billct || !withbill)) break; } if (shkp) { if (NOTANGRY(shkp)) { if (ESHK(shkp)->surcharge) pacify_shk(shkp); } else { if (!ESHK(shkp)->surcharge) rile_shk(shkp); } } return shkp; } /* called in mon.c */ void shkgone(mtmp) struct monst *mtmp; { struct eshk *eshk = ESHK(mtmp); struct mkroom *sroom = &rooms[eshk->shoproom - ROOMOFFSET]; struct obj *otmp; char *p; int sx, sy; /* [BUG: some of this should be done on the shop level */ /* even when the shk dies on a different level.] */ if (on_level(&eshk->shoplevel, &u.uz)) { remove_damage(mtmp, TRUE); sroom->resident = (struct monst *) 0; if (!search_special(ANY_SHOP)) level.flags.has_shop = 0; /* items on shop floor revert to ordinary objects */ for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) for (otmp = level.objects[sx][sy]; otmp; otmp = otmp->nexthere) otmp->no_charge = 0; /* Make sure bill is set only when the dead shk is the resident shk. */ if ((p = index(u.ushops, eshk->shoproom)) != 0) { setpaid(mtmp); eshk->bill_p = (struct bill_x *) 0; /* remove eshk->shoproom from u.ushops */ do { *p = *(p + 1); } while (*++p); } } } void set_residency(shkp, zero_out) register struct monst *shkp; register boolean zero_out; { if (on_level(&(ESHK(shkp)->shoplevel), &u.uz)) rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident = (zero_out) ? (struct monst *) 0 : shkp; } void replshk(mtmp, mtmp2) register struct monst *mtmp, *mtmp2; { rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2; if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) { ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]); } } /* do shopkeeper specific structure munging -dlc */ void restshk(shkp, ghostly) struct monst *shkp; boolean ghostly; { if (u.uz.dlevel) { struct eshk *eshkp = ESHK(shkp); if (eshkp->bill_p != (struct bill_x *) -1000) eshkp->bill_p = &eshkp->bill[0]; /* shoplevel can change as dungeons move around */ /* savebones guarantees that non-homed shk's will be gone */ if (ghostly) { assign_level(&eshkp->shoplevel, &u.uz); if (ANGRY(shkp) && strncmpi(eshkp->customer, plname, PL_NSIZ)) pacify_shk(shkp); } } } /* Clear the unpaid bit on all of the objects in the list. */ STATIC_OVL void clear_unpaid(list) register struct obj *list; { while (list) { if (Has_contents(list)) clear_unpaid(list->cobj); list->unpaid = 0; list = list->nobj; } } /* either you paid or left the shop or the shopkeeper died */ STATIC_OVL void setpaid(shkp) register struct monst *shkp; { register struct obj *obj; register struct monst *mtmp; /* FIXME: object handling should be limited to items which are on this particular shk's bill */ clear_unpaid(invent); clear_unpaid(fobj); clear_unpaid(level.buriedobjlist); if (thrownobj) thrownobj->unpaid = 0; if (kickedobj) kickedobj->unpaid = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) clear_unpaid(mtmp->minvent); for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) clear_unpaid(mtmp->minvent); while ((obj = billobjs) != 0) { obj_extract_self(obj); dealloc_obj(obj); } if (shkp) { ESHK(shkp)->billct = 0; ESHK(shkp)->credit = 0L; ESHK(shkp)->debit = 0L; ESHK(shkp)->loan = 0L; } } STATIC_OVL long addupbill(shkp) register struct monst *shkp; { register int ct = ESHK(shkp)->billct; register struct bill_x *bp = ESHK(shkp)->bill_p; register long total = 0L; while (ct--) { total += bp->price * bp->bquan; bp++; } return total; } STATIC_OVL void call_kops(shkp, nearshop) register struct monst *shkp; register boolean nearshop; { /* Keystone Kops srt@ucla */ register boolean nokops; if (!shkp) return; if (!Deaf) pline("An alarm sounds!"); nokops = ((mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) && (mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) && (mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) && (mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE)); if (!angry_guards(!!Deaf) && nokops) { if (flags.verbose && !Deaf) pline("But no one seems to respond to it."); return; } if (nokops) return; { coord mm; if (nearshop) { /* Create swarm around you, if you merely "stepped out" */ if (flags.verbose) pline_The("Keystone Kops appear!"); mm.x = u.ux; mm.y = u.uy; makekops(&mm); return; } if (flags.verbose) pline_The("Keystone Kops are after you!"); /* Create swarm near down staircase (hinders return to level) */ mm.x = xdnstair; mm.y = ydnstair; makekops(&mm); /* Create swarm near shopkeeper (hinders return to shop) */ mm.x = shkp->mx; mm.y = shkp->my; makekops(&mm); } } /* x,y is strictly inside shop */ char inside_shop(x, y) register xchar x, y; { register char rno; rno = levl[x][y].roomno; if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno - ROOMOFFSET)) return NO_ROOM; else return rno; } void u_left_shop(leavestring, newlev) char *leavestring; boolean newlev; { struct monst *shkp; struct eshk *eshkp; /* * IF player * ((didn't leave outright) AND * ((he is now strictly-inside the shop) OR * (he wasn't strictly-inside last turn anyway))) * THEN (there's nothing to do, so just return) */ if (!*leavestring && (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge)) return; shkp = shop_keeper(*u.ushops0); if (!shkp || !inhishop(shkp)) return; /* shk died, teleported, changed levels... */ eshkp = ESHK(shkp); if (!eshkp->billct && !eshkp->debit) /* bill is settled */ return; if (!*leavestring && !muteshk(shkp)) { /* * Player just stepped onto shop-boundary (known from above logic). * Try to intimidate him into paying his bill */ verbalize(NOTANGRY(shkp) ? "%s! Please pay before leaving." : "%s! Don't you leave without paying!", plname); return; } if (rob_shop(shkp)) { call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge)); } } /* robbery from outside the shop via telekinesis or grappling hook */ void remote_burglary(x, y) xchar x, y; { struct monst *shkp; struct eshk *eshkp; shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if (!shkp || !inhishop(shkp)) return; /* shk died, teleported, changed levels... */ eshkp = ESHK(shkp); if (!eshkp->billct && !eshkp->debit) /* bill is settled */ return; if (rob_shop(shkp)) { /*[might want to set 2nd arg based on distance from shop doorway]*/ call_kops(shkp, FALSE); } } /* shop merchandise has been taken; pay for it with any credit available; return false if the debt is fully covered by credit, true otherwise */ STATIC_OVL boolean rob_shop(shkp) struct monst *shkp; { struct eshk *eshkp; long total; eshkp = ESHK(shkp); rouse_shk(shkp, TRUE); total = (addupbill(shkp) + eshkp->debit); if (eshkp->credit >= total) { Your("credit of %ld %s is used to cover your shopping bill.", eshkp->credit, currency(eshkp->credit)); total = 0L; /* credit gets cleared by setpaid() */ } else { You("escaped the shop without paying!"); total -= eshkp->credit; } setpaid(shkp); if (!total) return FALSE; /* by this point, we know an actual robbery has taken place */ eshkp->robbed += total; You("stole %ld %s worth of merchandise.", total, currency(total)); if (!Role_if(PM_ROGUE)) /* stealing is unlawful */ adjalign(-sgn(u.ualign.type)); hot_pursuit(shkp); return TRUE; } /* give a message when entering an untended shop (caller has verified that) */ STATIC_OVL void deserted_shop(enterstring) /*const*/ char *enterstring; { struct monst *mtmp; struct mkroom *r = &rooms[(int) *enterstring - ROOMOFFSET]; int x, y, m = 0, n = 0; for (x = r->lx; x <= r->hx; ++x) for (y = r->ly; y <= r->hy; ++y) { if (x == u.ux && y == u.uy) continue; if ((mtmp = m_at(x, y)) != 0) { ++n; if (sensemon(mtmp) || ((mtmp->m_ap_type == M_AP_NOTHING || mtmp->m_ap_type == M_AP_MONSTER) && canseemon(mtmp))) ++m; } } if (Blind && !(Blind_telepat || Detect_monsters)) ++n; /* force feedback to be less specific */ pline("This shop %s %s.", (m < n) ? "seems to be" : "is", !n ? "deserted" : "untended"); } void u_entered_shop(enterstring) char *enterstring; { register int rt; register struct monst *shkp; register struct eshk *eshkp; static char empty_shops[5]; if (!*enterstring) return; if (!(shkp = shop_keeper(*enterstring))) { if (!index(empty_shops, *enterstring) && in_rooms(u.ux, u.uy, SHOPBASE) != in_rooms(u.ux0, u.uy0, SHOPBASE)) deserted_shop(enterstring); Strcpy(empty_shops, u.ushops); u.ushops[0] = '\0'; return; } eshkp = ESHK(shkp); if (!inhishop(shkp)) { /* dump core when referenced */ eshkp->bill_p = (struct bill_x *) -1000; if (!index(empty_shops, *enterstring)) deserted_shop(enterstring); Strcpy(empty_shops, u.ushops); u.ushops[0] = '\0'; return; } eshkp->bill_p = &(eshkp->bill[0]); if ((!eshkp->visitct || *eshkp->customer) && strncmpi(eshkp->customer, plname, PL_NSIZ)) { /* You seem to be new here */ eshkp->visitct = 0; eshkp->following = 0; (void) strncpy(eshkp->customer, plname, PL_NSIZ); pacify_shk(shkp); } if (muteshk(shkp) || eshkp->following) return; /* no dialog */ if (Invis) { pline("%s senses your presence.", shkname(shkp)); verbalize("Invisible customers are not welcome!"); return; } rt = rooms[*enterstring - ROOMOFFSET].rtype; if (ANGRY(shkp)) { verbalize("So, %s, you dare return to %s %s?!", plname, s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); } else if (eshkp->robbed) { pline("%s mutters imprecations against shoplifters.", shkname(shkp)); } else { verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), plname, eshkp->visitct++ ? " again" : "", s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); } /* can't do anything about blocking if teleported in */ if (!inside_shop(u.ux, u.uy)) { boolean should_block; int cnt; const char *tool; struct obj *pick = carrying(PICK_AXE), *mattock = carrying(DWARVISH_MATTOCK); if (pick || mattock) { cnt = 1; /* so far */ if (pick && mattock) { /* carrying both types */ tool = "digging tool"; cnt = 2; /* `more than 1' is all that matters */ } else if (pick) { tool = "pick-axe"; /* hack: `pick' already points somewhere into inventory */ while ((pick = pick->nobj) != 0) if (pick->otyp == PICK_AXE) ++cnt; } else { /* assert(mattock != 0) */ tool = "mattock"; while ((mattock = mattock->nobj) != 0) if (mattock->otyp == DWARVISH_MATTOCK) ++cnt; /* [ALI] Shopkeeper identifies mattock(s) */ if (!Blind) makeknown(DWARVISH_MATTOCK); } verbalize(NOTANGRY(shkp) ? "Will you please leave your %s%s outside?" : "Leave the %s%s outside.", tool, plur(cnt)); should_block = TRUE; } else if (u.usteed) { verbalize(NOTANGRY(shkp) ? "Will you please leave %s outside?" : "Leave %s outside.", y_monnam(u.usteed)); should_block = TRUE; } else { should_block = (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) || sobj_at(DWARVISH_MATTOCK, u.ux, u.uy))); } if (should_block) (void) dochug(shkp); /* shk gets extra move */ } return; } /* called when removing a pick-axe or mattock from a container */ void pick_pick(obj) struct obj *obj; { struct monst *shkp; if (obj->unpaid || !is_pick(obj)) return; shkp = shop_keeper(*u.ushops); if (shkp && inhishop(shkp) && !muteshk(shkp)) { static NEARDATA long pickmovetime = 0L; /* if you bring a sack of N picks into a shop to sell, don't repeat this N times when they're taken out */ if (moves != pickmovetime) verbalize("You sneaky %s! Get out of here with that pick!", cad(FALSE)); pickmovetime = moves; } } /* Decide whether two unpaid items are mergable; caller is responsible for making sure they're unpaid and the same type of object; we check the price quoted by the shopkeeper and also that they both belong to the same shk. */ boolean same_price(obj1, obj2) struct obj *obj1, *obj2; { register struct monst *shkp1, *shkp2; struct bill_x *bp1 = 0, *bp2 = 0; boolean are_mergable = FALSE; /* look up the first object by finding shk whose bill it's on */ for (shkp1 = next_shkp(fmon, TRUE); shkp1; shkp1 = next_shkp(shkp1->nmon, TRUE)) if ((bp1 = onbill(obj1, shkp1, TRUE)) != 0) break; /* second object is probably owned by same shk; if not, look harder */ if (shkp1 && (bp2 = onbill(obj2, shkp1, TRUE)) != 0) { shkp2 = shkp1; } else { for (shkp2 = next_shkp(fmon, TRUE); shkp2; shkp2 = next_shkp(shkp2->nmon, TRUE)) if ((bp2 = onbill(obj2, shkp2, TRUE)) != 0) break; } if (!bp1 || !bp2) impossible("same_price: object wasn't on any bill!"); else are_mergable = (shkp1 == shkp2 && bp1->price == bp2->price); return are_mergable; } /* * Figure out how much is owed to a given shopkeeper. * At present, we ignore any amount robbed from the shop, to avoid * turning the `$' command into a way to discover that the current * level is bones data which has a shk on the warpath. */ STATIC_OVL long shop_debt(eshkp) struct eshk *eshkp; { struct bill_x *bp; int ct; long debt = eshkp->debit; for (bp = eshkp->bill_p, ct = eshkp->billct; ct > 0; bp++, ct--) debt += bp->price * bp->bquan; return debt; } /* called in response to the `$' command */ void shopper_financial_report() { struct monst *shkp, *this_shkp = shop_keeper(inside_shop(u.ux, u.uy)); struct eshk *eshkp; long amt; int pass; eshkp = this_shkp ? ESHK(this_shkp) : 0; if (eshkp && !(eshkp->credit || shop_debt(eshkp))) { You("have no credit or debt in here."); this_shkp = 0; /* skip first pass */ } /* pass 0: report for the shop we're currently in, if any; pass 1: report for all other shops on this level. */ for (pass = this_shkp ? 0 : 1; pass <= 1; pass++) for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) { if ((shkp != this_shkp) ^ pass) continue; eshkp = ESHK(shkp); if ((amt = eshkp->credit) != 0) You("have %ld %s credit at %s %s.", amt, currency(amt), s_suffix(shkname(shkp)), shtypes[eshkp->shoptype - SHOPBASE].name); else if (shkp == this_shkp) You("have no credit in here."); if ((amt = shop_debt(eshkp)) != 0) You("owe %s %ld %s.", shkname(shkp), amt, currency(amt)); else if (shkp == this_shkp) You("don't owe any money here."); } } int inhishop(mtmp) register struct monst *mtmp; { struct eshk *eshkp = ESHK(mtmp); return (index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE), eshkp->shoproom) && on_level(&eshkp->shoplevel, &u.uz)); } struct monst * shop_keeper(rmno) register char rmno; { struct monst *shkp = rmno >= ROOMOFFSET ? rooms[rmno - ROOMOFFSET].resident : 0; if (shkp) { if (NOTANGRY(shkp)) { if (ESHK(shkp)->surcharge) pacify_shk(shkp); } else { if (!ESHK(shkp)->surcharge) rile_shk(shkp); } } return shkp; } boolean tended_shop(sroom) register struct mkroom *sroom; { register struct monst *mtmp = sroom->resident; if (!mtmp) return FALSE; else return (boolean) inhishop(mtmp); } STATIC_OVL struct bill_x * onbill(obj, shkp, silent) register struct obj *obj; register struct monst *shkp; register boolean silent; { if (shkp) { register struct bill_x *bp = ESHK(shkp)->bill_p; register int ct = ESHK(shkp)->billct; while (--ct >= 0) if (bp->bo_id == obj->o_id) { if (!obj->unpaid) pline("onbill: paid obj on bill?"); return bp; } else bp++; } if (obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?"); return (struct bill_x *) 0; } /* check whether an object or any of its contents belongs to a shop */ boolean is_unpaid(obj) struct obj *obj; { return (boolean) (obj->unpaid || (Has_contents(obj) && count_unpaid(obj->cobj))); } /* Delete the contents of the given object. */ void delete_contents(obj) register struct obj *obj; { register struct obj *curr; while ((curr = obj->cobj) != 0) { obj_extract_self(curr); obfree(curr, (struct obj *) 0); } } /* called with two args on merge */ void obfree(obj, merge) register struct obj *obj, *merge; { register struct bill_x *bp; register struct bill_x *bpm; register struct monst *shkp; if (obj->otyp == LEASH && obj->leashmon) o_unleash(obj); if (obj->oclass == FOOD_CLASS) food_disappears(obj); if (obj->oclass == SPBOOK_CLASS) book_disappears(obj); if (Has_contents(obj)) delete_contents(obj); shkp = 0; if (obj->unpaid) { /* look for a shopkeeper who owns this object */ for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp->nmon, TRUE)) if (onbill(obj, shkp, TRUE)) break; } /* sanity check, more or less */ if (!shkp) shkp = shop_keeper(*u.ushops); /* * Note: `shkp = shop_keeper(*u.ushops)' used to be * unconditional. But obfree() is used all over * the place, so making its behavior be dependent * upon player location doesn't make much sense. */ if ((bp = onbill(obj, shkp, FALSE)) != 0) { if (!merge) { bp->useup = 1; obj->unpaid = 0; /* only for doinvbill */ add_to_billobjs(obj); return; } bpm = onbill(merge, shkp, FALSE); if (!bpm) { /* this used to be a rename */ impossible("obfree: not on bill??"); return; } else { /* this was a merger */ bpm->bquan += bp->bquan; ESHK(shkp)->billct--; #ifdef DUMB { /* DRS/NS 2.2.6 messes up -- Peter Kendell */ int indx = ESHK(shkp)->billct; *bp = ESHK(shkp)->bill_p[indx]; } #else *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct]; #endif } } if (obj->owornmask) { impossible("obfree: deleting worn obj (%d: %ld)", obj->otyp, obj->owornmask); /* unfortunately at this point we don't know whether worn mask applied to hero or a monster or perhaps something bogus, so can't call remove_worn_item() to get _off() side-effects */ setnotworn(obj); } dealloc_obj(obj); } STATIC_OVL long check_credit(tmp, shkp) long tmp; register struct monst *shkp; { long credit = ESHK(shkp)->credit; if (credit == 0L) { ; /* nothing to do; just 'return tmp;' */ } else if (credit >= tmp) { pline_The("price is deducted from your credit."); ESHK(shkp)->credit -= tmp; tmp = 0L; } else { pline_The("price is partially covered by your credit."); ESHK(shkp)->credit = 0L; tmp -= credit; } return tmp; } STATIC_OVL void pay(tmp, shkp) long tmp; register struct monst *shkp; { long robbed = ESHK(shkp)->robbed; long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp)); if (balance > 0) money2mon(shkp, balance); else if (balance < 0) money2u(shkp, -balance); context.botl = 1; if (robbed) { robbed -= tmp; if (robbed < 0) robbed = 0L; ESHK(shkp)->robbed = robbed; } } /* return shkp to home position */ void home_shk(shkp, killkops) register struct monst *shkp; register boolean killkops; { register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y; (void) mnearto(shkp, x, y, TRUE); level.flags.has_shop = 1; if (killkops) { kops_gone(TRUE); pacify_guards(); } after_shk_move(shkp); } STATIC_OVL boolean angry_shk_exists() { register struct monst *shkp; for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) if (ANGRY(shkp)) return TRUE; return FALSE; } /* remove previously applied surcharge from all billed items */ STATIC_OVL void pacify_shk(shkp) register struct monst *shkp; { NOTANGRY(shkp) = TRUE; /* make peaceful */ if (ESHK(shkp)->surcharge) { register struct bill_x *bp = ESHK(shkp)->bill_p; register int ct = ESHK(shkp)->billct; ESHK(shkp)->surcharge = FALSE; while (ct-- > 0) { register long reduction = (bp->price + 3L) / 4L; bp->price -= reduction; /* undo 33% increase */ bp++; } } } /* add aggravation surcharge to all billed items */ STATIC_OVL void rile_shk(shkp) register struct monst *shkp; { NOTANGRY(shkp) = FALSE; /* make angry */ if (!ESHK(shkp)->surcharge) { register struct bill_x *bp = ESHK(shkp)->bill_p; register int ct = ESHK(shkp)->billct; ESHK(shkp)->surcharge = TRUE; while (ct-- > 0) { register long surcharge = (bp->price + 2L) / 3L; bp->price += surcharge; bp++; } } } /* wakeup and/or unparalyze shopkeeper */ STATIC_OVL void rouse_shk(shkp, verbosely) struct monst *shkp; boolean verbosely; { if (!shkp->mcanmove || shkp->msleeping) { /* greed induced recovery... */ if (verbosely && canspotmon(shkp)) pline("%s %s.", Monnam(shkp), shkp->msleeping ? "wakes up" : "can move again"); shkp->msleeping = 0; shkp->mfrozen = 0; shkp->mcanmove = 1; } } void make_happy_shk(shkp, silentkops) register struct monst *shkp; register boolean silentkops; { boolean wasmad = ANGRY(shkp); struct eshk *eshkp = ESHK(shkp); pacify_shk(shkp); eshkp->following = 0; eshkp->robbed = 0L; if (!Role_if(PM_ROGUE)) adjalign(sgn(u.ualign.type)); if (!inhishop(shkp)) { char shk_nam[BUFSZ]; boolean vanished = canseemon(shkp); Strcpy(shk_nam, mon_nam(shkp)); if (on_level(&eshkp->shoplevel, &u.uz)) { home_shk(shkp, FALSE); /* didn't disappear if shk can still be seen */ if (canseemon(shkp)) vanished = FALSE; } else { /* if sensed, does disappear regardless whether seen */ if (sensemon(shkp)) vanished = TRUE; /* can't act as porter for the Amulet, even if shk happens to be going farther down rather than up */ mdrop_special_objs(shkp); /* arrive near shop's door */ migrate_to_level(shkp, ledger_no(&eshkp->shoplevel), MIGR_APPROX_XY, &eshkp->shd); /* dismiss kops on that level when shk arrives */ eshkp->dismiss_kops = TRUE; } if (vanished) pline("Satisfied, %s suddenly disappears!", shk_nam); } else if (wasmad) pline("%s calms down.", Monnam(shkp)); make_happy_shoppers(silentkops); } /* called by make_happy_shk() and also by losedogs() for migrating shk */ void make_happy_shoppers(silentkops) boolean silentkops; { if (!angry_shk_exists()) { kops_gone(silentkops); pacify_guards(); } } void hot_pursuit(shkp) register struct monst *shkp; { if (!shkp->isshk) return; rile_shk(shkp); (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ); ESHK(shkp)->following = 1; } /* used when the shkp is teleported or falls (ox == 0) out of his shop, * or when the player is not on a costly_spot and he * damages something inside the shop. these conditions * must be checked by the calling function. */ void make_angry_shk(shkp, ox, oy) register struct monst *shkp; register xchar ox, oy; { xchar sx, sy; struct eshk *eshkp = ESHK(shkp); /* all pending shop transactions are now "past due" */ if (eshkp->billct || eshkp->debit || eshkp->loan || eshkp->credit) { eshkp->robbed += (addupbill(shkp) + eshkp->debit + eshkp->loan); eshkp->robbed -= eshkp->credit; if (eshkp->robbed < 0L) eshkp->robbed = 0L; /* billct, debit, loan, and credit will be cleared by setpaid */ setpaid(shkp); } /* If you just used a wand of teleportation to send the shk away, you might not be able to see her any more. Monnam would yield "it", which makes this message look pretty silly, so temporarily restore her original location during the call to Monnam. */ sx = shkp->mx, sy = shkp->my; if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy)) shkp->mx = ox, shkp->my = oy; pline("%s %s!", Monnam(shkp), !ANGRY(shkp) ? "gets angry" : "is furious"); shkp->mx = sx, shkp->my = sy; hot_pursuit(shkp); } STATIC_VAR const char no_money[] = "Moreover, you%s have no money."; STATIC_VAR const char not_enough_money[] = "Besides, you don't have enough to interest %s."; STATIC_OVL long cheapest_item(shkp) /* delivers the cheapest item on the list */ register struct monst *shkp; { register int ct = ESHK(shkp)->billct; register struct bill_x *bp = ESHK(shkp)->bill_p; register long gmin = (bp->price * bp->bquan); while (ct--) { if (bp->price * bp->bquan < gmin) gmin = bp->price * bp->bquan; bp++; } return gmin; } int dopay() { register struct eshk *eshkp; register struct monst *shkp; struct monst *nxtm, *resident; long ltmp; long umoney; int pass, tmp, sk = 0, seensk = 0; boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L); multi = 0; /* Find how many shk's there are, how many are in * sight, and are you in a shop room with one. */ nxtm = resident = 0; for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) { sk++; if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp; if (canspotmon(shkp)) seensk++; if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom)) resident = shkp; } if (nxtm) { /* Player should always appease an */ shkp = nxtm; /* irate shk standing next to them. */ goto proceed; } if ((!sk && (!Blind || Blind_telepat)) || (!Blind && !seensk)) { There("appears to be no shopkeeper here to receive your payment."); return 0; } if (!seensk) { You_cant("see..."); return 0; } /* The usual case. Allow paying at a distance when * inside a tended shop. Should we change that? */ if (sk == 1 && resident) { shkp = resident; goto proceed; } if (seensk == 1) { for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) if (canspotmon(shkp)) break; if (shkp != resident && distu(shkp->mx, shkp->my) > 2) { pline("%s is not near enough to receive your payment.", Monnam(shkp)); return 0; } } else { struct monst *mtmp; coord cc; int cx, cy; pline("Pay whom?"); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the creature you want to pay") < 0) return 0; /* player pressed ESC */ cx = cc.x; cy = cc.y; if (cx < 0) { pline("Try again..."); return 0; } if (u.ux == cx && u.uy == cy) { You("are generous to yourself."); return 0; } mtmp = m_at(cx, cy); if (!mtmp) { There("is no one there to receive your payment."); return 0; } if (!mtmp->isshk) { pline("%s is not interested in your payment.", Monnam(mtmp)); return 0; } if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) { pline("%s is too far to receive your payment.", Monnam(mtmp)); return 0; } shkp = mtmp; } if (!shkp) { debugpline0("dopay: null shkp."); return 0; } proceed: eshkp = ESHK(shkp); ltmp = eshkp->robbed; /* wake sleeping shk when someone who owes money offers payment */ if (ltmp || eshkp->billct || eshkp->debit) rouse_shk(shkp, TRUE); if (!shkp->mcanmove || shkp->msleeping) { /* still asleep/paralyzed */ pline("%s %s.", Monnam(shkp), rn2(2) ? "seems to be napping" : "doesn't respond"); return 0; } if (shkp != resident && NOTANGRY(shkp)) { umoney = money_cnt(invent); if (!ltmp) You("do not owe %s anything.", mon_nam(shkp)); else if (!umoney) { You("%shave no money.", stashed_gold ? "seem to " : ""); if (stashed_gold) pline("But you have some gold stashed away."); } else { if (umoney > ltmp) { You("give %s the %ld gold piece%s %s asked for.", shkname(shkp), ltmp, plur(ltmp), mhe(shkp)); pay(ltmp, shkp); } else { You("give %s all your%s gold.", shkname(shkp), stashed_gold ? " openly kept" : ""); pay(umoney, shkp); if (stashed_gold) pline("But you have hidden gold!"); } if ((umoney < ltmp / 2L) || (umoney < ltmp && stashed_gold)) pline("Unfortunately, %s doesn't look satisfied.", mhe(shkp)); else make_happy_shk(shkp, FALSE); } return 1; } /* ltmp is still eshkp->robbed here */ if (!eshkp->billct && !eshkp->debit) { umoney = money_cnt(invent); if (!ltmp && NOTANGRY(shkp)) { You("do not owe %s anything.", shkname(shkp)); if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); } else if (ltmp) { pline("%s is after blood, not money!", shkname(shkp)); if (umoney < ltmp / 2L || (umoney < ltmp && stashed_gold)) { if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); else pline(not_enough_money, mhim(shkp)); return 1; } pline("But since %s shop has been robbed recently,", mhis(shkp)); pline("you %scompensate %s for %s losses.", (umoney < ltmp) ? "partially " : "", shkname(shkp), mhis(shkp)); pay(umoney < ltmp ? umoney : ltmp, shkp); make_happy_shk(shkp, FALSE); } else { /* shopkeeper is angry, but has not been robbed -- * door broken, attacked, etc. */ pline("%s is after your hide, not your money!", Monnam(shkp)); if (umoney < 1000L) { if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); else pline(not_enough_money, mhim(shkp)); return 1; } You("try to appease %s by giving %s 1000 gold pieces.", x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE), mhim(shkp)); pay(1000L, shkp); if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3)) make_happy_shk(shkp, FALSE); else pline("But %s is as angry as ever.", shkname(shkp)); } return 1; } if (shkp != resident) { impossible("dopay: not to shopkeeper?"); if (resident) setpaid(resident); return 0; } /* pay debt, if any, first */ if (eshkp->debit) { long dtmp = eshkp->debit; long loan = eshkp->loan; char sbuf[BUFSZ]; umoney = money_cnt(invent); Sprintf(sbuf, "You owe %s %ld %s ", shkname(shkp), dtmp, currency(dtmp)); if (loan) { if (loan == dtmp) Strcat(sbuf, "you picked up in the store."); else Strcat(sbuf, "for gold picked up and the use of merchandise."); } else Strcat(sbuf, "for the use of merchandise."); pline1(sbuf); if (umoney + eshkp->credit < dtmp) { pline("But you don't%s have enough gold%s.", stashed_gold ? " seem to" : "", eshkp->credit ? " or credit" : ""); return 1; } else { if (eshkp->credit >= dtmp) { eshkp->credit -= dtmp; eshkp->debit = 0L; eshkp->loan = 0L; Your("debt is covered by your credit."); } else if (!eshkp->credit) { money2mon(shkp, dtmp); eshkp->debit = 0L; eshkp->loan = 0L; You("pay that debt."); context.botl = 1; } else { dtmp -= eshkp->credit; eshkp->credit = 0L; money2mon(shkp, dtmp); eshkp->debit = 0L; eshkp->loan = 0L; pline("That debt is partially offset by your credit."); You("pay the remainder."); context.botl = 1; } paid = TRUE; } } /* now check items on bill */ if (eshkp->billct) { register boolean itemize; int iprompt; umoney = money_cnt(invent); if (!umoney && !eshkp->credit) { You("%shave no money or credit%s.", stashed_gold ? "seem to " : "", paid ? " left" : ""); return 0; } if ((umoney + eshkp->credit) < cheapest_item(shkp)) { You("don't have enough money to buy%s the item%s you picked.", eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct)); if (stashed_gold) pline("Maybe you have some gold stashed away?"); return 0; } /* this isn't quite right; it itemizes without asking if the * single item on the bill is partly used up and partly unpaid */ iprompt = (eshkp->billct > 1 ? ynq("Itemized billing?") : 'y'); itemize = (iprompt == 'y'); if (iprompt == 'q') goto thanks; for (pass = 0; pass <= 1; pass++) { tmp = 0; while (tmp < eshkp->billct) { struct obj *otmp; register struct bill_x *bp = &(eshkp->bill_p[tmp]); /* find the object on one of the lists */ if ((otmp = bp_to_obj(bp)) != 0) { /* if completely used up, object quantity is stale; restoring it to its original value here avoids making the partly-used-up code more complicated */ if (bp->useup) otmp->quan = bp->bquan; } else { impossible("Shopkeeper administration out of order."); setpaid(shkp); /* be nice to the player */ return 1; } if (pass == bp->useup && otmp->quan == bp->bquan) { /* pay for used-up items on first pass and others * on second, so player will be stuck in the store * less often; things which are partly used up * are processed on both passes */ tmp++; } else { switch (dopayobj(shkp, bp, &otmp, pass, itemize)) { case PAY_CANT: return 1; /*break*/ case PAY_BROKE: paid = TRUE; goto thanks; /*break*/ case PAY_SKIP: tmp++; continue; /*break*/ case PAY_SOME: paid = TRUE; if (itemize) bot(); continue; /*break*/ case PAY_BUY: paid = TRUE; break; } if (itemize) bot(); *bp = eshkp->bill_p[--eshkp->billct]; } } } thanks: if (!itemize) update_inventory(); /* Done in dopayobj() if itemize. */ } if (!ANGRY(shkp) && paid && !muteshk(shkp)) verbalize("Thank you for shopping in %s %s!", s_suffix(shkname(shkp)), shtypes[eshkp->shoptype - SHOPBASE].name); return 1; } /* return 2 if used-up portion paid * 1 if paid successfully * 0 if not enough money * -1 if skip this object * -2 if no money/credit left */ STATIC_OVL int dopayobj(shkp, bp, obj_p, which, itemize) register struct monst *shkp; register struct bill_x *bp; struct obj **obj_p; int which; /* 0 => used-up item, 1 => other (unpaid or lost) */ boolean itemize; { register struct obj *obj = *obj_p; long ltmp, quan, save_quan; long umoney = money_cnt(invent); int buy; boolean stashed_gold = (hidden_gold() > 0L), consumed = (which == 0); if (!obj->unpaid && !bp->useup) { impossible("Paid object on bill??"); return PAY_BUY; } if (itemize && umoney + ESHK(shkp)->credit == 0L) { You("%shave no money or credit left.", stashed_gold ? "seem to " : ""); return PAY_BROKE; } /* we may need to temporarily adjust the object, if part of the original quantity has been used up but part remains unpaid */ save_quan = obj->quan; if (consumed) { /* either completely used up (simple), or split needed */ quan = bp->bquan; if (quan > obj->quan) /* difference is amount used up */ quan -= obj->quan; } else { /* dealing with ordinary unpaid item */ quan = obj->quan; } obj->quan = quan; /* to be used by doname() */ obj->unpaid = 0; /* ditto */ iflags.suppress_price++; /* affects containers */ ltmp = bp->price * quan; buy = PAY_BUY; /* flag; if changed then return early */ if (itemize) { char qbuf[BUFSZ], qsfx[BUFSZ]; Sprintf(qsfx, " for %ld %s. Pay?", ltmp, currency(ltmp)); (void) safe_qbuf(qbuf, (char *) 0, qsfx, obj, (quan == 1L) ? Doname2 : doname, ansimpleoname, (quan == 1L) ? "that" : "those"); if (yn(qbuf) == 'n') { buy = PAY_SKIP; /* don't want to buy */ } else if (quan < bp->bquan && !consumed) { /* partly used goods */ obj->quan = bp->bquan - save_quan; /* used up amount */ verbalize("%s for the other %s before buying %s.", ANGRY(shkp) ? "Pay" : "Please pay", simpleonames(obj), /* short name suffices */ save_quan > 1L ? "these" : "this one"); buy = PAY_SKIP; /* shk won't sell */ } } if (buy == PAY_BUY && umoney + ESHK(shkp)->credit < ltmp) { You("don't%s have gold%s enough to pay for %s.", stashed_gold ? " seem to" : "", (ESHK(shkp)->credit > 0L) ? " or credit" : "", thesimpleoname(obj)); buy = itemize ? PAY_SKIP : PAY_CANT; } if (buy != PAY_BUY) { /* restore unpaid object to original state */ obj->quan = save_quan; obj->unpaid = 1; iflags.suppress_price--; return buy; } pay(ltmp, shkp); shk_names_obj(shkp, obj, consumed ? "paid for %s at a cost of %ld gold piece%s.%s" : "bought %s for %ld gold piece%s.%s", ltmp, ""); obj->quan = save_quan; /* restore original count */ /* quan => amount just bought, save_quan => remaining unpaid count */ if (consumed) { if (quan != bp->bquan) { /* eliminate used-up portion; remainder is still unpaid */ bp->bquan = obj->quan; obj->unpaid = 1; bp->useup = 0; buy = PAY_SOME; } else { /* completely used-up, so get rid of it */ obj_extract_self(obj); /* assert( obj == *obj_p ); */ dealloc_obj(obj); *obj_p = 0; /* destroy pointer to freed object */ } } else if (itemize) update_inventory(); /* Done just once in dopay() if !itemize. */ iflags.suppress_price--; return buy; } static struct repo { /* repossession context */ struct monst *shopkeeper; coord location; } repo; /* routine called after dying (or quitting) */ boolean paybill(croaked) int croaked; /* -1: escaped dungeon; 0: quit; 1: died */ { struct monst *mtmp, *mtmp2, *firstshk, *resident, *creditor, *hostile, *localshk; struct eshk *eshkp; boolean taken = FALSE, local; int numsk = 0; /* if we escaped from the dungeon, shopkeepers can't reach us; shops don't occur on level 1, but this could happen if hero level teleports out of the dungeon and manages not to die */ if (croaked < 0) return FALSE; /* [should probably also return false when dead hero has been petrified since shk shouldn't be able to grab inventory which has been shut inside a statue] */ /* this is where inventory will end up if any shk takes it */ repo.location.x = repo.location.y = 0; repo.shopkeeper = 0; /* * Scan all shopkeepers on the level, to prioritize them: * 1) keeper of shop hero is inside and who is owed money, * 2) keeper of shop hero is inside who isn't owed any money, * 3) other shk who is owed money, 4) other shk who is angry, * 5) any shk local to this level, and if none is found, * 6) first shk on monster list (last resort; unlikely, since * any nonlocal shk will probably be in the owed category * and almost certainly be in the angry category). */ resident = creditor = hostile = localshk = (struct monst *) 0; for (mtmp = next_shkp(fmon, FALSE); mtmp; mtmp = next_shkp(mtmp2, FALSE)) { mtmp2 = mtmp->nmon; eshkp = ESHK(mtmp); local = on_level(&eshkp->shoplevel, &u.uz); if (local && index(u.ushops, eshkp->shoproom)) { /* inside this shk's shop [there might be more than one resident shk if hero is standing in a breech of a shared wall, so give priority to one who's also owed money] */ if (!resident || eshkp->billct || eshkp->debit || eshkp->robbed) resident = mtmp; } else if (eshkp->billct || eshkp->debit || eshkp->robbed) { /* owe this shopkeeper money (might also owe others) */ if (!creditor) creditor = mtmp; } else if (eshkp->following || ANGRY(mtmp)) { /* this shopkeeper is antagonistic (others might be too) */ if (!hostile) hostile = mtmp; } else if (local) { /* this shopkeeper's shop is on current level */ if (!localshk) localshk = mtmp; } } /* give highest priority shopkeeper first crack */ firstshk = resident ? resident : creditor ? creditor : hostile ? hostile : localshk; if (firstshk) { numsk++; taken = inherits(firstshk, numsk, croaked); } /* now handle the rest */ for (mtmp = next_shkp(fmon, FALSE); mtmp; mtmp = next_shkp(mtmp2, FALSE)) { mtmp2 = mtmp->nmon; eshkp = ESHK(mtmp); local = on_level(&eshkp->shoplevel, &u.uz); if (mtmp != firstshk) { numsk++; taken |= inherits(mtmp, numsk, croaked); } /* for bones: we don't want a shopless shk around */ if (!local) mongone(mtmp); } return taken; } STATIC_OVL boolean inherits(shkp, numsk, croaked) struct monst *shkp; int numsk; int croaked; { long loss = 0L; long umoney; struct eshk *eshkp = ESHK(shkp); boolean take = FALSE, taken = FALSE; unsigned save_minvis = shkp->minvis; int roomno = *u.ushops; char takes[BUFSZ]; shkp->minvis = 0; /* The simplifying principle is that first-come already took everything you had. */ if (numsk > 1) { if (cansee(shkp->mx, shkp->my) && croaked) { takes[0] = '\0'; if (has_head(shkp->data) && !rn2(2)) Sprintf(takes, ", shakes %s %s,", mhis(shkp), mbodypart(shkp, HEAD)); pline("%s %slooks at your corpse%s and %s.", Monnam(shkp), (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "", takes, !inhishop(shkp) ? "disappears" : "sighs"); } rouse_shk(shkp, FALSE); /* wake shk for bones */ taken = (roomno == eshkp->shoproom); goto skip; } /* get one case out of the way: you die in the shop, the */ /* shopkeeper is peaceful, nothing stolen, nothing owed. */ if (roomno == eshkp->shoproom && inhishop(shkp) && !eshkp->billct && !eshkp->robbed && !eshkp->debit && NOTANGRY(shkp) && !eshkp->following) { taken = (invent != 0); if (taken) pline("%s gratefully inherits all your possessions.", shkname(shkp)); set_repo_loc(shkp); goto clear; } if (eshkp->billct || eshkp->debit || eshkp->robbed) { if (roomno == eshkp->shoproom && inhishop(shkp)) loss = addupbill(shkp) + eshkp->debit; if (loss < eshkp->robbed) loss = eshkp->robbed; take = TRUE; } if (eshkp->following || ANGRY(shkp) || take) { if (!invent) goto skip; umoney = money_cnt(invent); takes[0] = '\0'; if (!shkp->mcanmove || shkp->msleeping) Strcat(takes, "wakes up and "); if (distu(shkp->mx, shkp->my) > 2) Strcat(takes, "comes and "); Strcat(takes, "takes"); if (loss > umoney || !loss || roomno == eshkp->shoproom) { eshkp->robbed -= umoney; if (eshkp->robbed < 0L) eshkp->robbed = 0L; if (umoney > 0) money2mon(shkp, umoney); context.botl = 1; pline("%s %s all your possessions.", shkname(shkp), takes); taken = TRUE; /* where to put player's invent (after disclosure) */ set_repo_loc(shkp); } else { money2mon(shkp, loss); context.botl = 1; pline("%s %s the %ld %s %sowed %s.", Monnam(shkp), takes, loss, currency(loss), strncmp(eshkp->customer, plname, PL_NSIZ) ? "" : "you ", shkp->female ? "her" : "him"); /* shopkeeper has now been paid in full */ pacify_shk(shkp); eshkp->following = 0; eshkp->robbed = 0L; } skip: /* in case we create bones */ rouse_shk(shkp, FALSE); /* wake up */ if (!inhishop(shkp)) home_shk(shkp, FALSE); } clear: shkp->minvis = save_minvis; setpaid(shkp); return taken; } STATIC_OVL void set_repo_loc(shkp) struct monst *shkp; { register xchar ox, oy; struct eshk *eshkp = ESHK(shkp); /* if you're not in this shk's shop room, or if you're in its doorway or entry spot, then your gear gets dumped all the way inside */ if (*u.ushops != eshkp->shoproom || IS_DOOR(levl[u.ux][u.uy].typ) || (u.ux == eshkp->shk.x && u.uy == eshkp->shk.y)) { /* shk.x,shk.y is the position immediately in * front of the door -- move in one more space */ ox = eshkp->shk.x; oy = eshkp->shk.y; ox += sgn(ox - eshkp->shd.x); oy += sgn(oy - eshkp->shd.y); } else { /* already inside this shk's shop */ ox = u.ux; oy = u.uy; } /* finish_paybill will deposit invent here */ repo.location.x = ox; repo.location.y = oy; repo.shopkeeper = shkp; } /* called at game exit, after inventory disclosure but before making bones */ void finish_paybill() { struct monst *shkp = repo.shopkeeper; int ox = repo.location.x, oy = repo.location.y; #if 0 /* don't bother */ if (ox == 0 && oy == 0) impossible("finish_paybill: no location"); #endif /* normally done by savebones(), but that's too late in this case */ unleash_all(); /* if hero has any gold left, take it into shopkeeper's possession */ if (shkp) { long umoney = money_cnt(invent); if (umoney) money2mon(shkp, umoney); } /* transfer rest of the character's inventory to the shop floor */ drop_upon_death((struct monst *) 0, (struct obj *) 0, ox, oy); } /* find obj on one of the lists */ STATIC_OVL struct obj * bp_to_obj(bp) register struct bill_x *bp; { register struct obj *obj; register unsigned int id = bp->bo_id; if (bp->useup) obj = o_on(id, billobjs); else obj = find_oid(id); return obj; } /* * Look for o_id on all lists but billobj. Return obj or NULL if not found. * Its OK for restore_timers() to call this function, there should not * be any timeouts on the billobjs chain. */ struct obj * find_oid(id) unsigned id; { struct obj *obj; struct monst *mon, *mmtmp[3]; int i; /* first check various obj lists directly */ if ((obj = o_on(id, invent)) != 0) return obj; if ((obj = o_on(id, fobj)) != 0) return obj; if ((obj = o_on(id, level.buriedobjlist)) != 0) return obj; if ((obj = o_on(id, migrating_objs)) != 0) return obj; /* not found yet; check inventory for members of various monst lists */ mmtmp[0] = fmon; mmtmp[1] = migrating_mons; mmtmp[2] = mydogs; /* for use during level changes */ for (i = 0; i < 3; i++) for (mon = mmtmp[i]; mon; mon = mon->nmon) if ((obj = o_on(id, mon->minvent)) != 0) return obj; /* not found at all */ return (struct obj *) 0; } /* Returns the price of an arbitrary item in the shop. Returns 0 if the item doesn't belong to a shopkeeper. */ long get_cost_of_shop_item(obj) register struct obj *obj; { struct monst *shkp; xchar x, y; long cost = 0L; if (*u.ushops && obj->oclass != COIN_CLASS && obj != uball && obj != uchain && get_obj_location(obj, &x, &y, 0) && (obj->unpaid || (obj->where == OBJ_FLOOR && !obj->no_charge && costly_spot(x, y))) && (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0 && inhishop(shkp)) { cost = obj->quan * get_cost(obj, shkp); if (Has_contents(obj)) cost += contained_cost(obj, shkp, 0L, FALSE, FALSE); } return cost; } /* calculate the value that the shk will charge for [one of] an object */ STATIC_OVL long get_cost(obj, shkp) register struct obj *obj; register struct monst *shkp; /* if angry, impose a surcharge */ { long tmp = getprice(obj, FALSE), /* used to perform a single calculation even when multiple adjustments (unID'd, dunce/tourist, charisma) are made */ multiplier = 1L, divisor = 1L; if (!tmp) tmp = 5L; /* shopkeeper may notice if the player isn't very knowledgeable - especially when gem prices are concerned */ if (!obj->dknown || !objects[obj->otyp].oc_name_known) { if (obj->oclass == GEM_CLASS && objects[obj->otyp].oc_material == GLASS) { int i; /* get a value that's 'random' from game to game, but the same within the same game */ boolean pseudorand = (((int) ubirthday % obj->otyp) >= obj->otyp / 2); /* all gems are priced high - real or not */ switch (obj->otyp - LAST_GEM) { case 1: /* white */ i = pseudorand ? DIAMOND : OPAL; break; case 2: /* blue */ i = pseudorand ? SAPPHIRE : AQUAMARINE; break; case 3: /* red */ i = pseudorand ? RUBY : JASPER; break; case 4: /* yellowish brown */ i = pseudorand ? AMBER : TOPAZ; break; case 5: /* orange */ i = pseudorand ? JACINTH : AGATE; break; case 6: /* yellow */ i = pseudorand ? CITRINE : CHRYSOBERYL; break; case 7: /* black */ i = pseudorand ? BLACK_OPAL : JET; break; case 8: /* green */ i = pseudorand ? EMERALD : JADE; break; case 9: /* violet */ i = pseudorand ? AMETHYST : FLUORITE; break; default: impossible("bad glass gem %d?", obj->otyp); i = STRANGE_OBJECT; break; } tmp = (long) objects[i].oc_cost; } else if (!(obj->o_id % 4)) { /* unid'd, arbitrarily impose surcharge: tmp *= 4/3 */ multiplier *= 4L; divisor *= 3L; } } if (uarmh && uarmh->otyp == DUNCE_CAP) multiplier *= 4L, divisor *= 3L; else if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV / 2)) || (uarmu && !uarm && !uarmc)) /* touristy shirt visible */ multiplier *= 4L, divisor *= 3L; if (ACURR(A_CHA) > 18) divisor *= 2L; else if (ACURR(A_CHA) == 18) multiplier *= 2L, divisor *= 3L; else if (ACURR(A_CHA) >= 16) multiplier *= 3L, divisor *= 4L; else if (ACURR(A_CHA) <= 5) multiplier *= 2L; else if (ACURR(A_CHA) <= 7) multiplier *= 3L, divisor *= 2L; else if (ACURR(A_CHA) <= 10) multiplier *= 4L, divisor *= 3L; /* tmp = (tmp * multiplier) / divisor [with roundoff tweak] */ tmp *= multiplier; if (divisor > 1L) { /* tmp = (((tmp * 10) / divisor) + 5) / 10 */ tmp *= 10L; tmp /= divisor; tmp += 5L; tmp /= 10L; } if (tmp <= 0L) tmp = 1L; /* the artifact prices in artilist[] are also used as a score bonus; inflate their shop price here without affecting score calculation */ if (obj->oartifact) tmp *= 4L; /* anger surcharge should match rile_shk's, so we do it separately from the multiplier/divisor calculation */ if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L; return tmp; } /* returns the price of a container's content. the price * of the "top" container is added in the calling functions. * a different price quoted for selling as vs. buying. */ long contained_cost(obj, shkp, price, usell, unpaid_only) struct obj *obj; struct monst *shkp; long price; boolean usell; boolean unpaid_only; { register struct obj *otmp; /* price of contained objects; "top" container handled by caller */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; if (usell) { if (saleable(shkp, otmp) && !otmp->unpaid && otmp->oclass != BALL_CLASS && !(otmp->oclass == FOOD_CLASS && otmp->oeaten) && !(Is_candle(otmp) && otmp->age < 20L * (long) objects[otmp->otyp].oc_cost)) price += set_cost(otmp, shkp); } else if (!otmp->no_charge && (otmp->unpaid || !unpaid_only)) { price += get_cost(otmp, shkp) * otmp->quan; } if (Has_contents(otmp)) price = contained_cost(otmp, shkp, price, usell, unpaid_only); } return price; } long contained_gold(obj) register struct obj *obj; { register struct obj *otmp; register long value = 0L; /* accumulate contained gold */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) value += otmp->quan; else if (Has_contents(otmp)) value += contained_gold(otmp); return value; } STATIC_OVL void dropped_container(obj, shkp, sale) register struct obj *obj; register struct monst *shkp; register boolean sale; { register struct obj *otmp; /* the "top" container is treated in the calling fn */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; if (!otmp->unpaid && !(sale && saleable(shkp, otmp))) otmp->no_charge = 1; if (Has_contents(otmp)) dropped_container(otmp, shkp, sale); } } void picked_container(obj) register struct obj *obj; { register struct obj *otmp; /* the "top" container is treated in the calling fn */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; if (otmp->no_charge) otmp->no_charge = 0; if (Has_contents(otmp)) picked_container(otmp); } } STATIC_OVL boolean special_stock(obj, shkp, quietly) struct obj *obj; struct monst *shkp; boolean quietly; { /* for unique situations */ if (ESHK(shkp)->shoptype == CANDLESHOP && obj->otyp == CANDELABRUM_OF_INVOCATION) { if (!quietly) { if (is_izchak(shkp, TRUE) && !u.uevent.invoked) { verbalize("No thanks, I'd hang onto that if I were you."); if (obj->spe < 7) verbalize( "You'll need %d%s candle%s to go along with it.", (7 - obj->spe), (obj->spe > 0) ? " more" : "", plur(7 - obj->spe)); /* [what if hero is already carrying enough candles? should Izchak explain how to attach them instead] */ } else { verbalize("I won't stock that. Take it out of here!"); } } return TRUE; } return FALSE; } /* calculate how much the shk will pay when buying [all of] an object */ STATIC_OVL long set_cost(obj, shkp) register struct obj *obj; register struct monst *shkp; { long tmp = getprice(obj, TRUE) * obj->quan, multiplier = 1L, divisor = 1L; if (uarmh && uarmh->otyp == DUNCE_CAP) divisor *= 3L; else if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV / 2)) || (uarmu && !uarm && !uarmc)) /* touristy shirt visible */ divisor *= 3L; else divisor *= 2L; /* shopkeeper may notice if the player isn't very knowledgeable - especially when gem prices are concerned */ if (!obj->dknown || !objects[obj->otyp].oc_name_known) { if (obj->oclass == GEM_CLASS) { /* different shop keepers give different prices */ if (objects[obj->otyp].oc_material == GEMSTONE || objects[obj->otyp].oc_material == GLASS) { tmp = (obj->otyp % (6 - shkp->m_id % 3)); tmp = (tmp + 3) * obj->quan; } } else if (tmp > 1L && !rn2(4)) multiplier *= 3L, divisor *= 4L; } if (tmp >= 1L) { /* [see get_cost()] */ tmp *= multiplier; if (divisor > 1L) { tmp *= 10L; tmp /= divisor; tmp += 5L; tmp /= 10L; } /* avoid adjusting nonzero to zero */ if (tmp < 1L) tmp = 1L; } /* (no adjustment for angry shk here) */ return tmp; } /* called when an item's value has been enhanced; if it happens to be on any shop bill, update that bill to reflect the new higher price [if the new price drops for some reason, keep the old one in place] */ void alter_cost(obj, amt) struct obj *obj; long amt; /* if 0, use regular shop pricing, otherwise force amount; if negative, use abs(amt) even if it's less than old cost */ { struct bill_x *bp = 0; struct monst *shkp; long new_price; for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp, TRUE)) if ((bp = onbill(obj, shkp, TRUE)) != 0) { new_price = !amt ? get_cost(obj, shkp) : (amt < 0L) ? -amt : amt; if (new_price > bp->price || amt < 0L) { bp->price = new_price; update_inventory(); } break; /* done */ } return; } /* called from doinv(invent.c) for inventory of unpaid objects */ long unpaid_cost(unp_obj, include_contents) struct obj *unp_obj; /* known to be unpaid or contain unpaid */ boolean include_contents; { struct bill_x *bp = (struct bill_x *) 0; struct monst *shkp; long amt = 0L; xchar ox, oy; if (!get_obj_location(unp_obj, &ox, &oy, BURIED_TOO | CONTAINED_TOO)) ox = u.ux, oy = u.uy; /* (shouldn't happen) */ if ((shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))) != 0) { bp = onbill(unp_obj, shkp, TRUE); } else { /* didn't find shk? try searching bills */ for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp->nmon, TRUE)) if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break; } /* onbill() gave no message if unexpected problem occurred */ if (!shkp || (unp_obj->unpaid && !bp)) { impossible("unpaid_cost: object wasn't on any bill."); } else { if (bp) amt = unp_obj->quan * bp->price; if (include_contents && Has_contents(unp_obj)) amt = contained_cost(unp_obj, shkp, amt, FALSE, TRUE); } return amt; } STATIC_OVL void add_one_tobill(obj, dummy, shkp) struct obj *obj; boolean dummy; struct monst *shkp; { struct eshk *eshkp; struct bill_x *bp; int bct; if (!billable(&shkp, obj, *u.ushops, TRUE)) return; eshkp = ESHK(shkp); if (eshkp->billct == BILLSZ) { You("got that for free!"); return; } bct = eshkp->billct; bp = &(eshkp->bill_p[bct]); bp->bo_id = obj->o_id; bp->bquan = obj->quan; if (dummy) { /* a dummy object must be inserted into */ bp->useup = 1; /* the billobjs chain here. crucial for */ add_to_billobjs(obj); /* eating floorfood in shop. see eat.c */ } else bp->useup = 0; bp->price = get_cost(obj, shkp); eshkp->billct++; obj->unpaid = 1; } STATIC_OVL void add_to_billobjs(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("add_to_billobjs: obj not free"); if (obj->timed) obj_stop_timers(obj); obj->nobj = billobjs; billobjs = obj; obj->where = OBJ_ONBILL; } /* recursive billing of objects within containers. */ STATIC_OVL void bill_box_content(obj, ininv, dummy, shkp) register struct obj *obj; register boolean ininv, dummy; register struct monst *shkp; { register struct obj *otmp; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; /* the "top" box is added in addtobill() */ if (!otmp->no_charge) add_one_tobill(otmp, dummy, shkp); if (Has_contents(otmp)) bill_box_content(otmp, ininv, dummy, shkp); } } /* shopkeeper tells you what you bought or sold, sometimes partly IDing it */ STATIC_OVL void shk_names_obj(shkp, obj, fmt, amt, arg) struct monst *shkp; struct obj *obj; const char *fmt; /* "%s %ld %s %s", doname(obj), amt, plur(amt), arg */ long amt; const char *arg; { char *obj_name, fmtbuf[BUFSZ]; boolean was_unknown = !obj->dknown; obj->dknown = TRUE; /* Use real name for ordinary weapons/armor, and spell-less * scrolls/books (that is, blank and mail), but only if the * object is within the shk's area of interest/expertise. */ if (!objects[obj->otyp].oc_magic && saleable(shkp, obj) && (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS || obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS || obj->otyp == MIRROR)) { was_unknown |= !objects[obj->otyp].oc_name_known; makeknown(obj->otyp); } obj_name = doname(obj); /* Use an alternate message when extra information is being provided */ if (was_unknown) { Sprintf(fmtbuf, "%%s; you %s", fmt); obj_name[0] = highc(obj_name[0]); pline(fmtbuf, obj_name, (obj->quan > 1L) ? "them" : "it", amt, plur(amt), arg); } else { You(fmt, obj_name, amt, plur(amt), arg); } } /* decide whether a shopkeeper thinks an item belongs to her */ boolean billable(shkpp, obj, roomno, reset_nocharge) struct monst **shkpp; /* in: non-null if shk has been validated; out: shk */ struct obj *obj; char roomno; boolean reset_nocharge; { struct monst *shkp = *shkpp; /* if caller hasn't supplied a shopkeeper, look one up now */ if (!shkp) { if (!roomno) return FALSE; shkp = shop_keeper(roomno); if (!shkp || !inhishop(shkp)) return FALSE; *shkpp = shkp; } /* perhaps we threw it away earlier */ if (onbill(obj, shkp, FALSE) || (obj->oclass == FOOD_CLASS && obj->oeaten)) return FALSE; /* outer container might be marked no_charge but still have contents which should be charged for; clear no_charge when picking things up */ if (obj->no_charge) { if (!Has_contents(obj) || (contained_gold(obj) == 0L && contained_cost(obj, shkp, 0L, FALSE, !reset_nocharge) == 0L)) shkp = 0; /* not billable */ if (reset_nocharge && !shkp && obj->oclass != COIN_CLASS) { obj->no_charge = 0; if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ } } return shkp ? TRUE : FALSE; } void addtobill(obj, ininv, dummy, silent) struct obj *obj; boolean ininv, dummy, silent; { struct monst *shkp = 0; long ltmp, cltmp, gltmp; int contentscount; boolean container; if (!billable(&shkp, obj, *u.ushops, TRUE)) return; if (obj->oclass == COIN_CLASS) { costly_gold(obj->ox, obj->oy, obj->quan); return; } else if (ESHK(shkp)->billct == BILLSZ) { if (!silent) You("got that for free!"); return; } ltmp = cltmp = gltmp = 0L; container = Has_contents(obj); if (!obj->no_charge) ltmp = get_cost(obj, shkp); if (obj->no_charge && !container) { obj->no_charge = 0; return; } if (container) { cltmp = contained_cost(obj, shkp, cltmp, FALSE, FALSE); gltmp = contained_gold(obj); if (ltmp) add_one_tobill(obj, dummy, shkp); if (cltmp) bill_box_content(obj, ininv, dummy, shkp); picked_container(obj); /* reset contained obj->no_charge */ ltmp += cltmp; if (gltmp) { costly_gold(obj->ox, obj->oy, gltmp); if (!ltmp) return; } if (obj->no_charge) obj->no_charge = 0; contentscount = count_unpaid(obj->cobj); } else { /* !container */ add_one_tobill(obj, dummy, shkp); contentscount = 0; } if (!muteshk(shkp) && !silent) { char buf[BUFSZ]; if (!ltmp) { pline("%s has no interest in %s.", Monnam(shkp), the(xname(obj))); return; } if (!ininv) { pline("%s will cost you %ld %s%s.", The(xname(obj)), ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : ""); } else { long save_quan = obj->quan; Strcpy(buf, "\"For you, "); if (ANGRY(shkp)) { Strcat(buf, "scum;"); } else { append_honorific(buf); Strcat(buf, "; only"); } obj->quan = 1L; /* fool xname() into giving singular */ pline("%s %ld %s %s %s%s.\"", buf, ltmp, currency(ltmp), (save_quan > 1L) ? "per" : (contentscount && !obj->unpaid) ? "for the contents of this" : "for this", xname(obj), (contentscount && obj->unpaid) ? and_its_contents : ""); obj->quan = save_quan; } } else if (!silent) { if (ltmp) pline_The("list price of %s%s%s is %ld %s%s.", (contentscount && !obj->unpaid) ? the_contents_of : "", the(xname(obj)), (contentscount && obj->unpaid) ? and_its_contents : "", ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : ""); else pline("%s does not notice.", Monnam(shkp)); } } void append_honorific(buf) char *buf; { /* (chooses among [0]..[3] normally; [1]..[4] after the Wizard has been killed or invocation ritual performed) */ static const char *const honored[] = { "good", "honored", "most gracious", "esteemed", "most renowned and sacred" }; Strcat(buf, honored[rn2(SIZE(honored) - 1) + u.uevent.udemigod]); if (is_vampire(youmonst.data)) Strcat(buf, (flags.female) ? " dark lady" : " dark lord"); else if (is_elf(youmonst.data)) Strcat(buf, (flags.female) ? " hiril" : " hir"); else Strcat(buf, !is_human(youmonst.data) ? " creature" : (flags.female) ? " lady" : " sir"); } void splitbill(obj, otmp) register struct obj *obj, *otmp; { /* otmp has been split off from obj */ register struct bill_x *bp; register long tmp; register struct monst *shkp = shop_keeper(*u.ushops); if (!shkp || !inhishop(shkp)) { impossible("splitbill: no resident shopkeeper??"); return; } bp = onbill(obj, shkp, FALSE); if (!bp) { impossible("splitbill: not on bill?"); return; } if (bp->bquan < otmp->quan) { impossible("Negative quantity on bill??"); } if (bp->bquan == otmp->quan) { impossible("Zero quantity on bill??"); } bp->bquan -= otmp->quan; if (ESHK(shkp)->billct == BILLSZ) otmp->unpaid = 0; else { tmp = bp->price; bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]); bp->bo_id = otmp->o_id; bp->bquan = otmp->quan; bp->useup = 0; bp->price = tmp; ESHK(shkp)->billct++; } } STATIC_OVL void sub_one_frombill(obj, shkp) register struct obj *obj; register struct monst *shkp; { register struct bill_x *bp; if ((bp = onbill(obj, shkp, FALSE)) != 0) { register struct obj *otmp; obj->unpaid = 0; if (bp->bquan > obj->quan) { otmp = newobj(); *otmp = *obj; otmp->oextra = (struct oextra *) 0; bp->bo_id = otmp->o_id = context.ident++; otmp->where = OBJ_FREE; otmp->quan = (bp->bquan -= obj->quan); otmp->owt = 0; /* superfluous */ bp->useup = 1; add_to_billobjs(otmp); return; } ESHK(shkp)->billct--; #ifdef DUMB { /* DRS/NS 2.2.6 messes up -- Peter Kendell */ int indx = ESHK(shkp)->billct; *bp = ESHK(shkp)->bill_p[indx]; } #else *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct]; #endif return; } else if (obj->unpaid) { impossible("sub_one_frombill: unpaid object not on bill"); obj->unpaid = 0; } } /* recursive check of unpaid objects within nested containers. */ void subfrombill(obj, shkp) register struct obj *obj; register struct monst *shkp; { register struct obj *otmp; sub_one_frombill(obj, shkp); if (Has_contents(obj)) for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; if (Has_contents(otmp)) subfrombill(otmp, shkp); else sub_one_frombill(otmp, shkp); } } STATIC_OVL long stolen_container(obj, shkp, price, ininv) struct obj *obj; struct monst *shkp; long price; boolean ininv; { struct obj *otmp; struct bill_x *bp; long billamt; /* the price of contained objects; caller handles top container */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; billamt = 0L; if (!billable(&shkp, otmp, ESHK(shkp)->shoproom, TRUE)) { /* billable() returns false for objects already on bill */ if ((bp = onbill(otmp, shkp, FALSE)) == 0) continue; /* this assumes that we're being called by stolen_value() (or by a recursive call to self on behalf of it) where the cost of this object is about to be added to shop debt in place of having it remain on the current bill */ billamt = bp->bquan * bp->price; sub_one_frombill(otmp, shkp); /* avoid double billing */ } if (billamt) price += billamt; else if (ininv ? otmp->unpaid : !otmp->no_charge) price += otmp->quan * get_cost(otmp, shkp); if (Has_contents(otmp)) price = stolen_container(otmp, shkp, price, ininv); } return price; } long stolen_value(obj, x, y, peaceful, silent) struct obj *obj; xchar x, y; boolean peaceful, silent; { long value = 0L, gvalue = 0L, billamt = 0L; char roomno = *in_rooms(x, y, SHOPBASE); struct bill_x *bp; struct monst *shkp = 0; if (!billable(&shkp, obj, roomno, FALSE)) { /* things already on the bill yield a not-billable result, so we need to check bill before deciding that shk doesn't care */ if ((bp = onbill(obj, shkp, FALSE)) == 0) return 0L; /* shk does care; take obj off bill to avoid double billing */ billamt = bp->bquan * bp->price; sub_one_frombill(obj, shkp); } if (obj->oclass == COIN_CLASS) { gvalue += obj->quan; } else { if (billamt) value += billamt; else if (!obj->no_charge) value += obj->quan * get_cost(obj, shkp); if (Has_contents(obj)) { boolean ininv = (obj->where == OBJ_INVENT || obj->where == OBJ_FREE); value += stolen_container(obj, shkp, 0L, ininv); if (!ininv) gvalue += contained_gold(obj); } } if (gvalue + value == 0L) return 0L; value += gvalue; if (peaceful) { boolean credit_use = !!ESHK(shkp)->credit; value = check_credit(value, shkp); /* 'peaceful' affects general treatment, but doesn't affect * the fact that other code expects that all charges after the * shopkeeper is angry are included in robbed, not debit */ if (ANGRY(shkp)) ESHK(shkp)->robbed += value; else ESHK(shkp)->debit += value; if (!silent) { const char *still = ""; if (credit_use) { if (ESHK(shkp)->credit) { You("have %ld %s credit remaining.", ESHK(shkp)->credit, currency(ESHK(shkp)->credit)); return value; } else if (!value) { You("have no credit remaining."); return 0; } still = "still "; } if (obj->oclass == COIN_CLASS) You("%sowe %s %ld %s!", still, mon_nam(shkp), value, currency(value)); else You("%sowe %s %ld %s for %s!", still, mon_nam(shkp), value, currency(value), obj->quan > 1L ? "them" : "it"); } } else { ESHK(shkp)->robbed += value; if (!silent) { if (cansee(shkp->mx, shkp->my)) { Norep("%s booms: \"%s, you are a thief!\"", Monnam(shkp), plname); } else Norep("You hear a scream, \"Thief!\""); } hot_pursuit(shkp); (void) angry_guards(FALSE); } return value; } /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */ static char sell_response = 'a'; static int sell_how = SELL_NORMAL; /* can't just use sell_response='y' for auto_credit because the 'a' response shouldn't carry over from ordinary selling to credit selling */ static boolean auto_credit = FALSE; void sellobj_state(deliberate) int deliberate; { /* If we're deliberately dropping something, there's no automatic response to the shopkeeper's "want to sell" query; however, if we accidentally drop anything, the shk will buy it/them without asking. This retains the old pre-query risk that slippery fingers while in shops entailed: you drop it, you've lost it. */ sell_response = (deliberate != SELL_NORMAL) ? '\0' : 'a'; sell_how = deliberate; auto_credit = FALSE; } void sellobj(obj, x, y) register struct obj *obj; xchar x, y; { register struct monst *shkp; register struct eshk *eshkp; long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer, shkmoney; boolean saleitem, cgold = FALSE, container = Has_contents(obj); boolean isgold = (obj->oclass == COIN_CLASS); boolean only_partially_your_contents = FALSE; if (!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp)) return; if (!costly_spot(x, y)) return; if (!*u.ushops) return; if (obj->unpaid && !container && !isgold) { sub_one_frombill(obj, shkp); return; } if (container) { /* find the price of content before subfrombill */ cltmp = contained_cost(obj, shkp, cltmp, TRUE, FALSE); /* find the value of contained gold */ gltmp += contained_gold(obj); cgold = (gltmp > 0L); } saleitem = saleable(shkp, obj); if (!isgold && !obj->unpaid && saleitem) ltmp = set_cost(obj, shkp); offer = ltmp + cltmp; /* get one case out of the way: nothing to sell, and no gold */ if (!isgold && ((offer + gltmp) == 0L || sell_how == SELL_DONTSELL)) { boolean unpaid = is_unpaid(obj); if (container) { dropped_container(obj, shkp, FALSE); if (!obj->unpaid && !saleitem) obj->no_charge = 1; if (unpaid) subfrombill(obj, shkp); } else obj->no_charge = 1; if (!unpaid && (sell_how != SELL_DONTSELL) && !special_stock(obj, shkp, FALSE)) pline("%s seems uninterested.", Monnam(shkp)); return; } /* you dropped something of your own - probably want to sell it */ rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */ eshkp = ESHK(shkp); if (ANGRY(shkp)) { /* they become shop-objects, no pay */ if (!muteshk(shkp)) verbalize("Thank you, scum!"); subfrombill(obj, shkp); return; } if (eshkp->robbed) { /* shkp is not angry? */ if (isgold) offer = obj->quan; else if (cgold) offer += cgold; if ((eshkp->robbed -= offer < 0L)) eshkp->robbed = 0L; if (offer && !muteshk(shkp)) verbalize( "Thank you for your contribution to restock this recently plundered shop."); subfrombill(obj, shkp); return; } if (isgold || cgold) { if (!cgold) gltmp = obj->quan; if (eshkp->debit >= gltmp) { if (eshkp->loan) { /* you carry shop's gold */ if (eshkp->loan >= gltmp) eshkp->loan -= gltmp; else eshkp->loan = 0L; } eshkp->debit -= gltmp; Your("debt is %spaid off.", eshkp->debit ? "partially " : ""); } else { long delta = gltmp - eshkp->debit; eshkp->credit += delta; if (eshkp->debit) { eshkp->debit = 0L; eshkp->loan = 0L; Your("debt is paid off."); } if (eshkp->credit == delta) You("have established %ld %s credit.", delta, currency(delta)); else pline("%ld %s added to your credit; total is now %ld %s.", delta, currency(delta), eshkp->credit, currency(eshkp->credit)); } if (!offer) { if (!isgold) { if (container) dropped_container(obj, shkp, FALSE); if (!obj->unpaid && !saleitem) obj->no_charge = 1; subfrombill(obj, shkp); } return; } } if ((!saleitem && !(container && cltmp > 0L)) || eshkp->billct == BILLSZ || obj->oclass == BALL_CLASS || obj->oclass == CHAIN_CLASS || offer == 0L || (obj->oclass == FOOD_CLASS && obj->oeaten) || (Is_candle(obj) && obj->age < 20L * (long) objects[obj->otyp].oc_cost)) { pline("%s seems uninterested%s.", Monnam(shkp), cgold ? " in the rest" : ""); if (container) dropped_container(obj, shkp, FALSE); obj->no_charge = 1; return; } shkmoney = money_cnt(shkp->minvent); if (!shkmoney) { char c, qbuf[BUFSZ]; long tmpcr = ((offer * 9L) / 10L) + (offer <= 1L); if (sell_how == SELL_NORMAL || auto_credit) { c = sell_response = 'y'; } else if (sell_response != 'n') { pline("%s cannot pay you at present.", shkname(shkp)); Sprintf(qbuf, "Will you accept %ld %s in credit for ", tmpcr, currency(tmpcr)); c = ynaq(safe_qbuf(qbuf, qbuf, "?", obj, doname, thesimpleoname, (obj->quan == 1L) ? "that" : "those")); if (c == 'a') { c = 'y'; auto_credit = TRUE; } } else /* previously specified "quit" */ c = 'n'; if (c == 'y') { shk_names_obj( shkp, obj, (sell_how != SELL_NORMAL) ? "traded %s for %ld zorkmid%s in %scredit." : "relinquish %s and acquire %ld zorkmid%s in %scredit.", tmpcr, (eshkp->credit > 0L) ? "additional " : ""); eshkp->credit += tmpcr; subfrombill(obj, shkp); } else { if (c == 'q') sell_response = 'n'; if (container) dropped_container(obj, shkp, FALSE); if (!obj->unpaid) obj->no_charge = 1; subfrombill(obj, shkp); } } else { char qbuf[BUFSZ], qsfx[BUFSZ]; boolean short_funds = (offer > shkmoney), one; if (short_funds) offer = shkmoney; if (!sell_response) { long yourc = 0L, shksc; if (container) { /* number of items owned by shk */ shksc = count_contents(obj, TRUE, TRUE, FALSE); /* number of items owned by you (total - shksc) */ yourc = count_contents(obj, TRUE, TRUE, TRUE) - shksc; only_partially_your_contents = shksc && yourc; } /* " offers * for ..." query formatting. Normal item(s): "... your . Sell it?" "... your . Sell them?" A container is either owned by the hero, or already owned by the shk (!ltmp), or the shk isn't interested in buying it (also !ltmp). It's either empty (!cltmp) or it has contents owned by the hero or it has some contents owned by the hero and others by the shk. (The case where it has contents already entirely owned by the shk is treated the same was if it were empty since the hero isn't selling any of those contents.) Your container: "... your . Sell it?" "... your and its contents. Sell them?" "... your and item inside. Sell them?" "... your and items inside. Sell them?" Shk's container: "... your item in the . Sell it?" "... your items in the . Sell them?" */ Sprintf(qbuf, "%s offers%s %ld gold piece%s for %s%s ", shkname(shkp), short_funds ? " only" : "", offer, plur(offer), (cltmp && !ltmp) ? ((yourc == 1L) ? "your item in " : "your items in ") : "", obj->unpaid ? "the" : "your"); one = obj->unpaid ? (yourc == 1L) : (obj->quan == 1L && !cltmp); Sprintf(qsfx, "%s. Sell %s?", (cltmp && ltmp) ? (only_partially_your_contents ? ((yourc == 1L) ? " and item inside" : " and items inside") : and_its_contents) : "", one ? "it" : "them"); (void) safe_qbuf(qbuf, qbuf, qsfx, obj, xname, simpleonames, one ? "that" : "those"); } else qbuf[0] = '\0'; /* just to pacify lint */ switch (sell_response ? sell_response : ynaq(qbuf)) { case 'q': sell_response = 'n'; case 'n': if (container) dropped_container(obj, shkp, FALSE); if (!obj->unpaid) obj->no_charge = 1; subfrombill(obj, shkp); break; case 'a': sell_response = 'y'; case 'y': if (container) dropped_container(obj, shkp, TRUE); if (!obj->unpaid && !saleitem) obj->no_charge = 1; subfrombill(obj, shkp); pay(-offer, shkp); shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ? ((!ltmp && cltmp && only_partially_your_contents) ? "sold some items inside %s for %ld gold piece%s.%s" : "sold %s for %ld gold piece%s.%s") : "relinquish %s and receive %ld gold piece%s in compensation.%s", offer, ""); break; default: impossible("invalid sell response"); } } } int doinvbill(mode) int mode; /* 0: deliver count 1: paged */ { #ifdef __SASC void sasc_bug(struct obj *, unsigned); #endif struct monst *shkp; struct eshk *eshkp; struct bill_x *bp, *end_bp; struct obj *obj; long totused; char *buf_p; winid datawin; shkp = shop_keeper(*u.ushops); if (!shkp || !inhishop(shkp)) { if (mode != 0) impossible("doinvbill: no shopkeeper?"); return 0; } eshkp = ESHK(shkp); if (mode == 0) { /* count expended items, so that the `I' command can decide whether to include 'x' in its prompt string */ int cnt = !eshkp->debit ? 0 : 1; for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct]; bp < end_bp; bp++) if (bp->useup || ((obj = bp_to_obj(bp)) != 0 && obj->quan < bp->bquan)) cnt++; return cnt; } datawin = create_nhwindow(NHW_MENU); putstr(datawin, 0, "Unpaid articles already used up:"); putstr(datawin, 0, ""); totused = 0L; for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct]; bp < end_bp; bp++) { obj = bp_to_obj(bp); if (!obj) { impossible("Bad shopkeeper administration."); goto quit; } if (bp->useup || bp->bquan > obj->quan) { long oquan, uquan, thisused; oquan = obj->quan; uquan = (bp->useup ? bp->bquan : bp->bquan - oquan); thisused = bp->price * uquan; totused += thisused; iflags.suppress_price++; /* suppress "(unpaid)" suffix */ /* Why 'x'? To match `I x', more or less. */ buf_p = xprname(obj, (char *) 0, 'x', FALSE, thisused, uquan); iflags.suppress_price--; putstr(datawin, 0, buf_p); } } if (eshkp->debit) { /* additional shop debt which has no itemization available */ if (totused) putstr(datawin, 0, ""); totused += eshkp->debit; buf_p = xprname((struct obj *) 0, "usage charges and/or other fees", GOLD_SYM, FALSE, eshkp->debit, 0L); putstr(datawin, 0, buf_p); } buf_p = xprname((struct obj *) 0, "Total:", '*', FALSE, totused, 0L); putstr(datawin, 0, ""); putstr(datawin, 0, buf_p); display_nhwindow(datawin, FALSE); quit: destroy_nhwindow(datawin); return 0; } #define HUNGRY 2 STATIC_OVL long getprice(obj, shk_buying) register struct obj *obj; boolean shk_buying; { register long tmp = (long) objects[obj->otyp].oc_cost; if (obj->oartifact) { tmp = arti_cost(obj); if (shk_buying) tmp /= 4; } switch (obj->oclass) { case FOOD_CLASS: /* simpler hunger check, (2-4)*cost */ if (u.uhs >= HUNGRY && !shk_buying) tmp *= (long) u.uhs; if (obj->oeaten) tmp = 0L; break; case WAND_CLASS: if (obj->spe == -1) tmp = 0L; break; case POTION_CLASS: if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed) tmp = 0L; break; case ARMOR_CLASS: case WEAPON_CLASS: if (obj->spe > 0) tmp += 10L * (long) obj->spe; break; case TOOL_CLASS: if (Is_candle(obj) && obj->age < 20L * (long) objects[obj->otyp].oc_cost) tmp /= 2L; break; } return tmp; } /* shk catches thrown pick-axe */ struct monst * shkcatch(obj, x, y) register struct obj *obj; register xchar x, y; { register struct monst *shkp; if (!(shkp = shop_keeper(inside_shop(x, y))) || !inhishop(shkp)) return 0; if (shkp->mcanmove && !shkp->msleeping && (*u.ushops != ESHK(shkp)->shoproom || !inside_shop(u.ux, u.uy)) && dist2(shkp->mx, shkp->my, x, y) < 3 /* if it is the shk's pos, you hit and anger him */ && (shkp->mx != x || shkp->my != y)) { if (mnearto(shkp, x, y, TRUE) && !muteshk(shkp)) verbalize("Out of my way, scum!"); if (cansee(x, y)) { pline("%s nimbly%s catches %s.", Monnam(shkp), (x == shkp->mx && y == shkp->my) ? "" : " reaches over and", the(xname(obj))); if (!canspotmon(shkp)) map_invisible(x, y); delay_output(); mark_synch(); } subfrombill(obj, shkp); (void) mpickobj(shkp, obj); return shkp; } return (struct monst *) 0; } void add_damage(x, y, cost) register xchar x, y; long cost; { struct damage *tmp_dam; char *shops; if (IS_DOOR(levl[x][y].typ)) { struct monst *mtmp; /* Don't schedule for repair unless it's a real shop entrance */ for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++) if ((mtmp = shop_keeper(*shops)) != 0 && x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y) break; if (!*shops) return; } for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) if (tmp_dam->place.x == x && tmp_dam->place.y == y) { tmp_dam->cost += cost; return; } tmp_dam = (struct damage *) alloc((unsigned) sizeof(struct damage)); tmp_dam->when = monstermoves; tmp_dam->place.x = x; tmp_dam->place.y = y; tmp_dam->cost = cost; tmp_dam->typ = levl[x][y].typ; tmp_dam->next = level.damagelist; level.damagelist = tmp_dam; /* If player saw damage, display as a wall forever */ if (cansee(x, y)) levl[x][y].seenv = SVALL; } /* * Do something about damage. Either (!croaked) try to repair it, or * (croaked) just discard damage structs for non-shared locations, since * they'll never get repaired. Assume that shared locations will get * repaired eventually by the other shopkeeper(s). This might be an erroneous * assumption (they might all be dead too), but we have no reasonable way of * telling that. */ STATIC_OVL void remove_damage(shkp, croaked) struct monst *shkp; boolean croaked; { struct damage *tmp_dam, *tmp2_dam; boolean did_repair = FALSE, saw_door = FALSE, saw_floor = FALSE, stop_picking = FALSE, doorway_trap = FALSE; int saw_walls = 0, saw_untrap = 0; char trapmsg[BUFSZ]; tmp_dam = level.damagelist; tmp2_dam = 0; while (tmp_dam) { register xchar x = tmp_dam->place.x, y = tmp_dam->place.y; char shops[5]; int disposition; unsigned old_doormask = 0; disposition = 0; Strcpy(shops, in_rooms(x, y, SHOPBASE)); if (index(shops, ESHK(shkp)->shoproom)) { if (IS_DOOR(levl[x][y].typ)) old_doormask = levl[x][y].doormask; if (croaked) disposition = (shops[1]) ? 0 : 1; else if (stop_picking) disposition = repair_damage(shkp, tmp_dam, FALSE); else { /* Defer the stop_occupation() until after repair msgs */ if (closed_door(x, y)) stop_picking = picking_at(x, y); disposition = repair_damage(shkp, tmp_dam, FALSE); if (!disposition) stop_picking = FALSE; } } if (!disposition) { tmp2_dam = tmp_dam; tmp_dam = tmp_dam->next; continue; } if (disposition > 1) { did_repair = TRUE; if (cansee(x, y)) { if (IS_WALL(levl[x][y].typ)) { saw_walls++; } else if (IS_DOOR(levl[x][y].typ) /* an existing door here implies trap removal */ && !(old_doormask & (D_ISOPEN | D_CLOSED))) { saw_door = TRUE; } else if (disposition == 3) { /* untrapped */ saw_untrap++; if (IS_DOOR(levl[x][y].typ)) doorway_trap = TRUE; } else { saw_floor = TRUE; } } } tmp_dam = tmp_dam->next; if (!tmp2_dam) { free((genericptr_t) level.damagelist); level.damagelist = tmp_dam; } else { free((genericptr_t) tmp2_dam->next); tmp2_dam->next = tmp_dam; } } if (!did_repair) return; if (saw_untrap) { Sprintf(trapmsg, "%s trap%s", (saw_untrap > 3) ? "several" : (saw_untrap > 1) ? "some" : "a", plur(saw_untrap)); Sprintf(eos(trapmsg), " %s", vtense(trapmsg, "are")); Sprintf(eos(trapmsg), " removed from the %s", (doorway_trap && saw_untrap == 1) ? "doorway" : "floor"); } else trapmsg[0] = '\0'; /* not just lint suppression... */ if (saw_walls) { char wallbuf[BUFSZ]; Sprintf(wallbuf, "section%s", plur(saw_walls)); pline("Suddenly, %s %s of wall %s up!", (saw_walls == 1) ? "a" : (saw_walls <= 3) ? "some" : "several", wallbuf, vtense(wallbuf, "close")); if (saw_door) pline_The("shop door reappears!"); if (saw_floor) pline_The("floor is repaired!"); if (saw_untrap) pline("%s!", upstart(trapmsg)); } else { if (saw_door || saw_floor || saw_untrap) pline("Suddenly, %s%s%s%s%s!", saw_door ? "the shop door reappears" : "", (saw_door && saw_floor) ? " and " : "", saw_floor ? "the floor damage is gone" : "", ((saw_door || saw_floor) && *trapmsg) ? " and " : "", trapmsg); else if (inside_shop(u.ux, u.uy) == ESHK(shkp)->shoproom) You_feel("more claustrophobic than before."); else if (!Deaf && !rn2(10)) Norep("The dungeon acoustics noticeably change."); } if (stop_picking) stop_occupation(); } /* * 0: repair postponed, 1: silent repair (no messages), 2: normal repair * 3: untrap */ int repair_damage(shkp, tmp_dam, catchup) register struct monst *shkp; register struct damage *tmp_dam; boolean catchup; /* restoring a level */ { register xchar x, y, i; xchar litter[9]; register struct monst *mtmp; register struct obj *otmp; register struct trap *ttmp; if ((monstermoves - tmp_dam->when) < REPAIR_DELAY) return 0; if (shkp->msleeping || !shkp->mcanmove || ESHK(shkp)->following) return 0; x = tmp_dam->place.x; y = tmp_dam->place.y; if (!IS_ROOM(tmp_dam->typ)) { if (x == u.ux && y == u.uy) if (!Passes_walls) return 0; if (x == shkp->mx && y == shkp->my) return 0; if ((mtmp = m_at(x, y)) && (!passes_walls(mtmp->data))) return 0; } if ((ttmp = t_at(x, y)) != 0) { if (x == u.ux && y == u.uy) if (!Passes_walls) return 0; if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) { /* convert to an object */ otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); (void) mpickobj(shkp, otmp); } deltrap(ttmp); if (IS_DOOR(tmp_dam->typ) && !(levl[x][y].doormask & D_ISOPEN)) { levl[x][y].doormask = D_CLOSED; block_point(x, y); } else if (IS_WALL(tmp_dam->typ)) { levl[x][y].typ = tmp_dam->typ; block_point(x, y); } newsym(x, y); return 3; } if (IS_ROOM(tmp_dam->typ)) { /* No messages, because player already filled trap door */ return 1; } if ((tmp_dam->typ == levl[x][y].typ) && (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN))) /* No messages if player already replaced shop door */ return 1; levl[x][y].typ = tmp_dam->typ; (void) memset((genericptr_t) litter, 0, sizeof(litter)); if ((otmp = level.objects[x][y]) != 0) { /* Scatter objects haphazardly into the shop */ #define NEED_UPDATE 1 #define OPEN 2 #define INSHOP 4 #define horiz(i) ((i % 3) - 1) #define vert(i) ((i / 3) - 1) for (i = 0; i < 9; i++) { if ((i == 4) || (!ZAP_POS(levl[x + horiz(i)][y + vert(i)].typ))) continue; litter[i] = OPEN; if (inside_shop(x + horiz(i), y + vert(i)) == ESHK(shkp)->shoproom) litter[i] |= INSHOP; } if (Punished && !u.uswallow && ((uchain->ox == x && uchain->oy == y) || (uball->ox == x && uball->oy == y))) { /* * Either the ball or chain is in the repair location. * * Take the easy way out and put ball&chain under hero. */ if (!muteshk(shkp)) verbalize("Get your junk out of my wall!"); unplacebc(); /* pick 'em up */ placebc(); /* put 'em down */ } while ((otmp = level.objects[x][y]) != 0) /* Don't mess w/ boulders -- just merge into wall */ if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } else { while (!(litter[i = rn2(9)] & INSHOP)) ; remove_object(otmp); place_object(otmp, x + horiz(i), y + vert(i)); litter[i] |= NEED_UPDATE; } } if (catchup) return 1; /* repair occurred while off level */ block_point(x, y); if (IS_DOOR(tmp_dam->typ)) { levl[x][y].doormask = D_CLOSED; /* arbitrary */ newsym(x, y); } else { /* don't set doormask - it is (hopefully) the same as it was if not, perhaps save it with the damage array... */ if (IS_WALL(tmp_dam->typ) && cansee(x, y)) { /* Player sees actual repair process, so they KNOW it's a wall */ levl[x][y].seenv = SVALL; newsym(x, y); } /* Mark this wall as "repaired". There currently is no code to do anything about repaired walls, so don't do it. */ } for (i = 0; i < 9; i++) if (litter[i] & NEED_UPDATE) newsym(x + horiz(i), y + vert(i)); return 2; #undef NEED_UPDATE #undef OPEN #undef INSHOP #undef vert #undef horiz } /* * shk_move: return 1: moved 0: didn't -1: let m_move do it -2: died */ int shk_move(shkp) register struct monst *shkp; { register xchar gx, gy, omx, omy; register int udist; register schar appr; register struct eshk *eshkp = ESHK(shkp); int z; boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv; omx = shkp->mx; omy = shkp->my; if (inhishop(shkp)) remove_damage(shkp, FALSE); if ((udist = distu(omx, omy)) < 3 && (shkp->data != &mons[PM_GRID_BUG] || (omx == u.ux || omy == u.uy))) { if (ANGRY(shkp) || (Conflict && !resist(shkp, RING_CLASS, 0, 0))) { if (Displaced) Your("displaced image doesn't fool %s!", mon_nam(shkp)); (void) mattacku(shkp); return 0; } if (eshkp->following) { if (strncmp(eshkp->customer, plname, PL_NSIZ)) { if (!muteshk(shkp)) verbalize("%s, %s! I was looking for %s.", Hello(shkp), plname, eshkp->customer); eshkp->following = 0; return 0; } if (moves > followmsg + 4) { if (!muteshk(shkp)) verbalize("%s, %s! Didn't you forget to pay?", Hello(shkp), plname); followmsg = moves; if (!rn2(9)) { pline("%s doesn't like customers who don't pay.", Monnam(shkp)); rile_shk(shkp); } } if (udist < 2) return 0; } } appr = 1; gx = eshkp->shk.x; gy = eshkp->shk.y; satdoor = (gx == omx && gy == omy); if (eshkp->following || ((z = holetime()) >= 0 && z * z <= udist)) { /* [This distance check used to apply regardless of whether the shk was following, but that resulted in m_move() sometimes taking the shk out of the shop if the player had fenced him in with boulders or traps. Such voluntary abandonment left unpaid objects in invent, triggering billing impossibilities on the next level once the character fell through the hole.] */ if (udist > 4 && eshkp->following && !eshkp->billct) return -1; /* leave it to m_move */ gx = u.ux; gy = u.uy; } else if (ANGRY(shkp)) { /* Move towards the hero if the shopkeeper can see him. */ if (shkp->mcansee && m_canseeu(shkp)) { gx = u.ux; gy = u.uy; } avoid = FALSE; } else { #define GDIST(x, y) (dist2(x, y, gx, gy)) if (Invis || u.usteed) { avoid = FALSE; } else { uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y); if (uondoor) { badinv = (carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) || (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) || sobj_at(DWARVISH_MATTOCK, u.ux, u.uy)))); if (satdoor && badinv) return 0; avoid = !badinv; } else { avoid = (*u.ushops && distu(gx, gy) > 8); badinv = FALSE; } if (((!eshkp->robbed && !eshkp->billct && !eshkp->debit) || avoid) && GDIST(omx, omy) < 3) { if (!badinv && !onlineu(omx, omy)) return 0; if (satdoor) appr = gx = gy = 0; } } } z = move_special(shkp, inhishop(shkp), appr, uondoor, avoid, omx, omy, gx, gy); if (z > 0) after_shk_move(shkp); return z; } /* called after shopkeeper moves, in case themove causes re-entry into shop */ void after_shk_move(shkp) struct monst *shkp; { struct eshk *eshkp = ESHK(shkp); if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) { /* reset bill_p, need to re-calc player's occupancy too */ eshkp->bill_p = &eshkp->bill[0]; check_special_room(FALSE); } } /* for use in levl_follower (mondata.c) */ boolean is_fshk(mtmp) register struct monst *mtmp; { return (boolean) (mtmp->isshk && ESHK(mtmp)->following); } /* You are digging in the shop. */ void shopdig(fall) register int fall; { register struct monst *shkp = shop_keeper(*u.ushops); int lang; const char *grabs = "grabs"; if (!shkp) return; /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */ lang = 0; if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data)) ; /* lang stays 0 */ else if (shkp->data->msound <= MS_ANIMAL) lang = 1; else if (shkp->data->msound >= MS_HUMANOID) lang = 2; if (!inhishop(shkp)) { if (Role_if(PM_KNIGHT)) { You_feel("like a common thief."); adjalign(-sgn(u.ualign.type)); } return; } if (!fall) { if (lang == 2) { if (u.utraptype == TT_PIT) verbalize( "Be careful, %s, or you might fall through the floor.", flags.female ? "madam" : "sir"); else verbalize("%s, do not damage the floor here!", flags.female ? "Madam" : "Sir"); } if (Role_if(PM_KNIGHT)) { You_feel("like a common thief."); adjalign(-sgn(u.ualign.type)); } } else if (!um_dist(shkp->mx, shkp->my, 5) && !shkp->msleeping && shkp->mcanmove && (ESHK(shkp)->billct || ESHK(shkp)->debit)) { register struct obj *obj, *obj2; if (nolimbs(shkp->data)) { grabs = "knocks off"; #if 0 /* This is what should happen, but for balance * reasons, it isn't currently. */ if (lang == 2) pline("%s curses %s inability to grab your backpack!", shkname(shkp), mhim(shkp)); rile_shk(shkp); return; #endif } if (distu(shkp->mx, shkp->my) > 2) { mnexto(shkp); /* for some reason the shopkeeper can't come next to you */ if (distu(shkp->mx, shkp->my) > 2) { if (lang == 2) pline("%s curses you in anger and frustration!", shkname(shkp)); else if (lang == 1) growl(shkp); rile_shk(shkp); return; } else pline("%s %s, and %s your backpack!", shkname(shkp), makeplural(locomotion(shkp->data, "leap")), grabs); } else pline("%s %s your backpack!", shkname(shkp), grabs); for (obj = invent; obj; obj = obj2) { obj2 = obj->nobj; if ((obj->owornmask & ~(W_SWAPWEP | W_QUIVER)) != 0 || (obj == uswapwep && u.twoweap) || (obj->otyp == LEASH && obj->leashmon)) continue; if (obj == current_wand) continue; setnotworn(obj); freeinv(obj); subfrombill(obj, shkp); (void) add_to_minv(shkp, obj); /* may free obj */ } } } STATIC_OVL void makekops(mm) coord *mm; { static const short k_mndx[4] = { PM_KEYSTONE_KOP, PM_KOP_SERGEANT, PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN }; int k_cnt[4], cnt, mndx, k; k_cnt[0] = cnt = abs(depth(&u.uz)) + rnd(5); k_cnt[1] = (cnt / 3) + 1; /* at least one sarge */ k_cnt[2] = (cnt / 6); /* maybe a lieutenant */ k_cnt[3] = (cnt / 9); /* and maybe a kaptain */ for (k = 0; k < 4; k++) { if ((cnt = k_cnt[k]) == 0) break; mndx = k_mndx[k]; if (mvitals[mndx].mvflags & G_GONE) continue; while (cnt--) if (enexto(mm, mm->x, mm->y, &mons[mndx])) (void) makemon(&mons[mndx], mm->x, mm->y, NO_MM_FLAGS); } } void pay_for_damage(dmgstr, cant_mollify) const char *dmgstr; boolean cant_mollify; { register struct monst *shkp = (struct monst *) 0; char shops_affected[5]; register boolean uinshp = (*u.ushops != '\0'); char qbuf[80]; register xchar x, y; boolean dugwall = (!strcmp(dmgstr, "dig into") /* wand */ || !strcmp(dmgstr, "damage")); /* pick-axe */ boolean animal, pursue; struct damage *tmp_dam, *appear_here = 0; /* any number >= (80*80)+(24*24) would do, actually */ long cost_of_damage = 0L; unsigned int nearest_shk = 7000, nearest_damage = 7000; int picks = 0; for (tmp_dam = level.damagelist; (tmp_dam && (tmp_dam->when == monstermoves)); tmp_dam = tmp_dam->next) { char *shp; if (!tmp_dam->cost) continue; cost_of_damage += tmp_dam->cost; Strcpy(shops_affected, in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE)); for (shp = shops_affected; *shp; shp++) { struct monst *tmp_shk; unsigned int shk_distance; if (!(tmp_shk = shop_keeper(*shp))) continue; if (tmp_shk == shkp) { unsigned int damage_distance = distu(tmp_dam->place.x, tmp_dam->place.y); if (damage_distance < nearest_damage) { nearest_damage = damage_distance; appear_here = tmp_dam; } continue; } if (!inhishop(tmp_shk)) continue; shk_distance = distu(tmp_shk->mx, tmp_shk->my); if (shk_distance > nearest_shk) continue; if ((shk_distance == nearest_shk) && picks) { if (rn2(++picks)) continue; } else picks = 1; shkp = tmp_shk; nearest_shk = shk_distance; appear_here = tmp_dam; nearest_damage = distu(tmp_dam->place.x, tmp_dam->place.y); } } if (!cost_of_damage || !shkp) return; animal = (shkp->data->msound <= MS_ANIMAL); pursue = FALSE; x = appear_here->place.x; y = appear_here->place.y; /* not the best introduction to the shk... */ (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ); /* if the shk is already on the war path, be sure it's all out */ if (ANGRY(shkp) || ESHK(shkp)->following) { hot_pursuit(shkp); return; } /* if the shk is not in their shop.. */ if (!*in_rooms(shkp->mx, shkp->my, SHOPBASE)) { if (!cansee(shkp->mx, shkp->my)) return; pursue = TRUE; goto getcad; } if (uinshp) { if (um_dist(shkp->mx, shkp->my, 1) && !um_dist(shkp->mx, shkp->my, 3)) { pline("%s leaps towards you!", shkname(shkp)); mnexto(shkp); } pursue = um_dist(shkp->mx, shkp->my, 1); if (pursue) goto getcad; } else { /* * Make shkp show up at the door. Effect: If there is a monster * in the doorway, have the hero hear the shopkeeper yell a bit, * pause, then have the shopkeeper appear at the door, having * yanked the hapless critter out of the way. */ if (MON_AT(x, y)) { if (!Deaf && !animal) { You_hear("an angry voice:"); verbalize("Out of my way, scum!"); wait_synch(); #if defined(UNIX) || defined(VMS) #if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) #endif sleep(1); #endif } else { growl(shkp); } } (void) mnearto(shkp, x, y, TRUE); } if ((um_dist(x, y, 1) && !uinshp) || cant_mollify || (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage || !rn2(50)) { getcad: if (muteshk(shkp)) { if (animal && shkp->mcanmove && !shkp->msleeping) yelp(shkp); } else if (pursue || uinshp || !um_dist(x, y, 1)) { verbalize("How dare you %s my %s?", dmgstr, dugwall ? "shop" : "door"); } else { pline("%s shouts:", shkname(shkp)); verbalize("Who dared %s my %s?", dmgstr, dugwall ? "shop" : "door"); } hot_pursuit(shkp); return; } if (Invis) Your("invisibility does not fool %s!", shkname(shkp)); Sprintf(qbuf, "%sYou did %ld %s worth of damage!%s Pay?", !animal ? cad(TRUE) : "", cost_of_damage, currency(cost_of_damage), !animal ? "\"" : ""); if (yn(qbuf) != 'n') { cost_of_damage = check_credit(cost_of_damage, shkp); money2mon(shkp, cost_of_damage); context.botl = 1; pline("Mollified, %s accepts your restitution.", shkname(shkp)); /* move shk back to his home loc */ home_shk(shkp, FALSE); pacify_shk(shkp); } else { if (!animal) verbalize("Oh, yes! You'll pay!"); else growl(shkp); hot_pursuit(shkp); adjalign(-sgn(u.ualign.type)); } } /* called in dokick.c when we kick an object that might be in a store */ boolean costly_spot(x, y) register xchar x, y; { struct monst *shkp; struct eshk *eshkp; if (!level.flags.has_shop) return FALSE; shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if (!shkp || !inhishop(shkp)) return FALSE; eshkp = ESHK(shkp); return (boolean) (inside_shop(x, y) && !(x == eshkp->shk.x && y == eshkp->shk.y)); } /* called by dotalk(sounds.c) when #chatting; returns obj if location contains shop goods and shopkeeper is willing & able to speak */ struct obj * shop_object(x, y) register xchar x, y; { register struct obj *otmp; register struct monst *shkp; if (!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp)) return (struct obj *) 0; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->oclass != COIN_CLASS) break; /* note: otmp might have ->no_charge set, but that's ok */ return (otmp && costly_spot(x, y) && NOTANGRY(shkp) && shkp->mcanmove && !shkp->msleeping) ? otmp : (struct obj *) 0; } /* give price quotes for all objects linked to this one (ie, on this spot) */ void price_quote(first_obj) register struct obj *first_obj; { register struct obj *otmp; char buf[BUFSZ], price[40]; long cost = 0L; int cnt = 0; boolean contentsonly = FALSE; winid tmpwin; struct monst *shkp = shop_keeper(inside_shop(u.ux, u.uy)); tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, "Fine goods for sale:"); putstr(tmpwin, 0, ""); for (otmp = first_obj; otmp; otmp = otmp->nexthere) { if (otmp->oclass == COIN_CLASS) continue; cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L : get_cost(otmp, (struct monst *) 0); contentsonly = !cost; if (Has_contents(otmp)) cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE); if (!cost) { Strcpy(price, "no charge"); contentsonly = FALSE; } else { Sprintf(price, "%ld %s%s", cost, currency(cost), (otmp->quan) > 1L ? " each" : ""); } Sprintf(buf, "%s%s, %s", contentsonly ? the_contents_of : "", doname(otmp), price); putstr(tmpwin, 0, buf), cnt++; } if (cnt > 1) { display_nhwindow(tmpwin, TRUE); } else if (cnt == 1) { if (!cost) { /* ", no charge" */ pline("%s!", upstart(buf)); /* buf still contains the string */ } else { /* print cost in slightly different format, so can't reuse buf; cost and contentsonly are already set up */ Sprintf(buf, "%s%s", contentsonly ? the_contents_of : "", doname(first_obj)); pline("%s, price %ld %s%s%s", upstart(buf), cost, currency(cost), (first_obj->quan > 1L) ? " each" : "", contentsonly ? "." : shk_embellish(first_obj, cost)); } } destroy_nhwindow(tmpwin); } STATIC_OVL const char * shk_embellish(itm, cost) register struct obj *itm; long cost; { if (!rn2(3)) { register int o, choice = rn2(5); if (choice == 0) choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3); switch (choice) { case 4: if (cost < 10L) break; else o = itm->oclass; if (o == FOOD_CLASS) return ", gourmets' delight!"; if (objects[itm->otyp].oc_name_known ? objects[itm->otyp].oc_magic : (o == AMULET_CLASS || o == RING_CLASS || o == WAND_CLASS || o == POTION_CLASS || o == SCROLL_CLASS || o == SPBOOK_CLASS)) return ", painstakingly developed!"; return ", superb craftsmanship!"; case 3: return ", finest quality."; case 2: return ", an excellent choice."; case 1: return ", a real bargain."; default: break; } } else if (itm->oartifact) { return ", one of a kind!"; } return "."; } /* First 4 supplied by Ronen and Tamar, remainder by development team */ const char *Izchak_speaks[] = { "%s says: 'These shopping malls give me a headache.'", "%s says: 'Slow down. Think clearly.'", "%s says: 'You need to take things one at a time.'", "%s says: 'I don't like poofy coffee... give me Columbian Supremo.'", "%s says that getting the devteam's agreement on anything is difficult.", "%s says that he has noticed those who serve their deity will prosper.", "%s says: 'Don't try to steal from me - I have friends in high places!'", "%s says: 'You may well need something from this shop in the future.'", "%s comments about the Valley of the Dead as being a gateway." }; void shk_chat(shkp) struct monst *shkp; { struct eshk *eshk; long shkmoney; if (!shkp->isshk) { /* The monster type is shopkeeper, but this monster is not actually a shk, which could happen if someone wishes for a shopkeeper statue and then animates it. (Note: shkname() would be "" in a case like this.) */ pline("%s asks whether you've seen any untended shops recently.", Monnam(shkp)); /* [Perhaps we ought to check whether this conversation is taking place inside an untended shop, but a shopless shk can probably be expected to be rather disoriented.] */ return; } eshk = ESHK(shkp); if (ANGRY(shkp)) { pline("%s mentions how much %s dislikes %s customers.", shkname(shkp), mhe(shkp), eshk->robbed ? "non-paying" : "rude"); } else if (eshk->following) { if (strncmp(eshk->customer, plname, PL_NSIZ)) { verbalize("%s %s! I was looking for %s.", Hello(shkp), plname, eshk->customer); eshk->following = 0; } else { verbalize("%s %s! Didn't you forget to pay?", Hello(shkp), plname); } } else if (eshk->billct) { register long total = addupbill(shkp) + eshk->debit; pline("%s says that your bill comes to %ld %s.", shkname(shkp), total, currency(total)); } else if (eshk->debit) { pline("%s reminds you that you owe %s %ld %s.", shkname(shkp), mhim(shkp), eshk->debit, currency(eshk->debit)); } else if (eshk->credit) { pline("%s encourages you to use your %ld %s of credit.", shkname(shkp), eshk->credit, currency(eshk->credit)); } else if (eshk->robbed) { pline("%s complains about a recent robbery.", shkname(shkp)); } else if ((shkmoney = money_cnt(shkp->minvent)) < 50) { pline("%s complains that business is bad.", shkname(shkp)); } else if (shkmoney > 4000) { pline("%s says that business is good.", shkname(shkp)); } else if (is_izchak(shkp, FALSE)) { pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))], shkname(shkp)); } else { pline("%s talks about the problem of shoplifters.", shkname(shkp)); } } STATIC_OVL void kops_gone(silent) boolean silent; { register int cnt = 0; register struct monst *mtmp, *mtmp2; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (mtmp->data->mlet == S_KOP) { if (canspotmon(mtmp)) cnt++; mongone(mtmp); } } if (cnt && !silent) pline_The("Kop%s (disappointed) vanish%s into thin air.", plur(cnt), (cnt == 1) ? "es" : ""); } STATIC_OVL long cost_per_charge(shkp, otmp, altusage) struct monst *shkp; struct obj *otmp; boolean altusage; /* some items have an "alternate" use with different cost */ { long tmp = 0L; if (!shkp || !inhishop(shkp)) return 0L; /* insurance */ tmp = get_cost(otmp, shkp); /* The idea is to make the exhaustive use of an unpaid item * more expensive than buying it outright. */ if (otmp->otyp == MAGIC_LAMP) { /* 1 */ /* normal use (ie, as light source) of a magic lamp never degrades its value, but not charging anything would make identification too easy; charge an amount comparable to what is charged for an ordinary lamp (don't bother with angry shk surcharge) */ if (!altusage) tmp = (long) objects[OIL_LAMP].oc_cost; else tmp += tmp / 3L; /* djinni is being released */ } else if (otmp->otyp == MAGIC_MARKER) { /* 70 - 100 */ /* No way to determine in advance how many charges will be * wasted. So, arbitrarily, one half of the price per use. */ tmp /= 2L; } else if (otmp->otyp == BAG_OF_TRICKS /* 1 - 20 */ || otmp->otyp == HORN_OF_PLENTY) { /* altusage: emptying of all the contents at once */ if (!altusage) tmp /= 5L; } else if (otmp->otyp == CRYSTAL_BALL /* 1 - 5 */ || otmp->otyp == OIL_LAMP /* 1 - 10 */ || otmp->otyp == BRASS_LANTERN || (otmp->otyp >= MAGIC_FLUTE && otmp->otyp <= DRUM_OF_EARTHQUAKE) /* 5 - 9 */ || otmp->oclass == WAND_CLASS) { /* 3 - 11 */ if (otmp->spe > 1) tmp /= 4L; } else if (otmp->oclass == SPBOOK_CLASS) { tmp -= tmp / 5L; } else if (otmp->otyp == CAN_OF_GREASE || otmp->otyp == TINNING_KIT || otmp->otyp == EXPENSIVE_CAMERA) { tmp /= 10L; } else if (otmp->otyp == POT_OIL) { tmp /= 5L; } return tmp; } /* Charge the player for partial use of an unpaid object. * * Note that bill_dummy_object() should be used instead * when an object is completely used. */ void check_unpaid_usage(otmp, altusage) struct obj *otmp; boolean altusage; { struct monst *shkp; const char *fmt, *arg1, *arg2; char buf[BUFSZ]; long tmp; if (!otmp->unpaid || !*u.ushops || (otmp->spe <= 0 && objects[otmp->otyp].oc_charged)) return; if (!(shkp = shop_keeper(*u.ushops)) || !inhishop(shkp)) return; if ((tmp = cost_per_charge(shkp, otmp, altusage)) == 0L) return; arg1 = arg2 = ""; if (otmp->oclass == SPBOOK_CLASS) { fmt = "%sYou owe%s %ld %s."; Sprintf(buf, "This is no free library, %s! ", cad(FALSE)); arg1 = rn2(2) ? buf : ""; arg2 = ESHK(shkp)->debit > 0L ? " an additional" : ""; } else if (otmp->otyp == POT_OIL) { fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax)."; } else if (altusage && (otmp->otyp == BAG_OF_TRICKS || otmp->otyp == HORN_OF_PLENTY)) { fmt = "%s%sEmptying that will cost you %ld %s."; if (!rn2(3)) arg1 = "Whoa! "; if (!rn2(3)) arg1 = "Watch it! "; } else { fmt = "%s%sUsage fee, %ld %s."; if (!rn2(3)) arg1 = "Hey! "; if (!rn2(3)) arg2 = "Ahem. "; } if (!muteshk(shkp)) { verbalize(fmt, arg1, arg2, tmp, currency(tmp)); exercise(A_WIS, TRUE); /* you just got info */ } ESHK(shkp)->debit += tmp; } /* for using charges of unpaid objects "used in the normal manner" */ void check_unpaid(otmp) struct obj *otmp; { check_unpaid_usage(otmp, FALSE); /* normal item use */ } void costly_gold(x, y, amount) register xchar x, y; register long amount; { register long delta; register struct monst *shkp; register struct eshk *eshkp; if (!costly_spot(x, y)) return; /* shkp now guaranteed to exist by costly_spot() */ shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); eshkp = ESHK(shkp); if (eshkp->credit >= amount) { if (eshkp->credit > amount) Your("credit is reduced by %ld %s.", amount, currency(amount)); else Your("credit is erased."); eshkp->credit -= amount; } else { delta = amount - eshkp->credit; if (eshkp->credit) Your("credit is erased."); if (eshkp->debit) Your("debt increases by %ld %s.", delta, currency(delta)); else You("owe %s %ld %s.", shkname(shkp), delta, currency(delta)); eshkp->debit += delta; eshkp->loan += delta; eshkp->credit = 0L; } } /* used in domove to block diagonal shop-exit */ /* x,y should always be a door */ boolean block_door(x, y) register xchar x, y; { register int roomno = *in_rooms(x, y, SHOPBASE); register struct monst *shkp; if (roomno < 0 || !IS_SHOP(roomno)) return FALSE; if (!IS_DOOR(levl[x][y].typ)) return FALSE; if (roomno != *u.ushops) return FALSE; if (!(shkp = shop_keeper((char) roomno)) || !inhishop(shkp)) return FALSE; if (shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y /* Actually, the shk should be made to block _any_ * door, including a door the player digs, if the * shk is within a 'jumping' distance. */ && ESHK(shkp)->shd.x == x && ESHK(shkp)->shd.y == y && shkp->mcanmove && !shkp->msleeping && (ESHK(shkp)->debit || ESHK(shkp)->billct || ESHK(shkp)->robbed)) { pline("%s%s blocks your way!", shkname(shkp), Invis ? " senses your motion and" : ""); return TRUE; } return FALSE; } /* used in domove to block diagonal shop-entry; u.ux, u.uy should always be a door */ boolean block_entry(x, y) register xchar x, y; { register xchar sx, sy; register int roomno; register struct monst *shkp; if (!(IS_DOOR(levl[u.ux][u.uy].typ) && levl[u.ux][u.uy].doormask == D_BROKEN)) return FALSE; roomno = *in_rooms(x, y, SHOPBASE); if (roomno < 0 || !IS_SHOP(roomno)) return FALSE; if (!(shkp = shop_keeper((char) roomno)) || !inhishop(shkp)) return FALSE; if (ESHK(shkp)->shd.x != u.ux || ESHK(shkp)->shd.y != u.uy) return FALSE; sx = ESHK(shkp)->shk.x; sy = ESHK(shkp)->shk.y; if (shkp->mx == sx && shkp->my == sy && shkp->mcanmove && !shkp->msleeping && (x == sx - 1 || x == sx + 1 || y == sy - 1 || y == sy + 1) && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) || u.usteed)) { pline("%s%s blocks your way!", shkname(shkp), Invis ? " senses your motion and" : ""); return TRUE; } return FALSE; } /* "your " or "Foobar's " (note the trailing space) */ char * shk_your(buf, obj) char *buf; struct obj *obj; { if (!shk_owns(buf, obj) && !mon_owns(buf, obj)) Strcpy(buf, the_your[carried(obj) ? 1 : 0]); return strcat(buf, " "); } char * Shk_Your(buf, obj) char *buf; struct obj *obj; { (void) shk_your(buf, obj); *buf = highc(*buf); return buf; } STATIC_OVL char * shk_owns(buf, obj) char *buf; struct obj *obj; { struct monst *shkp; xchar x, y; if (get_obj_location(obj, &x, &y, 0) && (obj->unpaid || (obj->where == OBJ_FLOOR && !obj->no_charge && costly_spot(x, y)))) { shkp = shop_keeper(inside_shop(x, y)); return strcpy(buf, shkp ? s_suffix(shkname(shkp)) : the_your[0]); } return (char *) 0; } STATIC_OVL char * mon_owns(buf, obj) char *buf; struct obj *obj; { if (obj->where == OBJ_MINVENT) return strcpy(buf, s_suffix(y_monnam(obj->ocarry))); return (char *) 0; } STATIC_OVL const char * cad(altusage) boolean altusage; /* used as a verbalized exclamation: \"Cad! ...\" */ { const char *res = 0; switch (is_demon(youmonst.data) ? 3 : poly_gender()) { case 0: res = "cad"; break; case 1: res = "minx"; break; case 2: res = "beast"; break; case 3: res = "fiend"; break; default: impossible("cad: unknown gender"); res = "thing"; break; } if (altusage) { char *cadbuf = mon_nam(&youmonst); /* snag an output buffer */ /* alternate usage adds a leading double quote and trailing exclamation point plus sentence separating spaces */ Sprintf(cadbuf, "\"%s! ", res); cadbuf[1] = highc(cadbuf[1]); res = cadbuf; } return res; } #ifdef __SASC void sasc_bug(struct obj *op, unsigned x) { op->unpaid = x; } #endif /*shk.c*/ nethack-3.6.0/src/shknam.c0000664000076400007660000006616112624044164014366 0ustar paxedpaxed/* NetHack 3.6 shknam.c $NHDT-Date: 1448094342 2015/11/21 08:25:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.38 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* shknam.c -- initialize a shop */ #include "hack.h" STATIC_DCL boolean FDECL(veggy_item, (struct obj * obj, int)); STATIC_DCL int NDECL(shkveg); STATIC_DCL void FDECL(mkveggy_at, (int, int)); STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *, int, int, BOOLEAN_P)); STATIC_DCL void FDECL(nameshk, (struct monst *, const char *const *)); STATIC_DCL int FDECL(shkinit, (const struct shclass *, struct mkroom *)); #define VEGETARIAN_CLASS (MAXOCLASSES + 1) /* * Name prefix codes: * dash - female, personal name * underscore _ female, general name * plus + male, personal name * vertical bar | male, general name (implied for most of shktools) * equals = gender not specified, personal name * * Personal names do not receive the honorific prefix "Mr." or "Ms.". */ static const char *const shkliquors[] = { /* Ukraine */ "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka", /* Belarus */ "Gomel", /* N. Russia */ "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl", /* Silezie */ "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice", "Brzeg", "Krnov", "Hradec Kralove", /* Schweiz */ "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm", "Flims", "Vals", "Schuls", "Zum Loch", 0 }; static const char *const shkbooks[] = { /* Eire */ "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch", "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra", "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan", "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh", "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea", "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh", 0 }; static const char *const shkarmors[] = { /* Turquie */ "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep", "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak", "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt", "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni", "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat", "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan", 0 }; static const char *const shkwands[] = { /* Wales */ "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader", "Llandrindod", "Llanfair-ym-muallt", "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi", /* Scotland */ "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven", "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch", "Kyleakin", "Dunvegan", 0 }; static const char *const shkrings[] = { /* Hollandse familienamen */ "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken", "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy", "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix", "Ypey", /* Skandinaviske navne */ "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko", "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda", "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske", 0 }; static const char *const shkfoods[] = { /* Indonesia */ "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan", "Bandjar", "Parbalingga", "Bojolali", "Sarangan", "Ngebel", "Djombang", "Ardjawinangun", "Berbek", "Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi", "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan", "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe", "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe", 0 }; static const char *const shkweapons[] = { /* Perigord */ "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard", "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac", "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac", "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac", "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon", "Eymoutiers", "Eygurande", "Eauze", "Labouheyre", 0 }; static const char *const shktools[] = { /* Spmi */ "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj", "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil", "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar", "Yelpur", "Nosnehpets", "Stewe", "Renrut", "-Zlaw", "Nosalnef", "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah", "Corsh", "Aned", "Niknar", "Lapu", "Lechaim", "Rebrol-nek", "AlliWar Wickson", "Oguhmk", #ifdef OVERLAY "Erreip", "Nehpets", "Mron", "Snivek", "Kahztiy", #endif #ifdef WIN32 "Lexa", "Niod", #endif #ifdef MAC "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s", "Yao-hang", "Tonbar", "Kivenhoug", "Llardom", #endif #ifdef AMIGA "Falo", "Nosid-da\'r", "Ekim-p", "Noslo", "Yl-rednow", "Mured-oog", "Ivrajimsal", #endif #ifdef TOS "Nivram", #endif #ifdef OS2 "Nedraawi-nav", #endif #ifdef VMS "Lez-tneg", "Ytnu-haled", #endif 0 }; static const char *const shklight[] = { /* Romania */ "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu", "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt", "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia", /* Bulgaria */ "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli", "Pernik", "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo", "Troyan", "Lovech", "Sliven", 0 }; static const char *const shkgeneral[] = { /* Suriname */ "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi", "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo", "Akalapi", "Sipaliwini", /* Greenland */ "Annootok", "Upernavik", "Angmagssalik", /* N. Canada */ "Aklavik", "Inuvik", "Tuktoyaktuk", "Chicoutimi", "Ouiatchouane", "Chibougamau", "Matagami", "Kipawa", "Kinojevis", "Abitibi", "Maganasipi", /* Iceland */ "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri", "Holmavik", 0 }; static const char *const shkhealthfoods[] = { /* Tibet */ "Ga'er", "Zhangmu", "Rikaze", "Jiangji", "Changdu", "Linzhi", "Shigatse", "Gyantse", "Ganden", "Tsurphu", "Lhasa", "Tsedong", "Drepung", /* Hippie names */ "=Azura", "=Blaze", "=Breanna", "=Breezy", "=Dharma", "=Feather", "=Jasmine", "=Luna", "=Melody", "=Moonjava", "=Petal", "=Rhiannon", "=Starla", "=Tranquilla", "=Windsong", "=Zennia", "=Zoe", "=Zora", 0 }; /* * To add new shop types, all that is necessary is to edit the shtypes[] * array. See mkroom.h for the structure definition. Typically, you'll * have to lower some or all of the probability fields in old entries to * free up some percentage for the new type. * * The placement type field is not yet used but will be in the near future. * * The iprobs array in each entry defines the probabilities for various kinds * of objects to be present in the given shop type. You can associate with * each percentage either a generic object type (represented by one of the * *_CLASS macros) or a specific object (represented by an onames.h define). * In the latter case, prepend it with a unary minus so the code can know * (by testing the sign) whether to use mkobj() or mksobj(). */ const struct shclass shtypes[] = { { "general store", RANDOM_CLASS, 42, D_SHOP, { { 100, RANDOM_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkgeneral }, { "used armor dealership", ARMOR_CLASS, 14, D_SHOP, { { 90, ARMOR_CLASS }, { 10, WEAPON_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkarmors }, { "second-hand bookstore", SCROLL_CLASS, 10, D_SHOP, { { 90, SCROLL_CLASS }, { 10, SPBOOK_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkbooks }, { "liquor emporium", POTION_CLASS, 10, D_SHOP, { { 100, POTION_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkliquors }, { "antique weapons outlet", WEAPON_CLASS, 5, D_SHOP, { { 90, WEAPON_CLASS }, { 10, ARMOR_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkweapons }, { "delicatessen", FOOD_CLASS, 5, D_SHOP, { { 83, FOOD_CLASS }, { 5, -POT_FRUIT_JUICE }, { 4, -POT_BOOZE }, { 5, -POT_WATER }, { 3, -ICE_BOX }, { 0, 0 } }, shkfoods }, { "jewelers", RING_CLASS, 3, D_SHOP, { { 85, RING_CLASS }, { 10, GEM_CLASS }, { 5, AMULET_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkrings }, { "quality apparel and accessories", WAND_CLASS, 3, D_SHOP, { { 90, WAND_CLASS }, { 5, -LEATHER_GLOVES }, { 5, -ELVEN_CLOAK }, { 0, 0 } }, shkwands }, { "hardware store", TOOL_CLASS, 3, D_SHOP, { { 100, TOOL_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shktools }, { "rare books", SPBOOK_CLASS, 3, D_SHOP, { { 90, SPBOOK_CLASS }, { 10, SCROLL_CLASS }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, shkbooks }, { "health food store", FOOD_CLASS, 2, D_SHOP, { { 70, VEGETARIAN_CLASS }, { 20, -POT_FRUIT_JUICE }, { 4, -POT_HEALING }, { 3, -POT_FULL_HEALING }, { 2, -SCR_FOOD_DETECTION }, { 1, -LUMP_OF_ROYAL_JELLY } }, shkhealthfoods }, /* Shops below this point are "unique". That is they must all have a * probability of zero. They are only created via the special level * loader. */ { "lighting store", TOOL_CLASS, 0, D_SHOP, { { 30, -WAX_CANDLE }, { 48, -TALLOW_CANDLE }, { 5, -BRASS_LANTERN }, { 9, -OIL_LAMP }, { 3, -MAGIC_LAMP }, { 5, -POT_OIL } }, shklight }, /* sentinel */ { (char *) 0, 0, 0, 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 0 } }; #if 0 /* validate shop probabilities; otherwise incorrect local changes could end up provoking infinite loops or wild subscripts fetching garbage */ void init_shop_selection() { register int i, j, item_prob, shop_prob; for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) { shop_prob += shtypes[i].prob; for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++) item_prob += shtypes[i].iprobs[j].iprob; if (item_prob != 100) panic("item probabilities total to %d for %s shops!", item_prob, shtypes[i].name); } if (shop_prob != 100) panic("shop probabilities total to %d!", shop_prob); } #endif /*0*/ /* decide whether an object or object type is considered vegetarian; for types, items which might go either way are assumed to be veggy */ STATIC_OVL boolean veggy_item(obj, otyp) struct obj *obj; int otyp; /* used iff obj is null */ { int corpsenm; char oclass; if (obj) { /* actual object; will check tin content and corpse species */ otyp = (int) obj->otyp; oclass = obj->oclass; corpsenm = obj->corpsenm; } else { /* just a type; caller will have to handle tins and corpses */ oclass = objects[otyp].oc_class; corpsenm = PM_LICHEN; /* veggy standin */ } if (oclass == FOOD_CLASS) { if (objects[otyp].oc_material == VEGGY || otyp == EGG) return TRUE; if (otyp == TIN && corpsenm == NON_PM) /* implies obj is non-null */ return (boolean) (obj->spe == 1); /* 0 = empty, 1 = spinach */ if (otyp == TIN || otyp == CORPSE) return (boolean) (corpsenm >= LOW_PM && vegetarian(&mons[corpsenm])); } return FALSE; } STATIC_OVL int shkveg() { int i, j, maxprob, prob; char oclass = FOOD_CLASS; int ok[NUM_OBJECTS]; j = maxprob = 0; ok[0] = 0; /* lint suppression */ for (i = bases[(int) oclass]; i < NUM_OBJECTS; ++i) { if (objects[i].oc_class != oclass) break; if (veggy_item((struct obj *) 0, i)) { ok[j++] = i; maxprob += objects[i].oc_prob; } } if (maxprob < 1) panic("shkveg no veggy objects"); prob = rnd(maxprob); j = 0; i = ok[0]; while ((prob -= objects[i].oc_prob) > 0) { j++; i = ok[j]; } if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) panic("shkveg probtype error, oclass=%d i=%d", (int) oclass, i); return i; } /* make a random item for health food store */ STATIC_OVL void mkveggy_at(sx, sy) int sx, sy; { struct obj *obj = mksobj_at(shkveg(), sx, sy, TRUE, TRUE); if (obj && obj->otyp == TIN) set_tin_variety(obj, HEALTHY_TIN); return; } /* make an object of the appropriate type for a shop square */ STATIC_OVL void mkshobj_at(shp, sx, sy, mkspecl) const struct shclass *shp; int sx, sy; boolean mkspecl; { struct monst *mtmp; struct permonst *ptr; int atype; /* 3.6.0 tribute */ if (mkspecl && (!strcmp(shp->name, "rare books") || !strcmp(shp->name, "second-hand bookstore"))) { struct obj *novel = mksobj_at(SPE_NOVEL, sx, sy, FALSE, FALSE); if (novel) context.tribute.bookstock = TRUE; return; } if (rn2(100) < depth(&u.uz) && !MON_AT(sx, sy) && (ptr = mkclass(S_MIMIC, 0)) != 0 && (mtmp = makemon(ptr, sx, sy, NO_MM_FLAGS)) != 0) { /* note: makemon will set the mimic symbol to a shop item */ if (rn2(10) >= depth(&u.uz)) { mtmp->m_ap_type = M_AP_OBJECT; mtmp->mappearance = STRANGE_OBJECT; } } else { atype = get_shop_item((int) (shp - shtypes)); if (atype == VEGETARIAN_CLASS) mkveggy_at(sx, sy); else if (atype < 0) (void) mksobj_at(-atype, sx, sy, TRUE, TRUE); else (void) mkobj_at(atype, sx, sy, TRUE); } } /* extract a shopkeeper name for the given shop type */ STATIC_OVL void nameshk(shk, nlp) struct monst *shk; const char *const *nlp; { int i, trycnt, names_avail; const char *shname = 0; struct monst *mtmp; int name_wanted; s_level *sptr; if (nlp == shkfoods && In_mines(&u.uz) && Role_if(PM_MONK) && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) { /* special-case override for minetown food store for monks */ nlp = shkhealthfoods; } if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) { /* special-case minetown lighting shk */ shname = "+Izchak"; shk->female = FALSE; } else { /* We want variation from game to game, without needing the save and restore support which would be necessary for randomization; try not to make too many assumptions about time_t's internals; use ledger_no rather than depth to keep mine town distinct. */ int nseed = (int) ((long) ubirthday / 257L); name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5); if (name_wanted < 0) name_wanted += (13 + 5); shk->female = name_wanted & 1; for (names_avail = 0; nlp[names_avail]; names_avail++) continue; for (trycnt = 0; trycnt < 50; trycnt++) { if (nlp == shktools) { shname = shktools[rn2(names_avail)]; shk->female = 0; /* reversed below for '_' prefix */ } else if (name_wanted < names_avail) { shname = nlp[name_wanted]; } else if ((i = rn2(names_avail)) != 0) { shname = nlp[i - 1]; } else if (nlp != shkgeneral) { nlp = shkgeneral; /* try general names */ for (names_avail = 0; nlp[names_avail]; names_avail++) continue; continue; /* next `trycnt' iteration */ } else { shname = shk->female ? "-Lucrezia" : "+Dirk"; } if (*shname == '_' || *shname == '-') shk->female = 1; else if (*shname == '|' || *shname == '+') shk->female = 0; /* is name already in use on this level? */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk) continue; if (strcmp(ESHK(mtmp)->shknam, shname)) continue; break; } if (!mtmp) break; /* new name */ } } (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ); ESHK(shk)->shknam[PL_NSIZ - 1] = 0; } void neweshk(mtmp) struct monst *mtmp; { if (!mtmp->mextra) mtmp->mextra = newmextra(); if (!ESHK(mtmp)) ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk)); (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk)); ESHK(mtmp)->bill_p = (struct bill_x *) 0; } void free_eshk(mtmp) struct monst *mtmp; { if (mtmp->mextra && ESHK(mtmp)) { free((genericptr_t) ESHK(mtmp)); ESHK(mtmp) = (struct eshk *) 0; } mtmp->isshk = 0; } /* create a new shopkeeper in the given room */ STATIC_OVL int shkinit(shp, sroom) const struct shclass *shp; struct mkroom *sroom; { register int sh, sx, sy; struct monst *shk; struct eshk *eshkp; /* place the shopkeeper in the given room */ sh = sroom->fdoor; sx = doors[sh].x; sy = doors[sh].y; /* check that the shopkeeper placement is sane */ if (sroom->irregular) { int rmno = (int) ((sroom - rooms) + ROOMOFFSET); if (isok(sx - 1, sy) && !levl[sx - 1][sy].edge && (int) levl[sx - 1][sy].roomno == rmno) sx--; else if (isok(sx + 1, sy) && !levl[sx + 1][sy].edge && (int) levl[sx + 1][sy].roomno == rmno) sx++; else if (isok(sx, sy - 1) && !levl[sx][sy - 1].edge && (int) levl[sx][sy - 1].roomno == rmno) sy--; else if (isok(sx, sy + 1) && !levl[sx][sy + 1].edge && (int) levl[sx][sy + 1].roomno == rmno) sx++; else goto shk_failed; } else if (sx == sroom->lx - 1) sx++; else if (sx == sroom->hx + 1) sx--; else if (sy == sroom->ly - 1) sy++; else if (sy == sroom->hy + 1) sy--; else { shk_failed: #ifdef DEBUG /* Said to happen sometimes, but I have never seen it. */ /* Supposedly fixed by fdoor change in mklev.c */ if (wizard) { register int j = sroom->doorct; pline("Where is shopdoor?"); pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx, sroom->hy); pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct, sh); while (j--) { pline("door [%d,%d]", doors[sh].x, doors[sh].y); sh++; } display_nhwindow(WIN_MESSAGE, FALSE); } #endif return -1; } if (MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */ /* now initialize the shopkeeper monster structure */ if (!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK))) return -1; eshkp = ESHK(shk); /* makemon(...,MM_ESHK) allocates this */ shk->isshk = shk->mpeaceful = 1; set_malign(shk); shk->msleeping = 0; shk->mtrapseen = ~0; /* we know all the traps already */ eshkp->shoproom = (schar) ((sroom - rooms) + ROOMOFFSET); sroom->resident = shk; eshkp->shoptype = sroom->rtype; assign_level(&eshkp->shoplevel, &u.uz); eshkp->shd = doors[sh]; eshkp->shk.x = sx; eshkp->shk.y = sy; eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L; eshkp->following = eshkp->surcharge = eshkp->dismiss_kops = FALSE; eshkp->billct = eshkp->visitct = 0; eshkp->bill_p = (struct bill_x *) 0; eshkp->customer[0] = '\0'; mkmonmoney(shk, 1000L + 30L * (long) rnd(100)); /* initial capital */ if (shp->shknms == shkrings) (void) mongets(shk, TOUCHSTONE); nameshk(shk, shp->shknms); return sh; } /* stock a newly-created room with objects */ void stock_room(shp_indx, sroom) int shp_indx; register struct mkroom *sroom; { /* * Someday soon we'll dispatch on the shdist field of shclass to do * different placements in this routine. Currently it only supports * shop-style placement (all squares except a row nearest the first * door get objects). */ int sx, sy, sh; int stockcount = 0, specialspot = 0; char buf[BUFSZ]; int rmno = (int) ((sroom - rooms) + ROOMOFFSET); const struct shclass *shp = &shtypes[shp_indx]; /* first, try to place a shopkeeper in the room */ if ((sh = shkinit(shp, sroom)) < 0) return; /* make sure no doorways without doors, and no trapped doors, in shops */ sx = doors[sroom->fdoor].x; sy = doors[sroom->fdoor].y; if (levl[sx][sy].doormask == D_NODOOR) { levl[sx][sy].doormask = D_ISOPEN; newsym(sx, sy); } if (levl[sx][sy].typ == SDOOR) { cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */ newsym(sx, sy); } if (levl[sx][sy].doormask & D_TRAPPED) levl[sx][sy].doormask = D_LOCKED; if (levl[sx][sy].doormask == D_LOCKED) { register int m = sx, n = sy; if (inside_shop(sx + 1, sy)) m--; else if (inside_shop(sx - 1, sy)) m++; if (inside_shop(sx, sy + 1)) n--; else if (inside_shop(sx, sy - 1)) n++; Sprintf(buf, "Closed for inventory"); make_engr_at(m, n, buf, 0L, DUST); } if (context.tribute.enabled && !context.tribute.bookstock) { /* * Out of the number of spots where we're actually * going to put stuff, randomly single out one in particular. */ for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) { if (sroom->irregular) { if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1) continue; } else if ((sx == sroom->lx && doors[sh].x == sx - 1) || (sx == sroom->hx && doors[sh].x == sx + 1) || (sy == sroom->ly && doors[sh].y == sy - 1) || (sy == sroom->hy && doors[sh].y == sy + 1)) continue; stockcount++; } specialspot = rnd(stockcount); stockcount = 0; } for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) { if (sroom->irregular) { if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1) continue; } else if ((sx == sroom->lx && doors[sh].x == sx - 1) || (sx == sroom->hx && doors[sh].x == sx + 1) || (sy == sroom->ly && doors[sh].y == sy - 1) || (sy == sroom->hy && doors[sh].y == sy + 1)) continue; stockcount++; mkshobj_at(shp, sx, sy, ((stockcount) && (stockcount == specialspot))); } /* * Special monster placements (if any) should go here: that way, * monsters will sit on top of objects and not the other way around. */ level.flags.has_shop = TRUE; } /* does shkp's shop stock this item type? */ boolean saleable(shkp, obj) struct monst *shkp; struct obj *obj; { int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE; const struct shclass *shp = &shtypes[shp_indx]; if (shp->symb == RANDOM_CLASS) return TRUE; for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++) { /* pseudo-class needs special handling */ if (shp->iprobs[i].itype == VEGETARIAN_CLASS) { if (veggy_item(obj, 0)) return TRUE; } else if ((shp->iprobs[i].itype < 0) ? shp->iprobs[i].itype == -obj->otyp : shp->iprobs[i].itype == obj->oclass) return TRUE; } /* not found */ return FALSE; } /* positive value: class; negative value: specific object type */ int get_shop_item(type) int type; { const struct shclass *shp = shtypes + type; register int i, j; /* select an appropriate object type at random */ for (j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++) continue; return shp->iprobs[i].itype; } const char * shkname(mtmp) struct monst *mtmp; { const char *shknm = ESHK(mtmp)->shknam; if (Hallucination && !program_state.gameover) { const char *const *nlp; int num; /* count the number of non-unique shop types; pick one randomly, ignoring shop generation probabilities; pick a name at random from that shop type's list */ for (num = 0; num < SIZE(shtypes); num++) if (shtypes[num].prob == 0) break; if (num > 0) { nlp = shtypes[rn2(num)].shknms; for (num = 0; nlp[num]; num++) continue; if (num > 0) shknm = nlp[rn2(num)]; } } /* strip prefix if present */ if (!letter(*shknm)) ++shknm; return shknm; } boolean shkname_is_pname(mtmp) struct monst *mtmp; { const char *shknm = ESHK(mtmp)->shknam; return (boolean) (*shknm == '-' || *shknm == '+' || *shknm == '='); } boolean is_izchak(shkp, override_hallucination) struct monst *shkp; boolean override_hallucination; { const char *shknm; if (Hallucination && !override_hallucination) return FALSE; if (!shkp->isshk) return FALSE; /* outside of town, Izchak becomes just an ordinary shopkeeper */ if (!in_town(shkp->mx, shkp->my)) return FALSE; shknm = ESHK(shkp)->shknam; /* skip "+" prefix */ if (!letter(*shknm)) ++shknm; return (boolean) !strcmp(shknm, "Izchak"); } /*shknam.c*/ nethack-3.6.0/src/sit.c0000664000076400007660000003676012613624165013711 0ustar paxedpaxed/* NetHack 3.6 sit.c $NHDT-Date: 1445906863 2015/10/27 00:47:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" /* take away the hero's money */ void take_gold() { struct obj *otmp, *nobj; int lost_money = 0; for (otmp = invent; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->oclass == COIN_CLASS) { lost_money = 1; remove_worn_item(otmp, FALSE); delobj(otmp); } } if (!lost_money) { You_feel("a strange sensation."); } else { You("notice you have no money!"); context.botl = 1; } } /* #sit command */ int dosit() { static const char sit_message[] = "sit on the %s."; register struct trap *trap = t_at(u.ux, u.uy); register int typ = levl[u.ux][u.uy].typ; if (u.usteed) { You("are already sitting on %s.", mon_nam(u.usteed)); return 0; } if (u.uundetected && is_hider(youmonst.data) && u.umonnum != PM_TRAPPER) u.uundetected = 0; /* no longer on the ceiling */ if (!can_reach_floor(FALSE)) { if (u.uswallow) There("are no seats in here!"); else if (Levitation) You("tumble in place."); else You("are sitting on air."); return 0; } else if (u.ustuck && !sticks(youmonst.data)) { /* holding monster is next to hero rather than beneath, but hero is in no condition to actually sit at has/her own spot */ if (humanoid(u.ustuck->data)) pline("%s won't offer %s lap.", Monnam(u.ustuck), mhis(u.ustuck)); else pline("%s has no lap.", Monnam(u.ustuck)); return 0; } else if (is_pool(u.ux, u.uy) && !Underwater) { /* water walking */ goto in_water; } if (OBJ_AT(u.ux, u.uy) /* ensure we're not standing on the precipice */ && !uteetering_at_seen_pit(trap)) { register struct obj *obj; obj = level.objects[u.ux][u.uy]; if (youmonst.data->mlet == S_DRAGON && obj->oclass == COIN_CLASS) { You("coil up around your %shoard.", (obj->quan + money_cnt(invent) < u.ulevel * 1000) ? "meager " : ""); } else { You("sit on %s.", the(xname(obj))); if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) pline("It's not very comfortable..."); } } else if (trap != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ if (u.utraptype == TT_BEARTRAP) { You_cant("sit down with your %s in the bear trap.", body_part(FOOT)); u.utrap++; } else if (u.utraptype == TT_PIT) { if (trap && trap->ttyp == SPIKED_PIT) { You("sit down on a spike. Ouch!"); losehp(Half_physical_damage ? rn2(2) : 1, "sitting on an iron spike", KILLED_BY); exercise(A_STR, FALSE); } else You("sit down in the pit."); u.utrap += rn2(5); } else if (u.utraptype == TT_WEB) { You("sit in the spider web and get entangled further!"); u.utrap += rn1(10, 5); } else if (u.utraptype == TT_LAVA) { /* Must have fire resistance or they'd be dead already */ You("sit in the lava!"); if (Slimed) burn_away_slime(); u.utrap += rnd(4); losehp(d(2, 10), "sitting in lava", KILLED_BY); /* lava damage */ } else if (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL) { You_cant("maneuver to sit!"); u.utrap++; } } else { You("sit down."); dotrap(trap, 0); } } else if (Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) There("are no cushions floating nearby."); else You("sit down on the muddy bottom."); } else if (is_pool(u.ux, u.uy)) { in_water: You("sit in the water."); if (!rn2(10) && uarm) (void) water_damage(uarm, "armor", TRUE); if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS) (void) water_damage(uarm, "armor", TRUE); } else if (IS_SINK(typ)) { You(sit_message, defsyms[S_sink].explanation); Your("%s gets wet.", humanoid(youmonst.data) ? "rump" : "underside"); } else if (IS_ALTAR(typ)) { You(sit_message, defsyms[S_altar].explanation); altar_wrath(u.ux, u.uy); } else if (IS_GRAVE(typ)) { You(sit_message, defsyms[S_grave].explanation); } else if (typ == STAIRS) { You(sit_message, "stairs"); } else if (typ == LADDER) { You(sit_message, "ladder"); } else if (is_lava(u.ux, u.uy)) { /* must be WWalking */ You(sit_message, "lava"); burn_away_slime(); if (likes_lava(youmonst.data)) { pline_The("lava feels warm."); return 1; } pline_The("lava burns you!"); losehp(d((Fire_resistance ? 2 : 10), 10), /* lava damage */ "sitting on lava", KILLED_BY); } else if (is_ice(u.ux, u.uy)) { You(sit_message, defsyms[S_ice].explanation); if (!Cold_resistance) pline_The("ice feels cold."); } else if (typ == DRAWBRIDGE_DOWN) { You(sit_message, "drawbridge"); } else if (IS_THRONE(typ)) { You(sit_message, defsyms[S_throne].explanation); if (rnd(6) > 4) { switch (rnd(13)) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4, 3), FALSE); losehp(rnd(10), "cursed throne", KILLED_BY_AN); break; case 2: (void) adjattrib(rn2(A_MAX), 1, FALSE); break; case 3: pline("A%s electric shock shoots through your body!", (Shock_resistance) ? "n" : " massive"); losehp(Shock_resistance ? rnd(6) : rnd(30), "electric chair", KILLED_BY_AN); exercise(A_CON, FALSE); break; case 4: You_feel("much, much better!"); if (Upolyd) { if (u.mh >= (u.mhmax - 5)) u.mhmax += 4; u.mh = u.mhmax; } if (u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; u.uhp = u.uhpmax; make_blinded(0L, TRUE); make_sick(0L, (char *) 0, FALSE, SICK_ALL); heal_legs(); context.botl = 1; break; case 5: take_gold(); break; case 6: if (u.uluck + rn2(5) < 0) { You_feel("your luck is changing."); change_luck(1); } else makewish(); break; case 7: { int cnt = rnd(10); /* Magical voice not affected by deafness */ pline("A voice echoes:"); verbalize("Thy audience hath been summoned, %s!", flags.female ? "Dame" : "Sire"); while (cnt--) (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); break; } case 8: /* Magical voice not affected by deafness */ pline("A voice echoes:"); verbalize("By thine Imperious order, %s...", flags.female ? "Dame" : "Sire"); do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */ break; case 9: /* Magical voice not affected by deafness */ pline("A voice echoes:"); verbalize( "A curse upon thee for sitting upon this most holy throne!"); if (Luck > 0) { make_blinded(Blinded + rn1(100, 250), TRUE); } else rndcurse(); break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { if (level.flags.nommap) { pline("A terrible drone fills your head!"); make_confused((HConfusion & TIMEOUT) + (long) rnd(30), FALSE); } else { pline("An image forms in your mind."); do_mapping(); } } else { Your("vision becomes clear."); HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); } break; case 11: if (Luck < 0) { You_feel("threatened."); aggravate(); } else { You_feel("a wrenching sensation."); tele(); /* teleport him */ } break; case 12: You("are granted an insight!"); if (invent) { /* rn2(5) agrees w/seffects() */ identify_pack(rn2(5), FALSE); } break; case 13: Your("mind turns into a pretzel!"); make_confused((HConfusion & TIMEOUT) + (long) rn1(7, 16), FALSE); break; default: impossible("throne effect"); break; } } else { if (is_prince(youmonst.data)) You_feel("very comfortable here."); else You_feel("somehow out of place..."); } if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ levl[u.ux][u.uy].typ = ROOM; pline_The("throne vanishes in a puff of logic."); newsym(u.ux, u.uy); } } else if (lays_eggs(youmonst.data)) { struct obj *uegg; if (!flags.female) { pline("%s can't lay eggs!", Hallucination ? "You may think you are a platypus, but a male still" : "Males"); return 0; } else if (u.uhunger < (int) objects[EGG].oc_nutrition) { You("don't have enough energy to lay an egg."); return 0; } uegg = mksobj(EGG, FALSE, FALSE); uegg->spe = 1; uegg->quan = 1L; uegg->owt = weight(uegg); /* this sets hatch timers if appropriate */ set_corpsenm(uegg, egg_type_from_parent(u.umonnum, FALSE)); uegg->known = uegg->dknown = 1; You("lay an egg."); dropy(uegg); stackobj(uegg); morehungry((int) objects[EGG].oc_nutrition); } else { pline("Having fun sitting on the %s?", surface(u.ux, u.uy)); } return 1; } /* curse a few inventory items at random! */ void rndcurse() { int nobj = 0; int cnt, onum; struct obj *otmp; static const char mal_aura[] = "feel a malignant aura surround %s."; if (uwep && (uwep->oartifact == ART_MAGICBANE) && rn2(20)) { You(mal_aura, "the magic-absorbing blade"); return; } if (Antimagic) { shieldeff(u.ux, u.uy); You(mal_aura, "you"); } for (otmp = invent; otmp; otmp = otmp->nobj) { /* gold isn't subject to being cursed or blessed */ if (otmp->oclass == COIN_CLASS) continue; nobj++; } if (nobj) { for (cnt = rnd(6 / ((!!Antimagic) + (!!Half_spell_damage) + 1)); cnt > 0; cnt--) { onum = rnd(nobj); for (otmp = invent; otmp; otmp = otmp->nobj) { /* as above */ if (otmp->oclass == COIN_CLASS) continue; if (--onum == 0) break; /* found the target */ } /* the !otmp case should never happen; picking an already cursed item happens--avoid "resists" message in that case */ if (!otmp || otmp->cursed) continue; /* next target */ if (otmp->oartifact && spec_ability(otmp, SPFX_INTEL) && rn2(10) < 8) { pline("%s!", Tobjnam(otmp, "resist")); continue; } if (otmp->blessed) unbless(otmp); else curse(otmp); } update_inventory(); } /* treat steed's saddle as extended part of hero's inventory */ if (u.usteed && !rn2(4) && (otmp = which_armor(u.usteed, W_SADDLE)) != 0 && !otmp->cursed) { /* skip if already cursed */ if (otmp->blessed) unbless(otmp); else curse(otmp); if (!Blind) { pline("%s %s.", Yobjnam2(otmp, "glow"), hcolor(otmp->cursed ? NH_BLACK : (const char *) "brown")); otmp->bknown = TRUE; } } } /* remove a random INTRINSIC ability */ void attrcurse() { switch (rnd(11)) { case 1: if (HFire_resistance & INTRINSIC) { HFire_resistance &= ~INTRINSIC; You_feel("warmer."); break; } case 2: if (HTeleportation & INTRINSIC) { HTeleportation &= ~INTRINSIC; You_feel("less jumpy."); break; } case 3: if (HPoison_resistance & INTRINSIC) { HPoison_resistance &= ~INTRINSIC; You_feel("a little sick!"); break; } case 4: if (HTelepat & INTRINSIC) { HTelepat &= ~INTRINSIC; if (Blind && !Blind_telepat) see_monsters(); /* Can't sense mons anymore! */ Your("senses fail!"); break; } case 5: if (HCold_resistance & INTRINSIC) { HCold_resistance &= ~INTRINSIC; You_feel("cooler."); break; } case 6: if (HInvis & INTRINSIC) { HInvis &= ~INTRINSIC; You_feel("paranoid."); break; } case 7: if (HSee_invisible & INTRINSIC) { HSee_invisible &= ~INTRINSIC; You("%s!", Hallucination ? "tawt you taw a puttie tat" : "thought you saw something"); break; } case 8: if (HFast & INTRINSIC) { HFast &= ~INTRINSIC; You_feel("slower."); break; } case 9: if (HStealth & INTRINSIC) { HStealth &= ~INTRINSIC; You_feel("clumsy."); break; } case 10: /* intrinsic protection is just disabled, not set back to 0 */ if (HProtection & INTRINSIC) { HProtection &= ~INTRINSIC; You_feel("vulnerable."); break; } case 11: if (HAggravate_monster & INTRINSIC) { HAggravate_monster &= ~INTRINSIC; You_feel("less attractive."); break; } default: break; } } /*sit.c*/ nethack-3.6.0/src/sounds.c0000664000076400007660000011425712616615700014421 0ustar paxedpaxed/* NetHack 3.6 sounds.c $NHDT-Date: 1446713641 2015/11/05 08:54:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.74 $ */ /* Copyright (c) 1989 Janet Walz, Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL boolean FDECL(mon_is_gecko, (struct monst *)); STATIC_DCL int FDECL(domonnoise, (struct monst *)); STATIC_DCL int NDECL(dochat); STATIC_DCL int FDECL(mon_in_room, (struct monst *, int)); /* this easily could be a macro, but it might overtax dumb compilers */ STATIC_OVL int mon_in_room(mon, rmtyp) struct monst *mon; int rmtyp; { int rno = levl[mon->mx][mon->my].roomno; if (rno >= ROOMOFFSET) return rooms[rno - ROOMOFFSET].rtype == rmtyp; return FALSE; } void dosounds() { register struct mkroom *sroom; register int hallu, vx, vy; #if defined(AMIGA) && defined(AZTEC_C_WORKAROUND) int xx; #endif struct monst *mtmp; if (Deaf || !flags.acoustics || u.uswallow || Underwater) return; hallu = Hallucination ? 1 : 0; if (level.flags.nfountains && !rn2(400)) { static const char *const fountain_msg[4] = { "bubbling water.", "water falling on coins.", "the splashing of a naiad.", "a soda fountain!", }; You_hear1(fountain_msg[rn2(3) + hallu]); } if (level.flags.nsinks && !rn2(300)) { static const char *const sink_msg[3] = { "a slow drip.", "a gurgling noise.", "dishes being washed!", }; You_hear1(sink_msg[rn2(2) + hallu]); } if (level.flags.has_court && !rn2(200)) { static const char *const throne_msg[4] = { "the tones of courtly conversation.", "a sceptre pounded in judgment.", "Someone shouts \"Off with %s head!\"", "Queen Beruthiel's cats!", }; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->msleeping || is_lord(mtmp->data) || is_prince(mtmp->data)) && !is_animal(mtmp->data) && mon_in_room(mtmp, COURT)) { /* finding one is enough, at least for now */ int which = rn2(3) + hallu; if (which != 2) You_hear1(throne_msg[which]); else pline(throne_msg[2], uhis()); return; } } } if (level.flags.has_swamp && !rn2(200)) { static const char *const swamp_msg[3] = { "hear mosquitoes!", "smell marsh gas!", /* so it's a smell...*/ "hear Donald Duck!", }; You1(swamp_msg[rn2(2) + hallu]); return; } if (level.flags.has_vault && !rn2(200)) { if (!(sroom = search_special(VAULT))) { /* strange ... */ level.flags.has_vault = 0; return; } if (gd_sound()) switch (rn2(2) + hallu) { case 1: { boolean gold_in_vault = FALSE; for (vx = sroom->lx; vx <= sroom->hx; vx++) for (vy = sroom->ly; vy <= sroom->hy; vy++) if (g_at(vx, vy)) gold_in_vault = TRUE; #if defined(AMIGA) && defined(AZTEC_C_WORKAROUND) /* Bug in aztec assembler here. Workaround below */ xx = ROOM_INDEX(sroom) + ROOMOFFSET; xx = (xx != vault_occupied(u.urooms)); if (xx) #else if (vault_occupied(u.urooms) != (ROOM_INDEX(sroom) + ROOMOFFSET)) #endif /* AZTEC_C_WORKAROUND */ { if (gold_in_vault) You_hear(!hallu ? "someone counting money." : "the quarterback calling the play."); else You_hear("someone searching."); break; } /* fall into... (yes, even for hallucination) */ } case 0: You_hear("the footsteps of a guard on patrol."); break; case 2: You_hear("Ebenezer Scrooge!"); break; } return; } if (level.flags.has_beehive && !rn2(200)) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data->mlet == S_ANT && is_flyer(mtmp->data)) && mon_in_room(mtmp, BEEHIVE)) { switch (rn2(2) + hallu) { case 0: You_hear("a low buzzing."); break; case 1: You_hear("an angry drone."); break; case 2: You_hear("bees in your %sbonnet!", uarmh ? "" : "(nonexistent) "); break; } return; } } } if (level.flags.has_morgue && !rn2(200)) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((is_undead(mtmp->data) || is_vampshifter(mtmp)) && mon_in_room(mtmp, MORGUE)) { const char *hair = body_part(HAIR); /* hair/fur/scales */ switch (rn2(2) + hallu) { case 0: You("suddenly realize it is unnaturally quiet."); break; case 1: pline_The("%s on the back of your %s %s up.", hair, body_part(NECK), vtense(hair, "stand")); break; case 2: pline_The("%s on your %s %s to stand up.", hair, body_part(HEAD), vtense(hair, "seem")); break; } return; } } } if (level.flags.has_barracks && !rn2(200)) { static const char *const barracks_msg[4] = { "blades being honed.", "loud snoring.", "dice being thrown.", "General MacArthur!", }; int count = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_mercenary(mtmp->data) #if 0 /* don't bother excluding these */ && !strstri(mtmp->data->mname, "watch") && !strstri(mtmp->data->mname, "guard") #endif && mon_in_room(mtmp, BARRACKS) /* sleeping implies not-yet-disturbed (usually) */ && (mtmp->msleeping || ++count > 5)) { You_hear1(barracks_msg[rn2(3) + hallu]); return; } } } if (level.flags.has_zoo && !rn2(200)) { static const char *const zoo_msg[3] = { "a sound reminiscent of an elephant stepping on a peanut.", "a sound reminiscent of a seal barking.", "Doctor Dolittle!", }; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->msleeping || is_animal(mtmp->data)) && mon_in_room(mtmp, ZOO)) { You_hear1(zoo_msg[rn2(2) + hallu]); return; } } } if (level.flags.has_shop && !rn2(200)) { if (!(sroom = search_special(ANY_SHOP))) { /* strange... */ level.flags.has_shop = 0; return; } if (tended_shop(sroom) && !index(u.ushops, (int) (ROOM_INDEX(sroom) + ROOMOFFSET))) { static const char *const shop_msg[3] = { "someone cursing shoplifters.", "the chime of a cash register.", "Neiman and Marcus arguing!", }; You_hear1(shop_msg[rn2(2) + hallu]); } return; } if (level.flags.has_temple && !rn2(200) && !(Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->ispriest && inhistemple(mtmp) /* priest must be active */ && mtmp->mcanmove && !mtmp->msleeping /* hero must be outside this temple */ && temple_occupied(u.urooms) != EPRI(mtmp)->shroom) break; } if (mtmp) { /* Generic temple messages; no attempt to match topic or tone to the pantheon involved, let alone to the specific deity. These are assumed to be coming from the attending priest; asterisk means that the priest must be capable of speech; pound sign (octathorpe,&c--don't go there) means that the priest and the altar must not be directly visible (we don't care if telepathy or extended detection reveals that the priest is not currently standing on the altar; he's mobile). */ static const char *const temple_msg[] = { "*someone praising %s.", "*someone beseeching %s.", "#an animal carcass being offered in sacrifice.", "*a strident plea for donations.", }; const char *msg; int trycount = 0, ax = EPRI(mtmp)->shrpos.x, ay = EPRI(mtmp)->shrpos.y; boolean speechless = (mtmp->data->msound <= MS_ANIMAL), in_sight = canseemon(mtmp) || cansee(ax, ay); do { msg = temple_msg[rn2(SIZE(temple_msg) - 1 + hallu)]; if (index(msg, '*') && speechless) continue; if (index(msg, '#') && in_sight) continue; break; /* msg is acceptable */ } while (++trycount < 50); while (!letter(*msg)) ++msg; /* skip control flags */ if (index(msg, '%')) You_hear(msg, halu_gname(EPRI(mtmp)->shralign)); else You_hear1(msg); return; } } if (Is_oracle_level(&u.uz) && !rn2(400)) { /* make sure the Oracle is still here */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->data == &mons[PM_ORACLE]) break; } /* and don't produce silly effects when she's clearly visible */ if (mtmp && (hallu || !canseemon(mtmp))) { static const char *const ora_msg[5] = { "a strange wind.", /* Jupiter at Dodona */ "convulsive ravings.", /* Apollo at Delphi */ "snoring snakes.", /* AEsculapius at Epidaurus */ "someone say \"No more woodchucks!\"", "a loud ZOT!" /* both rec.humor.oracle */ }; You_hear1(ora_msg[rn2(3) + hallu * 2]); } return; } } static const char *const h_sounds[] = { "beep", "boing", "sing", "belche", "creak", "cough", "rattle", "ululate", "pop", "jingle", "sniffle", "tinkle", "eep", "clatter", "hum", "sizzle", "twitter", "wheeze", "rustle", "honk", "lisp", "yodel", "coo", "burp", "moo", "boom", "murmur", "oink", "quack", "rumble", "twang", "bellow", "toot", "gargle", "hoot", "warble" }; const char * growl_sound(mtmp) register struct monst *mtmp; { const char *ret; switch (mtmp->data->msound) { case MS_MEW: case MS_HISS: ret = "hiss"; break; case MS_BARK: case MS_GROWL: ret = "growl"; break; case MS_ROAR: ret = "roar"; break; case MS_BUZZ: ret = "buzz"; break; case MS_SQEEK: ret = "squeal"; break; case MS_SQAWK: ret = "screech"; break; case MS_NEIGH: ret = "neigh"; break; case MS_WAIL: ret = "wail"; break; case MS_SILENT: ret = "commotion"; break; default: ret = "scream"; } return ret; } /* the sounds of a seriously abused pet, including player attacking it */ void growl(mtmp) register struct monst *mtmp; { register const char *growl_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) return; /* presumably nearness and soundok checks have already been made */ if (Hallucination) growl_verb = h_sounds[rn2(SIZE(h_sounds))]; else growl_verb = growl_sound(mtmp); if (growl_verb) { pline("%s %s!", Monnam(mtmp), vtense((char *) 0, growl_verb)); if (context.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18); } } /* the sounds of mistreated pets */ void yelp(mtmp) register struct monst *mtmp; { register const char *yelp_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) return; /* presumably nearness and soundok checks have already been made */ if (Hallucination) yelp_verb = h_sounds[rn2(SIZE(h_sounds))]; else switch (mtmp->data->msound) { case MS_MEW: yelp_verb = "yowl"; break; case MS_BARK: case MS_GROWL: yelp_verb = "yelp"; break; case MS_ROAR: yelp_verb = "snarl"; break; case MS_SQEEK: yelp_verb = "squeal"; break; case MS_SQAWK: yelp_verb = "screak"; break; case MS_WAIL: yelp_verb = "wail"; break; } if (yelp_verb) { pline("%s %s!", Monnam(mtmp), vtense((char *) 0, yelp_verb)); if (context.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 12); } } /* the sounds of distressed pets */ void whimper(mtmp) register struct monst *mtmp; { register const char *whimper_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) return; /* presumably nearness and soundok checks have already been made */ if (Hallucination) whimper_verb = h_sounds[rn2(SIZE(h_sounds))]; else switch (mtmp->data->msound) { case MS_MEW: case MS_GROWL: whimper_verb = "whimper"; break; case MS_BARK: whimper_verb = "whine"; break; case MS_SQEEK: whimper_verb = "squeal"; break; } if (whimper_verb) { pline("%s %s.", Monnam(mtmp), vtense((char *) 0, whimper_verb)); if (context.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 6); } } /* pet makes "I'm hungry" noises */ void beg(mtmp) register struct monst *mtmp; { if (mtmp->msleeping || !mtmp->mcanmove || !(carnivorous(mtmp->data) || herbivorous(mtmp->data))) return; /* presumably nearness and soundok checks have already been made */ if (!is_silent(mtmp->data) && mtmp->data->msound <= MS_ANIMAL) (void) domonnoise(mtmp); else if (mtmp->data->msound >= MS_HUMANOID) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); verbalize("I'm hungry."); } } /* return True if mon is a gecko or seems to look like one (hallucination) */ STATIC_OVL boolean mon_is_gecko(mon) struct monst *mon; { int glyph; /* return True if it is actually a gecko */ if (mon->data == &mons[PM_GECKO]) return TRUE; /* return False if it is a long worm; we might be chatting to its tail (not strictly needed; long worms are MS_SILENT so won't get here) */ if (mon->data == &mons[PM_LONG_WORM]) return FALSE; /* result depends upon whether map spot shows a gecko, which will be due to hallucination or to mimickery since mon isn't one */ glyph = glyph_at(mon->mx, mon->my); return (boolean) (glyph_to_mon(glyph) == PM_GECKO); } STATIC_OVL int domonnoise(mtmp) register struct monst *mtmp; { char verbuf[BUFSZ]; register const char *pline_msg = 0, /* Monnam(mtmp) will be prepended */ *verbl_msg = 0, /* verbalize() */ *verbl_msg_mcan = 0; /* verbalize() if cancelled */ struct permonst *ptr = mtmp->data; int msound = ptr->msound; /* presumably nearness and sleep checks have already been made */ if (Deaf) return 0; if (is_silent(ptr)) return 0; /* leader might be poly'd; if he can still speak, give leader speech */ if (mtmp->m_id == quest_status.leader_m_id && msound > MS_ANIMAL) msound = MS_LEADER; /* make sure it's your role's quest guardian; adjust if not */ else if (msound == MS_GUARDIAN && ptr != &mons[urole.guardnum]) msound = mons[genus(monsndx(ptr), 1)].msound; /* some normally non-speaking types can/will speak if hero is similar */ else if (msound == MS_ORC /* note: MS_ORC is same as MS_GRUNT */ && (same_race(ptr, youmonst.data) /* current form, */ || same_race(ptr, &mons[Race_switch]))) /* unpoly'd form */ msound = MS_HUMANOID; /* silliness, with slight chance to interfere with shopping */ else if (Hallucination && mon_is_gecko(mtmp)) msound = MS_SELL; /* be sure to do this before talking; the monster might teleport away, in * which case we want to check its pre-teleport position */ if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); switch (msound) { case MS_ORACLE: return doconsult(mtmp); case MS_PRIEST: priest_talk(mtmp); break; case MS_LEADER: case MS_NEMESIS: case MS_GUARDIAN: quest_chat(mtmp); break; case MS_SELL: /* pitch, pay, total */ if (!Hallucination || (mtmp->isshk && !rn2(2))) { shk_chat(mtmp); } else { /* approximation of GEICO's advertising slogan (it actually concludes with "save you 15% or more on car insurance.") */ Sprintf(verbuf, "15 minutes could save you 15 %s.", currency(15L)); /* "zorkmids" */ verbl_msg = verbuf; } break; case MS_VAMPIRE: { /* vampire messages are varied by tameness, peacefulness, and time of * night */ boolean isnight = night(); boolean kindred = (Upolyd && (u.umonnum == PM_VAMPIRE || u.umonnum == PM_VAMPIRE_LORD)); boolean nightchild = (Upolyd && (u.umonnum == PM_WOLF || u.umonnum == PM_WINTER_WOLF || u.umonnum == PM_WINTER_WOLF_CUB)); const char *racenoun = (flags.female && urace.individual.f) ? urace.individual.f : (urace.individual.m) ? urace.individual.m : urace.noun; if (mtmp->mtame) { if (kindred) { Sprintf(verbuf, "Good %s to you Master%s", isnight ? "evening" : "day", isnight ? "!" : ". Why do we not rest?"); verbl_msg = verbuf; } else { Sprintf(verbuf, "%s%s", nightchild ? "Child of the night, " : "", midnight() ? "I can stand this craving no longer!" : isnight ? "I beg you, help me satisfy this growing craving!" : "I find myself growing a little weary."); verbl_msg = verbuf; } } else if (mtmp->mpeaceful) { if (kindred && isnight) { Sprintf(verbuf, "Good feeding %s!", flags.female ? "sister" : "brother"); verbl_msg = verbuf; } else if (nightchild && isnight) { Sprintf(verbuf, "How nice to hear you, child of the night!"); verbl_msg = verbuf; } else verbl_msg = "I only drink... potions."; } else { int vampindex; static const char *const vampmsg[] = { /* These first two (0 and 1) are specially handled below */ "I vant to suck your %s!", "I vill come after %s without regret!", /* other famous vampire quotes can follow here if desired */ }; if (kindred) verbl_msg = "This is my hunting ground that you dare to prowl!"; else if (youmonst.data == &mons[PM_SILVER_DRAGON] || youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) { /* Silver dragons are silver in color, not made of silver */ Sprintf(verbuf, "%s! Your silver sheen does not frighten me!", youmonst.data == &mons[PM_SILVER_DRAGON] ? "Fool" : "Young Fool"); verbl_msg = verbuf; } else { vampindex = rn2(SIZE(vampmsg)); if (vampindex == 0) { Sprintf(verbuf, vampmsg[vampindex], body_part(BLOOD)); verbl_msg = verbuf; } else if (vampindex == 1) { Sprintf(verbuf, vampmsg[vampindex], Upolyd ? an(mons[u.umonnum].mname) : an(racenoun)); verbl_msg = verbuf; } else verbl_msg = vampmsg[vampindex]; } } } break; case MS_WERE: if (flags.moonphase == FULL_MOON && (night() ^ !rn2(13))) { pline("%s throws back %s head and lets out a blood curdling %s!", Monnam(mtmp), mhis(mtmp), ptr == &mons[PM_HUMAN_WERERAT] ? "shriek" : "howl"); wake_nearto(mtmp->mx, mtmp->my, 11 * 11); } else pline_msg = "whispers inaudibly. All you can make out is \"moon\"."; break; case MS_BARK: if (flags.moonphase == FULL_MOON && night()) { pline_msg = "howls."; } else if (mtmp->mpeaceful) { if (mtmp->mtame && (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5)) pline_msg = "whines."; else if (mtmp->mtame && EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "yips."; else { if (mtmp->data != &mons[PM_DINGO]) /* dingos do not actually bark */ pline_msg = "barks."; } } else { pline_msg = "growls."; } break; case MS_MEW: if (mtmp->mtame) { if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || mtmp->mtame < 5) pline_msg = "yowls."; else if (moves > EDOG(mtmp)->hungrytime) pline_msg = "meows."; else if (EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "purrs."; else pline_msg = "mews."; break; } /* else FALLTHRU */ case MS_GROWL: pline_msg = mtmp->mpeaceful ? "snarls." : "growls!"; break; case MS_ROAR: pline_msg = mtmp->mpeaceful ? "snarls." : "roars!"; break; case MS_SQEEK: pline_msg = "squeaks."; break; case MS_SQAWK: if (ptr == &mons[PM_RAVEN] && !mtmp->mpeaceful) verbl_msg = "Nevermore!"; else pline_msg = "squawks."; break; case MS_HISS: if (!mtmp->mpeaceful) pline_msg = "hisses!"; else return 0; /* no sound */ break; case MS_BUZZ: pline_msg = mtmp->mpeaceful ? "drones." : "buzzes angrily."; break; case MS_GRUNT: pline_msg = "grunts."; break; case MS_NEIGH: if (mtmp->mtame < 5) pline_msg = "neighs."; else if (moves > EDOG(mtmp)->hungrytime) pline_msg = "whinnies."; else pline_msg = "whickers."; break; case MS_WAIL: pline_msg = "wails mournfully."; break; case MS_GURGLE: pline_msg = "gurgles."; break; case MS_BURBLE: pline_msg = "burbles."; break; case MS_SHRIEK: pline_msg = "shrieks."; aggravate(); break; case MS_IMITATE: pline_msg = "imitates you."; break; case MS_BONES: pline("%s rattles noisily.", Monnam(mtmp)); You("freeze for a moment."); nomul(-2); multi_reason = "scared by rattling"; nomovemsg = 0; break; case MS_LAUGH: { static const char *const laugh_msg[4] = { "giggles.", "chuckles.", "snickers.", "laughs.", }; pline_msg = laugh_msg[rn2(4)]; } break; case MS_MUMBLE: pline_msg = "mumbles incomprehensibly."; break; case MS_DJINNI: if (mtmp->mtame) { verbl_msg = "Sorry, I'm all out of wishes."; } else if (mtmp->mpeaceful) { if (ptr == &mons[PM_WATER_DEMON]) pline_msg = "gurgles."; else verbl_msg = "I'm free!"; } else { if (ptr != &mons[PM_PRISONER]) verbl_msg = "This will teach you not to disturb me!"; #if 0 else verbl_msg = "??????????"; #endif } break; case MS_BOAST: /* giants */ if (!mtmp->mpeaceful) { switch (rn2(4)) { case 0: pline("%s boasts about %s gem collection.", Monnam(mtmp), mhis(mtmp)); break; case 1: pline_msg = "complains about a diet of mutton."; break; default: pline_msg = "shouts \"Fee Fie Foe Foo!\" and guffaws."; wake_nearto(mtmp->mx, mtmp->my, 7 * 7); break; } break; } /* else FALLTHRU */ case MS_HUMANOID: if (!mtmp->mpeaceful) { if (In_endgame(&u.uz) && is_mplayer(ptr)) mplayer_talk(mtmp); else pline_msg = "threatens you."; break; } /* Generic peaceful humanoid behaviour. */ if (mtmp->mflee) pline_msg = "wants nothing to do with you."; else if (mtmp->mhp < mtmp->mhpmax / 4) pline_msg = "moans."; else if (mtmp->mconf || mtmp->mstun) verbl_msg = !rn2(3) ? "Huh?" : rn2(2) ? "What?" : "Eh?"; else if (!mtmp->mcansee) verbl_msg = "I can't see!"; else if (mtmp->mtrapped) { struct trap *t = t_at(mtmp->mx, mtmp->my); if (t) t->tseen = 1; verbl_msg = "I'm trapped!"; } else if (mtmp->mhp < mtmp->mhpmax / 2) pline_msg = "asks for a potion of healing."; else if (mtmp->mtame && !mtmp->isminion && moves > EDOG(mtmp)->hungrytime) verbl_msg = "I'm hungry."; /* Specific monsters' interests */ else if (is_elf(ptr)) pline_msg = "curses orcs."; else if (is_dwarf(ptr)) pline_msg = "talks about mining."; else if (likes_magic(ptr)) pline_msg = "talks about spellcraft."; else if (ptr->mlet == S_CENTAUR) pline_msg = "discusses hunting."; else switch (monsndx(ptr)) { case PM_HOBBIT: pline_msg = (mtmp->mhpmax - mtmp->mhp >= 10) ? "complains about unpleasant dungeon conditions." : "asks you about the One Ring."; break; case PM_ARCHEOLOGIST: pline_msg = "describes a recent article in \"Spelunker Today\" magazine."; break; case PM_TOURIST: verbl_msg = "Aloha."; break; default: pline_msg = "discusses dungeon exploration."; break; } break; case MS_SEDUCE: { int swval; if (SYSOPT_SEDUCE) { if (ptr->mlet != S_NYMPH && could_seduce(mtmp, &youmonst, (struct attack *) 0) == 1) { (void) doseduce(mtmp); break; } swval = ((poly_gender() != (int) mtmp->female) ? rn2(3) : 0); } else swval = ((poly_gender() == 0) ? rn2(3) : 0); switch (swval) { case 2: verbl_msg = "Hello, sailor."; break; case 1: pline_msg = "comes on to you."; break; default: pline_msg = "cajoles you."; } } break; case MS_ARREST: if (mtmp->mpeaceful) verbalize("Just the facts, %s.", flags.female ? "Ma'am" : "Sir"); else { static const char *const arrest_msg[3] = { "Anything you say can be used against you.", "You're under arrest!", "Stop in the name of the Law!", }; verbl_msg = arrest_msg[rn2(3)]; } break; case MS_BRIBE: if (mtmp->mpeaceful && !mtmp->mtame) { (void) demon_talk(mtmp); break; } /* fall through */ case MS_CUSS: if (!mtmp->mpeaceful) cuss(mtmp); else if (is_lminion(mtmp)) verbl_msg = "It's not too late."; else verbl_msg = "We're all doomed."; break; case MS_SPELL: /* deliberately vague, since it's not actually casting any spell */ pline_msg = "seems to mutter a cantrip."; break; case MS_NURSE: verbl_msg_mcan = "I hate this job!"; if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) verbl_msg = "Put that weapon away before you hurt someone!"; else if (uarmc || uarm || uarmh || uarms || uarmg || uarmf) verbl_msg = Role_if(PM_HEALER) ? "Doc, I can't help you unless you cooperate." : "Please undress so I can examine you."; else if (uarmu) verbl_msg = "Take off your shirt, please."; else verbl_msg = "Relax, this won't hurt a bit."; break; case MS_GUARD: if (money_cnt(invent)) verbl_msg = "Please drop that gold and follow me."; else verbl_msg = "Please follow me."; break; case MS_SOLDIER: { static const char *const soldier_foe_msg[3] = { "Resistance is useless!", "You're dog meat!", "Surrender!", }, *const soldier_pax_msg[3] = { "What lousy pay we're getting here!", "The food's not fit for Orcs!", "My feet hurt, I've been on them all day!", }; verbl_msg = mtmp->mpeaceful ? soldier_pax_msg[rn2(3)] : soldier_foe_msg[rn2(3)]; break; } case MS_RIDER: /* 3.6.0 tribute */ if (ptr == &mons[PM_DEATH] && !context.tribute.Deathnotice && u_have_novel()) { struct obj *book = u_have_novel(); const char *tribtitle = (char *)0; if (book) { int novelidx = book->novelidx; tribtitle = noveltitle(&novelidx); } if (tribtitle) { Sprintf(verbuf, "Ah, so you have a copy of /%s/.", tribtitle); /* no Death featured in these two, so exclude them */ if (!(strcmpi(tribtitle, "Snuff") == 0 || strcmpi(tribtitle, "The Wee Free Men") == 0)) Strcat(verbuf, " I may have been misquoted there."); verbl_msg = verbuf; context.tribute.Deathnotice = 1; } } else if (ptr == &mons[PM_DEATH] && !rn2(2) && Death_quote(verbuf, BUFSZ)) { verbl_msg = verbuf; } /* end of tribute addition */ else if (ptr == &mons[PM_DEATH] && !rn2(10)) pline_msg = "is busy reading a copy of Sandman #8."; else verbl_msg = "Who do you think you are, War?"; break; } if (pline_msg) pline("%s %s", Monnam(mtmp), pline_msg); else if (mtmp->mcan && verbl_msg_mcan) verbalize1(verbl_msg_mcan); else if (verbl_msg) { if (ptr == &mons[PM_DEATH]) { /* Death talks in CAPITAL LETTERS and without quotation marks */ char tmpbuf[BUFSZ]; Sprintf(tmpbuf, "%s", verbl_msg); pline1(ucase(tmpbuf)); } else { verbalize1(verbl_msg); } } return 1; } /* #chat command */ int dotalk() { int result; result = dochat(); return result; } STATIC_OVL int dochat() { struct monst *mtmp; int tx, ty; struct obj *otmp; if (is_silent(youmonst.data)) { pline("As %s, you cannot speak.", an(youmonst.data->mname)); return 0; } if (Strangled) { You_cant("speak. You're choking!"); return 0; } if (u.uswallow) { pline("They won't hear you out there."); return 0; } if (Underwater) { Your("speech is unintelligible underwater."); return 0; } if (Deaf) { pline("How can you hold a conversation when you cannot hear?"); return 0; } if (!Blind && (otmp = shop_object(u.ux, u.uy)) != (struct obj *) 0) { /* standing on something in a shop and chatting causes the shopkeeper to describe the price(s). This can inhibit other chatting inside a shop, but that shouldn't matter much. shop_object() returns an object iff inside a shop and the shopkeeper is present and willing (not angry) and able (not asleep) to speak and the position contains any objects other than just gold. */ price_quote(otmp); return 1; } if (!getdir("Talk to whom? (in what direction)")) { /* decided not to chat */ return 0; } if (u.usteed && u.dz > 0) { if (!u.usteed->mcanmove || u.usteed->msleeping) { pline("%s seems not to notice you.", Monnam(u.usteed)); return 1; } else return domonnoise(u.usteed); } if (u.dz) { pline("They won't hear you %s there.", u.dz < 0 ? "up" : "down"); return 0; } if (u.dx == 0 && u.dy == 0) { /* * Let's not include this. * It raises all sorts of questions: can you wear * 2 helmets, 2 amulets, 3 pairs of gloves or 6 rings as a marilith, * etc... --KAA if (u.umonnum == PM_ETTIN) { You("discover that your other head makes boring conversation."); return 1; } */ pline("Talking to yourself is a bad habit for a dungeoneer."); return 0; } tx = u.ux + u.dx; ty = u.uy + u.dy; if (!isok(tx, ty)) return 0; mtmp = m_at(tx, ty); if ((!mtmp || mtmp->mundetected) && (otmp = vobj_at(tx, ty)) != 0 && otmp->otyp == STATUE) { /* Talking to a statue */ if (!Blind) { pline_The("%s seems not to notice you.", /* if hallucinating, you can't tell it's a statue */ Hallucination ? rndmonnam((char *) 0) : "statue"); } return 0; } if (!mtmp || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) return 0; /* sleeping monsters won't talk, except priests (who wake up) */ if ((!mtmp->mcanmove || mtmp->msleeping) && !mtmp->ispriest) { /* If it is unseen, the player can't tell the difference between not noticing him and just not existing, so skip the message. */ if (canspotmon(mtmp)) pline("%s seems not to notice you.", Monnam(mtmp)); return 0; } /* if this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; if (mtmp->mtame && mtmp->meating) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); pline("%s is eating noisily.", Monnam(mtmp)); return 0; } return domonnoise(mtmp); } #ifdef USER_SOUNDS extern void FDECL(play_usersound, (const char *, int)); typedef struct audio_mapping_rec { struct nhregex *regex; char *filename; int volume; struct audio_mapping_rec *next; } audio_mapping; static audio_mapping *soundmap = 0; char *sounddir = "."; /* adds a sound file mapping, returns 0 on failure, 1 on success */ int add_sound_mapping(mapping) const char *mapping; { char text[256]; char filename[256]; char filespec[256]; int volume; if (sscanf(mapping, "MESG \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d", text, filename, &volume) == 3) { audio_mapping *new_map; if (strlen(sounddir) + strlen(filename) > 254) { raw_print("sound file name too long"); return 0; } Sprintf(filespec, "%s/%s", sounddir, filename); if (can_read_file(filespec)) { new_map = (audio_mapping *) alloc(sizeof(audio_mapping)); new_map->regex = regex_init(); new_map->filename = dupstr(filespec); new_map->volume = volume; new_map->next = soundmap; if (!regex_compile(text, new_map->regex)) { raw_print(regex_error_desc(new_map->regex)); regex_free(new_map->regex); free(new_map->filename); free(new_map); return 0; } else { soundmap = new_map; } } else { Sprintf(text, "cannot read %.243s", filespec); raw_print(text); return 0; } } else { raw_print("syntax error in SOUND"); return 0; } return 1; } void play_sound_for_message(msg) const char *msg; { audio_mapping *cursor = soundmap; while (cursor) { if (regex_match(msg, cursor->regex)) { play_usersound(cursor->filename, cursor->volume); } cursor = cursor->next; } } #endif /* USER_SOUNDS */ /*sounds.c*/ nethack-3.6.0/src/sp_lev.c0000664000076400007660000050740712631241231014370 0ustar paxedpaxed/* NetHack 3.6 sp_lev.c $NHDT-Date: 1449269920 2015/12/04 22:58:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the various functions that are related to the special * levels. * * It contains also the special level loader. */ #include "hack.h" #include "dlb.h" #include "sp_lev.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) #endif typedef void FDECL((*select_iter_func), (int, int, genericptr)); extern void FDECL(mkmap, (lev_init *)); STATIC_DCL void NDECL(solidify_map); STATIC_DCL void FDECL(splev_stack_init, (struct splevstack *)); STATIC_DCL void FDECL(splev_stack_done, (struct splevstack *)); STATIC_DCL void FDECL(splev_stack_push, (struct splevstack *, struct opvar *)); STATIC_DCL struct opvar *FDECL(splev_stack_pop, (struct splevstack *)); STATIC_DCL struct splevstack *FDECL(splev_stack_reverse, (struct splevstack *)); STATIC_DCL struct opvar *FDECL(opvar_new_str, (char *)); STATIC_DCL struct opvar *FDECL(opvar_new_int, (long)); STATIC_DCL struct opvar *FDECL(opvar_new_coord, (int, int)); #if 0 STATIC_DCL struct opvar * FDECL(opvar_new_region, (int,int, int,int)); #endif /*0*/ STATIC_DCL void FDECL(opvar_free_x, (struct opvar *)); STATIC_DCL struct opvar *FDECL(opvar_clone, (struct opvar *)); STATIC_DCL struct opvar *FDECL(opvar_var_conversion, (struct sp_coder *, struct opvar *)); STATIC_DCL struct splev_var *FDECL(opvar_var_defined, (struct sp_coder *, char *)); STATIC_DCL struct opvar *FDECL(splev_stack_getdat, (struct sp_coder *, XCHAR_P)); STATIC_DCL struct opvar *FDECL(splev_stack_getdat_any, (struct sp_coder *)); STATIC_DCL void FDECL(variable_list_del, (struct splev_var *)); STATIC_DCL void FDECL(lvlfill_maze_grid, (int, int, int, int, SCHAR_P)); STATIC_DCL void FDECL(lvlfill_solid, (SCHAR_P, SCHAR_P)); STATIC_DCL void FDECL(set_wall_property, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, int)); STATIC_DCL void NDECL(shuffle_alignments); STATIC_DCL void NDECL(count_features); STATIC_DCL void NDECL(remove_boundary_syms); STATIC_DCL void FDECL(maybe_add_door, (int, int, struct mkroom *)); STATIC_DCL void NDECL(link_doors_rooms); STATIC_DCL void NDECL(fill_rooms); STATIC_DCL int NDECL(rnddoor); STATIC_DCL int NDECL(rndtrap); STATIC_DCL void FDECL(get_location, (schar *, schar *, int, struct mkroom *)); STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int)); STATIC_DCL unpacked_coord FDECL(get_unpacked_coord, (long, int)); STATIC_DCL void FDECL(get_location_coord, (schar *, schar *, int, struct mkroom *, long)); STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *)); STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *, packed_coord)); STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *)); STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *)); STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P)); STATIC_DCL boolean FDECL(m_bad_boulder_spot, (int, int)); STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *)); STATIC_DCL void FDECL(create_object, (object *, struct mkroom *)); STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *)); STATIC_DCL void FDECL(replace_terrain, (replaceterrain *, struct mkroom *)); STATIC_DCL boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *, XCHAR_P, int)); STATIC_DCL void NDECL(fix_stair_rooms); STATIC_DCL void FDECL(create_corridor, (corridor *)); STATIC_DCL struct mkroom *FDECL(build_room, (room *, struct mkroom *)); STATIC_DCL void FDECL(light_region, (region *)); STATIC_DCL void FDECL(wallify_map, (int, int, int, int)); STATIC_DCL void FDECL(maze1xy, (coord *, int)); STATIC_DCL void NDECL(fill_empty_maze); STATIC_DCL boolean FDECL(sp_level_loader, (dlb *, sp_lev *)); STATIC_DCL boolean FDECL(sp_level_free, (sp_lev *)); STATIC_DCL void FDECL(splev_initlev, (lev_init *)); STATIC_DCL struct sp_frame *FDECL(frame_new, (long)); STATIC_DCL void FDECL(frame_del, (struct sp_frame *)); STATIC_DCL void FDECL(spo_frame_push, (struct sp_coder *)); STATIC_DCL void FDECL(spo_frame_pop, (struct sp_coder *)); STATIC_DCL long FDECL(sp_code_jmpaddr, (long, long)); STATIC_DCL void FDECL(spo_call, (struct sp_coder *)); STATIC_DCL void FDECL(spo_return, (struct sp_coder *)); STATIC_DCL void FDECL(spo_end_moninvent, (struct sp_coder *)); STATIC_DCL void FDECL(spo_pop_container, (struct sp_coder *)); STATIC_DCL void FDECL(spo_message, (struct sp_coder *)); STATIC_DCL void FDECL(spo_monster, (struct sp_coder *)); STATIC_DCL void FDECL(spo_object, (struct sp_coder *)); STATIC_DCL void FDECL(spo_level_flags, (struct sp_coder *)); STATIC_DCL void FDECL(spo_initlevel, (struct sp_coder *)); STATIC_DCL void FDECL(spo_engraving, (struct sp_coder *)); STATIC_DCL void FDECL(spo_mineralize, (struct sp_coder *)); STATIC_DCL void FDECL(spo_room, (struct sp_coder *)); STATIC_DCL void FDECL(spo_endroom, (struct sp_coder *)); STATIC_DCL void FDECL(spo_stair, (struct sp_coder *)); STATIC_DCL void FDECL(spo_ladder, (struct sp_coder *)); STATIC_DCL void FDECL(spo_grave, (struct sp_coder *)); STATIC_DCL void FDECL(spo_altar, (struct sp_coder *)); STATIC_DCL void FDECL(spo_trap, (struct sp_coder *)); STATIC_DCL void FDECL(spo_gold, (struct sp_coder *)); STATIC_DCL void FDECL(spo_corridor, (struct sp_coder *)); STATIC_DCL struct opvar *FDECL(selection_opvar, (char *)); STATIC_DCL xchar FDECL(selection_getpoint, (int, int, struct opvar *)); STATIC_DCL void FDECL(selection_setpoint, (int, int, struct opvar *, XCHAR_P)); STATIC_DCL struct opvar *FDECL(selection_not, (struct opvar *)); STATIC_DCL struct opvar *FDECL(selection_logical_oper, (struct opvar *, struct opvar *, CHAR_P)); STATIC_DCL struct opvar *FDECL(selection_filter_mapchar, (struct opvar *, struct opvar *)); STATIC_DCL void FDECL(selection_filter_percent, (struct opvar *, int)); STATIC_DCL int FDECL(selection_rndcoord, (struct opvar *, schar *, schar *, BOOLEAN_P)); STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int)); STATIC_DCL void FDECL(set_selection_floodfillchk, (int FDECL((*), (int,int)))); STATIC_DCL int FDECL(floodfillchk_match_under, (int, int)); STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int)); STATIC_DCL void FDECL(selection_floodfill, (struct opvar *, int, int, BOOLEAN_P)); STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int, int, int, int)); STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long)); STATIC_DCL void FDECL(selection_do_gradient, (struct opvar *, long, long, long, long, long, long, long, long)); STATIC_DCL void FDECL(selection_do_line, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P, struct opvar *)); STATIC_DCL void FDECL(selection_do_randline, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P, struct opvar *)); STATIC_DCL void FDECL(selection_iterate, (struct opvar *, select_iter_func, genericptr_t)); STATIC_DCL void FDECL(sel_set_ter, (int, int, genericptr_t)); STATIC_DCL void FDECL(sel_set_feature, (int, int, genericptr_t)); STATIC_DCL void FDECL(sel_set_door, (int, int, genericptr_t)); STATIC_DCL void FDECL(spo_door, (struct sp_coder *)); STATIC_DCL void FDECL(spo_feature, (struct sp_coder *)); STATIC_DCL void FDECL(spo_terrain, (struct sp_coder *)); STATIC_DCL void FDECL(spo_replace_terrain, (struct sp_coder *)); STATIC_DCL boolean FDECL(generate_way_out_method, (int, int, struct opvar *)); STATIC_DCL void NDECL(ensure_way_out); STATIC_DCL void FDECL(spo_levregion, (struct sp_coder *)); STATIC_DCL void FDECL(spo_region, (struct sp_coder *)); STATIC_DCL void FDECL(spo_drawbridge, (struct sp_coder *)); STATIC_DCL void FDECL(spo_mazewalk, (struct sp_coder *)); STATIC_DCL void FDECL(spo_wall_property, (struct sp_coder *)); STATIC_DCL void FDECL(spo_room_door, (struct sp_coder *)); STATIC_DCL void FDECL(sel_set_wallify, (int, int, genericptr_t)); STATIC_DCL void FDECL(spo_wallify, (struct sp_coder *)); STATIC_DCL void FDECL(spo_map, (struct sp_coder *)); STATIC_DCL void FDECL(spo_jmp, (struct sp_coder *, sp_lev *)); STATIC_DCL void FDECL(spo_conditional_jump, (struct sp_coder *, sp_lev *)); STATIC_DCL void FDECL(spo_var_init, (struct sp_coder *)); #if 0 STATIC_DCL long FDECL(opvar_array_length, (struct sp_coder *)); #endif /*0*/ STATIC_DCL void FDECL(spo_shuffle_array, (struct sp_coder *)); STATIC_DCL boolean FDECL(sp_level_coder, (sp_lev *)); #define LEFT 1 #define H_LEFT 2 #define CENTER 3 #define H_RIGHT 4 #define RIGHT 5 #define TOP 1 #define BOTTOM 5 #define sq(x) ((x) * (x)) #define XLIM 4 #define YLIM 3 #define Fread (void) dlb_fread #define Fgetc (schar) dlb_fgetc #define New(type) (type *) alloc(sizeof(type)) #define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned) size) #define Free(ptr) if (ptr) free((genericptr_t) (ptr)) extern struct engr *head_engr; extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */ /* positions touched by level elements explicitly defined in the des-file */ static char SpLev_Map[COLNO][ROWNO]; static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL }; static NEARDATA xchar xstart, ystart; static NEARDATA char xsize, ysize; char *lev_message = 0; lev_region *lregions = 0; int num_lregions = 0; boolean splev_init_present = FALSE; boolean icedpools = FALSE; struct obj *container_obj[MAX_CONTAINMENT]; int container_idx = 0; struct monst *invent_carrying_monster = NULL; #define SPLEV_STACK_RESERVE 128 void solidify_map() { xchar x, y; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (IS_STWALL(levl[x][y].typ) && !SpLev_Map[x][y]) levl[x][y].wall_info |= (W_NONDIGGABLE | W_NONPASSWALL); } void splev_stack_init(st) struct splevstack *st; { if (st) { st->depth = 0; st->depth_alloc = SPLEV_STACK_RESERVE; st->stackdata = (struct opvar **) alloc(st->depth_alloc * sizeof(struct opvar *)); } } void splev_stack_done(st) struct splevstack *st; { if (st) { int i; if (st->stackdata && st->depth) { for (i = 0; i < st->depth; i++) { switch (st->stackdata[i]->spovartyp) { default: case SPOVAR_NULL: case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: break; case SPOVAR_VARIABLE: case SPOVAR_STRING: case SPOVAR_SEL: Free(st->stackdata[i]->vardata.str); st->stackdata[i]->vardata.str = NULL; break; } Free(st->stackdata[i]); st->stackdata[i] = NULL; } } Free(st->stackdata); st->stackdata = NULL; st->depth = st->depth_alloc = 0; Free(st); } } void splev_stack_push(st, v) struct splevstack *st; struct opvar *v; { if (!st || !v) return; if (!st->stackdata) panic("splev_stack_push: no stackdata allocated?"); if (st->depth >= st->depth_alloc) { struct opvar **tmp = (struct opvar **) alloc( (st->depth_alloc + SPLEV_STACK_RESERVE) * sizeof(struct opvar *)); (void) memcpy(tmp, st->stackdata, st->depth_alloc * sizeof(struct opvar *)); Free(st->stackdata); st->stackdata = tmp; st->depth_alloc += SPLEV_STACK_RESERVE; } st->stackdata[st->depth] = v; st->depth++; } struct opvar * splev_stack_pop(st) struct splevstack *st; { struct opvar *ret = NULL; if (!st) return ret; if (!st->stackdata) panic("splev_stack_pop: no stackdata allocated?"); if (st->depth) { st->depth--; ret = st->stackdata[st->depth]; st->stackdata[st->depth] = NULL; return ret; } else impossible("splev_stack_pop: empty stack?"); return ret; } struct splevstack * splev_stack_reverse(st) struct splevstack *st; { long i; struct opvar *tmp; if (!st) return NULL; if (!st->stackdata) panic("splev_stack_reverse: no stackdata allocated?"); for (i = 0; i < (st->depth / 2); i++) { tmp = st->stackdata[i]; st->stackdata[i] = st->stackdata[st->depth - i - 1]; st->stackdata[st->depth - i - 1] = tmp; } return st; } #define OV_typ(o) (o->spovartyp) #define OV_i(o) (o->vardata.l) #define OV_s(o) (o->vardata.str) #define OV_pop_i(x) (x = splev_stack_getdat(coder, SPOVAR_INT)) #define OV_pop_c(x) (x = splev_stack_getdat(coder, SPOVAR_COORD)) #define OV_pop_r(x) (x = splev_stack_getdat(coder, SPOVAR_REGION)) #define OV_pop_s(x) (x = splev_stack_getdat(coder, SPOVAR_STRING)) #define OV_pop(x) (x = splev_stack_getdat_any(coder)) #define OV_pop_typ(x, typ) (x = splev_stack_getdat(coder, typ)) struct opvar * opvar_new_str(s) char *s; { struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar)); tmpov->spovartyp = SPOVAR_STRING; if (s) { int len = strlen(s); tmpov->vardata.str = (char *) alloc(len + 1); (void) memcpy((genericptr_t) tmpov->vardata.str, (genericptr_t) s, len); tmpov->vardata.str[len] = '\0'; } else tmpov->vardata.str = NULL; return tmpov; } struct opvar * opvar_new_int(i) long i; { struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar)); tmpov->spovartyp = SPOVAR_INT; tmpov->vardata.l = i; return tmpov; } struct opvar * opvar_new_coord(x, y) int x, y; { struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar)); tmpov->spovartyp = SPOVAR_COORD; tmpov->vardata.l = SP_COORD_PACK(x, y); return tmpov; } #if 0 struct opvar * opvar_new_region(x1,y1,x2,y2) int x1,y1,x2,y2; { struct opvar *tmpov = (struct opvar *)alloc(sizeof (struct opvar)); tmpov->spovartyp = SPOVAR_REGION; tmpov->vardata.l = SP_REGION_PACK(x1,y1,x2,y2); return tmpov; } #endif /*0*/ void opvar_free_x(ov) struct opvar *ov; { if (!ov) return; switch (ov->spovartyp) { case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: break; case SPOVAR_VARIABLE: case SPOVAR_STRING: case SPOVAR_SEL: Free(ov->vardata.str); break; default: impossible("Unknown opvar value type (%i)!", ov->spovartyp); } Free(ov); } /* * Name of current function for use in messages: * __func__ -- C99 standard; * __FUNCTION__ -- gcc extension, starting before C99 and continuing after; * picked up by other compilers (or vice versa?); * __FUNC__ -- supported by Borland; * nhFunc -- slightly intrusive but fully portable nethack construct * for any version of any compiler. */ #define opvar_free(ov) \ do { \ if (ov) { \ opvar_free_x(ov); \ ov = NULL; \ } else \ impossible("opvar_free(), %s", nhFunc); \ } while (0) struct opvar * opvar_clone(ov) struct opvar *ov; { struct opvar *tmpov; if (!ov) panic("no opvar to clone"); tmpov = (struct opvar *) alloc(sizeof(struct opvar)); tmpov->spovartyp = ov->spovartyp; switch (ov->spovartyp) { case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: tmpov->vardata.l = ov->vardata.l; break; case SPOVAR_VARIABLE: case SPOVAR_STRING: case SPOVAR_SEL: tmpov->vardata.str = dupstr(ov->vardata.str); break; default: impossible("Unknown push value type (%i)!", ov->spovartyp); } return tmpov; } struct opvar * opvar_var_conversion(coder, ov) struct sp_coder *coder; struct opvar *ov; { static const char nhFunc[] = "opvar_var_conversion"; struct splev_var *tmp; struct opvar *tmpov; struct opvar *array_idx = NULL; if (!coder || !ov) return NULL; if (ov->spovartyp != SPOVAR_VARIABLE) return ov; tmp = coder->frame->variables; while (tmp) { if (!strcmp(tmp->name, OV_s(ov))) { if ((tmp->svtyp & SPOVAR_ARRAY)) { array_idx = opvar_var_conversion(coder, splev_stack_pop(coder->stack)); if (!array_idx || OV_typ(array_idx) != SPOVAR_INT) panic("array idx not an int"); if (tmp->array_len < 1) panic("array len < 1"); OV_i(array_idx) = (OV_i(array_idx) % tmp->array_len); tmpov = opvar_clone(tmp->data.arrayvalues[OV_i(array_idx)]); opvar_free(array_idx); return tmpov; } else { tmpov = opvar_clone(tmp->data.value); return tmpov; } } tmp = tmp->next; } return NULL; } struct splev_var * opvar_var_defined(coder, name) struct sp_coder *coder; char *name; { struct splev_var *tmp; if (!coder) return NULL; tmp = coder->frame->variables; while (tmp) { if (!strcmp(tmp->name, name)) return tmp; tmp = tmp->next; } return NULL; } struct opvar * splev_stack_getdat(coder, typ) struct sp_coder *coder; xchar typ; { static const char nhFunc[] = "splev_stack_getdat"; if (coder && coder->stack) { struct opvar *tmp = splev_stack_pop(coder->stack); struct opvar *ret = NULL; if (!tmp) panic("no value type %i in stack.", typ); if (tmp->spovartyp == SPOVAR_VARIABLE) { ret = opvar_var_conversion(coder, tmp); opvar_free(tmp); tmp = ret; } if (tmp->spovartyp == typ) return tmp; else opvar_free(tmp); } return NULL; } struct opvar * splev_stack_getdat_any(coder) struct sp_coder *coder; { static const char nhFunc[] = "splev_stack_getdat_any"; if (coder && coder->stack) { struct opvar *tmp = splev_stack_pop(coder->stack); if (tmp && tmp->spovartyp == SPOVAR_VARIABLE) { struct opvar *ret = opvar_var_conversion(coder, tmp); opvar_free(tmp); return ret; } return tmp; } return NULL; } void variable_list_del(varlist) struct splev_var *varlist; { static const char nhFunc[] = "variable_list_del"; struct splev_var *tmp = varlist; if (!tmp) return; while (tmp) { Free(tmp->name); if ((tmp->svtyp & SPOVAR_ARRAY)) { long idx = tmp->array_len; while (idx-- > 0) { opvar_free(tmp->data.arrayvalues[idx]); }; Free(tmp->data.arrayvalues); } else { opvar_free(tmp->data.value); } tmp = varlist->next; Free(varlist); varlist = tmp; } } void lvlfill_maze_grid(x1, y1, x2, y2, filling) int x1, y1, x2, y2; schar filling; { int x, y; for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) { if (level.flags.corrmaze) levl[x][y].typ = STONE; else levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE : filling; } } void lvlfill_solid(filling, lit) schar filling; schar lit; { int x, y; for (x = 2; x <= x_maze_max; x++) for (y = 0; y <= y_maze_max; y++) { SET_TYPLIT(x, y, filling, lit); } } /* * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able */ STATIC_OVL void set_wall_property(x1, y1, x2, y2, prop) xchar x1, y1, x2, y2; int prop; { register xchar x, y; for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++) for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++) if (IS_STWALL(levl[x][y].typ) || IS_TREE(levl[x][y].typ)) levl[x][y].wall_info |= prop; } STATIC_OVL void shuffle_alignments() { int i; aligntyp atmp; /* shuffle 3 alignments */ i = rn2(3); atmp = ralign[2]; ralign[2] = ralign[i]; ralign[i] = atmp; if (rn2(2)) { atmp = ralign[1]; ralign[1] = ralign[0]; ralign[0] = atmp; } } /* * Count the different features (sinks, fountains) in the level. */ STATIC_OVL void count_features() { xchar x, y; level.flags.nfountains = level.flags.nsinks = 0; for (y = 0; y < ROWNO; y++) for (x = 0; x < COLNO; x++) { int typ = levl[x][y].typ; if (typ == FOUNTAIN) level.flags.nfountains++; else if (typ == SINK) level.flags.nsinks++; } } void remove_boundary_syms() { /* * If any CROSSWALLs are found, must change to ROOM after REGION's * are laid out. CROSSWALLS are used to specify "invisible" * boundaries where DOOR syms look bad or aren't desirable. */ xchar x, y; boolean has_bounds = FALSE; for (x = 0; x < COLNO - 1; x++) for (y = 0; y < ROWNO - 1; y++) if (levl[x][y].typ == CROSSWALL) { has_bounds = TRUE; break; } if (has_bounds) { for (x = 0; x < x_maze_max; x++) for (y = 0; y < y_maze_max; y++) if ((levl[x][y].typ == CROSSWALL) && SpLev_Map[x][y]) levl[x][y].typ = ROOM; } } void maybe_add_door(x, y, droom) int x, y; struct mkroom *droom; { if (droom->hx >= 0 && doorindex < DOORMAX && inside_room(droom, x, y)) add_door(x, y, droom); } void link_doors_rooms() { int x, y; int tmpi, m; for (y = 0; y < ROWNO; y++) for (x = 0; x < COLNO; x++) if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) { for (tmpi = 0; tmpi < nroom; tmpi++) { maybe_add_door(x, y, &rooms[tmpi]); for (m = 0; m < rooms[tmpi].nsubrooms; m++) { maybe_add_door(x, y, rooms[tmpi].sbrooms[m]); } } } } void fill_rooms() { int tmpi; for (tmpi = 0; tmpi < nroom; tmpi++) { int m; if (rooms[tmpi].needfill) fill_room(&rooms[tmpi], (rooms[tmpi].needfill == 2)); for (m = 0; m < rooms[tmpi].nsubrooms; m++) if (rooms[tmpi].sbrooms[m]->needfill) fill_room(rooms[tmpi].sbrooms[m], FALSE); } } /* * Choose randomly the state (nodoor, open, closed or locked) for a door */ STATIC_OVL int rnddoor() { int i = 1 << rn2(5); i >>= 1; return i; } /* * Select a random trap */ STATIC_OVL int rndtrap() { int rtrap; do { rtrap = rnd(TRAPNUM - 1); switch (rtrap) { case HOLE: /* no random holes on special levels */ case VIBRATING_SQUARE: case MAGIC_PORTAL: rtrap = NO_TRAP; break; case TRAPDOOR: if (!Can_dig_down(&u.uz)) rtrap = NO_TRAP; break; case LEVEL_TELEP: case TELEP_TRAP: if (level.flags.noteleport) rtrap = NO_TRAP; break; case ROLLING_BOULDER_TRAP: case ROCKTRAP: if (In_endgame(&u.uz)) rtrap = NO_TRAP; break; } } while (rtrap == NO_TRAP); return rtrap; } /* * Coordinates in special level files are handled specially: * * if x or y is < 0, we generate a random coordinate. * The "humidity" flag is used to insure that engravings aren't * created underwater, or eels on dry land. */ STATIC_OVL void get_location(x, y, humidity, croom) schar *x, *y; int humidity; struct mkroom *croom; { int cpt = 0; int mx, my, sx, sy; if (croom) { mx = croom->lx; my = croom->ly; sx = croom->hx - mx + 1; sy = croom->hy - my + 1; } else { mx = xstart; my = ystart; sx = xsize; sy = ysize; } if (*x >= 0) { /* normal locations */ *x += mx; *y += my; } else { /* random location */ do { if (croom) { /* handle irregular areas */ coord tmpc; somexy(croom, &tmpc); *x = tmpc.x; *y = tmpc.y; } else { *x = mx + rn2((int) sx); *y = my + rn2((int) sy); } if (is_ok_location(*x, *y, humidity)) break; } while (++cpt < 100); if (cpt >= 100) { register int xx, yy; /* last try */ for (xx = 0; xx < sx; xx++) for (yy = 0; yy < sy; yy++) { *x = mx + xx; *y = my + yy; if (is_ok_location(*x, *y, humidity)) goto found_it; } if (!(humidity & NO_LOC_WARN)) { impossible("get_location: can't find a place!"); } else { *x = *y = -1; } } } found_it: ; if (!(humidity & ANY_LOC) && !isok(*x, *y)) { if (!(humidity & NO_LOC_WARN)) { /*warning("get_location: (%d,%d) out of bounds", *x, *y);*/ *x = x_maze_max; *y = y_maze_max; } else { *x = *y = -1; } } } STATIC_OVL boolean is_ok_location(x, y, humidity) register schar x, y; register int humidity; { register int typ; if (Is_waterlevel(&u.uz)) return TRUE; /* accept any spot */ /* TODO: Should perhaps check if wall is diggable/passwall? */ if (humidity & ANY_LOC) return TRUE; if ((humidity & SOLID) && IS_ROCK(levl[x][y].typ)) return TRUE; if (humidity & DRY) { typ = levl[x][y].typ; if (typ == ROOM || typ == AIR || typ == CLOUD || typ == ICE || typ == CORR) return TRUE; } if ((humidity & WET) && is_pool(x, y)) return TRUE; if ((humidity & HOT) && is_lava(x, y)) return TRUE; return FALSE; } unpacked_coord get_unpacked_coord(loc, defhumidity) long loc; int defhumidity; { static unpacked_coord c; if (loc & SP_COORD_IS_RANDOM) { c.x = c.y = -1; c.is_random = 1; c.getloc_flags = (loc & ~SP_COORD_IS_RANDOM); if (!c.getloc_flags) c.getloc_flags = defhumidity; } else { c.is_random = 0; c.getloc_flags = defhumidity; c.x = SP_COORD_X(loc); c.y = SP_COORD_Y(loc); } return c; } STATIC_OVL void get_location_coord(x, y, humidity, croom, crd) schar *x, *y; int humidity; struct mkroom *croom; long crd; { unpacked_coord c; c = get_unpacked_coord(crd, humidity); *x = c.x; *y = c.y; get_location(x, y, c.getloc_flags | (c.is_random ? NO_LOC_WARN : 0), croom); if (*x == -1 && *y == -1 && c.is_random) get_location(x, y, humidity, croom); } /* * Get a relative position inside a room. * negative values for x or y means RANDOM! */ STATIC_OVL void get_room_loc(x, y, croom) schar *x, *y; struct mkroom *croom; { coord c; if (*x < 0 && *y < 0) { if (somexy(croom, &c)) { *x = c.x; *y = c.y; } else panic("get_room_loc : can't find a place!"); } else { if (*x < 0) *x = rn2(croom->hx - croom->lx + 1); if (*y < 0) *y = rn2(croom->hy - croom->ly + 1); *x += croom->lx; *y += croom->ly; } } /* * Get a relative position inside a room. * negative values for x or y means RANDOM! */ STATIC_OVL void get_free_room_loc(x, y, croom, pos) schar *x, *y; struct mkroom *croom; packed_coord pos; { schar try_x, try_y; register int trycnt = 0; get_location_coord(&try_x, &try_y, DRY, croom, pos); if (levl[try_x][try_y].typ != ROOM) { do { try_x = *x, try_y = *y; get_room_loc(&try_x, &try_y, croom); } while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100); if (trycnt > 100) panic("get_free_room_loc: can't find a place!"); } *x = try_x, *y = try_y; } boolean check_room(lowx, ddx, lowy, ddy, vault) xchar *lowx, *ddx, *lowy, *ddy; boolean vault; { register int x, y, hix = *lowx + *ddx, hiy = *lowy + *ddy; register struct rm *lev; int xlim, ylim, ymax; xlim = XLIM + (vault ? 1 : 0); ylim = YLIM + (vault ? 1 : 0); if (*lowx < 3) *lowx = 3; if (*lowy < 2) *lowy = 2; if (hix > COLNO - 3) hix = COLNO - 3; if (hiy > ROWNO - 3) hiy = ROWNO - 3; chk: if (hix <= *lowx || hiy <= *lowy) return FALSE; /* check area around room (and make room smaller if necessary) */ for (x = *lowx - xlim; x <= hix + xlim; x++) { if (x <= 0 || x >= COLNO) continue; y = *lowy - ylim; ymax = hiy + ylim; if (y < 0) y = 0; if (ymax >= ROWNO) ymax = (ROWNO - 1); lev = &levl[x][y]; for (; y <= ymax; y++) { if (lev++->typ) { if (!vault) { debugpline2("strange area [%d,%d] in check_room.", x, y); } if (!rn2(3)) return FALSE; if (x < *lowx) *lowx = x + xlim + 1; else hix = x - xlim - 1; if (y < *lowy) *lowy = y + ylim + 1; else hiy = y - ylim - 1; goto chk; } } } *ddx = hix - *lowx; *ddy = hiy - *lowy; return TRUE; } /* * Create a new room. * This is still very incomplete... */ boolean create_room(x, y, w, h, xal, yal, rtype, rlit) xchar x, y; xchar w, h; xchar xal, yal; xchar rtype, rlit; { xchar xabs, yabs; int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp; NhRect *r1 = 0, r2; int trycnt = 0; boolean vault = FALSE; int xlim = XLIM, ylim = YLIM; if (rtype == -1) /* Is the type random ? */ rtype = OROOM; if (rtype == VAULT) { vault = TRUE; xlim++; ylim++; } /* on low levels the room is lit (usually) */ /* some other rooms may require lighting */ /* is light state random ? */ if (rlit == -1) rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; /* * Here we will try to create a room. If some parameters are * random we are willing to make several try before we give * it up. */ do { xchar xborder, yborder; wtmp = w; htmp = h; xtmp = x; ytmp = y; xaltmp = xal; yaltmp = yal; /* First case : a totally random room */ if ((xtmp < 0 && ytmp < 0 && wtmp < 0 && xaltmp < 0 && yaltmp < 0) || vault) { xchar hx, hy, lx, ly, dx, dy; r1 = rnd_rect(); /* Get a random rectangle */ if (!r1) { /* No more free rectangles ! */ debugpline0("No more rects..."); return FALSE; } hx = r1->hx; hy = r1->hy; lx = r1->lx; ly = r1->ly; if (vault) dx = dy = 1; else { dx = 2 + rn2((hx - lx > 28) ? 12 : 8); dy = 2 + rn2(4); if (dx * dy > 50) dy = 50 / dx; } xborder = (lx > 0 && hx < COLNO - 1) ? 2 * xlim : xlim + 1; yborder = (ly > 0 && hy < ROWNO - 1) ? 2 * ylim : ylim + 1; if (hx - lx < dx + 3 + xborder || hy - ly < dy + 3 + yborder) { r1 = 0; continue; } xabs = lx + (lx > 0 ? xlim : 3) + rn2(hx - (lx > 0 ? lx : 3) - dx - xborder + 1); yabs = ly + (ly > 0 ? ylim : 2) + rn2(hy - (ly > 0 ? ly : 2) - dy - yborder + 1); if (ly == 0 && hy >= (ROWNO - 1) && (!nroom || !rn2(nroom)) && (yabs + dy > ROWNO / 2)) { yabs = rn1(3, 2); if (nroom < 4 && dy > 1) dy--; } if (!check_room(&xabs, &dx, &yabs, &dy, vault)) { r1 = 0; continue; } wtmp = dx + 1; htmp = dy + 1; r2.lx = xabs - 1; r2.ly = yabs - 1; r2.hx = xabs + wtmp; r2.hy = yabs + htmp; } else { /* Only some parameters are random */ int rndpos = 0; if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */ xtmp = rnd(5); ytmp = rnd(5); rndpos = 1; } if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */ wtmp = rn1(15, 3); htmp = rn1(8, 2); } if (xaltmp == -1) /* Horizontal alignment is RANDOM */ xaltmp = rnd(3); if (yaltmp == -1) /* Vertical alignment is RANDOM */ yaltmp = rnd(3); /* Try to generate real (absolute) coordinates here! */ xabs = (((xtmp - 1) * COLNO) / 5) + 1; yabs = (((ytmp - 1) * ROWNO) / 5) + 1; switch (xaltmp) { case LEFT: break; case RIGHT: xabs += (COLNO / 5) - wtmp; break; case CENTER: xabs += ((COLNO / 5) - wtmp) / 2; break; } switch (yaltmp) { case TOP: break; case BOTTOM: yabs += (ROWNO / 5) - htmp; break; case CENTER: yabs += ((ROWNO / 5) - htmp) / 2; break; } if (xabs + wtmp - 1 > COLNO - 2) xabs = COLNO - wtmp - 3; if (xabs < 2) xabs = 2; if (yabs + htmp - 1 > ROWNO - 2) yabs = ROWNO - htmp - 3; if (yabs < 2) yabs = 2; /* Try to find a rectangle that fit our room ! */ r2.lx = xabs - 1; r2.ly = yabs - 1; r2.hx = xabs + wtmp + rndpos; r2.hy = yabs + htmp + rndpos; r1 = get_rect(&r2); } } while (++trycnt <= 100 && !r1); if (!r1) { /* creation of room failed ? */ return FALSE; } split_rects(r1, &r2); if (!vault) { smeq[nroom] = nroom; add_room(xabs, yabs, xabs + wtmp - 1, yabs + htmp - 1, rlit, rtype, FALSE); } else { rooms[nroom].lx = xabs; rooms[nroom].ly = yabs; } return TRUE; } /* * Create a subroom in room proom at pos x,y with width w & height h. * x & y are relative to the parent room. */ STATIC_OVL boolean create_subroom(proom, x, y, w, h, rtype, rlit) struct mkroom *proom; xchar x, y; xchar w, h; xchar rtype, rlit; { xchar width, height; width = proom->hx - proom->lx + 1; height = proom->hy - proom->ly + 1; /* There is a minimum size for the parent room */ if (width < 4 || height < 4) return FALSE; /* Check for random position, size, etc... */ if (w == -1) w = rnd(width - 3); if (h == -1) h = rnd(height - 3); if (x == -1) x = rnd(width - w - 1) - 1; if (y == -1) y = rnd(height - h - 1) - 1; if (x == 1) x = 0; if (y == 1) y = 0; if ((x + w + 1) == width) x++; if ((y + h + 1) == height) y++; if (rtype == -1) rtype = OROOM; if (rlit == -1) rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; add_subroom(proom, proom->lx + x, proom->ly + y, proom->lx + x + w - 1, proom->ly + y + h - 1, rlit, rtype, FALSE); return TRUE; } /* * Create a new door in a room. * It's placed on a wall (north, south, east or west). */ STATIC_OVL void create_door(dd, broom) room_door *dd; struct mkroom *broom; { int x = 0, y = 0; int trycnt = 0, wtry = 0; if (dd->secret == -1) dd->secret = rn2(2); if (dd->mask == -1) { /* is it a locked door, closed, or a doorway? */ if (!dd->secret) { if (!rn2(3)) { if (!rn2(5)) dd->mask = D_ISOPEN; else if (!rn2(6)) dd->mask = D_LOCKED; else dd->mask = D_CLOSED; if (dd->mask != D_ISOPEN && !rn2(25)) dd->mask |= D_TRAPPED; } else dd->mask = D_NODOOR; } else { if (!rn2(5)) dd->mask = D_LOCKED; else dd->mask = D_CLOSED; if (!rn2(20)) dd->mask |= D_TRAPPED; } } do { register int dwall, dpos; dwall = dd->wall; if (dwall == -1) /* The wall is RANDOM */ dwall = 1 << rn2(4); dpos = dd->pos; /* Convert wall and pos into an absolute coordinate! */ wtry = rn2(4); switch (wtry) { case 0: if (!(dwall & W_NORTH)) goto redoloop; y = broom->ly - 1; x = broom->lx + ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos); if (IS_ROCK(levl[x][y - 1].typ)) goto redoloop; goto outdirloop; case 1: if (!(dwall & W_SOUTH)) goto redoloop; y = broom->hy + 1; x = broom->lx + ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos); if (IS_ROCK(levl[x][y + 1].typ)) goto redoloop; goto outdirloop; case 2: if (!(dwall & W_WEST)) goto redoloop; x = broom->lx - 1; y = broom->ly + ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos); if (IS_ROCK(levl[x - 1][y].typ)) goto redoloop; goto outdirloop; case 3: if (!(dwall & W_EAST)) goto redoloop; x = broom->hx + 1; y = broom->ly + ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos); if (IS_ROCK(levl[x + 1][y].typ)) goto redoloop; goto outdirloop; default: x = y = 0; panic("create_door: No wall for door!"); goto outdirloop; } outdirloop: if (okdoor(x, y)) break; redoloop: ; } while (++trycnt <= 100); if (trycnt > 100) { impossible("create_door: Can't find a proper place!"); return; } levl[x][y].typ = (dd->secret ? SDOOR : DOOR); levl[x][y].doormask = dd->mask; } /* * Create a secret door in croom on any one of the specified walls. */ void create_secret_door(croom, walls) struct mkroom *croom; xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */ { xchar sx, sy; /* location of the secret door */ int count; for (count = 0; count < 100; count++) { sx = rn1(croom->hx - croom->lx + 1, croom->lx); sy = rn1(croom->hy - croom->ly + 1, croom->ly); switch (rn2(4)) { case 0: /* top */ if (!(walls & W_NORTH)) continue; sy = croom->ly - 1; break; case 1: /* bottom */ if (!(walls & W_SOUTH)) continue; sy = croom->hy + 1; break; case 2: /* left */ if (!(walls & W_EAST)) continue; sx = croom->lx - 1; break; case 3: /* right */ if (!(walls & W_WEST)) continue; sx = croom->hx + 1; break; } if (okdoor(sx, sy)) { levl[sx][sy].typ = SDOOR; levl[sx][sy].doormask = D_CLOSED; return; } } impossible("couldn't create secret door on any walls 0x%x", walls); } /* * Create a trap in a room. */ STATIC_OVL void create_trap(t, croom) trap *t; struct mkroom *croom; { schar x, y; coord tm; if (croom) get_free_room_loc(&x, &y, croom, t->coord); else { int trycnt = 0; do { get_location_coord(&x, &y, DRY, croom, t->coord); } while ((levl[x][y].typ == STAIRS || levl[x][y].typ == LADDER) && ++trycnt <= 100); if (trycnt > 100) return; } tm.x = x; tm.y = y; mktrap(t->type, 1, (struct mkroom *) 0, &tm); } /* * Create a monster in a room. */ STATIC_OVL int noncoalignment(alignment) aligntyp alignment; { int k; k = rn2(2); if (!alignment) return (k ? -1 : 1); return (k ? -alignment : 0); } /* attempt to screen out locations where a mimic-as-boulder shouldn't occur */ STATIC_OVL boolean m_bad_boulder_spot(x, y) int x, y; { struct rm *lev; /* avoid trap locations */ if (t_at(x, y)) return TRUE; /* try to avoid locations which already have a boulder (this won't actually work; we get called before objects have been placed...) */ if (sobj_at(BOULDER, x, y)) return TRUE; /* avoid closed doors */ lev = &levl[x][y]; if (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED | D_LOCKED)) != 0) return TRUE; /* spot is ok */ return FALSE; } STATIC_OVL void create_monster(m, croom) monster *m; struct mkroom *croom; { struct monst *mtmp; schar x, y; char class; aligntyp amask; coord cc; struct permonst *pm; unsigned g_mvflags; if (m->class >= 0) class = (char) def_char_to_monclass((char) m->class); else class = 0; if (class == MAXMCLASSES) panic("create_monster: unknown monster class '%c'", m->class); amask = (m->align == AM_SPLEV_CO) ? Align2amask(u.ualignbase[A_ORIGINAL]) : (m->align == AM_SPLEV_NONCO) ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) : (m->align <= -(MAX_REGISTERS + 1)) ? induced_align(80) : (m->align < 0 ? ralign[-m->align - 1] : m->align); if (!class) pm = (struct permonst *) 0; else if (m->id != NON_PM) { pm = &mons[m->id]; g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags; if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT)) return; else if (g_mvflags & G_GONE) /* genocided or extinct */ pm = (struct permonst *) 0; /* make random monster */ } else { pm = mkclass(class, G_NOGEN); /* if we can't get a specific monster type (pm == 0) then the class has been genocided, so settle for a random monster */ } if (In_mines(&u.uz) && pm && your_race(pm) && (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3)) pm = (struct permonst *) 0; if (pm) { int loc = DRY; if (pm->mlet == S_EEL || amphibious(pm) || is_swimmer(pm)) loc = WET; if (is_flyer(pm) || is_floater(pm)) loc |= (HOT | WET); if (passes_walls(pm) || noncorporeal(pm)) loc |= SOLID; if (flaming(pm)) loc |= HOT; /* If water-liking monster, first try is without DRY */ get_location_coord(&x, &y, loc | NO_LOC_WARN, croom, m->coord); if (x == -1 && y == -1) { loc |= DRY; get_location_coord(&x, &y, loc, croom, m->coord); } } else { get_location_coord(&x, &y, DRY, croom, m->coord); } /* try to find a close place if someone else is already there */ if (MON_AT(x, y) && enexto(&cc, x, y, pm)) x = cc.x, y = cc.y; if (m->align != -(MAX_REGISTERS + 2)) mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful); else if (PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD) mtmp = mk_mplayer(pm, x, y, FALSE); else mtmp = makemon(pm, x, y, NO_MM_FLAGS); if (mtmp) { x = mtmp->mx, y = mtmp->my; /* sanity precaution */ m->x = x, m->y = y; /* handle specific attributes for some special monsters */ if (m->name.str) mtmp = christen_monst(mtmp, m->name.str); /* * This is currently hardwired for mimics only. It should * eventually be expanded. */ if (m->appear_as.str && ((mtmp->data->mlet == S_MIMIC) || mtmp->cham)) { int i; switch (m->appear) { case M_AP_NOTHING: impossible( "create_monster: mon has an appearance, \"%s\", but no type", m->appear_as.str); break; case M_AP_FURNITURE: for (i = 0; i < MAXPCHARS; i++) if (!strcmp(defsyms[i].explanation, m->appear_as.str)) break; if (i == MAXPCHARS) { impossible("create_monster: can't find feature \"%s\"", m->appear_as.str); } else { mtmp->m_ap_type = M_AP_FURNITURE; mtmp->mappearance = i; } break; case M_AP_OBJECT: for (i = 0; i < NUM_OBJECTS; i++) if (OBJ_NAME(objects[i]) && !strcmp(OBJ_NAME(objects[i]), m->appear_as.str)) break; if (i == NUM_OBJECTS) { impossible("create_monster: can't find object \"%s\"", m->appear_as.str); } else { mtmp->m_ap_type = M_AP_OBJECT; mtmp->mappearance = i; /* try to avoid placing mimic boulder on a trap */ if (i == BOULDER && m->x < 0 && m_bad_boulder_spot(x, y)) { int retrylimit = 10; remove_monster(x, y); do { x = m->x; y = m->y; get_location(&x, &y, DRY, croom); if (MON_AT(x, y) && enexto(&cc, x, y, pm)) x = cc.x, y = cc.y; } while (m_bad_boulder_spot(x, y) && --retrylimit > 0); place_monster(mtmp, x, y); /* if we didn't find a good spot then mimic something else */ if (!retrylimit) set_mimic_sym(mtmp); } } break; case M_AP_MONSTER: { int mndx; if (!strcmpi(m->appear_as.str, "random")) mndx = select_newcham_form(mtmp); else mndx = name_to_mon(m->appear_as.str); if ((mndx != NON_PM) && (&mons[mndx] != mtmp->data)) { struct permonst *mdat = &mons[mndx]; struct permonst *olddata = mtmp->data; mgender_from_permonst(mtmp, mdat); set_mon_data(mtmp, mdat, 0); if (emits_light(olddata) != emits_light(mtmp->data)) { /* used to give light, now doesn't, or vice versa, or light's range has changed */ if (emits_light(olddata)) del_light_source(LS_MONSTER, (genericptr_t) mtmp); if (emits_light(mtmp->data)) new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data), LS_MONSTER, (genericptr_t) mtmp); } if (!mtmp->perminvis || pm_invisible(olddata)) mtmp->perminvis = pm_invisible(mdat); } break; } default: impossible( "create_monster: unimplemented mon appear type [%d,\"%s\"]", m->appear, m->appear_as.str); break; } if (does_block(x, y, &levl[x][y])) block_point(x, y); } if (m->peaceful >= 0) { mtmp->mpeaceful = m->peaceful; /* changed mpeaceful again; have to reset malign */ set_malign(mtmp); } if (m->asleep >= 0) { #ifdef UNIXPC /* optimizer bug strikes again */ if (m->asleep) mtmp->msleeping = 1; else mtmp->msleeping = 0; #else mtmp->msleeping = m->asleep; #endif } if (m->seentraps) mtmp->mtrapseen = m->seentraps; if (m->female) mtmp->female = 1; if (m->cancelled) mtmp->mcan = 1; if (m->revived) mtmp->mrevived = 1; if (m->avenge) mtmp->mavenge = 1; if (m->stunned) mtmp->mstun = 1; if (m->confused) mtmp->mconf = 1; if (m->invis) { mtmp->minvis = mtmp->perminvis = 1; } if (m->blinded) { mtmp->mcansee = 0; mtmp->mblinded = (m->blinded % 127); } if (m->paralyzed) { mtmp->mcanmove = 0; mtmp->mfrozen = (m->paralyzed % 127); } if (m->fleeing) { mtmp->mflee = 1; mtmp->mfleetim = (m->fleeing % 127); } if (m->has_invent) { discard_minvent(mtmp); invent_carrying_monster = mtmp; } } } /* * Create an object in a room. */ STATIC_OVL void create_object(o, croom) object *o; struct mkroom *croom; { struct obj *otmp; schar x, y; char c; boolean named; /* has a name been supplied in level description? */ named = o->name.str ? TRUE : FALSE; get_location_coord(&x, &y, DRY, croom, o->coord); if (o->class >= 0) c = o->class; else c = 0; if (!c) otmp = mkobj_at(RANDOM_CLASS, x, y, !named); else if (o->id != -1) otmp = mksobj_at(o->id, x, y, TRUE, !named); else { /* * The special levels are compiled with the default "text" object * class characters. We must convert them to the internal format. */ char oclass = (char) def_char_to_objclass(c); if (oclass == MAXOCLASSES) panic("create_object: unexpected object class '%c'", c); /* KMH -- Create piles of gold properly */ if (oclass == COIN_CLASS) otmp = mkgold(0L, x, y); else otmp = mkobj_at(oclass, x, y, !named); } if (o->spe != -127) /* That means NOT RANDOM! */ otmp->spe = (schar) o->spe; switch (o->curse_state) { case 1: bless(otmp); break; /* BLESSED */ case 2: unbless(otmp); uncurse(otmp); break; /* uncursed */ case 3: curse(otmp); break; /* CURSED */ default: break; /* Otherwise it's random and we're happy * with what mkobj gave us! */ } /* corpsenm is "empty" if -1, random if -2, otherwise specific */ if (o->corpsenm != NON_PM) { if (o->corpsenm == NON_PM - 1) set_corpsenm(otmp, rndmonnum()); else set_corpsenm(otmp, o->corpsenm); } /* set_corpsenm() took care of egg hatch and corpse timers */ if (named) otmp = oname(otmp, o->name.str); if (o->eroded) { if (o->eroded < 0) { otmp->oerodeproof = 1; } else { otmp->oeroded = (o->eroded % 4); otmp->oeroded2 = ((o->eroded >> 2) % 4); } } if (o->recharged) otmp->recharged = (o->recharged % 8); if (o->locked) { otmp->olocked = 1; } else if (o->broken) { otmp->obroken = 1; otmp->olocked = 0; /* obj generation may set */ } if (o->trapped) otmp->otrapped = 1; if (o->greased) otmp->greased = 1; #ifdef INVISIBLE_OBJECTS if (o->invis) otmp->oinvis = 1; #endif if (o->quan > 0 && objects[otmp->otyp].oc_merge) { otmp->quan = o->quan; otmp->owt = weight(otmp); } /* contents */ if (o->containment & SP_OBJ_CONTENT) { if (!container_idx) { if (!invent_carrying_monster) { /*impossible("create_object: no container");*/ /* don't complain, the monster may be gone legally (eg. unique demon already generated) TODO: In the case of unique demon lords, they should get their inventories even when they get generated outside the des-file. Maybe another data file that determines what inventories monsters get by default? */ } else { int ci; struct obj *objcheck = otmp; int inuse = -1; for (ci = 0; ci < container_idx; ci++) if (container_obj[ci] == objcheck) inuse = ci; remove_object(otmp); if (mpickobj(invent_carrying_monster, otmp)) { if (inuse > -1) { impossible( "container given to monster was merged or deallocated."); for (ci = inuse; ci < container_idx - 1; ci++) container_obj[ci] = container_obj[ci + 1]; container_obj[container_idx] = NULL; container_idx--; } /* we lost track of it. */ return; } } } else { remove_object(otmp); if (container_obj[container_idx - 1]) (void) add_to_container(container_obj[container_idx - 1], otmp); else { obj_extract_self(otmp); obfree(otmp, NULL); return; } } } /* container */ if (o->containment & SP_OBJ_CONTAINER) { delete_contents(otmp); if (container_idx < MAX_CONTAINMENT) { container_obj[container_idx] = otmp; container_idx++; } else impossible("create_object: too deeply nested containers."); } /* Medusa level special case: statues are petrified monsters, so they * are not stone-resistant and have monster inventory. They also lack * other contents, but that can be specified as an empty container. */ if (o->id == STATUE && Is_medusa_level(&u.uz) && o->corpsenm == NON_PM) { struct monst *was; struct obj *obj; int wastyp; int i = 0; /* prevent endless loop in case makemon always fails */ /* Named random statues are of player types, and aren't stone- * resistant (if they were, we'd have to reset the name as well as * setting corpsenm). */ for (wastyp = otmp->corpsenm; i < 1000; i++, wastyp = rndmonnum()) { /* makemon without rndmonst() might create a group */ was = makemon(&mons[wastyp], 0, 0, MM_NOCOUNTBIRTH); if (was) { if (!resists_ston(was)) { (void) propagate(wastyp, TRUE, FALSE); break; } mongone(was); was = NULL; } } if (was) { set_corpsenm(otmp, wastyp); while (was->minvent) { obj = was->minvent; obj->owornmask = 0; obj_extract_self(obj); (void) add_to_container(otmp, obj); } otmp->owt = weight(otmp); mongone(was); } } /* Nasty hack here: try to determine if this is the Mines or Sokoban * "prize" and then set record_achieve_special (maps to corpsenm) * for the object. That field will later be checked to find out if * the player obtained the prize. */ if (otmp->otyp == LUCKSTONE && Is_mineend_level(&u.uz)) { otmp->record_achieve_special = 1; } else if ((otmp->otyp == AMULET_OF_REFLECTION || otmp->otyp == BAG_OF_HOLDING) && Is_sokoend_level(&u.uz)) { otmp->record_achieve_special = 1; } stackobj(otmp); if (o->lit) { begin_burn(otmp, FALSE); } if (o->buried) { boolean dealloced; (void) bury_an_obj(otmp, &dealloced); if (dealloced && container_idx) { container_obj[container_idx - 1] = NULL; } } } /* * Create an altar in a room. */ STATIC_OVL void create_altar(a, croom) altar *a; struct mkroom *croom; { schar sproom, x, y; aligntyp amask; boolean croom_is_temple = TRUE; int oldtyp; if (croom) { get_free_room_loc(&x, &y, croom, a->coord); if (croom->rtype != TEMPLE) croom_is_temple = FALSE; } else { get_location_coord(&x, &y, DRY, croom, a->coord); if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0) croom = &rooms[sproom - ROOMOFFSET]; else croom_is_temple = FALSE; } /* check for existing features */ oldtyp = levl[x][y].typ; if (oldtyp == STAIRS || oldtyp == LADDER) return; /* Is the alignment random ? * If so, it's an 80% chance that the altar will be co-aligned. * * The alignment is encoded as amask values instead of alignment * values to avoid conflicting with the rest of the encoding, * shared by many other parts of the special level code. */ amask = (a->align == AM_SPLEV_CO) ? Align2amask(u.ualignbase[A_ORIGINAL]) : (a->align == AM_SPLEV_NONCO) ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) : (a->align == -(MAX_REGISTERS + 1)) ? induced_align(80) : (a->align < 0 ? ralign[-a->align - 1] : a->align); levl[x][y].typ = ALTAR; levl[x][y].altarmask = amask; if (a->shrine < 0) a->shrine = rn2(2); /* handle random case */ if (!croom_is_temple || !a->shrine) return; if (a->shrine) { /* Is it a shrine or sanctum? */ priestini(&u.uz, croom, x, y, (a->shrine > 1)); levl[x][y].altarmask |= AM_SHRINE; level.flags.has_temple = TRUE; } } void replace_terrain(terr, croom) replaceterrain *terr; struct mkroom *croom; { schar x, y, x1, y1, x2, y2; if (terr->toter >= MAX_TYPE) return; x1 = terr->x1; y1 = terr->y1; get_location(&x1, &y1, ANY_LOC, croom); x2 = terr->x2; y2 = terr->y2; get_location(&x2, &y2, ANY_LOC, croom); for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++) for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++) if (levl[x][y].typ == terr->fromter && rn2(100) < terr->chance) { SET_TYPLIT(x, y, terr->toter, terr->tolit); } } /* * Search for a door in a room on a specified wall. */ STATIC_OVL boolean search_door(croom, x, y, wall, cnt) struct mkroom *croom; xchar *x, *y; xchar wall; int cnt; { int dx, dy; int xx, yy; switch (wall) { case W_NORTH: dy = 0; dx = 1; xx = croom->lx; yy = croom->hy + 1; break; case W_SOUTH: dy = 0; dx = 1; xx = croom->lx; yy = croom->ly - 1; break; case W_EAST: dy = 1; dx = 0; xx = croom->hx + 1; yy = croom->ly; break; case W_WEST: dy = 1; dx = 0; xx = croom->lx - 1; yy = croom->ly; break; default: dx = dy = xx = yy = 0; panic("search_door: Bad wall!"); break; } while (xx <= croom->hx + 1 && yy <= croom->hy + 1) { if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) { *x = xx; *y = yy; if (cnt-- <= 0) return TRUE; } xx += dx; yy += dy; } return FALSE; } /* * Dig a corridor between two points. */ boolean dig_corridor(org, dest, nxcor, ftyp, btyp) coord *org, *dest; boolean nxcor; schar ftyp, btyp; { int dx = 0, dy = 0, dix, diy, cct; struct rm *crm; int tx, ty, xx, yy; xx = org->x; yy = org->y; tx = dest->x; ty = dest->y; if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 || xx > COLNO - 1 || tx > COLNO - 1 || yy > ROWNO - 1 || ty > ROWNO - 1) { debugpline4("dig_corridor: bad coords <%d,%d> <%d,%d>.", xx, yy, tx, ty); return FALSE; } if (tx > xx) dx = 1; else if (ty > yy) dy = 1; else if (tx < xx) dx = -1; else dy = -1; xx -= dx; yy -= dy; cct = 0; while (xx != tx || yy != ty) { /* loop: dig corridor at [xx,yy] and find new [xx,yy] */ if (cct++ > 500 || (nxcor && !rn2(35))) return FALSE; xx += dx; yy += dy; if (xx >= COLNO - 1 || xx <= 0 || yy <= 0 || yy >= ROWNO - 1) return FALSE; /* impossible */ crm = &levl[xx][yy]; if (crm->typ == btyp) { if (ftyp != CORR || rn2(100)) { crm->typ = ftyp; if (nxcor && !rn2(50)) (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE); } else { crm->typ = SCORR; } } else if (crm->typ != ftyp && crm->typ != SCORR) { /* strange ... */ return FALSE; } /* find next corridor position */ dix = abs(xx - tx); diy = abs(yy - ty); if ((dix > diy) && diy && !rn2(dix-diy+1)) { dix = 0; } else if ((diy > dix) && dix && !rn2(diy-dix+1)) { diy = 0; } /* do we have to change direction ? */ if (dy && dix > diy) { register int ddx = (xx > tx) ? -1 : 1; crm = &levl[xx + ddx][yy]; if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) { dx = ddx; dy = 0; continue; } } else if (dx && diy > dix) { register int ddy = (yy > ty) ? -1 : 1; crm = &levl[xx][yy + ddy]; if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) { dy = ddy; dx = 0; continue; } } /* continue straight on? */ crm = &levl[xx + dx][yy + dy]; if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) continue; /* no, what must we do now?? */ if (dx) { dx = 0; dy = (ty < yy) ? -1 : 1; } else { dy = 0; dx = (tx < xx) ? -1 : 1; } crm = &levl[xx + dx][yy + dy]; if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) continue; dy = -dy; dx = -dx; } return TRUE; } /* * Disgusting hack: since special levels have their rooms filled before * sorting the rooms, we have to re-arrange the speed values upstairs_room * and dnstairs_room after the rooms have been sorted. On normal levels, * stairs don't get created until _after_ sorting takes place. */ STATIC_OVL void fix_stair_rooms() { int i; struct mkroom *croom; if (xdnstair && !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) && (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) { for (i = 0; i < nroom; i++) { croom = &rooms[i]; if ((croom->lx <= xdnstair && xdnstair <= croom->hx) && (croom->ly <= ydnstair && ydnstair <= croom->hy)) { dnstairs_room = croom; break; } } if (i == nroom) panic("Couldn't find dnstair room in fix_stair_rooms!"); } if (xupstair && !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) && (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) { for (i = 0; i < nroom; i++) { croom = &rooms[i]; if ((croom->lx <= xupstair && xupstair <= croom->hx) && (croom->ly <= yupstair && yupstair <= croom->hy)) { upstairs_room = croom; break; } } if (i == nroom) panic("Couldn't find upstair room in fix_stair_rooms!"); } } /* * Corridors always start from a door. But it can end anywhere... * Basically we search for door coordinates or for endpoints coordinates * (from a distance). */ STATIC_OVL void create_corridor(c) corridor *c; { coord org, dest; if (c->src.room == -1) { fix_stair_rooms(); makecorridors(); /*makecorridors(c->src.door);*/ return; } if (!search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall, c->src.door)) return; if (c->dest.room != -1) { if (!search_door(&rooms[c->dest.room], &dest.x, &dest.y, c->dest.wall, c->dest.door)) return; switch (c->src.wall) { case W_NORTH: org.y--; break; case W_SOUTH: org.y++; break; case W_WEST: org.x--; break; case W_EAST: org.x++; break; } switch (c->dest.wall) { case W_NORTH: dest.y--; break; case W_SOUTH: dest.y++; break; case W_WEST: dest.x--; break; case W_EAST: dest.x++; break; } (void) dig_corridor(&org, &dest, FALSE, CORR, STONE); } } /* * Fill a room (shop, zoo, etc...) with appropriate stuff. */ void fill_room(croom, prefilled) struct mkroom *croom; boolean prefilled; { if (!croom || croom->rtype == OROOM) return; if (!prefilled) { int x, y; /* Shop ? */ if (croom->rtype >= SHOPBASE) { stock_room(croom->rtype - SHOPBASE, croom); level.flags.has_shop = TRUE; return; } switch (croom->rtype) { case VAULT: for (x = croom->lx; x <= croom->hx; x++) for (y = croom->ly; y <= croom->hy; y++) (void) mkgold((long) rn1(abs(depth(&u.uz)) * 100, 51), x, y); break; case COURT: case ZOO: case BEEHIVE: case MORGUE: case BARRACKS: fill_zoo(croom); break; } } switch (croom->rtype) { case VAULT: level.flags.has_vault = TRUE; break; case ZOO: level.flags.has_zoo = TRUE; break; case COURT: level.flags.has_court = TRUE; break; case MORGUE: level.flags.has_morgue = TRUE; break; case BEEHIVE: level.flags.has_beehive = TRUE; break; case BARRACKS: level.flags.has_barracks = TRUE; break; case TEMPLE: level.flags.has_temple = TRUE; break; case SWAMP: level.flags.has_swamp = TRUE; break; } } struct mkroom * build_room(r, mkr) room *r; struct mkroom *mkr; { boolean okroom; struct mkroom *aroom; xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM; if (mkr) { aroom = &subrooms[nsubroom]; okroom = create_subroom(mkr, r->x, r->y, r->w, r->h, rtype, r->rlit); } else { aroom = &rooms[nroom]; okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, r->yalign, rtype, r->rlit); } if (okroom) { #ifdef SPECIALIZATION topologize(aroom, FALSE); /* set roomno */ #else topologize(aroom); /* set roomno */ #endif aroom->needfill = r->filled; aroom->needjoining = r->joined; return aroom; } return (struct mkroom *) 0; } /* * set lighting in a region that will not become a room. */ STATIC_OVL void light_region(tmpregion) region *tmpregion; { register boolean litstate = tmpregion->rlit ? 1 : 0; register int hiy = tmpregion->y2; register int x, y; register struct rm *lev; int lowy = tmpregion->y1; int lowx = tmpregion->x1, hix = tmpregion->x2; if (litstate) { /* adjust region size for walls, but only if lighted */ lowx = max(lowx - 1, 1); hix = min(hix + 1, COLNO - 1); lowy = max(lowy - 1, 0); hiy = min(hiy + 1, ROWNO - 1); } for (x = lowx; x <= hix; x++) { lev = &levl[x][lowy]; for (y = lowy; y <= hiy; y++) { if (lev->typ != LAVAPOOL) /* this overrides normal lighting */ lev->lit = litstate; lev++; } } } void wallify_map(x1, y1, x2, y2) int x1, y1, x2, y2; { int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy; for (y = y1; y <= y2; y++) { lo_yy = (y > 0) ? y - 1 : 0; hi_yy = (y < y2) ? y + 1 : y2; for (x = x1; x <= x2; x++) { if (levl[x][y].typ != STONE) continue; lo_xx = (x > 0) ? x - 1 : 0; hi_xx = (x < x2) ? x + 1 : x2; for (yy = lo_yy; yy <= hi_yy; yy++) for (xx = lo_xx; xx <= hi_xx; xx++) if (IS_ROOM(levl[xx][yy].typ) || levl[xx][yy].typ == CROSSWALL) { levl[x][y].typ = (yy != y) ? HWALL : VWALL; yy = hi_yy; /* end `yy' loop */ break; /* end `xx' loop */ } } } } /* * Select a random coordinate in the maze. * * We want a place not 'touched' by the loader. That is, a place in * the maze outside every part of the special level. */ STATIC_OVL void maze1xy(m, humidity) coord *m; int humidity; { register int x, y, tryct = 2000; /* tryct: normally it won't take more than ten or so tries due to the circumstances under which we'll be called, but the `humidity' screening might drastically change the chances */ do { x = rn1(x_maze_max - 3, 3); y = rn1(y_maze_max - 3, 3); if (--tryct < 0) break; /* give up */ } while (!(x % 2) || !(y % 2) || SpLev_Map[x][y] || !is_ok_location((schar) x, (schar) y, humidity)); m->x = (xchar) x, m->y = (xchar) y; } /* * If there's a significant portion of maze unused by the special level, * we don't want it empty. * * Makes the number of traps, monsters, etc. proportional * to the size of the maze. */ STATIC_OVL void fill_empty_maze() { int mapcountmax, mapcount, mapfact; xchar x, y; coord mm; mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2); mapcountmax = mapcountmax / 2; for (x = 2; x < x_maze_max; x++) for (y = 0; y < y_maze_max; y++) if (SpLev_Map[x][y]) mapcount--; if ((mapcount > (int) (mapcountmax / 10))) { mapfact = (int) ((mapcount * 100L) / mapcountmax); for (x = rnd((int) (20 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS, mm.x, mm.y, TRUE); } for (x = rnd((int) (12 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE); } for (x = rn2(2); x; x--) { maze1xy(&mm, DRY); (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS); } for (x = rnd((int) (12 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS); } for (x = rn2((int) (15 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) mkgold(0L, mm.x, mm.y); } for (x = rn2((int) (15 * mapfact) / 100); x; x--) { int trytrap; maze1xy(&mm, DRY); trytrap = rndtrap(); if (sobj_at(BOULDER, mm.x, mm.y)) while (trytrap == PIT || trytrap == SPIKED_PIT || trytrap == TRAPDOOR || trytrap == HOLE) trytrap = rndtrap(); (void) maketrap(mm.x, mm.y, trytrap); } } } /* * special level loader */ STATIC_OVL boolean sp_level_loader(fd, lvl) dlb *fd; sp_lev *lvl; { long n_opcode = 0; struct opvar *opdat; int opcode; Fread((genericptr_t) & (lvl->n_opcodes), 1, sizeof(lvl->n_opcodes), fd); lvl->opcodes = (_opcode *) alloc(sizeof(_opcode) * (lvl->n_opcodes)); while (n_opcode < lvl->n_opcodes) { Fread((genericptr_t) &lvl->opcodes[n_opcode].opcode, 1, sizeof(lvl->opcodes[n_opcode].opcode), fd); opcode = lvl->opcodes[n_opcode].opcode; opdat = NULL; if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES) panic("sp_level_loader: impossible opcode %i.", opcode); if (opcode == SPO_PUSH) { int nsize; struct opvar *ov = (struct opvar *) alloc(sizeof(struct opvar)); opdat = ov; ov->spovartyp = SPO_NULL; ov->vardata.l = 0; Fread((genericptr_t) & (ov->spovartyp), 1, sizeof(ov->spovartyp), fd); switch (ov->spovartyp) { case SPOVAR_NULL: break; case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: Fread((genericptr_t) & (ov->vardata.l), 1, sizeof(ov->vardata.l), fd); break; case SPOVAR_VARIABLE: case SPOVAR_STRING: case SPOVAR_SEL: { char *opd; Fread((genericptr_t) &nsize, 1, sizeof(nsize), fd); opd = (char *) alloc(nsize + 1); if (nsize) Fread(opd, 1, nsize, fd); opd[nsize] = 0; ov->vardata.str = opd; break; } default: panic("sp_level_loader: unknown opvar type %i", ov->spovartyp); } } lvl->opcodes[n_opcode].opdat = opdat; n_opcode++; } /*while*/ return TRUE; } /* Frees the memory allocated for special level creation structs */ STATIC_OVL boolean sp_level_free(lvl) sp_lev *lvl; { static const char nhFunc[] = "sp_level_free"; long n_opcode = 0; while (n_opcode < lvl->n_opcodes) { int opcode = lvl->opcodes[n_opcode].opcode; struct opvar *opdat = lvl->opcodes[n_opcode].opdat; if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES) panic("sp_level_free: unknown opcode %i", opcode); if (opdat) opvar_free(opdat); n_opcode++; } Free(lvl->opcodes); lvl->opcodes = NULL; return TRUE; } void splev_initlev(linit) lev_init *linit; { switch (linit->init_style) { default: impossible("Unrecognized level init style."); break; case LVLINIT_NONE: break; case LVLINIT_SOLIDFILL: if (linit->lit == -1) linit->lit = rn2(2); lvlfill_solid(linit->filling, linit->lit); break; case LVLINIT_MAZEGRID: lvlfill_maze_grid(2, 0, x_maze_max, y_maze_max, linit->filling); break; case LVLINIT_ROGUE: makeroguerooms(); break; case LVLINIT_MINES: if (linit->lit == -1) linit->lit = rn2(2); if (linit->filling > -1) lvlfill_solid(linit->filling, 0); linit->icedpools = icedpools; mkmap(linit); break; } } struct sp_frame * frame_new(execptr) long execptr; { struct sp_frame *frame = (struct sp_frame *) alloc(sizeof(struct sp_frame)); frame->next = NULL; frame->variables = NULL; frame->n_opcode = execptr; frame->stack = (struct splevstack *) alloc(sizeof(struct splevstack)); splev_stack_init(frame->stack); return frame; } void frame_del(frame) struct sp_frame *frame; { if (!frame) return; if (frame->stack) { splev_stack_done(frame->stack); frame->stack = NULL; } if (frame->variables) { variable_list_del(frame->variables); frame->variables = NULL; } Free(frame); } void spo_frame_push(coder) struct sp_coder *coder; { struct sp_frame *tmpframe = frame_new(coder->frame->n_opcode); tmpframe->next = coder->frame; coder->frame = tmpframe; } void spo_frame_pop(coder) struct sp_coder *coder; { if (coder->frame && coder->frame->next) { struct sp_frame *tmpframe = coder->frame->next; frame_del(coder->frame); coder->frame = tmpframe; coder->stack = coder->frame->stack; } } long sp_code_jmpaddr(curpos, jmpaddr) long curpos, jmpaddr; { return (curpos + jmpaddr); } void spo_call(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_call"; struct opvar *addr; struct opvar *params; struct sp_frame *tmpframe; if (!OV_pop_i(addr) || !OV_pop_i(params)) return; if (OV_i(params) < 0) return; tmpframe = frame_new(sp_code_jmpaddr(coder->frame->n_opcode, OV_i(addr) - 1)); while (OV_i(params)-- > 0) { splev_stack_push(tmpframe->stack, splev_stack_getdat_any(coder)); } splev_stack_reverse(tmpframe->stack); /* push a frame */ tmpframe->next = coder->frame; coder->frame = tmpframe; opvar_free(addr); opvar_free(params); } void spo_return(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_return"; struct opvar *params; if (!coder->frame || !coder->frame->next) panic("return: no frame."); if (!OV_pop_i(params)) return; if (OV_i(params) < 0) return; while (OV_i(params)-- > 0) { splev_stack_push(coder->frame->next->stack, splev_stack_pop(coder->stack)); } /* pop the frame */ if (coder->frame->next) { struct sp_frame *tmpframe = coder->frame->next; frame_del(coder->frame); coder->frame = tmpframe; coder->stack = coder->frame->stack; } opvar_free(params); } /*ARGUSED*/ void spo_end_moninvent(coder) struct sp_coder *coder UNUSED; { if (invent_carrying_monster) m_dowear(invent_carrying_monster, TRUE); invent_carrying_monster = NULL; } /*ARGUSED*/ void spo_pop_container(coder) struct sp_coder *coder UNUSED; { if (container_idx > 0) { container_idx--; container_obj[container_idx] = NULL; } } void spo_message(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_message"; struct opvar *op; char *msg, *levmsg; int old_n, n; if (!OV_pop_s(op)) return; msg = OV_s(op); if (!msg) return; old_n = lev_message ? (strlen(lev_message) + 1) : 0; n = strlen(msg); levmsg = (char *) alloc(old_n + n + 1); if (old_n) levmsg[old_n - 1] = '\n'; if (lev_message) (void) memcpy((genericptr_t) levmsg, (genericptr_t) lev_message, old_n - 1); (void) memcpy((genericptr_t) &levmsg[old_n], msg, n); levmsg[old_n + n] = '\0'; Free(lev_message); lev_message = levmsg; opvar_free(op); } void spo_monster(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_monster"; int nparams = 0; struct opvar *varparam; struct opvar *id, *mcoord, *has_inv; monster tmpmons; tmpmons.peaceful = -1; tmpmons.asleep = -1; tmpmons.name.str = (char *) 0; tmpmons.appear = 0; tmpmons.appear_as.str = (char *) 0; tmpmons.align = -MAX_REGISTERS - 2; tmpmons.female = 0; tmpmons.invis = 0; tmpmons.cancelled = 0; tmpmons.revived = 0; tmpmons.avenge = 0; tmpmons.fleeing = 0; tmpmons.blinded = 0; tmpmons.paralyzed = 0; tmpmons.stunned = 0; tmpmons.confused = 0; tmpmons.seentraps = 0; tmpmons.has_invent = 0; if (!OV_pop_i(has_inv)) return; if (!OV_pop_i(varparam)) return; while ((nparams++ < (SP_M_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT) && (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_M_V_END)) { struct opvar *parm = NULL; OV_pop(parm); switch (OV_i(varparam)) { case SP_M_V_NAME: if ((OV_typ(parm) == SPOVAR_STRING) && !tmpmons.name.str) tmpmons.name.str = dupstr(OV_s(parm)); break; case SP_M_V_APPEAR: if ((OV_typ(parm) == SPOVAR_INT) && !tmpmons.appear_as.str) { tmpmons.appear = OV_i(parm); opvar_free(parm); OV_pop(parm); tmpmons.appear_as.str = dupstr(OV_s(parm)); } break; case SP_M_V_ASLEEP: if (OV_typ(parm) == SPOVAR_INT) tmpmons.asleep = OV_i(parm); break; case SP_M_V_ALIGN: if (OV_typ(parm) == SPOVAR_INT) tmpmons.align = OV_i(parm); break; case SP_M_V_PEACEFUL: if (OV_typ(parm) == SPOVAR_INT) tmpmons.peaceful = OV_i(parm); break; case SP_M_V_FEMALE: if (OV_typ(parm) == SPOVAR_INT) tmpmons.female = OV_i(parm); break; case SP_M_V_INVIS: if (OV_typ(parm) == SPOVAR_INT) tmpmons.invis = OV_i(parm); break; case SP_M_V_CANCELLED: if (OV_typ(parm) == SPOVAR_INT) tmpmons.cancelled = OV_i(parm); break; case SP_M_V_REVIVED: if (OV_typ(parm) == SPOVAR_INT) tmpmons.revived = OV_i(parm); break; case SP_M_V_AVENGE: if (OV_typ(parm) == SPOVAR_INT) tmpmons.avenge = OV_i(parm); break; case SP_M_V_FLEEING: if (OV_typ(parm) == SPOVAR_INT) tmpmons.fleeing = OV_i(parm); break; case SP_M_V_BLINDED: if (OV_typ(parm) == SPOVAR_INT) tmpmons.blinded = OV_i(parm); break; case SP_M_V_PARALYZED: if (OV_typ(parm) == SPOVAR_INT) tmpmons.paralyzed = OV_i(parm); break; case SP_M_V_STUNNED: if (OV_typ(parm) == SPOVAR_INT) tmpmons.stunned = OV_i(parm); break; case SP_M_V_CONFUSED: if (OV_typ(parm) == SPOVAR_INT) tmpmons.confused = OV_i(parm); break; case SP_M_V_SEENTRAPS: if (OV_typ(parm) == SPOVAR_INT) tmpmons.seentraps = OV_i(parm); break; case SP_M_V_END: nparams = SP_M_V_END + 1; break; default: impossible("MONSTER with unknown variable param type!"); break; } opvar_free(parm); if (OV_i(varparam) != SP_M_V_END) { opvar_free(varparam); OV_pop(varparam); } } if (!OV_pop_c(mcoord)) panic("no monster coord?"); if (!OV_pop_typ(id, SPOVAR_MONST)) panic("no mon type"); tmpmons.id = SP_MONST_PM(OV_i(id)); tmpmons.class = SP_MONST_CLASS(OV_i(id)); tmpmons.coord = OV_i(mcoord); tmpmons.has_invent = OV_i(has_inv); create_monster(&tmpmons, coder->croom); Free(tmpmons.name.str); Free(tmpmons.appear_as.str); opvar_free(id); opvar_free(mcoord); opvar_free(has_inv); opvar_free(varparam); } void spo_object(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_object"; int nparams = 0; long quancnt; struct opvar *varparam; struct opvar *id, *containment; object tmpobj; tmpobj.spe = -127; tmpobj.curse_state = -1; tmpobj.corpsenm = NON_PM; tmpobj.name.str = (char *) 0; tmpobj.quan = -1; tmpobj.buried = 0; tmpobj.lit = 0; tmpobj.eroded = 0; tmpobj.locked = 0; tmpobj.trapped = 0; tmpobj.recharged = 0; tmpobj.invis = 0; tmpobj.greased = 0; tmpobj.broken = 0; tmpobj.coord = SP_COORD_PACK_RANDOM(0); if (!OV_pop_i(containment)) return; if (!OV_pop_i(varparam)) return; while ((nparams++ < (SP_O_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT) && (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_O_V_END)) { struct opvar *parm; OV_pop(parm); switch (OV_i(varparam)) { case SP_O_V_NAME: if ((OV_typ(parm) == SPOVAR_STRING) && !tmpobj.name.str) tmpobj.name.str = dupstr(OV_s(parm)); break; case SP_O_V_CORPSENM: if (OV_typ(parm) == SPOVAR_MONST) { char monclass = SP_MONST_CLASS(OV_i(parm)); int monid = SP_MONST_PM(OV_i(parm)); if (monid >= 0 && monid < NUMMONS) { tmpobj.corpsenm = monid; break; /* we're done! */ } else { struct permonst *pm = (struct permonst *) 0; if (def_char_to_monclass(monclass) != MAXMCLASSES) { pm = mkclass(def_char_to_monclass(monclass), G_NOGEN); } else { pm = rndmonst(); } if (pm) tmpobj.corpsenm = monsndx(pm); } } break; case SP_O_V_CURSE: if (OV_typ(parm) == SPOVAR_INT) tmpobj.curse_state = OV_i(parm); break; case SP_O_V_SPE: if (OV_typ(parm) == SPOVAR_INT) tmpobj.spe = OV_i(parm); break; case SP_O_V_QUAN: if (OV_typ(parm) == SPOVAR_INT) tmpobj.quan = OV_i(parm); break; case SP_O_V_BURIED: if (OV_typ(parm) == SPOVAR_INT) tmpobj.buried = OV_i(parm); break; case SP_O_V_LIT: if (OV_typ(parm) == SPOVAR_INT) tmpobj.lit = OV_i(parm); break; case SP_O_V_ERODED: if (OV_typ(parm) == SPOVAR_INT) tmpobj.eroded = OV_i(parm); break; case SP_O_V_LOCKED: if (OV_typ(parm) == SPOVAR_INT) tmpobj.locked = OV_i(parm); break; case SP_O_V_TRAPPED: if (OV_typ(parm) == SPOVAR_INT) tmpobj.trapped = OV_i(parm); break; case SP_O_V_RECHARGED: if (OV_typ(parm) == SPOVAR_INT) tmpobj.recharged = OV_i(parm); break; case SP_O_V_INVIS: if (OV_typ(parm) == SPOVAR_INT) tmpobj.invis = OV_i(parm); break; case SP_O_V_GREASED: if (OV_typ(parm) == SPOVAR_INT) tmpobj.greased = OV_i(parm); break; case SP_O_V_BROKEN: if (OV_typ(parm) == SPOVAR_INT) tmpobj.broken = OV_i(parm); break; case SP_O_V_COORD: if (OV_typ(parm) != SPOVAR_COORD) panic("no coord for obj?"); tmpobj.coord = OV_i(parm); break; case SP_O_V_END: nparams = SP_O_V_END + 1; break; default: impossible("OBJECT with unknown variable param type!"); break; } opvar_free(parm); if (OV_i(varparam) != SP_O_V_END) { opvar_free(varparam); OV_pop(varparam); } } if (!OV_pop_typ(id, SPOVAR_OBJ)) panic("no obj type"); tmpobj.id = SP_OBJ_TYP(OV_i(id)); tmpobj.class = SP_OBJ_CLASS(OV_i(id)); tmpobj.containment = OV_i(containment); quancnt = (tmpobj.id > STRANGE_OBJECT) ? tmpobj.quan : 0; do { create_object(&tmpobj, coder->croom); quancnt--; } while ((quancnt > 0) && ((tmpobj.id > STRANGE_OBJECT) && !objects[tmpobj.id].oc_merge)); Free(tmpobj.name.str); opvar_free(varparam); opvar_free(id); opvar_free(containment); } void spo_level_flags(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_level_flags"; struct opvar *flagdata; long lflags; if (!OV_pop_i(flagdata)) return; lflags = OV_i(flagdata); if (lflags & NOTELEPORT) level.flags.noteleport = 1; if (lflags & HARDFLOOR) level.flags.hardfloor = 1; if (lflags & NOMMAP) level.flags.nommap = 1; if (lflags & SHORTSIGHTED) level.flags.shortsighted = 1; if (lflags & ARBOREAL) level.flags.arboreal = 1; if (lflags & MAZELEVEL) level.flags.is_maze_lev = 1; if (lflags & PREMAPPED) coder->premapped = TRUE; if (lflags & SHROUD) level.flags.hero_memory = 0; if (lflags & GRAVEYARD) level.flags.graveyard = 1; if (lflags & ICEDPOOLS) icedpools = TRUE; if (lflags & SOLIDIFY) coder->solidify = TRUE; if (lflags & CORRMAZE) level.flags.corrmaze = TRUE; if (lflags & CHECK_INACCESSIBLES) coder->check_inaccessibles = TRUE; opvar_free(flagdata); } void spo_initlevel(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_initlevel"; lev_init init_lev; struct opvar *init_style, *fg, *bg, *smoothed, *joined, *lit, *walled, *filling; if (!OV_pop_i(fg) || !OV_pop_i(bg) || !OV_pop_i(smoothed) || !OV_pop_i(joined) || !OV_pop_i(lit) || !OV_pop_i(walled) || !OV_pop_i(filling) || !OV_pop_i(init_style)) return; splev_init_present = TRUE; init_lev.init_style = OV_i(init_style); init_lev.fg = OV_i(fg); init_lev.bg = OV_i(bg); init_lev.smoothed = OV_i(smoothed); init_lev.joined = OV_i(joined); init_lev.lit = OV_i(lit); init_lev.walled = OV_i(walled); init_lev.filling = OV_i(filling); coder->lvl_is_joined = OV_i(joined); splev_initlev(&init_lev); opvar_free(init_style); opvar_free(fg); opvar_free(bg); opvar_free(smoothed); opvar_free(joined); opvar_free(lit); opvar_free(walled); opvar_free(filling); } void spo_engraving(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_engraving"; struct opvar *etyp, *txt, *ecoord; xchar x, y; if (!OV_pop_i(etyp) || !OV_pop_s(txt) || !OV_pop_c(ecoord)) return; get_location_coord(&x, &y, DRY, coder->croom, OV_i(ecoord)); make_engr_at(x, y, OV_s(txt), 0L, OV_i(etyp)); opvar_free(etyp); opvar_free(txt); opvar_free(ecoord); } void spo_mineralize(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_mineralize"; struct opvar *kelp_pool, *kelp_moat, *gold_prob, *gem_prob; if (!OV_pop_i(gem_prob) || !OV_pop_i(gold_prob) || !OV_pop_i(kelp_moat) || !OV_pop_i(kelp_pool)) return; mineralize(OV_i(kelp_pool), OV_i(kelp_moat), OV_i(gold_prob), OV_i(gem_prob), TRUE); opvar_free(gem_prob); opvar_free(gold_prob); opvar_free(kelp_moat); opvar_free(kelp_pool); } void spo_room(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_room"; if (coder->n_subroom > MAX_NESTED_ROOMS) { panic("Too deeply nested rooms?!"); } else { struct opvar *rflags, *h, *w, *yalign, *xalign, *y, *x, *rlit, *chance, *rtype; room tmproom; struct mkroom *tmpcr; if (!OV_pop_i(h) || !OV_pop_i(w) || !OV_pop_i(y) || !OV_pop_i(x) || !OV_pop_i(yalign) || !OV_pop_i(xalign) || !OV_pop_i(rflags) || !OV_pop_i(rlit) || !OV_pop_i(chance) || !OV_pop_i(rtype)) return; tmproom.x = OV_i(x); tmproom.y = OV_i(y); tmproom.w = OV_i(w); tmproom.h = OV_i(h); tmproom.xalign = OV_i(xalign); tmproom.yalign = OV_i(yalign); tmproom.rtype = OV_i(rtype); tmproom.chance = OV_i(chance); tmproom.rlit = OV_i(rlit); tmproom.filled = (OV_i(rflags) & (1 << 0)); /*tmproom.irregular = (OV_i(rflags) & (1 << 1));*/ tmproom.joined = !(OV_i(rflags) & (1 << 2)); opvar_free(x); opvar_free(y); opvar_free(w); opvar_free(h); opvar_free(xalign); opvar_free(yalign); opvar_free(rtype); opvar_free(chance); opvar_free(rlit); opvar_free(rflags); if (!coder->failed_room[coder->n_subroom - 1]) { tmpcr = build_room(&tmproom, coder->croom); if (tmpcr) { coder->tmproomlist[coder->n_subroom] = tmpcr; coder->failed_room[coder->n_subroom] = FALSE; coder->n_subroom++; return; } } /* failed to create parent room, so fail this too */ } coder->tmproomlist[coder->n_subroom] = (struct mkroom *) 0; coder->failed_room[coder->n_subroom] = TRUE; coder->n_subroom++; } void spo_endroom(coder) struct sp_coder *coder; { if (coder->n_subroom > 1) { coder->n_subroom--; coder->tmproomlist[coder->n_subroom] = NULL; coder->failed_room[coder->n_subroom] = TRUE; } else { /* no subroom, get out of top-level room */ /* Need to ensure xstart/ystart/xsize/ysize have something sensible, in case there's some stuff to be created outside the outermost room, and there's no MAP. */ if (xsize <= 1 && ysize <= 1) { xstart = 1; ystart = 0; xsize = COLNO - 1; ysize = ROWNO; } } } void spo_stair(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_stair"; xchar x, y; struct opvar *up, *scoord; struct trap *badtrap; if (!OV_pop_i(up) || !OV_pop_c(scoord)) return; get_location_coord(&x, &y, DRY, coder->croom, OV_i(scoord)); if ((badtrap = t_at(x, y)) != 0) deltrap(badtrap); mkstairs(x, y, (char) OV_i(up), coder->croom); SpLev_Map[x][y] = 1; opvar_free(scoord); opvar_free(up); } void spo_ladder(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_ladder"; xchar x, y; struct opvar *up, *lcoord; if (!OV_pop_i(up) || !OV_pop_c(lcoord)) return; get_location_coord(&x, &y, DRY, coder->croom, OV_i(lcoord)); levl[x][y].typ = LADDER; SpLev_Map[x][y] = 1; if (OV_i(up)) { xupladder = x; yupladder = y; levl[x][y].ladder = LA_UP; } else { xdnladder = x; ydnladder = y; levl[x][y].ladder = LA_DOWN; } opvar_free(lcoord); opvar_free(up); } void spo_grave(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_grave"; struct opvar *gcoord, *typ, *txt; schar x, y; if (!OV_pop_i(typ) || !OV_pop_s(txt) || !OV_pop_c(gcoord)) return; get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord)); if (isok(x, y) && !t_at(x, y)) { levl[x][y].typ = GRAVE; switch (OV_i(typ)) { case 2: make_grave(x, y, OV_s(txt)); break; case 1: make_grave(x, y, NULL); break; default: del_engr_at(x, y); break; } } opvar_free(gcoord); opvar_free(typ); opvar_free(txt); } void spo_altar(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_altar"; struct opvar *al, *shrine, *acoord; altar tmpaltar; if (!OV_pop_i(al) || !OV_pop_i(shrine) || !OV_pop_c(acoord)) return; tmpaltar.coord = OV_i(acoord); tmpaltar.align = OV_i(al); tmpaltar.shrine = OV_i(shrine); create_altar(&tmpaltar, coder->croom); opvar_free(acoord); opvar_free(shrine); opvar_free(al); } void spo_trap(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_trap"; struct opvar *type; struct opvar *tcoord; trap tmptrap; if (!OV_pop_i(type) || !OV_pop_c(tcoord)) return; tmptrap.coord = OV_i(tcoord); tmptrap.type = OV_i(type); create_trap(&tmptrap, coder->croom); opvar_free(tcoord); opvar_free(type); } void spo_gold(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_gold"; struct opvar *gcoord, *amt; schar x, y; long amount; if (!OV_pop_c(gcoord) || !OV_pop_i(amt)) return; amount = OV_i(amt); get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord)); if (amount == -1) amount = rnd(200); mkgold(amount, x, y); opvar_free(gcoord); opvar_free(amt); } void spo_corridor(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_corridor"; struct opvar *deswall, *desdoor, *desroom, *srcwall, *srcdoor, *srcroom; corridor tc; if (!OV_pop_i(deswall) || !OV_pop_i(desdoor) || !OV_pop_i(desroom) || !OV_pop_i(srcwall) || !OV_pop_i(srcdoor) || !OV_pop_i(srcroom)) return; tc.src.room = OV_i(srcroom); tc.src.door = OV_i(srcdoor); tc.src.wall = OV_i(srcwall); tc.dest.room = OV_i(desroom); tc.dest.door = OV_i(desdoor); tc.dest.wall = OV_i(deswall); create_corridor(&tc); opvar_free(deswall); opvar_free(desdoor); opvar_free(desroom); opvar_free(srcwall); opvar_free(srcdoor); opvar_free(srcroom); } struct opvar * selection_opvar(nbuf) char *nbuf; { struct opvar *ov; char buf[(COLNO * ROWNO) + 1]; if (!nbuf) { (void) memset(buf, 1, sizeof(buf)); buf[(COLNO * ROWNO)] = '\0'; ov = opvar_new_str(buf); } else { ov = opvar_new_str(nbuf); } ov->spovartyp = SPOVAR_SEL; return ov; } xchar selection_getpoint(x, y, ov) int x, y; struct opvar *ov; { if (!ov || ov->spovartyp != SPOVAR_SEL) return 0; if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO) return 0; return (ov->vardata.str[COLNO * y + x] - 1); } void selection_setpoint(x, y, ov, c) int x, y; struct opvar *ov; xchar c; { if (!ov || ov->spovartyp != SPOVAR_SEL) return; if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO) return; ov->vardata.str[COLNO * y + x] = (char) (c + 1); } struct opvar * selection_not(s) struct opvar *s; { struct opvar *ov; int x, y; ov = selection_opvar((char *) 0); if (!ov) return NULL; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (!selection_getpoint(x, y, s)) selection_setpoint(x, y, ov, 1); return ov; } struct opvar * selection_logical_oper(s1, s2, oper) struct opvar *s1, *s2; char oper; { struct opvar *ov; int x, y; ov = selection_opvar((char *) 0); if (!ov) return NULL; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { switch (oper) { default: case '|': if (selection_getpoint(x, y, s1) || selection_getpoint(x, y, s2)) selection_setpoint(x, y, ov, 1); break; case '&': if (selection_getpoint(x, y, s1) && selection_getpoint(x, y, s2)) selection_setpoint(x, y, ov, 1); break; } } return ov; } struct opvar * selection_filter_mapchar(ov, mc) struct opvar *ov; struct opvar *mc; { int x, y; schar mapc; xchar lit; struct opvar *ret = selection_opvar((char *) 0); if (!ov || !mc || !ret) return NULL; mapc = SP_MAPCHAR_TYP(OV_i(mc)); lit = SP_MAPCHAR_LIT(OV_i(mc)); for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (selection_getpoint(x, y, ov) && (levl[x][y].typ == mapc)) { switch (lit) { default: case -2: selection_setpoint(x, y, ret, 1); break; case -1: selection_setpoint(x, y, ret, rn2(2)); break; case 0: case 1: if (levl[x][y].lit == lit) selection_setpoint(x, y, ret, 1); break; } } return ret; } void selection_filter_percent(ov, percent) struct opvar *ov; int percent; { int x, y; if (!ov) return; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (selection_getpoint(x, y, ov) && (rn2(100) >= percent)) selection_setpoint(x, y, ov, 0); } STATIC_OVL int selection_rndcoord(ov, x, y, removeit) struct opvar *ov; schar *x, *y; boolean removeit; { int idx = 0; int c; int dx, dy; for (dx = 0; dx < COLNO; dx++) for (dy = 0; dy < ROWNO; dy++) if (isok(dx, dy) && selection_getpoint(dx, dy, ov)) idx++; if (idx) { c = rn2(idx); for (dx = 0; dx < COLNO; dx++) for (dy = 0; dy < ROWNO; dy++) if (isok(dx, dy) && selection_getpoint(dx, dy, ov)) { if (!c) { *x = dx; *y = dy; if (removeit) selection_setpoint(dx, dy, ov, 0); return 1; } c--; } } *x = *y = -1; return 0; } void selection_do_grow(ov, dir) struct opvar *ov; int dir; { int x, y, c; char tmp[COLNO][ROWNO]; if (ov->spovartyp != SPOVAR_SEL) return; if (!ov) return; (void) memset(tmp, 0, sizeof(tmp)); for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { c = 0; if ((dir & W_WEST) && (x > 0) && (selection_getpoint(x - 1, y, ov))) c++; if ((dir & (W_WEST | W_NORTH)) && (x > 0) && (y > 0) && (selection_getpoint(x - 1, y - 1, ov))) c++; if ((dir & W_NORTH) && (y > 0) && (selection_getpoint(x, y - 1, ov))) c++; if ((dir & (W_NORTH | W_EAST)) && (y > 0) && (x < COLNO - 1) && (selection_getpoint(x + 1, y - 1, ov))) c++; if ((dir & W_EAST) && (x < COLNO - 1) && (selection_getpoint(x + 1, y, ov))) c++; if ((dir & (W_EAST | W_SOUTH)) && (x < COLNO - 1) && (y < ROWNO - 1) && (selection_getpoint(x + 1, y + 1, ov))) c++; if ((dir & W_SOUTH) && (y < ROWNO - 1) && (selection_getpoint(x, y + 1, ov))) c++; if ((dir & (W_SOUTH | W_WEST)) && (y < ROWNO - 1) && (x > 0) && (selection_getpoint(x - 1, y + 1, ov))) c++; if (c) tmp[x][y] = 1; } for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (tmp[x][y]) selection_setpoint(x, y, ov, 1); } STATIC_VAR int FDECL((*selection_flood_check_func), (int, int)); STATIC_VAR schar floodfillchk_match_under_typ; STATIC_OVL void set_selection_floodfillchk(f) int FDECL((*f), (int, int)); { selection_flood_check_func = f; } STATIC_OVL int floodfillchk_match_under(x,y) int x,y; { return (floodfillchk_match_under_typ == levl[x][y].typ); } STATIC_OVL int floodfillchk_match_accessible(x, y) int x, y; { return (ACCESSIBLE(levl[x][y].typ) || levl[x][y].typ == SDOOR || levl[x][y].typ == SCORR); } STATIC_OVL void selection_floodfill(ov, x, y, diagonals) struct opvar *ov; int x, y; boolean diagonals; { static const char nhFunc[] = "selection_floodfill"; struct opvar *tmp = selection_opvar((char *) 0); #define SEL_FLOOD_STACK (COLNO * ROWNO) #define SEL_FLOOD(nx, ny) \ do { \ if (idx < SEL_FLOOD_STACK) { \ dx[idx] = (nx); \ dy[idx] = (ny); \ idx++; \ } else \ panic(floodfill_stack_overrun); \ } while (0) #define SEL_FLOOD_CHKDIR(mx,my,sel) \ if (isok((mx), (my)) \ && (*selection_flood_check_func)((mx), (my)) \ && !selection_getpoint((mx), (my), (sel))) \ SEL_FLOOD((mx), (my)) static const char floodfill_stack_overrun[] = "floodfill stack overrun"; int idx = 0; xchar dx[SEL_FLOOD_STACK]; xchar dy[SEL_FLOOD_STACK]; if (selection_flood_check_func == NULL) { opvar_free(tmp); return; } SEL_FLOOD(x, y); do { idx--; x = dx[idx]; y = dy[idx]; if (isok(x, y)) { selection_setpoint(x, y, ov, 1); selection_setpoint(x, y, tmp, 1); } SEL_FLOOD_CHKDIR((x + 1), y, tmp); SEL_FLOOD_CHKDIR((x - 1), y, tmp); SEL_FLOOD_CHKDIR(x, (y + 1), tmp); SEL_FLOOD_CHKDIR(x, (y - 1), tmp); if (diagonals) { SEL_FLOOD_CHKDIR((x + 1), (y + 1), tmp); SEL_FLOOD_CHKDIR((x - 1), (y - 1), tmp); SEL_FLOOD_CHKDIR((x - 1), (y + 1), tmp); SEL_FLOOD_CHKDIR((x + 1), (y - 1), tmp); } } while (idx > 0); #undef SEL_FLOOD #undef SEL_FLOOD_STACK #undef SEL_FLOOD_CHKDIR opvar_free(tmp); } /* McIlroy's Ellipse Algorithm */ void selection_do_ellipse(ov, xc, yc, a, b, filled) struct opvar *ov; int xc, yc, a, b, filled; { /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */ int x = 0, y = b; long a2 = (long) a * a, b2 = (long) b * b; long crit1 = -(a2 / 4 + a % 2 + b2); long crit2 = -(b2 / 4 + b % 2 + a2); long crit3 = -(b2 / 4 + b % 2); long t = -a2 * y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */ long dxt = 2 * b2 * x, dyt = -2 * a2 * y; long d2xt = 2 * b2, d2yt = 2 * a2; long width = 1; long i; if (!ov) return; filled = !filled; if (!filled) { while (y >= 0 && x <= a) { selection_setpoint(xc + x, yc + y, ov, 1); if (x != 0 || y != 0) selection_setpoint(xc - x, yc - y, ov, 1); if (x != 0 && y != 0) { selection_setpoint(xc + x, yc - y, ov, 1); selection_setpoint(xc - x, yc + y, ov, 1); } if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */ || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */ x++; dxt += d2xt; t += dxt; } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */ y--; dyt += d2yt; t += dyt; } else { x++; dxt += d2xt; t += dxt; y--; dyt += d2yt; t += dyt; } } } else { while (y >= 0 && x <= a) { if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */ || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */ x++; dxt += d2xt; t += dxt; width += 2; } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */ for (i = 0; i < width; i++) selection_setpoint(xc - x + i, yc - y, ov, 1); if (y != 0) for (i = 0; i < width; i++) selection_setpoint(xc - x + i, yc + y, ov, 1); y--; dyt += d2yt; t += dyt; } else { for (i = 0; i < width; i++) selection_setpoint(xc - x + i, yc - y, ov, 1); if (y != 0) for (i = 0; i < width; i++) selection_setpoint(xc - x + i, yc + y, ov, 1); x++; dxt += d2xt; t += dxt; y--; dyt += d2yt; t += dyt; width += 2; } } } } /* distance from line segment (x1,y1, x2,y2) to point (x3,y3) */ long line_dist_coord(x1, y1, x2, y2, x3, y3) long x1, y1, x2, y2, x3, y3; { long px = x2 - x1; long py = y2 - y1; long s = px * px + py * py; long x, y, dx, dy, dist = 0; float lu = 0; if (x1 == x2 && y1 == y2) return isqrt(dist2(x1, y1, x3, y3)); lu = ((x3 - x1) * px + (y3 - y1) * py) / (float) s; if (lu > 1) lu = 1; else if (lu < 0) lu = 0; x = x1 + lu * px; y = y1 + lu * py; dx = x - x3; dy = y - y3; dist = isqrt(dx * dx + dy * dy); return dist; } void selection_do_gradient(ov, x, y, x2, y2, gtyp, mind, maxd, limit) struct opvar *ov; long x, y, x2, y2, gtyp, mind, maxd, limit; { long dx, dy, dofs; if (mind > maxd) { long tmp = mind; mind = maxd; maxd = tmp; } dofs = maxd - mind; if (dofs < 1) dofs = 1; switch (gtyp) { default: case SEL_GRADIENT_RADIAL: { for (dx = 0; dx < COLNO; dx++) for (dy = 0; dy < ROWNO; dy++) { long d0 = line_dist_coord(x, y, x2, y2, dx, dy); if (d0 >= mind && (!limit || d0 <= maxd)) { if (d0 - mind > rn2(dofs)) selection_setpoint(dx, dy, ov, 1); } } break; } case SEL_GRADIENT_SQUARE: { for (dx = 0; dx < COLNO; dx++) for (dy = 0; dy < ROWNO; dy++) { long d1 = line_dist_coord(x, y, x2, y2, x, dy); long d2 = line_dist_coord(x, y, x2, y2, dx, y); long d3 = line_dist_coord(x, y, x2, y2, x2, dy); long d4 = line_dist_coord(x, y, x2, y2, dx, y2); long d5 = line_dist_coord(x, y, x2, y2, dx, dy); long d0 = min(d5, min(max(d1, d2), max(d3, d4))); if (d0 >= mind && (!limit || d0 <= maxd)) { if (d0 - mind > rn2(dofs)) selection_setpoint(dx, dy, ov, 1); } } break; } /*case*/ } /*switch*/ } /* bresenham line algo */ void selection_do_line(x1, y1, x2, y2, ov) schar x1, y1, x2, y2; struct opvar *ov; { int d0, dx, dy, ai, bi, xi, yi; if (x1 < x2) { xi = 1; dx = x2 - x1; } else { xi = -1; dx = x1 - x2; } if (y1 < y2) { yi = 1; dy = y2 - y1; } else { yi = -1; dy = y1 - y2; } selection_setpoint(x1, y1, ov, 1); if (dx > dy) { ai = (dy - dx) * 2; bi = dy * 2; d0 = bi - dx; do { if (d0 >= 0) { y1 += yi; d0 += ai; } else d0 += bi; x1 += xi; selection_setpoint(x1, y1, ov, 1); } while (x1 != x2); } else { ai = (dx - dy) * 2; bi = dx * 2; d0 = bi - dy; do { if (d0 >= 0) { x1 += xi; d0 += ai; } else d0 += bi; y1 += yi; selection_setpoint(x1, y1, ov, 1); } while (y1 != y2); } } void selection_do_randline(x1, y1, x2, y2, rough, rec, ov) schar x1, y1, x2, y2, rough, rec; struct opvar *ov; { int mx, my; int dx, dy; if (rec < 1) { return; } if ((x2 == x1) && (y2 == y1)) { selection_setpoint(x1, y1, ov, 1); return; } if (rough > max(abs(x2 - x1), abs(y2 - y1))) rough = max(abs(x2 - x1), abs(y2 - y1)); if (rough < 2) { mx = ((x1 + x2) / 2); my = ((y1 + y2) / 2); } else { do { dx = (Rand() % rough) - (rough / 2); dy = (Rand() % rough) - (rough / 2); mx = ((x1 + x2) / 2) + dx; my = ((y1 + y2) / 2) + dy; } while ((mx > COLNO - 1 || mx < 0 || my < 0 || my > ROWNO - 1)); } selection_setpoint(mx, my, ov, 1); rough = (rough * 2) / 3; rec--; selection_do_randline(x1, y1, mx, my, rough, rec, ov); selection_do_randline(mx, my, x2, y2, rough, rec, ov); } void selection_iterate(ov, func, arg) struct opvar *ov; select_iter_func func; genericptr_t arg; { int x, y; /* yes, this is very naive, but it's not _that_ expensive. */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (selection_getpoint(x, y, ov)) (*func)(x, y, arg); } void sel_set_ter(x, y, arg) int x, y; genericptr_t arg; { terrain terr; terr = *(terrain *) arg; SET_TYPLIT(x, y, terr.ter, terr.tlit); /* handle doors and secret doors */ if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) { if (levl[x][y].typ == SDOOR) levl[x][y].doormask = D_CLOSED; if (x && (IS_WALL(levl[x - 1][y].typ) || levl[x - 1][y].horizontal)) levl[x][y].horizontal = 1; } } void sel_set_feature(x, y, arg) int x, y; genericptr_t arg; { if (IS_FURNITURE(levl[x][y].typ)) return; levl[x][y].typ = (*(int *) arg); } void sel_set_door(dx, dy, arg) int dx, dy; genericptr_t arg; { xchar typ = *(xchar *) arg; xchar x = dx; xchar y = dy; if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR) levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR; if (typ & D_SECRET) { typ &= ~D_SECRET; if (typ < D_CLOSED) typ = D_CLOSED; } levl[x][y].doormask = typ; SpLev_Map[x][y] = 1; } void spo_door(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_door"; struct opvar *msk, *sel; xchar typ; if (!OV_pop_i(msk) || !OV_pop_typ(sel, SPOVAR_SEL)) return; typ = OV_i(msk) == -1 ? rnddoor() : (xchar) OV_i(msk); selection_iterate(sel, sel_set_door, (genericptr_t) &typ); opvar_free(sel); opvar_free(msk); } void spo_feature(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_feature"; struct opvar *sel; int typ; if (!OV_pop_typ(sel, SPOVAR_SEL)) return; switch (coder->opcode) { default: impossible("spo_feature called with wrong opcode %i.", coder->opcode); break; case SPO_FOUNTAIN: typ = FOUNTAIN; break; case SPO_SINK: typ = SINK; break; case SPO_POOL: typ = POOL; break; } selection_iterate(sel, sel_set_feature, (genericptr_t) &typ); opvar_free(sel); } void spo_terrain(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_terrain"; terrain tmpterrain; struct opvar *ter, *sel; if (!OV_pop_typ(ter, SPOVAR_MAPCHAR) || !OV_pop_typ(sel, SPOVAR_SEL)) return; tmpterrain.ter = SP_MAPCHAR_TYP(OV_i(ter)); tmpterrain.tlit = SP_MAPCHAR_LIT(OV_i(ter)); selection_iterate(sel, sel_set_ter, (genericptr_t) &tmpterrain); opvar_free(ter); opvar_free(sel); } void spo_replace_terrain(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_replace_terrain"; replaceterrain rt; struct opvar *reg, *from_ter, *to_ter, *chance; if (!OV_pop_i(chance) || !OV_pop_typ(to_ter, SPOVAR_MAPCHAR) || !OV_pop_typ(from_ter, SPOVAR_MAPCHAR) || !OV_pop_r(reg)) return; rt.chance = OV_i(chance); rt.tolit = SP_MAPCHAR_LIT(OV_i(to_ter)); rt.toter = SP_MAPCHAR_TYP(OV_i(to_ter)); rt.fromter = SP_MAPCHAR_TYP(OV_i(from_ter)); /* TODO: use SP_MAPCHAR_LIT(OV_i(from_ter)) too */ rt.x1 = SP_REGION_X1(OV_i(reg)); rt.y1 = SP_REGION_Y1(OV_i(reg)); rt.x2 = SP_REGION_X2(OV_i(reg)); rt.y2 = SP_REGION_Y2(OV_i(reg)); replace_terrain(&rt, coder->croom); opvar_free(reg); opvar_free(from_ter); opvar_free(to_ter); opvar_free(chance); } STATIC_OVL boolean generate_way_out_method(nx,ny, ov) int nx,ny; struct opvar *ov; { static const char nhFunc[] = "generate_way_out_method"; const int escapeitems[] = { PICK_AXE, DWARVISH_MATTOCK, WAN_DIGGING, WAN_TELEPORTATION, SCR_TELEPORTATION, RIN_TELEPORTATION }; struct opvar *ov2 = selection_opvar((char *) 0), *ov3; schar x, y; boolean res = TRUE; selection_floodfill(ov2, nx, ny, TRUE); ov3 = opvar_clone(ov2); /* try to make a secret door */ while (selection_rndcoord(ov3, &x, &y, TRUE)) { if (isok(x+1, y) && !selection_getpoint(x+1, y, ov) && IS_WALL(levl[x+1][y].typ) && isok(x+2, y) && selection_getpoint(x+2, y, ov) && ACCESSIBLE(levl[x+2][y].typ)) { levl[x+1][y].typ = SDOOR; goto gotitdone; } if (isok(x-1, y) && !selection_getpoint(x-1, y, ov) && IS_WALL(levl[x-1][y].typ) && isok(x-2, y) && selection_getpoint(x-2, y, ov) && ACCESSIBLE(levl[x-2][y].typ)) { levl[x-1][y].typ = SDOOR; goto gotitdone; } if (isok(x, y+1) && !selection_getpoint(x, y+1, ov) && IS_WALL(levl[x][y+1].typ) && isok(x, y+2) && selection_getpoint(x, y+2, ov) && ACCESSIBLE(levl[x][y+2].typ)) { levl[x][y+1].typ = SDOOR; goto gotitdone; } if (isok(x, y-1) && !selection_getpoint(x, y-1, ov) && IS_WALL(levl[x][y-1].typ) && isok(x, y-2) && selection_getpoint(x, y-2, ov) && ACCESSIBLE(levl[x][y-2].typ)) { levl[x][y-1].typ = SDOOR; goto gotitdone; } } /* try to make a hole or a trapdoor */ if (Can_fall_thru(&u.uz)) { opvar_free(ov3); ov3 = opvar_clone(ov2); while (selection_rndcoord(ov3, &x, &y, TRUE)) { if (maketrap(x,y, rn2(2) ? HOLE : TRAPDOOR)) goto gotitdone; } } /* generate one of the escape items */ if (selection_rndcoord(ov2, &x, &y, FALSE)) { mksobj_at(escapeitems[rn2(SIZE(escapeitems))], x, y, TRUE, FALSE); goto gotitdone; } res = FALSE; gotitdone: opvar_free(ov2); opvar_free(ov3); return res; } STATIC_OVL void ensure_way_out() { static const char nhFunc[] = "ensure_way_out"; struct opvar *ov = selection_opvar((char *) 0); struct trap *ttmp = ftrap; int x,y; boolean ret = TRUE; set_selection_floodfillchk(floodfillchk_match_accessible); if (xupstair && !selection_getpoint(xupstair, yupstair, ov)) selection_floodfill(ov, xupstair, yupstair, TRUE); if (xdnstair && !selection_getpoint(xdnstair, ydnstair, ov)) selection_floodfill(ov, xdnstair, ydnstair, TRUE); if (xupladder && !selection_getpoint(xupladder, yupladder, ov)) selection_floodfill(ov, xupladder, yupladder, TRUE); if (xdnladder && !selection_getpoint(xdnladder, ydnladder, ov)) selection_floodfill(ov, xdnladder, ydnladder, TRUE); while (ttmp) { if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) && !selection_getpoint(ttmp->tx, ttmp->ty, ov)) selection_floodfill(ov, ttmp->tx, ttmp->ty, TRUE); ttmp = ttmp->ntrap; } do { ret = TRUE; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (ACCESSIBLE(levl[x][y].typ) && !selection_getpoint(x, y, ov)) { if (generate_way_out_method(x,y, ov)) selection_floodfill(ov, x,y, TRUE); ret = FALSE; goto outhere; } outhere: ; } while (!ret); opvar_free(ov); } void spo_levregion(coder) struct sp_coder *coder; { static const char nhFunc[] = "spot_levregion"; struct opvar *rname, *padding, *rtype, *del_islev, *dy2, *dx2, *dy1, *dx1, *in_islev, *iy2, *ix2, *iy1, *ix1; lev_region *tmplregion; if (!OV_pop_s(rname) || !OV_pop_i(padding) || !OV_pop_i(rtype) || !OV_pop_i(del_islev) || !OV_pop_i(dy2) || !OV_pop_i(dx2) || !OV_pop_i(dy1) || !OV_pop_i(dx1) || !OV_pop_i(in_islev) || !OV_pop_i(iy2) || !OV_pop_i(ix2) || !OV_pop_i(iy1) || !OV_pop_i(ix1)) return; tmplregion = (lev_region *) alloc(sizeof(lev_region)); tmplregion->inarea.x1 = OV_i(ix1); tmplregion->inarea.y1 = OV_i(iy1); tmplregion->inarea.x2 = OV_i(ix2); tmplregion->inarea.y2 = OV_i(iy2); tmplregion->delarea.x1 = OV_i(dx1); tmplregion->delarea.y1 = OV_i(dy1); tmplregion->delarea.x2 = OV_i(dx2); tmplregion->delarea.y2 = OV_i(dy2); tmplregion->in_islev = OV_i(in_islev); tmplregion->del_islev = OV_i(del_islev); tmplregion->rtype = OV_i(rtype); tmplregion->padding = OV_i(padding); tmplregion->rname.str = dupstr(OV_s(rname)); if (!tmplregion->in_islev) { get_location(&tmplregion->inarea.x1, &tmplregion->inarea.y1, ANY_LOC, (struct mkroom *) 0); get_location(&tmplregion->inarea.x2, &tmplregion->inarea.y2, ANY_LOC, (struct mkroom *) 0); } if (!tmplregion->del_islev) { get_location(&tmplregion->delarea.x1, &tmplregion->delarea.y1, ANY_LOC, (struct mkroom *) 0); get_location(&tmplregion->delarea.x2, &tmplregion->delarea.y2, ANY_LOC, (struct mkroom *) 0); } if (num_lregions) { /* realloc the lregion space to add the new one */ lev_region *newl = (lev_region *) alloc( sizeof(lev_region) * (unsigned) (1 + num_lregions)); (void) memcpy((genericptr_t) (newl), (genericptr_t) lregions, sizeof(lev_region) * num_lregions); Free(lregions); num_lregions++; lregions = newl; } else { num_lregions = 1; lregions = (lev_region *) alloc(sizeof(lev_region)); } (void) memcpy(&lregions[num_lregions - 1], tmplregion, sizeof(lev_region)); free(tmplregion); opvar_free(dx1); opvar_free(dy1); opvar_free(dx2); opvar_free(dy2); opvar_free(ix1); opvar_free(iy1); opvar_free(ix2); opvar_free(iy2); opvar_free(del_islev); opvar_free(in_islev); opvar_free(rname); opvar_free(rtype); opvar_free(padding); } void spo_region(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_region"; struct opvar *rtype, *rlit, *rflags, *area; xchar dx1, dy1, dx2, dy2; register struct mkroom *troom; boolean prefilled, room_not_needed, irregular, joined; if (!OV_pop_i(rflags) || !OV_pop_i(rtype) || !OV_pop_i(rlit) || !OV_pop_r(area)) return; prefilled = !(OV_i(rflags) & (1 << 0)); irregular = (OV_i(rflags) & (1 << 1)); joined = !(OV_i(rflags) & (1 << 2)); if (OV_i(rtype) > MAXRTYPE) { OV_i(rtype) -= MAXRTYPE + 1; prefilled = TRUE; } else prefilled = FALSE; if (OV_i(rlit) < 0) OV_i(rlit) = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; dx1 = SP_REGION_X1(OV_i(area)); dy1 = SP_REGION_Y1(OV_i(area)); dx2 = SP_REGION_X2(OV_i(area)); dy2 = SP_REGION_Y2(OV_i(area)); get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0); get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0); /* for an ordinary room, `prefilled' is a flag to force an actual room to be created (such rooms are used to control placement of migrating monster arrivals) */ room_not_needed = (OV_i(rtype) == OROOM && !irregular && !prefilled); if (room_not_needed || nroom >= MAXNROFROOMS) { region tmpregion; if (!room_not_needed) impossible("Too many rooms on new level!"); tmpregion.rlit = OV_i(rlit); tmpregion.x1 = dx1; tmpregion.y1 = dy1; tmpregion.x2 = dx2; tmpregion.y2 = dy2; light_region(&tmpregion); opvar_free(area); opvar_free(rflags); opvar_free(rlit); opvar_free(rtype); return; } troom = &rooms[nroom]; /* mark rooms that must be filled, but do it later */ if (OV_i(rtype) != OROOM) troom->needfill = (prefilled ? 2 : 1); troom->needjoining = joined; if (irregular) { min_rx = max_rx = dx1; min_ry = max_ry = dy1; smeq[nroom] = nroom; flood_fill_rm(dx1, dy1, nroom + ROOMOFFSET, OV_i(rlit), TRUE); add_room(min_rx, min_ry, max_rx, max_ry, FALSE, OV_i(rtype), TRUE); troom->rlit = OV_i(rlit); troom->irregular = TRUE; } else { add_room(dx1, dy1, dx2, dy2, OV_i(rlit), OV_i(rtype), TRUE); #ifdef SPECIALIZATION topologize(troom, FALSE); /* set roomno */ #else topologize(troom); /* set roomno */ #endif } if (!room_not_needed) { if (coder->n_subroom > 1) impossible("region as subroom"); else { coder->tmproomlist[coder->n_subroom] = troom; coder->failed_room[coder->n_subroom] = FALSE; coder->n_subroom++; } } opvar_free(area); opvar_free(rflags); opvar_free(rlit); opvar_free(rtype); } void spo_drawbridge(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_drawbridge"; xchar x, y; struct opvar *dir, *db_open, *dcoord; if (!OV_pop_i(dir) || !OV_pop_i(db_open) || !OV_pop_c(dcoord)) return; get_location_coord(&x, &y, DRY | WET | HOT, coder->croom, OV_i(dcoord)); if (!create_drawbridge(x, y, OV_i(dir), OV_i(db_open))) impossible("Cannot create drawbridge."); SpLev_Map[x][y] = 1; opvar_free(dcoord); opvar_free(db_open); opvar_free(dir); } void spo_mazewalk(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_mazewalk"; xchar x, y; struct opvar *ftyp, *fstocked, *fdir, *mcoord; int dir; if (!OV_pop_i(ftyp) || !OV_pop_i(fstocked) || !OV_pop_i(fdir) || !OV_pop_c(mcoord)) return; dir = OV_i(fdir); get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(mcoord)); if (!isok(x, y)) return; if (OV_i(ftyp) < 1) { OV_i(ftyp) = level.flags.corrmaze ? CORR : ROOM; } /* don't use move() - it doesn't use W_NORTH, etc. */ switch (dir) { case W_NORTH: --y; break; case W_SOUTH: y++; break; case W_EAST: x++; break; case W_WEST: --x; break; default: impossible("spo_mazewalk: Bad MAZEWALK direction"); } if (!IS_DOOR(levl[x][y].typ)) { levl[x][y].typ = OV_i(ftyp); levl[x][y].flags = 0; } /* * We must be sure that the parity of the coordinates for * walkfrom() is odd. But we must also take into account * what direction was chosen. */ if (!(x % 2)) { if (dir == W_EAST) x++; else x--; /* no need for IS_DOOR check; out of map bounds */ levl[x][y].typ = OV_i(ftyp); levl[x][y].flags = 0; } if (!(y % 2)) { if (dir == W_SOUTH) y++; else y--; } walkfrom(x, y, OV_i(ftyp)); if (OV_i(fstocked)) fill_empty_maze(); opvar_free(mcoord); opvar_free(fdir); opvar_free(fstocked); opvar_free(ftyp); } void spo_wall_property(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_wall_property"; struct opvar *r; xchar dx1, dy1, dx2, dy2; int wprop = (coder->opcode == SPO_NON_DIGGABLE) ? W_NONDIGGABLE : W_NONPASSWALL; if (!OV_pop_r(r)) return; dx1 = SP_REGION_X1(OV_i(r)); dy1 = SP_REGION_Y1(OV_i(r)); dx2 = SP_REGION_X2(OV_i(r)); dy2 = SP_REGION_Y2(OV_i(r)); get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0); get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0); set_wall_property(dx1, dy1, dx2, dy2, wprop); opvar_free(r); } void spo_room_door(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_room_door"; struct opvar *wall, *secret, *mask, *pos; room_door tmpd; if (!OV_pop_i(wall) || !OV_pop_i(secret) || !OV_pop_i(mask) || !OV_pop_i(pos) || !coder->croom) return; tmpd.secret = OV_i(secret); tmpd.mask = OV_i(mask); tmpd.pos = OV_i(pos); tmpd.wall = OV_i(wall); create_door(&tmpd, coder->croom); opvar_free(wall); opvar_free(secret); opvar_free(mask); opvar_free(pos); } /*ARGSUSED*/ void sel_set_wallify(x, y, arg) int x, y; genericptr_t arg UNUSED; { wallify_map(x, y, x, y); } void spo_wallify(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_wallify"; struct opvar *typ, *r; int dx1, dy1, dx2, dy2; if (!OV_pop_i(typ)) return; switch (OV_i(typ)) { default: case 0: if (!OV_pop_r(r)) return; dx1 = (xchar) SP_REGION_X1(OV_i(r)); dy1 = (xchar) SP_REGION_Y1(OV_i(r)); dx2 = (xchar) SP_REGION_X2(OV_i(r)); dy2 = (xchar) SP_REGION_Y2(OV_i(r)); wallify_map(dx1 < 0 ? (xstart-1) : dx1, dy1 < 0 ? (ystart-1) : dy1, dx2 < 0 ? (xstart + xsize + 1) : dx2, dy2 < 0 ? (ystart + ysize + 1) : dy2); break; case 1: if (!OV_pop_typ(r, SPOVAR_SEL)) return; selection_iterate(r, sel_set_wallify, NULL); break; } opvar_free(r); opvar_free(typ); } void spo_map(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_map"; mazepart tmpmazepart; struct opvar *mpxs, *mpys, *mpmap, *mpa, *mpkeepr, *mpzalign; xchar halign, valign; xchar tmpxstart, tmpystart, tmpxsize, tmpysize; unpacked_coord upc; if (!OV_pop_i(mpxs) || !OV_pop_i(mpys) || !OV_pop_s(mpmap) || !OV_pop_i(mpkeepr) || !OV_pop_i(mpzalign) || !OV_pop_c(mpa)) return; tmpmazepart.xsize = OV_i(mpxs); tmpmazepart.ysize = OV_i(mpys); tmpmazepart.zaligntyp = OV_i(mpzalign); upc = get_unpacked_coord(OV_i(mpa), ANY_LOC); tmpmazepart.halign = upc.x; tmpmazepart.valign = upc.y; tmpxsize = xsize; tmpysize = ysize; tmpxstart = xstart; tmpystart = ystart; halign = tmpmazepart.halign; valign = tmpmazepart.valign; xsize = tmpmazepart.xsize; ysize = tmpmazepart.ysize; switch (tmpmazepart.zaligntyp) { default: case 0: break; case 1: switch ((int) halign) { case LEFT: xstart = splev_init_present ? 1 : 3; break; case H_LEFT: xstart = 2 + ((x_maze_max - 2 - xsize) / 4); break; case CENTER: xstart = 2 + ((x_maze_max - 2 - xsize) / 2); break; case H_RIGHT: xstart = 2 + ((x_maze_max - 2 - xsize) * 3 / 4); break; case RIGHT: xstart = x_maze_max - xsize - 1; break; } switch ((int) valign) { case TOP: ystart = 3; break; case CENTER: ystart = 2 + ((y_maze_max - 2 - ysize) / 2); break; case BOTTOM: ystart = y_maze_max - ysize - 1; break; } if (!(xstart % 2)) xstart++; if (!(ystart % 2)) ystart++; break; case 2: if (!coder->croom) { xstart = 1; ystart = 0; xsize = COLNO - 1 - tmpmazepart.xsize; ysize = ROWNO - tmpmazepart.ysize; } get_location_coord(&halign, &valign, ANY_LOC, coder->croom, OV_i(mpa)); xsize = tmpmazepart.xsize; ysize = tmpmazepart.ysize; xstart = halign; ystart = valign; break; } if ((ystart < 0) || (ystart + ysize > ROWNO)) { /* try to move the start a bit */ ystart += (ystart > 0) ? -2 : 2; if (ysize == ROWNO) ystart = 0; if (ystart < 0 || ystart + ysize > ROWNO) panic("reading special level with ysize too large"); } if (xsize <= 1 && ysize <= 1) { xstart = 1; ystart = 0; xsize = COLNO - 1; ysize = ROWNO; } else { xchar x, y; /* Load the map */ for (y = ystart; y < ystart + ysize; y++) for (x = xstart; x < xstart + xsize; x++) { xchar mptyp = (mpmap->vardata.str[(y - ystart) * xsize + (x - xstart)] - 1); if (mptyp >= MAX_TYPE) continue; levl[x][y].typ = mptyp; levl[x][y].lit = FALSE; /* clear out levl: load_common_data may set them */ levl[x][y].flags = 0; levl[x][y].horizontal = 0; levl[x][y].roomno = 0; levl[x][y].edge = 0; SpLev_Map[x][y] = 1; /* * Set secret doors to closed (why not trapped too?). Set * the horizontal bit. */ if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) { if (levl[x][y].typ == SDOOR) levl[x][y].doormask = D_CLOSED; /* * If there is a wall to the left that connects to a * (secret) door, then it is horizontal. This does * not allow (secret) doors to be corners of rooms. */ if (x != xstart && (IS_WALL(levl[x - 1][y].typ) || levl[x - 1][y].horizontal)) levl[x][y].horizontal = 1; } else if (levl[x][y].typ == HWALL || levl[x][y].typ == IRONBARS) levl[x][y].horizontal = 1; else if (levl[x][y].typ == LAVAPOOL) levl[x][y].lit = 1; else if (splev_init_present && levl[x][y].typ == ICE) levl[x][y].icedpool = icedpools ? ICED_POOL : ICED_MOAT; } if (coder->lvl_is_joined) remove_rooms(xstart, ystart, xstart + xsize, ystart + ysize); } if (!OV_i(mpkeepr)) { xstart = tmpxstart; ystart = tmpystart; xsize = tmpxsize; ysize = tmpysize; } opvar_free(mpxs); opvar_free(mpys); opvar_free(mpmap); opvar_free(mpa); opvar_free(mpkeepr); opvar_free(mpzalign); } void spo_jmp(coder, lvl) struct sp_coder *coder; sp_lev *lvl; { static const char nhFunc[] = "spo_jmp"; struct opvar *tmpa; long a; if (!OV_pop_i(tmpa)) return; a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(tmpa) - 1)); if ((a >= 0) && (a < lvl->n_opcodes) && (a != coder->frame->n_opcode)) coder->frame->n_opcode = a; opvar_free(tmpa); } void spo_conditional_jump(coder, lvl) struct sp_coder *coder; sp_lev *lvl; { static const char nhFunc[] = "spo_conditional_jump"; struct opvar *oa, *oc; long a, c; int test = 0; if (!OV_pop_i(oa) || !OV_pop_i(oc)) return; a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(oa) - 1)); c = OV_i(oc); switch (coder->opcode) { default: impossible("spo_conditional_jump: illegal opcode"); break; case SPO_JL: test = (c & SP_CPUFLAG_LT); break; case SPO_JLE: test = (c & (SP_CPUFLAG_LT | SP_CPUFLAG_EQ)); break; case SPO_JG: test = (c & SP_CPUFLAG_GT); break; case SPO_JGE: test = (c & (SP_CPUFLAG_GT | SP_CPUFLAG_EQ)); break; case SPO_JE: test = (c & SP_CPUFLAG_EQ); break; case SPO_JNE: test = (c & ~SP_CPUFLAG_EQ); break; } if ((test) && (a >= 0) && (a < lvl->n_opcodes) && (a != coder->frame->n_opcode)) coder->frame->n_opcode = a; opvar_free(oa); opvar_free(oc); } void spo_var_init(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_var_init"; struct opvar *vname; struct opvar *arraylen; struct opvar *vvalue; struct splev_var *tmpvar; struct splev_var *tmp2; long idx; OV_pop_s(vname); OV_pop_i(arraylen); if (!vname || !arraylen) panic("no values for SPO_VAR_INIT"); tmpvar = opvar_var_defined(coder, OV_s(vname)); if (tmpvar) { /* variable redefinition */ if (OV_i(arraylen) < 0) { /* copy variable */ if (tmpvar->array_len) { idx = tmpvar->array_len; while (idx-- > 0) { opvar_free(tmpvar->data.arrayvalues[idx]); } Free(tmpvar->data.arrayvalues); } else { opvar_free(tmpvar->data.value); } tmpvar->data.arrayvalues = NULL; goto copy_variable; } else if (OV_i(arraylen)) { /* redefined array */ idx = tmpvar->array_len; while (idx-- > 0) { opvar_free(tmpvar->data.arrayvalues[idx]); } Free(tmpvar->data.arrayvalues); tmpvar->data.arrayvalues = NULL; goto create_new_array; } else { /* redefined single value */ OV_pop(vvalue); if (tmpvar->svtyp != vvalue->spovartyp) panic("redefining variable as different type"); opvar_free(tmpvar->data.value); tmpvar->data.value = vvalue; tmpvar->array_len = 0; } } else { /* new variable definition */ tmpvar = (struct splev_var *) alloc(sizeof(struct splev_var)); tmpvar->next = coder->frame->variables; tmpvar->name = dupstr(OV_s(vname)); coder->frame->variables = tmpvar; if (OV_i(arraylen) < 0) { /* copy variable */ copy_variable: OV_pop(vvalue); tmp2 = opvar_var_defined(coder, OV_s(vvalue)); if (!tmp2) panic("no copyable var"); tmpvar->svtyp = tmp2->svtyp; tmpvar->array_len = tmp2->array_len; if (tmpvar->array_len) { idx = tmpvar->array_len; tmpvar->data.arrayvalues = (struct opvar **) alloc(sizeof(struct opvar *) * idx); while (idx-- > 0) { tmpvar->data.arrayvalues[idx] = opvar_clone(tmp2->data.arrayvalues[idx]); } } else { tmpvar->data.value = opvar_clone(tmp2->data.value); } opvar_free(vvalue); } else if (OV_i(arraylen)) { /* new array */ create_new_array: idx = OV_i(arraylen); tmpvar->array_len = idx; tmpvar->data.arrayvalues = (struct opvar **) alloc(sizeof(struct opvar *) * idx); while (idx-- > 0) { OV_pop(vvalue); if (!vvalue) panic("no value for arrayvariable"); tmpvar->data.arrayvalues[idx] = vvalue; } tmpvar->svtyp = SPOVAR_ARRAY; } else { /* new single value */ OV_pop(vvalue); if (!vvalue) panic("no value for variable"); tmpvar->svtyp = OV_typ(vvalue); tmpvar->data.value = vvalue; tmpvar->array_len = 0; } } opvar_free(vname); opvar_free(arraylen); } #if 0 STATIC_OVL long opvar_array_length(coder) struct sp_coder *coder; { static const char nhFunc[] = "opvar_array_length"; struct opvar *vname; struct splev_var *tmp; long len = 0; if (!coder) return 0; vname = splev_stack_pop(coder->stack); if (!vname) return 0; if (vname->spovartyp != SPOVAR_VARIABLE) goto pass; tmp = coder->frame->variables; while (tmp) { if (!strcmp(tmp->name, OV_s(vname))) { if ((tmp->svtyp & SPOVAR_ARRAY)) { len = tmp->array_len; if (len < 1) len = 0; } goto pass; } tmp = tmp->next; } pass: opvar_free(vname); return len; } #endif /*0*/ void spo_shuffle_array(coder) struct sp_coder *coder; { static const char nhFunc[] = "spo_shuffle_array"; struct opvar *vname; struct splev_var *tmp; struct opvar *tmp2; long i, j; if (!OV_pop_s(vname)) return; tmp = opvar_var_defined(coder, OV_s(vname)); if (!tmp || (tmp->array_len < 1)) { opvar_free(vname); return; } for (i = tmp->array_len - 1; i > 0; i--) { if ((j = rn2(i + 1)) == i) continue; tmp2 = tmp->data.arrayvalues[j]; tmp->data.arrayvalues[j] = tmp->data.arrayvalues[i]; tmp->data.arrayvalues[i] = tmp2; } opvar_free(vname); } /* Special level coder, creates the special level from the sp_lev codes. * Does not free the allocated memory. */ STATIC_OVL boolean sp_level_coder(lvl) sp_lev *lvl; { static const char nhFunc[] = "sp_level_coder"; unsigned long exec_opcodes = 0; int tmpi; long room_stack = 0; unsigned long max_execution = SPCODER_MAX_RUNTIME; struct sp_coder *coder = (struct sp_coder *) alloc(sizeof(struct sp_coder)); coder->frame = frame_new(0); coder->stack = NULL; coder->premapped = FALSE; coder->solidify = FALSE; coder->check_inaccessibles = FALSE; coder->croom = NULL; coder->n_subroom = 1; coder->exit_script = FALSE; coder->lvl_is_joined = 0; splev_init_present = FALSE; icedpools = FALSE; if (wizard) { char *met = nh_getenv("SPCODER_MAX_RUNTIME"); if (met && met[0] == '1') max_execution = (1 << 30) - 1; } for (tmpi = 0; tmpi <= MAX_NESTED_ROOMS; tmpi++) { coder->tmproomlist[tmpi] = (struct mkroom *) 0; coder->failed_room[tmpi] = FALSE; } shuffle_alignments(); for (tmpi = 0; tmpi < MAX_CONTAINMENT; tmpi++) container_obj[tmpi] = NULL; container_idx = 0; invent_carrying_monster = NULL; (void) memset((genericptr_t) &SpLev_Map[0][0], 0, sizeof SpLev_Map); level.flags.is_maze_lev = 0; xstart = 1; ystart = 0; xsize = COLNO - 1; ysize = ROWNO; while (coder->frame->n_opcode < lvl->n_opcodes && !coder->exit_script) { coder->opcode = lvl->opcodes[coder->frame->n_opcode].opcode; coder->opdat = lvl->opcodes[coder->frame->n_opcode].opdat; coder->stack = coder->frame->stack; if (exec_opcodes++ > max_execution) { impossible("Level script is taking too much time, stopping."); coder->exit_script = TRUE; } if (coder->failed_room[coder->n_subroom - 1] && coder->opcode != SPO_ENDROOM && coder->opcode != SPO_ROOM && coder->opcode != SPO_SUBROOM) goto next_opcode; coder->croom = coder->tmproomlist[coder->n_subroom - 1]; switch (coder->opcode) { case SPO_NULL: break; case SPO_EXIT: coder->exit_script = TRUE; break; case SPO_FRAME_PUSH: spo_frame_push(coder); break; case SPO_FRAME_POP: spo_frame_pop(coder); break; case SPO_CALL: spo_call(coder); break; case SPO_RETURN: spo_return(coder); break; case SPO_END_MONINVENT: spo_end_moninvent(coder); break; case SPO_POP_CONTAINER: spo_pop_container(coder); break; case SPO_POP: { struct opvar *ov = splev_stack_pop(coder->stack); opvar_free(ov); break; } case SPO_PUSH: splev_stack_push(coder->stack, opvar_clone(coder->opdat)); break; case SPO_MESSAGE: spo_message(coder); break; case SPO_MONSTER: spo_monster(coder); break; case SPO_OBJECT: spo_object(coder); break; case SPO_LEVEL_FLAGS: spo_level_flags(coder); break; case SPO_INITLEVEL: spo_initlevel(coder); break; case SPO_ENGRAVING: spo_engraving(coder); break; case SPO_MINERALIZE: spo_mineralize(coder); break; case SPO_SUBROOM: case SPO_ROOM: if (!coder->failed_room[coder->n_subroom - 1]) { spo_room(coder); } else room_stack++; break; case SPO_ENDROOM: if (coder->failed_room[coder->n_subroom - 1]) { if (!room_stack) spo_endroom(coder); else room_stack--; } else { spo_endroom(coder); } break; case SPO_DOOR: spo_door(coder); break; case SPO_STAIR: spo_stair(coder); break; case SPO_LADDER: spo_ladder(coder); break; case SPO_GRAVE: spo_grave(coder); break; case SPO_ALTAR: spo_altar(coder); break; case SPO_SINK: case SPO_POOL: case SPO_FOUNTAIN: spo_feature(coder); break; case SPO_TRAP: spo_trap(coder); break; case SPO_GOLD: spo_gold(coder); break; case SPO_CORRIDOR: spo_corridor(coder); break; case SPO_TERRAIN: spo_terrain(coder); break; case SPO_REPLACETERRAIN: spo_replace_terrain(coder); break; case SPO_LEVREGION: spo_levregion(coder); break; case SPO_REGION: spo_region(coder); break; case SPO_DRAWBRIDGE: spo_drawbridge(coder); break; case SPO_MAZEWALK: spo_mazewalk(coder); break; case SPO_NON_PASSWALL: case SPO_NON_DIGGABLE: spo_wall_property(coder); break; case SPO_ROOM_DOOR: spo_room_door(coder); break; case SPO_WALLIFY: spo_wallify(coder); break; case SPO_COPY: { struct opvar *a = splev_stack_pop(coder->stack); splev_stack_push(coder->stack, opvar_clone(a)); splev_stack_push(coder->stack, opvar_clone(a)); opvar_free(a); break; } case SPO_DEC: { struct opvar *a; if (!OV_pop_i(a)) break; OV_i(a)--; splev_stack_push(coder->stack, a); break; } case SPO_INC: { struct opvar *a; if (!OV_pop_i(a)) break; OV_i(a)++; splev_stack_push(coder->stack, a); break; } case SPO_MATH_SIGN: { struct opvar *a; if (!OV_pop_i(a)) break; OV_i(a) = ((OV_i(a) < 0) ? -1 : ((OV_i(a) > 0) ? 1 : 0)); splev_stack_push(coder->stack, a); break; } case SPO_MATH_ADD: { struct opvar *a, *b; if (!OV_pop(b) || !OV_pop(a)) break; if (OV_typ(b) == OV_typ(a)) { if (OV_typ(a) == SPOVAR_INT) { OV_i(a) = OV_i(a) + OV_i(b); splev_stack_push(coder->stack, a); opvar_free(b); } else if (OV_typ(a) == SPOVAR_STRING) { struct opvar *c; char *tmpbuf = (char *) alloc(strlen(OV_s(a)) + strlen(OV_s(b)) + 1); (void) sprintf(tmpbuf, "%s%s", OV_s(a), OV_s(b)); c = opvar_new_str(tmpbuf); splev_stack_push(coder->stack, c); opvar_free(a); opvar_free(b); Free(tmpbuf); } else { splev_stack_push(coder->stack, a); opvar_free(b); impossible("adding weird types"); } } else { splev_stack_push(coder->stack, a); opvar_free(b); impossible("adding different types"); } break; } case SPO_MATH_SUB: { struct opvar *a, *b; if (!OV_pop_i(b) || !OV_pop_i(a)) break; OV_i(a) = OV_i(a) - OV_i(b); splev_stack_push(coder->stack, a); opvar_free(b); break; } case SPO_MATH_MUL: { struct opvar *a, *b; if (!OV_pop_i(b) || !OV_pop_i(a)) break; OV_i(a) = OV_i(a) * OV_i(b); splev_stack_push(coder->stack, a); opvar_free(b); break; } case SPO_MATH_DIV: { struct opvar *a, *b; if (!OV_pop_i(b) || !OV_pop_i(a)) break; if (OV_i(b) >= 1) { OV_i(a) = OV_i(a) / OV_i(b); } else { OV_i(a) = 0; } splev_stack_push(coder->stack, a); opvar_free(b); break; } case SPO_MATH_MOD: { struct opvar *a, *b; if (!OV_pop_i(b) || !OV_pop_i(a)) break; if (OV_i(b) > 0) { OV_i(a) = OV_i(a) % OV_i(b); } else { OV_i(a) = 0; } splev_stack_push(coder->stack, a); opvar_free(b); break; } case SPO_CMP: { struct opvar *a; struct opvar *b; struct opvar *c; long val = 0; OV_pop(b); OV_pop(a); if (!a || !b) { impossible("spo_cmp: no values in stack"); break; } if (OV_typ(a) != OV_typ(b)) { impossible("spo_cmp: trying to compare differing datatypes"); break; } switch (OV_typ(a)) { case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: if (OV_i(b) > OV_i(a)) val |= SP_CPUFLAG_LT; if (OV_i(b) < OV_i(a)) val |= SP_CPUFLAG_GT; if (OV_i(b) == OV_i(a)) val |= SP_CPUFLAG_EQ; c = opvar_new_int(val); break; case SPOVAR_STRING: c = opvar_new_int(!strcmp(OV_s(b), OV_s(a)) ? SP_CPUFLAG_EQ : 0); break; default: c = opvar_new_int(0); break; } splev_stack_push(coder->stack, c); opvar_free(a); opvar_free(b); break; } case SPO_JMP: spo_jmp(coder, lvl); break; case SPO_JL: case SPO_JLE: case SPO_JG: case SPO_JGE: case SPO_JE: case SPO_JNE: spo_conditional_jump(coder, lvl); break; case SPO_RN2: { struct opvar *tmpv; struct opvar *t; if (!OV_pop_i(tmpv)) break; t = opvar_new_int((OV_i(tmpv) > 1) ? rn2(OV_i(tmpv)) : 0); splev_stack_push(coder->stack, t); opvar_free(tmpv); break; } case SPO_DICE: { struct opvar *a, *b, *t; if (!OV_pop_i(b) || !OV_pop_i(a)) break; if (OV_i(b) < 1) OV_i(b) = 1; if (OV_i(a) < 1) OV_i(a) = 1; t = opvar_new_int(d(OV_i(a), OV_i(b))); splev_stack_push(coder->stack, t); opvar_free(a); opvar_free(b); break; } case SPO_MAP: spo_map(coder); break; case SPO_VAR_INIT: spo_var_init(coder); break; case SPO_SHUFFLE_ARRAY: spo_shuffle_array(coder); break; case SPO_SEL_ADD: /* actually, logical or */ { struct opvar *sel1, *sel2, *pt; if (!OV_pop_typ(sel1, SPOVAR_SEL)) panic("no sel1 for add"); if (!OV_pop_typ(sel2, SPOVAR_SEL)) panic("no sel2 for add"); pt = selection_logical_oper(sel1, sel2, '|'); opvar_free(sel1); opvar_free(sel2); splev_stack_push(coder->stack, pt); break; } case SPO_SEL_COMPLEMENT: { struct opvar *sel, *pt; if (!OV_pop_typ(sel, SPOVAR_SEL)) panic("no sel for not"); pt = selection_not(sel); opvar_free(sel); splev_stack_push(coder->stack, pt); break; } case SPO_SEL_FILTER: /* sorta like logical and */ { struct opvar *filtertype; if (!OV_pop_i(filtertype)) panic("no sel filter type"); switch (OV_i(filtertype)) { case SPOFILTER_PERCENT: { struct opvar *tmp1, *sel; if (!OV_pop_i(tmp1)) panic("no sel filter percent"); if (!OV_pop_typ(sel, SPOVAR_SEL)) panic("no sel filter"); selection_filter_percent(sel, OV_i(tmp1)); splev_stack_push(coder->stack, sel); opvar_free(tmp1); break; } case SPOFILTER_SELECTION: /* logical and */ { struct opvar *pt, *sel1, *sel2; if (!OV_pop_typ(sel1, SPOVAR_SEL)) panic("no sel filter sel1"); if (!OV_pop_typ(sel2, SPOVAR_SEL)) panic("no sel filter sel2"); pt = selection_logical_oper(sel1, sel2, '&'); splev_stack_push(coder->stack, pt); opvar_free(sel1); opvar_free(sel2); break; } case SPOFILTER_MAPCHAR: { struct opvar *pt, *tmp1, *sel; if (!OV_pop_typ(sel, SPOVAR_SEL)) panic("no sel filter"); if (!OV_pop_typ(tmp1, SPOVAR_MAPCHAR)) panic("no sel filter mapchar"); pt = selection_filter_mapchar(sel, tmp1); splev_stack_push(coder->stack, pt); opvar_free(tmp1); opvar_free(sel); break; } default: panic("unknown sel filter type"); } opvar_free(filtertype); break; } case SPO_SEL_POINT: { struct opvar *tmp; struct opvar *pt = selection_opvar((char *) 0); schar x, y; if (!OV_pop_c(tmp)) panic("no ter sel coord"); get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp)); selection_setpoint(x, y, pt, 1); splev_stack_push(coder->stack, pt); opvar_free(tmp); break; } case SPO_SEL_RECT: case SPO_SEL_FILLRECT: { struct opvar *tmp, *pt = selection_opvar((char *) 0); schar x, y, x1, y1, x2, y2; if (!OV_pop_r(tmp)) panic("no ter sel region"); x1 = min(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp))); y1 = min(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp))); x2 = max(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp))); y2 = max(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp))); get_location(&x1, &y1, ANY_LOC, coder->croom); get_location(&x2, &y2, ANY_LOC, coder->croom); x1 = (x1 < 0) ? 0 : x1; y1 = (y1 < 0) ? 0 : y1; x2 = (x2 >= COLNO) ? COLNO - 1 : x2; y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2; if (coder->opcode == SPO_SEL_RECT) { for (x = x1; x <= x2; x++) { selection_setpoint(x, y1, pt, 1); selection_setpoint(x, y2, pt, 1); } for (y = y1; y <= y2; y++) { selection_setpoint(x1, y, pt, 1); selection_setpoint(x2, y, pt, 1); } } else { for (x = x1; x <= x2; x++) for (y = y1; y <= y2; y++) selection_setpoint(x, y, pt, 1); } splev_stack_push(coder->stack, pt); opvar_free(tmp); break; } case SPO_SEL_LINE: { struct opvar *tmp = NULL, *tmp2 = NULL, *pt = selection_opvar((char *) 0); schar x1, y1, x2, y2; if (!OV_pop_c(tmp)) panic("no ter sel linecoord1"); if (!OV_pop_c(tmp2)) panic("no ter sel linecoord2"); get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp)); get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2)); x1 = (x1 < 0) ? 0 : x1; y1 = (y1 < 0) ? 0 : y1; x2 = (x2 >= COLNO) ? COLNO - 1 : x2; y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2; selection_do_line(x1, y1, x2, y2, pt); splev_stack_push(coder->stack, pt); opvar_free(tmp); opvar_free(tmp2); break; } case SPO_SEL_RNDLINE: { struct opvar *tmp = NULL, *tmp2 = NULL, *tmp3, *pt = selection_opvar((char *) 0); schar x1, y1, x2, y2; if (!OV_pop_i(tmp3)) panic("no ter sel randline1"); if (!OV_pop_c(tmp)) panic("no ter sel randline2"); if (!OV_pop_c(tmp2)) panic("no ter sel randline3"); get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp)); get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2)); x1 = (x1 < 0) ? 0 : x1; y1 = (y1 < 0) ? 0 : y1; x2 = (x2 >= COLNO) ? COLNO - 1 : x2; y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2; selection_do_randline(x1, y1, x2, y2, OV_i(tmp3), 12, pt); splev_stack_push(coder->stack, pt); opvar_free(tmp); opvar_free(tmp2); opvar_free(tmp3); break; } case SPO_SEL_GROW: { struct opvar *dirs, *pt; if (!OV_pop_i(dirs)) panic("no dirs for grow"); if (!OV_pop_typ(pt, SPOVAR_SEL)) panic("no selection for grow"); selection_do_grow(pt, OV_i(dirs)); splev_stack_push(coder->stack, pt); opvar_free(dirs); break; } case SPO_SEL_FLOOD: { struct opvar *tmp; schar x, y; if (!OV_pop_c(tmp)) panic("no ter sel flood coord"); get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp)); if (isok(x, y)) { struct opvar *pt = selection_opvar((char *) 0); set_selection_floodfillchk(floodfillchk_match_under); floodfillchk_match_under_typ = levl[x][y].typ; selection_floodfill(pt, x, y, FALSE); splev_stack_push(coder->stack, pt); } opvar_free(tmp); break; } case SPO_SEL_RNDCOORD: { struct opvar *pt; schar x, y; if (!OV_pop_typ(pt, SPOVAR_SEL)) panic("no selection for rndcoord"); if (selection_rndcoord(pt, &x, &y, FALSE)) { x -= xstart; y -= ystart; } splev_stack_push(coder->stack, opvar_new_coord(x, y)); opvar_free(pt); break; } case SPO_SEL_ELLIPSE: { struct opvar *filled, *xaxis, *yaxis, *pt; struct opvar *sel = selection_opvar((char *) 0); schar x, y; if (!OV_pop_i(filled)) panic("no filled for ellipse"); if (!OV_pop_i(yaxis)) panic("no yaxis for ellipse"); if (!OV_pop_i(xaxis)) panic("no xaxis for ellipse"); if (!OV_pop_c(pt)) panic("no pt for ellipse"); get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(pt)); selection_do_ellipse(sel, x, y, OV_i(xaxis), OV_i(yaxis), OV_i(filled)); splev_stack_push(coder->stack, sel); opvar_free(filled); opvar_free(yaxis); opvar_free(xaxis); opvar_free(pt); break; } case SPO_SEL_GRADIENT: { struct opvar *gtyp, *glim, *mind, *maxd, *gcoord, *coord2; struct opvar *sel; schar x, y, x2, y2; if (!OV_pop_i(gtyp)) panic("no gtyp for grad"); if (!OV_pop_i(glim)) panic("no glim for grad"); if (!OV_pop_c(coord2)) panic("no coord2 for grad"); if (!OV_pop_c(gcoord)) panic("no coord for grad"); if (!OV_pop_i(maxd)) panic("no maxd for grad"); if (!OV_pop_i(mind)) panic("no mind for grad"); get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(gcoord)); get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(coord2)); sel = selection_opvar((char *) 0); selection_do_gradient(sel, x, y, x2, y2, OV_i(gtyp), OV_i(mind), OV_i(maxd), OV_i(glim)); splev_stack_push(coder->stack, sel); opvar_free(gtyp); opvar_free(glim); opvar_free(gcoord); opvar_free(coord2); opvar_free(maxd); opvar_free(mind); break; } default: panic("sp_level_coder: Unknown opcode %i", coder->opcode); } next_opcode: coder->frame->n_opcode++; } /*while*/ link_doors_rooms(); fill_rooms(); remove_boundary_syms(); if (coder->check_inaccessibles) ensure_way_out(); /* FIXME: Ideally, we want this call to only cover areas of the map * which were not inserted directly by the special level file (see * the insect legs on Baalzebub's level, for instance). Since that * is currently not possible, we overload the corrmaze flag for this * purpose. */ if (!level.flags.corrmaze) wallification(1, 0, COLNO - 1, ROWNO - 1); count_features(); if (coder->premapped) sokoban_detect(); if (coder->solidify) solidify_map(); if (coder->frame) { struct sp_frame *tmpframe; do { tmpframe = coder->frame->next; frame_del(coder->frame); coder->frame = tmpframe; } while (coder->frame); } Free(coder); return TRUE; } /* * General loader */ boolean load_special(name) const char *name; { dlb *fd; sp_lev *lvl = NULL; boolean result = FALSE; struct version_info vers_info; fd = dlb_fopen(name, RDBMODE); if (!fd) return FALSE; Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd); if (!check_version(&vers_info, name, TRUE)) { (void) dlb_fclose(fd); goto give_up; } lvl = (sp_lev *) alloc(sizeof(sp_lev)); result = sp_level_loader(fd, lvl); (void) dlb_fclose(fd); if (result) result = sp_level_coder(lvl); sp_level_free(lvl); Free(lvl); give_up: return result; } #ifdef _MSC_VER #pragma warning(pop) #endif /*sp_lev.c*/ nethack-3.6.0/src/spell.c0000664000076400007660000016622112622306536014224 0ustar paxedpaxed/* NetHack 3.6 spell.c $NHDT-Date: 1447653429 2015/11/16 05:57:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.72 $ */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* spellmenu arguments; 0 thru n-1 used as spl_book[] index when swapping */ #define SPELLMENU_CAST (-2) #define SPELLMENU_VIEW (-1) #define SPELLMENU_SORT (MAXSPELL) /* special menu entry */ /* spell retention period, in turns; at 10% of this value, player becomes eligible to reread the spellbook and regain 100% retention (the threshold used to be 1000 turns, which was 10% of the original 10000 turn retention period but didn't get adjusted when that period got doubled to 20000) */ #define KEEN 20000 /* x: need to add 1 when used for reading a spellbook rather than for hero initialization; spell memory is decremented at the end of each turn, including the turn on which the spellbook is read; without the extra increment, the hero used to get cheated out of 1 turn of retention */ #define incrnknow(spell, x) (spl_book[spell].sp_know = KEEN + (x)) #define spellev(spell) spl_book[spell].sp_lev #define spellname(spell) OBJ_NAME(objects[spellid(spell)]) #define spellet(spell) \ ((char) ((spell < 26) ? ('a' + spell) : ('A' + spell - 26))) STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P)); STATIC_DCL boolean FDECL(cursed_book, (struct obj * bp)); STATIC_DCL boolean FDECL(confused_book, (struct obj *)); STATIC_DCL void FDECL(deadbook, (struct obj *)); STATIC_PTR int NDECL(learn); STATIC_DCL boolean NDECL(rejectcasting); STATIC_DCL boolean FDECL(getspell, (int *)); STATIC_PTR int FDECL(CFDECLSPEC spell_cmp, (const genericptr, const genericptr)); STATIC_DCL void NDECL(sortspells); STATIC_DCL boolean NDECL(spellsortmenu); STATIC_DCL boolean FDECL(dospellmenu, (const char *, int, int *)); STATIC_DCL int FDECL(percent_success, (int)); STATIC_DCL char *FDECL(spellretention, (int, char *)); STATIC_DCL int NDECL(throwspell); STATIC_DCL void NDECL(cast_protection); STATIC_DCL void FDECL(spell_backfire, (int)); STATIC_DCL const char *FDECL(spelltypemnemonic, (int)); /* The roles[] table lists the role-specific values for tuning * percent_success(). * * Reasoning: * spelbase, spelheal: * Arc are aware of magic through historical research * Bar abhor magic (Conan finds it "interferes with his animal instincts") * Cav are ignorant to magic * Hea are very aware of healing magic through medical research * Kni are moderately aware of healing from Paladin training * Mon use magic to attack and defend in lieu of weapons and armor * Pri are very aware of healing magic through theological research * Ran avoid magic, preferring to fight unseen and unheard * Rog are moderately aware of magic through trickery * Sam have limited magical awareness, preferring meditation to conjuring * Tou are aware of magic from all the great films they have seen * Val have limited magical awareness, preferring fighting * Wiz are trained mages * * The arms penalty is lessened for trained fighters Bar, Kni, Ran, * Sam, Val -- the penalty is its metal interference, not encumbrance. * The `spelspec' is a single spell which is fundamentally easier * for that role to cast. * * spelspec, spelsbon: * Arc map masters (SPE_MAGIC_MAPPING) * Bar fugue/berserker (SPE_HASTE_SELF) * Cav born to dig (SPE_DIG) * Hea to heal (SPE_CURE_SICKNESS) * Kni to turn back evil (SPE_TURN_UNDEAD) * Mon to preserve their abilities (SPE_RESTORE_ABILITY) * Pri to bless (SPE_REMOVE_CURSE) * Ran to hide (SPE_INVISIBILITY) * Rog to find loot (SPE_DETECT_TREASURE) * Sam to be At One (SPE_CLAIRVOYANCE) * Tou to smile (SPE_CHARM_MONSTER) * Val control the cold (SPE_CONE_OF_COLD) * Wiz all really, but SPE_MAGIC_MISSILE is their party trick * * See percent_success() below for more comments. * * uarmbon, uarmsbon, uarmhbon, uarmgbon, uarmfbon: * Fighters find body armour & shield a little less limiting. * Headgear, Gauntlets and Footwear are not role-specific (but * still have an effect, except helm of brilliance, which is designed * to permit magic-use). */ #define uarmhbon 4 /* Metal helmets interfere with the mind */ #define uarmgbon 6 /* Casting channels through the hands */ #define uarmfbon 2 /* All metal interferes to some degree */ /* since the spellbook itself doesn't blow up, don't say just "explodes" */ static const char explodes[] = "radiates explosive energy"; /* convert a letter into a number in the range 0..51, or -1 if not a letter */ STATIC_OVL int spell_let_to_idx(ilet) char ilet; { int indx; indx = ilet - 'a'; if (indx >= 0 && indx < 26) return indx; indx = ilet - 'A'; if (indx >= 0 && indx < 26) return indx + 26; return -1; } /* TRUE: book should be destroyed by caller */ STATIC_OVL boolean cursed_book(bp) struct obj *bp; { int lev = objects[bp->otyp].oc_level; int dmg = 0; switch (rn2(lev)) { case 0: You_feel("a wrenching sensation."); tele(); /* teleport him */ break; case 1: You_feel("threatened."); aggravate(); break; case 2: make_blinded(Blinded + rn1(100, 250), TRUE); break; case 3: take_gold(); break; case 4: pline("These runes were just too much to comprehend."); make_confused(HConfusion + rn1(7, 16), FALSE); break; case 5: pline_The("book was coated with contact poison!"); if (uarmg) { erode_obj(uarmg, "gloves", ERODE_CORRODE, EF_GREASE | EF_VERBOSE); break; } /* temp disable in_use; death should not destroy the book */ bp->in_use = FALSE; losestr(Poison_resistance ? rn1(2, 1) : rn1(4, 3)); losehp(rnd(Poison_resistance ? 6 : 10), "contact-poisoned spellbook", KILLED_BY_AN); bp->in_use = TRUE; break; case 6: if (Antimagic) { shieldeff(u.ux, u.uy); pline_The("book %s, but you are unharmed!", explodes); } else { pline("As you read the book, it %s in your %s!", explodes, body_part(FACE)); dmg = 2 * rnd(10) + 5; losehp(Maybe_Half_Phys(dmg), "exploding rune", KILLED_BY_AN); } return TRUE; default: rndcurse(); break; } return FALSE; } /* study while confused: returns TRUE if the book is destroyed */ STATIC_OVL boolean confused_book(spellbook) struct obj *spellbook; { boolean gone = FALSE; if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { spellbook->in_use = TRUE; /* in case called from learn */ pline( "Being confused you have difficulties in controlling your actions."); display_nhwindow(WIN_MESSAGE, FALSE); You("accidentally tear the spellbook to pieces."); if (!objects[spellbook->otyp].oc_name_known && !objects[spellbook->otyp].oc_uname) docall(spellbook); useup(spellbook); gone = TRUE; } else { You("find yourself reading the %s line over and over again.", spellbook == context.spbook.book ? "next" : "first"); } return gone; } /* special effects for The Book of the Dead */ STATIC_OVL void deadbook(book2) struct obj *book2; { struct monst *mtmp, *mtmp2; coord mm; You("turn the pages of the Book of the Dead..."); makeknown(SPE_BOOK_OF_THE_DEAD); /* KMH -- Need ->known to avoid "_a_ Book of the Dead" */ book2->known = 1; if (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { register struct obj *otmp; register boolean arti1_primed = FALSE, arti2_primed = FALSE, arti_cursed = FALSE; if (book2->cursed) { pline_The("runes appear scrambled. You can't read them!"); return; } if (!u.uhave.bell || !u.uhave.menorah) { pline("A chill runs down your %s.", body_part(SPINE)); if (!u.uhave.bell) You_hear("a faint chime..."); if (!u.uhave.menorah) pline("Vlad's doppelganger is amused."); return; } for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->otyp == CANDELABRUM_OF_INVOCATION && otmp->spe == 7 && otmp->lamplit) { if (!otmp->cursed) arti1_primed = TRUE; else arti_cursed = TRUE; } if (otmp->otyp == BELL_OF_OPENING && (moves - otmp->age) < 5L) { /* you rang it recently */ if (!otmp->cursed) arti2_primed = TRUE; else arti_cursed = TRUE; } } if (arti_cursed) { pline_The("invocation fails!"); pline("At least one of your artifacts is cursed..."); } else if (arti1_primed && arti2_primed) { unsigned soon = (unsigned) d(2, 6); /* time til next intervene() */ /* successful invocation */ mkinvokearea(); u.uevent.invoked = 1; /* in case you haven't killed the Wizard yet, behave as if you just did */ u.uevent.udemigod = 1; /* wizdead() */ if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon; } else { /* at least one artifact not prepared properly */ You("have a feeling that %s is amiss...", something); goto raise_dead; } return; } /* when not an invocation situation */ if (book2->cursed) { raise_dead: You("raised the dead!"); /* first maybe place a dangerous adversary */ if (!rn2(3) && ((mtmp = makemon(&mons[PM_MASTER_LICH], u.ux, u.uy, NO_MINVENT)) != 0 || (mtmp = makemon(&mons[PM_NALFESHNEE], u.ux, u.uy, NO_MINVENT)) != 0)) { mtmp->mpeaceful = 0; set_malign(mtmp); } /* next handle the affect on things you're carrying */ (void) unturn_dead(&youmonst); /* last place some monsters around you */ mm.x = u.ux; mm.y = u.uy; mkundead(&mm, TRUE, NO_MINVENT); } else if (book2->blessed) { for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; /* tamedog() changes chain */ if (DEADMONSTER(mtmp)) continue; if ((is_undead(mtmp->data) || is_vampshifter(mtmp)) && cansee(mtmp->mx, mtmp->my)) { mtmp->mpeaceful = TRUE; if (sgn(mtmp->data->maligntyp) == sgn(u.ualign.type) && distu(mtmp->mx, mtmp->my) < 4) if (mtmp->mtame) { if (mtmp->mtame < 20) mtmp->mtame++; } else (void) tamedog(mtmp, (struct obj *) 0); else monflee(mtmp, 0, FALSE, TRUE); } } } else { switch (rn2(3)) { case 0: Your("ancestors are annoyed with you!"); break; case 1: pline_The("headstones in the cemetery begin to move!"); break; default: pline("Oh my! Your name appears in the book!"); } } return; } STATIC_PTR int learn(VOID_ARGS) { int i; short booktype; char splname[BUFSZ]; boolean costly = TRUE; struct obj *book = context.spbook.book; /* JDS: lenses give 50% faster reading; 33% smaller read time */ if (context.spbook.delay && ublindf && ublindf->otyp == LENSES && rn2(2)) context.spbook.delay++; if (Confusion) { /* became confused while learning */ (void) confused_book(book); context.spbook.book = 0; /* no longer studying */ context.spbook.o_id = 0; nomul(context.spbook.delay); /* remaining delay is uninterrupted */ multi_reason = "reading a book"; nomovemsg = 0; context.spbook.delay = 0; return 0; } if (context .spbook.delay) { /* not if (context.spbook.delay++), so at end delay == 0 */ context.spbook.delay++; return 1; /* still busy */ } exercise(A_WIS, TRUE); /* you're studying. */ booktype = book->otyp; if (booktype == SPE_BOOK_OF_THE_DEAD) { deadbook(book); return 0; } Sprintf(splname, objects[booktype].oc_name_known ? "\"%s\"" : "the \"%s\" spell", OBJ_NAME(objects[booktype])); for (i = 0; i < MAXSPELL; i++) if (spellid(i) == booktype || spellid(i) == NO_SPELL) break; if (i == MAXSPELL) { impossible("Too many spells memorized!"); } else if (spellid(i) == booktype) { /* normal book can be read and re-read a total of 4 times */ if (book->spestudied > MAX_SPELL_STUDY) { pline("This spellbook is too faint to be read any more."); book->otyp = booktype = SPE_BLANK_PAPER; /* reset spestudied as if polymorph had taken place */ book->spestudied = rn2(book->spestudied); } else if (spellknow(i) > KEEN / 10) { You("know %s quite well already.", splname); costly = FALSE; } else { /* spellknow(i) <= KEEN/10 */ Your("knowledge of %s is %s.", splname, spellknow(i) ? "keener" : "restored"); incrnknow(i, 1); book->spestudied++; exercise(A_WIS, TRUE); /* extra study */ } /* make book become known even when spell is already known, in case amnesia made you forget the book */ makeknown((int) booktype); } else { /* (spellid(i) == NO_SPELL) */ /* for a normal book, spestudied will be zero, but for a polymorphed one, spestudied will be non-zero and one less reading is available than when re-learning */ if (book->spestudied >= MAX_SPELL_STUDY) { /* pre-used due to being the product of polymorph */ pline("This spellbook is too faint to read even once."); book->otyp = booktype = SPE_BLANK_PAPER; /* reset spestudied as if polymorph had taken place */ book->spestudied = rn2(book->spestudied); } else { spl_book[i].sp_id = booktype; spl_book[i].sp_lev = objects[booktype].oc_level; incrnknow(i, 1); book->spestudied++; You(i > 0 ? "add %s to your repertoire." : "learn %s.", splname); } makeknown((int) booktype); } if (book->cursed) { /* maybe a demon cursed it */ if (cursed_book(book)) { useup(book); context.spbook.book = 0; context.spbook.o_id = 0; return 0; } } if (costly) check_unpaid(book); context.spbook.book = 0; context.spbook.o_id = 0; return 0; } int study_book(spellbook) register struct obj *spellbook; { int booktype = spellbook->otyp; boolean confused = (Confusion != 0); boolean too_hard = FALSE; /* attempting to read dull book may make hero fall asleep */ if (!confused && booktype != SPE_BLANK_PAPER && !strcmp(OBJ_DESCR(objects[booktype]), "dull")) { const char *eyes; int dullbook = rnd(25) - ACURR(A_WIS); /* adjust chance if hero stayed awake, got interrupted, retries */ if (context.spbook.delay && spellbook == context.spbook.book) dullbook -= rnd(objects[booktype].oc_level); if (dullbook > 0) { eyes = body_part(EYE); if (eyecount(youmonst.data) > 1) eyes = makeplural(eyes); pline("This book is so dull that you can't keep your %s open.", eyes); dullbook += rnd(2 * objects[booktype].oc_level); fall_asleep(-dullbook, TRUE); return 1; } } if (context.spbook.delay && !confused && spellbook == context.spbook.book /* handle the sequence: start reading, get interrupted, have context.spbook.book become erased somehow, resume reading it */ && booktype != SPE_BLANK_PAPER) { You("continue your efforts to %s.", (booktype == SPE_NOVEL) ? "read the novel" : "memorize the spell"); } else { /* KMH -- Simplified this code */ if (booktype == SPE_BLANK_PAPER) { pline("This spellbook is all blank."); makeknown(booktype); return 1; } /* 3.6.0 tribute */ if (booktype == SPE_NOVEL) { /* Obtain current Terry Pratchett book title */ const char *tribtitle = noveltitle(&spellbook->novelidx); if (read_tribute("books", tribtitle, 0, (char *) 0, 0, spellbook->o_id)) { u.uconduct.literate++; check_unpaid(spellbook); if (!u.uevent.read_tribute) { /* give bonus of 20 xp and 4*20+0 pts */ more_experienced(20, 0); newexplevel(); u.uevent.read_tribute = 1; /* only once */ } } return 1; } switch (objects[booktype].oc_level) { case 1: case 2: context.spbook.delay = -objects[booktype].oc_delay; break; case 3: case 4: context.spbook.delay = -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay; break; case 5: case 6: context.spbook.delay = -objects[booktype].oc_level * objects[booktype].oc_delay; break; case 7: context.spbook.delay = -8 * objects[booktype].oc_delay; break; default: impossible("Unknown spellbook level %d, book %d;", objects[booktype].oc_level, booktype); return 0; } /* Books are often wiser than their readers (Rus.) */ spellbook->in_use = TRUE; if (!spellbook->blessed && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { if (spellbook->cursed) { too_hard = TRUE; } else { /* uncursed - chance to fail */ int read_ability = ACURR(A_INT) + 4 + u.ulevel / 2 - 2 * objects[booktype].oc_level + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0); /* only wizards know if a spell is too difficult */ if (Role_if(PM_WIZARD) && read_ability < 20 && !confused) { char qbuf[QBUFSZ]; Sprintf(qbuf, "This spellbook is %sdifficult to comprehend. Continue?", (read_ability < 12 ? "very " : "")); if (yn(qbuf) != 'y') { spellbook->in_use = FALSE; return 1; } } /* its up to random luck now */ if (rnd(20) > read_ability) { too_hard = TRUE; } } } if (too_hard) { boolean gone = cursed_book(spellbook); nomul(context.spbook.delay); /* study time */ multi_reason = "reading a book"; nomovemsg = 0; context.spbook.delay = 0; if (gone || !rn2(3)) { if (!gone) pline_The("spellbook crumbles to dust!"); if (!objects[spellbook->otyp].oc_name_known && !objects[spellbook->otyp].oc_uname) docall(spellbook); useup(spellbook); } else spellbook->in_use = FALSE; return 1; } else if (confused) { if (!confused_book(spellbook)) { spellbook->in_use = FALSE; } nomul(context.spbook.delay); multi_reason = "reading a book"; nomovemsg = 0; context.spbook.delay = 0; return 1; } spellbook->in_use = FALSE; You("begin to %s the runes.", spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : "memorize"); } context.spbook.book = spellbook; if (context.spbook.book) context.spbook.o_id = context.spbook.book->o_id; set_occupation(learn, "studying", 0); return 1; } /* a spellbook has been destroyed or the character has changed levels; the stored address for the current book is no longer valid */ void book_disappears(obj) struct obj *obj; { if (obj == context.spbook.book) { context.spbook.book = (struct obj *) 0; context.spbook.o_id = 0; } } /* renaming an object usually results in it having a different address; so the sequence start reading, get interrupted, name the book, resume reading would read the "new" book from scratch */ void book_substitution(old_obj, new_obj) struct obj *old_obj, *new_obj; { if (old_obj == context.spbook.book) { context.spbook.book = new_obj; if (context.spbook.book) context.spbook.o_id = context.spbook.book->o_id; } } /* called from moveloop() */ void age_spells() { int i; /* * The time relative to the hero (a pass through move * loop) causes all spell knowledge to be decremented. * The hero's speed, rest status, conscious status etc. * does not alter the loss of memory. */ for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) if (spellknow(i)) decrnknow(i); return; } /* return True if spellcasting is inhibited; only covers a small subset of reasons why casting won't work */ STATIC_OVL boolean rejectcasting() { /* rejections which take place before selecting a particular spell */ if (Stunned) { You("are too impaired to cast a spell."); return TRUE; } else if (!freehand()) { /* Note: !freehand() occurs when weapon and shield (or two-handed * weapon) are welded to hands, so "arms" probably doesn't need * to be makeplural(bodypart(ARM)). * * But why isn't lack of free arms (for gesturing) an issue when * poly'd hero has no limbs? */ Your("arms are not free to cast!"); return TRUE; } return FALSE; } /* * Return TRUE if a spell was picked, with the spell index in the return * parameter. Otherwise return FALSE. */ STATIC_OVL boolean getspell(spell_no) int *spell_no; { int nspells, idx; char ilet, lets[BUFSZ], qbuf[QBUFSZ]; if (spellid(0) == NO_SPELL) { You("don't know any spells right now."); return FALSE; } if (rejectcasting()) return FALSE; /* no spell chosen */ if (flags.menu_style == MENU_TRADITIONAL) { /* we know there is at least 1 known spell */ for (nspells = 1; nspells < MAXSPELL && spellid(nspells) != NO_SPELL; nspells++) continue; if (nspells == 1) Strcpy(lets, "a"); else if (nspells < 27) Sprintf(lets, "a-%c", 'a' + nspells - 1); else if (nspells == 27) Sprintf(lets, "a-zA"); /* this assumes that there are at most 52 spells... */ else Sprintf(lets, "a-zA-%c", 'A' + nspells - 27); for (;;) { Sprintf(qbuf, "Cast which spell? [%s *?]", lets); ilet = yn_function(qbuf, (char *) 0, '\0'); if (ilet == '*' || ilet == '?') break; /* use menu mode */ if (index(quitchars, ilet)) return FALSE; idx = spell_let_to_idx(ilet); if (idx < 0 || idx >= nspells) { You("don't know that spell."); continue; /* ask again */ } *spell_no = idx; return TRUE; } } return dospellmenu("Choose which spell to cast", SPELLMENU_CAST, spell_no); } /* the 'Z' command -- cast a spell */ int docast() { int spell_no; if (getspell(&spell_no)) return spelleffects(spell_no, FALSE); return 0; } STATIC_OVL const char * spelltypemnemonic(skill) int skill; { switch (skill) { case P_ATTACK_SPELL: return "attack"; case P_HEALING_SPELL: return "healing"; case P_DIVINATION_SPELL: return "divination"; case P_ENCHANTMENT_SPELL: return "enchantment"; case P_CLERIC_SPELL: return "clerical"; case P_ESCAPE_SPELL: return "escape"; case P_MATTER_SPELL: return "matter"; default: impossible("Unknown spell skill, %d;", skill); return ""; } } int spell_skilltype(booktype) int booktype; { return objects[booktype].oc_skill; } STATIC_OVL void cast_protection() { int l = u.ulevel, loglev = 0, gain, natac = u.uac + u.uspellprot; /* note: u.uspellprot is subtracted when find_ac() factors it into u.uac, so adding here factors it back out (versions prior to 3.6 had this backwards) */ /* loglev=log2(u.ulevel)+1 (1..5) */ while (l) { loglev++; l /= 2; } /* The more u.uspellprot you already have, the less you get, * and the better your natural ac, the less you get. * * LEVEL AC SPELLPROT from successive SPE_PROTECTION casts * 1 10 0, 1, 2, 3, 4 * 1 0 0, 1, 2, 3 * 1 -10 0, 1, 2 * 2-3 10 0, 2, 4, 5, 6, 7, 8 * 2-3 0 0, 2, 4, 5, 6 * 2-3 -10 0, 2, 3, 4 * 4-7 10 0, 3, 6, 8, 9, 10, 11, 12 * 4-7 0 0, 3, 5, 7, 8, 9 * 4-7 -10 0, 3, 5, 6 * 7-15 -10 0, 3, 5, 6 * 8-15 10 0, 4, 7, 10, 12, 13, 14, 15, 16 * 8-15 0 0, 4, 7, 9, 10, 11, 12 * 8-15 -10 0, 4, 6, 7, 8 * 16-30 10 0, 5, 9, 12, 14, 16, 17, 18, 19, 20 * 16-30 0 0, 5, 9, 11, 13, 14, 15 * 16-30 -10 0, 5, 8, 9, 10 */ natac = (10 - natac) / 10; /* convert to positive and scale down */ gain = loglev - (int) u.uspellprot / (4 - min(3, natac)); if (gain > 0) { if (!Blind) { int rmtyp; const char *hgolden = hcolor(NH_GOLDEN), *atmosphere; if (u.uspellprot) { pline_The("%s haze around you becomes more dense.", hgolden); } else { rmtyp = levl[u.ux][u.uy].typ; atmosphere = u.uswallow ? ((u.ustuck->data == &mons[PM_FOG_CLOUD]) ? "mist" : is_whirly(u.ustuck->data) ? "maelstrom" : is_animal(u.ustuck->data) ? "maw" : "ooze") : (u.uinwater ? "water" : (rmtyp == CLOUD) ? "cloud" : IS_TREE(rmtyp) ? "vegitation" : IS_STWALL(rmtyp) ? "stone" : "air"); pline_The("%s around you begins to shimmer with %s haze.", atmosphere, an(hgolden)); } } u.uspellprot += gain; u.uspmtime = (P_SKILL(spell_skilltype(SPE_PROTECTION)) == P_EXPERT) ? 20 : 10; if (!u.usptime) u.usptime = u.uspmtime; find_ac(); } else { Your("skin feels warm for a moment."); } } /* attempting to cast a forgotten spell will cause disorientation */ STATIC_OVL void spell_backfire(spell) int spell; { long duration = (long) ((spellev(spell) + 1) * 3), /* 6..24 */ old_stun = (HStun & TIMEOUT), old_conf = (HConfusion & TIMEOUT); /* Prior to 3.4.1, only effect was confusion; it still predominates. * * 3.6.0: this used to override pre-existing confusion duration * (cases 0..8) and pre-existing stun duration (cases 4..9); * increase them instead. (Hero can no longer cast spells while * Stunned, so the potential increment to stun duration here is * just hypothetical.) */ switch (rn2(10)) { case 0: case 1: case 2: case 3: make_confused(old_conf + duration, FALSE); /* 40% */ break; case 4: case 5: case 6: make_confused(old_conf + 2L * duration / 3L, FALSE); /* 30% */ make_stunned(old_stun + duration / 3L, FALSE); break; case 7: case 8: make_stunned(old_conf + 2L * duration / 3L, FALSE); /* 20% */ make_confused(old_stun + duration / 3L, FALSE); break; case 9: make_stunned(old_stun + duration, FALSE); /* 10% */ break; } return; } int spelleffects(spell, atme) int spell; boolean atme; { int energy, damage, chance, n, intell; int skill, role_skill; boolean confused = (Confusion != 0); boolean physical_damage = FALSE; struct obj *pseudo; coord cc; /* * Reject attempting to cast while stunned or with no free hands. * Already done in getspell() to stop casting before choosing * which spell, but duplicated here for cases where spelleffects() * gets called directly for ^T without intrinsic teleport capability * or #turn for non-priest/non-knight. * (There's no duplication of messages; when the rejection takes * place in getspell(), we don't get called.) */ if (rejectcasting()) { return 0; /* no time elapses */ } /* * Spell casting no longer affects knowledge of the spell. A * decrement of spell knowledge is done every turn. */ if (spellknow(spell) <= 0) { Your("knowledge of this spell is twisted."); pline("It invokes nightmarish images in your mind..."); spell_backfire(spell); return 1; } else if (spellknow(spell) <= KEEN / 200) { /* 100 turns left */ You("strain to recall the spell."); } else if (spellknow(spell) <= KEEN / 40) { /* 500 turns left */ You("have difficulty remembering the spell."); } else if (spellknow(spell) <= KEEN / 20) { /* 1000 turns left */ Your("knowledge of this spell is growing faint."); } else if (spellknow(spell) <= KEEN / 10) { /* 2000 turns left */ Your("recall of this spell is gradually fading."); } energy = (spellev(spell) * 5); /* 5 <= energy <= 35 */ if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { You("are too hungry to cast that spell."); return 0; } else if (ACURR(A_STR) < 4 && spellid(spell) != SPE_RESTORE_ABILITY) { You("lack the strength to cast spells."); return 0; } else if (check_capacity( "Your concentration falters while carrying so much stuff.")) { return 1; } if (u.uhave.amulet) { You_feel("the amulet draining your energy away."); energy += rnd(2 * energy); } if (energy > u.uen) { You("don't have enough energy to cast that spell."); return 0; } else { if (spellid(spell) != SPE_DETECT_FOOD) { int hungr = energy * 2; /* If hero is a wizard, their current intelligence * (bonuses + temporary + current) * affects hunger reduction in casting a spell. * 1. int = 17-18 no reduction * 2. int = 16 1/4 hungr * 3. int = 15 1/2 hungr * 4. int = 1-14 normal reduction * The reason for this is: * a) Intelligence affects the amount of exertion * in thinking. * b) Wizards have spent their life at magic and * understand quite well how to cast spells. */ intell = acurr(A_INT); if (!Role_if(PM_WIZARD)) intell = 10; switch (intell) { case 25: case 24: case 23: case 22: case 21: case 20: case 19: case 18: case 17: hungr = 0; break; case 16: hungr /= 4; break; case 15: hungr /= 2; break; } /* don't put player (quite) into fainting from * casting a spell, particularly since they might * not even be hungry at the beginning; however, * this is low enough that they must eat before * casting anything else except detect food */ if (hungr > u.uhunger - 3) hungr = u.uhunger - 3; morehungry(hungr); } } chance = percent_success(spell); if (confused || (rnd(100) > chance)) { You("fail to cast the spell correctly."); u.uen -= energy / 2; context.botl = 1; return 1; } u.uen -= energy; context.botl = 1; exercise(A_WIS, TRUE); /* pseudo is a temporary "false" object containing the spell stats */ pseudo = mksobj(spellid(spell), FALSE, FALSE); pseudo->blessed = pseudo->cursed = 0; pseudo->quan = 20L; /* do not let useup get it */ /* * Find the skill the hero has in a spell type category. * See spell_skilltype for categories. */ skill = spell_skilltype(pseudo->otyp); role_skill = P_SKILL(skill); switch (pseudo->otyp) { /* * At first spells act as expected. As the hero increases in skill * with the appropriate spell type, some spells increase in their * effects, e.g. more damage, further distance, and so on, without * additional cost to the spellcaster. */ case SPE_FIREBALL: case SPE_CONE_OF_COLD: if (role_skill >= P_SKILLED) { if (throwspell()) { cc.x = u.dx; cc.y = u.dy; n = rnd(8) + 1; while (n--) { if (!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "zapped %sself with a spell", uhim()); losehp(damage, buf, NO_KILLER_PREFIX); } } else { explode(u.dx, u.dy, pseudo->otyp - SPE_MAGIC_MISSILE + 10, spell_damage_bonus(u.ulevel / 2 + 1), 0, (pseudo->otyp == SPE_CONE_OF_COLD) ? EXPL_FROSTY : EXPL_FIERY); } u.dx = cc.x + rnd(3) - 2; u.dy = cc.y + rnd(3) - 2; if (!isok(u.dx, u.dy) || !cansee(u.dx, u.dy) || IS_STWALL(levl[u.dx][u.dy].typ) || u.uswallow) { /* Spell is reflected back to center */ u.dx = cc.x; u.dy = cc.y; } } } break; } /* else fall through... */ /* these spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: physical_damage = TRUE; /* fall through */ case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_LIGHT: case SPE_DETECT_UNSEEN: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: if (!(objects[pseudo->otyp].oc_dir == NODIR)) { if (atme) { u.dx = u.dy = u.dz = 0; } else if (!getdir((char *) 0)) { /* getdir cancelled, re-use previous direction */ /* * FIXME: reusing previous direction only makes sense * if there is an actual previous direction. When there * isn't one, the spell gets cast at self which is rarely * what the player intended. Unfortunately, the way * spelleffects() is organized means that aborting with * "nevermind" is not an option. */ pline_The("magical energy is released!"); } if (!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "zapped %sself with a spell", uhim()); if (physical_damage) damage = Maybe_Half_Phys(damage); losehp(damage, buf, NO_KILLER_PREFIX); } } else weffects(pseudo); } else weffects(pseudo); update_inventory(); /* spell may modify inventory */ break; /* these are all duplicates of scroll effects */ case SPE_REMOVE_CURSE: case SPE_CONFUSE_MONSTER: case SPE_DETECT_FOOD: case SPE_CAUSE_FEAR: case SPE_IDENTIFY: /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: (void) seffects(pseudo); break; /* these are all duplicates of potion effects */ case SPE_HASTE_SELF: case SPE_DETECT_TREASURE: case SPE_DETECT_MONSTERS: case SPE_LEVITATION: case SPE_RESTORE_ABILITY: /* high skill yields effect equivalent to blessed potion */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_INVISIBILITY: (void) peffects(pseudo); break; case SPE_CURE_BLINDNESS: healup(0, 0, FALSE, TRUE); break; case SPE_CURE_SICKNESS: if (Sick) You("are no longer ill."); if (Slimed) make_slimed(0L, "The slime disappears!"); healup(0, 0, TRUE, FALSE); break; case SPE_CREATE_FAMILIAR: (void) make_familiar((struct obj *) 0, u.ux, u.uy, FALSE); break; case SPE_CLAIRVOYANCE: if (!BClairvoyant) do_vicinity_map(); /* at present, only one thing blocks clairvoyance */ else if (uarmh && uarmh->otyp == CORNUTHAUM) You("sense a pointy hat on top of your %s.", body_part(HEAD)); break; case SPE_PROTECTION: cast_protection(); break; case SPE_JUMPING: if (!jump(max(role_skill, 1))) pline1(nothing_happens); break; default: impossible("Unknown spell %d attempted.", spell); obfree(pseudo, (struct obj *) 0); return 0; } /* gain skill for successful cast */ use_skill(skill, spellev(spell)); obfree(pseudo, (struct obj *) 0); /* now, get rid of it */ return 1; } /* Choose location where spell takes effect. */ STATIC_OVL int throwspell() { coord cc; struct monst *mtmp; if (u.uinwater) { pline("You're joking! In this weather?"); return 0; } else if (Is_waterlevel(&u.uz)) { You("had better wait for the sun to come out."); return 0; } pline("Where do you want to cast the spell?"); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the desired position") < 0) return 0; /* user pressed ESC */ /* The number of moves from hero to where the spell drops.*/ if (distmin(u.ux, u.uy, cc.x, cc.y) > 10) { pline_The("spell dissipates over the distance!"); return 0; } else if (u.uswallow) { pline_The("spell is cut short!"); exercise(A_WIS, FALSE); /* What were you THINKING! */ u.dx = 0; u.dy = 0; return 1; } else if ((!cansee(cc.x, cc.y) && (!(mtmp = m_at(cc.x, cc.y)) || !canspotmon(mtmp))) || IS_STWALL(levl[cc.x][cc.y].typ)) { Your("mind fails to lock onto that location!"); return 0; } u.dx = cc.x; u.dy = cc.y; return 1; } /* forget a random selection of known spells due to amnesia; they used to be lost entirely, as if never learned, but now we just set the memory retention to zero so that they can't be cast */ void losespells() { int n, nzap, i; /* in case reading has been interrupted earlier, discard context */ context.spbook.book = 0; context.spbook.o_id = 0; /* count the number of known spells */ for (n = 0; n < MAXSPELL; ++n) if (spellid(n) == NO_SPELL) break; /* lose anywhere from zero to all known spells; if confused, use the worse of two die rolls */ nzap = rn2(n + 1); if (Confusion) { i = rn2(n + 1); if (i > nzap) nzap = i; } /* good Luck might ameliorate spell loss */ if (nzap > 1 && !rnl(7)) nzap = rnd(nzap); /* * Forget 'nzap' out of 'n' known spells by setting their memory * retention to zero. Every spell has the same probability to be * forgotten, even if its retention is already zero. * * Perhaps we should forget the corresponding book too? * * (3.4.3 removed spells entirely from the list, but always did * so from its end, so the 'nzap' most recently learned spells * were the ones lost by default. Player had sort control over * the list, so could move the most useful spells to front and * only lose them if 'nzap' turned out to be a large value. * * Discarding from the end of the list had the virtue of making * casting letters for lost spells become invalid and retaining * the original letter for the ones which weren't lost, so there * was no risk to the player of accidentally casting the wrong * spell when using a letter that was in use prior to amnesia. * That wouldn't be the case if we implemented spell loss spread * throughout the list of known spells; every spell located past * the first lost spell would end up with new letter assigned.) */ for (i = 0; nzap > 0; ++i) { /* when nzap is small relative to the number of spells left, the chance to lose spell [i] is small; as the number of remaining candidates shrinks, the chance per candidate gets bigger; overall, exactly nzap entries are affected */ if (rn2(n - i) < nzap) { /* lose access to spell [i] */ spellknow(i) = 0; #if 0 /* also forget its book */ forget_single_object(spellid(i)); #endif /* and abuse wisdom */ exercise(A_WIS, FALSE); /* there's now one less spell slated to be forgotten */ --nzap; } } } /* * Allow player to sort the list of known spells. Manually swapping * pairs of them becomes very tedious once the list reaches two pages. * * Possible extensions: * provide means for player to control ordering of skill classes; * provide means to supply value N such that first N entries stick * while rest of list is being sorted; * make chosen sort order be persistent such that when new spells * are learned, they get inserted into sorted order rather than be * appended to the end of the list? */ static const char *spl_sortchoices[] = { "by casting letter", #define SORTBY_LETTER 0 "alphabetically", #define SORTBY_ALPHA 1 "by level, low to high", #define SORTBY_LVL_LO 2 "by level, high to low", #define SORTBY_LVL_HI 3 "by skill group, alphabetized within each group", #define SORTBY_SKL_AL 4 "by skill group, low to high level within group", #define SORTBY_SKL_LO 5 "by skill group, high to low level within group", #define SORTBY_SKL_HI 6 "maintain current ordering", #define SORTBY_CURRENT 7 /* a menu choice rather than a sort choice */ "reassign casting letters to retain current order", #define SORTRETAINORDER 8 }; static int spl_sortmode = 0; /* index into spl_sortchoices[] */ static int *spl_orderindx = 0; /* array of spl_book[] indices */ /* qsort callback routine */ STATIC_PTR int CFDECLSPEC spell_cmp(vptr1, vptr2) const genericptr vptr1; const genericptr vptr2; { /* * gather up all of the possible parameters except spell name * in advance, even though some might not be needed: * indx. = spl_orderindx[] index into spl_book[]; * otyp. = spl_book[] index into objects[]; * levl. = spell level; * skil. = skill group aka spell class. */ int indx1 = *(int *) vptr1, indx2 = *(int *) vptr2, otyp1 = spl_book[indx1].sp_id, otyp2 = spl_book[indx2].sp_id, levl1 = objects[otyp1].oc_level, levl2 = objects[otyp2].oc_level, skil1 = objects[otyp1].oc_skill, skil2 = objects[otyp2].oc_skill; switch (spl_sortmode) { case SORTBY_LETTER: return indx1 - indx2; case SORTBY_ALPHA: break; case SORTBY_LVL_LO: if (levl1 != levl2) return levl1 - levl2; break; case SORTBY_LVL_HI: if (levl1 != levl2) return levl2 - levl1; break; case SORTBY_SKL_AL: if (skil1 != skil2) return skil1 - skil2; break; case SORTBY_SKL_LO: if (skil1 != skil2) return skil1 - skil2; if (levl1 != levl2) return levl1 - levl2; break; case SORTBY_SKL_HI: if (skil1 != skil2) return skil1 - skil2; if (levl1 != levl2) return levl2 - levl1; break; case SORTBY_CURRENT: default: return (vptr1 < vptr2) ? -1 : (vptr1 > vptr2); /* keep current order */ } /* tie-breaker for most sorts--alphabetical by spell name */ return strcmpi(OBJ_NAME(objects[otyp1]), OBJ_NAME(objects[otyp2])); } /* sort the index used for display order of the "view known spells" list (sortmode == SORTBY_xxx), or sort the spellbook itself to make the current display order stick (sortmode == SORTRETAINORDER) */ STATIC_OVL void sortspells() { int i; #if defined(SYSV) || defined(DGUX) unsigned n; #else int n; #endif if (spl_sortmode == SORTBY_CURRENT) return; for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; ++n) continue; if (n < 2) return; /* not enough entries to need sorting */ if (!spl_orderindx) { /* we haven't done any sorting yet; list is in casting order */ if (spl_sortmode == SORTBY_LETTER /* default */ || spl_sortmode == SORTRETAINORDER) return; /* allocate enough for full spellbook rather than just N spells */ spl_orderindx = (int *) alloc(MAXSPELL * sizeof(int)); for (i = 0; i < MAXSPELL; i++) spl_orderindx[i] = i; } if (spl_sortmode == SORTRETAINORDER) { struct spell tmp_book[MAXSPELL]; /* sort spl_book[] rather than spl_orderindx[]; this also updates the index to reflect the new ordering (we could just free it since that ordering becomes the default) */ for (i = 0; i < MAXSPELL; i++) tmp_book[i] = spl_book[spl_orderindx[i]]; for (i = 0; i < MAXSPELL; i++) spl_book[i] = tmp_book[i], spl_orderindx[i] = i; spl_sortmode = SORTBY_LETTER; /* reset */ return; } /* usual case, sort the index rather than the spells themselves */ qsort((genericptr_t) spl_orderindx, n, sizeof *spl_orderindx, spell_cmp); return; } /* called if the [sort spells] entry in the view spells menu gets chosen */ STATIC_OVL boolean spellsortmenu() { winid tmpwin; menu_item *selected; anything any; char let; int i, n, choice; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; /* zero out all bits */ for (i = 0; i < SIZE(spl_sortchoices); i++) { if (i == SORTRETAINORDER) { let = 'z'; /* assumes fewer than 26 sort choices... */ /* separate final choice from others with a blank line */ any.a_int = 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); } else { let = 'a' + i; } any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, let, 0, ATR_NONE, spl_sortchoices[i], (i == spl_sortmode) ? MENU_SELECTED : MENU_UNSELECTED); } end_menu(tmpwin, "View known spells list sorted"); n = select_menu(tmpwin, PICK_ONE, &selected); destroy_nhwindow(tmpwin); if (n > 0) { choice = selected[0].item.a_int - 1; /* skip preselected entry if we have more than one item chosen */ if (n > 1 && choice == spl_sortmode) choice = selected[1].item.a_int - 1; free((genericptr_t) selected); spl_sortmode = choice; return TRUE; } return FALSE; } /* the '+' command -- view known spells */ int dovspell() { char qbuf[QBUFSZ]; int splnum, othnum; struct spell spl_tmp; if (spellid(0) == NO_SPELL) { You("don't know any spells right now."); } else { while (dospellmenu("Currently known spells", SPELLMENU_VIEW, &splnum)) { if (splnum == SPELLMENU_SORT) { if (spellsortmenu()) sortspells(); } else { Sprintf(qbuf, "Reordering spells; swap '%c' with", spellet(splnum)); if (!dospellmenu(qbuf, splnum, &othnum)) break; spl_tmp = spl_book[splnum]; spl_book[splnum] = spl_book[othnum]; spl_book[othnum] = spl_tmp; } } } if (spl_orderindx) { free((genericptr_t) spl_orderindx); spl_orderindx = 0; } spl_sortmode = SORTBY_LETTER; /* 0 */ return 0; } STATIC_OVL boolean dospellmenu(prompt, splaction, spell_no) const char *prompt; int splaction; /* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */ int *spell_no; { winid tmpwin; int i, n, how, splnum; char buf[BUFSZ], retentionbuf[24]; const char *fmt; menu_item *selected; anything any; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any = zeroany; /* zero out all bits */ /* * The correct spacing of the columns when not using * tab separation depends on the following: * (1) that the font is monospaced, and * (2) that selection letters are pre-pended to the * given string and are of the form "a - ". */ if (!iflags.menu_tab_sep) { Sprintf(buf, "%-20s Level %-12s Fail Retention", " Name", "Category"); fmt = "%-20s %2d %-12s %3d%% %9s"; } else { Sprintf(buf, "Name\tLevel\tCategory\tFail\tRetention"); fmt = "%s\t%-d\t%s\t%-d%%\t%s"; } add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED); for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) { splnum = !spl_orderindx ? i : spl_orderindx[i]; Sprintf(buf, fmt, spellname(splnum), spellev(splnum), spelltypemnemonic(spell_skilltype(spellid(splnum))), 100 - percent_success(splnum), spellretention(splnum, retentionbuf)); any.a_int = splnum + 1; /* must be non-zero */ add_menu(tmpwin, NO_GLYPH, &any, spellet(splnum), 0, ATR_NONE, buf, (splnum == splaction) ? MENU_SELECTED : MENU_UNSELECTED); } how = PICK_ONE; if (splaction == SPELLMENU_VIEW) { if (spellid(1) == NO_SPELL) { /* only one spell => nothing to swap with */ how = PICK_NONE; } else { /* more than 1 spell, add an extra menu entry */ any.a_int = SPELLMENU_SORT + 1; add_menu(tmpwin, NO_GLYPH, &any, '+', 0, ATR_NONE, "[sort spells]", MENU_UNSELECTED); } } end_menu(tmpwin, prompt); n = select_menu(tmpwin, how, &selected); destroy_nhwindow(tmpwin); if (n > 0) { *spell_no = selected[0].item.a_int - 1; /* menu selection for `PICK_ONE' does not de-select any preselected entry */ if (n > 1 && *spell_no == splaction) *spell_no = selected[1].item.a_int - 1; free((genericptr_t) selected); /* default selection of preselected spell means that user chose not to swap it with anything */ if (*spell_no == splaction) return FALSE; return TRUE; } else if (splaction >= 0) { /* explicit de-selection of preselected spell means that user is still swapping but not for the current spell */ *spell_no = splaction; return TRUE; } return FALSE; } STATIC_OVL int percent_success(spell) int spell; { /* Intrinsic and learned ability are combined to calculate * the probability of player's success at cast a given spell. */ int chance, splcaster, special, statused; int difficulty; int skill; /* Calculate intrinsic ability (splcaster) */ splcaster = urole.spelbase; special = urole.spelheal; statused = ACURR(urole.spelstat); if (uarm && is_metallic(uarm)) splcaster += (uarmc && uarmc->otyp == ROBE) ? urole.spelarmr / 2 : urole.spelarmr; else if (uarmc && uarmc->otyp == ROBE) splcaster -= urole.spelarmr; if (uarms) splcaster += urole.spelshld; if (uarmh && is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE) splcaster += uarmhbon; if (uarmg && is_metallic(uarmg)) splcaster += uarmgbon; if (uarmf && is_metallic(uarmf)) splcaster += uarmfbon; if (spellid(spell) == urole.spelspec) splcaster += urole.spelsbon; /* `healing spell' bonus */ if (spellid(spell) == SPE_HEALING || spellid(spell) == SPE_EXTRA_HEALING || spellid(spell) == SPE_CURE_BLINDNESS || spellid(spell) == SPE_CURE_SICKNESS || spellid(spell) == SPE_RESTORE_ABILITY || spellid(spell) == SPE_REMOVE_CURSE) splcaster += special; if (splcaster > 20) splcaster = 20; /* Calculate learned ability */ /* Players basic likelihood of being able to cast any spell * is based of their `magic' statistic. (Int or Wis) */ chance = 11 * statused / 2; /* * High level spells are harder. Easier for higher level casters. * The difficulty is based on the hero's level and their skill level * in that spell type. */ skill = P_SKILL(spell_skilltype(spellid(spell))); skill = max(skill, P_UNSKILLED) - 1; /* unskilled => 0 */ difficulty = (spellev(spell) - 1) * 4 - ((skill * 6) + (u.ulevel / 3) + 1); if (difficulty > 0) { /* Player is too low level or unskilled. */ chance -= isqrt(900 * difficulty + 2000); } else { /* Player is above level. Learning continues, but the * law of diminishing returns sets in quickly for * low-level spells. That is, a player quickly gains * no advantage for raising level. */ int learning = 15 * -difficulty / spellev(spell); chance += learning > 20 ? 20 : learning; } /* Clamp the chance: >18 stat and advanced learning only help * to a limit, while chances below "hopeless" only raise the * specter of overflowing 16-bit ints (and permit wearing a * shield to raise the chances :-). */ if (chance < 0) chance = 0; if (chance > 120) chance = 120; /* Wearing anything but a light shield makes it very awkward * to cast a spell. The penalty is not quite so bad for the * player's role-specific spell. */ if (uarms && weight(uarms) > (int) objects[SMALL_SHIELD].oc_weight) { if (spellid(spell) == urole.spelspec) { chance /= 2; } else { chance /= 4; } } /* Finally, chance (based on player intell/wisdom and level) is * combined with ability (based on player intrinsics and * encumbrances). No matter how intelligent/wise and advanced * a player is, intrinsics and encumbrance can prevent casting; * and no matter how able, learning is always required. */ chance = chance * (20 - splcaster) / 15 - splcaster; /* Clamp to percentile */ if (chance > 100) chance = 100; if (chance < 0) chance = 0; return chance; } STATIC_OVL char * spellretention(idx, outbuf) int idx; char *outbuf; { long turnsleft, percent, accuracy; int skill; skill = P_SKILL(spell_skilltype(spellid(idx))); skill = max(skill, P_UNSKILLED); /* restricted same as unskilled */ turnsleft = spellknow(idx); *outbuf = '\0'; /* lint suppression */ if (turnsleft < 1L) { /* spell has expired; hero can't successfully cast it anymore */ Strcpy(outbuf, "(gone)"); } else if (turnsleft >= (long) KEEN) { /* full retention, first turn or immediately after reading book */ Strcpy(outbuf, "100%"); } else { /* * Retention is displayed as a range of percentages of * amount of time left until memory of the spell expires; * the precision of the range depends upon hero's skill * in this spell. * expert: 2% intervals; 1-2, 3-4, ..., 99-100; * skilled: 5% intervals; 1-5, 6-10, ..., 95-100; * basic: 10% intervals; 1-10, 11-20, ..., 91-100; * unskilled: 25% intervals; 1-25, 26-50, 51-75, 76-100. * * At the low end of each range, a value of N% really means * (N-1)%+1 through N%; so 1% is "greater than 0, at most 200". * KEEN is a multiple of 100; KEEN/100 loses no precision. */ percent = (turnsleft - 1L) / ((long) KEEN / 100L) + 1L; accuracy = (skill == P_EXPERT) ? 2L : (skill == P_SKILLED) ? 5L : (skill == P_BASIC) ? 10L : 25L; /* round up to the high end of this range */ percent = accuracy * ((percent - 1L) / accuracy + 1L); Sprintf(outbuf, "%ld%%-%ld%%", percent - accuracy + 1L, percent); } return outbuf; } /* Learn a spell during creation of the initial inventory */ void initialspell(obj) struct obj *obj; { int i, otyp = obj->otyp; for (i = 0; i < MAXSPELL; i++) if (spellid(i) == NO_SPELL || spellid(i) == otyp) break; if (i == MAXSPELL) { impossible("Too many spells memorized!"); } else if (spellid(i) != NO_SPELL) { /* initial inventory shouldn't contain duplicate spellbooks */ impossible("Spell %s already known.", OBJ_NAME(objects[otyp])); } else { spl_book[i].sp_id = otyp; spl_book[i].sp_lev = objects[otyp].oc_level; incrnknow(i, 0); } return; } /*spell.c*/ nethack-3.6.0/src/steal.c0000664000076400007660000005635412622262031014211 0ustar paxedpaxed/* NetHack 3.6 steal.c $NHDT-Date: 1446713643 2015/11/05 08:54:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.65 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(stealarm); STATIC_DCL const char *FDECL(equipname, (struct obj *)); STATIC_OVL const char * equipname(otmp) register struct obj *otmp; { return ((otmp == uarmu) ? "shirt" : (otmp == uarmf) ? "boots" : (otmp == uarms) ? "shield" : (otmp == uarmg) ? "gloves" : (otmp == uarmc) ? cloak_simple_name(otmp) : (otmp == uarmh) ? helm_simple_name(otmp) : suit_simple_name(otmp)); } /* proportional subset of gold; return value actually fits in an int */ long somegold(lmoney) long lmoney; { #ifdef LINT /* long conv. ok */ int igold = 0; #else int igold = (lmoney >= (long) LARGEST_INT) ? LARGEST_INT : (int) lmoney; #endif if (igold < 50) ; /* all gold */ else if (igold < 100) igold = rn1(igold - 25 + 1, 25); else if (igold < 500) igold = rn1(igold - 50 + 1, 50); else if (igold < 1000) igold = rn1(igold - 100 + 1, 100); else if (igold < 5000) igold = rn1(igold - 500 + 1, 500); else if (igold < 10000) igold = rn1(igold - 1000 + 1, 1000); else igold = rn1(igold - 5000 + 1, 5000); return (long) igold; } /* * Find the first (and hopefully only) gold object in a chain. * Used when leprechaun (or you as leprechaun) looks for * someone else's gold. Returns a pointer so the gold may * be seized without further searching. * May search containers too. * Deals in gold only, as leprechauns don't care for lesser coins. */ struct obj * findgold(chain) register struct obj *chain; { while (chain && chain->otyp != GOLD_PIECE) chain = chain->nobj; return chain; } /* * Steal gold coins only. Leprechauns don't care for lesser coins. */ void stealgold(mtmp) register struct monst *mtmp; { register struct obj *fgold = g_at(u.ux, u.uy); register struct obj *ygold; register long tmp; struct monst *who; const char *whose, *what; /* skip lesser coins on the floor */ while (fgold && fgold->otyp != GOLD_PIECE) fgold = fgold->nexthere; /* Do you have real gold? */ ygold = findgold(invent); if (fgold && (!ygold || fgold->quan > ygold->quan || !rn2(5))) { obj_extract_self(fgold); add_to_minv(mtmp, fgold); newsym(u.ux, u.uy); if (u.usteed) { who = u.usteed; whose = s_suffix(y_monnam(who)); what = makeplural(mbodypart(who, FOOT)); } else { who = &youmonst; whose = "your"; what = makeplural(body_part(FOOT)); } /* [ avoid "between your rear regions" :-] */ if (slithy(who->data)) what = "coils"; /* reduce "rear hooves/claws" to "hooves/claws" */ if (!strncmp(what, "rear ", 5)) what += 5; pline("%s quickly snatches some gold from %s %s %s!", Monnam(mtmp), (Levitation || Flying) ? "beneath" : "between", whose, what); if (!ygold || !rn2(5)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); monflee(mtmp, 0, FALSE, FALSE); } } else if (ygold) { const int gold_price = objects[GOLD_PIECE].oc_cost; tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price; tmp = min(tmp, ygold->quan); if (tmp < ygold->quan) ygold = splitobj(ygold, tmp); else setnotworn(ygold); freeinv(ygold); add_to_minv(mtmp, ygold); Your("purse feels lighter."); if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); monflee(mtmp, 0, FALSE, FALSE); context.botl = 1; } } /* steal armor after you finish taking it off */ unsigned int stealoid; /* object to be stolen */ unsigned int stealmid; /* monster doing the stealing */ STATIC_PTR int stealarm(VOID_ARGS) { register struct monst *mtmp; register struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->o_id == stealoid) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (mtmp->m_id == stealmid) { if (DEADMONSTER(mtmp)) impossible("stealarm(): dead monster stealing"); if (!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */ goto botm; if (otmp->unpaid) subfrombill(otmp, shop_keeper(*u.ushops)); freeinv(otmp); pline("%s steals %s!", Monnam(mtmp), doname(otmp)); (void) mpickobj(mtmp, otmp); /* may free otmp */ /* Implies seduction, "you gladly hand over ..." so we don't set mavenge bit here. */ monflee(mtmp, 0, FALSE, FALSE); if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); break; } } break; } } botm: stealoid = 0; return 0; } /* An object you're wearing has been taken off by a monster (theft or seduction). Also used if a worn item gets transformed (stone to flesh). */ void remove_worn_item(obj, unchain_ball) struct obj *obj; boolean unchain_ball; /* whether to unpunish or just unwield */ { if (donning(obj)) cancel_don(); if (!obj->owornmask) return; if (obj->owornmask & W_ARMOR) { if (obj == uskin) { impossible("Removing embedded scales?"); skinback(TRUE); /* uarm = uskin; uskin = 0; */ } if (obj == uarm) (void) Armor_off(); else if (obj == uarmc) (void) Cloak_off(); else if (obj == uarmf) (void) Boots_off(); else if (obj == uarmg) (void) Gloves_off(); else if (obj == uarmh) (void) Helmet_off(); else if (obj == uarms) (void) Shield_off(); else if (obj == uarmu) (void) Shirt_off(); /* catchall -- should never happen */ else setworn((struct obj *) 0, obj->owornmask & W_ARMOR); } else if (obj->owornmask & W_AMUL) { Amulet_off(); } else if (obj->owornmask & W_RING) { Ring_gone(obj); } else if (obj->owornmask & W_TOOL) { Blindf_off(obj); } else if (obj->owornmask & W_WEAPON) { if (obj == uwep) uwepgone(); if (obj == uswapwep) uswapwepgone(); if (obj == uquiver) uqwepgone(); } if (obj->owornmask & (W_BALL | W_CHAIN)) { if (unchain_ball) unpunish(); } else if (obj->owornmask) { /* catchall */ setnotworn(obj); } } /* Returns 1 when something was stolen (or at least, when N should flee now) * Returns -1 if the monster died in the attempt * Avoid stealing the object stealoid * Nymphs and monkeys won't steal coins */ int steal(mtmp, objnambuf) struct monst *mtmp; char *objnambuf; { struct obj *otmp; int tmp, could_petrify, armordelay, olddelay, named = 0, retrycnt = 0; boolean monkey_business, /* true iff an animal is doing the thievery */ was_doffing; if (objnambuf) *objnambuf = '\0'; /* the following is true if successful on first of two attacks. */ if (!monnear(mtmp, u.ux, u.uy)) return 0; /* food being eaten might already be used up but will not have been removed from inventory yet; we don't want to steal that, so this will cause it to be removed now */ if (occupation) (void) maybe_finished_meal(FALSE); if (!invent || (inv_cnt(FALSE) == 1 && uskin)) { nothing_to_steal: /* Not even a thousand men in armor can strip a naked man. */ if (Blind) pline("Somebody tries to rob you, but finds nothing to steal."); else pline("%s tries to rob you, but there is nothing to steal!", Monnam(mtmp)); return 1; /* let her flee */ } monkey_business = is_animal(mtmp->data); if (monkey_business || uarmg) { ; /* skip ring special cases */ } else if (Adornment & LEFT_RING) { otmp = uleft; goto gotobj; } else if (Adornment & RIGHT_RING) { otmp = uright; goto gotobj; } retry: tmp = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin && otmp->oclass != COIN_CLASS) tmp += (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) ? 5 : 1; if (!tmp) goto nothing_to_steal; tmp = rn2(tmp); for (otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin && otmp->oclass != COIN_CLASS) { tmp -= (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) ? 5 : 1; if (tmp < 0) break; } if (!otmp) { impossible("Steal fails!"); return 0; } /* can't steal ring(s) while wearing gloves */ if ((otmp == uleft || otmp == uright) && uarmg) otmp = uarmg; /* can't steal gloves while wielding - so steal the wielded item. */ if (otmp == uarmg && uwep) otmp = uwep; /* can't steal armor while wearing cloak - so steal the cloak. */ else if (otmp == uarm && uarmc) otmp = uarmc; /* can't steal shirt while wearing cloak or suit */ else if (otmp == uarmu && uarmc) otmp = uarmc; else if (otmp == uarmu && uarm) otmp = uarm; gotobj: if (otmp->o_id == stealoid) return 0; if (otmp->otyp == BOULDER && !throws_rocks(mtmp->data)) { if (!retrycnt++) goto retry; goto cant_take; } /* animals can't overcome curse stickiness nor unlock chains */ if (monkey_business) { boolean ostuck; /* is the player prevented from voluntarily giving up this item? (ignores loadstones; the !can_carry() check will catch those) */ if (otmp == uball) ostuck = TRUE; /* effectively worn; curse is implicit */ else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) ostuck = FALSE; /* not really worn; curse doesn't matter */ else ostuck = ((otmp->cursed && otmp->owornmask) /* nymphs can steal rings from under cursed weapon but animals can't */ || (otmp == uright && welded(uwep)) || (otmp == uleft && welded(uwep) && bimanual(uwep))); if (ostuck || can_carry(mtmp, otmp) == 0) { static const char *const how[] = { "steal", "snatch", "grab", "take" }; cant_take: pline("%s tries to %s %s%s but gives up.", Monnam(mtmp), how[rn2(SIZE(how))], (otmp->owornmask & W_ARMOR) ? "your " : "", (otmp->owornmask & W_ARMOR) ? equipname(otmp) : yname(otmp)); /* the fewer items you have, the less likely the thief is going to stick around to try again (0) instead of running away (1) */ return !rn2(inv_cnt(FALSE) / 5 + 2); } } if (otmp->otyp == LEASH && otmp->leashmon) { if (monkey_business && otmp->cursed) goto cant_take; o_unleash(otmp); } was_doffing = doffing(otmp); /* stop donning/doffing now so that afternmv won't be clobbered below; stop_occupation doesn't handle donning/doffing */ olddelay = stop_donning(otmp); /* you're going to notice the theft... */ stop_occupation(); if (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) { switch (otmp->oclass) { case TOOL_CLASS: case AMULET_CLASS: case RING_CLASS: case FOOD_CLASS: /* meat ring */ remove_worn_item(otmp, TRUE); break; case ARMOR_CLASS: armordelay = objects[otmp->otyp].oc_delay; if (olddelay > 0 && olddelay < armordelay) armordelay = olddelay; if (monkey_business) { /* animals usually don't have enough patience to take off items which require extra time */ if (armordelay >= 1 && !olddelay && rn2(10)) goto cant_take; remove_worn_item(otmp, TRUE); break; } else { int curssv = otmp->cursed; int slowly; boolean seen = canspotmon(mtmp); otmp->cursed = 0; /* can't charm you without first waking you */ if (Unaware) unmul((char *) 0); slowly = (armordelay >= 1 || multi < 0); if (flags.female) pline("%s charms you. You gladly %s your %s.", !seen ? "She" : Monnam(mtmp), curssv ? "let her take" : !slowly ? "hand over" : was_doffing ? "continue removing" : "start removing", equipname(otmp)); else pline("%s seduces you and %s off your %s.", !seen ? "She" : Adjmonnam(mtmp, "beautiful"), curssv ? "helps you to take" : !slowly ? "you take" : was_doffing ? "you continue taking" : "you start taking", equipname(otmp)); named++; /* the following is to set multi for later on */ nomul(-armordelay); multi_reason = "taking off clothes"; nomovemsg = 0; remove_worn_item(otmp, TRUE); otmp->cursed = curssv; if (multi < 0) { /* multi = 0; afternmv = 0; */ stealoid = otmp->o_id; stealmid = mtmp->m_id; afternmv = stealarm; return 0; } } break; default: impossible("Tried to steal a strange worn thing. [%d]", otmp->oclass); } } else if (otmp->owornmask) remove_worn_item(otmp, TRUE); /* do this before removing it from inventory */ if (objnambuf) Strcpy(objnambuf, yname(otmp)); /* set mavenge bit so knights won't suffer an * alignment penalty during retaliation; */ mtmp->mavenge = 1; if (otmp->unpaid) subfrombill(otmp, shop_keeper(*u.ushops)); freeinv(otmp); pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp)); could_petrify = (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])); (void) mpickobj(mtmp, otmp); /* may free otmp */ if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) { minstapetrify(mtmp, TRUE); return -1; } return (multi < 0) ? 0 : 1; } /* Returns 1 if otmp is free'd, 0 otherwise. */ int mpickobj(mtmp, otmp) register struct monst *mtmp; register struct obj *otmp; { int freed_otmp; boolean snuff_otmp = FALSE; /* if monster is acquiring a thrown or kicked object, the throwing or kicking code shouldn't continue to track and place it */ if (otmp == thrownobj) thrownobj = 0; else if (otmp == kickedobj) kickedobj = 0; /* don't want hidden light source inside the monster; assumes that engulfers won't have external inventories; whirly monsters cause the light to be extinguished rather than letting it shine thru */ if (obj_sheds_light(otmp) && attacktype(mtmp->data, AT_ENGL)) { /* this is probably a burning object that you dropped or threw */ if (u.uswallow && mtmp == u.ustuck && !Blind) pline("%s out.", Tobjnam(otmp, "go")); snuff_otmp = TRUE; } /* for hero owned object on shop floor, mtmp is taking possession and if it's eventually dropped in a shop, shk will claim it */ if (!mtmp->mtame) otmp->no_charge = 0; /* Must do carrying effects on object prior to add_to_minv() */ carry_obj_effects(otmp); /* add_to_minv() might free otmp [if merged with something else], so we have to call it after doing the object checks */ freed_otmp = add_to_minv(mtmp, otmp); /* and we had to defer this until object is in mtmp's inventory */ if (snuff_otmp) snuff_light_source(mtmp->mx, mtmp->my); return freed_otmp; } void stealamulet(mtmp) struct monst *mtmp; { struct obj *otmp = (struct obj *) 0; int real = 0, fake = 0; /* select the artifact to steal */ if (u.uhave.amulet) { real = AMULET_OF_YENDOR; fake = FAKE_AMULET_OF_YENDOR; } else if (u.uhave.questart) { for (otmp = invent; otmp; otmp = otmp->nobj) if (is_quest_artifact(otmp)) break; if (!otmp) return; /* should we panic instead? */ } else if (u.uhave.bell) { real = BELL_OF_OPENING; fake = BELL; } else if (u.uhave.book) { real = SPE_BOOK_OF_THE_DEAD; } else if (u.uhave.menorah) { real = CANDELABRUM_OF_INVOCATION; } else return; /* you have nothing of special interest */ if (!otmp) { /* If we get here, real and fake have been set up. */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz)) break; } if (otmp) { /* we have something to snatch */ if (otmp->owornmask) remove_worn_item(otmp, TRUE); if (otmp->unpaid) subfrombill(otmp, shop_keeper(*u.ushops)); freeinv(otmp); /* mpickobj wont merge otmp because none of the above things to steal are mergable */ (void) mpickobj(mtmp, otmp); /* may merge and free otmp */ pline("%s stole %s!", Monnam(mtmp), doname(otmp)); if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) (void) rloc(mtmp, TRUE); } } /* when a mimic gets poked with something, it might take that thing (at present, only implemented for when the hero does the poking) */ void maybe_absorb_item(mon, obj, ochance, achance) struct monst *mon; struct obj *obj; int ochance, achance; /* percent chance for ordinary item, artifact */ { if (obj == uball || obj == uchain || obj->oclass == ROCK_CLASS || obj_resists(obj, 100 - ochance, 100 - achance) || !touch_artifact(obj, mon)) return; if (carried(obj)) { if (obj->owornmask) remove_worn_item(obj, TRUE); if (obj->unpaid) subfrombill(obj, shop_keeper(*u.ushops)); if (cansee(mon->mx, mon->my)) { const char *MonName = Monnam(mon); /* mon might be invisible; avoid "It pulls ... and absorbs it!" */ if (!strcmp(MonName, "It")) MonName = "Something"; pline("%s pulls %s away from you and absorbs %s!", MonName, yname(obj), (obj->quan > 1L) ? "them" : "it"); } else { const char *hand_s = body_part(HAND); if (bimanual(obj)) hand_s = makeplural(hand_s); pline("%s %s pulled from your %s!", upstart(yname(obj)), otense(obj, "are"), hand_s); } freeinv(obj); } else { /* not carried; presumably thrown or kicked */ if (canspotmon(mon)) pline("%s absorbs %s!", Monnam(mon), yname(obj)); } /* add to mon's inventory */ (void) mpickobj(mon, obj); } /* drop one object taken from a (possibly dead) monster's inventory */ void mdrop_obj(mon, obj, verbosely) struct monst *mon; struct obj *obj; boolean verbosely; { int omx = mon->mx, omy = mon->my; boolean update_mon = FALSE; if (obj->owornmask) { /* perform worn item handling if the monster is still alive */ if (mon->mhp > 0) { mon->misc_worn_check &= ~obj->owornmask; update_mon = TRUE; /* don't charge for an owned saddle on dead steed (provided that the hero is within the same shop at the time) */ } else if (mon->mtame && (obj->owornmask & W_SADDLE) && !obj->unpaid && costly_spot(omx, omy) /* being at costly_spot guarantees lev->roomno is not 0 */ && index(in_rooms(u.ux, u.uy, SHOPBASE), levl[omx][omy].roomno)) { obj->no_charge = 1; } /* this should be done even if the monster has died */ if (obj->owornmask & W_WEP) setmnotwielded(mon, obj); obj->owornmask = 0L; } /* obj_no_longer_held(obj); -- done by place_object */ if (verbosely && cansee(omx, omy)) pline("%s drops %s.", Monnam(mon), distant_name(obj, doname)); if (!flooreffects(obj, omx, omy, "fall")) { place_object(obj, omx, omy); stackobj(obj); } /* do this last, after placing obj on floor; removing steed's saddle throws rider, possibly inflicting fatal damage and producing bones */ if (update_mon) update_mon_intrinsics(mon, obj, FALSE, TRUE); } /* some monsters bypass the normal rules for moving between levels or even leaving the game entirely; when that happens, prevent them from taking the Amulet or invocation tools with them */ void mdrop_special_objs(mon) struct monst *mon; { struct obj *obj, *otmp; for (obj = mon->minvent; obj; obj = otmp) { otmp = obj->nobj; /* the Amulet, invocation tools, and Rider corpses resist even when artifacts and ordinary objects are given 0% resistance chance */ if (obj_resists(obj, 0, 0)) { obj_extract_self(obj); mdrop_obj(mon, obj, FALSE); } } } /* release the objects the creature is carrying */ void relobj(mtmp, show, is_pet) struct monst *mtmp; int show; boolean is_pet; /* If true, pet should keep wielded/worn items */ { struct obj *otmp; int omx = mtmp->mx, omy = mtmp->my; /* vault guard's gold goes away rather than be dropped... */ if (mtmp->isgd && (otmp = findgold(mtmp->minvent)) != 0) { if (canspotmon(mtmp)) pline("%s gold %s.", s_suffix(Monnam(mtmp)), canseemon(mtmp) ? "vanishes" : "seems to vanish"); obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } /* isgd && has gold */ while ((otmp = (is_pet ? droppables(mtmp) : mtmp->minvent)) != 0) { obj_extract_self(otmp); mdrop_obj(mtmp, otmp, is_pet && flags.verbose); } if (show && cansee(omx, omy)) newsym(omx, omy); } /*steal.c*/ nethack-3.6.0/src/steed.c0000664000076400007660000005415112613624165014210 0ustar paxedpaxed/* NetHack 3.6 steed.c $NHDT-Date: 1445906867 2015/10/27 00:47:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Kevin Hugo, 1998-1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Monsters that might be ridden */ static NEARDATA const char steeds[] = { S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0' }; STATIC_DCL boolean FDECL(landing_spot, (coord *, int, int)); STATIC_DCL void FDECL(maybewakesteed, (struct monst *)); /* caller has decided that hero can't reach something while mounted */ void rider_cant_reach() { You("aren't skilled enough to reach from %s.", y_monnam(u.usteed)); } /*** Putting the saddle on ***/ /* Can this monster wear a saddle? */ boolean can_saddle(mtmp) struct monst *mtmp; { struct permonst *ptr = mtmp->data; return (index(steeds, ptr->mlet) && (ptr->msize >= MZ_MEDIUM) && (!humanoid(ptr) || ptr->mlet == S_CENTAUR) && !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr) && !unsolid(ptr)); } int use_saddle(otmp) struct obj *otmp; { struct monst *mtmp; struct permonst *ptr; int chance; const char *s; if (!u_handsy()) return 0; /* Select an animal */ if (u.uswallow || Underwater || !getdir((char *) 0)) { pline1(Never_mind); return 0; } if (!u.dx && !u.dy) { pline("Saddle yourself? Very funny..."); return 0; } if (!isok(u.ux + u.dx, u.uy + u.dy) || !(mtmp = m_at(u.ux + u.dx, u.uy + u.dy)) || !canspotmon(mtmp)) { pline("I see nobody there."); return 1; } /* Is this a valid monster? */ if (mtmp->misc_worn_check & W_SADDLE || which_armor(mtmp, W_SADDLE)) { pline("%s doesn't need another one.", Monnam(mtmp)); return 1; } ptr = mtmp->data; if (touch_petrifies(ptr) && !uarmg && !Stone_resistance) { char kbuf[BUFSZ]; You("touch %s.", mon_nam(mtmp)); if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { Sprintf(kbuf, "attempting to saddle %s", an(mtmp->data->mname)); instapetrify(kbuf); } } if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { pline("Shame on you!"); exercise(A_WIS, FALSE); return 1; } if (mtmp->isminion || mtmp->isshk || mtmp->ispriest || mtmp->isgd || mtmp->iswiz) { pline("I think %s would mind.", mon_nam(mtmp)); return 1; } if (!can_saddle(mtmp)) { You_cant("saddle such a creature."); return 1; } /* Calculate your chance */ chance = ACURR(A_DEX) + ACURR(A_CHA) / 2 + 2 * mtmp->mtame; chance += u.ulevel * (mtmp->mtame ? 20 : 5); if (!mtmp->mtame) chance -= 10 * mtmp->m_lev; if (Role_if(PM_KNIGHT)) chance += 20; switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: default: chance -= 20; break; case P_BASIC: break; case P_SKILLED: chance += 15; break; case P_EXPERT: chance += 30; break; } if (Confusion || Fumbling || Glib) chance -= 20; else if (uarmg && (s = OBJ_DESCR(objects[uarmg->otyp])) != (char *) 0 && !strncmp(s, "riding ", 7)) /* Bonus for wearing "riding" (but not fumbling) gloves */ chance += 10; else if (uarmf && (s = OBJ_DESCR(objects[uarmf->otyp])) != (char *) 0 && !strncmp(s, "riding ", 7)) /* ... or for "riding boots" */ chance += 10; if (otmp->cursed) chance -= 50; /* [intended] steed becomes alert if possible */ maybewakesteed(mtmp); /* Make the attempt */ if (rn2(100) < chance) { You("put the saddle on %s.", mon_nam(mtmp)); if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); /* mpickobj may free otmp it if merges, but we have already checked for a saddle above, so no merger should happen */ (void) mpickobj(mtmp, otmp); mtmp->misc_worn_check |= W_SADDLE; otmp->owornmask = W_SADDLE; otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, FALSE); } else pline("%s resists!", Monnam(mtmp)); return 1; } /*** Riding the monster ***/ /* Can we ride this monster? Caller should also check can_saddle() */ boolean can_ride(mtmp) struct monst *mtmp; { return (mtmp->mtame && humanoid(youmonst.data) && !verysmall(youmonst.data) && !bigmonst(youmonst.data) && (!Underwater || is_swimmer(mtmp->data))); } int doride() { boolean forcemount = FALSE; if (u.usteed) { dismount_steed(DISMOUNT_BYCHOICE); } else if (getdir((char *) 0) && isok(u.ux + u.dx, u.uy + u.dy)) { if (wizard && yn("Force the mount to succeed?") == 'y') forcemount = TRUE; return (mount_steed(m_at(u.ux + u.dx, u.uy + u.dy), forcemount)); } else { return 0; } return 1; } /* Start riding, with the given monster */ boolean mount_steed(mtmp, force) struct monst *mtmp; /* The animal */ boolean force; /* Quietly force this animal */ { struct obj *otmp; char buf[BUFSZ]; struct permonst *ptr; /* Sanity checks */ if (u.usteed) { You("are already riding %s.", mon_nam(u.usteed)); return (FALSE); } /* Is the player in the right form? */ if (Hallucination && !force) { pline("Maybe you should find a designated driver."); return (FALSE); } /* While riding Wounded_legs refers to the steed's, * not the hero's legs. * That opens up a potential abuse where the player * can mount a steed, then dismount immediately to * heal leg damage, because leg damage is always * healed upon dismount (Wounded_legs context switch). * By preventing a hero with Wounded_legs from * mounting a steed, the potential for abuse is * reduced. However, dismounting still immediately * heals the steed's wounded legs. [In 3.4.3 and * earlier, that unintentionally made the hero's * temporary 1 point Dex loss become permanent.] */ if (Wounded_legs) { Your("%s are in no shape for riding.", makeplural(body_part(LEG))); if (force && wizard && yn("Heal your legs?") == 'y') HWounded_legs = EWounded_legs = 0; else return (FALSE); } if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) || bigmonst(youmonst.data) || slithy(youmonst.data))) { You("won't fit on a saddle."); return (FALSE); } if (!force && (near_capacity() > SLT_ENCUMBER)) { You_cant("do that while carrying so much stuff."); return (FALSE); } /* Can the player reach and see the monster? */ if (!mtmp || (!force && ((Blind && !Blind_telepat) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT))) { pline("I see nobody there."); return (FALSE); } if (u.uswallow || u.ustuck || u.utrap || Punished || !test_move(u.ux, u.uy, mtmp->mx - u.ux, mtmp->my - u.uy, TEST_MOVE)) { if (Punished || !(u.uswallow || u.ustuck || u.utrap)) You("are unable to swing your %s over.", body_part(LEG)); else You("are stuck here for now."); return (FALSE); } /* Is this a valid monster? */ otmp = which_armor(mtmp, W_SADDLE); if (!otmp) { pline("%s is not saddled.", Monnam(mtmp)); return (FALSE); } ptr = mtmp->data; if (touch_petrifies(ptr) && !Stone_resistance) { char kbuf[BUFSZ]; You("touch %s.", mon_nam(mtmp)); Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname)); instapetrify(kbuf); } if (!mtmp->mtame || mtmp->isminion) { pline("I think %s would mind.", mon_nam(mtmp)); return (FALSE); } if (mtmp->mtrapped) { struct trap *t = t_at(mtmp->mx, mtmp->my); You_cant("mount %s while %s's trapped in %s.", mon_nam(mtmp), mhe(mtmp), an(defsyms[trap_to_defsym(t->ttyp)].explanation)); return (FALSE); } if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) { /* no longer tame */ newsym(mtmp->mx, mtmp->my); pline("%s resists%s!", Monnam(mtmp), mtmp->mleashed ? " and its leash comes off" : ""); if (mtmp->mleashed) m_unleash(mtmp, FALSE); return (FALSE); } if (!force && Underwater && !is_swimmer(ptr)) { You_cant("ride that creature while under water."); return (FALSE); } if (!can_saddle(mtmp) || !can_ride(mtmp)) { You_cant("ride such a creature."); return (0); } /* Is the player impaired? */ if (!force && !is_floater(ptr) && !is_flyer(ptr) && Levitation && !Lev_at_will) { You("cannot reach %s.", mon_nam(mtmp)); return (FALSE); } if (!force && uarm && is_metallic(uarm) && greatest_erosion(uarm)) { Your("%s armor is too stiff to be able to mount %s.", uarm->oeroded ? "rusty" : "corroded", mon_nam(mtmp)); return (FALSE); } if (!force && (Confusion || Fumbling || Glib || Wounded_legs || otmp->cursed || (u.ulevel + mtmp->mtame < rnd(MAXULEV / 2 + 5)))) { if (Levitation) { pline("%s slips away from you.", Monnam(mtmp)); return FALSE; } You("slip while trying to get on %s.", mon_nam(mtmp)); Sprintf(buf, "slipped while mounting %s", /* "a saddled mumak" or "a saddled pony called Dobbin" */ x_monnam(mtmp, ARTICLE_A, (char *) 0, SUPPRESS_IT | SUPPRESS_INVISIBLE | SUPPRESS_HALLUCINATION, TRUE)); losehp(Maybe_Half_Phys(rn1(5, 10)), buf, NO_KILLER_PREFIX); return (FALSE); } /* Success */ maybewakesteed(mtmp); if (!force) { if (Levitation && !is_floater(ptr) && !is_flyer(ptr)) /* Must have Lev_at_will at this point */ pline("%s magically floats up!", Monnam(mtmp)); You("mount %s.", mon_nam(mtmp)); } /* setuwep handles polearms differently when you're mounted */ if (uwep && is_pole(uwep)) unweapon = FALSE; u.usteed = mtmp; remove_monster(mtmp->mx, mtmp->my); teleds(mtmp->mx, mtmp->my, TRUE); return (TRUE); } /* You and your steed have moved */ void exercise_steed() { if (!u.usteed) return; /* It takes many turns of riding to exercise skill */ if (u.urideturns++ >= 100) { u.urideturns = 0; use_skill(P_RIDING, 1); } return; } /* The player kicks or whips the steed */ void kick_steed() { char He[4]; if (!u.usteed) return; /* [ALI] Various effects of kicking sleeping/paralyzed steeds */ if (u.usteed->msleeping || !u.usteed->mcanmove) { /* We assume a message has just been output of the form * "You kick ." */ Strcpy(He, mhe(u.usteed)); *He = highc(*He); if ((u.usteed->mcanmove || u.usteed->mfrozen) && !rn2(2)) { if (u.usteed->mcanmove) u.usteed->msleeping = 0; else if (u.usteed->mfrozen > 2) u.usteed->mfrozen -= 2; else { u.usteed->mfrozen = 0; u.usteed->mcanmove = 1; } if (u.usteed->msleeping || !u.usteed->mcanmove) pline("%s stirs.", He); else pline("%s rouses %sself!", He, mhim(u.usteed)); } else pline("%s does not respond.", He); return; } /* Make the steed less tame and check if it resists */ if (u.usteed->mtame) u.usteed->mtame--; if (!u.usteed->mtame && u.usteed->mleashed) m_unleash(u.usteed, TRUE); if (!u.usteed->mtame || (u.ulevel + u.usteed->mtame < rnd(MAXULEV / 2 + 5))) { newsym(u.usteed->mx, u.usteed->my); dismount_steed(DISMOUNT_THROWN); return; } pline("%s gallops!", Monnam(u.usteed)); u.ugallop += rn1(20, 30); return; } /* * Try to find a dismount point adjacent to the steed's location. * If all else fails, try enexto(). Use enexto() as a last resort because * enexto() chooses its point randomly, possibly even outside the * room's walls, which is not what we want. * Adapted from mail daemon code. */ STATIC_OVL boolean landing_spot(spot, reason, forceit) coord *spot; /* landing position (we fill it in) */ int reason; int forceit; { int i = 0, x, y, distance, min_distance = -1; boolean found = FALSE; struct trap *t; /* avoid known traps (i == 0) and boulders, but allow them as a backup */ if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) i = 1; for (; !found && i < 2; ++i) { for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; if (accessible(x, y) && !MON_AT(x, y)) { distance = distu(x, y); if (min_distance < 0 || distance < min_distance || (distance == min_distance && rn2(2))) { if (i > 0 || (((t = t_at(x, y)) == 0 || !t->tseen) && (!sobj_at(BOULDER, x, y) || throws_rocks(youmonst.data)))) { spot->x = x; spot->y = y; min_distance = distance; found = TRUE; } } } } } /* If we didn't find a good spot and forceit is on, try enexto(). */ if (forceit && min_distance < 0 && !enexto(spot, u.ux, u.uy, youmonst.data)) return FALSE; return found; } /* Stop riding the current steed */ void dismount_steed(reason) int reason; /* Player was thrown off etc. */ { struct monst *mtmp; struct obj *otmp; coord cc; const char *verb = "fall"; boolean repair_leg_damage = (Wounded_legs != 0L); unsigned save_utrap = u.utrap; boolean have_spot = landing_spot(&cc, reason, 0); mtmp = u.usteed; /* make a copy of steed pointer */ /* Sanity check */ if (!mtmp) /* Just return silently */ return; /* Check the reason for dismounting */ otmp = which_armor(mtmp, W_SADDLE); switch (reason) { case DISMOUNT_THROWN: verb = "are thrown"; case DISMOUNT_FELL: You("%s off of %s!", verb, mon_nam(mtmp)); if (!have_spot) have_spot = landing_spot(&cc, reason, 1); losehp(Maybe_Half_Phys(rn1(10, 10)), "riding accident", KILLED_BY_AN); set_wounded_legs(BOTH_SIDES, (int) HWounded_legs + rn1(5, 5)); repair_leg_damage = FALSE; break; case DISMOUNT_POLY: You("can no longer ride %s.", mon_nam(u.usteed)); if (!have_spot) have_spot = landing_spot(&cc, reason, 1); break; case DISMOUNT_ENGULFED: /* caller displays message */ break; case DISMOUNT_BONES: /* hero has just died... */ break; case DISMOUNT_GENERIC: /* no messages, just make it so */ break; case DISMOUNT_BYCHOICE: default: if (otmp && otmp->cursed) { You("can't. The saddle %s cursed.", otmp->bknown ? "is" : "seems to be"); otmp->bknown = TRUE; return; } if (!have_spot) { You("can't. There isn't anywhere for you to stand."); return; } if (!has_mname(mtmp)) { pline("You've been through the dungeon on %s with no name.", an(mtmp->data->mname)); if (Hallucination) pline("It felt good to get out of the rain."); } else You("dismount %s.", mon_nam(mtmp)); } /* While riding, Wounded_legs refers to the steed's legs; after dismounting, it reverts to the hero's legs. */ if (repair_leg_damage) { /* [TODO: make heal_legs() take a parameter to handle this] */ in_steed_dismounting = TRUE; heal_legs(); in_steed_dismounting = FALSE; } /* Release the steed and saddle */ u.usteed = 0; u.ugallop = 0L; /* Set player and steed's position. Try moving the player first unless we're in the midst of creating a bones file. */ if (reason == DISMOUNT_BONES) { /* move the steed to an adjacent square */ if (enexto(&cc, u.ux, u.uy, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); else /* evidently no room nearby; move steed elsewhere */ (void) rloc(mtmp, FALSE); return; } if (mtmp->mhp > 0) { place_monster(mtmp, u.ux, u.uy); if (!u.uswallow && !u.ustuck && have_spot) { struct permonst *mdat = mtmp->data; /* The steed may drop into water/lava */ if (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) { if (is_pool(u.ux, u.uy)) { if (!Underwater) pline("%s falls into the %s!", Monnam(mtmp), surface(u.ux, u.uy)); if (!is_swimmer(mdat) && !amphibious(mdat)) { killed(mtmp); adjalign(-1); } } else if (is_lava(u.ux, u.uy)) { pline("%s is pulled into the lava!", Monnam(mtmp)); if (!likes_lava(mdat)) { killed(mtmp); adjalign(-1); } } } /* Steed dismounting consists of two steps: being moved to another * square, and descending to the floor. We have functions to do * each of these activities, but they're normally called * individually and include an attempt to look at or pick up the * objects on the floor: * teleds() --> spoteffects() --> pickup() * float_down() --> pickup() * We use this kludge to make sure there is only one such attempt. * * Clearly this is not the best way to do it. A full fix would * involve having these functions not call pickup() at all, * instead * calling them first and calling pickup() afterwards. But it * would take a lot of work to keep this change from having any * unforeseen side effects (for instance, you would no longer be * able to walk onto a square with a hole, and autopickup before * falling into the hole). */ /* [ALI] No need to move the player if the steed died. */ if (mtmp->mhp > 0) { /* Keep steed here, move the player to cc; * teleds() clears u.utrap */ in_steed_dismounting = TRUE; teleds(cc.x, cc.y, TRUE); in_steed_dismounting = FALSE; /* Put your steed in your trap */ if (save_utrap) (void) mintrap(mtmp); } /* Couldn't... try placing the steed */ } else if (enexto(&cc, u.ux, u.uy, mtmp->data)) { /* Keep player here, move the steed to cc */ rloc_to(mtmp, cc.x, cc.y); /* Player stays put */ /* Otherwise, kill the steed */ } else { killed(mtmp); adjalign(-1); } } /* Return the player to the floor */ if (reason != DISMOUNT_ENGULFED) { in_steed_dismounting = TRUE; (void) float_down(0L, W_SADDLE); in_steed_dismounting = FALSE; context.botl = 1; (void) encumber_msg(); vision_full_recalc = 1; } else context.botl = 1; /* polearms behave differently when not mounted */ if (uwep && is_pole(uwep)) unweapon = TRUE; return; } /* when attempting to saddle or mount a sleeping steed, try to wake it up (for the saddling case, it won't be u.usteed yet) */ STATIC_OVL void maybewakesteed(steed) struct monst *steed; { int frozen = (int) steed->mfrozen; boolean wasimmobile = steed->msleeping || !steed->mcanmove; steed->msleeping = 0; if (frozen) { frozen = (frozen + 1) / 2; /* half */ /* might break out of timed sleep or paralysis */ if (!rn2(frozen)) { steed->mfrozen = 0; steed->mcanmove = 1; } else { /* didn't awake, but remaining duration is halved */ steed->mfrozen = frozen; } } if (wasimmobile && !steed->msleeping && steed->mcanmove) pline("%s wakes up.", Monnam(steed)); /* regardless of waking, terminate any meal in progress */ finish_meating(steed); } /* decide whether hero's steed is able to move; doesn't check for holding traps--those affect the hero directly */ boolean stucksteed(checkfeeding) boolean checkfeeding; { struct monst *steed = u.usteed; if (steed) { /* check whether steed can move */ if (steed->msleeping || !steed->mcanmove) { pline("%s won't move!", upstart(y_monnam(steed))); return TRUE; } /* optionally check whether steed is in the midst of a meal */ if (checkfeeding && steed->meating) { pline("%s is still eating.", upstart(y_monnam(steed))); return TRUE; } } return FALSE; } void place_monster(mon, x, y) struct monst *mon; int x, y; { if (mon == u.usteed /* special case is for convoluted vault guard handling */ || (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) { impossible("placing %s onto map?", (mon == u.usteed) ? "steed" : "defunct monster"); return; } mon->mx = x, mon->my = y; level.monsters[x][y] = mon; } /*steed.c*/ nethack-3.6.0/src/sys.c0000664000076400007660000000717412624522452013723 0ustar paxedpaxed/* NetHack 3.6 sys.c $NHDT-Date: 1448241785 2015/11/23 01:23:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.35 $ */ /* Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifndef SYSCF /* !SYSCF configurations need '#define DEBUGFILES "foo.c bar.c"' * to enable debugging feedback for source files foo.c and bar.c; * to activate debugpline(), set an appropriate value and uncomment */ /* # define DEBUGFILES "*" */ /* note: DEBUGFILES value here or in sysconf.DEBUGFILES can be overridden at runtime by setting up a value for "DEBUGFILES" in the environment */ #endif struct sysopt sysopt; void sys_early_init() { sysopt.support = (char *) 0; sysopt.recover = (char *) 0; #ifdef SYSCF sysopt.wizards = (char *) 0; #else sysopt.wizards = dupstr(WIZARD_NAME); #endif #if defined(SYSCF) || !defined(DEBUGFILES) sysopt.debugfiles = (char *) 0; #else sysopt.debugfiles = dupstr(DEBUGFILES); #endif sysopt.env_dbgfl = 0; /* haven't checked getenv("DEBUGFILES") yet */ sysopt.shellers = (char *) 0; sysopt.explorers = (char *) 0; sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */ /* record file */ sysopt.persmax = PERSMAX; sysopt.entrymax = ENTRYMAX; sysopt.pointsmin = POINTSMIN; sysopt.pers_is_uid = PERS_IS_UID; sysopt.tt_oname_maxrank = 10; /* sanity checks */ if (PERSMAX < 1) sysopt.persmax = 1; if (ENTRYMAX < 10) sysopt.entrymax = 10; if (POINTSMIN < 1) sysopt.pointsmin = 1; if (PERS_IS_UID != 0 && PERS_IS_UID != 1) panic("config error: PERS_IS_UID must be either 0 or 1"); #ifdef PANICTRACE /* panic options */ sysopt.gdbpath = dupstr(GDBPATH); sysopt.greppath = dupstr(GREPPATH); #ifdef BETA sysopt.panictrace_gdb = 1; #ifdef PANICTRACE_LIBC sysopt.panictrace_libc = 2; #endif #else sysopt.panictrace_gdb = 0; #ifdef PANICTRACE_LIBC sysopt.panictrace_libc = 0; #endif #endif #endif sysopt.check_save_uid = 1; sysopt.seduce = 1; /* if it's compiled in, default to on */ sysopt_seduce_set(sysopt.seduce); return; } void sysopt_release() { if (sysopt.support) free((genericptr_t) sysopt.support), sysopt.support = (char *) 0; if (sysopt.recover) free((genericptr_t) sysopt.recover), sysopt.recover = (char *) 0; if (sysopt.wizards) free((genericptr_t) sysopt.wizards), sysopt.wizards = (char *) 0; if (sysopt.explorers) free((genericptr_t) sysopt.explorers), sysopt.explorers = (char *) 0; if (sysopt.shellers) free((genericptr_t) sysopt.shellers), sysopt.shellers = (char *) 0; if (sysopt.debugfiles) free((genericptr_t) sysopt.debugfiles), sysopt.debugfiles = (char *) 0; #ifdef PANICTRACE if (sysopt.gdbpath) free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = (char *) 0; if (sysopt.greppath) free((genericptr_t) sysopt.greppath), sysopt.greppath = (char *) 0; #endif /* this one's last because it might be used in panic feedback, although none of the preceding ones are likely to trigger a controlled panic */ if (sysopt.fmtd_wizard_list) free((genericptr_t) sysopt.fmtd_wizard_list), sysopt.fmtd_wizard_list = (char *) 0; return; } extern struct attack sa_yes[NATTK]; extern struct attack sa_no[NATTK]; void sysopt_seduce_set(val) int val; { struct attack *setval = val ? sa_yes : sa_no; int x; for (x = 0; x < NATTK; x++) { mons[PM_INCUBUS].mattk[x] = setval[x]; mons[PM_SUCCUBUS].mattk[x] = setval[x]; } return; } /*sys.c*/ nethack-3.6.0/src/teleport.c0000664000076400007660000012737512622262031014741 0ustar paxedpaxed/* NetHack 3.6 teleport.c $NHDT-Date: 1446887535 2015/11/07 09:12:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL boolean FDECL(tele_jump_ok, (int, int, int, int)); STATIC_DCL boolean FDECL(teleok, (int, int, BOOLEAN_P)); STATIC_DCL void NDECL(vault_tele); STATIC_DCL boolean FDECL(rloc_pos_ok, (int, int, struct monst *)); STATIC_DCL void FDECL(mvault_tele, (struct monst *)); /* non-null when teleporting via having read this scroll */ STATIC_VAR struct obj *telescroll = 0; /* * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good * for an object? * * This function will only look at mtmp->mdat, so makemon, mplayer, etc can * call it to generate new monster positions with fake monster structures. */ boolean goodpos(x, y, mtmp, gpflags) int x, y; struct monst *mtmp; unsigned gpflags; { struct permonst *mdat = (struct permonst *) 0; boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0); if (!isok(x, y)) return FALSE; /* in many cases, we're trying to create a new monster, which * can't go on top of the player or any existing monster. * however, occasionally we are relocating engravings or objects, * which could be co-located and thus get restricted a bit too much. * oh well. */ if (mtmp != &youmonst && x == u.ux && y == u.uy && (!u.usteed || mtmp != u.usteed)) return FALSE; if (mtmp) { struct monst *mtmp2 = m_at(x, y); /* Be careful with long worms. A monster may be placed back in * its own location. Normally, if m_at() returns the same monster * that we're trying to place, the monster is being placed in its * own location. However, that is not correct for worm segments, * because all the segments of the worm return the same m_at(). * Actually we overdo the check a little bit--a worm can't be placed * in its own location, period. If we just checked for mtmp->mx * != x || mtmp->my != y, we'd miss the case where we're called * to place the worm segment and the worm's head is at x,y. */ if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno)) return FALSE; mdat = mtmp->data; if (is_pool(x, y) && !ignorewater) { if (mtmp == &youmonst) return (Levitation || Flying || Wwalking || Swimming || Amphibious); else return (is_floater(mdat) || is_flyer(mdat) || is_swimmer(mdat) || is_clinger(mdat)); } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) { return FALSE; } else if (is_lava(x, y)) { if (mtmp == &youmonst) return (Levitation || Flying || (Fire_resistance && Wwalking && uarmf && uarmf->oerodeproof) || (Upolyd && likes_lava(youmonst.data))); else return (is_floater(mdat) || is_flyer(mdat) || likes_lava(mdat)); } if (passes_walls(mdat) && may_passwall(x, y)) return TRUE; if (amorphous(mdat) && closed_door(x, y)) return TRUE; } if (!accessible(x, y)) { if (!(is_pool(x, y) && ignorewater)) return FALSE; } if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat))) return FALSE; return TRUE; } /* * "entity next to" * * Attempt to find a good place for the given monster type in the closest * position to (xx,yy). Do so in successive square rings around (xx,yy). * If there is more than one valid position in the ring, choose one randomly. * Return TRUE and the position chosen when successful, FALSE otherwise. */ boolean enexto(cc, xx, yy, mdat) coord *cc; register xchar xx, yy; struct permonst *mdat; { return enexto_core(cc, xx, yy, mdat, 0); } boolean enexto_core(cc, xx, yy, mdat, entflags) coord *cc; register xchar xx, yy; struct permonst *mdat; unsigned entflags; { #define MAX_GOOD 15 coord good[MAX_GOOD], *good_ptr; int x, y, range, i; int xmin, xmax, ymin, ymax; struct monst fakemon; /* dummy monster */ if (!mdat) { debugpline0("enexto() called with null mdat"); /* default to player's original monster type */ mdat = &mons[u.umonster]; } fakemon.data = mdat; /* set up for goodpos */ good_ptr = good; range = 1; /* * Walk around the border of the square with center (xx,yy) and * radius range. Stop when we find at least one valid position. */ do { xmin = max(1, xx - range); xmax = min(COLNO - 1, xx + range); ymin = max(0, yy - range); ymax = min(ROWNO - 1, yy + range); for (x = xmin; x <= xmax; x++) if (goodpos(x, ymin, &fakemon, entflags)) { good_ptr->x = x; good_ptr->y = ymin; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD - 1]) goto full; } for (x = xmin; x <= xmax; x++) if (goodpos(x, ymax, &fakemon, entflags)) { good_ptr->x = x; good_ptr->y = ymax; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD - 1]) goto full; } for (y = ymin + 1; y < ymax; y++) if (goodpos(xmin, y, &fakemon, entflags)) { good_ptr->x = xmin; good_ptr->y = y; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD - 1]) goto full; } for (y = ymin + 1; y < ymax; y++) if (goodpos(xmax, y, &fakemon, entflags)) { good_ptr->x = xmax; good_ptr->y = y; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD - 1]) goto full; } range++; /* return if we've grown too big (nothing is valid) */ if (range > ROWNO && range > COLNO) return FALSE; } while (good_ptr == good); full: i = rn2((int) (good_ptr - good)); cc->x = good[i].x; cc->y = good[i].y; return TRUE; } /* * Check for restricted areas present in some special levels. (This might * need to be augmented to allow deliberate passage in wizard mode, but * only for explicitly chosen destinations.) */ STATIC_OVL boolean tele_jump_ok(x1, y1, x2, y2) int x1, y1, x2, y2; { if (dndest.nlx > 0) { /* if inside a restricted region, can't teleport outside */ if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy) && !within_bounded_area(x2, y2, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy)) return FALSE; /* and if outside, can't teleport inside */ if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy) && within_bounded_area(x2, y2, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy)) return FALSE; } if (updest.nlx > 0) { /* ditto */ if (within_bounded_area(x1, y1, updest.nlx, updest.nly, updest.nhx, updest.nhy) && !within_bounded_area(x2, y2, updest.nlx, updest.nly, updest.nhx, updest.nhy)) return FALSE; if (!within_bounded_area(x1, y1, updest.nlx, updest.nly, updest.nhx, updest.nhy) && within_bounded_area(x2, y2, updest.nlx, updest.nly, updest.nhx, updest.nhy)) return FALSE; } return TRUE; } STATIC_OVL boolean teleok(x, y, trapok) register int x, y; boolean trapok; { if (!trapok && t_at(x, y)) return FALSE; if (!goodpos(x, y, &youmonst, 0)) return FALSE; if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE; if (!in_out_region(x, y)) return FALSE; return TRUE; } void teleds(nux, nuy, allow_drag) register int nux, nuy; boolean allow_drag; { boolean ball_active, ball_still_in_range; if (u.utraptype == TT_BURIEDBALL) { /* unearth it */ buried_ball_to_punishment(); } ball_active = (Punished && uball->where != OBJ_FREE), ball_still_in_range = FALSE; /* If they have to move the ball, then drag if allow_drag is true; * otherwise they are teleporting, so unplacebc(). * If they don't have to move the ball, then always "drag" whether or * not allow_drag is true, because we are calling that function, not * to drag, but to move the chain. *However* there are some dumb * special cases: * 0 0 * _X move east -----> X_ * @ @ * These are permissible if teleporting, but not if dragging. As a * result, drag_ball() needs to know about allow_drag and might end * up dragging the ball anyway. Also, drag_ball() might find that * dragging the ball is completely impossible (ball in range but there's * rock in the way), in which case it teleports the ball on its own. */ if (ball_active) { if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2) ball_still_in_range = TRUE; /* don't have to move the ball */ else { /* have to move the ball */ if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) { /* we should not have dist > 1 and allow_drag at the same * time, but just in case, we must then revert to teleport. */ allow_drag = FALSE; unplacebc(); } } } u.utrap = 0; u.ustuck = 0; u.ux0 = u.ux; u.uy0 = u.uy; if (!hideunder(&youmonst) && youmonst.data->mlet == S_MIMIC) { /* mimics stop being unnoticed */ youmonst.m_ap_type = M_AP_NOTHING; } if (u.uswallow) { u.uswldtim = u.uswallow = 0; if (Punished && !ball_active) { /* ensure ball placement, like unstuck */ ball_active = TRUE; allow_drag = FALSE; } docrt(); } if (ball_active) { if (ball_still_in_range || allow_drag) { int bc_control; xchar ballx, bally, chainx, chainy; boolean cause_delay; if (drag_ball(nux, nuy, &bc_control, &ballx, &bally, &chainx, &chainy, &cause_delay, allow_drag)) move_bc(0, bc_control, ballx, bally, chainx, chainy); } } /* must set u.ux, u.uy after drag_ball(), which may need to know the old position if allow_drag is true... */ u_on_newpos(nux, nuy); /* set u., usteed->; cliparound() */ fill_pit(u.ux0, u.uy0); if (ball_active) { if (!ball_still_in_range && !allow_drag) placebc(); } initrack(); /* teleports mess up tracking monsters without this */ update_player_regions(); /* * Make sure the hero disappears from the old location. This will * not happen if she is teleported within sight of her previous * location. Force a full vision recalculation because the hero * is now in a new location. */ newsym(u.ux0, u.uy0); see_monsters(); vision_full_recalc = 1; nomul(0); vision_recalc(0); /* vision before effects */ if (telescroll) { /* when teleporting by scroll, we need to handle discovery now before getting feedback about any objects at our destination since we might land on another such scroll */ if (distu(u.ux0, u.uy0) >= 16 || !couldsee(u.ux0, u.uy0)) learnscroll(telescroll); else telescroll = 0; /* no discovery by scrolltele()'s caller */ } spoteffects(TRUE); invocation_message(); } boolean safe_teleds(allow_drag) boolean allow_drag; { register int nux, nuy, tcnt = 0; do { nux = rnd(COLNO - 1); nuy = rn2(ROWNO); } while (!teleok(nux, nuy, (boolean) (tcnt > 200)) && ++tcnt <= 400); if (tcnt <= 400) { teleds(nux, nuy, allow_drag); return TRUE; } else return FALSE; } STATIC_OVL void vault_tele() { register struct mkroom *croom = search_special(VAULT); coord c; if (croom && somexy(croom, &c) && teleok(c.x, c.y, FALSE)) { teleds(c.x, c.y, FALSE); return; } tele(); } boolean teleport_pet(mtmp, force_it) register struct monst *mtmp; boolean force_it; { register struct obj *otmp; if (mtmp == u.usteed) return FALSE; if (mtmp->mleashed) { otmp = get_mleash(mtmp); if (!otmp) { impossible("%s is leashed, without a leash.", Monnam(mtmp)); goto release_it; } if (otmp->cursed && !force_it) { yelp(mtmp); return FALSE; } else { Your("leash goes slack."); release_it: m_unleash(mtmp, FALSE); return TRUE; } } return TRUE; } /* teleport the hero via some method other than scroll of teleport */ void tele() { (void) scrolltele((struct obj *) 0); } /* teleport the hero; return true if scroll of teleportation should become discovered; teleds() will usually do the actual discovery, since the outcome sometimes depends upon destination and discovery needs to be performed before arrival, in case we land on another teleport scroll */ boolean scrolltele(scroll) struct obj *scroll; { coord cc; boolean result = FALSE; /* don't learn scroll */ /* Disable teleportation in stronghold && Vlad's Tower */ if (level.flags.noteleport) { if (!wizard) { pline("A mysterious force prevents you from teleporting!"); return TRUE; } } /* don't show trap if "Sorry..." */ if (!Blinded) make_blinded(0L, FALSE); if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) { You_feel("disoriented for a moment."); if (!wizard || yn("Override?") != 'y') return FALSE; } if ((Teleport_control && !Stunned) || wizard) { if (unconscious()) { pline("Being unconscious, you cannot control your teleport."); } else { char whobuf[BUFSZ]; Strcpy(whobuf, "you"); if (u.usteed) Sprintf(eos(whobuf), " and %s", mon_nam(u.usteed)); pline("To what position do %s want to be teleported?", whobuf); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the desired position") < 0) return TRUE; /* abort */ /* possible extensions: introduce a small error if magic power is low; allow transfer to solid rock */ if (teleok(cc.x, cc.y, FALSE)) { /* for scroll, discover it regardless of destination */ if (scroll) learnscroll(scroll); teleds(cc.x, cc.y, FALSE); return TRUE; } pline("Sorry..."); result = TRUE; } } else if (scroll && scroll->blessed) { /* (this used to be handled in seffects()) */ if (yn("Do you wish to teleport?") == 'n') return TRUE; result = TRUE; } telescroll = scroll; (void) safe_teleds(FALSE); /* teleds() will leave telescroll intact iff random destination is far enough away for scroll discovery to be warranted */ if (telescroll) result = TRUE; telescroll = 0; /* reset */ return result; } int dotele() { struct trap *trap; boolean trap_once = FALSE; trap = t_at(u.ux, u.uy); if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP)) trap = 0; if (trap) { trap_once = trap->once; /* trap may get deleted, save this */ if (trap->once) { pline("This is a vault teleport, usable once only."); if (yn("Jump in?") == 'n') trap = 0; else { deltrap(trap); newsym(u.ux, u.uy); } } if (trap) You("%s onto the teleportation trap.", locomotion(youmonst.data, "jump")); } if (!trap) { boolean castit = FALSE; register int sp_no = 0, energy = 0; if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12) && !can_teleport(youmonst.data))) { /* Try to use teleport away spell. */ if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion) for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) { castit = TRUE; break; } if (!wizard) { if (!castit) { if (!Teleportation) You("don't know that spell."); else You("are not able to teleport at will."); return 0; } } } if (u.uhunger <= 100 || ACURR(A_STR) < 6) { if (!wizard) { You("lack the strength %s.", castit ? "for a teleport spell" : "to teleport"); return 1; } } energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2; if (u.uen <= energy) { if (wizard) energy = u.uen; else { You("lack the energy %s.", castit ? "for a teleport spell" : "to teleport"); return 1; } } if (check_capacity( "Your concentration falters from carrying so much.")) return 1; if (castit) { exercise(A_WIS, TRUE); if (spelleffects(sp_no, TRUE)) return 1; else if (!wizard) return 0; } else { u.uen -= energy; context.botl = 1; } } if (next_to_u()) { if (trap && trap_once) vault_tele(); else tele(); (void) next_to_u(); } else { You1(shudder_for_moment); return 0; } if (!trap) morehungry(100); return 1; } void level_tele() { register int newlev; d_level newlevel; const char *escape_by_flying = 0; /* when surviving dest of -N */ char buf[BUFSZ]; boolean force_dest = FALSE; if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz)) && !wizard) { You_feel("very disoriented for a moment."); return; } if ((Teleport_control && !Stunned) || wizard) { char qbuf[BUFSZ]; int trycnt = 0; Strcpy(qbuf, "To what level do you want to teleport?"); do { if (++trycnt == 2) { if (wizard) Strcat(qbuf, " [type a number or ? for a menu]"); else Strcat(qbuf, " [type a number]"); } getlin(qbuf, buf); if (!strcmp(buf, "\033")) { /* cancelled */ if (Confusion && rnl(5)) { pline("Oops..."); goto random_levtport; } return; } else if (!strcmp(buf, "*")) { goto random_levtport; } else if (Confusion && rnl(5)) { pline("Oops..."); goto random_levtport; } if (wizard && !strcmp(buf, "?")) { schar destlev = 0; xchar destdnum = 0; newlev = (int) print_dungeon(TRUE, &destlev, &destdnum); if (!newlev) return; newlevel.dnum = destdnum; newlevel.dlevel = destlev; if (In_endgame(&newlevel) && !In_endgame(&u.uz)) { struct obj *amu; if (!u.uhave.amulet && (amu = mksobj(AMULET_OF_YENDOR, TRUE, FALSE)) != 0) { /* ordinarily we'd use hold_another_object() for something like this, but we don't want fumbling or already full pack to interfere */ amu = addinv(amu); prinv("Endgame prerequisite:", amu, 0L); } } force_dest = TRUE; } else if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf); } while (!newlev && !digit(buf[0]) && (buf[0] != '-' || !digit(buf[1])) && trycnt < 10); /* no dungeon escape via this route */ if (newlev == 0) { if (trycnt >= 10) goto random_levtport; if (ynq("Go to Nowhere. Are you sure?") != 'y') return; You("%s in agony as your body begins to warp...", is_silent(youmonst.data) ? "writhe" : "scream"); display_nhwindow(WIN_MESSAGE, FALSE); You("cease to exist."); if (invent) Your("possessions land on the %s with a thud.", surface(u.ux, u.uy)); killer.format = NO_KILLER_PREFIX; Strcpy(killer.name, "committed suicide"); done(DIED); pline("An energized cloud of dust begins to coalesce."); Your("body rematerializes%s.", invent ? ", and you gather up all your possessions" : ""); return; } /* if in Knox and the requested level > 0, stay put. * we let negative values requests fall into the "heaven" loop. */ if (Is_knox(&u.uz) && newlev > 0 && !force_dest) { You1(shudder_for_moment); return; } /* if in Quest, the player sees "Home 1", etc., on the status * line, instead of the logical depth of the level. controlled * level teleport request is likely to be relativized to the * status line, and consequently it should be incremented to * the value of the logical depth of the target level. * * we let negative values requests fall into the "heaven" loop. */ if (In_quest(&u.uz) && newlev > 0) newlev = newlev + dungeons[u.uz.dnum].depth_start - 1; } else { /* involuntary level tele */ random_levtport: newlev = random_teleport_level(); if (newlev == depth(&u.uz)) { You1(shudder_for_moment); return; } } if (u.utrap && u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); if (!next_to_u() && !force_dest) { You1(shudder_for_moment); return; } if (In_endgame(&u.uz)) { /* must already be wizard */ int llimit = dunlevs_in_dungeon(&u.uz); if (newlev >= 0 || newlev <= -llimit) { You_cant("get there from here."); return; } newlevel.dnum = u.uz.dnum; newlevel.dlevel = llimit + newlev; schedule_goto(&newlevel, FALSE, FALSE, 0, (char *) 0, (char *) 0); return; } killer.name[0] = 0; /* still alive, so far... */ if (newlev < 0 && !force_dest) { if (*u.ushops0) { /* take unpaid inventory items off of shop bills */ in_mklev = TRUE; /* suppress map update */ u_left_shop(u.ushops0, TRUE); /* you're now effectively out of the shop */ *u.ushops0 = *u.ushops = '\0'; in_mklev = FALSE; } if (newlev <= -10) { You("arrive in heaven."); verbalize("Thou art early, but we'll admit thee."); killer.format = NO_KILLER_PREFIX; Strcpy(killer.name, "went to heaven prematurely"); } else if (newlev == -9) { You_feel("deliriously happy. "); pline("(In fact, you're on Cloud 9!) "); display_nhwindow(WIN_MESSAGE, FALSE); } else You("are now high above the clouds..."); if (killer.name[0]) { ; /* arrival in heaven is pending */ } else if (Levitation) { escape_by_flying = "float gently down to earth"; } else if (Flying) { escape_by_flying = "fly down to the ground"; } else { pline("Unfortunately, you don't know how to fly."); You("plummet a few thousand feet to your death."); Sprintf(killer.name, "teleported out of the dungeon and fell to %s death", uhis()); killer.format = NO_KILLER_PREFIX; } } if (killer.name[0]) { /* the chosen destination was not survivable */ d_level lsav; /* set specific death location; this also suppresses bones */ lsav = u.uz; /* save current level, see below */ u.uz.dnum = 0; /* main dungeon */ u.uz.dlevel = (newlev <= -10) ? -10 : 0; /* heaven or surface */ done(DIED); /* can only get here via life-saving (or declining to die in explore|debug mode); the hero has now left the dungeon... */ escape_by_flying = "find yourself back on the surface"; u.uz = lsav; /* restore u.uz so escape code works */ } /* calls done(ESCAPED) if newlevel==0 */ if (escape_by_flying) { You("%s.", escape_by_flying); newlevel.dnum = 0; /* specify main dungeon */ newlevel.dlevel = 0; /* escape the dungeon */ /* [dlevel used to be set to 1, but it doesn't make sense to teleport out of the dungeon and float or fly down to the surface but then actually arrive back inside the dungeon] */ } else if (u.uz.dnum == medusa_level.dnum && newlev >= dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz)) { if (!(wizard && force_dest)) find_hell(&newlevel); } else { /* if invocation did not yet occur, teleporting into * the last level of Gehennom is forbidden. */ if (!wizard && Inhell && !u.uevent.invoked && newlev >= (dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz) - 1)) { newlev = dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz) - 2; pline("Sorry..."); } /* no teleporting out of quest dungeon */ if (In_quest(&u.uz) && newlev < depth(&qstart_level)) newlev = depth(&qstart_level); /* the player thinks of levels purely in logical terms, so * we must translate newlev to a number relative to the * current dungeon. */ if (!(wizard && force_dest)) get_level(&newlevel, newlev); } schedule_goto(&newlevel, FALSE, FALSE, 0, (char *) 0, (char *) 0); /* in case player just read a scroll and is about to be asked to call it something, we can't defer until the end of the turn */ if (u.utotype && !context.mon_moving) deferred_goto(); } void domagicportal(ttmp) register struct trap *ttmp; { struct d_level target_level; if (u.utrap && u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); if (!next_to_u()) { You1(shudder_for_moment); return; } /* if landed from another portal, do nothing */ /* problem: level teleport landing escapes the check */ if (!on_level(&u.uz, &u.uz0)) return; You("activated a magic portal!"); /* prevent the poor shnook, whose amulet was stolen while in * the endgame, from accidently triggering the portal to the * next level, and thus losing the game */ if (In_endgame(&u.uz) && !u.uhave.amulet) { You_feel("dizzy for a moment, but nothing happens..."); return; } target_level = ttmp->dst; schedule_goto(&target_level, FALSE, FALSE, 1, "You feel dizzy for a moment, but the sensation passes.", (char *) 0); } void tele_trap(trap) struct trap *trap; { if (In_endgame(&u.uz) || Antimagic) { if (Antimagic) shieldeff(u.ux, u.uy); You_feel("a wrenching sensation."); } else if (!next_to_u()) { You1(shudder_for_moment); } else if (trap->once) { deltrap(trap); newsym(u.ux, u.uy); /* get rid of trap symbol */ vault_tele(); } else tele(); } void level_tele_trap(trap) struct trap *trap; { You("%s onto a level teleport trap!", Levitation ? (const char *) "float" : locomotion(youmonst.data, "step")); if (Antimagic) { shieldeff(u.ux, u.uy); } if (Antimagic || In_endgame(&u.uz)) { You_feel("a wrenching sensation."); return; } if (!Blind) You("are momentarily blinded by a flash of light."); else You("are momentarily disoriented."); deltrap(trap); newsym(u.ux, u.uy); /* get rid of trap symbol */ level_tele(); } /* check whether monster can arrive at location via Tport (or fall) */ STATIC_OVL boolean rloc_pos_ok(x, y, mtmp) register int x, y; /* coordinates of candidate location */ struct monst *mtmp; { register int xx, yy; if (!goodpos(x, y, mtmp, 0)) return FALSE; /* * Check for restricted areas present in some special levels. * * `xx' is current column; if 0, then `yy' will contain flag bits * rather than row: bit #0 set => moving upwards; bit #1 set => * inside the Wizard's tower. */ xx = mtmp->mx; yy = mtmp->my; if (!xx) { /* no current location (migrating monster arrival) */ if (dndest.nlx && On_W_tower_level(&u.uz)) return (((yy & 2) != 0) /* inside xor not within */ ^ !within_bounded_area(x, y, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy)); if (updest.lx && (yy & 1) != 0) /* moving up */ return (within_bounded_area(x, y, updest.lx, updest.ly, updest.hx, updest.hy) && (!updest.nlx || !within_bounded_area(x, y, updest.nlx, updest.nly, updest.nhx, updest.nhy))); if (dndest.lx && (yy & 1) == 0) /* moving down */ return (within_bounded_area(x, y, dndest.lx, dndest.ly, dndest.hx, dndest.hy) && (!dndest.nlx || !within_bounded_area(x, y, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy))); } else { /* [try to] prevent a shopkeeper or temple priest from being sent out of his room (caller might resort to goodpos() if we report failure here, so this isn't full prevention) */ if (mtmp->isshk && inhishop(mtmp)) { if (levl[x][y].roomno != ESHK(mtmp)->shoproom) return FALSE; } else if (mtmp->ispriest && inhistemple(mtmp)) { if (levl[x][y].roomno != EPRI(mtmp)->shroom) return FALSE; } /* current location is */ if (!tele_jump_ok(xx, yy, x, y)) return FALSE; } /* is ok */ return TRUE; } /* * rloc_to() * * Pulls a monster from its current position and places a monster at * a new x and y. If oldx is 0, then the monster was not in the * levels.monsters * array. However, if oldx is 0, oldy may still have a value because mtmp is * a * migrating_mon. Worm tails are always placed randomly around the head of * the worm. */ void rloc_to(mtmp, x, y) struct monst *mtmp; register int x, y; { register int oldx = mtmp->mx, oldy = mtmp->my; boolean resident_shk = mtmp->isshk && inhishop(mtmp); if (x == mtmp->mx && y == mtmp->my) /* that was easy */ return; if (oldx) { /* "pick up" monster */ if (mtmp->wormno) remove_worm(mtmp); else { remove_monster(oldx, oldy); newsym(oldx, oldy); /* update old location */ } } place_monster(mtmp, x, y); /* put monster down */ update_monster_region(mtmp); if (mtmp->wormno) /* now put down tail */ place_worm_tail_randomly(mtmp, x, y); if (u.ustuck == mtmp) { if (u.uswallow) { u.ux = x; u.uy = y; docrt(); } else u.ustuck = 0; } newsym(x, y); /* update new location */ set_apparxy(mtmp); /* orient monster */ /* shopkeepers will only teleport if you zap them with a wand of teleportation or if they've been transformed into a jumpy monster; the latter only happens if you've attacked them with polymorph */ if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy); } /* place a monster at a random location, typically due to teleport */ /* return TRUE if successful, FALSE if not */ boolean rloc(mtmp, suppress_impossible) struct monst *mtmp; /* mx==0 implies migrating monster arrival */ boolean suppress_impossible; { register int x, y, trycount; if (mtmp == u.usteed) { tele(); return TRUE; } if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */ if (!In_W_tower(u.ux, u.uy, &u.uz)) x = xupstair, y = yupstair; else if (!xdnladder) /* bottom level of tower */ x = xupladder, y = yupladder; else x = xdnladder, y = ydnladder; /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed (deliberately use `goodpos' rather than `rloc_pos_ok' here) */ if (goodpos(x, y, mtmp, 0)) goto found_xy; } trycount = 0; do { x = rn1(COLNO - 3, 2); y = rn2(ROWNO); if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp) : goodpos(x, y, mtmp, 0)) goto found_xy; } while (++trycount < 1000); /* last ditch attempt to find a good place */ for (x = 2; x < COLNO - 1; x++) for (y = 0; y < ROWNO; y++) if (goodpos(x, y, mtmp, 0)) goto found_xy; /* level either full of monsters or somehow faulty */ if (!suppress_impossible) impossible("rloc(): couldn't relocate monster"); return FALSE; found_xy: rloc_to(mtmp, x, y); return TRUE; } STATIC_OVL void mvault_tele(mtmp) struct monst *mtmp; { register struct mkroom *croom = search_special(VAULT); coord c; if (croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, 0)) { rloc_to(mtmp, c.x, c.y); return; } (void) rloc(mtmp, TRUE); } boolean tele_restrict(mon) struct monst *mon; { if (level.flags.noteleport) { if (canseemon(mon)) pline("A mysterious force prevents %s from teleporting!", mon_nam(mon)); return TRUE; } return FALSE; } void mtele_trap(mtmp, trap, in_sight) struct monst *mtmp; struct trap *trap; int in_sight; { char *monname; if (tele_restrict(mtmp)) return; if (teleport_pet(mtmp, FALSE)) { /* save name with pre-movement visibility */ monname = Monnam(mtmp); /* Note: don't remove the trap if a vault. Other- * wise the monster will be stuck there, since * the guard isn't going to come for it... */ if (trap->once) mvault_tele(mtmp); else (void) rloc(mtmp, TRUE); if (in_sight) { if (canseemon(mtmp)) pline("%s seems disoriented.", monname); else pline("%s suddenly disappears!", monname); seetrap(trap); } } } /* return 0 if still on level, 3 if not */ int mlevel_tele_trap(mtmp, trap, force_it, in_sight) struct monst *mtmp; struct trap *trap; boolean force_it; int in_sight; { int tt = trap->ttyp; struct permonst *mptr = mtmp->data; if (mtmp == u.ustuck) /* probably a vortex */ return 0; /* temporary? kludge */ if (teleport_pet(mtmp, force_it)) { d_level tolevel; int migrate_typ = MIGR_RANDOM; if ((tt == HOLE || tt == TRAPDOOR)) { if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { if (in_sight && trap->tseen) pline("%s avoids the %s.", Monnam(mtmp), (tt == HOLE) ? "hole" : "trap"); return 0; } else { get_level(&tolevel, depth(&u.uz) + 1); } } else if (tt == MAGIC_PORTAL) { if (In_endgame(&u.uz) && (mon_has_amulet(mtmp) || is_home_elemental(mptr))) { if (in_sight && mptr->mlet != S_ELEMENTAL) { pline("%s seems to shimmer for a moment.", Monnam(mtmp)); seetrap(trap); } return 0; } else { assign_level(&tolevel, &trap->dst); migrate_typ = MIGR_PORTAL; } } else { /* (tt == LEVEL_TELEP) */ int nlev; if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (in_sight) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 0; } nlev = random_teleport_level(); if (nlev == depth(&u.uz)) { if (in_sight) pline("%s shudders for a moment.", Monnam(mtmp)); return 0; } get_level(&tolevel, nlev); } if (in_sight) { pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp)); seetrap(trap); } migrate_to_level(mtmp, ledger_no(&tolevel), migrate_typ, (coord *) 0); return 3; /* no longer on this level */ } return 0; } /* place object randomly, returns False if it's gone (eg broken) */ boolean rloco(obj) register struct obj *obj; { register xchar tx, ty, otx, oty; boolean restricted_fall; int try_limit = 4000; if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) { if (revive_corpse(obj)) return FALSE; } obj_extract_self(obj); otx = obj->ox; oty = obj->oy; restricted_fall = (otx == 0 && dndest.lx); do { tx = rn1(COLNO - 3, 2); ty = rn2(ROWNO); if (!--try_limit) break; } while (!goodpos(tx, ty, (struct monst *) 0, 0) || (restricted_fall && (!within_bounded_area(tx, ty, dndest.lx, dndest.ly, dndest.hx, dndest.hy) || (dndest.nlx && within_bounded_area(tx, ty, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy)))) /* on the Wizard Tower levels, objects inside should stay inside and objects outside should stay outside */ || (dndest.nlx && On_W_tower_level(&u.uz) && within_bounded_area(tx, ty, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy) != within_bounded_area(otx, oty, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy))); if (flooreffects(obj, tx, ty, "fall")) { return FALSE; } else if (otx == 0 && oty == 0) { ; /* fell through a trap door; no update of old loc needed */ } else { if (costly_spot(otx, oty) && (!costly_spot(tx, ty) || !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) { if (costly_spot(u.ux, u.uy) && index(u.urooms, *in_rooms(otx, oty, 0))) addtobill(obj, FALSE, FALSE, FALSE); else (void) stolen_value(obj, otx, oty, FALSE, FALSE); } newsym(otx, oty); /* update old location */ } place_object(obj, tx, ty); newsym(tx, ty); return TRUE; } /* Returns an absolute depth */ int random_teleport_level() { int nlev, max_depth, min_depth, cur_depth = (int) depth(&u.uz); /* [the endgame case can only occur in wizard mode] */ if (!rn2(5) || Is_knox(&u.uz) || In_endgame(&u.uz)) return cur_depth; /* What I really want to do is as follows: * -- If in a dungeon that goes down, the new level is to be restricted * to [top of parent, bottom of current dungeon] * -- If in a dungeon that goes up, the new level is to be restricted * to [top of current dungeon, bottom of parent] * -- If in a quest dungeon or similar dungeon entered by portals, * the new level is to be restricted to [top of current dungeon, * bottom of current dungeon] * The current behavior is not as sophisticated as that ideal, but is * still better what we used to do, which was like this for players * but different for monsters for no obvious reason. Currently, we * must explicitly check for special dungeons. We check for Knox * above; endgame is handled in the caller due to its different * message ("disoriented"). * --KAA * 3.4.2: explicitly handle quest here too, to fix the problem of * monsters sometimes level teleporting out of it into main dungeon. * Also prevent monsters reaching the Sanctum prior to invocation. */ if (In_quest(&u.uz)) { int bottom = dunlevs_in_dungeon(&u.uz), qlocate_depth = qlocate_level.dlevel; /* if hero hasn't reached the middle locate level yet, no one can randomly teleport past it */ if (dunlev_reached(&u.uz) < qlocate_depth) bottom = qlocate_depth; min_depth = dungeons[u.uz.dnum].depth_start; max_depth = bottom + (dungeons[u.uz.dnum].depth_start - 1); } else { min_depth = 1; max_depth = dunlevs_in_dungeon(&u.uz) + (dungeons[u.uz.dnum].depth_start - 1); /* can't reach Sanctum if the invocation hasn't been performed */ if (Inhell && !u.uevent.invoked) max_depth -= 1; } /* Get a random value relative to the current dungeon */ /* Range is 1 to current+3, current not counting */ nlev = rn2(cur_depth + 3 - min_depth) + min_depth; if (nlev >= cur_depth) nlev++; if (nlev > max_depth) { nlev = max_depth; /* teleport up if already on bottom */ if (Is_botlevel(&u.uz)) nlev -= rnd(3); } if (nlev < min_depth) { nlev = min_depth; if (nlev == cur_depth) { nlev += rnd(3); if (nlev > max_depth) nlev = max_depth; } } return nlev; } /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack); return false iff the attempt fails */ boolean u_teleport_mon(mtmp, give_feedback) struct monst *mtmp; boolean give_feedback; { coord cc; if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) { if (give_feedback) pline("%s resists your magic!", Monnam(mtmp)); return FALSE; } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) { if (give_feedback) You("are no longer inside %s!", mon_nam(mtmp)); unstuck(mtmp); (void) rloc(mtmp, TRUE); } else if (is_rider(mtmp->data) && rn2(13) && enexto(&cc, u.ux, u.uy, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); else (void) rloc(mtmp, TRUE); return TRUE; } /*teleport.c*/ nethack-3.6.0/src/timeout.c0000664000076400007660000016766712617413107014607 0ustar paxedpaxed/* NetHack 3.6 timeout.c $NHDT-Date: 1446861771 2015/11/07 02:02:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" /* for checking save modes */ STATIC_DCL void NDECL(stoned_dialogue); STATIC_DCL void NDECL(vomiting_dialogue); STATIC_DCL void NDECL(choke_dialogue); STATIC_DCL void NDECL(slime_dialogue); STATIC_DCL void NDECL(slip_or_trip); STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *)); STATIC_DCL void FDECL(lantern_message, (struct obj *)); STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long)); /* He is being petrified - dialogue by inmet!tower */ static NEARDATA const char *const stoned_texts[] = { "You are slowing down.", /* 5 */ "Your limbs are stiffening.", /* 4 */ "Your limbs have turned to stone.", /* 3 */ "You have turned to stone.", /* 2 */ "You are a statue." /* 1 */ }; STATIC_OVL void stoned_dialogue() { register long i = (Stoned & TIMEOUT); if (i > 0L && i <= SIZE(stoned_texts)) { char buf[BUFSZ]; Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]); if (nolimbs(youmonst.data) && strstri(buf, "limbs")) (void) strsubst(buf, "limbs", "extremities"); pline1(buf); } switch ((int) i) { case 5: /* slowing down */ HFast = 0L; if (multi > 0) nomul(0); break; case 4: /* limbs stiffening */ /* just one move left to save oneself so quit fiddling around; don't stop attempt to eat tin--might be lizard or acidic */ if (!Popeye(STONED)) stop_occupation(); if (multi > 0) nomul(0); break; case 3: /* limbs turned to stone */ stop_occupation(); nomul(-3); /* can't move anymore */ multi_reason = "getting stoned"; nomovemsg = You_can_move_again; /* not unconscious */ break; default: break; } exercise(A_DEX, FALSE); } /* He is getting sicker and sicker prior to vomiting */ static NEARDATA const char *const vomiting_texts[] = { "are feeling mildly nauseated.", /* 14 */ "feel slightly confused.", /* 11 */ "can't seem to think straight.", /* 8 */ "feel incredibly sick.", /* 5 */ "suddenly vomit!" /* 2 */ }; STATIC_OVL void vomiting_dialogue() { const char *txt = 0; long v = (Vomiting & TIMEOUT); /* note: nhtimeout() hasn't decremented timed properties for the current turn yet, so we use Vomiting-1 here */ switch ((int) (v - 1L)) { case 14: txt = vomiting_texts[0]; break; case 11: txt = vomiting_texts[1]; break; case 6: make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE); if (!Popeye(VOMITING)) stop_occupation(); /*FALLTHRU*/ case 9: make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE); if (multi > 0) nomul(0); break; case 8: txt = vomiting_texts[2]; break; case 5: txt = vomiting_texts[3]; break; case 2: txt = vomiting_texts[4]; if (cantvomit(youmonst.data)) txt = "gag uncontrolably."; break; case 0: stop_occupation(); if (!cantvomit(youmonst.data)) morehungry(20); vomit(); break; default: break; } if (txt) You1(txt); exercise(A_CON, FALSE); } static NEARDATA const char *const choke_texts[] = { "You find it hard to breathe.", "You're gasping for air.", "You can no longer breathe.", "You're turning %s.", "You suffocate." }; static NEARDATA const char *const choke_texts2[] = { "Your %s is becoming constricted.", "Your blood is having trouble reaching your brain.", "The pressure on your %s increases.", "Your consciousness is fading.", "You suffocate." }; STATIC_OVL void choke_dialogue() { register long i = (Strangled & TIMEOUT); if (i > 0 && i <= SIZE(choke_texts)) { if (Breathless || !rn2(50)) pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK)); else { const char *str = choke_texts[SIZE(choke_texts) - i]; if (index(str, '%')) pline(str, hcolor(NH_BLUE)); else pline1(str); } } exercise(A_STR, FALSE); } static NEARDATA const char *const slime_texts[] = { "You are turning a little %s.", /* 5 */ "Your limbs are getting oozy.", /* 4 */ "Your skin begins to peel away.", /* 3 */ "You are turning into %s.", /* 2 */ "You have become %s." /* 1 */ }; STATIC_OVL void slime_dialogue() { register long i = (Slimed & TIMEOUT) / 2L; if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) { char buf[BUFSZ]; Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]); if (nolimbs(youmonst.data) && strstri(buf, "limbs")) (void) strsubst(buf, "limbs", "extremities"); if (index(buf, '%')) { if (i == 4L) { /* "you are turning green" */ if (!Blind) /* [what if you're already green?] */ pline(buf, hcolor(NH_GREEN)); } else pline(buf, an(Hallucination ? rndmonnam(NULL) : "green slime")); } else pline1(buf); } if (i == 3L) { /* limbs becoming oozy */ HFast = 0L; /* lose intrinsic speed */ if (!Popeye(SLIMED)) stop_occupation(); if (multi > 0) nomul(0); } exercise(A_DEX, FALSE); } void burn_away_slime() { if (Slimed) { make_slimed(0L, "The slime that covers you is burned away!"); } } void nh_timeout() { register struct prop *upp; struct kinfo *kptr; int sleeptime; int m_idx; int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0; if (flags.friday13) baseluck -= 1; if (u.uluck != baseluck && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) { /* Cursed luckstones stop bad luck from timing out; blessed luckstones * stop good luck from timing out; normal luckstones stop both; * neither is stopped if you don't have a luckstone. * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th */ register int time_luck = stone_luck(FALSE); boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE); if (u.uluck > baseluck && (nostone || time_luck < 0)) u.uluck--; else if (u.uluck < baseluck && (nostone || time_luck > 0)) u.uluck++; } if (u.uinvulnerable) return; /* things past this point could kill you */ if (Stoned) stoned_dialogue(); if (Slimed) slime_dialogue(); if (Vomiting) vomiting_dialogue(); if (Strangled) choke_dialogue(); if (u.mtimedone && !--u.mtimedone) { if (Unchanging) u.mtimedone = rnd(100 * youmonst.data->mlevel + 1); else rehumanize(); } if (u.ucreamed) u.ucreamed--; /* Dissipate spell-based protection. */ if (u.usptime) { if (--u.usptime == 0 && u.uspellprot) { u.usptime = u.uspmtime; u.uspellprot--; find_ac(); if (!Blind) Norep("The %s haze around you %s.", hcolor(NH_GOLDEN), u.uspellprot ? "becomes less dense" : "disappears"); } } if (u.ugallop) { if (--u.ugallop == 0L && u.usteed) pline("%s stops galloping.", Monnam(u.usteed)); } for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++) if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) { kptr = find_delayed_killer((int) (upp - u.uprops)); switch (upp - u.uprops) { case STONED: if (kptr && kptr->name[0]) { killer.format = kptr->format; Strcpy(killer.name, kptr->name); } else { killer.format = NO_KILLER_PREFIX; Strcpy(killer.name, "killed by petrification"); } dealloc_killer(kptr); /* (unlike sliming, you aren't changing form here) */ done(STONING); break; case SLIMED: if (kptr && kptr->name[0]) { killer.format = kptr->format; Strcpy(killer.name, kptr->name); } else { killer.format = NO_KILLER_PREFIX; Strcpy(killer.name, "turned into green slime"); } dealloc_killer(kptr); /* involuntarily break "never changed form" conduct */ u.uconduct.polyselfs++; done(TURNED_SLIME); break; case VOMITING: make_vomiting(0L, TRUE); break; case SICK: You("die from your illness."); if (kptr && kptr->name[0]) { killer.format = kptr->format; Strcpy(killer.name, kptr->name); } else { killer.format = KILLED_BY_AN; killer.name[0] = 0; /* take the default */ } dealloc_killer(kptr); if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) { if (type_is_pname(&mons[m_idx])) { killer.format = KILLED_BY; } else if (mons[m_idx].geno & G_UNIQ) { Strcpy(killer.name, the(killer.name)); killer.format = KILLED_BY; } } u.usick_type = 0; done(POISONING); break; case FAST: if (!Very_fast) You_feel("yourself slowing down%s.", Fast ? " a bit" : ""); break; case CONFUSION: /* So make_confused works properly */ set_itimeout(&HConfusion, 1L); make_confused(0L, TRUE); if (!Confusion) stop_occupation(); break; case STUNNED: set_itimeout(&HStun, 1L); make_stunned(0L, TRUE); if (!Stunned) stop_occupation(); break; case BLINDED: set_itimeout(&Blinded, 1L); make_blinded(0L, TRUE); if (!Blind) stop_occupation(); break; case DEAF: set_itimeout(&HDeaf, 1L); make_deaf(0L, TRUE); if (!Deaf) stop_occupation(); break; case INVIS: newsym(u.ux, u.uy); if (!Invis && !BInvis && !Blind) { You(!See_invisible ? "are no longer invisible." : "can no longer see through yourself."); stop_occupation(); } break; case SEE_INVIS: set_mimic_blocking(); /* do special mimic handling */ see_monsters(); /* make invis mons appear */ newsym(u.ux, u.uy); /* make self appear */ stop_occupation(); break; case WOUNDED_LEGS: heal_legs(); stop_occupation(); break; case HALLUC: set_itimeout(&HHallucination, 1L); (void) make_hallucinated(0L, TRUE, 0L); if (!Hallucination) stop_occupation(); break; case SLEEPY: if (unconscious() || Sleep_resistance) { incr_itimeout(&HSleepy, rnd(100)); } else if (Sleepy) { You("fall asleep."); sleeptime = rnd(20); fall_asleep(-sleeptime, TRUE); incr_itimeout(&HSleepy, sleeptime + rnd(100)); } break; case LEVITATION: (void) float_down(I_SPECIAL | TIMEOUT, 0L); break; case STRANGLED: killer.format = KILLED_BY; Strcpy(killer.name, (u.uburied) ? "suffocation" : "strangulation"); done(DIED); /* must be declining to die in explore|wizard mode; treat like being cured of strangulation by prayer */ if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) { Your("amulet vanishes!"); useup(uamul); } break; case FUMBLING: /* call this only when a move took place. */ /* otherwise handle fumbling msgs locally. */ if (u.umoved && !Levitation) { slip_or_trip(); nomul(-2); multi_reason = "fumbling"; nomovemsg = ""; /* The more you are carrying the more likely you * are to make noise when you fumble. Adjustments * to this number must be thoroughly play tested. */ if ((inv_weight() > -500)) { You("make a lot of noise!"); wake_nearby(); } } /* from outside means slippery ice; don't reset counter if that's the only fumble reason */ HFumbling &= ~FROMOUTSIDE; if (Fumbling) incr_itimeout(&HFumbling, rnd(20)); break; case DETECT_MONSTERS: see_monsters(); break; } } run_timers(); } void fall_asleep(how_long, wakeup_msg) int how_long; boolean wakeup_msg; { stop_occupation(); nomul(how_long); multi_reason = "sleeping"; /* generally don't notice sounds while sleeping */ if (wakeup_msg && multi == how_long) { /* caller can follow with a direct call to Hear_again() if there's a need to override this when wakeup_msg is true */ incr_itimeout(&HDeaf, how_long); afternmv = Hear_again; /* this won't give any messages */ } /* early wakeup from combat won't be possible until next monster turn */ u.usleep = monstermoves; nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again; } /* Attach an egg hatch timeout to the given egg. * when = Time to hatch, usually only passed if re-creating an * existing hatch timer. Pass 0L for random hatch time. */ void attach_egg_hatch_timeout(egg, when) struct obj *egg; long when; { int i; /* stop previous timer, if any */ (void) stop_timer(HATCH_EGG, obj_to_any(egg)); /* * Decide if and when to hatch the egg. The old hatch_it() code tried * once a turn from age 151 to 200 (inclusive), hatching if it rolled * a number x, 1<=x<=age, where x>150. This yields a chance of * hatching > 99.9993%. Mimic that here. */ if (!when) { for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++) if (rnd(i) > 150) { /* egg will hatch */ when = (long) i; break; } } if (when) { (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg)); } } /* prevent an egg from ever hatching */ void kill_egg(egg) struct obj *egg; { /* stop previous timer, if any */ (void) stop_timer(HATCH_EGG, obj_to_any(egg)); } /* timer callback routine: hatch the given egg */ void hatch_egg(arg, timeout) anything *arg; long timeout; { struct obj *egg; struct monst *mon, *mon2; coord cc; xchar x, y; boolean yours, silent, knows_egg = FALSE; boolean cansee_hatchspot = FALSE; int i, mnum, hatchcount = 0; egg = arg->a_obj; /* sterilized while waiting */ if (egg->corpsenm == NON_PM) return; mon = mon2 = (struct monst *) 0; mnum = big_to_little(egg->corpsenm); /* The identity of one's father is learned, not innate */ yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2))); silent = (timeout != monstermoves); /* hatched while away */ /* only can hatch when in INVENT, FLOOR, MINVENT */ if (get_obj_location(egg, &x, &y, 0)) { hatchcount = rnd((int) egg->quan); cansee_hatchspot = cansee(x, y) && !silent; if (!(mons[mnum].geno & G_UNIQ) && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) { for (i = hatchcount; i > 0; i--) { if (!enexto(&cc, x, y, &mons[mnum]) || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT))) break; /* tame if your own egg hatches while you're on the same dungeon level, or any dragon egg which hatches while it's in your inventory */ if ((yours && !silent) || (carried(egg) && mon->data->mlet == S_DRAGON)) { if (tamedog(mon, (struct obj *) 0)) { if (carried(egg) && mon->data->mlet != S_DRAGON) mon->mtame = 20; } } if (mvitals[mnum].mvflags & G_EXTINCT) break; /* just made last one */ mon2 = mon; /* in case makemon() fails on 2nd egg */ } if (!mon) mon = mon2; hatchcount -= i; egg->quan -= (long) hatchcount; } #if 0 /* * We could possibly hatch while migrating, but the code isn't * set up for it... */ } else if (obj->where == OBJ_MIGRATING) { /* * We can do several things. The first ones that come to * mind are: * + Create the hatched monster then place it on the migrating * mons list. This is tough because all makemon() is made * to place the monster as well. Makemon() also doesn't lend * itself well to splitting off a "not yet placed" subroutine. * + Mark the egg as hatched, then place the monster when we * place the migrating objects. * + Or just kill any egg which gets sent to another level. * Falling is the usual reason such transportation occurs. */ cansee_hatchspot = FALSE; mon = ???; #endif } if (mon) { char monnambuf[BUFSZ], carriedby[BUFSZ]; boolean siblings = (hatchcount > 1), redraw = FALSE; if (cansee_hatchspot) { Sprintf(monnambuf, "%s%s", siblings ? "some " : "", siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon))); /* we don't learn the egg type here because learning an egg type requires either seeing the egg hatch or being familiar with the egg already, as well as being able to see the resulting monster, checked below */ } switch (egg->where) { case OBJ_INVENT: knows_egg = TRUE; /* true even if you are blind */ if (!cansee_hatchspot) You_feel("%s %s from your pack!", something, locomotion(mon->data, "drop")); else You_see("%s %s out of your pack!", monnambuf, locomotion(mon->data, "drop")); if (yours) { pline("%s cries sound like \"%s%s\"", siblings ? "Their" : "Its", flags.female ? "mommy" : "daddy", egg->spe ? "." : "?"); } else if (mon->data->mlet == S_DRAGON && !Deaf) { verbalize("Gleep!"); /* Mything eggs :-) */ } break; case OBJ_FLOOR: if (cansee_hatchspot) { knows_egg = TRUE; You_see("%s hatch.", monnambuf); redraw = TRUE; /* update egg's map location */ } break; case OBJ_MINVENT: if (cansee_hatchspot) { /* egg carrying monster might be invisible */ if (canseemon(egg->ocarry)) { Sprintf(carriedby, "%s pack", s_suffix(a_monnam(egg->ocarry))); knows_egg = TRUE; } else if (is_pool(mon->mx, mon->my)) Strcpy(carriedby, "empty water"); else Strcpy(carriedby, "thin air"); You_see("%s %s out of %s!", monnambuf, locomotion(mon->data, "drop"), carriedby); } break; #if 0 case OBJ_MIGRATING: break; #endif default: impossible("egg hatched where? (%d)", (int) egg->where); break; } if (cansee_hatchspot && knows_egg) learn_egg_type(mnum); if (egg->quan > 0) { /* still some eggs left */ /* Instead of ordinary egg timeout use a short one */ attach_egg_hatch_timeout(egg, (long) rnd(12)); } else if (carried(egg)) { useup(egg); } else { /* free egg here because we use it above */ obj_extract_self(egg); obfree(egg, (struct obj *) 0); } if (redraw) newsym(x, y); } } /* Learn to recognize eggs of the given type. */ void learn_egg_type(mnum) int mnum; { /* baby monsters hatch from grown-up eggs */ mnum = little_to_big(mnum); mvitals[mnum].mvflags |= MV_KNOWS_EGG; /* we might have just learned about other eggs being carried */ update_inventory(); } /* Attach a fig_transform timeout to the given figurine. */ void attach_fig_transform_timeout(figurine) struct obj *figurine; { int i; /* stop previous timer, if any */ (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine)); /* * Decide when to transform the figurine. */ i = rnd(9000) + 200; /* figurine will transform */ (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM, obj_to_any(figurine)); } /* give a fumble message */ STATIC_OVL void slip_or_trip() { struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2; const char *what; char buf[BUFSZ]; boolean on_foot = TRUE; if (u.usteed) on_foot = FALSE; if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0; if (otmp && on_foot) { /* trip over something in particular */ /* If there is only one item, it will have just been named during the move, so refer to by via pronoun; otherwise, if the top item has been or can be seen, refer to it by name; if not, look for rocks to trip over; trip over anonymous "something" if there aren't any rocks. */ what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE) ? ((otmp->quan == 1L) ? "it" : Hallucination ? "they" : "them") : (otmp->dknown || !Blind) ? doname(otmp) : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0 ? something : (otmp2->quan == 1L ? "a rock" : "some rocks")); if (Hallucination) { what = strcpy(buf, what); buf[0] = highc(buf[0]); pline("Egads! %s bite%s your %s!", what, (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT)); } else { You("trip over %s.", what); } if (!uarmf && otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) { Sprintf(killer.name, "tripping over %s corpse", an(mons[otmp->corpsenm].mname)); instapetrify(killer.name); } } else if (rn2(3) && is_ice(u.ux, u.uy)) { pline("%s %s%s on the ice.", u.usteed ? upstart(x_monnam(u.usteed, (has_mname(u.usteed)) ? ARTICLE_NONE : ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE)) : "You", rn2(2) ? "slip" : "slide", on_foot ? "" : "s"); } else { if (on_foot) { switch (rn2(4)) { case 1: You("trip over your own %s.", Hallucination ? "elbow" : makeplural(body_part(FOOT))); break; case 2: You("slip %s.", Hallucination ? "on a banana peel" : "and nearly fall"); break; case 3: You("flounder."); break; default: You("stumble."); break; } } else { switch (rn2(4)) { case 1: Your("%s slip out of the stirrups.", makeplural(body_part(FOOT))); break; case 2: You("let go of the reins."); break; case 3: You("bang into the saddle-horn."); break; default: You("slide to one side of the saddle."); break; } dismount_steed(DISMOUNT_FELL); } } } /* Print a lamp flicker message with tailer. */ STATIC_OVL void see_lamp_flicker(obj, tailer) struct obj *obj; const char *tailer; { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s flickers%s.", Yname2(obj), tailer); break; case OBJ_FLOOR: You_see("%s flicker%s.", an(xname(obj)), tailer); break; } } /* Print a dimming message for brass lanterns. */ STATIC_OVL void lantern_message(obj) struct obj *obj; { /* from adventure */ switch (obj->where) { case OBJ_INVENT: Your("lantern is getting dim."); if (Hallucination) pline("Batteries have not been invented yet."); break; case OBJ_FLOOR: You_see("a lantern getting dim."); break; case OBJ_MINVENT: pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry))); break; } } /* * Timeout callback for for objects that are burning. E.g. lamps, candles. * See begin_burn() for meanings of obj->age and obj->spe. */ void burn_object(arg, timeout) anything *arg; long timeout; { struct obj *obj = arg->a_obj; boolean canseeit, many, menorah, need_newsym; xchar x, y; char whose[BUFSZ]; menorah = obj->otyp == CANDELABRUM_OF_INVOCATION; many = menorah ? obj->spe > 1 : obj->quan > 1L; /* timeout while away */ if (timeout != monstermoves) { long how_long = monstermoves - timeout; if (how_long >= obj->age) { obj->age = 0; end_burn(obj, FALSE); if (menorah) { obj->spe = 0; /* no more candles */ } else if (Is_candle(obj) || obj->otyp == POT_OIL) { /* get rid of candles and burning oil potions; we know this object isn't carried by hero, nor is it migrating */ obj_extract_self(obj); obfree(obj, (struct obj *) 0); obj = (struct obj *) 0; } } else { obj->age -= how_long; begin_burn(obj, TRUE); } return; } /* only interested in INVENT, FLOOR, and MINVENT */ if (get_obj_location(obj, &x, &y, 0)) { canseeit = !Blind && cansee(x, y); /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */ (void) Shk_Your(whose, obj); } else { canseeit = FALSE; } need_newsym = FALSE; /* obj->age is the age remaining at this point. */ switch (obj->otyp) { case POT_OIL: /* this should only be called when we run out */ if (canseeit) { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%spotion of oil has burnt away.", whose); break; case OBJ_FLOOR: You_see("a burning potion of oil go out."); need_newsym = TRUE; break; } } end_burn(obj, FALSE); /* turn off light source */ if (carried(obj)) { useupall(obj); } else { /* clear migrating obj's destination code before obfree to avoid false complaint of deleting worn item */ if (obj->where == OBJ_MIGRATING) obj->owornmask = 0L; obj_extract_self(obj); obfree(obj, (struct obj *) 0); } obj = (struct obj *) 0; break; case BRASS_LANTERN: case OIL_LAMP: switch ((int) obj->age) { case 150: case 100: case 50: if (canseeit) { if (obj->otyp == BRASS_LANTERN) lantern_message(obj); else see_lamp_flicker(obj, obj->age == 50L ? " considerably" : ""); } break; case 25: if (canseeit) { if (obj->otyp == BRASS_LANTERN) lantern_message(obj); else { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s seems about to go out.", Yname2(obj)); break; case OBJ_FLOOR: You_see("%s about to go out.", an(xname(obj))); break; } } } break; case 0: /* even if blind you'll know if holding it */ if (canseeit || obj->where == OBJ_INVENT) { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: if (obj->otyp == BRASS_LANTERN) pline("%slantern has run out of power.", whose); else pline("%s has gone out.", Yname2(obj)); break; case OBJ_FLOOR: if (obj->otyp == BRASS_LANTERN) You_see("a lantern run out of power."); else You_see("%s go out.", an(xname(obj))); break; } } end_burn(obj, FALSE); break; default: /* * Someone added fuel to the lamp while it was * lit. Just fall through and let begin burn * handle the new age. */ break; } if (obj->age) begin_burn(obj, TRUE); break; case CANDELABRUM_OF_INVOCATION: case TALLOW_CANDLE: case WAX_CANDLE: switch (obj->age) { case 75: if (canseeit) switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s%scandle%s getting short.", whose, menorah ? "candelabrum's " : "", many ? "s are" : " is"); break; case OBJ_FLOOR: You_see("%scandle%s getting short.", menorah ? "a candelabrum's " : many ? "some " : "a ", many ? "s" : ""); break; } break; case 15: if (canseeit) switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s%scandle%s flame%s flicker%s low!", whose, menorah ? "candelabrum's " : "", many ? "s'" : "'s", many ? "s" : "", many ? "" : "s"); break; case OBJ_FLOOR: You_see("%scandle%s flame%s flicker low!", menorah ? "a candelabrum's " : many ? "some " : "a ", many ? "s'" : "'s", many ? "s" : ""); break; } break; case 0: /* we know even if blind and in our inventory */ if (canseeit || obj->where == OBJ_INVENT) { if (menorah) { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%scandelabrum's flame%s.", whose, many ? "s die" : " dies"); break; case OBJ_FLOOR: You_see("a candelabrum's flame%s die.", many ? "s" : ""); break; } } else { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s %s consumed!", Yname2(obj), many ? "are" : "is"); break; case OBJ_FLOOR: /* You see some wax candles consumed! You see a wax candle consumed! */ You_see("%s%s consumed!", many ? "some " : "", many ? xname(obj) : an(xname(obj))); need_newsym = TRUE; break; } /* post message */ pline(Hallucination ? (many ? "They shriek!" : "It shrieks!") : Blind ? "" : (many ? "Their flames die." : "Its flame dies.")); } } end_burn(obj, FALSE); if (menorah) { obj->spe = 0; } else { if (carried(obj)) { useupall(obj); } else { /* clear migrating obj's destination code so obfree won't think this item is worn */ if (obj->where == OBJ_MIGRATING) obj->owornmask = 0L; obj_extract_self(obj); obfree(obj, (struct obj *) 0); } obj = (struct obj *) 0; } break; default: /* * Someone added fuel (candles) to the menorah while * it was lit. Just fall through and let begin burn * handle the new age. */ break; } if (obj && obj->age) begin_burn(obj, TRUE); break; default: impossible("burn_object: unexpeced obj %s", xname(obj)); break; } if (need_newsym) newsym(x, y); } /* * Start a burn timeout on the given object. If not "already lit" then * create a light source for the vision system. There had better not * be a burn already running on the object. * * Magic lamps stay lit as long as there's a genie inside, so don't start * a timer. * * Burn rules: * potions of oil, lamps & candles: * age = # of turns of fuel left * spe = * magic lamps: * age = * spe = 0 not lightable, 1 lightable forever * candelabrum: * age = # of turns of fuel left * spe = # of candles * * Once the burn begins, the age will be set to the amount of fuel * remaining _once_the_burn_finishes_. If the burn is terminated * early then fuel is added back. * * This use of age differs from the use of age for corpses and eggs. * For the latter items, age is when the object was created, so we * know when it becomes "bad". * * This is a "silent" routine - it should not print anything out. */ void begin_burn(obj, already_lit) struct obj *obj; boolean already_lit; { int radius = 3; long turns = 0; boolean do_timer = TRUE; if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj)) return; switch (obj->otyp) { case MAGIC_LAMP: obj->lamplit = 1; do_timer = FALSE; break; case POT_OIL: turns = obj->age; radius = 1; /* very dim light */ break; case BRASS_LANTERN: case OIL_LAMP: /* magic times are 150, 100, 50, 25, and 0 */ if (obj->age > 150L) turns = obj->age - 150L; else if (obj->age > 100L) turns = obj->age - 100L; else if (obj->age > 50L) turns = obj->age - 50L; else if (obj->age > 25L) turns = obj->age - 25L; else turns = obj->age; break; case CANDELABRUM_OF_INVOCATION: case TALLOW_CANDLE: case WAX_CANDLE: /* magic times are 75, 15, and 0 */ if (obj->age > 75L) turns = obj->age - 75L; else if (obj->age > 15L) turns = obj->age - 15L; else turns = obj->age; radius = candle_light_range(obj); break; default: /* [ALI] Support artifact light sources */ if (artifact_light(obj)) { obj->lamplit = 1; do_timer = FALSE; radius = arti_light_radius(obj); } else { impossible("begin burn: unexpected %s", xname(obj)); turns = obj->age; } break; } if (do_timer) { if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) { obj->lamplit = 1; obj->age -= turns; if (carried(obj) && !already_lit) update_inventory(); } else { obj->lamplit = 0; } } else { if (carried(obj) && !already_lit) update_inventory(); } if (obj->lamplit && !already_lit) { xchar x, y; if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO)) new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj)); else impossible("begin_burn: can't get obj position"); } } /* * Stop a burn timeout on the given object if timer attached. Darken * light source. */ void end_burn(obj, timer_attached) struct obj *obj; boolean timer_attached; { if (!obj->lamplit) { impossible("end_burn: obj %s not lit", xname(obj)); return; } if (obj->otyp == MAGIC_LAMP || artifact_light(obj)) timer_attached = FALSE; if (!timer_attached) { /* [DS] Cleanup explicitly, since timer cleanup won't happen */ del_light_source(LS_OBJECT, obj_to_any(obj)); obj->lamplit = 0; if (obj->where == OBJ_INVENT) update_inventory(); } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj))) impossible("end_burn: obj %s not timed!", xname(obj)); } /* * Cleanup a burning object if timer stopped. */ static void cleanup_burn(arg, expire_time) anything *arg; long expire_time; { struct obj *obj = arg->a_obj; if (!obj->lamplit) { impossible("cleanup_burn: obj %s not lit", xname(obj)); return; } del_light_source(LS_OBJECT, obj_to_any(obj)); /* restore unused time */ obj->age += expire_time - monstermoves; obj->lamplit = 0; if (obj->where == OBJ_INVENT) update_inventory(); } void do_storms() { int nstrike; register int x, y; int dirx, diry; int count; /* no lightning if not the air level or too often, even then */ if (!Is_airlevel(&u.uz) || rn2(8)) return; /* the number of strikes is 8-log2(nstrike) */ for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) { count = 0; do { x = rnd(COLNO - 1); y = rn2(ROWNO); } while (++count < 100 && levl[x][y].typ != CLOUD); if (count < 100) { dirx = rn2(3) - 1; diry = rn2(3) - 1; if (dirx != 0 || diry != 0) buzz(-15, /* "monster" LIGHTNING spell */ 8, x, y, dirx, diry); } } if (levl[u.ux][u.uy].typ == CLOUD) { /* Inside a cloud during a thunder storm is deafening. */ /* Even if already deaf, we sense the thunder's vibrations. */ pline("Kaboom!!! Boom!! Boom!!"); incr_itimeout(&HDeaf, rn1(20, 30)); if (!u.uinvulnerable) { stop_occupation(); nomul(-3); multi_reason = "hiding from thunderstorm"; nomovemsg = 0; } } else You_hear("a rumbling noise."); } /* ------------------------------------------------------------------------- */ /* * Generic Timeout Functions. * * Interface: * * General: * boolean start_timer(long timeout,short kind,short func_index, * anything *arg) * Start a timer of kind 'kind' that will expire at time * monstermoves+'timeout'. Call the function at 'func_index' * in the timeout table using argument 'arg'. Return TRUE if * a timer was started. This places the timer on a list ordered * "sooner" to "later". If an object, increment the object's * timer count. * * long stop_timer(short func_index, anything *arg) * Stop a timer specified by the (func_index, arg) pair. This * assumes that such a pair is unique. Return the time the * timer would have gone off. If no timer is found, return 0. * If an object, decrement the object's timer count. * * long peek_timer(short func_index, anything *arg) * Return time specified timer will go off (0 if no such timer). * * void run_timers(void) * Call timers that have timed out. * * Save/Restore: * void save_timers(int fd, int mode, int range) * Save all timers of range 'range'. Range is either global * or local. Global timers follow game play, local timers * are saved with a level. Object and monster timers are * saved using their respective id's instead of pointers. * * void restore_timers(int fd, int range, boolean ghostly, long adjust) * Restore timers of range 'range'. If from a ghost pile, * adjust the timeout by 'adjust'. The object and monster * ids are not restored until later. * * void relink_timers(boolean ghostly) * Relink all object and monster timers that had been saved * using their object's or monster's id number. * * Object Specific: * void obj_move_timers(struct obj *src, struct obj *dest) * Reassign all timers from src to dest. * * void obj_split_timers(struct obj *src, struct obj *dest) * Duplicate all timers assigned to src and attach them to dest. * * void obj_stop_timers(struct obj *obj) * Stop all timers attached to obj. * * boolean obj_has_timer(struct obj *object, short timer_type) * Check whether object has a timer of type timer_type. */ STATIC_DCL const char *FDECL(kind_name, (SHORT_P)); STATIC_DCL void FDECL(print_queue, (winid, timer_element *)); STATIC_DCL void FDECL(insert_timer, (timer_element *)); STATIC_DCL timer_element *FDECL(remove_timer, (timer_element **, SHORT_P, ANY_P *)); STATIC_DCL void FDECL(write_timer, (int, timer_element *)); STATIC_DCL boolean FDECL(mon_is_local, (struct monst *)); STATIC_DCL boolean FDECL(timer_is_local, (timer_element *)); STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P)); /* ordered timer list */ static timer_element *timer_base; /* "active" */ static unsigned long timer_id = 1; /* If defined, then include names when printing out the timer queue */ #define VERBOSE_TIMER typedef struct { timeout_proc f, cleanup; #ifdef VERBOSE_TIMER const char *name; #define TTAB(a, b, c) \ { \ a, b, c \ } #else #define TTAB(a, b, c) \ { \ a, b \ } #endif } ttable; /* table of timeout functions */ static const ttable timeout_funcs[NUM_TIME_FUNCS] = { TTAB(rot_organic, (timeout_proc) 0, "rot_organic"), TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"), TTAB(revive_mon, (timeout_proc) 0, "revive_mon"), TTAB(burn_object, cleanup_burn, "burn_object"), TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"), TTAB(fig_transform, (timeout_proc) 0, "fig_transform"), TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away") }; #undef TTAB STATIC_OVL const char * kind_name(kind) short kind; { switch (kind) { case TIMER_LEVEL: return "level"; case TIMER_GLOBAL: return "global"; case TIMER_OBJECT: return "object"; case TIMER_MONSTER: return "monster"; } return "unknown"; } STATIC_OVL void print_queue(win, base) winid win; timer_element *base; { timer_element *curr; char buf[BUFSZ]; if (!base) { putstr(win, 0, ""); } else { putstr(win, 0, "timeout id kind call"); for (curr = base; curr; curr = curr->next) { #ifdef VERBOSE_TIMER Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout, curr->tid, kind_name(curr->kind), timeout_funcs[curr->func_index].name, fmt_ptr((genericptr_t) curr->arg.a_void)); #else Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout, curr->tid, kind_name(curr->kind), curr->func_index, fmt_ptr((genericptr_t) curr->arg.a_void)); #endif putstr(win, 0, buf); } } } int wiz_timeout_queue() { winid win; char buf[BUFSZ]; win = create_nhwindow(NHW_MENU); /* corner text window */ if (win == WIN_ERR) return 0; Sprintf(buf, "Current time = %ld.", monstermoves); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, "Active timeout queue:"); putstr(win, 0, ""); print_queue(win, timer_base); display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } void timer_sanity_check() { timer_element *curr; /* this should be much more complete */ for (curr = timer_base; curr; curr = curr->next) if (curr->kind == TIMER_OBJECT) { struct obj *obj = curr->arg.a_obj; if (obj->timed == 0) { pline("timer sanity: untimed obj %s, timer %ld", fmt_ptr((genericptr_t) obj), curr->tid); } } } /* * Pick off timeout elements from the global queue and call their functions. * Do this until their time is less than or equal to the move count. */ void run_timers() { timer_element *curr; /* * Always use the first element. Elements may be added or deleted at * any time. The list is ordered, we are done when the first element * is in the future. */ while (timer_base && timer_base->timeout <= monstermoves) { curr = timer_base; timer_base = curr->next; if (curr->kind == TIMER_OBJECT) (curr->arg.a_obj)->timed--; (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout); free((genericptr_t) curr); } } /* * Start a timer. Return TRUE if successful. */ boolean start_timer(when, kind, func_index, arg) long when; short kind; short func_index; anything *arg; { timer_element *gnu; if (func_index < 0 || func_index >= NUM_TIME_FUNCS) panic("start_timer"); gnu = (timer_element *) alloc(sizeof(timer_element)); gnu->next = 0; gnu->tid = timer_id++; gnu->timeout = monstermoves + when; gnu->kind = kind; gnu->needs_fixup = 0; gnu->func_index = func_index; gnu->arg = *arg; insert_timer(gnu); if (kind == TIMER_OBJECT) /* increment object's timed count */ (arg->a_obj)->timed++; /* should check for duplicates and fail if any */ return TRUE; } /* * Remove the timer from the current list and free it up. Return the time * remaining until it would have gone off, 0 if not found. */ long stop_timer(func_index, arg) short func_index; anything *arg; { timer_element *doomed; long timeout; doomed = remove_timer(&timer_base, func_index, arg); if (doomed) { timeout = doomed->timeout; if (doomed->kind == TIMER_OBJECT) (arg->a_obj)->timed--; if (timeout_funcs[doomed->func_index].cleanup) (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout); free((genericptr_t) doomed); return (timeout - monstermoves); } return 0L; } /* * Find the timeout of specified timer; return 0 if none. */ long peek_timer(type, arg) short type; anything *arg; { timer_element *curr; for (curr = timer_base; curr; curr = curr->next) { if (curr->func_index == type && curr->arg.a_void == arg->a_void) return curr->timeout; } return 0L; } /* * Move all object timers from src to dest, leaving src untimed. */ void obj_move_timers(src, dest) struct obj *src, *dest; { int count; timer_element *curr; for (count = 0, curr = timer_base; curr; curr = curr->next) if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) { curr->arg.a_obj = dest; dest->timed++; count++; } if (count != src->timed) panic("obj_move_timers"); src->timed = 0; } /* * Find all object timers and duplicate them for the new object "dest". */ void obj_split_timers(src, dest) struct obj *src, *dest; { timer_element *curr, *next_timer = 0; for (curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; /* things may be inserted */ if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) { (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT, curr->func_index, obj_to_any(dest)); } } } /* * Stop all timers attached to this object. We can get away with this because * all object pointers are unique. */ void obj_stop_timers(obj) struct obj *obj; { timer_element *curr, *prev, *next_timer = 0; for (prev = 0, curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) { if (prev) prev->next = curr->next; else timer_base = curr->next; if (timeout_funcs[curr->func_index].cleanup) (*timeout_funcs[curr->func_index].cleanup)(&curr->arg, curr->timeout); free((genericptr_t) curr); } else { prev = curr; } } obj->timed = 0; } /* * Check whether object has a timer of type timer_type. */ boolean obj_has_timer(object, timer_type) struct obj *object; short timer_type; { long timeout = peek_timer(timer_type, obj_to_any(object)); return (boolean) (timeout != 0L); } /* * Stop all timers of index func_index at this spot. * */ void spot_stop_timers(x, y, func_index) xchar x, y; short func_index; { timer_element *curr, *prev, *next_timer = 0; long where = (((long) x << 16) | ((long) y)); for (prev = 0, curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; if (curr->kind == TIMER_LEVEL && curr->func_index == func_index && curr->arg.a_long == where) { if (prev) prev->next = curr->next; else timer_base = curr->next; if (timeout_funcs[curr->func_index].cleanup) (*timeout_funcs[curr->func_index].cleanup)(&curr->arg, curr->timeout); free((genericptr_t) curr); } else { prev = curr; } } } /* * When is the spot timer of type func_index going to expire? * Returns 0L if no such timer. */ long spot_time_expires(x, y, func_index) xchar x, y; short func_index; { timer_element *curr; long where = (((long) x << 16) | ((long) y)); for (curr = timer_base; curr; curr = curr->next) { if (curr->kind == TIMER_LEVEL && curr->func_index == func_index && curr->arg.a_long == where) return curr->timeout; } return 0L; } long spot_time_left(x, y, func_index) xchar x, y; short func_index; { long expires = spot_time_expires(x, y, func_index); return (expires > 0L) ? expires - monstermoves : 0L; } /* Insert timer into the global queue */ STATIC_OVL void insert_timer(gnu) timer_element *gnu; { timer_element *curr, *prev; for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next) if (curr->timeout >= gnu->timeout) break; gnu->next = curr; if (prev) prev->next = gnu; else timer_base = gnu; } STATIC_OVL timer_element * remove_timer(base, func_index, arg) timer_element **base; short func_index; anything *arg; { timer_element *prev, *curr; for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next) if (curr->func_index == func_index && curr->arg.a_void == arg->a_void) break; if (curr) { if (prev) prev->next = curr->next; else *base = curr->next; } return curr; } STATIC_OVL void write_timer(fd, timer) int fd; timer_element *timer; { anything arg_save; arg_save = zeroany; switch (timer->kind) { case TIMER_GLOBAL: case TIMER_LEVEL: /* assume no pointers in arg */ bwrite(fd, (genericptr_t) timer, sizeof(timer_element)); break; case TIMER_OBJECT: if (timer->needs_fixup) bwrite(fd, (genericptr_t) timer, sizeof(timer_element)); else { /* replace object pointer with id */ arg_save.a_obj = timer->arg.a_obj; timer->arg = zeroany; timer->arg.a_uint = (arg_save.a_obj)->o_id; timer->needs_fixup = 1; bwrite(fd, (genericptr_t) timer, sizeof(timer_element)); timer->arg.a_obj = arg_save.a_obj; timer->needs_fixup = 0; } break; case TIMER_MONSTER: if (timer->needs_fixup) bwrite(fd, (genericptr_t) timer, sizeof(timer_element)); else { /* replace monster pointer with id */ arg_save.a_monst = timer->arg.a_monst; timer->arg = zeroany; timer->arg.a_uint = (arg_save.a_monst)->m_id; timer->needs_fixup = 1; bwrite(fd, (genericptr_t) timer, sizeof(timer_element)); timer->arg.a_monst = arg_save.a_monst; timer->needs_fixup = 0; } break; default: panic("write_timer"); break; } } /* * Return TRUE if the object will stay on the level when the level is * saved. */ boolean obj_is_local(obj) struct obj *obj; { switch (obj->where) { case OBJ_INVENT: case OBJ_MIGRATING: return FALSE; case OBJ_FLOOR: case OBJ_BURIED: return TRUE; case OBJ_CONTAINED: return obj_is_local(obj->ocontainer); case OBJ_MINVENT: return mon_is_local(obj->ocarry); } panic("obj_is_local"); return FALSE; } /* * Return TRUE if the given monster will stay on the level when the * level is saved. */ STATIC_OVL boolean mon_is_local(mon) struct monst *mon; { struct monst *curr; for (curr = migrating_mons; curr; curr = curr->nmon) if (curr == mon) return FALSE; /* `mydogs' is used during level changes, never saved and restored */ for (curr = mydogs; curr; curr = curr->nmon) if (curr == mon) return FALSE; return TRUE; } /* * Return TRUE if the timer is attached to something that will stay on the * level when the level is saved. */ STATIC_OVL boolean timer_is_local(timer) timer_element *timer; { switch (timer->kind) { case TIMER_LEVEL: return TRUE; case TIMER_GLOBAL: return FALSE; case TIMER_OBJECT: return obj_is_local(timer->arg.a_obj); case TIMER_MONSTER: return mon_is_local(timer->arg.a_monst); } panic("timer_is_local"); return FALSE; } /* * Part of the save routine. Count up the number of timers that would * be written. If write_it is true, actually write the timer. */ STATIC_OVL int maybe_write_timer(fd, range, write_it) int fd, range; boolean write_it; { int count = 0; timer_element *curr; for (curr = timer_base; curr; curr = curr->next) { if (range == RANGE_GLOBAL) { /* global timers */ if (!timer_is_local(curr)) { count++; if (write_it) write_timer(fd, curr); } } else { /* local timers */ if (timer_is_local(curr)) { count++; if (write_it) write_timer(fd, curr); } } } return count; } /* * Save part of the timer list. The parameter 'range' specifies either * global or level timers to save. The timer ID is saved with the global * timers. * * Global range: * + timeouts that follow the hero (global) * + timeouts that follow obj & monst that are migrating * * Level range: * + timeouts that are level specific (e.g. storms) * + timeouts that stay with the level (obj & monst) */ void save_timers(fd, mode, range) int fd, mode, range; { timer_element *curr, *prev, *next_timer = 0; int count; if (perform_bwrite(mode)) { if (range == RANGE_GLOBAL) bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id)); count = maybe_write_timer(fd, range, FALSE); bwrite(fd, (genericptr_t) &count, sizeof count); (void) maybe_write_timer(fd, range, TRUE); } if (release_data(mode)) { for (prev = 0, curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; /* in case curr is removed */ if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) { if (prev) prev->next = curr->next; else timer_base = curr->next; free((genericptr_t) curr); /* prev stays the same */ } else { prev = curr; } } } } /* * Pull in the structures from disk, but don't recalculate the object and * monster pointers. */ void restore_timers(fd, range, ghostly, adjust) int fd, range; boolean ghostly; /* restoring from a ghost level */ long adjust; /* how much to adjust timeout */ { int count; timer_element *curr; if (range == RANGE_GLOBAL) mread(fd, (genericptr_t) &timer_id, sizeof timer_id); /* restore elements */ mread(fd, (genericptr_t) &count, sizeof count); while (count-- > 0) { curr = (timer_element *) alloc(sizeof(timer_element)); mread(fd, (genericptr_t) curr, sizeof(timer_element)); if (ghostly) curr->timeout += adjust; insert_timer(curr); } } /* reset all timers that are marked for reseting */ void relink_timers(ghostly) boolean ghostly; { timer_element *curr; unsigned nid; for (curr = timer_base; curr; curr = curr->next) { if (curr->needs_fixup) { if (curr->kind == TIMER_OBJECT) { if (ghostly) { if (!lookup_id_mapping(curr->arg.a_uint, &nid)) panic("relink_timers 1"); } else nid = curr->arg.a_uint; curr->arg.a_obj = find_oid(nid); if (!curr->arg.a_obj) panic("cant find o_id %d", nid); curr->needs_fixup = 0; } else if (curr->kind == TIMER_MONSTER) { panic("relink_timers: no monster timer implemented"); } else panic("relink_timers 2"); } } } /*timeout.c*/ nethack-3.6.0/src/topten.c0000664000076400007660000010717512624166366014430 0ustar paxedpaxed/* NetHack 3.6 topten.c $NHDT-Date: 1448117546 2015/11/21 14:52:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef VMS /* We don't want to rewrite the whole file, because that entails creating a new version which requires that the old one be deletable. */ #define UPDATE_RECORD_IN_PLACE #endif /* * Updating in place can leave junk at the end of the file in some * circumstances (if it shrinks and the O.S. doesn't have a straightforward * way to truncate it). The trailing junk is harmless and the code * which reads the scores will ignore it. */ #ifdef UPDATE_RECORD_IN_PLACE static long final_fpos; #endif #define done_stopprint program_state.stopprint #define newttentry() (struct toptenentry *) alloc(sizeof (struct toptenentry)) #define dealloc_ttentry(ttent) free((genericptr_t) (ttent)) #define NAMSZ 10 #define DTHSZ 100 #define ROLESZ 3 struct toptenentry { struct toptenentry *tt_next; #ifdef UPDATE_RECORD_IN_PLACE long fpos; #endif long points; int deathdnum, deathlev; int maxlvl, hp, maxhp, deaths; int ver_major, ver_minor, patchlevel; long deathdate, birthdate; int uid; char plrole[ROLESZ + 1]; char plrace[ROLESZ + 1]; char plgend[ROLESZ + 1]; char plalign[ROLESZ + 1]; char name[NAMSZ + 1]; char death[DTHSZ + 1]; } * tt_head; /* size big enough to read in all the string fields at once; includes room for separating space or trailing newline plus string terminator */ #define SCANBUFSZ (4 * (ROLESZ + 1) + (NAMSZ + 1) + (DTHSZ + 1) + 1) STATIC_DCL void FDECL(topten_print, (const char *)); STATIC_DCL void FDECL(topten_print_bold, (const char *)); STATIC_DCL xchar FDECL(observable_depth, (d_level *)); STATIC_DCL void NDECL(outheader); STATIC_DCL void FDECL(outentry, (int, struct toptenentry *, BOOLEAN_P)); STATIC_DCL void FDECL(discardexcess, (FILE *)); STATIC_DCL void FDECL(readentry, (FILE *, struct toptenentry *)); STATIC_DCL void FDECL(writeentry, (FILE *, struct toptenentry *)); STATIC_DCL void FDECL(writexlentry, (FILE *, struct toptenentry *)); STATIC_DCL long NDECL(encodexlogflags); STATIC_DCL long NDECL(encodeconduct); STATIC_DCL long NDECL(encodeachieve); STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *)); STATIC_DCL int FDECL(classmon, (char *, BOOLEAN_P)); STATIC_DCL int FDECL(score_wanted, (BOOLEAN_P, int, struct toptenentry *, int, const char **, int)); #ifdef NO_SCAN_BRACK STATIC_DCL void FDECL(nsb_mung_line, (char *)); STATIC_DCL void FDECL(nsb_unmung_line, (char *)); #endif static winid toptenwin = WIN_ERR; /* "killed by",&c ["an"] 'killer.name' */ void formatkiller(buf, siz, how) char *buf; unsigned siz; int how; { static NEARDATA const char *const killed_by_prefix[] = { /* DIED, CHOKING, POISONING, STARVING, */ "killed by ", "choked on ", "poisoned by ", "died of ", /* DROWNING, BURNING, DISSOLVED, CRUSHING, */ "drowned in ", "burned by ", "dissolved in ", "crushed to death by ", /* STONING, TURNED_SLIME, GENOCIDED, */ "petrified by ", "turned to slime by ", "killed by ", /* PANICKED, TRICKED, QUIT, ESCAPED, ASCENDED */ "", "", "", "", "" }; unsigned l; char *kname = killer.name; buf[0] = '\0'; /* so strncat() can find the end */ switch (killer.format) { default: impossible("bad killer format? (%d)", killer.format); /*FALLTHRU*/ case NO_KILLER_PREFIX: break; case KILLED_BY_AN: kname = an(kname); /*FALLTHRU*/ case KILLED_BY: (void) strncat(buf, killed_by_prefix[how], siz - 1); l = strlen(buf); buf += l, siz -= l; break; } /* we're writing into buf[0] (after possibly advancing buf) rather than appending, but strncat() appends a terminator and strncpy() doesn't */ (void) strncat(buf, kname, siz - 1); } STATIC_OVL void topten_print(x) const char *x; { if (toptenwin == WIN_ERR) raw_print(x); else putstr(toptenwin, ATR_NONE, x); } STATIC_OVL void topten_print_bold(x) const char *x; { if (toptenwin == WIN_ERR) raw_print_bold(x); else putstr(toptenwin, ATR_BOLD, x); } STATIC_OVL xchar observable_depth(lev) d_level *lev; { #if 0 /* if we ever randomize the order of the elemental planes, we must use a constant external representation in the record file */ if (In_endgame(lev)) { if (Is_astralevel(lev)) return -5; else if (Is_waterlevel(lev)) return -4; else if (Is_firelevel(lev)) return -3; else if (Is_airlevel(lev)) return -2; else if (Is_earthlevel(lev)) return -1; else return 0; /* ? */ } else #endif return depth(lev); } /* throw away characters until current record has been entirely consumed */ STATIC_OVL void discardexcess(rfile) FILE *rfile; { int c; do { c = fgetc(rfile); } while (c != '\n' && c != EOF); } STATIC_OVL void readentry(rfile, tt) FILE *rfile; struct toptenentry *tt; { char inbuf[SCANBUFSZ], s1[SCANBUFSZ], s2[SCANBUFSZ], s3[SCANBUFSZ], s4[SCANBUFSZ], s5[SCANBUFSZ], s6[SCANBUFSZ]; #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */ static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c"; static const char fmt32[] = "%c%c %s %s%*c"; static const char fmt33[] = "%s %s %s %s %s %s%*c"; #else static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d "; static const char fmt32[] = "%c%c %[^,],%[^\n]%*c"; static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c"; #endif #ifdef UPDATE_RECORD_IN_PLACE /* note: input below must read the record's terminating newline */ final_fpos = tt->fpos = ftell(rfile); #endif #define TTFIELDS 13 if (fscanf(rfile, fmt, &tt->ver_major, &tt->ver_minor, &tt->patchlevel, &tt->points, &tt->deathdnum, &tt->deathlev, &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths, &tt->deathdate, &tt->birthdate, &tt->uid) != TTFIELDS) { #undef TTFIELDS tt->points = 0; discardexcess(rfile); } else { /* load remainder of record into a local buffer; this imposes an implicit length limit of SCANBUFSZ on every string field extracted from the buffer */ if (!fgets(inbuf, sizeof inbuf, rfile)) { /* sscanf will fail and tt->points will be set to 0 */ *inbuf = '\0'; } else if (!index(inbuf, '\n')) { Strcpy(&inbuf[sizeof inbuf - 2], "\n"); discardexcess(rfile); } /* Check for backwards compatibility */ if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3)) { int i; if (sscanf(inbuf, fmt32, tt->plrole, tt->plgend, s1, s2) == 4) { tt->plrole[1] = tt->plgend[1] = '\0'; /* read via %c */ copynchars(tt->name, s1, (int) (sizeof tt->name) - 1); copynchars(tt->death, s2, (int) (sizeof tt->death) - 1); } else tt->points = 0; tt->plrole[1] = '\0'; if ((i = str2role(tt->plrole)) >= 0) Strcpy(tt->plrole, roles[i].filecode); Strcpy(tt->plrace, "?"); Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem"); Strcpy(tt->plalign, "?"); } else if (sscanf(inbuf, fmt33, s1, s2, s3, s4, s5, s6) == 6) { copynchars(tt->plrole, s1, (int) (sizeof tt->plrole) - 1); copynchars(tt->plrace, s2, (int) (sizeof tt->plrace) - 1); copynchars(tt->plgend, s3, (int) (sizeof tt->plgend) - 1); copynchars(tt->plalign, s4, (int) (sizeof tt->plalign) - 1); copynchars(tt->name, s5, (int) (sizeof tt->name) - 1); copynchars(tt->death, s6, (int) (sizeof tt->death) - 1); } else tt->points = 0; #ifdef NO_SCAN_BRACK if (tt->points > 0) { nsb_unmung_line(tt->name); nsb_unmung_line(tt->death); } #endif } /* check old score entries for Y2K problem and fix whenever found */ if (tt->points > 0) { if (tt->birthdate < 19000000L) tt->birthdate += 19000000L; if (tt->deathdate < 19000000L) tt->deathdate += 19000000L; } } STATIC_OVL void writeentry(rfile, tt) FILE *rfile; struct toptenentry *tt; { static const char fmt32[] = "%c%c "; /* role,gender */ static const char fmt33[] = "%s %s %s %s "; /* role,race,gndr,algn */ #ifndef NO_SCAN_BRACK static const char fmt0[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d "; static const char fmtX[] = "%s,%s%s%s\n"; #else /* NO_SCAN_BRACK */ static const char fmt0[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d "; static const char fmtX[] = "%s %s%s%s\n"; nsb_mung_line(tt->name); nsb_mung_line(tt->death); #endif (void) fprintf(rfile, fmt0, tt->ver_major, tt->ver_minor, tt->patchlevel, tt->points, tt->deathdnum, tt->deathlev, tt->maxlvl, tt->hp, tt->maxhp, tt->deaths, tt->deathdate, tt->birthdate, tt->uid); if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3)) (void) fprintf(rfile, fmt32, tt->plrole[0], tt->plgend[0]); else (void) fprintf(rfile, fmt33, tt->plrole, tt->plrace, tt->plgend, tt->plalign); (void) fprintf(rfile, fmtX, onlyspace(tt->name) ? "_" : tt->name, tt->death, (multi ? ", while " : ""), (multi ? (multi_reason ? multi_reason : "helpless") : "")); #ifdef NO_SCAN_BRACK nsb_unmung_line(tt->name); nsb_unmung_line(tt->death); #endif } /* as tab is never used in eg. plname or death, no need to mangle those. */ STATIC_OVL void writexlentry(rfile, tt) FILE *rfile; struct toptenentry *tt; { #define Fprintf (void) fprintf #define XLOG_SEP '\t' /* xlogfile field separator. */ char buf[BUFSZ]; Sprintf(buf, "version=%d.%d.%d", tt->ver_major, tt->ver_minor, tt->patchlevel); Sprintf(eos(buf), "%cpoints=%ld%cdeathdnum=%d%cdeathlev=%d", XLOG_SEP, tt->points, XLOG_SEP, tt->deathdnum, XLOG_SEP, tt->deathlev); Sprintf(eos(buf), "%cmaxlvl=%d%chp=%d%cmaxhp=%d", XLOG_SEP, tt->maxlvl, XLOG_SEP, tt->hp, XLOG_SEP, tt->maxhp); Sprintf(eos(buf), "%cdeaths=%d%cdeathdate=%ld%cbirthdate=%ld%cuid=%d", XLOG_SEP, tt->deaths, XLOG_SEP, tt->deathdate, XLOG_SEP, tt->birthdate, XLOG_SEP, tt->uid); Fprintf(rfile, "%s", buf); Sprintf(buf, "%crole=%s%crace=%s%cgender=%s%calign=%s", XLOG_SEP, tt->plrole, XLOG_SEP, tt->plrace, XLOG_SEP, tt->plgend, XLOG_SEP, tt->plalign); Fprintf(rfile, "%s%cname=%s%cdeath=%s", buf, /* (already includes separator) */ XLOG_SEP, plname, XLOG_SEP, tt->death); if (multi) Fprintf(rfile, "%cwhile=%s", XLOG_SEP, multi_reason ? multi_reason : "helpless"); Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP, encodeconduct(), XLOG_SEP, moves, XLOG_SEP, encodeachieve()); Fprintf(rfile, "%crealtime=%ld%cstarttime=%ld%cendtime=%ld", XLOG_SEP, (long) urealtime.realtime, XLOG_SEP, (long) ubirthday, XLOG_SEP, (long) urealtime.endtime); Fprintf(rfile, "%cgender0=%s%calign0=%s", XLOG_SEP, genders[flags.initgend].filecode, XLOG_SEP, aligns[1 - u.ualignbase[A_ORIGINAL]].filecode); Fprintf(rfile, "%cflags=0x%lx", XLOG_SEP, encodexlogflags()); Fprintf(rfile, "\n"); #undef XLOG_SEP } STATIC_OVL long encodexlogflags() { long e = 0L; if (wizard) e |= 1L << 0; if (discover) e |= 1L << 1; if (!u.uroleplay.numbones) e |= 1L << 2; return e; } STATIC_OVL long encodeconduct() { long e = 0L; if (!u.uconduct.food) e |= 1L << 0; if (!u.uconduct.unvegan) e |= 1L << 1; if (!u.uconduct.unvegetarian) e |= 1L << 2; if (!u.uconduct.gnostic) e |= 1L << 3; if (!u.uconduct.weaphit) e |= 1L << 4; if (!u.uconduct.killer) e |= 1L << 5; if (!u.uconduct.literate) e |= 1L << 6; if (!u.uconduct.polypiles) e |= 1L << 7; if (!u.uconduct.polyselfs) e |= 1L << 8; if (!u.uconduct.wishes) e |= 1L << 9; if (!u.uconduct.wisharti) e |= 1L << 10; if (!num_genocides()) e |= 1L << 11; return e; } STATIC_OVL long encodeachieve() { long r = 0L; if (u.uachieve.bell) r |= 1L << 0; if (u.uachieve.enter_gehennom) r |= 1L << 1; if (u.uachieve.menorah) r |= 1L << 2; if (u.uachieve.book) r |= 1L << 3; if (u.uevent.invoked) r |= 1L << 4; if (u.uachieve.amulet) r |= 1L << 5; if (In_endgame(&u.uz)) r |= 1L << 6; if (Is_astralevel(&u.uz)) r |= 1L << 7; if (u.uachieve.ascended) r |= 1L << 8; if (u.uachieve.mines_luckstone) r |= 1L << 9; if (u.uachieve.finish_sokoban) r |= 1L << 10; if (u.uachieve.killed_medusa) r |= 1L << 11; if (u.uroleplay.blind) r |= 1L << 12; if (u.uroleplay.nudist) r |= 1L << 13; return r; } STATIC_OVL void free_ttlist(tt) struct toptenentry *tt; { struct toptenentry *ttnext; while (tt->points > 0) { ttnext = tt->tt_next; dealloc_ttentry(tt); tt = ttnext; } dealloc_ttentry(tt); } void topten(how, when) int how; time_t when; { int uid = getuid(); int rank, rank0 = -1, rank1 = 0; int occ_cnt = sysopt.persmax; register struct toptenentry *t0, *tprev; struct toptenentry *t1; FILE *rfile; register int flg = 0; boolean t0_used; #ifdef LOGFILE FILE *lfile; #endif /* LOGFILE */ #ifdef XLOGFILE FILE *xlfile; #endif /* XLOGFILE */ #ifdef _DCC /* Under DICE 3.0, this crashes the system consistently, apparently due to * corruption of *rfile somewhere. Until I figure this out, just cut out * topten support entirely - at least then the game exits cleanly. --AC */ return; #endif /* If we are in the midst of a panic, cut out topten entirely. * topten uses alloc() several times, which will lead to * problems if the panic was the result of an alloc() failure. */ if (program_state.panicking) return; if (iflags.toptenwin) { toptenwin = create_nhwindow(NHW_TEXT); } #if defined(UNIX) || defined(VMS) || defined(__EMX__) #define HUP if (!program_state.done_hup) #else #define HUP #endif #ifdef TOS restore_colors(); /* make sure the screen is black on white */ #endif /* create a new 'topten' entry */ t0_used = FALSE; t0 = newttentry(); t0->ver_major = VERSION_MAJOR; t0->ver_minor = VERSION_MINOR; t0->patchlevel = PATCHLEVEL; t0->points = u.urexp; t0->deathdnum = u.uz.dnum; /* deepest_lev_reached() is in terms of depth(), and reporting the * deepest level reached in the dungeon death occurred in doesn't * seem right, so we have to report the death level in depth() terms * as well (which also seems reasonable since that's all the player * sees on the screen anyway) */ t0->deathlev = observable_depth(&u.uz); t0->maxlvl = deepest_lev_reached(TRUE); t0->hp = u.uhp; t0->maxhp = u.uhpmax; t0->deaths = u.umortality; t0->uid = uid; copynchars(t0->plrole, urole.filecode, ROLESZ); copynchars(t0->plrace, urace.filecode, ROLESZ); copynchars(t0->plgend, genders[flags.female].filecode, ROLESZ); copynchars(t0->plalign, aligns[1 - u.ualign.type].filecode, ROLESZ); copynchars(t0->name, plname, NAMSZ); formatkiller(t0->death, sizeof t0->death, how); t0->birthdate = yyyymmdd(ubirthday); t0->deathdate = yyyymmdd(when); t0->tt_next = 0; urealtime.endtime = when; #ifdef UPDATE_RECORD_IN_PLACE t0->fpos = -1L; #endif #ifdef LOGFILE /* used for debugging (who dies of what, where) */ if (lock_file(LOGFILE, SCOREPREFIX, 10)) { if (!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) { HUP raw_print("Cannot open log file!"); } else { writeentry(lfile, t0); (void) fclose(lfile); } unlock_file(LOGFILE); } #endif /* LOGFILE */ #ifdef XLOGFILE if (lock_file(XLOGFILE, SCOREPREFIX, 10)) { if (!(xlfile = fopen_datafile(XLOGFILE, "a", SCOREPREFIX))) { HUP raw_print("Cannot open extended log file!"); } else { writexlentry(xlfile, t0); (void) fclose(xlfile); } unlock_file(XLOGFILE); } #endif /* XLOGFILE */ if (wizard || discover) { if (how != PANICKED) HUP { char pbuf[BUFSZ]; topten_print(""); Sprintf(pbuf, "Since you were in %s mode, the score list will not be checked.", wizard ? "wizard" : "discover"); topten_print(pbuf); } goto showwin; } if (!lock_file(RECORD, SCOREPREFIX, 60)) goto destroywin; #ifdef UPDATE_RECORD_IN_PLACE rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX); #else rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); #endif if (!rfile) { HUP raw_print("Cannot open record file!"); unlock_file(RECORD); goto destroywin; } HUP topten_print(""); /* assure minimum number of points */ if (t0->points < sysopt.pointsmin) t0->points = 0; t1 = tt_head = newttentry(); tprev = 0; /* rank0: -1 undefined, 0 not_on_list, n n_th on list */ for (rank = 1;;) { readentry(rfile, t1); if (t1->points < sysopt.pointsmin) t1->points = 0; if (rank0 < 0 && t1->points < t0->points) { rank0 = rank++; if (tprev == 0) tt_head = t0; else tprev->tt_next = t0; t0->tt_next = t1; #ifdef UPDATE_RECORD_IN_PLACE t0->fpos = t1->fpos; /* insert here */ #endif t0_used = TRUE; occ_cnt--; flg++; /* ask for a rewrite */ } else tprev = t1; if (t1->points == 0) break; if ((sysopt.pers_is_uid ? t1->uid == t0->uid : strncmp(t1->name, t0->name, NAMSZ) == 0) && !strncmp(t1->plrole, t0->plrole, ROLESZ) && --occ_cnt <= 0) { if (rank0 < 0) { rank0 = 0; rank1 = rank; HUP { char pbuf[BUFSZ]; Sprintf(pbuf, "You didn't beat your previous score of %ld points.", t1->points); topten_print(pbuf); topten_print(""); } } if (occ_cnt < 0) { flg++; continue; } } if (rank <= sysopt.entrymax) { t1->tt_next = newttentry(); t1 = t1->tt_next; rank++; } if (rank > sysopt.entrymax) { t1->points = 0; break; } } if (flg) { /* rewrite record file */ #ifdef UPDATE_RECORD_IN_PLACE (void) fseek(rfile, (t0->fpos >= 0 ? t0->fpos : final_fpos), SEEK_SET); #else (void) fclose(rfile); if (!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))) { HUP raw_print("Cannot write record file"); unlock_file(RECORD); free_ttlist(tt_head); goto destroywin; } #endif /* UPDATE_RECORD_IN_PLACE */ if (!done_stopprint) if (rank0 > 0) { if (rank0 <= 10) { topten_print("You made the top ten list!"); } else { char pbuf[BUFSZ]; Sprintf(pbuf, "You reached the %d%s place on the top %d list.", rank0, ordin(rank0), sysopt.entrymax); topten_print(pbuf); } topten_print(""); } } if (rank0 == 0) rank0 = rank1; if (rank0 <= 0) rank0 = rank; if (!done_stopprint) outheader(); t1 = tt_head; for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { if (flg #ifdef UPDATE_RECORD_IN_PLACE && rank >= rank0 #endif ) writeentry(rfile, t1); if (done_stopprint) continue; if (rank > flags.end_top && (rank < rank0 - flags.end_around || rank > rank0 + flags.end_around) && (!flags.end_own || (sysopt.pers_is_uid ? t1->uid == t0->uid : strncmp(t1->name, t0->name, NAMSZ) == 0))) continue; if (rank == rank0 - flags.end_around && rank0 > flags.end_top + flags.end_around + 1 && !flags.end_own) topten_print(""); if (rank != rank0) outentry(rank, t1, FALSE); else if (!rank1) outentry(rank, t1, TRUE); else { outentry(rank, t1, TRUE); outentry(0, t0, TRUE); } } if (rank0 >= rank) if (!done_stopprint) outentry(0, t0, TRUE); #ifdef UPDATE_RECORD_IN_PLACE if (flg) { #ifdef TRUNCATE_FILE /* if a reasonable way to truncate a file exists, use it */ truncate_file(rfile); #else /* use sentinel record rather than relying on truncation */ t1->points = 0L; /* terminates file when read back in */ t1->ver_major = t1->ver_minor = t1->patchlevel = 0; t1->uid = t1->deathdnum = t1->deathlev = 0; t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0; t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-'; t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0; t1->birthdate = t1->deathdate = yyyymmdd((time_t) 0L); Strcpy(t1->name, "@"); Strcpy(t1->death, "\n"); writeentry(rfile, t1); (void) fflush(rfile); #endif /* TRUNCATE_FILE */ } #endif /* UPDATE_RECORD_IN_PLACE */ (void) fclose(rfile); unlock_file(RECORD); free_ttlist(tt_head); showwin: if (iflags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1); destroywin: if (!t0_used) dealloc_ttentry(t0); if (iflags.toptenwin) { destroy_nhwindow(toptenwin); toptenwin = WIN_ERR; } } STATIC_OVL void outheader() { char linebuf[BUFSZ]; register char *bp; Strcpy(linebuf, " No Points Name"); bp = eos(linebuf); while (bp < linebuf + COLNO - 9) *bp++ = ' '; Strcpy(bp, "Hp [max]"); topten_print(linebuf); } /* so>0: standout line; so=0: ordinary line */ STATIC_OVL void outentry(rank, t1, so) struct toptenentry *t1; int rank; boolean so; { boolean second_line = TRUE; char linebuf[BUFSZ]; char *bp, hpbuf[24], linebuf3[BUFSZ]; int hppos, lngr; linebuf[0] = '\0'; if (rank) Sprintf(eos(linebuf), "%3d", rank); else Strcat(linebuf, " "); Sprintf(eos(linebuf), " %10ld %.10s", t1->points ? t1->points : u.urexp, t1->name); Sprintf(eos(linebuf), "-%s", t1->plrole); if (t1->plrace[0] != '?') Sprintf(eos(linebuf), "-%s", t1->plrace); /* Printing of gender and alignment is intentional. It has been * part of the NetHack Geek Code, and illustrates a proper way to * specify a character from the command line. */ Sprintf(eos(linebuf), "-%s", t1->plgend); if (t1->plalign[0] != '?') Sprintf(eos(linebuf), "-%s ", t1->plalign); else Strcat(linebuf, " "); if (!strncmp("escaped", t1->death, 7)) { Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]", !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "", t1->maxlvl); /* fixup for closing paren in "escaped... with...Amulet)[max..." */ if ((bp = index(linebuf, ')')) != 0) *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' '; second_line = FALSE; } else if (!strncmp("ascended", t1->death, 8)) { Sprintf(eos(linebuf), "ascended to demigod%s-hood", (t1->plgend[0] == 'F') ? "dess" : ""); second_line = FALSE; } else { if (!strncmp(t1->death, "quit", 4)) { Strcat(linebuf, "quit"); second_line = FALSE; } else if (!strncmp(t1->death, "died of st", 10)) { Strcat(linebuf, "starved to death"); second_line = FALSE; } else if (!strncmp(t1->death, "choked", 6)) { Sprintf(eos(linebuf), "choked on h%s food", (t1->plgend[0] == 'F') ? "er" : "is"); } else if (!strncmp(t1->death, "poisoned", 8)) { Strcat(linebuf, "was poisoned"); } else if (!strncmp(t1->death, "crushed", 7)) { Strcat(linebuf, "was crushed to death"); } else if (!strncmp(t1->death, "petrified by ", 13)) { Strcat(linebuf, "turned to stone"); } else Strcat(linebuf, "died"); if (t1->deathdnum == astral_level.dnum) { const char *arg, *fmt = " on the Plane of %s"; switch (t1->deathlev) { case -5: fmt = " on the %s Plane"; arg = "Astral"; break; case -4: arg = "Water"; break; case -3: arg = "Fire"; break; case -2: arg = "Air"; break; case -1: arg = "Earth"; break; default: arg = "Void"; break; } Sprintf(eos(linebuf), fmt, arg); } else { Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname); if (t1->deathdnum != knox_level.dnum) Sprintf(eos(linebuf), " on level %d", t1->deathlev); if (t1->deathlev != t1->maxlvl) Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); } /* kludge for "quit while already on Charon's boat" */ if (!strncmp(t1->death, "quit ", 5)) Strcat(linebuf, t1->death + 4); } Strcat(linebuf, "."); /* Quit, starved, ascended, and escaped contain no second line */ if (second_line) Sprintf(eos(linebuf), " %c%s.", highc(*(t1->death)), t1->death + 1); lngr = (int) strlen(linebuf); if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0'; else Sprintf(hpbuf, "%d", t1->hp); /* beginning of hp column after padding (not actually padded yet) */ hppos = COLNO - (sizeof(" Hp [max]") - 1); /* sizeof(str) includes \0 */ while (lngr >= hppos) { for (bp = eos(linebuf); !(*bp == ' ' && (bp - linebuf < hppos)); bp--) ; /* special case: word is too long, wrap in the middle */ if (linebuf + 15 >= bp) bp = linebuf + hppos - 1; /* special case: if about to wrap in the middle of maximum dungeon depth reached, wrap in front of it instead */ if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5)) bp -= 5; if (*bp != ' ') Strcpy(linebuf3, bp); else Strcpy(linebuf3, bp + 1); *bp = 0; if (so) { while (bp < linebuf + (COLNO - 1)) *bp++ = ' '; *bp = 0; topten_print_bold(linebuf); } else topten_print(linebuf); Sprintf(linebuf, "%15s %s", "", linebuf3); lngr = strlen(linebuf); } /* beginning of hp column not including padding */ hppos = COLNO - 7 - (int) strlen(hpbuf); bp = eos(linebuf); if (bp <= linebuf + hppos) { /* pad any necessary blanks to the hit point entry */ while (bp < linebuf + hppos) *bp++ = ' '; Strcpy(bp, hpbuf); Sprintf(eos(bp), " %s[%d]", (t1->maxhp < 10) ? " " : (t1->maxhp < 100) ? " " : "", t1->maxhp); } if (so) { bp = eos(linebuf); if (so >= COLNO) so = COLNO - 1; while (bp < linebuf + so) *bp++ = ' '; *bp = 0; topten_print_bold(linebuf); } else topten_print(linebuf); } STATIC_OVL int score_wanted(current_ver, rank, t1, playerct, players, uid) boolean current_ver; int rank; struct toptenentry *t1; int playerct; const char **players; int uid; { int i; if (current_ver && (t1->ver_major != VERSION_MAJOR || t1->ver_minor != VERSION_MINOR || t1->patchlevel != PATCHLEVEL)) return 0; if (sysopt.pers_is_uid && !playerct && t1->uid == uid) return 1; for (i = 0; i < playerct; i++) { if (players[i][0] == '-' && index("pr", players[i][1]) && players[i][2] == 0 && i + 1 < playerct) { const char *arg = players[i + 1]; if ((players[i][1] == 'p' && str2role(arg) == str2role(t1->plrole)) || (players[i][1] == 'r' && str2race(arg) == str2race(t1->plrace))) return 1; i++; } else if (strcmp(players[i], "all") == 0 || strncmp(t1->name, players[i], NAMSZ) == 0 || (players[i][0] == '-' && players[i][1] == t1->plrole[0] && players[i][2] == 0) || (digit(players[i][0]) && rank <= atoi(players[i]))) return 1; } return 0; } /* * print selected parts of score list. * argc >= 2, with argv[0] untrustworthy (directory names, et al.), * and argv[1] starting with "-s". */ void prscore(argc, argv) int argc; char **argv; { const char **players; int playerct, rank; boolean current_ver = TRUE, init_done = FALSE; register struct toptenentry *t1; FILE *rfile; boolean match_found = FALSE; register int i; char pbuf[BUFSZ]; int uid = -1; const char *player0; if (argc < 2 || strncmp(argv[1], "-s", 2)) { raw_printf("prscore: bad arguments (%d)", argc); return; } rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); if (!rfile) { raw_print("Cannot open record file!"); return; } #ifdef AMIGA { extern winid amii_rawprwin; init_nhwindows(&argc, argv); amii_rawprwin = create_nhwindow(NHW_TEXT); } #endif /* If the score list isn't after a game, we never went through * initialization. */ if (wiz1_level.dlevel == 0) { dlb_init(); init_dungeons(); init_done = TRUE; } if (!argv[1][2]) { /* plain "-s" */ argc--; argv++; } else argv[1] += 2; if (argc > 1 && !strcmp(argv[1], "-v")) { current_ver = FALSE; argc--; argv++; } if (argc <= 1) { if (sysopt.pers_is_uid) { uid = getuid(); playerct = 0; players = (const char **) 0; } else { player0 = plname; if (!*player0) #ifdef AMIGA player0 = "all"; /* single user system */ #else player0 = "hackplayer"; #endif playerct = 1; players = &player0; } } else { playerct = --argc; players = (const char **) ++argv; } raw_print(""); t1 = tt_head = newttentry(); for (rank = 1;; rank++) { readentry(rfile, t1); if (t1->points == 0) break; if (!match_found && score_wanted(current_ver, rank, t1, playerct, players, uid)) match_found = TRUE; t1->tt_next = newttentry(); t1 = t1->tt_next; } (void) fclose(rfile); if (init_done) { free_dungeons(); dlb_cleanup(); } if (match_found) { outheader(); t1 = tt_head; for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { if (score_wanted(current_ver, rank, t1, playerct, players, uid)) (void) outentry(rank, t1, FALSE); } } else { Sprintf(pbuf, "Cannot find any %sentries for ", current_ver ? "current " : ""); if (playerct < 1) Strcat(pbuf, "you."); else { if (playerct > 1) Strcat(pbuf, "any of "); for (i = 0; i < playerct; i++) { /* stop printing players if there are too many to fit */ if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) { if (strlen(pbuf) < BUFSZ - 4) Strcat(pbuf, "..."); else Strcpy(pbuf + strlen(pbuf) - 4, "..."); break; } Strcat(pbuf, players[i]); if (i < playerct - 1) { if (players[i][0] == '-' && index("pr", players[i][1]) && players[i][2] == 0) Strcat(pbuf, " "); else Strcat(pbuf, ":"); } } } raw_print(pbuf); raw_printf("Usage: %s -s [-v] [maxrank] [playernames]", hname); raw_printf("Player types are: [-p role] [-r race]"); } free_ttlist(tt_head); #ifdef AMIGA { extern winid amii_rawprwin; display_nhwindow(amii_rawprwin, 1); destroy_nhwindow(amii_rawprwin); amii_rawprwin = WIN_ERR; } #endif } STATIC_OVL int classmon(plch, fem) char *plch; boolean fem; { int i; /* Look for this role in the role table */ for (i = 0; roles[i].name.m; i++) if (!strncmp(plch, roles[i].filecode, ROLESZ)) { if (fem && roles[i].femalenum != NON_PM) return roles[i].femalenum; else if (roles[i].malenum != NON_PM) return roles[i].malenum; else return PM_HUMAN; } /* this might be from a 3.2.x score for former Elf class */ if (!strcmp(plch, "E")) return PM_RANGER; impossible("What weird role is this? (%s)", plch); return PM_HUMAN_MUMMY; } /* * Get a random player name and class from the high score list, * and attach them to an object (for statues or morgue corpses). */ struct obj * tt_oname(otmp) struct obj *otmp; { int rank; register int i; register struct toptenentry *tt; FILE *rfile; struct toptenentry tt_buf; if (!otmp) return (struct obj *) 0; rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); if (!rfile) { impossible("Cannot open record file!"); return (struct obj *) 0; } tt = &tt_buf; rank = rnd(sysopt.tt_oname_maxrank); pickentry: for (i = rank; i; i--) { readentry(rfile, tt); if (tt->points == 0) break; } if (tt->points == 0) { if (rank > 1) { rank = 1; rewind(rfile); goto pickentry; } otmp = (struct obj *) 0; } else { set_corpsenm(otmp, classmon(tt->plrole, (tt->plgend[0] == 'F'))); otmp = oname(otmp, tt->name); } (void) fclose(rfile); return otmp; } #ifdef NO_SCAN_BRACK /* Lattice scanf isn't up to reading the scorefile. What */ /* follows deals with that; I admit it's ugly. (KL) */ /* Now generally available (KL) */ STATIC_OVL void nsb_mung_line(p) char *p; { while ((p = index(p, ' ')) != 0) *p = '|'; } STATIC_OVL void nsb_unmung_line(p) char *p; { while ((p = index(p, '|')) != 0) *p = ' '; } #endif /* NO_SCAN_BRACK */ /*topten.c*/ nethack-3.6.0/src/track.c0000664000076400007660000000266112536476415014216 0ustar paxedpaxed/* NetHack 3.6 track.c $NHDT-Date: 1432512769 2015/05/25 00:12:49 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* track.c - version 1.0.2 */ #include "hack.h" #define UTSZ 50 STATIC_VAR NEARDATA int utcnt, utpnt; STATIC_VAR NEARDATA coord utrack[UTSZ]; void initrack() { utcnt = utpnt = 0; } /* add to track */ void settrack() { if (utcnt < UTSZ) utcnt++; if (utpnt == UTSZ) utpnt = 0; utrack[utpnt].x = u.ux; utrack[utpnt].y = u.uy; utpnt++; } coord * gettrack(x, y) register int x, y; { register int cnt, ndist; register coord *tc; cnt = utcnt; for (tc = &utrack[utpnt]; cnt--;) { if (tc == utrack) tc = &utrack[UTSZ - 1]; else tc--; ndist = distmin(x, y, tc->x, tc->y); /* if far away, skip track entries til we're closer */ if (ndist > 2) { ndist -= 2; /* be careful due to extra decrement at top of loop */ cnt -= ndist; if (cnt <= 0) return (coord *) 0; /* too far away, no matches possible */ if (tc < &utrack[ndist]) tc += (UTSZ - ndist); else tc -= ndist; } else if (ndist <= 1) return (ndist ? tc : 0); } return (coord *) 0; } /*track.c*/ nethack-3.6.0/src/trap.c0000664000076400007660000053304212625515645014060 0ustar paxedpaxed/* NetHack 3.6 trap.c $NHDT-Date: 1448492213 2015/11/25 22:56:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.249 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" extern const char *const destroy_strings[][3]; /* from zap.c */ STATIC_DCL void FDECL(dofiretrap, (struct obj *)); STATIC_DCL void NDECL(domagictrap); STATIC_DCL boolean FDECL(emergency_disrobe, (boolean *)); STATIC_DCL int FDECL(untrap_prob, (struct trap *)); STATIC_DCL void FDECL(move_into_trap, (struct trap *)); STATIC_DCL int FDECL(try_disarm, (struct trap *, BOOLEAN_P)); STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *)); STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *)); STATIC_DCL int FDECL(disarm_landmine, (struct trap *)); STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *)); STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P)); STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int, BOOLEAN_P)); STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); STATIC_DCL int FDECL(mkroll_launch, (struct trap *, XCHAR_P, XCHAR_P, SHORT_P, long)); STATIC_DCL boolean FDECL(isclearpath, (coord *, int, SCHAR_P, SCHAR_P)); STATIC_DCL char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); #if 0 STATIC_DCL void FDECL(join_adjacent_pits, (struct trap *)); #endif STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *)); STATIC_DCL int FDECL(steedintrap, (struct trap *, struct obj *)); STATIC_DCL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, struct obj *, struct obj *)); STATIC_DCL void NDECL(maybe_finish_sokoban); /* mintrap() should take a flags argument, but for time being we use this */ STATIC_VAR int force_mintrap = 0; STATIC_VAR const char *const a_your[2] = { "a", "your" }; STATIC_VAR const char *const A_Your[2] = { "A", "Your" }; STATIC_VAR const char tower_of_flame[] = "tower of flame"; STATIC_VAR const char *const A_gush_of_water_hits = "A gush of water hits"; STATIC_VAR const char *const blindgas[6] = { "humid", "odorless", "pungent", "chilling", "acrid", "biting" }; /* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode); returns TRUE if hit on torso */ boolean burnarmor(victim) struct monst *victim; { struct obj *item; char buf[BUFSZ]; int mat_idx, oldspe; boolean hitting_u; if (!victim) return 0; hitting_u = (victim == &youmonst); /* burning damage may dry wet towel */ item = hitting_u ? carrying(TOWEL) : m_carrying(victim, TOWEL); while (item) { if (is_wet_towel(item)) { oldspe = item->spe; dry_a_towel(item, rn2(oldspe + 1), TRUE); if (item->spe != oldspe) break; /* stop once one towel has been affected */ } item = item->nobj; } #define burn_dmg(obj, descr) erode_obj(obj, descr, ERODE_BURN, EF_GREASE) while (1) { switch (rn2(5)) { case 0: item = hitting_u ? uarmh : which_armor(victim, W_ARMH); if (item) { mat_idx = objects[item->otyp].oc_material; Sprintf(buf, "%s %s", materialnm[mat_idx], helm_simple_name(item)); } if (!burn_dmg(item, item ? buf : "helmet")) continue; break; case 1: item = hitting_u ? uarmc : which_armor(victim, W_ARMC); if (item) { (void) burn_dmg(item, cloak_simple_name(item)); return TRUE; } item = hitting_u ? uarm : which_armor(victim, W_ARM); if (item) { (void) burn_dmg(item, xname(item)); return TRUE; } item = hitting_u ? uarmu : which_armor(victim, W_ARMU); if (item) (void) burn_dmg(item, "shirt"); return TRUE; case 2: item = hitting_u ? uarms : which_armor(victim, W_ARMS); if (!burn_dmg(item, "wooden shield")) continue; break; case 3: item = hitting_u ? uarmg : which_armor(victim, W_ARMG); if (!burn_dmg(item, "gloves")) continue; break; case 4: item = hitting_u ? uarmf : which_armor(victim, W_ARMF); if (!burn_dmg(item, "boots")) continue; break; } break; /* Out of while loop */ } #undef burn_dmg return FALSE; } /* Generic erode-item function. * "ostr", if non-null, is an alternate string to print instead of the * object's name. * "type" is an ERODE_* value for the erosion type * "flags" is an or-ed list of EF_* flags * * Returns an erosion return value (ER_*) */ int erode_obj(otmp, ostr, type, ef_flags) register struct obj *otmp; const char *ostr; int type; int ef_flags; { static NEARDATA const char *const action[] = { "smoulder", "rust", "rot", "corrode" }; static NEARDATA const char *const msg[] = { "burnt", "rusted", "rotten", "corroded" }; boolean vulnerable = FALSE; boolean is_primary = TRUE; boolean check_grease = ef_flags & EF_GREASE; boolean print = ef_flags & EF_VERBOSE; int erosion; struct monst *victim; boolean vismon; boolean visobj; int cost_type; if (!otmp) return ER_NOTHING; victim = carried(otmp) ? &youmonst : mcarried(otmp) ? otmp->ocarry : NULL; vismon = victim && (victim != &youmonst) && canseemon(victim); /* Is bhitpos correct here? Ugh. */ visobj = !victim && cansee(bhitpos.x, bhitpos.y); switch (type) { case ERODE_BURN: vulnerable = is_flammable(otmp); check_grease = FALSE; cost_type = COST_BURN; break; case ERODE_RUST: vulnerable = is_rustprone(otmp); cost_type = COST_RUST; break; case ERODE_ROT: vulnerable = is_rottable(otmp); check_grease = FALSE; is_primary = FALSE; cost_type = COST_ROT; break; case ERODE_CORRODE: vulnerable = is_corrodeable(otmp); is_primary = FALSE; cost_type = COST_CORRODE; break; default: impossible("Invalid erosion type in erode_obj"); return ER_NOTHING; } erosion = is_primary ? otmp->oeroded : otmp->oeroded2; if (!ostr) ostr = cxname(otmp); if (check_grease && otmp->greased) { grease_protect(otmp, ostr, victim); return ER_GREASED; } else if (!vulnerable || (otmp->oerodeproof && otmp->rknown)) { if (print && flags.verbose) { if (victim == &youmonst) Your("%s %s not affected.", ostr, vtense(ostr, "are")); else if (vismon) pline("%s %s %s not affected.", s_suffix(Monnam(victim)), ostr, vtense(ostr, "are")); } return ER_NOTHING; } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) { if (flags.verbose && (print || otmp->oerodeproof)) { if (victim == &youmonst) pline("Somehow, your %s %s not affected.", ostr, vtense(ostr, "are")); else if (vismon) pline("Somehow, %s %s %s not affected.", s_suffix(mon_nam(victim)), ostr, vtense(ostr, "are")); else if (visobj) pline("Somehow, the %s %s not affected.", ostr, vtense(ostr, "are")); } /* We assume here that if the object is protected because it * is blessed, it still shows some minor signs of wear, and * the hero can distinguish this from an object that is * actually proof against damage. */ if (otmp->oerodeproof) { otmp->rknown = TRUE; if (victim == &youmonst) update_inventory(); } return ER_NOTHING; } else if (erosion < MAX_ERODE) { const char *adverb = (erosion + 1 == MAX_ERODE) ? " completely" : erosion ? " further" : ""; if (victim == &youmonst) Your("%s %s%s!", ostr, vtense(ostr, action[type]), adverb); else if (vismon) pline("%s %s %s%s!", s_suffix(Monnam(victim)), ostr, vtense(ostr, action[type]), adverb); else if (visobj) pline("The %s %s%s!", ostr, vtense(ostr, action[type]), adverb); if (ef_flags & EF_PAY) costly_alteration(otmp, cost_type); if (is_primary) otmp->oeroded++; else otmp->oeroded2++; if (victim == &youmonst) update_inventory(); return ER_DAMAGED; } else if (ef_flags & EF_DESTROY) { if (victim == &youmonst) Your("%s %s away!", ostr, vtense(ostr, action[type])); else if (vismon) pline("%s %s %s away!", s_suffix(Monnam(victim)), ostr, vtense(ostr, action[type])); else if (visobj) pline("The %s %s away!", ostr, vtense(ostr, action[type])); if (ef_flags & EF_PAY) costly_alteration(otmp, cost_type); setnotworn(otmp); delobj(otmp); return ER_DESTROYED; } else { if (flags.verbose && print) { if (victim == &youmonst) Your("%s %s completely %s.", ostr, vtense(ostr, Blind ? "feel" : "look"), msg[type]); else if (vismon) pline("%s %s %s completely %s.", s_suffix(Monnam(victim)), ostr, vtense(ostr, "look"), msg[type]); else if (visobj) pline("The %s %s completely %s.", ostr, vtense(ostr, "look"), msg[type]); } return ER_NOTHING; } } /* Protect an item from erosion with grease. Returns TRUE if the grease * wears off. */ boolean grease_protect(otmp, ostr, victim) register struct obj *otmp; const char *ostr; struct monst *victim; { static const char txt[] = "protected by the layer of grease!"; boolean vismon = victim && (victim != &youmonst) && canseemon(victim); if (ostr) { if (victim == &youmonst) Your("%s %s %s", ostr, vtense(ostr, "are"), txt); else if (vismon) pline("%s's %s %s %s", Monnam(victim), ostr, vtense(ostr, "are"), txt); } else if (victim == &youmonst || vismon) { pline("%s %s", Yobjnam2(otmp, "are"), txt); } if (!rn2(2)) { otmp->greased = 0; if (carried(otmp)) { pline_The("grease dissolves."); update_inventory(); } return TRUE; } return FALSE; } struct trap * maketrap(x, y, typ) register int x, y, typ; { static union vlaunchinfo zero_vl; register struct trap *ttmp; register struct rm *lev; boolean oldplace; if ((ttmp = t_at(x, y)) != 0) { if (ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE) return (struct trap *) 0; oldplace = TRUE; if (u.utrap && x == u.ux && y == u.uy && ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) || (u.utraptype == TT_WEB && typ != WEB) || (u.utraptype == TT_PIT && typ != PIT && typ != SPIKED_PIT))) u.utrap = 0; /* old remain valid */ } else if (IS_FURNITURE(levl[x][y].typ)) { /* no trap on top of furniture (caller usually screens the location to inhibit this, but wizard mode wishing doesn't) */ return (struct trap *) 0; } else { oldplace = FALSE; ttmp = newtrap(); ttmp->ntrap = 0; ttmp->tx = x; ttmp->ty = y; } /* [re-]initialize all fields except ntrap (handled below) and */ ttmp->vl = zero_vl; ttmp->launch.x = ttmp->launch.y = -1; /* force error if used before set */ ttmp->dst.dnum = ttmp->dst.dlevel = -1; ttmp->madeby_u = 0; ttmp->once = 0; ttmp->tseen = (typ == HOLE); /* hide non-holes */ ttmp->ttyp = typ; switch (typ) { case SQKY_BOARD: { int tavail[12], tpick[12], tcnt = 0, k; struct trap *t; for (k = 0; k < 12; ++k) tavail[k] = tpick[k] = 0; for (t = ftrap; t; t = t->ntrap) if (t->ttyp == SQKY_BOARD && t != ttmp) tavail[t->tnote] = 1; /* now populate tpick[] with the available indices */ for (k = 0; k < 12; ++k) if (tavail[k] == 0) tpick[tcnt++] = k; /* choose an unused note; if all are in use, pick a random one */ ttmp->tnote = (short) ((tcnt > 0) ? tpick[rn2(tcnt)] : rn2(12)); break; } case STATUE_TRAP: { /* create a "living" statue */ struct monst *mtmp; struct obj *otmp, *statue; struct permonst *mptr; int trycount = 10; do { /* avoid ultimately hostile co-aligned unicorn */ mptr = &mons[rndmonnum()]; } while (--trycount > 0 && is_unicorn(mptr) && sgn(u.ualign.type) == sgn(mptr->maligntyp)); statue = mkcorpstat(STATUE, (struct monst *) 0, mptr, x, y, CORPSTAT_NONE); mtmp = makemon(&mons[statue->corpsenm], 0, 0, MM_NOCOUNTBIRTH); if (!mtmp) break; /* should never happen */ while (mtmp->minvent) { otmp = mtmp->minvent; otmp->owornmask = 0; obj_extract_self(otmp); (void) add_to_container(statue, otmp); } statue->owt = weight(statue); mongone(mtmp); break; } case ROLLING_BOULDER_TRAP: /* boulder will roll towards trigger */ (void) mkroll_launch(ttmp, x, y, BOULDER, 1L); break; case PIT: case SPIKED_PIT: ttmp->conjoined = 0; /*FALLTHRU*/ case HOLE: case TRAPDOOR: lev = &levl[x][y]; if (*in_rooms(x, y, SHOPBASE) && (typ == HOLE || typ == TRAPDOOR || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) add_damage(x, y, /* schedule repair */ ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) && !context.mon_moving) ? 200L : 0L); lev->doormask = 0; /* subsumes altarmask, icedpool... */ if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */ lev->typ = ROOM; /* * some cases which can happen when digging * down while phazing thru solid areas */ else if (lev->typ == STONE || lev->typ == SCORR) lev->typ = CORR; else if (IS_WALL(lev->typ) || lev->typ == SDOOR) lev->typ = level.flags.is_maze_lev ? ROOM : level.flags.is_cavernous_lev ? CORR : DOOR; unearth_objs(x, y); break; } if (!oldplace) { ttmp->ntrap = ftrap; ftrap = ttmp; } else { /* oldplace; it shouldn't be possible to override a sokoban pit or hole with some other trap, but we'll check just to be safe */ if (Sokoban) maybe_finish_sokoban(); } return ttmp; } void fall_through(td) boolean td; /* td == TRUE : trap door or hole */ { d_level dtmp; char msgbuf[BUFSZ]; const char *dont_fall = 0; int newlevel, bottom; /* we'll fall even while levitating in Sokoban; otherwise, if we won't fall and won't be told that we aren't falling, give up now */ if (Blind && Levitation && !Sokoban) return; bottom = dunlevs_in_dungeon(&u.uz); /* when in the upper half of the quest, don't fall past the middle "quest locate" level if hero hasn't been there yet */ if (In_quest(&u.uz)) { int qlocate_depth = qlocate_level.dlevel; /* deepest reached < qlocate implies current < qlocate */ if (dunlev_reached(&u.uz) < qlocate_depth) bottom = qlocate_depth; /* early cut-off */ } newlevel = dunlev(&u.uz); /* current level */ do { newlevel++; } while (!rn2(4) && newlevel < bottom); if (td) { struct trap *t = t_at(u.ux, u.uy); feeltrap(t); if (!Sokoban) { if (t->ttyp == TRAPDOOR) pline("A trap door opens up under you!"); else pline("There's a gaping hole under you!"); } } else pline_The("%s opens up under you!", surface(u.ux, u.uy)); if (Sokoban && Can_fall_thru(&u.uz)) ; /* KMH -- You can't escape the Sokoban level traps */ else if (Levitation || u.ustuck || (!Can_fall_thru(&u.uz) && !levl[u.ux][u.uy].candig) || Flying || is_clinger(youmonst.data) || (Inhell && !u.uevent.invoked && newlevel == bottom)) { dont_fall = "don't fall in."; } else if (youmonst.data->msize >= MZ_HUGE) { dont_fall = "don't fit through."; } else if (!next_to_u()) { dont_fall = "are jerked back by your pet!"; } if (dont_fall) { You1(dont_fall); /* hero didn't fall through, but any objects here might */ impact_drop((struct obj *) 0, u.ux, u.uy, 0); if (!td) { display_nhwindow(WIN_MESSAGE, FALSE); pline_The("opening under you closes up."); } return; } if (*u.ushops) shopdig(1); if (Is_stronghold(&u.uz)) { find_hell(&dtmp); } else { int dist = newlevel - dunlev(&u.uz); dtmp.dnum = u.uz.dnum; dtmp.dlevel = newlevel; if (dist > 1) You("fall down a %s%sshaft!", dist > 3 ? "very " : "", dist > 2 ? "deep " : ""); } if (!td) Sprintf(msgbuf, "The hole in the %s above you closes up.", ceiling(u.ux, u.uy)); schedule_goto(&dtmp, FALSE, TRUE, 0, (char *) 0, !td ? msgbuf : (char *) 0); } /* * Animate the given statue. May have been via shatter attempt, trap, * or stone to flesh spell. Return a monster if successfully animated. * If the monster is animated, the object is deleted. If fail_reason * is non-null, then fill in the reason for failure (or success). * * The cause of animation is: * * ANIMATE_NORMAL - hero "finds" the monster * ANIMATE_SHATTER - hero tries to destroy the statue * ANIMATE_SPELL - stone to flesh spell hits the statue * * Perhaps x, y is not needed if we can use get_obj_location() to find * the statue's location... ??? * * Sequencing matters: * create monster; if it fails, give up with statue intact; * give "statue comes to life" message; * if statue belongs to shop, have shk give "you owe" message; * transfer statue contents to monster (after stolen_value()); * delete statue. * [This ordering means that if the statue ends up wearing a cloak of * invisibility or a mummy wrapping, the visibility checks might be * wrong, but to avoid that we'd have to clone the statue contents * first in order to give them to the monster before checking their * shop status--it's not worth the hassle.] */ struct monst * animate_statue(statue, x, y, cause, fail_reason) struct obj *statue; xchar x, y; int cause; int *fail_reason; { int mnum = statue->corpsenm; struct permonst *mptr = &mons[mnum]; struct monst *mon = 0, *shkp; struct obj *item; coord cc; boolean historic = (Role_if(PM_ARCHEOLOGIST) && (statue->spe & STATUE_HISTORIC) != 0), golem_xform = FALSE, use_saved_traits; const char *comes_to_life; char statuename[BUFSZ], tmpbuf[BUFSZ]; static const char historic_statue_is_gone[] = "that the historic statue is now gone"; if (cant_revive(&mnum, TRUE, statue)) { /* mnum has changed; we won't be animating this statue as itself */ if (mnum != PM_DOPPELGANGER) mptr = &mons[mnum]; use_saved_traits = FALSE; } else if (is_golem(mptr) && cause == ANIMATE_SPELL) { /* statue of any golem hit by stone-to-flesh becomes flesh golem */ golem_xform = (mptr != &mons[PM_FLESH_GOLEM]); mnum = PM_FLESH_GOLEM; mptr = &mons[PM_FLESH_GOLEM]; use_saved_traits = (has_omonst(statue) && !golem_xform); } else { use_saved_traits = has_omonst(statue); } if (use_saved_traits) { /* restore a petrified monster */ cc.x = x, cc.y = y; mon = montraits(statue, &cc); if (mon && mon->mtame && !mon->isminion) wary_dog(mon, TRUE); } else { /* statues of unique monsters from bones or wishing end up here (cant_revive() sets mnum to be doppelganger; mptr reflects the original form for use by newcham()) */ if ((mnum == PM_DOPPELGANGER && mptr != &mons[PM_DOPPELGANGER]) /* block quest guards from other roles */ || (mptr->msound == MS_GUARDIAN && quest_info(MS_GUARDIAN) != mnum)) { mon = makemon(&mons[PM_DOPPELGANGER], x, y, NO_MINVENT | MM_NOCOUNTBIRTH | MM_ADJACENTOK); /* if hero has protection from shape changers, cham field will be NON_PM; otherwise, set form to match the statue */ if (mon && mon->cham >= LOW_PM) (void) newcham(mon, mptr, FALSE, FALSE); } else mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ? (NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT); } if (!mon) { if (fail_reason) *fail_reason = unique_corpstat(&mons[statue->corpsenm]) ? AS_MON_IS_UNIQUE : AS_NO_MON; return (struct monst *) 0; } /* a non-montraits() statue might specify gender */ if (statue->spe & STATUE_MALE) mon->female = FALSE; else if (statue->spe & STATUE_FEMALE) mon->female = TRUE; /* if statue has been named, give same name to the monster */ if (has_oname(statue)) mon = christen_monst(mon, ONAME(statue)); /* mimic statue becomes seen mimic; other hiders won't be hidden */ if (mon->m_ap_type) seemimic(mon); else mon->mundetected = FALSE; mon->msleeping = 0; if (cause == ANIMATE_NORMAL || cause == ANIMATE_SHATTER) { /* trap always releases hostile monster */ mon->mtame = 0; /* (might be petrified pet tossed onto trap) */ mon->mpeaceful = 0; set_malign(mon); } comes_to_life = !canspotmon(mon) ? "disappears" : golem_xform ? "turns into flesh" : (nonliving(mon->data) || is_vampshifter(mon)) ? "moves" : "comes to life"; if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) { /* "the|your|Manlobbi's statue [of a wombat]" */ shkp = shop_keeper(*in_rooms(mon->mx, mon->my, SHOPBASE)); Sprintf(statuename, "%s%s", shk_your(tmpbuf, statue), (cause == ANIMATE_SPELL /* avoid "of a shopkeeper" if it's Manlobbi himself (if carried, it can't be unpaid--hence won't be described as "Manlobbi's statue"--because there wasn't any living shk when statue was picked up) */ && (mon != shkp || carried(statue))) ? xname(statue) : "statue"); pline("%s %s!", upstart(statuename), comes_to_life); } else if (Hallucination) { /* They don't know it's a statue */ pline_The("%s suddenly seems more animated.", rndmonnam((char *) 0)); } else if (cause == ANIMATE_SHATTER) { if (cansee(x, y)) Sprintf(statuename, "%s%s", shk_your(tmpbuf, statue), xname(statue)); else Strcpy(statuename, "a statue"); pline("Instead of shattering, %s suddenly %s!", statuename, comes_to_life); } else { /* cause == ANIMATE_NORMAL */ You("find %s posing as a statue.", canspotmon(mon) ? a_monnam(mon) : something); if (!canspotmon(mon) && Blind) map_invisible(x, y); stop_occupation(); } /* if this isn't caused by a monster using a wand of striking, there might be consequences for the hero */ if (!context.mon_moving) { /* if statue is owned by a shop, hero will have to pay for it; stolen_value gives a message (about debt or use of credit) which refers to "it" so needs to follow a message describing the object ("the statue comes to life" one above) */ if (cause != ANIMATE_NORMAL && costly_spot(x, y) && (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0 /* avoid charging for Manlobbi's statue of Manlobbi if stone-to-flesh is used on petrified shopkeep */ && mon != shkp) (void) stolen_value(statue, x, y, (boolean) shkp->mpeaceful, FALSE); if (historic) { You_feel("guilty %s.", historic_statue_is_gone); adjalign(-1); } } else { if (historic && cansee(x, y)) You_feel("regret %s.", historic_statue_is_gone); /* no alignment penalty */ } /* transfer any statue contents to monster's inventory */ while ((item = statue->cobj) != 0) { obj_extract_self(item); (void) mpickobj(mon, item); } m_dowear(mon, TRUE); /* in case statue is wielded and hero zaps stone-to-flesh at self */ if (statue->owornmask) remove_worn_item(statue, TRUE); /* statue no longer exists */ delobj(statue); /* avoid hiding under nothing */ if (x == u.ux && y == u.uy && Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y)) u.uundetected = 0; if (fail_reason) *fail_reason = AS_OK; return mon; } /* * You've either stepped onto a statue trap's location or you've triggered a * statue trap by searching next to it or by trying to break it with a wand * or pick-axe. */ struct monst * activate_statue_trap(trap, x, y, shatter) struct trap *trap; xchar x, y; boolean shatter; { struct monst *mtmp = (struct monst *) 0; struct obj *otmp = sobj_at(STATUE, x, y); int fail_reason; /* * Try to animate the first valid statue. Stop the loop when we * actually create something or the failure cause is not because * the mon was unique. */ deltrap(trap); while (otmp) { mtmp = animate_statue(otmp, x, y, shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, &fail_reason); if (mtmp || fail_reason != AS_MON_IS_UNIQUE) break; otmp = nxtobj(otmp, STATUE, TRUE); } feel_newsym(x, y); return mtmp; } STATIC_OVL boolean keep_saddle_with_steedcorpse(steed_mid, objchn, saddle) unsigned steed_mid; struct obj *objchn, *saddle; { if (!saddle) return FALSE; while (objchn) { if (objchn->otyp == CORPSE && has_omonst(objchn)) { struct monst *mtmp = OMONST(objchn); if (mtmp->m_id == steed_mid) { /* move saddle */ xchar x, y; if (get_obj_location(objchn, &x, &y, 0)) { obj_extract_self(saddle); place_object(saddle, x, y); stackobj(saddle); } return TRUE; } } if (Has_contents(objchn) && keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle)) return TRUE; objchn = objchn->nobj; } return FALSE; } void dotrap(trap, trflags) register struct trap *trap; unsigned trflags; { register int ttype = trap->ttyp; register struct obj *otmp; boolean already_seen = trap->tseen, forcetrap = (trflags & FORCETRAP) != 0, webmsgok = (trflags & NOWEBMSG) == 0, forcebungle = (trflags & FORCEBUNGLE) != 0, plunged = (trflags & TOOKPLUNGE) != 0, adj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE); int oldumort; int steed_article = ARTICLE_THE; nomul(0); /* KMH -- You can't escape the Sokoban level traps */ if (Sokoban && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || ttype == TRAPDOOR)) { /* The "air currents" message is still appropriate -- even when * the hero isn't flying or levitating -- because it conveys the * reason why the player cannot escape the trap with a dexterity * check, clinging to the ceiling, etc. */ pline("Air currents pull you down into %s %s!", a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); /* then proceed to normal trap effect */ } else if (already_seen && !forcetrap) { if ((Levitation || (Flying && !plunged)) && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || ttype == BEAR_TRAP)) { You("%s over %s %s.", Levitation ? "float" : "fly", a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); return; } if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE && ttype != ANTI_MAGIC && !forcebungle && !plunged && !adj_pit && (!rn2(5) || ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) { You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" : a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); return; } } if (u.usteed) { u.usteed->mtrapseen |= (1 << (ttype - 1)); /* suppress article in various steed messages when using its name (which won't occur when hallucinating) */ if (has_mname(u.usteed) && !Hallucination) steed_article = ARTICLE_NONE; } switch (ttype) { case ARROW_TRAP: if (trap->once && trap->tseen && !rn2(15)) { You_hear("a loud click!"); deltrap(trap); newsym(u.ux, u.uy); break; } trap->once = 1; seetrap(trap); pline("An arrow shoots out at you!"); otmp = mksobj(ARROW, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); otmp->opoisoned = 0; if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ ; } else if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) { obfree(otmp, (struct obj *) 0); } else { place_object(otmp, u.ux, u.uy); if (!Blind) otmp->dknown = 1; stackobj(otmp); newsym(u.ux, u.uy); } break; case DART_TRAP: if (trap->once && trap->tseen && !rn2(15)) { You_hear("a soft click."); deltrap(trap); newsym(u.ux, u.uy); break; } trap->once = 1; seetrap(trap); pline("A little dart shoots out at you!"); otmp = mksobj(DART, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (!rn2(6)) otmp->opoisoned = 1; oldumort = u.umortality; if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ ; } else if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) { if (otmp->opoisoned) poisoned("dart", A_CON, "little dart", /* if damage triggered life-saving, poison is limited to attrib loss */ (u.umortality > oldumort) ? 0 : 10, TRUE); obfree(otmp, (struct obj *) 0); } else { place_object(otmp, u.ux, u.uy); if (!Blind) otmp->dknown = 1; stackobj(otmp); newsym(u.ux, u.uy); } break; case ROCKTRAP: if (trap->once && trap->tseen && !rn2(15)) { pline("A trap door in %s opens, but nothing falls out!", the(ceiling(u.ux, u.uy))); deltrap(trap); newsym(u.ux, u.uy); } else { int dmg = d(2, 6); /* should be std ROCK dmg? */ trap->once = 1; feeltrap(trap); otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); pline("A trap door in %s opens and %s falls on your %s!", the(ceiling(u.ux, u.uy)), an(xname(otmp)), body_part(HEAD)); if (uarmh) { if (is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); dmg = 2; } else if (flags.verbose) { pline("%s does not protect you.", Yname2(uarmh)); } } if (!Blind) otmp->dknown = 1; stackobj(otmp); newsym(u.ux, u.uy); /* map the rock */ losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN); exercise(A_STR, FALSE); } break; case SQKY_BOARD: /* stepped on a squeaky board */ if ((Levitation || Flying) && !forcetrap) { if (!Blind) { seetrap(trap); if (Hallucination) You("notice a crease in the linoleum."); else You("notice a loose board below you."); } } else { seetrap(trap); pline("A board beneath you %s%s%s.", Deaf ? "vibrates" : "squeaks ", Deaf ? "" : trapnote(trap, 0), Deaf ? "" : " loudly"); wake_nearby(); } break; case BEAR_TRAP: { int dmg = d(2, 4); if ((Levitation || Flying) && !forcetrap) break; feeltrap(trap); if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { pline("%s bear trap closes harmlessly through you.", A_Your[trap->madeby_u]); break; } if (!u.usteed && youmonst.data->msize <= MZ_SMALL) { pline("%s bear trap closes harmlessly over you.", A_Your[trap->madeby_u]); break; } u.utrap = rn1(4, 4); u.utraptype = TT_BEARTRAP; if (u.usteed) { pline("%s bear trap closes on %s %s!", A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)), mbodypart(u.usteed, FOOT)); if (thitm(0, u.usteed, (struct obj *) 0, dmg, FALSE)) u.utrap = 0; /* steed died, hero not trapped */ } else { pline("%s bear trap closes on your %s!", A_Your[trap->madeby_u], body_part(FOOT)); set_wounded_legs(rn2(2) ? RIGHT_SIDE : LEFT_SIDE, rn1(10, 10)); if (u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR) You("howl in anger!"); losehp(Maybe_Half_Phys(dmg), "bear trap", KILLED_BY_AN); } exercise(A_DEX, FALSE); break; } case SLP_GAS_TRAP: seetrap(trap); if (Sleep_resistance || breathless(youmonst.data)) { You("are enveloped in a cloud of gas!"); } else { pline("A cloud of gas puts you to sleep!"); fall_asleep(-rnd(25), TRUE); } (void) steedintrap(trap, (struct obj *) 0); break; case RUST_TRAP: seetrap(trap); /* Unlike monsters, traps cannot aim their rust attacks at * you, so instead of looping through and taking either the * first rustable one or the body, we take whatever we get, * even if it is not rustable. */ switch (rn2(5)) { case 0: pline("%s you on the %s!", A_gush_of_water_hits, body_part(HEAD)); (void) water_damage(uarmh, helm_simple_name(uarmh), TRUE); break; case 1: pline("%s your left %s!", A_gush_of_water_hits, body_part(ARM)); if (water_damage(uarms, "shield", TRUE) != ER_NOTHING) break; if (u.twoweap || (uwep && bimanual(uwep))) (void) water_damage(u.twoweap ? uswapwep : uwep, 0, TRUE); glovecheck: (void) water_damage(uarmg, "gauntlets", TRUE); /* Not "metal gauntlets" since it gets called * even if it's leather for the message */ break; case 2: pline("%s your right %s!", A_gush_of_water_hits, body_part(ARM)); (void) water_damage(uwep, 0, TRUE); goto glovecheck; default: pline("%s you!", A_gush_of_water_hits); for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->lamplit && otmp != uwep && (otmp != uswapwep || !u.twoweap)) (void) snuff_lit(otmp); if (uarmc) (void) water_damage(uarmc, cloak_simple_name(uarmc), TRUE); else if (uarm) (void) water_damage(uarm, "armor", TRUE); else if (uarmu) (void) water_damage(uarmu, "shirt", TRUE); } update_inventory(); if (u.umonnum == PM_IRON_GOLEM) { int dam = u.mhmax; pline("%s you!", A_gush_of_water_hits); You("are covered with rust!"); losehp(Maybe_Half_Phys(dam), "rusting away", KILLED_BY); } else if (u.umonnum == PM_GREMLIN && rn2(3)) { pline("%s you!", A_gush_of_water_hits); (void) split_mon(&youmonst, (struct monst *) 0); } break; case FIRE_TRAP: seetrap(trap); dofiretrap((struct obj *) 0); break; case PIT: case SPIKED_PIT: /* KMH -- You can't escape the Sokoban level traps */ if (!Sokoban && (Levitation || (Flying && !plunged))) break; feeltrap(trap); if (!Sokoban && is_clinger(youmonst.data) && !plunged) { if (trap->tseen) { You_see("%s %spit below you.", a_your[trap->madeby_u], ttype == SPIKED_PIT ? "spiked " : ""); } else { pline("%s pit %sopens up under you!", A_Your[trap->madeby_u], ttype == SPIKED_PIT ? "full of spikes " : ""); You("don't fall in!"); } break; } if (!Sokoban) { char verbbuf[BUFSZ]; if (u.usteed) { if ((trflags & RECURSIVETRAP) != 0) Sprintf(verbbuf, "and %s fall", x_monnam(u.usteed, steed_article, (char *) 0, SUPPRESS_SADDLE, FALSE)); else Sprintf(verbbuf, "lead %s", x_monnam(u.usteed, steed_article, "poor", SUPPRESS_SADDLE, FALSE)); } else if (adj_pit) { You("move into an adjacent pit."); } else { Strcpy(verbbuf, !plunged ? "fall" : (Flying ? "dive" : "plunge")); You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]); } } /* wumpus reference */ if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once && In_quest(&u.uz) && Is_qlocate(&u.uz)) { pline("Fortunately it has a bottom after all..."); trap->once = 1; } else if (u.umonnum == PM_PIT_VIPER || u.umonnum == PM_PIT_FIEND) { pline("How pitiful. Isn't that the pits?"); } if (ttype == SPIKED_PIT) { const char *predicament = "on a set of sharp iron spikes"; if (u.usteed) { pline("%s %s %s!", upstart(x_monnam(u.usteed, steed_article, "poor", SUPPRESS_SADDLE, FALSE)), adj_pit ? "steps" : "lands", predicament); } else You("%s %s!", adj_pit ? "step" : "land", predicament); } u.utrap = rn1(6, 2); u.utraptype = TT_PIT; if (!steedintrap(trap, (struct obj *) 0)) { if (ttype == SPIKED_PIT) { oldumort = u.umortality; losehp(Maybe_Half_Phys(rnd(adj_pit ? 6 : 10)), plunged ? "deliberately plunged into a pit of iron spikes" : adj_pit ? "stepped into a pit of iron spikes" : "fell into a pit of iron spikes", NO_KILLER_PREFIX); if (!rn2(6)) poisoned("spikes", A_STR, adj_pit ? "stepping on poison spikes" : "fall onto poison spikes", /* if damage triggered life-saving, poison is limited to attrib loss */ (u.umortality > oldumort) ? 0 : 8, FALSE); } else { /* plunging flyers take spike damage but not pit damage */ if (!adj_pit && !(plunged && (Flying || is_clinger(youmonst.data)))) losehp(Maybe_Half_Phys(rnd(6)), plunged ? "deliberately plunged into a pit" : "fell into a pit", NO_KILLER_PREFIX); } if (Punished && !carried(uball)) { unplacebc(); ballfall(); placebc(); } if (!adj_pit) selftouch("Falling, you"); vision_full_recalc = 1; /* vision limits change */ exercise(A_STR, FALSE); exercise(A_DEX, FALSE); } break; case HOLE: case TRAPDOOR: if (!Can_fall_thru(&u.uz)) { seetrap(trap); /* normally done in fall_through */ impossible("dotrap: %ss cannot exist on this level.", defsyms[trap_to_defsym(ttype)].explanation); break; /* don't activate it after all */ } fall_through(TRUE); break; case TELEP_TRAP: seetrap(trap); tele_trap(trap); break; case LEVEL_TELEP: seetrap(trap); level_tele_trap(trap); break; case WEB: /* Our luckless player has stumbled into a web. */ feeltrap(trap); if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE || u.umonnum == PM_FIRE_ELEMENTAL) { if (webmsgok) You("%s %s spider web!", (u.umonnum == PM_FIRE_ELEMENTAL) ? "burn" : "dissolve", a_your[trap->madeby_u]); deltrap(trap); newsym(u.ux, u.uy); break; } if (webmsgok) You("flow through %s spider web.", a_your[trap->madeby_u]); break; } if (webmaker(youmonst.data)) { if (webmsgok) pline(trap->madeby_u ? "You take a walk on your web." : "There is a spider web here."); break; } if (webmsgok) { char verbbuf[BUFSZ]; if (forcetrap) { Strcpy(verbbuf, "are caught by"); } else if (u.usteed) { Sprintf(verbbuf, "lead %s into", x_monnam(u.usteed, steed_article, "poor", SUPPRESS_SADDLE, FALSE)); } else { Sprintf(verbbuf, "%s into", Levitation ? (const char *) "float" : locomotion(youmonst.data, "stumble")); } You("%s %s spider web!", verbbuf, a_your[trap->madeby_u]); } u.utraptype = TT_WEB; /* Time stuck in the web depends on your/steed strength. */ { register int str = ACURR(A_STR); /* If mounted, the steed gets trapped. Use mintrap * to do all the work. If mtrapped is set as a result, * unset it and set utrap instead. In the case of a * strongmonst and mintrap said it's trapped, use a * short but non-zero trap time. Otherwise, monsters * have no specific strength, so use player strength. * This gets skipped for webmsgok, which implies that * the steed isn't a factor. */ if (u.usteed && webmsgok) { /* mtmp location might not be up to date */ u.usteed->mx = u.ux; u.usteed->my = u.uy; /* mintrap currently does not return 2(died) for webs */ if (mintrap(u.usteed)) { u.usteed->mtrapped = 0; if (strongmonst(u.usteed->data)) str = 17; } else { break; } webmsgok = FALSE; /* mintrap printed the messages */ } if (str <= 3) u.utrap = rn1(6, 6); else if (str < 6) u.utrap = rn1(6, 4); else if (str < 9) u.utrap = rn1(4, 4); else if (str < 12) u.utrap = rn1(4, 2); else if (str < 15) u.utrap = rn1(2, 2); else if (str < 18) u.utrap = rnd(2); else if (str < 69) u.utrap = 1; else { u.utrap = 0; if (webmsgok) You("tear through %s web!", a_your[trap->madeby_u]); deltrap(trap); newsym(u.ux, u.uy); /* get rid of trap symbol */ } } break; case STATUE_TRAP: (void) activate_statue_trap(trap, u.ux, u.uy, FALSE); break; case MAGIC_TRAP: /* A magic trap. */ seetrap(trap); if (!rn2(30)) { deltrap(trap); newsym(u.ux, u.uy); /* update position */ You("are caught in a magical explosion!"); losehp(rnd(10), "magical explosion", KILLED_BY_AN); Your("body absorbs some of the magical energy!"); u.uen = (u.uenmax += 2); break; } else { domagictrap(); } (void) steedintrap(trap, (struct obj *) 0); break; case ANTI_MAGIC: seetrap(trap); /* hero without magic resistance loses spell energy, hero with magic resistance takes damage instead; possibly non-intuitive but useful for play balance */ if (!Antimagic) { drain_en(rnd(u.ulevel) + 1); } else { int dmgval2 = rnd(4), hp = Upolyd ? u.mh : u.uhp; /* Half_XXX_damage has opposite its usual effect (approx) but isn't cumulative if hero has more than one */ if (Half_physical_damage || Half_spell_damage) dmgval2 += rnd(4); /* give Magicbane wielder dose of own medicine */ if (uwep && uwep->oartifact == ART_MAGICBANE) dmgval2 += rnd(4); /* having an artifact--other than own quest one--which confers magic resistance simply by being carried also increases the effect */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->oartifact && !is_quest_artifact(otmp) && defends_when_carried(AD_MAGM, otmp)) break; if (otmp) dmgval2 += rnd(4); if (Passes_walls) dmgval2 = (dmgval2 + 3) / 4; You_feel((dmgval2 >= hp) ? "unbearably torpid!" : (dmgval2 >= hp / 4) ? "very lethargic." : "sluggish."); /* opposite of magical explosion */ losehp(dmgval2, "anti-magic implosion", KILLED_BY_AN); } break; case POLY_TRAP: { char verbbuf[BUFSZ]; seetrap(trap); if (u.usteed) Sprintf(verbbuf, "lead %s", x_monnam(u.usteed, steed_article, (char *) 0, SUPPRESS_SADDLE, FALSE)); else Sprintf(verbbuf, "%s", Levitation ? (const char *) "float" : locomotion(youmonst.data, "step")); You("%s onto a polymorph trap!", verbbuf); if (Antimagic || Unchanging) { shieldeff(u.ux, u.uy); You_feel("momentarily different."); /* Trap did nothing; don't remove it --KAA */ } else { (void) steedintrap(trap, (struct obj *) 0); deltrap(trap); /* delete trap before polymorph */ newsym(u.ux, u.uy); /* get rid of trap symbol */ You_feel("a change coming over you."); polyself(0); } break; } case LANDMINE: { unsigned steed_mid = 0; struct obj *saddle = 0; if ((Levitation || Flying) && !forcetrap) { if (!already_seen && rn2(3)) break; feeltrap(trap); pline("%s %s in a pile of soil below you.", already_seen ? "There is" : "You discover", trap->madeby_u ? "the trigger of your mine" : "a trigger"); if (already_seen && rn2(3)) break; pline("KAABLAMM!!! %s %s%s off!", forcebungle ? "Your inept attempt sets" : "The air currents set", already_seen ? a_your[trap->madeby_u] : "", already_seen ? " land mine" : "it"); } else { /* prevent landmine from killing steed, throwing you to * the ground, and you being affected again by the same * mine because it hasn't been deleted yet */ static boolean recursive_mine = FALSE; if (recursive_mine) break; feeltrap(trap); pline("KAABLAMM!!! You triggered %s land mine!", a_your[trap->madeby_u]); if (u.usteed) steed_mid = u.usteed->m_id; recursive_mine = TRUE; (void) steedintrap(trap, (struct obj *) 0); recursive_mine = FALSE; saddle = sobj_at(SADDLE, u.ux, u.uy); set_wounded_legs(LEFT_SIDE, rn1(35, 41)); set_wounded_legs(RIGHT_SIDE, rn1(35, 41)); exercise(A_DEX, FALSE); } blow_up_landmine(trap); if (steed_mid && saddle && !u.usteed) (void) keep_saddle_with_steedcorpse(steed_mid, fobj, saddle); newsym(u.ux, u.uy); /* update trap symbol */ losehp(Maybe_Half_Phys(rnd(16)), "land mine", KILLED_BY_AN); /* fall recursively into the pit... */ if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP); fill_pit(u.ux, u.uy); break; } case ROLLING_BOULDER_TRAP: { int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); feeltrap(trap); pline("Click! You trigger a rolling boulder trap!"); if (!launch_obj(BOULDER, trap->launch.x, trap->launch.y, trap->launch2.x, trap->launch2.y, style)) { deltrap(trap); newsym(u.ux, u.uy); /* get rid of trap symbol */ pline("Fortunately for you, no boulder was released."); } break; } case MAGIC_PORTAL: feeltrap(trap); domagicportal(trap); break; case VIBRATING_SQUARE: feeltrap(trap); /* messages handled elsewhere; the trap symbol is merely to mark the * square for future reference */ break; default: feeltrap(trap); impossible("You hit a trap of type %u", trap->ttyp); } } STATIC_OVL char * trapnote(trap, noprefix) struct trap *trap; boolean noprefix; { static char tnbuf[12]; const char *tn, *tnnames[12] = { "C note", "D flat", "D note", "E flat", "E note", "F note", "F sharp", "G note", "G sharp", "A note", "B flat", "B note" }; tnbuf[0] = '\0'; tn = tnnames[trap->tnote]; if (!noprefix) Sprintf(tnbuf, "%s ", (*tn == 'A' || *tn == 'E' || *tn == 'F') ? "an" : "a"); Sprintf(eos(tnbuf), "%s", tn); return tnbuf; } STATIC_OVL int steedintrap(trap, otmp) struct trap *trap; struct obj *otmp; { struct monst *steed = u.usteed; int tt; boolean trapkilled, steedhit; if (!steed || !trap) return 0; tt = trap->ttyp; steed->mx = u.ux; steed->my = u.uy; trapkilled = steedhit = FALSE; switch (tt) { case ARROW_TRAP: if (!otmp) { impossible("steed hit by non-existant arrow?"); return 0; } trapkilled = thitm(8, steed, otmp, 0, FALSE); steedhit = TRUE; break; case DART_TRAP: if (!otmp) { impossible("steed hit by non-existant dart?"); return 0; } trapkilled = thitm(7, steed, otmp, 0, FALSE); steedhit = TRUE; break; case SLP_GAS_TRAP: if (!resists_sleep(steed) && !breathless(steed->data) && !steed->msleeping && steed->mcanmove) { if (sleep_monst(steed, rnd(25), -1)) /* no in_sight check here; you can feel it even if blind */ pline("%s suddenly falls asleep!", Monnam(steed)); } steedhit = TRUE; break; case LANDMINE: trapkilled = thitm(0, steed, (struct obj *) 0, rnd(16), FALSE); steedhit = TRUE; break; case PIT: case SPIKED_PIT: trapkilled = (steed->mhp <= 0 || thitm(0, steed, (struct obj *) 0, rnd((tt == PIT) ? 6 : 10), FALSE)); steedhit = TRUE; break; case POLY_TRAP: if (!resists_magm(steed) && !resist(steed, WAND_CLASS, 0, NOTELL)) { (void) newcham(steed, (struct permonst *) 0, FALSE, FALSE); if (!can_saddle(steed) || !can_ride(steed)) dismount_steed(DISMOUNT_POLY); else You("have to adjust yourself in the saddle on %s.", x_monnam(steed, ARTICLE_A, (char *) 0, SUPPRESS_SADDLE, FALSE)); } steedhit = TRUE; break; default: break; } if (trapkilled) { dismount_steed(DISMOUNT_POLY); return 2; } return steedhit ? 1 : 0; } /* some actions common to both player and monsters for triggered landmine */ void blow_up_landmine(trap) struct trap *trap; { int x = trap->tx, y = trap->ty, dbx, dby; struct rm *lev = &levl[x][y]; (void) scatter(x, y, 4, MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS, (struct obj *) 0); del_engr_at(x, y); wake_nearto(x, y, 400); if (IS_DOOR(lev->typ)) lev->doormask = D_BROKEN; /* destroy drawbridge if present */ if (lev->typ == DRAWBRIDGE_DOWN || is_drawbridge_wall(x, y) >= 0) { dbx = x, dby = y; /* if under the portcullis, the bridge is adjacent */ if (find_drawbridge(&dbx, &dby)) destroy_drawbridge(dbx, dby); trap = t_at(x, y); /* expected to be null after destruction */ } /* convert landmine into pit */ if (trap) { if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) { /* no pits here */ deltrap(trap); } else { trap->ttyp = PIT; /* explosion creates a pit */ trap->madeby_u = FALSE; /* resulting pit isn't yours */ seetrap(trap); /* and it isn't concealed */ } } } /* * The following are used to track launched objects to * prevent them from vanishing if you are killed. They * will reappear at the launchplace in bones files. */ static struct { struct obj *obj; xchar x, y; } launchplace; static void launch_drop_spot(obj, x, y) struct obj *obj; xchar x, y; { if (!obj) { launchplace.obj = (struct obj *) 0; launchplace.x = 0; launchplace.y = 0; } else { launchplace.obj = obj; launchplace.x = x; launchplace.y = y; } } boolean launch_in_progress() { if (launchplace.obj) return TRUE; return FALSE; } void force_launch_placement() { if (launchplace.obj) { launchplace.obj->otrapped = 0; place_object(launchplace.obj, launchplace.x, launchplace.y); } } /* * Move obj from (x1,y1) to (x2,y2) * * Return 0 if no object was launched. * 1 if an object was launched and placed somewhere. * 2 if an object was launched, but used up. */ int launch_obj(otyp, x1, y1, x2, y2, style) short otyp; register int x1, y1, x2, y2; int style; { register struct monst *mtmp; register struct obj *otmp, *otmp2; register int dx, dy; struct obj *singleobj; boolean used_up = FALSE; boolean otherside = FALSE; int dist; int tmp; int delaycnt = 0; otmp = sobj_at(otyp, x1, y1); /* Try the other side too, for rolling boulder traps */ if (!otmp && otyp == BOULDER) { otherside = TRUE; otmp = sobj_at(otyp, x2, y2); } if (!otmp) return 0; if (otherside) { /* swap 'em */ int tx, ty; tx = x1; ty = y1; x1 = x2; y1 = y2; x2 = tx; y2 = ty; } if (otmp->quan == 1L) { obj_extract_self(otmp); singleobj = otmp; otmp = (struct obj *) 0; } else { singleobj = splitobj(otmp, 1L); obj_extract_self(singleobj); } newsym(x1, y1); /* in case you're using a pick-axe to chop the boulder that's being launched (perhaps a monster triggered it), destroy context so that next dig attempt never thinks you're resuming previous effort */ if ((otyp == BOULDER || otyp == STATUE) && singleobj->ox == context.digging.pos.x && singleobj->oy == context.digging.pos.y) (void) memset((genericptr_t) &context.digging, 0, sizeof(struct dig_info)); dist = distmin(x1, y1, x2, y2); bhitpos.x = x1; bhitpos.y = y1; dx = sgn(x2 - x1); dy = sgn(y2 - y1); switch (style) { case ROLL | LAUNCH_UNSEEN: if (otyp == BOULDER) { You_hear(Hallucination ? "someone bowling." : "rumbling in the distance."); } style &= ~LAUNCH_UNSEEN; goto roll; case ROLL | LAUNCH_KNOWN: /* use otrapped as a flag to ohitmon */ singleobj->otrapped = 1; style &= ~LAUNCH_KNOWN; /* fall through */ roll: case ROLL: delaycnt = 2; /* fall through */ default: if (!delaycnt) delaycnt = 1; if (!cansee(bhitpos.x, bhitpos.y)) curs_on_u(); tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); tmp_at(bhitpos.x, bhitpos.y); } /* Mark a spot to place object in bones files to prevent * loss of object. Use the starting spot to ensure that * a rolling boulder will still launch, which it wouldn't * do if left midstream. Unfortunately we can't use the * target resting spot, because there are some things/situations * that would prevent it from ever getting there (bars), and we * can't tell that yet. */ launch_drop_spot(singleobj, bhitpos.x, bhitpos.y); /* Set the object in motion */ while (dist-- > 0 && !used_up) { struct trap *t; tmp_at(bhitpos.x, bhitpos.y); tmp = delaycnt; /* dstage@u.washington.edu -- Delay only if hero sees it */ if (cansee(bhitpos.x, bhitpos.y)) while (tmp-- > 0) delay_output(); bhitpos.x += dx; bhitpos.y += dy; t = t_at(bhitpos.x, bhitpos.y); if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (otyp == BOULDER && throws_rocks(mtmp->data)) { if (rn2(3)) { pline("%s snatches the boulder.", Monnam(mtmp)); singleobj->otrapped = 0; (void) mpickobj(mtmp, singleobj); used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); break; } } if (ohitmon(mtmp, singleobj, (style == ROLL) ? -1 : dist, FALSE)) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); break; } } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (multi) nomul(0); if (thitu(9 + singleobj->spe, dmgval(singleobj, &youmonst), singleobj, (char *) 0)) stop_occupation(); } if (style == ROLL) { if (down_gate(bhitpos.x, bhitpos.y) != -1) { if (ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); break; } } if (t && otyp == BOULDER) { switch (t->ttyp) { case LANDMINE: if (rn2(10) > 2) { pline( "KAABLAMM!!!%s", cansee(bhitpos.x, bhitpos.y) ? " The rolling boulder triggers a land mine." : ""); deltrap(t); del_engr_at(bhitpos.x, bhitpos.y); place_object(singleobj, bhitpos.x, bhitpos.y); singleobj->otrapped = 0; fracture_rock(singleobj); (void) scatter(bhitpos.x, bhitpos.y, 4, MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS, (struct obj *) 0); if (cansee(bhitpos.x, bhitpos.y)) newsym(bhitpos.x, bhitpos.y); used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); } break; case LEVEL_TELEP: case TELEP_TRAP: if (cansee(bhitpos.x, bhitpos.y)) pline("Suddenly the rolling boulder disappears!"); else You_hear("a rumbling stop abruptly."); singleobj->otrapped = 0; if (t->ttyp == TELEP_TRAP) (void) rloco(singleobj); else { int newlev = random_teleport_level(); d_level dest; if (newlev == depth(&u.uz) || In_endgame(&u.uz)) continue; add_to_migration(singleobj); get_level(&dest, newlev); singleobj->ox = dest.dnum; singleobj->oy = dest.dlevel; singleobj->owornmask = (long) MIGR_RANDOM; } seetrap(t); used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); break; case PIT: case SPIKED_PIT: case HOLE: case TRAPDOOR: /* the boulder won't be used up if there is a monster in the trap; stop rolling anyway */ x2 = bhitpos.x, y2 = bhitpos.y; /* stops here */ if (flooreffects(singleobj, x2, y2, "fall")) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); } dist = -1; /* stop rolling immediately */ break; } if (used_up || dist == -1) break; } if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); break; } if (otyp == BOULDER && (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) { const char *bmsg = " as one boulder sets another in motion"; if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)) bmsg = " as one boulder hits another"; You_hear("a loud crash%s!", cansee(bhitpos.x, bhitpos.y) ? bmsg : ""); obj_extract_self(otmp2); /* pass off the otrapped flag to the next boulder */ otmp2->otrapped = singleobj->otrapped; singleobj->otrapped = 0; place_object(singleobj, bhitpos.x, bhitpos.y); singleobj = otmp2; otmp2 = (struct obj *) 0; wake_nearto(bhitpos.x, bhitpos.y, 10 * 10); } } if (otyp == BOULDER && closed_door(bhitpos.x, bhitpos.y)) { if (cansee(bhitpos.x, bhitpos.y)) pline_The("boulder crashes through a door."); levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN; if (dist) unblock_point(bhitpos.x, bhitpos.y); } /* if about to hit iron bars, do so now */ if (dist > 0 && isok(bhitpos.x + dx, bhitpos.y + dy) && levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) { if (!singleobj) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); } break; } } } tmp_at(DISP_END, 0); launch_drop_spot((struct obj *) 0, 0, 0); if (!used_up) { singleobj->otrapped = 0; place_object(singleobj, x2, y2); newsym(x2, y2); return 1; } else return 2; } void seetrap(trap) struct trap *trap; { if (!trap->tseen) { trap->tseen = 1; newsym(trap->tx, trap->ty); } } /* like seetrap() but overrides vision */ void feeltrap(trap) struct trap *trap; { trap->tseen = 1; map_trap(trap, 1); /* in case it's beneath something, redisplay the something */ newsym(trap->tx, trap->ty); } STATIC_OVL int mkroll_launch(ttmp, x, y, otyp, ocount) struct trap *ttmp; xchar x, y; short otyp; long ocount; { struct obj *otmp; register int tmp; schar dx, dy; int distance; coord cc; coord bcc; int trycount = 0; boolean success = FALSE; int mindist = 4; if (ttmp->ttyp == ROLLING_BOULDER_TRAP) mindist = 2; distance = rn1(5, 4); /* 4..8 away */ tmp = rn2(8); /* randomly pick a direction to try first */ while (distance >= mindist) { dx = xdir[tmp]; dy = ydir[tmp]; cc.x = x; cc.y = y; /* Prevent boulder from being placed on water */ if (ttmp->ttyp == ROLLING_BOULDER_TRAP && is_pool_or_lava(x + distance * dx, y + distance * dy)) success = FALSE; else success = isclearpath(&cc, distance, dx, dy); if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { boolean success_otherway; bcc.x = x; bcc.y = y; success_otherway = isclearpath(&bcc, distance, -(dx), -(dy)); if (!success_otherway) success = FALSE; } if (success) break; if (++tmp > 7) tmp = 0; if ((++trycount % 8) == 0) --distance; } if (!success) { /* create the trap without any ammo, launch pt at trap location */ cc.x = bcc.x = x; cc.y = bcc.y = y; } else { otmp = mksobj(otyp, TRUE, FALSE); otmp->quan = ocount; otmp->owt = weight(otmp); place_object(otmp, cc.x, cc.y); stackobj(otmp); } ttmp->launch.x = cc.x; ttmp->launch.y = cc.y; if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { ttmp->launch2.x = bcc.x; ttmp->launch2.y = bcc.y; } else ttmp->launch_otyp = otyp; newsym(ttmp->launch.x, ttmp->launch.y); return 1; } STATIC_OVL boolean isclearpath(cc, distance, dx, dy) coord *cc; int distance; schar dx, dy; { uchar typ; xchar x, y; x = cc->x; y = cc->y; while (distance-- > 0) { x += dx; y += dy; typ = levl[x][y].typ; if (!isok(x, y) || !ZAP_POS(typ) || closed_door(x, y)) return FALSE; } cc->x = x; cc->y = y; return TRUE; } int mintrap(mtmp) register struct monst *mtmp; { register struct trap *trap = t_at(mtmp->mx, mtmp->my); boolean trapkilled = FALSE; struct permonst *mptr = mtmp->data; struct obj *otmp; if (!trap) { mtmp->mtrapped = 0; /* perhaps teleported? */ } else if (mtmp->mtrapped) { /* is currently in the trap */ if (!trap->tseen && cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) && (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP || trap->ttyp == HOLE || trap->ttyp == PIT || trap->ttyp == WEB)) { /* If you come upon an obviously trapped monster, then * you must be able to see the trap it's in too. */ seetrap(trap); } if (!rn2(40)) { if (sobj_at(BOULDER, mtmp->mx, mtmp->my) && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { if (!rn2(2)) { mtmp->mtrapped = 0; if (canseemon(mtmp)) pline("%s pulls free...", Monnam(mtmp)); fill_pit(mtmp->mx, mtmp->my); } } else { mtmp->mtrapped = 0; } } else if (metallivorous(mptr)) { if (trap->ttyp == BEAR_TRAP) { if (canseemon(mtmp)) pline("%s eats a bear trap!", Monnam(mtmp)); deltrap(trap); mtmp->meating = 5; mtmp->mtrapped = 0; } else if (trap->ttyp == SPIKED_PIT) { if (canseemon(mtmp)) pline("%s munches on some spikes!", Monnam(mtmp)); trap->ttyp = PIT; mtmp->meating = 5; } } } else { register int tt = trap->ttyp; boolean in_sight, tear_web, see_it, inescapable = force_mintrap || ((tt == HOLE || tt == PIT) && Sokoban && !trap->madeby_u); const char *fallverb; /* true when called from dotrap, inescapable is not an option */ if (mtmp == u.usteed) inescapable = TRUE; if (!inescapable && ((mtmp->mtrapseen & (1 << (tt - 1))) != 0 || (tt == HOLE && !mindless(mptr)))) { /* it has been in such a trap - perhaps it escapes */ if (rn2(4)) return 0; } else { mtmp->mtrapseen |= (1 << (tt - 1)); } /* Monster is aggravated by being trapped by you. Recognizing who made the trap isn't completely unreasonable; everybody has their own style. */ if (trap->madeby_u && rnl(5)) setmangry(mtmp); in_sight = canseemon(mtmp); see_it = cansee(mtmp->mx, mtmp->my); /* assume hero can tell what's going on for the steed */ if (mtmp == u.usteed) in_sight = TRUE; switch (tt) { case ARROW_TRAP: if (trap->once && trap->tseen && !rn2(15)) { if (in_sight && see_it) pline("%s triggers a trap but nothing happens.", Monnam(mtmp)); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } trap->once = 1; otmp = mksobj(ARROW, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); otmp->opoisoned = 0; if (in_sight) seetrap(trap); if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case DART_TRAP: if (trap->once && trap->tseen && !rn2(15)) { if (in_sight && see_it) pline("%s triggers a trap but nothing happens.", Monnam(mtmp)); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } trap->once = 1; otmp = mksobj(DART, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (!rn2(6)) otmp->opoisoned = 1; if (in_sight) seetrap(trap); if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case ROCKTRAP: if (trap->once && trap->tseen && !rn2(15)) { if (in_sight && see_it) pline( "A trap door above %s opens, but nothing falls out!", mon_nam(mtmp)); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } trap->once = 1; otmp = mksobj(ROCK, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (in_sight) seetrap(trap); if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) trapkilled = TRUE; break; case SQKY_BOARD: if (is_flyer(mptr)) break; /* stepped on a squeaky board */ if (in_sight) { if (!Deaf) { pline("A board beneath %s squeaks %s loudly.", mon_nam(mtmp), trapnote(trap, 0)); seetrap(trap); } else { pline("%s stops momentarily and appears to cringe.", Monnam(mtmp)); } } else You_hear("a distant %s squeak.", trapnote(trap, 1)); /* wake up nearby monsters */ wake_nearto(mtmp->mx, mtmp->my, 40); break; case BEAR_TRAP: if (mptr->msize > MZ_SMALL && !amorphous(mptr) && !is_flyer(mptr) && !is_whirly(mptr) && !unsolid(mptr)) { mtmp->mtrapped = 1; if (in_sight) { pline("%s is caught in %s bear trap!", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } else { if (mptr == &mons[PM_OWLBEAR] || mptr == &mons[PM_BUGBEAR]) You_hear("the roaring of an angry bear!"); } } else if (force_mintrap) { if (in_sight) { pline("%s evades %s bear trap!", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } } if (mtmp->mtrapped) trapkilled = thitm(0, mtmp, (struct obj *) 0, d(2, 4), FALSE); break; case SLP_GAS_TRAP: if (!resists_sleep(mtmp) && !breathless(mptr) && !mtmp->msleeping && mtmp->mcanmove) { if (sleep_monst(mtmp, rnd(25), -1) && in_sight) { pline("%s suddenly falls asleep!", Monnam(mtmp)); seetrap(trap); } } break; case RUST_TRAP: { struct obj *target; if (in_sight) seetrap(trap); switch (rn2(5)) { case 0: if (in_sight) pline("%s %s on the %s!", A_gush_of_water_hits, mon_nam(mtmp), mbodypart(mtmp, HEAD)); target = which_armor(mtmp, W_ARMH); (void) water_damage(target, helm_simple_name(target), TRUE); break; case 1: if (in_sight) pline("%s %s's left %s!", A_gush_of_water_hits, mon_nam(mtmp), mbodypart(mtmp, ARM)); target = which_armor(mtmp, W_ARMS); if (water_damage(target, "shield", TRUE) != ER_NOTHING) break; target = MON_WEP(mtmp); if (target && bimanual(target)) (void) water_damage(target, 0, TRUE); glovecheck: target = which_armor(mtmp, W_ARMG); (void) water_damage(target, "gauntlets", TRUE); break; case 2: if (in_sight) pline("%s %s's right %s!", A_gush_of_water_hits, mon_nam(mtmp), mbodypart(mtmp, ARM)); (void) water_damage(MON_WEP(mtmp), 0, TRUE); goto glovecheck; default: if (in_sight) pline("%s %s!", A_gush_of_water_hits, mon_nam(mtmp)); for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->lamplit && (otmp->owornmask & (W_WEP | W_SWAPWEP)) == 0) (void) snuff_lit(otmp); if ((target = which_armor(mtmp, W_ARMC)) != 0) (void) water_damage(target, cloak_simple_name(target), TRUE); else if ((target = which_armor(mtmp, W_ARM)) != 0) (void) water_damage(target, "armor", TRUE); else if ((target = which_armor(mtmp, W_ARMU)) != 0) (void) water_damage(target, "shirt", TRUE); } if (mptr == &mons[PM_IRON_GOLEM]) { if (in_sight) pline("%s falls to pieces!", Monnam(mtmp)); else if (mtmp->mtame) pline("May %s rust in peace.", mon_nam(mtmp)); mondied(mtmp); if (mtmp->mhp <= 0) trapkilled = TRUE; } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { (void) split_mon(mtmp, (struct monst *) 0); } break; } /* RUST_TRAP */ case FIRE_TRAP: mfiretrap: if (in_sight) pline("A %s erupts from the %s under %s!", tower_of_flame, surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); else if (see_it) /* evidently `mtmp' is invisible */ You_see("a %s erupt from the %s!", tower_of_flame, surface(mtmp->mx, mtmp->my)); if (resists_fire(mtmp)) { if (in_sight) { shieldeff(mtmp->mx, mtmp->my); pline("%s is uninjured.", Monnam(mtmp)); } } else { int num = d(2, 4), alt; boolean immolate = FALSE; /* paper burns very fast, assume straw is tightly * packed and burns a bit slower */ switch (monsndx(mptr)) { case PM_PAPER_GOLEM: immolate = TRUE; alt = mtmp->mhpmax; break; case PM_STRAW_GOLEM: alt = mtmp->mhpmax / 2; break; case PM_WOOD_GOLEM: alt = mtmp->mhpmax / 4; break; case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break; default: alt = 0; break; } if (alt > num) num = alt; if (thitm(0, mtmp, (struct obj *) 0, num, immolate)) trapkilled = TRUE; else /* we know mhp is at least `num' below mhpmax, so no (mhp > mhpmax) check is needed here */ mtmp->mhpmax -= rn2(num + 1); } if (burnarmor(mtmp) || rn2(3)) { (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); } if (burn_floor_objects(mtmp->mx, mtmp->my, see_it, FALSE) && !see_it && distu(mtmp->mx, mtmp->my) <= 3 * 3) You("smell smoke."); if (is_ice(mtmp->mx, mtmp->my)) melt_ice(mtmp->mx, mtmp->my, (char *) 0); if (see_it) seetrap(trap); break; case PIT: case SPIKED_PIT: fallverb = "falls"; if (is_flyer(mptr) || is_floater(mptr) || (mtmp->wormno && count_wsegs(mtmp) > 5) || is_clinger(mptr)) { if (force_mintrap && !Sokoban) { /* openfallingtrap; not inescapable here */ if (in_sight) { seetrap(trap); pline("%s doesn't fall into the pit.", Monnam(mtmp)); } break; /* inescapable = FALSE; */ } if (!inescapable) break; /* avoids trap */ fallverb = "is dragged"; /* sokoban pit */ } if (!passes_walls(mptr)) mtmp->mtrapped = 1; if (in_sight) { pline("%s %s into %s pit!", Monnam(mtmp), fallverb, a_your[trap->madeby_u]); if (mptr == &mons[PM_PIT_VIPER] || mptr == &mons[PM_PIT_FIEND]) pline("How pitiful. Isn't that the pits?"); seetrap(trap); } mselftouch(mtmp, "Falling, ", FALSE); if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *) 0, rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; break; case HOLE: case TRAPDOOR: if (!Can_fall_thru(&u.uz)) { impossible("mintrap: %ss cannot exist on this level.", defsyms[trap_to_defsym(tt)].explanation); break; /* don't activate it after all */ } if (is_flyer(mptr) || is_floater(mptr) || mptr == &mons[PM_WUMPUS] || (mtmp->wormno && count_wsegs(mtmp) > 5) || mptr->msize >= MZ_HUGE) { if (force_mintrap && !Sokoban) { /* openfallingtrap; not inescapable here */ if (in_sight) { seetrap(trap); if (tt == TRAPDOOR) pline( "A trap door opens, but %s doesn't fall through.", mon_nam(mtmp)); else /* (tt == HOLE) */ pline("%s doesn't fall through the hole.", Monnam(mtmp)); } break; /* inescapable = FALSE; */ } if (inescapable) { /* sokoban hole */ if (in_sight) { pline("%s seems to be yanked down!", Monnam(mtmp)); /* suppress message in mlevel_tele_trap() */ in_sight = FALSE; seetrap(trap); } } else break; } /*FALLTHRU*/ case LEVEL_TELEP: case MAGIC_PORTAL: { int mlev_res; mlev_res = mlevel_tele_trap(mtmp, trap, inescapable, in_sight); if (mlev_res) return mlev_res; break; } case TELEP_TRAP: mtele_trap(mtmp, trap, in_sight); break; case WEB: /* Monster in a web. */ if (webmaker(mptr)) break; if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)) { if (acidic(mptr) || mptr == &mons[PM_GELATINOUS_CUBE] || mptr == &mons[PM_FIRE_ELEMENTAL]) { if (in_sight) pline("%s %s %s spider web!", Monnam(mtmp), (mptr == &mons[PM_FIRE_ELEMENTAL]) ? "burns" : "dissolves", a_your[trap->madeby_u]); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } if (in_sight) { pline("%s flows through %s spider web.", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } break; } tear_web = FALSE; switch (monsndx(mptr)) { case PM_OWLBEAR: /* Eric Backus */ case PM_BUGBEAR: if (!in_sight) { You_hear("the roaring of a confused bear!"); mtmp->mtrapped = 1; break; } /* fall though */ default: if (mptr->mlet == S_GIANT /* exclude baby dragons and relatively short worms */ || (mptr->mlet == S_DRAGON && extra_nasty(mptr)) || (mtmp->wormno && count_wsegs(mtmp) > 5)) { tear_web = TRUE; } else if (in_sight) { pline("%s is caught in %s spider web.", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } mtmp->mtrapped = tear_web ? 0 : 1; break; /* this list is fairly arbitrary; it deliberately excludes wumpus & giant/ettin zombies/mummies */ case PM_TITANOTHERE: case PM_BALUCHITHERIUM: case PM_PURPLE_WORM: case PM_JABBERWOCK: case PM_IRON_GOLEM: case PM_BALROG: case PM_KRAKEN: case PM_MASTODON: case PM_ORION: case PM_NORN: case PM_CYCLOPS: case PM_LORD_SURTUR: tear_web = TRUE; break; } if (tear_web) { if (in_sight) pline("%s tears through %s spider web!", Monnam(mtmp), a_your[trap->madeby_u]); deltrap(trap); newsym(mtmp->mx, mtmp->my); } else if (force_mintrap && !mtmp->mtrapped) { if (in_sight) { pline("%s avoids %s spider web!", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } } break; case STATUE_TRAP: break; case MAGIC_TRAP: /* A magic trap. Monsters usually immune. */ if (!rn2(21)) goto mfiretrap; break; case ANTI_MAGIC: /* similar to hero's case, more or less */ if (!resists_magm(mtmp)) { /* lose spell energy */ if (!mtmp->mcan && (attacktype(mptr, AT_MAGC) || attacktype(mptr, AT_BREA))) { mtmp->mspec_used += d(2, 2); if (in_sight) { seetrap(trap); pline("%s seems lethargic.", Monnam(mtmp)); } } } else { /* take some damage */ int dmgval2 = rnd(4); if ((otmp = MON_WEP(mtmp)) != 0 && otmp->oartifact == ART_MAGICBANE) dmgval2 += rnd(4); for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->oartifact && defends_when_carried(AD_MAGM, otmp)) break; if (otmp) dmgval2 += rnd(4); if (passes_walls(mptr)) dmgval2 = (dmgval2 + 3) / 4; if (in_sight) seetrap(trap); if ((mtmp->mhp -= dmgval2) <= 0) monkilled(mtmp, in_sight ? "compression from an anti-magic field" : (const char *) 0, -AD_MAGM); if (mtmp->mhp <= 0) trapkilled = TRUE; if (see_it) newsym(trap->tx, trap->ty); } break; case LANDMINE: if (rn2(3)) break; /* monsters usually don't set it off */ if (is_flyer(mptr)) { boolean already_seen = trap->tseen; if (in_sight && !already_seen) { pline("A trigger appears in a pile of soil below %s.", mon_nam(mtmp)); seetrap(trap); } if (rn2(3)) break; if (in_sight) { newsym(mtmp->mx, mtmp->my); pline_The("air currents set %s off!", already_seen ? "a land mine" : "it"); } } else if (in_sight) { newsym(mtmp->mx, mtmp->my); pline("KAABLAMM!!! %s triggers %s land mine!", Monnam(mtmp), a_your[trap->madeby_u]); } if (!in_sight) pline("Kaablamm! You hear an explosion in the distance!"); blow_up_landmine(trap); /* explosion might have destroyed a drawbridge; don't dish out more damage if monster is already dead */ if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) trapkilled = TRUE; else { /* monsters recursively fall into new pit */ if (mintrap(mtmp) == 2) trapkilled = TRUE; } /* a boulder may fill the new pit, crushing monster */ fill_pit(trap->tx, trap->ty); if (mtmp->mhp <= 0) trapkilled = TRUE; if (unconscious()) { multi = -1; nomovemsg = "The explosion awakens you!"; } break; case POLY_TRAP: if (resists_magm(mtmp)) { shieldeff(mtmp->mx, mtmp->my); } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE)) /* we're done with mptr but keep it up to date */ mptr = mtmp->data; if (in_sight) seetrap(trap); } break; case ROLLING_BOULDER_TRAP: if (!is_flyer(mptr)) { int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); newsym(mtmp->mx, mtmp->my); if (in_sight) pline("Click! %s triggers %s.", Monnam(mtmp), trap->tseen ? "a rolling boulder trap" : something); if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, trap->launch2.x, trap->launch2.y, style)) { if (in_sight) trap->tseen = TRUE; if (mtmp->mhp <= 0) trapkilled = TRUE; } else { deltrap(trap); newsym(mtmp->mx, mtmp->my); } } break; case VIBRATING_SQUARE: if (see_it && !Blind) { if (in_sight) pline("You see a strange vibration beneath %s %s.", s_suffix(mon_nam(mtmp)), makeplural(mbodypart(mtmp, FOOT))); else pline("You see the ground vibrate in the distance."); seetrap(trap); } break; default: impossible("Some monster encountered a strange trap of type %d.", tt); } } if (trapkilled) return 2; return mtmp->mtrapped; } /* Combine cockatrice checks into single functions to avoid repeating code. */ void instapetrify(str) const char *str; { if (Stone_resistance) return; if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) return; You("turn to stone..."); killer.format = KILLED_BY; if (str != killer.name) Strcpy(killer.name, str ? str : ""); done(STONING); } void minstapetrify(mon, byplayer) struct monst *mon; boolean byplayer; { if (resists_ston(mon)) return; if (poly_when_stoned(mon->data)) { mon_to_stone(mon); return; } /* give a " is slowing down" message and also remove intrinsic speed (comparable to similar effect on the hero) */ mon_adjust_speed(mon, -3, (struct obj *) 0); if (cansee(mon->mx, mon->my)) pline("%s turns to stone.", Monnam(mon)); if (byplayer) { stoned = TRUE; xkilled(mon, 0); } else monstone(mon); } void selftouch(arg) const char *arg; { char kbuf[BUFSZ]; if (uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm]) && !Stone_resistance) { pline("%s touch the %s corpse.", arg, mons[uwep->corpsenm].mname); Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname)); instapetrify(kbuf); /* life-saved; unwield the corpse if we can't handle it */ if (!uarmg && !Stone_resistance) uwepgone(); } /* Or your secondary weapon, if wielded [hypothetical; we don't allow two-weapon combat when either weapon is a corpse] */ if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE && touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance) { pline("%s touch the %s corpse.", arg, mons[uswapwep->corpsenm].mname); Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); instapetrify(kbuf); /* life-saved; unwield the corpse */ if (!uarmg && !Stone_resistance) uswapwepgone(); } } void mselftouch(mon, arg, byplayer) struct monst *mon; const char *arg; boolean byplayer; { struct obj *mwep = MON_WEP(mon); if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm]) && !resists_ston(mon)) { if (cansee(mon->mx, mon->my)) { pline("%s%s touches %s.", arg ? arg : "", arg ? mon_nam(mon) : Monnam(mon), corpse_xname(mwep, (const char *) 0, CXN_PFX_THE)); } minstapetrify(mon, byplayer); /* if life-saved, might not be able to continue wielding */ if (mon->mhp > 0 && !which_armor(mon, W_ARMG) && !resists_ston(mon)) mwepgone(mon); } } /* start levitating */ void float_up() { if (u.utrap) { if (u.utraptype == TT_PIT) { u.utrap = 0; You("float up, out of the pit!"); vision_full_recalc = 1; /* vision limits change */ fill_pit(u.ux, u.uy); } else if (u.utraptype == TT_INFLOOR) { Your("body pulls upward, but your %s are still stuck.", makeplural(body_part(LEG))); } else { You("float up, only your %s is still stuck.", body_part(LEG)); } #if 0 } else if (Is_waterlevel(&u.uz)) { pline("It feels as though you've lost some weight."); #endif } else if (u.uinwater) { spoteffects(TRUE); } else if (u.uswallow) { You(is_animal(u.ustuck->data) ? "float away from the %s." : "spiral up into %s.", is_animal(u.ustuck->data) ? surface(u.ux, u.uy) : mon_nam(u.ustuck)); } else if (Hallucination) { pline("Up, up, and awaaaay! You're walking on air!"); } else if (Is_airlevel(&u.uz)) { You("gain control over your movements."); } else { You("start to float in the air!"); } if (u.usteed && !is_floater(u.usteed->data) && !is_flyer(u.usteed->data)) { if (Lev_at_will) { pline("%s magically floats up!", Monnam(u.usteed)); } else { You("cannot stay on %s.", mon_nam(u.usteed)); dismount_steed(DISMOUNT_GENERIC); } } if (Flying) You("are no longer able to control your flight."); BFlying |= I_SPECIAL; return; } void fill_pit(x, y) int x, y; { struct obj *otmp; struct trap *t; if ((t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) && (otmp = sobj_at(BOULDER, x, y))) { obj_extract_self(otmp); (void) flooreffects(otmp, x, y, "settle"); } } /* stop levitating */ int float_down(hmask, emask) long hmask, emask; /* might cancel timeout */ { register struct trap *trap = (struct trap *) 0; d_level current_dungeon_level; boolean no_msg = FALSE; HLevitation &= ~hmask; ELevitation &= ~emask; if (Levitation) return 0; /* maybe another ring/potion/boots */ if (BLevitation) { /* Levitation is blocked, so hero is not actually floating hence shouldn't have float_down effects and feedback */ float_vs_flight(); /* before nomul() rather than after */ return 0; } nomul(0); /* stop running or resting */ if (BFlying) { /* controlled flight no longer overridden by levitation */ BFlying &= ~I_SPECIAL; if (Flying) { You("have stopped levitating and are now flying."); return 1; } } if (u.uswallow) { You("float down, but you are still %s.", is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); return 1; } if (Punished && !carried(uball) && (is_pool(uball->ox, uball->oy) || ((trap = t_at(uball->ox, uball->oy)) && ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) || (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { u.ux0 = u.ux; u.uy0 = u.uy; u.ux = uball->ox; u.uy = uball->oy; movobj(uchain, uball->ox, uball->oy); newsym(u.ux0, u.uy0); vision_full_recalc = 1; /* in case the hero moved. */ } /* check for falling into pool - added by GAN 10/20/86 */ if (!Flying) { if (!u.uswallow && u.ustuck) { if (sticks(youmonst.data)) You("aren't able to maintain your hold on %s.", mon_nam(u.ustuck)); else pline("Startled, %s can no longer hold you!", mon_nam(u.ustuck)); u.ustuck = 0; } /* kludge alert: * drown() and lava_effects() print various messages almost * every time they're called which conflict with the "fall * into" message below. Thus, we want to avoid printing * confusing, duplicate or out-of-order messages. * Use knowledge of the two routines as a hack -- this * should really be handled differently -dlc */ if (is_pool(u.ux, u.uy) && !Wwalking && !Swimming && !u.uinwater) no_msg = drown(); if (is_lava(u.ux, u.uy)) { (void) lava_effects(); no_msg = TRUE; } } if (!trap) { trap = t_at(u.ux, u.uy); if (Is_airlevel(&u.uz)) { You("begin to tumble in place."); } else if (Is_waterlevel(&u.uz) && !no_msg) { You_feel("heavier."); /* u.uinwater msgs already in spoteffects()/drown() */ } else if (!u.uinwater && !no_msg) { if (!(emask & W_SADDLE)) { if (Sokoban && trap) { /* Justification elsewhere for Sokoban traps is based * on air currents. This is consistent with that. * The unexpected additional force of the air currents * once levitation ceases knocks you off your feet. */ if (Hallucination) pline("Bummer! You've crashed."); else You("fall over."); losehp(rnd(2), "dangerous winds", KILLED_BY); if (u.usteed) dismount_steed(DISMOUNT_FELL); selftouch("As you fall, you"); } else if (u.usteed && (is_floater(u.usteed->data) || is_flyer(u.usteed->data))) { You("settle more firmly in the saddle."); } else if (Hallucination) { pline("Bummer! You've %s.", is_pool(u.ux, u.uy) ? "splashed down" : "hit the ground"); } else { You("float gently to the %s.", surface(u.ux, u.uy)); } } } } /* can't rely on u.uz0 for detecting trap door-induced level change; it gets changed to reflect the new level before we can check it */ assign_level(¤t_dungeon_level, &u.uz); if (trap) { switch (trap->ttyp) { case STATUE_TRAP: break; case HOLE: case TRAPDOOR: if (!Can_fall_thru(&u.uz) || u.ustuck) break; /*FALLTHRU*/ default: if (!u.utrap) /* not already in the trap */ dotrap(trap, 0); } } if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow /* falling through trap door calls goto_level, and goto_level does its own pickup() call */ && on_level(&u.uz, ¤t_dungeon_level)) (void) pickup(1); return 1; } /* shared code for climbing out of a pit */ void climb_pit() { if (!u.utrap || u.utraptype != TT_PIT) return; if (Passes_walls) { /* marked as trapped so they can pick things up */ You("ascend from the pit."); u.utrap = 0; fill_pit(u.ux, u.uy); vision_full_recalc = 1; /* vision limits change */ } else if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) { Your("%s gets stuck in a crevice.", body_part(LEG)); display_nhwindow(WIN_MESSAGE, FALSE); clear_nhwindow(WIN_MESSAGE); You("free your %s.", body_part(LEG)); } else if ((Flying || is_clinger(youmonst.data)) && !Sokoban) { /* eg fell in pit, then poly'd to a flying monster; or used '>' to deliberately enter it */ You("%s from the pit.", Flying ? "fly" : "climb"); u.utrap = 0; fill_pit(u.ux, u.uy); vision_full_recalc = 1; /* vision limits change */ } else if (!(--u.utrap)) { You("%s to the edge of the pit.", (Sokoban && Levitation) ? "struggle against the air currents and float" : u.usteed ? "ride" : "crawl"); fill_pit(u.ux, u.uy); vision_full_recalc = 1; /* vision limits change */ } else if (u.dz || flags.verbose) { if (u.usteed) Norep("%s is still in a pit.", upstart(y_monnam(u.usteed))); else Norep((Hallucination && !rn2(5)) ? "You've fallen, and you can't get up." : "You are still in a pit."); } } STATIC_OVL void dofiretrap(box) struct obj *box; /* null for floor trap */ { boolean see_it = !Blind; int num, alt; /* Bug: for box case, the equivalent of burn_floor_objects() ought * to be done upon its contents. */ if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) { pline("A cascade of steamy bubbles erupts from %s!", the(box ? xname(box) : surface(u.ux, u.uy))); if (Fire_resistance) You("are uninjured."); else losehp(rnd(3), "boiling water", KILLED_BY); return; } pline("A %s %s from %s!", tower_of_flame, box ? "bursts" : "erupts", the(box ? xname(box) : surface(u.ux, u.uy))); if (Fire_resistance) { shieldeff(u.ux, u.uy); num = rn2(2); } else if (Upolyd) { num = d(2, 4); switch (u.umonnum) { case PM_PAPER_GOLEM: alt = u.mhmax; break; case PM_STRAW_GOLEM: alt = u.mhmax / 2; break; case PM_WOOD_GOLEM: alt = u.mhmax / 4; break; case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break; default: alt = 0; break; } if (alt > num) num = alt; if (u.mhmax > mons[u.umonnum].mlevel) u.mhmax -= rn2(min(u.mhmax, num + 1)), context.botl = 1; } else { num = d(2, 4); if (u.uhpmax > u.ulevel) u.uhpmax -= rn2(min(u.uhpmax, num + 1)), context.botl = 1; } if (!num) You("are uninjured."); else losehp(num, tower_of_flame, KILLED_BY_AN); /* fire damage */ burn_away_slime(); if (burnarmor(&youmonst) || rn2(3)) { destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); } if (!box && burn_floor_objects(u.ux, u.uy, see_it, TRUE) && !see_it) You("smell paper burning."); if (is_ice(u.ux, u.uy)) melt_ice(u.ux, u.uy, (char *) 0); } STATIC_OVL void domagictrap() { register int fate = rnd(20); /* What happened to the poor sucker? */ if (fate < 10) { /* Most of the time, it creates some monsters. */ register int cnt = rnd(4); if (!resists_blnd(&youmonst)) { You("are momentarily blinded by a flash of light!"); make_blinded((long) rn1(5, 10), FALSE); if (!Blind) Your1(vision_clears); } else if (!Blind) { You_see("a flash of light!"); } else You_hear("a deafening roar!"); incr_itimeout(&HDeaf, rn1(20, 30)); while (cnt--) (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); } else switch (fate) { case 10: case 11: /* sometimes nothing happens */ break; case 12: /* a flash of fire */ dofiretrap((struct obj *) 0); break; /* odd feelings */ case 13: pline("A shiver runs up and down your %s!", body_part(SPINE)); break; case 14: You_hear(Hallucination ? "the moon howling at you." : "distant howling."); break; case 15: if (on_level(&u.uz, &qstart_level)) You_feel( "%slike the prodigal son.", (flags.female || (Upolyd && is_neuter(youmonst.data))) ? "oddly " : ""); else You("suddenly yearn for %s.", Hallucination ? "Cleveland" : (In_quest(&u.uz) || at_dgn_entrance("The Quest")) ? "your nearby homeland" : "your distant homeland"); break; case 16: Your("pack shakes violently!"); break; case 17: You(Hallucination ? "smell hamburgers." : "smell charred flesh."); break; case 18: You_feel("tired."); break; /* very occasionally something nice happens. */ case 19: { /* tame nearby monsters */ int i, j; struct monst *mtmp; (void) adjattrib(A_CHA, 1, FALSE); for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { if (!isok(u.ux + i, u.uy + j)) continue; mtmp = m_at(u.ux + i, u.uy + j); if (mtmp) (void) tamedog(mtmp, (struct obj *) 0); } break; } case 20: { /* uncurse stuff */ struct obj pseudo; long save_conf = HConfusion; pseudo = zeroobj; /* neither cursed nor blessed, and zero out oextra */ pseudo.otyp = SCR_REMOVE_CURSE; HConfusion = 0L; (void) seffects(&pseudo); HConfusion = save_conf; break; } default: break; } } /* Set an item on fire. * "force" means not to roll a luck-based protection check for the * item. * "x" and "y" are the coordinates to dump the contents of a * container, if it burns up. * * Return whether the object was destroyed. */ boolean fire_damage(obj, force, x, y) struct obj *obj; boolean force; xchar x, y; { int chance; struct obj *otmp, *ncobj; int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */ int dindx; /* object might light in a controlled manner */ if (catch_lit(obj)) return FALSE; if (Is_container(obj)) { switch (obj->otyp) { case ICE_BOX: return FALSE; /* Immune */ case CHEST: chance = 40; break; case LARGE_BOX: chance = 30; break; default: chance = 20; break; } if ((!force && (Luck + 5) > rn2(chance)) || (is_flammable(obj) && obj->oerodeproof)) return FALSE; /* Container is burnt up - dump contents out */ if (in_sight) pline("%s catches fire and burns.", Yname2(obj)); if (Has_contents(obj)) { if (in_sight) pline("Its contents fall out."); for (otmp = obj->cobj; otmp; otmp = ncobj) { ncobj = otmp->nobj; obj_extract_self(otmp); if (!flooreffects(otmp, x, y, "")) place_object(otmp, x, y); } } setnotworn(obj); delobj(obj); return TRUE; } else if (!force && (Luck + 5) > rn2(20)) { /* chance per item of sustaining damage: * max luck (Luck==13): 10% * avg luck (Luck==0): 75% * awful luck (Luck<-4): 100% */ return FALSE; } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) return FALSE; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (in_sight) pline("Smoke rises from %s.", the(xname(obj))); return FALSE; } dindx = (obj->oclass == SCROLL_CLASS) ? 3 : 4; if (in_sight) pline("%s %s.", Yname2(obj), destroy_strings[dindx][(obj->quan > 1L)]); setnotworn(obj); delobj(obj); return TRUE; } else if (obj->oclass == POTION_CLASS) { dindx = (obj->otyp != POT_OIL) ? 1 : 2; if (in_sight) pline("%s %s.", Yname2(obj), destroy_strings[dindx][(obj->quan > 1L)]); setnotworn(obj); delobj(obj); return TRUE; } else if (erode_obj(obj, (char *) 0, ERODE_BURN, EF_DESTROY) == ER_DESTROYED) { return TRUE; } return FALSE; } /* * Apply fire_damage() to an entire chain. * * Return number of objects destroyed. --ALI */ int fire_damage_chain(chain, force, here, x, y) struct obj *chain; boolean force, here; xchar x, y; { struct obj *obj, *nobj; int num = 0; for (obj = chain; obj; obj = nobj) { nobj = here ? obj->nexthere : obj->nobj; if (fire_damage(obj, force, x, y)) ++num; } if (num && (Blind && !couldsee(x, y))) You("smell smoke."); return num; } void acid_damage(obj) struct obj *obj; { /* Scrolls but not spellbooks can be erased by acid. */ struct monst *victim; boolean vismon; if (!obj) return; victim = carried(obj) ? &youmonst : mcarried(obj) ? obj->ocarry : NULL; vismon = victim && (victim != &youmonst) && canseemon(victim); if (obj->greased) { grease_protect(obj, (char *) 0, victim); } else if (obj->oclass == SCROLL_CLASS && obj->otyp != SCR_BLANK_PAPER) { if (obj->otyp != SCR_BLANK_PAPER #ifdef MAIL && obj->otyp != SCR_MAIL #endif ) { if (!Blind) { if (victim == &youmonst) pline("Your %s.", aobjnam(obj, "fade")); else if (vismon) pline("%s %s.", s_suffix(Monnam(victim)), aobjnam(obj, "fade")); } } obj->otyp = SCR_BLANK_PAPER; obj->spe = 0; obj->dknown = 0; } else erode_obj(obj, (char *) 0, ERODE_CORRODE, EF_GREASE | EF_VERBOSE); } /* context for water_damage(), managed by water_damage_chain(); when more than one stack of potions of acid explode while processing a chain of objects, use alternate phrasing after the first message */ static struct h2o_ctx { int dkn_boom, unk_boom; /* track dknown, !dknown separately */ boolean ctx_valid; } acid_ctx = { 0, 0, FALSE }; /* Get an object wet and damage it appropriately. * "ostr", if present, is used instead of the object name in some * messages. * "force" means not to roll luck to protect some objects. * Returns an erosion return value (ER_*) */ int water_damage(obj, ostr, force) struct obj *obj; const char *ostr; boolean force; { if (!obj) return ER_NOTHING; if (snuff_lit(obj)) return ER_DAMAGED; if (!ostr) ostr = cxname(obj); if (obj->otyp == CAN_OF_GREASE && obj->spe > 0) { return ER_NOTHING; } else if (obj->otyp == TOWEL && obj->spe < 7) { wet_a_towel(obj, rnd(7), TRUE); return ER_NOTHING; } else if (obj->greased) { if (!rn2(2)) obj->greased = 0; if (carried(obj)) update_inventory(); return ER_GREASED; } else if (Is_container(obj) && !Is_box(obj) && (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) { if (carried(obj)) pline("Water gets into your %s!", ostr); water_damage_chain(obj->cobj, FALSE); return ER_NOTHING; } else if (!force && (Luck + 5) > rn2(20)) { /* chance per item of sustaining damage: * max luck: 10% * avg luck (Luck==0): 75% * awful luck (Luck<-4): 100% */ return ER_NOTHING; } else if (obj->oclass == SCROLL_CLASS) { #ifdef MAIL if (obj->otyp == SCR_MAIL) return 0; #endif if (carried(obj)) pline("Your %s %s.", ostr, vtense(ostr, "fade")); obj->otyp = SCR_BLANK_PAPER; obj->dknown = 0; obj->spe = 0; if (carried(obj)) update_inventory(); return ER_DAMAGED; } else if (obj->oclass == SPBOOK_CLASS) { if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { pline("Steam rises from %s.", the(xname(obj))); return 0; } if (carried(obj)) pline("Your %s %s.", ostr, vtense(ostr, "fade")); if (obj->otyp == SPE_NOVEL) { obj->novelidx = 0; free_oname(obj); } obj->otyp = SPE_BLANK_PAPER; obj->dknown = 0; if (carried(obj)) update_inventory(); return ER_DAMAGED; } else if (obj->oclass == POTION_CLASS) { if (obj->otyp == POT_ACID) { char *bufp; boolean one = (obj->quan == 1L), update = carried(obj), exploded = FALSE; if (Blind && !carried(obj)) obj->dknown = 0; if (acid_ctx.ctx_valid) exploded = ((obj->dknown ? acid_ctx.dkn_boom : acid_ctx.unk_boom) > 0); /* First message is * "a [potion| potion|potion of acid] explodes" * depending on obj->dknown (potion has been seen) and * objects[POT_ACID].oc_name_known (fully discovered), * or "some {plural version} explode" when relevant. * Second and subsequent messages for same chain and * matching dknown status are * "another [potion| &c] explodes" or plural * variant. */ bufp = simpleonames(obj); pline("%s %s %s!", /* "A potion explodes!" */ !exploded ? (one ? "A" : "Some") : (one ? "Another" : "More"), bufp, vtense(bufp, "explode")); if (acid_ctx.ctx_valid) { if (obj->dknown) acid_ctx.dkn_boom++; else acid_ctx.unk_boom++; } setnotworn(obj); delobj(obj); if (update) update_inventory(); return ER_DESTROYED; } else if (obj->odiluted) { if (carried(obj)) pline("Your %s %s further.", ostr, vtense(ostr, "dilute")); obj->otyp = POT_WATER; obj->dknown = 0; obj->blessed = obj->cursed = 0; obj->odiluted = 0; if (carried(obj)) update_inventory(); return ER_DAMAGED; } else if (obj->otyp != POT_WATER) { if (carried(obj)) pline("Your %s %s.", ostr, vtense(ostr, "dilute")); obj->odiluted++; if (carried(obj)) update_inventory(); return ER_DAMAGED; } } else { return erode_obj(obj, ostr, ERODE_RUST, EF_NONE); } return ER_NOTHING; } void water_damage_chain(obj, here) struct obj *obj; boolean here; { struct obj *otmp; /* initialize acid context: so far, neither seen (dknown) potions of acid nor unseen have exploded during this water damage sequence */ acid_ctx.dkn_boom = acid_ctx.unk_boom = 0; acid_ctx.ctx_valid = TRUE; for (; obj; obj = otmp) { otmp = here ? obj->nexthere : obj->nobj; water_damage(obj, (char *) 0, FALSE); } /* reset acid context */ acid_ctx.dkn_boom = acid_ctx.unk_boom = 0; acid_ctx.ctx_valid = FALSE; } /* * This function is potentially expensive - rolling * inventory list multiple times. Luckily it's seldom needed. * Returns TRUE if disrobing made player unencumbered enough to * crawl out of the current predicament. */ STATIC_OVL boolean emergency_disrobe(lostsome) boolean *lostsome; { int invc = inv_cnt(TRUE); while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) { register struct obj *obj, *otmp = (struct obj *) 0; register int i; /* Pick a random object */ if (invc > 0) { i = rn2(invc); for (obj = invent; obj; obj = obj->nobj) { /* * Undroppables are: body armor, boots, gloves, * amulets, and rings because of the time and effort * in removing them + loadstone and other cursed stuff * for obvious reasons. */ if (!((obj->otyp == LOADSTONE && obj->cursed) || obj == uamul || obj == uleft || obj == uright || obj == ublindf || obj == uarm || obj == uarmc || obj == uarmg || obj == uarmf || obj == uarmu || (obj->cursed && (obj == uarmh || obj == uarms)) || welded(obj))) otmp = obj; /* reached the mark and found some stuff to drop? */ if (--i < 0 && otmp) break; /* else continue */ } } if (!otmp) return FALSE; /* nothing to drop! */ if (otmp->owornmask) remove_worn_item(otmp, FALSE); *lostsome = TRUE; dropx(otmp); invc--; } return TRUE; } /* return TRUE iff player relocated */ boolean drown() { const char *pool_of_water; boolean inpool_ok = FALSE, crawl_ok; int i, x, y; /* happily wading in the same contiguous pool */ if (u.uinwater && is_pool(u.ux - u.dx, u.uy - u.dy) && (Swimming || Amphibious)) { /* water effects on objects every now and then */ if (!rn2(5)) inpool_ok = TRUE; else return FALSE; } if (!u.uinwater) { You("%s into the water%c", Is_waterlevel(&u.uz) ? "plunge" : "fall", Amphibious || Swimming ? '.' : '!'); if (!Swimming && !Is_waterlevel(&u.uz)) You("sink like %s.", Hallucination ? "the Titanic" : "a rock"); } water_damage_chain(invent, FALSE); if (u.umonnum == PM_GREMLIN && rn2(3)) (void) split_mon(&youmonst, (struct monst *) 0); else if (u.umonnum == PM_IRON_GOLEM) { You("rust!"); i = Maybe_Half_Phys(d(2, 6)); if (u.mhmax > i) u.mhmax -= i; losehp(i, "rusting away", KILLED_BY); } if (inpool_ok) return FALSE; if ((i = number_leashed()) > 0) { pline_The("leash%s slip%s loose.", (i > 1) ? "es" : "", (i > 1) ? "" : "s"); unleash_all(); } if (Amphibious || Swimming) { if (Amphibious) { if (flags.verbose) pline("But you aren't drowning."); if (!Is_waterlevel(&u.uz)) { if (Hallucination) Your("keel hits the bottom."); else You("touch bottom."); } } if (Punished) { unplacebc(); placebc(); } vision_recalc(2); /* unsee old position */ u.uinwater = 1; under_water(1); vision_full_recalc = 1; return FALSE; } if ((Teleportation || can_teleport(youmonst.data)) && !Unaware && (Teleport_control || rn2(3) < Luck + 2)) { You("attempt a teleport spell."); /* utcsri!carroll */ if (!level.flags.noteleport) { (void) dotele(); if (!is_pool(u.ux, u.uy)) return TRUE; } else pline_The("attempted teleport spell fails."); } if (u.usteed) { dismount_steed(DISMOUNT_GENERIC); if (!is_pool(u.ux, u.uy)) return TRUE; } crawl_ok = FALSE; x = y = 0; /* lint suppression */ /* if sleeping, wake up now so that we don't crawl out of water while still asleep; we can't do that the same way that waking due to combat is handled; note unmul() clears u.usleep */ if (u.usleep) unmul("Suddenly you wake up!"); /* being doused will revive from fainting */ if (is_fainted()) reset_faint(); /* can't crawl if unable to move (crawl_ok flag stays false) */ if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl; /* look around for a place to crawl to */ for (i = 0; i < 100; i++) { x = rn1(3, u.ux - 1); y = rn1(3, u.uy - 1); if (crawl_destination(x, y)) { crawl_ok = TRUE; goto crawl; } } /* one more scan */ for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) if (crawl_destination(x, y)) { crawl_ok = TRUE; goto crawl; } crawl: if (crawl_ok) { boolean lost = FALSE; /* time to do some strip-tease... */ boolean succ = Is_waterlevel(&u.uz) ? TRUE : emergency_disrobe(&lost); You("try to crawl out of the water."); if (lost) You("dump some of your gear to lose weight..."); if (succ) { pline("Pheew! That was close."); teleds(x, y, TRUE); return TRUE; } /* still too much weight */ pline("But in vain."); } u.uinwater = 1; You("drown."); for (i = 0; i < 5; i++) { /* arbitrary number of loops */ /* killer format and name are reconstructed every iteration because lifesaving resets them */ pool_of_water = waterbody_name(u.ux, u.uy); killer.format = KILLED_BY_AN; /* avoid "drowned in [a] water" */ if (!strcmp(pool_of_water, "water")) pool_of_water = "deep water", killer.format = KILLED_BY; Strcpy(killer.name, pool_of_water); done(DROWNING); /* oops, we're still alive. better get out of the water. */ if (safe_teleds(TRUE)) break; /* successful life-save */ /* nowhere safe to land; repeat drowning loop... */ pline("You're still drowning."); } if (u.uinwater) { u.uinwater = 0; You("find yourself back %s.", Is_waterlevel(&u.uz) ? "in an air bubble" : "on land"); } return TRUE; } void drain_en(n) int n; { if (!u.uenmax) { /* energy is completely gone */ You_feel("momentarily lethargic."); } else { /* throttle further loss a bit when there's not much left to lose */ if (n > u.uenmax || n > u.ulevel) n = rnd(n); You_feel("your magical energy drain away%c", (n > u.uen) ? '!' : '.'); u.uen -= n; if (u.uen < 0) { u.uenmax -= rnd(-u.uen); if (u.uenmax < 0) u.uenmax = 0; u.uen = 0; } context.botl = 1; } } /* disarm a trap */ int dountrap() { if (near_capacity() >= HVY_ENCUMBER) { pline("You're too strained to do that."); return 0; } if ((nohands(youmonst.data) && !webmaker(youmonst.data)) || !youmonst.data->mmove) { pline("And just how do you expect to do that?"); return 0; } else if (u.ustuck && sticks(youmonst.data)) { pline("You'll have to let go of %s first.", mon_nam(u.ustuck)); return 0; } if (u.ustuck || (welded(uwep) && bimanual(uwep))) { Your("%s seem to be too busy for that.", makeplural(body_part(HAND))); return 0; } return untrap(FALSE); } /* Probability of disabling a trap. Helge Hafting */ STATIC_OVL int untrap_prob(ttmp) struct trap *ttmp; { int chance = 3; /* Only spiders know how to deal with webs reliably */ if (ttmp->ttyp == WEB && !webmaker(youmonst.data)) chance = 30; if (Confusion || Hallucination) chance++; if (Blind) chance++; if (Stunned) chance += 2; if (Fumbling) chance *= 2; /* Your own traps are better known than others. */ if (ttmp && ttmp->madeby_u) chance--; if (Role_if(PM_ROGUE)) { if (rn2(2 * MAXULEV) < u.ulevel) chance--; if (u.uhave.questart && chance > 1) chance--; } else if (Role_if(PM_RANGER) && chance > 1) chance--; return rn2(chance); } /* Replace trap with object(s). Helge Hafting */ void cnv_trap_obj(otyp, cnt, ttmp, bury_it) int otyp; int cnt; struct trap *ttmp; boolean bury_it; { struct obj *otmp = mksobj(otyp, TRUE, FALSE); otmp->quan = cnt; otmp->owt = weight(otmp); /* Only dart traps are capable of being poisonous */ if (otyp != DART) otmp->opoisoned = 0; place_object(otmp, ttmp->tx, ttmp->ty); if (bury_it) { /* magical digging first disarms this trap, then will unearth it */ (void) bury_an_obj(otmp, (boolean *) 0); } else { /* Sell your own traps only... */ if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty); stackobj(otmp); } newsym(ttmp->tx, ttmp->ty); if (u.utrap && ttmp->tx == u.ux && ttmp->ty == u.uy) u.utrap = 0; deltrap(ttmp); } /* while attempting to disarm an adjacent trap, we've fallen into it */ STATIC_OVL void move_into_trap(ttmp) struct trap *ttmp; { int bc = 0; xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy; boolean unused; bx = by = cx = cy = 0; /* lint suppression */ /* we know there's no monster in the way, and we're not trapped */ if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE)) { u.ux0 = u.ux, u.uy0 = u.uy; u.ux = x, u.uy = y; u.umoved = TRUE; newsym(u.ux0, u.uy0); vision_recalc(1); check_leash(u.ux0, u.uy0); if (Punished) move_bc(0, bc, bx, by, cx, cy); /* marking the trap unseen forces dotrap() to treat it like a new discovery and prevents pickup() -> look_here() -> check_here() from giving a redundant "there is a here" message when there are objects covering this trap */ ttmp->tseen = 0; /* hack for check_here() */ /* trigger the trap */ spoteffects(TRUE); /* pickup() + dotrap() */ exercise(A_WIS, FALSE); } } /* 0: doesn't even try * 1: tries and fails * 2: succeeds */ STATIC_OVL int try_disarm(ttmp, force_failure) struct trap *ttmp; boolean force_failure; { struct monst *mtmp = m_at(ttmp->tx, ttmp->ty); int ttype = ttmp->ttyp; boolean under_u = (!u.dx && !u.dy); boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB); /* Test for monster first, monsters are displayed instead of trap. */ if (mtmp && (!mtmp->mtrapped || !holdingtrap)) { pline("%s is in the way.", Monnam(mtmp)); return 0; } /* We might be forced to move onto the trap's location. */ if (sobj_at(BOULDER, ttmp->tx, ttmp->ty) && !Passes_walls && !under_u) { There("is a boulder in your way."); return 0; } /* duplicate tight-space checks from test_move */ if (u.dx && u.dy && bad_rock(youmonst.data, u.ux, ttmp->ty) && bad_rock(youmonst.data, ttmp->tx, u.uy)) { if ((invent && (inv_weight() + weight_cap() > 600)) || bigmonst(youmonst.data)) { /* don't allow untrap if they can't get thru to it */ You("are unable to reach the %s!", defsyms[trap_to_defsym(ttype)].explanation); return 0; } } /* untrappable traps are located on the ground. */ if (!can_reach_floor(TRUE)) { if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) rider_cant_reach(); else You("are unable to reach the %s!", defsyms[trap_to_defsym(ttype)].explanation); return 0; } /* Will our hero succeed? */ if (force_failure || untrap_prob(ttmp)) { if (rnl(5)) { pline("Whoops..."); if (mtmp) { /* must be a trap that holds monsters */ if (ttype == BEAR_TRAP) { if (mtmp->mtame) abuse_dog(mtmp); if ((mtmp->mhp -= rnd(4)) <= 0) killed(mtmp); } else if (ttype == WEB) { if (!webmaker(youmonst.data)) { struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB); if (ttmp2) { pline_The( "webbing sticks to you. You're caught too!"); dotrap(ttmp2, NOWEBMSG); if (u.usteed && u.utrap) { /* you, not steed, are trapped */ dismount_steed(DISMOUNT_FELL); } } } else pline("%s remains entangled.", Monnam(mtmp)); } } else if (under_u) { dotrap(ttmp, 0); } else { move_into_trap(ttmp); } } else { pline("%s %s is difficult to %s.", ttmp->madeby_u ? "Your" : under_u ? "This" : "That", defsyms[trap_to_defsym(ttype)].explanation, (ttype == WEB) ? "remove" : "disarm"); } return 1; } return 2; } STATIC_OVL void reward_untrap(ttmp, mtmp) struct trap *ttmp; struct monst *mtmp; { if (!ttmp->madeby_u) { if (rnl(10) < 8 && !mtmp->mpeaceful && !mtmp->msleeping && !mtmp->mfrozen && !mindless(mtmp->data) && mtmp->data->mlet != S_HUMAN) { mtmp->mpeaceful = 1; set_malign(mtmp); /* reset alignment */ pline("%s is grateful.", Monnam(mtmp)); } /* Helping someone out of a trap is a nice thing to do, * A lawful may be rewarded, but not too often. */ if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) { adjalign(1); You_feel("that you did the right thing."); } } } STATIC_OVL int disarm_holdingtrap(ttmp) /* Helge Hafting */ struct trap *ttmp; { struct monst *mtmp; int fails = try_disarm(ttmp, FALSE); if (fails < 2) return fails; /* ok, disarm it. */ /* untrap the monster, if any. There's no need for a cockatrice test, only the trap is touched */ if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { mtmp->mtrapped = 0; You("remove %s %s from %s.", the_your[ttmp->madeby_u], (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing", mon_nam(mtmp)); reward_untrap(ttmp, mtmp); } else { if (ttmp->ttyp == BEAR_TRAP) { You("disarm %s bear trap.", the_your[ttmp->madeby_u]); cnv_trap_obj(BEARTRAP, 1, ttmp, FALSE); } else /* if (ttmp->ttyp == WEB) */ { You("succeed in removing %s web.", the_your[ttmp->madeby_u]); deltrap(ttmp); } } newsym(u.ux + u.dx, u.uy + u.dy); return 1; } STATIC_OVL int disarm_landmine(ttmp) /* Helge Hafting */ struct trap *ttmp; { int fails = try_disarm(ttmp, FALSE); if (fails < 2) return fails; You("disarm %s land mine.", the_your[ttmp->madeby_u]); cnv_trap_obj(LAND_MINE, 1, ttmp, FALSE); return 1; } /* getobj will filter down to cans of grease and known potions of oil */ static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 0 }; /* it may not make much sense to use grease on floor boards, but so what? */ STATIC_OVL int disarm_squeaky_board(ttmp) struct trap *ttmp; { struct obj *obj; boolean bad_tool; int fails; obj = getobj(oil, "untrap with"); if (!obj) return 0; bad_tool = (obj->cursed || ((obj->otyp != POT_OIL || obj->lamplit) && (obj->otyp != CAN_OF_GREASE || !obj->spe))); fails = try_disarm(ttmp, bad_tool); if (fails < 2) return fails; /* successfully used oil or grease to fix squeaky board */ if (obj->otyp == CAN_OF_GREASE) { consume_obj_charge(obj, TRUE); } else { useup(obj); /* oil */ makeknown(POT_OIL); } You("repair the squeaky board."); /* no madeby_u */ deltrap(ttmp); newsym(u.ux + u.dx, u.uy + u.dy); more_experienced(1, 5); newexplevel(); return 1; } /* removes traps that shoot arrows, darts, etc. */ STATIC_OVL int disarm_shooting_trap(ttmp, otyp) struct trap *ttmp; int otyp; { int fails = try_disarm(ttmp, FALSE); if (fails < 2) return fails; You("disarm %s trap.", the_your[ttmp->madeby_u]); cnv_trap_obj(otyp, 50 - rnl(50), ttmp, FALSE); return 1; } /* Is the weight too heavy? * Formula as in near_capacity() & check_capacity() */ STATIC_OVL int try_lift(mtmp, ttmp, wt, stuff) struct monst *mtmp; struct trap *ttmp; int wt; boolean stuff; { int wc = weight_cap(); if (((wt * 2) / wc) >= HVY_ENCUMBER) { pline("%s is %s for you to lift.", Monnam(mtmp), stuff ? "carrying too much" : "too heavy"); if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove && !mindless(mtmp->data) && mtmp->data->mlet != S_HUMAN && rnl(10) < 3) { mtmp->mpeaceful = 1; set_malign(mtmp); /* reset alignment */ pline("%s thinks it was nice of you to try.", Monnam(mtmp)); } return 0; } return 1; } /* Help trapped monster (out of a (spiked) pit) */ STATIC_OVL int help_monster_out(mtmp, ttmp) struct monst *mtmp; struct trap *ttmp; { int wt; struct obj *otmp; boolean uprob; /* * This works when levitating too -- consistent with the ability * to hit monsters while levitating. * * Should perhaps check that our hero has arms/hands at the * moment. Helping can also be done by engulfing... * * Test the monster first - monsters are displayed before traps. */ if (!mtmp->mtrapped) { pline("%s isn't trapped.", Monnam(mtmp)); return 0; } /* Do you have the necessary capacity to lift anything? */ if (check_capacity((char *) 0)) return 1; /* Will our hero succeed? */ if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) { You("try to reach out your %s, but %s backs away skeptically.", makeplural(body_part(ARM)), mon_nam(mtmp)); return 1; } /* is it a cockatrice?... */ if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) { You("grab the trapped %s using your bare %s.", mtmp->data->mname, makeplural(body_part(HAND))); if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) { display_nhwindow(WIN_MESSAGE, FALSE); } else { char kbuf[BUFSZ]; Sprintf(kbuf, "trying to help %s out of a pit", an(mtmp->data->mname)); instapetrify(kbuf); return 1; } } /* need to do cockatrice check first if sleeping or paralyzed */ if (uprob) { You("try to grab %s, but cannot get a firm grasp.", mon_nam(mtmp)); if (mtmp->msleeping) { mtmp->msleeping = 0; pline("%s awakens.", Monnam(mtmp)); } return 1; } You("reach out your %s and grab %s.", makeplural(body_part(ARM)), mon_nam(mtmp)); if (mtmp->msleeping) { mtmp->msleeping = 0; pline("%s awakens.", Monnam(mtmp)); } else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) { /* After such manhandling, perhaps the effect wears off */ mtmp->mcanmove = 1; mtmp->mfrozen = 0; pline("%s stirs.", Monnam(mtmp)); } /* is the monster too heavy? */ wt = inv_weight() + mtmp->data->cwt; if (!try_lift(mtmp, ttmp, wt, FALSE)) return 1; /* is the monster with inventory too heavy? */ for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) wt += otmp->owt; if (!try_lift(mtmp, ttmp, wt, TRUE)) return 1; You("pull %s out of the pit.", mon_nam(mtmp)); mtmp->mtrapped = 0; fill_pit(mtmp->mx, mtmp->my); reward_untrap(ttmp, mtmp); return 1; } int untrap(force) boolean force; { register struct obj *otmp; register int x, y; int ch; struct trap *ttmp; struct monst *mtmp; const char *trapdescr; boolean here, useplural, confused = (Confusion || Hallucination), trap_skipped = FALSE, deal_with_floor_trap; int boxcnt = 0; char the_trap[BUFSZ], qbuf[QBUFSZ]; if (!getdir((char *) 0)) return 0; x = u.ux + u.dx; y = u.uy + u.dy; if (!isok(x, y)) { pline_The("perils lurking there are beyond your grasp."); return 0; } ttmp = t_at(x, y); if (ttmp && !ttmp->tseen) ttmp = 0; trapdescr = ttmp ? defsyms[trap_to_defsym(ttmp->ttyp)].explanation : 0; here = (x == u.ux && y == u.uy); /* !u.dx && !u.dy */ if (here) /* are there are one or more containers here? */ for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { if (++boxcnt > 1) break; } deal_with_floor_trap = can_reach_floor(FALSE); if (!deal_with_floor_trap) { *the_trap = '\0'; if (ttmp) Strcat(the_trap, an(trapdescr)); if (ttmp && boxcnt) Strcat(the_trap, " and "); if (boxcnt) Strcat(the_trap, (boxcnt == 1) ? "a container" : "containers"); useplural = ((ttmp && boxcnt > 0) || boxcnt > 1); /* note: boxcnt and useplural will always be 0 for !here case */ if (ttmp || boxcnt) There("%s %s %s but you can't reach %s%s.", useplural ? "are" : "is", the_trap, here ? "here" : "there", useplural ? "them" : "it", u.usteed ? " while mounted" : ""); trap_skipped = (ttmp != 0); } else { /* deal_with_floor_trap */ if (ttmp) { Strcpy(the_trap, the(trapdescr)); if (boxcnt) { if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { You_cant("do much about %s%s.", the_trap, u.utrap ? " that you're stuck in" : " while standing on the edge of it"); trap_skipped = TRUE; deal_with_floor_trap = FALSE; } else { Sprintf( qbuf, "There %s and %s here. %s %s?", (boxcnt == 1) ? "is a container" : "are containers", an(trapdescr), (ttmp->ttyp == WEB) ? "Remove" : "Disarm", the_trap); switch (ynq(qbuf)) { case 'q': return 0; case 'n': trap_skipped = TRUE; deal_with_floor_trap = FALSE; break; } } } if (deal_with_floor_trap) { if (u.utrap) { You("cannot deal with %s while trapped%s!", the_trap, (x == u.ux && y == u.uy) ? " in it" : ""); return 1; } if ((mtmp = m_at(x, y)) != 0 && (mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT)) { stumble_onto_mimic(mtmp); return 1; } switch (ttmp->ttyp) { case BEAR_TRAP: case WEB: return disarm_holdingtrap(ttmp); case LANDMINE: return disarm_landmine(ttmp); case SQKY_BOARD: return disarm_squeaky_board(ttmp); case DART_TRAP: return disarm_shooting_trap(ttmp, DART); case ARROW_TRAP: return disarm_shooting_trap(ttmp, ARROW); case PIT: case SPIKED_PIT: if (here) { You("are already on the edge of the pit."); return 0; } if (!mtmp) { pline("Try filling the pit instead."); return 0; } return help_monster_out(mtmp, ttmp); default: You("cannot disable %s trap.", !here ? "that" : "this"); return 0; } } } /* end if */ if (boxcnt) { for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { (void) safe_qbuf(qbuf, "There is ", " here. Check it for traps?", otmp, doname, ansimpleoname, "a box"); switch (ynq(qbuf)) { case 'q': return 0; case 'n': continue; } if ((otmp->otrapped && (force || (!confused && rn2(MAXULEV + 1 - u.ulevel) < 10))) || (!force && confused && !rn2(3))) { You("find a trap on %s!", the(xname(otmp))); if (!confused) exercise(A_WIS, TRUE); switch (ynq("Disarm it?")) { case 'q': return 1; case 'n': trap_skipped = TRUE; continue; } if (otmp->otrapped) { exercise(A_DEX, TRUE); ch = ACURR(A_DEX) + u.ulevel; if (Role_if(PM_ROGUE)) ch *= 2; if (!force && (confused || Fumbling || rnd(75 + level_difficulty() / 2) > ch)) { (void) chest_trap(otmp, FINGER, TRUE); } else { You("disarm it!"); otmp->otrapped = 0; } } else pline("That %s was not trapped.", xname(otmp)); return 1; } else { You("find no traps on %s.", the(xname(otmp))); return 1; } } You(trap_skipped ? "find no other traps here." : "know of no traps here."); return 0; } if (stumble_on_door_mimic(x, y)) return 1; } /* deal_with_floor_trap */ /* doors can be manipulated even while levitating/unskilled riding */ if (!IS_DOOR(levl[x][y].typ)) { if (!trap_skipped) You("know of no traps there."); return 0; } switch (levl[x][y].doormask) { case D_NODOOR: You("%s no door there.", Blind ? "feel" : "see"); return 0; case D_ISOPEN: pline("This door is safely open."); return 0; case D_BROKEN: pline("This door is broken."); return 0; } if ((levl[x][y].doormask & D_TRAPPED && (force || (!confused && rn2(MAXULEV - u.ulevel + 11) < 10))) || (!force && confused && !rn2(3))) { You("find a trap on the door!"); exercise(A_WIS, TRUE); if (ynq("Disarm it?") != 'y') return 1; if (levl[x][y].doormask & D_TRAPPED) { ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel * 3 : u.ulevel); exercise(A_DEX, TRUE); if (!force && (confused || Fumbling || rnd(75 + level_difficulty() / 2) > ch)) { You("set it off!"); b_trapped("door", FINGER); levl[x][y].doormask = D_NODOOR; unblock_point(x, y); newsym(x, y); /* (probably ought to charge for this damage...) */ if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); } else { You("disarm it!"); levl[x][y].doormask &= ~D_TRAPPED; } } else pline("This door was not trapped."); return 1; } else { You("find no traps on the door."); return 1; } } /* for magic unlocking; returns true if targetted monster (which might be hero) gets untrapped; the trap remains intact */ boolean openholdingtrap(mon, noticed) struct monst *mon; boolean *noticed; /* set to true iff hero notices the effect; */ { /* otherwise left with its previous value intact */ struct trap *t; char buf[BUFSZ]; const char *trapdescr, *which; boolean ishero = (mon == &youmonst); if (mon == u.usteed) ishero = TRUE; t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); /* if no trap here or it's not a holding trap, we're done */ if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) return FALSE; trapdescr = defsyms[trap_to_defsym(t->ttyp)].explanation; which = t->tseen ? the_your[t->madeby_u] : index(vowels, *trapdescr) ? "an" : "a"; if (ishero) { if (!u.utrap) return FALSE; u.utrap = 0; /* released regardless of type */ *noticed = TRUE; /* give message only if trap was the expected type */ if (u.utraptype == TT_BEARTRAP || u.utraptype == TT_WEB) { if (u.usteed) Sprintf(buf, "%s is", noit_Monnam(u.usteed)); else Strcpy(buf, "You are"); pline("%s released from %s %s.", buf, which, trapdescr); } } else { if (!mon->mtrapped) return FALSE; mon->mtrapped = 0; if (canspotmon(mon)) { *noticed = TRUE; pline("%s is released from %s %s.", Monnam(mon), which, trapdescr); } else if (cansee(t->tx, t->ty) && t->tseen) { *noticed = TRUE; if (t->ttyp == WEB) pline("%s is released from %s %s.", Something, which, trapdescr); else /* BEAR_TRAP */ pline("%s %s opens.", upstart(strcpy(buf, which)), trapdescr); } /* might pacify monster if adjacent */ if (rn2(2) && distu(mon->mx, mon->my) <= 2) reward_untrap(t, mon); } return TRUE; } /* for magic locking; returns true if targetted monster (which might be hero) gets hit by a trap (might avoid actually becoming trapped) */ boolean closeholdingtrap(mon, noticed) struct monst *mon; boolean *noticed; /* set to true iff hero notices the effect; */ { /* otherwise left with its previous value intact */ struct trap *t; unsigned dotrapflags; boolean ishero = (mon == &youmonst), result; if (mon == u.usteed) ishero = TRUE; t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); /* if no trap here or it's not a holding trap, we're done */ if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) return FALSE; if (ishero) { if (u.utrap) return FALSE; /* already trapped */ *noticed = TRUE; dotrapflags = FORCETRAP; /* dotrap calls mintrap when mounted hero encounters a web */ if (u.usteed) dotrapflags |= NOWEBMSG; ++force_mintrap; dotrap(t, dotrapflags); --force_mintrap; result = (u.utrap != 0); } else { if (mon->mtrapped) return FALSE; /* already trapped */ /* you notice it if you see the trap close/tremble/whatever or if you sense the monster who becomes trapped */ *noticed = cansee(t->tx, t->ty) || canspotmon(mon); ++force_mintrap; result = (mintrap(mon) != 0); --force_mintrap; } return result; } /* for magic unlocking; returns true if targetted monster (which might be hero) gets hit by a trap (target might avoid its effect) */ boolean openfallingtrap(mon, trapdoor_only, noticed) struct monst *mon; boolean trapdoor_only; boolean *noticed; /* set to true iff hero notices the effect; */ { /* otherwise left with its previous value intact */ struct trap *t; boolean ishero = (mon == &youmonst), result; if (mon == u.usteed) ishero = TRUE; t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); /* if no trap here or it's not a falling trap, we're done (note: falling rock traps have a trapdoor in the ceiling) */ if (!t || ((t->ttyp != TRAPDOOR && t->ttyp != ROCKTRAP) && (trapdoor_only || (t->ttyp != HOLE && t->ttyp != PIT && t->ttyp != SPIKED_PIT)))) return FALSE; if (ishero) { if (u.utrap) return FALSE; /* already trapped */ *noticed = TRUE; dotrap(t, FORCETRAP); result = (u.utrap != 0); } else { if (mon->mtrapped) return FALSE; /* already trapped */ /* you notice it if you see the trap close/tremble/whatever or if you sense the monster who becomes trapped */ *noticed = cansee(t->tx, t->ty) || canspotmon(mon); /* monster will be angered; mintrap doesn't handle that */ wakeup(mon); ++force_mintrap; result = (mintrap(mon) != 0); --force_mintrap; /* mon might now be on the migrating monsters list */ } return TRUE; } /* only called when the player is doing something to the chest directly */ boolean chest_trap(obj, bodypart, disarm) register struct obj *obj; register int bodypart; boolean disarm; { register struct obj *otmp = obj, *otmp2; char buf[80]; const char *msg; coord cc; if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ obj->ox = cc.x, obj->oy = cc.y; otmp->otrapped = 0; /* trap is one-shot; clear flag first in case chest kills you and ends up in bones file */ You(disarm ? "set it off!" : "trigger a trap!"); display_nhwindow(WIN_MESSAGE, FALSE); if (Luck > -13 && rn2(13 + Luck) > 7) { /* saved by luck */ /* trap went off, but good luck prevents damage */ switch (rn2(13)) { case 12: case 11: msg = "explosive charge is a dud"; break; case 10: case 9: msg = "electric charge is grounded"; break; case 8: case 7: msg = "flame fizzles out"; break; case 6: case 5: case 4: msg = "poisoned needle misses"; break; case 3: case 2: case 1: case 0: msg = "gas cloud blows away"; break; default: impossible("chest disarm bug"); msg = (char *) 0; break; } if (msg) pline("But luckily the %s!", msg); } else { switch (rn2(20) ? ((Luck >= 13) ? 0 : rn2(13 - Luck)) : rn2(26)) { case 25: case 24: case 23: case 22: case 21: { struct monst *shkp = 0; long loss = 0L; boolean costly, insider; register xchar ox = obj->ox, oy = obj->oy; /* the obj location need not be that of player */ costly = (costly_spot(ox, oy) && (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))) != (struct monst *) 0); insider = (*u.ushops && inside_shop(u.ux, u.uy) && *in_rooms(ox, oy, SHOPBASE) == *u.ushops); pline("%s!", Tobjnam(obj, "explode")); Sprintf(buf, "exploding %s", xname(obj)); if (costly) loss += stolen_value(obj, ox, oy, (boolean) shkp->mpeaceful, TRUE); delete_contents(obj); /* we're about to delete all things at this location, * which could include the ball & chain. * If we attempt to call unpunish() in the * for-loop below we can end up with otmp2 * being invalid once the chain is gone. * Deal with ball & chain right now instead. */ if (Punished && !carried(uball) && ((uchain->ox == u.ux && uchain->oy == u.uy) || (uball->ox == u.ux && uball->oy == u.uy))) unpunish(); for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (costly) loss += stolen_value(otmp, otmp->ox, otmp->oy, (boolean) shkp->mpeaceful, TRUE); delobj(otmp); } wake_nearby(); losehp(Maybe_Half_Phys(d(6, 6)), buf, KILLED_BY_AN); exercise(A_STR, FALSE); if (costly && loss) { if (insider) You("owe %ld %s for objects destroyed.", loss, currency(loss)); else { You("caused %ld %s worth of damage!", loss, currency(loss)); make_angry_shk(shkp, ox, oy); } } return TRUE; } /* case 21 */ case 20: case 19: case 18: case 17: pline("A cloud of noxious gas billows from %s.", the(xname(obj))); poisoned("gas cloud", A_STR, "cloud of poison gas", 15, FALSE); exercise(A_CON, FALSE); break; case 16: case 15: case 14: case 13: You_feel("a needle prick your %s.", body_part(bodypart)); poisoned("needle", A_CON, "poisoned needle", 10, FALSE); exercise(A_CON, FALSE); break; case 12: case 11: case 10: case 9: dofiretrap(obj); break; case 8: case 7: case 6: { int dmg; You("are jolted by a surge of electricity!"); if (Shock_resistance) { shieldeff(u.ux, u.uy); You("don't seem to be affected."); dmg = 0; } else dmg = d(4, 4); destroy_item(RING_CLASS, AD_ELEC); destroy_item(WAND_CLASS, AD_ELEC); if (dmg) losehp(dmg, "electric shock", KILLED_BY_AN); break; } /* case 6 */ case 5: case 4: case 3: if (!Free_action) { pline("Suddenly you are frozen in place!"); nomul(-d(5, 6)); multi_reason = "frozen by a trap"; exercise(A_DEX, FALSE); nomovemsg = You_can_move_again; } else You("momentarily stiffen."); break; case 2: case 1: case 0: pline("A cloud of %s gas billows from %s.", Blind ? blindgas[rn2(SIZE(blindgas))] : rndcolor(), the(xname(obj))); if (!Stunned) { if (Hallucination) pline("What a groovy feeling!"); else You("%s%s...", stagger(youmonst.data, "stagger"), Halluc_resistance ? "" : Blind ? " and get dizzy" : " and your vision blurs"); } make_stunned((HStun & TIMEOUT) + (long) rn1(7, 16), FALSE); (void) make_hallucinated( (HHallucination & TIMEOUT) + (long) rn1(5, 16), FALSE, 0L); break; default: impossible("bad chest trap"); break; } bot(); /* to get immediate botl re-display */ } return FALSE; } struct trap * t_at(x, y) register int x, y; { register struct trap *trap = ftrap; while (trap) { if (trap->tx == x && trap->ty == y) return trap; trap = trap->ntrap; } return (struct trap *) 0; } void deltrap(trap) register struct trap *trap; { register struct trap *ttmp; clear_conjoined_pits(trap); if (trap == ftrap) { ftrap = ftrap->ntrap; } else { for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) if (ttmp->ntrap == trap) break; if (!ttmp) panic("deltrap: no preceding trap!"); ttmp->ntrap = trap->ntrap; } if (Sokoban && (trap->ttyp == PIT || trap->ttyp == HOLE)) maybe_finish_sokoban(); dealloc_trap(trap); } boolean conjoined_pits(trap2, trap1, u_entering_trap2) struct trap *trap2, *trap1; boolean u_entering_trap2; { int dx, dy, diridx, adjidx; if (!trap1 || !trap2) return FALSE; if (!isok(trap2->tx, trap2->ty) || !isok(trap1->tx, trap1->ty) || !(trap2->ttyp == PIT || trap2->ttyp == SPIKED_PIT) || !(trap1->ttyp == PIT || trap1->ttyp == SPIKED_PIT) || (u_entering_trap2 && !(u.utrap && u.utraptype == TT_PIT))) return FALSE; dx = sgn(trap2->tx - trap1->tx); dy = sgn(trap2->ty - trap1->ty); for (diridx = 0; diridx < 8; diridx++) if (xdir[diridx] == dx && ydir[diridx] == dy) break; /* diridx is valid if < 8 */ if (diridx < 8) { adjidx = (diridx + 4) % 8; if ((trap1->conjoined & (1 << diridx)) && (trap2->conjoined & (1 << adjidx))) return TRUE; } return FALSE; } void clear_conjoined_pits(trap) struct trap *trap; { int diridx, adjidx, x, y; struct trap *t; if (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { for (diridx = 0; diridx < 8; ++diridx) { if (trap->conjoined & (1 << diridx)) { x = trap->tx + xdir[diridx]; y = trap->ty + ydir[diridx]; if (isok(x, y) && (t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { adjidx = (diridx + 4) % 8; t->conjoined &= ~(1 << adjidx); } trap->conjoined &= ~(1 << diridx); } } } } #if 0 /* * Mark all neighboring pits as conjoined pits. * (currently not called from anywhere) */ STATIC_OVL void join_adjacent_pits(trap) struct trap *trap; { struct trap *t; int diridx, x, y; if (!trap) return; for (diridx = 0; diridx < 8; ++diridx) { x = trap->tx + xdir[diridx]; y = trap->ty + ydir[diridx]; if (isok(x, y)) { if ((t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { trap->conjoined |= (1 << diridx); join_adjacent_pits(t); } else trap->conjoined &= ~(1 << diridx); } } } #endif /*0*/ /* * Returns TRUE if you escaped a pit and are standing on the precipice. */ boolean uteetering_at_seen_pit(trap) struct trap *trap; { if (trap && trap->tseen && (!u.utrap || u.utraptype != TT_PIT) && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) return TRUE; else return FALSE; } /* Destroy a trap that emanates from the floor. */ boolean delfloortrap(ttmp) register struct trap *ttmp; { /* some of these are arbitrary -dlc */ if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || (ttmp->ttyp == BEAR_TRAP) || (ttmp->ttyp == LANDMINE) || (ttmp->ttyp == FIRE_TRAP) || (ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT) || (ttmp->ttyp == HOLE) || (ttmp->ttyp == TRAPDOOR) || (ttmp->ttyp == TELEP_TRAP) || (ttmp->ttyp == LEVEL_TELEP) || (ttmp->ttyp == WEB) || (ttmp->ttyp == MAGIC_TRAP) || (ttmp->ttyp == ANTI_MAGIC))) { register struct monst *mtmp; if (ttmp->tx == u.ux && ttmp->ty == u.uy) { u.utrap = 0; u.utraptype = 0; } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { mtmp->mtrapped = 0; } deltrap(ttmp); return TRUE; } return FALSE; } /* used for doors (also tins). can be used for anything else that opens. */ void b_trapped(item, bodypart) const char *item; int bodypart; { int lvl = level_difficulty(), dmg = rnd(5 + (lvl < 5 ? lvl : 2 + lvl / 2)); pline("KABOOM!! %s was booby-trapped!", The(item)); wake_nearby(); losehp(Maybe_Half_Phys(dmg), "explosion", KILLED_BY_AN); exercise(A_STR, FALSE); if (bodypart) exercise(A_CON, FALSE); make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE); } /* Monster is hit by trap. */ /* Note: doesn't work if both obj and d_override are null */ STATIC_OVL boolean thitm(tlev, mon, obj, d_override, nocorpse) int tlev; struct monst *mon; struct obj *obj; int d_override; boolean nocorpse; { int strike; boolean trapkilled = FALSE; if (d_override) strike = 1; else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20)); else strike = (find_mac(mon) + tlev <= rnd(20)); /* Actually more accurate than thitu, which doesn't take * obj->spe into account. */ if (!strike) { if (obj && cansee(mon->mx, mon->my)) pline("%s is almost hit by %s!", Monnam(mon), doname(obj)); } else { int dam = 1; if (obj && cansee(mon->mx, mon->my)) pline("%s is hit by %s!", Monnam(mon), doname(obj)); if (d_override) dam = d_override; else if (obj) { dam = dmgval(obj, mon); if (dam < 1) dam = 1; } if ((mon->mhp -= dam) <= 0) { int xx = mon->mx; int yy = mon->my; monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); if (mon->mhp <= 0) { newsym(xx, yy); trapkilled = TRUE; } } } if (obj && (!strike || d_override)) { place_object(obj, mon->mx, mon->my); stackobj(obj); } else if (obj) dealloc_obj(obj); return trapkilled; } boolean unconscious() { if (multi >= 0) return FALSE; return (boolean) (u.usleep || (nomovemsg && (!strncmp(nomovemsg, "You awake", 9) || !strncmp(nomovemsg, "You regain con", 14) || !strncmp(nomovemsg, "You are consci", 14)))); } static const char lava_killer[] = "molten lava"; boolean lava_effects() { register struct obj *obj, *obj2; int dmg = d(6, 6); /* only applicable for water walking */ boolean usurvive, boil_away; burn_away_slime(); if (likes_lava(youmonst.data)) return FALSE; usurvive = Fire_resistance || (Wwalking && dmg < u.uhp); /* * A timely interrupt might manage to salvage your life * but not your gear. For scrolls and potions this * will destroy whole stacks, where fire resistant hero * survivor only loses partial stacks via destroy_item(). * * Flag items to be destroyed before any messages so * that player causing hangup at --More-- won't get an * emergency save file created before item destruction. */ if (!usurvive) for (obj = invent; obj; obj = obj->nobj) if ((is_organic(obj) || obj->oclass == POTION_CLASS) && !obj->oerodeproof && objects[obj->otyp].oc_oprop != FIRE_RES && obj->otyp != SCR_FIRE && obj->otyp != SPE_FIREBALL && !obj_resists(obj, 0, 0)) /* for invocation items */ obj->in_use = TRUE; /* Check whether we should burn away boots *first* so we know whether to * make the player sink into the lava. Assumption: water walking only * comes from boots. */ if (Wwalking && uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { obj = uarmf; pline("%s into flame!", Yobjnam2(obj, "burst")); iflags.in_lava_effects++; /* (see above) */ (void) Boots_off(); useup(obj); iflags.in_lava_effects--; } if (!Fire_resistance) { if (Wwalking) { pline_The("lava here burns you!"); if (usurvive) { losehp(dmg, lava_killer, KILLED_BY); /* lava damage */ goto burn_stuff; } } else You("fall into the lava!"); usurvive = Lifesaved || discover; if (wizard) usurvive = TRUE; /* prevent remove_worn_item() -> Boots_off(WATER_WALKING_BOOTS) -> spoteffects() -> lava_effects() recursion which would successfully delete (via useupall) the no-longer-worn boots; once recursive call returned, we would try to delete them again here in the outer call (and access stale memory, probably panic) */ iflags.in_lava_effects++; for (obj = invent; obj; obj = obj2) { obj2 = obj->nobj; /* above, we set in_use for objects which are to be destroyed */ if (obj->otyp == SPE_BOOK_OF_THE_DEAD && !Blind) { if (usurvive) pline("%s glows a strange %s, but remains intact.", The(xname(obj)), hcolor("dark red")); } else if (obj->in_use) { if (obj->owornmask) { if (usurvive) pline("%s into flame!", Yobjnam2(obj, "burst")); remove_worn_item(obj, TRUE); } useupall(obj); } } iflags.in_lava_effects--; /* s/he died... */ boil_away = (u.umonnum == PM_WATER_ELEMENTAL || u.umonnum == PM_STEAM_VORTEX || u.umonnum == PM_FOG_CLOUD); for (;;) { u.uhp = -1; /* killer format and name are reconstructed every iteration because lifesaving resets them */ killer.format = KILLED_BY; Strcpy(killer.name, lava_killer); You("%s...", boil_away ? "boil away" : "burn to a crisp"); done(BURNING); if (safe_teleds(TRUE)) break; /* successful life-save */ /* nowhere safe to land; repeat burning loop */ pline("You're still burning."); } You("find yourself back on solid %s.", surface(u.ux, u.uy)); return TRUE; } else if (!Wwalking && (!u.utrap || u.utraptype != TT_LAVA)) { boil_away = !Fire_resistance; /* if not fire resistant, sink_into_lava() will quickly be fatal; hero needs to escape immediately */ u.utrap = rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8); u.utraptype = TT_LAVA; You("sink into the lava%s!", !boil_away ? ", but it only burns slightly" : " and are about to be immolated"); if (u.uhp > 1) losehp(!boil_away ? 1 : (u.uhp / 2), lava_killer, KILLED_BY); /* lava damage */ } burn_stuff: destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); return FALSE; } /* called each turn when trapped in lava */ void sink_into_lava() { static const char sink_deeper[] = "You sink deeper into the lava."; if (!u.utrap || u.utraptype != TT_LAVA) { ; /* do nothing; this shouldn't happen */ } else if (!is_lava(u.ux, u.uy)) { u.utrap = 0; /* this shouldn't happen either */ } else if (!u.uinvulnerable) { /* ordinarily we'd have to be fire resistant to survive long enough to become stuck in lava, but it can happen without resistance if water walking boots allow survival and then get burned up; u.utrap time will be quite short in that case */ if (!Fire_resistance) u.uhp = (u.uhp + 2) / 3; u.utrap -= (1 << 8); if (u.utrap < (1 << 8)) { killer.format = KILLED_BY; Strcpy(killer.name, "molten lava"); You("sink below the surface and die."); burn_away_slime(); /* add insult to injury? */ done(DISSOLVED); } else if (!u.umoved) { /* can't fully turn into slime while in lava, but might not have it be burned away until you've come awfully close */ if (Slimed && rnd(10 - 1) >= (int) (Slimed & TIMEOUT)) { pline(sink_deeper); burn_away_slime(); } else { Norep(sink_deeper); } u.utrap += rnd(4); } } } /* called when something has been done (breaking a boulder, for instance) which entails a luck penalty if performed on a sokoban level */ void sokoban_guilt() { if (Sokoban) { change_luck(-1); /* TODO: issue some feedback so that player can learn that whatever he/she just did is a naughty thing to do in sokoban and should probably be avoided in future.... Caveat: doing this might introduce message sequencing issues, depending upon feedback during the various actions which trigger Sokoban luck penalties. */ } } /* called when a trap has been deleted or had its ttyp replaced */ STATIC_OVL void maybe_finish_sokoban() { struct trap *t; if (Sokoban && !in_mklev) { /* scan all remaining traps, ignoring any created by the hero; if this level has no more pits or holes, the current sokoban puzzle has been solved */ for (t = ftrap; t; t = t->ntrap) { if (t->madeby_u) continue; if (t->ttyp == PIT || t->ttyp == HOLE) break; } if (!t) { /* we've passed the last trap without finding a pit or hole; clear the sokoban_rules flag so that luck penalties for things like breaking boulders or jumping will no longer be given, and restrictions on diagonal moves are lifted */ Sokoban = 0; /* clear level.flags.sokoban_rules */ /* TODO: give some feedback about solving the sokoban puzzle (perhaps say "congratulations" in Japanese?) */ } } } /*trap.c*/ nethack-3.6.0/src/u_init.c0000664000076400007660000011135312623162643014370 0ustar paxedpaxed/* NetHack 3.6 u_init.c $NHDT-Date: 1446861772 2015/11/07 02:02:52 $ $NHDT-Branch: master $:$NHDT-Revision: 1.35 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" struct trobj { short trotyp; schar trspe; char trclass; Bitfield(trquan, 6); Bitfield(trbless, 2); }; STATIC_DCL void FDECL(ini_inv, (struct trobj *)); STATIC_DCL void FDECL(knows_object, (int)); STATIC_DCL void FDECL(knows_class, (CHAR_P)); STATIC_DCL boolean FDECL(restricted_spell_discipline, (int)); #define UNDEF_TYP 0 #define UNDEF_SPE '\177' #define UNDEF_BLESS 2 /* * Initial inventory for the various roles. */ static struct trobj Archeologist[] = { /* if adventure has a name... idea from tan@uvm-gen */ { BULLWHIP, 2, WEAPON_CLASS, 1, UNDEF_BLESS }, { LEATHER_JACKET, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { FEDORA, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 3, 0 }, { PICK_AXE, UNDEF_SPE, TOOL_CLASS, 1, UNDEF_BLESS }, { TINNING_KIT, UNDEF_SPE, TOOL_CLASS, 1, UNDEF_BLESS }, { TOUCHSTONE, 0, GEM_CLASS, 1, 0 }, { SACK, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Barbarian[] = { #define B_MAJOR 0 /* two-handed sword or battle-axe */ #define B_MINOR 1 /* matched with axe or short sword */ { TWO_HANDED_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { AXE, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { RING_MAIL, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Cave_man[] = { #define C_AMMO 2 { CLUB, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { SLING, 2, WEAPON_CLASS, 1, UNDEF_BLESS }, { FLINT, 0, GEM_CLASS, 15, UNDEF_BLESS }, /* quan is variable */ { ROCK, 0, GEM_CLASS, 3, 0 }, /* yields 18..33 */ { LEATHER_ARMOR, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Healer[] = { { SCALPEL, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { LEATHER_GLOVES, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { STETHOSCOPE, 0, TOOL_CLASS, 1, 0 }, { POT_HEALING, 0, POTION_CLASS, 4, UNDEF_BLESS }, { POT_EXTRA_HEALING, 0, POTION_CLASS, 4, UNDEF_BLESS }, { WAN_SLEEP, UNDEF_SPE, WAND_CLASS, 1, UNDEF_BLESS }, /* always blessed, so it's guaranteed readable */ { SPE_HEALING, 0, SPBOOK_CLASS, 1, 1 }, { SPE_EXTRA_HEALING, 0, SPBOOK_CLASS, 1, 1 }, { SPE_STONE_TO_FLESH, 0, SPBOOK_CLASS, 1, 1 }, { APPLE, 0, FOOD_CLASS, 5, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Knight[] = { { LONG_SWORD, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { LANCE, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { RING_MAIL, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { HELMET, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { SMALL_SHIELD, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { LEATHER_GLOVES, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { APPLE, 0, FOOD_CLASS, 10, 0 }, { CARROT, 0, FOOD_CLASS, 10, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Monk[] = { #define M_BOOK 2 { LEATHER_GLOVES, 2, ARMOR_CLASS, 1, UNDEF_BLESS }, { ROBE, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 1, 1 }, { UNDEF_TYP, UNDEF_SPE, SCROLL_CLASS, 1, UNDEF_BLESS }, { POT_HEALING, 0, POTION_CLASS, 3, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 3, 0 }, { APPLE, 0, FOOD_CLASS, 5, UNDEF_BLESS }, { ORANGE, 0, FOOD_CLASS, 5, UNDEF_BLESS }, /* Yes, we know fortune cookies aren't really from China. They were * invented by George Jung in Los Angeles, California, USA in 1916. */ { FORTUNE_COOKIE, 0, FOOD_CLASS, 3, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Priest[] = { { MACE, 1, WEAPON_CLASS, 1, 1 }, { ROBE, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { SMALL_SHIELD, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { POT_WATER, 0, POTION_CLASS, 4, 1 }, /* holy water */ { CLOVE_OF_GARLIC, 0, FOOD_CLASS, 1, 0 }, { SPRIG_OF_WOLFSBANE, 0, FOOD_CLASS, 1, 0 }, { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 2, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Ranger[] = { #define RAN_BOW 1 #define RAN_TWO_ARROWS 2 #define RAN_ZERO_ARROWS 3 { DAGGER, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { BOW, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { ARROW, 2, WEAPON_CLASS, 50, UNDEF_BLESS }, { ARROW, 0, WEAPON_CLASS, 30, UNDEF_BLESS }, { CLOAK_OF_DISPLACEMENT, 2, ARMOR_CLASS, 1, UNDEF_BLESS }, { CRAM_RATION, 0, FOOD_CLASS, 4, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Rogue[] = { #define R_DAGGERS 1 { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { DAGGER, 0, WEAPON_CLASS, 10, 0 }, /* quan is variable */ { LEATHER_ARMOR, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { POT_SICKNESS, 0, POTION_CLASS, 1, 0 }, { LOCK_PICK, 9, TOOL_CLASS, 1, 0 }, { SACK, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Samurai[] = { #define S_ARROWS 3 { KATANA, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, /* wakizashi */ { YUMI, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { YA, 0, WEAPON_CLASS, 25, UNDEF_BLESS }, /* variable quan */ { SPLINT_MAIL, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Tourist[] = { #define T_DARTS 0 { DART, 2, WEAPON_CLASS, 25, UNDEF_BLESS }, /* quan is variable */ { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 10, 0 }, { POT_EXTRA_HEALING, 0, POTION_CLASS, 2, UNDEF_BLESS }, { SCR_MAGIC_MAPPING, 0, SCROLL_CLASS, 4, UNDEF_BLESS }, { HAWAIIAN_SHIRT, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { EXPENSIVE_CAMERA, UNDEF_SPE, TOOL_CLASS, 1, 0 }, { CREDIT_CARD, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Valkyrie[] = { { LONG_SWORD, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { DAGGER, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { SMALL_SHIELD, 3, ARMOR_CLASS, 1, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Wizard[] = { #define W_MULTSTART 2 #define W_MULTEND 6 { QUARTERSTAFF, 1, WEAPON_CLASS, 1, 1 }, { CLOAK_OF_MAGIC_RESISTANCE, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, WAND_CLASS, 1, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, RING_CLASS, 2, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, POTION_CLASS, 3, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, SCROLL_CLASS, 3, UNDEF_BLESS }, { SPE_FORCE_BOLT, 0, SPBOOK_CLASS, 1, 1 }, { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 1, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; /* * Optional extra inventory items. */ static struct trobj Tinopener[] = { { TIN_OPENER, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Magicmarker[] = { { MAGIC_MARKER, UNDEF_SPE, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Lamp[] = { { OIL_LAMP, 1, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Blindfold[] = { { BLINDFOLD, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Instrument[] = { { WOODEN_FLUTE, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Xtra_food[] = { { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 2, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Leash[] = { { LEASH, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Towel[] = { { TOWEL, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Wishing[] = { { WAN_WISHING, 3, WAND_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Money[] = { { GOLD_PIECE, 0, COIN_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; /* race-based substitutions for initial inventory; the weaker cloak for elven rangers is intentional--they shoot better */ static struct inv_sub { short race_pm, item_otyp, subs_otyp; } inv_subs[] = { { PM_ELF, DAGGER, ELVEN_DAGGER }, { PM_ELF, SPEAR, ELVEN_SPEAR }, { PM_ELF, SHORT_SWORD, ELVEN_SHORT_SWORD }, { PM_ELF, BOW, ELVEN_BOW }, { PM_ELF, ARROW, ELVEN_ARROW }, { PM_ELF, HELMET, ELVEN_LEATHER_HELM }, /* { PM_ELF, SMALL_SHIELD, ELVEN_SHIELD }, */ { PM_ELF, CLOAK_OF_DISPLACEMENT, ELVEN_CLOAK }, { PM_ELF, CRAM_RATION, LEMBAS_WAFER }, { PM_ORC, DAGGER, ORCISH_DAGGER }, { PM_ORC, SPEAR, ORCISH_SPEAR }, { PM_ORC, SHORT_SWORD, ORCISH_SHORT_SWORD }, { PM_ORC, BOW, ORCISH_BOW }, { PM_ORC, ARROW, ORCISH_ARROW }, { PM_ORC, HELMET, ORCISH_HELM }, { PM_ORC, SMALL_SHIELD, ORCISH_SHIELD }, { PM_ORC, RING_MAIL, ORCISH_RING_MAIL }, { PM_ORC, CHAIN_MAIL, ORCISH_CHAIN_MAIL }, { PM_DWARF, SPEAR, DWARVISH_SPEAR }, { PM_DWARF, SHORT_SWORD, DWARVISH_SHORT_SWORD }, { PM_DWARF, HELMET, DWARVISH_IRON_HELM }, /* { PM_DWARF, SMALL_SHIELD, DWARVISH_ROUNDSHIELD }, */ /* { PM_DWARF, PICK_AXE, DWARVISH_MATTOCK }, */ { PM_GNOME, BOW, CROSSBOW }, { PM_GNOME, ARROW, CROSSBOW_BOLT }, { NON_PM, STRANGE_OBJECT, STRANGE_OBJECT } }; static const struct def_skill Skill_A[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_BASIC }, { P_PICK_AXE, P_EXPERT }, { P_SHORT_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_EXPERT }, { P_CLUB, P_SKILLED }, { P_QUARTERSTAFF, P_SKILLED }, { P_SLING, P_SKILLED }, { P_DART, P_BASIC }, { P_BOOMERANG, P_EXPERT }, { P_WHIP, P_EXPERT }, { P_UNICORN_HORN, P_SKILLED }, { P_ATTACK_SPELL, P_BASIC }, { P_HEALING_SPELL, P_BASIC }, { P_DIVINATION_SPELL, P_EXPERT }, { P_MATTER_SPELL, P_BASIC }, { P_RIDING, P_BASIC }, { P_TWO_WEAPON_COMBAT, P_BASIC }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_B[] = { { P_DAGGER, P_BASIC }, { P_AXE, P_EXPERT }, { P_PICK_AXE, P_SKILLED }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_SKILLED }, { P_TWO_HANDED_SWORD, P_EXPERT }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_SKILLED }, { P_MORNING_STAR, P_SKILLED }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_BASIC }, { P_SPEAR, P_SKILLED }, { P_TRIDENT, P_SKILLED }, { P_BOW, P_BASIC }, { P_ATTACK_SPELL, P_SKILLED }, { P_RIDING, P_BASIC }, { P_TWO_WEAPON_COMBAT, P_BASIC }, { P_BARE_HANDED_COMBAT, P_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_C[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_CLUB, P_EXPERT }, { P_MACE, P_EXPERT }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_SKILLED }, { P_HAMMER, P_SKILLED }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_EXPERT }, { P_TRIDENT, P_SKILLED }, { P_BOW, P_SKILLED }, { P_SLING, P_EXPERT }, { P_ATTACK_SPELL, P_BASIC }, { P_MATTER_SPELL, P_SKILLED }, { P_BOOMERANG, P_EXPERT }, { P_UNICORN_HORN, P_BASIC }, { P_BARE_HANDED_COMBAT, P_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_H[] = { { P_DAGGER, P_SKILLED }, { P_KNIFE, P_EXPERT }, { P_SHORT_SWORD, P_SKILLED }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_BASIC }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_BASIC }, { P_SPEAR, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_SLING, P_SKILLED }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_SKILLED }, { P_UNICORN_HORN, P_EXPERT }, { P_HEALING_SPELL, P_EXPERT }, { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; static const struct def_skill Skill_K[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_BASIC }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_SKILLED }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_SKILLED }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_SKILLED }, { P_CLUB, P_BASIC }, { P_MACE, P_SKILLED }, { P_MORNING_STAR, P_SKILLED }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_TRIDENT, P_BASIC }, { P_LANCE, P_EXPERT }, { P_BOW, P_BASIC }, { P_CROSSBOW, P_SKILLED }, { P_ATTACK_SPELL, P_SKILLED }, { P_HEALING_SPELL, P_SKILLED }, { P_CLERIC_SPELL, P_SKILLED }, { P_RIDING, P_EXPERT }, { P_TWO_WEAPON_COMBAT, P_SKILLED }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_Mon[] = { { P_QUARTERSTAFF, P_BASIC }, { P_SPEAR, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_SHURIKEN, P_BASIC }, { P_ATTACK_SPELL, P_BASIC }, { P_HEALING_SPELL, P_EXPERT }, { P_DIVINATION_SPELL, P_BASIC }, { P_ENCHANTMENT_SPELL, P_BASIC }, { P_CLERIC_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_SKILLED }, { P_MATTER_SPELL, P_BASIC }, { P_MARTIAL_ARTS, P_GRAND_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_P[] = { { P_CLUB, P_EXPERT }, { P_MACE, P_EXPERT }, { P_MORNING_STAR, P_EXPERT }, { P_FLAIL, P_EXPERT }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_TRIDENT, P_SKILLED }, { P_LANCE, P_BASIC }, { P_BOW, P_BASIC }, { P_SLING, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_DART, P_BASIC }, { P_SHURIKEN, P_BASIC }, { P_BOOMERANG, P_BASIC }, { P_UNICORN_HORN, P_SKILLED }, { P_HEALING_SPELL, P_EXPERT }, { P_DIVINATION_SPELL, P_EXPERT }, { P_CLERIC_SPELL, P_EXPERT }, { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; static const struct def_skill Skill_R[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_EXPERT }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_SKILLED }, { P_TWO_HANDED_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_SKILLED }, { P_CLUB, P_SKILLED }, { P_MACE, P_SKILLED }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_BASIC }, { P_POLEARMS, P_BASIC }, { P_SPEAR, P_BASIC }, { P_CROSSBOW, P_EXPERT }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_SKILLED }, { P_DIVINATION_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_SKILLED }, { P_MATTER_SPELL, P_SKILLED }, { P_RIDING, P_BASIC }, { P_TWO_WEAPON_COMBAT, P_EXPERT }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_Ran[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_BASIC }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_SKILLED }, { P_HAMMER, P_BASIC }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_EXPERT }, { P_TRIDENT, P_BASIC }, { P_BOW, P_EXPERT }, { P_SLING, P_EXPERT }, { P_CROSSBOW, P_EXPERT }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_SKILLED }, { P_BOOMERANG, P_EXPERT }, { P_WHIP, P_BASIC }, { P_HEALING_SPELL, P_BASIC }, { P_DIVINATION_SPELL, P_EXPERT }, { P_ESCAPE_SPELL, P_BASIC }, { P_RIDING, P_BASIC }, { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; static const struct def_skill Skill_S[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_SKILLED }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_EXPERT }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_FLAIL, P_SKILLED }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_LANCE, P_SKILLED }, { P_BOW, P_EXPERT }, { P_SHURIKEN, P_EXPERT }, { P_ATTACK_SPELL, P_SKILLED }, { P_CLERIC_SPELL, P_SKILLED }, { P_RIDING, P_SKILLED }, { P_TWO_WEAPON_COMBAT, P_EXPERT }, { P_MARTIAL_ARTS, P_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_T[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_BASIC }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_BASIC }, { P_LONG_SWORD, P_BASIC }, { P_TWO_HANDED_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_SKILLED }, { P_MACE, P_BASIC }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_BASIC }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_BASIC }, { P_SPEAR, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_LANCE, P_BASIC }, { P_BOW, P_BASIC }, { P_SLING, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_BASIC }, { P_BOOMERANG, P_BASIC }, { P_WHIP, P_BASIC }, { P_UNICORN_HORN, P_SKILLED }, { P_DIVINATION_SPELL, P_BASIC }, { P_ENCHANTMENT_SPELL, P_BASIC }, { P_ESCAPE_SPELL, P_SKILLED }, { P_RIDING, P_BASIC }, { P_TWO_WEAPON_COMBAT, P_SKILLED }, { P_BARE_HANDED_COMBAT, P_SKILLED }, { P_NONE, 0 } }; static const struct def_skill Skill_V[] = { { P_DAGGER, P_EXPERT }, { P_AXE, P_EXPERT }, { P_PICK_AXE, P_SKILLED }, { P_SHORT_SWORD, P_SKILLED }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_EXPERT }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_TRIDENT, P_BASIC }, { P_LANCE, P_SKILLED }, { P_SLING, P_BASIC }, { P_ATTACK_SPELL, P_BASIC }, { P_ESCAPE_SPELL, P_BASIC }, { P_RIDING, P_SKILLED }, { P_TWO_WEAPON_COMBAT, P_SKILLED }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_W[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_SHORT_SWORD, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_BASIC }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_SLING, P_SKILLED }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_BASIC }, { P_ATTACK_SPELL, P_EXPERT }, { P_HEALING_SPELL, P_SKILLED }, { P_DIVINATION_SPELL, P_EXPERT }, { P_ENCHANTMENT_SPELL, P_SKILLED }, { P_CLERIC_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_EXPERT }, { P_MATTER_SPELL, P_EXPERT }, { P_RIDING, P_BASIC }, { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; STATIC_OVL void knows_object(obj) register int obj; { discover_object(obj, TRUE, FALSE); objects[obj].oc_pre_discovered = 1; /* not a "discovery" */ } /* Know ordinary (non-magical) objects of a certain class, * like all gems except the loadstone and luckstone. */ STATIC_OVL void knows_class(sym) register char sym; { register int ct; for (ct = 1; ct < NUM_OBJECTS; ct++) if (objects[ct].oc_class == sym && !objects[ct].oc_magic) knows_object(ct); } void u_init() { register int i; struct u_roleplay tmpuroleplay = u.uroleplay; /* set by rcfile options */ flags.female = flags.initgend; flags.beginner = 1; /* zero u, including pointer values -- * necessary when aborting from a failed restore */ (void) memset((genericptr_t) &u, 0, sizeof(u)); u.ustuck = (struct monst *) 0; (void) memset((genericptr_t) &ubirthday, 0, sizeof(ubirthday)); (void) memset((genericptr_t) &urealtime, 0, sizeof(urealtime)); u.uroleplay = tmpuroleplay; /* restore options set via rcfile */ #if 0 /* documentation of more zero values as desirable */ u.usick_cause[0] = 0; u.uluck = u.moreluck = 0; uarmu = 0; uarm = uarmc = uarmh = uarms = uarmg = uarmf = 0; uwep = uball = uchain = uleft = uright = 0; uswapwep = uquiver = 0; u.twoweap = 0; u.ublessed = 0; /* not worthy yet */ u.ugangr = 0; /* gods not angry */ u.ugifts = 0; /* no divine gifts bestowed */ u.uevent.uhand_of_elbereth = 0; u.uevent.uheard_tune = 0; u.uevent.uopened_dbridge = 0; u.uevent.udemigod = 0; /* not a demi-god yet... */ u.udg_cnt = 0; u.mh = u.mhmax = u.mtimedone = 0; u.uz.dnum = u.uz0.dnum = 0; u.utotype = 0; #endif /* 0 */ u.uz.dlevel = 1; u.uz0.dlevel = 0; u.utolev = u.uz; u.umoved = FALSE; u.umortality = 0; u.ugrave_arise = NON_PM; u.umonnum = u.umonster = (flags.female && urole.femalenum != NON_PM) ? urole.femalenum : urole.malenum; u.ulycn = NON_PM; set_uasmon(); u.ulevel = 0; /* set up some of the initial attributes */ u.uhp = u.uhpmax = newhp(); u.uen = u.uenmax = newpw(); u.uspellprot = 0; adjabil(0, 1); u.ulevel = u.ulevelmax = 1; init_uhunger(); for (i = 0; i <= MAXSPELL; i++) spl_book[i].sp_id = NO_SPELL; u.ublesscnt = 300; /* no prayers just yet */ u.ualignbase[A_CURRENT] = u.ualignbase[A_ORIGINAL] = u.ualign.type = aligns[flags.initalign].value; #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *) &ubirthday); #else (void) time(&ubirthday); #endif /* * For now, everyone starts out with a night vision range of 1 and * their xray range disabled. */ u.nv_range = 1; u.xray_range = -1; /*** Role-specific initializations ***/ switch (Role_switch) { /* rn2(100) > 50 necessary for some choices because some * random number generators are bad enough to seriously * skew the results if we use rn2(2)... --KAA */ case PM_ARCHEOLOGIST: ini_inv(Archeologist); if (!rn2(10)) ini_inv(Tinopener); else if (!rn2(4)) ini_inv(Lamp); else if (!rn2(10)) ini_inv(Magicmarker); knows_object(SACK); knows_object(TOUCHSTONE); skill_init(Skill_A); break; case PM_BARBARIAN: if (rn2(100) >= 50) { /* see above comment */ Barbarian[B_MAJOR].trotyp = BATTLE_AXE; Barbarian[B_MINOR].trotyp = SHORT_SWORD; } ini_inv(Barbarian); if (!rn2(6)) ini_inv(Lamp); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); skill_init(Skill_B); break; case PM_CAVEMAN: Cave_man[C_AMMO].trquan = rn1(11, 10); /* 10..20 */ ini_inv(Cave_man); skill_init(Skill_C); break; case PM_HEALER: u.umoney0 = rn1(1000, 1001); ini_inv(Healer); if (!rn2(25)) ini_inv(Lamp); knows_object(POT_FULL_HEALING); skill_init(Skill_H); break; case PM_KNIGHT: ini_inv(Knight); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); /* give knights chess-like mobility * -- idea from wooledge@skybridge.scl.cwru.edu */ HJumping |= FROMOUTSIDE; skill_init(Skill_K); break; case PM_MONK: switch (rn2(90) / 30) { case 0: Monk[M_BOOK].trotyp = SPE_HEALING; break; case 1: Monk[M_BOOK].trotyp = SPE_PROTECTION; break; case 2: Monk[M_BOOK].trotyp = SPE_SLEEP; break; } ini_inv(Monk); if (!rn2(5)) ini_inv(Magicmarker); else if (!rn2(10)) ini_inv(Lamp); knows_class(ARMOR_CLASS); skill_init(Skill_Mon); break; case PM_PRIEST: ini_inv(Priest); if (!rn2(10)) ini_inv(Magicmarker); else if (!rn2(10)) ini_inv(Lamp); knows_object(POT_WATER); skill_init(Skill_P); /* KMH, conduct -- * Some may claim that this isn't agnostic, since they * are literally "priests" and they have holy water. * But we don't count it as such. Purists can always * avoid playing priests and/or confirm another player's * role in their YAAP. */ break; case PM_RANGER: Ranger[RAN_TWO_ARROWS].trquan = rn1(10, 50); Ranger[RAN_ZERO_ARROWS].trquan = rn1(10, 30); ini_inv(Ranger); skill_init(Skill_Ran); break; case PM_ROGUE: Rogue[R_DAGGERS].trquan = rn1(10, 6); u.umoney0 = 0; ini_inv(Rogue); if (!rn2(5)) ini_inv(Blindfold); knows_object(SACK); skill_init(Skill_R); break; case PM_SAMURAI: Samurai[S_ARROWS].trquan = rn1(20, 26); ini_inv(Samurai); if (!rn2(5)) ini_inv(Blindfold); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); skill_init(Skill_S); break; case PM_TOURIST: Tourist[T_DARTS].trquan = rn1(20, 21); u.umoney0 = rnd(1000); ini_inv(Tourist); if (!rn2(25)) ini_inv(Tinopener); else if (!rn2(25)) ini_inv(Leash); else if (!rn2(25)) ini_inv(Towel); else if (!rn2(25)) ini_inv(Magicmarker); skill_init(Skill_T); break; case PM_VALKYRIE: ini_inv(Valkyrie); if (!rn2(6)) ini_inv(Lamp); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); skill_init(Skill_V); break; case PM_WIZARD: ini_inv(Wizard); if (!rn2(5)) ini_inv(Magicmarker); if (!rn2(5)) ini_inv(Blindfold); skill_init(Skill_W); break; default: /* impossible */ break; } /*** Race-specific initializations ***/ switch (Race_switch) { case PM_HUMAN: /* Nothing special */ break; case PM_ELF: /* * Elves are people of music and song, or they are warriors. * Non-warriors get an instrument. We use a kludge to * get only non-magic instruments. */ if (Role_if(PM_PRIEST) || Role_if(PM_WIZARD)) { static int trotyp[] = { WOODEN_FLUTE, TOOLED_HORN, WOODEN_HARP, BELL, BUGLE, LEATHER_DRUM }; Instrument[0].trotyp = trotyp[rn2(SIZE(trotyp))]; ini_inv(Instrument); } /* Elves can recognize all elvish objects */ knows_object(ELVEN_SHORT_SWORD); knows_object(ELVEN_ARROW); knows_object(ELVEN_BOW); knows_object(ELVEN_SPEAR); knows_object(ELVEN_DAGGER); knows_object(ELVEN_BROADSWORD); knows_object(ELVEN_MITHRIL_COAT); knows_object(ELVEN_LEATHER_HELM); knows_object(ELVEN_SHIELD); knows_object(ELVEN_BOOTS); knows_object(ELVEN_CLOAK); break; case PM_DWARF: /* Dwarves can recognize all dwarvish objects */ knows_object(DWARVISH_SPEAR); knows_object(DWARVISH_SHORT_SWORD); knows_object(DWARVISH_MATTOCK); knows_object(DWARVISH_IRON_HELM); knows_object(DWARVISH_MITHRIL_COAT); knows_object(DWARVISH_CLOAK); knows_object(DWARVISH_ROUNDSHIELD); break; case PM_GNOME: break; case PM_ORC: /* compensate for generally inferior equipment */ if (!Role_if(PM_WIZARD)) ini_inv(Xtra_food); /* Orcs can recognize all orcish objects */ knows_object(ORCISH_SHORT_SWORD); knows_object(ORCISH_ARROW); knows_object(ORCISH_BOW); knows_object(ORCISH_SPEAR); knows_object(ORCISH_DAGGER); knows_object(ORCISH_CHAIN_MAIL); knows_object(ORCISH_RING_MAIL); knows_object(ORCISH_HELM); knows_object(ORCISH_SHIELD); knows_object(URUK_HAI_SHIELD); knows_object(ORCISH_CLOAK); break; default: /* impossible */ break; } if (discover) ini_inv(Wishing); if (wizard) read_wizkit(); if (u.umoney0) ini_inv(Money); u.umoney0 += hidden_gold(); /* in case sack has gold in it */ find_ac(); /* get initial ac value */ init_attr(75); /* init attribute values */ max_rank_sz(); /* set max str size for class ranks */ /* * Do we really need this? */ for (i = 0; i < A_MAX; i++) if (!rn2(20)) { register int xd = rn2(7) - 2; /* biased variation */ (void) adjattrib(i, xd, TRUE); if (ABASE(i) < AMAX(i)) AMAX(i) = ABASE(i); } /* make sure you can carry all you have - especially for Tourists */ while (inv_weight() > 0) { if (adjattrib(A_STR, 1, TRUE)) continue; if (adjattrib(A_CON, 1, TRUE)) continue; /* only get here when didn't boost strength or constitution */ break; } return; } /* skills aren't initialized, so we use the role-specific skill lists */ STATIC_OVL boolean restricted_spell_discipline(otyp) int otyp; { const struct def_skill *skills; int this_skill = spell_skilltype(otyp); switch (Role_switch) { case PM_ARCHEOLOGIST: skills = Skill_A; break; case PM_BARBARIAN: skills = Skill_B; break; case PM_CAVEMAN: skills = Skill_C; break; case PM_HEALER: skills = Skill_H; break; case PM_KNIGHT: skills = Skill_K; break; case PM_MONK: skills = Skill_Mon; break; case PM_PRIEST: skills = Skill_P; break; case PM_RANGER: skills = Skill_Ran; break; case PM_ROGUE: skills = Skill_R; break; case PM_SAMURAI: skills = Skill_S; break; case PM_TOURIST: skills = Skill_T; break; case PM_VALKYRIE: skills = Skill_V; break; case PM_WIZARD: skills = Skill_W; break; default: skills = 0; /* lint suppression */ break; } while (skills && skills->skill != P_NONE) { if (skills->skill == this_skill) return FALSE; ++skills; } return TRUE; } STATIC_OVL void ini_inv(trop) register struct trobj *trop; { struct obj *obj; int otyp, i; while (trop->trclass) { if (trop->trotyp != UNDEF_TYP) { otyp = (int) trop->trotyp; if (urace.malenum != PM_HUMAN) { /* substitute specific items for generic ones */ for (i = 0; inv_subs[i].race_pm != NON_PM; ++i) if (inv_subs[i].race_pm == urace.malenum && otyp == inv_subs[i].item_otyp) { otyp = inv_subs[i].subs_otyp; break; } } obj = mksobj(otyp, TRUE, FALSE); } else { /* UNDEF_TYP */ static NEARDATA short nocreate = STRANGE_OBJECT; static NEARDATA short nocreate2 = STRANGE_OBJECT; static NEARDATA short nocreate3 = STRANGE_OBJECT; static NEARDATA short nocreate4 = STRANGE_OBJECT; /* * For random objects, do not create certain overly powerful * items: wand of wishing, ring of levitation, or the * polymorph/polymorph control combination. Specific objects, * i.e. the discovery wishing, are still OK. * Also, don't get a couple of really useless items. (Note: * punishment isn't "useless". Some players who start out with * one will immediately read it and use the iron ball as a * weapon.) */ obj = mkobj(trop->trclass, FALSE); otyp = obj->otyp; while (otyp == WAN_WISHING || otyp == nocreate || otyp == nocreate2 || otyp == nocreate3 || otyp == nocreate4 || otyp == RIN_LEVITATION /* 'useless' items */ || otyp == POT_HALLUCINATION || otyp == POT_ACID || otyp == SCR_AMNESIA || otyp == SCR_FIRE || otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER || otyp == RIN_AGGRAVATE_MONSTER || otyp == RIN_HUNGER || otyp == WAN_NOTHING /* Monks don't use weapons */ || (otyp == SCR_ENCHANT_WEAPON && Role_if(PM_MONK)) /* wizard patch -- they already have one */ || (otyp == SPE_FORCE_BOLT && Role_if(PM_WIZARD)) /* powerful spells are either useless to low level players or unbalancing; also spells in restricted skill categories */ || (obj->oclass == SPBOOK_CLASS && (objects[otyp].oc_level > 3 || restricted_spell_discipline(otyp)))) { dealloc_obj(obj); obj = mkobj(trop->trclass, FALSE); otyp = obj->otyp; } /* Don't start with +0 or negative rings */ if (objects[otyp].oc_charged && obj->spe <= 0) obj->spe = rne(3); /* Heavily relies on the fact that 1) we create wands * before rings, 2) that we create rings before * spellbooks, and that 3) not more than 1 object of a * particular symbol is to be prohibited. (For more * objects, we need more nocreate variables...) */ switch (otyp) { case WAN_POLYMORPH: case RIN_POLYMORPH: case POT_POLYMORPH: nocreate = RIN_POLYMORPH_CONTROL; break; case RIN_POLYMORPH_CONTROL: nocreate = RIN_POLYMORPH; nocreate2 = SPE_POLYMORPH; nocreate3 = POT_POLYMORPH; } /* Don't have 2 of the same ring or spellbook */ if (obj->oclass == RING_CLASS || obj->oclass == SPBOOK_CLASS) nocreate4 = otyp; } /* nudist gets no armor */ if (u.uroleplay.nudist && obj->oclass == ARMOR_CLASS) { dealloc_obj(obj); trop++; continue; } if (trop->trclass == COIN_CLASS) { /* no "blessed" or "identified" money */ obj->quan = u.umoney0; } else { if (objects[otyp].oc_uses_known) obj->known = 1; obj->dknown = obj->bknown = obj->rknown = 1; if (Is_container(obj) || obj->otyp == STATUE) { obj->cknown = obj->lknown = 1; obj->otrapped = 0; } obj->cursed = 0; if (obj->opoisoned && u.ualign.type != A_CHAOTIC) obj->opoisoned = 0; if (obj->oclass == WEAPON_CLASS || obj->oclass == TOOL_CLASS) { obj->quan = (long) trop->trquan; trop->trquan = 1; } else if (obj->oclass == GEM_CLASS && is_graystone(obj) && obj->otyp != FLINT) { obj->quan = 1L; } if (trop->trspe != UNDEF_SPE) obj->spe = trop->trspe; if (trop->trbless != UNDEF_BLESS) obj->blessed = trop->trbless; } /* defined after setting otyp+quan + blessedness */ obj->owt = weight(obj); obj = addinv(obj); /* Make the type known if necessary */ if (OBJ_DESCR(objects[otyp]) && obj->known) discover_object(otyp, TRUE, FALSE); if (otyp == OIL_LAMP) discover_object(POT_OIL, TRUE, FALSE); if (obj->oclass == ARMOR_CLASS) { if (is_shield(obj) && !uarms) { setworn(obj, W_ARMS); if (uswapwep) setuswapwep((struct obj *) 0); } else if (is_helmet(obj) && !uarmh) setworn(obj, W_ARMH); else if (is_gloves(obj) && !uarmg) setworn(obj, W_ARMG); else if (is_shirt(obj) && !uarmu) setworn(obj, W_ARMU); else if (is_cloak(obj) && !uarmc) setworn(obj, W_ARMC); else if (is_boots(obj) && !uarmf) setworn(obj, W_ARMF); else if (is_suit(obj) && !uarm) setworn(obj, W_ARM); } if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || otyp == TIN_OPENER || otyp == FLINT || otyp == ROCK) { if (is_ammo(obj) || is_missile(obj)) { if (!uquiver) setuqwep(obj); } else if (!uwep) setuwep(obj); else if (!uswapwep) setuswapwep(obj); } if (obj->oclass == SPBOOK_CLASS && obj->otyp != SPE_BLANK_PAPER) initialspell(obj); #if !defined(PYRAMID_BUG) && !defined(MAC) if (--trop->trquan) continue; /* make a similar object */ #else if (trop->trquan) { /* check if zero first */ --trop->trquan; if (trop->trquan) continue; /* make a similar object */ } #endif trop++; } } /*u_init.c*/ nethack-3.6.0/src/uhitm.c0000664000076400007660000030052312623162627014230 0ustar paxedpaxed/* NetHack 3.6 uhitm.c $NHDT-Date: 1446887537 2015/11/07 09:12:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.151 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL boolean FDECL(known_hitum, (struct monst *, struct obj *, int *, int, int, struct attack *)); STATIC_DCL boolean FDECL(theft_petrifies, (struct obj *)); STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *)); STATIC_DCL boolean FDECL(hitum, (struct monst *, struct attack *)); STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *, struct obj *, int)); STATIC_DCL int FDECL(joust, (struct monst *, struct obj *)); STATIC_DCL void NDECL(demonpet); STATIC_DCL boolean FDECL(m_slips_free, (struct monst * mtmp, struct attack *mattk)); STATIC_DCL int FDECL(explum, (struct monst *, struct attack *)); STATIC_DCL void FDECL(start_engulf, (struct monst *)); STATIC_DCL void NDECL(end_engulf); STATIC_DCL int FDECL(gulpum, (struct monst *, struct attack *)); STATIC_DCL boolean FDECL(hmonas, (struct monst *)); STATIC_DCL void FDECL(nohandglow, (struct monst *)); STATIC_DCL boolean FDECL(shade_aware, (struct obj *)); extern boolean notonhead; /* for long worms */ /* The below might become a parameter instead if we use it a lot */ static int dieroll; /* Used to flag attacks caused by Stormbringer's maliciousness. */ static boolean override_confirmation = FALSE; #define PROJECTILE(obj) ((obj) && is_ammo(obj)) void erode_armor(mdef, hurt) struct monst *mdef; int hurt; { struct obj *target; /* What the following code does: it keeps looping until it * finds a target for the rust monster. * Head, feet, etc... not covered by metal, or covered by * rusty metal, are not targets. However, your body always * is, no matter what covers it. */ while (1) { switch (rn2(5)) { case 0: target = which_armor(mdef, W_ARMH); if (!target || erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING) continue; break; case 1: target = which_armor(mdef, W_ARMC); if (target) { (void) erode_obj(target, xname(target), hurt, EF_GREASE | EF_VERBOSE); break; } if ((target = which_armor(mdef, W_ARM)) != (struct obj *) 0) { (void) erode_obj(target, xname(target), hurt, EF_GREASE | EF_VERBOSE); } else if ((target = which_armor(mdef, W_ARMU)) != (struct obj *) 0) { (void) erode_obj(target, xname(target), hurt, EF_GREASE | EF_VERBOSE); } break; case 2: target = which_armor(mdef, W_ARMS); if (!target || erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING) continue; break; case 3: target = which_armor(mdef, W_ARMG); if (!target || erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING) continue; break; case 4: target = which_armor(mdef, W_ARMF); if (!target || erode_obj(target, xname(target), hurt, EF_GREASE) == ER_NOTHING) continue; break; } break; /* Out of while loop */ } } /* FALSE means it's OK to attack */ boolean attack_checks(mtmp, wep) register struct monst *mtmp; struct obj *wep; /* uwep for attack(), null for kick_monster() */ { char qbuf[QBUFSZ]; /* if you're close enough to attack, alert any waiting monster */ mtmp->mstrategy &= ~STRAT_WAITMASK; if (u.uswallow && mtmp == u.ustuck) return FALSE; if (context.forcefight) { /* Do this in the caller, after we checked that the monster * didn't die from the blow. Reason: putting the 'I' there * causes the hero to forget the square's contents since * both 'I' and remembered contents are stored in .glyph. * If the monster dies immediately from the blow, the 'I' will * not stay there, so the player will have suddenly forgotten * the square's contents for no apparent reason. if (!canspotmon(mtmp) && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) map_invisible(bhitpos.x, bhitpos.y); */ return FALSE; } /* Put up an invisible monster marker, but with exceptions for * monsters that hide and monsters you've been warned about. * The former already prints a warning message and * prevents you from hitting the monster just via the hidden monster * code below; if we also did that here, similar behavior would be * happening two turns in a row. The latter shows a glyph on * the screen, so you know something is there. */ if (!canspotmon(mtmp) && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y)) && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) && !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) { pline("Wait! There's %s there you can't see!", something); map_invisible(bhitpos.x, bhitpos.y); /* if it was an invisible mimic, treat it as if we stumbled * onto a visible mimic */ if (mtmp->m_ap_type && !Protection_from_shape_changers /* applied pole-arm attack is too far to get stuck */ && distu(mtmp->mx, mtmp->my) <= 2) { if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK)) u.ustuck = mtmp; } wakeup(mtmp); /* always necessary; also un-mimics mimics */ return TRUE; } if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp) && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))) { /* If a hidden mimic was in a square where a player remembers * some (probably different) unseen monster, the player is in * luck--he attacks it even though it's hidden. */ if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) { seemimic(mtmp); return FALSE; } stumble_onto_mimic(mtmp); return TRUE; } if (mtmp->mundetected && !canseemon(mtmp) && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y)) && (hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) { mtmp->mundetected = mtmp->msleeping = 0; newsym(mtmp->mx, mtmp->my); if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) { seemimic(mtmp); return FALSE; } if (!((Blind ? Blind_telepat : Unblind_telepat) || Detect_monsters)) { struct obj *obj; if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater)) pline("Wait! There's a hidden monster there!"); else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) pline("Wait! There's %s hiding under %s!", an(l_monnam(mtmp)), doname(obj)); return TRUE; } } /* * make sure to wake up a monster from the above cases if the * hero can sense that the monster is there. */ if ((mtmp->mundetected || mtmp->m_ap_type) && sensemon(mtmp)) { mtmp->mundetected = 0; wakeup(mtmp); } if (flags.confirm && mtmp->mpeaceful && !Confusion && !Hallucination && !Stunned) { /* Intelligent chaotic weapons (Stormbringer) want blood */ if (wep && wep->oartifact == ART_STORMBRINGER) { override_confirmation = TRUE; return FALSE; } if (canspotmon(mtmp)) { Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp)); if (!paranoid_query(ParanoidHit, qbuf)) { context.move = 0; return TRUE; } } } return FALSE; } /* * It is unchivalrous for a knight to attack the defenseless or from behind. */ void check_caitiff(mtmp) struct monst *mtmp; { if (u.ualign.record <= -10) return; if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL && (!mtmp->mcanmove || mtmp->msleeping || (mtmp->mflee && !mtmp->mavenge))) { You("caitiff!"); adjalign(-1); } else if (Role_if(PM_SAMURAI) && mtmp->mpeaceful) { /* attacking peaceful creatures is bad for the samurai's giri */ You("dishonorably attack the innocent!"); adjalign(-1); } } int find_roll_to_hit(mtmp, aatyp, weapon, attk_count, role_roll_penalty) register struct monst *mtmp; uchar aatyp; /* usually AT_WEAP or AT_KICK */ struct obj *weapon; /* uwep or uswapwep or NULL */ int *attk_count, *role_roll_penalty; { int tmp, tmp2; *role_roll_penalty = 0; /* default is `none' */ tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc + maybe_polyd(youmonst.data->mlevel, u.ulevel); /* some actions should occur only once during multiple attacks */ if (!(*attk_count)++) { /* knight's chivalry or samurai's giri */ check_caitiff(mtmp); } /* adjust vs. (and possibly modify) monster state */ if (mtmp->mstun) tmp += 2; if (mtmp->mflee) tmp += 2; if (mtmp->msleeping) { mtmp->msleeping = 0; tmp += 2; } if (!mtmp->mcanmove) { tmp += 4; if (!rn2(10)) { mtmp->mcanmove = 1; mtmp->mfrozen = 0; } } /* role/race adjustments */ if (Role_if(PM_MONK) && !Upolyd) { if (uarm) tmp -= (*role_roll_penalty = urole.spelarmr); else if (!uwep && !uarms) tmp += (u.ulevel / 3) + 2; } if (is_orc(mtmp->data) && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) tmp++; /* encumbrance: with a lot of luggage, your agility diminishes */ if ((tmp2 = near_capacity()) != 0) tmp -= (tmp2 * 2) - 1; if (u.utrap) tmp -= 3; /* * hitval applies if making a weapon attack while wielding a weapon; * weapon_hit_bonus applies if doing a weapon attack even bare-handed * or if kicking as martial artist */ if (aatyp == AT_WEAP || aatyp == AT_CLAW) { if (weapon) tmp += hitval(weapon, mtmp); tmp += weapon_hit_bonus(weapon); } else if (aatyp == AT_KICK && martial_bonus()) { tmp += weapon_hit_bonus((struct obj *) 0); } return tmp; } /* try to attack; return False if monster evaded; u.dx and u.dy must be set */ boolean attack(mtmp) register struct monst *mtmp; { register struct permonst *mdat = mtmp->data; /* This section of code provides protection against accidentally * hitting peaceful (like '@') and tame (like 'd') monsters. * Protection is provided as long as player is not: blind, confused, * hallucinating or stunned. * changes by wwp 5/16/85 * More changes 12/90, -dkh-. if its tame and safepet, (and protected * 07/92) then we assume that you're not trying to attack. Instead, * you'll usually just swap places if this is a movement command */ /* Intelligent chaotic weapons (Stormbringer) want blood */ if (is_safepet(mtmp) && !context.forcefight) { if (!uwep || uwep->oartifact != ART_STORMBRINGER) { /* there are some additional considerations: this won't work * if in a shop or Punished or you miss a random roll or * if you can walk thru walls and your pet cannot (KAA) or * if your pet is a long worm (unless someone does better). * there's also a chance of displacing a "frozen" monster. * sleeping monsters might magically walk in their sleep. */ boolean foo = (Punished || !rn2(7) || is_longworm(mtmp->data)), inshop = FALSE; char *p; for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++) if (tended_shop(&rooms[*p - ROOMOFFSET])) { inshop = TRUE; break; } if (inshop || foo || (IS_ROCK(levl[u.ux][u.uy].typ) && !passes_walls(mtmp->data))) { char buf[BUFSZ]; monflee(mtmp, rnd(6), FALSE, FALSE); Strcpy(buf, y_monnam(mtmp)); buf[0] = highc(buf[0]); You("stop. %s is in the way!", buf); return TRUE; } else if ((mtmp->mfrozen || (!mtmp->mcanmove) || (mtmp->data->mmove == 0)) && rn2(6)) { pline("%s doesn't seem to move!", Monnam(mtmp)); return TRUE; } else return FALSE; } } /* possibly set in attack_checks; examined in known_hitum, called via hitum or hmonas below */ override_confirmation = FALSE; /* attack_checks() used to use directly, now it uses bhitpos instead; it might map an invisible monster there */ bhitpos.x = u.ux + u.dx; bhitpos.y = u.uy + u.dy; if (attack_checks(mtmp, uwep)) return TRUE; if (Upolyd && noattacks(youmonst.data)) { /* certain "pacifist" monsters don't attack */ You("have no way to attack monsters physically."); mtmp->mstrategy &= ~STRAT_WAITMASK; goto atk_done; } if (check_capacity("You cannot fight while so heavily loaded.") /* consume extra nutrition during combat; maybe pass out */ || overexertion()) goto atk_done; if (u.twoweap && !can_twoweapon()) untwoweapon(); if (unweapon) { unweapon = FALSE; if (flags.verbose) { if (uwep) You("begin bashing monsters with %s.", yobjnam(uwep, (char *) 0)); else if (!cantwield(youmonst.data)) You("begin %sing monsters with your %s %s.", Role_if(PM_MONK) ? "strik" : "bash", uarmg ? "gloved" : "bare", /* Del Lamb */ makeplural(body_part(HAND))); } } exercise(A_STR, TRUE); /* you're exercising muscles */ /* andrew@orca: prevent unlimited pick-axe attacks */ u_wipe_engr(3); /* Is the "it died" check actually correct? */ if (mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping && !mtmp->mconf && mtmp->mcansee && !rn2(7) && (m_move(mtmp, 0) == 2 /* it died */ || mtmp->mx != u.ux + u.dx || mtmp->my != u.uy + u.dy)) /* it moved */ return FALSE; if (Upolyd) (void) hmonas(mtmp); else (void) hitum(mtmp, youmonst.data->mattk); mtmp->mstrategy &= ~STRAT_WAITMASK; atk_done: /* see comment in attack_checks() */ /* we only need to check for this if we did an attack_checks() * and it returned 0 (it's okay to attack), and the monster didn't * evade. */ if (context.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp) && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph) && !(u.uswallow && mtmp == u.ustuck)) map_invisible(u.ux + u.dx, u.uy + u.dy); return TRUE; } /* really hit target monster; returns TRUE if it still lives */ STATIC_OVL boolean known_hitum(mon, weapon, mhit, rollneeded, armorpenalty, uattk) register struct monst *mon; struct obj *weapon; int *mhit; int rollneeded, armorpenalty; /* for monks */ struct attack *uattk; { register boolean malive = TRUE; if (override_confirmation) { /* this may need to be generalized if weapons other than Stormbringer acquire similar anti-social behavior... */ if (flags.verbose) Your("bloodthirsty blade attacks!"); } if (!*mhit) { missum(mon, uattk, (rollneeded + armorpenalty > dieroll)); } else { int oldhp = mon->mhp, x = u.ux + u.dx, y = u.uy + u.dy; long oldweaphit = u.uconduct.weaphit; /* KMH, conduct */ if (weapon && (weapon->oclass == WEAPON_CLASS || is_weptool(weapon))) u.uconduct.weaphit++; /* we hit the monster; be careful: it might die or be knocked into a different location */ notonhead = (mon->mx != x || mon->my != y); malive = hmon(mon, weapon, HMON_MELEE); if (malive) { /* monster still alive */ if (!rn2(25) && mon->mhp < mon->mhpmax / 2 && !(u.uswallow && mon == u.ustuck)) { /* maybe should regurgitate if swallowed? */ monflee(mon, !rn2(3) ? rnd(100) : 0, FALSE, TRUE); if (u.ustuck == mon && !u.uswallow && !sticks(youmonst.data)) u.ustuck = 0; } /* Vorpal Blade hit converted to miss */ /* could be headless monster or worm tail */ if (mon->mhp == oldhp) { *mhit = 0; /* a miss does not break conduct */ u.uconduct.weaphit = oldweaphit; } if (mon->wormno && *mhit) cutworm(mon, x, y, weapon); } } return malive; } /* hit target monster; returns TRUE if it still lives */ STATIC_OVL boolean hitum(mon, uattk) struct monst *mon; struct attack *uattk; { boolean malive, wep_was_destroyed = FALSE; struct obj *wepbefore = uwep; int armorpenalty, attknum = 0, x = u.ux + u.dx, y = u.uy + u.dy, tmp = find_roll_to_hit(mon, uattk->aatyp, uwep, &attknum, &armorpenalty); int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow); if (tmp > dieroll) exercise(A_DEX, TRUE); malive = known_hitum(mon, uwep, &mhit, tmp, armorpenalty, uattk); /* second attack for two-weapon combat; won't occur if Stormbringer overrode confirmation (assumes Stormbringer is primary weapon) or if the monster was killed or knocked to different location */ if (u.twoweap && !override_confirmation && malive && m_at(x, y) == mon) { tmp = find_roll_to_hit(mon, uattk->aatyp, uswapwep, &attknum, &armorpenalty); mhit = (tmp > (dieroll = rnd(20)) || u.uswallow); malive = known_hitum(mon, uswapwep, &mhit, tmp, armorpenalty, uattk); } if (wepbefore && !uwep) wep_was_destroyed = TRUE; (void) passive(mon, mhit, malive, AT_WEAP, wep_was_destroyed); return malive; } /* general "damage monster" routine; return True if mon still alive */ boolean hmon(mon, obj, thrown) struct monst *mon; struct obj *obj; int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */ { boolean result, anger_guards; anger_guards = (mon->mpeaceful && (mon->ispriest || mon->isshk || is_watch(mon->data))); result = hmon_hitmon(mon, obj, thrown); if (mon->ispriest && !rn2(2)) ghod_hitsu(mon); if (anger_guards) (void) angry_guards(!!Deaf); return result; } /* guts of hmon() */ STATIC_OVL boolean hmon_hitmon(mon, obj, thrown) struct monst *mon; struct obj *obj; int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */ { int tmp; struct permonst *mdat = mon->data; int barehand_silver_rings = 0; /* The basic reason we need all these booleans is that we don't want * a "hit" message when a monster dies, so we have to know how much * damage it did _before_ outputting a hit message, but any messages * associated with the damage don't come out until _after_ outputting * a hit message. */ boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE; boolean get_dmg_bonus = TRUE; boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE, unpoisonmsg = FALSE; boolean silvermsg = FALSE, silverobj = FALSE; boolean valid_weapon_attack = FALSE; boolean unarmed = !uwep && !uarm && !uarms; boolean hand_to_hand = (thrown == HMON_MELEE /* not grapnels; applied implies uwep */ || (thrown == HMON_APPLIED && is_pole(uwep))); int jousting = 0; int wtype; struct obj *monwep; char unconventional[BUFSZ]; /* substituted for word "attack" in msg */ char saved_oname[BUFSZ]; unconventional[0] = '\0'; saved_oname[0] = '\0'; wakeup(mon); if (!obj) { /* attack with bare hands */ if (mdat == &mons[PM_SHADE]) tmp = 0; else if (martial_bonus()) tmp = rnd(4); /* bonus for martial arts */ else tmp = rnd(2); valid_weapon_attack = (tmp > 1); /* blessed gloves give bonuses when fighting 'bare-handed' */ if (uarmg && uarmg->blessed && (is_undead(mdat) || is_demon(mdat) || is_vampshifter(mon))) tmp += rnd(4); /* So do silver rings. Note: rings are worn under gloves, so you * don't get both bonuses. */ if (!uarmg) { if (uleft && objects[uleft->otyp].oc_material == SILVER) barehand_silver_rings++; if (uright && objects[uright->otyp].oc_material == SILVER) barehand_silver_rings++; if (barehand_silver_rings && mon_hates_silver(mon)) { tmp += rnd(20); silvermsg = TRUE; } } } else { Strcpy(saved_oname, cxname(obj)); if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { /* is it not a melee weapon? */ if (/* if you strike with a bow... */ is_launcher(obj) /* or strike with a missile in your hand... */ || (!thrown && (is_missile(obj) || is_ammo(obj))) /* or use a pole at short range and not mounted... */ || (!thrown && !u.usteed && is_pole(obj)) /* or throw a missile without the proper bow... */ || (is_ammo(obj) && (thrown != HMON_THROWN || !ammo_and_launcher(obj, uwep)))) { /* then do only 1-2 points of damage */ if (mdat == &mons[PM_SHADE] && !shade_glare(obj)) tmp = 0; else tmp = rnd(2); if (objects[obj->otyp].oc_material == SILVER && mon_hates_silver(mon)) { silvermsg = TRUE; silverobj = TRUE; /* if it will already inflict dmg, make it worse */ tmp += rnd((tmp) ? 20 : 10); } if (!thrown && obj == uwep && obj->otyp == BOOMERANG && rnl(4) == 4 - 1) { boolean more_than_1 = (obj->quan > 1L); pline("As you hit %s, %s%s breaks into splinters.", mon_nam(mon), more_than_1 ? "one of " : "", yname(obj)); if (!more_than_1) uwepgone(); /* set unweapon */ useup(obj); if (!more_than_1) obj = (struct obj *) 0; hittxt = TRUE; if (mdat != &mons[PM_SHADE]) tmp++; } } else { tmp = dmgval(obj, mon); /* a minimal hit doesn't exercise proficiency */ valid_weapon_attack = (tmp > 1); if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) { ; /* no special bonuses */ } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd /* multi-shot throwing is too powerful here */ && hand_to_hand) { You("strike %s from behind!", mon_nam(mon)); tmp += rnd(u.ulevel); hittxt = TRUE; } else if (dieroll == 2 && obj == uwep && obj->oclass == WEAPON_CLASS && (bimanual(obj) || (Role_if(PM_SAMURAI) && obj->otyp == KATANA && !uarms)) && ((wtype = uwep_skill_type()) != P_NONE && P_SKILL(wtype) >= P_SKILLED) && ((monwep = MON_WEP(mon)) != 0 && !is_flimsy(monwep) && !obj_resists( monwep, 50 + 15 * greatest_erosion(obj), 100))) { /* * 2.5% chance of shattering defender's weapon when * using a two-handed weapon; less if uwep is rusted. * [dieroll == 2 is most successful non-beheading or * -bisecting hit, in case of special artifact damage; * the percentage chance is (1/20)*(50/100).] */ setmnotwielded(mon, monwep); mon->weapon_check = NEED_WEAPON; pline("%s from the force of your blow!", Yobjnam2(monwep, "shatter")); m_useupall(mon, monwep); /* If someone just shattered MY weapon, I'd flee! */ if (rn2(4)) { monflee(mon, d(2, 3), TRUE, TRUE); } hittxt = TRUE; } if (obj->oartifact && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) { if (mon->mhp <= 0) /* artifact killed monster */ return FALSE; if (tmp == 0) return TRUE; hittxt = TRUE; } if (objects[obj->otyp].oc_material == SILVER && mon_hates_silver(mon)) { silvermsg = TRUE; silverobj = TRUE; } if (u.usteed && !thrown && tmp > 0 && weapon_type(obj) == P_LANCE && mon != u.ustuck) { jousting = joust(mon, obj); /* exercise skill even for minimal damage hits */ if (jousting) valid_weapon_attack = TRUE; } if (thrown == HMON_THROWN && (is_ammo(obj) || is_missile(obj))) { if (ammo_and_launcher(obj, uwep)) { /* Elves and Samurai do extra damage using * their bows&arrows; they're highly trained. */ if (Role_if(PM_SAMURAI) && obj->otyp == YA && uwep->otyp == YUMI) tmp++; else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW && uwep->otyp == ELVEN_BOW) tmp++; } if (obj->opoisoned && is_poisonable(obj)) ispoisoned = TRUE; } } } else if (obj->oclass == POTION_CLASS) { if (obj->quan > 1L) obj = splitobj(obj, 1L); else setuwep((struct obj *) 0); freeinv(obj); potionhit(mon, obj, TRUE); if (mon->mhp <= 0) return FALSE; /* killed */ hittxt = TRUE; /* in case potion effect causes transformation */ mdat = mon->data; tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1; } else { if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) { tmp = 0; Strcpy(unconventional, cxname(obj)); } else { switch (obj->otyp) { case BOULDER: /* 1d20 */ case HEAVY_IRON_BALL: /* 1d25 */ case IRON_CHAIN: /* 1d4+1 */ tmp = dmgval(obj, mon); break; case MIRROR: if (breaktest(obj)) { You("break %s. That's bad luck!", ysimple_name(obj)); change_luck(-2); useup(obj); obj = (struct obj *) 0; unarmed = FALSE; /* avoid obj==0 confusion */ get_dmg_bonus = FALSE; hittxt = TRUE; } tmp = 1; break; case EXPENSIVE_CAMERA: You("succeed in destroying %s. Congratulations!", ysimple_name(obj)); release_camera_demon(obj, u.ux, u.uy); useup(obj); return TRUE; case CORPSE: /* fixed by polder@cs.vu.nl */ if (touch_petrifies(&mons[obj->corpsenm])) { tmp = 1; hittxt = TRUE; You("hit %s with %s.", mon_nam(mon), corpse_xname(obj, (const char *) 0, obj->dknown ? CXN_PFX_THE : CXN_ARTICLE)); obj->dknown = 1; if (!munstone(mon, TRUE)) minstapetrify(mon, TRUE); if (resists_ston(mon)) break; /* note: hp may be <= 0 even if munstoned==TRUE */ return (boolean) (mon->mhp > 0); #if 0 } else if (touch_petrifies(mdat)) { ; /* maybe turn the corpse into a statue? */ #endif } tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize : 0) + 1; break; #define useup_eggs(o) \ { \ if (thrown) \ obfree(o, (struct obj *) 0); \ else \ useupall(o); \ o = (struct obj *) 0; \ } /* now gone */ case EGG: { long cnt = obj->quan; tmp = 1; /* nominal physical damage */ get_dmg_bonus = FALSE; hittxt = TRUE; /* message always given */ /* egg is always either used up or transformed, so next hand-to-hand attack should yield a "bashing" mesg */ if (obj == uwep) unweapon = TRUE; if (obj->spe && obj->corpsenm >= LOW_PM) { if (obj->quan < 5L) change_luck((schar) - (obj->quan)); else change_luck(-5); } if (touch_petrifies(&mons[obj->corpsenm])) { /*learn_egg_type(obj->corpsenm);*/ pline("Splat! You hit %s with %s %s egg%s!", mon_nam(mon), obj->known ? "the" : cnt > 1L ? "some" : "a", obj->known ? mons[obj->corpsenm].mname : "petrifying", plur(cnt)); obj->known = 1; /* (not much point...) */ useup_eggs(obj); if (!munstone(mon, TRUE)) minstapetrify(mon, TRUE); if (resists_ston(mon)) break; return (boolean) (mon->mhp > 0); } else { /* ordinary egg(s) */ const char *eggp = (obj->corpsenm != NON_PM && obj->known) ? the(mons[obj->corpsenm].mname) : (cnt > 1L) ? "some" : "an"; You("hit %s with %s egg%s.", mon_nam(mon), eggp, plur(cnt)); if (touch_petrifies(mdat) && !stale_egg(obj)) { pline_The("egg%s %s alive any more...", plur(cnt), (cnt == 1L) ? "isn't" : "aren't"); if (obj->timed) obj_stop_timers(obj); obj->otyp = ROCK; obj->oclass = GEM_CLASS; obj->oartifact = 0; obj->spe = 0; obj->known = obj->dknown = obj->bknown = 0; obj->owt = weight(obj); if (thrown) place_object(obj, mon->mx, mon->my); } else { pline("Splat!"); useup_eggs(obj); exercise(A_WIS, FALSE); } } break; #undef useup_eggs } case CLOVE_OF_GARLIC: /* no effect against demons */ if (is_undead(mdat) || is_vampshifter(mon)) { monflee(mon, d(2, 4), FALSE, TRUE); } tmp = 1; break; case CREAM_PIE: case BLINDING_VENOM: mon->msleeping = 0; if (can_blnd(&youmonst, mon, (uchar) (obj->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), obj)) { if (Blind) { pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!"); } else if (obj->otyp == BLINDING_VENOM) { pline_The("venom blinds %s%s!", mon_nam(mon), mon->mcansee ? "" : " further"); } else { char *whom = mon_nam(mon); char *what = The(xname(obj)); if (!thrown && obj->quan > 1L) what = An(singular(obj, xname)); /* note: s_suffix returns a modifiable buffer */ if (haseyes(mdat) && mdat != &mons[PM_FLOATING_EYE]) whom = strcat(strcat(s_suffix(whom), " "), mbodypart(mon, FACE)); pline("%s %s over %s!", what, vtense(what, "splash"), whom); } setmangry(mon); mon->mcansee = 0; tmp = rn1(25, 21); if (((int) mon->mblinded + tmp) > 127) mon->mblinded = 127; else mon->mblinded += tmp; } else { pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!"); setmangry(mon); } if (thrown) obfree(obj, (struct obj *) 0); else useup(obj); hittxt = TRUE; get_dmg_bonus = FALSE; tmp = 0; break; case ACID_VENOM: /* thrown (or spit) */ if (resists_acid(mon)) { Your("venom hits %s harmlessly.", mon_nam(mon)); tmp = 0; } else { Your("venom burns %s!", mon_nam(mon)); tmp = dmgval(obj, mon); } if (thrown) obfree(obj, (struct obj *) 0); else useup(obj); hittxt = TRUE; get_dmg_bonus = FALSE; break; default: /* non-weapons can damage because of their weight */ /* (but not too much) */ tmp = obj->owt / 100; if (is_wet_towel(obj)) { /* wielded wet towel should probably use whip skill (but not by setting objects[TOWEL].oc_skill==P_WHIP because that would turn towel into a weptool) */ tmp += obj->spe; if (rn2(obj->spe + 1)) /* usually lose some wetness */ dry_a_towel(obj, -1, TRUE); } if (tmp < 1) tmp = 1; else tmp = rnd(tmp); if (tmp > 6) tmp = 6; /* * Things like silver wands can arrive here so * so we need another silver check. */ if (objects[obj->otyp].oc_material == SILVER && mon_hates_silver(mon)) { tmp += rnd(20); silvermsg = TRUE; silverobj = TRUE; } } } } } /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) * *OR* if attacking bare-handed!! */ if (get_dmg_bonus && tmp > 0) { tmp += u.udaminc; /* If you throw using a propellor, you don't get a strength * bonus but you do get an increase-damage bonus. */ if (thrown != HMON_THROWN || !obj || !uwep || !ammo_and_launcher(obj, uwep)) tmp += dbon(); } if (valid_weapon_attack) { struct obj *wep; /* to be valid a projectile must have had the correct projector */ wep = PROJECTILE(obj) ? uwep : obj; tmp += weapon_dam_bonus(wep); /* [this assumes that `!thrown' implies wielded...] */ wtype = thrown ? weapon_type(wep) : uwep_skill_type(); use_skill(wtype, 1); } if (ispoisoned) { int nopoison = (10 - (obj->owt / 10)); if (nopoison < 2) nopoison = 2; if (Role_if(PM_SAMURAI)) { You("dishonorably use a poisoned weapon!"); adjalign(-sgn(u.ualign.type)); } else if (u.ualign.type == A_LAWFUL && u.ualign.record > -10) { You_feel("like an evil coward for using a poisoned weapon."); adjalign(-1); } if (obj && !rn2(nopoison)) { /* remove poison now in case obj ends up in a bones file */ obj->opoisoned = FALSE; /* defer "obj is no longer poisoned" until after hit message */ unpoisonmsg = TRUE; } if (resists_poison(mon)) needpoismsg = TRUE; else if (rn2(10)) tmp += rnd(6); else poiskilled = TRUE; } if (tmp < 1) { /* make sure that negative damage adjustment can't result in inadvertently boosting the victim's hit points */ tmp = 0; if (mdat == &mons[PM_SHADE]) { if (!hittxt) { const char *what = *unconventional ? unconventional : "attack"; Your("%s %s harmlessly through %s.", what, vtense(what, "pass"), mon_nam(mon)); hittxt = TRUE; } } else { if (get_dmg_bonus) tmp = 1; } } if (jousting) { tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */ You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : "."); if (jousting < 0) { pline("%s shatters on impact!", Yname2(obj)); /* (must be either primary or secondary weapon to get here) */ u.twoweap = FALSE; /* untwoweapon() is too verbose here */ if (obj == uwep) uwepgone(); /* set unweapon */ /* minor side-effect: broken lance won't split puddings */ useup(obj); obj = 0; } /* avoid migrating a dead monster */ if (mon->mhp > tmp) { mhurtle(mon, u.dx, u.dy, 1); mdat = mon->data; /* in case of a polymorph trap */ if (DEADMONSTER(mon)) already_killed = TRUE; } hittxt = TRUE; } else if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) { /* VERY small chance of stunning opponent if unarmed. */ if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat) && !thick_skinned(mdat)) { if (canspotmon(mon)) pline("%s %s from your powerful strike!", Monnam(mon), makeplural(stagger(mon->data, "stagger"))); /* avoid migrating a dead monster */ if (mon->mhp > tmp) { mhurtle(mon, u.dx, u.dy, 1); mdat = mon->data; /* in case of a polymorph trap */ if (DEADMONSTER(mon)) already_killed = TRUE; } hittxt = TRUE; } } if (!already_killed) mon->mhp -= tmp; /* adjustments might have made tmp become less than what a level draining artifact has already done to max HP */ if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (mon->mhp < 1) destroyed = TRUE; if (mon->mtame && tmp > 0) { /* do this even if the pet is being killed (affects revival) */ abuse_dog(mon); /* reduces tameness */ /* flee if still alive and still tame; if already suffering from untimed fleeing, no effect, otherwise increases timed fleeing */ if (mon->mtame && !destroyed) monflee(mon, 10 * rnd(tmp), FALSE, FALSE); } if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING]) /* pudding is alive and healthy enough to split */ && mon->mhp > 1 && !mon->mcan /* iron weapon using melee or polearm hit */ && obj && obj == uwep && objects[obj->otyp].oc_material == IRON && hand_to_hand) { if (clone_mon(mon, 0, 0)) { pline("%s divides as you hit it!", Monnam(mon)); hittxt = TRUE; } } if (!hittxt /*( thrown => obj exists )*/ && (!destroyed || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) { if (thrown) hit(mshot_xname(obj), mon, exclam(tmp)); else if (!flags.verbose) You("hit it."); else You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit", mon_nam(mon), canseemon(mon) ? exclam(tmp) : "."); } if (silvermsg) { const char *fmt; char *whom = mon_nam(mon); char silverobjbuf[BUFSZ]; if (canspotmon(mon)) { if (barehand_silver_rings == 1) fmt = "Your silver ring sears %s!"; else if (barehand_silver_rings == 2) fmt = "Your silver rings sear %s!"; else if (silverobj && saved_oname[0]) { Sprintf(silverobjbuf, "Your %s%s %s %%s!", strstri(saved_oname, "silver") ? "" : "silver ", saved_oname, vtense(saved_oname, "sear")); fmt = silverobjbuf; } else fmt = "The silver sears %s!"; } else { *whom = highc(*whom); /* "it" -> "It" */ fmt = "%s is seared!"; } /* note: s_suffix returns a modifiable buffer */ if (!noncorporeal(mdat) && !amorphous(mdat)) whom = strcat(s_suffix(whom), " flesh"); pline(fmt, whom); } /* if a "no longer poisoned" message is coming, it will be last; obj->opoisoned was cleared above and any message referring to "poisoned " has now been given; we want just "" for last message, so reformat while obj is still accessible */ if (unpoisonmsg) Strcpy(saved_oname, cxname(obj)); /* [note: thrown obj might go away during killed/xkilled call] */ if (needpoismsg) pline_The("poison doesn't seem to affect %s.", mon_nam(mon)); if (poiskilled) { pline_The("poison was deadly..."); if (!already_killed) xkilled(mon, 0); destroyed = TRUE; /* return FALSE; */ } else if (destroyed) { if (!already_killed) killed(mon); /* takes care of most messages */ } else if (u.umconf && hand_to_hand) { nohandglow(mon); if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) { mon->mconf = 1; if (!mon->mstun && mon->mcanmove && !mon->msleeping && canseemon(mon)) pline("%s appears confused.", Monnam(mon)); } } if (unpoisonmsg) Your("%s %s no longer poisoned.", saved_oname, vtense(saved_oname, "are")); return destroyed ? FALSE : TRUE; } STATIC_OVL boolean shade_aware(obj) struct obj *obj; { if (!obj) return FALSE; /* * The things in this list either * 1) affect shades. * OR * 2) are dealt with properly by other routines * when it comes to shades. */ if (obj->otyp == BOULDER || obj->otyp == HEAVY_IRON_BALL || obj->otyp == IRON_CHAIN /* dmgval handles those first three */ || obj->otyp == MIRROR /* silver in the reflective surface */ || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */ || objects[obj->otyp].oc_material == SILVER) return TRUE; return FALSE; } /* check whether slippery clothing protects from hug or wrap attack */ /* [currently assumes that you are the attacker] */ STATIC_OVL boolean m_slips_free(mdef, mattk) struct monst *mdef; struct attack *mattk; { struct obj *obj; if (mattk->adtyp == AD_DRIN) { /* intelligence drain attacks the head */ obj = which_armor(mdef, W_ARMH); } else { /* grabbing attacks the body */ obj = which_armor(mdef, W_ARMC); /* cloak */ if (!obj) obj = which_armor(mdef, W_ARM); /* suit */ if (!obj) obj = which_armor(mdef, W_ARMU); /* shirt */ } /* if monster's cloak/armor is greased, your grab slips off; this protection might fail (33% chance) when the armor is cursed */ if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) && (!obj->cursed || rn2(3))) { You("%s %s %s %s!", mattk->adtyp == AD_WRAP ? "slip off of" : "grab, but cannot hold onto", s_suffix(mon_nam(mdef)), obj->greased ? "greased" : "slippery", /* avoid "slippery slippery cloak" for undiscovered oilskin cloak */ (obj->greased || objects[obj->otyp].oc_name_known) ? xname(obj) : cloak_simple_name(obj)); if (obj->greased && !rn2(2)) { pline_The("grease wears off."); obj->greased = 0; } return TRUE; } return FALSE; } /* used when hitting a monster with a lance while mounted; 1: joust hit; 0: ordinary hit; -1: joust but break lance */ STATIC_OVL int joust(mon, obj) struct monst *mon; /* target */ struct obj *obj; /* weapon */ { int skill_rating, joust_dieroll; if (Fumbling || Stunned) return 0; /* sanity check; lance must be wielded in order to joust */ if (obj != uwep && (obj != uswapwep || !u.twoweap)) return 0; /* if using two weapons, use worse of lance and two-weapon skills */ skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */ if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating) skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT); if (skill_rating == P_ISRESTRICTED) skill_rating = P_UNSKILLED; /* 0=>1 */ /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */ if ((joust_dieroll = rn2(5)) < skill_rating) { if (joust_dieroll == 0 && rnl(50) == (50 - 1) && !unsolid(mon->data) && !obj_resists(obj, 0, 100)) return -1; /* hit that breaks lance */ return 1; /* successful joust */ } return 0; /* no joust bonus; revert to ordinary attack */ } /* * Send in a demon pet for the hero. Exercise wisdom. * * This function used to be inline to damageum(), but the Metrowerks compiler * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too * Complex." * Pulling it out makes it work. */ STATIC_OVL void demonpet() { int i; struct permonst *pm; struct monst *dtmp; pline("Some hell-p has arrived!"); i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM; pm = i != NON_PM ? &mons[i] : youmonst.data; if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0) (void) tamedog(dtmp, (struct obj *) 0); exercise(A_WIS, TRUE); } STATIC_OVL boolean theft_petrifies(otmp) struct obj *otmp; { if (uarmg || otmp->otyp != CORPSE || !touch_petrifies(&mons[otmp->corpsenm]) || Stone_resistance) return FALSE; #if 0 /* no poly_when_stoned() critter has theft capability */ if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) { display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */ return TRUE; } #endif /* stealing this corpse is fatal... */ instapetrify(corpse_xname(otmp, "stolen", CXN_ARTICLE)); /* apparently wasn't fatal after all... */ return TRUE; } /* * Player uses theft attack against monster. * * If the target is wearing body armor, take all of its possessions; * otherwise, take one object. [Is this really the behavior we want?] */ STATIC_OVL void steal_it(mdef, mattk) struct monst *mdef; struct attack *mattk; { struct obj *otmp, *stealoid, **minvent_ptr; long unwornmask; if (!mdef->minvent) return; /* nothing to take */ /* look for worn body armor */ stealoid = (struct obj *) 0; if (could_seduce(&youmonst, mdef, mattk)) { /* find armor, and move it to end of inventory in the process */ minvent_ptr = &mdef->minvent; while ((otmp = *minvent_ptr) != 0) if (otmp->owornmask & W_ARM) { if (stealoid) panic("steal_it: multiple worn suits"); *minvent_ptr = otmp->nobj; /* take armor out of minvent */ stealoid = otmp; stealoid->nobj = (struct obj *) 0; } else { minvent_ptr = &otmp->nobj; } *minvent_ptr = stealoid; /* put armor back into minvent */ } if (stealoid) { /* we will be taking everything */ if (gender(mdef) == (int) u.mfemale && youmonst.data->mlet == S_NYMPH) You("charm %s. She gladly hands over her possessions.", mon_nam(mdef)); else You("seduce %s and %s starts to take off %s clothes.", mon_nam(mdef), mhe(mdef), mhis(mdef)); } while ((otmp = mdef->minvent) != 0) { if (!Upolyd) break; /* no longer have ability to steal */ /* take the object away from the monster */ obj_extract_self(otmp); if ((unwornmask = otmp->owornmask) != 0L) { mdef->misc_worn_check &= ~unwornmask; if (otmp->owornmask & W_WEP) setmnotwielded(mdef, otmp); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); if (otmp == stealoid) /* special message for final item */ pline("%s finishes taking off %s suit.", Monnam(mdef), mhis(mdef)); } /* give the object to the character */ otmp = hold_another_object(otmp, "You snatched but dropped %s.", doname(otmp), "You steal: "); if (otmp->where != OBJ_INVENT) continue; if (theft_petrifies(otmp)) break; /* stop thieving even though hero survived */ /* more take-away handling, after theft message */ if (unwornmask & W_WEP) { /* stole wielded weapon */ possibly_unwield(mdef, FALSE); } else if (unwornmask & W_ARMG) { /* stole worn gloves */ mselftouch(mdef, (const char *) 0, TRUE); if (mdef->mhp <= 0) /* it's now a statue */ return; /* can't continue stealing */ } if (!stealoid) break; /* only taking one item */ } } int damageum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { register struct permonst *pd = mdef->data; int armpro, tmp = d((int) mattk->damn, (int) mattk->damd); boolean negated; armpro = magic_negation(mdef); /* since hero can't be cancelled, only defender's armor applies */ negated = !(rn2(10) >= 3 * armpro); if (is_demon(youmonst.data) && !rn2(13) && !uwep && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS && u.umonnum != PM_BALROG) { demonpet(); return 0; } switch (mattk->adtyp) { case AD_STUN: if (!Blind) pline("%s %s for a moment.", Monnam(mdef), makeplural(stagger(pd, "stagger"))); mdef->mstun = 1; goto physical; case AD_LEGS: #if 0 if (u.ucancelled) { tmp = 0; break; } #endif goto physical; case AD_WERE: /* no special effect on monsters */ case AD_HEAL: /* likewise */ case AD_PHYS: physical: if (mattk->aatyp == AT_WEAP) { if (uwep) tmp = 0; } else if (mattk->aatyp == AT_KICK) { if (thick_skinned(pd)) tmp = 0; if (pd == &mons[PM_SHADE]) { if (!(uarmf && uarmf->blessed)) { impossible("bad shade attack function flow?"); tmp = 0; } else tmp = rnd(4); /* bless damage */ } /* add ring(s) of increase damage */ if (u.udaminc > 0) { /* applies even if damage was 0 */ tmp += u.udaminc; } else if (tmp > 0) { /* ring(s) might be negative; avoid converting 0 to non-0 or positive to non-positive */ tmp += u.udaminc; if (tmp < 1) tmp = 1; } } break; case AD_FIRE: if (negated) { tmp = 0; break; } if (!Blind) pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (!Blind) pline("%s burns completely!", Monnam(mdef)); xkilled(mdef, 2); tmp = 0; break; /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ } tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (resists_fire(mdef)) { if (!Blind) pline_The("fire doesn't heat %s!", mon_nam(mdef)); golemeffects(mdef, AD_FIRE, tmp); shieldeff(mdef->mx, mdef->my); tmp = 0; } /* only potions damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); break; case AD_COLD: if (negated) { tmp = 0; break; } if (!Blind) pline("%s is covered in frost!", Monnam(mdef)); if (resists_cold(mdef)) { shieldeff(mdef->mx, mdef->my); if (!Blind) pline_The("frost doesn't chill %s!", mon_nam(mdef)); golemeffects(mdef, AD_COLD, tmp); tmp = 0; } tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); break; case AD_ELEC: if (negated) { tmp = 0; break; } if (!Blind) pline("%s is zapped!", Monnam(mdef)); tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); if (resists_elec(mdef)) { if (!Blind) pline_The("zap doesn't shock %s!", mon_nam(mdef)); golemeffects(mdef, AD_ELEC, tmp); shieldeff(mdef->mx, mdef->my); tmp = 0; } /* only rings damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC); break; case AD_ACID: if (resists_acid(mdef)) tmp = 0; break; case AD_STON: if (!munstone(mdef, TRUE)) minstapetrify(mdef, TRUE); tmp = 0; break; case AD_SSEX: case AD_SEDU: case AD_SITM: steal_it(mdef, mattk); tmp = 0; break; case AD_SGLD: /* This you as a leprechaun, so steal real gold only, no lesser coins */ { struct obj *mongold = findgold(mdef->minvent); if (mongold) { obj_extract_self(mongold); if (merge_choice(invent, mongold) || inv_cnt(FALSE) < 52) { addinv(mongold); Your("purse feels heavier."); } else { You("grab %s's gold, but find no room in your knapsack.", mon_nam(mdef)); dropy(mongold); } } } exercise(A_DEX, TRUE); tmp = 0; break; case AD_TLPT: if (tmp <= 0) tmp = 1; if (!negated && tmp < mdef->mhp) { char nambuf[BUFSZ]; boolean u_saw_mon = canseemon(mdef) || (u.uswallow && u.ustuck == mdef); /* record the name before losing sight of monster */ Strcpy(nambuf, Monnam(mdef)); if (u_teleport_mon(mdef, FALSE) && u_saw_mon && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef))) pline("%s suddenly disappears!", nambuf); } break; case AD_BLND: if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *) 0)) { if (!Blind && mdef->mcansee) pline("%s is blinded.", Monnam(mdef)); mdef->mcansee = 0; tmp += mdef->mblinded; if (tmp > 127) tmp = 127; mdef->mblinded = tmp; } tmp = 0; break; case AD_CURS: if (night() && !rn2(10) && !mdef->mcan) { if (pd == &mons[PM_CLAY_GOLEM]) { if (!Blind) pline("Some writing vanishes from %s head!", s_suffix(mon_nam(mdef))); xkilled(mdef, 0); /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ } else { mdef->mcan = 1; You("chuckle."); } } tmp = 0; break; case AD_DRLI: if (!negated && !rn2(3) && !resists_drli(mdef)) { int xtmp = d(2, 6); pline("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= xtmp; if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) { pline("%s dies!", Monnam(mdef)); xkilled(mdef, 0); } else mdef->m_lev--; tmp = 0; } break; case AD_RUST: if (pd == &mons[PM_IRON_GOLEM]) { pline("%s falls to pieces!", Monnam(mdef)); xkilled(mdef, 0); } erode_armor(mdef, ERODE_RUST); tmp = 0; break; case AD_CORR: erode_armor(mdef, ERODE_CORRODE); tmp = 0; break; case AD_DCAY: if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { pline("%s falls to pieces!", Monnam(mdef)); xkilled(mdef, 0); } erode_armor(mdef, ERODE_ROT); tmp = 0; break; case AD_DREN: if (!negated && !rn2(4)) xdrainenergym(mdef, TRUE); tmp = 0; break; case AD_DRST: case AD_DRDX: case AD_DRCO: if (!negated && !rn2(8)) { Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk)); if (resists_poison(mdef)) pline_The("poison doesn't seem to affect %s.", mon_nam(mdef)); else { if (!rn2(10)) { Your("poison was deadly..."); tmp = mdef->mhp; } else tmp += rn1(10, 6); } } break; case AD_DRIN: { struct obj *helmet; if (notonhead || !has_head(pd)) { pline("%s doesn't seem harmed.", Monnam(mdef)); tmp = 0; if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) { if (!Slimed) { You("suck in some slime and don't feel very well."); make_slimed(10L, (char *) 0); } } break; } if (m_slips_free(mdef, mattk)) break; if ((helmet = which_armor(mdef, W_ARMH)) != 0 && rn2(8)) { pline("%s %s blocks your attack to %s head.", s_suffix(Monnam(mdef)), helm_simple_name(helmet), mhis(mdef)); break; } (void) eat_brains(&youmonst, mdef, TRUE, &tmp); break; } case AD_STCK: if (!negated && !sticks(pd)) u.ustuck = mdef; /* it's now stuck to you */ break; case AD_WRAP: if (!sticks(pd)) { if (!u.ustuck && !rn2(10)) { if (m_slips_free(mdef, mattk)) { tmp = 0; } else { You("swing yourself around %s!", mon_nam(mdef)); u.ustuck = mdef; } } else if (u.ustuck == mdef) { /* Monsters don't wear amulets of magical breathing */ if (is_pool(u.ux, u.uy) && !is_swimmer(pd) && !amphibious(pd)) { You("drown %s...", mon_nam(mdef)); tmp = mdef->mhp; } else if (mattk->aatyp == AT_HUGS) pline("%s is being crushed.", Monnam(mdef)); } else { tmp = 0; if (flags.verbose) You("brush against %s %s.", s_suffix(mon_nam(mdef)), mbodypart(mdef, LEG)); } } else tmp = 0; break; case AD_PLYS: if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) { if (!Blind) pline("%s is frozen by you!", Monnam(mdef)); paralyze_monst(mdef, rnd(10)); } break; case AD_SLEE: if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { if (!Blind) pline("%s is put to sleep by you!", Monnam(mdef)); slept_monst(mdef); } break; case AD_SLIM: if (negated) break; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { if (!munslime(mdef, TRUE) && mdef->mhp > 0) { /* this assumes newcham() won't fail; since hero has a slime attack, green slimes haven't been geno'd */ You("turn %s into slime.", mon_nam(mdef)); if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE)) pd = mdef->data; } /* munslime attempt could have been fatal */ if (mdef->mhp < 1) return 2; /* skip death message */ tmp = 0; } break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ /* there's no msomearmor() function, so just do damage */ /* if (negated) break; */ break; case AD_SLOW: if (!negated && mdef->mspeed != MSLOW) { unsigned int oldspeed = mdef->mspeed; mon_adjust_speed(mdef, -1, (struct obj *) 0); if (mdef->mspeed != oldspeed && canseemon(mdef)) pline("%s slows down.", Monnam(mdef)); } break; case AD_CONF: if (!mdef->mconf) { if (canseemon(mdef)) pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; } break; default: tmp = 0; break; } mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */ if ((mdef->mhp -= tmp) < 1) { if (mdef->mtame && !cansee(mdef->mx, mdef->my)) { You_feel("embarrassed for a moment."); if (tmp) xkilled(mdef, 0); /* !tmp but hp<1: already killed */ } else if (!flags.verbose) { You("destroy it!"); if (tmp) xkilled(mdef, 0); } else if (tmp) killed(mdef); return 2; } return 1; } STATIC_OVL int explum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { register int tmp = d((int) mattk->damn, (int) mattk->damd); You("explode!"); switch (mattk->adtyp) { boolean resistance; /* only for cold/fire/elec */ case AD_BLND: if (!resists_blnd(mdef)) { pline("%s is blinded by your flash of light!", Monnam(mdef)); mdef->mblinded = min((int) mdef->mblinded + tmp, 127); mdef->mcansee = 0; } break; case AD_HALU: if (haseyes(mdef->data) && mdef->mcansee) { pline("%s is affected by your flash of light!", Monnam(mdef)); mdef->mconf = 1; } break; case AD_COLD: resistance = resists_cold(mdef); goto common; case AD_FIRE: resistance = resists_fire(mdef); goto common; case AD_ELEC: resistance = resists_elec(mdef); common: if (!resistance) { pline("%s gets blasted!", Monnam(mdef)); mdef->mhp -= tmp; if (mdef->mhp <= 0) { killed(mdef); return 2; } } else { shieldeff(mdef->mx, mdef->my); if (is_golem(mdef->data)) golemeffects(mdef, (int) mattk->adtyp, tmp); else pline_The("blast doesn't seem to affect %s.", mon_nam(mdef)); } break; default: break; } return 1; } STATIC_OVL void start_engulf(mdef) struct monst *mdef; { if (!Invisible) { map_location(u.ux, u.uy, TRUE); tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst)); tmp_at(mdef->mx, mdef->my); } You("engulf %s!", mon_nam(mdef)); delay_output(); delay_output(); } STATIC_OVL void end_engulf() { if (!Invisible) { tmp_at(DISP_END, 0); newsym(u.ux, u.uy); } } STATIC_OVL int gulpum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { #ifdef LINT /* static char msgbuf[BUFSZ]; */ char msgbuf[BUFSZ]; #else static char msgbuf[BUFSZ]; /* for nomovemsg */ #endif register int tmp; register int dam = d((int) mattk->damn, (int) mattk->damd); boolean fatal_gulp; struct obj *otmp; struct permonst *pd = mdef->data; /* Not totally the same as for real monsters. Specifically, these * don't take multiple moves. (It's just too hard, for too little * result, to program monsters which attack from inside you, which * would be necessary if done accurately.) Instead, we arbitrarily * kill the monster immediately for AD_DGST and we regurgitate them * after exactly 1 round of attack otherwise. -KAA */ if (!engulf_target(&youmonst, mdef)) return 0; if (u.uhunger < 1500 && !u.uswallow) { for (otmp = mdef->minvent; otmp; otmp = otmp->nobj) (void) snuff_lit(otmp); /* engulfing a cockatrice or digesting a Rider or Medusa */ fatal_gulp = (touch_petrifies(pd) && !Stone_resistance) || (mattk->adtyp == AD_DGST && (is_rider(pd) || (pd == &mons[PM_MEDUSA] && !Stone_resistance))); if ((mattk->adtyp == AD_DGST && !Slow_digestion) || fatal_gulp) eating_conducts(pd); if (fatal_gulp && !is_rider(pd)) { /* petrification */ char kbuf[BUFSZ]; const char *mname = pd->mname; if (!type_is_pname(pd)) mname = an(mname); You("englut %s.", mon_nam(mdef)); Sprintf(kbuf, "swallowing %s whole", mname); instapetrify(kbuf); } else { start_engulf(mdef); switch (mattk->adtyp) { case AD_DGST: /* eating a Rider or its corpse is fatal */ if (is_rider(pd)) { pline("Unfortunately, digesting any of it is fatal."); end_engulf(); Sprintf(killer.name, "unwisely tried to eat %s", pd->mname); killer.format = NO_KILLER_PREFIX; done(DIED); return 0; /* lifesaved */ } if (Slow_digestion) { dam = 0; break; } /* Use up amulet of life saving */ if (!!(otmp = mlifesaver(mdef))) m_useup(mdef, otmp); newuhs(FALSE); xkilled(mdef, 2); if (mdef->mhp > 0) { /* monster lifesaved */ You("hurriedly regurgitate the sizzling in your %s.", body_part(STOMACH)); } else { tmp = 1 + (pd->cwt >> 8); if (corpse_chance(mdef, &youmonst, TRUE) && !(mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) { /* nutrition only if there can be a corpse */ u.uhunger += (pd->cnutrit + 1) / 2; } else tmp = 0; Sprintf(msgbuf, "You totally digest %s.", mon_nam(mdef)); if (tmp != 0) { /* setting afternmv = end_engulf is tempting, * but will cause problems if the player is * attacked (which uses his real location) or * if his See_invisible wears off */ You("digest %s.", mon_nam(mdef)); if (Slow_digestion) tmp *= 2; nomul(-tmp); multi_reason = "digesting something"; nomovemsg = msgbuf; } else pline1(msgbuf); if (pd == &mons[PM_GREEN_SLIME]) { Sprintf(msgbuf, "%s isn't sitting well with you.", The(pd->mname)); if (!Unchanging) { make_slimed(5L, (char *) 0); } } else exercise(A_CON, TRUE); } end_engulf(); return 2; case AD_PHYS: if (youmonst.data == &mons[PM_FOG_CLOUD]) { pline("%s is laden with your moisture.", Monnam(mdef)); if (amphibious(pd) && !flaming(pd)) { dam = 0; pline("%s seems unharmed.", Monnam(mdef)); } } else pline("%s is pummeled with your debris!", Monnam(mdef)); break; case AD_ACID: pline("%s is covered with your goo!", Monnam(mdef)); if (resists_acid(mdef)) { pline("It seems harmless to %s.", mon_nam(mdef)); dam = 0; } break; case AD_BLND: if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *) 0)) { if (mdef->mcansee) pline("%s can't see in there!", Monnam(mdef)); mdef->mcansee = 0; dam += mdef->mblinded; if (dam > 127) dam = 127; mdef->mblinded = dam; } dam = 0; break; case AD_ELEC: if (rn2(2)) { pline_The("air around %s crackles with electricity.", mon_nam(mdef)); if (resists_elec(mdef)) { pline("%s seems unhurt.", Monnam(mdef)); dam = 0; } golemeffects(mdef, (int) mattk->adtyp, dam); } else dam = 0; break; case AD_COLD: if (rn2(2)) { if (resists_cold(mdef)) { pline("%s seems mildly chilly.", Monnam(mdef)); dam = 0; } else pline("%s is freezing to death!", Monnam(mdef)); golemeffects(mdef, (int) mattk->adtyp, dam); } else dam = 0; break; case AD_FIRE: if (rn2(2)) { if (resists_fire(mdef)) { pline("%s seems mildly hot.", Monnam(mdef)); dam = 0; } else pline("%s is burning to a crisp!", Monnam(mdef)); golemeffects(mdef, (int) mattk->adtyp, dam); } else dam = 0; break; case AD_DREN: if (!rn2(4)) xdrainenergym(mdef, TRUE); dam = 0; break; } end_engulf(); if ((mdef->mhp -= dam) <= 0) { killed(mdef); if (mdef->mhp <= 0) /* not lifesaved */ return 2; } You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel", mon_nam(mdef)); if (Slow_digestion || is_animal(youmonst.data)) { pline("Obviously, you didn't like %s taste.", s_suffix(mon_nam(mdef))); } } } return 0; } void missum(mdef, mattk, wouldhavehit) register struct monst *mdef; register struct attack *mattk; boolean wouldhavehit; { if (wouldhavehit) /* monk is missing due to penalty for wearing suit */ Your("armor is rather cumbersome..."); if (could_seduce(&youmonst, mdef, mattk)) You("pretend to be friendly to %s.", mon_nam(mdef)); else if (canspotmon(mdef) && flags.verbose) You("miss %s.", mon_nam(mdef)); else You("miss it."); if (!mdef->msleeping && mdef->mcanmove) wakeup(mdef); } /* attack monster as a monster. */ STATIC_OVL boolean hmonas(mon) register struct monst *mon; { struct attack *mattk, alt_attk; struct obj *weapon; boolean altwep = FALSE, weapon_used = FALSE; int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0; for (i = 0; i < NATTK; i++) { sum[i] = 0; mattk = getmattk(youmonst.data, i, sum, &alt_attk); switch (mattk->aatyp) { case AT_WEAP: use_weapon: /* Certain monsters don't use weapons when encountered as enemies, * but players who polymorph into them have hands or claws and * thus should be able to use weapons. This shouldn't prohibit * the use of most special abilities, either. * If monster has multiple claw attacks, only one can use weapon. */ weapon_used = TRUE; /* Potential problem: if the monster gets multiple weapon attacks, * we currently allow the player to get each of these as a weapon * attack. Is this really desirable? */ /* approximate two-weapon mode */ weapon = (altwep && uswapwep) ? uswapwep : uwep; altwep = !altwep; /* toggle for next attack */ tmp = find_roll_to_hit(mon, AT_WEAP, weapon, &attknum, &armorpenalty); dhit = (tmp > (dieroll = rnd(20)) || u.uswallow); /* Enemy dead, before any special abilities used */ if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk)) { sum[i] = 2; break; } else sum[i] = dhit; /* might be a worm that gets cut in half */ if (m_at(u.ux + u.dx, u.uy + u.dy) != mon) return (boolean) (nsum != 0); /* Do not print "You hit" message, since known_hitum * already did it. */ if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS) sum[i] = damageum(mon, mattk); break; case AT_CLAW: if (uwep && !cantwield(youmonst.data) && !weapon_used) goto use_weapon; /*FALLTHRU*/ case AT_TUCH: if (uwep && youmonst.data->mlet == S_LICH && !weapon_used) goto use_weapon; /*FALLTHRU*/ case AT_KICK: case AT_BITE: case AT_STNG: case AT_BUTT: case AT_TENT: tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0, &attknum, &armorpenalty); dhit = (tmp > (dieroll = rnd(20)) || u.uswallow); if (dhit) { int compat; if (!u.uswallow && (compat = could_seduce(&youmonst, mon, mattk))) { You("%s %s %s.", mon->mcansee && haseyes(mon->data) ? "smile at" : "talk to", mon_nam(mon), compat == 2 ? "engagingly" : "seductively"); /* doesn't anger it; no wakeup() */ sum[i] = damageum(mon, mattk); break; } wakeup(mon); /* maybe this check should be in damageum()? */ if (mon->data == &mons[PM_SHADE] && !(mattk->aatyp == AT_KICK && uarmf && uarmf->blessed)) { Your("attack passes harmlessly through %s.", mon_nam(mon)); break; } if (mattk->aatyp == AT_KICK) You("kick %s.", mon_nam(mon)); else if (mattk->aatyp == AT_BITE) You("bite %s.", mon_nam(mon)); else if (mattk->aatyp == AT_STNG) You("sting %s.", mon_nam(mon)); else if (mattk->aatyp == AT_BUTT) You("butt %s.", mon_nam(mon)); else if (mattk->aatyp == AT_TUCH) You("touch %s.", mon_nam(mon)); else if (mattk->aatyp == AT_TENT) Your("tentacles suck %s.", mon_nam(mon)); else You("hit %s.", mon_nam(mon)); sum[i] = damageum(mon, mattk); } else { missum(mon, mattk, (tmp + armorpenalty > dieroll)); } break; case AT_HUGS: /* automatic if prev two attacks succeed, or if * already grabbed in a previous attack */ dhit = 1; wakeup(mon); if (mon->data == &mons[PM_SHADE]) Your("hug passes harmlessly through %s.", mon_nam(mon)); else if (!sticks(mon->data) && !u.uswallow) { if (mon == u.ustuck) { pline("%s is being %s.", Monnam(mon), u.umonnum == PM_ROPE_GOLEM ? "choked" : "crushed"); sum[i] = damageum(mon, mattk); } else if (i >= 2 && sum[i - 1] && sum[i - 2]) { You("grab %s!", mon_nam(mon)); u.ustuck = mon; sum[i] = damageum(mon, mattk); } } break; case AT_EXPL: /* automatic hit if next to */ dhit = -1; wakeup(mon); sum[i] = explum(mon, mattk); break; case AT_ENGL: tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0, &attknum, &armorpenalty); if ((dhit = (tmp > rnd(20 + i)))) { wakeup(mon); if (mon->data == &mons[PM_SHADE]) Your("attempt to surround %s is harmless.", mon_nam(mon)); else { sum[i] = gulpum(mon, mattk); if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE || mon->data->mlet == S_MUMMY) && rn2(5) && !Sick_resistance) { You_feel("%ssick.", (Sick) ? "very " : ""); mdamageu(mon, rnd(8)); } } } else { missum(mon, mattk, FALSE); } break; case AT_MAGC: /* No check for uwep; if wielding nothing we want to * do the normal 1-2 points bare hand damage... */ if ((youmonst.data->mlet == S_KOBOLD || youmonst.data->mlet == S_ORC || youmonst.data->mlet == S_GNOME) && !weapon_used) goto use_weapon; case AT_NONE: case AT_BOOM: continue; /* Not break--avoid passive attacks from enemy */ case AT_BREA: case AT_SPIT: case AT_GAZE: /* all done using #monster command */ dhit = 0; break; default: /* Strange... */ impossible("strange attack of yours (%d)", mattk->aatyp); } if (dhit == -1) { u.mh = -1; /* dead in the current form */ rehumanize(); } if (sum[i] == 2) return (boolean) passive(mon, 1, 0, mattk->aatyp, FALSE); /* defender dead */ else { (void) passive(mon, sum[i], 1, mattk->aatyp, FALSE); nsum |= sum[i]; } if (!Upolyd) break; /* No extra attacks if no longer a monster */ if (multi < 0) break; /* If paralyzed while attacking, i.e. floating eye */ } return (boolean) (nsum != 0); } /* Special (passive) attacks on you by monsters done here. */ int passive(mon, mhit, malive, aatyp, wep_was_destroyed) register struct monst *mon; register boolean mhit; register int malive; uchar aatyp; boolean wep_was_destroyed; { register struct permonst *ptr = mon->data; register int i, tmp; for (i = 0;; i++) { if (i >= NATTK) return (malive | mhit); /* no passive attacks */ if (ptr->mattk[i].aatyp == AT_NONE) break; /* try this one */ } /* Note: tmp not always used */ if (ptr->mattk[i].damn) tmp = d((int) ptr->mattk[i].damn, (int) ptr->mattk[i].damd); else if (ptr->mattk[i].damd) tmp = d((int) mon->m_lev + 1, (int) ptr->mattk[i].damd); else tmp = 0; /* These affect you even if they just died. */ switch (ptr->mattk[i].adtyp) { case AD_FIRE: if (mhit && !mon->mcan) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); } break; case AD_ACID: if (mhit && rn2(2)) { if (Blind || !flags.verbose) You("are splashed!"); else You("are splashed by %s acid!", s_suffix(mon_nam(mon))); if (!Acid_resistance) mdamageu(mon, tmp); if (!rn2(30)) erode_armor(&youmonst, ERODE_CORRODE); } if (mhit) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); } exercise(A_STR, FALSE); break; case AD_STON: if (mhit) { /* successful attack */ long protector = attk_protection((int) aatyp); /* hero using monsters' AT_MAGC attack is hitting hand to hand rather than casting a spell */ if (aatyp == AT_MAGC) protector = W_ARMG; if (protector == 0L /* no protection */ || (protector == W_ARMG && !uarmg && !uwep && !wep_was_destroyed) || (protector == W_ARMF && !uarmf) || (protector == W_ARMH && !uarmh) || (protector == (W_ARMC | W_ARMG) && (!uarmc || !uarmg))) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { done_in_by(mon, STONING); /* "You turn to stone..." */ return 2; } } } break; case AD_RUST: if (mhit && !mon->mcan) { if (aatyp == AT_KICK) { if (uarmf) (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); } break; case AD_CORR: if (mhit && !mon->mcan) { if (aatyp == AT_KICK) { if (uarmf) (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, EF_GREASE | EF_VERBOSE); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i])); } break; case AD_MAGM: /* wrath of gods for attacking Oracle */ if (Antimagic) { shieldeff(u.ux, u.uy); pline("A hail of magic missiles narrowly misses you!"); } else { You("are hit by magic missiles appearing from thin air!"); mdamageu(mon, tmp); } break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (mhit) { struct obj *obj = (struct obj *) 0; if (aatyp == AT_KICK) { obj = uarmf; if (!obj) break; } else if (aatyp == AT_BITE || aatyp == AT_BUTT || (aatyp >= AT_STNG && aatyp < AT_WEAP)) { break; /* no object involved */ } passive_obj(mon, obj, &(ptr->mattk[i])); } break; default: break; } /* These only affect you if they still live. */ if (malive && !mon->mcan && rn2(3)) { switch (ptr->mattk[i].adtyp) { case AD_PLYS: if (ptr == &mons[PM_FLOATING_EYE]) { if (!canseemon(mon)) { break; } if (mon->mcansee) { if (ureflects("%s gaze is reflected by your %s.", s_suffix(Monnam(mon)))) { ; } else if (Free_action) { You("momentarily stiffen under %s gaze!", s_suffix(mon_nam(mon))); } else if (Hallucination && rn2(4)) { pline("%s looks %s%s.", Monnam(mon), !rn2(2) ? "" : "rather ", !rn2(2) ? "numb" : "stupified"); } else { You("are frozen by %s gaze!", s_suffix(mon_nam(mon))); nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127); multi_reason = "frozen by a monster's gaze"; nomovemsg = 0; } } else { pline("%s cannot defend itself.", Adjmonnam(mon, "blind")); if (!rn2(500)) change_luck(-1); } } else if (Free_action) { You("momentarily stiffen."); } else { /* gelatinous cube */ You("are frozen by %s!", mon_nam(mon)); nomovemsg = You_can_move_again; nomul(-tmp); multi_reason = "frozen by a monster"; exercise(A_DEX, FALSE); } break; case AD_COLD: /* brown mold or blue jelly */ if (monnear(mon, u.ux, u.uy)) { if (Cold_resistance) { shieldeff(u.ux, u.uy); You_feel("a mild chill."); ugolemeffects(AD_COLD, tmp); break; } You("are suddenly very cold!"); mdamageu(mon, tmp); /* monster gets stronger with your heat! */ mon->mhp += tmp / 2; if (mon->mhpmax < mon->mhp) mon->mhpmax = mon->mhp; /* at a certain point, the monster will reproduce! */ if (mon->mhpmax > ((int) (mon->m_lev + 1) * 8)) (void) split_mon(mon, &youmonst); } break; case AD_STUN: /* specifically yellow mold */ if (!Stunned) make_stunned((long) tmp, TRUE); break; case AD_FIRE: if (monnear(mon, u.ux, u.uy)) { if (Fire_resistance) { shieldeff(u.ux, u.uy); You_feel("mildly warm."); ugolemeffects(AD_FIRE, tmp); break; } You("are suddenly very hot!"); mdamageu(mon, tmp); /* fire damage */ } break; case AD_ELEC: if (Shock_resistance) { shieldeff(u.ux, u.uy); You_feel("a mild tingle."); ugolemeffects(AD_ELEC, tmp); break; } You("are jolted with electricity!"); mdamageu(mon, tmp); break; default: break; } } return (malive | mhit); } /* * Special (passive) attacks on an attacking object by monsters done here. * Assumes the attack was successful. */ void passive_obj(mon, obj, mattk) register struct monst *mon; register struct obj *obj; /* null means pick uwep, uswapwep or uarmg */ struct attack *mattk; /* null means we find one internally */ { struct permonst *ptr = mon->data; register int i; /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */ if (!obj) { obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep; if (!obj && mattk->adtyp == AD_ENCH) obj = uarmg; /* no weapon? then must be gloves */ if (!obj) return; /* no object to affect */ } /* if caller hasn't specified an attack, find one */ if (!mattk) { for (i = 0;; i++) { if (i >= NATTK) return; /* no passive attacks */ if (ptr->mattk[i].aatyp == AT_NONE) break; /* try this one */ } mattk = &(ptr->mattk[i]); } switch (mattk->adtyp) { case AD_FIRE: if (!rn2(6) && !mon->mcan) { (void) erode_obj(obj, NULL, ERODE_BURN, EF_NONE); } break; case AD_ACID: if (!rn2(6)) { (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE); } break; case AD_RUST: if (!mon->mcan) { (void) erode_obj(obj, NULL, ERODE_RUST, EF_NONE); } break; case AD_CORR: if (!mon->mcan) { (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE); } break; case AD_ENCH: if (!mon->mcan) { if (drain_item(obj) && carried(obj) && (obj->known || obj->oclass == ARMOR_CLASS)) { pline("%s less effective.", Yobjnam2(obj, "seem")); } break; } default: break; } if (carried(obj)) update_inventory(); } /* Note: caller must ascertain mtmp is mimicking... */ void stumble_onto_mimic(mtmp) struct monst *mtmp; { const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0; if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK)) u.ustuck = mtmp; if (Blind) { if (!Blind_telepat) what = generic; /* with default fmt */ else if (mtmp->m_ap_type == M_AP_MONSTER) what = a_monnam(mtmp); /* differs from what was sensed */ } else { int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph; if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor || glyph_to_cmap(glyph) == S_vcdoor)) fmt = "The door actually was %s!"; else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE) fmt = "That gold was %s!"; /* cloned Wiz starts out mimicking some other monster and might make himself invisible before being revealed */ if (mtmp->minvis && !See_invisible) what = generic; else what = a_monnam(mtmp); } if (what) pline(fmt, what); wakeup(mtmp); /* clears mimicking */ /* if hero is blind, wakeup() won't display the monster even though it's no longer concealed */ if (!canspotmon(mtmp) && !glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) map_invisible(mtmp->mx, mtmp->my); } STATIC_OVL void nohandglow(mon) struct monst *mon; { char *hands = makeplural(body_part(HAND)); if (!u.umconf || mon->mconf) return; if (u.umconf == 1) { if (Blind) Your("%s stop tingling.", hands); else Your("%s stop glowing %s.", hands, hcolor(NH_RED)); } else { if (Blind) pline_The("tingling in your %s lessens.", hands); else Your("%s no longer glow so brightly %s.", hands, hcolor(NH_RED)); } u.umconf--; } int flash_hits_mon(mtmp, otmp) struct monst *mtmp; struct obj *otmp; /* source of flash */ { int tmp, amt, res = 0, useeit = canseemon(mtmp); if (mtmp->msleeping) { mtmp->msleeping = 0; if (useeit) { pline_The("flash awakens %s.", mon_nam(mtmp)); res = 1; } } else if (mtmp->data->mlet != S_LIGHT) { if (!resists_blnd(mtmp)) { tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my); if (useeit) { pline("%s is blinded by the flash!", Monnam(mtmp)); res = 1; } if (mtmp->data == &mons[PM_GREMLIN]) { /* Rule #1: Keep them out of the light. */ amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4) : rn2(min(mtmp->mhp, 4)); light_hits_gremlin(mtmp, amt); } if (mtmp->mhp > 0) { if (!context.mon_moving) setmangry(mtmp); if (tmp < 9 && !mtmp->isshk && rn2(4)) monflee(mtmp, rn2(4) ? rnd(100) : 0, FALSE, TRUE); mtmp->mcansee = 0; mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp); } } } return res; } void light_hits_gremlin(mon, dmg) struct monst *mon; int dmg; { pline("%s %s!", Monnam(mon), (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain"); if ((mon->mhp -= dmg) <= 0) { if (context.mon_moving) monkilled(mon, (char *) 0, AD_BLND); else killed(mon); } else if (cansee(mon->mx, mon->my) && !canspotmon(mon)) { map_invisible(mon->mx, mon->my); } } /*uhitm.c*/ nethack-3.6.0/src/vault.c0000664000076400007660000007324012614367060014236 0ustar paxedpaxed/* NetHack 3.6 vault.c $NHDT-Date: 1446078792 2015/10/29 00:33:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL struct monst *NDECL(findgd); STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(blackout, (int, int)); STATIC_DCL void FDECL(restfakecorr, (struct monst *)); STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *, int, int)); STATIC_DCL void FDECL(move_gold, (struct obj *, int)); STATIC_DCL void FDECL(wallify_vault, (struct monst *)); void newegd(mtmp) struct monst *mtmp; { if (!mtmp->mextra) mtmp->mextra = newmextra(); if (!EGD(mtmp)) { EGD(mtmp) = (struct egd *) alloc(sizeof(struct egd)); (void) memset((genericptr_t) EGD(mtmp), 0, sizeof(struct egd)); } } void free_egd(mtmp) struct monst *mtmp; { if (mtmp->mextra && EGD(mtmp)) { free((genericptr_t) EGD(mtmp)); EGD(mtmp) = (struct egd *) 0; } mtmp->isgd = 0; } STATIC_OVL boolean clear_fcorr(grd, forceshow) struct monst *grd; boolean forceshow; { register int fcx, fcy, fcbeg; struct monst *mtmp; boolean sawcorridor = FALSE; struct egd *egrd = EGD(grd); struct trap *trap; struct rm *lev; if (!on_level(&egrd->gdlevel, &u.uz)) return TRUE; while ((fcbeg = egrd->fcbeg) < egrd->fcend) { fcx = egrd->fakecorr[fcbeg].fx; fcy = egrd->fakecorr[fcbeg].fy; if ((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) && egrd->gddone) forceshow = TRUE; if ((u.ux == fcx && u.uy == fcy && grd->mhp > 0) || (!forceshow && couldsee(fcx, fcy)) || (Punished && !carried(uball) && uball->ox == fcx && uball->oy == fcy)) return FALSE; if ((mtmp = m_at(fcx, fcy)) != 0) { if (mtmp->isgd) { return FALSE; } else if (!in_fcorridor(grd, u.ux, u.uy)) { if (mtmp->mtame) yelp(mtmp); (void) rloc(mtmp, FALSE); } } lev = &levl[fcx][fcy]; if (lev->typ == CORR && cansee(fcx, fcy)) sawcorridor = TRUE; lev->typ = egrd->fakecorr[fcbeg].ftyp; if (IS_STWALL(lev->typ)) { /* destroy any trap here (pit dug by you, hole dug via wand while levitating or by monster, bear trap or land mine via object, spun web) when spot reverts to stone */ if ((trap = t_at(fcx, fcy)) != 0) deltrap(trap); /* undo scroll/wand/spell of light affecting this spot */ if (lev->typ == STONE) blackout(fcx, fcy); } map_location(fcx, fcy, 1); /* bypass vision */ if (!ACCESSIBLE(lev->typ)) block_point(fcx, fcy); vision_full_recalc = 1; egrd->fcbeg++; } if (sawcorridor) pline_The("corridor disappears."); if (IS_ROCK(levl[u.ux][u.uy].typ)) You("are encased in rock."); return TRUE; } /* as a temporary corridor is removed, set stone locations and adjacent spots to unlit; if player used scroll/wand/spell of light while inside the corridor, we don't want the light to reappear if/when a new tunnel goes through the same area */ STATIC_OVL void blackout(x, y) int x, y; { struct rm *lev; int i, j; for (i = x - 1; i <= x + 1; ++i) for (j = y - 1; j <= y + 1; ++j) { if (!isok(i, j)) continue; lev = &levl[i][j]; /* [possible bug: when (i != x || j != y), perhaps we ought to check whether the spot on the far side is lit instead of doing a blanket blackout of adjacent locations] */ if (lev->typ == STONE) lev->lit = lev->waslit = 0; /* mark as not having been seen from */ unset_seenv(lev, x, y, i, j); } } STATIC_OVL void restfakecorr(grd) struct monst *grd; { /* it seems you left the corridor - let the guard disappear */ if (clear_fcorr(grd, FALSE)) { grd->isgd = 0; /* dmonsfree() should delete this mon */ mongone(grd); } } /* called in mon.c */ boolean grddead(grd) struct monst *grd; { boolean dispose = clear_fcorr(grd, TRUE); if (!dispose) { /* destroy guard's gold; drop any other inventory */ relobj(grd, 0, FALSE); /* guard is dead; monster traversal loops should skip it */ grd->mhp = 0; if (grd == context.polearm.hitmon) context.polearm.hitmon = 0; /* see comment by newpos in gd_move() */ remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, 0, 0); EGD(grd)->ogx = grd->mx; EGD(grd)->ogy = grd->my; dispose = clear_fcorr(grd, TRUE); } if (dispose) grd->isgd = 0; /* for dmonsfree() */ return dispose; } STATIC_OVL boolean in_fcorridor(grd, x, y) struct monst *grd; int x, y; { register int fci; struct egd *egrd = EGD(grd); for (fci = egrd->fcbeg; fci < egrd->fcend; fci++) if (x == egrd->fakecorr[fci].fx && y == egrd->fakecorr[fci].fy) return TRUE; return FALSE; } STATIC_OVL struct monst * findgd() { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->isgd && on_level(&(EGD(mtmp)->gdlevel), &u.uz)) return mtmp; } return (struct monst *) 0; } char vault_occupied(array) char *array; { register char *ptr; for (ptr = array; *ptr; ptr++) if (rooms[*ptr - ROOMOFFSET].rtype == VAULT) return *ptr; return '\0'; } void invault() { #ifdef BSD_43_BUG int dummy; /* hack to avoid schain botch */ #endif struct monst *guard; boolean gsensed; int trycount, vaultroom = (int) vault_occupied(u.urooms); if (!vaultroom) { u.uinvault = 0; return; } vaultroom -= ROOMOFFSET; guard = findgd(); if (++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */ char buf[BUFSZ]; register int x, y, dd, gx, gy; int lx = 0, ly = 0; long umoney; /* first find the goal for the guard */ for (dd = 2; (dd < ROWNO || dd < COLNO); dd++) { for (y = u.uy - dd; y <= u.uy + dd; ly = y, y++) { if (y < 0 || y > ROWNO - 1) continue; for (x = u.ux - dd; x <= u.ux + dd; lx = x, x++) { if (y != u.uy - dd && y != u.uy + dd && x != u.ux - dd) x = u.ux + dd; if (x < 1 || x > COLNO - 1) continue; if (levl[x][y].typ == CORR) { if (x < u.ux) lx = x + 1; else if (x > u.ux) lx = x - 1; else lx = x; if (y < u.uy) ly = y + 1; else if (y > u.uy) ly = y - 1; else ly = y; if (levl[lx][ly].typ != STONE && levl[lx][ly].typ != CORR) goto incr_radius; goto fnd; } } } incr_radius: ; } impossible("Not a single corridor on this level??"); tele(); return; fnd: gx = x; gy = y; /* next find a good place for a door in the wall */ x = u.ux; y = u.uy; if (levl[x][y].typ != ROOM) { /* player dug a door and is in it */ if (levl[x + 1][y].typ == ROOM) x = x + 1; else if (levl[x][y + 1].typ == ROOM) y = y + 1; else if (levl[x - 1][y].typ == ROOM) x = x - 1; else if (levl[x][y - 1].typ == ROOM) y = y - 1; else if (levl[x + 1][y + 1].typ == ROOM) { x = x + 1; y = y + 1; } else if (levl[x - 1][y - 1].typ == ROOM) { x = x - 1; y = y - 1; } else if (levl[x + 1][y - 1].typ == ROOM) { x = x + 1; y = y - 1; } else if (levl[x - 1][y + 1].typ == ROOM) { x = x - 1; y = y + 1; } } while (levl[x][y].typ == ROOM) { register int dx, dy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if (abs(gx - x) >= abs(gy - y)) x += dx; else y += dy; } if (x == u.ux && y == u.uy) { if (levl[x + 1][y].typ == HWALL || levl[x + 1][y].typ == DOOR) x = x + 1; else if (levl[x - 1][y].typ == HWALL || levl[x - 1][y].typ == DOOR) x = x - 1; else if (levl[x][y + 1].typ == VWALL || levl[x][y + 1].typ == DOOR) y = y + 1; else if (levl[x][y - 1].typ == VWALL || levl[x][y - 1].typ == DOOR) y = y - 1; else return; } /* make something interesting happen */ if (!(guard = makemon(&mons[PM_GUARD], x, y, MM_EGD))) return; guard->isgd = 1; guard->mpeaceful = 1; set_malign(guard); EGD(guard)->gddone = 0; EGD(guard)->ogx = x; EGD(guard)->ogy = y; assign_level(&(EGD(guard)->gdlevel), &u.uz); EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; reset_faint(); /* if fainted - wake up */ gsensed = !canspotmon(guard); if (!gsensed) pline("Suddenly one of the Vault's %s enters!", makeplural(guard->data->mname)); else pline("Someone else has entered the Vault."); newsym(guard->mx, guard->my); if (u.uswallow) { /* can't interrogate hero, don't interrogate engulfer */ verbalize("What's going on here?"); if (gsensed) pline_The("other presence vanishes."); mongone(guard); return; } if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) { if (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance != GOLD_PIECE) verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst)); /* You're mimicking some object or you're hidden. */ pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Strangled || is_silent(youmonst.data) || multi < 0) { /* [we ought to record whether this this message has already been given in order to vary it upon repeat visits, but discarding the monster and its egd data renders that hard] */ verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } stop_occupation(); /* if occupied, stop it *now* */ if (multi > 0) { nomul(0); unmul((char *) 0); } trycount = 5; do { getlin("\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); } while (!letter(buf[0]) && --trycount > 0); if (u.ualign.type == A_LAWFUL /* ignore trailing text, in case player includes rank */ && strncmpi(buf, plname, (int) strlen(plname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") || !strcmpi(buf, "Creosote")) { if (!mvitals[PM_CROESUS].died) { verbalize( "Oh, yes, of course. Sorry to have disturbed you."); mongone(guard); } else { setmangry(guard); verbalize("Back from the dead, are you? I'll remedy that!"); /* don't want guard to waste next turn wielding a weapon */ if (!MON_WEP(guard)) { guard->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(guard); } } return; } verbalize("I don't know you."); umoney = money_cnt(invent); if (Deaf) { ; } else if (!umoney && !hidden_gold()) { verbalize("Please follow me."); } else { if (!umoney) verbalize("You have hidden gold."); verbalize( "Most likely all your gold was stolen from this vault."); verbalize("Please drop that gold and follow me."); } EGD(guard)->gdx = gx; EGD(guard)->gdy = gy; EGD(guard)->fcbeg = 0; EGD(guard)->fakecorr[0].fx = x; EGD(guard)->fakecorr[0].fy = y; if (IS_WALL(levl[x][y].typ)) EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ; else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx; xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy; if (x == lowx - 1 && y == lowy - 1) EGD(guard)->fakecorr[0].ftyp = TLCORNER; else if (x == hix + 1 && y == lowy - 1) EGD(guard)->fakecorr[0].ftyp = TRCORNER; else if (x == lowx - 1 && y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = BLCORNER; else if (x == hix + 1 && y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = BRCORNER; else if (y == lowy - 1 || y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = HWALL; else if (x == lowx - 1 || x == hix + 1) EGD(guard)->fakecorr[0].ftyp = VWALL; } levl[x][y].typ = DOOR; levl[x][y].doormask = D_NODOOR; unblock_point(x, y); /* doesn't block light */ EGD(guard)->fcend = 1; EGD(guard)->warncnt = 1; } } STATIC_OVL void move_gold(gold, vroom) struct obj *gold; int vroom; { xchar nx, ny; remove_object(gold); newsym(gold->ox, gold->oy); nx = rooms[vroom].lx + rn2(2); ny = rooms[vroom].ly + rn2(2); place_object(gold, nx, ny); stackobj(gold); newsym(nx, ny); } STATIC_OVL void wallify_vault(grd) struct monst *grd; { int x, y, typ; int vlt = EGD(grd)->vroom; char tmp_viz; xchar lox = rooms[vlt].lx - 1, hix = rooms[vlt].hx + 1, loy = rooms[vlt].ly - 1, hiy = rooms[vlt].hy + 1; struct monst *mon; struct obj *gold; struct trap *trap; boolean fixed = FALSE; boolean movedgold = FALSE; for (x = lox; x <= hix; x++) for (y = loy; y <= hiy; y++) { /* if not on the room boundary, skip ahead */ if (x != lox && x != hix && y != loy && y != hiy) continue; if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { if ((mon = m_at(x, y)) != 0 && mon != grd) { if (mon->mtame) yelp(mon); (void) rloc(mon, FALSE); } if ((gold = g_at(x, y)) != 0) { move_gold(gold, EGD(grd)->vroom); movedgold = TRUE; } if ((trap = t_at(x, y)) != 0) deltrap(trap); if (x == lox) typ = (y == loy) ? TLCORNER : (y == hiy) ? BLCORNER : VWALL; else if (x == hix) typ = (y == loy) ? TRCORNER : (y == hiy) ? BRCORNER : VWALL; else /* not left or right side, must be top or bottom */ typ = HWALL; levl[x][y].typ = typ; levl[x][y].doormask = 0; /* * hack: player knows walls are restored because of the * message, below, so show this on the screen. */ tmp_viz = viz_array[y][x]; viz_array[y][x] = IN_SIGHT | COULD_SEE; newsym(x, y); viz_array[y][x] = tmp_viz; block_point(x, y); fixed = TRUE; } } if (movedgold || fixed) { if (in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my)) pline("%s whispers an incantation.", noit_Monnam(grd)); else You_hear("a distant chant."); if (movedgold) pline("A mysterious force moves the gold into the vault."); if (fixed) pline_The("damaged vault's walls are magically restored!"); } } /* * return 1: guard moved, 0: guard didn't, -1: let m_move do it, -2: died */ int gd_move(grd) register struct monst *grd; { int x, y, nx, ny, m, n; int dx, dy, gx, gy, fci; uchar typ; struct fakecorridor *fcp; register struct egd *egrd = EGD(grd); struct rm *crm; boolean goldincorridor = FALSE, u_in_vault = vault_occupied(u.urooms) ? TRUE : FALSE, grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT) ? TRUE : FALSE; boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0); long umoney = money_cnt(invent); register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); boolean see_guard, newspot = FALSE; if (!on_level(&(egrd->gdlevel), &u.uz)) return -1; nx = ny = m = n = 0; if (!u_in_vault && !grd_in_vault) wallify_vault(grd); if (!grd->mpeaceful) { if (semi_dead) { egrd->gddone = 1; goto newpos; } if (!u_in_vault && (grd_in_vault || (in_fcorridor(grd, grd->mx, grd->my) && !in_fcorridor(grd, u.ux, u.uy)))) { (void) rloc(grd, FALSE); wallify_vault(grd); (void) clear_fcorr(grd, TRUE); goto letknow; } if (!in_fcorridor(grd, grd->mx, grd->my)) (void) clear_fcorr(grd, TRUE); return -1; } if (abs(egrd->ogx - grd->mx) > 1 || abs(egrd->ogy - grd->my) > 1) return -1; /* teleported guard - treat as monster */ if (egrd->witness) { verbalize("How dare you %s that gold, scoundrel!", (egrd->witness & GD_EATGOLD) ? "consume" : "destroy"); egrd->witness = 0; grd->mpeaceful = 0; return -1; } if (egrd->fcend == 1) { if (u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) { if (egrd->warncnt == 3 && !Deaf) verbalize("I repeat, %sfollow me!", u_carry_gold ? (!umoney ? "drop that hidden money and " : "drop that money and ") : ""); if (egrd->warncnt == 7) { m = grd->mx; n = grd->my; if (!Deaf) verbalize("You've been warned, knave!"); mnexto(grd); levl[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m, n); grd->mpeaceful = 0; return -1; } /* not fair to get mad when (s)he's fainted or paralyzed */ if (!is_fainted() && multi >= 0) egrd->warncnt++; return 0; } if (!u_in_vault) { if (u_carry_gold) { /* player teleported */ m = grd->mx; n = grd->my; (void) rloc(grd, TRUE); levl[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m, n); grd->mpeaceful = 0; letknow: if (!cansee(grd->mx, grd->my) || !mon_visible(grd)) You_hear("the shrill sound of a guard's whistle."); else You(um_dist(grd->mx, grd->my, 2) ? "see %s approaching." : "are confronted by %s.", /* "an angry guard" */ x_monnam(grd, ARTICLE_A, "angry", 0, FALSE)); return -1; } else { if (!Deaf) verbalize("Well, begone."); wallify_vault(grd); egrd->gddone = 1; goto cleanup; } } } if (egrd->fcend > 1) { if (egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) && !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) && levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ == egrd->fakecorr[0].ftyp) { pline("%s, confused, disappears.", noit_Monnam(grd)); disappear_msg_seen = TRUE; goto cleanup; } if (u_carry_gold && (in_fcorridor(grd, u.ux, u.uy) /* cover a 'blind' spot */ || (egrd->fcend > 1 && u_in_vault))) { if (!grd->mx) { restfakecorr(grd); return -2; } if (egrd->warncnt < 6) { egrd->warncnt = 6; if (!Deaf) verbalize("Drop all your gold, scoundrel!"); return 0; } else { if (!Deaf) verbalize("So be it, rogue!"); grd->mpeaceful = 0; return -1; } } } for (fci = egrd->fcbeg; fci < egrd->fcend; fci++) if (g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)) { m = egrd->fakecorr[fci].fx; n = egrd->fakecorr[fci].fy; goldincorridor = TRUE; } if (goldincorridor && !egrd->gddone) { x = grd->mx; y = grd->my; if (m == u.ux && n == u.uy) { struct obj *gold = g_at(m, n); /* Grab the gold from between the hero's feet. */ obj_extract_self(gold); add_to_minv(grd, gold); newsym(m, n); } else if (m == x && n == y) { mpickgold(grd); /* does a newsym */ } else { /* just for insurance... */ if (MON_AT(m, n) && m != grd->mx && n != grd->my) { if (!Deaf) verbalize("Out of my way, scum!"); (void) rloc(m_at(m, n), FALSE); } remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, m, n); mpickgold(grd); /* does a newsym */ } if (cansee(m, n)) pline("%s%s picks up the gold.", Monnam(grd), grd->mpeaceful ? " calms down and" : ""); if (x != grd->mx || y != grd->my) { remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, x, y); newsym(x, y); } if (!grd->mpeaceful) return -1; egrd->warncnt = 5; return 0; } if (um_dist(grd->mx, grd->my, 1) || egrd->gddone) { if (!egrd->gddone && !rn2(10) && !Deaf && !u.uswallow && !(u.ustuck && !sticks(youmonst.data))) verbalize("Move along!"); restfakecorr(grd); return 0; /* didn't move */ } x = grd->mx; y = grd->my; if (u_in_vault) goto nextpos; /* look around (hor & vert only) for accessible places */ for (nx = x - 1; nx <= x + 1; nx++) for (ny = y - 1; ny <= y + 1; ny++) { if ((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) { typ = (crm = &levl[nx][ny])->typ; if (!IS_STWALL(typ) && !IS_POOL(typ)) { if (in_fcorridor(grd, nx, ny)) goto nextnxy; if (*in_rooms(nx, ny, VAULT)) continue; /* seems we found a good place to leave him alone */ egrd->gddone = 1; if (ACCESSIBLE(typ)) goto newpos; #ifdef STUPID if (typ == SCORR) crm->typ = CORR; else crm->typ = DOOR; #else crm->typ = (typ == SCORR) ? CORR : DOOR; #endif if (crm->typ == DOOR) crm->doormask = D_NODOOR; goto proceed; } } nextnxy: ; } nextpos: nx = x; ny = y; gx = egrd->gdx; gy = egrd->gdy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if (abs(gx - x) >= abs(gy - y)) nx += dx; else ny += dy; while ((typ = (crm = &levl[nx][ny])->typ) != 0) { /* in view of the above we must have IS_WALL(typ) or typ == POOL */ /* must be a wall here */ if (isok(nx + nx - x, ny + ny - y) && !IS_POOL(typ) && IS_ROOM(levl[nx + nx - x][ny + ny - y].typ)) { crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } if (dy && nx != x) { nx = x; ny = y + dy; continue; } if (dx && ny != y) { ny = y; nx = x + dx; dy = 0; continue; } /* I don't like this, but ... */ if (IS_ROOM(typ)) { crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } break; } crm->typ = CORR; proceed: newspot = TRUE; unblock_point(nx, ny); /* doesn't block light */ if (cansee(nx, ny)) newsym(nx, ny); fcp = &(egrd->fakecorr[egrd->fcend]); if (egrd->fcend++ == FCSIZ) panic("fakecorr overflow"); fcp->fx = nx; fcp->fy = ny; fcp->ftyp = typ; newpos: if (egrd->gddone) { /* The following is a kludge. We need to keep */ /* the guard around in order to be able to make */ /* the fake corridor disappear as the player */ /* moves out of it, but we also need the guard */ /* out of the way. We send the guard to never- */ /* never land. We set ogx ogy to mx my in order */ /* to avoid a check at the top of this function. */ /* At the end of the process, the guard is killed */ /* in restfakecorr(). */ cleanup: x = grd->mx; y = grd->my; see_guard = canspotmon(grd); wallify_vault(grd); remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, 0, 0); egrd->ogx = grd->mx; egrd->ogy = grd->my; restfakecorr(grd); if (!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) { if (!disappear_msg_seen && see_guard) pline("Suddenly, %s disappears.", noit_mon_nam(grd)); return 1; } return -2; } egrd->ogx = grd->mx; /* update old positions */ egrd->ogy = grd->my; remove_monster(grd->mx, grd->my); place_monster(grd, nx, ny); if (newspot && g_at(nx, ny)) { /* if there's gold already here (most likely from mineralize()), pick it up now so that guard doesn't later think hero dropped it and give an inappropriate message */ mpickgold(grd); if (canspotmon(grd)) pline("%s picks up some gold.", Monnam(grd)); } else newsym(grd->mx, grd->my); restfakecorr(grd); return 1; } /* Routine when dying or quitting with a vault guard around */ void paygd() { register struct monst *grd = findgd(); long umoney = money_cnt(invent); struct obj *coins, *nextcoins; int gx, gy; char buf[BUFSZ]; if (!umoney || !grd) return; if (u.uinvault) { Your("%ld %s goes into the Magic Memory Vault.", umoney, currency(umoney)); gx = u.ux; gy = u.uy; } else { if (grd->mpeaceful) { /* guard has no "right" to your gold */ mongone(grd); return; } mnexto(grd); pline("%s remits your gold to the vault.", Monnam(grd)); gx = rooms[EGD(grd)->vroom].lx + rn2(2); gy = rooms[EGD(grd)->vroom].ly + rn2(2); Sprintf(buf, "To Croesus: here's the gold recovered from %s the %s.", plname, mons[u.umonster].mname); make_grave(gx, gy, buf); } for (coins = invent; coins; coins = nextcoins) { nextcoins = coins->nobj; if (objects[coins->otyp].oc_class == COIN_CLASS) { freeinv(coins); place_object(coins, gx, gy); stackobj(coins); } } mongone(grd); } long hidden_gold() { long value = 0L; struct obj *obj; for (obj = invent; obj; obj = obj->nobj) if (Has_contents(obj)) value += contained_gold(obj); /* unknown gold stuck inside statues may cause some consternation... */ return value; } /* prevent "You hear footsteps.." when inappropriate */ boolean gd_sound() { struct monst *grd = findgd(); if (vault_occupied(u.urooms)) return FALSE; else return (boolean) (grd == (struct monst *) 0); } void vault_gd_watching(activity) unsigned int activity; { struct monst *guard = findgd(); if (guard && guard->mcansee && m_canseeu(guard)) { if (activity == GD_EATGOLD || activity == GD_DESTROYGOLD) EGD(guard)->witness = activity; } } /*vault.c*/ nethack-3.6.0/src/version.c0000664000076400007660000002157012631241231014555 0ustar paxedpaxed/* NetHack 3.6 version.c $NHDT-Date: 1449328116 2015/12/05 15:08:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #include "date.h" /* * All the references to the contents of patchlevel.h have been moved * into makedefs.... */ #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #define BETA_INFO "" STATIC_DCL void FDECL(insert_rtoptions, (winid,char *,const char *)); /* fill buffer with short version (so caller can avoid including date.h) */ char * version_string(buf) char *buf; { return strcpy(buf, VERSION_STRING); } /* fill and return the given buffer with the long nethack version string */ char * getversionstring(buf) char *buf; { Strcpy(buf, VERSION_ID); #if defined(BETA) && defined(BETA_INFO) Sprintf(eos(buf), " %s", BETA_INFO); #endif #if defined(RUNTIME_PORT_ID) append_port_id(buf); #endif return buf; } /* the 'v' command */ int doversion() { char buf[BUFSZ]; pline("%s", getversionstring(buf)); return 0; } /* the '#version' command; also a choice for '?' */ int doextversion() { dlb *f; char *cr, *pd, buf[BUFSZ]; winid win = create_nhwindow(NHW_TEXT); boolean rtadded = FALSE; /* instead of using ``display_file(OPTIONS_USED,TRUE)'' we handle the file manually so we can include dynamic version info */ putstr(win, 0, getversionstring(buf)); f = dlb_fopen(OPTIONS_USED, "r"); if (!f) { putstr(win, 0, ""); Sprintf(buf, "[Configuration '%s' not available?]", OPTIONS_USED); putstr(win, 0, buf); } else { /* * already inserted above: * + outdented program name and version plus build date and time * dat/options; display the contents with lines prefixed by '-' * deleted: * - blank-line * - indented program name and version * blank-line * outdented feature header * - blank-line * indented feature list * spread over multiple lines * blank-line * outdented windowing header * - blank-line * indented windowing choices with * optional second line for default * - blank-line * - EOF */ boolean prolog = TRUE; /* to skip indented program name */ while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; if ((cr = index(buf, '\r')) != 0) *cr = 0; if (index(buf, '\t') != 0) (void) tabexpand(buf); if (*buf && *buf != ' ') { /* found outdented header; insert a separator since we'll have skipped corresponding blank line inside the file */ putstr(win, 0, ""); prolog = FALSE; } /* skip blank lines and prolog (progame name plus version) */ if (prolog || !*buf) continue; if (!rtadded) { const char *catchphrase = ", and basic NetHack features."; pd = strstri(buf, catchphrase); if (pd) { *pd = '\0'; insert_rtoptions(win, buf, &catchphrase[2]); rtadded = TRUE; /* only do it once */ } } if (*buf) putstr(win, 0, buf); } (void) dlb_fclose(f); display_nhwindow(win, FALSE); destroy_nhwindow(win); } return 0; } extern const char regex_id[]; static const char *rt_opts[] = { "pattern matching via", regex_id, }; static const char indent[] = " "; /* * 3.6.0 * Some optional stuff is no longer available to makedefs because * it depends which of several object files got linked into the * game image, so we insert those options here. */ STATIC_OVL void insert_rtoptions(win, buf, finalphrase) winid win; char *buf; const char *finalphrase; { char rtbuf[BUFSZ]; int l, i; const char *s1 = 0, *s2 = 0, *s3 = 0, *s4 = 0; if ((int) strlen(buf) >= (BUFSZ - 1)) return; strcpy(rtbuf, buf); for (i = 0; i < (SIZE(rt_opts) + 1); i += 2) { if (i < SIZE(rt_opts)) { s1 = ", "; s2 = rt_opts[i]; s3 = " "; s4 = rt_opts[i+1]; } else { s1 = " "; s2 = finalphrase; s3 = ""; s4 = ""; } l = (int) strlen(rtbuf) + (int) strlen(s1) + (int) strlen(s2) + (int) strlen(s3) + (int) strlen(s4) + 1; if (l <= (COLNO - 5) && l < (BUFSZ - 1)) { Strcat(rtbuf, s1); Strcat(rtbuf, s2); Strcat(rtbuf, s3); Strcat(rtbuf, s4); } else { putstr(win, 0, rtbuf); if (i >= SIZE(rt_opts)) s1 = ""; l = (int) strlen(indent) + (int) strlen(s1) + (int) strlen(s2) + (int) strlen(s3) + (int) strlen(s4) + 1; if (l <= (COLNO - 5) && l < (BUFSZ - 1)) { Strcpy(rtbuf, indent); Strcat(rtbuf, s1); Strcat(rtbuf, s2); Strcat(rtbuf, s3); Strcat(rtbuf, s4); } } } if (l) putstr(win, 0, rtbuf); *buf = '\0'; } #ifdef MICRO boolean comp_times(filetime) long filetime; { return (boolean) (filetime < BUILD_TIME); } #endif boolean check_version(version_data, filename, complain) struct version_info *version_data; const char *filename; boolean complain; { if ( #ifdef VERSION_COMPATIBILITY version_data->incarnation < VERSION_COMPATIBILITY || version_data->incarnation > VERSION_NUMBER #else version_data->incarnation != VERSION_NUMBER #endif ) { if (complain) pline("Version mismatch for file \"%s\".", filename); return FALSE; } else if ( #ifndef IGNORED_FEATURES version_data->feature_set != VERSION_FEATURES #else (version_data->feature_set & ~IGNORED_FEATURES) != (VERSION_FEATURES & ~IGNORED_FEATURES) #endif || version_data->entity_count != VERSION_SANITY1 || version_data->struct_sizes1 != VERSION_SANITY2 || version_data->struct_sizes2 != VERSION_SANITY3) { if (complain) pline("Configuration incompatibility for file \"%s\".", filename); return FALSE; } return TRUE; } /* this used to be based on file date and somewhat OS-dependant, but now examines the initial part of the file's contents */ boolean uptodate(fd, name) int fd; const char *name; { int rlen; struct version_info vers_info; boolean verbose = name ? TRUE : FALSE; rlen = read(fd, (genericptr_t) &vers_info, sizeof vers_info); minit(); /* ZEROCOMP */ if (rlen == 0) { if (verbose) { pline("File \"%s\" is empty?", name); wait_synch(); } return FALSE; } if (!check_version(&vers_info, name, verbose)) { if (verbose) wait_synch(); return FALSE; } return TRUE; } void store_version(fd) int fd; { static const struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3 }; bufoff(fd); /* bwrite() before bufon() uses plain write() */ bwrite(fd, (genericptr_t) &version_data, (unsigned) (sizeof version_data)); bufon(fd); return; } #ifdef AMIGA const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif unsigned long get_feature_notice_ver(str) char *str; { char buf[BUFSZ]; int ver_maj, ver_min, patch; char *istr[3]; int j = 0; if (!str) return 0L; str = strcpy(buf, str); istr[j] = str; while (*str) { if (*str == '.') { *str++ = '\0'; j++; istr[j] = str; if (j == 2) break; } else if (index("0123456789", *str) != 0) { str++; } else return 0L; } if (j != 2) return 0L; ver_maj = atoi(istr[0]); ver_min = atoi(istr[1]); patch = atoi(istr[2]); return FEATURE_NOTICE_VER(ver_maj, ver_min, patch); /* macro from hack.h */ } unsigned long get_current_feature_ver() { return FEATURE_NOTICE_VER(VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); } /*ARGUSED*/ const char * copyright_banner_line(indx) int indx; { #ifdef COPYRIGHT_BANNER_A if (indx == 1) return COPYRIGHT_BANNER_A; #endif #ifdef COPYRIGHT_BANNER_B if (indx == 2) return COPYRIGHT_BANNER_B; #endif #ifdef COPYRIGHT_BANNER_C if (indx == 3) return COPYRIGHT_BANNER_C; #endif #ifdef COPYRIGHT_BANNER_D if (indx == 4) return COPYRIGHT_BANNER_D; #endif return ""; } /*version.c*/ nethack-3.6.0/src/vision.c0000664000076400007660000027522412623572456014427 0ustar paxedpaxed/* NetHack 3.6 vision.c $NHDT-Date: 1448013598 2015/11/20 09:59:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Circles * ==================================================================*/ /* * These numbers are limit offsets for one quadrant of a circle of a given * radius (the first number of each line) from the source. The number in * the comment is the element number (so pointers can be set up). Each * "circle" has as many elements as its radius+1. The radius is the number * of points away from the source that the limit exists. The radius of the * offset on the same row as the source *is* included so we don't have to * make an extra check. For example, a circle of radius 4 has offsets: * * XXX +2 * ...X +3 * ....X +4 * ....X +4 * @...X +4 * */ char circle_data[] = { /* 0*/ 1, 1, /* 2*/ 2, 2, 1, /* 5*/ 3, 3, 2, 1, /* 9*/ 4, 4, 4, 3, 2, /* 14*/ 5, 5, 5, 4, 3, 2, /* 20*/ 6, 6, 6, 5, 5, 4, 2, /* 27*/ 7, 7, 7, 6, 6, 5, 4, 2, /* 35*/ 8, 8, 8, 7, 7, 6, 6, 4, 2, /* 44*/ 9, 9, 9, 9, 8, 8, 7, 6, 5, 3, /* 54*/ 10, 10, 10, 10, 9, 9, 8, 7, 6, 5, 3, /* 65*/ 11, 11, 11, 11, 10, 10, 9, 9, 8, 7, 5, 3, /* 77*/ 12, 12, 12, 12, 11, 11, 10, 10, 9, 8, 7, 5, 3, /* 90*/ 13, 13, 13, 13, 12, 12, 12, 11, 10, 10, 9, 7, 6, 3, /*104*/ 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 10, 9, 8, 6, 3, /*119*/ 15, 15, 15, 15, 14, 14, 14, 13, 13, 12, 11, 10, 9, 8, 6, 3, /*135*/ 16 /* MAX_RADIUS+1; used to terminate range loops -dlc */ }; /* * These are the starting indexes into the circle_data[] array for a * circle of a given radius. */ char circle_start[] = { /* */ 0, /* circles of radius zero are not used */ /* 1*/ 0, /* 2*/ 2, /* 3*/ 5, /* 4*/ 9, /* 5*/ 14, /* 6*/ 20, /* 7*/ 27, /* 8*/ 35, /* 9*/ 44, /*10*/ 54, /*11*/ 65, /*12*/ 77, /*13*/ 90, /*14*/ 104, /*15*/ 119, }; /*==========================================================================*/ /* Vision (arbitrary line of sight) * =========================================*/ /*------ global variables ------*/ #if 0 /* (moved to decl.c) */ /* True if we need to run a full vision recalculation. */ boolean vision_full_recalc = 0; /* Pointers to the current vision array. */ char **viz_array; #endif char *viz_rmin, *viz_rmax; /* current vision cs bounds */ /*------ local variables ------*/ static char could_see[2][ROWNO][COLNO]; /* vision work space */ static char *cs_rows0[ROWNO], *cs_rows1[ROWNO]; static char cs_rmin0[ROWNO], cs_rmax0[ROWNO]; static char cs_rmin1[ROWNO], cs_rmax1[ROWNO]; static char viz_clear[ROWNO][COLNO]; /* vision clear/blocked map */ static char *viz_clear_rows[ROWNO]; static char left_ptrs[ROWNO][COLNO]; /* LOS algorithm helpers */ static char right_ptrs[ROWNO][COLNO]; /* Forward declarations. */ STATIC_DCL void FDECL(fill_point, (int, int)); STATIC_DCL void FDECL(dig_point, (int, int)); STATIC_DCL void NDECL(view_init); STATIC_DCL void FDECL(view_from, (int, int, char **, char *, char *, int, void (*)(int, int, genericptr_t), genericptr_t)); STATIC_DCL void FDECL(get_unused_cs, (char ***, char **, char **)); STATIC_DCL void FDECL(rogue_vision, (char **, char *, char *)); /* Macro definitions that I can't find anywhere. */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #define v_abs(z) ((z) < 0 ? -(z) : (z)) /* don't use abs -- it may exist */ /* * vision_init() * * The one-time vision initialization routine. * * This must be called before mklev() is called in newgame() [allmain.c], * or before a game restore. Else we die a horrible death. */ void vision_init() { int i; /* Set up the pointers. */ for (i = 0; i < ROWNO; i++) { cs_rows0[i] = could_see[0][i]; cs_rows1[i] = could_see[1][i]; viz_clear_rows[i] = viz_clear[i]; } /* Start out with cs0 as our current array */ viz_array = cs_rows0; viz_rmin = cs_rmin0; viz_rmax = cs_rmax0; vision_full_recalc = 0; (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); /* Initialize the vision algorithm (currently C or D). */ view_init(); #ifdef VISION_TABLES /* Note: this initializer doesn't do anything except guarantee that * we're linked properly. */ vis_tab_init(); #endif } /* * does_block() * * Returns true if the level feature, object, or monster at (x,y) blocks * sight. */ int does_block(x, y, lev) int x, y; register struct rm *lev; { struct obj *obj; struct monst *mon; /* Features that block . . */ if (IS_ROCK(lev->typ) || lev->typ == TREE || (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED | D_LOCKED | D_TRAPPED)))) return 1; if (lev->typ == CLOUD || lev->typ == WATER || (lev->typ == MOAT && Underwater)) return 1; /* Boulders block light. */ for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if (obj->otyp == BOULDER) return 1; /* Mimics mimicing a door or boulder block light. */ if ((mon = m_at(x, y)) && (!mon->minvis || See_invisible) && (is_door_mappear(mon) || is_obj_mappear(mon,BOULDER))) return 1; return 0; } /* * vision_reset() * * This must be called *after* the levl[][] structure is set with the new * level and the level monsters and objects are in place. */ void vision_reset() { int y; register int x, i, dig_left, block; register struct rm *lev; /* Start out with cs0 as our current array */ viz_array = cs_rows0; viz_rmin = cs_rmin0; viz_rmax = cs_rmax0; (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); /* Reset the pointers and clear so that we have a "full" dungeon. */ (void) memset((genericptr_t) viz_clear, 0, sizeof(viz_clear)); /* Dig the level */ for (y = 0; y < ROWNO; y++) { dig_left = 0; block = TRUE; /* location (0,y) is always stone; it's !isok() */ lev = &levl[1][y]; for (x = 1; x < COLNO; x++, lev += ROWNO) if (block != (IS_ROCK(lev->typ) || does_block(x, y, lev))) { if (block) { for (i = dig_left; i < x; i++) { left_ptrs[y][i] = dig_left; right_ptrs[y][i] = x - 1; } } else { i = dig_left; if (dig_left) dig_left--; /* point at first blocked point */ for (; i < x; i++) { left_ptrs[y][i] = dig_left; right_ptrs[y][i] = x; viz_clear[y][i] = 1; } } dig_left = x; block = !block; } /* handle right boundary; almost identical for blocked/unblocked */ i = dig_left; if (!block && dig_left) dig_left--; /* point at first blocked point */ for (; i < COLNO; i++) { left_ptrs[y][i] = dig_left; right_ptrs[y][i] = (COLNO - 1); viz_clear[y][i] = !block; } } iflags.vision_inited = 1; /* vision is ready */ vision_full_recalc = 1; /* we want to run vision_recalc() */ } /* * get_unused_cs() * * Called from vision_recalc() and at least one light routine. Get pointers * to the unused vision work area. */ STATIC_OVL void get_unused_cs(rows, rmin, rmax) char ***rows; char **rmin, **rmax; { register int row; register char *nrmin, *nrmax; if (viz_array == cs_rows0) { *rows = cs_rows1; *rmin = cs_rmin1; *rmax = cs_rmax1; } else { *rows = cs_rows0; *rmin = cs_rmin0; *rmax = cs_rmax0; } /* return an initialized, unused work area */ nrmin = *rmin; nrmax = *rmax; (void) memset((genericptr_t) * *rows, 0, ROWNO * COLNO); /* we see nothing */ for (row = 0; row < ROWNO; row++) { /* set row min & max */ *nrmin++ = COLNO - 1; *nrmax++ = 0; } } /* * rogue_vision() * * Set the "could see" and in sight bits so vision acts just like the old * rogue game: * * + If in a room, the hero can see to the room boundaries. * + The hero can always see adjacent squares. * * We set the in_sight bit here as well to escape a bug that shows up * due to the one-sided lit wall hack. */ STATIC_OVL void rogue_vision(next, rmin, rmax) char **next; /* could_see array pointers */ char *rmin, *rmax; { int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */ int start, stop, in_door, xhi, xlo, yhi, ylo; register int zx, zy; /* If in a lit room, we are able to see to its boundaries. */ /* If dark, set COULD_SEE so various spells work -dlc */ if (rnum >= 0) { for (zy = rooms[rnum].ly - 1; zy <= rooms[rnum].hy + 1; zy++) { rmin[zy] = start = rooms[rnum].lx - 1; rmax[zy] = stop = rooms[rnum].hx + 1; for (zx = start; zx <= stop; zx++) { if (rooms[rnum].rlit) { next[zy][zx] = COULD_SEE | IN_SIGHT; levl[zx][zy].seenv = SVALL; /* see the walls */ } else next[zy][zx] = COULD_SEE; } } } in_door = levl[u.ux][u.uy].typ == DOOR; /* Can always see adjacent. */ ylo = max(u.uy - 1, 0); yhi = min(u.uy + 1, ROWNO - 1); xlo = max(u.ux - 1, 1); xhi = min(u.ux + 1, COLNO - 1); for (zy = ylo; zy <= yhi; zy++) { if (xlo < rmin[zy]) rmin[zy] = xlo; if (xhi > rmax[zy]) rmax[zy] = xhi; for (zx = xlo; zx <= xhi; zx++) { next[zy][zx] = COULD_SEE | IN_SIGHT; /* * Yuck, update adjacent non-diagonal positions when in a doorway. * We need to do this to catch the case when we first step into * a room. The room's walls were not seen from the outside, but * now are seen (the seen bits are set just above). However, the * positions are not updated because they were already in sight. * So, we have to do it here. */ if (in_door && (zx == u.ux || zy == u.uy)) newsym(zx, zy); } } } /*#define EXTEND_SPINE*/ /* possibly better looking wall-angle */ #ifdef EXTEND_SPINE STATIC_DCL int FDECL(new_angle, (struct rm *, unsigned char *, int, int)); /* * new_angle() * * Return the new angle seen by the hero for this location. The angle * bit is given in the value pointed at by sv. * * For T walls and crosswall, just setting the angle bit, even though * it is technically correct, doesn't look good. If we can see the * next position beyond the current one and it is a wall that we can * see, then we want to extend a spine of the T to connect with the wall * that is beyond. Example: * * Correct, but ugly Extend T spine * * | ... | ... * | ... <-- wall beyond & floor --> | ... * | ... | ... * Unseen --> ... | ... * spine +-... <-- trwall & doorway --> +-... * | ... | ... * * * @ <-- hero --> @ * * * We fake the above check by only checking if the horizontal & * vertical positions adjacent to the crosswall and T wall are * unblocked. Then, _in general_ we can see beyond. Generally, * this is good enough. * * + When this function is called we don't have all of the seen * information (we're doing a top down scan in vision_recalc). * We would need to scan once to set all IN_SIGHT and COULD_SEE * bits, then again to correctly set the seenv bits. * + I'm trying to make this as cheap as possible. The display & * vision eat up too much CPU time. * * * Note: Even as I write this, I'm still not convinced. There are too * many exceptions. I may have to bite the bullet and do more * checks. - Dean 2/11/93 */ STATIC_OVL int new_angle(lev, sv, row, col) struct rm *lev; unsigned char *sv; int row, col; { register int res = *sv; /* * Do extra checks for crosswalls and T walls if we see them from * an angle. */ if (lev->typ >= CROSSWALL && lev->typ <= TRWALL) { switch (res) { case SV0: if (col > 0 && viz_clear[row][col - 1]) res |= SV7; if (row > 0 && viz_clear[row - 1][col]) res |= SV1; break; case SV2: if (row > 0 && viz_clear[row - 1][col]) res |= SV1; if (col < COLNO - 1 && viz_clear[row][col + 1]) res |= SV3; break; case SV4: if (col < COLNO - 1 && viz_clear[row][col + 1]) res |= SV3; if (row < ROWNO - 1 && viz_clear[row + 1][col]) res |= SV5; break; case SV6: if (row < ROWNO - 1 && viz_clear[row + 1][col]) res |= SV5; if (col > 0 && viz_clear[row][col - 1]) res |= SV7; break; } } return res; } #else /* * new_angle() * * Return the new angle seen by the hero for this location. The angle * bit is given in the value pointed at by sv. * * The other parameters are not used. */ #define new_angle(lev, sv, row, col) (*sv) #endif /* * vision_recalc() * * Do all of the heavy vision work. Recalculate all locations that could * possibly be seen by the hero --- if the location were lit, etc. Note * which locations are actually seen because of lighting. Then add to * this all locations that be seen by hero due to night vision and x-ray * vision. Finally, compare with what the hero was able to see previously. * Update the difference. * * This function is usually called only when the variable 'vision_full_recalc' * is set. The following is a list of places where this function is called, * with three valid values for the control flag parameter: * * Control flag = 0. A complete vision recalculation. Generate the vision * tables from scratch. This is necessary to correctly set what the hero * can see. (1) and (2) call this routine for synchronization purposes, (3) * calls this routine so it can operate correctly. * * + After the monster move, before input from the player. [moveloop()] * + At end of moveloop. [moveloop() ??? not sure why this is here] * + Right before something is printed. [pline()] * + Right before we do a vision based operation. [do_clear_area()] * + screen redraw, so we can renew all positions in sight. [docrt()] * + When toggling temporary blindness, in case additional events * impacted by vision occur during the same move [make_blinded()] * * Control flag = 1. An adjacent vision recalculation. The hero has moved * one square. Knowing this, it might be possible to optimize the vision * recalculation using the current knowledge. This is presently unimplemented * and is treated as a control = 0 call. * * + Right after the hero moves. [domove()] * * Control flag = 2. Turn off the vision system. Nothing new will be * displayed, since nothing is seen. This is usually done when you need * a newsym() run on all locations in sight, or on some locations but you * don't know which ones. * * + Before a screen redraw, so all positions are renewed. [docrt()] * + Right before the hero arrives on a new level. [goto_level()] * + Right after a scroll of light is read. [litroom()] * + After an option has changed that affects vision [parseoptions()] * + Right after the hero is swallowed. [gulpmu()] * + Just before bubbles are moved. [movebubbles()] */ void vision_recalc(control) int control; { char **temp_array; /* points to the old vision array */ char **next_array; /* points to the new vision array */ char *next_row; /* row pointer for the new array */ char *old_row; /* row pointer for the old array */ char *next_rmin; /* min pointer for the new array */ char *next_rmax; /* max pointer for the new array */ char *ranges; /* circle ranges -- used for xray & night vision */ int row = 0; /* row counter (outer loop) */ int start, stop; /* inner loop starting/stopping index */ int dx, dy; /* one step from a lit door or lit wall (see below) */ register int col; /* inner loop counter */ register struct rm *lev; /* pointer to current pos */ struct rm *flev; /* pointer to position in "front" of current pos */ extern unsigned char seenv_matrix[3][3]; /* from display.c */ static unsigned char colbump[COLNO + 1]; /* cols to bump sv */ unsigned char *sv; /* ptr to seen angle bits */ int oldseenv; /* previous seenv value */ vision_full_recalc = 0; /* reset flag */ if (in_mklev || !iflags.vision_inited) return; /* * Either the light sources have been taken care of, or we must * recalculate them here. */ /* Get the unused could see, row min, and row max arrays. */ get_unused_cs(&next_array, &next_rmin, &next_rmax); /* You see nothing, nothing can see you --- if swallowed or refreshing. */ if (u.uswallow || control == 2) { /* do nothing -- get_unused_cs() nulls out the new work area */ ; } else if (Blind) { /* * Calculate the could_see array even when blind so that monsters * can see you, even if you can't see them. Note that the current * setup allows: * * + Monsters to see with the "new" vision, even on the rogue * level. * * + Monsters can see you even when you're in a pit. */ view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0, (void FDECL((*), (int, int, genericptr_t))) 0, (genericptr_t) 0); /* * Our own version of the update loop below. We know we can't see * anything, so we only need update positions we used to be able * to see. */ temp_array = viz_array; /* set viz_array so newsym() will work */ viz_array = next_array; for (row = 0; row < ROWNO; row++) { old_row = temp_array[row]; /* Find the min and max positions on the row. */ start = min(viz_rmin[row], next_rmin[row]); stop = max(viz_rmax[row], next_rmax[row]); for (col = start; col <= stop; col++) if (old_row[col] & IN_SIGHT) newsym(col, row); } /* skip the normal update loop */ goto skip; } else if (Is_rogue_level(&u.uz)) { rogue_vision(next_array, next_rmin, next_rmax); } else { int has_night_vision = 1; /* hero has night vision */ if (Underwater && !Is_waterlevel(&u.uz)) { /* * The hero is under water. Only see surrounding locations if * they are also underwater. This overrides night vision but * does not override x-ray vision. */ has_night_vision = 0; for (row = u.uy - 1; row <= u.uy + 1; row++) for (col = u.ux - 1; col <= u.ux + 1; col++) { if (!isok(col, row) || !is_pool(col, row)) continue; next_rmin[row] = min(next_rmin[row], col); next_rmax[row] = max(next_rmax[row], col); next_array[row][col] = IN_SIGHT | COULD_SEE; } /* if in a pit, just update for immediate locations */ } else if (u.utrap && u.utraptype == TT_PIT) { for (row = u.uy - 1; row <= u.uy + 1; row++) { if (row < 0) continue; if (row >= ROWNO) break; next_rmin[row] = max(0, u.ux - 1); next_rmax[row] = min(COLNO - 1, u.ux + 1); next_row = next_array[row]; for (col = next_rmin[row]; col <= next_rmax[row]; col++) next_row[col] = IN_SIGHT | COULD_SEE; } } else view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0, (void FDECL((*), (int, int, genericptr_t))) 0, (genericptr_t) 0); /* * Set the IN_SIGHT bit for xray and night vision. */ if (u.xray_range >= 0) { if (u.xray_range) { ranges = circle_ptr(u.xray_range); for (row = u.uy - u.xray_range; row <= u.uy + u.xray_range; row++) { if (row < 0) continue; if (row >= ROWNO) break; dy = v_abs(u.uy - row); next_row = next_array[row]; start = max(0, u.ux - ranges[dy]); stop = min(COLNO - 1, u.ux + ranges[dy]); for (col = start; col <= stop; col++) { char old_row_val = next_row[col]; next_row[col] |= IN_SIGHT; oldseenv = levl[col][row].seenv; levl[col][row].seenv = SVALL; /* see all! */ /* Update if previously not in sight or new angle. */ if (!(old_row_val & IN_SIGHT) || oldseenv != SVALL) newsym(col, row); } next_rmin[row] = min(start, next_rmin[row]); next_rmax[row] = max(stop, next_rmax[row]); } } else { /* range is 0 */ next_array[u.uy][u.ux] |= IN_SIGHT; levl[u.ux][u.uy].seenv = SVALL; next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]); next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]); } } if (has_night_vision && u.xray_range < u.nv_range) { if (!u.nv_range) { /* range is 0 */ next_array[u.uy][u.ux] |= IN_SIGHT; levl[u.ux][u.uy].seenv = SVALL; next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]); next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]); } else if (u.nv_range > 0) { ranges = circle_ptr(u.nv_range); for (row = u.uy - u.nv_range; row <= u.uy + u.nv_range; row++) { if (row < 0) continue; if (row >= ROWNO) break; dy = v_abs(u.uy - row); next_row = next_array[row]; start = max(0, u.ux - ranges[dy]); stop = min(COLNO - 1, u.ux + ranges[dy]); for (col = start; col <= stop; col++) if (next_row[col]) next_row[col] |= IN_SIGHT; next_rmin[row] = min(start, next_rmin[row]); next_rmax[row] = max(stop, next_rmax[row]); } } } } /* Set the correct bits for all light sources. */ do_light_sources(next_array); /* * Make the viz_array the new array so that cansee() will work correctly. */ temp_array = viz_array; viz_array = next_array; /* * The main update loop. Here we do two things: * * + Set the IN_SIGHT bit for places that we could see and are lit. * + Reset changed places. * * There is one thing that make deciding what the hero can see * difficult: * * 1. Directional lighting. Items that block light create problems. * The worst offenders are doors. Suppose a door to a lit room * is closed. It is lit on one side, but not on the other. How * do you know? You have to check the closest adjacent position. * Even so, that is not entirely correct. But it seems close * enough for now. */ colbump[u.ux] = colbump[u.ux + 1] = 1; for (row = 0; row < ROWNO; row++) { dy = u.uy - row; dy = sign(dy); next_row = next_array[row]; old_row = temp_array[row]; /* Find the min and max positions on the row. */ start = min(viz_rmin[row], next_rmin[row]); stop = max(viz_rmax[row], next_rmax[row]); lev = &levl[start][row]; sv = &seenv_matrix[dy + 1][start < u.ux ? 0 : (start > u.ux ? 2 : 1)]; for (col = start; col <= stop; lev += ROWNO, sv += (int) colbump[++col]) { if (next_row[col] & IN_SIGHT) { /* * We see this position because of night- or xray-vision. */ oldseenv = lev->seenv; lev->seenv |= new_angle(lev, sv, row, col); /* update seen angle */ /* Update pos if previously not in sight or new angle. */ if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) newsym(col, row); } else if ((next_row[col] & COULD_SEE) && (lev->lit || (next_row[col] & TEMP_LIT))) { /* * We see this position because it is lit. */ if ((IS_DOOR(lev->typ) || lev->typ == SDOOR || IS_WALL(lev->typ)) && !viz_clear[row][col]) { /* * Make sure doors, walls, boulders or mimics don't show * up * at the end of dark hallways. We do this by checking * the adjacent position. If it is lit, then we can see * the door or wall, otherwise we can't. */ dx = u.ux - col; dx = sign(dx); flev = &(levl[col + dx][row + dy]); if (flev->lit || next_array[row + dy][col + dx] & TEMP_LIT) { next_row[col] |= IN_SIGHT; /* we see it */ oldseenv = lev->seenv; lev->seenv |= new_angle(lev, sv, row, col); /* Update pos if previously not in sight or new * angle.*/ if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) newsym(col, row); } else goto not_in_sight; /* we don't see it */ } else { next_row[col] |= IN_SIGHT; /* we see it */ oldseenv = lev->seenv; lev->seenv |= new_angle(lev, sv, row, col); /* Update pos if previously not in sight or new angle. */ if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) newsym(col, row); } } else if ((next_row[col] & COULD_SEE) && lev->waslit) { /* * If we make it here, the hero _could see_ the location, * but doesn't see it (location is not lit). * However, the hero _remembers_ it as lit (waslit is true). * The hero can now see that it is not lit, so change waslit * and update the location. */ lev->waslit = 0; /* remember lit condition */ newsym(col, row); /* * At this point we know that the row position is *not* in normal * sight. That is, the position is could be seen, but is dark * or LOS is just plain blocked. * * Update the position if: * o If the old one *was* in sight. We may need to clean up * the glyph -- E.g. darken room spot, etc. * o If we now could see the location (yet the location is not * lit), but previously we couldn't see the location, or vice * versa. Update the spot because there there may be an * infrared monster there. */ } else { not_in_sight: if ((old_row[col] & IN_SIGHT) || ((next_row[col] & COULD_SEE) ^ (old_row[col] & COULD_SEE))) newsym(col, row); } } /* end for col . . */ } /* end for row . . */ colbump[u.ux] = colbump[u.ux + 1] = 0; skip: /* This newsym() caused a crash delivering msg about failure to open * dungeon file init_dungeons() -> panic() -> done(11) -> * vision_recalc(2) -> newsym() -> crash! u.ux and u.uy are 0 and * program_state.panicking == 1 under those circumstances */ if (!program_state.panicking) newsym(u.ux, u.uy); /* Make sure the hero shows up! */ /* Set the new min and max pointers. */ viz_rmin = next_rmin; viz_rmax = next_rmax; recalc_mapseen(); } /* * block_point() * * Make the location opaque to light. */ void block_point(x, y) int x, y; { fill_point(y, x); /* recalc light sources here? */ /* * We have to do a full vision recalculation if we "could see" the * location. Why? Suppose some monster opened a way so that the * hero could see a lit room. However, the position of the opening * was out of night-vision range of the hero. Suddenly the hero should * see the lit room. */ if (viz_array[y][x]) vision_full_recalc = 1; } /* * unblock_point() * * Make the location transparent to light. */ void unblock_point(x, y) int x, y; { dig_point(y, x); /* recalc light sources here? */ if (viz_array[y][x]) vision_full_recalc = 1; } /*==========================================================================*\ | | | Everything below this line uses (y,x) instead of (x,y) --- the | | algorithms are faster if they are less recursive and can scan | | on a row longer. | | | \*==========================================================================*/ /* ======================================================================= *\ Left and Right Pointer Updates \* ======================================================================= */ /* * LEFT and RIGHT pointer rules * * * **NOTE** The rules changed on 4/4/90. This comment reflects the * new rules. The change was so that the stone-wall optimization * would work. * * OK, now the tough stuff. We must maintain our left and right * row pointers. The rules are as follows: * * Left Pointers: * ______________ * * + If you are a clear spot, your left will point to the first * stone to your left. If there is none, then point the first * legal position in the row (0). * * + If you are a blocked spot, then your left will point to the * left-most blocked spot to your left that is connected to you. * This means that a left-edge (a blocked spot that has an open * spot on its left) will point to itself. * * * Right Pointers: * --------------- * + If you are a clear spot, your right will point to the first * stone to your right. If there is none, then point the last * legal position in the row (COLNO-1). * * + If you are a blocked spot, then your right will point to the * right-most blocked spot to your right that is connected to you. * This means that a right-edge (a blocked spot that has an open * spot on its right) will point to itself. */ STATIC_OVL void dig_point(row, col) int row, col; { int i; if (viz_clear[row][col]) return; /* already done */ viz_clear[row][col] = 1; /* * Boundary cases first. */ if (col == 0) { /* left edge */ if (viz_clear[row][1]) { right_ptrs[row][0] = right_ptrs[row][1]; } else { right_ptrs[row][0] = 1; for (i = 1; i <= right_ptrs[row][1]; i++) left_ptrs[row][i] = 1; } } else if (col == (COLNO - 1)) { /* right edge */ if (viz_clear[row][COLNO - 2]) { left_ptrs[row][COLNO - 1] = left_ptrs[row][COLNO - 2]; } else { left_ptrs[row][COLNO - 1] = COLNO - 2; for (i = left_ptrs[row][COLNO - 2]; i < COLNO - 1; i++) right_ptrs[row][i] = COLNO - 2; } /* * At this point, we know we aren't on the boundaries. */ } else if (viz_clear[row][col - 1] && viz_clear[row][col + 1]) { /* Both sides clear */ for (i = left_ptrs[row][col - 1]; i <= col; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ right_ptrs[row][i] = right_ptrs[row][col + 1]; } for (i = col; i <= right_ptrs[row][col + 1]; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ left_ptrs[row][i] = left_ptrs[row][col - 1]; } } else if (viz_clear[row][col - 1]) { /* Left side clear, right side blocked. */ for (i = col + 1; i <= right_ptrs[row][col + 1]; i++) left_ptrs[row][i] = col + 1; for (i = left_ptrs[row][col - 1]; i <= col; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ right_ptrs[row][i] = col + 1; } left_ptrs[row][col] = left_ptrs[row][col - 1]; } else if (viz_clear[row][col + 1]) { /* Right side clear, left side blocked. */ for (i = left_ptrs[row][col - 1]; i < col; i++) right_ptrs[row][i] = col - 1; for (i = col; i <= right_ptrs[row][col + 1]; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ left_ptrs[row][i] = col - 1; } right_ptrs[row][col] = right_ptrs[row][col + 1]; } else { /* Both sides blocked */ for (i = left_ptrs[row][col - 1]; i < col; i++) right_ptrs[row][i] = col - 1; for (i = col + 1; i <= right_ptrs[row][col + 1]; i++) left_ptrs[row][i] = col + 1; left_ptrs[row][col] = col - 1; right_ptrs[row][col] = col + 1; } } STATIC_OVL void fill_point(row, col) int row, col; { int i; if (!viz_clear[row][col]) return; viz_clear[row][col] = 0; if (col == 0) { if (viz_clear[row][1]) { /* adjacent is clear */ right_ptrs[row][0] = 0; } else { right_ptrs[row][0] = right_ptrs[row][1]; for (i = 1; i <= right_ptrs[row][1]; i++) left_ptrs[row][i] = 0; } } else if (col == COLNO - 1) { if (viz_clear[row][COLNO - 2]) { /* adjacent is clear */ left_ptrs[row][COLNO - 1] = COLNO - 1; } else { left_ptrs[row][COLNO - 1] = left_ptrs[row][COLNO - 2]; for (i = left_ptrs[row][COLNO - 2]; i < COLNO - 1; i++) right_ptrs[row][i] = COLNO - 1; } /* * Else we know that we are not on an edge. */ } else if (viz_clear[row][col - 1] && viz_clear[row][col + 1]) { /* Both sides clear */ for (i = left_ptrs[row][col - 1] + 1; i <= col; i++) right_ptrs[row][i] = col; if (!left_ptrs[row][col - 1]) /* catch the end case */ right_ptrs[row][0] = col; for (i = col; i < right_ptrs[row][col + 1]; i++) left_ptrs[row][i] = col; if (right_ptrs[row][col + 1] == COLNO - 1) /* catch the end case */ left_ptrs[row][COLNO - 1] = col; } else if (viz_clear[row][col - 1]) { /* Left side clear, right side blocked. */ for (i = col; i <= right_ptrs[row][col + 1]; i++) left_ptrs[row][i] = col; for (i = left_ptrs[row][col - 1] + 1; i < col; i++) right_ptrs[row][i] = col; if (!left_ptrs[row][col - 1]) /* catch the end case */ right_ptrs[row][i] = col; right_ptrs[row][col] = right_ptrs[row][col + 1]; } else if (viz_clear[row][col + 1]) { /* Right side clear, left side blocked. */ for (i = left_ptrs[row][col - 1]; i <= col; i++) right_ptrs[row][i] = col; for (i = col + 1; i < right_ptrs[row][col + 1]; i++) left_ptrs[row][i] = col; if (right_ptrs[row][col + 1] == COLNO - 1) /* catch the end case */ left_ptrs[row][i] = col; left_ptrs[row][col] = left_ptrs[row][col - 1]; } else { /* Both sides blocked */ for (i = left_ptrs[row][col - 1]; i <= col; i++) right_ptrs[row][i] = right_ptrs[row][col + 1]; for (i = col; i <= right_ptrs[row][col + 1]; i++) left_ptrs[row][i] = left_ptrs[row][col - 1]; } } /*==========================================================================*/ /*==========================================================================*/ /* Use either algorithm C or D. See the config.h for more details. * =========*/ /* * Variables local to both Algorithms C and D. */ static int start_row; static int start_col; static int step; static char **cs_rows; static char *cs_left; static char *cs_right; static void FDECL((*vis_func), (int, int, genericptr_t)); static genericptr_t varg; /* * Both Algorithms C and D use the following macros. * * good_row(z) - Return TRUE if the argument is a legal row. * set_cs(rowp,col) - Set the local could see array. * set_min(z) - Save the min value of the argument and the current * row minimum. * set_max(z) - Save the max value of the argument and the current * row maximum. * * The last three macros depend on having local pointers row_min, row_max, * and rowp being set correctly. */ #define set_cs(rowp, col) (rowp[col] = COULD_SEE) #define good_row(z) ((z) >= 0 && (z) < ROWNO) #define set_min(z) \ if (*row_min > (z)) \ *row_min = (z) #define set_max(z) \ if (*row_max < (z)) \ *row_max = (z) #define is_clear(row, col) viz_clear_rows[row][col] /* * clear_path() expanded into 4 macros/functions: * * q1_path() * q2_path() * q3_path() * q4_path() * * "Draw" a line from the start to the given location. Stop if we hit * something that blocks light. The start and finish points themselves are * not checked, just the points between them. These routines do _not_ * expect to be called with the same starting and stopping point. * * These routines use the generalized integer Bresenham's algorithm (fast * line drawing) for all quadrants. The algorithm was taken from _Procedural * Elements for Computer Graphics_, by David F. Rogers. McGraw-Hill, 1985. */ #ifdef MACRO_CPATH /* quadrant calls are macros */ /* * When called, the result is in "result". * The first two arguments (srow,scol) are one end of the path. The next * two arguments (row,col) are the destination. The last argument is * used as a C language label. This means that it must be different * in each pair of calls. */ /* * Quadrant I (step < 0). */ #define q1_path(srow, scol, y2, x2, label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); \ y = (srow); \ dx = (x2) -x; \ dy = y - (y2); \ \ result = 0; /* default to a blocked path */ \ \ dxs = dx << 1; /* save the shifted values */ \ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy - 1; k; k--) { \ if (err >= 0) { \ x++; \ err -= dys; \ } \ y--; \ err += dxs; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ } else { \ err = dys - dx; \ \ for (k = dx - 1; k; k--) { \ if (err >= 0) { \ y--; \ err -= dxs; \ } \ x++; \ err += dys; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ } \ \ result = 1; \ } /* * Quadrant IV (step > 0). */ #define q4_path(srow, scol, y2, x2, label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); \ y = (srow); \ dx = (x2) -x; \ dy = (y2) -y; \ \ result = 0; /* default to a blocked path */ \ \ dxs = dx << 1; /* save the shifted values */ \ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy - 1; k; k--) { \ if (err >= 0) { \ x++; \ err -= dys; \ } \ y++; \ err += dxs; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ \ } else { \ err = dys - dx; \ \ for (k = dx - 1; k; k--) { \ if (err >= 0) { \ y++; \ err -= dxs; \ } \ x++; \ err += dys; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ } \ \ result = 1; \ } /* * Quadrant II (step < 0). */ #define q2_path(srow, scol, y2, x2, label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); \ y = (srow); \ dx = x - (x2); \ dy = y - (y2); \ \ result = 0; /* default to a blocked path */ \ \ dxs = dx << 1; /* save the shifted values */ \ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy - 1; k; k--) { \ if (err >= 0) { \ x--; \ err -= dys; \ } \ y--; \ err += dxs; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ } else { \ err = dys - dx; \ \ for (k = dx - 1; k; k--) { \ if (err >= 0) { \ y--; \ err -= dxs; \ } \ x--; \ err += dys; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ } \ \ result = 1; \ } /* * Quadrant III (step > 0). */ #define q3_path(srow, scol, y2, x2, label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); \ y = (srow); \ dx = x - (x2); \ dy = (y2) -y; \ \ result = 0; /* default to a blocked path */ \ \ dxs = dx << 1; /* save the shifted values */ \ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy - 1; k; k--) { \ if (err >= 0) { \ x--; \ err -= dys; \ } \ y++; \ err += dxs; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ \ } else { \ err = dys - dx; \ \ for (k = dx - 1; k; k--) { \ if (err >= 0) { \ y++; \ err -= dxs; \ } \ x--; \ err += dys; \ if (!is_clear(y, x)) \ goto label; /* blocked */ \ } \ } \ \ result = 1; \ } #else /* !MACRO_CPATH -- quadrants are really functions */ STATIC_DCL int FDECL(_q1_path, (int, int, int, int)); STATIC_DCL int FDECL(_q2_path, (int, int, int, int)); STATIC_DCL int FDECL(_q3_path, (int, int, int, int)); STATIC_DCL int FDECL(_q4_path, (int, int, int, int)); #define q1_path(sy, sx, y, x, dummy) result = _q1_path(sy, sx, y, x) #define q2_path(sy, sx, y, x, dummy) result = _q2_path(sy, sx, y, x) #define q3_path(sy, sx, y, x, dummy) result = _q3_path(sy, sx, y, x) #define q4_path(sy, sx, y, x, dummy) result = _q4_path(sy, sx, y, x) /* * Quadrant I (step < 0). */ STATIC_OVL int _q1_path(srow, scol, y2, x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x2 - x; dy = y - y2; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy - 1; k; k--) { if (err >= 0) { x++; err -= dys; } y--; err += dxs; if (!is_clear(y, x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx - 1; k; k--) { if (err >= 0) { y--; err -= dxs; } x++; err += dys; if (!is_clear(y, x)) return 0; /* blocked */ } } return 1; } /* * Quadrant IV (step > 0). */ STATIC_OVL int _q4_path(srow, scol, y2, x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x2 - x; dy = y2 - y; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy - 1; k; k--) { if (err >= 0) { x++; err -= dys; } y++; err += dxs; if (!is_clear(y, x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx - 1; k; k--) { if (err >= 0) { y++; err -= dxs; } x++; err += dys; if (!is_clear(y, x)) return 0; /* blocked */ } } return 1; } /* * Quadrant II (step < 0). */ STATIC_OVL int _q2_path(srow, scol, y2, x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x - x2; dy = y - y2; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy - 1; k; k--) { if (err >= 0) { x--; err -= dys; } y--; err += dxs; if (!is_clear(y, x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx - 1; k; k--) { if (err >= 0) { y--; err -= dxs; } x--; err += dys; if (!is_clear(y, x)) return 0; /* blocked */ } } return 1; } /* * Quadrant III (step > 0). */ STATIC_OVL int _q3_path(srow, scol, y2, x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x - x2; dy = y2 - y; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy - 1; k; k--) { if (err >= 0) { x--; err -= dys; } y++; err += dxs; if (!is_clear(y, x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx - 1; k; k--) { if (err >= 0) { y++; err -= dxs; } x--; err += dys; if (!is_clear(y, x)) return 0; /* blocked */ } } return 1; } #endif /* ?MACRO_CPATH */ /* * Use vision tables to determine if there is a clear path from * (col1,row1) to (col2,row2). This is used by: * m_cansee() * m_canseeu() * do_light_sources() */ boolean clear_path(col1, row1, col2, row2) int col1, row1, col2, row2; { int result; if (col1 < col2) { if (row1 > row2) { q1_path(row1, col1, row2, col2, cleardone); } else { q4_path(row1, col1, row2, col2, cleardone); } } else { if (row1 > row2) { q2_path(row1, col1, row2, col2, cleardone); } else if (row1 == row2 && col1 == col2) { result = 1; } else { q3_path(row1, col1, row2, col2, cleardone); } } #ifdef MACRO_CPATH cleardone: #endif return (boolean) result; } #ifdef VISION_TABLES /*==========================================================================*\ GENERAL LINE OF SIGHT Algorithm D \*==========================================================================*/ /* * Indicate caller for the shadow routines. */ #define FROM_RIGHT 0 #define FROM_LEFT 1 /* * Include the table definitions. */ #include "vis_tab.h" /* 3D table pointers. */ static close2d *close_dy[CLOSE_MAX_BC_DY]; static far2d *far_dy[FAR_MAX_BC_DY]; STATIC_DCL void FDECL(right_side, (int, int, int, int, int, int, int, char *)); STATIC_DCL void FDECL(left_side, (int, int, int, int, int, int, int, char *)); STATIC_DCL int FDECL(close_shadow, (int, int, int, int)); STATIC_DCL int FDECL(far_shadow, (int, int, int, int)); /* * Initialize algorithm D's table pointers. If we don't have these, * then we do 3D table lookups. Verrrry slow. */ STATIC_OVL void view_init() { int i; for (i = 0; i < CLOSE_MAX_BC_DY; i++) close_dy[i] = &close_table[i]; for (i = 0; i < FAR_MAX_BC_DY; i++) far_dy[i] = &far_table[i]; } /* * If the far table has an entry of OFF_TABLE, then the far block prevents * us from seeing the location just above/below it. I.e. the first visible * location is one *before* the block. */ #define OFF_TABLE 0xff STATIC_OVL int close_shadow(side, this_row, block_row, block_col) int side, this_row, block_row, block_col; { register int sdy, sdx, pdy, offset; /* * If on the same column (block_row = -1), then we can see it. */ if (block_row < 0) return block_col; /* Take explicit absolute values. Adjust. */ if ((sdy = (start_row - block_row)) < 0) sdy = -sdy; --sdy; /* src dy */ if ((sdx = (start_col - block_col)) < 0) sdx = -sdx; /* src dx */ if ((pdy = (block_row - this_row)) < 0) pdy = -pdy; /* point dy */ if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX || pdy >= CLOSE_MAX_BC_DY) { impossible("close_shadow: bad value"); return block_col; } offset = close_dy[sdy]->close[sdx][pdy]; if (side == FROM_RIGHT) return block_col + offset; return block_col - offset; } STATIC_OVL int far_shadow(side, this_row, block_row, block_col) int side, this_row, block_row, block_col; { register int sdy, sdx, pdy, offset; /* * Take care of a bug that shows up only on the borders. * * If the block is beyond the border, then the row is negative. Return * the block's column number (should be 0 or COLNO-1). * * Could easily have the column be -1, but then wouldn't know if it was * the left or right border. */ if (block_row < 0) return block_col; /* Take explicit absolute values. Adjust. */ if ((sdy = (start_row - block_row)) < 0) sdy = -sdy; /* src dy */ if ((sdx = (start_col - block_col)) < 0) sdx = -sdx; --sdx; /* src dx */ if ((pdy = (block_row - this_row)) < 0) pdy = -pdy; --pdy; /* point dy */ if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX || pdy < 0 || pdy >= FAR_MAX_BC_DY) { impossible("far_shadow: bad value"); return block_col; } if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1; if (side == FROM_RIGHT) return block_col + offset; return block_col - offset; } /* * right_side() * * Figure out what could be seen on the right side of the source. */ STATIC_OVL void right_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits) int row; /* current row */ int cb_row, cb_col; /* close block row and col */ int fb_row, fb_col; /* far block row and col */ int left; /* left mark of the previous row */ int right_mark; /* right mark of previous row */ char *limits; /* points at range limit for current row, or NULL */ { register int i; register char *rowp = NULL; int hit_stone = 0; int left_shadow, right_shadow, loc_right; int lblock_col; /* local block column (current row) */ int nrow, deeper; char *row_min = NULL; /* left most */ char *row_max = NULL; /* right most */ int lim_max; /* right most limit of circle */ nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1))); if (!vis_func) { rowp = cs_rows[row]; row_min = &cs_left[row]; row_max = &cs_right[row]; } if (limits) { lim_max = start_col + *limits; if (lim_max > COLNO - 1) lim_max = COLNO - 1; if (right_mark > lim_max) right_mark = lim_max; limits++; /* prepare for next row */ } else lim_max = COLNO - 1; /* * Get the left shadow from the close block. This value could be * illegal. */ left_shadow = close_shadow(FROM_RIGHT, row, cb_row, cb_col); /* * Mark all stone walls as seen before the left shadow. All this work * for a special case. * * NOTE. With the addition of this code in here, it is now *required* * for the algorithm to work correctly. If this is commented out, * change the above assignment so that left and not left_shadow is the * variable that gets the shadow. */ while (left <= right_mark) { loc_right = right_ptrs[row][left]; if (loc_right > lim_max) loc_right = lim_max; if (viz_clear_rows[row][left]) { if (loc_right >= left_shadow) { left = left_shadow; /* opening ends beyond shadow */ break; } left = loc_right; loc_right = right_ptrs[row][left]; if (loc_right > lim_max) loc_right = lim_max; if (left == loc_right) return; /* boundary */ /* Shadow covers opening, beyond right mark */ if (left == right_mark && left_shadow > right_mark) return; } if (loc_right > right_mark) /* can't see stone beyond the mark */ loc_right = right_mark; if (vis_func) { for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= loc_right; i++) set_cs(rowp, i); set_min(left); set_max(loc_right); } if (loc_right == right_mark) return; /* all stone */ if (loc_right >= left_shadow) hit_stone = 1; left = loc_right + 1; } /* * At this point we are at the first visible clear spot on or beyond * the left shadow, unless the left shadow is an illegal value. If we * have "hit stone" then we have a stone wall just to our left. */ /* * Get the right shadow. Make sure that it is a legal value. */ if ((right_shadow = far_shadow(FROM_RIGHT, row, fb_row, fb_col)) >= COLNO) right_shadow = COLNO - 1; /* * Make vertical walls work the way we want them. In this case, we * note when the close block blocks the column just above/beneath * it (right_shadow < fb_col [actually right_shadow == fb_col-1]). If * the location is filled, then we want to see it, so we put the * right shadow back (same as fb_col). */ if (right_shadow < fb_col && !viz_clear_rows[row][fb_col]) right_shadow = fb_col; if (right_shadow > lim_max) right_shadow = lim_max; /* * Main loop. Within the range of sight of the previous row, mark all * stone walls as seen. Follow open areas recursively. */ while (left <= right_mark) { /* Get the far right of the opening or wall */ loc_right = right_ptrs[row][left]; if (loc_right > lim_max) loc_right = lim_max; if (!viz_clear_rows[row][left]) { hit_stone = 1; /* use stone on this row as close block */ /* * We can see all of the wall until the next open spot or the * start of the shadow caused by the far block (right). * * Can't see stone beyond the right mark. */ if (loc_right > right_mark) loc_right = right_mark; if (vis_func) { for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= loc_right; i++) set_cs(rowp, i); set_min(left); set_max(loc_right); } if (loc_right == right_mark) return; /* hit the end */ left = loc_right + 1; loc_right = right_ptrs[row][left]; if (loc_right > lim_max) loc_right = lim_max; /* fall through... we know at least one position is visible */ } /* * We are in an opening. * * If this is the first open spot since the could see area (this is * true if we have hit stone), get the shadow generated by the wall * just to our left. */ if (hit_stone) { lblock_col = left - 1; /* local block column */ left = close_shadow(FROM_RIGHT, row, row, lblock_col); if (left > lim_max) break; /* off the end */ } /* * Check if the shadow covers the opening. If it does, then * move to end of the opening. A shadow generated on from a * wall on this row does *not* cover the wall on the right * of the opening. */ if (left >= loc_right) { if (loc_right == lim_max) { /* boundary */ if (left == lim_max) { if (vis_func) (*vis_func)(lim_max, row, varg); else { set_cs(rowp, lim_max); /* last pos */ set_max(lim_max); } } return; /* done */ } left = loc_right; continue; } /* * If the far wall of the opening (loc_right) is closer than the * shadow limit imposed by the far block (right) then use the far * wall as our new far block when we recurse. * * If the limits are the the same, and the far block really exists * (fb_row >= 0) then do the same as above. * * Normally, the check would be for the far wall being closer OR EQUAL * to the shadow limit. However, there is a bug that arises from the * fact that the clear area pointers end in an open space (if it * exists) on a boundary. This then makes a far block exist where it * shouldn't --- on a boundary. To get around that, I had to * introduce the concept of a non-existent far block (when the * row < 0). Next I have to check for it. Here is where that check * exists. */ if ((loc_right < right_shadow) || (fb_row >= 0 && loc_right == right_shadow)) { if (vis_func) { for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= loc_right; i++) set_cs(rowp, i); set_min(left); set_max(loc_right); } if (deeper) { if (hit_stone) right_side(nrow, row, lblock_col, row, loc_right, left, loc_right, limits); else right_side(nrow, cb_row, cb_col, row, loc_right, left, loc_right, limits); } /* * The following line, setting hit_stone, is needed for those * walls that are only 1 wide. If hit stone is *not* set and * the stone is only one wide, then the close block is the old * one instead one on the current row. A way around having to * set it here is to make left = loc_right (not loc_right+1) and * let the outer loop take care of it. However, if we do that * then we then have to check for boundary conditions here as * well. */ hit_stone = 1; left = loc_right + 1; /* * The opening extends beyond the right mark. This means that * the next far block is the current far block. */ } else { if (vis_func) { for (i = left; i <= right_shadow; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= right_shadow; i++) set_cs(rowp, i); set_min(left); set_max(right_shadow); } if (deeper) { if (hit_stone) right_side(nrow, row, lblock_col, fb_row, fb_col, left, right_shadow, limits); else right_side(nrow, cb_row, cb_col, fb_row, fb_col, left, right_shadow, limits); } return; /* we're outta here */ } } } /* * left_side() * * This routine is the mirror image of right_side(). Please see right_side() * for blow by blow comments. */ STATIC_OVL void left_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits) int row; /* the current row */ int cb_row, cb_col; /* close block row and col */ int fb_row, fb_col; /* far block row and col */ int left_mark; /* left mark of previous row */ int right; /* right mark of the previous row */ char *limits; { register int i; register char *rowp = NULL; int hit_stone = 0; int left_shadow, right_shadow, loc_left; int lblock_col; /* local block column (current row) */ int nrow, deeper; char *row_min = NULL; /* left most */ char *row_max = NULL; /* right most */ int lim_min; nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1))); if (!vis_func) { rowp = cs_rows[row]; row_min = &cs_left[row]; row_max = &cs_right[row]; } if (limits) { lim_min = start_col - *limits; if (lim_min < 0) lim_min = 0; if (left_mark < lim_min) left_mark = lim_min; limits++; /* prepare for next row */ } else lim_min = 0; /* This value could be illegal. */ right_shadow = close_shadow(FROM_LEFT, row, cb_row, cb_col); while (right >= left_mark) { loc_left = left_ptrs[row][right]; if (loc_left < lim_min) loc_left = lim_min; if (viz_clear_rows[row][right]) { if (loc_left <= right_shadow) { right = right_shadow; /* opening ends beyond shadow */ break; } right = loc_left; loc_left = left_ptrs[row][right]; if (loc_left < lim_min) loc_left = lim_min; if (right == loc_left) return; /* boundary */ } if (loc_left < left_mark) /* can't see beyond the left mark */ loc_left = left_mark; if (vis_func) { for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = loc_left; i <= right; i++) set_cs(rowp, i); set_min(loc_left); set_max(right); } if (loc_left == left_mark) return; /* all stone */ if (loc_left <= right_shadow) hit_stone = 1; right = loc_left - 1; } /* At first visible clear spot on or beyond the right shadow. */ if ((left_shadow = far_shadow(FROM_LEFT, row, fb_row, fb_col)) < 0) left_shadow = 0; /* Do vertical walls as we want. */ if (left_shadow > fb_col && !viz_clear_rows[row][fb_col]) left_shadow = fb_col; if (left_shadow < lim_min) left_shadow = lim_min; while (right >= left_mark) { loc_left = left_ptrs[row][right]; if (!viz_clear_rows[row][right]) { hit_stone = 1; /* use stone on this row as close block */ /* We can only see walls until the left mark */ if (loc_left < left_mark) loc_left = left_mark; if (vis_func) { for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = loc_left; i <= right; i++) set_cs(rowp, i); set_min(loc_left); set_max(right); } if (loc_left == left_mark) return; /* hit end */ right = loc_left - 1; loc_left = left_ptrs[row][right]; if (loc_left < lim_min) loc_left = lim_min; /* fall through...*/ } /* We are in an opening. */ if (hit_stone) { lblock_col = right + 1; /* stone block (local) */ right = close_shadow(FROM_LEFT, row, row, lblock_col); if (right < lim_min) return; /* off the end */ } /* Check if the shadow covers the opening. */ if (right <= loc_left) { /* Make a boundary condition work. */ if (loc_left == lim_min) { /* at boundary */ if (right == lim_min) { if (vis_func) (*vis_func)(lim_min, row, varg); else { set_cs(rowp, lim_min); /* caught the last pos */ set_min(lim_min); } } return; /* and break out the loop */ } right = loc_left; continue; } /* If the far wall of the opening is closer than the shadow limit. */ if ((loc_left > left_shadow) || (fb_row >= 0 && loc_left == left_shadow)) { if (vis_func) { for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = loc_left; i <= right; i++) set_cs(rowp, i); set_min(loc_left); set_max(right); } if (deeper) { if (hit_stone) left_side(nrow, row, lblock_col, row, loc_left, loc_left, right, limits); else left_side(nrow, cb_row, cb_col, row, loc_left, loc_left, right, limits); } hit_stone = 1; /* needed for walls of width 1 */ right = loc_left - 1; /* The opening extends beyond the left mark. */ } else { if (vis_func) { for (i = left_shadow; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = left_shadow; i <= right; i++) set_cs(rowp, i); set_min(left_shadow); set_max(right); } if (deeper) { if (hit_stone) left_side(nrow, row, lblock_col, fb_row, fb_col, left_shadow, right, limits); else left_side(nrow, cb_row, cb_col, fb_row, fb_col, left_shadow, right, limits); } return; /* we're outta here */ } } } /* * view_from * * Calculate a view from the given location. Initialize and fill a * ROWNOxCOLNO array (could_see) with all the locations that could be * seen from the source location. Initialize and fill the left most * and right most boundaries of what could be seen. */ STATIC_OVL void view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg) int srow, scol; /* source row and column */ char **loc_cs_rows; /* could_see array (row pointers) */ char *left_most, *right_most; /* limits of what could be seen */ int range; /* 0 if unlimited */ void FDECL((*func), (int, int, genericptr_t)); genericptr_t arg; { register int i; char *rowp; int nrow, left, right, left_row, right_row; char *limits; /* Set globals for near_shadow(), far_shadow(), etc. to use. */ start_col = scol; start_row = srow; cs_rows = loc_cs_rows; cs_left = left_most; cs_right = right_most; vis_func = func; varg = arg; /* Find the left and right limits of sight on the starting row. */ if (viz_clear_rows[srow][scol]) { left = left_ptrs[srow][scol]; right = right_ptrs[srow][scol]; } else { left = (!scol) ? 0 : (viz_clear_rows[srow][scol - 1] ? left_ptrs[srow][scol - 1] : scol - 1); right = (scol == COLNO - 1) ? COLNO - 1 : (viz_clear_rows[srow][scol + 1] ? right_ptrs[srow][scol + 1] : scol + 1); } if (range) { if (range > MAX_RADIUS || range < 1) panic("view_from called with range %d", range); limits = circle_ptr(range) + 1; /* start at next row */ if (left < scol - range) left = scol - range; if (right > scol + range) right = scol + range; } else limits = (char *) 0; if (func) { for (i = left; i <= right; i++) (*func)(i, srow, arg); } else { /* Row optimization */ rowp = cs_rows[srow]; /* We know that we can see our row. */ for (i = left; i <= right; i++) set_cs(rowp, i); cs_left[srow] = left; cs_right[srow] = right; } /* The far block has a row number of -1 if we are on an edge. */ right_row = (right == COLNO - 1) ? -1 : srow; left_row = (!left) ? -1 : srow; /* * Check what could be seen in quadrants. */ if ((nrow = srow + 1) < ROWNO) { step = 1; /* move down */ if (scol < COLNO - 1) right_side(nrow, -1, scol, right_row, right, scol, right, limits); if (scol) left_side(nrow, -1, scol, left_row, left, left, scol, limits); } if ((nrow = srow - 1) >= 0) { step = -1; /* move up */ if (scol < COLNO - 1) right_side(nrow, -1, scol, right_row, right, scol, right, limits); if (scol) left_side(nrow, -1, scol, left_row, left, left, scol, limits); } } #else /*===== End of algorithm D =====*/ /*==========================================================================*\ GENERAL LINE OF SIGHT Algorithm C \*==========================================================================*/ /* * Defines local to Algorithm C. */ STATIC_DCL void FDECL(right_side, (int, int, int, char *)); STATIC_DCL void FDECL(left_side, (int, int, int, char *)); /* Initialize algorithm C (nothing). */ STATIC_OVL void view_init() { } /* * Mark positions as visible on one quadrant of the right side. The * quadrant is determined by the value of the global variable step. */ STATIC_OVL void right_side(row, left, right_mark, limits) int row; /* current row */ int left; /* first (left side) visible spot on prev row */ int right_mark; /* last (right side) visible spot on prev row */ char *limits; /* points at range limit for current row, or NULL */ { int right; /* right limit of "could see" */ int right_edge; /* right edge of an opening */ int nrow; /* new row (calculate once) */ int deeper; /* if TRUE, call self as needed */ int result; /* set by q?_path() */ register int i; /* loop counter */ register char *rowp = NULL; /* row optimization */ char *row_min = NULL; /* left most [used by macro set_min()] */ char *row_max = NULL; /* right most [used by macro set_max()] */ int lim_max; /* right most limit of circle */ nrow = row + step; /* * Can go deeper if the row is in bounds and the next row is within * the circle's limit. We tell the latter by checking to see if the next * limit value is the start of a new circle radius (meaning we depend * on the structure of circle_data[]). */ deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1))); if (!vis_func) { rowp = cs_rows[row]; /* optimization */ row_min = &cs_left[row]; row_max = &cs_right[row]; } if (limits) { lim_max = start_col + *limits; if (lim_max > COLNO - 1) lim_max = COLNO - 1; if (right_mark > lim_max) right_mark = lim_max; limits++; /* prepare for next row */ } else lim_max = COLNO - 1; while (left <= right_mark) { right_edge = right_ptrs[row][left]; if (right_edge > lim_max) right_edge = lim_max; if (!is_clear(row, left)) { /* * Jump to the far side of a stone wall. We can set all * the points in between as seen. * * If the right edge goes beyond the right mark, check to see * how much we can see. */ if (right_edge > right_mark) { /* * If the mark on the previous row was a clear position, * the odds are that we can actually see part of the wall * beyond the mark on this row. If so, then see one beyond * the mark. Otherwise don't. This is a kludge so corners * with an adjacent doorway show up in nethack. */ right_edge = is_clear(row - step, right_mark) ? right_mark + 1 : right_mark; } if (vis_func) { for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= right_edge; i++) set_cs(rowp, i); set_min(left); set_max(right_edge); } left = right_edge + 1; /* no limit check necessary */ continue; } /* No checking needed if our left side is the start column. */ if (left != start_col) { /* * Find the left side. Move right until we can see it or we run * into a wall. */ for (; left <= right_edge; left++) { if (step < 0) { q1_path(start_row, start_col, row, left, rside1); } else { q4_path(start_row, start_col, row, left, rside1); } rside1: /* used if q?_path() is a macro */ if (result) break; } /* * Check for boundary conditions. We *need* check (2) to break * an infinite loop where: * * left == right_edge == right_mark == lim_max. * */ if (left > lim_max) return; /* check (1) */ if (left == lim_max) { /* check (2) */ if (vis_func) { (*vis_func)(lim_max, row, varg); } else { set_cs(rowp, lim_max); set_max(lim_max); } return; } /* * Check if we can see any spots in the opening. We might * (left == right_edge) or might not (left == right_edge+1) have * been able to see the far wall. Make sure we *can* see the * wall (remember, we can see the spot above/below this one) * by backing up. */ if (left >= right_edge) { left = right_edge; /* for the case left == right_edge+1 */ continue; } } /* * Find the right side. If the marker from the previous row is * closer than the edge on this row, then we have to check * how far we can see around the corner (under the overhang). Stop * at the first non-visible spot or we actually hit the far wall. * * Otherwise, we know we can see the right edge of the current row. * * This must be a strict less than so that we can always see a * horizontal wall, even if it is adjacent to us. */ if (right_mark < right_edge) { for (right = right_mark; right <= right_edge; right++) { if (step < 0) { q1_path(start_row, start_col, row, right, rside2); } else { q4_path(start_row, start_col, row, right, rside2); } rside2: /* used if q?_path() is a macro */ if (!result) break; } --right; /* get rid of the last increment */ } else right = right_edge; /* * We have the range that we want. Set the bits. Note that * there is no else --- we no longer handle splinters. */ if (left <= right) { /* * An ugly special case. If you are adjacent to a vertical wall * and it has a break in it, then the right mark is set to be * start_col. We *want* to be able to see adjacent vertical * walls, so we have to set it back. */ if (left == right && left == start_col && start_col < (COLNO - 1) && !is_clear(row, start_col + 1)) right = start_col + 1; if (right > lim_max) right = lim_max; /* set the bits */ if (vis_func) { for (i = left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= right; i++) set_cs(rowp, i); set_min(left); set_max(right); } /* recursive call for next finger of light */ if (deeper) right_side(nrow, left, right, limits); left = right + 1; /* no limit check necessary */ } } } /* * This routine is the mirror image of right_side(). See right_side() for * extensive comments. */ STATIC_OVL void left_side(row, left_mark, right, limits) int row, left_mark, right; char *limits; { int left, left_edge, nrow, deeper, result; register int i; register char *rowp = NULL; char *row_min = NULL; char *row_max = NULL; int lim_min; #ifdef GCC_WARN rowp = row_min = row_max = 0; #endif nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1))); if (!vis_func) { rowp = cs_rows[row]; row_min = &cs_left[row]; row_max = &cs_right[row]; } if (limits) { lim_min = start_col - *limits; if (lim_min < 0) lim_min = 0; if (left_mark < lim_min) left_mark = lim_min; limits++; /* prepare for next row */ } else lim_min = 0; while (right >= left_mark) { left_edge = left_ptrs[row][right]; if (left_edge < lim_min) left_edge = lim_min; if (!is_clear(row, right)) { /* Jump to the far side of a stone wall. */ if (left_edge < left_mark) { /* Maybe see more (kludge). */ left_edge = is_clear(row - step, left_mark) ? left_mark - 1 : left_mark; } if (vis_func) { for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = left_edge; i <= right; i++) set_cs(rowp, i); set_min(left_edge); set_max(right); } right = left_edge - 1; /* no limit check necessary */ continue; } if (right != start_col) { /* Find the right side. */ for (; right >= left_edge; right--) { if (step < 0) { q2_path(start_row, start_col, row, right, lside1); } else { q3_path(start_row, start_col, row, right, lside1); } lside1: /* used if q?_path() is a macro */ if (result) break; } /* Check for boundary conditions. */ if (right < lim_min) return; if (right == lim_min) { if (vis_func) { (*vis_func)(lim_min, row, varg); } else { set_cs(rowp, lim_min); set_min(lim_min); } return; } /* Check if we can see any spots in the opening. */ if (right <= left_edge) { right = left_edge; continue; } } /* Find the left side. */ if (left_mark > left_edge) { for (left = left_mark; left >= left_edge; --left) { if (step < 0) { q2_path(start_row, start_col, row, left, lside2); } else { q3_path(start_row, start_col, row, left, lside2); } lside2: /* used if q?_path() is a macro */ if (!result) break; } left++; /* get rid of the last decrement */ } else left = left_edge; if (left <= right) { /* An ugly special case. */ if (left == right && right == start_col && start_col > 0 && !is_clear(row, start_col - 1)) left = start_col - 1; if (left < lim_min) left = lim_min; if (vis_func) { for (i = left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= right; i++) set_cs(rowp, i); set_min(left); set_max(right); } /* Recurse */ if (deeper) left_side(nrow, left, right, limits); right = left - 1; /* no limit check necessary */ } } } /* * Calculate all possible visible locations from the given location * (srow,scol). NOTE this is (y,x)! Mark the visible locations in the * array provided. */ STATIC_OVL void view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg) int srow, scol; /* starting row and column */ char **loc_cs_rows; /* pointers to the rows of the could_see array */ char *left_most; /* min mark on each row */ char *right_most; /* max mark on each row */ int range; /* 0 if unlimited */ void FDECL((*func), (int, int, genericptr_t)); genericptr_t arg; { register int i; /* loop counter */ char *rowp; /* optimization for setting could_see */ int nrow; /* the next row */ int left; /* the left-most visible column */ int right; /* the right-most visible column */ char *limits; /* range limit for next row */ /* Set globals for q?_path(), left_side(), and right_side() to use. */ start_col = scol; start_row = srow; cs_rows = loc_cs_rows; /* 'could see' rows */ cs_left = left_most; cs_right = right_most; vis_func = func; varg = arg; /* * Determine extent of sight on the starting row. */ if (is_clear(srow, scol)) { left = left_ptrs[srow][scol]; right = right_ptrs[srow][scol]; } else { /* * When in stone, you can only see your adjacent squares, unless * you are on an array boundary or a stone/clear boundary. */ left = (!scol) ? 0 : (is_clear(srow, scol - 1) ? left_ptrs[srow][scol - 1] : scol - 1); right = (scol == COLNO - 1) ? COLNO - 1 : (is_clear(srow, scol + 1) ? right_ptrs[srow][scol + 1] : scol + 1); } if (range) { if (range > MAX_RADIUS || range < 1) panic("view_from called with range %d", range); limits = circle_ptr(range) + 1; /* start at next row */ if (left < scol - range) left = scol - range; if (right > scol + range) right = scol + range; } else limits = (char *) 0; if (func) { for (i = left; i <= right; i++) (*func)(i, srow, arg); } else { /* Row pointer optimization. */ rowp = cs_rows[srow]; /* We know that we can see our row. */ for (i = left; i <= right; i++) set_cs(rowp, i); cs_left[srow] = left; cs_right[srow] = right; } /* * Check what could be seen in quadrants. We need to check for valid * rows here, since we don't do it in the routines right_side() and * left_side() [ugliness to remove extra routine calls]. */ if ((nrow = srow + 1) < ROWNO) { /* move down */ step = 1; if (scol < COLNO - 1) right_side(nrow, scol, right, limits); if (scol) left_side(nrow, left, scol, limits); } if ((nrow = srow - 1) >= 0) { /* move up */ step = -1; if (scol < COLNO - 1) right_side(nrow, scol, right, limits); if (scol) left_side(nrow, left, scol, limits); } } #endif /*===== End of algorithm C =====*/ /* * AREA OF EFFECT "ENGINE" * * Calculate all possible visible locations as viewed from the given location * (srow,scol) within the range specified. Perform "func" with (x, y) args and * additional argument "arg" for each square. * * If not centered on the hero, just forward arguments to view_from(); it * will call "func" when necessary. If the hero is the center, use the * vision matrix and reduce extra work. */ void do_clear_area(scol, srow, range, func, arg) int scol, srow, range; void FDECL((*func), (int, int, genericptr_t)); genericptr_t arg; { /* If not centered on hero, do the hard work of figuring the area */ if (scol != u.ux || srow != u.uy) { view_from(srow, scol, (char **) 0, (char *) 0, (char *) 0, range, func, arg); } else { register int x; int y, min_x, max_x, max_y, offset; char *limits; boolean override_vision; /* vision doesn't pass through water or clouds, detection should [this probably ought to be an arg supplied by our caller...] */ override_vision = (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) && detecting(func); if (range > MAX_RADIUS || range < 1) panic("do_clear_area: illegal range %d", range); if (vision_full_recalc) vision_recalc(0); /* recalc vision if dirty */ limits = circle_ptr(range); if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO - 1; if ((y = (srow - range)) < 0) y = 0; for (; y <= max_y; y++) { offset = limits[v_abs(y - srow)]; if ((min_x = (scol - offset)) < 0) min_x = 0; if ((max_x = (scol + offset)) >= COLNO) max_x = COLNO - 1; for (x = min_x; x <= max_x; x++) if (couldsee(x, y) || override_vision) (*func)(x, y, arg); } } } /* bitmask indicating ways mon is seen; extracted from lookat(pager.c) */ unsigned howmonseen(mon) struct monst *mon; { boolean useemon = (boolean) canseemon(mon); int xraydist = (u.xray_range < 0) ? -1 : (u.xray_range * u.xray_range); unsigned how_seen = 0; /* result */ /* normal vision; cansee is true for both normal and astral vision, but couldsee it not true for astral vision */ if ((mon->wormno ? worm_known(mon) : (cansee(mon->mx, mon->my) && couldsee(mon->mx, mon->my))) && mon_visible(mon) && !mon->minvis) how_seen |= MONSEEN_NORMAL; /* see invisible */ if (useemon && mon->minvis) how_seen |= MONSEEN_SEEINVIS; /* infravision */ if ((!mon->minvis || See_invisible) && see_with_infrared(mon)) how_seen |= MONSEEN_INFRAVIS; /* telepathy */ if (tp_sensemon(mon)) how_seen |= MONSEEN_TELEPAT; /* xray */ if (useemon && xraydist > 0 && distu(mon->mx, mon->my) <= xraydist) how_seen |= MONSEEN_XRAYVIS; /* extended detection */ if (Detect_monsters) how_seen |= MONSEEN_DETECT; /* class-/type-specific warning */ if (MATCH_WARN_OF_MON(mon)) how_seen |= MONSEEN_WARNMON; return how_seen; } /*vision.c*/ nethack-3.6.0/src/weapon.c0000664000076400007660000013756712614367060014411 0ustar paxedpaxed/* NetHack 3.6 weapon.c $NHDT-Date: 1446078767 2015/10/29 00:32:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.55 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * This module contains code for calculation of "to hit" and damage * bonuses for any given weapon used, as well as weapons selection * code for monsters. */ #include "hack.h" /* Categories whose names don't come from OBJ_NAME(objects[type]) */ #define PN_BARE_HANDED (-1) /* includes martial arts */ #define PN_TWO_WEAPONS (-2) #define PN_RIDING (-3) #define PN_POLEARMS (-4) #define PN_SABER (-5) #define PN_HAMMER (-6) #define PN_WHIP (-7) #define PN_ATTACK_SPELL (-8) #define PN_HEALING_SPELL (-9) #define PN_DIVINATION_SPELL (-10) #define PN_ENCHANTMENT_SPELL (-11) #define PN_CLERIC_SPELL (-12) #define PN_ESCAPE_SPELL (-13) #define PN_MATTER_SPELL (-14) STATIC_DCL void FDECL(give_may_advance_msg, (int)); STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = { 0, DAGGER, KNIFE, AXE, PICK_AXE, SHORT_SWORD, BROADSWORD, LONG_SWORD, TWO_HANDED_SWORD, SCIMITAR, PN_SABER, CLUB, MACE, MORNING_STAR, FLAIL, PN_HAMMER, QUARTERSTAFF, PN_POLEARMS, SPEAR, TRIDENT, LANCE, BOW, SLING, CROSSBOW, DART, SHURIKEN, BOOMERANG, PN_WHIP, UNICORN_HORN, PN_ATTACK_SPELL, PN_HEALING_SPELL, PN_DIVINATION_SPELL, PN_ENCHANTMENT_SPELL, PN_CLERIC_SPELL, PN_ESCAPE_SPELL, PN_MATTER_SPELL, PN_BARE_HANDED, PN_TWO_WEAPONS, PN_RIDING }; /* note: entry [0] isn't used */ STATIC_VAR NEARDATA const char *const odd_skill_names[] = { "no skill", "bare hands", /* use barehands_or_martial[] instead */ "two weapon combat", "riding", "polearms", "saber", "hammer", "whip", "attack spells", "healing spells", "divination spells", "enchantment spells", "clerical spells", "escape spells", "matter spells", }; /* indexed vis `is_martial() */ STATIC_VAR NEARDATA const char *const barehands_or_martial[] = { "bare handed combat", "martial arts" }; STATIC_OVL void give_may_advance_msg(skill) int skill; { You_feel("more confident in your %sskills.", skill == P_NONE ? "" : skill <= P_LAST_WEAPON ? "weapon " : skill <= P_LAST_SPELL ? "spell casting " : "fighting "); } STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P)); STATIC_DCL boolean FDECL(could_advance, (int)); STATIC_DCL boolean FDECL(peaked_skill, (int)); STATIC_DCL int FDECL(slots_required, (int)); STATIC_DCL char *FDECL(skill_level_name, (int, char *)); STATIC_DCL void FDECL(skill_advance, (int)); #define P_NAME(type) \ ((skill_names_indices[type] > 0) \ ? OBJ_NAME(objects[skill_names_indices[type]]) \ : (type == P_BARE_HANDED_COMBAT) \ ? barehands_or_martial[martial_bonus()] \ : odd_skill_names[-skill_names_indices[type]]) static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0' }; /* weapon's skill category name for use as generalized description of weapon; mostly used to shorten "you drop your " messages when slippery fingers or polymorph causes hero to involuntarily drop wielded weapon(s) */ const char * weapon_descr(obj) struct obj *obj; { int skill = weapon_type(obj); const char *descr = P_NAME(skill); /* assorted special cases */ switch (skill) { case P_NONE: /* not a weapon or weptool: use item class name; override class name "food" for corpses, tins, and eggs, "large rock" for statues and boulders, and "tool" for towels */ descr = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG || obj->otyp == STATUE || obj->otyp == BOULDER || obj->otyp == TOWEL) ? OBJ_NAME(objects[obj->otyp]) : def_oc_syms[(int) obj->oclass].name; break; case P_SLING: if (is_ammo(obj)) descr = (obj->otyp == ROCK || is_graystone(obj)) ? "stone" /* avoid "rock"; what about known glass? */ : (obj->oclass == GEM_CLASS) ? "gem" /* in case somebody adds odd sling ammo */ : def_oc_syms[(int) obj->oclass].name; break; case P_BOW: if (is_ammo(obj)) descr = "arrow"; break; case P_CROSSBOW: if (is_ammo(obj)) descr = "bolt"; break; case P_FLAIL: if (obj->otyp == GRAPPLING_HOOK) descr = "hook"; break; case P_PICK_AXE: /* even if "dwarvish mattock" hasn't been discovered yet */ if (obj->otyp == DWARVISH_MATTOCK) descr = "mattock"; break; default: break; } return makesingular(descr); } /* * hitval returns an integer representing the "to hit" bonuses * of "otmp" against the monster. */ int hitval(otmp, mon) struct obj *otmp; struct monst *mon; { int tmp = 0; struct permonst *ptr = mon->data; boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)); if (Is_weapon) tmp += otmp->spe; /* Put weapon specific "to hit" bonuses in below: */ tmp += objects[otmp->otyp].oc_hitbon; /* Put weapon vs. monster type "to hit" bonuses in below: */ /* Blessed weapons used against undead or demons */ if (Is_weapon && otmp->blessed && (is_demon(ptr) || is_undead(ptr) || is_vampshifter(mon))) tmp += 2; if (is_spear(otmp) && index(kebabable, ptr->mlet)) tmp += 2; /* trident is highly effective against swimmers */ if (otmp->otyp == TRIDENT && is_swimmer(ptr)) { if (is_pool(mon->mx, mon->my)) tmp += 4; else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2; } /* Picks used against xorns and earth elementals */ if (is_pick(otmp) && (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2; /* Check specially named weapon "to hit" bonuses */ if (otmp->oartifact) tmp += spec_abon(otmp, mon); return tmp; } /* Historical note: The original versions of Hack used a range of damage * which was similar to, but not identical to the damage used in Advanced * Dungeons and Dragons. I figured that since it was so close, I may as well * make it exactly the same as AD&D, adding some more weapons in the process. * This has the advantage that it is at least possible that the player would * already know the damage of at least some of the weapons. This was circa * 1987 and I used the table from Unearthed Arcana until I got tired of typing * them in (leading to something of an imbalance towards weapons early in * alphabetical order). The data structure still doesn't include fields that * fully allow the appropriate damage to be described (there's no way to say * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon * doesn't do an exact die of damage. * * Of course new weapons were added later in the development of Nethack. No * AD&D consistency was kept, but most of these don't exist in AD&D anyway. * * Second edition AD&D came out a few years later; luckily it used the same * table. As of this writing (1999), third edition is in progress but not * released. Let's see if the weapon table stays the same. --KAA * October 2000: It didn't. Oh, well. */ /* * dmgval returns an integer representing the damage bonuses * of "otmp" against the monster. */ int dmgval(otmp, mon) struct obj *otmp; struct monst *mon; { int tmp = 0, otyp = otmp->otyp; struct permonst *ptr = mon->data; boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)); if (otyp == CREAM_PIE) return 0; if (bigmonst(ptr)) { if (objects[otyp].oc_wldam) tmp = rnd(objects[otyp].oc_wldam); switch (otyp) { case IRON_CHAIN: case CROSSBOW_BOLT: case MORNING_STAR: case PARTISAN: case RUNESWORD: case ELVEN_BROADSWORD: case BROADSWORD: tmp++; break; case FLAIL: case RANSEUR: case VOULGE: tmp += rnd(4); break; case ACID_VENOM: case HALBERD: case SPETUM: tmp += rnd(6); break; case BATTLE_AXE: case BARDICHE: case TRIDENT: tmp += d(2, 4); break; case TSURUGI: case DWARVISH_MATTOCK: case TWO_HANDED_SWORD: tmp += d(2, 6); break; } } else { if (objects[otyp].oc_wsdam) tmp = rnd(objects[otyp].oc_wsdam); switch (otyp) { case IRON_CHAIN: case CROSSBOW_BOLT: case MACE: case WAR_HAMMER: case FLAIL: case SPETUM: case TRIDENT: tmp++; break; case BATTLE_AXE: case BARDICHE: case BILL_GUISARME: case GUISARME: case LUCERN_HAMMER: case MORNING_STAR: case RANSEUR: case BROADSWORD: case ELVEN_BROADSWORD: case RUNESWORD: case VOULGE: tmp += rnd(4); break; case ACID_VENOM: tmp += rnd(6); break; } } if (Is_weapon) { tmp += otmp->spe; /* negative enchantment mustn't produce negative damage */ if (tmp < 0) tmp = 0; } if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr)) /* thick skinned/scaled creatures don't feel it */ tmp = 0; if (ptr == &mons[PM_SHADE] && !shade_glare(otmp)) tmp = 0; /* "very heavy iron ball"; weight increase is in increments of 160 */ if (otyp == HEAVY_IRON_BALL && tmp > 0) { int wt = (int) objects[HEAVY_IRON_BALL].oc_weight; if ((int) otmp->owt > wt) { wt = ((int) otmp->owt - wt) / 160; tmp += rnd(4 * wt); if (tmp > 25) tmp = 25; /* objects[].oc_wldam */ } } /* Put weapon vs. monster type damage bonuses in below: */ if (Is_weapon || otmp->oclass == GEM_CLASS || otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) { int bonus = 0; if (otmp->blessed && (is_undead(ptr) || is_demon(ptr) || is_vampshifter(mon))) bonus += rnd(4); if (is_axe(otmp) && is_wooden(ptr)) bonus += rnd(4); if (objects[otyp].oc_material == SILVER && mon_hates_silver(mon)) bonus += rnd(20); /* if the weapon is going to get a double damage bonus, adjust this bonus so that effectively it's added after the doubling */ if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25) bonus = (bonus + 1) / 2; tmp += bonus; } if (tmp > 0) { /* It's debatable whether a rusted blunt instrument should do less damage than a pristine one, since it will hit with essentially the same impact, but there ought to some penalty for using damaged gear so always subtract erosion even for blunt weapons. */ tmp -= greatest_erosion(otmp); if (tmp < 1) tmp = 1; } return tmp; } STATIC_DCL struct obj *FDECL(oselect, (struct monst *, int)); #define Oselect(x) \ if ((otmp = oselect(mtmp, x)) != 0) \ return otmp; STATIC_OVL struct obj * oselect(mtmp, x) struct monst *mtmp; int x; { struct obj *otmp; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { if (otmp->otyp == x /* never select non-cockatrice corpses */ && !((x == CORPSE || x == EGG) && !touch_petrifies(&mons[otmp->corpsenm])) && (!otmp->oartifact || touch_artifact(otmp, mtmp))) return otmp; } return (struct obj *) 0; } static NEARDATA const int rwep[] = { DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN, SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW, CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, FLINT, ROCK, LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE }; static NEARDATA const int pwep[] = { HALBERD, BARDICHE, SPETUM, BILL_GUISARME, VOULGE, RANSEUR, GUISARME, GLAIVE, LUCERN_HAMMER, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE }; static struct obj *propellor; /* select a ranged weapon for the monster */ struct obj * select_rwep(mtmp) register struct monst *mtmp; { register struct obj *otmp; struct obj *mwep; boolean mweponly; int i; char mlet = mtmp->data->mlet; propellor = &zeroobj; Oselect(EGG); /* cockatrice egg */ if (mlet == S_KOP) /* pies are first choice for Kops */ Oselect(CREAM_PIE); if (throws_rocks(mtmp->data)) /* ...boulders for giants */ Oselect(BOULDER); /* Select polearms first; they do more damage and aren't expendable. But don't pick one if monster's weapon is welded, because then we'd never have a chance to throw non-wielding missiles. */ /* The limit of 13 here is based on the monster polearm range limit * (defined as 5 in mthrowu.c). 5 corresponds to a distance of 2 in * one direction and 1 in another; one space beyond that would be 3 in * one direction and 2 in another; 3^2+2^2=13. */ mwep = MON_WEP(mtmp); /* NO_WEAPON_WANTED means we already tried to wield and failed */ mweponly = (mwelded(mwep) && mtmp->weapon_check == NO_WEAPON_WANTED); if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13 && couldsee(mtmp->mx, mtmp->my)) { for (i = 0; i < SIZE(pwep); i++) { /* Only strong monsters can wield big (esp. long) weapons. * Big weapon is basically the same as bimanual. * All monsters can wield the remaining weapons. */ if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0) || !objects[pwep[i]].oc_bimanual) && (objects[pwep[i]].oc_material != SILVER || !mon_hates_silver(mtmp))) { if ((otmp = oselect(mtmp, pwep[i])) != 0 && (otmp == mwep || !mweponly)) { propellor = otmp; /* force the monster to wield it */ return otmp; } } } } /* * other than these two specific cases, always select the * most potent ranged weapon to hand. */ for (i = 0; i < SIZE(rwep); i++) { int prop; /* shooting gems from slings; this goes just before the darts */ /* (shooting rocks is already handled via the rwep[] ordering) */ if (rwep[i] == DART && !likes_gems(mtmp->data) && m_carrying(mtmp, SLING)) { /* propellor */ for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->oclass == GEM_CLASS && (otmp->otyp != LOADSTONE || !otmp->cursed)) { propellor = m_carrying(mtmp, SLING); return otmp; } } /* KMH -- This belongs here so darts will work */ propellor = &zeroobj; prop = (objects[rwep[i]]).oc_skill; if (prop < 0) { switch (-prop) { case P_BOW: propellor = (oselect(mtmp, YUMI)); if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW)); if (!propellor) propellor = (oselect(mtmp, BOW)); if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW)); break; case P_SLING: propellor = (oselect(mtmp, SLING)); break; case P_CROSSBOW: propellor = (oselect(mtmp, CROSSBOW)); } if ((otmp = MON_WEP(mtmp)) && mwelded(otmp) && otmp != propellor && mtmp->weapon_check == NO_WEAPON_WANTED) propellor = 0; } /* propellor = obj, propellor to use * propellor = &zeroobj, doesn't need a propellor * propellor = 0, needed one and didn't have one */ if (propellor != 0) { /* Note: cannot use m_carrying for loadstones, since it will * always select the first object of a type, and maybe the * monster is carrying two but only the first is unthrowable. */ if (rwep[i] != LOADSTONE) { /* Don't throw a cursed weapon-in-hand or an artifact */ if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact && !(otmp == MON_WEP(mtmp) && mwelded(otmp))) return otmp; } else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { if (otmp->otyp == LOADSTONE && !otmp->cursed) return otmp; } } } /* failure */ return (struct obj *) 0; } /* Weapons in order of preference */ static const NEARDATA short hwep[] = { CORPSE, /* cockatrice corpse */ TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE, KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, ELVEN_BROADSWORD, BROADSWORD, SCIMITAR, SILVER_SABER, MORNING_STAR, ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD, ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB, PICK_AXE, RUBBER_HOSE, WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME, SCALPEL, KNIFE, WORM_TOOTH }; /* select a hand to hand weapon for the monster */ struct obj * select_hwep(mtmp) register struct monst *mtmp; { register struct obj *otmp; register int i; boolean strong = strongmonst(mtmp->data); boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0; /* prefer artifacts to everything else */ for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { if (otmp->oclass == WEAPON_CLASS && otmp->oartifact && touch_artifact(otmp, mtmp) && ((strong && !wearing_shield) || !objects[otmp->otyp].oc_bimanual)) return otmp; } if (is_giant(mtmp->data)) /* giants just love to use clubs */ Oselect(CLUB); /* only strong monsters can wield big (esp. long) weapons */ /* big weapon is basically the same as bimanual */ /* all monsters can wield the remaining weapons */ for (i = 0; i < SIZE(hwep); i++) { if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp)) continue; if (((strong && !wearing_shield) || !objects[hwep[i]].oc_bimanual) && (objects[hwep[i]].oc_material != SILVER || !mon_hates_silver(mtmp))) Oselect(hwep[i]); } /* failure */ return (struct obj *) 0; } /* Called after polymorphing a monster, robbing it, etc.... Monsters * otherwise never unwield stuff on their own. Might print message. */ void possibly_unwield(mon, polyspot) struct monst *mon; boolean polyspot; { struct obj *obj, *mw_tmp; if (!(mw_tmp = MON_WEP(mon))) return; for (obj = mon->minvent; obj; obj = obj->nobj) if (obj == mw_tmp) break; if (!obj) { /* The weapon was stolen or destroyed */ MON_NOWEP(mon); mon->weapon_check = NEED_WEAPON; return; } if (!attacktype(mon->data, AT_WEAP)) { setmnotwielded(mon, mw_tmp); mon->weapon_check = NO_WEAPON_WANTED; obj_extract_self(obj); if (cansee(mon->mx, mon->my)) { pline("%s drops %s.", Monnam(mon), distant_name(obj, doname)); newsym(mon->mx, mon->my); } /* might be dropping object into water or lava */ if (!flooreffects(obj, mon->mx, mon->my, "drop")) { if (polyspot) bypass_obj(obj); place_object(obj, mon->mx, mon->my); stackobj(obj); } return; } /* The remaining case where there is a change is where a monster * is polymorphed into a stronger/weaker monster with a different * choice of weapons. This has no parallel for players. It can * be handled by waiting until mon_wield_item is actually called. * Though the monster still wields the wrong weapon until then, * this is OK since the player can't see it. (FIXME: Not okay since * probing can reveal it.) * Note that if there is no change, setting the check to NEED_WEAPON * is harmless. * Possible problem: big monster with big cursed weapon gets * polymorphed into little monster. But it's not quite clear how to * handle this anyway.... */ if (!(mwelded(mw_tmp) && mon->weapon_check == NO_WEAPON_WANTED)) mon->weapon_check = NEED_WEAPON; return; } /* Let a monster try to wield a weapon, based on mon->weapon_check. * Returns 1 if the monster took time to do it, 0 if it did not. */ int mon_wield_item(mon) register struct monst *mon; { struct obj *obj; /* This case actually should never happen */ if (mon->weapon_check == NO_WEAPON_WANTED) return 0; switch (mon->weapon_check) { case NEED_HTH_WEAPON: obj = select_hwep(mon); break; case NEED_RANGED_WEAPON: (void) select_rwep(mon); obj = propellor; break; case NEED_PICK_AXE: obj = m_carrying(mon, PICK_AXE); /* KMH -- allow other picks */ if (!obj && !which_armor(mon, W_ARMS)) obj = m_carrying(mon, DWARVISH_MATTOCK); break; case NEED_AXE: /* currently, only 2 types of axe */ obj = m_carrying(mon, BATTLE_AXE); if (!obj || which_armor(mon, W_ARMS)) obj = m_carrying(mon, AXE); break; case NEED_PICK_OR_AXE: /* prefer pick for fewer switches on most levels */ obj = m_carrying(mon, DWARVISH_MATTOCK); if (!obj) obj = m_carrying(mon, BATTLE_AXE); if (!obj || which_armor(mon, W_ARMS)) { obj = m_carrying(mon, PICK_AXE); if (!obj) obj = m_carrying(mon, AXE); } break; default: impossible("weapon_check %d for %s?", mon->weapon_check, mon_nam(mon)); return 0; } if (obj && obj != &zeroobj) { struct obj *mw_tmp = MON_WEP(mon); if (mw_tmp && mw_tmp->otyp == obj->otyp) { /* already wielding it */ mon->weapon_check = NEED_WEAPON; return 0; } /* Actually, this isn't necessary--as soon as the monster * wields the weapon, the weapon welds itself, so the monster * can know it's cursed and needn't even bother trying. * Still.... */ if (mw_tmp && mwelded(mw_tmp)) { if (canseemon(mon)) { char welded_buf[BUFSZ]; const char *mon_hand = mbodypart(mon, HAND); if (bimanual(mw_tmp)) mon_hand = makeplural(mon_hand); Sprintf(welded_buf, "%s welded to %s %s", otense(mw_tmp, "are"), mhis(mon), mon_hand); if (obj->otyp == PICK_AXE) { pline("Since %s weapon%s %s,", s_suffix(mon_nam(mon)), plur(mw_tmp->quan), welded_buf); pline("%s cannot wield that %s.", mon_nam(mon), xname(obj)); } else { pline("%s tries to wield %s.", Monnam(mon), doname(obj)); pline("%s %s!", Yname2(mw_tmp), welded_buf); } mw_tmp->bknown = 1; } mon->weapon_check = NO_WEAPON_WANTED; return 1; } mon->mw = obj; /* wield obj */ setmnotwielded(mon, mw_tmp); mon->weapon_check = NEED_WEAPON; if (canseemon(mon)) { pline("%s wields %s!", Monnam(mon), doname(obj)); if (mwelded(mw_tmp)) { pline("%s %s to %s %s!", Tobjnam(obj, "weld"), is_plural(obj) ? "themselves" : "itself", s_suffix(mon_nam(mon)), mbodypart(mon, HAND)); obj->bknown = 1; } } if (artifact_light(obj) && !obj->lamplit) { begin_burn(obj, FALSE); if (canseemon(mon)) pline("%s %s in %s %s!", Tobjnam(obj, "shine"), arti_light_description(obj), s_suffix(mon_nam(mon)), mbodypart(mon, HAND)); } obj->owornmask = W_WEP; return 1; } mon->weapon_check = NEED_WEAPON; return 0; } /* force monster to stop wielding current weapon, if any */ void mwepgone(mon) struct monst *mon; { struct obj *mwep = MON_WEP(mon); if (mwep) { setmnotwielded(mon, mwep); mon->weapon_check = NEED_WEAPON; } } /* attack bonus for strength & dexterity */ int abon() { int sbon; int str = ACURR(A_STR), dex = ACURR(A_DEX); if (Upolyd) return (adj_lev(&mons[u.umonnum]) - 3); if (str < 6) sbon = -2; else if (str < 8) sbon = -1; else if (str < 17) sbon = 0; else if (str <= STR18(50)) sbon = 1; /* up to 18/50 */ else if (str < STR18(100)) sbon = 2; else sbon = 3; /* Game tuning kludge: make it a bit easier for a low level character to * hit */ sbon += (u.ulevel < 3) ? 1 : 0; if (dex < 4) return (sbon - 3); else if (dex < 6) return (sbon - 2); else if (dex < 8) return (sbon - 1); else if (dex < 14) return sbon; else return (sbon + dex - 14); } /* damage bonus for strength */ int dbon() { int str = ACURR(A_STR); if (Upolyd) return 0; if (str < 6) return -1; else if (str < 16) return 0; else if (str < 18) return 1; else if (str == 18) return 2; /* up to 18 */ else if (str <= STR18(75)) return 3; /* up to 18/75 */ else if (str <= STR18(90)) return 4; /* up to 18/90 */ else if (str < STR18(100)) return 5; /* up to 18/99 */ else return 6; } /* increase a towel's wetness */ void wet_a_towel(obj, amt, verbose) struct obj *obj; int amt; /* positive: new value; negative: increment by -amt; zero: no-op */ boolean verbose; { int newspe = (amt <= 0) ? obj->spe - amt : amt; /* new state is only reported if it's an increase */ if (newspe > obj->spe) { if (verbose) { const char *wetness = (newspe < 3) ? (!obj->spe ? "damp" : "damper") : (!obj->spe ? "wet" : "wetter"); if (carried(obj)) pline("%s gets %s.", Yobjnam2(obj, (const char *) 0), wetness); else if (mcarried(obj) && canseemon(obj->ocarry)) pline("%s %s gets %s.", s_suffix(Monnam(obj->ocarry)), xname(obj), wetness); } } obj->spe = min(newspe, 7); /* if hero is wielding this towel, don't give "you begin bashing with your wet towel" message on next attack with it */ if (obj == uwep) unweapon = !is_wet_towel(obj); } /* decrease a towel's wetness */ void dry_a_towel(obj, amt, verbose) struct obj *obj; int amt; /* positive: new value; negative: decrement by -amt; zero: no-op */ boolean verbose; { int newspe = (amt <= 0) ? obj->spe + amt : amt; /* new state is only reported if it's a decrease */ if (newspe < obj->spe) { if (verbose) { if (carried(obj)) pline("%s dries%s.", Yobjnam2(obj, (const char *) 0), !newspe ? " out" : ""); else if (mcarried(obj) && canseemon(obj->ocarry)) pline("%s %s drie%s.", s_suffix(Monnam(obj->ocarry)), xname(obj), !newspe ? " out" : ""); } } newspe = min(newspe, 7); obj->spe = max(newspe, 0); /* if hero is wielding this towel and it is now dry, give "you begin bashing with your towel" message on next attack with it */ if (obj == uwep) unweapon = !is_wet_towel(obj); } /* copy the skill level name into the given buffer */ STATIC_OVL char * skill_level_name(skill, buf) int skill; char *buf; { const char *ptr; switch (P_SKILL(skill)) { case P_UNSKILLED: ptr = "Unskilled"; break; case P_BASIC: ptr = "Basic"; break; case P_SKILLED: ptr = "Skilled"; break; case P_EXPERT: ptr = "Expert"; break; /* these are for unarmed combat/martial arts only */ case P_MASTER: ptr = "Master"; break; case P_GRAND_MASTER: ptr = "Grand Master"; break; default: ptr = "Unknown"; break; } Strcpy(buf, ptr); return buf; } /* return the # of slots required to advance the skill */ STATIC_OVL int slots_required(skill) int skill; { int tmp = P_SKILL(skill); /* The more difficult the training, the more slots it takes. * unskilled -> basic 1 * basic -> skilled 2 * skilled -> expert 3 */ if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT) return tmp; /* Fewer slots used up for unarmed or martial. * unskilled -> basic 1 * basic -> skilled 1 * skilled -> expert 2 * expert -> master 2 * master -> grand master 3 */ return (tmp + 1) / 2; } /* return true if this skill can be advanced */ /*ARGSUSED*/ STATIC_OVL boolean can_advance(skill, speedy) int skill; boolean speedy; { if (P_RESTRICTED(skill) || P_SKILL(skill) >= P_MAX_SKILL(skill) || u.skills_advanced >= P_SKILL_LIMIT) return FALSE; if (wizard && speedy) return TRUE; return (boolean) ((int) P_ADVANCE(skill) >= practice_needed_to_advance(P_SKILL(skill)) && u.weapon_slots >= slots_required(skill)); } /* return true if this skill could be advanced if more slots were available */ STATIC_OVL boolean could_advance(skill) int skill; { if (P_RESTRICTED(skill) || P_SKILL(skill) >= P_MAX_SKILL(skill) || u.skills_advanced >= P_SKILL_LIMIT) return FALSE; return (boolean) ((int) P_ADVANCE(skill) >= practice_needed_to_advance(P_SKILL(skill))); } /* return true if this skill has reached its maximum and there's been enough practice to become eligible for the next step if that had been possible */ STATIC_OVL boolean peaked_skill(skill) int skill; { if (P_RESTRICTED(skill)) return FALSE; return (boolean) (P_SKILL(skill) >= P_MAX_SKILL(skill) && ((int) P_ADVANCE(skill) >= practice_needed_to_advance(P_SKILL(skill)))); } STATIC_OVL void skill_advance(skill) int skill; { u.weapon_slots -= slots_required(skill); P_SKILL(skill)++; u.skill_record[u.skills_advanced++] = skill; /* subtly change the advance message to indicate no more advancement */ You("are now %s skilled in %s.", P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more", P_NAME(skill)); } static const struct skill_range { short first, last; const char *name; } skill_ranges[] = { { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" }, { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" }, { P_FIRST_SPELL, P_LAST_SPELL, "Spellcasting Skills" }, }; /* * The `#enhance' extended command. What we _really_ would like is * to keep being able to pick things to advance until we couldn't any * more. This is currently not possible -- the menu code has no way * to call us back for instant action. Even if it did, we would also need * to be able to update the menu since selecting one item could make * others unselectable. */ int enhance_weapon_skill() { int pass, i, n, len, longest, to_advance, eventually_advance, maxxed_cnt; char buf[BUFSZ], sklnambuf[BUFSZ]; const char *prefix; menu_item *selected; anything any; winid win; boolean speedy = FALSE; if (wizard && yn("Advance skills without practice?") == 'y') speedy = TRUE; do { /* find longest available skill name, count those that can advance */ to_advance = eventually_advance = maxxed_cnt = 0; for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) { if (P_RESTRICTED(i)) continue; if ((len = strlen(P_NAME(i))) > longest) longest = len; if (can_advance(i, speedy)) to_advance++; else if (could_advance(i)) eventually_advance++; else if (peaked_skill(i)) maxxed_cnt++; } win = create_nhwindow(NHW_MENU); start_menu(win); /* start with a legend if any entries will be annotated with "*" or "#" below */ if (eventually_advance > 0 || maxxed_cnt > 0) { any = zeroany; if (eventually_advance > 0) { Sprintf(buf, "(Skill%s flagged by \"*\" may be enhanced %s.)", plur(eventually_advance), (u.ulevel < MAXULEV) ? "when you're more experienced" : "if skill slots become available"); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } if (maxxed_cnt > 0) { Sprintf(buf, "(Skill%s flagged by \"#\" cannot be enhanced any further.)", plur(maxxed_cnt)); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); } /* List the skills, making ones that could be advanced selectable. List the miscellaneous skills first. Possible future enhancement: list spell skills before weapon skills for spellcaster roles. */ for (pass = 0; pass < SIZE(skill_ranges); pass++) for (i = skill_ranges[pass].first; i <= skill_ranges[pass].last; i++) { /* Print headings for skill types */ any = zeroany; if (i == skill_ranges[pass].first) add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, skill_ranges[pass].name, MENU_UNSELECTED); if (P_RESTRICTED(i)) continue; /* * Sigh, this assumes a monospaced font unless * iflags.menu_tab_sep is set in which case it puts * tabs between columns. * The 12 is the longest skill level name. * The " " is room for a selection letter and dash, "a - ". */ if (can_advance(i, speedy)) prefix = ""; /* will be preceded by menu choice */ else if (could_advance(i)) prefix = " * "; else if (peaked_skill(i)) prefix = " # "; else prefix = (to_advance + eventually_advance + maxxed_cnt > 0) ? " " : ""; (void) skill_level_name(i, sklnambuf); if (wizard) { if (!iflags.menu_tab_sep) Sprintf(buf, " %s%-*s %-12s %5d(%4d)", prefix, longest, P_NAME(i), sklnambuf, P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i))); else Sprintf(buf, " %s%s\t%s\t%5d(%4d)", prefix, P_NAME(i), sklnambuf, P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i))); } else { if (!iflags.menu_tab_sep) Sprintf(buf, " %s %-*s [%s]", prefix, longest, P_NAME(i), sklnambuf); else Sprintf(buf, " %s%s\t[%s]", prefix, P_NAME(i), sklnambuf); } any.a_int = can_advance(i, speedy) ? i + 1 : 0; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:" : "Current skills:"); if (wizard && !speedy) Sprintf(eos(buf), " (%d slot%s available)", u.weapon_slots, plur(u.weapon_slots)); end_menu(win, buf); n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected); destroy_nhwindow(win); if (n > 0) { n = selected[0].item.a_int - 1; /* get item selected */ free((genericptr_t) selected); skill_advance(n); /* check for more skills able to advance, if so then .. */ for (n = i = 0; i < P_NUM_SKILLS; i++) { if (can_advance(i, speedy)) { if (!speedy) You_feel("you could be more dangerous!"); n++; break; } } } } while (speedy && n > 0); return 0; } /* * Change from restricted to unrestricted, allowing P_BASIC as max. This * function may be called with with P_NONE. Used in pray.c. */ void unrestrict_weapon_skill(skill) int skill; { if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) { P_SKILL(skill) = P_UNSKILLED; P_MAX_SKILL(skill) = P_BASIC; P_ADVANCE(skill) = 0; } } void use_skill(skill, degree) int skill; int degree; { boolean advance_before; if (skill != P_NONE && !P_RESTRICTED(skill)) { advance_before = can_advance(skill, FALSE); P_ADVANCE(skill) += degree; if (!advance_before && can_advance(skill, FALSE)) give_may_advance_msg(skill); } } void add_weapon_skill(n) int n; /* number of slots to gain; normally one */ { int i, before, after; for (i = 0, before = 0; i < P_NUM_SKILLS; i++) if (can_advance(i, FALSE)) before++; u.weapon_slots += n; for (i = 0, after = 0; i < P_NUM_SKILLS; i++) if (can_advance(i, FALSE)) after++; if (before < after) give_may_advance_msg(P_NONE); } void lose_weapon_skill(n) int n; /* number of slots to lose; normally one */ { int skill; while (--n >= 0) { /* deduct first from unused slots then from last placed one, if any */ if (u.weapon_slots) { u.weapon_slots--; } else if (u.skills_advanced) { skill = u.skill_record[--u.skills_advanced]; if (P_SKILL(skill) <= P_UNSKILLED) panic("lose_weapon_skill (%d)", skill); P_SKILL(skill)--; /* drop skill one level */ /* Lost skill might have taken more than one slot; refund rest. */ u.weapon_slots = slots_required(skill) - 1; /* It might now be possible to advance some other pending skill by using the refunded slots, but giving a message to that effect would seem pretty confusing.... */ } } } int weapon_type(obj) struct obj *obj; { /* KMH -- now uses the object table */ int type; if (!obj) return P_BARE_HANDED_COMBAT; /* Not using a weapon */ if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS && obj->oclass != GEM_CLASS) return P_NONE; /* Not a weapon, weapon-tool, or ammo */ type = objects[obj->otyp].oc_skill; return (type < 0) ? -type : type; } int uwep_skill_type() { if (u.twoweap) return P_TWO_WEAPON_COMBAT; return weapon_type(uwep); } /* * Return hit bonus/penalty based on skill of weapon. * Treat restricted weapons as unskilled. */ int weapon_hit_bonus(weapon) struct obj *weapon; { int type, wep_type, skill, bonus = 0; static const char bad_skill[] = "weapon_hit_bonus: bad skill %d"; wep_type = weapon_type(weapon); /* use two weapon skill only if attacking with one of the wielded weapons */ type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ? P_TWO_WEAPON_COMBAT : wep_type; if (type == P_NONE) { bonus = 0; } else if (type <= P_LAST_WEAPON) { switch (P_SKILL(type)) { default: impossible(bad_skill, P_SKILL(type)); /* fall through */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -4; break; case P_BASIC: bonus = 0; break; case P_SKILLED: bonus = 2; break; case P_EXPERT: bonus = 3; break; } } else if (type == P_TWO_WEAPON_COMBAT) { skill = P_SKILL(P_TWO_WEAPON_COMBAT); if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type); switch (skill) { default: impossible(bad_skill, skill); /* fall through */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -9; break; case P_BASIC: bonus = -7; break; case P_SKILLED: bonus = -5; break; case P_EXPERT: bonus = -3; break; } } else if (type == P_BARE_HANDED_COMBAT) { /* * b.h. m.a. * unskl: +1 n/a * basic: +1 +3 * skild: +2 +4 * exprt: +2 +5 * mastr: +3 +6 * grand: +3 +7 */ bonus = P_SKILL(type); bonus = max(bonus, P_UNSKILLED) - 1; /* unskilled => 0 */ bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2; } /* KMH -- It's harder to hit while you are riding */ if (u.usteed) { switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: bonus -= 2; break; case P_BASIC: bonus -= 1; break; case P_SKILLED: break; case P_EXPERT: break; } if (u.twoweap) bonus -= 2; } return bonus; } /* * Return damage bonus/penalty based on skill of weapon. * Treat restricted weapons as unskilled. */ int weapon_dam_bonus(weapon) struct obj *weapon; { int type, wep_type, skill, bonus = 0; wep_type = weapon_type(weapon); /* use two weapon skill only if attacking with one of the wielded weapons */ type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ? P_TWO_WEAPON_COMBAT : wep_type; if (type == P_NONE) { bonus = 0; } else if (type <= P_LAST_WEAPON) { switch (P_SKILL(type)) { default: impossible("weapon_dam_bonus: bad skill %d", P_SKILL(type)); /* fall through */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -2; break; case P_BASIC: bonus = 0; break; case P_SKILLED: bonus = 1; break; case P_EXPERT: bonus = 2; break; } } else if (type == P_TWO_WEAPON_COMBAT) { skill = P_SKILL(P_TWO_WEAPON_COMBAT); if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type); switch (skill) { default: case P_ISRESTRICTED: case P_UNSKILLED: bonus = -3; break; case P_BASIC: bonus = -1; break; case P_SKILLED: bonus = 0; break; case P_EXPERT: bonus = 1; break; } } else if (type == P_BARE_HANDED_COMBAT) { /* * b.h. m.a. * unskl: 0 n/a * basic: +1 +3 * skild: +1 +4 * exprt: +2 +6 * mastr: +2 +7 * grand: +3 +9 */ bonus = P_SKILL(type); bonus = max(bonus, P_UNSKILLED) - 1; /* unskilled => 0 */ bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2; } /* KMH -- Riding gives some thrusting damage */ if (u.usteed && type != P_TWO_WEAPON_COMBAT) { switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: break; case P_BASIC: break; case P_SKILLED: bonus += 1; break; case P_EXPERT: bonus += 2; break; } } return bonus; } /* * Initialize weapon skill array for the game. Start by setting all * skills to restricted, then set the skill for every weapon the * hero is holding, finally reading the given array that sets * maximums. */ void skill_init(class_skill) const struct def_skill *class_skill; { struct obj *obj; int skmax, skill; /* initialize skill array; by default, everything is restricted */ for (skill = 0; skill < P_NUM_SKILLS; skill++) { P_SKILL(skill) = P_ISRESTRICTED; P_MAX_SKILL(skill) = P_ISRESTRICTED; P_ADVANCE(skill) = 0; } /* Set skill for all weapons in inventory to be basic */ for (obj = invent; obj; obj = obj->nobj) { /* don't give skill just because of carried ammo, wait until we see the relevant launcher (prevents an archeologist's touchstone from inadvertently providing skill in sling) */ if (is_ammo(obj)) continue; skill = weapon_type(obj); if (skill != P_NONE) P_SKILL(skill) = P_BASIC; } /* set skills for magic */ if (Role_if(PM_HEALER) || Role_if(PM_MONK)) { P_SKILL(P_HEALING_SPELL) = P_BASIC; } else if (Role_if(PM_PRIEST)) { P_SKILL(P_CLERIC_SPELL) = P_BASIC; } else if (Role_if(PM_WIZARD)) { P_SKILL(P_ATTACK_SPELL) = P_BASIC; P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC; } /* walk through array to set skill maximums */ for (; class_skill->skill != P_NONE; class_skill++) { skmax = class_skill->skmax; skill = class_skill->skill; P_MAX_SKILL(skill) = skmax; if (P_SKILL(skill) == P_ISRESTRICTED) /* skill pre-set */ P_SKILL(skill) = P_UNSKILLED; } /* High potential fighters already know how to use their hands. */ if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT) P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC; /* Roles that start with a horse know how to ride it */ if (urole.petnum == PM_PONY) P_SKILL(P_RIDING) = P_BASIC; /* * Make sure we haven't missed setting the max on a skill * & set advance */ for (skill = 0; skill < P_NUM_SKILLS; skill++) { if (!P_RESTRICTED(skill)) { if (P_MAX_SKILL(skill) < P_SKILL(skill)) { impossible("skill_init: curr > max: %s", P_NAME(skill)); P_MAX_SKILL(skill) = P_SKILL(skill); } P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill) - 1); } } } void setmnotwielded(mon, obj) register struct monst *mon; register struct obj *obj; { if (!obj) return; if (artifact_light(obj) && obj->lamplit) { end_burn(obj, FALSE); if (canseemon(mon)) pline("%s in %s %s %s shining.", The(xname(obj)), s_suffix(mon_nam(mon)), mbodypart(mon, HAND), otense(obj, "stop")); } if (MON_WEP(mon) == obj) MON_NOWEP(mon); obj->owornmask &= ~W_WEP; } /*weapon.c*/ nethack-3.6.0/src/were.c0000664000076400007660000001240312536476415014047 0ustar paxedpaxed/* NetHack 3.6 were.c $NHDT-Date: 1432512763 2015/05/25 00:12:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" void were_change(mon) register struct monst *mon; { if (!is_were(mon->data)) return; if (is_human(mon->data)) { if (!Protection_from_shape_changers && !rn2(night() ? (flags.moonphase == FULL_MOON ? 3 : 30) : (flags.moonphase == FULL_MOON ? 10 : 50))) { new_were(mon); /* change into animal form */ if (!Deaf && !canseemon(mon)) { const char *howler; switch (monsndx(mon->data)) { case PM_WEREWOLF: howler = "wolf"; break; case PM_WEREJACKAL: howler = "jackal"; break; default: howler = (char *) 0; break; } if (howler) You_hear("a %s howling at the moon.", howler); } } } else if (!rn2(30) || Protection_from_shape_changers) { new_were(mon); /* change back into human form */ } } int counter_were(pm) int pm; { switch (pm) { case PM_WEREWOLF: return (PM_HUMAN_WEREWOLF); case PM_HUMAN_WEREWOLF: return (PM_WEREWOLF); case PM_WEREJACKAL: return (PM_HUMAN_WEREJACKAL); case PM_HUMAN_WEREJACKAL: return (PM_WEREJACKAL); case PM_WERERAT: return (PM_HUMAN_WERERAT); case PM_HUMAN_WERERAT: return (PM_WERERAT); default: return NON_PM; } } /* convert monsters similar to werecritters into appropriate werebeast */ int were_beastie(pm) int pm; { switch (pm) { case PM_WERERAT: case PM_SEWER_RAT: case PM_GIANT_RAT: case PM_RABID_RAT: return PM_WERERAT; case PM_WEREJACKAL: case PM_JACKAL: case PM_FOX: case PM_COYOTE: return PM_WEREJACKAL; case PM_WEREWOLF: case PM_WOLF: case PM_WARG: case PM_WINTER_WOLF: return PM_WEREWOLF; default: break; } return NON_PM; } void new_were(mon) register struct monst *mon; { register int pm; pm = counter_were(monsndx(mon->data)); if (pm < LOW_PM) { impossible("unknown lycanthrope %s.", mon->data->mname); return; } if (canseemon(mon) && !Hallucination) pline("%s changes into a %s.", Monnam(mon), is_human(&mons[pm]) ? "human" : mons[pm].mname + 4); set_mon_data(mon, &mons[pm], 0); if (mon->msleeping || !mon->mcanmove) { /* transformation wakens and/or revitalizes */ mon->msleeping = 0; mon->mfrozen = 0; /* not asleep or paralyzed */ mon->mcanmove = 1; } /* regenerate by 1/4 of the lost hit points */ mon->mhp += (mon->mhpmax - mon->mhp) / 4; newsym(mon->mx, mon->my); mon_break_armor(mon, FALSE); possibly_unwield(mon, FALSE); } int were_summon(ptr, yours, visible, genbuf) /* were-creature (even you) summons a horde */ register struct permonst *ptr; register boolean yours; int *visible; /* number of visible helpers created */ char *genbuf; { register int i, typ, pm = monsndx(ptr); register struct monst *mtmp; int total = 0; *visible = 0; if (Protection_from_shape_changers && !yours) return 0; for (i = rnd(5); i > 0; i--) { switch (pm) { case PM_WERERAT: case PM_HUMAN_WERERAT: typ = rn2(3) ? PM_SEWER_RAT : rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT; if (genbuf) Strcpy(genbuf, "rat"); break; case PM_WEREJACKAL: case PM_HUMAN_WEREJACKAL: typ = PM_JACKAL; if (genbuf) Strcpy(genbuf, "jackal"); break; case PM_WEREWOLF: case PM_HUMAN_WEREWOLF: typ = rn2(5) ? PM_WOLF : PM_WINTER_WOLF; if (genbuf) Strcpy(genbuf, "wolf"); break; default: continue; } mtmp = makemon(&mons[typ], u.ux, u.uy, NO_MM_FLAGS); if (mtmp) { total++; if (canseemon(mtmp)) *visible += 1; } if (yours && mtmp) (void) tamedog(mtmp, (struct obj *) 0); } return total; } void you_were() { char qbuf[QBUFSZ]; boolean controllable_poly = Polymorph_control && !(Stunned || Unaware); if (Unchanging || (u.umonnum == u.ulycn)) return; if (controllable_poly) { /* `+4' => skip "were" prefix to get name of beast */ Sprintf(qbuf, "Do you want to change into %s?", an(mons[u.ulycn].mname + 4)); if (yn(qbuf) == 'n') return; } (void) polymon(u.ulycn); } void you_unwere(purify) boolean purify; { boolean controllable_poly = Polymorph_control && !(Stunned || Unaware); if (purify) { You_feel("purified."); u.ulycn = NON_PM; /* cure lycanthropy */ } if (!Unchanging && is_were(youmonst.data) && (!controllable_poly || yn("Remain in beast form?") == 'n')) rehumanize(); } /*were.c*/ nethack-3.6.0/src/wield.c0000664000076400007660000005570112617413107014206 0ustar paxedpaxed/* NetHack 3.6 wield.c $NHDT-Date: 1446887539 2015/11/07 09:12:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* KMH -- Differences between the three weapon slots. * * The main weapon (uwep): * 1. Is filled by the (w)ield command. * 2. Can be filled with any type of item. * 3. May be carried in one or both hands. * 4. Is used as the melee weapon and as the launcher for * ammunition. * 5. Only conveys intrinsics when it is a weapon, weapon-tool, * or artifact. * 6. Certain cursed items will weld to the hand and cannot be * unwielded or dropped. See erodeable_wep() and will_weld() * below for the list of which items apply. * * The secondary weapon (uswapwep): * 1. Is filled by the e(x)change command, which swaps this slot * with the main weapon. If the "pushweapon" option is set, * the (w)ield command will also store the old weapon in the * secondary slot. * 2. Can be filled with anything that will fit in the main weapon * slot; that is, any type of item. * 3. Is usually NOT considered to be carried in the hands. * That would force too many checks among the main weapon, * second weapon, shield, gloves, and rings; and it would * further be complicated by bimanual weapons. A special * exception is made for two-weapon combat. * 4. Is used as the second weapon for two-weapon combat, and as * a convenience to swap with the main weapon. * 5. Never conveys intrinsics. * 6. Cursed items never weld (see #3 for reasons), but they also * prevent two-weapon combat. * * The quiver (uquiver): * 1. Is filled by the (Q)uiver command. * 2. Can be filled with any type of item. * 3. Is considered to be carried in a special part of the pack. * 4. Is used as the item to throw with the (f)ire command. * This is a convenience over the normal (t)hrow command. * 5. Never conveys intrinsics. * 6. Cursed items never weld; their effect is handled by the normal * throwing code. * 7. The autoquiver option will fill it with something deemed * suitable if (f)ire is used when it's empty. * * No item may be in more than one of these slots. */ STATIC_DCL boolean FDECL(cant_wield_corpse, (struct obj *)); STATIC_DCL int FDECL(ready_weapon, (struct obj *)); /* used by will_weld() */ /* probably should be renamed */ #define erodeable_wep(optr) \ ((optr)->oclass == WEAPON_CLASS || is_weptool(optr) \ || (optr)->otyp == HEAVY_IRON_BALL || (optr)->otyp == IRON_CHAIN) /* used by welded(), and also while wielding */ #define will_weld(optr) \ ((optr)->cursed && (erodeable_wep(optr) || (optr)->otyp == TIN_OPENER)) /*** Functions that place a given item in a slot ***/ /* Proper usage includes: * 1. Initializing the slot during character generation or a * restore. * 2. Setting the slot due to a player's actions. * 3. If one of the objects in the slot are split off, these * functions can be used to put the remainder back in the slot. * 4. Putting an item that was thrown and returned back into the slot. * 5. Emptying the slot, by passing a null object. NEVER pass * zeroobj! * * If the item is being moved from another slot, it is the caller's * responsibility to handle that. It's also the caller's responsibility * to print the appropriate messages. */ void setuwep(obj) register struct obj *obj; { struct obj *olduwep = uwep; if (obj == uwep) return; /* necessary to not set unweapon */ /* This message isn't printed in the caller because it happens * *whenever* Sunsword is unwielded, from whatever cause. */ setworn(obj, W_WEP); if (uwep == obj && artifact_light(olduwep) && olduwep->lamplit) { end_burn(olduwep, FALSE); if (!Blind) pline("%s shining.", Tobjnam(olduwep, "stop")); } /* Note: Explicitly wielding a pick-axe will not give a "bashing" * message. Wielding one via 'a'pplying it will. * 3.2.2: Wielding arbitrary objects will give bashing message too. */ if (obj) { unweapon = (obj->oclass == WEAPON_CLASS) ? is_launcher(obj) || is_ammo(obj) || is_missile(obj) || (is_pole(obj) && !u.usteed) : !is_weptool(obj) && !is_wet_towel(obj); } else unweapon = TRUE; /* for "bare hands" message */ update_inventory(); } STATIC_OVL boolean cant_wield_corpse(obj) struct obj *obj; { char kbuf[BUFSZ]; if (uarmg || obj->otyp != CORPSE || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance) return FALSE; /* Prevent wielding cockatrice when not wearing gloves --KAA */ You("wield %s in your bare %s.", corpse_xname(obj, (const char *) 0, CXN_PFX_THE), makeplural(body_part(HAND))); Sprintf(kbuf, "wielding %s bare-handed", killer_xname(obj)); instapetrify(kbuf); return TRUE; } STATIC_OVL int ready_weapon(wep) struct obj *wep; { /* Separated function so swapping works easily */ int res = 0; if (!wep) { /* No weapon */ if (uwep) { You("are empty %s.", body_part(HANDED)); setuwep((struct obj *) 0); res++; } else You("are already empty %s.", body_part(HANDED)); } else if (wep->otyp == CORPSE && cant_wield_corpse(wep)) { /* hero must have been life-saved to get here; use a turn */ res++; /* corpse won't be wielded */ } else if (uarms && bimanual(wep)) { You("cannot wield a two-handed %s while wearing a shield.", is_sword(wep) ? "sword" : wep->otyp == BATTLE_AXE ? "axe" : "weapon"); } else if (!retouch_object(&wep, FALSE)) { res++; /* takes a turn even though it doesn't get wielded */ } else { /* Weapon WILL be wielded after this point */ res++; if (will_weld(wep)) { const char *tmp = xname(wep), *thestr = "The "; if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp), thestr, 4)) tmp = thestr; else tmp = ""; pline("%s%s %s to your %s!", tmp, aobjnam(wep, "weld"), (wep->quan == 1L) ? "itself" : "themselves", /* a3 */ bimanual(wep) ? (const char *) makeplural(body_part(HAND)) : body_part(HAND)); wep->bknown = TRUE; } else { /* The message must be printed before setuwep (since * you might die and be revived from changing weapons), * and the message must be before the death message and * Lifesaved rewielding. Yet we want the message to * say "weapon in hand", thus this kludge. */ long dummy = wep->owornmask; wep->owornmask |= W_WEP; prinv((char *) 0, wep, 0L); wep->owornmask = dummy; } setuwep(wep); /* KMH -- Talking artifacts are finally implemented */ arti_speak(wep); if (artifact_light(wep) && !wep->lamplit) { begin_burn(wep, FALSE); if (!Blind) pline("%s to shine %s!", Tobjnam(wep, "begin"), arti_light_description(wep)); } #if 0 /* we'll get back to this someday, but it's not balanced yet */ if (Race_if(PM_ELF) && !wep->oartifact && objects[wep->otyp].oc_material == IRON) { /* Elves are averse to wielding cold iron */ You("have an uneasy feeling about wielding cold iron."); change_luck(-1); } #endif if (wep->unpaid) { struct monst *this_shkp; if ((this_shkp = shop_keeper(inside_shop(u.ux, u.uy))) != (struct monst *) 0) { pline("%s says \"You be careful with my %s!\"", shkname(this_shkp), xname(wep)); } } } return res; } void setuqwep(obj) register struct obj *obj; { setworn(obj, W_QUIVER); update_inventory(); } void setuswapwep(obj) register struct obj *obj; { setworn(obj, W_SWAPWEP); update_inventory(); } /*** Commands to change particular slot(s) ***/ static NEARDATA const char wield_objs[] = { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0 }; static NEARDATA const char ready_objs[] = { COIN_CLASS, ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 }; static NEARDATA const char bullets[] = /* (note: different from dothrow.c) */ { COIN_CLASS, ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 }; int dowield() { register struct obj *wep, *oldwep; int result; /* May we attempt this? */ multi = 0; if (cantwield(youmonst.data)) { pline("Don't be ridiculous!"); return 0; } /* Prompt for a new weapon */ if (!(wep = getobj(wield_objs, "wield"))) /* Cancelled */ return 0; else if (wep == uwep) { You("are already wielding that!"); if (is_weptool(wep) || is_wet_towel(wep)) unweapon = FALSE; /* [see setuwep()] */ return 0; } else if (welded(uwep)) { weldmsg(uwep); /* previously interrupted armor removal mustn't be resumed */ reset_remarm(); return 0; } /* Handle no object, or object in other slot */ if (wep == &zeroobj) wep = (struct obj *) 0; else if (wep == uswapwep) return doswapweapon(); else if (wep == uquiver) setuqwep((struct obj *) 0); else if (wep->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE)) { You("cannot wield that!"); return 0; } /* Set your new primary weapon */ oldwep = uwep; result = ready_weapon(wep); if (flags.pushweapon && oldwep && uwep != oldwep) setuswapwep(oldwep); untwoweapon(); return result; } int doswapweapon() { register struct obj *oldwep, *oldswap; int result = 0; /* May we attempt this? */ multi = 0; if (cantwield(youmonst.data)) { pline("Don't be ridiculous!"); return 0; } if (welded(uwep)) { weldmsg(uwep); return 0; } /* Unwield your current secondary weapon */ oldwep = uwep; oldswap = uswapwep; setuswapwep((struct obj *) 0); /* Set your new primary weapon */ result = ready_weapon(oldswap); /* Set your new secondary weapon */ if (uwep == oldwep) /* Wield failed for some reason */ setuswapwep(oldswap); else { setuswapwep(oldwep); if (uswapwep) prinv((char *) 0, uswapwep, 0L); else You("have no secondary weapon readied."); } if (u.twoweap && !can_twoweapon()) untwoweapon(); return result; } int dowieldquiver() { register struct obj *newquiver; const char *quivee_types = (uslinging() || (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ? bullets : ready_objs; /* Since the quiver isn't in your hands, don't check cantwield(), */ /* will_weld(), touch_petrifies(), etc. */ multi = 0; /* Prompt for a new quiver */ if (!(newquiver = getobj(quivee_types, "ready"))) /* Cancelled */ return 0; /* Handle no object, or object in other slot */ /* Any type is okay, since we give no intrinsics anyways */ if (newquiver == &zeroobj) { /* Explicitly nothing */ if (uquiver) { You("now have no ammunition readied."); setuqwep(newquiver = (struct obj *) 0); } else { You("already have no ammunition readied!"); return 0; } } else if (newquiver == uquiver) { pline("That ammunition is already readied!"); return 0; } else if (newquiver == uwep) { /* Prevent accidentally readying the main weapon */ pline("%s already being used as a weapon!", !is_plural(uwep) ? "That is" : "They are"); return 0; } else if (newquiver->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE)) { You("cannot ready that!"); return 0; } else { long dummy; /* Check if it's the secondary weapon */ if (newquiver == uswapwep) { setuswapwep((struct obj *) 0); untwoweapon(); } /* Okay to put in quiver; print it */ dummy = newquiver->owornmask; newquiver->owornmask |= W_QUIVER; prinv((char *) 0, newquiver, 0L); newquiver->owornmask = dummy; } /* Finally, place it in the quiver */ setuqwep(newquiver); /* Take no time since this is a convenience slot */ return 0; } /* used for #rub and for applying pick-axe, whip, grappling hook or polearm */ boolean wield_tool(obj, verb) struct obj *obj; const char *verb; /* "rub",&c */ { const char *what; boolean more_than_1; if (obj == uwep) return TRUE; /* nothing to do if already wielding it */ if (!verb) verb = "wield"; what = xname(obj); more_than_1 = (obj->quan > 1L || strstri(what, "pair of ") != 0 || strstri(what, "s of ") != 0); if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) { You_cant("%s %s while wearing %s.", verb, yname(obj), more_than_1 ? "them" : "it"); return FALSE; } if (welded(uwep)) { if (flags.verbose) { const char *hand = body_part(HAND); if (bimanual(uwep)) hand = makeplural(hand); if (strstri(what, "pair of ") != 0) more_than_1 = FALSE; pline( "Since your weapon is welded to your %s, you cannot %s %s %s.", hand, verb, more_than_1 ? "those" : "that", xname(obj)); } else { You_cant("do that."); } return FALSE; } if (cantwield(youmonst.data)) { You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it"); return FALSE; } /* check shield */ if (uarms && bimanual(obj)) { You("cannot %s a two-handed %s while wearing a shield.", verb, (obj->oclass == WEAPON_CLASS) ? "weapon" : "tool"); return FALSE; } if (uquiver == obj) setuqwep((struct obj *) 0); if (uswapwep == obj) { (void) doswapweapon(); /* doswapweapon might fail */ if (uswapwep == obj) return FALSE; } else { struct obj *oldwep = uwep; You("now wield %s.", doname(obj)); setuwep(obj); if (flags.pushweapon && oldwep && uwep != oldwep) setuswapwep(oldwep); } if (uwep != obj) return FALSE; /* rewielded old object after dying */ /* applying weapon or tool that gets wielded ends two-weapon combat */ if (u.twoweap) untwoweapon(); if (obj->oclass != WEAPON_CLASS) unweapon = TRUE; return TRUE; } int can_twoweapon() { struct obj *otmp; #define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS) if (!could_twoweap(youmonst.data)) { if (Upolyd) You_cant("use two weapons in your current form."); else pline("%s aren't able to use two weapons at once.", makeplural((flags.female && urole.name.f) ? urole.name.f : urole.name.m)); } else if (!uwep || !uswapwep) Your("%s%s%s empty.", uwep ? "left " : uswapwep ? "right " : "", body_part(HAND), (!uwep && !uswapwep) ? "s are" : " is"); else if (NOT_WEAPON(uwep) || NOT_WEAPON(uswapwep)) { otmp = NOT_WEAPON(uwep) ? uwep : uswapwep; pline("%s %s.", Yname2(otmp), is_plural(otmp) ? "aren't weapons" : "isn't a weapon"); } else if (bimanual(uwep) || bimanual(uswapwep)) { otmp = bimanual(uwep) ? uwep : uswapwep; pline("%s isn't one-handed.", Yname2(otmp)); } else if (uarms) You_cant("use two weapons while wearing a shield."); else if (uswapwep->oartifact) pline("%s being held second to another weapon!", Yobjnam2(uswapwep, "resist")); else if (uswapwep->otyp == CORPSE && cant_wield_corpse(uswapwep)) { /* [Note: NOT_WEAPON() check prevents ever getting here...] */ ; /* must be life-saved to reach here; return FALSE */ } else if (Glib || uswapwep->cursed) { if (!Glib) uswapwep->bknown = TRUE; drop_uswapwep(); } else return TRUE; return FALSE; } void drop_uswapwep() { char str[BUFSZ]; struct obj *obj = uswapwep; /* Avoid trashing makeplural's static buffer */ Strcpy(str, makeplural(body_part(HAND))); pline("%s from your %s!", Yobjnam2(obj, "slip"), str); dropx(obj); } int dotwoweapon() { /* You can always toggle it off */ if (u.twoweap) { You("switch to your primary weapon."); u.twoweap = 0; update_inventory(); return 0; } /* May we use two weapons? */ if (can_twoweapon()) { /* Success! */ You("begin two-weapon combat."); u.twoweap = 1; update_inventory(); return (rnd(20) > ACURR(A_DEX)); } return 0; } /*** Functions to empty a given slot ***/ /* These should be used only when the item can't be put back in * the slot by life saving. Proper usage includes: * 1. The item has been eaten, stolen, burned away, or rotted away. * 2. Making an item disappear for a bones pile. */ void uwepgone() { if (uwep) { if (artifact_light(uwep) && uwep->lamplit) { end_burn(uwep, FALSE); if (!Blind) pline("%s shining.", Tobjnam(uwep, "stop")); } setworn((struct obj *) 0, W_WEP); unweapon = TRUE; update_inventory(); } } void uswapwepgone() { if (uswapwep) { setworn((struct obj *) 0, W_SWAPWEP); update_inventory(); } } void uqwepgone() { if (uquiver) { setworn((struct obj *) 0, W_QUIVER); update_inventory(); } } void untwoweapon() { if (u.twoweap) { You("can no longer use two weapons at once."); u.twoweap = FALSE; update_inventory(); } return; } int chwepon(otmp, amount) register struct obj *otmp; register int amount; { const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE); const char *xtime, *wepname = ""; boolean multiple; int otyp = STRANGE_OBJECT; if (!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) { char buf[BUFSZ]; Sprintf(buf, "Your %s %s.", makeplural(body_part(HAND)), (amount >= 0) ? "twitch" : "itch"); strange_feeling(otmp, buf); exercise(A_DEX, (boolean) (amount >= 0)); return 0; } if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp; if (uwep->otyp == WORM_TOOTH && amount >= 0) { multiple = (uwep->quan > 1L); /* order: message, transformation, shop handling */ Your("%s %s much sharper now.", simpleonames(uwep), multiple ? "fuse, and become" : "is"); uwep->otyp = CRYSKNIFE; uwep->oerodeproof = 0; if (multiple) { uwep->quan = 1L; uwep->owt = weight(uwep); } if (uwep->cursed) uncurse(uwep); /* update shop bill to reflect new higher value */ if (uwep->unpaid) alter_cost(uwep, 0L); if (otyp != STRANGE_OBJECT) makeknown(otyp); if (multiple) encumber_msg(); return 1; } else if (uwep->otyp == CRYSKNIFE && amount < 0) { multiple = (uwep->quan > 1L); /* order matters: message, shop handling, transformation */ Your("%s %s much duller now.", simpleonames(uwep), multiple ? "fuse, and become" : "is"); costly_alteration(uwep, COST_DEGRD); /* DECHNT? other? */ uwep->otyp = WORM_TOOTH; uwep->oerodeproof = 0; if (multiple) { uwep->quan = 1L; uwep->owt = weight(uwep); } if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp); if (multiple) encumber_msg(); return 1; } if (has_oname(uwep)) wepname = ONAME(uwep); if (amount < 0 && uwep->oartifact && restrict_name(uwep, wepname)) { if (!Blind) pline("%s %s.", Yobjnam2(uwep, "faintly glow"), color); return 1; } /* there is a (soft) upper and lower limit to uwep->spe */ if (((uwep->spe > 5 && amount >= 0) || (uwep->spe < -5 && amount < 0)) && rn2(3)) { if (!Blind) pline("%s %s for a while and then %s.", Yobjnam2(uwep, "violently glow"), color, otense(uwep, "evaporate")); else pline("%s.", Yobjnam2(uwep, "evaporate")); useupall(uwep); /* let all of them disappear */ return 1; } if (!Blind) { xtime = (amount * amount == 1) ? "moment" : "while"; pline("%s %s for a %s.", Yobjnam2(uwep, amount == 0 ? "violently glow" : "glow"), color, xtime); if (otyp != STRANGE_OBJECT && uwep->known && (amount > 0 || (amount < 0 && otmp->bknown))) makeknown(otyp); } if (amount < 0) costly_alteration(uwep, COST_DECHNT); uwep->spe += amount; if (amount > 0) { if (uwep->cursed) uncurse(uwep); /* update shop bill to reflect new higher price */ if (uwep->unpaid) alter_cost(uwep, 0L); } /* * Enchantment, which normally improves a weapon, has an * addition adverse reaction on Magicbane whose effects are * spe dependent. Give an obscure clue here. */ if (uwep->oartifact == ART_MAGICBANE && uwep->spe >= 0) { Your("right %s %sches!", body_part(HAND), (((amount > 1) && (uwep->spe > 1)) ? "flin" : "it")); } /* an elven magic clue, cookie@keebler */ /* elven weapons vibrate warningly when enchanted beyond a limit */ if ((uwep->spe > 5) && (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7))) pline("%s unexpectedly.", Yobjnam2(uwep, "suddenly vibrate")); return 1; } int welded(obj) register struct obj *obj; { if (obj && obj == uwep && will_weld(obj)) { obj->bknown = TRUE; return 1; } return 0; } void weldmsg(obj) register struct obj *obj; { long savewornmask; savewornmask = obj->owornmask; pline("%s welded to your %s!", Yobjnam2(obj, "are"), bimanual(obj) ? (const char *) makeplural(body_part(HAND)) : body_part(HAND)); obj->owornmask = savewornmask; } /* test whether monster's wielded weapon is stuck to hand/paw/whatever */ boolean mwelded(obj) struct obj *obj; { /* caller is responsible for making sure this is a monster's item */ if (obj && (obj->owornmask & W_WEP) && will_weld(obj)) return TRUE; return FALSE; } /*wield.c*/ nethack-3.6.0/src/windows.c0000664000076400007660000005725412623572456014613 0ustar paxedpaxed/* NetHack 3.6 windows.c $NHDT-Date: 1448013599 2015/11/20 09:59:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.35 $ */ /* Copyright (c) D. Cohrs, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef TTY_GRAPHICS #include "wintty.h" #endif #ifdef X11_GRAPHICS /* Cannot just blindly include winX.h without including all of X11 stuff and must get the order of include files right. Don't bother. */ extern struct window_procs X11_procs; extern void FDECL(win_X11_init, (int)); #endif #ifdef QT_GRAPHICS extern struct window_procs Qt_procs; #endif #ifdef GEM_GRAPHICS #include "wingem.h" #endif #ifdef MAC extern struct window_procs mac_procs; #endif #ifdef BEOS_GRAPHICS extern struct window_procs beos_procs; extern void FDECL(be_win_init, (int)); FAIL /* be_win_init doesn't exist? XXX*/ #endif #ifdef AMIGA_INTUITION extern struct window_procs amii_procs; extern struct window_procs amiv_procs; extern void FDECL(ami_wininit_data, (int)); #endif #ifdef WIN32_GRAPHICS extern struct window_procs win32_procs; #endif #ifdef GNOME_GRAPHICS #include "winGnome.h" extern struct window_procs Gnome_procs; #endif #ifdef MSWIN_GRAPHICS extern struct window_procs mswin_procs; #endif #ifdef WINCHAIN extern struct window_procs chainin_procs; extern void FDECL(chainin_procs_init, (int)); extern void *FDECL(chainin_procs_chain, (int, int, void *, void *, void *)); extern struct chain_procs chainout_procs; extern void FDECL(chainout_procs_init, (int)); extern void *FDECL(chainout_procs_chain, (int, int, void *, void *, void *)); extern struct chain_procs trace_procs; extern void FDECL(trace_procs_init, (int)); extern void *FDECL(trace_procs_chain, (int, int, void *, void *, void *)); #endif STATIC_DCL void FDECL(def_raw_print, (const char *s)); #ifdef HANGUPHANDLING volatile #endif NEARDATA struct window_procs windowprocs; #ifdef WINCHAIN #define CHAINR(x) , x #else #define CHAINR(x) #endif static struct win_choices { struct window_procs *procs; void FDECL((*ini_routine), (int)); /* optional (can be 0) */ #ifdef WINCHAIN void *FDECL((*chain_routine), (int, int, void *, void *, void *)); #endif } winchoices[] = { #ifdef TTY_GRAPHICS { &tty_procs, win_tty_init CHAINR(0) }, #endif #ifdef X11_GRAPHICS { &X11_procs, win_X11_init CHAINR(0) }, #endif #ifdef QT_GRAPHICS { &Qt_procs, 0 CHAINR(0) }, #endif #ifdef GEM_GRAPHICS { &Gem_procs, win_Gem_init CHAINR(0) }, #endif #ifdef MAC { &mac_procs, 0 CHAINR(0) }, #endif #ifdef BEOS_GRAPHICS { &beos_procs, be_win_init CHAINR(0) }, #endif #ifdef AMIGA_INTUITION { &amii_procs, ami_wininit_data CHAINR(0) }, /* Old font version of the game */ { &amiv_procs, ami_wininit_data CHAINR(0) }, /* Tile version of the game */ #endif #ifdef WIN32_GRAPHICS { &win32_procs, 0 CHAINR(0) }, #endif #ifdef GNOME_GRAPHICS { &Gnome_procs, 0 CHAINR(0) }, #endif #ifdef MSWIN_GRAPHICS { &mswin_procs, 0 CHAINR(0) }, #endif #ifdef WINCHAIN { &chainin_procs, chainin_procs_init, chainin_procs_chain }, { (struct window_procs *) &chainout_procs, chainout_procs_init, chainout_procs_chain }, { (struct window_procs *) &trace_procs, trace_procs_init, trace_procs_chain }, #endif { 0, 0 CHAINR(0) } /* must be last */ }; #ifdef WINCHAIN struct winlink { struct winlink *nextlink; struct win_choices *wincp; void *linkdata; }; /* NB: this chain does not contain the terminal real window system pointer */ static struct winlink *chain = 0; static struct winlink * wl_new() { return calloc(1, sizeof(struct winlink)); } static void wl_addhead(struct winlink *wl) { wl->nextlink = chain; chain = wl; } static void wl_addtail(struct winlink *wl) { struct winlink *p = chain; if (!chain) { chain = wl; return; } while (p->nextlink) { p = p->nextlink; } p->nextlink = wl; return; } #endif /* WINCHAIN */ static struct win_choices *last_winchoice = 0; boolean genl_can_suspend_no(VOID_ARGS) { return FALSE; } boolean genl_can_suspend_yes(VOID_ARGS) { return TRUE; } STATIC_OVL void def_raw_print(s) const char *s; { puts(s); } #ifdef WINCHAIN static struct win_choices * win_choices_find(s) const char *s; { register int i; for (i = 0; winchoices[i].procs; i++) { if (!strcmpi(s, winchoices[i].procs->name)) { return &winchoices[i]; } } return (struct win_choices *) 0; } #endif void choose_windows(s) const char *s; { register int i; for (i = 0; winchoices[i].procs; i++) { if ('+' == winchoices[i].procs->name[0]) continue; if ('-' == winchoices[i].procs->name[0]) continue; if (!strcmpi(s, winchoices[i].procs->name)) { windowprocs = *winchoices[i].procs; if (last_winchoice && last_winchoice->ini_routine) (*last_winchoice->ini_routine)(WININIT_UNDO); if (winchoices[i].ini_routine) (*winchoices[i].ini_routine)(WININIT); last_winchoice = &winchoices[i]; return; } } if (!windowprocs.win_raw_print) windowprocs.win_raw_print = def_raw_print; if (!winchoices[0].procs) { raw_printf("No window types?"); exit(EXIT_FAILURE); } if (!winchoices[1].procs) { raw_printf("Window type %s not recognized. The only choice is: %s.", s, winchoices[0].procs->name); } else { raw_printf("Window type %s not recognized. Choices are:", s); for (i = 0; winchoices[i].procs; i++) { if ('+' == winchoices[i].procs->name[0]) continue; if ('-' == winchoices[i].procs->name[0]) continue; raw_printf(" %s", winchoices[i].procs->name); } } if (windowprocs.win_raw_print == def_raw_print) terminate(EXIT_SUCCESS); wait_synch(); } #ifdef WINCHAIN void addto_windowchain(s) const char *s; { register int i; for (i = 0; winchoices[i].procs; i++) { if ('+' != winchoices[i].procs->name[0]) continue; if (!strcmpi(s, winchoices[i].procs->name)) { struct winlink *p = wl_new(); p->wincp = &winchoices[i]; wl_addtail(p); /* NB: The ini_routine() will be called during commit. */ return; } } windowprocs.win_raw_print = def_raw_print; raw_printf("Window processor %s not recognized. Choices are:", s); for (i = 0; winchoices[i].procs; i++) { if ('+' != winchoices[i].procs->name[0]) continue; raw_printf(" %s", winchoices[i].procs->name); } exit(EXIT_FAILURE); } void commit_windowchain() { struct winlink *p; int n; int wincap, wincap2; if (!chain) return; /* Save wincap* from the real window system - we'll restore it below. */ wincap = windowprocs.wincap; wincap2 = windowprocs.wincap2; /* add -chainin at head and -chainout at tail */ p = wl_new(); p->wincp = win_choices_find("-chainin"); if (!p->wincp) { raw_printf("Can't locate processor '-chainin'"); exit(EXIT_FAILURE); } wl_addhead(p); p = wl_new(); p->wincp = win_choices_find("-chainout"); if (!p->wincp) { raw_printf("Can't locate processor '-chainout'"); exit(EXIT_FAILURE); } wl_addtail(p); /* Now alloc() init() similar to Objective-C. */ for (n = 1, p = chain; p; n++, p = p->nextlink) { p->linkdata = (*p->wincp->chain_routine)(WINCHAIN_ALLOC, n, 0, 0, 0); } for (n = 1, p = chain; p; n++, p = p->nextlink) { if (p->nextlink) { (void) (*p->wincp->chain_routine)(WINCHAIN_INIT, n, p->linkdata, p->nextlink->wincp->procs, p->nextlink->linkdata); } else { (void) (*p->wincp->chain_routine)(WINCHAIN_INIT, n, p->linkdata, last_winchoice->procs, 0); } } /* Restore the saved wincap* values. We do it here to give the * ini_routine()s a chance to change or check them. */ chain->wincp->procs->wincap = wincap; chain->wincp->procs->wincap2 = wincap2; /* Call the init procs. Do not re-init the terminal real win. */ p = chain; while (p->nextlink) { if (p->wincp->ini_routine) { (*p->wincp->ini_routine)(WININIT); } p = p->nextlink; } /* Install the chain into window procs very late so ini_routine()s * can raw_print on error. */ windowprocs = *chain->wincp->procs; p = chain; while (p) { struct winlink *np = p->nextlink; free(p); p = np; /* assignment, not proof */ } } #endif /* WINCHAIN */ /* * tty_message_menu() provides a means to get feedback from the * --More-- prompt; other interfaces generally don't need that. */ /*ARGSUSED*/ char genl_message_menu(let, how, mesg) char let UNUSED; int how UNUSED; const char *mesg; { pline("%s", mesg); return 0; } /*ARGSUSED*/ void genl_preference_update(pref) const char *pref UNUSED; { /* window ports are expected to provide their own preference update routine for the preference capabilities that they support. Just return in this genl one. */ return; } char * genl_getmsghistory(init) boolean init UNUSED; { /* window ports can provide their own getmsghistory() routine to preserve message history between games. The routine is called repeatedly from the core save routine, and the window port is expected to successively return each message that it wants saved, starting with the oldest message first, finishing with the most recent. Return null pointer when finished. */ return (char *) 0; } void genl_putmsghistory(msg, is_restoring) const char *msg; boolean is_restoring; { /* window ports can provide their own putmsghistory() routine to load message history from a saved game. The routine is called repeatedly from the core restore routine, starting with the oldest saved message first, and finishing with the latest. The window port routine is expected to load the message recall buffers in such a way that the ordering is preserved. The window port routine should make no assumptions about how many messages are forthcoming, nor should it assume that another message will follow this one, so it should keep all pointers/indexes intact at the end of each call. */ /* this doesn't provide for reloading the message window with the previous session's messages upon restore, but it does put the quest message summary lines there by treating them as ordinary messages */ if (!is_restoring) pline("%s", msg); return; } #ifdef HANGUPHANDLING /* * Dummy windowing scheme used to replace current one with no-ops * in order to avoid all terminal I/O after hangup/disconnect. */ static int NDECL(hup_nhgetch); static char FDECL(hup_yn_function, (const char *, const char *, CHAR_P)); static int FDECL(hup_nh_poskey, (int *, int *, int *)); static void FDECL(hup_getlin, (const char *, char *)); static void FDECL(hup_init_nhwindows, (int *, char **)); static void FDECL(hup_exit_nhwindows, (const char *)); static winid FDECL(hup_create_nhwindow, (int)); static int FDECL(hup_select_menu, (winid, int, MENU_ITEM_P **)); static void FDECL(hup_add_menu, (winid, int, const anything *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); static void FDECL(hup_end_menu, (winid, const char *)); static void FDECL(hup_putstr, (winid, int, const char *)); static void FDECL(hup_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); static void FDECL(hup_outrip, (winid, int, time_t)); static void FDECL(hup_curs, (winid, int, int)); static void FDECL(hup_display_nhwindow, (winid, BOOLEAN_P)); static void FDECL(hup_display_file, (const char *, BOOLEAN_P)); #ifdef CLIPPING static void FDECL(hup_cliparound, (int, int)); #endif #ifdef CHANGE_COLOR static void FDECL(hup_change_color, (int, long, int)); #ifdef MAC static short FDECL(hup_set_font_name, (winid, char *)); #endif static char *NDECL(hup_get_color_string); #endif /* CHANGE_COLOR */ #ifdef STATUS_VIA_WINDOWPORT static void FDECL(hup_status_update, (int, genericptr_t, int, int)); #endif static int NDECL(hup_int_ndecl); static void NDECL(hup_void_ndecl); static void FDECL(hup_void_fdecl_int, (int)); static void FDECL(hup_void_fdecl_winid, (winid)); static void FDECL(hup_void_fdecl_constchar_p, (const char *)); static struct window_procs hup_procs = { "hup", 0L, 0L, hup_init_nhwindows, hup_void_ndecl, /* player_selection */ hup_void_ndecl, /* askname */ hup_void_ndecl, /* get_nh_event */ hup_exit_nhwindows, hup_void_fdecl_constchar_p, /* suspend_nhwindows */ hup_void_ndecl, /* resume_nhwindows */ hup_create_nhwindow, hup_void_fdecl_winid, /* clear_nhwindow */ hup_display_nhwindow, hup_void_fdecl_winid, /* destroy_nhwindow */ hup_curs, hup_putstr, hup_putstr, /* putmixed */ hup_display_file, hup_void_fdecl_winid, /* start_menu */ hup_add_menu, hup_end_menu, hup_select_menu, genl_message_menu, hup_void_ndecl, /* update_inventory */ hup_void_ndecl, /* mark_synch */ hup_void_ndecl, /* wait_synch */ #ifdef CLIPPING hup_cliparound, #endif #ifdef POSITIONBAR (void FDECL((*), (char *))) hup_void_fdecl_constchar_p, /* update_positionbar */ #endif hup_print_glyph, hup_void_fdecl_constchar_p, /* raw_print */ hup_void_fdecl_constchar_p, /* raw_print_bold */ hup_nhgetch, hup_nh_poskey, hup_void_ndecl, /* nhbell */ hup_int_ndecl, /* doprev_message */ hup_yn_function, hup_getlin, hup_int_ndecl, /* get_ext_cmd */ hup_void_fdecl_int, /* number_pad */ hup_void_ndecl, /* delay_output */ #ifdef CHANGE_COLOR hup_change_color, #ifdef MAC hup_void_fdecl_int, /* change_background */ hup_set_font_name, #endif hup_get_color_string, #endif /* CHANGE_COLOR */ hup_void_ndecl, /* start_screen */ hup_void_ndecl, /* end_screen */ hup_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT hup_void_ndecl, /* status_init */ hup_void_ndecl, /* status_finish */ genl_status_enablefield, hup_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif /* STATUS_VIA_WINDOWPORT */ genl_can_suspend_no, }; static void FDECL((*previnterface_exit_nhwindows), (const char *)) = 0; /* hangup has occurred; switch to no-op user interface */ void nhwindows_hangup() { char *FDECL((*previnterface_getmsghistory), (BOOLEAN_P)) = 0; #ifdef ALTMETA /* command processor shouldn't look for 2nd char after seeing ESC */ iflags.altmeta = FALSE; #endif /* don't call exit_nhwindows() directly here; if a hangup occurs while interface code is executing, exit_nhwindows could knock the interface's active data structures out from under itself */ if (iflags.window_inited && windowprocs.win_exit_nhwindows != hup_exit_nhwindows) previnterface_exit_nhwindows = windowprocs.win_exit_nhwindows; /* also, we have to leave the old interface's getmsghistory() in place because it will be called while saving the game */ if (windowprocs.win_getmsghistory != hup_procs.win_getmsghistory) previnterface_getmsghistory = windowprocs.win_getmsghistory; windowprocs = hup_procs; if (previnterface_getmsghistory) windowprocs.win_getmsghistory = previnterface_getmsghistory; } static void hup_exit_nhwindows(lastgasp) const char *lastgasp; { /* core has called exit_nhwindows(); call the previous interface's shutdown routine now; xxx_exit_nhwindows() needs to call other xxx_ routines directly rather than through windowprocs pointers */ if (previnterface_exit_nhwindows) { lastgasp = 0; /* don't want exit routine to attempt extra output */ (*previnterface_exit_nhwindows)(lastgasp); previnterface_exit_nhwindows = 0; } iflags.window_inited = 0; } static int hup_nhgetch(VOID_ARGS) { return '\033'; /* ESC */ } /*ARGSUSED*/ static char hup_yn_function(prompt, resp, deflt) const char *prompt UNUSED, *resp UNUSED; char deflt; { if (!deflt) deflt = '\033'; return deflt; } /*ARGSUSED*/ static int hup_nh_poskey(x, y, mod) int *x UNUSED, *y UNUSED, *mod UNUSED; { return '\033'; } /*ARGSUSED*/ static void hup_getlin(prompt, outbuf) const char *prompt UNUSED; char *outbuf; { Strcpy(outbuf, "\033"); } /*ARGSUSED*/ static void hup_init_nhwindows(argc_p, argv) int *argc_p UNUSED; char **argv UNUSED; { iflags.window_inited = 1; } /*ARGUSED*/ static winid hup_create_nhwindow(type) int type UNUSED; { return WIN_ERR; } /*ARGSUSED*/ static int hup_select_menu(window, how, menu_list) winid window UNUSED; int how UNUSED; struct mi **menu_list UNUSED; { return -1; } /*ARGSUSED*/ static void hup_add_menu(window, glyph, identifier, sel, grpsel, attr, txt, preselected) winid window UNUSED; int glyph UNUSED, attr UNUSED; const anything *identifier UNUSED; char sel UNUSED, grpsel UNUSED; const char *txt UNUSED; boolean preselected UNUSED; { return; } /*ARGSUSED*/ static void hup_end_menu(window, prompt) winid window UNUSED; const char *prompt UNUSED; { return; } /*ARGSUSED*/ static void hup_putstr(window, attr, text) winid window UNUSED; int attr UNUSED; const char *text UNUSED; { return; } /*ARGSUSED*/ static void hup_print_glyph(window, x, y, glyph, bkglyph) winid window UNUSED; xchar x UNUSED, y UNUSED; int glyph UNUSED; int bkglyph UNUSED; { return; } /*ARGSUSED*/ static void hup_outrip(tmpwin, how, when) winid tmpwin UNUSED; int how UNUSED; time_t when UNUSED; { return; } /*ARGSUSED*/ static void hup_curs(window, x, y) winid window UNUSED; int x UNUSED, y UNUSED; { return; } /*ARGSUSED*/ static void hup_display_nhwindow(window, blocking) winid window UNUSED; boolean blocking UNUSED; { return; } /*ARGSUSED*/ static void hup_display_file(fname, complain) const char *fname UNUSED; boolean complain UNUSED; { return; } #ifdef CLIPPING /*ARGSUSED*/ static void hup_cliparound(x, y) int x UNUSED, y UNUSED; { return; } #endif #ifdef CHANGE_COLOR /*ARGSUSED*/ static void hup_change_color(color, rgb, reverse) int color, reverse; long rgb; { return; } #ifdef MAC /*ARGSUSED*/ static short hup_set_font_name(window, fontname) winid window; char *fontname; { return 0; } #endif /* MAC */ static char * hup_get_color_string(VOID_ARGS) { return (char *) 0; } #endif /* CHANGE_COLOR */ #ifdef STATUS_VIA_WINDOWPORT /*ARGSUSED*/ static void hup_status_update(idx, ptr, chg, percent) int idx UNUSED, chg UNUSED, percent UNUSED; genericptr_t ptr UNUSED; { return; } #endif /* STATUS_VIA_WINDOWPORT */ /* * Non-specific stubs. */ static int hup_int_ndecl(VOID_ARGS) { return -1; } static void hup_void_ndecl(VOID_ARGS) { return; } /*ARGUSED*/ static void hup_void_fdecl_int(arg) int arg UNUSED; { return; } /*ARGUSED*/ static void hup_void_fdecl_winid(window) winid window UNUSED; { return; } /*ARGUSED*/ static void hup_void_fdecl_constchar_p(string) const char *string UNUSED; { return; } #endif /* HANGUPHANDLING */ #ifdef STATUS_VIA_WINDOWPORT /****************************************************************************/ /* genl backward compat stuff */ /****************************************************************************/ const char *status_fieldnm[MAXBLSTATS]; const char *status_fieldfmt[MAXBLSTATS]; char *status_vals[MAXBLSTATS]; boolean status_activefields[MAXBLSTATS]; NEARDATA winid WIN_STATUS; void genl_status_init() { int i; for (i = 0; i < MAXBLSTATS; ++i) { status_vals[i] = (char *) alloc(MAXCO); *status_vals[i] = '\0'; status_activefields[i] = FALSE; status_fieldfmt[i] = (const char *) 0; } /* Use a window for the genl version; backward port compatibility */ WIN_STATUS = create_nhwindow(NHW_STATUS); display_nhwindow(WIN_STATUS, FALSE); } void genl_status_finish() { /* tear down routine */ int i; /* free alloc'd memory here */ for (i = 0; i < MAXBLSTATS; ++i) { if (status_vals[i]) free((genericptr_t) status_vals[i]); status_vals[i] = (char *) 0; } } void genl_status_enablefield(fieldidx, nm, fmt, enable) int fieldidx; const char *nm; const char *fmt; boolean enable; { status_fieldfmt[fieldidx] = fmt; status_fieldnm[fieldidx] = nm; status_activefields[fieldidx] = enable; } void genl_status_update(idx, ptr, chg, percent) int idx, chg, percent; genericptr_t ptr; { char newbot1[MAXCO], newbot2[MAXCO]; long cond, *condptr = (long *) ptr; register int i; char *text = (char *) ptr; enum statusfields fieldorder[2][15] = { { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH }, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; if (idx != BL_FLUSH) { if (!status_activefields[idx]) return; switch (idx) { case BL_CONDITION: cond = *condptr; *status_vals[idx] = '\0'; if (cond & BL_MASK_BLIND) Strcat(status_vals[idx], " Blind"); if (cond & BL_MASK_CONF) Strcat(status_vals[idx], " Conf"); if (cond & BL_MASK_FOODPOIS) Strcat(status_vals[idx], " FoodPois"); if (cond & BL_MASK_ILL) Strcat(status_vals[idx], " Ill"); if (cond & BL_MASK_STUNNED) Strcat(status_vals[idx], " Stun"); if (cond & BL_MASK_HALLU) Strcat(status_vals[idx], " Hallu"); if (cond & BL_MASK_SLIMED) Strcat(status_vals[idx], " Slime"); break; default: Sprintf(status_vals[idx], status_fieldfmt[idx] ? status_fieldfmt[idx] : "%s", text); break; } } /* This genl version updates everything on the display, everytime */ newbot1[0] = '\0'; for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) { int idx1 = fieldorder[0][i]; if (status_activefields[idx1]) Strcat(newbot1, status_vals[idx1]); } newbot2[0] = '\0'; for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) { int idx2 = fieldorder[1][i]; if (status_activefields[idx2]) Strcat(newbot2, status_vals[idx2]); } curs(WIN_STATUS, 1, 0); putstr(WIN_STATUS, 0, newbot1); curs(WIN_STATUS, 1, 1); putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */ } #ifdef STATUS_HILITES void genl_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over) int fldidx, thresholdtype; int behavior, under, over; anything threshold; { return; } #endif /* STATUS_HILITES */ #endif /* STATUS_VIA_WINDOWPORT */ /*windows.c*/ nethack-3.6.0/src/wizard.c0000664000076400007660000005075612614367060014412 0ustar paxedpaxed/* NetHack 3.6 wizard.c $NHDT-Date: 1446078768 2015/10/29 00:32:48 $ $NHDT-Branch: master $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */ /* - heavily modified to give the wiz balls. (genat!mike) */ /* - dewimped and given some maledictions. -3. */ /* - generalized for 3.1 (mike@bullns.on01.bull.ca) */ #include "hack.h" #include "qtext.h" extern const int monstr[]; STATIC_DCL short FDECL(which_arti, (int)); STATIC_DCL boolean FDECL(mon_has_arti, (struct monst *, SHORT_P)); STATIC_DCL struct monst *FDECL(other_mon_has_arti, (struct monst *, SHORT_P)); STATIC_DCL struct obj *FDECL(on_ground, (SHORT_P)); STATIC_DCL boolean FDECL(you_have, (int)); STATIC_DCL unsigned long FDECL(target_on, (int, struct monst *)); STATIC_DCL unsigned long FDECL(strategy, (struct monst *)); static NEARDATA const int nasties[] = { PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON, PM_BLACK_DRAGON, PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM, PM_ROCK_TROLL, PM_XAN, PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD, PM_XORN, PM_ZRUTY, PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON, PM_LEOCROTTA, PM_BALUCHITHERIUM, PM_CARNIVOROUS_APE, PM_FIRE_GIANT, PM_COUATL, PM_CAPTAIN, PM_WINGED_GARGOYLE, PM_MASTER_MIND_FLAYER, PM_FIRE_ELEMENTAL, PM_JABBERWOCK, PM_ARCH_LICH, PM_OGRE_KING, PM_OLOG_HAI, PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME, PM_DISENCHANTER }; static NEARDATA const unsigned wizapp[] = { PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE, PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK, PM_XORN, PM_XAN, PM_COCKATRICE, PM_FLOATING_EYE, PM_GUARDIAN_NAGA, PM_TRAPPER }; /* If you've found the Amulet, make the Wizard appear after some time */ /* Also, give hints about portal locations, if amulet is worn/wielded -dlc */ void amulet() { struct monst *mtmp; struct trap *ttmp; struct obj *amu; #if 0 /* caller takes care of this check */ if (!u.uhave.amulet) return; #endif if ((((amu = uamul) != 0 && amu->otyp == AMULET_OF_YENDOR) || ((amu = uwep) != 0 && amu->otyp == AMULET_OF_YENDOR)) && !rn2(15)) { for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { if (ttmp->ttyp == MAGIC_PORTAL) { int du = distu(ttmp->tx, ttmp->ty); if (du <= 9) pline("%s hot!", Tobjnam(amu, "feel")); else if (du <= 64) pline("%s very warm.", Tobjnam(amu, "feel")); else if (du <= 144) pline("%s warm.", Tobjnam(amu, "feel")); /* else, the amulet feels normal */ break; } } } if (!context.no_of_wizards) return; /* find Wizard, and wake him if necessary */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->iswiz && mtmp->msleeping && !rn2(40)) { mtmp->msleeping = 0; if (distu(mtmp->mx, mtmp->my) > 2) You( "get the creepy feeling that somebody noticed your taking the Amulet."); return; } } } int mon_has_amulet(mtmp) register struct monst *mtmp; { register struct obj *otmp; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->otyp == AMULET_OF_YENDOR) return 1; return 0; } int mon_has_special(mtmp) register struct monst *mtmp; { register struct obj *otmp; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->otyp == AMULET_OF_YENDOR || is_quest_artifact(otmp) || otmp->otyp == BELL_OF_OPENING || otmp->otyp == CANDELABRUM_OF_INVOCATION || otmp->otyp == SPE_BOOK_OF_THE_DEAD) return 1; return 0; } /* * New for 3.1 Strategy / Tactics for the wiz, as well as other * monsters that are "after" something (defined via mflag3). * * The strategy section decides *what* the monster is going * to attempt, the tactics section implements the decision. */ #define STRAT(w, x, y, typ) \ ((unsigned long) (w) | ((unsigned long) (x) << 16) \ | ((unsigned long) (y) << 8) | (unsigned long) (typ)) #define M_Wants(mask) (mtmp->data->mflags3 & (mask)) STATIC_OVL short which_arti(mask) register int mask; { switch (mask) { case M3_WANTSAMUL: return AMULET_OF_YENDOR; case M3_WANTSBELL: return BELL_OF_OPENING; case M3_WANTSCAND: return CANDELABRUM_OF_INVOCATION; case M3_WANTSBOOK: return SPE_BOOK_OF_THE_DEAD; default: break; /* 0 signifies quest artifact */ } return 0; } /* * If "otyp" is zero, it triggers a check for the quest_artifact, * since bell, book, candle, and amulet are all objects, not really * artifacts right now. [MRS] */ STATIC_OVL boolean mon_has_arti(mtmp, otyp) register struct monst *mtmp; register short otyp; { register struct obj *otmp; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { if (otyp) { if (otmp->otyp == otyp) return 1; } else if (is_quest_artifact(otmp)) return 1; } return 0; } STATIC_OVL struct monst * other_mon_has_arti(mtmp, otyp) register struct monst *mtmp; register short otyp; { register struct monst *mtmp2; for (mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) /* no need for !DEADMONSTER check here since they have no inventory */ if (mtmp2 != mtmp) if (mon_has_arti(mtmp2, otyp)) return mtmp2; return (struct monst *) 0; } STATIC_OVL struct obj * on_ground(otyp) register short otyp; { register struct obj *otmp; for (otmp = fobj; otmp; otmp = otmp->nobj) if (otyp) { if (otmp->otyp == otyp) return otmp; } else if (is_quest_artifact(otmp)) return otmp; return (struct obj *) 0; } STATIC_OVL boolean you_have(mask) register int mask; { switch (mask) { case M3_WANTSAMUL: return (boolean) u.uhave.amulet; case M3_WANTSBELL: return (boolean) u.uhave.bell; case M3_WANTSCAND: return (boolean) u.uhave.menorah; case M3_WANTSBOOK: return (boolean) u.uhave.book; case M3_WANTSARTI: return (boolean) u.uhave.questart; default: break; } return 0; } STATIC_OVL unsigned long target_on(mask, mtmp) register int mask; register struct monst *mtmp; { register short otyp; register struct obj *otmp; register struct monst *mtmp2; if (!M_Wants(mask)) return (unsigned long) STRAT_NONE; otyp = which_arti(mask); if (!mon_has_arti(mtmp, otyp)) { if (you_have(mask)) return STRAT(STRAT_PLAYER, u.ux, u.uy, mask); else if ((otmp = on_ground(otyp))) return STRAT(STRAT_GROUND, otmp->ox, otmp->oy, mask); else if ((mtmp2 = other_mon_has_arti(mtmp, otyp)) != 0 /* when seeking the Amulet, avoid targetting the Wizard or temple priests (to protect Moloch's high priest) */ && (otyp != AMULET_OF_YENDOR || (!mtmp2->iswiz && !inhistemple(mtmp2)))) return STRAT(STRAT_MONSTR, mtmp2->mx, mtmp2->my, mask); } return (unsigned long) STRAT_NONE; } STATIC_OVL unsigned long strategy(mtmp) register struct monst *mtmp; { unsigned long strat, dstrat; if (!is_covetous(mtmp->data) /* perhaps a shopkeeper has been polymorphed into a master lich; we don't want it teleporting to the stairs to heal because that will leave its shop untended */ || (mtmp->isshk && inhishop(mtmp)) /* likewise for temple priests */ || (mtmp->ispriest && inhistemple(mtmp))) return (unsigned long) STRAT_NONE; switch ((mtmp->mhp * 3) / mtmp->mhpmax) { /* 0-3 */ default: case 0: /* panic time - mtmp is almost snuffed */ return (unsigned long) STRAT_HEAL; case 1: /* the wiz is less cautious */ if (mtmp->data != &mons[PM_WIZARD_OF_YENDOR]) return (unsigned long) STRAT_HEAL; /* else fall through */ case 2: dstrat = STRAT_HEAL; break; case 3: dstrat = STRAT_NONE; break; } if (context.made_amulet) if ((strat = target_on(M3_WANTSAMUL, mtmp)) != STRAT_NONE) return strat; if (u.uevent.invoked) { /* priorities change once gate opened */ if ((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE) return strat; if ((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE) return strat; if ((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE) return strat; if ((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE) return strat; } else { if ((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE) return strat; if ((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE) return strat; if ((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE) return strat; if ((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE) return strat; } return dstrat; } int tactics(mtmp) register struct monst *mtmp; { unsigned long strat = strategy(mtmp); mtmp->mstrategy = (mtmp->mstrategy & (STRAT_WAITMASK | STRAT_APPEARMSG)) | strat; switch (strat) { case STRAT_HEAL: /* hide and recover */ /* if wounded, hole up on or near the stairs (to block them) */ /* unless, of course, there are no stairs (e.g. endlevel) */ mtmp->mavenge = 1; /* covetous monsters attack while fleeing */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) || (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) { if (!rn2(3 + mtmp->mhp / 10)) (void) rloc(mtmp, TRUE); } else if (xupstair && (mtmp->mx != xupstair || mtmp->my != yupstair)) { (void) mnearto(mtmp, xupstair, yupstair, TRUE); } /* if you're not around, cast healing spells */ if (distu(mtmp->mx, mtmp->my) > (BOLT_LIM * BOLT_LIM)) if (mtmp->mhp <= mtmp->mhpmax - 8) { mtmp->mhp += rnd(8); return 1; } /* fall through :-) */ case STRAT_NONE: /* harass */ if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp); return 0; default: /* kill, maim, pillage! */ { long where = (strat & STRAT_STRATMASK); xchar tx = STRAT_GOALX(strat), ty = STRAT_GOALY(strat); int targ = (int) (strat & STRAT_GOAL); struct obj *otmp; if (!targ) { /* simply wants you to close */ return 0; } if ((u.ux == tx && u.uy == ty) || where == STRAT_PLAYER) { /* player is standing on it (or has it) */ mnexto(mtmp); return 0; } if (where == STRAT_GROUND) { if (!MON_AT(tx, ty) || (mtmp->mx == tx && mtmp->my == ty)) { /* teleport to it and pick it up */ rloc_to(mtmp, tx, ty); /* clean old pos */ if ((otmp = on_ground(which_arti(targ))) != 0) { if (cansee(mtmp->mx, mtmp->my)) pline("%s picks up %s.", Monnam(mtmp), (distu(mtmp->mx, mtmp->my) <= 5) ? doname(otmp) : distant_name(otmp, doname)); obj_extract_self(otmp); (void) mpickobj(mtmp, otmp); return 1; } else return 0; } else { /* a monster is standing on it - cause some trouble */ if (!rn2(5)) mnexto(mtmp); return 0; } } else { /* a monster has it - 'port beside it. */ (void) mnearto(mtmp, tx, ty, FALSE); return 0; } } } /*NOTREACHED*/ return 0; } void aggravate() { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mtmp->mstrategy &= ~(STRAT_WAITFORU | STRAT_APPEARMSG); mtmp->msleeping = 0; if (!mtmp->mcanmove && !rn2(5)) { mtmp->mfrozen = 0; mtmp->mcanmove = 1; } } } void clonewiz() { register struct monst *mtmp2; if ((mtmp2 = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, NO_MM_FLAGS)) != 0) { mtmp2->msleeping = mtmp2->mtame = mtmp2->mpeaceful = 0; if (!u.uhave.amulet && rn2(2)) { /* give clone a fake */ (void) add_to_minv(mtmp2, mksobj(FAKE_AMULET_OF_YENDOR, TRUE, FALSE)); } mtmp2->m_ap_type = M_AP_MONSTER; mtmp2->mappearance = wizapp[rn2(SIZE(wizapp))]; newsym(mtmp2->mx, mtmp2->my); } } /* also used by newcham() */ int pick_nasty() { int res = nasties[rn2(SIZE(nasties))]; /* To do? Possibly should filter for appropriate forms when * in the elemental planes or surrounded by water or lava. * * We want monsters represented by uppercase on rogue level, * but we don't try very hard. */ if (Is_rogue_level(&u.uz) && !('A' <= mons[res].mlet && mons[res].mlet <= 'Z')) res = nasties[rn2(SIZE(nasties))]; return res; } /* create some nasty monsters, aligned or neutral with the caster */ /* a null caster defaults to a chaotic caster (e.g. the wizard) */ int nasty(mcast) struct monst *mcast; { register struct monst *mtmp; register int i, j, tmp; int castalign = (mcast ? sgn(mcast->data->maligntyp) : -1); coord bypos; int count, census; /* some candidates may be created in groups, so simple count of non-null makemon() return is inadequate */ census = monster_census(FALSE); if (!rn2(10) && Inhell) { count = msummon((struct monst *) 0); /* summons like WoY */ } else { count = 0; tmp = (u.ulevel > 3) ? u.ulevel / 3 : 1; /* just in case -- rph */ /* if we don't have a casting monster, the nasties appear around you */ bypos.x = u.ux; bypos.y = u.uy; for (i = rnd(tmp); i > 0; --i) for (j = 0; j < 20; j++) { int makeindex; /* Don't create more spellcasters of the monsters' level or * higher--avoids chain summoners filling up the level. */ do { makeindex = pick_nasty(); } while (mcast && attacktype(&mons[makeindex], AT_MAGC) && monstr[makeindex] >= monstr[mcast->mnum]); /* do this after picking the monster to place */ if (mcast && !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex])) continue; if ((mtmp = makemon(&mons[makeindex], bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0; set_malign(mtmp); } else /* GENOD? */ mtmp = makemon((struct permonst *) 0, bypos.x, bypos.y, NO_MM_FLAGS); if (mtmp) { count++; if (mtmp->data->maligntyp == 0 || sgn(mtmp->data->maligntyp) == castalign) break; } } } if (count) count = monster_census(FALSE) - census; return count; } /* Let's resurrect the wizard, for some unexpected fun. */ void resurrect() { struct monst *mtmp, **mmtmp; long elapsed; const char *verb; if (!context.no_of_wizards) { /* make a new Wizard */ verb = "kill"; mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, MM_NOWAIT); /* affects experience; he's not coming back from a corpse but is subject to repeated killing like a revived corpse */ if (mtmp) mtmp->mrevived = 1; } else { /* look for a migrating Wizard */ verb = "elude"; mmtmp = &migrating_mons; while ((mtmp = *mmtmp) != 0) { if (mtmp->iswiz /* if he has the Amulet, he won't bring it to you */ && !mon_has_amulet(mtmp) && (elapsed = monstermoves - mtmp->mlstmv) > 0L) { mon_catchup_elapsed_time(mtmp, elapsed); if (elapsed >= LARGEST_INT) elapsed = LARGEST_INT - 1; elapsed /= 50L; if (mtmp->msleeping && rn2((int) elapsed + 1)) mtmp->msleeping = 0; if (mtmp->mfrozen == 1) /* would unfreeze on next move */ mtmp->mfrozen = 0, mtmp->mcanmove = 1; if (mtmp->mcanmove && !mtmp->msleeping) { *mmtmp = mtmp->nmon; mon_arrive(mtmp, TRUE); /* note: there might be a second Wizard; if so, he'll have to wait til the next resurrection */ break; } } mmtmp = &mtmp->nmon; } } if (mtmp) { mtmp->mtame = mtmp->mpeaceful = 0; /* paranoia */ set_malign(mtmp); if (!Deaf) { pline("A voice booms out..."); verbalize("So thou thought thou couldst %s me, fool.", verb); } } } /* Here, we make trouble for the poor shmuck who actually managed to do in the Wizard. */ void intervene() { int which = Is_astralevel(&u.uz) ? rnd(4) : rn2(6); /* cases 0 and 5 don't apply on the Astral level */ switch (which) { case 0: case 1: You_feel("vaguely nervous."); break; case 2: if (!Blind) You("notice a %s glow surrounding you.", hcolor(NH_BLACK)); rndcurse(); break; case 3: aggravate(); break; case 4: (void) nasty((struct monst *) 0); break; case 5: resurrect(); break; } } void wizdead() { context.no_of_wizards--; if (!u.uevent.udemigod) { u.uevent.udemigod = TRUE; u.udg_cnt = rn1(250, 50); } } const char *const random_insult[] = { "antic", "blackguard", "caitiff", "chucklehead", "coistrel", "craven", "cretin", "cur", "dastard", "demon fodder", "dimwit", "dolt", "fool", "footpad", "imbecile", "knave", "maledict", "miscreant", "niddering", "poltroon", "rattlepate", "reprobate", "scapegrace", "varlet", "villein", /* (sic.) */ "wittol", "worm", "wretch", }; const char *const random_malediction[] = { "Hell shall soon claim thy remains,", "I chortle at thee, thou pathetic", "Prepare to die, thou", "Resistance is useless,", "Surrender or die, thou", "There shall be no mercy, thou", "Thou shalt repent of thy cunning,", "Thou art as a flea to me,", "Thou art doomed,", "Thy fate is sealed,", "Verily, thou shalt be one dead" }; /* Insult or intimidate the player */ void cuss(mtmp) register struct monst *mtmp; { if (Deaf) return; if (mtmp->iswiz) { if (!rn2(5)) /* typical bad guy action */ pline("%s laughs fiendishly.", Monnam(mtmp)); else if (u.uhave.amulet && !rn2(SIZE(random_insult))) verbalize("Relinquish the amulet, %s!", random_insult[rn2(SIZE(random_insult))]); else if (u.uhp < 5 && !rn2(2)) /* Panic */ verbalize(rn2(2) ? "Even now thy life force ebbs, %s!" : "Savor thy breath, %s, it be thy last!", random_insult[rn2(SIZE(random_insult))]); else if (mtmp->mhp < 5 && !rn2(2)) /* Parthian shot */ verbalize(rn2(2) ? "I shall return." : "I'll be back."); else verbalize("%s %s!", random_malediction[rn2(SIZE(random_malediction))], random_insult[rn2(SIZE(random_insult))]); } else if (is_lminion(mtmp)) { com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) + QT_ANGELIC); } else { if (!rn2(5)) pline("%s casts aspersions on your ancestry.", Monnam(mtmp)); else com_pager(rn2(QTN_DEMONIC) + QT_DEMONIC); } } /*wizard.c*/ nethack-3.6.0/src/worm.c0000664000076400007660000005500512617413107014063 0ustar paxedpaxed/* NetHack 3.6 worm.c $NHDT-Date: 1446887540 2015/11/07 09:12:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #define newseg() (struct wseg *) alloc(sizeof (struct wseg)) #define dealloc_seg(wseg) free((genericptr_t) (wseg)) /* worm segment structure */ struct wseg { struct wseg *nseg; xchar wx, wy; /* the segment's position */ }; STATIC_DCL void FDECL(toss_wsegs, (struct wseg *, BOOLEAN_P)); STATIC_DCL void FDECL(shrink_worm, (int)); STATIC_DCL void FDECL(random_dir, (XCHAR_P, XCHAR_P, xchar *, xchar *)); STATIC_DCL struct wseg *FDECL(create_worm_tail, (int)); /* Description of long worm implementation. * * Each monst struct of the head of a tailed worm has a wormno set to * 1 <= wormno < MAX_NUM_WORMS * If wormno == 0 this does not mean that the monster is not a worm, * it just means that the monster does not have a long worm tail. * * The actual segments of a worm are not full blown monst structs. * They are small wseg structs, and their position in the levels.monsters[][] * array is held by the monst struct of the head of the worm. This makes * things like probing and hit point bookkeeping much easier. * * The segments of the long worms on a level are kept as an array of * singly threaded linked lists. The wormno variable is used as an index * for these segment arrays. * * wtails: The first (starting struct) of a linked list. This points * to the tail (last) segment of the worm. * * wheads: The last (end) of a linked list of segments. This points to * the segment that is at the same position as the real monster * (the head). Note that the segment that wheads[wormno] points * to, is not displayed. It is simply there to keep track of * where the head came from, so that worm movement and display * are simplified later. * Keeping the head segment of the worm at the end of the list * of tail segments is an endless source of confusion, but it is * necessary. * From now on, we will use "start" and "end" to refer to the * linked list and "head" and "tail" to refer to the worm. * * One final worm array is: * * wgrowtime: This tells us when to add another segment to the worm. * * When a worm is moved, we add a new segment at the head, and delete the * segment at the tail (unless we want it to grow). This new head segment is * located in the same square as the actual head of the worm. If we want * to grow the worm, we don't delete the tail segment, and we give the worm * extra hit points, which possibly go into its maximum. * * Non-moving worms (worm_nomove) are assumed to be surrounded by their own * tail, and, thus, shrink instead of grow (as their tails keep going while * their heads are stopped short). In this case, we delete the last tail * segment, and remove hit points from the worm. */ struct wseg *wheads[MAX_NUM_WORMS] = DUMMY, *wtails[MAX_NUM_WORMS] = DUMMY; long wgrowtime[MAX_NUM_WORMS] = DUMMY; /* * get_wormno() * * Find an unused worm tail slot and return the index. A zero means that * there are no slots available. This means that the worm head can exist, * it just cannot ever grow a tail. * * It, also, means that there is an optimisation to made. The [0] positions * of the arrays are never used. Meaning, we really *could* have one more * tailed worm on the level, or use a smaller array (using wormno - 1). * * Implementation is left to the interested hacker. */ int get_wormno() { register int new_wormno = 1; while (new_wormno < MAX_NUM_WORMS) { if (!wheads[new_wormno]) return new_wormno; /* found an empty wtails[] slot at new_wormno */ new_wormno++; } return 0; /* level infested with worms */ } /* * initworm() * * Use if (mon->wormno = get_wormno()) before calling this function! * * Initialize the worm entry. This will set up the worm grow time, and * create and initialize the dummy segment for wheads[] and wtails[]. * * If the worm has no tail (ie get_wormno() fails) then this function need * not be called. */ void initworm(worm, wseg_count) struct monst *worm; int wseg_count; { register struct wseg *seg, *new_tail = create_worm_tail(wseg_count); register int wnum = worm->wormno; /* if (!wnum) return; bullet proofing */ if (new_tail) { wtails[wnum] = new_tail; for (seg = new_tail; seg->nseg; seg = seg->nseg) ; wheads[wnum] = seg; } else { wtails[wnum] = wheads[wnum] = seg = newseg(); seg->nseg = (struct wseg *) 0; seg->wx = worm->mx; seg->wy = worm->my; } wgrowtime[wnum] = 0L; } /* * toss_wsegs() * * Get rid of all worm segments on and following the given pointer curr. * The display may or may not need to be updated as we free the segments. */ STATIC_OVL void toss_wsegs(curr, display_update) register struct wseg *curr; register boolean display_update; { register struct wseg *seg; while (curr) { seg = curr->nseg; /* remove from level.monsters[][] */ /* need to check curr->wx for genocided while migrating_mon */ if (curr->wx) { remove_monster(curr->wx, curr->wy); /* update screen before deallocation */ if (display_update) newsym(curr->wx, curr->wy); } /* free memory used by the segment */ dealloc_seg(curr); curr = seg; } } /* * shrink_worm() * * Remove the tail segment of the worm (the starting segment of the list). */ STATIC_OVL void shrink_worm(wnum) int wnum; /* worm number */ { struct wseg *seg; if (wtails[wnum] == wheads[wnum]) return; /* no tail */ seg = wtails[wnum]; wtails[wnum] = seg->nseg; seg->nseg = (struct wseg *) 0; toss_wsegs(seg, TRUE); } /* * worm_move() * * Check for mon->wormno before calling this function! * * Move the worm. Maybe grow. */ void worm_move(worm) struct monst *worm; { register struct wseg *seg, *new_seg; /* new segment */ register int wnum = worm->wormno; /* worm number */ /* if (!wnum) return; bullet proofing */ /* * Place a segment at the old worm head. The head has already moved. */ seg = wheads[wnum]; place_worm_seg(worm, seg->wx, seg->wy); newsym(seg->wx, seg->wy); /* display the new segment */ /* * Create a new dummy segment head and place it at the end of the list. */ new_seg = newseg(); new_seg->wx = worm->mx; new_seg->wy = worm->my; new_seg->nseg = (struct wseg *) 0; seg->nseg = new_seg; /* attach it to the end of the list */ wheads[wnum] = new_seg; /* move the end pointer */ if (wgrowtime[wnum] <= moves) { if (!wgrowtime[wnum]) wgrowtime[wnum] = moves + rnd(5); else wgrowtime[wnum] += rn1(15, 3); worm->mhp += 3; if (worm->mhp > MHPMAX) worm->mhp = MHPMAX; if (worm->mhp > worm->mhpmax) worm->mhpmax = worm->mhp; } else /* The worm doesn't grow, so the last segment goes away. */ shrink_worm(wnum); } /* * worm_nomove() * * Check for mon->wormno before calling this function! * * The worm don't move so it should shrink. */ void worm_nomove(worm) register struct monst *worm; { shrink_worm((int) worm->wormno); /* shrink */ if (worm->mhp > 3) worm->mhp -= 3; /* mhpmax not changed ! */ else worm->mhp = 1; } /* * wormgone() * * Check for mon->wormno before calling this function! * * Kill a worm tail. */ void wormgone(worm) register struct monst *worm; { register int wnum = worm->wormno; /* if (!wnum) return; bullet proofing */ worm->wormno = 0; /* This will also remove the real monster (ie 'w') from the its * position in level.monsters[][]. */ toss_wsegs(wtails[wnum], TRUE); wheads[wnum] = wtails[wnum] = (struct wseg *) 0; } /* * wormhitu() * * Check for mon->wormno before calling this function! * * If the hero is near any part of the worm, the worm will try to attack. */ void wormhitu(worm) register struct monst *worm; { register int wnum = worm->wormno; register struct wseg *seg; /* if (!wnum) return; bullet proofing */ /* This does not work right now because mattacku() thinks that the head * is * out of range of the player. We might try to kludge, and bring the * head * within range for a tiny moment, but this needs a bit more looking at * before we decide to do this. */ for (seg = wtails[wnum]; seg; seg = seg->nseg) if (distu(seg->wx, seg->wy) < 3) (void) mattacku(worm); } /* cutworm() * * Check for mon->wormno before calling this function! * * When hitting a worm (worm) at position x, y, with a weapon (weap), * there is a chance that the worm will be cut in half, and a chance * that both halves will survive. */ void cutworm(worm, x, y, weap) struct monst *worm; xchar x, y; struct obj *weap; { register struct wseg *curr, *new_tail; register struct monst *new_worm; int wnum = worm->wormno; int cut_chance, new_wnum; if (!wnum) return; /* bullet proofing */ if (x == worm->mx && y == worm->my) return; /* hit on head */ /* cutting goes best with a bladed weapon */ cut_chance = rnd(20); /* Normally 1-16 does not cut */ /* Normally 17-20 does */ if (weap && is_blade(weap)) /* With a blade 1- 6 does not cut */ cut_chance += 10; /* 7-20 does */ if (cut_chance < 17) return; /* not good enough */ /* Find the segment that was attacked. */ curr = wtails[wnum]; while ((curr->wx != x) || (curr->wy != y)) { curr = curr->nseg; if (!curr) { impossible("cutworm: no segment at (%d,%d)", (int) x, (int) y); return; } } /* If this is the tail segment, then the worm just loses it. */ if (curr == wtails[wnum]) { shrink_worm(wnum); return; } /* * Split the worm. The tail for the new worm is the old worm's tail. * The tail for the old worm is the segment that follows "curr", * and "curr" becomes the dummy segment under the new head. */ new_tail = wtails[wnum]; wtails[wnum] = curr->nseg; curr->nseg = (struct wseg *) 0; /* split the worm */ /* * At this point, the old worm is correct. Any new worm will have * it's head at "curr" and its tail at "new_tail". The old worm * must be at least level 3 in order to produce a new worm. */ new_worm = 0; new_wnum = (worm->m_lev >= 3 && !rn2(3)) ? get_wormno() : 0; if (new_wnum) { remove_monster(x, y); /* clone_mon puts new head here */ /* clone_mon() will fail if enough long worms have been created to have them be marked as extinct or if the hit that cut the current one has dropped it down to 1 HP */ new_worm = clone_mon(worm, x, y); } /* Sometimes the tail end dies. */ if (!new_worm) { if (context.mon_moving) { if (canspotmon(worm)) pline("Part of %s tail has been cut off.", s_suffix(mon_nam(worm))); } else You("cut part of the tail off of %s.", mon_nam(worm)); toss_wsegs(new_tail, TRUE); if (worm->mhp > 1) worm->mhp /= 2; return; } new_worm->wormno = new_wnum; /* affix new worm number */ new_worm->mcloned = 0; /* treat second worm as a normal monster */ /* Devalue the monster level of both halves of the worm. Note: m_lev is always at least 3 in order to get this far. */ worm->m_lev = max((unsigned) worm->m_lev - 2, 3); new_worm->m_lev = worm->m_lev; /* Calculate the lower-level mhp; use d8 for long worms. Can't use newmonhp() here because it would reset m_lev. */ new_worm->mhpmax = new_worm->mhp = d((int) new_worm->m_lev, 8); worm->mhpmax = d((int) worm->m_lev, 8); /* new maxHP for old worm */ if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax; wtails[new_wnum] = new_tail; /* We've got all the info right now */ wheads[new_wnum] = curr; /* so we can do this faster than */ wgrowtime[new_wnum] = 0L; /* trying to call initworm(). */ /* Place the new monster at all the segment locations. */ place_wsegs(new_worm); if (context.mon_moving) pline("%s is cut in half.", Monnam(worm)); else You("cut %s in half.", mon_nam(worm)); } /* * see_wsegs() * * Refresh all of the segments of the given worm. This is only called * from see_monster() in display.c or when a monster goes minvis. It * is located here for modularity. */ void see_wsegs(worm) struct monst *worm; { struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr != wheads[worm->wormno]) { newsym(curr->wx, curr->wy); curr = curr->nseg; } } /* * detect_wsegs() * * Display all of the segments of the given worm for detection. */ void detect_wsegs(worm, use_detection_glyph) struct monst *worm; boolean use_detection_glyph; { int num; struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr != wheads[worm->wormno]) { num = use_detection_glyph ? detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) : (worm->mtame ? petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) : monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL))); show_glyph(curr->wx, curr->wy, num); curr = curr->nseg; } } /* * save_worm() * * Save the worm information for later use. The count is the number * of segments, including the dummy. Called from save.c. */ void save_worm(fd, mode) int fd, mode; { int i; int count; struct wseg *curr, *temp; if (perform_bwrite(mode)) { for (i = 1; i < MAX_NUM_WORMS; i++) { for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++; /* Save number of segments */ bwrite(fd, (genericptr_t) &count, sizeof(int)); /* Save segment locations of the monster. */ if (count) { for (curr = wtails[i]; curr; curr = curr->nseg) { bwrite(fd, (genericptr_t) & (curr->wx), sizeof(xchar)); bwrite(fd, (genericptr_t) & (curr->wy), sizeof(xchar)); } } } bwrite(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime)); } if (release_data(mode)) { /* Free the segments only. savemonchn() will take care of the * monsters. */ for (i = 1; i < MAX_NUM_WORMS; i++) { if (!(curr = wtails[i])) continue; while (curr) { temp = curr->nseg; dealloc_seg(curr); /* free the segment */ curr = temp; } wheads[i] = wtails[i] = (struct wseg *) 0; } } } /* * rest_worm() * * Restore the worm information from the save file. Called from restore.c */ void rest_worm(fd) int fd; { int i, j, count; struct wseg *curr, *temp; for (i = 1; i < MAX_NUM_WORMS; i++) { mread(fd, (genericptr_t) &count, sizeof(int)); if (!count) continue; /* none */ /* Get the segments. */ for (curr = (struct wseg *) 0, j = 0; j < count; j++) { temp = newseg(); temp->nseg = (struct wseg *) 0; mread(fd, (genericptr_t) & (temp->wx), sizeof(xchar)); mread(fd, (genericptr_t) & (temp->wy), sizeof(xchar)); if (curr) curr->nseg = temp; else wtails[i] = temp; curr = temp; } wheads[i] = curr; } mread(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime)); } /* * place_wsegs() * * Place the segments of the given worm. Called from restore.c */ void place_wsegs(worm) struct monst *worm; { struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr != wheads[worm->wormno]) { place_worm_seg(worm, curr->wx, curr->wy); curr = curr->nseg; } } /* * remove_worm() * * This function is equivalent to the remove_monster #define in * rm.h, only it will take the worm *and* tail out of the levels array. * It does not get rid of (dealloc) the worm tail structures, and it does * not remove the mon from the fmon chain. */ void remove_worm(worm) register struct monst *worm; { register struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr) { remove_monster(curr->wx, curr->wy); newsym(curr->wx, curr->wy); curr = curr->nseg; } } /* * place_worm_tail_randomly() * * Place a worm tail somewhere on a level behind the head. * This routine essentially reverses the order of the wsegs from head * to tail while placing them. * x, and y are most likely the worm->mx, and worm->my, but don't *need* to * be, if somehow the head is disjoint from the tail. */ void place_worm_tail_randomly(worm, x, y) struct monst *worm; xchar x, y; { int wnum = worm->wormno; struct wseg *curr = wtails[wnum]; struct wseg *new_tail; register xchar ox = x, oy = y; /* if (!wnum) return; bullet proofing */ if (wnum && (!wtails[wnum] || !wheads[wnum])) { impossible("place_worm_tail_randomly: wormno is set without a tail!"); return; } wheads[wnum] = new_tail = curr; curr = curr->nseg; new_tail->nseg = (struct wseg *) 0; new_tail->wx = x; new_tail->wy = y; while (curr) { xchar nx, ny; char tryct = 0; /* pick a random direction from x, y and search for goodpos() */ do { random_dir(ox, oy, &nx, &ny); } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50)); if (tryct < 50) { place_worm_seg(worm, nx, ny); curr->wx = ox = nx; curr->wy = oy = ny; wtails[wnum] = curr; curr = curr->nseg; wtails[wnum]->nseg = new_tail; new_tail = wtails[wnum]; newsym(nx, ny); } else { /* Oops. Truncate because there was */ toss_wsegs(curr, FALSE); /* no place for the rest of it */ curr = (struct wseg *) 0; } } } /* * Given a coordinate x, y. * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining. * * This function, and the loop it serves, could be eliminated by coding * enexto() with a search radius. */ STATIC_OVL void random_dir(x, y, nx, ny) register xchar x, y; register xchar *nx, *ny; { *nx = x; *ny = y; *nx += (x > 1 /* extreme left ? */ ? (x < COLNO /* extreme right ? */ ? (rn2(3) - 1) /* neither so +1, 0, or -1 */ : -rn2(2)) /* 0, or -1 */ : rn2(2)); /* 0, or 1 */ *ny += (*nx == x /* same kind of thing with y */ ? (y > 1 ? (y < ROWNO ? (rn2(2) ? 1 : -1) : -1) : 1) : (y > 1 ? (y < ROWNO ? (rn2(3) - 1) : -rn2(2)) : rn2(2))); } /* count_wsegs() * returns the number of visible segments that a worm has. */ int count_wsegs(mtmp) struct monst *mtmp; { register int i = 0; register struct wseg *curr = (wtails[mtmp->wormno])->nseg; /* if (!mtmp->wormno) return 0; bullet proofing */ while (curr) { i++; curr = curr->nseg; } return i; } /* create_worm_tail() * will create a worm tail chain of (num_segs + 1) and return pointer to it. */ STATIC_OVL struct wseg * create_worm_tail(num_segs) int num_segs; { register int i = 0; register struct wseg *new_tail, *curr; if (!num_segs) return (struct wseg *) 0; new_tail = curr = newseg(); curr->nseg = (struct wseg *) 0; curr->wx = 0; curr->wy = 0; while (i < num_segs) { curr->nseg = newseg(); curr = curr->nseg; curr->nseg = (struct wseg *) 0; curr->wx = 0; curr->wy = 0; i++; } return new_tail; } /* worm_known() * Is any segment of this worm in viewing range? Note: caller must check * invisibility and telepathy (which should only show the head anyway). * Mostly used in the canseemon() macro. */ boolean worm_known(worm) struct monst *worm; { struct wseg *curr = wtails[worm->wormno]; while (curr) { if (cansee(curr->wx, curr->wy)) return TRUE; curr = curr->nseg; } return FALSE; } /* would moving from to involve passing between two consecutive segments of the same worm? */ boolean worm_cross(x1, y1, x2, y2) int x1, y1, x2, y2; { struct monst *worm; struct wseg *curr, *wnxt; /* * With digits representing relative sequence number of the segments, * returns true when testing between @ and ? (passes through worm's * body), false between @ and ! (stays on same side of worm). * .w1?.. * ..@2.. * .65!3. * ...4.. */ if (distmin(x1, y1, x2, y2) != 1) { impossible("worm_cross checking for non-adjacent location?"); return FALSE; } /* attempting to pass between worm segs is only relevant for diagonal */ if (x1 == x2 || y1 == y2) return FALSE; /* is the same monster at and at ? */ worm = m_at(x1, y2); if (!worm || m_at(x2, y1) != worm) return FALSE; /* same monster is at both adjacent spots, so must be a worm; we need to figure out if the two spots are occupied by consecutive segments */ for (curr = wtails[worm->wormno]; curr; curr = wnxt) { wnxt = curr->nseg; if (!wnxt) break; /* no next segment; can't continue */ /* we don't know which of or we'll hit first, but whichever it is, they're consecutive iff next seg is the other */ if (curr->wx == x1 && curr->wy == y2) return (boolean) (wnxt->wx == x2 && wnxt->wy == y1); if (curr->wx == x2 && curr->wy == y1) return (boolean) (wnxt->wx == x1 && wnxt->wy == y2); } /* should never reach here... */ return FALSE; } /*worm.c*/ nethack-3.6.0/src/worn.c0000664000076400007660000007574012617413107014074 0ustar paxedpaxed/* NetHack 3.6 worn.c $NHDT-Date: 1446887541 2015/11/07 09:12:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL void FDECL(m_lose_armor, (struct monst *, struct obj *)); STATIC_DCL void FDECL(m_dowear_type, (struct monst *, long, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *)); const struct worn { long w_mask; struct obj **w_obj; } worn[] = { { W_ARM, &uarm }, { W_ARMC, &uarmc }, { W_ARMH, &uarmh }, { W_ARMS, &uarms }, { W_ARMG, &uarmg }, { W_ARMF, &uarmf }, { W_ARMU, &uarmu }, { W_RINGL, &uleft }, { W_RINGR, &uright }, { W_WEP, &uwep }, { W_SWAPWEP, &uswapwep }, { W_QUIVER, &uquiver }, { W_AMUL, &uamul }, { W_TOOL, &ublindf }, { W_BALL, &uball }, { W_CHAIN, &uchain }, { 0, 0 } }; /* This only allows for one blocking item per property */ #define w_blocks(o, m) \ ((o->otyp == MUMMY_WRAPPING && ((m) &W_ARMC)) \ ? INVIS \ : (o->otyp == CORNUTHAUM && ((m) &W_ARMH) && !Role_if(PM_WIZARD)) \ ? CLAIRVOYANT \ : 0) /* note: monsters don't have clairvoyance, so your role has no significant effect on their use of w_blocks() */ /* Updated to use the extrinsic and blocked fields. */ void setworn(obj, mask) register struct obj *obj; long mask; { register const struct worn *wp; register struct obj *oobj; register int p; if ((mask & (W_ARM | I_SPECIAL)) == (W_ARM | I_SPECIAL)) { /* restoring saved game; no properties are conferred via skin */ uskin = obj; /* assert( !uarm ); */ } else { if ((mask & W_ARMOR)) u.uroleplay.nudist = FALSE; for (wp = worn; wp->w_mask; wp++) if (wp->w_mask & mask) { oobj = *(wp->w_obj); if (oobj && !(oobj->owornmask & wp->w_mask)) impossible("Setworn: mask = %ld.", wp->w_mask); if (oobj) { if (u.twoweap && (oobj->owornmask & (W_WEP | W_SWAPWEP))) u.twoweap = 0; oobj->owornmask &= ~wp->w_mask; if (wp->w_mask & ~(W_SWAPWEP | W_QUIVER)) { /* leave as "x = x y", here and below, for broken * compilers */ p = objects[oobj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; if ((p = w_blocks(oobj, mask)) != 0) u.uprops[p].blocked &= ~wp->w_mask; if (oobj->oartifact) set_artifact_intrinsic(oobj, 0, mask); } } *(wp->w_obj) = obj; if (obj) { obj->owornmask |= wp->w_mask; /* Prevent getting/blocking intrinsics from wielding * potions, through the quiver, etc. * Allow weapon-tools, too. * wp_mask should be same as mask at this point. */ if (wp->w_mask & ~(W_SWAPWEP | W_QUIVER)) { if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || mask != W_WEP) { p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic | wp->w_mask; if ((p = w_blocks(obj, mask)) != 0) u.uprops[p].blocked |= wp->w_mask; } if (obj->oartifact) set_artifact_intrinsic(obj, 1, mask); } } } } update_inventory(); } /* called e.g. when obj is destroyed */ /* Updated to use the extrinsic and blocked fields. */ void setnotworn(obj) register struct obj *obj; { register const struct worn *wp; register int p; if (!obj) return; if (obj == uwep || obj == uswapwep) u.twoweap = 0; for (wp = worn; wp->w_mask; wp++) if (obj == *(wp->w_obj)) { *(wp->w_obj) = 0; p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; obj->owornmask &= ~wp->w_mask; if (obj->oartifact) set_artifact_intrinsic(obj, 0, wp->w_mask); if ((p = w_blocks(obj, wp->w_mask)) != 0) u.uprops[p].blocked &= ~wp->w_mask; } update_inventory(); } /* return a bitmask of the equipment slot(s) a given item might be worn in */ long wearslot(obj) struct obj *obj; { int otyp = obj->otyp; /* practically any item can be wielded or quivered; it's up to our caller to handle such things--we assume "normal" usage */ long res = 0L; /* default: can't be worn anywhere */ switch (obj->oclass) { case AMULET_CLASS: res = W_AMUL; /* WORN_AMUL */ break; case RING_CLASS: res = W_RINGL | W_RINGR; /* W_RING, BOTH_SIDES */ break; case ARMOR_CLASS: switch (objects[otyp].oc_armcat) { case ARM_SUIT: res = W_ARM; break; /* WORN_ARMOR */ case ARM_SHIELD: res = W_ARMS; break; /* WORN_SHIELD */ case ARM_HELM: res = W_ARMH; break; /* WORN_HELMET */ case ARM_GLOVES: res = W_ARMG; break; /* WORN_GLOVES */ case ARM_BOOTS: res = W_ARMF; break; /* WORN_BOOTS */ case ARM_CLOAK: res = W_ARMC; break; /* WORN_CLOAK */ case ARM_SHIRT: res = W_ARMU; break; /* WORN_SHIRT */ } break; case WEAPON_CLASS: res = W_WEP | W_SWAPWEP; if (objects[otyp].oc_merge) res |= W_QUIVER; break; case TOOL_CLASS: if (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES) res = W_TOOL; /* WORN_BLINDF */ else if (is_weptool(obj) || otyp == TIN_OPENER) res = W_WEP | W_SWAPWEP; else if (otyp == SADDLE) res = W_SADDLE; break; case FOOD_CLASS: if (obj->otyp == MEAT_RING) res = W_RINGL | W_RINGR; break; case GEM_CLASS: res = W_QUIVER; break; case BALL_CLASS: res = W_BALL; break; case CHAIN_CLASS: res = W_CHAIN; break; default: break; } return res; } void mon_set_minvis(mon) struct monst *mon; { mon->perminvis = 1; if (!mon->invis_blkd) { mon->minvis = 1; newsym(mon->mx, mon->my); /* make it disappear */ if (mon->wormno) see_wsegs(mon); /* and any tail too */ } } void mon_adjust_speed(mon, adjust, obj) struct monst *mon; int adjust; /* positive => increase speed, negative => decrease */ struct obj *obj; /* item to make known if effect can be seen */ { struct obj *otmp; boolean give_msg = !in_mklev, petrify = FALSE; unsigned int oldspeed = mon->mspeed; switch (adjust) { case 2: mon->permspeed = MFAST; give_msg = FALSE; /* special case monster creation */ break; case 1: if (mon->permspeed == MSLOW) mon->permspeed = 0; else mon->permspeed = MFAST; break; case 0: /* just check for worn speed boots */ break; case -1: if (mon->permspeed == MFAST) mon->permspeed = 0; else mon->permspeed = MSLOW; break; case -2: mon->permspeed = MSLOW; give_msg = FALSE; /* (not currently used) */ break; case -3: /* petrification */ /* take away intrinsic speed but don't reduce normal speed */ if (mon->permspeed == MFAST) mon->permspeed = 0; petrify = TRUE; break; case -4: /* green slime */ if (mon->permspeed == MFAST) mon->permspeed = 0; give_msg = FALSE; break; } for (otmp = mon->minvent; otmp; otmp = otmp->nobj) if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST) break; if (otmp) /* speed boots */ mon->mspeed = MFAST; else mon->mspeed = mon->permspeed; /* no message if monster is immobile (temp or perm) or unseen */ if (give_msg && (mon->mspeed != oldspeed || petrify) && mon->data->mmove && !(mon->mfrozen || mon->msleeping) && canseemon(mon)) { /* fast to slow (skipping intermediate state) or vice versa */ const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ? "much " : ""; if (petrify) { /* mimic the player's petrification countdown; "slowing down" even if fast movement rate retained via worn speed boots */ if (flags.verbose) pline("%s is slowing down.", Monnam(mon)); } else if (adjust > 0 || mon->mspeed == MFAST) pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch); else pline("%s seems to be moving %sslower.", Monnam(mon), howmuch); /* might discover an object if we see the speed change happen */ if (obj != 0) learnwand(obj); } } /* armor put on or taken off; might be magical variety */ void update_mon_intrinsics(mon, obj, on, silently) struct monst *mon; struct obj *obj; boolean on, silently; { int unseen; uchar mask; struct obj *otmp; int which = (int) objects[obj->otyp].oc_oprop; unseen = !canseemon(mon); if (!which) goto maybe_blocks; if (on) { switch (which) { case INVIS: mon->minvis = !mon->invis_blkd; break; case FAST: { boolean save_in_mklev = in_mklev; if (silently) in_mklev = TRUE; mon_adjust_speed(mon, 0, obj); in_mklev = save_in_mklev; break; } /* properties handled elsewhere */ case ANTIMAGIC: case REFLECTING: break; /* properties which have no effect for monsters */ case CLAIRVOYANT: case STEALTH: case TELEPAT: break; /* properties which should have an effect but aren't implemented */ case LEVITATION: case WWALKING: break; /* properties which maybe should have an effect but don't */ case DISPLACED: case FUMBLING: case JUMPING: case PROTECTION: break; default: if (which <= 8) { /* 1 thru 8 correspond to MR_xxx mask values */ /* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */ mask = (uchar) (1 << (which - 1)); mon->mintrinsics |= (unsigned short) mask; } break; } } else { /* off */ switch (which) { case INVIS: mon->minvis = mon->perminvis; break; case FAST: { boolean save_in_mklev = in_mklev; if (silently) in_mklev = TRUE; mon_adjust_speed(mon, 0, obj); in_mklev = save_in_mklev; break; } case FIRE_RES: case COLD_RES: case SLEEP_RES: case DISINT_RES: case SHOCK_RES: case POISON_RES: case ACID_RES: case STONE_RES: mask = (uchar) (1 << (which - 1)); /* If the monster doesn't have this resistance intrinsically, check whether any other worn item confers it. Note that we don't currently check for anything conferred via simply carrying an object. */ if (!(mon->data->mresists & mask)) { for (otmp = mon->minvent; otmp; otmp = otmp->nobj) if (otmp->owornmask && (int) objects[otmp->otyp].oc_oprop == which) break; if (!otmp) mon->mintrinsics &= ~((unsigned short) mask); } break; default: break; } } maybe_blocks: /* obj->owornmask has been cleared by this point, so we can't use it. However, since monsters don't wield armor, we don't have to guard against that and can get away with a blanket worn-mask value. */ switch (w_blocks(obj, ~0L)) { case INVIS: mon->invis_blkd = on ? 1 : 0; mon->minvis = on ? 0 : mon->perminvis; break; default: break; } if (!on && mon == u.usteed && obj->otyp == SADDLE) dismount_steed(DISMOUNT_FELL); /* if couldn't see it but now can, or vice versa, update display */ if (!silently && (unseen ^ !canseemon(mon))) newsym(mon->mx, mon->my); } int find_mac(mon) register struct monst *mon; { register struct obj *obj; int base = mon->data->ac; long mwflags = mon->misc_worn_check; for (obj = mon->minvent; obj; obj = obj->nobj) { if (obj->owornmask & mwflags) base -= ARM_BONUS(obj); /* since ARM_BONUS is positive, subtracting it increases AC */ } return base; } /* * weapons are handled separately; * rings and eyewear aren't used by monsters */ /* Wear the best object of each type that the monster has. During creation, * the monster can put everything on at once; otherwise, wearing takes time. * This doesn't affect monster searching for objects--a monster may very well * search for objects it would not want to wear, because we don't want to * check which_armor() each round. * * We'll let monsters put on shirts and/or suits under worn cloaks, but * not shirts under worn suits. This is somewhat arbitrary, but it's * too tedious to have them remove and later replace outer garments, * and preventing suits under cloaks makes it a little bit too easy for * players to influence what gets worn. Putting on a shirt underneath * already worn body armor is too obviously buggy... */ void m_dowear(mon, creation) register struct monst *mon; boolean creation; { #define RACE_EXCEPTION TRUE /* Note the restrictions here are the same as in dowear in do_wear.c * except for the additional restriction on intelligence. (Players * are always intelligent, even if polymorphed). */ if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data)) return; /* give mummies a chance to wear their wrappings * and let skeletons wear their initial armor */ if (mindless(mon->data) && (!creation || (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON]))) return; m_dowear_type(mon, W_AMUL, creation, FALSE); /* can't put on shirt if already wearing suit */ if (!cantweararm(mon->data) && !(mon->misc_worn_check & W_ARM)) m_dowear_type(mon, W_ARMU, creation, FALSE); /* treating small as a special case allows hobbits, gnomes, and kobolds to wear cloaks */ if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL) m_dowear_type(mon, W_ARMC, creation, FALSE); m_dowear_type(mon, W_ARMH, creation, FALSE); if (!MON_WEP(mon) || !bimanual(MON_WEP(mon))) m_dowear_type(mon, W_ARMS, creation, FALSE); m_dowear_type(mon, W_ARMG, creation, FALSE); if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR) m_dowear_type(mon, W_ARMF, creation, FALSE); if (!cantweararm(mon->data)) m_dowear_type(mon, W_ARM, creation, FALSE); else m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION); } STATIC_OVL void m_dowear_type(mon, flag, creation, racialexception) struct monst *mon; long flag; boolean creation; boolean racialexception; { struct obj *old, *best, *obj; int m_delay = 0; int unseen = !canseemon(mon); boolean autocurse; char nambuf[BUFSZ]; if (mon->mfrozen) return; /* probably putting previous item on */ /* Get a copy of monster's name before altering its visibility */ Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon)); old = which_armor(mon, flag); if (old && old->cursed) return; if (old && flag == W_AMUL) return; /* no such thing as better amulets */ best = old; for (obj = mon->minvent; obj; obj = obj->nobj) { switch (flag) { case W_AMUL: if (obj->oclass != AMULET_CLASS || (obj->otyp != AMULET_OF_LIFE_SAVING && obj->otyp != AMULET_OF_REFLECTION)) continue; best = obj; goto outer_break; /* no such thing as better amulets */ case W_ARMU: if (!is_shirt(obj)) continue; break; case W_ARMC: if (!is_cloak(obj)) continue; break; case W_ARMH: if (!is_helmet(obj)) continue; /* changing alignment is not implemented for monsters; priests and minions could change alignment but wouldn't want to, so they reject helms of opposite alignment */ if (obj->otyp == HELM_OF_OPPOSITE_ALIGNMENT && (mon->ispriest || mon->isminion)) continue; /* (flimsy exception matches polyself handling) */ if (has_horns(mon->data) && !is_flimsy(obj)) continue; break; case W_ARMS: if (!is_shield(obj)) continue; break; case W_ARMG: if (!is_gloves(obj)) continue; break; case W_ARMF: if (!is_boots(obj)) continue; break; case W_ARM: if (!is_suit(obj)) continue; if (racialexception && (racial_exception(mon, obj) < 1)) continue; break; } if (obj->owornmask) continue; /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the * monster knows obj->spe, but if I did that, a monster would keep * switching forever between two -2 caps since when it took off one * it would forget spe and once again think the object is better * than what it already has. */ if (best && (ARM_BONUS(best) + extra_pref(mon, best) >= ARM_BONUS(obj) + extra_pref(mon, obj))) continue; best = obj; } outer_break: if (!best || best == old) return; /* same auto-cursing behavior as for hero */ autocurse = ((best->otyp == HELM_OF_OPPOSITE_ALIGNMENT || best->otyp == DUNCE_CAP) && !best->cursed); /* if wearing a cloak, account for the time spent removing and re-wearing it when putting on a suit or shirt */ if ((flag == W_ARM || flag == W_ARMU) && (mon->misc_worn_check & W_ARMC)) m_delay += 2; /* when upgrading a piece of armor, account for time spent taking off current one */ if (old) m_delay += objects[old->otyp].oc_delay; if (old) /* do this first to avoid "(being worn)" */ old->owornmask = 0L; if (!creation) { if (canseemon(mon)) { char buf[BUFSZ]; if (old) Sprintf(buf, " removes %s and", distant_name(old, doname)); else buf[0] = '\0'; pline("%s%s puts on %s.", Monnam(mon), buf, distant_name(best, doname)); if (autocurse) pline("%s %s %s %s for a moment.", s_suffix(Monnam(mon)), simpleonames(best), otense(best, "glow"), hcolor(NH_BLACK)); } /* can see it */ m_delay += objects[best->otyp].oc_delay; mon->mfrozen = m_delay; if (mon->mfrozen) mon->mcanmove = 0; } if (old) update_mon_intrinsics(mon, old, FALSE, creation); mon->misc_worn_check |= flag; best->owornmask |= flag; if (autocurse) curse(best); update_mon_intrinsics(mon, best, TRUE, creation); /* if couldn't see it but now can, or vice versa, */ if (!creation && (unseen ^ !canseemon(mon))) { if (mon->minvis && !See_invisible) { pline("Suddenly you cannot see %s.", nambuf); makeknown(best->otyp); } /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */ } } #undef RACE_EXCEPTION struct obj * which_armor(mon, flag) struct monst *mon; long flag; { if (mon == &youmonst) { switch (flag) { case W_ARM: return uarm; case W_ARMC: return uarmc; case W_ARMH: return uarmh; case W_ARMS: return uarms; case W_ARMG: return uarmg; case W_ARMF: return uarmf; case W_ARMU: return uarmu; default: impossible("bad flag in which_armor"); return 0; } } else { register struct obj *obj; for (obj = mon->minvent; obj; obj = obj->nobj) if (obj->owornmask & flag) return obj; return (struct obj *) 0; } } /* remove an item of armor and then drop it */ STATIC_OVL void m_lose_armor(mon, obj) struct monst *mon; struct obj *obj; { mon->misc_worn_check &= ~obj->owornmask; if (obj->owornmask) update_mon_intrinsics(mon, obj, FALSE, FALSE); obj->owornmask = 0L; obj_extract_self(obj); place_object(obj, mon->mx, mon->my); /* call stackobj() if we ever drop anything that can merge */ newsym(mon->mx, mon->my); } /* all objects with their bypass bit set should now be reset to normal */ void clear_bypasses() { struct obj *otmp, *nobj; struct monst *mtmp; for (otmp = fobj; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->bypass) { otmp->bypass = 0; /* bypass will have inhibited any stacking, but since it's * used for polymorph handling, the objects here probably * have been transformed and won't be stacked in the usual * manner afterwards; so don't bother with this. * [Changing the fobj chain mid-traversal would also be risky.] */ #if 0 if (objects[otmp->otyp].oc_merge) { xchar ox, oy; (void) get_obj_location(otmp, &ox, &oy, 0); stack_object(otmp); newsym(ox, oy); } #endif /*0*/ } } for (otmp = invent; otmp; otmp = otmp->nobj) otmp->bypass = 0; for (otmp = migrating_objs; otmp; otmp = otmp->nobj) otmp->bypass = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; } for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; } /* billobjs and mydogs chains don't matter here */ context.bypasses = FALSE; } void bypass_obj(obj) struct obj *obj; { obj->bypass = 1; context.bypasses = TRUE; } /* set or clear the bypass bit in a list of objects */ void bypass_objlist(objchain, on) struct obj *objchain; boolean on; /* TRUE => set, FALSE => clear */ { if (on && objchain) context.bypasses = TRUE; while (objchain) { objchain->bypass = on ? 1 : 0; objchain = objchain->nobj; } } /* return the first object without its bypass bit set; set that bit before returning so that successive calls will find further objects */ struct obj * nxt_unbypassed_obj(objchain) struct obj *objchain; { while (objchain) { if (!objchain->bypass) { bypass_obj(objchain); break; } objchain = objchain->nobj; } return objchain; } void mon_break_armor(mon, polyspot) struct monst *mon; boolean polyspot; { register struct obj *otmp; struct permonst *mdat = mon->data; boolean vis = cansee(mon->mx, mon->my); boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat)); const char *pronoun = mhim(mon), *ppronoun = mhis(mon); if (breakarm(mdat)) { if ((otmp = which_armor(mon, W_ARM)) != 0) { if ((Is_dragon_scales(otmp) && mdat == Dragon_scales_to_pm(otmp)) || (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp))) ; /* no message here; "the dragon merges with his scaly armor" is odd and the monster's previous form is already gone */ else if (vis) pline("%s breaks out of %s armor!", Monnam(mon), ppronoun); else You_hear("a cracking sound."); m_useup(mon, otmp); } if ((otmp = which_armor(mon, W_ARMC)) != 0) { if (otmp->oartifact) { if (vis) pline("%s %s falls off!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } else { if (vis) pline("%s %s tears apart!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else You_hear("a ripping sound."); m_useup(mon, otmp); } } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) pline("%s shirt rips to shreds!", s_suffix(Monnam(mon))); else You_hear("a ripping sound."); m_useup(mon, otmp); } } else if (sliparm(mdat)) { if ((otmp = which_armor(mon, W_ARM)) != 0) { if (vis) pline("%s armor falls around %s!", s_suffix(Monnam(mon)), pronoun); else You_hear("a thud."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMC)) != 0) { if (vis) { if (is_whirly(mon->data)) pline("%s %s falls, unsupported!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else pline("%s shrinks out of %s %s!", Monnam(mon), ppronoun, cloak_simple_name(otmp)); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) { if (sliparm(mon->data)) pline("%s seeps right through %s shirt!", Monnam(mon), ppronoun); else pline("%s becomes much too small for %s shirt!", Monnam(mon), ppronoun); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny) { /* [caller needs to handle weapon checks] */ if ((otmp = which_armor(mon, W_ARMG)) != 0) { if (vis) pline("%s drops %s gloves%s!", Monnam(mon), ppronoun, MON_WEP(mon) ? " and weapon" : ""); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMS)) != 0) { if (vis) pline("%s can no longer hold %s shield!", Monnam(mon), ppronoun); else You_hear("a clank."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny || has_horns(mdat)) { if ((otmp = which_armor(mon, W_ARMH)) != 0 /* flimsy test for horns matches polyself handling */ && (handless_or_tiny || !is_flimsy(otmp))) { if (vis) pline("%s helmet falls to the %s!", s_suffix(Monnam(mon)), surface(mon->mx, mon->my)); else You_hear("a clank."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) { if ((otmp = which_armor(mon, W_ARMF)) != 0) { if (vis) { if (is_whirly(mon->data)) pline("%s boots fall away!", s_suffix(Monnam(mon))); else pline("%s boots %s off %s feet!", s_suffix(Monnam(mon)), verysmall(mdat) ? "slide" : "are pushed", ppronoun); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (!can_saddle(mon)) { if ((otmp = which_armor(mon, W_SADDLE)) != 0) { if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); if (vis) pline("%s saddle falls off.", s_suffix(Monnam(mon))); } if (mon == u.usteed) goto noride; } else if (mon == u.usteed && !can_ride(mon)) { noride: You("can no longer ride %s.", mon_nam(mon)); if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; You("touch %s.", mon_nam(u.usteed)); Sprintf(buf, "falling off %s", an(u.usteed->data->mname)); instapetrify(buf); } dismount_steed(DISMOUNT_FELL); } return; } /* bias a monster's preferences towards armor that has special benefits. */ STATIC_OVL int extra_pref(mon, obj) struct monst *mon; struct obj *obj; { /* currently only does speed boots, but might be expanded if monsters * get to use more armor abilities */ if (obj) { if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST) return 20; } return 0; } /* * Exceptions to things based on race. * Correctly checks polymorphed player race. * Returns: * 0 No exception, normal rules apply. * 1 If the race/object combination is acceptable. * -1 If the race/object combination is unacceptable. */ int racial_exception(mon, obj) struct monst *mon; struct obj *obj; { const struct permonst *ptr = raceptr(mon); /* Acceptable Exceptions: */ /* Allow hobbits to wear elven armor - LoTR */ if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj)) return 1; /* Unacceptable Exceptions: */ /* Checks for object that certain races should never use go here */ /* return -1; */ return 0; } /*worn.c*/ nethack-3.6.0/src/write.c0000664000076400007660000003147112614367060014235 0ustar paxedpaxed/* NetHack 3.6 write.c $NHDT-Date: 1446078770 2015/10/29 00:32:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL int FDECL(cost, (struct obj *)); STATIC_DCL boolean FDECL(label_known, (int, struct obj *)); STATIC_DCL char *FDECL(new_book_description, (int, char *)); /* * returns basecost of a scroll or a spellbook */ STATIC_OVL int cost(otmp) register struct obj *otmp; { if (otmp->oclass == SPBOOK_CLASS) return (10 * objects[otmp->otyp].oc_level); switch (otmp->otyp) { #ifdef MAIL case SCR_MAIL: return 2; #endif case SCR_LIGHT: case SCR_GOLD_DETECTION: case SCR_FOOD_DETECTION: case SCR_MAGIC_MAPPING: case SCR_AMNESIA: case SCR_FIRE: case SCR_EARTH: return 8; case SCR_DESTROY_ARMOR: case SCR_CREATE_MONSTER: case SCR_PUNISHMENT: return 10; case SCR_CONFUSE_MONSTER: return 12; case SCR_IDENTIFY: return 14; case SCR_ENCHANT_ARMOR: case SCR_REMOVE_CURSE: case SCR_ENCHANT_WEAPON: case SCR_CHARGING: return 16; case SCR_SCARE_MONSTER: case SCR_STINKING_CLOUD: case SCR_TAMING: case SCR_TELEPORTATION: return 20; case SCR_GENOCIDE: return 30; case SCR_BLANK_PAPER: default: impossible("You can't write such a weird scroll!"); } return 1000; } /* decide whether the hero knowns a particular scroll's label; unfortunately, we can't track things are haven't been added to the discoveries list and aren't present in current inventory, so some scrolls with ought to yield True will end up False */ STATIC_OVL boolean label_known(scrolltype, objlist) int scrolltype; struct obj *objlist; { struct obj *otmp; /* only scrolls */ if (objects[scrolltype].oc_class != SCROLL_CLASS) return FALSE; /* type known implies full discovery; otherwise, user-assigned name implies partial discovery */ if (objects[scrolltype].oc_name_known || objects[scrolltype].oc_uname) return TRUE; /* check inventory, including carried containers with known contents */ for (otmp = objlist; otmp; otmp = otmp->nobj) { if (otmp->otyp == scrolltype && otmp->dknown) return TRUE; if (Has_contents(otmp) && otmp->cknown && label_known(scrolltype, otmp->cobj)) return TRUE; } /* not found */ return FALSE; } static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 }; /* write -- applying a magic marker */ int dowrite(pen) register struct obj *pen; { register struct obj *paper; char namebuf[BUFSZ], *nm, *bp; register struct obj *new_obj; int basecost, actualcost; int curseval; char qbuf[QBUFSZ]; int first, last, i, deferred, deferralchance; boolean by_descr = FALSE; const char *typeword; if (nohands(youmonst.data)) { You("need hands to be able to write!"); return 0; } else if (Glib) { pline("%s from your %s.", Tobjnam(pen, "slip"), makeplural(body_part(FINGER))); dropx(pen); return 1; } /* get paper to write on */ paper = getobj(write_on, "write on"); if (!paper) return 0; /* can't write on a novel (unless/until it's been converted into a blank spellbook), but we want messages saying so to avoid "spellbook" */ typeword = (paper->otyp == SPE_NOVEL) ? "book" : (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll"; if (Blind) { if (!paper->dknown) { You("don't know if that %s is blank or not.", typeword); return 1; } else if (paper->oclass == SPBOOK_CLASS) { /* can't write a magic book while blind */ pline("%s can't create braille text.", upstart(ysimple_name(pen))); return 1; } } paper->dknown = 1; if (paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) { pline("That %s is not blank!", typeword); exercise(A_WIS, FALSE); return 1; } /* what to write */ Sprintf(qbuf, "What type of %s do you want to write?", typeword); getlin(qbuf, namebuf); (void) mungspaces(namebuf); /* remove any excess whitespace */ if (namebuf[0] == '\033' || !namebuf[0]) return 1; nm = namebuf; if (!strncmpi(nm, "scroll ", 7)) nm += 7; else if (!strncmpi(nm, "spellbook ", 10)) nm += 10; if (!strncmpi(nm, "of ", 3)) nm += 3; if ((bp = strstri(nm, " armour")) != 0) { (void) strncpy(bp, " armor ", 7); /* won't add '\0' */ (void) mungspaces(bp + 1); /* remove the extra space */ } deferred = 0; /* not any scroll or book */ deferralchance = 0; /* incremented for each oc_uname match */ first = bases[(int) paper->oclass]; last = bases[(int) paper->oclass + 1] - 1; for (i = first; i <= last; i++) { /* extra shufflable descr not representing a real object */ if (!OBJ_NAME(objects[i])) continue; if (!strcmpi(OBJ_NAME(objects[i]), nm)) goto found; if (!strcmpi(OBJ_DESCR(objects[i]), nm)) { by_descr = TRUE; goto found; } /* user-assigned name might match real name of a later entry, so we don't simply use first match with it; also, player might assign same name multiple times and if so, we choose one of those matches randomly */ if (objects[i].oc_uname && !strcmpi(objects[i].oc_uname, nm) /* * First match: chance incremented to 1, * !rn2(1) is 1, we remember i; * second match: chance incremented to 2, * !rn2(2) has 1/2 chance to replace i; * third match: chance incremented to 3, * !rn2(3) has 1/3 chance to replace i * and 2/3 chance to keep previous 50:50 * choice; so on for higher match counts. */ && !rn2(++deferralchance)) deferred = i; } /* writing by user-assigned name is same as by description: fails for books, works for scrolls (having an assigned type name guarantees presence on discoveries list) */ if (deferred) { i = deferred; by_descr = TRUE; goto found; } There("is no such %s!", typeword); return 1; found: if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) { You_cant("write that!"); pline("It's obscene!"); return 1; } else if (i == SPE_BOOK_OF_THE_DEAD) { pline("No mere dungeon adventurer could write that."); return 1; } else if (by_descr && paper->oclass == SPBOOK_CLASS && !objects[i].oc_name_known) { /* can't write unknown spellbooks by description */ pline("Unfortunately you don't have enough information to go on."); return 1; } /* KMH, conduct */ u.uconduct.literate++; new_obj = mksobj(i, FALSE, FALSE); new_obj->bknown = (paper->bknown && pen->bknown); /* shk imposes a flat rate per use, not based on actual charges used */ check_unpaid(pen); /* see if there's enough ink */ basecost = cost(new_obj); if (pen->spe < basecost / 2) { Your("marker is too dry to write that!"); obfree(new_obj, (struct obj *) 0); return 1; } /* we're really going to write now, so calculate cost */ actualcost = rn1(basecost / 2, basecost / 2); curseval = bcsign(pen) + bcsign(paper); exercise(A_WIS, TRUE); /* dry out marker */ if (pen->spe < actualcost) { pen->spe = 0; Your("marker dries out!"); /* scrolls disappear, spellbooks don't */ if (paper->oclass == SPBOOK_CLASS) { pline_The("spellbook is left unfinished and your writing fades."); update_inventory(); /* pen charges */ } else { pline_The("scroll is now useless and disappears!"); useup(paper); } obfree(new_obj, (struct obj *) 0); return 1; } pen->spe -= actualcost; /* * Writing by name requires that the hero knows the scroll or * book type. One has previously been read (and its effect * was evident) or been ID'd via scroll/spell/throne and it * will be on the discoveries list. * (Previous versions allowed scrolls and books to be written * by type name if they were on the discoveries list via being * given a user-assigned name, even though doing the latter * doesn't--and shouldn't--make the actual type become known.) * * Writing by description requires that the hero knows the * description (a scroll's label, that is, since books by_descr * are rejected above). BUG: We can only do this for known * scrolls and for the case where the player has assigned a * name to put it onto the discoveries list; we lack a way to * track other scrolls which have been seen closely enough to * read the label without then being ID'd or named. The only * exception is for currently carried inventory, where we can * check for one [with its dknown bit set] of the same type. * * Normal requirements can be overridden if hero is Lucky. */ /* if known, then either by-name or by-descr works */ if (!objects[new_obj->otyp].oc_name_known /* else if named, then only by-descr works */ && !(by_descr && label_known(new_obj->otyp, invent)) /* and Luck might override after both checks have failed */ && rnl(Role_if(PM_WIZARD) ? 5 : 15)) { You("%s to write that.", by_descr ? "fail" : "don't know how"); /* scrolls disappear, spellbooks don't */ if (paper->oclass == SPBOOK_CLASS) { You( "write in your best handwriting: \"My Diary\", but it quickly fades."); update_inventory(); /* pen charges */ } else { if (by_descr) { Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp])); wipeout_text(namebuf, (6 + MAXULEV - u.ulevel) / 6, 0); } else Sprintf(namebuf, "%s was here!", plname); You("write \"%s\" and the scroll disappears.", namebuf); useup(paper); } obfree(new_obj, (struct obj *) 0); return 1; } /* can write scrolls when blind, but requires luck too; attempts to write books when blind are caught above */ if (Blind && rnl(3)) { /* writing while blind usually fails regardless of whether the target scroll is known; even if we have passed the write-an-unknown scroll test above we can still fail this one, so it's doubly hard to write an unknown scroll while blind */ You("fail to write the scroll correctly and it disappears."); useup(paper); obfree(new_obj, (struct obj *) 0); return 1; } /* useup old scroll / spellbook */ useup(paper); /* success */ if (new_obj->oclass == SPBOOK_CLASS) { /* acknowledge the change in the object's description... */ pline_The("spellbook warps strangely, then turns %s.", new_book_description(new_obj->otyp, namebuf)); } new_obj->blessed = (curseval > 0); new_obj->cursed = (curseval < 0); #ifdef MAIL if (new_obj->otyp == SCR_MAIL) new_obj->spe = 1; #endif new_obj = hold_another_object(new_obj, "Oops! %s out of your grasp!", The(aobjnam(new_obj, "slip")), (const char *) 0); return 1; } /* most book descriptions refer to cover appearance, so we can issue a message for converting a plain book into one of those with something like "the spellbook turns red" or "the spellbook turns ragged"; but some descriptions refer to composition and "the book turns vellum" looks funny, so we want to insert "into " prior to such descriptions; even that's rather iffy, indicating that such descriptions probably ought to be eliminated (especially "cloth"!) */ STATIC_OVL char * new_book_description(booktype, outbuf) int booktype; char *outbuf; { /* subset of description strings from objects.c; if it grows much, we may need to add a new flag field to objects[] instead */ static const char *const compositions[] = { "parchment", "vellum", "cloth", #if 0 "canvas", "hardcover", /* not used */ "papyrus", /* not applicable--can't be produced via writing */ #endif /*0*/ 0 }; const char *descr, *const *comp_p; descr = OBJ_DESCR(objects[booktype]); for (comp_p = compositions; *comp_p; ++comp_p) if (!strcmpi(descr, *comp_p)) break; Sprintf(outbuf, "%s%s", *comp_p ? "into " : "", descr); return outbuf; } /*write.c*/ nethack-3.6.0/src/zap.c0000664000076400007660000050727412625027201013676 0ustar paxedpaxed/* NetHack 3.6 zap.c $NHDT-Date: 1447987787 2015/11/20 02:49:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.236 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Disintegration rays have special treatment; corpses are never left. * But the routine which calculates the damage is separate from the routine * which kills the monster. The damage routine returns this cookie to * indicate that the monster should be disintegrated. */ #define MAGIC_COOKIE 1000 static NEARDATA boolean obj_zapped; static NEARDATA int poly_zapped; extern boolean notonhead; /* for long worms */ /* kludge to use mondied instead of killed */ extern boolean m_using; STATIC_DCL void FDECL(polyuse, (struct obj *, int, int)); STATIC_DCL void FDECL(create_polymon, (struct obj *, int)); STATIC_DCL int FDECL(stone_to_flesh_obj, (struct obj *)); STATIC_DCL boolean FDECL(zap_updown, (struct obj *)); STATIC_DCL void FDECL(zhitu, (int, int, const char *, XCHAR_P, XCHAR_P)); STATIC_DCL void FDECL(revive_egg, (struct obj *)); STATIC_DCL boolean FDECL(zap_steed, (struct obj *)); STATIC_DCL void FDECL(skiprange, (int, int *, int *)); STATIC_DCL int FDECL(zap_hit, (int, int)); STATIC_OVL void FDECL(disintegrate_mon, (struct monst *, int, const char *)); STATIC_DCL void FDECL(backfire, (struct obj *)); STATIC_DCL int FDECL(spell_hit_bonus, (int)); #define ZT_MAGIC_MISSILE (AD_MAGM - 1) #define ZT_FIRE (AD_FIRE - 1) #define ZT_COLD (AD_COLD - 1) #define ZT_SLEEP (AD_SLEE - 1) #define ZT_DEATH (AD_DISN - 1) /* or disintegration */ #define ZT_LIGHTNING (AD_ELEC - 1) #define ZT_POISON_GAS (AD_DRST - 1) #define ZT_ACID (AD_ACID - 1) /* 8 and 9 are currently unassigned */ #define ZT_WAND(x) (x) #define ZT_SPELL(x) (10 + (x)) #define ZT_BREATH(x) (20 + (x)) #define is_hero_spell(type) ((type) >= 10 && (type) < 20) #define M_IN_WATER(ptr) \ ((ptr)->mlet == S_EEL || amphibious(ptr) || is_swimmer(ptr)) STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!"; const char *const flash_types[] = { /* also used in buzzmu(mcastu.c) */ "magic missile", /* Wands must be 0-9 */ "bolt of fire", "bolt of cold", "sleep ray", "death ray", "bolt of lightning", "", "", "", "", "magic missile", /* Spell equivalents must be 10-19 */ "fireball", "cone of cold", "sleep ray", "finger of death", "bolt of lightning", /* There is no spell, used for retribution */ "", "", "", "", "blast of missiles", /* Dragon breath equivalents 20-29*/ "blast of fire", "blast of frost", "blast of sleep gas", "blast of disintegration", "blast of lightning", "blast of poison gas", "blast of acid", "", "" }; /* * Recognizing unseen wands by zapping: in 3.4.3 and earlier, zapping * most wand types while blind would add that type to the discoveries * list even if it had never been seen (ie, picked up while blinded * and shown in inventory as simply "a wand"). This behavior has been * changed; now such wands won't be discovered. But if the type is * already discovered, then the individual wand whose effect was just * observed will be flagged as if seen. [You already know wands of * striking; you zap "a wand" and observe striking effect (presumably * by sound or touch); it'll become shown in inventory as "a wand of * striking".] * * Unfortunately, the new behavior isn't really correct either. There * should be an `eknown' bit for "effect known" added for wands (and * for potions since quaffing one of a stack is similar) so that the * particular wand which has been zapped would have its type become * known (it would change from "a wand" to "a wand of striking", for * example) without the type becoming discovered or other unknown wands * of that type showing additional information. When blindness ends, * all objects in inventory with the eknown bit set would be discovered * and other items of the same type would become known as such. */ /* wand discovery gets special handling when hero is blinded */ void learnwand(obj) struct obj *obj; { /* For a wand (or wand-like tool) zapped by the player, if the effect was observable (determined by caller; usually seen, but possibly heard or felt if the hero is blinded) then discover the object type provided that the object itself is known (as more than just "a wand"). If object type is already discovered and we observed the effect, mark the individual wand as having been seen. Suppress spells (which use fake spellbook object for `obj') so that casting a spell won't re-discover its forgotten book. */ if (obj->oclass != SPBOOK_CLASS) { /* if type already discovered, treat this item has having been seen even if hero is currently blinded (skips redundant makeknown) */ if (objects[obj->otyp].oc_name_known) { obj->dknown = 1; /* will usually be set already */ /* otherwise discover it if item itself has been or can be seen */ } else { /* in case it was picked up while blind and then zapped without examining inventory after regaining sight (bypassing xname) */ if (!Blind) obj->dknown = 1; /* make the discovery iff we know what we're manipulating */ if (obj->dknown) makeknown(obj->otyp); } } } /* Routines for IMMEDIATE wands and spells. */ /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */ int bhitm(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { boolean wake = TRUE; /* Most 'zaps' should wake monster */ boolean reveal_invis = FALSE, learn_it = FALSE; boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart; int dmg, otyp = otmp->otyp; const char *zap_type_text = "spell"; struct obj *obj; boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC && mtmp->m_ap_type != M_AP_NOTHING); if (u.uswallow && mtmp == u.ustuck) reveal_invis = FALSE; switch (otyp) { case WAN_STRIKING: zap_type_text = "wand"; /* fall through */ case SPE_FORCE_BOLT: reveal_invis = TRUE; if (resists_magm(mtmp)) { /* match effect on player */ shieldeff(mtmp->mx, mtmp->my); pline("Boing!"); break; /* skip makeknown */ } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) { dmg = d(2, 12); if (dbldam) dmg *= 2; if (otyp == SPE_FORCE_BOLT) dmg = spell_damage_bonus(dmg); hit(zap_type_text, mtmp, exclam(dmg)); (void) resist(mtmp, otmp->oclass, dmg, TELL); } else miss(zap_type_text, mtmp); learn_it = TRUE; break; case WAN_SLOW_MONSTER: case SPE_SLOW_MONSTER: if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { mon_adjust_speed(mtmp, -1, otmp); m_dowear(mtmp, FALSE); /* might want speed boots */ if (u.uswallow && (mtmp == u.ustuck) && is_whirly(mtmp->data)) { You("disrupt %s!", mon_nam(mtmp)); pline("A huge hole opens up..."); expels(mtmp, mtmp->data, TRUE); } } break; case WAN_SPEED_MONSTER: if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { mon_adjust_speed(mtmp, 1, otmp); m_dowear(mtmp, FALSE); /* might want speed boots */ } break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: wake = FALSE; if (unturn_dead(mtmp)) wake = TRUE; if (is_undead(mtmp->data) || is_vampshifter(mtmp)) { reveal_invis = TRUE; wake = TRUE; dmg = rnd(8); if (dbldam) dmg *= 2; if (otyp == SPE_TURN_UNDEAD) dmg = spell_damage_bonus(dmg); context.bypasses = TRUE; /* for make_corpse() */ if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) { if (mtmp->mhp > 0) monflee(mtmp, 0, FALSE, TRUE); } } break; case WAN_POLYMORPH: case SPE_POLYMORPH: case POT_POLYMORPH: if (resists_magm(mtmp)) { /* magic resistance protects from polymorph traps, so make it guard against involuntary polymorph attacks too... */ shieldeff(mtmp->mx, mtmp->my); } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { /* dropped inventory (due to death by system shock, or loss of wielded weapon and/or worn armor due to limitations of new shape) won't be hit by this zap */ for (obj = mtmp->minvent; obj; obj = obj->nobj) bypass_obj(obj); /* natural shapechangers aren't affected by system shock (unless protection from shapechangers is interfering with their metabolism...) */ if (mtmp->cham == NON_PM && !rn2(25)) { if (canseemon(mtmp)) { pline("%s shudders!", Monnam(mtmp)); learn_it = TRUE; } /* context.bypasses = TRUE; ## for make_corpse() */ /* no corpse after system shock */ xkilled(mtmp, 3); } else if (newcham(mtmp, (struct permonst *) 0, (otyp != POT_POLYMORPH), FALSE)) { if (!Hallucination && canspotmon(mtmp)) learn_it = TRUE; } } break; case WAN_CANCELLATION: case SPE_CANCELLATION: (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: reveal_invis = !u_teleport_mon(mtmp, TRUE); break; case WAN_MAKE_INVISIBLE: { int oldinvis = mtmp->minvis; char nambuf[BUFSZ]; /* format monster's name before altering its visibility */ Strcpy(nambuf, Monnam(mtmp)); mon_set_minvis(mtmp); if (!oldinvis && knowninvisible(mtmp)) { pline("%s turns transparent!", nambuf); learn_it = TRUE; } break; } case WAN_LOCKING: case SPE_WIZARD_LOCK: wake = closeholdingtrap(mtmp, &learn_it); break; case WAN_PROBING: wake = FALSE; reveal_invis = TRUE; probe_monster(mtmp); learn_it = TRUE; break; case WAN_OPENING: case SPE_KNOCK: wake = FALSE; /* don't want immediate counterattack */ if (u.uswallow && mtmp == u.ustuck) { if (is_animal(mtmp->data)) { if (Blind) You_feel("a sudden rush of air!"); else pline("%s opens its mouth!", Monnam(mtmp)); } expels(mtmp, mtmp->data, TRUE); /* zap which hits steed will only release saddle if it doesn't hit a holding or falling trap; playability here overrides the more logical target ordering */ } else if (openholdingtrap(mtmp, &learn_it)) { break; } else if (openfallingtrap(mtmp, TRUE, &learn_it)) { /* mtmp might now be on the migrating monsters list */ break; } else if ((obj = which_armor(mtmp, W_SADDLE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)), distant_name(obj, xname)); if (cansee(mtmp->mx, mtmp->my)) { if (!canspotmon(mtmp)) Strcpy(buf, An(distant_name(obj, xname))); pline("%s falls to the %s.", buf, surface(mtmp->mx, mtmp->my)); } else if (canspotmon(mtmp)) { pline("%s falls off.", buf); } obj_extract_self(obj); mdrop_obj(mtmp, obj, FALSE); } break; case SPE_HEALING: case SPE_EXTRA_HEALING: reveal_invis = TRUE; if (mtmp->data != &mons[PM_PESTILENCE]) { wake = FALSE; /* wakeup() makes the target angry */ mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4); if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; if (mtmp->mblinded) { mtmp->mblinded = 0; mtmp->mcansee = 1; } if (canseemon(mtmp)) { if (disguised_mimic) { if (is_obj_mappear(mtmp,STRANGE_OBJECT)) { /* it can do better now */ set_mimic_sym(mtmp); newsym(mtmp->mx, mtmp->my); } else mimic_hit_msg(mtmp, otyp); } else pline("%s looks%s better.", Monnam(mtmp), otyp == SPE_EXTRA_HEALING ? " much" : ""); } if (mtmp->mtame || mtmp->mpeaceful) { adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type)); } } else { /* Pestilence */ /* Pestilence will always resist; damage is half of 3d{4,8} */ (void) resist(mtmp, otmp->oclass, d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL); } break; case WAN_LIGHT: /* (broken wand) */ if (flash_hits_mon(mtmp, otmp)) { learn_it = TRUE; reveal_invis = TRUE; } break; case WAN_SLEEP: /* (broken wand) */ /* [wakeup() doesn't rouse victims of temporary sleep, so it's okay to leave `wake' set to TRUE here] */ reveal_invis = TRUE; if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS)) slept_monst(mtmp); if (!Blind) learn_it = TRUE; break; case SPE_STONE_TO_FLESH: if (monsndx(mtmp->data) == PM_STONE_GOLEM) { char *name = Monnam(mtmp); /* turn into flesh golem */ if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) { if (canseemon(mtmp)) pline("%s turns to flesh!", name); } else { if (canseemon(mtmp)) pline("%s looks rather fleshy for a moment.", name); } } else wake = FALSE; break; case SPE_DRAIN_LIFE: dmg = monhp_per_lvl(mtmp); if (dbldam) dmg *= 2; if (otyp == SPE_DRAIN_LIFE) dmg = spell_damage_bonus(dmg); if (resists_drli(mtmp)) shieldeff(mtmp->mx, mtmp->my); else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && mtmp->mhp > 0) { mtmp->mhp -= dmg; mtmp->mhpmax -= dmg; if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) xkilled(mtmp, 1); else { mtmp->m_lev--; if (canseemon(mtmp)) pline("%s suddenly seems weaker!", Monnam(mtmp)); } } break; case WAN_NOTHING: wake = FALSE; break; default: impossible("What an interesting effect (%d)", otyp); break; } if (wake) { if (mtmp->mhp > 0) { wakeup(mtmp); m_respond(mtmp); if (mtmp->isshk && !*u.ushops) hot_pursuit(mtmp); } else if (mtmp->m_ap_type) seemimic(mtmp); /* might unblock if mimicing a boulder/door */ } /* note: bhitpos won't be set if swallowed, but that's okay since * reveal_invis will be false. We can't use mtmp->mx, my since it * might be an invisible worm hit on the tail. */ if (reveal_invis) { if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } /* if effect was observable then discover the wand type provided that the wand itself has been seen */ if (learn_it) learnwand(otmp); return 0; } void probe_monster(mtmp) struct monst *mtmp; { struct obj *otmp; mstatusline(mtmp); if (notonhead) return; /* don't show minvent for long worm tail */ if (mtmp->minvent) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { otmp->dknown = 1; /* treat as "seen" */ if (Is_container(otmp) || otmp->otyp == STATUE) { otmp->lknown = 1; if (!SchroedingersBox(otmp)) otmp->cknown = 1; } } (void) display_minventory(mtmp, MINV_ALL | MINV_NOLET, (char *) 0); } else { pline("%s is not carrying anything%s.", noit_Monnam(mtmp), (u.uswallow && mtmp == u.ustuck) ? " besides you" : ""); } } /* * Return the object's physical location. This only makes sense for * objects that are currently on the level (i.e. migrating objects * are nowhere). By default, only things that can be seen (in hero's * inventory, monster's inventory, or on the ground) are reported. * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get * the location of buried and contained objects. Note that if an * object is carried by a monster, its reported position may change * from turn to turn. This function returns FALSE if the position * is not available or subject to the constraints above. */ boolean get_obj_location(obj, xp, yp, locflags) struct obj *obj; xchar *xp, *yp; int locflags; { switch (obj->where) { case OBJ_INVENT: *xp = u.ux; *yp = u.uy; return TRUE; case OBJ_FLOOR: *xp = obj->ox; *yp = obj->oy; return TRUE; case OBJ_MINVENT: if (obj->ocarry->mx) { *xp = obj->ocarry->mx; *yp = obj->ocarry->my; return TRUE; } break; /* !mx => migrating monster */ case OBJ_BURIED: if (locflags & BURIED_TOO) { *xp = obj->ox; *yp = obj->oy; return TRUE; } break; case OBJ_CONTAINED: if (locflags & CONTAINED_TOO) return get_obj_location(obj->ocontainer, xp, yp, locflags); break; } *xp = *yp = 0; return FALSE; } boolean get_mon_location(mon, xp, yp, locflags) struct monst *mon; xchar *xp, *yp; int locflags; /* non-zero means get location even if monster is buried */ { if (mon == &youmonst) { *xp = u.ux; *yp = u.uy; return TRUE; } else if (mon->mx > 0 && (!mon->mburied || locflags)) { *xp = mon->mx; *yp = mon->my; return TRUE; } else { /* migrating or buried */ *xp = *yp = 0; return FALSE; } } /* used by revive() and animate_statue() */ struct monst * montraits(obj, cc) struct obj *obj; coord *cc; { struct monst *mtmp = (struct monst *) 0; struct monst *mtmp2 = (struct monst *) 0; if (has_omonst(obj)) mtmp2 = get_mtraits(obj, TRUE); if (mtmp2) { /* save_mtraits() validated mtmp2->mnum */ mtmp2->data = &mons[mtmp2->mnum]; if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data)) return (struct monst *) 0; mtmp = makemon(mtmp2->data, cc->x, cc->y, NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH); if (!mtmp) return mtmp; /* heal the monster */ if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data)) mtmp2->mhpmax = mtmp->mhpmax; mtmp2->mhp = mtmp2->mhpmax; /* Get these ones from mtmp */ mtmp2->minvent = mtmp->minvent; /*redundant*/ /* monster ID is available if the monster died in the current game, but will be zero if the corpse was in a bones level (we cleared it when loading bones) */ if (mtmp->m_id) { mtmp2->m_id = mtmp->m_id; /* might be bringing quest leader back to life */ if (quest_status.leader_is_dead && /* leader_is_dead implies leader_m_id is valid */ mtmp2->m_id == quest_status.leader_m_id) quest_status.leader_is_dead = FALSE; } mtmp2->mx = mtmp->mx; mtmp2->my = mtmp->my; mtmp2->mux = mtmp->mux; mtmp2->muy = mtmp->muy; mtmp2->mw = mtmp->mw; mtmp2->wormno = mtmp->wormno; mtmp2->misc_worn_check = mtmp->misc_worn_check; mtmp2->weapon_check = mtmp->weapon_check; mtmp2->mtrapseen = mtmp->mtrapseen; mtmp2->mflee = mtmp->mflee; mtmp2->mburied = mtmp->mburied; mtmp2->mundetected = mtmp->mundetected; mtmp2->mfleetim = mtmp->mfleetim; mtmp2->mlstmv = mtmp->mlstmv; mtmp2->m_ap_type = mtmp->m_ap_type; /* set these ones explicitly */ mtmp2->mrevived = 1; mtmp2->mavenge = 0; mtmp2->meating = 0; mtmp2->mleashed = 0; mtmp2->mtrapped = 0; mtmp2->msleeping = 0; mtmp2->mfrozen = 0; mtmp2->mcanmove = 1; /* most cancelled monsters return to normal, but some need to stay cancelled */ if (!dmgtype(mtmp2->data, AD_SEDU) && (!SYSOPT_SEDUCE || !dmgtype(mtmp2->data, AD_SSEX))) mtmp2->mcan = 0; mtmp2->mcansee = 1; /* set like in makemon */ mtmp2->mblinded = 0; mtmp2->mstun = 0; mtmp2->mconf = 0; replmon(mtmp, mtmp2); newsym(mtmp2->mx, mtmp2->my); /* Might now be invisible */ /* in case Protection_from_shape_changers is different now than it was when the traits were stored */ restore_cham(mtmp2); } return mtmp2; } /* * get_container_location() returns the following information * about the outermost container: * loc argument gets set to: * OBJ_INVENT if in hero's inventory; return 0. * OBJ_FLOOR if on the floor; return 0. * OBJ_BURIED if buried; return 0. * OBJ_MINVENT if in monster's inventory; return monster. * container_nesting is updated with the nesting depth of the containers * if applicable. */ struct monst * get_container_location(obj, loc, container_nesting) struct obj *obj; int *loc; int *container_nesting; { if (!obj || !loc) return 0; if (container_nesting) *container_nesting = 0; while (obj && obj->where == OBJ_CONTAINED) { if (container_nesting) *container_nesting += 1; obj = obj->ocontainer; } if (obj) { *loc = obj->where; /* outermost container's location */ if (obj->where == OBJ_MINVENT) return obj->ocarry; } return (struct monst *) 0; } /* * Attempt to revive the given corpse, return the revived monster if * successful. Note: this does NOT use up the corpse if it fails. */ struct monst * revive(corpse, by_hero) struct obj *corpse; boolean by_hero; { struct monst *mtmp = 0; struct permonst *mptr; struct obj *container; coord xy; xchar x, y; int montype, container_nesting = 0; if (corpse->otyp != CORPSE) { impossible("Attempting to revive %s?", xname(corpse)); return (struct monst *) 0; } x = y = 0; if (corpse->where != OBJ_CONTAINED) { /* only for invent, minvent, or floor */ container = 0; (void) get_obj_location(corpse, &x, &y, 0); } else { /* deal with corpses in [possibly nested] containers */ struct monst *carrier; int holder = OBJ_FREE; container = corpse->ocontainer; carrier = get_container_location(container, &holder, &container_nesting); switch (holder) { case OBJ_MINVENT: x = carrier->mx, y = carrier->my; break; case OBJ_INVENT: x = u.ux, y = u.uy; break; case OBJ_FLOOR: (void) get_obj_location(corpse, &x, &y, CONTAINED_TOO); break; default: break; /* x,y are 0 */ } } if (!x || !y || /* Rules for revival from containers: - the container cannot be locked - the container cannot be heavily nested (>2 is arbitrary) - the container cannot be a statue or bag of holding (except in very rare cases for the latter) */ (container && (container->olocked || container_nesting > 2 || container->otyp == STATUE || (container->otyp == BAG_OF_HOLDING && rn2(40))))) return (struct monst *) 0; /* record the object's location now that we're sure where it is */ corpse->ox = x, corpse->oy = y; /* prepare for the monster */ montype = corpse->corpsenm; mptr = &mons[montype]; /* [should probably handle recorporealization first; if corpse and ghost are at same location, revived creature shouldn't be bumped to an adjacent spot by ghost which joins with it] */ if (MON_AT(x, y)) { if (enexto(&xy, x, y, mptr)) x = xy.x, y = xy.y; } if (mons[montype].mlet == S_EEL && !IS_POOL(levl[x][y].typ)) { if (by_hero && cansee(x,y)) pline("%s twitches feebly.", upstart(corpse_xname(corpse, (const char *) 0, CXN_PFX_THE))); return (struct monst *) 0; } if (cant_revive(&montype, TRUE, corpse)) { /* make a zombie or doppelganger instead */ /* note: montype has changed; mptr keeps old value for newcham() */ mtmp = makemon(&mons[montype], x, y, NO_MINVENT | MM_NOWAIT); if (mtmp) { /* skip ghost handling */ if (has_omid(corpse)) free_omid(corpse); if (has_omonst(corpse)) free_omonst(corpse); if (mtmp->cham == PM_DOPPELGANGER) { /* change shape to match the corpse */ (void) newcham(mtmp, mptr, FALSE, FALSE); } else if (mtmp->data->mlet == S_ZOMBIE) { mtmp->mhp = mtmp->mhpmax = 100; mon_adjust_speed(mtmp, 2, (struct obj *) 0); /* MFAST */ } } } else if (has_omonst(corpse)) { /* use saved traits */ xy.x = x, xy.y = y; mtmp = montraits(corpse, &xy); if (mtmp && mtmp->mtame && !mtmp->isminion) wary_dog(mtmp, TRUE); } else { /* make a new monster */ mtmp = makemon(mptr, x, y, NO_MINVENT | MM_NOWAIT | MM_NOCOUNTBIRTH); } if (!mtmp) return (struct monst *) 0; /* hiders shouldn't already be re-hidden when they revive */ if (mtmp->mundetected) { mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); } if (mtmp->m_ap_type) seemimic(mtmp); /* if this is caused by the hero there might be a shop charge */ if (by_hero) { struct monst *shkp = 0; x = corpse->ox, y = corpse->oy; if (costly_spot(x, y)) shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if (cansee(x, y)) pline( "%s glows iridescently.", upstart(corpse_xname(corpse, (const char *) 0, CXN_PFX_THE))); else if (shkp) /* need some prior description of the corpse since stolen_value() will refer to the object as "it" */ pline("A corpse is resuscitated."); /* don't charge for shopkeeper's own corpse if we just revived him */ if (shkp && mtmp != shkp) (void) stolen_value(corpse, x, y, (boolean) shkp->mpeaceful, FALSE); /* [we don't give any comparable message about the corpse for the !by_hero case because caller might have already done so] */ } /* handle recorporealization of an active ghost */ if (has_omid(corpse)) { unsigned m_id; struct monst *ghost; struct obj *otmp; (void) memcpy((genericptr_t) &m_id, (genericptr_t) OMID(corpse), sizeof m_id); ghost = find_mid(m_id, FM_FMON); if (ghost && ghost->data == &mons[PM_GHOST]) { if (canseemon(ghost)) pline("%s is suddenly drawn into its former body!", Monnam(ghost)); /* transfer the ghost's inventory along with it */ while ((otmp = ghost->minvent) != 0) { obj_extract_self(otmp); add_to_minv(mtmp, otmp); } /* tame the revived monster if its ghost was tame */ if (ghost->mtame && !mtmp->mtame) { if (tamedog(mtmp, (struct obj *) 0)) { /* ghost's edog data is ignored */ mtmp->mtame = ghost->mtame; } } /* was ghost, now alive, it's all very confusing */ mtmp->mconf = 1; /* separate ghost monster no longer exists */ mongone(ghost); } free_omid(corpse); } /* monster retains its name */ if (has_oname(corpse)) mtmp = christen_monst(mtmp, ONAME(corpse)); /* partially eaten corpse yields wounded monster */ if (corpse->oeaten) mtmp->mhp = eaten_stat(mtmp->mhp, corpse); /* track that this monster was revived at least once */ mtmp->mrevived = 1; /* finally, get rid of the corpse--it's gone now */ switch (corpse->where) { case OBJ_INVENT: useup(corpse); break; case OBJ_FLOOR: /* in case MON_AT+enexto for invisible mon */ x = corpse->ox, y = corpse->oy; /* not useupf(), which charges */ if (corpse->quan > 1L) corpse = splitobj(corpse, 1L); delobj(corpse); newsym(x, y); break; case OBJ_MINVENT: m_useup(corpse->ocarry, corpse); break; case OBJ_CONTAINED: obj_extract_self(corpse); obfree(corpse, (struct obj *) 0); break; default: panic("revive"); } return mtmp; } STATIC_OVL void revive_egg(obj) struct obj *obj; { /* * Note: generic eggs with corpsenm set to NON_PM will never hatch. */ if (obj->otyp != EGG) return; if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)) attach_egg_hatch_timeout(obj, 0L); } /* try to revive all corpses and eggs carried by `mon' */ int unturn_dead(mon) struct monst *mon; { struct obj *otmp, *otmp2; struct monst *mtmp2; char owner[BUFSZ], corpse[BUFSZ]; boolean youseeit; int once = 0, res = 0; youseeit = (mon == &youmonst) ? TRUE : canseemon(mon); otmp2 = (mon == &youmonst) ? invent : mon->minvent; while ((otmp = otmp2) != 0) { otmp2 = otmp->nobj; if (otmp->otyp == EGG) revive_egg(otmp); if (otmp->otyp != CORPSE) continue; /* save the name; the object is liable to go away */ if (youseeit) Strcpy(corpse, corpse_xname(otmp, (const char *) 0, CXN_SINGULAR)); /* for a merged group, only one is revived; should this be fixed? */ if ((mtmp2 = revive(otmp, !context.mon_moving)) != 0) { ++res; if (youseeit) { if (!once++) Strcpy(owner, (mon == &youmonst) ? "Your" : s_suffix(Monnam(mon))); pline("%s %s suddenly comes alive!", owner, corpse); } else if (canseemon(mtmp2)) pline("%s suddenly appears!", Amonnam(mtmp2)); } } return res; } /* cancel obj, possibly carried by you or a monster */ void cancel_item(obj) register struct obj *obj; { boolean u_ring = (obj == uleft || obj == uright); int otyp = obj->otyp; switch (otyp) { case RIN_GAIN_STRENGTH: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_STR) -= obj->spe; context.botl = 1; } break; case RIN_GAIN_CONSTITUTION: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CON) -= obj->spe; context.botl = 1; } break; case RIN_ADORNMENT: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CHA) -= obj->spe; context.botl = 1; } break; case RIN_INCREASE_ACCURACY: if ((obj->owornmask & W_RING) && u_ring) u.uhitinc -= obj->spe; break; case RIN_INCREASE_DAMAGE: if ((obj->owornmask & W_RING) && u_ring) u.udaminc -= obj->spe; break; case GAUNTLETS_OF_DEXTERITY: if ((obj->owornmask & W_ARMG) && (obj == uarmg)) { ABON(A_DEX) -= obj->spe; context.botl = 1; } break; case HELM_OF_BRILLIANCE: if ((obj->owornmask & W_ARMH) && (obj == uarmh)) { ABON(A_INT) -= obj->spe; ABON(A_WIS) -= obj->spe; context.botl = 1; } break; /* case RIN_PROTECTION: not needed */ } if (objects[otyp].oc_magic || (obj->spe && (obj->oclass == ARMOR_CLASS || obj->oclass == WEAPON_CLASS || is_weptool(obj))) || otyp == POT_ACID || otyp == POT_SICKNESS || (otyp == POT_WATER && (obj->blessed || obj->cursed))) { if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) && otyp != WAN_CANCELLATION /* can't cancel cancellation */ && otyp != MAGIC_LAMP /* cancelling doesn't remove djinni */ && otyp != CANDELABRUM_OF_INVOCATION) { costly_alteration(obj, COST_CANCEL); obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0; } switch (obj->oclass) { case SCROLL_CLASS: costly_alteration(obj, COST_CANCEL); obj->otyp = SCR_BLANK_PAPER; obj->spe = 0; break; case SPBOOK_CLASS: if (otyp != SPE_CANCELLATION && otyp != SPE_NOVEL && otyp != SPE_BOOK_OF_THE_DEAD) { costly_alteration(obj, COST_CANCEL); obj->otyp = SPE_BLANK_PAPER; } break; case POTION_CLASS: costly_alteration(obj, (otyp != POT_WATER) ? COST_CANCEL : obj->cursed ? COST_UNCURS : COST_UNBLSS); if (otyp == POT_SICKNESS || otyp == POT_SEE_INVISIBLE) { /* sickness is "biologically contaminated" fruit juice; cancel it and it just becomes fruit juice... whereas see invisible tastes like "enchanted" fruit juice, it similarly cancels */ obj->otyp = POT_FRUIT_JUICE; } else { obj->otyp = POT_WATER; obj->odiluted = 0; /* same as any other water */ } break; } } unbless(obj); uncurse(obj); return; } /* Remove a positive enchantment or charge from obj, * possibly carried by you or a monster */ boolean drain_item(obj) register struct obj *obj; { boolean u_ring; /* Is this a charged/enchanted object? */ if (!obj || (!objects[obj->otyp].oc_charged && obj->oclass != WEAPON_CLASS && obj->oclass != ARMOR_CLASS && !is_weptool(obj)) || obj->spe <= 0) return FALSE; if (defends(AD_DRLI, obj) || defends_when_carried(AD_DRLI, obj) || obj_resists(obj, 10, 90)) return FALSE; /* Charge for the cost of the object */ costly_alteration(obj, COST_DRAIN); /* Drain the object and any implied effects */ obj->spe--; u_ring = (obj == uleft) || (obj == uright); switch (obj->otyp) { case RIN_GAIN_STRENGTH: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_STR)--; context.botl = 1; } break; case RIN_GAIN_CONSTITUTION: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CON)--; context.botl = 1; } break; case RIN_ADORNMENT: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CHA)--; context.botl = 1; } break; case RIN_INCREASE_ACCURACY: if ((obj->owornmask & W_RING) && u_ring) u.uhitinc--; break; case RIN_INCREASE_DAMAGE: if ((obj->owornmask & W_RING) && u_ring) u.udaminc--; break; case HELM_OF_BRILLIANCE: if ((obj->owornmask & W_ARMH) && (obj == uarmh)) { ABON(A_INT)--; ABON(A_WIS)--; context.botl = 1; } break; case GAUNTLETS_OF_DEXTERITY: if ((obj->owornmask & W_ARMG) && (obj == uarmg)) { ABON(A_DEX)--; context.botl = 1; } break; case RIN_PROTECTION: context.botl = 1; break; } if (carried(obj)) update_inventory(); return TRUE; } boolean obj_resists(obj, ochance, achance) struct obj *obj; int ochance, achance; /* percent chance for ordinary objects, artifacts */ { if (obj->otyp == AMULET_OF_YENDOR || obj->otyp == SPE_BOOK_OF_THE_DEAD || obj->otyp == CANDELABRUM_OF_INVOCATION || obj->otyp == BELL_OF_OPENING || (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) { return TRUE; } else { int chance = rn2(100); return (boolean) (chance < (obj->oartifact ? achance : ochance)); } } boolean obj_shudders(obj) struct obj *obj; { int zap_odds; if (context.bypasses && obj->bypass) return FALSE; if (obj->oclass == WAND_CLASS) zap_odds = 3; /* half-life = 2 zaps */ else if (obj->cursed) zap_odds = 3; /* half-life = 2 zaps */ else if (obj->blessed) zap_odds = 12; /* half-life = 8 zaps */ else zap_odds = 8; /* half-life = 6 zaps */ /* adjust for "large" quantities of identical things */ if (obj->quan > 4L) zap_odds /= 2; return (boolean) !rn2(zap_odds); } /* Use up at least minwt number of things made of material mat. * There's also a chance that other stuff will be used up. Finally, * there's a random factor here to keep from always using the stuff * at the top of the pile. */ STATIC_OVL void polyuse(objhdr, mat, minwt) struct obj *objhdr; int mat, minwt; { register struct obj *otmp, *otmp2; for (otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (context.bypasses && otmp->bypass) continue; if (otmp == uball || otmp == uchain) continue; if (obj_resists(otmp, 0, 0)) continue; /* preserve unique objects */ #ifdef MAIL if (otmp->otyp == SCR_MAIL) continue; #endif if (((int) objects[otmp->otyp].oc_material == mat) == (rn2(minwt + 1) != 0)) { /* appropriately add damage to bill */ if (costly_spot(otmp->ox, otmp->oy)) { if (*u.ushops) addtobill(otmp, FALSE, FALSE, FALSE); else (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); } if (otmp->quan < LARGEST_INT) minwt -= (int) otmp->quan; else minwt = 0; delobj(otmp); } } } /* * Polymorph some of the stuff in this pile into a monster, preferably * a golem of the kind okind. */ STATIC_OVL void create_polymon(obj, okind) struct obj *obj; int okind; { struct permonst *mdat = (struct permonst *) 0; struct monst *mtmp; const char *material; int pm_index; if (context.bypasses) { /* this is approximate because the "no golems" !obj->nexthere check below doesn't understand bypassed objects; but it should suffice since bypassed objects always end up as a consecutive group at the top of their pile */ while (obj && obj->bypass) obj = obj->nexthere; } /* no golems if you zap only one object -- not enough stuff */ if (!obj || (!obj->nexthere && obj->quan == 1L)) return; /* some of these choices are arbitrary */ switch (okind) { case IRON: case METAL: case MITHRIL: pm_index = PM_IRON_GOLEM; material = "metal "; break; case COPPER: case SILVER: case PLATINUM: case GEMSTONE: case MINERAL: pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM; material = "lithic "; break; case 0: case FLESH: /* there is no flesh type, but all food is type 0, so we use it */ pm_index = PM_FLESH_GOLEM; material = "organic "; break; case WOOD: pm_index = PM_WOOD_GOLEM; material = "wood "; break; case LEATHER: pm_index = PM_LEATHER_GOLEM; material = "leather "; break; case CLOTH: pm_index = PM_ROPE_GOLEM; material = "cloth "; break; case BONE: pm_index = PM_SKELETON; /* nearest thing to "bone golem" */ material = "bony "; break; case GOLD: pm_index = PM_GOLD_GOLEM; material = "gold "; break; case GLASS: pm_index = PM_GLASS_GOLEM; material = "glassy "; break; case PAPER: pm_index = PM_PAPER_GOLEM; material = "paper "; break; default: /* if all else fails... */ pm_index = PM_STRAW_GOLEM; material = ""; break; } if (!(mvitals[pm_index].mvflags & G_GENOD)) mdat = &mons[pm_index]; mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS); polyuse(obj, okind, (int) mons[pm_index].cwt); if (mtmp && cansee(mtmp->mx, mtmp->my)) { pline("Some %sobjects meld, and %s arises from the pile!", material, a_monnam(mtmp)); } } /* Assumes obj is on the floor. */ void do_osshock(obj) struct obj *obj; { long i; #ifdef MAIL if (obj->otyp == SCR_MAIL) return; #endif obj_zapped = TRUE; if (poly_zapped < 0) { /* some may metamorphosize */ for (i = obj->quan; i; i--) if (!rn2(Luck + 45)) { poly_zapped = objects[obj->otyp].oc_material; break; } } /* if quan > 1 then some will survive intact */ if (obj->quan > 1L) { if (obj->quan > LARGEST_INT) obj = splitobj(obj, (long) rnd(30000)); else obj = splitobj(obj, (long) rnd((int) obj->quan - 1)); } /* appropriately add damage to bill */ if (costly_spot(obj->ox, obj->oy)) { if (*u.ushops) addtobill(obj, FALSE, FALSE, FALSE); else (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE); } /* zap the object */ delobj(obj); } /* classes of items whose current charge count carries over across polymorph */ static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, '\0' }; /* * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT * then pick random object from the source's class (this is the standard * "polymorph" case). If ID is set to a specific object, inhibit fusing * n objects into 1. This could have been added as a flag, but currently * it is tied to not being the standard polymorph case. The new polymorphed * object replaces obj in its link chains. Return value is a pointer to * the new object. * * This should be safe to call for an object anywhere. */ struct obj * poly_obj(obj, id) struct obj *obj; int id; { struct obj *otmp; xchar ox, oy; boolean can_merge = (id == STRANGE_OBJECT); int obj_location = obj->where; if (obj->otyp == BOULDER) sokoban_guilt(); if (id == STRANGE_OBJECT) { /* preserve symbol */ int try_limit = 3; unsigned magic_obj = objects[obj->otyp].oc_magic; if (obj->otyp == UNICORN_HORN && obj->degraded_horn) magic_obj = 0; /* Try up to 3 times to make the magic-or-not status of the new item be the same as it was for the old one. */ otmp = (struct obj *) 0; do { if (otmp) delobj(otmp); otmp = mkobj(obj->oclass, FALSE); } while (--try_limit > 0 && objects[otmp->otyp].oc_magic != magic_obj); } else { /* literally replace obj with this new thing */ otmp = mksobj(id, FALSE, FALSE); /* Actually more things use corpsenm but they polymorph differently */ #define USES_CORPSENM(typ) \ ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE) if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id)) set_corpsenm(otmp, obj->corpsenm); #undef USES_CORPSENM } /* preserve quantity */ otmp->quan = obj->quan; /* preserve the shopkeepers (lack of) interest */ otmp->no_charge = obj->no_charge; /* preserve inventory letter if in inventory */ if (obj_location == OBJ_INVENT) otmp->invlet = obj->invlet; #ifdef MAIL /* You can't send yourself 100 mail messages and then * polymorph them into useful scrolls */ if (obj->otyp == SCR_MAIL) { otmp->otyp = SCR_MAIL; otmp->spe = 1; } #endif /* avoid abusing eggs laid by you */ if (obj->otyp == EGG && obj->spe) { int mnum, tryct = 100; /* first, turn into a generic egg */ if (otmp->otyp == EGG) kill_egg(otmp); else { otmp->otyp = EGG; otmp->owt = weight(otmp); } otmp->corpsenm = NON_PM; otmp->spe = 0; /* now change it into something laid by the hero */ while (tryct--) { mnum = can_be_hatched(random_monster()); if (mnum != NON_PM && !dead_species(mnum, TRUE)) { otmp->spe = 1; /* laid by hero */ set_corpsenm(otmp, mnum); /* also sets hatch timer */ break; } } } /* keep special fields (including charges on wands) */ if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe; otmp->recharged = obj->recharged; otmp->cursed = obj->cursed; otmp->blessed = obj->blessed; otmp->oeroded = obj->oeroded; otmp->oeroded2 = obj->oeroded2; if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0; if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0; if (is_damageable(otmp)) otmp->oerodeproof = obj->oerodeproof; /* Keep chest/box traps and poisoned ammo if we may */ if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE; if (obj->opoisoned && is_poisonable(otmp)) otmp->opoisoned = TRUE; if (id == STRANGE_OBJECT && obj->otyp == CORPSE) { /* turn crocodile corpses into shoes */ if (obj->corpsenm == PM_CROCODILE) { otmp->otyp = LOW_BOOTS; otmp->oclass = ARMOR_CLASS; otmp->spe = 0; otmp->oeroded = 0; otmp->oerodeproof = TRUE; otmp->quan = 1L; otmp->cursed = FALSE; } } /* no box contents --KAA */ if (Has_contents(otmp)) delete_contents(otmp); /* 'n' merged objects may be fused into 1 object */ if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge || (can_merge && otmp->quan > (long) rn2(1000)))) otmp->quan = 1L; switch (otmp->oclass) { case TOOL_CLASS: if (otmp->otyp == MAGIC_LAMP) { otmp->otyp = OIL_LAMP; otmp->age = 1500L; /* "best" oil lamp possible */ } else if (otmp->otyp == MAGIC_MARKER) { otmp->recharged = 1; /* degraded quality */ } /* don't care about the recharge count of other tools */ break; case WAND_CLASS: while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH) otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); /* altering the object tends to degrade its quality (analogous to spellbook `read count' handling) */ if ((int) otmp->recharged < rn2(7)) /* recharge_limit */ otmp->recharged++; break; case POTION_CLASS: while (otmp->otyp == POT_POLYMORPH) otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER); break; case SPBOOK_CLASS: while (otmp->otyp == SPE_POLYMORPH) otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER); /* reduce spellbook abuse; non-blank books degrade */ if (otmp->otyp != SPE_BLANK_PAPER) { otmp->spestudied = obj->spestudied + 1; if (otmp->spestudied > MAX_SPELL_STUDY) { otmp->otyp = SPE_BLANK_PAPER; /* writing a new book over it will yield an unstudied one; re-polymorphing this one as-is may or may not get something non-blank */ otmp->spestudied = rn2(otmp->spestudied); } } break; case GEM_CLASS: if (otmp->quan > (long) rnd(4) && objects[obj->otyp].oc_material == MINERAL && objects[otmp->otyp].oc_material != MINERAL) { otmp->otyp = ROCK; /* transmutation backfired */ otmp->quan /= 2L; /* some material has been lost */ } break; } /* update the weight */ otmp->owt = weight(otmp); /* handle polymorph of worn item: stone-to-flesh cast on self can affect multiple objects at once, but their new forms won't produce any side-effects; a single worn item dipped into potion of polymorph can produce side-effects but those won't yield out of sequence messages because current polymorph is finished */ if (obj_location == OBJ_INVENT && obj->owornmask) { long old_wornmask = obj->owornmask & ~(W_ART | W_ARTI), new_wornmask = wearslot(otmp); boolean was_twohanded = bimanual(obj), was_twoweap = u.twoweap; remove_worn_item(obj, TRUE); /* if the new form can be worn in the same slot, make it so [possible extension: if it could be worn in some other slot which is currently unfilled, wear it there instead] */ if ((old_wornmask & W_QUIVER) != 0L) { setuqwep(otmp); } else if ((old_wornmask & W_SWAPWEP) != 0L) { if (was_twohanded || !bimanual(otmp)) setuswapwep(otmp); if (was_twoweap && uswapwep) u.twoweap = TRUE; } else if ((old_wornmask & W_WEP) != 0L) { if (was_twohanded || !bimanual(otmp) || !uarms) setuwep(otmp); if (was_twoweap && uwep && !bimanual(uwep)) u.twoweap = TRUE; } else if ((old_wornmask & new_wornmask) != 0L) { new_wornmask &= old_wornmask; setworn(otmp, new_wornmask); set_wear(otmp); /* Armor_on() for side-effects */ } } /* ** we are now done adjusting the object ** */ /* swap otmp for obj */ replace_object(obj, otmp); if (obj_location == OBJ_INVENT) { /* * We may need to do extra adjustments for the hero if we're * messing with the hero's inventory. The following calls are * equivalent to calling freeinv on obj and addinv on otmp, * while doing an in-place swap of the actual objects. */ freeinv_core(obj); addinv_core1(otmp); addinv_core2(otmp); } else if (obj_location == OBJ_FLOOR) { ox = otmp->ox, oy = otmp->oy; /* set by replace_object() */ if (obj->otyp == BOULDER && otmp->otyp != BOULDER && !does_block(ox, oy, &levl[ox][oy])) unblock_point(ox, oy); else if (obj->otyp != BOULDER && otmp->otyp == BOULDER) /* (checking does_block() here would be redundant) */ block_point(ox, oy); } if ((!carried(otmp) || obj->unpaid) && get_obj_location(otmp, &ox, &oy, BURIED_TOO | CONTAINED_TOO) && costly_spot(ox, oy)) { register struct monst *shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE)); if ((!obj->no_charge || (Has_contents(obj) && (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L))) && inhishop(shkp)) { if (shkp->mpeaceful) { if (*u.ushops && *in_rooms(u.ux, u.uy, 0) == *in_rooms(shkp->mx, shkp->my, 0) && !costly_spot(u.ux, u.uy)) make_angry_shk(shkp, ox, oy); else { pline("%s gets angry!", Monnam(shkp)); hot_pursuit(shkp); } } else Norep("%s is furious!", Monnam(shkp)); } } delobj(obj); return otmp; } /* stone-to-flesh spell hits and maybe transforms or animates obj */ STATIC_OVL int stone_to_flesh_obj(obj) struct obj *obj; { int res = 1; /* affected object by default */ struct permonst *ptr; struct monst *mon; struct obj *item; xchar oox, ooy; boolean smell = FALSE, golem_xform = FALSE; if (objects[obj->otyp].oc_material != MINERAL && objects[obj->otyp].oc_material != GEMSTONE) return 0; /* Heart of Ahriman usually resists; ordinary items rarely do */ if (obj_resists(obj, 2, 98)) return 0; (void) get_obj_location(obj, &oox, &ooy, 0); /* add more if stone objects are added.. */ switch (objects[obj->otyp].oc_class) { case ROCK_CLASS: /* boulders and statues */ case TOOL_CLASS: /* figurines */ if (obj->otyp == BOULDER) { obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT); smell = TRUE; } else if (obj->otyp == STATUE || obj->otyp == FIGURINE) { ptr = &mons[obj->corpsenm]; if (is_golem(ptr)) { golem_xform = (ptr != &mons[PM_FLESH_GOLEM]); } else if (vegetarian(ptr)) { /* Don't animate monsters that aren't flesh */ obj = poly_obj(obj, MEATBALL); smell = TRUE; break; } if (obj->otyp == STATUE) { /* animate_statue() forces all golems to become flesh golems */ mon = animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *) 0); } else { /* (obj->otyp == FIGURINE) */ if (golem_xform) ptr = &mons[PM_FLESH_GOLEM]; mon = makemon(ptr, oox, ooy, NO_MINVENT); if (mon) { if (costly_spot(oox, ooy) && !obj->no_charge) { if (costly_spot(u.ux, u.uy)) addtobill(obj, carried(obj), FALSE, FALSE); else stolen_value(obj, oox, ooy, TRUE, FALSE); } if (obj->timed) obj_stop_timers(obj); if (carried(obj)) useup(obj); else delobj(obj); if (cansee(mon->mx, mon->my)) pline_The("figurine %sanimates!", golem_xform ? "turns to flesh and " : ""); } } if (mon) { ptr = mon->data; /* this golem handling is redundant... */ if (is_golem(ptr) && ptr != &mons[PM_FLESH_GOLEM]) (void) newcham(mon, &mons[PM_FLESH_GOLEM], TRUE, FALSE); } else if ((ptr->geno & (G_NOCORPSE | G_UNIQ)) != 0) { /* didn't revive but can't leave corpse either */ res = 0; } else { /* unlikely to get here since genociding monsters also sets the G_NOCORPSE flag; drop statue's contents */ while ((item = obj->cobj) != 0) { bypass_obj(item); /* make stone-to-flesh miss it */ obj_extract_self(item); place_object(item, oox, ooy); } obj = poly_obj(obj, CORPSE); } } else { /* miscellaneous tool or unexpected rock... */ res = 0; } break; /* maybe add weird things to become? */ case RING_CLASS: /* some of the rings are stone */ obj = poly_obj(obj, MEAT_RING); smell = TRUE; break; case WAND_CLASS: /* marble wand */ obj = poly_obj(obj, MEAT_STICK); smell = TRUE; break; case GEM_CLASS: /* stones & gems */ obj = poly_obj(obj, MEATBALL); smell = TRUE; break; case WEAPON_CLASS: /* crysknife */ /*FALLTHRU*/ default: res = 0; break; } if (smell) { /* non-meat eaters smell meat, meat eaters smell its flavor; monks are considered non-meat eaters regardless of behavior; other roles are non-meat eaters if they haven't broken vegetarian conduct yet (or if poly'd into non-carnivorous/ non-omnivorous form, regardless of whether it's herbivorous, non-eating, or something stranger) */ if (Role_if(PM_MONK) || !u.uconduct.unvegetarian || !carnivorous(youmonst.data)) Norep("You smell the odor of meat."); else Norep("You smell a delicious smell."); } newsym(oox, ooy); return res; } /* * Object obj was hit by the effect of the wand/spell otmp. Return * non-zero if the wand/spell had any effect. */ int bhito(obj, otmp) struct obj *obj, *otmp; { int res = 1; /* affected object by default */ boolean learn_it = FALSE, maybelearnit; /* fundamental: a wand effect hitting itself doesn't do anything; otherwise we need to guard against accessing otmp after something strange has happened to it (along the lines of polymorph or stone-to-flesh [which aren't good examples since polymorph wands aren't affected by polymorph zaps and stone-to-flesh isn't available in wand form, but the concept still applies...]) */ if (obj == otmp) return 0; if (obj->bypass) { /* The bypass bit is currently only used as follows: * * POLYMORPH - When a monster being polymorphed drops something * from its inventory as a result of the change. * If the items fall to the floor, they are not * subject to direct subsequent polymorphing * themselves on that same zap. This makes it * consistent with items that remain in the * monster's inventory. They are not polymorphed * either. * UNDEAD_TURNING - When an undead creature gets killed via * undead turning, prevent its corpse from being * immediately revived by the same effect. * STONE_TO_FLESH - If a statue can't be revived, its * contents get dropped before turning it into * meat; prevent those contents from being hit. * retouch_equipment() - bypass flag is used to track which * items have been handled (bhito isn't involved). * menu_drop(), askchain() - inventory traversal where multiple * Drop can alter the invent chain while traversal * is in progress (bhito isn't involved). * * The bypass bit on all objects is reset each turn, whenever * context.bypasses is set. * * We check the obj->bypass bit above AND context.bypasses * as a safeguard against any stray occurrence left in an obj * struct someplace, although that should never happen. */ if (context.bypasses) { return 0; } else { debugpline1("%s for a moment.", Tobjnam(obj, "pulsate")); obj->bypass = 0; } } /* * Some parts of this function expect the object to be on the floor * obj->{ox,oy} to be valid. The exception to this (so far) is * for the STONE_TO_FLESH spell. */ if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH)) impossible("bhito: obj is not floor or Stone To Flesh spell"); if (obj == uball) { res = 0; } else if (obj == uchain) { if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) { learn_it = TRUE; unpunish(); } else res = 0; } else switch (otmp->otyp) { case WAN_POLYMORPH: case SPE_POLYMORPH: if (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH || obj->otyp == POT_POLYMORPH || obj_resists(obj, 5, 95)) { res = 0; break; } /* KMH, conduct */ u.uconduct.polypiles++; /* any saved lock context will be dangerously obsolete */ if (Is_box(obj)) (void) boxlock(obj, otmp); if (obj_shudders(obj)) { boolean cover = ((obj == level.objects[u.ux][u.uy]) && u.uundetected && hides_under(youmonst.data)); if (cansee(obj->ox, obj->oy)) learn_it = TRUE; do_osshock(obj); /* eek - your cover might have been blown */ if (cover) (void) hideunder(&youmonst); break; } obj = poly_obj(obj, STRANGE_OBJECT); newsym(obj->ox, obj->oy); break; case WAN_PROBING: res = !obj->dknown; /* target object has now been "seen (up close)" */ obj->dknown = 1; if (Is_container(obj) || obj->otyp == STATUE) { obj->cknown = obj->lknown = 1; if (!obj->cobj) { boolean catbox = SchroedingersBox(obj); /* we don't want to force alive vs dead determination for Schroedinger's Cat here, so just make probing be inconclusive for it */ if (catbox) obj->cknown = 0; pline("%s empty.", Tobjnam(obj, catbox ? "seem" : "are")); } else { struct obj *o; /* view contents (not recursively) */ for (o = obj->cobj; o; o = o->nobj) o->dknown = 1; /* "seen", even if blind */ (void) display_cinventory(obj); } res = 1; } if (res) learn_it = TRUE; break; case WAN_STRIKING: case SPE_FORCE_BOLT: /* learn the type if you see or hear something break (the sound could be implicit) */ maybelearnit = cansee(obj->ox, obj->oy) || !Deaf; if (obj->otyp == BOULDER) { if (cansee(obj->ox, obj->oy)) pline_The("boulder falls apart."); else You_hear("a crumbling sound."); fracture_rock(obj); } else if (obj->otyp == STATUE) { if (break_statue(obj)) { if (cansee(obj->ox, obj->oy)) { if (Hallucination) pline_The("%s shatters.", rndmonnam(NULL)); else pline_The("statue shatters."); } else You_hear("a crumbling sound."); } } else { if (context.mon_moving ? !breaks(obj, obj->ox, obj->oy) : !hero_breaks(obj, obj->ox, obj->oy, FALSE)) maybelearnit = FALSE; /* nothing broke */ res = 0; } if (maybelearnit) learn_it = TRUE; break; case WAN_CANCELLATION: case SPE_CANCELLATION: cancel_item(obj); #ifdef TEXTCOLOR newsym(obj->ox, obj->oy); /* might change color */ #endif break; case SPE_DRAIN_LIFE: (void) drain_item(obj); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: (void) rloco(obj); break; case WAN_MAKE_INVISIBLE: break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: if (obj->otyp == EGG) { revive_egg(obj); } else if (obj->otyp == CORPSE) { int corpsenm = corpse_revive_type(obj); res = !!revive(obj, TRUE); if (res && Role_if(PM_HEALER)) { if (Hallucination && !Deaf) { You_hear("the sound of a defibrillator."); learn_it = TRUE; } else if (!Blind) { You("observe %s %s change dramatically.", s_suffix(an(mons[corpsenm].mname)), nonliving(&mons[corpsenm]) ? "motility" : "health"); learn_it = TRUE; } if (learn_it) exercise(A_WIS, TRUE); } } break; case WAN_OPENING: case SPE_KNOCK: case WAN_LOCKING: case SPE_WIZARD_LOCK: if (Is_box(obj)) res = boxlock(obj, otmp); else res = 0; if (res) learn_it = TRUE; break; case WAN_SLOW_MONSTER: /* no effect on objects */ case SPE_SLOW_MONSTER: case WAN_SPEED_MONSTER: case WAN_NOTHING: case SPE_HEALING: case SPE_EXTRA_HEALING: res = 0; break; case SPE_STONE_TO_FLESH: res = stone_to_flesh_obj(obj); break; default: impossible("What an interesting effect (%d)", otmp->otyp); break; } /* if effect was observable then discover the wand type provided that the wand itself has been seen */ if (learn_it) learnwand(otmp); return res; } /* returns nonzero if something was hit */ int bhitpile(obj, fhito, tx, ty, zz) struct obj *obj; int FDECL((*fhito), (OBJ_P, OBJ_P)); int tx, ty; schar zz; { int hitanything = 0; register struct obj *otmp, *next_obj; if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) { struct trap *t = t_at(tx, ty); /* We can't settle for the default calling sequence of bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy) because that last call might end up operating on our `next_obj' (below), rather than on the current object, if it happens to encounter a statue which mustn't become animated. */ if (t && t->ttyp == STATUE_TRAP && activate_statue_trap(t, tx, ty, TRUE)) learnwand(obj); } poly_zapped = -1; for (otmp = level.objects[tx][ty]; otmp; otmp = next_obj) { next_obj = otmp->nexthere; /* for zap downwards, don't hit object poly'd hero is hiding under */ if (zz > 0 && u.uundetected && otmp == level.objects[u.ux][u.uy] && hides_under(youmonst.data)) continue; hitanything += (*fhito)(otmp, obj); } if (poly_zapped >= 0) create_polymon(level.objects[tx][ty], poly_zapped); return hitanything; } /* * zappable - returns 1 if zap is available, 0 otherwise. * it removes a charge from the wand if zappable. * added by GAN 11/03/86 */ int zappable(wand) register struct obj *wand; { if (wand->spe < 0 || (wand->spe == 0 && rn2(121))) return 0; if (wand->spe == 0) You("wrest one last charge from the worn-out wand."); wand->spe--; return 1; } /* * zapnodir - zaps a NODIR wand/spell. * added by GAN 11/03/86 */ void zapnodir(obj) register struct obj *obj; { boolean known = FALSE; switch (obj->otyp) { case WAN_LIGHT: case SPE_LIGHT: litroom(TRUE, obj); if (!Blind) known = TRUE; if (lightdamage(obj, TRUE, 5)) known = TRUE; break; case WAN_SECRET_DOOR_DETECTION: case SPE_DETECT_UNSEEN: if (!findit()) return; if (!Blind) known = TRUE; break; case WAN_CREATE_MONSTER: known = create_critters(rn2(23) ? 1 : rn1(7, 2), (struct permonst *) 0, FALSE); break; case WAN_WISHING: known = TRUE; if (Luck + rn2(5) < 0) { pline("Unfortunately, nothing happens."); break; } makewish(); break; case WAN_ENLIGHTENMENT: known = TRUE; You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); pline_The("feeling subsides."); exercise(A_WIS, TRUE); break; } if (known) { if (!objects[obj->otyp].oc_name_known) more_experienced(0, 10); /* effect was observable; discover the wand type provided that the wand itself has been seen */ learnwand(obj); } } STATIC_OVL void backfire(otmp) struct obj *otmp; { int dmg; otmp->in_use = TRUE; /* in case losehp() is fatal */ pline("%s suddenly explodes!", The(xname(otmp))); dmg = d(otmp->spe + 2, 6); losehp(Maybe_Half_Phys(dmg), "exploding wand", KILLED_BY_AN); useup(otmp); } static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 }; /* 'z' command (or 'y' if numbed_pad==-1) */ int dozap() { register struct obj *obj; int damage; if (check_capacity((char *) 0)) return 0; obj = getobj(zap_syms, "zap"); if (!obj) return 0; check_unpaid(obj); /* zappable addition done by GAN 11/03/86 */ if (!zappable(obj)) pline1(nothing_happens); else if (obj->cursed && !rn2(WAND_BACKFIRE_CHANCE)) { backfire(obj); /* the wand blows up in your face! */ exercise(A_STR, FALSE); return 1; } else if (!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *) 0)) { if (!Blind) pline("%s glows and fades.", The(xname(obj))); /* make him pay for knowing !NODIR */ } else if (!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) { if ((damage = zapyourself(obj, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "zapped %sself with a wand", uhim()); losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX); } } else { /* Are we having fun yet? * weffects -> buzz(obj->otyp) -> zhitm (temple priest) -> * attack -> hitum -> known_hitum -> ghod_hitsu -> * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) -> * useup -> obfree -> dealloc_obj -> free(obj) */ current_wand = obj; weffects(obj); obj = current_wand; current_wand = 0; } if (obj && obj->spe < 0) { pline("%s to dust.", Tobjnam(obj, "turn")); useup(obj); } update_inventory(); /* maybe used a charge */ return 1; } int zapyourself(obj, ordinary) struct obj *obj; boolean ordinary; { boolean learn_it = FALSE; int damage = 0; switch (obj->otyp) { case WAN_STRIKING: case SPE_FORCE_BOLT: learn_it = TRUE; if (Antimagic) { shieldeff(u.ux, u.uy); pline("Boing!"); } else { if (ordinary) { You("bash yourself!"); damage = d(2, 12); } else damage = d(1 + obj->spe, 6); exercise(A_STR, FALSE); } break; case WAN_LIGHTNING: learn_it = TRUE; if (!Shock_resistance) { You("shock yourself!"); damage = d(12, 6); exercise(A_CON, FALSE); } else { shieldeff(u.ux, u.uy); You("zap yourself, but seem unharmed."); ugolemeffects(AD_ELEC, d(12, 6)); } destroy_item(WAND_CLASS, AD_ELEC); destroy_item(RING_CLASS, AD_ELEC); (void) flashburn((long) rnd(100)); break; case SPE_FIREBALL: You("explode a fireball on top of yourself!"); explode(u.ux, u.uy, 11, d(6, 6), WAND_CLASS, EXPL_FIERY); break; case WAN_FIRE: case FIRE_HORN: learn_it = TRUE; if (Fire_resistance) { shieldeff(u.ux, u.uy); You_feel("rather warm."); ugolemeffects(AD_FIRE, d(12, 6)); } else { pline("You've set yourself afire!"); damage = d(12, 6); } burn_away_slime(); (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(FOOD_CLASS, AD_FIRE); /* only slime for now */ break; case WAN_COLD: case SPE_CONE_OF_COLD: case FROST_HORN: learn_it = TRUE; if (Cold_resistance) { shieldeff(u.ux, u.uy); You_feel("a little chill."); ugolemeffects(AD_COLD, d(12, 6)); } else { You("imitate a popsicle!"); damage = d(12, 6); } destroy_item(POTION_CLASS, AD_COLD); break; case WAN_MAGIC_MISSILE: case SPE_MAGIC_MISSILE: learn_it = TRUE; if (Antimagic) { shieldeff(u.ux, u.uy); pline_The("missiles bounce!"); } else { damage = d(4, 6); pline("Idiot! You've shot yourself!"); } break; case WAN_POLYMORPH: case SPE_POLYMORPH: if (!Unchanging) { learn_it = TRUE; polyself(0); } break; case WAN_CANCELLATION: case SPE_CANCELLATION: (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); break; case SPE_DRAIN_LIFE: if (!Drain_resistance) { learn_it = TRUE; /* (no effect for spells...) */ losexp("life drainage"); } damage = 0; /* No additional damage */ break; case WAN_MAKE_INVISIBLE: { /* have to test before changing HInvis but must change * HInvis before doing newsym(). */ int msg = !Invis && !Blind && !BInvis; if (BInvis && uarmc->otyp == MUMMY_WRAPPING) { /* A mummy wrapping absorbs it and protects you */ You_feel("rather itchy under %s.", yname(uarmc)); break; } if (ordinary || !rn2(10)) { /* permanent */ HInvis |= FROMOUTSIDE; } else { /* temporary */ incr_itimeout(&HInvis, d(obj->spe, 250)); } if (msg) { learn_it = TRUE; newsym(u.ux, u.uy); self_invis_message(); } break; } case WAN_SPEED_MONSTER: if (!(HFast & INTRINSIC)) { learn_it = TRUE; if (!Fast) You("speed up."); else Your("quickness feels more natural."); exercise(A_DEX, TRUE); } HFast |= FROMOUTSIDE; break; case WAN_SLEEP: case SPE_SLEEP: learn_it = TRUE; if (Sleep_resistance) { shieldeff(u.ux, u.uy); You("don't feel sleepy!"); } else { pline_The("sleep ray hits you!"); fall_asleep(-rnd(50), TRUE); } break; case WAN_SLOW_MONSTER: case SPE_SLOW_MONSTER: if (HFast & (TIMEOUT | INTRINSIC)) { learn_it = TRUE; u_slow_down(); } break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: tele(); /* same criteria as when mounted (zap_steed) */ if ((Teleport_control && !Stunned) || !couldsee(u.ux0, u.uy0) || distu(u.ux0, u.uy0) >= 16) learn_it = TRUE; break; case WAN_DEATH: case SPE_FINGER_OF_DEATH: if (nonliving(youmonst.data) || is_demon(youmonst.data)) { pline((obj->otyp == WAN_DEATH) ? "The wand shoots an apparently harmless beam at you." : "You seem no deader than before."); break; } learn_it = TRUE; Sprintf(killer.name, "shot %sself with a death ray", uhim()); killer.format = NO_KILLER_PREFIX; You("irradiate yourself with pure energy!"); You("die."); /* They might survive with an amulet of life saving */ done(DIED); break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: learn_it = TRUE; (void) unturn_dead(&youmonst); if (is_undead(youmonst.data)) { You_feel("frightened and %sstunned.", Stunned ? "even more " : ""); make_stunned((HStun & TIMEOUT) + (long) rnd(30), FALSE); } else You("shudder in dread."); break; case SPE_HEALING: case SPE_EXTRA_HEALING: learn_it = TRUE; /* (no effect for spells...) */ healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4), 0, FALSE, (obj->otyp == SPE_EXTRA_HEALING)); You_feel("%sbetter.", obj->otyp == SPE_EXTRA_HEALING ? "much " : ""); break; case WAN_LIGHT: /* (broken wand) */ /* assert( !ordinary ); */ damage = d(obj->spe, 25); case EXPENSIVE_CAMERA: if (!damage) damage = 5; damage = lightdamage(obj, ordinary, damage); damage += rnd(25); if (flashburn((long) damage)) learn_it = TRUE; damage = 0; /* reset */ break; case WAN_OPENING: case SPE_KNOCK: if (Punished) { learn_it = TRUE; unpunish(); } if (u.utrap) { /* escape web or bear trap */ (void) openholdingtrap(&youmonst, &learn_it); } else { /* trigger previously escaped trapdoor */ (void) openfallingtrap(&youmonst, TRUE, &learn_it); } break; case WAN_LOCKING: case SPE_WIZARD_LOCK: if (!u.utrap) { (void) closeholdingtrap(&youmonst, &learn_it); } break; case WAN_DIGGING: case SPE_DIG: case SPE_DETECT_UNSEEN: case WAN_NOTHING: break; case WAN_PROBING: { struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) { otmp->dknown = 1; if (Is_container(otmp) || otmp->otyp == STATUE) { otmp->lknown = 1; if (!SchroedingersBox(otmp)) otmp->cknown = 1; } } learn_it = TRUE; ustatusline(); break; } case SPE_STONE_TO_FLESH: { struct obj *otmp, *onxt; boolean didmerge; if (u.umonnum == PM_STONE_GOLEM) { learn_it = TRUE; (void) polymon(PM_FLESH_GOLEM); } if (Stoned) { learn_it = TRUE; fix_petrification(); /* saved! */ } /* but at a cost.. */ for (otmp = invent; otmp; otmp = onxt) { onxt = otmp->nobj; if (bhito(otmp, obj)) learn_it = TRUE; } /* * It is possible that we can now merge some inventory. * Do a highly paranoid merge. Restart from the beginning * until no merges. */ do { didmerge = FALSE; for (otmp = invent; !didmerge && otmp; otmp = otmp->nobj) for (onxt = otmp->nobj; onxt; onxt = onxt->nobj) if (merged(&otmp, &onxt)) { didmerge = TRUE; break; } } while (didmerge); break; } default: impossible("zapyourself: object %d used?", obj->otyp); break; } /* if effect was observable then discover the wand type provided that the wand itself has been seen */ if (learn_it) learnwand(obj); return damage; } /* called when poly'd hero uses breath attack against self */ void ubreatheu(mattk) struct attack *mattk; { int dtyp = 20 + mattk->adtyp - 1; /* breath by hero */ const char *fltxt = flash_types[dtyp]; /* blast of */ zhitu(dtyp, mattk->damn, fltxt, u.ux, u.uy); } /* light damages hero in gremlin form */ int lightdamage(obj, ordinary, amt) struct obj *obj; /* item making light (fake book if spell) */ boolean ordinary; /* wand/camera zap vs wand destruction */ int amt; /* pseudo-damage used to determine blindness duration */ { char buf[BUFSZ]; const char *how; int dmg = amt; if (dmg && youmonst.data == &mons[PM_GREMLIN]) { /* reduce high values (from destruction of wand with many charges) */ dmg = rnd(dmg); if (dmg > 10) dmg = 10 + rnd(dmg - 10); if (dmg > 20) dmg = 20; pline("Ow, that light hurts%c", (dmg > 2 || u.mh <= 5) ? '!' : '.'); /* [composing killer/reason is superfluous here; if fatal, cause of death will always be "killed while stuck in creature form"] */ if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) ordinary = FALSE; /* say blasted rather than zapped */ how = (obj->oclass != SPBOOK_CLASS) ? (const char *) ansimpleoname(obj) : "spell of light"; Sprintf(buf, "%s %sself with %s", ordinary ? "zapped" : "blasted", uhim(), how); /* might rehumanize(); could be fatal, but only for Unchanging */ losehp(Maybe_Half_Phys(dmg), buf, NO_KILLER_PREFIX); } return dmg; } /* light[ning] causes blindness */ boolean flashburn(duration) long duration; { if (!resists_blnd(&youmonst)) { You(are_blinded_by_the_flash); make_blinded(duration, FALSE); if (!Blind) Your1(vision_clears); return TRUE; } return FALSE; } /* you've zapped a wand downwards while riding * Return TRUE if the steed was hit by the wand. * Return FALSE if the steed was not hit by the wand. */ STATIC_OVL boolean zap_steed(obj) struct obj *obj; /* wand or spell */ { int steedhit = FALSE; switch (obj->otyp) { /* * Wands that are allowed to hit the steed * Carefully test the results of any that are * moved here from the bottom section. */ case WAN_PROBING: probe_monster(u.usteed); learnwand(obj); steedhit = TRUE; break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: /* you go together */ tele(); /* same criteria as when unmounted (zapyourself) */ if ((Teleport_control && !Stunned) || !couldsee(u.ux0, u.uy0) || distu(u.ux0, u.uy0) >= 16) learnwand(obj); steedhit = TRUE; break; /* Default processing via bhitm() for these */ case SPE_CURE_SICKNESS: case WAN_MAKE_INVISIBLE: case WAN_CANCELLATION: case SPE_CANCELLATION: case WAN_POLYMORPH: case SPE_POLYMORPH: case WAN_STRIKING: case SPE_FORCE_BOLT: case WAN_SLOW_MONSTER: case SPE_SLOW_MONSTER: case WAN_SPEED_MONSTER: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case WAN_OPENING: case SPE_KNOCK: (void) bhitm(u.usteed, obj); steedhit = TRUE; break; default: steedhit = FALSE; break; } return steedhit; } /* * cancel a monster (possibly the hero). inventory is cancelled only * if the monster is zapping itself directly, since otherwise the * effect is too strong. currently non-hero monsters do not zap * themselves with cancellation. */ boolean cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel) register struct monst *mdef; register struct obj *obj; boolean youattack, allow_cancel_kill, self_cancel; { boolean youdefend = (mdef == &youmonst); static const char writing_vanishes[] = "Some writing vanishes from %s head!"; static const char your[] = "your"; /* should be extern */ if (youdefend ? (!youattack && Antimagic) : resist(mdef, obj->oclass, 0, NOTELL)) return FALSE; /* resisted cancellation */ if (self_cancel) { /* 1st cancel inventory */ struct obj *otmp; for (otmp = (youdefend ? invent : mdef->minvent); otmp; otmp = otmp->nobj) cancel_item(otmp); if (youdefend) { context.botl = 1; /* potential AC change */ find_ac(); } } /* now handle special cases */ if (youdefend) { if (Upolyd) { if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) pline(writing_vanishes, your); if (Unchanging) Your("amulet grows hot for a moment, then cools."); else rehumanize(); } } else { mdef->mcan = TRUE; if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) were_change(mdef); if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (canseemon(mdef)) pline(writing_vanishes, s_suffix(mon_nam(mdef))); if (allow_cancel_kill) { if (youattack) killed(mdef); else monkilled(mdef, "", AD_SPEL); } } } return TRUE; } /* you've zapped an immediate type wand up or down */ STATIC_OVL boolean zap_updown(obj) struct obj *obj; /* wand or spell */ { boolean striking = FALSE, disclose = FALSE; int x, y, xx, yy, ptmp; struct obj *otmp; struct engr *e; struct trap *ttmp; char buf[BUFSZ]; /* some wands have special effects other than normal bhitpile */ /* drawbridge might change */ x = xx = u.ux; /* is zap location */ y = yy = u.uy; /* is drawbridge (portcullis) position */ ttmp = t_at(x, y); /* trap if there is one */ switch (obj->otyp) { case WAN_PROBING: ptmp = 0; if (u.dz < 0) { You("probe towards the %s.", ceiling(x, y)); } else { ptmp += bhitpile(obj, bhito, x, y, u.dz); You("probe beneath the %s.", surface(x, y)); ptmp += display_binventory(x, y, TRUE); } if (!ptmp) Your("probe reveals nothing."); return TRUE; /* we've done our own bhitpile */ case WAN_OPENING: case SPE_KNOCK: /* up or down, but at closed portcullis only */ if (is_db_wall(x, y) && find_drawbridge(&xx, &yy)) { open_drawbridge(xx, yy); disclose = TRUE; } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) && /* can't use the stairs down to quest level 2 until leader "unlocks" them; give feedback if you try */ on_level(&u.uz, &qstart_level) && !ok_to_quest()) { pline_The("stairs seem to ripple momentarily."); disclose = TRUE; } /* down will release you from bear trap or web */ if (u.dz > 0 && u.utrap) { (void) openholdingtrap(&youmonst, &disclose); /* down will trigger trapdoor, hole, or [spiked-] pit */ } else if (u.dz > 0 && !u.utrap) { (void) openfallingtrap(&youmonst, FALSE, &disclose); } break; case WAN_STRIKING: case SPE_FORCE_BOLT: striking = TRUE; /*FALLTHRU*/ case WAN_LOCKING: case SPE_WIZARD_LOCK: /* down at open bridge or up or down at open portcullis */ if (((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) : (is_drawbridge_wall(x, y) >= 0 && !is_db_wall(x, y))) && find_drawbridge(&xx, &yy)) { if (!striking) close_drawbridge(xx, yy); else destroy_drawbridge(xx, yy); disclose = TRUE; } else if (striking && u.dz < 0 && rn2(3) && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater && !Is_qstart(&u.uz)) { int dmg; /* similar to zap_dig() */ pline("A rock is dislodged from the %s and falls on your %s.", ceiling(x, y), body_part(HEAD)); dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6); losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN); if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) { (void) xname(otmp); /* set dknown, maybe bknown */ stackobj(otmp); } newsym(x, y); } else if (u.dz > 0 && ttmp) { if (!striking && closeholdingtrap(&youmonst, &disclose)) { ; /* now stuck in web or bear trap */ } else if (striking && ttmp->ttyp == TRAPDOOR) { /* striking transforms trapdoor into hole */ if (Blind && !ttmp->tseen) { pline("%s beneath you shatters.", Something); } else if (!ttmp->tseen) { /* => !Blind */ pline("There's a trapdoor beneath you; it shatters."); } else { pline("The trapdoor beneath you shatters."); disclose = TRUE; } ttmp->ttyp = HOLE; ttmp->tseen = 1; newsym(x, y); /* might fall down hole */ dotrap(ttmp, 0); } else if (!striking && ttmp->ttyp == HOLE) { /* locking transforms hole into trapdoor */ ttmp->ttyp = TRAPDOOR; if (Blind || !ttmp->tseen) { pline("Some %s swirls beneath you.", is_ice(x, y) ? "frost" : "dust"); } else { ttmp->tseen = 1; newsym(x, y); pline("A trapdoor appears beneath you."); disclose = TRUE; } /* hadn't fallen down hole; won't fall now */ } } break; case SPE_STONE_TO_FLESH: if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || Underwater || (Is_qstart(&u.uz) && u.dz < 0)) { pline1(nothing_happens); } else if (u.dz < 0) { /* we should do more... */ pline("Blood drips on your %s.", body_part(FACE)); } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) { /* Print this message only if there wasn't an engraving affected here. If water or ice, act like waterlevel case. */ e = engr_at(u.ux, u.uy); if (!(e && e->engr_type == ENGRAVE)) { if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy)) pline1(nothing_happens); else pline("Blood %ss %s your %s.", is_lava(u.ux, u.uy) ? "boil" : "pool", Levitation ? "beneath" : "at", makeplural(body_part(FOOT))); } } break; default: break; } if (u.dz > 0) { /* zapping downward */ (void) bhitpile(obj, bhito, x, y, u.dz); /* subset of engraving effects; none sets `disclose' */ if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) { switch (obj->otyp) { case WAN_POLYMORPH: case SPE_POLYMORPH: del_engr(e); make_engr_at(x, y, random_engraving(buf), moves, (xchar) 0); break; case WAN_CANCELLATION: case SPE_CANCELLATION: case WAN_MAKE_INVISIBLE: del_engr(e); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: rloc_engr(e); break; case SPE_STONE_TO_FLESH: if (e->engr_type == ENGRAVE) { /* only affects things in stone */ pline_The(Hallucination ? "floor runs like butter!" : "edges on the floor get smoother."); wipe_engr_at(x, y, d(2, 4), TRUE); } break; case WAN_STRIKING: case SPE_FORCE_BOLT: wipe_engr_at(x, y, d(2, 4), TRUE); break; default: break; } } } else if (u.dz < 0) { /* zapping upward */ /* game flavor: if you're hiding under "something" * a zap upward should hit that "something". */ if (u.uundetected && hides_under(youmonst.data)) { int hitit = 0; otmp = level.objects[u.ux][u.uy]; if (otmp) hitit = bhito(otmp, obj); if (hitit) { (void) hideunder(&youmonst); disclose = TRUE; } } } return disclose; } /* used by do_break_wand() was well as by weffects() */ void zapsetup() { obj_zapped = FALSE; } void zapwrapup() { /* if do_osshock() set obj_zapped while polying, give a message now */ if (obj_zapped) You_feel("shuddering vibrations."); obj_zapped = FALSE; } /* called for various wand and spell effects - M. Stephenson */ void weffects(obj) struct obj *obj; { int otyp = obj->otyp; boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known; exercise(A_WIS, TRUE); if (u.usteed && (objects[otyp].oc_dir != NODIR) && !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) { disclose = TRUE; } else if (objects[otyp].oc_dir == IMMEDIATE) { zapsetup(); /* reset obj_zapped */ if (u.uswallow) { (void) bhitm(u.ustuck, obj); /* [how about `bhitpile(u.ustuck->minvent)' effect?] */ } else if (u.dz) { disclose = zap_updown(obj); } else { (void) bhit(u.dx, u.dy, rn1(8, 6), ZAPPED_WAND, bhitm, bhito, &obj); } zapwrapup(); /* give feedback for obj_zapped */ } else if (objects[otyp].oc_dir == NODIR) { zapnodir(obj); } else { /* neither immediate nor directionless */ if (otyp == WAN_DIGGING || otyp == SPE_DIG) zap_dig(); else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH) buzz(otyp - SPE_MAGIC_MISSILE + 10, u.ulevel / 2 + 1, u.ux, u.uy, u.dx, u.dy); else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING) buzz(otyp - WAN_MAGIC_MISSILE, (otyp == WAN_MAGIC_MISSILE) ? 2 : 6, u.ux, u.uy, u.dx, u.dy); else impossible("weffects: unexpected spell or wand"); disclose = TRUE; } if (disclose) { learnwand(obj); if (was_unkn) more_experienced(0, 10); } return; } /* augment damage for a spell dased on the hero's intelligence (and level) */ int spell_damage_bonus(dmg) int dmg; /* base amount to be adjusted by bonus or penalty */ { int intell = ACURR(A_INT); /* Punish low intelligence before low level else low intelligence gets punished only when high level */ if (intell <= 9) { /* -3 penalty, but never reduce combined amount below 1 (if dmg is 0 for some reason, we're careful to leave it there) */ if (dmg > 1) dmg = (dmg <= 3) ? 1 : dmg - 3; } else if (intell <= 13 || u.ulevel < 5) ; /* no bonus or penalty; dmg remains same */ else if (intell <= 18) dmg += 1; else if (intell <= 24 || u.ulevel < 14) dmg += 2; else dmg += 3; /* Int 25 */ return dmg; } /* * Generate the to hit bonus for a spell. Based on the hero's skill in * spell class and dexterity. */ STATIC_OVL int spell_hit_bonus(skill) int skill; { int hit_bon = 0; int dex = ACURR(A_DEX); switch (P_SKILL(spell_skilltype(skill))) { case P_ISRESTRICTED: case P_UNSKILLED: hit_bon = -4; break; case P_BASIC: hit_bon = 0; break; case P_SKILLED: hit_bon = 2; break; case P_EXPERT: hit_bon = 3; break; } if (dex < 4) hit_bon -= 3; else if (dex < 6) hit_bon -= 2; else if (dex < 8) hit_bon -= 1; else if (dex < 14) /* Will change when print stuff below removed */ hit_bon -= 0; else /* Even increment for dextrous heroes (see weapon.c abon) */ hit_bon += dex - 14; return hit_bon; } const char * exclam(force) int force; { /* force == 0 occurs e.g. with sleep ray */ /* note that large force is usual with wands so that !! would require information about hand/weapon/wand */ return (const char *) ((force < 0) ? "?" : (force <= 4) ? "." : "!"); } void hit(str, mtmp, force) const char *str; struct monst *mtmp; const char *force; /* usually either "." or "!" */ { if ((!cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp) && !(u.uswallow && mtmp == u.ustuck)) || !flags.verbose) pline("%s %s it.", The(str), vtense(str, "hit")); else pline("%s %s %s%s", The(str), vtense(str, "hit"), mon_nam(mtmp), force); } void miss(str, mtmp) register const char *str; register struct monst *mtmp; { pline( "%s %s %s.", The(str), vtense(str, "miss"), ((cansee(bhitpos.x, bhitpos.y) || canspotmon(mtmp)) && flags.verbose) ? mon_nam(mtmp) : "it"); } STATIC_OVL void skiprange(range, skipstart, skipend) int range, *skipstart, *skipend; { int tr = (range / 4); int tmp = range - ((tr > 0) ? rnd(tr) : 0); *skipstart = tmp; *skipend = tmp - ((tmp / 4) * rnd(3)); if (*skipend >= tmp) *skipend = tmp - 1; } /* * Called for the following distance effects: * when a weapon is thrown (weapon == THROWN_WEAPON) * when an object is kicked (KICKED_WEAPON) * when an IMMEDIATE wand is zapped (ZAPPED_WAND) * when a light beam is flashed (FLASHED_LIGHT) * when a mirror is applied (INVIS_BEAM) * A thrown/kicked object falls down at end of its range or when a monster * is hit. The variable 'bhitpos' is set to the final position of the weapon * thrown/zapped. The ray of a wand may affect (by calling a provided * function) several objects and monsters on its path. The return value * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer. * * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be * destroyed and *pobj set to NULL to indicate this. * * Check !u.uswallow before calling bhit(). * This function reveals the absence of a remembered invisible monster in * necessary cases (throwing or kicking weapons). The presence of a real * one is revealed for a weapon, but if not a weapon is left up to fhitm(). */ struct monst * bhit(ddx, ddy, range, weapon, fhitm, fhito, pobj) register int ddx, ddy, range; /* direction and range */ int weapon; /* see values in hack.h */ int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */ FDECL((*fhito), (OBJ_P, OBJ_P)); struct obj **pobj; /* object tossed/used, set to NULL * if object is destroyed */ { struct monst *mtmp; struct obj *obj = *pobj; uchar typ; boolean shopdoor = FALSE, point_blank = TRUE; boolean in_skip = FALSE, allow_skip = FALSE; int skiprange_start = 0, skiprange_end = 0, skipcount = 0; if (weapon == KICKED_WEAPON) { /* object starts one square in front of player */ bhitpos.x = u.ux + ddx; bhitpos.y = u.uy + ddy; range--; } else { bhitpos.x = u.ux; bhitpos.y = u.uy; } if (weapon == THROWN_WEAPON && obj && obj->otyp == ROCK) { skiprange(range, &skiprange_start, &skiprange_end); allow_skip = !rn2(3); } if (weapon == FLASHED_LIGHT) { tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam)); } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_FLASH, obj_to_glyph(obj)); while (range-- > 0) { int x, y; bhitpos.x += ddx; bhitpos.y += ddy; x = bhitpos.x; y = bhitpos.y; if (!isok(x, y)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (is_pick(obj) && inside_shop(x, y) && (mtmp = shkcatch(obj, x, y))) { tmp_at(DISP_END, 0); return mtmp; } typ = levl[bhitpos.x][bhitpos.y].typ; /* iron bars will block anything big enough */ if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && typ == IRONBARS && hits_bars(pobj, x - ddx, y - ddy, point_blank ? 0 : !rn2(5), 1)) { /* caveat: obj might now be null... */ obj = *pobj; bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (weapon == ZAPPED_WAND && find_drawbridge(&x, &y)) { boolean learn_it = FALSE; switch (obj->otyp) { case WAN_OPENING: case SPE_KNOCK: if (is_db_wall(bhitpos.x, bhitpos.y)) { if (cansee(x, y) || cansee(bhitpos.x, bhitpos.y)) learn_it = TRUE; open_drawbridge(x, y); } break; case WAN_LOCKING: case SPE_WIZARD_LOCK: if ((cansee(x, y) || cansee(bhitpos.x, bhitpos.y)) && levl[x][y].typ == DRAWBRIDGE_DOWN) learn_it = TRUE; close_drawbridge(x, y); break; case WAN_STRIKING: case SPE_FORCE_BOLT: if (typ != DRAWBRIDGE_UP) destroy_drawbridge(x, y); learn_it = TRUE; break; } if (learn_it) learnwand(obj); } mtmp = m_at(bhitpos.x, bhitpos.y); /* * skipping rocks * * skiprange_start is only set if this is a thrown rock */ if (skiprange_start && (range == skiprange_start) && allow_skip) { if (is_pool(bhitpos.x, bhitpos.y) && !mtmp) { in_skip = TRUE; if (!Blind) pline("%s %s%s.", Yname2(obj), otense(obj, "skip"), skipcount ? " again" : ""); else You_hear("%s skip.", yname(obj)); skipcount++; } else if (skiprange_start > skiprange_end + 1) { --skiprange_start; } } if (in_skip) { if (range <= skiprange_end) { in_skip = FALSE; if (range > 3) /* another bounce? */ skiprange(range, &skiprange_start, &skiprange_end); } else if (mtmp && M_IN_WATER(mtmp->data)) { if ((!Blind && canseemon(mtmp)) || sensemon(mtmp)) pline("%s %s over %s.", Yname2(obj), otense(obj, "pass"), mon_nam(mtmp)); } } if (mtmp && !(in_skip && M_IN_WATER(mtmp->data))) { notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my); if (weapon == FLASHED_LIGHT) { /* FLASHED_LIGHT hitting invisible monster should pass through instead of stop so we call flash_hits_mon() directly rather than returning mtmp back to caller. That allows the flash to keep on going. Note that we use mtmp->minvis not canspotmon() because it makes no difference whether the hero can see the monster or not. */ if (mtmp->minvis) { obj->ox = u.ux, obj->oy = u.uy; (void) flash_hits_mon(mtmp, obj); } else { tmp_at(DISP_END, 0); return mtmp; /* caller will call flash_hits_mon */ } } else if (weapon == INVIS_BEAM) { /* Like FLASHED_LIGHT, INVIS_BEAM should continue through invisible targets; unlike it, we aren't prepared for multiple hits so just get first one that's either visible or could see its invisible self. [No tmp_at() cleanup is needed here.] */ if (!mtmp->minvis || perceives(mtmp->data)) return mtmp; } else if (weapon != ZAPPED_WAND) { /* THROWN_WEAPON, KICKED_WEAPON */ tmp_at(DISP_END, 0); if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); return mtmp; } else { /* ZAPPED_WAND */ (*fhitm)(mtmp, obj); range -= 3; } } else { if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING && glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) { unmap_object(bhitpos.x, bhitpos.y); newsym(x, y); } } if (fhito) { if (bhitpile(obj, fhito, bhitpos.x, bhitpos.y, 0)) range--; } else { if (weapon == KICKED_WEAPON && ((obj->oclass == COIN_CLASS && OBJ_AT(bhitpos.x, bhitpos.y)) || ship_object(obj, bhitpos.x, bhitpos.y, costly_spot(bhitpos.x, bhitpos.y)))) { tmp_at(DISP_END, 0); return (struct monst *) 0; } } if (weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) { switch (obj->otyp) { case WAN_OPENING: case WAN_LOCKING: case WAN_STRIKING: case SPE_KNOCK: case SPE_WIZARD_LOCK: case SPE_FORCE_BOLT: if (doorlock(obj, bhitpos.x, bhitpos.y)) { if (cansee(bhitpos.x, bhitpos.y) || (obj->otyp == WAN_STRIKING && !Deaf)) learnwand(obj); if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) { shopdoor = TRUE; add_damage(bhitpos.x, bhitpos.y, 400L); } } break; } } if (!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) { /* 'I' present but no monster: erase */ /* do this before the tmp_at() */ if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) && cansee(x, y)) { unmap_object(bhitpos.x, bhitpos.y); newsym(x, y); } tmp_at(bhitpos.x, bhitpos.y); delay_output(); /* kicked objects fall in pools */ if ((weapon == KICKED_WEAPON) && (is_pool(bhitpos.x, bhitpos.y) || is_lava(bhitpos.x, bhitpos.y))) break; if (IS_SINK(typ) && weapon != FLASHED_LIGHT) break; /* physical objects fall onto sink */ } /* limit range of ball so hero won't make an invalid move */ if (weapon == THROWN_WEAPON && range > 0 && obj->otyp == HEAVY_IRON_BALL) { struct obj *bobj; struct trap *t; if ((bobj = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x, y)) pline("%s hits %s.", The(distant_name(obj, xname)), an(xname(bobj))); range = 0; } else if (obj == uball) { if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) { /* nb: it didn't hit anything directly */ if (cansee(x, y)) pline("%s jerks to an abrupt halt.", The(distant_name(obj, xname))); /* lame */ range = 0; } else if (Sokoban && (t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { /* hero falls into the trap, so ball stops */ range = 0; } } } /* thrown/kicked missile has moved away from its starting spot */ point_blank = FALSE; /* affects passing through iron bars */ } if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0); if (shopdoor) pay_for_damage("destroy", FALSE); return (struct monst *) 0; } /* process thrown boomerang, which travels a curving path... * A multi-shot volley ought to have all missiles in flight at once, * but we're called separately for each one. We terminate the volley * early on a failed catch since continuing to throw after being hit * is too obviously silly. */ struct monst * boomhit(obj, dx, dy) struct obj *obj; int dx, dy; { register int i, ct; int boom; /* showsym[] index */ struct monst *mtmp; boolean counterclockwise = TRUE; /* right-handed throw */ /* counterclockwise traversal patterns: * ..........................54................................. * ..................43.....6..3....765......................... * ..........32.....5..2...7...2...8...4....87.................. * .........4..1....6..1...8..1....9...3...9..6.....98.......... * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9.. * .3...9....6..9....89.....................1..4...1..6....1..8. * .4...8.....78.............................23....2..5...2...7. * ..567............................................34....3..6.. * ........................................................45... * (invert rows for corresponding clockwise patterns) */ bhitpos.x = u.ux; bhitpos.y = u.uy; boom = counterclockwise ? S_boomleft : S_boomright; for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break; tmp_at(DISP_FLASH, cmap_to_glyph(boom)); for (ct = 0; ct < 10; ct++) { i = (i + 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */ boom = (S_boomleft + S_boomright - boom); /* toggle */ tmp_at(DISP_CHANGE, cmap_to_glyph(boom)); /* change glyph */ dx = xdir[i]; dy = ydir[i]; bhitpos.x += dx; bhitpos.y += dy; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { m_respond(mtmp); tmp_at(DISP_END, 0); return mtmp; } if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) || closed_door(bhitpos.x, bhitpos.y)) { bhitpos.x -= dx; bhitpos.y -= dy; break; } if (bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */ if (Fumbling || rn2(20) >= ACURR(A_DEX)) { /* we hit ourselves */ (void) thitu(10 + obj->spe, dmgval(obj, &youmonst), obj, "boomerang"); endmultishot(TRUE); break; } else { /* we catch it */ tmp_at(DISP_END, 0); You("skillfully catch the boomerang."); return &youmonst; } } tmp_at(bhitpos.x, bhitpos.y); delay_output(); if (IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) { if (!Deaf) pline("Klonk!"); break; /* boomerang falls on sink */ } /* ct==0, initial position, we want next delta to be same; ct==5, opposite position, repeat delta undoes first one */ if (ct % 5 != 0) i += (counterclockwise ? -1 : 1); } tmp_at(DISP_END, 0); /* do not leave last symbol */ return (struct monst *) 0; } /* used by buzz(); also used by munslime(muse.c); returns damage to mon */ int zhitm(mon, type, nd, ootmp) register struct monst *mon; register int type, nd; struct obj **ootmp; /* to return worn armor for caller to disintegrate */ { register int tmp = 0; register int abstype = abs(type) % 10; boolean sho_shieldeff = FALSE; boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */ *ootmp = (struct obj *) 0; switch (abstype) { case ZT_MAGIC_MISSILE: if (resists_magm(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd, 6); if (spellcaster) tmp = spell_damage_bonus(tmp); break; case ZT_FIRE: if (resists_fire(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd, 6); if (resists_cold(mon)) tmp += 7; if (spellcaster) tmp = spell_damage_bonus(tmp); if (burnarmor(mon)) { if (!rn2(3)) (void) destroy_mitem(mon, POTION_CLASS, AD_FIRE); if (!rn2(3)) (void) destroy_mitem(mon, SCROLL_CLASS, AD_FIRE); if (!rn2(5)) (void) destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE); destroy_mitem(mon, FOOD_CLASS, AD_FIRE); /* carried slime */ } break; case ZT_COLD: if (resists_cold(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd, 6); if (resists_fire(mon)) tmp += d(nd, 3); if (spellcaster) tmp = spell_damage_bonus(tmp); if (!rn2(3)) (void) destroy_mitem(mon, POTION_CLASS, AD_COLD); break; case ZT_SLEEP: tmp = 0; (void) sleep_monst(mon, d(nd, 25), type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0'); break; case ZT_DEATH: /* death/disintegration */ if (abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */ if (mon->data == &mons[PM_DEATH]) { mon->mhpmax += mon->mhpmax / 2; if (mon->mhpmax >= MAGIC_COOKIE) mon->mhpmax = MAGIC_COOKIE - 1; mon->mhp = mon->mhpmax; tmp = 0; break; } if (nonliving(mon->data) || is_demon(mon->data) || is_vampshifter(mon) || resists_magm(mon)) { /* similar to player */ sho_shieldeff = TRUE; break; } type = -1; /* so they don't get saving throws */ } else { struct obj *otmp2; if (resists_disint(mon)) { sho_shieldeff = TRUE; } else if (mon->misc_worn_check & W_ARMS) { /* destroy shield; victim survives */ *ootmp = which_armor(mon, W_ARMS); } else if (mon->misc_worn_check & W_ARM) { /* destroy body armor, also cloak if present */ *ootmp = which_armor(mon, W_ARM); if ((otmp2 = which_armor(mon, W_ARMC)) != 0) m_useup(mon, otmp2); } else { /* no body armor, victim dies; destroy cloak and shirt now in case target gets life-saved */ tmp = MAGIC_COOKIE; if ((otmp2 = which_armor(mon, W_ARMC)) != 0) m_useup(mon, otmp2); if ((otmp2 = which_armor(mon, W_ARMU)) != 0) m_useup(mon, otmp2); } type = -1; /* no saving throw wanted */ break; /* not ordinary damage */ } tmp = mon->mhp + 1; break; case ZT_LIGHTNING: if (resists_elec(mon)) { sho_shieldeff = TRUE; tmp = 0; /* can still blind the monster */ } else tmp = d(nd, 6); if (spellcaster) tmp = spell_damage_bonus(tmp); if (!resists_blnd(mon) && !(type > 0 && u.uswallow && mon == u.ustuck)) { register unsigned rnd_tmp = rnd(50); mon->mcansee = 0; if ((mon->mblinded + rnd_tmp) > 127) mon->mblinded = 127; else mon->mblinded += rnd_tmp; } if (!rn2(3)) (void) destroy_mitem(mon, WAND_CLASS, AD_ELEC); /* not actually possible yet */ if (!rn2(3)) (void) destroy_mitem(mon, RING_CLASS, AD_ELEC); break; case ZT_POISON_GAS: if (resists_poison(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd, 6); break; case ZT_ACID: if (resists_acid(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd, 6); if (!rn2(6)) acid_damage(MON_WEP(mon)); if (!rn2(6)) erode_armor(mon, ERODE_CORRODE); break; } if (sho_shieldeff) shieldeff(mon->mx, mon->my); if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart)) tmp *= 2; if (tmp > 0 && type >= 0 && resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL)) tmp /= 2; if (tmp < 0) tmp = 0; /* don't allow negative damage */ debugpline3("zapped monster hp = %d (= %d - %d)", mon->mhp - tmp, mon->mhp, tmp); mon->mhp -= tmp; return tmp; } STATIC_OVL void zhitu(type, nd, fltxt, sx, sy) int type, nd; const char *fltxt; xchar sx, sy; { int dam = 0, abstyp = abs(type); switch (abstyp % 10) { case ZT_MAGIC_MISSILE: if (Antimagic) { shieldeff(sx, sy); pline_The("missiles bounce off!"); } else { dam = d(nd, 6); exercise(A_STR, FALSE); } break; case ZT_FIRE: if (Fire_resistance) { shieldeff(sx, sy); You("don't feel hot!"); ugolemeffects(AD_FIRE, d(nd, 6)); } else { dam = d(nd, 6); } burn_away_slime(); if (burnarmor(&youmonst)) { /* "body hit" */ if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE); if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE); if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(FOOD_CLASS, AD_FIRE); } break; case ZT_COLD: if (Cold_resistance) { shieldeff(sx, sy); You("don't feel cold."); ugolemeffects(AD_COLD, d(nd, 6)); } else { dam = d(nd, 6); } if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD); break; case ZT_SLEEP: if (Sleep_resistance) { shieldeff(u.ux, u.uy); You("don't feel sleepy."); } else { fall_asleep(-d(nd, 25), TRUE); /* sleep ray */ } break; case ZT_DEATH: if (abstyp == ZT_BREATH(ZT_DEATH)) { if (Disint_resistance) { You("are not disintegrated."); break; } else if (uarms) { /* destroy shield; other possessions are safe */ (void) destroy_arm(uarms); break; } else if (uarm) { /* destroy suit; if present, cloak goes too */ if (uarmc) (void) destroy_arm(uarmc); (void) destroy_arm(uarm); break; } /* no shield or suit, you're dead; wipe out cloak and/or shirt in case of life-saving or bones */ if (uarmc) (void) destroy_arm(uarmc); if (uarmu) (void) destroy_arm(uarmu); } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) { shieldeff(sx, sy); You("seem unaffected."); break; } else if (Antimagic) { shieldeff(sx, sy); You("aren't affected."); break; } killer.format = KILLED_BY_AN; Strcpy(killer.name, fltxt ? fltxt : ""); /* when killed by disintegration breath, don't leave corpse */ u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM; done(DIED); return; /* lifesaved */ case ZT_LIGHTNING: if (Shock_resistance) { shieldeff(sx, sy); You("aren't affected."); ugolemeffects(AD_ELEC, d(nd, 6)); } else { dam = d(nd, 6); exercise(A_CON, FALSE); } if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC); if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC); break; case ZT_POISON_GAS: poisoned("blast", A_DEX, "poisoned blast", 15, FALSE); break; case ZT_ACID: if (Acid_resistance) { pline_The("acid doesn't hurt."); dam = 0; } else { pline_The("acid burns!"); dam = d(nd, 6); exercise(A_STR, FALSE); } /* using two weapons at once makes both of them more vulnerable */ if (!rn2(u.twoweap ? 3 : 6)) acid_damage(uwep); if (u.twoweap && !rn2(3)) acid_damage(uswapwep); if (!rn2(6)) erode_armor(&youmonst, ERODE_CORRODE); break; } /* Half_spell_damage protection yields half-damage for wands & spells, including hero's own ricochets; breath attacks do full damage */ if (dam && Half_spell_damage && !(abstyp >= 20 && abstyp <= 29)) dam = (dam + 1) / 2; losehp(dam, fltxt, KILLED_BY_AN); return; } /* * burn objects (such as scrolls and spellbooks) on floor * at position x,y; return the number of objects burned */ int burn_floor_objects(x, y, give_feedback, u_caused) int x, y; boolean give_feedback; /* caller needs to decide about visibility checks */ boolean u_caused; { struct obj *obj, *obj2; long i, scrquan, delquan; char buf1[BUFSZ], buf2[BUFSZ]; int cnt = 0; for (obj = level.objects[x][y]; obj; obj = obj2) { obj2 = obj->nexthere; if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS || (obj->oclass == FOOD_CLASS && obj->otyp == GLOB_OF_GREEN_SLIME)) { if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL || obj_resists(obj, 2, 100)) continue; scrquan = obj->quan; /* number present */ delquan = 0L; /* number to destroy */ for (i = scrquan; i > 0L; i--) if (!rn2(3)) delquan++; if (delquan) { /* save name before potential delobj() */ if (give_feedback) { obj->quan = 1L; Strcpy(buf1, (x == u.ux && y == u.uy) ? xname(obj) : distant_name(obj, xname)); obj->quan = 2L; Strcpy(buf2, (x == u.ux && y == u.uy) ? xname(obj) : distant_name(obj, xname)); obj->quan = scrquan; } /* useupf(), which charges, only if hero caused damage */ if (u_caused) useupf(obj, delquan); else if (delquan < scrquan) obj->quan -= delquan; else delobj(obj); cnt += delquan; if (give_feedback) { if (delquan > 1L) pline("%ld %s burn.", delquan, buf2); else pline("%s burns.", An(buf1)); } } } } return cnt; } /* will zap/spell/breath attack score a hit against armor class `ac'? */ STATIC_OVL int zap_hit(ac, type) int ac; int type; /* either hero cast spell type or 0 */ { int chance = rn2(20); int spell_bonus = type ? spell_hit_bonus(type) : 0; /* small chance for naked target to avoid being hit */ if (!chance) return rnd(10) < ac + spell_bonus; /* very high armor protection does not achieve invulnerability */ ac = AC_VALUE(ac); return (3 - chance < ac + spell_bonus); } STATIC_OVL void disintegrate_mon(mon, type, fltxt) struct monst *mon; int type; /* hero vs other */ const char *fltxt; { struct obj *otmp, *otmp2, *m_amulet = mlifesaver(mon); if (canseemon(mon)) { if (!m_amulet) pline("%s is disintegrated!", Monnam(mon)); else hit(fltxt, mon, "!"); } /* note: worn amulet of life saving must be preserved in order to operate */ #define oresist_disintegration(obj) \ (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \ || is_quest_artifact(obj) || obj == m_amulet) for (otmp = mon->minvent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (!oresist_disintegration(otmp)) { if (otmp->owornmask) { /* in case monster's life gets saved */ mon->misc_worn_check &= ~otmp->owornmask; if (otmp->owornmask & W_WEP) setmnotwielded(mon, otmp); /* also dismounts hero if this object is steed's saddle */ update_mon_intrinsics(mon, otmp, FALSE, TRUE); otmp->owornmask = 0L; } obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } } #undef oresist_disintegration if (type < 0) monkilled(mon, (char *) 0, -AD_RBRE); else xkilled(mon, 2); } /* * type == 0 to 9 : you shooting a wand * type == 10 to 19 : you casting a spell * type == 20 to 29 : you breathing as a monster * type == -10 to -19 : monster casting spell * type == -20 to -29 : monster breathing at you * type == -30 to -39 : monster shooting a wand * called with dx = dy = 0 with vertical bolts */ void buzz(type, nd, sx, sy, dx, dy) register int type, nd; register xchar sx, sy; register int dx, dy; { int range, abstype = abs(type) % 10; struct rm *lev; register xchar lsx, lsy; struct monst *mon; coord save_bhitpos; boolean shopdamage = FALSE; const char *fltxt; struct obj *otmp; int spell_type; /* if its a Hero Spell then get its SPE_TYPE */ spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0; fltxt = flash_types[(type <= -30) ? abstype : abs(type)]; if (u.uswallow) { register int tmp; if (type < 0) return; tmp = zhitm(u.ustuck, type, nd, &otmp); if (!u.ustuck) u.uswallow = 0; else pline("%s rips into %s%s", The(fltxt), mon_nam(u.ustuck), exclam(tmp)); /* Using disintegration from the inside only makes a hole... */ if (tmp == MAGIC_COOKIE) u.ustuck->mhp = 0; if (u.ustuck->mhp < 1) killed(u.ustuck); return; } if (type < 0) newsym(u.ux, u.uy); range = rn1(7, 7); if (dx == 0 && dy == 0) range = 1; save_bhitpos = bhitpos; tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype)); while (range-- > 0) { lsx = sx; sx += dx; lsy = sy; sy += dy; if (isok(sx, sy) && (lev = &levl[sx][sy])->typ) { mon = m_at(sx, sy); if (cansee(sx, sy)) { /* reveal/unreveal invisible monsters before tmp_at() */ if (mon && !canspotmon(mon)) map_invisible(sx, sy); else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) { unmap_object(sx, sy); newsym(sx, sy); } if (ZAP_POS(lev->typ) || (isok(lsx, lsy) && cansee(lsx, lsy))) tmp_at(sx, sy); delay_output(); /* wait a little */ } } else goto make_bounce; /* hit() and miss() need bhitpos to match the target */ bhitpos.x = sx, bhitpos.y = sy; /* Fireballs only damage when they explode */ if (type != ZT_SPELL(ZT_FIRE)) range += zap_over_floor(sx, sy, type, &shopdamage, 0); if (mon) { if (type == ZT_SPELL(ZT_FIRE)) break; if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK; buzzmonst: if (zap_hit(find_mac(mon), spell_type)) { if (mon_reflects(mon, (char *) 0)) { if (cansee(mon->mx, mon->my)) { hit(fltxt, mon, exclam(0)); shieldeff(mon->mx, mon->my); (void) mon_reflects(mon, "But it reflects from %s %s!"); } dx = -dx; dy = -dy; } else { boolean mon_could_move = mon->mcanmove; int tmp = zhitm(mon, type, nd, &otmp); if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) { if (canseemon(mon)) { hit(fltxt, mon, "."); pline("%s disintegrates.", Monnam(mon)); pline("%s body reintegrates before your %s!", s_suffix(Monnam(mon)), (eyecount(youmonst.data) == 1) ? body_part(EYE) : makeplural(body_part(EYE))); pline("%s resurrects!", Monnam(mon)); } mon->mhp = mon->mhpmax; break; /* Out of while loop */ } if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) { if (canseemon(mon)) { hit(fltxt, mon, "."); pline("%s absorbs the deadly %s!", Monnam(mon), type == ZT_BREATH(ZT_DEATH) ? "blast" : "ray"); pline("It seems even stronger than before."); } break; /* Out of while loop */ } if (tmp == MAGIC_COOKIE) { /* disintegration */ disintegrate_mon(mon, type, fltxt); } else if (mon->mhp < 1) { if (type < 0) monkilled(mon, fltxt, AD_RBRE); else killed(mon); } else { if (!otmp) { /* normal non-fatal hit */ hit(fltxt, mon, exclam(tmp)); } else { /* some armor was destroyed; no damage done */ if (canseemon(mon)) pline("%s %s is disintegrated!", s_suffix(Monnam(mon)), distant_name(otmp, xname)); m_useup(mon, otmp); } if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */ slept_monst(mon); } } range -= 2; } else { miss(fltxt, mon); } } else if (sx == u.ux && sy == u.uy && range >= 0) { nomul(0); if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *) 0)) { mon = u.usteed; goto buzzmonst; } else if (zap_hit((int) u.uac, 0)) { range -= 2; pline("%s hits you!", The(fltxt)); if (Reflecting) { if (!Blind) { (void) ureflects("But %s reflects from your %s!", "it"); } else pline("For some reason you are not affected."); dx = -dx; dy = -dy; shieldeff(sx, sy); } else { zhitu(type, nd, fltxt, sx, sy); } } else if (!Blind) { pline("%s whizzes by you!", The(fltxt)); } else if (abstype == ZT_LIGHTNING) { Your("%s tingles.", body_part(ARM)); } if (abstype == ZT_LIGHTNING) (void) flashburn((long) d(nd, 50)); stop_occupation(); nomul(0); } if (!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) { int bounce; uchar rmn; make_bounce: if (type == ZT_SPELL(ZT_FIRE)) { sx = lsx; sy = lsy; break; /* fireballs explode before the wall */ } bounce = 0; range--; if (range && isok(lsx, lsy) && cansee(lsx, lsy)) { pline("%s %s!", The(fltxt), Is_airlevel(&u.uz) ? "vanishes into the aether" : "bounces"); if (Is_airlevel(&u.uz)) goto get_out_buzz; } if (!dx || !dy || !rn2(20)) { dx = -dx; dy = -dy; } else { if (isok(sx, lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) && !closed_door(sx, lsy) && (IS_ROOM(rmn) || (isok(sx + dx, lsy) && ZAP_POS(levl[sx + dx][lsy].typ)))) bounce = 1; if (isok(lsx, sy) && ZAP_POS(rmn = levl[lsx][sy].typ) && !closed_door(lsx, sy) && (IS_ROOM(rmn) || (isok(lsx, sy + dy) && ZAP_POS(levl[lsx][sy + dy].typ)))) if (!bounce || rn2(2)) bounce = 2; switch (bounce) { case 0: dx = -dx; /* fall into... */ case 1: dy = -dy; break; case 2: dx = -dx; break; } tmp_at(DISP_CHANGE, zapdir_to_glyph(dx, dy, abstype)); } } } tmp_at(DISP_END, 0); if (type == ZT_SPELL(ZT_FIRE)) explode(sx, sy, type, d(12, 6), 0, EXPL_FIERY); get_out_buzz: if (shopdamage) pay_for_damage(abstype == ZT_FIRE ? "burn away" : abstype == ZT_COLD ? "shatter" /* "damage" indicates wall rather than door */ : abstype == ZT_ACID ? "damage" : abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE); bhitpos = save_bhitpos; } void melt_ice(x, y, msg) xchar x, y; const char *msg; { struct rm *lev = &levl[x][y]; struct obj *otmp; if (!msg) msg = "The ice crackles and melts."; if (lev->typ == DRAWBRIDGE_UP) { lev->drawbridgemask &= ~DB_ICE; /* revert to DB_MOAT */ } else { /* lev->typ == ICE */ #ifdef STUPID if (lev->icedpool == ICED_POOL) lev->typ = POOL; else lev->typ = MOAT; #else lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT); #endif lev->icedpool = 0; } spot_stop_timers(x, y, MELT_ICE_AWAY); /* no more ice to melt away */ obj_ice_effects(x, y, FALSE); unearth_objs(x, y); if (Underwater) vision_recalc(1); newsym(x, y); if (cansee(x, y)) Norep("%s", msg); if ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x, y)) pline("%s settles...", An(xname(otmp))); do { obj_extract_self(otmp); /* boulder isn't being pushed */ if (!boulder_hits_pool(otmp, x, y, FALSE)) impossible("melt_ice: no pool?"); /* try again if there's another boulder and pool didn't fill */ } while (is_pool(x, y) && (otmp = sobj_at(BOULDER, x, y)) != 0); newsym(x, y); } if (x == u.ux && y == u.uy) spoteffects(TRUE); /* possibly drown, notice objects */ } #define MIN_ICE_TIME 50 #define MAX_ICE_TIME 2000 /* * Usually start a melt_ice timer; sometimes the ice will become * permanent instead. */ void start_melt_ice_timeout(x, y, min_time) xchar x, y; long min_time; /* 's old melt timeout (deleted by time we get here) */ { int when; long where; when = (int) min_time; if (when < MIN_ICE_TIME - 1) when = MIN_ICE_TIME - 1; /* random timeout; surrounding ice locations ought to be a factor... */ while (++when <= MAX_ICE_TIME) if (!rn2((MAX_ICE_TIME - when) + MIN_ICE_TIME)) break; /* if we're within MAX_ICE_TIME, install a melt timer; otherwise, omit it to leave this ice permanent */ if (when <= MAX_ICE_TIME) { where = ((long) x << 16) | (long) y; (void) start_timer((long) when, TIMER_LEVEL, MELT_ICE_AWAY, long_to_any(where)); } } #undef MIN_ICE_TIME #undef MAX_ICE_TIME /* * Called when ice has melted completely away. */ void melt_ice_away(arg, timeout) anything *arg; long timeout UNUSED; { xchar x, y; long where = arg->a_long; y = (xchar) (where & 0xFFFF); x = (xchar) ((where >> 16) & 0xFFFF); /* melt_ice does newsym when appropriate */ melt_ice(x, y, "Some ice melts away."); } /* Burn floor scrolls, evaporate pools, etc... in a single square. * Used both for normal bolts of fire, cold, etc... and for fireballs. * Sets shopdamage to TRUE if a shop door is destroyed, and returns the * amount by which range is reduced (the latter is just ignored by fireballs) */ int zap_over_floor(x, y, type, shopdamage, exploding_wand_typ) xchar x, y; int type; boolean *shopdamage; short exploding_wand_typ; { const char *zapverb; struct monst *mon; struct trap *t; struct rm *lev = &levl[x][y]; boolean see_it = cansee(x, y), yourzap; int rangemod = 0, abstype = abs(type) % 10; switch (abstype) { case ZT_FIRE: t = t_at(x, y); if (t && t->ttyp == WEB) { /* a burning web is too flimsy to notice if you can't see it */ if (see_it) Norep("A web bursts into flames!"); (void) delfloortrap(t); if (see_it) newsym(x, y); } if (is_ice(x, y)) { melt_ice(x, y, (char *) 0); } else if (is_pool(x, y)) { const char *msgtxt = "You hear hissing gas."; if (lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */ if (see_it) msgtxt = "Some water evaporates."; } else { rangemod -= 3; lev->typ = ROOM; t = maketrap(x, y, PIT); if (t) t->tseen = 1; if (see_it) msgtxt = "The water evaporates."; } Norep("%s", msgtxt); if (lev->typ == ROOM) newsym(x, y); } else if (IS_FOUNTAIN(lev->typ)) { if (see_it) pline("Steam billows from the fountain."); rangemod -= 1; dryup(x, y, type > 0); } break; /* ZT_FIRE */ case ZT_COLD: if (is_pool(x, y) || is_lava(x, y)) { boolean lava = is_lava(x, y); boolean moat = is_moat(x, y); if (lev->typ == WATER) { /* For now, don't let WATER freeze. */ if (see_it) pline_The("water freezes for a moment."); else You_hear("a soft crackling."); rangemod -= 1000; /* stop */ } else { rangemod -= 3; if (lev->typ == DRAWBRIDGE_UP) { lev->drawbridgemask &= ~DB_UNDER; /* clear lava */ lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE); } else { if (!lava) lev->icedpool = (lev->typ == POOL ? ICED_POOL : ICED_MOAT); lev->typ = (lava ? ROOM : ICE); } bury_objs(x, y); if (see_it) { if (lava) Norep("The lava cools and solidifies."); else if (moat) Norep("The %s is bridged with ice!", waterbody_name(x, y)); else Norep("The water freezes."); newsym(x, y); } else if (!lava) You_hear("a crackling sound."); if (x == u.ux && y == u.uy) { if (u.uinwater) { /* not just `if (Underwater)' */ /* leave the no longer existent water */ u.uinwater = 0; u.uundetected = 0; docrt(); vision_full_recalc = 1; } else if (u.utrap && u.utraptype == TT_LAVA) { if (Passes_walls) { u.utrap = 0; You("pass through the now-solid rock."); } else { u.utrap = rn1(50, 20); u.utraptype = TT_INFLOOR; You("are firmly stuck in the cooling rock."); } } } else if ((mon = m_at(x, y)) != 0) { /* probably ought to do some hefty damage to any non-ice creature caught in freezing water; at a minimum, eels are forced out of hiding */ if (is_swimmer(mon->data) && mon->mundetected) { mon->mundetected = 0; newsym(x, y); } } if (!lava) { start_melt_ice_timeout(x, y, 0L); obj_ice_effects(x, y, TRUE); } } /* ?WATER */ } else if (is_ice(x, y)) { long melt_time; /* Already ice here, so just firm it up. */ /* Now ensure that only ice that is already timed is affected */ if ((melt_time = spot_time_left(x, y, MELT_ICE_AWAY)) != 0L) { spot_stop_timers(x, y, MELT_ICE_AWAY); start_melt_ice_timeout(x, y, melt_time); } } break; /* ZT_COLD */ case ZT_ACID: if (lev->typ == IRONBARS) { if ((lev->wall_info & W_NONDIGGABLE) != 0) { if (see_it) Norep("The %s corrode somewhat but remain intact.", defsyms[S_bars].explanation); /* but nothing actually happens... */ } else { rangemod -= 3; if (see_it) Norep("The %s melt.", defsyms[S_bars].explanation); if (*in_rooms(x, y, SHOPBASE)) { /* in case we ever have a shop bounded by bars */ lev->typ = ROOM; if (see_it) newsym(x, y); add_damage(x, y, (type >= 0) ? 300L : 0L); if (type >= 0) *shopdamage = TRUE; } else { lev->typ = DOOR; lev->doormask = D_NODOOR; if (see_it) newsym(x, y); } } } break; /* ZT_ACID */ default: break; } /* set up zap text for possible door feedback; for exploding wand, we want "the blast" rather than "your blast" even if hero caused it */ yourzap = (type >= 0 && !exploding_wand_typ); zapverb = "blast"; /* breath attack or wand explosion */ if (!exploding_wand_typ) { if (abs(type) < ZT_SPELL(0)) zapverb = "bolt"; /* wand zap */ else if (abs(type) < ZT_BREATH(0)) zapverb = "spell"; } /* secret door gets revealed, converted into regular door */ if (levl[x][y].typ == SDOOR) { cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ /* target spot will now pass closed_door() test below (except on rogue level) */ newsym(x, y); if (see_it) pline("%s %s reveals a secret door.", yourzap ? "Your" : "The", zapverb); else if (Is_rogue_level(&u.uz)) draft_message(FALSE); /* "You feel a draft." (open doorway) */ } /* regular door absorbs remaining zap range, possibly gets destroyed */ if (closed_door(x, y)) { int new_doormask = -1; const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0; rangemod = -1000; switch (abstype) { case ZT_FIRE: new_doormask = D_NODOOR; see_txt = "The door is consumed in flames!"; sense_txt = "smell smoke."; break; case ZT_COLD: new_doormask = D_NODOOR; see_txt = "The door freezes and shatters!"; sense_txt = "feel cold."; break; case ZT_DEATH: /* death spells/wands don't disintegrate */ if (abs(type) != ZT_BREATH(ZT_DEATH)) goto def_case; new_doormask = D_NODOOR; see_txt = "The door disintegrates!"; hear_txt = "crashing wood."; break; case ZT_LIGHTNING: new_doormask = D_BROKEN; see_txt = "The door splinters!"; hear_txt = "crackling."; break; default: def_case: if (exploding_wand_typ > 0) { /* Magical explosion from misc exploding wand */ if (exploding_wand_typ == WAN_STRIKING) { new_doormask = D_BROKEN; see_txt = "The door crashes open!"; sense_txt = "feel a burst of cool air."; break; } } if (see_it) { /* "the door absorbs the blast" would be inaccurate for an exploding wand since other adjacent locations still get hit */ if (exploding_wand_typ) pline_The("door remains intact."); else pline_The("door absorbs %s %s!", yourzap ? "your" : "the", zapverb); } else You_feel("vibrations."); break; } if (new_doormask >= 0) { /* door gets broken */ if (*in_rooms(x, y, SHOPBASE)) { if (type >= 0) { add_damage(x, y, 400L); *shopdamage = TRUE; } else /* caused by monster */ add_damage(x, y, 0L); } lev->doormask = new_doormask; unblock_point(x, y); /* vision */ if (see_it) { pline1(see_txt); newsym(x, y); } else if (sense_txt) { You1(sense_txt); } else if (hear_txt) You_hear1(hear_txt); if (picking_at(x, y)) { stop_occupation(); reset_pick(); } } } if (OBJ_AT(x, y) && abstype == ZT_FIRE) if (burn_floor_objects(x, y, FALSE, type > 0) && couldsee(x, y)) { newsym(x, y); You("%s of smoke.", !Blind ? "see a puff" : "smell a whiff"); } if ((mon = m_at(x, y)) != 0) { /* Cannot use wakeup() which also angers the monster */ mon->msleeping = 0; if (mon->m_ap_type) seemimic(mon); if (type >= 0) { setmangry(mon); if (mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE)) ghod_hitsu(mon); if (mon->isshk && !*u.ushops) hot_pursuit(mon); } } return rangemod; } /* fractured by pick-axe or wand of striking */ void fracture_rock(obj) register struct obj *obj; /* no texts here! */ { xchar x, y; boolean by_you = !context.mon_moving; if (by_you && get_obj_location(obj, &x, &y, 0) && costly_spot(x, y)) { struct monst *shkp = 0; char objroom = *in_rooms(x, y, SHOPBASE); if (billable(&shkp, obj, objroom, FALSE)) { /* shop message says "you owe <$> for it!" so we need to precede that with a message explaining what "it" is */ You("fracture %s %s.", s_suffix(shkname(shkp)), xname(obj)); breakobj(obj, x, y, TRUE, FALSE); /* charges for shop goods */ } } if (by_you && obj->otyp == BOULDER) sokoban_guilt(); obj->otyp = ROCK; obj->oclass = GEM_CLASS; obj->quan = (long) rn1(60, 7); obj->owt = weight(obj); obj->dknown = obj->bknown = obj->rknown = 0; obj->known = objects[obj->otyp].oc_uses_known ? 0 : 1; dealloc_oextra(obj); if (obj->where == OBJ_FLOOR) { obj_extract_self(obj); /* move rocks back on top */ place_object(obj, obj->ox, obj->oy); if (!does_block(obj->ox, obj->oy, &levl[obj->ox][obj->oy])) unblock_point(obj->ox, obj->oy); if (cansee(obj->ox, obj->oy)) newsym(obj->ox, obj->oy); } } /* handle statue hit by striking/force bolt/pick-axe */ boolean break_statue(obj) register struct obj *obj; { /* [obj is assumed to be on floor, so no get_obj_location() needed] */ struct trap *trap = t_at(obj->ox, obj->oy); struct obj *item; boolean by_you = !context.mon_moving; if (trap && trap->ttyp == STATUE_TRAP && activate_statue_trap(trap, obj->ox, obj->oy, TRUE)) return FALSE; /* drop any objects contained inside the statue */ while ((item = obj->cobj) != 0) { obj_extract_self(item); place_object(item, obj->ox, obj->oy); } if (by_you && Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) { You_feel("guilty about damaging such a historic statue."); adjalign(-1); } obj->spe = 0; fracture_rock(obj); return TRUE; } /* * destroy_strings[dindx][0:singular,1:plural,2:killer_reason] * [0] freezing potion * [1] boiling potion other than oil * [2] boiling potion of oil * [3] burning scroll * [4] burning spellbook * [5] shocked ring * [6] shocked wand * (books, rings, and wands don't stack so don't need plural form; * crumbling ring doesn't do damage so doesn't need killer reason) */ const char *const destroy_strings[][3] = { /* also used in trap.c */ { "freezes and shatters", "freeze and shatter", "shattered potion" }, { "boils and explodes", "boil and explode", "boiling potion" }, { "ignites and explodes", "ignite and explode", "exploding potion" }, { "catches fire and burns", "catch fire and burn", "burning scroll" }, { "catches fire and burns", "", "burning book" }, { "turns to dust and vanishes", "", "" }, { "breaks apart and explodes", "", "exploding wand" }, }; void destroy_item(osym, dmgtyp) register int osym, dmgtyp; { register struct obj *obj, *obj2; int dmg, xresist, skip; long i, cnt, quan; int dindx; const char *mult; boolean physical_damage; for (obj = invent; obj; obj = obj2) { obj2 = obj->nobj; physical_damage = FALSE; if (obj->oclass != osym) continue; /* test only objs of type osym */ if (obj->oartifact) continue; /* don't destroy artifacts */ if (obj->in_use && obj->quan == 1L) continue; /* not available */ xresist = skip = 0; /* lint suppression */ dmg = dindx = 0; quan = 0L; switch (dmgtyp) { case AD_COLD: if (osym == POTION_CLASS && obj->otyp != POT_OIL) { quan = obj->quan; dindx = 0; dmg = rnd(4); } else skip++; break; case AD_FIRE: xresist = (Fire_resistance && obj->oclass != POTION_CLASS && obj->otyp != GLOB_OF_GREEN_SLIME); if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) skip++; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { skip++; if (!Blind) pline("%s glows a strange %s, but remains intact.", The(xname(obj)), hcolor("dark red")); } quan = obj->quan; switch (osym) { case POTION_CLASS: dindx = (obj->otyp != POT_OIL) ? 1 : 2; dmg = rnd(6); break; case SCROLL_CLASS: dindx = 3; dmg = 1; break; case SPBOOK_CLASS: dindx = 4; dmg = 1; break; case FOOD_CLASS: if (obj->otyp == GLOB_OF_GREEN_SLIME) { dindx = obj->owt / 20; dmg = 1; } else { skip++; } break; default: skip++; break; } break; case AD_ELEC: xresist = (Shock_resistance && obj->oclass != RING_CLASS); quan = obj->quan; switch (osym) { case RING_CLASS: if (obj->otyp == RIN_SHOCK_RESISTANCE) { skip++; break; } dindx = 5; dmg = 0; break; case WAND_CLASS: if (obj->otyp == WAN_LIGHTNING) { skip++; break; } #if 0 if (obj == current_wand) { skip++; break; } #endif dindx = 6; dmg = rnd(10); break; default: skip++; break; } break; default: skip++; break; } if (!skip) { if (obj->in_use) --quan; /* one will be used up elsewhere */ for (i = cnt = 0L; i < quan; i++) if (!rn2(3)) cnt++; if (!cnt) continue; mult = (cnt == quan) ? (quan > 1) ? "All of your " : "Your" : (cnt == 1L) ? "One of your" : "Some of your"; pline("%s %s %s!", mult, xname(obj), destroy_strings[dindx][(cnt > 1L)]); if (osym == POTION_CLASS && dmgtyp != AD_COLD) { if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(obj); } if (obj->owornmask) { if (obj->owornmask & W_RING) /* ring being worn */ Ring_gone(obj); else setnotworn(obj); } if (obj == current_wand) current_wand = 0; /* destroyed */ for (i = 0; i < cnt; i++) useup(obj); if (dmg) { if (xresist) You("aren't hurt!"); else { const char *how = destroy_strings[dindx][2]; boolean one = (cnt == 1L); if (physical_damage) dmg = Maybe_Half_Phys(dmg); losehp(dmg, one ? how : (const char *) makeplural(how), one ? KILLED_BY_AN : KILLED_BY); exercise(A_STR, FALSE); } } } } return; } int destroy_mitem(mtmp, osym, dmgtyp) struct monst *mtmp; int osym, dmgtyp; { struct obj *obj, *obj2; int skip, tmp = 0; long i, cnt, quan; int dindx; boolean vis; if (mtmp == &youmonst) { /* this simplifies artifact_hit() */ destroy_item(osym, dmgtyp); return 0; /* arbitrary; value doesn't matter to artifact_hit() */ } vis = canseemon(mtmp); for (obj = mtmp->minvent; obj; obj = obj2) { obj2 = obj->nobj; if (obj->oclass != osym) continue; /* test only objs of type osym */ skip = 0; quan = 0L; dindx = 0; switch (dmgtyp) { case AD_COLD: if (osym == POTION_CLASS && obj->otyp != POT_OIL) { quan = obj->quan; dindx = 0; tmp++; } else skip++; break; case AD_FIRE: if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) skip++; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { skip++; if (vis) pline("%s glows a strange %s, but remains intact.", The(distant_name(obj, xname)), hcolor("dark red")); } quan = obj->quan; switch (osym) { case POTION_CLASS: dindx = (obj->otyp != POT_OIL) ? 1 : 2; tmp++; break; case SCROLL_CLASS: dindx = 3; tmp++; break; case SPBOOK_CLASS: dindx = 4; tmp++; break; case FOOD_CLASS: if (obj->otyp == GLOB_OF_GREEN_SLIME) { dindx = obj->owt / 20; tmp++; } else { skip++; } break; default: skip++; break; } break; case AD_ELEC: quan = obj->quan; switch (osym) { case RING_CLASS: if (obj->otyp == RIN_SHOCK_RESISTANCE) { skip++; break; } dindx = 5; break; case WAND_CLASS: if (obj->otyp == WAN_LIGHTNING) { skip++; break; } dindx = 6; tmp++; break; default: skip++; break; } break; default: skip++; break; } if (!skip) { for (i = cnt = 0L; i < quan; i++) if (!rn2(3)) cnt++; if (!cnt) continue; if (vis) pline("%s%s %s!", (cnt == obj->quan) ? "" : (cnt > 1L) ? "Some of " : "One of ", (cnt == obj->quan) ? Yname2(obj) : yname(obj), destroy_strings[dindx][(cnt > 1L)]); for (i = 0; i < cnt; i++) m_useup(mtmp, obj); } } return tmp; } int resist(mtmp, oclass, damage, tell) struct monst *mtmp; char oclass; int damage, tell; { int resisted; int alev, dlev; /* attack level */ switch (oclass) { case WAND_CLASS: alev = 12; break; case TOOL_CLASS: alev = 10; break; /* instrument */ case WEAPON_CLASS: alev = 10; break; /* artifact */ case SCROLL_CLASS: alev = 9; break; case POTION_CLASS: alev = 6; break; case RING_CLASS: alev = 5; break; default: alev = u.ulevel; break; /* spell */ } /* defense level */ dlev = (int) mtmp->m_lev; if (dlev > 50) dlev = 50; else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1; resisted = rn2(100 + alev - dlev) < mtmp->data->mr; if (resisted) { if (tell) { shieldeff(mtmp->mx, mtmp->my); pline("%s resists!", Monnam(mtmp)); } damage = (damage + 1) / 2; } if (damage) { mtmp->mhp -= damage; if (mtmp->mhp < 1) { if (m_using) monkilled(mtmp, "", AD_RBRE); else killed(mtmp); } } return resisted; } #define MAXWISHTRY 5 STATIC_OVL void wishcmdassist(triesleft) int triesleft; { static NEARDATA const char * wishinfo[] = { "Wish details:", "", "Enter the name of an object, such as \"potion of monster detection\",", "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"", "(without the quotes).", "", "For object types which come in stacks, you may specify a plural name", "such as \"potions of healing\", or specify a count, such as \"1000 gold", "pieces\", although that aspect of your wish might not be granted.", "", "You may also specify various prefix values which might be used to", "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".", "Most modifiers shown when viewing your inventory can be specified.", "", "You may specify 'nothing' to explicitly decline this wish.", 0, }, preserve_wishless[] = "Doing so will preserve 'wishless' conduct.", retry_info[] = "If you specify an unrecognized object name %s%s time%s,", retry_too[] = "a randomly chosen item will be granted.", suppress_cmdassist[] = "(Suppress this assistance with !cmdassist in your config file.)", *cardinals[] = { "zero", "one", "two", "three", "four", "five" }, too_many[] = "too many"; int i; winid win; char buf[BUFSZ]; win = create_nhwindow(NHW_TEXT); if (!win) return; for (i = 0; i < SIZE(wishinfo) - 1; ++i) putstr(win, 0, wishinfo[i]); if (!u.uconduct.wishes) putstr(win, 0, preserve_wishless); putstr(win, 0, ""); Sprintf(buf, retry_info, (triesleft >= 0 && triesleft < SIZE(cardinals)) ? cardinals[triesleft] : too_many, (triesleft < MAXWISHTRY) ? " more" : "", plur(triesleft)); putstr(win, 0, buf); putstr(win, 0, retry_too); putstr(win, 0, ""); if (iflags.cmdassist) putstr(win, 0, suppress_cmdassist); display_nhwindow(win, FALSE); destroy_nhwindow(win); } void makewish() { char buf[BUFSZ], promptbuf[BUFSZ]; struct obj *otmp, nothing; int tries = 0; promptbuf[0] = '\0'; nothing = zeroobj; /* lint suppression; only its address matters */ if (flags.verbose) You("may wish for an object."); retry: Strcpy(promptbuf, "For what do you wish"); if (iflags.cmdassist && tries > 0) Strcat(promptbuf, " (enter 'help' for assistance)"); Strcat(promptbuf, "?"); getlin(promptbuf, buf); (void) mungspaces(buf); if (buf[0] == '\033') { buf[0] = '\0'; } else if (!strcmpi(buf, "help")) { wishcmdassist(MAXWISHTRY - tries); goto retry; } /* * Note: if they wished for and got a non-object successfully, * otmp == &zeroobj. That includes gold, or an artifact that * has been denied. Wishing for "nothing" requires a separate * value to remain distinct. */ otmp = readobjnam(buf, ¬hing); if (!otmp) { pline("Nothing fitting that description exists in the game."); if (++tries < MAXWISHTRY) goto retry; pline1(thats_enough_tries); otmp = readobjnam((char *) 0, (struct obj *) 0); if (!otmp) return; /* for safety; should never happen */ } else if (otmp == ¬hing) { /* explicitly wished for "nothing", presumably attempting to retain wishless conduct */ return; } /* KMH, conduct */ u.uconduct.wishes++; if (otmp != &zeroobj) { const char *verb = ((Is_airlevel(&u.uz) || u.uinwater) ? "slip" : "drop"), *oops_msg = (u.uswallow ? "Oops! %s out of your reach!" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || levl[u.ux][u.uy].typ < IRONBARS || levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" : "Oops! %s to the floor!"); /* The(aobjnam()) is safe since otmp is unidentified -dlc */ (void) hold_another_object(otmp, oops_msg, The(aobjnam(otmp, verb)), (const char *) 0); u.ublesscnt += rn1(100, 50); /* the gods take notice */ } } /*zap.c*/ nethack-3.6.0/sys/amiga/Build.ami0000664000076400007660000001605412536476415015603 0ustar paxedpaxed Compiling Amiga NetHack 3.4 Last Revision: 21 February 2002 for NetHack 3.4.1 We would like to thank each and every one of the people who took the time and effort to report bugs to us. THANK YOU! (And keep up the good work!) I. Introduction The Amiga-specific documentation has been split since the 3.1.3 release - please read the file Install.ami for information specific to the Amiga port before continuing. If you have problems with compilation, installation, or think you have found a bug in the game, please report it by electronic mail to the development group at nethack-bugs@nethack.org, where it will be routed to the appropriate person. Include your configuration, the version of NetHack you are playing (use the 'v' command or see include/patchlevel.h), and as much specific information as possible. As NetHack runs on many different machines, be sure to mention that you are playing the Amiga version and also mention if you are using the version for mc68k or ppc. If you want to find out about distributing NetHack, read the license (in NetHack:license or type ?i during the game). II. Compiling Amiga NetHack 3.4 II.A. Compilation Overview Compiling NetHack is not very hard - basically you do a little configuration and start make. It does, however, require a good amount of disk space and time. It also needs a good bit of memory, especially for linking. II.B. Basic Compilation NetHack can be built with SAS/C version 6.5x. The commercial version of DICE might work, but NetHack version 3.2.2 or later haven't been compiled with it. The "official" compiler for NetHack 3.6 is SAS/C 6.58 - we have dropped support for SAS/C 5.x. The Manx/Aztec port has not been tested recently and is certainly broken. Anyone managing to compile NetHack with this compiler is encouraged to submit context diffs of the required changes. When last tested, NetHack required version 5.0B of that compiler. Compiling with gcc should also work. II.B.1. Introduction to Compiling NetHack Before doing any compilation, read the README files distributed with the source. These should familiarize you with the source tree layout and what files are shared with what computers; everything in the sys/amiga directory is used exclusively by the Amiga. The makefile (sys/amiga/Makefile.ami) depends on certain assignments, providing the developer with a fairly flexible environment. See sys/amiga/Makefile.ami for assignment assumptions. DICE users should see section II.B.3 for information on creating a DMakefile usable with DMake. Edit config.h to your liking and system configuration. The defaults should be satisfactory for most systems. Read VERY CAREFULLY through the Makefile to familiarize yourself with which assignments are assumed. Otherwise, you're going to get something like "Insert NH: in any drive." You will need uudecode, and, if you need to modify dgn_comp or lev_comp, flex, and bison. The first thing Makefile.ami does is build makedefs, which handles a variety of data file generation, and then lev_comp and dgn_comp which compile the special levels. Makedefs will then be run to create a few files, followed by a roughly alphabetically sorted compilation of the entire source tree. This process will compile selected files from the sys/amiga, sys/share, win/tty, and src directories, eventually creating sbin/nethack. After building the main binary, a make install will build the auxiliary files including help files, special levels, icons, and the font files and will put these files into their final positions - most will be in dlb archives (if DLB was defined in config.h). The first make run should be done in NH:obj and the make install should be done in NetHack:; for both runs, the makefile is NH:sys/amiga/Makefile.ami (or NH:sys/amiga/DMakefile for DMake and NH:sys/amiga/Makefile.agc for gcc). Note that not all the source is simple C code. If you are modifying lev_comp or dgn_comp you may need bison and/or flex (depending on what modifications you are making). You do not need any of these tools to simply build NetHack - all the C output files are provided in the source distribution. Also, the ifchange script requires a version of diff that produces standard Unix format context diffs for proper operation - the version shipped with SAS/C is not sufficient. If you do not have bison and flex, copy the files from sys/share. The include files go in include/ and the C files go in util/. If the compile fails due to prototype errors for malloc and realloc, try deleting the first line of lev_comp.c and dgn_comp.c. II.B.2. Compiling NetHack with SAS/C version 6.58 NOTE WELL - Amiga NetHack has dropped support for SAS/C version 5. This version of NetHack was developed with SAS/C 6.58. Earlier versions than version of the compiler are known to cause problems - don't use them. A couple of notes and warnings from the SAS/C users on the team: * Included in the SAS/C port is code for generating a SnapShot.tb file upon catching various internal disasters. That is why the debug=l flag is in the makefile. This adds about 270K to the disk image, but it does not increase the run time memory requirements. * The 5.10b optimizer did not produce correct code for NetHack. The current optimizer has not been tested. II.B.3. Compiling NetHack with the commercial version of DICE IMPORTANT NOTE: If you are using DMake, you need to create DMakefile from Makefile.ami. Do the following: cd NH:sys/amiga edit from Makefile.ami to DMakefile with mkdmake opt w255 Some versions of DMake have been known to crash horribly on the makefile - if this happens, you'll need to download another make utility, such as AMake (ftp://ftp.dragonfire.net/amiga/utils/amake), which will run in DMake-compatibility mode if invoked with the -C switch (e.g. "amake -C -f NH:sys/amiga/DMakefile", or just "alias dmake amake -C"). SECOND IMPORTANT NOTE: The score list is currently disabled when compiling under DICE, due to an as-yet-unknown problem which causes system crashes when displaying the score list. NetHack can be compiled using the commercial version of DICE only. The registered shareware version had a bug in it which resulted in odd- aligned procedures. (It is possible to patch DC1 to fix this problem; however, this is not recommended, and you should upgrade to the commercial version.) DICE 3.0 (the first commercial release) has a couple of bugs in it which turn up in several of the NetHack sources; the DCC30_BUG define fixes them. If you have a more recent version of the compiler, you may be able to compile without this (and get slightly more efficient code) by commenting out the define in amiconf.h. During compilation, DICE will output a lot of warnings; they can be safely ignored. nethack-3.6.0/sys/amiga/Install.ami0000664000076400007660000002223012536476415016143 0ustar paxedpaxed Using and Installing Amiga NetHack 3.4 (or Everything You Never Wanted to Know Before NetHacking) (or Not Everything That Happens Always Comes Knocking) Last Revision: 28 March 2000 for NetHack 3.4.1 0. Pre-intro for NetHack 3.4.1: Amiga-specific changes for 3.4.1: Most (around 99%) known bugs fixed (volunteers welcome). HackWB and HackCli are no longer supported. Use the main binary. We would like to thank each and every one of the people who took the time and effort to report bugs to us. THANK YOU! I. Introduction I.A. Overview Welcome to Amiga NetHack! If this is your first visit to our fair city, you are in for an amazing but dangerous journey; if you have visited us before, beware! the city has changed in many strange and subtle ways; it has also grown quite a bit. This missive brings to light those mundane tasks which must be dealt with before beginning your journey; for those of you who are faced with the task of installing the pre-fabricated version of our town, section III (Installing Amiga NetHack 3.6) will guide you through the task at hand. If you are ready to visit, the local visitors guide is in section II (Using Amiga NetHack 3.6); please also see the general guide packaged separately (the file "GuideBook"). To all our visitors, a hearty Welcome! - and please be careful. [Those responsible for the previous paragraphs have been sacked. The documentation has been completed at great expense in a more traditional style. -- The Management] I.B. Getting Help If you have questions about strategy, weapons, or monsters, the best place to go for help is the Usenet newsgroup rec.games.roguelike.nethack. If you have problems with installation or think you have found a bug in the game, please report it by electronic mail to the development team at nethack-bugs@nethack.org, where it will be routed to the appropriate person. Include your configuration, the version of NetHack you are playing (use the 'v' command), whether or not you are using an official binary release (and if so which one) and as much specific information as possible. As NetHack runs on many different machines, be sure to mention that you are playing the Amiga version. I.C. Credits Olaf Seibert first ported NetHack 2.3 and 3.0 to the Amiga. Richard Addison, Andrew Church, Jochen Erwied, Mark Gooderum, Ken Lorber, Greg Olson, Mike Passaretti, and Gregg Wonderly polished and extended the 3.0 and 3.1 ports. Andrew Church, Ken Lorber, and Gregg Wonderly are responsible for the 3.2 port. Janne Salmijrvi resurrected the amigaport for 3.3 and Teemu Suikki joined before 3.4.0. II. Using Amiga NetHack 3.4 Run NetHack from the shell or from some tool that allows that, ie. ToolManager. See the NetHack.txt file for command line options and other usage. II.A. Sources of Information Where to go depends on what you want to find out. If you want to find out about distributing NetHack, read the license (in NetHack:license or type ?i during the game). For an introduction to NetHack, read the GuideBook file. To find out what options are compiled into your copy of NetHack, type #v during the game. Finally, for information during the game on all kinds of things, type ? and select from the menu or by pressing Help key. II.B. The Amiga NetHack WorkBench Front End Starting from 3.3.0 HackWB is not supported. II.C. The Amiga NetHack CLI Front End Starting from 3.3.0 CLI Front end is not supported either. Instead, use the main binary. See NetHack.txt file for the standard Unix flags for NetHack. In addition to those flags, Amiga NetHack accepts the flags -l to force non-interlaced mode and -L to force interlaced mode. II.D. Amiga-Specific Information for NetHack There are several options that are unique to the Amiga version of NetHack that may be specified in the NetHack.cnf file or on an OPTIONS line: altmeta allows the ALT keys to function as META keys. The default is altmeta. flush flush discards all characters in the queue except the first, which limits typeahead accidents. The default is !flush. silent turn off the audio output. The default is silent. The current version of Amiga NetHack also supports menu accelerators. See Guidebook.txt for a detailed description. Also supported is selecting the number of stacked objects to drop, used with the (D)rop command. Type the number and then select an item (or items with accelerators). Items with a count associated with them are denoted with # in place of -. I.e. 'd - 3 blessed daggers' becomes 'd # 3 blessed daggers'. You can clear the count by hitting esc while counting or deselect and reselect the item. The default is to drop all selected items (as before). For other options how to configure the screen setting and colors refer to Nethack.cnf. III. Installing Amiga NetHack 3.4 III.A. General Installation Installation should be easy - basically it consists of putting files where they belong and adding an assign to your startup. If you are installing from the official binary distribution, simply unpacking the archive in the appropriate directory will put the files in the places they belong. IF YOU ALREADY HAVE A PREVIOUS VERSION INSTALLED YOU MUST DELETE THE OLD SAVE AND BONES FILES - THEY WILL NOT WORK! This includes save and bones files from all previous versions of NetHack (yes, even 3.3.1). If you have a game in progress and want to finish it, use your current version and then update. Will NetHack fit on your machine? NetHack 3.6 is large. NetHack 3.4 is very large. You will need: > Any standard series Amiga: 500, 600, 1000, 1200, 2000, 2500, 3000, 4000. > WorkBench 2.04 or later. > At least 3 meg of RAM. NetHack will NOT run in 1 meg (probably even 2). > Mass storage: A hard drive with over 3 meg of free space is highly recommended. Hard Disk Installation: Unpack the archive to your place of choice. Since you are reading this you've probably done that already. Now just assign NetHack: to NetHack directory containing the executable and datafiles and other needed directories. Use the table in the next section to see where things should end up. Be sure that the file 8 ends up in NetHack:hack/8. Configuration Using your favorite text editor, edit NetHack:NetHack.cnf to match your system. Create the save file directory (makedir NetHack:save) and the levels file directory (makedir NetHack:levels), if they don't already exist. Create the score file (echo to NetHack:record) and, if desired, the log file (echo to NetHack:logfile), if they don't already exist. You may leave out logfile, but record is needed. III.B. File Location Table NetHack: amii.hlp Guidebook.txt hack.font license NetHack NetHack.cnf NetHack.txt nhdat nhsdat record Recover Recover.txt logfile (optional, but useful) NetHack:hack 8 NetHack:tiles monsters.iff objects.iff other.iff IV. BBS Interface [Since HackCli and split binary is no longer supported the following probably doesn't apply anymore. Due to lack of a suitable environment it is also untested.] The BBS mode is based on the standard NetHack tty port and is designed for use in a BBS setting - it is specifically not recommended for use on the console. The current TTY mode has changed significantly since the preliminary version released with 3.1.2. In particular, BBS mode now works with split binaries (only), and now supports multiple games in progress at the same time for multi-line boards (note however that any individual user should not be allowed to run two instances of NetHack at the same time). To set up NetHack for use with a BBS, set OPTIONS=windowtype:tty and unset DUNGEONS, TRAPS, and EFFECTS in NetHack.cnf. Configure the BBS to expect I/O through stdin and stdout, and have NetHack invoked as: HackCLI :uid -u uname options... where uid is any string (without embedded spaces, colons, or slashes) that is unique for each BBS user and uname is some corresponding human- readable name for that user. Uid is used in constructing file names to prevent collisions between simultaneous games and to prevent people from using other people's save files. Uname is the name the character will have in the game and the name that will appear in the record file. The terminal is assumed to be a 24x80 ANSI-compatible terminal. The present version does not deal with situations such as low memory gracefully - as NetHack uses a considerable amount of memory this is particularly painful with multiple games in progress. Sysops are reminded to be familiar with the recover utility, which may be needed from time to time and which should probably not be available directly to users. Bug reports and suggestions for improvements are requested from the user community - this is still considered alpha software. nethack-3.6.0/sys/amiga/Makefile.agc0000664000076400007660000011172512536476415016246 0ustar paxedpaxed# NetHack Makefile. # Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996. # NetHack may be freely redistributed. See license for details. ### ### modified for gcc by Teemu Suikki (zu@iki.fi) ### ### note: you need to use smake.. sorry ### ### ### DIRECTORY STRUCTURE ### NH = nh: SBIN = $(NH)sbin/ SLIB = $(NH)slib/ NETHACK = $(NH)NetHack/ HACKEXE = $(NH)HackExe/ AMI = $(NH)sys/amiga/ DAT = $(NH)dat/ DOC = $(NH)doc/ I = $(NH)include/ SHARE = $(NH)sys/share/ NHS = $(NH)src/ TTY = $(NH)win/tty/ WSHARE = $(NH)win/share/ UTIL = $(NH)util/ O = $(NH)obj/ OO = $(NH)objo/ # NB: O and OO MUST be different directories ### ### INVOCATION ### MAKE = smake # Startup makefile with: # # $(MAKE) -f $(AMI)Makefile.amigcc # $(MAKE) -f $(AMI)Makefile.amigcc install # # You may use following targets on $(MAKE) command lines: # all do it all (default) # link just create binary from object files # obj just create common object files # obja just create amiga object files # objs just create shared object files # clean deletes the object files # spotless deletes the object files, main binary, and more # # Note: We do not build the Guidebook here since it needs tbl # (See the file sys/unix/Makefile.doc for more information) #[SAS5] [and gcc?] # If we were to use the precompiled header file feature in a newer version # of SAS/C, we would comment out these following two lines. # If we don't use precompiled header files, we uncomment it as well. HDEP = $(I)hack.h CSYM = #Pathname for uudecode program: UUDEC = uudecode # Flex/Bison command assignments -- Useful only if you have flex/bison FLEX = flex BISON = bison # FBFIL and FBLIB may be used, if required by your version of flex or bison, # to specify additional files or libraries to be linked with FBFIL = FBLIB = #lib lib:compat.lib # If you're compiling this on a 1.3 system, you'll have to uncomment the # following (for use with the ifchange script below). Also useful instead of # "protect ifchange +s" EXECUTE = execute # Headers we depend on AMDEP = $(AMI)winproto.h $(AMI)winext.h $(AMI)windefs.h $(I)winami.h # Pathname for the C compiler being used. CC = gcc -c ASM = as # Compilation flags for selected C Compiler: # $(CFLAGS) should appear before filename arguments of $(CC) command line. CFLAGS = -O3 -I $(I) # Components of various link command lines: # $(LINK) should be the pathname of the linker being used (with any options # that should appear at the beginning of the command line). The name of the # output file should appear immediately after $(LNSPEC). $(LIN) should # appear before the list of object files in each link command. $(LLINK) # should appear as the list of object files in the link command line that # creates the NetHack executable. $(LLIB) should appear at the end of each # link command line. LINK = gcc -noixemul -O3 LIN = LLINK = LLIB = FLLIB = OBJSPEC = -o PNSPEC = -o LNSPEC = -o CCLINK = gcc -noixemul CLFLAGS = -O3 INCLSPEC = -I DEFSPEC = -D IGNSPEC = -j ### ### FILE LISTS ### # A more reasonable random number generator (recommended for the Amiga): RANDOBJ = $(O)random.o .PRECIOUS: $(I)config.h $(I)decl.h $(I)hack.h $(I)permonst.h $(I)you.h # Almost nothing below this line should have to be changed. # (Exceptions are marked by [SAS6], [MANX], etc.) # # Other things that have to be reconfigured are in config.h, # (amiconf.h, pcconf.h), and possibly system.h, tradstdc.h. # Object files for makedefs: MAKEOBJS = \ $(OO)makedefs.o $(O)monst.o $(O)objects.o # Object files for special levels compiler: SPLEVOBJS = \ $(OO)lev_yacc.o $(OO)lev_lex.o $(OO)lev_main.o \ $(O)decl.o $(O)drawing.o $(O)monst.o \ $(O)objects.o $(OO)panic.o # Object files for dungeon compiler DGNCOMPOBJS = \ $(OO)dgn_yacc.o $(OO)dgn_lex.o $(OO)dgn_main.o $(O)alloc.o $(OO)panic.o # Object files for NetHack: COMMOBJ = \ $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o \ $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o \ $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o \ $(O)dig.o $(O)display.o $(O)dlb.o $(O)do.o \ $(O)do_name.o $(O)do_wear.o $(O)dog.o $(O)dogmove.o \ $(O)dokick.o $(O)dothrow.o $(O)drawing.o $(O)dungeon.o \ $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o \ $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o \ $(O)hack.o $(O)hacklib.o $(O)invent.o $(O)light.o \ $(O)lock.o $(O)mail.o $(O)makemon.o $(O)mapglyph.o \ $(O)mcastu.o $(O)mhitm.o $(O)mhitu.o $(O)minion.o \ $(O)mklev.o $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o \ $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o \ $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o \ $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o \ $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o \ $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o \ $(O)quest.o $(O)questpgr.o $(O)read.o $(O)rect.o \ $(O)region.o $(O)restore.o $(O)rnd.o $(O)role.o \ $(O)rumors.o $(O)save.o $(O)shk.o $(O)shknam.o \ $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o \ $(O)steal.o $(O)steed.o $(O)sys.o $(O)teleport.o \ $(O)timeout.o $(O)topten.o $(O)track.o $(O)trap.o \ $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)version.o \ $(O)vision.o $(O)weapon.o $(O)were.o $(O)wield.o \ $(O)windows.o $(O)wizard.o $(O)worm.o $(O)worn.o \ $(O)write.o $(O)zap.o MAKEDEFOBJ = \ $(O)monstr.o AMIGAOBJ = \ $(O)amidos.o $(O)amirip.o $(O)amisnd.o $(O)amistack.o \ $(O)amiwind.o $(O)winami.o $(O)winchar.o $(O)winfuncs.o \ $(O)winkey.o $(O)winmenu.o $(O)winreq.o $(O)winstr.o # Objects from assembly sources (because DMake can't handle default rules) AMIGAOBJ2 = \ # $(O)dispmap.o SHAREOBJ = \ $(O)pcmain.o $(RANDOBJ) TTYOBJ = \ $(O)getline.o $(O)termcap.o $(O)topl.o $(O)wintty.o $(O)amitty.o \ $(O)rip.o # Yuck yuck yuck. Have to tell DMake where these are, since they're not # all in the same place. TTYSRC = \ $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \ $(AMI)amitty.c $(NHS)rip.c # All the object files for NetHack: HOBJ = $(COMMOBJ) $(AMIGAOBJ) $(AMIGAOBJ2) $(SHAREOBJ) $(MAKEDEFOBJ) $(TTYOBJ) ### ### DATA FILES ### # quest files ADFILES1= $(SLIB)Arc-fila.lev $(SLIB)Arc-filb.lev $(SLIB)Arc-loca.lev \ $(SLIB)Arc-strt.lev ADFILES= $(SLIB)Arc-goal.lev $(ADFILES1) BDFILES1= $(SLIB)Bar-fila.lev $(SLIB)Bar-filb.lev $(SLIB)Bar-loca.lev \ $(SLIB)Bar-strt.lev BDFILES= $(SLIB)Bar-goal.lev $(BDFILES1) CDFILES1= $(SLIB)Cav-fila.lev $(SLIB)Cav-filb.lev $(SLIB)Cav-loca.lev \ $(SLIB)Cav-strt.lev CDFILES= $(SLIB)Cav-goal.lev $(CDFILES1) HDFILES1= $(SLIB)Hea-fila.lev $(SLIB)Hea-filb.lev $(SLIB)Hea-loca.lev \ $(SLIB)Hea-strt.lev HDFILES= $(SLIB)Hea-goal.lev $(HDFILES1) KDFILES1= $(SLIB)Kni-fila.lev $(SLIB)Kni-filb.lev $(SLIB)Kni-loca.lev \ $(SLIB)Kni-strt.lev KDFILES= $(SLIB)Kni-goal.lev $(KDFILES1) MDFILES1= $(SLIB)Mon-fila.lev $(SLIB)Mon-filb.lev $(SLIB)Mon-loca.lev \ $(SLIB)Mon-strt.lev MDFILES= $(SLIB)Mon-goal.lev $(MDFILES1) PDFILES1= $(SLIB)Pri-fila.lev $(SLIB)Pri-filb.lev $(SLIB)Pri-loca.lev \ $(SLIB)Pri-strt.lev PDFILES= $(SLIB)Pri-goal.lev $(PDFILES1) RDFILES1= $(SLIB)Rog-fila.lev $(SLIB)Rog-filb.lev $(SLIB)Rog-loca.lev \ $(SLIB)Rog-strt.lev RDFILES= $(SLIB)Rog-goal.lev $(RDFILES1) RANFILES1= $(SLIB)Ran-fila.lev $(SLIB)Ran-filb.lev $(SLIB)Ran-loca.lev \ $(SLIB)Ran-strt.lev RANFILES= $(SLIB)Ran-goal.lev $(RANFILES1) SDFILES1= $(SLIB)Sam-fila.lev $(SLIB)Sam-filb.lev $(SLIB)Sam-loca.lev \ $(SLIB)Sam-strt.lev SDFILES= $(SLIB)Sam-goal.lev $(SDFILES1) TDFILES1= $(SLIB)Tou-fila.lev $(SLIB)Tou-filb.lev $(SLIB)Tou-loca.lev \ $(SLIB)Tou-strt.lev TDFILES= $(SLIB)Tou-goal.lev $(TDFILES1) VDFILES1= $(SLIB)Val-fila.lev $(SLIB)Val-filb.lev $(SLIB)Val-loca.lev \ $(SLIB)Val-strt.lev VDFILES= $(SLIB)Val-goal.lev $(VDFILES1) WDFILES1= $(SLIB)Wiz-fila.lev $(SLIB)Wiz-filb.lev $(SLIB)Wiz-loca.lev \ $(SLIB)Wiz-strt.lev WDFILES= $(SLIB)Wiz-goal.lev $(WDFILES1) XDFILES= $(ADFILES) $(BDFILES) $(CDFILES) $(HDFILES) $(KDFILES) \ $(MDFILES) $(PDFILES) $(RDFILES) $(RANFILES) $(SDFILES) $(TDFILES) \ $(VDFILES) $(WDFILES) SOUNDFILES= \ $(SBIN)cvtsnd \ $(SLIB)sounds \ $(SLIB)sounds/Bell $(SLIB)sounds/Bugle \ $(SLIB)sounds/Drum_Of_Earthquake \ $(SLIB)sounds/Fire_Horn $(SLIB)sounds/Frost_Horn \ $(SLIB)sounds/Leather_Drum $(SLIB)sounds/Magic_Flute \ $(SLIB)sounds/Magic_Harp $(SLIB)sounds/Tooled_Horn \ $(SLIB)sounds/Wooden_Flute $(SLIB)sounds/Wooden_Harp TILEFILES= \ $(SBIN)txt2iff \ $(NETHACK)tiles \ $(NETHACK)tiles/objects.iff \ $(NETHACK)tiles/monsters.iff \ $(NETHACK)tiles/other.iff INSTDUNGEONFILES1= \ $(SLIB)air.lev $(SLIB)asmodeus.lev $(SLIB)astral.lev \ $(SLIB)baalz.lev $(SLIB)bigrm-1.lev $(SLIB)bigrm-2.lev \ $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev \ $(SLIB)castle.lev $(SLIB)dungeon $(SLIB)earth.lev \ $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev $(SLIB)fire.lev \ $(SLIB)juiblex.lev $(SLIB)knox.lev $(SLIB)medusa-1.lev \ $(SLIB)medusa-2.lev $(SLIB)minend-1.lev $(SLIB)minend-2.lev \ $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(SLIB)minefill.lev \ $(SLIB)options $(SLIB)oracle.lev $(SLIB)orcus.lev \ $(SLIB)sanctum.lev $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev \ $(SLIB)soko2-1.lev $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev \ $(SLIB)soko3-2.lev $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev \ $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev \ $(SLIB)valley.lev $(SLIB)water.lev $(SLIB)wizard1.lev \ $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(XDFILES) INSTDUNGEONFILES= $(NETHACK)NetHack.cnf $(INSTDUNGEONFILES1) INSTDATAFILES= \ $(NETHACK)license $(NETHACK)logfile $(NETHACK)record \ $(NETHACK)tomb.iff $(NETHACK)amii.hlp $(NETHACK)Recover.txt \ $(NETHACK)GuideBook.txt $(NETHACK)NetHack.txt $(NETHACK)Install.ami \ # $(NETHACK)HackWB.hlp $(NETHACK)WBDefaults.def LIBFILES= \ $(INSTDUNGEONFILES1) \ $(SLIB)cmdhelp $(SLIB)data $(SLIB)dungeon \ $(SLIB)help $(SLIB)hh $(SLIB)history \ $(SLIB)opthelp $(SLIB)oracles $(SLIB)rumors \ $(SLIB)quest.dat $(SLIB)wizhelp ### ### Getting down to business: ### all: $(COMPACT_HEADERS) $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \ $(SBIN)dlb $(NETHACK)recover #$(NETHACK)HackCli $(SBIN)splitter \ # $(NETHACK)HackWB install: inst-data inst-dungeon inst-fonts inst-sounds inst-tiles \ $(NETHACK)recover $(NETHACK)NetHack $(NETHACK)nhdat #$(NETHACK)NetHack.dir inst-icons $(SBIN)NetHack: link $(NETHACK)NetHack: $(SBIN)NetHack copy $(SBIN)NetHack $(NETHACK)NetHack ## uuh this is messy.. smake has weird command line length limit link: $(HOBJ) list to t:link lformat="$(O)%s" $(O)\#?.o QUICK NOHEAD echo "\#sh" to t:cc echo "$(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLIB) $(LLINK) " >>t:cc noline fmt -u -w 2500 t:link >>t:cc sh t:cc delete t:cc t:link ## dlb support $(OO)dlb_main.o: $(UTIL)dlb_main.c $(HDEP) $(I)dlb.h $(I)date.h $(CC) $(CFLAGS) $(OBJSPEC)$(OO)dlb_main.o $(UTIL)dlb_main.c $(SBIN)dlb: $(OO)dlb_main.o $(O)dlb.o $(O)alloc.o $(OO)panic.o $(LINK) $(PNSPEC) $(SBIN)dlb $(LIN) $(OO)dlb_main.o $(O)dlb.o \ $(O)alloc.o $(OO)panic.o $(LLIB) obj: $(HOBJ) obja: $(AMIGAOBJ) objs: $(SHAREOBJ) SUFFIXES = .lev .des .des.lev: $(SBIN)lev_comp $< # The default method for creating object files: #$(O)%.o: $(NHS)%.c .c.o: $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)$@ $< clean: -delete $(O)\#?.o $(OO)\#?.o spotless: clean -delete $(SBIN)NetHack $(SBIN)lev_comp $(SBIN)makedefs $(SBIN)dgn_comp -delete $(SBIN)cvtsnd $(SBIN)dlb $(SBIN)txt2iff $(SBIN)splitter -delete $(SBIN)tilemap -delete $(SLIB)data $(SLIB)rumors -delete $(SLIB)\#?.lev -delete $(SLIB)dungeon -delete $(SLIB)cmdhelp $(SLIB)help $(SLIB)hh $(SLIB)history -delete $(SLIB)opthelp $(SLIB)options $(SLIB)oracles -delete $(SLIB)quest.dat $(SLIB)wizhelp # -delete $(SLIB)earth.lev $(SLIB)air.lev $(SLIB)fire.lev # -delete $(SLIB)water.lev $(SLIB)astral.lev # -delete $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev # -delete $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev # -delete $(SLIB)medusa-1.lev $(SLIB)medusa-2.lev # -delete $(SLIB)oracle.lev $(SLIB)wizard1.lev $(SLIB)wizard2.lev # -delete $(SLIB)wizard3.lev $(DAT)dungeon.pdf $(SLIB)valley.lev # -delete $(SLIB)minefill.lev # -delete $(SLIB)minetn-1 $(SLIB)minetn-2 $(SLIB)minend-1 $(SLIB)minend-2 # -delete $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev # -delete $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev # -delete $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev # -delete $(ADFILES) # -delete $(BDFILES) # -delete $(CDFILES) # -delete $(HDFILES) # -delete $(KDFILES) # -delete $(MDFILES) # -delete $(PDFILES) # -delete $(RDFILES) # -delete $(RANFILES) # -delete $(SDFILES) # -delete $(TDFILES) # -delete $(VDFILES) # -delete $(WDFILES) -delete $(I)onames.h $(I)pm.h $(I)date.h -delete $(NHS)tile.c $(NHS)monstr.c -delete $(I)tile.h # -echo to $(I)onames.h "" noline # -c:wait 2 # -echo to $(I)pm.h "" noline # -c:wait 2 # -setdate $(UTIL)makedefs.c # -c:wait 2 # Creating precompiled version of $(I)hack.h to save disk I/O. # # Please note: The dependency lines for the modules here are # deliberately incorrect. Including "hack.h" in # the dependency list would cause a dependency # loop. # $(SBIN)makedefs: $(MAKEOBJS) $(LINK) $(LNSPEC) $(SBIN)makedefs $(LIN) $(MAKEOBJS) $(LLIB) $(OO)makedefs.o: $(UTIL)makedefs.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)objclass.h $(I)patchlevel.h $(I)qtext.h $(I)artilist.h $(CC) $(DEFSPEC)MAKEDEFS_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)makedefs.c $(SBIN)lev_comp: $(SPLEVOBJS) $(LINK) $(LNSPEC) $(SBIN)lev_comp $(LIN) $(SPLEVOBJS) $(FBFIL) $(FLLIB) $(SBIN)dgn_comp: $(DGNCOMPOBJS) $(LINK) $(LNSPEC) $(SBIN)dgn_comp $(LIN) $(DGNCOMPOBJS) $(FBFIL) $(FLLIB) $(OO)lev_yacc.o: $(UTIL)lev_yacc.c $(HDEP) $(I)sp_lev.h $(I)pm.h $(I)onames.h # setdate $(UTIL)lev_yacc.c $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)PREFIX="NH:slib/" $(CFLAGS) \ $(DEFSPEC)alloca=malloc $(OBJSPEC)$@ $(UTIL)lev_yacc.c $(OO)lev_lex.o: $(UTIL)lev_lex.c $(HDEP) $(I)lev_comp.h $(I)sp_lev.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)lev_lex.c $(OO)lev_main.o: $(UTIL)lev_main.c $(HDEP) $(I)pm.h $(I)onames.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)lev_main.c $(OO)dgn_yacc.o: $(UTIL)dgn_yacc.c $(HDEP) $(I)dgn_file.h $(I)patchlevel.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(DEFSPEC)alloca=malloc \ $(OBJSPEC)$@ $(UTIL)dgn_yacc.c $(OO)dgn_lex.o: $(UTIL)dgn_lex.c $(I)config.h $(I)dgn_comp.h $(I)dgn_file.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)dgn_lex.c $(OO)dgn_main.o: $(UTIL)dgn_main.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)dgn_main.c $(OO)panic.o: $(UTIL)panic.c $(HDEP) $(OO)recover.o: $(UTIL)recover.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)recover.c $(NETHACK)recover: $(OO)recover.o $(LINK) $(LNSPEC) $(NETHACK)recover $(LIN) $(OO)recover.o $(LLIB) # [OPTION] -- If you have flex/bison, leave these uncommented. Otherwise, # comment them out and be careful! (You're not guaranteed to have the most # up to date *_comp.c, *_comp.h and *_lex.c) $(I)lev_comp.h: $(UTIL)lev_yacc.c $(I)patchlevel.h $(UTIL)lev_yacc.c: $(UTIL)lev_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)lev_comp.y # copy y.tab.c $(UTIL)lev_yacc.c # copy y.tab.h $(I)lev_comp.h copy $(UTIL)lev_comp.tab.c $(UTIL)lev_yacc.c copy $(UTIL)lev_comp.tab.h $(I)lev_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)lev_comp.tab.c delete $(UTIL)lev_comp.tab.h $(UTIL)lev_lex.c: $(UTIL)lev_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)lev_comp.l copy lex.yy.c $(UTIL)lev_lex.c delete lex.yy.c $(I)dgn_comp.h: $(UTIL)dgn_yacc.c $(I)patchlevel.h $(UTIL)dgn_yacc.c: $(UTIL)dgn_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)dgn_comp.y # copy y.tab.c $(UTIL)dgn_yacc.c # copy y.tab.h $(I)dgn_comp.h copy $(UTIL)dgn_comp.tab.c $(UTIL)dgn_yacc.c copy $(UTIL)dgn_comp.tab.h $(I)dgn_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)dgn_comp.tab.c delete $(UTIL)dgn_comp.tab.h $(UTIL)dgn_lex.c: $(UTIL)dgn_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)dgn_comp.l copy lex.yy.c $(UTIL)dgn_lex.c delete lex.yy.c # # The following include files depend on makedefs to be created. # As a result, they are not defined in HACKINCL, instead, their # dependencies are explicitly outlined here. # # # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # $(I)date.h $(DAT)options: $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)patchlevel.h $(SBIN)makedefs -v $(EXECUTE) ifchange MOVE $(I)t.date.h $(I)date.h -c:wait 2 $(I)onames.h: $(SBIN)makedefs $(SBIN)makedefs -o $(EXECUTE) ifchange TOUCH $(I)t.onames.h $(I)onames.h $(I)decl.h $(EXECUTE) ifchange MOVE $(I)t.onames.h $(I)onames.h -c:wait 2 $(I)pm.h: $(SBIN)makedefs $(SBIN)makedefs -p $(EXECUTE) ifchange TOUCH $(I)t.pm.h $(I)pm.h $(I)decl.h $(I)youprop.h $(EXECUTE) ifchange MOVE $(I)t.pm.h $(I)pm.h -c:wait 2 $(SLIB)quest.dat: $(DAT)quest.txt $(SBIN)makedefs $(SBIN)makedefs -q $(NHS)monstr.c: $(HDEP) $(SBIN)makedefs $(SBIN)makedefs -m -c:wait 2 $(SLIB)oracles: $(DAT)oracles.txt $(SBIN)makedefs $(SBIN)makedefs -h -c:wait 2 # # The following programs vary depending on what OS you are using. # As a result, they are not defined in HACKSRC and their dependencies # are explicitly outlined here. # $(O)amidos.o: $(AMI)amidos.c $(HDEP) $(O)amirip.o: $(AMI)amirip.c $(HDEP) $(O)aglue.o: $(AMI)aglue.a $(ASM) $(AFLAGS) $(AOBJSPEC)$(O)aglue.o $(AMI)aglue.a $(O)amisnd.o: $(AMI)amisnd.c $(HDEP) $(O)winchar.o: $(AMI)winchar.c $(NHS)tile.c $(HDEP) $(NHS)tile.c: $(WSHARE)tilemap.c $(CCLINK) $(CFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c $(SBIN)tilemap $(O)winstr.o: $(AMI)winstr.c $(HDEP) $(AMDEP) $(O)winreq.o: $(AMI)winreq.c $(HDEP) $(AMDEP) $(AMI)colorwin.c $(AMI)clipwin.c $(O)winfuncs.o: $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h $(O)winkey.o: $(AMI)winkey.c $(HDEP) $(AMDEP) $(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP) $(O)winami.o: $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c #$(O)amilib.o: $(AMI)amilib.c $(HDEP) $(AMDEP) $(O)amiwind.o: $(AMI)amiwind.c $(AMI)amimenu.c $(HDEP) $(AMDEP) $(O)amiwbench.o: $(AMI)amiwbench.c $(HDEP) $(O)random.o: $(SHARE)random.c $(O)pcmain.o: $(SHARE)pcmain.c $(HDEP) $(I)dlb.h $(O)dispmap.o: $(AMI)dispmap.s $(ASM) $(AFLAGS) $(AOBJSPEC)$@ $< # Stuff to build the front ends $(NETHACK)HackWB: $(OO)wb.o $(OO)wbx.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackWB $(LIN) $(OO)wb.o $(OO)wbx.o \ $(OO)loader.o $(OO)multi.o $(LLIB) $(NETHACK)HackCli: $(OO)cli.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackCli $(LIN) $(OO)cli.o $(OO)loader.o \ $(OO)multi.o $(LLIB) # This needs to exist to eliminate the HackWB startup message $(NETHACK)WBDefaults.def: echo to $(NETHACK)WBDefaults.def WBH = $(AMI)wbdefs.h $(AMI)wbstruct.h $(AMI)wbprotos.h ASP = $(AMI)splitter $(OO)wb.o: $(WBH) $(AMI)wb.c $(AMI)wbwin.c $(AMI)wbdata.c $(AMI)wbgads.c \ $(I)patchlevel.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wb.o $(AMI)wb.c $(OO)wbx.o: $(WBH) $(AMI)wbcli.c $(AMI)wbwin.c $(AMI)wbdata.c \ $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wbx.o $(AMI)wbcli.c $(OO)loader.o: $(ASP)/loader.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)loader.o $(ASP)/loader.c $(OO)multi.o: $(ASP)/multi.c $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)multi.o $(ASP)/multi.c $(OO)cli.o: $(WBH) $(AMI)wbcli.c $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(WBC2FLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)cli.o \ $(AMI)wbcli.c #### # splitter support $(SBIN)splitter: $(OO)splitter.o $(OO)arg.o $(LINK) $(LNSPEC) $(SBIN)splitter $(LIN) $(OO)splitter.o $(OO)arg.o \ $(LLIB) $(NETHACK)NetHack.dir: $(SBIN)splitter $(SBIN)NetHack $(SBIN)splitter $(SBIN)NetHack $(OO)splitter.o: $(ASP)/splitter.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)splitter.o \ $(ASP)/splitter.c $(OO)arg.o: $(ASP)/arg.c $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)arg.o $(ASP)/arg.c # Create/copy other stuff into NetHack: directory: $(NETHACK)tomb.iff: $(SBIN)xpm2iff $(AMI)grave16.xpm $(SBIN)xpm2iff $(AMI)grave16.xpm $(NETHACK)tomb.iff $(OO)xpm2iff.o: $(AMI)xpm2iff.c $(CC) $(CFLAGS) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(AMI)xpm2iff.c $(SBIN)xpm2iff: $(OO)xpm2iff.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)xpm2iff.o $(FLLIB) # Tile installation for the tile version of the game inst-tiles: $(TILEFILES) $(NETHACK)tiles: -makedir $(NETHACK)tiles $(OO)txt2iff.o: $(AMI)txt2iff.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ \ $(AMI)txt2iff.c $(OO)ppmwrite.o: $(WSHARE)ppmwrite.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)ppmwrite.c $(OO)tiletext.o: $(WSHARE)tiletext.c $(I)config.h $(WSHARE)tile.h $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tiletext.c $(OO)tiletxt.o: $(WSHARE)tilemap.c $(I)hack.h $(CC) $(CFLAGS) $(CSYM) $(DEFSPEC)TILETEXT $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tilemap.c NAMEOBJS = $(O)drawing.o $(O)decl.o $(O)monst.o $(O)objects.o $(SBIN)txt2ppm: $(OO)ppmwrite.o $(NAMEOBJS) $(O)alloc.o $(OO)panic.o $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)ppmwrite.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(O)alloc.o $(OO)panic.o $(FLLIB) $(SBIN)txt2iff: $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o \ $(OO)tiletxt.o $(FLLIB) $(NETHACK)tiles/objects.iff: $(WSHARE)objects.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)objects.txt $(NETHACK)tiles/objects.iff $(NETHACK)tiles/monsters.iff: $(WSHARE)monsters.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)monsters.txt $(NETHACK)tiles/monsters.iff $(NETHACK)tiles/other.iff: $(WSHARE)other.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)other.txt $(NETHACK)tiles/other.iff # Sound installation rules. inst-sounds: $(SOUNDFILES) list to T:nhsdat.lst $(SLIB)sounds QUICK NOHEAD echo >T:make-nhsdat $(SBIN)dlb cCfI $(SLIB)sounds $(NETHACK)nhsdat T:nhsdat.lst echo >>T:make-nhsdat if not exists $(NETHACK)nhsdat echo >>T:make-nhsdat copy $(SLIB)sounds/\#? $(NETHACK)sounds echo >>T:make-nhsdat endif execute T:make-nhsdat -delete T:make-nhsdat $(SLIB)sounds: -makedir $(SLIB)sounds $(SBIN)cvtsnd: $(OO)cvtsnd.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)cvtsnd.o $(FLLIB) $(OO)cvtsnd.o: $(AMI)cvtsnd.c $(SLIB)sounds/Bell: $(SHARE)sounds/bell.uu $(UUDEC) $(SHARE)sounds/bell.uu $(SBIN)cvtsnd Bell $(SLIB)sounds/Bell -delete Bell $(SLIB)sounds/Bugle: $(SHARE)sounds/bugle.uu $(UUDEC) $(SHARE)sounds/bugle.uu $(SBIN)cvtsnd Bugle $(SLIB)sounds/Bugle -delete Bugle $(SLIB)sounds/Drum_Of_Earthquake: $(SHARE)sounds/erthdrum.uu $(UUDEC) $(SHARE)sounds/erthdrum.uu $(SBIN)cvtsnd Drum_Of_Earthquake $(SLIB)sounds/Drum_Of_Earthquake -delete Drum_Of_Earthquake $(SLIB)sounds/Fire_Horn: $(SHARE)sounds/firehorn.uu $(UUDEC) $(SHARE)sounds/firehorn.uu $(SBIN)cvtsnd Fire_Horn $(SLIB)sounds/Fire_Horn -delete Fire_Horn $(SLIB)sounds/Frost_Horn: $(SHARE)sounds/frsthorn.uu $(UUDEC) $(SHARE)sounds/frsthorn.uu $(SBIN)cvtsnd Frost_Horn $(SLIB)sounds/Frost_Horn -delete Frost_Horn $(SLIB)sounds/Leather_Drum: $(SHARE)sounds/lethdrum.uu $(UUDEC) $(SHARE)sounds/lethdrum.uu $(SBIN)cvtsnd Leather_Drum $(SLIB)sounds/Leather_Drum -delete Leather_Drum $(SLIB)sounds/Magic_Flute: $(SHARE)sounds/mgcflute.uu $(UUDEC) $(SHARE)sounds/mgcflute.uu $(SBIN)cvtsnd Magic_Flute $(SLIB)sounds/Magic_Flute -delete Magic_Flute $(SLIB)sounds/Magic_Harp: $(SHARE)sounds/mgcharp.uu $(UUDEC) $(SHARE)sounds/mgcharp.uu $(SBIN)cvtsnd Magic_Harp $(SLIB)sounds/Magic_Harp -delete Magic_Harp $(SLIB)sounds/Tooled_Horn: $(SHARE)sounds/toolhorn.uu $(UUDEC) $(SHARE)sounds/toolhorn.uu $(SBIN)cvtsnd Tooled_Horn $(SLIB)sounds/Tooled_Horn -delete Tooled_Horn $(SLIB)sounds/Wooden_Flute: $(SHARE)sounds/wdnflute.uu $(UUDEC) $(SHARE)sounds/wdnflute.uu $(SBIN)cvtsnd Wooden_Flute $(SLIB)sounds/Wooden_Flute -delete Wooden_Flute $(SLIB)sounds/Wooden_Harp: $(SHARE)sounds/wdnharp.uu $(UUDEC) $(SHARE)sounds/wdnharp.uu $(SBIN)cvtsnd Wooden_Harp $(SLIB)sounds/Wooden_Harp -delete Wooden_Harp inst-dungeon: $(INSTDUNGEONFILES) $(NETHACK)options : $(DAT)options copy $(DAT)options $@ # Create compiled dungeon files BGM= $(SLIB)bigrm-2.lev $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev $(BGM): $(SLIB)bigrm-1.lev $(SLIB)bigrm-1.lev: $(DAT)bigroom.des $(SBIN)lev_comp $(SLIB)castle.lev: $(DAT)castle.des $(SBIN)lev_comp ENDGAME1= $(SLIB)air.lev $(SLIB)earth.lev $(SLIB)fire.lev $(SLIB)water.lev $(ENDGAME1): $(SLIB)astral.lev $(SLIB)astral.lev: $(DAT)endgame.des $(SBIN)lev_comp GEHENNOM1= $(SLIB)asmodeus.lev $(SLIB)baalz.lev $(SLIB)juiblex.lev \ $(SLIB)orcus.lev $(SLIB)sanctum.lev $(GEHENNOM1): $(SLIB)valley.lev $(SLIB)valley.lev: $(DAT)gehennom.des $(SBIN)lev_comp $(SLIB)knox.lev: $(DAT)knox.des $(SBIN)lev_comp MINES1= $(SLIB)minend-1.lev $(SLIB)minend-2.lev $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(MINES1): $(SLIB)minefill.lev $(SLIB)minefill.lev: $(DAT)mines.des $(SBIN)lev_comp $(SLIB)oracle.lev: $(DAT)oracle.des $(SBIN)lev_comp TOWER1= $(SLIB)tower1.lev $(SLIB)tower2.lev $(TOWER1): $(SLIB)tower3.lev $(SLIB)tower3.lev: $(DAT)tower.des $(SBIN)lev_comp WIZARD1= $(SLIB)wizard1.lev $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(SLIB)fakewiz1.lev $(WIZARD1): $(SLIB)fakewiz2.lev $(SLIB)fakewiz2.lev: $(DAT)yendor.des $(SBIN)lev_comp MEDUSA1= $(SLIB)medusa-1.lev $(MEDUSA1): $(SLIB)medusa-2.lev $(SLIB)medusa-2.lev: $(DAT)medusa.des $(SBIN)lev_comp SOKOBAN1= $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev \ $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev \ $(SLIB)soko4-1.lev $(SOKOBAN1): $(SLIB)soko4-2.lev $(SLIB)soko4-2.lev: $(DAT)sokoban.des $(SBIN)lev_comp $(ADFILES1): $(SLIB)Arc-goal.lev $(SLIB)Arc-goal.lev: $(DAT)Arch.des $(SBIN)lev_comp $(BDFILES1): $(SLIB)Bar-goal.lev $(SLIB)Bar-goal.lev: $(DAT)Barb.des $(SBIN)lev_comp $(CDFILES1): $(SLIB)Cav-goal.lev $(SLIB)Cav-goal.lev: $(DAT)Caveman.des $(SBIN)lev_comp $(HDFILES1): $(SLIB)Hea-goal.lev $(SLIB)Hea-goal.lev: $(DAT)Healer.des $(SBIN)lev_comp $(KDFILES1): $(SLIB)Kni-goal.lev $(SLIB)Kni-goal.lev: $(DAT)Knight.des $(SBIN)lev_comp $(MDFILES1): $(SLIB)Mon-goal.lev $(SLIB)Mon-goal.lev: $(DAT)Monk.des $(SBIN)lev_comp $(PDFILES1): $(SLIB)Pri-goal.lev $(SLIB)Pri-goal.lev: $(DAT)Priest.des $(SBIN)lev_comp $(RDFILES1): $(SLIB)Rog-goal.lev $(SLIB)Rog-goal.lev: $(DAT)Rogue.des $(SBIN)lev_comp $(RANFILES1): $(SLIB)Ran-goal.lev $(SLIB)Ran-goal.lev: $(DAT)Ranger.des $(SBIN)lev_comp $(SDFILES1): $(SLIB)Sam-goal.lev $(SLIB)Sam-goal.lev: $(DAT)Samurai.des $(SBIN)lev_comp $(TDFILES1): $(SLIB)Tou-goal.lev $(SLIB)Tou-goal.lev: $(DAT)Tourist.des $(SBIN)lev_comp $(VDFILES1): $(SLIB)Val-goal.lev $(SLIB)Val-goal.lev: $(DAT)Valkyrie.des $(SBIN)lev_comp $(WDFILES1): $(SLIB)Wiz-goal.lev $(SLIB)Wiz-goal.lev: $(DAT)Wizard.des $(SBIN)lev_comp $(SLIB)dungeon: $(DAT)dungeon.def $(SBIN)makedefs $(SBIN)dgn_comp $(SBIN)makedefs -e $(SBIN)dgn_comp $(DAT)dungeon.pdf copy $(DAT)dungeon $(SLIB)dungeon delete $(DAT)dungeon inst-data: $(INSTDATAFILES) $(NETHACK)amii.hlp: $(AMI)amii.hlp copy $(AMI)amii.hlp $@ #$(NETHACK)data: $(DAT)data # copy $(DAT)data $@ $(SLIB)data: $(DAT)data.base $(I)config.h $(SBIN)makedefs $(SBIN)makedefs -d #$(NETHACK)rumors: $(DAT)rumors # copy $(DAT)rumors $@ $(SLIB)rumors: $(DAT)rumors.tru $(DAT)rumors.fal $(SBIN)makedefs $(SBIN)makedefs -r $(SLIB)cmdhelp: $(DAT)cmdhelp copy $(DAT)cmdhelp $@ $(SLIB)help: $(DAT)help copy $(DAT)help $@ $(SLIB)hh: $(DAT)hh copy $(DAT)hh $@ $(NETHACK)HackWB.hlp: $(AMI)HackWB.hlp copy $(AMI)HackWB.hlp $@ $(SLIB)history: $(DAT)history copy $(DAT)history $@ $(NETHACK)license: $(DAT)license copy $(DAT)license $@ $(SLIB)opthelp: $(DAT)opthelp copy $(DAT)opthelp $@ $(NETHACK)Recover.txt: $(DOC)Recover.txt copy $(DOC)Recover.txt $@ $(NETHACK)GuideBook.txt: $(DOC)GuideBook.txt copy $(DOC)GuideBook.txt $@ $(NETHACK)NetHack.txt: $(DOC)NetHack.txt copy $(DOC)NetHack.txt $@ $(NETHACK)Install.ami: $(AMI)Install.ami copy $(AMI)Install.ami $@ $(NETHACK)logfile: echo to $@ $(NETHACK)record: echo to $@ $(SLIB)wizhelp: $(DAT)wizhelp copy $(DAT)wizhelp $@ # Create the directories here because NetHack.cnf puts them there by default $(NETHACK)NetHack.cnf: $(AMI)NetHack.cnf copy $(AMI)NetHack.cnf $@ -makedir $(NETHACK)save -makedir $(NETHACK)levels # Unpack and install fonts INSTFONTFILES= $(NETHACK)hack.font $(NETHACK)hack $(NETHACK)hack/8 inst-fonts: $(INSTFONTFILES) $(NETHACK)hack/8: $(AMI)amifont8.uu $(NETHACK)hack $(UUDEC) $(AMI)amifont8.uu copy 8 $(NETHACK)hack/8 delete 8 $(NETHACK)hack.font: $(AMI)amifont.uu $(UUDEC) $(AMI)amifont.uu copy hack.font $(NETHACK)hack.font delete hack.font $(NETHACK)hack: -makedir $@ INSTICONFILES= \ $(NETHACK)default.icon $(NETHACK)NetHack.info $(NETHACK)NewGame.info \ $(NETHACK)HackWB.info inst-icons: $(INSTICONFILES) # Unpack the icons into place $(NETHACK)default.icon: $(AMI)dflticon.uu $(UUDEC) $(AMI)dflticon.uu # copy default.icon $(NETHACK)default.icon # delete default.icon $(NETHACK)NetHack.info: $(AMI)NHinfo.uu $(UUDEC) $(AMI)NHinfo.uu # copy NetHack.info $(NETHACK)NetHack.info # delete NetHack.info $(NETHACK)NewGame.info: $(AMI)NewGame.uu $(UUDEC) $(AMI)NewGame.uu # copy NewGame.info $(NETHACK)NewGame.info # delete NewGame.info $(NETHACK)HackWB.info: $(AMI)HackWB.uu $(UUDEC) $(AMI)HackWB.uu # copy HackWB.info $(NETHACK)HackWB.info # delete HackWB.info # If DLB is defined, create the nhdat library file in the playground # directory. If not, move all the data files there. $(NETHACK)nhdat: $(LIBFILES) list to T:nhdat.lst $(SLIB) QUICK NOHEAD FILES echo >T:make-nhdat $(SBIN)dlb cCfI $(SLIB) $(NETHACK)nhdat T:nhdat.lst echo >>T:make-nhdat if not exists $(NETHACK)nhdat echo >>T:make-nhdat copy $(SLIB)\#? $(NETHACK) echo >>T:make-nhdat endif execute T:make-nhdat -delete T:make-nhdat # DO NOT DELETE THIS LINE $(O)allmain.o: $(NHS)allmain.c $(HDEP) $(O)alloc.o: $(NHS)alloc.c $(I)config.h $(O)apply.o: $(NHS)apply.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)apply.c $(O)artifact.o: $(NHS)artifact.c $(HDEP) $(I)artifact.h $(I)artilist.h $(O)attrib.o: $(NHS)attrib.c $(HDEP) $(I)artifact.h $(O)ball.o: $(NHS)ball.c $(HDEP) $(O)bones.o: $(NHS)bones.c $(HDEP) $(I)lev.h $(O)botl.o: $(NHS)botl.c $(HDEP) $(O)cmd.o: $(NHS)cmd.c $(HDEP) $(I)func_tab.h $(O)dbridge.o: $(NHS)dbridge.c $(HDEP) $(O)decl.o: $(NHS)decl.c $(HDEP) $(I)quest.h $(O)detect.o: $(NHS)detect.c $(HDEP) $(I)artifact.h $(O)dig.o: $(NHS)dig.c $(HDEP) $(O)display.o: $(NHS)display.c $(HDEP) $(O)dlb.o: $(NHS)dlb.c $(HDEP) $(I)dlb.h $(O)do.o: $(NHS)do.c $(HDEP) $(I)lev.h $(O)do_name.o: $(NHS)do_name.c $(HDEP) $(O)do_wear.o: $(NHS)do_wear.c $(HDEP) $(O)dog.o: $(NHS)dog.c $(HDEP) $(O)dogmove.o: $(NHS)dogmove.c $(HDEP) $(I)mfndpos.h $(O)dokick.o: $(NHS)dokick.c $(HDEP) $(O)dothrow.o: $(NHS)dothrow.c $(HDEP) $(O)drawing.o: $(NHS)drawing.c $(HDEP) $(I)tcap.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)drawing.c $(O)dungeon.o: $(NHS)dungeon.c $(HDEP) $(I)dgn_file.h $(I)dlb.h $(O)eat.o: $(NHS)eat.c $(HDEP) $(O)end.o: $(NHS)end.c $(HDEP) $(I)lev.h $(I)dlb.h $(O)engrave.o: $(NHS)engrave.c $(HDEP) $(I)lev.h $(O)exper.o: $(NHS)exper.c $(HDEP) $(O)explode.o: $(NHS)explode.c $(HDEP) $(O)extralev.o: $(NHS)extralev.c $(HDEP) $(O)files.o: $(NHS)files.c $(HDEP) $(I)dlb.h $(I)date.h $(O)fountain.o: $(NHS)fountain.c $(HDEP) $(O)hack.o: $(NHS)hack.c $(HDEP) $(O)hacklib.o: $(NHS)hacklib.c $(HDEP) $(O)invent.o: $(NHS)invent.c $(HDEP) $(I)artifact.h $(O)light.o: $(NHS)light.c $(HDEP) $(I)lev.h $(O)lock.o: $(NHS)lock.c $(HDEP) $(O)mail.o: $(NHS)mail.c $(HDEP) $(I)mail.h $(O)makemon.o: $(NHS)makemon.c $(HDEP) $(O)mapglyph.o: $(NHS)mapglyph.c $(HDEP) $(O)mcastu.o: $(NHS)mcastu.c $(HDEP) $(O)mhitm.o: $(NHS)mhitm.c $(HDEP) $(I)artifact.h $(O)mhitu.o: $(NHS)mhitu.c $(HDEP) $(I)artifact.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)mhitu.c $(O)minion.o: $(NHS)minion.c $(HDEP) $(O)mklev.o: $(NHS)mklev.c $(HDEP) $(O)mkmap.o: $(NHS)mkmap.c $(HDEP) $(I)sp_lev.h $(O)mkmaze.o: $(NHS)mkmaze.c $(HDEP) $(I)sp_lev.h $(I)lev.h $(O)mkobj.o: $(NHS)mkobj.c $(HDEP) $(I)artifact.h $(I)prop.h $(O)mkroom.o: $(NHS)mkroom.c $(HDEP) $(O)mon.o: $(NHS)mon.c $(HDEP) $(I)mfndpos.h $(O)mondata.o: $(NHS)mondata.c $(HDEP) $(O)monmove.o: $(NHS)monmove.c $(HDEP) $(I)mfndpos.h $(I)artifact.h $(O)monst.o: $(NHS)monst.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)color.h $(O)monstr.o: $(NHS)monstr.c $(HDEP) $(O)mplayer.o: $(NHS)mplayer.c $(HDEP) $(O)mthrowu.o: $(NHS)mthrowu.c $(HDEP) $(O)muse.o: $(NHS)muse.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)muse.c $(O)music.o: $(NHS)music.c $(HDEP) #interp.c $(O)o_init.o: $(NHS)o_init.c $(HDEP) $(I)lev.h $(O)objects.o: $(NHS)objects.c $(I)config.h $(I)obj.h $(I)objclass.h \ $(I)prop.h $(I)skills.h $(I)color.h $(CC) $(CFLAGS) $(INCLSPEC)$(NHS) $(OBJSPEC)$@ $(NHS)objects.c $(O)objnam.o: $(NHS)objnam.c $(HDEP) $(O)options.o: $(NHS)options.c $(HDEP) $(I)tcap.h $(I)config.h \ $(I)objclass.h $(I)flag.h $(O)pager.o: $(NHS)pager.c $(HDEP) $(I)dlb.h $(O)pickup.o: $(NHS)pickup.c $(HDEP) $(O)pline.o: $(NHS)pline.c $(HDEP) $(O)polyself.o: $(NHS)polyself.c $(HDEP) $(O)potion.o: $(NHS)potion.c $(HDEP) $(O)pray.o: $(NHS)pray.c $(HDEP) $(O)priest.o: $(NHS)priest.c $(HDEP) $(I)mfndpos.h $(O)quest.o: $(NHS)quest.c $(HDEP) $(I)quest.h $(I)qtext.h $(O)questpgr.o: $(NHS)questpgr.c $(HDEP) $(I)qtext.h $(I)dlb.h $(O)read.o: $(NHS)read.c $(HDEP) $(O)rect.o: $(NHS)rect.c $(HDEP) $(O)region.o: $(NHS)region.c $(HDEP) $(O)restore.o: $(NHS)restore.c $(HDEP) $(I)lev.h $(I)tcap.h $(I)quest.h $(O)rnd.o: $(NHS)rnd.c $(HDEP) $(O)role.o: $(NHS)role.c $(HDEP) $(O)rumors.o: $(NHS)rumors.c $(HDEP) $(I)dlb.h $(O)save.o: $(NHS)save.c $(HDEP) $(I)lev.h $(I)quest.h $(O)shk.o: $(NHS)shk.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)shk.c $(O)shknam.o: $(NHS)shknam.c $(HDEP) $(O)sit.o: $(NHS)sit.c $(HDEP) $(I)artifact.h $(O)sounds.o: $(NHS)sounds.c $(HDEP) $(O)sp_lev.o: $(NHS)sp_lev.c $(HDEP) $(I)sp_lev.h $(I)rect.h $(I)dlb.h $(O)spell.o: $(NHS)spell.c $(HDEP) $(O)steal.o: $(NHS)steal.c $(HDEP) $(O)steed.o: $(NHS)steed.c $(HDEP) $(O)sys.o: $(NHS)sys.c $(HDEP) $(O)teleport.o: $(NHS)teleport.c $(HDEP) $(O)timeout.o: $(NHS)timeout.c $(HDEP) $(I)lev.h $(O)topten.o: $(NHS)topten.c $(HDEP) $(I)dlb.h $(O)track.o: $(NHS)track.c $(HDEP) $(O)trap.o: $(NHS)trap.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)trap.c $(O)u_init.o: $(NHS)u_init.c $(HDEP) $(O)uhitm.o: $(NHS)uhitm.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)uhitm.c $(O)vault.o: $(NHS)vault.c $(HDEP) $(O)version.o: $(NHS)version.c $(HDEP) $(I)date.h $(I)patchlevel.h $(O)vision.o: $(NHS)vision.c $(HDEP) #$(I)vis_tab.h $(O)weapon.o: $(NHS)weapon.c $(HDEP) $(O)were.o: $(NHS)were.c $(HDEP) $(O)wield.o: $(NHS)wield.c $(HDEP) $(O)windows.o: $(NHS)windows.c $(HDEP) $(I)wintty.h $(O)wizard.o: $(NHS)wizard.c $(HDEP) $(I)qtext.h $(O)worm.o: $(NHS)worm.c $(HDEP) $(I)lev.h $(O)worn.o: $(NHS)worn.c $(HDEP) $(O)write.o: $(NHS)write.c $(HDEP) $(O)zap.o: $(NHS)zap.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)zap.c $(O)getline.o: $(TTY)getline.c $(HDEP) $(I)wintty.h $(O)termcap.o: $(TTY)termcap.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)topl.o: $(TTY)topl.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)wintty.o: $(TTY)wintty.c $(HDEP) $(I)wintty.h $(I)tcap.h \ $(I)date.h $(I)patchlevel.h $(O)amitty.o: $(AMI)amitty.c $(HDEP) $(O)amistack.o: $(AMI)amistack.c $(CC) $(CFLAGS3) $(CSYM) $(OBJSPEC)$@ $(AMI)amistack.c $(O)rip.o: $(NHS)rip.c $(HDEP) $(I)config.h: $(I)config1.h $(I)tradstdc.h $(I)global.h -setdate $(I)config.h -c:wait 2 # onames.h handled at onames.h target, pm.h $(I)decl.h: $(I)quest.h $(I)spell.h $(I)color.h $(I)obj.h $(I)you.h -setdate $(I)decl.h -c:wait 2 $(I)global.h: $(I)coord.h $(I)pcconf.h $(I)amiconf.h -setdate $(I)global.h -c:wait 2 $(I)hack.h: $(I)config.h $(I)context.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h $(I)display.h $(I)wintype.h $(I)engrave.h $(I)rect.h $(I)region.h $(I)trampoli.h $(I)sys.h -setdate $(I)hack.h -c:wait 2 $(I)permonst.h: $(I)monattk.h $(I)monflag.h $(I)align.h -setdate $(I)permonst.h -c:wait 2 $(I)you.h: $(I)align.h $(I)attrib.h $(I)monst.h $(I)mextra.h $(I)youprop.h $(I)skills.h -setdate $(I)you.h -c:wait 2 # pm.h handled at target $(I)youprop.h: $(I)prop.h $(I)permonst.h $(I)mondata.h -setdate $(I)youprop.h -c:wait 2 $(I)display.h: $(I)vision.h $(I)mondata.h -setdate $(I)display.h -c:wait 2 $(I)dungeon.h: $(I)align.h -setdate $(I)dungeon.h -c:wait 2 $(I)engrave.h: $(I)trampoli.h $(I)rect.h -setdate $(I)engrave.h -c:wait 2 $(I)mextra.h: $(I)align.h -setdate $(I)mextra.h -c:wait 2 $(I)mondata.h: $(I)align.h -setdate $(I)mondata.h -c:wait 2 $(I)monst.h: $(I)align.h $(I)mextra.h -setdate $(I)monst.h -c:wait 2 $(I)pcconf.h: $(I)micro.h $(I)system.h -setdate $(I)pcconf.h -c:wait 2 $(I)rm.h: $(I)align.h -setdate $(I)rm.h -c:wait 2 #notes # install keeps doing re-install because it keeps rebuilding lev_comp??? # fixed(?) - deleted setdate nethack-3.6.0/sys/amiga/Makefile.ami0000664000076400007660000013540612536476415016264 0ustar paxedpaxed# NetHack Makefile. # Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996. # NetHack may be freely redistributed. See license for details. ### ### INTRODUCTION ### # This makefile is arranged for compiling for the Amiga with SAS/C 6.51 but # can be configured for compiling with Manx C 5 or commercial DICE with # simple changes. The appropriate changes are identified by #[compiler] # where compiler is one of: SAS6, MANX, or DICE; the options in this # makefile as should be set according to the compiler being used. (But see # note 3 below.) # Note: When using the Manx compiler, an alternate make utility is # required. The bundled Aztec make is just too damaged. # Note 2: The #SFD_xxx lines are used with mkdmake to generate a DMake- # compatible makefile (DMakefile) from this file. Any line beginning with # #SFD_INSTEAD replaces, in DMakefile, the following line from Makefile.ami. # #SFD_BEGIN, #SFD_ELSE, and #SFD_END bracket multi-line sections for the two # makefile formats. # When changing this file, #SFD_INSTEAD lines will need to be inserted for # the following cases: # - Dependencies with different numbers of filenames (both > 1) on # either side. The #SFD_INSTEAD line should immediately precede # the line with the colon, and should contain a double colon "::" # instead of a single colon. # - Special command lists that override the default. A line containing # "#SFD_INSTEAD #none" should precede such a rule. If the rule is # more than one line long, precede it with "#SFD_BEGIN" and # "#SFD_ELSE", and follow it with "#SFD_END". # - Files not in the src, sys/amiga, sys/share, or win/tty directories # that rely on the default ".c.o" rule. Following the dependency # should be "#SFD_INSTEAD " with the filename inserted # into the default rule where appropriate, then a line contianing # "#none". # In any SFD_BEGIN/ELSE/END block added, put a '##' before every line # between the BEGIN and ELSE. Any line that's really a comment needs three # '#'s, e.g. "### DICE comment". # Note 2A: Whenever an SFD line/block is added, the appropriate repeat count # in mkdmake must be changed. (The repeat count "0" meaning "repeat # until end of file" doesn't work as advertised.) # Note 3: mkdmake will automatically substitute DICE flags, etc. for SAS # where appropriate. Since the makefile is already set up for SAS, # the only people who end up having to make changes here are Manx # users (or people who want to change the defaults). ### ### DIRECTORY STRUCTURE ### NH = NH: SBIN = $(NH)sbin/ SLIB = $(NH)slib/ NETHACK = $(NH)NetHack/ HACKEXE = $(NH)HackExe/ AMI = $(NH)sys/amiga/ DAT = $(NH)dat/ DOC = $(NH)doc/ I = $(NH)include/ SHARE = $(NH)sys/share/ NHS = $(NH)src/ TTY = $(NH)win/tty/ WSHARE = $(NH)win/share/ UTIL = $(NH)util/ O = $(NH)obj/ OO = $(NH)objo/ # NB: O and OO MUST be different directories ### ### INVOCATION ### #[SAS6] #MAKE = smake #[MANX] #MAKE = make #[DICE] #MAKE = dmake # Startup makefile with: # #[SAS6] #[MANX] # $(MAKE) -f $(AMI)Makefile.ami # $(MAKE) -f $(AMI)Makefile.ami install # #[DICE] # $(MAKE) -f $(AMI)DMakefile # $(MAKE) -f $(AMI)DMakefile install # # # You may use following targets on $(MAKE) command lines: # all do it all (default) # link just create binary from object files # obj just create common object files # obja just create amiga object files # objs just create shared object files # clean deletes the object files # spotless deletes the object files, main binary, and more # # Note: We do not build the Guidebook here since it needs tbl # (See the file sys/unix/Makefile.doc for more information) #X# Precompiled header files: #X# $(HDEP) should appear in any dependency list for an object file where #X# we would want to make use of the precompiled version of $(I)hack.h, #X# while $(CSYM) should appear in the C compiler command line that creates #X# any such object file. (Changes made here should agree with the $(HDEP): #X# target that appears later in this makefile.) #X# #SFD_BEGIN ## ###[DICE] ### If we were compiling with DICE and wanted to use the symbol table ### pre-loading feature, we would uncomment these following two lines. ## ##HDEP = $(I)hack.sym ##CSYM = -H$(I)hack.sym=hack.h ## #SFD_ELSE #[SAS5] # If we were to use the precompiled header file feature in a newer version # of SAS/C, we would comment out these following two lines. # If we don't use precompiled header files, we uncomment it as well. HDEP = $(I)hack.h $(I)pm.h $(I)onames.h CSYM = #[MANX] # If we were compiling with Aztec, and wanted to use the symbol table # pre-loading feature, we would uncomment these following two lines. #HDEP = Ram:hack.sym #CSYM = +IRam:hack.sym #SFD_END #Pathname for uudecode program: UUDEC = uudecode # Flex/Bison command assignments -- Useful only if you have flex/bison FLEX = flex BISON = bison # FBFIL and FBLIB may be used, if required by your version of flex or bison, # to specify additional files or libraries to be linked with FBFIL = FBLIB = #lib lib:compat.lib # If you're compiling this on a 1.3 system, you'll have to uncomment the # following (for use with the ifchange script below). Also useful instead of # "protect ifchange +s" EXECUTE = execute # Headers we depend on AMDEP = $(AMI)winproto.h $(AMI)winext.h $(AMI)windefs.h $(I)winami.h # Pathname for the C compiler being used. #SFD_BEGIN ## ###[DICE] ##CC = dcc ##ASM = das ## #SFD_ELSE #[SAS6] CC = sc ASM = asm #[MANX] #CC = cc #SFD_END # Compilation flags for selected C Compiler: # $(CFLAGS) should appear before filename arguments of $(CC) command line. #SFD_BEGIN ## ###[DICE] ##CFLAGS = -c -I$(I) -mC -mD -ms -// ##CFLAGS2 = ##WBCFLAGS = -c -I$(I) -mC -mD -ms -// ##WBC2FLAGS = -DCLI ##SPLFLAGS = -DSPLIT ## #SFD_ELSE #[SAS6] # Note: make sure your CLI stack size is large (at least 50K) or lev_comp # and makedefs may fail terribly - stack checking is disabled. # # **** WARNING **** GST support is not fool proof. You must make makedefs # without a GST first so that the generated headers # that are part of the GST can be made. # #GSTSRC=$(AMI)gst.c # #GSTHEAD=$(I)hack.h $(I)pm.h $(I)trap.h $(I)onames.h \ # $(AMI)winami.p $(AMI)amidos.p $(AMI)amiwind.p # #GSTFILE=$(O)NetHack.gst # undefine this to not compile with GSTs #GST=gst=$(GSTFILE) # DEBUG=debug=symbol CPU=cpu=68000 #OPTFLAGS=opt opttime optpeep optgo optinl optsched optcomp=10 optdep=5 optrdep=5 #optalias +OPTTIME -OPTSIZE CFLAGS = data=far nominc $(DEBUG) idir=$(I) $(CPU) nostkchk nover \ codename=nhcode dataname=nhdata strmerge $(OPTFLAGS) $(TILES) $(SAVEDS) \ afp $(ERRREXX) $(GST) # for files that are too large for the standard flags: CFLAGS2 = code=far strmerge $(SAVEDS) WBCFLAGS = ignore=217,62 data=far ansi nminc code=far idir=$(I) $(CPU) afp \ $(DEBUG) $(ERRREXX) define=AMIGA $(GST) XXX = data=far ansi nminc idir=$(I) $(CPU) afp opt optinline optinlocal \ optloop opttime WBC2FLAGS = define=CLI SPLFLAGS = define=SPLIT #dollarok #for amistack.c CFLAGS3 = data=near dataname=__MERGED nominc $(DEBUG) idir=$(I) $(CPU) nover nostkchk \ codename=nhcode strmerge $(OPTFLAGS) $(TILES) $(SAVEDS) \ afp $(ERRREXX) $(GST) #[MANX] #CFLAGS = -i$(I) -mc -md -ms -pa -ps -bs -wo -qq #WBCFLAGS = -mc -md -ms -pa -ps -bs -wo -qq -pp #SFD_END # Assembly flags: #SFD_BEGIN ## ###[DICE] ##AFLAGS = ##AOBJSPEC = -o ## #SFD_ELSE #[SAS6] AFLAGS = #what to put here? AOBJSPEC = -o #SFD_END # Components of various link command lines: # $(LINK) should be the pathname of the linker being used (with any options # that should appear at the beginning of the command line). The name of the # output file should appear immediately after $(LNSPEC). $(LIN) should # appear before the list of object files in each link command. $(LLINK) # should appear as the list of object files in the link command line that # creates the NetHack executable. $(LLIB) should appear at the end of each # link command line. # Note: amiga.lib added due to missing prototypes/pragmas. # Should be deleted when this is resolved. #SFD_BEGIN ## ###[DICE] ### If you have flex/bison libraries, use the second definition of FLLIB ### instead of the first. ## ##LINK = dcc -mD ##LIN = ##LLINK = @$(AMI)ami.lnk ##LLIB = ##FLLIB = ###FLLIB = -l$(FBLIB) ##OBJSPEC = -o ##PNSPEC = -o ##LNSPEC = -o ##CCLINK = dcc ##CLFLAGS = -I$(I) -mC -mD -ms -// ##INCLSPEC = -I ##DEFSPEC = -D ##IGNSPEC = -j ## #SFD_ELSE #[SAS6] LINK = slink noicons verbose maxhunk 262144 stripdebug LIN = from lib:catch.o LLINK = with $(AMI)ami.lnk LLIB = lib lib:scnb.lib BATCH #lib lib:amiga.lib BATCH #scnb.lib or sc.lib FLLIB = $(FBLIB) lib Lib:sc.lib BATCH OBJSPEC = objname= PNSPEC = noicons to #pname= LNSPEC = to CCLINK = sc link INCLSPEC = idir= DEFSPEC = define= IGNSPEC = ignore= COMPACT_HEADERS=$(GSTFILE) #[MANX] #LINK = ln -g +q +ss -o #LIN = #LLINK = -f $(AMI)ami.lnk #LLIB = -lcl16 #FLLIB = -lcl16 #OBJSPEC = -o #PNSPEC = -o #LNSPEC = -o #CCLINK = cc #INCLSPEC = -i #DEFSPEC = -d #IGNSPEC = -j #SFD_END ### ### FILE LISTS ### # A more reasonable random number generator (recommended for the Amiga): RANDOBJ = $(O)random.o #SFD_INSTEAD #none .PRECIOUS: $(I)config.h $(I)decl.h $(I)hack.h $(I)permonst.h $(I)you.h # Almost nothing below this line should have to be changed. # (Exceptions are marked by [SAS6], [MANX], etc.) # # Other things that have to be reconfigured are in config.h, # (amiconf.h, pcconf.h), and possibly system.h, tradstdc.h. # Object files for makedefs: MAKEOBJS = \ $(OO)makedefs.o $(O)monst.o $(O)objects.o # Object files for special levels compiler: SPLEVOBJS = \ $(OO)lev_yacc.o $(OO)lev_lex.o $(OO)lev_main.o \ $(O)decl.o $(O)drawing.o $(O)monst.o \ $(O)objects.o $(OO)panic.o # Object files for dungeon compiler DGNCOMPOBJS = \ $(OO)dgn_yacc.o $(OO)dgn_lex.o $(OO)dgn_main.o $(O)alloc.o $(OO)panic.o # Object files for NetHack: COMMOBJ = \ $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o \ $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o \ $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o \ $(O)dig.o $(O)display.o $(O)dlb.o $(O)do.o \ $(O)do_name.o $(O)do_wear.o $(O)dog.o $(O)dogmove.o \ $(O)dokick.o $(O)dothrow.o $(O)drawing.o $(O)dungeon.o \ $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o \ $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o \ $(O)hack.o $(O)hacklib.o $(O)invent.o $(O)light.o \ $(O)lock.o $(O)mail.o $(O)makemon.o $(O)mapglyph.o \ $(O)mcastu.o $(O)mhitm.o $(O)mhitu.o $(O)minion.o \ $(O)mklev.o $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o \ $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o \ $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o \ $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o \ $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o \ $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o \ $(O)quest.o $(O)questpgr.o $(O)read.o $(O)rect.o \ $(O)region.o $(O)restore.o $(O)rnd.o $(O)role.o \ $(O)rumors.o $(O)save.o $(O)shk.o $(O)shknam.o \ $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o \ $(O)steal.o $(O)steed.o $(O)sys.o $(O)teleport.o \ $(O)timeout.o $(O)topten.o $(O)track.o $(O)trap.o \ $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)version.o \ (O)vision.o $(O)weapon.o $(O)were.o $(O)wield.o \ $(O)windows.o $(O)wizard.o $(O)worm.o $(O)worn.o \ $(O)write.o $(O)zap.o MAKEDEFOBJ = \ $(O)monstr.o AMIGAOBJ = \ $(O)amidos.o $(O)amirip.o $(O)amisnd.o $(O)amistack.o \ $(O)amiwind.o $(O)winami.o $(O)winchar.o $(O)winfuncs.o \ $(O)winkey.o $(O)winmenu.o $(O)winreq.o $(O)winstr.o # Objects from assembly sources (because DMake can't handle default rules) AMIGAOBJ2 = \ # $(O)dispmap.o SHAREOBJ = \ $(O)pcmain.o $(RANDOBJ) TTYOBJ = \ $(O)getline.o $(O)termcap.o $(O)topl.o $(O)wintty.o $(O)amitty.o \ $(O)rip.o # Yuck yuck yuck. Have to tell DMake where these are, since they're not # all in the same place. TTYSRC = \ $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \ $(AMI)amitty.c $(NHS)rip.c # All the object files for NetHack: HOBJ = $(COMMOBJ) $(AMIGAOBJ) $(AMIGAOBJ2) $(SHAREOBJ) $(MAKEDEFOBJ) $(TTYOBJ) ### ### DATA FILES ### # quest files ADFILES1= $(SLIB)Arc-fila.lev $(SLIB)Arc-filb.lev $(SLIB)Arc-loca.lev \ $(SLIB)Arc-strt.lev ADFILES= $(SLIB)Arc-goal.lev $(ADFILES1) BDFILES1= $(SLIB)Bar-fila.lev $(SLIB)Bar-filb.lev $(SLIB)Bar-loca.lev \ $(SLIB)Bar-strt.lev BDFILES= $(SLIB)Bar-goal.lev $(BDFILES1) CDFILES1= $(SLIB)Cav-fila.lev $(SLIB)Cav-filb.lev $(SLIB)Cav-loca.lev \ $(SLIB)Cav-strt.lev CDFILES= $(SLIB)Cav-goal.lev $(CDFILES1) HDFILES1= $(SLIB)Hea-fila.lev $(SLIB)Hea-filb.lev $(SLIB)Hea-loca.lev \ $(SLIB)Hea-strt.lev HDFILES= $(SLIB)Hea-goal.lev $(HDFILES1) KDFILES1= $(SLIB)Kni-fila.lev $(SLIB)Kni-filb.lev $(SLIB)Kni-loca.lev \ $(SLIB)Kni-strt.lev KDFILES= $(SLIB)Kni-goal.lev $(KDFILES1) MDFILES1= $(SLIB)Mon-fila.lev $(SLIB)Mon-filb.lev $(SLIB)Mon-loca.lev \ $(SLIB)Mon-strt.lev MDFILES= $(SLIB)Mon-goal.lev $(MDFILES1) PDFILES1= $(SLIB)Pri-fila.lev $(SLIB)Pri-filb.lev $(SLIB)Pri-loca.lev \ $(SLIB)Pri-strt.lev PDFILES= $(SLIB)Pri-goal.lev $(PDFILES1) RDFILES1= $(SLIB)Rog-fila.lev $(SLIB)Rog-filb.lev $(SLIB)Rog-loca.lev \ $(SLIB)Rog-strt.lev RDFILES= $(SLIB)Rog-goal.lev $(RDFILES1) RANFILES1= $(SLIB)Ran-fila.lev $(SLIB)Ran-filb.lev $(SLIB)Ran-loca.lev \ $(SLIB)Ran-strt.lev RANFILES= $(SLIB)Ran-goal.lev $(RANFILES1) SDFILES1= $(SLIB)Sam-fila.lev $(SLIB)Sam-filb.lev $(SLIB)Sam-loca.lev \ $(SLIB)Sam-strt.lev SDFILES= $(SLIB)Sam-goal.lev $(SDFILES1) TDFILES1= $(SLIB)Tou-fila.lev $(SLIB)Tou-filb.lev $(SLIB)Tou-loca.lev \ $(SLIB)Tou-strt.lev TDFILES= $(SLIB)Tou-goal.lev $(TDFILES1) VDFILES1= $(SLIB)Val-fila.lev $(SLIB)Val-filb.lev $(SLIB)Val-loca.lev \ $(SLIB)Val-strt.lev VDFILES= $(SLIB)Val-goal.lev $(VDFILES1) WDFILES1= $(SLIB)Wiz-fila.lev $(SLIB)Wiz-filb.lev $(SLIB)Wiz-loca.lev \ $(SLIB)Wiz-strt.lev WDFILES= $(SLIB)Wiz-goal.lev $(WDFILES1) XDFILES= $(ADFILES) $(BDFILES) $(CDFILES) $(HDFILES) $(KDFILES) \ $(MDFILES) $(PDFILES) $(RDFILES) $(RANFILES) $(SDFILES) $(TDFILES) \ $(VDFILES) $(WDFILES) SOUNDFILES= \ $(SBIN)cvtsnd \ $(SLIB)sounds \ $(SLIB)sounds/Bell $(SLIB)sounds/Bugle \ $(SLIB)sounds/Drum_Of_Earthquake \ $(SLIB)sounds/Fire_Horn $(SLIB)sounds/Frost_Horn \ $(SLIB)sounds/Leather_Drum $(SLIB)sounds/Magic_Flute \ $(SLIB)sounds/Magic_Harp $(SLIB)sounds/Tooled_Horn \ $(SLIB)sounds/Wooden_Flute $(SLIB)sounds/Wooden_Harp TILEFILES= \ $(SBIN)txt2iff \ $(NETHACK)tiles \ $(NETHACK)tiles/objects.iff \ $(NETHACK)tiles/monsters.iff \ $(NETHACK)tiles/other.iff INSTDUNGEONFILES1= \ $(SLIB)air.lev $(SLIB)asmodeus.lev $(SLIB)astral.lev \ $(SLIB)baalz.lev $(SLIB)bigrm-1.lev $(SLIB)bigrm-2.lev \ $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev \ $(SLIB)castle.lev $(SLIB)dungeon $(SLIB)earth.lev \ $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev $(SLIB)fire.lev \ $(SLIB)juiblex.lev $(SLIB)knox.lev $(SLIB)medusa-1.lev \ $(SLIB)medusa-2.lev $(SLIB)minend-1.lev $(SLIB)minend-2.lev \ $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(SLIB)minefill.lev \ $(SLIB)options $(SLIB)oracle.lev $(SLIB)orcus.lev \ $(SLIB)sanctum.lev $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev \ $(SLIB)soko2-1.lev $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev \ $(SLIB)soko3-2.lev $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev \ $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev \ $(SLIB)valley.lev $(SLIB)water.lev $(SLIB)wizard1.lev \ $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(XDFILES) INSTDUNGEONFILES= $(NETHACK)NetHack.cnf $(INSTDUNGEONFILES1) INSTDATAFILES= \ $(NETHACK)license $(NETHACK)logfile $(NETHACK)record \ $(NETHACK)tomb.iff $(NETHACK)amii.hlp $(NETHACK)Recover.txt \ $(NETHACK)GuideBook.txt $(NETHACK)NetHack.txt $(NETHACK)Install.ami LIBFILES= \ $(INSTDUNGEONFILES1) \ $(SLIB)cmdhelp $(SLIB)data $(SLIB)dungeon \ $(SLIB)help $(SLIB)hh $(SLIB)history \ $(SLIB)opthelp $(SLIB)oracles $(SLIB)rumors \ $(SLIB)quest.dat $(SLIB)wizhelp ### ### Getting down to business: ### #SFD_INSTEAD all: $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \ all: $(COMPACT_HEADERS) $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \ $(SBIN)dlb $(NETHACK)recover install: all inst-data inst-dungeon inst-fonts inst-sounds inst-tiles \ $(NETHACK)nhdat $(NETHACK)NetHack $(SBIN)NetHack: $(HOBJ) $(AMI)ami.lnk $(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLINK) $(LLIB) $(NETHACK)NetHack: $(SBIN)NetHack copy $(SBIN)NetHack $(NETHACK)NetHack link: $(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLINK) $(LLIB) $(AMI)ami.lnk: $(AMI)Makefile.ami list to $(AMI)ami.lnk lformat="$(O)%s" $(O)\#?.o QUICK NOHEAD ## dlb support $(OO)dlb_main.o: $(UTIL)dlb_main.c $(HDEP) $(I)dlb.h $(I)date.h $(CC) $(CFLAGS) $(OBJSPEC)$(OO)dlb_main.o $(UTIL)dlb_main.c $(SBIN)dlb: $(OO)dlb_main.o $(O)dlb.o $(O)alloc.o $(OO)panic.o $(LINK) $(PNSPEC) $(SBIN)dlb $(LIN) $(OO)dlb_main.o $(O)dlb.o \ $(O)alloc.o $(OO)panic.o $(LLIB) obj: $(HOBJ) obja: $(AMIGAOBJ) objs: $(SHAREOBJ) #SFD_BEGIN #SFD_ELSE SUFFIXES = .lev .des .des.lev: $(SBIN)lev_comp $< #SFD_END # The default method for creating object files: #SFD_BEGIN ## ###[DICE] ## ##$(COMMOBJ): $(COMMOBJ:"$(O)*.o":"$(NHS)%1.c") ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## ##$(AMIGAOBJ): $(AMIGAOBJ:"$(O)*.o":"$(AMI)%1.c") ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## ##$(SHAREOBJ): $(SHAREOBJ:"$(O)*.o":"$(SHARE)%1.c") ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## ##$(TTYOBJ): $(TTYSRC) ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## #SFD_ELSE #[SAS6] .c.o: $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)$@ $< #SFD_END clean: -delete $(O)\#?.o $(OO)\#?.o spotless: clean -delete $(SBIN)NetHack $(SBIN)lev_comp $(SBIN)makedefs $(SBIN)dgn_comp -delete $(SBIN)cvtsnd $(SBIN)dlb $(SBIN)txt2iff $(SBIN)splitter -delete $(SBIN)tilemap -delete $(SLIB)data $(SLIB)rumors -delete $(SLIB)\#?.lev -delete $(SLIB)dungeon -delete $(SLIB)cmdhelp $(SLIB)help $(SLIB)hh $(SLIB)history -delete $(SLIB)opthelp $(SLIB)options $(SLIB)oracles -delete $(SLIB)quest.dat $(SLIB)wizhelp # -delete $(SLIB)earth.lev $(SLIB)air.lev $(SLIB)fire.lev # -delete $(SLIB)water.lev $(SLIB)astral.lev # -delete $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev # -delete $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev # -delete $(SLIB)medusa-1.lev $(SLIB)medusa-2.lev # -delete $(SLIB)oracle.lev $(SLIB)wizard1.lev $(SLIB)wizard2.lev # -delete $(SLIB)wizard3.lev $(DAT)dungeon.pdf $(SLIB)valley.lev # -delete $(SLIB)minefill.lev # -delete $(SLIB)minetn-1 $(SLIB)minetn-2 $(SLIB)minend-1 $(SLIB)minend-2 # -delete $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev # -delete $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev # -delete $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev # -delete $(ADFILES) # -delete $(BDFILES) # -delete $(CDFILES) # -delete $(HDFILES) # -delete $(KDFILES) # -delete $(MDFILES) # -delete $(PDFILES) # -delete $(RDFILES) # -delete $(RANFILES) # -delete $(SDFILES) # -delete $(TDFILES) # -delete $(VDFILES) # -delete $(WDFILES) -delete $(I)onames.h $(I)pm.h $(I)date.h -delete $(NHS)tile.c $(NHS)monstr.c -delete $(I)tile.h # -echo to $(I)onames.h "" noline # -wait 2 # -echo to $(I)pm.h "" noline # -wait 2 # -setdate $(UTIL)makedefs.c # -wait 2 # Creating precompiled version of $(I)hack.h to save disk I/O. #SFD_BEGIN ## ###[DICE] ### If we were compiling with DICE and wanted to use the symbol table ### pre-loading feature, we would technically not need a rule to make the ### precompiled header file, because DCC handles this automatically; ### however, we must delete the precompiled header file if any of the ### includes change, and we need to create it manually because the ### sys/amiga sources, compiled first, define things differently than the ### main sources want them. ## ##$(HDEP): $(I)hack.h $(I)pm.h $(I)onames.h ## -delete $(I)hack.sym ## echo to Ram:hackincl.c "#include " ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)Ram:hackincl.o Ram:hackincl.c ## -delete Ram:hackincl.c Ram:hackincl.o ## #SFD_ELSE #X#[SAS5] #X# If we were to use the precompiled header file feature of SAS/C, we #X# would uncomment the following lines. (Also see defines for HDEP and #X# CSYM near the beginning of this file, as these should be appropriately #X# defined.) #X#$(HDEP): $(I)hack.h $(SBIN)makedefs #X# echo to Ram:hackincl.c "#include <$(I)hack.h>" #X# $(CC) $(CFLAGS) -ph $(OBJSPEC)$@ Ram:hackincl.c #X# -delete Ram:hackincl.c #[MANX] # If we were compiling with Aztec, and wanted to use the symbol table # pre-loading feature, we would uncomment these following two lines. #$(HDEP): $(I)hack.h $(SBIN)makedefs # $(CC) $(CFLAGS) -a $(OBJSPEC)Ram:hack.asm +h$@ $(I)hack.h # -delete Ram:hack.asm #SFD_END # # Please note: The dependency lines for the modules here are # deliberately incorrect. Including "hack.h" in # the dependency list would cause a dependency # loop. # $(SBIN)makedefs: $(MAKEOBJS) $(LINK) $(LNSPEC) $(SBIN)makedefs $(LIN) $(MAKEOBJS) $(LLIB) $(OO)makedefs.o: $(UTIL)makedefs.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)objclass.h $(I)patchlevel.h $(I)qtext.h $(I)artilist.h $(CC) $(DEFSPEC)MAKEDEFS_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)makedefs.c $(SBIN)lev_comp: $(SPLEVOBJS) $(LINK) $(LNSPEC) $(SBIN)lev_comp $(LIN) $(SPLEVOBJS) $(FBFIL) $(FLLIB) $(SBIN)dgn_comp: $(DGNCOMPOBJS) $(LINK) $(LNSPEC) $(SBIN)dgn_comp $(LIN) $(DGNCOMPOBJS) $(FBFIL) $(FLLIB) $(OO)lev_yacc.o: $(UTIL)lev_yacc.c $(HDEP) $(I)sp_lev.h $(I)pm.h $(I)onames.h # setdate $(UTIL)lev_yacc.c $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)PREFIX="NH:slib/" $(CFLAGS) \ $(DEFSPEC)alloca=malloc $(OBJSPEC)$@ $(UTIL)lev_yacc.c $(OO)lev_lex.o: $(UTIL)lev_lex.c $(HDEP) $(I)lev_comp.h $(I)sp_lev.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)lev_lex.c $(OO)lev_main.o: $(UTIL)lev_main.c $(HDEP) $(I)pm.h $(I)onames.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)lev_main.c $(OO)dgn_yacc.o: $(UTIL)dgn_yacc.c $(HDEP) $(I)dgn_file.h $(I)patchlevel.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(DEFSPEC)alloca=malloc \ $(OBJSPEC)$@ $(UTIL)dgn_yacc.c $(OO)dgn_lex.o: $(UTIL)dgn_lex.c $(I)config.h $(I)dgn_comp.h $(I)dgn_file.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)dgn_lex.c $(OO)dgn_main.o: $(UTIL)dgn_main.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)dgn_main.c $(OO)panic.o: $(UTIL)panic.c $(HDEP) #SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) $(UTIL)panic.c #none $(OO)recover.o: $(UTIL)recover.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)recover.c $(NETHACK)recover: $(OO)recover.o $(LINK) $(LNSPEC) $(NETHACK)recover $(LIN) $(OO)recover.o $(LLIB) # [OPTION] -- If you have flex/bison, leave these uncommented. Otherwise, # comment them out and be careful! (You're not guaranteed to have the most # up to date *_comp.c, *_comp.h and *_lex.c) $(I)lev_comp.h: $(UTIL)lev_yacc.c $(I)patchlevel.h $(UTIL)lev_yacc.c: $(UTIL)lev_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)lev_comp.y # copy y.tab.c $(UTIL)lev_yacc.c # copy y.tab.h $(I)lev_comp.h copy $(UTIL)lev_comp.tab.c $(UTIL)lev_yacc.c copy $(UTIL)lev_comp.tab.h $(I)lev_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)lev_comp.tab.c delete $(UTIL)lev_comp.tab.h $(UTIL)lev_lex.c: $(UTIL)lev_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)lev_comp.l copy lex.yy.c $(UTIL)lev_lex.c delete lex.yy.c $(I)dgn_comp.h: $(UTIL)dgn_yacc.c $(I)patchlevel.h $(UTIL)dgn_yacc.c: $(UTIL)dgn_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)dgn_comp.y # copy y.tab.c $(UTIL)dgn_yacc.c # copy y.tab.h $(I)dgn_comp.h copy $(UTIL)dgn_comp.tab.c $(UTIL)dgn_yacc.c copy $(UTIL)dgn_comp.tab.h $(I)dgn_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)dgn_comp.tab.c delete $(UTIL)dgn_comp.tab.h $(UTIL)dgn_lex.c: $(UTIL)dgn_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)dgn_comp.l copy lex.yy.c $(UTIL)dgn_lex.c delete lex.yy.c # # The following include files depend on makedefs to be created. # As a result, they are not defined in HACKINCL, instead, their # dependencies are explicitly outlined here. # # # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # #SFD_INSTEAD $(I)date.h $(DAT)options:: $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)date.h $(DAT)options: $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)patchlevel.h $(SBIN)makedefs -v $(EXECUTE) $(AMI)ifchange MOVE $(I)t.date.h $(I)date.h -wait 2 $(I)onames.h: $(SBIN)makedefs $(SBIN)makedefs -o $(EXECUTE) $(AMI)ifchange TOUCH $(I)t.onames.h $(I)onames.h $(I)decl.h $(EXECUTE) $(AMI)ifchange MOVE $(I)t.onames.h $(I)onames.h -wait 2 $(I)pm.h: $(SBIN)makedefs $(SBIN)makedefs -p $(EXECUTE) $(AMI)ifchange TOUCH $(I)t.pm.h $(I)pm.h $(I)decl.h $(I)youprop.h $(EXECUTE) $(AMI)ifchange MOVE $(I)t.pm.h $(I)pm.h -wait 2 $(SLIB)quest.dat: $(DAT)quest.txt $(SBIN)makedefs $(SBIN)makedefs -q $(NHS)monstr.c: $(HDEP) $(SBIN)makedefs $(SBIN)makedefs -m -wait 2 $(SLIB)oracles: $(DAT)oracles.txt $(SBIN)makedefs $(SBIN)makedefs -h -wait 2 # # The following programs vary depending on what OS you are using. # As a result, they are not defined in HACKSRC and their dependencies # are explicitly outlined here. # $(O)amidos.o: $(AMI)amidos.c $(HDEP) $(O)amirip.o: $(AMI)amirip.c $(HDEP) $(O)aglue.o: $(AMI)aglue.a $(ASM) $(AFLAGS) $(AOBJSPEC)$(O)aglue.o $(AMI)aglue.a $(O)amisnd.o: $(AMI)amisnd.c $(HDEP) $(O)winchar.o: $(AMI)winchar.c $(NHS)tile.c $(HDEP) $(NHS)tile.c: $(WSHARE)tilemap.c #SFD_INSTEAD $(CCLINK) $(CLFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c $(CCLINK) $(CFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c $(SBIN)tilemap $(O)winstr.o: $(AMI)winstr.c $(HDEP) $(AMDEP) $(O)winreq.o: $(AMI)winreq.c $(HDEP) $(AMDEP) $(AMI)colorwin.c $(AMI)clipwin.c $(O)winfuncs.o: $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h $(O)winkey.o: $(AMI)winkey.c $(HDEP) $(AMDEP) $(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP) $(O)winami.o: $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c #$(O)amilib.o: $(AMI)amilib.c $(HDEP) $(AMDEP) $(O)amiwind.o: $(AMI)amiwind.c $(AMI)amimenu.c $(HDEP) $(AMDEP) $(O)amiwbench.o: $(AMI)amiwbench.c $(HDEP) $(O)random.o: $(SHARE)random.c $(O)pcmain.o: $(SHARE)pcmain.c $(HDEP) $(I)dlb.h $(O)dispmap.o: $(AMI)dispmap.s $(ASM) $(AFLAGS) $(AOBJSPEC)$@ $< # Stuff to build the front ends $(NETHACK)HackWB: $(OO)wb.o $(OO)wbx.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackWB $(LIN) $(OO)wb.o $(OO)wbx.o \ $(OO)loader.o $(OO)multi.o $(LLIB) $(NETHACK)HackCli: $(OO)cli.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackCli $(LIN) $(OO)cli.o $(OO)loader.o \ $(OO)multi.o $(LLIB) # This needs to exist to eliminate the HackWB startup message #SFD_INSTEAD $(NETHACK)WBDefaults.def: $(NETHACK)WBDefaults.def $(NETHACK)WBDefaults.def: echo to $(NETHACK)WBDefaults.def WBH = $(AMI)wbdefs.h $(AMI)wbstruct.h $(AMI)wbprotos.h ASP = $(AMI)splitter $(OO)wb.o: $(WBH) $(AMI)wb.c $(AMI)wbwin.c $(AMI)wbdata.c $(AMI)wbgads.c \ $(I)patchlevel.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wb.o $(AMI)wb.c $(OO)wbx.o: $(WBH) $(AMI)wbcli.c $(AMI)wbwin.c $(AMI)wbdata.c \ $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wbx.o $(AMI)wbcli.c $(OO)loader.o: $(ASP)/loader.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)loader.o $(ASP)/loader.c $(OO)multi.o: $(ASP)/multi.c $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)multi.o $(ASP)/multi.c $(OO)cli.o: $(WBH) $(AMI)wbcli.c $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(WBC2FLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)cli.o \ $(AMI)wbcli.c #### # splitter support $(SBIN)splitter: $(OO)splitter.o $(OO)arg.o $(LINK) $(LNSPEC) $(SBIN)splitter $(LIN) $(OO)splitter.o $(OO)arg.o \ $(LLIB) $(NETHACK)NetHack.dir: $(SBIN)splitter $(SBIN)NetHack $(SBIN)splitter $(SBIN)NetHack $(OO)splitter.o: $(ASP)/splitter.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)splitter.o \ $(ASP)/splitter.c $(OO)arg.o: $(ASP)/arg.c $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)arg.o $(ASP)/arg.c # Create/copy other stuff into NetHack: directory: $(NETHACK)tomb.iff: $(SBIN)xpm2iff $(AMI)grave16.xpm $(SBIN)xpm2iff $(AMI)grave16.xpm $(NETHACK)tomb.iff $(OO)xpm2iff.o: $(AMI)xpm2iff.c $(CC) $(CFLAGS) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(AMI)xpm2iff.c $(SBIN)xpm2iff: $(OO)xpm2iff.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)xpm2iff.o $(FLLIB) # Tile installation for the tile version of the game inst-tiles: $(TILEFILES) #SFD_INSTEAD $(NETHACK)tiles: $(NETHACK)tiles $(NETHACK)tiles: -makedir $(NETHACK)tiles $(OO)txt2iff.o: $(AMI)txt2iff.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ \ $(AMI)txt2iff.c $(OO)ppmwrite.o: $(WSHARE)ppmwrite.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)ppmwrite.c $(OO)tiletext.o: $(WSHARE)tiletext.c $(I)config.h $(WSHARE)tile.h $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tiletext.c $(OO)tiletxt.o: $(WSHARE)tilemap.c $(I)hack.h $(CC) $(CFLAGS) $(CSYM) $(DEFSPEC)TILETEXT $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tilemap.c NAMEOBJS = $(O)drawing.o $(O)decl.o $(O)monst.o $(O)objects.o $(SBIN)txt2ppm: $(OO)ppmwrite.o $(NAMEOBJS) $(O)alloc.o $(OO)panic.o $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)ppmwrite.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(O)alloc.o $(OO)panic.o $(FLLIB) $(SBIN)txt2iff: $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o \ $(OO)tiletxt.o $(FLLIB) $(NETHACK)tiles/objects.iff: $(WSHARE)objects.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)objects.txt $(NETHACK)tiles/objects.iff $(NETHACK)tiles/monsters.iff: $(WSHARE)monsters.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)monsters.txt $(NETHACK)tiles/monsters.iff $(NETHACK)tiles/other.iff: $(WSHARE)other.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)other.txt $(NETHACK)tiles/other.iff # Sound installation rules. inst-sounds: $(SOUNDFILES) list to T:nhsdat.lst $(SLIB)sounds QUICK NOHEAD echo >T:make-nhsdat $(SBIN)dlb cCfI $(SLIB)sounds $(NETHACK)nhsdat T:nhsdat.lst echo >>T:make-nhsdat if not exists $(NETHACK)nhsdat echo >>T:make-nhsdat copy $(SLIB)sounds/\#? $(NETHACK)sounds echo >>T:make-nhsdat endif execute T:make-nhsdat -delete T:make-nhsdat #SFD_INSTEAD $(SLIB)sounds: $(SLIB)sounds $(SLIB)sounds: -makedir $(SLIB)sounds $(SBIN)cvtsnd: $(OO)cvtsnd.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)cvtsnd.o $(FLLIB) $(OO)cvtsnd.o: $(AMI)cvtsnd.c #SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) %(right) #none $(SLIB)sounds/Bell: $(SHARE)sounds/bell.uu $(UUDEC) $(SHARE)sounds/bell.uu $(SBIN)cvtsnd Bell $(SLIB)sounds/Bell -delete Bell $(SLIB)sounds/Bugle: $(SHARE)sounds/bugle.uu $(UUDEC) $(SHARE)sounds/bugle.uu $(SBIN)cvtsnd Bugle $(SLIB)sounds/Bugle -delete Bugle $(SLIB)sounds/Drum_Of_Earthquake: $(SHARE)sounds/erthdrum.uu $(UUDEC) $(SHARE)sounds/erthdrum.uu $(SBIN)cvtsnd Drum_Of_Earthquake $(SLIB)sounds/Drum_Of_Earthquake -delete Drum_Of_Earthquake $(SLIB)sounds/Fire_Horn: $(SHARE)sounds/firehorn.uu $(UUDEC) $(SHARE)sounds/firehorn.uu $(SBIN)cvtsnd Fire_Horn $(SLIB)sounds/Fire_Horn -delete Fire_Horn $(SLIB)sounds/Frost_Horn: $(SHARE)sounds/frsthorn.uu $(UUDEC) $(SHARE)sounds/frsthorn.uu $(SBIN)cvtsnd Frost_Horn $(SLIB)sounds/Frost_Horn -delete Frost_Horn $(SLIB)sounds/Leather_Drum: $(SHARE)sounds/lethdrum.uu $(UUDEC) $(SHARE)sounds/lethdrum.uu $(SBIN)cvtsnd Leather_Drum $(SLIB)sounds/Leather_Drum -delete Leather_Drum $(SLIB)sounds/Magic_Flute: $(SHARE)sounds/mgcflute.uu $(UUDEC) $(SHARE)sounds/mgcflute.uu $(SBIN)cvtsnd Magic_Flute $(SLIB)sounds/Magic_Flute -delete Magic_Flute $(SLIB)sounds/Magic_Harp: $(SHARE)sounds/mgcharp.uu $(UUDEC) $(SHARE)sounds/mgcharp.uu $(SBIN)cvtsnd Magic_Harp $(SLIB)sounds/Magic_Harp -delete Magic_Harp $(SLIB)sounds/Tooled_Horn: $(SHARE)sounds/toolhorn.uu $(UUDEC) $(SHARE)sounds/toolhorn.uu $(SBIN)cvtsnd Tooled_Horn $(SLIB)sounds/Tooled_Horn -delete Tooled_Horn $(SLIB)sounds/Wooden_Flute: $(SHARE)sounds/wdnflute.uu $(UUDEC) $(SHARE)sounds/wdnflute.uu $(SBIN)cvtsnd Wooden_Flute $(SLIB)sounds/Wooden_Flute -delete Wooden_Flute $(SLIB)sounds/Wooden_Harp: $(SHARE)sounds/wdnharp.uu $(UUDEC) $(SHARE)sounds/wdnharp.uu $(SBIN)cvtsnd Wooden_Harp $(SLIB)sounds/Wooden_Harp -delete Wooden_Harp inst-dungeon: $(INSTDUNGEONFILES) $(NETHACK)options : $(DAT)options copy $(DAT)options $@ # Create compiled dungeon files BGM= $(SLIB)bigrm-2.lev $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev $(BGM): $(SLIB)bigrm-1.lev $(SLIB)bigrm-1.lev: $(DAT)bigroom.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)bigroom.des #none $(SLIB)castle.lev: $(DAT)castle.des $(SBIN)lev_comp ENDGAME1= $(SLIB)air.lev $(SLIB)earth.lev $(SLIB)fire.lev $(SLIB)water.lev $(ENDGAME1): $(SLIB)astral.lev $(SLIB)astral.lev: $(DAT)endgame.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)endgame.des #none GEHENNOM1= $(SLIB)asmodeus.lev $(SLIB)baalz.lev $(SLIB)juiblex.lev \ $(SLIB)orcus.lev $(SLIB)sanctum.lev $(GEHENNOM1): $(SLIB)valley.lev $(SLIB)valley.lev: $(DAT)gehennom.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)gehennom.des #none $(SLIB)knox.lev: $(DAT)knox.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)knox.des #none MINES1= $(SLIB)minend-1.lev $(SLIB)minend-2.lev $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(MINES1): $(SLIB)minefill.lev $(SLIB)minefill.lev: $(DAT)mines.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)mines.des #none $(SLIB)oracle.lev: $(DAT)oracle.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)oracle.des #none TOWER1= $(SLIB)tower1.lev $(SLIB)tower2.lev $(TOWER1): $(SLIB)tower3.lev $(SLIB)tower3.lev: $(DAT)tower.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)tower.des #none WIZARD1= $(SLIB)wizard1.lev $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(SLIB)fakewiz1.lev $(WIZARD1): $(SLIB)fakewiz2.lev $(SLIB)fakewiz2.lev: $(DAT)yendor.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)yendor.des #none MEDUSA1= $(SLIB)medusa-1.lev $(MEDUSA1): $(SLIB)medusa-2.lev $(SLIB)medusa-2.lev: $(DAT)medusa.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)medusa.des #none SOKOBAN1= $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev \ $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev \ $(SLIB)soko4-1.lev $(SOKOBAN1): $(SLIB)soko4-2.lev $(SLIB)soko4-2.lev: $(DAT)sokoban.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)sokoban.des #none $(ADFILES1): $(SLIB)Arc-goal.lev $(SLIB)Arc-goal.lev: $(DAT)Arch.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Arch.des #none $(BDFILES1): $(SLIB)Bar-goal.lev $(SLIB)Bar-goal.lev: $(DAT)Barb.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Barb.des #none $(CDFILES1): $(SLIB)Cav-goal.lev $(SLIB)Cav-goal.lev: $(DAT)Caveman.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Caveman.des #none $(HDFILES1): $(SLIB)Hea-goal.lev $(SLIB)Hea-goal.lev: $(DAT)Healer.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Healer.des #none $(KDFILES1): $(SLIB)Kni-goal.lev $(SLIB)Kni-goal.lev: $(DAT)Knight.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Knight.des #none $(MDFILES1): $(SLIB)Mon-goal.lev $(SLIB)Mon-goal.lev: $(DAT)Monk.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Monk.des #none $(PDFILES1): $(SLIB)Pri-goal.lev $(SLIB)Pri-goal.lev: $(DAT)Priest.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Priest.des #none $(RDFILES1): $(SLIB)Rog-goal.lev $(SLIB)Rog-goal.lev: $(DAT)Rogue.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Rogue.des #none $(RANFILES1): $(SLIB)Ran-goal.lev $(SLIB)Ran-goal.lev: $(DAT)Ranger.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Ranger.des #none $(SDFILES1): $(SLIB)Sam-goal.lev $(SLIB)Sam-goal.lev: $(DAT)Samurai.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Samurai.des #none $(TDFILES1): $(SLIB)Tou-goal.lev $(SLIB)Tou-goal.lev: $(DAT)Tourist.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Tourist.des #none $(VDFILES1): $(SLIB)Val-goal.lev $(SLIB)Val-goal.lev: $(DAT)Valkyrie.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Valkyrie.des #none $(WDFILES1): $(SLIB)Wiz-goal.lev $(SLIB)Wiz-goal.lev: $(DAT)Wizard.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Wizard.des #none $(SLIB)dungeon: $(DAT)dungeon.def $(SBIN)makedefs $(SBIN)dgn_comp $(SBIN)makedefs -e $(SBIN)dgn_comp $(DAT)dungeon.pdf copy $(DAT)dungeon $(SLIB)dungeon delete $(DAT)dungeon inst-data: $(INSTDATAFILES) $(NETHACK)amii.hlp: $(AMI)amii.hlp copy $(AMI)amii.hlp $@ #$(NETHACK)data: $(DAT)data # copy $(DAT)data $@ $(SLIB)data: $(DAT)data.base $(I)config.h $(SBIN)makedefs $(SBIN)makedefs -d #$(NETHACK)rumors: $(DAT)rumors # copy $(DAT)rumors $@ $(SLIB)rumors: $(DAT)rumors.tru $(DAT)rumors.fal $(SBIN)makedefs $(SBIN)makedefs -r $(SLIB)cmdhelp: $(DAT)cmdhelp copy $(DAT)cmdhelp $@ $(SLIB)help: $(DAT)help copy $(DAT)help $@ $(SLIB)hh: $(DAT)hh copy $(DAT)hh $@ $(NETHACK)HackWB.hlp: $(AMI)HackWB.hlp copy $(AMI)HackWB.hlp $@ $(SLIB)history: $(DAT)history copy $(DAT)history $@ $(NETHACK)license: $(DAT)license copy $(DAT)license $@ $(SLIB)opthelp: $(DAT)opthelp copy $(DAT)opthelp $@ $(NETHACK)Recover.txt: $(DOC)Recover.txt copy $(DOC)Recover.txt $@ $(NETHACK)GuideBook.txt: $(DOC)GuideBook.txt copy $(DOC)GuideBook.txt $@ $(NETHACK)NetHack.txt: $(DOC)NetHack.txt copy $(DOC)NetHack.txt $@ $(NETHACK)Install.ami: $(AMI)Install.ami copy $(AMI)Install.ami $@ #SFD_INSTEAD $(NETHACK)logfile: $(NETHACK)logfile $(NETHACK)logfile: echo to $@ #SFD_INSTEAD $(NETHACK)record: $(NETHACK)record $(NETHACK)record: echo to $@ $(SLIB)wizhelp: $(DAT)wizhelp copy $(DAT)wizhelp $@ # Create the directories here because NetHack.cnf puts them there by default $(NETHACK)NetHack.cnf: $(AMI)NetHack.cnf copy $(AMI)NetHack.cnf $@ -makedir $(NETHACK)save -makedir $(NETHACK)levels #SFD_BEGIN #SFD_ELSE $(O)NetHack.gst: $(GSTSRC) $(I)hack.h sc makegst=$(GSTFILE) $(CFLAGS) $(GSTSRC) #SFD_END # Unpack and install fonts INSTFONTFILES= $(NETHACK)hack.font $(NETHACK)hack $(NETHACK)hack/8 inst-fonts: $(INSTFONTFILES) $(NETHACK)hack/8: $(AMI)amifont8.uu $(NETHACK)hack $(UUDEC) $(AMI)amifont8.uu copy 8 $(NETHACK)hack/8 delete 8 $(NETHACK)hack.font: $(AMI)amifont.uu $(UUDEC) $(AMI)amifont.uu copy hack.font $(NETHACK)hack.font delete hack.font #SFD_INSTEAD $(NETHACK)hack: $(NETHACK)hack $(NETHACK)hack: -makedir $@ INSTICONFILES= \ $(NETHACK)default.icon $(NETHACK)NetHack.info $(NETHACK)NewGame.info \ $(NETHACK)HackWB.info inst-icons: $(INSTICONFILES) # Unpack the icons into place $(NETHACK)default.icon: $(AMI)dflticon.uu $(UUDEC) $(AMI)dflticon.uu # copy default.icon $(NETHACK)default.icon # delete default.icon $(NETHACK)NetHack.info: $(AMI)NHinfo.uu $(UUDEC) $(AMI)NHinfo.uu # copy NetHack.info $(NETHACK)NetHack.info # delete NetHack.info $(NETHACK)NewGame.info: $(AMI)NewGame.uu $(UUDEC) $(AMI)NewGame.uu # copy NewGame.info $(NETHACK)NewGame.info # delete NewGame.info $(NETHACK)HackWB.info: $(AMI)HackWB.uu $(UUDEC) $(AMI)HackWB.uu # copy HackWB.info $(NETHACK)HackWB.info # delete HackWB.info # If DLB is defined, create the nhdat library file in the playground # directory. If not, move all the data files there. $(NETHACK)nhdat: $(LIBFILES) $(SBIN)dlb list to T:nhdat.lst $(SLIB) QUICK NOHEAD FILES echo >T:make-nhdat $(SBIN)dlb cCfI $(SLIB) $(NETHACK)nhdat T:nhdat.lst echo >>T:make-nhdat if not exists $(NETHACK)nhdat echo >>T:make-nhdat copy $(SLIB)\#? $(NETHACK) echo >>T:make-nhdat endif execute T:make-nhdat -delete T:make-nhdat # DO NOT DELETE THIS LINE $(O)allmain.o: $(NHS)allmain.c $(HDEP) $(O)alloc.o: $(NHS)alloc.c $(I)config.h $(O)apply.o: $(NHS)apply.c $(HDEP) #SFD_INSTEAD #none $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)apply.c $(O)artifact.o: $(NHS)artifact.c $(HDEP) $(I)artifact.h $(I)artilist.h $(O)attrib.o: $(NHS)attrib.c $(HDEP) $(I)artifact.h $(O)ball.o: $(NHS)ball.c $(HDEP) $(O)bones.o: $(NHS)bones.c $(HDEP) $(I)lev.h $(O)botl.o: $(NHS)botl.c $(HDEP) $(O)cmd.o: $(NHS)cmd.c $(HDEP) $(I)func_tab.h $(O)dbridge.o: $(NHS)dbridge.c $(HDEP) $(O)decl.o: $(NHS)decl.c $(HDEP) $(I)quest.h $(O)detect.o: $(NHS)detect.c $(HDEP) $(I)artifact.h $(O)dig.o: $(NHS)dig.c $(HDEP) $(O)display.o: $(NHS)display.c $(HDEP) $(O)dlb.o: $(NHS)dlb.c $(HDEP) $(I)dlb.h $(O)do.o: $(NHS)do.c $(HDEP) $(I)lev.h $(O)do_name.o: $(NHS)do_name.c $(HDEP) $(O)do_wear.o: $(NHS)do_wear.c $(HDEP) $(O)dog.o: $(NHS)dog.c $(HDEP) $(O)dogmove.o: $(NHS)dogmove.c $(HDEP) $(I)mfndpos.h $(O)dokick.o: $(NHS)dokick.c $(HDEP) $(O)dothrow.o: $(NHS)dothrow.c $(HDEP) $(O)drawing.o: $(NHS)drawing.c $(HDEP) $(I)tcap.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)drawing.c $(O)dungeon.o: $(NHS)dungeon.c $(HDEP) $(I)dgn_file.h $(I)dlb.h $(O)eat.o: $(NHS)eat.c $(HDEP) $(O)end.o: $(NHS)end.c $(HDEP) $(I)lev.h $(I)dlb.h $(O)engrave.o: $(NHS)engrave.c $(HDEP) $(I)lev.h $(O)exper.o: $(NHS)exper.c $(HDEP) $(O)explode.o: $(NHS)explode.c $(HDEP) $(O)extralev.o: $(NHS)extralev.c $(HDEP) $(O)files.o: $(NHS)files.c $(HDEP) $(I)dlb.h $(I)date.h $(O)fountain.o: $(NHS)fountain.c $(HDEP) $(O)hack.o: $(NHS)hack.c $(HDEP) $(O)hacklib.o: $(NHS)hacklib.c $(HDEP) $(O)invent.o: $(NHS)invent.c $(HDEP) $(I)artifact.h $(O)light.o: $(NHS)light.c $(HDEP) $(I)lev.h $(O)lock.o: $(NHS)lock.c $(HDEP) $(O)mail.o: $(NHS)mail.c $(HDEP) $(I)mail.h $(O)makemon.o: $(NHS)makemon.c $(HDEP) $(O)mapglyph.o: $(NHS)mapglyph.c $(HDEP) $(O)mcastu.o: $(NHS)mcastu.c $(HDEP) $(O)mhitm.o: $(NHS)mhitm.c $(HDEP) $(I)artifact.h $(O)mhitu.o: $(NHS)mhitu.c $(HDEP) $(I)artifact.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)mhitu.c $(O)minion.o: $(NHS)minion.c $(HDEP) $(O)mklev.o: $(NHS)mklev.c $(HDEP) $(O)mkmap.o: $(NHS)mkmap.c $(HDEP) $(I)sp_lev.h $(O)mkmaze.o: $(NHS)mkmaze.c $(HDEP) $(I)sp_lev.h $(I)lev.h $(O)mkobj.o: $(NHS)mkobj.c $(HDEP) $(I)artifact.h $(I)prop.h $(O)mkroom.o: $(NHS)mkroom.c $(HDEP) $(O)mon.o: $(NHS)mon.c $(HDEP) $(I)mfndpos.h $(O)mondata.o: $(NHS)mondata.c $(HDEP) $(O)monmove.o: $(NHS)monmove.c $(HDEP) $(I)mfndpos.h $(I)artifact.h $(O)monst.o: $(NHS)monst.c $(I)config.h $(I)permonst.h $(I)monsym.h $(I)color.h $(O)monstr.o: $(NHS)monstr.c $(HDEP) #SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) $(NHS)monstr.c #none $(O)mplayer.o: $(NHS)mplayer.c $(HDEP) $(O)mthrowu.o: $(NHS)mthrowu.c $(HDEP) $(O)muse.o: $(NHS)muse.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)muse.c $(O)music.o: $(NHS)music.c $(HDEP) #interp.c $(O)o_init.o: $(NHS)o_init.c $(HDEP) $(I)lev.h $(O)objects.o: $(NHS)objects.c $(I)config.h $(I)obj.h $(I)objclass.h \ $(I)prop.h $(I)skills.h $(I)color.h #SFD_INSTEAD #none $(CC) $(CFLAGS) $(INCLSPEC)$(NHS) $(OBJSPEC)$@ $(NHS)objects.c $(O)objnam.o: $(NHS)objnam.c $(HDEP) $(O)options.o: $(NHS)options.c $(HDEP) $(I)tcap.h $(I)config.h \ $(I)objclass.h $(I)flag.h $(O)pager.o: $(NHS)pager.c $(HDEP) $(I)dlb.h $(O)pickup.o: $(NHS)pickup.c $(HDEP) $(O)pline.o: $(NHS)pline.c $(HDEP) $(O)polyself.o: $(NHS)polyself.c $(HDEP) $(O)potion.o: $(NHS)potion.c $(HDEP) $(O)pray.o: $(NHS)pray.c $(HDEP) $(O)priest.o: $(NHS)priest.c $(HDEP) $(I)mfndpos.h $(O)quest.o: $(NHS)quest.c $(HDEP) $(I)quest.h $(I)qtext.h $(O)questpgr.o: $(NHS)questpgr.c $(HDEP) $(I)qtext.h $(I)dlb.h $(O)read.o: $(NHS)read.c $(HDEP) $(O)rect.o: $(NHS)rect.c $(HDEP) $(O)region.o: $(NHS)region.c $(HDEP) $(O)restore.o: $(NHS)restore.c $(HDEP) $(I)lev.h $(I)tcap.h $(I)quest.h $(O)rnd.o: $(NHS)rnd.c $(HDEP) $(O)role.o: $(NHS)role.c $(HDEP) $(O)rumors.o: $(NHS)rumors.c $(HDEP) $(I)dlb.h $(O)save.o: $(NHS)save.c $(HDEP) $(I)lev.h $(I)quest.h $(O)shk.o: $(NHS)shk.c $(HDEP) #SFD_INSTEAD #none $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)shk.c $(O)shknam.o: $(NHS)shknam.c $(HDEP) $(O)sit.o: $(NHS)sit.c $(HDEP) $(I)artifact.h $(O)sounds.o: $(NHS)sounds.c $(HDEP) $(O)sp_lev.o: $(NHS)sp_lev.c $(HDEP) $(I)sp_lev.h $(I)rect.h $(I)dlb.h $(O)spell.o: $(NHS)spell.c $(HDEP) $(O)steal.o: $(NHS)steal.c $(HDEP) $(O)steed.o: $(NHS)steed.c $(HDEP) $(O)sys.o: $(NHS)sys.c $(HDEP) $(O)teleport.o: $(NHS)teleport.c $(HDEP) $(O)timeout.o: $(NHS)timeout.c $(HDEP) $(I)lev.h $(O)topten.o: $(NHS)topten.c $(HDEP) $(I)dlb.h $(O)track.o: $(NHS)track.c $(HDEP) $(O)trap.o: $(NHS)trap.c $(HDEP) #SFD_INSTEAD #none $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)trap.c $(O)u_init.o: $(NHS)u_init.c $(HDEP) $(O)uhitm.o: $(NHS)uhitm.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)uhitm.c $(O)vault.o: $(NHS)vault.c $(HDEP) $(O)version.o: $(NHS)version.c $(HDEP) $(I)date.h $(I)patchlevel.h # DMake doesn't grok mid-line comments #SFD_INSTEAD $(O)vision.o: $(NHS)vision.c $(HDEP) $(O)vision.o: $(NHS)vision.c $(HDEP) #$(I)vis_tab.h $(O)weapon.o: $(NHS)weapon.c $(HDEP) $(O)were.o: $(NHS)were.c $(HDEP) $(O)wield.o: $(NHS)wield.c $(HDEP) $(O)windows.o: $(NHS)windows.c $(HDEP) $(I)wintty.h $(O)wizard.o: $(NHS)wizard.c $(HDEP) $(I)qtext.h $(O)worm.o: $(NHS)worm.c $(HDEP) $(I)lev.h $(O)worn.o: $(NHS)worn.c $(HDEP) $(O)write.o: $(NHS)write.c $(HDEP) $(O)zap.o: $(NHS)zap.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)zap.c $(O)getline.o: $(TTY)getline.c $(HDEP) $(I)wintty.h $(O)termcap.o: $(TTY)termcap.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)topl.o: $(TTY)topl.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)wintty.o: $(TTY)wintty.c $(HDEP) $(I)wintty.h $(I)tcap.h \ $(I)date.h $(I)patchlevel.h $(O)amitty.o: $(AMI)amitty.c $(HDEP) $(O)amistack.o: $(AMI)amistack.c $(CC) $(CFLAGS3) $(CSYM) $(OBJSPEC)$@ $(AMI)amistack.c $(O)rip.o: $(NHS)rip.c $(HDEP) $(I)config.h: $(I)config1.h $(I)tradstdc.h $(I)global.h -setdate $(I)config.h -wait 2 # onames.h handled at onames.h target, pm.h $(I)decl.h: $(I)quest.h $(I)spell.h $(I)color.h $(I)obj.h $(I)you.h -setdate $(I)decl.h -wait 2 $(I)global.h: $(I)coord.h $(I)pcconf.h $(I)amiconf.h -setdate $(I)global.h -wait 2 $(I)hack.h: $(I)config.h $(I)context.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h $(I)display.h $(I)wintype.h $(I)engrave.h $(I)rect.h $(I)region.h $(I)trampoli.h $(I)sys.h -setdate $(I)hack.h -wait 2 $(I)permonst.h: $(I)monattk.h $(I)monflag.h $(I)align.h -setdate $(I)permonst.h -wait 2 $(I)you.h: $(I)align.h $(I)attrib.h $(I)monst.h $(I)mextra.h $(I)youprop.h $(I)skills.h -setdate $(I)you.h -wait 2 # pm.h handled at target $(I)youprop.h: $(I)prop.h $(I)permonst.h $(I)mondata.h -setdate $(I)youprop.h -wait 2 $(I)display.h: $(I)vision.h $(I)mondata.h -setdate $(I)display.h -wait 2 $(I)dungeon.h: $(I)align.h -setdate $(I)dungeon.h -wait 2 $(I)engrave.h: $(I)trampoli.h $(I)rect.h -setdate $(I)engrave.h -wait 2 $(I)mextra.h: $(I)align.h -setdate $(I)mextra.h -wait 2 $(I)mondata.h: $(I)align.h -setdate $(I)mondata.h -wait 2 $(I)monst.h: $(I)align.h $(I)mextra.h -setdate $(I)monst.h -wait 2 $(I)pcconf.h: $(I)micro.h $(I)system.h -setdate $(I)pcconf.h -wait 2 $(I)rm.h: $(I)align.h -setdate $(I)rm.h -wait 2 #notes # install keeps doing re-install because it keeps rebuilding lev_comp??? # fixed(?) - deleted setdate # make nhdat rebuils sys/amiga objects nethack-3.6.0/sys/amiga/NetHack.cnf0000664000076400007660000001467212467321052016052 0ustar paxedpaxed# A '#' at the beginning of a line means the rest of the line is a comment. # This is an example configuration file. # If several people are to use it, don't specify "name" or personal # prefences like "dogname" or "packorder" in OPTIONS. # To change configuration, comment out the unwanted configurations, and # remove the comment from the configuration you want. # Some options to set personal preferences. If several people are to # use it, options like these should not be set here - use the command line #OPTIONS=name:Janet-V,female,dogname:Fido,fruit:apricot #OPTIONS=packorder:")[%?+/=!(*0_`,scores:10t/2a,noverbose #OPTIONS=gender:male #OPTIONS=role:random #OPTIONS=race:random #OPTIONS=align:chaotic # Other general options #OPTIONS=time,rest_on_space,noautopickup # The search path for files like record, help, opthelp, etc. PATH=NetHack: # My own setup #OPTIONS=nolegacy,fruit:lemon,time,autopickup,checkpoint,showexp,showscore,standout,nonews #OPTIONS=nomail,flush,eight_bit_tty,scores:10t/2a,pickup_types:$,suppress_alert:3.3.0,autoquiver # The windowtype option must be set before any options regarding colors and palette # are set otherwise previously set values will be overridden by the defaults # # The font version of the game OPTIONS=windowtype:amii # # New tile version of the game #OPTIONS=windowtype:amitile # # A hard disk configuration. # HACKDIR=NetHack: LEVELS=Nethack:Levels SAVE=Nethack:Save BONESDIR=Nethack:Levels SCOREDIR=Nethack: LOCKDIR=Nethack: CONFIGDIR=Nethack: DATADIR=Nethack: TROUBLEDIR=Nethack: # *** CHARACTER GRAPHICS *** # # See the on-line help or the Guidebook for which symbols are in which # positions. # # Note that the hack.font has special graphics characters from 192 on. # An example using the hack.font graphics character set: DUNGEON = 032 192 193 194 195 196 197 198 216 214 \ 215 213 217 145 146 147 148 035 035 217 \ 218 229 060 062 060 062 095 124 092 035 \ 123 125 042 125 042 042 035 035 046 035 \ 125 TRAPS = 094 094 094 094 094 094 094 094 094 094 \ 094 094 094 094 094 094 094 034 094 094 \ 094 094 EFFECTS = 241 240 242 243 042 033 123 125 \ 064 038 042 035 \ 244 245 246 247 239 248 249 250 \ 230 234 231 236 212 237 232 235 233 WARNINGS = 048 049 050 051 052 053 # Monitors vary greatly in their color response. If the default colors # are not good on your monitor, here are some other alternatives for the # font version of the game: # # Last color of the palette is always used for the cursor. # #CBM 1960, set color/contrast for good pure red, green, and blue. True colors. #PENS=000,fff,a61,7bb,0f0,e0c,00f,f00 #CBM 1960, set color/contrast as above, better colors for NetHack. #PENS=667,fff,da1,7bb,2f0,e0d,0af,f42 #and other suggestions: #PENS=888,ffc,840,0b8,4e4,e8b,7be,a04 #PENS=000,fff,830,7ae,181,c06,23e,c00 # # For an "interlaced"+ line screen, the default font is courier:13. If you want # a different font, set it here. The format is "fontname.font:size"; i.e. the # .font extension is required. #FONT=courier.font:13 #FONT=topaz.font:8 # # Proportional fonts such as CGTimes are probably not a good idea because they # result in many things not being spaced out correctly. #FONT=CGTimes.font:15 # # This sized proportional font is readable, but still has spacing problems #FONT=CGTimes.font:21 # # FOR AGA OR OTHER DISPLAYS CAPABLE OF 5 OR MORE PLANES... # # For a screen of depth 5 the following dripens provide a brown border # using pens 16-31. # # Pens 16-31 can be redefined with PENS= if you want different colors, # using the PENS= values below for a 4 plane screen as the first 16 colors. # #DEPTH=5 #DRIPENS=0,0,0,17,27,23,1,23,15,0,23,27 # # The APEN and BPEN values in the various types of windows can be set in # the manner shown below. These values are for the 16 color version of # the tile game. # # These values are specified as APEN,BPEN (foreground,background) # #MSGPENS=1,12 #STATUSPENS=1,12 #MENUPENS=1,23 #TEXTPENS=1,23 #OTHERPENS=1,23 # # FOR ECS OR OTHERS ONLY CAPABLE OF 4 PLANES... # # These values work good for the TILE version of the game on ECS machines # These are the default values for reference purposes. # #DEPTH=4 #defaults for tilemode: #PENS=000,fff,0bf,f60,00f,090,69b,f00,6f0,ff0,f0f,940,466,c40,ddb,fb9 #DRIPENS=0,1,0,2,4,12,14,12,7,1,12,4 #defaults for fontmode: #PENS=000,fff,830,7ac,181,c06,23e,c00 #DRIPENS=0,6,2,1,6,3,1,3,7,1,3,6 # # The APEN and BPEN values in the various types of windows can be set in # the manner shown below. These values are for a 32 color version of # the tile game. # # These values are specified as APEN,BPEN (foreground,background) # #MSGPENS=1,12 #STATUSPENS=1,12 #MENUPENS=0,14 #TEXTPENS=0,14 #OTHERPENS=1,12 # # New alternative color scheme for 16 color font mode. # This changes the colors of monsters, objects etc. # # FGPENS and BGPENS define APEN and BPEN for objects and monsters on the map. # The colors are in the following order: # black, red, green, brown, blue, magenta, cyan, gray, no color, orange, # bright green, yellow, bright blue, bright magenta, bright cyan, white # DEPTH=4 PENS=000,fff,830,7ac,181,c06,23e,c00,888,f60,4f4,ff0,4af,f8f,8ff,f00 FGPENS= 0, 7, 4, 2, 6, 5, 3, 8, 1, 9,10,11,12,13,14, 1 BGPENS= 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 # # Screen mode selections below should all work for either the font or tile # version of the game. Other modes can be tried and as long as they are at # least 640x200, the game should adapt to them... # # Select screenmode with a requester #SCREENMODE=Req # NTSC_MONITOR_ID #SCREENMODE=0x00019000 # PAL_MONITOR_ID #SCREENMODE=0x00029000 # NTSC_MONITOR_ID+LACE #SCREENMODE=0x00019004 # PAL_MONITOR_ID+LACE #SCREENMODE=0x00029004 # NTSC_MONITOR_ID+HIRES+LACE #SCREENMODE=0x00019024 # PAL_MONITOR_ID+HIRES+LACE #SCREENMODE=0x00029024 # VGA_MONITOR_ID #SCREENMODE=0x00031000 # VGAPRODUCT_KEY #SCREENMODE=0x00039024 # A2024TENHERTZ_KEY #SCREENMODE=0x00041000 # A2024FIFTEENHERTZ_KEY #SCREENMODE=0x00049000 # EURO72_MONITOR_ID #SCREENMODE=0x00061000 # EURO72PRODUCT_KEY #SCREENMODE=0x00069024 # EURO72PRODUCTLACE_KEY #SCREENMODE=0x00069025 # EURO72PRODUCTDBL_KEY #SCREENMODE=0x00069020 # EURO36_MONITOR_ID #SCREENMODE=0x00071000 # SUPER72HIRESDBL_KEY #SCREENMODE=0x00089008 # SUPER72SUPERDBL_KEY #SCREENMODE=0x00089028 # DBLNTSCHIRES_KEY #SCREENMODE=0x00099000 # DBLNTSCHIRESFF_KEY #SCREENMODE=0x00099004 # DBLNTSCHIRESLACE_KEY #SCREENMODE=0x00099005 # DBLPALHIRES_KEY #SCREENMODE=0x000a9000 # DBLPALHIRESFF_KEY #SCREENMODE=0x000a9004 # DBLPALHIRESLACE_KEY #SCREENMODE=0x000a9005 nethack-3.6.0/sys/amiga/amidos.c0000664000076400007660000002767612536476415015510 0ustar paxedpaxed/* NetHack 3.6 amidos.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Olaf Seibert, Nijmegen, The Netherlands, 1988,1990. */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ /* * An assortment of imitations of cheap plastic MSDOS and Unix functions. */ #include "hack.h" #include "winami.h" /* Defined in config.h, let's undefine it here (static function below) */ #undef strcmpi #include #include #include #undef COUNT #if defined(__SASC_60) || defined(__GNUC__) #include #include #endif #ifdef AZTEC_50 #include #undef strcmpi #endif /* Prototypes */ #include "NH:sys/amiga/winami.p" #include "NH:sys/amiga/amiwind.p" #include "NH:sys/amiga/amidos.p" extern char Initialized; extern struct window_procs amii_procs; #ifndef __SASC_60 int Enable_Abort = 0; /* for stdio package */ #endif /* Initial path, so we can find NetHack.cnf */ char PATH[PATHLEN] = "NetHack:"; static boolean record_exists(void); void flushout() { (void) fflush(stdout); } #ifndef getuid getuid() { return 1; } #endif #ifndef getlogin char * getlogin() { return ((char *) NULL); } #endif #ifndef AZTEC_50 int abs(x) int x; { return x < 0 ? -x : x; } #endif #ifdef SHELL int dosh() { int i; char buf[BUFSZ]; extern struct ExecBase *SysBase; /* Only under 2.0 and later ROMs do we have System() */ if (SysBase->LibNode.lib_Version >= 37 && !amibbs) { getlin("Enter CLI Command...", buf); if (buf[0] != '\033') i = System(buf, NULL); } else { i = 0; pline("No mysterious force prevented you from using multitasking."); } return i; } #endif /* SHELL */ #ifdef MFLOPPY #include #define Sprintf (void) sprintf #define EXTENSION 72 /* * This routine uses an approximation of the free bytes on a disk. * How large a file you can actually write depends on the number of * extension blocks you need for it. * In each extenstion block there are maximum 72 pointers to blocks, * so every 73 disk blocks have only 72 available for data. * The (necessary) file header is also good for 72 data block pointers. */ /* TODO: update this for FFS */ long freediskspace(path) char *path; { #ifdef UNTESTED /* these changes from Patric Mueller for AROS to * handle larger disks. Also needs limits.h and aros/oldprograms.h * for AROS. (keni) */ unsigned long long freeBytes = 0; #else register long freeBytes = 0; #endif register struct InfoData *infoData; /* Remember... longword aligned */ char fileName[32]; /* * Find a valid path on the device of which we want the free space. * If there is a colon in the name, it is an absolute path * and all up to the colon is everything we need. * Remember slashes in a volume name are allowed! * If there is no colon, it is relative to the current directory, * so must be on the current device, so "" is enough... */ { register char *colon; strncpy(fileName, path, sizeof(fileName) - 1); fileName[31] = 0; if (colon = index(fileName, ':')) colon[1] = '\0'; else fileName[0] = '\0'; } { BPTR fileLock; infoData = (struct InfoData *) alloc(sizeof(struct InfoData)); if (fileLock = Lock(fileName, SHARED_LOCK)) { if (Info(fileLock, infoData)) { /* We got a kind of DOS volume, since we can Lock it. */ /* Calculate number of blocks available for new file */ /* Kludge for the ever-full VOID: (oops RAM:) device */ if (infoData->id_UnitNumber == -1 && infoData->id_NumBlocks == infoData->id_NumBlocksUsed) { freeBytes = AvailMem(0L) - 64 * 1024L; /* Just a stupid guess at the */ /* Ram-Handler overhead per block: */ freeBytes -= freeBytes / 16; } else { /* Normal kind of DOS file system device/volume */ freeBytes = infoData->id_NumBlocks - infoData->id_NumBlocksUsed; freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1); freeBytes *= infoData->id_BytesPerBlock; #ifdef UNTESTED if (freeBytes > LONG_MAX) { freeBytes = LONG_MAX; } #endif } if (freeBytes < 0) freeBytes = 0; } UnLock(fileLock); } free(infoData); return freeBytes; } } long filesize(file) char *file; { register BPTR fileLock; register struct FileInfoBlock *fileInfoBlock; register long size = 0; fileInfoBlock = (struct FileInfoBlock *) alloc(sizeof(struct FileInfoBlock)); if (fileLock = Lock(file, SHARED_LOCK)) { if (Examine(fileLock, fileInfoBlock)) { size = fileInfoBlock->fib_Size; } UnLock(fileLock); } free(fileInfoBlock); return size; } #if 0 void eraseall(path, files) const char *path, *files; { BPTR dirLock, dirLock2; struct FileInfoBlock *fibp; int chklen; #ifdef BETA if(files != alllevels)panic("eraseall"); #endif chklen=(int)index(files,'*')-(int)files; if (dirLock = Lock( (char *)path ,SHARED_LOCK)) { dirLock2=DupLock(dirLock); dirLock2= CurrentDir(dirLock2); fibp=AllocMem(sizeof(struct FileInfoBlock),0); if(fibp){ if(Examine(dirLock,fibp)){ while(ExNext(dirLock,fibp)){ if(!strncmp(fibp->fib_FileName,files,chklen)){ DeleteFile(fibp->fib_FileName); } } } FreeMem(fibp,sizeof(struct FileInfoBlock)); } UnLock(dirLock); UnLock(CurrentDir(dirLock2)); } } #endif /* This size makes that most files can be copied with two Read()/Write()s */ #if 0 /* Unused */ #define COPYSIZE 4096 char *CopyFile(from, to) const char *from, *to; { register BPTR fromFile, toFile; register char *buffer; register long size; char *error = NULL; buffer = (char *) alloc(COPYSIZE); if (fromFile = Open( (char *)from, MODE_OLDFILE)) { if (toFile = Open( (char *)to, MODE_NEWFILE)) { while (size = Read(fromFile, buffer, (long)COPYSIZE)) { if (size == -1){ error = "Read error"; break; } if (size != Write(toFile, buffer, size)) { error = "Write error"; break; } } Close(toFile); } else error = "Cannot open destination"; Close(fromFile); } else error = "Cannot open source (this should not occur)"; free(buffer); return error; } #endif /* this should be replaced */ saveDiskPrompt(start) { char buf[BUFSIZ], *bp; BPTR fileLock; if (sysflags.asksavedisk) { /* Don't prompt if you can find the save file */ if (fileLock = Lock(SAVEF, SHARED_LOCK)) { UnLock(fileLock); #if defined(TTY_GRAPHICS) if (windowprocs.win_init_nhwindows != amii_procs.win_init_nhwindows) clear_nhwindow(WIN_MAP); #endif #if defined(AMII_GRAPHICS) if (windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) clear_nhwindow(WIN_BASE); #endif return 1; } pline("If save file is on a SAVE disk, put that disk in now."); if (strlen(SAVEF) > QBUFSZ - 25 - 22) panic("not enough buffer space for prompt"); /* THIS IS A HACK */ #if defined(TTY_GRAPHICS) if (windowprocs.win_init_nhwindows != amii_procs.win_init_nhwindows) { getlin("File name ?", buf); clear_nhwindow(WIN_MAP); } #endif #if defined(AMII_GRAPHICS) if (windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) { getlind("File name ?", buf, SAVEF); clear_nhwindow(WIN_BASE); } #endif clear_nhwindow(WIN_MESSAGE); if (!start && *buf == '\033') return 0; /* Strip any whitespace. Also, if nothing was entered except * whitespace, do not change the value of SAVEF. */ for (bp = buf; *bp; bp++) { if (!isspace(*bp)) { strncpy(SAVEF, bp, PATHLEN); break; } } } return 1; } /* Return 1 if the record file was found */ static boolean record_exists() { FILE *file; if (file = fopenp(RECORD, "r")) { fclose(file); return TRUE; } return FALSE; } #ifdef MFLOPPY /* * Under MSDOS: Prompt for game disk, then check for record file. * For Amiga: do nothing, but called from restore.c */ void gameDiskPrompt() { } #endif /* * Add a slash to any name not ending in / or :. There must * be room for the /. */ void append_slash(name) char *name; { char *ptr; if (!*name) return; ptr = eos(name) - 1; if (*ptr != '/' && *ptr != ':') { *++ptr = '/'; *++ptr = '\0'; } } void getreturn(str) const char *str; { int ch; raw_printf("Hit %s.", str); while ((ch = nhgetch()) != '\n' && ch != '\r') continue; } /* Follow the PATH, trying to fopen the file. */ #define PATHSEP ';' FILE * fopenp(name, mode) register const char *name, *mode; { register char *bp, *pp, lastch; register FILE *fp; register BPTR theLock; char buf[BUFSIZ]; /* Try the default directory first. Then look along PATH. */ if (strlen(name) >= BUFSIZ) return (NULL); strcpy(buf, name); if (theLock = Lock(buf, SHARED_LOCK)) { UnLock(theLock); if (fp = fopen(buf, mode)) return fp; } pp = PATH; while (pp && *pp) { bp = buf; while (*pp && *pp != PATHSEP) { if (bp > buf + BUFSIZ - 1) return (NULL); lastch = *bp++ = *pp++; } if (lastch != ':' && lastch != '/' && bp != buf) *bp++ = '/'; if (bp + strlen(name) > buf + BUFSIZ - 1) return (NULL); strcpy(bp, name); if (theLock = Lock(buf, SHARED_LOCK)) { UnLock(theLock); if (fp = fopen(buf, mode)) return fp; } if (*pp) pp++; } return NULL; } #endif /* MFLOPPY */ #ifdef CHDIR /* * A not general-purpose directory changing routine. * Assumes you want to return to the original directory eventually, * by chdir()ing to orgdir (which is defined in pcmain.c). * Assumes -1 is not a valid lock, since 0 is valid. */ #define NO_LOCK ((BPTR) -1) static BPTR OrgDirLock = NO_LOCK; chdir(dir) char *dir; { extern char orgdir[]; if (dir == orgdir) { /* We want to go back to where we came from. */ if (OrgDirLock != NO_LOCK) { UnLock(CurrentDir(OrgDirLock)); OrgDirLock = NO_LOCK; } } else { /* * Go to some new place. If still at the original * directory, save the FileLock. */ BPTR newDir; if (newDir = Lock((char *) dir, SHARED_LOCK)) { if (OrgDirLock == NO_LOCK) { OrgDirLock = CurrentDir(newDir); } else { UnLock(CurrentDir(newDir)); } } else { return -1; /* Failed */ } } /* CurrentDir always succeeds if you have a lock */ return 0; } #endif /* CHDIR */ /* Chdir back to original directory */ #undef exit void nethack_exit(code) { #ifdef CHDIR extern char orgdir[]; #endif #ifdef CHDIR chdir(orgdir); /* chdir, not chdirx */ #endif #ifdef AMII_GRAPHICS if (windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) CleanUp(); #endif exit(code); } void regularize(s) /* normalize file name - we don't like :'s or /'s */ register char *s; { register char *lp; while ((lp = index(s, ':')) || (lp = index(s, '/'))) *lp = '_'; } nethack-3.6.0/sys/amiga/amidos.p0000664000076400007660000000232312536476415015503 0ustar paxedpaxed/* NetHack 3.6 amidos.p $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* amidos.c */ void NDECL(flushout ); #ifndef getuid int NDECL(getuid ); #endif #ifndef getpid int NDECL(getpid ); #endif #ifndef getlogin char *NDECL(getlogin ); #endif #ifndef abs int FDECL(abs, (int )); #endif int NDECL(tgetch ); int NDECL(dosh ); long FDECL(freediskspace, (char *)); long FDECL(filesize, (char *)); void FDECL(eraseall, (const char * , const char *)); char *FDECL(CopyFile, (const char * , const char *)); void FDECL(copybones, (int )); void NDECL(playwoRAMdisk ); int FDECL(saveDiskPrompt, (int )); void NDECL(gameDiskPrompt ); void FDECL(append_slash, (char *)); void FDECL(getreturn, (const char *)); #ifndef msmsg void FDECL(msmsg, ( const char *, ... )); #endif #if !defined(__SASC_60) && !defined(_DCC) int FDECL(chdir, (char *)); #endif #ifndef strcmpi int FDECL(strcmpi, (char * , char *)); #endif #if !defined(memcmp) && !defined(AZTEC_C) && !defined(_DCC) && !defined(__GNUC__) int FDECL(memcmp, (unsigned char * , unsigned char * , int )); #endif nethack-3.6.0/sys/amiga/amifont.uu0000664000076400007660000000060612467321052016045 0ustar paxedpaxedbegin 777 hack.font M#P```6AA8VLO.``````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` G````````````````````````````````````````````````"`!` ` end nethack-3.6.0/sys/amiga/amifont8.uu0000664000076400007660000000664212467321052016143 0ustar paxedpaxedbegin 644 8 M```#\P`````````!``````````````)E```#Z0```F5P_TYU```````````, M`````!H/@``!``````````````````````````````````````````!&140` M```````````,`````!H`````"20`"`!```@`!@`!```@_P```&X`M```!@X` M```````````8;&P8`#@8##````````,\&#P\''X?G MYVH```!J:A@````8&!@``!@88L!6`%96```8`!@8`*@5P8.BP:@5YP/_[W_^ M````P,```P`\;&P^QFP8&!AF&`````9F.&9F/&`P9F9F&!@8`!AFQCQF9FQF M9F9F&`9F8,;F;&9L9F9:9L/&9L/&,&`,.``8`&``!@`V`&```&`8```````` M`!@````````8&!B<,Z6BH:&EI*2AI:6EI*2AI*3__\,8`&:DH:6EI:2DH:2D MI58```!65CP````8&!@``!@\96-J`&IJ```8`!@8UB/$`\`C+"O4A`/_]Y_Y M````P,```P`\`/Y@S&@P,`P\&`````QN&`8&;'Q@!F9F&!@P?@P&WCQFP&9@ M8,!F&`9L8.[VQF;&9G`89F;&/&:,,#`,;``,/&P\-CPP.VPX!F889GP\W#WL M/CYF9F-C9GX8&!@`S.7BY^?GY^?AY^?GY^3GY^?_`.<8`,/GX>?GY^?DY^?G MY6K_#_!KZCP````8&!@``!AF8#97_];7`&8<`#@\;&I6)F1I/&F6YP./]]_[ M#__PP,```P`8`&P\&'8`,`S_?@!^`!A^&!P,Y^&`9X8/[>QGS&?#@89F;6&#P8,!@,Q@``!G9F;F9X9G88!FP8=V9F9F9V M8!AF9FLV9DQP&`X`,Z6BI*&AH:6AI:&EI:2EI*3_`.<8_P`E(24A)24D)20D MI595/5Q55F;_#_`/\/\``-O#?AMJ5:JJ```?__C_JIPY:];X*]I;A`-F[\_S M.``,/\//C^ M\#YF?CSF_L;&./`\XSP\/AC&PSS^/`,\````.SP\.SQXQN8\9N8\8V8\8`;P M?`P[ C&'X.&'``S`````````````````````#__\,8`&8````````````` M`&H`:VH``,,`&!@``!B<&#P89F-6:E8``&88&!@`K`/`(\0L(T&"``/_W_F? MP``#P````````````````````#```````````````````#`````````````` M```````````````&`````````````````/X`````````?```/```````\`<` M````````<```````,P````````````````````#__\,8`&8````````````` M`%8`5E8`````&!@``!@``!@8`,!J5FH````8&!@``,&#J!7!HL&#``/_[_Y_ MP``#P`````````@`"``(`!``"``8``@`(``(`"@`"``P``@`.``(`$``"`!( M``@`4``(`%@`"`!@``@`:``(`'``"`!X``@`@``(`(@`"`"0``@`F``(`*`` M"`"H``@`L``(`+@`"`#```@`R``(`-``"`#8``@`X``(`.@`"`#P``@`^``( M`0``"`$(``@!$``(`1@`"`$@``@!*``(`3``"`$X``@!0``(`4@`"`%0``@! M6``(`6``"`%H``@!<``(`7@`"`&```@!B``(`9``"`&8``@!H``(`:@`"`&P M``@!N``(`<``"`'(``@!T``(`=@`"`'@``@!Z``(`?``"`'X``@"```(`@@` M"`(0``@"&``(`B``"`(H``@",``(`C@`"`)```@"2``(`E``"`)8``@"8``( M`F@`"`)P``@">``(`H``"`*(``@"D``(`I@`"`*@``@"J``(`K``"`*X``@" MP``(`L@`"`+0``@"V``(`N``"`+H``@"\``(`O@`"`,```@#"``(`Q``"`,8 M``@#(``(`R@`"`,P``@#.``(`T``"`-(``@#4``(`U@`"`-@``@#:``(`W`` M"`-X``@#@``(`X@`"`.0``@#F``(`Z``"`.H``@#L``(`[@`"`/```@#R``( M`]``"`/8``@#X``(`^@`"`/P``@#^``(!```"``(``@`$``(`!@`"``@``@` M*``(`#``"``X``@`0``(`$@`"`!0``@`6``(`&``"`!H``@`<``(`'@`"`"` M``@`B``(`)``"`"8``@`H``(`*@`"`"P``@`N``(`,``"`#(``@`T``(`-@` M"`#@``@`Z``(`/``"`#X``@$"``(!!``"`08``@$(``(!"@`"`0P``@#J``( M!#@`"`.8``@$0``(!$@`"`10``@$6``(!&``"`1H``@$<``(!'@`"`2```@$ MB``(!)``"`28``@$H``(!*@`"`2P``@$N``(!,``"`3(``@!V``(`>``"`'H M``@!\``(`?@`"`(```@$T``(!-@`"`3@``@$Z``(!/``"`3X``@%```(!0@` M"`40``@%&``(!2``"`4H``@%,``(!3@`"`5```@%2``(!5``"`58``@%8``( M!6@`"`5P``@%>``(!8``"`6(``@%D``(!9@`"`+8``@"X``(`N@`"`+P``@" M^``(````"``````#[`````0`````````#@```$0```!<````8@````````/R ` end nethack-3.6.0/sys/amiga/amigst.c0000664000076400007660000000204312536476415015475 0ustar paxedpaxed/* NetHack 3.6 amigst.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993 */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #include #include #include #include #include #include #include #include #undef strcmpi #include #include #ifdef __SASC #include /* for __emit */ #include #include #include #include #include #include #include #endif #include "hack.h" #include "winprocs.h" #include "winami.h" #ifdef AZTEC #include #endif #include "NH:sys/amiga/winami.p" #include "NH:sys/amiga/amiwind.p" #include "NH:sys/amiga/amidos.p" /* end amigst.c */ nethack-3.6.0/sys/amiga/amii.hlp0000664000076400007660000000244012536476415015472 0ustar paxedpaxed Amiga-specific help file for NetHack 3.6 The Amiga port of NetHack supports a number of additional commands and facilities specific to the Amiga. Listed below are the things which are either specific to the Amiga port or might not appear in other ports. While playing NetHack you can press: ALT-HELP Color requestor. CTL-HELP Scale display (amitile only). SHIFT-HELP Overview window (amitile only). Amiga-specific run-time options: altmeta use the alt keys as meta keys flush throw away keyboard type-ahead Command line options recognized are -n No News at game startup. -X Play in discovery mode. -D Play in debug mode. -L Interlaced screen. -l Never Interlaced screen. -u Play as player given as an argument. -r Pick a race given as an argument. -p Pick a profession given as an argument -? Gives command line usage. nethack-3.6.0/sys/amiga/amimenu.c0000664000076400007660000001334312536476415015651 0ustar paxedpaxed/* NetHack 3.6 amimenu.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Olaf 'Rhialto' Seibert, 1989 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993, 1996 */ /* Copyright (c) Janne Salmijrvi, 2000 */ /* NetHack may be freely redistributed. See license for details. */ /* Originally by John Toebes. */ /* GadTools menus by jhsa */ struct NewMenu GTHackMenu[] = { { NM_TITLE, "Commands", 0, 0, 0, 0 }, { NM_ITEM, "? Display help menu", 0, 0, 0, (void *) '?' }, { NM_ITEM, "& Explain a command", 0, 0, 0, (void *) '&' }, { NM_ITEM, "O Set options", 0, 0, 0, (void *) 'O' }, { NM_ITEM, "! AmigaDos command", 0, 0, 0, (void *) '!' }, { NM_ITEM, "v Version number", 0, 0, 0, (void *) 'v' }, { NM_ITEM, "V Long version and game history", 0, 0, 0, (void *) 'V' }, { NM_ITEM, "^R Redraw screen", 0, 0, 0, (void *) 022 }, { NM_ITEM, "^P Repeat previous messages", 0, 0, 0, (void *) 020 }, { NM_ITEM, "M-q #quit the game", 0, 0, 0, (void *)(128 + 'q') }, { NM_ITEM, "S Save the game", 0, 0, 0, (void *) 'S' }, { NM_TITLE, "Inventory", 0, 0, 0, 0 }, { NM_ITEM, "i Inventory", 0, 0, 0, (void *) 'i' }, { NM_ITEM, "p Pay your bill", 0, 0, 0, (void *) 'p' }, { NM_ITEM, "d Drop an object", 0, 0, 0, (void *) 'd' }, { NM_ITEM, "D Drop several things", 0, 0, 0, (void *) 'D' }, { NM_ITEM, ", Pickup an object", 0, 0, 0, (void *) ',' }, { NM_ITEM, "@ Toggle pickup", 0, 0, 0, (void *) '@' }, { NM_ITEM, "/ Identify something", 0, 0, 0, (void *) '/' }, { NM_ITEM, "C Christen a monster", 0, 0, 0, (void *) 'C' }, { NM_ITEM, "+ List known spells", 0, 0, 0, (void *) '+' }, { NM_ITEM, "$ Your gold", 0, 0, 0, (void *) '$' }, { NM_TITLE, "Actions", 0, 0, 0, 0 }, { NM_ITEM, "a Apply/use something", 0, 0, 0, (void *) 'a' }, { NM_ITEM, "e Eat something", 0, 0, 0, (void *) 'e' }, { NM_ITEM, "f Fire ammunition", 0, 0, 0, (void *) 'f' }, { NM_ITEM, "F Fight a monster", 0, 0, 0, (void *) 'F' }, { NM_ITEM, "q Quaff a monster", 0, 0, 0, (void *) 'q' }, { NM_ITEM, "r Read scroll/book", 0, 0, 0, (void *) 'r' }, { NM_ITEM, "t Throw something", 0, 0, 0, (void *) 't' }, { NM_ITEM, "z Zap a wand", 0, 0, 0, (void *) 'z' }, { NM_ITEM, "Z Cast a spell", 0, 0, 0, (void *) 'Z' }, { NM_TITLE, "Preparations", 0, 0, 0, 0 }, { NM_ITEM, "A Remove all armor", 0, 0, 0, (void *) 'A' }, { NM_ITEM, "P Put on a ring", 0, 0, 0, (void *) 'P' }, { NM_ITEM, "R Remove ring", 0, 0, 0, (void *) 'R' }, { NM_ITEM, "Q Select ammunition for quiver", 0, 0, 0, (void *) 'Q' }, { NM_ITEM, "T Take off armor", 0, 0, 0, (void *) 'T' }, { NM_ITEM, "w Wield a weapon", 0, 0, 0, (void *) 'w' }, { NM_ITEM, "W Wear armor", 0, 0, 0, (void *) 'W' }, { NM_ITEM, "x Swap wielded and secondary weapons", 0, 0, 0, (void *) 'x' }, { NM_ITEM, ") Current weapon", 0, 0, 0, (void *) ')' }, { NM_ITEM, "[ Current armor", 0, 0, 0, (void *) '[' }, { NM_ITEM, "= Current rings", 0, 0, 0, (void *) '=' }, { NM_ITEM, "\" Current amulet", 0, 0, 0, (void *) '"' }, { NM_ITEM, "( Current tools", 0, 0, 0, (void *) '(' }, { NM_ITEM, "* Current equipment", 0, 0, 0, (void *) '*' }, { NM_TITLE, "Movement", 0, 0, 0, 0 }, { NM_ITEM, "o Open door", 0, 0, 0, (void *) 'o' }, { NM_ITEM, "c Close door", 0, 0, 0, (void *) 'c' }, { NM_ITEM, "^D Kick door", 0, 0, 0, (void *) 004 }, { NM_ITEM, "s Search", 0, 0, 0, (void *) 's' }, { NM_ITEM, "< Go up stairs", 0, 0, 0, (void *) '<' }, { NM_ITEM, "> Go down stairs", 0, 0, 0, (void *) '>' }, { NM_ITEM, "^T Teleport", 0, 0, 0, (void *) 024 }, { NM_ITEM, ". Wait a moment", 0, 0, 0, (void *) '.' }, { NM_ITEM, "E Engrave message on floor", 0, 0, 0, (void *) 'E' }, { NM_TITLE, "Extended", 0, 0, 0, 0 }, { NM_ITEM, "M-a #adjust inventory letters", 0, 0, 0, (void *)(128 + 'a') }, { NM_ITEM, "M-c #chat with someone", 0, 0, 0, (void *)(128 + 'c') }, { NM_ITEM, "M-d #dip an object into something", 0, 0, 0, (void *)(128 + 'd') }, #ifdef WEAPON_SKILLS { NM_ITEM, "M-e #enhance weapon skills", 0, 0, 0, (void *)(128 + 'e') }, #endif { NM_ITEM, "M-f #force a lock", 0, 0, 0, (void *)(128 + 'f') }, { NM_ITEM, "M-i #invoke an object's special powers", 0, 0, 0, (void *)(128 + 'i') }, { NM_ITEM, "M-j #jump to another location", 0, 0, 0, (void *)(128 + 'j') }, { NM_ITEM, "M-l #loot a box on the floor", 0, 0, 0, (void *)(128 + 'l') }, { NM_ITEM, "M-m Use a #monster's special ability", 0, 0, 0, (void *)(128 + 'm') }, { NM_ITEM, "M-n #name an item or type of object", 0, 0, 0, (void *)(128 + 'n') }, { NM_ITEM, "M-o #offer a sacrifice to the gods", 0, 0, 0, (void *)(128 + 'o') }, { NM_ITEM, "M-p #pray to the gods for help", 0, 0, 0, (void *)(128 + 'p') }, { NM_ITEM, "M-q #quit the game", 0, 0, 0, (void *)(128 + 'q') }, { NM_ITEM, "M-r #rub a lamp", 0, 0, 0, (void *)(128 + 'r') }, { NM_ITEM, "M-s #sit down", 0, 0, 0, (void *)(128 + 's') }, { NM_ITEM, "M-t #turn undead", 0, 0, 0, (void *)(128 + 't') }, { NM_ITEM, "M-u #untrap something", 0, 0, 0, (void *)(128 + 'u') }, { NM_ITEM, "M-v Long #version information", 0, 0, 0, (void *)(128 + 'v') }, { NM_ITEM, "M-w #wipe off your face", 0, 0, 0, (void *)(128 + 'w') }, { NM_ITEM, " Your #conduct", 0, 0, 0, (void *) '#' }, /* "#co\n" */ { NM_ITEM, " #ride your steed", 0, 0, 0, (void *) '#' }, /* "#ri\n" */ { NM_ITEM, "M-2 Switch #twoweapon mode on/off", 0, 0, 0, (void *)(128 + '2') }, { NM_END, NULL, 0, 0, 0, 0 } }; nethack-3.6.0/sys/amiga/amirip.c0000664000076400007660000002225512563053246015472 0ustar paxedpaxed/* NetHack 3.6 amirip.c $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1991,1992,1993,1995,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "winami.h" #include "windefs.h" #include "winext.h" #include "winproto.h" static struct RastPort *rp; #ifdef AMII_GRAPHICS #undef NULL #define NULL 0 #ifdef AZTEC_C #include #else #ifdef _DCC #include #include #include #include #else #include #include #include #include #endif static char *load_list[] = { "tomb.iff", 0 }; static BitMapHeader tomb_bmhd; static struct BitMap *tbmp[1] = { 0 }; static int cols[2] = { 154, 319 }; /* X location of center of columns */ static int cno = 0; /* current column */ #define TEXT_TOP (65 + yoff) static xoff, yoff; /* image centering */ /* terrible kludge */ /* this is why prototypes should have ONLY types in them! */ #undef red #undef green #undef blue #undef index #ifdef _DCC #include #include #else #include #include #endif #endif /* AZTEC_C */ static struct Window *ripwin = 0; static void tomb_text(char *); static void dofade(int, int, int); static int search_cmap(int, int, int); #define STONE_LINE_LEN \ 13 /* # chars that fit on one line \ * (note 1 ' ' border) */ #define DEATH_LINE 10 #define YEAR_LINE 15 static unsigned short tomb_line; extern struct amii_DisplayDesc *amiIDisplay; extern struct Screen *HackScreen; extern int havelace; static unsigned short transpalette[AMII_MAXCOLORS] = { 0x0000, }; static struct NewWindow newwin = { 0, 0, 640, 200, 1, 0, MOUSEBUTTONS | VANILLAKEY | NOCAREREFRESH, BORDERLESS | ACTIVATE | SMART_REFRESH, NULL, NULL, (UBYTE *) NULL, NULL, NULL, -1, -1, 0xffff, 0xffff, CUSTOMSCREEN }; int wh; /* was local in outrip, but needed for SCALE macro */ int cmap_white, cmap_black; void amii_outrip(tmpwin, how, when) winid tmpwin; int how; time_t when; { int just_return = 0; int done, rtxth; struct IntuiMessage *imsg; int i; register char *dpx; char buf[200]; int line, tw, ww; char *errstr = NULL; long year; if (!WINVERS_AMIV || HackScreen->RastPort.BitMap->Depth < 4) goto cleanup; /* Use the users display size */ newwin.Height = amiIDisplay->ypix - newwin.TopEdge; newwin.Width = amiIDisplay->xpix; newwin.Screen = HackScreen; for (i = 0; i < amii_numcolors; ++i) sysflags.amii_curmap[i] = GetRGB4(HackScreen->ViewPort.ColorMap, i); ripwin = OpenWindow((void *) &newwin); if (!ripwin) goto cleanup; LoadRGB4(&HackScreen->ViewPort, transpalette, amii_numcolors); rp = ripwin->RPort; wh = ripwin->Height; ww = ripwin->Width; #ifdef HACKFONT if (HackFont) SetFont(rp, HackFont); #endif tomb_bmhd = ReadImageFiles(load_list, tbmp, &errstr); if (errstr) goto cleanup; if (tomb_bmhd.w > ww || tomb_bmhd.h > wh) goto cleanup; #define GENOFF(full, used) ((((full) - (used)) / 2) & ~7) xoff = GENOFF(ww, tomb_bmhd.w); yoff = GENOFF(wh, tomb_bmhd.h); for (i = 0; i < SIZE(cols); i++) cols[i] += xoff; cmap_white = search_cmap(0, 0, 0); cmap_black = search_cmap(15, 15, 15); BltBitMap(*tbmp, 0, 0, rp->BitMap, xoff, yoff, tomb_bmhd.w, tomb_bmhd.h, 0xc0, 0xff, NULL); /* Put together death description */ formatkiller(buf, sizeof buf, how); tw = TextLength(rp, buf, STONE_LINE_LEN) + 40; { char *p = buf; int x, tmp; for (x = STONE_LINE_LEN; x; x--) *p++ = 'W'; *p = '\0'; tmp = TextLength(rp, buf, STONE_LINE_LEN) + 40; tw = max(tw, tmp); } /* There are 5 lines of text on the stone. */ rtxth = ripwin->RPort->TxHeight * 5; SetAfPt(rp, (UWORD *) NULL, 0); SetDrPt(rp, 0xFFFF); tomb_line = TEXT_TOP; SetDrMd(rp, JAM1); /* Put name on stone */ Sprintf(buf, "%s", plname); buf[STONE_LINE_LEN] = 0; tomb_text(buf); /* Put $ on stone */ Sprintf(buf, "%ld Au", done_money); buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ tomb_text(buf); /* Put together death description */ formatkiller(buf, sizeof buf, how); /* Put death type on stone */ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { register int i, i0; char tmpchar; if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) { if (dpx[i] == ' ') i0 = i; } if (!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; tomb_text(dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx = &dpx[i0]; } else { dpx = &dpx[i0 + 1]; } } /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(buf, "%4ld", year); tomb_text(buf); #ifdef NH320_DEDICATION /* dedication */ cno = 1; tomb_line = TEXT_TOP; tomb_text("This release"); tomb_text("of NetHack"); tomb_text("is dedicated"); tomb_text("to the"); tomb_text("memory of"); tomb_text(""); tomb_text("Izchak"); tomb_text(" Miller"); tomb_text(""); tomb_text("1935-1994"); tomb_text(""); tomb_text("Ascended"); #endif /* Fade from black to full color */ dofade(0, 16, 1); /* Flush all messages to avoid typeahead */ while (imsg = (struct IntuiMessage *) GetMsg(ripwin->UserPort)) ReplyMsg((struct Message *) imsg); done = 0; while (!done) { WaitPort(ripwin->UserPort); while (imsg = (struct IntuiMessage *) GetMsg(ripwin->UserPort)) { switch (imsg->Class) { case MOUSEBUTTONS: case VANILLAKEY: done = 1; break; } ReplyMsg((struct Message *) imsg); } } /* Fade out */ dofade(16, 0, -1); just_return = 1; cleanup: /* free everything */ if (ripwin) { Forbid(); while (imsg = (struct IntuiMessage *) GetMsg(ripwin->UserPort)) ReplyMsg((struct Message *) imsg); CloseWindow(ripwin); Permit(); } LoadRGB4(&HackScreen->ViewPort, sysflags.amii_curmap, amii_numcolors); if (tbmp[0]) FreeImageFiles(load_list, tbmp); if (just_return) return; /* fall back to the straight-ASCII version */ genl_outrip(tmpwin, how, when); } static void tomb_text(p) char *p; { char buf[STONE_LINE_LEN * 2]; int l; tomb_line += rp->TxHeight; if (!*p) return; sprintf(buf, " %s ", p); l = TextLength(rp, buf, strlen(buf)); SetAPen(rp, cmap_white); Move(rp, cols[cno] - (l / 2) - 1, tomb_line); Text(rp, buf, strlen(buf)); SetAPen(rp, cmap_white); Move(rp, cols[cno] - (l / 2) + 1, tomb_line); Text(rp, buf, strlen(buf)); SetAPen(rp, cmap_white); Move(rp, cols[cno] - (l / 2), tomb_line - 1); Text(rp, buf, strlen(buf)); SetAPen(rp, cmap_white); Move(rp, cols[cno] - (l / 2), tomb_line + 1); Text(rp, buf, strlen(buf)); SetAPen(rp, cmap_black); Move(rp, cols[cno] - (l / 2), tomb_line); Text(rp, buf, strlen(buf)); } /* search colormap for best match to given color */ static int search_cmap(int r0, int g0, int b0) { int best = 0; int bdiff = 0x0fffffff; int x; for (x = 0; x < amii_numcolors; x++) { int r = r0 - ((amiv_init_map[x] >> 8) & 15); int g = g0 - ((amiv_init_map[x] >> 4) & 15); int b = b0 - ((amiv_init_map[x]) & 15); int diff = (r * r) + (g * g) + (b * b); if (diff < bdiff) { bdiff = diff; best = x; } } return best; } /* caution: this is NOT general! */ static void dofade(int start, int stop, int inc) { int i, j; for (i = start; (i * inc) <= stop; i += inc) { for (j = 0; j < amii_numcolors; ++j) { int r, g, b; r = (amiv_init_map[j] & 0xf00) >> 8; g = (amiv_init_map[j] & 0xf0) >> 4; b = (amiv_init_map[j] & 0xf); r = (r * i) / 16; g = (g * i) / 16; b = (b * i) / 16; transpalette[j] = ((r << 8) | (g << 4) | b); } LoadRGB4(&HackScreen->ViewPort, transpalette, amii_numcolors); Delay(1); } } #endif /* AMII_GRAPHICS */ /* TODO: memory leaks fix ReadImageFiles to return error instead of panic on error */ nethack-3.6.0/sys/amiga/amisnd.c0000664000076400007660000002077612536476415015501 0ustar paxedpaxed/* NetHack 3.6 amisnd.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) 1992, 1993, 1995 by Gregg Wonderly */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains music playing code. * * If we were REALLY determined, we would make the sound play * asynchronously, but I'll save that one for a rainy day... */ #include "hack.h" #include "dlb.h" #undef red #undef blue #undef green #include #include #include #include #include #include #include #include #include #include #include #include #include #define AMII_AVERAGE_VOLUME 60 int amii_volume = AMII_AVERAGE_VOLUME; typedef struct VHDR { char name[4]; long len; unsigned long oneshot, repeat, samples; UWORD freq; UBYTE n_octaves, compress; LONG volume; } VHDR; typedef struct IFFHEAD { char FORM[4]; long flen; char _8SVX[4]; VHDR vhdr; char NAME[4]; long namelen; } IFFHEAD; extern struct GfxBase *GfxBase; UBYTE whichannel[] = { 1, 2, 4, 8 }; void makesound(char *, char *, int vol); void amii_speaker(struct obj *instr, char *melody, int vol); /* A major scale in indexs to freqtab... */ int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 }; /* Frequencies for a scale starting at one octave below 'middle C' */ long freqtab[] = { 220, /*A */ 233, /*Bb*/ 246, /*B */ 261, /*C */ 277, /*Db*/ 293, /*D */ 311, /*Eb*/ 329, /*E */ 349, /*F */ 370, /*Gb*/ 392, /*G */ 415, /*Ab*/ 440, /*A */ }; #ifdef TESTING main(argc, argv) int argc; char **argv; { makesound("wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60); makesound("wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60); makesound("wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60); makesound("wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60); makesound("wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60); } #else void amii_speaker(struct obj *instr, char *melody, int vol) { int typ = instr->otyp; char *actualn = (char *) OBJ_NAME(objects[typ]); /* Make volume be relative to users volume level, with 60 being the * average level that will be passed to us. */ vol = vol * amii_volume / AMII_AVERAGE_VOLUME; makesound(actualn, melody, vol); } #endif void makesound(char *actualn, char *melody, int vol) { char *t; int c, cycles, dot, dlay; dlb *stream = 0; IFFHEAD iffhead; struct IOAudio *AudioIO = 0; struct MsgPort *AudioMP = 0; struct Message *AudioMSG = 0; ULONG device = -1; BYTE *waveptr = 0; LONG frequency = 440, duration = 1, clock, samp, samples, samcyc = 1; unsigned char name[100]; if (flags.silent) return; if (GfxBase->DisplayFlags & PAL) clock = 3546895; else clock = 3579545; /* * Convert type to file name - if there's nothing to play we * shouldn't be here in the first place. */ strncpy(name, actualn, sizeof(name)); for (t = strchr(name, ' '); t; t = strchr(name, ' ')) *t = '_'; if ((stream = dlb_fopen(name, "r")) == NULL) { perror(name); return; } AudioIO = (struct IOAudio *) AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR); if (AudioIO == 0) goto killaudio; AudioMP = CreateMsgPort(); if (AudioMP == 0) goto killaudio; AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP; AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0; AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE; AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT; AudioIO->ioa_AllocKey = 0; AudioIO->ioa_Data = whichannel; AudioIO->ioa_Length = sizeof(whichannel); device = OpenDevice(AUDIONAME, 0L, (struct IORequest *) AudioIO, 0L); if (device != 0) goto killaudio; if (dlb_fread((genericptr_t) &iffhead, sizeof(iffhead), 1, stream) != 1) goto killaudio; /* This is an even number of bytes long */ if (dlb_fread(name, (iffhead.namelen + 1) & ~1, 1, stream) != 1) goto killaudio; if (dlb_fread((genericptr_t) &samples, 4, 1, stream) != 1) goto killaudio; if (dlb_fread((genericptr_t) &samples, 4, 1, stream) != 1) goto killaudio; waveptr = AllocMem(samples, MEMF_CHIP | MEMF_PUBLIC); if (!waveptr) goto killaudio; if (dlb_fread(waveptr, samples, 1, stream) != 1) goto killaudio; while (melody[0] && melody[1]) { c = *melody++; duration = *melody++; dot = 0; if (*melody == '.') { dot = 1; ++melody; } switch (duration) { case 'w': dlay = 3; duration = 1; cycles = 1; break; case 'h': dlay = 3; duration = 2; cycles = 1; break; case 'q': dlay = 2; duration = 4; cycles = 1; break; case 'e': dlay = 1; duration = 8; cycles = 1; break; case 'x': dlay = 0; duration = 16; cycles = 1; break; case 't': dlay = 0; duration = 32; cycles = 1; break; default: goto killaudio; /* unrecognized duration */ } /* Lower case characters are one octave above upper case */ switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': c -= 'a' - 7; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': c -= 'A'; break; default: continue; } samcyc = samples; /* lowercase start at middle 'C', upper case are one octave below */ frequency = c > 7 ? freqtab[notetab[c % 7]] * 2 : freqtab[notetab[c]]; /* We can't actually do a dotted whole note unless we add code for a * real * 8SVX sample which includes sustain sample information to tell us * how * to hold the note steady... So when duration == 1, ignore 'dot'... */ if (dot && duration > 1) samp = ((samples / duration) * 3) / 2; else samp = samples / duration; /* Only use some of the samples based on frequency */ samp = frequency * samp / 880; /* The 22khz samples are middle C samples, so adjust the play * back frequency accordingly */ frequency = (frequency * (iffhead.vhdr.freq * 2) / 3) / 440L; AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP; AudioIO->ioa_Request.io_Command = CMD_WRITE; AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL; AudioIO->ioa_Data = (BYTE *) waveptr; AudioIO->ioa_Length = samp; /* The clock rate represents the unity rate, so dividing by * the frequency gives us a period ratio... */ /*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, * clock/frequency );*/ AudioIO->ioa_Period = clock / frequency; AudioIO->ioa_Volume = vol; AudioIO->ioa_Cycles = cycles; BeginIO((struct IORequest *) AudioIO); WaitPort(AudioMP); AudioMSG = GetMsg(AudioMP); if (dlay) Delay(dlay); } killaudio: if (stream) dlb_fclose(stream); if (waveptr) FreeMem(waveptr, samples); if (device == 0) CloseDevice((struct IORequest *) AudioIO); if (AudioMP) DeleteMsgPort(AudioMP); if (AudioIO) FreeMem(AudioIO, sizeof(*AudioIO)); } nethack-3.6.0/sys/amiga/amistack.c0000664000076400007660000000110412536476415016002 0ustar paxedpaxed/* NetHack 3.6 amistack.c $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Janne Salmijrvi, Tampere, Finland, 2000 */ /* NetHack may be freely redistributed. See license for details. */ /* * Increase stack size to allow deep recursions. * * Note: This is SAS/C specific, using other compiler probably * requires another method for increasing stack. * */ #ifdef __SASC_60 #include /* * At the moment 90*1024 would suffice, but just to be on the safe side ... */ long __stack = 128 * 1024; #endif nethack-3.6.0/sys/amiga/amitty.c0000664000076400007660000000314012536476415015517 0ustar paxedpaxed/* NetHack 3.6 amitty.c $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996 */ /* NetHack may be freely redistributed. See license for details. */ /* TTY-specific code for the Amiga * This is still experimental. * Still to do: * add real termcap handling - currently requires ANSI_DEFAULT */ #include "hack.h" #include "tcap.h" #include #include #ifdef _DCC #define getch() getchar() #endif #ifdef __SASC_60 #include #endif void NDECL(tty_change_color); char *NDECL(tty_get_color_string); #ifdef TTY_GRAPHICS int amibbs = 0; /* BBS mode */ char bbs_id[80] = ""; /* BBS uid equivalent */ long afh_in, afh_out; /* BBS mode Amiga filehandles */ void settty(const char *s) { end_screen(); if (s) raw_print(s); iflags.cbreak = ON; /* this is too easy: probably wrong */ #if 1 /* should be version>=36 */ /* if(IsInteractive(afh_in)){ */ SetMode(afh_in, 0); /* con mode */ /* } */ #endif } void gettty() { #if 1 /* should be VERSION >=36 */ /* if(IsInteractive(afh_in)){ */ SetMode(afh_in, 1); /* raw mode */ /* } */ #endif } void setftty() { iflags.cbreak = ON; /* ditto */ } char kill_char = 'X' - '@'; char erase_char = '\b'; tgetch() { char x; Read(afh_in, &x, 1); return (x == '\r') ? '\n' : x; } void get_scr_size() { CO = 80; LI = 24; } #endif void tty_change_color() { } char * tty_get_color_string() { return (""); } nethack-3.6.0/sys/amiga/amiwind.c0000664000076400007660000005720412536476415015652 0ustar paxedpaxed/* NetHack 3.6 amiwind.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996 */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" /* Have to undef CLOSE as display.h and intuition.h both use it */ #undef CLOSE #ifdef AMII_GRAPHICS /* too early in the file? too late? */ #ifdef AMIFLUSH static struct Message *FDECL(GetFMsg, (struct MsgPort *)); #endif static int BufferGetchar(void); static void ProcessMessage(register struct IntuiMessage *message); #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch)) struct Library *ConsoleDevice; #include "NH:sys/amiga/amimenu.c" /* Now our own variables */ struct IntuitionBase *IntuitionBase; struct Screen *HackScreen; struct Window *pr_WindowPtr; struct MsgPort *HackPort; struct IOStdReq ConsoleIO; struct Menu *MenuStrip; APTR *VisualInfo; char Initialized = 0; WEVENT lastevent; #ifdef HACKFONT struct GfxBase *GfxBase; struct Library *DiskfontBase; #endif #define KBDBUFFER 10 static unsigned char KbdBuffer[KBDBUFFER]; unsigned char KbdBuffered; #ifdef HACKFONT struct TextFont *TextsFont = NULL; struct TextFont *HackFont = NULL; struct TextFont *RogueFont = NULL; UBYTE FontName[] = "NetHack:hack.font"; /* # chars in "NetHack:": */ #define SIZEOF_DISKNAME 8 #endif struct TextAttr Hack80 = { #ifdef HACKFONT &FontName[SIZEOF_DISKNAME], #else (UBYTE *) "topaz.font", #endif 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED | FPF_ROMFONT }; struct TextAttr TextsFont13 = { (UBYTE *) "courier.font", 13, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED #ifndef HACKFONT | FPF_ROMFONT #endif }; /* Avoid doing a ReplyMsg through a window that no longer exists. */ static enum { NoAction, CloseOver } delayed_key_action = NoAction; /* * Open a window that shares the HackPort IDCMP. Use CloseShWindow() * to close. */ struct Window * OpenShWindow(nw) struct NewWindow *nw; { register struct Window *win; register ULONG idcmpflags; if (!HackPort) /* Sanity check */ return (struct Window *) 0; idcmpflags = nw->IDCMPFlags; nw->IDCMPFlags = 0; if (!(win = OpenWindow((void *) nw))) { nw->IDCMPFlags = idcmpflags; return (struct Window *) 0; } nw->IDCMPFlags = idcmpflags; win->UserPort = HackPort; ModifyIDCMP(win, idcmpflags); return win; } /* * Close a window that shared the HackPort IDCMP port. */ void FDECL(CloseShWindow, (struct Window *)); void CloseShWindow(win) struct Window *win; { register struct IntuiMessage *msg; if (!HackPort) panic("HackPort NULL in CloseShWindow"); if (!win) return; Forbid(); /* Flush all messages for all windows to avoid typeahead and other * similar problems... */ while (msg = (struct IntuiMessage *) GetMsg(win->UserPort)) ReplyMsg((struct Message *) msg); KbdBuffered = 0; win->UserPort = (struct MsgPort *) 0; ModifyIDCMP(win, 0L); Permit(); CloseWindow(win); } static int BufferGetchar() { register int c; if (KbdBuffered > 0) { c = KbdBuffer[0]; KbdBuffered--; /* Move the remaining characters */ if (KbdBuffered < sizeof(KbdBuffer)) memcpy(KbdBuffer, KbdBuffer + 1, KbdBuffered); return c; } return NO_CHAR; } /* * This should remind you remotely of DeadKeyConvert, but we are cheating * a bit. We want complete control over the numeric keypad, and no dead * keys... (they are assumed to be on Alted keys). * * Also assumed is that the IntuiMessage is of type RAWKEY. For some * reason, IECODE_UP_PREFIX events seem to be lost when they occur while * our console window is inactive. This is particulary troublesome with * qualifier keys... Is this because I never RawKeyConvert those events??? */ int ConvertKey(message) register struct IntuiMessage *message; { static struct InputEvent theEvent; static char numpad[] = "bjnh.lyku"; static char ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15"; static char shift_numpad[] = "BJNH.LYKU"; unsigned char buffer[10]; struct Window *w = message->IDCMPWindow; register int length; register ULONG qualifier; char numeric_pad, shift, control, alt; if (amii_wins[WIN_MAP]) w = amii_wins[WIN_MAP]->win; qualifier = message->Qualifier; control = (qualifier & IEQUALIFIER_CONTROL) != 0; shift = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0; alt = (qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT)) != 0; /* Allow ALT to function as a META key ... */ /* But make it switchable - alt is needed for some non-US keymaps */ if (sysflags.altmeta) qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT); numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0; /* * Shortcut for HELP and arrow keys. I suppose this is allowed. * The defines are in intuition/intuition.h, and the keys don't * serve 'text' input, normally. Also, parsing their escape * sequences is such a mess... */ switch (message->Code) { case RAWHELP: if (alt) { EditColor(); return (-1); } #ifdef CLIPPING else if (WINVERS_AMIV && control) { EditClipping(); CO = (w->Width - w->BorderLeft - w->BorderRight) / mxsize; LI = (w->Height - w->BorderTop - w->BorderBottom) / mysize; clipxmax = CO + clipx; clipymax = LI + clipy; if (CO < COLNO || LI < ROWNO) { clipping = TRUE; amii_cliparound(u.ux, u.uy); } else { clipping = FALSE; clipx = clipy = 0; } BufferQueueChar('R' - 64); return (-1); } #endif else if (WINVERS_AMIV && shift) { if (WIN_OVER == WIN_ERR) { WIN_OVER = amii_create_nhwindow(NHW_OVER); BufferQueueChar('R' - 64); } else { delayed_key_action = CloseOver; } return (-1); } return ('?'); break; case CURSORLEFT: length = '4'; numeric_pad = 1; goto arrow; case CURSORDOWN: length = '2'; numeric_pad = 1; goto arrow; case CURSORUP: length = '8'; numeric_pad = 1; goto arrow; case CURSORRIGHT: length = '6'; numeric_pad = 1; goto arrow; } theEvent.ie_Class = IECLASS_RAWKEY; theEvent.ie_Code = message->Code; theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier; theEvent.ie_EventAddress = (APTR)(message->IAddress); length = RawKeyConvert(&theEvent, (char *) buffer, (long) sizeof(buffer), NULL); if (length == 1) { /* Plain ASCII character */ length = buffer[0]; /* * If iflags.num_pad is set, movement is by 4286. * If not set, translate 4286 into hjkl. * This way, the numeric pad can /always/ be used * for moving, though best results are when it is off. */ arrow: if (!iflags.num_pad && numeric_pad && length >= '1' && length <= '9') { length -= '1'; if (control) { length = ctrl_numpad[length]; } else if (shift) { length = shift_numpad[length]; } else { length = numpad[length]; } } /* Kludge to allow altmeta on eg. scandinavian keymap (# == shift+alt+3) and prevent it from interfering with # command (M-#) */ if (length == ('#' | 0x80)) return '#'; if (alt && sysflags.altmeta) length |= 0x80; return (length); } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */ else if (length > 1) { int i; if (length == 3 && buffer[0] == 155 && buffer[2] == 126) { int got = 1; switch (buffer[1]) { case 53: mxsize = mysize = 8; break; case 54: mxsize = mysize = 16; break; case 55: mxsize = mysize = 24; break; case 56: mxsize = mysize = 32; break; case 57: mxsize = mysize = 48; break; default: got = 0; break; } #ifdef OPT_DISPMAP dispmap_sanity(); #endif if (got) { CO = (w->Width - w->BorderLeft - w->BorderRight) / mxsize; LI = (w->Height - w->BorderTop - w->BorderBottom) / mysize; clipxmax = CO + clipx; clipymax = LI + clipy; if (CO < COLNO || LI < ROWNO) { amii_cliparound(u.ux, u.uy); } else { CO = COLNO; LI = ROWNO; } reclip = 1; doredraw(); flush_screen(1); reclip = 0; /*BufferQueueChar( 'R'-64 );*/ return (-1); } } printf("Unrecognized key: %d ", (int) buffer[0]); for (i = 1; i < length; ++i) printf("%d ", (int) buffer[i]); printf("\n"); } return (-1); } /* * Process an incoming IntuiMessage. * It would certainly look nicer if this could be done using a * PA_SOFTINT message port, but we cannot call RawKeyConvert() * during a software interrupt. * Anyway, amikbhit()/kbhit() is called often enough, and usually gets * ahead of input demands, when the user types ahead. */ static void ProcessMessage(message) register struct IntuiMessage *message; { int c; int cnt; menu_item *mip; static int skip_mouse = 0; /* need to ignore next mouse event on * a window activation */ struct Window *w = message->IDCMPWindow; switch (message->Class) { case ACTIVEWINDOW: if (alwaysinvent && WIN_INVEN != WIN_ERR && w == amii_wins[WIN_INVEN]->win) { cnt = DoMenuScroll(WIN_INVEN, 0, PICK_NONE, &mip); } else if (scrollmsg && WIN_MESSAGE != WIN_ERR && w == amii_wins[WIN_MESSAGE]->win) { cnt = DoMenuScroll(WIN_MESSAGE, 0, PICK_NONE, &mip); } else { skip_mouse = 1; } break; case MOUSEBUTTONS: { if (skip_mouse) { skip_mouse = 0; break; } if (!amii_wins[WIN_MAP] || w != amii_wins[WIN_MAP]->win) break; if (message->Code == SELECTDOWN) { lastevent.type = WEMOUSE; lastevent.un.mouse.x = message->MouseX; lastevent.un.mouse.y = message->MouseY; /* With shift equals RUN */ lastevent.un.mouse.qual = (message->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0; } } break; case MENUPICK: { USHORT thismenu; struct MenuItem *item; thismenu = message->Code; while (thismenu != MENUNULL) { item = ItemAddress(MenuStrip, (ULONG) thismenu); if (KbdBuffered < KBDBUFFER) BufferQueueChar((char) (GTMENUITEM_USERDATA(item))); thismenu = item->NextSelect; } } break; case REFRESHWINDOW: { if (scrollmsg && amii_wins[WIN_MESSAGE] && w == amii_wins[WIN_MESSAGE]->win) { cnt = DoMenuScroll(WIN_MESSAGE, 0, PICK_NONE, &mip); } } break; case CLOSEWINDOW: if (WIN_INVEN != WIN_ERR && w == amii_wins[WIN_INVEN]->win) { dismiss_nhwindow(WIN_INVEN); } if (WINVERS_AMIV && (WIN_OVER != WIN_ERR && w == amii_wins[WIN_OVER]->win)) { destroy_nhwindow(WIN_OVER); WIN_OVER = WIN_ERR; } break; case RAWKEY: if (!(message->Code & IECODE_UP_PREFIX)) { /* May queue multiple characters * but doesn't do that yet... */ if ((c = ConvertKey(message)) > 0) BufferQueueChar(c); } break; case GADGETDOWN: if (WIN_MESSAGE != WIN_ERR && w == amii_wins[WIN_MESSAGE]->win) { cnt = DoMenuScroll(WIN_MESSAGE, 0, PICK_NONE, &mip); } else if (WIN_INVEN != WIN_ERR && w == amii_wins[WIN_INVEN]->win) { cnt = DoMenuScroll(WIN_INVEN, 0, PICK_NONE, &mip); } break; case NEWSIZE: if (WIN_MESSAGE != WIN_ERR && w == amii_wins[WIN_MESSAGE]->win) { if (WINVERS_AMIV) { /* Make sure that new size is honored for good. */ SetAPen(w->RPort, amii_msgBPen); SetBPen(w->RPort, amii_msgBPen); SetDrMd(w->RPort, JAM2); RectFill(w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); } ReDisplayData(WIN_MESSAGE); } else if (WIN_INVEN != WIN_ERR && w == amii_wins[WIN_INVEN]->win) { ReDisplayData(WIN_INVEN); } else if (WINVERS_AMIV && (WIN_OVER != WIN_ERR && w == amii_wins[WIN_OVER]->win)) { BufferQueueChar('R' - 64); } else if (WIN_MAP != WIN_ERR && w == amii_wins[WIN_MAP]->win) { #ifdef CLIPPING CO = (w->Width - w->BorderLeft - w->BorderRight) / mxsize; LI = (w->Height - w->BorderTop - w->BorderBottom) / mysize; clipxmax = CO + clipx; clipymax = LI + clipy; if (CO < COLNO || LI < ROWNO) { amii_cliparound(u.ux, u.uy); } else { clipping = FALSE; clipx = clipy = 0; } BufferQueueChar('R' - 64); #endif } break; } ReplyMsg((struct Message *) message); switch (delayed_key_action) { case CloseOver: amii_destroy_nhwindow(WIN_OVER); WIN_OVER = WIN_ERR; delayed_key_action = NoAction; case NoAction: ; /* null */ } } #endif /* AMII_GRAPHICS */ /* * Get all incoming messages and fill up the keyboard buffer, * thus allowing Intuition to (maybe) free up the IntuiMessages. * Return when no more messages left, or keyboard buffer half full. * We need to do this since there is no one-to-one correspondence * between characters and incoming messages. */ #if defined(TTY_GRAPHICS) && !defined(AMII_GRAPHICS) int kbhit() { return 0; } #else int kbhit() { int c; #ifdef TTY_GRAPHICS /* a kludge to defuse the mess in allmain.c */ /* I hope this is the right approach */ if (windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) return 0; #endif c = amikbhit(); if (c <= 0) return (0); return (c); } #endif #ifdef AMII_GRAPHICS int amikbhit() { register struct IntuiMessage *message; while (KbdBuffered < KBDBUFFER / 2) { #ifdef AMIFLUSH message = (struct IntuiMessage *) GetFMsg(HackPort); #else message = (struct IntuiMessage *) GetMsg(HackPort); #endif if (message) { ProcessMessage(message); if (lastevent.type != WEUNK && lastevent.type != WEKEY) break; } else break; } return (lastevent.type == WEUNK) ? KbdBuffered : -1; } /* * Get a character from the keyboard buffer, waiting if not available. * Ignore other kinds of events that happen in the mean time. */ int WindowGetchar() { while ((lastevent.type = WEUNK), amikbhit() <= 0) { WaitPort(HackPort); } return BufferGetchar(); } WETYPE WindowGetevent() { lastevent.type = WEUNK; while (amikbhit() == 0) { WaitPort(HackPort); } if (KbdBuffered) { lastevent.type = WEKEY; lastevent.un.key = BufferGetchar(); } return (lastevent.type); } /* * Clean up everything. But before we do, ask the user to hit return * when there is something that s/he should read. */ void amii_cleanup() { register struct IntuiMessage *msg; /* Close things up */ if (HackPort) { amii_raw_print(""); amii_getret(); } if (ConsoleIO.io_Device) CloseDevice((struct IORequest *) &ConsoleIO); ConsoleIO.io_Device = 0; if (ConsoleIO.io_Message.mn_ReplyPort) DeleteMsgPort(ConsoleIO.io_Message.mn_ReplyPort); ConsoleIO.io_Message.mn_ReplyPort = 0; /* Strip messages before deleting the port */ if (HackPort) { Forbid(); while (msg = (struct IntuiMessage *) GetMsg(HackPort)) ReplyMsg((struct Message *) msg); kill_nhwindows(1); DeleteMsgPort(HackPort); HackPort = NULL; Permit(); } /* Close the screen, under v37 or greater it is a pub screen and there may * be visitors, so check close status and wait till everyone is gone. */ if (HackScreen) { #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { if (MenuStrip) FreeMenus(MenuStrip); if (VisualInfo) FreeVisualInfo(VisualInfo); while (CloseScreen(HackScreen) == FALSE) { struct EasyStruct easy = { sizeof(struct EasyStruct), 0, "Nethack Problem", "Can't Close Screen, Close Visiting Windows", "Okay" }; EasyRequest(NULL, &easy, NULL, NULL); } } else #endif { CloseScreen(HackScreen); } HackScreen = NULL; } #ifdef HACKFONT if (HackFont) { CloseFont(HackFont); HackFont = NULL; } if (TextsFont) { CloseFont(TextsFont); TextsFont = NULL; } if (RogueFont) { CloseFont(RogueFont); RogueFont = NULL; } if (DiskfontBase) { CloseLibrary(DiskfontBase); DiskfontBase = NULL; } #endif if (GadToolsBase) { CloseLibrary((struct Library *) GadToolsBase); GadToolsBase = NULL; } if (LayersBase) { CloseLibrary((struct Library *) LayersBase); LayersBase = NULL; } if (GfxBase) { CloseLibrary((struct Library *) GfxBase); GfxBase = NULL; } if (IntuitionBase) { CloseLibrary((struct Library *) IntuitionBase); IntuitionBase = NULL; } #ifdef SHAREDLIB if (DOSBase) { CloseLibrary((struct Library *) DOSBase); DOSBase = NULL; } #endif ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr; Initialized = 0; } #endif /* AMII_GRAPHICS */ #ifndef SHAREDLIB void Abort(rc) long rc; { int fault = 1; #ifdef CHDIR extern char orgdir[]; chdir(orgdir); #endif #ifdef AMII_GRAPHICS if (Initialized && ConsoleDevice && windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) { printf("\n\nAbort with alert code %08lx...\n", rc); amii_getret(); } else #endif printf("\n\nAbort with alert code %08lx...\n", rc); /* Alert(rc); this is too severe */ #ifdef __SASC #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { struct EasyStruct es = { sizeof(struct EasyStruct), 0, "NetHack Panic Request", "NetHack is Aborting with code == 0x%08lx", "Continue Abort|Return to Program|Clean up and exit", }; fault = EasyRequest(NULL, &es, NULL, (long) rc); if (fault == 2) return; } #endif if (fault == 1) { /* __emit(0x4afc); */ /* illegal instruction */ __emit(0x40fc); /* divide by */ __emit(0x0000); /* #0 */ /* NOTE: don't move amii_cleanup() above here - */ /* it is too likely to kill the system */ /* before it can get the SnapShot out, if */ /* there is something really wrong. */ } #endif #ifdef AMII_GRAPHICS if (windowprocs.win_init_nhwindows == amii_procs.win_init_nhwindows) amii_cleanup(); #endif #undef exit #ifdef AZTEC_C _abort(); #endif exit((int) rc); } void CleanUp() { amii_cleanup(); } #endif #ifdef AMII_GRAPHICS #ifdef AMIFLUSH /* This routine adapted from AmigaMail IV-37 by Michael Sinz */ static struct Message * GetFMsg(port) struct MsgPort *port; { struct IntuiMessage *msg, *succ, *succ1; if (msg = (struct IntuiMessage *) GetMsg(port)) { if (!sysflags.amiflush) return ((struct Message *) msg); if (msg->Class == RAWKEY) { Forbid(); succ = (struct IntuiMessage *) (port->mp_MsgList.lh_Head); while (succ1 = (struct IntuiMessage *) (succ->ExecMessage.mn_Node .ln_Succ)) { if (succ->Class == RAWKEY) { Remove((struct Node *) succ); ReplyMsg((struct Message *) succ); } succ = succ1; } Permit(); } } return ((struct Message *) msg); } #endif struct NewWindow * DupNewWindow(win) struct NewWindow *win; { struct NewWindow *nwin; struct Gadget *ngd, *gd, *pgd = NULL; struct PropInfo *pip; struct StringInfo *sip; /* Copy the (Ext)NewWindow structure */ nwin = (struct NewWindow *) alloc(sizeof(struct NewWindow)); *nwin = *win; /* Now do the gadget list */ nwin->FirstGadget = NULL; for (gd = win->FirstGadget; gd; gd = gd->NextGadget) { ngd = (struct Gadget *) alloc(sizeof(struct Gadget)); *ngd = *gd; if (gd->GadgetType == STRGADGET) { sip = (struct StringInfo *) alloc(sizeof(struct StringInfo)); *sip = *((struct StringInfo *) gd->SpecialInfo); sip->Buffer = (UBYTE *) alloc(sip->MaxChars); *sip->Buffer = 0; ngd->SpecialInfo = (APTR) sip; } else if (gd->GadgetType == PROPGADGET) { pip = (struct PropInfo *) alloc(sizeof(struct PropInfo)); *pip = *((struct PropInfo *) gd->SpecialInfo); ngd->SpecialInfo = (APTR) pip; } if (pgd) pgd->NextGadget = ngd; else nwin->FirstGadget = ngd; pgd = ngd; ngd->NextGadget = NULL; ngd->UserData = (APTR) 0x45f35c3d; // magic cookie for FreeNewWindow() } return (nwin); } void FreeNewWindow(win) struct NewWindow *win; { register struct Gadget *gd, *pgd; register struct StringInfo *sip; for (gd = win->FirstGadget; gd; gd = pgd) { pgd = gd->NextGadget; if ((ULONG) gd->UserData == 0x45f35c3d) { if (gd->GadgetType == STRGADGET) { sip = (struct StringInfo *) gd->SpecialInfo; free(sip->Buffer); free(sip); } else if (gd->GadgetType == PROPGADGET) { free((struct PropInfo *) gd->SpecialInfo); } free(gd); } } free(win); } void bell() { if (flags.silent) return; DisplayBeep(NULL); } void amii_delay_output() { /* delay 50 ms */ Delay(2L); } void amii_number_pad(state) int state; { } #endif /* AMII_GRAPHICS */ #ifndef SHAREDLIB void amiv_loadlib(void) { } void amii_loadlib(void) { } /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *, s) { VA_START(s); VA_INIT(s, char *); putchar('\n'); vprintf(s, VA_ARGS); putchar('\n'); VA_END(); Abort(0L); } #endif nethack-3.6.0/sys/amiga/amiwind.p0000664000076400007660000000267712536476415015673 0ustar paxedpaxed/* NetHack 3.6 amiwind.p $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ /* Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* amiwind.c */ #ifdef INTUI_NEW_LOOK struct Window *FDECL( OpenShWindow, (struct ExtNewWindow *) ); #else struct Window *FDECL( OpenShWindow, (struct NewWindow *) ); #endif void FDECL( CloseShWindow, (struct Window *)); int NDECL( kbhit ); int NDECL( amikbhit ); int NDECL( WindowGetchar ); WETYPE NDECL( WindowGetevent ); void NDECL( WindowFlush ); void FDECL( WindowPutchar, (char )); void FDECL( WindowFPuts, (const char *)); void FDECL( WindowPuts, (const char *)); void FDECL( WindowPrintf, ( char *,... )); void NDECL( CleanUp ); int FDECL( ConvertKey, ( struct IntuiMessage * )); #ifndef SHAREDLIB void FDECL( Abort, (long )); #endif void FDECL( flush_glyph_buffer, (struct Window *)); void FDECL( amiga_print_glyph, (winid , int , int )); void FDECL( start_glyphout, (winid )); void FDECL( amii_end_glyphout, (winid )); #ifdef INTUI_NEW_LOOK struct ExtNewWindow *FDECL( DupNewWindow, (struct ExtNewWindow *)); void FDECL( FreeNewWindow, (struct ExtNewWindow *)); #else struct NewWindow *FDECL( DupNewWindow, (struct NewWindow *)); void FDECL( FreeNewWindow, (struct NewWindow *)); #endif void NDECL( bell ); void NDECL( amii_delay_output ); void FDECL( amii_number_pad, (int )); void amii_cleanup( void ); nethack-3.6.0/sys/amiga/clipwin.c0000664000076400007660000002606612536476415015671 0ustar paxedpaxedstatic USHORT Palette[] = { 0x0AAA, /* color #0 */ 0x0000, /* color #1 */ 0x0FFF, /* color #2 */ 0x058B, /* color #3 */ 0x000F, /* color #4 */ 0x0F0F, /* color #5 */ 0x00FF, /* color #6 */ 0x0FFF /* color #7 */ #define PaletteColorCount 8 }; #define PALETTE Palette static SHORT ClipBorderVectors1[] = { 0, 0, 76, 0, 76, 11, 0, 11, 0, 0 }; static struct Border ClipBorder1 = { -1, -1, /* XY origin relative to container TopLeft */ 3, 0, JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ ClipBorderVectors1, /* pointer to XY vectors */ NULL /* next border in list */ }; static struct IntuiText ClipIText1 = { 4, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 15, 1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Cancel", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipCancel = { NULL, /* next gadget */ 240, 59, /* origin XY of hit box relative to window TopLeft */ 75, 10, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR) &ClipBorder1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText1, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCANCEL, /* user-definable data */ NULL /* pointer to user-definable data */ }; static SHORT ClipBorderVectors2[] = { 0, 0, 78, 0, 78, 11, 0, 11, 0, 0 }; static struct Border ClipBorder2 = { -1, -1, /* XY origin relative to container TopLeft */ 3, 0, JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ ClipBorderVectors2, /* pointer to XY vectors */ NULL /* next border in list */ }; static struct IntuiText ClipIText2 = { 4, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 24, 1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Okay", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipOkay = { &ClipCancel, /* next gadget */ 17, 60, /* origin XY of hit box relative to window TopLeft */ 77, 10, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR) &ClipBorder2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText2, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADOKAY, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipXCLIPSInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ 24504, -1, /* horizontal and vertical pot values */ 10922, -1, /* horizontal and vertical body values */ }; static struct Image ClipImage1 = { 43, 0, /* XY origin relative to container TopLeft */ 24, 3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText3 = { 3, 0, JAM1, /* front and back text pens, drawmode and fill byte */ -116, -1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "X Clip Border:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipXCLIP = { &ClipOkay, /* next gadget */ 134, 37, /* origin XY of hit box relative to window TopLeft */ -199, 7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY + GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &ClipImage1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText3, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &ClipClipXCLIPSInfo, /* SpecialInfo structure */ XCLIP, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipYCLIPSInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ 13106, -1, /* horizontal and vertical pot values */ 10922, -1, /* horizontal and vertical body values */ }; static struct Image ClipImage2 = { 22, 0, /* XY origin relative to container TopLeft */ 24, 3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText4 = { 3, 0, JAM1, /* front and back text pens, drawmode and fill byte */ -116, -1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Y Clip Border:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipYCLIP = { &ClipXCLIP, /* next gadget */ 134, 46, /* origin XY of hit box relative to window TopLeft */ -199, 7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY + GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &ClipImage2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText4, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &ClipClipYCLIPSInfo, /* SpecialInfo structure */ YCLIP, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipXSIZESInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ 26212, -1, /* horizontal and vertical pot values */ 10922, -1, /* horizontal and vertical body values */ }; static struct Image ClipImage3 = { 45, 0, /* XY origin relative to container TopLeft */ 24, 3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText5 = { 3, 0, JAM1, /* front and back text pens, drawmode and fill byte */ -124, -1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "X Scale Factor:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipXSIZE = { &ClipYCLIP, /* next gadget */ 134, 15, /* origin XY of hit box relative to window TopLeft */ -199, 7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY + GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &ClipImage3, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText5, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &ClipClipXSIZESInfo, /* SpecialInfo structure */ XSIZE, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipYSIZESInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ -25937, -1, /* horizontal and vertical pot values */ 10922, -1, /* horizontal and vertical body values */ }; static struct Image ClipImage4 = { 69, 0, /* XY origin relative to container TopLeft */ 24, 3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText6 = { 3, 0, JAM1, /* front and back text pens, drawmode and fill byte */ -124, -1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Y Scale Factor:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipYSIZE = { &ClipXSIZE, /* next gadget */ 134, 24, /* origin XY of hit box relative to window TopLeft */ -199, 7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY + GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &ClipImage4, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText6, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &ClipClipYSIZESInfo, /* SpecialInfo structure */ YSIZE, /* user-definable data */ NULL /* pointer to user-definable data */ }; #define ClipGadgetList1 ClipYSIZE static struct NewWindow ClipNewWindowStructure1 = { 114, 16, /* window XY origin relative to TopLeft of screen */ 346, 76, /* window width and height */ 0, 1, /* detail and block pens */ NEWSIZE + MOUSEMOVE + GADGETDOWN + GADGETUP + CLOSEWINDOW + ACTIVEWINDOW + VANILLAKEY + INTUITICKS, /* IDCMP flags */ WINDOWSIZING + WINDOWDRAG + WINDOWDEPTH + WINDOWCLOSE + ACTIVATE + NOCAREREFRESH, /* other window flags */ &ClipYSIZE, /* first gadget in gadget list */ NULL, /* custom CHECKMARK imagery */ "Edit Clipping Parameters", /* window title */ NULL, /* custom screen pointer */ NULL, /* custom bitmap */ 350, 76, /* minimum width and height */ -1, -1, /* maximum width and height */ CUSTOMSCREEN /* destination screen type */ }; /* end of PowerWindows source generation */ nethack-3.6.0/sys/amiga/colorwin.c0000664000076400007660000002476512536476415016064 0ustar paxedpaxedSHORT Col_BorderVectors1[] = { 0, 0, 59, 0, 59, 12, 0, 12, 0, 0 }; struct Border Col_Border1 = { -1, -1, /* XY origin relative to container TopLeft */ 3, 0, JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ Col_BorderVectors1, /* pointer to XY vectors */ NULL /* next border in list */ }; struct IntuiText Col_IText1 = { 7, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 13, 1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Save", /* pointer to text */ NULL /* next IntuiText structure */ }; struct Gadget Col_Save = { NULL, /* next gadget */ 9, 77, /* origin XY of hit box relative to window TopLeft */ 58, 11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR) &Col_Border1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &Col_IText1, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCOLSAVE, /* user-definable data */ NULL /* pointer to user-definable data */ }; SHORT Col_BorderVectors2[] = { 0, 0, 59, 0, 59, 12, 0, 12, 0, 0 }; struct Border Col_Border2 = { -1, -1, /* XY origin relative to container TopLeft */ 3, 0, JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ Col_BorderVectors2, /* pointer to XY vectors */ NULL /* next border in list */ }; struct IntuiText Col_IText2 = { 7, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 17, 1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Use", /* pointer to text */ NULL /* next IntuiText structure */ }; struct Gadget Col_Okay = { &Col_Save, /* next gadget */ 128, 77, /* origin XY of hit box relative to window TopLeft */ 58, 11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR) &Col_Border2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &Col_IText2, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCOLOKAY, /* user-definable data */ NULL /* pointer to user-definable data */ }; SHORT Col_BorderVectors3[] = { 0, 0, 59, 0, 59, 12, 0, 12, 0, 0 }; struct Border Col_Border3 = { -1, -1, /* XY origin relative to container TopLeft */ 3, 0, JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ Col_BorderVectors3, /* pointer to XY vectors */ NULL /* next border in list */ }; struct IntuiText Col_IText3 = { 7, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 6, 1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Cancel", /* pointer to text */ NULL /* next IntuiText structure */ }; struct Gadget Col_Cancel = { &Col_Okay, /* next gadget */ 244, 77, /* origin XY of hit box relative to window TopLeft */ 58, 11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR) &Col_Border3, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &Col_IText3, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCOLCANCEL, /* user-definable data */ NULL /* pointer to user-definable data */ }; struct PropInfo Col_Col_RedPenSInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ 0, 0, /* horizontal and vertical pot values */ -1, -1, /* horizontal and vertical body values */ }; struct Image Col_Image1 = { 0, 0, /* XY origin relative to container TopLeft */ 263, 7, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; struct Gadget Col_RedPen = { &Col_Cancel, /* next gadget */ 32, 12, /* origin XY of hit box relative to window TopLeft */ 271, 11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY + GADGIMMEDIATE + FOLLOWMOUSE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &Col_Image1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ NULL, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &Col_Col_RedPenSInfo, /* SpecialInfo structure */ GADREDPEN, /* user-definable data */ NULL /* pointer to user-definable data */ }; struct PropInfo Col_Col_GreenPenSInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ 0, 0, /* horizontal and vertical pot values */ -1, -1, /* horizontal and vertical body values */ }; struct Image Col_Image2 = { 0, 0, /* XY origin relative to container TopLeft */ 263, 7, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; struct Gadget Col_GreenPen = { &Col_RedPen, /* next gadget */ 32, 24, /* origin XY of hit box relative to window TopLeft */ 271, 11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY + GADGIMMEDIATE + FOLLOWMOUSE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &Col_Image2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ NULL, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &Col_Col_GreenPenSInfo, /* SpecialInfo structure */ GADGREENPEN, /* user-definable data */ NULL /* pointer to user-definable data */ }; struct PropInfo Col_Col_BluePenSInfo = { AUTOKNOB + FREEHORIZ, /* PropInfo flags */ 0, 0, /* horizontal and vertical pot values */ -1, -1, /* horizontal and vertical body values */ }; struct Image Col_Image3 = { 0, 0, /* XY origin relative to container TopLeft */ 263, 7, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000, 0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; struct Gadget Col_BluePen = { &Col_GreenPen, /* next gadget */ 32, 36, /* origin XY of hit box relative to window TopLeft */ 271, 11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY + GADGIMMEDIATE + FOLLOWMOUSE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR) &Col_Image3, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ NULL, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR) &Col_Col_BluePenSInfo, /* SpecialInfo structure */ GADBLUEPEN, /* user-definable data */ NULL /* pointer to user-definable data */ }; #define Col_GadgetList1 Col_BluePen struct IntuiText Col_IText6 = { 3, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 17, 38, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "B", /* pointer to text */ NULL /* next IntuiText structure */ }; struct IntuiText Col_IText5 = { 4, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 16, 26, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "G", /* pointer to text */ &Col_IText6 /* next IntuiText structure */ }; struct IntuiText Col_IText4 = { 7, 0, JAM1, /* front and back text pens, drawmode and fill byte */ 16, 14, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "R", /* pointer to text */ &Col_IText5 /* next IntuiText structure */ }; #define Col_IntuiTextList1 Col_IText4 struct NewWindow Col_NewWindowStructure1 = { 175, 45, /* window XY origin relative to TopLeft of screen */ 312, 93, /* window width and height */ 0, 1, /* detail and block pens */ MOUSEBUTTONS + MOUSEMOVE + GADGETDOWN + GADGETUP + CLOSEWINDOW + VANILLAKEY + INTUITICKS, /* IDCMP flags */ WINDOWDRAG + WINDOWDEPTH + WINDOWCLOSE + ACTIVATE + NOCAREREFRESH, /* other window flags */ &Col_BluePen, /* first gadget in gadget list */ NULL, /* custom CHECKMARK imagery */ "Edit Screen Colors", /* window title */ NULL, /* custom screen pointer */ NULL, /* custom bitmap */ 5, 5, /* minimum width and height */ -1, -1, /* maximum width and height */ CUSTOMSCREEN /* destination screen type */ }; /* end of PowerWindows source generation */ nethack-3.6.0/sys/amiga/cvtsnd.c0000664000076400007660000000463312536476415015521 0ustar paxedpaxed/* NetHack 3.6 cvtsnd.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) 1995, Andrew Church, Olney, Maryland */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include typedef struct { short namelen; char name[62]; char misc[64]; /* rest of MacBinary header */ long FORM; long flen; long AIFF; long SSND; long sndlen; } AIFF; typedef struct { char FORM[4]; long flen; char _8SVX[4]; char VHDR[4]; long vhlen; long oneshot, repeat; long samples; /* 'samplesPerHiCycle' in the docs - usually 32, so * we'll use that */ short freq; char octaves, compress; long volume; char NAME[4]; long nlen; /* should be 64; see name[] comment */ char name[64]; /* for simplicity, i.e. just fwrite() entiree header */ char BODY[4]; long blen; } IFF; main(int ac, char **av) { FILE *in, *out; AIFF aiff; IFF iff; static char buf[16384]; long n, len; if (ac != 3) { fprintf(stderr, "Usage: %s input-file output-file\n", av[0]); exit(20); } if (!(in = fopen(av[1], "r"))) { fprintf(stderr, "Can't open input file\n"); exit(20); } if (!(out = fopen(av[2], "w"))) { fprintf(stderr, "Can't open output file\n"); exit(20); } fread(&aiff, sizeof(aiff), 1, in); memcpy(iff.FORM, "FORM", 4); iff.flen = sizeof(iff) + aiff.sndlen - 8; memcpy(iff._8SVX, "8SVX", 4); memcpy(iff.VHDR, "VHDR", 4); iff.vhlen = 20; iff.oneshot = aiff.sndlen; iff.repeat = 0; iff.samples = 32; iff.freq = 22000; iff.octaves = 1; iff.compress = 0; iff.volume = 0x10000; memcpy(iff.NAME, "NAME", 4); iff.nlen = 64; strncpy(iff.name, aiff.name, 62); iff.name[aiff.namelen] = 0; memcpy(iff.BODY, "BODY", 4); iff.blen = aiff.sndlen; fwrite(&iff, sizeof(iff), 1, out); len = aiff.sndlen; do { if (len >= sizeof(buf)) n = fread(buf, 1, sizeof(buf), in); else n = fread(buf, 1, len, in); if (n) { fwrite(buf, 1, n, out); len -= n; } } while (len && n); if (len) fprintf(stderr, "Warning: %ld bytes of sample missing\n", len); fclose(in); fclose(out); exit(0); } nethack-3.6.0/sys/amiga/grave16.xpm0000664000076400007660000023641312467321052016045 0ustar paxedpaxed/* XPM */ static char *noname[] = { /* width height ncolors chars_per_pixel */ "400 200 16 1", /* colors */ "` c #66686A", "a c #797979", "b c #929291", "c c #43444A", "d c #758A74", "e c #F2F2F2", "f c #D1D0CE", "g c #066906", "h c #065506", "i c #53535C", "j c #0C0D0F", "k c #A3A5A2", "l c #2D332E", "m c #C3C4C1", "n c #B4B4B2", "o c #07840A", /* pixels */ "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjjjjjjjjjljjjjjjjjjjjljljjljljjljjllljljclljlllljlllljlllllllllllllllcicl``clcllclclllclclclcclclclcccccccccccccccccccii`iiccicicicciiciiiiiibiic`iii`a`iiii`icaii`iiii`iiii`ii`ii`iii```iii`i`ii`ii`ii`iiii`iii`ii`iifi`ii`ii`iiiiiiiiiiiiiiiiiiiiii`iciibicicicicciiccciiibiicciiiiccccbicicccccccciccclcccccclc`aiciiiciccclilccccccccccclcccacccccccclccclcclccc", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjljjjjjjljjjjjjajljjljljljljjjjljjljc`baljjllcljjcjlljllllllllllllllllllllllcclllllllclllcclcllclclccccccccclccccccccccccicciicciicicicic`cciiciciciciacicii`iiiiii``iiakii`iiii`ii`ii`iiii`bkb`i`ci``iiiiii`iii`ii``i`iiiiiaiiiiiiiiii`iiiiiiiiiiiiiiiiiiiiiciiciciicicciciiiicllic`iciiiicicciliccccccccccccc`ccccliccccccccciciccclccccclclclclcclccclclclllccclcllccll", "ijjjjjjjjjjjjjjjjjjljjjjjjjjljjjjjjjjjjjljjjljjjjjjljljjjjjjjljjjljljljljjjjlljljljljcclljllllljlllljllllllllllllllllcclccclcjcllclclclclllcclclcccccccccccciccccciiic`a`icciiccciciiiiiiiiibi`iiiiii`ii`ci`iii`ii`i`iiiiiiiii`iii``ici`i`i`i``ii`ii`iiiiiiic``iiiiiiiiiiiiiiaiiiiiiiiiiciicicii`iiiiiliiccicicccicccci`ccicccicccclccinccccccccclcccaccccccclccccccccccilcl`lllccclcclcclcllcllclcccclllilcllci", "jjjjjjjjjjjjj`cjjjjljjjjjjjjcljljjjjjjjljjljijjljjjjjjjljljljjljljljlljljllljjljllflcjljllljljlljllllcllllllllllllcllllccllcc`clclllcllcclclcccclccccccccciccciciccccccic`iciic`iiiiciiiiiiiaiii`iii`i`icak`c``i`iiiiii`ii`i`iii`i`ii`iiiiiiici`iii`ii`i`ii``iiii`c`iiiiiiiii`iiiiiiiiciiiiiiiiiiiccccciccicicciiccccciaillcccciiciccclcccccccccccccc`cclclccillccllcliibilikaicllcclccccclcccclcccccllccllcclcl", "jjcjjjjjjjjljjjjjjjjjjjjjjjjljjjljjjjjjjjjjjljjjjjljjcjjjljjljjljjjljjljljjjlljllljlllcljllllllllllllcclllllllllclllcclccibccclclcclcclcllicicccccccclcccccccciciicciccciaaiciccciiiiiiii`ciiiiii`iiiii`ic`iiiiiiii`ii`iiiiiiiiii`iiiiiciiiii`i`iiiii`ii`iiiciiiiiiiiiiiiiiciiiciiciciiccicciiiiiicicc`cccccccicccccicciiccicccicclilccccccclccccclccllcccilcccclcciclccciclcclccclccclclllcllcllccllcccclaacccl", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljljjjjjjjlljjjjljljjjjjljjljjljljlljljlljlllllljajljljlllllllllllllllcllllllllclccilcicclc`clalcclclclcclcccicclclccccciiccicciccciciiiiiiciib`iiiiiiiiiii`iiii``i`i`iiiiiiii`iiiiiiiiiiiiiiiiiibaiiici`iiiiibiiiii`iiiic`kaiiiiiiiiiiiiiciiiciiiciiciciccicciiiiciiiciccicicccccccciclcccccciiccccaciclclcccciilcccclcclcclcllclilacclcccclccclclcccccclccclclccllcclllllkblllc", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjljjjljjjjjljljjjjjjjljljjljjljljlllljljljljjjjjljllljcjllllllllllllllllllllccclclabclccccciccccllclclcclcclclccccccccciiaiiicciciiicccccciiiiiiiiiciiiiiicii`i`i``i`iiiii`iiiiiiiiiiiiiiiiiiiiiibiciiiicciiii`iiiiiiiiiie`i``ic`iiiiiiiiiciiciciiciciciciciiiciic`cccclcccccccccciccccccciccciicilcillcccccclciccccclclccclibaili`lillccccciicliccccccclcccllallclliiiclcliilcll", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjljjjjjjjjljjljjjljjjjjljjljljlllllljllljlclllllljlllllllllllllllllllllllllcccclccliiccccciccccclclcclccccccclcciccccciacciciiiccci`iiiiciiiiiiiiiiiiiii`i`c``````i``iiiiciiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii`kciiiiiiiiii`c`iciciiiiiiciiiiiiciccicicicciciiiiii`ifcccciccicccccccccccccccclccccccclcclccclccclclclcllilclcclcllclcliilclclclccicccccccccllllcecclclliaacllcllclc", "jjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjljljjjljjjjlljjljjjljljjlijjllllllllllllljljajlljlalllllllllllllllllllllccccclllccclclccccccccccclcccccc`clcccccccccccicacicciciciciiiiiiib`iiciiiii`c`iiii``iii``ii``ciiiiiiciiiiciiiii`biii`iiiiciiiiciiicib`iiiiiiiiiiiiiiiiicii```cccciciciciiiiiiiciiiciiccccccccccciicciccccccccccccciccccclccclcccllccclclc`ccclcclcccccclcccllclccclclllcllcliccllclmccclcccl`lclclclll", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjljjjlljjjllljlljjjljljjjljljlcllllljcljjcljlllijllllllllllllllilcllcccccllicllllclcllcclliccccclccclcccccccccccccccc`iciicicciiiaiciciicl`ici`iiiiiiii`ii`i`ii``iiiiiiiiiiiiiii`iiiiiaciiciiiiiiiciiiciiiiiiicici`ciiciiiiciicciiiciiciciiiciiiiiii`cbi`liicicccccccccclccccccccclclccccccclcilccllccccllcclcccclcclclclllllcllllcllllllclcllccccclllcllilllclllclilillccll", "jjjjjjjljljjjjjjjjjjjjjjjjjjljjjjljljjjjjjjjlljjljlllljllljllljlcljjljljcjlllljcljllllcllllllllllim`lljccllcclcbacllcllclccliclcccclccccccccccccccicciciciiciiciiiiiibiiiib``iiii`i`iiaii`ii`iiiiiciiiiiiiiiiicciiiiiii`iiiiiciiiiciciici`cciiciciiiiib`c`aaicciicicciccccciiiiiiiicciiicciilccccclcccccccccccclccccccclccliccccclclclcillccccllcclclccilcccclclcclcccclclclclllcllllcclllllllclllcllcllclcll`cc", "jjjjjjjjjjjjjjjjjjjjijljjjjjjjljjljjljjjljjjjjjcjljljlcjjlcljlljkclllllllcllllljllllllljllllllllllliiccccclllllcccllcclcclclclcicccccclcclcccccccicccciicciciiciiiicc`ciii`ciiiiiiiiii``ii`iiiiiiiicii`i`i`iii`iicic`ii``iiiiiiiiiiciciciiiicc`ciicici`cc`iiiciciicicciicicci`iiiiiciciicicccibiccccccclcccccclclcclclcclccicclclcicclikclcllclllcllcllclccccllclclcliclci`cllclllillliccclcllclclbilllclllclcal", "jjjjjjcbljjcajjjjjjjljjjljljjjjjljjjjjjljljjljjjlljcjllljlilllllaljlljjl`mllljcillllclllllllllllcllclllciiilccclllclclclcclckaclccccccccclccccccccciiciciiciiciiciiiiii`ic`ii`ii`ii`````i`iiiiiiiiciiciiiiiiiiiiic`ibiiciiiiiiiiicicicicccicicicciciccccicccciiicccciccciccciiiiiiiiciccii`cicbicciccciiciclcccccccclcclcccccllcclllliclclcccccclcclcllclcccclcllclclccllc`lllcllcll`llllllcllllllilllllllclcclc", "jjjjjjjljjjlijjjjjjjjljjjjjjjjljjjjjlljjjjljjljljljajljljlljlljcljjlllllljlljijjlllllllllllllllcjcllllaclclllllcccclccclllccclcccccccccccccccccii``a`cccciciciiiiic`i`baba`iiii`ii```ii`ii`iiiiiiiiicciiccciciiiic`ia`iccii`c`iiciciccccccccbcccccic`iciciiiiccciccicicccccccccciiiiciccccccciccccccccccciicii`a``icccccccilclclciaa`iiccciclllcllclcllcllcccllllclllcllllclclcllllamiccaclllllccllllccllclcllcl", "ljjjjjjjjljjjjjjjjljljnjjljljljjljllcjljjjljjjlbjllblljljjjljlcljclljlljlljclikllljlllllllllllllcljclccccccccllclllllcccccclcclcccciccciccciabbkakbnaccici`iciiiiiiic`bbnnnnkbaa``iiii`ciiiiicici``ic``ciiiaiiiiiiiciiciciiiiiiicccciciciiccbcciiccccccciccciicicicicccccccccicccicccccccliccicliiccccici```iabkbaccccccccclccclciammnbbbaaicclcclclclclllllllllllclllllclllllllllccijlakillcllllllclllllllcjcll", "jjljjjjjjljjjjjljjjjjjjljjjjjjljjjjjljjjljjljljjljjijjljljl`liklljljllllllillljlllllllllllllllllllclllccccllccclcccccllcclcclccccccccciii`abnnbknmnmblciiibiiciicik`i`nbkmnmmnmnnk``i`niiiiciiiiciicccicccibciciiiciciccciciiciccicicccccccciccccccicc`ccccicibfcccccccicccccccccccccccclc`cclcclcci`abbbbaii`nnk`ccccccclllc`cciiknnnnbbakbkkicllclllclclllllclclllcllllclllllllllllclccllcllllllllkalllcljclll", "jljjljjjjjljjjliljjljjjjjcljjjjjjljljljljlljjjljljljlljlljlijblljljlljljllcjllllllliklllllllllcllllclccccccclclcccclccclccclcccclccciiaa`babnmnnmnnmkjiiccacciiiiiiiiakkknmmmmmnmnkkbbaiibciiccciciiccccccccccciciicicciccccccciicccccccccccciiiilicicccccccciiiilcccccci`ailciclcccclcccckbcllclciabbkkb`icianmnkcccclllclccccii`ammmnbabknkkaa`iillclllcjcclllllcllli`lllllllllclclllclllllllllllllljcllclllll", "jjjljjljlljljjjljjjjjjljcejjlljlljjjjjjjjjjjjlljjljljljljljllkijlllllllcjkllllcllllcallllllllllllclcclilcclclclcllcccllccccccccccc`bk```baabnmnmmmfmklciiciiiiiciiciiakbbknnmnmnnnkbbbbaknicciiiicccciiiccicciccccciicciiccicccccccccccccccccccccicililccccccciiccicccccciiclcclcccclilclliclccli`abbbnkkacciaknmkllllllclllcccii`amnnnnbbakbk`i`aaa`ccicclllcclcljclllclllllllllllllclllccllcllcjcj`alllllllcll", "jjjjljljljjjjjjjjljljjjjljjjjljjjjlllljlljjlljjlljljljlllllljilljllljlciacjlljb`llllclllcllllcclclllccciccclclcccclcccccclccllc`aabnkii`bbabbnnnnnmnbljiiiciiiiii`i`i`kkkbknmmmnmnnbbknkak`iccccicicccccccccccccicccccibccccccclcciccccccccccccciciicni`ccccccccccccccclcclccclcclacclcclclliiciabbbbbbnb`cc`bkknnlllllclcllccc`iiamnknnnkaaknaiiabbabbkkcccclccjcclllllllllllllllillllllcllcccllllccelllccclicl", "jljjjjjljjjljljljjjjjjljjjjjljbjljjjjjjljjljjlljjljljlljljjljljlllllljlllclllcjllllllllllllcllllll`ccilicccclclc`illcccccccci`bnbaakk``abbb``knbnmmkbllciii`i`i`i`i``akbbbbkmmnnnnbbkkkabnmnb`icccccccciccccccccccccccc`ccccccccciicccccccccccciccccciilcccccccclcclclclcclcclccclicllcllcc`aiiabbbkkbakacl`bnnknklccllllcclciiii`bmnknmmbaabka``akaaaakkicllclccibclllllllllllllc`lllllllcllcllllllcjlccclcc`ll", "jjjjljljjjjjjjjjljjljjjljlljjjljljljljljljlljljlljllljlljlcjllllllllllllljcjllmclllljcllllccllllcclcccccclcccccccccclccccciibnmmaaabbbbbbbb``bmbbnmnbljc`ii`ib`iikb``bnkbabbknmmmkbnnkbbbkmmkkaccccccccccccccccccccccclccccclccclcicccclclccclciic`lccciccccccccclclilccclcclcllcllllc`cc`abaliabkkkkkabiciabnmnfnlllllcllllii`i`i`nkbbmmnbbabaakbbba`iknbbbciclcl`llljcllllllllllllllllllllcllllclljclcclllclll", "jljjjjjjljjljljjjjjjlljjljjljjjljjjljljliljljljljlljlljllllllljljljllllllllcllallllclllllcbkbaclcciillclcccccccclcccccccciaaaknknbai`bbbbbbb`bmnkmnnalliii`i`aiii`ii``bbbbbbnmmnmmbkkkbbbbnmnnnbaiccccccccccccccccclcccillcccclclccllcclcclclccccclciliccclclclcclclcllclcclclcllcilclbaabb`icaakbbknkbaii`abknmnbclllccllllii`iiiibabbbkkkaa`abbbbkbaaknnkmnalclllclclllllllllllljllllllllccllclljlclclllclclll", "jjjljjjjjjljjljljlljjjljlicjljlllljljli`cccjl`cjljlljlllljllllllllllllllljcjlllllllllllllliclclclcmbclicccccccclccccccci`bkbbbbbbaaaabbkbbbbabnmfnbacljici`iiii`ici`iiiaabbbkmmnmnbbbababbnnmknnkbiclc`acccccccclccccclccclccclcllclccccccclccccccicllciccccccccllcclilccllclclclcjccababbicc`bbbbbkknbac`ababbaicllllllllllcii`i`iiiababbbaaaabbbkabbabnnnmmfna`acclclllllllllllllllllllllllllclcalllllclclllll", "jjjjjjljjljjjjjl`ailjljjjljjljjljlc`aabkbaba`aiclljllljljcb`ljlllllllllllclllclillllclllllcllclcililclkclcccccccccccccannbabbbbaaaabbbbkkkkbbkmnbiljlllciiiiic`i`i`iiillcakbbknfnkbbnbkbabbkmnnnknnbilccccclccccccccclcaacllcllccclclllcllclccccclclccccccccclllcclclbclclllcllllccl`aaabaicabkkbbkkknka``bkbbilljlllllllllcciiaaijlljcabaaaaaabbbkkkbbknmnnmnnmbillccjlllllllllljlllcllllllllllllllllclllccllll", "jljljljjljjlljljcjljjljljjlljljc`bbknnkkkkkkkbbbbbcjllljllllllllllllljlllllllllcclllclllllclllcacclcccclcliliclcclcc`mfnnmkbkkbaai`a`aakmkkbikmmlllljllciiii`iiii`iin`iljcbbdbnmnbbbmknnkaaakmkmmnbbbilclclclclcclclk`abilcaclclcllclcclicccccclillcccclilccclclllclllclllcclllcllibbbaaailiakkkkbbnkkk`bbbaballllcllllllcllci`a`lljlllcba`c`a`aakmbkbabmmnnmnnmbacllccllllljllllllllbjlljljllllllclllllllclllll", "jljjjljljjljjljjljljljjjjljjlc`akkkkbkmmnnmnkbkkbkb`cjjllllllllllllllcllllllclacjcllllflclllclc`cclliiicclccclciaciabkkmnmmkkka`cc`a`akbnkkb`knkjllljlll``iiii`aiiiiicccllakkkkkkbbbnnmnmkaabnmnkbbkkbiccccliacllillilccccllli`llllcllllcccclllcailllllcllclcclcclccllllclllllllliabka`i`clibbkknbbkknkbkkbbbillllllllllllllc```llllljjlb`cci``abbknkbianmnnmmnnnallilllljllllcjllljllllllcllllllllllcllllllijjl", "ljljjjjjljjljjljljjjjjlljljjibbkmnnkknnfffmnnknnnkbaa`clllllllllllllllllclilllllcccllclclcllccccccclcccccccclcic`cannbbmnnmnbaiiii``akkdknkaabmblljllllciiiabknmniiiiiijljannkkkbbbkkmmnmk``bbkkbbkkkkkaclcclclclclcllclbilcclllillllccllccclclcclcliccll`llilcclllllllclllllllliabba````ccabbbkknbbkkbknkbbbiljcljcljcbnkbabballlljlllc`iii`a`bkbbknbabnnnnmnnnnalcicilllllljllllllljclljljllljljjclllllllla`ll", "llljljljjljjljljjlj`ljljljlikbbmnfnnmmnfffmnmnmmmkkbkbiiljlllllllllllllciaiclcllllllclcllclccccclcccclcclaclcilc``bknnbkmnnnka`bba`adbkbbkbaabmkcljllllciicbnmnnkiiiiicljcanmnmnkkbbkmnnn`ibbabbbknkabknbclclllclllcllclcllllllcllcclllllilllilllllliclllllcjliccllclllclclllccci`aa`i`aii`bnkbkkkbabaakbnnkkacllllllc`knmkbbbbljjjjjlj``abba``bkkabkaaaknmnmnnnbacli`acllljllllljlllllllllljlbblljllljcllclabll", "jljljljljjljljjljjl`jjljjcabkkbefmmfnfefefffmffmfmfnkkbaillllljlllllcllll`llllllajiclllclcccccclcclcccccc`lciccakbbbknkbnnnmnnnnbaabbbbkbb`iadmmaclllllcclcaknkmmkiiiiicc`knkmmmbkbnnnnnbi`bkbbkbkbbbaakkaiclcclclllcclllcclllllllllllcll`ill`cllcllcllcikllillc`cccclclllllcciii`aa``iii`akkkkbaaaaiakkbknknkaallllcabkknnkabkallllllibkmka`aaabkbbai`akmmnmnnmballcibbillcljllllljlljljlllljcjlllljlllcjlllljl", "jlljljjjjljljjljlljljlajl`bkkkkmffffffeffefffmmfffmmnmkbbillllllllllllllcjcllclllilllilclcccccccllclcccccccclcakmnbbbbbkbkmnnmmbabnkbbbkk`cc`bmmmb`ciia`iii`aabnnmaa`c`abkknmnmmbbknmmnkbiababbbaba`ba`aakk`clclllllciccllllcllclllllllllclllllllllclllclllllllliclclcclcclli`aaaaaa`iclc`bbnnkbaiiiibnbnbbknkbb`ccci`knnknnkbbbb`cjjikfmnbabnnbakkk`li`knmnmnnnb`icccaabclilljll`llllllllljllcljlljlljlllllljal", "ljljjllljljjljljjjljlabliakknmknmfffefmffefefffffffffnmkkailllllllllllialclcllilcllc`jicccccicccccccclcccciccbnnknnkbbkbbknnnmnbbkmmnkbbbiccabnnmmnknkb`ccii`abmnbbbmknnmmnmmmnmkbkkfmnkaa`aabaaa``ia`akbbkkacllccllliillllllllljiaaillclllclllcclllllllllllllclclllllcllcciaaabkbb`iicciabbkkba`iiiaknbmkbbkkbabknbabnknkknmkkbkabbkmnknnabnmmkbbbbiliabnmmnnnnbbaicii`akallllljilljjllllicljjlljljcljljllllcbl", "jljllllcjjljljljlljlljllbbnnmmffffeffeefeefefeeffmmefmmknkbclllllllclllclllclclccccccicccicccclcccccccccclccbnmnnnnmmnbbbbbmnnkknmnnfnbb`i`aabnmmmmnnnbaiii`abbkkbkkknkmmfkmnmmmnkkknnmnaaabkkbaaiii`bknbkbkbcllclclclblllclllllllllllllclllllllcjllclcllllllllllllllllllliabbaaaaa````a`abbkba`a```abbknnkbbbkknkkk`bnmnmnnknnmkbkbabnmnnbnmknfnka`iiaabnmmmnnnnbaci``aabkaljllljlljcljllljllllljlliljlljlljjll", "llljljjjljljjljljljjljc`bkbmnfffefeeeefeefeefffeefffmmnnmnkaclllclllclllllclccccccclccccccciccccccliccclbccanmnmmmnknmnbkbbkmnnnnfmmnmnbi`abbaknmnmnnkb``iai`aa`aabknmmnmnnnmnmmmbkbkfnnkbakmnabaabaabnakbbkbbilllllllllllllllllllllllllllllllllllcjallllllllllllllllllllinkbabbba`iaaaa`akbb``````abbbbkfmbabnmmnbakknmmnmnmnnnmkbbbbknnnnnnnmnnmbiiabbakknmmnnkb`````iaa`ailjlljljlljlljlljljlllljljljiclllljl", "jljljljljljljljljjllljlbknkfnffffefeeeeefeeeeefeeeefffmmnkkbillllllllllclijcclclclccclclccccccccicinacciiibnmmnnnmnnnmnkbkbamnkmnmmnmmnabdaabbbbmmnnnba``iaii``ii`bnknmnnmnmmmmnnkkbbknmmkbknnbkkbbbabnbbkkbbnaclllllllllllllllllllllllclllllllllllcllllccclllllliclllllikfkbaaaaa``aba```baa`a`aaaabbbbkmnnknmnnkbbknnnnmmmnnnnnnnkbbbknnnnmmmnnnabaaakabbnnmnnba`````c``i`iicjlllljllllljllllijjcjlllllcjjjllj", "lljljjljljljljljlcjjllkbknmfnffffeeefeeeeeeeeeefeeefffffmnkkbclllllcl`llllccccklllclclcclcccclcccccilccccbmmnmmnmnmnnnmmkkbbnnnbknmmnmkkmkaabbbaknnkkbaa```c``iiiabkbmmmmnmnnnnmmmkkkkknmnbnmkbkkkaa`bbbbbkkbnkacllljcllllllllllllllllllllllllllllllallllllllllll`cjlljlabkbab`aaa`iaba``abaaaa`aabkkkkkknnnmmnkbabnnnnnnmnnnmnknmnmkbbbnkkbnnnnnkbnnabbbbbbnnnkkaaiii`iaiciaailjjlll`bialjlljjclljljajjljjlljll", "jlljjljljjljlljlcjllljanbmmfnffefeefefeeeeeeeeeeeeeeeeffmfnnk`clcllllaclllcclllclcllccciclcccccccccclicc`mmnnnmmnmnnnknmfbbbbdba`abbdbabkaaaabkbbnnnkbaa``ic`iiiaaabbmnbkkbbdbbkbbabkknmnmkmnnabkkbabbkbkbnkkkbb`llcjllllllllllljllllllllllllllllljlllclllljlllljlllcjl`kbbbbbaaaa```a```abaab`ii``aabbabbbbbkkai`bmnnmmmbbkbkmnnnnmka`aaa``aabbbbaknbabbkbbknmkb``a`ii``iiiaaacllijlcklllbljlljljlljijlljla`ljj", "ljjllljljljljlljljjljibbknffmfeffeeeeeeeeeeeeeeeeeefeffemfmnkbclllcllclcicbcclillccccclcccccccccclcciclinmnnmnmnnnmmnnnnnnkaai``lllllcllllcllc`abknmnac`i`clclliaaaabnalllclclcclcllcc`kmmnnnkbbbkbkknkknkkkbbaa`iccclljlllljllllljllllljllllllllacljljlllllllllljllcliabnnbaaabbaa``````aababllllllcllllcllcciii`bnnnnnncllllnnnnnnnilcllllllcllllciadkbkkbbnnnb`i``iciilc`aaaaclealljllcecllljjjljljjljljjjjll", "jjljljjjlljljljlljllclbbmnmffeefeeeeeeeeeeeeeeeeeeeeefefffmkkb`lclcllllclicciclccclccllccccccccccicccciknmnnmnnmmnnnmnnnkmnbiia`lllllllllllllllliaknnb`i`aclllli``i`abilllllllljllllllliknnnnkbbbbbbknnnkknkbkaiiaillljlllllllljlljlllllllljllllcjjlllcllllllljlllljlcabbbba`babbba```iaaaakkbllllllllllllllclicadkmnmnknlllllmmmnnnmijlllllllllllllccibbkkkkbknna`i```icli``i`aaclljjljljlljjlllljljlljjllllllj", "ljljljllljljljlljifccibbmmfffeffeefeeeeeeeeeeeeeeeefefeffffnknaccclccclcccicclcllllclcccccccccccccccccanmnnnknnmnnmnmmmnnnnbi`nilllcllllllllllllliabbkb`aacllll```iiabillllllcllllllllllibnmnnbabbbknnnnnnknbkaiib`ijljcljlljljllllcljcljlllljll`cjlcjjlljllljlllllllibbka``bbbkbba`i``abbbknbcclclllllllclllllladnnnmnnncllllnnnnnnnallllllllllllllllc`bkknbbakbbaaaaaiiii```ciaalllllljljljljjjl`jljllljjjjjjl", "ljljljl`llljlljljlcclaakmnfffffeeeeeeeeeeeeeeeeeeeeefefefffmnnacccccllccilcclclccci`cclccccccccccccccinknnmkkmmknnnnnmmmmnbaaakicclc``ai````illlllibbaabaalcllc`aai`abilllciada```aicllllannnmkbbbknnkkkkkbnbk````aklllllljlllllljlillijllljlllljlllllcjlljllllljljllbknbaa`kkbbkbai``abbbbbnbilclcccici`icccccllaknnnkkn`lclcknnfnmndlllc`````aaaaccclldbnnbbbabbaaaa`a`ai`aaiibb`jlljljllljljlll`ljljjjjjlljlj", "jjljjljcjljlljlllllllcbnnmneemefeeeeeeeeeeeeeeeeeeeeefeeffmmnbbiccciccccccclcclcccccccccliclicccccicibknnnnnnnnnmnnnnnnmmkabbbbiliclnmmkkkbbkalcclcbbbbaaallllc`ab``abcllllaknffnnnkalllllnkmnbkbbkkknnkkkkkbb```i`alljllllljlljlllilljlljllljlljlllljllljlljljlllljakbkkkaabnmbababbbbkbbbbkacllccciiii``aablllccnkknnnkillcldnnnmnmblllc`kkkknmmnblcillbnnkbbbbabba```aaaaaaa`aabcjlljljljlljljjljjjljlljjjljj", "lljlljljlljljlljlllllibnkmnmffefefeeeeeeeeeeeeeeeeeeefffeffmmkkaccccclcillcllclclccccccci`icicccciciakkbknkknnnnnknnnnmnnbadbkkilclcnnmkkbbkkbllllcabbkabblcllcaabaabkilcclakknnnkbkbcilllkbbbbbbbbkbkkbkkbbbaa`iaaaallljjllljljljlclljlllljlllllljljljlbcjllljljjj`nnkbknbbabkbaabkbkkbbbbbbalcllcciabb``bnnilclckkknkkniccccannnnnnalllc`bbbbnnmmnillcldbdnkdabbbbaaaabaabab`aabb`ljlljljljljljljljljjljjljljl", "jjljllljljllllccjcljlcbmknnnfefeefeeeeeeeeeeeeeeeeeeeefffemmnkk`cclccli`clbcblilccccccccciccccciial`kkkkknkknnnnnkknnmnnbdaabbkclllcknmnkbkmn`cclliaabbbbbcllclabkdaabilllcbkkkmnkakaliilibbbakbbkbkkbbkkbkkba``ibbaailllljlllllllllljlljljlljljlllillllljlljlljllcaknnbbkkbaaa``abkkkkbbabaa`cllcci`abkkabkkclllcbkknkknilllcannnnnk`clcc`bkbabmnnkllccldkkbkb`abbbbbkbbbbbbbbaabknajljlljljljljljljjljljllljll", "ljlljjjljljljlccjlllccamnnnnfemeefeeeeeeeeeeeeeeeeeeeeffmffmfnbacclclllillil`cclcclccccclccccciia`canbkknnnnmnnnmnnknnmkkiidnbbclccl`aa``i``illclc`abbbkkbcllllbbkb``b`llcl````a`a`illicl`bbbbkkabbbbbabbbbkb``i``aaaalljlljjljjljljllljljlljllljlcalljlljllljlibjcbkmkmkbab``iiabbbkbbkbabbaailllcci``iii`icllcl`kkknnnm`cllcannnnnb`lllli```i`ab`ccllccnfnnkdbabbbbkkbakbabkbaiabnkijjljljljljljljjljljlllljlj", "lljlljcjlljlljclclljclamnnknnenefeeeeeeeeeeeeeeeeeeeeefemffmmnb`clcllcllcclccclicccccccccccccciiicinnkknknmnnnnnmnmnnnnkbcc`mnklccllllcllllclccll`kkkkbbkkclclcbbkbaabillclcclllclllllllidbbkbnkbkbbkkbkbbkbaii`aiabbklljlllljlljlllljljlljljljlljlcjljllljjjljljlbbannnmba`ii`akbbbbbbbbbkaad`lllclllllllcljlllidmkbnnmn`cllcannnnnb`llccclllllllccllcldkmmnnmkkbbbbkbbbbbbbbbb`babkaljljljljjljljjljllljljljjl", "jjljlljljllljllljjcc`l`bnmnnkeffefeeeeeeeeeeeeeeeefeeeeemffnnnb`llclccccclccclciclccccccccicccciccknknkkknnkkkbknnnmnmnka``dnkkllclccllllllcllll`kmnkkbkkkclcllbkabbabclllllllllljlllllibkkabbnkknkbbbbabbkbai`aa`abkkbjljljljljljljljljljljljljljjlljljjlljlicjliakkkmnnkkacc`kkkkbbaababnkabalccclllllcllllllcdnnkkmnkkallll`nnnnnballiclllllllllllll`akkkmmnnkkbkkbbbabbabbbabbbbmnclljljljljljjljljljljljjjj", "alljaklllljlllllllllllibknmnneefefeeeeeeeeeeeeeeeeefeeeffmfnmkbicccllclllclcliibcccccccciciiiiiic`nmnnnknnnbbbbkkknknmnkbbkkkbdccclcccllcijcjlcbnmnmnbbkbklllllbkbabbbilcclclllllcllc``kknnbbbkknmnbkkbabbbaa`aaabbabkncljlljjljllljljljljljlljljljljlllljljljjllkbbaannkknac`bkkkkkbbbbbknkbb`lclllllllllcllcibnmnkkmkkb`ccccannnmkbkllllclllllcllllidkbbknnnnnnkkbkkkbbbbbbbbaabbkmmaljjljjljjljljljljjjjjljjl", "ljjl`ajljlllljlljllllliinbmnmmefefeeeeeeeeeeeeeeeeeeeeffmnmnnkblclccclccclilillccccccciciciiiicccamnmnknmnkbknnnkbbkkmmknmnmkballclc`aacl`ccibknnmnnmnkbbkclcclkbbbbab`lllc```aaab`iakkkbnmnkbbkkknbbkkbkbaii`babbbbakb`jlaaljllljljljjljljljljljljljljjjlljjljj`nkbbabkknk`cbkkbbkkbbabnkbbbb`lcllcaailllll`bbmmmknnnkkballlcibkkmnnmllclci`iiaaabbkknkbkbnnnnnnnnbbbbbbbbbkabbabkmnmmcljljljjljjljlljljljljjjj", "lllljljlllbllljllllllllcaknknmffeffeeeeeeeeeeeefeefeefemmfnnnkacclccclclcccccccccccccccccciii`ciabnmmmnnnnbknnmnmmnkkkknnnmkdballcclbmn`llcll`nknmnknkmnbdlcllcbkbbbbk`lcllkkkknnmnkbbknbnknkbkbnkbbbkbakkaiabaabbbbbbabjljcljljlljjljljljljjlljljljljljljjljjclannbbaanbkacikmnkkbbkkbbnnnkbaacclcibbbilcclcaknmnmknmkbbklllccmkkbnkmclclcai``abbnnknnnkbkkknnnnnknkkbbbbbabkbbkbknmmkaljjlljjjlllljjjjjljjajlj", "jljljccjllljllllljllilll`bbnmmfffefefeeeeeeeeeeeefffefenmfmnkbiclccclcccccccccccccccccccciiiiiii`bbknnnnknbbmnmnnnnnnkkkmnkaad`lcllcbkmk`cllll`knmnmnknnnkllllinbbkmnn`clllbnkknknnnkkkkbknnnkbbkkkbkb`iaba`abbbbbknnbbbllilljllljljljljjljjljljljljljjljjlljia`bnkbb`akab`aaknnnnbkbbaabnnbbbdllliibbbailllclabnnnmkbkkbkclcccmnnkkkniclcl`i`akbbknknknnbbkknnmnkknnkbbbabbkbbnknnnnmnnljljjjljljljljljjjjljjlj", "klljljjclljlljllllll`cllcakbmmmfefmffeeeeeeeeeeeeefeeffmmfnnbailclccccclccccccccccccccccciiici`iabbbbkkbkkbnmnnknmnnnnnkkkbdab`lcccibknkn`clillakmnnmnkkmkllccinmnknmncjcccknnkkknmmnnbbkbnknnbbbkbabaciaaaabaabaknmnnbbilijljljlljjljjljljjljljjljjljljljjjljjaknkbbaaba``bknnnmnkkbbabbknkbbblllccbbbbailllcc`bkbkkbkbkklclccnnmnnknillcc`c`abbbknnnnnmkbkkknnnnnnnnnkmkbkmnknnmnknnmm`lljjjljjljljjjjljjcjljj", "ljlllllljlcljcllllllillll`bbkkmmfffffefffeeeeefeeefefffmmmnkb`ccacclcliccclccccccccicciciiciciaibbbkbkbbakbmmbnnnknnnnnnkkkbbaiclllcbnmknncllllldmfknmnknkllllikbknnnniilllknnkkknnnmmnbkbnknnkkabbbaccaaaaabbabknnnnnnkallljjljjljljjljjljjlljljjjjljjljjjljlcbknkkkbbda`aknnnnnmnkbbbbbbbkbbalcclcknkkbaicllil`bkbbbkdmnlllclnknnnnk`llclii`bbabknkkknnbbbkknnnmnnknnnnnnkbkkknnknnmkkbjjjljjjljljljljjjanjjjj", "llmjjljllllllilljlllllllllikbbnmmmfffffefeeeeffeefffmffmmnkbaicclcccccclccccccccccccccciiiiicc``bbkkknkbakbnnknknnkkknnnmnbbbaclcccibnmnmnncllclldmnnmnnnnllclckkkbkmmilllcknnnnbkknmfnnbkknkknnkabaic`bbbabbbbknmnknnnnkljjljljljjjljjljjljjijljljljljjjlljjj`ikkkbnkbaaadnnnkknmmkbbbbbbbkbballlclbbbbbabclllcidnkbbbbnmlccilnkkkknn`llccciabaabnmnnkmnnbbbbnknmmnkkkknmnkbbkbbnnnmnnnflljjljajljljjjjjljjjjjj", "illllllllljllclllllllclllll`bbkmnmmfefeffeffefefmeffmffmknkaiclcclclcccccccccccccccicciciicici`aabbbkknkbabknnnkkkknkkkkkknkb`clcllibknnnmkkcllllcdkmfmnnkllllcbbbbabbclcllknnnnkkknnmnbbkkmnknnnkb`c`bbkbbbbbbbknnnnmnknlljljjljjljjljjljjljcjjjjjjjjljljjjllibkkkknnbaabknmnkkkkknkbkkkbbkknklcclcbkbbakdbilllliakkbabkncllllnnnkknkalllliiaaabbbnnnknmnkbbbkbknmmnkkknkbbkbbaabbknnkkniljjjjljjjljljjjjjljjlj", "lcljlljlllllljlllllllclllillabbnknmmfmfffffffffffmefmnnnkkaicclcilccbcccccccccicciccciciiciiii`babbbbbbkkakkkmnnknkkkkkkknmnda`clllibbbbbakbacllcl`knmnnnklllc`nmb``bbcllclknnnnnnkknnkbbbknnkknnmna`bbbkbbbbbabkknnnnnnncjjjjjjjljjjjjljjljjjljjljljljljjljjj`anknnmnbbabknmmnnkabnnknmkkbaknkcllllbbkbbakaaillclibkbbbbkiclcckkkknkkaclll`bbkkbaabbkabkbbbabbkkbnmmnnkknmmkkkb`abbkkkbkbjjlljjjljljjjjjjjjjljj", "cbjcjllljlllllllllllcllllllclcbbkkmnmnffffffemmmfnmnmknkkbiccccclccliclcccccccciccciccciiiiciciabaabaaabkbnkknnnkkkkknnnknkdakndbkbabbbbbnbkbbaaa`bkbkmfnmbkkbbnna`ammakaaamnnnkkkkkknnkkakknkkkkmnaabakkbbabbbkknnnnnnmkajjljljjjjljljjjjjjljiljjjjjjjjjljjcccknknknnbbdknnnmmnbbbknmmnnnkkbbbabababbbbbkkkbaaa`aiabakdnkdbdbbkbkkkkkkab``bnnnnbkbbbbbbkbkkbbabbbbnnmknnmknmmm``bnmkbkbknjjjjljjjljljljjljjj`jj", "lljljlllllllllllllcllllllllllc`abbkknkmfmmfmfknfmmnnnkkba`cclliliccccncccccciicciccciciciiiiii`bbkbaaabbkbnnbkmkkkkkkbkbkkd`bknknnmnkabbnbkkbknbbbbbbbknmnnnnmnbkiannmnnnknnmnnkkkkkkkknnkkknnkknnnbbabbbkbbbbnkbknnmmmmnbcjjjjjjjljjjjlj`jjjlljjjjllljljljlliiknnnnnnkkbkknknfnkknknnnmmnmnmkkbbknkbaabbnknkbbbbaa`bbkbnkbkmnkkkkbbkbkkaabmkknnnnbbakkbkkkkkbakbbbdbmmnmkmnkbbcdnnmnknbkma`ijjjjjjljjjjljjjjljj", "ljcbaljllllllllllclllllllclcllcci`bbnbkbnknnmkknkkmkkba`ilccilcclcicl`cccciclcliccicicic`icici`nkkkbaabbkbknkbkfnnkkbbkkbbaannknnnnnnbkbkmkknnkkabaaabbbknnnnmfnk`annnmmnnnnnmnnknnknkknnkkknnnkkkkkkbabkkbbbbbkkknmmnmmfkjjljjlljjjlcljjljjjljjljljjjljjlljii`nknnnmmkbbbbnnnmnknknknnnnnmnmnnnkkkkkbaabkmmnbbnbbaabbkbkkkkknkkkkbkkkkdabknknnnnnnbbbkkkbkkkkbaadbbbkknkkmmfkkibnknnnnknmajjjljjljljljjjjjjjjjj", "lljci`cjlllllllllclllllllllccllllc``bbkkkkknknnkbnkba`icccccc`ccccccclcccccccaciciciciciiiiiiiankkmkbbbbbkbbkbbknnnnnkkkbaaknkknnnmmmkbbbnkbknkkbbabbbbbbkmmnmmmb`kmknnnmnknknnnkknnnnknknnkkknnnnkkmnkbbbbbkbbnnkkmmnnnnmjc`ljjjjjjjljjjjlj`jljjjljljjlljlj`c`nnknnnmkbbaabkbbknmnnknknnnnnmnmmnkbnkbbbkbnmnnknnkbbbbbbbkkbknnnnknkbkk`akkkknknnmnnbbknkbkkkkbaaabbabbknmnnmnk`kkknnnnnnbillljjljjjljjjjjjjjljj", "jlljcillllllllllclclllllcllllcccclcliiaabbbbbkbabaaiiiiccccccacccclciciccccciaiccicicicici`iiibnnkfnknbbbkaaknkbnnnmnnnkkbknnnkknnnnmkbbbbkbbkkbaaabbbbbbknmnknkbbknnnnnmnnnnnmmnnknknkkkmnnbkknkkkknnkbbbbkknbkkkknnnkknfjjjjjljjlljjjjljjj`jjljljjlljijjjjccaknnkkknnkb`iaabknnmnnnnknnnnnnnnnmnbkkkabkbknmnkkfnkkkbbbabbbbbknnmnnknkaknknnkknnmnnbbbbkabkbbbadaabbaabnmnknkkaknnnnnnnnfkljcjljljljjjjjjjjjjjj", "llllcjllllllcllllclllclclclclclcccclclcliiiai``icccccccccccibcccccccccccciciiiiciciciciciiiciinmnkmmnmkkbbbbbabbnnnmknnnkkknknnnnnnnnkkbabbbbkka`aabbbbbabnnnnkknnkmnnmmnmnnmmmnmmnnkkkknnnmkbkknnknnnnnkkkkbmmkkkkkkkkkbnjjjljjjljjjljljlljajljjjjljljjjljjjc`kmnnkknnnba```akmnnnnmnnnnknnnnnnmnkkkkbbkkknnnmknmmmnbbbkbbbbbknnmkknnkknknnknnnnnkkkbabbbbkkbiabbbbbbbdnnkkmbknnknnmnnmkmbjinijljljjjjjjjjjjjjj", "llljllllllllllllccclllcllclclllcllcccccccccclcccccccclcccccc`lccccicciccciccicciciciciiiiii`ickmmnmnmnbbbbbclciicccilcciliiilciccicccccclcclicllllcclcccllciiciciiciiiiicciiiicci`iiclliiiciiccciiiicciiiccccamknkkbkbkkkblljljjljjjjjjjjjjljljjlljjljjjjjjlllinmmnnnknmkaacccciiiciiiiiiiciiiciiiicccclciiicc`cciccillccclclciiciclicliicccliiciccccccclccccllllciccccliiciiiakkknnmmnmnnkciijljjjjjjjjjjjjjjjj", "ljlcljlllllllllllclllcllllccccccccclccllcccccccccccccccccccclccccccccicccicci`iiciiiicicii`a`ikmnmmmnkbabbijjjjjjjjljljjjjjljjjjjljjjjjjjjljljjjjjjjjjljjjljjjjjjljjljjjjjjjjljjjjljjjjjljjjljjjljjjjjjjjjjjjinnnkkbbbbbkbjjjjjjlljjjjjjjjljjljljjljajjjjjjljccknnnnknnmkbacjjjjjljjjjjljjljjljjjjljjjjjjjjljjljjljjjljjjjjjjjjjjljjljjjljjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlikkbknnmnnmkncjljjjljjjjjjjjjjjjjj", "llllllcllllllllcclclclclccllclclclcclcccccclilccccccccccilicciccicccccciciciibiciciciiciiia``immmmnnmknnkkillljcccjljclljlllccjijljcllljljlljjljljjljlcjlllllllllcllljlcjljjljllljjlclljllilljllclljlcicjclclcknkkkkkabbbkljjjjljjjjjjjjjjjljjljjjjjjjjjjjjjjcianmnnnknmnbacjllclcjcjcjcjllllllllljllllccjlllllljljllcjjllllljlljljjljljjjjlljjjllllllllcjllljllclljjllljljjllabbbbbknknmkn`jjljjjjjjjjjjjjjjjjj", "lllllljcllcllllccclllclcclclclclcccccccccmkcccilccccccccccccccicccciccccciciiaiiciiiiiiiciii`immmnmnnmmnnkclnmfffffffeeffmmffmmffmfffffmmffffeffemfffffmmmffffffffffffffffmmmffffffmffmmfffffmffffmffmmmmffmmkkmnnkbbnkabkjailjjjjjjjjjjjjjjjjjjjjjjjljjjjjjlcibknmknnnnmkdidkkkmnnnnmmmnkknkkkkkkkknkkkkkknknknnkkkkkkbkbknknnkkknnkkkbkkbbbbbkkbbbbbbbbnkkbbkbkbbkkkabbkbkda`dbbbbbbkbnmnljljljjjj`jljjjjjjjjj", "jlllllcbccnnclclllklclllllcclcclcllccclcciclclciccccccicccccicaiccccciciicciciciiicicicii`ii`innmmnnnmfnmnilmffffeffffffffffffmffmmffffmmfffffffffffmfmmmmffffefffeffeffmffmmmfffmmmffffffffffffffffffmmfffffnbnnkkbbkkkbaljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlcibbmmnknnmkka`bnknmmnnnnnnknnnkkkkkbkknnkbkkknknknnkkkkkkbbbkkkkkkkkkkknnkkkkbbbbkbbbbbkbbbkkkbbbkkkkkkbbbbkkbba`bbabbbabaknniljjjjljjjjjjjjjjjjj`", "c`iljllllliclclclkicllicllccccccccccccccaaiciclcccciclilcicccc`cciciccciciiaiiciiiciciiiii`i``nmmnkknmmmmmilmmmfffffmmffffffmmffmfmmfffmfmmfffffemmffffmmfffffffffffffffmffmmnmffmnmmfmmfeffffffffefffmmfffffkbknnmkbbknkbljjjjjjjjjjllcjjjjjjjjjjjjjjiljjjjliibknmkknnnmnnabkkkmnmnkkknknnkkkkknkkkkknkkkbkknknnkkkkkkbbkkbkkkbkbkkkkkkbkkbbbbkbbbbbkbkkkkkkbkbkbkbkkbbbkbkba`bbbbbbaabkknbjljjjjj`jjjjjjjjijjj", "lljlcclllllllcccclcllcllccclclcccccclccccccclciccccccciccciccaccccccicicciibiiiciiiiiii`i``i``nmnnnkknmmmnicffffffffmmmmfffmmffmffmmfffffmmmffffffmefefmfffffffnfmmmmmmmmffffffffmmmfffffffffffmefffmmffffffmnbbnnmmkbbbknjjjjjjjjjjjjjjjjjjijjjjjjjjjljjjjjliidbnmnnnknmnnaaknmnnnkkkknknnkkknkkkkbknnknkkbbkknnkkkkkkbbnkknnbbbbkbkkbbbkkkkbkkkbbbbkkkkkbkkbkbkkkbbkbkbkbkkaiabbabkkkbbbbajjjjjjjbljjjjjjjljjj", "llllllllcjccjlcllcclalccclclaccccccccccccccccccccciccicicccicbcicicicicicic`iciiiiiiii`iii`ii`nnnnnnknmmnmccmffffffmfmfmffffmffmfffmfeffmfmmffffffmfffmmmmfffffmmmmmmmmmmffffefffffmmffffmfffffffffmmfffefffmnkbkkmmnkbbbkjjjjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjci`bbkmmnkknnnn`annnnnnnnkkknkkkknkkkkkkknnknbkbkkkkkkkkkkkkbnkkkkkbkbbbbbbbbkbknnkkbkbkbkbkbbbkbbbkkkbbbkkkkkkkbbibababbkkkkba`ljjjjjjjjjjjjjjjljjj", "llllllcllclliccclllclccllccik`lc`ccicccccclccccccccciclccicccciciciciciciiccciiiciiiiiiiii`ii`nmnkkkknnmnnlcmmmmffmfmffffffmmffmmfffefffmffmfffmmmnmmmmfmfffffmmmfmmmfmmmfffffmmffffmmfffmmfffffffmmmfffmefmnnkkbbknnnkbabjjjjjjjjjjjjjjijjjjjjjjjjjjjjjjjjjlc`kkkbknnnkmnnaakkknknknnkknnkkknkkkkknmnnkkkkkkkkkbbkbbkkkbkkkkkbkbkbbbbkbbbkbkkkbkbkbkbbbkkbkbbkkkbbbbkbbkkbbba`abbbaabknkkb`ljjjjjjjjjjjjjjjcjjj", "cllcclllllccccclclclccllcclliccciclcccccciccciccicccicaccciciciiciciciciiciiiiiiiii`i`iiiiiiibnmkkkkkknnnmcifmfmmmmmfmmffffmfffffffeffffmffffefmmfmmffmfmfefmmmmmmfmfmmmnfmmmmnmmffffffefmfffmfffmmmmmmnmfmnmnbkbbbkknnnkbljjcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`bmbbbknmkkkkbannnknkkkkkknnnknnnkkknnnnkkkknknkkkkbkbkkkbkbkkkbbbbkkbkkbbbbbbbbbbbkbkbkkkkbbkkbkbkbbbbbabbkbabb`abbbbaaabkkkbljjjjjjjjjdcjjjjjjjj", "lccllcilclllccclllclcccccccclcclccccc`biccccccc`ccicicfiiccciiliiciciciiciiciiciiii``iii`iiiibnmmnkkknnnkklcmmmmmmmmmmmmefffffefffffmmffffmfffffnfmfffnfmfffmmmmfffmfmmmffmnmmmmmnmmfffffmfffnmfnmnmnnmmmfnmfnbkkkkkkknnnmljjljjjjjjjjjjjjjjjjjjjjjjjjljjjjjlciamkba`knnnnbb`nknkkkkkkkkknmkknmnnnkkkkkknknknknnkkkkkknkkbknbbbkkbkbbbbbbkkbbbbbbbbbbbkkkbakkbbbbbbabbababbbbb`aba`aaaabbbbbjjjjljjjjjjjjjjjjjjj", "lclccc``cllccclclccclccclcccccccccccccccbaiccci`cicicciicciciciciciciciiiiaiiii````ii`iiii`i``nmmnnkknnmnklammffmfmmmmmmmmffffmffffffffeffffemmmmffffffmmffmmmmffmffmmmmfffmmnmmnfmmmffffffffffmmmmnmnmmmfffmmnkkkknkbkmnnjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjcccbnbbabbbnnknn`nnknnkkkkkkkkknnnkknnnnknkkknnkkbkbbkkkkkkkkkkbbbbkkbkbkbbbkkkbbbbbbbbbbbkkkkbkkkbbbbabbabbbkbbkbbbnbi`ii`abkbbjjjjeajjjjjjjjjjjjjj", "ccllllcclclcclcclcllcclccccclcccccccccciciicicccilckciciiciciciciiciiicicii`i`iiii`iiiiii`ii``nnmnnnnnmnnklammfffmfmmmmmmmffmmmmffmfffmfffmffnmmmfmfmfmmnmmmmmmmmmmfmmnmmmmnmmmmmmmnnmmmefffmnmfnnnnmnnmnnffmmkbbkkkbabmnkljljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl``abkbkbbbknnmm`knknnknkkkkkkknkkkkkkbkkkkknnnknbkbbkkkbbbbbbbkbbbbkkbkkkbbbbbbbbbbbbbbbbbbbkkkbbbkbbbbabbaabbbkbaakbiiii`aabbkcljjjjjjjjjjljjjjdkj", "clllclclimalccllcclclcccclcccccccccccccccicccciiiciiccicciciciciiciiiiic`iakciiiiiiiiii`ii`iiakmmnnnnnnmnkjanmmfffmfmmmnmmmmmnmmmmmmmmmmfeffmmfmmffmmffmmmmmmmmmmmffmmmmmmmmmmmmmnmmmnnmmfffffmnmnmmmnmnnmffmnnbbbbbbabnmmcjjjj`jjjjjjjjjjjjjjjjjjjjjjjjjcljlii`knkbbbkkbnnn`kknnnnkkkkkbkknkbbkkkkbbkkbknnknkkbkkkkbkkkbbbbkbbbbbbkbkbbbbbbbbbbbbbbbababbkbkbbbbabbbbababbbbb``ka`icc``aabkljjjjjjjjjjjjjjjjjjj", "lclcllcccclcllcclc`kcclcclccclcacicciliccccccccccicciciciciciciciiiciciiii`i`iiiiiii`iiaiii`iakmnmnmnnnnnblbmmfmfffmmmmmmfmmmmmffmmnmnmfmffmmmmmmfmmmffnfmmmmnmnmmmmmmmmmmmmmmnmmmmmmmnmmmmffmmmmmmmmmnnffmfmnnnbbbkkbbbbbcjjjjiljjjljjjjjjjjjjjjjjjjjjjjljjlc`aknnkkbbkbbbk`knnnnnnnkkkkkkkkkkkkkkkkkbbkbnkkkkkbkkkbkkkkbbkbbbbbbbbbbkbbkbkbbbbbbbbbbbbbkbbbkbbababbbbbbbbbkba`bb``lciaabkncjjjjjjjjjjjjjjjjjjj", "llllllccccllcclccccciclccclc`iliccclccicicciiicccicciiciciiciiiiciiiiiii`iicii`c`iiiiii`iii``annmmnnnmnnnbjbmffffmfmmmnnmmmmmmmfmmffmmmnmmfmmfmmmmfnmfmmnmnmmmmffmnmnmmmnmmmmmmmmnnmmnmmfmknffmknnmmmnmmffffnmnnnkbbkbbba`ljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`annnnnkbbbb`aiknnknknkkkkkkkkkbkknkkbkbkkbkkkkbkkbkkbbbbkbbbbbbbkkkkbbbbbbbbbbbbbbbbbbbbabkbbbkbbbbbabbbakbkbbbb`kbailciankkn`jjjjjjjjjjjljjjjjjj", "clllccllllccjcilccllnacllicanaclccn`ccikaicccciicci`cciciciciciiii`iiii`ib`iiiciiiii`iiiii`i`knmmmnmnnmmmblkffffmfmmmmmmmnmmmmmmmmmmmmmnfmfnmffmmmmfmmfmmmfnmmffffmnmmmmmnmnmmnmmmnmmmmfnffffmffmmnmnmmfffffmnnnnnkbbakn``jjjjajji`jjjjjjjjjjjjjljjjjjjjjjjjl`i`nnnnnnbka`ciinnnnnknkkkbkbbkkkkkkkbkkbkbkkkbkbbkkbbkkkkbkkkkbbbnknkbbbbbbbbbbbbbbbbbbbbbkbbbbkbbbbbbbabbbkkkkka`kb`clciannkk`jjjjjjjjjjjjjjjjjjj", "clclcclccclicllclcccacciccciicciicacccli`cccccccicimiiciiiciiiiii`i`i`i`iicii`iii`iiii`ii`ii`knnmnnnmmnmmblkmffmfmmmmnmmnmmmmmmfmnmmnmfffmfmmfmmmmmfmffffffmmffmffmnmmmmmmmmmmmmmmmnmmfmfmmmmmffffmmmnmffmffmmnnmnnkbbknblijjljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiannnknkbbi`ciinnnnnkkkkkkkkkkkkkkkkkkkkbkkkkkkkkkbbkkkkkknkkkbkkkkkkbbbkbbbbbbbbbbbbbbbbbbbkkbbbkbkbbbbbbbbkbbbbibbicci`kknnnajjjjjjjjjjjjjjjjjjj", "llcllclclcjcccclclcclcccbcccccccccicicicccciciiccccicciiciicicii`iii``iiiiiiicii`a`iii`iiiiiinnnnnmnnmnmnbjkmffmmmmmmmmmmmmmmmmmmmffffeffnmmffmmmmmmmnffmffnmffmmmmnnmmmmmmmmmmmmmmnnmmnnmmfmmmmmnmnnmmmmmmmmnmnnmnnkbbba`jijjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjl`iaknmkkb`iiii``nnnkkkkkkkkkkkkkbbkkbbkknnmnkkkkkkkbkbkkbbbkkkkkkknkkkbbbbbkbbbbkbbbbbbbabbbbabkkbabbbbbabakbbbbbb`ab`````nnnkk`jjjjjjjjjjjjjjjjjjj", "lcllccccccclclcccccccccciccccccccccccicciciccciciiciciciiciciiiiaiia`iiiiiiiiiii```i`iii`iiiikkkbmmmnmmnnalnfmmmnmmnmmmmmmmmnmmnmffmffmffffmmfmnmmmmmnmffmfmffffffmmmnnmnnmmmmmmmmmmnnnmmmmmmmnmmmmmmmnnmnnmmmnnmkmnnkabi`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`nnnka`ic`a``innknkkkkkkbkkkkkkkkbkkkknkkkknkkkkbbkkbkbbbkkkkkbknbkkbbbbbbbbbbbbbbbbbbbababbkbbbbbbabbbbbabbabbbcibbai`akkmkkbjjjjjjjjjjjjjjjjjjj", "lccllccclclccclccccccccccccicccc`ciliciccccciccccciciciciciiiii`faiii`iiiiii`ii`ii`ii`iiiiiiikmnkbmmnmmnfalkmmfmmffnmnmmmmmmmmfmffffffnmfmfmffmmmmmmmmmfmfffffffmffmmmmmmmmmmnnmnnnnmmmmnmmmmmmmmmmmmnnmnnnmmmmnnmnnnkba`ajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj`i`nnbbaa`iaaa`inkkkkknkkkkkkkkkbkkkkkknknnbkkkkknkkkbkbbkbkkbbkkkkbkkknbbbbbbbbkbbbbbbabbbbbbbbbbbbbbbbbbabbababa``bba`aabbbnfkjjjjjjjjjjjjjjjjjjj", "clcllclllclccclcclcccccccccclciccicccccciciiiciiciciciiciiiiii`iicciiiiiiiiiiiiiiiiiii`iiiii`nnmbbkmnmmnk`jnnmmmffmmnmnmmnmmnmfmmmfffffmfmfmffnmmmnmmmmfnfmfmfffffffmnnmmmmnmmnmmmnmnmmmmmmmmmmnmmmmmmmfnnnnnnknnfkkknn``aljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji``nnnbbbaaabaaikknkknnkbkbkkkkkkbkknkkknnnkkkkkkkbbbbbbbkkbkkkknkknkkkkbbbbbkbbbbbbbbabbbbbbbbbbbbbbbbbbbbbbbabba`aba`abbbkbakkjjjjjjjjjjjjjjjjjjj", "lclclccccccllccccccccccccciciccclic`cciiiciiiiciiiicicciiiiiiiciii`iiiiiiii`iii`ii`i`iii`ii`akbmnabnnnmnb`jffffmfffmmmnmmnmmmmfmfmmmffffffffffmfnmmnmmmfmffmmfffmmfmmmmmmnnmmmmmmmmnmnmnmmmmmmmnmnnnmfmmfmmmmnknnmnkknkaabjlljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlic`bkmkbbbabbaainnnknnnkkkkbkkkkkkknkkkkkkknkknkkkkkkkbbbbbbnnkkkbnnkbbbkbbbbbbbbbbkbbbbbbbbbbbbbbbabbbabbbkbbbbbba`baaabkbnbbkbccjjjjjjjjjjjjjjjjj", "clcccclcall`lcclccccccccccccbiciicicccicccciicciciciciiii`iiiiiiiiccii`iiiiii`ii`iiiiiiiiiciabbkbbbbmmnnn`jffmmfmfmmmmnfmmmfffffffmmmfffmfffffffffmnmnnmfffmmmffffmmmmnnmnmmfmfmnmmmmmmmmnmnnnnnmnnmmmmmmfmmmnnknknkknbbbkljjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjj`iabknnnkknnkbbinnnnnnnkkkkkkkkknnknnkkkkkkkkkkknnknnkkbkbbbnkkkbbkkkkkkbbbbbbbbkkkbkbbbbbbbbbbbbbabbabbbbbbbbbbbbaabababbbbmnkbljjjjjjjjjjjjjjjjjj", "clclclcl`lcmcccccccccccccciikiiiii``iiicicciiccicicicii`iiiiiiiii```iiiiii`iiiiii`ii`iiiiiii`bbbbkbbmmnmmilmfnmmmmmmmmmmmmffffffffmmffmmffmmfmffmmmmmmmffmfnmmffffmmmmnnmmmffmmmmnmmmmmmmnmnmnmmmfffnnnnmnnmmnnkkknnkkbkbkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji``mnkkknnmmkbbiknnnkkkknnkkkknknnnnnnnkkkkkkknkkkkkkkkbkbkbkbkkbbbkkbkbkbbbbbbkbkkbbbbbbbbbbbbbabbbbbbbbbbbabbabba`b`bkkkkabmmbljjjjjjjjjjjjjjjjjj", "clcccllclcikcc`cccccccciiciib`iiiiabibiiiiiiciiiiiiiiiiiiiiiiiiiiiiciiiiiiii`i`iiiiiiiiiiiic`kbkbbbbnmnnmicmfffmmmfmfmnmfmmfffffmmmmffmffffmmnmmmmmmffmmmmmnmfffnmmmmfffmffffmnmmmmmmmnnmmnmmmmmmffmmnmmnmmnmnnnkkknkkdbbkljjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjji``mnkbbkknkkbaiknnnkbkknkkkknkknnknkkkkknnnknkkbkbbbkbkkkkkkkkkbbkkkbbbbkkbkbkkkbbbbbbbbbbbbbbabbkbbbkbbbbabababaaiiibknnkkknnnijjjjjjjjjjjjjjjjjj", "cclcclcclccclcnicccccciiiiiiciii`ca`iaiciiiciiiiiiiii`iiiiiiiiiiiiii`ic`i`iiiii`iii`iiiiiiii`bknbkkbbnmnnilnfffnmmmmmmmffmfffffmmfnmffffffnmfnmfmfffffmnffmmnfmmmfmmfmmmmffffmmmmmmnmnmmnmmmmmmfmnnnmmnnmnmnnkknkkbnnkbbnbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`kmnkbbkkbbbbiknnnkknkkkkkknkknnnknkbkkkkkkknbkkkkkkkkknnkbkkbbbkbbbkkkbkbbbkknkbbbkbbbbbbbbbbbbkbbbbbbabbbbbabbalilbkkkknnnnmijjjjjjjjjjjjjjjjjj", "lccclccclcccccccccccciiiiiiiiciiiiii`i`iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii`ii`iiiiiiiiiiciankbbkbbbkkmmccnfffffffmffffmmnmmmmfmmmfffffmmfffmfffmmfffmmffffffnmmfffmmmfmfffmmmnfmnmmmnmnnmffmnnnnnnnnmmnmmnnnkknnkkbkkkknljjjjajjjjjjjjjjjjjjjjjjjjjjjjjjjjjc`iknmnbbbkbbba`bnmnnnnnnnnnnnkkkkbnkbkkknkkkkknnkbkknkkkkkbkknnkkbkbkkkbkbkkbbkkbkbbkbbbbbbababkbbabbaabbbaabbbaaalccankknkbnbkajjjjjjjjjjjjjjjjjj", "lclliclcccccccccccccciiia`ccciiicickkiiiiiiii`ii`iiiiiiiiiiiiiiiiiiiii`ii`iiii`ai`iiiiii`ii``mnkkbbbabkkklcnnffffffffefffmmnfffmffffmmmmfmfmmnmmffmnmmmffffffmmmmmmmmmffmfffffmmmmnmnnmnmmmmnnnnnnmmmnnkmmmnmnbbknnkbbknnnljjjjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjia`kbnmnbbbbbkaabknnnnmnnnnnnnkkkknkkknkkknkkbkbkkkkknkkkkknnkkkknkkbbkbkbbkkkkkkkkkbbbbbbbbbbbbbbbababbbabbbbbbkbalciakkknnknkkdjjjjjjjjjjjjjjjjjj", "cclibccaccclcccccccciiicaccciiicic`aai`iiiiiiiiiiiiiiciii`iiiiiii`i`iii`iii`ii`iiiiiiiiciccc`knknkkkbaaa`lifmfmmmfffffffmmnmmffmmfmmmmmmffmfmfffffmfmmmfmfmmnnfnfmmmmnfffffffmmmnmnmmnmmmfmnnmfmfmmfffmmmnmnmnkkbkkkabkknncjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc``kbknmnbbknnkabnkkbnnnnmnnnnnkkknknnnnkknbknkkkbkkkkkkkkkkbkkkbbbkbkbbbkbbkkkkkbbbbbbbbbabbbbbbbakbkbkkkbabbabbbkci`akknkknkkkajjjjjjjjjjjjjjjjjj", "cclc`lcccccccccccccciiiccciiicciicac`ii`ii`i`iiiiiiiiiiiiiiiiiii`iiii`ii`iiiiiiiiiiiiiiciiiiakkknnmnba``ij`mmmmmffffmmnmnmfmmffmfffffmmmffmmmmnmnffffmmmmfnmmmfffnmfnnffmmmmmmmmmnmnnmmfmmnnnffffmmmmmmnmnnnmnknkbabkkkbbkljjjjjjjjjjjjjjjjjjljjjjjjjjjjjjjjji`ikkkkkmmnnnfnbbnknknnnnkknkkkkkkknkkkknnnbknnkkkkbkkknknkbkkkkbbbbkkkbkbbkkkkbbbbbbbbbabbbbkkababkbkbbbbbbbbbbabki`abkkkkkknnkbjjjjjjjjjjjjjjjjjj", "lcllccclcccccccccciiiiiccciicciiciciiiiiiii`iiiiiciiiiiiiiiiiiiiii`iiiiii`bb`iiii`iiiciiiccibnkkbknbba`cijafmmfmfffmmmnmnnmffmffffffffffffmmmmffmffffmmnmfnnmnfmfmmfnnmnmmnnnnmmmnnnmmmmmnnnfmmmnmmfffnnnmmffmknkbabbbkkkkljjjjjjjjjjjjjjjjjjjjjjjjjjjjj`ljjjca`bknkknmnmnnmbannnknkkkkknkbkkkkknnknnnknknkkkbkknkkkkkkkkbbkbbbbbkbbkkbbbbbbbbabbbbbbbbbbkbbabbbbbbbbbkbkbaabkkbaakkkkbbbkknnnjjjjjjjjjjkjjjjjlj", "cccclcccccccccccccccciiiiciicciccici`ii`i`i`iiiiiiiiiiiiiiiiiii`iiiii`iiiiiicci`iiiiciiiiiciakkkknkaaa`i`jamfmmmmmmfmmnnfnnmffmfmfmfmmffffffffffffmmmfmmmmnmmnfmmmmfmnmnnmmmmmnnmnnmmmmnnnnmfmmnffmmfmmmnnmmmnnnmkbkbbknnbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji`ikkknkbkmnnkkbannkkknknnkkbkbkbkknnnnnkkknknnknknkkkkkkkkkbbbkkbbbkkbbkbbabbbbbbbbbbbabbbbbbaabkkbbkkkbkbbbbbbkbbaakkkkkkkbbbknjjjjjjjjjjjjjjjjjj", "clcccilcccccccciiciciiicccciciicic`iii``ii`iiiiiciiiiiiiii`iii`ii`iiiiiiiiii`iiiiiiiiiiiiiiibkknnkaaaa`abjanmnnfmmmfmmnnmmnmmmmmffmmnnmmffffmmnnfmfmfffmffmffmmmmfmmnmmnmmmmmnmnnmmmfmnnnnmmmmmfmmnnnnmmnmmnmmnmmnkkkkkkkkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc``kbkkkbknmnkkbannkknkkkkkbkkkbkkknkkkkkbbkkknnkkkkbkknkkkkknnkkkkbbbkkbbbbbbbbbbbbbbbbbbbbbabbbbkbbbbbbabbbbbbabbaaknknkknkkbkkljjjjjjjjjjjjjjjjk", "lcccbf`cccccciiaccccciiiiciccciiiiim`iaii`iiiciiiiiiiiiiiii`iiiiiii`i`iii`iciiiiiiii```iiiicabbbkb`iba`abjamfnnmfmmmmmmfnffmmmmnnmmmmnmfmmmmmnnnnfffmmfffnmmmfnmmmmnnnmmmmmmnmnmnnnmmnnnnmfmnmmmnnnnnnnnmmfmffmnnmmnkknbbbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`ibabbkkkbnnkbkakkbkkkkknkkknkkknknkbbkkkbbkkbkkbkbbbknnkkkkkkbkkkbkbbkbbbbkbbkkbbbabbbbbbbbabbkbbakbabbabbbabbkkka`knknnmnnnbnkljjljjjjjjjjjjjjjj", "k`ii`icclccccciccciicc`ccicicciiciicibniiiiiiiiiiiiiiii`caci`ii`i`iiiiiiiiiiiiciiciiiniiiiic`b`abaiiaaabbjbmmmmmnnnmmmfffffmfmnnmnffmnnnmmmnnnmnnmffmmmffmmffmmmnmfmmmnmmmmnnnmnfffmnnmmffmmmnmnnnnmmnmfnmmfmnnmnmmnnkkknbcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjci`akkbkkkbbbmkkanknnkkbkkknnkknnknbbbbnknkbkbkkkbbkbbbkkknbkkbbkkkbbbkknkbbbbkbbbbbbbbkkbbabkbbbbbkbbaaabbabbbbbbbaakknnnkbknnkbijjjjjjjjjjjjjjjjj", "ilcciccciccccccciccccii`iiiiciiciiiiiiai`iiiiiiiiiiii`ic`ii`iiaciiiiiiiiiiiciiiiii`iiaiiiccaabaab`iiaabbblkfmmfmmnmmmfmmfffmmnnmnnmmffmmffffmmmmmmmmmmmnmnmmmnnmmmnmmnnmnnnnmmnmmmnmnnmfnmmfmnnnnnnmmmmmmmmmmnnnmmnmnnnkbk`jjjjjjjjjjajjjjjjjjjjjjjjjjjjjjjjjc`iabnkkkbbbbkkk`knnnnbbkknnnnnmnbkbkkkbkknkkkknkkkbbbbkkkkbbkbkbbkbbbbbbbbbbbbbbbbbbbbbbbabbkkbkbkababbbbbkkbbbbbbb`knnnnkbbkkkkijjjjjjjjjjjjjjjjj", "cccciciclccicliaccccciliiicciiiiiii`iiiiiiiiiiiiifkiikaiiiiii`c`iiiii`aai`c`iiiiiiiiiciiiac`bb`aacc`bbkkalkmnmfmnnnnmmmnfffnnnnmnmmmmmmmmmnmmmnmmffffmmffmmmmmmmnnnffmnmnnmmfmmmnnmmmnmmnnmnnnnnnnmnffmmnmnnmmnfmnmmnmnnkbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`bbbbkkkkkbkkk`knkkkkkbbkbkbknnkbbkbbbkkkbkkkkkbkkkkkkkkkkkkkkbbkbkkbbbknbbbbbbbbkbbbbkkbbbbbbbbabbbbbbbbbkbbbbabaannnknnbbknkk`jjjjjjjjjjjjjjjjj", "cciccicccccccciicciciiiiiciiiiiiiiiii`iiiiiiiiiiiic`iicii``ii`iiiiiiiii`iaikiiiiiiiciciiikilab`a`ciakkbk`jnmnmmmmmnmmffmmfmnnmmnnmfmnmmfmmmnmmffmmmfmfmmfmmmmmmfnnmffmnmnnknnnknmmfffmnnnnnnnmmmnmfmnmnmnnnnnnmmnmmnnnnnmkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`bkbbbbkkbbnkk`kkknnnnkbnnnknnkbkbbbkknkbkknkkbkbkkkkkkkkkkkkkbkkbkbbbbkkbbbbabbbbbbbbkkkkbbbaabbbbbbbbbbbbbabbaba`knnnnmkbmmnndjjjjjjjjjjjjjjjjj", "ccccccciccccciclcicicia`aiiiicciii`iiai`iiiiiiiic`iikb```ii`eic`iiiiiciccnicbiciiccciciciiickai``c`bnkkkajnmmmmmmnmmmfmmmmmnmmmnnmfmmmffmmnnmmfmnmmfmfmfmnmmnmmnnmfmmmfffnnmnnnmmmfffnnnnnnfffmmmmfmnnmnmfmnnnnmmnkknnnnnn`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlicibnnnkbbkkbnkk`nknnkkkkknnnkkkkbkbbkbnnkkbkkkkkbkkkkbbbkkkkkbbkkbbbbbbkkbkkkbbbabbabkkkkkbbbbbkkkkkbbbkbbbabbbbbbb`aaknnknkmmnnbjjjjjjjjjjjjjjjjj", "cclicciiccccccciccciccbib`ciiiiiiiiii`iiiiiiiiii`iiia`ica`iciin`iiii`iii``cinciccicccccciccinic``aaknnkkajnmfmmnnnnnnnnnnmnnmfmmffmfmmmmnmfmmmmnmmmffffmmmmfmnmnnmffmmmnmnnnnnnmmmmmnmnnmffffmmmmfmmmmmmnmmmnmnnmnnkknnnkn`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiciibkmnkkkkkkkkk`nmkkbbkbbkbbbbkbbkkkkkkkknkkkkbbkbkkbbbkkkknkbkkkbkkbbbkkkkbkbbbbbbbbkbbkbababkbkbkbbbkkbbbbbbbbbbb`baabnnnkmnnkkjjjjjjjjjjjjjjjjj", "cclcccciaicccccciic`icacaiciiii`ii`iiiiiiiiiiiiiiiii`ii`i`i`ciaiiiiiiiiciliaf`ilcciccccccicckic`abkknnnnajmmmnnmmmmnmnmnnnnnmfmmnnnmffffmffffmmnnnmmmmmmmnffmmfmnmfffmmnmmfmmmffmmnmnmmffmmmnnmnfmmmfmmmnmmnmnnnnnmkbbknmkijjjjjjjbjjjjjjjjjjjjjjjjjjjjjjjjjlciibbkknnkknbkkbikkkknknkkkkkkkkbbkkknkbkkknnnnkknkkkbbbkkkbkkkkkkbbbkbbbkkbbbbkbbbkbkkbbbbbbkkkbbbbbbbbkbbbkbbbbbbbakkbbknmnmnnnkjjjjjjjjjjjjjjjjj", "ccccciciiiicciccccciiciiii`iiiiiiiiiii`iiiiiiiiiiii```ii`iiiiiiiiiiiiii`cicia`aiicicccccciciaca`aknkknnn`jfmmnnmmnmmmnmmnnnnmnnmmmnnmnmffffffnnnnmmmfmfmnmmfmmmmfmmmmmnmnmffmmmnnnmmmmmfnnnnmfmnmmmfmmnmmnnnnnkknmnkabkknnijjjijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjci`akkkkknnbknkkannbnkkkkkkkkkbkbknbkbkbkbbkbkkkknkbbbbbbbbkkkkbbbnkkbkknkkkbkbkkkkbbbbbbbkkbbbabbbbbbbbkkkbbbbbabbb`bnnbbknmmnnkbjjjjjjjjjjjjjjjjj", "cccccciiicccccicicicciiiii``biiii`ii`a`iiiiiiiiiiii`iiiia`ii``iciccici`ciicci`icbicccccccici`i`aknknnnnn`jffnnfmmnmnmmmnnnmmmmmnfmmmnmmmnmmffnmnnnmnnnnfnmmfmmmfmnmmmnnnmnnnmmmmmnmmfmmfnnnnmfmmmmmnnmmfnmnnmnmkknnkbbbbkkcjjjjjjjjjjjjjjjjjjjjjjjljcljjjjjjjci`abkkkknkmbnkn`nkkkkkkkkkkknkbkkkbkkknkkbkkkkbbkmkkbbbbbbbbkbbbknkbkkbbbkbkbbbbbbkkkbakkbkkkbbaabbkbkbabbbbkbbbbbbaannnkbbnnmnnnjjjjjjjjjjjjjjjjj", "ccccccciicicicciciaaiccc`iii`iiiiiiiii`iiiiiiiii``iiiii`aiiiaa``ciiiiiiccciciiicilcclcccccciaabkkknnnnnn`jfmnnmnmmnnmmnnnnmmmmfmnnmmfnmfnmmffmmmmnmnnnmmnnnmmnnmmmmmmfffmnmmmmmmmnmmfmmmmnnnnmmnmnnnnmnnnnnmnmmnbnnbbkkbakijjjjcljjjjjjjjjjjjjjbljcjjljjjjjjcjiaakbkkbnknnnmm`nkkkkkkkkkkkbbbkkkkkkkkbknbkkkkbbkkkkkbkbbbbbkbbbkbbbbkbkkbkbkbbbbbbbkbbbkbbkkbkabkbkbbbbabbbbabbbaabnnnnbbbknmnnljjjjjjjjjjjjjjjj", "lciccciiciciccicciiiiiciii```i``i`iiiiiiiiiiii`iii`ii``b`iiiiiicicicciiiciccccccccicccccccciabkkknnnnnnnilnnnmnmnnnnnnnmnffmmmmmnmmfmnmffmmmfmfmnmmmnnnmmmmmnmmnnnnmnmmmnnmmmnmmmmmmmmnnmmmmfffmmmmnnmmnmmnnnnnnbkbbbkbbabcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj``iabkbkbkkknknn`kkkkkkkkbkbkbkkknkknkkbkknbkknkkknkknbbkkbbbbbkbbbbbbbbbbkbbkkbbbkbkkbkkkbkbbabkbkbbbbbbaabkbbbbbbaaannnmnbbbkknmcjjjjjjjjjjjjjjjj", "iiiccciiiiciciccicicccci``iiii`ii`iiiiiiiiii`iii`i`iiii`iiiiiciiiciciiiiciicccccci`ilccccccaabkknnnnnnnnclmnnmnnnnnnnnmnmfmmmnnmmmmmmnmmmmmmfmmmnnmnmnnnmmmnnmmmnnnnnnnnmnnnffmnmnmmmnnnfmmnmmmmmmmnmmffmmnmnkkknkbkkbabbbcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`abkbkbkkknkkkckkbkkbkbkbkbkkknkkkkbbknkkkbkkkkknkkkbbbkbbbbbkbkkbkkbbbbbbbbbbbbbbkkbbbkbkabbkkbbbknkbkkkbbkkbbbabaamnnnnkbbabbncjjjjj`ljjjjjjjjj", "ciicciiiiiiiciicccciiiamb`i`i````iiiiiiiii`iii`iiii`iiciiiiiiiiiiciiiiiciiiccccccciccclccli`kkmmknknknnnccmnnfnnnnnnnnmfnmfnmnnnmmmmmmnnmnmmmmmmnnnmnnnnnnnnmmmmfmnnnnnmnnnmffmmmmmmnnnnnnnnnnmmnfmmnmmfmnnnnnkkkbbkkbabbbcjjjjjbjjjjjjjjjjjjjjjjjcjjjjjjjjjjcci`bbkbbkbkkkbkckkkkkkbbbbbkkkknkkbbbbnnkkkkbkkbbkkkkkbbbbbbbbbbbbbbkkbbbbbbbbbabkkbbbbbbkbabbbbababbbbbbbabkkbbaababnnmnmnbbbbab`jjjjjijjjjjjjjjj", "ccccciiciiiiiiiiiiciiccaiii`iiii`iiiiiiiiiii`i`i`iii`i`iiiiiiicciiciii`iiiiiciccclcclccccccaknmmmmnnnkknlcmnnmnnnnnnnnmfmfmmmnnnfmmmffmmmmnnnmnfnmnnmnmnnnnnnmmfnnnmmmnnnmmmnmmmmfmmnknnnnnnmmmfmmmnnmmmmknnnnkbabbbabaakaljjjjjjjjjjjjjjjjjjcjjjjjjjjjjjj`jjli``bkbbbkbkknkkckkkkkbkbkbbkknnknnkbbkkkkknkkkkkbbbbbkkbbbkbbbbabbbkbkbbbbbbbbbbbbkkkkkkkkbdbaabbbkbbbkkbbbbbbbabbabakmnnnkkbkkbbijjjjjjjljjjjjjjj", "cccciciiiiiiiiiiciiab`icci`a`ic`i`iii`ii`iiiii`i`iiiicciciiicciiiccicibiiiccccccicccccclcccanmnmmmmnkkkklimnnmnnnnnnnmfffffmnnnnfnnnmffffnmnnmnmmmnmnnnmnnnmmnmmnnmffmmnmmmnnnmmfmnmmnmmmmmnnnnnmmnmmmnmnnnnknkbabkbbbabbaljjjjjjjjjjjbjjjjjjjjjjjjjjjjjjjjijliiabbkbbkkbkkkb`kkkkkkbbkbbknnnnkkkbkbkbbkknkkkkkbbbbkkbkbbbbbbbbbbbbkbbbbkbbbbbbbbbbkbkbbbbbkkbbbbbbbbbbbbbbbbabbba`bnnnnknnbkbb`jjjjjjjjjjjjjjjj", "ccccccciiiiiiiiii`iiiiii``iiiiciiiiiii`iiiiii`i`iiiiiiiiiiiciiicciiaicaicciiccccclcclcclllcafmnfnmnnnnnnlcmfnmnmnnnnnmmfmmnnnnnnnnnnmmmmmnmnmfnnfmnnnnnnnnnmnknnnnnnnnnmmnnnnmfmmnnnnmmmmnmnnnmfnnmmmnnmnknkknbbbbbkbaaaaaljjjjjjjjjjjljjji`jjjjjjjjjjjcljjjjj`iabkkkbkkkkkmaaknkkkkbkbbkknnkkkkbbbbnbbbkkkkkbkbnkkbkkkbbbbbbbbkbbbbbabbbbbbbbbbbbbkkbbbbbkbbbbbabbkbabkbbbbbbaaaa`aknnnmnkknbbajjjjjjjjjjjjjjjj", "icccci`cciciiiiiii`iiiiiii``iiiiii`iiiii`i```iii``ci`ciiiiiccicicccciciiicicccccccclccccclikmmnmnmnnnnnklammnnknnnnnnnnnmmmnnknmnnnnnnmmmmmmfnnmnmmmmnmnmnnnmmnnnnnnnnnnnnmmmmmfnnnnnfnmmnnnnnkmmnnnmmnnmnmnnkbbabbba`aaailjjcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiakbknkkkbknnk`nkkbbkkbkbbbkknkkbbkbkbkbbbkkkkbknbnbbbkbnkbbbkbkbbbbbbbbbabbbbbbbkbbbbbbbabkkkbbbbbbbbbabbbabbbbbaaibbbbknmmknkabjjjjjjjjjjjjjjjj", "icciccccciicci`bi``i`iii`i``ciiiciiiiiiiiiiiii`aci`iiiciiiiiiiccciicccccccciciccccccccclclcbnnmmnnnnnnnklaffmnnmnnnnnnmmmmmnnnmmnnknmmmmnnmmfnnnnnmmnmnnnmnnmnmnknmnnmmnmmfmmnnnnnnmmfmmnnnnnnnmmmmmnnnkmnnnnkbababaa`aaicjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiakkabkkkkknnnannkkbbkbbkbkkkknkkkbbnbbbbbbkkkkkkbkkbbbkkkkbbbbbbbbbbbabbbbbbbkkkbbbbbabbbkbbbbabbbabkkbbabbabbbabb`abbbkknmmmkbb`ljjjjjjjjjjjjjj", "macciiiicicciii`iii`i`i`i`knai`c`iii`iii`ii`ii`aaciiafiiiciiiciacciccccciciiccclccclccllclcaknnmmnnmnnnnjbmffmnnmnnnnnmmmfnmnnmfmnknmmmnmnmnnnmnmmnmmmnnnnnnnnnnnmmmnmmnnmmnnnnnnnnnnnnnnnmnnnmnnnmnnnknnnnnnkabaaaai```iiljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiakbaakkknnnmnankmnkkkkkkbbkkkkkkkbbnkkbbnkkkkbbbbbkbkbnkkkbbbbabbbbbbbkkkkbbbbbbbbbbbbbbabbbbabbabbbbabkabababbbbb`abbbbbknmmnbbljjjjjjjjjjjjjjj", "biccclcciicciccii`iiii`iii``ci`ia`iiiii`iii`iii`c`iiii`ciiicccibccciciciiiiiiicccccclccclclabkkkmnnmmnmklanmmnnnmnnnnnnmmfmnnnnmmnknmmnnmnmnnmfmmnmmmmmnnknknnnnmmmmmmnnmnnmmmmmmnmknmmmnmmmmmnnnnnmnnnnknnnmkabbaa```a`iiljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`kkbabkbkknmnakknkkbkkkkbbkknkkkkbbnkkbbkkbbbkkkbbknkbkbbkkbabbbbbbbbbkkbbbbbkbbbbbbbbbbbbbbkbbbbkbbbabbabbababbbb`abbbbbabknkkajjjjjjjjjjjjjjjj", "cciiiiiicciiccib`iii`ii`i`````ic`ii`iii`i`i`iiiiiiiciiciicciiciiiccciiiciiciccilcclclcllcll``aaknmmnmnmblbnnmnnmmnmnnnnmmmmmnknnmnnnnnnnnnmnmnfnknnnnknnnnnnnnnnnnmmnmnmnmnnmmmmmnfnfmmnnnnmmmmnnnnknnnknnkknkabbaaaabba``cjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`baaaabakkbknakkkkbkkkkkkbbkknkkkbbbkkkbbbbbbbkkbbkkbbbbbbbbbbbbbbbkbkbbbkbkbbbkbbkkbbbbbkbbbbbbkkbbabaabaaaabaaaa`i```aabaknnbacjjjjjjjjjjjjjjl", "icccciccicciic`b```iiiiii``iiiiiiiii`iii`iiii`iiicii`cicciiciicccccccicciicicciclcclclcllcli``akkmmmnmnbjbnmmnmnmmmmnnnnmmmmnnnkmnnnnnnnkknnnnnnnnnnnknnmnnnnmmmnmmnnnnnnknknnnmmnmnnnnnnnknmmnnkkkknnkknnnknkabbaaabbkabaijjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjcci`ii`abbkkbkkabnkknknknknkbbkknnkkbbbkkbbkkbbbbbkkbkbbbbbbbabbbbbbkbkkkkbbkbbababbbbkbbbbbbabbabbkbabaababbbbbbabaiciii`aabbnnkacjjjjjjjjjjjjjjj", "liiicciiiicciiii`i`iiiii``ii``iii`iiii`i`iiiiiiiki`cciciciiccccicccccccccicciiaicccllcllclcaaabknmmnmnnbjkmmfnnnmmfmmnnknmmfmnmnnnnnnnnnnnnnnnnmnnnnnnnnnnnnnnnmmmmnnmmknnnknnmmnnknnmmfmnnmmmnmnnnnnmmnnnnkkbabaaaabkkbnaijjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjilcic``bkbkkkkbaankkkbkkkkkkkbbkknnkkbkbkbbbkkbbbkkbbbbkbbbbabbbbbabbbbbkbbbbbbbbababbkbbabbkkkbbbbkkkbbbbbabbbbabaaalccciabbbkkkbijjjjjjjjjjjjjjj", "icciciccciiciiiiii`iiiiiii`iii`iiiii`i`iii`iiiiiiic`ciiiiicciicccciccccccilcclilclclclccllcbbbbmmmmmmnnbjkmmmnknnmmnmmmnmfmfmmmfnnmmmmnnknmnmnnmnnnnnnnnnnnnnnnnmmmmmmmmnnnnnnnmnnnmnmnnnnknnmmnmnnnnnnnnnnnnkbb`i`aabnnkaijjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjcllcc`abbbabbkbaannkbbbkkkkkkkkkkknknnkbkbkkkbbbbkbbkbnbbbbbbbbbbbbbbbbkkkkkkkbbbbbabbbababbbabbabbbbbbbbabbbbabbbab`lllciibbabbbbijjjjjjjjjjjjjjj", "ccciciicciiciii``c`i`cii``iiiii`ikbn`iiii`iiiiiiiciiiiiccakaiccccccccccciccccclccllcllclllcbbbnmmmmmmnnajmmmnnnnnnmmnnnmnmmmmmmmmnnnnmmnnnmnmmmknmmnknmnnknknnmnmnmmmnnnmnknnnnnnkkmmmnnmnmnnnnknkknmmmnmnmkkkaaii``bkkkbaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicllccaakbbbann`bnnkbbkkknkkkkbkknnkknkkbbbbkkbbbbbkkbbbkbbbbbbbbabbbbkkbbbkbbbbbabbabbbabbkkbbbbbbabbbaaabbbbbbbbaaalccc`abkbbbabajjjjjjjjjjjjjjj", "ciiil`ciciciciiii`iiiii`ii```iiii`ia`i`iic`ci`iiiiiicciiiciccccciccccccccccllcclcccllclclccbbbnnnnnmmnn`lnmnknnnnnnmmnmnnmfmmmmmmknkknnknnmnmmmnmnnmmnnnnnnnmnnnnknnnnmmnnknnnnnnnnmmnnnmnnnnnnknnnknmnnknnnmka`i``abbknaaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicjcii`bkbkkknmaankbkbkbbknkkkkbknnnknkbbbbbbbbbkkbkkkbbbkkbbbbbbbbbkkbabbbbbbkbbabbbbbbbbbbbbbbbbabbbabbaabbbbaabbbblli``bkbbbbaaajjjjjjjjjjjjjjj", "ccciina`iicicii`iaiiiiiii``i`iiii`i``ii`i`a`iic`iciciiccciicciccccccclcccccccclclclccllclciabkmnnnnmmnm`jnnnnknnkknmmmmknmfmmnmfmnnnnnmnnmmnnmmmmmmmmnknnnnnmmmnnnnnmmmfkknnkknnmmmmnnnnmnmnnnnknkkknnnmnnnnmna````bbknbaaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjcila`i`bkbknnnnaabbkkkbbbbnkkkbbkkkkkkknkbbbkkbbbkbkbnkkkkbbbbbbbbbbkkbbabbkbkkbaabababbbbbbbabbkbbbaaabababbbbbbabbbllababkbbbbbbbjjjjjjjjjjjjjjj", "iiccik`iiciacii`ibiiii`iii```i`ii`i`iciiiiiiiciciiiiiiiiiccciccccccccccccclccllcieillclllciabknnnnnnnnnilknnnnnnnnmmnmmnnmmmmmmmnnkknmmmmnnnnnmmnfmmnmmknnnnnmmnnnmmmmmmnnknnknnmnnmnnnnnmmnnknnknknkmmmmnkknkaaa`abakkaab`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicca`iibbbknnnnb`bkbkbbkkkkkknkkknknnkkkbbbbbkkkbbbbbbkkkkbkkkbbbbbkbbbbkbkkkbkbabbbabbbbkbbbabbbbbbabbaabbabbbbbbaablcabbbkkbbbbbbjjjjjjjjjjjjjjj", "ciccccicciibiiiiiaiiiiiiiii`i`i``iii```iiiiiiiiiciiiccciciccccicilclcicccilclclclccclclcll`kknnnnmnnnnn`jnknnnnkmmmmnmmmnmmmmmmmmnnnknnnnnknnnnmnnmnnfmmmmnnmnnnmmnnnmmnnnnnknknnmnmmnnknmnnknknnnmnnmmnnnnkkkabaaabbaaibk`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliccb`iibbbbknknk`kkkkbknknkbnnkbkkknkkkkkbbbkkkkbkbakkkbbkbbkkkbbbkbbbbbkbbbbbkbbbababbbbbbbkbabbbbaabbabbbbbbbbaaabbcibbabbkbbaabbljjjjjjjjjjjjjj", "ciciiciicii`iii`i`ii`iiiii`iii``i``iaaai`iici`ciiicc`iccciiiccclccicccciiaillcclcjlallllll`knnnmnmmnnnn`lnnnnnnnmnnnnmmnnnnnnmnnmfmnmmnnnnknnmmmnnmmmmnmmmnmknkkmmnnnmmmnnkknnnnmmmnmmnknnnknnknnnmmnmmnnnmnnkbbb`abba`abkijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiicnk`cakbbknknkabkbkbkkkbkbkkkbbbbkbkkkkkkkbkkbbbbkbkkkbbkkkkkkkkbbbabbkkdkkbkkbabbbbbbbbbkbbabbbabbabbbbbbbbbbabbbaiiabbabkbabbbbjjjjjjjjjjjjjjj", "icciiciciicccii`iiiiiiiiiii`i````iiii`iikiiiabiiiiccaa`ibicbbicicc`iccc`ibcclclllacjclllll`bkknmmmnnnnnilnnnnknnnnnnnmmknnknnnnnnmnmmmnnnnnmnmnnmmmmnknnnnknnkknmmmmmmmmknknnmmmmnmnmnnnnnnknnknnnnnnmnnnnmnknkaiiiab`abbk`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji`cnnic`bbkbknkk`bkkbbkkbkkkknkkbkkkkbkbkkkkkkkbbbkbbnbnbbkbbbbbbbbbbbabkkkkkkkbbababbbkbkbbbbbabbabbbabbbbabbbbabbab`ibbabbbbbbbkbljjjjjjjjjjjjjj", "cciiciciciiii`iiii`iii`i`i`iiii`````iiiiiiciiiicciii`iccciccccicccilccccc`lclllcclcllcllll`bbkbknmnnnnnicnnnnknmnnnnnnnnnnnnnnnnkmmmmmnnknnmnmnnnmmnknnnnnnmnnknknmmmnmnnnknnnmnnnmnnnnnnmnknmnnnnnknnnkkbnmnmbilcci``abkkijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`kb``akmbakkknakkbbbbkbknbbkbbbbbbbkbbbkkkkbbbbkkkkbbbkkbbbabbbbkbbbbbbbkkbkkbabbbbkkbkbkbbbbbbkbabbbaababbbaaabbbb`ibkabbbbkbbabljjjjjjjjjjjjjj", "iciciiiiiccci`i`iiiiiiiiii``i``i``iiiiiiiiiiciciiacciilccccciicciccccccclclclcllllllllllcl`abbbknmmnmnnlcnnkknnnnmnknnnnknnnnnnmmmnmmknnnffmmmnnnmnkknnnknnknnnnnkknnnnnkknnnmmnnmmnnnmnnnnmmmnknknnmnnnnkmnnnii`ciccikkbbijjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjjic`bb``bkknbbbnnakkbbkkkkkbbbkkbbkbkbbbknkbkkbbbbnkkkbbbkkbabbbbbbbbbbbbababbbbababbbbbbbbbbbkbbakbbbbbbbabkbbbaabbbb``bbkaknbbkkakijjjajjjjjjjjjj", "cicciccia``ii``i`i`iiiii`i```i```i`iiiiiciiiiiiic`ciccaiciicciicicccccccclclcllclllllllcjcabbbknnmnmnnnlinnnnknmnnnknnnnnmnmmnmnmmnmnkknknmnmnnmknnnknnnknnnkknknnnknnknnnnmmmmmnmnnnnnmnnmnmnnnnnnmmmnnnnnknk`c`iiciiabbbijjjjjjjjjjjjjjjjcjjjjjjjjjjjjjjjjjjci`bb``bkkkkbbkkakbkbbkkkkbbbkkkbkkkkkkkkkkkkbbbbkkkkkkbbbbbbbabbbbababbbbabbbabbbbkbkkbkbbbabbbbbbbbbbbabbbbbbbabbab``babbbkkbbkkbijjjljjjjjjjjjj", "cciciiiciiciii``i`i`i`i`ii`````i`iiiiiii`iicicccciciicb`ciiicicicicccccclcllclllllllllllclakknmnmnnmnmmlinknkknmmnnmnkkmnnnmnmnnmnkmmnnmnmmnmmnmmnnmmkknnnnkknknnnnnnnnknnknnnnnnnnnnknmnmmmnnknknmmnnnnkknkkkiciiclcc`ank`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`kb`bbbkkkkbbk`bkbbkkknkkkkkbknbbknkkbkkkkbbbbbkbkkkkkbkbbbbbbbbbbbabbbbbkabbbbbbbbbbkbbbbaabbbkkbbbababbbbbbabaaabaibabbbbkkbbnkajjjjjjjjjjjjjj", "ciciciciiciiiiiiii`i`i``a`i```i`iiiiiiiiicic`iiiiccccci`iicccciccicciclccllclllcllcllcll`c`bbbmfmnnmmmnl`nknnkkmnnnmmnnmmnknnnnknnnkkkkknmmmnmnnmmnmnnkknnnnkknknnnnnmnnnmnnnmnnnnnnnknnnnmmnnknknnnnnnkkknknk`iicclcciakkajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlli`bbbknkkkkkkbbibbkbbbkkkbnkkkkkbbbbbbbkbbbbbbbbkkkkbbbbkbkbbbabkkbbbbbbbbbbbbbbbbbbbbbabbbbbabbkbkbbbabbbbbbabaabakaikaabkbkkbbkkajjjjjjjjjjjjjj", "cciciciciiiiiiiiiii````ibaiiiii`iiiiiiiiiciabiiliccciiiiccccccccccciclcllclllcllllllllllcjbnkbbknkmmmnmj`nnnnnknnnnnmmnmnnkknnnnknnkknnnnmmnnnkknnnnnnnnnnnnnknkknnkknnnnmmnmmnmknmnknnnmmnnnnknnnnknnkkknnnmkaiiccici`abbbjjjjjjjjjljjjcajjjjjjjjjjjjjjjjjjjjcciabbknkkkkkkkb`kkkkbbkkbkkkkkkkbbbbbbbbbbbbbbbkkkbbbbbbbkbbbbbbkbbababbbbbabbbkkbbbbbbbbbbbabbbbbbbbaabbbbabaaabbaba`nbabbkkkkbbkkjjjjjnljjjjjjj", "iiciciciiciiiii`iiiiiii`a`iiiiiiiiiiiiiib`iciciiiciiiibiccccccccccccclcllllclllllccllllllcbbbkkbkkkmnmnlannmnknnknknnmmnmnkknnnmnknnmmnfmnnnknnnknknnmmnknnnnnknknkkknnnmmmnnnnknnmkknnnmnnnnnnknnkkknkkknknnb`icc`ai`a`aa`jjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjlci`abbknkkkknnk`kkkkkbkbbbbkkkkkkbbbbkkkbbbbkbkkkbbbbbbbbabkkkbbaabbbbabaababbbbkbbkbbabbbbabbbbbbbbbabbbaaaabaabaabbikkbakkbbnkbbbljjjjajjjjjjjj", "iiciciiiiiiiiiiiiiiii`iiiii`i`iiiiiiiiii`ccciiciiiiiccalcccccccccclclc`lcllllllllcclllllllbbbnbabbbknmkjannmnnnknnknnmmmmnnnnknmfnmnnnkkmnnnnnnnkkkkknnkknknnnnkknknknknnnmnnnnknnnnknmmmnnnknnnnkkkkkkknnnnnk`cc`ab`a`cii`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlciaabbkknkkknnkakkkkkkbbkbbkkkkkkbbbbkkkkkkkkbbkbbkbbbbbabbbbbbbbbbbbbbababbabbbbbbbbbbbbbabakbkbbbabbbabaaabaabbabbaiakbabbbbbkankijjjjjjjjjjjjj", "iiicciciciiiiiiiiii`iii`ii`iii`iiiiiiiiciiiiciiiicciccliccciicclcllclcaclcllclllllclllllllbabbdkdddbnnklannnknnkknknnnnmmnnnkknmmmmnnfnnnknnnnnknnknnnnnkknnnnnkkkknkknnnnnnnnmknnnnmnnnmnnkkknnkkkkkkkknnnknb`c`bkbba`i``ijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjcibbbkkbknknkkn`kkbkkbbbbbkkbkkkbkkbbbknkkbkkbbbbbbbbbbbbbbbbbbbbbkbbbbbbabababbakbbbkabbbbkbbbkkbababbbaabaaaabbkaaa`bnabbkkbabbbkcjjjjjjjjjjjjj", "ciiiiciiiiciiiiiiiiii``i`iiiiiii`iiiiiiiciiciiicicccicccililccccclccllllllclllllllllbllllikkabbbbbkbkmblanmnknnknnnkknnnnnnnmmnmmnnnnnnnnnnnknnnnknnnnnnnnnknnnknnnkknnnkkkknnknknmnkknnnnknknnbkkkkkkkknmkkkb`ibknnkbaa``cjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`akkbbkbknnnnnibkbbbbkbkbbbkkbkkkkkkknkkbkbbbbbbbbbbbbbbbbbbbbbabbbbbabbbbbbbbbababbbabbbkabbbbababbbaaabbaaaakbbaaa`bnbbbbnkkbbbbljjjjjjjjjjjjj", "icciccicicii`c`ii`i``cc`ii`iii`ai`iic`iiciiciiiiccccccccclcccclcllciilclllllllllllllcjcllannkbbbkkbaknajknnkkkkkknnknmnnnnnnknnmnnnnnnnknnkkkkkkkknkknkkkknnnnkkmnnkkkkknkkknnnnnknnnknknkknknnnkkkkkkkknnmnnk`aknknknkb`d`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl``aknkbbkknnnkkikkbbbbbbbbkbbbkbbbbbbbkkkbbbbkbbbbbbbbbbbbbabbabbbbbbbabkbbaaaabaaababbbabbaabababbaabbbaaaaababbkbbb`ankabbknkbbkbijjjljjjjjjjjj", "iccici`c`ciii`kiiiiiiiai`iiiiii`ii`iiiccicciiicccciccccc`mlclclclccccllcllllclllllllllail`bkkbaknkbabkijnnkknknnkkkkknnmnnkkknnmkkkknnnnnknknnkknnnnnkknknnnknkkmmmnnnnkkkknnnnnkkknknkknkkkknnkknnnnnnnnmmnkbaknnnknfnbbnbjjjjjljjjjlcjjjjjjjjjjjjjjjjjjjjjjjl``bnnknkkbkknkk`kbkbkbbbkbkbbkkkbbbbbbkbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbbbkkbbbbbbbbbbbkbbbbabbaabbbabbbaaabbdbbbbbbbaa`amkbbbknknkbbijjjjjjjjjjjjj", "ciiiiia`ci`bna`iii`iibfiii``i`iiii`iiiiiiiciiicccccicccclccl`cilcllllllcclllccllllllll``liabbabkkkkbbbilknkknnknnnkkknnnknnnkknnkkknknknknknknknnnnnnknknnnkknnmmnnkkkkknknknnnmknmnkknnnnnmmmnkkknknkknknnkkbbnnnknmmkdakbjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjli`bnknnnkkbbkkmabbbkbkbbkbbbbbkkbkbbbbbbbbbbkbbbbbbbbbbbbbbbbbbbbbababbbkbbbabaabababbbbabbabbbbabbbbabbababbbaabaabaaamnabbkkkkkkkijjjjjjjjjjjjj", "c`icciiciiciiiii`ii`ian`i```iiiaiciiciibiciiiicccccccccccccinlclclcccccllllclclllljcljlilibbbbbbaabkkb`jbkkknkknknkkknnnkknkkkkknkknnkkkkkknknnknnnnkkknknnkknnmmmnnkkknnnnnnnkknnnmnknnkkknnnkbkknnkkkkkkknnkbkkknmnkbbknkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`i`bknknmkkbbbk`bbbbbbkbbkbbbkbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbababbbabbbkkknbababkkbkbbbbkabbabbbabbbbbbaaabbaaabaababa`nkbabbkkkknbaljjjjjjjjjjjj", "ibaiiiiiik`ciai`iiiiii`iii`iiii`iciiiciaiiciiccicccccccccllililcclllcclllllllllllclllllllibkbkndaabnkb`jknnkkkknkknnnnkkknknkkkknnnnnknkknkknnnnkkknknknknnnnnnnknnnnkkknmnnnnnnnnkkknnnnnnknmnmknnnkkkkkkkknnbnnknmnbbnnnncjjjjjjjjjjjjjjjjjjl`jjjjjjjjjjjjjjl``abkkkknmkbbbbibbbbbkbbbkbbkbbbkbbbbbbbbbbbbbbbabbbbbbbbbbbabbbabbbbbbbbbkbbbabbbbbbbabbbabbabbabbabbbbabbbaabbaaabaaikbbbabbkkbbbbjjjjjjjjjjjjj", "c`iciiiii`i`iiii`a`ii`iiii`iiiiciiiiicciiiiicccccccccccclicjillccllcllcllllllllljlljllljlanmnnnbabnnnbclknnnnnnnkkknnkkkknknknnnnkknkkknnknnknnnknknnnnnknnnnnnnnnnnnnmmnnmnnnnnnkbkknnknnkkknnnnnnnkkkkkkbkkkbnknnkbbkmmnkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`iakkkmnkknkkbbibkkkkkkbbbbbbbbbbbbkbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbkbbbbbkbbbbbkbkbbbbbaababbbbbaabbbbbbabaaaababaaaikbababbbkkkkbjjjjjjjjji`lj", "iiiiiciii`iiiiiiiii`iii``i`ii`i`iiicciiciiicicccccccccicc`ciiilallccllcllllllllllllllllllannmnkbbmkkfkljknnmfnnknkkkkkknkkknnnnnknkkkkkknnkknkknkkkknnnnkknnnmmmnnknkknmmmmmmnnnbknnkkmnnnkknnnnnnkkkkkkkknnkkbnknnbbakmnmbjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`iiaknnnnknnmnkcakknkbkbkbbbbbbbbbbbbkbbbbbbbabbbbbbbbbbababbbkbabbbbkkkbbbbbabkkbkbkbbaabaaabbbbbbaabbbbbbbaabaaabbabikbbbbaabbknbkjjjjjjjjjjjjj", "iiiiiiiiiiiiiiiii`i````ii```ii`iiicicici`iicccccccccccclcclclcclclclllllcllllbllljcbcljllannnnbaknnmnncjnmnnnkkkkkknnkkknnnnnkkkkkkkknnnnknnknkknknnnkkkknmnnnnnmmnnnnnnnnnkkkkkkkkkkkkknnnkknnnnknnnkkknkknnb`knkkbdbnmnmbjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`abbkkknnkkmk`kknkkbbbbbbkbbbbbbbkkbbbbbabbbbbbbbbabbbbbbbbbbbbakkbbbbkkbbbkbkbkbbabaababbaaababbabakbbabbbaabbbababcanbaabbabkknkjjjjjjjjjjjjj", "ciciiiiiiiiiii`i`i```i`i`icc``i`iiiiiiiiicciciccccclccccccclcccllllllclllllllijllllijllllaknkkabkkknmnclmnknknkbnknnnnkkkkkknnknkkkknknknnkknkkkkknnkkkkkknnkknfnmnnknnnnnkkkkknkkkkkkkbkknmnnnkkkknkkkkknkkkbabnkkkbknnfnmjijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`akdbbbbkmmk`cabbbbbbbbbkkkbbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbaabbbbabbbkbbbbbbbbbbaaabbbaaaabaaabbbkbbaaaaabbbaadababiabbbabaaabbkbljjjjjjjjjjjj", "iiiiiiiiiiiii`i````iiiiiiii`baiiiiiiiicccccccccccccccccclclclcclclllcccllllllllllllljlljlbknkbankabknncckknknnnmnnnnmnkkknknkkkkkkknnnkknkknkkknknnnnnnnkkkkkknmknnnkkknknnnnnnknkkkkkkknkknnnnnnnnnnnknkkkkkkbknkkkknnnmnajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiciakbkbkkkbbbaiakbkkkkbkkbkkkbbbbbbbbbbbbbbbbbbbbbbbbbababkbbbbbabbaabkbbbbaaabababbbbababbbabababbbkbbbbbbbbabbabaabc`aaaaaaaabkknijjjjjjjjjjjj", "iiiiiiii``i`ii`i``i`i`iii`cciiia`i`i`iiiiiccccccccclccccccclccccclcllilllllllllllllllllllkmkkkknbdabkklcknmmnnnnnkknnnkkkkkknknkkkknknnkkkkkkkkkkknnkknknkkkkkkmkkkkkkknnnnnnkkkknnkknnnnkkkknmnnnkkkbkkknkkbkbnmnnnkknmnnajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiibbbbbbkka`caabkkbkkkkbkbbbkbbbbbbbbbbbbbbbbbbbabababbabbbbbbbbbababbbbaabbabbbbbbkbbaabbabbbbbbbbaabbbbaaaabaababaacc`iaaaa`aabkkijjjjjjjjjjjj", "lllllllllllllllllllljlllllllllllllllllljlljlljljlljljljljjljjljljjljjljjljjjljjjljjjljjjjknknmnnbbbbkklcnnnnnnkknkknnnkbkkknkkkknknknkknkkkkkkknnnmnnnmnnnnnknnnkkkkkknnmnnkkkkkkknknkmmnknkknnkkbkkkkkkkkbkkbbnnmmkkkkmmnkjljjjjjjljljjjjjjljljjjjjjjjjjjjjjjli``bbbbbbbaiiiaaakbkbbkbkbbbkbbabbbbbbbbbbbbkbbbbbbbbbbbbbbbbbbkbkbbbbbkbbababbbkbbbaaabbbbabbbbbbbabbbbaaaaaaababaaaaiccii`ii``aaab`jjjjjjjjjjjj", "ljljljljljljjljlljljlljljjljjjljjjjjjjljljlljljljjjjljljlljljljjljlllllljllljllljlljljjljbbknmmnkbbbbblinnnnnnnnknkknnnnkkkkknknknkkknkkkkkkknkknknnkknknnmnnnmnkkkkkknnnnkkkkknkkkknnnnknnknnnkkkknnnkkkbkkbbakmmkbbbbknnkjjjlljlljljllljljjljlllllllljlljljll`cibabaaa`cliaba`kkkkkbbkbbbbbkbbbbbbbbbbbbbbbbbbbababbbbbkkbbbbbkkbbbkbbbaababbbkbaabaabaabbbbbbababbkababbbbbbaaaaaaiciiicci```aad`ljllllllljlj", "ljlljlljljljljljlllljljljljllljllllhllllljljljjjlllljllllllljljljjljjljljlljjjljllllllljlddknmmnkbkbbbj`mmmnkknnnknkknnnkkkkkkkknkkkkkkkkkknkknknknnnnnnnnnnnnnnknkkbkknnkkknkkkkkbkknnknnkkkknkkknnkkbkkkbkkkaknnbbbbbbknnjljljljllllljllllljlljljljljlllllljl```bbaa`cjlcabbakknkkbkkkbbkbbkkbbbbbbbbbbbbbbbababbbbbbbbbbbbbbbbbkbkbbbbbaaabbabbbbbbaaaaabbbbbbbbaabaababbaaaaaaaab`c``icci`aaaa`iljjjljjljljl", "jlljlljlllhllhlhlljhlllljlljlljllhjljhjllhlllllhljljllhjllllhllhlhllhjllljhjlhjlhjjljlljlbkmmmmnmbkbkbj`knknnnnnnnknkknnkkkkkknkkkkkkkkkkkkknnknkkbnnnmnnnknkkkkknnnkknmmkkbkkkbkkkbknnnkkknkbkkkkkkkbkkknkknnbkmnkbbbabbadllllllhlllljhjhjljlljlllllllhjlllllc```bba`clliakkbabbbkbbbkkbkkbbbkbbbbbbbbbbbbbbbbbbbbbbbbbbabbbkkbbbbbbbabbbbbabbbbaaaabababaaabbababaaabaaaaaaaaababbaaiaa``i`a`add`cljhljlljljll", "lljhjhlhjllllllllhlljlljhjlljllllllhlllhjllhllljlllljljlljljlllllllllhlllhllljljlllllljljnknmnmmmnkkbal`kkknnnkkkkknkknmkkkkkkkkmnkkkkkkkknmnkknnkkbkkkkkkknknknknnnknnnnkkkkbkkkkkkkbkkkkkkknkbkkkkkknnnmnkknnknmnbbbkbbbbljljljjljljhjljlhlhllhjhlllllljljllli``kkaiclc`bbkkkbbbbkkkkbbbbkbbkkbbbbabbbkbbababbabbkkbabbbaabbabbabbbbbbbbkbabbbbbbaaabaabaaabbbaababaaababaabbbbbbabacbbaaa`i`abb`iljlllljhjljj", "llllljljlhllhlllhjllhjhllhlllllljhjljhjlllhjllhlhjhlhlhlhlhlhjhjlljhjljlljlllhlhllhllhllhkknmknmmnkkbbj`nnnnnnnnkkkknnkmnnmnkkkkkkkkkkkkkknnkkkkkkkkkkknkkkkkkkkknmnnnnnkkkkkkkkkkkkbkknkknnnkkknknknnnnknkknmnnnnnbbbbbdbdjlljhlhlhlhlllhlllllljljjhjllllllljhiiiba``ic`bnkbbkbbbkbkkbkbbbkbbbkkkkbbbbbababbbbabbbbbabbbbabbbbbbbbabaabbbkbbbkbbbaabaabaaabaaababbbbbbbabbbbbbbbbababiababba``add`iljhjllljhjhl", "llhllhjhjllljhjhjlhjllllllllhjhlhllhlllhjljhljljllljlljljljhlllhlhllhlhlhlhlljllljljlllllkbnmkknmmnkkalakknnkkkknknnkkkkmnnnnnnkkkbkkkknkknnkkkkkkkkkknkkkkkkkkknnmnnnnnkkbkbkbkbkbkkbkkkknnkkkkbkknnkkkknknknbkbkbbbabbbkbhllhllljljljhjjljlljhllhlllhlllhjhlli`i````a`abnnkbb`bkkkbbbbbkbbbbbbkkbbkbbbbabababbbbbkbbbaaabaaaabbaababbbbbkbbkbbaaaaaabaabaaabababbabaaaaabbbbaabaabbbibabnnk`iaaa``llljhjhllllj", "lllllhlllhllhlllhlllhlhlhjhjlllljlljlhjlllllllhlhlhlhlhlhlhlllllljlljljljlljlhjhjhjhllllckbbkkbknfmkbalannnnkkbknkkknkkknkbknnnkkkkkkknnnnnnnnkkkknnkkkkkkkkkkkkkknnnnnkbkkkkkkkkkkkkkknkkkkkbbkkkkkbkkbkkknnnbbbbbbabbbbbbllllllhlhlhljhlllllhjljljhjljhlllllhiiciiiaaabbnnmnk`kkkkbbbakbbbkbbbbbbbbkbbbbababbkbbkbbbbbbbbbbbabababbabaabbbbbbbaababaaaaabbababbabaaaaaaaaaaaaaabbbbbiabannnb``addahlllllljljll", "jhjhjllhlllhllhlllhllllllllhjhjlllllljhjhjhjhljlllllllhlllllhlhllhlhlhlhlllhljhlllllllllhbbbbbkbknkkb`jamnnnnkkkkkkknnnnnkkkkknkkkkkkkknnnnnnkkkknnnnkkkkkkkkkkkkkkkkkkkkkkkkkkkbkkkknnknnkbkkkkkbkbkkbkbkbnnnkkkkkbbbbkbbdljhjhjljljlllllhlllllhlhllhlhljhlllli`lli`aabbkmmnnmakkkkbbbbbbbbkkkkbbbbbkbbbbbbbbbbbbkbbbkabbkbbbbbababbbaabababaaaababaabaabaabbbbbbaabababaaaababaaabbaibbaknmka`abbbillllllllllj", "llljhjhjlllllllllhlllhlhlhllllhlhlhlhllhjllljlllljhjhljljllllllhllllhllllhlllhljlhllllllibdbbbbknkabkajbnnnnnnnkkbkknnnmkkkkkkknkkbkbkknnknmnnnnknnnnkkkkkkkkkkkkkkkkkkbkbkkbkbkbbkkkkknnkbkkkkbkkkkkkkkkkknnkbknkkkkbbbbkdlllllllhlhlhlhlljllllllllljljllllllliilc`abaabbknnnn`kkkkkkkkbabbbkkkbbbbbbbbbbababbbkbbkbkkbbbbbbbabababaabbabaaababaababaaaaaabababbbaaababaabbabaaaaaabb`abknkkka`abbbcljlljljllll", "lllhjllllljhjhllljhllllllllhllllllllllllhlhlhlhlhlllljhlhllllljllllljlhjhjllllhlhllhllllibdkbabknnbbkalknnnnmmnnnkkkkknnkbbkknnknkkkkkkkkknnnnnnknnnkkkkkkkkkkkkkkbkkkkkkkkkkkkkbkkbknnknkkkkkkbkkkkkkkbbkbbkkbkkkkkbkbbkkkllhjhllljljljlllhlllhllhlhlhlhlllllhiic`aabbbbbbnmmn`kkbkkkkbbbbbbbbbbbbbbbbbkbbabbbbbbkbbkbbbbkbkbbbbbbaabbabababababaaabababaaabbbbbabaaaaaaaaabaaabaaaab`annnkbka`abbdilllllhllllh", "lhlllhlhlhllllhjhlljljllllllllllhjhjhjhllllllllllllhlhllllhllhlhlhlhlhjllhjhlhllllllllll`ddbddaknmkkb`jnmnnknnkkkkkbkknnkknnkknnnkkkkkkknkknkbkknnnnnnnknnnkbkkkkkkkkkkkkkbkbkbkkkkknnnnnnkkbbbkkkkkkkkkkkbkbkbbkkbbbkkbkkbhllllhlllhlhlhllllllljljljlllljhjlll`ciakakbbkbbbknnakkkbkkkbbbkabbbkaabbbbkkbbbbbbbbbbbbbabbbkbbbkbabbbbababbabababbbbababaababbbbbbbbbbaaaababaaaabaaab`aibnmnkbnb`abbb`ljhlllllhll", "lllhllllhllhlhlllllhlhlhlhllllllllllllllllhlhllhjlljllllllllhllhlhlhlhhhlhhlhlhhhhhhhhhlodddddddknmkdglknknnnnkkkkkkkkkkkkkkknnmkkkknkkbnkkknkknmnnnnnnknkkkkknbkkkkkknnknkkkkkkkkbnnknnnknnnnkbkbkbbbkbkkkbbbbbbkkbbkkkbkkljhlljlhlllllljhjhlllhlhlhlhllhllhlh`i`ababkbbkmbknmakkkbbkbbbbbbbbbabbbbabbbkbbbbbbabbbbbbbbbbbkbbbbbbbbbaabbababbbbbbbabaabbaabbbabbbabbbbaaaaaaaaabaaaa``annnnkbb`bbad`llllhlljlll", "hlhllhlhllhlllhlhllllllllllllllhjhlllhjhlljhjhjhlhlhlhlhlhhhlhhhhhhhhhlhhllhhhhhhhhhhhhhhhhhhhhhghghhhhggghhghhhhhhgg`g`g`o`dddbddbbkkkkkkknnnkmnnmnnnkbnnnkbbbkbkbknkkbnknkkkknnkkkkkknnnnnmnkkkbkbkkkkbkkbkkbbbbkkkknnknklljhjhlljljhjllllljllljlllllhllhllllii`dbbbbbkbnnbkncbbbknkbabbkbbabbbbbbbbbbkbbbbabbbababbbbbbkkbkbbbbbbbabaababbbabababababbababbbbkbbbbbbaaaaaaabaaaabaa``mnmkkbb`bbdddllhllhlhlhl", "ljllllllhllhlhllhlhhlhhlhhhhhhhlhlhhhlhhlhhlhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghghhghghhhhhhhhhhhhhhhhhhhhhhhchhhco`oddkknnmnnkknnnkknkkbbkkkkkkbkkkkkkkknmnnnnnnnnnkkbkbkbkbbkkbkkkkbbbkknkbknkkhlllhllhlhllhlhlhlhllhlhlllllllljhjlii`abbbbakbmnkkkibbbbkbbbbbkbbbabbbbbbakbkbbbkbabaabbabbkbbkbbkbbbbbbbbbbbaaaaabaaababaabbaabbbbbbbbbbbbabaaadaaaaaaabaa`knnkbdaadd`ddhlhlhlhlllh", "lhlhlhlhlhllhlhlhhlhhlhhhlhhlhhhhhhhhhhhhhhhhhhhhhhhgghhggggogoogggghhhhhhhhggggggghhhhhhhhhhhhhhhhhhlghhhhhhhhhgghghhhhlhhhhhghghhhhhhhhhhhhhhhhhhgho`oknknmnnmnkkkbkkkkkkkkkkkkknnnkknnnnnnnkbkbbbkbkbkkkbkkbbkkknnkkkkkblllhllllhlllhlllllllhllllhlhlhjhlllh`i`abbabbbknnnkn`bbbabbbbknkkkbkkbbbbbbbkbbbkkbdbbbbbbbbbbbbkbbkbbabbbbbbbbbaabaabbaabababbbbbbdabbbbbbddadddddddddddddd`kmkdd`higio`ghhhhhhhhhhh", "lhlllhllhlhlhlhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhgggghgggggggggggggghghhhhhhhhhhhhhhhhlljhlhhhhhhhhhhhhhhhhhhgggghhhhghggghghhhhhgghhhhhhhgghhhhghhhlhlhhhhhh`oddnnnnkkkkbkkkkkkkkkbkkknnnnnnnnkbkkkbbkkkbkbkbkbbbbbkkkkbkdblhlllllljhlljhlllllllllllljllllljhlli``aaabbanbnnknncaabbbbbbbbbbabbbbbkkbkbbbbbkkdbbdabbbbabbbbbbbkbabbbbbbbkkbbbbbababbbababaaabdbbkbkkbkdddd`oig`og`ghhhhhhhghhhhghhhhhhhhghhhgghh", "hhhhhhhhhhhhhhhhghgggggggggggggggggggghghghggggghghghggggogggggogggggghhhhhhggoggggghhghhghggggghhhhhhhhhghghhhhgggggghghhhhgggggggggggghhhhhgghhhhghhhhllhhhhhglhgiodddnknnnnnkkkkkknnnkknnkkbbbbbkkbbkbkkkkkkbbbbbbbbdbbdlljhjhjhlljhllllllllllllllhlhjlllljli`i`baabbbbnnkkblbkkkbbbbkbbbbbbbbbbkbbbbbbbkbdabbdddabbbbbbbabbbbbbbabbabbbkbabbbbabbbbbbbdddddkddd`oihhlhhhhghgggghhhhhhhhhghhhhhhhghghghghgggg", "hhhhhhhhhhhhhhghggggghghgghghghgggggggghgggggggggghhhhhhggggggggggggggggggggghhhghghhhhhhhhhhhhhgggghhhhghgggghghggggggggggggggggggghhhhhhghghhhhhhhgghhhhhhhhhhhhlhlhhhhhh`ddkkddbbkkkkkknkkkbkkkkbkkkbbbkbbkknnnnnkbbbkkkllhlllhllhlllhlhlhlhllhllhlllhlhlhlhiii`abbbbakkbba`ibbbbkbbkbbbababbkbbabbkkbbkbdbdbbabbbbbkkbkbbbkbbbbbbbbbabbkkbbbkbkbbdbbddd``o`ohhhhhhhhhhhhhhhlhhhhghggghhhhgghhhggggggggghgggg", "gggggggogggggggggggggggggggggggggggghgggggggggggghghgghhhggggghgggggghhhhhggghhghhhhhhhhhhhhhgggghgggggghhhhhghghhhhghhhghghhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhlhhghhhhhhhhhhhhhhhcg`bknnnnnnnnnnnknnnbbbbbbabkknnnnbbbkmnklllllllllllhllljllljlllllljhjllljlll`i`abababkaa`ii````aababbkkkkkkknnkbbbbbbbkbbabbnbkmnnmknknkkbkkkbbbbbkkkkbbkkddkkddd`gcglhhhhhhhhhhhhhhhhghghhhghhhgggggghghhhhhghhhgggghhhhhhhh", "ggoggogogogoggggoggogoggggggghggggggghhgggggggggggggghghgggggggggggghghhhhhhhghhgghghhhhghgggggggggggghghgggghghhhhhhhhhhhhhhhghghhhhhghhhhhhhhlhhhhhhhhhhhhhhhhlhhhhhhlhhhhhhhlhlhhh`ddknnnknnnkknbnnnkabbbbbknnmnnnnnknnnhlllhjhjhjljlllhlllhllllllllllllhljhi`idkkbbabaiciiiccciabbabbknbbkkkkkbabbbbbbbbaabnnkkkmkknnnnkbbknkbdkkkknkkddo`ooggghhhghhhhhggggghghgghhhhhhhgghgggggggggghgggghggogghggghhhhggg", "ggogoggoggggggoggggggggggggghggghgggggggggggggggghhgghgggggggggghhhhhhhhhhhhhhhhhhhlhhhhhhhhhhhhhhhhhhhhhghhghghhhhhhhhghghhhghgggghhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhhhhlhhhhhgddknnkkknknnkbbkkbbbkmnnnnnnnnnnncjhjlllllhlhlllljllljhjllllllllljllli`ibkkbbba`i`aaiccc`aka``abbkbkkkknnbkbaaabkbabbnnkbkknnnknnnkdddmkddo`gghhhhhhhchghhghhhghggggghgghhhhggghhhhhhhhhhggggghgggogogggghhhhhhhghgggg", "hghghghghghhhhhhhghhhggghhghgggggogggggggggogggghghhgghgggggggggggghhhhhhhhhhghhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhghhhhhhhhggghhhhhhhhhhhhhhhhghghhhhhghhhhhhhhhhghghghhhhhhhhhhhhhhlhhhhhgddbkmmmnkakkkbbbkbbbbbbnnmmnnhlllhjhljlljhjhlhlllhllhjhlllllhlhjhi`idbnkkkb```aa`ii``i```i`abbbbknbnkkbaaabbbbbabkmnkbbnnnmnkddo`oghhhhhgghhghhhhgghggghghgggggggggggghghgggghhhhhgogogggggghggggggghgghhghhhhhhhg", "hhhghhhhhhhhhhhhhhhhghhghgggggggggggoggogoggggggghgghhgghggggggggghhhhhhhhhhghhghhhhhhhhhhhhhhghhhhghggghhhhhhhhhhgggggghhhhhgghghghhghhhhhhhhhhgghhhghhhhhhhhhhggggggggggghhhhhhhhhlhhhhlhhhhhhhhgdddbbbbbabkkkkbbaabkknmnllhllhllhlhllhllllhllllllllhlhllllhli`iabkknkbaaaa`aa```aa`icl`akkkkkkkkka`abaabbbbbbkndddndkd`oghhhhhhhhhhhhhghghhhghggggggghgggggoggggooggghhgogggghghhhgggggggggghhghghgghgghghggh", "ggghghhhhhhhlhhhhgggggghgggghghghggggggoggggggggggghhghhhgggggghhhhhhhhhhghhhhghghhhhhhlllhhhhhhhhhhhhhhhhhhhhhhgghggggggghgggggggggggggggghgggghhhhggghghghhhhhgghghhhhhgghghhhhlhhhhhlhhhhlhhhlhlhhhhi`dkdddbbknkkkkkknnmlllhlllhlllhllhlhllhlhlhlhllllhlhlll````bbbbbabbaaabka`akkbicliannkkkbkkba`abbbdkkkbdkkdo`ghhhhhhhhhggghghhggggghggggghhgghghhggggoggghhhhghhhhhhhghgghhhhggohghhhhhgggogogggggggghgh", "hghghghhhhhhhhhhhhgggggggghghghggggghggggggggggggggggggghhhhghghhhhhhhhgghggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhghggggggghghhhghggghghghhhhhhhhhhhhhhhhhhghhhhhhlhhhgggghhhhhhhhhhhhhhhhhhhhhhhlhhlhllhhhhh`dkkdkbbbbbbbkknlhlchlhllhllhlllllhlllllhllhlhlllhlhi`i`bbbbbbbbbabbbbaakkaiiliaknkkbkbbaddbddddddddohhhhhhhhhhhhhhhhggggggggggghhhhhggghghhhhgggoggggggggggghgggggggghghhhhhhhhhghggggggggggggghhhhh", "gggggghghhhhhhhhggggggghhhghhhghhhgggggggggggggggogggggghgghgggggggggghhhhhhggggggggghhhhhhhhhhhgggghggghhhhhhhghgggggghhhhhhghghhhhhhhhhhhhhhhghhhghhhhhhhhhhhhhhhlhhhhgghgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdnmnnnkbbbkblllllhlchlchlchlhllhlhchlchllchcllcliiiabakbbkbaaaaabaaakaaicciabknbbkbaddbddo`gggghhhhhhhhggggggghhgggggoggggggggogggggghghhhhghgggghhhhghhhhhggggggggggggggggggggggogoogggggggggggg", "ghhhhhhhhhhhhghggggggghhhhhhhhhhgggggggggggggoggggggggghggggghghhhhhhhhhhhggghggghgghghghhhhhhhhhhhhhhhhhhhhhghggggggggghghghhghggghhhhllllhhhhgghgggghgghghhhhhhlhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhlhhhhlhlhhlhh`dknmkkbbdlllhlchllhllchllchlchllclllchlllhchlgciabbkbbbbabbbabbabbaailcc`abkkbd`iiihhhhhhhhgghghghgggggggggghhghggggoggogggggggghhhhghgggggggggggghggggghhgggggghggggghggggogogogggggggggghhhh", "hhhhhhggggggghghhhhhhhhhhhhhhhhhhhhhhhhhhggggggohggggggggghhhhhhhhhhhhggggggggghghghghhhhhhhhhhhlhlhlhhhhhhgggggggggghghghhghhhhhhhhhhhlhhhhhhhggghhhhhhhhhhghghhhhhhhgggghhhhhhhhhhhhhhhhhhhhlllhhhhhhhhhhhlhhhllhlgakmkdglhlllllclcclllchllchlchlhchllhcllllccciabbabbbbbbababbaaaiiiiii`ddd`dgghhghhggghhhghhgggggggggggggggggggggogggggghhhhhhgggggggghhhhhhgghgggggggggggoggggghghggggggggggggggggghhghgggg", "hhgggggggggghhhhhhhhhhlhhhhhhhhhhlhhhhhhgghghhhhhhhhhgggghghhhhhhhhhhhgggggggghgggggggggggggghhhhhhhhhhhhgggggggggggggggghhhhhhhhhghhhhhhlhhhhhhgghhhhjljllhhgggghghhhhghghgghhhhhhlhhhhhhhhhhhhlhlhhhhhhhhhhhhhhhhhhhhg`gchllhlhlljjjjljjljljllllllllllllhllhllhidbbaabaabbkkbbbbaa````igioihhhhghghhhghhgggggggggghhhhgggggggghhhgghgggggghghhgghhhhggggggogggggggggggghggggggoggggggoggghhhhhhhhhhhhhgggggggg", "ggggggogggghghhhhhhhhhhhhhhhhhhhhhhhhggghghhhghhhhhhghghgghghhhhhhhhhgggggggggghgggggggggggghghhhhhhhhhgggggggggggghgggghhhghhhhhghghhhhhhhhhhhhhgghhlhjhjhhhhgghhhhhhhhhhghghghhhhhhhhhhhhhlllhhhhhhhhhhhhhhhhhhhhhhjhlhlhlhlhjjjjjjjjjjjjjjjjjjjjjjjjjjljllllhiiidbababbabbbknnkkdido`hhhhhhhhhhghgghghggghhgghgggggggggoggggoggggogggggoggggghgggggghggggggghgggggghhghggggogogghhggggggggggghhhggggggghggggg", "ogogoggggggggggghghggggghhhghggghghghggggghghhhghghghhgggggggggghhhhghgggggggggggggggggggghgggggggghggggggggggggggghghhhhghhhhhhggghhhhhhhhhhhhhhgghhhhhhlhjhhhhhhhhghhhhhhhhghhhhhhhhhhhhhhhhhlhhhhhhhhhhhhlhhhhhhhjhhhlhlhlhllljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc`iibbbbbaaakbdkkkddighhhhhhhhhghgggggggghgghhhhghgggggggggggggggggogggggoggggggggghggggggggggggggogogghghhgggggggghhhhhhhhgghghhghghghhhgggggogo", "ggogogogggggghhhhhhhhhhhhhghgghhghhhghhhgggggghhghgggghggggghhhhhhhghhhhgggggggggggggggghhghgggggghghghhghhhhgggggghghhghhhhhhggghghhhhhhhhhhhhhgghghhljhjhhhhhhhhghghgghhhhhhhghhhhhhhhlhhhhhhhhhhhhhghhhhhhhhhhhhhhhllhhhhlhlllljjjjjjjjjjjjjjjjjjjjjjjjjjjjlli``bababbddddddogggghhhhhghghgghgggggggghggghggggggggggoggoggggggggggggggggghgggggggggggggggggogggggghghghgggggogghhhhhhggggggggggggogogggoggogo", "oogogogogogghgghhhhhhhhhhhhhhhhhhhhhhhgggggggggghghhhghghghhhhhhhhghgghghhhghhhhhhhhhhhhhghggggghgghghgghgghghhhgghghhghghhhhhhghhhhhhhhhhhhhhhhghghhhhhlhhhhhhhghhhhghhhhhhhhhhhhhhhhhhlhhlhhhhhhhhgghhhghhhhhhhhhhhhhhlhhhhhhhhlhlljjjjjjjjjjjjjjjjjjjjjjjjjjjiiibabbdbd`oghhhhghhghhohhhgggggghghgggghgggggggggggggogggggggogoggggggggogghhggggogoogggggogggggogggggggggggggggggghhgggggggggggggggggggogoogoo", "ggogoggggggggghhhhhhhhhhhhhhhhhhhhgggggghhghhhhhhhhhhhhhhhhhhhhhgghggggggghhghhhhhhghggggggghggghghghghgghhhhhghhhghhghghggggggghhhhhhhhhghgggggghhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhghhhlhhhhhlhhhhhlhlhlhhhlhjljjjjjjjjjjjjjjjjjjjjjjjjl```kbbd`ggihhhhgggghhghhghhghhhhggggggghgggggghhghggggggoogggggggggggggggoggggggggghhggogggggoggghhhhhhhgggggghgghghgggggggogogggggggggggggggogg", "ggggggogggggghhhhhhhhlllhlhhhhhhgghhhhhhghhhhhhhhhhhhhhhhhhhhhhhhghghghghhhhhhhhhhhhhghggghghghghhhhhhghhhhhhhhhhhhhhhhgghhggghhghghhhhgghgggggggghhhhhhhhhhhghghhhhhhhhhhhhhhhhllhhhhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhlhhhhlhhhhhhhlhlhjjjjjjjjjjjjjjjjjjjjjjlhi``ddihhhhhhhghhhghhhghhghhhhhhggggggggggggghhghgghgggggggogghhhghhgooogggogggggggggggggogoggggggogggggoggghghhhghhggogggghhhhghgggggggggggogggg", "gggggggghhhhhhhhhlhhhhhhhhhhhhghghhghghhhghghhhhhhhhhhhhhhhhhhgghgggghghhghhhhhghgggggggghgggggggggggghhhhhhhhhhhhhhhghhhggggggggggghghghghggggghhhhhhlhhhhhhhghhhhhhhhhhhhghghhhhhhhhhhhhghhhhghhhhhhhhhhhhhhhhllhhhhhhhhhhlhhhhhhhlhlhlhjjjjjjjjjjjjjjjjjjhlhcgggghghhhhhgghghgghgghgggggghhhhgggggghggggghhhgghhgggggogoggggghggghhgoogogoogggooogogogoggogogogogoggghhgggghhhhhghhgoghghhghhhhhhhgggoogggggh", "ghghhhhhhhhhlhhhhhhhhhhhghhhhghhghghhghghhghggghhhhhhhhhhhhhghhhgghghghggghghghghghhghhghggghghgggggggghhhhhlhlhhhhhhhghhhhghggggggghghghgghgggggghhhhhhhhhghhhhhhhhhghhgghgggghhhhhhhhhghhhhhghhhhhhhhhhhhhhhhhhhllhhhhhhhhhhhhhhhhhhhlhlllljjjjjjjjjjjjljlhllhhghhghghhghgggghgghggggghhhhhhhhhghggggghgggggggghhggggogggogogggggggggggggggoggogggggggggggogoggghggggggghggggogggggggggoggggggoggggggggggggggg", "hhhhhhhlhhhhhhhhhhhhhhhhhhghghghghghggggggggggggghhhhhhhhghghggggghghhghhhhhhhhghggghgghghhggggggggggggghhhhhhhhhhhhhhhhghgggghghgghghhghghgghggghhhhhhhhgggghghghghgghghghghhhhhhhhhlhhhhhghhghhhhhhhhhhhhhhlhhhhhhhhhhhhhhhhhlhhhhhlhhhlhhhhjljjjjjjllhhhhhhhhhhhggggogghhghhhggggggggggggghhhhhgghggghgggggggghhhhgggggggogoggggggggggggogogoggggggggggggggggggggggogggggggggogggggggoggggggghggghggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhghhggggggggggggggggoggggggghghhghghghgghgghghhhhhhhhhhhghghgggggghghhhghggggghghhhhhhhhhhhhhhghhghhhghghgggghhghghghhhhhhghhhhghghgggggghggghghhhhhhhhhhhhhhhhhhhgggghhhhhhhhllhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhlhhlhlhhhlljjhjhlhlhhhhhhggggggggggggggggggggooggggggggggggggghghggggoggghgghhggggggggogogggooogggggoggogogogoggghghghhggggggggggooghhhhhgogggooggggogggghhhggggggghghghg", "hhhhhhhghhhhhhhhhhhhhhhhghggggggggghhhghgggggggggghhghhhgghghghghghghhhhhhhhhgggggggghhghghghgghgggggggggggghhhhhhhhhhhhhhhhhhhggggghhhhhhhhghhhhhhhhhhgghghhhhghgghgghghghghhhhhhlhlhlhhhhhhhghhhhhhhhhhhhhhhhlhhhhhhghghhhhhhhhhhhhhlhhlhlhhlhhlhlhlhhhhhghhggggogggogggggghggggggghhggggggghgggggggggghggogggghghhggogggoggggoogggggggoggggggoggggggggggggggggggggggogggghhhghgggggggogoggggggggggggoggghhhhh", "hhhhhhhhhhhhhhhhhhhhhhhggggggggggghghhhghhgggggggggghhghhhhghghggghhhhhhhhhhhghgggggggggghghghgggggogggggghhhghggghgghghhhhhhhhghgghghhhhhhhghghhhhhhghggghghhhhhhghghhghhghhhhhhhhlhjhlhhhhhhghhhhhhhhhhhhhhhhhhhhhhghhghghhhhhhhhhhhhlhlhhhhhhhhhlhhhgghggggggggghggghggghghhggoggghhhggggggggggghhgggghggggggghhhhgggogoggogoggggggggggghghgggggoggggogoogggggogggoggggghggggggoogogggggggghghghggogogogoggog", "hhhhhhhhhhhhhggggggggggggggggghghghhhhhhgggggogggghgghhhhhhggggghghhhhhhhhhhghgggggggggghghhghgggogogggghhhhhggghggghghghhhhgggggghhhhhhhhhghggghhhhhhhghgghhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhgghhghhhhhhghhhhhhhhhhhhgghhhhghhhlhhhhhhhhhhhhhhhhllhhlhhhhggggggoghghggoggoggggggggggghhgggggghggghghgggggggggggghhhhhgoogoggoggggooggghggggggggghggogoggggggggggggoggggggghghhhhggggggoggghgggggggggooooogogoggg", "hghhhhhhhhhhggggggggggghhhhhhhhhhhhhhhhgghgggggggghghhhhhghghghhhhhhhhhhhhhggggggggggghhhhghhggggggggghghghgghhghghgggggghggghghgghhhhhhhhhhgggggghhhhhhhhhhgghghhhhhhhhhhhhhhhhlhhhhhhhhhhhhggghhhhhhhgghghhhhhhghghhhghghhhhhhhhhhhhhhhlhlhlhhhhlhhhhhgggggggggghgggggoggggggggggghhhggghggggggggggggggoogggghhhhgoggggggggggggogghhhggggogghhghggghggghgggggggggogooogghhhghhhhhggggghhgggogogogoogogoogogogg", "ghghhhhhgggggggghhhhhhhhhhhhhhhhhhhhhhgghgggghghghghghgggggghhhhhhhhhhhhhhggggggggghghghggggghghgghhhhhhhhhhggggggggggggggghgghggghghhhhhhhgghghhhhghhhhhhhhhhhhhhhghhhhhhhhhhllhlhhhhhhhhhhhhghghhgggghhhhhhhhhhhhghghhghhhghhhhhhhhhhlhhhlhlhhlhhhhhhlghhggoggggggogghggogggggggghhghghggghgghggoggogggggggoogggggggggogoggogogggogghhggogghhhhhggggghhggggoooooooogggoggggghhghhhgghggggggogoghgghgggggoggggg", "ghghggggggggggggghghhhhhhhhhlhhhhhhhhhhhgghggghggggggggghghhghghhhhhhhghhggggggggggggggggggggggghhghghhhhhhghgghghggggogggggggggggghhhhhhggggghghhhhghhhhhhhhhhhggghhhhhlhlhlhhlhhhhhhhhhhhhhghghghhhghhgghhhhlhlhhhghghhhghhhhhhhhhhhhhhhhlhhhhhhhlhhhhhlhhhggoggggggooggggoggggggghhhhggggghgggggggggggggogogghgggggghhggggggghhgggggogoggggggggggggggggggggogogoggooggggggggggggggogoggggoggggggggghggggogggg", "hgggggghghggghghgghghhhhhhhhhhlhhhhhhhhghghhhghgggggghhhghghghhhhhhghghgghghhgggoogogogggghghhgghgghghghghghgghgggggggggggghggggggggghhggggghghhhhghghggghghhhhhhhghhhhhhlhlhlhhhhhhghhhlhhhhhgghhhhhhgghhhhhhhhhhhhhhhghghhhhhhhhhhhghhhhhhhhhhlhhhhhhhlhhhhhhhgggggghhggooggggggoggggggggghghhgooggggogogggggggggghhhhhhgggoghhhggogooggggggggggggogghhggogogoggoggggogggggggggggogogggooogoggoggggggggoggoggg", "ghghghhghhhhhghgggggghhhhhhhlhhhlhhhhhghghghhghggggggghhgggghgggggghhhhhhhhggggggggoggggghghhhhghgggggggggggggggggggggoggghghghgggggggghggggggggghhhhghghgghhhhhhhghhlhhlhhlhlhhhhhghhhlhllhhhhhhhhhhhhhhhhhhhhhhhhhhhgggghhhhhhhhlhhhhhhhlhlhhhlhhhhhhhhlhhhhhhhhggggggogoggggggggggggggghggghgggoogogoggoogogggggghhhhhhgggggggggggogggggggooggogoggghgggoogoogoggogogoggghgggggggggggghggggggggggggggoggogogg", "hhhhhhhhhghghggggggghhhhhhhhhhhhhhhhhhgggggggggggggghgggghgggghghghhhhhhhhgggggggoggggghhhhhhhhhghgghghhggggggggggggggggggggggggggghghghgghghgghhhhghghgghhhhhhhhggghhlhlhlhlhlhhhghhhhhlhlhhhhhhhhhhhhhhhhhhhhhhhhhhgggghhhhhhhlhhlhlhhlhhlhhhhhhhllhhhhlhhhhhhhhggggghggghggghgghhgggghhggggghggggoggggoggggggggogggghhhgghggggghgggggghgggggggggggggggooggogggggogogoggggghggggoooogoggggggggggggggggggoggggg", "hhhhhhhhghggggggggghghhhhhhhhhhhhhhhhggggggggggggggggggggggghghghhhhhhhggggggggoggggghhhhhhhhhhhhghgghggggggghghggggogggogggggghgghggghghghgggggggghghhhhhhhlllhhhghhhhhlhhlhlhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhgghhjljhlhhlhlhhlhhhhhhlhhhhlhjhhlhhjhhhhhggghhhoghhgggggghhggggogggghhggggggggoggggggggggggggoggghgggggghhggogggghgggggogggggoggggghghghhhgggggggggggggoggggggggggggogggoggggggogogggg", "hhhhggggggggggggggghhhhhhhhhhhhhhhhggggggggggggghhhghghghghgghgghhhghgggghgggggggggghhhhhhhhhhhhghghggghgghhhhhghgggggggggggghggghgghgghhhgghgghghhgghghhhlllhlhhhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhlllhlhhhhhhhhhghhhhhhhhhhhhhhhlhjhlhhlhhhhhhhhhlhlhhhhllhhlhjhllhhlhlhggggogooggggggggogggggoggggggooggogggggggggggggggggggghggggggggogoggggggooogogggggggggghghhhhhhhhhhhhggggggggoggghhhhhggggogggghggggoooogg", "gggggghggggggggggghgghhhhhhhhhhghgghghggggggggghggggghghggghggghghggghghhhghgggghghhghhhhhhhhhhghhhghggggggghhghghgggggogoggggghgghghghhghghgghghhhghghhhhlhhlhlhhhhhhhhhhhhhhhhhhhghhhhhhhgghhhhlhjhlhlhhhhhhhhhhhhhhhhhhhhhhhhlljlhhhlhhhhhhhhhhlhjhhhjhlhhhgjhhhhhhhhoggoogggoogghggghgggggggggoggggogoggoogggggghgghggghggggggogogogoooggghggoggggggggghhhhhhhhhhhhhhhhggghgggogoggghhhhhggogoghhhhhhgggggog" }; nethack-3.6.0/sys/amiga/ifchange0000664000076400007660000000215012536476415015533 0ustar paxedpaxed.KEY oper/a,tmp/a,real/a,f1,f2,f3,f4,f5 . ; miscellaneous script functions for the Amiga . ; Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993, 1996. . ; NetHack may be freely redistributed. See license for details. FAILAT 6 IF EQ "MOVE" IF EXISTS diff >T:mic -c search from T:mic SEARCH "---" QUIET IF WARN echo "MOVE: no change" delete ELSE echo "MOVE: copy" copy clone delete ENDIF ELSE echo "MOVE: copy2" copy clone delete ENDIF QUIT ENDIF IF EQ "TOUCH" IF EXISTS diff >T:mic -c search from T:mic SEARCH "---" QUIET IF NOT WARN echo "TOUCH: touch" IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF ENDIF ENDIF QUIT ENDIF echo "ifchange: '' not recognized" quit 10 nethack-3.6.0/sys/amiga/mkdmake0000664000076400007660000000055612536476415015410 0ustar paxedpaxedGE/$@/%(left)/ GE/$ #include "config.h" #include "tile.h" #include #include #include #include #include #include #include #include #include #include #ifndef _DCC #include #include #include #endif void panic(const char *); void map_colors(void); int BestMatch(int, int, int); extern pixval ColorMap[3][MAXCOLORMAPSIZE]; extern int colorsinmap; /* * WARNING: * This program carries forth the assumption that the colormaps in all * of the .txt files are the same. This is a bug. */ struct { int Height; int Width; } IFFScreen; /* * We are using a hybrid form of our own design which we call a BMAP (for * bitmap) form. It is an ILBM with the bitmaps already deinterleaved, * completely uncompressed. * This speeds the loading of the images from the games point of view because * it * does not have to deinterleave and uncompress them. */ #define ID_BMAP MAKE_ID('B', 'M', 'A', 'P') /* instead of ILBM */ #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* Same as ILBM */ #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* Same as ILBM */ #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* Same as ILBM */ #define ID_PDAT \ MAKE_ID('P', 'D', 'A', 'T') /* Extra data describing plane \ * size due to graphics.library \ * rounding requirements. \ */ #define ID_PLNE MAKE_ID('P', 'L', 'N', 'E') /* The planes of the image */ #ifndef _DCC extern #endif struct Library *IFFParseBase; int nplanes; /* BMHD from IFF documentation */ typedef struct { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE reserved1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; } BitMapHeader; typedef struct { UBYTE r, g, b; } AmiColorMap; pixel pixels[TILE_Y][TILE_X]; AmiColorMap *cmap; int findcolor(register pixel *pix); void packwritebody(pixel (*tile)[TILE_X], char **planes, int tileno); void error(char *str) { fprintf(stderr, "ERROR: %s\n", str); } /* * This array maps the image colors to the amiga's first 16 colors. The * colors * are reordered to help with maintaining dripen settings. */ int colrmap[] = { 0, 6, 9, 15, 4, 10, 2, 3, 5, 11, 7, 13, 8, 1, 14, 12 }; /* How many tiles fit across and down. */ #define COLS 20 #define ROWS ((tiles + COLS - 1) / COLS) main(int argc, char **argv) { int colors; struct { long nplanes; long pbytes; long across; long down; long npics; long xsize; long ysize; } pdat; long pbytes; /* Bytes of data in a plane */ int i, cnt; BitMapHeader bmhd; struct IFFHandle *iff; long camg = HIRES | LACE; int tiles = 0; char **planes; if (argc != 3) { fprintf(stderr, "Usage: %s source destination\n", argv[0]); exit(1); } #if defined(_DCC) || defined(__GNUC__) IFFParseBase = OpenLibrary("iffparse.library", 0); if (!IFFParseBase) { error("unable to open iffparse.library"); exit(1); } #endif /* First, count the files in the file */ if (fopen_text_file(argv[1], "r") != TRUE) { perror(argv[1]); return (1); } nplanes = 0; i = colorsinmap - 1; /*IFFScreen.Colors - 1; */ while (i != 0) { nplanes++; i >>= 1; } planes = malloc(nplanes * sizeof(char *)); if (planes == 0) { error("can not allocate planes pointer"); exit(1); } while (read_text_tile(pixels) == TRUE) ++tiles; fclose_text_file(); IFFScreen.Width = COLS * TILE_X; IFFScreen.Height = ROWS * TILE_Y; pbytes = (COLS * ROWS * TILE_X + 15) / 16 * 2 * TILE_Y; for (i = 0; i < nplanes; ++i) { planes[i] = calloc(1, pbytes); if (planes[i] == 0) { error("can not allocate planes pointer"); exit(1); } } /* Now, process it */ if (fopen_text_file(argv[1], "r") != TRUE) { perror(argv[1]); return (1); } iff = AllocIFF(); if (!iff) { error("Can not allocate IFFHandle"); return (1); } iff->iff_Stream = Open(argv[2], MODE_NEWFILE); if (!iff->iff_Stream) { error("Can not open output file"); return (1); } InitIFFasDOS(iff); OpenIFF(iff, IFFF_WRITE); PushChunk(iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN); bmhd.w = IFFScreen.Width; bmhd.h = IFFScreen.Height; bmhd.x = 0; bmhd.y = 0; bmhd.nPlanes = nplanes; bmhd.masking = 0; bmhd.compression = 0; bmhd.reserved1 = 0; bmhd.transparentColor = 0; bmhd.xAspect = 100; bmhd.yAspect = 100; bmhd.pageWidth = TILE_X; bmhd.pageHeight = TILE_Y; PushChunk(iff, ID_BMAP, ID_BMHD, sizeof(bmhd)); WriteChunkBytes(iff, &bmhd, sizeof(bmhd)); PopChunk(iff); PushChunk(iff, ID_BMAP, ID_CAMG, sizeof(camg)); WriteChunkBytes(iff, &camg, sizeof(camg)); PopChunk(iff); /* We need to reorder the colors to get reasonable default pens but * we also need to know where some of the colors are - so go find out. */ map_colors(); cmap = malloc((colors = (1L << nplanes)) * sizeof(AmiColorMap)); for (i = 0; i < colors; ++i) { cmap[colrmap[i]].r = ColorMap[CM_RED][i]; cmap[colrmap[i]].g = ColorMap[CM_GREEN][i]; cmap[colrmap[i]].b = ColorMap[CM_BLUE][i]; } PushChunk(iff, ID_BMAP, ID_CMAP, IFFSIZE_UNKNOWN); for (i = 0; i < colors; ++i) WriteChunkBytes(iff, &cmap[i], 3); PopChunk(iff); cnt = 0; while (read_text_tile(pixels) == TRUE) { packwritebody(pixels, planes, cnt); if (cnt % 20 == 0) printf("%d..", cnt); ++cnt; fflush(stdout); } pdat.nplanes = nplanes; pdat.pbytes = pbytes; pdat.xsize = TILE_X; pdat.ysize = TILE_Y; pdat.across = COLS; pdat.down = ROWS; pdat.npics = cnt; PushChunk(iff, ID_BMAP, ID_PDAT, IFFSIZE_UNKNOWN); WriteChunkBytes(iff, &pdat, sizeof(pdat)); PopChunk(iff); PushChunk(iff, ID_BMAP, ID_PLNE, IFFSIZE_UNKNOWN); for (i = 0; i < nplanes; ++i) WriteChunkBytes(iff, planes[i], pbytes); PopChunk(iff); CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); printf("\n%d tiles converted\n", cnt); #if defined(_DCC) || defined(__GNUC__) CloseLibrary(IFFParseBase); #endif exit(0); } findcolor(register pixel *pix) { register int i; for (i = 0; i < MAXCOLORMAPSIZE; ++i) { if ((pix->r == ColorMap[CM_RED][i]) && (pix->g == ColorMap[CM_GREEN][i]) && (pix->b == ColorMap[CM_BLUE][i])) { return (i); } } return (-1); } void packwritebody(pixel (*tile)[TILE_X], char **planes, int tileno) { register int i, j, k, col; register char *buf; register int across, rowbytes, xoff, yoff; /* how many tiles fit across? */ across = COLS; /* How many bytes per pixel row */ rowbytes = ((IFFScreen.Width + 15) / 16) * 2; /* How many bytes to account for y distance in planes */ yoff = ((tileno / across) * TILE_Y) * rowbytes; /* How many bytes to account for x distance in planes */ xoff = (tileno % across) * (TILE_X / 8); /* For each row... */ for (i = 0; i < TILE_Y; ++i) { /* For each bitplane... */ for (k = 0; k < nplanes; ++k) { const int mask = 1l << k; /* Go across the row */ for (j = 0; j < TILE_X; j++) { col = findcolor(&tile[i][j]); if (col == -1) { error("can not convert pixel color to colormap index"); return; } /* Shift the colors around to have good complements and to * know the dripen values. */ col = colrmap[col]; /* To top left corner of tile */ buf = planes[k] + yoff + xoff; /*To i'th row of tile and the correct byte for the j'th * pixel*/ buf += (i * rowbytes) + (j / 8); /* Or in the bit for this color */ *buf |= (((col & mask) != 0) << (7 - (j % 8))); } } } } /* #define DBG */ /* map_colors * The incoming colormap is in arbitrary order and has arbitrary colors in * it, but we need (some) specific colors in specific places. Find the * colors we need and fix the mapping table to match. */ /* What we are aiming for: */ /* XXX was 0-7 */ #define CX_BLACK 0 #define CX_WHITE 1 #define CX_BROWN 11 #define CX_CYAN 2 #define CX_GREEN 5 #define CX_MAGENTA 10 #define CX_BLUE 4 #define CX_RED 7 /* we don't care about the rest, at least now */ /* should get: black white blue red grey greyblue ltgrey */ void map_colors() { int x; #if 1 int tmpmap[] = { 0, 2, 3, 7, 4, 5, 8, 9, 10, 11, 13, 15, 12, 1, 14, 6 }; /* still not right: gray green yellow lost somewhere? */ #else int tmpmap[16]; int x, y; for (x = 0; x < 16; x++) tmpmap[x] = -1; /* set not assigned yet */ tmpmap[BestMatch(0, 0, 0)] = CX_BLACK; tmpmap[BestMatch(255, 255, 255)] = CX_WHITE; tmpmap[BestMatch(255, 0, 0)] = CX_RED; tmpmap[BestMatch(0, 255, 0)] = CX_GREEN; tmpmap[BestMatch(0, 0, 255)] = CX_BLUE; /* clean up the rest */ for (x = 0; x < 16; x++) { for (y = 0; y < 16; y++) if (tmpmap[y] == x) goto outer_cont; for (y = 0; y < 16; y++) if (tmpmap[y] == -1) { tmpmap[y] = x; break; } if (y == 16) panic("too many colors?"); outer_cont: ; } for (x = 0; x < 16; x++) if (tmpmap[y] == -1) panic("lost color?"); #endif for (x = 0; x < 16; x++) { #ifdef DBG printf("final: c[%d]=%d (target: %d)\n", x, tmpmap[x], colrmap[x]); #endif colrmap[x] = tmpmap[x]; } } BestMatch(r, g, b) int r, g, b; { int x; int bestslot; int bestrate = 99999999L; for (x = 0; x < 16; x++) { int rr = r - ColorMap[CM_RED][x]; int gg = g - ColorMap[CM_GREEN][x]; int bb = b - ColorMap[CM_BLUE][x]; int rate = rr * rr + gg * gg + bb * bb; if (bestrate > rate) { bestrate = rate; bestslot = x; } } #ifdef DBG printf("map (%d,%d,%d) -> %d (error=%d)\n", r, g, b, bestslot, bestrate); #endif return bestslot; } long * alloc(unsigned int n) { long *ret = malloc(n); if (!ret) { error("Can't allocate memory"); exit(1); } return (ret); } void panic(const char *msg) { fprintf(stderr, "PANIC: %s\n", msg); exit(1); } nethack-3.6.0/sys/amiga/winami.c0000664000076400007660000015437312536476415015513 0ustar paxedpaxed/* NetHack 3.6 winami.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #include "dlb.h" #ifdef AMIGA_INTUITION static int FDECL(put_ext_cmd, (char *, int, struct amii_WinDesc *, int)); struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ struct Rectangle lastinvent, lastmsg; int clipping = 0; int clipx = 0; int clipy = 0; int clipxmax = 0; int clipymax = 0; int scrollmsg = 1; int alwaysinvent = 0; int amii_numcolors; long amii_scrnmode; /* Interface definition, for use by windows.c and winprocs.h to provide * the intuition interface for the amiga... */ struct window_procs amii_procs = { "amii", WC_COLOR | WC_HILITE_PET | WC_INVERSE, 0L, amii_init_nhwindows, amii_player_selection, amii_askname, amii_get_nh_event, amii_exit_nhwindows, amii_suspend_nhwindows, amii_resume_nhwindows, amii_create_nhwindow, amii_clear_nhwindow, amii_display_nhwindow, amii_destroy_nhwindow, amii_curs, amii_putstr, genl_putmixed, amii_display_file, amii_start_menu, amii_add_menu, amii_end_menu, amii_select_menu, genl_message_menu, amii_update_inventory, amii_mark_synch, amii_wait_synch, #ifdef CLIPPING amii_cliparound, #endif #ifdef POSITIONBAR donull, #endif amii_print_glyph, amii_raw_print, amii_raw_print_bold, amii_nhgetch, amii_nh_poskey, amii_bell, amii_doprev_message, amii_yn_function, amii_getlin, amii_get_ext_cmd, amii_number_pad, amii_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ amii_change_color, amii_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ amii_delay_output, amii_delay_output, amii_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif genl_can_suspend_yes, }; /* The view window layout uses the same function names so we can use * a shared library to allow the executable to be smaller. */ struct window_procs amiv_procs = { "amitile", WC_COLOR | WC_HILITE_PET | WC_INVERSE, 0L, amii_init_nhwindows, amii_player_selection, amii_askname, amii_get_nh_event, amii_exit_nhwindows, amii_suspend_nhwindows, amii_resume_nhwindows, amii_create_nhwindow, amii_clear_nhwindow, amii_display_nhwindow, amii_destroy_nhwindow, amii_curs, amii_putstr, genl_putmixed, amii_display_file, amii_start_menu, amii_add_menu, amii_end_menu, amii_select_menu, genl_message_menu, amii_update_inventory, amii_mark_synch, amii_wait_synch, #ifdef CLIPPING amii_cliparound, #endif #ifdef POSITIONBAR donull, #endif amii_print_glyph, amii_raw_print, amii_raw_print_bold, amii_nhgetch, amii_nh_poskey, amii_bell, amii_doprev_message, amii_yn_function, amii_getlin, amii_get_ext_cmd, amii_number_pad, amii_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ amii_change_color, amii_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ amii_delay_output, amii_delay_output, amii_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif genl_can_suspend_yes, }; unsigned short amii_initmap[AMII_MAXCOLORS]; /* Default pens used unless user overides in nethack.cnf. */ unsigned short amii_init_map[AMII_MAXCOLORS] = { 0x0000, /* color #0 C_BLACK */ 0x0FFF, /* color #1 C_WHITE */ 0x0830, /* color #2 C_BROWN */ 0x07ac, /* color #3 C_CYAN */ 0x0181, /* color #4 C_GREEN */ 0x0C06, /* color #5 C_MAGENTA */ 0x023E, /* color #6 C_BLUE */ 0x0c00, /* color #7 C_RED */ }; unsigned short amiv_init_map[AMII_MAXCOLORS] = { 0x0000, /* color #0 C_BLACK */ 0x0fff, /* color #1 C_WHITE */ 0x00bf, /* color #2 C_CYAN */ 0x0f60, /* color #3 C_ORANGE */ 0x000f, /* color #4 C_BLUE */ 0x0090, /* color #5 C_GREEN */ 0x069b, /* color #6 C_GREY */ 0x0f00, /* color #7 C_RED */ 0x06f0, /* color #8 C_LTGREEN */ 0x0ff0, /* color #9 C_YELLOW */ 0x0f0f, /* color #10 C_MAGENTA */ 0x0940, /* color #11 C_BROWN */ 0x0466, /* color #12 C_GREYBLUE */ 0x0c40, /* color #13 C_LTBROWN */ 0x0ddb, /* color #14 C_LTGREY */ 0x0fb9, /* color #15 C_PEACH */ /* Pens for dripens etc under AA or better */ 0x0222, /* color #16 */ 0x0fdc, /* color #17 */ 0x0000, /* color #18 */ 0x0ccc, /* color #19 */ 0x0bbb, /* color #20 */ 0x0BA9, /* color #21 */ 0x0999, /* color #22 */ 0x0987, /* color #23 */ 0x0765, /* color #24 */ 0x0666, /* color #25 */ 0x0555, /* color #26 */ 0x0533, /* color #27 */ 0x0333, /* color #28 */ 0x018f, /* color #29 */ 0x0f81, /* color #30 */ 0x0fff, /* color #31 */ }; #if !defined(TTY_GRAPHICS) \ || defined(SHAREDLIB) /* this should be shared better */ char morc; /* the character typed in response to a --more-- prompt */ #endif char spaces[76] = " " " "; winid WIN_BASE = WIN_ERR; winid WIN_OVER = WIN_ERR; winid amii_rawprwin = WIN_ERR; /* Changed later during window/screen opens... */ int txwidth = FONTWIDTH, txheight = FONTHEIGHT, txbaseline = FONTBASELINE; /* If a 240 or more row screen is in front when we start, this will be * set to 1, and the windows will be given borders to allow them to be * arranged differently. The Message window may eventually get a scroller... */ int bigscreen = 0; /* This gadget data is replicated for menu/text windows... */ struct PropInfo PropScroll = { AUTOKNOB | FREEVERT, 0xffff, 0xffff, 0xffff, 0xffff, }; struct Image Image1 = { 0, 0, 7, 102, 0, NULL, 0x0000, 0x0000, NULL }; struct Gadget MenuScroll = { NULL, -15, 10, 15, -19, GRELRIGHT | GRELHEIGHT, RELVERIFY | FOLLOWMOUSE | RIGHTBORDER | GADGIMMEDIATE | RELVERIFY, PROPGADGET, (APTR) &Image1, NULL, NULL, NULL, (APTR) &PropScroll, 1, NULL }; /* This gadget is for the message window... */ struct PropInfo MsgPropScroll = { AUTOKNOB | FREEVERT, 0xffff, 0xffff, 0xffff, 0xffff, }; struct Image MsgImage1 = { 0, 0, 7, 102, 0, NULL, 0x0000, 0x0000, NULL }; struct Gadget MsgScroll = { NULL, -15, 10, 14, -19, GRELRIGHT | GRELHEIGHT, RELVERIFY | FOLLOWMOUSE | RIGHTBORDER | GADGIMMEDIATE | RELVERIFY, PROPGADGET, (APTR) &MsgImage1, NULL, NULL, NULL, (APTR) &MsgPropScroll, 1, NULL }; int wincnt = 0; /* # of nh windows opened */ /* We advertise a public screen to allow some people to do other things * while they are playing... like compiling... */ #ifdef INTUI_NEW_LOOK extern struct Hook fillhook; struct TagItem tags[] = { { WA_BackFill, (ULONG) &fillhook }, { WA_PubScreenName, (ULONG) "NetHack" }, { TAG_DONE, 0 }, }; #endif /* * The default dimensions and status values for each window type. The * data here is generally changed in create_nhwindow(), so beware that * what you see here may not be exactly what you get. */ struct win_setup new_wins[] = { /* First entry not used, types are based at 1 */ { { 0 } }, /* NHW_MESSAGE */ { { 0, 1, 640, 11, 0xff, 0xff, NEWSIZE | GADGETUP | GADGETDOWN | MOUSEMOVE | MOUSEBUTTONS | RAWKEY, BORDERLESS | ACTIVATE | SMART_REFRESH #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , NULL, NULL, (UBYTE *) "Messages", NULL, NULL, 320, 40, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 1, 1, 80, 80 }, /* NHW_STATUS */ { { 0, 181, 640, 24, 0xff, 0xff, RAWKEY | MENUPICK | DISKINSERTED, BORDERLESS | ACTIVATE | SMART_REFRESH | BACKDROP #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , NULL, NULL, (UBYTE *) "Game Status", NULL, NULL, 0, 0, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 2, 2, 78, 78 }, /* NHW_MAP */ { { 0, 0, WIDTH, WINDOWHEIGHT, 0xff, 0xff, RAWKEY | MENUPICK | MOUSEBUTTONS | ACTIVEWINDOW | MOUSEMOVE, BORDERLESS | ACTIVATE | SMART_REFRESH | BACKDROP #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , NULL, NULL, (UBYTE *) "Dungeon Map", NULL, NULL, 64, 64, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 22, 22, 80, 80 }, /* NHW_MENU */ { { 400, 10, 10, 10, 0xff, 0xff, RAWKEY | MENUPICK | DISKINSERTED | MOUSEMOVE | MOUSEBUTTONS | GADGETUP | GADGETDOWN | CLOSEWINDOW | VANILLAKEY | NEWSIZE | INACTIVEWINDOW, WINDOWSIZING | WINDOWCLOSE | WINDOWDRAG | ACTIVATE | SMART_REFRESH #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , &MenuScroll, NULL, NULL, NULL, NULL, 64, 32, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 1, 1, 22, 78 }, /* NHW_TEXT */ { { 0, 0, 640, 200, 0xff, 0xff, RAWKEY | MENUPICK | DISKINSERTED | MOUSEMOVE | GADGETUP | CLOSEWINDOW | VANILLAKEY | NEWSIZE, WINDOWSIZING | WINDOWCLOSE | WINDOWDRAG | ACTIVATE | SMART_REFRESH #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , &MenuScroll, NULL, (UBYTE *) NULL, NULL, NULL, 100, 32, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 1, 1, 22, 78 }, /* NHW_BASE */ { { 0, 0, WIDTH, WINDOWHEIGHT, 0xff, 0xff, RAWKEY | MENUPICK | MOUSEBUTTONS, BORDERLESS | ACTIVATE | SMART_REFRESH | BACKDROP #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , NULL, NULL, (UBYTE *) NULL, NULL, NULL, -1, -1, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 22, 22, 80, 80 }, /* NHW_OVER */ { { 320, 20, 319, 179, 0xff, 0xff, RAWKEY | MENUPICK | MOUSEBUTTONS, BORDERLESS | ACTIVATE | SMART_REFRESH | BACKDROP #ifdef INTUI_NEW_LOOK | WFLG_NW_EXTENDED #endif , NULL, NULL, (UBYTE *) NULL, NULL, NULL, 64, 32, 0xffff, 0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN, tags #else CUSTOMSCREEN #endif }, 0, 0, 22, 22, 80, 80 }, }; const char winpanicstr[] = "Bad winid %d in %s()"; /* The opened windows information */ struct amii_WinDesc *amii_wins[MAXWIN + 1]; #ifdef INTUI_NEW_LOOK /* * NUMDRIPENS varies based on headers, so don't use it * here, its value is used elsewhere. */ UWORD amii_defpens[20]; struct TagItem scrntags[] = { { SA_PubName, (ULONG) "NetHack" }, { SA_Overscan, OSCAN_TEXT }, { SA_AutoScroll, TRUE }, #if LIBRARY_VERSION >= 39 { SA_Interleaved, TRUE }, #endif { SA_Pens, (ULONG) 0 }, { SA_DisplayID, 0 }, { TAG_DONE, 0 }, }; #endif struct NewScreen NewHackScreen = { 0, 0, WIDTH, SCREENHEIGHT, 3, 0, 1, /* DetailPen, BlockPen */ HIRES, CUSTOMSCREEN #ifdef INTUI_NEW_LOOK | NS_EXTENDED #endif , &Hack80, /* Font */ NULL, /*(UBYTE *)" NetHack X.Y.Z" */ NULL, /* Gadgets */ NULL, /* CustomBitmap */ #ifdef INTUI_NEW_LOOK scrntags #endif }; /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting pl_character. * Always called after init_nhwindows() and before display_gamewindows(). */ void amii_askname() { char plnametmp[300]; /* From winreq.c: sizeof(StrStringSIBuff) */ *plnametmp = 0; do { amii_getlin("Who are you?", plnametmp); } while (strlen(plnametmp) == 0); strncpy(plname, plnametmp, PL_NSIZ - 1); /* Avoid overflowing plname[] */ plname[PL_NSIZ - 1] = 0; if (*plname == '\33') { clearlocks(); exit_nhwindows(NULL); terminate(0); } } /* Discarded ... -jhsa #include "NH:sys/amiga/char.c" */ /* Get the player selection character */ #if 0 /* New function at the bottom */ void amii_player_selection() { register struct Window *cwin; register struct IntuiMessage *imsg; register int aredone = 0; register struct Gadget *gd; static int once = 0; long class, code; amii_clear_nhwindow( WIN_BASE ); if (validrole(flags.initrole)) return; else { flags.initrole=randrole(); return; } #if 0 /* Don't query the user ... instead give random character -jhsa */ #if 0 /* OBSOLETE */ if( *pl_character ){ pl_character[ 0 ] = toupper( pl_character[ 0 ] ); if( index( pl_classes, pl_character[ 0 ] ) ) return; } #endif if( !once ){ if( bigscreen ){ Type_NewWindowStructure1.TopEdge = (HackScreen->Height/2) - (Type_NewWindowStructure1.Height/2); } for( gd = Type_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget ) { if( gd->GadgetID != 0 ) SetBorder( gd ); } once = 1; } if( WINVERS_AMIV ) { #ifdef INTUI_NEW_LOOK Type_NewWindowStructure1.Extension = wintags; Type_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED; fillhook.h_Entry = (ULONG(*)())LayerFillHook; fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; #endif } Type_NewWindowStructure1.Screen = HackScreen; if( ( cwin = OpenShWindow( (void *)&Type_NewWindowStructure1 ) ) == NULL ) { return; } #if 0 WindowToFront( cwin ); #endif while( !aredone ) { WaitPort( cwin->UserPort ); while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL ) { class = imsg->Class; code = imsg->Code; gd = (struct Gadget *)imsg->IAddress; ReplyMsg( (struct Message *)imsg ); switch( class ) { case VANILLAKEY: if( index( pl_classes, toupper( code ) ) ) { pl_character[0] = toupper( code ); aredone = 1; } else if( code == ' ' || code == '\n' || code == '\r' ) { flags.initrole = randrole(); #if 0 /* OBSOLETE */ strcpy( pl_character, roles[ rnd( 11 ) ] ); #endif aredone = 1; amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); RandomWindow( pl_character ); return; } else if( code == 'q' || code == 'Q' ) { CloseShWindow( cwin ); clearlocks(); exit_nhwindows(NULL); terminate(0); } else DisplayBeep( NULL ); break; case GADGETUP: switch( gd->GadgetID ) { case 1: /* Random Character */ flags.initrole = randrole(); #if 0 /* OBSOLETE */ strcpy( pl_character, roles[ rnd( 11 ) ] ); #endif amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); RandomWindow( pl_character ); return; default: pl_character[0] = gd->GadgetID; break; } aredone = 1; break; case CLOSEWINDOW: CloseShWindow( cwin ); clearlocks(); exit_nhwindows(NULL); terminate(0); break; } } } amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); #endif /* Do not query user ... -jhsa */ } #endif /* Function elsewhere */ #if 0 /* Unused ... -jhsa */ #include "NH:sys/amiga/randwin.c" void RandomWindow( name ) char *name; { struct MsgPort *tport; struct timerequest *trq; static int once = 0; struct Gadget *gd; struct Window *w; struct IntuiMessage *imsg; int ticks = 0, aredone = 0, timerdone = 0; long mask, got; tport = CreateMsgPort(); trq = (struct timerequest *)CreateIORequest( tport, sizeof( *trq ) ); if( tport == NULL || trq == NULL ) { allocerr: if( tport ) DeleteMsgPort( tport ); if( trq ) DeleteIORequest( (struct IORequest *)trq ); Delay( 8 * 50 ); return; } if( OpenDevice( TIMERNAME, UNIT_VBLANK, (struct IORequest *)trq, 0L ) != 0 ) goto allocerr; trq->tr_node.io_Command = TR_ADDREQUEST; trq->tr_time.tv_secs = 8; trq->tr_time.tv_micro = 0; SendIO( (struct IORequest *)trq ); /* Place the name in the center of the screen */ Rnd_IText5.IText = name; Rnd_IText6.LeftEdge = Rnd_IText4.LeftEdge + (strlen(Rnd_IText4.IText)+1)*8; Rnd_NewWindowStructure1.Width = ( (strlen( Rnd_IText2.IText )+1) * 8 ) + HackScreen->WBorLeft + HackScreen->WBorRight; Rnd_IText5.LeftEdge = (Rnd_NewWindowStructure1.Width - (strlen(name)*8))/2; gd = Rnd_NewWindowStructure1.FirstGadget; gd->LeftEdge = (Rnd_NewWindowStructure1.Width - gd->Width)/2; /* Chose correct modifier */ Rnd_IText6.IText = "a"; switch( *name ) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'A': case 'E': case 'I': case 'O': case 'U': Rnd_IText6.IText = "an"; break; } if( !once ) { if( bigscreen ) { Rnd_NewWindowStructure1.TopEdge = (HackScreen->Height/2) - (Rnd_NewWindowStructure1.Height/2); } for( gd = Rnd_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget ) { if( gd->GadgetID != 0 ) SetBorder( gd ); } Rnd_NewWindowStructure1.IDCMPFlags |= VANILLAKEY; once = 1; } if( WINVERS_AMIV ) { #ifdef INTUI_NEW_LOOK Rnd_NewWindowStructure1.Extension = wintags; Rnd_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED; fillhook.h_Entry = (ULONG(*)())LayerFillHook; fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; #endif } Rnd_NewWindowStructure1.Screen = HackScreen; if( ( w = OpenShWindow( (void *)&Rnd_NewWindowStructure1 ) ) == NULL ) { AbortIO( (struct IORequest *)trq ); WaitIO( (struct IORequest *)trq ); CloseDevice( (struct IORequest *)trq ); DeleteIORequest( (struct IORequest *) trq ); DeleteMsgPort( tport ); Delay( 50 * 8 ); return; } PrintIText( w->RPort, &Rnd_IntuiTextList1, 0, 0 ); mask = (1L << tport->mp_SigBit)|(1L << w->UserPort->mp_SigBit); while( !aredone ) { got = Wait( mask ); if( got & (1L << tport->mp_SigBit ) ) { aredone = 1; timerdone = 1; GetMsg( tport ); } while( w && ( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) ) ) { switch( (long)imsg->Class ) { /* Must be up for a little while... */ case INACTIVEWINDOW: if( ticks >= 40 ) aredone = 1; break; case INTUITICKS: ++ticks; break; case GADGETUP: aredone = 1; break; case VANILLAKEY: if(imsg->Code=='\n' || imsg->Code==' ' || imsg->Code=='\r') aredone = 1; break; } ReplyMsg( (struct Message *)imsg ); } } if( !timerdone ) { AbortIO( (struct IORequest *)trq ); WaitIO( (struct IORequest *)trq ); } CloseDevice( (struct IORequest *)trq ); DeleteIORequest( (struct IORequest *) trq ); DeleteMsgPort( tport ); if(w) CloseShWindow( w ); } #endif /* Discarded randwin ... -jhsa */ /* this should probably not be needed (or be renamed) void flush_output(){} */ /* Read in an extended command - doing command line completion for * when enough characters have been entered to make a unique command. */ int amii_get_ext_cmd(void) { menu_item *mip; anything id; struct amii_WinDesc *cw; #ifdef EXTMENU winid win; int i; char buf[256]; #endif int colx; int bottom = 0; struct Window *w; char obufp[100]; register char *bufp = obufp; register int c; int com_index, oindex; int did_comp = 0; /* did successful completion? */ int sel = -1; if (WIN_MESSAGE == WIN_ERR || (cw = amii_wins[WIN_MESSAGE]) == NULL) panic(winpanicstr, WIN_MESSAGE, "get_ext_cmd"); w = cw->win; bottom = amii_msgborder(w); colx = 3; #ifdef EXTMENU if (iflags.extmenu) { win = amii_create_nhwindow(NHW_MENU); amii_start_menu(win); pline("#"); amii_putstr(WIN_MESSAGE, -1, " "); for (i = 0; extcmdlist[i].ef_txt != NULL; ++i) { id.a_char = *extcmdlist[i].ef_txt; sprintf(buf, "%-10s - %s ", extcmdlist[i].ef_txt, extcmdlist[i].ef_desc); amii_add_menu(win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED); } amii_end_menu(win, (char *) 0); sel = amii_select_menu(win, PICK_ONE, &mip); amii_destroy_nhwindow(win); if (sel == 1) { sel = mip->item.a_char; for (i = 0; extcmdlist[i].ef_txt != NULL; ++i) { if (sel == extcmdlist[i].ef_txt[0]) break; } /* copy in the text */ if (extcmdlist[i].ef_txt != NULL) { amii_clear_nhwindow(WIN_MESSAGE); (void) put_ext_cmd((char *) extcmdlist[i].ef_txt, 0, cw, bottom); return (i); } else DisplayBeep(NULL); } return (-1); } else { #else amii_clear_nhwindow(WIN_MESSAGE); /* Was NHW_MESSAGE */ if (scrollmsg) { pline("#"); amii_addtopl(" "); } else { pline("# "); } sel = -1; while ((c = WindowGetchar()) != EOF) { amii_curs(WIN_MESSAGE, colx, bottom); if (c == '?') { int win, i; char buf[100]; if (did_comp) { while (bufp != obufp) { bufp--; amii_curs(WIN_MESSAGE, --colx, bottom); Text(w->RPort, spaces, 1); amii_curs(WIN_MESSAGE, colx, bottom); did_comp = 0; } } win = amii_create_nhwindow(NHW_MENU); amii_start_menu(win); for (i = 0; extcmdlist[i].ef_txt != NULL; ++i) { id.a_char = extcmdlist[i].ef_txt[0]; sprintf(buf, "%-10s - %s ", extcmdlist[i].ef_txt, extcmdlist[i].ef_desc); amii_add_menu(win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED); } amii_end_menu(win, (char *) 0); sel = amii_select_menu(win, PICK_ONE, &mip); amii_destroy_nhwindow(win); if (sel == 0) { return (-1); } else { sel = mip->item.a_char; for (i = 0; extcmdlist[i].ef_txt != NULL; ++i) { if (sel == extcmdlist[i].ef_txt[0]) break; } /* copy in the text */ if (extcmdlist[i].ef_txt != NULL) { amii_clear_nhwindow(WIN_MESSAGE); strcpy(bufp = obufp, extcmdlist[i].ef_txt); (void) put_ext_cmd(obufp, colx, cw, bottom); return (i); } else DisplayBeep(NULL); } } else if (c == '\033') { return (-1); } else if (c == '\b') { if (did_comp) { while (bufp != obufp) { bufp--; amii_curs(WIN_MESSAGE, --colx, bottom); Text(w->RPort, spaces, 1); amii_curs(WIN_MESSAGE, colx, bottom); did_comp = 0; sel = -1; } } else if (bufp != obufp) { sel = -1; bufp--; amii_curs(WIN_MESSAGE, --colx, bottom); Text(w->RPort, spaces, 1); amii_curs(WIN_MESSAGE, colx, bottom); } else DisplayBeep(NULL); } else if (c == '\n' || c == '\r') { return (sel); } else if (c >= ' ' && c < '\177') { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ *bufp = c; bufp[1] = 0; oindex = 0; com_index = -1; while (extcmdlist[oindex].ef_txt != NULL) { if (!strnicmp(obufp, (char *) extcmdlist[oindex].ef_txt, strlen(obufp))) { if (com_index == -1) /* No matches yet*/ com_index = oindex; else /* More than 1 match */ com_index = -2; } oindex++; } if (com_index >= 0 && *obufp) { Strcpy(obufp, extcmdlist[com_index].ef_txt); /* finish printing our string */ colx = put_ext_cmd(obufp, colx, cw, bottom); bufp = obufp; /* reset it */ if (strlen(obufp) < BUFSZ - 1 && strlen(obufp) < COLNO) bufp += strlen(obufp); did_comp = 1; sel = com_index; } else { colx = put_ext_cmd(obufp, colx, cw, bottom); if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO) bufp++; } } else if (c == ('X' - 64) || c == '\177') { colx = 0; amii_clear_nhwindow(WIN_MESSAGE); pline("# "); bufp = obufp; } else DisplayBeep(NULL); } return (-1); #endif } static int put_ext_cmd(obufp, colx, cw, bottom) char * obufp; int colx, bottom; struct amii_WinDesc *cw; { struct Window *w = cw->win; char *t; t = (char *) alloc(strlen(obufp) + 7); if (t != NULL) { if (scrollmsg) { sprintf(t, "xxx%s", obufp); t[0] = 1; t[1] = 1; t[2] = '#'; amii_curs(WIN_MESSAGE, 0, bottom); SetAPen(w->RPort, C_WHITE); Text(w->RPort, "># ", 3); /* SetAPen( w->RPort, C_BLACK ); */ /* Black text on black screen doesn't look too well ... -jhsa */ Text(w->RPort, t + 3, strlen(t) - 3); } else { sprintf(t, "# %s", obufp); amii_curs(WIN_MESSAGE, 0, bottom); SetAPen(w->RPort, C_WHITE); Text(w->RPort, t, strlen(t)); } if (scrollmsg) SetAPen(w->RPort, C_WHITE); if (cw->data[cw->maxrow - 1]) free(cw->data[cw->maxrow - 1]); cw->data[cw->maxrow - 1] = t; } else { amii_curs(WIN_MESSAGE, 0, bottom); SetAPen(w->RPort, C_WHITE); Text(w->RPort, "# ", 2); /* SetAPen( w->RPort, C_BLACK ); */ /* Black on black ... -jhsa */ Text(w->RPort, obufp, strlen(obufp)); SetAPen(w->RPort, C_WHITE); } amii_curs(WIN_MESSAGE, colx = strlen(obufp) + 3 + (scrollmsg != 0), bottom); return (colx); } /* Ask a question and get a response */ char amii_yn_function(query, resp, def) const char * query, *resp; char def; /* * Generic yes/no function. 'def' is the default (returned by space or * return; 'esc' returns 'q', or 'n', or the default, depending on * what's in the string. The 'query' string is printed before the user * is asked about the string. * If resp is NULL, any single character is accepted and returned. * If not-NULL, only characters in it are allowed (exceptions: the * quitchars are always allowed, and if it contains '#' then digits * are allowed); if it includes an , anything beyond that won't * be shown in the prompt to the user but will be acceptable as input. */ { register char q; char rtmp[40]; boolean digit_ok, allow_num; char prompt[BUFSZ]; register struct amii_WinDesc *cw; if (cw = amii_wins[WIN_MESSAGE]) cw->disprows = 0; if (resp) { char *rb, respbuf[QBUFSZ]; allow_num = (index(resp, '#') != 0); Strcpy(respbuf, resp); /* any acceptable responses that follow aren't displayed */ if ((rb = index(respbuf, '\033')) != 0) *rb = '\0'; (void) strncpy(prompt, query, QBUFSZ - 1); prompt[QBUFSZ - 1] = '\0'; Sprintf(eos(prompt), " [%s]", respbuf); if (def) Sprintf(eos(prompt), " (%c)", def); Strcat(prompt, " "); pline("%s", prompt); } else { amii_putstr(WIN_MESSAGE, 0, query); cursor_on(WIN_MESSAGE); q = WindowGetchar(); cursor_off(WIN_MESSAGE); *rtmp = q; rtmp[1] = 0; amii_addtopl(rtmp); goto clean_up; } do { /* loop until we get valid input */ cursor_on(WIN_MESSAGE); q = lowc(WindowGetchar()); cursor_off(WIN_MESSAGE); #if 0 /* fix for PL2 */ if (q == '\020') { /* ctrl-P */ if(!doprev) (void) tty_doprev_message(); /* need two initially */ (void) tty_doprev_message(); q = (char)0; doprev = 1; continue; } else if(doprev) { tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; doprev = 0; amii_addtopl(prompt); continue; } #endif digit_ok = allow_num && isdigit(q); if (q == '\033') { if (index(resp, 'q')) q = 'q'; else if (index(resp, 'n')) q = 'n'; else q = def; break; } else if (index(quitchars, q)) { q = def; break; } if (!index(resp, q) && !digit_ok) { amii_bell(); q = (char) 0; } else if (q == '#' || digit_ok) { char z, digit_string[2]; int n_len = 0; long value = 0; amii_addtopl("#"), n_len++; digit_string[1] = '\0'; if (q != '#') { digit_string[0] = q; amii_addtopl(digit_string), n_len++; value = q - '0'; q = '#'; } do { /* loop until we get a non-digit */ cursor_on(WIN_MESSAGE); z = lowc(WindowGetchar()); cursor_off(WIN_MESSAGE); if (isdigit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; amii_addtopl(digit_string), n_len++; } else if (z == 'y' || index(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ } else if (z == '\b') { if (n_len <= 1) { value = -1; break; } else { value /= 10; removetopl(1), n_len--; } } else { value = -1; /* abort */ amii_bell(); break; } } while (z != '\n'); if (value > 0) yn_number = value; else if (value == 0) q = 'n'; /* 0 => "no" */ else { /* remove number from top line, then try again */ removetopl(n_len), n_len = 0; q = '\0'; } } } while (!q); if (q != '#' && q != '\033') { Sprintf(rtmp, "%c", q); amii_addtopl(rtmp); } clean_up: cursor_off(WIN_MESSAGE); clear_nhwindow(WIN_MESSAGE); return q; } void amii_display_file(fn, complain) const char * fn; boolean complain; { register struct amii_WinDesc *cw; register int win; register dlb *fp; register char *t; register char buf[200]; if (fn == NULL) panic("NULL file name in display_file()"); if ((fp = dlb_fopen(fn, RDTMODE)) == (dlb *) NULL) { if (complain) { sprintf(buf, "Can't display %s: %s", fn, #if defined(_DCC) || defined(__GNUC__) strerror(errno) #else #ifdef __SASC_60 __sys_errlist[errno] #else sys_errlist[errno] #endif #endif ); amii_addtopl(buf); } return; } win = amii_create_nhwindow(NHW_TEXT); /* Set window title to file name */ if (cw = amii_wins[win]) cw->morestr = (char *) fn; while (dlb_fgets(buf, sizeof(buf), fp) != NULL) { if (t = index(buf, '\n')) *t = 0; amii_putstr(win, 0, buf); } dlb_fclose(fp); /* If there were lines in the file, display those lines */ if (amii_wins[win]->cury > 0) amii_display_nhwindow(win, TRUE); amii_wins[win]->morestr = NULL; /* don't free title string */ amii_destroy_nhwindow(win); } /* Put a 3-D motif border around the gadget. String gadgets or those * which do not have highlighting are rendered down. Boolean gadgets * are rendered in the up position by default. */ void SetBorder(gd) register struct Gadget * gd; { register struct Border *bp; register short *sp; register int i, inc = -1, dec = -1; int borders = 6; int hipen = sysflags.amii_dripens[SHINEPEN], shadowpen = sysflags.amii_dripens[SHADOWPEN]; #ifdef INTUI_NEW_LOOK struct DrawInfo *dip; #endif #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { if (dip = GetScreenDrawInfo(HackScreen)) { hipen = dip->dri_Pens[SHINEPEN]; shadowpen = dip->dri_Pens[SHADOWPEN]; FreeScreenDrawInfo(HackScreen, dip); } } #endif /* Allocate two border structures one for up image and one for down * image, plus vector arrays for the border lines. */ if (gd->GadgetType == STRGADGET) borders = 12; if ((bp = (struct Border *) alloc(((sizeof(struct Border) * 2) + (sizeof(short) * borders)) * 2)) == NULL) { return; } /* For a string gadget, we expand the border beyond the area where * the text will be entered. */ /* Remove any special rendering flags to avoid confusing intuition */ gd->Flags &= ~(GADGHIGHBITS | GADGIMAGE); sp = (short *) (bp + 4); if (gd->GadgetType == STRGADGET || (gd->GadgetType == BOOLGADGET && (gd->Flags & GADGHIGHBITS) == GADGHNONE)) { sp[0] = -1; sp[1] = gd->Height - 1; sp[2] = -1; sp[3] = -1; sp[4] = gd->Width - 1; sp[5] = -1; sp[6] = gd->Width + 1; sp[7] = -2; sp[8] = gd->Width + 1; sp[9] = gd->Height + 1; sp[10] = -2; sp[11] = gd->Height + 1; sp[12] = -2; sp[13] = gd->Height; sp[14] = -2; sp[15] = -2; sp[16] = gd->Width; sp[17] = -2; sp[18] = gd->Width; sp[19] = gd->Height; sp[20] = -2; sp[21] = gd->Height; for (i = 0; i < 3; ++i) { bp[i].LeftEdge = bp[i].TopEdge = -1; bp[i].FrontPen = (i == 0 || i == 1) ? shadowpen : hipen; /* Have to use JAM2 so that the old colors disappear. */ bp[i].BackPen = C_BLACK; bp[i].DrawMode = JAM2; bp[i].Count = (i == 0 || i == 1) ? 3 : 5; bp[i].XY = &sp[i * 6]; bp[i].NextBorder = (i == 2) ? NULL : &bp[i + 1]; } /* bp[0] and bp[1] two pieces for the up image */ gd->GadgetRender = (APTR) bp; /* No image change for select */ gd->SelectRender = (APTR) bp; gd->LeftEdge++; gd->TopEdge++; gd->Flags |= GADGHCOMP; } else { /* Create the border vector values for up and left side, and * also the lower and right side. */ sp[0] = dec; sp[1] = gd->Height + inc; sp[2] = dec; sp[3] = dec; sp[4] = gd->Width + inc; sp[5] = dec; sp[6] = gd->Width + inc; sp[7] = dec; sp[8] = gd->Width + inc; sp[9] = gd->Height + inc; sp[10] = dec; sp[11] = gd->Height + inc; /* We are creating 4 sets of borders, the two sides of the * rectangle share the border vectors with the opposite image, * but specify different colors. */ for (i = 0; i < 4; ++i) { bp[i].TopEdge = bp[i].LeftEdge = 0; /* A GADGHNONE is always down */ if (gd->GadgetType == BOOLGADGET && (gd->Flags & GADGHIGHBITS) != GADGHNONE) { bp[i].FrontPen = (i == 1 || i == 2) ? shadowpen : hipen; } else { bp[i].FrontPen = (i == 1 || i == 3) ? hipen : shadowpen; } /* Have to use JAM2 so that the old colors disappear. */ bp[i].BackPen = C_BLACK; bp[i].DrawMode = JAM2; bp[i].Count = 3; bp[i].XY = &sp[6 * ((i & 1) != 0)]; bp[i].NextBorder = (i == 1 || i == 3) ? NULL : &bp[i + 1]; } /* bp[0] and bp[1] two pieces for the up image */ gd->GadgetRender = (APTR) bp; /* bp[2] and bp[3] two pieces for the down image */ gd->SelectRender = (APTR)(bp + 2); gd->Flags |= GADGHIMAGE; } } /* Following function copied from wintty.c */ /* Modified slightly to fit amiga needs */ void amii_player_selection() { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ], rolenamebuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; rigid_role_checks(); /* Should we randomly pick for the player? */ if (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE) { char *prompt = build_plselection_prompt( pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); pline("%s", prompt); do { /* loop until we get valid input */ cursor_on(WIN_MESSAGE); pick4u = lowc(WindowGetchar()); cursor_off(WIN_MESSAGE); if (index(quitchars, pick4u)) pick4u = 'y'; } while (!index(ynqchars, pick4u)); pbuf[0] = pick4u; pbuf[1] = 0; amii_addtopl(pbuf); if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); clearlocks(); exit_nhwindows(NULL); terminate(0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible role!"); flags.initrole = randrole(); } } else { /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole() + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible race!"); flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ } #endif /* AMIGA_INTUITION */ nethack-3.6.0/sys/amiga/winami.p0000664000076400007660000000504612536476415015520 0ustar paxedpaxed/* NetHack 3.6 winami.p $NHDT-Date: 1433806595 2015/06/08 23:36:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* winami.c */ void FDECL(amii_raw_print, (const char *)); void FDECL(amii_raw_print_bold, (const char *)); void FDECL(amii_start_menu, (winid )); void FDECL(amii_add_menu, (winid , char , int , const char *)); void FDECL(amii_end_menu, (winid , char , const char * , const char *)); char FDECL(amii_select_menu, (winid )); void NDECL(amii_update_inventory ); void NDECL(amii_mark_synch ); void NDECL(amii_wait_synch ); void NDECL(amii_setclipped ); void FDECL(amii_cliparound, (int , int )); void NDECL(amii_askname ); void NDECL(amii_player_selection ); void NDECL(flush_output ); void FDECL(amii_destroy_nhwindow, (winid )); int FDECL(amii_create_nhwindow, (int )); void NDECL(amii_init_nhwindows ); int NDECL(amii_get_ext_cmd); char FDECL(amii_yn_function, (const char * , const char * , char )); void FDECL(amii_addtopl, (const char *)); void FDECL(TextSpaces, (struct RastPort * , int )); void FDECL(amii_putstr, (winid , int , const char *)); void FDECL(amii_putsym, (winid , int , int , CHAR_P )); void FDECL(amii_clear_nhwindow, (winid )); void FDECL(amii_exit_nhwindows, (const char *)); int FDECL(amii_nh_poskey, (int * , int * , int *)); int NDECL(amii_nhgetch ); void NDECL(amii_get_nh_event ); void NDECL(amii_remember_topl ); int NDECL(amii_doprev_message ); void FDECL(amii_display_nhwindow, (winid , boolean )); void FDECL(amii_display_file, (const char * , boolean )); void FDECL(amii_curs, (winid , int , int )); void FDECL(amii_print_glyph, (winid , xchar , xchar , int, int )); void FDECL(DoMenuScroll, (int , int )); void FDECL(DisplayData, (int , int , int )); void FDECL(SetPropInfo, (struct Window * , struct Gadget * , long , long , long )); void FDECL(kill_nhwindows, (int )); void FDECL(amii_cl_end, (struct amii_WinDesc * , int )); void FDECL(cursor_off, (winid )); void FDECL(cursor_on, (winid )); void NDECL(amii_getret ); void FDECL(amii_getlin, (const char * , char *)); void FDECL(getlind, (const char * , char * , const char *)); void FDECL(amii_suspend_nhwindows, (char * )); void NDECL(amii_resume_nhwindows); void NDECL(amii_bell); void NDECL(EditColor); void FDECL(DrawCol, ( struct Window *, int, UWORD * ) ); void FDECL( DispCol, ( struct Window *w, int idx, UWORD * ) ); void FDECL( SetBorder, (struct Gadget *) ); void NDECL( port_help ); void FDECL( dismiss_nhwindow, (winid) ); nethack-3.6.0/sys/amiga/winchar.c0000664000076400007660000010443712536476415015656 0ustar paxedpaxed/* NetHack 3.6 winchar.c $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993 */ /* Copyright (c) Gregg Wonderly, Naperville Illinois, 1994. */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #ifndef _DCC #include #endif #ifdef TESTING #include "hack.h" #else #include "NH:src/tile.c" #endif #include "NH:win/share/tile.h" #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #ifdef OPT_DISPMAP #define DISPMAP /* use display_map() from dispmap.s */ #endif /* NH:sys/amiga/winvchar.c */ int main(int, char **); struct BitMap *MyAllocBitMap(int, int, int, long); void MyFreeBitMap(struct BitMap *); void FreeImageFiles(char **, struct BitMap **); void amiv_flush_glyph_buffer(struct Window *); void amiv_lprint_glyph(winid, int, int); void amii_lprint_glyph(winid, int, int); void amiv_start_glyphout(winid); void amii_end_glyphout(winid); void SetMazeType(MazeType); int GlyphToIcon(int); void amii_start_glyphout(winid); void amii_end_glyphout(winid); void amii_flush_glyph_buffer(struct Window *); int amii_extraplanes = 0; extern int reclip; struct BitMap *MyAllocBitMap(int xsize, int ysize, int depth, long mflags); void MyFreeBitMap(struct BitMap *bmp); #ifdef DISPMAP extern void display_map(struct Window *); #endif /* * These values will be available from tile.c source * * #define MAXMONTILE 335 * #define MAXOBJTILE 722 * #define MAXOTHTILE 841 */ #define IMGROWS 12 #define IMGCOLUMNS 20 #define IMGPAGESIZE (IMGROWS * IMGCOLUMNS) #define ID_BMAP MAKE_ID('B', 'M', 'A', 'P') /* The type of form we use */ #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* The ILBM bitmap header */ #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* The ILBM camg (ignored) */ #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* Standard ILBM color map */ #define ID_PLNE MAKE_ID('P', 'L', 'N', 'E') /* The plane data */ #define ID_PDAT MAKE_ID('P', 'D', 'A', 'T') /* The PDAT structure below */ struct PDAT pictdata; #define NUMTILEIMAGES 3 char *tileimages[] = { #define TBLMONTILE 0 "NetHack:tiles/monsters.iff", #define TBLOBJTILE 1 "NetHack:tiles/objects.iff", #define TBLOTHTILE 2 "NetHack:tiles/other.iff", 0, }; struct BitMap *ifftimg[NUMTILEIMAGES], *tile; #ifdef TESTING short pens[NUMDRIPENS] = { 8, 3, 15, 0, 15, 7, 7, 8, 0 }; main(int argc, char **argv) { BitMapHeader bmhd; struct IntuiMessage *imsg; long code, class; char buf[100]; int i, x, y, tbl, done = 0, num; struct Window *w; struct Screen *scr; bmhd = ReadTileImageFiles(); scr = OpenScreenTags( NULL, SA_Depth, pictdata.nplanes + amii_extraplanes, SA_DisplayID, DBLNTSC_MONITOR_ID | HIRESLACE_KEY, SA_Overscan, OSCAN_TEXT, SA_Top, 0, SA_Left, 0, SA_Width, STDSCREENWIDTH, SA_Height, STDSCREENHEIGHT, SA_Type, CUSTOMSCREEN, SA_DetailPen, 0, SA_BlockPen, 1, SA_Title, "NetHack Chars", SA_Pens, pens, TAG_DONE); if (scr == NULL) { printf("no screen\n"); #undef exit exit(1); } w = OpenWindowTags( 0, WA_CustomScreen, scr, WA_Flags, WFLG_DRAGBAR | WFLG_SIZEGADGET | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET, WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS, WA_Left, 0, WA_Top, scr->WBorTop + 1 + 13, WA_MinWidth, 100, WA_MinHeight, 100, WA_MaxWidth, 700, WA_MaxHeight, 1000, WA_Width, 640, WA_Height, 340, WA_SmartRefresh, TRUE, TAG_DONE); if (w) { while (!done) { for (i = 0; i < NUMTILEIMAGES * IMGPAGESIZE; ++i) { int dx, dy; tbl = i / IMGPAGESIZE; x = i % IMGPAGESIZE; y = x / IMGCOLUMNS; x = x % IMGCOLUMNS; dx = i % (IMGCOLUMNS * 2); dy = i / (IMGCOLUMNS * 2); BltBitMapRastPort(ifftimg[tbl], x * pictdata.xsize, y * pictdata.ysize, w->RPort, w->BorderLeft + 1 + dx * pictdata.xsize, w->BorderTop + 1 + dy * pictdata.ysize, pictdata.xsize, pictdata.ysize, 0xc0); } WaitPort(w->UserPort); while (imsg = (struct IntuiMessage *) GetMsg(w->UserPort)) { class = imsg->Class; code = imsg->Code; ReplyMsg((struct Message *) imsg); switch (class) { case IDCMP_MOUSEBUTTONS: { x = imsg->MouseX - w->BorderLeft; y = imsg->MouseY - w->BorderTop; num = ((y / pictdata.ysize) * IMGCOLUMNS * 2) + (x / pictdata.xsize); sprintf(buf, "Char #%d", num); SetWindowTitles(w, buf, buf); } break; case IDCMP_CLOSEWINDOW: done = 1; break; } } } CloseWindow(w); CloseScreen(scr); } FreeImageFiles(tileimages, ifftimg); return (0); } #endif BitMapHeader ReadTileImageFiles() { char *errstr = NULL; BitMapHeader ret = ReadImageFiles(tileimages, ifftimg, &errstr); if (errstr) { panic(errstr); } return ret; } BitMapHeader ReadImageFiles(char **filenames, struct BitMap **iffimg, char **errstrp) { BitMapHeader *bmhd = NULL, bmhds; unsigned char *cmap; extern int errno; register int i, j; struct IFFHandle *iff; struct StoredProperty *prop; IFFParseBase = OpenLibrary("iffparse.library", 0L); if (!IFFParseBase) { *errstrp = "No iffparse.library"; return bmhds; } /* for( i = 0; filenames[i]; ++i ) memset( iffimg[i], 0, sizeof( struct BitMap ) ); */ for (i = 0; filenames[i]; ++i) { iff = AllocIFF(); if (!iff) { FreeImageFiles(filenames, iffimg); *errstrp = "can't start IFF processing"; return bmhds; } iff->iff_Stream = Open(filenames[i], MODE_OLDFILE); if (iff->iff_Stream == 0) { char *buf = malloc(100 + strlen(filenames[i])); FreeImageFiles(filenames, iffimg); sprintf(buf, "Can't open %s: %s", filenames[i], strerror(errno)); *errstrp = buf; return bmhds; } InitIFFasDOS(iff); OpenIFF(iff, IFFF_READ); PropChunk(iff, ID_BMAP, ID_BMHD); PropChunk(iff, ID_BMAP, ID_CMAP); PropChunk(iff, ID_BMAP, ID_CAMG); PropChunk(iff, ID_BMAP, ID_PDAT); StopChunk(iff, ID_BMAP, ID_PLNE); if ((j = ParseIFF(iff, IFFPARSE_SCAN)) != 0) { char *buf = malloc(100); FreeImageFiles(filenames, iffimg); sprintf(buf, "ParseIFF failed for image %d, failure code: %d", i, j); *errstrp = buf; return bmhds; } if (prop = FindProp(iff, ID_BMAP, ID_BMHD)) { bmhd = (BitMapHeader *) prop->sp_Data; } else { FreeImageFiles(filenames, iffimg); CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); *errstrp = "No BMHD CHUNK in file"; return bmhds; } if (prop = FindProp(iff, ID_BMAP, ID_CMAP)) { cmap = prop->sp_Data; for (j = 0; j < (1L << bmhd->nPlanes) * 3; j += 3) { #if 0 /* Some day we will want to use the larger palette * resolution available under v39 and later. i.e. * 32 instead of 12 bits of color. Ususally this * just means shifting the color left by 16-20 bits * depending on what intensity looks best. Experience * says that the higher values are better intensities. * * For now though we won't do this. The color table * structure is incompatible with earlier versions of * intuition. We would have to do some funny things * to make 3*AMII_MAXCOLORS longs work like 3*AMII_MAXCOLORS * UWORD's at run time... A union would help, but... */ if( IntuitionBase->LibNode.lib_Version >= 39 ) { /* 8 bits of color, so shift to left end. */ amiv_init_map[ j+0 ] = cmap[j+0]<<24; amiv_init_map[ j+1 ] = cmap[j+1]<<24; amiv_init_map[ j+2 ] = cmap[j+2]<<24; } else #endif { /* We can only use 4 bits of the 8 that are stored in the * cmap, so mask them and then shift them into position * for the UWORD value to store. */ #ifndef TESTING amii_initmap[j / 3] = amiv_init_map[j / 3] = ((cmap[j + 0] >> 4) << 8) | ((cmap[j + 1] >> 4) << 4) | (cmap[j + 2] >> 4); #endif } } } else { FreeImageFiles(filenames, iffimg); CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); *errstrp = "No CMAP CHUNK in file"; return bmhds; } if (prop = FindProp(iff, ID_BMAP, ID_PDAT)) { struct PDAT *pp; pp = (struct PDAT *) prop->sp_Data; pictdata = *pp; } else { FreeImageFiles(filenames, iffimg); CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); *errstrp = "No PDAT CHUNK in file"; return bmhds; } iffimg[i] = MyAllocBitMap(bmhd->w, bmhd->h, pictdata.nplanes + amii_extraplanes, MEMF_CHIP | MEMF_CLEAR); if (iffimg[i] == NULL) { char *buf = malloc(80); FreeImageFiles(filenames, iffimg); sprintf(buf, "Can't allocate bitmap for image %d\n", i); *errstrp = buf; return bmhds; } for (j = 0; j < pictdata.nplanes + amii_extraplanes; ++j) { ReadChunkBytes(iff, iffimg[i]->Planes[j], RASSIZE(bmhd->w, bmhd->h)); } bmhds = *bmhd; CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); } CloseLibrary(IFFParseBase); tile = MyAllocBitMap(pictdata.xsize, pictdata.ysize, pictdata.nplanes + amii_extraplanes, MEMF_CHIP | MEMF_CLEAR); if (tile == NULL) { FreeImageFiles(filenames, iffimg); *errstrp = "Can't allocate tile bitmap for scaling"; } return (bmhds); } struct MyBitMap { struct BitMap bm; long mflags; USHORT xsize, ysize; }; struct BitMap * MyAllocBitMap(int xsize, int ysize, int depth, long mflags) { int j; struct MyBitMap *bm; bm = (struct MyBitMap *) alloc(sizeof(*bm)); if (!bm) return (NULL); bm->xsize = xsize; bm->ysize = ysize; InitBitMap(&bm->bm, depth, xsize, ysize); for (j = 0; j < depth; ++j) { if (mflags & MEMF_CHIP) bm->bm.Planes[j] = AllocRaster(xsize, ysize); else bm->bm.Planes[j] = AllocMem(RASSIZE(xsize, ysize), mflags); if (bm->bm.Planes[j] == 0) { MyFreeBitMap(&bm->bm); return (NULL); } if (mflags & MEMF_CLEAR) memset(bm->bm.Planes[j], 0, RASSIZE(xsize, ysize)); } return (&bm->bm); } void MyFreeBitMap(struct BitMap *bmp) { int j; struct MyBitMap *bm = (struct MyBitMap *) bmp; for (j = 0; j < bm->bm.Depth; ++j) { if (bm->bm.Planes[j]) { if (bm->mflags & MEMF_CHIP) FreeRaster(bm->bm.Planes[j], bm->xsize, bm->ysize); else FreeMem(bm->bm.Planes[j], RASSIZE(bm->xsize, bm->ysize)); } } free(bm); } #ifdef TESTING void panic(s, a1, a2, a3, a4) char *s; { printf(s, a1, a2, a3, a4); putchar('\n'); } long * alloc(unsigned int x) { long *p = (long *) malloc(x); if (!p) { panic("malloc failed"); exit(1); } return p; } #endif void FreeTileImageFiles() { FreeImageFiles(tileimages, ifftimg); } void FreeImageFiles(char **filenames, struct BitMap **img) { register int i; for (i = 0; filenames[i]; ++i) { if (img[i]) MyFreeBitMap(img[i]); } /* REALLY ugly hack alert! */ if (tile && img == ifftimg) MyFreeBitMap(tile); } #ifndef TESTING /* * Define some stuff for our special glyph drawing routines */ unsigned short glyph_node_index, glyph_buffer_index; #define NUMBER_GLYPH_NODES 80 #define GLYPH_BUFFER_SIZE 512 struct amiv_glyph_node { short odstx, odsty; short srcx, srcy, dstx, dsty; struct BitMap *bitmap; }; struct amiv_glyph_node amiv_g_nodes[NUMBER_GLYPH_NODES]; static char amiv_glyph_buffer[GLYPH_BUFFER_SIZE]; void flush_glyph_buffer(vw) struct Window *vw; { if (WINVERS_AMIV) amiv_flush_glyph_buffer(vw); else amii_flush_glyph_buffer(vw); } /* * Routine to flush whatever is buffered */ void amiv_flush_glyph_buffer(vw) struct Window *vw; { #if !defined(DISPMAP) || defined(OPT_DISPMAP) int xsize, ysize, x, y; struct BitScaleArgs bsa; struct BitScaleArgs bsm; struct RastPort rast; struct Window *w = NULL; struct BitMap *imgbm = 0, *bm = 0; int i, k; int scaling_needed; register struct RastPort *rp = vw->RPort; #endif /* If nothing is buffered, return before we do anything */ if (glyph_node_index == 0) return; cursor_off(WIN_MAP); amiv_start_glyphout(WIN_MAP); #ifdef OPT_DISPMAP if (sysflags.fast_map) { #endif #ifdef DISPMAP display_map(vw); #endif #ifdef OPT_DISPMAP } else { #endif #if !defined(DISPMAP) || defined(OPT_DISPMAP) /* XXX fix indent */ /* This is a dynamic value based on this relationship. */ scaling_needed = (pictdata.xsize != mxsize || pictdata.ysize != mysize); /* If overview window is up, set up to render the correct scale there */ if (WIN_OVER != WIN_ERR && (w = amii_wins[WIN_OVER]->win) != NULL) { InitRastPort(&rast); /* Calculate the x and y size of each tile for a ROWNO by COLNO * map */ xsize = (w->Width - w->BorderLeft - w->BorderRight) / COLNO; ysize = (w->Height - w->BorderTop - w->BorderBottom) / ROWNO; /* Get a chip memory bitmap to blit out of */ bm = MyAllocBitMap(pictdata.xsize, pictdata.ysize, pictdata.nplanes + amii_extraplanes, MEMF_CLEAR | MEMF_CHIP); if (bm == NULL) { amii_putstr( WIN_MESSAGE, 0, "Can't allocate bitmap for scaling overview window"); } rast.BitMap = bm; memset(&bsa, 0, sizeof(bsa)); bsa.bsa_SrcX = bsa.bsa_SrcY = 0; bsa.bsa_SrcBitMap = tile; bsa.bsa_SrcWidth = pictdata.xsize; bsa.bsa_SrcHeight = pictdata.ysize; bsa.bsa_XSrcFactor = pictdata.xsize; bsa.bsa_YSrcFactor = pictdata.ysize; bsa.bsa_DestX = 0; bsa.bsa_DestY = 0; bsa.bsa_DestWidth = xsize; bsa.bsa_DestHeight = ysize; bsa.bsa_XDestFactor = xsize; bsa.bsa_YDestFactor = ysize; bsa.bsa_DestBitMap = bm; } if (scaling_needed) { /* Fill in scaling data for map rendering */ memset(&bsm, 0, sizeof(bsm)); bsm.bsa_SrcX = bsm.bsa_SrcY = 0; bsm.bsa_SrcBitMap = tile; bsm.bsa_SrcWidth = pictdata.xsize; bsm.bsa_SrcHeight = pictdata.ysize; bsm.bsa_XSrcFactor = pictdata.xsize; bsm.bsa_YSrcFactor = pictdata.ysize; bsm.bsa_DestWidth = mxsize; bsm.bsa_DestHeight = mysize; bsm.bsa_XDestFactor = mxsize; bsm.bsa_YDestFactor = mysize; bsm.bsa_DestBitMap = rp->BitMap; bsm.bsa_DestY = bsm.bsa_DestX = 0; imgbm = MyAllocBitMap(mxsize, mysize, pictdata.nplanes + amii_extraplanes, MEMF_CLEAR | MEMF_CHIP); if (imgbm == NULL) { amii_putstr(WIN_MESSAGE, 0, "Can't allocate scaling bitmap for map window"); } else bsm.bsa_DestBitMap = imgbm; } /* Go ahead and start dumping the stuff */ for (i = 0; i < glyph_node_index; ++i) { /* Do it */ register int offx, offy, j; struct BitMap *nodebm = amiv_g_nodes[i].bitmap; /* Get the unclipped coordinates */ x = amiv_g_nodes[i].odstx; y = amiv_g_nodes[i].odsty; /* If image is not in CHIP. copy each plane into tile line by line */ offx = amiv_g_nodes[i].srcx / 8; /* 8 is bits per byte */ offy = amiv_g_nodes[i].srcy * nodebm->BytesPerRow; for (j = 0; j < pictdata.nplanes + amii_extraplanes; ++j) { for (k = 0; k < pictdata.ysize; ++k) { /* For a 16x16 tile, this could just be short assignments, * but * this code is generalized to handle any size tile * image... */ memcpy(tile->Planes[j] + ((k * pictdata.ysize) / 8), nodebm->Planes[j] + offx + offy + (nodebm->BytesPerRow * k), pictdata.ysize / 8); } } if (!clipping || (x >= clipx && y >= clipy && x < clipxmax && y < clipymax)) { /* scaling is needed, do it */ if (scaling_needed) { BitMapScale(&bsm); BltBitMapRastPort(imgbm, 0, 0, rp, amiv_g_nodes[i].dstx, amiv_g_nodes[i].dsty, mxsize, mysize, 0xc0); } else { BltBitMapRastPort(tile, 0, 0, rp, amiv_g_nodes[i].dstx, amiv_g_nodes[i].dsty, pictdata.xsize, pictdata.ysize, 0xc0); } } /* Draw the overview window unless we are scrolling the map raster * around */ if (bm && w && reclip != 2) { BitMapScale(&bsa); BltBitMapRastPort( rast.BitMap, 0, 0, w->RPort, w->BorderLeft + amiv_g_nodes[i].odstx * xsize, w->BorderTop + amiv_g_nodes[i].odsty * ysize, xsize, ysize, 0xc0); } } if (imgbm) MyFreeBitMap(imgbm); if (bm) MyFreeBitMap(bm); #endif /* DISPMAP */ #ifdef OPT_DISPMAP } #endif amii_end_glyphout(WIN_MAP); /* Clean up */ glyph_node_index = glyph_buffer_index = 0; } /* * Glyph buffering routine. Called instead of WindowPuts(). */ void amiv_lprint_glyph(window, color_index, glyph) winid window; int color_index, glyph; { int base; struct amii_WinDesc *cw; struct Window *w; int curx; int cury; int tbl, icon; register int xoff, yoff; /* Get the real icon index */ if (glyph != NO_GLYPH) icon = GlyphToIcon(glyph); if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL) panic("bad winid in amiv_lprint_glyph: %d", window); w = cw->win; if (glyph != NO_GLYPH && glyph < 10000) { /* decide on which image has the needed picture */ if (icon <= MAXMONTILE) { tbl = TBLMONTILE; base = 0; } else if (icon <= MAXOBJTILE) { tbl = TBLOBJTILE; base = MAXMONTILE + 1; } else if (icon <= MAXOTHTILE) { tbl = TBLOTHTILE; base = MAXOBJTILE + 1; } else panic("Bad icon #%d, glyph #%d, only %d icons known\n", icon, glyph, MAXOTHTILE); /* Get the relative offset in the page */ /* How many pixels to account for y distance down */ yoff = ((icon - base) / pictdata.across) * pictdata.ysize; /* How many pixels to account for x distance across */ xoff = ((icon - base) % pictdata.across) * pictdata.xsize; } if (glyph >= 10000) { /* Run a single ASCII character out to the rastport right now */ char c = glyph - 10000; int xxx, xxy; struct RastPort *rp = w->RPort; Move(rp, xxx = (((cw->curx - clipx) * rp->TxWidth) + w->BorderLeft), xxy = (w->BorderTop + (((cw->cury - clipy) + 1) * rp->TxHeight) + 1)); Text(rp, &c, 1); /* XXX this shouldn't be necessary: */ if (cw->cursx == xxx && cw->cursy == xxy) { cw->wflags &= ~FLMAP_CURSUP; } cw->curx += rp->TxWidth; /* keep things in sync */ return; } if (cw->type == NHW_MAP) { curx = cw->curx - clipx; cury = cw->cury - clipy; /* See if we're out of glyph nodes */ if (glyph_node_index >= NUMBER_GLYPH_NODES) amiv_flush_glyph_buffer(w); /* Fill in the node. */ amiv_g_nodes[glyph_node_index].dsty = min(w->BorderTop + (cury * mysize), w->Height - 1); #ifdef OPT_DISPMAP if (sysflags.fast_map) { #endif /* keni */ #ifdef DISPMAP /* display_map() needs byte-aligned destinations, and we don't * want to * overwrite the window border. */ amiv_g_nodes[glyph_node_index].dstx = (w->BorderLeft + 8 + (curx * mxsize)) & -8; #endif #ifdef OPT_DISPMAP } else { #endif #if !defined(DISPMAP) || defined(OPT_DISPMAP) amiv_g_nodes[glyph_node_index].dstx = min(w->BorderLeft + (curx * mxsize), w->Width - 1); #endif #ifdef OPT_DISPMAP } #endif amiv_g_nodes[glyph_node_index].odsty = cw->cury; amiv_g_nodes[glyph_node_index].odstx = cw->curx; amiv_g_nodes[glyph_node_index].srcx = xoff; amiv_g_nodes[glyph_node_index].srcy = yoff; amiv_g_nodes[glyph_node_index].bitmap = ifftimg[tbl]; ++glyph_node_index; } else { /* Do it */ register int j, k, x, y, apen; struct RastPort *rp = w->RPort; x = rp->cp_x - pictdata.xsize - 3; #ifdef OPT_DISPMAP if (sysflags.fast_map) { #endif #ifdef DISPMAP x &= -8; if (x == 0) x = 8; #endif #ifdef OPT_DISPMAP } #endif y = rp->cp_y - pictdata.ysize + 1; if (glyph != NO_GLYPH) { struct BitMap *bm = ifftimg[tbl]; /* 8 bits per byte */ xoff /= 8; yoff *= bm->BytesPerRow; for (j = 0; j < pictdata.nplanes; ++j) { for (k = 0; k < pictdata.ysize; ++k) { memcpy(tile->Planes[j] + ((k * pictdata.ysize) / 8), bm->Planes[j] + xoff + yoff + (bm->BytesPerRow * k), pictdata.ysize / 8); } } BltBitMapRastPort(tile, 0, 0, rp, x, y, pictdata.xsize, pictdata.ysize, 0xc0); apen = rp->FgPen; SetAPen(rp, sysflags.amii_dripens[SHINEPEN]); Move(rp, x - 1, y + pictdata.ysize); Draw(rp, x - 1, y - 1); Draw(rp, x + pictdata.xsize, y - 1); SetAPen(rp, sysflags.amii_dripens[SHADOWPEN]); Move(rp, x + pictdata.xsize, y); Draw(rp, x + pictdata.xsize, y + pictdata.ysize); Draw(rp, x, y + pictdata.ysize); SetAPen(rp, apen); } else if (x > w->BorderLeft) { int apen, bpen; apen = rp->FgPen; bpen = rp->BgPen; SetAPen(rp, amii_menuBPen); SetBPen(rp, amii_menuBPen); RectFill(rp, x - 1, y - 1, x + pictdata.xsize, y + pictdata.ysize); SetAPen(rp, apen); SetBPen(rp, bpen); } } } /* * Define some variables which will be used to save context when toggling * back and forth between low level text and console I/O. */ static long xsave, ysave, modesave, apensave, bpensave; static int usecolor; /* * The function is called before any glyphs are driven to the screen. It * removes the cursor, saves internal state of the window, then returns. */ void amiv_start_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL) panic("bad winid %d in start_glyphout()", window); if (cw->wflags & FLMAP_INGLYPH) return; if (!(w = cw->win)) panic("bad winid %d, no window ptr set", window); /* * Save the context of the window */ xsave = w->RPort->cp_x; ysave = w->RPort->cp_y; modesave = w->RPort->DrawMode; apensave = w->RPort->FgPen; bpensave = w->RPort->BgPen; /* * Set the mode, and be done with it */ usecolor = iflags.use_color; iflags.use_color = FALSE; cw->wflags |= FLMAP_INGLYPH; } /* * General cleanup routine -- flushes and restores cursor */ void amii_end_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL) panic("bad window id %d in amii_end_glyphout()", window); if ((cw->wflags & FLMAP_INGLYPH) == 0) return; cw->wflags &= ~(FLMAP_INGLYPH); if (!(w = cw->win)) panic("bad winid %d, no window ptr set", window); /* * Clean up whatever is left in the buffer */ iflags.use_color = usecolor; /* * Reset internal data structs */ SetAPen(w->RPort, apensave); SetBPen(w->RPort, bpensave); SetDrMd(w->RPort, modesave); Move(w->RPort, xsave, ysave); } static maze_type = COL_MAZE_BRICK; void SetMazeType(MazeType t) { maze_type = t; } int GlyphToIcon(int glyph) { if (glyph > 10000) return glyph; return (glyph2tile[glyph]); } #endif #ifdef AMII_GRAPHICS #ifdef TESTING /* * Define some stuff for our special glyph drawing routines */ static unsigned short glyph_node_index, glyph_buffer_index; #define NUMBER_GLYPH_NODES 80 #define GLYPH_BUFFER_SIZE 512 #endif /* TESTING */ struct amii_glyph_node { short x; short y; short len; unsigned char bg_color; unsigned char fg_color; char *buffer; }; static struct amii_glyph_node amii_g_nodes[NUMBER_GLYPH_NODES]; static char amii_glyph_buffer[GLYPH_BUFFER_SIZE]; #ifdef TEXTCOLOR /* * Map our amiga-specific colormap into the colormap specified in color.h. * See winami.c for the amiga specific colormap. */ int foreg[AMII_MAXCOLORS] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; int backg[AMII_MAXCOLORS] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 }; #if 0 #define CLR_BLACK 0 #define CLR_RED 1 #define CLR_GREEN 2 #define CLR_BROWN 3 /* on IBM, low-intensity yellow is brown */ #define CLR_BLUE 4 #define CLR_MAGENTA 5 #define CLR_CYAN 6 #define CLR_GRAY 7 /* low-intensity white */ #define NO_COLOR 8 #define CLR_ORANGE 9 #define CLR_BRIGHT_GREEN 10 #define CLR_YELLOW 11 #define CLR_BRIGHT_BLUE 12 #define CLR_BRIGHT_MAGENTA 13 #define CLR_BRIGHT_CYAN 14 #define CLR_WHITE 15 #define CLR_MAX 16 #endif #endif #ifndef TESTING /* * Begin Revamped Text display routines * * Up until version 3.1, the only method for displaying text on the playing * field was by using the console.device. This was nice for a number of * reasons, the most signifigant of which was a lot of the nuts and bolts was * done for you via escape sequences interpreted by said device. This did * not come without a price however. And that price was speed. It has now * come to a point where the speed has now been deemed unacceptable. * * The following series of routines are designed to drop into the current * nethack display code, using hooks provided for such a measure. It works * on similar principals as the WindowPuts(), buffering I/O internally * until either an explicit flush or internal buffering is exceeded, thereby * forcing the flush. The output (or glyphs) does not go to the * console.device, however. It is driven directly to the rasterport of the * nethack window via the low-level Text() calls, increasing the speed by * a very signifigant factor. */ /* * Routine to simply flush whatever is buffered */ void amii_flush_glyph_buffer(w) struct Window *w; { short i, x, y; register struct RastPort *rp = w->RPort; /* If nothing is buffered, return before we do anything */ if (glyph_node_index == 0) return; cursor_off(WIN_MAP); amii_start_glyphout(WIN_MAP); /* Set up the drawing mode */ SetDrMd(rp, JAM2); /* Go ahead and start dumping the stuff */ for (i = 0; i < glyph_node_index; ++i) { /* These coordinate calculations must be synced with the * code in amii_curs() in winfuncs.c. curs_on_u() calls amii_curs() * to draw the cursor on top of the player */ y = w->BorderTop + (amii_g_nodes[i].y - 2) * rp->TxHeight + rp->TxBaseline + 1; x = amii_g_nodes[i].x * rp->TxWidth + w->BorderLeft; /* Move pens to correct location */ Move(rp, (long) x, (long) y); /* Setup the colors */ SetAPen(rp, (long) amii_g_nodes[i].fg_color); SetBPen(rp, (long) amii_g_nodes[i].bg_color); /* Do it */ Text(rp, amii_g_nodes[i].buffer, amii_g_nodes[i].len); } amii_end_glyphout(WIN_MAP); /* Clean up */ glyph_node_index = glyph_buffer_index = 0; } void amiga_print_glyph(window, color_index, glyph) winid window; int color_index, glyph; { if (WINVERS_AMIV) amiv_lprint_glyph(window, color_index, glyph); else amii_lprint_glyph(window, color_index, glyph); } /* * Glyph buffering routine. Called instead of WindowPuts(). */ void amii_lprint_glyph(window, color_index, glyph) winid window; int color_index, glyph; { int fg_color, bg_color; struct amii_WinDesc *cw; struct Window *w; int curx; int cury; if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL) panic("bad winid in amii_lprint_glyph: %d", window); w = cw->win; curx = cw->curx; cury = cw->cury; #ifdef TEXTCOLOR fg_color = foreg[color_index]; bg_color = backg[color_index]; #else fg_color = 1; bg_color = 0; #endif /* TEXTCOLOR */ /* See if we have enough character buffer space... */ if (glyph_buffer_index >= GLYPH_BUFFER_SIZE) amii_flush_glyph_buffer(w); /* * See if we can append it to the current active node of glyph buffer. It * must satisfy the following conditions: * * * background colors are the same, AND * * foreground colors are the same, AND * * they are precisely side by side */ if ((glyph_buffer_index != 0) && (fg_color == amii_g_nodes[glyph_node_index - 1].fg_color) && (bg_color == amii_g_nodes[glyph_node_index - 1].bg_color) && (amii_g_nodes[glyph_node_index - 1].x + amii_g_nodes[glyph_node_index - 1].len == curx) && (amii_g_nodes[glyph_node_index - 1].y == cury)) { /* * Add it to the end of the buffer */ amii_glyph_buffer[glyph_buffer_index++] = glyph; amii_g_nodes[glyph_node_index - 1].len++; } else { /* See if we're out of glyph nodes */ if (glyph_node_index >= NUMBER_GLYPH_NODES) amii_flush_glyph_buffer(w); amii_g_nodes[glyph_node_index].len = 1; amii_g_nodes[glyph_node_index].x = curx; amii_g_nodes[glyph_node_index].y = cury; amii_g_nodes[glyph_node_index].fg_color = fg_color; amii_g_nodes[glyph_node_index].bg_color = bg_color; amii_g_nodes[glyph_node_index].buffer = &amii_glyph_buffer[glyph_buffer_index]; amii_glyph_buffer[glyph_buffer_index] = glyph; ++glyph_buffer_index; ++glyph_node_index; } } #endif /* !TESTING */ #ifdef TESTING /* * Define some variables which will be used to save context when toggling * back and forth between low level text and console I/O. */ static long xsave, ysave, modesave, apensave, bpensave; static int usecolor; #endif /* TESTING */ #ifndef TESTING /* * The function is called before any glyphs are driven to the screen. It * removes the cursor, saves internal state of the window, then returns. */ void amii_start_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if ((cw = amii_wins[window]) == (struct amii_WinDesc *) NULL) panic("bad winid %d in start_glyphout()", window); if (cw->wflags & FLMAP_INGLYPH) return; if (!(w = cw->win)) panic("bad winid %d, no window ptr set", window); /* * Save the context of the window */ xsave = w->RPort->cp_x; ysave = w->RPort->cp_y; modesave = w->RPort->DrawMode; apensave = w->RPort->FgPen; bpensave = w->RPort->BgPen; /* * Set the mode, and be done with it */ usecolor = iflags.use_color; iflags.use_color = FALSE; cw->wflags |= FLMAP_INGLYPH; } #endif /* !TESTING */ #if 0 /* * General cleanup routine -- flushes and restores cursor */ void amii_end_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL ) panic("bad window id %d in amii_end_glyphout()", window ); if( ( cw->wflags & FLMAP_INGLYPH ) == 0 ) return; cw->wflags &= ~(FLMAP_INGLYPH); if( !(w = cw->win ) ) panic( "bad winid %d, no window ptr set", window ); /* * Clean up whatever is left in the buffer */ iflags.use_color = usecolor; /* * Reset internal data structs */ SetAPen(w->RPort, apensave); SetBPen(w->RPort, bpensave); SetDrMd(w->RPort, modesave); Move(w->RPort, xsave, ysave); } #endif #endif #ifndef TESTING #ifdef OPT_DISPMAP /* don't use dispmap unless x & y are 8,16,24,32,48 and equal */ void dispmap_sanity() { if (mxsize != mysize || dispmap_sanity1(mxsize) || dispmap_sanity1(mysize)) { sysflags.fast_map = 0; } } int dispmap_sanity1(x) int x; { static unsigned char valid[] = { 8, 16, 24, 32, 48, 0 }; return !!strchr(valid, x); } #endif /* OPT_DISPMAP */ #endif /* TESTING */ nethack-3.6.0/sys/amiga/windefs.h0000664000076400007660000001147412536476415015665 0ustar paxedpaxed/* NetHack 3.6 windefs.h $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #if !defined(_DCC) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include /* stddef.h is included in the precompiled version of hack.h . If we include * it here normally (through string.h) we'll get an "illegal typedef" later * on. This is the easiest way I can think of to fix it without messing * around with the rest of the #includes. --AMC */ #if defined(_DCC) && !defined(HACK_H) #define ptrdiff_t ptrdiff_t_ #define size_t size_t_ #define wchar_t wchar_t_ #endif #include #undef strcmpi #include #include #if defined(_DCC) && !defined(HACK_H) #undef ptrdiff_t #undef size_t #undef wchar_T #endif #ifdef IDCMP_CLOSEWINDOW #ifndef INTUI_NEW_LOOK #define INTUI_NEW_LOOK #endif #endif #ifndef HACK_H #include "hack.h" #endif #include "wintype.h" #include "winami.h" #include "func_tab.h" #ifndef CLIPPING CLIPPING must be defined for the AMIGA version #endif #undef LI #undef CO /*#define TOPL_GETLINE /* Don't use a window for getlin() */ /*#define WINDOW_YN /* Use a window for y/n questions */ #ifdef AZTEC_C #include #else #ifdef _DCC #include #include #include #include #include #include #else #include #include #include #include #include #include #include #endif /* kludge - see amirip for why */ #undef red #undef green #undef blue #ifdef _DCC #include #else #include #endif #ifdef _DCC #define __asm /* DICE doesn't like __asm */ #endif #ifndef __SASC_60 #undef index #define index strchr #endif #ifdef _DCC #include #else #include #endif #endif #ifdef SHAREDLIB #include "NH:sys/amiga/lib/libmacs.h" #endif #ifdef INTUI_NEW_LOOK #include #endif #define WINVERS_AMII (strcmp("amii", windowprocs.name) == 0) #define WINVERS_AMIV (strcmp("amitile", windowprocs.name) == 0) #define WINVERS_AMIT (strcmp("amitty", windowprocs.name) == 0) /* cw->data[x] contains 2 characters worth of special information. These * characters are stored at the offsets as described here. */ #define VATTR 0 /* Video attribute is in this slot */ #define SEL_ITEM 1 /* If this is a select item, slot is 1 else 0 */ #define SOFF 2 /* The string starts here. */ #undef NULL #define NULL 0L /* * Versions we need of various libraries. We can't use LIBRARY_VERSION * as defined in because some of the libraries we need * don't have that version number in the 1.2 ROM. */ #define LIBRARY_FONT_VERSION 34L #define LIBRARY_TILE_VERSION 37L /* These values are just sorta suggestions in use, but are minimum * requirements * in reality... */ #define WINDOWHEIGHT 192 #define SCREENHEIGHT 200 #define WIDTH 640 /* This character is a solid block (cursor) in Hack.font */ #define CURSOR_CHAR 0x90 #define FONTHEIGHT 8 #define FONTWIDTH 8 #define FONTBASELINE 8 #define MAPFTWIDTH 8 #define MAPFTHEIGHT 8 #define MAPFTBASELN 6 /* If Compiling with the "New Look", redefine these now */ #ifdef INTUI_NEW_LOOK #define NewWindow ExtNewWindow #define NewScreen ExtNewScreen #endif #define SIZEOF_DISKNAME 8 #define CSI '\x9b' #define NO_CHAR -1 #define RAWHELP 0x5F /* Rawkey code of the HELP key */ #define C_BLACK 0 #define C_WHITE 1 #define C_BROWN (WINVERS_AMIV ? 11 : 2) #define C_CYAN (WINVERS_AMIV ? 2 : 3) #define C_GREEN (WINVERS_AMIV ? 5 : 4) #define C_MAGENTA (WINVERS_AMIV ? 10 : 5) #define C_BLUE (WINVERS_AMIV ? 4 : 6) #define C_RED 7 #define C_ORANGE 3 #define C_GREY 6 #define C_LTGREEN 8 #define C_YELLOW 9 #define C_GREYBLUE 12 #define C_LTBROWN 13 #define C_LTGREY 14 #define C_PEACH 15 /* Structure describing tile files */ struct PDAT { long nplanes; /* Depth of images */ long pbytes; /* Bytes in a plane of data */ long across; /* Number of tiles across */ long down; /* Number of tiles down */ long npics; /* Number of pictures in this file */ long xsize; /* X-size of a tile */ long ysize; /* Y-size of a-tile */ }; #undef MAXCOLORS #define MAXCOLORS 256 nethack-3.6.0/sys/amiga/winext.h0000664000076400007660000001005312536476415015534 0ustar paxedpaxed/* NetHack 3.6 winext.h $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ extern int reclip; #ifdef CLIPPING extern int clipping; extern int clipx; extern int clipy; extern int clipxmax; extern int clipymax; extern int xclipbord, yclipbord; #endif extern int CO; extern int LI; extern int scrollmsg; extern int alwaysinvent; #ifndef SHAREDLIB extern unsigned short amii_defpens[20]; extern struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ extern struct window_procs amii_procs; extern struct window_procs amiv_procs; extern unsigned short amii_initmap[AMII_MAXCOLORS]; extern unsigned short amiv_init_map[AMII_MAXCOLORS]; extern unsigned short amii_init_map[AMII_MAXCOLORS]; extern int bigscreen; extern int amii_numcolors; extern long amii_scrnmode; extern winid amii_rawprwin; extern struct Screen *HackScreen; extern char Initialized; /* These have already been defined elsewhere (and some are conflicting) * ... going ... going once ... going twice .... * extern const char *roles[]; * extern struct Library *ConsoleDevice; * extern char toplines[ TBUFSZ ]; * extern NEARDATA winid WIN_MESSAGE; * extern NEARDATA winid WIN_MAP; * extern NEARDATA winid WIN_STATUS; * extern NEARDATA winid WIN_INVEN; * extern winid WIN_OVER; * extern struct GfxBase *GfxBase; * extern struct Library *DiskfontBase; * extern struct IntuitionBase *IntuitionBase; * extern struct Library *LayersBase; */ extern int amii_msgAPen; extern int amii_msgBPen; extern int amii_statAPen; extern int amii_statBPen; extern int amii_menuAPen; extern int amii_menuBPen; extern int amii_textAPen; extern int amii_textBPen; extern int amii_otherAPen; extern int amii_otherBPen; #else extern WinamiBASE *WinamiBase; #endif /* All kinds of shared stuff */ extern struct TextAttr Hack160; extern struct TextAttr Hack40; extern struct TextAttr Hack80; extern struct TextAttr TextsFont13; extern struct Window *pr_WindowPtr; extern struct Menu HackMenu[]; extern struct Menu *MenuStrip; extern struct NewMenu GTHackMenu[]; extern APTR *VisualInfo; extern unsigned char KbdBuffered; extern struct TextFont *TextsFont; extern struct TextFont *HackFont; extern struct IOStdReq ConsoleIO; extern struct MsgPort *HackPort; extern int txwidth, txheight, txbaseline; #ifdef SUPERBITMAP_MAP extern struct BitMap amii_vbm; #endif /* This gadget data is replicated for menu/text windows... */ extern struct PropInfo PropScroll; extern struct Image Image1; extern struct Gadget MenuScroll; /* This gadget is for the message window... */ extern struct PropInfo MsgPropScroll; extern struct Image MsgImage1; extern struct Gadget MsgScroll; extern struct TagItem tags[]; extern struct win_setup { struct NewWindow newwin; UWORD offx, offy, maxrow, rows, maxcol, cols; /* CHECK TYPES */ } new_wins[]; extern UWORD scrnpens[]; /* The last Window event is stored here for reference. */ extern WEVENT lastevent; extern const char winpanicstr[]; extern struct TagItem scrntags[]; extern struct NewScreen NewHackScreen; extern int topl_addspace; extern char spaces[76]; extern int wincnt; /* # of nh windows opened */ extern struct Rectangle lastinvent, lastmsg; typedef struct { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE reserved1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; } BitMapHeader; typedef enum { COL_MAZE_BRICK, COL_MAZE_STONE, COL_MAZE_HEAT, COL_MAZE_WOOD } MazeType; extern struct PDAT pictdata; extern struct Hook fillhook; extern struct TagItem wintags[]; #ifndef SHAREDLIB #ifndef __GNUC__ void __asm LayerFillHook(register __a0 struct Hook *hk, register __a2 struct RastPort *rp, register __a1 struct FillParams *fp); #else #ifdef __PPC__ struct EmulLibEntry LayerFillHook; #else void LayerFillHook(void); #endif #endif #endif extern int mxsize, mysize; nethack-3.6.0/sys/amiga/winfuncs.c0000664000076400007660000020646112536476415016057 0ustar paxedpaxed/* NetHack 3.6 winfuncs.c $NHDT-Date: 1433806596 2015/06/08 23:36:36 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #include "patchlevel.h" #include "date.h" extern struct TagItem scrntags[]; static BitMapHeader amii_bmhd; static void cursor_common(struct RastPort *, int, int); #ifdef CLIPPING int CO, LI; /* Changing clipping region, skip clear of screen in overview window. */ int reclip; /* Must be set to at least two or you will get stuck! */ int xclipbord = 4, yclipbord = 2; #endif int mxsize, mysize; struct Rectangle amii_oldover; struct Rectangle amii_oldmsg; extern struct TextFont *RogueFont; int amii_msgAPen; int amii_msgBPen; int amii_statAPen; int amii_statBPen; int amii_menuAPen; int amii_menuBPen; int amii_textAPen; int amii_textBPen; int amii_otherAPen; int amii_otherBPen; long amii_libvers = LIBRARY_FONT_VERSION; void ami_wininit_data(dir) int dir; { extern unsigned short amii_init_map[AMII_MAXCOLORS]; extern unsigned short amiv_init_map[AMII_MAXCOLORS]; if (dir != WININIT) return; if (!WINVERS_AMIV) { #ifdef TEXTCOLOR amii_numcolors = 8; #else amii_numcolors = 4; #endif amii_defpens[0] = C_BLACK; /* DETAILPEN */ amii_defpens[1] = C_BLUE; /* BLOCKPEN */ amii_defpens[2] = C_BROWN; /* TEXTPEN */ amii_defpens[3] = C_WHITE; /* SHINEPEN */ amii_defpens[4] = C_BLUE; /* SHADOWPEN */ amii_defpens[5] = C_CYAN; /* FILLPEN */ amii_defpens[6] = C_WHITE; /* FILLTEXTPEN */ amii_defpens[7] = C_CYAN; /* BACKGROUNDPEN */ amii_defpens[8] = C_RED; /* HIGHLIGHTTEXTPEN */ amii_defpens[9] = C_WHITE; /* BARDETAILPEN */ amii_defpens[10] = C_CYAN; /* BARBLOCKPEN */ amii_defpens[11] = C_BLUE; /* BARTRIMPEN */ amii_defpens[12] = (unsigned short) ~0; amii_msgAPen = C_WHITE; amii_msgBPen = C_BLACK; amii_statAPen = C_WHITE; amii_statBPen = C_BLACK; amii_menuAPen = C_WHITE; amii_menuBPen = C_BLACK; amii_textAPen = C_WHITE; amii_textBPen = C_BLACK; amii_otherAPen = C_RED; amii_otherBPen = C_BLACK; mxsize = 8; mysize = 8; amii_libvers = LIBRARY_FONT_VERSION; memcpy(amii_initmap, amii_init_map, sizeof(amii_initmap)); } else { mxsize = 16; mysize = 16; amii_numcolors = 16; amii_defpens[0] = C_BLACK; /* DETAILPEN */ amii_defpens[1] = C_WHITE; /* BLOCKPEN */ amii_defpens[2] = C_BLACK; /* TEXTPEN */ amii_defpens[3] = C_CYAN; /* SHINEPEN */ amii_defpens[4] = C_BLUE; /* SHADOWPEN */ amii_defpens[5] = C_GREYBLUE; /* FILLPEN */ amii_defpens[6] = C_LTGREY; /* FILLTEXTPEN */ amii_defpens[7] = C_GREYBLUE; /* BACKGROUNDPEN */ amii_defpens[8] = C_RED; /* HIGHLIGHTTEXTPEN */ amii_defpens[9] = C_WHITE; /* BARDETAILPEN */ amii_defpens[10] = C_GREYBLUE; /* BARBLOCKPEN */ amii_defpens[11] = C_BLUE; /* BARTRIMPEN */ amii_defpens[12] = (unsigned short) ~0; amii_msgAPen = C_WHITE; amii_msgBPen = C_GREYBLUE; amii_statAPen = C_WHITE; amii_statBPen = C_GREYBLUE; amii_menuAPen = C_BLACK; amii_menuBPen = C_LTGREY; amii_textAPen = C_BLACK; amii_textBPen = C_LTGREY; amii_otherAPen = C_RED; amii_otherBPen = C_BLACK; amii_libvers = LIBRARY_TILE_VERSION; memcpy(amii_initmap, amiv_init_map, sizeof(amii_initmap)); } #ifdef OPT_DISPMAP dispmap_sanity(); #endif memcpy(sysflags.amii_dripens, amii_defpens, sizeof(sysflags.amii_dripens)); } #ifdef INTUI_NEW_LOOK struct Hook SM_FilterHook; struct Hook fillhook; struct TagItem wintags[] = { { WA_BackFill, (ULONG) &fillhook }, { WA_PubScreenName, (ULONG) "NetHack" }, { TAG_END, 0 }, }; #endif void amii_destroy_nhwindow(win) /* just hide */ register winid win; { int i; int type; register struct amii_WinDesc *cw; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) { panic(winpanicstr, win, "destroy_nhwindow"); } if (WINVERS_AMIV) { if (cw->type == NHW_MAP) { /* If inventory is up, close it now, it will be freed later */ if (alwaysinvent && WIN_INVEN != WIN_ERR && amii_wins[WIN_INVEN] && amii_wins[WIN_INVEN]->win) { dismiss_nhwindow(WIN_INVEN); } /* Tear down overview window if it is up */ if (WIN_OVER != WIN_ERR) { amii_destroy_nhwindow(WIN_OVER); WIN_OVER = WIN_ERR; } } else if (cw->type == NHW_OVER) { struct Window *w = amii_wins[WIN_OVER]->win; amii_oldover.MinX = w->LeftEdge; amii_oldover.MinY = w->TopEdge; amii_oldover.MaxX = w->Width; amii_oldover.MaxY = w->Height; if (WIN_MESSAGE != WIN_ERR && amii_wins[WIN_MESSAGE]) { w = amii_wins[WIN_MESSAGE]->win; amii_oldmsg.MinX = w->LeftEdge; amii_oldmsg.MinY = w->TopEdge; amii_oldmsg.MaxX = w->Width; amii_oldmsg.MaxY = w->Height; SizeWindow(amii_wins[WIN_MESSAGE]->win, (amiIDisplay->xpix - amii_wins[WIN_MESSAGE]->win->LeftEdge) - amii_wins[WIN_MESSAGE]->win->Width, 0); } } } /* Tear down the Intuition stuff */ dismiss_nhwindow(win); type = cw->type; if (cw->resp) { free(cw->resp); cw->resp = NULL; } if (cw->canresp) { free(cw->canresp); cw->canresp = NULL; } if (cw->morestr) { free(cw->morestr); cw->morestr = NULL; } if (cw->hook) { free(cw->hook); cw->hook = NULL; } if (cw->data && (cw->type == NHW_MESSAGE || cw->type == NHW_MENU || cw->type == NHW_TEXT)) { for (i = 0; i < cw->maxrow; ++i) { if (cw->data[i]) free(cw->data[i]); } free(cw->data); } free(cw); amii_wins[win] = NULL; /* Set globals to WIN_ERR for known one-of-a-kind windows. */ if (win == WIN_MAP) WIN_MAP = WIN_ERR; else if (win == WIN_STATUS) WIN_STATUS = WIN_ERR; else if (win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR; else if (win == WIN_INVEN) WIN_INVEN = WIN_ERR; } #ifdef INTUI_NEW_LOOK struct FillParams { struct Layer *layer; struct Rectangle bounds; WORD offsetx; WORD offsety; }; #ifdef __GNUC__ #ifdef __PPC__ void PPC_LayerFillHook(void); struct EmulLibEntry LayerFillHook = { TRAP_LIB, 0, (void (*)(void)) PPC_LayerFillHook }; void PPC_LayerFillHook(void) { struct Hook *hk = (struct Hook *) REG_A0; struct RastPort *rp = (struct RastPort *) REG_A2; struct FillParams *fp = (struct FillParams *) REG_A1; #else void LayerFillHook(void) { register struct Hook *hk asm("a0"); register struct RastPort *rp asm("a2"); register struct FillParams *fp asm("a1"); #endif #else void #ifndef _DCC __interrupt #endif __saveds __asm LayerFillHook(register __a0 struct Hook *hk, register __a2 struct RastPort *rp, register __a1 struct FillParams *fp) { #endif register long x, y, xmax, ymax; register int apen; struct RastPort rptmp; memcpy(&rptmp, rp, sizeof(struct RastPort)); rptmp.Layer = NULL; switch ((int) hk->h_Data) { case NHW_STATUS: apen = amii_statBPen; break; case NHW_MESSAGE: apen = amii_msgBPen; break; case NHW_TEXT: apen = amii_textBPen; break; case NHW_MENU: apen = amii_menuBPen; break; case -2: apen = amii_otherBPen; break; case NHW_BASE: case NHW_MAP: case NHW_OVER: default: apen = C_BLACK; break; } x = fp->bounds.MinX; y = fp->bounds.MinY; xmax = fp->bounds.MaxX; ymax = fp->bounds.MaxY; SetAPen(&rptmp, apen); SetBPen(&rptmp, apen); SetDrMd(&rptmp, JAM2); RectFill(&rptmp, x, y, xmax, ymax); } #endif amii_create_nhwindow(type) register int type; { register struct Window *w = NULL; register struct NewWindow *nw = NULL; register struct amii_WinDesc *wd = NULL; struct Window *mapwin = NULL, *stwin = NULL, *msgwin = NULL; register int newid; int maph, stath, scrfontysize; scrfontysize = HackScreen->Font->ta_YSize; /* * Initial mapwindow height, this might change later in tilemode * and low screen */ maph = (21 * mxsize) + 2 + (bigscreen ? HackScreen->WBorTop + HackScreen->WBorBottom + scrfontysize + 1 : 0); /* Status window height, avoids having to calculate many times */ stath = txheight * 2 + 2 + (WINVERS_AMIV || bigscreen ? HackScreen->WBorTop + HackScreen->WBorBottom + (bigscreen ? scrfontysize + 1 : 0) : 0); if (WIN_STATUS != WIN_ERR && amii_wins[WIN_STATUS]) stwin = amii_wins[WIN_STATUS]->win; if (WIN_MESSAGE != WIN_ERR && amii_wins[WIN_MESSAGE]) msgwin = amii_wins[WIN_MESSAGE]->win; if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) mapwin = amii_wins[WIN_MAP]->win; /* Create Port anytime that we need it */ if (HackPort == NULL) { HackPort = CreateMsgPort(); if (!HackPort) panic("no memory for msg port"); } nw = &new_wins[type].newwin; nw->Width = amiIDisplay->xpix; nw->Screen = HackScreen; if (WINVERS_AMIV) { nw->DetailPen = C_WHITE; nw->BlockPen = C_GREYBLUE; } else { nw->DetailPen = C_WHITE; nw->BlockPen = C_BLACK; } if (type == NHW_BASE) { nw->LeftEdge = 0; nw->TopEdge = HackScreen->BarHeight + 1; nw->Width = HackScreen->Width; nw->Height = HackScreen->Height - nw->TopEdge; } else if (!WINVERS_AMIV && type == NHW_MAP) { nw->LeftEdge = 0; nw->Height = maph; if (msgwin && stwin) { nw->TopEdge = stwin->TopEdge - maph; } else { panic("msgwin and stwin must open before map"); } if (nw->TopEdge < 0) panic("Too small screen to fit map"); } else if (type == NHW_MAP && WINVERS_AMIV) { struct Window *w; w = amii_wins[WIN_MESSAGE]->win; nw->LeftEdge = 0; nw->TopEdge = w->TopEdge + w->Height; nw->Width = amiIDisplay->xpix - nw->LeftEdge; w = amii_wins[WIN_STATUS]->win; nw->Height = w->TopEdge - nw->TopEdge; nw->MaxHeight = 0xffff; nw->MaxWidth = 0xffff; if (nw->TopEdge + nw->Height > amiIDisplay->ypix - 1) nw->Height = amiIDisplay->ypix - nw->TopEdge - 1; } else if (type == NHW_STATUS) { if (!WINVERS_AMIV && (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP])) w = amii_wins[WIN_MAP]->win; else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) w = amii_wins[WIN_BASE]->win; else panic("No window to base STATUS location from"); nw->Height = stath; nw->TopEdge = amiIDisplay->ypix - nw->Height; nw->LeftEdge = w->LeftEdge; if (nw->LeftEdge + nw->Width >= amiIDisplay->xpix) nw->LeftEdge = 0; if (nw->Width >= amiIDisplay->xpix - nw->LeftEdge) nw->Width = amiIDisplay->xpix - nw->LeftEdge; } else if (WINVERS_AMIV && type == NHW_OVER) { nw->Flags |= WINDOWSIZING | WINDOWDRAG | WINDOWCLOSE; nw->IDCMPFlags |= CLOSEWINDOW; /* Bring up window as half the width of the message window, and make * the message window change to one half the width... */ if (amii_oldover.MaxX != 0) { nw->LeftEdge = amii_oldover.MinX; nw->TopEdge = amii_oldover.MinY; nw->Width = amii_oldover.MaxX; nw->Height = amii_oldover.MaxY; ChangeWindowBox(amii_wins[WIN_MESSAGE]->win, amii_oldmsg.MinX, amii_oldmsg.MinY, amii_oldmsg.MaxX, amii_oldmsg.MaxY); } else { nw->LeftEdge = (amii_wins[WIN_MESSAGE]->win->Width * 4) / 9; nw->TopEdge = amii_wins[WIN_MESSAGE]->win->TopEdge; nw->Width = amiIDisplay->xpix - nw->LeftEdge; nw->Height = amii_wins[WIN_MESSAGE]->win->Height; SizeWindow(amii_wins[WIN_MESSAGE]->win, nw->LeftEdge - amii_wins[WIN_MESSAGE]->win->Width, 0); } } else if (type == NHW_MESSAGE) { if (!WINVERS_AMIV && (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP])) w = amii_wins[WIN_MAP]->win; else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) w = amii_wins[WIN_BASE]->win; else panic("No window to base STATUS location from"); nw->TopEdge = bigscreen ? HackScreen->BarHeight + 1 : 0; /* Assume highest possible message window */ nw->Height = HackScreen->Height - nw->TopEdge - maph - stath; /* In tilemode we can cope with this */ if (WINVERS_AMIV && nw->Height < 0) nw->Height = 0; /* If in fontmode messagewindow is too small, open it with 3 lines and overlap it with map */ if (nw->Height < txheight + 2) { nw->Height = txheight * 4 + 3 + HackScreen->WBorTop + HackScreen->WBorBottom; } if ((nw->Height - 2) / txheight < 3) { scrollmsg = 0; nw->Title = 0; } else { nw->FirstGadget = &MsgScroll; nw->Flags |= WINDOWSIZING | WINDOWDRAG; nw->Flags &= ~BORDERLESS; if (WINVERS_AMIV || nw->Height == 0) { if (WINVERS_AMIV) { nw->Height = TextsFont->tf_YSize + HackScreen->WBorTop + 3 + HackScreen->WBorBottom; if (bigscreen) nw->Height += (txheight * 6); else nw->Height += (txheight * 3); } else { nw->Height = HackScreen->Height - nw->TopEdge - stath - maph; } } } /* Do we have room for larger message window ? * This is possible if we can show full height map in tile * mode with default scaling. */ if (nw->Height + stath + maph < HackScreen->Height - nw->TopEdge) nw->Height = HackScreen->Height - nw->TopEdge - 1 - maph - stath; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { MsgPropScroll.Flags |= PROPNEWLOOK; PropScroll.Flags |= PROPNEWLOOK; } #endif } nw->IDCMPFlags |= MENUPICK; /* Check if there is "Room" for all this stuff... */ if ((WINVERS_AMIV || bigscreen) && type != NHW_BASE) { nw->Flags &= ~(BORDERLESS | BACKDROP); if (WINVERS_AMIV) { if (type == NHW_STATUS) { nw->Flags &= ~(WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING); nw->IDCMPFlags &= ~NEWSIZE; } else { nw->Flags |= (WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING); nw->IDCMPFlags |= NEWSIZE; } } else { if (HackScreen->Width < 657) { nw->Flags |= (WINDOWDRAG | WINDOWDEPTH); } else { nw->Flags |= (WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT); } } } if (WINVERS_AMII && type == NHW_MAP) nw->Flags &= ~WINDOWSIZING; if (type == NHW_MESSAGE && scrollmsg) { nw->Flags |= WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING; nw->Flags &= ~BORDERLESS; } /* No titles on a hires only screen except for messagewindow */ if (!(WINVERS_AMIV && type == NHW_MAP) && !bigscreen && type != NHW_MESSAGE) nw->Title = 0; wd = (struct amii_WinDesc *) alloc(sizeof(struct amii_WinDesc)); memset(wd, 0, sizeof(struct amii_WinDesc)); /* Both, since user may have changed the pen settings so respect those */ if (WINVERS_AMII || WINVERS_AMIV) { /* Special backfill for these types of layers */ switch (type) { case NHW_MESSAGE: case NHW_STATUS: case NHW_TEXT: case NHW_MENU: case NHW_BASE: case NHW_OVER: case NHW_MAP: if (wd) { #ifdef __GNUC__ fillhook.h_Entry = (void *) &LayerFillHook; #else fillhook.h_Entry = (ULONG (*) ()) LayerFillHook; #endif fillhook.h_Data = (void *) type; fillhook.h_SubEntry = 0; wd->hook = alloc(sizeof(fillhook)); memcpy(wd->hook, &fillhook, sizeof(fillhook)); memcpy(wd->wintags, wintags, sizeof(wd->wintags)); wd->wintags[0].ti_Data = (long) wd->hook; nw->Extension = (void *) wd->wintags; } break; } } /* Don't open MENU or TEXT windows yet */ if (type == NHW_MENU || type == NHW_TEXT) w = NULL; else w = OpenShWindow((void *) nw); if (w == NULL && type != NHW_MENU && type != NHW_TEXT) { char buf[100]; sprintf(buf, "nw type (%d) dims l: %d, t: %d, w: %d, h: %d", type, nw->LeftEdge, nw->TopEdge, nw->Width, nw->Height); raw_print(buf); panic("bad openwin %d", type); } /* Check for an empty slot */ for (newid = 0; newid < MAXWIN + 1; newid++) { if (amii_wins[newid] == 0) break; } if (newid == MAXWIN + 1) panic("time to write re-alloc code\n"); /* Set wincnt accordingly */ if (newid > wincnt) wincnt = newid; /* Do common initialization */ amii_wins[newid] = wd; wd->newwin = NULL; wd->win = w; wd->type = type; wd->wflags = 0; wd->active = FALSE; wd->curx = wd->cury = 0; wd->resp = wd->canresp = wd->morestr = 0; /* CHECK THESE */ wd->maxrow = new_wins[type].maxrow; wd->maxcol = new_wins[type].maxcol; if (type != NHW_TEXT && type != NHW_MENU) { if (TextsFont && (type == NHW_MESSAGE || type == NHW_STATUS)) { SetFont(w->RPort, TextsFont); txheight = w->RPort->TxHeight; txwidth = w->RPort->TxWidth; txbaseline = w->RPort->TxBaseline; if (type == NHW_MESSAGE) { if (scrollmsg) { if (WINVERS_AMIV) { WindowLimits(w, 100, w->BorderTop + w->BorderBottom + ((txheight + 1) * 2) + 1, 0, 0); } else { WindowLimits(w, w->Width, w->BorderTop + w->BorderBottom + ((txheight + 1) * 2) + 1, 0, 0); } } else { WindowLimits(w, w->Width, w->BorderTop + w->BorderBottom + txheight + 2, 0, 0); } } } if (type != NHW_MAP) { SetFont(w->RPort, TextsFont); } #ifdef HACKFONT else if (HackFont) SetFont(w->RPort, HackFont); #endif } /* Text and menu windows are not opened yet */ if (w) { wd->rows = (w->Height - w->BorderTop - w->BorderBottom - 2) / w->RPort->TxHeight; wd->cols = (w->Width - w->BorderLeft - w->BorderRight - 2) / w->RPort->TxWidth; } /* Okay, now do the individual type initialization */ switch (type) { /* History lines for MESSAGE windows are stored in cw->data[?]. * maxcol and maxrow are used as cursors. maxrow is the count * of the number of history lines stored. maxcol is the cursor * to the last line that was displayed by ^P. */ case NHW_MESSAGE: SetMenuStrip(w, MenuStrip); MsgScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; iflags.msg_history = wd->rows * 10; if (iflags.msg_history < 40) iflags.msg_history = 40; if (iflags.msg_history > 400) iflags.msg_history = 400; iflags.window_inited = TRUE; wd->data = (char **) alloc(iflags.msg_history * sizeof(char *)); memset(wd->data, 0, iflags.msg_history * sizeof(char *)); wd->maxrow = wd->maxcol = 0; /* Indicate that we have not positioned the cursor yet */ wd->curx = -1; break; /* A MENU contains a list of lines in wd->data[?]. These * lines are created in amii_putstr() by reallocating the size * of wd->data to hold enough (char *)'s. wd->rows is the * number of (char *)'s allocated. wd->maxrow is the number * used. wd->maxcol is used to track how wide the menu needs * to be. wd->resp[x] contains the characters that correspond * to selecting wd->data[x]. wd->resp[x] corresponds to * wd->data[x] for any x. Elements of wd->data[?] that are not * valid selections have the corresponding element of * wd->resp[] set to a value of '\01'; i.e. a ^A which is * not currently a valid keystroke for responding to any * MENU or TEXT window. */ case NHW_MENU: MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; wd->resp = (char *) alloc(256); wd->resp[0] = 0; wd->rows = wd->maxrow = 0; wd->cols = wd->maxcol = 0; wd->data = NULL; break; /* See the explanation of MENU above. Except, wd->resp[] is not * used for TEXT windows since there is no selection of a * a line performed/allowed. The window is always full * screen width. */ case NHW_TEXT: MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; wd->rows = wd->maxrow = 0; wd->cols = wd->maxcol = amiIDisplay->cols; wd->data = NULL; wd->morestr = NULL; break; /* The status window has only two lines. These are stored in * wd->data[], and here we allocate the space for them. */ case NHW_STATUS: SetMenuStrip(w, MenuStrip); /* wd->cols is the number of characters which fit across the * screen. */ wd->data = (char **) alloc(3 * sizeof(char *)); wd->data[0] = (char *) alloc(wd->cols + 10); wd->data[1] = (char *) alloc(wd->cols + 10); wd->data[2] = NULL; break; /* NHW_OVER does not use wd->data[] or the other text * manipulating members of the amii_WinDesc structure. */ case NHW_OVER: SetMenuStrip(w, MenuStrip); break; /* NHW_MAP does not use wd->data[] or the other text * manipulating members of the amii_WinDesc structure. */ case NHW_MAP: SetMenuStrip(w, MenuStrip); if (WINVERS_AMIV) { CO = (w->Width - w->BorderLeft - w->BorderRight) / mxsize; LI = (w->Height - w->BorderTop - w->BorderBottom) / mysize; amii_setclipped(); SetFont(w->RPort, RogueFont); SetAPen(w->RPort, C_WHITE); /* XXX not sufficient */ SetBPen(w->RPort, C_BLACK); SetDrMd(w->RPort, JAM2); } else { if (HackFont) SetFont(w->RPort, HackFont); } break; /* The base window must exist until CleanUp() deletes it. */ case NHW_BASE: SetMenuStrip(w, MenuStrip); /* Make our requesters come to our screen */ { register struct Process *myProcess = (struct Process *) FindTask(NULL); pr_WindowPtr = (struct Window *) (myProcess->pr_WindowPtr); myProcess->pr_WindowPtr = (APTR) w; } /* Need this for RawKeyConvert() */ ConsoleIO.io_Data = (APTR) w; ConsoleIO.io_Length = sizeof(struct Window); ConsoleIO.io_Message.mn_ReplyPort = CreateMsgPort(); if (OpenDevice("console.device", -1L, (struct IORequest *) &ConsoleIO, 0L) != 0) { Abort(AG_OpenDev | AO_ConsoleDev); } ConsoleDevice = (struct Library *) ConsoleIO.io_Device; KbdBuffered = 0; #ifdef HACKFONT if (TextsFont) SetFont(w->RPort, TextsFont); else if (HackFont) SetFont(w->RPort, HackFont); #endif txwidth = w->RPort->TxWidth; txheight = w->RPort->TxHeight; txbaseline = w->RPort->TxBaseline; break; default: panic("bad create_nhwindow( %d )\n", type); return WIN_ERR; } return (newid); } #ifdef __GNUC__ #ifdef __PPC__ int PPC_SM_Filter(void); struct EmulLibEntry SM_Filter = { TRAP_LIB, 0, (int (*)(void)) PPC_SM_Filter }; int PPC_SM_Filter(void) { struct Hook *hk = (struct Hook *) REG_A0; ULONG modeID = (ULONG) REG_A1; struct ScreenModeRequester *smr = (struct ScreenModeRequester *) REG_A2; #else int SM_Filter(void) { register struct Hook *hk asm("a0"); register ULONG modeID asm("a1"); register struct ScreenModeRequester *smr asm("a2"); #endif #else int #ifndef _DCC __interrupt #endif __saveds __asm SM_Filter( register __a0 struct Hook *hk, register __a1 ULONG modeID, register __a2 struct ScreenModeRequester *smr) { #endif struct DimensionInfo dims; struct DisplayInfo disp; DisplayInfoHandle handle; handle = FindDisplayInfo(modeID); if (handle) { GetDisplayInfoData(handle, (char *) &dims, sizeof(dims), DTAG_DIMS, modeID); GetDisplayInfoData(handle, (char *) &disp, sizeof(disp), DTAG_DISP, modeID); if (!disp.NotAvailable && dims.MaxDepth <= 8 && dims.StdOScan.MaxX >= WIDTH - 1 && dims.StdOScan.MaxY >= SCREENHEIGHT - 1) { return 1; } } return 0; } /* Initialize the windowing environment */ void amii_init_nhwindows(argcp, argv) int *argcp; char **argv; { int i; struct Screen *wbscr; int forcenobig = 0; if (HackScreen) panic("init_nhwindows() called twice", 0); /* run args & set bigscreen from -L(1)/-l(-1) */ { int lclargc = *argcp; int t; char **argv_in = argv; char **argv_out = argv; for (t = 1; t <= lclargc; t++) { if (!strcmp("-L", *argv_in) || !strcmp("-l", *argv_in)) { bigscreen = (*argv_in[1] == 'l') ? -1 : 1; /* and eat the flag */ (*argcp)--; } else { *argv_out = *argv_in; /* keep the flag */ argv_out++; } argv_in++; } *argv_out = 0; } WIN_MESSAGE = WIN_ERR; WIN_MAP = WIN_ERR; WIN_STATUS = WIN_ERR; WIN_INVEN = WIN_ERR; WIN_BASE = WIN_ERR; WIN_OVER = WIN_ERR; if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_Intuition); } if ((GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_GraphicsLib); } if ((LayersBase = (struct Library *) OpenLibrary("layers.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_LayersLib); } if ((GadToolsBase = OpenLibrary("gadtools.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_GadTools); } if ((AslBase = OpenLibrary("asl.library", amii_libvers)) == NULL) { Abort(AG_OpenLib); } amiIDisplay = (struct amii_DisplayDesc *) alloc(sizeof(struct amii_DisplayDesc)); memset(amiIDisplay, 0, sizeof(struct amii_DisplayDesc)); /* Use Intuition sizes for overscan screens... */ amiIDisplay->xpix = 0; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { if (wbscr = LockPubScreen("Workbench")) { amiIDisplay->xpix = wbscr->Width; amiIDisplay->ypix = wbscr->Height; UnlockPubScreen(NULL, wbscr); } } #endif if (amiIDisplay->xpix == 0) { amiIDisplay->ypix = GfxBase->NormalDisplayRows; amiIDisplay->xpix = GfxBase->NormalDisplayColumns; } amiIDisplay->cols = amiIDisplay->xpix / FONTWIDTH; amiIDisplay->toplin = 0; amiIDisplay->rawprint = 0; amiIDisplay->lastwin = 0; if (bigscreen == 0) { if ((GfxBase->ActiView->ViewPort->Modes & LACE) == LACE) { amiIDisplay->ypix *= 2; NewHackScreen.ViewModes |= LACE; bigscreen = 1; } else if (GfxBase->NormalDisplayRows >= 300 || amiIDisplay->ypix >= 300) { bigscreen = 1; } } else if (bigscreen == -1) { bigscreen = 0; forcenobig = 1; } else if (bigscreen) { /* If bigscreen requested and we don't have enough rows in * noninterlaced mode, switch to interlaced... */ if (GfxBase->NormalDisplayRows < 300) { amiIDisplay->ypix *= 2; NewHackScreen.ViewModes |= LACE; } } if (!bigscreen) { alwaysinvent = 0; } amiIDisplay->rows = amiIDisplay->ypix / FONTHEIGHT; #ifdef HACKFONT /* * Load the fonts that we need. */ if (DiskfontBase = OpenLibrary("diskfont.library", amii_libvers)) { Hack80.ta_Name -= SIZEOF_DISKNAME; HackFont = OpenDiskFont(&Hack80); Hack80.ta_Name += SIZEOF_DISKNAME; /* Textsfont13 is filled in with "FONT=" settings. The default is * courier/13. */ TextsFont = NULL; if (bigscreen) TextsFont = OpenDiskFont(&TextsFont13); /* Try hack/8 for texts if no user specified font */ if (TextsFont == NULL) { Hack80.ta_Name -= SIZEOF_DISKNAME; TextsFont = OpenDiskFont(&Hack80); Hack80.ta_Name += SIZEOF_DISKNAME; } /* If no fonts, make everything topaz 8 for non-view windows. */ Hack80.ta_Name = "topaz.font"; RogueFont = OpenFont(&Hack80); if (!RogueFont) panic("Can't get topaz:8"); if (!HackFont || !TextsFont) { if (!HackFont) { HackFont = OpenFont(&Hack80); if (!HackFont) panic("Can't get a map font, topaz:8"); } if (!TextsFont) { TextsFont = OpenFont(&Hack80); if (!TextsFont) panic("Can't open text font"); } } CloseLibrary(DiskfontBase); DiskfontBase = NULL; } #endif /* Adjust getlin window size to font */ if (TextsFont) { extern SHORT BorderVectors1[]; extern SHORT BorderVectors2[]; extern struct Gadget Gadget2; extern struct Gadget String; extern struct NewWindow StrWindow; BorderVectors1[2] += (TextsFont->tf_XSize - 8) * 6; /* strlen("Cancel") == 6 */ BorderVectors1[4] += (TextsFont->tf_XSize - 8) * 6; BorderVectors1[5] += TextsFont->tf_YSize - 8; BorderVectors1[7] += TextsFont->tf_YSize - 8; BorderVectors2[2] += (TextsFont->tf_XSize - 8) * 6; BorderVectors2[4] += (TextsFont->tf_XSize - 8) * 6; BorderVectors2[5] += TextsFont->tf_YSize - 8; BorderVectors2[7] += TextsFont->tf_YSize - 8; Gadget2.TopEdge += TextsFont->tf_YSize - 8; Gadget2.Width += (TextsFont->tf_XSize - 8) * 6; Gadget2.Height += TextsFont->tf_YSize - 8; String.LeftEdge += (TextsFont->tf_XSize - 8) * 6; String.TopEdge += TextsFont->tf_YSize - 8; String.Width += TextsFont->tf_XSize - 8; String.Height += TextsFont->tf_YSize - 8; StrWindow.Width += (TextsFont->tf_XSize - 8) * 7; StrWindow.Height += (TextsFont->tf_YSize - 8) * 2; /* Titlebar + 1 row of gadgets */ } /* This is the size screen we want to open, within reason... */ NewHackScreen.Width = max(WIDTH, amiIDisplay->xpix); NewHackScreen.Height = max(SCREENHEIGHT, amiIDisplay->ypix); { static char fname[18]; sprintf(fname, "NetHack %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); NewHackScreen.DefaultTitle = fname; } #if 0 NewHackScreen.BlockPen = C_BLACK; NewHackScreen.DetailPen = C_WHITE; #endif #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { int i; struct DimensionInfo dims; DisplayInfoHandle handle; struct DisplayInfo disp; ULONG modeid = DEFAULT_MONITOR_ID | HIRES_KEY; NewHackScreen.Width = STDSCREENWIDTH; NewHackScreen.Height = STDSCREENHEIGHT; #ifdef HACKFONT if (TextsFont) { NewHackScreen.Font = &TextsFont13; } #endif if (amii_scrnmode == 0xffffffff) { struct ScreenModeRequester *SMR; #ifdef __GNUC__ SM_FilterHook.h_Entry = (void *) &SM_Filter; #else SM_FilterHook.h_Entry = (ULONG (*) ()) SM_Filter; #endif SM_FilterHook.h_Data = 0; SM_FilterHook.h_SubEntry = 0; SMR = AllocAslRequest(ASL_ScreenModeRequest, NULL); if (AslRequestTags(SMR, ASLSM_FilterFunc, (ULONG) &SM_FilterHook, TAG_END)) amii_scrnmode = SMR->sm_DisplayID; else amii_scrnmode = 0; FreeAslRequest(SMR); } if (forcenobig == 0) { if ((wbscr = LockPubScreen("Workbench")) != NULL || (wbscr = LockPubScreen(NULL)) != NULL) { /* Get the default pub screen's size */ modeid = GetVPModeID(&wbscr->ViewPort); if (modeid == INVALID_ID || ModeNotAvailable(modeid) || (handle = FindDisplayInfo(modeid)) == NULL || GetDisplayInfoData(handle, (char *) &dims, sizeof(dims), DTAG_DIMS, modeid) <= 0 || GetDisplayInfoData(handle, (char *) &disp, sizeof(disp), DTAG_DISP, modeid) <= 0) { modeid = DEFAULT_MONITOR_ID | HIRES_KEY; /* If the display database seems to not work, use the * screen * dimensions */ NewHackScreen.Height = wbscr->Height; NewHackScreen.Width = wbscr->Width; /* * Request LACE if it looks laced. For 2.1/3.0, we will * get * promoted to the users choice of modes (if promotion is * allowed) * If the user is using a dragable screen, things will get * hosed * but that is life... */ if (wbscr->ViewPort.Modes & LACE) NewHackScreen.ViewModes |= LACE; modeid = -1; } else { /* Use the display database to get the correct information */ if (disp.PropertyFlags & DIPF_IS_LACE) NewHackScreen.ViewModes |= LACE; NewHackScreen.Height = dims.StdOScan.MaxY + 1; NewHackScreen.Width = dims.StdOScan.MaxX + 1; } NewHackScreen.TopEdge = 0; NewHackScreen.LeftEdge = 0; UnlockPubScreen(NULL, wbscr); } } for (i = 0; scrntags[i].ti_Tag != TAG_DONE; ++i) { switch (scrntags[i].ti_Tag) { case SA_DisplayID: if (!amii_scrnmode || ModeNotAvailable(amii_scrnmode)) { if (ModeNotAvailable(modeid)) { scrntags[i].ti_Tag = TAG_IGNORE; break; } else scrntags[i].ti_Data = (long) modeid; } else modeid = scrntags[i].ti_Data = (long) amii_scrnmode; if ((handle = FindDisplayInfo(modeid)) != NULL && GetDisplayInfoData(handle, (char *) &dims, sizeof(dims), DTAG_DIMS, modeid) > 0 && GetDisplayInfoData(handle, (char *) &disp, sizeof(disp), DTAG_DISP, modeid) > 0) { if (disp.PropertyFlags & DIPF_IS_LACE) NewHackScreen.ViewModes |= LACE; NewHackScreen.Height = dims.StdOScan.MaxY + 1; NewHackScreen.Width = dims.StdOScan.MaxX + 1; } break; case SA_Pens: scrntags[i].ti_Data = (long) sysflags.amii_dripens; break; } } } #endif if (WINVERS_AMIV) amii_bmhd = ReadTileImageFiles(); else memcpy(amii_initmap, amii_init_map, sizeof(amii_initmap)); memcpy(sysflags.amii_curmap, amii_initmap, sizeof(sysflags.amii_curmap)); /* Find out how deep the screen needs to be, 32 planes is enough! */ for (i = 0; i < 32; ++i) { if ((1L << i) >= amii_numcolors) break; } NewHackScreen.Depth = i; /* If for some reason Height/Width became smaller than the required, have the required one */ if (NewHackScreen.Height < SCREENHEIGHT) NewHackScreen.Height = SCREENHEIGHT; if (NewHackScreen.Width < WIDTH) NewHackScreen.Width = WIDTH; #ifdef HACKFONT i = max(TextsFont->tf_XSize, HackFont->tf_XSize); if (NewHackScreen.Width < 80 * i + 4) NewHackScreen.Width = 80 * i + 4; #endif /* While openscreen fails try fewer colors to see if that is the problem. */ while ((HackScreen = OpenScreen((void *) &NewHackScreen)) == NULL) { #ifdef TEXTCOLOR if (--NewHackScreen.Depth < 3) #else if (--NewHackScreen.Depth < 2) #endif Abort(AN_OpenScreen & ~AT_DeadEnd); } amii_numcolors = 1L << NewHackScreen.Depth; if (HackScreen->Height > 300 && forcenobig == 0) bigscreen = 1; else bigscreen = 0; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) PubScreenStatus(HackScreen, 0); #endif amiIDisplay->ypix = HackScreen->Height; amiIDisplay->xpix = HackScreen->Width; LoadRGB4(&HackScreen->ViewPort, sysflags.amii_curmap, amii_numcolors); VisualInfo = GetVisualInfo(HackScreen, TAG_END); MenuStrip = CreateMenus(GTHackMenu, TAG_END); LayoutMenus(MenuStrip, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END); /* Display the copyright etc... */ if (WIN_BASE == WIN_ERR) WIN_BASE = amii_create_nhwindow(NHW_BASE); amii_clear_nhwindow(WIN_BASE); amii_putstr(WIN_BASE, 0, ""); amii_putstr(WIN_BASE, 0, ""); amii_putstr(WIN_BASE, 0, ""); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_A); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_B); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_C); amii_putstr(WIN_BASE, 0, COPYRIGHT_BANNER_D); amii_putstr(WIN_BASE, 0, ""); Initialized = 1; } void amii_sethipens(struct Window *w, int type, int attr) { switch (type) { default: SetAPen(w->RPort, attr ? C_RED : amii_otherAPen); SetBPen(w->RPort, C_BLACK); break; case NHW_STATUS: SetAPen(w->RPort, attr ? C_WHITE : amii_statAPen); SetBPen(w->RPort, amii_statBPen); break; case NHW_MESSAGE: SetAPen(w->RPort, attr ? C_WHITE : amii_msgAPen); SetBPen(w->RPort, amii_msgBPen); break; case NHW_MENU: SetAPen(w->RPort, attr ? C_BLACK : amii_menuAPen); SetBPen(w->RPort, amii_menuBPen); break; case NHW_TEXT: SetAPen(w->RPort, attr ? C_BLACK : amii_textAPen); SetBPen(w->RPort, amii_textBPen); case -2: SetBPen(w->RPort, amii_otherBPen); SetAPen(w->RPort, attr ? C_RED : amii_otherAPen); break; } } void amii_setfillpens(struct Window *w, int type) { switch (type) { case NHW_MESSAGE: SetAPen(w->RPort, amii_msgBPen); SetBPen(w->RPort, amii_msgBPen); break; case NHW_STATUS: SetAPen(w->RPort, amii_statBPen); SetBPen(w->RPort, amii_statBPen); break; case NHW_MENU: SetAPen(w->RPort, amii_menuBPen); SetBPen(w->RPort, amii_menuBPen); break; case NHW_TEXT: SetAPen(w->RPort, amii_textBPen); SetBPen(w->RPort, amii_textBPen); break; case NHW_MAP: case NHW_BASE: case NHW_OVER: default: SetAPen(w->RPort, C_BLACK); SetBPen(w->RPort, C_BLACK); break; case -2: SetAPen(w->RPort, amii_otherBPen); SetBPen(w->RPort, amii_otherBPen); break; } } void amii_setdrawpens(struct Window *w, int type) { switch (type) { case NHW_MESSAGE: SetAPen(w->RPort, amii_msgAPen); SetBPen(w->RPort, amii_msgBPen); break; case NHW_STATUS: SetAPen(w->RPort, amii_statAPen); SetBPen(w->RPort, amii_statBPen); break; case NHW_MENU: SetAPen(w->RPort, amii_menuAPen); SetBPen(w->RPort, amii_menuBPen); break; case NHW_TEXT: SetAPen(w->RPort, amii_textAPen); SetBPen(w->RPort, amii_textBPen); break; case NHW_MAP: case NHW_BASE: case NHW_OVER: SetAPen(w->RPort, C_WHITE); SetBPen(w->RPort, C_BLACK); break; default: SetAPen(w->RPort, amii_otherAPen); SetBPen(w->RPort, amii_otherBPen); break; } } /* Clear the indicated window */ void amii_clear_nhwindow(win) register winid win; { register struct amii_WinDesc *cw; register struct Window *w; if (reclip == 2) return; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) panic(winpanicstr, win, "clear_nhwindow"); /* Clear the overview window too if it is displayed */ if (WINVERS_AMIV && (cw->type == WIN_MAP && WIN_OVER != WIN_ERR && reclip == 0)) { amii_clear_nhwindow(WIN_OVER); } if (w = cw->win) SetDrMd(w->RPort, JAM2); else return; if ((cw->wflags & FLMAP_CURSUP)) { if (cw->type != NHW_MAP) cursor_off(win); else cw->wflags &= ~FLMAP_CURSUP; } amii_setfillpens(w, cw->type); SetDrMd(w->RPort, JAM2); if (cw->type == NHW_MENU || cw->type == NHW_TEXT) { RectFill(w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); } else { if (cw->type == NHW_MESSAGE) { amii_curs(win, 1, 0); if (!scrollmsg) TextSpaces(w->RPort, cw->cols); } else { RectFill(w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); } } cw->cury = 0; cw->curx = 0; amii_curs(win, 1, 0); } /* Dismiss the window from the screen */ void dismiss_nhwindow(win) register winid win; { register struct Window *w; register struct amii_WinDesc *cw; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) { panic(winpanicstr, win, "dismiss_nhwindow"); } w = cw->win; if (w) { /* All windows have this stuff attached to them. */ if (cw->type == NHW_MAP || cw->type == NHW_OVER || cw->type == NHW_BASE || cw->type == NHW_MESSAGE || cw->type == NHW_STATUS) { ClearMenuStrip(w); } /* Save where user like inventory to appear */ if (win == WIN_INVEN) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } /* Close the window */ CloseShWindow(w); cw->win = NULL; /* Free copy of NewWindow structure for TEXT/MENU windows. */ if (cw->newwin) FreeNewWindow((void *) cw->newwin); cw->newwin = NULL; } } void amii_exit_nhwindows(str) const char *str; { /* Seems strange to have to do this... but we need the BASE window * left behind... */ kill_nhwindows(0); if (WINVERS_AMIV) FreeTileImageFiles(); if (str) { raw_print(""); /* be sure we're not under the top margin */ raw_print(str); } } void amii_display_nhwindow(win, blocking) winid win; boolean blocking; { menu_item *mip; int cnt; static int lastwin = -1; struct amii_WinDesc *cw; if (!Initialized) return; lastwin = win; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) panic(winpanicstr, win, "display_nhwindow"); if (cw->type == NHW_MESSAGE) cw->wflags &= ~FLMAP_SKIP; if (cw->type == NHW_MESSAGE || cw->type == NHW_STATUS) return; if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) { flush_glyph_buffer(amii_wins[WIN_MAP]->win); } if (cw->type == NHW_MENU || cw->type == NHW_TEXT) { cnt = DoMenuScroll(win, blocking, PICK_ONE, &mip); } else if (cw->type == NHW_MAP) { amii_end_glyphout(win); /* Do more if it is time... */ if (blocking == TRUE && amii_wins[WIN_MESSAGE]->curx) { outmore(amii_wins[WIN_MESSAGE]); } } } void amii_curs(window, x, y) winid window; register int x, y; /* not xchar: perhaps xchar is unsigned and curx-x would be unsigned as well */ { register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) panic(winpanicstr, window, "curs"); if ((w = cw->win) == NULL) { if (cw->type == NHW_MENU || cw->type == NHW_TEXT) return; else panic("No window open yet in curs() for winid %d\n", window); } amiIDisplay->lastwin = window; /* Make sure x is within bounds */ if (x > 0) --x; /* column 0 is never used */ else x = 0; cw->curx = x; cw->cury = y; #ifdef DEBUG if (x < 0 || y < 0 || y >= cw->rows || x >= cw->cols) { char *s = "[unknown type]"; switch (cw->type) { case NHW_MESSAGE: s = "[topl window]"; break; case NHW_STATUS: s = "[status window]"; break; case NHW_MAP: s = "[map window]"; break; case NHW_MENU: s = "[menu window]"; break; case NHW_TEXT: s = "[text window]"; break; case NHW_BASE: s = "[base window]"; break; case NHW_OVER: s = "[overview window]"; break; } impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y); return; } #endif #ifdef CLIPPING if (clipping && cw->type == NHW_MAP) { x -= clipx; y -= clipy; } #endif /* Output all saved output before doing cursor movements for MAP */ if (cw->type == NHW_MAP) { flush_glyph_buffer(w); } /* Actually do it */ rp = w->RPort; if (cw->type == NHW_MENU) { if (WINVERS_AMIV) { if (window == WIN_INVEN) { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1 + pictdata.xsize + 4, (y * max(rp->TxHeight, pictdata.ysize + 3)) + rp->TxBaseline + pictdata.ysize - rp->TxHeight + w->BorderTop + 4); } else { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1); } } else { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1); } } else if (cw->type == NHW_TEXT) { Move(rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1); } else if (cw->type == NHW_MAP || cw->type == NHW_BASE) { /* These coordinate calculations must be synced with those * in flush_glyph_buffer() in winchar.c. curs_on_u() will * use this code, all other drawing occurs through the glyph * code. In order for the cursor to appear on top of the hero, * the code must compute X,Y in the same manner relative to * the RastPort coordinates. * * y = w->BorderTop + (g_nodes[i].y-2) * rp->TxHeight + * rp->TxBaseline + 1; * x = g_nodes[i].x * rp->TxWidth + w->BorderLeft; */ if (WINVERS_AMIV) { if (cw->type == NHW_MAP) { if (Is_rogue_level(&u.uz)) { #if 0 int qqx= (x * w->RPort->TxWidth) + w->BorderLeft; int qqy= w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1; printf("pos: (%d,%d)->(%d,%d)\n",x,y,qqx,qqy); #endif SetAPen(w->RPort, C_WHITE); /* XXX should be elsewhere (was 4)*/ Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ((y + 1) * w->RPort->TxHeight) + 1); } else { Move(rp, (x * mxsize) + w->BorderLeft, w->BorderTop + ((y + 1) * mysize) + 1); } } else { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ((y + 1) * w->RPort->TxHeight) + w->RPort->TxBaseline + 1); } } else { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + (y * w->RPort->TxHeight) + w->RPort->TxBaseline + 1); } } else if (WINVERS_AMIV && cw->type == NHW_OVER) { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, w->BorderTop + w->RPort->TxBaseline + 3); } else if (cw->type == NHW_MESSAGE && !scrollmsg) { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, w->BorderTop + w->RPort->TxBaseline + 3); } else if (cw->type == NHW_STATUS) { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, (y * (w->RPort->TxHeight + 1)) + w->BorderTop + w->RPort->TxBaseline + 1); } else { Move(rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, (y * w->RPort->TxHeight) + w->BorderTop + w->RPort->TxBaseline + 1); } } void amii_set_text_font(name, size) char *name; int size; { register int i; register struct amii_WinDesc *cw; int osize = TextsFont13.ta_YSize; static char nname[100]; strncpy(nname, name, sizeof(nname) - 1); nname[sizeof(nname) - 1] = 0; TextsFont13.ta_Name = nname; TextsFont13.ta_YSize = size; /* No alternate text font allowed for 640x269 or smaller */ if (!HackScreen || !bigscreen) return; /* Look for windows to set, and change them */ if (DiskfontBase = OpenLibrary("diskfont.library", amii_libvers)) { TextsFont = OpenDiskFont(&TextsFont13); for (i = 0; TextsFont && i < MAXWIN; ++i) { if ((cw = amii_wins[i]) && cw->win != NULL) { switch (cw->type) { case NHW_STATUS: MoveWindow(cw->win, 0, -(size - osize) * 2); SizeWindow(cw->win, 0, (size - osize) * 2); SetFont(cw->win->RPort, TextsFont); break; case NHW_MESSAGE: case NHW_MAP: case NHW_BASE: case NHW_OVER: SetFont(cw->win->RPort, TextsFont); break; } } } } CloseLibrary(DiskfontBase); DiskfontBase = NULL; } void kill_nhwindows(all) register int all; { register int i; register struct amii_WinDesc *cw; /* Foreach open window in all of amii_wins[], CloseShWindow, free memory */ for (i = 0; i < MAXWIN; ++i) { if ((cw = amii_wins[i]) && (cw->type != NHW_BASE || all)) { amii_destroy_nhwindow(i); } } } void amii_cl_end(cw, curs_pos) register struct amii_WinDesc *cw; register int curs_pos; { register struct Window *w = cw->win; register int oy, ox; if (!w) panic("NULL window pointer in amii_cl_end()"); oy = w->RPort->cp_y; ox = w->RPort->cp_x; TextSpaces(w->RPort, cw->cols - curs_pos); Move(w->RPort, ox, oy); } void cursor_off(window) winid window; { register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; int curx, cury; int x, y; long dmode; short apen, bpen; unsigned char ch; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) { iflags.window_inited = 0; panic(winpanicstr, window, "cursor_off"); } if (!(cw->wflags & FLMAP_CURSUP)) return; w = cw->win; if (!w) return; cw->wflags &= ~FLMAP_CURSUP; rp = w->RPort; /* Save the current information */ curx = rp->cp_x; cury = rp->cp_y; x = cw->cursx; y = cw->cursy; dmode = rp->DrawMode; apen = rp->FgPen; bpen = rp->BgPen; SetAPen(rp, cw->curs_apen); SetBPen(rp, cw->curs_bpen); SetDrMd(rp, COMPLEMENT); /*printf("CURSOR OFF: %d %d\n",x,y);*/ if (WINVERS_AMIV && cw->type == NHW_MAP) { cursor_common(rp, x, y); if (Is_rogue_level(&u.uz)) Move(rp, curx, cury); } else { ch = CURSOR_CHAR; Move(rp, x, y); Text(rp, &ch, 1); /* Put back the other stuff */ Move(rp, curx, cury); } SetDrMd(rp, dmode); SetAPen(rp, apen); SetBPen(rp, bpen); } void cursor_on(window) winid window; { int x, y; register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; unsigned char ch; long dmode; short apen, bpen; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) { /* tty does this differently - is this OK? */ iflags.window_inited = 0; panic(winpanicstr, window, "cursor_on"); } /*printf("CURSOR ON: %d %d\n",cw->win->RPort->cp_x, * cw->win->RPort->cp_y);*/ if ((cw->wflags & FLMAP_CURSUP)) cursor_off(window); w = cw->win; if (!w) return; cw->wflags |= FLMAP_CURSUP; rp = w->RPort; /* Save the current information */ #ifdef DISPMAP if (WINVERS_AMIV && cw->type == NHW_MAP && !Is_rogue_level(&u.uz)) x = cw->cursx = (rp->cp_x & -8) + 8; else #endif x = cw->cursx = rp->cp_x; y = cw->cursy = rp->cp_y; apen = rp->FgPen; bpen = rp->BgPen; dmode = rp->DrawMode; /* Draw in complement mode. The cursor body will be C_WHITE */ cw->curs_apen = 0xff; /* Last color/all planes, regardless of depth */ cw->curs_bpen = 0xff; SetAPen(rp, cw->curs_apen); SetBPen(rp, cw->curs_bpen); SetDrMd(rp, COMPLEMENT); if (WINVERS_AMIV && cw->type == NHW_MAP) { cursor_common(rp, x, y); } else { Move(rp, x, y); ch = CURSOR_CHAR; Text(rp, &ch, 1); Move(rp, x, y); } SetDrMd(rp, dmode); SetAPen(rp, apen); SetBPen(rp, bpen); } static void cursor_common(rp, x, y) struct RastPort *rp; int x, y; { int x1, x2, y1, y2; if (Is_rogue_level(&u.uz)) { x1 = x - 2; y1 = y - rp->TxHeight; x2 = x + rp->TxWidth + 1; y2 = y + 3; /*printf("COMM: (%d %d) (%d %d) (%d %d) (%d * %d)\n",x1,y1,x2,y2,x1+2,y1+2,x2-2,y2-2);*/ } else { x1 = x; y1 = y - mysize - 1; x2 = x + mxsize - 1; y2 = y - 2; RectFill(rp, x1, y1, x2, y2); } RectFill(rp, x1 + 2, y1 + 2, x2 - 2, y2 - 2); } void amii_suspend_nhwindows(str) const char *str; { if (HackScreen) ScreenToBack(HackScreen); } void amii_resume_nhwindows() { if (HackScreen) ScreenToFront(HackScreen); } void amii_bell() { DisplayBeep(NULL); } void removetopl(cnt) int cnt; { struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE]; /* NB - this is sufficient for * yn_function, but that's it */ if (cw->curx < cnt) cw->curx = 0; else cw->curx -= cnt; amii_curs(WIN_MESSAGE, cw->curx + 1, cw->cury); amii_cl_end(cw, cw->curx); } /*#endif /* AMIGA_INTUITION */ #ifdef PORT_HELP void port_help() { display_file(PORT_HELP, 1); } #endif /* * print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void amii_print_glyph(win, x, y, glyph, bkglyph) winid win; xchar x, y; int glyph, bkglyph; { struct amii_WinDesc *cw; uchar ch; int color, och; extern const int zapcolors[]; unsigned special; /* In order for the overview window to work, we can not clip here */ if (!WINVERS_AMIV) { #ifdef CLIPPING /* If point not in visible part of window just skip it */ if (clipping) { if (x <= clipx || y < clipy || x >= clipxmax || y >= clipymax) return; } #endif } if (win == WIN_ERR || (cw = amii_wins[win]) == NULL || cw->type != NHW_MAP) { panic(winpanicstr, win, "amii_print_glyph"); } #if 0 { static int x=-1; if(u.uz.dlevel != x){ fprintf(stderr,"lvlchg: %d (%d)\n",u.uz.dlevel,Is_rogue_level(&u.uz)); x = u.uz.dlevel; } } #endif if (WINVERS_AMIV && !Is_rogue_level(&u.uz)) { amii_curs(win, x, y); amiga_print_glyph(win, 0, glyph); } else /* AMII, or Rogue level in either version */ { /* map glyph to character and color */ (void) mapglyph(glyph, &och, &color, &special, x, y); ch = (uchar) och; if (WINVERS_AMIV) { /* implies Rogue level here */ amii_curs(win, x, y); amiga_print_glyph(win, NO_COLOR, ch + 10000); } else { /* Move the cursor. */ amii_curs(win, x, y + 2); #ifdef TEXTCOLOR /* Turn off color if rogue level. */ if (Is_rogue_level(&u.uz)) color = NO_COLOR; amiga_print_glyph(win, color, ch); #else g_putch(ch); /* print the character */ #endif cw->curx++; /* one character over */ } } } /* Make sure the user sees a text string when no windowing is available */ void amii_raw_print(s) register const char *s; { int argc = 0; if (!s) return; if (amiIDisplay) amiIDisplay->rawprint++; if (!Initialized) { /* Not yet screen open ... */ puts(s); fflush(stdout); return; } if (Initialized == 0 && WIN_BASE == WIN_ERR) init_nhwindows(&argc, (char **) 0); if (amii_rawprwin != WIN_ERR) amii_putstr(amii_rawprwin, 0, s); else if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) amii_putstr(WIN_MAP, 0, s); else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) amii_putstr(WIN_BASE, 0, s); else { puts(s); fflush(stdout); } } /* Make sure the user sees a bold text string when no windowing * is available */ void amii_raw_print_bold(s) register const char *s; { int argc = 0; if (!s) return; if (amiIDisplay) amiIDisplay->rawprint++; if (!Initialized) { /* Not yet screen open ... */ puts(s); fflush(stdout); return; } if (Initialized == 0 && WIN_BASE == WIN_ERR) init_nhwindows(&argc, (char **) 0); if (amii_rawprwin != WIN_ERR) amii_putstr(amii_rawprwin, 1, s); else if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) amii_putstr(WIN_MAP, 1, s); else if (WIN_BASE != WIN_ERR && amii_wins[WIN_BASE]) amii_putstr(WIN_BASE, 1, s); else { printf("\33[1m%s\33[0m\n", s); fflush(stdout); } } /* Rebuild/update the inventory if the window is up. */ void amii_update_inventory() { register struct amii_WinDesc *cw; if (WIN_INVEN != WIN_ERR && (cw = amii_wins[WIN_INVEN]) && cw->type == NHW_MENU && cw->win) { display_inventory(NULL, FALSE); } } /* Humm, doesn't really do anything useful */ void amii_mark_synch() { if (!amiIDisplay) fflush(stderr); /* anything else? do we need this much? */ } /* Wait for everything to sync. Nothing is asynchronous, so we just * ask for a key to be pressed. */ void amii_wait_synch() { if (!amiIDisplay || amiIDisplay->rawprint) { if (amiIDisplay) amiIDisplay->rawprint = 0; } else { if (WIN_MAP != WIN_ERR) { display_nhwindow(WIN_MAP, TRUE); flush_glyph_buffer(amii_wins[WIN_MAP]->win); } } } void amii_setclipped() { #ifdef CLIPPING clipping = TRUE; clipx = clipy = 0; clipxmax = CO; clipymax = LI; /* some of this is now redundant with top of amii_cliparound XXX */ #endif } /* XXX still to do: suppress scrolling if we violate the boundary but the * edge of the map is already displayed */ void amii_cliparound(x, y) register int x, y; { extern boolean restoring; #ifdef CLIPPING int oldx = clipx, oldy = clipy; int oldxmax = clipxmax, oldymax = clipymax; int COx, LIx; #define SCROLLCNT 1 /* Get there in 3 moves... */ int scrollcnt = SCROLLCNT; /* ...or 1 if we changed level */ if (!clipping) /* And 1 in anycase, cleaner, simpler, quicker */ return; if (Is_rogue_level(&u.uz)) { struct Window *w = amii_wins[WIN_MAP]->win; struct RastPort *rp = w->RPort; COx = (w->Width - w->BorderLeft - w->BorderRight) / rp->TxWidth; LIx = (w->Height - w->BorderTop - w->BorderBottom) / rp->TxHeight; } else { COx = CO; LIx = LI; } /* * On a level change, move the clipping region so that for a * reasonablely large window extra motion is avoided; for * the rogue level hopefully this means no motion at all. */ { static d_level saved_level = { 127, 127 }; /* XXX */ if (!on_level(&u.uz, &saved_level)) { scrollcnt = 1; /* jump with blanking */ clipx = clipy = 0; clipxmax = COx; clipymax = LIx; saved_level = u.uz; /* save as new current level */ } } if (x <= clipx + xclipbord) { clipx = max(0, x - (clipxmax - clipx) / 2); clipxmax = clipx + COx; } else if (x > clipxmax - xclipbord) { clipxmax = min(COLNO, x + (clipxmax - clipx) / 2); clipx = clipxmax - COx; } if (y <= clipy + yclipbord) { clipy = max(0, y - (clipymax - clipy) / 2); clipymax = clipy + LIx; } else if (y > clipymax - yclipbord) { clipymax = min(ROWNO, y + (clipymax - clipy) / 2); clipy = clipymax - LIx; } reclip = 1; if (clipx != oldx || clipy != oldy || clipxmax != oldxmax || clipymax != oldymax) { #ifndef NOSCROLLRASTER struct Window *w = amii_wins[WIN_MAP]->win; struct RastPort *rp = w->RPort; int xdelta, ydelta, xmod, ymod, i; int incx, incy, mincx, mincy; int savex, savey, savexmax, saveymax; int scrx, scry; if (Is_rogue_level(&u.uz)) { scrx = rp->TxWidth; scry = rp->TxHeight; } else { scrx = mxsize; scry = mysize; } /* Ask that the glyph routines not draw the overview window */ reclip = 2; cursor_off(WIN_MAP); /* Compute how far we are moving in terms of tiles */ mincx = clipx - oldx; mincy = clipy - oldy; /* How many tiles to get there in SCROLLCNT moves */ incx = (clipx - oldx) / scrollcnt; incy = (clipy - oldy) / scrollcnt; /* If less than SCROLLCNT tiles, then move by 1 tile if moving at all */ if (incx == 0) incx = (mincx != 0); if (incy == 0) incy = (mincy != 0); /* Get count of pixels to move each iteration and final pixel count */ xdelta = ((clipx - oldx) * scrx) / scrollcnt; xmod = ((clipx - oldx) * scrx) % scrollcnt; ydelta = ((clipy - oldy) * scry) / scrollcnt; ymod = ((clipy - oldy) * scry) % scrollcnt; /* Preserve the final move location */ savex = clipx; savey = clipy; saveymax = clipymax; savexmax = clipxmax; /* * Set clipping rectangle to be just the region that will be exposed so * that drawing will be faster */ #if 0 /* Doesn't seem to work quite the way it should */ /* In some cases hero is 'centered' offscreen */ if( xdelta < 0 ) { clipx = oldx; clipxmax = clipx + incx; } else if( xdelta > 0 ) { clipxmax = oldxmax; clipx = clipxmax - incx; } else { clipx = oldx; clipxmax = oldxmax; } if( ydelta < 0 ) { clipy = oldy; clipymax = clipy + incy; } else if( ydelta > 0 ) { clipymax = oldymax; clipy = clipymax - incy; } else { clipy = oldy; clipymax = oldymax; } #endif /* Now, in scrollcnt moves, move the picture toward the final view */ for (i = 0; i < scrollcnt; ++i) { #ifdef DISPMAP if (i == scrollcnt - 1 && (xmod != 0 || ymod != 0) && (xdelta != 0 || ydelta != 0)) { incx += (clipx - oldx) % scrollcnt; incy += (clipy - oldy) % scrollcnt; xdelta += xmod; ydelta += ymod; } #endif /* Scroll the raster if we are scrolling */ if (xdelta != 0 || ydelta != 0) { ScrollRaster(rp, xdelta, ydelta, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); if (mincx == 0) incx = 0; else mincx -= incx; clipx += incx; clipxmax += incx; if (mincy == 0) incy = 0; else mincy -= incy; clipy += incy; clipymax += incy; /* Draw the exposed portion */ if (on_level(&u.uz0, &u.uz) && !restoring) (void) doredraw(); flush_glyph_buffer(amii_wins[WIN_MAP]->win); } } clipx = savex; clipy = savey; clipymax = saveymax; clipxmax = savexmax; #endif if (on_level(&u.uz0, &u.uz) && !restoring && moves > 1) (void) doredraw(); flush_glyph_buffer(amii_wins[WIN_MAP]->win); } reclip = 0; #endif } void flushIDCMP(port) struct MsgPort *port; { struct Message *msg; while (msg = GetMsg(port)) ReplyMsg(msg); } nethack-3.6.0/sys/amiga/winkey.c0000664000076400007660000000421012536476415015515 0ustar paxedpaxed/* NetHack 3.6 winkey.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" amii_nh_poskey(x, y, mod) int *x, *y, *mod; { struct amii_WinDesc *cw; WETYPE type; struct RastPort *rp; struct Window *w; if (cw = amii_wins[WIN_MESSAGE]) { cw->wflags &= ~FLMAP_SKIP; if (scrollmsg) cw->wflags |= FLMSG_FIRST; cw->disprows = 0; } if (WIN_MAP != WIN_ERR && (cw = amii_wins[WIN_MAP]) && (w = cw->win)) { cursor_on(WIN_MAP); } else panic("no MAP window opened for nh_poskey\n"); rp = w->RPort; while (1) { type = WindowGetevent(); if (type == WEMOUSE) { *mod = CLICK_1; if (lastevent.un.mouse.qual) *mod = 0; /* X coordinates are 1 based, Y are 1 based. */ *x = ((lastevent.un.mouse.x - w->BorderLeft) / mxsize) + 1; *y = ((lastevent.un.mouse.y - w->BorderTop - MAPFTBASELN) / mysize) + 1; #ifdef CLIPPING if (clipping) { *x += clipx; *y += clipy; } #endif return (0); } else if (type == WEKEY) { lastevent.type = WEUNK; return (lastevent.un.key); } } } int amii_nhgetch() { int ch; struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE]; if (WIN_MAP != WIN_ERR && amii_wins[WIN_MAP]) { cursor_on(WIN_MAP); } if (cw) cw->wflags &= ~FLMAP_SKIP; ch = WindowGetchar(); return (ch); } void amii_get_nh_event() { /* nothing now - later I have no idea. Is this just a Mac hook? */ } void amii_getret() { register int c; raw_print(""); raw_print("Press Return..."); c = 0; while (c != '\n' && c != '\r') { if (HackPort) c = WindowGetchar(); else c = getchar(); } return; } nethack-3.6.0/sys/amiga/winmenu.c0000664000076400007660000014253012536476415015701 0ustar paxedpaxed/* NetHack 3.6 winmenu.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" /* Start building the text for a menu */ void amii_start_menu(window) register winid window; { register int i; register struct amii_WinDesc *cw; register amii_menu_item *mip; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) panic(winpanicstr, window, "start_menu"); amii_clear_nhwindow(window); if (cw->data && (cw->type == NHW_MESSAGE || cw->type == NHW_MENU || cw->type == NHW_TEXT)) { for (i = 0; i < cw->maxrow; ++i) { if (cw->data[i]) free(cw->data[i]); } free(cw->data); cw->data = NULL; } for (mip = cw->menu.items, i = 0; (mip = cw->menu.items) && i < cw->menu.count; ++i) { cw->menu.items = mip->next; free(mip); } cw->menu.items = 0; cw->menu.count = 0; cw->menu.chr = 'a'; if (cw->morestr) free(cw->morestr); cw->morestr = NULL; if (window == WIN_INVEN && cw->win != NULL) { if (alwaysinvent) cw->wasup = 1; } cw->cury = cw->rows = cw->maxrow = cw->maxcol = 0; return; } /* Add a string to a menu */ void amii_add_menu(window, glyph, id, ch, gch, attr, str, preselected) register winid window; register int glyph; register const anything *id; register char ch; register char gch; register int attr; register const char *str; register BOOLEAN_P preselected; { register struct amii_WinDesc *cw; amii_menu_item *mip; char buf[4 + BUFSZ]; if (str == NULL) return; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) panic(winpanicstr, window, "add_menu"); mip = (amii_menu_item *) alloc(sizeof(*mip)); mip->identifier = *id; mip->selected = preselected; mip->attr = attr; mip->glyph = Is_rogue_level(&u.uz) ? NO_GLYPH : glyph; mip->selector = 0; mip->gselector = gch; mip->count = -1; if (id->a_void && !ch && cw->menu.chr != 0) { ch = cw->menu.chr++; if (ch == 'z') cw->menu.chr = 'A'; if (ch == 'Z') cw->menu.chr = 0; } mip->canselect = (id->a_void != 0); if (id->a_void && ch != '\0') { Sprintf(buf, "%c - %s", ch, str); str = buf; mip->canselect = 1; } mip->selector = ch; amii_putstr(window, attr, str); mip->str = cw->data[cw->cury - 1]; cw->menu.count++; mip->next = NULL; if (cw->menu.items == 0) cw->menu.last = cw->menu.items = mip; else { cw->menu.last->next = mip; cw->menu.last = mip; } } /* Done building a menu. */ void amii_end_menu(window, morestr) register winid window; register const char *morestr; { register struct amii_WinDesc *cw; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) panic(winpanicstr, window, "end_menu"); if (morestr && *morestr) { anything any; #define PROMPTFIRST /* Define this to have prompt first */ #ifdef PROMPTFIRST amii_menu_item *mip; int i; char *t; mip = cw->menu.last; #endif any.a_void = 0; amii_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, morestr, MENU_UNSELECTED); #ifdef PROMPTFIRST /* Do some shuffling. Last first, push others one forward \ */ mip->next = NULL; cw->menu.last->next = cw->menu.items; cw->menu.items = cw->menu.last; cw->menu.last = mip; t = cw->data[cw->cury - 1]; for (i = cw->cury - 1; i > 0; i--) { cw->data[i] = cw->data[i - 1]; } cw->data[0] = t; #endif } /* If prompt first, don't put same string in title where in most cases it's not entirely visible anyway */ #ifndef PROMPTFIRST if (morestr) cw->morestr = strdup(morestr); #endif } /* Select something from the menu. */ int amii_select_menu(window, how, mip) register winid window; register int how; register menu_item **mip; { int cnt; register struct amii_WinDesc *cw; if (window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) panic(winpanicstr, window, "select_menu"); cnt = DoMenuScroll(window, 1, how, mip); /* This would allow the inventory window to stay open. */ if (!alwaysinvent || window != WIN_INVEN) dismiss_nhwindow(window); /* Now tear it down */ return cnt; } amii_menu_item * find_menu_item(register struct amii_WinDesc *cw, int idx) { amii_menu_item *mip; for (mip = cw->menu.items; idx > 0 && mip; mip = mip->next) --idx; return (mip); } int make_menu_items(register struct amii_WinDesc *cw, register menu_item **rmip) { register int idx = 0; register amii_menu_item *mip; register menu_item *mmip; for (mip = cw->menu.items; mip; mip = mip->next) { if (mip->selected) ++idx; } if (idx) { mmip = *rmip = (menu_item *) alloc(idx * sizeof(*mip)); for (mip = cw->menu.items; mip; mip = mip->next) { if (mip->selected) { mmip->item = mip->identifier; mmip->count = mip->count; mmip++; } } cw->mi = *rmip; } return (idx); } int DoMenuScroll(win, blocking, how, retmip) int win, blocking, how; menu_item **retmip; { amii_menu_item *amip; register struct Window *w; register struct NewWindow *nw; struct PropInfo *pip; register struct amii_WinDesc *cw; struct IntuiMessage *imsg; struct Gadget *gd; register int wheight, xsize, ysize, aredone = 0; register int txwd, txh; long mics, secs, class, code; long oldmics = 0, oldsecs = 0; int aidx, oidx, topidx, hidden; int totalvis; SHORT mx, my; static char title[100]; int dosize = 1; struct Screen *scrn = HackScreen; int x1, x2, y1, y2; long counting = FALSE, count = 0, reset_counting = FALSE; char countString[32]; if (win == WIN_ERR || (cw = amii_wins[win]) == NULL) panic(winpanicstr, win, "DoMenuScroll"); /* Initial guess at window sizing values */ txwd = txwidth; if (WINVERS_AMIV) { if (win == WIN_INVEN) txh = max(txheight, pictdata.ysize + 3); /* interline space */ else txh = txheight; /* interline space */ } else txh = txheight; /* interline space */ /* Check to see if we should open the window, should need to for * TEXT and MENU but not MESSAGE. */ w = cw->win; topidx = 0; if (w == NULL) { #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { PropScroll.Flags |= PROPNEWLOOK; } #endif nw = (void *) DupNewWindow((void *) (&new_wins[cw->type].newwin)); if (!alwaysinvent || win != WIN_INVEN) { xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 + (txwd * cw->maxcol); if (WINVERS_AMIV) { if (win == WIN_INVEN) xsize += pictdata.xsize + 4; } if (xsize > amiIDisplay->xpix) xsize = amiIDisplay->xpix; /* If next row not off window, use it, else use the bottom */ ysize = (txh * cw->maxrow) + /* The text space */ HackScreen->WBorTop + txheight + 1 + /* Top border */ HackScreen->WBorBottom + 3; /* The bottom border */ if (ysize > amiIDisplay->ypix) ysize = amiIDisplay->ypix; /* Adjust the size of the menu scroll gadget */ nw->TopEdge = 0; if (cw->type == NHW_TEXT && ysize < amiIDisplay->ypix) nw->TopEdge += (amiIDisplay->ypix - ysize) / 2; nw->LeftEdge = amiIDisplay->xpix - xsize; if (cw->type == NHW_MENU) { if (nw->LeftEdge > 10) nw->LeftEdge -= 10; else nw->LeftEdge = 0; if (amiIDisplay->ypix - nw->Height > 10) nw->TopEdge += 10; else nw->TopEdge = amiIDisplay->ypix - nw->Height - 1; } if (cw->type == NHW_TEXT && xsize < amiIDisplay->xpix) nw->LeftEdge -= (amiIDisplay->xpix - xsize) / 2; } else if (win == WIN_INVEN) { struct Window *mw = amii_wins[WIN_MAP]->win; struct Window *sw = amii_wins[WIN_STATUS]->win; xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 + (txwd * cw->maxcol); /* Make space for the glyph to appear at the left of the * description */ if (WINVERS_AMIV) xsize += pictdata.xsize + 4; if (xsize > amiIDisplay->xpix) xsize = amiIDisplay->xpix; /* If next row not off window, use it, else use the bottom */ ysize = sw->TopEdge - (mw->TopEdge + mw->Height) - 1; if (ysize > amiIDisplay->ypix) ysize = amiIDisplay->ypix; /* Adjust the size of the menu scroll gadget */ nw->TopEdge = mw->TopEdge + mw->Height; nw->LeftEdge = 0; } cw->newwin = (void *) nw; if (nw == NULL) panic("No NewWindow Allocated"); nw->Screen = HackScreen; if (win == WIN_INVEN) { sprintf(title, "%s the %s's Inventory", plname, pl_character); nw->Title = title; if (lastinvent.MaxX != 0) { nw->LeftEdge = lastinvent.MinX; nw->TopEdge = lastinvent.MinY; nw->Width = lastinvent.MaxX; nw->Height = lastinvent.MaxY; } } else if (cw->morestr) nw->Title = cw->morestr; /* Adjust the window coordinates and size now that we know * how many items are to be displayed. */ if ((xsize > amiIDisplay->xpix - nw->LeftEdge) && (xsize < amiIDisplay->xpix)) { nw->LeftEdge = amiIDisplay->xpix - xsize; nw->Width = xsize; } else { nw->Width = min(xsize, amiIDisplay->xpix - nw->LeftEdge); } nw->Height = min(ysize, amiIDisplay->ypix - nw->TopEdge); if (WINVERS_AMIV || WINVERS_AMII) { /* Make sure we are using the correct hook structure */ nw->Extension = cw->wintags; } /* Now, open the window */ w = cw->win = OpenShWindow((void *) nw); if (w == NULL) { char buf[130]; sprintf(buf, "No Window Opened For Menu (%d,%d,%d-%d,%d-%d)", nw->LeftEdge, nw->TopEdge, nw->Width, amiIDisplay->xpix, nw->Height, amiIDisplay->ypix); panic(buf); } #ifdef HACKFONT if (TextsFont) SetFont(w->RPort, TextsFont); else if (HackFont) SetFont(w->RPort, HackFont); #endif txwd = w->RPort->TxWidth; if (WINVERS_AMIV) { if (win == WIN_INVEN) txh = max(w->RPort->TxHeight, pictdata.ysize + 3); /* interline space */ else txh = w->RPort->TxHeight; /* interline space */ } else txh = w->RPort->TxHeight; /* interline space */ /* subtract 2 to account for spacing away from border (1 on each side) */ wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / txh; if (WINVERS_AMIV) { if (win == WIN_INVEN) { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } totalvis = CountLines(win); } else { txwd = w->RPort->TxWidth; if (WINVERS_AMIV) { if (win == WIN_INVEN) txh = max(w->RPort->TxHeight, pictdata.ysize + 3); /* interline space */ else txh = w->RPort->TxHeight; /* interline space */ } else { txh = w->RPort->TxHeight; /* interline space */ } /* subtract 2 to account for spacing away from border (1 on each side) */ wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / txh; if (WINVERS_AMIV) { if (win == WIN_INVEN) { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } totalvis = CountLines(win); for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (gd) { pip = (struct PropInfo *) gd->SpecialInfo; hidden = max(totalvis - wheight, 0); topidx = (((ULONG) hidden * pip->VertPot) + (MAXPOT / 2)) >> 16; } } for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) panic("Can't find scroll gadget"); morc = 0; oidx = -1; #if 0 /* Make sure there are no selections left over from last time. */ /* XXX potential problem for preselection if this is really needed */ for( amip = cw->menu.items; amip; amip = amip->next ) amip->selected = 0; #endif DisplayData(win, topidx); /* Make the prop gadget the right size and place */ SetPropInfo(w, gd, wheight, totalvis, topidx); oldsecs = oldmics = 0; /* If window already up, don't stop to process events */ if (cw->wasup) { aredone = 1; cw->wasup = 0; } while (!aredone) { /* Process window messages */ WaitPort(w->UserPort); while (imsg = (struct IntuiMessage *) GetMsg(w->UserPort)) { class = imsg->Class; code = imsg->Code; mics = imsg->Micros; secs = imsg->Seconds; gd = (struct Gadget *) imsg->IAddress; mx = imsg->MouseX; my = imsg->MouseY; /* Only do our window or VANILLAKEY from other windows */ if (imsg->IDCMPWindow != w && class != VANILLAKEY && class != RAWKEY) { ReplyMsg((struct Message *) imsg); continue; } /* Do DeadKeyConvert() stuff if RAWKEY... */ if (class == RAWKEY) { class = VANILLAKEY; code = ConvertKey(imsg); } ReplyMsg((struct Message *) imsg); switch (class) { case NEWSIZE: /* * Ignore every other newsize, no action needed, * except RefreshWindowFrame() in case borders got overwritten * for some reason. It should not happen, but ... */ if (!dosize) { RefreshWindowFrame(w); dosize = 1; break; } if (win == WIN_INVEN) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } else if (win == WIN_MESSAGE) { lastmsg.MinX = w->LeftEdge; lastmsg.MinY = w->TopEdge; lastmsg.MaxX = w->Width; lastmsg.MaxY = w->Height; } /* Find the gadget */ for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) panic("Can't find scroll gadget"); totalvis = CountLines(win); wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / txh; if (WINVERS_AMIV) { if (win == WIN_INVEN) { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } if (wheight < 2) wheight = 2; /* * Clear the right side & bottom. Parts of letters are not * erased by * amii_cl_end if window shrinks and columns decrease. */ if (WINVERS_AMII || WINVERS_AMIV) { amii_setfillpens(w, cw->type); SetDrMd(w->RPort, JAM2); x2 = w->Width - w->BorderRight; y2 = w->Height - w->BorderBottom; x1 = x2 - w->IFont->tf_XSize - w->IFont->tf_XSize; y1 = w->BorderTop; if (x1 < w->BorderLeft) x1 = w->BorderLeft; RectFill(w->RPort, x1, y1, x2, y2); x1 = w->BorderLeft; y1 = y1 - w->IFont->tf_YSize; RectFill(w->RPort, x1, y1, x2, y2); RefreshWindowFrame(w); } /* Make the prop gadget the right size and place */ DisplayData(win, topidx); SetPropInfo(w, gd, wheight, totalvis, topidx); /* Force the window to a text line boundary <= to * what the user dragged it to. This eliminates * having to clean things up on the bottom edge. */ SizeWindow(w, 0, (wheight * txh) + w->BorderTop + w->BorderBottom + 2 - w->Height); /* Don't do next NEWSIZE, we caused it */ dosize = 0; oldsecs = oldmics = 0; break; case VANILLAKEY: #define CTRL(x) ((x) - '@') morc = code = map_menu_cmd(code); if (code == MENU_SELECT_ALL) { if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { if (amip->canselect && amip->selector) { /* * Select those yet unselected * and apply count if necessary */ if (!amip->selected) { amip->selected = TRUE; if (counting) { amip->count = count; reset_counting = TRUE; /* * This makes the assumption that * the string is in format "X - foo" * with additional selecting and * formatting * data in front (size SOFF) */ amip->str[SOFF + 2] = '#'; } else { amip->count = -1; amip->str[SOFF + 2] = '-'; } } } amip = amip->next; } DisplayData(win, topidx); } } else if (code == MENU_UNSELECT_ALL) { if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { if (amip->selected) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF + 2] = '-'; } amip = amip->next; } DisplayData(win, topidx); } } else if (code == MENU_INVERT_ALL) { if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { if (amip->canselect && amip->selector) { amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; amip->str[SOFF + 2] = '#'; reset_counting = TRUE; } else { amip->count = -1; amip->str[SOFF + 2] = '-'; } } amip = amip->next; } DisplayData(win, topidx); } } else if (code == MENU_SELECT_PAGE) { if (how == PICK_ANY) { int i = 0; amip = cw->menu.items; while (amip && i++ < topidx) amip = amip->next; for (i = 0; i < wheight && amip; i++, amip = amip->next) { if (amip->canselect && amip->selector) { if (!amip->selected) { if (counting) { amip->count = count; reset_counting = TRUE; amip->str[SOFF + 2] = '#'; } else { amip->count = -1; amip->str[SOFF + 2] = '-'; } } amip->selected = TRUE; } } DisplayData(win, topidx); } } else if (code == MENU_UNSELECT_PAGE) { if (how == PICK_ANY) { int i = 0; amip = cw->menu.items; while (amip && i++ < topidx) amip = amip->next; for (i = 0; i < wheight && amip; i++, amip = amip->next) { if (amip->selected) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF + 2] = '-'; } } DisplayData(win, topidx); } } else if (code == MENU_INVERT_PAGE) { if (how == PICK_ANY) { int i = 0; amip = cw->menu.items; while (amip && i++ < topidx) amip = amip->next; for (i = 0; i < wheight && amip; i++, amip = amip->next) { if (amip->canselect && amip->selector) { amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; amip->str[SOFF + 2] = '#'; reset_counting = TRUE; } else { amip->count = -1; amip->str[SOFF + 2] = '-'; } } } DisplayData(win, topidx); } } else if (code == MENU_SEARCH && cw->type == NHW_MENU) { if (how == PICK_ONE || how == PICK_ANY) { char buf[BUFSZ]; amip = cw->menu.items; amii_getlin("Search for:", buf); if (!*buf || *buf == '\033') break; while (amip) { if (amip->canselect && amip->selector && amip->str && strstri(&amip->str[SOFF], buf)) { if (how == PICK_ONE) { amip->selected = TRUE; aredone = 1; break; } amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; reset_counting = TRUE; amip->str[SOFF + 2] = '#'; } else { amip->count = -1; reset_counting = TRUE; amip->str[SOFF + 2] = '-'; } } amip = amip->next; } } DisplayData(win, topidx); } else if (how == PICK_ANY && isdigit(code) && (counting || (!counting && code != '0'))) { if (count < LARGEST_INT) { count = count * 10 + (long) (code - '0'); if (count > LARGEST_INT) count = LARGEST_INT; if (count > 0) { counting = TRUE; reset_counting = FALSE; } else { reset_counting = TRUE; } sprintf(countString, "Count: %d", count); pline(countString); } } else if (code == CTRL('D') || code == CTRL('U') || code == MENU_NEXT_PAGE || code == MENU_PREVIOUS_PAGE || code == MENU_FIRST_PAGE || code == MENU_LAST_PAGE) { int endcnt, i; for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) panic("Can't find scroll gadget"); endcnt = wheight; /* /2; */ if (endcnt == 0) endcnt = 1; if (code == MENU_FIRST_PAGE) { topidx = 0; } else if (code == MENU_LAST_PAGE) { topidx = cw->maxrow - wheight; } else for (i = 0; i < endcnt; ++i) { if (code == CTRL('D') || code == MENU_NEXT_PAGE) { if (topidx + wheight < cw->maxrow) ++topidx; else break; } else if (code = CTRL('U') || code == MENU_PREVIOUS_PAGE) { if (topidx > 0) --topidx; else break; } } /* Make prop gadget the right size and place */ DisplayData(win, topidx); SetPropInfo(w, gd, wheight, totalvis, topidx); oldsecs = oldmics = 0; } else if (code == '\b') { for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) panic("Can't find scroll gadget"); if (topidx - wheight - 2 < 0) { topidx = 0; } else { topidx -= wheight - 2; } DisplayData(win, topidx); SetPropInfo(w, gd, wheight, totalvis, topidx); oldsecs = oldmics = 0; } else if (code == ' ') { for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) panic("Can't find scroll gadget"); if (topidx + wheight >= cw->maxrow) { morc = 0; aredone = 1; } else { /* If there are still lines to be seen */ if (cw->maxrow > topidx + wheight) { if (wheight > 2) topidx += wheight - 2; else ++topidx; DisplayData(win, topidx); SetPropInfo(w, gd, wheight, totalvis, topidx); } oldsecs = oldmics = 0; } } else if (code == '\n' || code == '\r') { for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) panic("Can't find scroll gadget"); /* If all line displayed, we are done */ if (topidx + wheight >= cw->maxrow) { morc = 0; aredone = 1; } else { /* If there are still lines to be seen */ if (cw->maxrow > topidx + 1) { ++topidx; DisplayData(win, topidx); SetPropInfo(w, gd, wheight, totalvis, topidx); } oldsecs = oldmics = 0; } } else if (code == '\33') { if (counting) { reset_counting = TRUE; } else { aredone = 1; } } else { int selected = FALSE; for (amip = cw->menu.items; amip; amip = amip->next) { if (amip->selector == code) { if (how == PICK_ONE) aredone = 1; amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; reset_counting = TRUE; amip->str[SOFF + 2] = '#'; } else { amip->count = -1; reset_counting = TRUE; amip->str[SOFF + 2] = '-'; } selected = TRUE; } else if (amip->gselector == code) { amip->selected = !amip->selected; if (counting) { amip->count = count; reset_counting = TRUE; amip->str[SOFF + 2] = '#'; } else { amip->count = -1; reset_counting = TRUE; amip->str[SOFF + 2] = '-'; } selected = TRUE; } } if (selected) DisplayData(win, topidx); } break; case CLOSEWINDOW: if (win == WIN_INVEN) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } else if (win == WIN_MESSAGE) { lastmsg.MinX = w->LeftEdge; lastmsg.MinY = w->TopEdge; lastmsg.MaxX = w->Width; lastmsg.MaxY = w->Height; } aredone = 1; morc = '\33'; break; case GADGETUP: if (win == WIN_MESSAGE) aredone = 1; for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; pip = (struct PropInfo *) gd->SpecialInfo; totalvis = CountLines(win); hidden = max(totalvis - wheight, 0); aidx = (((ULONG) hidden * pip->VertPot) + (MAXPOT / 2)) >> 16; if (aidx != topidx) DisplayData(win, topidx = aidx); break; case MOUSEMOVE: for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; pip = (struct PropInfo *) gd->SpecialInfo; totalvis = CountLines(win); hidden = max(totalvis - wheight, 0); aidx = (((ULONG) hidden * pip->VertPot) + (MAXPOT / 2)) >> 16; if (aidx != topidx) DisplayData(win, topidx = aidx); break; case INACTIVEWINDOW: if (win == WIN_MESSAGE || (win == WIN_INVEN && alwaysinvent)) aredone = 1; break; case MOUSEBUTTONS: if ((code == SELECTUP || code == SELECTDOWN) && cw->type == NHW_MENU && how != PICK_NONE) { /* Which one is the mouse pointing at? */ aidx = ((my - w->BorderTop - 1) / txh) + topidx; /* If different lines, don't select double click */ if (aidx != oidx) { oldsecs = 0; oldmics = 0; } /* If releasing, check for double click */ if (code == SELECTUP) { amip = find_menu_item(cw, aidx); if (aidx == oidx) { if (DoubleClick(oldsecs, oldmics, secs, mics)) { aredone = 1; } oldsecs = secs; oldmics = mics; } else { amip = find_menu_item(cw, oidx); amip->selected = 0; amip->count = -1; reset_counting = TRUE; if (amip->canselect && amip->selector) amip->str[SOFF + 2] = '-'; } if (counting && amip->selected && amip->canselect && amip->selector) { amip->count = count; reset_counting = TRUE; amip->str[SOFF + 2] = '#'; } DisplayData(win, topidx); } else if (aidx - topidx < wheight && aidx < cw->maxrow && code == SELECTDOWN) { /* Remove old highlighting if visible */ amip = find_menu_item(cw, oidx); if (amip && oidx != aidx && (oidx > topidx && oidx - topidx < wheight)) { if (how != PICK_ANY) { amip->selected = 0; amip->count = -1; reset_counting = TRUE; if (amip->canselect && amip->selector) amip->str[SOFF + 2] = '-'; } oidx = -1; } amip = find_menu_item(cw, aidx); if (amip && amip->canselect && amip->selector && how != PICK_NONE) { oidx = aidx; if (!DoubleClick(oldsecs, oldmics, secs, mics)) { amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; reset_counting = TRUE; amip->str[SOFF + 2] = '#'; } else { amip->count = -1; reset_counting = TRUE; if (amip->canselect && amip->selector) amip->str[SOFF + 2] = '-'; } } } else { DisplayBeep(NULL); oldsecs = 0; oldmics = 0; } DisplayData(win, topidx); } } else { DisplayBeep(NULL); } break; } if (!counting && morc == '\33') { amip = cw->menu.items; while (amip) { if (amip->canselect && amip->selector) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF + 2] = '-'; } amip = amip->next; } } if (reset_counting) { count = 0; if (counting) pline("Count: 0"); counting = FALSE; } } } /* Force a cursor reposition before next message output */ if (win == WIN_MESSAGE) cw->curx = -1; return (make_menu_items(cw, retmip)); } void ReDisplayData(win) winid win; { int totalvis; register struct amii_WinDesc *cw; register struct Window *w; register struct Gadget *gd; unsigned long hidden, aidx, wheight; struct PropInfo *pip; if (win == WIN_ERR || !(cw = amii_wins[win]) || !(w = cw->win)) return; for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (!gd) return; wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / w->RPort->TxHeight; pip = (struct PropInfo *) gd->SpecialInfo; totalvis = CountLines(win); hidden = max(totalvis - wheight, 0); aidx = (((ULONG) hidden * pip->VertPot) + (MAXPOT / 2)) >> 16; clear_nhwindow(win); DisplayData(win, aidx); } long FindLine(win, line) winid win; int line; { int txwd; register char *t; register struct amii_WinDesc *cw; register struct Window *w; register int i, disprow, len; int col = -1; if (win == WIN_ERR || !(cw = amii_wins[win]) || !(w = cw->win)) { panic(winpanicstr, win, "No Window in FindLine"); } txwd = w->RPort->TxWidth; if (WINVERS_AMIV) { if (win == WIN_INVEN) { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } disprow = 0; for (col = i = 0; line > disprow && i < cw->maxrow; ++i) { t = cw->data[i] + SOFF; if (cw->data[i][1] >= 0) { ++disprow; col = 0; } while (*t) { len = strlen(t); if (col + len > cw->cols) len = cw->cols - col; while (len > 0) { if (!t[len] || t[len] == ' ') break; --len; } if (len == 0) { while (*t && *t != ' ') { t++; col++; } } else { t += len; col += len; } if (*t) { while (*t == ' ') ++t; col = 0; ++disprow; } } } return (i); } long CountLines(win) winid win; { int txwd; amii_menu_item *mip; register char *t; register struct amii_WinDesc *cw; register struct Window *w; register int i, disprow, len; int col = -1; if (win == WIN_ERR || !(cw = amii_wins[win]) || !(w = cw->win)) { panic(winpanicstr, win, "No Window in CountLines"); } txwd = w->RPort->TxWidth; if (WINVERS_AMIV) { if (win == WIN_INVEN) { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } disprow = cw->maxrow; mip = cw->menu.items; for (col = i = 0; i < cw->maxrow; ++i) { t = cw->data[i] + SOFF; if (cw->type == NHW_MESSAGE && cw->data[i][SEL_ITEM] < 0) --disprow; else col = 0; while (*t) { len = strlen(t); if (col + len > cw->cols) len = cw->cols - col; while (len > 0) { if (!t[len] || t[len] == ' ') break; --len; } if (len == 0) { while (*t && *t != ' ') { t++; col++; } } else { t += len; col += len; } if (*t) { while (*t == ' ') ++t; col = 0; ++disprow; } } } return (disprow); } void DisplayData(win, start) winid win; int start; { int txwd; amii_menu_item *mip; register char *t; register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; register int i, disprow, len, wheight; int whichcolor = -1; int col; if (win == WIN_ERR || !(cw = amii_wins[win]) || !(w = cw->win)) { panic(winpanicstr, win, "No Window in DisplayData"); } rp = w->RPort; SetDrMd(rp, JAM2); if (WINVERS_AMIV && win == WIN_INVEN) { wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / max(rp->TxHeight, pictdata.ysize + 3); } else { wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / rp->TxHeight; } cw->rows = wheight; txwd = rp->TxWidth; if (WINVERS_AMIV) { if (win == WIN_INVEN) { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } else { cw->cols = (w->Width - w->BorderLeft - w->BorderRight - 4) / txwd; } /* Get the real line to display at */ start = FindLine(win, start); mip = cw->menu.items; for (i = 0; mip && i < start; ++i) { mip = mip->next; } /* Skip any initial response to a previous line */ if (cw->type == NHW_MESSAGE && mip && mip->selected < 0) ++start; if (WINVERS_AMIV && cw->type == NHW_MESSAGE) SetAPen(rp, amii_msgAPen); for (disprow = i = start; disprow < wheight + start; i++) { /* Just erase unused lines in the window */ if (i >= cw->maxrow) { if (WINVERS_AMIV && win == WIN_INVEN) { amii_curs(win, 0, disprow - start); amiga_print_glyph(win, 0, NO_GLYPH); } amii_curs(win, 1, disprow - start); amii_cl_end(cw, 0); ++disprow; continue; } /* Any string with a highlighted attribute goes * onto the end of the current line in the message window. */ if (cw->type == NHW_MESSAGE) SetAPen(rp, cw->data[i][SEL_ITEM] < 0 ? C_RED : amii_msgAPen); /* Selected text in the message window goes onto the end of the * current line */ if (cw->type != NHW_MESSAGE || cw->data[i][SEL_ITEM] >= 0) { amii_curs(win, 1, disprow - start); if (WINVERS_AMIV && win == WIN_INVEN) { if (mip) amiga_print_glyph(win, 0, mip->glyph); amii_curs(win, 1, disprow - start); } col = 0; } /* If this entry is to be highlighted, do so */ if (mip && mip->selected != 0) { if (whichcolor != 1) { SetDrMd(rp, JAM2); if (WINVERS_AMIV) { SetAPen(rp, amii_menuBPen); SetBPen(rp, C_BLUE); } else { SetAPen(rp, C_BLUE); SetBPen(rp, amii_menuAPen); } whichcolor = 1; } } else if (whichcolor != 2) { SetDrMd(rp, JAM2); if (cw->type == NHW_MESSAGE) { SetAPen(rp, amii_msgAPen); SetBPen(rp, amii_msgBPen); } else if (cw->type == NHW_MENU) { SetAPen(rp, amii_menuAPen); SetBPen(rp, amii_menuBPen); } else if (cw->type == NHW_TEXT) { SetAPen(rp, amii_textAPen); SetBPen(rp, amii_textBPen); } whichcolor = 2; } /* Next line out, wrap if too long */ t = cw->data[i] + SOFF; ++disprow; col = 0; while (*t) { len = strlen(t); if (len > (cw->cols - col)) len = cw->cols - col; while (len > 0) { if (!t[len] || t[len] == ' ') break; --len; } if (len == 0) { Text(rp, t, cw->cols - col); while (*t && *t != ' ') { t++; col++; } } else { Text(rp, t, len); t += len; col += len; } amii_cl_end(cw, col); if (*t) { ++disprow; /* Stop at the bottom of the window */ if (disprow > wheight + start) break; while (*t == ' ') ++t; amii_curs(win, 1, disprow - start - 1); if (mip && win == WIN_INVEN && WINVERS_AMIV) { /* Erase any previous glyph drawn here. */ amiga_print_glyph(win, 0, NO_GLYPH); amii_curs(win, 1, disprow - start - 1); } Text(rp, "+", 1); col = 1; } } if (cw->type == NHW_MESSAGE) { SetAPen(rp, amii_msgBPen); SetBPen(rp, amii_msgBPen); } else if (cw->type == NHW_MENU) { SetAPen(rp, amii_menuBPen); SetBPen(rp, amii_menuBPen); } else if (cw->type == NHW_TEXT) { SetAPen(rp, amii_textBPen); SetBPen(rp, amii_textBPen); } amii_cl_end(cw, col); whichcolor = -1; if (mip) mip = mip->next; } RefreshWindowFrame(w); return; } void SetPropInfo(win, gad, vis, total, top) register struct Window *win; register struct Gadget *gad; register long vis, total, top; { long mflags; register long hidden; register int body, pot; hidden = max(total - vis, 0); /* Force the last section to be just to the bottom */ if (top > hidden) top = hidden; /* Scale the body position. */ /* 2 lines overlap */ if (hidden > 0 && total > 2) body = (ULONG)((vis - 2) * MAXBODY) / (total - 2); else body = MAXBODY; if (hidden > 0) pot = (ULONG)(top * MAXPOT) / hidden; else pot = 0; mflags = AUTOKNOB | FREEVERT; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { mflags |= PROPNEWLOOK; } #endif NewModifyProp(gad, win, NULL, mflags, 0, pot, MAXBODY, body, 1); } nethack-3.6.0/sys/amiga/winproto.h0000664000076400007660000001203612536476415016102 0ustar paxedpaxed/* NetHack 3.6 winproto.h $NHDT-Date: 1433806597 2015/06/08 23:36:37 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ /* winreq.c */ void EditColor(void); void EditClipping(void); void DrawCol(struct Window *w, int idx, UWORD *colors); void DispCol(struct Window *w, int idx, UWORD *colors); void amii_change_color(int, long, int); char *amii_get_color_string(); void amii_getlin(const char *prompt, char *bufp); void getlind(const char *prompt, char *bufp, const char *dflt); char *amii_get_color_string(void); int filecopy(char *from, char *to); char *basename(char *str); char *dirname(char *str); /* winstr.c */ void amii_putstr(winid window, int attr, const char *str); void outmore(struct amii_WinDesc *cw); void outsubstr(struct amii_WinDesc *cw, char *str, int len, int fudge); void amii_putsym(winid st, int i, int y, CHAR_P c); void amii_addtopl(const char *s); void TextSpaces(struct RastPort *rp, int nr); void amii_remember_topl(void); long CountLines(winid); long FindLine(winid, int); int amii_doprev_message(void); void flushIDCMP(struct MsgPort *); int amii_msgborder(struct Window *); void amii_scrollmsg(register struct Window *w, register struct amii_WinDesc *cw); /* winkey.c */ int amii_nh_poskey(int *x, int *y, int *mod); int amii_nhgetch(void); void amii_get_nh_event(void); void amii_getret(void); /* winmenu.c */ void amii_start_menu(winid window); void FDECL(amii_add_menu, (winid, int, const anything *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); void FDECL(amii_end_menu, (winid, const char *)); int FDECL(amii_select_menu, (winid, int, menu_item **)); int DoMenuScroll(int win, int blocking, int how, menu_item **); void ReDisplayData(winid win); void DisplayData(winid win, int start); void SetPropInfo(struct Window *win, struct Gadget *gad, long vis, long total, long top); /* amiwind.c */ struct Window *OpenShWindow(struct NewWindow *nw); void CloseShWindow(struct Window *win); int ConvertKey(struct IntuiMessage *message); int kbhit(void); int kbhit(void); int amikbhit(void); int WindowGetchar(void); WETYPE WindowGetevent(void); void amii_cleanup(void); #ifndef SHAREDLIB void Abort(long rc); #endif void CleanUp(void); void flush_glyph_buffer(struct Window *w); void amiga_print_glyph(winid window, int color_index, int glyph, int bkglyph); void start_glyphout(winid window); void amii_end_glyphout(winid window); struct NewWindow *DupNewWindow(struct NewWindow *win); void FreeNewWindow(struct NewWindow *win); void bell(void); void amii_delay_output(void); void amii_number_pad(int state); #ifndef SHAREDLIB void amiv_loadlib(void); void amii_loadlib(void); #endif void preserve_icon(void); void clear_icon(void); /* winfuncs.c */ void amii_destroy_nhwindow(winid win); int amii_create_nhwindow(int type); void amii_init_nhwindows(int *, char **); void amii_setdrawpens(struct Window *, int type); void amii_sethipens(struct Window *, int type, int attr); void amii_setfillpens(struct Window *, int type); void amii_clear_nhwindow(winid win); void dismiss_nhwindow(winid win); void amii_exit_nhwindows(const char *str); void amii_display_nhwindow(winid win, boolean blocking); void amii_curs(winid window, int x, int y); void kill_nhwindows(int all); void amii_cl_end(struct amii_WinDesc *cw, int i); void cursor_off(winid window); void cursor_on(winid window); void amii_suspend_nhwindows(const char *str); void amii_resume_nhwindows(void); void amii_bell(void); void removetopl(int cnt); void port_help(void); void amii_print_glyph(winid win, xchar x, xchar y, int glyph, int bkglyph); void amii_raw_print(const char *s); void amii_raw_print_bold(const char *s); void amii_update_inventory(void); void amii_mark_synch(void); void amii_wait_synch(void); void amii_setclipped(void); void amii_cliparound(int x, int y); void amii_set_text_font(char *font, int size); BitMapHeader ReadImageFiles(char **, struct BitMap **, char **); BitMapHeader ReadTileImageFiles(void); void FreeImageFiles(char **, struct BitMap **); void FreeTileImageFiles(); /* winami.c */ #ifdef SHAREDLIB int __UserLibInit(void); void __UserLibCleanup(void); #endif void amii_askname(void); void amii_player_selection(void); void RandomWindow(char *name); int amii_get_ext_cmd(void); char amii_yn_function(const char *prompt, const char *resp, char def); char amii_yn_function(const char *query, const char *resp, char def); void amii_display_file(const char *fn, boolean complain); void SetBorder(struct Gadget *gd); void *malloc(register unsigned size); void free(void *q); #ifdef SHAREDLIB /* amilib.c */ void amii_loadlib(void); void amiv_loadlib(void); void CleanUp(void); void setup_librefs(WinamiBASE *base); #else void Abort(long rc); #endif /* amirip.c */ void FDECL(amii_outrip, (winid tmpwin, int how, time_t when)); /* winchar.c */ void SetMazeType(MazeType); int GlyphToIcon(int glyph); #ifdef OPT_DISPMAP void dispmap_sanity(void); int dispmap_sanity1(int); #endif void FreeTileImageFiles(void); nethack-3.6.0/sys/amiga/winreq.c0000664000076400007660000007701012536476415015524 0ustar paxedpaxed/* NetHack 3.6 winreq.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #define GADBLUEPEN 2 #define GADREDPEN 3 #define GADGREENPEN 4 #define GADCOLOKAY 5 #define GADCOLCANCEL 6 #define GADCOLSAVE 7 UBYTE UNDOBUFFER[300]; SHORT BorderVectors1[] = { 0, 0, 57, 0, 57, 11, 0, 11, 0, 0 }; struct Border Border1 = { -1, -1, 3, 0, JAM1, 5, BorderVectors1, NULL }; struct IntuiText IText1 = { 3, 0, JAM1, 4, 1, NULL, (UBYTE *) "Cancel", NULL }; struct Gadget Gadget2 = { NULL, 9, 15, 56, 10, NULL, RELVERIFY, BOOLGADGET, (APTR) &Border1, NULL, &IText1, NULL, NULL, 1, NULL }; UBYTE StrStringSIBuff[300]; struct StringInfo StrStringSInfo = { StrStringSIBuff, UNDOBUFFER, 0, 300, 0, 0, 0, 0, 0, 0, 0, 0, NULL }; SHORT BorderVectors2[] = { 0, 0, 439, 0, 439, 11, 0, 11, 0, 0 }; struct Border Border2 = { -1, -1, 3, 0, JAM1, 5, BorderVectors2, NULL }; struct Gadget String = { &Gadget2, 77, 15, 438, 10, NULL, RELVERIFY + STRINGCENTER, STRGADGET, (APTR) &Border2, NULL, NULL, NULL, (APTR) &StrStringSInfo, 2, NULL }; #define StrString \ ((char *) (((struct StringInfo *) (String.SpecialInfo))->Buffer)) struct NewWindow StrWindow = { 57, 74, 526, 31, 0, 1, GADGETUP + CLOSEWINDOW + ACTIVEWINDOW + VANILLAKEY, WINDOWDRAG + WINDOWDEPTH + WINDOWCLOSE + ACTIVATE + NOCAREREFRESH, &String, NULL, NULL, NULL, NULL, 5, 5, 0xffff, 0xffff, CUSTOMSCREEN }; #include "NH:sys/amiga/colorwin.c" #define XSIZE 2 #define YSIZE 3 #define XCLIP 4 #define YCLIP 5 #define GADOKAY 6 #define GADCANCEL 7 #include "NH:sys/amiga/clipwin.c" void ClearCol(struct Window *w); void EditColor() { extern const char *configfile; int i, done = 0, okay = 0; long code, qual, class; register struct Gadget *gd, *dgad; register struct Window *nw; register struct IntuiMessage *imsg; register struct PropInfo *pip; register struct Screen *scrn; long aidx; int msx, msy; int curcol = 0, drag = 0; int bxorx, bxory, bxxlen, bxylen; static UWORD colors[AMII_MAXCOLORS]; static UWORD svcolors[AMII_MAXCOLORS]; static int once = 0; scrn = HackScreen; if (!once) { if (WINVERS_AMIV) { Col_NewWindowStructure1.Width += 300; Col_NewWindowStructure1.Height += 20; Col_NewWindowStructure1.LeftEdge -= 150; Col_BluePen.Width += 300; Col_RedPen.Width += 300; Col_GreenPen.Width += 300; Col_Cancel.LeftEdge += 300; Col_Okay.LeftEdge += 150; Col_Cancel.TopEdge += 20; Col_Save.TopEdge += 20; Col_Okay.TopEdge += 20; } SetBorder(&Col_Okay); SetBorder(&Col_Cancel); SetBorder(&Col_Save); once = 1; } bxylen = Col_NewWindowStructure1.Height - (Col_BluePen.TopEdge + Col_BluePen.Height + 6); bxxlen = Col_BluePen.Width; bxorx = Col_BluePen.LeftEdge; bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2; /* Save the current colors */ for (i = 0; i < amii_numcolors; ++i) svcolors[i] = colors[i] = GetRGB4(scrn->ViewPort.ColorMap, i); Col_NewWindowStructure1.Screen = scrn; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { ((struct PropInfo *) Col_BluePen.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *) Col_RedPen.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *) Col_GreenPen.SpecialInfo)->Flags |= PROPNEWLOOK; } #endif if (WINVERS_AMIV || WINVERS_AMII) { #ifdef INTUI_NEW_LOOK Col_NewWindowStructure1.Extension = wintags; Col_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED; #ifdef __GNUC__ fillhook.h_Entry = (void *) &LayerFillHook; #else fillhook.h_Entry = (ULONG (*) ()) LayerFillHook; #endif fillhook.h_Data = (void *) -2; fillhook.h_SubEntry = 0; #endif } nw = OpenWindow((void *) &Col_NewWindowStructure1); if (nw == NULL) { DisplayBeep(NULL); return; } PrintIText(nw->RPort, &Col_IntuiTextList1, 0, 0); ClearCol(nw); DrawCol(nw, curcol, colors); while (!done) { WaitPort(nw->UserPort); while (imsg = (struct IntuiMessage *) GetMsg(nw->UserPort)) { gd = (struct Gadget *) imsg->IAddress; code = imsg->Code; class = imsg->Class; qual = imsg->Qualifier; msx = imsg->MouseX; msy = imsg->MouseY; ReplyMsg((struct Message *) imsg); switch (class) { case VANILLAKEY: if (code == 'v' && qual == AMIGALEFT) okay = done = 1; else if (code == 'b' && qual == AMIGALEFT) okay = 0, done = 1; else if (code == 'o' || code == 'O') okay = done = 1; else if (code == 'c' || code == 'C') okay = 0, done = 1; break; case CLOSEWINDOW: done = 1; break; case GADGETUP: drag = 0; if (gd->GadgetID == GADREDPEN || gd->GadgetID == GADBLUEPEN || gd->GadgetID == GADGREENPEN) { pip = (struct PropInfo *) gd->SpecialInfo; aidx = pip->HorizPot / (MAXPOT / 15); if (gd->GadgetID == GADREDPEN) { colors[curcol] = (colors[curcol] & ~0xf00) | (aidx << 8); LoadRGB4(&scrn->ViewPort, colors, amii_numcolors); } else if (gd->GadgetID == GADBLUEPEN) { colors[curcol] = (colors[curcol] & ~0xf) | aidx; LoadRGB4(&scrn->ViewPort, colors, amii_numcolors); } else if (gd->GadgetID == GADGREENPEN) { colors[curcol] = (colors[curcol] & ~0x0f0) | (aidx << 4); LoadRGB4(&scrn->ViewPort, colors, amii_numcolors); } DispCol(nw, curcol, colors); } else if (gd->GadgetID == GADCOLOKAY) { done = 1; okay = 1; } else if (gd->GadgetID == GADCOLSAVE) { FILE *fp, *nfp; char buf[300], nname[300], oname[300]; int once = 0; fp = fopen(configfile, "r"); if (!fp) { pline("can't find NetHack.cnf"); break; } strcpy(oname, dirname((char *) configfile)); if (oname[strlen(oname) - 1] != ':') { sprintf(nname, "%s/New_NetHack.cnf", oname); strcat(oname, "/"); strcat(oname, "Old_NetHack.cnf"); } else { sprintf(nname, "%sNew_NetHack.cnf", oname); strcat(oname, "Old_NetHack.cnf"); } nfp = fopen(nname, "w"); if (!nfp) { pline("can't write to New_NetHack.cnf"); fclose(fp); break; } while (fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, "PENS=", 5) == 0) { once = 1; fputs("PENS=", nfp); for (i = 0; i < amii_numcolors; ++i) { fprintf(nfp, "%03x", colors[i]); if ((i + 1) < amii_numcolors) putc('/', nfp); } putc('\n', nfp); } else { fputs(buf, nfp); } } /* If none in the file yet, now write it */ if (!once) { fputs("PENS=", nfp); for (i = 0; i < amii_numcolors; ++i) { fprintf(nfp, "%03x", colors[i]); if ((i + 1) < amii_numcolors) putc(',', nfp); } putc('\n', nfp); } fclose(fp); fclose(nfp); unlink(oname); if (filecopy((char *) configfile, oname) == 0) if (filecopy(nname, (char *) configfile) == 0) unlink(nname); done = 1; okay = 1; } else if (gd->GadgetID == GADCOLCANCEL) { done = 1; okay = 0; } break; case GADGETDOWN: drag = 1; dgad = gd; break; case MOUSEMOVE: if (!drag) break; pip = (struct PropInfo *) dgad->SpecialInfo; aidx = pip->HorizPot / (MAXPOT / 15); if (dgad->GadgetID == GADREDPEN) { colors[curcol] = (colors[curcol] & ~0xf00) | (aidx << 8); LoadRGB4(&scrn->ViewPort, colors, amii_numcolors); } else if (dgad->GadgetID == GADBLUEPEN) { colors[curcol] = (colors[curcol] & ~0xf) | aidx; LoadRGB4(&scrn->ViewPort, colors, amii_numcolors); } else if (dgad->GadgetID == GADGREENPEN) { colors[curcol] = (colors[curcol] & ~0x0f0) | (aidx << 4); LoadRGB4(&scrn->ViewPort, colors, amii_numcolors); } DispCol(nw, curcol, colors); break; case MOUSEBUTTONS: if (code == SELECTDOWN) { if (msy > bxory && msy < bxory + bxylen - 1 && msx > bxorx && msx < bxorx + bxxlen - 1) { curcol = (msx - bxorx) / (bxxlen / amii_numcolors); if (curcol >= 0 && curcol < amii_numcolors) DrawCol(nw, curcol, colors); } } break; } } } if (okay) { for (i = 0; i < (amii_numcolors); ++i) sysflags.amii_curmap[i] = colors[i]; LoadRGB4(&scrn->ViewPort, sysflags.amii_curmap, amii_numcolors); } else LoadRGB4(&scrn->ViewPort, svcolors, amii_numcolors); CloseWindow(nw); } void ShowClipValues(struct Window *nw) { char buf[50]; struct Gadget *gd; SetAPen(nw->RPort, 5); SetBPen(nw->RPort, amii_otherBPen); SetDrMd(nw->RPort, JAM2); sprintf(buf, "%d ", mxsize); gd = &ClipXSIZE; Move(nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline); Text(nw->RPort, buf, strlen(buf)); sprintf(buf, "%d ", mysize); gd = &ClipYSIZE; Move(nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline); Text(nw->RPort, buf, strlen(buf)); sprintf(buf, "%d ", xclipbord); gd = &ClipXCLIP; Move(nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline); Text(nw->RPort, buf, strlen(buf)); sprintf(buf, "%d ", yclipbord); gd = &ClipYCLIP; Move(nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline); Text(nw->RPort, buf, strlen(buf)); } void EditClipping(void) { int i; long mflags; static int sizes[] = { 8, 16, 20, 24, 28, 32, 36 }; char buf[40]; int done = 0, okay = 0; long code, qual, class; register struct Gadget *gd, *dgad; register struct Window *nw; register struct IntuiMessage *imsg; register struct PropInfo *pip; register struct Screen *scrn; long aidx; int lmxsize = mxsize, lmysize = mysize; int lxclipbord = xclipbord, lyclipbord = yclipbord; int msx, msy; int drag = 0; static int once = 0; scrn = HackScreen; if (!once) { SetBorder(&ClipOkay); SetBorder(&ClipCancel); once = 1; } ClipNewWindowStructure1.Screen = scrn; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { ((struct PropInfo *) ClipXSIZE.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *) ClipYSIZE.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *) ClipXCLIP.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *) ClipYCLIP.SpecialInfo)->Flags |= PROPNEWLOOK; } #endif if (WINVERS_AMIV || WINVERS_AMII) { #ifdef INTUI_NEW_LOOK ClipNewWindowStructure1.Extension = wintags; ClipNewWindowStructure1.Flags |= WFLG_NW_EXTENDED; #ifdef __GNUC__ fillhook.h_Entry = (void *) &LayerFillHook; #else fillhook.h_Entry = (ULONG (*) ()) LayerFillHook; #endif fillhook.h_Data = (void *) -2; fillhook.h_SubEntry = 0; #endif } nw = OpenWindow((void *) &ClipNewWindowStructure1); if (nw == NULL) { DisplayBeep(NULL); return; } ShowClipValues(nw); mflags = AUTOKNOB | FREEHORIZ; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { mflags |= PROPNEWLOOK; } #endif for (i = 0; i < 7; ++i) { if (mxsize <= sizes[i]) break; } NewModifyProp(&ClipXSIZE, nw, NULL, mflags, (i * MAXPOT) / 6, 0, MAXPOT / 6, 0, 1); for (i = 0; i < 7; ++i) { if (mysize <= sizes[i]) break; } NewModifyProp(&ClipYSIZE, nw, NULL, mflags, (i * MAXPOT) / 6, 0, MAXPOT / 6, 0, 1); NewModifyProp(&ClipXCLIP, nw, NULL, mflags, ((xclipbord - 2) * MAXPOT) / 6, 0, MAXPOT / 6, 0, 1); NewModifyProp(&ClipYCLIP, nw, NULL, mflags, ((yclipbord - 2) * MAXPOT) / 6, 0, MAXPOT / 6, 0, 1); while (!done) { WaitPort(nw->UserPort); while (imsg = (struct IntuiMessage *) GetMsg(nw->UserPort)) { gd = (struct Gadget *) imsg->IAddress; code = imsg->Code; class = imsg->Class; qual = imsg->Qualifier; msx = imsg->MouseX; msy = imsg->MouseY; ReplyMsg((struct Message *) imsg); switch (class) { case VANILLAKEY: if (code == '\33') okay = 0, done = 1; else if (code == 'v' && qual == AMIGALEFT) okay = done = 1; else if (code == 'b' && qual == AMIGALEFT) okay = 0, done = 1; else if (code == 'o' || code == 'O') okay = done = 1; else if (code == 'c' || code == 'C') okay = 0, done = 1; break; case CLOSEWINDOW: done = 1; break; case GADGETUP: drag = 0; if (gd->GadgetID == XSIZE || gd->GadgetID == YSIZE || gd->GadgetID == XCLIP || gd->GadgetID == YCLIP) { pip = (struct PropInfo *) gd->SpecialInfo; aidx = pip->HorizPot / (MAXPOT / 6); if (gd->GadgetID == XSIZE) { mxsize = sizes[aidx]; } else if (gd->GadgetID == YSIZE) { mysize = sizes[aidx]; } else if (gd->GadgetID == XCLIP) { xclipbord = aidx + 2; } else if (gd->GadgetID == YCLIP) { yclipbord = aidx + 2; } ShowClipValues(nw); #ifdef OPT_DISPMAP dispmap_sanity(); #endif } else if (gd->GadgetID == GADOKAY) { done = 1; okay = 1; } else if (gd->GadgetID == GADCANCEL) { done = 1; okay = 0; } ReportMouse(0, nw); reclip = 2; doredraw(); flush_glyph_buffer(amii_wins[WIN_MAP]->win); reclip = 0; break; case GADGETDOWN: drag = 1; dgad = gd; ReportMouse(1, nw); break; case MOUSEMOVE: if (!drag) break; pip = (struct PropInfo *) dgad->SpecialInfo; aidx = pip->HorizPot / (MAXPOT / 6); Move(nw->RPort, dgad->LeftEdge + (nw->Width + dgad->Width) + 8, dgad->TopEdge + nw->RPort->TxBaseline); if (dgad->GadgetID == XSIZE) { mxsize = sizes[aidx]; sprintf(buf, "%d ", lmxsize); } else if (dgad->GadgetID == YSIZE) { mysize = sizes[aidx]; sprintf(buf, "%d ", mysize); } else if (dgad->GadgetID == XCLIP) { xclipbord = aidx + 2; sprintf(buf, "%d ", xclipbord); } else if (dgad->GadgetID == YCLIP) { yclipbord = aidx + 2; sprintf(buf, "%d ", yclipbord); } SetAPen(nw->RPort, 5); SetBPen(nw->RPort, amii_otherBPen); SetDrMd(nw->RPort, JAM2); Text(nw->RPort, buf, strlen(buf)); #ifdef OPT_DISPMAP dispmap_sanity(); #endif break; } } } CloseWindow(nw); /* Restore oldvalues if cancelled. */ if (!okay) { mxsize = lmxsize; mysize = lmysize; xclipbord = lxclipbord; yclipbord = lyclipbord; } } char * dirname(str) char *str; { char *t, c; static char dir[300]; t = strrchr(str, '/'); if (!t) t = strrchr(str, ':'); if (!t) t = str; else { c = *t; *t = 0; strcpy(dir, str); *t = c; } return (dir); } char * basename(str) char *str; { char *t; t = strrchr(str, '/'); if (!t) t = strrchr(str, ':'); if (!t) t = str; else ++t; return (t); } filecopy(from, to) char *from, *to; { char *buf; int i = 0; buf = (char *) alloc(strlen(to) + strlen(from) + 20); if (buf) { sprintf(buf, "c:copy \"%s\" \"%s\" clone", from, to); /* Check SysBase instead? Shouldn't matter */ #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) i = System(buf, NULL); else #endif Execute(buf, NULL, NULL); free(buf); } else { return (-1); } return (i); } /* The colornames, and the default values for the pens */ static struct COLDEF { char *name, *defval; }; struct COLDEF amii_colnames[AMII_MAXCOLORS] = { "Black", "(000)", "White", "(fff)", "Brown", "(830)", "Cyan", "(7ac)", "Green", "(181)", "Magenta", "(c06)", "Blue", "(23e)", "Red", "(c00)", }; struct COLDEF amiv_colnames[AMII_MAXCOLORS] = { "Black", "(000)", "White", "(fff)", "Cyan", "(0bf)", "Orange", "(f60)", "Blue", "(00f)", "Green", "(090)", "Grey", "(69b)", "Red", "(f00)", "Light Green", "(6f0)", "Yellow", "(ff0)", "Magenta", "(f0f)", "Brown", "(940)", "Grey Blue", "(466)", "Light Brown", "(c40)", "Light Grey", "(ddb)", "Peach", "(fb9)", "Col 16", "(222)", "Col 17", "(eee)", "Col 18", "(000)", "Col 19", "(ccc)", "Col 20", "(bbb)", "Col 21", "(aaa)", "Col 22", "(999)", "Col 23", "(888)", "Col 24", "(777)", "Col 25", "(666)", "Col 26", "(555)", "Col 27", "(444)", "Col 28", "(333)", "Col 29", "(18f)", "Col 30", "(f81)", "Col 31", "(fff)", }; void ClearCol(struct Window *w) { int bxorx, bxory, bxxlen, bxylen; int incx, incy; bxylen = Col_Okay.TopEdge - (Col_BluePen.TopEdge + Col_BluePen.Height) - 1 - txheight - 3; bxxlen = Col_BluePen.Width - 2; bxorx = Col_BluePen.LeftEdge + 1; bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2; incx = bxxlen / amii_numcolors; incy = bxylen - 2; bxxlen /= incx; bxxlen *= incx; bxxlen += 2; SetAPen(w->RPort, C_WHITE); SetDrMd(w->RPort, JAM1); RectFill(w->RPort, bxorx, bxory, bxorx + bxxlen + 1, bxory + bxylen); SetAPen(w->RPort, C_BLACK); RectFill(w->RPort, bxorx + 1, bxory + 1, bxorx + bxxlen, bxory + bxylen - 1); } void DrawCol(w, idx, colors) struct Window *w; int idx; UWORD *colors; { int bxorx, bxory, bxxlen, bxylen; int i, incx, incy, r, g, b; long mflags; bxylen = Col_Okay.TopEdge - (Col_BluePen.TopEdge + Col_BluePen.Height) - 1 - txheight - 3; bxxlen = Col_BluePen.Width - 2; bxorx = Col_BluePen.LeftEdge + 1; bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2; incx = bxxlen / amii_numcolors; incy = bxylen - 2; bxxlen /= incx; bxxlen *= incx; bxxlen += 2; for (i = 0; i < amii_numcolors; ++i) { int x, y; x = bxorx + 2 + (i * incx); y = bxory + 2; if (i == idx) { SetAPen(w->RPort, sysflags.amii_dripens[SHADOWPEN]); Move(w->RPort, x, y + bxylen - 4); Draw(w->RPort, x, y); Draw(w->RPort, x + incx - 1, y); Move(w->RPort, x + 1, y + bxylen - 5); Draw(w->RPort, x + 1, y + 1); Draw(w->RPort, x + incx - 2, y + 1); SetAPen(w->RPort, sysflags.amii_dripens[SHINEPEN]); Move(w->RPort, x + incx - 1, y + 1); Draw(w->RPort, x + incx - 1, y + bxylen - 4); Draw(w->RPort, x, y + bxylen - 4); Move(w->RPort, x + incx - 2, y + 2); Draw(w->RPort, x + incx - 2, y + bxylen - 5); Draw(w->RPort, x + 1, y + bxylen - 5); } else { SetAPen(w->RPort, C_BLACK); Move(w->RPort, x, y); Draw(w->RPort, x + incx - 1, y); Draw(w->RPort, x + incx - 1, y + bxylen - 4); Draw(w->RPort, x, y + bxylen - 4); Draw(w->RPort, x, y); SetAPen(w->RPort, C_BLACK); Move(w->RPort, x + 1, y + 1); Draw(w->RPort, x + incx - 2, y + 1); Draw(w->RPort, x + incx - 2, y + bxylen - 6); Draw(w->RPort, x + 1, y + bxylen - 6); Draw(w->RPort, x + 1, y + 1); } SetAPen(w->RPort, i); RectFill(w->RPort, x + 3, y + 3, x + incx - 4, y + bxylen - 6); } DispCol(w, idx, colors); r = (colors[idx] & 0xf00) >> 8; g = (colors[idx] & 0x0f0) >> 4; b = colors[idx] & 0x00f; mflags = AUTOKNOB | FREEHORIZ; #ifdef INTUI_NEW_LOOK if (IntuitionBase->LibNode.lib_Version >= 37) { mflags |= PROPNEWLOOK; } #endif NewModifyProp(&Col_RedPen, w, NULL, mflags, (r * MAXPOT) / 15, 0, MAXPOT / 15, 0, 1); NewModifyProp(&Col_GreenPen, w, NULL, mflags, (g * MAXPOT) / 15, 0, MAXPOT / 15, 0, 1); NewModifyProp(&Col_BluePen, w, NULL, mflags, (b * MAXPOT) / 15, 0, MAXPOT / 15, 0, 1); } void DispCol(w, idx, colors) struct Window *w; int idx; UWORD *colors; { char buf[50]; char *colname, *defval; if (WINVERS_AMIV) { colname = amiv_colnames[idx].name; defval = amiv_colnames[idx].defval; } else { colname = amii_colnames[idx].name; defval = amii_colnames[idx].defval; } if (colname == NULL) { colname = "unknown"; defval = "unknown"; } Move(w->RPort, Col_Save.LeftEdge, Col_Save.TopEdge - 7); sprintf(buf, "%s=%03x default=%s%s", colname, colors[idx], defval, " " + strlen(colname) + 1); SetAPen(w->RPort, C_RED); SetBPen(w->RPort, amii_otherBPen); SetDrMd(w->RPort, JAM2); Text(w->RPort, buf, strlen(buf)); } void amii_setpens(int count) { #ifdef INTUI_NEW_LOOK struct EasyStruct ea = { sizeof(struct EasyStruct), 0l, "NetHack Request", "Number of pens requested(%ld) not correct", "Use default pens|Use requested pens" }; struct EasyStruct ea2 = { sizeof(struct EasyStruct), 0l, "NetHack Request", "Number of pens requested(%ld) not\ncompatible " "with game configuration(%ld)", "Use default pens|Use requested pens" }; #endif /* If the pens in amii_curmap are * more pens than in amii_numcolors, then we choose to ignore * those pens. */ #ifdef INTUI_NEW_LOOK if (IntuitionBase && IntuitionBase->LibNode.lib_Version >= 39) { if (count != amii_numcolors) { long args[2]; args[0] = count; args[1] = amii_numcolors; if (EasyRequest(NULL, &ea2, NULL, args) == 1) { memcpy(sysflags.amii_curmap, amii_initmap, amii_numcolors * sizeof(amii_initmap[0])); } } } else if (IntuitionBase && IntuitionBase->LibNode.lib_Version >= 37) { if (count != amii_numcolors) { if (EasyRequest(NULL, &ea, NULL, NULL) == 1) { memcpy(sysflags.amii_curmap, amii_initmap, amii_numcolors * sizeof(amii_initmap[0])); } } } else #endif if (count != amii_numcolors) { memcpy(sysflags.amii_curmap, amii_initmap, amii_numcolors * sizeof(amii_initmap[0])); } /* If the pens are set in NetHack.cnf, we can get called before * HackScreen has been opened. */ if (HackScreen != NULL) { LoadRGB4(&HackScreen->ViewPort, sysflags.amii_curmap, amii_numcolors); } } /* Generate a requester for a string value. */ void amii_getlin(prompt, bufp) const char *prompt; char *bufp; { getlind(prompt, bufp, 0); } /* and with default */ void getlind(prompt, bufp, dflt) const char *prompt; char *bufp; const char *dflt; { #ifndef TOPL_GETLINE register struct Window *cwin; register struct IntuiMessage *imsg; register long class, code, qual; register int aredone = 0; register struct Gadget *gd; static int once; *StrString = 0; if (dflt) strcpy(StrString, dflt); StrWindow.Title = (UBYTE *) prompt; StrWindow.Screen = HackScreen; if (!once) { if (bigscreen) { StrWindow.LeftEdge = (HackScreen->Width / 2) - (StrWindow.Width / 2); if (amii_wins[WIN_MAP]) { StrWindow.TopEdge = amii_wins[WIN_MAP]->win->TopEdge; } else { StrWindow.TopEdge = (HackScreen->Height / 2) - (StrWindow.Height / 2); } } SetBorder(&String); SetBorder(&Gadget2); once = 1; } if (WINVERS_AMIV || WINVERS_AMII) { #ifdef INTUI_NEW_LOOK StrWindow.Extension = wintags; StrWindow.Flags |= WFLG_NW_EXTENDED; #ifdef __GNUC__ fillhook.h_Entry = (void *) &LayerFillHook; #else fillhook.h_Entry = (ULONG (*) ()) LayerFillHook; #endif fillhook.h_Data = (void *) -2; fillhook.h_SubEntry = 0; #endif } if ((cwin = OpenWindow((void *) &StrWindow)) == NULL) { return; } while (!aredone) { WaitPort(cwin->UserPort); while ((imsg = (void *) GetMsg(cwin->UserPort)) != NULL) { class = imsg->Class; code = imsg->Code; qual = imsg->Qualifier; gd = (struct Gadget *) imsg->IAddress; switch (class) { case VANILLAKEY: if (code == '\033' && (qual & (IEQUALIFIER_LALT | IEQUALIFIER_RALT | IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND)) == 0) { if (bufp) { bufp[0] = '\033'; bufp[1] = 0; } aredone = 1; } else { ActivateGadget(&String, cwin, NULL); } break; case ACTIVEWINDOW: ActivateGadget(&String, cwin, NULL); break; case GADGETUP: switch (gd->GadgetID) { case 2: aredone = 1; if (bufp) strcpy(bufp, StrString); break; case 1: if (bufp) { bufp[0] = '\033'; bufp[1] = 0; } aredone = 1; break; } break; case CLOSEWINDOW: if (bufp) { bufp[0] = '\033'; bufp[1] = 0; } aredone = 1; break; } ReplyMsg((struct Message *) imsg); } } CloseWindow(cwin); #else struct amii_WinDesc *cw; struct Window *w; int colx, ocolx, c; char *obufp; amii_clear_nhwindow(WIN_MESSAGE); amii_putstr(WIN_MESSAGE, 0, prompt); cw = amii_wins[WIN_MESSAGE]; w = cw->win; ocolx = colx = strlen(prompt) + 1; obufp = bufp; cursor_on(WIN_MESSAGE); while ((c = WindowGetchar()) != EOF) { cursor_off(WIN_MESSAGE); amii_curs(WIN_MESSAGE, colx, 0); if (c == '\033') { *obufp = c; obufp[1] = 0; return; } else if (c == '\b') { if (bufp != obufp) { bufp--; amii_curs(WIN_MESSAGE, --colx, 0); Text(w->RPort, "\177 ", 2); amii_curs(WIN_MESSAGE, colx, 0); } else DisplayBeep(NULL); } else if (c == '\n' || c == '\r') { *bufp = 0; amii_addtopl(obufp); return; } else if (' ' <= c && c < '\177') { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ *bufp = c; bufp[1] = 0; Text(w->RPort, bufp, 1); Text(w->RPort, "\177", 1); if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO) { colx++; bufp++; } } else if (c == ('X' - 64) || c == '\177') { amii_curs(WIN_MESSAGE, ocolx, 0); Text(w->RPort, " " " ", colx - ocolx); amii_curs(WIN_MESSAGE, colx = ocolx, 0); } else DisplayBeep(NULL); cursor_on(WIN_MESSAGE); } cursor_off(WIN_MESSAGE); *bufp = 0; #endif } void amii_change_color(pen, val, rev) int pen, rev; long val; { if (rev) sysflags.amii_curmap[pen] = ~val; else sysflags.amii_curmap[pen] = val; if (HackScreen) LoadRGB4(&HackScreen->ViewPort, sysflags.amii_curmap, amii_numcolors); } char * amii_get_color_string() { int i; char s[10]; static char buf[BUFSZ]; *buf = 0; for (i = 0; i < min(32, amii_numcolors); ++i) { sprintf(s, "%s%03lx", i ? "/" : "", (long) sysflags.amii_curmap[i]); strcat(buf, s); } return (buf); } nethack-3.6.0/sys/amiga/winstr.c0000664000076400007660000003266112536476415015550 0ustar paxedpaxed/* NetHack 3.6 winstr.c $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" /* Put a string into the indicated window using the indicated attribute */ void amii_putstr(window, attr, str) winid window; int attr; const char *str; { int fudge; int len; struct Window *w; register struct amii_WinDesc *cw; char *ob; int i, j, n0, bottom, totalvis, wheight; static int wrapping = 0; /* Always try to avoid a panic when there is no window */ if (window == WIN_ERR) { window = WIN_BASE; if (window == WIN_ERR) window = WIN_BASE = amii_create_nhwindow(NHW_BASE); } if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) { iflags.window_inited = 0; panic(winpanicstr, window, "putstr"); } w = cw->win; if (!str) return; amiIDisplay->lastwin = window; /* do we care??? */ /* NHW_MENU windows are not opened immediately, so check if we * have the window pointer yet */ if (w) { /* Set the drawing mode and pen colors */ SetDrMd(w->RPort, JAM2); amii_sethipens(w, cw->type, attr); } else if (cw->type != NHW_MENU && cw->type != NHW_TEXT) { panic("NULL window pointer in putstr 2: %d", window); } /* Okay now do the work for each type */ switch (cw->type) { case NHW_MESSAGE: if (WINVERS_AMIV) fudge = 2; else { /* 8 for --more--, 1 for preceeding sp, 1 for putstr pad */ fudge = 10; } /* There is a one pixel border at the borders, so subtract two */ bottom = amii_msgborder(w); wheight = (w->Height - w->BorderTop - w->BorderBottom - 3) / w->RPort->TxHeight; if (scrollmsg || wheight > 1) fudge = 0; amii_scrollmsg(w, cw); while (isspace(*str)) str++; strncpy(toplines, str, TBUFSZ); toplines[TBUFSZ - 1] = 0; /* For initial message to be visible, we need to explicitly position * the * cursor. This flag, cw->curx == -1 is set elsewhere to force the * cursor to be repositioned to the "bottom". */ if (cw->curx == -1) { amii_curs(WIN_MESSAGE, 1, bottom); cw->curx = 0; } /* If used all of history lines, move them down */ if (cw->maxrow >= iflags.msg_history) { if (cw->data[0]) free(cw->data[0]); memcpy(cw->data, &cw->data[1], (iflags.msg_history - 1) * sizeof(char *)); cw->data[iflags.msg_history - 1] = (char *) alloc(strlen(toplines) + 5); strcpy(cw->data[i = iflags.msg_history - 1] + SOFF + (scrollmsg != 0), toplines); } else { /* Otherwise, allocate a new one and copy the line in */ cw->data[cw->maxrow] = (char *) alloc(strlen(toplines) + 5); strcpy(cw->data[i = cw->maxrow++] + SOFF + (scrollmsg != 0), toplines); } cw->data[i][SEL_ITEM] = 1; cw->data[i][VATTR] = attr + 1; if (scrollmsg) { cw->curx = 0; cw->data[i][2] = (cw->wflags & FLMSG_FIRST) ? '>' : ' '; } str = cw->data[i] + SOFF; if (cw->curx + strlen(str) >= (cw->cols - fudge)) { int i; char *ostr = (char *) str; char *p; while (cw->curx + strlen(str) >= (cw->cols - fudge)) { for (p = ((char *) &str[cw->cols - 1 - cw->curx]) - fudge; !isspace(*p) && p > str;) --p; if (p < str) p = (char *) str; if (p == str) { /* p = (char *)&str[ cw->cols ]; */ outmore(cw); continue; } i = (long) p - (long) str; outsubstr(cw, (char *) str, i, fudge); cw->curx += i; while (isspace(*p)) p++; str = p; #if 0 if( str != ostr ) { outsubstr( cw, "+", 1, fudge ); cw->curx+=2; } #endif if (*str) amii_scrollmsg(w, cw); amii_cl_end(cw, cw->curx); } if (*str) { if (str != ostr) { outsubstr(cw, "+", 1, fudge); cw->curx += 2; } while (isspace(*str)) ++str; outsubstr(cw, (char *) str, i = strlen((char *) str), fudge); cw->curx += i; amii_cl_end(cw, cw->curx); } } else { outsubstr(cw, (char *) str, i = strlen((char *) str), fudge); cw->curx += i; amii_cl_end(cw, cw->curx); } cw->wflags &= ~FLMSG_FIRST; len = 0; if (scrollmsg) { totalvis = CountLines(window); SetPropInfo(w, &MsgScroll, (w->Height - w->BorderTop - w->BorderBottom) / w->RPort->TxHeight, totalvis, totalvis); } i = strlen(toplines + SOFF); cw->maxcol = max(cw->maxcol, i); cw->vwy = cw->maxrow; break; case NHW_STATUS: if (cw->data[cw->cury] == NULL) panic("NULL pointer for status window"); ob = &cw->data[cw->cury][j = cw->curx]; if (flags.botlx) *ob = 0; /* Display when beam at top to avoid flicker... */ WaitTOF(); Text(w->RPort, (char *) str, strlen((char *) str)); if (cw->cols > strlen(str)) TextSpaces(w->RPort, cw->cols - strlen(str)); (void) strncpy(cw->data[cw->cury], str, cw->cols); cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ cw->cury = (cw->cury + 1) % 2; cw->curx = 0; break; case NHW_MAP: case NHW_BASE: if (cw->type == NHW_BASE && wrapping) { amii_curs(window, cw->curx + 1, cw->cury); TextSpaces(w->RPort, cw->cols); if (cw->cury < cw->rows) { amii_curs(window, cw->curx + 1, cw->cury + 1); TextSpaces(w->RPort, cw->cols); cw->cury--; } } amii_curs(window, cw->curx + 1, cw->cury); Text(w->RPort, (char *) str, strlen((char *) str)); cw->curx = 0; /* CR-LF is automatic in these windows */ cw->cury++; if (cw->type == NHW_BASE && cw->cury >= cw->rows) { cw->cury = 0; wrapping = 1; } break; case NHW_MENU: case NHW_TEXT: /* always grows one at a time, but alloc 12 at a time */ if (cw->cury >= cw->rows || !cw->data) { char **tmp; /* Allocate 12 more rows */ cw->rows += 12; tmp = (char **) alloc(sizeof(char *) * cw->rows); /* Copy the old lines */ for (i = 0; i < cw->cury; i++) tmp[i] = cw->data[i]; if (cw->data) { free(cw->data); cw->data = NULL; } cw->data = tmp; /* Null out the unused entries. */ for (i = cw->cury; i < cw->rows; i++) cw->data[i] = 0; } if (!cw->data) panic("no data storage"); /* Shouldn't need to do this, but... */ if (cw->data && cw->data[cw->cury]) { free(cw->data[cw->cury]); cw->data[cw->cury] = NULL; } n0 = strlen(str) + 1; cw->data[cw->cury] = (char *) alloc(n0 + SOFF); /* avoid nuls, for convenience */ cw->data[cw->cury][VATTR] = attr + 1; cw->data[cw->cury][SEL_ITEM] = 0; Strcpy(cw->data[cw->cury] + SOFF, str); if (n0 > cw->maxcol) cw->maxcol = n0; if (++cw->cury > cw->maxrow) cw->maxrow = cw->cury; break; default: panic("Invalid or unset window type in putstr()"); } } void amii_scrollmsg(w, cw) register struct Window *w; register struct amii_WinDesc *cw; { int bottom, wheight; bottom = amii_msgborder(w); wheight = (w->Height - w->BorderTop - w->BorderBottom - 3) / w->RPort->TxHeight; if (scrollmsg) { if (++cw->disprows > wheight) { outmore(cw); cw->disprows = 1; /* count this line... */ } else { ScrollRaster(w->RPort, 0, w->RPort->TxHeight, w->BorderLeft, w->BorderTop + 1, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); } amii_curs(WIN_MESSAGE, 1, bottom); } } int amii_msgborder(w) struct Window *w; { register int bottom; /* There is a one pixel border at the borders, so subtract two */ bottom = w->Height - w->BorderTop - w->BorderBottom - 2; bottom /= w->RPort->TxHeight; if (bottom > 0) --bottom; return (bottom); } void outmore(cw) register struct amii_WinDesc *cw; { struct Window *w = cw->win; if ((cw->wflags & FLMAP_SKIP) == 0) { if (scrollmsg) { int bottom; bottom = amii_msgborder(w); ScrollRaster(w->RPort, 0, w->RPort->TxHeight, w->BorderLeft, w->BorderTop + 1, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1); amii_curs(WIN_MESSAGE, 1, bottom); /* -1 for inner border */ Text(w->RPort, "--more--", 8); } else Text(w->RPort, " --more--", 9); /* Make sure there are no events in the queue */ flushIDCMP(HackPort); /* Allow mouse clicks to clear --more-- */ WindowGetchar(); if (lastevent.type == WEKEY && lastevent.un.key == '\33') cw->wflags |= FLMAP_SKIP; } if (!scrollmsg) { amii_curs(WIN_MESSAGE, 1, 0); amii_cl_end(cw, cw->curx); } } void outsubstr(cw, str, len, fudge) register struct amii_WinDesc *cw; char *str; int len; int fudge; { struct Window *w = cw->win; if (cw->curx) { /* Check if this string and --more-- fit, if not, * then put out --more-- and wait for a key. */ if ((len + fudge) + cw->curx >= cw->cols) { if (!scrollmsg) outmore(cw); } else { /* Otherwise, move and put out a blank separator */ Text(w->RPort, spaces, 1); cw->curx += 1; } } Text(w->RPort, str, len); } /* Put a graphics character onto the screen */ void amii_putsym(st, i, y, c) winid st; int i, y; CHAR_P c; { amii_curs(st, i, y); Text(amii_wins[st]->win->RPort, &c, 1); } /* Add to the last line in the message window */ void amii_addtopl(s) const char *s; { register struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE]; while (*s) { if (cw->curx == cw->cols - 1) amii_putstr(WIN_MESSAGE, 0, ""); amii_putsym(WIN_MESSAGE, cw->curx + 1, amii_msgborder(cw->win), *s++); cw->curx++; } } void TextSpaces(rp, nr) struct RastPort *rp; int nr; { if (nr < 1) return; while (nr > sizeof(spaces) - 1) { Text(rp, spaces, (long) sizeof(spaces) - 1); nr -= sizeof(spaces) - 1; } if (nr > 0) Text(rp, spaces, (long) nr); } void amii_remember_topl() { /* ignore for now. I think this will be done automatically by * the code writing to the message window, but I could be wrong. */ } int amii_doprev_message() { struct amii_WinDesc *cw; struct Window *w; char *str; if (WIN_MESSAGE == WIN_ERR || (cw = amii_wins[WIN_MESSAGE]) == NULL || (w = cw->win) == NULL) { panic(winpanicstr, WIN_MESSAGE, "doprev_message"); } /* When an interlaced/tall screen is in use, the scroll bar will be there */ /* Or in some other cases as well */ if (scrollmsg) { struct Gadget *gd; struct PropInfo *pip; int hidden, topidx, i, total, wheight; for (gd = w->FirstGadget; gd && gd->GadgetID != 1;) gd = gd->NextGadget; if (gd) { pip = (struct PropInfo *) gd->SpecialInfo; wheight = (w->Height - w->BorderTop - w->BorderBottom - 2) / w->RPort->TxHeight; hidden = max(cw->maxrow - wheight, 0); topidx = (((ULONG) hidden * pip->VertPot) + (MAXPOT / 2)) >> 16; for (total = i = 0; i < cw->maxrow; ++i) { if (cw->data[i][1] != 0) ++total; } i = 0; topidx -= wheight / 4 + 1; if (topidx < 0) topidx = 0; SetPropInfo(w, &MsgScroll, wheight, total, topidx); DisplayData(WIN_MESSAGE, topidx); } return (0); } if (--cw->vwy < 0) { cw->maxcol = 0; DisplayBeep(NULL); str = "\0\0No more history saved..."; } else str = cw->data[cw->vwy]; amii_cl_end(cw, 0); amii_curs(WIN_MESSAGE, 1, 0); amii_setdrawpens(amii_wins[WIN_MESSAGE]->win, NHW_MESSAGE); Text(w->RPort, str + SOFF, strlen(str + SOFF)); cw->curx = cw->cols + 1; return (0); } nethack-3.6.0/sys/amiga/xpm2iff.c0000664000076400007660000002243312536476415015571 0ustar paxedpaxed/* NetHack 3.6 xpm2iff.c $NHDT-Date: 1432512795 2015/05/25 00:13:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) 1995 by Gregg Wonderly, Naperville, Illinois */ /* NetHack may be freely redistributed. See license for details. */ #include #include "config.h" #include "tile.h" #include #include #include #include #include #include #include #include #ifndef _DCC #include #include #include #endif struct xpmscreen { int Width; int Height; int Colors; int ColorResolution; int Background; int AspectRatio; int Interlace; int BytesPerRow; } XpmScreen; /* translation table from xpm characters to RGB and colormap slots */ struct Ttable { char flag; char r, g, b; int slot; /* output colortable index */ } ttable[256]; pixval ColorMap[3][MAXCOLORMAPSIZE]; int colorsinmap; /* * We are using a hybrid form of our own design which we call a BMAP (for * bitmap) form. It is an ILBM with the bitmaps already deinterleaved, * completely uncompressed. * This speeds the loading of the images from the games point of view because * it * does not have to deinterleave and uncompress them. */ #define ID_BMAP MAKE_ID('B', 'M', 'A', 'P') /* instead of ILBM */ #define ID_BMHD MAKE_ID('B', 'M', 'H', 'D') /* Same as ILBM */ #define ID_CAMG MAKE_ID('C', 'A', 'M', 'G') /* Same as ILBM */ #define ID_CMAP MAKE_ID('C', 'M', 'A', 'P') /* Same as ILBM */ #define ID_PDAT \ MAKE_ID('P', 'D', 'A', 'T') /* Extra data describing plane \ * size due to graphics.library \ * rounding requirements. \ */ #define ID_PLNE MAKE_ID('P', 'L', 'N', 'E') /* The planes of the image */ int nplanes; /* BMHD from IFF documentation */ typedef struct { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE reserved1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; } BitMapHeader; typedef struct { UBYTE r, g, b; } AmiColorMap; pixel pixels[TILE_Y][TILE_X]; AmiColorMap *cmap; void error(char *str) { fprintf(stderr, "ERROR: %s\n", str); } char **planes; main(int argc, char **argv) { int colors; struct { long nplanes; long pbytes; long across; long down; long npics; long xsize; long ysize; } pdat; long pbytes; /* Bytes of data in a plane */ int i, cnt; BitMapHeader bmhd; struct IFFHandle *iff; long camg = HIRES | LACE; int tiles = 0; int index; #if defined(_DCC) || defined(__GNUC__) IFFParseBase = OpenLibrary("iffparse.library", 0); if (!IFFParseBase) { error("unable to open iffparse.library"); exit(1); } #endif if (fopen_xpm_file(argv[1], "r") != TRUE) { perror(argv[1]); return (1); } nplanes = 0; i = XpmScreen.Colors - 1; while (i != 0) { nplanes++; i >>= 1; } planes = malloc(nplanes * sizeof(char *)); if (planes == 0) { error("can not allocate planes pointer"); exit(1); } XpmScreen.BytesPerRow = ((XpmScreen.Width + 15) / 16) * 2; pbytes = XpmScreen.BytesPerRow * XpmScreen.Height; for (i = 0; i < nplanes; ++i) { planes[i] = malloc(pbytes); if (planes[i] == 0) { error("can not allocate planes pointer"); exit(1); } memset(planes[i], 0, pbytes); } iff = AllocIFF(); if (!iff) { error("Can not allocate IFFHandle"); return (1); } iff->iff_Stream = Open(argv[2], MODE_NEWFILE); if (!iff->iff_Stream) { error("Can not open output file"); return (1); } InitIFFasDOS(iff); OpenIFF(iff, IFFF_WRITE); PushChunk(iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN); bmhd.w = XpmScreen.Width; bmhd.h = XpmScreen.Height; bmhd.x = 0; bmhd.y = 0; bmhd.nPlanes = nplanes; bmhd.masking = 0; bmhd.compression = 0; bmhd.reserved1 = 0; bmhd.transparentColor = 0; bmhd.xAspect = 100; bmhd.yAspect = 100; bmhd.pageWidth = 0; /* not needed for this program */ bmhd.pageHeight = 0; /* not needed for this program */ PushChunk(iff, ID_BMAP, ID_BMHD, sizeof(bmhd)); WriteChunkBytes(iff, &bmhd, sizeof(bmhd)); PopChunk(iff); PushChunk(iff, ID_BMAP, ID_CAMG, sizeof(camg)); WriteChunkBytes(iff, &camg, sizeof(camg)); PopChunk(iff); #define SCALE(x) (x) cmap = malloc((colors = (1L << nplanes)) * sizeof(AmiColorMap)); if (cmap == 0) { error("Can't allocate color map"); exit(1); } for (index = 0; index < 256; index++) { if (ttable[index].flag) { cmap[ttable[index].slot].r = SCALE(ttable[index].r); cmap[ttable[index].slot].g = SCALE(ttable[index].g); cmap[ttable[index].slot].b = SCALE(ttable[index].b); } } #undef SCALE PushChunk(iff, ID_BMAP, ID_CMAP, IFFSIZE_UNKNOWN); WriteChunkBytes(iff, cmap, colors * sizeof(*cmap)); PopChunk(iff); conv_image(); pdat.nplanes = nplanes; pdat.pbytes = pbytes; pdat.xsize = XpmScreen.Width; pdat.ysize = XpmScreen.Height; pdat.across = 0; pdat.down = 0; pdat.npics = 1; PushChunk(iff, ID_BMAP, ID_PDAT, IFFSIZE_UNKNOWN); WriteChunkBytes(iff, &pdat, sizeof(pdat)); PopChunk(iff); PushChunk(iff, ID_BMAP, ID_PLNE, IFFSIZE_UNKNOWN); for (i = 0; i < nplanes; ++i) WriteChunkBytes(iff, planes[i], pbytes); PopChunk(iff); CloseIFF(iff); Close(iff->iff_Stream); FreeIFF(iff); #if defined(_DCC) || defined(__GNUC__) CloseLibrary(IFFParseBase); #endif exit(0); } #define SETBIT(Plane, Plane_offset, Col, Value) \ if (Value) { \ planes[Plane][Plane_offset + (Col / 8)] |= 1 << (7 - (Col & 7)); \ } conv_image() { int row, col, planeno; for (row = 0; row < XpmScreen.Height; row++) { char *xb = xpmgetline(); int plane_offset; if (xb == 0) return; plane_offset = row * XpmScreen.BytesPerRow; for (col = 0; col < XpmScreen.Width; col++) { int slot; int color = xb[col]; if (!ttable[color].flag) { fprintf(stderr, "Bad image data\n"); } slot = ttable[color].slot; for (planeno = 0; planeno < nplanes; planeno++) { SETBIT(planeno, plane_offset, col, slot & (1 << planeno)); } } } } long * alloc(unsigned int n) { long *ret = malloc(n); if (!ret) { error("Can't allocate memory"); exit(1); } return (ret); } FILE *xpmfh = 0; char initbuf[200]; char *xpmbuf = initbuf; /* version 1. Reads the raw xpm file, NOT the compiled version. This is * not a particularly good idea but I don't have time to do the right thing * at this point, even if I was absolutely sure what that was. */ fopen_xpm_file(const char *fn, const char *mode) { int temp; char *xb; if (strcmp(mode, "r")) return FALSE; /* no choice now */ if (xpmfh) return FALSE; /* one file at a time */ xpmfh = fopen(fn, mode); if (!xpmfh) return FALSE; /* I'm hard to please */ /* read the header */ xb = xpmgetline(); if (xb == 0) return FALSE; if (4 != sscanf(xb, "%d %d %d %d", &XpmScreen.Width, &XpmScreen.Height, &XpmScreen.Colors, &temp)) return FALSE; /* bad header */ /* replace the original buffer with one big enough for * the real data */ /* XXX */ xpmbuf = malloc(XpmScreen.Width * 2); if (!xpmbuf) { error("Can't allocate line buffer"); exit(1); } if (temp != 1) return FALSE; /* limitation of this code */ { /* read the colormap and translation table */ int ccount = -1; while (ccount++ < (XpmScreen.Colors - 1)) { char index; int r, g, b; xb = xpmgetline(); if (xb == 0) return FALSE; if (4 != sscanf(xb, "%c c #%2x%2x%2x", &index, &r, &g, &b)) { fprintf(stderr, "Bad color entry: %s\n", xb); return FALSE; } ttable[index].flag = 1; /* this color is valid */ ttable[index].r = r; ttable[index].g = g; ttable[index].b = b; ttable[index].slot = ccount; } } return TRUE; } /* This deserves better. Don't read it too closely - you'll get ill. */ #define bufsz 2048 char buf[bufsz]; xpmgetline() { char *bp; do { if (fgets(buf, bufsz, xpmfh) == 0) return 0; } while (buf[0] != '"'); /* strip off the trailing <",> if any */ for (bp = buf; *bp; bp++) ; bp--; while (isspace(*bp)) bp--; if (*bp == ',') bp--; if (*bp == '"') bp--; bp++; *bp = '\0'; return &buf[1]; } nethack-3.6.0/sys/atari/Install.tos0000664000076400007660000001447212536476415016235 0ustar paxedpaxed Instructions for compiling and installing NetHack 3.6 on a TOS system ===================================================== (or, How to make ST NetHack 3.6) Last revision: 2 February 2000 1. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, util, sys\atari, sys\share, sys\unix, and at least one of win\tty and win\gem. You may have other subdirectories under sys and win, but they needn't concern you. If you do not follow this structure, the Makefiles will not function properly. The .c files for the main program belong in src, those for utility programs in util, and Atari-specific ones in sys\atari. All the .h files belong in include, the documentation in doc, and assorted data files in dat. You may also use random.c from sys\share. The Makefiles belong in sys\unix. (A more detailed explanation of the directory structure may be found in Files, which should be in the top directory.) 2. If you don't already have a good command line interpreter, get one. Doing all of the following from the desktop or a GEM shell will probably be a *big* pain. If you can get a Bourne shell compatible one, and put it in \bin\sh, then you'll save yourself some trouble with the Makefiles. There are several good shells on various FTP sites (including atari.archive.umich.edu). Run the "setup.g" shell script in sys\atari. This will setup all the makefiles and other files in the appropriate directories. It assumes that your compiler prefers \ to / as a directory separator. If not, simply copy the makefiles instead of running sed on them. 3. Now go to the include subdirectory to edit a couple of the header files there. First edit config.h according to the comments to match your system and desired set of features. In particular: make sure that UNIX is *not* defined, and TOS is (if you're using the MiNT library, and/or the -mint option to gcc, this will be done automatically) make sure that HACKDIR is defined properly (or not at all) make sure that COMPRESS is not defined Also edit tosconf.h; this shouldn't need much changing. If you are not going to include random.c you will need to comment out RANDOM. Gcc users don't need RANDOM, since the gcc and MiNT libraries have a Berkeley derived srandom() function already. If you have no termcap support and don't want to use the supplied termcap.uu, comment out TERMLIB. Gcc has a termcap library, so TERMLIB should always be "on" with gcc (and you don't need to worry about termcap.uu at all). 4. If you want to change the high score list behavior, examine the top of topten.c, in the src directory. You may want to change the definitions of PERSMAX, POINTSMIN, and ENTRYMAX. I set POINTSMIN to 51 and ENTRYMAX to 50 to keep the size of the score list down. 5. Go to the src directory and edit your Makefile. You'll want the Systos target configuration; the comments explain most of what needs to be done, at least for the gcc. Next, go to the top, util, dat, and doc directories, and edit the Makefiles there, as necessary. You'll need nroff and/or TeX to do the files in doc; if you don't have one/both of these, you can skip it (docs?? we don't need no steenking docs :-)). If you elected to use Fred Fish's termcap library (bundled in as termcap.arc), you will have to generate termcap.a from those sources. If you are recompiling after patching your sources, or if you got your files from somewhere other than the official distribution, "touch makedefs.c" to ensure that certain files (onames.h and pm.h) are remade, lest potentially troublesome timestamps fool "make." 8. Now, enter "make all", and take a long siesta; your computer will be occupied for a long time. If all goes well, you will get an executable. If you tried to compile in too many features, you will probably get a dysfunctional executable, and will have to start over. Hint 1: If you're short on memory, you might enter "make -n all >make.bat," and then run script.bat with some sort of batch program or with the gulam command "script make.bat." Hint 2: You'll save yourself a lot of grief if you use the GNU version of the "make" program. Some of the smaller makes aren't completely compatible. GNU software for the Atari is widely available; for example, by anonymous FTP from atari.archive.umich.edu. 9. Make sure the support files -- data, rumors, cmdhelp, opthelp, help, hh, history, license, and oracles, or simply nhdat if DLB was defined -- were copied to the game directory. If not, move them there from the dat directory yourself. rumors can be created manually by entering "makedefs -r;" data by entering "makedefs -d." Also, make sure that the various level files (*.lev, from the dat subdirectory) were copied over correctly. If you're not sure what files should have been made, double check with Makefile.dat. 10. Go to the src\atari directory. Copy atari.cnf to your game directory as NetHack.cnf. Edit it to reflect your particular setup and personal preferences, following the comments. If you compiled in the TERMLIB feature, also move the "termcap" file to your game directory. (Note: gcc's termcap routines have built-in defaults, so the termcap file is not necessary with that compiler.) If you're running NetHack from the MultiTOS desktop, and you want a more useful set of drop down menus than the plain system "File/Edit" ones, copy nethack.mnu to your games directory. This file contains a menu definition that puts a lot of the common commands into the menu. 11. Play NetHack. If it works, you're done! Notes ----- 1) Save files and bones files from previous versions will not work with NetHack 3.4. Don't bother trying to keep them. 2) To install an update of NetHack after changing something, enter "make" from the src directory. If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but more often produces crashes.) nethack-3.6.0/sys/atari/atarifnt.uue0000664000076400007660000001577412467321052016423 0ustar paxedpaxedtable !"#$%&'()*+,-./0123456789:;<=>? @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ begin 644 hackfnt.arc M&@A(04-+1DY4+E!21P E!, #\48JO>BQ\= ,8#0 #" S4 ,! ! &@!Bz M8 "#D!2 > . !Q_P%!5= 'D!0(GN10.X('EB9,Z1L+0"<,&1!DY*5L<@-B,#H(!<(N' 8XIH'SYK3.CQSX057EA26DQ\r MPP$/)REU#@XPB$ 1!G0 0$(: &!033IT8:&$"0KPY1<)0XR@#%5_4O90D1D<"*$)%H((p M\1T&9O C)HDD(,.H$I#R \9 B%1Z::9HFB&+HHQ*\Q4@$&2 !" R (!$,"!Lo MB<0;",#!#S"!4 -(-P(L0$8"*1J 3#1,GNM,T),m M8$< (PQ#%1UHGB%!I5*81\>GD8;JCA"2@" %H 4R0 ')RW% P@\ZO " !H l M>>.0 !1) ))U+(4#""D*H,^.3/PP0)!!@"PRQ76 @!Z5/%1,5,HZ_(//"#Dk MD3,#: P3_2)LS)@#4:4< V708,0A\>,3@X(80P0Z%CR-^,G"0D)$00%@$8 ("#0CD i MH9 +/!B@4 E@R- J) ;$PX.,"_&PD$(&M E) 0B(=+E"&Q0."08%@,(T'ZM_h MKA !"\P)">$ , W)#6UN"HD&#F PX.P&% X&!U4"L"D&8.C$0&W"(P^ 3@ Xg M()(!LTNN4 %@Z#Z Y &(!(,>>IC1N4A;C)[Y["3$-E D(N%#EPT#F>] UAY(f M#PD"A1M^^.?^>,\ '_YP1_<,@P<( '/_CA@GXP #/ 8 PXK1 ?d M/O"#3FIH!C]X@#UM@H/Q . XZ7F' <#87^\P (/XF8$!/# ##. 711C R8H?c M!( )I<@#*RX$ QXP P8\@C&G(0L!G*"UB@ E,>"(?],"Z+YAO).@#b M !5:PSX9@0,$/O!! $PH(S^X@7A?[%__%@*!IOC Q#P0=; 8(#>#80-68,!a M#/#0/Q#B@ ,X\(<$J1YB$ ,,L*+Iz M$N,'#+APA"'<7/0 X_K-"%?/##0GHH0QKV<"'\<.$.=>)#]ASN<)MR'&R.y MF$2%',!TP6/B0'182PP03R?E7(@? ( /=(K1# ?! 9P\@('9P1&-:@%!_N"Xx M3@ LDG 04(8QC%&%.VJ. .E306O6N4YPQ& ,-A@ (;7H!OAE;IW]4Q$$_- 2w M"&RTDW!P0 8P@ $!$"%K>$!"_GA A;00!?^L,8 Q/@ .* 2%*I<2"M?N3DAv M N T*C@/\# !AR8$P=97(@!S"#/B8$!#DL5HSG] 9PFCV!P'T ">@:/Q:P ,:@$4.^_P/;XA7L%\Z+,& 6T-'4+3J#JQ!@CK20!C#&2IR;/EF_$1Z;!BKY;6g M,"\\P.@+'H2<>MP5KYIUPH<-V/I^8(!!G&,(J85$6XP'68@-L+%4-YAA&S>_f M<$!%(0M>\^,#^ #V/XRF@EJ8 \8R(L !,#L(9\?8#@Y@:B80(6=4,*"&,!"$e M'VKH[;ZX$)0D]4-K%@*-K]'U'(&HK37TH0M&=(*%'N! #CBQ95SH8"$(U(4.d M*GD >,P( /\PM3>JM/$9H1B7;#! +\4W$#B0\,B/(H86+D'.$&"D&\ZYE\$,!_VT$Z<^P-2KNVY1'5(b M5QC((+ULN* =W+"-"NM0)'H0A2X '41_RC8 $ !%7HQ#QGS "/?R&P.GVV a MI>+@'8C ,0K.+L5&L8%AMU4M6E5?.!^()*B?0P+#X%*2( ^2P B!P /X $2z MD >>H$K L$JJI$I^ $/X#Y?!'D&8 .31U))-0"ZA'FLQGF&8VG<$'HX%G+?y M90Q&YV+8T#LZX0\?A%YF)1(HN'DC]V/;!08?%(/(9U2' WO*A#T6IF8N! ;_x M4'P)<&IBM'F0)44N9'08@ TVH$-VX ??8'WPM! *H N[YFO>)V+# $JP $[w MH 4]A!' L&S)Q'X>Q 9F4&U@@ (8@':-@@+X!VYHUCL+D348 770P),Q0&Zv M8 _6@ W#0%4

@4X,@ TZ6'LP>'Y5-%< ( 0ZD3RUt M-SLSAV/8@ UAA0 'AGSOM!!&!V#3X S0)UX#9HR;PX6,]5/@$(;!1F)4@ 'Ss MX ;#\ _^ _P@%G!\&(QUGZ*=F-S" -H5T.J8 9 )F3($SRV*$L\($0!V$7,r M90[&@ 4O9C04T(B/J%.1N%0"@!"6Z&*8"$KP5#B9QD0B9T5+)#T#(@[BI56Fq MB(J_J :K""D\ %9G%3PB\8LXYDMO)E\U5'NL&)(AA%[B- PF&8R$$XM@4(PFp MAU5=I$+*.#O21$D&H $8,'3;A9/5. *,%"BLSEX!4\J\ ]7%8Y\0(XV\ >#o M "IM4Y?I%8 !@TS]#Z%IPP@#.P ,U9&$YY@&6R6"])$YL!@D+@%C45&M#l MF$.]] ?IY4LAA%7M%6#2\GRQ9ICB2$TBH0"LLY2)A5CI0P4OY&S_P ?\P \Vk M, 8Y-#KMQP:NQP:;X@\XT 5&PP-L,)<;Y7%%B FO8SH-T$3[,P!!( BKLYZUj MLT)&XY> "0!V0$1M!9$\Z$)Q]$'_h M@#QPT%X?"CT>2DD8\ /YTUZ\P M_H)/!>3V(Y:$+D5"7LPQLQIS\$$C)))T&g M<)Y@X'C]DQZ>,P#P$$G@^47Z* $-X3D1X &8XP!-! E:JA KT$^V@SWZ=@#Kf MU#L#TA:8d M8P"A T\!8ACS83Y"J1!PYH$C-D@D18ZIPP<&P#H(ZCIXT'B"4T'%8U3B=CT"c M\$$A!$P3143&U(2-,M#R+>60#<601Q%*@E G"z MIEL\$*C D$H2Z$J1Z'%@<(&Q4T'1=TL.N4ON)UW4A4ZX! (%D48U%UB9 #6y MZ0Z#5@!DI1/!XQV'DQYKU41MY1W>!$YJYAT.^Y"%\Y#/0U>%@PJU,@.U L1(D35$'^0%3--1+/17#!$V?C@D[JI$%&u M)XM.IZ^t M1&&6R%\1^TI+@?)$0D%7#KA $H1BZ9EZ#^![-MP0!Jq MX'![%G%^!@=@<'HNMD*K]T&SXW$P '(Z@6 DE4'^8'*S6%KF18.>0 /)8I47/9@?FR@;4Q@=BD$&+"RDZQ U4<'K%6SIHn M23AL /+ P#G, Q/-@SYD D/7('>\ ^_59"L=) NA!! 53R9!P,=6'D+$8*:m MMU16%#R;0U)])HLJ*+NI*&"95TNN2(.[=$')WR%T]*(_(-SL,0 /4l M9 ^T'XY%GR@Q@=_4'P(D'-5Q(H^=\.$O 8$QP8VL%1V8 =9>#E># %Z$ HAk MX6M05\9(0 7=@+[R.XYKZ -TRW[090SO@ PX-LAY+%[,T,<<]+!3" "M4B78j M@$D1)(B0FPGS, QP,(9IY@$9@ F2/(&L!@$$@%PBX0\,21?R)$X1:470]8EFi MA4L'9CSB99VF:)T\1%3N%))BY!TD:9,X!@-37)LKR5TMR5Y7FUAB$$4YUD,Fh MU%U&&&!&60 7=$60&F/G ,Jg MX%I^, ;+R0_E> ?O*YU0M*!R"(=Y'$4DP XX8 V$.R.VR 0'H8\%0 (;BU3Gf M< X@, PXL'(;X("RFF]ZO4(>@*5DALD88 3SV:LDC % <)OYV45- ;..XQT7e MM$(M! ::): %"@8V "?)=YD^) .*DD?VD42"I(5Z@,7FJ'8IGG9JD4(T%Z_d M][:40TU86**__*&^I$*2?3D[/1!2Q "&\ D8\*[MI4XW>GUG=4%:)*6#M:5M68T$4(%MU8BJZJC[b MTP"ZHP-9P]:7"@D'X(0#L %T@ 9A, 9KD%5TX (Z+@"X$.(C7N(G7N6XH.)B$ 8Wx M3A]B@072\ 4+P1(V409*O@%\H.)E@ =I$"4J(A)63N)OP 9Rw M\ 5D$ 9^N35L/@!$4 1&$ 15$.> H.)H@.-P\.5^61 JSN(U'B4I7A1N\ : v M+N@B,0!%7@9T4.=XKN.4_A-VD 8QX09Q3@B53@=K, =IH =QC@A?\!)RL.EBu MON2,<.MV'B4+P>5?8.9H'NQZK@]?8!-WKN=Z#@^W'N@K 1;'$>IN0 :O$^>#t M(1(0$,T,@ Z@ +2H@ *X (H &H 0( .KQ !"8*)6P ZP $0X #C3@$ s # !H r q end nethack-3.6.0/sys/atari/nethack.mnu0000664000076400007660000000150412467321052016213 0ustar paxedpaxed# Sample .mnu file for NetHack # This will work only with MINIWIN v1.1 # or TOSWIN v2.0 (or better) #%title "NetHack" #%about "About NetHack" "v" File "Shell" "!" "Options" "O" --- "Save Game" "S" --- "Quit" ?"[1][Really quit?][ Yes | No ]":%A"#quit y":! Edit "Copy" %C "Paste" %P "Paste Options..." %O --- "Set Font..." %F Inventory "Show Inventory" "i" -- "Put on jewelry" "P" "Remove jewelry" "R" "Wear armor" "W" "Take off armor" "T" "Wield weapon" "w" "Exchange weapons" "x" "Ready ammo in quiver" "Q" --- "Eat" "e" "Quaff potion" "q" --- "Drop" "d" "Throw" "t" "Fire" "f" Move "North" "k" 4800 "South" "j" 5000 "East" "l" 4d00 "West" "h" 4b00 --- "Rest" "." --- "Open door" "o" "Close door" "c" Misc "Help" "?" 6200 "List known spells" "+" "Cast spell" "Z" --- "Abort" 001b 6100 nethack-3.6.0/sys/atari/setup.g0000664000076400007660000000131012467321052015360 0ustar paxedpaxed# gulam shell script -- should work with tcsh and many # other Atari shells, too # UNIX shells use '/' in file names, but at least some Atari shells need '\' # so we process the UNIX makefiles to make that switch # sed script not included as a here document in this script because at # least some Atari shells don't do that sed -f unx2atar.sed < ..\unix\Makefile.top > ..\..\Makefile sed -f unx2atar.sed < ..\unix\Makefile.dat > ..\..\dat\Makefile sed -f unx2atar.sed < ..\unix\Makefile.doc > ..\..\doc\Makefile sed -f unx2atar.sed < ..\unix\Makefile.src > ..\..\src\Makefile sed -f unx2atar.sed < ..\unix\Makefile.utl > ..\..\util\Makefile # KLUDGE to fix a Makefile problem echo > ..\..\include\win32api.h nethack-3.6.0/sys/atari/tos.c0000664000076400007660000002024712536476415015046 0ustar paxedpaxed/* NetHack 3.6 tos.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* NetHack may be freely redistributed. See license for details. */ /* * TOS system functions. */ #define NEED_VARARGS #include "hack.h" #ifdef TTY_GRAPHICS #include "tcap.h" #else /* To avoid error for tos.c; will be removed later */ static char *nh_HE = "\033q"; #endif #ifdef TOS #include #ifndef WORD #define WORD short /* 16 bits -- redefine if necessary */ #endif #include static char NDECL(DOSgetch); static char NDECL(BIOSgetch); static void NDECL(init_aline); char *_a_line; /* for Line A variables */ #ifdef TEXTCOLOR boolean colors_changed = FALSE; #endif int tgetch() { char ch; /* BIOSgetch can use the numeric key pad on IBM compatibles. */ if (iflags.BIOS) ch = BIOSgetch(); else ch = DOSgetch(); return ((ch == '\r') ? '\n' : ch); } /* * Keyboard translation tables. */ #define KEYPADLO 0x61 #define KEYPADHI 0x71 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { { C('['), 'Q', C('[') }, /* UNDO */ { '?', '/', '?' }, /* HELP */ { '(', 'a', '(' }, /* ( */ { ')', 'w', ')' }, /* ) */ { '/', '/', '/' }, /* / */ { C('p'), '$', C('p') }, /* * */ { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'h', 'H', C('h') }, /* 4 */ { '.', '.', '.' }, { 'l', 'L', C('l') }, /* 6 */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[PADKEYS] = { { C('['), 'Q', C('[') }, /* UNDO */ { '?', '/', '?' }, /* HELP */ { '(', 'a', '(' }, /* ( */ { ')', 'w', ')' }, /* ) */ { '/', '/', '/' }, /* / */ { C('p'), '$', C('p') }, /* * */ { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { '4', M('4'), '4' }, /* 4 */ { '.', '.', '.' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }; /* * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII * meaning unless assigned one by a keyboard conversion table, so the * keyboard BIOS normally does not return a character code when Alt-letter * is pressed. So, to interpret unassigned Alt-letters, we must use a * scan code table to translate the scan code into a letter, then set the * "meta" bit for it. -3. */ #define SCANLO 0x10 static const char scanmap[] = { /* ... */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'N', 'm', ',', '.', '?' /* ... */ }; #define inmap(x) (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap)) /* * BIOSgetch gets keys directly with a BIOS call. */ #define SHIFT (0x1 | 0x2) #define CTRL 0x4 #define ALT 0x8 static char BIOSgetch() { unsigned char scan, shift, ch; const struct pad *kpad; long x; /* Get scan code. */ x = Crawcin(); ch = x & 0x0ff; scan = (x & 0x00ff0000L) >> 16; /* Get shift status. */ shift = Kbshift(-1); /* Translate keypad keys */ if (iskeypad(scan)) { kpad = iflags.num_pad ? numpad : keypad; if (shift & SHIFT) ch = kpad[scan - KEYPADLO].shift; else if (shift & CTRL) ch = kpad[scan - KEYPADLO].cntrl; else ch = kpad[scan - KEYPADLO].normal; } /* Translate unassigned Alt-letters */ if ((shift & ALT) && !ch) { if (inmap(scan)) ch = scanmap[scan - SCANLO]; return (isprint(ch) ? M(ch) : ch); } return ch; } static char DOSgetch() { return (Crawcin() & 0x007f); } long freediskspace(path) char *path; { int drive = 0; struct { long freal; /*free allocation units*/ long total; /*total number of allocation units*/ long bps; /*bytes per sector*/ long pspal; /*physical sectors per allocation unit*/ } freespace; if (path[0] && path[1] == ':') drive = (toupper(path[0]) - 'A') + 1; if (Dfree(&freespace, drive) < 0) return -1; return freespace.freal * freespace.bps * freespace.pspal; } /* * Functions to get filenames using wildcards */ int findfirst(path) char *path; { return (Fsfirst(path, 0) == 0); } int findnext() { return (Fsnext() == 0); } char * foundfile_buffer() { return (char *) Fgetdta() + 30; } long filesize(file) char *file; { if (findfirst(file)) return (*(long *) ((char *) Fgetdta() + 26)); else return -1L; } /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { char *ptr; char drive; if ((ptr = index(str, ':')) != (char *) 0) { drive = toupper(*(ptr - 1)); (void) Dsetdrv(drive - 'A'); } return; } void get_scr_size() { #ifdef MINT #include struct winsize win; char *tmp; if ((tmp = nh_getenv("LINES"))) LI = atoi(tmp); else if ((tmp = nh_getenv("ROWS"))) LI = atoi(tmp); if (tmp && (tmp = nh_getenv("COLUMNS"))) CO = atoi(tmp); else { ioctl(0, TIOCGWINSZ, &win); LI = win.ws_row; CO = win.ws_col; } #else init_aline(); LI = (*((WORD *) (_a_line + -42L))) + 1; CO = (*((WORD *) (_a_line + -44L))) + 1; #endif } #define BIGBUF 8192 int _copyfile(from, to) char *from, *to; { int fromfd, tofd, r; char *buf; if ((fromfd = open(from, O_RDONLY | O_BINARY, 0)) < 0) return -1; if ((tofd = open(to, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK)) < 0) return -1; buf = (char *) alloc((size_t) BIGBUF); while ((r = read(fromfd, buf, BIGBUF)) > 0) write(tofd, buf, r); close(fromfd); close(tofd); free(buf); return 0; /* successful */ } int kbhit() { return Cconis(); } static void init_aline() { #ifdef __GNUC__ /* line A calls nuke registers d0-d2,a0-a2; not all compilers regard these as scratch registers, though, so we save them */ asm(" moveml d0-d2/a0-a2, sp@-"); asm(" .word 0xa000; movel d0, __a_line"); asm(" moveml sp@+, d0-d2/a0-a2"); #else asm(" movem.l d0-d2/a0-a2, -(sp)"); asm(" .dc.w 0xa000"); /* tweak as necessary for your compiler */ asm(" move.l d0, __a_line"); asm(" movem.l (sp)+, d0-d2/a0-a2"); #endif } #ifdef TEXTCOLOR /* used in termcap.c to decide how to set up the hilites */ unsigned long tos_numcolors = 2; void set_colors() { static char colorHE[] = "\033q\033b0"; if (!iflags.BIOS) return; init_aline(); tos_numcolors = 1 << (((unsigned char *) _a_line)[1]); if (tos_numcolors <= 2) { /* mono */ iflags.use_color = FALSE; return; } else { colors_changed = TRUE; nh_HE = colorHE; } } void restore_colors() { static char plainHE[] = "\033q"; if (colors_changed) nh_HE = plainHE; colors_changed = FALSE; } #endif /* TEXTCOLOR */ #ifdef SUSPEND #include #ifdef MINT extern int __mint; #endif int dosuspend() { #ifdef MINT extern int kill(); if (__mint == 0) { #endif pline("Sorry, it seems we have no SIGTSTP here. Try ! or S."); #ifdef MINT } else if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) { suspend_nhwindows((char *) 0); (void) signal(SIGTSTP, SIG_DFL); (void) kill(0, SIGTSTP); get_scr_size(); resume_nhwindows(); } else { pline("I don't think your shell has job control."); } #endif /* MINT */ return (0); } #endif /* SUSPEND */ #endif /* TOS */ nethack-3.6.0/sys/atari/unx2atar.sed0000664000076400007660000000143712467321052016323 0ustar paxedpaxed: loop /\\$/N /\\$/b loop # for each line, append any continuation lines before trying to classify it /^ / { # if it starts with a tab, it's meant for the shell, and we should think # about reversing the slashes s;cd ../util;cd ..\\util; s;cd ../src;cd ..\\src; /librarian/ s;dat/options;dat\\options; /$(MAKE)/b /$(CC)/b s;/;\\;g } # unfortunately, we do not want to reverse *all* the slashes, as even the # Atari make and gcc like forward ones, and it's messy to avoid the ones in # sed addresses # so, flip the first one in e.g. # @( cd ../util ; $(MAKE) ../include/onames.h ) # flip the librarian-related ones in dat/options # ignore other lines related to make and gcc # and flip any slashes left over, which include a number of UNIX-only things # that we didn't need to do but don't hurt nethack-3.6.0/sys/be/README0000664000076400007660000000473412536476415014246 0ustar paxedpaxedThis file is sys/be/README. It is for those intending to compile NetHack 3.6 on a BeOS 4.5 system. BeOS NetHack currently only supports the TTY windowing system. In order to compile it, it would benefit you greatly to think of your Be system as a UNIX variant. It is possible to compile using BeIDE. However, there are four executables and several steps involved in making NetHack. Unless you are extremely familiar with the build sequence and are willing to modify the code somewhat, I suggest you avoid it for now. Let the UNIX Makefiles take care of all that for you. Known problems: + No special characters for walls. None of the fonts available for use in a tty window has the graphics characters needed to improve the look. If such a font existed, then all you need to do is set the dungeon, object, and/or monter mappings in your defaults file. + The arrow keys don't work. Build instructions. From a freshly unpacked source tree: 1. Copy the Makfiles in sys/unix to their proper spots. You may use setup.sh or copy them by hand. Using setup.sh to create links instead of copying the Makefiles will work, but BeOS will not let you edit a link. It may be helpful to read sys/unix/Install.unx. 2. Edit src/Makefile: o Change System to SysBe. o Comment out the UNIX versions of SYSSRC and SYSOBJ variables. o Uncomment the BeOS versions of SYSRC and SYSOBJ. o Uncomment the BeOS versions of CC, CFLAGS, LD, and LFLAGS. The flags are different for Intel vs BeBox/Mac. o Uncomment one of the Intel or BeBox/Mac BeOS versions of CC, CFLAGS, LD, and LFLAGS. o Comment out the default CFLAGS and LFLAGS. o Change WINTTYLIB to be -ltermcap. 3. Edit util/Makefile: o If on a BeBox/Mac: - Uncomment the BeOS versions of CC and CFLAGS - Comment out the default CFLAGS and LFLAGS. o If on Intel: - the default values of CFLAGS and LFLAGS work fine o Change YACC and LEX to be bison -y and flex respectively. 4. Edit include/config.h to change HACKDIR to be the location of your install directory. 5. Edit top level Makefile and change GAMEDIR to match HACKDIR in include/config.h. Make sure the path to GAMEDIR exists. Change SHELLDIR to a "throw away" directory, like /tmp. We don't use the shell. Change CHOWN and CHGRP commands to "true", there really aren't groups on the BeOS. 6. Type "make install" at the top level. It is possible that some necessary steps needed to make the game have been omitted. Feel free to ad-lib as necessary. nethack-3.6.0/sys/be/bemain.c0000664000076400007660000001637112623162643014755 0ustar paxedpaxed/* NetHack 3.6 bemain.c $NHDT-Date: 1447844549 2015/11/18 11:02:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (c) Dean Luick, 1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #include static void whoami(void); static void process_options(int argc, char **argv); static void chdirx(const char *dir); static void getlock(void); #ifdef __begui__ #define MAIN nhmain int nhmain(int argc, char **argv); #else #define MAIN main #endif int MAIN(int argc, char **argv) { int fd; char *dir; boolean resuming = FALSE; /* assume new game */ sys_early_init(); dir = nh_getenv("NETHACKDIR"); if (!dir) dir = nh_getenv("HACKDIR"); choose_windows(DEFAULT_WINDOW_SYS); chdirx(dir); initoptions(); init_nhwindows(&argc, argv); whoami(); /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ process_options(argc, argv); /* command line options */ set_playmode(); /* sets plname to "wizard" for wizard mode */ /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); /* unlike Unix where the game might be invoked with a script which forces a particular character name for each player using a shared account, we always allow player to rename the character during role/race/&c selection */ iflags.renameallowed = TRUE; getlock(); dlb_init(); /* must be before newgame() */ /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. */ attempt_restore: if ((fd = restore_saved_game()) >= 0) { #ifdef NEWS if (iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if (dorecover(fd)) { resuming = TRUE; /* not starting new game */ if (discover) You("are in non-scoring discovery mode."); if (discover || wizard) { if (yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { nh_compress(fqname(SAVEF, SAVEPREFIX, 0)); } } } } if (!resuming) { /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name and skip selection this time if that didn't succeed */ if (!iflags.renameinprogress) { player_selection(); if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; discard current lock file and create another for the new character name */ delete_levelfile(0); /* remove empty lock file */ getlock(); goto attempt_restore; } } newgame(); if (discover) You("are in non-scoring discovery mode."); } moveloop(resuming); return 0; } static void whoami(void) { /* * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS * 2. Use $USER or $LOGNAME (if 1. fails) * The resulting name is overridden by command line options. * If everything fails, or if the resulting name is some generic * account like "games", "play", "player", "hack" then eventually * we'll ask him. */ char *s; if (*plname) return; if (s = nh_getenv("USER")) { (void) strncpy(plname, s, sizeof(plname) - 1); return; } if (s = nh_getenv("LOGNAME")) { (void) strncpy(plname, s, sizeof(plname) - 1); return; } } /* normalize file name - we don't like .'s, /'s, spaces */ void regularize(char *s) { register char *lp; while ((lp = strchr(s, '.')) || (lp = strchr(s, '/')) || (lp = strchr(s, ' '))) *lp = '_'; } static void process_options(int argc, char **argv) { int i; while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case 'D': wizard = TRUE, discover = FALSE; break; case 'X': discover = TRUE, wizard = FALSE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if (argv[0][2]) (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1); else if (argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname) - 1); } else raw_print("Player name expected after -u"); break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; case '@': flags.randomall = 1; break; default: raw_printf("Unknown option: %s", *argv); break; } } } static void chdirx(const char *dir) { if (!dir) dir = HACKDIR; if (chdir(dir) < 0) error("Cannot chdir to %s.", dir); /* Warn the player if we can't write the record file */ /* perhaps we should also test whether . is writable */ check_recordfile(dir); } void getlock(void) { int fd; Sprintf(lock, "%d%s", getuid(), plname); regularize(lock); set_levelfile_name(lock, 0); fd = creat(lock, FCMASK); if (fd == -1) { error("cannot creat lock file."); } else { if (write(fd, (genericptr_t) &hackpid, sizeof(hackpid)) != sizeof(hackpid)) { error("cannot write lock"); } if (close(fd) == -1) { error("cannot close lock"); } } } /* validate wizard mode if player has requested access to it */ boolean authorize_wizard_mode() { /* other ports validate user name or character name here */ return TRUE; } #ifndef __begui__ /* * If we are not using the Be GUI, then just exit -- we don't need to * do anything extra. */ void nethack_exit(int status); void nethack_exit(int status) { exit(status); } #endif /* !__begui__ */ /*bemain.c*/ nethack-3.6.0/sys/mac/Files.r0000664000076400007660000003335712504242744014757 0ustar paxedpaxed#include #include "date.h" #include "patchlevel.h" /* Carbon 'carb' resource * has been made obsolete by the 'plst' resource below. */ /* Carbon 'plst' resource * Single-file applications must have this resource for MacOS X to * count it as a Carbon app rather than a Classic app. It contains * an embedded Info.plist file, with the same format as would occur * in an application based on a directory bundle. The attributes * declared in this resource override the 'BNDL', 'FREF', and 'vers' * resources in MacOS X. * * For further information, see * http://developer.apple.com/technotes/tn/tn2013.html */ read 'plst' (0) "carbon.plist"; /* Classic resources * These resources are used in MacOS 9.x and earlier. */ resource 'vers' (1, purgeable) { VERSION_MAJOR, (VERSION_MINOR<<4) | PATCHLEVEL, final, EDITLEVEL, verUS, VERSION_STRING, VERSION_STRING }; resource 'vers' (2, purgeable) { VERSION_MAJOR, (VERSION_MINOR<<4) | PATCHLEVEL, final, EDITLEVEL, verUS, VERSION_STRING, "devteam@nethack.org" }; /* Dungeon librarian files * File data and quest.dat have gotten too big to be put into resources! */ #ifdef TARGET_API_MAC_CARBON read 'File' (1000,"cmdhelp") "cmdhelp"; read 'File' (1001,"help") "help"; read 'File' (1002,"hh") "hh"; read 'File' (1003,"history") "history"; read 'File' (1004,"license") "license"; read 'File' (1005,"MacHelp") "MacHelp"; read 'File' (1006,"News") "News"; read 'File' (1007,"opthelp") "opthelp"; read 'File' (1008,"wizhelp") "wizhelp"; read 'File' (1009,"air.lev") "air.lev"; read 'File' (1010,"asmodeus.lev") "asmodeus.lev"; read 'File' (1011,"astral.lev") "astral.lev"; read 'File' (1012,"baalz.lev") "baalz.lev"; read 'File' (1013,"bigrm-1.lev") "bigrm-1.lev"; read 'File' (1014,"bigrm-2.lev") "bigrm-2.lev"; read 'File' (1015,"bigrm-3.lev") "bigrm-3.lev"; read 'File' (1016,"bigrm-4.lev") "bigrm-4.lev"; read 'File' (1017,"bigrm-5.lev") "bigrm-5.lev"; read 'File' (1018,"castle.lev") "castle.lev"; //read 'File' (1019,"data") "data"; read 'File' (1020,"dungeon") "dungeon"; read 'File' (1021,"earth.lev") "earth.lev"; read 'File' (1022,"fakewiz1.lev") "fakewiz1.lev"; read 'File' (1023,"fakewiz2.lev") "fakewiz2.lev"; read 'File' (1024,"fire.lev") "fire.lev"; read 'File' (1025,"juiblex.lev") "juiblex.lev"; read 'File' (1026,"knox.lev") "knox.lev"; read 'File' (1027,"medusa-1.lev") "medusa-1.lev"; read 'File' (1028,"medusa-2.lev") "medusa-2.lev"; read 'File' (1029,"minefill.lev") "minefill.lev"; read 'File' (1030,"minend-1.lev") "minend-1.lev"; read 'File' (1031,"minend-2.lev") "minend-2.lev"; read 'File' (1032,"minend-3.lev") "minend-3.lev"; read 'File' (1034,"minetn-1.lev") "minetn-1.lev"; read 'File' (1035,"minetn-2.lev") "minetn-2.lev"; read 'File' (1036,"minetn-3.lev") "minetn-3.lev"; read 'File' (1037,"minetn-4.lev") "minetn-4.lev"; read 'File' (1038,"minetn-5.lev") "minetn-5.lev"; read 'File' (1039,"minetn-6.lev") "minetn-6.lev"; read 'File' (1040,"minetn-7.lev") "minetn-7.lev"; read 'File' (1041,"options") "options"; read 'File' (1042,"oracle.lev") "oracle.lev"; read 'File' (1043,"oracles") "oracles"; read 'File' (1044,"orcus.lev") "orcus.lev"; //read 'File' (1045,"quest.dat") "quest.dat"; read 'File' (1046,"rumors") "rumors"; read 'File' (1047,"sanctum.lev") "sanctum.lev"; read 'File' (1048,"soko1-1.lev") "soko1-1.lev"; read 'File' (1049,"soko1-2.lev") "soko1-2.lev"; read 'File' (1050,"soko2-1.lev") "soko2-1.lev"; read 'File' (1051,"soko2-2.lev") "soko2-2.lev"; read 'File' (1052,"soko3-1.lev") "soko3-1.lev"; read 'File' (1053,"soko3-2.lev") "soko3-2.lev"; read 'File' (1054,"soko4-1.lev") "soko4-1.lev"; read 'File' (1055,"soko4-2.lev") "soko4-2.lev"; read 'File' (1056,"tower1.lev") "tower1.lev"; read 'File' (1057,"tower2.lev") "tower2.lev"; read 'File' (1058,"tower3.lev") "tower3.lev"; read 'File' (1059,"valley.lev") "valley.lev"; read 'File' (1060,"water.lev") "water.lev"; read 'File' (1061,"wizard1.lev") "wizard1.lev"; read 'File' (1062,"wizard2.lev") "wizard2.lev"; read 'File' (1063,"wizard3.lev") "wizard3.lev"; read 'File' (1100,"Arc-fila.lev") "Arc-fila.lev"; read 'File' (1101,"Arc-filb.lev") "Arc-filb.lev"; read 'File' (1102,"Arc-goal.lev") "Arc-goal.lev"; read 'File' (1103,"Arc-loca.lev") "Arc-loca.lev"; read 'File' (1104,"Arc-strt.lev") "Arc-strt.lev"; read 'File' (1105,"Bar-fila.lev") "Bar-fila.lev"; read 'File' (1106,"Bar-filb.lev") "Bar-filb.lev"; read 'File' (1107,"Bar-goal.lev") "Bar-goal.lev"; read 'File' (1108,"Bar-loca.lev") "Bar-loca.lev"; read 'File' (1109,"Bar-strt.lev") "Bar-strt.lev"; read 'File' (1110,"Cav-fila.lev") "Cav-fila.lev"; read 'File' (1111,"Cav-filb.lev") "Cav-filb.lev"; read 'File' (1112,"Cav-goal.lev") "Cav-goal.lev"; read 'File' (1113,"Cav-loca.lev") "Cav-loca.lev"; read 'File' (1114,"Cav-strt.lev") "Cav-strt.lev"; read 'File' (1115,"Hea-fila.lev") "Hea-fila.lev"; read 'File' (1116,"Hea-filb.lev") "Hea-filb.lev"; read 'File' (1117,"Hea-goal.lev") "Hea-goal.lev"; read 'File' (1118,"Hea-loca.lev") "Hea-loca.lev"; read 'File' (1119,"Hea-strt.lev") "Hea-strt.lev"; read 'File' (1120,"Kni-fila.lev") "Kni-fila.lev"; read 'File' (1121,"Kni-filb.lev") "Kni-filb.lev"; read 'File' (1122,"Kni-goal.lev") "Kni-goal.lev"; read 'File' (1123,"Kni-loca.lev") "Kni-loca.lev"; read 'File' (1124,"Kni-strt.lev") "Kni-strt.lev"; read 'File' (1125,"Mon-fila.lev") "Mon-fila.lev"; read 'File' (1126,"Mon-filb.lev") "Mon-filb.lev"; read 'File' (1127,"Mon-goal.lev") "Mon-goal.lev"; read 'File' (1128,"Mon-loca.lev") "Mon-loca.lev"; read 'File' (1129,"Mon-strt.lev") "Mon-strt.lev"; read 'File' (1130,"Pri-fila.lev") "Pri-fila.lev"; read 'File' (1131,"Pri-filb.lev") "Pri-filb.lev"; read 'File' (1132,"Pri-goal.lev") "Pri-goal.lev"; read 'File' (1133,"Pri-loca.lev") "Pri-loca.lev"; read 'File' (1134,"Pri-strt.lev") "Pri-strt.lev"; read 'File' (1135,"Ran-fila.lev") "Ran-fila.lev"; read 'File' (1136,"Ran-filb.lev") "Ran-filb.lev"; read 'File' (1137,"Ran-goal.lev") "Ran-goal.lev"; read 'File' (1138,"Ran-loca.lev") "Ran-loca.lev"; read 'File' (1139,"Ran-strt.lev") "Ran-strt.lev"; read 'File' (1140,"Rog-fila.lev") "Rog-fila.lev"; read 'File' (1141,"Rog-filb.lev") "Rog-filb.lev"; read 'File' (1142,"Rog-goal.lev") "Rog-goal.lev"; read 'File' (1143,"Rog-loca.lev") "Rog-loca.lev"; read 'File' (1144,"Rog-strt.lev") "Rog-strt.lev"; read 'File' (1145,"Sam-fila.lev") "Sam-fila.lev"; read 'File' (1146,"Sam-filb.lev") "Sam-filb.lev"; read 'File' (1147,"Sam-goal.lev") "Sam-goal.lev"; read 'File' (1148,"Sam-loca.lev") "Sam-loca.lev"; read 'File' (1149,"Sam-strt.lev") "Sam-strt.lev"; read 'File' (1150,"Tou-fila.lev") "Tou-fila.lev"; read 'File' (1151,"Tou-filb.lev") "Tou-filb.lev"; read 'File' (1152,"Tou-goal.lev") "Tou-goal.lev"; read 'File' (1153,"Tou-loca.lev") "Tou-loca.lev"; read 'File' (1154,"Tou-strt.lev") "Tou-strt.lev"; read 'File' (1155,"Val-fila.lev") "Val-fila.lev"; read 'File' (1156,"Val-filb.lev") "Val-filb.lev"; read 'File' (1157,"Val-goal.lev") "Val-goal.lev"; read 'File' (1158,"Val-loca.lev") "Val-loca.lev"; read 'File' (1159,"Val-strt.lev") "Val-strt.lev"; read 'File' (1160,"Wiz-fila.lev") "Wiz-fila.lev"; read 'File' (1161,"Wiz-filb.lev") "Wiz-filb.lev"; read 'File' (1162,"Wiz-goal.lev") "Wiz-goal.lev"; read 'File' (1163,"Wiz-loca.lev") "Wiz-loca.lev"; read 'File' (1164,"Wiz-strt.lev") "Wiz-strt.lev"; #else read 'File' (1000,"cmdhelp") ":dat:cmdhelp"; read 'File' (1001,"help") ":dat:help"; read 'File' (1002,"hh") ":dat:hh"; read 'File' (1003,"history") ":dat:history"; read 'File' (1004,"license") ":dat:license"; read 'File' (1005,"MacHelp") ":sys:mac:MacHelp"; read 'File' (1006,"News") ":sys:mac:News"; read 'File' (1007,"opthelp") ":dat:opthelp"; read 'File' (1008,"wizhelp") ":dat:wizhelp"; read 'File' (1009,"air.lev") ":lib:air.lev"; read 'File' (1010,"asmodeus.lev") ":lib:asmodeus.lev"; read 'File' (1011,"astral.lev") ":lib:astral.lev"; read 'File' (1012,"baalz.lev") ":lib:baalz.lev"; read 'File' (1013,"bigrm-1.lev") ":lib:bigrm-1.lev"; read 'File' (1014,"bigrm-2.lev") ":lib:bigrm-2.lev"; read 'File' (1015,"bigrm-3.lev") ":lib:bigrm-3.lev"; read 'File' (1016,"bigrm-4.lev") ":lib:bigrm-4.lev"; read 'File' (1017,"bigrm-5.lev") ":lib:bigrm-5.lev"; read 'File' (1018,"castle.lev") ":lib:castle.lev"; read 'File' (1019,"data") ":lib:data"; read 'File' (1020,"dungeon") ":lib:dungeon"; read 'File' (1021,"earth.lev") ":lib:earth.lev"; read 'File' (1022,"fakewiz1.lev") ":lib:fakewiz1.lev"; read 'File' (1023,"fakewiz2.lev") ":lib:fakewiz2.lev"; read 'File' (1024,"fire.lev") ":lib:fire.lev"; read 'File' (1025,"juiblex.lev") ":lib:juiblex.lev"; read 'File' (1026,"knox.lev") ":lib:knox.lev"; read 'File' (1027,"medusa-1.lev") ":lib:medusa-1.lev"; read 'File' (1028,"medusa-2.lev") ":lib:medusa-2.lev"; read 'File' (1029,"minefill.lev") ":lib:minefill.lev"; read 'File' (1030,"minend-1.lev") ":lib:minend-1.lev"; read 'File' (1031,"minend-2.lev") ":lib:minend-2.lev"; read 'File' (1032,"minend-3.lev") ":lib:minend-3.lev"; read 'File' (1034,"minetn-1.lev") ":lib:minetn-1.lev"; read 'File' (1035,"minetn-2.lev") ":lib:minetn-2.lev"; read 'File' (1036,"minetn-3.lev") ":lib:minetn-3.lev"; read 'File' (1037,"minetn-4.lev") ":lib:minetn-4.lev"; read 'File' (1038,"minetn-5.lev") ":lib:minetn-5.lev"; read 'File' (1039,"minetn-6.lev") ":lib:minetn-6.lev"; read 'File' (1040,"minetn-7.lev") ":lib:minetn-7.lev"; read 'File' (1041,"options") ":lib:options"; read 'File' (1042,"oracle.lev") ":lib:oracle.lev"; read 'File' (1043,"oracles") ":lib:oracles"; read 'File' (1044,"orcus.lev") ":lib:orcus.lev"; read 'File' (1045,"quest.dat") ":lib:quest.dat"; read 'File' (1046,"rumors") ":lib:rumors"; read 'File' (1047,"sanctum.lev") ":lib:sanctum.lev"; read 'File' (1048,"soko1-1.lev") ":lib:soko1-1.lev"; read 'File' (1049,"soko1-2.lev") ":lib:soko1-2.lev"; read 'File' (1050,"soko2-1.lev") ":lib:soko2-1.lev"; read 'File' (1051,"soko2-2.lev") ":lib:soko2-2.lev"; read 'File' (1052,"soko3-1.lev") ":lib:soko3-1.lev"; read 'File' (1053,"soko3-2.lev") ":lib:soko3-2.lev"; read 'File' (1054,"soko4-1.lev") ":lib:soko4-1.lev"; read 'File' (1055,"soko4-2.lev") ":lib:soko4-2.lev"; read 'File' (1056,"tower1.lev") ":lib:tower1.lev"; read 'File' (1057,"tower2.lev") ":lib:tower2.lev"; read 'File' (1058,"tower3.lev") ":lib:tower3.lev"; read 'File' (1059,"valley.lev") ":lib:valley.lev"; read 'File' (1060,"water.lev") ":lib:water.lev"; read 'File' (1061,"wizard1.lev") ":lib:wizard1.lev"; read 'File' (1062,"wizard2.lev") ":lib:wizard2.lev"; read 'File' (1063,"wizard3.lev") ":lib:wizard3.lev"; read 'File' (1100,"Arc-fila.lev") ":lib:Arc-fila.lev"; read 'File' (1101,"Arc-filb.lev") ":lib:Arc-filb.lev"; read 'File' (1102,"Arc-goal.lev") ":lib:Arc-goal.lev"; read 'File' (1103,"Arc-loca.lev") ":lib:Arc-loca.lev"; read 'File' (1104,"Arc-strt.lev") ":lib:Arc-strt.lev"; read 'File' (1105,"Bar-fila.lev") ":lib:Bar-fila.lev"; read 'File' (1106,"Bar-filb.lev") ":lib:Bar-filb.lev"; read 'File' (1107,"Bar-goal.lev") ":lib:Bar-goal.lev"; read 'File' (1108,"Bar-loca.lev") ":lib:Bar-loca.lev"; read 'File' (1109,"Bar-strt.lev") ":lib:Bar-strt.lev"; read 'File' (1110,"Cav-fila.lev") ":lib:Cav-fila.lev"; read 'File' (1111,"Cav-filb.lev") ":lib:Cav-filb.lev"; read 'File' (1112,"Cav-goal.lev") ":lib:Cav-goal.lev"; read 'File' (1113,"Cav-loca.lev") ":lib:Cav-loca.lev"; read 'File' (1114,"Cav-strt.lev") ":lib:Cav-strt.lev"; read 'File' (1115,"Hea-fila.lev") ":lib:Hea-fila.lev"; read 'File' (1116,"Hea-filb.lev") ":lib:Hea-filb.lev"; read 'File' (1117,"Hea-goal.lev") ":lib:Hea-goal.lev"; read 'File' (1118,"Hea-loca.lev") ":lib:Hea-loca.lev"; read 'File' (1119,"Hea-strt.lev") ":lib:Hea-strt.lev"; read 'File' (1120,"Kni-fila.lev") ":lib:Kni-fila.lev"; read 'File' (1121,"Kni-filb.lev") ":lib:Kni-filb.lev"; read 'File' (1122,"Kni-goal.lev") ":lib:Kni-goal.lev"; read 'File' (1123,"Kni-loca.lev") ":lib:Kni-loca.lev"; read 'File' (1124,"Kni-strt.lev") ":lib:Kni-strt.lev"; read 'File' (1125,"Mon-fila.lev") ":lib:Mon-fila.lev"; read 'File' (1126,"Mon-filb.lev") ":lib:Mon-filb.lev"; read 'File' (1127,"Mon-goal.lev") ":lib:Mon-goal.lev"; read 'File' (1128,"Mon-loca.lev") ":lib:Mon-loca.lev"; read 'File' (1129,"Mon-strt.lev") ":lib:Mon-strt.lev"; read 'File' (1130,"Pri-fila.lev") ":lib:Pri-fila.lev"; read 'File' (1131,"Pri-filb.lev") ":lib:Pri-filb.lev"; read 'File' (1132,"Pri-goal.lev") ":lib:Pri-goal.lev"; read 'File' (1133,"Pri-loca.lev") ":lib:Pri-loca.lev"; read 'File' (1134,"Pri-strt.lev") ":lib:Pri-strt.lev"; read 'File' (1135,"Ran-fila.lev") ":lib:Ran-fila.lev"; read 'File' (1136,"Ran-filb.lev") ":lib:Ran-filb.lev"; read 'File' (1137,"Ran-goal.lev") ":lib:Ran-goal.lev"; read 'File' (1138,"Ran-loca.lev") ":lib:Ran-loca.lev"; read 'File' (1139,"Ran-strt.lev") ":lib:Ran-strt.lev"; read 'File' (1140,"Rog-fila.lev") ":lib:Rog-fila.lev"; read 'File' (1141,"Rog-filb.lev") ":lib:Rog-filb.lev"; read 'File' (1142,"Rog-goal.lev") ":lib:Rog-goal.lev"; read 'File' (1143,"Rog-loca.lev") ":lib:Rog-loca.lev"; read 'File' (1144,"Rog-strt.lev") ":lib:Rog-strt.lev"; read 'File' (1145,"Sam-fila.lev") ":lib:Sam-fila.lev"; read 'File' (1146,"Sam-filb.lev") ":lib:Sam-filb.lev"; read 'File' (1147,"Sam-goal.lev") ":lib:Sam-goal.lev"; read 'File' (1148,"Sam-loca.lev") ":lib:Sam-loca.lev"; read 'File' (1149,"Sam-strt.lev") ":lib:Sam-strt.lev"; read 'File' (1150,"Tou-fila.lev") ":lib:Tou-fila.lev"; read 'File' (1151,"Tou-filb.lev") ":lib:Tou-filb.lev"; read 'File' (1152,"Tou-goal.lev") ":lib:Tou-goal.lev"; read 'File' (1153,"Tou-loca.lev") ":lib:Tou-loca.lev"; read 'File' (1154,"Tou-strt.lev") ":lib:Tou-strt.lev"; read 'File' (1155,"Val-fila.lev") ":lib:Val-fila.lev"; read 'File' (1156,"Val-filb.lev") ":lib:Val-filb.lev"; read 'File' (1157,"Val-goal.lev") ":lib:Val-goal.lev"; read 'File' (1158,"Val-loca.lev") ":lib:Val-loca.lev"; read 'File' (1159,"Val-strt.lev") ":lib:Val-strt.lev"; read 'File' (1160,"Wiz-fila.lev") ":lib:Wiz-fila.lev"; read 'File' (1161,"Wiz-filb.lev") ":lib:Wiz-filb.lev"; read 'File' (1162,"Wiz-goal.lev") ":lib:Wiz-goal.lev"; read 'File' (1163,"Wiz-loca.lev") ":lib:Wiz-loca.lev"; read 'File' (1164,"Wiz-strt.lev") ":lib:Wiz-strt.lev"; #endif nethack-3.6.0/sys/mac/Install.mw0000664000076400007660000002222412536476415015505 0ustar paxedpaxedBuilding a PPC NetHack 3.6 with the Metrowerks compilers You must be familiar with the Metrowerks compiler and know how to construct projects. The NetHack source may come with the four pre-made projects that are needed to build NetHack and the files it needs. These four projects are in :sys:mac and are MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u. If you do not have them, or wish to construct them yourself, see the section "Project Contents" below. 1. Move the projects MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u to the top level of the NetHack tree. If you are building your own, create each project as needed, in the order given below. 2. Create a folder "lib" in the top level. This is where the files used by NetHack will be deposited by MakeDefs, DgnComp, and LevComp. 3. Build and run MakeDefs. You will be presented with a list of options. Initially choose them all (the default). Later you may wish to only run a few of them. The options are "odemvpqrhz", each of which makes a file: -o creates :include:onames.h -p creates :include:pm.h -z creates :src:vis_tab.c -m creates :src:monstr.c -e creates :dat:dundeon.pdf -v creates :lib:options -d creates :lib:data -r creates :lib:rumors -h creates :lib:oracles -q creates :lib:quest.dat 4. If you are _not_ using DLB, follow these directions. As of v3.3, DLB is ON for the Mac. Copy the following files. You may want to change News or NHDeflts. a. copy ':sys:mac:MacHelp' to ':lib:MacHelp' b. copy ':sys:mac:News' to ':lib:News' c. copy ':sys:mac:NHDeflts' to ':lib:NetHack Defaults' d. copy ':dat:cmdhelp' to ':lib:cmdhelp' e. copy ':dat:help' to ':lib:help' f. copy ':dat:hh' to 'lib:hh' g. copy ':dat:history' to ':lib:history' h. copy ':dat:license' to ':lib:license' i. copy ':dat:opthelp' to ':lib:opthelp' j. copy ':dat:wizhelp' to ':lib:wizhelp' 5. Create an empty file, ':lib:record' 6. Build and run DgnComp. This will create a file "dungeon" in the lib directory. 7. Build and run LevComp. This will build the level files (*.lev) in the lib directory. 8. Build NetHack. Move NetHack in the lib directory. ------------------------ Building NetHack with MetroWerks IDE 1.x (DR7-DR10, DR11 was never used) To build NetHack, you will need to create four projects at the top level of the NetHack directory tree. These four projects are MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u. The projects don't have to end in ".u", but you should append some form of ".XXX" to the end of the project's name to distinguish the project from the executable that it produces. The files and libraries to include in these projects are listed in the "Project Contents" section below. You must create and run Makedefs before creating NetHack because MakeDefs will create files used by NetHack. Use the MacOS C/C++ template for each of the projects. The libraries included will be overkill for all the projects (e.g. the C++ libraries are not needed). Add the .c and resource files as indicated below. Unless otherwise noted, the projects can use the default preferences: Font The tabbing on all non-mac files is 8. All mac files have a tab of 4. PPC Processor All projects must have the same alignment to build a consistent NetHack. To share save files with 68K, the alignments must match for their projects, as well. Turn on Global Optimization (official version is compiled with level 1). If you don't turn it on, some files may not compile because of register overflow. [NetHack only] PPC Project Set name to Other settings [NetHack only] creator: nh31 preferred heap size:2500 minimum heap size: 2000 stack size: 128 [PPC only] The SIOUX library may be replaced with console.stubs.c for the NetHack project. NOTE: As NetHack 3.3, you must turn on OLDROUTINENAMES -- so you can't use the default pre-compiled header. You should either remove it from the preferences or insert another precompiled header that has this define off. ------------------------ Building NetHack with MetroWerks IDE 2.0. This is for building a PowerPC version only. This doesn't take advantage of the IDE's subprojects. These will be investigated later. MakeDefs.u, DgnComp.u, LevComp.u: Select ANSI C Console PPC. Settings: PPC Target + Change File Name to MakeDefs, DgnComp, or LevComp respectively. C/C++ Language + Turn off ANSI strict, ANSI Keywords Only, Expand Trigraphs PPC Processor + Turn on global optimization (at least to level 1) NetHack.u: Basic ToolBox PPC PPC Target + Change File Name to NetHack. Other settings creator: nh31 preferred heap size:2500 minimum heap size: 2000 stack size: 128 [PPC only] C/C++ Language + Options ANSI strict, ANSI Keywords Only, Expand Trigraphs are already turned off, so you don't have to do anything. PPC Processor + Turn on global optimization (at least to level 1) ------------------------ Creating projects for NetHack with MetroWerks IDE 3.3 (Pro 4) This is what I changed from the default settings when creating a 68K version. Some of the settings may not be necessary. For example, NetHack doesn't use floating point, so I didn't have to check 8 byte doubles. Some are interrelated. For example, the codegen and the Math and MSL libraries used. For MakeDefs.u, DgnComp.u, LevComp.u: 1. Select File>>New Project...>>MacOS>>C_C++>>Standard Console>>Std C Console 68K 2. 68K Settings: Target Settings: + Set "Target Name" to {MakeDefs,DgnComp,LevComp}. 68K Target: + Set "File Name" to {MakeDefs,DgnComp,LevComp}. C/C++ Language: + Check Require Function Prototypes, uncheck everything else. + Clear "Prefix File". 68K Processor: + Set "Code Model" to Large. + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables, Far String Constants. Uncheck everything else. 3. Libraries 68K + Remove the C++ Library (it is not needed). + Change math library to MathLib68K Fa(4i_8d).Lib. + Change MSL C library to MSL C.68K Fa(4i_8d).Lib. Note: The actual libraries used must match the CodeGen options in 68K Processor. For NetHack.u: 1. Select File>>New Project...>>MacOS>>C_C++>>MacOS ToolBox>>MacOS ToolBox 68K 2. 68K Settings Target Settings: + Set "Target Name" to NetHack Debug and NetHack Final. 68K Target: + Set "File Name" to NetHack Debug and NetHack Final. + Set "Creator" to 'nh31'. + Set "Preferred Heap Size (k)" to 2500. + Set "Minimum Heap Size (k)" to 1500. C/C++ Language: + Check Require Function Prototypes, uncheck everything else. + Set "Prefix File" to LocalDefines.h. I use this header to define OLDROUTINENAMES because the pre-compiled header doesn't have it set any more. One of these days we'll fix up the code... 68K Processor: + Set "Code Model" to Large. + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables, Far String Constants. Uncheck everything else. 3. Libraries 68K + Remove the C++ Library (it is not needed). + Change math library to MathLib68K Fa(4i_8d).Lib. + Change MSL C library to MSL C.68K Fa(4i_8d).Lib. Note: The actual libraries used must match the CodeGen options in 68K Processor. For Recover.u: 1. Select File>>New Project...>>MacOS>>C_C++>>MacOS ToolBox>>MacOS ToolBox 68K 2. 68K Settings Target Settings: + Set "Target Name" to Recover Debug and Recover Final. 68K Target: + Set "File Name" to Recover Debug and Recover Final. + Set "Creator" to 'nhRc'. C/C++ Language: + Check Require Function Prototypes, uncheck everything else. + Set "Prefix File" to LocalDefines.h. I use this header to define OLDROUTINENAMES because the pre-compiled header doesn't have it set any more. One of these days we'll fix up the code... 68K Processor: + Set "Code Model" to Large. + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables, Far String Constants. Uncheck everything else. 3. Libraries 68K + Remove the C++ Library (it is not needed). + Change math library to MathLib68K Fa(4i_8d).Lib. + Change MSL C library to MSL C.68K Fa(4i_8d).Lib. Note: The actual libraries used must match the CodeGen options in 68K Processor. ------------------------ Project Contents: MakeDefs.u should contain the following source files: src objects.c monst.c util makedefs.c DgnComp.u should contain the following source files: src alloc.c sys:share dgn_lex.c dgn_yacc.c util dgn_main.c panic.c LevComp.u should contain the following source files: src alloc.c decl.c drawing.c monst.c objects.c sys:mac macerrs.c macfile.c sys:share lev_lex.c lev_yacc.c util lev_main.c panic.c NetHack.u should contain the following source files: src *.c [can do an add all] sys:mac *.c except mrecover.c NetHack.rsrc machelp.bh [for baloon help] Sound.rsrc [if you wish to have a few, crude sounds] Files.r [if you use DLB (on by default)] sys:share random.c win:tty *.c [can do an add all - termcap.c is not needed, but will compile to nothing] Note: src:monstr.c and src:vis_tab.c are created by MakeDefs -m and -s respectively. Recover.u should contain the following source files: sys:mac mrecover.c mrecover.rsrc nethack-3.6.0/sys/mac/MacHelp0000664000076400007660000001604712536476415014774 0ustar paxedpaxed Macintosh-specific help file for NetHack 3.6 The following are options, features, or concerns specific to the MacOS Classic port of NetHack. Bug reports, suggestions, comments, and so on, should be addressed to: To: nethack-bugs@nethack.org Subject: Mac NetHack 3.6 or you can use our on-line bug reporting form at http://www.nethack.org Please include your machine-type, system software version and other relevant information (i.e. system extensions, monitor, accelerators and so on). === Configuration of a playground NetHack is packaged in a Dungeon Folder which includes: NetHack - the application file itself. NetHack Defaults - text file for default option settings. License - licensing terms for nethack. Guidebook - description of the game in long format. Recover - the application to restore save files from crashed games. Previous versions had a large number of data files in the Dungeon Folder. These are now packaged as resources inside the application file and will no longer appear in the Dungeon Folder. During play another file type appears: Player level files (labelled "iName.n", i is a constant number, Name is the player name and n is the dungeon level). Two other types of files will appear in the Dungeon Folder as a result of playing NetHack: Bones files (of previously deceased players). Saved games (labelled "save/iName", i is a number, same as above, and Name is the player name). The following files or file types may be thrown away: logfile - if it becomes too large. A new one will be generated. Player level files _not_ belonging to a game in progress. Alternatively, these files may be processed by Recover, which may be able to restore a save file from the level files. Old bones files and saved games. === Resuming a saved game Double-click (or open) the desired saved game file or open NetHack and answer the "Who are you?" dialog with the player name of the saved game in the Dungeon Folder. === Windows The Dungeon Map and Message windows are the essential windows used during window-mode play. During tty-mode play there is only one window which displays the map, messages, lists and other info. For window-mode play, lists (e.g. the list of objects that may be wielded) and special info windows appear as needed. Windows may be closed in the normal ways (i.e. clicking their close box, choosing 'Close' from the File menu or typing the command equivalent for 'Close', cmd-W) and the list windows may also be dismissed by hitting the space bar (or Return or Enter Keys). Hitting the ESCape key will dismiss special windows without scrolling to the end. The command "Reposition" on the File menu may be used to restore the the startup sizes and locations of the various windows. The window positions are saved in a file labelled "NetHack Windows" in the appropriate preferences folder. === Default options The following options are specific to the Macintosh port: background: - black or white MACgraphics - use enhanced dungeon map symbols [TRUE] page_wait - display --MORE-- after messages [TRUE] Default options may be set by editing the NetHack Defaults text file (using SimpleText or your favorite editor). The following notation is used: OPTIONS=name:Arnold,time,!tombstone It should also be mentioned here that there are two graphic interface modes available: 'mac' and 'tty'. Choosing between these interfaces is accomplished by the option: window:mac - the default multi-window Macintosh(tm) interface. window:tty - traditional Unix(tm)-style TTY window interface. See option help (?f or ?g) for more details. === Movement by mouse The shape (direction) of the cursor over the Dungeon Map window, typically, indicates the direction that you desire to move in when the mouse is clicked. Modifier keys affect mouse-movement in the same way that they affect keyboard movement. Clicking on yourself means rest one turn and Shift-clicking on yourself means "open door" in the subsequently indicated direction. === Sounds Real sounds (resources) have been added for various instruments. The option "silent" [FALSE] controls whether or not a sound will be heard when an instrument is applied. === Explore and Debug Modes As of version 3.1.2, you can enter Explore (aka Discover) mode or Debug (aka Wizard) mode by choosing the appropriate entries on the 'Mode' popup-menu section of the "Who are you?" startup dialog. This same dialog allows you to specify your role, race, gender, alignment, and name, of course. Starting in Explore mode is essentially the same as playing in Regular mode except that if you are killed then you are given an opportunity to override your death. Because of this advantage, your Explore mode scores are not entered on the scoreboard record. You also get a wand of wishing in your starting inventory and can see your intrinsic abilities using the command ctl-X (also available on the 'Explore' submenu on the File menu). Starting in Debug mode is only intended for developers and others interested in characterizing bugs. Using this mode for other purposes will have confusing results and eliminate your enjoyment of the game! === Menus As of version 3.1.2, the menus have been reworked to provide access to all the NetHack commands and a special 'Kbd' menu was added to facilitate play using only the mouse. In some cases, a command may appear on more than one menu. In general, the commands have been grouped to appear on an appropriate menu: File - commands related to windows, start mode and play control. Help - info commands generally not related to a specific game (i.e. (key descriptions, version info, internal option editor). Info - commands that are generally game-specific (i.e. inventory related, describe features seen on the map or name things). Equip - commands related to things you might wield or wear. Act - commands for actions that you might do alone (i.e. wait, jump) or do with another dungeon denizen (i.e. pay, chat). Magic - commands for things that you might do with items (drop, eat, read) or spell-related. Bits - commands for things you might do to dungeon pieces (i.e. open door, loot chest, engrave on the floor, climb stairs). The key related to a command generally appears to the left of the menu entry for that command (i.e. w for wield and W for wear). A leftmost # denotes an extended command (without a related key) and a left cloverleaf or command symbol denotes a command that requires either a control or command key modifier (i.e. holding down the control or command key while hitting the related key). === The members of the Macintosh NetHack port team hope you enjoy this game. nethack-3.6.0/sys/mac/NHDeflts0000664000076400007660000001001012536476415015112 0ustar paxedpaxed# NetHack 3.6 NHDeflts $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ # Copyright (c) 2002 by Dean Luick, Mark Modrall, and Kevin Hugo # NetHack may be freely redistributed. See license for details. # # Default settings for the Macintosh port of NetHack. # Lines beginning with a `#' character are "comments" and are # ignored all the way to the end of the line. Using this # method, some of the lines below have been disabled so you # can see an example without having those options actually # set. Remove the `#' character to "uncomment" the line and # allow those options to take effect. ### Display ### # Uncomment for the traditional single-window tty interface #OPTIONS=win:tty # Boulder symbol #OPTIONS=boulder:0 # Color OPTIONS=color # Fonts #OPTIONS=font_map:NewHackFont,font_size_map:9 #OPTIONS=font_menu:geneva,font_size_menu:9 #OPTIONS=font_message:PSHackFont,font_size_message:9 #OPTIONS=font_status:monaco,font_size_status:9 #OPTIONS=font_text:geneva,font_size_text:9 # Don't make dark corridors look like lit corridors OPTIONS=!lit_corridor # Enable sound and beeps OPTIONS=sound,!silent ### Start-up and ending ### # Don't display the game introduction and new feature list at start #OPTIONS=!legacy,!news # Save game state periodically in case of crashes (recommended) OPTIONS=checkpoint # How to prompt for things after death #OPTIONS=disclose:+i na -v yg nc # Show tombstone and top scores at death OPTIONS=tombstone,scores:10t/3a/o # Show top ten list in its own window #OPTIONS=toptenwin ### User input and feedback ### # Choose between menus or text prompts # (traditional, combination, partial, or full) OPTIONS=menustyle:full # Extended (`#') commands by menu #OPTIONS=extmenu # Increase the number of message lines remembered #OPTIONS=msghistory:60 # Enable the number pad keys OPTIONS=number_pad # Pause for --more-- and make it boldface OPTIONS=page_wait,standout # Ask for confirmation with the #pray command OPTIONS=prayconfirm # Allow spacebar as rest command #OPTIONS=rest_on_space # Display experience, score, and time on status line OPTIONS=showexp,showscore,time # Turn off animations #OPTIONS=!sparkle # Display a little more information with some commands #OPTIONS=suppress_alert:3.3.0 OPTIONS=verbose ### Character ### # A Valkyrie... #OPTIONS=name:Brunhilda,role:Val # The old way works, too: #OPTIONS=name:Brunhilda-V # How about an Elven Ranger? #OPTIONS=name:Silwa,role:Ranger,race:Elf,gender:Male # Always a human female #OPTIONS=race:human,female # Or leave them commented out and the game will ask you ### Inventory ### # Automatically dig if wielding a pick #OPTIONS=autodig # Disable autopickup (toggle it with the `@' command) #OPTIONS=!autopickup,pickup_types:$* # Automatically fill the quiver #OPTIONS=autoquiver # Don't use fixed inventory letters OPTIONS=!fixinv,perm_invent,sortpack # What you want to call slime molds #OPTIONS=fruit:grape # Desired inventory display order #OPTIONS=packorder:)[( # How much you're willing to carry without confirmation #OPTIONS=pickup_burden:B # Put weapon in secondary slot when wielding another #OPTIONS=pushweapon ### Pets ### # What to call your starting pet, and its type #OPTIONS=dogname:Quinn,catname:Vladimir,horsename:Silver,pettype:dog # Don't intentionally attack your pets OPTIONS=confirm,!hilite_pet,safe_pet ### Unused options ### # Now obsolete # # background, large_font, popup_dialog, use_stone # Obsolete way to obtain reverse video; use at your own risk #OPTIONS=palette:000/c22/2c2/ca0/22c/a2a/2aa/ccc/999/f00/0f0/dd0/00f/d0d/0dd/fff/999/444/622/62c/-222 # Options used in tty window mode, but not mac window mode # # menu_..., msg_window, timed_delay, use_inverse, vary_msgcount # Options used by other ports but not Macintosh: # # align_message, align_status, ascii_map, BIOS, checkspace, # decgraphics, eight_bit_tty, ibmgraphics, ignintr, mail, # map_mode, null, player_selection, preload_tiles, rawio, # splash_screen, tiled_map, tile_..., videocolors, videoshades, # windowcolors # End-of-file nethack-3.6.0/sys/mac/NHrsrc.hqx0000664000076400007660000017561012467321052015450 0ustar paxedpaxed(This file must be converted with BinHex 4.0) :$%jPG%KKBfXZFR0bB`"58e*$8P0&4!%!N!I4j"fk!*!%!3#3!mRS!!$)k!!!"r` !N!30!"!!,3!`S!)!U!#3"4B!1!!R!1')'&0dE`a1CA4)B@0V,R*cFQ0UFfecFQ0 PER4c+f036(0`F'pM!!"58e*$8P0&4!%!!&-"%!#3%V0,SqB!N!CM'`!!b!%`!!% !N!J,Z3#3""8!N!AQ!9`!!3#3#!Zi!*!%&3"3!'i!qJ'i!!%!N!J(e!#3""8!8!" Z!2S"Z!!"!*!)"p-!N!39!&!!EJ$k!EJ!!3#3#!I5!*!%&3"3!'i!qJ'i!*!$(!% )!!J"5J$`!*!+"dePFh0KCf8i#J#3!a`",J!%!9)"bJ#3#JC6G'&dGA0V1!S!N!- @!(`!fJ$i!BS!N!3"!*!'66J+!*!$'J#q!!B"8!%b!*!%!3#3"34*EQC[)$J+!*! $)J!S!#J!M!#L!*!%!3#3"3e1G@aX)>EQ4[Gb!K1!S!N!-m$NjeE@*PFL"[CL" VCAPc6d019!8UN!9-8e4$"dYPH@0[C'9)3PP8"%0SBA*$5%&5"5U3"8a69%8!N!- J!#J!+!&+!Hi!N!S,4(9ZCf9[EL"0BA!i#J#3!b!!+!!S!+`"c!#3"!%!N!8,4'P KCfj[Fh4TBh-i#J#3!aB!!400B@-J6Q9d5'&MDb")C@a`b5mr!*!$J!#3#`rr!*! %r`$a!I!!N!2lm!m3(`#3!`qr$`%"m!#3!r[r%"$`!!$`$lrrmI!!$`rrqr!2!!! 2%"$r[`#3!`m"!I$lm!#3!r!3m!qr!*!$$`%2!2[`!*!$rr!!$lm!N!Ilm!#3"Jq r!*!(r`#3!i!!rj!%m!#3!r!!N!2r!*!$m!#3!rc`!!$`!*!$rrm!!2!!N!32!!$ `$r!!!!m!!2$rr`!!$`!!m2rr$rm2!!$`$r!!!!m!!2!!N!32!!$`$r!!!!m!!2$ `$`r`$`!!m2!2!!!2!!$`$r!!!!m!!2!!N!32!!$rN!B!N!4!!!!"`$)J14!G#!m )*qKIN!"$`%,J)R!41!iF!!i!"`!$!!!"`$2J1I!Gq!ri*rKrN!"r`(lJ2R!I1!i F!!i!"`!$!*!$3$rJ)$!J+#!m)!3Q"#m%,h3Q"#!%*J3TC#N%*J3J"$rm2q!rm$r i2r`rr$rm2r`rr$rm2r`rr$rm2r`rr$rm2r`!!!%!N!B2J!!!-'!!%#!3!"`3#!! 1%!J!$a!%!!H3!!3!!r!%!!(J"!!!m!3!-2[N!%mq'!"!(J!!3!m!!%!2J!"!%m! !3"(J!#!3m!!J%(J!%!Jm!!`B(J!$i!m!N!-(J!!!!m!!!!(J!*!$m!#3!hJ!N!- m!*!$(J#3!`i!N!-%!*!&$i!!!$rJ!"!rm!!F(rJ!$Kri!!mIr!!(Rr`!!rrm!!( rr!!!rr`!-2rm!(rq'!"rrJ!!Irm!!(rrJ!"rmm!!Ir(J!$r`m!!rm(J!(rJm!!r i(J!$i!m!N!-(J!!!!m!!!!(J!*!$m!#3!hJ!N!-m!*!$(J#3!`i!N!-%!!!"!!r rr!!)!!B!#!i&!!Q4")!*b)4!#1K%)!Ki4r!*2d!3#[b!%!SH!"!+&`!3#41!%!L *`"!)F1!3#!"`%!J!1"!)!"J3#'!!%!L3!!!3#@J!%!PTrK!)N!!!%!KJ!"!)!!! 3#'!!%!L3!!!3#3J!%!N*[j!!#*!!!"!)B!!3#!!!%!rrrr!2rr`!$rrq!!rrr`! 2rrq!$rrr`!rrrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr! 2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr! 2rrr`$rrrm!rrrr!2rrr`$rrrm!!!!J#3&rrrm!#3$2m3%"r`!*!($`#3!r%"N!- 2!*!($rm!!!m3N!6`!*!(qr!!$`'3"2!!N!Il[`!2%*!%(`#3"`qlm!m"N!32!*! )qlrr%*!%(`#3#!qlm3'3"!m!N!Rl[a#3""m!N!Er!!$rZr(rrr%2!*!&$a$rra$ l[r!!$r!!N!82!C!%$l[`!*!)$a#3"IZr!*!)$`'3"Iqlm!#3"`m3N!3I!2Zr!*! ($`'3"!m!$l[`!*!(m"#3!am!!2Zr!*!(m3'3!`m!!!qlm!#3"Jm3N!6`!!$l[`# 3"rm"!3r`!!!2Zr!!N!Irrr!!N!6l[`#3$Jqlm!#3$[Zr!*!1$l[`!*!1qlm!N!i 2Zr!!N!ll[`#3$Jqlm!#3$[[`!*!1$`#3!`)!N!2rN!N!N!I`!*!($r!!N!E`!*! $rr!!!!r2!*!'m!r`$a!I!!!2c2!!N!A`$lm!m3(`!!r-c`#3"I!!qr$`%"m!$mc -m!#3"2!!$lra!3m!$rq3!`#3"2!2!2[rram!N!32!*!%m2$rrlm!m!#3"!m!N!6 `m3%2qr!!N!82!*!%m2!3(`qr!*!&$`#3"2!2!3m!qr!!N!32!*!%m!$`%2!2[`# 3"!m!N!6`!!rr!!$lm!#3!`m!N!6`!*!&$lm!N!-2!*!%m!#3"[[`!!!2!*!%m!# 3"Jr`!!!2!*!%m!!2m!#3"`m!N!6`!2!2!*!($`#3"2!2$r$`!*!'$`#3"2!2$r$ `$rq3!r!!$`#3"2!!m!m!N!F2!*!%m!!2m!#3"`m!N!6`!*!+$`#3"2!!$r!!N!F 2!*!%m!$`$`#3"`m!N!6`$`!!m!#3"Jm!N!6`$`!!m!r`rj!$m!m!N!6`!2!2!*! ($`#3"2!!$r!!N!F2!*!%m!#3#Jm!N!6rN!`!N!8-!&S!EJ$Z!C)!J84%!*!$6!! #!*!&H!$'!)S"%!3#6dX!N!8+!%B!F`%3L"a$Eh9XC#"ZEh3JAM)JBQ9MBA9cC5" H-#iJ)&ia!*!&#J!8!#S!0+!#!*!%!3!2rr`!#!!'!!J1"3!*N35!#FL%3!MS4#! )H%I`#6p!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J!F"!)!$J3#!!B%!Q8aP! +95P3#P8T8!T9+9!+95P3#C6'8!J!!"!+C6'3!!U95P!+P8T3#T9+8!U95P!+C6' 3!!J!!"!2rrr`$rrm!!rrrJ!2rrm!$rrrJ!rrrm!2rrrJ$rrrm!rrrr!2rrr`$rr rm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rr rm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!!N!0!2q! J-#!S)$`J"#5N+U3UT#5N)!3T*#UN+U3T*#!%2r`ri$r`2rJrr$rm2r`rr$rm2r` rr$rm2r`rr$rm2r`rr!!!!J#3!rq3#3#3"r!!N!F2m!#3"[!!N!2rm!!!$mm!N!E `$r!2%"m!!!r-m!#3"I!2[`$a!I!!$mc2!*!&m!$lm2!3(`!2c-c`!*!%m!!2[r% "$`!2rj!$!*!%m!m!qrrr(`#3"!m!N!6`m2rr[`$`!*!%$`#3"2$a!3rlm!#3"3m !N!6`m"!I$lm!N!82!*!%m!m"$`$lm!#3"!m!N!6`!2!3m!qr!*!%$`#3"2!!$rm !!2[`!*!$$`#3"2!!N!82[`#3!`m!N!6`!*!'qr!!!!m!N!6`!*!'$r!!!!m!N!6 `$r!2$`$r!!r`$`m!N!6`m!q3"!$`m!q3!`#3"2$`$j!%!2$`$j!$!*!%m2!2N!3 !m2!2N!-!N!6`m!q3"!$`m!q3!`#3"2!2m!m2!2m!$r!2$`#3"2!!N!S2!*!%m2! 2m!m2!2m!$r!2!*!%m*!$$j!%!2$`$`m!N!6`N!-2N!3!m2!2$`#3"2#3!`q3"!$ `m!m2!*!%m*!$$j!%!2$`$`m!N!6`m!r`$`m!r`!2m!m!N!6`!*!+$`#3"2q3$!# 3"5)!!3#3"9!"4!"N!Ai%!Np,!*!&"J!i!%B"I)J#AM!!N!1!!2q3"2!!N!2`!*! $r`#3!r!!N!2mm!!!m!#3!rrr!!$`!*!%$`!!m!m!m2!2!!$`N!82!!$`N!82!!$ `$`$`m!m!!2!!N!32!!$`m!m!m!m!!2#3"3m!!2#3"3m!!2$`$`$`$`!!m!#3"!m !!2q3"J#3!`Q)N!!!N!6q!!B!!2rh!!B!#`1l!!N!!J#3!cm!N$2B!*!'&%%!N!8 T3!!!-!!!'J!!!KK!"@YBL8!(i$P%))"!"*A!F"`"`K3!&3!8))r!rr!"q!#3!h1 !)!#3"5!!!!jJ!3!3!*![F!"3L!)B"!%#J+)!"!))J!!!B!"")K0X!!!#+)!!!IL *3!@J+83JJ%!%P8"3&!&#&!!9!"3JMm$rm!d)!*!$*%"3![2!!!3J!`!*N!!'e6R X6#!!"FZF,l[ZF!!1Flc[Iqk2$'%BZmlc[aM'-ImD!J3!%"JK--!!N!-#!*!%UDl j&+%N#P#YA1q"kP%846SJP(a#4#@Ll%!#55!&DeL*3!@J+83JJ%!%P8"3&!&#&!! 9!"3JMm$rm"-!2J!fG&a!"I`J%KSJ")!*)26IeV+5U3!'2'*S3$'))*'-BaM#%BS -SEc'-Ba*'-94$3d""!!3)#!33!#3!`)!N!5UdIJ!!"J!N!-M'!+!!*!$4L5#SN! !!$-b!!+U!!!"q)P!"D!T4##!3!593&!8!8)8!"8!&##2`2r`)`!5!!QXBL!pr$q 4+L3-Z$P!PB95e#&a!!TS3Upi-BeI3HaM#-)3LJdK@XBaM!NBa*%8L!"rR2Gcr6* pChRfImBeM(kS%&1Hplh1Fj*M'$U1Fk-BaLlRiZI1MDXb3!&9B!9V@2P"rErTI## !3!6eIprhrhq9q"Ai&IL2`2rhC3I)r)L[iZh,r#"mb#"cI#RqPiqj5#'[ciUSM5$ %6SL!)Urp#2[6qJiK'FI4miNBa)SNL!#-BaLNBc4VQ-BjJNBe9%8%%&4M'-BaM&* rreI4M'-BaM@"2%M4MQEXMriCDC!!!Iq2IM'aMmIrN!5A-``c$#"q"rmRrLIrN!2 iT3+&&)LXBaV,r$q4+$q)I%!1N!#&&E8K)3!6+32`a*&iAd6dB`M#%BU0)4M'%BK *'05%4%J!M'%IT'-mDaM'-(*'054)U""hiaM'(rr5BaKqNBaM'-BdKq4)dBaL!3J %)I*0DeMj5rfpq$a!!N!%pIIrGrprJIP"r4Ai6rrm#+-#L45)G'-Gdr`J%KJJF(p !$T!!!&Db%J%!%LSL+-54###!K'-B`K'+M+%BaK'-549Y4)4)!*aK'#4M-QXBaM! +69988+J4*#FjcK#%%Q-B8T'-CcM'0BNZ5G'FBrmB"%"b5!(iL8SPT3!!3!*!"*3 8!93"3!!K3#88)%rrr!LM!T-8L#49%&2m2i!)*)!iJ!#3!)!k63`!%'(2h#FiMR8 !"(4mlhi1Mh4r',S1LiML4L6q12a[R[HMic&V&hR`mE5+LrkS$L2DeVA[Hp*M(pl ZFjVAZFla*%E1E')!i!"`DC9V@)P+*D8!!%!#3!58&!&8!8!!)8!P&#"2rr`(E3+ qjdKcYZ!pr#"rq5!!!)!!m!!3!*!$%#!!N!8"!*!-!3#3"L!!N!9!)!!!3#!!N!4 !F!*`!*!$J!#3#B!%!!C!!*!*!IL*5L@P!!"!!N!%P"3"9!&!!#&!*43J6rrm!#! !!!3!N!3Krq!!#5!!N!SJ!*!'!J#3'!1!`!!!3#!!N!-$J!!%!*!$!3#3#3F!N!- "J!#3#!9V@)P+*qF!!%!#3!58(!(F!F!!)8!P&#"2rr`!N!3%!*!%3!#3!`M!!*" +!3!%!!N!$J!6!"J!'J!G!#!!*3!U!#`!-3!b!$B!1`!p!%)!4`"-!&%!9J"E!'! !C3"Q!'J!D`"`!(-!H!"p!))!K`#-!*%!PJ#E!+!!T3#S!+d!XJ#h!,`!`3$'!-X !d!$9!0S!h`$N!1N!lJ$c!2J!r3$r!3-""3%)!3i"%!%9!4S"(`%N!5N",3%b!6F "1!%l!8!"3J&(!8`"83&@!9X"B!&P!@N"EJ&c!AJ"I3'#!BF"LJ',!Bi"N`'6!CJ "R3'L!DF"V!'a!EB"Z`(!!F8"bJ(0!G!"dJ(A!G`"i3(Q!HX"m!(e!IS"r`)%!JN #$J)6!KJ#(3)L!LF#,!)a!M-#1!)p!N)#4`*,!Nm#9!*C!Pi#C!*U!QX#F!*e!RS #I`+%!S8#L3+0!T)#P`+E!U!#S`+S!Ud#XJ+f!VS#[3,$!XN#c!,5!YJ#f`,I!Z- #j`,Y![-#p`,p!j!$#3-2!a8$'`-I!b)$*3-T!bm$03-j!c`$3J0)!dX$6J08!eS $A`0P!fS$E`0e!hS$J!1&!iS$M`18!jN$R`1P!kX$X31f!lN$[!1r!m-$b!20!p% $eJ2A!p`$i!2N!qF$l3!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B !"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!D3!`)'!3B!"J!'!!B!"J)'!3B #"J!'!!B""J!'!JB""J!'!JB!"J!'!!B!"J!'!!B!"J!'!JB""J%'!!B""J!'!!B !"J!'!!B!"J!'!!B!"J!'!3B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B !"J!'!JB""J)'!3B!"J%'!!B!"J!'!!B!"J%'!!B!"J)'!!B!"J%'!!B!"J!'!!B !"J!'!!B""J!'!!B!"J!'!!B!"J)'!JB""J!'!*!$"J!'!!B!"J!'!!B!"J!'!!B !"J!'!3B""J%'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B #"J!'!!B!"J!'!3B""J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B !"J)'!!B!"J!'!!B!"J-'!!B!"J-'!!B!"J-'!JB#"J)'!!B!"J)'!!B!"J!'!!B !"J!'!JB$"J-'!JB!"J!'!!B$"J!'!!B!"J-'!!B!"J!'!!B!"J!'!!B!"J!'!!B !"J!'!!B!"J!'!!B!"J!'!!B""J%'!`B!"J!'!!B""J!'!JB!"J!'!!B""J!'rrm !!![HN!!!N!6r!!F!!2rp!!F!$`6P!!`!!`#3!d)!N$`i!*!-"S!!N!99UeBL8!( i$P%)%!)!#)T`"`"`!F%&!!#N!!S)%2i$rrJ!N!dJ!*"!"84!!*!%#P!!!!`!!!X !N!-JJ!!!!IiL8!&S#P%)%!)!#)T3"3"3!8%&!!#N!!S)%2i$rrJ!N!N$`!!!)!! !#Q!!!"!!$!#3(("`!*!3(!#3"!B!N!4%J!#3#"!!N!BJJ!"9UeBL8!&S#P%)%!) !#)T3"3"3!8%&!!#N!!S)%2i$rrJ!N!8i!"J!p#!!!#!!!!f3!!$915a5)!!#jFi AcIFi!!(!1mlhrZM`aK',[1mlmBaM(mJ5!)%!"!B)6!#3#5TVJ#)!L3%!J+Fli(X !JL!1L!dI%%L%f,h%!#++!!!"rL*3!@J+83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2 rq!li2J!!%FiJ!I`J!#!J!`!j)(hIeV*5U!!$(M%d%"M%##)J4M'-)4LJbKZ-BaM %NBaM%-J9!%%!"!J)6$!!N!5!!*!$+V4845K*!T4,@-B!T*4&%9')%+L3!*%*D-B N!#55!&@V9L*3!@J+83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2rq"&))J!ENM%J"I` J"%`J")!T6d698Y*KF3!&&#&8)"M%%"![4M'-)3LJdKA-BaM!NBaM%-3BJ!%!"!J )""!!N!5!!*!$+J4!!!!'!*!$#-B!S!#3!a'*%IL3!!!!$-BJ!!JJ!!!"rL*3!@J +83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2rqh&!%!!N1M%3"I`r)T)N")!Trd5&-G3 KF3!&0#DA[#G'TmK3ap#-)3LJiK'XBaM!NBa9%833!"rR2Gcr6*pjhRfGdBeM(kS %)ZHplh1Fj*M'$U1Fk-BaLj!!5,RcSfV'*!!@5PT9UeBq8(p[qPm)%!)!#2TIrIr IrhrP2i#Rq!Tr%2i$rrb54mMm4%BaH"hm)#&5)%Xi)!p%MjL))Dr!#94"q'*)aX! %P[i`MldrS-)4R(dI1*'-5+*#%!!M'-BT'-dDaM'1BT'094&*"#-BaM'-Ba5BapA mBaM'-Bejra)dBjQpa2rTQU8!!IrMhiaXBr(rN!@,aM"JaJ`3(m"rr%IrL2q3"2b 53S8N4%IaMZ[m2rS`2l"m)!p%K498)5%2LC5"%'*)[#I)PXB`M#%BS1)4M'%BK*' -9%4#%!!M'%IT'-iDaM'-A*'054)U"#2iaM'(rr5IrKHNBaM'-Bd35")dBaL!#)" "+d,9UeBq8[p[IJm3!#)!#2Tqrr[IrhrJ2j3(r3Tr#2rrr!0a3SNN4%BaM@[m)#3 4)%Kq)!p%!"@bS3%!%48"%'*)K"!3&mB`M#%BU0)4M'%BK*'0BNK"%!!M'%B*'-d DaM'-!T'0543U"#-)aM'%)35BaK5NBaM'-Bd554)dBaMrm)"#Id+!!IiL8SPT3!! 3!#)!#)S#J!T3!8!!""3!43S)#2rrr!!43T%N4%BUMZ[m2b$a*,"pS!p%J&Da%J! 384B4&'*)LSJJN!"'-B`K'+M+%BaK'-549Z*)34!!*aM'+4M-QXBaM#+6998B+J4 R'FjcM'%8Q-B9T'-CcM'08NZ5G'FBJ"%!"!UP9DY@)P+*D8!!%!!L!!L+!S!+8!& !!!38!%8+#!Mrrr`!%8+M*-3k+SJVr#!(%-!!1'!!4)!k6T)!%'$RlK1F4c+!!)p (c[IJk2G(mBZJk,L1*'*2`*!!Ia[R2FMic&V&hR`FE5+LrkS$QZDeVA1Hj*M(lVZ FjVAZFla*%E1E')!1!!m+@J!"rL*5L@P!!"!!)J!)LJ+!#P!"3!!%&!"&#JJ)rrr m!"C#[XG#%GY`(IrJq"!!N!-J!(d!%!!-!"!J!*!'J!#3$%!!N!9`m!#3"4!)!!! 3#!#3""!F!3#3"#!!N!NJ!3!"%!#3#9@V9L*5L@P!!"!!)J!)LJ+!#P!"3!!%&!" &#JJ)rrrm!"!!!!3!%!!!%IJ!!"!!N!XJ!*!'!3#3$5!!N!X"%!J!!"!)!*!$!4! !!3#3"#!!N!NJ!!!"i!#3#J(q)P+*D8!!%!!L!!L+!S!+8!&!!!38!%8+#!Mrrr` !N!3%!$J!!"!!N!-3!*!Yi$!!N!MJ!!)!N!4!!*!)!F!!N!e9UeBL8SRj`!!3!#) !#)S$J!j`!F!!""3!43S)#2rrr!#3$4!!N%X"!!3!#3!1!"-!'3!D!"d!)!!P!#S !,!!a!$)!0`!m!$i!3`")!%d!8J"A!&`!B3"Q!'F!D3"Y!()!GJ"l!)%!KJ#,!*! !!*8!QJ#I!+3!U3#X!,%!YJ#l!-!!a3$+!-m!e!$C!0i!i`$S!1d!mJ$h!2`"N!- %!3N"$!%4!4J"'J%I!53"+3%Z!6-"0`%m!8%"3J&&!8S"6!&4!9B"@`&J!@8"DJ& [!A-"H!&p!B)"K`'-!C%"P!'9!CJ"R3'G!D)"T`'X!E%"YJ'l!F!"a3(+!Fm"e!( A!GS"h!(K!HB"k`(`!I8"qJ(r!J3##3)1!K-#'!)G!L)#*`)X!M%#0J)l!Md#3J* (!N`#83*@!PX#B!*P!QS#F!*f!RF#I!+"!SJ#M`+@!TF#Q`+I!U3#U3+Y!V)#Y3+ k!Vm#a!,)!X`#d!,A!Yi#iJ,T![!#p!,j![i$N!-+!a%$&J-G!b3$+`-b!cN$3!0 &!dN$6305!eN$B!0N!fJ$E`0f!hS$IJ1&!iX$N!!$P31D!jm$T31U!l%$YJ1l!m! $a32+!mm$e32E!q!$j32S!qX$l`2c!rJ$r33""!B%"`3-""!%&!3B""J%(`!(!!F !"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F !"`!(!!F!"`!(!!F!"`-(!JF""`%(!3F!"`-(!JF#"`%(!3F#"`%(!`F""`%(!JF ""`%(!3F""`%(!3F""`%(!`F#"`%(!3F#"`%(!!F""`%(!3F""`%(!3F""`%(!JF ""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!JF""`)(!3F!"`-(!3F ""`%(!3F""`)(!3F""`-(!3F""`)(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F ""`)(!`F#"`%(!!!""`%(!3F""`%(!3F""`%(!3F""`%(!JF#"`)(!3F""`%(!3F ""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F$"`%(!3F""`%(!3F""`%(!3F ""`%(!3F$"`%(!3F!"`!(!!F$"`!(!!F!"`!(!!F!"`)(!!F!"`!(!!F!"`-(!!F !"`-(!!F!"`-(!JF#"`)(!!F!"`)(!!F!"`!(!!F!"`!(!JF$"`-(!JF!"`!(!!F $"`!(!!F!"`-(!!F""`%(!3F""`%(!3F""`!(!3F""`%(!3F""`%(!3F""`%(!3F #"`)(!`F!"`%(!3F""`%(!`F""`!(!!F""`!"!!Irr`#3!d)!m!#A!*![!3!"!!N !!%Z*!!`!!%Z-!*!$&J!+@APEDeae9QKAEeKX8f*8DP9Z8L`!N!-@!!TC@9Y,A&9 @5&G[@%a63P4+98j5,!#3!d*J!!#B!*![!3!"!!N!!$J*!!`!!$J-!!!)`T!!!*! %l`!+!!$rpJ!+!!`$C`!+!!)!N!-d!*!a!i"0!*!G(i(!!*!'F"`(!(!!N$T83*C 5J!!"J!#3%J+J!*!%&S&!!*!%J!"3&!8!8!#3#383!-$!!!#!!*!A!FB!N!i$J!1 !!!!*#"C!N3'3!&*%"54!6!!i!!(Ki!#3#4D"6J#3!`d!!&!8"3"3!!&93!!!$c` !hlRp*58!!,PhaI0pcJ!"MK21jrZM$')1AHGjhiaJaMp#J))!3-)6'!#3!`3!N!- &65%GqA43P@Q"#UCYT#UD3URb3d32FK)ALd!qGU!!L$2rP[P4!!#J#3!!9j3&!&! !!TC!)N!I`rM99NP'%K!"4iL0"!Ba""*4%M'84'--SajM'-BNM'$')b0!3J""!J% )!*!$"!#3!`9@)5-CM%!!N!Y5j%(9MFc+h!43L!3N9)NTGXpJJ$3!%35!A2B&JGJ !!UU)8!qI``L2dP##(j!!!88*&HJ+-D[SCUS`M%3M$5+YBaM'")a9+88L!"ZCfjq h,fjZHhmaJaRe3(+K&BaGhGhCQC[fjQCQQCP09$[eM5d+U$j3QU4#r*5*4ZaJ[NL J%lL%cF2mr`YJ!*!$LM"I``L&1EP5%Rcb441N(`R2%!5UUp#2G2m1)NeMk2R%LT8 3L4)!"QCP*P0-QCQFK5T8U5JJFU(9M'D3"@95QC!&38j(pEA0#SJ)r+JIJ55N5AD [i-PC2k&&5Aer$F2FN!!!!$m'-2r$#)!8CL)9%!*&)(iBNL%,k5Vq-)a%BidL$1- )d#5+LLL4%J!HBRdQ8ibCQCKP+P4*48$ri41-CT!$Brrp8TQ3"3&81qq0,-J!2T! !bU4#r+5*&UJ46fSLS6P5"3(GIP6rr!!!LM"r``J!9+C5%"!%484&'*)L""!R4M' 84'1-SJcM#XSNL3T%N3S!*QCK*P0-QCQB&53SUB9!M'-6M'D3"#)K8TQ3"3$NKF@ +%K!!%4#)"#3NT5N@U!T)5Q*"3LN&!&8!9)!!!!K5,jr$#)!j'BNJ!3`jqi6R%Fb J!4"(cZI$Sh4q$&d(4F4a#N5I#MmIQGNH8bbCERMLj#NAp8#-AI&cRGhGfGQG8TC QCRGh!%p%"E(Ki!!"(h+rrbGEk4Di'ckaS%%$j)F!93"6i!#3!b(SRm2i!"!!!-! "!*!()!!1!*!*!3#3"3''!*!%"!)!!!J3!*!$!31!!!J!N!8)!*!+1!#3#J3!!"q !!*!%!3#3"&F!F!#3"5!IrJ#3"J)!N!G!!*!A'!`!!!J3!*!$"J#3!a!!N!83!*! 9"!#3#!)!N!4`!*!'!F!!N%J"!!3!#3!1!"B!(3!H!#%!*!!T!#i!-!!d!$8!13! q!%!!43"+!%m!9!"C!&i!B`"S!'N!D`"Z!(-!GJ"k!)%!KJ#,!*!!!*8!Q3#G!+) !T`#S!+d!XJ#f!,d!`J$(!-`!d3$@!0X!i!$P!1S!m3$f!2X!r`'3!`8""`%+!4! "%J%@!4S"(J%L!5B"+J%Z!6)"0!%h!6X"23&%!8J"6!&3!93"@!&F!9m"B`&S!@m "G!&i!A`"I`'!!B-"L!')!Bd"NJ'A!CX"S!'P!DS"VJ'b!EB"ZJ'q!F)"aJ(+!Fi "dJ(@!GJ"fJ(G!H!"j!(S!H`"m!(d!IJ"r!)!!J3##!),!Jm#&!)C!Ki#)`)S!Ld #03)p!N8#4`*+!Nm#9`*H!Q-#D!*X!R!#G3*k!Ri#J`+*!Si#N3+9!TS#S3+S!Ui #XJ+c!VF#[J,"!XB#b`,4!Y8#f3,I!Z8#k3,[![8#r!-!!`B$#J-1!a!$%J-A!ai $)`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-a!cF $2J#3$2q3"JB'rj!'!!$rN"`!"rq3"J-$!3-""3%(!!B!#3!)!3-!"!!%!3F!"J% %!!8"!`%'!!B""J!'!!B!"J!'!!B!"J!'!!B#"!%%!38!"J%&!3B!#!%(!!B!"J! '!!8!"3!'!!B"!`!'!!B!"3!)!!B!"J!'!!B!"J!'!!B!"J!'!!J!"J!'!!8""!% '!33!"!!'!!-!"3!&!!8!"3!&!!3!"3!&!!-!"!!&!!-!#!!&!!8!"3!&!!8!"3! %!!8!"J!)!!B!"J!&!!3!!J!%!!B!N!-'!3F!"J!&!!B!"J!'!!8!"3!&!!8!"3! &!!8!"3!&!!8!"3!$!!-!"!!%!!8!"3!&!!8!"3!&!!8!"3!&!!8!"!!&!!B!"J! '!!B!"J!'!!N!#3!*!33!"!!'!!N!"`%+!!B!"3!&!!B!"J!&!!B!"`-)!J8""3! &!!J"#3!'!3B"!`!&!!J""3!'!3F!#!!)!3J!"J!(!`F!"J!*!!J!"3!(!3F#"`% %!33!"J!)!!B!#Iq3+!!'!!B!"`#3"!XQN!!!N!6[!!m!!2rd!!m!$`5C!!`!!`! "!$i!N$Y`!6)!N!3'!*!@!93!N!8IJ1!!N!S1!$J!N!X&!*!k+)J#6**!!!!*!*! G&S#J!*!($RcJ#J!S!*!)m!!!"3!%!!!`!!!%!*!G"``!N"%(!!#)!*!$"#%!f3# ))"N'L33$4))"!*!,!93!N!8@r+!!N!3-!!!+4+!+!#J!!!P+J!!$!I[!!!A46Rj K55!!"-6[`Ajhlc`!!2!!MjlcrhSB--)1,hchchq'$!Bar38!3)!#!`36$!#3"!) !N!3+Q4"alq,d+"+9CJ%%8UEE%)T9L%8VX!ai!mi!!(4D!(jk!!!4!-rrPX5RJ!! %J!L!!!TFS!S!+!!!%Nb!"%B"r#r`"GIeNT&)`!!*,4#$3)!``J!"#H#)BBS3KKJ a3ai`````L)B-"M%-KS!JJ!)%"!%%!*!%!J#3"!UQ%#)BB``J!*!0!8N5K!94(Ki Qi!#JK93!#J!N84EdU%!!N!-4!#!+8+!+!#J!!"+9!%!-!I`S%!@#P*5JKr)!#KB 4"8%!8-)%%3S45'#'%))B-N+Y-----!L'$%94&)3!$[1HlRfh&XeRHIGh4M%BaqU !+&))8``ZFjcR1FjcT5XjcR1M'-9,N!#"k9%K)59!!+#-!)5I4")4&T5`,Z1NJ"% !)!T3TrS!+1i!N!-3T&rer#J3"Br-D%#%`J!5&"-*II"23dJ)&1P2S)B3JKJd3Nd `````#)8558S84!!4M'-8MP-R-jM'1)T'-4M%+S!S8JK6$$'-BaM'-BaP,-BaM'- Ba693HrP5A-bN3"%JP95)4%4a%ADAX$%84)!MXP!+8+3EJ1m4!*!$!44rrI`S%!@ &"K#JK5qI%K3JN3-)N!$#%q3P+LKJKpkIq$K#$,$p$mm)K4+SLL4%!!q-)a5-8dB M'-B`JNBUT8453%5+$dX-,h[Hpm)aM'8SaM'-BaM%"6L(q9&5d)!"qIbN!r!r4*! !N8D@-#m8b2`K6&#Edlpiri-4!*!$IJarqI`S%!@!"5d8K!)!)K4!B3-)N!#q)!* &+LKJKK#''$4#$,$"$3#)K++T4%3N!"'-)r5-8iBM'-B`FN9+SN5+J%5+#%X--Ba M'-2rrq8SaM'-BaM%"4#(p9$Fd)!!)L$&9)K%44%4GTIS8I93KN%!L5M5#8["lar ri!!#$%2jr#J3"B!&8`L%!J!L&)"rJ`N3JK!%42IiB)B3KK`b3Ja``3b!L)5K%84 %*!!4M#-%M&0')aM'-!T&4%9&#S$rrJK($$'-BaM#%)3P+-BaM'-Ba!83Hr23dXb !!%)JK!#%K%85%4D8#&%'8B9"-ST2mrP+IbN3!*!$%44'(r`S%!8!&C-85!!!358 )J8-*%)3,k!)%'''+%)BF-8)-F-%X8)L%34)NK"3!%BaM&)a6*L-BaM#+6)4)aJU !J`BB4``aM'-BaM'-C5M'-BaR1F`&83AK85%K!!(m)B98!!4&*&%@R!54&&'!J8d &)!!"5J!T%3#3"+4)!I`S%!@!$ScL5!!J`-Ih!6ca$cP%%%(%(jlcm(SEd2i-,d$ d,`Ki34)Nr"4rMr1Hj(a6&L-AHI"aY)4)[qU!J`A[`[22HplhZFjcT5LjcR1DeV3 $[S3"GKiH!!#%2RJ$rq4kcp%@J!c1kik!J3(mN!!!!8S!+1i!N!4$`!(m,r!&!!3 !!$!!)!#3#%!!N!i)!*!'"J`!N!8)!J#3!d!J!*!%"!F!N!0!!*!'%!#3#J%!H!# 3#!&8!!"!!!!@J!#3"3%!N!3"5J!S!*!'3!!(i!!&!*!'3!#3#)!!N"b)!J#3!d! J!*!%4!#3"#!!N!BJ!*!CJ!!!&S!!N!8"!*!%!FS!+!#3"34!!*!%"3#3,(!-!*! *1!#3"%!!N"`"9!#3"4q!!*!&!J#3"3i!1!#3"31!!*!%"3#343%!"!!,!"!!&`! I!#!!)`!Q!#`!-3!c!$J!13!q!%3!4J"-!&)!@3"I!'8!D`"a!(F!H!"k!(i!J`# (!)d!P3#F!+)!U!#Z!,-!Z!#q!-3!a3$,!0%!eJ$G!1-!k3$[!28!q`'3!`J"$J% 9!4i")`%S!5d",`%d!6B"13&"!8-"5!&0!9)"9`&F!@!"C3&U!@`"E`&d!AB"I`' %!BN"MJ'6!CJ"R3'K!DB"U`'d!EN"[J($!FB"a`(+!G!"d!(A!Gi"j!(T!Hm"p3( l!J!#"3)+!Jm#&!)C!Ki#)`)S!Ld#-J)d!MB#13)m!N%#4J*,!P!#93*D!Pm#C!* T!Qi#F3*e!RS#J!+'!S`#NJ+C!U%#U3+b!V3#Y`+p!XF#c`,@!YX#h`,M!ZJ#l`, d![S$!3-'!`N$$J-6!aX$*!-V!c!$-3-f!ci$330(!di$9!0C!ei$C30X!h%$H!0 r!iJ$M!16!jJ$R31I!k%$TJ1Y!l)$[`1r!lm$[`1r!lm$[`1r!lm$[`1r!lm$[`1 r!lm$[`1r!lm$[`1r!lm$a32,!p8!!2rr!*!)rj!'#!MrN!B!!2q3*!3%!3-""3% *!3F"#3!*!3-""3%&!3J""`%%!3F"!`%(!3J$#!%)!3J"#!%)!3J"#!%)!3J"!`% %!3B""`%'!3J"#J%*!3J"#!%)!3F""`%)!3J#"3!(!3J""`%*!3J"#!%)!3J"#!% )!!J"#!%*!3X""`%(!3F""!%(!33""!!)!33""`%(!3F""`%(!3B""`%(!38""J% (!38"#`%(!3F""`%(!3B""`%'!3F""`%,!3F""`%(!38"!`%&!3J!!!%*!3N"#!% (!3J"#!%)!3F""`%(!3F""`%(!3F""`%(!3F""`)&!38""3%&!3F""`%(!3F""`% (!3F""`%(!3F""3%'!3F"#!%)!3J"#!%*!3S"#J%,!33""3%)!3`!#!!,!3F""J% '!3F"#3%(!3J"#3)+!38!"J!'!3S"#`!(!3J#"!%(!3S""3%)!3N"#!%)!JS!#!% *!JN"#!--!3X""J%*!3F""`%%!33""`%*!3J"$rq3+!)*!JN!#VEE!*!$4!#3#3J !$!"k!%%!HJ!-!!J!N"-)!!`!IJ"r!(i!$!!)!*!,"`!*!*!$4!#3%J(!!8!"3!G `!L!"3!#!!*!5!F!"`!(!"r!$i!(!!)!!#3!)!*!$4!#3#K!!-!"H!))!AJ!`!"! !N"-3!$!!IJ$q!(i!-!!3!*!+#!!'!*!$4!#3&4!!+3!A!!N!#3!I!*!9%!!j!"m !$`!2!"m!#`!,!*!$4!#3&!J!P!$S!*!!!*!!!2J!N"8)!*`!q!$`!2!!q!!!#`! %!*!$42J!N!!!N!!!k!#8!!J!N"Ai!2!!m!$i!*`!#!#3&J3!"!#3!d3!N!32m!J 3#"!)%!J3#"!)%!J3#"!)%!r`!*!)$r!Iq"L3%Kri$r!!N!8(!!F!N!0%!3!#J!4 !$Z!#J!+!!i!!N")"!!1!"m!2i!1!!i!$J!#3%`B!"`#3!d3!(`!*!!N!&`!T!"! !N"8I!!m!$`!I!$N!%!#3&33!#`#3!b!!-!!3!8)"l3!%!*!)#d4eEQGPEfiJ6@& `+!S!N!-f0DP6G'PMD(4TEQFJ6@&dD'9YBA4TFf0S)%0PER4bG@dX)%&YFh4PFQ4 KE5`J-6Ni0G!a1C!$!*!$J!$rN!6`!*!$m!#3!rm!N!2`!*!$r2!!!2!!N!2rr`! !m!#3"!m!!2!!N!32!!$`!2rr!!m!!2!2!3(`$`!!m2!Im"m2!!$`mI%2N!-!!2# 3!amI$`!!m2%2rr!2!!$`$a#3!`m!!2!!rrr`$`!!m!#3"!m!!2q3"J#3")!!rj! %m!#3!r!!N!2r!*!$m!#3!rc`!!$`!*!$rrm!!2!!N!32!!$`!2rr!!m!!2!2%"$ `$`!!m2(a$j!$!!$`N!-I(`m!!2$a!3%2$`!!m!m3%2!2!!$`$`ram!m!!2!2%"$ `$`!!m!$rr`!2!!$`!*!%$`!!rj!'!*!%3$rJ)$!J+#!m)!3J"#2%*#3TP#T8+P3 Tj#3%)q3J"$rm2q!rm$ri2r`rr$rm2r`rr$rm2r`rr$rm2r`rr$rm2r`!N!0!2q! J-#!S)$`J"#2%*#3U9#T8+"3N*#@N*#3Ma#!%2r`ri$r`2rJrr$rm2r`rr$rm2r` rr$rm2r`rr$rm2r`rr!!!!3!2rr`!#!!'!!J1"3!*N35!#FL%3!MS4#!)H%I`#6p !%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J!F"!)!$J3#!!B%!J!!"!)!!!3#!! !%!J$`"!)"#!3#!Q3!"!)#P!3#!T3%!J*i"!)"!!3#!2J%!J!!"!)!!!3#!!!%!r rrr!2rr`!$rrq!!rrr`!2rrq!$rrr`!rrrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!!!!3!2rr`!#!!'!!J 1"3!*N35!#FL%3!MS4#!)H%I`#6p!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J !F"!)!$J3#!!B%!L(`K!*@$83#@!0%!SXD*!!#Y+@N!!*8T83#%aN%!NJ#4!+d"D 3!!SAd*!!#5JT%!P)*4!)amB3#!!!%!rrrr!2rr`!$rrq!!rrr`!2rrq!$rrr`!r rrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!!!!J#3!rq3#3#3"r!!N!F2m!#3"[!!N!2rm!!!$mm!N!E`$r! 2%"m!!!r-m!#3"I!2[`$a!I!!$mc2!*!&m!$lm2!3(`!2c-c`!*!%m!!2[r%"$`! 2rj!$!*!%m!m!qrrr(`#3"!m!N!6`m2rr[`$`!*!%$`#3"2$a!3rlm!#3"3m!N!6 `m"!I$lm!N!82!*!%m!m"$`$lm!#3"!m!N!6`!2!3m!qr!*!%$`#3"2!!$rm!!2[ `!*!$$`#3"2!!N!82[`#3!`m!N!6`!*!'qr!!!!m!N!6`!*!'$r!!!!m!N!6`!*! +$`#3"2!!N!S2!*!%m!#3#Jm!N!6`!*!%rrm!N!32!*!%m!#3!`m"!I!!N!-2!*! %m!#3!r!Im"m!N!-2!*!%m!#3!r(a$`m!N!-2!*!%m!#3!r$`(am!N!-2!*!%m!# 3!r%2rr!!N!-2!*!%m!#3!`m3N!-!N!-2!*!%m!#3"2rrm!#3!`m!N!6`!*!+$`# 3"2!!N!S2!*!%m!#3#Jm!N!6rN!`!N!3#!*!$rj!*!*!(m!#3"`r`!*!'m!#3!rr `!!!2c`#3"[!2m!m3(`!!$mc`!*!&m!qr!2%"m!!2c-m!N!A`!2[`m"!I!!r-c2! !N!6`!!qrm3%2!!rrN!-!N!6`$`$lrrmI!*!%$`#3"2$`rrqr!2!!N!32!*!%m2% "$r[`!*!&$`#3"2$`%"m2[`#3"3m!N!6`$`%2!2[`!*!%$`#3"2!!m"$`$lm!N!3 2!*!%m!!2r`!!qr!!N!-2!*!%m!#3"3qr!*!$$`#3"2!!N!Elm!!!$`#3"2!!N!B 2m!!!$`#3"2!!m!!2rrm!!2!!$`#3"2!2(`r`%"$r$am!$`#3"2!2$r%"N!6r$`! 2!*!%m2!3m2m3(r$`%2!2!*!%m2(r$mcar-m2mI!2!*!%m!m2(mc`r-mI$`!2!*! %m!!2!Im"$r%2!!!2!*!%m!m!m"#3"2!2!!m!N!6`mIm2!C!$$`ram!m!N!6`m"! I(rrr(a!3m!m!N!6`$`(`m3%"m2%2!!m!N!6`$am!m"!3m!mI!!m!N!6`!2m!$rr r!!r`!!m!N!6`!*!+$`#3"2q3$!#3"3G"8&"-!*!'"e"548B!!3#3"!G%394"!!) !N!3(8d&@43!$!*!%"d*26N8!"!#3"$aZD$-a!*!$!8C548B!"!#3!i!!!3#"!!) !JJ!$!)-!"!#%5801)`!%!!!$k!!"!qN!!J2U!!-$k`!%!q`!N!-1!$i!6J#k!E) 6L3!%-!S!N!1&!)%!N!Mrrre2"%CTE'8+8Q9NFQ&h)%eKF!"5%3!-8(*PGQP[GA- J6A0R!&!4!!T5CA"[FfPdD@pZ!%i!!!%Y!*!%"e*PCh9XBA)!'mJ!$89ZG'9b)%9 iF'a[FQ8!!&J!!5d!N!3%8f&fC3"68`!",3#3"!44G@Pd!&&4!*!&5!##!*!)rj! $q`4&C'Pd"&9ZC'm!@J!!!5d!N!3$3h9d!&J!!!4$Eh"j!%-!!!93BA0dC3"@!!! &3faPBA)!N!LX!)-!N!Mrrrhr!dYLC!a$EfjdFQpX)%YPHA-!'mN!#e"eEQ0dG@& dD@pZ!"[+!!K#FQ&MDf9dF`!Eb`!&B5!Y)'d!'m`!"@iJ,5"k!"[0!!9")#dJ63! EcJ!&6L!Y)&S!'mm!"6!J,5!j!"[3!!%Y!*!%##KPFf0KF'8T!*!%"bKcF'&MC5N !N!3)+'4PE'9dC5N!N!3)+(*PG(9bELN!N!Kc!)3!N!MrN!2E"%KPE(!(6h"dD@p ZF`!!6`!",3#3"!4)C@a`!!!r!!a%CA0MFQPLC5",CAN!!#B!!5d!N!3(9Q9bFfP [EJ!!GJ!(5'PcG'pbH3!!9J!39Q9bFfP[EL"'C@&dGA*PF`!!)`#3"5S!J!#3#2q 3!rX"&!j"BQpeG#"1CA4)B@0Vb3#3"!%Y!*!)aJ#&!*!)rrrpl`4*EQC[$8PZGQ9 ZG'pbH5""E'`!!'N!%%PZGQ9ZG'pbH5"6C@aPBh3!!%N!"N&NDR9cG!!!)`!",3# 3"!P-EfpV)%4[Gfi!!$S!$%4PFf0bD@*P)%pZC3!!1`!04'9cBh*TBQ8J6@&ZH3! !,`!04'9cBh*TBQ8J9(*KF!!!AJ!",3#3"!a$B@aX)%e[ER0dCA)!!%-!#djKE@8 J6f*UC@0d!!!M!!Y%DA0MEhCPFQPPF`!!A!#3"EN!L!#3#2rrqpm&6@&RD@-*4(* [F#"*G'9Y!!"N!!Y%FQp`)&0PE'9MG!!!4!!'8'PMDh9`!!!X!!e8EfGRE'8JF'P MDh9`!!"!!!%Y!*!%!d9KG!!!C3!%8Q9KC!!!FJ!&8A9KCQB!!(%!!d4TF!!!)`! ",3#3"!Y-DA0d)&0`C@aXF`!!+`!+3f&cG#"6F'9XE!!!@J!$@Q&`!!"k!!C*ERC [Df8!!#-!!e*eBJ!!)`#3"EF!L3#3#2rrZlm%3QPdF`C6C@&bBfJ!!(-!#N0XEh0 P)%4[Eh)!!'-!#8p`C@iJ4'p[FJ!!E`!&3A"`E(N!!'%!"%YTBfX!4"%!!5d!N!3 '9@jdFQ&`!!!M!!9'Eh*MC3!!)`!%6'p[G!!!)`!",3#3"!G&EQGbBACP!!"&!!0 %DA!!!#-!!e0TG!!!)`!",3!!)`))3faTEA!J9A!!!$`!#N0XD@eL)%4[Gfi!!$i !N!@,!-S!N!MrN!3,F(9ZBh4eBA4TEfi#)#i!N!3#)#`!N!3#)$X!N!3#)$S!N!3 #)#%!N!3#)$m!N!3#)#X!N!3#)#d!N!3#)$d!N!3#)#-!N!3#)#3!N!3#)%!!N!3 #)#B!N!3#)#S!N!3#)(i!N!3#)&m!N!Ki!-X!N!MrN!3)BR*KBfYPG(-"@`#3"!& G!*!%!5J!N!3"+3#3"!&l!*!%!Ad!N!3"2!#3"!%q!*!%!9i!N!3"B!#3"!%R!*! %!5)!N!3"A!#3"!%[!*!%!A`!N!3"*3#3#'-!c!#3#2q3"!9K)#dJE3&K!*!%!@) !N!3"B`#3"!&N!*!%!@8!N!3"CJ#3"!&R!*!%!@J!N!3"D3#3"!&U!*!%!@X!N!3 "E!#3"!&Y!*!)B`$0!*!)rj!%"@iJ,5"k!@i!N!3"E`#3"!&`!*!%!A%!N!3"FJ# 3"!&c!*!%!A3!N!3"G3#3"!&f!*!%!AF!N!3"H!#3"!&j!*!%!AS!N!KM!-i!N!M rN!3&35!Y)%d"33#3"!&#!*!%!8-!N!3"4!#3"!&&!*!%!8B!N!3"4`#3"!&)!*! %!8N!N!3"5J#3"!&,!*!%!8`!N!3"63#3#'-!c`#3#2q3"!91)#dJ@J&1!*!%!8m !N!3"8!#3"!&4!*!%!9)!N!3"8`#3"!&8!*!%!98!N!3"9J#3"!&A!*!%!9J!N!3 "@3#3"!&D!*!)DJ$*!*!)rrrpr`aMEfjdFQpX)'YPHA-"BJ!a!!!"DJ!b!!!"EJ! c!!!"D!!d!!!"E!!f!!!"H3!h!!!"D`!i!!!"G3!j!!!",3#3"!&N!%3!!!&`!&! !!!&b!&)!!!&d!&3!N!C4!0!!N!MrN!3&-#!Y)$N"-!#3"!%a!*!%!6)!N!3"-`# 3"!%d!*!%!68!N!3"0J#3"!%h!*!%!6J!N!3"13#3#*%!b!#3#2q3"!ChDATKFQ3 +3A4dFQPLGA4PF`!!H!!04'9dC@0d)&9ZFf9PEJ!!C3!*4Qa[Eh)J6@&`!!"Q!"" (C@jPFQ&dC5"0EfjcG'9b!!"R!!K*C'9ZG'PQH3!!D3!*6'pMBA4TEfjc!!"[!!j -CACPE#"8C@aPF'pbG!!!GJ!%9fPcD!!!G`#3"9m!d3#3#2q3"!GMGA*bC@jd"PG PBA"[EJ!!+3!&3A*YEh)!!&X!"9*TEQGc!!!p!!C"EA9XCA3!!#)!"94[Efac!!! S!!4(EfaN!!!N!!C6F'9XE(-!!#X!N!8X!)!!#J#!!*!$J3#3!i)!N!1$!*!$K!# 3!i8!N!1'!*!$K`#3!iJ!N!1*!*!&,!$)!!S!b!#3!mN!N!2+!*!$b`#3!m`!N!2 0!*!$cJ#3!mm!N!23!*!$d3#3"C!!!!d4T6)`-5"$EfjdFQpX)%YPHA-3T6)`-L" 3G@jMG(9KG'P[EJfP-M!c)%*bB@0VCA4c#U8b-$3JB5!Y)'d+T6)`05"Z)#dJHJU P-M!f)%%J,5"0#U8b-$FJ6L!Y)&S+T6)`1#!`)#dJ13+P,3JET@9cBf&`C3FJTA0 `B@0P#!LPC'9XCA4P#!fPFQ9dGA*Z!*!$C3!0"`+PBh4X,@)(#U9MG'`YDJF1T@0 dE#eZ"`LPBh4X,@J($+9MG'`YE!FCT@0dE#ej"`ZPBh4X,@X(&D9MG'`YG3+P,3F %T@0dE#eN"a#PBh4X,A!(%U9MG'`YFJF8T@0dE#ed!*!$)J!3!5i",!%l!6S")3% r!5X",3%p!5-"*!&!!5B"+J&q!9m!N!-L!"!"@`&G!5J"+3&l!Ad"2!%q!9i"B!% R!5)"A!%[!A`"*3#3!a`!$3&K!@)"B`&N!@8"CJ&R!@J"D3&U!@X"E!&Y!*!$(!! 0!@i"E`&`!A%"FJ&c!A3"G3&f!AF"H!&j!AS!N!-F!!d"33&#!8-"4!&&!8B"4`& )!8N"5J&,!8`"63#3!a`!$3&1!8m"8!&4!9)"8`&8!98"9J&A!9J"@3&D!*!$&J! +!6!"-3%b!6-"0!%e!6B"0`%i!6N!N!0#!!J('+9MG'`YH!F&T@0dE#eP"`DPBh4 X,@B("k9MG'`YC`F*T@0dE#eT"`qPBh4X,@m(&U9MG'`YGJFAT@0dE#eh!*!$%!! (!5N"@`%p!5)"+!%N!5X!N!0,#c&cG#"YC@je)%P%4&G54!SM)'pQ)%e&6P9c6d0 19!8UN!9-8e4$"P*PFb"*4%4A8N3)8Q9cCA*fC@4'9e*%"5U3"8a69%8!N!-E!!J "6`+P,3%r!5B#T5d"GJ&@##0fCA*cD@pZ!*!$*J!-!@N"53FMB@4UGA0d!U8Y!6S "1`%[!9i#T5d"3`8MEQ&YC3&F!*!$0!!#!*!&C`%%!(X"9!3#6dX!N!8,!&%!@!& JL!4H-&ia!*!&#J!B!#S!1+!#!!%!N!0%!!-!N!9G!3i!F3&+"!*1E`#3"9d!A3" a!*N%!ePPF`#3"JS!6`"3!91)!Pi`!*!&#J!@!#S!0U!#!*!&$J"%!%3!XJ(9!)" %4$!+!*!$$J"+!'S!d`(A%iJ!"$!+!*!$3!!3!A-"B`&[!@%("+9MG'`YC!+P,3F MG@jdFQ&`"L0QEh*MC38ME'p[G!+P,3&&"#0NDA!%)h0TG!+P,3%m!6i!N!-8%dj PG%KKBfXJ8(*PCQ9bC@jMCA-!N!06!!m",J+P,3J8T5"MG'`YG!8MDR9YF!JME@p ZFh4PFJ8MGfP`C3+P,3&K!A!("+9MG'`YC!8MBfKKG!BMEfCQCA)&)h"bBAN&)h* TC'8&)h4eFQi!N!1F!)F!N!MrN!0l!d&MG!4AB@Pd!!!Z!!%Y!*!%#&4PE'9`Eh* d!&34!!4+G@e`!!!M!!G0EfjcG'9b!!!M!!4ADA"P!!!M!!%Y!*!%"8&`F'aj!!" K!!03BAN!!(!!"%YTBfX!4"%!"%0SBA3!!#-!"8pQCQ9b!!!M!!43FQ&j!!!M!!4 5D@4P!!!M!!48GA*Z!!!M!*!&,J!2!@3"4!%X!8!#T5d"C3&b!A%%)f4TF!+P,3% V!9S"HJFMD@jfEfYP"#0bG@)!N!0#!"%-T6)`15"$GA*bC@jd!U8Y!AF"H!&4!@B "G!&K##0PEQKKEQ0P#L0dGfphC@&`Efi#T5d"9`&8!8%#T5d"8!&5!*!$m3#'!*! )rrphq`9&FA9TF!G$GA*bC@jd!"[4!!%Y!*!%$>C@aN)&GPBA"[EJ!!G`!24AK MD'&ZCf8J9f9KF'pZ!!"i!!e6C@aPBh3J8A9TGQ9b!!"4!!Y'DA*P)&&eDACPFJ! !CJ!&9'KbEhF!!(3!"8&`F'aj!!"K!!G&EQKKEQ0P!!!M!"&8GfmJ9f9KF'pZ)%0 [E@*KG!!!)`!",3#3"!TAC@&b)%&bE@pb!!"A!!K8B@YP)%pQCJ!!9!!+3A0V)&* PE@pfC3!!33!",3#3"!C3GA3J6fi!!&!!"P*PE@pfC3!!8J#3"6!!N!F%!!$GN!B !!3#3"`)!N!F$!*!("2q3"J#3!bS!3J!Z!1)"XJ!&!3#3"aG`%P0PE'9MG#"K)%0 SBA*KBh4PFMB`#J#3!e3!N#!J!!"!!*!Srj!'!*!%!5i!%!#3"5J"%J!m!@)%"&" XBAN!N!91!4)!BJ&L"!44G@Pd!*!&*!%1!%!"CS!!N!C3!%J!B3"k!*!(8!#k!'% !lJ#3"hJ!5!#*!(S!N!Gi!,`!L3$Z!*!(H!%q!)N"B3#3"bN!5J!j!2!3"%jKE@8 !N!8B!"3!1!!dS!)!!3#3"9!!*!"J!%L)"9*[E'8k!*!'8!#@!'!!ZSJ&8Q&MC6T P!*!&H!!8!)J!5)J(4f9ZC'9b1J#3"RJ!PJ#)!,b)"N&XD@GZ1J#3"AJ"%J#)!6k )"8e[C'8kD!#3"4-!5!!N!2+)$&GSEb"KFQ8JH@pe2`#3$!%%!!%AF!#3!c!!N!F %!!$GN!B!!3#3"`)!N!F$!*!("2q3"J#3!c!!N!F%!!$GN!B!!3#3"`)!N!F$!*! ("2q3"J#3!c!!N!F%!!$GN!B!!3#3"`)!N!F$!*!("2q3"J#3!c!!N!F%!!$GN!B !!3#3"`)!N!F$!*!("2q3"J!!#-i!!3#3!a`!N!01!*!%rrm!N"#!)!#3"8!!3!# 3#8J!N!0)!*!&"!!"!!3!N!B)6J#3"#)c-L+3"5-L%4)L)MYiXL+3"K)M-bY$1l- LN!-c-L+3"5-L)K)5[(h$)T!')5)M-b9$)eXb)L)c)T!*)eHA8b+3#50$1d-bZd) L)L3b)T!$-L)M0,CpRFXL)b)L)b+3"M1l3c)PBb)L)l-cZfc'E(ICU[fb)e-M-b+ 3#E4$-b1mXd0,HCQCUT!$rkUBa6-L*M-c)T!()b1d3c-b*'amb0aP9EZlE'9EY&D c-L46-c)K)c)5)lY8+l4$-M-b*FCXZd-L)K&,4%ZdYV-c-eXc-L)MZj!$3V3VY$1 3"E-L@d-b)L'lN!0%4E3c4,8c)LYPXb+3!bXl4$0%-dZl-c1l-c-L)9ZlY%3cY%4 %1l-MCM)LN!3N*83d0%5l3c-b46-c)L*8Zl4%3lY%4$0EA&-b)T!&*84$0%5d-c) L*6-c-L0EZl4%3cY%5c*FDc-LN!BQZd0$Y%3c-L)V3c-L+l5lZdXc+d4%-V@d-L+ 3"%)L0E4%-c4$-c)L)d3c)L@dZd4%3cY$0$)f4$)LN!3b)PY$-c3cN!3L)N-b)LC ,Zd4%-b3d4$)QY$)LN!4#)V4$-c3l-j!$)L)c-L+eZlZd4$-MY8-b*N-b)T!%3b+ l4$0$-j!$0$)L)M)LDlZlY%3c+eDd-MBc-b+3"$3LY%-c0$13"$)L)M-PDlZd4%- c1eCPXN8c-b+3!a%V)N3cN!BM)T!$-caEZl4$-c0,9E99Zc-b)T!$%4Xb0$13!c) M-b)L)5)b9EZ3!c-L1l9EZl[--b+3""%E3c3c-c)L)c)LN!3c@lZ3!d-M5e9EZl4 ADc)LN!-4%e-l-b-b)M)b)T!$)$C9@lZlXcZe@lZlY,aQY$)L)K%5`c3b-c)L-M) LN!-Vc&@lZl3c4E9EZlY$YV[&Y#)K%4,,*$-M-L-LN!3V8la9ZlZc0&YEZj!$-f@ e9QGfZlYSfc4$)M)LN!3VC6-m9EZdY,@lN!5d3f@lZeA-amc-M$3c)T!&1maE3c9 VZlY9DlZ3!l4$1f@l4,Z3"$0V4$)L)L-L)XaV4$-cbe9QCEZ3!d4%-c9EXc-d4$1 3!eZlN!1e9V9F@l-c-b*P9P@lN!0%3d-c0VY$-j!&0'Xc-l0&E-c'3c-c)L+m9PZ lZl4$0$-c0VY%-j!&ZlXb-cAF@lY%3c-b)L%X99Y%4%-cN!3fY$13"#)NY$1c)he EZl4%3b-L)c*'9E3cN!3b)c1fXc13"#)VXc06@0@l4*!$-L)L098d@l-b)T!%)c+ l3c13!c)L+d-bE0GEZlY%-c-L)VZlXeZc)T!'-VXd4$-c-L)NXc*&@lY%4$-c)L+ l-c0#Zl3LN!BbZd-cN!-b)L08-d5d4%-c-b-L+d-L)M0&Y$)cN!-L-c0E3c13!c) L)QZl-l-c3c-b)L*$-L)L-c5l3c-c-L)M-fXc-c4%-L%Pbc)N8c1d-b)L1l-b)L) c-l4$-cZdY%4EZj!$99Xb*'@c)M1c0&@c)L-l-c-b)MZlN!1d3c-b)VY%Zl-cYEY Q4$)L-N)VaV-K%83L)c-b0%4%3c)dY$-L@d53!c5l9V)N3b)c0$5e-L%5Xc13!c) VZl5d-dY$-L+l-c0%-c5l-L+d-c-N4,Zd-L)b)c0%-LZlY%-cN!-M)VXcN!BL)MY $-c1lZc3c5c)M-c-b+d3c-c)L-b)L5c-M-j!%)L)MYEZ3!c-L-cXb)c0$-L4%0$) L)b+3!cXb)c-c-L)M)T!$)c13!c)L*E-cN!-b*%Xc-L-c)T!$06-M-j!$)L)b)L) c-b-c3b*#1c13!c)N5d-cN!-LN!-Q3b-cN!-LN!8M-L)L-c3L)d-c-c)MZd-cN!- b)L)QXc-d-c-L-c)L)M)b)L)M3L)L)d3c-b1l-j!&)L)PY$13!d-LN!NM-L+3!c@ c-cZd-j!&-M)PY$13"#+3"6-b)T!&-b)lY8)eZd3cN!3L)LZc-j!%)T!+)b-c)L- d99@l4,-c3c-L)LYL-j!%)T!$-L+3"M-M-c)L-c)L-j!$3d-c)L)MBc-L)M-LN!J l@d-cN!-L-L+3!b-lY$-c)L)MDc)cY@Xb)T!'+eZl@c0$3c-LN!-c-N1d-c1c)L+ mZl9EY$)L)M)LN!-VZl3c0#-c3c0%-b)N-N4$-c5l3dI'@d4%-c-L)L-L)MZlY$) LN!8M-L1c-d4$-b)L1l@d1c-c0%-b-c-b)VZ3!c-LN!BVZl)b-c-b)T!$5l-N3c- dZd1lZl4$@lZl-b)L-j!&YN)L)c)LN!3M-L+dYEZlY9Zl4,9EY%Y$)L-c-b)L)cX b)T!*)f@d-d4,3c13!l0$0%)L)c-LN!-b)l)LN!-K)T!&Zd-b)M-c-M3c4%-c0E) L)L-LN!-K%V)LN!F4*&3c)K)K)L)l4$1c-d8b)T!%)5)L)E3LN!BK%5Bd-L+3"6Z l3d-d9$)LN!FK+c)LN!-M)L%4YM-LN!3K)NZl3dZl3c)LN!-M)L)5)4-b%4)L)b) K%FXLN!84)N5lY,Zc-b)K%M)LN!853b%4)M)L)5Yc)T!(-d3lZlXc)L)!N!F1!!$ ZN!B!!Gf3"J!#c*!'!!1lN!B!"+U3"J!&L*!'!!ChN!B!"e@3"J!)4*!'!!NLN!B !#K'3"J!,QC!'!!aQN!B!$613"J!2!*!*3J$`!*N!N#m"!!%!#3!!6)N!$!!!6)` !!!Q)N!!!N!6q!!B!!2rh!!B!#`1l!!N!!J#3!cm!N!H!!*!("!#3%#!!N"!"!!E !!*!'SJJ!N!3"5J!!!B!!!0!!!"$#!#YDa%S!ri2P%))"!"*AKm(Jq)8!"8!&##2 `2r`!IJ#3!acJ#!#3"5!!!!jJ!!!3!*!&J!#3"`i!N"!J!*!3!i!#K%!3`#!)&!8 3!#!34!!!!`!##4#EB!!!%83!&!r%5J#ZqU83JJ%!%P@pIlqSK3!&3!8))r!rr!0 #!*!$#4!8!,R!!!3J!`!*N!!!e6RX6#!!!6PcKIGpcJ!"a(HGlrh4iB`M&hRHGq- BaMr3d"!J!)$"#BB!N!33!*!$"8ehb+8*)&+&DZGm$e+)SLR4"+2L%L%Y&f)!%NN !+eV%5J$Glf83JJ%!%PEZkh[BK3!&3!8))r!rr!6!$i!0R4F3!8IJ%KSJ")!*)2( IeV+5U3!"4ia0#!Ba"")ZM'-B3M&"P$HBaM'*)aLU)C!!D!JJ!)%"!))!N!33!*! $"9D2`!!!`!!!!4M!&!#3!`)a*"85!!!"QC!!!"93!"32a%S!VYDP%))"!"*9hAH eU)8!"8!&##2`2r`)`!5!!QXBL!p(rj%U*!bi18#4K9,8)A%!!Nd)9Hm'-D[S2ia K'%)43D3V@-BaJ5-BNL+)3!2mjlZIkC2V1mqcrM'XBr9!JTch[HjcR*-B`G4cR4M '-AFr&cjdE9Q5!!UV!#YDamS2hHpPm))"!"2@lZYlhq9q"Ai&IL2`2rhC3I)r)L[ iZh,(i(c))(0m+Ik9MlP))Dr2`P84T"L*d4!%9IqK(hTr3F3M12SqF5-BN85)3!4 M'-8M'D0FaM(-%M'USLNJJU-BaM'-BT2rqVk-BaM'-D`*iND-FcGNIr$,6*32r([ aVYDr(rq3!rjGhAHeU"q"rmRrLIq3!riT3+&&)LXBaV,(rj%S2iKm3!k9K4@e)5% !"'8JIKL5,`[SPBaK'%)a8D3M'-)a#5-DN!#)K%!%B`Mp)aRM@-BaJj)aU5*&3)1 r'-B`rrk6'-2dM'-BaM'N2b*'M'-3#%!K$j*V@XI+Aph[B2%!#3!6eZlVHprJIP" r4Ai6rrm#+-#L45)G'-Gdaq!5'#"`Id!1P3"@XK)"!!4&4%8BNL%%%!k-BaK#-9' 8)aM#-BNLVDL3!)4!"1-)`5-CNeM'-B"5DUULK8#*)6R1F)3JNaM#P)aM1FBaV%P b6ScM(rM!)J159!r%5P'ZeU!"!!N!%PAGGl@S!!K3#88)%rrr!LM!T-8L#49%&-I rJ!JNJ$L!!*'!1Nd-!"!S1IZ%ja(1S!#+Mjh[`G(ZMq-A3G&a(%M%Rm,(ihch[4m CLeLlciH0T&4Ip8"a(YDeVh[HNaMqph1FeVh1GiNL0R0M%!F!!i0-UeV%5P(Glf! "!!N!%PEZkh[B!!K3#88)%rrr!GY!VlR5(1fi$dIJIrNJ!!#!!2%!%!#3!a!)!*! ')!!+!*!+)!#3"3)!N!8#!3!!!J%!N!3#!i!6J!!!"!#3#33!)!!b!*!*&!r%5P( rrm!"!!N!%P2rN!2i!!K3#88)%rrr!!J!!!%!N!3)Iq!!#5!!N!SJ%!#3"N!!'`# 3%!%!N!8F"J!!!J%!N!3F!3!J!*!$#!#3#6J!N!--!*!*!9V%5P%!N!-"!!N!%P! !N!8)8!P&#"2rr`#3"!%!N!33!*!$#-!!N%S"!!3!#3!1!"-!'!!D!"d!)!!P!#S !,!!b!$-!13!q!%!!43"+!%m!9!"C!&i!B`"S!'N!D`"Z!(-!GJ"l!)!!K3#+!)m !P!#C!*i!S`#S!+X!X!#e!,S![`$%!-N!cJ$6!0J!h3$L!1F!l!$a!2B!q`%!!3) "#!%+!3d"%`%9!4S"(`%N!5N",J%b!6F"2!%p!8!"43&(!8`"83&@!9X"B!&P!@S "EJ&c!AJ"I3'#!BF"M!'2!C!!!C-"Q!'B!Cd"SJ'R!D`"X3'f!EX"`!(&!FS"c`( 5!G8"e`(F!H%"jJ(V!I!"p3(k!Im#"!)*!Ji#%`)B!Kd#)J)R!L`#-3)f!MJ#23* #!NF#6!*3!P3#@3*H!Q-#D3*[!R!#G3*k!Rm#K!+*!SS#MJ+5!TF#R!+J!U8#U3+ Z!V-#Z!+m!X!#``,*!Xm#dJ,B!Yi#i3,P!ZN#l3,b![F#q`-!!`8$#`-4!aF$(3- K!b3$*`-V!c%$0`-l!ci$4!0+!dd$8!0@!e`$B30R!f`$F30h!h`$JJ1(!i`$N31 @!jX$S31Q!kX$X31f!lN$[!1r!m-$b!20!p%$eJ2A!p`$i!2N!qF$l3!'!!B!"J! '!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J! '!!B!"J!'!!D3!`)'!3B!"J!'!!B!"J)'!3B#"J!'!!B""J!'!JB!"J!'!JB!"J! '!!B!"J!'!!B!"J!'!JB""J%'!!B""J!'!!B!"J!'!!B!"J!'!!B!"J!'!3B!"J! '!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!JB!"J)'!3B!"J%'!!B!"J! '!!B!"J%'!!B!"J)'!!B!"J%'!!B!"J!'!!B!"J!'!!B""J!'!!B!"J!'!!B!"J) '!JB""J!'!*!$"J!'!!B!"J!'!!B!"J!'!!B!"J!'!3B""J%'!!B!"J!'!!B!"J! '!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B#"J!'!!B!"J!'!3B""J!'!!B!"J! '!!B$"J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B!"J%'!!B!"J!'!!B!"J-'!!B!"J- '!!B!"J-'!JB""J%'!!B!"J%'!!B!"J!'!!B!"J!'!JB$"J-'!JB!"J!'!!B$"J! '!!B!"J-'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B""J% '!`B!"J!'!!B""J!'!JB!"J!'!!B""J!'rrm!!![mN!!!N!6r!!F!!2rp!!F!$`6 d!!`!!`#3!d-!N$0!!*!)!F!!N!`d!*!&!UUeBL8!Ir!r+)3)!3!%46i2`2JIL#J !"5!!8%#(m"rr`!#3#!Fi!!!%!*!'!`#3"b!!N!K!!*!2!3#3%N!!N!JU)J#3"9+ !!!"J!!"B!!!""!!"8"rL*3"A[l8SK!J"!!4&+[VrVr@)+!!&)!"33)I`(rr!!*! )#2`!!!3!!!&-!!!$!"!!$!#3!b!!N!MJ!*!2$`1!!*!3i!#3"$!!N!-#*!#3#B! !N!8""!!#UV9L*3"V@ZXSK!J"!!4&0leVhAU)+!!&)!"33)I`(rr!!*!%!F!!`!M m!!!%!!!"XJ!!!p8j,&)J!!"1A1&mhh1!!"a(HGlrh4iB`M&hRHGq-BaMq)#3!!3 )!#!`3Q!!N!J"8e`"%!4)#!3&1Gm$f!34!(4!D2L#4#E&lL!"&&!"8"rL*3"A[A8 SK!J"!!4&+eVeVV@)+!!&)!"33)I`(rr!Gm(`!!#1F3!)r!!%"!"J"b32J!2IeV* 5U!!!8H-633'-3))Lk-BaK#-8'80aM'-BNM'-BKL!U!))!#"!3Q'!!*!$"!#3!`& 9SU)T3NJ8SPV'-!8NSLL+M%#&4)5)5dBa)!%NN!!#UV9L*3"V@ZXSK!J"!!4&0le VhAU)+!!&)!"33)I`(rr!LN%3!0b4L3!Sr!#*K!#3!!8Tk)!$e9,5BA%!!*&#&8) "M%%"!rM'-B3K&"T#ZBaM'")aM')B3-3!#!!J3%!JJ!#3!`3!N!-"8#)!N!-`!*! $4M!&!*!%M%L2a)!!!'Ba!!""!!&3(q)P!&HpG5L%#!%!"%8V@[@ZYBJS!!8J!&" !Kr!IrpZ+!)!")G')J#Mrj&*%J*!!"6rSJ!1&-G3KF3!!Nd*THm*dDRb&@2S4K#% 8(%)eM'-B%M'+SLK!J!$r1HlRqQ6lc[2XlSaV'2e3)4FplhZFjb6'-(8FjdBaM&b #4FqG'eBa)!#b8Y+UY@2P"qYDkbq%#!%!"(dh[@[GH[mTr!8r`&2iKr!Irq552NI L)M',`1Mm"#T%#@F%!HL!!iqBL#'[`!%94"q'*)aX!%PIaK(hTr3B3M12SqF5-BN 85##!!4M'-8M'D0BaM(-8M'USLNJK'-BaM'-BT-BqVq-BaM'-DmriND-FcHiRrdc 9+9!IrMhieleeq2q3"FAV@[@ZYB$q!rrL2ra(rj!%j*)8+5)L2iah@2rr4JIf$i3 "k)!$K498)5%2i4P)%3BNLm*mL9M'%B3M&"a#-B`M%*)aLSL)))!"'-)r5-C`eM' -BZ5-DNL48#%IaM'-2rqNrr#p)aM'-BaSJN#4SaM%!%3##9S@UV9Mj5rV@ZX(L!! 4!!4p0leVhAVr!IbJ2qK6q%Irrq!ELK4*)L)aM'YBr!5#*!N2a!(SJ!-!&E+K!3! #%9!4"L5)33%!5-B4K#-9'N)aM#-3NM'X53J3J!%B`M")aQM@-BaJ&)aU5+&3)4K '-B`K##6'-+8M'-BaM'L55*'M'-IrK!)6qK93(q)P+0HpG3!)!"%!"%8V@[@ZYB! !)+!#+&"!4rrri!#+&)NL)M&8GeMrj"iNPJqd!HL!!i"@X4)!%")4B4&'*)LSJJM SaM'%)a8C3M'-)aL5+Ya*#"#!!6M'-8M'C0BaM'%8QUUS`9!M1-jcR'-)T-B`V5- BcR'-DT*FNk-ia!#)!#"9+UUeBL8SkeVV!!J!%3!%46HpDpekJ!!JS!)S8%"(rrr J!)S9'5BKd94"@2`!iKJ!"``!#)!$J$T1NJ!3&!jqi6R%FbJ!#+Mjh[`G(ZMq-A3 G&a(%M%Ri#)2ihcRZ4mCLeLlci10T&4Ip8"cA0DeVR2FNaMpeh1FeVh1GiNL0R0M %!(!!H&,48"rL*5MA[A8!#!!4!!4&+eVeVV@!!##J!LK33%Irrq!!XKAf1K#1fi$ Sr"m#!*!$"!!2J!-!%!!-!"!%!*!'#!!!S!#3#3J!N!81#i!!N!@!3!!!J%!!N!5 !i!J!N!-"!*!*!3!)!!L!!*!)!UUeBL8SkeVV!!J!%3!%46HpDpekJ!!JS!)S8%" (rrrJ!)!!!#!!J!!!L2`!!J#3"`-!N!8J#!#3"K!!!+!!N!N%!*!'"!#3"3L!3!! !J%!!N!-)J%!)!*!$!3#3#3%!N!-2!*!*!9!IiL8Srrrq!!J!%3!%44rrN!5!!## J!LK33%Irrq!!N!3J!F!!!)rm!!)!N!F$!*!'#!#3#!'`!*!3"!#3"3F"J!#3"`F !3"!!N!-#!*!*$J#3$JUeBL8SJ!#3!`J!%3!%43#3"b#J!LK33%Irrq!!N!`#!*! (!`#343%!"!!*!!i!%`!C!"S!(3!J!#8!+J!X!$-!0!!l!%!!3J"(!%`!83"@!&X !B!"P!'S!D`"Y!(%!GJ"k!(m!K!#*!)i!N`#B!*d!SJ#R!+`!V`#d!,N![J$$!-J !c3$5!0F!h!$K!1B!k`$`!28!qJ$r!33""`%1!4%"&J%G!4m"*!%T!5i"-`%i!6` "33&'!8F"5J&2!9%"9J&E!@!"C3&U!@m"G!&i!Ad"JJ'(!B`"N3'@!CN"QJ'G!D) "SJ'R!D`"X3'f!EX"`!(&!FS"c`(8!GN"h!(I!H%"jJ(V!I!"p3(k!Im#"!)*!Ji #%`)B!Kd#)J)R!L`#-3)f!MX#3!*#!NF#6!*4!PB#@`*J!Q8#DJ*[!R8#H`*m!S% #KJ+-!T-#QJ+E!Tm#S`+S!Ud#X3+h!V`#`J,)!Xd#d3,9!YN#i!,R!ZX#mJ,j![d $!J-(!``$%J-B!ad$)`-T!c!$0`-q!d8$5J01!e)$9`0H!f8$D30Y!h3$H`0r!i- $LJ13!!19!jS$R`1N!kS$V`1f!lX$`!2&!mS$c`28!pN$hJ2M!qJ$k`2Z!r)$pJ2 l"!!%N!-*"!S%$`36""F%'`3E"#)!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`! (!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F$"`)(!3F""`% (!!F$"`)(!JF""`%(!JF!"`-(!!F""`)(!3F""`%(!3F""`%(!3F""`-(!JF""`% (!JF""`%(!3F""`%(!3F""`%(!3F""`)(!3F""`%(!3F""`%(!3F""`%(!3F""`% (!3F""`%(!3F""`)(!!F#"`%(!!F$"`%(!3F""`%(!3F#"`%(!3F$"`%(!3F#"`% (!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F#"`-(!JF""`!!!3F""`%(!3F""`% (!3F""`%(!3F""`)(!JF#"`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`% (!3F""`%(!`F""`%(!3F""`%(!3F""`%(!3F""`%(!`F""`%(!!F!"`!(!`F!"`! (!!F!"`!(!!F""`!(!!F!"`!(!!F$"`!(!!F$"`!(!!F$"`)(!3F""`!(!!F""`! (!!F!"`!(!!F!"`)(!`F$"`)(!!F!"`!(!`F!"`!(!!F$"`!(!3F""`%(!3F""`% (!3F!"`%(!3F""`%(!3F""`%(!3F""`%(!JF#"`-(!!F""`%(!3F""`-(!3F!"`! (!3F!!3!(rrm!!"%Q!!%!N!-F!*!$6J#3"2rr!*!3J%!!N!9!!%!!N!P)!*!$5!# 3"3J!!3!)!*!'%%i!N!3%N!-&"*!,"C!%!J%#!33&"33%"3F4%JS&N!`#!J@3!`F ("!N("3H3"!8&"*!%"`8&"*!,"C!$"*!$!3)""3F,%483"`@3$3)#"38(N!-%#3F &"3F*"`8&"*!%"353%`8&#a%A%3X("C!)"!@3"!3&!3)&"!3'N!-*"`F&"3F*"`8 &"*!%"`53"`8%N!8&"j!$#a%@&a)2#33&N!B%"38%"33&"33%"33&"!3'"!H3"!8 &"!X,"`8&"!3&"`F&N!-(#JX4$!X,$4%5%KFB'4N5#J3%"`N("C!'"!8%N!J&"*! H3!`@3!`B($3N&"`8("a%A&K3B&"L3"4Q3""J8%K%*"`8%"!8,"`@3"!53#`8 &"!F%"!N(N!-&N!3%"`X0%!d4%4-3#j!%#T!%#a!,N!-+"`F,#`F("33%"JN("C! %"!%%"!8%!33%"3F(#3F%"j!&"33&N!-%"!X0$!X,"JF("353"!%""j!*#`H3!`3 '"!N("C!&"!3(#3N("`N("`3("`3*"j!&"!8&"`D3"33%#`F("C!&"!%(N!N*"j! (#`F&N!3,N!-("33&N!-%"38("!N(N!B&"`F'#3N'"*!$"j!$"C!%"!3"#3H3#!B *"j!'#3F&"!8,#`F&N!B%N!-&"`3*"j!*"T!$"353!`F*"`F&"33&"!3*"j!3"3X (#a!,"`8%"353"J@3!`3,"j!$"JH3#!8%N!3*"j!$"C!$"!3,"j!*"!H3"J8,%!X ("`8&"*!-#`H3#J8&"!3&"!3(N!-&N!-%"!F*"j!*"!H3"J3'#`F("C!$"*!("`5 3!`B,"j!+"C!$"*!%"j!%"C!$"!X(N!S%"`B(N!3%"JX("`8&"*!)"C!%#`N(N!S &N!3%N!3(N!-&N!-%#`H3#33%"`B(N!3%"!X(N!-&"*!)"`8%"!H3#`@3"!F%N!3 '"C!&"`X(N!N%"!B'#3F("J3%#`F("C!$"*!("`8&"!H3#33(N!-&"3F&"353"!@ 3!`30#3H3#!8%"!B,#`F("*!$#`F&N!3%N!F("`3%"j!%"3H3"38("`@3"353"!8 &"!X,"j!*"T!%#3d0#3B%"JX&N!8%N!8"!33("38(N!3&"`F&N!8("33&N!-%N!3 &"3B0#3H3"`B%"T!$"`Q3"!X*#3F&N!8%N!8"!33*"38(N!-&N!i%"!%%"!8%#3X (N!F'"!3'#!B,#3N(N!33$3F&N!-%"33&"!3"N!-("`8(N!-&N!3%"C!&"*!$"35 3"3F'#`F*"`N(N!3'"!D3!`X,#3H3"!B*%!X("C!$"*!%!C!%"`X&"!F("C!%"!3 &N!F%N!8!"JX*N!3(N!B%"`B,#`N(N!F0#`X*"`8%N!8"N!-%$38&"`F&N!X%N!3 &"!3'$3d,#C!$"j!&"JB*"JX*#3H3"JN,#3N0#3N("*!$!C!%""!("!F("C!+"*! %"38(#`B($3X*"j!&"T!$#`B*#3F*"j!&"!X,"`N*#`d4%!X(N!-+#a)@"`8("`@ 3"33&N!-%N!3&"`X,"`8($3N*"j!$"T!$"`X*#3H3#3B0#3H3"!N,$C!$%!f3""% 0"!F("C!$"!8%"C!%"!F($3d*"j!$"3X,#3N("`N*#`X*N!-(N!S,#3H3$JX*"`F &N!-%"33%"33&N!-4$3X(N!3&N!-0"`N*#`d,#`F*"j!+"JN,"j!+"38%"!8,#3H 3"3Q3"!X*#3X1#3H3"3@3!`3,N!--#`N*"`N(N!S&"!X*"j!'"3F&N!8("`X*"C! $"`F&"`X,$C!%#`H3"3@3!`3%"`d,$!N*"j!0"3B,"j!("C!'"`F*"j!$"C!%#a% 0#`N(N!J&"353"3d,#`N(N!J&N!F'$3H3!`8("`8("C!&"j!$"3F("38(%"8,"j! )"C!%"!3("!3'#`X*#3F("38("C!'"!@3!`F,"j!$"C!$"`F&N!3%"j!$"38,"3X 5%`X(N!J&N!8%"!N,#`B'#`H3!`8&"!8%"C!%"*!$"38(#3H3"!8(N!-&"33&"!F ("C!$#`d9%3X(N!N&N!-%N!-(#3H3"!X(N!-&"!8%N!J&N!-*"j!'"38("38%N!- (N!-&"3F,#3H3#3@3!`53!`H3!`8%"!F%#3N,"`53"J8&"*!$"38%#3H3!`@3"`5 3"!8*"`F&"`B*"j!("C!%"*!$"`F&"33&"3F("JN("`8&"!3("C!$"*!$"38%#`H 3!`@3"`53"3X("`B%"JN'"j!%"C!("!F'"38%N!3'"!B'#3F("38("C!%"*!&"JX (N!-&"3H3"!8%N!3,$3F'"!3'#`B%"j!%"38%N!-'N!3&"33&"!3("!3'"JH3$3X (N!F*#`N'"J3%"`X,"JB%N!-'#3B%"``*"`8%N!3'"`F&N!F(N!3*#3H3"`8("C! $#3H3#JQ3!`X,"T!$"*!$"J3'!`3($3d("*!$!3%'"`@3#!3(N!F&N!-(N!-&N!3 ,"j!,#`X*"!3("`53!`F%"!B%"`N*"`53!`%%#3@3"!H3!`8%"!H3"`8&"j!%"C! %#3H3$38%"33(N!-%"`3%"JB(N!-'N!-%N!-&N!3(N!3&"!3(N!F&N!N%"JF("C! $"j!%"C!&"!3&"3N("JF&"!3(N!3'N!8("C!&"j!$"33%"JH3"3@3#J3'"`@3"!F ("C!("*!$"33(#3F*N!-("`B%N!-'"!B("`@3"!H3!`8&"!B(N!8&N!S%"JN&N!i %N!J&N!-("3F("*!%#`F&N!B("38%"JH3"3@3#`3,"`@3$J53"3@3"33&"`F%N!- '"!F("C!)"!B(N!3&N!`%#`F&N!3(N!-&N!3%N!-&"*!&"C!+"`3&N!-("`8("C! $"*!$"j!%"3F&"3F("C!&"!3,"`@3"!H3"!@3"J53!`8%"C!'"!8%"3F%"!@3!`3 (N!3&"`3%"JN(N!-&N!3("`@3"33%#`N("C!$"j!%"C!&"*!("33&"*!*"38%N!- (#`F'N!3*#3H3!`8%"j!$"3F&N!3%"!N*"`8("C!)"*!&"33&N!3%N!3&"!3&N!N ("`N'"!B,"j!)"C!&"*!%#3N'"3F&N!F%N!B&N!8%N!J&N!S("`N*#`X(#3H3"38 ("C!&"*!$"`X%"C!&"!8&"*!'"C!%"*!+"C!&"`@3#!3%"J3%"JB(N!8&N!B%"!d %N!J&N!-%N!3&"353#!F*#`N("`@3!`F&N!J%N!F(N!B&N!8%"!X'"*!%"`X,#38 &"*!&"353"`F*"j!$#3F&"3H3!`@3#!3%"38%"JB(N!3&"j!$"353!`F0"`F,N!- (N!-&N!3%"C!&"*!H3"38("`8&"j!*"38%"!F%"!H3"J3(N!3%"a!0#`X(N!B &"`53"!8%"C!$"*!$"`F*"`F&N!N%"!8%"!F&"!8("C!$"j!&"C!$"!3("`N*"`B '"`3'"j!&"JB%N!-&N!3%"!H3"J@3"!3%"38%"38%"!8&"`F*"`@3#33&"!8%"!H 3!`B%"JB%"JH3!`N*"JB,#3N(N!8,"j!'"C!$"!@3#`F,"`@3$J3&"3F%N!-*"JF ,"j!%#3X,"`N*"j!$#`X(N!B&N!i(N!3&N"%%N!-'#j!$"`8(N!B&"`F&"3H3!`B (N!-'"J@3$!3("!8&"`@3#!%&N!-%"C!%"!3'N!-%"C!$"!3'"J8&"!H3"`B("33 *"J@3#J)&"!3#!J8("C!+"!@3"!)#"!B*"JB&N!-""!3""!8&"!H3#!8&"`X&N!X ""38#"3)#"`F&N!-%N!B&N!3"!3)&#`B("`@3"!53"!@3!`H3#!8(#3F&N!S%"C! $!T!%"3F&N!-""*!&"`8%"3)#!3F,"C!*!38#"38(N!J*#3F&N!8%"!8&"!8&"*! $!38&!J%("`8"N!-%"!@3"J)"!JX("C!+!J%&"3H3"`N(N!-&N!3""!3&"353"`8 %!J%%"`8#!C!$"!3&"33%"3%&#K%&N!`#"C!$"j!$"!F*"j!%"C!%"!#3"aN!!2q 3"*QC!!(rN!4QCJ!#rj!%-c-!!rrrc-bCQ3!%rrr-c'CQ!!Arrmc--c-!"[rrQCP QCJ!(rrqCQ6-c!!MrrfD3"!!*rrpQCM-c!!V-c*QC-c-!#mc-CQBc-`!-c-aQCJ# 3!`h-c$13"!!1c-`c-`#3!`qCQ@CQ-c-!%*QC-j!%!"'CQ6-c!*!$%QCQ-c-!N!- 6CQB!N!88-c-!N!89GhF!N!8@998!N!8A4%3!N!8B)L)!N!8C%4%!N!B)[J!"!*! $(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8%!!%!"!#3"JK1!*!%E-C Xc-c'Gfc-c'c'TRT'c-E-aQE-c+CR%A4(DQc-E-aQUNGQChHU4Xc'c-c'aUE-N!2 'E-c-5RUUGUCk4QCXE(DNCXCN&X4-c*!$aNChT-E'c-aXE-4QGk&(4NC-afTXT+T RDNT-a(E-N!4UV'DQc-CXc-aQaRTkGNCfGdCQc'GQCdG+UNG'aXc'aQI-ChCQc*! %C+Ch4NCf&QCdCXaUc%DQ4'4'4QGXc-aQI'aRc'aQCRTRC(4RDKCfUQ4QCmaQ4+H U&NCR4(CQc+GQaRE'c'TdCU5K4dGRCdGQG'TfE-c'UNTf5RC'5QE'GkGXCmE-CU6 -HRTf4(S@G%HQ4kCQc-aXC"URCRCk3@c'HQc-CXb3"'G'4RB@C%CQC'Td4-b3"'H UCRGQGQChaQCQC'a%CRDNCfS@Gk4N4NCf4XCXc*!%TR4'GNGXCmaXCfc'CQE+CdG RCdGhGRGfC'6-aXb3!m6'ThCk4UahChc*aRafaN&kG(SATf4R4fD3"-b3"-I-akG fGfGhc%GNCkCmCXCfTNCNC'GKC'CUC-b3"XCmGj!$CQCR6%V+4'I'4NGfCkCfS@G UGT!$E-b3"'c'I+CQGk4dG%4d5RCQDXCfCQChGRCdGQHNCQc-N!4Xc(c"GhDQ4RB @C'4'GdTfCQI+TRbKCd4kaQE-E-b3!dE"c'E'CRGU&RHNC%CRTdaR5Q4fGQG%CQC %E-E-CXc'CRc'N!2%GfGR4hGfGQ4NI'bKa%HKCaC%C'c-c-E-I-CXaXaXChGdHKH RC'GNC(E'E-a(B@C%CXGhc-c'GhE(Cmb3"AGf4Q4NChThCf4fGQV-ChT'4'aNE-c %GhCfE-I-c-E-a'CRTRDRC'5NE%G-b'CQGhGRHQV'c-CRN!0%E-E-N!0XaQChGK5 NUNG(CfG#I(V'4R4mE-CXI'Gda%V-I-b3!f6(CRCdTkDUGN4k&R4'&TGXGm&Uc-E (FDaQUXb3"FI(4'Tm3@4f4RB@C%CU"T4QDNHXE-aQ5Nc+'XD3!mb3!fCXaXI%DQD NTRHNC'GX&mUKG(E'E%akUQ'NE-b3"@ahCdV%CfahCQCdE'I(N!#N5N4Qc'c'c%' K&Qc-c'E-c-E'4%GNG(CNCRGhc(Cf&KP+T'CXE-c'a"&Qc-c'CXc-E'CNT(4NGR4 h4RCQCXI'G"CdI-c'E'E-a-b3!fE-N!6(4RC%aRDQT(GhTQE(DQ&"c'b3!mc-aXc -E-CQE-c-E'I-ChGU`AHRGQ4fTU4'4%5Qc-E-CXCXE-aXE'4'c-c'C%SDG(&fGNC +5UU3!k&+4d&XCXE-CXE-N!4UTmaXE'5N%8Tk38T+UU4"SDT+GfCNTQc-CQE-E-a XCU'UGQc'C%T%C'T+HQTUUX4'4Xb3!fc*TXE'E(c'CQCf%4UNGXCRHUT%G+3@4dG 'aQI-N!2'aQbTE'c%c-E-E'CN%D&faXGd5QT"a%UU5USAE-c'aQE-N!1@E'I-c'a XaXE"URE(E'G+UNTU5NUUUNI-CXCQaXaQE&PQGmaQCQGQCmG"GQCRT+5USD&+S8U Ua'c-c(aXE-c-aaT+DUCQI(GQE('XE-ad4(&"4%T%T%4NaXc'aQCXN!3CN4UQ4mE -aXCN4QbNG%TdE-E(5NUK5@aQaQaQCXc-aKT8NCSDE(aXN!9mBDT'aXaK4*!%GQC NE'D3!fc-SA%4N!-Fc*!$aXCXCXCfV-E'bNT+DQTXE-aXN!6-CUT"4"%4('CXE'D 3!fGUa%V+CQUUT+T'Gmc'N!6-CQ`4&"4%%4GQCmI+bNUUCRUQc-c%UNC+4(4Qc'C RCfE-aNT+4+UK&dGQN!0N&(TfBD(-E'aUT''THRaQE'GXafc'&+CU%4&"5RCfG(T %F8TaS4UU&QURDNUKTQaQafCXc'`D4Q3D4+4hGXaRCkC(G%SD&"5R5RT"3DUNTQb 3"-CQUUUKUUUKCh('N!0RCQDRHN53!a4%3D&"T"&-E'E-akC"UUSDT%4fGfaRCfT +&dT+4%5N4'UNS8UK34C'E-c'TK5NDUTQYQE'CRC'T+UK3A&"UT!$5U'K5U38UQC %CQC(UU%AUN4kUQE-c'C%UR4h4(4%G%6%5N&"UUSDUUG+CN4(4(5N58CkI'aXTa& "S@&kHNSDS8UKT*!$C'UN5RCa5RCRTkC+GNGQ4XCm`DT"4+5N4%TdT%T+DUTmCU' 3!a%4aQ4QaQI'Gfamc-c'TQGUHT!$UNUUT+HUSDc%UN4d5NV-SDUKV'D3"-c-C%4 U4NUUUNUU&-E(ah4mc+GXbUUUaUSD3@E'UXamc'a+5Q4KG%T+UNT(E'c(C+c'N!5 T%@GUT%CQCQQQCQCf38&%4NDUTU&"GXc'aQ3@c'c'CN5U%CURDUC'Ci&XC%U3!d5 NTUDU'U&%GfE(a+E-aQC+DK3@4QS@E-aX4'aQT%TRTNTh4mC"3Ac(E-aXUXc-bRT d4%UNG-6'CN&Qc'HUUNT'5N4fc-DNTXE-E-bUV-c-CQa+3Dc-5XaXa+4QDUU3!dC K5Rc-CK%AaXCQCUSAaQCXaQT%4Xc'aXb3"'UUDN&kHUTmE-bR4XaXc'GfCQc-N!4 Qc-c'c*!&aNTkGRGUG"E-CNCXN!0QUUT"GXE'c-bRE-aXI-c-CXc'F84aGd5UNfa Q4Qc'DT!$GQT%c*!&CXE+aXCQCXaQG'4fI-4Q4'5UI-4Q5UUU3A&a4QE'c!#3"`` !!*Q3"J!"CT!'!!*QCM-cCQB!!c-cCT!%!!3c-fCQ-c-!"613"'CQ!!BcN!B!"`! !998!N!-)UT!'!!PhN!B!#P@3"J!,4*!'!!`LN!B!!"%@!!%!N!-F!*!$6J#3"2r r!*!3J%!!N!9!!%!!N!P)!*!$5!#3"3J!!3!)!*!'%%i!N!36"a)*"`S5%`J#!`) 4%K86#3B(!`)$!K)4!`F5!`)4!`B#!K!#!`8#N!3"!T!$"J-3!`8'N!-#!K!$!K% $"K)(%a-)%JB#!K!4%JN)%JJ("`B'!K!#%`)#%3F#%3-'%JF5%JF'!K%3!a!$%3- #N!84!J-(!J-4"K%(%JB(%`S6%J+3!`-4!`B(%4%6%4)4!`B(%a-'!J-'"J)(%3B (!`-'%JJ9#48(%j!$"K)5%"!("JN6"K%'"a-(#3B*N!-#!`)#%J-3!J)(!`)(!J) $!T!$%K)(!`B'"`-4!J-#!a%#!J-#%3F$%a3(N!-*"a)("K)("a-("a13!a)+"a% $"a%#"J)#%3B5!`)'!K!#!3)'%JF'!`8'"`B#!a!'"a!#!K-8&3F$!JB#!K%$!K! $%JJ(%K)#"J-*"a)#!K%(%4!'%JB'%K-(%K-6"J-$%JB6#3N)%K%%%JJ$"JF6N!- (%a3*#3B$%a-(%JB#"JB$!J-#%`F'!a%(%3-4!`)3!J)(!J)$"JF(%JF$"JF'#K- 0#JJ5"`-4%a)4!K)*#K-'%K-*#3F(&!F6"`B3!JB#"a)4#4)3!J-5#!B(!JB$%T! $!`B6"JF'"K-#"a%'%T!$"`-5"`-4"`F4!`S6%J-#%3J6#K%$"J)$"J)$"`d6#4) #"a-$!`B4!K%(%3B$%4)(%a%("JF'"`J(%K)(N!-'"`-'%3)'"`N'"`F6"JF4%`J ("a%#N!-'%`B'%K-5"`F*$480%`S6"`d("J-4%4-6#!)'"`F*&!N5"J-'"K)(!K% #"JF5%JF$"K)6"`-4"`F5%3)'!`B*%`F$"a-6#3B5"`-5!`F5"a30&4-(N!-+%J) 4"a)$"J)#"`B(!J-$%!-("K)("J-4%3-'%J)("T!$!J)'%4%(!`-5#K-*"`)(%J) 4!K!#!K%$!J-#%JB*!`)$"J-#"`-'"K!#!K!$"3-5%4-(%3-(%JH3!`)$%K)("`B '!JF(#3N@"a%#!J%5!J-'%J+3!`-'"a'3!`-'!`)4!K%5%`B(%JF5N!-("K)(%JF 5!J-'%3)4"K)5%`F5!`B'#"-0#4)+%a%'!`B(!`)4%3)3%a)6#JB5!`F'"`B5"JJ 5"`N6N!-'"`F5"a)(#4-*"a)(%3)$!`)$!J-$!K%#!JF6"a)("J)$!JB$%3-#"JF $%`F'"a)(%JF5"JS'!a%("K-)"`F$!K%#"K)$%JF#!`)$%3)'%j!$!JB#!K!#!a- 4!a%#%3)4!J-#%3F'%JF'"`B'#")(%J+3!a-#%3F(%j!$%3B4!a)$%JF#%3B#%3) 4%3B6#K-'!K)5%`B#!`B$"`F'!K%#!`B5"`N'"JF5&3d8"a-5!`)3%K)(!`B'%JF (!T!%!`B(%`B5!`)$%JF5%3F(%`F(#3N(!`)5%K-5%J)5%JB$"J)("J-#"a-("JN $%JF5"`B8#")'!J)(!a)5%!)5"JF5!`+3!`B'%J-#!`F6%`)3!J)$!K%5"`N+#3B '"`F$"J)5"JF4!a)$!JB#!`F'!a%(%JF6"`N*%JB$!K)("JB6!K)'!`B(N!-5%a- 5!`)3!J-5!4!#!K%5!`-'#JB5"a%(%JF'%3B#%4-("K)'"3-'N!-5!J-#!`B("a) $%K-("JF'!K)6%K-5%JF'"`B4!`F5%3B(%K38"a%5"`B$!J-4!`-'!JF'"`B$!J- ("JF'!T!%%!)3"`-'%3)(%`F5!`B#%a-("a-)"`B#!a%$%K)'"`B$%JF(!`S6%J- #%3)$#3F'!`)$!`B(%4)4!J-2!K%$"J-#!`)3!`)$%JB$"J)'%JJ("JF'%3-4"a- (%JF(%J)'"a+3!a-'!JB#!JB$"`8'%3F5%K-(!`B("J)#"K)(%`F5"K)5"`B#"JJ 6%`B'"a%#!a)6""%4"T!$%JF5"a%)#4-(%a-(!a)#%3-6#3N6"`B(%3F("JB("J- 5#3F)#3F'%JF+#4-(#3S6"`-("`B6%JN+"J8$"j!%%a-5!`B("a-9#3F'!T!$%4- (%a)(%JJ'"K%$%4))"K-("K-5"`B(!`B'"`-6#3N'!JB'!a))"a-'!a+3!a36%JF #!`F5%`N(%J)'!`B'%JS6"a)#!J-#!JB(%JF6%3F(!`F$!K%$%3F(%JF5%`J(!a% $%3F("JB(!a%(!a%$%3N6%K-'"`B'!J-$%3)'"a36"a)$%3)'"K-+%`F5"`-'!a% 3!JB#"JB5%JF5"a)5%4%#!K%5"a%$!3+3!`F(%`F$!J)$%JF$"JF5"`-'!`B#!a! ("JF5#JN8%`F5%a)'"a%#!K)(%JH3!`B'!J-'!J-#"K-(%J)(%3)5N!-'%J)3!J) '%JF'"JF*"a)&"a%5"a%6"`-'N!-)#3F'"`B#"J-#%JN8%a-(%JB$!J-3!T!$!a% $"J-5%`F5#K)(%J-#"J)5"`B#!K)6"JB#%J-(#3F5"`)5!`F'"`)3!a)$"`B#%JJ 6"`)$!`B'!`B'!`F'%3F("JF(%JB#!j!$%J-'%J-5%J-#%4-(!`)#%!-'%`)'"a) 5"K%'!`)3!K%4%JF'"a)4!`)'"JF$!J)4"a-'N!-5%JF'"J+3!a%&"J)#"3-4"`B #"JF(%K%'!JB("JF5"K)$"JH3!a)5&"3,"a%$!3)$"a%4!T!$%3B'"a)("`J("JF 5!`B#!`B'!J-'%K-(%a)'"a-5%J-#%3-9%JF$"JN(!JF'%`N,%a)("JF6"`B("K% #!`)$%!-'"a-5%`D3!`-'%4%$!a)6"a)6"`F6"a-("a)(&!F'!JB6"`B$!JB$!K) '"J-4!J)'"`B5!J-'%JF("K%'%`F*"a)(&3J4!J-("J)$"4%(!J-6"`B5!`F5%J- '"J)4!JN)"`)4!K)("J-#!J-(%4%(%J-'!J%4"a)6%JF(%JF6#4-'#!F#!K%("J) $!JB(!`B(!`-("JB5!T!$%3-3!K)(%4-)%a)5!J%#!a)(%3F6N!-(!`)(%a)(!J- 5%`S*#JB("`B3%!)4!`F'%4%("K)(%K-5%J-(!K%4!J-#"K-(!a-#"`-("`B#%4% '!`B'"a%$!K!#"K%$"T!$!`)3!a!(#!B'!J-)%K)'!`F'"`J(%a-(%`F4!`%$"JF 5%`F#%"%#!`)"%3)#%`J("a)(#a-$!J)3!K)(%JF'"a%("J)4%J)'"`D3!`F5!JB '#"-'%K-(%JB#%4%("a)'"a)#"J)#%"!$"J)3!`B##3N+%`F#%")6%JJ5"`N(%JB (%JF9#K-6#!B("a)("K)6"`N'"`S6%JF'!JF(%K-(#!B#"J)$%JF6%3F5&K8("JB 5N!-$"JF4!`F9#!N'!`)$"JJ8%JS6"`B$!J-$"a%$%3B$"a)6%JF$!a-5%JF'%J) $%JB$%K)@&3X6%`F4"K3+%`-#!JF'"JF5"`B("J)4%4-6!`B'!`-#%4%'"J)$%`F (%JB'!J)$%3F'!`F$"J)$%J)(#3S+#3)(%3F5!`)'N!-4"JB"!J)'%a))!`)$"a8 +%JF6"`B#%3F5"a)'%JB5"JF("K)5"a)'!`)4!J-6$"-*%T!$%`B6"J-4N!-+%J3 #N!-$%K-("`B("3)3%4-("K)5"`D3!`F5"a)("a-("a-("J-#"K!#N!-5"K-0#") ("a-)%JF#%3-8"`F5"a%5%`B'%JF5#3N(%J-3"`F5"`B$!K!#!K%$%JB(%3-#%a) )%JF'"a)(%JB'!a%6"JF'"J-(%3B$!`)'!J)3"`-'!`)##!F4!`-#%3-#!JB'#") '!T!$!a!#N!-$%JB6#4)(%a)(&!F5!a%$"a-(#!F$!J)5%JB%!K)(%J)3!J-#N!- 3%J-3!a%#%!-#%!-4%`B#!K!'%J)#%!-4"`-(%JF$"K%$"J-#!J-#"K)4!`8$!K% '"`F5%")5"`B$"a-5%K!5"`-#N!-5%`S5!`8(&3S("J-'"a)$%K%("K%4"`)$"J- #!J-#%"!#"JN("`N5!K%(%K)#!`B(!`B#"K-6!`F("T!%%JF6%K)#"JJ0#3B$"a- )%J8$"K)*#JF)"K)'"a%#"K!#%3F*$3F5#3B#"K-(#3F*%`F'%3)$%JF#"a-5%JF #"a)9&3F#!3F6%JF$%4!#!J-#"J)("a-'%JF)%`)#%JF(%K)(%J)$"J)#"JF5"a) '"`)$!JB$%a-(%K-#!a%(&4-,%`F'"JS6"J)#%!F'%K)#!K))&43'"`D3!`)$%K- 5"JB)!`)4!J)3"JB5!`B$"J)4%3-4"3-#%3B$%K%("JJ6%JB'!`F5"a-6%J-#!a% ("JN(&!N6"a)("J)'%3F5!`)4!K!(!`B4!`F$"`F*%JF'"a%5"a-6#!B(!J)(%`N (%3)#!`8$!a!#N!34"a%$"K)("J)"%!)#!`-#"a)$!J-#!`B3!K%#"a)(%K)#"`B (%`F6%JF'!JF5%JJ*N!-'"J)(%3)'%4%$%!-4%JJ5!T!$%3)$!`B#%3+3!a3*%`F 3%3F4!a-(%K-5"a)$"J-#!`)5!JF'!a-8"JF5%J-#!J-'"J-("JF(%K-("JF'!K) 5%`N5"a)4"a+3!a3(!J%#"a%'"a-6%JS5"a)4"a)'"J-#!`B'!K-)%3B("`B("K% $!J-'"a)(%`F'"JJ6"J-'"`N)%a%$!K)(#3N+"J)#%3)2!a%4!a)("K)("a%'!JF '%`B$!JB("J)$%!)#"J-(%`S6%JB$%JB$"JF6"`F6"a)(!`)#"JJ5%JF'%J)'%`B 5&3S(#T!$%J)$%K)*"a)(%4)#"`B(!`%"!J)6%JB'"a)5"J)("JF'"a-(%J)$"K) +&K-'"J)5"`J(%J-5%J)$#K38&3N5%`-6#4-)"a%("K-#"JB(%`F#%a-9&!F(%JF 5!JB(%`N(%JB$"J-5%`F6%`)$%3F5%JF'%`F$!a%(%a)$"`B$%J-'%3F#!J%#%!) #!`F'%`-#%Jd,#4-6#3S6"J-#!a%$%3-4"a-5%`F6#"%#N!-$#4)6"`)3%3)$"K) (%JB#N!-4"`F$%!)!%J)$%3)$"a%#%!X6%JB(!a)3!J)3!JB'!T!$"JF$!J-'"JF $"T!$%`F(%a)6%`F*#4-+"a%5!K)'!JB$%4)5$3S6&"%5!a%$%K81%3B#!J-#!J% "!J-5"`B5#3F'!K%'!`F4!J)$%JS*&!-(%3-5"a)6"a!#!K!#!`N("JF'!`)"!J% #%3F5"a-(%!-("J-"N!-#%JJ8%JB(#4-*"JF5!`F5!`B'%JF5!`)'!a%(%`)'!K! #%3-5%K-("JB$!J)4!J-4"`-'!a-("J)#!3+3!`B(%`N6"`F5#!F(!a%5"a3*"K% 4!a%5!K%$!J)6"`)$!K!#%JF0&`J6"J)("JB*!`B#"JN+$489%`-5%JF4%3-5&!S 6%a)6"a)4!`B("a-6"`)("a)+%a)(%4%'"K!3%4)5#"-6#K%(#3F)%J)'!JB+&!d 0#3B'"`F4#3F6%JF6%`F$!J)$!`B'"`N(%K%$!K!#!`B(%JF5!K)("`)#!`#3"aF !!2rrc*!%!!(-N!B!!Xb3"*QC!!2-c*Q3"!!%c-bCQ@CQ!!@CQFc-QCN!"TQ3"J! (QC!%CQB!#*QCCT!%!!PQN!B!#QD3"$-c!!YQCM13"!!--c0QCM-c!!dcN!B!$J! !)L)!N!-2hC!'!"#lN!B!%DU3"J!5L*!'!"0hN!B!&&@3"J!94*!'!"BLN!B!&a' 3"J!!#)B!!3#3!a`!N!01!*!%rrm!N"#!)!#3"8!!3!#3#8J!N!0)!*!&"!!"!!3 !N!B)6J#3"%4!0%3c-%0$4$-c3c4%!$-`-%4%-c3d-d%d4%3d-$13!d0$-$-d&%4 %-j!$4$-$4!"%&$3c3d%4%c-d-$-c3c4%-c-$-d4%3d-!-!4%-$-c0$&%-d4"%84 %-c3cN!4"3c0$3c0$-c3d-c0$0#-cN!0"0$4%384$-d4$-c-d4"4%-6"!4$!`3d- `-c!`-c0!-a4%3d4%0$4%3d-$0%4%3c-c!c383d-c-`!c0$4%3d3d0$13!d-c!d3 `!c4$4$-d-d4$4"-c-$-`!$3d383c-d4%0$3c-`-d3c-%4$!80%-c3c0$!c-d0$- $3d53!c"$4%4$3c0$-d3c-d0%0$4$-`-c3d-d-$0$3$53!a-c!d0%4$4$!c!d0$1 3"8%$!c13"%0%-d4$384"-c0$0$3c4%3$0%3cN!3d4%-`4$"%-c0%-d4%-$4%4$4 "-a0%4$3cN!0%-c!c-a3c3c-a-d4$3d3c"$-c&%3dN!-c0%-84$-c3d-$0%3c4*! $-a3c4$4$-c0$-c-80"4$0$4%4$0%0$0%-!3c3d-44%0%4$4%0%4%3c3c0%3c3$0 %3d4$4"4%3d-$4$0%3a4%0%4%3d0"-c-`4$-c3c3$"%3c3d0"4%4$!$0$0%3c3d- d3d&%-c3d4$-`!c0%3d0%3c4$3d4$3`3c-a3c4%4"%838&%-c&$3d!$-c"$0$3d4 $4$3c4%-`4$0%4$4"-49"0%4"0%3c4$13"%-c0$4"3a-$-d-d0%!`-d-c4%380$- 84%3c3`-d!c3c3%13!d4%-$-a0%&$-`4$3$4%4%0%0%4"-c0$4%3c-`-$4!0%0$- $343c3d0%0!-d4$-44%%d4$-c-%0%N!0$-%0$0%0$!c4$&$4$-c-d0$-d4*!%3d3 d0%4"4%-c-d4%3838&%0%N!0$4$3c-d53""&%4%0%4%-c%84$-c"%3d4%&%3d-d3 63c4%0$4!0%4%%8-84*!$0$383c!c-"3d4%4"3d4%38&%0!4%4$380%343d&$4%3 `0%4$-j!$3d-84"%c4$0%4$3c3d-d4%0"384$&"4%N!-8363c0%4%3d4$4$0$3d3 4-c3d-d3d3a384*!$0$4%-a4"-`"%4%0%-d4$3d3d%83c4%0%36-c4%0%0%-d4%3 c&%0!-%3d-d-c0%-d4"4%3`-c0%36-d&%0%4%0%4$4$4$0$!c4$0$3`-$4$4%&"3 cN!0%4$-d4%0%4$4$&%53!c3c!d53!c-d3d%d!d-c-$-c0"3c3c4$0%4%0%4%3d3 c4%3d-c3c3d9%4%13!d!!4$0"3d3$4$-c3c!d-d%c4%-c!c0%0%-d4%0%0%-d!c0 %-d-$3`0%4$3`0%0"&$0%3c-d0$0%3c4"3a4$-d-%-d-c0$3c0%3c4$4%4%%63d3 cN!-`-d-c&%&$0$4$0%4%3c0$-j!$3c-c4%38%63d4$-c0$-$4$4%4%0$4%0%4%- c0$0$-j!%4%0"&%0%4"&$-d3c3a-c&$-d3c-$3d-c-d4%0%4$4$4%-43d4"&"363 c0%4$3d%d4%-c-d53!c-c4%0%3d0%4%0"4*!$38383c0%0$0"4$-d0%-c0$0$-c4 $4$3c"$0%-d3d4%36360%N!0$-d&"3d4$-d4%-c-%0$0$3c"%0%4$4$4%N!Bc-c" %3c-c4$3d-%3$-d3c4%%c0%3dN!0$4%-d4$3c3`3c0$4%-c4$0%3d0!4$3d4%&$3 c4%3c4*!$0$3c0$!c4$3c3c!d3`0%-c0%-c0$3d%d0%0%0$36-d4$4*!%0$0$N!- c4%!$0$3%4$0%-c0%%8-`&%0"-%%d-d4%&%3c4$!d3`4$!d4%0$4$-c4%-83d0$- 40%-c4$0$&%4%0%4$N!3c3c4$3c%c3c4$4*!$36-d&%4$0"-c3d4%0%%$3`-c4%0 "3c0"4$4%-c4$3c0$4$0"3d-c3c4%0"0%-6-!-d4%384$-d53!d0$-d-c-c3d3a0 $3c3d4%0%0%0%0$4$0$-c0$-d&$3d-`0$-c!`0$3c4$3d-$0$-c0$4%3d4!0%3c3 d-%3c4%-c4!-c-c53!c-dN!-$0$-d4*!$3d!c3c3d3c3d4%&%0%-c4$3c4$4$&%0 %-`0%4%0%N!3c-c!a4$0%4"4%4$3`0%-c&%!8360$-c!d&%&%&$3cN!4%3c-d3d3 dN!0$0"-d0%0%3d53"!4$4$4%N!0$4$-d-d4$-853!c4%3d3d3d4%-d4"-83d0%- 8384$0$3`0%13!c0"4$0%-d4%0$-c0%4%0"0$3c-d3c3c-d4$-c3c0$!c-d3d4%% d4$-d3c3d3c!8-c3`-c%!4$13!c3c3$-d-c3c4%4$&%4%-c4%N!-c-d-d3c0$3c3 6-c3d3c-d-d0%4%0%3d53"N0%3c-c3d4%0!-d-j!$0%4%0%-c3c!c-d%d0!4$"$- d4$13"%3c3j!$&%3d4%4$-c"%-`!d0!4%4$0%-d0$4%-cN!-a3d4%3d4%-%4$N!- c-d%c!%4%0%3d4"4%4%-d3c-d0%3$4%-c4$-%4*!$3d3d3`!c-d-d4$4"3d3d-%- d-c3d4$4%-c0%3c4%4%0$4%0%3$4%N!0$4%3c&%-d3d0%3a4$4*!%3c0%4%"!-d3 d4$"%4%0%N!0$0%4%-c0%0%38-d4$384$3a%8-$-c4%%8!%3d-d4$4%4$4$3c%a4 %-d3c36&%0!-84$-c4$&%N!-!N!F&!!"QN!B!!613"J!#Gj!'!!09N!B!"%53"J! &)T!'!!!)IJ!"!*!$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8%!!% !"!#3"JK1!*!%%c!#-`#3""-$!`)J-!!b!$#3!c)b-$!J)!#3!a!L)K!c!!"!!!! `!!!J!J!!-!!K%J#3!b)5)J#3"#!#!!%3!%!`!$!%!!)`%#)J!$-!!J)J!`!")5% !)3-#!L)!!!)J!3!c!J!`)!!4)!)$-$!!)*!$!L)4!3!5)J!L)J!J!")J%!!c!!) !!!)5)c!c-#!$)3!L)K%J)J!!!5)!)3!#)"%!%!!`!J#3!b%"*!!!-J)"!J)!N!3 J!J!b!c!#%#-J)5!!-3)!!$!`)#!!!#%`%K%K)J#3!a)L!!!J!#!#!L)4)L!!!J! #!`!4)J!`)$!L)3!!!L!L%3)J!#-#)#-J%4%")!!3)J)J)"!3)!-#!L!")J-L!4! K!K!!!#3%!J!K)4%!)!%5)J!`%3!#3$-!!M%K)"!!)J)5)!)!%J!J)#)K%!%J)T! $)!)4)!!`!b!3)J!`!L)")L!!!!)J)J!!)K)5!!)$3J)J)!!5-!-b!L!L!!"#)3) 3%6!!%K!#!`!!)J!`!5)!)5!#-J-!-#!#-#%#!L)$)K)30!)#)#!c!b!L!#!L)!) !)5!J!$)#)!)5%L!L%J!"!M)K!!)J!!0!)K%J!!)$!J%!)6)#!`!L)J%!!K)J!#% !!L%!)!!"-a!#%L-J)J!!!`!"!`-#N!-!)J)K!3!!!L)5%#)5)3%5!L!L!3!`!!) L)J#3!`)J)!!b)J!L)3)!-L#3!b)#%3-3!J"!!!!#)"!!3!3#!!!3!#)5!J%J!5% L!#!#%J)L)!)!N!-")J!#N!-5!!)L!"%#!L)J!J)L)K)J%#)5)5!K%J%J%K%3-`! !!K)$!L)#!5!#%!)4!J!#%K)J)!!!!L)5)M-5)L-c)!!3!$-`!#)!)!)L!L%3)J! L!L!K%!%L)3!#!!)"!J)J!5!J!!)$%3)%%K-!%3!#!!!#)J!3!*!$-#!!%3!4)L) J!J!!)4!`!L!!)L!4)!#3!a!"!#!J)M-#!#)5)4)L)#)J-!%K!#!$)`!!)#)#!!- J!L!J)J)$!#!J!!)`)L)6)!)!!L)$)!)3)#)d!J!#!b%K!J!J!J%!!J)J!J)L)L- d)`!K!5-6)!)L!L!!!!)L!6)4)!!M!!!J!"!#!K!#%b!J)L!K)L)M)b)J!L!!%5! #N!-3-!%`!!-!%!!!%3%$!3!!-J)5)J)4)5!!!3!3%%)K%L!!N!B#!#%#!!!%)3) !%L)K!5)J)!!K!J)!!"!!!!)!!J!!!j!$!L!K-#)5)L)4%L)J)!)M)4%5)b!!)J) #-!!!!b-N)!-J-J)!-5!J%"%J)J%4!K!#%L%b-#!!)3!M"#)!!!)!!#%$)!!"!$) L)5)!)5!3%#%L!M)#!J#3!b!J!$-#!#)b!5-M3#!L!K)4)T!%%4!!)!-!)$!!!`) !!L"$)$)b!`)`)`)#)L%5!K!L)K%M)!)!)!)!!J-b-5!5!!&!)*!$!$#3!b!M)L! 4)K)#)K)!)#)c-3)J-`!c)J!3)$)!-J!#)`-`%b!!)5%c)L!L%#!#)J!$-!#3!c! a!L!J%K)c!!!b!`-5!!)K!M-!%"!J3J!!)$3!N!-#!!)L%3)L)$!$!!!$!`!b%!) !N!-L)J-#!J!#)J)#!!-!!L!!!5)J!`-`-$)`%J!L)J!c-#)J-d!!-!!!%5!!-`) !!J)K%5)J!`%J!`!L!!)`"$"!)M!!!!)#!")K)J-J-`!#-J%5)L!!)$-!)#!!N!N #)!!L!"%33L%#)J)!)K)`!J!4!!!5!J!J!`!!)!!!-J)J)!%!!K!#)J&!)5!L)M! #)#)!!a!#!#!#-$)J)$0!)!)b)#!#)!!5!J!L%L%3!#)`)#!#)#)J)b!#!L)$"!) b)L!L!*!$-#)#)!)#!!)!)4-J-c!#!!!`!L!`!$!d-!)$)#-J-!)!)3-!!!)`)J% 3)#-$"$-!-!)!N!3#!d0!)")J"$!c!*!$!L!J!#)J!J!b!$"$3!0#)$3!!!3d3`- !%L!%!`3J!$-!!J"!!#!J!`!J)#)c!!!d!b-#!%!c)c)$!3!!%`!J!#)L!*!$-!- `-#!L!b!!)!-!-!-!!`!#-!)")#%!)#)J)#)#!!!b-"!!%#!J!J-!-!!M!!)!3%! #!")J%!-!!!)4)33#!b%#-M)M-#-$!$!c-`!`)*!$-!-#)!)#!#!!)5!J!`)$!5! #-`)`3c!!!#-$!!!L!!!3)!!L)6)J!`%#)#-!!K3!!!-d-$-!-$!!!#33)J!a!#! #!`!!!`-!!3*!!!)L!$!$!`!J!#!M-%!!N!-L!#)#)!)$!`!`!M-#)!#3!a%c"$! %!b!!"!!`-#!!)$!M!J!5)`!!-$!L)!!"!!3J!#-`)!-`!J!!)J"!-L)!N!-$)#! L!L!"-#*!-!0$!!)J-!)!-`!!!J!M-!!#!`#3"#)`)3!L)$!%!$!#%`!J!$!")!! b!J!J)!!b)#)#)L!#%J!J!!!$-$!$!$!#!#!!!!%J)c!!N!-#)#-5*!)%%#)K!3! J!c3$)#-!3`-!!#!#)!)`0$!L!J-!!J!L)!!$!K)#)L)`)`!J-!!!-c!J-#!#)%0 !4$!!N!-M)*!$!!!M-J-b)J!$!!!#)J!`!j!$)$)c)`3!!b!!)%!L-M!L!J#3""! J!!*!)"%"!!!d-J-#!!-!!$!!)#)!N!-c-!)#!$)#!`!J!$)#)b)!)!3!-#!!-c- $-$-J!J%!-*!$!`-!3J-`)J#3!a!3)!!J!`#3"`3!!*Q3"J!"Zj!'!!+UN!B!!iL 3"J!%Gj!'!!!)PJ!"!*!$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8 %!!%!"!#3"JK1!*!%35)R)RBR&L%aFR)L*aG"&8F@%4)LF84(%4%5*b4%&4%Q%L* eBRB8%LBK*fBQ%Q&b)@%4CfGfGK*fCAFR&P%4&@FQ*b4#*Q8QBKChGfB5*N8L%KB LCb)5CfBACK*K)5&K*fBP9d*fCL4@*")A&a)N38&b&L)RFRFR)RGdB5&Q&b*Q%A) 4GR)RB8BP&eF5G(Bf!L%5Gb*L%@GK*bB4%KFR%5FK%LCh)KCQC"%Q)4CK3LCR)R% Q*h*L)4&K)K*'Gb%4*K&K)@)Q&QB9&a*fCb35%d-4%R)RB5GK%@&a0N4b)L%L)K) N3@&KBK%Q4K)ACL48&8CeFR*RFK349RB54"*LGf)bGRB8CaBK&b)b*R*LC@08-(C 5GbBA*K)9BQ%d&h)5&eC"%5)d)4%KCK*LBA)93"96GQ*L&aFL%A3LGP3R)LC5%L% 8%8F5BR*f*b*L*Q)RFL&Q&"*K*b94BL*hN!0Q)K)A*L*48L*LBLBQ)L*#&(Ca34& N&a*L&K9$*b*h&hFL%4*bFKFPGb*LB4)QB5GRGK4K%RCh)K*K%8%LGbFL*R*RFKF L)5BL*Q*LF4%84RBR%5Ca4hFK&a&PCb*QCRF5FQCKF@B@GLFQ)QF@34-@BL%9)A& "&hCLB4%KFR)8*f89CL)L3NF4GfCQB484%4)Q*Q9K*%%5)L)K*'Gb)Q%R&")Q9(* A)4%4*QCR%4&#FPGKCK*a%83A&a0N4b)N)K4%-5&K%N)K8K&LBQGa34&"&5&KCbC '*NGhB54"*P3P99&#)Q*L)5GKB8*LCh)R)dC"FR)RGa%43RBQ%d&h&eB@99*a%53 MGh%4&bFLF5)LC8%L&hGb%4%@)LGP3R*e&PC8Ch0"BQ84Ca&h*a&b%L)Q3A0%4hF @&K4L*hH3!aGa3988)9-5GeBQ%L*&348KFRC#4&3@)K&4%b*b*h%R)LG84f*K4P% QB@)N%@&"GL%4%RBN4"*fF4&#)LGbFL)R)QBLF4Gb)5)L*R3A)QCL%4&a)Q*K%K% K&N*L)Q)LCQGL*L%L%C!$*R*b)5BR)5F@&K4b)A)44hB8FR&44'BAFRBLGh)4%@3 5*L*K&LFLFL%5%R)L*"*A*bGR&&-@&d4LFLG"BKBK%4FQ9aF83")QCL*h*bFL&Q) Q%KCA&44'&K*LF@3A)5%@&a8K)5)@3KB8)@%LF8*L*Q%@&h&&-@%Q*aCfCb)L)4* #*MGK%4*LCQ95GRC"35*LB5)L%L%aFLBA)A&b&@Gh)4*5)4F44"GKCPFL*f&hFQB 4&R&Q%LBK*hF5GLBK&b&R)LB5*534FACKF@GfFK)LF9BN)4%QBKBL&h*fCK8LBRF KCK)K3@Gd*f*9*fCKGb)KBL%K%54@*#CK&bGb*@)RFKCRBL*b)K34)P)QB9FR)Q% A*hGa&8)R)Q)8*LFL)4GKGb)RC5*K*Q*K)Q)5%M4LF5Gd3R9N*h)QN!4KB5%5*hC f)6F89f*4)@*hF5%M84FLGb-QFR*e99%LB5CRB4*f%NGN8K9#Gf&h*RF5%@BN*Q) L4"C')K&84")MBQ%5!5)@)L)R%@)K%R%ABQFRCA9(*8-4FK4b&9*8B5%L*#CdF53 5)4%R*h&")R&K*h&a)LFP-4Ca9#GQ9$33FLFR%f)5%L%@%4)RCd%5)AGa8KB9BL4 %-435BK45&`%9BR*M4NGh)4%8%K)@44BA)L)5%4&R&&38FK%A)QCQF94#*9944a% L&K%4CR34CaC@*R%4BLF5GK*LF@%A)R*f9R8!84F4)8)Q%5CbCR)Q)4G&4bGK%LB L3R)4&&)LGQGb%e4aFAF4"'BRBA%L%5BK&e&KCa%@CK%@)4%84b*PGbG%4#*Q*#* %4'F4)5CaCQBLF4*"FA35)4%KBA8@&RFQ&P8%Gf&R&R3"FLGb&hFK%K864#*Q)Q% R%5*K%5%4GLB598B4)Q)4*f)R*LBLBLB54P0%GL*aF4-LFKB4N!-KB4%M4"%5BR% 54#GaB4G@GQ)L88!5GbC"Ch&QFL)4G#9"44%Q&h*bB4)8Cb&K&f4hCL)L85)KF8) Q%RBKCh)8)K35FL)LFLBLF50L*QB4FQ)L4#*a&b*aCRCR%4BAF4!AFL*L%5&%4#8 5FRGf%@*RChBN%8)ACf*b*KCbBL*aC%GbGLB4)83d%d&4*L*LFM%Q8K&#G(FQ*Q) R)A&LCLC4!QGbGR)L384N4K*%*N&"&a%N&%*N3Q%QBQ)QC(FR)435)d)Q&Q*d%A% 5ChG"FL4bFQ)4Cf)@*L*4*%B93Q%Q&%)P"hCQCLFLC6)R)44"%6*b%N%hB@Ga!K3 K%9%A&(BQCR*L"N)P84)N&KB4&%3N45FL-8CQCL9")5*P%@%LCK)R45%8&#C8%KG QGK8434*"*')4BKCQ%NBL3A&8)LCQ&dF53Q*@3K-bGK*4GK9(-4BAB5GfCT!$*QC LC%*K*QCA%L4(*QC%)R)@F63b*LBa%4)@B5CQCe%QBQBK)K&RBP*L*KGb)K-P"aF 4*4)5*b&%GQD3!f)KB4)QGf*b%5*LF5&K*RCR3"%Q%90P38GRBN*QCP*Q&fBL4LG a)L*hGf)KCb)5CK%@Gf*R&L&#%83L*bCK*#)5B"*&B4&R)L)R*e&#Cb*(3K*#GK% L%a)P%aF43L%8%K3K*4853QGa*hFQC4&N)Q&L&R*KF4BL*fBd&L8$8Q*c%!&f%a% L)N)P3LCL)5C'F83%4#F8*Q%KF488C4&"*f493(*f)8%5G4*$%4&fCKC`4!#3"`F !!2q3"J!"QC!'!!*QN!B!!pf3"J!%Zj!'!!@UN!B!"RH3"J!(4*!'!!!4$J!"!*! $(!#3!di!N!6rr`#3%)"!!*!&3!"!!*!*5!#3!dJ!N!8)!!%!#!#3"K"1!*!%#43 9&!Q3"43-#438%38&%4%&N!36&Im1r`lr$JN&%C!'"4)*$!i,$!@3!a)'%`N8#a8 5"4-*N!F8#C!'&"@3!`8'%C!&"C!$%K)6"`N8ra8(""'3"!84"4)*&Im-$4%&N!- 5%`N9&3i*%K)*N!B8#C!(&!`1r`88%C!'"385%a)6#485"385%a'3"!8&%a39r`i 9%K%&"4)6&"6r&3N&%K-*N!89#3N8#C!%&!crra),%C!'"385%a-8&!@3"")*"4% 4"385#431$K81&"%4"3B*#3`2&"+3"!Q3"")8#C!(&"Arr`B8"4%&N!85%K-*#K% &N!8'#4%&N!-6&"81#a8-%`88"4)*&3i9%T!$"JN6%`8&%K3*N!F9&Im,#43*%38 5"4)5%`N8&384N!3&"4)*%J85#439$K8-$48("!N$"3S1&!@3!`B6&383%386&!N *%a-*N!-9$!`8$!N&N!35%JN*&!`&%3-4%3@3""-8&"81&488&"8-&!B!%K!&&!i &N!85&"3%"388&")6#3J*#439$Im9#4%&%JB6%a39#3F5%C!("3B6&3crN!-&"4) '#43%""%$"438"3B&N!35&436#4Ar%JB*N!-8#C!$&3i&N!-5"K-(%`N9#`N4%"! 4N!-&N!-5&3i-rrm&"4)6#3N8"J-3"3N8%4-&N!3'#Im,#4Ar&!F*N!-(%J8&"K3 5%385%JB5%JN8&Im8%3-4N!3&"3N9N!-1r`8&%K)(#3N'!a!X&%J@3"3N-"4% *rj!$&3N5"K'3!`86#4%&%38&%K)6#46r$K33%"'3!`8@3"2m&N!-'%K)*&"! $"431"C!$%3@3!`F8"4%*$[m-#3N&"4'3!`8'#4'3!`@3!a)5#439r``&%C!%"38 *$"@3!`i5"385N!-6&!83"48,"4%&N!85#384#Im9%`B&"4%3%"%&"3S&%C!%"C! $%JN8r`i0%4!4"386$!i8%aAr#38'"3B5%JN*%3B9&!83"C!&%K3&%3N8"33&&2m &%"%3%388#4'3"!8&%JN*&"Ar&3N4%385&3i*"K)9ra35%J85"K)(&"%5#a8&%3@ 3!`B5#435"4-&%C!$%`i-"3-3"388ra)4N!-&N!-(#439$[m1%`8&"`N5"38($!i 9%`B&"4)'#3`&"`N5"K)&N!-5"JN8%J85#384""%8$"33%4%5&2m9"C!&%K-8&3m 9$[m*"385N!88$[m1&4)&"3B5#Im*"C!$%K-,#38%"`N8"C!%%a)4%3B,$4)4"3B 0r``8"C!%%JN8&C!$$!N4"C!%%T!%&2q3!a8&%385$434"C!%"JN9!33-#4%&N!3 5#4%4"3N9$K-ǡ&38&#"3)%a-9&3N*&"%&%38&%K)'%K)*&Im-#4%4"385&"3 &N!35#3X"""34%3@3"")*"4%4#3i-&4-8$JX&N!-'#K8&%C!$"3B5%"%&"4)'%T! %%a6r$K34N!-&"3B9&!@3!a)6&")*"4%&N!B*"4%&&!`9&3d9ra)4"385#3N4N!3 &%`83%3@3!a+3!`B6%a39&434%4!&N!-*$4)'%K)6&!S&%384"C!%%K-6%388$[m 9r``9%4%&"4)*#4%%%4%%3%4%&%T!&"K)8$`i*%C!$"385%K39%K)6#438%"% &N!B5%`N4"KArN!-1$")4%!8&%JF*%C!$"3B8%C!$"385N!3'%JN*&3i6%4%$%4% &%JN1&!B6#485%4%&N!85%JN*"46r$Jcrr`N3%4%&N!-*#K)4%3B+#a'3!`8&"K+ 3""-*&!i-"4'3"!8&%JN0&3J5#434N!-&N!85%JQ3!`lrN!--#4'3"!@3!`N8"`8 5#3`-"4%4"385N!-6%JN*&2m9%3-4""'3!`86&C!$%K36%"%&N!85"3B8#439$[r r%a!$""'3"!8*&485#48-#4'3!`8&%T!$%a)6#48-#4!4%384%38&%K39&43+%!3 4"C!&%K)(&!84%Jcr&!85%K'3"!8+-#4)$#3N&%4%&"4)5%a)6#4Ar&")3%"' 3!`@3!`B8r`i-#4!$"C!(%K3*"386&2q3!a3*&!84%38ǩ%`8$"3S5%4%&"4) 5%a-*#Im1&4'3"`8&%K6r$K8*%"%&N!B5%`N4%386&3X8%J@3!`B8&!N5#489%J- %"4)*%J8&%T!$%`N*&3i-&!-4N!B&"4)9&4-'#3N4%3@3"4)*"4%4%a6r#3@3"4) 5&"@3"!8#"4'3!`8'#488#4-6#481$[m8""!3%C!%"386&435N!-*#4%&N!3'#4- 4%4-9&"%4"C!&%JB(&"@3!`3$%4!3%4%&"K-8$"88&Im9#C!%%C!&"385#3i5"4) 5%a8)"38'%JN6%38*ra)3%3@3"a)5#"6r&433%!-3N!-4"38*&"81rrm9#3J(#3N 4N!8&%K3*"C!$%K)*&4)&"4-*"JN9ra3#%"%&N!-5"C!%%K)*&480%K%3N!84"38 *&Iq3!``8#3N6#434N!-&"K3*"C!%%K)*ra85#435%`N*$!N#!a%&N!-5"4)&%T! $%a39&3N4%3-3%4!4%38&&"Ar$J`9&43(%a6r&"-*&"-4%3@3"")6#`i8%a)&"4) 5&"3#%"%&N!J'%K)*&3lr"4'3"`85#46r$J`9N!-6%`N1rrm6%`N4%3@3"4-9&4) 5"C!%%K-8!K!3"C!'%T!@3!a3&%38&%C!$"3B*&3i-&C!$$JB6#Im8"385&!N 4"384"385&"35"4%&"4)&%JN4%"%4"C!&%J85N!-6&3`8#4)'%J8&%38&%K39r`i -&48*%a-8#38&%K)6&"34"4%&"4)9%`84"385N!36#4!$%4%&N!B5%JB*$43&N!3 5%K-&"4)*&2rr$J`8#")6%`N&"4+3!`J*&4-4"4%&%K35%4%&"4+3"!B8%K!4%3@ 3"4)5"K)*&4)4N!3%"38*&!N8$!lr&")'%a)6%K%&N!-5N!-6#484%38N&%4% &"4)5"JB5#484%"%&%3@3""+3!`N9%K!4%"%$%!8&#Irr$J`1&!85N!-*"4%&N!- 5"K)6#436"38'&!8&%4%&"4+3!`B6#488!a%4"C!&%K)*&!i&%C!%%"!4%JIr$!i 9&3i*%K)6#4%4"C!$%T!$"JN8&3N5&384"384"385"K)6%JN9$")4N!3&%J85"a6 rr`84%334%"!&"3F9r`i9#481%a)(%a!4"C!$%T!$"K-*$2m-$K%&N!-4"385N!- 6%JN9$K85%3@3"")6&2m1ra)4!a%3%"%&"3N9&3i*"JVrra38#4%&N!-5"4+3!a- 8r`lr$!N&%3@3""+3!a-6#43-&3`9%J8&%a-*#439$!N%%C!&"4)*&Im*"4)*&3l rra33%3@3""+3!a-*$[m1&48&N!B5"K)5#3N9$K81rj!$&!@3!a)*&"31"4'3!`3 4"4)+ra8&"4)*$"89$"83%3@3"4)5%`Rr$K3)#43&N!85%JF)#439$K8-$J`*"38 4"3B*#439#4'3"!8'#489"4%&"JN9$K88r`84%38&%JB5%K-*&3i*%`N8%a%&%T! %%`N*&"@3!rm1%`84%38'%K-*#4Ar"J@3!`B*$"34"!8&%JN1$!N6#`N4N!-&"4) 5%a-8$K85%K-*&!85%K-5%`Q3!a89$K89%K'3"!85N!-6#489&!B&"JN9&4)4%38 &%K3-&")'&2m5%3@3!a)5%`N8&3N5N!-6#486%K13!a)'"4)8&!i&N!-4"C!$"K) 5%`N*"4%&%T!$"JN8$K)&"3Ir$385%JN9ra)4"385%JN*&43&%T!%#43-%a-8#4% 4"3B*$!d4%3@3"")'%JB6%K%4"3B&"4)'%`N8$4)5&2m*"C!$%``1$JN&"3B6#"8 9"C!&"K)*&38&%K%&"JN8$2m8%"!4%38'%T!&%4%&N!35N!-'"JN9&3Rrr`@3!a) 5&!i9"`8&%a3-%K%4"4%&N!-'"a34"C!&%K)*&"33%4%&"4)5%a-'"4!4"4%&N!- 5N!-6%`RrN!35"C!$%K6r%K!4"4)*&"84N!-&N!35#43&%3@3"4)'%a3'%4%&%K- *#4-'%4!4"C!'%JB5%JN9rrm1#3@3!a)*&!-3"C!$%JN8&"%4"4%&"3B(&"-&N!F '%K-8#38&"JN8#3F6!a!3%3@3"K)'%JN9rj!$$!@3!`B8"4!3%38&"K-8&384"38 4"4)6&!i&"4%4"C!$%J85%K8*"3B8&!N6%`)$%"%&N!-5"C!$%K)*&!i9%K-8&"- 5#3-3%4%&"4)(#438%3@3"!B*$!`5"C!$%4%&N!3'#3`*#438#3S*!K!4%3@3"JB &"JN8$"3&"4-8&C!$%"!4"C!$%K-*&"8'"C!%%K3*&")&%C!'"385#3i-&488#`N 5!K!4%3@3!a)&"K+3!`N8$K-&N!-6&481#3-4%38&"K)6&"Ar#385%a-5#3N6%C! ("385#480$"89#4)&!J)$%3@3!a)&%T!$#3N,$J84"38'#3lr$!84"C!$%K)*&"6 r&4)5"K13!`Q3!a%&"4%4"C!$%JN9&3lr&3@3!`-!%"%%"385"4)5%`J*&484%3@ 3!a-8ra88%38&"K)5%`N8r`N5%K-6#C!%&4)4N!-&%38&%a3-&3`9%K%&"4%!!J- 4%3@3!a+3!a-8&434N!-&"4)8r``9%`8&%JB5#!N8&4+3!a13!`Q3!a38%C!%"38 5#4@3!`i5%4%&%38!!K%3%3@3!a)5%`N8$!N4N!3&"JN1&488"C!$%K)6#43-%J8 '%`Q3"439%4%%%385#3X1#a36!K%&N!34!J-3!`84"3B6#439&384%"%4"4)*r`` 9&4)&"4)5%`N8&4)&%K-*N!B9"4%4"JN8$!i9#433%"%4"4%4%K)3!`-4N!-&%`N 9$JN4%4!4%385#3`9N!-'"385%K-*#485"4)6#C!&&"35%3B*#439&385"K3&N!3 4"385#4%$%3-4"3B8&3N4N!8&"4)6$!i9&4-&"4)'%`N8&!8&%K)6#C!&&43&#C! %&!`*"3N1%a%&N!B5&43'"38(&3i1%a'3"J8`9N!-'"C!$%JF*&"3+"4)5#C! &!*!(&J!!c-bCN!3!!Fc-QCPQCJ!#QC!'!!1CN!4QCJ!%QCPQN!3!"@D3"J!'CT! %-c-!"fCQ-j!%!!Jc-fCQ-c-!#613"J!+-j!%!*!$#b)L!*!&$"%4!*!&$3!!)L) !N!-1!!!4%3#3!`m!N!34%3!3L*!'!"&hN!B!%P@3"J!64*!'!"3LN!B!&4'3"J$ r!*!)!3#3!mRS!!$)k!!!"r`$XkJd!hS!N!-F"TB!&eG*6N3!"`$#9%e36!!"!5* 1G@e`!!%"1N&-8P3!!`&54%P86!!%!B*69&)M!"%"[QPMFc3!"!+@D@0c)`!%!Y* *3diM!!3$$QPME$3!"!0+4%a24`!!!iC'6dj8!!8$NNC26N3!!J2D3e958`!)!rj ZD$-a!!!%DNC548B!"!4f3Nj%6!!!",*048j9!"-%[Ne195-!!3@Z8e45)!!!"FC NBh4L!!!&dQPMG')!!!AHB@0dBJ!$"HT`F'&d!!F''J#!!#d!N!0i!*!&J3#3#i) !#!#3!b!!N!@$!!m!N!2H!*!&K!!A!*!$3!#3"B8!(!#3!eS!N!@'!#%!!!%#!*! &K`"f!!!jh!#3"B!!-J#3!ji!N!@"!2d!!%h1!*!&J!!h!!!LkJ#3"B%!33!!)`3 !N!@"rrmJ!!MJ!l1Qf!#!rrm!!%lQ!l1PV"1)!58!!%li!l1Q%"1*!6%!!%*4!l1 Pm!#"rrmJ!!M`!l1PK!#!rrm!!!b-!l1QB"1)rrm!!%jQ!l1QL"1*rrm!!%kH!l1 PZ"G`rrm!!&+%!l1P[!#!!'JJ!!%Q!l1Q,!#$!*%!!%Z4!l1P(!#%!*8!!%iG!l1 Pi!#&!*S!!%im!l1Pr!#'!4%!!!l1Pj!#(!*m!!%pQ!l1Pf!#)!+-!!&"G!l1 PJ!#*!+N!!%m+!l1Q0!$*!+i!!%`P!l1QR!$+!,X!!%b1!l1Rk!$,!-F!!%bd!l1 PM!$-!0!!!%cD!l1Q2!$0!0B!!%ck!l1PX!$1!0`!!%dD!l1PD!$2!1)!!%dk!l1 Q"!$3!1J!!%eD!l1PT!$)!1i!!%ed!l14Y!$4!28!!%fk!l1Q)!2Srrm!!!&!!*! %!qRrr`!!!F3!N!3$k[rr!!!-XJ#3"!2VrrmJ!$Sk!*!%!qcrrb!!1Vi!N!3$k2r r!!!#5!#3"!2Trrm!!!+-!*!%!qVrr`!!#N3!N!3$krrr)!!l3J#3"!2XrrmJ!$Z '!*!%!qMrr`!!!Y!!N!3$kIrr!!!$e!#3"!2Urrm!!!P!!*!%!q[rrb!!1mS!N!3 $l2rr)!!mcJ#3"!2Srrm!!!6B!*!%!qRrr`!!"Y`!N!3$k[rr!!!+L!#3"!2Vrrm J!$h5!*!%!qcrrb!!2pB!N!3AF!%A!!"4rJ1cT0",LIrr)!!00J1cTe4,M2rr!!! @`J1cTe"-$!"G)!!X+J1cTda-LIrr)!"GRJ1cTdK-M2rr!!"R+J1cTd4-#3&C)!! MC!1cTd!!P`"*"!!LT!1cTc`!Q!"5"!!M(J1cTcJ!Q3&0"!"G@!1cTc3#!2rr)!! j"!#3"!)$rrmJ!$P-!*!%!J6rrb!!1C3!N!3#"Irr)!!h9!#3"!)(rrmJ!$HF!*! %!J(rrb!!0q3!N!3#"[rr)!!i,!#3"!))rrmJ!$Kd!*!%!J,rrb!!1,`!N!Errb! !1J#3"S$rrb!!3GS!N!@"rrmJ!%(P!*!&J[rr)!""m!#3"B2rrb!!3IX!N!@%rrm J!%)'!*!&J2rr)!"#%3#3"B(rr`!!3Q-!N!@#rrm!!%,X!*!&Jrrr!!"$1!#3"B6 rr`!!3qJ!N!@!rrm!!%4I!*!&KIrr!!"%M3#3"BErr`!!808!N!@(rrm!!%qp!*! &L2rr!!"&9`#3"BRrr`!!4K3!N!A+rrm!!%E2!*!&brrr!!"(AJ#3"Fcrr`!!4pS !N!A0rrm!!%K"!*!&c[rr!!")U!#3"Frrr`!!53m!N!A*rrm!!%Pf!*!&d2rr!!" *j!#3"FMrr`!!5MN!N!A4rrm!!%V1!*!&J!#"&!",-31cT0J!J3#*&!",B31cT53 !J!%#!!"26J1cT5`AF!%I!!"4bJ1cTG!AF2rr!!"5,!#3""1)!6N!!&1f!l1QG"1 *!88!!&2U!l1Qa!#!rrm!!&3H!l1Ph!#"rrm!!&45!l1N%!#!rrm!!&5'!*!&J[r r!!"c+J#3"B(rr`!!K&3!N!@$rrm!!)d@!*!&K2rr!!#H-!#3"BArr`!!TVS!N!@ 'rrm!!+mm!*!&Krrr!!#heJ#3"!G0CA0cB@GP"P0dBA4eF`G%G@jRC@pZ"%ePER8 %9'9iG!Y%D@&REQpcG'PMF`4198a-"%jeEA!*9@jcD'PQG'9N"e0SD@CdC@3)5'& MDdC[ER3+8&0)B@0V4QpZG!T38dKKBfY'Efjd$8eTFf-Z)&0dFQPZCh-+9&4C)&G TEQ4[G`GYC@jeBQ&b"h0eBQePER8$5f*N"%KPE(!%5@jQE`0"Bh3&6@&RD@-%3QP dF`aMEfjdFQpX)'YPHA-,F(9ZBh4eBA4TEfi)BR*KBfYPG(-&B5!Y)'d&EL!Y)(S &35!Y)%d&6L!Y)&S&-#!Y)$N'GfPkBA*N"f0eFR*PER3%68j9)`j3FQ9Q)%CTE'8 J6Q&YC39&FA9TF!GKFfYZB@eP"90dBA*d#d&LEh9d,f9bFQpb"d0[EQCTFQd,3@* [GA3[CA*bEh)(3fpZCQPbE3Y1CAG)B@0V4QpZG!a38dKKBfY'Efjd)$Q6)`: nethack-3.6.0/sys/mac/NHsound.hqx0000664000076400007660000102443012467321052015621 0ustar paxedpaxed(This file must be converted with BinHex 4.0) :#e0[G@jNFbjbFh*M!(*cFQ058d9%!!!!!!!!!!-,a@BE!!!!!!%!!!-+K!!$#B3 !!!&"!!!"MJ!)Tc`pR`!!$rF!!!'1!!LR2$fI!!!2q!!!!Bi,8fpeEQ4c,R*cFQ- #!!!!FR0bBe*6483"!2rrrrm!!!!!FR0bBe*6483"!2rrrrm!!!!!!!!!!!!!!!! !!!!!$hQR2DiI!!!!!!!$#m83X3!!!C8!#+Fm2eJ!!"$"!!!"P3!)Tc`r@!!!%-3 !!!'9!!LR2$q"!!!3e!!!!C8!#+Fm2kX!!"$P!!!"P3!)Tc`rd!!!%2X!!!'1!!L R2$rR!!!4"`!!!Bi!#+Fm2qJ!!"%)!!!"S!!)Tc`rlJ!!%3d!!!'J!!LR2%!"!!! 4(3!!!!!h3!!"!!%!"3!!!+!!!B"4!!!!!!!8!!!!!!!!0aC@lSZM!!!h&!!!0a8 !2)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)# !J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIi#!JB+$Ji5&KBD'KSD'KB@%K)1 #JS'"J)"rIhprIhprIhprJ)#!J)'"JB+#JS1$Ji1$Ji+#JS+#JS'"J)"rIhjpIAY kHAGfG(0aF'p[EQp[F(*cGRKlIB#%KSL,MBq3!*!!N!#3!)q0M)Z*L)D%Ji'!Ihj qIAepIAepIAepIRjrIi#"JB+$K)5&KB@&KB@&KB@%Ji1#JB"rIRelHAGeFR"YDfP RC@9PC@GTE("dHAf#KSU1NT@AQ*QBPjD8NBq-LSL'K)+!IhemI(YlHhYlHhYmI(e pIRq!JB1$K)5&KBD'KiL)LBQ)KiD%Ji&rIAYjGR*ZDQ9KA9YC9eGC@ejMD'jeHi+ )MT5CR*qKSU'JRTbCPT12M)U(KB1"IhjmHhTkHRTkHRTkHhYmIAk!JB+$K)@'KiL )LBU,LiZ+LBL'KB1"IRYiG'pUC9pD9P*26Np38eGEB@CYG(Z%M*1DS+5SUUUUU+@ LRTZANiq-LBD$JAppI(YkHRTjHAPkHRYmIAk!JB+$Ji5%KBD(L)Q*LSU+LBL(KS@ $J(ekGR&XCf&E99&058P*5de499YLDA*lKBkAS+HXX,+bXDqVTk1HQC@4MBQ'Ji" qI(YkHAPjH(KiHAPkI(erJ)'#JS1%KBD(L)Q,M)f0MBb+LBL'K)&qHR9aDQ0G9e& ,4d0"3%*%5%e8A'9[HSD4R+DZY,LkZVLeX+ZQSCZ@NSf*KB*rIAYkHAKhGhGhGhK iHAYmIS#"JS+$K)@(L)Q+Lib-M)Z+LBL(KS1!IAKcE@CI9e")3cik1$Sm38K4@Q9 [HiH5RUH`YVUm[,UhXkfSSTfBNiq,Ki5!IRakHAKiGhGhGhGiHATmIRq!JB+%KBD )LBZ0MSq3!)q1MBZ+L)5!I(KcE@CI9Nj(3$Se-M%c0Me&8&aTGiD9SUki[m2&a-+ qZ,+VTCqCP)q,Ki5"IRakHAKhGhGhGhKjHAYpIRq!JB'#Ji5&KiL+Lib0MBf-M)Z +L)@"IAGbDf4E8da%2MJc-#ma0$T#6PYVHiZEUVDraFR+b-5rZ,'USjfANBf*KB+ !IRalHRPjHAKiHAPkHhapIRjrIi#!JB+$KBD(LBU,M)b,LiZ+L)@#IRPcE'9F98a &2MJc-#ma0$T#6PYVI)kHVER"amV+b-1pYUkRS*U8MiZ)KB+!IhjpI(amHhYlHha mIAeqIRjqIRjqIRq!JB1&KiQ+Lib0MBf-LSH%J(aeEQCH98j(3$Sd-6!`-MBq5&C RHBZGVEV%bXh0bX@qYkqQRjQ6MSU'K)+!IhjpIAamI(amI(amIAeqIRjpIAepIRj rJB+%KSL*LBU+LSU*L)D%JAeiF@TM@P0-4$ik0cBf1$Y#5P9NG)@@TE+ma-M*am1 qYkqSS*U8MiZ)KB+!IhjqIAepIAamI(apIAjqIRjqIRjqIRq!JS1&KSH)LBU,LiZ *L)D$IhTdE'9F98a%2MJc-$!a0$Y%8@&cKCHSYX()c-h,am#jX+QJQT51LSD$JB" rIRjpIAepIAjqIRprJ)"rIhjqIRjqIRq"JS5'KiL)LBQ+LBL(KB0rHR9ZCejA6dK !1M8a-$!b0Mj+@@TqND1c`-M1d-r,a,bdUk+EP)q,Ki5#JB"rIhjqIRjqIRjqIhp rJ)"rIhjqIAepIAk!JS1&KiL+Lib-LiU)KB*pH(&UBeT66%3q1$-`,c!b0d"0AA# &QDZkaXl4dXr+`lU`TjqANBb)KB1"J)"rIhprIhprIhq!J)'"JB"rIhjpI(amI(j rJB1&KSL*LSZ-M)U)KB&pH(&UBPY66%8r163a-$!b0d"-AA''Qkfmb-r6dp$*`VQ [TTf@N!#,Ki5$JB#!J(prIhpqIRjrIhq!J)"rIhjqIAepIAeqJ)'$KBD(L)Q*LSQ )Ki@$IhTcE'4G98j'3$Xh0$-d0MY$6Pe[JjDSYm2,cp(1bF+jX+HIPj'-L)@$JS' !J(prIhjqIRjqIhq!J)#!IhjqIAepIAjrJ)+$KBD(KiL*LSU+LBH%J(YdE'9F8da $2$Bb,bi[-MP%8Q4iMD#b[mR2dY(0alkfV+1EP)k+KS5#JB"rIRjqIRjqIRjrIi# "JB'!IhpqIRepIAjrJB1&KiQ+LSZ,LiQ)KS5!Hh9ZCej@688q0c%Y+b`[0$j,@fq &QUbmamr6dp$+`lU`TjkANBb)KB1"J(prIRjqIRjqIRprIi#!JB'!IhpqIAepIAk !JB1&KiL)LBU,LSU)KS5!HR4XC&e86%-m0M!X+bd`06p-AR1*RDqqbY(8e0$*`VL [TTf@N!#,Ki@$JS'!IhpqIRjqIRjqIhq!J)'"J(prIRepIAeqJ)+%KSH*LSZ,LiZ +L)H%J(YdE@4F8da$2$Ba,LdY,c3q5eaaKjb[[mV5eGA4bX+iVk@FPC!!LiH&Ji+ "J(prIRjqIRjqIRjqIi#!J(prIRepIAepIS#"Ji@'L)Q+LSZ,LiU*KS0pGfpRAPC 046dh-LiX,#ic2%PDES5CV,c)d069dF[$ZV#RRjH4MBQ'K)+"J(prIRjqIRjqIRj qIhprJ(prIRepIAeqIS#"Ji@(L)Q+LSU,LiU)KB*qH(&SB&G24cmi-LmY,M!f2NY FEi5BUVR&cG$4cXR#ZE#SRjL5MSU(KB1"J(pqIRjpIAepIRjqIRprJ)"rIhjqIAj qIRq"Ji@(LBZ-M)f-LiU)KB&pGQpQA94,3cXd,LXU+bmf3%pKGSZIX,l*cp,4cXM !YkqQRTL5MBU(K)+!IhjpIAepIAepIAeqIRprIhprIRepIAeqIi##K)D)LSU,Lib ,LiQ(KB&mG@jPA94,3MNb,#NS+5`d3&"MHBqMYF2-dY66cXHrYUfNRCD4MBQ(KB1 "J(pqIAepIAepIAeqIRprIhprIRepI(epIS##Ji@(LBU,M)f0MBb+Ki0qGfpQA94 ,3MNb,#JQ*LNa2%aKH)kMYF20dpA8cmLrYUfNR*D4MBQ(KB1"J(pqIAepIAepIAe qIRjrIhpqIAamI(apIRq!JS5'L)U,M)f0MBZ*KS0rHR0UBPP35$mi-LiU+5S[1%C BES@DVEh)d026d-R#ZE#RS*Q6MiZ*Ki5#JApqIAepI(amI(apIAjqIRpqIRepIAe pIS#"JS5'L)U,Lib-M)b+L)5!Hh9YCPe85d-m0M%Z,5ia1846CRZ2SV2!bFr3cm[ %Zl5XSjfANSk,L)D%JS"qIAemI(amI(amI(amIAepIAemI(apIi##K)D)LBZ-M)b ,LiZ+Ki5"I(C[Cej@6N8q0M%Y+b`[0N&3C(Q1SV2!bY$4d-c&[,@XT*kBNiq-L)D %JApqIAamHhYlHhYlI(amIAepIAemI(epIS##K)D(L)U,M)b-M)Z+Ki5"I(G`D&p @683l05mV+LSY08"3CAU2Sl6"bp$5dFc&[V@YTCqCP*!!M)Q'Ji&rIRemHhYlHhY lHhYmI(apIAamI(amIAk!JB1&KiQ+M)b0MBf-LiQ'JhjiF@TK9dj&2$8[+LJR+M% m6'&hMD'c`F[4dp,0aVqfVUDJQT53!)f+Ki5"IhjmI(YlHhYlHhamI(apIAemI(Y lHhapIS##K)D*Lib0MSf0M)Z)KB*rHR0VBPP35$mi-5dU+5X`1NPFFBHEVEc)cY( 4cXM"Z+qSSCZ@NSk,L)D$JApqIAamI(alHhYlHhYlI(amHhYlHhYpIS#"Ji@(LBU -MBk1MSf-LBD#IRG`D&p@683l0#mV+5JV-Mj3CAZ4TEE$c0,6dFc&[,@XTCkCPC' 0LSH%JAppI(YlHRTkHRTkHRYlI(amI(alHhYmIRq"JS5'L)U-MSk0MBf-LBD$IRP bDQ&C8%K"1cBa,LdZ-Ma+A('(QkflaXh3d-h(`,H`U++FPj12LiL&JS"qIAalHRT kHAPjHAPkHRYlHhYlI(apIi##K)D)LBZ-MBf0MBf,LBH$IhTcDf0D8%Fq0c%X+#F U-$Y+AR5+RV#qb-r5dFl)`EQ`UD+FPj12LiH&JAppI(YkHRTkHRTkHAPjHAPjHRP jHRYmIS'$KBH*LSZ-M)b,LiU*L)@#IhTdE@CG98a%2$Fa,5XV,MC%9QZ"PUQjaFh 4dXr+`lbcUk@IQC@4MBU'K)&qIAYkHAPjHAPjHAPjHATkHRTkHRYmIAq"Ji@(LBZ 0MSk0MBb,LBH%JAefEQGH98a$1c8[+bJR+M*!8fQ!PUUlb0$8e0(-aEfdV+@HQC@ 4MBQ'Ji"qIAYkHRTkHRTkHRTkHRTkHRTjHATlI(k!JS5&KiL*Lib0MSf0MBZ)KB& mG@aN@e*)2cJa+bFP*b`h4eadLk'c`Xc5eG22b-'iVkLLR*H6MiZ)K)+!IRalHRP jHAPjHAPjHRTlHhTkHRTkHherJB1%KSL+M)f1MSk0M)Z)KB*pGh"RAP904$`e,bS Q*LSc399XJjQX[-M3e064bm5mXkbPRjQ8N!#-L)@#IhemHhTkHAPjHAKiH(KjHAT jHAPjHRYmIS'$KBH)LSb0MSk1MSf-LBD$IRPbDQ&B6N8m0#iS*#-Q,ce4DB#AUl[ )d069dXc&[E5XTCkCP*!!M)Q&JRppHhTjHAPjHAPjHAPkHRYlHhYkHRTlI(erJB1 &L)U-MBk1Mik0M)U'JRjiF@TK@%p(2cJb,#JR+#ml6'*jN!#NYX61dp66cXHqYkk RSCZ@NSk+KS1!IRalHRPjHAKiH(KiH(PjHRTkHATkHhaqJ)+%KSH*Lif0MSk1MBf ,L)@"Hh4XBeT458!j-L`S*LFY1%PHGBbKXm,0dp66cmM"Z,#SSCbANSk,Ki1"IRa lHRPjHATkHAPjHATkHRTjHAKjHRYmIS##K)H*Lib0MSk0MBb,L)@#IAKaDQ&C8%F q0c!U*5-P,Me4DS1DVVr+dYE9dX[%Zl1VT*kBP*!!MBQ&JRppHhTjHAPjHAPjHAP kHRYlHhTkHRTmIAq!JS5&KiQ+Lib0MSk1MBU(K(pjFQYK@%p&2$3Y+#3M*Lim8'L !PkZmbG(9eG,-aEfdV+@IQC53!)b*KB*rIAakHRPjHATkHAPjHATkHRTjHAPkHha qJ)+%KBH*Lib0MBk1MSf+Ki@!HR0XBPP34cih,bSQ*#FZ1djNI*1RZ-E2e0A5cFD rYUfQS*U9NBf*KS1!IAYkHAPjHAPjHAPjHAPkHRTjHAPjHRaqJ)+$KBH*M)f1Mj! !Miq1M)Q&JAaeE@4E8NP!1$%V*L-N+M9(A(1-SV6$cY29e-r)`,H[Tk'EPT+1LSH %JAjmHhTjHATkHRTkHRTkHhYlHRTjHATlI(jrJB5'LBb0MSq2MSk0M)Q'JRehF'G I9Ne%2$3Z+#-L*Lmr9@k'RV,#cG6AeY(+`VQaU+'FPT+1LiH%J(jmHRPiH(PjHAT kHRTkHRTkHRTjHATlI(k!JS5'L)U-MSk2Miq1MBZ)K(pkFfYL@P&)2cF`+53L*5X j6'0mP+QlbG(@ep61alkeVD@IQC@4MBQ&JRppHhPiH(KiHAPjHAPjHATkHRTjHAP kHherJB5'L)Z0MSq2N!#3!*!!Mib*KS&mG@eN@e**3$Na+L3L)bJd4PaeMU5faFr 9eYA3bF#hVkHKQjD4MBU'Ji"pHhTjH(PjHATkHRTkHRTlHRTjHAPkHherJB1&KiQ ,M)b0MSk1MBb*KS*pGh"SAeC04$Xd,LJN)LBa3PKaLU#c`ml8eYA4bX+jX+QLR*H 5MSZ(Ji&qI(TjH(KiH(KjHAPjHRTlHhTkHRTlI(erJ)+&KiQ,MBq3!*!!N!#3!)q 0LSH$IRG`CPa658!i-#FI'aXJ,8&DG)kPZFM5f0R@dFV"Z+qRSCZ9NBf*KB*rIAY jH(KiHAPkHRYlHhYlHhYkHAKiHATmIS##K)D*Lif1MSk0MBb,LBD#IAKaD'"A6N8 q0LmR)L%M,$a5E)@GXF(0e0I@dFV$ZV'TSTbANiq,L)5"IhelHRTkHRTkHRTkHRY lHhYkHAKiHATlIAq"Ji@(LBZ-MBk2Miq1M)Q&J(YdE'0D8NP!1$!R)4mJ*cC,C(q BVVr-e0MAe-h&[,1USjbANiq,L)@"IhelHRPjHRTkHRTkHRYlHhYkHAPjHATlIAq "Ji@)LSZ0MSq3!*!!N!#2MBU'JAaeE@4E8NJr0biP(KXE)M&(BAf@VF$0eGRCeFr ([V@XT*kBNiq-L)5#IhelHRPjHAPkHRTlHhYlHhYlHRPiH(PkI(k!JS@(LSb0Mj! !NC'3!)q0LB@"Hh4YC&Y558!h,bJL(KdN-8GKHjDX[Xc8fGR9cXHqYDbNRTL8N!# -L)@#IhelHRPjHAPkHRTlHhYmI(alHRPjHAPkI(k!JS5(LSb0MSq2Miq0M)Q'JRe fEQCF8dT"1#mR)4XD)#j%ARU8Ull,eGRCeXr)[V@XT*fBNiq,L)5"IRakHAKiHAP kHRYlHhamI(amHRPjHAPlI(k!JS5'L)Z0MSq2N!#3!)q0LiL%IRG`CPa658!i,bB I'KNI,%&EGj+U[Fc9fY[AdFQrYUfNRCL6Mib)KB*rIAYkHAPjHRTlHhYlHhamI(Y kHAPiH(PlI(k"Ji@(LSb1Mj!!Miq2MSb*K(pjFQPJ9dj&263X*"iD(#Bi8Qf*SVI (dpREf02,`VL[TU#DPC'0LBD$J(jmHRPjHAPkHhYlHhYmI(amHhTjH(PjHherJS5 'KiQ,MBk2Mj!!N!#2MBU'JAYcDf*C8%Bp05XL("FC)M41DiHKYmM6fYcDe-c$ZE# SS*U9NBf*KS+!IAYjH(KiHATkHhYmI(amI(alHRPjHATlIAq"Ji@)LSf3!*+6P*1 5NBk+KB"jFQPI9Na#16%S)"N@'#-f8'b)SVI)e0[GfYA0a,UaU+'DPC'0LBD$Ihe lHRPjHATlI(amI(amI(alHRPiGhGiHRarJB5(LBb1N!#4NC'3!)q0LiL%J(PbD@" A6dBp05`N(4ND)M*,Ci1HY-E5fGcDe-h%ZV'SSCU9NBk+KS5"IRakHAPjHATlI(a mIAepIAalHAKiH(PkI(q"Ji@)LSb0Mj!!N!#4N!#2M)Q&JAYdE'*C8%Fq0biP(KN B(bp)C)'FXX64fGcEeXl&[,+TSTZ@NSk+KS5!IRakHAPjHRTlHhamI(apIAalHRT jHAPkHhf!JS5(LSb1Mj!!N!#3!)q1M)U(JRefE@9F8dT"16%R(KF8'5P"ARbBX-2 5fYhFep$([E5VSjbANiq,L)5"IRakHAKiHAPkHhYmI(apIAemHhTjHAPkI(k!JS5 'L)U-MBk2Miq2MBZ)K(piF'GG9%Y#16!R(KF9'LJr@hQ9VF$2f0cFf0()[V5VSjf ANiq-L)@#IhelHRPjHATkHhYlI(amI(amHhTjHAPkI(k!JS5(LSb1Miq2Miq2MSb *KB"jF@KH98Y#15mP("34&L3m@AH8VF(3fYlHfY2+`,DYTCkBNiq,L)5"IRakHAK iHAPkHhYmI(amI(amHhTjH(KjHhf!JS5(LSb1Mj!!NC+5NBq0LB@!HA"SAP9-3cS `*K`8%"-J0e4cND[!cpRHhYV6bX#fVD@HQ*12M)L&JRpmHRPiH(PkHhYmI(amI(a mI(YjH(KiHAYpIS#$KSQ-Mj'5Nj15NT!!MBU'J(PaCee658!f,#)A%!d6)caDHCD [`p,DhYhCdXLqY+ZMR*H5MSZ(KB&rIAYjHAPjHRYmI(epIAepIAemHRPiH(KkHhf !JS5(Lif2N!#4NC+4Mif+KS"jF@KI9Na$1M!Q("32%Kmf8h14UVr3fYrIfp6+`,H ZTCkBNiq-LB@#IhelHRPjHATkHhYmI(amI(amHhTiH(KjHRapJ)+&L)Z0Mj!!NC+ 6Nj'2M)L#I(9XBeT34cie,#)C%4!C+dCPK+#hbGAFhYc@cX5kXDQKQjD5MSU(Ji" pHhTjHAPjHRYmI(apIAepI(akHAKhH(PlIB#$KBL-MSq3!*'5NT+4MSZ(JhaeE'0 D8NP"1#mP("88'LT$BAqEXXA5fYhEeXr&Zl+TSTb@NSk,Ki5"IRakHAKjHATlHha mI(apIAemHhTjH(KjHhaqJ)1'LSf2NC+6P*56NBk+KApiEf9F8NJr0LdM'K34&bB qA(UAVm,4fGhFf0()[V@XT*fBP*!!M)Q&JRpmHRPiH(PkHhYmI(alHhYlHhTjH(K iHAYpJ)1&L)U-MT!!NC+6Nj+3!)f*KB"jF'GH98Y"1#mQ(4B6&b8l9h@5UVl0ep[ Ef0(*[lDYTCqCP*!!MBQ'JhppHhPiH(KjHRYlI(amI(amI(YkHRPkHhaqIi'$KBL ,MBk2N!#4NT+4MSU'J(PaCej85d%i,L3C%Jm9*$aCGj5Y`G$ChGcBdFLqYDbNRTL 8N!#-L)@#IhelHRPjHATlI(apIAepIAemHhTiH(KiHRaqJ)+%KiZ1N!#5NT16Nj' 1LSD"HR&SAeG146`d+Km@%"%F-8eXLkDlc0MGhY[8c-+jX+HKQjD5MSU(Ji"pHhP iH(KjHATlHhamI(epIAakHAKiHATmIS#$KBH+M)k3!*'5Nj15N!#0LB4pGQePA&* *3$J[*4`@&"XU3PppQ,$$d0RFfpE2aVfcUk1GQ*52M)L&JAppHhTjHAPkHRYlHhY lHhamI(YkHAPjHRYpIi'$KSQ0Mj!!NT18P*+3!)f+KApiF'GH98a$1M!Q("33&#) k9hD6V-$2fGhGfG,*[lDYTCkCPC'0LB@#IhakHAKiH(PkHRTlHhTkHhYlHhTjHAT lIAq!JS5'L)Z0Mj'5Nj15N!#0LS@!HA*TAeC04$Xb+5!B&4FM1&0`M+5jbG6CfYI 5bX'iVkHKQjD5MSU(Ji"pHhPiH(KiHATkHRTkHRTlHhTjHAKjHRYqJ)+%KiU0Mj' 5Nj16NT!!MSZ(JRYdDf*B6N8l-LFG%`i4(643EifR[-c@fpcCdX["Z+qRS*U9NBk +KS0rIATiGhGiHATlHhamI(amI(YlHRKiH(KkI(k!JiD*M)k3!*+6Nj15N!#1LiH "Hh4VBPP34cid+L!A%4%E,NTTKk1jbYEFhG[9cF5kXDLLR*H6MiZ(K)&qI(TjH(K jHATlHhYlHhYmHhYkHAKiHATmIS#$KSL,MT!!NC'5NT+4Mib*K(efEfCF8dP!0b` J&3d,&#P&C)1IYXR@h0lFeXr'[,1USjfANiq,L)5!IRYjH(KiHATlHhamI(amI(a lHRKhGhKjHRaqJ)1'LSk3!*'5Nj16NBq0LSD!HA"SAe9-3cN[*"J2#a!K1eTkPl( %dp[HhGM4alkeV+5HQ*53!)b)KB&rI(TjH(KjHATlHhamI(amI(akHAKiH(TlIAq "JiD)LSf2N!#4NC'4Mif+KS*lG'aM@P&)2c8V(a82%"Xb6fk-TV[-eY[FfG,+`EL [Tk#DPT+1LSD#IhakHAKhH(PkHhYlHhYlHhalHRPiH(KiHAYqJ)1'L)Z0Mj'5Nj1 6NBk,Ki*mG@eN@e**3$BX)KJ4%"SZ5@L(SVM*e0[FfY6-`lUaU++FPT+1LiH$J(e lHAKiH(PkHhYlHhYlHhYlHRPiH(KjHherJB1'L)Z1N!#4NT16NT'2M)L%IACYC&Y 45$id+4d5#`X@,%PTLD5lc0MHhpc9cX5lXUULR*D5MSU'JhppHhPhGhKiHATlI(a mI(amI(YjH(GhH(TmIS##KBH*M)q4NT58NT'2LiL$IRG[CPe656me+Ki6#`X9+NG RKk+jbpIGhY[@cF5kXDQLR*H5MSU(Ji&qHhPiH(KjHRYmI(amI(amHhTjH(GhGhP lIAq"JiD)Lik3!*+8P*58NSq,KS&kF@KH9%Y"0LSG%3F&$b4#C)5KZF[AhYrFeXr &Zl+USTbANSk,Ki5"IRYjH(KiHATlI(epIAemI(YlHAKhGhGiHRaqJ)1'LBf2NC1 8P*56NBk+KB"jFQPJ9de%1M!M&``($4mj@RUBXXA8h0rHf0(([V5VSjfANiq,L)@ #IhakHAKiH(PkHhamI(amI(alHRPhGhGiHAYpIi+&L)b2NC18P*58NBk+KS&kFQT K@%p'26-T(4)-$KXc8A'3!+UrcpRGhGV6bX#hVUDIQC@4MBQ'JhppHhPiH(PjHRY lI(amI(YlHhTjGhGhGhPlIAq#KBL-MT!!NT59PC55MiZ(JRefE@4E8dT#16!N'4% 2&LP%C)5IYXR9fphEe-h%ZV'SSCZ@NSk+Ki5"IRYjH(KiHATkHhamI(amI(YlHRP iH(PkI(k!JS5'LSf2NC18PC56NBf*K(jhEfGH98a#15iM'!m-%L9!B)#FY-I8fpl Fep$([E5VT*fBNiq,Ki5"IAYjH(KiHATlI(amI(amHhTjH(GhGhKkI(k"Ji@)LSf 2NC+6Nj+4MSZ)JhjhF'KI9dj&1c!N'!m,%L-qARqFY-I8fplFemr'[E5VT*fBNj! !M)L&JRjmHRKhGhKjHRYmI(amI(alHRPhGRChHAYpIi+&KiU1N!#4Nj58P*14MiZ &J(PbD&p@683l-5FF%3d4(cK@GT5Z`Y$ChGcBdFLqYDbPRTQ9NBf+Ki1!IATjH(G iHATlI(apIAamI(YjH(GhH(PlI(jrJS@)Lik3!*+6P*@8Niq,Ki*lFQPJ9dj&1c% Q'a%-$ade8h15V-(3fYlGfG,+`,DYTCqCP*!!M)L&JRppHhPiH(KjHhamIAepI(a lHRPiGhCfH(PlIAq"K)H+MT+8PCD@PC13!)f)JhaeE'0D88Jq05SH%``-&ba*DBL MZX[@h0hDe-c$ZE#SSTb@NSk,Ki5"IAYjH(KiHATlHhamI(amHhYkH(GhGhKjHhk "JiD*M)q4NT18P*14Mib*K(piF'KI9Ne%15dJ&!S)%54"BS1JYmV@hGrFeFl&Zl+ TSTbANSk,Ki5"IAYjGhGhH(PkHhamIAamI(alHAKiH(KjHhf!JS5(LBb2NC18PC5 6NBk*K(piEfGH9%Y#15iL&3`*%54!B)'HYXR9h0rFeXr&[,1USjfANiq,L)@#IRa kH(KiH(PkHhamI(amI(YkH(GfGRGiHRaqJB@)Liq4NT59PC56NBk+KB"kFfTK@%p '2$%P'3i)$"dh9RH@Vm24fplGf0()[V@XTCfBP*!!M)Q&Ji"pHRKiH(KjHRYmI(a mI(amHhTiGhGiHATmIS##K)H+MC!!NT18P*55Mib)JhaeE'*C8%Bm-LFE%3`1'c0 4FC!!UVr1f0hGfG,*`,HZTTqCP*!!M)Q&JhppHhPiH(KjHRYmI(amI(amHhTjH(G hGhPlIAq#KBL-N!#6PTHAPT@6N!#-Ki&lG'YK@8p'2$)R'a!*#KF[6Qq2UVr3fYl HfY2,`EL[Tk#DPC'0LBD#IhakHAKhH(PkHhapIAepI(alHRPhGhGiHATmIS'%KiZ 2NT19PTD9Nj!!MBQ$IACYC&Y45$me+am8$3dA,%KSKk1jbYEEh0V6bm1jX+QKQjD 5MSU(K)&qI(TjH(KjHRYmIAepIAamHhTjH(GhH(PlI(q#KBL-MT!!NC+6Nj+4Mif +KApiF@KI9Na$15dK&!X)%59$C)@KZ-V@hGlEeFl&Zl+TSTbANSk,Ki5"IRYjH(G iH(PlI(apIAepI(alHRPhGhGhHAYpJ)1(LSk4Nj58P*@8NSq,KS"jF@KI9Na$15d K%`J$#KipB)'JZ-[Bhq(Hf0$'[,1USjbANSk+Ki5"IRYjH(GiHATlI(epIAemI(Y kH(GfGA9fH(TpJ)1(Lik4Nj59PC@8NT!!M)H#Hh4VBPK246Xa*4N2#JdE-e*cNUc "d0RGhGR5bEqfVD5HQ*53!)f*KS0rIAYjH(KiHATlI(amI(amI(YkHAGhGhKjHhe qJB5(Lik4Nj5@PjD8NBf)JhadDf*C6dBm-LBD$`N+'$"2FC!!Um$3fYrHfY2+`EH ZTU#DPC'0LBD#IhakHAKiH(PkHhapIAemI(alHRKhGhGiHAYpJ)1'LBb2NC18PC@ 8NT!!M)H$I(9XBeT45$mf+Ki5#JS9,%YXM+LpcYMGhYV8bm+iVkLJQT@4MBQ'JS" pHRKhGhKjHRYmI(amI(amHhTjH(GhH(TlIB##KBL,MT'6P*@9P*+3!)b)JhefEQ9 F8NJq0#NG%``,&La*DSUP[-hBhGlEe-c#ZE#RSCZ9NBf+Ki5"IRakHAPjHATmI(e pIAepI(YkHAGfGRGjHhf!Ji@)M)k3!*+6Nj56NBq-L)0pGQePA&0*3$BX)"3-#a8 V5@U+TEc0f0hHfp6,`VL[Tk#DPT+1LSH%JAjlHAKhH(PkHhapIRjqIRemHRPhGRC hH(TpIi'$KSQ-MT!!NT19PC56N!#,KS&kF@KI98Y"0b`I%3B##b&!BS1KZFcChq$ Gf-r&[,1USTb@NSk+KS1!IRYjH(GhH(PlI(epIAepI(YkH(GfGAChHAYpJ)5(LSf 2NC+8P*58NSq-Ki*lFfTK9dj%1LmM&3N$#4Xh@AZDY-M@hZ$HfG$([E1USjbANiq -LB@#IhakH(GhH(PkHhapIAjqIAelHRPhGhGiHRYpIi+&LBZ0Mj'5Nj56NT!!M)L $I(0VBPK04$S`*"J0#!`F0PCiPl$&e0cIhYR4b,keV+5HQ*12LiL%JAjmHRKhGhK jHRapIRjqIRepHhTiGhGhH(TlIB##KBQ-Mj'6PC@9P*13!)b(JRYcDQ"A683k-#- 9#J8*'MCAHCQcapEHiGrCdXLrYDbPRTL6MiZ)K)&qI(TiGhKiHAYmIAjqIRjqIAa kH(GhGhKjHhf!Ji@)M)k3!*'6P*56NSq-L)0mFfYK@%j%15iJ%38!"KSiA(qIZFc Ci1,IfG(([E5VSjfANSk+KS5"IAYjH(GiH(TlIAjrIhprIRemHRKhGA9fH(TpJ)1 'LBb2NC+6Nj16NBk,KS&lFfTK@%p'26)Q'3d(#KJb8h@9X-A8hH$IfY,)[V5VT*b ANiq,L)@#J(elHAKiHATlI(eqIRprIRemHRPhGhGhHATmIS'%KiU0Mj'5Nj16NSq -LB4pGQeNA&0+36FV(3m&"4!S5'b1UX(5hH,Kh06,`EHZTCqCP*!!M)Q'JS"pHhP iH(KjHRapIRprIhpqI(YjH(GfGhKkI(k!JiD*M)q3!*+6Nj15Mib)JhefEQ9F8dT #1#dJ%JJ'%#G(DSbT[p$Ei1$FeF["YkkPRjQ8N!#-L)D$J(elHAKhH(PkHhepIRj qIRemHhTiGhGiHATmIS#%KiU1NC18PC@8Nj'1LS9qGfjP@e*)2M8T'`m'"4%S4QQ +U,r3fq(KhGE0`lQ`Tk#DP*!!M)Q'Ji"pHhPhGhKjHRapIRprIhpqIAYjH(GhGhP kI(k"K)H-N!#5P*D@PT@6N!#0L)0mG'YL@%j%1LmM&JS%"K8a8R@@XFE9hZ(Jfp2 *[l@XT*kBNiq,Ki@#IhelHAKiHATmIAjrJ)#!IhjmHRKhGR9fGhTmIi+%KiZ0MT! !NT16Nj+3!)f*K(jhEfCG9%Y#15iK&3X($b0"Bi@MZmlDi1$GeXl$ZE#SS*U9NBf +Ki5"IRakH(GhH(TlI(jrIhprIRemHRKhGhGiHATpJ)+&LBb3!*+6P*58Nj+2LiD !HA"QA94,3MNZ)K3+"JdJ2&k!RlR-fH$KhYM2aEZaU+'EPT+1LiL%JAjmHAKhGhK jHheqIRprIhjpHhTiGhGhH(TmIS#$KSL,MT!!NC18P*14MSU'J(PbD&pA6N8p-bB D$`S0(6GAHCLbaY6FhphBd-HpY+ZMRCH6MiZ)KB*rI(TjH(KiHATmIAjqIRjqI(Y kHAKhGhKkI(k!Ji@)Lif2NC+5Nj15Mib)JRadE'0D88Jr0#JD$JF*&c&4Fj5[a02 Fi0rDdmR!YUfPRjQ8N!#-LB@#IhakH(GhH(PkI(epIRjqIAalHAKhGRCiHAYqJB5 (LSf3!*+6Nj56NT!!MBU'JATcDf*C8%Fp-bFF%3X0'c06GC5Z`p,EhYhCdFQrYUf PRTL6Mib*KB+!I(TjGhGiHATmIAjqIRjqIAakHAKhGhPkI(k!JiD*MBq4Nj58Nj1 4MSU'J(PbD@"A6dBp-bFD$`N-'M*5G*1Z`p2Gi0rEdmV!YkkPRjQ8N!#-L)D$Ihe lHAKiH(PkI(eqIRpqIRalHAKhGRGiHAaqJ)1&L)Z1N!#5NT16NT'1LiL#I(9YC&Y 558!h,#!9$3`@+NGSL+@mcGMHhY[9c-+jX+HKQj@4MBU(K)&qI(TiH(KjHRYmIAj qIRjpI(TjH(GiH(PlI(erJS@*M)q4Nj59PC55MiZ&IhG[C9a656me+Kd5#JJ5*d0 NKU1lcGMHhpc@cF5kXDQKQjD4MBU(K)&qI(TjH(KjHRYmIAjqIRjpI(YjH(GhGhK kI(q#K)H+MBq4Nj58P*14MSU&IRG[CPa55$ic*aS0!`)0*89UM+R"dYhLiYlAcX@ kXDLKQj@4MBQ&JRpmHAKhGhGiHRapIRprIhpqI(YjGhCfGhKkI(k"K)H,MT'6P*@ 8Nj+2M)L$IA9YC&T45$me+ai5#JS8+8GRL+@mcYVIi0c9cF5kXDLKQj@4MBU'K)& qI(TjH(KjHRapIRprIhjpI(TjGhCfGRKkI(k"JiD+MC!!NT18P*56NBf+KApiF'G H9%T!0LSG%!F%$L4$CSLP[Y$EiH,Heml%ZV'SS*U9N!#-LSH%JAjlHAKhH(KkHhe qIhq!IhjpHhPiGhCfGhPlIB'%KiU1N!#4NT18P*14MSU&IhK`Cej@6%-k,Km4"3% )($YJJk1mcp[LiprBcm@lXUQLQjD5MSU(K)&qI(TiGhKiHAYmIAjqIRjpI(YjH(G fGhKjHRf!JS@*M)k4Nj@9P*15MiZ'J(PbD9p@683k,b%6"`)*(6aJJU'kcGRIi0h @cF1kXDLKQT@4MBQ(K)&qHhTiGhKiHRYpIRprIhpqI(YjH(GfGRGjHhf!JS@)Lik 4Nj58P*14MSZ'JATcDf0D8NJr0#FD$`N0(6KCHTLaaG,Ch0V8cF5kXDQKQjD5MSZ )KB*rI(TjH(KjHRYmIAjrIhpqIAYjH(KiH(KjHherJB5)M)q3!*'6P*16NBq,Ki* lG'aL@9")2c8S'Jm,%#%mA(fEXmE5fG[Ce-[#ZE#SS*U8N!#-LBD$J(jmHRPiHAP kI(eqIhprIhjpHhTiGhGhH(PlIAq#K)H,MT!!NT16Nj+3!)k,KS&mG@eNA&0+3MJ X(a32%b)m@hZBVm,1eGI9d-R!YkqRS*U9NBf*Ki5"IhakHAKiHATmIAjrIhprIRe mHRPiGhGiHRYpIi+&L)Z0Mj'5NT+4Mif+KS&mG@jQAeC24Mdb*adB'53j9(12TlV (d026cmM!Z+qSSCZ@NSk+L)@#J(jmHRPjHATlIAjqIhprIRelHRPiH(KiHAYmIi' $KSQ,MBq3!*'4NC!!MSb)K(jhF'PJ@9"*3$8T(aNC)cK6FBfNYmA0dG$0aVqfVUH JQT@4MBU(K)+!IAYkHAKjHAYmIAjrIhpqIRalHRKiH(KjHRYpIi+&LBb2NC+5NT+ 4Mib)JhpjFQTM@e*,3cN[*4iG*6G3E)HHXX$*cFh+aEkhVUHKQj@4MSZ)KB1!IRa kHAPjHRYmIAjrIhpqIAalHRPiH(PkHhaqJB1&LBb0Mj!!N!#3!)q1M)U(K(pjFfa PA9C24cdc+L3L+6P2DB5EVVc&bX[)`lffVUHJQT@4MBZ)KS1"IhelHRPjHRYmIAj qIhjqIAalHRPjHAPkHhaqJ)+&L)U-MT!!N!#3!*!!Mik,L)4rHR0XC9jA8%P#1#m T*L`j6@H!PUQi`FE)aX+lY+fQS*U9NBk,L)D$JAppHhTjHATlI(eqIRprIRjpI(Y kHAPkHhapIi##K)D*Lif1Mj!!Mik0LSH%J(TeEQKK@P404$Xb+LFX18jRJ*DSYVr %aX6!ZE1XTCqCP*!!MBU)KB1"IhelHRPkHRYmIAjrIhprIRemHRTjHAPkHhaqJ)+ %KSQ,M)f0MBf0M)U)KB&mGh&VC&jB88P!0bmU+cG+BRZ4Sl+l`F2#[VLbUk@HQC@ 4MBU)KS1"IhelHRTkHRYmIAjqIhprIRemHhTkHATkHhapIi'$KBL,MBk2Mik0M)U (K)&mGh*VC&jA88T!0c!X-$Y0C(b4Sl#k[m'rZlD`UD1GQ*53!)b+Ki@$JAppI(Y kHRYlI(eqIhprIhjpI(YkHAPjHRYmIRq"Ji@)LSb0MSk1MBb+Ki5"I(GbE'CJ@P4 04$Xe-M9!8'9lMk#YYEZpZlLcVULLR*H6Mib*Ki@$JB"qIAalHhYmIAeqIhprIhj pI(YkHRPkHRYmIRq"Ji5'L)U,M)f0MBb+L)D#IRTdEfPMA9G34cmh0$Br6f0iM*f UXlLkZEHbVDHJQjD5MSb*Ki@$JS"qIAalHhYmI(eqIRprIhjpIAalHRTkHhapIS# #Ji@(LBU+LiZ,LiU*Ki5"IRTeEfTPB&Y96N8q1MNr6&pcKjLPVl@iZ,@aV+DKQjH 6Mib+L)D%JS"rIAalHhYlI(eqIRprIhjqIAalHhTkHRYmIAq"JS5'KiQ+Lib-M)Z *Ki@#IhYfF@aRB9a@6dFr1MT!6Q"dKjHNVE1eYE1[UU5IQTD5MSZ*Ki@$JApqI(Y lHhYlI(eqIRprIhjqIAalHRTkHRYmIAq!JS1&L)U,M)b-LiZ*Ki@#IhYhFQeTC&p D8da&3$j$6PpaJj+IU+kaXV#YU+1HQC@4MBZ*Ki@%JS"rIRemHhYmI(eqIRjqIRj qIAamHhYkHhYmIAk!JB1&KiL*LiZ,LiZ+L)D$J(ejG'pUC@"F9e"+480(8&eYISf DT+UZVkkVU+1HQTD5Mib*Ki@$JS"rIRemI(amIAeqIRprIhjqIAemHhYlHhapIRq !JB+$KBH)LBU+LSQ)KiD%JAjkGR*ZD@9KA&G46%P+8&YTH)H8RD@TUkZTTU+HQTD 5MSb+L)D%Ji&rIRemI(amI(epIRjqIRjqIAepI(amI(apIAjrJB1%KSH)LBQ+LSQ )Ki@$JAjlH(4`E'KNAeT86dY,8&TSGi@5Qk+RUDQRTD'GQC@4MSb*KiD%Ji&rIRe mI(amI(epIRjqIRjqIRepI(amI(apIAjrJ)+$KBD(L)Q*LBQ)Ki@$JApmH(4aE@P PB&Y@8Np29&eTGS52Q*qMTUDNSTqEPj53!)f,LBH'K)1"J(pqIAamI(epIRjqIRp rIRjqIAamI(amIAeqIi#"JS5&KSD(KiL)KiD&K)+!IAThFh"XD'4J@eG88eCGCh1 !Lj5ERk+MSU#GQTD6N!#0LiQ(KS5$JS&rIRepI(apIAeqIRjqIRjqIRepI(amI(e pIRq!JB+$KBD(KiL)L)H'KB1#J(jlH(9bEQYSC'"F@&CBA@9`I)H3!*DERk#JRTb CPT12MBZ*KiD%Ji+"J(pqIAepIAepIRjqIRjqIRjpIAepI(epIAjrJ)#"JS5&KSH (KiH(KS@%JS&rI(PfFh"XDQGMAeaD@PjQF(U%MC1BR*fGR*UBPC+2MBZ*KiD%Ji+ "J(pqIRepIAeqIRjqIRjqIRjqIAepIAepIAjrIi#"JS1%KBD'KSD'KS@$JS&rIAY iGA0`E@TRC'&IAf&QEACrL)k8Q*QDQTL@P*'2M)U)KiD%Ji+"J)"rIRjpIAeqIRj qIRjqIRjpIAepIAepIRjrIi#"JS1%KB@'KSD'KB@%Ji'!IRakGh4bEfaTCQ*JB'& QERCrKif5PTHBQ*D8NT!!MSb+L)H&K)1#JB"rIhjqIAepIRjqIRprIhjqIRjpIAe pIAeqIRq!JB+#Ji5&KB@&KB5%Ji+"IhjmHRKfG(&[E@PRC@4PD@pfIS5+Mj+8PC@ 8NT'2M)Z*KiD&K)1#JB#!IhjqIRjqIRjqIRprIhpqIRjqIAepIRjqIRq!J)'#Ji1 %K)5%K)5%Ji+"J(pqI(TiGR0aEfaTCfCRDQpfIB1*MC!!NT16NT'2MBZ+L)H&K)1 #JB'!IhpqIRjqIRjqIhprIhprIhjqIRjqIRjqIRjrIi#"JB+$Ji1%K)5%Ji1#JB& rIRelHAGfG(*[E@YTD@a`GRb#KiZ1Mj!!N!#3!)k0LiU)KiD%K)1#JB'!J(prIRj qIRjrIhprIhprIhpqIRjqIRjqIRprIi#!JB+#Ji1$Ji1$Ji+#JB"rIRemHRPhGR4 cF@pYE@pbGRZ!K)L,M)f1MBb,LSL(KS@%Ji+#JB'!J(prIhjqIRjrIhprIhprIhp rIRjqIRjqIRprIi#!JB'#JS+#JS+#JS+"JB"rIhjmHhTjH(GeG(*aFA*dGhYrJiD )LSZ,LiU*L)H'KB5$JS+"JB'!J(prIhprIhprIhprIhprIhprIhprIhprIhprIi# !J)'"JB'"JS+#JB'"JB#!IhjpIAalHRPiGhCeG(9fH(YrJB5'KiL)L)L(KS@&K)1 #JS'"JB#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#"JB'"JB'"JB' "J)#!IhpqIRemI(YkHRPiH(KjHRaqJ)+%KB@&KB@&K)5$JS+#JB'"J)#!J)"rIhp rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!JB'!J)#!J)#!IhprIRjqIAe pI(alHhYlI(erJ)'#JS1$Ji1#JS+"JB'"J)#!J)#!J)"rIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhjqIRjqIhprJ)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)!!!%*!!!%!!3!&!!!!S!! "J&%!!!!!!"3!!!!!!!"#&PEZLk-!!%)8!!"#&3!mJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhpqIRjqIRepIAa mI(amHhKhGhGiGh9dG(CkIAjrJ)'#JS+"J(jlHAKiHi##JS+#JS+#JS+#JS1"H') p)"dJ(b-R,$)f1MSh1$BY'`B!#!`1$`S$#KNR-cJk2N0)6P0DAQ&J99&CB@adGA9 fHAk&LBZ0N!#5NT+4N!#2MBU)L)Q0NC'4N!#3!*!!N!#3!*!!N!#3!)q2MiPkBe* 26Nj38eCDAQ"IAPpG98-`+5SV,#`Q)b`i3da38P9DAQ0RDfj`E'*LDh4qJi+#JiD -NT@AQCZGRCfFQjQAPC56PCQEQjZEQjZDQTUDQTUCQ*1#E&pF@PTFAf0QD@YUD@T SANXl0cJi1$Fa-6Y'89KDA@&PD@eaGAGiFQTZGhq)LiU,M)q9QTbHSD1NT+5MSU# HR*ZERU+LSU+LSD'KSD'JS+#JS*U(FQGPBf0NCfYZFA*bFA*`C&"$38"!3$ii1N9 3@Q"LC@KXF(4iHhemGA&hIiL2N!#3!*!!NT@DRk'MTDHTUDLSTU5LSD#JSkDQTUD QTU@PTD@PT+5NT*k-GfeUD'KUE("cGRGfGRGfD99+5%C'4N-p3%Y9Af9RDQeaG(K mIi"qGh9mK)f6Nj16PCQHSU5QU+UXV+ZVUDHPT+1NTkQTUDQTU+LSU+LRTkHRTk+ 4I(*[E'YYEh*fHATjHATkE9P16%T+5NC"4%jBBQKUEA"cGhYqJB*rH(KrKSq9PC@ 9PjUJSk@RUDZYVUfYUkQRTU@QUDZVUkZUUUUUUUQTUDQSU+@@J(CcEfj[FA4iHRa mI(amF&e58%e-5dK#49"CBfPVER*eHAarJB1"HAQ"L*'APTDAQ*ZJT+DSUUbZVkq ZVDZTTkDRUkfXV+bXV+ZVUkZUUUUUUDLEKATeF@p[FA9iHhamIAepFf"98Np06%P $48pBBQPXEh*fHAarJS1!HAQ"LC'APjHAQ*ZJT+DSUUbZX+q[VDZTU+HSUkfYVDb XV+bXUkZVUkUUUDQJM(eiFh"`FA0hHRapIAeqG@0A9&"168Y&4%e@B'KVER*eH(a qJ)&rH(L!LC'APjHAQ*UISkDRUDZYVkq[VDbUU+HSUkfYVDbXV+bVUkZVUUUUUUQ MNS*kGA&[F(*eHAYmI(apGfCC9&"06%T&3NP6A'9UE("cGRTmIS"qGh9qKiq@PjD @PjQGSU5QU+UXVUq[VDbUU+HRUUfYV+bXV+ZVUkZUUUUUUUQQQBKpH(*[Eh"cGRP lHhamH'YF9P*05dT'3%419f&SDQjaGAKkI(jpGh0jK)f9PTD@PTHDRk1PTkQVVDq ZVDbUU+HRUDbXV+bXUkZVUkUUUUUTUDQRRiq"Hh9`EQj`G(GjHRTlH@pK@9426%T (38"+8eaPD@a[FhCiHRamGh&fJ)Q5PT@9PCDBRD'MTDHTUkfZVDbUU+HQU+ZXV+Z VUkZUUUUUUDQTUDQSSjH*IhKbEfeZFA4hH(PkHA*PA&G46%T)3Me%69CJCQPYF(0 fH(TkH("aHS51PC58P*5@QCkKSk@RUDZYVDbUU+HQTUQVUkZUUUUUUDQTUDLSU+L RTCf2K(eeF'eYER"dGRGhH(4TAPP66NT(4$ip4NpBBQGUER&dGRKiGh"YG(k)NT5 6Nj18PTZISD1PTkQVV+bUU+DPTDHUUUUUUDQTUDLSU+LRTkHQTU+@LS*lFfpXE'e `Fh9eGR9XBPa@8%Y(48!l2NK3@f0QDQe`Fh9fGA&UEAH!Lj+5NT+5NjDERU#LT+D SUUZUU+DPT+@SUDQTU+LSU+HRTkDQTUDQTD5GN!#(JAPaE@YUE'paFh0dF'9I@e4 15NC$2$P!59*GBfCTEA"bG(4bE'K`HB11NC'4NC'6PTZHRk'MTDHTUULQTD5MTDL SU+LRTkHRTUDQTD@PTD@NSTQ,KB"hF'aUDQYZF(*bFQTJAPT568K%3$Ni3NT8AQ0 QDQe[FA*bEQGSFRZ'Mj!!N!#3!*!!N!#5PjZGRk'MTDHSU+HPT+1MTUHRTkHQTUD QTD@PTD5NT+5MRj1(K(jeEfYTD@YYEh"aEf9HAPK35dC#1c8j3NY@AQ*QD@a[FA& `DQ9UG(f)MSq2MSq3!*1AQTbHS++NTUHRTU5MSU1QTkDQTUDPTD@PT+5NT+1MSk' CM)@$I(0YDQKTDfeZEh"XB9eH@&"+4$mf-cY%69KHB@9SE'j[F'jRBfYeISQ0MBf 0MBq6PjQERCqKSk@RTk@MSU+MTDDQTD@PTD5NT+1MSk1LSU'GNB@%JAKaDfKSD'T XE@j[DPpGAPK358)j-63q4P"CA'"ND'YYEfpXC'0XGAq*M)Z,Lib2NjDBQTbHRk' MTD@NSU'KSk@PT+5NT+1MSk1LSU+LSD'IPiQ$JhjdEQPRCfKUDfaZEfPIA9pD8%F q-Lmi38T69eYJC'KVE@pZDf0MEAD!LBU+LSU-N!#6PCHBQTbHS++NT+1LSD'LT+5 NT+1MSk1LSU+LSD'KRjU0Ji1"HA*XD'GRD'PUE@p`D9pHB&T246FZ-ca%6P0@@f" ND'YYEfjUBf0ZGi#)LBL)LSf4Nj5@Q*QERCqKSk5MSD#KSk5NSk1MSk+LSU+KSD' KRjb4K)+$IR9ZDQGRD'PTDfj`F'KIAf"D6Mmb-6P!5Np59PYJC'KXEQpZD@*PF(L #L)H(L)U1NC+8PCHCQjfISD+MSU'JSD1NSk1MSk+LSU+KSD'KS*f6KS'$J(PaE'K RCfKSDQe`FR&RAepI@%Ni-cJq4de28PGEB'9TE'j[E@GLD(*kJiH'KSQ-Mj!!NC1 9PTLDR*kJSU1LSD#KSk1MSk+LSU+KSD'KS+#GPBL#JS&mG@eTCfGRCfPXEh*dF'9 HAPa53$Fk2N9,68p59eaKCQTYEfpYCQ0VG(f%KB@(LSf1Mj'5P*DBQTbHS+'LSD# JSD1MSU+LSU'KSD'JS*qGPSL"JS*qGfpVD'GRCfGUER&dG@eKA9a94cdp3%9,6%e 29&KHBfGVER"[Df4PEhGrK)5'LBb0MSq4NT5@Q*QERCqKSD'JS++MSU+LSU'KSD# JS*qGPBL"JS*rHA&XD@GRCQGUEA&eGR4SAPY@5d9%4%K-6%a1899DB'9UER"`EfK MDR0kJB5&LBU,MBk2NC+8PTLDR*kIS+'JS+'LSU+LSU'KSD'JS*qGPBH"JS+!Hh0 YDQKRCQGUEA&eH(G`BPY95dP-5de168e06e0BA@0SE'paF@ePCQphIB1'L)U,M)f 1N!#4Nj5@Q*UFRTqJSD#JSU+LSU+KSD'KS+#IR*+'JB+#JAadEfYSCfCRDQeaGAK jG@GE8dY-8P*58Np16Nj49PYKCQY[FA*`D@9XG(Z#KSL*LSZ-MBk3!*'6PCHBQTb HRk#JS+'LSU+LSD'KSD#JRjZ2Ji+#JS&pG@pVD@GQCfTZFRCjHRGV@e"+6PCB@&9 46dj18&4CAf9UER&cFQeQDA*iJ)H)L)Q+Lib0Mj!!NT19PjQERCkIS+#JSU+LSD' KSD#JS*kBM)+#JS+"IAC`DfPRCQGUER*fHATiEPa16&*BA9jB8e&26P"6@&eMD'e aFh0[CfG`Ghq'KiH)LBU,M)k2NC+8PTLDQjfHRjqJSU+KSD'KSD#JRjf9L)+$JS' "IAC`E'PRCQKVEh0hHATjF&e-6P9DB@0F9e048&"59eaLD'eaG(4aD@G[Ghk'KiH )LBU,M)f1N!#4Nj@AQCUFRCkIS+'LSD'KSD#JS*kENB@#Ji+#JRefF'aTCfGTE(" dH(TlHA"F6&&CA@4QB&T@8e&48eGFB@GYFA4eFfYSEhGqKSL(L)Q+LSZ0MSq4NT5 @Q*UER*kIS+'LSU'KSD'JS*kBLi1%K)+#JRafF'aTCfKUEA&eHAYlH'jD6e9FB@C QBejB99048eGFB@KYFA9fG'eTF(KrKSL(L)Q*LSZ-MSq3!*+8PCHCQjbGRU#KSU+ KSD'KS*qFNSD$K)5$Ji&mG("XD'GTDfpcGhTmHhCV@90CAf9RCf9J@PG88P4AA'& SEA&eGR4YDR&jJ)D(KiL)LBU,M)f1N!#4Nj@AQ*UER*kJSD+KSD'KS*qGPiZ%K)5 $Ji1"HR0[DfKSDQeaGAKkHhPcCPTBA@4RCfKSBeeC9P489eaLCfebGACdEQYcHS# 'KiH)L)Q+LSZ0MSq4NT5@Q*QER*fISD'KSD'KS*kEN!#&K)@%Ji1$IhKbE@TSD@a [FhGkHhYhE@9JA@&SD'KTD@CJ@eG99PKGBfKZFhChG@jYGAb"KSH(L)L*LBU,MBk 2NC+8PTHCQTZGRk'KSD'KSCqFP)L%KB@%Ji1#IACaE'PTDfjbGRPlHhPbDQKMB'G UD'KTDQGLA9PA9eTIC'P[GAGiG@p`H(f#KiL)L)L*LSZ,MBk2NC+8PTHCQTZGRk+ LSD'KS*fALi@'KS5%K)5"HR4ZDfTVEA&eHAYlHR9YE@eQCQTTD@PUDfPMAeYB@9a JC@YaGAGiGA"bHRq%L)L)L)L*LSZ-MBk2NC+8PTHCQTZGS++LSD'JRTL0KBD'KB@ %KB0pGR&XDQYYF(4iHRalGQpZFfpTD@TUDQTVE'TPB&aD@eeLCfebGRKiGA&eI)' 'L)L)L)Q*LSZ-MBk2NC+8PTHCQTZGS++LSD#HQSq'KiH&KB@&KB&kFfjVDfe[FhG jHhTfF'peG@pUDQYVDQYXE@YPB&eEA&pNDQpdGhPjG(*jIi1(L)L)L)Q*LSZ-MBk 2NC+8PTHBQTZHS+'KS*kDMiD(KiD&KB@&JhaeEfaXE@pcGRPlHhG`FAGkGfpUDfY VDfaYEfaQB&eGAQ&RE(&eH(TiFh9pJ)@)L)L)L)Q*LSZ-MBk2NC+8PTHCQTbISD' JRTU2KiH)KSD&KBD%IRGaEQaYEh*fHATkGh"bHAamGQaVE'aXE'e[F'aQB9pIB@9 UER0hHRYeFRQ!K)L)L)L)LBQ+LSZ-MBq3!*'6PCDBQCZGRk+KRTQ1KiL)KiD'KSD &J(KcEfeZF(0fHATkGh&cHhjrI("VE@eXE@eZF(&XCQ*JB@0REA*fHRajFhGqJSH *L)L)LBQ*LSZ-MBk2NC+8PCHBQTbHS+#HQ)f(LBQ(KiD'KiD#HR4`EQj`FhCiHRT fFA4mIi+!G@aXE@eYE@j`FR"UC@*LBfCVF(9jI(YeGAb#KSQ*L)L*LBQ+LSZ-MBk 3!*'6P*DBQCUGRk#HQ)f(LBQ)KiH'KiH%I(9aEfj`FR9iHRPfFR9pJB1#H@jXEQe YE@j[FA*ZD'4LBf9TER0hHhYhG(U"KBQ+LBL)LBQ*LSZ-MBk2N!#5Nj@@Q*QERTq HQ)k)LBQ)KiH(KiH&IhGcF'p`FR9iHAPfFR4pJB1$I(&XEQjZEQj[FA0aE'GNBf9 SE(&fHRYiG(Q!K)L+LBL)L)Q*LSU,M)f1N!#4Nj5@PjLDRCkGQT!!L)Q+LBL(KiH (Ki*kGA&[F(&dGhPjGh*dIB'$K(jbE'jZEQjZEh"bFfpTC@4NCfY`G(KkHA4iJ)5 )LSQ*LBQ*LBU+Lib0MSq4NT59PjLDR*fGQT'*LBU*L)L(KiH)KAjhFh&`FA0fH(P hFh0lJB5&Ih4YEQpZEQj[F(*dF@YRC@4QDQjcGhPjGAH!KBL,LSQ*LBQ*LSU,M)f 1Mj!!NT19PjLDR*kGR*5,LBZ+LBL(KiL)Ki0lGR*aFA0eGhKiG(*jJB5&JAGZEQp [EQj[F(&cFfjSCQ9QD'aaG(GiGACrKBL,LiU*LBQ*LSU,M)f1Mj!!NC18PTHCQjf GR*L1LBZ,LSQ)L)L)L)D!HA9bFA*dGRKiGA*hJ)1%JhP[EQp[EQjZEh&bG("UCf9 PCfTZFR9fG(CqKBL-LiU+LBQ*LBU+Lib0MSq4NT59PTLDR*fGQT+*LSZ+LBL)L)L )L)4qH(4bFR0eGRGfFR0mJS1$I(&YEfpZEQj[F(&cFQeSC@4QD'a`Fh9dG(Z$KiZ -LiU*LBQ*LSU,M)b1Mj!!NC18PTHCQjfGQjD-LBZ,LSQ)L)L)L)L$HhGdFR*dGRG hG(*iJB1%J(9ZEfpZEQjZEh"bFh&VCf9PCfTYFA0cFRL#KiU0M)U+LSQ*LSU,Lib 0MSq4NT59PTLDR*fFQT++LSb,LSQ)L)L)L)H"HhGcFR0dGACeFR0mJi1$HR"[F'p ZEQj[F(&cFfpTCQ9PD'YZFA*aFhk'LBf0M)Z+LSU+LSU,M)f1Mj!!NT18PTHCQjf GR*L1LSb-LSU*L)L*LBQ(JAYhG(0cG(9fG(&fJ)1$Ih4[F("ZEQjZEh"aFh*YD@C PCQKXEh&`F(H$L)b1MBb,LSU+LSU,Lib0MSq4NT19PTLDR*fFQj@-LSb-LiU*LBQ *LBQ(JAYhG(0cG(9eFR&jJB1#Hh&`F@pZEQeZEh"aFR&XCf9PCQKVEQpZF(b'LSk 1MBb,LSU+LSZ,M)b0MT!!NC+8PCHCQjfGR*U5LSZ0M)Z+LBQ*LBQ*Ki*lGh4cFh4 dFh"bI)+#J(G[FA&[EQeYEQp`FA*`DfGPC@CSDfeYEA1!L)b1MSf-LiU+LSU,Lib 0MSq3!*'6P*DAQCZGRCZBN!#+M)f-LiU*LBQ*LBQ(JRYhG(0cG(4bEh4qJS*qFfp aF'pZE@eZEh"`FR"XCf9PCQKUE'YXGS+*MBq1MBb,LSU+LSZ,M)f1Mj!!NC18PTL CQjfFQTH1LSf0M)Z+LBQ*LBQ*L)0mH(9dFh0cF@peIi+"I(*`FR"[EQeYEQp`F(* aE'KQC@CSDQYUE(Q%LSq2MSf-LiZ,LiZ,M)b0MSq3!*'6PCDBQTbGR*U9MBZ1MBb ,LSQ*LBQ*LBQ%IRPfG(4cFh&[Gi#"JATaFA*`EfjYE@j[Eh"bF@aSCQ9PCfPTD'e kKBU2N!#2MSf-LiZ,LiZ-M)f1Mj!!NT19PTLDR*fFQT@0Lik1M)Z+LSQ*LSQ*LBD !HRGeG(0bF'phIi'!HA&aFR"[EQeYEQj[F(&bEQPQC@9QD'KRE(Q%Lj!!N!#2MSf -LiZ,LiZ-M)f1Mj!!NT18PTLDQjfEQC@1Lik1M)Z+LSU+LSU*LBH#I(KeG(0bEfj fIi'!H("aFR"[E@eYE@j[Eh"bEfTRC@9QCfGQDhQ$LSq3!)q1MBb,LiZ,LiZ-MBk 2N!#4NT5@PjQERCZCPBf,MSk0M)U+LSU+LSQ*LB9qHRGeFh*[EA4pJ(piFA*cF@p YE@eYEQj[F(*`DfKQC@9QCQ9UH)+*Mj!!Miq0MBb,LiZ,Lib0MBk3!*'5P*@AQCU FR*U@MiZ1MSf-LiU+LSU+LBQ+L)*mH(CdFQpYFRarIhKaFR0aEfjYE@eYEQp`FA& YD'CPC@9PBfKfJBH0N!#3!)q1MBb,LiZ,Lib-MBk2N!#5Nj@@Q*UFR*UAN!#,MBq 1M)Z+LSU+LSU*LSU&IhYhGA0`EA"jIRjjFR*dFR"ZE@eYE@j[Eh"bF'YSCQ9PC'* QFhk'M*!!N!#2Mik0M)Z,Lib-M)f1Mj!!NC18PTHCQjbDQ*+-M)q1MBb,LSU+LSU +LSU)JhjkGR4aEQjfI(ejFh*dFh&[EQeYE@jZEh"aF@eTCf9NBf*NEhb$LSk3!*! !Mik0M)Z,LiZ-M)f0MSq4NT19PjLDR*UBP)f,MSk0M)Z+LSU+LSU+LSU(JAajGA0 [EA*kIATdFA4dFR"ZE@eYE@jZEh"bF'YSCQ4MB@&UH)#(M)k2Mik0M)b,LiZ,M)b 0MSq3!*'5P*@AQCZDQ*D3!)Z0MSf-LiU+LBU+LBQ*LSU'J(aiG(&YERClHR9aFh4 bF@pYE@eYE@jZEh&bEQTRC@0KB'9cIB1*M)k2Mik0M)Z,LiZ,M)b0MSq3!*'6P*D BQTZCPj1-Lik1MBb,LSU+LSU*LBU,LS9rHhGcEfe`H(TfFA*dFh*`EQeYE@eZEQp `FR&YD@CNBPpKE(L!KSZ0Miq1MBf-LiZ,Lib-MBf1Mj!!NT19PTLDQTL@MiU-Mik 0M)Z+LSU+LSU+LSZ+KApkGR*ZEA0jH(0aG(9cFA"ZE@eYEQjZEh&cF@aSCQ0JAf9 bI)+)Lif2Mik0M)b,LiZ,M)b0MBk3!*'5P*@AQCUCPj50LSk2MSf,LSU+LSU+LSU +LiU&IhTfF@eZGAPeFA*eG(*aEfjZEQjZEQp`FR0`E'KPBPjJDhCpK)Q,MBq2MSf -LiZ,LiZ-M)f1Mj!!NC+8PCHCQTL@NBZ,Miq0M)Z+LSU+LSQ*LSU-LS9rHR9`E@p fGh*`Fh9dFR&[EQjZE@jZEh"bFh"VCf4JA@*[HAq&L)Z0Miq1MBb,LiZ,Lib-MBk 2N!#4NT59PjQBPT51LBb2MSf-LiU+LSQ*LBQ+LSb+K(jjG'pYFRGeF(&dG(0bF'p ZEQjZEQj[F(*cF'YRBepHCR*kJ)D)Lif2MSf0M)Z,LiZ,Lib0MBk3!*'5P*@AQ*D 8NBU)MBq1MBZ+LSU+LSQ*LBU,M)U%IRKbEQpeH(4`FR9dFh*`EQjZE@jZEQpaFh4 aE'GMAepTG(Z"KSQ,MBq1MBb-LiZ,LiZ,M)b0MSq3!*+6PCH@P*+-KiQ1MSf-LiU +LSU*LBQ+LSZ-L)*mGR"[G(PjG("bGA4cFR"[EQjZEQj[F(&cGA*YD'4JB@YfI)+ (LBb1Mik0MBb,LiZ,LiZ-M)f1Mj!!NT19PT55MSH'Lik1MBb,LSU+LSU+LSU,MBb (J(TcEh0kHhTdF(0eG(0aF'pZEQjZEQp`FA4fG'jTC@"LERGpJiH+M)q2MSk0M)Z ,LiZ,Lib-MBk2N!#4Nj58NBk)JiH,M)f-LiU+LSU+LSU+Lib0Li4qGh&bHRepI(4 `G(9dFh&[EQjZEQjZEh"bG(CeF'YPB@4[H(k%L)U0Miq1MSf-LiZ+LSZ,Lib0MBk 3!*'6NT!!MSL#K)Q+Lib,LiU+LSU+LSU+Lib0LB&kFh"iIhprI(4aG(9dFR"[EQj YEQjZEh"bG(GfF@aQBQGbHRq&L)Z1Miq1MBb-LiU+LSU+LiZ-MBk2NC'1M)L"JBD )LBU,LiU+LSU+LSU+Lib0Li4pGR&hIi+"J(TbFR9eG(*`EfjZEQjZEh"aFh9hH(0 YCf4UGAb"KSQ-MSq2MSf0M)Z+LSU+LSZ,M)f1N!#3!)k,Ki"rJiD(L)Q+LiU+LSU +LSU,M)k0Ki"iFhCqJi5#IhKaFh9eFh&`EQjZEQj[Eh"bG(CiH(0YCfC[H(k$KiZ 0MSq1MSf-M)Z+LSU+LSZ,M)f1Mif+Ki"pJS@'KiH*LSZ,LiU+LSU,M)f1Li0kG(G qJiD&JAefFA4fG(0aEfjZEQj[Eh"aFh9hHRPdE@GUG(Z!KBQ-MSk2MSk0M)Z,LSU +LSU,Lib0MBZ*KAjlJ)1%KBD(L)U,LiZ+LSU,M)f1Li4lGAKrJiD(Ji"kFh*eGA0 aF'jZEQjZEh"`FR4fHAYjFfaTEhPqJiL,MBk1MSk0MBb,LSU+LSU+LSZ-MBU(Jha kIi+#Ji5&KiQ+LiZ,LSZ,M)f1M)9mGRQ!JiD)KB*qGR&dGA4bF'pZEQjZEfp`FA0 eH(TmHA*XEACpJSD*M)f0MSk1MBb,LSU*LBQ+LSU,LiL&JATjIS#"JB+$KBH*LiZ ,LSZ,M)f1M)CpH(b#K)H*Ki1!HR0bGA4cF@pZEQjZEfp`FA0eGhPmI(G`EA4mJ)@ )Lif0MBk1MBf-LiU+LBQ*LSU,LSD$IRKjIAq!J)'#K)D)LSZ,LiZ-M)f1M)CpHAq %KBH)L)@#IA9aG(9cFR"ZEQjZEh"`FA*dGhPlIAaeEh0lJ)5)LSZ-MBf1MBf-LiZ +LBQ*LBU+L)5"HhCjIAjrIi#"Ji@(LBZ,LiZ-MBf1MB9pI)'&KSL)LBH$IhGbFh9 dFR"[EQjZEh"`FA0dGRPlIAjkFh0lJ)1)LSZ-M)f0MBf-LiZ+LBQ*LBQ*KS0rH(9 jI(eqIRq!JS5'L)U,LiZ-MBf0M)9qIi5'KiL)LBH$J(TbFR9dFR&[EQj[Eh"aFR0 dGRPlIAppGR4lJB5(LSU,M)b0MBf-LiZ+LBQ*LBQ)K)&mGACkI(amIAjrJB1&KiQ +LiZ-MBf0Li0rJSH(L)L)LBL%JAYcFR9dFR&`Efj[Eh"aFR0dGRKlIAprHAClJS5 (LBQ+Lib-M)b-LiZ+LBQ)L)L&JAjiFhClHhYlI(eqJ)+%KSL+LiZ-M)f0LB1"KSL (L)H(LBL%JAYdFR4dFh&`Efp[Eh"aFR0dGRKlIAq!I(KpJi@)LBQ*LSZ-M)b-LiZ +LBQ)L)H$IhYdG(KkHRTlHhaqIi'$KBH*LiZ-MBb-L)1&LBL)L)H)LBL%JAYdFR4 dFh&`Efp[F("aFR0eGhPlIAq"IRTqK)D)LBQ*LSU,Lib,LiU+LBL)L)5!IACbGAP jHRTkHhapIi'$KBH*Lib-M)b+KS@*LSQ)KiH)LBL%JAYdFR9dFh*`F("`F(&bFh4 eGhPmIS#"Ihf"KSL*LSQ*LBU,LiZ,LiU+LBL)KS&qHA0cGhPjHAPjHRYpIi'$K)D *Lib-M)b*KSQ,LSQ)KiH)LBL%JAYdFR9dFh*aF("`FA&bFh4fH(TmIS#"J(q$L)Q +LBL)LBQ+LiZ,LiU+L)L(JhjlG(*fH(KiH(KjHRYpIi##K)D)Lib-LiU*LSb,LBL (KiH)LBL$J(TcFR9dFh*aF("aFA*cG(9hHAYpIi'"JS+'LSU+LBL)L)Q+LSZ,LSU *LBL%IhYeFA4hH(GhGhKiHRYpIi##K)D)Lib,LSQ,MSf,LBL(KiH)LBH#IhKbFh9 dFh*aF(&aFR0dGAChHAYqJ)'#JS5*M)b,LBL)L)Q*LSU+LSQ*L)@!I(GaFhGhGhG fGhGiHRYpIS##K)D)LSZ+LSb2MSb+L)H(KiL*LBD"IRGbG(9dFh*aFA&bFh4dGRG iHRarJB+#K)L0MSb+L)H(L)L*LBU+LSQ*KS&pH(*cGRGhGRCfGRGjHRapIS##K)D )LSU*M*!!N!#0LiL(KiH(L)Q)K)"lG(*eGA4cFR*bFR*cG(9fH(PlIS#"JS1'M)q 1M)U)KiH(L)Q*LBQ*LBD"IAKbFRChGhCfGAChH(PlI(erJ)1&KiQ*LBf5NBk-LBH (KiH)L)Q'JRjiFh0eGA4cFR*bFh0dGAChHAYpIi'#Ji5+N!#4MSb*KiH(KiL)LBQ *LBD"IAKcFhChGRCeGA9fGhKkHhapIi'$KBH)LBf6Niq-LBL(KSH(L)L)K)"lGA* dGA9dFh*bFh0dGAChH(TmIS##Ji1'MT14MSZ*KiH(KiL)L)Q*KS&pH(0cGRGfGR9 eGA9fGhPkHhaqIi'$KBD)MT56N!#0LSH'KSD(KiL)KB&qH(0cGR9eG(0cFh0dGAC hH(TlIAq"Ji1%Lj16Mif+L)D'KSH(L)L)KB"pH(0dGhGfGR9dG(9fGhKjHRYpIS# #Ji5'MT@8N!#0LSL'KSD'KiH)Ki*qHh9cGACeGA4cFh4dGAChH(PlIAq!JS1%L*' 9NSk,LBH'KSD'KiH)KB"pH(4eH(GhGR9eGA9fGhKjHATmIAq"JS1&M*@9NBk+L)D 'KSD'KiH(K(pmGR0eGRCeGA4dG(4eGRGiHAYmIS#"Ji1&MC@8N!#0LBH'KSD'KSH (KB"pH(4eH(KhGR9eGA9fGhKiHATlIAk!JB+%Lj5@NSq,L)H'KBD'KiH(KB&pH(4 dGhGfGA4dG(4eGRGiHATmIAq"JS1%Lj59NSq,L)H'KBD'KSH&JAjjGA9iH(KhGR9 eGA9fGhKjHRYmIRq"JS1*NTD8N!#-LBH'KB@'KSD(KB&qHR4dGhGfGR9dG(9eGRG iHATlIAk!JB+$L*+@Nj!!M)Q(KS@&KBD'KB&qHhCeH(PiGhCeGA9fGRGiHAPkI(e rJ)'#Kiq@PC'0LBH'KB@&KBD'KB&qHR9dGhGhGR9eG(9eGRGiH(PkI(jrJ)'#Kiq 9P*'0LBH'KB@&KBD&JRjlGh9iHAKhGhCeGA9fGhKiHATlI(jrJ)'&M*5@Niq,L)D &KB@&KBD&JAjlGR9hH(GfGA9eGA9fGhKiHATlIAk!JB+&MC59NSk+L)D&KB@&KBD $IhejGAGjHAKhGRCfGRChH(PjHRYmIAq!JB1*NC@9NBf*KiD&K)5&KB@#IhahGAG iH(GfGA9eGAChGhKjHAYmIAq!JB1+NT@6MiZ*Ki@%K)@&KB5!IAThGhPkHAKhGRC fGRGiHAPjHRYpIRq!JSD1Nj@6MiZ)KS@%K)5&KB0rIAPeGhPiH(GfGA9eGRGhH(K jHRYpIRq!JSL2P*54MBU)KS@%K)@&KB*qI(KfHATkHAKhGhCfGhKjHAPkHhapIi# "K)U4PC54MBU)KS@%K)5&K)"qHRGhHAPiGhCfGA9fGRGiH(PjHRapIRq!K)Z4P*1 2M)Q(KB5%K)@&K)"pHRGhHRTkHAKhGhChGhKjHATlHheqIi#"KBf5P*53!)b*Ki@ %K)5%K)&qI(KfH(PjH(GfGR9fGRGhH(KjHRYmIAjrJSL1NT55MSU)KS@%K)5%KB* qI(PfH(YkHAKiGhGhGhKjHATkHhapIRq!JSL1NT56MiZ*KS@%K)5%JRppHRGhHRT jH(GfGRCfGRGhH(KjHRYmIAjrK)Z3!*+6N!#-LBH&K)5%K)5$J(elH(GkHhTjHAK hGhGiH(PjHRTlI(eqIi#$LT!!NT55MiZ)KS@%K)5$J(jmH(GjHRTjH(GfGRCfGhG iH(KjHRYmIAk!KSb2NC+2LiQ'KB5$K)5%JhppHRGiHhYkHAPiGhGhH(PjHRTlHha pIRq"K)Z3!*+6NSk,L)D&K)1$JRppHhGiHRTkHAKhGRCfGhGiH(KjHATlI(eqJSQ 0Mj'4MSZ)KS@%Ji1%K)&qI(PhHAYlHhTjH(KiH(KjHRTkHhapIRq!JBD0N!#5Nj+ 1LSL'KB5$Ji&qI(PhHAYlHRPiGhGfGRGiH(KiHAPkHhapIi1+MBq4NBk+L)D%K)1 $K)5"IRajH(TmHhYkHAKiH(KjHATkHRYmIAjqIi'(MC!!NC+4MSU)KS5$Ji1!IAY iGhPlHhTjH(GhGhGhH(KiH(PjHRYmIAq%LSf2N!#3!)k,L)D%Ji1$Ji1!IAajH(T mHhYkHAKiH(KjHATkHRYmI(eqIi+)MBq4NT'1LiL'K)1$JRppHhKhHRYlHRPiGhG hGhGiH(KiHAPkHhapIi@,MBk3!*!!MSU)KS5$Ji1$JRppHhPiHRalHhTjH(KiH(P jHRTkHhYmIAjrJSH0Mj!!NC'2LiL'KB5$JRjmHhKiHRYlHRPiGhGhGhKiH(KiHAP kHhapJ)@+M)k2Mik,L)D%Ji1$Ji*rIAYjH(YmHhYkHAKiH(KjHATkHRYlI(eqIi' 'M)k3!*'4Mib*Ki@%Ji*qI(TiH(YmHhTjH(KhGhGiH(KiH(PjHRYmIB#&LSb0MSq 1M)Q'KB5$Ji1#IhelHAKlI(alHRPjH(KiHATkHRTlHhapIRq"KSZ1Mj!!NC!!MBU )KS5$JRjmHRKiHhalHhTjH(GhGhKiH(KiHAPkHhYmIi5*M)f1Mik-LBH&K)1$Ji1 !IAakH(TmI(YkHRPjH(KjHRTkHRYlI(eqIS#&LSf2N!#3!*!!MSZ)KS5$JRjmHRK iHhamHhTjH(KhGhKiH(KiHAPkHRYmIi5*Lib0MSk-LSL'K)1$Ji1!IAakH(TmI(a lHRPjH(KjHRTkHRTlI(apIS#%LBb1Mj!!N!#2MBU(KB5#IRakH(KkI(alHRPiH(G hH(KiH(KiHAPkHhYqJiL+Lib0MSf,L)D%Ji1#JS&qI(YjHAYmI(YkHAPiH(PjHRT kHRYlI(eqIi+(Lif1Mj!!N!#1LiL'K)0rI(YiGhTmI(YkHRPiH(KiH(KiH(KjHAT kHhf#KiQ,Lib1MSb*Ki@%Ji1$JRpmHhPjHhamHhYkHAPjHAPkHRTkHhYmI(eqJ)@ +M)k2Miq2MBU(KB5!IAYjGhPmI(YlHRPiH(KiH(KiH(KiHAPkHhb!KBL+Lib-MBb +L)D%Ji1#JS"pI(TjHRamI(YkHRPjHAPkHRTkHRYmI(eqIi+)Lif1Miq2MSb*Ki@ #IRakGhKlI(alHRTjH(KiH(KiH(KiHAPkHRYqJiH*LSZ-MBf,LBH&K)1#JS&qI(Y jHAYpI(alHRPjHAPkHRTkHRYlI(epIS#&LSb0MSq2Mik,L)D%IhalH(KkI(alHhT jHAKiH(KiH(KiH(PjHRYmJBD)LBU,M)f-LSL'KB5$JS+!IAakHATmIAalHhTjHAP jHRTkHRTlHhapIRq#KiZ-MBk2Miq0LSL'JAelHAGjHhamHhTkHAPiH(PiH(KiH(P jHATlIS1(L)Q+LiZ-LiQ)KS5$Ji+"IhalHRPlI(amHhTkHAPjHATkHRTkHhYmIAj rJiL,M)f1Miq1MBU)K)"pHhKiHRamHhYkHRPjH(PjH(KiH(KjHAPkI)'&KiL*LSZ ,M)Z*Ki@%Ji+#JAjmHhPkI(epI(YkHRPjHATkHRTkHhYmI(eqJ)@*Lib0MSk1MSf +Ki0rI(TiHAYmI(YlHRTjHAPjHAKiH(KjHAPkHhf#KSH)LBU+Lib+L)H&K)1#JS" pI(TjHRepIAalHRTjHATkHRTkHRYlI(epIi+'LSZ-MBk1MSk-LSD#IRajH(TmI(a lHhTkHAPjHAPjH(KiHAPjHRYrJiD(L)Q+LSZ,LSL(KB5$JS&qI(YkHAYpIAamHhT kHAPkHRTkHRTlHhapIRq$L)U,M)f1MSk1M)Q&JAelH(KkI(amHhYkHRPjHAPjHAK iHAPjHATmJ)5'KiL*LSU,LiU*Ki@%Ji+!IAalHATmIAemHhYkHRPkHRTkHRTkHhY mIAk"KBQ+Lib-MBk1MBZ)K)"pHhKjHhamI(YlHRTjHAPjHAPjHAPjHATlIB'&KSH )LBQ+LiZ+LBH&K)1"IRalHAPlIAepI(YkHRTjHRTkHRTkHRYlI(erJiH*LSU,M)f 0MBb+Ki0rI(TiHAYmI(alHhTkHAPjHAPjHAPjHAPkHhf#KBD(L)Q+LSZ-LiQ(KB5 #IhalHRPkIAepI(alHRTkHRTkHRTkHRTlHhaqJ)@)LBQ+Lib-MBf,LBD#IRakH(P lI(amHhTkHRPjHRTjHAPjHAPkHRYqJS@(L)L*LSU,M)b+Ki@%JAemHRPkI(epIAa lHhTkHRTkHRTkHRTkHhYmIi1'L)L*LSZ,M)f-LSL&JAjmHRKkI(amI(YlHRTkHRT kHAPjHAPkHRYmIi1'KiL)LBU,Lib-LSH'JhpmHhPjHhepIAamHhYkHRTkHRTkHRT kHRYmIS+&KiL)LBU+Lib-LiL'K)"pHhPiHRepIAalHhTkHRTkHRTjHAPkHRYlIB# %KSH)LBQ+LiZ-M)Q(K)"pHhPjHhepIAamHhYkHRTkHRTkHRPkHRYlIB#%KSH(L)Q *LSZ,LiQ(KB0rI(YjHAYpIAemHhYkHRTkHRTkHAPkHRTlI(f"KBH(L)Q*LSZ-M)Z *KS*qI(TjHRapIAamHhYlHRYlHRTkHRPkHRTlIB#%KBD(KiL)LBU+LiU)KS5"IAa kHATmIAemI(YlHRTkHRTkHRPkHRTlHharJiD(L)L*LSU,M)b,L)0rIAYkHhapI(a mHhYlHhYlHRTkHRTjHRTlI(q$KB@'KSH)L)Q+LSQ)KS5#IhalHRPlIAepI(alHRT kHRTkHRTkHRTlHhaqJB@(KiL*LBU,M)b,LS@"IRYkHhamI(amHhYlHhYlHhTkHRT jHRTlI(q$K)@&KSD(KiL*LBQ)KS@$J(emHhPkI(epIAalHhTkHRTlHRTkHRTlHha pIi1'KiL)LBU+LiZ,LSD#IhalI(epI(amHhYlHhYlHhYkHRTkHRTlI)#$K)5&KBD 'KiL)LBQ(KS@$JAjmHhTkHhepIAamHhYkHRYlHRTkHhYlHhapIS+&KiL)LBQ+LiZ ,LSD$J(emIAepI(amHhYlHhYlHhYkHRTkHRTlIB#$Ji5%KB@'KSH(L)L(KB5$JS" pI(YkHhepIAemHhYlHRYlHhYlHhYlHhamIS'%KSH)LBQ+LSZ,LBD%JAjpIRjpI(a lHhYlHhamHhYkHRTkHRTlIB'$Ji5%K)@&KSD(KiH'KB5$JS"pI(YkHRapIAemI(Y lHhYlHhYlHhYlHhamIAq$KSH)L)Q*LSU+L)@%JRpqIhjpI(alHhYlHhamHhYlHRT kHRTmIS'#Ji1%K)5&KBD'KiH'K)1$JS&qI(YkHRapIAemI(YlHhYlHhYlHhYlI(a pIAq#KBH(L)Q*LSU*KS@%JS#!J(pqIAalHhYlI(amHhYlHRTkHRYmIi+#Ji1$K)5 %KB@'KSD&K)1#JS&qI(akHRapIAepI(alHhYlHhYlHhYmI(apIAq#KBH(L)L*LSU )KB5$JS'"JApqIAalHhYmI(amI(YlHhYkHhYpJ)+#JS1$Ji5%KB@&KSD%Ji+#JS& rIAalHRaqIRepI(alHhYlHhYmHhamI(apIRq#KBD(L)L*LBQ(KB5$JS1#JApqIAa mHhYmI(amI(YlHhYlHharJB+#JS+$Ji1%K)@&KB@%Ji+#JB&rIAalHhaqIRepI(a lHhYlI(amI(amI(epIRq#KBD(L)L*LBH&K)1#Ji5$JB"qI(amHhamI(amI(YlHhY lI(k!JB+#JS+$Ji1$K)5&KB5$JS'"JB&rIAalHhaqIRepI(amHhYlI(amI(amI(e pIRq#KBH(KiL)L)D%Ji+#K)@$JB"qIAamHhamI(amI(YlHhYmIAq"JB'#JS+#Ji1 $K)5%K)1#JB'"JB"qIAalHhaqIRepI(amHhYmI(amI(amIAepIS##KBD(KiL)KS5 %Ji+$KB@$JS"qIAamI(amI(amI(YlHhapIi#"JB'#JS+#JS1$Ji5%Ji+"JB#!J)" qIAalHheqIRepI(alHhYmI(amI(apIAeqIS#$KBD(KiL'KB5$JS1%KB@$JB"qIAa mI(amI(amI(amI(aqJ)'"JB'"JS+#JS1$Ji1$JS'"J)#!J)"qIAalHheqIRepIAa mI(amIAepIAepIAjqIi'%KSH(KiH&K)1#JS5&KB5$JB"qIAepI(amI(amI(amIAk !JB'"JB'"JB+#JS+$Ji1$JB'!J)#!J(pqIAalI(eqIRepI(amI(apIAepIAepIAj qIi'%KSD(KS5$Ji+#K)@&K)5$JApqIAepI(amI(amI(apIS#"JB'"JB'"JB+#JS+ $Ji1"JB"rIhq!J(ppIAamI(jqIRepI(amI(apIAepIAepIRjrJ)+&KSD'K)1$JS+ $K)5%K)1#J(pqIRepI(amI(amI(eqJ)'"JB'"JB'"JB'#JS+#JS'!J(prIhq!Ihj pIAamIAjqIRemI(amI(epIAepIAeqIRprJB1&KS@%Ji1#JS1%K)5%Ji1#J(pqIRe pI(amI(amIAk!JB'"JB'"JB'"JB'#JS+#JB#!IhprIhq!IhjpI(apIRjqIAepI(a pIAepIAepIRjqIRq!JS5&KB5$JS+#Ji5%K)5$Ji+"J(pqIRemI(amI(apIS#"JB' "JB'"JB'"JB'"JS+"J)"rIhprIhprIRepI(apIRjqIAepIAepIAeqIRjqIRjqIi# "Ji@&Ji1#JS+$K)5%K)1$Ji+"J(pqIAemI(amIAerJ)'"JB'!J)'"JB'"JB'"JS' !J(prIhprIhpqIAemI(eqIRjpIAepIAepIRjqIRjqIRjrIi'$K)5$JS+#JS1%K)5 $Ji1$JS+"J(pqIAemI(apIAq!JB'"JB#!J)'"JB'"JB'"JB#!IhpqIRprIhppIAe mIAjqIRjpIAepIAeqIRjqIRjqIRprJ)+%K)1#JS+#Ji5%K)1$Ji+#JS'!IhjpIAa mI(epIi#"JB'"J)#!J)#"JB'"JB'"JB"rIhjqIRprIhjpIAamIRjqIRepIAepIAj qIRjqIRjqIhq!JB1$JS+#JB+$K)5$Ji1$JS+#JS'!IhjpIAapIAeqJ)'"JB'!J)# !J)#"JB'"JB'"J(prIRjqIhprIRepIAepIRjqIRepIAepIRjqIRjqIRjrIi#"Ji1 #JS+"JB1%K)1$Ji1#JS+#JB"rIRepIAepIAk!JB'"JB#!J)#!J)#"JB'"JB'!J(p rIRjrIhpqIAepIAeqIRjqIRepIAeqIRjqIRjqIRjrIi'#Ji+#JS'"JS1$Ji1$Ji+ #JS+#J(pqIRepIAepIRq!JB'"J)#!J)#!J)#"JB'"JB'!IhprIRprIhjpIAepIAj rIRjqIRepIAjqIRjqIRjqIRprJ)+$JS'"JB'#Ji1$Ji1$JS+#JS+"J(pqIAepIAe qIi#"JB'!J)#!J)#!J)#"JB'"JB#!IhprIhprIRepIAepIRpqIRjqIRepIRjqIRj qIRjqIhq!JB1$JS'"JB'#Ji1$Ji1#JS+#JS'!IhjqIAepIAjrJ)#!J)#!J)#!J)# !J)#!JB'"JB#!IhprIhpqIAepIAeqIhjqIRjqIRjqIRjqIRjqIRjqIhq"JS1#JB' "JB+$Ji1$JS+#JS+#JS'!IhjqIAepIAjrJ)#!J)#!J)#!J)#!J)#!JB'"JB"rIhp rIhjpIAepIAjrIhjqIRjqIRjqIRjqIRjqIRjrIi#"JS+"JB'"JB+$Ji1$JS+#JS+ #JB#!IhjqIAepIRq!J)#!J)#!J)#!J)#!J)#!JB'"JB"rIhprIhjpIAepIAjrIhj qIRjqIRjqIRjqIRjqIRjrJ)'#JS'"JB'"JB+$Ji1#JS+#JS+#JB"rIhjqIAeqIRq !J)#!J)#!J)#!J)#!J)#!JB'"J)"rIhprIRepIAepIRprIhjqIRjqIRjqIRjqIRj qIRprJ)'#JS'"JB'"JS+$Ji+#JS+#JS+#JB"rIRjqIRjqIhq!J)#!J)#!J)#!J)# !J)#!JB'"J)"rIhprIRepIAeqIRprIRjqIRjqIRjqIRjqIRjqIRprJ)+#JB'!J)# "JS+#JS+#JS+#JS+"JB"rIRjqIRjqIi#!J)#!J)#!J)#!J)#!J)#!J)'"J)"rIhp qIAepIAeqIhprIRjqIRjqIRjqIRjqIRjqIhq!JB+#JB#!J)#"JS+#JS+#JS'"JB+ "JB"rIRjqIRjqIi#!J)#!J)#!J)#!J)#!J)#!J)'"J)"rIhpqIAepIAeqIhprIRj qIRjqIRjqIRjqIRjqIhq!JB+"JB#!J)#"JS+#JS+#JS'"JB'"J)"rIhjqIRjqIi# !J)#!J)#!J)#!J)#!J)#!J)#"J)#!IhpqIAepIAjrIhprIRjqIRjqIRjqIRjqIRj qIhq!JB'"J)#!J)#"JS+#JS+#JB'"JB'"J)"rIhjqIRjrIi#!J)#!J)#!J)#!J)# !J)#!J)#"J)#!IhpqIAepIAjrIhprIRjqIRjqIRjqIRjqIRjrIhq!JB'"J)#!J)# "JS+#JS+"JB'"JB'"J)"rIhjqIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp qIAepIAjrIhprIRjqIRjqIRjqIRjqIRjrIhq!JB'"J)#!J)#"JS+#JS+"JB'"JB' "JB"rIhjqIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhpqIAepIAjrIhprIhj qIRjqIhpqIRjqIRjrIhq!JB'"J)#!J)#"JS+#JS'"JB'"JB'"JB"rIhpqIRjrIi# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhpqIAepIAjrIhprIhjqIRjqIhpqIRjqIRj rIhq!JB'"J)#!J)#"JB+#JB'"JB'"JB'"JB#!IhpqIRjrIi#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J(pqIRepIAjrIhprIhjqIRjrIhprIRjqIRjrIhq!JB'"J)#!J)# !JB'"JB'"JB'"JB'"JB#!IhprIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(p qIRjpIRjrIhprIhpqIRjrIhprIhjqIRprIhq!J)'"J)#!J)#!JB'"JB'"JB'"JB' "JB#!IhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIRjqIRjrIhprIhp rIhprIhprIhpqIRprIhq!J)'"J)#!J)#!J)'"JB'"JB'"JB'"JB'!J(prIhprIhq !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIRjqIRjqIhprIhprIhprIhprIhprIhp rIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'!J(prIhprIhq!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)"rIhjqIRjqIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!Ihq !J)#"JB'"JB'"JB'"JB'"J)"rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhpqIRjqIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!IhprJ)#!JB'"JB'"JB' "JB'"J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(pqIRjqIhprIhp rIhprIhprIhprIhprIhprIi#!J)#!J(prIi#!J)'"JB'"JB#!J)'"J)#!J(prIhp rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhjqIRprIhprIhprIhprIhprIhp rIhprIi#!J)#!J(prIhq!J)#"JB'"JB#!J)#!J)#!J(prIhprIhq!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)"rIhpqIRprIhprIhprIhprIhprIhprIhprIhq!J)#!J)" rIhprJ)#!JB'"JB#!J)#!J)#!J)"rIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!IhprIRprIhprIhprIhprIhprIhprIhprIhprJ)#!J)"rIhprJ)#!J)#!J)# !J)#!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhp rIhprIhprIhprIhprIhprIhprIi#!J)#!IhprIi#!J)#!J)#!J)#!J)#!J)#!J(p rIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIi#!J)#!IhprIi#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIi#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)# !J(prIhq!J)#!J)#!J)#!J)#!J)#!J)#!J(prIi#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J(prIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)" rIi#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhq !J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ii#!J)#!J)#!J)# !J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihq!J)#!J)#!J)#!J)#!J)#!J)"rIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J(prIi#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhq!J)#!J)# !J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!Ihp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!Ihq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)!!!%0!!!%!!3!&!!!!S!!"J&%!!!!!!"3!!!!!!!"$&PE ZLk-!!%-8!!"$&3!mJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!Ihq!Ii#!J)"rJ)#!J)#!J(q!J)"rIhprIhprIhprIhprIhp rIhq!IhprIhprIhprIhprIi"rJ)#!J(q!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB# !J)"rIi#!J)#!J(q!JB#!JB'!J)#"JS'"JB'#JB'"JB'"JB'!Ii'!Ii"qIi"rIhp rJ(prIhq!Ihq!IRk"J(prJ)"qJ)&rIi"rIi"rJ)"rJ)&rIRprIRjrIhpqIi"rJ)" rIi'"Ii#"J)#!J)"mIS4pH)"rHhemHhepHhTqIAYqIAk!IAf"JAjqJ(prJ(jqJAp rJ(q!J(jrJ)"rIi"rJ)"rIRjqJ)"qIB'!Hhk$J(aqJAppIRq!J(eqJ)"rIhjrJ)# "Ihb#KRYpKi&pJS#!K(pqKSCrJ)@%JS&rJB&pJS9pIB@&IAb!K)*pI(q#JAf"KAp lJBU!GB+(Hhb'J(f&Jhf"JRk!K(pkJBCiI)f!GB'(K(q"KAPkK(TqL(KeLiYcFSU *G(q)H(b&Ii1#G(H1MRCbJB'%M(aTHTH-DhQ5I(H0IR+(KA0rM(PcIhk'L(GcHBH 1G(',J('"JhGmLRT[KRTfN!"pFi4kI)0mIAafJBClIS4pJB4pKiTkIB@*MhaZIBU -I'jrLi&cFRamJRe`LBP[HiU*H@k%QS&VK*L+EhfEJ'f(MB&iFAD,LA"jI@q0P'K bQiP`K*5)JBH%LBejHC@9Df@JS9YMPB4UG)'"IB&pFAq6JR+(M(+#RS&aMT4rI)k *H)#%GAb#GhD!IfYlQR*NRBGIMTTVGTk*GC!!LA#2RR"ZPB*UJSC[GiKbG)afCS1 8Hf4qQ)CaJ*H)HC'CJ(Q'MB*fIB&dGAecGACbH@pTG)5+E'Q3!)YlMSb$JS#0N!# &IAD'N!"eFBGjEAYcF(pUB)1$FhTmK)GpL*+0LB#(PjH(G)@8JAaeDhjfBh9dCQe mKQeBKjpjFAU(R*1"L*',M*Z@HhQ(JRq%G@&XK(GID(KlHhT`GT@'ECLSGR@XVS& qQC@+K(Z2Lf*VHQpfE&plI'CbK(aXGiq-IAf-R*f3!)Z9Q)Z-L(Z'MB*XA(#$GQ9 NF(TfI(pbDA@9PATpP+1@J*UUJ@b#R*PZBhpjDR4dDQp`GBTe8AQMG&L,RB+%QTk 2LBq+L)U#JieeD)Cf8'U-HeGMJ(GZEh9pGA#'RiefMDLGIRf6Lhf3!*&aERajF'j XEhTfE(CfERGbGi0aHTZ5K*DGN!"rKjf'HjL-FRC`FApbDA&pH9eYL@pKH(KVJjD "KU+9LTL5J)LINAQ0KPejS(eEFSCmGR4RCRKfB'b0K(L8Qib@QBZ*LSH-NiplE)@ 1ER@5Gf+!HPpaFeaUIR"`N!#@JSqLN!##N!#6Kj@BJBH(H(q,L(KeI'pVH@YCA@C jFf&rR)q%N!#GNi5$LD'FG)#IKh12NAYpHfpSF(0E@QYHCBPpDC+NL(k2PRGpUjK pNS*bS*p[HTKk9Qk$CP"GEQ"AH)YhFSDESS9YKk+MMhQ-QBk8LAZHS@PKIR9TE&Y 1@f0`KAjUFjfVJ'b3!*b6PBarKD5JHC1hKQ5%K'*QD%a@Ef*GGiPkGT1@H)1KNB1 9QBk6S*'B[TGbSip(CT&D2fPF3h@&AR1@FQQAQQjZVV4cGkZTNTkfU)U"K)&cCQ0 F9&9FC'KZHRjUCiq3!'9rVj4jN!#HT,5PMDh(Le5)U&`pEfP#@@YHFhY9AT9r9iL CFiZNKSqrV)HhcTU2Q(TaJRP33&aMC'Y4AS"TAQG[K(GmR)0lT,+PRUh%UiZ6M(e hCeY989KRDPYADA"L@(D+EA@@MRqJ`jkAeX@EVjZ&LRGf@$TTFdG2DQKE@@9DAhe bFiU"MV@JN!$*eUHZc*YYKjCk9dY@DR&66QaM694TEPYQLhj`Sl@ATFV5ZE+hT*1 )IATS69TfC8T2Bej29eC9CAKfBhqVTCbUaFc$bl'BPiD(L@C2BQpI9PK@68K@A99 5BS0eAk$"QD6%dZ'mP,'cMAjeE@*QFf**8ej(29*94e0kG9"dUU5UZ,6@jVbNVlU 9FSGbAi*R2PYM8$mV6Q4'6P9FGhH-Tk5c[GMXVU$AYB1)I(KeC'PI89K006e(89X i4RaXFCLGVF62h-r"aV+QT)"cKS"Q@@4U6$ir0%G8-M9HC@9fQ+QUa0,1f-V!`k+ CPR4qIeeeIN)e@88M3PSi+8pZDhLBSV[CbF6HcmE#NTUVIQKhIR0H66dl46%Y8$3 H@faHL+5DYq65Zq$SZl1bQ*H*DA+$G%Xp6NFX)N&*)cGKB@4qTX2!aG21iH$%Z)b 8[RT'G(YQB$`U26XR,$3S5R"@G+UYaq(FdZ$dflLVSCf2A&"fE%3c,bJX3$)E,8a +8(D'PFRB[0([f0RU[DZhQj9iBiec9P8Z-8Bc("NX1#dd@(f8Ql(#[Z(cd-r0Ylq eJQq6QQ&1CN3X6MiB-6dV1NpULk1XUEhFiF@qdlbHRi"bJR"dG%a19P0F0b&,8$j $5(5IPTbVY-l8a,bmZDfaQR@@TA9aH&T)@9`K&dFX%6G(9B5-K+R)cXh0cFR&X+f YLBfCJ(TT8Pe0068k4LNJ9PGFMSqAXlR2[kE&[U1JRTk+KTb%H)*cF8i`683Y,bi [0f@%BhZcVE#p`mh"aFQ`[VH5Y+KaI'a155dS+KFE*#ip8S"qJX6'SVE+cF1MX,b *Kkk6FBCq8&9N5$Y)589$9Q4QJBq8Tk@LXE#VSkLRPD5DKCZEL)*M594'1cdH+$i Y8'pKH*QPUlV9`lAIhm#cVmHVIUUJ8P&H0L-V&4Fr,aK+HAQ"PTZNZEbjYVZjTkq aS+#6P+1"Bf0G@8)p68&(5%aeI("hKjkDMjHQ[E1JTkbkXDDmPeeeI$id65J826i V5fKJHCk@P+h+aVE5flLZb-fSN!#PNeTH5b9#1K)N1640DQeRFC!!PBQLZ*kC[X# QXF5`UE@PNT&qA&CM6bBm@5ibCP*3H@9@JU1@Ll$&VlRFem$"Xk@4GRC1+dJk&bF q2c93C@'1MfHIekbCb1+lS-MBXTUGMfKRBMT*@b!XEP%kD(&8E)YXDU1GFC[#S*U jYUHecl"pNTG`DQaG6da69dC0CNa1EP4SViPNXm'G[-qiUm2#LSb2A9KH98%hB9B TA)03AC0hCTbeMSr-Zi1[`D'`SSClFS&f9NYAC'9VA&4lGPCKE("ZFT+4JTbPQk' EXG+YLCUPNheVHAa18QTA9f*&,9*V9@5'HB5dZDQ`YlV!Y*D5T)9VE9pK@&*939e b9eYICA4dN!#VQSkF[VD0TVb0JT1-M(&JHQYLEePTENYNE9"+8@jlEAkDQC+KXD5 Vf,5([-+@Tk&`F(KK6e&,2Mib06e)AeC`RC!!M,'qT+M0[SqXaj@1U)alGh&V8R9 e3'YV0QD)C@1,N!"THk'&JT*iJk19MCHJRi#3!+D!G)4mEPpB8dYMDNPLLfpMMj0 qQlqQR,Hca-HMRj!!L)pL9Qe@3cNk6$p(A%YaRA4`Tjf&UUf3!++XT,HhRSb6S(a IJTPi@'CVAhCY8'YVAR4Y9f4rG'*rQBqCYDfPZl+5KBkHLPp@G'%mAQ0$6ejaC&5 3!*U&RTQTZVEIbjHcUiZ(CQ&cAdp+4dp09Pj4CRGQG)*fJjq'E+qlL,I)RTqKQ)U ,Q)CpK@pkM'aN@NaUDP064Q5&APk+N!#9Ul1USlUQJT+-Ghq$CeahG@KV9PeqFQU #M(q3!,+DL+qiSk#6K)b!@P&VF&CFG@9RKhKSIh0ZLB*lHhU4LS#@N!#5UD#&L+# 9GB1AKS11Ji#1FPpkANYQ8e9aA@'$HR58R*ZAN!#VX*H'J)L@NRPaMjKaCQjYG@C VGQ"pPA+&PhQ1Rhq%Nh9pRRYFEi15I@f2JQH*K'GYGhGJCiaeFjTqFD+EKk+8LU@ DJiHAQBZ"HS+2ENpH9Pjc6%e`DfTmJh5*Rhk'YCTrSjL'Sj@$Piq(PjChEhTZGh& NI(akG'#!LQThF@L2Kh+#IB@3!)H'L*Q@JT!!JA@&F('$CA@KDQ@JIh'3!)1!LBH 0LTfKJSf,FibTMeKIK@92D9p6EhKGDSGcGiL"J)@JTSQ@[UQ3!+bHMU'NMhQ-F6j `INpKD'GE6Bq!5RpX8+16AjH[P*!!SjerNkU*Lj!!FR*LCSTbAA+*J@U(NA#+Nf* YR*@2XijRRU'#L)"bE(ab4e0[9&4[FA&MBT'+F*&dGUf0T-fiUil%fAQJ`S@'EPY Y@9GF8dj)@eP1F&j,J(*8J+'ENU5kXjqEREUmIB'EI@TmM&eCNh*1J)YT8fL0CNL ,VipqMkfINCq4S+P[Dijk6dq0E6"fDNChBPTlHfYHQVq'Vp+@XFR!b)qFY9U'Y%* 5INj188p*A(p+-h&k@&Z!Q)@)VTq)RV5pRSZMTD5)G*q5C(')HQf(GN&GK(9PAfb #JRq%K*HUQif+Pk9eBSGZA@9(@PT)LAp%DiQ%N!#9P*He[k@bXUc-XhGrUCYH6Qp K05a5HPNpF(&CIhGLHAPiJjPlAm#jE,'hKlh"N!#5QiarJhGNNSY,E(pIBfeZ8cp ZFeb,QikNRT+VZCPcHSCq9bKDN!"C2(''GiZJNSDZVA5DXBqYXBqIPhZ4N@0CAdF rAf-dCDeRAkUPJAfCKeGbI9P[Lj!!N!#&TEHSX+1IU(aRHS@)D@&fDfalFR"XA@4 hE&H!YCD*[lQ5U+*cGQa35c8mAQ"QFS#HTk2%c*LF[Tb"L)Q8MfTGHiG[AeYHD&T -Bi#-P)k8TS1"ThCGIfe-5PpkFAUBMkM4XTkcXTf%J(T2B)9H6h"dD(YmAAkdI81 *`ijhP)b8T(K6D(TL5P"15@q,Gh@efkUak,0cVGCf1hGqA'05@B1"Bf'AP9aaL(Y qIRpeHDZL8(DM5'QJ5&+6JAQ6UCZEi-jiR,f'GATN8&YQ4%@+P&acTj&iKT1$Kjq $Eib-KSTaEReI8QpN@PjIKi0KSHA&QU62[(Z(N!"bDfC95Qb+FRfCMi9mMijMISa RC@4[M)KL5h@$2NZ*CQ'6JSl5dF2IfE'TSBU)8bjX@b"5E'4rGS+LP(GVQDYSCk5 *3@HcDc+&H6YCF'0TPkKhR1'hVGDeQDQ*F(TYAQ*YD@4YI*1KNB@2JQChG8G9FP3 p8A"RBRKcFS1BQj'VYUZcTkc5`CbIQi"iI'G9Bh"B9B&p@RZEGPPLD9jDF(&8DBG `KTq!L*Z8PSU'MhZBZ)H6[l#STk'1GCDK4%#LILj-IP`PGjNcAT9BGSjNKTq"LTQ +GhQAI&k5QAGcNm#ANpZXLXD`L*Z9Gf9N4bG)9L8[G(a@Dk1PMCUZP)HMM@*rKPG AD@GUJ+#'HDqRR,UVYmfQJiQ8GdeAA$Bq6MpFFfjkQU1$RFLEIBPcChKJ5PGFDRT ZECA$ViHbil1)`XKrJ(T'8Q!r4QK21hD2BA+cX)b@QjfMJ)L$8A119%amGfb'FQQ FTk'SRBf&RBT0AR45DRp,@U#IK*qbQjkXMSbPJfeXEB"QARGKEBaT@A#0MA+#Ihk LM'jmHfekIQCdLBDCRS#%b0b3!(bbUATSBfGaEP41G)0aISQ(LS#(Heq)M%T4B&H !H8eeRiq*QT5Dam1,MF$&Q(f5SSTI5Q0RCA0KHieGKlGjDjZLF$a9C$T,A6YBGQf 6SC+ZcXLMRX,&TB*mUE"S9S'$M'meG*4YJ(&dL'PhL@T8A'eD3NG0@9aQMj@4XVU XVG,JQ)h%UB4mKTYeGjCiHiQ'H95"Md&`Kb!rH%Be2&&D9@jFDjq@Pk1ki-Lk[+[ -b*UUTRYeJ)&TETed1A5@9%4cE%P54M&ME6KDKQPXNUUbTDDmZUH8NDk[MQp`Pi9 NIS1&NhKbP++-KCU&G(KYD6SrH%8ZB&*3H(b"KT1fP(1`ZReaQDk0H*'FKS+NVD+ CQE@cLAk4RiG@18",0a-22&Sl5SebGFkkRVl"ZU#5NTDbR'GVLi*hKhU$P(YpJiL 0Ij9i8R4S894*4PeV69'(VV@YY,1V[jk'TS"38dpHC%SqCj'"JkZpTCDp`*5FUCD #E9pQGP8R29GC@%eSLRq1TCfYYTfLSSL3!'e9K'P3M+@(JDl!STQFN!"hE'")@9% d89a6CA&VFk#YLj5`Ul1p[-+fVVq24'&a3Lm`2eCF5fUVIPZka@eVPiGZK*@%H(f 3!+UmRh#2YTG[BRL2FQH(Ff9m@&f&@e*iG(L$DRHiY)U6UTf-U*0DIhp#DT!!C&G qKR+'Nh*aPTD$Ii'&Kj+,L,#ZKC@SL("qDNGK9Lj8D%06HRTdG)12IC!!TTHXZ+q PSG6&LULEGi9U8PCUGeY`P(jLE)&F3&K40$G@E(GlKkqi[-c-bV'p`S#-YC4`D(P Z5ea9,Mj59@9SGSfRYD1ablU5G)U*A&YQ@&pbER9kFjQdPSKfD*'3!'PeN!#,B&b ETRZ,Uk'KTTUFPiZ4Qj0T4PGD3c3G+die+PpeLEQaXGVQfFr9cVHPIR#2HNKCG'0 PGP3mD)"33'pY9QGZJCb9KAkGVB#%V+5CSUQPQ+#iRAb%C%GE5LNe@'pIARZ0UUk BQUUlS(U(I(UKK&YhLReM9fGXH@8d@(p`Ij+$JV#kLSD[bk+)T)QCZ(9eVijJCQ4 $-8G20c!`3h*ZDERGT+64ZTfeZCf-MiCdJ(U)VhjLK(*JA90HC9Y469eaG)"fE*U 3!'f0Q*qUVYR&TG$0S)&lJ%mJ*b8L1%43Dhf8YkUPcEkKVU#"JiprEhfAK&4EEfK cC9C`GAapGTQaRi"rK'CIG(CRDiqLPD(0bEhAZBKfA&T5)"Bl3#BX9A*mMjH+SXk hNV6EfF#GUlfDJS"kC$e!86T#B@CbJi*hGSk+BQ*`FQ"'FC@&QlbrZ,R*XC@`S(9 iB6e4F'pF8faN6h4S6BbNI(5@VU1MYV1PS)KSFR&-9fe58h9jJBk(LC5'C@Z$J(U "LBkTZkfRUELeMRTXC@j6-d&FBP03B(0dBQprHi52LT1VUVcA[*58XDf'GhKpG&K LFAD+Jh"XBeC29%dk6RCX8A@hdEUddpI!VjD,PSGM9PYC8fGb9&9hF&48CBHbN@q aak'RX*fAP(&3AQeCEB9FC+qXHibPNRKS9dKHDP&@E)#HPiDK`F#YS+1PPTD6D&q )LdddCeic2N&#Ci*iH+6$`m'kY,QkMQL$H%j9B&pFBi'1JAk1PiKUBhKpE'"VKiT dGj+MNAf0PjDEP)Z5QjQ(KC&`@'YG3cBc9f&0HCq4QkDS[UQ9V*&rMfaLJS9lHAf "HRD'JeYVMQ4KMRq!QSQ$LS1&LB9qFh'*P(GlR*U"Gi+(HQGJC@9I@'&fMjZ!KUD SUBf$U*KpPiPfQ*0dIj0pCRjm68aYCNY8EQaULiGSLCk2Pi9pT+5AQD'YS+1IKjb BA9PZBej28R*VG(Y`Q)TFHBejDh0jI)Q%Mk+8QTf,RT9`H)"rG@H!Ih+-NS0aChP lFhejJTD2NjH9TjjiBhZ%3cYa96YSI@eaNk+-M+#-Lk+#M,bCKU5GPD'LJR+)I@e aD'CTE@jTB9TUEeT*8Q4PCh'1TjDGb-A![TbU[TZ!IAebCQ4KDh*fGA@(EPPpJhT aCi&pG)CjL*YkI)0XK*!!JC0rEC@JQCk2KTq,6(542NZ4F'Q8P+5bR+5GKSPaCRT K5'*VBh4kGRaiJ)KMEjb+IikDYV+BTk+(M)&PB@j[A'k)HBUMNSZ-JfKKF9G3C&e VGh13!*bIU)q3!+kBL**rPUjfEBqCL9jXIPpMBePEB(PpF(H4QSQDQA+&N!"RH(p DJl#(F*@bUC5DTCD%I'KHIAa6D)&PFiG`EhGrJ8p5IfTNJiqFUCk*QDQ>+#CB@ )DTDlRB@EXSaREA&X@%TEDR4dHBf0JRpmG'4FBQTTC(bERTqGTEZPJBfMNSL3!)L &RU1*P*&ZKi&*9Q426f0N5@kLD9+*E&'(H90pK@H#Sk'XcG1l[XZdT+qTMA0QC@* EAeYHDPG)69ph984`G'*PICq@JSqUU(YfVTpaPU+"RmHUSFLjM)'@Ld4(I9-V@RK YG(4lNheHFB*G4fTVESb%IS+3!*TpJ*1%FiLMMBLfd0A&U*q`UA&FF@C4-cGkD%" iF9L(DMK@DQCSBh#$N!#SV*UF`,H&TEb+N!#GQE@MMDbjPfjrNeB[6%Xp06TK8NC kF9aqKhjfICHAK*!!ZEbSVXl2PTUiMB5)E@aQEi*IED*q@hb!D9jDBQ*45f*YBR# 8Qik3!)b,MSk3!)'DYi@,bUQBZ*!!Kj4SEA"8C'PbJ'L!V*Q#I(Z!@MY38dC!4QK qJ)1&RV@HM*qfYk#J`,bRZmDHIiZ)B%G*88Nd1PTaFhU"J)jb8'CTA&aCBRLAQ*+ ecX,!d-LKPV#fMA#1R(CLD'4B5N8k(6CJ480XKjQ@Q*Z@U+H*IR4aI(&UKCqRT+' i[DZNMj'GHfe[C(1!F9KMI9Nl@@C*3fjd8e+#Z*q&UCb(RiKUIC')FBLkXDA'e-H [T+5'F(GmB%&5@NaA68*E5MC+15eMGf0rRUE!j-qIb1QULULYPjL,IE+iH(LFJda LIcd[@dmr4PTLD(aY@@*`IA0QIjqHMC[%bkqVaEbDS+&fEC5%@@TrJ)KiJCaqF)9 T4f9j@&KP68aKBepKBA&jBR+,Mk+HV0c1YpEL`,#jQA4kE9TVHhGLDh0DB'YG66d f1$9&C9P8LC4rL*ZYUk+ITX$%YVhHilZbV)f(D%TB66Nl6PC'9RjbBAKaDRPL9R* rG(Q*JiqdRALCUjk2JTqMPl@JPE16LCTdEBad8@0Z68GUFQjrGQ0XGRpR9(GZ8A1 -Fh@NYjk8SE5rVU+aYCQ3!*f*KTb5J'pIBeB[1&Fk0%0&DApmIB'9PS@*MiqFUCb AVlZ`VELkUj0qGQTGA&PYEdTIK&K0H'C*9eaNEfYbJCUeSC5XQSqYRRTrNTD0KBq KXDb2JRjZEh"B8Qp[9PCFEhYLBRKS5QYj5RLLDhQLQk+LT+qSV+L)QDD5Yl4jLUL AJACUC("I-LNf5PG+-%*lE&GrGhqIIRqMRTDK[,LYeXQNYUfKUjarDAU4E&0rJf9 cC$a!6NNe18Nl8RTTCj'VSBH4UTfAS*bU[UDD`-bcTkqZMR4bFR"QCQpZCPaKC9e 23%"%58P#9'PkK(H3!+f6QE1HUF1NSEHcYEl"ZV#NRCKiEiaQ4@C+,8j28e)j9'* (49"BCh0XCBURQCLfd,U`cVqLVVLUS+5AM*Q,IijqFQC(4%K"2N"19NP5I)*IEj' !D@TrIhb1MTbSTDkJUY#mQTZIQ*LKRBk-PSKRDR"A6d`m26`j490HCB1%BB@bMPT fYUCdLE@NLDE*Z*@J[kH%R*YcMj9DAA9F9@PG4%j93e9U9P"dPhT[Ul#2TEDEJSb VR(L'Q)Z+N!#)QUH5N!#6NSPbDeaQLQJl@AjJ5AGf@(4pCPKXMS'+TT+0X,'*P,f MHiL5I(@CTB1&Q)*rMfYDIQ9(98p8C@TIAiQ$B)5IH@f1NB5FU*HN[+bMYTjrM*H +EQKdDR"jB8jAGACB9&jRF'4XKS0qLj@&JTqUNAb)PSU&N!#3!*1TR(D(SC'4Mh9 iKRK96@KUA9C5@Q&YF'GpLAq(IS#MQ)14S+DBMk'@N!#fSR'(NSLINR+%PB&SCf9 CBe)[4eFm5fCID)18KRZJVjqFSDb`VD+GUVbaLBbIK(k%GA"dL)0GCA4A8Q4@4%j F@8P6GhYeHAD5RhZ0[l5IUV#LU-5[NUkMHSZ9IAU0L@aXG@PI8&CE5&CA194jAPP kFQCrJ(D+PBkEYUbM[-2$[E'bSC@DP*q6F)@%C@YF6e!q38a!1PCJ49f+G&epNAQ %QSb4SD+SV+Ubam#JSU'PYT'+QS+'H'PL2eTM,6j518aN4db&HePfNSD"LCbkTBk TUjkNUl#5M+qDLDDQPTHQN@*RD9TK4MjA3N"@A'*FDA0UHhGZQTpmQDfDTDQSVjf CR)f-Q*QDSCZ9QjD(Gh"mA#jBC6T"8&KM9eKUEhb+FQ@9YCCqRVDYVV5kUC+[VBb BMiDDNi&TAhaa6'0P38T-3P&FDf96G*5(J)kKVCb*QCqCYUk"RED9MjfHQSq-IfC TDPP-9A"R5ePXC'f!FPTZN!#(GhL@V*+3!*U(LCL4JSH6PB9pPDQLS+HAIS9mA@4 S5N4L8caUHP9TN!"fDBb'FSqELT'4Jj1QPifAP)HAUC+8XkD@U*L!K(&HB8dq5cS L0NG"6@efBS5`RD1[VF5aPD@LRUfJLT@DP*!!KBH@R)KbIfp-CfT(@Pim3dG$@f* PC''-Tj+HYmE6YD'YRTDDP)plEi+,HhU3!*@+JRPmJ'KQJQe+@fj95'GY9&*RF@4 XMik*TUH8PULkXU@GPD5QNTLGR+LFKiD%Ff4MBe&&8N-b3dC-@&TECRPdHj@@VV# %TpQZRmR"Tl+fSik1QTD-J@eNC99186e$9#ihB99PF'U2Lfq4U*UAS*k5M*@PPS@ BRjb6KjHIRk'5LSb0IfefGep89Na!4eeH8f*dFRZ3!)arN!#NN!#'PB5%RBKfQDL 6MjZXYDDYYC@5SRYIG'aA9d)e6NBk8PP6@'q$GS@dVTq`TjUXUk#EKiZ9KBQ1KU' iLAHPP9eTIQ949eBl5R&C9(*GAiKqC)1VQSDMYDHDUE@JP*''LiGYHCU>Z6FAZ 'Hh&eD%09FeT3Ch"PC(CmF(+1M)'5J(qYVjbCRkqdS(q,XTb!NSjbIiaSBR0KAPG !8f4889jVB&9YK(aiLjkHKB@cVi1DaUk8VUL@ZEH2Mj11Kfj869eA2MSh3PP46fG `D'jjHBQAQDDDRl#ERl'NPTqTL(LFQ)HGPi10NR*ADApN1MK+8&&EE'4YKR4ZIi' 5Rik,M)5GU)H@UC!!NjD,PjqFNT5YS)LBPiZ&D9KI6MG$8NBm6e4'DAe4C+@GG)@ eXBbDbF'ETlUXTUZINUbREA+@GejcDde+9Nim3P*GA9&0BAU#GRbUZ*54V+'S[C+ C`*@1T*LFQT54HRL!G'4GAeYJBdY,FApQCi"V@B#(Bh+2LB@"LCb0KTD6P*Z0Jjr "TjUqRiLXPh&`Hfe066SRC(T,@hCABiTdAi1BIRU+K)fKRCkNRT@CT*bGVUZPRC5 JRB*jFQaE-#p"-$G,4%pKDS')K*'T[CU*[,+)RkqDLC+@JSUEM(q0PhjpLR&hNB" TB&Y89@*24'aU1P')IA1EZ+#9X,+KRDDfQ@KiM)@0Ji5KPhYfI)4rLBK9B)KJ6h" eC'G[8$eTH&YMG(U2RjQEZXbYSlbAJl@THBLIMhb%I'YqL'T5@P94A8e2GR9EAR& hEfYbJBGqFAkCTVHkTl$"YUbRU+fFLBeh9&edE9YA4dGE1$Pd9e+#B@',MSQ$SE# *LCD*Mjq8L*'BTk++Um'8Rl*cGkaU1RCm48&E5#p@G'&@9@k&F'k-TkH,KCQMQj' @P*!!N!"iDCbiMjZrUjZJRTL5M)"U9%!k5%T&2MYBB%4AJ(jrQ*Q-QkqUT,DhT+5 CLT+CQ)KlQDClGD#3!'q6LdG8G8ik8Na%9Na(DRPdI)U5ND#JNUr"SD+cQBqHQ*! !J)DJJ'4[HBb#F(plEfPEDQjJF'j66f*VDA&lK)f!FiQHRU1GN!#DUTPiSFf6HU1 HG(5-F@Z&CNYGCepMFfTJC@PdGh"VGSKqI)&qPTH0RCU5Qk+CPE'hQjfFN!#IN!" JDieT-%480daJ9PeRFA4mJAkEVC&iKkHJL)ZHS*!!LB'#PjL6Q*@APBq)ISL&E@Y I2$eG@NG5@9jaH(L8XTD#TkqIPBHCUjU)K(9aT+GTGU@FJ(k)LSQ1L'KECQ4H9&0 F8%aBCQ4RPjGlS,'FR+UhX*UBRT&mKTZ"GT@CKQYXLi"hJ'j[D9TXFfCRD9aBAPC MGQekKS1BP)QaeV5+T,UEL*QDNk@9GSH(DA"rG'426ep6@'YPE'4@DfaPGh9cJhY kMT'5Y-kKP-HeP+LRQkDLI'L"KfpQB@&U9$K'C@P8@A9bDAk&HSb@I)'9G@q8MS' DRiCqREDGRVkVND'QKR1"M(jVC&9-B'G@6e038'GTA(1,L)Q3!)Z+P*QCN!#1L)D DQjZVVVM!Y*Z*Qk&lDfpI58"28N"1A8!pAfTPCAL1R+HCQEkqTE@VJS#&GAU+I(b DPRb)QTDIQ'ePL(0%@i&`9eCPEfGSDQb%K@jkJi'KVCZ8NTL3!(H"M(H$R(j[SD+ )SkqNPi#&M'jLFfG#2%pB8NpFCh"aD(9pK+@PK*V*UiU[XTkSTik!MBp`FiemD(C hDQTQEfj18f4D99KVLBaqKCfJPU#KRUfEGi19MC+@LSf0HA"XEAYfC&KGDRb0H'Z ARQjXNBGRIj0qG)#2K)ZVP(H#KRTZGB"qIB15NBQ2SDD1KSG`EhpVB(ahAQYbFh0 EIC4JC)9rG(bKSBkSSSbLUSppP++,H@emRC+!K(4aGeY5B&9B8d&FE&YSLk#@P+1 MSTZS`DQ+PkbBKCQDK)&qF'CFA("[5e#"H9KbJR&qG&CQI(YYCS1FQTk6PV1RP+L IJSL#H(jhM*&[KTYlF(Z(Kf*DH@pFCS#'AQZ3!'"'DA"RFA0UFAq1SDU`YUDCV+k @Qj1-UTjrK*!!Q*+%FQCQ88C%2%G-2d0GC9eiL(CrQT@"L+5q[D@fcV1TXkbFQCP fDAGcG'jdI'"JG'YF6%jR86KPEP0iKRZMX*!!LjZFR*Z+MD@0HCQ4LU18MTL)IB@ 9JAQ6JR*hI(*PKhJr8@&-3NCPF'9pJf50`U'4QU#ULiQJNjkKSE'6NEDTLBZ@Gep aAdYKC9P*4eeN8N*AGR9SDhb,Sl@NU-1jTkkHM*5,JB4qFQq-Ti9RJBpdC@PNBQT M9'4dB'*iHiq,9QQFLi#9Mi@IV)q1RC+RURC`MBTlIBGrJC5)Bh'4Gh*[9'Kb86p PL@GKLRYSMD*lI+'5NCQ+NjQTXTDBT*@EQhTbNBCE@@CNDh*HA(KZ89&QIhPUF)' -Kj'RSjbIPT@HLhqFRS'%Qjf!J+QEGhP`BQP93@TY3PYhB@4eHif+IiQ-NTHPUSU @Y*Q#M*H%GB@(IRG`IjD@Ji@0IR9kEeTGC99AANjDEi'(Fj!!S(16ZC1AU*QGRC5 -KT'6KRprF'5-QQadS)PMHheBBRTX5$p@8&CeD'q2IiDPTULRTl+SSkf6LUU9JT4 hCAjmD@PpJ'CMG'"EKhP'9("U8&&ZHR0VJT@+Ql#UV+fRX,+GQTb1NSZ"JPpZQQT 3JAj-6R"U8PPYFfTICAU(HhD3!)K`Mjq)Nk5PTUQZPSURTBk,NReTKj!!FhQ,I'G QCPK)8'4C4eGYE@0qSiejN!#6Kj!!PTU6MD@VR*@GVk'6SjYlGT'-HSL,H9pQF%P %9N!i5dC%AfYfRTaqPEHpU)QIcUGhS+k)L*qPQSQ!I)56J(##Hf"ID&P%9&%h8eX b5RekF)+DQjfkZU5m`*ZNYBCUNCGeH)0kEA12N!#$L)1#LAaF8'Yb99&B5P&SE'e `EhD+STCrUX5ETEqNN!#AU+GqFCH0CAf4JBf0ISTlA9aIA&&)8%a)@Q9UGRZ(LB+ 8TkZSX-#fX+kYZ+@IU)"KFR9NDR4MBQTIDPp4F@**EAGM@QfFPfb$TT@9QiZGXT* pU,Z0HTfcRReiJRThHQeaF'CfF&46DAPP@feXCA50LA5#Mi+2PSD6TCQ)PkZ,IUD RNk+2ET1XKfq$M@YGEPFj5e9&6PC1A'eeHi+6PTDCPk5`UkDdV)f8STk2JT@8F@4 iLhTYFQjjCdC089"15&C25RQ*H)kKPTqhXk#EZmZ2LVZ4I*Z%H)Z%F'4JEhplC'# *M&Y8D@PKBQ*DC@CPKiGhM*ULSBbDZUbBRU@SPB5CPifCIf4lN!"qE(*kHA9ZBPP AA9eG@djDDfTfGR+6PiZ5Mkc(TTfl`kbGTl1lThYhLAjTBfPD6@PP,cCJ5d*H@%e QH(1)PBQHUTbJU+qaTULhXkH6KkHhMhU$HfjcBdPQHNp%B&!h5'PbBPG`MAjjPU+ APTq3!)#IVj5,RkkAGSkVN!#%Q*CiDSUII&pfMA&069Y928CG69TVA(Z6KSb1PTf 0PCq9R+qdTU#PQUI#Rhf*LiGkA@0dF@K559)l1&T&19eB6R59NT'RXE1ZS+biTk5 [ST58Nj!!S+'&IAY`D'ehBeT`DP*6AeP9DQYACR&PITU&JDHLKT1XXCb@UkL9M)' *Tk@#H)U&HS&pGRGhG9j59e09@9PC@@4SDi+0HBDQLAUPUTkUZ-1eQ*bPRkqEDAb %B'ehA@f$CePG@PG*8'4E99pSHSU*PUZBK*'JT*kCUELPMk'QPUDJHRGlB&TVC'" YE'"EC'4GD'TNCQ*TH(k2MS5DRBD-QTQJTCbGRT16RkQILjQ3!'"ZLQaIE@TEA@4 95daHI'Y3BR&lMB+"QC+'PjD5XEULRUqVN!#5UU58N!"mEhKkG'pVD&pG96j"6eC LAPYRF(k8RjkHR)Z1TU5DVEQJPU5ENCQ9M)9Y@@TkEQTZDh&hDP"2A9pLBPeMD(Q 8Q*19Pj14NBk6SU5AN!#XVi+,VCL,LfYVKR*PG(ChDfTR58jQB&KHA%CDMijpNTk 0LC@HTDLXY,QRM*5TSTZFI'0fIQ9GGA"FB9*'9Ne%A'TLBQ9PKD1HPSkET*'BTE# rS*A$XhL"T*KeDQeKB(G`B(&pGA*V8e"X@8PfDdPdPSb)R+D*MUD(HCqYSD#HT+1 -NCfFN@eUGQ9VJAehJRpG9fTJ8eK86Nj4BhL&P*HARTbJSDE%[Tf[`k5+QDLINhe RBQ0bEeaFBfKB5PKE99eKD@K9DBZ1Qk@9MTkcXjqTblbMXkQ)IBH5JfCDC@CEDR4 XC'GqDN0EH'eMH(4@EjfDJifPM(D1NS'+Sl@ZRULMLjf[LhU0EPGhHQKbHh4X@e4 IA8a,B&e"@)H+JT'LQSf5QBq0V,1BUm#PQD1RXU*hERKX@eCRE&"3AdT#B&Sp8R0 X@'b@R*bdZk@CT+5ESkZRRCZ4IS52M)L&F9pZE'&[FQGA@'"0@h*6AiY`6A'RTCD JQjLBP*59RjU4SU'3!)Z(Lj''IAPiJ(plKi0aFA&J894@3ceDAe&IGSU*ND58NU5 CN!#@V-'dVVZbRC1CUTKTARPe8&0jG&KD9NY95d"5A&TC9h'5PUDrX*fTXDDETlH aUk55QCf2MB&hH&G(B@PK@eCDCfYHA@PSFS*T8A'8NSq6NT@CPSb+Q+DSPBQKUik *Qjk9KAepF'q)J9P2C@K,3&"BA@"ECA4dG)HBNS50QSU)SV'bV+qpYDHIRD5BKRj RChp`@eeB9P!h1%Fm39TQB&b$UU5QX+LNUU12QUZJSU@IV+1#MDU0C'ecA9j`Ef& PF@GE@eCCAfCVBPjZM*U9R+bRQjL)L*fFMSL6R)k*PU#GMBD(IRGlIRTeF'KMAPT 8699NA%G2E(4iKBf5NCbYSk+m`UkNV+kQN!#&SU*fF)Pf@A&rA8YE9$a!88j0AQj ZCQq-R*D6S+@6Pl+cVEUkUDDZSS0dH(KSA9P6@f0UH@p8EAj36@YMDi+!FR@CUif -Sj'%Jh1#Q*'@TD+JV*k0RD1-FQ*TE@K`HA"PEA9Q6P&XDeGBB'*cJS14QT@8LiU BS+LGPV@dSDq[U,'SN!"hGS0K3Q4S28G80MeC@9*KH(0ZHBLNTC+GX+kERVU`QUQ URjZ-JRq-MhKeF'KcE@GaCP06@Nj!8f9THRphKC!!PkHJMC@HN!"pLD@LSUL9R+D +Jiq-KRTZE'jeL)TXF)0K590*5eY56f0UD)#GQSUFU)Q-UkHNUU#R`,DBP*ZCPS0 TB&YJEfKHBPpFBee)4ejSA9THDAk)Mj@AV+qCSl+XX+fRX+@CN!#"Q+"jE'jKA'* RC9a1A(051@"eCfYqIQafP)b!NT@+KSkSTjDXYk+MVD++JTLGIh&`CQb!G9TEAeC 956j9C'"XGA0rNjH1N!#9Nj!!LT5ER+k[SkfZVD+#N!#YK9pUG'jPE'j@AQe33%P 09f&QB@U,Ki5VT)kUU)Z5T+58RDDCT+Q8KiQKRACVD'epEeaPE@KJ6Na@8PC9@(& XDiD4NTZVUT19YEkJPVHeR*f5JT+LM@CXK'aJF@9LD&TC@Nj'9@GB9R"lFQarPC@ @RTZAUlURTVLfV+DGK)@BLRCZG(CKB'0THPp*Aee*5e9HEhCXEAk)Kj@HJhUBVDL AS,qqVEQZND'IJS9mEQaC@A&eB9"GEe-p8eP4Ah&fDR'4QCDHPTQJMj5MRkU[T+U fVC+2TU5'FhGS8@9b@8jDAPG33N0JCPjSFhPqLCbEQ,#SLD@pQjQ[RCU`TSk1NT5 HL@GfK'48CQC09@)q-PPH5@5$DQQ,MBUAU+Q-LkkfSTUVVjqRViaiMCZ@K'jhIQ0 SI@YJB&C83MK8@8KVKf4JLD#AN!#DNBqUTCDFTDkbVU1PRiD6UBGRFhKMBh0S@&j L9NY%2NPGDA"N@hDHV*Q3!+1VT*qGV+qJUE+MRjk4LSfENfG3CA&E9&j34@&N0$K TEQCcG(1&PjbBQUHVUDHBSDqEQkUBPTU#IT1CMhjVE(KSAQGD8Q4I1$9GE'&NFA+ "PS'#U+D9QCU8QkkYSU+RV+H6KT5JPSCZERPNB@eI8e*13$G#590RCQ&fK)HNV*L LY+HGUl@SSkbVX+q(I+'HKApR9f9K99pI4P"`@$K)@@&VD'TcJT+,PE1RPk5QTD1 BPk5YR)kEQBH+PT0lBQGYB'CK6QGa8N4'8fGPBh0bCRD+MT+ESCH3!++[Sjkc[DH IUk54NDLSGPebFPpJAdT-@P!r180-8fK[DA*jLTk@P+DYSTUMX,1ZVlbmU*qKQ*1 @J@aR@P*BAP9'99a'4%T'A(0UEi0lJU#KSkZFQU#4QD@@S,5LQ+HHKjDSM(&cFQ& CCfYG99YI8N93BeaCFAPXFBZALBZPSif(RV'GPV+aRk1TRjHQUBjpG'e[DQ&D89" @8N)j39"MF@GJGiU4QTQATDDBQUHTTE#fU+'LNSLJTRpVF@GGC@aG5P9P@N3k3eY fGPjMJ*1ER*QETkD4PUQHNk'ZST@HQ)b8N!#&I'4JGh&CAfKcGeY2B&P6C(*aBQC rLSb4PTUIPBD9Sj1BUU#CSjk0ND@IK(PhF'j[DQCHAA"S4NTFAQGQCh&TGjL6K*b `P)LNV*qLVkZITDU@Kj+5J(PiDePDD&a5A9P@@9"4BA"pIA&fN!#JQTLPST1BT*f 6QkHNQjD9PBU$MSGaCepJE@YA@h0S@'"C9'acDA@"GhQDTT18QjHANSq8PjkLQTq PPSqEQSk%FQKVCeT5@@4L9&"C9NpCC@eaF(@(QT59VkqAQDZSR+5TR+1bSif1QTD )GfKLAP&1@90&9@"-3&CTCQTfH(f0PjDDUV+NR+5RTTkCU+H@PT5+NCD%G(0VCfY E8Q9M5P4I59*X@&4rLR4mPTQ9TUL0Mk5NQTQLSk@URTbRR*+3!)"cEh&cC&9JC9C A@8T,@P4)AhabD)#BRD'NR*UVVC@6UUfXVD#MVU@6Nj9qDQ9IB&aGBP&-CQ&&8Q" 6@R"fER',QCfVT*kYSTDRUCHCUDH9NTU9MC!!L(9[F@GAB'e@5faU5e4QCf9REQa eL)5'PTHAQ*!!PUHMP*DUXk@0KkZjM(5!IhelD@"SCQ&R@%*6Bdp4D'CYJRelMC@ CR*!!LjbPQCbKRl+hQ*'LSSjlI(9SFQ03E(CD@fYJ@&jGAejQJRY`MTLDU*H1RjU BRik)RUDFP*5KRSZ%JRYbFfPADhKL@QC[BeTTCPKXIQe`JB51PTLIPj'FSTb4N!# LU)q*S*b*NT9rF(CjD@PaBPCGBeeB9eaRD'4bJB+#K)fLSj'8SDUVQTQRUU18MBk )KiCmF'YaH@pG@@&SCeC)@QTDA'e`JBTqLjqGPCDKRjHDRjqBR+ZJMBZ*LB9fDQ0 XIA"CB(*cC9pNAf&SA&a[HAeiH*1HNC5MS*QHSTH5TV5GLT@KQBTmER*iE9a8CA* L8eYUE9j9B'jQAh5%JS+(QkQGQULZTjqMTCkMU*H3!*k9JAKiIQa3AR0J4%pQAeT I@@&[F(0iISH&KT5HQC5HSk+LQTZSUD1DM)qENApiHAKXDA&T99&JC900@&aMDfK `JB+'N!#2N!#EPj!!R+1CQ*kDRDZQNT5HNS"rJ(CaH(4UBPaSEPC09eTD8PGZFR5 %KSLASk@CPkHKMSqHSjfCQ*L5NippHhjiF@KSEf9JCQCJ99YXB&0LER*mKBL'QE' LPkZRP*UJPSk6P)U*MBQ"HAZ!GfjdF@CVD'4XCeeUF&YIHA9[Ji9mMCQ0P+LFN!# GT*QATD'4M)H*N!#(G(+"J("`FfaLD(4M89pUB&aUFR+$LhL%STH2SU1BQTUFTUD BNTL6L)CqEfY[Fh*VB'0aF@GIB'Y[Bf9dFA5*MS'0STUDS*@HTSf&N!#8Q)q$KBU 2IfYkJA"`DQ4iDeCdH&aXI'PKERCeIBCmJ*fCKjDSRj'3!*bCL)Z@Li5+MBKkGAq #H@aaGQCDA@GTB9YFDA&XDRL(JB#6P*DRSTUNUTf6SU54N!#5M)9pJS&[ERTdB9e UCf&XANjUFeYMER*qIS@8MT5PSCZISD+EPT+1QTq+J)L1M(CTI)0aEA9[B'CbCfC bC&TSDQ&ZK(T`MD'9N!#FSD@NPT'CS*U+Ljk@K)f,HAf&H@TYFf9KC&eLDQ"9@'9 PCA4eGj19KCQSS+U`SCDASTq0Nj1+NiYmK)&fH(CUCQeZCPjKCQ0I@Q"UB'9lGB1 HL)5SVTk@RDZNMj'DNT!!N!#(LSk"GA4mIR"UGA&JCR"UC9jIDQ"8DAYaFAq+Nj5 5QU1RS*56QjkANj+5MSq3!(ekKAeiGQTVFfPHCQPQCee@C'aRDR9pKBk,LCULQTq NPBqGSC@-NTQ6LBH'JAPfG'aVE@GPBQ9YC@0TCQP`FRTrIikCMSUFUCU,PCH1PT' )NC+3!*1,Ihk)Jh*fGfT[E&YQGfjGA@TZD@ehHi#3!*'#LjfFRCZ,KCDIL)'5Mif AM)+%IiL&E(5%F&jNEh"UCPTDD@YMD(Q&L)k0MTbJRk@6KCQCK)12PBZ(N!#'HSL *GA0kGA0ZC'T`E@PJA@&JBfPZHi"rN!#EP*UUUCb8QTZ-KiL*N!#+J)D&H(KqHA& cFfeUD@jjEejQF'TQCfphI)Q)HiqRRjbPRT!!P*q8IiH@Li+)JhKiGRPmF'jbCfa hFR&`D'YZCfTdGhQ"Ki5&NjLERTHAPTLFNC!!R*H5NBQ%IACjGQeYE'*KEACbB9e XE&pNFA*kL)5#P*Z9Q++IPj@9PTH@NC1CQC5'HAYpGfeMB@KRAQG[CQYTBQPQDRe qHi@1P*16RD+KRC+1N!#*LBq-NTZ-JSQ$JBCkE'aYD@KSCfTXBeYJDfGQH(YlKSH &MTbNQj1BR*f8KBfGNSL0Nib!J)+$JA0bF'4SE'GH@@CR8eTUERb$HS18N!#4T+L EQD'KPif4QjD5Mi5%JRCeIAeaC'KbF'eXDQjRA@&NCQTdJiH!KTH@P+'JQCkAKik DNSZ4Q*@)JAq!KAp`E(&aDfY[EfjYDfGJB@0UHRYfHS#3!*b4PDDDQ*k5PC@0PTD 2N!#2K(k*KA9`F'aNC@YRB@PYBPeSDQGiJA9kMBU$PD@DPD+LPC+9Q*UBMS1(MS* cHB&kF'GQER4XAf*YCPaHCQaeIi'$KBH8R*58QCQ9Lib8NT'4MBq3!)TrHAYqH@p XE'TbG@KNEh*P@PjUFhCiI)''M*HHPjUNQ)H1NSL0PBf)MT1+I(k+KhPYDR"bD@G UD@GQBf&KChKlFAU%K*'CQD+JQjU9PTL3!)Z9PB5&M(plKB4pG'peFQaYD'4SD@9 EA'jcFB#"HBZ4MCZJQCH8QCU1MC18PSq#JSL$HRGjIAKYERGcDfjdE'*KB@0UFhK eHSD)MTQBP*5FQib+P*H8P*!!LSf2KRekJ)&ZCR"[DA&[C@e[B'9VCA&rGA#$MiD ,PjHFRC52NT11P*U1Kif2LRpiIS9hCQKYDfTSCfPVDQ&QG(*aJSClJ*!!Nj'ARCQ 1MjD6N!#2NT5*Kj!!LhphIiKfDR&[DfpcDf"XEf&NDh&dH)@$HSU9Mj+BQC@0MC+ 3!*!!MT'CNBH,Li4rJAjfGQpSFh&MDA4UA'CTAh&rFhb+Ji5AS*H5Qjq8MBq5Nj@ 3!)f0LSQ$Hhf!GfjYDfT`E'T[D@4NCfjXEhaqHi'+NjD9QjfAP*'6NSk8PSZ'Lib "IS4lEhGdCfacD'TaDfTZCQ9[G(ChHB+&KT'5NTZDP*58Nik1Pj@(KBq*HAarHRK cEQeXEQjYDfPPBQK`ER"lHhZ$JBH@N!#4Q*'6PT!!NjD@PC@4M)Z%IS1"H("[E'G [G@aLBQTSB@4RF(amH(b)N!#6QT@1RD#1LTD9N!#ANi@*NBepH)0qG("UE(&`F'e SDh"SB@adG(TlH)'2N!#0NjQCQT@(LTf8KT'2KSq-IAk,KAGfFQpfGQjRDh*SB@T TD@pYG(jpIi@2PT5DRC56QTQ4Mj58M)5*Khf"K(KbGA&`F'eaF@TTD@KXDQPfIAC pKRk*SC@*QTk6P*11PCQ4KSD*K(q"HA0lG@CYGR"bG'j[EfpbE@CcK(TZH)H0MSb *MjU@MSb0NCQ@KS55N!#%K)&iIS&[CA"jG'aYF("`D@4[HhCZH)"lJSq+LCLCN!# 1Mj1CPik+Mj!!Mif!IS9pGh9UDh9`C@PaEfPPDh*aGRalIB@)Lj59NTH@NC!!NT! !MC!!MB@'MBPqIi+!I(4`FR4bF(&XEA4VCA"cF(PqHhk$LC'4MC5DM)D8NiL-N!# +LBQ'Ki5#KRpeH(G[G(9[F'jTDfYSCfY`GhjlHS54PC'5PT18Pik-PT'+NBb$LSY qHAjrFfTcGh"XE@eZEQTQCfTaHAPdI)Q0N!#5PC@3!*HFN!#)MT@ALRf&NSThH)0 qG(0[E(9hE@P[GQeLEA0UFB"kG)#0MSU1PC15PBk-P*10LBH0M)1$J(q"I(4`FhG cE'e[E'aTC@PbFA&rJ(+#Pib+NT+5P*54P*52NC1+LBZ&JB"qHRGhFfpcFh"VDA& YBQT`E(9pHRf(Lif2NC58NT!!MT!!N!#0MT'+KSb*K)&pIhTdH(4bHR9TE(9eE'0 VGA0dGhL!LSH)P*+0Nj'3!*+*Lj@-KBU+LBL!J)4rHh9cHA9[FA*ZE@jSDh4YEAY jGRk%LSq+LC'9NSb1Nik0LiD)KSH'I(k"HRGkHA4cFR"`EQj[D@abGAKjHi''KSH 2MSZ3!*+2M*!!NSf0MBL'KB4rI(ppHACdGhPfFA"dFQj`E@efHATkIBH*LBk-Lj' 3!)f,Lj!!M)Q-LBL*KB@"IApqH(9iHA0bGR4aFR"[FR4hGhGqJB+(LBQ1NBq,MBf 0MBZ,KiQ+JiH(IB'&Hh4kI("aG@pZF@pZF(*eHRPkJ)1)LBQ3!)f0Nik,MSq1LiL )Ki1$JhjrJAYhH(PhFR"dF@e`F'e`GA9jJ(k!LBQ*MBZ,N!#,KSb1LBH*LB5"K)1 "I(TqHhTkG(CiGA9bF(&ZE(&hGR4mJ(k&LSH+MBb0M)U(L)q2KB''L)D#I(f%Ih9 eHRTdEh9dER"`ER"eGRClIRZ$MSL)N!#2MT!!MiU0NSb(LBH'KB'!IRq"HR9kHhC bG(CaG(CXF(YhH(pqIB+*LSH*MSf-M)H,N!#0L)H(KS@#Ii'$J(ajHheiGRKhFh0 eFQpcGRGjHRZ!K)D(KiQ-LSZ+M)f+LiU*LSH&K)1!JB*mHAaiG(4dG(0bEfecH(* dIReqJi1&LBf1LSZ0LiZ+LSZ)JS+&K)1"IRjqHRKjGhGhFh*dFR&dGRChHRaqJ)' $LBZ(L)b-LiU*LBU'JS1&JB#&J(U"JRPjHRKjGh4aFh4bG(9eHRajHi##JiL*KBL 0LSH*LSZ*KS5%KS@"Ihq#J(PhHATiGAGdFRGeFR9eGhjpHRk#KBD'LBZ*LBZ+LBb )KBQ)Ji1&JAq#IhPlIAGeHhGcH(GdGRPiHAjpI)#"JS@*LBL)LBZ+KiQ+KS@&KB@ $Ji0rI)"qH(PlHRKfGh9hHAGfHRelHi##Ii+)L)D'L)b'JiZ*KBH%JiH(JS##JB& qH(PmHA9fGR9eGA9hGRKmI(eqJB1%KSH*L)D)LBH)L)@$KSD"JB5"IAq!HhTlH(K iGAGhGA9eH(TkHherJ)'#KBH)KiH(KiL)KBD'JS5%JS*rIi"mHhalHRKjHRThGRG fH(PiHRYqJ(k"Ji5(KiH(KSL*KB5(K)+'Ji'#IhepIAakHATjHRKhHAPiH(KiHRe qI(f#K)5&KSL*L)D'L)L&K)5%K)5!IS&rHhjpHAPkHRPjHRGjI(PjHharJAjqK)@ $KBH'KSQ(KBH'KBD%Ji1%JAf!JAamI(TlHRKlHhGjH(PkHRaqIAq"J)1(Ji1)Ki5 &KiD&KS@%K)1%Ji"rIhpmIAjjH(YmHRPjHAPkHhTlJ(pqJB'$KS@%KSD&KB@%K)@ %JB+%JS'!IhjqIRakHRTkI(PhHhajHRTjIS"rIRq%KB5%JiD*KS5$KBD$JS+"JS0 qIB#"IAamHhamHhTjHhYkHRPlIRjrIhq"JS+%K)5&KB@%Ji5%Ji'"JS&rIRf!IRT mIRelHhalHhalHAYmI(eqIhq!JB'%K)5&Ji1&K)1$K)1"JS+!J(jqJ(jkI(emI(a mI(YmI(YpI(arIhjrJ)'$JS1$Ji@&JS+&K)+#JS'"JAprIhppIAelIAplHhemIAj mI(f"J(erJB+#JS1$JS1$JS1$Ji1"J)'#JAjrJ(pqIRepIRemIAelIAjmIAjqIhq !Ii#$JB#$Ji+#Ji1#JS+#JB'#JApqJB"qIRjpIAjqIAapIRamI(eqIRprIi#"JB+ #JS1#JS+#JB'#JAq"JAprJ(pqIRpqIAjqIRepIRjpIAjqIRprIhq!JB'#JS'#JB' #JB'"JAq!JB"rIi#!IhprIRjqIRjqIRjqIReqIhjrIhprJB'"JB'"JB'"JB'"J)# !J)#!Ii"rIhpqIhpqIRjqIhpqIRjrIhprIi#!J)#"JB#"JB#!JB#"JB#!J)"rIi# !IhprIhprIhprIhprIhprIhprJ(q!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp rIhprIhprIhprIhprJ(prIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!! !4US!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!%D!9Zk,S`!!4Ri!!%Cr!$b!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp rJ)"rJ)1#JB'!J(prL)k%H(9hIB&jGRb!J(pmI(ajG("aG(9eGACjHAKiHR0VDfj bG(9iGh*aFAD#L)b2M)Q+MjH9MSf(IRU"N!#CQ*56PTLES+#8LSD#J)@0Nj52LSQ ,KRjkH(GhGRU$KB+%Ki0lG@eUIjUJQT5,JApkGR"SC&jGDA4fE@ahF@9KB@GXCPG ,46`l59KKBPaCA&pHAf&LC@acHS#"J)+&Lj5FT+bdZVQfZ,l"`XM6fplJiq,GeF[ %`m1rZ+fMQC!!L)0rHA0VBeeD9e&-5%9%36Xf-c)d06Bi1cXh-5m`-M3f0M8d-c- i3NY49eaME(*fHAYmIS+(M*'9PjUIT+LYXV@fYlHhYV5bXV+bY,HkZlblZVUkZVQ hY,1bX+qVTk@NSk'JRjqGQTD4MSZ*Ki0rHR9`E@PQBPeC9&"+3MSd,LNQ*#-M)b3 P*L8Q*bS[0$T!48K+6P*9@9pND@jcHB#&Lj'@QjqMTULVVV+dYVLk[,r$b-c4eGE @eY64cFR&`EfjYV+[UU@JQjD4MBQ'Ji"pHA9bEfaTCQ4LB&pGA&YC@&KB9e958%j ,58G%3N&"38*$48G)58P*58P+5de18&0CAf9XFRKrK)U3!*@CRU+PU+b[XlDj[Er "`X2%a-6&a-2#`F#r[VflZ,@bVkfUTk5KRTZANj!!M)L%IhTeF'aRBepE@&968%e +4N*!2M`l16Ji1$Jj1ce!3dC)5dj499KD@eaHB'*PD'Y[FRCjHhk!K)H+MT'8PTQ ERD#LTDLXVl5j[X2)c-r3d0(3cmc*aX+qZE1[UU@LRTUAP*'1LSD#IRTfF@eSBep D99"-4d0"2cir2cmr2cmr2d"!3%d9(5Nj499PHBfKXF(4iHhq#KSU0N!#6PCH BQTbHS++NTULTUkbXVDfYVDkYVDbVUkUUUUQTU+LTUDLRTD1JRCZCPj55Mif,L)D $J(ejGA&YD'0H@PG68%a*4N4"2cmr2ciq2Mp!38*$48C(58Y06e*9@&YIC'PZG(T rKBU2PCUGSD5RUkqbYEHiZEQkZlZm[,blZVLfY,1`VUZST+#GQTH8NBk,L)5"IAP fFh&ZE'YTD'GQC@9QCfKSD'GRCQ9NBf&IA9YC9eG@99C@9PGA9eKC@PYFAQ"MCQK VER&dGhYqJB5)Lik3!*+8PjQERCqKSk@RUDUXVDqbYEHjZVZlZlUiYV5aVUURSk# FQ*53!)b)K)"mH(4[DfKNB&eC9P458%p168e06Nj16dp389089PKEAQ*PD@eaGAP mIS#"JS+$Ji1$Ji1$K)5&KiL+Lif2N!#4NC+6PCDAQ*QDQTZFR*fHRTkHRTqIRjq HRCbFQjUCQ*LAPC15N!#2MBZ*KS5"IhajGR*ZDQ9KA9P@8e"05dP(4N9&4NG(5%T ,68p38P9B@PeKC@PXF(0iI)'&LBk6PTUGSD5QUDZYVUq`X,#`VkkXUkQRTD1JRCU BPT56NC!!MSf,LBL(KB5#JApqIAYkH(CdFR"[EQjYE@aXE@eYE@eYE@eXE'YVDfT TD@KRCfGRCQCPC@9NC'0MBf0NC@CSDQa[FA4iHhk"KBL-Mj1@QCbHSD5QTkQVVUq aXl5eYE@eY,1aX+kXUDDLRjZANiq,Ki0rHhKdF@jVD'CMB@"IAPjHAPeGA9eGA9a FA&eGAPpJBQ0PCfPXER&cGAGjHherJB+$K)@'KSD'KSH(KiL)L)Q*LBQ+LSZ,M)b 0MSq3!*'5Nj@@PjQDQjbFR*bFR*bFQjZEQTUCPjD8NT!!MSb+Ki5#IhajGR0`E@T RC'&HA&PA99468P&48&&489*699CB@PaIBQ9SDfjaG(GkIB#$KSL,MT!!Nj@@Q*U FRTqJSD+MSk1LSU'JRjkFQjQBPT@6NT'3!)q1MBb+LBL)KiD&K)1#JB"rIRemHhY kHAPiGhCeGA4cFR&`EfjYE'TSCf9NBf*KB&pIAejHAepIB'&MC'CRD@YYEh*dGhT mIi'%KiU0N!#5PCLDRCqKT+DRU+QUUkZXUkZUUDLRTD5LRjfEQ*D6NBk-LBD%JAj mHAGeFh&[EQeXDfTSCfCPC@9NC@9PC@9QCQCRCfKTDQYXE@j[F(*cG(9fGhKjHAT lI(epIRq!J)'#K)@'KiL+M)f2NC+6P*@@PjLCQTUER*bFR*fGR*bEQjUCQ*H@P*1 4N!#1M)U)KB1!IRYjGR4aEfaUD'CNBQ&JAejGA9aFA&eGAPpJB@*NC@GTDQaZF(* dGRKkHherJB+%KBH)LSb1Mj!!NT16P*59PC@9PC@8P*58Nj15NT'4NC!!N!#3!*! !Miq2Mik1MBf-LiQ)Ki@%Ji+!IhjmHhTjGhCeGA4cFR&`EQeXDfTTD'GQC@4NBf0 MC'4NC@CRD'TVE@paG(CjHhf!JS@(LBZ0N!#5Nj@AQ*QEQjbFRCkHRTkHRjkHRCf FQjQBPj@8NT'2MSb+L)D&Ji&rIAakHAKhGR9dFh0bFA&`F("`F("`F("`F("[Efp [Efp`F("`F(&aFA*cFh4eGAChH(PkHhYmIAeqIhq!JB+%KBD)LBZ0MT!!NT19PTL CQTZFR*fGRCbFQjUCQ*H9P*+4Mif,LSL'K)+!IRelHAGeFh&[EQaUD@GQC@4MBf* LBQ0MC'9PCfKTDfeZF(&cG(ChH(PlI(eqIhq!JB+$K)@'KiH)LBQ*LSU+Lib-MBf 1MSk1Miq1MSk1MSk1MSk1MBf0MBf-M)b-M)Z,LSU+LBL(KB5$JB"qIAYkH(CdFR& [EQaVDQPTD'KSD'KSD'KSD@PTDQYXE@j[F(*cGAGiHRaqJ)1&KiU-MT!!NT18PCD AQ*LBQ*LBQ*HAPT@8Nj+4N!#3!)q1MBb,LSQ(KS@%Ji+"J(pqIRemI(YlHRTjHAP jHAPjHAPjHAPjHAKiH(GhGhCfGA9dG(0cFR*bFR*bFR*bFR0cG(9fGhKjHRYpIRq "JS1%KSH*LSb0MT!!NC+6P*@@PjHBQ*QCQCLBPjH@PC15NBq0M)U)KS5#J(jmHRK hGA4bFA"[EQeXDfYUDQTUDQTVDfaYE@j[F(&bFh4fGhKkHhapIi#"JB+$Ji5%KB@ &KBD'KS@&KB@&KB@'KSD(KiH(L)L)L)Q*LSU+LiZ,LiZ-M)b-M)b-M)b-M)Z,LSU *L)H'KB5#JApqIAYjH(CeG(*aF'pZE@aVDQTTD@PTD@TUDfaYEQp`FR0dGRGjHRa qIi'$KBD)LSZ-MSq3!*!!NC+6Nj16Nj16Nj+5NC!!N!#2MSf0M)Z+LBL(KS@%Ji1 #JB'!IhpqIAemI(amHhYlHhYlHhYlHRTkHRTkHAPjH(KiGhGfGR9eGA4dG(4dFh0 cG(4dG(9fGRGiHAPkHheqIi##Ji5'KiL+Lib0MSq3!*'5NT16P*58P*56Nj15NC! !Mik0LiU)Ki@%JS&rIRalHRKhGR9dFh0bFR&aF("`F("`FA&aFA*bFh4dGAChH(P kHhapIRprJ)#"JB'#JS+$Ji1$Ji1$Ji1$Ji1$Ji5%K)@&KBD'KSH(L)L)LBQ+LSU +LSU+LSU,LiZ,LiZ+LSU*LBL(KS@%Ji+"IhjpHhTjGhCeG(0bFA"`Efp[EQjZEQp [Eh"aFR0dGAChH(PlI(eqJ)'#K)@'KiL+Lib-MBk1Miq3!*!!N!#3!*!!Miq1MBf -LiU*LBL(KS@&K)1#JB'!J(prIhjqIRjpIAepIAamI(amI(amI(YlHhYlHhYlHRT kHRTjHAPjH(KiGhGhGhCfGRCfGRChGhGiHATlHhapIRq"JS1%KBD(L)Q+Lib-MBk 1Miq2N!#3!*!!N!#3!)q2Mik1MBb,LiU)KiD&K)+"IhjmHhTiGhCeG(4cFR*bFA& aFA&bFR0cG(9eGRGiH(PkHRYmI(eqIRprJ)#"JB+#JS1$Ji1$K)5%K)5%Ji1$Ji5 %K)5%K)5%K)5%KB@&KSD'KiH)L)L*LBQ*LBQ*LBQ)L)L(KSD&K)5$JS+"J(pqIAa lHRPiH(GfGA4dFh0bFR*aFA&aFR*bFh4eGRGiHATmIAjrJ)+$K)@(L)Q*LSZ,M)b -MBf0MBf0MBb-LiZ+LSQ)L)H'KS@%Ji+"JB"rIRjpIAamI(YlHhYlHhYlHhYmI(a pIAepIAepIAjpIAepIAepI(amI(alHhYlHhTkHRTkHRTkHRTlHhYlI(apIAjrIi# "JS1%KBD'KiL*LSU,M)b0MBf0MSk0MBf-M)Z+LBQ)KiD&Ji+"J(pqIAalHAKhGhC eGA4dFh0cFR*bFR0cFh4eGAChH(PkHRYmIAjrJ)'#JS1%K)@&KSD'KSD(KiH(KiD 'KS@&KB@%K)5%K)5$Ji1$Ji+#JS+#JS+#JS+#Ji1$Ji1$Ji5%K)5%K)5%Ji1$JS+ "JB"rIhjqIAamHhTjHAKiGhGfGR9eGA9eGA9eGRChH(KjHRYmIAjrJ)'#Ji5&KSH )LBU+LiZ-M)f0MBf0MBf-M)b,LSU*L)H'KB5$Ji+"J(pqIAalHRTjHAPiH(KiH(K iH(KiH(PjHATkHhYmI(apIAeqIRjrIhq!J)#!J)"rIhprIhprIhprIhprIRjqIRp rIhprIi#!J)'"JS+$Ji5%KB@'KSH(KiL)L)L)L)L)L)L)KiH'KS@%Ji1#JB"rIRj pI(YkHAKhGhCfGA9eG(4dG(4dGA9fGRGiHAPkHhapIRq!JB+$K)@'KSH(L)L*LBQ *LBQ*LBQ*LBL)L)H'KS@&K)5$Ji+"JB#!IhpqIRjqIAepIAepIAepIAeqIRjqIhp rIhq!J)#!J)#!J)#!J)"rIhprIhjqIRjpIAepIAepIAepIAepIAjqIRprJ)#!JB+ #Ji1%K)@'KSH(KiL)LBQ*LBQ*LBQ)L)L(KiD'KB5$JS'!IhpqIAamHhTkHAKiGhG fGRCfGRCfGRCfGhGhH(PjHRYlI(eqIRq!JB'#Ji1%K)@&KB@&KSD'KB@&KB@&KB5 %K)1$Ji+#JS'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'"J)#!J)#!Ihp rIRjqIAepI(alHhYkHRTjHAPjHAPjHATkHRYlHhamIAeqIhq!JB'#JS1%K)@'KSH (L)L)LBQ*LBQ*L)L)L)H(KSD&K)5$JS'!J(pqIRemI(YlHRTkHAPjHAPjHAPjHRT kHRYlI(apIAjqIhq!J)'"JS+$Ji1%K)5%K)5%K)5%K)5%Ji1$Ji+#JS+#JB'"JB' "JB'"JB'"JB'"JB+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"J)#!IhpqIRepI(amHhY lHhTkHRTkHAPjHRTkHRYlI(apIAjqIhq!JB+#Ji5%KB@'KSD(KiH)L)L)L)L(KiH (KSD'KB@%K)1#JS'!J(pqIRepI(alHhYkHRTkHRTkHRTkHRTlHhYlI(amIAeqIRj rIhq!J)#!JB'"JB'"JB'#JS+"JB+"JB'"JB'"JB'"JB'"JB'"JB'"JS+#JS1$Ji1 $K)5%K)5%K)5%K)5%Ji1$Ji+#JB'"J)"rIhjqIAamHhYkHRTjHAPjHAPiH(KiH(P jHATkHhYmI(epIRprJ)'#JS1%K)@&KSD(KiH)L)L)L)L)L)H(KiD'KS@&K)5$Ji+ #JB#!IhprIRjpIAemI(amI(YlHhYlHhYlHhamI(apIAepIAjqIRjqIhprIhprIhp rIhprIhprIhprIhprIhprIhq!J)#!J)'"JB'#JS+$Ji1%K)5&KB@&KB@&KB@&KB@ &KB5%Ji1#JS'"J)"rIRjpIAalHhTkHAPiH(KiGhGhGhGhH(KiH(PjHRTlHhapIAj rIi#"JB+$Ji5&KBD'KiH(L)L)L)L)L)L)L)H(KiH'KS@&KB5%Ji1#JS'"J)"rIhp qIRjqIAepIAepIAepI(amI(apIAepIAepIAepIAepIAepIAepIAepIAepIAepIAe qIRjqIRprIi#!JB'#JS1$K)5&KB@'KSH(L)L)L)L*LBQ)L)L)L)H(KSD'KB5%Ji+ "JB"rIhjpIAalHhTkHAPiH(KiGhGhGhKiH(KiHAPjHRTlHhamIAjqIhq!JB'#JS1 $Ji5%KB@&KBD'KSD'KSD'KSD&KB@%K)5%Ji1$JS+#JS'"JB#!J)#!IhprIhprIhp rIRjqIRjqIAepIAepIAamI(alHhYlHhYlHhTkHRTkHRTkHhYlHhamI(epIAjqIi# !JB'#Ji1%K)@'KSH(KiL)L)Q*LBQ*LBQ*L)L)KiH'KS@%K)1$JS'!J(pqIAemI(Y kHRPjH(KiGhGhGhGhGhGhH(KiHAPjHRTlHhamIAjqIhq!J)'"JS+$Ji1%K)5%KB@ &KB@&KB@&KB@&KB@&KB5%K)5%K)5%K)1$Ji1$Ji+#JS+#JS+#JB'"JB#!IhprIRj qIAepI(alHhYkHRTjHAPjHAPiH(KiHAPjHATkHRYlI(apIAjqIi#!JB+#Ji5%KBD 'KiH)L)L*LBQ*LBQ*LBQ*L)L)KiD'KB@%Ji1#JB'!IhjqIAamHhYkHRPjHAKiH(K iH(KiH(KjHAPjHRTlHhYmI(epIRjrIi#!JB'#JS+$Ji1%K)5%KB@&KB@&KB@&KB@ &KB@&KB@&KB@&KB5%K)5%K)1$Ji1#JS+"JB'"J)"rIhpqIRjpIAamHhYlHRTkHAP jHAPiH(KiH(KiH(PjHATkHRYlI(apIRjrJ)#"JS+$K)5&KBD(KiL)LBQ*LBU+LSU +LSQ*LBQ)L)H(KS@&K)1$JS'"J(pqIRemI(YkHRTjHAKiH(KiGhGhH(KiH(KjHAP jHRTkHhYmI(epIAjqIhq!J)#"JB+#JS1$Ji1%K)5%K)@&KB@&KB@&KB@&KB@&KB@ &KB@&KB@%K)5%Ji1#JS+"JB#!IhpqIRepI(alHhTkHAPjH(KiH(GhGhGhGhGhGhG iH(KjHATkHhYmIAeqIi#"JB+$K)5&KSD(KiL)LBQ*LSU+LSU+LSU*LBQ*L)L(KSD &K)5$JS+"J(prIRepI(YlHRTjHAPiH(KiH(KiH(KiH(KiH(PjHATkHRYlHhamI(e pIRjrIhq!J)'"JS+$Ji1%K)5&KBD'KSD(KiH(KiL)L)L)L)L)L)L(KiH(KSD'KB@ %K)1$JS+"J)"rIhjpIAalHhTkHAPiH(GhGhCfGRCfGRCfGRCfGhGiH(PjHRYlI(e pIRq!JB'#Ji5&KBD(KiL*LBU+LSU,LiZ,LSU+LSU*LBL)KiH'KB@%Ji1#JB#!Ihj qIAamHhYkHRPjHAKiH(KhGhGhGhGhGhGiH(KiHAPjHRTkHhYmI(apIAjqIhq!J)' "JS+$Ji5%KB@&KSD(KiH(L)L)L)L)LBQ*L)L)L)L(KiH'KS@&K)5$Ji+"J)"rIRe pI(YlHRPjH(GhGRCeGA9dG(4dG(4dG(9eGACfGhGiHATkHhapIRq!JB+#Ji5&KSH (L)Q*LSU,Lib-M)b-M)b-LiZ,LSU*L)L(KSD&K)1$JS'!J(pqIAemHhYkHAPiH(K hGhCfGRCfGRCfGRCfGRGhGhGiH(PjHRTlHhamIAeqIRq!J)'"JS1$K)5&KBD'KiH )L)Q*LBQ+LSU+LSU+LSU+LSU*LBQ)L)H'KS@%Ji1#JB"rIRepI(YkHAPiGhCfGA4 dFh0cFh*bFR*cFh0cG(4eGAChH(KjHRYmIAjrJ)'#Ji5&KSH(L)Q+LSZ-M)b0MBf 0MBf0MBf-M)Z,LSU*L)H(KS@%K)1#JB"rIRjpI(YlHRPjH(KhGhCfGR9eGA9eGA9 eGA9eGACfGRGhH(KjHATkHhamIAjqIi#"JB+$K)5&KSH(L)Q*LSU,Lib-M)b0MBf 0MBf0M)b-LiZ+LBQ)KiD&K)5$JS'!IhjpI(YkHAKhGR9eG(0cFR*bFA&aFA&aFA& bFR0cG(9eGRGiHATlI(eqIi#"JS1%KBD(L)Q+LiZ-MBf1MSk1MSk1MSk1MBf0M)Z ,LSQ)L)H'KB5$JS'!IhjpI(YkHRPiGhGfGA9dG(4cFh*bFR*bFR*bFR0cFh4dG(9 fGRGiH(PkHhapIAjrJ)'#Ji5&KSH)LBU+Lib-MBf1MSk2Miq2Miq2MSk0MBb-LiU *L)H'KB5$JS&rIRemHhPiGhCeG(0bFA&`F'p[EQjZEQjZEQp[Eh"aFR*cG(9fGhK jHhapIS#"JS5&KSH*LSZ-MBf1Mj!!N!#4NC+5NT+5NC'4N!#3!)q2MSf-LiU*L)H 'KB5$JB"rIRemHhTjH(GfGA4cFh*aFA"`F("[Efp[Eh"`F(&aFR*cG(4eGRGiHAT lI(erJ)'#Ji@'KiL*LSZ-MBk2N!#4NC+5NT16Nj16Nj+5NC'3!)q2MSf,LSQ)Ki@ %JS&rIRelHRKhGR9cFR&`EfjZE@aXDfYVDfYVDfaXE@eZEh"aFR0dGAGiHAYmIAq !JS1&KSL*LSb0MSq3!*'5NT18P*58PC@9P*58Nj+5NC!!Mik0M)Z+L)H'K)1#J(p pI(YjH(GfGA0bFA"[EfjYE@aXDfYVDfYVDfYXE'eYEQp[F(&bG(9fGhPkI(erJ)+ $KBD)LBU-MBq3!*'5Nj59PCD@PjHAPjHAPTD9PC56NT'2MSf,LSL'KB1"J(jmHRP hGR4cFA"[EQeXDfTTD'KSCfGRCfKSD@PUDfYYEQp`FA0dGRGjHhaqJ)'$K)D)LBZ -MBq3!*'5Nj59PTDAPjHAQ*HAPjD@PC@8Nj+4Mik0LiU*Ki@%JS&rIAakHAGfGA0 bFA"ZE@eXDfTUD@PSD'KSD'KSD@PUDQYXE@j[F(*cG(ChHAYmIS#"Ji@(L)U-MBq 3!*+6P*DAQ*LCQTUDQjZEQTUDQCLAPT@8Nj'2MSb+L)H&Ji&rIAYjGhCdFR&[EQa VDQPSCfCQC@9PC'4PC@9QCQGSD@TVE@j[FA0dGRKjHherJ)+%KSH*Lib1N!#4NT5 9PTHBQCQDQjZEQjZEQTUCQ*LAPT56NT!!Mif,LSL'K)1"IhelHAKfG(0aF'pYE'Y UD@KRCQCPC@9PC@9PC@CRCfKTDQYXEQpaFR4fGhPlIAq"Ji@'L)U-MT!!NC19PTH CQTZFR*fGRCkGRCfFR*ZDQCL@PC15N!#1M)U)KS5#J(jlHAKfG(*`EfeXDQPSCfC PC@4NC'0MBf4NC@9QCfKTDQYXEQpaFR4fGhPlIAq!JS5'L)Q,MBk3!*+6P*DAQ*Q CQTZEQjZEQjZEQTUCQ*H@P*15N!#1MBZ*Ki@$JAppHhTiGR4cF@pZE'YUD@KRCQ9 NC'4MBf0MBf4NC@CQCfPUDfaZF(&cGACiHRaqJ)+%KSL+M)k3!*+6PCHBQCUER*f GRTkHRTfGR*bEQTQBPT@6NC!!MSb+L)D%JAppHhPhGA4bF'pYE'YTD'GRCQ9PC'4 NC'4NC@9QCQGSD@TVE@j[FA0dGRGjHheqJ)+%KBH*Lif1N!#4Nj5@PjLCQTZER*b FR*bFR*ZEQTQBPjD8Nj'3!)k-LSQ(KB1"IhelHAGeFh*`EfeXDfPSCfGQC@9NC'4 NC'4PC@CQCfKTDQaYEh"bFh9hHAYpIS##K)D)LSb1N!#4Nj5@PjQDQjZFRCfGRCf GR*bEQTQBPjD8Nj'2MBZ+L)D%JS"qI(TiGR4bF@pZE@YUD@KRCfCQC@9PC@9PCQC RCfKTDQYXE@p`FR0eGRKjHherJ)+%KBH*LSb1Mj'5Nj@@PjLCQCUDQTZEQjUDQCQ BPjD9P*+4N!#1M)Z*Ki@$JAppHhPiGR4cF@pZE@YUD@KSCfCQC@9PC@9QCQCRD'P TDQaYER"aFR4fGhPlI(k!JS1&KiQ+M)k2NC+8PCDAQ*QDQTZEQjZEQTUCQCLAPT5 6NT!!MSf,LBH&K)+!IRakH(GeFh*aEfjYE'YUD@PSD'GRCfGRCfGSD'PUDfaYEQp `FA0dGAGiHRYpIS##Ji@'L)U,MBk3!*'5P*@@PTHBQ*QCQCQCQCLBPjD9P*15NBq 1M)Z*Ki@%JS"qI(YjGhCdFh&`EfeXDfTUD@KSCfGRCfGRCfKSD@TVE'eZEh"bFh9 fH(PlIAk!JS1&KiL+M)f1N!#4NT59PTDAQ*LBQCQCQ*LAPjD9P*15NC!!MSf-LSL (KB1#J(jpHhTiGh9dFh&`EfjYE@aVDfTUDQTUDQTUDQYVE'eZEh"aFR0dGAGiHAY mIRq!JS1&KSL*Lib1Mj!!NC+6P*@@PjHAQ*LBQ*HAPTD9P*15NC!!Mif-LSL(KB1 "J(jmHhPhGR4cFR"[EQeXE'YUDQPTD@PTD@PUDQYVE'eZEh"aFR4eGRKjHhaqIi' $K)D(LBU,MBk2NC+6P*59PTDAPjHAPjD@PT@8P*15NBq1MBZ+L)H&K)+!IhelHRP hGR4cFR&`EfjYE@aXDfYVDQTUDfYVDfaXE@j[F(&bFh4eGRGjHRYpIRq"JS5&KSL *LSb0MSq3!*'5Nj58PC@@PTD@PT@9P*56NT'3!)q1MBZ+LBH'K)+"IhemHRKhGR4 cFR"[EQeYE'YVDQTUDQPUDQTUDfaXE@j[F(&bFh9fGhPkHheqJ)'$K)D(L)U,M)k 2N!#4NT16P*@9PCD@PTD9PC58Nj+5NC!!Mif-LiQ)Ki@$JS"rIAakHAKfGA4cFR& `EfpZE@eYE'aXE'aXE'eYEQj[F("aFR0dGACiHATlI(jrJ)+$K)D(L)U,M)f1Mj! !NC+5Nj18P*@9PC@8P*56Nj+4N!#2MSf-LiQ)KS@$JS&rIRalHAKhGA4cFR&`Efj ZE@eXE'aXE'aXE'eYEQj[F("aFR0eGRGiHAYmIAk!JB+%KBD)LBU,M)f1Mj!!NC+ 6Nj18P*58P*58Nj15NC'3!)q1MBb+LBL'KB5#JApqIAYkH(GfGA4cFR&`EfpZEQe YE@eYE@eYE@jZEfp`FA&bFh4eGRGjHRYmIAq!JB1%KBD)LBU,M)f1Mj!!NC'5NT1 6Nj58Nj16Nj+5NC!!Mik0M)Z+LBL'KB1#JApqI(YkH(GfGA4cFR&`EfpZEQeYE@e XE@eYE@jZEfp`FA*cG(9fGhKjHRapIRq"JS1%KSH)LBU,M)f1Miq3!*'4NT+5NT1 6NT+5NT'4N!#2Mik0M)Z+LBH'KB1#JApqIAYkHAKfGA4cFR&aF'p[EQjYE@eYE@e YE@jZEfp`FA&bFh4eGRGiHRYmIAk!JB+$KBD(L)Q+M)f1Miq3!*'4NT+6Nj16Nj1 6Nj+5NC!!N!#2MSf-LSQ)KS@%JS'!IRelHRPhGR9dFh*aF("[EfjZE@eYE@eYE@j ZEfp`F(&bFh4eGRGiHATlIAjrJ)'#K)@'KiL*LSZ-MBk2Mj!!NC'4NT+5NT+5NT+ 4NC!!N!#2MSf-LiU*L)H'KB1#JApqIAalHAKhGR9dFh0bFA&`F'p[EfpZEQp[Efp `F(&aFR0cG(9fGhKjHRYmIAq!JB+$K)D(L)Q+Lib0MSq2N!#4NC+5NT+5NT+5NT' 4N!#2Mik0M)Z+LBL'KB5#JB"qIAalHAKhGR9dFh*aFA"`EfpZEQjZEQjZEfp`F(& aFR0dG(9fGhKjHRYmIRq!JB+$K)@'KiL*LSZ-MBk1Miq3!*!!NC'4NC'4NC'3!*! !Miq1MBb-LiU*KiD&K)1"J(pqIAYkHAKhGR9dFh*bFA&`F'p[Efp[Efp[Eh"`FA& bFR0dG(9fGhKjHRYmIAjrJB+$K)@'KiL*LSZ-MBk1Mj!!N!#4NC'4NC'4NC!!N!# 3!)q1MSf-LiU*L)H'K)1#JB"qIAalHRPiGhCeG(0bFR&aF("`Efp[Efp`F("`FA& bFh0dGACfGhKjHRYmIAjrJ)'#K)@'KiL*LSU,M)f0MSq2N!#3!*!!N!#4NC'3!*! !N!#3!)q2MSf0M)Z+LBL(KS@%Ji'!IhjpHhTjH(GfGA4dFh*aFA"`F("[Efp[F(" `F(&aFR0cG(9fGhGiHATlIAjrJ)'#Ji5&KSH)LBU,M)f1MSq2N!#3!*!!NC'4NC' 3!*!!N!#2Mik0MBb,LSQ)KiD&Ji+"J(ppI(YkHAKhGR9dG(0bFR&aFA"`F("`F(" aFA&bFR0cG(9eGRGiHATlI(eqIi#"JS1%KBD'KiL*LSZ-M)f0MSk2Miq2Miq2Miq 2MSk1MBb-LiU*L)H'KB5$JS'!IhjpHhTjH(GhGR9dFh0bFR&aFA"`F("`F(&aFA* bFh0dGA9fGhKjHRYlIAjrJ)'#Ji5&KSH)LBQ+Lib0MBk1Miq2Mj!!N!#3!)q2Miq 1MSf-M)Z+LBL(KS@%Ji+"J(jpI(YkHAKhGR9eG(0cFR*aFA&aFA"`FA&aFA*bFR0 dG(9fGRGiHATlI(eqIi#"JS1%K)@'KiL*LSZ,M)b0MBk1MSq2Miq2Mik1MSf0M)b ,LSQ)KiD&K)1#JB"rIRemHhTjH(GfGA4dFh*bFR&aFA&`F(&aFA&aFR*cG(4eGRC hH(PkHhapIRq!JB+$K)@'KiH)LBU,Lib0MBk1MSq2Miq2Miq1MSk0MBb-LiU*L)L (KS@%JS'!IhjpI(YkHAKhGRCeG(4cFh*bFR&aFA&aFA*bFR0cG(4eGAChGhKjHRY mIAjqIi#"JS1%KBD(L)Q+LSZ-M)f1MSk2Miq2Miq2Miq1MSf0M)Z,LSQ)KiD&K)1 #JB"qIAalHRPiGhGfGA4dFh*bFR&aFA&aFA&aFR*bFh0dGA9fGhKiHATlI(eqIi# "JS1%K)@'KiL*LSU,M)b0MBk1MSk2Miq1MSk1MBf-M)Z+LSQ)KiD&K)1#JB"rIRe mHhTjH(GfGR9dG(0cFR*bFR*aFA&bFR*bFh0dG(9eGRGhH(PkHhamIAjrJ)'#Ji5 &KSH(L)Q+LSZ-M)f0MBk1MSk1MSk0MBf-M)Z,LSQ)L)H'KB5$JS'!IhjpI(YkHAK hGhCeGA4cFh0bFR*bFR*bFR*cFh0dG(9eGRGhH(PkHhamIAjrJ)'#Ji5%KBD(L)L *LSU,Lib-M)f0MBf0MBf0M)b-LiZ+LSQ)KiH'KB5$JS'!IhjqIAalHRPiH(GfGR9 eG(4dFh0cFh0cFh0dG(4eGACfGhGiHAPkHhamIAjrJ)'"JS1%KB@'KiL)LBU+LiZ -M)b-M)f0MBf-M)b-LiZ+LSQ)L)H'KB5$Ji+"J(pqIAalHRTjH(GhGRCeGA4dG(4 dFh4dG(4dG(9eGRChGhKjHATlHhapIRprJ)'#JS1%KB@'KiH)LBQ+LSU,LiZ,Lib -M)Z,LiZ+LSU*LBL(KiD&KB5$JS+"J(pqIAemHhTkHAKiGhGfGR9eGA9eG(4eGA9 eGA9fGRGhH(KjHATlHhapIAjrJ)#"JS1$K)@'KSH(L)L*LBU+LSZ,LiZ,LiZ,LSU +LBQ*L)L(KSD&K)5$JS'"J(pqIAemHhYkHAPiH(GhGRCfGA9eGA9eGA9eGRCfGhG iH(PjHRTlI(apIRjrJ)#"JS1$K)@&KSD(KiL)L)Q*LBQ*LSU+LBQ*LBQ*L)L(KiD 'KB@%K)1#JS'!J(pqIRemI(YkHRPjH(KhGhGfGRCfGRCfGRCfGRGhGhKiH(PjHRT lI(apIAjrIi#"JB+$Ji5%KB@'KSH(L)L)LBQ*LBQ*LBQ*LBQ*L)L)KiH'KS@&K)1 $JS'"J(prIRemI(YlHRTjHAKiGhGhGhCfGRCfGRGhGhGiH(KjHATkHhYmI(epIRp rJ)'"JS+$K)5&KBD'KiH(L)L)L)Q*LBQ*LBL)L)L)KiH(KSD&KB5%Ji1#JS'!J(p rIRjpI(alHhYkHRPjHAKiH(KiH(KiH(KiH(KjHAPkHRYlHhamIAeqIRq!J)'"JS+ $Ji5%KB@'KSD(KiH(L)L)L)L)L)L)KiH(KiD'KS@&K)5$Ji+#JB'!J(prIRepI(a lHhYkHRPjHAPiH(KiH(KiH(KiHAPjHATkHRYlI(apIAjqIhq!J)'#JS1$K)5&KB@ 'KSD(KiH(KiH)L)H(KiH(KiD'KS@&KB5%Ji1#JS'"J)"rIhjpIAamHhYlHRTkHAP jH(KiH(KiH(KiH(KjHAPjHRTkHhYmI(epIRjrIi#!JB'#JS1$K)5&KBD'KSH(KiH (KiH(KiH(KiH(KSD'KB@&K)5$Ji+#JB'!J(pqIRepI(alHhYkHRPjHAPiH(KiH(K iH(KiH(PjHAPkHRYlHhamIAeqIRprJ)#"JB+#Ji1%K)@&KSD'KiH(KiH)L)L)L)L (KiH(KiD'KS@&K)5$Ji+#JB'!J(pqIRepI(alHhYkHRPjHAPiH(KiH(KiH(KiH(K jHAPkHRTlHhamIAeqIRprJ)#"JB+$Ji5%KB@&KSD(KiH(L)L)L)L)L)L)L)L(KiH 'KSD&KB5%Ji1#JS'"J)"rIRjpIAamHhYlHRTjHAPiH(KiH(KiH(KiH(KjHAPkHRT lHhamIAeqIRprJ)#"JB+#Ji1%K)5&KBD'KSH(KiH(KiH)KiH(KiH(KiD'KSD&KB5 %K)1$JS+"JB#!IhpqIRepI(alHhYkHRTjHAPjH(KiH(KiH(KjHAPjHATkHhYlI(a pIAjqIhq!J)'"JS+$Ji5%KB@&KSD'KiH(KiH)L)L)L)H(KiH(KSD'KB@%K)5$Ji+ "JB#!IhpqIAemI(YlHhTkHAPjH(KiH(KiH(KiH(KiH(PjHATkHRYlI(apIAjqIhq !J)'"JS+$Ji5%KB@&KSD'KSH(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+"JB#!Ihp qIRepI(alHhYkHRTjHAPjH(KiH(KiH(KiHAPjHATkHRYlI(amIAeqIRprJ)#"JB+ #Ji1%K)@&KBD'KSD(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+"JB#!IhpqIRepI(a mHhYkHRTkHAPjHAPjHAPjHAPjHAPkHRTlHhYmI(epIAjqIhq!J)'"JS+$Ji5%KB@ &KSD'KiH(KiH(KiH(KiH(KiH'KSD&KB@%K)1$JS+"JB#!IhpqIRepI(amHhYkHRT kHAPjHAPjHAPjHAPjHAPkHRTlHhYmI(apIAjqIhq!J)'"JS+$Ji5%KB@&KSD'KiH (KiH(L)L(KiH(KiH'KSD'KB@%K)1$JS+"JB#!IhpqIRepI(alHhYkHRTjHAPjHAP iH(KiHAPjHAPkHRTkHhYlI(apIAjqIhq!J)'"JS+$Ji5%K)@&KSD'KSH(KiH(KiH (KiH(KSD'KS@&KB5%Ji1$JS+"JB"rIhjqIAepI(alHhTkHRPjHAPjH(KiH(KiH(K jHAPjHATkHRYlI(amIAeqIRprJ)#"JB+#Ji1%K)@&KBD'KSH(KiH(KiH(KiH(KiD 'KSD&KB@%K)1$JS+"JB#!IhpqIAepI(alHhTkHRPjHAPjHAKiH(KiH(PjHAPjHRT kHhYmI(apIAjqIhq!J)'"JS+$Ji1%K)@&KBD'KSD(KiH(KiH(KiH(KSD'KS@&KB5 %K)1$JS+"JB#!IhpqIRepIAamHhYlHRTkHAPjHAPjHAPjHAPjHATkHRTlHhYmI(a pIAjqIhq!J)'"JS+$Ji5%K)@&KBD'KSH(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+ "JB#!IhpqIRepIAamHhYlHRTkHRTjHAPjHAPjHAPjHRTkHRYlHhYmI(epIAjqIhq !J)'"JS+$Ji1%K)@&KBD'KSD'KiH(KiH(KiH'KSD'KB@&KB5%Ji1#JS'"JB#!Ihp qIRepIAamHhYlHhTkHRTkHAPjHAPjHAPkHRTkHRYlHhamI(epIAjqIhq!J)'"JB+ #Ji1%K)5&KB@'KSD'KSD(KiH'KSD'KSD'KB@&K)5%Ji1#JS'"J)"rIhjqIAepI(a lHhYkHRTkHAPjHAPjHAPjHAPjHATkHRTlHhYmI(apIAjqIhprJ)#"JB+#Ji1$K)5 %KB@&KSD'KSD'KSD'KSD'KSD'KB@&K)5%Ji1$JS+"JB#!IhpqIRepIAamHhYlHRT kHRPjHAPjHAPjHAPjHAPjHRTkHhYlI(amIAeqIRprJ)#"JB+#JS1$K)5%KB@&KSD 'KSD'KSH(KiD'KSD'KSD&KB@%K)5$Ji+#JB'!J)"rIhjqIAemI(alHhYkHRTkHRT jHAPjHAPjHRTkHRTlHhYlI(apIAeqIRprJ)#!JB'#JS1$Ji5%KB@&KBD'KSD'KSD 'KSD'KSD'KS@&KB@%K)5$Ji+#JB'"J)"rIhjqIRepI(amHhYlHhTkHRTkHRTkHRT kHRTkHRYlHhYmI(apIAeqIRprJ)#!JB'#JS1$Ji5%K)@&KB@'KSD'KSD'KSD'KSD 'KB@&KB5%K)1$Ji+#JB'"J)"rIhjqIRepIAamI(YlHhTkHRTkHRTkHRTkHRTkHRT lHhYlI(amIAepIRjrIi#!J)'"JS+#Ji1%K)5%KB@&KB@'KSD'KSD'KB@&KB@&K)5 %Ji1$JS+"JB'!J(prIhjqIAepI(amHhYlHhTkHRTkHRTkHRTkHRTkHRTlHhYmI(a pIAeqIRjrIi#!JB'"JS+#Ji1%K)5%KB@&KB@&KBD'KS@&KB@&KB@%K)5%Ji1$JS+ "JB'!J(prIhjqIRepIAamI(YlHhYlHRTkHRTkHRTkHRTkHhYlHhYmI(apIAeqIRj rIi#!J)'"JB+#Ji1$K)5%K)@&KB@&KB@&KB@&KB@&KB@%K)5%Ji1$JS+#JB'!J)" rIhpqIRjpIAemI(amHhYlHhYlHRTkHRTkHhYlHhYlI(amI(epIAjqIRprIi#!JB' "JS+$Ji1%K)5%KB@&KB@&KB@'KSD&KB@&KB@&K)5%K)1$Ji+#JS'"J)#!IhpqIRj pIAemI(amHhYlHhYkHRTkHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)'"JB+#JS1 $Ji5%K)5&KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjpIAepI(a mHhYlHhYlHRTkHRTkHRYlHhYlHhYmI(apIAepIRjqIhq!J)#"JB'#JS+$Ji1$K)5 %K)5&KB@&KB@&KB@&KB5%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhY lHRTkHRTkHRTkHRTlHhYlHhamI(epIAjqIRprIi#!JB'"JS+$Ji1$K)5%K)@&KB@ &KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAepI(amHhYlHhYlHRTkHRT kHRTkHhYlHhYmI(amI(epIAjqIhprJ)#!JB'#JS+$Ji1$K)5%K)@&KB@&KB@&KB@ &KB@&KB@%K)5%Ji1$JS+#JB'!J)"rIhpqIRepIAemI(amHhYlHhYlHhTkHRTlHhY lHhYlI(amI(epIAjqIRprIi#!JB'"JS+#Ji1$K)5%K)@&KB@&KB@&KB@&KB@&KB@ %K)5%Ji1$JS+#JB'"J)#!IhprIRjpIAepI(amI(YlHhYlHhYlHhYlHhYlHhYmI(a mI(epIAjqIRjrIhq!J)#"JB+#JS+$Ji1%K)5%K)5&KB@&KB@&KB@&KB@%K)5%Ji1 $Ji+#JS'"J)#!IhprIRjqIAepI(amHhYlHhYlHRTkHRTkHRTkHhYlHhYmI(amIAe pIRjqIhq!J)#"JB'#JS+$Ji1%K)5%KB@&KB@&KB@&KB@&KB@%K)5%Ji1$Ji+#JS' "J)#!IhprIRjpIAemI(amHhYlHhTkHRTkHRTkHRTkHRYlHhYlI(amIAepIRjqIhp rJ)#!JB'"JS+#Ji1$Ji5%K)5&KB@&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(p rIhjqIRepIAamI(alHhYlHhYlHRTkHRTkHhYlHhYlI(amI(epIAjqIRprIi#!J)' "JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&KB@&KB5%K)5%Ji1$JS+#JB'"J)#!IhpqIRj pIAepI(amI(YlHhYlHhYlHhYlHhYlHhYmI(amIAepIAjqIRprIi#!J)'"JB+#JS1 $Ji5%K)5%KB@&KB@&KB@&KB@&KB5%K)5%Ji1$JS+#JB'"J)#!IhprIRjqIAepI(a mI(alHhYlHhYlHhYlHhYlHhYmI(amI(epIAjqIRjrIi#!J)'"JB+#JS+$Ji1%K)5 %K)@&KB@&KB@&KB@%K)5%K)5$Ji1$JS+#JB'"J)#!IhprIRjqIAepIAamI(alHhY lHhYlHhYlHhYlHhYlI(amI(apIAepIRjqIhprJ)#!JB'"JS+#JS1$Ji1%K)5%K)5 %K)@&K)5%K)5%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYkHRT kHhYlHhYlHhYmI(amIAepIRjqIhprJ)#!JB'"JS+#JS1$Ji1%K)5%K)@&KB@&KB@ &KB5%K)5%K)1$Ji1#JS+"JB'!J)"rIhjqIRepIAemI(amHhYlHhYlHhYlHhYlHhY lHhYmI(amIAepIAjqIRprIi#!J)'"JB+#JS1$Ji1%K)5%K)@&KB@&KB@&KB@&K)5 %K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepIAamI(amHhYlHhYlHhYlHhYlHhamI(a mIAepIAjqIRprIi#!J)'"JB+#JS1$Ji1%K)5%K)5&KB@&KB@&KB@&K)5%K)5$Ji1 $JS+#JB'"J)#!IhprIRjqIAepIAamI(alHhYlHhYlHhYlHhYlHhamI(amI(epIAe qIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)5%KB@&KB@&KB@&KB5%K)5%K)1$Ji+#JS' "JB#!J(prIRjqIAepI(amI(YlHhYlHhYkHRTkHhYlHhYlHhYmI(amI(epIAjqIRp rIhq!J)#"JB'#JS+$Ji1$K)5%K)5%KB@&KB@&KB@&K)5%K)5%Ji1$JS+#JB'"J)# !IhpqIRjpIAemI(amHhYlHhYlHRTkHRTkHRTlHhYlHhYmI(amIAepIRjqIhprJ)# !JB'"JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhj qIRepIAamI(alHhYlHhYlHhYlHhYlHhYlHhYmI(amIAepIAjqIRprIi#!J)'"JB+ #JS1$Ji5%K)5%KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAe pI(amHhYlHhYlHhTkHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1 %K)5%KB@&KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JB'"J)"rIhpqIRepIAamI(a lHhYlHhTkHRTkHRTkHRTlHhYlHhamI(epIAeqIRjrIhq!J)'"JB+#JS1$Ji1%K)5 %K)@&KB@&KB@&KB@&KB@%K)5%K)1$Ji+#JS'"J)#!IhpqIRjpIAemI(alHhYlHhY kHRTkHRTkHRTkHhYlHhYmI(amIAepIAjqIRprIi#!JB'"JS+#JS1$Ji5%K)5%KB@ &KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhjqIRepIAamI(YlHhYlHRTkHRT kHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)@&KB@&KB@ &KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhjqIRepIAamI(alHhYlHhYlHhYlHhY lHhYlHhYmI(amIAepIAjqIRprJ)#!JB'"JS+#Ji1$Ji5%K)5&KB@&KB@&KB@&KB@ &KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYlHhYlHhYlHhY lI(amI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)5&KB@&KB@&KB@&KB@&KB5 %K)5$Ji1$JS+#JB'!J)"rIhpqIRjpIAemI(amHhYlHhYlHhYlHhYlHhYlHhYlI(a mI(epIAeqIRjrIhq!J)#"JB'#JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&K)5%K)5%Ji1 $Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYlHRTkHRYlHhYlHhYmI(amIAe pIAjqIRprIi#!J)'"JB+#JS+$Ji1$K)5%K)5%KB@&KB@&KB5%K)5%K)1$Ji1#JS+ "JB'!J)"rIhpqIRjpIAemI(amHhYlHhYlHhYlHhYlHhYlHhYlI(amI(apIAeqIRj rIhprJ)#!JB'"JS+#Ji1$Ji5%K)5%K)@&KB@&KB@&KB5%K)5%K)1$Ji1#JS+"JB' !J)"rIhpqIRjpIAepI(amI(alHhYlHhYlHhYlHhYlI(amI(apIAepIRjqIRprIi# !J)'"JB'#JS+$Ji1$Ji5%K)5%K)@&KB@&KB@%K)5%K)5%Ji1$Ji+#JS'"JB#!J(p rIhjqIRjpIAepI(amI(amI(YlHhYlHhYmI(amI(amI(epIAeqIRjqIhprJ)#!J)' "JB+#JS+$Ji1$Ji5%K)5%K)5%K)5%K)5%K)5%K)5$Ji1$JS+#JB'"J)#!IhprIRj qIAepIAamI(amI(YlHhYlHhYlHhYlHhamI(amI(epIAeqIRjqIhprJ)#!J)'"JB' #JS+#Ji1$Ji1%K)5%K)5%K)5%K)5%K)5$Ji1$Ji+#JS'"JB'!J)"rIhpqIRjqIAe pIAamI(amI(YlHhYlHhYlHhYlI(amI(amIAepIAeqIRjqIhprJ)#!J)'"JB'#JS+ #Ji1$Ji1%K)5%K)5%K)5%K)5%K)1$Ji1$JS+#JS'"JB'!J)"rIhpqIRjqIAepIAa mI(amI(amI(amI(amI(amI(amI(epIAepIRjqIRprIhq!J)#"JB'"JS+#JS+$Ji1 $Ji1$K)5%K)5%K)5%Ji1$Ji1$Ji+#JS+#JB'"JB#!J(prIhpqIRjqIRepIAepIAe pI(amI(amI(amI(epIAepIAepIRjqIRjrIhprJ)#!J)'"JB'#JS+#JS1$Ji1$Ji1 %K)5%K)5%K)5%Ji1$Ji1$Ji+#JS+"JB'!J)#!IhprIhjqIRjpIAepIAemI(amI(a mI(amI(amI(epIAepIAjqIRjqIhprIi#!J)#"JB'"JB+#JS+#Ji1$Ji1$Ji1$Ji1 $Ji1$Ji1$Ji1#JS+#JS'"JB'"J)#!J(prIhpqIRjqIRepIAepIAepIAepIAamIAe pIAepIAepIAepIRjqIRjqIhprIi#!J)#!JB'"JB'#JS+#JS+#Ji1$Ji1$Ji1$Ji1 $Ji1#JS+#JS+"JB'"JB#!J)"rIhprIRjqIRjpIAepIAepIAamI(amI(amI(apIAe pIAepIAjqIRjqIRprIhprJ)#!J)#"JB'"JB+#JS+#JS+$Ji1$Ji1$Ji1$Ji1$Ji+ #JS+#JS+"JB'"JB#!J)"rIhprIhjqIRjqIRepIAepIAepIAepIAepIAepIAepIAe pIRjqIRjqIhprIhq!J)#!J)'"JB'"JS+#JS+#JS1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+ #JS+"JB'"JB#!J)#!IhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAeqIRjqIRj qIhprIhprJ)#!J)#!JB'"JB'"JS+#JS+#JS+$Ji1$Ji1$Ji1$Ji1$JS+#JS+#JS+ "JB'"JB#!J)#!IhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAepIAjqIRjqIRj rIhprIhq!J)#!JB'"JB'"JS+#JS+#JS+$Ji1$Ji1$Ji1$JS+#JS+#JS+"JB'"JB# !J)#!IhprIhpqIRjqIRjpIAepIAepIAepIAepIAepIAepIAeqIRjqIRjqIRprIhp rIi#!J)#!JB'"JB'"JB+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"J)#!J)" rIhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAepIAepIRjqIRjqIRprIhprIi# !J)#!JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"J)#!J)#!Ihp rIhprIRjqIRjqIRjqIRjqIAepIAepIAepIAjqIRjqIRjqIRjrIhprIhprJ)#!J)# !JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"JB#!J)#!J)"rIhp rIhprIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhq!J)#!J)#!JB' "JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"JB'"J)#!J)#!J(prIhprIhp rIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprJ)#!J)#!J)'"JB' "JB'"JS+#JS+#JS+#JS+#JS+#JB'"JB'"JB'"J)#!J)#!J)"rIhprIhprIhjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRprIhprIhq!J)#!J)#!J)'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)"rIhprIhprIhprIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRprIhprIhprIi#!J)#!J)#!JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)#!IhprIhprIhprIhprIRjqIRj qIRjqIRjqIRjqIRprIhprIhprIhprIi#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhpqIRj qIRjqIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIRjqIRjqIRjqIRj qIRjrIhprIhprIhprIhprJ)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB#!J)#!J)#!J)#!J(prIhprIhprIhprIhjqIRjqIRjqIRjqIRjqIRjqIRj qIRprIhprIhprIhprIi#!J)#!J)#!J)#!JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhjqIRjqIRjqIRjqIRprIhp rIhprIhprIhprIi#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIi#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprJ)#!J)#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)# !J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB#"J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!IhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!!!"&3!!"!!%!"3!!!+!!!B"4!!!!!!!8!!!!!!! !44C@lSZM!!"&&!!!448!2)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhprIhprIhprIRTjHRTlHRCfH(*ZEfYSFR9eKBeeAeP28'CeHiU4J(CdCQ&L9PT fJAZ#J@TME@P[LBaiEfePCh"ZGib,K)Q!E@KI6&Z"M)kGPS"kEPYJEh"eK)@%LRY TG(piJ*!!KRaqEPeYJ)#*P)q1LR*KD'GPIC+3!*LMMAChDeeVIAk*NB*lJAYdIAj mNC9lG(PRAhZ,LjZBI(L!F@*NDhf9QC5HPA4QC@"aLiChK)alGhplJ)U(KSq+Hh4 UB(@0LBqHMA*[Df0cKS'(QTUAP(eSE@jRHSf'KBThES1*IBH@M)D'GR"jFQYrMj+ FPRPZG'GLHif4S+',KBTiCQGUGiD%J)k4Hh4rJSZFNRYlHfCLFhf'NBU,QT!!G'P MA(#1P*qcS(TcG@YbHQYVK)U&M)KrL)KqMU+6IhTQ@A5)JBqNPi5!HhGhDQ@"Qk# YVj*qH@*BHSjpHi4mISk,KT'0JSU1KBKqB'&hHB@VVBPiF@*RHReqLj'EUjprG'e FB'pdJTH5GA1*PCU@K(CiI(q'HfG[Hi1JVSPTG(GPFSZ+Lj+2NCZBL(GK@h"kH*+ LK('!KSLIRhPYIRjjHhPlI(4mQk52JQj*8i'-MUZVJ(5(JAGkDePNHBL9PiCiD9q 'ZUk'FQ*CES4pJ*++J)k8LheM69ChNUUiRB"lF'GqMACPFAL"QCQ#HAClNk#AN!" m8NGUJSQBNR0aKRj`GQjDBRbBX+k6H@KJFik$FhjkBh1FRB@#JRk0PSYmCP4CDhZ AVTKeF@TIF(jXCS'4MjkQNRjU9Q&qMC',EQ1'PiUBT)CcKBf"IQp,5(@KXk@+I(" @9(H)ISQ6Ii#BNhYaD&eUJSZ-IfKSHAq1TTerHhTPCRPZ@fZ(PD'MLh4J8Q1!MCb TPRk*NAYfJ("RHS*kHAGUCfplPkL5IAGJ6f9lFAD4NBfHQAeXBeYNJTZLPi5$L(G YK)afG)9pGB&lF(k1N!#9Q)q!CNY6DQaiQTq-MC&mEA*VC(Z@TDUGLiCqGiD9MBf 8JR5%Lhf%R*U4PBTdC9G19@*dMj0lGRKG6@0XCRbEQC@GNAjfEQplHhU"GepRI(Q )VDb9PC&eDQaHARU-Q+@NQ)9N8fH!LD5rUSb2KQeXG'KRJjL5GeP6@epeRVDZT)j @-d&$3@U9RD+cXU#+E&TKF)fVUTL9L'PdQCL+MB4bFR*F699QJCfZ[Dpa2d"*6R@ JSCZMNRKlJQjIG*UiZU'0H&G@GibFX+"`BA"N9fYlHB5AQije@%G%8)'aTSf+G90 AE'9QJBf-QD@HMAk!QV#f[DjmA&e9@)+DIh+'LA9QA&KJEB@NXDZJI8Y*DQjLGSK rKTqNT+kRQ*kVVCYf@9YF@RUGPBQ+GQ*fMRpbJ)H!K)PrDPGBCfa`K)PZDAY`DSq SQ*!!Rjb3!*53!)"`C@q"I'pZBdpHJSf9V+D(L*Q0FfKPB&jLFiD)KiKmHjZaSCZ RPRU!M(YUCPT19@KeEQ&ZLBf5XVfCKT')I)H$Be0EB@PrNTL3!)'*T,#[VTPmJj0 qDh&P5%CGD'GUE("eHj!!SjkBP(PGC(4N9@0SD)5PX,'iZ+qVVE1aQSZ,Ih*lH9j @BPP4Di*pGAf+QDHTS)a[APP)3PCF5daPFA@(KR"YIif6Q*b@KA0cJB0qIR4UHC' 2M+HeV,2#ZTjqC&&*6f&dHAf,KhZ0S**qK)Q#ND'9I@aNB@*UFfjA6f9bFiZNUVM !U)k@Q(09@'PfJBZ4M)5(P*+3!+#HI@jhE&06A9*1@&TEBfTN@@&qQk+MVkD"E'j VEB'+J)qh`lDYUDQSVXACe,qXM'KYHf04BfYC@'YS99*EFBUGTj&H1$!Y+6jB@9a `I(f&M(YMFTQcZVDUMA"XIBfDTTjqGj+HNj!!R+'P[Y6)TAeB1cG9Fh9TE(CZEiD 0IRb*P+'aThT65%a39fq$G9eIGBHEXl'RZFQpU*f'B9&PKCZLST9c@fU!KBqNRSZ 4NhPH6$NZ2PPNBPeC8deEJ*LCR*k2JBb0FQ9ZF(')V,QcV+kf[ml@`UDJSjZHXl# 0HRKSA'CX@%KAF)L@NS"F3e4XDPeA35Ne8f4dM*@,LU#eVjCrIBDAXlULK@j00e1 $P*bZYl[$aE56HA"`F("jFeK1A'PlT,LFJSH0M)k#E'C[HS1&GQ"(-6PBEhk2P*5 Xcp'qY+5&DfTeHA9cG(D%TVkXNj19LS5)IQjZEQPaJB*N1bJ[394VJSk8QBprHA9 K6&4[L*bKPSZ&M*@GV,ZmVU+PT*qNTk+LUkQ0EP8r0dCQLkc$al+5IA9P5M`k3&K bH'PJC'4MES@CRjD'ISZNUSppLBjiC&Y@9f&[LERLk0#YQT&h9e"HCfTeIiD9N@j 9C)#3!*D9Li5#JB&mHi4lA%C5B9aGF)@K`pE4[kCr9%*0CRU0TV+[YEZUMiH)JSQ GS*D8PiapISf1E6iS,$%j499iTm#hVUU,@cFZ2@'(QCQ9P*1)ISkYY+fe`m5kUSk "P+HKMAjV45N`8h+&Q+5CMBTf8$Xk0MpRKS*cDQCPFBZLUkqhYk'@S*U%IB@(KB4 b8dC-ARZVi2(6VCL*F'"KAf"cJ(eqKRC44f1(SUbRNh9MDACqLBprEhb"C%3p4&9 qX0,JelD*D@CfJB1*PTQARTZ$EfppP,I3`*PkEQpkLT'#E@&9363j1$*,H*HNTjC U3$4$B)'DSjU5PjD%FR5!MUh5hp6!UC10RDbNMATV@8K-Ah#%R+baXk4i5$!Y190 bJhpcD@"@9f9cHikSYVQjVjH1Qk5KRjb'Be*GFBQQa-frY+Q0E9e869f"P*!!LAj P58CFFAZ"KB&pK)GeD'eZB9TE8d9#4e9qZ0hFbELKJ@0FC@4UKCq[[lqIH("mJSL 9SD#ANC'@QjH$CPKB5c-U,M0(GU1j[E#0BNK(694QIik5QU'6I(ChH)QU[EUeX+# 8Q++GLhe`A8e0@'&fRll$a,fED8Y!0ceCFhYjHR9J6&"LFAk9TUU`XCU%LTUBMif "C8j-@@Q$U-6-bmQaKfpR8dPII)+"Jh&869eNA@0jJRPjLBPiGAelHB1!D&C86e" [RVUq[EURLhYdDQf'S+Ha`V+&D'T[Ehq5PBk-MB9pJB"XB'KS6MSm1MPDL*bHSja k9da+4%9HI)Q9UDU5IhKZEj+eYUqj[+@4PTb6LSGiA&"A8NCBISq@V,D@DP!l+64 FGA9mM)ThFRelFi+IVVI'[TQ'NjqKUlDVMRajFh'#Q*bJZXDRIQ4&)LG5EhH$LRG B68`q-N&CB'H!LR*EAf4LG)k"@dBr0$aNMk'[bpE&XkZ@GAQK[FVHjX5@K)*mJ*@ KQjUMQ(edHR&JD(ac8M`S#!)S8QZ(TU@(F@TD5P4bKC'UZ*jlF@eNFjkkYl#YRSU (N!#2MTLHLfeD4LBF0eYeNUDCG9a21c*'CR9lLj+$EQ9I@@kBXE1eXTQ#KjkZZmV )VjD+H&a5Ci'@Y-l#QA9E3N"GGAPiI(CM9P923NKJE@ebFeP!5&TQHjDCIQ4@4M) a4PpfP+k`Sj@!C@@1YF,*d-1TQ)q&KC@PTD+XX*YrHAjqKjH5FeFp'`SL5fKiLjL 6JQpG58GGGi5@UCprDfTXGSkLTU5STjH(L)b(L*56Hf*,+K8P49efN!#9K(0ZD@" GD(4lK*!!Mi0pHh4lQl5aU+HJNj5LVV5iYkL4Ih&E599hNUM#bE+5H@"5A'PRAf" PANe%4NG+A(4lH(*K5NPHFAf)MApQ8N-d-%&II*l#d,qRQBYpKk#VVE'bV+Q[XUD FSkkRPj1-GfpjJ)'+Lh*53$%K)cYCEhb,NSU#Ih4NDS'(J)D0JR4dGRH"M)k*KBZ 5Mj+KTCL6P)"I56BN+%0FDA4rHQPKC@GG@QK`GB@8MiH,MifCVlHVRjZFRkZj[,D cVjZ!G@Y@6f@#Nk+VRSZ!H'aPD@aPAQ&QBPYFA&CFE("SD@YJ@QCiJB&qG@GE98j '5Q*hJjHYVTb1L)+&NCLFTV+cUkLbYUqXXV5TSCU+JSZ3!)f2PBGS6d%p2N98C'e fIha`EQjJ@@b"KBH*JRPpKSfCTkbPRD#QRC!!NTQ6MBk%E9a32MG+BQKPCQPM8NT 06%Y8A&eTJ)4lLD1[Y,r%[V5SR*QKVV@ZUV1cR)D#HR1"PCkSYDk8JAYeE'GTE'T XGhGXDR*aEhq,HQGK9dP+A@abG(4YBPYG9NK4DR4iLTH1KBD&JBQ8P*!!PU'NRk' YXkqd[V@NQiPbG)L3!*!!PTU0H@KD6dP-9epVJBq'IS+#H(Z(K(eqHhCkKj@IUE' dUCH3!)q'K*!!Q*LDPAaM@P&!1dGBAf&PDfeUD@CF@@"B5%T68&4YM++f`EkeV+1 GR+HlamE*d-HaST@)LTQIRD'PRT@6PjZ8KRPYA9&*2cY,@f0cKiCeDQ4IB'CUE'a YE@056eC@@'apJ)L3!)Z'MC14NC52K(elIAk#NkH`Ym#mVDLQQ*1HSjZ8MAp`Cf0 NDA&qJAGdIAjjJBq3!*!!P)TiEQPKAh#,RkLUVDbKPj@4Mj@8Ki#"G@&FB@9QBea 86%G)6P4MFhCaF@T94NG+8'9pMTqZX+UQTUUVUUqiYDfUT*QFTD1JU+QGNSq2N!# 5PTbHPB9b@NY-68pKGRPcGA9XBea@99TKBepFA9pFB'aaEQeVAeeSF(*rNTbKSk# CMi@%MCZ[`F1q`m1`T+DMPSq2M)Z*I@pVFheqFfGJ8d9)99jXIi@(N!#1H@9F@&P MGBZFSD+PTD5ST*D4Q*@,Lib$HhCZE'eL6MSb1NP5A(+!I(CbBP*268TAGC!!S+U aYE5[Vl+aVl+bVVE"[,Dl[,1YTjU+J(b!LjDJTU1ENRYI9&K46&PTER*bDfGSCQ* NDA"[B9GFB9jIBPeGBea5A'a[F)#ATkfTSTf@NT5CSl5lX+UeYkbQTDDUVDLFNSK pFfpfIhY[DfGF@@&QEi16PC@@L'jA69*IEAf,Mj+CR*UNXl1ZY,DSPB4aC'*MC'9 N@d`l18K@B(+'LB0rFPT-5djDGT'FQC@8NT!!PUHeZm'rXUZXT*16SDHPSjf6M)Q 1QUUl`V@IN!"m@8!p3846C@aYEQKH@f0YF@p`FQTE8e06@&pE@@&P@%pBCh@(QkU [TT1$IB14Q*UQYlQaVkqSSk5MT+QPNRTVD'TVERGlFfTM9e"@A'9qR+LINS&ZB&T IEAk1QCQ@QTk9N!#DSk@TUCb*I(9`FRPmG@GD88Br3dj@CRk+K(PQ5$-f4&0PHiZ 5PCQFQCLJUDbbYkZAMiZ#JSqGTUQNQBk-NCUMVlfpUjQ,FeY489KTI)&jF'PJ@&G LF(GfGA"RCQ4E@'9`E@PSAP06@QL!RDk[TCH)H'ehLTDP[FV(`EDJNjQMSk'KQSC aD@TXEhZ&JAGY9d!k3NTCGT!!Q*1*HQYNC@YbJ*1AL(q"IACqMjfXZE5KPT+*IRk *NBKhCP-r06Fq8'epGfjVA88k3P0TJ*1FQT5,IRH#NTHEUE+YUULJQCfQUDLJMRC PCA5&PDZp[E+SPATTAe02A@aVB&G04%&*@'0UFA"PBQKQA@CmKS"iE&Y04dP@F)f IR*@APSKrKj5LYm5qYV+PN!#+PD'RUDUMNAphFh*lKS&dE@*+1Mj,@R+1SUQQQB0 UB'9YFi'4NSH#IhKiIi1)PCqEN!#)KiU3!*fZXUD4H9j069"6CAk0MSKmCdp"4&& PHB@#HRGdEA'%NjZQVkZHNSL#KT1HSCb8KhCYHBqKXmI3cmQjQi"bE'PaJ)L"EeY 04N9,8&GNFA"RD'YTD("hHhacB903@'4cLkHfYE'TQ)4iFhH+T+qZV+LGNBk8R+# MS*@*Ih4RBfa`D'*J98C!4%jJHC!!Rk5KNhaTCQY[HBU6NT!!M)"dGRf$MTqXUU# EQjZGT+5CMB&YA&PIBff"PCZ@L'e11$!b2&"RF@pZEfKMDR0mLTbNRCH8N!#2QDQ dXkUINB0qK)ZCVm$$a-'YMhGUBf*VGhYhF'CD8eTMC@PeHA"SCf4KD("aFhCaBPC CC(&rNk@TTTk2Hh0dGAL+RkDQTD#CP*+5P*UIQ)GrJS"jISb2L(pbB&436%jHH)b 4MiTrE&eC@&YTHAq$M)q)KSk9Qk+RSTD1M)f5S+fZU+5CJh&YDQ9UH)+)Li&T8de 38PKUI(aeGACbFRGiHiQAPBZ,Miq3!*URVl#TQiZ&KS@%N!#QXV5fXk@5Jh9[GiH 0LB5#HfeQDQeVD'KMAf"I@9YRFACjH@pE58*%6&jcJBQ6QT@3!*'2KiQ@SULVUU5 HR+'QU+LMPSU-Nj'-M)U&JAKS9dj*3dKEG)+$JAjiFh*aERH)N!#4Q*k@Ki5,NC@ @NSZ(L)U)MCQEMi4qF&j66%0'@@efHhppG'p`FR"ZFhCcG(TjGRZ#KSqFRjL8Nj! !LiZ4Q*H9NiTrHhYdF(f3!*fSXV1USCQ3!)k8QCD-KiL#GQjSB@"RE@jeHh&PC'T VCf&C6d8r2Mp'@@YfKjfST*qCM(ppJiU8RD'LT+QYUkUZXDbUVDUHPSk$HhKaBe9 04Mir5eaZJ*+DQjQ5JA0cGR*bIB@$JS+#JiU6QCfRX+kNS+#BMSQ$GfaL8dG)8Pe PF(arGfjQA&069eGIFAajGhk"JSL6Qk#LRjL8PjZCPTUFNiU)K(erLjLT[-M'Zkk HLAKbF@eSDfjTC'9PBfPbGhU!JReiHRjrIAPcD@&E8NP+9Q"VIC!!Q*@1JR9[Eh0 jKT@HS+1UVkbUUkbVUkDCN!#1LS&mIhjdD@4JA&eRFAU*P*++Ki&cD@aaG(KmI(P jH(9fJT+9NTHJSU#KRjQBQC+)JAKQ9P0DBfYeI(K[D&e24dT08&pcI(f!K)D,PCZ DQ*H5LSH+LB+#MT@9P*'*JS5,PDDh[EH[UCq1J(PiGhKmHRCbE'*KEAGeFh9cE'9 MCQehJ)"lHA0H5NG3@QChKik4M(jcG(b"K)fESCqJSTqGSkUYXV+PNBD"HA"`GRC `E'TMAf4UEAH+PjQDQSjqGACjI)"rHA0aEQPVGi1,NjU@MBL%IS#,NSf&J(9QA9Y E@f&[IB+%IQeIB@TZFAPqHA*ZE'pkKBQ,Mj11JAPeFA5%PCbHQSq%JSD,NTkVXl5 cX+DBMib+LSZ&GfeSAeKHDh&aF'jVCQ*IA@&YHAalGQG33d0*9'4dJ)Z5Mi9pIB+ <1AMS0lG(4qLT'ARjq8LB4rHhPlJSZ4NBChF'p[GiQDS+#GPSf'K)+%LBb)JAa iF@KTGB')Mj+0LB4pH(f)LiH#IA0Q@9*6@fKdHAYlGQPKBf4MBQ&F@&9489PRGAf $MC10JhpqJ)QASDZeYDQGPj@@Qk1XXE+cXDbUVDZNS*b2I@pK9P4EC@aaFQaL@PK B@fCeHR4ZCPC'2ce%@'jlJSL+KRjkHRepIS"rI(YjG(L(NT@BR*U4KhjjI)1)Lj+ EQialGA9bFhf(MC5DR+'TUk5FPik!FfeYE@aaH(q(Mib'K)&lGhGiGh9`D'*G@PT FBQeeGhf&JRKaDf4KBQ*NDQjXDfphI(jrJB*rIhppJ)Z5PCbMRT+(JS+(MC5FTV# hZVUlZ+ZJR*H1KRjeFhKpIAYlGfeK@P9158pCAPpG8N8q2$a'@@PbI)L2NBk*K)" rKBU+LSU%Ii50N!#5QCfDPT!!LSH,NC+3!*'5LhYXC'&MEAL#N!#ISCZCQC@0LBQ *KAplHRf#KSH*MSb"G@pSBQ&NCfYYD@"B8e059&jXGi'(KS&rI(9bGRPhFh&`FRG qK)L1PCL5LS4qIBL8Q*ZLSCL2LSD&KSL0NjfNSCZFSkHPT++BMSGrHRTpI(KkIRY [B9P88&4GC'PXCPK389"08&PMERGjGhKmJ)'"L)b)Ji1#J)@-N!#9RU@QT*qAN!# 0NCHCQCZDNSZ(IhGiI(YkIi+#JiL-MSf+KAjfF'PMC@jcGS#)Ki&qHRGiHhalJ)D $H'pVCepHBfGXFR4aFAGhFA"dGRCdG(0aFhGlJBZ3!)U"J)"qJBf@R+1VV+LJPSZ $JB+"J)1+MC+CQjH9NiTrHR9XC@CYGAYrJAafGA9cFRGhFR0dE@&B88Y)5e&BAf9 SD'ahIRajJ)5$KBH&KSf6PTZKSTfAP*@@Q*fHRD#PSTZAMAPTC'4NCQeeI)1+M)L $Ih9VDQeUCQP`G(f,Nj15N!#+Ji'"J(apK)@"IRGR9Nj,6&KVG(CkJ)"mHRTjH(K pJ)@,Li5$Lik+L)U)KB@+NCUKT+'GQ)jlD'&LBfk#NjbLSTD1Mif%I(b!JS+'M)k 1MSb+MT'&FfTTD'TeHhK`CPK+3$Ne0d*5BQeiK)D$K)L,NCLCPTQIS*kJTDDLS+1 KPSU$Ii12PT55N!#$E@"GA@"RF(Z$L)L#HRCdEfjjJS1#KBL0PjfGR*ZAM)"mIS' #KSZ,KRaS88C%3802B'aeI)"rHhGdFhGrKSQ1PCD6Q++PSTf8L(ehGRU$MC@BQ*H 2J(9bFR0kKSk9QjU4MBk0LBH)M)f,LSU0P*H5Mj'2JACfHAPjHhThF@9A5dC$2MT "6eTKD'jcHB'$KBk@Q*DAR++SVE+cVUHHP)f,L)@*P*UDQ*'$FfCHA'"SF(CpK)Q )KiZ,KS1%JhpqJ)1-PTZFR*bCMi@"IhYkJ)5%JRPQ8dP"1ce*9f*SDfaXDfTUERU +NC'8Pj@4NTDCRTkCNSf*K)#$M*@DR*b6KAP[CfPdJ)L6R*bANiq-LBH)M*!!Nj5 3!)f3!*'1MT16Li9rH(4cFR9kI(9R@&"+36T!69GIC@KXFR9eGhq(LBL*Mj5@QCZ HSkLMPj!!M)5!KT@NUkZNQj+(H@aQDQpcHB#%JAprJBD-M)H$JB#"KSf9QjqKRC1 (IRCdHS@0P*D0I'TH9P&49f&YGAKhG(*[D@CUEQaRCQT`Ghq*PCkGNSH!HR9bHSf JV,1dVkLGN!#(LBq6Nj@BQCH6NC+8PT@3!)Z*KAaiISH2PCD3!)GlEQ9NDR"cGAP jEQ0G@945@@0ZGhakHAYlH(ChHAPkI(jrJiU3!*LLTjq4KhjiHS13!*ZMTUDPSTb 3!)*mIS'$LC!!NT+5NT+8NiU!HhYlHhk&MC1AQTH1JR9TCQadHAk$JATeF@YNAf" QF(PlGh0cFh&bG(0[DfTSCfY`GAf'M)Q!Gh&VDR1"MTUNU+LSSjU9PCQGSD@RTk@ LRjfHS*k9MBGrHRTrKSq8NSPrFf4A899FB@G[GA9`D&pC9eKGC@jcFh0fHhq#Ji* rHhCbFhZ'M*'@Pj+*IR0ZF(9rM*QMTkDLR*5-LSf3!*5APjDCR*fFQjQ6Li@#JS+ &M*+@QC5+J(GYC'9YGAk%L)U*JhKYCQ4QCQCTDQPTER*eH(GcF'eTC@9UFRZ%MC! !LAedDfCTF(Q(QUHXVl'ZUD1LTUZ[XE#ZUkQPSD'LR*11LiL&KBD-P*D3!)GqG@T G999FC'pjIi&pEep@8e*48eTLCfPYGRarI(GeGhGbFRKrKSf9Qjb9KhKaEQpfJT+ KU+LQSjb@NBf0P*QCQ*UDPT'0LBH&K)1$JB'$L*'BPBb$GQGJBQPcIiQ0MBQ!F@& B9ePFB@KUDQKQCQY[EQYVE'YQBQ&REhQ&LiU#G@CE@PpTHSqHTDHRTD+HR+#SX,5 bVUfVTU+LSk#BMSD%K)5)NCZKSCL+H'"*2N06ChKrIRYbC9P66de18PaSEQjVDQe hIi5'Ki&iFh9pL*+AQCD0J(*PB@9ZHikITD+FPC!!MSf0P*kNTkLQSjkBPCD9MiG qGA&dHS@6QCD0JhGVB9YFChL(NT@4KhCM@&C@9ePGB'4SDh"hIApqI(TfEQGQDh@ $N!#9NiYkD9jEA@4aJBqDRTfCPC1@Qk'VXDqVUDQTUUUTTTq9LB"iFh0jKTDDNB0 `@dY(6&GQFRTqIRGVA9"+58e9B'GSCQ4QEhPqIAYjG(&bGi'1Q*fHQT!!IfTD9Pa QGB54QTkFPj58NT'9R++QTUDQTkQXV+DHNi4iGA4dH(k"J(YaD'*JB@4VFhk%JRa eE@PTDQKQC&pHBfGVFRU$L)H#IRKZDQjjLTUHQ)k!EPj88PGMF(b(Mj+4MBZ1NTD DRU#IRk#PVVDjYl5ZS)YiF("fIBD0MBGkDPjFA&aLEA9jHA9ZCPa99&GGBQ9NC'C RDh@!KBD%IhYlI(k'NTfLSCb5JQpLB'C`I)D0Nj@5M)Q)L)U-NTZJSD+NU+bXUD@ KPS9jG(0fHi'&L)4kEf9IAf&SG(q#IA9YCQ*HA'"SE@eYEh*fH(b%LiZ'IR4XDQa fL*LHR*@+IR*RB'&PDR0lJB1"IAb#LT'DRjqISD+QV,+eYE+USC5)Ji5)N!#DRjf 8JfpL@eTHC@jeH(0YCep96Ne4@&jIAQ"ND'piJ)@'J(KcEfpaHBHCTkZPQSTlF'T UFhb!JiH)Ki5$KBZ4PjfJS*kEQ*ZPV+fUST@&H(&bHB'(MBk+J(*L@PYJD(4pIRT `C9pHAPjKCQPTCQ4REA0pLC!!NijrF@YVF(f2RD5LQ)f$GfaPBQC`H(YlHhKdGRk )NjQBPTHCQjqQVV5fXUZIMi&mISQDTDHKPS9bC&eFB@CVF(&YC9Y46%T,6e9B8dj 16e9IDRD"L)L"HA9jJBbEUDqZTCH'HR&UEAL$Liq4NBf&Ii'(MT+6NT'2LSH0QU5 RTjq8LB"mIiL5QCbFQ)emDQ"E@Q"QDfp[D@"FA&eF@9KEA9YC@Q*[ISU4P)q#GR* dIBZDTkqZTCD%FfGLBfajJS@%J(emIS'%LBZ-M)b-MT1ETV#cVkDCMSH&LjLRX,' VRiaiCPaDAQ0RDQaTB9G48&"28&056NT*6&CPFhq&L)@!HRKmK*'IUUkYSj'!G@p ZFhf&M)q0LSL&Ji1'Lj!!N!#-LBH&L*!!R+HXUU1DNBU'Kif@QjbDP)KhD@*JC'T VE'aTB&K999GA9PPGAepHAfGeJSZ5PC'(IhTmKT+GTUQPQieqFQTRCfjhI(jpHA9 dGAGpJ(pqIRk!KBbAT,#fYDZGNBU)MjbTVl#URj+%Gh"[FRCjHACX@dT"2d**8&0 88e"08&KLDh4lJ)+!I(f$MTkXY,LeTj5&HhCfHAk'M)q0KRplHAKjI(ppH(4cHB5 1PCfLS*U6LS&mIB@3!*ZJRjH-JRTfHB#%K)1!HA"QA9C899CCA&jIA9jRFhk%KS* kG(0dIBZBSUUYUU#4JRKcFR9kIS&rGh"ZEQp`FhCkIRprJSD-NjZLTU5EMiL&L*! !QCqNTD#CNib'JS'&M*'4Li"bC&aA9eTF@PG98e09@&jQEA&eGR4aFRU+QkL`XUf JNSH!IS+&LBk3!)f&I(CfHi#'M)q-Ki"lHRf#LT1DQT5+IhGcG(f+PCUBMi9mGA& hJBf9Q*50K(T`DQGRD'GQC@4JAQ0YH(pqH(&YDfadJT+ITDDPRj1'IAPjI(pqHR0 UC@CXFhU!K)H)KS1!J)5,NTLFQ)f#HhZ#M*@HTUDHNiH!IS'(NCZHQBk"G@aPB'& MC'0J@9*-5NY4@f4UDfKPC@K`Ij+KV,#XTCb4Ki5&L)b-LSL%IAYqKBb6PT11KRY fGRPrKSb2MSGpFfp`GAq)N!#9PBk)K)1)NCUKT+#BMB&fEfaYEh"YCf&F9P4BB'P `F@jUCQ0NDRD*QkDVUCq4KRjpJSD)Ki@"I(GbF(0kJ)D+M)Z(JAq$LBq6NSb&IhP iIB@1PCfKSTk@N!#2NCHITDDKPSCkFh"ZE@YSC&j@6dY)5P"AAf*LAejICA'"NCk QU+@JQT10Lif6PjD6MSCpGhCjJ)L,M)Z)JRelIB+(LBU+Ki&mGhL!LT1DRCZ8M)D %KiZ1NC58NBZ%IAG`E'YTCf4JA9eKC@PZF'pYDQPUEh@!MTULTU1FPT!!LiU0MBQ %IhYfEfPRD@abHAaqIRakI)+*MBk,L)H&K)L3!*QJTUHQSjZ5MSf1NC59PT5-JRT dF'jUCQ0JA&G88P0BA@4VEfjUD'P[H)'*NTUGRCbDQ*H9PC@6MSL"HRCeGAKpIhe kGA&aFRGrKif2N!#1LSD$JiU6QTkIR*H5M)H'LBZ0MSq1LAphFh&[E@YSC@&F@ep QDQe`Fh4aE@aZFRL#MTQKT+'IRTkFQTL8N!#+JhaiFfjVDQeaFQpZEh*hI)''LBQ 'KBD)LSf3!*@ERU#KRjU@PCDCQjL4LS0mGh4cG(0`E'KPB9eD@PjND'YYEQaTCQC YGAZ#LT'@Q*H@Q*QDR*fGQT@-KB1"IhjpHRCdFR*cGRPqK)Q0M)H%JAemIi@+MBq 2NC15Mib)KB1"JS1#IRakGR0ZD'*HA&aJCQaaFh0dGRGhGA0bFh9jJ)L,MBf1NC5 9P*13!)f)K(pjGA"YEA"bFh9jIS1(LBb1MBZ*L)H'Ji'%LBf5PjQEQjD5Mib)K)+ #JRpkGR&VCQ&GA&jJAejLD'aZE@eZF(&aFR0dGhb#LBf1N!#5Nj56NBk0LiL'KiH (KB&qI(YlIB#%L)b3!*5@P*!!M)Q&JApqIi1(Lik2MBU&J(jqIRq#Ji*rH(&VCQ& GAQ0SEA&eH(TlIS+'Ki0mH(KiH(TpJSD+M)q4N!#0LSL*LSD!I(PcE@TTD@ebH)+ -NT56P*HAP*+3!)b'Ji1<!!NjDERjkCNSU%J(q"K)*lG'aQBf&IAf*PCfYZEh& bFR4iHAGbEQaXF(CrKiZ1MSZ*L)D$Ji@(L)Q)KB*mGh9hHAk#K)Q1N!#4PCLAPC! !LiH$IherK)U2NC'3!)U"I(YmJ)@'JhpkFfeSC'4QD@peGRChHRk#KSD&JRYeF'e XEA*kJSL,LSH$IhjqIS#!I(KeF@eUD@Y`HB#&LSk3!*!!MSq6PTD@Niq,L)@%L)k 6Q*Q@MiL!IAapJ)+"IAPcE'PSCfCSDfjbG(9iHhaqIhjmGfjSCQGTFAb&Liq1LiH #IATjHhk!J(ppH(9dGRU#L)U0NC58PjQCQ*LAPC'0LBD%Kib3!*!!MSQ"HA9cG(Z !Ji@%IhK[D'*LC'TaGhb"Ji@)LiZ*LBH"HR0ZE'pfISH-Miq)IhPeFA"aFA"[E'K PC@KZGS'*Mj'5P*DAQjqKSU#CN!#+K)#$Lj5GSD#ENiQ"IRq$L)U)KB"fDf9KB@C YG(TpI(PiHAf!IRajFfYPBQ0XH)52Q*U8LS"iFh"[FA4hGhGfG(GjHRf%LSq8Q*U FRCfIS*kAMB&iFh0hJBZ3!*!!MSH"HhGeHB+*MBq0L)"fF'pbGAGiHAYmHRPpJS@ &KB0qH'pTD@jhJ)D*LSCpGR*`F(&bFh4bE@GPCQP[Gi'+N!#6PCQFRCfEQTQ5L(p iG(4iJSkCRTbAN!#,Ki@'Lik-LBH%J(ajGR4dFh*cG(0bFA0hH(GfGA"VD'KYGhq &M*+6MSGrHAGeGRGiGh4`EA"eHRk%LSk3!*'4NC+5NT+5N!#+J(KcFR4kJSZ3!*+ 2LSH$Ihq%Lj5CQTH6M)4qHhTlHR9bFR*aFRGlIAq!IRYfF'e[GS#)M)k0KhpjGA& aFR"ZE@YRC@4REA9pKBL*LSU,MC'8PCD8MiH!HRCfHi10PCQCPC!!M)Q(LT'9PjH @NBU#HA0aFR0eGA4cFA"bGACeFQeRC'0PEAH"LT+APT!!KhjiGA4fGR9dFh&`FA4 hHi#%L)b-LBD&KSU1N!#5MSCrHhPlIS'&Lik1M)U&JB'&Lj+9PC'-KS1"J)'$Ji' !IhajGR4dGhTlH(4`Efj[GRq'M)q0L)4qHA9dG(*`Eh"aFA&dGRKjHAKjHhamJ)@ ,N!#9PC13!)U$Ihq#Kib4PTL@Nj+5NC+5N!#1M)H!I(TiH(TpJ)"mGh&YE'aYEh* cFR&aEfj[G(f*NCDCPT!!KhpkHRalHAYmHRPjHAPkHRKiHAGeG(4hHhq&LBU*L)@ #JS@(LT!!P*D6MSL(KiL,MBk2M)H$JAppIS'"J(afF@eXEA*jJBD(JhjjFh"bGhk (M)k2Li0kGA*bG(CiH(9`E'TTDfj[EQp`EfpbGAU"Kib2Mik,LBZ4Q*qQV+fUT*k ANSq1Mj+6MSCpGR*`Eh&cF'YQBQ0QD@acHRjqHR0XCQ9TFi'1PTL@NBU$Ii##K)D )Ki&kF@YUE'pcGRGfF@TQCQP[GRYrK)H(KiU1NjLHT+LQSCZ@NBq3!*!!N!#2LB* mGh*[E@aYEfpXD@KTEA4qL)f,KS&kGA0dH)#)MC!!NBk)J(YlIi5'KB"jFQYNAej IAPjKBf0MBQ9VGAq*N!#5NBf+M*'ARkL`Y,DcVDHLR*H9PC52KRadE'CMBf0LBQ* LC@PVEA*hHhjpH(0`Eh0kK)f9PjD8NSf,Lib1Mib'J(P`DQKTEA"`EQTNAeeIC'a fISD+LSL%JS1+NTfPUUURSTkEQTUDQjU6M)4lFfjVE'pbFR&YDfYYFAL"KSL'JAY hGA0eIBD0NT56MiU'KBH*LSH!H(&VCQ4PCQKUD'4LB'&PEAL'MT'3!)f(JB#%Lj@ JTUUXUU@KRCbISk@LQj'&HR"XE'paG(4aE@TSD'Y`GhamH(0YD@TZGAq,NjLCPBk *KiD)M)q0KhedE@TUEh9kI(TfF'aUDR"kJSL,LiL%J(k$M*DITDHQSCQ5N!#4NT5 8NSk*J(KeGRKmIi'"Hh&UCfPZGAb"K)&jFh&cGhq*NjUFQ*+,K)"rJ)5)Ki"hF'P PC@T[GAGdEfaUDQacISH-N!#3!)Z&JB''NCfQV+kVTCb9NC'6PCLCPSk&I(GiHhq #JhphF'PPC'9TER0eG("VDQjeJ)bAR*bAMiL%JB#$KiL'J(KaE'TYGAk%KB&lGA& ZF(H!L)f3!*!!MBU'KSZ8RD@STU#@Li5%KBL-MBb*K(pmI(q&LBb+JhKXBejIC@j hIB'"IATjHRq(N!#AQjU9Li*mHharK)@!GfpRB@&QEA9kHhG`D'4PDR*pL*!!P*5 4N!#4NjDGTDUVTTb6M)L(Lj!!Nj13!)Z'JRprJSD)LB9pFfPJA&jNEA9iHACbEh" dHi@2PTQANSb'Ji'#K)0rHA"TBf&PE(9mJS0qGQeSCfefIiL3!*@@PT56PCQGSD' GQ*11L)D'KSL+Ki5"IRalIB'&Ki@!HA&VD'GXFhTqIhejGA0cHS@4QTqJR*@-KS+ #JB'!I(9YC&jFAQ&PDQjZDf4IAf*UGS11PTZFQTUCQCZISk5KR*L8NT'5PCHBPT! !LS4qHRKiH(TkGh0`E@YVER*fH(GdF@p[FhU%MT@BQ*D2LBD'KiQ*Ki*lF@KLAf" ND@pcG(0aEQYZGS#+NTHCQ*D6NC'5PTQDQCH5MSU)LBU0MSb(JAYhG(4eGRCiH(C cF'eXER0iIB#!IRemIB+*Mj5@PT53!)U'KBD)L)H#I(9VBPaC@PeKC@KUDQPUERH "LT+9PC'0LSQ,MT+AR*kGQTH8NSq0Mj'3!)Z'J(ThGA9iHhYkH(0[E'TVF(9jI(e lHAGfGhb#KSL*L)D&K)1$K)D'JhefE@4IAf9XFhPmIAYjH(Z"Kif5P*53!)Z)KiL *MT5BQjUAP*!!LS@$JS+"IRakHAPjHhk!JApkGR*[F(9kIi@)Ki@"IRerJiH,MSq 2M)L&JS'"J(jjG'aPAeeICQecH(YlHAGeGAPrKSb2Mif,LSU,MBq6PC@9Niq-LSQ *LBU*KS*qHhYmIAepHhPeFR"[FA9mJB5'KB&pHRKjIS+&KiH(KB1!IRalHAGbE@P PBf4TF(KqJS5$J(ajHAf$LBf3!*'3!)k-M)f3!*18P*+2LSD%Ji1$JB'!IRakH(K iH(PkHA4`E'TVF(9lJ)1$JS'!JS5)MC1AQ*H4LS4qHACfGRCcEfYSC@9SEA*fHAP hG(&`FRGmJSH*LSU+LBZ0Mj'4NC!!Mik-M)b0Miq1M)L$IAPhGhPkH(CdF@pZEQp bGhb!JS"pHhYqK)Z3!*15MiU%J(aiGA9hGR4`DQ4JB@K`H(k"JB"rIReqJ)5)M*! !NC!!MSU(KSQ-MSq1MSf,L)L)KS5#J(jkGA&[Efp`FA&`EfeXER0hHherJB5'KiQ 0NTHDQjZAN!#*JhjlHhYkH(9ZCf*HA9jLD@pdGhKjH(KjIB''LBQ)Ki@%KBD(LSZ -MT!!N!#3!)q1N!#4N!#0LS9rHA9bFA"ZE@jZEQjZER"cGRb"K)@&KSH*Lib-M)Z *L)H&JRpmHAGeF@TMA9YEAQ9ZGAYrJS5'KB5%KSL+LiZ+L)D%K)5&KSH)Lik2Mif ,L)5"IRTfFQpYE'aXDfYYEQjZF(0iIB#%L)Z,LSU+M)q3!*'6Nj'0L)5"IAPfFQj TBPY@9PTICQjeHhjrIRepIi'$KB@'KB@%JS"rJ)1)M*!!NT+4NC+4MSb(J(TeFA" `Efj[FA0dG(0cGAPqK)Q,LSL%JS#"JiH*Lik2M)Q'JAelH(4ZCf"E@&KFBfTbHAq $KSD'KSH*Lif0M)Q&J(jmHhk#KSQ0Miq1M)L'JhplGh9bEQeZFA0bFh4cFh4fHAk $KiQ,LiZ*KS5&L)b3!*+5N!#0LBH&JRplGR&VC9pE@&PGCR"iIS#!IhjqIi#!JB1 %Ji&qI(apIi1(LBQ*LBL*LBQ(JhjkHAPiH(KiHAPjHAPiH(PmJSL,MBk0LSD$JS# !JB1'L)L)KS1"IRakGR&UBeeD@PjME(CqJiD(KiD%Ji5(LBZ,L)D%K)5&KiL*LBL )Ki@"IRakHAKhGR9cFR0eGRGiHAYpIi##K)D)LSZ,LBD$Ji5(Lik3!)q1LiQ(K)" pHhKeF@aQBQ"LCfjfIB+%K)1"IhepIS'&LBb-LBH'KSH(KS@%JS"rIi"rIAYlI(Y jGR4cFh4hHhq"JS5'LBb1Miq1M)L&JAppIS'&LBZ,LB@"IRakGh4[DQCLB@&MCQY aHS''KiD&Ji1(LSf3!*'2MSf-LSQ)KiL)L)H%IhYjGhKiGh9cEfeYE@j`G(KpJSD )L)L)LBZ-M)b+L)D&KBD*Lib0MBf,Ki*pHA9cF@jVD@GRD'a`G(KlIAprIRepIi+ 'Liq5NT!!MBU(KSD&KBD%Ji1#J(ekH(GfGR9cFA&bGRTqJ)+&KiL+M)k1MSk0M)Q %IhamIB'&LBU*KS0qHRCcEfaUDQTUDfaZF(0iIB'#JS'!JS5(M*!!P*D@P*+1LSH (L)U+Ki@$JApmHACbF("`F(&aFA*dH(b!Ji@(KiQ-MSq3!*!!MBU(Ji'"JiD+MSq 1LiD"I(GdFh*bFA"ZER"aFh9iHRaqIAYjGhKlJBL1NC+4Mib+LSL(KiH(KiD&Ji" pHhYkHAKhGhGfGRGkI(f"K)L,MBf1MSk-LS@"IhepJ)5(LBL&JAjmHAGfGA9fGh9 cFA*bFh4iHRYmI(apIi'$KiZ1Mj!!N!#2MSb-MBk1MSf-LSL'KB5"IRYiG(*aFA& bFhCkIS#"JB'#Ji5(LBQ)KiD&KBD)LSb0LiQ&JAelHherJ)"rI(TjH(GfGA9fH(K fG(0dH(f#KSU-M)Z+LSU,M)k3!*!!NC!!Mif,LBQ)KS*rI(PhGhKiH(KjHRYmI(e qJ)5)M)f,L)@$JS1&KiQ*Ki1"J(jmHhaqJ)'!IATfGA4dGACfGhGhGhPlIB'%KiU ,LiU)KiQ-N!#8PTD9P*+3!)q0M)Q'JhpmHRGdFh4eGRGfGA4bFhCkIi5(L)L(KB5 %K)D)LSb,LBD%JS'"JB+#JS"pHhPiGhCfGRGhGR9dG(9iIB+&KiH(KB1#JiD+Mj+ 8PC13!)k0MBk1MBZ)K)'!IRakHAPiGR9dG(9hHi'(LSU(K)&rIRq#KBH)L)H&JAj mIAjrJB"qHhGeGA4eGhGiHATjHATlIS+'LBU)KS1"J)+(M*!!NT15NT'2Miq3!*! !Mif*K(pkGhChHRamHR9aF(&cGRYrJS1#J(jmI(k"KSU-M)U'Ji"rJ)#!J(pqIAa kH(KjHheqIAajGR9hHi#%KSD'K)&rIRq#KBL,MBb,LSQ+M)k3!*!!Mib)KB+!Ii# "JS+!IAPeG(CiI)##JS&rIAamIS#$KBD&Ji"pHhTkHhapIAakH(9cG(CjHheqIRe lHRYqJB@(L)H&JRprJ)+&LBZ-MBb-LiU+M)k1M)Q&JAjpIS'$K)5"IAKdFA"aFhG kI(emHRPjHhf!Ji@&K)+"IhjqIRjrIhemHRPjHRarJS1#J(ajH(PlIS'#Ji5#J(j mI(k"K)H)L)D&K)5'L)Q,LiZ*L)D&KBD(L)Q(JhjjGR4eH(TmIRjqIAepI(eqIi# !IhekH(GhH(KjHAGeGAChHAYpIi#"J(ppI(aqJ)1'KSD&KB@&KBD(KiH)KiD&KBD (L)Q+LBH%JS'"JS5'KiD%J(aiGA4dGRKkHhamHhYlI(jrJB'"J(jlHAKhGhGiHAP jHRTlIB##Ji+"IhjpIAjrJB+%KSD'KSD&K)5&KS@%Ji'"JB'#Ji5&KB@&KB5$Ji1 &KSD&Ji"qI(apIAepIAeqIRprIi#!J)"rIAThGA9dG(4dFh4eGRGiH(PkHheqIAa mIAk"K)D)L)L)KiH)L)L)KiD'KSH(KiH(KiD&Ji&qI(YlIAq!JS+"J(ppI(YlI(a pIAalHhYpIi#"JB#!IhelHRPhGRChH(KhGhGjHhapIAemHhYlI(q"JS1&KSD&Ji' "JS1%K)1#JS1$K)@&KB5$JS'!IRalIAq"Ji5%K)1#JS+#Ji+#JB#!J(prJ)'#JS' !IRakH(GfGA9dFh0bFR*cGACiHATkHAKhHAb!Ji5&KSD'KSD(KiH)L)Q*LBL(KiH )L)L'Ji"pHhTkHhaqIi#!IhjqIRq!JS1$JRppI(amIAk!J)'#JB'!IRalHRTjGhC dG(9hHRaqIRjmHRKhGhPlIS#$KB@%Ji+#K)@'KiL)KiD&K)1#JS+#JS&rIRemI(a qIRprIhq!JB1&KB@&KB@%K)1#JS+$Ji1#JApqIAalHAKhGA0bFA&cG(GjHRTjGh9 cFh9hHhf!Ji@&KS@&KBH)Lif2N!#1M)Z*L)D%Ji'!IhjpIAamIAepIAemI(erJB1 $Ji1"JB'#Ji1%K)5%K)1"J(pqIAakHAKfGRChHATlI(amHhTiGR9fH(YpIi'"JB# !JB1&KiQ-MBf-LSH%JS'"JB+!IRemIAk!JB+"J(jpIAeqJ)'%KiQ*L)H'KSD(L)H 'KB1!IRepHhTiGhCfGA9eGA9hH(PjH(CdFh0dGRKkIAq"JS+#Ji@)Lik3!*!!Mif ,LSU+LBH'K)+!IRjqIi##Ji+!IAPhGhKlIi+&KiH&K)+"JB+%KiL)Ki@#J(jpI(Y kH(KiH(PkHRYmIAepI(TjGhCfGhPlI(apIRq"K)L+LiZ,LBH&K)5&KSD'KB1!IRe qJ)+%KB@$JAejH(KlJ)@+MBf+Ki5#JS1&KSH)KiD%JRppHhTkHAKhGR9eGRGiHAT kHRKfG(0cG(GkI(k!JB+$KSL+LiZ+LBQ*LSU-M)b,LBH%JS'"JB+$K)5"IAPhGRG kIS1'KiD%JS"qIAerJS@(L)H&Ji'!IhjqIAalHRTjHAPlI(eqIAakH(ChH(PlIAj rJ)'$K)5&KB@&KB@&KBD)LSU*Ki@#J(q!J)+$K)5$JAjlHATpJ)5)LBQ)KS5$JB' "JS5&KSD&K)+"JB'!IhekH(GfGRGjHRYlHhPhGR4dGAKlIS'#JS+#JS1%KBD'KiH )LBQ*LSQ*L)H'KB5$JS+$Ji+"IRakHRTmIi'$K)@%Ji&rIReqIi#"JB'"JB+$Ji1 #J(jmHRKiH(TpIi#!IhelHAPjHAYpIi#"JB#!Ii#"JS1%K)5$Ji+$Ji1$JS+"JB' #JS+$Ji1$JAppI(erJS@(L)L(KS@%Ji+#JS+"JB'!J)'"JB'!IRYiGR9fH(TpIhp qIAYjGhCfH(YpIhprIRepIRq"Ji5&KSD&K)5%K)@'KS@&K)1$Ji5%K)1#JApqIAj qJ)'#Ji1#JB"rIhprIi"rIhprIhprIhjpI(YjH(KjI(q"Ji1#J(jmHhYmIAprIhj pI(YlI(k!JS1%Ji+"J)#!JS1$JS&rIRjqJ)+$K)@%Ji'!Ihq!JB1%KB@&K)1$JS+ #Ji1$Ji+"J(pqIRepHhPiH(KjHheqIhpqI(TkHATlIAq!IhelHRPkI(k!JS1%K)5 $Ji1$K)@&K)5#JB#"JS1%KB@%JS"rIRjqIi'#Ji1$JB#!Ihq!JB'"J)"rIhprIRj pI(YlHRTlIAjrJ)#!J(prJ)#!J)#!IhemHhYlI(jrJ)'#JS'#JS+$JS+"J(jpIAe qIi'#Ji5$JS"qIRjrJB1%KB@&K)1$Ji5&KB@%Ji+!J)#!J)"qIAYkHAPjHRYmIAe qIRepI(apIAjqIRemHhYlHheqIi'#Ji1%K)5&KB5%Ji+"J)#!JB'#JS+"JB"rIhq !JB+$Ji+"J)#!JB+$Ji1"J(prIhprJ)"rIRemHRTkHhaqJ)'#JS'!IhjpIAeqIRj qIRepIAepIAjrIi#"JS1$Ji+"J(prIRepIRjrJ)#!IhjqIi#"JS1$Ji+#JB'#K)@ 'KSD%Ji+"J)#!J)#!IhemHhTkHhapIRq!IhemHRTkHhYmIAepIAemI(amIAk!JB+ $Ji5&KB@&KB5$JS'!IhprIi#!J)"rIhprIhprIhprIhq!JS+$Ji+#JB'!IhjqIRj qIRepIAepIRq!JB+#JB"qIAamI(amIAepI(alHhYlI(eqJ)'"JS+#JS+"JB'!Ihj qIRjqIhprIhprIRjqIRjrJ)'#JS1%K)@&KB@%K)1#JB"rIRjpI(apIAjrIi#"JB# !IhemHhTkHRTkHhYkHRPjHATlIAjrJ)'"JS+$Ji1$K)5%Ji+"JB#!J)#!J(pqIAe mI(apIRq!JB'#JS+#JS+#JB'"J(prIRjpIAepIRq!JB+#JS+"JB"rIRepI(amI(a mHhYlHhYmIAjqIi#"JB'#JS+#JS+"JB#!J)#!J)#!IhjpIAamI(eqIhq!JB+$Ji5 %KB@&K)5$JS'!IhpqIRjrIi#"JB'"JB"rIhjpI(alHhYlHhTkHRTlHhamIAepIRq !JB+#Ji1$Ji1$Ji+#JS+#JS+"J(pqIAamIAepIRjrIi#!JB+$Ji1$Ji+"J(prIhp rIhq!J)'"JB#!J)#!J)"rIRjpIAjqIRepIAemI(amI(apIRq!JB'#JS+"JB'!J)# !J)#!J)#!IhjqIAamI(epIRjqIhq!JB+$K)@&KB5$JS'!J)#!JB'#JS+#JB"rIhp rIRjqIAemI(amI(amI(YlHhYlI(epIRq!JB'#JS1$Ji1$JS+#JB'#JS+"JB"rIRe pIAeqIRjqIhprJ)#"JS+#JS+"JB#!J)#!JB+#JS+"J)"rIhprIhprIRjpIAepIRj qIRemI(amI(epIRq!J)'#JS+#JS+#JB'!J)#!J)#!J(prIRjqIRjqIRprIhprJ)# "JS1%K)5$Ji+#JS+#JS+$JS+"JB'!J)#!IhpqIAamI(amI(epIAamI(amI(epIRj rIi#"JS1%K)5$JS'"JB'"JB'"JB'!IhpqIRjqIRjqIRjqIRprJ)'#JS+#JS'"JB' #JS+"JB#!J)'"JS+"J(pqIAamI(apIRjqIRjqIAepIAepIRprIi#"JS1$Ji+#JB" rIi#!J)#!J)#!IhjqIRjqIAepIAjqIi#"JS+$Ji1$Ji1$Ji+#JS+#JB'"JB+#JS+ "J(ppI(YkHRTlHhapIAepIAepIAapIAjqIi##JS1$Ji1#JB'"JB'#JS+#JS'"J(p qIRjpIAepIRjqIhq!JB'"JB'"JS+#JS+#JS+"JB'"JB+#Ji1#JB"qIAalHhYmI(e qIRjqIRjqIRjqIhprJ)#"JS+$Ji+#JB#!J)#"JB'#JB'!IhpqIRepIAepIRjqIi# "JB'#JS+#JS1$Ji1$Ji+#JB'"JS+$Ji1#JB"rIAalHRTlHhYmI(epIAepIRjqIRj qIhq!JB+$Ji1#JS+"JS+#JS1$JS+"J)"rIRjqIRjqIRjqIhq!J)#!J)'"JB+#JS+ #JS'"JB'"JB+#Ji+#JB"rIRepI(apIAepIAeqIRjqIhprIhjqIhq!J)'#JS+#JS+ "JB'"JS+#JS'"J(pqIRjqIRjqIRjrIhq!J)#"JB'"JS+#JS+#JS+"JB'"JB+#JS+ #JB"rIRjpIAamI(apIAepIAjqIRjqIRjqIRprJ)#"JB+#JS+#JS+$Ji1$JS+"J)" rIhprIhprIhprIhprIi#!J)#!J)'"JB'"JB#!J)#!J)#"JB'"JB"rIhjqIRjqIRj qIRjqIRjqIRjqIRjqIhprJ)#!JB'"JB'"JB'#JS+#JB'!J(prIhprIhprIhprIhp rJ)#!JB'"JB'"JB'"JB#!J)#!J)#"JB'"JB#!IhjqIRjqIRjqIRjqIRjqIRjqIRj qIRjrIi#!J)'"JB'"JB+#JS+#JS'"J)"rIhprIi#!J)#!J(prIi#!J)'"JB'!J)# !IhprIhprIhq!J)#!J)#!IhprIRjqIRprIhprIhpqIRjqIRjqIRprIi#!J)#"J)# !J)'"JB+#JB'!IhprIhprIhprJ)#!J)#!J)#"JB'"JB'"J)#!J)"rIhprIhprJ)# !J)#!J(pqIRjqIRjrIhprIhjqIRjqIRjqIRprIhprJ)#!J)#!JB'"JS+#JB'!J)" rIhprIhprJ)#!J)#!J)'"JB#!J)#!J)"rIhprIRjqIRjrIhq!J)#!IhprIhprIhp rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"J)#!J(prIhprIhprIi#!J)# "JB'"JB'!J)#!J)#!J(prIhjqIhprIhq!J)#!IhprIhprIhprIhjqIRjqIhprIhp rIhprIhprIi#!J)#!J)#!J)'"JB#!J)"rIhprIhq!J)#!J)#!JB'"JB#!J)#!J(p rIhprIhpqIRjqIRprIhprIhprIhprIhprIhprIhprIhq!J)"rIhprIhprJ)#!J)# !J)#!J)#!J)"rIhprIhprIhprIi#!J)#!JB'"JB'!J)#!J)#!J)"rIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!Ihp rIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprJ)#!J)#!J)#!J)#!IhprIi#!J)#!J(prIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq !J)#!J)#!J)#!J(q!J)#!J)#!J(prIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhp rIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIi# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIi#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!!!!X3!!"!!%!"3!!!+!!!B"4!!! !!!!8!!!!!!!!,"C@lSZM!!!X&!!!,"8!2)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J(prIhq!J)#!J)# !J)#!J)#!J)#!J)"rIhprIhprIhprIhprIRjqIRekH(KpJB*rHh"H6%%m2$j!2$% R,d989dp&26Fd0MY"4de6@&jMCfY[FA4jJ)U@SUqla-[4ephKjHRYlr,cp2AfprI fp[Eep22cmr,blqV9Rh&pRDHXXE+aVUHJQ*!!L)"e8"3!'c8p4%P*4N!i,bJP*#F X-cT"4da49PTHB@4QDR"iJBfCT+kf[-,(c0$8f0[Hi1(Mj1AQjqIRk1MRjqIQj0r 8VRjXHBQ8Qk+QUDLPS*Q5LApZ443%%L)X06a!3N!m0M%Y,#da0Ma"4NT18PCCA&j JBfKYGAq*P*kRVV1i[-$%b-[1dG,8eYMCfY[Fh0hGh0[DeXqlNR&XFRZ%M*1DRk' JRCL5LAjV3aS,$aBI+#mh1cdm1MFe0$8i1d"%5%Y1894A@9YGAf*RE(9rL*+ESDH XX,5i[,r#a-I*bXc1cp$4dY26dp(2blqQJfjVEA&iIiD1P*LDQCD4LAjU5#88%K3 B(L8X-MFk1cXl1c`r3N9)5dj38P9A@9YFA@"MD'phJ)Q4QCqMTkZ[XV@iZll!`X2 &amM*bXV,bmR'[l'BI@jXE'eaGRf%Lj!!P*@8NBTrE9%b(aXC'4`J*5Xa0MSp2d& $4NP-6e&69&CA@9YFA9jJBQCVFRU$Lj+BRU+PUDb[XV5hZEZp[X$"`m6%aFA$[lD RNAa`E@eYEh*hIB1*MT'5N!#,JA&D35dP)L!J)5-S,6-i28&&5%a38P9A@9TDA&e HAf"JBQ0QDh"hISD0P*UHSD5RUkf[XV5fZ,Ul[Ekr`-(![VQ`SBjpFfp[Eh"aG(P qK)U1N!#2M)4fC%dk,bSS*bBQ*bX`06Y"4Na39&KEA9jIAf"KB@*LBf4PCfT[G(Z $LC!!PTUHSD5RUDbZX,+dYVHjZVbp[EbkYDZGMApeFR&aFR*dGRZ!KBU0MSb'HfY C4cSc-#iX+bXX,M-j2dC-8PGFB'*MC'4NC'9PC@CQCfPVEh4jIiD-NTHERk'NTUL VVDqaXV5fYlQkZVQfX+HEMB&iG(0cFh4eGRPpJSH,M)Z(IR&L8N8p0c8c-6!`-$- i284-8PKHBQ9RD'KSD'KSD@PTD@YXEh0iIB1*Mj@CR*qKT+DSUUbZX,+dYEHhYlD cVD5CMS4mGh9eGRChH(TmJ)@*LiZ)JAGUA&"'2cXj1$Be06Bi280+8PPJC'KVE'a XE'aXE'aXE'eZF(0hI)+(MC1AQjkJSU5RUDZYVl'bY,@fYV5aUk1CMiCrHRKhH(P kHRapJ)5)LSZ*K(aaC9P35%0!2Mdm1cSl2N0+89PIC@TYEh"`F("`Efp[Eh"`FR4 iI)''M*'@QTfJSU5QU+UXVV#bXl@eYE1`UU1DNBQ#IAYkHRYmIAjrJB5(LSZ+KS" hE@*B8%T'3d*"3$mr384+8&GIC@Y[FA0cFh0cFR*bFR*bG(9iI)#<!!P*LFRk' MTDHUV+k`XV1dY,5bVUQLQj+,KB"pI(apIi#"JS1&KiQ,LiL$I(0TB&G46%K'489 %4%9(5P"@A@4UER*dGA9eGA9dG(4dG(9fHAarK)Q1NTHERU#LTDHTUkf[XE+cXl1 aVDLLQj10Ki*rIRjrJ)'#Ji5&KiQ+LSQ&IhGZCPe@88e+58K)5%K+6&"9A'*SER* dGRGhGhCfGR9eGAChHAYqJSH-N!#9QCfISU5QU+UXVV#aXV+aVkbRSTZ8MBL%JAp rJ)'$K)@'KiL*LSU*Ki*lG'YMA9G56Na,5dY-68p59PYKCfaaG(ChH(KiH(GhGhG hH(PlIS'&LSq6PjZISD1QU+UXVUqaXV'aVkZQSTZ9MiU'Ji'!JB+%KSH)L)Q+LiZ +L)4rH("TBPaA8e"26Nj28&*89eYKCQY`G(CiHAPjHAPjHAPjHATmIS'&LBf5PTU HSD1PU+UXVUqaXE'`VUZRSTb@N!#-L)5$JS+%KBH*LSU,Lib-LiU(JRaeEQGK@eG 88P&48P099ePGB@CUEh0fH(PkHRTkHRTkHRTlI(k"K)L-N!#9QCfJSkDSUUbZVl# aXE#ZUkDKR*H4MBQ'K)1$K)D)LSZ-M)b0MBb,L)4rHA*XCQ"E9e968e499ePEAQ& PD@eaGAGjHRTlHhYkHRTlHhaqJ)1'LSq6PjZISU@RUDZYVUq`X+qXUDDKR*H5MBQ (K)1$K)D)LSZ-MBf0MBb,LBD"I(C[D@4I@eG9999@@&TGAf*PD'a`FhChHATkHRY kHRYlHhapIi+&L)b4PCQGS+1QU+UVVDkZVUfVU+5JQjD5MBQ(KB5$K)D)LSZ0MBk 1MBf-LSH$IRPcE@GLAPTB9eGA@9YHB@0QD@a[FR4fH(PkHRTkHRTlHhapIS'%KiU 1NjHERk+PTkQVV+bYV+ZTTU1IQTD5MSU(KB5%K)D)LSb1Miq2MSf-LSH$IhTeF'T QBPjE@9PC@eeIBQ9RDQaZF(*dGRGhH(PjHAPkHRYmIB#$KBQ0NC@CRD'NTULTUUZ VUUQRT+'GQC@4MSU)KS@&KBD)Lif2N!#4N!#3!)k0LiL&JAaiFfjUCQ*IA9YEA&j KC'GTDfe[FA*cG(9fGhKiH(PjHRYmIAq#KBL-N!#8Q*bJSkDSUDQUUDLRTD+IR*L 9NBk,LBH'KBD(L)Z0Mj'5NT'3!)k-LBD$IhTfF@eTC@*JAPeHAf&NCfTXER"aFR0 dG(9fGhGiH(PjHRYpIi'%KiZ2NjHERk+NTUHSU+LRTD1KRTUAP*'0LiQ(KS@&KSL +MBq3!*+5NC!!Mib+Ki5!I(KdEfYSC@*JAepJB@4RDQe[F(&bFh0cG(9eGRGhH(P jHRaqJ)1'LBf4PCQFS++NTDDQTU@MSCqFQCD6N!#0LSL'KB@&KBH*Lif2NC+4NBq 0LiL%JAjkGR*ZDQCNBQ"JB'*NCQTXER"bFR0cFh0dG(9fGRGiHATlIAq"K)H,Mj+ @QTkJSU5PTD5MSU#HQjL9NBq-LBH'KB5%KBD)LSf2N!#4NC'3!)k-LBD$IhaiG(" XD@CNBQ&KBQ4QD@aZF(*cFh0cFh4dG(9fGhGiHRYmIS'%KSQ0NC@BR*kKSk1MSk+ KRjfDPj54MSZ*Ki@%K)5%KBH*M)k3!*'5NC!!Mif+L)5"IRTfFfpVD@CNBf0MC'C TE'j`FR0dG(4dG(4dGAChGhKjHhaqJ)+&LBb2NjDCRCqKSU+LSD#HR*QAP*'1LiQ (KB5$Ji5&KSL,MBq3!*'4NBq1LiQ'Ji"mH(9aE@YSCQ9NC'4QD'YYF(*cG(4dG(4 dG(9eGRGiHATmIAq#K)H+MT'8PjUGRk#KSD#IRCZBPT13!)f+L)D%Ji+#JS1&KiQ ,MSq3!*'3!*!!MSb+Ki5"IATfFfpXDQKQC@4PCQGTE'paFR0dG(4dG(4dGA9fGhK jHhaqJ)+&L)Z2NT@BQTbHRjqHRCZCPj54Mib*Ki@$JS'"JB+$KBH*M)k2N!#3!)q 1M)U(K)*qHhKdF@eVD@GQC@9PCfPVE@paFh0dG(0cFh0dG(9fGhKkHherJB1'LBb 2NT@BQTbGRCfFQTL@Nj!!MSZ)KS5#JB#!J)##Ji@)LSb1Miq2MSb+L)D$J(ejGR* [E'TSCfCPC@CSDQaZF(*cG(4dFh0cG(4eGRGiHAYmIS##KBL+MC!!NjDBQTZEQjU CPj@5Mif+Ki@$JB"rIhq!JB+%KiQ,MBk2MSk0LiQ(K)&qHhKeF@jXDQKRCQCRD'T XER"bFh4dG(4dG(4dGAChH(PkI(k!JS5(LSb2NT5@Q*UDQTUBPj@5N!#0LSL&Ji' !IhjqIi#"Ji@)LSb0MSk1MBb+L)@$J(ejGR0`E@YTD'GRCfKTDfe[FA0dG(4dG(4 dG(9fGhKjHRYpIi'$KBL,MT!!Nj@@Q*QCQCL@P*+2M)Q(K)+!IhjpIAjrJ)+%KSQ ,M)f1MSf-LSL'K)&qHhKeFQpYDfPSD'GSD@TXER"bFh4dG(4dG(4dGAChH(PlI(k !JS5'LBb1NC18PTHAPjD9Nj'1LiL'Ji&rIRemI(apIS##KBH*Lib0MBb,LSQ'K)* rHhPfFR"YDfTTD'KSD'TVE@paFR0dG(4dFh4dG(9fGhKkHherJB1&KiU-MT!!NT5 9PC@9P*+2MBZ)KB1"IhemHhYlI(erJB1&KiQ,M)b-LiU*Ki@$J(ekGh4aEfeVD@K SD'KTDfaZF(&cFh4dG(4dG(4eGRGiHAYmIS##K)D)Lif2NC+6P*58Nj'2MBU(KB+ !IRemHhYlHhaqJ)+%KSL+Lib-LiU*L)D%JApmHACcF'jXDfTTD@PUDfaZEh&bFh4 dG(4dG(9eGRGiHAYmIS##K)D)LSb1N!#4Nj16Nj+4Mif+L)@$J(jpI(YkHRYmIAq "JiD)LBZ-M)b,LSQ(KB+!IRYiGA*`EQaVDQTUDQYXE@paFR0dG(9eGA9eGRChH(P lI(jrJB1&KiQ,MBq3!*'5NT+5N!#2MBU(KB+!IRelHRTkHRYmIS##KBH*LSZ-LiZ +LBL'K)&rI(PhG(&[E@aVDQTUDfaYER"aFh4dGA9eGA9fGRGiHATmIAq!JS5'L)U -MBq3!*'4NC!!Mik-LSH%JS"qI(YkHAPjHRYpIi'$KBH*LSU,LiU*L)D%JS"pHRG eFh"ZE@YUDQTVDfaZEh"bFh4dGA9eGA9fGRGiHRYmIRq"Ji@(LBU-MBk2N!#3!)q 1MBZ*KS5#IhelHRPiH(KjHRapIi+%KSH*LSU+LSQ)KS@$J(jmHACdF@pZE'YVDfY VE'e[F(&bFh4dGA9eGACfGhKjHhapIi'#K)D)LBZ-MBk2Mik0M)Z*KS5#IhelHRP iH(KjHAYpIS'$KBH)LBU+LSQ)Ki@%JRppHhKeFh&[E@aXDfYXE'e[F(&bFh4eGA9 fGRChH(KkHhaqIi'#K)D(LBU-MBf1MSk0M)Z*Ki5#J(jmHRPiH(KjHAYmIS##K)D )LBU+LSU*L)H&Ji&rI(TiGA0aEfjYE@eYE@j[F(&bFh4eGRCfGhGiH(PkHhaqIi' #K)@(L)U,M)f0MBf0M)U*Ki5#J(jmHhPiH(KiHATmIAq"Ji@(L)Q+LSU*L)H'K)+ !IRYjGh4bF@pZEQeYE@j[F(&bFh4eGRChGhGiH(PkHhaqIi##Ji@'L)Q+Lib-MBb -LiU)KS5#J(jmHRPiH(KiHATlI(k!JS5'KiL*LBQ*L)H'KB1"IhekH(CdFR"[EQj YEQj[Eh"aFh4eGAChGhGiH(PkHhapIS#"Ji5&KiL*LSZ,LiZ,LSQ(KS5#J(jmHRP iGhGhH(PkHherJB1&KSH)LBQ*L)H'KB1#J(elHAGeFh&`EfjZEQj[Eh"aFR0dGAC fGhGiH(PkHhapIRq"JS1&KSH)LBU+LiZ+LBL(KB5#J(jmHRPiGhGhH(KkHheqJ)+ %KBH)L)Q*L)L(KS5$JAppHhKfG(0aF'p[Efp[F("aFR0dGAChGhKiHAPkHhapIRq "JS5&KSH)LBU+LSU+LBL(KB5#J(jmHhPiH(GhH(PkHhaqJ)+%KBH)L)Q*LBL)Ki@ %JS"qI(TiGR9cFR&`F("`F(&bFh4eGRChH(PjHRTlI(apIi#"JS5&KSH)LBU+LSU +LBL(KS5#JAppHhTjH(KiH(PkHhaqJ)'$KBD(L)Q*LBQ)KiD&Ji+!IRakH(CdFh* aFA&aFA&bFh4eGRChH(PjHRYlI(eqIi#"JS5&KSH)LBQ+LSU*LBL(KB5#JAppI(T jH(KiH(KjHRapIi'#K)@(L)L*LBQ)KiH'K)+"IhelHAGfG(0bFA&aFA&bFh0dGAC hH(PjHRTlI(apIRq"JS1%KBD(L)L*LBQ)L)H'KB1#J(jpHhTjH(GhGhKjHRYmIS# "Ji5'KiH)L)L)KiH'K)1"J(jmHRKfGA4cFR&aFA*bFh0dGAChH(KjHRTlI(apIRq !JB1%KBD(KiL)L)L)KiD'K)1#J(jpHhTjH(KhGhKiHATmIAq"JS5&KSH)L)L)L)H 'KB5#JAppHhPiGR9dFh*bFR*bFh0dGAChH(KjHRYlI(eqIRq!JB1%KBD'KiL)L)L )KiD&K)1#J(ppI(YkHAKiH(KjHATmIAq!JS1&KSH(L)L)L)L(KS@%JS"rIAYkH(G eG(4cFh0cG(4eGRChH(PkHhamIAjqIi#"JS1%KBD(KiL)L)L)KiH'KB1#JApqI(Y kHAPiH(KjHRYmIAq!JS1&KSH(L)L)L)L)KiD&Ji+!IRelHRKhGR9dG(4dG(9eGRG iH(PkHhapIAjrIi#"JS1%KBD(KiL)L)L)KiH'KB1#JApqIAYlHRPiH(PjHRTmIAk !JB1%KBD(L)L)L)L)KiD&K)1"IhjmHhPiGhCeGA4dGA9eGRGhH(PkHhamIAjrIi# "JS1%KB@'KiH)L)L(KiD&K)1#J(pqI(YkHAPiH(KjHATlI(erJ)+$K)@'KiH)L)L (KiD&K)1#J(jpHhTiGhCfGA9eGA9eGRChH(PjHRYmIAjqIi#"JB+$K)@'KSH(KiH (KSD&K)1"J(ppI(YkHAPiH(KiHATlI(eqJ)'#K)@&KSH(KiH(KiD'KB5#JApqI(Y kH(GhGR9eGA9fGRGhH(PkHRYmIAjrIi#"JS+$K)@'KSH(KiH(KSD&K)1"J(pqIAY lHRPjH(KjHATlI(eqIi'#Ji5&KSH(KiH(KiH'KB5$JS&rIRalHRPiGhGfGRCfGhG iH(PkHhapIRjrJ)'"JS1%K)@'KSH(KiH(KiD&K)1#JB"qIAalHRTjHAPjHRTlI(e qIi'#Ji5&KSH(L)L)L)H(KS@%Ji+"IhjmHhTjH(KhGhGhGhKiHATkHhapIRprJ)' #JS1%KB@'KiH(KiH(KiD&K)1#JB"rIRamHhTkHAPjHRTlI(eqIi##Ji5&KSD(KiL )L)L(KiD&K)1"J(ppI(YkHAKiH(KiH(KiHATkHhapIRprJ)'#JS1%K)@'KSH(KiH (KSD&K)1#JB"rIAalHhTkHAPjHRTlHhapIS#"JS1%KB@'KiH(KiH(KSD&K)1#J(p qIAYkHRPiH(KiH(KiHAPkHhYmIAjrJ)'"JS1$K)@&KSD'KiD'KS@&K)1#J(pqIAa lHhTjHAPjHATkHhapIRq!JB+$K)@&KSD(KiH(KSD&K)1#JB"rIAalHRPjH(KiH(K iHAPkHhYmIAjrJ)'"JS1$K)@&KSD'KSD'KS@&K)1#JB"qIAamHhTkHAPjHATkHha pIRq!JB+$K)5&KSD(KiH(KiD'KB5$JS'!IRemHhTkHAPjHAPjHATkHhamIAjrJ)' #JS1%K)@'KSD(KiH(KSD&K)1#JB"rIRemHhYkHRTkHRTlHhapIRq!JB+$K)5&KSD (KiH(KiH'KS@%Ji+"J(pqI(alHRTkHAPkHRTlHhapIRprJ)'#Ji1%KB@'KSH(KiH (KSD&K)5$JS"rIRjpI(YlHhTkHhYlI(apIRq!JB+$Ji5&KSD'KiH(KiH'KS@&K)1 #J(pqIAamHhYkHRTkHRYlHhapIRjrJ)'#Ji1%KB@'KSD(KiH(KSD&K)1$JS"rIhj pI(YlHhTkHRYlHhapIRjrJ)'#Ji5%KB@'KSD(KiD'KS@%K)1#JB"rIRemHhYkHRT kHRTlHhamIAjrJ)#"JS1$K)@&KSD'KSD'KS@&K)1#JB"rIRemI(YlHRTkHRTlHha mIAjrIi#"JS1$K)@&KBD'KSD'KS@&K)1#JB"rIRemI(YlHRTkHRTlHhYmIAjqIi# "JS+$K)5&KBD'KSD'KS@&K)1#JB"rIRjpI(YlHhTkHRTlHhamIAjqIi#"JS+$K)5 &KBD'KSD'KS@&K)1$JS'!IhjpI(alHhYlHhYlHhamIAjrIi#"JS1$K)5&KBD'KSD 'KS@&K)1$JS'!IhjpIAamHhYlHhYlI(apIAjrIi#"JS+$K)5&KBD'KSD'KSD&KB5 $Ji+"J(pqIAemI(alHhamI(apIAjrJ)#"JS1%K)@&KSD'KSD'KSD&KB5$JS'!Ihp qIAamI(YlHhYmI(apIAjrIi#"JS+$K)5&KBD'KSD'KSD'KB@%Ji+"JB"rIRjpI(a mI(amI(epIRjrJ)#"JS1$K)@&KSD'KSD'KSD&KB5$JS'!J(pqIAemI(alHhamI(a pIAjrIi#"JB+#Ji5%KB@&KSD'KSD'KB@%Ji1#JB"rIRjpIAamI(amI(apIAjqIi# "JB+$Ji5&KB@'KSD'KB@&K)1$JS'!IhjqIAamI(YlHhYlI(amIAeqIhq!J)'#JS1 $K)5&KB@&KB@&KB5%Ji+#JB"rIhjpIAamI(amI(amIAeqIhq!JB+#Ji5%KB@&KB@ &KB@%K)1$JS'!IhjqIAamI(YlHhYlI(amIAeqIRq!J)'"JS+$Ji5%KB@&KB@&KB@ %Ji1#JB'!IhjqIAemI(amI(apIAjqIhq!JB'#Ji1%K)@&KB@&KB@%K)1$JS'!J(p qIAemI(amI(amI(apIAjqIhq!J)'"JS1$K)5%KB@&KBD&KB@&K)5$JS'"J(prIRj pIAepIAepIRjrIi#!JB+#Ji5%KB@&KSD'KB@&K)5$JS+"J(prIRepIAamI(amI(e pIAjqIhq!J)'"JS+$Ji5%KB@&KBD'KB@&K)5$Ji+"JB"rIhjqIRepIAeqIRjrIi# !JB+#Ji5%KB@&KSD'KB@&K)5$Ji+"J)"rIRjpIAemI(amIAepIAjqIhq!J)'"JS+ $Ji1%K)@&KB@&KB@&KB5%Ji+#JB#!IhjqIRepIAepIRjqIhq!JB'#Ji1%K)5&KB@ &KB@%K)1$JS'"J(prIRepI(amI(amI(apIAeqIRprJ)#!JB'#JS1$Ji5%K)5&KB@ %K)5$Ji+"JB#!IhjqIRepIAepIAjqIRprJ)'"JS+$K)5%K)@&K)5%K)1$JS'"J(p qIRepI(amI(amI(amIAepIRjrIi#!JB'"JS+$Ji1%K)5%K)5%K)5$Ji+#JB'!Ihp qIRjpIAepIAjqIRprJ)#"JS+$Ji5%K)5&K)5%K)1$JS'"J(prIRjpIAamI(amI(a pIAeqIRjrIi#!J)'"JS+$Ji1%K)5%KB@%K)5%Ji1#JS'"J)"rIhjqIRjqIRjqIhq !J)'"JS1$K)5%KB@&KB@%K)5$Ji+"JB"rIhjqIAepIAepIAepIAjqIRprIi#!JB' #JS+$Ji1%K)5&KB@&KB5%K)1$JS+"JB#!IhprIRjqIRprIhq!J)'"JS1$K)5%KB@ &KB@%K)5$Ji+"JB#!IhjqIRepIAepIAepIAjqIRprIi#!JB'"JS+#Ji1$K)5%K)@ &KB5%K)1$Ji+"JB#!J(prIhpqIRjrIhq!J)'"JS+$Ji5%K)5%K)5%K)1$JS+"JB" rIhjqIAepIAemIAepIAepIRjqIhprJ)#"JB'#JS+$Ji1%K)5%K)5%Ji1$JS+"JB# !IhprIRjqIRjqIRprJ)#!JB'#JS1$K)5%K)5%Ji1$JS'"J)"rIRjqIAepI(amI(a pIAepIAjqIRprJ)#!J)'"JS+#Ji1$Ji1%K)5$Ji1$JS+"JB#!IhprIhjqIRjqIhp rJ)#!JB'#JS1$Ji5%K)5$Ji1#JS'"J)"rIhjqIAepIAamI(epIAepIRjqIRprIi# !J)'"JB+#JS1$Ji1%K)5%Ji1$JS+#JB'!J)"rIhprIhprIhprJ)#"JB+#JS1$K)5 %K)5%K)1$JS+"JB#!IhpqIRjpIAepIAepIAeqIRjrIhprJ)#!JB'"JS+#Ji1$Ji5 %K)5%K)5$Ji1#JS'"JB#!J(prIhprIhq!J)#"JB+#Ji1$K)5%K)5%K)1$Ji+#JB' !J(prIRjqIAepIAepIRjqIRjrIhprJ)#!JB'"JB+#JS1$Ji1%K)5%K)5$Ji1#JS+ "JB#!J)"rIhprIhq!J)#"JB'#JS1$Ji5%K)5%K)1$Ji+#JB'!J(prIRjqIAepIAe pIAjqIRjqIRprIi#!J)#"JB'"JS+#JS1$Ji1$Ji1$Ji+#JS'"JB#!J(prIhprIhp rIi#!J)'"JS+#Ji1$Ji1$Ji1#JS+"JB#!IhpqIRjpIAepIAepIAepIAjqIRjrIhp rJ)#!J)'"JB'#JS+#Ji1$Ji1$JS+#JS'"J)#!IhprIhprIhprIhq!J)#"JB+#JS1 $Ji1$Ji1#JS+"JB#!IhpqIRjpIAepIAepIAepIAjqIRjrIhprIi#!J)#"JB'"JS+ #JS1$Ji1$Ji+#JS'"JB#!J)"rIhprIhprIi#!J)'"JB+#JS1$Ji1$Ji1$JS+"JB' !J(prIhjqIRjpIAepIRjqIRjqIRprIhq!J)#!J)'"JB'#JS+#Ji1$Ji1$Ji1$JS+ #JB'"J)#!J)"rJ)#!J)#!JB'"JS+#Ji1$Ji1$Ji1$Ji+#JB'!J)"rIhpqIRjqIRj qIRjqIRjqIhprIhq!J)#!J)'"JB'#JS+#Ji1$Ji1$Ji1$JS+#JS'"JB#!J)#!J)# !J)#!J)'"JS+#JS1$Ji1$Ji1$JS+#JB'!J)"rIhpqIRjqIRjqIRjqIRjqIRprIhp rJ)#!J)#!JB'"JS+#JS+#Ji1$Ji+#JS+#JB'"J)#!J(prIhprIi#!J)#"JB'"JS+ #JS1#JS+#JS+"JB#!J(prIhjqIRjpIAepIAepIRjqIRjqIRprIhprJ)#!J)#"JB' "JB+#JS+#JS+#JS+"JB'!J)#!IhprIhprIhprJ)#!JB'"JB+#JS+#JS+#JS'"JB# !J(prIRjqIRjpIAepIAeqIRjqIRjqIRprIhprIi#!J)#!JB'"JB+#JS+#JS+#JS+ "JB'"J)#!J(prIhprIhprJ)#!J)'"JB+#JS+#JS+#JS+"JB'!J(prIhpqIRjqIRj qIRjqIRjqIRprIhprIhq!J)#!J)'"JB'"JS+#JS+#JS+#JS+#JS'"JB'!J)#!J)# !J)#!J)#"JB'"JS+#JS+#Ji+#JS+#JB'"J)#!IhprIhjqIRjqIRjqIRjrIhprIhp rJ)#!J)#!J)'"JB'"JS+#JS+#JS+#JS+#JS+"JB'"JB#!J)#!J)#!J)#"JB'"JS+ #JS+#JS+#JS+#JB'"J)#!IhprIhjqIRjqIRjqIRjqIhprIhprIi#!J)#!J)#"JB' "JB+#JS+#JS+#JS+#JS'"JB'"J)#!J)#!J)#!J)#!J)'"JB'"JS+#JS+#JS'"JB' !J(prIhpqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprJ)#!J)#!JB'"JB'"JS+#JS+ "JB'"JB#!J)#!IhprIhprIi#!J)#!JB'"JB'"JB'"JB'"JB#!J(prIhjqIRjqIRj qIRjqIRjqIRjqIRjrIhprIhprIi#!J)#!JB'"JB'"JB'#JS'"JB'"JB#!J)#!J(p rIhprIi#!J)#!JB'"JB'"JB'"JB'"JB#!J)"rIhpqIRjqIRjqIRjqIRjqIRjqIRp rIhprIhprJ)#!J)#!JB'"JB'#JS+#JS+#JS+"JB'"JB#!J)#!J)#!J)#!J)'"JB' "JB+#JS+#JS'"JB'!J)#!IhprIhpqIRjqIRjqIRjrIhprIhprIhq!J)#!J)#!J)# "JB'"JB+#JS+#JS+#JS+#JS'"JB'"J)#!J)#!J)#!JB'"JB'"JS+#JS+#JS+"JB' "J)#!J(prIhprIhjqIRjqIRprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'#JS+#JS+ #JS+#JB'"JB'"J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'!J)#!IhprIhjqIRj qIRjqIRjqIRjqIRjrIhprIhprIhq!J)#!J)#!JB'"JB'"JB'"JB'"JB'"JB#!J)# !J)#!J)#!J)#!J)#!JB'"JB'"JB'!J)#!J(prIhprIRjqIRjqIRjqIRjqIRjqIRj qIRprIhprIhprIi#!J)#!J)#"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)# !JB'"JB'"JB'"J)#!J(prIhprIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprIi# !J)#!J)'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB'"JB' !J)#!J(prIhprIhjrIRjqIRjrIhprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'"JB+ #JS+#JS'"JB'"JB'"J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'"JB'#JS+"JS'"JB'"JB' "J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'!J)#!J(prIhprIhpqIRjqIRjqIRjrIhp rIhprIhprIhprIhprJ)#!J)#!J)'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)# !J)#"JB'"JB#!J)#!J)"rIhprIhjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhp rIhprJ)#!J)#!J)'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#"J)#!J)# !J)"rIhprIhpqIRjqIRjqIRjqIRjqIRjqIRjrIhprIhprIhprIhprJ)#!J)#!J)' "JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)'"JB'"JB'"JB#!J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB' "JB'"J)#!J)#"JB'"JB'"JB'"JB'"JB'"J)#!J)#!IhprIhprIhprIhprIhprIhp rIhprIhprIhprJ)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#"JB' "JB'"JB'"JB'"JB'!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIi#!J)#!J)#!J)#!JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!IhprIhprIhprIRjqIRjqIRjqIRjqIRjqIhprIhprIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhp rIRjqIRjqIRjqIRjqIRprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'!J)#!J)#!J)# !JB'"JB'"JB'"JB'!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIi# !J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#"JB'"JB'"JB'"JB# !J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)# !J)#!JB'"JB'"JB'!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIRprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhq!J)#!J)#!J)#!J)#"J)'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)# !J)#!JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB' "JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB' "JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhp rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J)!!!#K!!!%!!3!&!!!!S!!"J&%!!!!!!"3 !!!!!!!!S&PEZLk-!!#J8!!!S&3!mJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)'"JS1%KBD(LBU,MC@ KUDLSX,Hl[lfcTk@``YANl2(bm1VJdmHlVk5FPSq)L*h$hqAHi[6rr2VikG5rV*q BNSb'JAYjHAPkJT[%j[AaiFQhYF(2dmr'YkDR`Y[A`kqCIQPD8P&DFTLrf1$DcVq aVE5jYl+bYVLeVUDCLA4H6%0-Dj5cZUZ5Gej,5eTUFRPrIhKXC'"HA9pLB9eA9Pp fP+bbSSZ#MUM#f1AKeY$*[,'XUkZTTk+CMSUDZYILhXqlTC58Skq[Tjb1IAZ5VlH `Tj4hA%Bi2PCeM*QGR*qLRTD3!)PqFQTTEh0aDf&@890DD)Lkir(Yh-#RRk+VZ-# rZlZm[,fqZl1QQ)TpF@0@8&GME'aJ5M3a5'9bG(4R8cmV'!i1&L%T,5dX-%9QJik (G@&45%eHER0aE'094dTCB&4'1#`T,cjFIT1AMRYN9PjfMTbMS*H2LSD#IRGXA8X h*KiV8AkETk13!(aS9%T2AQppLBPpE@"E@PYHB@0JA&pZJBkARTb3!)*qN!#SX+Z NQ)PqGQeN@P"-5dT(3$j+BRL#JAGZD'0LCQPN@8j#05db4eaMBee01c!`3ephKib *K)QCUlHl[EU[RSf"IB#)P*qJPB4hITbjaF@mVCq8LS*qHA&UCfKYG(k(LS9mF'* @9fZ(QCZ1Gee+3P*pTV@aSB4M56Xk38K19&KC994FEAk&J(4UD@j`FR0aE'CLBQ" HAfTfIS1(KAppK*Qa`,qbTD+TXEDeXUqVST5'I(CdFR&ZCeT15&9mUEqmUj0pF'j hKBk2KhTVA9GHDh0`CPK*2Mp3F)Q3!)PmE9j48QU)PT@4LS"jFQTM@e415dY19'0 hJB*rHA&VC&jB88Jq0#XP)LFqBharG@&(,L-Y5QKjI(CYC&pMFS#&JRefEQ9IA9Y A8Nj'1c%d8AkLYEDTQjD6N!#1Li*fD@0NCfPYG(K`AdSi-d9PJ)b-KAaeHj1NRBT jCeP68PGGB&pE9%Y)9'TpKS0eCf&QEhGmIAKYB&YSM,6-dF@TMAf#R,R'`V1LPj+ 6Qk'IQC!!LSH%JAjfD9Y668-m4Q@%N!#,IQeLB@PaFh*bFR4kJB5!HhTmIRemKTb YVk',Ff9RGjLh`,DPN!"pE&T,4dY16Na)4PClSEHhU)jeBPYJCfedHRGVB'0hM*1 4JQPA9fKpLiZ!FQYXG(q&Ki@#K)fETDQNPi9hF("qSFRKj0M$V*fCRUDQS*Q9NT! !MSZ'IhalGQP@4NC9CQYSA%Si-N9RH(CZAdj"0LXU0%416dFr4Q"mLBKrFfTQCfK QAeC048"!6QYqIR9S9%0$@AZ4PSq#G'peJ)H0NBq(IA*SAPKA@ea84cSf5h+4R*H (GfpXE'j`F("aEfPJ@P438PTLD(+(RU5CK@jC6NjLK*ZHQBarHheqJBD)KB1"JSb FU+QMPSGlEf0E@&G988a)3d44CA&eF'CHBA#(QUDSTD+JRk@VUkDJQC'-LSH"H(& ZE@adN!#mhZRPeEbQQTQPXVLdV+HQTU@MRj@&FPp148PHGB&pEPT*3NeTJB@"G@0 98&&AA@4VFhCdGAq-N!#0Jh*K@9aPERChG'jVEAQ4TkUGLR*H9PebMk@[X+fTTU@ NSTkEQ*1*IhC`ER&jIheeF)+R`XR%Xjb0KiH0PTZDNiZ!FQ*86%T089GDA'GpN!# 8LhaVBQL#R+5IPib!HRGiHhYfE'*A6%G5DRf#HfeE56dl3de699&)2$P)@PpG9NN q1N"9GT+GQBb"I(YqJB+"K)b6P*',JhPZBP4+5Pq&SkZPNRYUBf0SE'aUE(*hH(9 [D@GUE@TPBQf%PjZ8KA0NCRkARjU,Fej46%pCBfCPC'"GBA@@XlkiU*5%I)+5Rk+ ENSZ5VmlCdEkMLRKaIk$!cp$+`Vr$aX5lVk#3!)*fF'e[GAKeE@*@8&ekMj+&EPC )5&0PHBU6PT10KB"rJ(adD&T,3dpVKC'0I'CDCB@KV+ZJM(KUC'9TEA*fG@pRB@G eIRjiFh0eGR4ZC9a@8e0GFi5$H@pMA&YHDS#BU+fQQT5@R+1TVV+cXl'ZV+fbYDq KMi52XG,Khp#pX+QSUkq`VUbSSCL2KRpeE'4H9dj*8'"VDf"12$Y5FS&qG'*56%a 4@&aC8%8l-L`U-N4FE("R@8j09f9`F'GC6%TFHiq8PC!!K(CP8NK9GTDRVDQIPBb %IRK[CPeA88T%3%"#4NG%4&&VLTqMPS*bERH)QD@VU+'FR*qLSk+GPSf$GfTTICZ XUTU$G)'JXl@YR)9bC'&UGAKhI)+&JAPaF(Z(Li9kEQPYGAb$K(jdCf0`JB4pHR4 XD'CPDhfCVlQhVkUVXEQr[E1PPiZ$JB1(LB4jD9YDET'daF#`RBYqHi'*MBf*JRK ZCPpD9&"-58G'4%*&6ePF@&*9Chf,N!#1J(&YF(CpJ(pmHRTkGh9iKk#jaX5hUD1 PUV#aUTb-JibKVl5hVTb,IA&ZGikSZ,QbUUHRUDfYTTb5LiH)M*'6Mi0bB9PKFSQ HTk#BNBb1PCUFR*Q6MBD"I(CZCf4LAeT446e%@@TYC9eNHSZ3!*'-IQpL@9CB@&4 389496d-f0dTKE'aSB9aGC@pfFfGA6eYaHRGaC9G268e19@L"P*ZAMB0mH(KlIi& rHhPjHRaqIAG`EAH'MC+FRjH3!)b*MTHISU+IQT52LS@!HA"P@%T!1cT"9(#$KRP TDRZ-Q+'JPiq)JAppH(4cGAGhGA"XFibUZlfeTjL,JAq!IhGXCh#&PCbIQ)CfE@G PES+JZmV-`V5QRjkMTk5EN!#)KBL-M)CmEf&A@QTpN!#RZ,HXRSamGACqL)q2LB" iFQeUD'GPBPjC8Ne6CAb,Mif5Sl'`UU#3!)1!JSH1NBq+KS+!IAKaEA"lJi0qGh& `GS#)M)PqEfPaJ)H*LB0kGA*[ER&pPE,)dmr"XDDLTl6"aX1jVD+@LRpiFQe[JTQ PVEUpXkQIPj59PjZIS*fBNib$I(4UB&4(2cXj1dCFEh&Q@&&ECfKNB&9,4N4&58Y +4dC(58T+58K3Chq-LhpZA9&2@'CcHi#-RUDIPBb!FfPH99"8CS@KVUZIN!#%IRk !JAjhF@aTCQ"D9P*-4dTBDA@&Qk@KQ)TmGRKpKBk9QCZGRCQ4LS4rHR0UB9aIF)k TYVDbZ-("ZVDZT*b@N!#0LiQ)LBL%IRG[CQ*VJC@FPSGdC&aFC@e[CPaHEhq%K(p bCQ&KBfKcLkc(dXh!YE#[XVHkYUfNQj+*J(PfGhGkKTDEPCLLT*qDNSU&K)@(Ki9 rH(0XBeK35dT-6Np168pDDA*`D@4VHS1*Mj!!Miq-Ki"kG(&bG(KmIhprLD#lcG( *Z+LKSkbbXDQKTV[0cF@jTj5)JAjrJikPZX#jV*f8N!#4NT'1KhjjGR*VC&pHAQ& ZL*bGQCkJR*Q9MSZ*LBU+L)H+MBf*JhafEQCD5c`Z*Le&C(KlHAf'KS&rI(9XBPC 058K+8&CB9P&)2ca)Ah9pHQpL@9CAA'"H@Q"hNjkDNB"VAeYC@&TNH*1TXl5`UU1 HR*ZCNib%IhalI(q$K)'"LTHANCDIRTL6M)H'LC!!Q*fDMi&bC&TB@epJA9K346` m6@KqKiL4SUZRSCZ3!)CrGR"ZEQpbGAKpJB"iEQTfLTHCNSCqIS+)LiL!GRH*Qjf @Mi4jFh"ZE@adL*qXUk+8KRprL*5GSD+HPBTqG@jRB&eKERU#MTqQU+ZQQj52LiU +LSQ+Lik3!*!!MBCqG@pYE'TVFhk&KB+(Ql#iZ,5PN!"qEQ9NDA"hIAjpHhCaER1 %RDkdVk5@LAaaDQCLB'KrQD@MQSPhEh"cGRQ!NDDh[m'r[VbhXUZNRC5-KiD(LSf 1LiD%M*HGSkQRRTH1Ki1#JS5(Ki"hE@0D8Nj+4N4!1c-Y,6K-@PeC@QQ!LiU(IR" PAPPDAQ0TEA&bF@aK9P0KHSf8Nif(K)+!IRP`DQf"QD#CMi*`B9G36e9QJjkVUTq 5L)*rIi1(KS&jEf095%&$4dP,9'&YHif@P*'0KApmHRPjGh9eGhKhG'pVD@KRC@0 LDAU4SD+AL)HCV,'`UTf6MSb-MBf-LB0lEf0B8ePYKTQJR*'&Ii#(MT'0KS+0TVZ pXkD5Ih0YDh@,Um60bEb[Tk@SV+fUT*kEQjZCP)YqF'*B@@Z*UEl"YULCLS'!JB+ #IRGZD'9NC@4LAeP88%a+8'"cIRpfD@0[KjLGQSTeD@9REhKpJB@)L)0rJ)fQ[m[ )ZD@9MBf6QCfGPT!!P+Hl[V#ILhCTCQKbKk+bXkZJPBq1N!#4N!#-L)5#JB'$KB@ !G@CA8PjpRV+iVjk-Hh"[Gi+0P*D8N!#,K(aaD@0H@9026ePZJSQ(Ih0ZHBf@P)b !F'0F@9KA8de'2cXi1%"9Ehq!H'aI9P&389&25NC&6fL(Q*H1J'aF8e&GGT1QV+L GNBCrIB+*Mj'1LB4qHAGhH(GcEQKVJCqd[,LUQSf$IAaqK)U0M)U*L)H#Hh*TB&T A@'4lNCU6J@aJDBHQY,@XQ)4eD@9UF(4fGR4[D@b!RE6"`lbcV+QUUkUQRjL2L)b HUk@ALRGL@&PPITLSUUDJQTD5Mib)JhjjGR9iIB'$JRecCeaFFjLc[EQUPSCjFhL !Ji*rHhCcFR0cF@eRB&P89f4kMjQ9Kh9TDhkBTUDFL(0TDA"hHhjqI(PfGS#8U,' ZSjH0LBZ6RD+JPiTqG(@'RUbaX+12IA0hMDDdYE#RSCkLUV'dXkqTSCL4MBU)KS& iDepKHCbbY+bFL(KXCfTZFA"ZDfGLAPTB9e414d!m2dpTHhjeC99)5f1#NBf#G@4 @8%j4@&pLC'CQCh'&PjbCMi*fF(*hI(q"J(jkFfjcJSk0LB"[AeaRIC!!PC')IAC dH)#)L)&iEfKPBf"H@eP@88Y(6'5-UV1ZS)PeDQYiLC@BPj@5MSU'IR0SBPpGA@G pPD@SS*+&HA5$SEDiVTk'F@CQE(9lI(GaDQ4UIT@LSjb6MBZ-MSq0LB@!Hh4YF)' 8QTH1IQeSFS@CTUHKRU'RXEc#`VZbU*f5LB5&M*1@P)PpHSbV[,Q[ST!!IR0cHS+ %JATaD'"B8e"168e06P*EDA0hG'YJ@9CBBRQ4RD'KPiU$J(jqIRelHAZ&Ql2#`lL SQBf)MCDFRCfFQT@0Ji@ATkQLQBPlJ*@UYE@XS*H6NjDCQjbEQ*51Ki"hEfKNAeY BA(#4VVLaSj1"FQYVEQp[E'YXF(4hHAThF@GF9PjiNjqHPSPmF'9JDS#2MSCmE&Y 46%a18%j'2$Fr9h'!JAGUB&aFB'*MBf0MBf0JAQClLiU"G@9IEBDAQjD*HR&dIif 5MiCmG'paHB1)L)*hD9P26PalRE#`U*U)H(*cH(k#Ji"lGR"SBPpKC@CREi+CTD5 CLhpiGhKqMUDeXDHHP)Z(KBD(KAphGB#BXm6&ZkbKQjQES+5PT+'FPSf!F@afKBU (JAKlM*UHQj1*JB#'MC+6NBf+L)D$IRG`DfGLA&TKF)5GXlQYRBaiD'0ND@eaGAK mIi'"J(eiF@PND(L1RCq@LAacEfj`HSbDQj@0Ih0YDQKRD@PRDA5&PU+PSTb@Nj5 BQjL4LiU-N!#5N!#2PUD`UTk6MC@TZEklY+kYXVQr`,beVUHJQC12MBZ*KApeE'P ZGS+5QC1+Ih&RBepGAPpG@&436%Y08946894MGi+#HQpJ8NK$3N42ChTmG@eL@&4 69&KFA9ePHBkANS9dCPpKDhH"KSH'JATcDf&B9fCjIhejHB53!*12KhedEh&hHAK iHAapHhKeFh&[E'CH9e9FDAQ3!+QdX+QINib+L)Q,LiL&K)5$Ji1"I(9bIC+NUD1 BLAacFAClIiQDTU1DMhpbE@YXEQeUES'HY,fkVCk5LSH(LBQ(K)"lG'jRB@"YKjU HQTHFTDDFMi&hG(U)Pk#JQC',KAplH(GjHACaDQ9THBfKYX1qVk'6KAjmIB#$Jhp jGR4cFh*ZCf"GBh&rKB0kEfGPDA*iISfKUkLLPS4fF'paGRTmKCDSX+qRR*@@RDH [X+ZNRTbDPj++J(b%PCqHRCqPVV'XSTH3!)f4QD#LRjQ4L)"hF'TQC'CSD@GREhb "K)fCQT@2LB&kF@KLB@4SE("aE'9F99"6BRb3!*H8LAY`D'9NBf"FBR*mI(TdDQ& D88T&2cY#@("mI(GbEfj`G(KjGA&[F("YD'"A9@*jJhpmJ)@)KS&lHAb"Lj@DQCD 5MBQ(KS@$J(ahFQaQCh@'MjDKUDLKQT!!L)@"IAKcE'4HA@"MC@GSCfCYHSD,L)& iFQjYEQeUEAk8RCQ4K(0SBQ&ND'eiMU[!b-5hUCqFR*kJS*kFQjZCPBq'JBDATU+ AP*UMU+DJQT51L)L-N!#0LBD'KiH'KB@$IhGVAPCAB@aeKCbXVUZMPBQ!HA0aFhC iHRTiGA"UBepMFB@5P)f#GQpXE@p`F(0rLSf-L)5#K)D%IhPdGB5CUV'YT*fCQTq PTk@IPj!!M)b0LS*mISZ6N!#2QkUdYUkNR*QDRU1RTk+FP)q0MT'6NSq*JA9SB'0 [GRCjJSH%IhTbDQ4H@PPB9P*48e966NFq1$Y,B'j`CeP26&*EB'&HBR+%L)9qF@9 H@eTEA&eRIC1IRjQ4M)Z1NjH@NBb(KB1!Hh4XC'9bHhC`Gi5-MSU$I(KiHRq%K(p hE@4IAPjHAPjH@eC36eTVGRf*R+QRRC5+KSH(LBk8PT54N!#4NT'0KRjpLTZLSCQ 2KS"pIAYcDQPhKSQ&Ih4SB9eGAPjJDRk6SU5GNSU)MCDFR*H4LS@"IATiGRU*S+b UU+fbYV@aUk@KRjqKSCfANSq0LiQ&IRG`DfCK@eeTGRYpL*UMSjq9KhedE'CNBPj D@&KC@eeGA&eRH)L4NBTrGR"`G(KmJT1TY,1UR)f%J(epIAf"N!#T`Fh1aVbcVUZ TTk@MSU'IRTZ6KhTdISf3!)f3!*HER*H1KAjmIB#&L)D"Hh9`E'PRC'*H9de$1ca ,AQafKT14KRY`BejIBfefI(prIhekGQpQ@eTSJ*!!NSU!HRPmIi&qGh0kKiZ)JhG TB&YA9&09AR+-Rk1EMB&lI)+)LSQ(KS@#I(4VBejNGiU-KiU5QCZANBU'KSL0NT5 9PC55MiZ%I(0VCQ&F9eCGDh9kK*+CPC'-Ki5$J(epJB5$JAjkGA"UC'"RIjURTCU ,HfaJ@9KDAQZ"NjLBNS4eD&pFA&jMFSbNX,+URC+-LSZ0LiD"JB5(Ki0mFQaaIiL (KiqET+@HPBf+Lj!!PTbHR*H3!)Q$IRTeEfKLA9PA@fPpM*LQX+fPRjQ8NT!!MSf ,L)@#IhajGR&UB9aJF)10MSL!H(9cFh"VD('#M)f+J(*QAPPDA@&UICHYYV#KNB4 mHRf!JB"rIi#!IAK`DQk"PTZ@PCULU+DKQC14P*UIS*bAMiCqH(4bF@eSBejD9PG LEA9rMTLBP*!!LBD'KB&rIRakGh0[DfKNB@"QGikHSCZ4L)+"Ji@%JiZETUDJPSG jEQCJAPjJDi5JXE@ZSTD2LiZ2NC'1LS@!HR*SA&9EEhjrI)#*P*D3!)PrGh*aGRY mHAGeFh*`EQPNA94-4N0&6PaUGiLCRjbBNSU'JAYfFh*bGAb#KB*lFQPMCRD*P*5 0K(ahH(aqIAq0RCq@M(p`Cf0KB@*KBQf!P*qLR*+,L)Q0MSU#HhCeG(0bEQPUGS1 'JB',RDQTSTZAPjbNVE5bV++AM)0lGA"ZE@eUCQGbKjDDRD1MQT+*IhCdG(9hGh9 aE@PQBepD9P*5AA'#L)&dD'4QDfpaFRU,PjD4KhKUC'0NCfPVGBZNYVUbT*H1M*+ DRTqIRCL5Li4lF'TbK)k*JiH6Rk5KQC+0MBq4NT'2M)Q(KiD%IhCXBPP68&0JFS# )NCbJRCQ@N!#-Ki+!J(pjFh"bGRKfF@TPEB#5QCL4L(pjH(PiFQa`J)f,K(YZC&j E@9KA@QGrPU+KPiU"J)@-N!#2LB&fE'4IA9YDAQPkJi@-Q+'LRT@-KiH,PCkNTD1 HQ*'+JhehFQaRBPjHDAb)L)5*NTD5Li"cE@jbGAKiG'eQB&aE@PKBBR@)N!#0JR9 VD'T[G(9bFi'8QT1+IR"SCfCRDh5'Rl5r`,Q[Tk+JS*kEPj56NBb(J(K[CQ4XGhq *QD+KRTL4MSq4NT!!MBL$IAG`D@"C99046dj08Q*jMC55NTfQSjZ8LAeeF'eZFR9 jIS+"Hh0TC'b#PTqGNiL#J)'#J(TbDQalLSk,JhCUBPaB@@*aJSk6Nj+8PjQFRTk EP)f'J(TdEfTPB@"SHj+RY,1TRTD5PCbKSCkCP*!!MBQ$IRPcE@GLA&KDCA@$L)C mGi+BT+1HNi9jF@aVE'TPAeaFA&eKEAq3!*H@MiD#JS@)L)*iE@9QH*'JSTf2I'a MB@f(S+k`UU1GQjZHSD'HQTH8NT!!M)CmF@CG994KI*@JRBprFh"fJ)Q0M)H"HR9 bF'jUC@&G@999AfpmIhYcD'*VJjbRTCU+H@pUDR"hHRGaE'KREi'6R*b@MB@#JiQ 0M)GrG@PH@Q9fIRjjE9j@9fCpNCH6MBQ)Lj!!P*13!)Q#I(PkIB'%K(jeE'GZKUI !bF@hT*H4NTHHSD#HQjH4Li@!HhC[CQ"IDRZ*MSU"G@YNBfq'PjU9LhaXB&K89&C @994@BR@+Q*Z@MBD!I(TiGR0[DfKNB&jNGB5(JACUCQjqMCQIRTZES+DTTk+GQC@ 5MSQ%IRPcE'9LBfTjNUUeXUUJPBk-LiU*Ki5!IRakGh4[DQCMD(H*P*QBP)q*JRY cFRq8SD1HPBGlF@KMBQ*NE(b0PjQ9N!#-LBQ*L)@$Ji1"IAPbDQ*GBQeeH(f$L)U ,LSU0NC'2M)Q%J(ajH(PkH(0ZD'0H@PaNE'pYERZ5SUDMQiq'IhPkJ)D*LBH$I(9 XCfYjL)q2LB*qIAq"JAY`BeaNH)L-LS0fD9jA@@9cIB+'L)H&Ji5(LBD!HA0[EQp aFA"XCf&JE)1CTUQJN!##HRKmKBU0N!#6PTQDQTH5Li4lFh*lLjHDPj',Ki1'P+H YTjk6KATdEQYVE'TSDA+!M*'5N!#-L)@#J(jlGh*YD@CLA&KGDh9eFR*eHi'%KB@ 'KSL-N!#5N!#-Ki*mGR&YDQKSDR*mKBQ&I(ClM*bLSTb5L)0rIAjrI(KfG(0eISU 6PjD6MSL%Ji5'L)H%IACcHibBQCD3!)Q+NTLER*UAP*18PTLBPT+1LiH"HR0ZDfe dIB&qGQe[IBU-LS4kFQeTD'PUD@CNB@"LE(f2QCL3!)GqGh&YER*fH(9[DQq!Mj+ -JRKfJBf5Nj'0LSU-N!#8PTH@NSf(J(YeEfaUD@ekKBCrIiU6P*'0KApmI(k!J(j kGR*`E'GPDhb2Pj5,Ih0VCfP`GhPhFhH'PTU@MAp[BPTEE)15PT50Ki&pI(k#K)1 !I(KeFh*`E'CJ@9GLHj+GQT'#FfYVFhq)LiZ*KS&mHAKiGA"VERZ,PTU@MiQ$IAP hIj!!Rk'EP)TrHAGhH(KhISZARCbANBf,LSU,LiL%J(elGh*VBPYA@fTrP*qHPSb #Gh"XEA"eGhKhGhKiGhCdF@eTDh5"LBb+JhP`ERb4RU'HP)GqHAChHATjH(U#MCH DQC52LB5#JiH,LiQ&JAadE'CVH)1+NCDCQCD3!)U%IhYkIi1&KSD(LBU*KRphEQG PE(U'L)0kFRD$MT!!N!#0KS&rIRk!Ji1"IRTiIBQ6Pj@1KhpkH(Z!KSL'JAT`D'G bIS+!HhKlKBU,LSQ(KB@&KiZ1MSf,Ki*pGh*ZDfP[I)Q1LS5%MTLDQ*50Ki1"J)# !IRYjGh0ZD@ahJiL(JheiGA4fHRjrHR*TCQjlJAjiEQ&CA@YiIRjkGA&ZEh0kJ)+ #J(YeF'eVDfTRC@9VFRb,Qk+KRCD4Mj'5NT14MSU'JAppIAb!LjLIRTU6M)4rHhT jGh0aHBQ9PT'+Ih0UBf*VHiD,M)Q&JRppI(eqI(TiH(KhGA0[DQ9LCR@0Rk@LQBf #I(TlIi'"IhjqIRq!J)"pHAKmKSf2MBL"HR4`EQjcIik@P)q(IRCaE'TVFAZ%LSk 3!*!!MSZ(K)@(LBQ+LiZ+L)@#IAKdHBUET+@JPj!!MBZ+Lib0MBb,LBL(KS0qH(* aGS#,NC!!Li*iEfKMD(H,PTH6Li"hEQKNBf0QEhZ&LSZ)KB&pHRKjI)#$JS"pHAC bE@TXGiD6RCqFPj+1LiQ'K)+#Ji5'KS5"IATfFQjYG(q(L)D"Hh4ZERL'MBb*Jha hFfpYDfPRCQYfJSb2MSZ)K)'!JB1%K)*qH(0ZDQKTEhCkIS5)L)D$IhTfG(4fHAb !Ji*rHhCbF("[E@e`GRYpI(PeFR4pKSU-MBZ)KB1!IRakHATlJ)Q3!*58NSq-LSQ (KiD'KSD&Ji&pHAPrK)5%LBk6Niq*JRYeFR0iIB'$K)+"IRTfFQpYDfYaHS#$J(T dG(b%L)U*KS1"IhelHAKhGRCfHS+0PTZDPT+0LB@$Ji5%K)0rHRGlK)Z0LiL&KiZ 0MBb*KS+!Ii#$KSL*LBL'Ji"pHA9aF(&hIS+"Ihq'MT'3!)k+K)"pHRPiGhCdG(0 dGRb'N!#9PC+2LiQ'KB5$JRjkG@pZFhk(LBL$IAYqJi@'KS1!IRk!Ji@&K)1#JB& rI(TiGR0bG(PmI(TpKT!!Nj!!M)L&K)1"IhemHRKhGhKlIi5*MBk0LiH%JS"rIAY jGR0`ER&lK)D$IhTfGhf$KiL'Ji&rIAamI(YkHRTkHRPhFQeRBf&KC@Y`FhCpJi@ "IAYiGhGhHAaqIhjpHhPhGRKpKBf5Nj'-KS*qIAk"Ji1!HhKmKSk4MiU%IRb"L)Z -LiQ'K)1$KBL+Lib,LBD#IhakH(CcFA&dH(TpJiZ1MBU(K)+#Ji1#J(aiG(*cG(4 dGRPqJB1#JApqIAakGh9dFh0cFh9mJiD%JAejH(YrJS1%Ji1%KB@'KiD'KSD(KiL (KS@%Ji+"JS@)L)D&LC+APT54MSf,LBD%Ji+!IRakHAPkIB+)LiZ)K)"qIAepJ)1 %K)*qHRGjJ)D'JRplHATrKBH'JhpmHhf#KSQ+L)D%Ji'!IRajGR0aFA9mJSD(KB5 (Mj58Nj!!M)Q&JS#!IhjpI(TiGR4eHAk#JS+!IhjqIi#"JB"qI(PfFh&[FRPpHhG dG(Q!K)@$J(aiGhKlIS#!IhemHhYlHRPhG(&`FAGrKSQ(JRYhHB1,MSq-KS&pHRT mIAelH(CeG(9jIi1'KS5"Ihq"Ji5$JS"qI(TiGR9dGRZ"JAprJB5(KiD%JB#!JS5 'L)L(KB1"JB+%K)*rI(PfGRZ#KSH&J(TfGAb'LiZ*KB"mHhTjHAGeFh&aFhQ!KSL (JhjkGhGkIAprIhjpHhTiGh9cFhClJ)5*MT'5NBf)KB+"JB'#Ji@(L)H(KSD'KiD $JB#"KBb2N!#1LiD#IRf"Lj+8NSq,Ki1"IhjmHRGdFR0hIiD+LiU)KB1"J)#!J)# !IhprIRajGh4aFRGmJSQ-LiL&JRppIAeqIRepIAjrIRjpI(amI(YlI(q&Lif,L)5 #J(ejHS')LiU)KB"mHRPjHRTjHAPmJSH+LiU)KS5#JB#!J)"rIhprIhelH(9cFA* fJ)Q1Mif*KB+!IhpqI(YjH(GfGRCfG(0bFA&bFhClJ)1$JAppHhTkHAGfGhf%LSZ *KS*qHhPiHATmIi+&KiH'KB@&KBD(KiD&K)5$JAppHRKfGA9eGACkJSQ1MSb)KB+ !IRjpIAemHhTiGhCeGACiHRk"K)D)KiD$JB"rIAemI(amI(f!KSQ+Ki5"IRalHha qJB5&KB@%Ji&rIRjrJ)'"J(ppHhPiH(KjHAPkHRYmIS#$KiU,LiQ'K)1$Ji+"J(p qIRepI(apIRq#K)H,M)b,L)D%JS'!J(prIRemI(YmIB'&KS5#IhemIS#$KB5$JAj pI(apIAjqIRjrIi#!IhpqIAepIAepIS#$KB@$JB'$KiQ*KiD%Ji1$Ji1#JB'!J)# "J)"rIi##K)@&K)1#J(pqIi#!JB'!IRelHAKhGhTqJB+!IRalI)##JS'!IhjpIAj qIRjqIRjqIhq!J(pqI(YkHAKhGhPmJ)+#JB"pHhPkIS+$Ji+"J(prIRemI(YlHRT jHAPlIi5(L)L'KB1#JB'#JS1#JS'"J(pqIRjpI(YlIS+%KBD)LBQ)KS5$JB#!J)# !J(prIhjqIAepIRjqIAalHAKiHhq#Ji1"IhjmHRPhH(b"K)5$JAppI(YkHAPiHAP kI)#%KSD'K)+"J)#!J)'"JS1%K)1#JB"qIAamI(amIS''LSb-LSH%JS'!J)#"JB' #Ji1$JS+"J(pqIRjpIAjrJ)'$K)1$JS#!IhprIhjpIAamIi1(KiD%JS"qIAamI(a qJ)1&KB@%Ji+"J(pqIRjrIi#"JB'"J(pqIAalHhYlHRYlIAq$KSH'K)+!IRjqIRj qIRjrIhprIhprIRjqIRprJ)+$KB@%K)1#JB"rIhprIRjpI(alHhk"Ji1$JB"qIAe mI(eqIi#!J)"rIRjpI(amIAepIAjqIRprIRjqIAjqIRjpIAamI(amIS#$KB@&K)1 #JB'!J)'"JB'"JB'"JB#!IhjqIAeqJ)+%K)5$JS'!J(pqIRemI(YlHRTlI(q"JS+ "J(jpIAamI(eqJ)+$Ji+!IhjqIRjqIhq!J)#"JB'"JB#!IhprIRjpIAamI(apJ)1 &KB@%Ji+"J(prIRprJ)#"JB'!J)#!J)#!J(prIRjqIS'$KB@%Ji+"J)"rIhprIhp rIi#!JB'"JB'"JB#!IhjpIAeqJ)+#JS+"J(prIRjqIRjqIhq!JB'!J(prIhjqIRe pIAemIAeqJ)+$JS+"JB'#JS'"J)#!J)#"JB'"JB'"J)"rIhjqIRjrJ)'#Ji1$JS+ "JB#!J(prIRjpIAepIRjrIhprIhjqIRjqIRjqIhq!JB'"J)#!J(prIhprIhprIhq !J)#!J)"rIhpqIRepIRjqIRprJ)'"J)#!IhpqIRjqIRjrIi#!J)#!J)#!J)#!Ihp rIhprIhprIi#!JB'"JB'!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhq!JB+ #JB'!J(prIhprIhprIhprIhjrIhprIhprIhjqIRjqIRjqIRprJ)'"JB'!J(prIhp rIhpqIhprJ)'#JS+"JB#!J)#!J)#!J(prIhq!JB'"JB'!J)"rIhprIi#!J)#!J)# !IhprIhprIhprIhjqIRjqIRprJ)'#JS'"J)#!IhprIhprJ)#!J)#!J(prIi#!J)# !J)"rIhprIhprJ)#"JB'"J)#!IhprIhprIhprIhprJ)#!J)#!J)#!IhprIhprIhp rIhq!J)#!J)#!J(prIhprIhprIi#!J)#!J(prIhprIhprIhprIhprIhprIi#!J)# !J)"rIhprIhprIhprIhprJ)#!J)#!IhprIhprIhprIhprIi#!J)#!J)#!J)#!J(p rIhprIhprIhprIi#!J)#!J)#!J)#!IhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J!!!0%!!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!$3@9Zk,S`!!0"3!!$3 9!$b!J)#!J)#!J)#!IhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB' !JB'!JB'"JB#!JB'"J)'"JB'"JB'"JB'"JB'"JB'"IhjrJ(prJB'!IhekHAk"JiU 0L)Q0L)1"Ii'$K)@&KS@!I(TkH(4dH(U%M)*hIAphG(CrLSf*JRapIRk$JS"rHiD DNiD(KB"qJSf9PC+)I(&XF(YlE'CXE@GSDQ9MD'CLEAPlIiU&HAq%ISUDQj52Mj' 2Ki#'M)9iDQKcG'CHC@995e0LE'GLD@TTF(Q-R*++PCD5RUUMN!#2S+LINT+AQT@ (HA*qMRPNDf*+3%GHCeC9BQ4PFAPcH)Q0Lj@RXDqaYE+XUkkQU,UrXjk8Qj4kDfa TB'"G6%G46Mmj2NpMEAQ0QCZDQ+'[YE[#`XA-`lV)fY#qZ+fIQj5$Ef&95%4%26d r,b)S18Y19'KlQ+kGNU@XV,rDhFDqeq$4cXDl[,LMLAU$M(9-,b3M+5mZ,MFj-6) m4P4KG)Z-M+Hqc0V3ZEI$aXcPlYrEelqPNhpVC'0@2cBf,LBY-5)9'bSj6QCeJBZ 4Nj1DU,V2f0(-cYAHhG2&XU1JRSk!I@e53c8R-6de-63b0$K$@'9XH(q&Nk@i`-A 1bm(%b,klcH6E[,#[Rj55He!k3%3k1%"#1#mQ("BL5@ebEi'APT5Y[lD[Y,r-f1R jpqI*S)Q4RTH+LAYA3Mij,b3H*#JN,NY46'"`BP9HGBqYcYl5b-@hU+feYm2+`+Z ISjU'E8`c+5B`3%8q1#mH%ada3e"A@fL#Q+#MU+LJR+@[[Fh6ep1lTD'HLR9cFf" 49&4&1MBZ)a`C'#)k6P9KDf0FDRk3!++ZY-('[-,@e,qaV++ESDfZQhaG46e"1Li Z-bdQ,$Y$36Y#8PCBDiUMVl@dVV'fXUf`YEc0hYR&Y+LGK@426&0BA@9G3#XR*#% L,NCIF(aqJjbXRT+CRkM%i16Cdp2*Yl#cVU@HNi0aD'KK6Mij0c%e1M3e4%pACR* eGhk-R+Q`Ylh$c-['`,+ZYlbdV+qbTT4j9$p'6Ne,4N0)q05ml6&CVMDQl`,1 HMT+V`F'iZmhEf-ZiRib%J(9MA@PaC9!r063i-#8U3&CLERCcGB@8Q*'*NkLl`EZ fZ,5SSU'KUkqSST0lF'TG8dBk0cFj2N4$16%c294XHSH3!*DKTD'GRDHcXUqc`Fr 1`,@VRC'*J(&J99YK96id0cJf-Lie3NTBF)')P*Z@N!#-N!#KY,l#`Ebm`m1mXTZ (Ji5*Mi0S88-h,bi[-$9!46ml5'9fH(YkHBk[[E'UXlLbV+qeZ-25cE@RRj'&Hfj J88a14$Jl3d-l-bdT-e0dJS5-PC!!M+#iXk+PVDZbbYrGbE1JM)##LB*`Df*,3dK #05mZ+5Jf8'GVERb"HAq0Nk5rbX6"a-+jXEI'alQXSTQ4LiTmA83k0cJr5Nj$1$3 a0dPFDR0iHS+G[-@fTU5NR*DSb0E6e-ZcR*+1Jh0VCPpE9Np*4M`V)bNe2NaTKj' 'Ii1)ND'd[lqp[Er%dGR1[EHXQTHHR*!!HPj*16)j3d!f-c-c0d"3Af*TFh1!RDq h[lkXR+'c`FR2cX@qYUZNQik&FeT-68p26%8h+bFX0%"@DQa`IiU)M+1fXkURVVD i`Y(3`lL[S*bMS*!!J(&E4N*(5N8m-bSL+$T%5PaQA9aeNCbNVEHeU+Lf[,h"a,b [UUZUUU15H&p24$j#5dj%0c%U*bp!5djCEhq%MD#VTU'GQUDj`XV1aEffUkHUTTU 5K@G16P4346JZ+bFR-$8h3Ne4@'9iLjHGRjbHUlUq[mA$ZVHdUUQf[Db-FfGG88G '5d3j1$8`06e%5NY0@@q,RU+IRU#JS+Ud[FA'[lDdZm'lUCL)FfCPB9C-48%q0#X Y-M3m4%0+BAZ-NjHDQCfUVkklcp$"[VffZ-($ZU@4K(a`@dJr16Fh0$)e1MSi16Y "8fk'Q+5SU+LRVEHj[-E)bmr+bmQjUCZ&Fh&cDPa02c3a-$%e0MFj0ce-@@CjLC5 @NjZ[Z,5f[EqlZEUraX@jTT@+Ih9ZDPp+1cJf,bXa16Sd-MT%9@emJBUBSUU`XV@ r`lfhYX,1c-LpU*@+LB*Y@eG42bmX-$3c,bma-cP$8Q9eIiQ6PTHNYVqpYE1l`mR 1cFI"YD#1IRChEeP)2$)c-bma0$)b06K"8@*`I)1,Pk1[ZVkm[,r"`mR0cp(+XCZ APiPfD&j226-b-6)c-#iZ-$G(@Q4TGBD8R+@`ZEl!Zl5e[FVAeXQpYDUFLAKaD&K '1cJh0$%Z+b3N,cT(9epUIiD"MULf[m+l[F6"`F[3d-QmXkqNPSPjCNmq1M`m0c) [+#3N*Lp"6PPXHhq'P+1YY,Up[-$(cpA4b-M%YUQPRj*rCNp"163d06)Y+#JV,$! p6&KKD(Q4S+Lf[VHb[FM(ap$Bemh!ZEDZSBpjDPT(2d%p0M3c,5FQ,6a&5P4KEhk 2SV'fZX($[m(2hGh9d0$0a,ZaSj0qCP4+36Sl2cBR)5FY,6%q6&CKEAf6T+LZZm, !ap6BeGACeXc&`,ZjVT4pE9C"2Mdd,LiZ,#JQ,68k3%eEDRk4SDqeYER"aFM2f0l DdFh0b-#eTC&pE&a03$Nh-LdT*L8T-$8i2%96D(k4RkL`Yll#`XM8hGV6c-R+b,k [S)ekDPY24MXb,5NL(L-X-6%f2dC3BR@(QkbeYl["ap$6d-r3dY20aX+fSBjrD8p '58)c+LFS*b-N,$3f1d98CRU2SDHSX,l(bFc5fYh8bm[1bm@jSSGhF@K@36Bd-LS M)5BY-M3e1$p1CRU&N!#LYlkk[XV4e0E5dG24dY6)XCf8KQeC6NT(1LNN*5BS+#` a0Me(8PaXL+'XVE'pbY29dXh0dY68e0,,`Uf+EQCQ@dSq16BZ*#!M*#F[1$a!6@9 pL)U5Sl1raml9fYM4bFI,dGE4[+HCM(CH6dK!0LmX+LJS+LNS+6%q8@ChJj'GSUU f`XhCh021dYE6dG(+ZUQEM(jYA8`p-5FN+LiV+#JU,#mi6'"cKC+DTDqlb-r1cY, 8dpADfYA,ZUHAMB*cBP!r-#`Y+5NX+bNU,M3q6&eYISkFTE#qb0$6cF[1dGEIiYR +ZkZGMRpcCP9$0#`V,#dX*L3R+M"!89jZIiH2RUkpbY(5dFl0dp[IfY$(ZDQKQip pCNSh-bdQ*Li`+#-P+5ii4PCQFRq8UVLp`FA(aX,&e1$PjGM"XUbKNS9jEPY#-bm V+LSQ)L)L*M*!59&IERQ%QE2$bml+`X62fGlJi0V1`,#MQ)pqCNiq0LmX,#NL(Ki J*Ldk5PCGCR5*RV#p`XM4cXE,eGVFhGM)Z,@bSBajBdXl-bm`-LmP(KdH)5`p5%p FEAb,Qkbl`m2$aFlDi1(Jh-kqYl1XST@!CN`l06!Y+bBL)"iJ+$)l3dY6AA#*TEV "[m((bXR0fH,KfY,-aEUZT**e@NP#2$Ba-#XI&aBH+$!i4e4BBA5+S,+la-c*bGE HhGhDdp(,`F'mTipjA%3p1cJf-#BI(4`F*$!k2dPEDRQ4U+q[YX$'d0lPjZAGcm6 &aX'kV*L!C%p%1M%Y+5)H(b)P+M%e0Me-ARLBYF#lZX$#b0ALk16LiGR2bX5dRST dB&9-3cXa*4S9&aSJ+c3i1Me*ARD+RV,!aF2(e0lJhY[CeYECeXZkT)edAe"'3$` d+"dD'4NH*#S[0N*5BA5-SUqbYVr0hqRSj1(Bcmr8e-brVT4eAeG-2#mS*#!G(5% M*5BR+c9&BS5GU+faYm,+cpcVl16KiGhEemDYQ)PpF'493cBV(4-4&KdP+bST-$K %@R@+QDZma-R@iH,HfpRFiH2MhXqjSSYeC9a64cSX)"ND'KJG*#-P,cp-AA5'P+1 a[-[CiqMQhYM@f0cIfp,"Tj!!IQaB5N)h+5)I(4iK)4XC(bNh6@GlLCDLUlA"dGh LjZINiprGi0M&XD#4L)"[@NBb)a`D'4`I)b8M)LNf3e4TI*!!S+r#dYIBh0cAdpE Jl1lJc,HMNB"aCea*0b`N(4XH(KNA'b-Y1daBC(U-PUDmcYhQiYE6f0cJjHAIdX# XQ)GkE&P%0#dU*4mI(aN5&"mU08PKEh9qM+1lbG$Eiq(KiqARj0cBd,fYUD'*E&C $-bFJ)#3L(aiD'4`M-%"1B(@,RkqmbY,@e06EjZhbm1MFblQYT*1$H'0*1#`N)b! E'4F8&b-X-Me,9Q9kN!#T`Y$@eY28fq(Ql1cPiGE$YDZFLR"@4MX`+LFL'488&"B F)c!r5P9MGT+XZXM9e0(DiZAVlZVNfXr([+qNN!"c@dNk,bSP)4iC&439(#J`-ca 2CAkAUl[(c-h0dYrTlr2[j0M4c-#XQj'%DNmp0#XM(KS@%a3F*#NV,cY,@'k1V-, 2d-c-dYVMkHhYlqcHcX'dT)jaAP9-36BV(a83%4)@(LNb16j%6fQ+S,$!cYEEhYr IiH2PiYVDfp2#USabB9)X*L!A%!m8'b8V,MP+A(#&QDbla-[5eq$Ym1AGh0l IfmkmUCQ%DP4'1c)U)KS8&4NE("dK+MG$9@f#PUZh[FE3fH$NjqRQj12GeFl$VCD #EPa-2c8U(4BA&a-9(#8T+c*!8fKmMU@laXV9iH2IiHAMh0cRkYV$VjQ#DPG-3cB V*L3I'"-6&aXJ+cP'9@PrNCZPYXI6hqVYk1,IiZ6JfG6,Z+#)G'453$3V)aXA'4X B&4NL+6%p6fCmMTbUZFI9iHAPjZATkqAIh0R0ZU1,GQ993c3T)KdC'4NC'"NG*Li j5f4lLCDS[XV2eYcIiqISkHMRiY6#XD'1IQj@4$JV)amD&KFA&4JI*M%q59P[KCL SYmE2eH$Uk1ASkqIKfpA,ZkUAJ'TC5$8Q(a`F("N9&KNH)LSf4eTYK*QUYmE@fpI Cj[$ZlHhQhYA)Z+UDK@jD56JV*"mF'"8@'"NF*#dh4&GVJ*5PYFM5eYlNjH[Yk1M Ti0A1`+bBKA4F3c8[*KmF'4B@&48C)5`h4&4PHT'PZFM0e1$RkZcYl1VRh0,,`,+ LLQpA4$Sa*KX@'"S@%4)E*#S`28eLIT5MXVr0h1(IiqV`mHhPfY21`V+FJR&Q8MN U*"mE&!i3&KJF)LBY1NPHFSHL[-[3dpMJk1cVjqMVkq63[E+LL'jB58)h+4iA%3i 4%K-A(5Ff2N08FSbIXEr+fqEQjHVam1cTipV5bVkPLRCN8d%[*5%E&4)3%"-C)#B U-80FF)'AVm24epMKkqlZm2,VjHAHbl1JNS"S88%f,#%C&!m0%"8C(#-X08*5CS' DVEh,eH(XlZcZlHITlZVHclfRN!"iC&9&1#`I&K-4$`i1%KSM,$G%8@4mMk+ibpR Nkq[Ul[$VkHAKhpI$V*4pD&9"-LSM("B4$3i6&4JG*6"$9@9iM*kaaGAIjqrdmHM NjqVSiY+qVjZ"E&K#0#`M'aB2$a35$")G+$9!5epkMk#b`-cFk[,hmZVVm1lLeY( ,ZCU!EPa+1bXG&a89&"!0%"FE)bik6fCfKCU[`02Rl1ETpIMak1ARjGI$XD#2H9p )0bSL(4F4$Ji6&aF@(bip69aYK*kd`mh8i[,dlZlZl[(UhYE)XTq2H&j*1biN'a3 4%a)2$"!D*5mk4e9XL*UMYY$MkHRVpIM`l1[MhGI+ZD51H@C61bJI("N@%Jm1%"3 A(#Be4Pa`I)qV`-cAiZRYm22dp2,UhY2'Xk5@J@T415dS(4-5%K!2%"!A)5Fa39" QIC+T`-c9iHVZlZrbp[6Xj0E%Z+L4IQe92c8T'a85$`i2$a%@(bXh38PCGT1QYmh Ik1VUlI,cmI$Xj0I+`V1BI@P@3c%P)"dB%K%2#JdA)5FY1e*QGSLLZX[9h1AZm26 mqr$Sj0h2ZkLFMh9B3c8V)KX@%3d1%4-6'LJh2N49FBkMYmM5h1IZmrAcmIEdip( *aEQJK("I5MFT)4`9$3i5%!mB)5BV0NCBESDGYX[Chq6SkZrhqI(TjH2FaDkGLR" C56S[*amB%JX)$4)@'b)Y1dC8DB'DX,r-fH2XmrAbm1lTjZ(6aEUPLh4H5MX`+#! A%!i-$3m6'b3X08"4D)#AV-$2eplUpIRfmZhSjGr@cF#TMRTN6$dc+"i@%K%2$K! 8'"dR-d&6CRbAVER'eqETkI(lqZrSk1ADblbZQ(YM8N3e+#%E%`d-$a%8&amT-$a 1CAk6TVV'cGcZprEbmr6[jZ$Hdm#VPB&X9%)h,5!8%K34%")6&KdP-$j0B(b8Skr !e1,VmIAhpqrSk1AGd-+bQRpV@8Bd+#!E&3m1%438&"FI+MP0CRf2S,6$bG2Nm[E cmrAdkYlCd,bSQ)PfA8Jm,am8%"!4%K)9'K`I+$9&@h+,S+qqdYrMjZhbmZrYlHV Kdm5YP)&aB&"",L!D&!i-%")6&4NI+6G'9QZ%QUc!dq(Rl2$bm1hZmI,Tf-DaR)K aAP&"-5FH&4!2%"!3%KJK+cK*@@TrP+@hcH(Zmr2bmI([l1IPfmLdTC4pCe-q,53 H'4B9&"%4%a8F*c0$9fYqP+QpcpVJjqrfp[2dp2$RfFLhTC*qDeK&05JG&a-4%4) 4%43D*64%8f0hM+#fc0rTl1cXmr[jm1cUhXUiUjU%EeT%-b8G'aN8$``0%"-B*$) q6@"bKCkhb0AJkI(blr2hpHrQfFr%XCZ)FeT$-bJI&a8A&K%1$!iA*#mj4ejeLCf caY2FiqEXp[clq22SfXr"VjZ*Gf001LXL("F4$!N-%43B)bih4&9TIjQdbYIIj1V Zm[6eprAVhY,(Yk'1H9j(1c)S(KB6%!d,$4)C)bde3P9RI*Lb`p,JkHcXmIIemZl Uj0R,ZUH5H9p,1LiQ)4mD%3`-$!d5(5Nh4&*SJjQTZmh@fH2br[rlqI2Pemh&[Dq AI@YA2bmQ("84$a%4$a-D(L3Z1NYPIjLb`XRAiq,Nl[AjqI6VipV+YkHAI@&54cJ V)a`8$JX-$K%A(LB`2%KEH*+RZXI6hHEZmr6cmr$QiGl4`+qDJ'K84$BY+#%B%!i 1$3m8'b3Z2%pJFibMXX,6hHIcq2RkpqrNhp[3`lHPLfpA46JX)K`A&434$K)@'4i S0N9EH*+QYF64fH$Rl[6kqrA`kq$6`kkCKA4N8N!c+5%C$`S-$a)A(53X0N09E)1 FYFM5fZIcp[$YlZlYkH6EblDJL'pC5%!i,"m@%3m1$!X3&b!X1849EiD9TEE-i1h dpI2cm1[QiprCdm1QM(KK66d`*amE'"84%"%3%4NM-N9CFBHATVM(dYlUm[IjpI$ Xjpr8alDLNB&Z@%3e*K`B%`m3%4)8&KXN-$e2C(Z@UlR+fq(Mkr,al[$bl1AGcVQ MMheX@NSl,5)D&K)2$`m2&"`Q-6e3D(U*RE,#eZMZlr([l[$XjZ$Dd-+[QB9cA8B e,#-E'4N@%!m5%aBI,6j4C(H-SE2"c0IPl[,bmHrVkHIEb,HYSBejC8`j-#FF&a8 @'"F3$4BL,6T+AA5+RV,%dGVJjHVZpIVflHAFcEZUR)YjD&C$-LBH'KB3$!m5&4` P,MP%8fL!NkV(fGcKkHhZkqIUlZMHeFLiSielCNir0LdP)"XA%`m,$aJL,6K%9@T rNkQpbpEMk1RXm22cl12FdF+hV*ClD&C$05dN(4NA%`m0%"FJ+cK$6f0lNDHpcYM Ei1[am[2bkZ$CdFHkUTD#EPK'0bdS)KS8%3i2&"NK+c-q69jdN!#S[Fr9f1(XmI, Zk1ERiYI,[+kGJfG54$Xe,53F&a%0$!i9(bXf3%YHH*!!SDqqdH(Skr$epZlNfp2 0c-QkRS"VA%Xj,LNN(aS8$a!8'4dL+cT2C(H-Rl,%cG(Gl[MjpZlPhGVAc,qdTj* h@dBk05mM'489&K88&"NL,$P(@AD9U,@m`XlJkr(fpHrXkGh6cF1bS)YdC9G'1#i M'a84%4)8'"iL+69'@h1(PkLkbpMKlIAhp1cMhGcFeFQjSielDP9%15dM'aB8&KJ A&KJG*6*%@@k&QUUhapAHk1ramHcQjZMJdF5fTj*kCeY225`M(aX9%a39%a8G+$0 !9R1*PD#``0$Hk2$emH[Ukq6BcmHfRiq%H'G83#iK'"8@'"JC'aXE)Lp#9QChMU@ haG,Hk1hYkqMNjHMPf-5bTCQ(FPe036BS'aBA'4SB%a)B*$0"6f0lND+`[F[Hkqh Sjql[kZAJeXLeSC1)HQTC4M%L(4mI'"-6&4JG*6!r8@0cJC'U`pEIi1,UlHEPk16 GemLdT*H0JQT22MBX)adD'4J9&4BD*$0"69PTJCb``0$GjZRPiHAUlHlPdF+lVjk ,H@KB5$JY*5%G'aJ4$"-I+6%p5PPXISkM[Y,Fi12Pk1hZkH6EdXQpV*f5KR*F4M8 Y+#)I("F8&aJF*c!k59GLGjHba-h8h0rKk1cXlHVJeXUkUk1AK@pF6$id,#3J'aB 8&4FH+6-k4&&MHC!!TVh2f0cEhHMcp1hRiGA([E5UQS9bB%`p05mT)KN6%a3A(bJ a18*2Ah1,TEc)cGIMjqR[m1VJeFr0a,Q`SBTbA%Xr0LmU*KmB&4BA'b)X0N"0Ah@ +SEI"aXh@jI(clqcNeXh*`VbcRiakB%T#2$)T)a`A&KB@'b3X-MT*AA''RV1paY$ EjH[Ym1hLep$+b-+`Rj&jB&0*26-Y*KdA%a3D(b)S-ce'9Qq(QDLfa-rDjHcam1E EeY(-bF@kTSpkCeC)2cJ[*"dD'"SF("mR,69&@h1)Q+@c[mM9iqhdmZMKfY,2blq cTT5!F'"236JX)KdE'KXI)#!N+M4$9'Z%QD@`[-M9iZRYlHIKhGM4bm1eSj!!IR* V@NBj,b-F'KSF(b%L*#Ja3&*UJC!!Rl#laYAKjHVXjq(FeGIBa+kLNi4kE&T-2Lm N(KSC(5%L)L%P-d45BA1*S+feaYVNkHMMi1$Jhpc4`E@SPSCiDf"42biP)4dI)4d D(53U-Me0C(U*Nk+hbpMGiqMPj1AKfpM8blbQNSQ#GfC226-X*5!H(4mK(b!S-N& 6Afb!Nk5ibp6EiqEPj1,JiGr9a,1RRj1$FQ*33cFT)#!L)KmE(#)T-6j0@farND+ daYEKjGrEhqITj0[3aVfZQBZ&HQPA4$3Y+58K(4`F(5)U-d"1@@4eKjbeb0AGhG[ NjprDhYh9bEQTT*Q&G'443MF[+bJM)"iE'KiR-d&-9Q4bKCk`[FrCfGhQjH$JhYE 1aEUZSjL+HfK33$Nb+bFP)KmF'L!U-ca)9Q4aK*kb[XV9fYcFhqEShpA2`l@`VCq +GfKC56Sa,b`S)"SE(b%S06j#6&jcKCHT[Fh4dYEGiqENhG2,alqcTTb5JfT64N% k-L`Q)L!H(L-U-$Y+9&TRJ*b`ZX21eYhJi1AShFr,albdXDD4HfKD68)i-LmX*4m H)#-U-cT"5PYeLT5KXm(*dGMHjZVPh0,(`X'pXU+5KA4H68-m0LmT*#)L*#FU,68 q5PYZJCDUYVh#bYAIjZRRh0(,aEkjVk+8K'pI9%P!0bdS*5)K*5SX-$8l4PCTJ*H QVlR'cpAEi1,Kh0I2aX'pXU'3!)"bCPa02cF`*b-N*53Q,M3f1%*AE(f0Rl#k`Xc @h0rJhYM4bmV+`l'INiCdC9T24MXa+b8K*LXV+LSb2NP9DAk1RDZf`-[6h12Mfp6 8e-l'Zl#MP)4hEQ*95MXX*LBS+5XX+c!e1%*8D(b+QDQh`mrBfpI9fG[Ad-h1aV+ IMi&hF'CA56`d,LJN*#JV,5ie3%P4Ah+%NU#ebG(6fYrAcXl3dpM4`VHTNi*iE'& A6%)h,LdX+58L*#Xe2dYECh&pLTLV[-cEj0r8dpE3bXR([EDZRSk"FPp346Xc-$% a-#XQ*LNZ0N0@Ch@#MCUY[F60epI@f0RBe-r*`,#LQT1(GfTB4M`f-LiZ,b`R*bX `1NK6A@amM*fa[mI0dG$3epVBep6(ZV1RR*@'G'TH6$ij06-a,#JR+5ie2NC2@fT fKCU[[XV5dY(8f0I@e-l(`EQZSTH-IQP64N%q163c-#XS*bNb28C0@QelL*kb[-( 'bp$9ep[IhG,$YUqXTTZ1I@YF6N!k1$8a,5NU,M!d280)8f"cMD1[ZX6(a-M5fGR Bep(([lHVSCU1H@CD8dY$1M-[+bSU+c!h280*8f"[KTkZYEc'c-h4epRBdmR!Zlb jV*b1HQ0@8%Y$26Sd,#FT,M%d18"*9Q4eL*UQVlV"a-hCiGr9bXE#ZlHfVk+4I@Y I9%P!2$Fb-M%[-$)h1MY"6Q&iMTfTXlLl`FV3eYVEemc![m#iUCL*I("N@e90363 Z,#SU-6Sp1Ma'8PeVJ*DSXEDrcG6@ep,+amE*cFDjX+'+GfPI@eC,3M`b,$!`,#m h1cj$6f*jL)kATV5la06Ef0A4b,qq`mE"Xjq-IR9U@8p+36Se-#md0cFd-64"8&p dLT5ETl#h`Fc4dp65cmR(b-+dU*f3!(pbEfPD5Mme,5da-c8f0$Bm3dYBEB#-Pk@ c`-V3dmr*aXE*cmr)[l'HLheeEQ4E6d)k068d-c)a-$-l490PFRZ&MjQSZFR@ep, ,b-M(aF6$[,'NPiYqEf*95$ik2$dj0MFf,b`c3&"MGB5,MjUTYX$&bp2Adml-bmL rX+@KQT'0JQY@5Mme-63k2Mdj0$-h2NK@CA1(RUZ[ZF2&aF2#aXrAf-r%Z+QCN!# ,JhY`BP4'1MFj0c8c-M-j3%4-@@C[HSQCUlh+c-I$`X2,dFh*`lZbTjL2L(eV@8Y &4%%m1MJa,5md1804A'0ZIBLAU,E!aFE(bXc0cFc&[V@UT+5FMhaS@e&&3$mm1MX j0$-f18*-8PPSIC'KUl5l[lkp`X[2d020[l+YUU'8KhYaCPK-4d-q0c-a-cBl3NK +6PTSFi'AV,V"a-#k[m[0bmM"[X#kUjkBMAYUAPK568P%1c3a-M8i2NK39&YSGS5 8T,'i[-,(bFV+bFE!YV5fXDULNRpZ@e&5680!3cdc-cFl26p%6eYPH)qJU+Q[YlQ pbG$5cmHqZVDaUkLJNB&aC&a@6N9!1M3h2$Xl3%4(6&9MGSHATl'`Xlh%aXV,b-@ rZVLfY+bGM)"bBeaD88G"2$Nh0$P!3%"%5e9MGiUBSD@UXl[#b-[1cF1jZEQcX+b JMS&fD@&E88Fr1cXj18"#3$p#4e*PHSQAS+DYX,@ramc1bF,![ELdVD@FN!#&I(* RA94)16%e2d0$38༃Afq#PU@XVDqkaF6!`F,$a-1rZl+PQ)YmFh0bCP9*2cS k1$Fp3N*$4NY4B(@%LT+KX,V!`m$#b-DmZEfr[VLTQ)b"IAKUA9C13cdk1$a"36p !3NKCD("kL*5KVE+mb-M$`,kp[Efq[,#MRC@'HR0XCea*26Sl2d*"2Mj"48Y8Afe qLjDIU,6$b-6![EQp`m+q[EDSQSq&I(CaC9C,4N%q2Mik16a"4djACR9jI)LFV,D paXV([VLm`VqiYE+UR*+2Kh4PAeP13cj!3d%m1c`q3NaFDh"dJ)fATEE!aXR%[Vf mZ,UpYkfSTTU)IRPZB&&*5%C%4%!l1MXq48eABQpkJBQAU,Lr`,qr`FE$[,ZkXl# UR*12L(e[Ae&-5dP%2MXp2M`p5&4CB'TeIiZATV5q`X,$aF+k[-1mVDHQSTf@LRa ZB&G24N0(4d0!1cY#4NT@BQGaJiqCTV#j`,fi[FM,aEbfVk5ISk1@LS*eBe9-5dT &3$mr2Mp#48T5A'KaHSLEV,1bXlV!`X,%aVqdXDfIPjfINS"bC9a96dK#3%!p2%* '58p9@PpQG)UHUUqdZEbq`-(#[lLeX+LSUU5DM(KUCPp@8e403MXl26a"58p9@f" ZJ)b5R+QbYV["a-A*aEU`UD@SUU+CNB9eDQ"A8Ne'3d!p2%"(69"289jZHS@6TE+ bVlM$aFE)`EL[UDbYTU#FNB*cD@*F@%p'36Xk3dY*5%a499KKH*!!QU+XXV+f[X6 %[VUlZE'UUUZMP)CmG@pUCep45%)l1$P"6&*46e0GCh@%N!#ESkQf`F(#b-DkXDZ RV,+YSTU3!)&cE@TN@%e)3M`m38K,4N0-9&YRH)L9QCZRXlDmb-V#ZE1`VUUQTk@ BKi#!HQeNAP*$1MY!4NY-5dY*5eGRGB'1Qk+RVVDr`lqlZ,1ZX,+bV*f-Ki4lGAC bCP9%16Np3NK,6%a-89aREhZ(MjLQY-(,bEqhX+b`YE@cVU5@L(pkHACXB9C,3cp !3N9'4%9,8Pp[H(b!L*5LVlc*cX5jYE'XV+q[Uk5AMBH#IA9TAe4(3dC'4NK'38* (8Q&VFRq(KBkJVV[*bF'lYV+cY+qTT*fCNSH#K)&[@8T)5NC&58P%38*(8PjSGB# !JSqKXm(%`VqlYE'dYDqXUCZ-MC12K(CTAP9-4N9'5%4!380)9'4XEh*iK*DLVEh )aVkhXlDkYUqQRTZDP*12JhKX@P&25NT15d%p2d&*9f"QF(GkJ)kLYEr![EHf[X# jXDfSS*D6Q*U5KhYU@P&388j*4%*#3N"&9'*SDQecK*UQV,DmZlZq[,c![E#LQ*5 @QCZALhj[AP0368Y,48%46@9CFC@TdKC5NZ,UdY,@i[X(![+qLQTDAQCQ6M(j VB9eA8de#28"!3%YB@PCBA'*[KCUTXV@dZEUfZX6#YUbNRCbFQjZ6Jh9XD'4E99* (2$Jk38T39PYF@Q*bJC!!T,+cVl#i`FA#[E@TRTQCSD+DNSYjD'0NC&a13$`m2N0 ,89999PTKF)DCSD5UXEDl`-A&[E'QRTbISU+GN!#!HAC`C9a@8%3j1N&)6e048P0 6A(D,P*kTVDfaZm6'`VQ`UD5ISkLNPSU"HA4[EQjK5MXj16j+8P*58%j@BR#$Njb LTkfi`XE)`lDUSk+QUkZNQBTpGR4eG@aE5Mmk1N&*68p16P*CCA1#NCHBRl#raXR *`E@TSU1QUDQQR)k"H(9fF@4A683p2dG-6%P&48PBEAU$MC59QULi`m[-`E5XTD' RVkUEN!#0LB&mHR9T9N3p2N"&69&,4%*+@'GdJSU0N!#FX,r(b-+mYUbSU+LXVD+ 8Khk!KB"aC9C'3%"$5%Y)4N9#4PCYHAk%KSfFVV[)cmHjXDURUDfZUD#4L)Z*IRP dCe9'3N9+6NT%26Sr6&eYGhk%KBUAU,V(bmLrYl1cXUUKRCbAMik8PBCY@8a$3%C 28dj(3d%q3P"MG(k!Jj+NXEZq[EZhYVQiYVLbSSq(Lj1@NSGiCP4*38"'5dT*4Mm r6PpMBfYeJ*+SZ-(%[l@ZXE@j[EZ`STD4Miq1LS0jDeP058Y-4$Xk2N**8PeNC@G [HBHFYXE'[lHcYVLfXV#VSjbBPjQ9Mi0Z@e058P&15%!l1$P%8PaJC@PVHC'LX,Q jZ,ZkZ,Zr[E@QPT!!PCfLR)jqEf4D8Ne16%Br2$a#5e*A@9KGE(q5T,'j[,UcX,I #`lQ`UU'ER*bDQC!!I@aPBPa@9%`r1$Fl3dY4@&eHB'4bLU1aZ,UiYlh![EbkVk+ ERDHUSjU1H@KLAepJ@8Y!1cFf2dY589*DBQerNCZMVV1bY,r*bm5fTTbDRk1QTjk 0I(*UB9TC98Nl1$j#4NY06Nj29fCrPU1SV+qZXEl'aEqjXUDFRUHTSC5(IAGaDf9 H8$mh16Sq59*56%G*9fTlM*bPUl#cZF,&[lLaTk@SV+fSRjH(GR"`F@aK8N8p16T !48G(58j@A@KmN!#APjbTYm('bFR"X++LT++QV+UFLRjmGfaJ9dp)2cY$5dT(4$m r5PadL)f5RU+MVEV$bmQpYDkMTV#VRjZAMiH"I(GZ@dBl2$j!5P013d&&5P4SIBZ 6QTqSYm6&[lfiX+fXVDq[UU#2JS'%IA4YB%e"2d&$4%9#384*89eZI)+&MTfUY-, 1bVbcVkQPUDfYUTk5MSb&H@pQ@%P%48G*5%C#1cJr6@&dIAq(NCQNXll"`F#kXDf [XDbMRC@3!)q2MBGpD99(2MT!4da04Mip49&BB@jjKT5KVlc#`,QaUUbcZ,LaUD5 EM)5(LS9lEf&3480%3Mik2%C,6&*HD'eZFi@HXEr,blfdX+ZRUDkbXDZJPC+3!)C lF'0C9PG35%G$1cFi28GAC@Y[GAZ$NU@f`F2![VUcVl+aUU'FQjkIQSq"Ff9@6dj -6%Y(3M`k2%96A'*TFAk3!*fQXVkqZ,1cZEqlXUbPQC5ERCD4LRTTB&C+5%P&36i q3%908eGFBfYeK*ba[F#jXlHjY,1cVDLSTU5KQj@4JfjLA&TG@%T$3cdh1%"*8&K MD@YfM*bMUl1h[F#pZlfjVD'DR+'PTU'6J(0XB9C26Np+3Mml2%9,5Ne9BA'%Mj5 IVV@dYEQp[m#kVk@IRTqIRTbBLRCXCee56%K!28"$48G'59"A@@&hMTfTXVDhY,1 k[lL`XE'QSD5RT*Q(I(TaC@*L@%Fm1cXj2NK,6&"6@fThJC!!SkZ[YVUm`-'jXDb NSDUXT+#FNSClF'PM@9",3cXk389&4%9+89PQGSD9Rk@ZZ,Ui[,kiXkqXV+HLTkL DLiCrFfjVAe0)2$Np2d&%48P-699PFhf1R+@YYE[!`,ZfXDZXVDQUVkLEMi*jGR9 YBP4)3Mmk1Mj"4%G*8&YRFhZ%NTqVZ-,%`EkkVU#GUE5cVDHKPiPqGQYKA&T85$i p3d3m0MY&6eYTGi1*NCULU,6%bF+jXUfZVD1LUUQHPj''HR9`Ada%4%C&3cmm3%9 %4e4MFRk)MCDMXm$$ZlLlZ,#YUkUYV+DLQBf)KhYS@P0-5%-r389!1ce$6&9KF(U !LTZSVlM!a-1jVUbYVl'`V+HLR*1*Ih0VBP91584%48%l16Nq5ePNEhU%Lj+HV,H r`lkiYV@bXE#TSU'KRjU3!)CrFPa058T)3d&$36`j28P@A@4aISL5Sl@kYV@l[VL `Vl+bVD@LSCb@Nik!E&jA6dG%3d0#3$`l2d90@fPZGiQESkLa[,qiXE5jYV5aUkH NSU+GNS9mFfC@68a058!k1$Jm3dG0@'*[ISD-QUUdZ,LfZ,Zp[,5RSDDSSCqLRSp qF@4C88P&4%0!2Mp!26e+@f&NFSDBT+Z[XV5fZ,HfYlLeVkDJSD5HPSq#G'YL98a &3%%r16Nr4da,6&CMEi'@SkUbYE@eXl@kZVDaV+UXUk+BNSZ$H@YJ@e9,36Nf16j "3dG-6eKSFRH*SDf[XVDiZVbjY,'`VUQTUkDKQSk#GfYMA94)3$dl2%"!2d*&5eG JEB59R+@XV,'jZEHkZlLbV+USTD@KPSk(IA4VANp$2MXl2N&!3NC&5&&GDhk1QU5 XXEDjYlDjYV5dXDqXUDDKQ)U"IhPVA9*04MSd1$e!3d9'5e&GERU$NCqUXlQl[Eb jY,#XU+kiYkZLR*+%G@aYCeP358!m1cXm2$Y"6&PNERZ'MC@IUE1raX5jXl@cV+D QVV5YRj1+Ih9XBPC048&&3cSj3%&!4NpEERf#LCHMUV+l[lbiYV@aVUk`XUfJQ*D 2K(Y[BeY24%%q16e$3$Y!59*GCfpmLT5HV,Hp[m#kX+QVX,5eY+fQRj@,JhGXC&j 85N4"2Mil1$Sr49"HDR9rK)ZDTkkh`-+qYkq[XDkYVUURSTL4M)&bC&C-5%9$4%3 q16Nl3NpECR0pK)ZATE+jZEUmZE@cXl'ZUkDMSCb@NBGdB9905%4"3NG&2$Sp38G 6BQefK*1HTUbcZ,HeXl1iZE@bVD5IRTkENB&fF9p+4NK'48-p16Sq48j@A'CfK)k 9RUbk[E@[XVbrYl#ZU+HQSCZCPBarDe9-68Y(4$mq2ciq3NT5A@YbGB5EV,+aX,1 iZE@bY,HdUU5MSU'KPS0dD9pE9%P$4%-r1MFm4e&A@&aUISZ9SkQ[ZE@ZY,UjYlD [TD5SU+DJNiClEf&98&*346`i0ce(58G-@@9YG)#9TDQXVl#cZEfmYkkRTkQQSD' LRBplD'"KA8j$3N%q3dC#48e48ePMG)LBSUHVVUq[XlDfYV1YUkHJTUbJMS4pG@j P@P424$dq3%9+6&"68eGNFi@5QU'VVkkaXl5hY+UQU+DRVkbEMB9lFfpVBeG04N* "384+8&"-89eVGi#,Q+#KT+beYlDhXkLLT+LUUD1GPSYrGh"RB&Y546p$6&"15NY 399TLFiD2NTZLSUD`YlLbU+5SUDDPTU@GNSGrHAGbC94+58T*5%Y48Np08&PQGB' *N!#8QDDaXDfYVkfPS+@VVUQHPC'*IhamFf4E98a'5%j588e+6ePKD(4qJB@3!*Z LUDqfYkbIRD+PU+UQS*U4LB4pH(0TA9*-6&*58%p06%pAB'YeIB'%LT5JUl1dVkL MSk1KT+LQRjQ9MSH"Hh0R@P0499G889&368pABQadHS#(Lj1HTkfYUDHRTD+PU+@ JQT12MSk+Ih*SAP959&CA9e436e0CB'aeGRD!MjLGT+QVUD+ISkDQTU1HQC54NSq 'IA9VB&P@@9YC99*38eKHBQG[GATrKT+JTkHNSk'JSU@QT*qEQCH5MSf-JR4RB&e GA&TD@&069PGEBfY`FhKlKjHGRU'LSU#JT+DPSjkANT'6PC++IhGZCPpE@eaE@PK @9ejNCQ4PEAGrLC@HSU'FQCbHS+@SSTZAPTD6Mib)JAP`D@CPB9aB9PCCA@"MCQT XE'pjL*5ERTqFQTfJRjfGRTbDQ*@9PBq$HR4`EQeUC@"F@9GBA@&QDQYVER4mKSf 4PCUHS*qHRk'HPT'8PjLAPBq(IRGaE@PSCf4JA9aHB@0MC'CVF(CqKif4PTD8Pjk KSCqEPj@6NT19P)k'J(PdFR"UCQ*HAQ&MBf9QCQGTE(0rL)f2NC1@QCZER*bCPC5 9PCD9NBU$IATjGh*XCf0KB@&LC@KRCQKXF(GqJSH-MSq6QCbFQjU@NT!!NT5@P*! !M)D"I(KeFfjSC@4NC@KSCQGRD'T`HB#%KSQ0MT'9Q*ZEQ*55Nj15Nj+0L)@$J(e jG'eTCQ9PCfTVDQPSD@ebGhZ"KBL,MT1@PTD@P*'2NT@9Nj!!M)L%J(jpHhKbE'P SD'PVE'TTDfe[FRKpIi#$L)f6PCD9P*'2MT!!NC'5NBf)Ji'"IRTfFQjYE'aYEQa UDQYYFRCkIAk!JiD+MT'8P*+3!)q3!)q2Mif,LBL(KB*qI(PbE@aYEh"`EfpZE@j bGAGkIS+%KiZ2N!#2MBf1MSk2NC!!MBU(KB1$JS&pH(9cF'p[F("`EfpaFh4hHRP kIS+'LSf1Mik-LiZ0MBb0MBU(KiD$JAppHACdFh0cFh&aFA&bG(CiHRYpIi#$KiU ,Lib-LiZ-LiU*L)H(KiD&JS"pHAGeGA9eGACdFh0dGACiHRYpIi'%KSL)L)L*LBZ ,LiQ)KiD&K)5$Ji&qHhPiGhCfGR9fGRChGhPkHRYmIB#%KSH(L)H(KiH(L)H(KS@ &K)5$JAppI(YlHRPjH(KhGhGiHRYlHhapIi#"Ji5&KBD'KSD'KB@%Ji5%K)1#JB" qIAamI(YlHhTkHRTkHRYmIAeqIi#"JS+#Ji1$K)5%Ji1$JS+#JS+"JB"rIRjpIAe mI(amIAepIAepIAjqIi#!JB'"JB'"JB'"JB'"JB'"JB#!J(prIhprIhprIhprIhp rIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!,d!!!3! "!!8!!!#J!!'!83!!!!!!&!!!!!!!!#m@9Zk,S`!!,a3!!#m9!$b!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J(prIhq!J)#!J)#!J)#!J)#!J)#!J)"rIhp rIhprIhprIhprIhprIhprIi#!J)#!J(prIi##JS&qHRf!JB&pJ)D$IRPdGAPkHAb %L)&fEh1!KB#!M*QJR)PeER*dFR4hK)TlHhpqJ(KdIT!!Rjk6JfeXGfaNERU#J(4 XCf9UC'b2S+HSMB')MSekI*HMXVDJQ)jlHhk$PDZcSSb#GfPRCQGqN!#,M)GiE'C dI)1HTT4rHRpbE(0cKD'MQjQ(GAk!Gi5CU++&F'CJBP*(@QCVHRGQ@946@fjbE@K PAe4HB8!m@'9VF@eSD'p`F)16NBL!KBGqIA4XG(q"HR&ZEQpfJ(q0QS&fIR9iIhC mMU'[U*H+NU#JUV+VY,#CSE#HLiL(ND'IJf&99&KRFhf)KRjZ8$Xi28eHEi18PRe NCh+)RkHia,fQM(jaFB'2R+qcT*&e@P4RE@TrNj+%FQ&-3%01D)@9PSKfD@TlMU# bbY1kSC'$Hhk0SDfaXCq!DQYcER&jI)*iANe&1$%j9)#CPik!I)++RVE+fH(C[jf 2N!#-M*@TZVQaQ(C[F@GKER4iJAPR8N!q1$eJHi4qC9025P"IEAQ&N!#8Mi0ZA9T THRk"J'C05da2@'&LChCS56Nc-M!lA(*kH@PRE'4NFB#(M*+%FQYMDRL&QUUSRT1 0KAYfGAD"QU+2G@CHA&e@9faiE&Y699TJDAH4UUqEJhGeJ)f+Mk#SSj*pEQ4MCfY rP*ZCKQjKCh9fIjDIRjf5KS"qJBbKVkqJJh0pLT5FV-("Zl1FMSGqI)QIV+bTPRC PCQplLj1)Hh"MA&aICAZHVUqeTSZ#JS5(NkHLNB9pHA*aGi@NYDZ9F94+6&pcHi1 (L(aVD@TVFAH%NBpqBP&39QGqNTkNSCQ0JACeJC'Zc-kiQATPBhQ3!*fTS)PjBdT !5PT[Mk@HMATQA&jSG(k)LS0lEf"45P0ZLjbHNhpI4d4*9fq%MC'0HfaZE9jNJBq 1Mi0VDRQ#N!#HU,'iYU#(HA"XHTHQTU@DKRTeG(*YER5"KQpJC'0FCAf,S,bTKB1 #H(GhEfT`E9P18Ne+BS1+JRGKAh4kEfKYFA1)P)&bFh4aFhq&IR0M@QGjIAb#KBH &HA0pK)5)QUb`U*H0P+QcRSb5PC1DS*k@MApjMUHTRC!!Lj!!RDQQRUUdTCD+H'Y M98eFEQeL@PCDF)*lHSU1KiH+MC!!M)kBVF#hTCqALiL1N!#@U+qMQjD&F@"-49T UBeTMD@*[JRTpM)b+NjZ5I@jG9'Q(SVUhQAYfIATiIS##LiTkEQGE9&TLC@KVC'* bGfYTEh0pMBPZBfefGh*bH)+*I@jcI(b#M*+DS*H*IRC[Eh9iGR*U@8e38e9PF(D ,PBKmGh0fIifDTUkRQC!!LAq#Q++LT**aAeY348Y26P464Mp$46Xq9@*[J(YVCQY `GAeqIRe`C@G`HAZ"PDDYUj4eDQCJCh"bFfjTD'jdFA1$NjbEP)PiEfGLG*@STUQ [Rj@@Mif4RVI$Yk56L)@0Rl'bT**rGR0UE(Z(NTfLR)YkE@Z!TlZ`STL(IS#'M*Q [ZVbpXCCkD'9`KTkMPi*cD@*IBA#%NjQ@Mi0eDfPiPDQbXk@8L)')Q*qKUE5hXCk $EQ9XGhf+MB"cCf*ND(+"M*'1JQjPC'b'QCUBNBL#JiL4T+kQSk5IQ*+,KBb@QC+ "EPeAB'jlKSb(Hh0Q8dp26PPVGh0L99CHB@9ZIj16K(9F4NY99&aZH(Y[984"5&Y XFhZ"JhpfEfCJ@PpqQCQ#D9C2D(ahHi1#H'jcGQYNB@0aH@pA4%0'6&0BAfPYCPe CA@9UF(0eGfT34P4VJj5AN!#-L(acF@jRDAL!IAGS9%T5B'ajJATXBQ&RFi1'L*1 FQSk!G@eVF)5HUU@GR*bFSkbRUEHbRiYiCQ"UFRH0STU*JhppJib3!*@QXUD2I@Y LFAf'QUDDJA9`D'CSFBUJT+#CN!"qC9KMJ++QMi@0MAq"MTUfb,HXVUHGLh0cMD5 TUDqiZ+LHRU@eZ+QJSkDLPSfAUkDANSb8RCUGT,E)`lblYD10LSkKZE+NSjqBN!# +KBH8Piq"FQeJ5d0$@A0XAeYD9d8a0&&`J)q4HQ"126%qBR9eIB4rH("M@QCkL*@ 4FeP168j3@'KaFh*Q9%T08&CVKU'TNA9UFhpeFB+9R*'!GA*XCh5*R+kQKA&cFQK XJ*HUUCH*JA9R@epeQEl%TReQAP9CFiqJQiQ%KApbBQ9qRD50F&eD9%P@DAkFQB" lIR9TC@f"QU@9I(4lGh*rL*'GPiGkI(efHB+1QC!!E8-[,MC,BA&kIAGQ@Np$8@b "PTqIQ(YB-LC(GC'AMi9rH&j'8h50P*@6H%mf-6eCITHHSU5CKA0dKjkjb-DlU)9 H@S@[ZELhTj+#DeYED)+IXlblRh&58'Z,QCbKUkQ1Efk&R,(#bX[)Vi"HBAZAVEL dU*Q)H(L%L*5XVTQ"B8Bl3eY[IBD'K(CI@QGkLjZ``EUJL(TjN!#`bGA1ZjKdDhQ 1QjD1NTQ)B$`L+6j-B'aYD&!k-MY8C'f"Q*b*GQ4+4&4UKk'QNA*UGi50N!#3!*Q PRi4U@8p,8QQ"MSf!GA&hHh4aFS'3!)k)KSZ6NBkLcH$#Nh4fMTH1KAq'Li&[D(C jDQYZDQT[EfPbIAaqJhaVEAKYEAejEA@,MSZBMS5MZlQaTjk@NBTlGAPlFh&hE&P 9C)+8Niq)JAejIB+(ND#UT*bIS++PRjqTYVUZQS"XFAefEhZ)J@aE5ca$@h5%KS0 dAP96AA"lIAabA%3k0M9-E)QLVl'MM(abGB+-NBf,M(aT@%P8FTDdVj4pE'&FDAk *PU#8Ji+-JfpcJCHbXjq2J(4eIBD8RjZ9PBakE'YdKkQkVTU*K(P`L+1bZkQ*G'T G8Q"cJD'dUjqCMS11S*kCPB&VC'*94%YPJTZ9IR&UC9pLITbKPSYkDfPSC'0bMjq GQ)PdEh*iKSq,L)GiCf"KD'GSG)'(Hf**3PCZKTbKQiYa@%K%5e4NHC@[XTZ'Kj@ LVV1SR*U6JhCeH(9lM*HFM@T9@QeeG)19P)Z"JT1@I9P-C(b$Gf&GE(PiEA@0PC' *JB1)IfPMFSD9KQPVK*U@L*LbZkkCQ*kENAeeLk@`U*LGY,Z`STLEQRpcJSq0Ih* eKT!!M)4jHSD,NTbMUU#+LCQFNB4jGi12LS+"JiD%JB1,PBjqHRepGfTSGS'%Hh9 `B@*[HSb8NiYlF@eL88G0BAL(MB9X@9j[HhK`F'CE@dp&89eKBPeQH'j858K9E(b "Ji0kE@jfG@p[GAb+N!"qCeP@C(*dGB+0KB*rDQk*NC'ETULJQCHHTUHXYF'rTjZ GPSb-M)U6RT4qGRk*NCD5NC@+GQeVEhU+P*!!Li4mHh4aKC!!ND#URj!!MSKpISH AVEQ[RT@+IhTmJ)@,M)4fE(*YA9KIFi&hE@GIA&TNIBD(MBGmGA4ZAf"fMTD5MSQ 0NBq@QT@*HR4SAfCPDAL)MRjTB&GA@fU+RCL+K)5%MC15RDkcUD'BL(GRBh'+Q)" NA9PFDQaUGSH1MB&eI)*[CRH3!*b8Ki+#LT52JAq&LC5DQk#GNC@XYDD8LAPTC'a YCh4jEA9iC9YKAeYZJACPBQCMCRL%Ki@!JBL-LiL$HS5GSjL$E'4H9epQB'4VB&4 96%0-8%P3CfpPAPj@8&aN@9T[J*'EPj+1LBZGVDHEQT!!IhYqHA&hKT+DRjD!G@j RG)@%IhppHAPhHS*lI)f9Q*Q6J'GQJT@1MU1RRjk1Ghk6QU5i[V1NNB+)RU#-L*D IRC*i@eaSDhqBS+1DJAH(T,'MR*f5KRj[A@9hGRZ8TCb+IR*fLiYlIB&fFhppCPp RFibQUk#ISTqNVULFRD1@Ji1#FQemKSZ8PiGbFS',P*b6JRKXAf0XA8P4ChQ+Pj! !Ihk'LTbZT)k"GQPUCe"2DRf$IAGjGR&hIiZEQS0YBQ0pP(pNDhKlHACcGAf'MCD QTjD-LT'ENhacISk4MBQ-MSH8XE+INB*ZDAQ'KAaeHB53!*H3!)f)KT@LRTLCKep 9BfCNB9aEAQ"D9f9`FiQHLR*jH'&FERq%IA"ZHhaXChD'PUDFIR9qG&K4DRaaA8S j1Mia,djYHSZ5IQpYA%"(ESGrCPPJEATdDS#NVD'1GA&qFeGAHjQ-EQPXDfTC5fU 5Q*QNNRKaB8eHLkH9G@TRC'&JBR#'NTUGN!#!H'eTITH@I(0qJACaG(@$PjfU`,q KKR9`JTHELRk1QBf4SkLRUDkeX+'0IAamHhpdA@"jKiL1PB&aIiUCVD11MBjpFSL @KRq,N!#@TkfHRkba[,UPPjD9LB@8P(YbI(GeKiG`DRq-NCbDLRaY@e0EC9a@C'e bI)*rKTUJPT!!KR"C6%YCDfT@8QGcDQ0F6e&SGAqASSebBPeeQ*4lHSq6J(9hIBq QY,'XVTYmG(1!QCQ(IiH-K(KYC@9iMBf4RT4lFAQ#K(piHBL4NBf*LBH3!+U`PRG N@P&299TRD@CT@e9SEepFHT+5NipmFR*aGAq'IR9mG'CZHRQ$R+LUU*0iEA*hH(K dCfGeE9PG@d9)BfaZKTU'EQGIAf"B9@&lM*1APC@ES++[a-+TQT''JR9JC(k8SkQ KMRCLA&pXLCf@Mj54J&p*69KLEAU%I@489@"fLSk(P+'3!(CG3cG&Ah1,RT4jBPa MBhD4Lj!!SC9lC9ePEhL)RVHpUC!!K)QEU+'9NiaqGQYJC'ekM*LBMSH%HhGiJT1 1H@pdIRafGhk0PT'4R+QZVDHXbp#YPBk$IAeeDh&rJh0UFfpZIhpjNjpi9dj"3P" @C(b-KhCqP*kQTjqQ`Ef*D@0A9PTDFSb&GRKiFhPkHB+)MSYrK(PIA'0XJj*qDi# ,J)D9RD@fZTq8RT5!HA4cLU#4Jj+EPj15N!#6PSU'PT!!F9a36fkBS)f*Q*@%KBU 2PT!!Mj@CN!"[9PGHAf&cKj15K)'%J)4kBQL*RS4C69455e0[Lk1TPik6PT!!Ji@ FYm1cNhGTA%)e4fCmGfGUF@GA589HL*PpAe4%,4iU9(U,PTqUXTjqERH4SkLLQC! !F8Nk2e&SIj'DR*4pC&TIBhHFSSTY55dS0%K56fH0NSClD@&dKBD4TD+,F&0%8QY `F*@hUTD@Li#)JRkEShaE8NpFG)'"LUL[P*5YVkHUTDHiU)0hHR&ZH(KdIBZ'D9e RD'YYCB+MJP42AfYfKj+PYkqMSU@ZYVQjaH2IVj!!KhYiH@TRIiYmHS1&Mj@6R+f kVSPS9NY6BfTrQCDATkHHQjUIUDQDKhpjE&eDDR9eDQ"UG("ZD'*fPT'%Pj!!D%m j+N*PD9K5BAH'LB'#SVkZRk+JPB"J8(#4KR9hK)KiER0mMk#IR+HRL'K69RU*JSH ,NjU5KAq)R+DVV*k0J("GAA9kEfphKBCmH(erJ)H2Q+LSNheZCf*TIiU,Nj+(KSZ (KTHUUjf8MS0c@Nj058Y06&"CBejFE(TmFQ9LAe%k,$0"8QCTE(k(GfYdJjU`TSk ,NSKbE(U(L)*eD'PYCPjIFBb+IB'#G93i0$e1@94GDQjU@eadMU1TTk'9LA*EBAU 'Hh*mIQaKCA+"QlDdTk#BLhTjLjQGSkHUTk#CNj1CSE#mYU#0JAPqLj15LiQ*I@p UERU'KBQ9MAZ"LSD(Mj!!NCDAMiL'JS56RkfkYkD8Mik-M)D$L)*ZAPpSDfedJ*5 HN!"cB'*I9ejUH)D%HRb)N!#,IB'9SU1EM)Q4M)'#L)k5KfaJD@TG@fGbJ)CfEAq ,Gf9ZGh4aFA"lNjZ4Mj'CT*q@NjkKN!#1RCf6KhGeJSQ'Kif3!)Z"K)CfITL@PUD LNB&dFRClKj5IQS"cG@j[JT!!MTLRMQeUBPTSG(KlHfpF9&KE9Q&pL)Q&Ef&QAeG NHiU4M)"pJiL"HBqVU+#8FeT@5$P2GAafEPC(58p,4eCQCQ"54Ne99Pk!R*H2LiH 3!*''JBfZb-+RP)TqF'"NK*b5Gf4JA9GBA@k2Nfj86%%q2N&FK*5%FQj[FR9kJT5 SRiU,MB&rHh'!Q*H-L)0mG@ebJBU3!)q-Li&hHhKhP,'QNj1,LjQBSDqRSkHZYUQ FS*f8QCQ*KSPiG)5)NU'8JS5+J@j`KC'5PCL9Pj@0Q+UdbY+jVl5RQ)q*Nk+DM)9 lGR4aFR@$NB0R@eYF@e05EB"lKT+(H'eSFS16QjL6NBk0MBQ+N!#!Fi10H@a[GS+ )K)Z@LRPlI@jND@aG9@YiD@akIik@M*!!QC+*Ji+*NTQCM)bHR)4pKjLSSj@HUT9 mHRf"J'pH99CQF'GKES"qGS@EQiKpIS54LRKmIAQ&JQpYGR4RChf5PBamFi'%AdP BBfGZE'GZIRpZEBUQTT+"K)TZ4d*+8Q&SBQ0ZDPG*8'YlG'TTEfY20$G)89YRFRe pF@PKE*1RQj1AQT*jCh&kFAD&MC@4JR*RG)qBPCH6KA4F4%&$3P"LE@TCA'GVJCZ KSU+2IRP[DhZ#IBbPT)YhHS+&ND+UZF'MN!#6Jh9lI)'JXTf$I)+'JjDme1(5T)f -JRq(JB+DR)4bDfp`DALDYXV'VD@QNhedFRq4MBQ0MC13!)+5[pR6Zk1GR)TcD@e eH(9dGAb)J'akPj10NiZ,NS9aD'GQC@0ND@jiGQYqPCLLS)q9Q)L&LAp`DQYVEhG kG(D)LAb#Ki#"JB@0Hf"A@PeMD@YZFhZ0QTLJS)b*L)1+KAPhG(4fFhD(PjbIRjL GRj@9NT55G'CaG(9jFR+"KRb%QUDdZD@8MSGhC@0MB9p@6eYZCPYYJ)LETCkLTCH !C&TA6eGSG)&mC@"hNTkTVULNPAPJ6e"86dp6A@jU8deDC@KXGR9XD@KH6dj258a FDh*VB@9bK*LRYEf`PSGlD@amJ)5*JR&K@PpXHS5)M(jE4NpD@f0N@9TJA&YB8ep fN!#QZXHcNB&lEQCiKB+&H'9XF'GZKU1b[XD`NB1%LSkCT++3!(PhJS&pJj@acGI 5[Tk-LS1$NjqBJ@PKC@CXHiQIXUfZUC!!IR0`HSL-GeY6A'YcH)QFYFI"am5MMSk 2N!#CNh&E@&eSFAPqKC51IiD'GA"cFA0qF&*'3djPG)#,Mj@ARV@iUD+JSD+FLhC TBQGeISD2Li&cFS+$Hhf#Ji1(K("M@Q&iJSL&Ghb%M+#NQ*58MB*pG@YUFSQNXDq BKBb0MjqCM*+8JQTSDQ*MC@f&NSThERZ'MD+USU@JJfpaDPP@@&edL)"ZDR9hJU' USD+@HfGC5%*29QD%LRYdGS#(PkbaVkD2H'jU@8T6A@TpH@&15NY)9R"rJAKXC9Y 02$jBDRH+LAGYEAH$P+qhUk'@LRpbCf4YHB+0MhpZCQ0JD(arH(9[E'GJ9%Y8BQk "JfjNC@KeMCkDMiPrI(aU@&pVEAqFSC@6NT5KTkZZUD1FPBf!G@pUF)'DSBk)MTQ XX,#dUCkIS*q1H'eUF)5DQSf0NC1BNjQQQBH(LSGkCe91B(qGTjkGTUbVUEDqV*@ 2PCQ3!(9A8Q4iLipqGhTaCfahIhCVFRYhBdJp49"PKTD@RCU'K*DSU*D+N!#EPi" UAQChJj1IR*4qDQjmLBZ#IifEM'jE9PYRGT1PSCH#Eh@0Rk+BP*U@KQjMFi#%NkQ XS*Q*Eh5)NC5,JRpdC&*$5PpVHTUUQSf$FRkHXEZkU*Q+G9p08'4dKjb8IATY@Qb +PU1NLR*RA%Fj3PKaMk#@Lj55KT+RVlDYLh*YC&KCBQjmJAaaCf"44&9eL*!!JQ4 A9%Bk2dpNHi0hERH(L)16VE1SP(efI(PXFBLCSTL#HATdC@*hMj+(G&a28%a'9Qp [D@YPAf9[FRZDTj@*IQGIAPKIFSD-L)9eFB'-MTLXVTL4L@jQC&pRHiZ-NC5+LT' 8RlE0cEfdU*1(J(Z#LiL&MT''JSD0PD'YUTZDQSGkFQYVDQY`J)Q&M*@DUVV'aE1 TST@2LiD$KBL+N!#,JBH)KS4rLC'!GA0R@eG33N&4AQPVDAU,LSU3!+'TQSPmH)# !H(CmKSQ,KRk(MB*jIBU*IRYhH(PU@eKID@j`Dh#(M)+$ND1UT*U4M)4mHS#(KBD (J)DANB1'Pk+CLi@#H@YE99YMDA&lIB'1N!#-P*qSTD5XU**fCQCVFR4dHAGfJ(p lIibDPiq6MAGM@P*39PKID'CSH)1"KjDJSD#PTjCpF'YZH)#%IQKAC'jRCfebGA0 YAdir1cp&8Q&SC&PHGiL)MCbPTCq@NSPfE("qP+HPMhKVEAKlIiL3!*!!Ki"lE&P 389CQH(&F894MG(b*Qjq6KBH1Kh"EA(52PSPiEfpjKT'QZ,@LNj+4Kh9MCAf9QBP iEfq$PTQTZ,#KQjZIS*4rHB58SCq4JAL#M)fETTU0KiD&JRYXB'"XHheaC@ClPk5 PT*kCPCHGS*k6Jhq+Q*D(I(9pLS&mKiGjD@*QD@052Me9DfYNBfb%Pj12PTL3!)4 kJj15JR0bKCQEKhGfIS&dDhD#KS*pK)k%DeYDC(0hF'pcGhTjISL0NT!!NkDVPAp iHB#*N!#1M)k-LB4rJSU1M)H(JR"F8PKTHB5(LBQ)MBf+NjZMUD5FP)b!Ghk,PU+ MR*'*KhpiISQET*D$IAGR@@"ZGi+(IhZ%LS0qKj1MVD@BNSepFAf0N!#-JAGjHR* M@Q*XFA&N9PK84804C'eSB@&UGAYiGS@5N!#'IATkGA0jM*kGMRehI(YmHR@!KhT aFQeK@&&IHi0cAe48@PjSGAU"K(TcGAGdEfq$QCb9LAjkIB+1PT!!N!#5L)5(KRT ZFAb(MBQ"HA0fISqKRC@BQTUBPT11MT+AQCbJQ)f(L*UJKhQ"JAPiH(9fGhClKBU ,KhYfJT+5J(Z$JS50NTUKPiH(PCbIRBq(LSf!E'T`E'9MD(0hC9PKEAGqJ(YlKiY rFhU!GfpcHi1*JRKkKC'CR*@+J(PcER9rFf4SE@eXC'0[I)5$J(KTBf9SDhk8NB@ )L)'!IRTpLjQJUUH1HA4bGSbKP(ppH'YRCQ*VJC'CS*Q$GRGiHj+ZUjL3!)Q'M)Q (MCDMXVL`RBPmFh+&S*TqF@GJC'KYHSqIS+#BL(jcEhL4Uk'#Gh9fIAjpLCLDP*1 4KhPN9PakNS*I6da-6dp@E(eqGhKlGQjL@@U*PS*RB@*QE@abLCL8Lik3!)U"F@T fLT1!BP048e98BRf#H(*[E@PJ9&0SK)eqD@*LAf4`IC!!QjQ3!)Z1M)*iH)@5Qj0 lF'jVE@pfLTUCNC'5Mib)L)kGVUD2LBZ)Ki@'NCfMSCUDQC!!KS5*MSq$F@a[FA4 bG)@9Pj'4PC+-IhKrKSb'G(#!LSCqIiU1Mik0Mj'*HAL"IRKYAPpZG'TLCQjiJAp pKSKhEhf*KAaaC@Z!KRaiJBU,N!#@PCD4IR@&NiGhDPGACfaTEA4kIS1,LiGqFA5 2Tk+5KhPaGRTpJS1%M*HGQBepGB#BU+19LACTE(0lJAalKj1DP)0cEhqATD5CLhT XDA*rLBD&MCQIQSepG)'BTk@BJfC269PXHhf"Lj!!MiTqF'YeLTZHPi9XAf0[HiD )K)L0M)ClEQGYHiL,JQp826T,A'GUDQeZFA0`DfKXHiL(IA0P@Pp[I)D*Ki+#KiD %KSH,P*H-I'pF4dKHFRjrH'pVE'TREAL"Liq%G@pP8eGbKj!!Mi9pHRejF(Q-PTq KNS*rG&jGFB#*LB&mH(9ZD(Q1PTbJQ)Z)JR0eLTH@N!#2N!#2LiD'PULVT*k5Ki* fD('#KB@(Kif1Ki+#LjL6LSZ%Hhq$JB@3!*!!Ki&qJ)*qIB')Mj'-JhK[F(9hHAe eE'PSDR"cGAZ$KS0rGfPKDhZ%LSb)IhCcFR0hI)#*NT@4JfaGB'piHRprGQaRDA* rKiD+NC+2KR0QEAf$KSZ+L)0rJSH0Nj'9RD#LRSjrKC'1LBf-JRGaFhU$L)+"KSD 'KAYhJj16Mik)J(ajHi13!*D5P*D1LSTpFRf+K(k!I(4[D@TfKSq2LB"eFR0YDRb 1N!#1MB9pHA*YG)#%JRjeEfeVCQ9bIhPaF'jVCPYBDATqIRPYC'"C99eaIhadFR9 jG@p`HS1'KS5!J(ecFhq-Mi9hF(*dF'a[Ghk#JAadE'4IDS'3!*5+I(CiHRKlKBb 0M)U*KAjfFS+FUDD@JRKiFh0rKiZ3!*+4NBf"Fh'#Q+5QQiU$IhPlKSq6P*@AQ*1 $GRH%PU@PNAefFR4rMT53!*!!Mib0KhYbG)'2QTb2JATcFi',L)5$HhTqHA"YG)+ -P*H+HA&UE(f-N!#1KhekHh9[EA"jKBf-K(KaEh&rLSD$JRYhGh*[FR0jIhpqH@P IAQ9kK(plGh&ZE@Y[GA9iIRaqIR4bH)54P)f(KB0rJ)#$LBQ0P*!!MBU!IB')NjD +K)9mFhL"M*D9MiZ"I(aiHB+-PTL2LBH"IB##K)L'Ji9qFfpZFAL%N!#5M)b1JhC hI)#)LiU-KhaiGhU!K)L&IAq#HA4eF@pdG(4kH("`GRYpIS5$I(f"I(PiFQpcG(9 jEfCZGhq%K)H&HhZ$K)H0LB5&JRjkDf0YHSD0LiL$G@jaGRYqHRQ"KB&pEf4YHiH 2MSf-J(CiIS'$KBD,LiH"F'GcIBH8Nj!!MiGqJBH1NBb,NT52KhP[G(U%MSb*L)& mJSb5N!#-M*!!MiCpG'pkJSD3!*!!M)KmGS#0NT++Ji5"Gh0bFAU"K)L$HA*SDhU 'MSk'JS9rE@KVEAL&LSb,KAT[F(Z(MSq+KB&kE@ecGS'+Lif*IR*UF(f*NC10LSP pDQ*JA'CdHRelG@pUEAL#KS5"IRPaE'pcG)'0Li9pFfj[G)#,MBU'J(jmGhPpIB5 2MSCpHS#$K)kES*b9M)D!HRb"JBH1KA9UCfjeI)L@Qj5-JhjrIRerISH3!)9hF(* qL)Z8RTqBMS@$JAf"KiD,Mi*aC@0XGAb'Mj!!L(pjGRChI)&qJB9jDfCQF(q)MBq ,JhekHhajIiU*LSf!F'TTF(b#L)q4Li1!JAjpJiCpHRaZB@4SFB+0MSf,Ki1"J)# "Ji4rIRjbD@PSEAb"JB1$JB#"Ji5&L)Q%JS*jFA0hJBk8PC53!)k3!*'2N!#4M)@ "IhYbE'ebHiD,M)b+LSf0MT'4MSk*JAY`CQK[HB1+NT50LBQ+M)k-KB*rI(KYAea LDR"iIRjrJB"rJB&pH(GhGRPcDQYaGAZ!JiD)Lib0Nj@3!)Q&IRTpHR&[Eh"cFQp [GRq$L)f,KAacEQe[EfeaFh0iHhCjJSH+MT5ANSKqGR0eGACkHhPpI(9fIB5-PCq NS*D-KS@&JS1*LSH+LSD(NCQFSUHTST5(JAafFR0iHhPlI(GiIi1'MC5DPiPrHRG fGA9iHRYqJi@'M*HHRjqIQif"I(GbF("`F'jZFR*[FRb&LSb0M)0fF'j`G(9dFA" aG(4bGi@5PjQCPBYrH(0`FA0bF'jZEh"[FAk*Mj'5N!#(H'jVEA&hH(CfHAamHhk (NjQCQTH-J(KdFh4fFh&aFh9dFhD!LSq3!*19N!#&IRTjHhppHRKjIAq!KT!!QCf FQC5,J(TeF("cGAGkHRYlHi'*Mj+6NSk(IRPiGRGkHRPkHhalHB14PjZGQ*5,I(4 `DfYYDQPYF(*bFAL'M)k2LS4rHAGhGRKkH(CeFR4iHAq-NjHDPT!!L(jkI(KdGA0 `F("cGhKrLSq5Niq)J(GeH(4aFh0bFR"bG(4kK)Z4PC'-L(jhGhCeHhpmHRTrJAq $Lj'@QjZCPBb&KB1"KSL&Ji5(L)H,NjQHRjUANiCkH(CfHhekHAf&Ki&qKBU0MBb 0M)*jH(KjI(YiHS'*LiH+NC@9Nik1N!#'H(0bFh0aE'acHRemIB1&JS"pIS&kFR9 kHhYhF'j`GATlJBU-LiU(KiGqGA9fGh9[D@T[FRCjI)+&KB@#J(jfFR9jHhalGhC fH(apIi@(KSH(KS*mGhGfGACdFA&aFRKpIS##KBQ,LSL$J)+"J)#"IhelIS@*L)U -M)k1LiD!IRjpHhYlHRYqJSH+LBQ)KSD(L)H%JB+"Ii#"IherJiQ1Miq3!)q1M)L $IRPfG(*bG(9dG(ClIRerJB'$KB1#IhalHhTlIAelH(GlJB5&KSH,MBU&J(TiGhC fHAepI(TmJ)'#KBH+LiL'JRYfG(*cGhYkGh9iI(q#K)H,M)U)JhahGA0cGAKkHRY qJB'$L)f4NC!!N!#2Li@#Ii##KBH'KSU-Lif3!*!!NC'2MSb&IRThGRGjI(elIB' #Ji@'KSD&KSH#IATiH(KkIAprJiH(KiU+LBH$Ji0pG("[ER"cGA4cGAPmIAq"Ji5 "IhppHAGeFR*hI(YjHhq#KBL+MBk-LB9rH(0bFR0hHhYjHAYpJ)1%KSD%Ji1"I(P iH(PmIRjqJB1$JSD+MSk-LSH$IAKeG(9iHRPjHhk!JiL,MBq3!)k+KS+!J(jlI(q "JB1'KiL,M)Z,LBD$IhThGhCfH(TjH(f#K)5(LBQ*Ki5#J(akHhYjHRYiGRZ#KBD (LBQ)KAjlHA9cFh0cGACcF(4lIAk"K)L,L)*rIATiH(PjHhjkH(f$KSD(LSf2M)D "IAKeFh*bGRTjHAk$KB1$KBL+L)@%JhplHRPiGhGhHAk$Ji'"Ji@%JS'!J(eiGA4 bF(*bG(Z%KiH(LBZ-LiQ)LBQ)Ki@$JB'!J)@0N!#3!)k0M)Q&Ji'"JS'"JAjlHRK kIiD+LiZ+LBL&J(epIRjqIRapIhemJBL-MBb,LSH#I(KhH(KiH(KhGR4cGRarJB+ #K)1"IRTjHAGfGhKjHhYlIi@)L)L*LiU'J(akH(4`F(&cGA9hIB'#JS'#Ji5$JB" qHhKhGR9fHAYqJiH'K)5%Ji+!IhjqIAKeFh0dGRPpJiQ,LSL*LiU)L)Q*L)D#IRY lIS'$KBQ,LiU*L)H&KB5$Ji&rIAamIRq#KBL*Ki@&Ki@!I(aqIAakHAKjI(apJSH )KS1$K)0qHAGfGR9cFA"bGRGfH(erIheqJS1"IhemHhPhGhKjI(q"Ji@%JS'$KiD "IRajGR*[F(0fHReqIi'"IRk!K)D%Ji+!IAPeG(4fHRjrJ)+#J)"rJ)'!J)"qHRC dFh0eHRq$KBD&KB5%K)D&KBD'K)5$JS+$KBL*LSb,LSQ*LSU*L)H$JApmHRTmIi1 'KB1$K)5$K)5$Ji0rIAepI(eqJB5'KSD'KiH'K)1"J(plH(CeGAKjHhq"JB"rIhq "Ji5%K)0rHhTjHATmJ)1&KB1#JS'!J(prJ(pmHAGdFR0eH(f!J)#!JB#!IhjqIi" qI(TjH(GhH(YpIRq"JS+#IhemIAemHhTjH(GhH(YqJ)'%KB@&KB5$JB#!J)#"JB' #JS1$JS+%KSH)KiD$JB"rIRemHhYpIRq"JB#"JS1$JS+!IRepHhTkI(k!JB+$JRp qIRprIRepHhYlHRKfGRGjHhf!J(jqIhpqI(erIRjqIRemI(aqIi'%K)+"JS1#J(j qIAamI(YkHAPkHharIhjrJB+"IhprIRjpIAjqIhq"JS+$Ji1%KBD'K)1$JRpqIRj qIAerJ)'#JS'#K)@&Ji1$Ji+#JS+#Ji5(LBQ+LBH'KB5$Ji+$Ji+"JB&rIAapIi# #Ji+$KB@%JAprIhprIhpqIRjqJ)'$Ji5&KS@$J(emIAalI(eqIRemI(amHhYqJB1 $JAjmHhTjHATmIRjrJ)'"J(jrJB'"JB#!JAppI(TkI(apIi"rIAapIRprIRjrJ(p pIAalHhYpIi'#J)#!JB&rIAk!JB&rIRalHRTmIi'#JS#!J(pqI(apIi'#Ji+"J)# !JB+%KB@&K)1!IRepIRq"JS'!IhjrJ)#"JB'#Ji1"IRamI(epIAjrIhjqIhprIhp rJ)'!IRalI(epI(amI(aqJ)#!IhjpIAjpI(amI(eqIRprIhq!Ji1$JS'"JS'!IRe pIi#!J)"rIAapIi#!J(jpIRjmHhYmIS'#JS+#JAq!JS1%KBD'KS@#IhepIi'#JS1 #J(jqJ)'#Ji5%K)5"IhepIi+%KBD(Ki@%Ji1$K)5%KSD$JApqIS#$K)5%K)1#JS+ $Ji1$Ji1"IhemI(eqIi#"JB#!J)#!JB#!JS+!IRemI(eqIRjqIhjpIAjqIRemI(Y jH(GhH(TmIRjqIRjqIRjqIRjqIRelHRPjHATmIRjqIAepIAjqIRjqIRjlHRTlIAj rJ)"rIi#!J)#"JB'"J)"qIAamIS#"JB'!Ii#"JS+%KB@%Ji&qIAeqIi+%KB@%JS' #Ji1$Ji1$JS&rIAeqJ)'#Ji1$JS'"JS+$Ji1%Ji&qI(YlI(erJ)#!J(prJ)#!Ihq !IhjpI(YlHhapIRjrIhprIhpqIRjrIhppI(alHhapIi#"Ji1%K)1#J)#!J(prIRj qIRepIAepIi#"JB'!IhjrIhpqIRjqIRq!J)#!JB+$Ji1#JB'!J)"rIRjrJ)'"J(p rJ)'#JS1$Ji+"JB"rIhjqIS##JS'"JB'#JS'"JB'"JB"rIRepIRq!J)'"J)#!J)# !J)#!JB'!IRepIAjrJ)#!JB'#Ji1$JS+"JB'"JB#!J)#"J)"rIhq!JB#!J)"rIhp qIRjqIRjqIRjqIRq!JB'!IhpqIRjpIAeqIRpqIRjqIAjrJ)'"J)"rIRjqIRjqIi" rIhprIRq!JB'"JB+"J(prIhprIi#!J(prIReqJ)#!J)'"J(pqIRepIRprJ)'"J)# !J)#!J)'#JS'"J(prIRq!JB+$JS'!J)#!Ii#"JB+#JB"rIRjqIi#"JB'"JB'!Ihp rJ)#"JB"rIRemI(epIAjqIhjpIAepIAepIRq!IhprIhpqIRq!JS+"JB'"J(pqIRq !J)#!J)#!IhjqIRq!J)'!J)"rIhprIi#!J)#!IhprJ(q!JB'"JB#!J)#!J)#"JB' "J(prIhprJ)'"JB'!IhjqIhq!JB+#JB#!Ihq!J)#"JB'"J)"rIhprJ)#"JB'!J)" rJ)#!J)#!IhprIhprJ)#!J)#!JB'"JB'"J)#!J)#!JB'"J)#!IhjqIhprIhq!J(p rIhprIhq!IhprIhjqIi#!J)#!IhpqIRprJ)#!J)#!IhjqIRq!J)#!J(prIRprIi# "JB#!J(prIi#"JB'"JB#!J)#!J)#"JB'"JB"rIhq!J)#!JB#!J)"rIhq!J)#!J)# !J)#!J)#!J(prIhq!J)#!J)#"JB#!J)#!JB#!J(prIhprIhprIhprIhprIhq!J(p rIhjqIRjqIRjqIhprIRjpIAjqIRprIRjqIRjqIhjqIhprIhjqIRjrIi#!IhprIhp rIi#!J)#!J(prIhjrIhq!J(prJ)#!J)#!J)#!J)#!J)#!JB'!J)#!J)#!J)#!J)# !J)#!J)#!JB#!J)#!J)#"JB'"JB#!J(prIi#!J)#!J(prIhq!J)#!J)#!J)#!J)# !J)#!J(prIi#!J)#!J)#!J)#!J)'"JB#!J(prIi#!J)"rIhprIhprIi#!J)#!Ihp rIi#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J(p rIhprIhq!J)#!J)"rIhprJ)#!J(prIhprIi#!J)#!J(prIhprJ)#!J(prIhprIhq !J)#!J(prIhq!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!J)"rIi#!J)#!J)#!J)# !J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprJ(prIhprIhprJ)#!J)# !IhprIhprIhprIhprIhprIi#!J)#!IhprIhprIhq!J)#!J)#!J)#!J)#!J(prIhp rIhprIi#!J)#!J)#!J)#!J)#!J)"rIhprJ)#!J)#!J)#!J)#!J)#!J)#!J(prIi# !J)#!J)#!J)#!J(q!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIi#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!NLS!!3!"!!8!!!#J!!'!83!!!!!!&!! !!!!!!*)!9Zk,S`!!NIi!!*(r!$b!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!IhprIhjqIAamHhTjH(GfG(0aF'pZE'YUD'CNBf& HA9YC9e988e&36Na+5%C&4%*!2cip2$`m1cSk16Nj16Sk1cXl1cXl2$dr3%""3N0 %48C(5%P,6%e16e&699GC@PaHB'0PD'YYEh"bG(CiHRaqJ)+$KBL,MBk1N!#6PTH APTLFSUDRTU5PUDkaVkURU+keZlZhXDkbZm2'`lZcXEE!bp28cF#aTD1V[-hCfY( !V*U0KSbHZp[amr$Ud+f9NTDAPjD8MiZ(KSqSb0[FdXDmXULIPSq)JAafF@aRB9a A8Na(3Mik0c8d06Bj28&(6PGKDhH$N!#FUE6!bY6FjHc[lr$`lqlZlZhZlHlYl1h YlZlZlqr`m1rYkZINhp[Ae026eGEBfYcGiHEXmI6dm[$YkZMSkHVXl[$bp2AcmHr [lZlXk1,Gf0E6d-c*aX2![VZkZ,HeYE5dY,@eYEDfYVDeY,1aVUZSTD+HQTD5MSQ &J(aiGhGfGA9eGA9eGA9eGA4dFh*bFA"`EfpZEQeYE'aVDQPSCfCPBf*JAeeF@eT C9e9689&48%j*3d!q1cNi0cFh0cFh0cFh0cBf06-`,#JP)KmG'aSD'aXE'4F@&KJ E(L%L)4mH("`E("iK*#FT+LSV,6!c0MJj1MSl28"$4NK+5NP(4%*#3d9)5Na06%T &2MF`+5-H'aSF)#BX-MJm26dp2N"$48K,6P*@@f&QE'pbFh9fGhKiHAKhGA0cG(G mJ)5(LSZ,LiZ,LiZ,M)b,LBD#IhelI)#(MjQLUl1j[Er#aXh5d-c3fH$KhZ$Pj0I 'Z,@iYkfGNSk2MBGrI(q'MC!!N!#,JA4UCQGXFRGmJBH0NTDCRD#MU,#mc0[PkZl `lq[NemDeUkLNQj!!LB@#IAKfFQYK9NT!1cT!5%e-4d)p0LiU+LXT*L3L(4-)!!! !!381'LJd284(5%K*58P+68j)2M8c1$p#3Ndj69PGBA@G`G'pQA&0,48*"38& "3$mq26dm1cSj1MXh-5SN)"`B'"JA%!F"!!3*$K8G)bBL'3m)#K8N-6Y$5e&58eC HC'GPBfCZHSD3!*HHT+UVTk'FQCQAP*+4NjHDQTbJSkLZXl@eYV[$b-V0dYMDep2 3cp,9e066cF5jVkQRUDbYUk@IPj!!LSD'LBb2NC5BQCD2KS"lGR"ZEh4iHRTlI(a kGhClJSL*K(ekISL6RD@VVV#`X+qYTjk6LiL+MBq0LB5%L*'GTkkbYEQp`F,$`m6 %a-'r[Vr&cYRPm2MqrrrrrrrrrrhflHAJh0M5cFR)bFR)amM,cp2@f0E2aVfjZEZ q[lkkXULGP)k+L)H)LBZ0N!#5P*HDR*ZCQCZIT+DPRjL3!)Q"HhGfGRGiGhCcEfP PC'9SDfaXDfecHS#$K)5$JAprJSD+MSq0LB@#JS5)MC!!Nj14MBU(KB5%K)1"Ihe kG@pSC'*LC@TbHS51QD'MS*U6M)H%Ji+$KBQ0NTHERTqIRTfCP*!!M)Q)LSk8QTk JRTL4LiD$IhTdDf&B8%K#2M`l1MSj1cj#5%e69eTGAf"IA&P86dY*5%T3@@9bI)1 (LSU+LSQ'IR*M9%K!2$Xm1cJe-5mZ,5i[-63f16`r48a9B'YfIB"rHhGdFQjVD'9 MBQ&KB@&KBQ0NC'4J@P49AQKTC'"IA&PDB'9PBf0NBeeA8P9C@P0*3Mp"5PKQEh" UB&C9BR@!Ji*rIRamHhTkHACcEfaTCQ0KAPYB9P014cmh-#`V,M%d0MFi16`r3dG -6e09@&YKDA&fGhC`CPaEB'4KAPYA99499PGB@&PEB'KcIB5&Ji1+P*fKSU@SUkZ UU+1CM)"fFR*hIi@,N!#6PCD@PC55N!#2MSk1Mj!!Mik,Ki0qH(4`EQe[G(f*PU' SUkQPSTkEQCQCQjbFQjQ@P*58PC@@PTD9PC56NC!!MSb,LiZ-MBk2Mj!!NC+6NBb $H'aNB'"JB@4RE(0qLjURX,5dXDkYVUq[VUbTTkDPTUHUV+k`X+q[VkkUTCk@Mif 9S+LSSk#JSkHVVUkUSC1&IS+2RDHTSjQ-Ih4YC9jA9&CFC'PZFRGpJ)&rIAYkI(q $L)k9RDHb[XVBjHh`l12@bEkfXDqZX,1fZEHbUD'EQCQDPSf"GQpXD@TXER"[E'G KAPjLDR0mJiL+LB@"IAf$MjUHQT53!)k3!*'3!)Z'JRpmHA9aD9p@8P*9@f0`JC! !QjkBMAjbE'aZF'pVC&jD@9PGC'jkK)U-M)Z+L)L,N!#8P*'1LB@#JS+"IRamI(e pIS''Lj+BR*kGQjH4M)L*M)q1LiL$IRTlIi5'K)&qHhGaD@0HA9eHA9aB9%p06P* BAQ*MB&aB9909A'4RBeY@9PTKDR0mK)Q+Ki0qHA0YE("dGR9dGRTrJB'!JS5%J(a jGA*`FA9lJBH,MBb)JRYdEQTTDfjZF(H$MT16PTfNUUbXV+qfZVQfZ,l#`,bk[,f fU*U2KhpjH(YmH'pRCQYdIS5"H(*dHATjHi#%JhefEQCF8%G%5P"2580$4NT-69" @AQ4SDQjeISH5R+@TV+kZVDQLPif*LSZ'IACaDf9LA94+4%9+6Nj*36j$5NY$16F r58j+4dY@BQTYFACjGQpP@8`q-#3F&aJF)5BT,6-l4%a16Ne39ejLBQ0PD'PTD@T YFA9lJ)@+M)k2Miq2N!#6PT@3!)Z2Q++SUUZYXEHlZE1`YX64eY2*ZkqQSk1QUUb XUU@JQjQBQ*QCPjD6NBq2Mj!!N!#3!)q1MSq5PTUGRCbHT+QUUD@LRjZBPC56Nj+ 3!)k-LSL'K)1!IATiGR4aDPj44$dj-bSK'aSG)L8P*#3P+#SR(aB6&KXH(K`D'K` H)53T,cBl2$Sm38G)48!q26`f,5BQ,$%f1d&'5e*FCQeaFh4fI)51PjkJRCD2Ki" jGR9cE@0D999CB'PdJ)Q1MBZ-N!#4MSD!Ii&rHR4`FACrLT5CQTUDQCH@PC54MSZ *L)U0MBZ)KB+!IhjqJ)+$JhplGh9eGRGjHRYjG'pXE'jaFR"TAeC6@Q9ZG(KkGfp SC@KYF("VC&pIC'PYEh"eIB@,MT'9R+5TUUHKQjZJU+fYUD1HQjQBQCQBPT'+Jha fFR&bFh0bF'j[FR9kIi@-P*kUZFA,bX5qZlUiY,#ZVl'`V++9LS5'MCDISk5QV,+ cVU+9LiL*M)k4N!#0LSU2Pk'TVDZRSk1QUUbVT*U0JRGZCf9XHikHUDfVSjQ3!)k 3!*+8NBb&IRYlIRppHAChH(CYB9P@@&YHAeaEA@4[H(k"Ji5$JRpkG(*fIiU6PT5 3!)k2NjHCQTbHRjfFQjbGRCbDPT!!KhecE'CNC'CVFA9hGhGiHRk#KSZ4PTUFRD' TYF((aVfaTU'LTkfcZEh"aFM+bXM'aFE%`EfmZVHeYVh&bm['`X2'aF'q`FI+b-+ lXUfZXlDdVkbZY,h$aXE'aFE*cYIJj1,FeXl'[VLbVUbUUUfcYV5XTUDUX,Dl[lk lYlDfYE5bX,#bYEHhYlHeVU@GQCLBNB4fE@KSDh*mL*1ES+#FPC!!N!#5P*11L)& lHheqI(TlIi5*M)f1MBb+LBH%JAjkH(GhGR*[E@YVE'j`G(KlHhTjGh9dH(q%Jhp iF'TRCQGQC@*IA9YE@PG98e058%a&2ce!48P+5%9#26Jd-M)b-6!b06Sr3N9'3ci j0MBi1Ma!489"2$e'9@*XG(U!KBQ1P*LDQCQGTDfcYE@cVULLRTZFR*ZCPjZLTk5 EN!#*KSH-NTQHRTL1KB#!JB&rHhPiHATjGhGiHhq$L*!!QD+RUDUVUU@HQ*DBR*q MTULSTU1JRTZCPBk%I(KhH(YqJ)"mGR*dGhGcDQ"C9eKHD(*iHRYmJBU9Rk5LQBq (KBD(KB"lGR0cGhq,Pk'TV+ZPR*'&HhCiJ)bAS+DSU+DKQjH8MiKqG@jTCQ*JB'4 UER"aFR0eGhGfGhTrK)L+M)b,M)k6QCfGQjD4MBZ,M)q4Nj+4Mj'ARCkDNif*KS@ 'L)Z1NC16Nj@CS+HXVDZRT+1NTUHQSTfBNSf)KB*rI(PeFR"ZE'YVE'eXDfPQBPe A88a(2cF`,#NP)L)Q,M-a+#%J*bia,LNR,$3k2d&$3d*$48G)4dC%3N*$4NY28P0 68e0899CA9eC99&966NC!2Mdl1$8e0cSj05mX,M3l3NC*6%j389"16%a28eKE@P9 25%0"3dP39PTFAQ&ND@jdHS#$JRaeEQKNC@TbHi+(Lik4NT'1LS9rH(*XD'CPC'4 NCQT[GRf%LBb1MBU'JS"pHA0UB&C14d%m1MNj1$Nj0c3[,5md16e!3NC-8PC98Ne -6%e-5NP+6%j48e*-4$Xc,bma0$8e-c!Y+LFM)L-Q+bmb06Sr4Na49&CBA&pI@e* )3$dq4%a6@&TD@9TGB@9UF(KrKBZ8RkUcZEl&cG,8dF[%Zl5ZUD5IR*UAN!#(I(0 [F(4jHRGdFhClJ)"qHhPlI(TdDf0G@ejQFAb)NjZGQT53!*'9Qk'QUDZVUD5FNBH !IB#(M)b)K)1$K)5(MjQMU+HLRCZFS+'IQjH6MSL#I(YqJS4rGh"VDQa[FRCjHRY pJifCTUqcY,1cXl@eYE5bXDkVTk5KRjfEPBb$IAapIATfGAGmJB@'K)&qI(f"L)k 6Q*bJSk1MSk+MSU#ENS9hDQ&GAQ&QD@PQB9jF@eYHC'ehJ)H,LSH"IAf#L)k3!)q 0M)b0M)Q&JAjlHhk"KBH)KS"hEQTXFRGiGhCiHhq"KBZ8RkHXVUqaYELk[,l"`m6 %`lqkYE#XUDLUVl5j[-,+dGEAdml*aX2![lr#aXV-bmM&aXR1cml+aF'pZV[!aX[ -b-1r[X$#`EkjYVHpaFc2cFM"ZV1VSjfEQTQANj!!Miq4NT5AQjkJS*kEQ*@6NBq -LSH&K)*rI(PiH(TlI(eqJiZ6QCfJSCqCP*1@Qk#LTDLVVV#`VkbRSTqJSU1NTDH UV+bUTk@PTD@NSCfCP)q)J(PeF@eSC'*KAeeE@9KA@&TGBQCTDfpeIiZBSUQYVUf YVDfYV+QMRCL9PCDAR+1XXV+YTU'IRjkFPj+0L)5!IAakHAKiGhCfGRKkIApqHA& UC'*LB9pGA&aE@eaIC@TUD'CSEhU'NCQFQj@1KS"pHhTlHRTiGR*ZE'YVDQKRD'T YFRGlI(YiGA9fHAk%LSf3!*+8PjD6MSQ&JS"rIi#"JS@*MC'8PjUFRk5SVDqaXV1 eYVDeY,1f[-60e0VIiZ,Jh0I5cFI!YUbMR*LAQ*bIS*qGQjQCR++SV+ZSTD1NTUL XX,Dm`FA(b-R+bXR&`,bl[EfjX+@GQTbJT+1HPiq+LBQ*KS1"JS1&KB1"IheqIRj lG'aNAeYC@9YKD'e`EfaSCQ9NC'0MC'GVE@eVDh"iJB@&JAYeFh0iIS@,Mj1AQjk KSU1PTUHSU+DLQj+)IhPeFh&[E@aZFACmJ)+$K)L-MSf)JAPcFR4iI(q!IRPdFA" bFh0`DQ*C8Nj,5NP)4dK,6e4CA9pIAPY@9&9FC@aYD@&F@epND'PUDfe[EfYPAPK 98Na$1MFi28C4A'0NAeK589GICfaaGRTpIRprIRTdE@PSCfCNC'CQBPK03MXh0MJ k26p"3N%r26`m2$Xh-#NP*5FU,#i[-$!`-6-f1Mdr3N4&489&4NT39PaLCQY`G(9 dFR&eI)1%IR9[FAGqIhTbDfKTDfYRAeC48PGJDA"cFR*dGhTmIAjrJS1#IA9XCQ4 NBPjD9eC@9P988Np06&"AAfCTDQTXEh&aEfjXE'e`Fh9eFfjTC@*JA&9+26%S)Kd E'KXG(amI)LXe1MNd-$)i2d0$3%"$59"9@Q&TF(*`E@jdHi#"IRPdF'j`FhKmIi' #K)Q1N!#0Ki&kFfeSC'"G@9946Na,6%Y(36p"4NT,589#38N4*8PYLD'abHAk "Ji1$J(elHAGfGA4bEfTPB&pIB'&KB&pG@eK99&GGC'PZFRCiHAPiH(TqJi@#HR0 `FRCjHRf"L)b0LiQ*LSU*KS5#JiL4QU#KR*@1LSD$IRThGRKkI(jrJ)'"JB+#IhP `CejA8eCGCfjbFR&[E'KQCfTXEQpZE@j[FA*cFh0cFh0cGA9bE@GLAPeHA9K66Na ,5dP(4N9'5%Y28eGDA&jKC'KXEQjYDQKRD'YZEfjXD@GNBQ&KBQ4PCfTYFA9iHhk !JB'$KSQ-N!#6PCHESUU`Y,1aXVDkZVHdXl@k[X#r[El#am[1cp(5dY$-b-E)bXc ,alqhXE'jaG,GjHVXl1RMhYR9e065cmc+cG6Hk1rbm[$Vk1ISkqh`mI,alqcTjH$ DeG,3cXl1c-M#ZUqPR*HARD@YXE'[VDUUV+k`Xl@fYE1`VDUSTU1KRjkHRk#IRCL 9PCDAPjLCQjbEQ*11LSH'KSD%J(TbDQ4IA9aE@PG888j068e2894A@ejMD@jeIiU 8Q*H8NC'6QCqQUUZST*qDPC'3!*18Nj!!MBb0MSk-LBQ-NC55MSZ+MBf+K)"rIhj lHi+2RDHXVV'dYV1URj@3!)q1M)L'L)f6QCbDPT'0LSH'Ji"pHRPiH(GiI)#%KiQ 0NTDBPjLESDL[YEUmZV@`VDbYVDbXUkZTTkDSUUbYV+USTD5RVEM$c0$8f0cJiZ( Ihq$Liq(JiZETjq2Gf061b-'mZVQfXDUMR*1,KB5(LSZ*KS@'KiL'JRjlHRTmIi5 *M)b+L)H'K)&qIAk!J)+&Lj1DRk'JR*L@PjZJSk@NSk1MT+5MSD#JRjqIRjkFQC@ 5N!#2N!#3!*'5Nj59PjQDR*bDQ*@5N!#0LBD$JAjmHhTkHRYqJiU3!*@APjH@PT@ 6MiL"H("UC@"GA&eHAPjIBfTZFA0fHi##JAajHRf!Ji*rIAYmIAepHhKfGA4dG(G lJBH0Mif'IRGbEQTTDQe`FR*`EQeXER&eHAaqJ)5)M*!!Nj@CRD#LSU'IQjH4LiD #IhYfF'PMB@0SER0hHAaqJB5(LBZ-MBb*K(eiG(&[EQp[EfjXDfPSCfGRCQ4MBf0 KA&G88e4@@9eJB9jB8Nj-5dY08PKFA&C258C(58P(4%0%58j599TKCfPSC@*JB&p HA&YHB@0LAeY@88T$2MSh0MFl2d*%48C'4N9!2$Sl2Mmq1cSk1cj#4NY39PeMD@j aG(GkIS'#JAjpIS+%JhplH(CeFQeQAPG899TJCQPUCf0JA9eHB'0RDQPRBf"G@99 468a,5NK'3d&!2d"#48T49eYFA9eGA9eFA9jKBf4MB&jE@PPEAQ0RCf4KB@*KAPT C@ejJAeT99&CDA&eGAQ*QD'GPC'4NC'*JAejHA9eF@eTD@eeJBQ&JAejHAPjHAQ" MCfTZFR9fGA0dGRTpIhjpHhKiHAf"KBQ-Miq2Mik2Miq4NC'1LiL'KB@'KSD&K)+ !IAPhGA0`E'9I9e"+4N)q1$%V+#BP*5FV0$p0@@"LB@"LCQPSBeeB9P998e089eP C9eCA@PpMCfPXF(0fGhGeG(0cFh*`E@TTDQaZEQeVDQTXE@eXE'eYE@eVD@GNBPp G@eTD@eYE@9G@9ePEAPpKBfCSD@PUE@paFR0dGA9bEQaXF(9kIi1&Ji&qI(YjG@p SB&P888e*4N9(5Np8@9pND@jaFh*`EQjZF(*dH(b!Ji5$JAjlHRPjHAKhGR9eGRG hGR9fHAf"KSZ4PjbJSU+KRTU@NSq1MBb*KB"pI(k#KBH&JRjmHhf!KBZ5QU#LS*f BPC'1LBD%JS"mH(4bFR4hHRYmIi+&KB*pGh4bG(GlIAajGhGjHRPhGA4cF@eSC'0 MBf*I@eG999KFB@P`Ghb!JS@(L)L(KSD*MBq2MBU*Lj!!Q*fIRTfGS++MSU'LTDZ `Y,DfYV@cXDkXV+faYVc#aXR)aF#kY+kVUUQRSjkEQjfJSD'LT+LVVUq`XE1hZVb mZVHcX+ZRSCZ@NT'5PCLDRU+PU+LRTD5LSD#IRk#IRCQ8Mib*KS@&KSL)L)L*LSU *LBU+L)*kFQj[FhPrJi5$JS'#Ji@(Lj!!PCLBPT14NC+8Q*fLTUUZYEc#b-c0bmI %`X#r[EZkZEUm[m6)bmc*aF#mZVZp`-,$a-E'`lbdVDQSUDUSSjfCQCkQVlDm[Vk p[,UhYE1eZ,c!a-R2dpIAe-r*`VZfXl+cXl1aX+k[XVHm[Vqq[Vr$amc5f0lKi0h CeG25dY(2bmM'aFA%`EfkZ,HhYlHiZEQjZlr'cG2@eG,-aX'r[lklYl1bY,Lm[lq q[,bm[,ZkYl5aVUZUUDLRTD+KSD5SUkfYV+UUUkbYVDbUUDLQSjf8Li@"IhajH(T qJiL-Mj'5Nj@BRD'NTD5JQj@2LB@"IhajH(PlI(epHhPiH(KjHRTlI(eqIRq#KSU 0Miq2Mj'5NT+5Nj15N!#-L)5!HhCcF("`FA&aFA"aFR4jIS+'LBb1N!#3!*'3!)k +KB&pHhPiGh4aE@PQBQ"HAPjHAPjHAf&NCQ9MB&eGA9pKC'CQCQ9QCQGRCQ4KB'" KC'KUE'aVDQPVEA"cGACfGhKkHhalHACbEfaUD'GQBf"G@ePA9949@&TE@PK@9&* 58e49994589"26Nj38eKEAPpHAPpKC@acH(apIRq"K)U4PjfJSU5PTUDPSTkEQ*H @Nik(J(TfFh0dGhYpIRYiGA0cG(KqKBb3!)q-Ki+!IhjrJB1&KiD$J(akHRarJB+ #JS+#JS"mGh&VC@"F@9K@99499eTFA9YA8e&48e056de1894A@9YGAf&KAeeF@eT C9P036%P(4dK,6e0@9eC68%e06e*@9e9468T+69&89&",4d0!26Sh06-a,bdX,#d a0$Fi0cFh16e#4dT-6%e39PjQER9lIi&qGh"UCfGTDQKPB9jGAf0SER4iHRTjH(K kHhalHRKeF@aSC'*KB&pHAPpJAejE9Np*4dP089488e*588p069"@@PeE@&0368T (484$38!r2Mip2$Xm2N"#4%9'4dP,5dT*5%K*58G$2$8Y*L%I(amI(4N@%a)3$J` +#3J)#!N,$!m5&adN+c%e0cJk1cj"48Y5@9pNCQCMB&aC@&PD@9C35dK)58e49ea JB@&KBQCUEh0iI(q!IhajHATpIi#"JB'"JB1&L)Z0MSf-LiU+Ki*mGA&`FhGmJ)+ %KSU2PCUHSUHXXE@iZELhY,'ZUkQRT+'GQCLBQjkIRjfBNik+Ki@$JB"rIi#!J(p pI(amI(amI(alHACeH(k'MT5BQjfIS++NTULTUDLRTkHPSTkFR*kKT+HTUUQTU+D MRTH4M)L&JAekH(GhH(TmIi1'KiH'K)+"JB+"J(jmHRKfFfpXDfa[Fh9eFh&aFA0 fHRq&Lik2MSk1Miq2Mif-LSH#IAKeFh0cG(CjHhamHRTlIAq!J(pmHRGeG(9hHi' (MC+8PC56Nj18PCD@PT@8PCHCQTQAPC@@PTD8NT'4NC+8PjQCQ*D9P*15Mib*KiD 'KSH(L)L,N!#ASDUcZVr#`m'q[,UiYV+ZUD5HPj+2Mj'9Q*UER*qLT+DRTU@LRjk ISkHXXEDjZVQfXUkVUUHNS*fDQTZEQjUBPT56NT'3!)q1MSb,LBL(L)Q-NC@CQCH 9Nj19PjUEQjL6Mif-MSq2N!#2MBU'Ji1%KSL*LBQ(KiH(L)Q)KS@&KSH)L)H&Ji& rIRk!JB+#JS'!J)#"J(prJ)1(LSf0MT!!Nj@AQ*LCQjkMU+faY,DhZ,HfYE5cXV+ bXDkTSTU5M)H%JApqJ)+'LBZ-MBk1Mj!!NC5AQTbEQTH@PC@9PCDAPjHAQ*QERU# MTDDSU+LSTU@MSCqHRCfHS++NT+5NTDDTUUZVUkbXUULNSCkGR*bISU5PSk#GQjb ISkHTTk5IQjQCQTbISD1NSk#EPT'3!*5DS+@SUDQTUl#i`-I,cFr2cmh*aF,"`F' rZlDbVUbTTD'GQTL8N!#0LSQ*LSb2NT15Mib*L)U0N!#8PTLBQ*H9PCDCR*fGRCf ISD1PTUHTUkf`XV5eYE@bVUUNRjZAPC56NT+8PjZGR*UAPC56Nj5@Qk#NTkLSU+L STkHRTU5IQC11LSQ*Lif2Miq2Mj'9QCqNU+bZVUUPRTQ9Nj+4NC+8PT@8Nj5BRU1 RUkk`XE'bY,Ll[EfmZlZlZlZlZVLdXE#[VkfTT*f@N!#0M)f0MSf-LSQ(KiL(KB& lGR*[E@aXE'eYE@j[FA0cG(9hHhq#K)5#IhaiFfaPAPPA9PC88e"05NG&4NG+6P& 99eKC@9KB@&PD@PPB9PCB@9PC@9TGB@0NBf&JB@*NC'0KAPYC9e956de-6%a-68e 28%p15dT+5da05dK%36im1cNi0cBe06Bj1c`m1cXm2N&&5%Y-68e16e"69eaJBf4 MBQ*MC'9PC'0LB@"HA&P@8e"26P"599KEA9jIAepIAPY@8%T'3d*#3N0%489&4%* "389,8PPIC'KVER&eHAf!JS&qHhGfGRChGhGhGhCeFh&[E@aVDQTXER"ZDQ4H@PK B@PYE@PG568K&4%C*69*@@&G66NT)5Nj69eKA9&&3890A@f"NCfGPBQ"IAepIB'& JA9K3580!3%*&4dG&3N"!38*&5%e6@&YE9e*15dT,5dY+58G&4%0&5%e48e068P" 15dP(4dP-8&0999469&9@@&KC@9K@8Ne*4N9&4NG)58P)58T089088e&168j49&G A9eGA@&PDA9pKBQ0MC'4MB9pG@eK988j,5NP*5Ne39&GDA&eKCQaaFh4eGhTmHhP dEfYTD'PUE'paFh4dG(CjIB'$KSL+LSQ'K)1$JS"qHhPhGA4dGRKlIRprIRYiGR9 fGA4cFh4hHReqIhprJB1'LSf0M)U)KiH(L)Q*LSU*L)H'KB@&K)1"IRTfFh*cGAG iGh9bFA&cGhb!K)D(KB5$K)D*M)q4P*@9P*!!MBZ*L)D%Ji5'LBb1NC19PjQEQjU BPjHAPjH@P*'1LiL'KB1!IAPeF'aUDQYXEQjYE'YUDfe`FhCjIS1+NTUKTULQSjq EQTQDR*kHRCQ8MBCrHhYpJ)1%K)1%K)@&Ji+!J)#"JS1#JAplH(CiI)##JS"mGR& `FA0fI)+)Lib-LB0mGh4`E'YZGAf&M*+8NSf(JhpmHhk"K)D)M*5ERjf@LRpjHAf "Ji1"Ii##KBL-N!#9Q*UDQTQBQTkNUUqeZVl![VZhXl'[Vl#aXE+bXl5fZ,c"amh 4dp,1aVkfXDkXUkUTUUkcYlLdV+1DNiq0MC!!P*UKTDQUUDDKR*H9P*@BRkLbZm$ "[VZjZ,Um[EfmZlbp[m$"`XA*c-[(`,DYTk1LSD'KSD'KRjbBNiq+KS1$KBL0P*Z NUl'f[-$%aXI(aXA$`F$"a-I+cFr3dG(3cml-bFM*bml4dpA@eG(*[lD[UkHMRjb DQjqNUDbXUkQQSk#GQTQES+DYXlLq`mR3eGRCeY(-bFM)b-I'amV0d0$1bF+lYE# YV+f[XE+cXV'ZV+ZYX,@iZVZm[EqrZl@ZU+@PTUHPSTfBNiq*JhjlIB''Lj!!NT5 9PC13!)Z'JAajGR4fHS')MT'5NBk-LSQ*L)L)L)Q,MBq3!)q0L)*kFfjUD'CNBf* MC@KUEA"bFh0`E@aXER&eHAf!JS1#J(ejGR9fHRq&LSf2N!#4NC!!Mj!!NTDERU# IRTkIS*qFPSk'IRKeFh4fH(PiGA&ZER"cGA9dFR*bG(GlIAjpIAerJSD*LSU,M)q 5PCQFRTqHRCbFRCqMTkZXUkUSU+LSTU1HQC@5NC+8PC53!)Z'Ji'"JB'"J)"rJB5 )Liq6PTQER*bCPT+1M)b0MBf,LBL*Lik4Nj58P*@AQCZEQCH8Nj'3!)f+Ki5"IhY hF@aSC'&HA&K66NY*58K)4dG(5%P+58G&3Mmq2$Nf-c%b0$Bh1$Nm2N$mq2Mi p2$Si0cFi1$Fe0$8i1MXl2$`m2d4+8&*588p26e"38%p05dT*58Y28P068Np,5%9 #38""3N4&4NG'4%%r26j!4%K08PCCA'&QEA&cFR&aFR0cEfTPB@"JBQ4QD@YZF(0 eGhPjH(GeFh0cGA9eFh"[EQpaFR*bFA&aFA"[F(&bG(4cFh0cFh0aF'pZEfp[F(" aFR0dG(0aEQYUD'CPC'CRD@TUDQTUCf0H@&968e4@9P946NY,69"699956dY+5Ne 49&998e"16P"69eTFA9eHBQGXF(&bFA*bG(9hHAYlHhKfFh*bFh9fGhPlIS'&L)U -MBk3!*+8PTHCQTUCPT+2M)U)L)D$IAGaE'KPB9jE@&C688j06%j59eeLC'*I@eP DAQ4SDQPRC@4NBf*KAeeC8dj*4dG)5%G%3N!r380%4%0%4NP,6P&8@9aHAPeF@PK @88a'36dk1$Fh1$Sm2$Xj0#mV+LSY,c%b-c-d0MJi0cBd0$8i2%"%5%a28P4A@Pj LC@CMA9G468a18&*899KEAQ"LBf0MC'9QCQGTDfpcGhPkHRKhGRKjHhYlHRKiH(K kHhepHhTiGhGiHRf!Ji5$JS+#JS5&KiL(KS5#JS1&KSH(KiH*M*'@R++RV+qaXE# XTk'EPBq+KiD'KB1"J(pqIAYjH(KiHAKhGA4eGA0aEfpaG(ChGh9eGhTqJSD*LSU ,MT1AQCQDQjfFQTH9Nj+4Mif-M)k3!*'4NC+8PjLBPC'1LiH#IAapJB5&Ji'#KBU 4PjQBPT58PCD@PT@@QCkLSk1IQjH8NT+8QD#QUDHMRjfHRjqGQjQCQ*LBQ*H9NSk ,L)D'KB@'KSD'KSD(LBb2NC'2MSq5PTZJT+QZXV@fYVDiZVh!`,fiXUfXVE+fZlr #aXM,c-h0cFl2cX[%ZV#SSU'LTDQVUkQRTkQYXlV"b-r6e024cFR'a-2"[VbjZ,Q l[Vqr[,HaUU5IRCfIT+Q[Y,Hk[,fpZlQiYV5aVDZTUDLSTkHRTU5LS+#KSk1LS*k HSUHZYEc#b-[-c-V*bFR*amA"[ELdVUHIPj14NT+4Mik2NTHFS+1PU+Z[XV1aVUU QSTkDPC+3!*'6PCD6MBD!IRk#L)q8PjH@P*16P*DBQTbIS+#FPT!!LiL)L)Q+LSU *LSb1NC@CRD'PTkQTU+DNSk'KRjfEQ*D@PjLCQ*52LB5$Ji@*M)k1LiH"IATkHhq %LBk5P*56Nj+5NC'6PCHBQ*H9NT!!MBb,LSZ-M)Z*KS1!IhjrJ)'$KBH)L)D&KSL -Mj!!N!#2Mj!!NT5AQCUBPC'1LiU,M)q5PTLCQCQCQjbGR*UAP*'1M)Q(KSD)Lj' @R+#MTUHSUUfaY,HiZELfY,'ZV+QRTU@PT+1LSU'LSkDTVDq`VUQNS*qKTDQYVkq YV+UTUDLRT*qCPC19Q*bISD'JSD'LSk5PT+1MT+DQTD'FPT+3!)q1MBU'JAemIAq "Ji@&KSD(L)L)KS@&KSL,MT!!NT5AQCUEQTQBPT53!)b)KiD%JRjjGA"YDQPUDQY UD'9LB@"KB@&JA9TA9PGA9eC@9eG@9P99@&eNE(*fGhGfGR9dFh"VC9j@8%Y)5%K )4N0!26Xm2N&%4dP,6%e-5dP*5Na16Na*4%!p26ir3%!r2Mdp26dp2N"$4NP-8&4 B@9TC@&KB@&KB@&KB@&PC@ejKCQTYEh"`Efp`FA*dGA9eG(9fGhKjH(GdF@pZE@j `FR*aEQTQBf*MC@PXEQp`FA4iIB'$K)1#JB+%KiQ,LiQ'JAjkGh4aEfj[F(*cG(9 eGRGhGR0YCPpC9&&15dK&3d*$48G+5da068a-6%Y+4d4#38""3dC)5de068e,58G %3N!r2MXi06)[,#JN)4iF'a`H)L8S+LSV,#ia0$8d-c%[,Li`0$P!4NY289*48%e *4N)r2$Sj1$Jf0$%Z,#`X,5mc1$j%58a28&"26dj068e168a-6%j49&GDA&eF@eT D@eeIB&pHA&YD@eaHB'&LBQ0MBf0MC'CRD'KSD@TVDfYVDQPSCfGSDQjcH(YpIRq !JB'"J(pqIAYkH(GfGA4cF'aSC&pE9eC999489&9A@&PEA9pLC@KUE'jaGAKmIS# !JB+$KSQ0N!#5P*@@PjLCQTUER*fHS+1QUDUVUDHNSU#IS+'LT+5NSk+JRTbER*b FQC++J(KcF'jZE@YUD'KTDfe[FA0eGhKiHATlIAjqI(ThGA0aF'pZE@aXDfYVDfY UD'KSDfe`FR0cF@pXD@KSD@YYF(0eGA4bF'p`FR0cF'jXE'jaGAPpJSD*LSZ,LSU *L)L(KS5"IRYjGhCfGhKjHAPjH(KiHAYmI(YiFfjUCQ0KB'&MCQGSD'PYFRPqJ)" rIhjmGh*YDQKSDfpcGRGhGRGjHhf!K)Z5QCfJSk@SUUUSTU5LS*qKTUfcYlQiYE+ ZU+#CP*+9QU#NTkLSUDQUUkf[XE1eZ,c"amh4e0E9dmr,aX2![VZjYl@eYlUr`mM ,cFl2d0,8eYIBfYlLjq[Zm2$[l1MMhYM6cml0cFc+am+mYV#XUDQTUDUVVV1k`FA )b-R+c-r4dG$2cmr4dY,3cFR&`VkkYl5cXl1dYEDfY,+[VDURTD@TVl@jZVZkZ,D cXDqYV+USTU5MT+@QTkDPSk+MT+5KR*@2M)f3!*5BQTbGRk#JRjkFQCD6N!#1MBb +L)@#IhemI(apIRpqI(ThG(*`EfjZE@eYE@YUD'KSDQe`FhCjI(k!JB1%KB@$J(j mI(apIRepIRq"JS+"IhajGR*ZE'YVE'jZEQp`FA0eGRCbE@CKAPeHAf"KBQ0MBQ& KBfGXFRL!KiqARU5TV+k`X,#[V+QRTULTUDHMS*bDQCL@P*'1M)b-MBq3!*+8PTH APjD@PjLDQjbFR*bFR*bGRCfGRTqIS++PUDb[XE+cXl5cXE#ZV+USU+UYX,+bXE# [Vl#aXE'[V+LNS*kEQCLAQCZFRCbEQTZHSUDUVDqZV+LNSCkFQTLAPjD@PC@9PC@ 9PCDCRU1QTkDNSU#JS+'JRTZ@NSk-MBk1MBQ$IAPhGA0`E@YUDQPRC@0LBQ0PCfT XEh&bFR&aFA*dGRPlIAjpHRGcF'eVDQYZFR9hGR9eGACiHAYpIi'%KSQ,LiU)KB& rI(ThFfpVCf9MBQ"IAejHAPjHAPpIAejHAQ"KBf4NBf&JB@4SER0fGhGfGA4dFh* `Efj[F(&bFR*aEfeTCQ4MBf0MBf0LB&pGA9aD9e036Na*4dG+8&GEA9eF@eYE@PK @9&*489*89&456dY'3Mim16Fd-M!`-$%c0MNl1cXl2$dr384)5dj38&"48P058%e +58T18PCC@eaIB@9SDfeZEQj[F(&aFR0dGACfG(&YDQGQC@4MB9pGA&aHB'*MBQ& IA&TB9PC@9eGB@&KB@&TGB'*KAPT988p38eGEA9pKC'GVE@j`FR9fGR4cFh9iHAG cEQPPBPpGA&aGA9eGB'4SDfaZEfp[Eh&fI)1*MT'5NBq1MSq1M)H"HR*UBPT66NY *4N)p1MNl28"#3N&!2Miq3%*&4dP-6e&58P&36dj068j499THB&pF@9968e4@9eK A9PC@9PKC@eaF@PG66de06Np38%p26dp48P*699GEAf*QD@a`FhChGR4cFR&bFR0 cG(9fGRCfGA4cFR"ZDfGNBQ&MCQKSCf9LAPTB9PGDA@"LC'9RD@eaGhf$L)b1MBZ +LSU,MBk2MSZ(Ji"qIi'$K)5%Ji&qHA9bFA&aF'jUCQ0KB&pIAf"LC'CPB9aA999 AA'&PCfGRCQGSDfeZE@YTD'PXFAGmIi'!IRYjGh9dFQpYE'e[FhGlIAq!JS5'KiL )LSb4PTUGRCbER*kJS*kEQCLCQTUCQ*LCQCUCQCLAPT@4MBL%JS1'LSk4Nj58Nj1 6NT'4NC'5NT+4NC19PjD4M)L(L)Z-M)U)KiL)Ki@$JS1&KiL(KS@'L)b3!*@DRU+ PTkLSU+LTUDUUUUQSTkHRTkDPSk#GQjL@P*+3!)q3!*'5P*58Nj15Nj59PT@8NBq -LiZ0N!#5Nj+3!)k0MBb-LiZ-MBk2NC1@Q*QDQCHAQ*UGRk#MTUZ[Xl5dXl1cY,D iZVbq[m#r[lr!`X6(b-M(a-,![Vfp[Vr![lfjYE'ZVDfZVl+eZ,UlZlZlZlZm[Ek q[EZjYV@eYVHj[,kr[VUfXDfVUUZXVV#aXV+aX+kXUD@KRCUCQTfJSkDSUDQTTk@ MS*fEQTUDQjbHRk'MTDHSU+LSU+QUV+fZVUkYVDbXUkUST+'IRTkJSU5QTkLSTk5 JR*UERD#LSk+KSD+NTkZ[XV5eYE5bX+qZVUq`XV'`VDZSTkDNSU#GQjQCQTUEQjZ EQTUEQjZCPj@6NT!!Mif-M)Z+LBL'Ji"pHhTlIS'$Ji&rI(YlIAq#KBQ1NjLFRk# JRTZBPT@8PC@9P*14MSb+LBQ*LSZ0MSq2Miq2MSk2N!#6PCHAPT55N!#2MSf,LBQ +MBq4NC!!MSf,LSL(KS@&KBD(L)L(KS@&K)5%K)5%K)5$Ji1%KBD(KiD&K)5&KSL *LSU+LSZ0MSq2MSf0MT!!NjHERU'NUDkbYVLjZEQiYlHhYVDeY,1aVkbSTD1LSk1 LSD#JSU@RUUZXV+ZVUkURT+'HR*ZDPj11LBD&K)1"IRTfFh&aF'eSBPaC@9YHB@* KB'&MCQPVE'aYE@j[F("[EQeYE'YTCQ0JAPYC9e99999@9PC98e&36Na+4d4#3$m p2$Sj16Sm2NN%r26`m26p"3N*#3N0&5%a38P*58P09@9YGA9aD9e988e489&4 56dY(3cml1$Ji16Sk16Fe-c)b-M3f16e!4%C)58T-6P"699GC@PTD@9G@9eTGB'* KAeaD@9KA9eG@99048%p38P9B@ejIB'"JB'"IAPaE@eYE@PK98e&26%P&36dk16J i1$Fe-LmX+LNT+L`[-M3f16`r3dC*5da-6%e16e&58e9@@9aJC'KXF(4fGR4bF'p `FR0dFh*aF'pZE@aUD'CMB@"IAPeFA&aHAf&MC'4PC@9QCQGSDfjbGRTqJSD*M)k 3!*'6PTQERCbCPC!!M)Q)KiD&Ji&qHhKeFR&aFA&[DfGNBQ&JB'"IAepHA&YD@PY FA9jHAPjGA&TB99*48&&48P089&9@9ePEA9pJAeeD@&GA@9YGAPpIAf"JB&pHA9a FA&jJBQ4PC'0LBQ0NCQPVE@jZEQeYEh&dGRKjHAGeG(4fHAaqIRjqIAjrJ)+%KSH )LBQ)KS5#JB#!JB1%KB@#J(ekHRYpIi"rI(TiGhGhH(PkHhapIAepIRq!JB"rI(P hGR9fGRCfGA0aEfaTCfCRD'PUE'jbGhZ!JiD*LBL'K)*rI(PfG(0bFh0dGA9hHAb !KBL+LiZ*Ki5#JS1'L)Z1N!#4NT18PCHAQ*LDR*kKSU+LSD#IRTbDQ*D8NT'4NC1 @QTfIS+'MSk1LRjfEQjbISU@PT+'IRCZER*bGRCkHS++NTUHRTUDQTkLTUUZXV+f [XE'`VkfXV+bYV+ZSTU1KRjkHRjqIRTfFRCkKSU+KRTZCQ*LCQTUCPj54MSb0MT' 5Nj16P*DCRU+QU+QTUDUVVDk[X,'bY,DiZ,DcX+fVU+DMS*fFR*fHRjqHRCZDQCQ CQCQDQjbFQjbGRU#KSCqHR*ZEQjbFRCfHRTkHRCbFQjZFR*fHS+'LSk1LS*kGRCf HRTbCPT14NC1AQTbGRU#MTUUYVkq[VUfYVl#aXV1dXl+`VDZVUkZUTk+GQ*@8PCD AQ*UFRCqKSU1NT+5NSU'HR*UBPT54MSb+LBQ+Lib0Mj'6PTQERCkIS+#JS+#IRTb EQTUDQCLAQ*QERCqKSU+JRCU@NT!!Miq3!*'5P*@@PjLBPjD@PTHBQTbHS++MT+@ PTD5LRjbCPjD@PTD9P*+3!)k-LSL&Ji+"J)"rIhjqJ)+%KB@$J(elHhaqJB@*MBq 3!*!!Miq2MSf,LBH'KSH(L)L(KiD(KiL*LSU+LiZ-MBk1MBZ(JRjkGhCfGhKjHRT kHRTkHherJ)'#Ji1&KiL+LSU+LBQ*LBL'K)*rIAYlHhYmI(epIS##KBH*LiZ,LSU +LSb0N!#6PTLERCfGR*bER*fGRTkIS++NTD@PSk#GQ*54MSb+LBL(KB5#JB"qI(T hGA4dG(9eGA9fGRCeGRGjI(k!J)#!J)'"Ji5&KiU-Mj+8P*55NC!!N!#3!)q1M)U *L)L)L)L(KS5"IRYiGhChHATlHhTjGh9bEfeVDQPSCfCPC'4NC@9RD@aZF("[E@Y UD@TVE'aXE'YVE'j`FhCiHATlHhapIAakHAPjHRYkH(CcFR"`F(&bFh4dFh&`Efj ZE@TSC'"G@PC88P&38&"36Ne-6P&9@f"NCfKRCQCPC@CRD@YYEQp`F("`F("aFhC iHRPiGA0aFA0hI)'&KSD%JS#!J)"rIAYiGA0bF'jVD'CQCQCRD@TVE'aXDfPSCQ9 MBQ*KB@&KB@&LBQ*MBQ&IAPeFA9jJB'"IA9TA9&*48%p168Y)480#38&"3N4'58Y -68j26e"489&58e999P999&069&499PGB@9TD@eYGB'4SDfj[EfpYDfPRC@*I@eK @994688p168e06%Y*5%K*5Na16Nj068e-5NP)58e499PEA&eIBQ9SDfeZEQeVD@G QCQGTDQTTCf4KB'"LC'CSDQYVDQPRC@*IA&P@8e"05NK(4NC'4NC'4NC'4dG)58a 28eGD@eYE@eeHB'*MBf4NC'4PCQGSD'KRCQ4LAeaC9P989&4999CA@9YIBfKXF(4 fGRCeFh*`EfjYE@aUD'9LAejIB@4QCfKSD@TVE'j[FA4eGRCeFh&`Efp`FA*cFh4 eGRGiHATlIAeqIAalHhapIRjpHRCcEfeVDQPSCf9LB&pIAepHA9YC@&KB@PjLCQP YF(0fHAYmI(apIi'%KiU0Mj'4NT+6Nj15NC!!N!#3!)q0LiL&JS"rIRemHhapIi' #K)@(LBb1N!#4N!#1M)Q'Ji&rIRjqIRprJ)#"JB+%KSU1NT@@PT@6NBq1MBb,LBD #IhepI(apIAerJB5(L)L(KSD(LSf2Mik-LSQ*Lik3!*'3!)k,LBH'KiQ+LiU)KS5 #JS1&KiL*LSZ-MT!!NC+6Nj15N!#2MSk2NC+8P*58PCHDRU+NTUHSUkkbYEHjZEL iYlDfYVLk[F$"`F(!`-(#`m2#`,kq[m,&aXE%`F#r`F6(b-R*b-I(b-R*bFM)b-M *bXV,bmV*amA$`F$!`-$!`,qr[lqr[lflZ,@bXE'bXl1bX+kYV+fZX,+cY,@dY,1 bXE'aXV1eYVLk[F(%aXE&a-'r[Vfq[Vqr[VblZVUl[,blZ,1ZUUHPSk+KS*kHRTk HRk#KSU+LSU+MT+@RUUbYVDbVUDHPSk+KSD'JS*qHRTfHRk#LSk1LRjZBPC16Nj+ 4N!#2MSf0MSk3!*+@QCbHRTkGR*ZDQ*H@PC15NC!!N!#2Mik1MSk2NC5@Q*UEQjZ FRCqKSU+LSD#IR*Q@Nj!!Mik2N!#4NC'3!)q3!*+@QTkLTDHRU+LTUkbXUULPSk' KSD'KSD#IRCbDQCQBQ*D6Mib+LSZ-MBk0M)b-MBq5PCHDQjZDQCLCQTZGRjqHRCZ CPjD9PC@AQCZGRTfFQTQBPjD9P*15NT+5NC'3!)q1M)U)KB*qHhKfGR9dFh&`EQa UD@PTD@YXE@j[F("aFR*cFh*bFR4fHAarJS@(L)Q*L)H'KB@&KSD'KB5%Ji+#JB# !J)'#K)@&KB5&KSL+M)b,L)D&KBD)LBU+LBL)LBZ0Mj'6PCHDR*kIRTbCPj55Mik -LSL'KB@'KiH(KS5#J(q!JB+$K)5%K)1#JB#!J)+$K)5#J(ajGA*`E@TRC'&IA9a E@PPB@&PEAQ*PCfGRCfCQC@9PCQ9PC'0LBQ*KB@"IA9eFA&aE@PK@99999PGA9PC 99&*36dj06Np389*58P*48P*699GB@9TD@9PC@9PD@9KA9PCB@PYFA&aD@9KA9P9 68P&38%p26Nj168e,5NP(4NC%3d&!2cip26dm2$Xj1$Fh1$Xq380$3d0#3N*#3N* !2M`k16Nj1M`q2d"!38d0$3N&!2cmr2d""3N4&4NG)5%G(4NC(5%P+6%j389& 46dj06%Y-69"69PKD@eaGA9aGA9jHAPeE@PKA9PCA@&TEA9pJBQ4PCfKTDQYXE'Y VDQPSD'KRCQ4MBf4PCQKSD'GPBQ"HA&TB9P988P*58e9B@ejKBf4PC'4NC'4NBf* KB'"IAPjHA9eGA9eHAQ"LC@KUDfYVDQTUDQYVDfYUDQPTD'KSD@PUDQTTCfCQCfK TDfaXE'aXE'eYEQjZEQp`FA*cGACiHRerJB5'LBb1N!#4N!#1LiQ)KS@%K)1$Ji+ #JAppHRKfGRCfGhKiGhCfGRGjI(k!JB'!IhjqIRjqIi##K)@(LBU,M)f1MSk-LSH $IhelHRPiGA0aF'p`F(&aFA&aFA&aF'pZE'YTCf9NBf*JAeeFA&eHAf&LC'9QCfG SD@YYEh"bFh4eGRCfGRChHAYpIRjpI(YkHAKhGR9eGACfGR9eGAChH(PjHRYmIAp rJ(prIRepIAamI(alHRPiH(TpJSD+M)b,LBL)L)L)KS@#JB"rJ)#"Ji@(LBU+LSU +Lik4Nj@9PC15NT16Nj+3!)k-LiZ-M)f-LiZ+LSU,Lib-MBk3!*1BRD'NTUDPTD5 PTULUV+fYVDfYVDfYV+bXV+fZVkq`X,'bXl5dXl+bXV+dYEDfYV5cXV+bXl5eYVH iZVZlZlZlZlbm[Er"`m6%aFA%`m,![VZjZ,HiZEUm[Vr!`,qpZlQiYlLiZ,DdXDk VUDHQT+'HQTH8NT!!N!#3!*!!NC'5P*@AQCUER*bFR*bFR*bEQTQCQCUER*bDQCL APTD@PTHAQ*LBQ*LBPjHAPT@8Nj+4N!#1MSk2N!#5Nj56NT'3!)q1MSq3!*+8PjQ FRk'KSD#IRk'NU+b[XV5fYlHhYV@cX+bRSTfCPC+3!)k0M)Z,M)k2NT5AQTkKTDL UV+fYVDbXUkQSTkDPSk+KSD'MT+DRU+LTUUbYVl#aXE'`VUkZVl#aXV#ZUULQTUD SUDUTTk5KRTbFR*fGRTqJSU@SV+qbY,DiZEZp[m$![lflZELfYE1aVkfYVUq`XE' bXV'[VUfVUUQSTk@MSCkEPj54MSf0M)Z*L)D&KBD(LBZ-M)b-MBk2N!#5Nj58P*5 8PCDAQ*QCQCQDQTZFR*bEQTQBPjD@PTD9P*+3!)k0M)U)KS5"IhjpI(YkHAKiGhG hGhGiH(KiGhGiHAYpIRq!JB'!IhelHRTkHhYmHhYkHRTlHhYkHAPiHATmIS'$K)@ %K)5%KBH*LSb-MBf-LiU+LSU,M)f1MSk0LiQ)KiH)LBU,LSL'Ji+#K)D*M)f1MSf 0MBf0M)b0MBk0LiQ(KB1#J(jmHACaE@TRC@4NC@9QCfKTDfaYEQj[Efp`FA0dGA9 eGA9dFh&ZDQGNBf0MC'4NBf*KB@"KB@&KB@*LBQ*LBQ*LBQ*MBf4NC'4MBf0NC@C PC'&IAPjIB'*MBf*LB@*MC@KUE'eYDfTTD'GRCfCQC@9QCQGRD'KRCfGRCQ4MBQ& KB&pG@eK98Np-5NK(4N9&4NG)58T08&4B@PaFA&eHB'"KB@&LBf9QCfGQC@4MBQ" IA9YD@&G@9P9999998e&16%P(484#3$mp26`p2Miq26dp2N""3N0&4NG(4dG&3d% q2$Nh063c-M)d0MJl2N"$4%C(58Y-68e06%a-68j389*48%j-5dY-6%e-5dP)4dC &480"2cdm2$dq2Mp!3%&"3N*#3N*#3d0%48C'4N9&489&4NC(58a28PCDAQ&PD'T YER"`FA&aF@pZE'TSC@0KAejGA&aFAQ"LBf4PCQGRD'PTDQYXEQp`F(&aFA*cFh0 aEfaUD@PTDfaZF(&bFR0dG(9fGR9dFR&aFA*dGRKjHAPhGA0aEfaTCf9NC'0KB&j GA9eHB'*MC@CQCfPUE'jaFh9hGhGfGR9fGhPlIAprJ(prIRjrIhprIRjqIRjrIhp rIRakH(CdFh*aFR*cG(9dFh"XD'4KAepIB'*MC'4MBf0NCQKVE@paFhCkIS+'LSb 0MBf-LiU*L)H'K)1#JB"rIRepI(alHhTkHAPjHRTjHAKiHAPjH(GfGACfGRChH(P lIAq"Ji1$JAppI(YlHhYkHAKhGR4bFR*bFh4fGhTpJB5'L)U+LiZ,LSQ*L)Q+M)k 2N!#4NC'3!*!!Mik0MBf0MSk1Miq3!*'6P*DAQ*QCQCQCQCQCQCUEQjUBPjD@PjH BQ*LBQCZGRTqJSU5RUUbZVkq`XV5fZ,QkZELfY,1bXE'aX+qYV+ZUUkbZX,#`Vkk XUkZVUkbXV+bXV+bZVl'bXV+aX+qZVUkYV+USTkHRU+QUUUQSU+LTUkk`XV5eYlQ l[X(%amV-cFl2cmr3d0(4dG(3d-r1cXh0cFc+amA$`F,$a-E'aF2![EUiYV@eYE5 dY,1cXl5dXl+aVkfUUDQTUDQSTU5MSD#JRjqJSU5QU+UXVl'cYEDiZEQjZELfXl# YUUHNSCkEQCH8NT!!Mik2N!#5P*@@PjD8NSk+Ki5#J(jpIAeqJ)1&KSH(KiH)LBU -MBk1MSk1MBf0MBf-LiU+LiZ-MBk1MSk2N!#3!*'5Nj18P*15NC!!MSf-LiU*L)L )LBU-MBk1MBf-M)b-M)f0MSk1MSf-LiQ)KiD&Ji"pHRKfGRChHAYpIi#"JB+%KSQ 0N!#5PCHDR*kJSD'KSU+MT+@PTD5MSk1NT+@PTD5NSk1MSk+LSk5PTUHRTkLSU+L SU+LTUUZYVUq[X,'aXV+aX,#[VUfVUDDNSk+LSk5NTD@PTUDQTUDPT++KRjbDPT1 2LiH%JS'!J)'"JS1%KBD(L)Q+Lib0MBk0MBb-LiU+LSQ)Ki@%JS"rIRakH(9cFR* bFA"ZDQCMBQ*MC'9NBf*KBQ0PCfKTDQPTCfCNBQ"HA&TC9eC999489&489&499PG C@PYFA&eHB'&MC@9PC@4NC'CSDQaZEQjZE@jZEfp`FA*cG(4cFR&`F("aFR*cFh0 dG(9eGA9fGhPlIS'%KSL+M)k3!*'5Nj+4Mik-LSL(KS@%Ji'!IhjqIAalH(4aE@Y UD@PTDQTUDQTUDfYXE@eXDQKPBf*KB@*NC@9QC@9NC'4PCfTYEh&cGAGjHheqIRj pI(PhFfpVCf0KAPaE@PKA990589"389&48P0899CA@&KC@9PC@9PD@PYFA9jIB@0 PCfKTD'CNB9jF@eTC@&G@9&468P&36dj-5dT*5%K*58P+5da06Np38&"38&"48P4 99PGB@&PC@PYFA9jIAf"KBQ0NC@4NBf0LB@&JAepIB'"JB&jF@eTD@eYE@eYD@9K A9eGB@9PD@9K@9&&05NG&3d&!2cmr3%&"38&"3N0%4NG)5Na28PCDA@"KBf9QD'P UDfe[FR0cFh0cFh0bFA"ZE@aVDfYUD@KQBf&HA9aFA&YE@PKA9eGB@9TE@eaGA9j HA9aD@9KB@&KC@PYE@eTC@9PEA@"MCfTZFA0eGRGiH(KiGhCdFh&`EfjYE'aXDfT UD@KSD@TVE'eYEQj[F(&bFA&`Efp[EQeVD@KQC@9PC@4NBf0MC'9QD@YZF(*dGRG jHhapIAepIAepIAjqIhq!J)"rIi#!JB+$Ji5%K)@'KiL+M)f0MBb,LSQ)KiD&K)1 "J(jpI(YkHAKiH(PlI(eqIRjpIAamHRPfG(0bFR0dGRGjHRYmIAeqIi#"JS+$Ji1 $K)5%Ji'!IRalHAKhGhGiHAYmIi'%KSL+Lib-M)Z+LSQ+LSb0N!#5PCLERD'NTkZ ZXE1eYlLiYl@cX+fUTD#EPT+2MSf1N!#5P*DCQjbGRTfGRTqJSU1NSk1LSD#JSD' KS+#IRjqIRjqIRTZBP*!!M)H%JAprIi#!IhjpHhYlI(k!Ji@(L)Q)KiD&K)1$K)@ 'KiL)L)H(KS@&KBD(L)L*LSb1N!#4NT'4N!#3!)q2Mj!!NC'4N!#1M)Q(KSD'KiL +Lib0MSk2NC19PjQERCkJSD1PTkQVVV#dYlQl[,kr`F2&amM)amA#[lbkZVUl[,b mZlUjZEUl[Ekq[VfmZlZkZELhYE5bX+fVUDLRTU@MSU'KSU5QTkLTU+LSU+LSTk@ MSCqHRCfFR*bGRCkIS+'LSk5NTD@PTULSUDQSU+DPSk+JRjfEQTLBPjH@PT@9PC@ @PjLBQCLBQCQER*kJSD+MT+DRU+UVVDk[X,'aX+qYV+bVUkZXV+bVUkQTU+HRTU@ NSU'JS+'LSk5PT+1JRTbEQjbHRk#IRjqISD1PTkHRTk@NT+@QTkLSTk@NSCqGQjL @P*'1LiL'K)1#JApmHACcFA"`FA*bFh0bF@pYDfKQC'0MBf4QD'TYEQpZEQeXE'Y VD@KRCfPUE@p`FA&bFR0eGhKkI(q!JS1%KSL*Lif1Mik1M)Z+LSU+LSQ*L)H'KB5 #JAprIhjqIAakHAKhGhKjHherJB1&KSH)LSZ-MBf0MBf0MBk2Mj!!NC'5NT59PjL CQ*H9Nj!!MSb,LiU+LSU,LiZ,M)b-M)Z+Ki@#IhemHhamIAeqIi##KBL,MBq4Nj5 9PTHAQ*HAPC55N!#1MBb-M)b0MBk2NC1@Q*UER*fGRCbEQCLAPjDAPjHBQ*QCQjb GRk#JSD+LSk1MSk1KRjbCPT13!)k-LiU*L)H&Ji+"J)#!IhpqIAepIRjqIRjpI(T iGhCeGA4cFR"YDQCMB&pHAf"KB@*LBQ&KB'"HA9aE@PPB9eC88P"05dP(4N9'4NG )5%P*58P*58K)4dG(4dG(4dG'489%4%0$3d*"3%!r2cip2$Xj0cBe0MFj1M`p2Mp !3N0%48G)5Na06Np28&&489&36de068e16Nj168e16e&699GB@9PB@&KB@&PD@ea GAQ"KBQ*MC'CRD@TXE'eYEQj[F(*cG(4dFh&`Efp[EQeXDfYUDQPTCfCNBQ"G@eP A99046Na*4d9$3N*$4%C(58T-68p38P0899C@9eKC@eaFA&YD@9G@99468e*488p 16%Y+5NP+5NY,6%a-6%a06P"48P089&9999CA@&PD@PTC@9PC@PYHB'*NC@GSD@Y XE@eZEQjYE@aXE'aXE@jZEfpZEQjZEQp[F("`F("`EfjYE@eYEQp`FA*bFh0cG(9 fH(TlI(epIAemHhTiGR9dG(4dG(0aEfaTCf9NBf4PCQGSD@PTD@PTD@PUDfe[FR9 hHATkHRTkHRPjH(GfGA4cFA"ZE'YUD@PTD@TUDfaXE'aXDfTTD'KTD@TVDfaXDfY XE@pbGAKlIB##K)@'KiH(KiH'KS@&K)5%KB@&KB@&KB5%K)1$Ji5&KSL*LBU,M)f 2NC18PCDAPjLBQ*H@PTDAQTfKT+DQTUDPTD@QTkQUUkUTTk@MSU'JRjkGR*ZDQCL @PC14Mif,LBH&Ji'!Ihq!JB1%KBD(KiH)LBZ1N!#6PCHCR*kKSk5PTD@NT+5NTDD SUDZXV+bVUUUTUDQTU+HQT+1LS+#JS+#JS*qIRTfFQjUBPj@8Nj+4NC'4NC'5P*@ @PTD@PTHCQjqLTDLTUUUUUDQTU+LSTkHQTUDQTUDQTU@PT+5NSk1LSU'JRTfEQTL APjD@PjLCQTZER*fGRTqIS+'MT+@RU+LRTU@NSU'KS*qIRTkGRCbEQjZFRCkGR*Z EQTUDQTUCQ*H9Nj!!Mif-M)b-M)f0MBk1Mj'5Nj@@PjQERU#MT+DRU+QUV+f[Vkq ZVUk[X,+dY,5dXl+aX,#[VUbTU+HRU+QUUUUTU+DPT++KS*qGR*ZDQCLAPC13!)k ,L)D&K)1$K)D(LBZ0Mj'6P*@9PC@@PjQDQjZEQTLAPTD@PTD@PTD9PC@9PC@9PC5 6NT'4NT19PTLCQTUDQTUDQTUDQTUDQCQBQ*LBQ*LBPjD9P*16NT+5NT+6P*59PjL CQTUCQ*HAPjHBQ*LCQCUEQjbFQjZEQjbGRU#LSk1LSCqHRCfGR*ZCPj55N!#2Miq 2Mik1MBf0MBf0MBk1Miq2MSf-LiQ(KB1"J(jmHRKfG(0bFA"[EQjYE@eYE'aUD@G PBf*KB@&LBf0MBf*LBQ0PCQKUDfaYEQj[F(*cG(0cFR&aFR0fH(TlI(epIRq!J)' "JB'"J)#!J)#!IhprIRjpIAamI(aqJ)+%KBD(L)L*LSU,LSU*L)D'KSD'KSD'KS@ %Ji&rIRepIAemHhPhGR4dG(9fGhKiHAPjHAPiH(KiGhCdF@jVCf0JAPaE@PPB9eC @99468P*58e499PKC@PYFA9jIB@*MC'9RD'TVE'eYE@aXDQPSCfCQCQCQC@4MBf0 MBf*LBQ&KBQ*MC'9QD'PUDfYVDfYVE'j`FR4fGhKiHATmIAjqIhpqIRjpIAamHhT jH(GhGhKjHRYlI(amHhYjH(CdFR&[E@YTCf4KAeaE@PTEA&jIB'"JB'&KB@*MBf0 MBf0LB&eD9P*25dP'3d!q2$Xl1MSj0cBe068f0cJk2$dq2dd4'4dG(4N4$3d0 %48G)58Y,6%a-6%Y,5dY-68j389&58e9@9eKD@eaHAf"JB@*LBQ&JAepHAf"KBQ0 NC'9RD@YYEh"aFR0dGAChH(KiGhCeFh&[EQaXDfTTD'GQC@4MBf*LBQ*LBf9RD@Y YEQp[F(&bFR0cFh0bFA"[EQeXE'YUD@KQC@9PC@9PCQGSD@TVE@j[F(&bFh0cFh0 dG(9eGA9dFh*aFA&bFR0cFh*bFR0eH(TpIi#"JS1%KBH)LBU*L)D&Ji+"JB'!Ihj pI(YkHRTkHRPjHAPkHhamIAepIRjqIRepI(YjGhCeG(4dGA9eGAChGhKjHATjHAP jHRTlHhYkHAPiH(KiHATkHRTjHAKiH(KiHATlHhYlHRTkHAPjHATkHhaqIhq!J)# "JB+%KBD'KSD'KiH)LBU,LiU)KS@%Ji1%KBD(L)L)L)L)L)L*LiZ-MBf1Mj'6P*D BQCUEQjZEQjZER*bGRCfGR*ZDQCH@PC56Nj16Nj15NC!!Mik-LiU*L)L)L)Q*LBQ *LSU,Lib-MBk3!*'5P*@@PTHAPjH@PTD@PC@9PC@9PC58P*59PCD@PC56NT'4NC' 3!*!!Mik0M)b-MBk1Mj!!N!#3!*'4NC'4NC'3!*!!Mik0LiU*L)L(KiD&KB@'KiL +M)f1Miq1MBf-M)f1Mj'5Nj59PTHBQ*LAPjD9P*58P*58P*58P*58P*58PC@AQ*Q CQCLAPC15N!#2Mj!!N!#4NC!!Mik-LiU+Lib0Mj!!NC+5P*@AQ*UFRCfGRTqJSU5 PTUDPT+5NT+5PTUHSU+HPSk'JRjqIS+#KSD'LSk5QU+UXVDq`X,'bXl5eYVDfYE5 cXV'`X+qZVUfYV+bXVDf[X,'aXV1cXl1cXl1cXl+bXV+bXl1cXV+aVkkXUULQTD5 NT+5MSk1MSk5PTD@QTUDQTUDQTU@NSk'JRjqHRTkGR*ZDQ*D9P*58P*58P*58Nj1 6NT+5NC+5NT16Nj59PjLDQjZEQjUCQCLAPT@8P*59PC@9PC55N!#1MBf0MSq3!*+ 6P*@9PC58P*15NC!!Mif-M)Z,LiZ,M)b-LiZ+LSQ*LSU,M)b-MBb-MBf0MSk2Miq 2MSk0M)Z+LSQ*L)L(KSD'KiH(L)H(KS@&KB@'KSD&K)1#JB#!J)"rIhpqIRjrIi# !J)#!IhjpHhYkHRYmIAjrIhprIAalHhYlI(YlHRPjH(KiH(GfGA4dG(4dG(4dG(4 dG(4dG(4dFh0bFA"[EQeXDfTTD'GQCQCQCQGRCfCPC@9PC@CQCQCRD'PVE@paFR* cFh4eGhKjHRTjH(GfGA0bF@pZE@aXDfTTD'GRCfGRCfKSD'PTDQYXE'eZEQp[Efj XDfTTD@PTD@KSCfCPC'0MBQ*KB@&KB@&LBQ0MC'4MBQ&HA&YC9eC88e&38&"38P0 8999@9PGB@9TFAQ"KBQ*MBf4PCQGRCfGRCQCQCQCRD'PTD@KSCfCQCQCQC@9NC'* KAejGA&eHAf&LBQ*LBQ&KB@&KB@&KB@"JB&pIAepIB'"JB'&KBQ0PCQGSD'PTD@P TD'KSCfCQCQCQCQCPC@4LB@"IAPpIB'&LBf0MBQ*MBf4QCfKTDQTTD@KQC@4MBQ* LB@&KB'&KBQ*MBf4NC'9QCfKTDQTUDQTUDQTUDQTTD'GQC@4MBQ&JB&pIAepIB'& LBf0MC'4MBf4NCQGSD@PSCfGQCQGSD'PUDQYVDfYXE'eYE@aXE@eZEQjYE'TTD'G RCfGRCfCQCQCQCQ9PC'4MC'4NC@9PC@CQCQ9PC'0LBQ*LBQ*MBf0NC'4NC'4MBf0 MC'4PC@9QC@9QCfKUE'paFh4eGRCfGRGhGhGiH(KiGhCeG(*aF("`F("`EfjYE'Y VDQTUDQPSCQ9PCQKUE'pbG(GjHhk!JS1%Ji1#JB#!JB'"JB"rIRepI(apI(amHhT kHAPjHAPiH(KiH(KiH(PjHATkHhYlHRTkHRTlI(erJ)'#Ji5&KSH)LSf2NC18P*5 8PC@9PC@9PC@@PTDAPjD@PjLCQTZFR*bFR*fIS+'KSD#IRjkHRCfFQjUBPT55NC! !Miq2Miq2Miq3!*!!NC'6P*@AQCZGRk'LSk1MSk+KS*qGQjUBPjH@PC@8NT'3!)k 0MBf0MSq2N!#3!*!!Miq2N!#3!*!!N!#3!*'4NC'5NT16P*59PTD@PT@9PCD@PjL CQTUDQTZFR*fHRTqJSD'LSU+LSU+LSU'KSD#IRjkGR*UCQ*H@PC@9PC@@PTH@PT@ 9P*16P*58PC58Nj16Nj58PC@9PC@9PCD@PjLBQCQDQjbGRTqJSD#JRjkGR*ZDQTU CQCLAPjD@PTD@PjHBQCUER*fGRCfFQTQAPT56Nj+4N!#2Mik1MSk2Miq2N!#3!*! !N!#2Mj!!N!#3!*'5Nj18P*16NT+6Nj58PC@9PC@8P*56NT'4N!#3!*!!N!#4Nj5 9PTHAPjHBQ*QDQjZER*bGRCkHRTkIS+#KSU1MSk1MSk1NT+5MSk+LSCqGQjQ@PC1 5NC!!MSb,LSQ*LSU,MBk2N!#4Nj59PTHBQ*LBPjHAPTD@PTD@PT@9PCD@PjQERCk JSD+MSk1MSk1MSk1NT+@PTUDQTD@PT+1MSU+KSD'KSU1MSk1MSU'JS*qHRCZDQCH 9P*15NT18PTLDR*fISD1PTkQTUDHPSk'JRTfEQTLAPT56NT'4NC+6P*58P*15NC! !N!#2Mik0M)Z+L)D&K)5$Ji1$JS'!IhjpI(alHhYkHRPiGhCeGA9eGA9eGA9dFh0 cFh*bFR&`EfjZEQj[Efp[Efp[F(&cG(ChH(PjHATlHhYlHhYlHhYlHRTjHAPjH(K iH(KjHRYpIRq!JB'!J(pqIRjpIAjqIRq!J)'"JS1$K)5%Ji1$Ji+"IhjmHRKfGA0 bFR&aF(&aFR*cFh4eGACfGRGhH(PjHAPiH(GfGA9eGAChGhKjHATlI(amI(YlHha pIAepIAalHhYlHhYmI(apIRjrJ)#!J)#"JS+#JS'!J)#!J)#!IhpqIAamHhTjH(G eG(0bFA"`Efp[Efp[EfpZEQj[Efp[Efp[EQj[Eh"aFR*bFR*bFR0cG(4dFR"ZE'T TD'GQCQCPC@0LB&pGA9eGAPjGA&TB9P989&488e068P*58e068e068e068e*589& 48P*68e058P*489&489&489&489&489*68e068P&36dp26dp26dp26e&59&GB@PY FA&jIB@*MC'4MBf*LB@"JAeeFA&aFA9eHA9aF@eYEA&eHAf&LC'CRD'PUE'eZEh& aFR0dGAGiH(KiGhGfGRCfGRCfGRCfGRCfGA9eGA4cFh&`EfjYE'aXE'YUD@KRCfG RCfGQC@9NBf0MBQ*KB&pHAPeFA&aFA9eGA9eGA9eGAPpJB@&KB&pHA9eGAPpJB@& LBQ0MC'9QCQCQCQCQC@9QCQGRD'KRCfCPC@9PCQGRCfGRCfGRD'KSD'KRCfCQC@9 PC@9QCQGRCfGRCfKSD'PTD@KRCQ9MBQ"HA9aE@PTC@9PD@eaGAPpJB@&LBf4PCQG SD'KSD'KRCfKSD@TVE'j[F(&bFh0cFh0bFR*aFA&aFA*bFh4eGRGjHRaqJ)'$KBD (L)L)L)H(KiH(L)L)L)L)L)L*LBQ*LBL(KiD&KB5%K)1$JS'"J)#!JB'"JS+#Ji1 $JS+#JS1$K)@&KS@&KB@&KB@&KBD(KiL*LSZ,M)b-MBk2NC18PTHBQCUDQTUCQCQ BQ*LBPjHAPjLCQTbHRk#KSD'KSD#JRjkFQjQAPT@8Nj+4N!#2MSk0MBf1Mj!!NT1 8PCDAPjHAQ*LBQ*QCQCLBQ*LAPjD9P*15NT+4NC'3!*!!N!#3!*'5Nj@AQCZGRk# LSk5PTUHSUDUVUkZUUUQSU+QTUDUUUDQSU+LSUDUUUkZXV+fZX,+cY,@fYE@dXV' [VUfXUkUSTk@MSD#HRCbFR*bGRCfGRCkHRjqJS*qJS+'KSU1MSU+KSD'KSU+LSD# IRTfEQjUDQTUER*fHRTqJS+'LSk5QTkQUUUZUUUQSTkDPT+1KRjfDQ*D9Nj'3!)k -LiU*LBQ*LSb0MT!!NC+5Nj58PCDBQCUER*bGRCfGR*bGRCfGRCfGR*fGRCkHRTk GR*bEQTUCQ*LAPT@9P*58PC58P*16Nj16P*59PC@9P*15NC'4NC'5NT16Nj59PTH BQ*LCQCQDQjZEQjUCQ*H@PT@8P*14N!#3!)q1MSf0MBf0MBf-M)b-M)b-M)b,LSL (KS@%Ji+"J(pqIAeqIRjrIhq!J)+$KBH*Lib0MSq3!*!!NC'4NC'3!*!!Mik0M)b ,LSQ*L)Q*LSZ-MBk2Mj!!N!#4NC+5Nj@@PjHAPTD9P*15NT+4NC!!Mik0MBf1Mj! !N!#4N!#3!)q2Miq2N!#3!*!!N!#3!)q1MSf0M)b-M)f0MBk1MSk1MSk0M)Z,LSU +LBQ)L)H'KB@%K)5&KSH)L)L)KiH'KSH(L)L)L)L(KiD&KB@%K)1#JB"rIhq!J)" rIhprIhprIhpqIRemHhTkHAKhGR9dG(4dFh0bFR*aFA&aFA&bFR*bFR0cFh0cG(4 eGRGiH(PjH(KiGhCfGA4cFR&`F'pZE@aXE'aXE'YVDfTUD@KSCQ9PC'0MBf4NC'9 QCQCQCQ9NBf*KB@&LBQ*LBQ*KB@*LBf4NC@9PC@CQCfGSD'KSCfCPC@9PC@9PC'4 NBf0MBf0MBf*LBQ&KB&pHA9aFA&aGA9eHAPjHAf"KBQ0MBf0LB@"HA9aE@eYFA9j HAf"KBf9RD@TXE@jZEfp`F("`F(&aFA&aFA&`F'p[EfjZE@eYE'aVDfTUD@PTD'K RCfGRD'KTD@PTD@KRCQ9MBQ&KB'"JB'"JB'"JB&pIAepIAepIAepIAepIAepIAf" JB'&KBQ*LBQ*KB@&KBQ0MBf0MBf*LBf0PCQGSD@PTD@TUDQTUD@KQC@4NBf0MC'4 MBf0MBf0NC'9QCQGSD'PTDQYXEQpaFh4fH(TlI(epIAemI(alHhTjH(GhGR9dFh* aF("`F("aFA&`EfpZE@YVDQPRCQ9NBf*LB@&KB@"JB'"JB'"JB@&KB'"JB&pIAep IAepJB'"JB@&LBf0MBf0MBf*LBQ*MBf0MBf0MBf0NC'9PC@9PCQCQCQCQCQ9PC@9 PCQCRCfKRCfGQCQCQCfKTDQYXE'eZEh"`FA*bFh4dGA9eG(4dFh0bFR*bFR0dGAC iHATlIAk!JB1&KSH)L)Q*LBL)KiH(KiH(KiH(KSD'KiH(L)L*LSU,M)b-M)Z,LiZ ,LiU+LBQ*LBQ+LiZ-LiZ,LiZ-MBf1Mj!!N!#3!*!!N!#2Miq1MBf0MBf-M)Z+LSU +LSU,LiU+LSQ*L)L)L)L*LSZ-MBk2Mj!!N!#4NC'4NC'4NC'4N!#2MBb-M)f1Mj' 5Nj@@Q*QDQjZFR*bFRCfGR*bFQjZDQCQCQCQCQCQCQ*LBPjD@PC56NT'3!*!!N!# 3!)q2Mik1MBf-M)Z,LiZ,LSU+LBQ*L)L)L)L*LBU,Lib0MBk2Mj!!N!#4NC+5NT+ 5NC'4N!#3!*!!N!#3!*!!N!#3!*!!N!#3!*'4NT19PTHBQCQCQCQCQ*LBPjHAPjH APjHAPjLBQCQDQjZFR*fGRTqKSU1NTD@QTUDPTD@PTD@PTUDQTkHRU+LSTkHQTU@ NT+1LSU'KS*qHRTfGRTkHRTfGRCbEQjZER*bGRTkIS+#JSD'KSU1NT+@PTD5NSk1 LS*qHRCbEQjZEQTUDQTUDQTQBPjD9P*56Nj+5NC!!MSf-LiU*L)H(KiH(KiH'KSD (L)L*LBU+LiZ,M)b-MBf0MSk1MSk1MSk2Mj!!N!#4NC'3!*!!N!#3!*!!N!#3!*! !N!#3!*!!N!#3!*!!N!#3!*!!N!#3!*'4NC!!Miq1MBb-M)b0MBf0MBb,LiU+LSU ,Lib-M)f0MBk1Miq3!*'5Nj18P*@9PC@9PC@8P*16Nj18P*58PC@8P*16NC!!Mif -LSQ*L)H'KB5#JB#!J)#!J)'"JB'"JB'#JS1%KB@'KiL*LBU,M)f2N!#4NT16Nj5 8P*58Nj16NT'3!)q1MSf0MBf-M)b-M)f0MBk1Miq2Miq2MSf0M)Z+LBL)L)L*LBU +LSQ*L)L)L)L(KiH'KS@&KB@&KBD'KS@&KB@%K)5%Ji1$Ji1#JS+#JB'!IhjpIAa mHhTjH(GfG(0cFR*aFA"`Efp[Eh"`FA*bFh0dGAChGhKiHAPjHAPjH(GhGRCeGA9 eG(4dFh0cG(4eGA9eG(9eGA9eGA9eGA4dFh0bFR&aF'pZEQeZEQjZEQp[Eh"`FA* cGAChHAYmIRjrIhprIRjpIAalHhTjGhCeGA4cFh*bFA&`F("`F("`F("`F'p[EQe YE'aVDfYUDQPSCfCQC@9NC'4MBf*LBQ0MC'9QCfKTD@TUDfaYEQp[EQjYE'YVDQT UDQPTD'GRCQ9PC'4MB@"IAPeGA9eGA9eHAPjHA9eGA9eHAPpIAejGA9aFA&aGAPp JB@*LBQ*LB@&JB'"IAepIB'"JB'&KB@&JB'"IAepJB'"JB'&KBQ0NC@9QCQCQCQ9 PC@9PC@4NBf0LB9pIAPjGA9eGA9aFA&aFA&aFA9eHAepJB@&KBQ*LBf0NC@CRCfK SD@PUDfaYEQj[Efp`F(&aFA&aFA&aFA*bFR&aF'p[EQjZEQeYE'aXE'aXE@eZEQp `F(&bFh0cG(4eGAChGhKiH(KjHAPkHRYlHhYlHhYmI(apIAepIAamI(amI(apIAa mI(YlHhYlI(apIRjrJ)'#JS1$Ji1$JS+#JB'"JS+#JB'"J)#"JB'"J(pqIAalHhY lHhTkHRTkHAPkHRTkHRPjHAKiGhCeGA4dFh0bFR*bFR*bFh4eGRGiH(KiH(KhGRC eFh0bFA"`F("`FA&aFR*cFh4dGA9eGA4dFh0cFh0cFh0dG(4eGACfGhKiHAPkHRP jHAPjHATkHRYlI(apIRjqIhprIhpqIRjqIRjpIAepIAepIAepIAjqJ)'#Ji5%KB@ %K)5$Ji+"JB#!J(prIhprJ)#!JB'"JS+#JS+#JS+#JS+#JS+$K)@'KiL*LSU,M)f 1Miq3!*!!N!#3!*!!N!#3!*!!N!#4NT+6P*@@PTHCQTZGRU#KSD+LSU+KSD'JS*q IRTkHRTkHRTfGRCfGRCkHRTkGRCfGRCfHRjqJSD'KSD'KS+#IRjqHRTkHRCfFQjZ DQTUDQTZER*bGRCfHRTkHRjqIRTkGRCbFR*bFQjZDQTQBQ*LBPjHAPjHAPjD@PC@ 9PC@@PTDAPjHAPjHBQ*LBQCQCQCQBQ*LBPjD@PT@@PjHBQ*QBQ*LBPjHAPjHAPTD @PC56Nj+4NC!!N!#3!*!!N!#3!)q2N!#3!*'5Nj16P*58PCD@PjHAPjD9P*56Nj+ 5NT+5NT+5Nj18P*@@PTHAPjD@PC@9PC@9P*58Nj16Nj15NT+4N!#2MSk0MBf0MBk 1Miq3!*!!NC+6Nj59PC@9PC@@PTD@PC@9P*56Nj16Nj16Nj16Nj16NT+4N!#2MSk 0M)Z,LSU+LSZ,Lib0MBk1Miq2Miq2Mik1MBf-M)b-LiZ+LSQ*LBQ+LSQ*LBL)LBQ +LSU,LiZ,M)b0MBk2N!#3!*!!Mik0M)Z+LBL(KSD&K)1$JS+#JB'!J)'"JB+#JS+ #JS+#JS+#JS'"J)#!J)'"JB'!J)#!J)'"JS+#JS1$Ji1$JS+"J(pqIAalHRPjH(G hGhCfGR9eGACfGhGiHAPkHRYmI(eqIhq!JB+#JS1$Ji1$Ji1$JS+#JB'"J)#!J(p rIhjqIRepIAamHhYlI(apIAeqIRjqIRprJ)#!J)"rIRemHRTjH(GhGR9eG(4dGA9 eGRCfGR9eGA4dFh0cFR*aF'pZEQeYE'aVDfYVDfYVDfYVDfYVDfTTD@KSD'KSD@P UDfaYE@jZEQeYE@eZEQp`FA*cG(ChH(PkHhamI(amI(amI(amHhYkHAPiGhCeG(0 cFR*bFh0dG(4eGA9eGA9fGRCfGR9eG(4cFh0cFh4dGA9eGA9eGA9fGhKjHAPjHAK iGhCfGA4cFR&`F'p[Efp[EQjYE@aXDfYUDQTTD@KSCfCQC@9PC@4NBf0LBQ*KB@& JB&pHAPeGA9eGA9jHAf"KB@&LBQ*LBQ0MC'4NC'4NC'4MBf*LBQ*LBf4PCQGRCfG RCfGRCfKTD@TUDQTUDQYVDfaXE'aVDfYVDfYVDfaXE'aYE@jZEh"`FA*bFh0dG(9 eGA9eGRCfGRCfGA9eGA9eGA4dG(4dFh0cFh0cG(4cFh0bFA"[EfjYE@eYE@eYEQj ZEQjZEQjZEQp[EQjZEQj[Eh"`F("[Efp[Eh"`FA*bFR*bFR&aFA&aFA"`F("`FA* cG(9fGhKiHATlI(epIRq!J)#"J)"rIhjpI(YlHhYmI(eqIi#!JB+#Ji1$Ji1$Ji1 $Ji+#JB'!IhprIhprIhpqIRjqIRjqIRepIAamI(amI(apIAepIRjqIRprIhq!J)" rIhjqIAamHhYkHRTjHAPjHRTlHheqIi'#Ji5&KSD'KiD'KS@%K)1$JS+"J(pqIAa mI(YlHhYmI(epIRjqIhprIhq!J)#!J(prIhq!J)'#Ji5%KB@'KSD(KiH(L)L*LBU ,M)b0MSk2Miq3!*!!N!#3!*!!Miq1MSf-M)Z,LiZ,M)b0MBk1MSk1MSk2N!#4NT1 8PCD@PTH@PT@9P*16NT'4N!#2MSb,LBH'K)1#JB#!J)#!J)'"JS+#Ji1$K)5%K)5 %K)5&KBD'KSH(KiH(KSD&KB@&K)5&KB@'KSH)LBQ+LiZ-M)b0M)b-LiU*LBL)KiH (KSD'KSD(L)Q+LSZ,LiZ-M)f1Miq3!*'4NC'4NC'4NT+6P*@9PTHAPjH@PT@9P*1 6Nj+5NT+5NT16P*@9PTD@PjHAQ*LBQ*HAPjD9P*15NT'4NC'5NT+5NT+5NT+5Nj1 8P*59PC@9PC@9PC@9PC@9P*58P*56Nj16Nj58P*58P*58P*56Nj15NT+5NT+5Nj1 6Nj16P*@9PTHBQCUER*bGRTqIS+'KSD#JS*qIRTkGR*bEQTQCQ*H@PC56NT'4N!# 3!)q2MSf-M)b-M)f0MSk2Miq3!*!!N!#3!)q2MSf-LiU*LBL(KiH'KSD'KSD'KSH (KiH(KiH'KSD'KSD'KS@&K)5$Ji1#JS'"J)"rIhprJ)#"JS1%K)@&KB@&KB@%K)1 #JB"rIhprIhprIi#!J)#!JB'"JS+$K)5%K)1$Ji1$Ji1$Ji1#JS+#JS+#JS1$Ji1 $Ji1$K)5&KB@&KB@&KB5%K)1$JS+#Ji5%KBD(L)L)L)Q*LSZ-M)f0MSk1MSf0MBb -LiZ+LSQ*L)L)L)L(KiH(KSD'KSH(KiH(L)L)L)Q*L)L)KiD&K)5$JS+"J(pqIAe qIRprJ)'"JS1%K)@&KB@&K)1$JS'"JB#!J(prIhpqIRjqIRjqIRjqIRprIhq!J)# "JB'"JB'!J(prIhprIhjpIAalHRPiGR9dFR&aF("`F("`F("aFA&aFR*cG(4eGRC fGRCfGA9dFh*aF'pZEQeYE@aXE'aXDfYVE'aXE'aYE@eYE@eXE'aVDfTUD@KSCfG RCfGRCfGQC@9NC'4PC@CQCQGRCfKSD'PTDQYXE'eZEQp[F("aFA&bFR*cFh0cFh0 bFR&aF("[F("`F(&aFA&aFA&bFR0dG(9eGRCfGRCfGhKiHAPkHRPjHAKiGhGfGRC eGA9eGA9eGA4dG(0cFh0bFR*bFR*cFh0cFh0cG(4cFh0cFR*aFA"[EfjYE'YUDQP SD'GRCfKSD'PTD@TUD@PTD'GRCQ9PC@9PC'4NC'4PC@CQCfGSD'PTDQTUDQTTD@P SD'KSD'GRCfCQCQ9PC'0MBQ*LBQ*LBQ*LBQ*LBf0NC@9QCfKTDQYXE@eZEQp[F(& aFR*bFR&aF'pZEQeYE@eYE'aXDfYUDQPTD@PSD'KSD'KSD'GRCfGRCfGRCfKSD'K TD@PTDQTUDQTUDQPTD@PTDQTUDfYXE'eZEQj[Efp`F(&aFR*cG(4eGACfGRChGhG iH(PjHATkHRPjHAKiGhGhGhKiH(PjHATkHhYlHhamI(amHhYlHhYlHhYmI(amIAe qIhq!J)'"JB'"JS+#Ji1$Ji1%K)5&KB@'KSD'KSH(KiD'KB@%K)5%K)5%K)5&KBD (KiL*LBQ*LSU+LSU*LBQ)L)H(KiH(KiD'KSD(KiL)LBQ*LSU+LBQ*LBQ*L)L(KiD 'KB@%K)5%K)5%K)@&KB@&KSD'KSD'KS@&KBD'KSH(KiH)L)Q+Lib-M)b-LiZ,LSU +LSU+LSU+LSU+LSU+LiZ,LiZ,LiZ,LiZ,LiZ,LiZ,LiZ,M)b0MBf1MSk2Mj!!N!# 3!*'4NC+5Nj16P*58PC@9PC@9PC@@PTD@PTD@PjHAPjHAPjHAPTD9PC56Nj15Nj1 6Nj16Nj16Nj16P*58P*@9PC@9PC58P*58Nj15NT+4NC'4NC+5NT+5NT+5NT16Nj1 6Nj18P*59PC@9PC@9PC@9PC58P*16NT+4NC!!N!#3!)q3!*!!N!#3!*!!N!#3!*! !NC'4NT+5Nj16Nj58P*58PC@9PC@@PTDAPjHAQ*LAPjHAPjHAPTD@PC@9PCD@PjH AQ*LBQ*LAPjHAPTD@PTD9PC@9PC58P*58PC@8P*16NT'3!)q1MBb-LiU*L)H'KB5 %Ji1#JS+#JS+#JS+$Ji5%K)5%K)5%Ji1$Ji1$Ji1$Ji1$K)5&KBD(L)Q*LSU,Lib 0MBk1MSk1MSk1MBf0MBf0MBf0MBf0MBf0MBk1MSq2Mj!!N!#4NC'5NT+6NT+5NC' 4NC!!N!#4NC'4NT+5NT+5NT+4NC'3!*!!N!#3!*!!N!#3!)q2Miq2Miq2Miq2MSk 0MBb-M)b-LiZ,LSU*LBL)KiH'KSD'KSD'KiH(L)L*LBU,LiZ,M)Z,LiZ+LSU+LBQ )L)H'KB5$JB"rIRepI(YlHRPjH(KhGhGhGhGhGhGhGhGhGhGfGRChGhGhGhGhGhG hGhGfGRCfGA9eGA9dG(4dG(9eGA9eGA9eGA9eGA9dG(4cFh*bFR*bFR*cFh0dG(9 eGACfGhKiH(KiH(GhGhCfGR9eGA4eGA9eGA9eG(4cFh0cFh0cFh0cFh4dG(9eGAC fGhKiHAPkHRTkHRTjHAKiGhGhGhGhGhGiH(KjHAPjHAPjHAPjHAPjHAKiH(KiH(K iH(KjHATkHRTkHRTkHRTkHRPjHAPjHAKiGhGfGR9eGA9eGA9dG(4dG(4dGA9eGA9 eGA9eGA9eGA4dFh0bFR*aFA&aFA&aFA*bFR*bFR&aF'p[EQjYE@eYE'aXE'YVDfY VDfYXE'aXE'eYE@eYE@eYE'aXE'YVDfYVDQTTD'GRCQCPC@9PC@9QCQCRCfGSD'K SD'KSD'KSD'GRCfGQCQ9PC'4NBf4NC@9QCQGRCfKSD'PTD@TUDQTUDQTUDfYVDfY VDfYVDQTVDfYVE'aYEQp`F(&bFR0cFh0cFh0cFh0cFh0bFR*bFR*cFh0cG(4dGA9 eGRChGhKjHATkHRTkHAPiH(KhGhCfGRCfGRCeGA9dG(4dG(4dG(0cFh0bFR*bFA& aF("`F(&aFA&aFA&bFR*cFh4dG(4cFh0dG(4dG(4dG(9eGAChGhKiHATlHhamI(e pIAepIAamHhYlHRTkHRTkHRTkHRTkHRYlHhYlHhamI(alHhYlHhTkHRPjHAKiH(K iH(KiGhGhGhCfGhGhGhGhGhGhGhGhGhKiH(PjHAPjH(KiH(KiH(KiH(KiH(KjHAP kHRTlHhapIAjrIi#!JB'"JB'#JS+$Ji1$Ji1%K)5%K)1$Ji5%K)@&KSD'KiH(KiH (KSD&KB@&KB@&KB@&KB@&KSD'KSD&KB5%K)1$Ji1$Ji1$Ji5%KBD(L)L*LBU+LSZ ,LiZ,LiZ,LiZ,LiU+LSQ*LBQ)L)L)L)L)L)L(KiH(KiH(KiD'KSD&KB@&KBD'KiH (KiL)L)Q*LSZ,LiZ,LiZ,LiU+LSU+LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBU +LiZ,Lib-M)b-M)b,LiU+LBQ)L)L)KiH(KiD(KiL)LBQ+LSZ,Lib-MBf1MSq2N!# 3!*!!N!#3!*!!Miq2Miq2Miq2Mik1MSq2Mj!!N!#3!*!!N!#3!*!!N!#4NC'4NC' 4NC!!N!#3!)q2Miq1MSk1MBf-M)b-M)b0MBk1Mj!!NC'5Nj58PC@9PC@9PC@9PC@ @PTD@PTD@PTD@PTD@PjHAPjLBQCUDQTZER*bGRCfHRTkHRTkGRCfFR*bFR*bFR*b FR*ZEQjZDQTUCQCLBPjHAPTD@PT@9PC@9PC@9PC@@PTDAPjHBQ*LBQ*LBQ*HAPjH @PT@8P*15NT'4N!#3!*!!Miq2Mj!!N!#3!*!!NC'3!*!!N!#3!)q2Miq2Miq2Mik 1MSf-M)Z,LiZ,LSU+LSQ*L)L)L)L(KiH(KSD'KS@&KB@&K)5%K)5$Ji1$Ji1$Ji1 #JS+"JB'!J)#!J)#"JB'"JB'"JB'"JB#!J(prIhpqIRprIhprIi#!JB'#Ji1%K)5 %K)5%Ji+#JB#!IhpqIRjqIRjqIRjqIRprIi#!J)#"JB'"JB#!IhprIRjqIRjqIRj qIRjqIRjrIhq!J)#"JB'#JS+#Ji1$K)5$Ji1#JS+"J)"rIhpqIRjqIRjqIRjrIhp rIhprIhprIhq!J)#!J)#!J)#!J(prIRjqIRjqIRjqIRjqIRjqIRjqIhprIRjqIAe mI(amHhYkHRPjHAKiH(GhGRCfGRCfGR9eGA9eGA9eG(4dFh0bFR&aFA&aFA&aFA* bFA&aFR*bFh0cG(4dFh0cFh0cFh0cFh0cFh0cFh0dG(4dG(4cFh0cFh0cFh0bFR* bFR*aFA&`F'p[EfjZEQeYE@aXE'YVDfYVDfYVDfYVDfYUDQTUDQTUDfYVDfaVDfY UDQTUD@PTDQTUDQYVDfaXE@eZEQp[F("`FA&aFA&aFA&`F("`F("`FA&aFA*bFR* bFR*bFR*bFR*bFR*bFR*bFR*bFR*bFh0cFh4dG(4cFh0cFh0dG(9eGRChGhKiHAT kHRTkHAPjH(KiGhGhGhCfGA9dG(4dG(9eGA9eGRChGhKiH(KiH(KhGhGhGRCfGA9 dG(4dG(4dG(9eGAChGhKjHRTlI(apIAeqIRjqIAepIAamHhYkHRPiH(KiH(GhGhG fGRCfGRCfGRCfGR9eGA9eGA9eGA4dG(0cFh*bFR*bFR*aFA&aFA&aFA&aFA&aFA& bFR*bFh0dG(9eGA9eGA9eGA9eGA9dG(0cFR*bFA&aF("`F("aFA*bFh4dGA9fGRC hGhGhGhGhGhCfGA9eGA9eGRCfGRChGhGiH(KiH(KiH(KiHAPjHAPjHRTkHhamIAe qIRjrIhprJ)#!JB'"JB'"JB'#JS+$Ji1$K)5%K)5%K)5%K)5%K)5$Ji1$Ji1$Ji1 $K)5%K)5&KB@&KB@&KB@&KB5%K)5%Ji1$Ji1$JS+#JS+$Ji1$K)5&KB@'KSD(KiH )L)L)L)L)L)L)L)L)L)L)KiH(KiH(KSD'KS@&KB@&KB@&KB@&KB@&KB@&KB@%K)5 $Ji+#JS'"JB'"JB'"JB+$Ji5%K)5&KB@&KB@&KB@&KB5%K)1$Ji1$Ji5%Ji1$Ji1 $JS1$Ji1%K)5&KB@'KSD(KiH(KSD'KSD'KS@&KB@&KB@&KB@&KSD'KiH)L)Q*LBU +LSZ,LiZ,LiZ,M)b-MBf0MBk1MSk1MSk2Miq1MSk2Miq2Mj!!N!#3!*!!NC'4NT+ 5NT+5Nj+5NT'4NC!!N!#3!)q2Miq1MSk1MSk1Miq2Miq2Mj!!N!#3!*'4NC'4NC' 4N!#3!*!!N!#3!)q2Miq1MSk1MBf0MBf-M)b-M)b0MBf0MBf0MBf0MSk1MSk1MSf 0MBf0M)b-M)b-LiZ,LiZ,Lib-M)b0MBf1MSk1MSk1MBf0M)b,LiU+LSQ*LBQ)L)L )L)L)LBQ*LBU+LSU,Lib-M)f0MBf0M)b-M)b,LiZ,LiZ+LSU+LSU*LBQ*LBQ*LBQ )L)L)L)H(KSD&KB@&KB5%K)5%K)5%K)5%K)5%K)5%K)5%KB@&KB@'KSH(KiH)L)L (KiH'KSD'KB@&KB@&KB5%K)5%K)5%KB@&KB@'KSD'KSD'KS@&KB@%K)5$Ji1#JS' "JB'!J)#"JB'"JS+#Ji1%K)@&KBD'KS@&KB@&KB@&KB@&KB@&KB@'KS@&KB@'KSD 'KSD'KiH(KiL)L)L)L)L)L)L)L)H(KiH(KSD'KSD'KSD'KB@&KB@&KB@&KB@&KB@ %K)5$Ji+"JB#!IhpqIRjpIAemI(amI(amI(YlHhYlHhYlHhYmI(amHhYkHRTjHAP jHAKiGhGfGR9eGA4dFh0cFR*bFR*bFR0cFh0dG(9eGRCfGRCfGRCfGRChGhGhH(K iHAPjHAPjHAPiH(KiH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAPjH(KhGhCfGRCfGRC hGhGhH(KiH(PjHAPjHAPjHRTkHhYmI(epIAepIRjqIAepI(YlHRPiH(KhGhGfGRC fGRGhGhKiH(KiH(KiH(KiGhGfGR9eG(4dG(0cFh0cG(4dGA9eGRCfGhGhGhGhGhC fGRCfGA9eG(4dG(4dG(4dG(4dG(4dFh0cFh0bFR*bFR*cFh0cFh4dG(4dGA9eGA9 fGRCfGRCfGRCfGRCfGR9eGA9dG(4dG(4cFh0dG(4dG(4dFh0cFh*bFA&`F("`F(" `F("`F("`FA&bFR*cFh0dG(4dG(4dFh0cFh0cFh0cFh0cFh0dG(4dG(4dG(0cFh0 cFR*bFR*cFh0cFh0cFh0cG(4dG(9eGA9eGA9eGRCfGRCfGRGhGhGhH(KiH(KjHAP kHRTlHhYmI(amI(epIAepIAepIAemI(YlHRTkHAPjHAPjHAPkHRTkHRTkHRPjHAP iH(GhGRCfGRCfGRChGhGiH(KjHATkHhYmI(apIAeqIRjqIRjpIAepIAepI(amI(a lHhYlHhYkHRTkHRTkHRTkHRTkHRYlHhYlHhYmI(amI(YlHhTkHRPjHAPiH(KjHAP kHRYlI(amIAeqIRprIi#!J)#!J)#!JB'"JB+#JS+#JS+#JS+#JB'"JB'#JS+$Ji1 %K)5%K)@&KBD'KSD'KSH(KiH(KiH(KiH(KiH(KiH(KSD'KSD'KSD'KSD'KSD(KiH (KiH(KiH(KiH(KiL)L)L)LBQ*LBQ+LSU,LiZ,LiZ+LSU+LBQ*LBL)L)L)L)L)LBQ *L)L)L)L)L)L)L)L*LBQ*LBU+LSU+LSU*LBQ*L)L)L)H(KiH(KiL)L)L)LBQ*LBQ +LSU+LSU+LSQ*L)L(KiD'KS@'KSD'KSD(KiH(KiH(KiH(KiH)L)L)L)L(KiH(KiH (KiL)L)L)L)L)L)Q*LBU*LBQ)L)L(KiH'KSD'KSD'KSD'KS@&KB@&KB@%K)5%K)5 %Ji1$Ji1%K)5&KB@'KSH(L)L)L)L)L)L)L)L)L)H(KiH(KiD'KSD'KSD'KiH(KiH (L)L)L)L)LBQ*LBQ*LBQ*LSU+LiZ,M)b0MBf0MSk1MSk1MSf0MBb-M)b-M)b-M)b 0MBf0MBk1MSk2Miq3!*!!N!#3!*!!N!#3!*!!N!#2Miq2Miq2Miq2MSk1MSk0MBf 0MBf0MBb-M)b-M)b-M)b-M)Z,LiU+LSQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBL)L)L (KiH'KSD'KB@&KB@&KB@&K)5%K)5%K)5%K)5%K)5%K)1$Ji1#JS+#JB'"JB'"JS+ #JS+$Ji1%K)5%K)5%K)1$JS+#JB'"JB'!J)#!J)#!J)#!J)#!J)"rIhprIhprIhj qIRjqIRjpIAepIAemI(amI(amI(amI(amI(amIAepIAjqIRjqIhprIhprIhprIhp rIhjqIRjqIRjpIAepIAepIAepIAepIRjqIRjqIRprIhprIRjqIRjqIRjqIRjqIRj qIhprJ)#!J)#"JB'#JS+#Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$JS+#JS'"JB'!J)#!J)# !J)#!IhprIhjqIRjpIAepIAepI(amHhYlHRTkHAPkHRTkHRTkHRYlHhTkHRTjHAP jH(KiH(KhGhGhGRCfGR9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA4dG(4 dG(4cFh0cFh0dG(4dG(4dG(4dG(4dG(4dGA9eGACfGRCfGRCfGRCfGA9eG(4dFh0 cFh0cG(4dGA9fGRChGhGhGhGhGRCfGRCfGRCfGA9fGRCfGRCfGRGhGhGhGhGiH(K iH(KhGhGhGhGhGRCfGRCfGR9eG(4dG(0cFh0cFh*bFR*bFR*cFh0cFh0cFh4dG(4 dG(4cFh0cFh0cFh0cG(4eGA9fGRChGhGhGhKiH(KiH(KiH(PjHAPjHAPjH(KiH(K iH(GhGhGhGhGhGhGhGhGhH(KiH(KiH(KiHAPjHAPjHAPiH(KiGhGhGRCfGRChGhG hH(KiH(PjHAPkHAPjHAKiH(KhGhGhGhCfGRChGhGhGhGhH(KiH(KiH(KiH(KiH(P jHRTlHhamI(epIAepIAepIAepI(amI(amIAepIAepIRjqIhprIhprIhprIi#!J)" rIhprIhprIhprIhpqIRjqIRprIhprJ)#!JB'#JS1$Ji1$Ji1%K)5%K)5%K)1$Ji+ #JS+#JS+#JS+#JS+#JS+$Ji1$Ji1$Ji1$K)5%K)5%K)5%K)5%K)5$K)5%K)5%KB@ &KB@&KB@&KBD'KSD(KiH(KSD'KS@&KB@&KB@%K)5%K)5%K)5%K)5%K)5%K)5%K)5 %K)5$Ji1$Ji1$Ji1$Ji1%K)5%K)5%K)5%K)@&KBD(KiL)L)Q*LBU+LSU+LSU+LSU +LBQ*L)L)L)L)L)L)L)L)L)L)L)L)L)L(KiH'KSD'KB@&K)5%K)5$Ji1$Ji1$Ji1 $Ji1$K)5%K)5%K)5&KB@&KB@&KB@%K)5%K)5%K)1$Ji1$Ji1$Ji1$K)5%K)5%K)@ &KB@&KB@&KB@%K)5%K)5$Ji1$Ji1%K)5%K)@&KBD'KSD(KiH(L)L)L)H(KiH(KiH (KSD'KSD'KSD(KiH(L)L)L)L)L)L)L)L(KiH(KiH(KiH)L)L)LBQ*LBQ*LBQ*LBQ *LBQ*LBQ)L)L(KiH(KiD'KSD'KB@&KB@&KB@&KB@&KBD'KSD(KiH)L)L*LBQ*LBQ *LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LSU+LBQ*LBL)L)L)KiH(KiD'KSD'KiH(KiL)L)L )L)H(KiH(KiH(KSD'KSD'KSD'KSH(KiH(KiH(L)L)KiH(KiH(KSD'KSD'KSD&KB@ &K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5$Ji1#JS+#JS'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!IhprIhprIhq!J)#!J)#!J)#"JB' "JB'"JB'"JB'"JB+#JS+#JS+#JS+#JS+#JB'"JB#!J)#!IhprIhprIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'"J)#!J)"rIhpqIRjpIAepIAepI(a mI(amI(amI(amI(amI(amI(amHhYlHhYlHRTkHRTkHAPjHAPjHAPjHRTkHRTkHRT jHRTkHRTkHAPjHAPiH(KiH(KhGhGhGhGiH(KiH(KiH(KiH(KiH(KiH(KiGhGhGhG hGhGhGhGhGhKiH(KiHAPjHAPjHAPjHAKiH(GhGhGfGRCfGA9eGA9fGRCfGhGhGhG hH(KiH(PjHAPjHAPkHRTkHRTjHAPjHAPjHAPiH(KiH(PjHAPjHAPjHAPkHRTkHRT kHhYlHhYlHhYlHhYkHRTkHRTjHAPjH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAPjHAP jH(KiH(KiH(KhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhKiH(K iH(KiH(KiHAPjHATkHRYlHhYmI(amHhYlHhYlHhYlHhYlHRTkHRTkHRTkHRTkHRY lHhYkHRTkHRTlHhYlHhYlHhamI(amI(amI(amI(amI(amHhamI(amI(alHhamI(a mI(alHhYlHhTkHRTkHRPjHAPjHATkHRTkHRTkHhYlHhYmI(amI(amI(amI(amI(a mI(amI(amI(amIAepIAepIAeqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIAepIAe pIAepIAepIAepIAeqIRjqIRjqIRprIhprIhprIhprIhprIRjqIRjpIAepI(amI(Y lHhYlHhTkHRTkHRTlHhYlHhYlHhYlI(amI(amI(apIAepIRjqIRjqIRjqIhprIhp qIRjqIRjqIRjqIhprIhq!J)#!J)#"JB'"JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+$Ji1$Ji5%K)5%K)@&KB@&KB@'KSD'KS@&KB@&KB@&KB@&KB@&KBD 'KSD'KSD'KB@&KB@&KSD'KSD'KSH(KiH(L)L)L)L)L)L)LBQ*LBQ*LBU+LSU+LSU +LSU+LiZ+LSU+LSU+LSU*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBL)L)L )L)H(KiH(KSD'KSH(KiH(L)L)L)L*LBQ*LBQ*LBQ*LBQ*LBL)L)H(KiH(KSD'KSD 'KB@&KB@&KBD'KSD'KSD(KiH(KiH(KiH(KiH'KSD'KS@&KB@%K)5%K)5%K)5%K)5 %K)5%K)5%K)1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji5%K)5 %K)5%KB@&KB@&KB@'KSD'KSD'KiH(KiH(KiH(KiH(KiH(L)L)L)L)L)L)L)L)L)L )L)L)L)L)L)L)L)L)L)H(L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L )L)L)KiH(KiH(KiH(KSD'KSD'KS@&KB@&KB@&K)5%K)5%K)1$Ji1$JS+#JS+"JB' "JB#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhpqIRjqIRjqIRe pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAjqIRepIAepIAepIAepIAepIAe pIAepIAepIAepIAepIAepI(amI(amI(YlHhYlHhYlHhYlHhYlHhYlHhYlHhYlHhY lHhYlHhYlHhYkHRTkHRTkHAPjHAPjHAPjHATkHRTkHRYlHhYlHhYlHhYlHhYlHhY lHhamI(amI(amI(amI(amI(amI(amHhYlHhYlHhamI(amI(amIAepIAepIAepIAe pI(amI(amI(amI(amI(amI(YlHhYlHhYlHhYlHhYlHhYlHhYlHhamI(amI(amI(a mI(amHhYlHhYlHRTkHRTkHRPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPiH(K iH(KiH(KiH(KiHAPjHAPjHAPjHAPjH(KiH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAP jHRTkHRTkHRTkHRTkHRPjHAPjHAKiH(KiH(KiH(KiH(KiH(PjHAPkHRTlHhYlHhY lHhYlHhYlHhYlHhYlHhYlHhYmI(amI(amI(amI(alHhYlHhYlHhamI(amI(amI(a mI(amI(epIAamI(amI(amI(amI(amI(amI(amIAepIAepIAepIAepIAepIRjqIRj qIRjqIhprIhprIhprIhq!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)# !IhprIhprIhprIhprIhprIhprIhprIRjqIRjqIRjqIRjqIRjpIAepIAepIAepIAe mI(amI(amI(amI(amI(amI(epIAepIAepIAepIAepIAepIAepIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRprIhprIhprIhprJ)#!J)#"JB'"JB'"JB'"JB+#JS+#JS+"JB' "JB'"JB'"JB'!J)#"JB'"JB'"JB'"JS+#JS+#JS+#JS+#JS+"JB'"JB'"JB+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"JB'"JB'"JB'"JB' "JS+#JS+#JS1$Ji1$K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5 %K)5%K)5%K)5%K)5%K)5%K)@&KB@&KB@&KB@&KB@%K)5%K)5%K)5%K)5%K)5%K)5 %K)5%K)5%K)5%K)5%K)5%K)5%K)1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1 $Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+#JS+#JS+#JS+#Ji1$Ji1$Ji1 $Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$JS+#JS+#JS+ #JS+"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS1$Ji1$Ji1$Ji1$Ji1$Ji+ #JS+#JS+#JS+#JS+"JB+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprJ)# !J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J(p rIhprIhprIhprIhprIhprIhprIhprIhprIhprJ(prIhprIhprIhprIhpqIRjqIRj qIRepIAepIAepIAepIAepIAepI(amI(amI(amI(amI(amI(amI(alHhYlHhYlHhY lHhamI(amI(amI(amI(amI(amI(amI(amI(amI(amI(amI(epIAepIAepIAepIAe pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAamI(a mI(amI(amI(amI(amI(apIAepIAepIAepIAepIAepIAepIAemI(amI(amI(amI(a mI(amI(epIAepIAepIAepIAepIAemI(amI(amI(amI(amI(amI(amI(amI(amI(a lHhYlHhYlHhYlHhYlHhYlHhYlHhYlHhYmI(amI(amI(amI(apIAamI(amI(amI(e pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAe pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAeqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)#"JB'!J)#!J)#!J)#!J)#!J)#!JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjrIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhq!J)#!IhprIhprIhprIhprIhprIhprIhq!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!0%!!!3!"!!8 !!!#J!!'!83!!!!!!&!!!!!!!!$3@9Zk,S`!!0"3!!$39!$b!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!IhprIi#!JB+#JS+#JS+#JS+"JS+"J)#!IhjqIi#!JB+#Ji1$K)5 'LBf2N!#3!)Z$H@eLA&YEA@*UFhb"K)5$J(elHRPiH(PmIi'#JB#!JB'!IhprIi# "Ji5$JS'"JB+#JS+#JS1$JS'!IhjqIAepIS##K)D)LSk8Q*UDQC@3!)Z%Hh"M9e* 59epSFAKmIAPaD@0KBQG`Ghb!JS1&KiH&K)5%Ji+!J)'$KSH(KS@%Ji1&KiL(KS@ %JS'"J(pqIRjqIi##Ji5(LSb-LiZ-Mj+9Q*UCPj@6N!#-K(KS9$md0$8j490MFRb "J(elHRKfGRKlJ)@,M)U'K)+!J)#!JS5&KiQ+LSU*L)D%Ji1$Ji+#JB'"IhprIhq "Ji@(LBZ0MSk-LiU+MC'9QTfIS++HNAjM5$-S*b`e2dG199aQFAKmIRelHAGjJSf 8PT52LBD'KSH*LSQ)Ki@&KiL)KS5$JS+#K)D)L)D&K)1#JB'"JS1%KBD(KiH)LSb 1MT!!NjQJTULSTCq4Hf&)0#NP*#3V1%C2@@GfI(eqJS1"Ii'*NTH9MiZ,LSL(KSD (L)D%K)D)LBL(KiD&Ji5(LSb,LSL'Ji"pHRTmIS'$KBL+LiZ+LSU,MBk3!*1AR+' RUkQDJ@4*-b)A$J`B+cpAFB5-N!#3!)k*JRamJSb8Pj+1LiH"Ii##JS'"J)''LSk 2MSb*Ki@#JiD)KiH(Ki@%JRppIAamIAq$KiU-M)Z+LBL)Lj'ARD1RV+kSPATC04S 1$K3L08GCEi1,M)U(KB*lGRL!M*@AP)q+K(epIi'#JS1%L)b1MSk1M)Q&JB#"KBH )LBQ)KB*pHAKhH(PmJB@*Lib-LiU)L)Q-NTUKTkkbVU+,ENmc(J`!"4Nd9hQ2QCH -JAalH(9fIBD1NC!!Mib(JhprJ)"qIAq%Lj!!NT+3!)f*KS5$Ji@)LBL(KS5#IRT iGhCfHAq&Liq4NC!!M)Q(KSH,NCHESUQXTT9pAd)S&!S2)$TCH)kAPSf#HRCdFA& iJSZ4PC53!)Z%IhepIAapJ)@+MT+8PC12LSD#J)'%KiL)L)H&JRjlGh9dGRZ!KBQ 0N!#4Mib*KiH+Mj5DSDHUU*k,F&8p*a!###0(EBUCR*1(I(GeFh&cHi5,MT!!Mif ,Ki*rIRjpIS+(M*!!Nj@@Nik*KB'!JB5'KiH(KS1!HhKfG(4hI)+)MC!!NC!!MSU )KiQ0NTLGSUDNQiPa@%!V&``9-&"[KjDBN!#%HhCdF@pbHS1,Mj'5NBk*Ji#!Ihe qJBD-N!#8PTD8MiU'JS#!JS5'KSD&Ji"pHACdFh9kJ)D-NC16NBk-LiZ1NC@DRU' IPiG`9$SX+#FR,N*KIC!!PT''IAKfG(*bH)+0P*@5M)L&K)1#J(jrJBD,Mj1@Q*H 6M)D"IRq#K)@&KB5$JAjlH(GhH(TrK)U1NC'3!)k,LBQ,Mj1BRD#KQieiB8Xe)43 4(MjQKCLGPSU!HRGdFR4jJ)H0NC+4N!#1LSD$IhamIi@+Mj1@PjD6MSQ&JB#!JS+ #Ji5&Ji&qHRGfGhTrK)Q1NC+5Mif,LSZ-N!#@QjkIQiplBdXf*KX9(6TKJTDFQ)k &IAPeFh0iJ)L1NC'2MBf-LSD#IheqJiL0NC@@PT11LB@#JB+#JS+$K)5$JAjkGh9 eGhb$LSk4Nj+2MBb-MBq4P*QGRjZ1HQ0+0#FH'#!kAS#@RTU3!)CrHhGeG(GqKSb 2Miq1MSf,Ki*qHhb"KSZ2NjDAP)q+KS1#Ji1#JS+#JS+"IhajGhGjIB'(MC!!NT+ 2M)Z,MBq5PTZHRjb4IfP41bJB$"3hBS1BRjQ2Ki&pHACfHAq'LSf0MBk2MSZ(JAe mIB#&LSk5P*55MSU(KB1#JB#!J)+$Ji+!IATiGhKlJBH,MT!!Mik-Lib0MT!!Nj@ CQjL2J'a@3#iI&4`mC)@CRjQ2KRpkH(9eH(q'LSb-M)f1MBU'JAemIB'&LBf4Nj1 5MSU(KB1#J(prJ)'#JS&rI(ThGhPmJBH-MT!!Mik-LSQ,MC'6PCLCPSk!E9G#-5) A(cpQKjUHQ)k'J(ekGh9iIS5*M)f0MBk0LS@"IReqJ)5)M*!!NT14MSU(KB1#JB# !J)'#JS&rIAYjHAPmJBH,MSk1MBZ*LBU0NC@AQCQAMi&Z@83b)48I3'L*QTfAMSD !I(KfGRPrKBU0MBf0MSf+KB&pHharK)L-N!#6Nj'1LSH&Ji'!Ihq!JB+$JS"qHhP iHAb"KSU0MSf-LiQ*LSb2NjDAQ*H2JR&F4c)I&L4)EifERCD0KS"mHAKiHRk$KiU ,M)f2MSU&J(emIB#%L)Z2NC+3!)f+Ki@$JB"rIi##JS+#J(elHAKjI)+'LSb0MBZ +LBL*M)q6PTHAPBq%Fej*-ad6*NphNCZDNiZ&IhYkHATmIi1(LBU-MSq1LB0qI(a pJ)5)M)q4NBq0LSL'Ji"qIRq!JS1$JB"pHRKhHAb"KSU,M)b,LBL)LBZ0NC5@PT5 2K(9K5M)G&La@Hj'EQC+,KAplHAPjHhk"KBL+M)k2MSQ%IhYkI)#$KSU1NC'2MBU )KS1!IReqJ)'#JS+!IATiGhPmJBD*Lib-LiQ)L)Q+MC!!Nj59P)q%G'"*-"`C-Pf !P*UAN!#+K(jlHRTkI(k"K)H*Lik3!)k*K(pmI(f!JiD+MT'4Mif,LBD$J(jqIS# "JB+"IhekH(KjIB+'LSb-M)Z*L)L*Lik4Nj@9NSb"F9a&,4XG2'D&PTU8MSL#IAY kHRYmIS'%KSL,MT!!MSQ%IhepIS#$KSU1NC!!MSf,LBH$IhepIRq!JB'"IhakH(K jIB+'LBZ,LiU*LBQ+M)q4NT58Nib!EPK!+"JK4h#,PjL6MBH"IAYlHhapIi'$KSL ,Mj!!MSQ%J(jqIi#$KiZ1N!#2MSf-LSH$J(jqIRq!JB'"IhekH(PlIS1(LBU,LiU *LBQ+M)q4Nj56N!#)HfK51L-A,&GlNCQ@MiU&IhYkHhapIRq"Ji@(Lik2MBL$J(p rJ)'$KiZ1Miq0M)b+Ki1!IRjqIhq!J)"rIATiHAZ!K)H*LSU+LBL)LBb1N!#4NT+ 4MS9hC8ie(KNhBi18Q*50L)0pHRYmIAjrJ)'#K)D+MBk-L)1"J)#!JB5)M)f1MBb -LiQ'Ji"rIRjrIi#!J(pmHRPkIB'&KiL*LSQ*L)L+M)q5NT'4MiTrEeP#+KNQ6hD 0Q*H3!)U&J(akHhaqIi#!JB+%KiZ0M)U'Ji+"JB'#KBQ-MBf-M)b,LBD#J(pqIRj qIRprIAYjHAb!K)D)LBQ*LBL)LBZ1NC+5NBq-KAPS8MSN($9IJ*+BP)f(JRekHha qJ)#!JB'#JiD+M)U(KB1$Ji1#JiD+M)f-M)b-LiQ&JS"rIRjqIRjqIRekHAYqJSD (L)L)L)L)L)U-Mj'5NT+3!)Z#G&p(,"JK5A',Q*L4LS@!HhTmIRq"JB'"JB+&L)U ,LBD%Ji1$Ji1&L)Z-M)Z,M)Z+Ki5#J(prIhprIRjpI(PjI)#%KiL*LBL)L)L*LSf 2N!#4NC'0KhYU8cSM(6GKJC5CNib'JAekHRarJB+#JS'"JS@)LSQ(KB5%K)5$K)D *M)b-LiZ-LiQ'K)+"IhprIRepIAakHATqJiH)LBQ)L)H(L)Q-Mj'4NT'2LS"aA88 X'LC1GBkCPiq)JhjkHAYpJB1$JS+"JB+&KiL(KB5%KB@%K)@)Lif-LiZ,LiZ*KS5 $JAprIRepI(YkHAPmJB@)LBU*L)H(KiL+MC!!NC+4MiZ%HQP814dB1'@'PjU6Li9 rHRKjI(q#K)5$JB'"Ji@(KS@%K)5&KB5%KSQ-M)U+LiZ,LSH&K)1"IhjqIAemHhP jHRq$KiQ+LSQ(KiH'L)U1N!#4N!#3!)k)Ih&G45F9+eTqP*Z@MBH"I(PiHRf"K)@ %JS'"JS5'KS5$Ji5&KB@&KSL+LiU*LSZ,LSL'KB5#J(jqIAamHhPiHAb"KBL+LiU )KiD'KiQ0N!#4N!#2MBU$GfC40"SK5R11QjQ3!)Q$I(KhHAYrJiD'Ji'"JB1&KB5 $Ji5&KSD'KSH*LiZ+LBU,LiQ(KSD&Ji"qIRemHhPhH(Z!K)H*LiZ*KiD'KSL,MT! !N!#3!)k,KRaX9MNH(d*XLCLDNSU%IAKfH(TqJS@'K)+"JS1%K)1#JS+%KSD'KSD )LSZ+LBU+LSQ(KB@'KB&rIRemHhPiH(TqJSD)LSZ,LBH'KSH+MT!!NC'2M)GrF&a "*4`hBB+@Qj@0KRpjGRGjI)#%KSD%JS+#Ji1#JB'#K)D(KiH'L)U,LiU*LSU*L)H 'KiH%JAjpI(YjGhCjIB'&KiQ,LiQ(KSD'LBb3!*'3!)q-L)*hC%XU&LP@Hj+FQ)q )JATfGRKlIi1&KS@$JS+#Ji+"J)'$KBH(KiD(LBZ+LBQ*LBQ)KiD(L)D$J(ppHhP hGRGlJ)5'L)Z-LiL(KS@(Lik3!*'3!)k*JRPT9$8C)%TcMTbENiZ%I(CeGhTqJS@ (KS5#JB'#JS#!JB+&KiH(KSH*LSZ+L)L*L)L(KSH*L)@"IhemHRKfGhTrJi@(LSb -LSL'KSH+MBq2Mik+JhYY@MmL'caTLCUGPSf'IAGdGRPpJB@(L)D%JS'"JB"rIi+ %KiL(KiH)LSZ+LBQ*L)H'KSH*LSH$J(jpHhKfGAKpJB@(LBb-LSL'KBD*M)k2N!# 2M)CrFf*++aJY@i#@RTQ2L)&jG(9iI(q%KiL(KB1"JB'!Ihq"Ji@(KiH(L)U-LiQ *L)L(KS@'LBZ+KS&rIRakGR4fHi#%KSL+M)b,LBH'KiZ0Mj!!MSb)J(9N6M!A*&& lNjkFNiU$HR4cGRTqJSD)L)D%JS'"J(jqJ)+&KiH(KiL+M)b+L)L)KS@&KBL,LiH $J(jpHRGdGAPqJS@(LSb0M)U)KSD*M)k2Mif*JhPV9c`J($pYLjZHPBb&IA9bG(K pJB@)LBL&JS#!J(pqIi'%KSH(KiH*Lib,LBL)KiD%K)H,M)U%J(pqI(PeG(GmJB5 'LBZ-M)Z*L)H*M)k2Mik+K(YY@6iK'$CQLCZIQ)q)IhGcFhGlJ)5)LBQ'Ji'!J(p qIS#%KSH(KiH)Lib,LBL)Ki@%K)@*M)Z'JRpqI(TfG(ClJ)1&L)U-M)Z*L)H)LSk 3!)q1LS9qFQ&+,4ST9Ab9RjZ5LS*jFh*eHRq$KiQ*Ki@#J)"rIRk!JiD)L)H(L)Z 0M)U)L)H'KB5&LBb-LB5!IhekGh9eHAk#KBH+M)b,LSQ)L)U0Mj!!Mib)JAGP6M! @(8ThNTqHPBb&I(9cG(KpJSD)LBL'Ji'!IhjqIi+&KiH(KiL*M)b+L)L)KS@%K)H ,MBU&JApqI(PfGAKpJB5'LBZ,LiU*KiH*MBq3!)q0L)&iDPBq*"ilD)QERTL2Khp fFR0fHi#&L)U*Ki5"J(pqIRq"K)D(KiH(LBb0LiQ)L)H&Ji1'LSf-Ki1!IhekGh9 hI)#$KBL+LiZ+LSQ)LSb2NC!!MSU$HQaB3#BD-@#&QU#DNBQ"H(0cGAPqJiH+LSL &JS"rIReqJ)1'KiH'KiQ,MBb+L)L(KB1$KBQ0MBL$J(jpHhKfGRYrJS5'LBZ,LSQ *L)Q,MT!!NC!!M)9pF&j),KSP6hU8Rjf8Li4lGA*dH(f"KSQ+LBD$JB"rIAk!JS@ (KiD(L)U-M)U)KiH'KB5%Kib0LS@"IhjmHAChHRk#K)D)LSU+LSQ*LBZ1NC'3!)f )J(9N6M8F(%*aMjkIPSk(IRCbFhGlJ)@*LiQ(Ji'!IhjpIi+%KiH'KSH+M)b,LBL (KS@%K)D+MBZ'JS"qIAThGRKpJB1&L)U,LSQ*LBQ+MC!!NC!!MiZ%HQY@2#%@-Q+ (R+'CN!#*J(KcFhCkIi1(LSZ)K)+!J(jpIS#$KSH'KSH*M)f-LBH(KS@&K)@*MBf )Ji"rIAYhGRKpJB1%KiQ,LiU*L)Q+M*!!NC'2Li4lEPY%+4JT9hqAS*b5LS0kG(0 eHAf#KSU,LB@$JB"rIRk!Ji@(KiD(L)Z0M)U)KiH'KB5&L)b0LS5!IhjmH(ChHi# $KBD)LSU+LBQ+LSb2NC'3!)f'IR&J5M%E)%KfNTqIPBb&I(9bG(KmJ)@*LiQ(Ji' !IhepIi+&KiH'KSL,MBf+L)H'KB@%KBL,M)U&JApqI(PhGhTrJS1&L)U,LSQ*LBQ ,Mj'4N!#0L)"dBdie("Y!EifGS*H1KhphFh0fHRk%L)U+L)@#J)"qIAk"K)H(KiD (LBb0LiQ(KiD&K)@(LSb,Ki*rIRekGhGkIS+%KBH*LSU*LBQ*Lik3!*'3!)k*JRK T96`K&c0MKjZKQT!!LB&jG(0fHAk#KSQ+L)D$JB"rIAk!JiD(KiD'L)Z-LiQ(KiD &K)@'LBb-L)1!IRelH(CjIS+%KBH*LSU+LBQ*LSb1N!#3!)q+JhPX@%!P'#jGJjQ JQj+,JhTdFh9iIB'&LBU*KS1"J(ppIAq#KBL)KiH)LSb-LSL(KS@%K)D)M)f+KB& qIAYiGhKpJB5&KSL+LSQ*LBQ+M)k3!*!!Mib'I'pF45SB*P0mPD#GP)b&I(CcG(K mJ)@*LSU(K)+!IhemIS+&L)L)KiL+M)f,L)H'KB5%KBH,MBZ'JRpqI(PhH(b"Ji5 &KiQ+LBQ*LBU-MT!!NC!!MBGpF&j),KJK6(L6S*k9MSGqGR0dGhYrK)L+LSL&JS" rIAeqJB5(L)L(L)U-M)U)KiD&K)5&KiZ0M)L$IhjmHAGhHi#$K)@(LBU+LBQ*LSZ 0MT!!N!#1L)"cBN`b'Ke%FSqIS*D1L(phFh0fHRk#KSQ+L)D$JAppI(f!JiD)KiH (LBZ-LiQ(KS@%K)5'LSf-L)5!IRakH(GkIi1&KBD)LBQ*LBQ*Lif2N!#3!)k+JRG R86BD&ceYMCfJQ*!!LB&iFh0eHAk#KSQ+LBH$JAppI(erJSD(KiH(LBZ-LiQ)Ki@ %Ji1&LBb0LS@"IRelH(GjIS+&KB@(LBQ*LBQ*Lib1Mj!!MSQ#GfP925)E1@H*Qk# CN!#+JRPdFR4iIB'&L)U*Ki5"IhemI(q#KBH)KiH)Lib-LSL(KS5$Ji@)M)f,KS* rIAYiGhPqJi@&KSL+LSQ*LBQ+Lif2N!#2M)9kE&P"*4J`B)@DSCU5Li4kG(*dH(b "KBL+LBL&JS"qI(aqJS@(L)H(L)Z-M)U)KiD%Ji1%KiZ0M)L$IhjmHAGiIB'%KB@ (LBU*LBQ*Lib1Miq1Li4jE&Y&+aXX@(q@S*b6MBCpGR0cGRZ!K)H*LSL&JS"qI(a qJB@(L)L(L)U-MBZ*KiD%Ji1$KSU0M)Q%J(jmHAGhHi#%KB@(LBQ*LBQ*LSb0MT! !Mib(IA"I55dB*&"kP+#GP)k(IRCbFR9kIi1(LBU)KS1!IRalIB'%KiL)KiL+M)b ,LBH'KB1$Ji@+MBf*KB&rIAThGhU!Ji@&KiL*LBQ*LBU,MBk3!*!!MSKrFf*0-KS I4h54Rjq@MiKrGh*bGAPqJSD*LSQ(K)&qI(YpJ)1'L)L(KiQ-MBb*KiD&Ji+#KBQ 0MBU'JRppHhKfHAk$KSD'L)Q*L)L)LBU-MT!!NBk*JACR8cNG'$YVM*fJQ*!!LS* jG(0eHAk#KSL*LBH%JApmHhf!JiD(KiH(LBZ0M)Q(KS@$JS+%L)b0LiD#IhelH(C iIB+&KSD)LSU*L)L*LSb1N!#4MiU#H'P@25)C0Q5(Qk#CNBZ$HR4bG(KpJB@)LBQ )KB*rIAYpIi+&KiL(KiQ,MBf,L)D&K)1#JiL-MSZ(Ji"qHhKfGhb#KBD'L)Q*LBL )L)Q,MBq4N!#-KRaZA%3Q&#TDJCLKR*+-KAaeFh4hI)'&KiQ*Ki5#J(emI(q#KBH (KiH)LSb0LiL(KS5$JS+'Lif-L)5"IhajGRGmJB5'KSH*LBQ)L)L*Lif2NC!!MBC qFQ"+,aNM6RQ6Rjf8MSGqGR0cGRYrJiH*LBL&JS"qI(aqJB5'KiH(L)U-MBZ)KiD %Ji+#KBU0M)L%JAppHRCfHAq%KSD(LBU*L)L)LBU-Mj'4MSQ"G'01-KNF4A13!*k IPSk*J(KdFh9jIi1(LBQ)KB1!IRemIS'%KSH(KiH*M)f-LBH'K)1#JS@*MBf*KB& rIAThGRKqK)D'KiL+LBL)L)L+M)k3!*!!MSU$H@T@2"mA1'H*R+#BMiU#HA4cGAP qJSD)LBL&Ji&rIAeqJ)1&KiH'KiQ,MBb*KiD&K)1#K)L-MBU'JS"qHhGeH(f$KSD 'L)Q*L)L(L)Q,MT!!N!#2M)CpF&e%*43X@i+BS*U4Li9lGA0dH(f"KBH*LBD$JB" qIAerJS@'KiH(L)Z0MBU(KS@$JS+$L)b0LiH$JApmH(ChI)'&KSH)LSU*L)L)L)U -Mj'3!)f'IA&J5LmD*P&kP*qFNif'IACcG(GmJ)5(LBQ(K)+!IRepIi+&KSH(KSH +M)f,L)D&K)1#JiD,MBZ(K)&qI(PfGhZ!KBD'L)U+LBL)KiH*M)q4N!#0L)"fCe- j(Ka"ESfHRjD1L(piG(4hHi#%KSL*Ki5#J(pqIAq"JiD(KiH(LBb0LiL'KB5$JS+ 'LSf-L)5"IhekGhCjIS1'KSH*LSQ*L)L*LSf2N!#3!)k*JACR86BG(%"VLTbIPiq *JRTeFh9kIi1'L)Q)KB+!IhjpIi'%KSH(KiH*Lif,L)D&K)1$JS@+MBf*KB&rIAY hGRKqJiD'KiL+LSQ)KiH)Lik3!*!!MiZ%I'pG45F@+eU!Pk#ENBZ%Hh9cGAPqJSD )LBL&JS"rIRjqJ)+&KiH'KSL,MBb*KiD&Ji1$K)Q0MBU'JS"qHhKfGhb"KBD'L)U +LBL(KiL+MT!!NC!!MBGrFPp'*a)P9Ak@S*b5M)9pGh4eH(f"KBH*LBD$JB"qIAk !JS@(KiH(L)U-M)Q(KB@%Ji+%L)b1LiH$J(jmHACfHi'&KSH)LSU*LBL)L)U0Mj! !Mif)J(4M66-G)dYeN!#HRC5-KhjhG(9hI)#%KiQ*Ki5"IhjpIAq"K)D(KiD(LBb 0LSH&KB5$Ji5(Lik-Ki1!IRajGRCkJ)5'KiL*LSQ)KiH'L)b2NC'2M)9lE9Jp(K8 hCiLERjH2LB*kGA4hHhq$KSL*Ki5#J(pqIAk!Ji@(KiH(LBZ0LiH&KB5$JS1'LSf 0LB@"IhekGhCiIB+&KSH)LSQ*L)H(L)Z1N!#3!)q-KAa[@d!M&c0JK*QJQBq+JhY eFh9jIS+&L)Q)KB+!IhjpIS##KBH(KiH)Lif-L)@%Ji1$Ji@*MBf+KB+!IRYhGAG mJB5'KiQ,LiQ)KSD(LBf3!*'3!)f)J(9P6M%C)8TfNTqFNiZ'IACcG(KpJB@(LBQ 'Ji&rIRepIi'%KSH(KiL,MBb*KS@%Ji1$K)L-MSZ(Ji"qI(KeGAU!Ji@'L)U+LBL (KiH*M)q3!*!!MSU%HQY@14N@2Qk-R*k9MBL!HA9eGhYrJiH*LBH$JB"rIRjrJB5 'KiH(L)Q-MBU'KB5$Ji1%KiZ0M)L%JAppHRCeHAk#KBD)Lib,LBL(KiL,MSq3!)k ,KAYY@6mN($KPKjUIPiq*JRTeG(CkIi1'LBU)K)'!IhjqIS#$KSH(KiH*M)f,Ki@ %K)1$JiD+MSf*KB&rIAPfGAKpJS5'KiU,LSQ(KB@'LBf3!*'3!)f)JhPT8c3A(%P hNTkFNiZ&IACdGAPpJB@(LBL&JS"rIhjqIi'%KSH'KiL,MBb)KB5$JS+$KBQ0MBU 'JS"rI(KeGRU!Ji@'L)U+LBL(KSH*M)q2Mif+K(aY9MJC&d&aMjfHP)b(J(KdG(G lJ)5(LBL'JS#!IhjqIi'%KSH(KiH+M)b*KB5$JS+$K)L-MBZ(Ji"qI(KeGAPqJS5 'LBZ,LSQ(KSD(LSf2Mif+KRpcB%FS'$"IJjLIQ)q*JRTdFhClJ)5(LBQ'Ji'!Ihp qIS##KBH(KSD)M)f,Ki@%Ji1$K)H,MBb)K)&rIATfGAGmJ)1&KiQ,LSQ(KiD(LBb 1Miq0L)0jD9)b&Kp1HC1IQj'+KAehG(CjIS+&L)Q(K)+!J)"rIS##K)D(KSH)LSf -L)@%Ji1$K)@*MBb*KB'!IRajGAClJ)1%KSQ,LiU)KiD'L)Z0MBf0LiCqEPJk'KT #F)kHRT5-Ki"iG(9iI)#%KiQ)KB+!J)"rIRq"K)H)KiH)LSb-LBD%Ji1$K)@)M)f +KS+!IhajGA9jIS+$KBL,LiU*L)H(L)Z0MBf0LiH!Fep&)a8cC)DDRjL1LB*jG(4 hHi#%KiQ)KB1"J)"rIRq!JiD(KiD'L)Z-LSH&K)1$K)@)M)k-Ki1!IhekGR9iIB' $KBH*LiU)KiH'KiU-MSk1M)L$H'C0+K-Q9Rq@RjU4LS0mGR4fHRk#KSL)KS5"J)" rIRk!Ji@(KiD'KiU-LSH&K)1$K)5'LBf-L)5"IhelGh9hI)#$K)@)LSU*L)H(KiQ 0MSk0LiL$HQY80KXJ5A53!*fFNib'IRGdGAKpJB@)LBL&JS#!IhepIi'&KiH(KSH +M)b*KB5$JS1%KBQ-MBU&JS"qI(KfGRTrJB1&L)U,LSL(KSH)M)k1MSf+KRpcAd- L&MGRL*ZIPSk)JAPdG(GlIi1(LBL'Ji'!J(jpIS#%KSH(KSH*Lib*KS5%Ji1%KBL -MSZ(Ji"rIAThGRPqJB1&KiQ+LSL(KSD(LSk3!*!!MSZ'JACP65`@+PPrPTqENBQ $Hh9cGRTqJSD*LBH%JB#!IheqJ)1'KiH(KiL+M)U(KB5$Ji1%KSU1MBL%JAppHhG eGhb!JS5'LBZ+LBH'KBD*MBq2Mif+KAe[@6SD'8*aMTkHP)b&IAGdGAKpJB@)LBL 'JS#!IhepIi'&KiH'KSH+M)b*KS5$JS1%KBQ0MSZ'JS"rI(KeGRTqJS1&L)U,LBL (KSD)Lik2MSf,L)&eB83K%c4PKjUIPik)JAPdG(GlIi1(LBQ'Ji'!J(jpIS'$KSH (KiH*Lib+KS5$Ji1$K)H-MSZ'JS"rIAPfGAKpJB1%KiU,LSL(KSD(LSf2Mif,Ki* jD9%`&b96I*5IQj++JhYeFR9jIS+'LBQ(K)'!J(ppIS#$KBH(KSD)Lib,Ki@%Ji1 %K)D+MBb)Ji"rIAYhGAGlIi+%KSQ+LSQ(KiD(LBf1MSk0LSGrF&Sm("JrESbGRj@ -KAjhFh4iI)'&L)Q)KB+!J)"qIRq"K)D(KSD(LBb-LB@%Ji1$K)D*M)f+KB+!IRa jGRCjIS'$KBL+LSQ)KiD'L)Z1MSk0LiQ$GQ*')a-[BS@CS*Q2L)&kG(4hHhq$KiQ *Ki1"J)"rIRq"JiD(KiD(L)Z-LSD%K)1$K)@(Lif,KS+!IhajGR9iIB##K)L+LiU *KiD'KiZ1Mif-LSL%HfT4-"8N8RZ6Rjb4LS0lGA0eHRk#KSQ*Ki5"J)"rIRk!JS@ (KiD'L)U-LSH&K)1$K)@(Lif-L)1!IhelH(ChHhq"JiD*LiZ*L)H'KiQ-MSf0MBZ (Ih"D2KmC2@b,RCq@MBCrH(0dGhb"KBL*L)D#J)"rIRjrJS5'KiH'KiQ-M)Q'K)1 $K)@'LBb0LS@"J(jmHAGhHRk"Ji@)LSU+LBL(KSL-MSk0MBZ)JA4J4588,f'&QD# CMiL"HR4dGRTrK)H*L)D%JB#!IReqJB1'KiH'KSL,M)Q'KB5$Ji5&KiZ0LiD#J(j mHRGfH(b!JS5(LSZ+LBL(KSH+MBk1MSb+KATT86%@)8piNU#GNSU$I(9cGAPqJSD *LBH&JB#!IheqJ)1&KiH'KSH+M)Z(KB5$Ji5&KiU0MBL%J(jpHhKfGhYrJB1'L)U +LBL(KSD*M)k1MSk,KRjZ@$XE'%"[MTqJPSb'IhKcG(KmJ)@)LBL'JS#!J(jqIi' %KSH'KSH*LiZ)KS@%Ji5&KSL-MBU&JApqI(PhGhTqJB1&L)U,LSQ)KiD*MBq1MBb +Ki&cAN)K&6CQKjbKQ)k)JAPdFhClIi5)LBQ(Ji'!IhjpIS#%KSH(KSH)Lib*KS@ %Ji1%KBL-MSZ'JS"qI(ThGRPpJ)+&KiQ,LSQ)KiD(Lik2MSk-LB4iC8XU&#GAIjH JQj'+JhYeFh9jIB+'LBQ)K)'!IhjpIB#$KBH(KSD)LSZ+Ki@%Ji1%KBD+MSf)Ji" rIAYiGRKmJ)+$KSL+LSQ)KiH)Lik2MSk-L)0jD9!`&5&3Hj5JRC1-KAeeFR4iI)' &L)Q)KS+!J(ppIAq#KBH(KiD(LBZ,L)@%Ji1%K)D)M)f+K)"qIAYiGRGlIi+$KBL +LSU*L)H(LBf1MSf-LB4mEPJk("e&FBfHRj@0KRphFR0hHi#%L)Q*Ki5"IhppI(k !JiD)KiD(LBZ-LBD&K)1%K)@(Lif,KS*rIRajGhGkIS'$K)H*LSU*KiH(LBb1MSk 1LiD!FPe")4FiD)LES*L2LB*jFh0fHRk$KiQ*L)@"IhppI(f!JiD)L)H(L)U-LSH &K)1$K)5'LSf0LB5!IhekH(CjIB'$K)D*LSU*L)H'KiU0Miq2M)H"GQ4+*a-XAS+ BSCb4LS0kG(*eHAf#KSQ+L)D#J(pqI(erJSD)L)H'L)U-LiH&K)1$Ji5&LBf1LS@ "IhelGhCiI)##Ji@)LSU*L)L(KiU1N!#2MSZ'JRTV9$-B)NpjNjqGP)b&IA9bG(K mJB@)LSQ(Ji"rIRamIS'%KiL(KiH*Lib*KS@%Ji1%KBL-MSZ'JRppI(PfGhTqJB1 &KiQ*LBQ)L)L+MBk1MSf+KAeY968@'dPeN!#IRT@0KhphFR0hHi#%KiQ+L)5"Ihj mI(k"K)H)KiD'L)Z-LBH&K)1$Ji1'LSk0Ki*rIRajGRCkIS'$K)H*LSQ*L)L(L)Z 0MSk0LSCqF9`r(KNqE)ZGS*H2L)"hFR*eHRq$KiQ+L)D#IhjmHherJiD)KiD(L)Z -LSH&K)1$Ji1&LSf0LB5!IRekGR9iIS'$K)H*LSU*L)L)LBZ1MSk0LiCqF9`q(4F lDSUFS*L3!)U#HA0bG(PqJSD)LSQ'JS"qI(YmIS+'L)L(KiL+LiU)KS@%Ji1$KBQ 0MSU&JAjpHhGeH(f"Ji5'LBU+LBQ)L)L+M)f1MSZ'Ih4L5#JC-f#$Q+#DNSZ%HR4 bG(KqJS@)LSQ(K)"rIAYmIS'&L)L(KSL+M)Z)KS@%Ji1$K)L-MSZ'JRpqHhKfH(f "Ji5&KiQ*LBQ)L)Q,M)f1MSb)JA4L4bFD-f#$Q*qDNSb&I(9bG(KmJB@(LBQ(K)& rIAYlIB#%KiL(KSH*LiZ*Ki@%Ji+#JiD-MSb)Ji"qI(PhH(b!Ji5&KiQ*LBQ)L)L *M)k1MSb(J(9P6#dF-&YrPCqENib&IA9bG(GmJ)5(LBQ(KB&rIAYlIB#$KiL(KSH *LSZ*Ki@%Ji+#JS@+MBb)K)"qI(PfGhb!Ji5%KSL)L)L)KiL*Lif2Mib(JAGT8c- E+PCmNTkENSb(IRGdG(GlJ)5'L)Q)KB+!IAYlI(q$KSL(KSD)LSZ*Ki@%Ji+"JS5 )M)b*KB&rIATiGhTrJS5%KBH)L)L(KiH)LBZ-MBb)JhTY@MdN+NpfMTbFNif(J(K dG(ClIi1&KiL)KS+!IAYlI(q#KSH(KSD)LSZ*Ki@&Ji+"JB1(Lib+KS+!IRYiGhT qJS5%KBH)L)L)KiH)LBZ0MSf*JRTY@d%R+8edM*ZFNif)JAPdG(CkIS+&KiQ)KS1 !IRalI(k"KBH(KSD(LSZ+L)D&Ji+"J)+'LSb+Ki1!IRYiGhPqJS5%KBD)L)H(KiH )LBU-MBb*KAjbBNNX*dCZLCLFPBf)JRTeG(CkIS+%KSL)Ki1"IhalI(k!K)D'KSD (LBZ+L)D&Ji+"J)'&LSb+Ki1"IhajGhKpJB5%K)D(KiH(KiH(L)Q,M)b+KApeC8d [*N0VKTHDNif*JhafG(CjIB'%KSL)KS1"IhelI(k!JiD'KB@'L)U+L)D%Ji'!J)' &LBZ*Ki5"IhekGhKmJ)1%K)@(KiH(KiD(L)Q+LiZ*KApeCP%h,80SK*5CP)f*K(a fGACjIB'$KBD(KS1"IhelI(f!Ji@'KB@'L)U+L)D&K)+"J)#$L)U*Ki5"IhekH(P mJ)1%K)@'KiH(KiD'L)U+M)b*K(phDPBp,MpNJC+CPBk+KAehGACjI)#$KBD(KS5 "IhemI(erJi@&KB@'KiQ+L)D%K)+"J)#$KiU+Ki5#J(jlHAKlIi1%K)@'KiH'KSD 'L)Q+LiZ+Ki&jE&P!,ceJIT!!Q*@1LS9rHACfH(b!Ji@'KiD%JS"qI(apJ)+%KS@ &KBH*LBL'K)5#JB#!JSD*LBH&JS"qI(PiHhq#K)5&KSD'KSD'KSH)LBU,LSL$Hfp I4c)i@RU0PTD2LSD!HRCfH(YrJi5'KiD%JS"qI(apIi+%KB@%KBD)LBL'K)5$JAp rJB@*LBH&JS"qI(PiHRk#K)5%KSH(KSD&KBD)LBU+LBD"HR"L6$Fl@RL,PTD2LBD !HRGfH(arJS5&KSD&JS"qIAapIi'$KB@%K)D)LBL'K)5$JB"rJB5)LBH&Ji&rI(T jHRk#Ji5%KBD'KSD&KBD(L)Q+LSL$IA0Q86`k9(1(Nj@2LSH"HhGhH(YrJS5&KSD &JS"rIAapIS'$K)5%K)@(LBL'K)1$JB"rJ)1(LBL&Ji&rIATjHRf"Ji1%KBD'KSD &KBD(L)Q*LBH$IRCT9Mmk8R'&NT52LSH$I(KhHAYqJB1%KBD&JS&rIAapIS##K)5 %K)@(L)L'K)1#JB"rJ)1(L)H&Ji'!IRYjHRf"Ji1%K)@'KS@&KB@'KiL*LBH%IhG X@dFq8'f$Mj53!)U(JhjjGhKlIS'$K)@'KB+!IhjpIAk!JS5%K)5&KSL)KS5$Ji+ "J)##KSL(KB1"J(jmHRTpJ)+$Ji5&KS@&KB5&KSH)LBQ(K)&kF@*02NTSIif6NBZ (JhjkH(KlIB'$K)@&KB1"IhjpIAk!JS1%K)5%KSH)KS5$Ji+"Ihq"KBL(KB1#JAp mHRTmJ)+$Ji5%KBD&KB@&KBD(L)L(K)"jF'033NeSISb5N!#,Ki4rHRKiHRf!JS5 %KB@$JApqIAeqJ)'$K)5$K)@(L)H&Ji1#J(prJB5(Ki@$JB&rIATkI(q"Ji1%KB@ &KB@&K)@'KiH)Ki@#IA4R984+BhU*NC!!LiH%IhYiH(TpJ)+$K)@&Ji&rIRepIRq "JS1$Ji1&KSH'KB1#JS'!Ii#$KSH&Ji+"IhelHRYqJB1$Ji5&KB@&K)5%KBD(L)H &JReeDPK(5Q*jL*!!N!#,Ki@!I(PjHRf!JS1%K)5$JB"rIReqIi'#Ji1$Ji5'KiD &Ji+#JB"rJ)1'Ki@$JB'!IRakHhq"JS1$K)@&KB5%K)5&KSD(Ki@"IACVA%e1BAH 'MSq,Ki@"I(PjHRerJB1%K)5$JB"rIReqIi'#Ji1$Ji5&KSD&Ji+#JB"rJ)+&Ki@ $JB#!IRalI(k"JS1$K)5&KB@%K)5&KBD'KS5#IRP`BP*0AA1$M)q-L)@"IATkHha rJB+$K)5$JS"rIRjqIi##Ji1$Ji5&KSD&Ji1#JB"rIi+&KSD%JS#!IhelHhf!JS+ #Ji5%K)5%K)5%KBD(KS@#IRK`Be42Ah5$M)k,Ki@#IRYkHRaqJB+$K)5$JS"rIRj qIi#"JS1$Ji1%KBD&Ji+#JB"rIi'%KS@%JS'!IhelI(k!JB+#Ji5%K)5%Ji1%KB@ 'KS@#IhYcD&T4@h"rLBf,Ki@#IhYkHRaqJ)+$Ji5$JS"rIReqIi#"JS1$JS1%KBD &Ji+#JB"rIi'%KS@%JS'!IhemHherJB+#JS1%K)5%K)5%K)5&KS@$J(adD9Y6A(" rL)f,Ki@#IhakHhaqJ)'#Ji1$JS"rIRjqIi#"JS1$JS1$K)@&Ji+#JB"rIi'$KB@ %JS'!IhjmI(erJB+#JS1%K)5$Ji1$Ji5&KB@$JAehEf&9@QemKSb,Ki@$IhalHha qJ)'#Ji1$JS&rIRjqIhq"JS+#JS+$K)@%Ji+#JB#!Ii##K)@%JS'!IhjpI(erJB+ #JS1$Ji1$Ji1$K)5&KB5$JAjjF@9EA'YkKBU,Ki@$J(elHhaqIi'#Ji1$JS'!Ihj qIhq!JB+#JS+$K)@%Ji+#JB#!Ii##K)@%JS'!J(ppI(eqJ)'#JS+$Ji1$Ji+#Ji5 %KB@$JAplG'TH@fKiJiQ,L)@$J(emHhapIi'#JS1$JS'!IhjqIhq!JB+#JS+#Ji5 %Ji+"JB#!Ii#"Ji5$JS'!J(ppI(aqJ)'"JS+$Ji1$JS+#Ji1%K)5$JApmGQjLA@G fJBH+L)@$JAjmI(apIi#"JS+$JS'!IhjqIRq!JB'#JS+#Ji5%Ji+"JB#!Ihq"Ji5 $JS'!J(pqI(aqJ)'"JB+#Ji1#JS+#Ji1$K)5$JS"pH("QB'CdIiD*L)@$JAppI(a pIi#"JS+#JS'!IhpqIhq!J)'#JS'#JS1%Ji+"JB#!Ihq"JS1$JS'!J(pqIAeqIi' "JB+#JS+#JS+#JS1$Ji1$JS"pHA*UBfGdIi@)Ki@$JAppI(apIS#"JB+#JS'!Ihp qIhq!J)'"JB'"JS1$Ji+"JB#!Ihq!JS1$JS'!J(pqIAeqIi#"JB'#JS+#JS+#JS+ $Ji1$JS&rHh9ZCQGbIB1(Ki@$JS"qIAepIS#"JB+#JS'!J(prIhq!J)'"JB'"JS+ $Ji+"JB'!J(q!JB1$JS'!J(prIReqIi#"JB'"JS+#JS'"JS+#JS1$JS&rIAKaD@K `Hi+'Ki@$JS"qIAepIRq!JB'#JB'!J(prIhprJ)'"JB'"JB+$JS'"JB#!J(q!JB+ #JS'!J)"rIReqIi#!JB'"JS+#JS'"JB+#JS+#JB&rIATeEQY`HB#%KS@$JS"qIAe pIRq!JB'"JB'!J(prIhprJ)#"JB'"JB'#JS+"JB#!J(q!JB+#JS'!J)"rIRjqIi# !J)'"JB'"JB'"JB'#JS+#JS'!IRYhF@e`HAq$KB5$JS"rIReqIRq!J)'"JB'!J(p rIhprJ)#!JB'"JB'#JS'"JB#!J)#!J)'#JS'!J)"rIhjqIi#!J)#"JB'"JB'"JB' "JB+#JB'!IhejG("bH(k#K)5$JS&rIRjqIRq!J)'"JB'!J(prIhprJ)#!JB'!J)' "JB'"J)#!J)#!J)'"JB'!J)"rIhjqIhq!J)#!JB'"JB'"JB'"JB'"JB'!IhjlGh0 bGhf"Ji5#JB'!IhjqIRprJ)#"JB'!J(prIhprJ)#!J)#!J)'"JB'"J)#!J)#!J)# "JB'!J)"rIhpqIi#!J)#!J)'"JB'!J)#"JB'"JB'!J(jpHRCdGhb!JS1#JB'!Ihj qIRprJ)#!J)#!J)"rIhprIi#!J)#!J)#"JB'!J)#!J)#!J)#"JB'!J)#!IhprIhq !J)#!J)#!J)#!J)#!JB'"JB'!J(pqI(KhH(arJB+#JB#!IhprIhprJ)#!J)#!J)" rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhq!J)#!J)#!J)#!J)# !J)#!J)#!J(pqIAakHRarJ)'"JB#!IhprIhprJ)#!J)#!J)"rIhprIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhj mI(erJ)#"J)#!J(prIhprIi#!J)#!J)#!IhprIhq!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprJ)#!J)#!J(p rIhprIi#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J!!!3N!!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!%) @9Zk,S`!!3K3!!%)9!$b!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rJ)#!J(q!J(prIRk!JB1 $IAeqHAZ'Li9pGh0lJ)#(MhKXIhaqJ)D(IhjZH)PjGiU8H'D'I@b,P)CaFReiJAp qL(YiL)0hG(&jLi9rPS49Ci9rMU5(DhCP9)LXMhf!J'44GTfFLSk'B9eNF+LJH*@ (6df'Qi+AM(Pk8'LEJAqJLeTdM'&lRAKqPh"VMRPSL)afLSYUIi*XJ)4mLiPSGTP ZAjD5HB"pIS"TC*DPFA10G'KYJjU1IRehCA#6IhZFI'TmH(5'M(Q#Lh&cL(KfL)C qG)#%HhacLSTVHSq&DhLAGQQ1NAGaI(PjLi#)Q(&LGhadLD5-FATRB(q)NjL5F9p lD@HDU)CeK(G@DBkCPhjlJ'aLGSq9MRpaGi"SG*Z4I(GrHfalLB&qKiTZFT0eCiq 5FAH4Hh'#Gh@4Kfk(PR0JIC&mH)11LfPNKT4eFj@2FR"lHB1(GS19G@H(K@f"Qh9 VNS*RIBZ!I(jqIBYcE*Q'DRD0KfYqKS'(Fh@0I'f)NATbMApMIi9rMS&mIAP`F)f *J)epG(0aJS@!KC!!JQG`K)"pKSH&H@eiKB&rLB4hH(CjLiKdJ)j`CiQ)ISGqG(k $EhUCJACpFhjpH)Z3!(KXL)"IM*KkK)&aFS*kHj@*F(erGAKiNj*VH*4mARkBGhL 1HRjmGB*rIi+%HRZ'Ehb3!'akRRjNM*!!ARLAHAZ-I(GkFB#1I(Q4I'q*IQk'L(5 !KRPmL(GeM(phJB@'H(D%Ih0hMBKkL(abJhTZLTjrChq)FA*mNjTeDAq0G'Q1QS9 [DBU'D(UIQ@9UMRYZJj+1GA'$Gh5*P)"`KhY[KRb(PhKXJiKMHk4qHBKfFhYeL*Y pF*+!9iLBDhbAJ@prKB4mCS5NF'5IQ'*MKSZ'GAUSL8Y`S(pUM*U#FfGiQ(0YSTC UEBGqFi1(MB0ZJB4YIC@$GS1&Hh9hJT!!G@qCKQb'J('!KRU,P'TaMR&ZNj*rJhC YJS4mM*&hGAe[I)f%KBTlFB"mFiZ5K(TcH(ahHjH@FAL!Eh5)Mj!!L'jTKRjPMUQ (E('!GR+)NBq"F(*fIRq'PiCfH(9hJS@'LiC[GBK[HjYqDiU-Eh51JhU+H(H-G@b %P)TfHB0jGRZ-MhGaKB9eH)q-ChH9IhL'IR&lKhZ,Q@pZJh0dMj4lHBCeE(k*N!# #G)@(F@D&Q)"cL)paE(Z%MSCeJBpdBBZ8Ehb4IR1(Ih1$JRKpMS9rHA"qJ(b+N!# "H(GjFi+2I)Q-DfL(M'k$TATSKAjQG*f4ISChFh"VLkD0FhU%G'"pMiq9FhQ*BfD 3!+*mG*Cm@A+@L(4kMSCiJRYlGQf$R)pVHiGKCSqIM(elFhCXGCf4JAamDfL)JB@ 3!)KmE(YlDifBI(U-H9pqM(D'Q(PYLRYXJi4jK*&rGS&bGB*cN!#LG'+%K@*hSj9 lI(0YHRCpPT0lI)pQ6BbLKB14J&PHHT5QJRD@G%PXQjZ&JiGlCe9rVSPiPiGL@hU 2LBk4MA*EERjqN!#DMi4VAh@"ISfJM("fFQGiL*56J(f"D9Q$RB1#NSK`BQb#Ni1 (RAPPER@"LjD&Ki4BD)H&MiU-JR"UD)Z4KSZ!JAaNEBq6J)',H'0fLiQ$J*D)9@k 3!)KdJ*U#EQGqQAGYP*jZA*+3!'&ePjP[CiQ(H'Z(QhKTJj4kBi5LJPKpURP*KV* eA)1FKf"[NjG`DTL0D@ppN!#'DhqAIef&S@jUP)aQG*1+FAL'HRTkJT5*Fh#'IPq #Uj*ZD(ppDhDKVh49I)9LH+5@KAPDF)jcGkfMB'U%D@b,Pj+%EA4iDS'INR*jJQT hJSQIJ@"VMS4QMD1'C@D'K(k-KRjlGQppN!#&Ji*kFAb"KC*jHhjUFSfBISL-APU !PSb2PAaT@&k-T*q1Jh459B'SSiQ$G'*5EE'QFS18CNeqRj!!Ji*rG@CYN!#BK)1 *F&plPSapIB9lBRUHNA*eJ(&lLjUDBe*rMhH&UT&R@QL0Nhb5Uh*)GBYcK+H2Fh0 VE(q8PBf+FPKRMiq(RC0K@R0pMD#4Ii"KA)51NTk%BACl@SZlKQf#FQ+!MSUPLP9 MJAU$TTf"F'"GFCLSQiK`CeCRM*keP@YPDQ"TTkZ,JA*ZF'CdVUCPH*jZ8AZ-LCU "E)b%@'kJM(L*KA4hGh@1KhL,K@phKAGrPi9eJRe[H(q'PB9bH(YqIS"qMBpUG)D #HhL#LiTeI)abEBQ'I*!!KA"qH'f)PRGkPAKbJRKmKB#+QA&DLi9HK+Q5GfpZIRp ZMkTqCReiDi#*M*0mGS"YDj!!PRD,MQ*aI(D2QAaePA*4LjQ$Ji'"G@YYN!#DH)D +Dff&JRf2NAKUHSCfGT51F)+*D(H2HhfCI@@+If5)PAL%L'YqL'plRRYTPhTQM)Y bHj9jG)edHiaiGiL*FhZ-HR1#MAjcKBPcHC!!IAH%JhKkL(f#Jh9rIRq#JS#%L@a aMS4fL**`G)*`GC5DH(b(E'0mP)U-MhCQE(arLU#6H'KZGh5'R+#!A@YrHAHAT)a YBA##K(kES'jMHh4VM+10KS"MD(KjMUk2EhaQ9(UNQj',G@pHB*'QMS@+FPYbIS@ ENi*iGfpYJj'4JRZ'G@TmL)b(IAH(K@YlNi4kIAU#LRYfM)4XJ)YqKSaiGRpiI)Z +Ii9jDB1,HBD@KfTbJh@'MS+(JACPICD%LB&rJfpVIjk(FSZ#GRGhJ)q0GB#2H@P kLiTqHj!!L@PaKS5!LS9jKhP[JB5'KhemLRaSJC0kJT!!Fh@*G@f5QhPcKRjdGi1 @L(9hJ)"iHSZAJQelM(YdJ)Q2Hff&MA*ePS9cL)*dJ)GiJBT[IT*fGCQ*AS#6FhL 8NAKdER13!)9rPC!!EQ'$JRq2L)TrE@GpPAQ%S)"PFB4pIj@*J)0XD)@5J)#3!)" XG(k'N!#"I)PiDAf4IhZ8Iff#I(5$N!#+J)&aGS4jJC!!LhTaHB#$Ii'5J@jkIi5 #IB'$Ih9rKAf)IhL-K'jjM(eiMS&lKh4`M)ChM*!!Fh#"HAU*LBq&E(Z!ERUBNAU 'H@CjIS5CNAjpFQ4kMBQ8NR"eGPb&VSCbQiK)DC')NSf!J(CGFCf2KC*kDRGeGC5 EI(KqEfk-MSU3!)"VCS+*ISq9IQGXHi15NSH+GeTVLBZ5PB&dGfeNNU#)KhafG(9 [LUPmDBU(E@q1MB5%GAk'I(D#N!"rG(Z#KBH!Hi0rGRQ(MSL!FhL(H(H2N!"rGi" jGSH%KBjrGRGmIhZ-NSKjEAYqJBD+PiCTChq'GifILA*YGh@$N!#2NReUF(jmJCL -HS0lE(L-L)Q(GB5)BfLLR@CrRhPRGS+'Li1!P(GEJSpiIjL4Hh4[G)*rKTZ2H(9 bEAH4QBZ&JhGNDiL2LiU%JhjXDiQ2JSb2HA&iEhb8MB@+J@abIRq0NS&lIh4`JSk &JSZ%GR0qJAk,M)9lDRU&JB#+PRGcIAf+Gh++PB4aKAjXH)D6MS4mH@jUKj!!Mib #HA*`DBkLJiL*F&pbMSQ2MiL&@eZ1Q(q)SB"MDQf0R)'!N!"k@ALBJAq*K(YeJ)5 *IA5'J(H'LhplK(jbHSb,JRjmJhTZHiZ8J(f*G("mKi@%MhCaKRTjMiYjI)"cJT* hI*9fBAq2KSZ-G(KrCAbIM(b(IQ&kMhk)N!#"GhPhH)b+J)4jHB&pJSZ*HA*jJS1 "NSpcD(Q"J*+1Ki4NAB1BKikJF9P[H)'AUC&aC@"dKiqKSB"G@hD!JCfVMQGMEfe pPk1FGfK`D@b4VSelK@jFH*+5Mi4hGh9aKD'*EAZ$H(+,S)K[FS"hG*19L(jbGhG hKTL0H(pkES5+I)f,F(1,JhQ@K'KqIA5-RBChJh"LIj!!PT@%HR0QC)UPN!#)Nh4 9CiH5NC@+J(&AF*DCLBQ3!(0GFBL2MBk,GfKbJiL(N!#3!(9YGhZ$LC1)HhYYGi@ *LBD,HA&kIBU'JiH%HR"mK)D'J)@'GA#)LR9rPi9VHiKqG(b8NAYdJ)4`HBq2MAa kI@j[KjU)JT&qAQU,Mi@-Pi"ICB#,K)kDJfeXH)+$Mj!!KRTXGS1!JC59EQU*J@k &Ri4`HhpkH)@6Lh4hKhP`Lj0qI)4mHATmLSemHBZ!ChL5LRQ%PAeLGSq!HT16GQp jGhk)M*5*Eh1!Fh+1R)ejFhYlD(LNS(TcJ(&PIj56LRpfFA4jKjQ4HR*pG@f'Qj! !GhPhERQ&Pj@$GQpaEi1CQ)TiEQaeISUMPA9[G'j`Njf)JAP`Ehb)NC'"G(4fHSL 6M(efGh*mN!#8M(ebEA*qM*k4HRKXBRUIPBH2HQ&QH)QJQhTlH&jVNTf2LhpXE'P pS*U#J)"KCSL1N!#9L@eTH(Z(NC!!Lh9XFi5*Jif,I'YbL)Q(L)*rFferNSq#L(a SGiD!LjU&Eh&eHSQ,LC*rCR'&Ji@5MAacF(D(LBQ3!)CcEAQ$K)f0L(j[F(Q)LS@ 4LhCTGSKrIiq8KA"cIhakJC'6JAGjHh4eMTL+K(pfCff)NT'1MRYHDB@+LCLFHQ& SGS+1NjH2EejYKBD(STTfBfTiGibHNi4eE@PfMjD3!)@"H'4VMCD'K)GpF(*qMjG qGiPrDADBLhD(JA0fKSb#KS+!HR#%M)"kKSTdGiQ'IhaqKi9fI*'(ERL-I(D,Li' !JAKcIi5)Li5#HR&cIiU&Lj*rF(0mIRq+Mj&rCR5$GhQAQhjiHQjfJSD6NRjbGh0 cLj'0N!"mDR0mHiLCMRjjD@b$Lif5LRP[ERD&NC'+HfpiGR54QSChHRTZH)bANA9 dIA0eKC@8Jh&VIi"eMTf(FA*fFi13!*!!LAjfE(1*MiH*LR&NHBU-MSTmGQpYJjH @KhYbEA0mN!#EM)"hD'@#PSZ4Q(CDE(k"NCk0HR&MESk3!)b6LQjNGRb*PBZ&I'j XIiZ,NSPbFRPaICQ6I(jpEA+'Lif4IA&jH(+$QBYlJhaZGiH0L)@!HRKcIiZ(Ji* qHAerIib,Hhb"HRH&Khq&KAajJB+!Ji5"Ii+!HAq(IhL"LS*qJi*rHAU$L)5"KAp fHAq$KSD)KAYfI)"jKC!!LRjhHATlJ)U8Kh9iHhjrKBb'IAGpIRk)K(q&K(TmK(a pMBKlIRpfHS@&LBeqGRYlHB@1LB@"H(*dHiZ9LB+'GfCbL)Z2PB&cG@a[LjU0L)T `CAL!Kj'6KR9dF(@$M*H+I(PeGhU)N!#,JhCdGRq+KBU*Gh*qJRf3!**dGS0cGC+ 5IiD"DRD&JT!!P(YdI'paLBq8P(GRH(aaLk'1JhPQChk)LCZ@I'YUG(b-PC5&Fh& ZG)@1P)arFh&iHBQ3!)U'H(4iI(f)Ni4hIAekIS5+L(adIB4qIiD$JAjmIi+!IB+ #IS+#IRjrJ(epKB9pIB@$FhZ0KRf!KAjfH(b+MhapKApcH)H'LBKlHAPfHB+0NBT lEhPiGBbAM(pkF@PfK)qEMRGfH'YUNU1)IBGeA(#,MC59JRC`ChD4NBL3!)"QEAQ !P*D%KATFFCL'I*k1A'L#Hi5BNi4lCfH&LS@8PhYKD(f&L)qDLfYPFRq)NC1'H(0 [F)+BNS#"HfpdJ)D2NRYcIhKbL*H%IB*iG(U)LBD,I(9fIS9qLSU%I'jmKS5!K*! !IR*hIS9rJSk)Gh@"J(U%MSGqHhYiHB@*KSQ$HhGdHBL6Ji+2H'*eLB@+NiPkG'Y fMSL*NiG`DhKjKT1,LS"bF(5&Lj!!LAPpGR*lLTD(IApfGAf&Lif'FhQ#FAbAMAZ #JA"iKi#*NhjbH(f!JB'+NRjYIBClIi1'LS"bH)U#Fi15KhGkKhehJ)+(LB4eHiG hGiU-L)4kFRf"H)H8L(piFRKrJiZ9KR4jGA#$Mif1L(0THhpmMjH*HA*YFSH2LBk -G@C[JBZ-N!#0HQeXH)'-QBq#FQPaHSH4PieiEfGcKBU6QBKXEA4`K*H8MS4[ChC lJjU8JRpaBh@,LSq9JA&bERH0P)k'HA"bGB#4N!#(JAKYGB+%MieqI(CdH)10LiG hHB&cI)f*JB"lFhq)IB1)IRYpIAk(LApkJ)"hHiU+IRf!HRZ!JBU+IAPpHhL%KB1 *IhKrI(Q(LRZ#MAKbJS*lJiPrJS4fHB+!JBD*I(U"H(H"LSU!JRahI(Z$LiQ$I(K bHSD$LBk"HAKdHBZ2JS1'FfjqJS12MRYfIRCdLC1)J(afG(TpLTQ(FhTpGRQ,MSb &F(9rHAf-P)&qIR"jJSH+Ki*iI(KeKik&IB5"F(Q-Khb&KRPiIAq&LRYkMS&bISL $J)1!Ji*eISPmI)f)H(q&HAb'IB'1JR9pKRKjL)D+KRPiJ)"hK)k%JRjiHS##JBZ 'IAepHhk%K)1$IhalIi@%IS+'I(KpKSYrHB+%GRH*Ki1)IAD#IAD'N!##IBGjF)# #KBb'JRekGAQ(L)Z&HRekHAf$MSb#HhGiHS@'JSf'F(5"Ii5-Ji#'G@b%M(f'MAa iHRU"Li9qKhjcHS''L)9rHhjkHS'*MRjjI(b!IB'+MAeZJS4cJiZ$JB0iGSClHj' 'GS'$GAQ'JS1)Ihf"HAQ)JAb(L(afIhpqKB'%KRjiH)+%IS@%I(arIRZ'LhprIAP rJB+#Ki"hIRYqLBD!JS*cGSL#JBQ'HA4kISQ*J)@'G@YrM)H&KB&jG(1!NBL$L(e ZF)D(JSb+Ih*bIi'&LBL$GRGrIRq%M)9fHhppJB##Ki&hH)L$HSQ'GhL!JB#'KS' !H(9rKiL'JAprH(9pLiZ!IB&rGRL)L)+#JhjiHRk(KRU%LhPeJiQ!I(q!K(jlKS0 iHiL%H)5+I(GrL(pqKB+"IRepJB&pKiKlHS'"I)'&KS9kH(q!I)5+J)D$FRD'KAb )MAejH(H!KSH*LAjcH(prKBb*Ih9hI(k(LiU"HhPiI)12LhakI(KiKBU,LhYdHha mLj5"IAp`ES+5LiL'HA9dI)H-LB*rG(0qK)H)KS0mGR@$LS+$L(e`HBD&J)H*I(0 lKS5%KAYqIhCpM)TqJ(edISU#JSb!FhKqJ)D+KB0pFAU'JS5-KhTeH(b%Ki@*JRG iIAaqMiekH)5"F(Z2L(f!JAYmIRZ+MATmKhaYJT'#I)1%HR0jL)f!JBPmFRQ"JBH ,JAjlFRH&LS5*M(GXHS&pKT1'HAacFS@0KSb-G@efHS+1M)D%G@YhJiQ0M)*pFfY lLBD*Mi&`G(arJSU1KhGbHRerK)@-KA&bL)KdK*&rG(Q!J)+"JiTmFAk'Ji#)KRY eGS1(Ji1)J(CfI)1$L)H#I(GmIi+$JiH!GhTrJS'&Jhq"HAL#LAppK(pjI)1!KBK pHhprI)''JS+#H(Q!K)#!KS9rG(Q*KAU$LheeIAq!L)0mKB0cGiZ'I)@$GhL#JS+ &JApqHhq%K)+"IRZ!IRq'KhpjIherKS5"JB0kGB''Ji+&IhCpIhb)MS*kJAPcJSQ #KiYiFRjqIib0K)"iF(Q%KBf1I(KjF(b5Li1+JQPaKB1'MiPlHA4dJiU+LB4lFh9 qKiQ*Li"bFRf$JiU-K(9bIRq"LSq&H(CeIB1%LBk&FRGpHi'+Mi9kGRKlHSH5LRp hHATlIiL3!)4mH(GlIiH)M)9lH(0kKSQ(KS*eGRamL*!!KhepHA4qJiH-JhTlI(P rLSQ(J(GpI(H#MiTlIhefHRf+NS0jI(jcHSU,LAaiJ(jeIT+(HhppHhYpJif&GS+ $F(L,LAf"K(ekGhk,L(YrLAedHS@(JAq#JhTfKBGmIiD#H(b(JRPqK)0pIB#"Jhe pL)&eIBKrGBD*HAU&K(epIS#(IRU%K(PlJhq$KRerJhTfK)0pL)ChHS0iHif(Hi# #GhH#K)L&I(emHAL#M)Q#HhajGS#,LB1$Hh9eHSQ-L)@"H@ekJS+1Li*lGR"hMBD %Mi9aF(epJib*K(jiFRQ$Kik(IhTeH(k$KSZ)GR*mJB+&LB9qHA9iK)Q%JS9qG(C qKBZ-KAKfGAU$L)f'IAGeI)+,L)'"IAKiJiD%JReqIReqKSGqJ(jpJ(b"Ki4mHB& pJ)H"Ji4jGS5%IiD'GhU&HS'+JB#$HR@)LAQ%KhemIAf$LAepKhejJBH"J)&rJRY pL)GqHRprIAk&MS*jIhYhJSb$KS9bH)*iIjL0G(jrF(U*KiZ,H(*pHRZ1MB##Hh0 mIB'1MRTdJRPfKBb,J(PhHi"qK)b*Hh*mJhU!NSPiHRajIiL'K)CkHB"kIiU&IS' #HRf!ISL(HB#(HRH%JRL#LB'!JRjmI(U$MB4pIRahH)#(MBPqHh9fIiD)LiPjEh9 pJSU-L(pdFhZ"Kib+Ih4cH)1'Kik(FQjpJi+(MB9eFRL!K)D,K(aeG(q'K)H*IR* hIRq'LB5!HR4qK(k(M(jdIApjKBL"JRYfJSClIif"Fhk#J)&rHi+%HAk+K(YmIRb "KB1$J(TiHi''Ki@"HRKlIi5(KApqH(H"KB@$JRjjI(f$Li*mIRaeIif%JB9kFAf %J)Z-IRChH(b*LS@)Hh*fI)+)Li0rHh*mKS'$M)0cH)#!JS1$JAakI)''L)"kIRj lJiH!J)0jGi@'J)5"HRarJS1$J)&mFhk+Ki+#IAClHhq2MhpiHAGhK)f+KS&fEAD 'LiZ,KA9YGS'*MBQ&Hfj[J)Z*MBPlG(&fKC!!LS@%FQapKS1,Ni&dG(L#KBH*L(T ZIB&pL)k)HACmJB&lKT!!JA&eJS5!KBf%GR9rJi++KRKeHS5(K)5%I("kLSZ'K(j cG(Z'MiH!JAYaGSL1LS4lHRCbISq3!)9rGR4jIiQ3!)YpG(0fK)L(Mi9`E(b'KBU +KAaXEi11LSD&IR4`HSb0KB5!Fh5"KSQ&JB"jGhf(KS'#HhTrJ)5&JheqI(5#Mi* mJAjlHhq)M)&iIAjiJ)Q)JATiI(pmKT'#FhL"Hhf+L)0pGAD!KS1)L(efH(f"KiL %IRGfHi+&L)PqGhTlISH0J(TqG(@%LSH&J(CfIhk$MBGkH(TiIB@'LB0hGRb"JS@ &IhjjH)+)JRb!IRPrKi5!JRjjHi#'Ki&kIAphHiQ,Ji"pH(TmJBQ*IRarG(D*MB0 qJhYeHB+1L(YlJATbKBf%J(pmH(jqJiZ"HReqH(b,KS#!IhTjJB1'K(ppH(b$KS+ !KAadISH%Ii1"H(YqJSQ%HRk"HAH*MRpmIhjjGi@-K(f"JA9hKSL$K)&lHhTqLSK qIS*jGB1+KAq!J(GhK)Z&JB*lGRU!KSQ'IhYkHAk&L)KqI(eiHS1+K)5"FhQ%Ii' 0LhGdI(k$KBD)J(4fJB+&LiClH(TkJSH(LB"eGS1&I)H,IRGkJ)'%K(q"J(Z"K(e rKRpkJS4pIi5"J(jpJB*rJSL"GAZ"Ii+(Ki&mGAQ(KS'&KRKbIS+#L)4qJ(aeISb (Ii+!HATmJSb*IAYrHhZ%KSL(HR4mJ(k'MS*kI(KiKBq'J)&iFRb&L)Q$I(YlGhf 1M(ppI(akHS1-LATjJRekJ)D'JRelJRpiJBU"HAk$IRf"K)9rGhZ'K(q"K(eiI)' 'K)'"HAQ"Ji'#KRjfHhq%KS*qIhpfHBQ+J(b!IRCjKBU%IRjmH(b"KBU'IAPjHhf &LB+#Ih9fJ)U$JBCpGAL#KB+'JRYkHAq'KRprK(TfIiH'JRjqIhGpKi4rJi0cHBQ !I)D(HhTqHi1'IS#$IAQ"KB'"J(amIRq&K(q!IhTlK)5"KB4lGAf%Ii#(KRYhIRq #JS+'JAGjKB*pK)9mH(jrKSGmJB4iGi5(IS5%H(k"IAq&KRppI(q$I(k)JRPmJS# #KB'!IRKpKSD"K)&iGRk'KB5'JRGeIi+"LSPqGhTlIBD(KB0lHAZ"JS1(K(jfHi@ "Ii5'J(PpIS5'IRq%JAYmJiD"I)#'IAL*LAPmJhppIi5+Kh0bL)0iKC+%F(@#Jhk $Mi9cGB'"IS@*KRadIB0qIiZ,HA4pJRalMT*lEhk%G(f5M)"hGRarIB+8Lh*hJ(Y kKSb(IhClJRZ!MB9kIi&jIi4rJi*mJ)9mHSH$Hhq&KAemJB&kHBQ,IRerIRPmK)U -I(CqI(KrMBf"HhGlIAq)LSL!GR4jJi@&LBClFhD!KiH(KAeeGAZ%LBU'IhGcHi' &LSZ"GRCkI)'(MBKkGAerGi'4LAakI(eiHB@2KhPqJhPdISZ*Ii#%I("iLBD#Ki9 jFhQ!K)H(KAecGAk%K)H,K(0ZIS9qK*!!LA4aHRf"KSZ,IR*cIB1"KiZ'H'plK(q "LiPlH(PlJ)D'JS5"HACmK)5$Ji&qHAPqKBH#Ii&qGRQ&Ki#!K(piHRq%KS*qJAp kHS#'JhpqJS"iIS1$JRk!J(pjHiL&IB#&JRKhJ)H$IB+%I(KmJSD%J)&rHRTrJS5 &JAf!IRYrJi5$Ihk!JATkKSD!IS+$HRU!KS4qK)&jI(q#JS@$IRpkHi'%KB1"IRa mIB+'KS0kHB#!Hi51KAGiIAerKBQ)J(GiHhq(LSL#Hh9iJB1*LS&pHhPkK)Q$JS* mHAZ$KS1$K(jfHi1#JiD#IRYjIiD&J)5%H(L#KB&rKB4mHAq%Ihk%K)&qIAprIS# %KB&rIhTkJ)5'Ji5#HRClK)5'LS&jHRKjK)b,K(jeG(b!LC!!LRjdFhCrLBf2JhC cFRL(Nif$J(9VGB12NiCpH(*bI)b2LS"hHRKiKBZ'JB"kGhk"JSD$J(plHi##J)' $Ihk!IRprIS+%JAk#JAPlJ)+%KB5!HhKlJ)1(LS0iGhKlJ)H-LApdGRemJBZ-JRK hHAb!KBf'GhPqHhb(Li&kHRZ!JB'(KAaeIS4rJ)5$IAKmJS1#Ji*mHAk#J)'$JRa iIS1&JAq#JATfJSZ$IS"pHATqJiU(I(YpHAf&Ki9rI(TmJ)''KRjmIAjpJB@#JAa jJ)&qJSD"HRf!I)#%JS"pIRprIi'(JAKmJB&pJSL#HhKqK)'"KB4jGAk%JS1'K(Y eHS5'JS1)I(0mJS+&KS&mHhPrKi+$KRYfIB+#JSD%J(KeKBKqK)L!GRTqIiH%JB5 !HAYrJ)5(JAprHhjrIS5'IRf$J(b#JRq#JS+!I(arIRf'L)#!IRTqJS#(LAekIhT fKSb%Ji"kHAKqLif"IS*eFB'*L)L$IAYfGSD3!)1"KATbGi5+L)1!J(GfJiQ'JS* qGhQ"LB5!JhpiHS1(K)#!JRefIBQ&IB'#IRYmJSD#IS+$Hhf%JAq!JB'!J)'%IhP rKB*rJB0qHRb"K)+$K(jjHi'#JS5%JAPjIi+!JSL'I(ClJS'!LBTpGRKqK)1%L)* hGi#$JSD$IRajI)5'Ji*rHRZ"JB+)JRTkIAq"Ji1&JAGjJi+!K)@!HhYlIi5$JB& qI(b!Ji5#IAamIS'$KB*mHRk!J)1(JhKhIS1!J)L'I(9jJB1&K)@#GR4pKSD%KRp hGhf"K)Q'I(KiI)'%KiGqH(KpJB@&Ji0mGAb&JS#&JRPjIi+$Ji+"IAKmK)@#Ihk !IRPrLS9lIB"lIB1$K)0mHAf!JS@$IhjlHi#$K)9qHRepIB+)JheqI(f"JSD%IRT mIAk&KB+#I(KpJB1)KRakI(KpLBU$IATjIB#%LiGjH(apJ)@(KAphH)#$K)H$Iha iHi1&KB@"HRPqJ)1&JS4qGRZ#Ji5&JRemHRf(KB'$IRPlJB1&KAprIAQ"KS+!JRp lIS#$KS"pJApkJ)H#IhpqJ(jqKSL"I(jpIB1%KB9pHAjrIBH+JAprHAQ"KB@&IRe qGhk*Ki'#J(PmIS'*KRaqJ(KmLBL#J(emIAQ!MSCmIhpjI)'"KiPrHhjmIB+"K)U !H(aqIS'$K)@!HAq$I(q'JRprIS#!I(k%JAq&JRaqIRf#K)+#IhTmIRk%LS*pIha lIS+)KRakJ(jjJBL'JAalIRjmK)H"IhemI)#%Ji'!J(jlIS5$Ii'#I(U!Ji+"JB0 mHS#"JS1#IhaqI(q&JS'"IAU!Jhq!Ji"lHi+&Ihk$J(GmKS0rJB*mH)#&JAk"JRj lI)'%JRq"K(ahIi0rJ)H$H(b#IRk&KhplHhk"Ii#%JRemJ(prJS+"IherJAepKB4 lIi9rHRq$Ii##J)#"I(b#JAb%KhelIhjpJB5%JhekIhjmJSD$JAjjI)*qJ)L$HAZ !IAk%K)*rI(aqJB'$Ji"mI)#!J)5&IhapIAk!JiD#I(b!IRZ&Ki'!IRaqIRq%LAp jJB"mIi1%JhpjIS4pIiD#IAjqIS'!Ii4rHi#$JAq"J)"rHS''J(f"JRjpJ)5$J(q !IRf"Ji'%JRjqIAq"K)1#JAYlIRq$KB5$IAPqJS+#KB0pI(apJS5$K)&mIAppJBH %Ii"pHRq"JS@$IRjrHRk(K)#"J(emIAq'KRjrJRjlIi+#JS+!J(emJB1#JB1$IAa mJ)1$JB#$IhPqKB*rJi0pIApqJB5"J)*pHS+%IRq%JAjqIS1$IAq$IhZ"K(q"JAf "J(aqKS0kJB*mIS+%J)#!IRppJ)1$J(aqIhjqJSH#I(k!IRb"KS0rIRemIi+$Ji* qIAepIiD'IRb!IAPrLBD!IhplH(k%Ki9rIRajHS#)L)0pIAehI)@'K)1!GhPrIS1 (K)&pHRTrJS+%JRjpHRf#JS'%JhTlJhjmJS@"IRapJhplJiL"HAk$IRYrKi4lIS0 rHAb%K(pqJB*mHS#'JAf#JRajJ)4rIi5$IAZ!J)##JB'!Hhb!J(q#K(emIi#!Ii1 &IhGpK(pqJi4rIAjpJS0qK)0mHhq#I)#&K)&lJ)*qIS'#IhprIi+!Ii#!J(q%Jhb !JRalJB@#Ii'#HhU"K)@"J)"pHAU'LB&pIi&kHB+*L(YlJRYfJ)Z(JAjjIApjJC! !L(ClJRPiKBQ(K(YiIhekKSb$IAjpHRf#KSH!I)"rHhq)KAerJAjpJ)5"J(jqJS" pJiKmGS1%Hhq'KRjlI)'%Hi'+JhGkKB"lIiD)I(Q!K(jjKBGrIRk#IheqJiCmIS1 !IAf$JS#!J)0pHS'$J(q%JheqIAq$JB'%JRTlJi&pK)D"HhTrJS"qKSCkH)##IRq (KAjiHi1"IS1+JR0kJi"lK)b!HRTrJRerL)YkFS1#H(f(LAelIB'!Gi+,JRKpKRe kIi5'IRb"JhpjJB0rIi'%Hhb"IRk!K)&pIhf!J(f$KRjiIS0qIS+%KAYfJBClI)Q &HRTmIi0rISL'G(H&JAb!Ki4mGRb(J(U'KhahIB#"Jhb"KAPjJS0mJSClIB"qJ)# #JB"lHiD!IS+"IhYqIi1$Hi'#HhU#L(pqJ(jmHB'%JS*qIReqIB++IhZ!IATrK)+ $JAPmJ(b"Ki0qJ(YjJi*rKS4iH)"pISL'IhplGhk%JS@(IRKkI(k%L)1!IRPlIS' %KS0kIApjISH(Ii##HharJBD$I(b%IRH&L(jmJB"pJRf"L(YjK)4jISGqIS'!J)& rIB*qHi@$IRq#IhU!JB1%IS'$HRH#LAjrKS&kHRq%Ji*rK)&hHi1'JRq$J(elIiL #IS+!HhU%JS#'JAYpJ(arLS0pJhpjISD!J)GpHRpqIi1%Ii+"HAq#IB+'IhZ$IAL 'KRf"KRaiK(jpKi0pIi0lI)@!JS@!IAk"IB##Ii@"Hi#%IAU%K(k!J(q!Ihf!KAp mJi*pI)1$IAk#JhpmJ)'!Ihk$JRjrJ)"pJB+!JAjrJAjrJS*mJ)9mIS5!IB##Ii* qHSD$HAq'J(Q!J)#%IAk&J(GrKherKApqIhemKB0mK)&mIS"pIiQ"HS+!Hhb"K)+ #HRb%IAU#LRpiJB"pIi#$K(jiJ)CkI)H$I(eqIB1!HS@'H(Z&J(f%J(Z#IhQ"KRj qJhamJRjrKB*lIRppJS&rKB0jHi1"I)1$J(jlIS+$J)#%J(alIi5!Ii'"IRb!J)+ #IS#!IRjrJS*rI)'$I(k&J(b!Ihf$Jhf#JRPmK(prKB*mIRamK)+!KS0hHi0mISL 'IRjqHAq#IiD)IAKrJ(Z!L)@!IAamIi##Ki0mIS"pI)5%IB+"I(q"IS#&IRZ&J(Q "KRjpK(pqJRk!Ji&mJS4lIi*rJ)&rIi9rHS5#I)'&J(k%IAZ$JAk$KRjmJRpqJS+ #JRppIi&rJi*qJB&mIB5$Ii+!IB#!Hi+*IhU$JRYmK)@"Ihk$IhKrKi4mIi*qIRf !L)0lIi4pGi1'IS'%J(arIi#&JRk$J(YpJi&rJi*rIRerJi&rKB0kHi1"IB1&J(p pIB+$IS#)J(GqK)"mJiD!IRZ!JhppJSGpH)+%Ihk"JRpqIS'&IRk%J(PrKB'!Jhp qJ(arKB&qJi&jIB0qJ)@!IS&mI)1"IS5%HRb#JB'"J)'"HAZ'JRb#JReqIRk%KRa mKAjhJ)@#J)"rIhplJB9rIB#!IRq"JS*qI)'#I(k&JRPqJhemKS4lJB*lI)+#JB4 mHi5!HB'*JAPrJB"rI)@)HRL$JhQ!LB&pIRYqJRprLB9hI)0pHS5(J(jqIAapJi@ $IRjrIAerK)0rIhk!IAb$Ji&pJ)4jI)5#Ii#$IhprHi#$J(q#JRYqJ(k"JB+#Ihp qIhjrK)'"JAjpJ)"qJS0rIS"qI)1$J)+!IReqIi#&JAq!I(q!J)+&JhYpJReqK)5 !J(plJ)*qJBH"HRk!I)#%JS1"I(f"Ihf'K(arJ(YqJi+!KB"lJB"pJS9rIi0mHS+ #Ii5%IS&rH(q'JAk&KRTmJ(q%JB#$JRajJi0qJi5"IhjmJ)5!J)5!I(f"IS+%J)' !IRerJi'$JAf"J(apK)CqIi&rIAf"Ji0rJ)*qI(q#Ji#"J)+!HAk&JRq"K(jpJ(k "Ji'"JB"pIi"rJi0rJ)"qIS+"JB*rI)'"I(q(JAb!JAprJB#$JhTpJi"mJBCrIB" rIi#!JS0rHi+"Hi'$J(q"IRf%Ihf'JRTqJhelKS*pJS"mIi*rJB4qIS*qIB'#IS' !I)+"I)#&J(U"JAarJB'"IharJhprK)*pIApqJB'!JhjlIi&rIiD$HRk!Ihq!Ji& rI(f$Ihk$K(jlJB&qIi+$IRarJS"qJi4qI(q#Ii#$J(pmHi#$J)#'JAPrJheqK)* qIAerJS"rKB0kHi&rJ)1!J)"pHi'%Ii'$IAarIRk$KAjqJ(emIi+"JS"mIS"qIi5 %Ii"qI)#"Ii#%JAZ"Ihf#JB#"JAepJhjpJS'!JB"qJ)"mJB1!J)+!I)#"Ii+"J)# !IAf$JAq"JAppIi##JRq"J(jpJ)1"JB"rJ(erJi5!IS0rHB#%JAq#JRjqIB#'JAf #JRamJi+"JAk!JAeqKi*lJi4kI)@#Ii+"IS"qIB5%IB#%IhZ!K)'!Ii'#IRf#K(p qJS&qJB1!Ii"qIi#"JB+#I(f#Ihq%JhaqJRerK)*rJAplJS4rJS*rIRprJB4rIi0 qIB'$J(q"Ihq"IS'%JAarK(ppJi4rIAprIi##KS&pIB"qI)5)JRepJ(jpJ)D(IAU "IhZ!Ki1!IheqIRq#KB"pJAjkJB5#IRk"IhemJiCpIB1"Hhk%JB#"IhprIAq%JRk !JRepJS&rJ(pqIi#"JS&qIRppIi5$IRprHhb#Ji1$J(apIAb&KhjrJRYjJ)1"Ji* mIApmJ)5$J)"qHRq#J)+#IhalIS'%JS#$IRPpJi1!JS&pI(aqJi@!Ii&pHRf$JS+ $IhjpIB##K)'!IhjqIB'&JAk!JAapJS#"JB"qIS"qIi+!J)#!J(prIRq"J)'!J)" pI)#$Ihq%JhYkJB"rJS+#J(elIi4qIi@"I(f!Ii#$J)'!HRk#Ii#%JRf!J(b#KB# !JRjmJS"qKB4mI)+!I)+%JS&pIB#"IAq&JRjpJ)'!Ihq%JAYrK)"lJ)0qJ)'!JB# !Ii+!IB1#IRk#JAb!Ji'!IS'$IRb!KAppJi*rIS#"JB"rJS"lJ)5"IB+$IAk!JS* rIS#"I(k&JhprJApqIi'%JAf!JApqJB1!JB"qJ(q!JB+#IB'#I(k#JAq!Jhq!JAk !JRprJi&qJB"rJAprJS*mIi4rIB'#IS##IS##IAk$JAf#JRarJhpqJS&qJB"rJhp mJS0pIB5!HS+"IS'!Ii'#I(k&IRf&JRarJReqJRq!JRjqJAppJi*pJ)*qI)#"J)* rJ)&qIB'$Ihq$IRerJ)#!JS#!Ihb"JAprJS&lIi&qIi##J(pqIS+!IS+"IAk"Ihk #J(q"IRk#J(Z"JhaqK(pmJB&pJ)&rJAppJ)*pIS1"IRpqJ)&qIS'#IAk#Ihk!JRj qJS"qJB&rIi&qIB+!Ii+#IRq#IAk#Ii#"IRq"IRb%K(Z!K(jmJB"qJRppJS&pIi0 rIB&rJB*rJ)&rIB#"I)+$IAf"JRerJS'!IRq!J(pqJi&pJ)+!IB'#Ii"qJ)*rIB+ %I(k%Ihb"JAk!JAq#JAb!JReqK)&qJi&mJ)"pJS*qJB4mHi+!IS+$Ihq!I)##IS' $J(k!J(f"JAq#JRjqJB"qJB'"JS"qIi+!IS+#Ihq!J(q"JB'#J)#"J(k!JS#!JAp rJ)"rJS+!JS"mIi&rIS1#IS"rIi#"JB##J(jrJ)#!JB'!Ihk"JRprJS&qJ)&qJB& rJ)'!IS+#IS+"IRq"JAq!J)##Ihk$J(jrJS'!JS#!J(jrJS"rJB*rIB#!IS'#J)' "IhprIi#$JAf"JRepJB*rJB&rJAjpJB*rIi*rIS&rIi+!IS'"Hhq$IRq#J(k!J(f !JRq"J(jrJ(prJS#!JReqJRpmJ)4rIS&rIRq!JB&rIS'!IRq"JRpqIi'"I)#$J(e rJhjpJS&rIB'"IS"rJB&qIi'!IAq$J(erJS"qJ)+#IAb#JReqJS*pIS#!J(q!JB" qIS&rIS#"J(q!J(prJ)&rIi'!IhprJ(prIi'"IhprJ)"rJ)+#IRk"Ihk!JB'!IRk !J(k!Ji&qIS#!IAk#K(jpJB"pIi+"J)"qJ(pqJ)+!Ii#!IRprJB*rJ)+!I)#$IRk #JRjqJ)#!Ihq#JAprJ)"qJ)#"JAk!JAprJB0rIi&rIRq!JB'"J(prIi#!JS+!IS" rIB##JB'!J(pqIi#$JB#!J(ppJ)+"JB'"Ihk!J)'!Ii+!IRq"J(q"JB"rJ)#"J(q #JRjrJS&rJ)'"J(pqJB&rJ)+!IS#"Ii#"JB"rIi#!Ii#"J)"rIi'!Ii##J(k"JAp rJB'!J(q!JAk!Ji"rJB&qIi'!JB&qJ)&rIS+$IRk"J(q!JB'"Ihk"JAq!JS'!Ihp rJ)#"JB&rIS#!J)##JB#!IRk"JAq!JhpqJ(q!JB#!J)*rIS#!Ihk!JB#!J)#!Ihp rJ)&rJ)'!IhjrJB&rIi'!IB#"Ii#"Ihk!Ihk"JRq!J(prJ)"rJB&qIS#!J(q"JRp qIi#!IS#"JApqJ(prJ(q!JB"pJ)*qIB'"IS#"IS#!IAq#J(f!JRpqJ(q!J(q!JAp qJ)"qJ)&qIi&rIRq"J(q!Ihq!Ihq!JAjqJi"pJ)'!IS#!Ii"qJ)*qIS'"IS#"IRq !Ii#"Ihq!IRk"JB#!JAprIhq"J(k"JAjqJB"rJB"rJ(jrJB"qJ)*rIS#!J)#!Ii# !IS##J)#"J(prJAjrJRprJB"qJ)&qIi*rIi*rIB'"IS##Ii##Ihq"Ihk#JRq!JRj rJAjrJS"rJB"pJ)&rJB&rIi#!J)#!J)*rIB'!Ii#"J(q"IRq"Ii##J(k!JAq!JB# #J(erJRppJS*rIi&rIi'!J)+"Ii#"IRq"J)#"JAprJ(q!JAq"JRprJB&pJ)0rJ)' !Ii#!Ii+#IAq"Ihq"JB#!Ihq"Ihq"JAq!JAprJAq!JRprJB"rJ)"rJ)#!JB&rJ)& pIi+!Ii'"IS#!Ii'"Ii#"Ihf!JAq!J)'!IS#!JB"rJB"rJ)#!Ii#!Ii#!J)#"J(k !J(q"JAq!JAjrJB"rJ)&rIhpqJB&qIi"rIS#"Ii'!IRprJ)#"JAprIRq!J)#!JB" rIRq"J(q"J(prIhq"JAprJ(prJB#!J(jqJ(prJB&rIhprJ)"rJ)"rIS#!IhprJ)" qIi&rJ)&rIS#"Ii#"IRprIRq"JAq!J(erJ)#"JB"rIhjrJB"rJB"qIS'!IS'"Ihk !J(q!J)#"J(jrJApqJB&qIi'!J)"qJ)"rJ)+!IS'!I)##J(q!J(prIS#$J(q"J(e pJ)'"J(q!IherJB'!J)"rIhq!JB"rJ(pqIi'"JB"rIRq!J)'"J(prIi#"JB#!J)" rJ)'!IhprIi"rJ)+!IRprIi'"J)'"IRf"JAq"JAprIhk!JS#!JS"pIi#!JB'!J)" rIi#!J)'!Ii#"J(q"JB#!J)#"J(q!JAq!J)#!J)#!J)"rJB&rJ(pqJ)#"JB#!Ii" rIi'"J)"rIhprJB'"J(prIhq!J)'!J(prJ)#!J)"rIi"rJ)+"IhprIhq"JB'!Ihq !Ii#"JB"rJ(prJB'!Ihq!J)#!JB&rIS"rIi#"J(prIRq!J)'"J(pqIS#"JB'!IRp rIS#"J)#!Ihq!J)#"J(jrIhk!JB#!JApqJ)#!J(q!J(prJ)&rIi#!J(q!JS"qIi# !J)#!J(pqJ)#!J)'!IRprIhq!JB"qIRprJ)#!J(prJ)#!J)'!IRq!J(q!JB"qIRq #JAq!J(jpJ)#!JB"rIhpqJ)'!J)&qIB#!Ii'"IhjqIS#"J)#!IhjrJ)'!J)#!Ihq !J)#!J)"rIi"rIi#!J(prJ)#!Ihq!J(prJ)"rIhprIi#"J(prIhprJ)'!J(jrJ)# !JB&rIi"rIi#!J)"rIi#!Ii#"Ii#"Ihk!J(q!J(q!J(q!JAprJ)"rIi#!J(prJ)" rJ)#!Ii#!Ii#"J(prJ)#!J)#!J(prJ)"rJ)'!IhprJ)#!JB&rIi#!J)#!J)"rIi# !J)#"J(q!Ii#"J)#"Ihk!J(q!JB#!J(q!JB'!J)"rIi"rJ)#!J)#!J)#!Ii#!J(q "JAprJ)#!J)#!JApqJ)"rJ)#"JB"qJ)"rJ)'!J(q!J)"rJ)&rIi'"Ihq!J(prJB' !Ihq!J(q"JB#!IhprIi#!JB#!J(prJ)'!Ii#!Ihk!JB"rJ)"rJ)#"JB"rIhprJ)# !J)"rIi#!JB"rIi"rIi#"J(prJ)"qJ)+!IRq!Ii#!J)#!IRq!IRq"JAprJ)"rIi' #Ihk!JAjrJB"rIi#!Ii#!J(prJ)"rIi#!J(jrJB"qJ)&rIRq!J(prJ)"qIi#!Ii' !Ihq!IhprJ)"rIRq!Ihq"JB"qIi#!Ii#"Ihk!Ihq!JB"rJ(q!J(k!JApqJ)'!J)# !IhprJ)&rIi&rIi#!Ihq!J(pqJ)#!Ihq!J(prJ)'!Ihq!Ii#!J)#!Ihq!Ihq!J)# !IhprJ(q!JB"rIhprJ)#!J)"rIRprJ)#"J(prIhprJ)'!IhprIhprJB'!Ihq!Ihq !J)#!J(q!J(q!J(q!J(prJ)#!J)#!J(prJ)"rIi#!J)"rIi"rJ)#!Ii"rIi#!J)" rIi"rIi#"Ihq!J)#!Ii#"Ihq!J(q!JAprJ)#!J)#"J(prJAprJB&rIhq!J(prJB& rIi#!Ii#!JB"qJ)'!Ii#!Ii#!J)"rJ)'!Ihq"J(q!J)"rIi#!Ii#!J(q!Ii#!J)# "Ihq!J(q!JB"rJ(prJB#!JB"rJ)"rJ)#!J)"qIi#!J)#!IhprIi#"J(q!J)"rIi' !J(q!J)#!Ii#!Ihq!J(q!Ihq!J)"rIi#!Ihq!J(prJ(prIi#!J)#!J(q!J)#!Ii# !Ihq!JAprJ)"rIi#!J)"rIi#!Ii#"IhprIi"rJ)#!IhprIhq!J)"rIi"rIi#"JAp rJ)"rIS#"IhjrJ(prJ)'!IRk"J(k!JApqIhq!J(q"JAjqIi"rIi+!IRprJ)"rJB+ !IRq!Ihq!JB"rIhprIhq!JAprJ)"qIi'!Ihq!J(prJ)#!IRq"J(jrJ)"rIi#!J(p rJ)"rJ)"rIi'!IS#"IhjrJ)#!J)#!IhjrJB"rJB"qIhq!J)#!J)"qIi'!Ii#"Ihk !J)#!Ihq!Ihk!JB#!IhprIi#!JB'!Ihq!Ii#"JB"rIhq!J)#"JApqIhprJB'!Ihp rIi#!JB&rIS#!IRq#JApqJ)"rIi#"J(jrJ)"rJB&rIS#!Ihq"J(prIi#"Ihq#JAj rJB"rJ)#!J(prJB"rJ)"rIi'!Ihq!J(q!JB'!Ihq!J(q!JS"rIi"rIi#!J)"rIi# !Ii#"Ihq!J(q!J)#!Ihq!J(q!JApqJ)#!J)#"J(prJ)"rJ)#!J(prJ)#!JB&rIhp rJB"rJ)"rIi#!Ii#!IhprIi'"Ihq"J(jrJB'!Ihq!Ihq!JB"rJ)"rIi#!J)"rJ(p rJ)'!IhprIhjrJB&rIi#!Ihq!JB"rIi&rIi#!Ii#!Ii"rIi#!Ihq"Ihq!J)"rIi# !J(q!J(prJ)#!J(prJ(prJ)"rJ(prIhq!J)"rJ(prIi"rJ)"rIi"rIi#!IhprIhq !Ii#!IRq!J(q!JB"rIhq!Ii#"J(jqJ)"rJ)'!IhjrJ(prJB&qIRq!J)#!JB"pIS# !J)#!J(pqIi'!J)'!IRq!Ii#!J)"rIRq"J(q!J(prIi#!J(q!J(prJ(q!J(prIhq !JB"rJ(prIhq!J)"rJ)"rJ)#!J)#!IhprIi#!J)"rIi#!Ii#!J)"rIi#!Ihq!J(q !Ii#!Ihq!Ihq!J(q!Ihq!J(q!JAprJ(q!J)#!JB"rJ)"rJ)#!J)#!J)"rJ)#!Ii# !J)"rJ)#!Ii#!J(q!Ii"rIi#!Ihq!J)#!J)"rIi#!J(q"JAprJ)"rJ)#!J(prJ)# !J)"rIi"rJ)#!J)"rIi"rIi#!IhprIi"rIi'!Ihq!J(q!J)#!Ii#!Ii#!J(prJ(p rJ(q!J(prJ(prJ)#!J(q!J(prJ)"rIi"rIhq!J)"rIi#!Ii"rJ)#!Ii"rIi#!Ii# !Ii#!Ihq!Ihq!J(q!J(q!Ihq!J(prJ(prJ)#!J(prJ)"rJ)"rJ)"rJ)#!J(prJ)" rIi#!J)"rJ)"rIi#!Ii#!Ihq!Ihq!Ihq!J(q!Ihq!J(q!Ihq!J(q!J(q!J(prJ(q !J)"rJ(prIi#!J)"rIhprJ)&rIhprIi#!J)"rIi#!Ii#"J(q!Ii#!Ii#!J(prIhq !Ihq!IhprJ(q!J)"rIhprIi#!J(prJ(prJ)"rIhprJ)"rJ)#!IhprJ)"rIi"rIi# !Ihq!IhprIi#!Ii#!J(q!J)"rIi#!Ii#!J(prIi#"J)#"J(jrJ(q!JB"rIhprJ(q !JB"rIi"rJ(q!J(prJ)"rIi'!Ii#!Ii#!J)#!Ii#!J)#!Ihq!Ii#!J)#!Ihq!JB# !J(prIhq!J(q!J(prJ)#!J(prJ)"rJ)"rJ)"rIi#!Ii#!Ihq!Ii#!J)"rIi#!J(p rJ)"rIi#"J(q!J(prIi#!J(q!J(prJ)#!Ii#!J(q!J)"rJ)"rIi"rIi#!Ii"rJ)# !Ii#!Ii#!J(prJ)"rIi#!Ihq!J(q!J)#!J)#!J(q!J)"rIi#!Ii#!J(q!J(q!J)" rIi#!Ii#!IhprIi#!Ihq!J(prJ)"rJ)"rJ)"rJ)"rIi#!Ihq!J)#!Ii"rIi#!J(q !Ii#!Ihq!J(q!J)"rJ(q!Ihq!J(q!J(q!J(q!J)"rJ(prIi"rJ)"rIhprJ)#!Ii" rIi#!Ii#!Ihq!Ihq!J)#!J(prJ)"rJ)"rJ(prJ(q!J(q!J(prJ)#!J(prJ(prIi# !Ihq!J)#!J)"rJ)"rJ)#!Ii"rIi"rIi"rJ)"rIi#!Ihq!J(prIi#!IhprJ(prIi# !Ihq!J(prIi"rJ(q!J(prJ(prJ(prJ(prIi#!J)#!Ii"rIi#!J(q!IhprJ)#!J)" rIi"rJ(q!J(q!Ihq!J)#!J)#!Ii#!J)#!IhprJ)#!J)"rJ)#!J)#!J(prJ)"rIi# !J(prJ)#!Ii#!IhprJ)"rIi"rIi#!J)#!J(prIi#!Ii#!IhprJ(q!J)"rIhq!J(q !Ii#!Ii"rJ)#!J(prJ)"rJ)#!Ii"rIi#!J)#!Ihq!J)#!Ii"rIi#!Ii#!Ii#!Ihq !J(q!J(prJ)"rJ)#!Ii#!Ihq!J)"rJ)"rIi#!J)"rIi#!Ii#!J(q!Ihq!J(prJ(q !J(q!J(q!J(q!J)#!J(prJ)"rJ)"rJ)"rIi#!J)"rIhq!Ii#!J)#!Ihq!Ihq!J(p rIhprJ)#!J(prJ(q!J)"rIi"rIi#!J)#!IhprIi#!J)#!IhprJ)#!Ii#!IhprJ(q !Ii"rIhprIi"rIi"rIi#!J(prJ)"rIhprJ)#!Ii#!Ii"rIi#!Ii#!Ihq!J(prJ(p rIi"rJ)"rJ(prJ)#!J(prJ)"rJ)#!Ii"rIhq!Ii#!J(prJ(q!J)"rIi#!J)"rJ)# !Ii#!Ihq!Ihq!Ii#!Ii#!Ihq!J(q!J(prJ)#!J)#!J(prJ)"rIi"rIi#!J)"rJ)# !Ii#!J(prJ)"rIi#!J)"rIi"rIi#!Ihq!Ihq!J)#!J(q!Ihq!J)#!J)"rJ)#!J)# !J)"rJ)#!J)"rIi#!Ii#!J)#!Ihq!J)#!J)"rIi"rJ)#!J(q!J(q!J)#!J)"rJ(q !J)"rJ)"rIi#!J(prJ)"rJ)#!Ii#!Ii#!J)#!Ihq!J(q!J)"rJ)"rJ)#!J)#!Ihq !J)#!J)#!Ii"rJ)#!J)#!Ii#!J)#!J(prJ)#!J)#!J)#!Ii#!J)#!J(q!Ii#!J)# !J)"rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J!!!!3!!!`U%!!-*K!!!!8%!di-8&i)!!!!F!,B!!(0 ZC#!!#`!+90m!!#!!!!!!di(S8%N!$#!!0d3!di(`4!-!&b!!HBJ!di(N*8S!)b! ![-`!di(J8L8!-#!"!hS!di(FGdN!Ib!"5,i!di(B,83!2b!"G3)!di(8+f3!FL! "R8B!di(38KX!5L!"dBS!di(-++X!9#!#!-i!di()2VF!Cb!#N[`!di(%C'd!E5! #ad!!di(!#e4[EfaPC#")Eh*Z#NeKCfPM)%KKFR!,6@&RD@-J4QaeG'8-6'9KG'K PFL"%FR9Y$NK[FQiJ6fBJ8'aPER4j#NCbEh0d)%K[FQi*4QPbC5")Eh*Z%N4bG@d J6fBJ4@&bG'KaG@&VC39#G@GXC34#C@aX$&G[Ef4PEL"'E(9dC3YAEfpNC@iJ5'& bF"31: nethack-3.6.0/sys/mac/News0000664000076400007660000000054012536476415014366 0ustar paxedpaxedWelcome to NetHack 3.6 for MacOS 7.0 - 9.x Unfortunately, the 68k version is no longer supported. This game is brought to you by Dean Luick, Kevin Hugo, and Mark Modrall. Bug reports, suggestions, comments, etc., should be e-mailed to the Internet address nethack-bugs@nethack.org, or fill out our comment form on the web at http://www.nethack.org. nethack-3.6.0/sys/mac/README0000664000076400007660000000261412467321052014400 0ustar paxedpaxedJan 2002 The MPW compilers are now supported again. Support for 68k has been discontinued due to a lack of a debugging system for 68k binaries. Note that the tiled MacOS X port uses the Qt windowport and the UNIX build system, not this windowport code. 26 Nov, 1999 NetHack 3.3.0 was built with Metrowerk's Pro 4 compiler on a PPC system. We are still compiling with 68K alignment because we know it works. No one has checked lately if the PPC alignment bug still exists. 23 May, 1996 NetHack 3.2.1 was built with Metrowerk's DR8 compiler on a PPC system. The official 68K and PPC versions were compiled with 68K Alignment to share files. The 3.2.0 versions were compiled with PPC alignment, but it was discovered that the Metrowerks 68K compiler has a bug with PPC alignment and structures that can be aligned to a single byte. This bug _may_ be fixed in DR10, it is not fixed in DR9. Why bother with PPC alignment at all? Because the space saving from 68K alignment is small and the PowerPC version will run better. The 68K version was compiled with 4 byte ints using the far model. Only the Metrowerks compiler has been used to compile the code in a long time. It is _very_ likely that the other compilers, Think C and MPW C, will no longer be able to compile NetHack out of the box. They and their files have been moved to the "old" directory until such time that someone can compile with them. nethack-3.6.0/sys/mac/carbon.plist0000664000076400007660000000153112504242744016040 0ustar paxedpaxed CFBundleIconFile nethack CFBundleIdentifier org.nethack.carbon CFBundleLongVersionString 3.5.0 © 1985-2005 devteam@nethack.org CFBundleName NetHack CFBundlePackageType APPL CFBundleShortVersionString 3.5.0 CFBundleSignature NHak CFBundleVersion 3.5.0 LSPrefersCarbon NSAppleScriptEnabled NSHumanReadableCopyright © 1985-2005 devteam@nethack.org nethack-3.6.0/sys/mac/dprintf.c0000664000076400007660000000237612536476415015352 0ustar paxedpaxed/* NetHack 3.6 dprintf.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Jon W{tte, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "macwin.h" static Boolean KeyDown(unsigned short code) { unsigned char keys[16]; GetKeys((void *) keys); return ((keys[code >> 3] >> (code & 7)) & 1) != 0; } void dprintf(char *format, ...) { char buffer[500]; va_list list; int doit; #define DO_DEBUGSTR 1 #define DO_PLINE 2 if (flags.debug) { doit = 0; if (macFlags.hasDebugger && KeyDown(0x39)) { /* Caps Lock */ doit = DO_DEBUGSTR; } else if (KeyDown(0x3B) && iflags.window_inited && /* Control */ (WIN_MESSAGE != -1) && theWindows[WIN_MESSAGE].its_window) { doit = DO_PLINE; } if (doit) { va_start(list, format); vsprintf(&buffer[1], format, list); va_end(list); if (doit == DO_DEBUGSTR) { buffer[0] = strlen(&buffer[1]); DebugStr((uchar *) buffer); } else if (doit == DO_PLINE) pline("%s", &buffer[1]); } } } nethack-3.6.0/sys/mac/maccurs.c0000664000076400007660000001120712536476415015332 0ustar paxedpaxed/* NetHack 3.6 maccurs.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Jon W{tte, 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mactty.h" #include "macwin.h" #if 1 /*!TARGET_API_MAC_CARBON*/ #include #include #include #endif static Boolean winFileInit = 0; static unsigned char winFileName[32] = "\pNetHack Preferences"; static long winFileDir; static short winFileVol; typedef struct WinPosSave { char validPos; char validSize; short top; short left; short height; short width; } WinPosSave; static WinPosSave savePos[kLastWindowKind + 1]; static void InitWinFile(void) { StringHandle sh; long len; short ref = 0; if (winFileInit) { return; } /* We trust the glue. If there's an error, store in game dir. */ if (FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, &winFileVol, &winFileDir)) { winFileVol = 0; winFileDir = 0; } sh = GetString(128); if (sh && *sh) { BlockMove(*sh, winFileName, **sh + 1); ReleaseResource((Handle) sh); } if (HOpen(winFileVol, winFileDir, winFileName, fsRdPerm, &ref)) { return; } len = sizeof(savePos); if (!FSRead(ref, &len, savePos)) { winFileInit = 1; } FSClose(ref); } static void FlushWinFile(void) { short ref; long len; if (!winFileInit) { if (!winFileName[0]) { return; } HCreate(winFileVol, winFileDir, winFileName, MAC_CREATOR, PREF_TYPE); HCreateResFile(winFileVol, winFileDir, winFileName); } if (HOpen(winFileVol, winFileDir, winFileName, fsWrPerm, &ref)) { return; } winFileInit = 1; len = sizeof(savePos); (void) FSWrite(ref, &len, savePos); /* Don't care about error */ FSClose(ref); } Boolean RetrievePosition(short kind, short *top, short *left) { Point p; if (kind < 0 || kind > kLastWindowKind) { dprintf("Retrieve Bad kind %d", kind); return 0; } InitWinFile(); if (!savePos[kind].validPos) { dprintf("Retrieve Not stored kind %d", kind); return 0; } p.v = savePos[kind].top; p.h = savePos[kind].left; *left = p.h; *top = p.v; dprintf("Retrieve Kind %d Pt (%d,%d)", kind, p.h, p.v); return (PtInRgn(p, GetGrayRgn())); } Boolean RetrieveSize(short kind, short top, short left, short *height, short *width) { Point p; if (kind < 0 || kind > kLastWindowKind) { return 0; } InitWinFile(); if (!savePos[kind].validSize) { return 0; } *width = savePos[kind].width; *height = savePos[kind].height; p.h = left + *width; p.v = top + *height; return PtInRgn(p, GetGrayRgn()); } static void SavePosition(short kind, short top, short left) { if (kind < 0 || kind > kLastWindowKind) { dprintf("Save bad kind %d", kind); return; } InitWinFile(); savePos[kind].validPos = 1; savePos[kind].top = top; savePos[kind].left = left; dprintf("Save kind %d pt (%d,%d)", kind, left, top); FlushWinFile(); } static void SaveSize(short kind, short height, short width) { if (kind < 0 || kind > kLastWindowKind) { dprintf("Save bad kind %d", kind); return; } InitWinFile(); savePos[kind].validSize = 1; savePos[kind].width = width; savePos[kind].height = height; FlushWinFile(); } static short GetWinKind(WindowPtr win) { short kind; if (!CheckNhWin(win)) { return -1; } kind = GetWindowKind(win) - WIN_BASE_KIND; if (kind < 0 || kind > NHW_TEXT) { return -1; } dprintf("In win kind %d (%lx)", kind, win); switch (kind) { case NHW_MAP: case NHW_STATUS: case NHW_BASE: kind = kMapWindow; break; case NHW_MESSAGE: kind = kMessageWindow; break; case NHW_MENU: kind = kMenuWindow; break; default: kind = kTextWindow; break; } dprintf("Out kind %d", kind); return kind; } Boolean RetrieveWinPos(WindowPtr win, short *top, short *left) { return RetrievePosition(GetWinKind(win), top, left); } void SaveWindowPos(WindowPtr win) { Rect r; GetWindowBounds(win, kWindowContentRgn, &r); SavePosition(GetWinKind(win), r.top, r.left); } void SaveWindowSize(WindowPtr win) { short width, height; Rect r; GetWindowBounds(win, kWindowContentRgn, &r); width = r.right - r.left; height = r.bottom - r.top; SaveSize(GetWinKind(win), height, width); } nethack-3.6.0/sys/mac/macerrs.c0000664000076400007660000001030112536476415015323 0ustar paxedpaxed/* NetHack 3.6 macerrs.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Michael Hamel, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #if defined(macintosh) && defined(__SC__) && !defined(__FAR_CODE__) /* this needs to be resident always */ #pragma segment Main #endif #include "hack.h" #include "macwin.h" #if !TARGET_API_MAC_CARBON #include #include #include #endif void error(const char *format, ...) { Str255 buf; va_list ap; va_start(ap, format); vsprintf((char *) buf, format, ap); va_end(ap); C2P((char *) buf, buf); ParamText(buf, (StringPtr) "", (StringPtr) "", (StringPtr) ""); Alert(128, (ModalFilterUPP) NULL); ExitToShell(); } #if 0 /* Remainder of file is obsolete and will be removed */ #define stackDepth 1 #define errAlertID 129 #define stdIOErrID 1999 static Str255 gActivities[stackDepth] = {""}; static short gTopactivity = 0; void showerror(char * errdesc, const char * errcomment) { short itemHit; Str255 paserr, pascomment; SetCursor(&qd.arrow); if (errcomment == nil) errcomment = ""; C2P (errcomment, pascomment); C2P (errdesc, paserr); ParamText(paserr,pascomment,gActivities[gTopactivity],(StringPtr)""); itemHit = Alert(errAlertID, (ModalFilterUPP)nil); } Boolean itworked(short errcode) /* Return TRUE if it worked, do an error message and return false if it didn't. Error strings for native C errors are in STR#1999, Mac errs in STR 2000-errcode, e.g 2108 for not enough memory */ { if (errcode != 0) { short itemHit; Str255 errdesc; StringHandle strh; errdesc[0] = '\0'; if (errcode > 0) GetIndString(errdesc,stdIOErrID,errcode); /* STDIO file rres, etc */ else { strh = GetString(2000-errcode); if (strh != (StringHandle) nil) { memcpy(errdesc,*strh,256); ReleaseResource((Handle)strh); } } if (errdesc[0] == '\0') { /* No description found, just give the number */ sprintf((char *)&errdesc[1],"a %d error occurred",errcode); errdesc[0] = strlen((char*)&errdesc[1]); } SetCursor(&qd.arrow); ParamText(errdesc,(StringPtr)"",gActivities[gTopactivity],(StringPtr)""); itemHit = Alert(errAlertID, (ModalFilterUPP)nil); } return(errcode==0); } void mustwork(short errcode) /* For cases where we can't recover from the error by any means */ { if (itworked(errcode)) ; else ExitToShell(); } #if defined(USE_STDARG) || defined(USE_VARARGS) #ifdef USE_STDARG static void vprogerror(const char *line, va_list the_args); #else static void vprogerror(); #endif /* Macro substitute for error() */ void error VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, char *); vprogerror(line, VA_ARGS); VA_END(); } #ifdef USE_STDARG static void vprogerror(const char *line, va_list the_args) #else static void vprogerror(line, the_args) const char *line; va_list the_args; #endif #else /* USE_STDARG | USE_VARARG */ void error VA_DECL(const char *, line) #endif { /* opening brace for vprogerror(), nested block for USE_OLDARG error() */ char pbuf[BUFSZ]; if(index(line, '%')) { Vsprintf(pbuf,line,VA_ARGS); line = pbuf; } showerror("of an internal error",line); #if !(defined(USE_STDARG) || defined(USE_VARARGS)) VA_END(); /* provides closing brace for USE_OLDARGS's nested block */ #endif } void attemptingto(char * activity) /* Say what we are trying to do for subsequent error-handling: will appear as x in an alert in the form "Could not x because y" */ { C2P(activity,gActivities[gTopactivity]); } void comment(char *s, long n) { Str255 paserr; short itemHit; sprintf((char *)&paserr[1], "%s - %d",s,n); paserr[0] = strlen ((char*)&paserr[1]); ParamText(paserr,(StringPtr)"",(StringPtr)"",(StringPtr)""); itemHit = Alert(128, (ModalFilterUPP)nil); } void pushattemptingto(char * activity) /* Push a new description onto stack so we can pop later to previous state */ { if (gTopactivity < stackDepth) { gTopactivity++; attemptingto(activity); } else error("activity stack overflow"); } void popattempt(void) /* Pop to previous state */ { if (gTopactivity > 1) --gTopactivity; else error("activity stack underflow"); } #endif /* Obsolete */ nethack-3.6.0/sys/mac/macfile.c0000664000076400007660000002366412536476415015307 0ustar paxedpaxed/* NetHack 3.6 macfile.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ /* * macfile.c * MAC file I/O routines */ #include "hack.h" #include "macwin.h" #ifndef __MACH__ #include #include #include #include #include #include #endif #include "dlb.h" /* * We should get the default dirID and volRefNum (from name) from prefs and * the situation at startup... For now, this will have to do. */ /* The HandleFiles are resources built into the application which are treated as read-only files: if we fail to open a file we look for a resource */ #define FIRST_HF 32000 /* file ID of first HandleFile */ #define MAX_HF 6 /* Max # of open HandleFiles */ #define APP_NAME_RES_ID (-16396) typedef struct handlefile { long type; /* Resource type */ short id; /* Resource id */ long mark; /* Current position */ long size; /* total size */ Handle data; /* The resource, purgeable */ } HandleFile; static HandleFile *FDECL(IsHandleFile, (int)); static int FDECL(OpenHandleFile, (const unsigned char *, long)); static int FDECL(CloseHandleFile, (int)); static int FDECL(ReadHandleFile, (int, void *, unsigned)); static long FDECL(SetHandleFilePos, (int, short, long)); HandleFile theHandleFiles[MAX_HF]; MacDirs theDirs; /* also referenced in macwin.c */ static HandleFile * IsHandleFile(int fd) { HandleFile *hfp = NULL; if (fd >= FIRST_HF && fd < FIRST_HF + MAX_HF) { /* in valid range, check for data */ hfp = &theHandleFiles[fd - FIRST_HF]; if (!hfp->data) hfp = NULL; } return hfp; } static int OpenHandleFile(const unsigned char *name, long fileType) { int i; Handle h; Str255 s; for (i = 0; i < MAX_HF; i++) { if (theHandleFiles[i].data == 0L) break; } if (i >= MAX_HF) return -1; h = GetNamedResource(fileType, name); if (!h) return (-1); theHandleFiles[i].data = h; theHandleFiles[i].size = GetHandleSize(h); GetResInfo(h, &theHandleFiles[i].id, (void *) &theHandleFiles[i].type, s); theHandleFiles[i].mark = 0L; return (i + FIRST_HF); } static int CloseHandleFile(int fd) { if (!IsHandleFile(fd)) { return -1; } fd -= FIRST_HF; ReleaseResource(theHandleFiles[fd].data); theHandleFiles[fd].data = 0L; return (0); } static int ReadHandleFile(int fd, void *ptr, unsigned len) { unsigned maxBytes; Handle h; if (!IsHandleFile(fd)) return -1; fd -= FIRST_HF; maxBytes = theHandleFiles[fd].size - theHandleFiles[fd].mark; if (len > maxBytes) len = maxBytes; h = theHandleFiles[fd].data; HLock(h); BlockMove(*h + theHandleFiles[fd].mark, ptr, len); HUnlock(h); theHandleFiles[fd].mark += len; return (len); } static long SetHandleFilePos(int fd, short whence, long pos) { long curpos; if (!IsHandleFile(fd)) return -1; fd -= FIRST_HF; curpos = theHandleFiles[fd].mark; switch (whence) { case SEEK_CUR: curpos += pos; break; case SEEK_END: curpos = theHandleFiles[fd].size - pos; break; default: /* set */ curpos = pos; break; } if (curpos < 0) curpos = 0; else if (curpos > theHandleFiles[fd].size) curpos = theHandleFiles[fd].size; theHandleFiles[fd].mark = curpos; return curpos; } void C2P(const char *c, unsigned char *p) { int len = strlen(c), i; if (len > 255) len = 255; for (i = len; i > 0; i--) p[i] = c[i - 1]; p[0] = len; } void P2C(const unsigned char *p, char *c) { int idx = *p++; for (; idx > 0; idx--) *c++ = *p++; *c = '\0'; } static void replace_resource(Handle new_res, ResType its_type, short its_id, Str255 its_name) { Handle old_res; SetResLoad(false); old_res = Get1Resource(its_type, its_id); SetResLoad(true); if (old_res) { RemoveResource(old_res); DisposeHandle(old_res); } AddResource(new_res, its_type, its_id, its_name); } int maccreat(const char *name, long fileType) { return macopen(name, O_RDWR | O_CREAT | O_TRUNC, fileType); } int macopen(const char *name, int flags, long fileType) { short refNum; short perm; Str255 s; C2P(name, s); if (flags & O_CREAT) { if (HCreate(theDirs.dataRefNum, theDirs.dataDirID, s, TEXT_CREATOR, fileType) && (flags & O_EXCL)) { return -1; } #if 0 /* Fails during makedefs */ if (fileType == SAVE_TYPE) { short resRef; HCreateResFile(theDirs.dataRefNum, theDirs.dataDirID, s); resRef = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, s, fsRdWrPerm); if (resRef != -1) { Handle name; Str255 plnamep; C2P(plname, plnamep); name = (Handle)NewString(plnamep); if (name) replace_resource(name, 'STR ', PLAYER_NAME_RES_ID, "\pPlayer Name"); /* The application name resource. See IM VI, page 9-21. */ name = (Handle)GetString(APP_NAME_RES_ID); if (name) { DetachResource(name); replace_resource(name, 'STR ', APP_NAME_RES_ID, "\pApplication Name"); } CloseResFile(resRef); } } #endif } /* * Here, we should check for file type, maybe a SFdialog if * we fail with default, etc. etc. Besides, we should use HOpen * and permissions. */ if ((flags & O_RDONLY) == O_RDONLY) { perm = fsRdPerm; } if ((flags & O_WRONLY) == O_WRONLY) { perm = fsWrPerm; } if ((flags & O_RDWR) == O_RDWR) { perm = fsRdWrPerm; } if (HOpen(theDirs.dataRefNum, theDirs.dataDirID, s, perm, &refNum)) { return OpenHandleFile(s, fileType); } if (flags & O_TRUNC) { if (SetEOF(refNum, 0L)) { FSClose(refNum); return -1; } } return refNum; } int macclose(int fd) { if (IsHandleFile(fd)) { CloseHandleFile(fd); } else { if (FSClose(fd)) { return -1; } FlushVol((StringPtr) 0, theDirs.dataRefNum); } return 0; } int macread(int fd, void *ptr, unsigned len) { long amt = len; if (IsHandleFile(fd)) { return ReadHandleFile(fd, ptr, amt); } else { short err = FSRead(fd, &amt, ptr); return ((err == noErr) || (err == eofErr && len)) ? amt : -1; } } #if 0 /* this function isn't used, if you use it, uncomment prototype in \ macwin.h */ char * macgets (int fd, char *ptr, unsigned len) { int idx = 0; char c; while (-- len > 0) { if (macread (fd, ptr + idx, 1) <= 0) return (char *)0; c = ptr[idx++]; if (c == '\n' || c == '\r') break; } ptr [idx] = '\0'; return ptr; } #endif /* 0 */ int macwrite(int fd, void *ptr, unsigned len) { long amt = len; if (IsHandleFile(fd)) return -1; if (FSWrite(fd, &amt, ptr) == noErr) return (amt); else return (-1); } long macseek(int fd, long where, short whence) { short posMode; long curPos; if (IsHandleFile(fd)) { return SetHandleFilePos(fd, whence, where); } switch (whence) { default: posMode = fsFromStart; break; case SEEK_CUR: posMode = fsFromMark; break; case SEEK_END: posMode = fsFromLEOF; break; } if (SetFPos(fd, posMode, where) == noErr && GetFPos(fd, &curPos) == noErr) return (curPos); else return (-1); } int macunlink(const char *name) { Str255 pname; C2P(name, pname); return (HDelete(theDirs.dataRefNum, theDirs.dataDirID, pname) == noErr ? 0 : -1); } /* ---------------------------------------------------------------------- */ boolean rsrc_dlb_init(void) { return TRUE; } void rsrc_dlb_cleanup(void) { } boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode) { #if defined(__SC__) || defined(__MRC__) #pragma unused(mode) #endif Str255 pname; C2P(name, pname); dp->fd = OpenHandleFile(pname, 'File'); /* automatically read-only */ return dp->fd >= 0; } int rsrc_dlb_fclose(dlb *dp) { return CloseHandleFile(dp->fd); } int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp) { int nread; if (size < 0 || quan < 0) return 0; nread = ReadHandleFile(dp->fd, buf, (unsigned) size * (unsigned) quan); return nread / size; /* # of whole pieces (== quan in normal case) */ } int rsrc_dlb_fseek(dlb *dp, long pos, int whence) { return SetHandleFilePos(dp->fd, whence, pos); } char * rsrc_dlb_fgets(char *buf, int len, dlb *dp) { HandleFile *hfp = IsHandleFile(dp->fd); char *p; int bytesLeft, n = 0; if (hfp && hfp->mark < hfp->size) { bytesLeft = hfp->size - hfp->mark; if (bytesLeft < len) len = bytesLeft; HLock(hfp->data); for (n = 0, p = *hfp->data + hfp->mark; n < len; n++, p++) { buf[n] = *p; if (*p == '\r') buf[n] = '\n'; if (buf[n] == '\n') { n++; /* we want the return in the buffer */ break; } } HUnlock(hfp->data); hfp->mark += n; if (n != 0) buf[n] = '\0'; /* null terminate result */ } return n ? buf : NULL; } int rsrc_dlb_fgetc(dlb *dp) { HandleFile *hfp = IsHandleFile(dp->fd); int ret; if (!hfp || hfp->size <= hfp->mark) return EOF; ret = *(unsigned char *) (*hfp->data + hfp->mark); hfp->mark++; return ret; } long rsrc_dlb_ftell(dlb *dp) { HandleFile *hfp = IsHandleFile(dp->fd); if (!hfp) return 0; return hfp->mark; } nethack-3.6.0/sys/mac/machelp.hqx0000664000076400007660000001025412467321052015652 0ustar paxedpaxed(This file must be converted with BinHex 4.0) :#QeKBfKPE(!ZBQJ!9%9B9%0A588"#!!!#PX!!!'XRNmM#90$3e-J5@3k)%!S)bP YB@0SC@a`,Q*S#6-Z-`Nj15m`-bma03dM#80[F(PbD@GSG#!SBbNJ-6Nj1#da16N j)'*j)%YPGQPZ)%KeCfm0)b"1CA4)B@0V)'eKH5"LC5"QFQ9PE(NJFQ9NDA0dFQP LGA4PC#iJ)&0PC5"XD@0PER0P)'C[FL"NCA4KD@ac,Jd0$5-M)b""FfYZB@eP)'4 TB@a[Cb!M)b-04%P"6%p()$B`-$!JBA0VEQ&YC3d0)b"3E'&j)'*eG(4[EJda,Q9 ZB@*XC@3J3faTBfXJD'9bC5"dEb"`E'&j)(4SDA-JBfKKFQ&MG'9b,Jda,Q4TFf& LE'9N)%0XD@0V)'KPFQ8JG'mJF'aKH5"dD'Pc)'0SBA*KBh4PFLl#$5!J6Qpd)'& fB@PXB@*XC5"LC@0KGA0P)(P[G5"SBACPELGd)(4jF'9N)'PZ)'%JEQ&YC5i0$5- J8A9TG#"LGA4dEfi0-LiU)%0XD@0V)'KPFQ8JG'mJFA9TG#"dD'8JF(*[Ch*KE5i 0$5-J8QpXC5"`Eh"eF#"YC@je$63Z+L"6C@aPBh3JH@peFL"NCA0TFQ9N)(*[E'8 J+%&bBfKPEfa[CfPcG#`J3Q&bBQ&bD@&Z,#"PG'-Z+F)0)(GTG'JJG'KTFb"`Eh" eF#"YC@je,Jd0)b"5B@0P)("[F(9`)'ePER8005iU)&0PE'9MG#"jEh9b)'4PFfP bC@3JFQ&MC5!S5(9YB@iX)%9XCL`JCA4M,LR#$5"hDA4S)(4SDA-JF'p`GA!JE@9 ZG5i0$5-J4f9ZC'9b)("[F(9`)'ePER800LiU)&0PE'9MG#"jEh9b)'GPEQ4PFL! SE@&XC5"[FL"QC@eKE'8T)(GTG'JJG'KTFb"`Eh"eF#"YC@je,Jd0)b""E'PREQe PER3JF'p`GA!JE@9ZG3dh,LSJ8f9XC@0d)(P[GA)JB@aTCfjYC@jd)#KXBAGQG@` X)'jPGA4bB@`X)'pb)'0SB@pdD@-T`JdJGfPdD#"dD'Pc)("[F(9`)'ePER8Z$3d M)%e[C'8JF'p`GA!JE@9ZG3di,LSJ9A0P)(4SDA-JF'p`GA!JE@9ZG5"dEb"cC@a PBh3JFQ9RG@aKFL"`E'&j)'e[C'8X`JdJCAK`E'pbC5"YEf4P,#"[FL"NC@*eCfG TEQFJE@pNC5i0$5-J6Q&YC5"dCAKd)'PdC@d015iU)&4jF'8JD@iJH@peFL"MD'& bB@0dCA)RFb"ZB@eP)'KPFQ8Z$3dM)%PMEfi0-6!Z+L"AD'mJDA-JG'KTFb"RGAN r$3e&6N3Y4%P"6%p($3d0689195!a-MJJ3A"`E'80$6%ZC@jKBQaPC#"%DA0`E'& jFb"TEQC[FQeKG'P[EL"KBQpeG#"dD'Pc)(CPFR0TEfiZ$3e&6N3Y689193d0$8e &6P8J-6)j)%CTE'80$6!ZC@jKBQaPC#"'D@aP)%ePERA#`P9cC5"dD'Pc)'ePER8 JG'mJE@&ZDA"eE'&dC5"hD@jNEhGc`JdJEfiJG'KP)(0MFQ9PEL`JB@jN)(4[)(0 KGQ8JEh)JFA9TG#"dD'8JCf&YC5i0$6%Z+L"0B@YPFb"dD'8JE@&`)'&`F'9KFL" [EL"dD'8JFf0bC@9Z,#"TEL"MBA0P)(P[G5"ME'pcC@6#$5"TG(-JGfPZC'ph,Jd 0-LiU)%C[FQ0PFb"dD'8JE@&`)(4[)'*P)(*PC(*KGfiZ$3dc,LSJ8f0bEfaXFb" dD'8J6@9cFf&RCA-JGfPZC'ph)'*KBfXJEfjP)'ePFh0KCf8Z$3dd,LSJ8Q9`Eh0 TG'P[ER-JB@aX)(GTEQ4[Gh-JFfmJG'KPH5"KFQ8JEfiYFf0bC@9Z,Jd005iU)%0 XEh0PFb"dD'8JCR*[ER4YEh0d)(GTEQ4[Gbi0$6JZ+L"&ER4PFR-JCAK`E'pbC5" YEf4P,#"hD'PMD#"TFb"K)'G[Ef3JGf&j)(4[)'aPBA*Z)(4SC5"RB@eP,Jd0-6! Z+L"6BACPFb"dD'8JCf&YC5`JB@jN)(4SC@iJFA9TG(-JG'KP)("bEfGbB@dZ$3d a-LiU)&&eDA4c)(4SC5"`FQpRFQ&Y)(GTG'K[GA3JFf&fD@jR)(4SC5"RB@eP,Jd 048j%,8e&6P80$3e048j9)$%c-#"&C'Pd$3d`,Q9ZB@*XC@3J4@4TG#"0C@je`X* 9Ff8JG'KTFb"YC@je)(4[)'9NDA3JG'9iG#"[FL"eEQ4[`JdJB@iJB@0dD@pZ,Jd `,Q4TFf&LE'9N)%9NDA3J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"PC'Pd)(4PH(3 JEh)JG@jNEm)0)'&Z)'&MG'P[ELiJ)%&fB@PXB@*XC5"[EQaj)'C[FL"NCA0V)'& MBf9cFfpbD@9c,Jd048j%,8e&6P80$3e048j9)$%c-5",BQ30$6!ZC@jKBQaPC#" ,CAPLEf&bC#"0C@je`X*9Ff8JG'KTFb"YC@je)(4[)(0TEA9XBA4P`JdJF(*PFh0 TEQFJDf9jFb"[EL"K)'YPH@*[BA*N,#"cEb"jEh8JBf&Z)("XBANJC@jdDA*PE(R #$5"LH5"YEh9cC5i0$8914#e048j9$3d0689195!a-c)J5'9XF!d0-#jPEQ&LE'9 N)%KPE(!J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"PH("XB@PZ)'K[Gm)0)(4SC5" RB@eP)(G[FQYc,#"[FL"dEb"cCA3JEh"dD@pZFbi0$8914#e048j9$3d0689195! a-c-J5@jQE`d0-#jPEQ&LE'9N)%PZCQmJ6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb" XEfpV)'&d)'pb`JdJE@&ZDA"eE'&dC5"jEh9b)'PZGQ9ZG'pbH5`JCAK`E'&TEL" cEfePG'KTEQFJEfiJG'KP`JdJFf0bC@9Z,#"[FL"RDACP)'&Z)'pLDQ9MG#"[FL" YEfjcG'9b)'%JEQ&YC5i0$8914#e048j9$3d0689195!a-c3J4A&eDA!0$6!ZC@j KBQaPC#"&FA9TF'ePER3J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"YB@jTF(9XBA4 P`JdJGf9KF'pZFb`JBA*YEh)X)'&ZC#"[G'KPFL"hEh*Z)'PdC@ec,Jd048j%,8e &6P80$3e048j9)$%c05""Bh30$6!ZC@jKBQaPC#""Bh4TEfiJ6@9ZGF,#9A0P)(4 SDA-JE@9ZG5"dEb"`CA*QEh*Y)'&Z)'&MG'P[ELi0$8914#e048j9$3d0689195! a-cBJ6@&RD@-0$6!ZC@jKBQaPC#"0B@GTBb"0C@je`X*9Ff8JG'KTFb"YC@je)(4 [)'eKEQP`G@aKG'8JE@&RD@2#$5"TG'9YFbi0$8914#e048j9$3e048j9)$%c0b" #DA4c$3d`,Q9ZB@*XC@3J3QPdFb"0C@je`X*9Ff8JG'KTFb"YC@je)(4[)("PFQC [FQh#$5"YDA0MC@aXB@jPEh9c)'&MG'P[ER-Z$3e&6N3Y689193d048j%$5dp!!! "!!!!!9S!!!"D!!!!8KY`!4m!6VVdjL!ZrqU`RfF-2`B["5m-U"YJ!!$+9Bmr#Qe KBfKPE(!ZBQKbUL"*4%8J8(*PCR0TEfjMCA0PFfi!$&4&@&4$9dP&!3Mrrrrr!!! !!!!!!!!!!!!!!!!!!!K$XNab!!!!#PX!!!'XmNkkqQSq(fCU9Bmr,[r`5'lrpNK ZrrK)E[rm6VVpU$iICP"9Mh!!,`!r"Lm&6VVkKMiICJS[$+Qa9BqTVciIF!+`V[r iCKC9Mh!!,`!r,[r`,blrmNkkqPik(f!39Bp`!#m!2blrm%kkpFJk(dT(CJ)q"6( (#Q"-lK$JrpT1AL"I6`!!!%J!#8e[EQ&ME`!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!)!"!!V!+F"dJ*H!#X!T`(5!Pkc58b!!!!!!!!!#PX!!!!!!3!!!!!#!!! !!!!%!!%!!!!!!3!!!!&D!!!!@J!!!&)"ITa%(YS!!!!F!&)!!8e38e)!!3!569G #3J!!!#S$lIrr!!!!!!!!!!!$lrrr!!!!6!!!!!!$m2rr!!!!8J!!!!#PK!: nethack-3.6.0/sys/mac/macmain.c0000664000076400007660000002046312536476415015306 0ustar paxedpaxed/* NetHack 3.6 macmain.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.21 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - Mac NetHack */ #include "hack.h" #include "dlb.h" #include "macwin.h" #include "mactty.h" #if 1 /*!TARGET_API_MAC_CARBON*/ #include #include #include #include #include #include #include #include #endif #ifndef O_RDONLY #include #endif static void finder_file_request(void); int main(void); #if __SC__ || __MRC__ QDGlobals qd; #endif int main(void) { register int fd = -1; int argc = 1; boolean resuming = FALSE; /* assume new game */ sys_early_init(); windowprocs = mac_procs; InitMac(); hname = "Mac Hack"; hackpid = getpid(); setrandom(); initoptions(); init_nhwindows(&argc, (char **) &hname); /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ finder_file_request(); dlb_init(); /* must be before newgame() */ /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); set_playmode(); /* sets plname to "wizard" for wizard mode */ /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); /* unlike Unix where the game might be invoked with a script which forces a particular character name for each player using a shared account, we always allow player to rename the character during role/race/&c selection */ iflags.renameallowed = TRUE; getlock(); /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. */ attempt_restore: if ((fd = restore_saved_game()) >= 0) { #ifdef NEWS if (iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ game_active = 1; if (dorecover(fd)) { resuming = TRUE; /* not starting new game */ if (discover) You("are in non-scoring discovery mode."); if (discover || wizard) { if (yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { nh_compress(fqname(SAVEF, SAVEPREFIX, 0)); } } } } if (!resuming) { /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name and skip selection this time if that didn't succeed */ if (!iflags.renameinprogress) { player_selection(); if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; discard current lock file and create another for the new character name */ delete_levelfile(0); /* remove empty lock file */ getlock(); goto attempt_restore; } } game_active = 1; /* done with selection, draw active game window */ newgame(); if (discover) You("are in non-scoring discovery mode."); } UndimMenuBar(); /* Yes, this is the place for it (!) */ moveloop(resuming); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static OSErr copy_file(short src_vol, long src_dir, short dst_vol, long dst_dir, Str255 fName, pascal OSErr (*opener)(short vRefNum, long dirID, ConstStr255Param fileName, signed char permission, short *refNum)) { short src_ref, dst_ref; OSErr err = (*opener)(src_vol, src_dir, fName, fsRdPerm, &src_ref); if (err == noErr) { err = (*opener)(dst_vol, dst_dir, fName, fsWrPerm, &dst_ref); if (err == noErr) { long file_len; err = GetEOF(src_ref, &file_len); if (err == noErr) { Handle buf; long count = MaxBlock(); if (count > file_len) count = file_len; buf = NewHandle(count); err = MemError(); if (err == noErr) { while (count > 0) { OSErr rd_err = FSRead(src_ref, &count, *buf); err = FSWrite(dst_ref, &count, *buf); if (err == noErr) err = rd_err; file_len -= count; } if (file_len == 0) err = noErr; DisposeHandle(buf); } } FSClose(dst_ref); } FSClose(src_ref); } return err; } static void force_hdelete(short vol, long dir, Str255 fName) { HRstFLock(vol, dir, fName); HDelete(vol, dir, fName); } void process_openfile(short src_vol, long src_dir, Str255 fName, OSType ftype) { OSErr err = noErr; if (ftype != SAVE_TYPE) return; /* only deal with save files */ if (src_vol != theDirs.dataRefNum || src_dir != theDirs.dataDirID && CatMove(src_vol, src_dir, fName, theDirs.dataDirID, "\p:") != noErr) { HCreate(theDirs.dataRefNum, theDirs.dataDirID, fName, MAC_CREATOR, SAVE_TYPE); err = copy_file(src_vol, src_dir, theDirs.dataRefNum, theDirs.dataDirID, fName, &HOpen); /* HOpenDF is only there under 7.0 */ if (err == noErr) err = copy_file(src_vol, src_dir, theDirs.dataRefNum, theDirs.dataDirID, fName, &HOpenRF); if (err == noErr) force_hdelete(src_vol, src_dir, fName); else HDelete(theDirs.dataRefNum, theDirs.dataDirID, fName); } if (err == noErr) { short ref; ref = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, fName, fsRdPerm); if (ref != -1) { Handle name = Get1Resource('STR ', PLAYER_NAME_RES_ID); if (name) { Str255 save_f_p; P2C(*(StringHandle) name, plname); set_savefile_name(TRUE); C2P(fqname(SAVEF, SAVEPREFIX, 0), save_f_p); force_hdelete(theDirs.dataRefNum, theDirs.dataDirID, save_f_p); if (HRename(theDirs.dataRefNum, theDirs.dataDirID, fName, save_f_p) == noErr) macFlags.gotOpen = 1; } CloseResFile(ref); } } } static void finder_file_request(void) { if (macFlags.hasAE) { /* we're capable of handling Apple Events, so let's see if we have any */ EventRecord event; long toWhen = TickCount() + 20; /* wait a third of a second for all initial AE */ while (TickCount() < toWhen) { if (WaitNextEvent(highLevelEventMask, &event, 3L, 0)) { AEProcessAppleEvent(&event); if (macFlags.gotOpen) break; } } } #if 0 #ifdef MAC68K else { short finder_msg, file_count; CountAppFiles(&finder_msg, &file_count); if (finder_msg == appOpen && file_count == 1) { OSErr err; AppFile src; FSSpec filespec; GetAppFiles(1, &src); err = FSMakeFSSpec(src.vRefNum, 0, src.fName, &filespec); if (err == noErr && src.fType == SAVE_TYPE) { process_openfile (filespec.vRefNum, filespec.parID, filespec.name, src.fType); if (macFlags.gotOpen) ClrAppFiles(1); } } } #endif /* MAC68K */ #endif /* 0 */ } /* validate wizard mode if player has requested access to it */ boolean authorize_wizard_mode() { /* other ports validate user name or character name here */ return TRUE; } /*macmain.c*/ nethack-3.6.0/sys/mac/macmenu.c0000664000076400007660000010110112536476415015313 0ustar paxedpaxed/* NetHack 3.6 macmenu.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Macintosh NetHack Port Team, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /****************************************\ * Extended Macintosh menu support * * provides access to all keyboard commands from cmd.c * provides control key functionality for classic keyboards * provides key equivalent references and logical menu groups * supports various menu highlighting modes \****************************************/ /****************************************\ * Edit History: * * 930512 - More bug fixes and getting tty to work again, Jon W{tte * 930508 - Bug fixes in-flight, Jon W{tte * 04/29/93 - 1st Release Draft, David Hairston * 04/11/93 - 1st Draft, David Hairston \****************************************/ /******** Application Defines ********/ #include "hack.h" #include "mactty.h" #include "macwin.h" #include "macpopup.h" #include "patchlevel.h" /******** Toolbox Defines ********/ #if !TARGET_API_MAC_CARBON #include #include #include #include #include #include #endif /* Borrowed from the Mac tty port */ extern WindowPtr _mt_window; /******** Local Defines ********/ /* 'MNU#' (menu list record) */ typedef union menuRefUnn { short mresID; /* MENU resource ID (before GetMenu) */ MenuHandle mhnd; /* MENU handle (after GetMenu) */ } menuRefUnn; typedef struct menuListRec { short firstMenuID; short numMenus; menuRefUnn mref[]; } menuListRec, *menuListPtr, **menuListHandle; /* indices and resource IDs of the menu list data */ enum { listMenubar, listSubmenu, menuBarListID = 128, subMenuListID }; /* the following mref[] indices are reserved */ enum { /* menu bar */ menuApple, menuFile, menuEdit, /* submenu */ menuWizard = 0 }; /* the following menu items are reserved */ enum { /* apple */ menuAppleAboutBox = 1, ____Apple__1, /* File */ menuFileRedraw = 1, menuFilePrevMsg, menuFileCleanup, ____File___1, menuFilePlayMode, menuFileEnterExplore, ____File___2, menuFileSave, ____File___3, menuFileQuit, /* standard minimum Edit menu items */ /* Wizard */ menuWizardAttributes = 1 }; /* * menuListRec data (preloaded and locked) specifies the number of menus in * the menu bar, the number of hierarchal or submenus and the menu IDs of * all of those menus. menus that go into in the menu bar are specified by * 'MNU#' 128 and submenus are specified by 'MNU#' 129. the fields of the * menuListRec are: * firstMenuID - the menu ID (not resource ID) of the 1st menu. subsequent * menus in the list are _forced_ to have consecutively incremented IDs. * numMenus - the total count of menus in a given list (and the extent of * valid menu IDs). * mref[] - initially the MENU resource ID is stored in the placeholder for * the resource handle. after loading (GetResource), the menu handle * is stored and the menu ID, in memory, is set as noted above. * * NOTE: a ResEdit template editor is supplied to edit the 'MNU#' resources. * * NOTE: the resource IDs do not need to match the menu IDs in a menu list * record although they have been originally set that way. * * NOTE: the menu ID's of menus in the submenu list record may be reset, as * noted above. it is the programmers responsibility to make sure that * submenu references/IDs are valid. * * WARNING: the existence of the submenu list record is assumed even if the * number of submenus is zero. also, no error checking is done on the * extents of the menu IDs. this must be correctly setup by the programmer. */ #define ID1_MBAR pMenuList[listMenubar]->firstMenuID #define ID1_SUBM pMenuList[listSubmenu]->firstMenuID #define NUM_MBAR pMenuList[listMenubar]->numMenus #define NUM_SUBM pMenuList[listSubmenu]->numMenus #define MHND_APPLE pMenuList[listMenubar]->mref[menuApple].mhnd #define MHND_FILE pMenuList[listMenubar]->mref[menuFile].mhnd #define MHND_EDIT pMenuList[listMenubar]->mref[menuEdit].mhnd #define MBARHND(x) pMenuList[listMenubar]->mref[(x)].mhnd #define MHND_WIZ pMenuList[listSubmenu]->mref[menuWizard].mhnd /* mutually exclusive (and prioritized) menu bar states */ enum { mbarDim, mbarNoWindows, mbarDA, mbarNoMap, mbarRegular, mbarSpecial /* explore or debug mode */ }; #define WKND_MAP (WIN_BASE_KIND + NHW_MAP) /* menu routine error numbers */ enum { errGetMenuList, errGetMenu, errGetANDlogTemplate, errGetANDlogItems, errGetANDialog, errANNewMenu, err_Menu_total }; /* menu 'STR#' comment char */ #define mstrEndChar 0xA5 /* '\245' or option-* or "bullet" */ /* 'ALRT' */ enum { alrt_Menu_start = 5000, alrtMenuNote = alrt_Menu_start, alrtMenu_NY, alrt_Menu_limit }; #define beepMenuAlertErr 1 /* # of SysBeep()'s before exitting */ enum { bttnMenuAlertNo = 1, bttnMenuAlertYes }; /******** Globals ********/ static unsigned char *menuErrStr[err_Menu_total] = { "\pAbort: Bad \'MNU#\' resource!", /* errGetMenuList */ "\pAbort: Bad \'MENU\' resource!", /* errGetMenu */ "\pAbort: Bad \'DLOG\' resource!", /* errGetANDlogTemplate */ "\pAbort: Bad \'DITL\' resource!", /* errGetANDlogItems */ "\pAbort: Bad Dialog Allocation!", /* errGetANDialog */ "\pAbort: Bad Menu Allocation!", /* errANNewMenu */ }; static menuListPtr pMenuList[2]; static short theMenubar = mbarDA; /* force initial update */ static short kAdjustWizardMenu = 1; /******** Prototypes ********/ #if !TARGET_API_MAC_CARBON static void alignAD(Rect *, short); #endif static void mustGetMenuAlerts(void); static void menuError(short); static void aboutNetHack(void); static void askSave(void); static void askQuit(void); /*** Askname dialog box ***/ #define RSRC_ASK 6000 /* Askname dialog and item list */ #define RSRC_ASK_PLAY 1 /* Play button */ #define RSRC_ASK_QUIT 2 /* Quit button */ #define RSRC_ASK_DEFAULT 3 /* Default ring */ #define RSRC_ASK_ROLE 4 /* Role popup menu */ #define RSRC_ASK_RACE 5 /* Race popup menu */ #define RSRC_ASK_GEND 6 /* Gender popup menu */ #define RSRC_ASK_ALIGN 7 /* Alignment popup menu */ #define RSRC_ASK_MODE 8 /* Mode popup menu */ #define RSRC_ASK_NAME 9 /* Name text field */ #define RSRC_ASK_MAX 10 /* Maximum enabled item */ #define KEY_MASK 0xff00 #define KEY_RETURN 0x2400 #define KEY_ENTER 0x4c00 #define KEY_ESCAPE 0x3500 #define CH_MASK 0x00ff #define CH_RETURN 0x000d #define CH_ENTER 0x0003 #define CH_ESCAPE 0x001b static void ask_restring(const char *cstr, unsigned char *pstr); static void ask_enable(DialogRef wind, short item, int enable); static pascal void ask_redraw(DialogRef wind, DialogItemIndex item); static pascal Boolean ask_filter(DialogRef wind, EventRecord *event, DialogItemIndex *item); #define noresource(t, n) \ { \ SysBeep(3); \ ExitToShell(); \ } #define fatal(s) \ { \ SysBeep(3); \ ExitToShell(); \ } static MenuHandle askmenu[RSRC_ASK_MAX]; static int askselect[RSRC_ASK_MAX]; #define currrole askselect[RSRC_ASK_ROLE] #define currrace askselect[RSRC_ASK_RACE] #define currgend askselect[RSRC_ASK_GEND] #define curralign askselect[RSRC_ASK_ALIGN] #define currmode askselect[RSRC_ASK_MODE] static RGBColor blackcolor = { 0x0000, 0x0000, 0x0000 }, // indentcolor = {0x4000, 0x4000, 0x4000}, darkcolor = { 0x8000, 0x8000, 0x8000 }, backcolor = { 0xdddd, 0xdddd, 0xdddd }, lightcolor = { 0xffff, 0xffff, 0xffff }, whitecolor = { 0xffff, 0xffff, 0xffff }; /* Convert a mixed-case C string to a Capitalized Pascal string */ static void ask_restring(const char *cstr, unsigned char *pstr) { int i; for (i = 0; *cstr && (i < 255); i++) pstr[i + 1] = *cstr++; pstr[0] = i; if ((pstr[1] >= 'a') && (pstr[1] <= 'z')) pstr[1] += 'A' - 'a'; return; } /* Enable the dialog item with the given index */ static void ask_enable(DialogRef wind, short item, int enable) { short type; Handle handle; Rect rect; /* Enable or disable the appropriate item */ GetDialogItem(wind, item, &type, &handle, &rect); if (enable) type &= ~itemDisable; else type |= itemDisable; HiliteControl((ControlHandle) handle, enable ? 0 : 255); SetDialogItem(wind, item, type, handle, &rect); return; } static pascal void ask_redraw(DialogRef wind, DialogItemIndex item) { short type; Handle handle; Rect rect; static char *modechar = "NED"; /* Which item shall we redraw? */ GetDialogItem(wind, item, &type, &handle, &rect); switch (item) { case RSRC_ASK_DEFAULT: PenSize(3, 3); FrameRoundRect(&rect, 16, 16); break; case RSRC_ASK_ROLE: case RSRC_ASK_RACE: case RSRC_ASK_GEND: case RSRC_ASK_ALIGN: case RSRC_ASK_MODE: if (macFlags.color) { RGBForeColor(&blackcolor); RGBBackColor(&backcolor); } PenNormal(); TextMode(srcOr); EraseRect(&rect); /* Draw the frame and drop shadow */ rect.right--; rect.bottom--; FrameRect(&rect); MoveTo(rect.right, rect.top + 1); LineTo(rect.right, rect.bottom); LineTo(rect.left + 1, rect.bottom); /* Draw the menu character */ MoveTo(rect.left + 4, rect.top + 12); switch (item) { case RSRC_ASK_ROLE: DrawText(roles[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_RACE: DrawText(races[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_GEND: DrawText(genders[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_ALIGN: DrawText(aligns[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_MODE: DrawChar(modechar[askselect[item]]); break; } /* Draw the popup symbol */ MoveTo(rect.right - 16, rect.top + 5); LineTo(rect.right - 6, rect.top + 5); LineTo(rect.right - 11, rect.top + 10); LineTo(rect.right - 15, rect.top + 6); LineTo(rect.right - 8, rect.top + 6); LineTo(rect.right - 11, rect.top + 9); LineTo(rect.right - 13, rect.top + 7); LineTo(rect.right - 10, rect.top + 7); LineTo(rect.right - 11, rect.top + 8); /* Draw the shadow */ InsetRect(&rect, 1, 1); if (macFlags.color) { RGBColor color; /* Save the foreground color */ GetForeColor(&color); /* Draw the top and left */ RGBForeColor(&lightcolor); MoveTo(rect.left, rect.bottom - 1); LineTo(rect.left, rect.top); LineTo(rect.right - 1, rect.top); /* Draw the bottom and right */ RGBForeColor(&darkcolor); MoveTo(rect.right - 1, rect.top + 1); LineTo(rect.right - 1, rect.bottom - 1); LineTo(rect.left + 1, rect.bottom - 1); /* Restore the foreground color */ RGBForeColor(&color); } break; case RSRC_ASK_NAME: PenNormal(); if (macFlags.color) { RGBForeColor(&whitecolor); RGBBackColor(&whitecolor); TextMode(srcOr); } else { PenMode(notPatCopy); TextMode(srcBic); } InsetRect(&rect, -1, -1); FrameRect(&rect); InsetRect(&rect, -1, -1); FrameRect(&rect); InsetRect(&rect, -2, -2); if (macFlags.color) { /* Draw the top and left */ RGBForeColor(&darkcolor); MoveTo(rect.left, rect.bottom - 1); LineTo(rect.left, rect.top); LineTo(rect.right - 1, rect.top); /* Draw the bottom and right */ RGBForeColor(&lightcolor); MoveTo(rect.right - 1, rect.top + 1); LineTo(rect.right - 1, rect.bottom - 1); LineTo(rect.left + 1, rect.bottom - 1); /* Restore the colors */ RGBForeColor(&blackcolor); RGBBackColor(&backcolor); } break; } return; } static pascal Boolean ask_filter(DialogRef wind, EventRecord *event, DialogItemIndex *item) { short ch, key; switch (event->what) { case keyDown: case autoKey: ch = event->message & CH_MASK; key = event->message & KEY_MASK; /* Handle equivalents for OK */ if ((ch == CH_RETURN) || (key == KEY_RETURN) || (ch == CH_ENTER) || (key == KEY_ENTER)) { if (GetDialogTextEditHandle(wind)[0]->teLength) { FlashButton(wind, RSRC_ASK_PLAY); *item = RSRC_ASK_PLAY; } else *item = 0; return (TRUE); } /* Handle equivalents for Normal/Explore/Debug */ if ((event->modifiers & cmdKey) && (ch == 'n')) { currmode = 0; ask_redraw(wind, RSRC_ASK_MODE); *item = RSRC_ASK_MODE; return (TRUE); } if ((event->modifiers & cmdKey) && (ch == 'e')) { currmode = 1; ask_redraw(wind, RSRC_ASK_MODE); *item = RSRC_ASK_MODE; return (TRUE); } if ((event->modifiers & cmdKey) && (ch == 'd')) { currmode = 2; ask_redraw(wind, RSRC_ASK_MODE); *item = RSRC_ASK_MODE; return (TRUE); } /* Handle equivalents for Cancel and Quit */ if ((ch == CH_ESCAPE) || (key == KEY_ESCAPE) || ((event->modifiers & cmdKey) && (ch == 'q')) || ((event->modifiers & cmdKey) && (ch == '.'))) { FlashButton(wind, RSRC_ASK_QUIT); *item = RSRC_ASK_QUIT; return (TRUE); } return (FALSE); case updateEvt: ask_redraw(wind, RSRC_ASK_NAME); return (FALSE); default: return (FALSE); } } void mac_askname() { GrafPtr oldport; DialogRef askdialog; short i, j, item, type; Handle handle; Rect rect; Str255 str; Point pt; UserItemUPP redraw = NewUserItemUPP(ask_redraw); ModalFilterUPP filter = NewModalFilterUPP(ask_filter); /* Create the dialog */ if (!(askdialog = GetNewDialog(RSRC_ASK, NULL, (WindowRef) -1))) noresource('DLOG', RSRC_ASK); GetPort(&oldport); SetPortDialogPort(askdialog); /* Initialize the name text item */ ask_restring(plname, str); if (plname[0]) { GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); SetDialogItemText(handle, str); } #if 0 { Str32 pName; pName [0] = 0; if (plname && plname [0]) { strcpy ((char *) pName, plname); c2pstr ((char *) pName); } else { Handle h; h = GetResource ('STR ', -16096); if (((Handle) 0 != h) && (GetHandleSize (h) > 0)) { DetachResource (h); HLock (h); if (**h > 31) { **h = 31; } BlockMove (*h, pName, **h + 1); DisposeHandle (h); } } if (pName [0]) { GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); SetDialogItemText(handle, pName); if (pName [0] > 2 && pName [pName [0] - 1] == '-') { short role = (*pANR).anMenu[anRole]; char suffix = (char) pName[pName[0]], *sfxindx = strchr(pl_classes, suffix); if (sfxindx) role = (short) (sfxindx - pl_classes); else if (suffix == '@') role = (short) rn2((int) strlen(pl_classes)); (*pANR).anMenu[anRole] = role; } } } #endif SelectDialogItemText(askdialog, RSRC_ASK_NAME, 0, 32767); /* Initialize the role popup menu */ if (!(askmenu[RSRC_ASK_ROLE] = NewMenu(RSRC_ASK_ROLE, "\p"))) fatal("\pCannot create role menu"); for (i = 0; roles[i].name.m; i++) { ask_restring(roles[i].name.m, str); AppendMenu(askmenu[RSRC_ASK_ROLE], str); } InsertMenu(askmenu[RSRC_ASK_ROLE], hierMenu); if (flags.initrole >= 0) currrole = flags.initrole; /* Check for backward compatibility */ else if ((currrole = str2role(pl_character)) < 0) currrole = randrole(); /* Initialize the race popup menu */ if (!(askmenu[RSRC_ASK_RACE] = NewMenu(RSRC_ASK_RACE, "\p"))) fatal("\pCannot create race menu"); for (i = 0; races[i].noun; i++) { ask_restring(races[i].noun, str); AppendMenu(askmenu[RSRC_ASK_RACE], str); } InsertMenu(askmenu[RSRC_ASK_RACE], hierMenu); if (flags.initrace >= 0) currrace = flags.initrace; else currrace = randrace(currrole); /* Initialize the gender popup menu */ if (!(askmenu[RSRC_ASK_GEND] = NewMenu(RSRC_ASK_GEND, "\p"))) fatal("\pCannot create gender menu"); for (i = 0; i < ROLE_GENDERS; i++) { ask_restring(genders[i].adj, str); AppendMenu(askmenu[RSRC_ASK_GEND], str); } InsertMenu(askmenu[RSRC_ASK_GEND], hierMenu); if (flags.initgend >= 0) currgend = flags.initgend; else if (flags.female) currgend = 1; else currgend = randgend(currrole, currrace); /* Initialize the alignment popup menu */ if (!(askmenu[RSRC_ASK_ALIGN] = NewMenu(RSRC_ASK_ALIGN, "\p"))) fatal("\pCannot create alignment menu"); for (i = 0; i < ROLE_ALIGNS; i++) { ask_restring(aligns[i].adj, str); AppendMenu(askmenu[RSRC_ASK_ALIGN], str); } InsertMenu(askmenu[RSRC_ASK_ALIGN], hierMenu); if (flags.initalign >= 0) curralign = flags.initalign; else curralign = randalign(currrole, currrace); /* Initialize the mode popup menu */ if (!(askmenu[RSRC_ASK_MODE] = NewMenu(RSRC_ASK_MODE, "\p"))) fatal("\pCannot create mode menu"); AppendMenu(askmenu[RSRC_ASK_MODE], "\pNormal"); AppendMenu(askmenu[RSRC_ASK_MODE], "\pExplore"); AppendMenu(askmenu[RSRC_ASK_MODE], "\pDebug"); InsertMenu(askmenu[RSRC_ASK_MODE], hierMenu); currmode = 0; /* Set the redraw procedures */ for (item = RSRC_ASK_DEFAULT; item <= RSRC_ASK_MODE; item++) { GetDialogItem(askdialog, item, &type, &handle, &rect); SetDialogItem(askdialog, item, type, (Handle) redraw, &rect); } /* Handle dialog events */ do { /* Adjust the Play button */ ask_enable(askdialog, RSRC_ASK_PLAY, GetDialogTextEditHandle(askdialog)[0]->teLength); /* Adjust the race popup menu */ i = j = currrace; do { if (validrace(currrole, j)) { EnableMenuItem(askmenu[RSRC_ASK_RACE], j + 1); CheckMenuItem(askmenu[RSRC_ASK_RACE], j + 1, currrace == j); } else { DisableMenuItem(askmenu[RSRC_ASK_RACE], j + 1); CheckMenuItem(askmenu[RSRC_ASK_RACE], j + 1, FALSE); if ((currrace == j) && !races[++currrace].noun) currrace = 0; } if (!races[++j].noun) j = 0; } while (i != j); if (currrace != i) { GetDialogItem(askdialog, RSRC_ASK_RACE, &type, &handle, &rect); InvalWindowRect(GetDialogWindow(askdialog), &rect); } /* Adjust the gender popup menu */ i = j = currgend; do { if (validgend(currrole, currrace, j)) { EnableMenuItem(askmenu[RSRC_ASK_GEND], j + 1); CheckMenuItem(askmenu[RSRC_ASK_GEND], j + 1, currgend == j); } else { DisableMenuItem(askmenu[RSRC_ASK_GEND], j + 1); CheckMenuItem(askmenu[RSRC_ASK_GEND], j + 1, FALSE); if ((currgend == j) && (++currgend >= ROLE_GENDERS)) currgend = 0; } if (++j >= ROLE_GENDERS) j = 0; } while (i != j); if (currgend != i) { GetDialogItem(askdialog, RSRC_ASK_GEND, &type, &handle, &rect); InvalWindowRect(GetDialogWindow(askdialog), &rect); } /* Adjust the alignment popup menu */ i = j = curralign; do { if (validalign(currrole, currrace, j)) { EnableMenuItem(askmenu[RSRC_ASK_ALIGN], j + 1); CheckMenuItem(askmenu[RSRC_ASK_ALIGN], j + 1, curralign == j); } else { DisableMenuItem(askmenu[RSRC_ASK_ALIGN], j + 1); CheckMenuItem(askmenu[RSRC_ASK_ALIGN], j + 1, FALSE); if ((curralign == j) && (++curralign >= ROLE_ALIGNS)) curralign = 0; } if (++j >= ROLE_ALIGNS) j = 0; } while (i != j); if (curralign != i) { GetDialogItem(askdialog, RSRC_ASK_ALIGN, &type, &handle, &rect); InvalWindowRect(GetDialogWindow(askdialog), &rect); } /* Adjust the role popup menu */ for (i = 0; roles[i].name.m; i++) { ask_restring((currgend && roles[i].name.f) ? roles[i].name.f : roles[i].name.m, str); SetMenuItemText(askmenu[RSRC_ASK_ROLE], i + 1, str); CheckMenuItem(askmenu[RSRC_ASK_ROLE], i + 1, currrole == i); } /* Adjust the mode popup menu */ CheckMenuItem(askmenu[RSRC_ASK_MODE], 1, currmode == 0); CheckMenuItem(askmenu[RSRC_ASK_MODE], 2, currmode == 1); CheckMenuItem(askmenu[RSRC_ASK_MODE], 3, currmode == 2); /* Wait for an action on an item */ ModalDialog(filter, &item); switch (item) { case RSRC_ASK_PLAY: break; case RSRC_ASK_QUIT: currmode = -1; break; case RSRC_ASK_ROLE: case RSRC_ASK_RACE: case RSRC_ASK_ALIGN: case RSRC_ASK_GEND: case RSRC_ASK_MODE: GetDialogItem(askdialog, item, &type, &handle, &rect); pt = *(Point *) ▭ LocalToGlobal(&pt); if (!!(i = PopUpMenuSelect(askmenu[item], pt.v, pt.h, askselect[item] + 1))) askselect[item] = LoWord(i) - 1; InvalWindowRect(GetDialogWindow(askdialog), &rect); break; case RSRC_ASK_NAME: #if 0 /* limit the data here to 25 chars */ { short beepTEDelete = 1; while ((**dRec.textH).teLength > 25) { if (beepTEDelete++ <= 3) SysBeep(3); TEKey('\b', dRec.textH); } } /* special case filter (that doesn't plug all the holes!) */ if (((**dRec.textH).teLength == 1) && (**((**dRec.textH).hText) < 32)) TEKey('\b', dRec.textH); #endif break; } } while ((item != RSRC_ASK_PLAY) && (item != RSRC_ASK_QUIT)); /* Process the name */ GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); GetDialogItemText(handle, str); if (str[0] > PL_NSIZ - 1) str[0] = PL_NSIZ - 1; BlockMove(&str[1], plname, str[0]); plname[str[0]] = '\0'; /* Destroy the dialog */ for (i = RSRC_ASK_ROLE; i <= RSRC_ASK_MODE; i++) { DeleteMenu(i); DisposeMenu(askmenu[i]); } SetPort(oldport); DisposeDialog(askdialog); DisposeModalFilterUPP(filter); DisposeUserItemUPP(redraw); /* Process the mode */ wizard = discover = 0; switch (currmode) { case 0: /* Normal */ break; case 1: /* Explore */ discover = 1; break; case 2: /* Debug */ wizard = 1; strcpy(plname, WIZARD_NAME); break; default: /* Quit */ ExitToShell(); } /* Process the role */ strcpy(pl_character, roles[currrole].name.m); flags.initrole = currrole; /* Process the race */ flags.initrace = currrace; /* Process the gender */ flags.female = flags.initgend = currgend; /* Process the alignment */ flags.initalign = curralign; return; } /*** Menu bar routines ***/ #if !TARGET_API_MAC_CARBON static void alignAD(Rect *pRct, short vExempt) { BitMap qbitmap; GetQDGlobalsScreenBits(&qbitmap); (*pRct).right -= (*pRct).left; /* width */ (*pRct).bottom -= (*pRct).top; /* height */ (*pRct).left = (qbitmap.bounds.right - (*pRct).right) / 2; (*pRct).top = (qbitmap.bounds.bottom - (*pRct).bottom - vExempt) / 2; (*pRct).top += vExempt; (*pRct).right += (*pRct).left; (*pRct).bottom += (*pRct).top; } #endif static void mustGetMenuAlerts() { short i; Rect **hRct; for (i = alrt_Menu_start; i < alrt_Menu_limit; i++) { if (!(hRct = (Rect **) GetResource('ALRT', i))) /* AlertTHndl */ { for (i = 0; i < beepMenuAlertErr; i++) SysBeep(3); ExitToShell(); } #if !TARGET_API_MAC_CARBON alignAD(*hRct, GetMBarHeight()); #endif } } static void menuError(short menuErr) { short i; for (i = 0; i < beepMenuAlertErr; i++) SysBeep(3); ParamText(menuErrStr[menuErr], "\p", "\p", "\p"); (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L); ExitToShell(); } void InitMenuRes() { static Boolean was_inited = 0; short i, j; menuListHandle mlHnd; MenuHandle menu; if (was_inited) return; was_inited = 1; mustGetMenuAlerts(); for (i = listMenubar; i <= listSubmenu; i++) { if (!(mlHnd = (menuListHandle) GetResource('MNU#', (menuBarListID + i)))) menuError(errGetMenuList); pMenuList[i] = (menuListPtr) NewPtr(GetHandleSize((Handle) mlHnd)); *pMenuList[i] = **mlHnd; for (j = 0; j < pMenuList[i]->numMenus; j++) { if (!(menu = (MenuHandle) GetMenu((**mlHnd).mref[j].mresID))) { Str31 d; NumToString((**mlHnd).mref[j].mresID, d); menuError(errGetMenu); } pMenuList[i]->mref[j].mhnd = menu; SetMenuID(menu, j + (**mlHnd).firstMenuID); /* consecutive IDs */ /* expand apple menu */ if ((i == listMenubar) && (j == menuApple)) { AppendResMenu(menu, 'DRVR'); } InsertMenu(menu, ((i == listSubmenu) ? hierMenu : 0)); } } DrawMenuBar(); return; } void AdjustMenus(short dimMenubar) { short newMenubar = mbarRegular; WindowRef win = FrontWindow(); short i; /* * if (windowprocs != mac_procs) { * return; * } */ /* determine the new menubar state */ if (dimMenubar) newMenubar = mbarDim; else if (!win) newMenubar = mbarNoWindows; else if (GetWindowKind(win) < 0) newMenubar = mbarDA; else if (!IsWindowVisible(_mt_window)) newMenubar = mbarNoMap; if (newMenubar != mbarRegular) ; /* we've already found its state */ else if (wizard) { newMenubar = mbarSpecial; if (kAdjustWizardMenu) { kAdjustWizardMenu = 0; SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pDebug"); } } else if (discover) { newMenubar = mbarSpecial; if (kAdjustWizardMenu) { kAdjustWizardMenu = 0; SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pExplore"); for (i = CountMenuItems(MHND_WIZ); i > menuWizardAttributes; i--) DeleteMenuItem(MHND_WIZ, i); } } /* adjust the menubar, if there's a state change */ if (theMenubar != newMenubar) { switch (theMenubar = newMenubar) { case mbarDim: /* disable all menus (except the apple menu) */ for (i = menuFile; i < NUM_MBAR; i++) DisableMenuItem(MBARHND(i), 0); break; case mbarNoWindows: case mbarDA: case mbarNoMap: /* enable the file menu, but ... */ EnableMenuItem(MHND_FILE, 0); /* ... disable the window commands! */ for (i = menuFileRedraw; i <= menuFileEnterExplore; i++) DisableMenuItem(MHND_FILE, i); /* ... and disable the rest of the menus */ for (i = menuEdit; i < NUM_MBAR; i++) DisableMenuItem(MBARHND(i), 0); if (theMenubar == mbarDA) EnableMenuItem(MHND_EDIT, 0); break; case mbarRegular: case mbarSpecial: /* enable all menus ... */ for (i = menuFile; i < NUM_MBAR; i++) EnableMenuItem(MBARHND(i), 0); /* ... except the unused Edit menu */ DisableMenuItem(MHND_EDIT, 0); /* ... enable the window commands */ for (i = menuFileRedraw; i <= menuFileEnterExplore; i++) EnableMenuItem(MHND_FILE, i); if (theMenubar == mbarRegular) DisableMenuItem(MHND_FILE, menuFilePlayMode); else DisableMenuItem(MHND_FILE, menuFileEnterExplore); break; } DrawMenuBar(); } } void DoMenuEvt(long menuEntry) { short menuID = HiWord(menuEntry); short menuItem = LoWord(menuEntry); switch (menuID - ID1_MBAR) /* all submenus are default case */ { case menuApple: if (menuItem == menuAppleAboutBox) aboutNetHack(); #if !TARGET_API_MAC_CARBON else { unsigned char daName[32]; GetMenuItemText(MHND_APPLE, menuItem, *(Str255 *) daName); (void) OpenDeskAcc(daName); } #endif break; /* * Those direct calls are ugly: they should be installed into cmd.c . * Those AddToKeyQueue() calls are also ugly: they should be put into * the 'STR#' resource. */ case menuFile: switch (menuItem) { case menuFileRedraw: AddToKeyQueue('R' & 0x1f, 1); break; case menuFilePrevMsg: AddToKeyQueue('P' & 0x1f, 1); break; case menuFileCleanup: (void) SanePositions(); break; case menuFileEnterExplore: AddToKeyQueue('X', 1); break; case menuFileSave: askSave(); break; case menuFileQuit: askQuit(); break; } break; case menuEdit: #if !TARGET_API_MAC_CARBON (void) SystemEdit(menuItem - 1); #endif break; default: /* get associated string and add to key queue */ { Str255 mstr; short i; GetIndString(mstr, menuID, menuItem); if (mstr[0] > QUEUE_LEN) mstr[0] = QUEUE_LEN; for (i = 1; ((i <= mstr[0]) && (mstr[i] != mstrEndChar)); i++) AddToKeyQueue(mstr[i], false); } break; } HiliteMenu(0); } static void aboutNetHack() { if (theMenubar >= mbarRegular) { (void) doversion(); /* is this necessary? */ } else { unsigned char aboutStr[32] = "\pNetHack 3.4."; if (PATCHLEVEL > 10) { aboutStr[++aboutStr[0]] = '0' + PATCHLEVEL / 10; } aboutStr[++aboutStr[0]] = '0' + (PATCHLEVEL % 10); ParamText(aboutStr, "\p\rdevteam@www.nethack.org", "\p", "\p"); (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L); ResetAlertStage(); } } static void askSave() { Boolean doSave = 1; Boolean doYes = 0; if (theMenubar < mbarRegular) { short itemHit; ParamText("\pReally Save?", "\p", "\p", "\p"); itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L); ResetAlertStage(); if (itemHit != bttnMenuAlertYes) { doSave = 0; } else { doYes = 1; } } if (doSave) { AddToKeyQueue('S', 1); if (doYes) { AddToKeyQueue('y', 1); } } } static void askQuit() { Boolean doQuit = 1; Boolean doYes = 0; Boolean winMac; char *quitinput; if (!strcmp(windowprocs.name, "mac")) winMac = 1; else winMac = 0; if (theMenubar < mbarRegular) { short itemHit; ParamText("\pReally Quit?", "\p", "\p", "\p"); itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L); ResetAlertStage(); if (itemHit != bttnMenuAlertYes) { doQuit = 0; } else { doYes = 1; } } if (doQuit) { /* MWM -- forgive me lord, an even uglier kludge to deal with differences in command input handling */ if (winMac) quitinput = "#quit\r"; else quitinput = "#q\r"; /* KMH -- Ugly kludge */ while (*quitinput) AddToKeyQueue(*quitinput++, 1); if (doYes) { if (winMac) quitinput = "y\rq\r\r\r"; else quitinput = "yq\r"; while (*quitinput) AddToKeyQueue(*quitinput++, 1); } } } nethack-3.6.0/sys/mac/macsnd.c0000664000076400007660000000543012536476415015143 0ustar paxedpaxed/* NetHack 3.6 macsnd.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) 1992 by Jon Watte */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains music playing code. * * If we were REALLY determinated, we would make the sound play * asynchronously, but I'll save that one for a rainy day... * * This may break A/UX, since it defines MAC but we need to * check that the toolbox is booted. I'll defer that one too. * * - h+ 921128 */ #include "hack.h" #include "mactty.h" #include "macwin.h" #if 1 /*!TARGET_API_MAC_CARBON*/ #include #include #endif #ifndef freqDurationCmd #define freqDurationCmd 40 #endif #define SND_BUFFER(s) (&(*s)[20]) #define SND_LEN(s) (GetHandleSize(s) - 42) void mac_speaker(struct obj *instr, char *melody) { SndChannelPtr theChannel = (SndChannelPtr) 0; SndCommand theCmd; Handle theSound; unsigned char theName[32]; char *n = (char *) &theName[1]; int typ = instr->otyp; const char *actualn = OBJ_NAME(objects[typ]); /* * First: are we in the library ? */ if (flags.silent) { return; } /* * Is this a known instrument ? */ strcpy(n, actualn); theName[0] = strlen(n); theSound = GetNamedResource('snd ', theName); if (!theSound) { return; } HLock(theSound); /* * Set up the synth */ if (SndNewChannel(&theChannel, sampledSynth, initMono + initNoInterp, (void *) 0) == noErr) { char midi_note[] = { 57, 59, 60, 62, 64, 65, 67 }; short err; short snd_len = SND_LEN(theSound) / 18; theCmd.cmd = soundCmd; theCmd.param1 = 0; theCmd.param2 = (long) SND_BUFFER(theSound); err = SndDoCommand(theChannel, &theCmd, false); /* * We rack 'em up all in a row * The mac will play them correctly and then end, since * we do a sync close below. * */ while (*melody && !err) { while (*melody > 'G') { *melody -= 8; } while (*melody < 'A') { *melody += 8; } theCmd.cmd = freqDurationCmd; theCmd.param1 = snd_len; theCmd.param2 = midi_note[*melody - 'A']; err = SndDoCommand(theChannel, &theCmd, false); melody++; } SndDisposeChannel(theChannel, false); /* Sync wait for completion */ ReleaseResource(theSound); } } void tty_nhbell(void) { Handle h = GetNamedResource('snd ', "\pNetHack Bell"); if (h) { HLock(h); SndPlay((SndChannelPtr) 0, (SndListHandle) h, 0); ReleaseResource(h); } else SysBeep(30); } nethack-3.6.0/sys/mac/mactopl.c0000664000076400007660000000316212536476415015335 0ustar paxedpaxed/* NetHack 3.6 mactopl.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mactty.h" #include "macwin.h" #include "macpopup.h" char queued_resp(char *resp) { char buf[30]; if (try_key_queue(buf)) { if (!resp || strchr(resp, buf[0])) return buf[0]; if (digit(buf[0]) && strchr(resp, '#')) { yn_number = atoi(buf); return '#'; } } return '\0'; } char topl_yn_function(const char *query, const char *resp, char def) { char buf[30]; char c = queued_resp((char *) resp); if (!c) { enter_topl_mode((char *) query); topl_set_resp((char *) resp, def); do { c = readchar(); if (c && resp && !strchr(resp, c)) { nhbell(); c = '\0'; } } while (!c); topl_set_resp("", '\0'); leave_topl_mode(buf); if (c == '#') yn_number = atoi(buf); } return c; } char mac_yn_function(query, resp, def) const char *query, *resp; char def; /* * Generic yes/no function. 'def' is the default (returned by space or * return; 'esc' returns 'q', or 'n', or the default, depending on * what's in the string. The 'query' string is printed before the user * is asked about the string. * If resp is NULL, any single character is accepted and returned. */ { return topl_yn_function(query, resp, def); } /* mactopl.c */ nethack-3.6.0/sys/mac/mactty.c0000664000076400007660000007435412610522241015170 0ustar paxedpaxed/* NetHack 3.6 mactty.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * mactty.c * * This file contains the actual code for the tty library. For a * description, see the file mactty.h, which contains all you * need to know to use the library. */ #include "hack.h" /* to get flags */ #include "mttypriv.h" #if !TARGET_API_MAC_CARBON #include #endif char game_active = 0; /* flag to window rendering routines not to use ppat */ /* these declarations are here because I can't include macwin.h without * including the world */ extern void dprintf(char *, ...); /* dprintf.c */ /* * Borrowed from the Mac tty port */ extern WindowPtr _mt_window; static void select_onscreen_window(tty_record *record); static void select_offscreen_port(tty_record *record); #define MEMORY_MARGIN 30000 /* * Convenience macro for most functions - put last in declaration */ #define RECORD_EXISTS(record) \ tty_record *record; \ if (!window || !(record = (tty_record *) GetWRefCon(window))) \ return general_failure; /* * Simple macro for deciding whether we draw at once or delay */ #define DRAW_DIRECT (TA_ALWAYS_REFRESH & record->attribute[TTY_ATTRIB_FLAGS]) /* * Table of special characters. Zero is ALWAYS special; it means * end of string and would be MISSED if it was not included here. */ #define COOKED_CONTROLS 0X00002581 #define RAW_CONTROLS 1 static unsigned long s_control = COOKED_CONTROLS; /* * Memory-related error */ static short mem_err(void) { short ret_val = MemError(); if (!ret_val) { ret_val = general_failure; } return ret_val; } /* * Make a rectangle empty */ static void empty_rect(Rect *r) { r->right = -20000; r->left = 20000; r->top = 20000; r->bottom = -20000; } /* * Union twp rect together */ static void union_rect(Rect *r1, Rect *r2, Rect *dest) { dest->left = min(r1->left, r2->left); dest->top = min(r1->top, r2->top); dest->bottom = max(r1->bottom, r2->bottom); dest->right = max(r1->right, r2->right); } /* * Dispose a pointer using the set memory-allocator */ static short dispose_ptr(void *ptr) { if (!ptr) { return noErr; /* Silently accept disposing nulls */ } DisposePtr(ptr); return MemError(); } #if 0 /* Use alloc.c instead */ /* * Allocate a pointer using the set memory-allocator */ static short alloc_ptr (void **ptr, long size) { *ptr = NewPtr (size); return MemError (); } #endif /* * Set up a GWorld in the record */ static short allocate_offscreen_world(tty_record *record) { GWorldPtr gw = (GWorldPtr) 0; GWorldFlags world_flags = 0; long mem_here, mem_there, other, required_mem; Point p = { 0, 0 }; Rect r_screen; GDHandle gdh; short s_err; select_onscreen_window(record); LocalToGlobal(&p); r_screen = record->its_bits.bounds; OffsetRect(&r_screen, p.h, p.v); gdh = GetMaxDevice(&r_screen); required_mem = (long) (*((*gdh)->gdPMap))->pixelSize * ((long) record->its_bits.bounds.right * record->its_bits.bounds.bottom) >> 3; PurgeSpace(&other, &mem_here); if (other < mem_here + MEMORY_MARGIN) { mem_here = other - MEMORY_MARGIN; } dprintf("Heap %ld Required %ld", mem_here, required_mem); if (required_mem > mem_here) { mem_there = required_mem; if (required_mem > TempMaxMem(&mem_there)) { dprintf("No memory"); return memFullErr; } world_flags |= useTempMem; } s_err = NewGWorld(&gw, 0, &r_screen, (CTabHandle) 0, (GDHandle) 0, world_flags); if (!s_err) { record->offscreen_world = gw; select_offscreen_port(record); SetOrigin(0, 0); select_onscreen_window(record); dprintf("New GWorld @ %lx;dm", gw); } return s_err; } /* * Done with GWorld, release data */ static short deallocate_gworld(tty_record *record) { if (record->offscreen_world) { DisposeGWorld(record->offscreen_world); record->offscreen_world = (GWorldPtr) 0; } return noErr; } /* * Get rid of offscreen bitmap */ static short free_bits(tty_record *record) { short s_err; if (record->uses_gworld) { s_err = deallocate_gworld(record); #if !TARGET_API_MAC_CARBON } else { s_err = dispose_ptr(record->its_bits.baseAddr); if (!s_err) { record->its_bits.baseAddr = (char *) 0; if (record->offscreen_port) { ClosePort(record->offscreen_port); s_err = dispose_ptr(record->offscreen_port); if (!s_err) { record->offscreen_port = (GrafPtr) 0; } } } #endif } return s_err; } /* * Snatch a window from the resource fork. Create the record. * Otherwise, do nothing. */ short create_tty(WindowRef *window, short resource_id, Boolean in_color) { tty_record *record; Boolean was_allocated = !!*window; if (in_color) { *window = GetNewCWindow(resource_id, (Ptr) *window, (WindowRef) -1L); } else { *window = GetNewWindow(resource_id, (Ptr) *window, (WindowRef) -1L); } if (!*window) { return mem_err(); } record = (tty_record *) NewPtrClear(sizeof(tty_record)); if (!record) { #if !TARGET_API_MAC_CARBON if (was_allocated) { CloseWindow(*window); } else { #endif DisposeWindow(*window); #if !TARGET_API_MAC_CARBON } #endif return mem_err(); } record->its_window = *window; SetWRefCon(*window, (long) record); record->was_allocated = was_allocated; record->its_bits.baseAddr = (char *) 0; record->curs_state = TRUE; /* * We need to keep the window world around if we switch worlds */ record->offscreen_world = (GWorldPtr) 0; record->uses_gworld = in_color; if (in_color) { GDHandle gh; SetPortWindowPort(*window); GetGWorld(&(record->its_window_world), &gh); } else { record->its_window_world = (GWorldPtr) 0; } #if CLIP_RECT_ONLY empty_rect(&(record->invalid_rect)); #else record->invalid_part = NewRgn(); if (!record->invalid_part) { return destroy_tty(*window); } #endif return noErr; } short init_tty_number(WindowPtr window, short font_number, short font_size, short x_size, short y_size) { RECORD_EXISTS(record); record->font_number = font_number; record->font_size = font_size; record->x_size = x_size; record->y_size = y_size; return force_tty_coordinate_system_recalc(window); } /* * Done with a window - destroy it. Release the memory only if * it wasn't allocated when we got it! */ short destroy_tty(WindowPtr window) { short s_err; RECORD_EXISTS(record); s_err = free_bits(record); if (!s_err) { #if !TARGET_API_MAC_CARBON if (record->was_allocated) { CloseWindow(window); } else { #endif DisposeWindow(window); #if !TARGET_API_MAC_CARBON } #endif s_err = dispose_ptr(record); } return s_err; } static void do_set_port_font(tty_record *record) { PenNormal(); TextFont(record->font_number); TextSize(record->font_size); if (0L != (record->attribute[TTY_ATTRIB_FLAGS] & TA_OVERSTRIKE)) { TextMode(srcOr); } else { TextMode(srcCopy); } } /* * Fill in some fields from some other fields that may have changed */ static void calc_font_sizes(tty_record *record) { FontInfo font_info; do_set_port_font(record); GetFontInfo(&font_info); record->char_width = font_info.widMax; record->ascent_height = font_info.ascent + font_info.leading; record->row_height = record->ascent_height + font_info.descent; } /* * Allocate memory for the bitmap holding the tty window */ static short alloc_bits(tty_record *record) { short s_err; SetRect(&record->its_bits.bounds, 0, 0, record->char_width * record->x_size, record->row_height * record->y_size); /* * Clear two highest and lowest bit - not a color pixMap, and even in size */ record->its_bits.rowBytes = ((record->its_bits.bounds.right + 15) >> 3) & 0x1ffe; if (record->uses_gworld) { s_err = allocate_offscreen_world(record); #if !TARGET_API_MAC_CARBON } else { s_err = alloc_ptr((void **) &(record->its_bits.baseAddr), record->its_bits.rowBytes * record->its_bits.bounds.bottom); if (!s_err) { s_err = alloc_ptr((void **) &(record->offscreen_port), sizeof(GrafPort)); } if (!s_err) { OpenPort(record->offscreen_port); SetPort(record->offscreen_port); ClipRect(&(record->its_bits.bounds)); SetPortBits(&(record->its_bits)); } #endif } return s_err; } /* * Save the current port/world in a safe place for later retrieval */ static void save_port(tty_record *record, void *save) { GWorldPtr gw; GDHandle gh; GrafPtr gp; if (record->uses_gworld) { GetGWorld(&gw, &gh); *(GWorldPtr *) save = gw; } else { GetPort(&gp); *(GrafPtr *) save = gp; } } /* * Restore current port/world after a save */ static void use_port(tty_record *record, void *port) { if (record->uses_gworld) { PixMapHandle pix_map; SetGWorld((GWorldPtr) port, (GDHandle) 0); pix_map = GetGWorldPixMap(record->offscreen_world); if (pix_map) { if (port == record->offscreen_world) LockPixels(pix_map); else UnlockPixels(pix_map); } } else { SetPort((GrafPtr) port); } } /* * Use offscreen drawing - lock the pixels through use_port */ static void select_offscreen_port(tty_record *record) { if (record->uses_gworld) { use_port(record, record->offscreen_world); } else { use_port(record, record->offscreen_port); } } /* * Use the window - unlock pixels */ static void select_onscreen_window(tty_record *record) { if (record->uses_gworld) { use_port(record, record->its_window_world); SetPortWindowPort(record->its_window); } else { use_port(record, record->its_window); } } /* * Do bits copy depending on if we're using color or not */ static void copy_bits(tty_record *record, Rect *bounds, short xfer_mode, RgnHandle mask_rgn) { GWorldFlags pix_state; BitMap *source; if (record->uses_gworld) { pix_state = GetPixelsState(GetGWorldPixMap(record->offscreen_world)); LockPixels(GetGWorldPixMap(record->offscreen_world)); source = (BitMapPtr) *GetGWorldPixMap(record->offscreen_world); } else source = &record->its_bits; SetPortWindowPort(record->its_window); CopyBits(source, GetPortBitMapForCopyBits(GetWindowPort(record->its_window)), bounds, bounds, xfer_mode, mask_rgn); if (record->uses_gworld) { SetPixelsState(GetGWorldPixMap(record->offscreen_world), pix_state); } } /* * Fill an area with the background color */ static void erase_rect(tty_record *record, Rect *area) { if (game_active && u.uhp > 0 && iflags.use_stone && record->its_window == _mt_window) { PixPatHandle ppat; ppat = GetPixPat(iflags.use_stone + 127); /* find which pat to get */ if (ppat) { /* in game window, using backgroung pattern, and have pattern */ FillCRect(area, ppat); DisposePixPat(ppat); return; } } EraseRect(area); } /* * Recalculate the window based on new size, font, extent values, * and re-allocate the bitmap. */ short force_tty_coordinate_system_recalc(WindowPtr window) { short s_err; RECORD_EXISTS(record); s_err = free_bits(record); if (s_err) { return s_err; } calc_font_sizes(record); s_err = alloc_bits(record); if (s_err) { /* * Catastrophe! We could not allocate memory for the bitmap! Things * may go very * much downhill from here! */ dprintf("alloc_bits returned null in " "force_tty_coordinate_system_recalc!"); return s_err; } select_offscreen_port(record); do_set_port_font(record); return clear_tty(window); } #if 0 /* * Update TTY according to new color environment for the window */ static short tty_environment_changed (tty_record *record) { Point p = {0, 0}; Rect r_screen; if (record->uses_gworld) { r_screen = record->its_bits.bounds; LocalToGlobal (&p); OffsetRect (&r_screen, p.h, p.v); UpdateGWorld (&(record->offscreen_world), 0, &r_screen, (CTabHandle) 0, (GDHandle) 0, stretchPix); select_offscreen_port (record); SetOrigin (0, 0); select_onscreen_window (record); } return 0; } #endif /* * Read a lot of interesting and useful information from the current tty */ short get_tty_metrics(WindowPtr window, short *x_size, short *y_size, short *x_size_pixels, short *y_size_pixels, short *font_number, short *font_size, short *char_width, short *row_height) { RECORD_EXISTS(record); /* * First, test that we actually have something to draw to... */ if ((((char *) 0 == record->its_bits.baseAddr) && !record->uses_gworld) || (((GWorldPtr) 0 == record->offscreen_world) && record->uses_gworld)) { return general_failure; } *x_size = record->x_size; *y_size = record->y_size; *x_size_pixels = record->its_bits.bounds.right; *y_size_pixels = record->its_bits.bounds.bottom; *font_number = record->font_number; *font_size = record->font_size; *char_width = record->char_width; *row_height = record->row_height; return noErr; } /* * Map a position on the map to screen coordinates */ static void pos_rect(tty_record *record, Rect *r, short x_pos, short y_pos, short x_end, short y_end) { SetRect(r, x_pos * (record->char_width), y_pos * (record->row_height), (1 + x_end) * (record->char_width), (1 + y_end) * (record->row_height)); } static void accumulate_rect(tty_record *record, Rect *rect) { #if CLIP_RECT_ONLY union_rect(rect, &(record->invalid_rect), &(record->invalid_rect)); #else RgnHandle rh = NewRgn(); RectRgn(rh, rect); UnionRgn(record->invalid_part, rh, record->invalid_part); DisposeRgn(rh); #endif } /* * get and set window invalid region. exposed for HandleUpdateEvent in * macwin.c * to correct display problem */ short get_invalid_region(WindowPtr window, Rect *inval_rect) { RECORD_EXISTS(record); #if CLIP_RECT_ONLY if (record->invalid_rect.right <= record->invalid_rect.left || record->invalid_rect.bottom <= record->invalid_rect.top) { return general_failure; } *inval_rect = record->invalid_rect; #else if (EmptyRgn(record->invalid_part)) { return general_failure; } *inval_rect = (*(record->invalid_part))->rgnBBox; #endif return noErr; } short set_invalid_region(WindowPtr window, Rect *inval_rect) { RECORD_EXISTS(record); accumulate_rect(record, inval_rect); return noErr; } /* * Invert the specified position */ static void curs_pos(tty_record *record, short x_pos, short y_pos, short to_state) { Rect r; if (record->curs_state == to_state) { return; } record->curs_state = to_state; pos_rect(record, &r, x_pos, y_pos, x_pos, y_pos); if (DRAW_DIRECT) { void *old_port; save_port(record, &old_port); select_onscreen_window(record); InvertRect(&r); use_port(record, old_port); } else { accumulate_rect(record, &r); } } /* * Move the cursor (both as displayed and where drawing goes) * HOWEVER: The cursor is NOT stored in the bitmap! */ short move_tty_cursor(WindowPtr window, short x_pos, short y_pos) { RECORD_EXISTS(record); if (record->x_curs == x_pos && record->y_curs == y_pos) { return noErr; } if (record->x_size <= x_pos || x_pos < 0 || record->y_size <= y_pos || y_pos < 0) { return general_failure; } curs_pos(record, record->x_curs, record->y_curs, 0); record->x_curs = x_pos; record->y_curs = y_pos; curs_pos(record, x_pos, y_pos, 1); return noErr; } /* * Update the screen to match the current bitmap, after adding stuff * with add_tty_char etc. */ short update_tty(WindowPtr window) { Rect r; RECORD_EXISTS(record); #if CLIP_RECT_ONLY if (record->invalid_rect.right <= record->invalid_rect.left || record->invalid_rect.bottom <= record->invalid_rect.top) { return noErr; } r = record->invalid_rect; #else if (EmptyRgn(record->invalid_part)) { return noErr; } r = (*(record->invalid_part))->rgnBBox; #endif select_onscreen_window(record); copy_bits(record, &r, srcCopy, (RgnHandle) 0); #if CLIP_RECT_ONLY empty_rect(&(record->invalid_rect)); #else SetEmptyRgn(record->invalid_part); #endif if (record->curs_state) { pos_rect(record, &r, record->x_curs, record->y_curs, record->x_curs, record->y_curs); InvertRect(&r); } return noErr; } /* * Low level add to screen */ static void do_add_string(tty_record *record, char *str, short len) { Rect r; if (len < 1) { return; } select_offscreen_port(record); MoveTo(record->x_curs * record->char_width, record->y_curs * record->row_height + record->ascent_height); DrawText(str, 0, len); pos_rect(record, &r, record->x_curs, record->y_curs, record->x_curs + len - 1, record->y_curs); select_onscreen_window(record); if (DRAW_DIRECT) { copy_bits(record, &r, srcCopy, (RgnHandle) 0); } else { accumulate_rect(record, &r); } } /* * Low-level cursor handling routine */ static void do_add_cursor(tty_record *record, short x_pos) { record->x_curs = x_pos; if (record->x_curs >= record->x_size) { if (0L != (record->attribute[TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND)) { record->y_curs++; record->x_curs = 0; if (record->y_curs >= record->y_size) { if (0L != (record->attribute[TTY_ATTRIB_FLAGS] & TA_INHIBIT_VERT_SCROLL)) { record->y_curs = record->y_size; } else { scroll_tty(record->its_window, 0, 1 + record->y_curs - record->y_size); } } } else { record->x_curs = record->x_size; } } } /* * Do control character */ static void do_control(tty_record *record, short character) { int recurse = 0; /* * Check recursion because nl_add_cr and cr_add_nl may both be set and * invoke each other */ do { switch (character) { case CHAR_CR: record->x_curs = 0; if (!recurse && (record->attribute[TTY_ATTRIB_CURSOR] & TA_CR_ADD_NL)) { recurse = 1; } else { recurse = 0; break; } /* FALL-THROUGH: if CR-LF, don't bother with loop */ case CHAR_LF: record->y_curs++; if (record->y_curs >= record->y_size) { scroll_tty(record->its_window, 0, 1 + record->y_curs - record->y_size); } if (!recurse && (record->attribute[TTY_ATTRIB_CURSOR] & TA_NL_ADD_CR)) { character = CHAR_CR; recurse = 1; } else recurse = 0; break; case CHAR_BELL: tty_nhbell(); break; case CHAR_BS: if (record->x_curs > 0) record->x_curs--; default: break; } } while (recurse); } /* * Add a single character. It is drawn directly if the correct flag is set, * else deferred to the next update event or call of update_tty() */ short add_tty_char(WindowPtr window, short character) { register char is_control; char ch; RECORD_EXISTS(record); if (!(record->attribute[TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND) && record->x_curs >= record->x_size) return noErr; /* Optimize away drawing across border without wrap */ if (record->curs_state != 0) curs_pos(record, record->x_curs, record->y_curs, 0); ch = character; is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L); if (is_control) do_control(record, ch); else { do_add_string(record, (char *) &ch, 1); do_add_cursor(record, record->x_curs + 1); } return noErr; } /* * Add a null-terminated string of characters */ short add_tty_string(WindowPtr window, const char *string) { register const unsigned char *start_c; register const unsigned char *the_c; register unsigned char ch, is_control = 0, tty_wrap; register short max_x, pos_x; RECORD_EXISTS(record); if (record->curs_state != 0) curs_pos(record, record->x_curs, record->y_curs, 0); the_c = (const unsigned char *) string; max_x = record->x_size; tty_wrap = (record->attribute[TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND); for (;;) { pos_x = record->x_curs; if (!tty_wrap && pos_x >= max_x) break; /* Optimize away drawing across border without wrap */ start_c = the_c; ch = *the_c; while (pos_x < max_x) { is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L); if (is_control) break; the_c++; ch = *the_c; pos_x++; } do_add_string(record, (char *) start_c, the_c - start_c); do_add_cursor(record, pos_x); if (!ch) break; if (is_control) { do_control(record, ch); the_c++; } } return noErr; } /* * Read or change attributes for the tty. Note that some attribs may * very well clear and reallocate the bitmap when changed, whereas * others (color, highlight, ...) are guaranteed not to. */ short get_tty_attrib(WindowPtr window, tty_attrib attrib, long *value) { RECORD_EXISTS(record); if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) { return general_failure; } *value = record->attribute[attrib]; return noErr; } short set_tty_attrib(WindowPtr window, tty_attrib attrib, long value) { RGBColor rgb_color; RECORD_EXISTS(record); if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) { return general_failure; } record->attribute[attrib] = value; /* * Presently, no attributes generate a new bitmap. */ switch (attrib) { case TTY_ATTRIB_CURSOR: /* * Check if we should change tables */ if (0L != (value & TA_RAW_OUTPUT)) { s_control = RAW_CONTROLS; } else { s_control = COOKED_CONTROLS; } break; case TTY_ATTRIB_FLAGS: /* * Check if we should flush the output going from cached to * draw-direct */ if (0L != (value & TA_ALWAYS_REFRESH)) { update_tty(window); } break; case TTY_ATTRIB_FOREGROUND: /* * Set foreground color */ TA_TO_RGB(value, rgb_color); select_offscreen_port(record); RGBForeColor(&rgb_color); select_onscreen_window(record); break; case TTY_ATTRIB_BACKGROUND: /* * Set background color */ TA_TO_RGB(value, rgb_color); select_offscreen_port(record); RGBBackColor(&rgb_color); select_onscreen_window(record); break; default: break; } return noErr; } /* * Scroll the window. Positive is up/left. scroll_tty ( window, 0, 1 ) is a * line feed. * Scroll flushes the accumulated update area by calling update_tty(). */ short scroll_tty(WindowPtr window, short delta_x, short delta_y) { RgnHandle rgn; short s_err; RECORD_EXISTS(record); s_err = update_tty(window); rgn = NewRgn(); select_offscreen_port(record); ScrollRect(&(record->its_bits.bounds), -delta_x * record->char_width, -delta_y * record->row_height, rgn); EraseRgn(rgn); SetEmptyRgn(rgn); select_onscreen_window(record); ScrollRect(&(record->its_bits.bounds), -delta_x * record->char_width, -delta_y * record->row_height, rgn); EraseRgn(rgn); DisposeRgn(rgn); record->y_curs -= delta_y; record->x_curs -= delta_x; return noErr; } /* * Clear the screen. Immediate. */ short clear_tty(WindowPtr window) { RECORD_EXISTS(record); record->curs_state = 0; select_offscreen_port(record); erase_rect(record, &(record->its_bits.bounds)); accumulate_rect(record, &(record->its_bits.bounds)); update_tty(window); return noErr; } /* * Blink cursor on window if necessary */ short blink_cursor(WindowPtr window, long when) { RECORD_EXISTS(record); if ((record->attribute[TTY_ATTRIB_CURSOR] & TA_BLINKING_CURSOR)) { if (when > record->last_cursor + GetCaretTime()) { curs_pos(record, record->x_curs, record->y_curs, !record->curs_state); record->last_cursor = when; update_tty(window); } } return 0; } /* * Draw an image of the tty - used for update events and can be called * for screen dumps. */ short image_tty(EventRecord *theEvent, WindowPtr window) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theEvent) #endif RECORD_EXISTS(record); #if CLIP_RECT_ONLY record->invalid_rect = record->its_bits.bounds; #else RgnHandle rh = NewRgn(); RectRgn(rh, record->its_bits.bounds); UnionRgn(record->invalid_part, rh, record->invalid_part); DisposeRgn(rh); #endif return update_tty(window); } /* * Clear an area */ short clear_tty_window(WindowPtr window, short from_x, short from_y, short to_x, short to_y) { Rect r; RECORD_EXISTS(record); if (from_x > to_x || from_y > to_y) { return general_failure; } pos_rect(record, &r, from_x, from_y, to_x, to_y); select_offscreen_port(record); erase_rect(record, &r); accumulate_rect(record, &r); if (DRAW_DIRECT) { update_tty(window); } else select_onscreen_window(record); return noErr; } #if EXTENDED_SUPPORT /* * Delete or insert operations used by many terminals can bottleneck through * here. Note that the order of executin for row/colum insertions is NOT * specified. Negative values for num_ mean delete, zero means no effect. */ short mangle_tty_rows_columns(WindowPtr window, short from_row, short num_rows, short from_column, short num_columns) { Rect r; RgnHandle rh = NewRgn(); RECORD_EXISTS(record); update_tty(window); /* Always make sure screen is OK */ curs_pos(record, record->x_curs, record->y_curs, 0); if (num_rows) { pos_rect(record, &r, 0, from_row, record->x_size - 1, record->y_size - 1); select_offscreen_port(record); ScrollRect(&r, 0, num_rows * record->row_height, rh); EraseRgn(rh); SetEmptyRgn(rh); select_onscreen_window(record); ScrollRect(&r, 0, num_rows * record->row_height, rh); EraseRgn(rh); SetEmptyRgn(rh); } if (num_columns) { pos_rect(record, &r, from_column, 0, record->x_size - 1, record->y_size - 1); select_offscreen_port(record); ScrollRect(&r, num_columns * record->char_width, 0, rh); EraseRgn(rh); SetEmptyRgn(rh); select_onscreen_window(record); ScrollRect(&r, num_columns * record->char_width, 0, rh); EraseRgn(rh); SetEmptyRgn(rh); } DisposeRgn(rh); if (record->x_curs >= from_column) { record->x_curs += num_columns; } if (record->y_curs >= from_row) { record->y_curs += num_rows; } curs_pos(record, record->x_curs, record->y_curs, 1); return noErr; } /* * Frame an area in an aesthetically pleasing way. */ short frame_tty_window(WindowPtr window, short from_x, short from_y, short to_x, short to_y, short frame_fatness) { Rect r; RECORD_EXISTS(record); if (from_x > to_x || from_y > to_y) { return general_failure; } pos_rect(record, &r, from_x, from_y, to_x, to_y); select_offscreen_port(record); PenSize(frame_fatness, frame_fatness); FrameRect(&r); PenNormal(); accumulate_rect(record, &r); if (DRAW_DIRECT) { update_tty(window); } else select_onscreen_window(record); } /* * Highlighting a specific part of the tty window */ short invert_tty_window(WindowPtr window, short from_x, short from_y, short to_x, short to_y) { Rect r; RECORD_EXISTS(record); if (from_x > to_x || from_y > to_y) { return general_failure; } pos_rect(record, &r, from_x, from_y, to_x, to_y); select_offscreen_port(record); InvertRect(&r); accumulate_rect(record, &r); if (DRAW_DIRECT) { update_tty(window); } else select_onscreen_window(record); } static void canonical_rect(Rect *r, short x1, short y1, short x2, short y2) { if (x1 < x2) { if (y1 < y2) { SetRect(r, x1, x2, y1, y2); } else { SetRect(r, x1, x2, y2, y1); } } else { if (y1 < y2) { SetRect(r, x2, x1, y1, y2); } else { SetRect(r, x2, x1, y2, y1); } } } /* * Line drawing - very device dependent */ short draw_tty_line(WindowPtr window, short from_x, short from_y, short to_x, short to_y) { Rect r; RECORD_EXISTS(record); select_offscreen_port(record); MoveTo(from_x, from_y); LineTo(to_x, to_y); canonical_rect(&r, from_x, from_y, to_x, to_y); accumulate_rect(record, &r); if (DRAW_DIRECT) { update_tty(window); } else select_onscreen_window(record); } #endif /* EXTENDED_SUPPORT */ nethack-3.6.0/sys/mac/macunix.c0000664000076400007660000000173412536476415015345 0ustar paxedpaxed/* NetHack 3.6 macunix.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file collects some Unix dependencies */ #include "hack.h" void regularize(char *s) { register char *lp; for (lp = s; *lp; lp++) { if (*lp == '.' || *lp == ':') *lp = '_'; } } void getlock(void) { int fd; int pid = getpid(); /* Process ID */ Sprintf(lock, "%d%s", getuid(), plname); set_levelfile_name(lock, 0); if ((fd = open(lock, O_RDWR | O_EXCL | O_CREAT, LEVL_TYPE)) == -1) { raw_printf("Could not lock the game %s.", lock); panic("Another game in progress?"); } if (write(fd, (char *) &pid, sizeof(pid)) != sizeof(pid)) { raw_printf("Could not lock the game %s.", lock); panic("Disk locked?"); } close(fd); } nethack-3.6.0/sys/mac/macwin.c0000664000076400007660000025721712536476415015170 0ustar paxedpaxed/* NetHack 3.6 macwin.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ /********************************************************************** * Imported variables and functions */ #include "hack.h" #include "func_tab.h" #include "macwin.h" #include "mactty.h" #include "wintty.h" #if 1 /*!TARGET_API_MAC_CARBON*/ #include #include #include #include #include #include #endif /********************************************************************** * Local variables and functions */ #if 0 // TARGET_API_MAC_CARBON static EventTypeSpec baseevents[] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassMouse, kEventMouseMoved }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowHandleContentClick }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec msgevents[] = { { kEventClassControl, kEventControlHit }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowHandleContentClick }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec menwevents[] = { { kEventClassControl, kEventControlHit }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowHandleContentClick }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec textevents[] = { { kEventClassControl, kEventControlHit }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat }, { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowClose } }; static EventTypeSpec globalevents[] = { { kEventClassCommand, kEventCommandProcess } }; EventTargetRef dispatcher; EventHandlerUPP baseupp, msgupp, menwupp, textupp; static pascal OSStatus BaseEvent(EventHandlerCallRef, EventRef, void *); static void MsgUpdate(NhWindow *wind); static pascal OSStatus MsgEvent(EventHandlerCallRef, EventRef, void *); static void MenwUpdate(NhWindow *wind); static pascal OSStatus MenwEvent(EventHandlerCallRef, EventRef, void *); static void TextUpdate(NhWindow *wind); static pascal OSStatus TextEvent(EventHandlerCallRef, EventRef, void *); static pascal OSStatus GlobalEvent(EventHandlerCallRef, EventRef, void *); #else static void FDECL(GeneralKey, (EventRecord *, WindowPtr)); static void FDECL(macKeyMenu, (EventRecord *, WindowPtr)); static void FDECL(macKeyText, (EventRecord *, WindowPtr)); static void FDECL(macClickMessage, (EventRecord *, WindowPtr)); static void FDECL(macClickTerm, (EventRecord *, WindowPtr)); static void FDECL(macClickMenu, (EventRecord *, WindowPtr)); static void FDECL(macClickText, (EventRecord *, WindowPtr)); static short FDECL(macDoNull, (EventRecord *, WindowPtr)); static short FDECL(macUpdateMessage, (EventRecord *, WindowPtr)); static short FDECL(macUpdateMenu, (EventRecord *, WindowPtr)); static short FDECL(GeneralUpdate, (EventRecord *, WindowPtr)); static void FDECL(macCursorTerm, (EventRecord *, WindowPtr, RgnHandle)); static void FDECL(GeneralCursor, (EventRecord *, WindowPtr, RgnHandle)); #endif static void TextUpdate(NhWindow *wind); NhWindow *theWindows = (NhWindow *) 0; Cursor qdarrow; /* Borrowed from the Mac tty port */ extern WindowPtr _mt_window; /* Some useful #defines for the scroll bar width and height */ #define SBARWIDTH 15 #define SBARHEIGHT 15 /* * We put a TE on the message window for the "top line" queries. * top_line is the TE that holds both the query and the user's * response. The first topl_query_len characters in top_line are * the query, the rests are the response. topl_resp is the valid * response to a yn query, while topl_resp[topl_def_idx] is the * default response to a yn query. */ static TEHandle top_line = (TEHandle) nil; static int topl_query_len; static int topl_def_idx = -1; static char topl_resp[10] = ""; #define CHAR_ANY '\n' /* * inSelect means we have a menu window up for selection or * something similar. It makes the window with win number == * inSelect a movable modal (unfortunately without the border) * and clicking the close box forces an RET into the key * buffer. Don't forget to set inSelect to WIN_ERR when you're * done... */ static winid inSelect = WIN_ERR; /* * The key queue ring buffer where Read is where to take from, * Write is where next char goes and count is queue depth. */ static unsigned char keyQueue[QUEUE_LEN]; static int keyQueueRead = 0, keyQueueWrite = 0, keyQueueCount = 0; static Boolean gClickedToMove = 0; /* For ObscureCursor */ static Point clicked_pos; /* For nh_poskey */ static int clicked_mod; static Boolean cursor_locked = false; static ControlActionUPP MoveScrollUPP; /* scrolling callback, init'ed in InitMac */ void lock_mouse_cursor(Boolean new_cursor_locked) { cursor_locked = new_cursor_locked; } /* * Add key to input queue, force means flush left and replace if full */ void AddToKeyQueue(unsigned char ch, Boolean force) { if (keyQueueCount < QUEUE_LEN) { keyQueue[keyQueueWrite++] = ch; keyQueueCount++; } else if (force) { keyQueue[keyQueueWrite++] = ch; keyQueueRead++; if (keyQueueRead >= QUEUE_LEN) keyQueueRead = 0; keyQueueCount = QUEUE_LEN; } if (keyQueueWrite >= QUEUE_LEN) keyQueueWrite = 0; } /* * Get key from queue */ unsigned char GetFromKeyQueue(void) { unsigned char ret; if (keyQueueCount) { ret = keyQueue[keyQueueRead++]; keyQueueCount--; if (keyQueueRead >= QUEUE_LEN) keyQueueRead = 0; } else ret = 0; return ret; } /* * Cursor movement */ static RgnHandle gMouseRgn = (RgnHandle) 0; /* * _Gestalt madness - we rely heavily on the _Gestalt glue, since we * don't check for the trap... */ MacFlags macFlags; /* * The screen layouts on the small 512x342 screen need special cares. */ Boolean small_screen = 0; #ifdef NHW_BASE #undef NHW_BASE #endif #define NHW_BASE 0 static int FDECL(filter_scroll_key, (const int, NhWindow *)); #if 1 //!TARGET_API_MAC_CARBON static void FDECL(DoScrollBar, (Point, short, ControlHandle, NhWindow *)); #endif static pascal void FDECL(MoveScrollBar, (ControlHandle, short)); #if 1 //!TARGET_API_MAC_CARBON typedef void (*CbFunc)(EventRecord *, WindowPtr); typedef short (*CbUpFunc)(EventRecord *, WindowPtr); typedef void (*CbCursFunc)(EventRecord *, WindowPtr, RgnHandle); #define NUM_FUNCS 6 static const CbFunc winKeyFuncs[NUM_FUNCS] = { GeneralKey, GeneralKey, GeneralKey, GeneralKey, macKeyMenu, macKeyText }; static const CbFunc winClickFuncs[NUM_FUNCS] = { (CbFunc) macDoNull, macClickMessage, macClickTerm, macClickTerm, macClickMenu, macClickText }; static const CbUpFunc winUpdateFuncs[NUM_FUNCS] = { macDoNull, macUpdateMessage, image_tty, image_tty, macUpdateMenu, GeneralUpdate }; static const CbCursFunc winCursorFuncs[NUM_FUNCS] = { (CbCursFunc) macDoNull, GeneralCursor, macCursorTerm, macCursorTerm, GeneralCursor, GeneralCursor }; #endif static NhWindow * GetNhWin(WindowPtr mac_win) { if (mac_win == _mt_window) /* term window is still maintained by both systems, and */ return theWindows; /* WRefCon still refers to tty struct, so we have to map it */ else { NhWindow *aWin = (NhWindow *) GetWRefCon(mac_win); if (aWin >= theWindows && aWin < &theWindows[NUM_MACWINDOWS]) return aWin; } return ((NhWindow *) nil); } Boolean CheckNhWin(WindowPtr mac_win) { return GetNhWin(mac_win) != nil; } static pascal OSErr AppleEventHandler(const AppleEvent *inAppleEvent, AppleEvent *outAEReply, long inRefCon) { #if defined(__SC__) || defined(__MRC__) #pragma unused(outAEReply, inRefCon) #endif Size actualSize; DescType typeCode; AEEventID EventID; OSErr err; /* Get Event ID */ err = AEGetAttributePtr(inAppleEvent, keyEventIDAttr, typeType, &typeCode, &EventID, sizeof(EventID), &actualSize); if (err == noErr) { switch (EventID) { default: case kAEOpenApplication: macFlags.gotOpen = 1; /* fall through */ case kAEPrintDocuments: err = errAEEventNotHandled; break; case kAEQuitApplication: /* Flush key queue */ keyQueueCount = keyQueueWrite = keyQueueRead = 0; AddToKeyQueue('S', 1); break; case kAEOpenDocuments: { FSSpec fss; FInfo fndrInfo; AEKeyword keywd; AEDescList docList; long index, itemsInList; if ((err = AEGetParamDesc(inAppleEvent, keyDirectObject, typeAEList, &docList)) != noErr || (err = AECountItems(&docList, &itemsInList)) != noErr) { if (err == errAEDescNotFound) itemsInList = 0; else break; } for (index = 1; index <= itemsInList; index++) { err = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode, (Ptr) &fss, sizeof(FSSpec), &actualSize); if (noErr != err) break; err = FSpGetFInfo(&fss, &fndrInfo); if (noErr != err) break; if (fndrInfo.fdType != SAVE_TYPE) continue; /* only look at save files */ process_openfile(fss.vRefNum, fss.parID, fss.name, fndrInfo.fdType); if (macFlags.gotOpen) break; /* got our save file */ } err = AEDisposeDesc(&docList); break; } } } /* Check to see if all required parameters for this type of event are * present */ if (err == noErr) { err = AEGetAttributePtr(inAppleEvent, keyMissedKeywordAttr, typeWildCard, &typeCode, NULL, 0, &actualSize); if (err == errAEDescNotFound) err = noErr; /* got all the required parameters */ else if (err == noErr) /* missed a required parameter */ err = errAEEventNotHandled; } return err; } short win_fonts[NHW_TEXT + 1]; void InitMac(void) { short i; long l; Str255 volName; #if !TARGET_API_MAC_CARBON if (LMGetDefltStack() < 50 * 1024L) { SetApplLimit((void *) ((long) LMGetCurStackBase() - (50 * 1024L))); } MaxApplZone(); for (i = 0; i < 5; i++) MoreMasters(); InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); InitDialogs(0L); TEInit(); #endif memset(&macFlags, 0, sizeof(macFlags)); if (!Gestalt(gestaltOSAttr, &l)) { macFlags.processes = (l & (1 << gestaltLaunchControl)) ? 1 : 0; macFlags.tempMem = (l & (1 << gestaltRealTempMemory)) ? 1 : 0; macFlags.hasDebugger = (l & (1 << gestaltSysDebuggerSupport)) ? 1 : 0; } if (!Gestalt(gestaltQuickdrawVersion, &l)) macFlags.color = (l >= gestalt8BitQD) ? 1 : 0; if (!Gestalt(gestaltFindFolderAttr, &l)) macFlags.folders = (l & (1 << gestaltFindFolderPresent)) ? 1 : 0; if (!Gestalt(gestaltHelpMgrAttr, &l)) macFlags.help = (l & (1 << gestaltHelpMgrPresent)) ? 1 : 0; if (!Gestalt(gestaltFSAttr, &l)) macFlags.fsSpec = (l & (1 << gestaltHasFSSpecCalls)) ? 1 : 0; if (!Gestalt(gestaltFontMgrAttr, &l)) macFlags.trueType = (l & (1 << gestaltOutlineFonts)) ? 1 : 0; if (!Gestalt(gestaltAUXVersion, &l)) macFlags.aux = (l >= 0x200) ? 1 : 0; if (!Gestalt(gestaltAliasMgrAttr, &l)) macFlags.alias = (l & (1 << gestaltAliasMgrPresent)) ? 1 : 0; if (!Gestalt(gestaltStandardFileAttr, &l)) macFlags.standardFile = (l & (1 << gestaltStandardFile58)) ? 1 : 0; gMouseRgn = NewRgn(); InitCursor(); GetQDGlobalsArrow(&qdarrow); ObscureCursor(); MoveScrollUPP = NewControlActionUPP(MoveScrollBar); /* Set up base fonts for all window types */ GetFNum("\pHackFont", &i); if (i == 0) i = kFontIDMonaco; win_fonts[NHW_BASE] = win_fonts[NHW_MAP] = win_fonts[NHW_STATUS] = i; GetFNum("\pPSHackFont", &i); if (i == 0) i = kFontIDGeneva; win_fonts[NHW_MESSAGE] = i; win_fonts[NHW_TEXT] = kFontIDGeneva; macFlags.hasAE = 0; if (!Gestalt(gestaltAppleEventsAttr, &l) && (l & (1L << gestaltAppleEventsPresent))) { if (AEInstallEventHandler(kCoreEventClass, typeWildCard, NewAEEventHandlerUPP(AppleEventHandler), 0, FALSE) == noErr) macFlags.hasAE = 1; } #if TARGET_API_MAC_CARBON HGetVol(volName, &theDirs.dataRefNum, &theDirs.dataDirID); #else /* * We should try to get this data from a rsrc, in the profile file * the user double-clicked... This data should be saved with the * save file in the resource fork, AND be saveable in "stationary" */ GetVol(volName, &theDirs.dataRefNum); GetWDInfo(theDirs.dataRefNum, &theDirs.dataRefNum, &theDirs.dataDirID, &l); #endif if (volName[0] > 31) volName[0] = 31; for (l = 1; l <= volName[0]; l++) { if (volName[l] == ':') { volName[l] = 0; volName[0] = l - 1; break; } } BlockMove(volName, theDirs.dataName, l); BlockMove(volName, theDirs.saveName, l); BlockMove(volName, theDirs.levelName, l); theDirs.saveRefNum = theDirs.levelRefNum = theDirs.dataRefNum; theDirs.saveDirID = theDirs.levelDirID = theDirs.dataDirID; /* Create the "record" file, if necessary */ check_recordfile(""); #if 0 // TARGET_API_MAC_CARBON /* Create event handler universal procedure pointers */ dispatcher = GetEventDispatcherTarget(); baseupp = NewEventHandlerUPP(BaseEvent); msgupp = NewEventHandlerUPP(MsgEvent); menwupp = NewEventHandlerUPP(MenwEvent); textupp = NewEventHandlerUPP(TextEvent); InstallApplicationEventHandler(NewEventHandlerUPP(GlobalEvent), sizeof(globalevents)/sizeof(EventTypeSpec), globalevents, NULL, NULL); #endif return; } /* * Change default window fonts. */ short set_tty_font_name(int window_type, char *font_name) { short fnum; Str255 new_font; if (window_type < NHW_BASE || window_type > NHW_TEXT) return general_failure; C2P(font_name, new_font); GetFNum(new_font, &(fnum)); if (!fnum) return general_failure; win_fonts[window_type] = fnum; return noErr; } static void DrawScrollbar(NhWindow *aWin) { WindowPtr theWindow = aWin->its_window; Rect crect, wrect; Boolean vis; short val, lin, win_height; if (!aWin->scrollBar) return; GetControlBounds(aWin->scrollBar, &crect); GetWindowBounds(aWin->its_window, kWindowContentRgn, &wrect); OffsetRect(&wrect, -wrect.left, -wrect.top); win_height = wrect.bottom - wrect.top; if (crect.top != wrect.top - 1 || crect.left != wrect.right - SBARWIDTH) { MoveControl(aWin->scrollBar, wrect.right - SBARWIDTH, wrect.top - 1); } if (crect.bottom != wrect.bottom - SBARHEIGHT || crect.right != wrect.right + 1) { SizeControl(aWin->scrollBar, SBARWIDTH + 1, win_height - SBARHEIGHT + 2); } vis = (win_height > (50 + SBARHEIGHT)); if (vis != IsControlVisible(aWin->scrollBar)) { /* current status != control */ if (vis) /* if visible, show */ ShowControl(aWin->scrollBar); else /* else hide */ HideControl(aWin->scrollBar); } lin = aWin->y_size; if (aWin == theWindows + WIN_MESSAGE) { /* calculate how big scroll bar is for message window */ lin -= (win_height - SBARHEIGHT) / aWin->row_height; if (lin < 0) lin = 0; val = 0; /* always have message scrollbar active */ } else { /* calculate how big scroll bar is for other windows */ lin -= win_height / aWin->row_height; if (lin < 0) lin = 0; if (lin) val = 0; /* if there are 1+ screen lines, activate scrollbar */ else val = 255; /* else grey it out */ } SetControlMaximum(aWin->scrollBar, lin); HiliteControl(aWin->scrollBar, val); val = GetControlValue(aWin->scrollBar); if (val != aWin->scrollPos) { InvalWindowRect(theWindow, &wrect); aWin->scrollPos = val; } } #define MAX_HEIGHT 100 #define MIN_HEIGHT 50 #define MIN_WIDTH 300 /* * This function could be overloaded with any amount of intelligence... */ int SanePositions(void) { #if TARGET_API_MAC_CARBON Rect rbase, rmsg; SInt16 i, width, height; ConstrainWindowToScreen(_mt_window, kWindowContentRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); GetWindowBounds(_mt_window, kWindowContentRgn, &rbase); if (RetrievePosition(kMapWindow, &rbase.top, &rbase.left)) MoveWindow(_mt_window, rbase.left, rbase.top, TRUE); GetWindowBounds(theWindows[NHW_MESSAGE].its_window, kWindowContentRgn, &rmsg); height = rmsg.bottom - rmsg.top; rmsg.top = rbase.bottom + 2; rmsg.bottom = rmsg.top + height; rmsg.left = rbase.left; rmsg.right = rbase.right; RetrievePosition(kMessageWindow, &rmsg.top, &rmsg.left); if (RetrieveSize(kMessageWindow, rmsg.top, rmsg.left, &height, &width)) { rmsg.right = rmsg.left + width; rmsg.bottom = rmsg.top + height; } SetWindowBounds(theWindows[NHW_MESSAGE].its_window, kWindowContentRgn, &rmsg); ConstrainWindowToScreen(theWindows[NHW_MESSAGE].its_window, kWindowContentRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); DrawScrollbar(&theWindows[NHW_MESSAGE]); for (i = 0; i < NUM_MACWINDOWS; i++) if (i != WIN_STATUS && i != WIN_MESSAGE && i != WIN_MAP && i != BASE_WINDOW && theWindows[i].its_window) { /* FIXME */ ConstrainWindowToScreen( theWindows[i].its_window, kWindowContentRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); } #else short left, top, width, height; int ix, numText = 0, numMenu = 0; int mbar_height = GetMBarHeight(); BitMap qbitmap; Rect screenArea; WindowPtr theWindow; NhWindow *nhWin; screenArea = GetQDGlobalsScreenBits(&qbitmap)->bounds; OffsetRect(&screenArea, -screenArea.left, -screenArea.top); /* Map Window */ height = _mt_window->portRect.bottom - _mt_window->portRect.top; width = _mt_window->portRect.right - _mt_window->portRect.left; if (!RetrievePosition(kMapWindow, &top, &left)) { top = mbar_height + (small_screen ? 2 : 20); left = (screenArea.right - width) / 2; } MoveWindow(_mt_window, left, top, 1); /* Message Window */ if (!RetrievePosition(kMessageWindow, &top, &left)) { top += height; if (!small_screen) top += 20; } if (!RetrieveSize(kMessageWindow, top, left, &height, &width)) { height = screenArea.bottom - top - (small_screen ? 2 - SBARHEIGHT : 2); if (height > MAX_HEIGHT) { height = MAX_HEIGHT; } else if (height < MIN_HEIGHT) { height = MIN_HEIGHT; width = MIN_WIDTH; left = screenArea.right - width; top = screenArea.bottom - MIN_HEIGHT; } } /* Move these windows */ nhWin = theWindows + WIN_MESSAGE; theWindow = nhWin->its_window; MoveWindow(theWindow, left, top, 1); SizeWindow(theWindow, width, height, 1); if (nhWin->scrollBar) DrawScrollbar(nhWin); /* Handle other windows */ for (ix = 0; ix < NUM_MACWINDOWS; ix++) { if (ix != WIN_STATUS && ix != WIN_MESSAGE && ix != WIN_MAP && ix != BASE_WINDOW) { theWindow = theWindows[ix].its_window; if (theWindow && ((WindowPeek) theWindow)->visible) { int shift; if (((WindowPeek) theWindow)->windowKind == WIN_BASE_KIND + NHW_MENU) { if (!RetrievePosition(kMenuWindow, &top, &left)) { top = mbar_height * 2; left = 2; } top += (numMenu * mbar_height); numMenu++; shift = 20; } else { if (!RetrievePosition(kTextWindow, &top, &left)) { top = mbar_height * 2; left = screenArea.right - 3 - (theWindow->portRect.right - theWindow->portRect.left); } top += (numText * mbar_height); numText++; shift = -20; } while (top > screenArea.bottom - MIN_HEIGHT) { top -= screenArea.bottom - mbar_height * 2; left += shift; } MoveWindow(theWindow, left, top, 1); } } } #endif return (0); } void mac_init_nhwindows(int *argcp, char **argv) { Rect r; #if !TARGET_API_MAC_CARBON Rect scr = (*GetGrayRgn())->rgnBBox; small_screen = scr.bottom - scr.top <= (iflags.large_font ? 12 * 40 : 9 * 40); #endif InitMenuRes(); theWindows = (NhWindow *) NewPtrClear(NUM_MACWINDOWS * sizeof(NhWindow)); if (MemError()) error("mac_init_nhwindows: Couldn't allocate memory for windows."); DimMenuBar(); tty_init_nhwindows(argcp, argv); iflags.window_inited = TRUE; /* Some ugly hacks to make both interfaces happy: * Mac port uses both tty interface (for main map) and extra windows. The * winids need to * be kept in synch for both interfaces to map. Also, the "blocked" * display_nhwindow case * for the map automatically calls the tty interface for the message box, * so some version * of the message box has to exist in the tty world to prevent a meltdown, * even though most * messages are handled in mac window. */ mac_create_nhwindow(NHW_BASE); tty_create_nhwindow(NHW_MESSAGE); #if 1 //!TARGET_API_MAC_CARBON /* Resize and reposition the message window */ RetrievePosition(kMessageWindow, &r.top, &r.left); RetrieveSize(kMessageWindow, r.top, r.left, &r.bottom, &r.right); MoveWindow(theWindows[NHW_MESSAGE].its_window, r.left, r.top, false); SizeWindow(theWindows[NHW_MESSAGE].its_window, r.right, r.bottom, true); #endif return; } winid mac_create_nhwindow(int kind) { int i; NhWindow *aWin; FontInfo fi; if (kind < NHW_BASE || kind > NHW_TEXT) { error("cre_win: Invalid kind %d.", kind); return WIN_ERR; } for (i = 0; i < NUM_MACWINDOWS; i++) { if (!theWindows[i].its_window) break; } if (i >= NUM_MACWINDOWS) { error("cre_win: Win full; freeing extras"); for (i = 0; i < NUM_MACWINDOWS; i++) { if (IsWindowVisible(theWindows[i].its_window) || i == WIN_INVEN || GetWindowKind(theWindows[i].its_window) != WIN_BASE_KIND + NHW_MENU && GetWindowKind(theWindows[i].its_window) != WIN_BASE_KIND + NHW_TEXT) continue; mac_destroy_nhwindow(i); goto got1; } error("cre_win: Out of ids!"); return WIN_ERR; } got1: aWin = &theWindows[i]; aWin->windowTextLen = 0L; aWin->scrollBar = (ControlHandle) 0; aWin->menuInfo = 0; aWin->menuSelected = 0; aWin->miLen = 0; aWin->miSize = 0; aWin->menuChar = 'a'; dprintf("cre_win: New kind %d", kind); if (kind == NHW_BASE || kind == NHW_MAP || kind == NHW_STATUS) { short x_sz, x_sz_p, y_sz, y_sz_p; if (kind != NHW_BASE) { if (i != tty_create_nhwindow(kind)) { dprintf("cre_win: error creating kind %d", kind); } if (kind == NHW_MAP) { wins[i]->offy = 0; /* the message box is in a separate window */ } } aWin->its_window = _mt_window; get_tty_metrics(aWin->its_window, &x_sz, &y_sz, &x_sz_p, &y_sz_p, &aWin->font_number, &aWin->font_size, &aWin->char_width, &aWin->row_height); #if 0 // TARGET_API_MAC_CARBON InstallWindowEventHandler(aWin->its_window, baseupp, sizeof(baseevents)/sizeof(EventTypeSpec), baseevents, (void *)aWin, NULL); #endif return i; } aWin->its_window = GetNewWindow(WIN_BASE_RES + kind, (WindowPtr) 0L, (WindowPtr) -1L); SetWindowKind(aWin->its_window, WIN_BASE_KIND + kind); SetWRefCon(aWin->its_window, (long) aWin); if (!(aWin->windowText = NewHandle(TEXT_BLOCK))) { error("cre_win: NewHandle fail(%ld)", (long) TEXT_BLOCK); DisposeWindow(aWin->its_window); aWin->its_window = (WindowPtr) 0; return WIN_ERR; } aWin->x_size = aWin->y_size = 0; aWin->x_curs = aWin->y_curs = 0; aWin->drawn = TRUE; mac_clear_nhwindow(i); #if 0 // TARGET_API_MAC_CARBON switch (kind) { case NHW_MESSAGE: InstallWindowEventHandler(aWin->its_window, msgupp, sizeof(msgevents)/sizeof(EventTypeSpec), msgevents, (void *)aWin, NULL); break; case NHW_MENU: InstallWindowEventHandler(aWin->its_window, menwupp, sizeof(menwevents)/sizeof(EventTypeSpec), menwevents, (void *)aWin, NULL); break; case NHW_TEXT: InstallWindowEventHandler(aWin->its_window, textupp, sizeof(textevents)/sizeof(EventTypeSpec), textevents, (void *)aWin, NULL); break; } #endif SetPortWindowPort(aWin->its_window); if (kind == NHW_MESSAGE) { aWin->font_number = win_fonts[NHW_MESSAGE]; aWin->font_size = iflags.wc_fontsiz_message ? iflags.wc_fontsiz_message : iflags.large_font ? 12 : 9; if (!top_line) { const Rect out_of_scr = { 10000, 10000, 10100, 10100 }; TextFont(aWin->font_number); TextSize(aWin->font_size); TextFace(bold); top_line = TENew(&out_of_scr, &out_of_scr); TEActivate(top_line); TextFace(normal); } } else { aWin->font_number = win_fonts[NHW_TEXT]; aWin->font_size = iflags.wc_fontsiz_text ? iflags.wc_fontsiz_text : 9; } TextFont(aWin->font_number); TextSize(aWin->font_size); GetFontInfo(&fi); aWin->ascent_height = fi.ascent + fi.leading; aWin->row_height = aWin->ascent_height + fi.descent; aWin->char_width = fi.widMax; if (kind == NHW_MENU || kind == NHW_TEXT || kind == NHW_MESSAGE) { Rect r; GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); r.right -= (r.left - 1); r.left = r.right - SBARWIDTH; r.bottom -= (r.top + SBARHEIGHT); r.top = -1; aWin->scrollBar = NewControl(aWin->its_window, &r, "\p", (r.bottom > r.top + 50), 0, 0, 0, 16, 0L); aWin->scrollPos = 0; } return i; } void mac_clear_nhwindow(winid win) { long l; Rect r; NhWindow *aWin = &theWindows[win]; WindowPtr theWindow = aWin->its_window; if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) { error("clr_win: Invalid win %d.", win); return; } if (theWindow == _mt_window) { tty_clear_nhwindow(win); return; } if (!aWin->drawn) return; SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (aWin->scrollBar) r.right -= SBARWIDTH; switch (GetWindowKind(theWindow) - WIN_BASE_KIND) { case NHW_MESSAGE: if (aWin->scrollPos == aWin->y_size - 1) /* if no change since last clear */ return; /* don't bother with redraw */ r.bottom -= SBARHEIGHT; for (l = 0; aWin->y_size > iflags.msg_history;) { const char cr = CHAR_CR; l = Munger(aWin->windowText, l, &cr, 1, nil, 0) + 1; --aWin->y_size; } if (l) { aWin->windowTextLen -= l; BlockMove(*aWin->windowText + l, *aWin->windowText, aWin->windowTextLen); } aWin->last_more_lin = aWin->y_size; aWin->save_lin = aWin->y_size; aWin->scrollPos = aWin->y_size ? aWin->y_size - 1 : 0; break; case NHW_MENU: if (aWin->menuInfo) { DisposeHandle((Handle) aWin->menuInfo); aWin->menuInfo = NULL; } if (aWin->menuSelected) { DisposeHandle((Handle) aWin->menuSelected); aWin->menuSelected = NULL; } aWin->menuChar = 'a'; aWin->miSelLen = 0; aWin->miLen = 0; aWin->miSize = 0; /* Fall-Through */ default: SetHandleSize(aWin->windowText, TEXT_BLOCK); aWin->windowTextLen = 0L; aWin->x_size = 0; aWin->y_size = 0; aWin->scrollPos = 0; break; } if (aWin->scrollBar) { SetControlMaximum(aWin->scrollBar, aWin->y_size); SetControlValue(aWin->scrollBar, aWin->scrollPos); } aWin->y_curs = 0; aWin->x_curs = 0; aWin->drawn = FALSE; InvalWindowRect(theWindow, &r); } static Boolean ClosingWindowChar(const int c) { return (c == CHAR_ESC || c == CHAR_BLANK || c == CHAR_LF || c == CHAR_CR); } static Boolean in_topl_mode(void) { Rect rect; GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); return (WIN_MESSAGE != WIN_ERR && top_line && (*top_line)->viewRect.left < rect.right); } #define BTN_IND 2 #define BTN_W 40 #define BTN_H (SBARHEIGHT - 3) static void topl_resp_rect(int resp_idx, Rect *r) { Rect rect; GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); r->left = (BTN_IND + BTN_W) * resp_idx + BTN_IND; r->right = r->left + BTN_W; r->bottom = rect.bottom - 1; r->top = r->bottom - BTN_H; return; } void enter_topl_mode(char *query) { if (in_topl_mode()) return; putstr(WIN_MESSAGE, ATR_BOLD, query); topl_query_len = strlen(query); (*top_line)->selStart = topl_query_len; (*top_line)->selEnd = topl_query_len; (*top_line)->viewRect.left = 0; PtrToXHand(query, (*top_line)->hText, topl_query_len); TECalText(top_line); DimMenuBar(); mac_display_nhwindow(WIN_MESSAGE, FALSE); } void leave_topl_mode(char *answer) { /*unsigned*/ char *ap, *bp; int ans_len = (*top_line)->teLength - topl_query_len; NhWindow *aWin = theWindows + WIN_MESSAGE; if (!in_topl_mode()) return; /* Cap length of reply */ if (ans_len >= BUFSZ) ans_len = BUFSZ - 1; /* remove unprintables from the answer */ for (ap = *(*top_line)->hText + topl_query_len, bp = answer; ans_len > 0; ans_len--, ap++) { if (*ap >= ' ' && *ap < 128) { *bp++ = *ap; } } *bp = 0; if (aWin->windowTextLen && (*aWin->windowText)[aWin->windowTextLen - 1] == CHAR_CR) { --aWin->windowTextLen; --aWin->y_size; } putstr(WIN_MESSAGE, ATR_BOLD, answer); (*top_line)->viewRect.left += 10000; UndimMenuBar(); } /* * TESetSelect flushes out all the pending key strokes. I hate it. */ static void topl_set_select(short selStart, short selEnd) { TEDeactivate(top_line); (*top_line)->selStart = selStart; (*top_line)->selEnd = selEnd; TEActivate(top_line); } static void topl_replace(char *new_ans) { topl_set_select(topl_query_len, (*top_line)->teLength); TEDelete(top_line); TEInsert(new_ans, strlen(new_ans), top_line); } Boolean topl_key(unsigned char ch, Boolean ext) { switch (ch) { case CHAR_ESC: topl_replace("\x1b"); case CHAR_ENTER: case CHAR_CR: case CHAR_LF: return false; case 0x1f & 'P': mac_doprev_message(); return true; case '\x1e' /* up arrow */: topl_replace(""); return true; case CHAR_BS: case '\x1c' /* left arrow */: if ((*top_line)->selEnd <= topl_query_len) return true; else if (ext) { topl_replace(""); return true; } default: TEKey(ch, top_line); if (ext) { int com_index = -1, oindex = 0; while (extcmdlist[oindex].ef_txt != (char *) 0) { if (!strncmpi(*(*top_line)->hText + topl_query_len, extcmdlist[oindex].ef_txt, (*top_line)->teLength - topl_query_len)) { if (com_index == -1) /* No matches yet*/ com_index = oindex; else /* More than 1 match */ { com_index = -2; break; } } oindex++; } if (com_index >= 0) topl_replace((char *) extcmdlist[com_index].ef_txt); } return true; } } static void topl_flash_resp(int resp_idx) { unsigned long dont_care; Rect frame; SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); topl_resp_rect(resp_idx, &frame); InsetRect(&frame, 1, 1); InvertRect(&frame); Delay(GetDblTime() / 2, &dont_care); InvertRect(&frame); } static void topl_set_def(int new_def_idx) { Rect frame; SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); topl_resp_rect(topl_def_idx, &frame); InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); topl_def_idx = new_def_idx; topl_resp_rect(new_def_idx, &frame); InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); } void topl_set_resp(char *resp, char def) { char *loc; Rect frame; int r_len, r_len1; if (!resp) { const char any_str[2] = { CHAR_ANY, '\0' }; resp = (char *) any_str; def = CHAR_ANY; } SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); r_len1 = strlen(resp); r_len = strlen(topl_resp); if (r_len < r_len1) r_len = r_len1; topl_resp_rect(0, &frame); frame.right = (BTN_IND + BTN_W) * r_len; InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); strcpy(topl_resp, resp); loc = strchr(resp, def); topl_def_idx = loc ? loc - resp : -1; } static char topl_resp_key(char ch) { if (strlen(topl_resp) > 0) { char *loc = strchr(topl_resp, ch); if (!loc) { if (ch == '\x9' /* tab */) { topl_set_def(topl_def_idx <= 0 ? strlen(topl_resp) - 1 : topl_def_idx - 1); ch = '\0'; } else if (ch == CHAR_ESC) { loc = strchr(topl_resp, 'q'); if (!loc) { loc = strchr(topl_resp, 'n'); if (!loc && topl_def_idx >= 0) loc = topl_resp + topl_def_idx; } } else if (ch == (0x1f & 'P')) { mac_doprev_message(); ch = '\0'; } else if (topl_def_idx >= 0) { if (ch == CHAR_ENTER || ch == CHAR_CR || ch == CHAR_LF || ch == CHAR_BLANK || topl_resp[topl_def_idx] == CHAR_ANY) loc = topl_resp + topl_def_idx; else if (strchr(topl_resp, '#')) { if (digit(ch)) { topl_set_def(strchr(topl_resp, '#') - topl_resp); TEKey(ch, top_line); ch = '\0'; } else if (topl_resp[topl_def_idx] == '#') { if (ch == '\x1e' /* up arrow */) { topl_set_select(topl_query_len, topl_query_len); ch = '\0'; } else if (ch == '\x1d' /* right arrow */ || ch == '\x1f' /* down arrow */ || ch == CHAR_BS || ch == '\x1c' /* left arrow */ && (*top_line)->selEnd > topl_query_len) { TEKey(ch, top_line); ch = '\0'; } } } } } if (loc) { topl_flash_resp(loc - topl_resp); if (*loc != CHAR_ANY) ch = *loc; TEKey(ch, top_line); } } return ch; } static void adjust_window_pos(NhWindow *aWin, short width, short height) { WindowRef theWindow = aWin->its_window; #if TARGET_API_MAC_CARBON Rect r; GetWindowBounds(theWindow, kWindowContentRgn, &r); RetrieveWinPos(theWindow, &r.top, &r.left); MoveWindow(theWindow, r.left, r.top, false); SizeWindow(theWindow, width, height, true); ConstrainWindowToScreen(theWindow, kWindowStructureRgn, kWindowConstrainMayResize | kWindowConstrainMoveRegardlessOfFit, NULL, NULL); #else Rect scr_r = (*GetGrayRgn())->rgnBBox; const Rect win_ind = { 2, 2, 3, 3 }; const short min_w = theWindow->portRect.right - theWindow->portRect.left, max_w = scr_r.right - scr_r.left - win_ind.left - win_ind.right; Point pos; short max_h; SetPortWindowPort(theWindow); if (!RetrieveWinPos(theWindow, &pos.v, &pos.h)) { pos.v = 0; /* take window's existing position */ pos.h = 0; LocalToGlobal(&pos); } max_h = scr_r.bottom - win_ind.bottom - pos.v; if (height > max_h) height = max_h; if (height < MIN_HEIGHT) height = MIN_HEIGHT; if (width < min_w) width = min_w; if (width > max_w) width = max_w; SizeWindow(theWindow, width, height, true); if (pos.v + height + win_ind.bottom > scr_r.bottom) pos.v = scr_r.bottom - height - win_ind.bottom; if (pos.h + width + win_ind.right > scr_r.right) pos.h = scr_r.right - width - win_ind.right; MoveWindow(theWindow, pos.h, pos.v, false); #endif if (aWin->scrollBar) DrawScrollbar(aWin); return; } /* * display/select/update the window. * If f is true, this window should be "modal" - don't return * until presumed seen. */ void mac_display_nhwindow(winid win, BOOLEAN_P f) { NhWindow *aWin = &theWindows[win]; WindowPtr theWindow = aWin->its_window; if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) { error("disp_win: Invalid window %d.", win); return; } if (theWindow == _mt_window) { tty_display_nhwindow(win, f); return; } if (f && inSelect == WIN_ERR && win == WIN_MESSAGE) { topl_set_resp((char *) 0, 0); if (aWin->windowTextLen > 0 && (*aWin->windowText)[aWin->windowTextLen - 1] == CHAR_CR) { --aWin->windowTextLen; --aWin->y_size; } putstr(win, flags.standout ? ATR_INVERSE : ATR_NONE, " --More--"); } if (!IsWindowVisible(theWindow)) { if (win != WIN_MESSAGE) adjust_window_pos(aWin, aWin->x_size + SBARWIDTH + 1, aWin->y_size * aWin->row_height); SelectWindow(theWindow); ShowWindow(theWindow); } if (f && inSelect == WIN_ERR) { int ch; DimMenuBar(); inSelect = win; do { ch = mac_nhgetch(); } while (!ClosingWindowChar(ch)); inSelect = WIN_ERR; UndimMenuBar(); if (win == WIN_MESSAGE) topl_set_resp("", '\0'); else HideWindow(theWindow); } } void mac_destroy_nhwindow(winid win) { WindowPtr theWindow; NhWindow *aWin = &theWindows[win]; int kind; if (win < 0 || win >= NUM_MACWINDOWS) { if (iflags.window_inited) error("dest_win: Invalid win %d.", win); return; } theWindow = aWin->its_window; if (!theWindow) { error("dest_win: Not allocated win %d.", win); return; } /* * Check special windows. The base window should never go away. * Other "standard" windows should not go away unless we've exitted * nhwindows. */ if (theWindow == _mt_window) { return; } if (win == WIN_INVEN || win == WIN_MESSAGE) { if (iflags.window_inited) { if (flags.tombstone && killer[0]) { /* Prepare for the coming of the tombstone window. */ win_fonts[NHW_TEXT] = kFontIDMonaco; } return; } if (win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR; } kind = GetWindowKind(theWindow) - WIN_BASE_KIND; if ((!IsWindowVisible(theWindow) || (kind != NHW_MENU && kind != NHW_TEXT))) { DisposeWindow(theWindow); if (aWin->windowText) { DisposeHandle(aWin->windowText); } aWin->its_window = (WindowPtr) 0; aWin->windowText = (Handle) 0; } } void mac_number_pad(int pad) { /* no effect */ #if defined(__SC__) || defined(__MRC__) #pragma unused(pad) #endif return; } void trans_num_keys(EventRecord *theEvent) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theEvent) #endif /* KMH -- Removed this translation. * Number pad keys should always emit digit characters. * That's consistent with the default MacOS behavior. * The number_pad option controls how digits are interpreted. */ #if 0 if (Cmd.num_pad) { Handle h = GetResource('Nump', theEvent->modifiers & shiftKey ? 129 : 128); if (h) { short inkey = (theEvent->message & keyCodeMask), *ab = (short *)*h; int i = ab[0]; for (; i; i--) { if (inkey == (ab[i] & keyCodeMask)) { theEvent->message = ab[i]; break; } } } } #endif } /* * Routine used to select and de-select elements in a menu window, used by * KeyMenu, * ClickMenu, and UpdateMenu. Takes the NhWindow and a line ref relative to * the scrollbar. */ static void ToggleMenuSelect(NhWindow *aWin, int line) { Rect r; GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (aWin->scrollBar) r.right -= SBARWIDTH; r.top = line * aWin->row_height; r.bottom = r.top + aWin->row_height; LMSetHiliteMode((UInt8)(LMGetHiliteMode() & 0x7F)); InvertRect(&r); } /* * Check to see if given item is selected, return index if it is */ static int ListItemSelected(NhWindow *aWin, int item) { int i; HLock((char **) aWin->menuSelected); /* Find item in selection list */ for (i = aWin->miSelLen - 1; i >= 0; i--) { if ((*aWin->menuSelected)[i] == item) break; } HUnlock((char **) aWin->menuSelected); return i; } /* * Add item to selection list if it's not selected already * If it is selected already, remove it from the list. */ static void ToggleMenuListItemSelected(NhWindow *aWin, short item) { int i = ListItemSelected(aWin, item); HLock((char **) aWin->menuSelected); if (i < 0) { /* not there, so add */ (*aWin->menuSelected)[aWin->miSelLen] = item; aWin->miSelLen++; } else { /* there, so remove */ short *mi = &(*aWin->menuSelected)[i]; aWin->miSelLen--; memcpy(mi, mi + 1, (aWin->miSelLen - i) * sizeof(short)); } HUnlock((char **) aWin->menuSelected); } /* * Find menu item in list given a line number on the window */ static short ListCoordinateToItem(NhWindow *aWin, short Row) { int i, item = -1; MacMHMenuItem *mi; HLock((char **) aWin->menuInfo); for (i = 0, mi = *aWin->menuInfo; i < aWin->miLen; i++, mi++) { if (mi->line == Row + aWin->scrollPos) { item = i; break; } } HUnlock((char **) aWin->menuInfo); return item; } static pascal void MoveScrollBar(ControlHandle theBar, short part) { #if 1 //!TARGET_API_MAC_CARBON EventRecord fake; #endif Rect r; RgnHandle rgn; int now, amtToScroll; WindowPtr theWin; NhWindow *winToScroll; if (!part) return; theWin = GetControlOwner(theBar); GetWindowBounds(theWin, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); winToScroll = (NhWindow *) (GetWRefCon(theWin)); now = GetControlValue(theBar); if (part == kControlPageUpPart || part == kControlPageDownPart) amtToScroll = (r.bottom - r.top) / winToScroll->row_height; else amtToScroll = 1; if (part == kControlPageUpPart || part == kControlUpButtonPart) { int bound = GetControlMinimum(theBar); if (now - bound < amtToScroll) amtToScroll = now - bound; amtToScroll = -amtToScroll; } else { int bound = GetControlMaximum(theBar); if (bound - now < amtToScroll) amtToScroll = bound - now; } if (!amtToScroll) return; SetControlValue(theBar, now + amtToScroll); winToScroll->scrollPos = now + amtToScroll; r.right -= SBARWIDTH; if (winToScroll == theWindows + WIN_MESSAGE) r.bottom -= SBARHEIGHT; rgn = NewRgn(); ScrollRect(&r, 0, -amtToScroll * winToScroll->row_height, rgn); if (rgn) { InvalWindowRgn(theWin, rgn); BeginUpdate(theWin); } #if 0 // TARGET_API_MAC_CARBON switch (GetWindowKind(theWin) - WIN_BASE_KIND) { case NHW_MESSAGE: MsgUpdate(GetNhWin(theWin)); break; case NHW_MENU: MenwUpdate(GetNhWin(theWin)); break; case NHW_TEXT: TextUpdate(GetNhWin(theWin)); break; } #else winUpdateFuncs[GetWindowKind(theWin) - WIN_BASE_KIND](&fake, theWin); #endif if (rgn) { EndUpdate(theWin); DisposeRgn(rgn); } } #if 1 //!TARGET_API_MAC_CARBON static void DoScrollBar(Point p, short code, ControlHandle theBar, NhWindow *aWin) { ControlActionUPP func = NULL; Rect rect; if (code == kControlUpButtonPart || code == kControlPageUpPart || code == kControlDownButtonPart || code == kControlPageDownPart) func = MoveScrollUPP; (void) TrackControl(theBar, p, func); if (!func) { if (aWin->scrollPos != GetControlValue(theBar)) { aWin->scrollPos = GetControlValue(theBar); GetWindowBounds(aWin->its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); InvalWindowRect(aWin->its_window, &rect); } } } #endif static int filter_scroll_key(const int ch, NhWindow *aWin) { if (aWin->scrollBar && GetControlValue(aWin->scrollBar) < GetControlMaximum(aWin->scrollBar)) { short part = 0; if (ch == CHAR_BLANK) { part = kControlPageDownPart; } else if (ch == CHAR_CR || ch == CHAR_LF) { part = kControlDownButtonPart; } if (part) { SetPortWindowPort(aWin->its_window); MoveScrollBar(aWin->scrollBar, part); return 0; } } return ch; } int mac_doprev_message(void) { if (WIN_MESSAGE) { NhWindow *winToScroll = &theWindows[WIN_MESSAGE]; mac_display_nhwindow(WIN_MESSAGE, FALSE); SetPortWindowPort(winToScroll->its_window); MoveScrollBar(winToScroll->scrollBar, kControlUpButtonPart); } return 0; } static void draw_growicon_vert_only(WindowPtr wind) { GrafPtr org_port; RgnHandle org_clip = NewRgn(); Rect r; GetPort(&org_port); SetPortWindowPort(wind); GetClip(org_clip); GetWindowBounds(wind, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); r.left = r.right - SBARWIDTH; ClipRect(&r); DrawGrowIcon(wind); SetClip(org_clip); DisposeRgn(org_clip); SetPort(org_port); } /* NOT_IN_CARBON */ static void WindowGoAway(EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin(theWindow); if (!theEvent || TrackGoAway(theWindow, theEvent->where)) { if (aWin - theWindows == BASE_WINDOW && !iflags.window_inited) { AddToKeyQueue('\033', 1); } else { HideWindow(theWindow); if (aWin - theWindows != inSelect) mac_destroy_nhwindow(aWin - theWindows); else /* if this IS the inSelect window put a close char */ AddToKeyQueue(CHAR_CR, 1); /* in queue to exit and maintain inSelect */ } } } void mac_get_nh_event(void) { EventRecord anEvent; /* KMH -- Don't proceed if the window system isn't set up */ if (!iflags.window_inited) return; #if TARGET_API_MAC_CARBON QDFlushPortBuffer(GetWindowPort(_mt_window), NULL); #endif (void) WaitNextEvent(everyEvent, &anEvent, 1, gMouseRgn); HandleEvent(&anEvent); return; } int mac_nhgetch(void) { int ch; long doDawdle = 1L; EventRecord anEvent; #if 1 //!TARGET_API_MAC_CARBON /* We want to take care of keys in the buffer as fast as * possible */ if (keyQueueCount) doDawdle = 0L; else { long total, contig; static char warn = 0; doDawdle = (in_topl_mode() ? GetCaretTime() : 120L); /* Since we have time, check memory */ PurgeSpace(&total, &contig); if (contig < 25000L || total < 50000L) { if (!warn) { pline("Low Memory!"); warn = 1; } } else { warn = 0; } } #endif do { #if TARGET_API_MAC_CARBON QDFlushPortBuffer(GetWindowPort(_mt_window), NULL); #endif #if 0 // TARGET_API_MAC_CARBON EventRef event; if (ReceiveNextEvent(0, NULL, kEventDurationForever, TRUE, &event) == noErr) { SendEventToEventTarget(event, dispatcher); ReleaseEvent(event); } #else (void) WaitNextEvent(everyEvent, &anEvent, doDawdle, gMouseRgn); HandleEvent(&anEvent); #endif ch = GetFromKeyQueue(); } while (!ch && !gClickedToMove); if (!gClickedToMove) ObscureCursor(); else gClickedToMove = 0; #ifdef THINK_C if (ch == '\r') ch = '\n'; #endif return (ch); } void mac_delay_output(void) { long destTicks = TickCount() + 1; while (TickCount() < destTicks) { mac_get_nh_event(); } } #ifdef CLIPPING static void mac_cliparound(int x, int y) { #if defined(__SC__) || defined(__MRC__) #pragma unused(x, y) #endif /* TODO */ } #endif void mac_exit_nhwindows(const char *s) { clear_screen(); tty_exit_nhwindows(s); mac_destroy_nhwindow(WIN_MESSAGE); mac_destroy_nhwindow(WIN_INVEN); } /* * Don't forget to decrease in_putstr before returning... */ void mac_putstr(winid win, int attr, const char *str) { long len, slen; NhWindow *aWin = &theWindows[win]; static char in_putstr = 0; short newWidth, maxWidth; Rect r; char *src, *sline, *dst, ch; if (win < 0 || win >= NUM_MACWINDOWS || !aWin->its_window) { error("putstr: Invalid win %d (Max %d).", win, NUM_MACWINDOWS, attr); return; } if (aWin->its_window == _mt_window) { tty_putstr(win, attr, str); return; } if (in_putstr > 3) return; in_putstr++; slen = strlen(str); SetPortWindowPort(aWin->its_window); GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (win == WIN_MESSAGE) { r.right -= SBARWIDTH; r.bottom -= SBARHEIGHT; if (flags.page_wait && aWin->last_more_lin <= aWin->y_size - (r.bottom - r.top) / aWin->row_height) { aWin->last_more_lin = aWin->y_size; mac_display_nhwindow(win, TRUE); } } /* * A "default" text window - uses TETextBox * We just add the text, without attributes for now */ len = GetHandleSize(aWin->windowText); while (aWin->windowTextLen + slen + 1 > len) { len = (len > 2048) ? (len + 2048) : (len * 2); SetHandleSize(aWin->windowText, len); if (MemError()) { error("putstr: SetHandleSize"); aWin->windowTextLen = 0L; aWin->save_lin = 0; aWin->y_curs = 0; aWin->y_size = 0; } } len = aWin->windowTextLen; dst = *(aWin->windowText) + len; sline = src = (char *) str; maxWidth = newWidth = 0; for (ch = *src; ch; ch = *src) { if (ch == CHAR_LF) ch = CHAR_CR; *dst++ = ch; if (ch == CHAR_CR) { aWin->y_curs++; aWin->y_size++; aWin->x_curs = 0; newWidth = TextWidth(sline, 0, src - sline); if (newWidth > maxWidth) { maxWidth = newWidth; } sline = src + 1; /* keep track of where new line begins */ } else aWin->x_curs++; src++; } newWidth = TextWidth(sline, 0, src - sline); if (newWidth > maxWidth) { maxWidth = newWidth; } aWin->windowTextLen += slen; if (ch != CHAR_CR) { (*(aWin->windowText))[len + slen] = CHAR_CR; aWin->windowTextLen++; aWin->y_curs++; aWin->y_size++; aWin->x_curs = 0; } if (win == WIN_MESSAGE) { short min = aWin->y_size - (r.bottom - r.top) / aWin->row_height; if (aWin->scrollPos < min) { aWin->scrollPos = min; SetControlMaximum(aWin->scrollBar, aWin->y_size); SetControlValue(aWin->scrollBar, min); } InvalWindowRect(aWin->its_window, &r); } else /* Message has a fixed width, other windows base on content */ if (maxWidth > aWin->x_size) aWin->x_size = maxWidth; in_putstr--; } void mac_curs(winid win, int x, int y) { NhWindow *aWin = &theWindows[win]; if (aWin->its_window == _mt_window) { tty_curs(win, x, y); return; } SetPortWindowPort(aWin->its_window); MoveTo(x * aWin->char_width, (y * aWin->row_height) + aWin->ascent_height); aWin->x_curs = x; aWin->y_curs = y; } int mac_nh_poskey(int *a, int *b, int *c) { int ch = mac_nhgetch(); *a = clicked_pos.h; *b = clicked_pos.v; *c = clicked_mod; return ch; } void mac_start_menu(winid win) { HideWindow(theWindows[win].its_window); mac_clear_nhwindow(win); } void mac_add_menu(winid win, int glyph, const anything *any, CHAR_P menuChar, CHAR_P groupAcc, int attr, const char *inStr, int preselected) { #if defined(__SC__) || defined(__MRC__) #pragma unused(glyph) #endif NhWindow *aWin = &theWindows[win]; const char *str; char locStr[4 + BUFSZ]; MacMHMenuItem *item; if (!inStr) return; if (any->a_void != 0) { #define kMenuSizeBump 26 if (!aWin->miSize) { aWin->menuInfo = (MacMHMenuItem **) NewHandle( sizeof(MacMHMenuItem) * kMenuSizeBump); if (!aWin->menuInfo) { error("Can't alloc menu handle"); return; } aWin->menuSelected = (short **) NewHandle(sizeof(short) * kMenuSizeBump); if (!aWin->menuSelected) { error("Can't alloc menu select handle"); return; } aWin->miSize = kMenuSizeBump; } if (aWin->miLen >= aWin->miSize) { SetHandleSize((Handle) aWin->menuInfo, sizeof(MacMHMenuItem) * (aWin->miLen + kMenuSizeBump)); if (MemError()) { error("Can't resize menu handle"); return; } SetHandleSize((Handle) aWin->menuSelected, sizeof(short) * (aWin->miLen + kMenuSizeBump)); if (MemError()) { error("Can't resize menu select handle"); return; } aWin->miSize += kMenuSizeBump; } if (menuChar == 0) { if (('a' <= aWin->menuChar && aWin->menuChar <= 'z') || ('A' <= aWin->menuChar && aWin->menuChar <= 'Z')) { menuChar = aWin->menuChar++; if (menuChar == 'z') aWin->menuChar = 'A'; } } Sprintf(locStr, "%c - %s", (menuChar ? menuChar : ' '), inStr); str = locStr; HLock((char **) aWin->menuInfo); HLock((char **) aWin->menuSelected); (*aWin->menuSelected)[aWin->miLen] = preselected; item = &(*aWin->menuInfo)[aWin->miLen]; aWin->miLen++; item->id = *any; item->accelerator = menuChar; item->groupAcc = groupAcc; item->line = aWin->y_size; HUnlock((char **) aWin->menuInfo); HUnlock((char **) aWin->menuSelected); } else str = inStr; putstr(win, attr, str); } /* * End a menu in this window, window must a type NHW_MENU. * str is a list of cancel characters (values that may be input) * morestr is a prompt to display, rather than the default. * str and morestr might be ignored by some ports. */ void mac_end_menu(winid win, const char *morestr) { Str255 buf; NhWindow *aWin = &theWindows[win]; buf[0] = 0; if (morestr) C2P(morestr, buf); SetWTitle(aWin->its_window, buf); } int mac_select_menu(winid win, int how, menu_item **selected_list) { int c; NhWindow *aWin = &theWindows[win]; WindowPtr theWin = aWin->its_window; inSelect = win; mac_display_nhwindow(win, FALSE); aWin->how = (short) how; for (;;) { c = map_menu_cmd(mac_nhgetch()); if (c == CHAR_ESC) { /* deselect everything */ aWin->miSelLen = 0; break; } else if (ClosingWindowChar(c)) { break; } else { nhbell(); } } HideWindow(theWin); if (aWin->miSelLen) { menu_item *mp; MacMHMenuItem *mi; *selected_list = mp = (menu_item *) alloc(aWin->miSelLen * sizeof(menu_item)); HLock((char **) aWin->menuInfo); HLock((char **) aWin->menuSelected); for (c = 0; c < aWin->miSelLen; c++) { mi = &(*aWin->menuInfo)[(*aWin->menuSelected)[c]]; mp->item = mi->id; mp->count = -1L; mp++; } HUnlock((char **) aWin->menuInfo); HUnlock((char **) aWin->menuSelected); } else *selected_list = 0; inSelect = WIN_ERR; return aWin->miSelLen; } #include "dlb.h" static void mac_display_file(name, complain) const char *name; /* not ANSI prototype because of boolean parameter */ boolean complain; { Ptr buf; int win; dlb *fp = dlb_fopen(name, "r"); if (fp) { long l = dlb_fseek(fp, 0, SEEK_END); (void) dlb_fseek(fp, 0, 0L); buf = NewPtr(l + 1); if (buf) { l = dlb_fread(buf, 1, l, fp); if (l > 0) { buf[l] = '\0'; win = create_nhwindow(NHW_TEXT); if (WIN_ERR == win) { if (complain) error("Cannot make window."); } else { putstr(win, 0, buf); display_nhwindow(win, FALSE); } } DisposePtr(buf); } dlb_fclose(fp); } else if (complain) error("Cannot open %s.", name); } void port_help() { display_file(PORT_HELP, TRUE); } static void mac_unimplemented(void) { } static void mac_suspend_nhwindows(const char *foo) { #if defined(__SC__) || defined(__MRC__) #pragma unused(foo) #endif /* Can't really do that :-) */ } int try_key_queue(char *bufp) { if (keyQueueCount) { char ch; for (ch = GetFromKeyQueue();; ch = GetFromKeyQueue()) { if (ch == CHAR_LF || ch == CHAR_CR) ch = 0; *bufp++ = ch; if (ch == 0) break; } return 1; } return 0; } /********************************************************************** * Base window */ static void BaseClick(NhWindow *wind, Point pt, UInt32 modifiers) { pt.h = pt.h / wind->char_width + 1; pt.v = pt.v / wind->row_height; clicked_mod = (modifiers & shiftKey) ? CLICK_2 : CLICK_1; if (strchr(topl_resp, *click_to_cmd(pt.h, pt.v, clicked_mod))) nhbell(); else { #if 1 //!TARGET_API_MAC_CARBON if (cursor_locked) while (WaitMouseUp()) /*SystemTask()*/; #endif gClickedToMove = TRUE; clicked_pos = pt; } return; } static void BaseCursor(NhWindow *wind, Point pt) { char *dir_bas, *dir; CursHandle ch; if (cursor_locked) dir = (char *) 0; else { dir_bas = (char *) Cmd.dirchars; dir = strchr(dir_bas, *click_to_cmd(pt.h / wind->char_width + 1, pt.v / wind->row_height, CLICK_1)); } ch = GetCursor(dir ? dir - dir_bas + 513 : 512); if (ch) { HLock((Handle) ch); SetCursor(*ch); HUnlock((Handle) ch); } else { SetCursor(&qdarrow); } return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus BaseEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); AddToKeyQueue(topl_resp_key(ch), TRUE); return (noErr); } case kEventClassMouse: { CGrafPtr saveport; GDHandle savedev; Point pt; switch (GetEventKind(event)) { case kEventMouseMoved: GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); BaseCursor(wind, pt); return (eventNotHandledErr); } break; } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); image_tty(NULL, wind->its_window); return (noErr); case kEventWindowHandleContentClick: { CGrafPtr saveport; GDHandle savedev; Point pt; UInt32 modifiers; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); BaseClick(wind, pt, modifiers); return (noErr); } case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macClickTerm(EventRecord *theEvent, WindowPtr theWindow) { Point where = theEvent->where; GlobalToLocal(&where); BaseClick(GetNhWin(theWindow), where, theEvent->modifiers); return; } static void macCursorTerm(EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) { GrafPtr gp; Point where = theEvent->where; Rect r = { 0, 0, 1, 1 }; GetPort(&gp); SetPortWindowPort(theWindow); GlobalToLocal(&where); BaseCursor(GetNhWin(theWindow), where); OffsetRect(&r, theEvent->where.h, theEvent->where.v); RectRgn(mouseRgn, &r); SetPort(gp); return; } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Status subwindow */ /********************************************************************** * Map subwindow */ /********************************************************************** * Message window */ static void MsgClick(NhWindow *wind, Point pt) { int r_idx = 0; while (topl_resp[r_idx]) { Rect frame; topl_resp_rect(r_idx, &frame); InsetRect(&frame, 1, 1); if (PtInRect(pt, &frame)) { Boolean in_btn = true; InvertRect(&frame); while (WaitMouseUp()) { #if !TARGET_API_MAC_CARBON SystemTask(); #endif GetMouse(&pt); if (PtInRect(pt, &frame) != in_btn) { in_btn = !in_btn; InvertRect(&frame); } } if (in_btn) { InvertRect(&frame); AddToKeyQueue(topl_resp[r_idx], 1); } return; } ++r_idx; } return; } static void MsgUpdate(NhWindow *wind) { RgnHandle org_clip = NewRgn(), clip = NewRgn(); Rect r; int l; GetClip(org_clip); GetWindowBounds(wind->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); DrawControls(wind->its_window); DrawGrowIcon(wind->its_window); for (l = 0; topl_resp[l]; l++) { StringPtr name; unsigned char tmp[2]; FontInfo font; Rect frame; topl_resp_rect(l, &frame); switch (topl_resp[l]) { case 'y': name = "\pyes"; break; case 'n': name = "\pno"; break; case 'N': name = "\pNone"; break; case 'a': name = "\pall"; break; case 'q': name = "\pquit"; break; case CHAR_ANY: name = "\pany key"; break; default: tmp[0] = 1; tmp[1] = topl_resp[l]; name = tmp; break; } TextFont(kFontIDGeneva); TextSize(9); GetFontInfo(&font); MoveTo((frame.left + frame.right - StringWidth(name)) / 2, (frame.top + frame.bottom + font.ascent - font.descent - font.leading - 1) / 2); DrawString(name); PenNormal(); if (l == topl_def_idx) PenSize(2, 2); FrameRoundRect(&frame, 4, 4); } r.right -= SBARWIDTH; r.bottom -= SBARHEIGHT; /* Clip to the portrect - scrollbar/growicon *before* adjusting the rect to be larger than the size of the window (!) */ RectRgn(clip, &r); SectRgn(clip, org_clip, clip); if (r.right < MIN_RIGHT) r.right = MIN_RIGHT; r.top -= wind->scrollPos * wind->row_height; #if 0 /* If you enable this band of code (and disable the next band), you will get fewer flickers but a slower performance while drawing the dot line. */ { RgnHandle dotl_rgn = NewRgn(); Rect dotl; dotl.left = r.left; dotl.right = r.right; dotl.bottom = r.top + aWin->save_lin * aWin->row_height; dotl.top = dotl.bottom - 1; FillRect(&dotl, &qd.gray); RectRgn(dotl_rgn, &dotl); DiffRgn(clip, dotl_rgn, clip); DisposeRgn(dotl_rgn); SetClip(clip); } #endif if (in_topl_mode()) { RgnHandle topl_rgn = NewRgn(); Rect topl_r = r; topl_r.top += (wind->y_size - 1) * wind->row_height; l = (*top_line)->destRect.right - (*top_line)->destRect.left; (*top_line)->viewRect = topl_r; (*top_line)->destRect = topl_r; if (l != topl_r.right - topl_r.left) TECalText(top_line); TEUpdate(&topl_r, top_line); RectRgn(topl_rgn, &topl_r); DiffRgn(clip, topl_rgn, clip); DisposeRgn(topl_rgn); SetClip(clip); } DisposeRgn(clip); TextFont(wind->font_number); TextSize(wind->font_size); HLock(wind->windowText); TETextBox(*wind->windowText, wind->windowTextLen, &r, teJustLeft); HUnlock(wind->windowText); #if !TARGET_API_MAC_CARBON r.bottom = r.top + aWin->save_lin * aWin->row_height; r.top = r.bottom - 1; FillRect(&r, (void *) &qd.gray); #endif SetClip(org_clip); DisposeRgn(org_clip); return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus MsgEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassControl: { ControlRef control; ControlID id; switch (GetEventKind(event)) { case kEventControlHit: GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); GetControlID(control, &id); /* TODO... */ return (noErr); } break; } case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); AddToKeyQueue(topl_resp_key(ch), TRUE); return (noErr); } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); MsgUpdate(wind); return (noErr); case kEventWindowHandleContentClick: { CGrafPtr saveport; GDHandle savedev; Point pt; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); MsgClick(wind, pt); return (noErr); } case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macClickMessage(EventRecord *theEvent, WindowPtr theWindow) { Point mouse = theEvent->where; GlobalToLocal(&mouse); MsgClick(GetNhWin(theWindow), mouse); macClickText(theEvent, theWindow); } static short macUpdateMessage(EventRecord *theEvent, WindowPtr theWindow) { if (!theEvent) return 0; MsgUpdate(GetNhWin(theWindow)); return 0; } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Menu windows */ static void MenwKey(NhWindow *wind, char ch) { MacMHMenuItem *mi; int i; ch = filter_scroll_key(ch, wind); if (!ch) return; if (ClosingWindowChar(ch)) { AddToKeyQueue(CHAR_CR, 1); return; } if (!wind || !wind->menuInfo) return; HLock((char **) wind->menuInfo); for (i = 0, mi = *wind->menuInfo; i < wind->miLen; i++, mi++) { if (mi->accelerator == ch) { ToggleMenuListItemSelected(wind, i); if (mi->line >= wind->scrollPos && mi->line <= wind->y_size) { SetPortWindowPort(wind->its_window); ToggleMenuSelect(wind, mi->line - wind->scrollPos); } /* Dismiss window if only picking one item */ if (wind->how != PICK_ANY) AddToKeyQueue(CHAR_CR, 1); break; } } HUnlock((char **) wind->menuInfo); /* add key if didn't find it in menu and not filtered */ return; } static void MenwClick(NhWindow *wind, Point pt) { Rect wrect; GetWindowBounds(wind->its_window, kWindowContentRgn, &wrect); OffsetRect(&wrect, -wrect.left, -wrect.top); if (inSelect != WIN_ERR && wind->how != PICK_NONE) { short currentRow = -1, previousRow = -1; short previousItem = -1, item = -1; Boolean majorSelectState, firstRow = TRUE; do { #if !TARGET_API_MAC_CARBON SystemTask(); #endif GetMouse(&pt); currentRow = pt.v / wind->row_height; if (pt.h < wrect.left || pt.h > wrect.right || pt.v < 0 || pt.v > wrect.bottom || currentRow >= wind->y_size) { continue; /* not in window range */ } item = ListCoordinateToItem(wind, currentRow); if (item != previousItem) { /* Implement typical Mac multiple-selection behavior * (ie, not the UI implemented by the Finder) */ Boolean itemIsSelected = (ListItemSelected(wind, item) >= 0); if (firstRow) { /* this is first valid row, so major state is opposite of * what this row is */ majorSelectState = !itemIsSelected; firstRow = FALSE; } if (wind->how == PICK_ONE && previousItem != -1) { /* if previous row was selected and we're only selecting * one object, * deselect previous row! */ ToggleMenuListItemSelected(wind, previousItem); ToggleMenuSelect(wind, previousRow); previousItem = -1; } if (item == -1) continue; /* header line */ if (majorSelectState != itemIsSelected) { ToggleMenuListItemSelected(wind, item); ToggleMenuSelect(wind, currentRow); } previousRow = currentRow; previousItem = item; } } while (StillDown()); /* Dismiss window if only picking one item */ if (wind->how == PICK_ONE) AddToKeyQueue(CHAR_CR, 1); } return; } static void MenwUpdate(NhWindow *wind) { int i, line; MacMHMenuItem *mi; TextUpdate(wind); HLock((Handle) wind->menuInfo); HLock((Handle) wind->menuSelected); for (i = 0; i < wind->miSelLen; i++) { mi = &(*wind->menuInfo)[(*wind->menuSelected)[i]]; line = mi->line; if (line > wind->scrollPos && line <= wind->y_size) ToggleMenuSelect(wind, line - wind->scrollPos); } HUnlock((Handle) wind->menuInfo); HUnlock((Handle) wind->menuSelected); return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus MenwEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassControl: { ControlRef control; ControlID id; switch (GetEventKind(event)) { case kEventControlHit: GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); GetControlID(control, &id); /* TODO... */ return (noErr); } break; } case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); MenwKey(wind, ch); return (noErr); } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); MenwUpdate(wind); return (noErr); case kEventWindowHandleContentClick: { CGrafPtr saveport; GDHandle savedev; Point pt; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pt); GetGWorld(&saveport, &savedev); SetPortWindowPort(wind->its_window); GlobalToLocal(&pt); SetGWorld(saveport, savedev); MenwClick(wind, pt); return (noErr); } case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macKeyMenu(EventRecord *theEvent, WindowPtr theWindow) { MenwKey(GetNhWin(theWindow), theEvent->message & 0xff); return; } static void macClickMenu(EventRecord *theEvent, WindowRef theWindow) { Point p; NhWindow *aWin = GetNhWin(theWindow); if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) { short code; ControlHandle theBar; p = theEvent->where; GlobalToLocal(&p); code = FindControl(p, theWindow, &theBar); if (code) { DoScrollBar(p, code, theBar, aWin); return; } } MenwClick(aWin, theEvent->where); } static short macUpdateMenu(EventRecord *theEvent, WindowPtr theWindow) { MenwUpdate(GetNhWin(theWindow)); return 0; } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Text windows */ static void TextKey(NhWindow *wind, char ch) { ch = filter_scroll_key(ch, wind); if (!ch) return; if (inSelect == WIN_ERR && ClosingWindowChar(ch)) { HideWindow(wind->its_window); mac_destroy_nhwindow(wind - theWindows); } else AddToKeyQueue(topl_resp_key(ch), TRUE); return; } static void TextUpdate(NhWindow *wind) { Rect r, r2; RgnHandle h; Boolean vis; GetWindowBounds(wind->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); r2 = r; r2.left = r2.right - SBARWIDTH; r2.right += 1; r2.top -= 1; vis = (r2.bottom > r2.top + 50); draw_growicon_vert_only(wind->its_window); DrawControls(wind->its_window); h = (RgnHandle) 0; if (vis && (h = NewRgn())) { RgnHandle tmp = NewRgn(); if (!tmp) { DisposeRgn(h); h = (RgnHandle) 0; } else { GetClip(h); RectRgn(tmp, &r2); DiffRgn(h, tmp, tmp); SetClip(tmp); DisposeRgn(tmp); } } if (r.right < MIN_RIGHT) r.right = MIN_RIGHT; r.top -= wind->scrollPos * wind->row_height; r.right -= SBARWIDTH; HLock(wind->windowText); TETextBox(*wind->windowText, wind->windowTextLen, &r, teJustLeft); HUnlock(wind->windowText); if (h) { SetClip(h); DisposeRgn(h); } return; } #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus TextEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { NhWindow *wind = (NhWindow *) userdata; switch (GetEventClass(event)) { case kEventClassControl: { ControlRef control; ControlID id; switch (GetEventKind(event)) { case kEventControlHit: GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); GetControlID(control, &id); /* TODO... */ return (noErr); } break; } case kEventClassKeyboard: { char ch; UInt32 modifiers; GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ch); GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (modifiers & cmdKey) return (eventNotHandledErr); TextKey(wind, ch); return (noErr); } case kEventClassWindow: switch (GetEventKind(event)) { case kEventWindowDrawContent: CallNextEventHandler(nexthandler, event); TextUpdate(wind); return (noErr); case kEventWindowClose: /* TODO... */ break; } break; } return (eventNotHandledErr); } #else static void macKeyText(EventRecord *theEvent, WindowPtr theWindow) { TextKey(GetNhWin(theWindow), theEvent->message & 0xff); return; } static void macClickText(EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin(theWindow); if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) { short code; Point p = theEvent->where; ControlHandle theBar; GlobalToLocal(&p); code = FindControl(p, theWindow, &theBar); if (code) { DoScrollBar(p, code, theBar, aWin); } } } #endif /* !TARGET_API_MAC_CARBON */ /********************************************************************** * Global events */ #if 0 // TARGET_API_MAC_CARBON static pascal OSStatus GlobalEvent(EventHandlerCallRef nexthandler, EventRef event, void *userdata) { switch (GetEventClass(event)) { case kEventClassCommand: return (eventNotHandledErr); } return (eventNotHandledErr); } #else static short macDoNull(EventRecord *theEvent, WindowPtr theWindow) { return 0; } /* * Note; theWindow may very well be null here, since keyDown may call * it when theres no window !!! */ /* NOT_IN_CARBON */ static void GeneralKey(EventRecord *theEvent, WindowPtr theWindow) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theWindow) #endif #if 0 trans_num_keys (theEvent); #endif AddToKeyQueue(topl_resp_key(theEvent->message & 0xff), TRUE); } static void HandleKey(EventRecord *theEvent) { WindowPtr theWindow = FrontWindow(); if (theEvent->modifiers & cmdKey) { if (theEvent->message & 0xff == '.') { /* Flush key queue */ keyQueueCount = keyQueueWrite = keyQueueRead = 0; theEvent->message = '\033'; goto dispatchKey; } else { UndimMenuBar(); DoMenuEvt(MenuKey(theEvent->message & 0xff)); } } else { dispatchKey: if (theWindow) { int kind = GetWindowKind(theWindow) - WIN_BASE_KIND; winKeyFuncs[kind](theEvent, theWindow); } else { GeneralKey(theEvent, (WindowPtr) 0); } } } #endif /* !TARGET_API_MAC_CARBON */ static void HandleClick(EventRecord *theEvent) { int code; unsigned long l; WindowPtr theWindow; NhWindow *aWin; Rect r; Boolean not_inSelect; InsetRect(GetRegionBounds(GetGrayRgn(), &r), 4, 4); code = FindWindow(theEvent->where, &theWindow); aWin = GetNhWin(theWindow); not_inSelect = (inSelect == WIN_ERR || aWin - theWindows == inSelect); switch (code) { case inContent: #if 1 //!TARGET_API_MAC_CARBON if (not_inSelect) { int kind = GetWindowKind(theWindow) - WIN_BASE_KIND; winCursorFuncs[kind](theEvent, theWindow, gMouseRgn); SelectWindow(theWindow); SetPortWindowPort(theWindow); winClickFuncs[kind](theEvent, theWindow); } else { nhbell(); } #endif break; case inDrag: if (not_inSelect) { SetCursor(&qdarrow); DragWindow(theWindow, theEvent->where, &r); SaveWindowPos(theWindow); } else { nhbell(); } break; case inGrow: if (not_inSelect) { SetCursor(&qdarrow); SetRect(&r, 80, 2 * aWin->row_height + 1, r.right, r.bottom); if (aWin == theWindows + WIN_MESSAGE) r.top += SBARHEIGHT; l = GrowWindow(theWindow, theEvent->where, &r); SizeWindow(theWindow, l & 0xffff, l >> 16, FALSE); SaveWindowSize(theWindow); SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); InvalWindowRect(theWindow, &r); if (aWin->scrollBar) { DrawScrollbar(aWin); } } else { nhbell(); } break; case inGoAway: WindowGoAway(theEvent, theWindow); break; case inMenuBar: DoMenuEvt(MenuSelect(theEvent->where)); break; #if !TARGET_API_MAC_CARBON case inSysWindow: SystemClick(theEvent, theWindow); #endif default: break; } } #if 1 //!TARGET_API_MAC_CARBON static short GeneralUpdate(EventRecord *theEvent, WindowPtr theWindow) { if (!theEvent) return 0; TextUpdate(GetNhWin(theWindow)); return 0; } #endif static void HandleUpdate(EventRecord *theEvent) { WindowPtr theWindow = (WindowPtr) theEvent->message; NhWindow *aWin = GetNhWin(theWindow); Rect r; #if 1 //!TARGET_API_MAC_CARBON EventRecord fake; #endif char existing_update_region = FALSE; Rect rect; if (theWindow == _mt_window) { existing_update_region = (get_invalid_region(theWindow, &rect) == noErr); } BeginUpdate(theWindow); SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); EraseRect(&r); #if 0 // TARGET_API_MAC_CARBON switch (GetWindowKind(theWindow) - WIN_BASE_KIND) { case NHW_BASE: case NHW_MAP: case NHW_STATUS: image_tty(NULL, theWindow); break; case NHW_MESSAGE: MsgUpdate(GetNhWin(theWindow)); break; case NHW_MENU: MenwUpdate(GetNhWin(theWindow)); break; case NHW_TEXT: TextUpdate(GetNhWin(theWindow)); break; } #else winUpdateFuncs[GetWindowKind(theWindow) - WIN_BASE_KIND](&fake, theWindow); #endif if (theWindow == _mt_window && existing_update_region) { set_invalid_region(theWindow, &rect); } aWin->drawn = TRUE; EndUpdate(theWindow); } #if 1 //!TARGET_API_MAC_CARBON static void GeneralCursor(EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) { #if defined(__SC__) || defined(__MRC__) #pragma unused(theWindow) #endif Rect r = { -1, -1, 2, 2 }; SetCursor(&qdarrow); OffsetRect(&r, theEvent->where.h, theEvent->where.v); RectRgn(mouseRgn, &r); } static void DoOsEvt(EventRecord *theEvent) { WindowRef win; short code; if ((theEvent->message & 0xff000000) == 0xfa000000) { /* Mouse Moved */ code = FindWindow(theEvent->where, &win); if (code != inContent) { Rect r = { -1, -1, 2, 2 }; SetCursor(&qdarrow); OffsetRect(&r, theEvent->where.h, theEvent->where.v); RectRgn(gMouseRgn, &r); } else { #if 1 //!TARGET_API_MAC_CARBON int kind = GetWindowKind(win) - WIN_BASE_KIND; if (kind >= 0 && kind <= NHW_TEXT) { winCursorFuncs[kind](theEvent, win, gMouseRgn); } #endif } } } #endif /* !TARGET_API_MAC_CARBON */ void HandleEvent(EventRecord *theEvent) { switch (theEvent->what) { #if 1 //!TARGET_API_MAC_CARBON case autoKey: case keyDown: HandleKey(theEvent); break; #endif case updateEvt: HandleUpdate(theEvent); break; case mouseDown: HandleClick(theEvent); break; #if !TARGET_API_MAC_CARBON case diskEvt: if ((theEvent->message & 0xffff0000) != 0) { Point p = { 150, 150 }; (void) DIBadMount(p, theEvent->message); } break; #endif #if !TARGET_API_MAC_CARBON case osEvt: DoOsEvt(theEvent); break; #endif case kHighLevelEvent: AEProcessAppleEvent(theEvent); default: break; } } /********************************************************************** * Interface definition, for windows.c */ struct window_procs mac_procs = { "mac", WC_COLOR | WC_HILITE_PET | WC_FONT_MAP | WC_FONT_MENU | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_TEXT | WC_FONTSIZ_MAP | WC_FONTSIZ_MENU | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_TEXT, 0L, mac_init_nhwindows, mac_unimplemented, /* see macmenu.c:mac_askname() for player selection */ mac_askname, mac_get_nh_event, mac_exit_nhwindows, mac_suspend_nhwindows, mac_unimplemented, mac_create_nhwindow, mac_clear_nhwindow, mac_display_nhwindow, mac_destroy_nhwindow, mac_curs, mac_putstr, genl_putmixed, mac_display_file, mac_start_menu, mac_add_menu, mac_end_menu, mac_select_menu, genl_message_menu, mac_unimplemented, mac_get_nh_event, mac_get_nh_event, #ifdef CLIPPING mac_cliparound, #endif #ifdef POSITIONBAR donull, #endif tty_print_glyph, tty_raw_print, tty_raw_print_bold, mac_nhgetch, mac_nh_poskey, tty_nhbell, mac_doprev_message, mac_yn_function, mac_getlin, mac_get_ext_cmd, mac_number_pad, mac_delay_output, #ifdef CHANGE_COLOR tty_change_color, tty_change_background, set_tty_font_name, tty_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ 0, // mac_start_screen, 0, // mac_end_screen, genl_outrip, genl_preference_update, genl_can_suspend_no, }; /*macwin.c*/ nethack-3.6.0/sys/mac/mgetline.c0000664000076400007660000000354612536476415015510 0ustar paxedpaxed/* NetHack 3.6 mgetline.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mactty.h" #include "macwin.h" #include "macpopup.h" #include "func_tab.h" extern int NDECL(extcmd_via_menu); /* cmd.c */ typedef Boolean FDECL((*key_func), (unsigned char)); int get_line_from_key_queue(char *bufp) { *bufp = 0; if (try_key_queue(bufp)) { while (*bufp) { if (*bufp == 10 || *bufp == 13) { *bufp = 0; } bufp++; } return true; } return false; } static void topl_getlin(const char *query, char *bufp, Boolean ext) { if (get_line_from_key_queue(bufp)) return; enter_topl_mode((char *) query); while (topl_key(nhgetch(), ext)) ; leave_topl_mode(bufp); } /* * Read a line closed with '\n' into the array char bufp[BUFSZ]. * (The '\n' is not stored. The string is closed with a '\0'.) * Reading can be interrupted by an escape ('\033') - now the * resulting string is "\033". */ void mac_getlin(const char *query, char *bufp) { topl_getlin(query, bufp, false); } /* Read in an extended command - doing command line completion for * when enough characters have been entered to make a unique command. * This is just a modified getlin() followed by a lookup. -jsb */ int mac_get_ext_cmd() { char bufp[BUFSZ]; int i; if (iflags.extmenu) return extcmd_via_menu(); topl_getlin("# ", bufp, true); for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++) if (!strcmp(bufp, extcmdlist[i].ef_txt)) break; if (extcmdlist[i].ef_txt == (char *) 0) i = -1; /* not found */ return i; } /* macgetline.c */ nethack-3.6.0/sys/mac/mmodal.c0000664000076400007660000000147512536476415015154 0ustar paxedpaxed/* NetHack 3.6 mmodal.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ #if 1 /*!TARGET_API_MAC_CARBON*/ #include #include #else #include #endif #include "macpopup.h" /* Flash a dialog button when its accelerator key is pressed */ void FlashButton(DialogRef wind, short item) { short type; Handle handle; Rect rect; unsigned long ticks; /* Apple recommends 8 ticks */ GetDialogItem(wind, item, &type, &handle, &rect); HiliteControl((ControlHandle) handle, kControlButtonPart); Delay(8, &ticks); HiliteControl((ControlHandle) handle, 0); return; } nethack-3.6.0/sys/mac/mrecover.c0000664000076400007660000010405512536476415015523 0ustar paxedpaxed/* NetHack 3.6 mrecover.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) David Hairston, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* Macintosh Recovery Application */ /* based on code in util/recover.c. the significant differences are: * - GUI vs. CLI. the vast majority of code here supports the GUI. * - Mac toolbox equivalents are used in place of ANSI functions. * - void restore_savefile(void) is event driven. * - integral type substitutions here and there. */ /* * Think C 5.0.4 project specs: * signature: 'nhRc' * SIZE (-1) info: flags: 0x5880, size: 65536L/65536L (64k/64k) * libraries: MacTraps [yes], MacTraps2 (HFileStuff) [yes], ANSI [no] * compatibility: system 6 and system 7 * misc: sizeof(int): 2, "\p": unsigned char, enum size varies, * prototypes required, type checking enforced, no optimizers, * FAR CODE [no], FAR DATA [no], SEPARATE STRS [no], single segment, * short macsbug symbols */ /* * To do (maybe, just maybe): * - Merge with the code in util/recover.c. * - Document launch (e.g. GUI equivalent of 'recover basename'). * - Drag and drop. * - Internal memory tweaks (stack and heap usage). * - Use status file to allow resuming aborted recoveries. * - Bundle 'LEVL' files with recover (easier document launch). * - Prohibit recovering games "in progress". * - Share AppleEvents with NetHack to auto-recover crashed games. */ #include "config.h" /**** Toolbox defines ****/ /* MPW C headers (99.44% pure) */ #include #include #include #include #ifdef applec #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef THINK /* glue for System 7 Icon Family call (needed by Think C 5.0.4) \ */ pascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, long selector) = { 0x303C, 0x0501, 0xABC9 }; #endif /**** Application defines ****/ /* Memory */ typedef struct memBytes /* format of 'memB' resource, preloaded/locked */ { short memReserved; short memCleanup; /* 4 - memory monitor activity limit */ long memPreempt; /* 32k - start iff FreeMem() > */ long memWarning; /* 12k - warn if MaxMem() < */ long memAbort; /* 4k - abort if MaxMem() < */ long memIOBuf; /* 16k - read/write buffer size */ } memBytes, *memBytesPtr, **memBytesHandle; #define membID 128 /* 'memB' resource ID */ /* Cursor */ #define CURS_FRAME 4L /* 1/15 second - spin cursor */ #define CURS_LATENT 60L /* pause before spin cursor */ #define curs_Init (-1) /* token for set arrow */ #define curs_Total 8 /* maybe 'acur' would be better */ #define cursorOffset 128 /* GetCursor(cursorOffset + i) */ /* Menu */ enum { mbar_Init = -1, mbarAppl, /* normal mode */ mbarRecover, /* in recovery mode */ mbarDA /* DA in front mode */ }; enum { menuApple, menuFile, menuEdit, menu_Total, muidApple = 128, muidFile, muidEdit }; enum { /* Apple menu */ mitmAbout = 1, mitmHelp, ____128_1, /* File menu */ mitmOpen = 1, ____129_1, mitmClose_DA, ____129_2, mitmQuit /* standard minimum required Edit menu */ }; /* Alerts */ enum { alrtNote, /* general messages */ alrtHelp, /* help message */ alrt_Total, alertAppleMenu = 127, /* menuItem to alert ID offset */ alidNote, alidHelp }; #define aboutBufSize 80 /* i.e. 2 lines of 320 pixels */ /* Notification */ #define nmBufSize (32 + aboutBufSize + 32) typedef struct notifRec { NMRec nmr; struct notifRec *nmNext; short nmDispose; unsigned char nmBuf[nmBufSize]; } notifRec, *notifPtr; #define nmPending nmRefCon /* &in.Notify */ #define iconNotifyID 128 #define ics_1_and_4 0x00000300 /* Dialogs */ enum { dlogProgress = 256 }; enum { uitmThermo = 1 }; enum { initItem, invalItem, drawItem }; /* Miscellaneous */ typedef struct modeFlags { short Front; /* fg/bg event handling */ short Notify; /* level of pending NM notifications */ short Dialog; /* a modeless dialog is open */ short Recover; /* restoration progress index */ } modeFlags; /* convenient define to allow easier (for me) parsing of 'vers' resource */ typedef struct versXRec { NumVersion numVers; short placeCode; unsigned char versStr[]; /* (small string)(large string) */ } versXRec, *versXPtr, **versXHandle; /**** Global variables ****/ modeFlags in = { 1 }; /* in Front */ EventRecord wnEvt; SysEnvRec sysEnv; unsigned char aboutBuf[aboutBufSize]; /* vers 1 "Get Info" string */ memBytesPtr pBytes; /* memory management */ unsigned short memActivity; /* more memory management */ MenuHandle mHnd[menu_Total]; CursPtr cPtr[curs_Total]; /* busy cursors */ unsigned long timeCursor; /* next cursor frame time */ short oldCursor = curs_Init; /* see adjustGUI() below */ notifPtr pNMQ; /* notification queue pointer */ notifRec nmt; /* notification template */ DialogTHndl thermoTHnd; DialogRecord dlgThermo; /* progress thermometer */ #define DLGTHM ((DialogPtr) &dlgThermo) #define WNDTHM ((WindowPtr) &dlgThermo) #define GRFTHM ((GrafPtr) &dlgThermo) Point sfGetWhere; /* top left corner of get file dialog */ Ptr pIOBuf; /* read/write buffer pointer */ short vRefNum; /* SFGetFile working directory/volume refnum */ long dirID; /* directory i.d. */ NMUPP nmCompletionUPP; /* UPP for nmCompletion */ FileFilterUPP basenameFileFilterUPP; /* UPP for basenameFileFilter */ UserItemUPP drawThermoUPP; /* UPP for progress callback */ #define MAX_RECOVER_COUNT 256 #define APP_NAME_RES_ID (-16396) /* macfile.h */ #define PLAYER_NAME_RES_ID 1001 /* macfile.h */ /* variables from util/recover.c */ #define SAVESIZE FILENAME unsigned char savename[SAVESIZE]; /* originally a C string */ unsigned char lock[256]; /* pascal string */ int hpid; /* NetHack (unix-style) process i.d. */ short saveRefNum; /* save file descriptor */ short gameRefNum; /* level 0 file descriptor */ short levRefNum; /* level n file descriptor */ /**** Prototypes ****/ static void warmup(void); static Handle alignTemplate(ResType, short, short, short, Point *); pascal void nmCompletion(NMRec *); static void noteErrorMessage(unsigned char *, unsigned char *); static void note(short, short, unsigned char *); static void adjustGUI(void); static void adjustMemory(void); static void optionMemStats(void); static void RecoverMenuEvent(long); static void eventLoop(void); static void cooldown(void); pascal void drawThermo(WindowPtr, short); static void itemizeThermo(short); pascal Boolean basenameFileFilter(ParmBlkPtr); static void beginRecover(void); static void continueRecover(void); static void endRecover(void); static short saveRezStrings(void); /* analogous prototypes from util/recover.c */ static void set_levelfile_name(long); static short open_levelfile(long); static short create_savefile(unsigned char *); static void copy_bytes(short, short); static void restore_savefile(void); /* auxiliary prototypes */ static long read_levelfile(short, Ptr, long); static long write_savefile(short, Ptr, long); static void close_file(short *); static void unlink_file(unsigned char *); /**** Routines ****/ main() { /* heap adjust */ MaxApplZone(); MoreMasters(); MoreMasters(); /* manager initialization */ InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(0L); InitCursor(); nmCompletionUPP = NewNMProc(nmCompletion); basenameFileFilterUPP = NewFileFilterProc(basenameFileFilter); drawThermoUPP = NewUserItemProc(drawThermo); /* get system environment, notification requires 6.0 or better */ (void) SysEnvirons(curSysEnvVers, &sysEnv); if (sysEnv.systemVersion < 0x0600) { ParamText("\pAbort: System 6.0 is required", "\p", "\p", "\p"); (void) Alert(alidNote, (ModalFilterUPP) 0L); ExitToShell(); } warmup(); eventLoop(); /* normally these routines are never reached from here */ cooldown(); ExitToShell(); return 0; } static void warmup() { short i; /* pre-System 7 MultiFinder hack for smooth launch */ for (i = 0; i < 10; i++) { if (WaitNextEvent(osMask, &wnEvt, 2L, (RgnHandle) 0L)) if (((wnEvt.message & osEvtMessageMask) >> 24) == suspendResumeMessage) in.Front = (wnEvt.message & resumeFlag); } #if 0 // ??? /* clear out the Finder info */ { short message, count; CountAppFiles(&message, &count); while(count) ClrAppFiles(count--); } #endif /* fill out the notification template */ nmt.nmr.qType = nmType; nmt.nmr.nmMark = 1; nmt.nmr.nmSound = (Handle) -1L; /* system beep */ nmt.nmr.nmStr = nmt.nmBuf; nmt.nmr.nmResp = nmCompletionUPP; nmt.nmr.nmPending = (long) &in.Notify; #if 1 { /* get the app name */ ProcessInfoRec info; ProcessSerialNumber psn; info.processInfoLength = sizeof(info); info.processName = nmt.nmBuf; info.processAppSpec = NULL; GetCurrentProcess(&psn); GetProcessInformation(&psn, &info); } #else /* prepend app name (31 chars or less) to notification buffer */ { short apRefNum; Handle apParams; GetAppParms(*(Str255 *) &nmt.nmBuf, &apRefNum, &apParams); } #endif /* add formatting (two line returns) */ nmt.nmBuf[++(nmt.nmBuf[0])] = '\r'; nmt.nmBuf[++(nmt.nmBuf[0])] = '\r'; /**** note() is usable now but not aesthetically complete ****/ /* get notification icon */ if (sysEnv.systemVersion < 0x0700) { if (!(nmt.nmr.nmIcon = GetResource('SICN', iconNotifyID))) note(nilHandleErr, 0, "\pNil SICN Handle"); } else { if (GetIconSuite(&nmt.nmr.nmIcon, iconNotifyID, ics_1_and_4)) note(nilHandleErr, 0, "\pBad Icon Family"); } /* load and align various dialog/alert templates */ (void) alignTemplate('ALRT', alidNote, 0, 4, (Point *) 0L); (void) alignTemplate('ALRT', alidHelp, 0, 4, (Point *) 0L); thermoTHnd = (DialogTHndl) alignTemplate('DLOG', dlogProgress, 20, 8, (Point *) 0L); (void) alignTemplate('DLOG', getDlgID, 0, 6, (Point *) &sfGetWhere); /* get the "busy cursors" (preloaded/locked) */ for (i = 0; i < curs_Total; i++) { CursHandle cHnd; if (!(cHnd = GetCursor(i + cursorOffset))) note(nilHandleErr, 0, "\pNil CURS Handle"); cPtr[i] = *cHnd; } /* get the 'vers' 1 long (Get Info) string - About Recover... */ { versXHandle vHnd; if (!(vHnd = (versXHandle) GetResource('vers', 1))) note(nilHandleErr, 0, "\pNil vers Handle"); i = (**vHnd).versStr[0] + 1; /* offset to Get Info pascal string */ if ((aboutBuf[0] = (**vHnd).versStr[i]) > (aboutBufSize - 1)) aboutBuf[0] = aboutBufSize - 1; i++; MoveHHi((Handle) vHnd); /* DEE - Fense ... */ HLock((Handle) vHnd); BlockMove(&((**vHnd).versStr[i]), &(aboutBuf[1]), aboutBuf[0]); ReleaseResource((Handle) vHnd); } /* form the menubar */ for (i = 0; i < menu_Total; i++) { if (!(mHnd[i] = GetMenu(i + muidApple))) note(nilHandleErr, 0, "\pNil MENU Handle"); /* expand the apple menu */ if (i == menuApple) AddResMenu(mHnd[menuApple], 'DRVR'); InsertMenu(mHnd[i], 0); } /* pre-emptive memory check */ { memBytesHandle hBytes; Size grow; if (!(hBytes = (memBytesHandle) GetResource('memB', membID))) note(nilHandleErr, 0, "\pNil Memory Handle"); pBytes = *hBytes; if (MaxMem(&grow) < pBytes->memPreempt) note(memFullErr, 0, "\pMore Memory Required\rTry adding 16k"); memActivity = pBytes->memCleanup; /* force initial cleanup */ } /* get the I/O buffer */ if (!(pIOBuf = NewPtr(pBytes->memIOBuf))) note(memFullErr, 0, "\pNil I/O Pointer"); } /* align a window-related template to the main screen */ static Handle alignTemplate(ResType rezType, short rezID, short vOff, short vDenom, Point *pPt) { Handle rtnHnd; Rect *pRct; vOff += GetMBarHeight(); if (!(rtnHnd = GetResource(rezType, rezID))) note(nilHandleErr, 0, "\pNil Template Handle"); pRct = (Rect *) *rtnHnd; /* don't move memory while aligning rect */ pRct->right -= pRct->left; /* width */ pRct->bottom -= pRct->top; /* height */ pRct->left = (qd.screenBits.bounds.right - pRct->right) / 2; pRct->top = (qd.screenBits.bounds.bottom - pRct->bottom - vOff) / vDenom; pRct->top += vOff; pRct->right += pRct->left; pRct->bottom += pRct->top; if (pPt) *pPt = *(Point *) pRct; /* top left corner */ return rtnHnd; } /* notification completion routine */ pascal void nmCompletion(NMRec *pNMR) { (void) NMRemove(pNMR); (*(short *) (pNMR->nmPending))--; /* decrement pending note level */ ((notifPtr) pNMR)->nmDispose = 1; /* allow DisposPtr() */ } /* * handle errors inside of note(). the error message is appended to the * given message but on a separate line and must fit within nmBufSize. */ static void noteErrorMessage(unsigned char *msg, unsigned char *errMsg) { short i = nmt.nmBuf[0] + 1; /* insertion point */ BlockMove(&msg[1], &nmt.nmBuf[i], msg[0]); nmt.nmBuf[i + msg[0]] = '\r'; nmt.nmBuf[0] += (msg[0] + 1); note(memFullErr, 0, errMsg); } /* * display messages using Notification Manager or an alert. * no run-length checking is done. the messages are created to fit * in the allocated space (nmBufSize and aboutBufSize). */ static void note(short errorSignal, short alertID, unsigned char *msg) { if (!errorSignal) { Size grow; if (MaxMem(&grow) < pBytes->memAbort) noteErrorMessage(msg, "\pOut of Memory"); } if (errorSignal || !in.Front) { notifPtr pNMR; short i = nmt.nmBuf[0] + 1; /* insertion point */ if (errorSignal) /* use notification template */ { pNMR = &nmt; /* we're going to abort so add in this prefix */ BlockMove("Abort: ", &nmt.nmBuf[i], 7); i += 7; nmt.nmBuf[0] += 7; } else /* allocate a notification record */ { if (!(pNMR = (notifPtr) NewPtr(sizeof(notifRec)))) noteErrorMessage(msg, "\pNil New Pointer"); /* initialize it */ *pNMR = nmt; pNMR->nmr.nmStr = (StringPtr) & (pNMR->nmBuf); /* update the notification queue */ if (!pNMQ) pNMQ = pNMR; else { notifPtr pNMX; /* find the end of the queue */ for (pNMX = pNMQ; pNMX->nmNext; pNMX = pNMX->nmNext) ; pNMX->nmNext = pNMR; } } /* concatenate the message */ BlockMove(&msg[1], &((pNMR->nmBuf)[i]), msg[0]); (pNMR->nmBuf)[0] += msg[0]; in.Notify++; /* increase note pending level */ NMInstall((NMRec *) pNMR); if (errorSignal) cooldown(); return; } /* in front and no error so use an alert */ ParamText(msg, "\p", "\p", "\p"); (void) Alert(alertID, (ModalFilterUPP) 0L); ResetAlrtStage(); memActivity++; } static void adjustGUI() { static short oldMenubar = mbar_Init; /* force initial update */ short newMenubar; WindowPeek frontWindow; /* oldCursor is external so it can be reset in endRecover() */ static short newCursor = curs_Init; unsigned long timeNow; short useArrow; /* adjust menubar 1st */ newMenubar = in.Recover ? mbarRecover : mbarAppl; /* desk accessories take precedence */ if (frontWindow = (WindowPeek) FrontWindow()) if (frontWindow->windowKind < 0) newMenubar = mbarDA; if (newMenubar != oldMenubar) { /* adjust menus */ switch (oldMenubar = newMenubar) { case mbarAppl: EnableItem(mHnd[menuFile], mitmOpen); SetItemMark(mHnd[menuFile], mitmOpen, noMark); DisableItem(mHnd[menuFile], mitmClose_DA); DisableItem(mHnd[menuEdit], 0); break; case mbarRecover: DisableItem(mHnd[menuFile], mitmOpen); SetItemMark(mHnd[menuFile], mitmOpen, checkMark); DisableItem(mHnd[menuFile], mitmClose_DA); DisableItem(mHnd[menuEdit], 0); break; case mbarDA: DisableItem(mHnd[menuFile], mitmOpen); EnableItem(mHnd[menuFile], mitmClose_DA); EnableItem(mHnd[menuEdit], 0); break; } DrawMenuBar(); } /* now adjust the cursor */ if (useArrow = (!in.Recover || (newMenubar == mbarDA))) newCursor = curs_Init; else if ((timeNow = TickCount()) >= timeCursor) /* spin cursor */ { timeCursor = timeNow + CURS_FRAME; if (++newCursor >= curs_Total) newCursor = 0; } if (newCursor != oldCursor) { oldCursor = newCursor; SetCursor(useArrow ? &qd.arrow : cPtr[newCursor]); } } static void adjustMemory() { Size grow; memActivity = 0; if (MaxMem(&grow) < pBytes->memWarning) note(noErr, alidNote, "\pWarning: Memory is running low"); (void) ResrvMem((Size) FreeMem()); /* move all handles high */ } /* show memory stats: FreeMem, MaxBlock, PurgeSpace, and StackSpace */ static void optionMemStats() { unsigned char *pFormat = "\pFree:#k Max:#k Purge:#k Stack:#k"; char *pSub = "#"; /* not a pascal string */ unsigned char nBuf[16]; long nStat, contig; Handle strHnd; long nOffset; short i; if (wnEvt.modifiers & shiftKey) adjustMemory(); if (!(strHnd = NewHandle((Size) 128))) { note(noErr, alidNote, "\pOops: Memory stats unavailable!"); return; } SetString((StringHandle) strHnd, pFormat); nOffset = 1L; for (i = 1; i <= 4; i++) { /* get the replacement number stat */ switch (i) { case 1: nStat = FreeMem(); break; case 2: nStat = MaxBlock(); break; case 3: PurgeSpace(&nStat, &contig); break; case 4: nStat = StackSpace(); break; } NumToString((nStat >> 10), *(Str255 *) &nBuf); **strHnd += nBuf[0] - 1; nOffset = Munger(strHnd, nOffset, (Ptr) pSub, 1L, (Ptr) &nBuf[1], nBuf[0]); } MoveHHi(strHnd); HLock(strHnd); note(noErr, alidNote, (unsigned char *) *strHnd); DisposHandle(strHnd); } static void RecoverMenuEvent(long menuEntry) { short menuID = HiWord(menuEntry); short menuItem = LoWord(menuEntry); switch (menuID) { case muidApple: switch (menuItem) { case mitmAbout: if (wnEvt.modifiers & optionKey) optionMemStats(); /* fall thru */ case mitmHelp: note(noErr, (alertAppleMenu + menuItem), aboutBuf); break; default: /* DA's or apple menu items */ { unsigned char daName[32]; GetItem(mHnd[menuApple], menuItem, *(Str255 *) &daName); (void) OpenDeskAcc(daName); memActivity++; } break; } break; case muidFile: switch (menuItem) { case mitmOpen: beginRecover(); break; case mitmClose_DA: { WindowPeek frontWindow; short refNum; if (frontWindow = (WindowPeek) FrontWindow()) if ((refNum = frontWindow->windowKind) < 0) CloseDeskAcc(refNum); memActivity++; } break; case mitmQuit: cooldown(); break; } break; case muidEdit: (void) SystemEdit(menuItem - 1); break; } HiliteMenu(0); } static void eventLoop() { short wneMask = (in.Front ? everyEvent : (osMask + updateMask)); long wneSleep = (in.Front ? 0L : 3L); while (1) { if (in.Front) adjustGUI(); if (memActivity >= pBytes->memCleanup) adjustMemory(); (void) WaitNextEvent(wneMask, &wnEvt, wneSleep, (RgnHandle) 0L); if (in.Dialog) (void) IsDialogEvent(&wnEvt); switch (wnEvt.what) { case osEvt: if (((wnEvt.message & osEvtMessageMask) >> 24) == suspendResumeMessage) { in.Front = (wnEvt.message & resumeFlag); wneMask = (in.Front ? everyEvent : (osMask + updateMask)); wneSleep = (in.Front ? 0L : 3L); } break; case nullEvent: /* adjust the FIFO notification queue */ if (pNMQ && pNMQ->nmDispose) { notifPtr pNMX = pNMQ->nmNext; DisposPtr((Ptr) pNMQ); pNMQ = pNMX; memActivity++; } if (in.Recover) continueRecover(); break; case mouseDown: { WindowPtr whichWindow; switch (FindWindow(wnEvt.where, &whichWindow)) { case inMenuBar: RecoverMenuEvent(MenuSelect(wnEvt.where)); break; case inSysWindow: SystemClick(&wnEvt, whichWindow); break; case inDrag: { Rect boundsRect = qd.screenBits.bounds; Point offsetPt; InsetRect(&boundsRect, 4, 4); boundsRect.top += GetMBarHeight(); DragWindow(whichWindow, *((Point *) &wnEvt.where), &boundsRect); boundsRect = whichWindow->portRect; offsetPt = *(Point *) &(whichWindow->portBits.bounds); OffsetRect(&boundsRect, -offsetPt.h, -offsetPt.v); *(Rect *) *thermoTHnd = boundsRect; } break; } } break; case keyDown: { char key = (wnEvt.message & charCodeMask); if (wnEvt.modifiers & cmdKey) { if (key == '.') { if (in.Recover) { endRecover(); note(noErr, alidNote, "\pSorry: Recovery aborted"); } } else RecoverMenuEvent(MenuKey(key)); } } break; /* without windows these events belong to our thermometer */ case updateEvt: case activateEvt: { DialogPtr dPtr; short itemHit; (void) DialogSelect(&wnEvt, &dPtr, &itemHit); } case diskEvt: if (HiWord(wnEvt.message)) { Point pt = { 60, 60 }; (void) DIBadMount(pt, wnEvt.message); DIUnload(); memActivity++; } break; } /* switch (wnEvt.what) */ } /* while (1) */ } static void cooldown() { if (in.Recover) endRecover(); /* wait for pending notifications to complete */ while (in.Notify) (void) WaitNextEvent(0, &wnEvt, 3L, (RgnHandle) 0L); ExitToShell(); } /* draw the progress thermometer and frame. 1 level <=> 1 horiz. pixel */ pascal void drawThermo(WindowPtr wPtr, short inum) { itemizeThermo(drawItem); } /* manage progress thermometer dialog */ static void itemizeThermo(short itemMode) { short iTyp, iTmp; Handle iHnd; Rect iRct; GetDItem(DLGTHM, uitmThermo, &iTyp, &iHnd, &iRct); switch (itemMode) { case initItem: SetDItem(DLGTHM, uitmThermo, iTyp, (Handle) drawThermoUPP, &iRct); break; case invalItem: { GrafPtr oldPort; GetPort(&oldPort); SetPort(GRFTHM); InsetRect(&iRct, 1, 1); InvalRect(&iRct); SetPort(oldPort); } break; case drawItem: FrameRect(&iRct); InsetRect(&iRct, 1, 1); iTmp = iRct.right; iRct.right = iRct.left + in.Recover; PaintRect(&iRct); iRct.left = iRct.right; iRct.right = iTmp; EraseRect(&iRct); break; } } /* show only .0 files in get file dialog */ pascal Boolean basenameFileFilter(ParmBlkPtr pPB) { unsigned char *pC; if (!(pC = (unsigned char *) pPB->fileParam.ioNamePtr)) return true; if ((*pC < 4) || (*pC > 28)) /* save/ 1name .0 */ return true; if ((pC[*pC - 1] == '.') && (pC[*pC] == '0')) /* bingo! */ return false; return true; } static void beginRecover() { SFTypeList levlType = { 'LEVL' }; SFReply sfGetReply; SFGetFile(sfGetWhere, "\p", basenameFileFilterUPP, 1, levlType, (DlgHookUPP) 0L, &sfGetReply); memActivity++; if (!sfGetReply.good) return; /* get volume (working directory) refnum, basename, and directory i.d. */ vRefNum = sfGetReply.vRefNum; BlockMove(sfGetReply.fName, lock, sfGetReply.fName[0] + 1); { static CInfoPBRec catInfo; catInfo.hFileInfo.ioNamePtr = (StringPtr) sfGetReply.fName; catInfo.hFileInfo.ioVRefNum = sfGetReply.vRefNum; catInfo.hFileInfo.ioDirID = 0L; if (PBGetCatInfoSync(&catInfo)) { note(noErr, alidNote, "\pSorry: Bad File Info"); return; } dirID = catInfo.hFileInfo.ioFlParID; } /* open the progress thermometer dialog */ (void) GetNewDialog(dlogProgress, (Ptr) &dlgThermo, (WindowPtr) -1L); if (ResError() || MemError()) note(noErr, alidNote, "\pOops: Progress thermometer unavailable"); else { in.Dialog = 1; memActivity++; itemizeThermo(initItem); ShowWindow(WNDTHM); } timeCursor = TickCount() + CURS_LATENT; saveRefNum = gameRefNum = levRefNum = -1; in.Recover = 1; } static void continueRecover() { restore_savefile(); /* update the thermometer */ if (in.Dialog && !(in.Recover % 4)) itemizeThermo(invalItem); if (in.Recover <= MAX_RECOVER_COUNT) return; endRecover(); if (saveRezStrings()) return; note(noErr, alidNote, "\pOK: Recovery succeeded"); } /* no messages from here (since we might be quitting) */ static void endRecover() { in.Recover = 0; oldCursor = curs_Init; SetCursor(&qd.arrow); /* clean up abandoned files */ if (gameRefNum >= 0) (void) FSClose(gameRefNum); if (levRefNum >= 0) (void) FSClose(levRefNum); if (saveRefNum >= 0) { (void) FSClose(saveRefNum); (void) FlushVol((StringPtr) 0L, vRefNum); /* its corrupted so trash it ... */ (void) HDelete(vRefNum, dirID, savename); } saveRefNum = gameRefNum = levRefNum = -1; /* close the progress thermometer dialog */ in.Dialog = 0; CloseDialog(DLGTHM); DisposHandle(dlgThermo.items); memActivity++; } /* add friendly, non-essential resource strings to save file */ static short saveRezStrings() { short sRefNum; StringHandle strHnd; short i, rezID; unsigned char *plName; HCreateResFile(vRefNum, dirID, savename); sRefNum = HOpenResFile(vRefNum, dirID, savename, fsRdWrPerm); if (sRefNum <= 0) { note(noErr, alidNote, "\pOK: Minor resource map error"); return 1; } /* savename and hpid get mutilated here... */ plName = savename + 5; /* save/ */ *savename -= 5; do { plName++; (*savename)--; hpid /= 10; } while (hpid); *plName = *savename; for (i = 1; i <= 2; i++) { switch (i) { case 1: rezID = PLAYER_NAME_RES_ID; strHnd = NewString(*(Str255 *) plName); break; case 2: rezID = APP_NAME_RES_ID; strHnd = NewString(*(Str255 *) "\pNetHack"); break; } if (!strHnd) { note(noErr, alidNote, "\pOK: Minor \'STR \' resource error"); CloseResFile(sRefNum); return 1; } /* should check for errors... */ AddResource((Handle) strHnd, 'STR ', rezID, *(Str255 *) "\p"); } memActivity++; /* should check for errors... */ CloseResFile(sRefNum); return 0; } static void set_levelfile_name(long lev) { unsigned char *tf; /* find the dot. this is guaranteed to happen. */ for (tf = (lock + *lock); *tf != '.'; tf--, lock[0]--) ; /* append the level number string (pascal) */ if (tf > lock) { NumToString(lev, *(Str255 *) tf); lock[0] += *tf; *tf = '.'; } else /* huh??? */ { endRecover(); note(noErr, alidNote, "\pSorry: File Name Error"); } } static short open_levelfile(long lev) { OSErr openErr; short fRefNum; set_levelfile_name(lev); if (!in.Recover) return (-1); if ((openErr = HOpen(vRefNum, dirID, lock, fsRdWrPerm, &fRefNum)) && (openErr != fnfErr)) { endRecover(); note(noErr, alidNote, "\pSorry: File Open Error"); return (-1); } return (openErr ? -1 : fRefNum); } static short create_savefile(unsigned char *savename) { short fRefNum; /* translate savename to a pascal string (in place) */ { unsigned char *pC; short nameLen; for (pC = savename; *pC; pC++) ; nameLen = pC - savename; for (; pC > savename; pC--) *pC = *(pC - 1); *savename = nameLen; } if (HCreate(vRefNum, dirID, savename, MAC_CREATOR, SAVE_TYPE) || HOpen(vRefNum, dirID, savename, fsRdWrPerm, &fRefNum)) { endRecover(); note(noErr, alidNote, "\pSorry: File Create Error"); return (-1); } return fRefNum; } static void copy_bytes(short inRefNum, short outRefNum) { char *buf = (char *) pIOBuf; long bufSiz = pBytes->memIOBuf; long nfrom, nto; do { nfrom = read_levelfile(inRefNum, buf, bufSiz); if (!in.Recover) return; nto = write_savefile(outRefNum, buf, nfrom); if (!in.Recover) return; if (nto != nfrom) { endRecover(); note(noErr, alidNote, "\pSorry: File Copy Error"); return; } } while (nfrom == bufSiz); } static void restore_savefile() { static int savelev; long saveTemp, lev; xchar levc; struct version_info version_data; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created * and game state */ lev = in.Recover - 1; if (lev == 0L) { gameRefNum = open_levelfile(0L); if (in.Recover) (void) read_levelfile(gameRefNum, (Ptr) &hpid, sizeof(hpid)); if (in.Recover) saveTemp = read_levelfile(gameRefNum, (Ptr) &savelev, sizeof(savelev)); if (in.Recover && (saveTemp != sizeof(savelev))) { endRecover(); note(noErr, alidNote, "\pSorry: \"checkpoint\" was not enabled"); return; } if (in.Recover) (void) read_levelfile(gameRefNum, (Ptr) savename, sizeof(savename)); if (in.Recover) (void) read_levelfile(gameRefNum, (Ptr) &version_data, sizeof version_data); /* save file should contain: * current level (including pets) * (non-level-based) game state * other levels */ if (in.Recover) saveRefNum = create_savefile(savename); if (in.Recover) levRefNum = open_levelfile(savelev); if (in.Recover) (void) write_savefile(saveRefNum, (Ptr) &version_data, sizeof version_data); if (in.Recover) copy_bytes(levRefNum, saveRefNum); if (in.Recover) close_file(&levRefNum); if (in.Recover) unlink_file(lock); if (in.Recover) copy_bytes(gameRefNum, saveRefNum); if (in.Recover) close_file(&gameRefNum); if (in.Recover) set_levelfile_name(0L); if (in.Recover) unlink_file(lock); } else if (lev != savelev) { levRefNum = open_levelfile(lev); if (levRefNum >= 0) { /* any or all of these may not exist */ levc = (xchar) lev; (void) write_savefile(saveRefNum, (Ptr) &levc, sizeof(levc)); if (in.Recover) copy_bytes(levRefNum, saveRefNum); if (in.Recover) close_file(&levRefNum); if (in.Recover) unlink_file(lock); } } if (in.Recover == MAX_RECOVER_COUNT) close_file(&saveRefNum); if (in.Recover) in.Recover++; } static long read_levelfile(short rdRefNum, Ptr bufPtr, long count) { OSErr rdErr; long rdCount = count; if ((rdErr = FSRead(rdRefNum, &rdCount, bufPtr)) && (rdErr != eofErr)) { endRecover(); note(noErr, alidNote, "\pSorry: File Read Error"); return (-1L); } return rdCount; } static long write_savefile(short wrRefNum, Ptr bufPtr, long count) { long wrCount = count; if (FSWrite(wrRefNum, &wrCount, bufPtr)) { endRecover(); note(noErr, alidNote, "\pSorry: File Write Error"); return (-1L); } return wrCount; } static void close_file(short *pFRefNum) { if (FSClose(*pFRefNum) || FlushVol((StringPtr) 0L, vRefNum)) { endRecover(); note(noErr, alidNote, "\pSorry: File Close Error"); return; } *pFRefNum = -1; } static void unlink_file(unsigned char *filename) { if (HDelete(vRefNum, dirID, filename)) { endRecover(); note(noErr, alidNote, "\pSorry: File Delete Error"); return; } } nethack-3.6.0/sys/mac/mrecover.hqx0000664000076400007660000001045312467321052016064 0ustar paxedpaxed(This file must be converted with BinHex 4.0) :$@ebC@0[GQ9b,R*cFQ-!FR0bBe*6483!!!!!!!!!!!aI55J!!!!!!3!!!!TJ!!! *B!!!!Im!!'1M#Q&$E'YTEQPd,Q1!!J!!!&4&@&4,38K-!3!!-"*YFQ9MEhCPFLj `FQpU,R*cFQ0b!J!!!(*cFQ058d9%!!"bFh*M8P0&4!%!!0!!J!!!!!!!!!!!!!! !!!!!!!!!!+lTZ(B!!!!!!!!-F`!!!!!!!!!!%!!!!'1M#Q&$E'YXEfp`,Q1!!J! !!&4&@&4,38K-!3!!B!"X!!!!!'1V!!!!!&Le!!"F!!!!!!!!!!!!!!#Mk`QeT3H i4`!!!!"hD3!!!!!!!!!!!!!!!!!!!!!p93!A!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!L!!%!!!!!!$J!EJ"-!1B%!Np,!!!!!!!+!!S!+J&+L!*H-!!!!!` !+!!S!))"I!#!!!3!!!!-!#J!+!$#!A`!J3!%!!!!5!##!!!!!!!!!!$rrrrl"%9 NDA3%9@jNE`"D!!!",3!!!!!$3h9d!&J!!!4$Eh"j!%-!!!93BA0dC3"@!!!&3fa PBA)!!!!!!!!!!$J!J!!!!!!!!!!!rrrrp`%8%%&LEh9d)&*PBfpfCA)Z,Li!!!! !"dKPE(!Z,Li!!!!!!5d!!!!!!!!!!%3!!!2!!X!$`!'!!m!--!J3%#J35"H)%!J )%!``!m!!!!2!"q!(i!IJ!m!2m"ri(rJrr$rm2r`rr"ri(rJ2m!2!!!N!"`!!!%! 'J!l!CZ!hB"r!6mcq%[mUkG6XL#N3-V!&@!5-!`3!!"r!Ir"rq2rmrrlrr[rrrrr rrrrrIrprrcrr(ri2rJ2i!!!!('jS8Q-!!!!"4P*&4J!!!!!!J%P$6L-!!!!!!)! !!!!(39"36!!!!!!!!"364'&fD@3J5'&TFR0dEfiJ-bmj-`!!!3!!!!!!!"m!!!" r`!!JIm!!1$q`!"3rF!!512J!#6Gi!!6rH!!#IlJ!!6ri!''Iq!$rc$$Jrq3"-1l b!T!!kIN&82IPLU$[ip9!6Z%LJ!(Jb3!2m))!$r%N!!I#LJ!!"9N!!!UNJ!!93N! !%S&J!"N!d!!1!&!!!!!`!!!!!!!!!!!2r`!!2rr!!(rrm!"rrrJ!rrrm!2rrrJ$ rrrm!rrrrJ2rrrm$rrrrJrrrrm2rrrrMrrrrmrrrrr2rrrrlrrrrqrrrrrhrrrrp rrrrr2rrrrcrrrrmIrrrr$rrrr`Irrrm$rrrr!Irrr`$rrrm!Irrr!$rrrJ!Irri !"rrm!!(rm!!!!J!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rrrm!!!!!!!!!!!!!!!! 2%4%4r`!!!!!!!!!!m!!!$a%4%4m!!!!!!!!!!2r`!!$a%4%Ir`!!!!!!!!!2h`! !m4%4m4m!!!!!!!!!$ph`!2%Ira%4m!!!!!!!!!$ph`$am4(a%I!!!!!!!!!!$ph r%4%4m4(`!!!!!!!!!!$pha%4%4m4m!!!!!!!!!!!$pha%4%4%I!!!!!!!!r`!!r pha(rra(`!!!!!!$a(rra(phr!!$r!!$rm!!!m4%4%4(ph`!!!!!242m!!2%I%4m 4(ph`!!!!p242!!$a(ara%Irph`!!$dp26`!!m4(a%4(`$p$`!26dp2!!!2%I%4% 4m!$`$`p26dm!!!!2ra%I%I!!$phd426`!!!!!!rrm4(`!!$r4242!!!!!!!2%4% 4(`!!p%4%m!!!!!!!$r%4%4m!$d6d6`!!!!!!!!!2rrr`!26d42h`!!!!!!!!!!! !!!p26drph`!!!!!!!!!!!!$dp26`$ph`!!!!!!!!!!!26dp2!!$ph`!!!!!!!!! !$d6dm!!!$p$`!!!!!!!!!!rd6`!!!!$`h`!!!!!!!!!!rr!!!!!!$pm!!!!!!!! !!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)! !!!rrm!!!!!!!m4mI!!!!$G!2(a(`!!!!h3m4mI!!!!!0ha%I!!!!$`$Grrm!r`$ arrh3!!p%m2%4(pd!p26`m4mI$Gp26`$rram!p%6`!!!!m!p%6`!!!!!!p26p!!! !!!p26`h3!!!!$d6`!0d!!!!!r`!!$3!!!!!!!!!!!!!!!#!'J!l!CZ!hB"r!6mc q%[mUkG6XL#N3-V!&@!5-!`3!!!!!!2B!!3!!!!!!H!"Z!)`!jJ3#6dX!!!!!!!S !#J"U!8U)e6%T)&0PE'9MG#!L6h"PELiZ,L)JCR*[E5"dD'8J4QPXC5"YC@je,Jd b+5"6C@aPBh3JG'KP)'GKE@8JG'mJFQ9MEhCPFL"QFQpY)(4SC5"ND@&XEfFZ$6- T)&GKDA3JCQpb)(4SC5"bCA0eE(3J+%p,)'pb)&0[FR*j+5i0$84[)'j[G#"KG(4 PEA"d)(4[)(*PBfpfCA)JB5"RB@eP)(4SBA3JDA-J)QPZ)("bEfGbCA0c)L!SD5j P,L"cG'PXE#"bG@jZD@jR)'PZ)%jPG%KKBfXT)3!!!!"#!)%!!!!!!!!!!2rrrqX %4QPXC3G2F'9Z,LiZ!%m!!!%Y!!!!!!K$E'pcC5"%33"A!!!",3!!!!!%8A9TG!" 4!!!!!!!!&!!!!!3!!)!!!!!`!!!!%!!!!%!!!!!!3J43FQPf4PG54!G$E'9KER9 `4&G54!G3FQ9PEA"d4%a14`GABA*ZD@jR4%a14`9"BQpbG%4-6NF'58mJ3R9Q4%a 14`!!!%3!!!2!!d!$`!'!!B!#3!4J"#!%B!@J"#!%B!*!!B!!!!2!"q!(i!IJ!m! $`!IJ$r!2m!r`$r!2m!r`"q!$`!'!!!N!"`!!!%3!!!2!!X!$`!'!!B!#3!2!!N! (`!C!!m!#3!2!!B!!!!2!"q!(i!IJ!m!$`!IJ"q!(i!rJ$q!(i!IJ"q!$`!'!!!N !"`!!!"d!+!!S!%!"3!!%!!!!!!!!!!!"!!K3FQpRFQ9cF`!!!"!!!!!!!!!!"`! ,!"%"$B!!!!!!4!!!!m!$3!2!!B!"J!*!"Q!%)!CJ"D!')!4J!d!"J!!!!m!(i!I J"q!$`!2!"q!2m!r`$r!2m!r`$r!(i!2!!B!!#3!(!!!!4!!!!m!$3!2!!B!"J!0 !"L!&B!8J"@!&)!9J!N!"J!!!!m!(i!IJ"q!$`!2!"q!2m!r`$r!2m!r`$r!(i!2 !!B!!#3!(!!!!4!!!!m!#`!2!!B!"J!*!!m!#3!2J!Q!$`!*!!m!"J!!!!m!(i!I J"q!$`!2!"q!(i!IJ"r!(m!IJ"q!(i!2!!B!!#3!(!!!!4!!!!m!#`!2!!B!$J!q 3!!`3'CJCQ"QB'CJ*N!!-%!2!!!!$`!IJ"q!(i!2!$r!Iq"ri2r`rr$rm2r`Iq"r i$r!$`!!*!!F!!!"%!!!$`!0!!m!"J!'!!m!&)!DJ"+!'S!5J"U!$3!'!!!!$`!I J"q!(i!2!!m!(i!r`$r!2m!r`$r!2m!IJ!m!"J!!*!!F!!!!U!c#!!!!!!c-Z-ap 5C@0[GQ9b)$-Z-`eNCACdC@&Y3'jPG'KKBfXZEh*R!!!!&J-`J!!!!!-c,M-,8Q9 MEhCPFL!c,M-!!!%!!!!+B!!!#@!!!!(r"-)(q#qq!!!!(!(k!!p"6&*8!!%!JN4 *9%`!!J#D689193!#!,j$99*6!!F!iNP$6L-!!!&#D@0c)`!!!8j#6N4-!!!"@Qj S8Q-!!!&Q4P*&4J!!!A*fCA*c!!%"IQPME$3!!!'@D@0c0!!!!D*65801!!!"VQe PE8)!!!'k9%e36!!!!FC%6%p(!!!"dJ#!rrm!!!!Q!!!!!!#"rrm!!!!f!!!!!!# !rrmJ!!!!!!!!!!#"rrmJ!!90!!!!!!%!rrmJ!!HF!!!!!!##rrm!!!"'!!!!!!# !rrm!!!#5!!!!!!#"rrm!!!C(!!!!!!#!rrm8!!$1!!!!!!#"rrm8!!EV!!!!!!# #rrm8!!Fc!!!!!!#(rrm8!!H`!!!!!!#&rrm8!!Ii!!!!!!#'rrm8!!K!!!!!!!# %rrm8!!L)!!!!!!#$rrm8!!M3!!!!!!#!rrm!!!'G!!!!!!#!rrm!!!%@!!!!!!# !rrm!!!&D!!!!!!!!rrm!!!'&!!!!!!#!rrm!!!&k!!!!!!!"rrm!!!NB!!!!!!! #rrm!!!P'!!!!!!#!rrm!!!+K!!!!!!#!rrm!!!5P!!!!!!#!rrm!!!8T!!!!!!# !rrm8!!D0!!!!!!#!!!!!!!DP!!!!!!%!rrm!!!Gl!!!!!!4YC@e#8i3: nethack-3.6.0/sys/mac/mttymain.c0000664000076400007660000003176112536476415015546 0ustar paxedpaxed/* NetHack 3.6 mttymain.c $NHDT-Date: 1432512797 2015/05/25 00:13:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Jon W{tte, 1993 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "macwin.h" #include "mttypriv.h" #include "mactty.h" #include "wintty.h" #if !TARGET_API_MAC_CARBON #include #endif #include #define MT_WINDOW 135 #define MT_WIDTH 80 #define MT_HEIGHT 24 /* * Names: * * Statics are prefixed _ * Mac-tty becomes mt_ */ static long _mt_attrs[5][2] = { { 0x000000, 0xffffff }, /* Normal */ { 0xff8080, 0xffffff }, /* Underline */ { 0x40c020, 0xe0e0e0 }, /* Bold */ { 0x003030, 0xff0060 }, /* Blink */ { 0xff8888, 0x000000 }, /* Inverse */ }; static char _attrs_inverse[5] = { 0, 0, 0, 0, 0, }; /* see color.h */ static long _mt_colors[CLR_MAX][2] = { { 0x000000, 0x808080 }, /* Black */ { 0x880000, 0xffffff }, /* Red */ { 0x008800, 0xffffff }, /* Green */ { 0x553300, 0xffffff }, /* Brown */ { 0x000088, 0xffffff }, /* Blue */ { 0x880088, 0xffffff }, /* Magenta */ { 0x008888, 0xffffff }, /* Cyan */ { 0x888888, 0xffffff }, /* Gray */ { 0x000000, 0xffffff }, /* No Color */ { 0xff4400, 0xffffff }, /* Orange */ { 0x00ff00, 0xffffff }, /* Bright Green */ { 0xffff00, 0x606060 }, /* Yellow */ { 0x0033ff, 0xffffff }, /* Bright Blue */ { 0xff00ff, 0xffffff }, /* Bright Magenta */ { 0x00ffff, 0xffffff }, /* Bright Cyan */ { 0xffffff, 0x505050 }, /* White */ }; static char _colors_inverse[CLR_MAX] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #ifdef CHANGE_COLOR #define POWER_LIMIT 22 #define SECONDARY_POWER_LIMIT 16 #define CHANNEL_LIMIT 14 #define SECONDARY_CHANNEL_LIMIT 12 void tty_change_color(int color, long rgb, int reverse) { long inverse, working_rgb = rgb; int total_power = 0, max_channel = 0; int cnt = 3; working_rgb >>= 4; while (cnt-- > 0) { total_power += working_rgb & 0xf; max_channel = max(max_channel, working_rgb & 0xf); working_rgb >>= 8; } if (total_power >= POWER_LIMIT || (total_power >= SECONDARY_POWER_LIMIT && max_channel >= SECONDARY_CHANNEL_LIMIT) || max_channel >= CHANNEL_LIMIT) inverse = 0x000000; else inverse = 0xffffff; if (reverse) { working_rgb = rgb; rgb = inverse; inverse = working_rgb; } if (color >= CLR_MAX) { if (color - CLR_MAX >= 5) impossible("Changing too many colors"); else { _mt_attrs[color - CLR_MAX][0] = rgb; _mt_attrs[color - CLR_MAX][1] = inverse; _attrs_inverse[color - CLR_MAX] = reverse; } } else if (color >= 0) { _mt_colors[color][0] = rgb; _mt_colors[color][1] = inverse; _colors_inverse[color] = reverse; } else impossible("Changing negative color"); } void tty_change_background(int white_or_black) { register int i; for (i = 0; i < CLR_MAX; i++) { if (white_or_black) _mt_colors[i][1] = 0xffffff; /* white */ else _mt_colors[i][1] = 0x000000; /* black */ } /* special cases */ if (white_or_black) { _mt_colors[CLR_BLACK][1] = 0x808080; /* differentiate black from no color */ _mt_colors[CLR_WHITE][1] = 0x505050; /* highlight white with grey background */ _mt_colors[CLR_YELLOW][1] = 0x606060; /* highlight yellow with grey background */ _mt_colors[CLR_BLUE][0] = 0x000088; /* make pure blue */ _mt_colors[NO_COLOR][0] = 0x000000; /* make no_color black on white */ _mt_attrs[0][0] = 0x000000; /* "normal" is black on white */ _mt_attrs[0][1] = 0xffffff; } else { _mt_colors[NO_COLOR][0] = 0xffffff; /* make no_color white on black */ _mt_colors[CLR_BLACK][1] = 0x808080; /* differentiate black from no color */ _mt_colors[CLR_BLUE][0] = 0x222288; /* lighten blue - it's too dark on black */ _mt_attrs[0][0] = 0xffffff; /* "normal" is white on black */ _mt_attrs[0][1] = 0x000000; } } char * tty_get_color_string(void) { char *ptr; int count; static char color_buf[5 * (CLR_MAX + 5) + 1]; color_buf[0] = 0; ptr = color_buf; for (count = 0; count < CLR_MAX; count++) { int flag = _colors_inverse[count] ? 1 : 0; sprintf(ptr, "%s%s%x%x%x", count ? "/" : "", flag ? "-" : "", (int) (_mt_colors[count][flag] >> 20) & 0xf, (int) (_mt_colors[count][flag] >> 12) & 0xf, (int) (_mt_colors[count][flag] >> 4) & 0xf); ptr += strlen(ptr); } for (count = 0; count < 5; count++) { int flag = _attrs_inverse[count] ? 1 : 0; sprintf(ptr, "/%s%x%x%x", flag ? "-" : "", (int) (_mt_attrs[count][flag] >> 20) & 0xf, (int) (_mt_attrs[count][flag] >> 12) & 0xf, (int) (_mt_attrs[count][flag] >> 4) & 0xf); ptr += strlen(ptr); } return color_buf; } #endif extern struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ char kill_char = CHAR_ESC; char erase_char = CHAR_BS; WindowRef _mt_window = (WindowRef) 0; static Boolean _mt_in_color = 0; extern short win_fonts[NHW_TEXT + 1]; static void _mt_init_stuff(void) { long resp, flag; short num_cols, num_rows, win_width, win_height, font_num, font_size; short char_width, row_height; short hor, vert; LI = MT_HEIGHT; CO = MT_WIDTH; if (!strcmp(windowprocs.name, "mac")) { dprintf("Mac Windows"); LI -= 1; } else { dprintf("TTY Windows"); } /* * If there is at least one screen CAPABLE of color, and if * 32-bit QD is there, we use color. 32-bit QD is needed for the * offscreen GWorld */ if (!Gestalt(gestaltQuickdrawVersion, &resp) && resp > 0x1ff) { GDHandle gdh = GetDeviceList(); while (gdh) { if (TestDeviceAttribute(gdh, screenDevice)) { if (HasDepth(gdh, 4, 1, 1) || HasDepth(gdh, 8, 1, 1) || HasDepth(gdh, 16, 1, 1) || HasDepth(gdh, 32, 1, 1)) { _mt_in_color = 1; break; } } gdh = GetNextDevice(gdh); } } if (create_tty(&_mt_window, WIN_BASE_KIND + NHW_MAP, _mt_in_color) != noErr) error("_mt_init_stuff: Couldn't create tty."); SetWindowKind(_mt_window, WIN_BASE_KIND + NHW_MAP); SelectWindow(_mt_window); SetPortWindowPort(_mt_window); SetOrigin(-1, -1); font_size = iflags.wc_fontsiz_map ? iflags.wc_fontsiz_map : (iflags.large_font && !small_screen) ? 12 : 9; if (init_tty_number(_mt_window, win_fonts[NHW_MAP], font_size, CO, LI) != noErr) error("_mt_init_stuff: Couldn't init tty."); if (get_tty_metrics(_mt_window, &num_cols, &num_rows, &win_width, &win_height, &font_num, &font_size, &char_width, &row_height)) error("_mt_init_stuff: Couldn't get tty metrics."); SizeWindow(_mt_window, win_width + 2, win_height + 2, 1); if (RetrievePosition(kMapWindow, &vert, &hor)) { dprintf("Moving window to (%d,%d)", hor, vert); MoveWindow(_mt_window, hor, vert, 1); } ShowWindow(_mt_window); /* Start in raw, always flushing mode */ get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag); flag |= TA_ALWAYS_REFRESH | TA_WRAP_AROUND; set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag); get_tty_attrib(_mt_window, TTY_ATTRIB_CURSOR, &flag); flag |= (TA_BLINKING_CURSOR | TA_NL_ADD_CR); set_tty_attrib(_mt_window, TTY_ATTRIB_CURSOR, flag); set_tty_attrib(_mt_window, TTY_ATTRIB_FOREGROUND, _mt_colors[NO_COLOR][0]); set_tty_attrib(_mt_window, TTY_ATTRIB_BACKGROUND, _mt_colors[NO_COLOR][1]); clear_tty(_mt_window); InitMenuRes(); } int tgetch(void) { EventRecord event; long sleepTime = 0; int ret = 0; for (; !ret;) { WaitNextEvent(-1, &event, sleepTime, 0); HandleEvent(&event); blink_cursor(_mt_window, event.when); if (event.what == nullEvent) { sleepTime = GetCaretTime(); } else { sleepTime = 0; } ret = GetFromKeyQueue(); if (ret == CHAR_CR) ret = CHAR_LF; } return ret; } void getreturn(char *str) { FlushEvents(-1, 0); msmsg("Press space %s", str); (void) tgetch(); } int has_color(int color) { #if defined(__SC__) || defined(__MRC__) #pragma unused(color) #endif Rect r; // Point p = {0, 0}; GDHandle gh; if (!_mt_in_color) return 0; GetWindowBounds(_mt_window, kWindowContentRgn, &r); // SetPortWindowPort(_mt_window); // LocalToGlobal (&p); // OffsetRect (&r, p.h, p.v); gh = GetMaxDevice(&r); if (!gh) { return 0; } return (*((*gh)->gdPMap))->pixelSize > 4; /* > 4 bpp */ } void tty_delay_output(void) { EventRecord event; long toWhen = TickCount() + 3; while (TickCount() < toWhen) { WaitNextEvent(updateMask, &event, 3L, 0); if (event.what == updateEvt) { HandleEvent(&event); blink_cursor(_mt_window, event.when); } } } void cmov(int x, int y) { move_tty_cursor(_mt_window, x, y); ttyDisplay->cury = y; ttyDisplay->curx = x; } void nocmov(int x, int y) { cmov(x, y); } static void _mt_set_colors(long *colors) { short err; if (!_mt_in_color) { return; } err = set_tty_attrib(_mt_window, TTY_ATTRIB_FOREGROUND, colors[0]); err = set_tty_attrib(_mt_window, TTY_ATTRIB_BACKGROUND, colors[1]); } void term_end_attr(int attr) { #if defined(__SC__) || defined(__MRC__) #pragma unused(attr) #endif _mt_set_colors(_mt_attrs[0]); } void term_start_attr(int attr) { switch (attr) { case ATR_ULINE: _mt_set_colors(_mt_attrs[1]); break; case ATR_BOLD: _mt_set_colors(_mt_attrs[2]); break; case ATR_BLINK: _mt_set_colors(_mt_attrs[3]); break; case ATR_INVERSE: _mt_set_colors(_mt_attrs[4]); break; default: _mt_set_colors(_mt_attrs[0]); break; } } void standoutend(void) { term_end_attr(ATR_INVERSE); } void standoutbeg(void) { term_start_attr(ATR_INVERSE); } void term_end_color(void) { _mt_set_colors(_mt_colors[NO_COLOR]); } void cl_end(void) { _mt_set_colors(_mt_attrs[0]); clear_tty_window(_mt_window, ttyDisplay->curx, ttyDisplay->cury, CO - 1, ttyDisplay->cury); } void clear_screen(void) { _mt_set_colors(_mt_attrs[0]); clear_tty(_mt_window); } void cl_eos(void) { _mt_set_colors(_mt_attrs[0]); clear_tty_window(_mt_window, ttyDisplay->curx, ttyDisplay->cury, CO - 1, LI - 1); } void home(void) { cmov(0, 0); } void backsp(void) { char eraser[] = { CHAR_BS, CHAR_BLANK, CHAR_BS, 0 }; short err; err = add_tty_string(_mt_window, eraser); err = update_tty(_mt_window); } void msmsg(const char *str, ...) { va_list args; char buf[1000]; va_start(args, str); vsprintf(buf, str, args); va_end(args); xputs(buf); } void term_end_raw_bold(void) { term_end_attr(ATR_INVERSE); } void term_start_raw_bold(void) { term_start_attr(ATR_INVERSE); } void term_start_color(int color) { if (color >= 0 && color < CLR_MAX) { _mt_set_colors(_mt_colors[color]); } } void setftty(void) { long flag; /* Buffered output for the game */ get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag); flag &= ~TA_ALWAYS_REFRESH; flag |= TA_INHIBIT_VERT_SCROLL; /* don't scroll */ set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag); iflags.cbreak = 1; } void tty_startup(int *width, int *height) { _mt_init_stuff(); *width = CO; *height = LI; } void gettty(void) { } void settty(const char *str) { long flag; update_tty(_mt_window); /* Buffered output for the game, raw in "raw" mode */ get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag); flag &= ~TA_INHIBIT_VERT_SCROLL; /* scroll */ flag |= TA_ALWAYS_REFRESH; set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag); tty_raw_print("\n"); if (str) { tty_raw_print(str); } } void tty_number_pad(int arg) { #if defined(__SC__) || defined(__MRC__) #pragma unused(arg) #endif } void tty_start_screen(void) { iflags.cbreak = 1; } void tty_end_screen(void) { } void xputs(const char *str) { add_tty_string(_mt_window, str); } int term_puts(const char *str) { xputs(str); return strlen(str); } int term_putc(int c) { short err; err = add_tty_char(_mt_window, c); return err ? EOF : c; } int term_flush(void *desc) { if (desc == stdout || desc == stderr) { update_tty(_mt_window); } else { impossible("Substituted flush for file"); return fflush(desc); } return 0; } nethack-3.6.0/sys/msdos/Install.dos0000664000076400007660000002667612536476415016253 0ustar paxedpaxed Copyright (c) NetHack PC Development Team 1990-2002. NetHack may be freely redistributed. See license for details. ============================================================== Instructions for compiling and installing NetHack 3.6 on a DOS system ====================================================== (or, How to make PC NetHack 3.6) Last revision: $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ Credit for a runnable full PC NetHack 3.6 goes to the PC Development team of Paul Winner, Kevin Smolkowski, Michael Allison, Yitzhak Sapir, Bill Dyer, Timo Hakulinen, Yamamoto Keizo, Mike Threepoint, Mike Stephenson, Stephen White, Ken Washikita and Janet Walz. The present port is based on the previous effort of Pierre Martineau, Stephen Spackman, Steve Creps, Mike Threepoint, Mike Stephenson, Norm Meluch and Don Kneller. There has been very little port-specific maintenance for NetHack on DOS since NetHack 3.3.0. CONTENTS: I. Dispelling the Myths II. Compiling on a DOS machine Appendix A - Building the "official binary" Appendix B - DJGPP Compiler (gcc ported to msdos) notes Appendix C - Additional Notes Appendix D - Contacting Us I. Dispelling the Myths: Compiling NetHack is not as easy as it sounds, nor as hard as it looks, however it will behoove you to read this entire file through before beginning the task. We have provided a proper Makefile for building NetHack using the following compilers: djgpp V2.03 or later For specific details concerning the djgpp compiler, please see the appendix B. The makefile named Makefile.GCC is for use with GNU Make that accompanies djgpp. If you want to build a copy of NetHack that is identical to the "official binary", please see appendix A. The unsupported sys/msdos/Makefile.MSC was for the old 16 bit Microsoft Visual C 1.52c compiler and has not been made compliant with 3.5.x. You may find it useful to obtain copies of lex (flex) and yacc (bison or byacc). While not strictly necessary to compile nethack, they are required should you desire to make any changes to the level and dungeon compilers. Flex and Bison are included with the DJGPP distribution and are also available on many archive sites. Also be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and touch.exe, since the Makefile uses them by default. II. To compile your copy of NetHack on a DOS machine: (or "just follow these few 'simple' steps outlined below.") 1. It almost goes without saying that you should make sure that your tools are set up and running correctly. 2. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, sys\share, sys\msdos, util, win\tty and win\share. Other subdirectories may also be included in your distribution, but they are not necessary for use with DOS. You can delete them to save space. Required Source Directories for DOS NetHack: (top) | ------------------------------------------------- | | | | | | | util dat doc include src sys win | | ------ ----- | | | | share msdos tty share Check the file "Files" in your top level directory for an exact listing of what files are in which directory. In order for the Makefiles to work, all the source files must be in the proper locations. If you downloaded or ftp'd the sources from a UNIX system, the lines will probably end in UNIX-style newlines, instead of the carriage return and line feed pairs used by DOS. Some programs have trouble with them, so you may need to convert them (with a utility like Rahul Dhesi's "flip"). 3. Go to the sys/msdos directory and ensure that the file setup.bat has MSDOS style end-of-line characters rather than UNIX style end-of-line characters. You can do that using a utility like Rahul Dhesi's "flip", or by invoking the MSDOS edit utility on setup.bat and saving the file without making any changes. Failure to do this will prevent the bat file from executing completely, yet no warning message will be given. Run the setup.bat batch file with the following as the argument: GCC For djgpp and GNU MAKE. The appropriate and necessary Makefile movement will be accomplished for you, as well as verifying a few files and fixing a few file names on FAT systems with long file name support. 4. Now go to the include subdirectory to check a couple of the header files there. Things *should* work as they are, but since you have probably set up your system in some sort of custom configuration it doesn't hurt to check out the following: First check config.h according to the comments to match your system and desired set of features. Mostly you need to check the WIZARD option, and check TERMLIB and COMPRESS. Also be sure to leave DLB support commented out in config.h. MSDOS has support for DLB, but it must be done through the Makefile, rather than config.h, to ensure that the necessary packaging steps are done. We've managed to enable all the special features. You may include all or as few of them as you wish. To conserve disk space, you may wish to disable LOGFILE and NEWS. Also check pcconf.h, which should not need much editing (if you are including random.c, and if you do not require termcap for screen management). If you are not including random.c you will need to comment out RANDOM. If using DJGPP, you can choose between SCREEN_BIOS and SCREEN_DJGPPFAST. Never, never, ever choose both. Bad things will happen. We are not kidding. 5. If you want to change the high score list behavior, examine the top of topten.c, in the src directory. You may want to change the definitions of PERSMAX, POINTSMIN, and ENTRYMAX. We set POINTSMIN to 51 and ENTRYMAX to 50 to keep the size of the score list down. 6. Go to the src directory and edit the top of your Makefile. Be sure the directory you want the game installed in (GAMEDIR) actually exists. 7. Now that everything is set up, Go to the src directory, and using the GNU Make utility, "make install". Depending on your particular machine and compiler, you can either grab a cup of coffee or go home for the day. Your computer will be occupied for quite some time. If all goes well, you will get an NetHack executable. 9. If you chose DLB support (recommended), make sure that the file nhdat got copied into the game directory. If you didn't choose DLB support, make sure the support files -- data, rumors, cmdhelp, opthelp, help, hh,history, guidebook.txt license, and all the *.lev files -- were copied to the game directory. If not, move them there from the dat directory yourself. rumors can be created manually be entering "makedefs -r", data by entering "makedefs -d". Make sure the files NetHack1.tib and NetHacko.tib made it to your game directory. Copy them from src to the game directory yourself if necessary. Make sure the files defaults.nh and termcap made it to your game directory. If not, go to sys\share and copy NetHack.cnf to your game directory as defaults.nh. The name in previous versions was nethack.cnf, but the CNF extension conflicted with the MS Windows speed-dialer, making the file hidden on many machines. If you changed your build settings to include TERMCAP support, copy termcap to your game directory. Also, make sure the file msdoshlp.txt made it to your game directory. If it didn't, move it from sys\msdos to your game directory yourself. 10. In your game directory, review the settings in defaults.nh and adjust them according to your style of play. 11. Play NetHack. If it works, you're done! Appendix A - Building the "official binary" If you wish to build a copy of NetHack identical to the one that the pc team distributes, simply do the following: The 32-bit Protected Mode DPMI version built with 32-bit djgpp compiler V2.03 or greater, make no changes to any of the defines and use the Makefile.GCC as distributed, and as moved in step 3. Paths below are relative to the top of your unpacked NetHack source distribution: md \nethack\binary (must match Makefile) cd sys\msdos setup GCC cd ..\..\src make install Make sure the following files have been converted from the unix style "^J" end of line, to the msdos style "^M^J": license, defaults.nh. Place all the files in a clean directory and test. Appendix B - DJGPP Compiler (gcc ported to msdos) If you have a 386 or better machine, you are in luck. You can compile NetHack without spending money on a compiler. DJGPP is available free from many archive sites. At the time of this release in April 2002, the URL http://www.delorie.com/djgpp/zip-picker.html/ had information on how to obtain djgpp and what pieces to get. Be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and touch.exe, since the Makefile uses them by default (or change the Makefile to use alternatives). Special note for Windows 2000 / Windows XP users: You must have a recent djgpp distribution for the build process, and the generated executables to work properly on those platforms. Setting up DJGPP is more than adequately explained in the documentation that comes with it. Be sure to pick up the yacc and flex built with DJGPP if you intend to do any modification of the special levels or dungeon compilers. They should be available at the same place you got djgpp. The latest version of djgpp, V2.03 with the most recent refresh will produce a binary that will run under Microsoft Windows, or any other DPMI provider. djgpp also comes with a DPMI provider called CWSDPMI. Place CWSDPMI.EXE in your path and it will be used in the absence of any other DPMI provider. If you want to use the built-in DJGPP screen routines, uncomment SCREEN_DJGPPFAST in pcconf.h (the default for djgpp). Appendix C - Additional Notes 1) Save files and bones files from versions of NetHack prior to 3.5.0 will not work with this NetHack. Don't bother trying to keep them. 2) To install an update of NetHack after changing something, type 'make' for DJGPP from the src directory. If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but usually crashes.) Appendix D - Contacting the Development Team If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: http://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: DevTeam (at) nethack.org nethack-3.6.0/sys/msdos/Makefile.BC0000664000076400007660000017644012536476415016054 0ustar paxedpaxed# NetHack 3.6 Makefile.BC $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ # Copyright (c) Yitzhak Sapir, 1999-2006. # NetHack may be freely distributed. See license for details. # # PC NetHack 3.6 Makefile for Borland C++ 3.1 and 4.5. # # Nota Bene: Before you get to here you should have already read # the Install.dos file located in the sys/msdos directory. # Additionally, you should run this makefile with the -N # Microsoft Compatibility option. # # This Makefile is for use with Borland C++ version 3.1 and 4.5, but might # also work with more up to date versions. # # This Makefile is specific to Borland's MAKE which is supplied with the # compiler. It supports only one overlay management facility - VROOMM. # (This Makefile won't work with make45l or NDMAKE) # # NOTE: This Makefile has not been tested with NetHack 3.6.x # # Game Installation Variables. # NOTE: Make sure GAMEDIR exists before nmake is started. # GAME = NetHack GAMEDIR = ..\binary # # # Directories # DAT = ..\dat DOC = ..\doc INCL = ..\include SRC = ..\src OBJ = o MSYS = ..\sys\msdos SYS = ..\sys\share UTIL = ..\util WTTY = ..\win\tty WSHR = ..\win\share # # Compiler File Info. # ($(MAKE) macro is often predefined, so we use $(MAKEBIN) instead.) # CC = bcc # Compiler LINK = tlink # Linker ASM = tasm # Assembler (not currently needed for BC) MAKEBIN = make UUDECODE = uudecode # Unix style uudecoder #BCTOP = c:\borlandc # main Borland C++ directory BCTOP = c:\bc31 # # Yacc/Lex ... if you got 'em. # # If you have yacc and lex programs (or work-alike such as bison # and flex), comment out the upper two lines below, and uncomment # the lower two. # # On Borland C++, the newest versions of flex and bison provide # problems when run from MAKE. # DO_YACC = YACC_MSG DO_LEX = LEX_MSG #DO_YACC = YACC_ACT #DO_LEX = LEX_ACT # # - Specify your yacc and lex programs (or work-alikes for each) here. # YACC = bison -y #YACC = yacc #YACC = byacc LEX = flex #LEX = lex # # - Specify your flex skeleton file (if needed). # FLEXSKEL = #FLEXSKEL = -Sc:\tools16\flex.ske # # - Your yacc (or work-alike) output files # YTABC = y_tab.c YTABH = y_tab.h #YTABC = ytab.c #YTABH = ytab.h # # - Your lex (or work-alike) output files # LEXYYC = lexyy.c #LEXYYC = lex.yy.c # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = # # If TERMLIB is #defined in the source (in include\pcconf.h), # comment out the upper line and uncomment the lower. Make sure # that TERMLIB contains the full pathname to the termcap library. TERMLIB = #TERMLIB = $(SYS)\termcap.lib # # MEMORY USAGE AND OVERLAYING # # Overlay Schema 1 # # - Minimal extended memory available, lots of 640K base RAM free # Minimize overlay turns. Requires that a minimum of # 607K RAM be free as follows: # 462K Executable load requirement # 115K for malloc() calls # 30K Overlay buffer # 607K Total memory requirement # # Overlay Schema 2 # # - Favor small load size, requires extended memory for bearable performance. # If you have very little base 640K RAM available, but lots of extended # memory for caching overlays, you might try this. (eg. A machine with # lots of TSR's or network drivers). Do not try to set SCHEMA = 2 # without a disk cache and extended memory. # 381K Executable load requirement # 115K for malloc() calls # 30K Overlay buffer # 526K Total memory requirement # # On Borland C++, you have to make a full rebuild of all object modules each # time you change schemas. # SCHEMA = 2 # # OPTIONAL TILE SUPPORT. # # This release of NetHack allows you to build a version of NetHack # that will draw 16x16 color tiles on the display to represent # NetHack maps, objects, monsters, etc. on machines with appropriate # display hardware. Currently the only supported video hardware is # VGA. # # Note: You can build NetHack with tile support and then choose # whether to use it or not at runtime via the defaults.nh file option # "video". # TILESUPPORT = Y # # C COMPILER AND LINKER SETTINGS # # For debugging ability, comment out the upper three # macros and uncomment the lower three. You can also # uncomment only either LDFLAGSU or LDFLAGSN if you # want to include debug information only in the utilities # or only in the game file. # On Borland C++, you cannot include debug information for # all the object modules because the linker cannot handle # it. #CDFLAGS = LDFLAGSN = #LDFLAGSU = CDFLAGS = -v -vi # use debug info (compiler) #LDFLAGSN = /v # use debug info (linker - game) LDFLAGSU = /v # use debug info (linker - utilities) # # - Don't warn about unreachable code because flex generates a whole bunch # of unreachable code warnings, which stops the compile process. # CW = -w-rch # # Select whether to use pre-compiled headers or not. # Set PRECOMPHEAD to Y to use pre-compiled headers, set it to anything # else and pre-compiled headers will not be used. # (Pre-compiled headers speed up compiles, but require a bit more # disk space during the build. The pre-compiled headers can be deleted # afterwards via DEL *.PCH if desired). # PRECOMPHEAD = N # # C Compiler Flags # CFLAGS = -c # Uncomment the line below if you want to store all the level files, # help files, etc. in a single library file (recommended). USE_DLB = Y # ######################################################################## ######################################################################## # # Nothing below here should have to be changed. # ######################################################################## ######################################################################## # # Warning: # # Changing anything below here means that you should be *very* # familiar with your compiler's workings, *very* knowledgeable # about the overlay structure and mechanics of NetHack, and *very* # confident in your understanding of Makefiles and Make utilities. # ######################################################################## # # Default Make Procedure # default: $(GAME) # ######################################################################## # Tile preparation # ! IF ("$(TILESUPPORT)"=="Y") TILEGAME = $(OBJ)\tile.o $(OBJ)\pctiles.0 $(OBJ)\pctiles.b # # - VGA Tile Support, uncomment these three lines. # TILEVGA = $(OBJ)\vidvga.0 $(OBJ)\vidvga.1 $(OBJ)\vidvga.2 $(OBJ)\vidvga.b PLANAR_TIB = NetHack1.tib OVERVIEW_TIB = NetHacko.tib # # Leave this line uncommented and unchanged. TILEUTIL = $(TILEGAME) $(TILEVGA) $(UTIL)\tile2bin.exe $(UTIL)\til2bin2.exe \ $(PLANAR_TIB) $(OVERVIEW_TIB) ! ENDIF ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF # ############################################################################# # # General Overlay Schema Settings # OVLINIT =$(OBJ)\ovlinit.o # ############################################################################# # # C Compiler and Linker Setup Options # (To Maintainer; modify only if absolutely necessary) # BCINCL = $(BCTOP)\include # include directory for main BC headers BCLIB = $(BCTOP)\lib # library directory for main BC libraries BCCFG = nethack.cfg # name of the nethack configuration file VROOMMCFG= vroomm.cfg # name of file with code segment information # # Model # MODEL = h # # - Optional C library specifier for those with non-standard # libraries or a multiple-target library setup. # CLIB = # # Borland C++ libraries # BCOVL = $(BCLIB)\OVERLAY BCMDL = $(BCLIB)\C$(MODEL) # # Compiler Options # CNOLNK = -c # just generate .OBJ CPCHUSE = -Hu # use precompiled headers CPCHGEN = -H # generate precompiled headers CPCHNAM = -H= # set the name of the precompiled header file CPCHEXT = .PCH # precompiled header extension CDEFINE = -D # define a macro CSTKSZ = -DSTKSIZ= # set stack size CCSNAM = -zC # set the code segment name COBJNAM = -o # name the .OBJ file # # Linker Options # LWCASE = /c # treat case as significant LMAP = /m # create map file LINIT = $(BCLIB)\C0$(MODEL) # initialization object file LOVL = /oOVLY # overlay all needed segments # # Stack Sizes # STKSUTL = 4096 # Utilities Stack Size STKSNRM = 5120 # Normal Stack Size CUSTACK = $(CSTKSZ)$(STKSUTL) # Utilities Stack Set for Compiler CNSTACK = $(CSTKSZ)$(STKSNRM) # Normal Stack Set for Compiler # ######################################################################## # DLB preparation # ! IF ("$(USE_DLB)"=="Y") DLBFLG = $(CDEFINE)DLB ! ELSE DLBFLG = ! ENDIF # ######################################################################## # tile preparation # ! IF ("$(TILESUPPORT)"=="Y") TILFLG = $(CDEFINE)USE_TILES ! ELSE TILFLG = ! ENDIF ############################################################################# # # Overlay switches # COVL0 = $(CDEFINE)OVL0 COVL1 = $(CDEFINE)OVL1 COVL2 = $(CDEFINE)OVL2 COVL3 = $(CDEFINE)OVL3 COVLB = $(CDEFINE)OVLB # # Flags # FLAGOPT = $(DLBFLG) $(TILFLG) # # Precompiled Header Section # #common options (placed in $(BCCFG)) CFLGTOT = $(CDFLAGS) $(CFLAGS) $(FLAGOPT) $(CW) #util builds CFLAGSU = $(CUSTACK) +$(VROOMMCFG) #normal build, no PCH CFLAGSN = $(CNSTACK) +$(VROOMMCFG) #no optimizations CFLAGNO = $(CNOOPT) $(CFLAGSN) ! IF ("$(PRECOMPHEAD)"!="Y") CFLAGCO = $(COVLO) CFLAGUO = $(COVLO) CFLAGC0 = $(COVL0) CFLAGU0 = $(COVL0) CFLAGC1 = $(COVL1) CFLAGU1 = $(COVL1) CFLAGC2 = $(COVL2) CFLAGU2 = $(COVL2) CFLAGC3 = $(COVL3) CFLAGU3 = $(COVL3) CFLAGCB = $(COVLB) CFLAGUB = $(COVLB) PCHO = PCH0 = PCH1 = PCH2 = PCH3 = PCHB = precomp.msg: @echo Not using precompiled headers... ! ELSE # .o files CFLAGUO = $(CPCHUSE) $(CPCHNAM)PHO$(CPCHEXT) $(COVLO) CFLAGCO = $(CPCHGEN) $(CPCHNAM)PHO$(CPCHEXT) $(COVLO) PCHO = PHO$(CPCHEXT) # .0 files CFLAGU0 = $(CPCHUSE) $(CPCHNAM)PH0$(CPCHEXT) $(COVL0) CFLAGC0 = $(CPCHGEN) $(CPCHNAM)PH0$(CPCHEXT) $(COVL0) PCH0 = PH0$(CPCHEXT) # .1 files CFLAGU1 = $(CPCHUSE) $(CPCHNAM)PH1$(CPCHEXT) $(COVL1) CFLAGC1 = $(CPCHGEN) $(CPCHNAM)PH1$(CPCHEXT) $(COVL1) PCH1 = PH1$(CPCHEXT) # .2 files CFLAGU2 = $(CPCHUSE) $(CPCHNAM)PH2$(CPCHEXT) $(COVL2) CFLAGC2 = $(CPCHGEN) $(CPCHNAM)PH2$(CPCHEXT) $(COVL2) PCH2 = PH2$(CPCHEXT) # .3 files CFLAGU3 = $(CPCHUSE) $(CPCHNAM)PH3$(CPCHEXT) $(COVL3) CFLAGC3 = $(CPCHGEN) $(CPCHNAM)PH3$(CPCHEXT) $(COVL3) PCH3 = PH3$(CPCHEXT) # .B files CFLAGUB = $(CPCHUSE) $(CPCHNAM)PHB$(CPCHEXT) $(COVLB) CFLAGCB = $(CPCHGEN) $(CPCHNAM)PHB$(CPCHEXT) $(COVLB) PCHB = PHB$(CPCHEXT) precomp.msg: @echo Using precompiled headers... ! ENDIF FLAGCO = $(CNSTACK) +$(VROOMMCFG) FLAGUO = $(CNSTACK) +$(VROOMMCFG) FLAGC0 = $(CNSTACK) +$(VROOMMCFG) FLAGU0 = $(CNSTACK) +$(VROOMMCFG) FLAGC1 = $(CNSTACK) +$(VROOMMCFG) FLAGU1 = $(CNSTACK) +$(VROOMMCFG) FLAGC2 = $(CNSTACK) +$(VROOMMCFG) FLAGU2 = $(CNSTACK) +$(VROOMMCFG) FLAGC3 = $(CNSTACK) +$(VROOMMCFG) FLAGU3 = $(CNSTACK) +$(VROOMMCFG) FLAGCB = $(CNSTACK) +$(VROOMMCFG) FLAGUB = $(CNSTACK) +$(VROOMMCFG) # End of Pre-compiled header section #=========================================================================== # # Basic Borland C++ option line # BCOPTS1 = -Y -O -Z -Oe -Ob -Os -Ff -I$(BCINCL);$(INCL) -m$(MODEL) BCOPTS2 = $(CDEFINE)__IO_H $(CFLGTOT) -DSTRNCMPI # # Linker options for building various things. # LFLAGSU = $(LDFLAGSU) $(LUSTACK) $(LINIT) LFLAGSN = $(LDFLAGSN) $(LNSTACK) $(LWCASE) $(LMAXSEG) $(INTOVL) $(LMAXALL) \ $(LINFO) $(LINIT) $(LOVL) # # Make Roolz dude. # Due to the inadequacy of some makes these must accord with a # topological sort of the generated-from relation... output on # the left, input on the right. Trust me. # .SUFFIXES: .exe .0 .1 .2 .3 .B .o .til .uu .c .y .l # # Rules for files in src # .c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< # # Rules for files in sys\share # {$(SYS)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< # # Rules for files in sys\msdos # {$(MSYS)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< {$(MSYS)}.h{$(INCL)}.h: @copy $< $@ # # Rules for files in util # {$(UTIL)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) (COBJNAM)$@ $< # # Rules for files in win\share # {$(WSHR)}.c.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) @$(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(WSHR)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) @$(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ {$(WSHR)}.txt{$(DAT)}.txt: @copy $< $@ # # Rules for files in win\tty # {$(WTTY)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< # # NETHACK OBJECTS # # This section creates shorthand macros for many objects # referenced later on in the Makefile. # # # Shorten up the location for some files # O = $(OBJ)\ # comment so \ isn't last char U = $(UTIL)\ # comment so \ isn't last char SPLEVDES = $(DAT)\Arch.des $(DAT)\Barb.des $(DAT)\bigroom.des \ $(DAT)\castle.des $(DAT)\Caveman.des $(DAT)\endgame.des \ $(DAT)\gehennom.des $(DAT)\Healer.des $(DAT)\Knight.des \ $(DAT)\knox.des $(DAT)\Monk.des $(DAT)\medusa.des \ $(DAT)\mines.des $(DAT)\oracle.des $(DAT)\Priest.des \ $(DAT)\Ranger.des $(DAT)\Rogue.des $(DAT)\Samurai.des \ $(DAT)\Tourist.des $(DAT)\tower.des $(DAT)\Valkyrie.des \ $(DAT)\Wizard.des $(DAT)\yendor.des # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS =$(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o $(O)monst.o \ $(O)objects.o $(O)panic.o $(O)stubvid.o DGNCOMPOBJS =$(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o GIFREADERS =$(O)gifread.o $(O)alloc.o $(O)panic.o TEXT_IO =$(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o $(O)stubvid.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o GIFREAD2 =$(O)gifread2.o $(O)alloc.o $(O)panic.o TEXT_IO2 =$(O)tiletex2.o $(O)tiletxt2.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o $(O)stubvid.o PPMWRIT2 = $(O)ppmwrit2.o $(O)alloc.o $(O)panic.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt TILEFILES2 = $(WSHR)\monthin.txt $(WSHR)\objthin.txt $(WSHR)\oththin.txt DLBOBJS = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # OBJ01 = $(O)alloc.o $(RANDOM) $(O)decl.o $(O)objects.o \ $(O)muse.o $(O)display.o $(O)vision.o $(O)mapglyph.o \ $(O)rect.o $(O)vis_tab.o $(O)monst.o $(O)wintty.o \ $(O)files.o $(O)sys.o $(O)monstr.o $(O)minion.o \ $(O)worm.o $(O)detect.o $(O)exper.o $(O)mplayer.o \ $(O)uhitm.o $(O)pager.o $(O)windows.o $(O)quest.o \ $(O)questpgr.o $(O)write.o $(O)drawing.o $(O)dokick.o \ $(O)dothrow.o $(O)pickup.o $(O)pray.o $(O)spell.o \ $(O)ball.o $(O)wield.o $(O)worn.o $(O)fountain.o \ $(O)music.o $(O)rumors.o $(O)dlb.o $(O)sit.o \ $(O)bones.o $(O)mklev.o $(O)save.o $(O)restore.o \ $(O)mkmaze.o $(O)mkmap.o $(O)end.o $(O)o_init.o \ $(O)options.o $(O)rip.o $(O)sound.o $(O)teleport.o \ $(O)topten.o $(O)tty.o $(O)u_init.o $(O)extralev.o \ $(O)sp_lev.o $(O)dig.o $(O)pckeys.o $(O)role.o \ $(O)steed.o $(O)region.o OVL0 = $(O)allmain.0 $(O)apply.0 $(O)artifact.0 $(O)attrib.0 \ $(O)botl.0 $(O)cmd.0 $(O)dbridge.0 $(O)do.0 \ $(O)do_name.0 $(O)do_wear.0 $(O)dogmove.0 $(O)dungeon.0 \ $(O)eat.0 $(O)engrave.0 $(O)hacklib.0 $(O)invent.0 \ $(O)lock.0 $(O)pcmain.0 $(O)mail.0 $(O)makemon.0 \ $(O)mcastu.0 $(O)mhitm.0 $(O)mhitu.0 $(O)mkobj.0 \ $(O)mkroom.0 $(O)mon.0 $(O)mondata.0 $(O)monmove.0 \ $(O)mthrowu.0 $(O)objnam.0 $(O)polyself.0 $(O)priest.0 \ $(O)rnd.0 $(O)shknam.0 $(O)sounds.0 $(O)steal.0 \ $(O)timeout.0 $(O)track.0 $(O)trap.0 $(O)vault.0 \ $(O)weapon.0 $(O)were.0 $(O)wizard.0 $(O)msdos.0 \ $(O)termcap.0 $(O)video.0 $(O)vidtxt.0 $(O)zap.0 \ $(O)explode.0 $(O)shk.0 OVL1 = $(O)allmain.1 $(O)apply.1 $(O)artifact.1 $(O)attrib.1 \ $(O)botl.1 $(O)cmd.1 $(O)dbridge.1 $(O)do.1 \ $(O)do_wear.1 $(O)dog.1 $(O)dungeon.1 $(O)eat.1 \ $(O)engrave.1 $(O)hack.1 $(O)hacklib.1 $(O)invent.1 \ $(O)makemon.1 $(O)mhitu.1 $(O)mkobj.1 $(O)mon.1 \ $(O)mondata.1 $(O)monmove.1 $(O)mthrowu.1 $(O)objnam.1 \ $(O)pcmain.1 $(O)polyself.1 $(O)rnd.1 $(O)shk.1 \ $(O)steal.1 $(O)timeout.1 $(O)track.1 $(O)trap.1 \ $(O)weapon.1 $(O)getline.1 $(O)termcap.1 $(O)topl.1 \ $(O)video.1 $(O)zap.1 $(O)explode.1 OVL2 = $(O)attrib.2 $(O)do.2 $(O)do_name.2 $(O)do_wear.2 \ $(O)dog.2 $(O)engrave.2 $(O)hack.2 $(O)hacklib.2 \ $(O)invent.2 $(O)makemon.2 $(O)mon.2 $(O)mondata.2 \ $(O)monmove.2 $(O)getline.2 $(O)shk.2 $(O)topl.2 \ $(O)trap.2 $(O)zap.2 OVL3 = $(O)do.3 $(O)hack.3 $(O)invent.3 $(O)light.3 \ $(O)shk.3 $(O)trap.3 $(O)zap.3 OVLB = $(O)allmain.B $(O)apply.B $(O)artifact.B $(O)attrib.B \ $(O)botl.B $(O)cmd.B $(O)dbridge.B $(O)do.B \ $(O)do_name.B $(O)do_wear.B $(O)dog.B $(O)dogmove.B \ $(O)eat.B $(O)engrave.B $(O)hack.B $(O)hacklib.B \ $(O)invent.B $(O)lock.B $(O)mail.B $(O)makemon.B \ $(O)mcastu.B $(O)mhitm.B $(O)mhitu.B $(O)mkobj.B \ $(O)mkroom.B $(O)mon.B $(O)mondata.B $(O)monmove.B \ $(O)mthrowu.B $(O)objnam.B $(O)pcmain.B $(O)pline.B \ $(O)polyself.B $(O)potion.B $(O)priest.B $(O)read.B \ $(O)rnd.B $(O)shk.B $(O)shknam.B $(O)sounds.B \ $(O)steal.B $(O)timeout.B $(O)track.B $(O)trap.B \ $(O)vault.B $(O)weapon.B $(O)were.B $(O)wizard.B \ $(O)msdos.B $(O)pcunix.B $(O)termcap.B $(O)topl.B \ $(O)video.B $(O)vidtxt.B $(O)zap.B TILOBJ = $(TILEGAME) $(TILEVGA) VVOBJ = $(O)version.o NVOBJ = $(OBJ01) $(OVL0) $(OVL1) $(OVL2) \ $(OVL3) $(OVLB) $(TILOBJ) ALLOBJ= $(NVOBJ) $(VVOBJ) $(OVLINIT) # # Header objects # # This comment copied from sys/unix/Makefile.src, # extern.h is ignored, even though its declared function types may affect the # compilation of all the .c files, since extern.h changes every time the # type of an external function does, and we would spend all our time recompiling # if we did not ignore it. #EXTERN_H = $(INCL)\extern.h EXTERN_H = PCCONF_H = $(INCL)\pcconf.h $(INCL)\micro.h $(INCL)\system.h PERMONST_H = $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\align.h YOUPROP_H = $(INCL)\prop.h $(PERMONST_H) $(INCL)\pm.h $(INCL)\youprop.h \ $(INCL)\mondata.h YOU_H = $(INCL)\attrib.h $(INCL)\monst.h $(INCL)\mextra.h $(YOUPROP_H) \ $(INCL)\align.h DECL_H = $(INCL)\quest.h $(INCL)\spell.h $(INCL)\color.h \ $(INCL)\obj.h $(YOU_H) $(INCL)\onames.h $(INCL)\pm.h CONFIG_H = $(INCL)\config1.h $(INCL)\tradstdc.h $(INCL)\coord.h $(PCCONF_H) \ $(INCL)\config.h HACK_H = $(CONFIG_H) $(INCL)\context.h $(INCL)\dungeon.h $(INCL)\align.h \ $(INCL)\monsym.h $(INCL)\mkroom.h $(INCL)\objclass.h $(DECL_H) \ $(INCL)\timeout.h $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\mondata.h $(INCL)\wintype.h \ $(INCL)\engrave.h $(INCL)\rect.h $(EXTERN_H) $(INCL)\sys.h \ $(INCL)\winprocs.h $(INCL)\trampoli.h $(INCL)\display.h TILE_H = $(INCL)\tile.h $(INCL)\pctiles.h PCVIDEO_H = $(INCL)\portio.h $(INCL)\pcvideo.h ALIGN_H = $(INCL)\align.h ARTIFACT_H = $(INCL)\artifact.h ARTILIST_H = $(INCL)\artilist.h COLOR_H = $(INCL)\color.h DATE_H = $(INCL)\date.h DGN_FILE_H = $(INCL)\dgn_file.h DLB_H = $(INCL)\dlb.h FUNC_TAB_H = $(INCL)\func_tab.h LEV_H = $(INCL)\lev.h LEV_COMP_H = $(INCL)\lev_comp.h MAIL_H = $(INCL)\mail.h MFNDPOS_H = $(INCL)\mfndpos.h MONSYM_H = $(INCL)\monsym.h OBJ_H = $(INCL)\obj.h OBJCLASS_H = $(INCL)\objclass.h OBJECTS_H = $(INCL)\objects.h PROP_H = $(INCL)\prop.h QTEXT_H = $(INCL)\qtext.h QUEST_H = $(INCL)\quest.h SP_LEV_H = $(INCL)\sp_lev.h TERMCAP_H = $(INCL)\tcap.h VIS_TAB_H = $(INCL)\vis_tab.h WINTTY_H = $(INCL)\wintty.h # # In the unix distribution this file is patchlevel.h, make it 8.3 here # to avoid an nmake warning under dos. # PATCHLEVEL_H = $(INCL)\patchlev.h # # The name of the game. # GAMEFILE = $(GAMEDIR)\$(GAME).exe # # make data.base an 8.3 filename to prevent an nmake warning # DATABASE = $(DAT)\data.bas ####################################################################### # # TARGETS # # The main target. # $(GAME): obj.tag envchk $(U)utility.tag $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all : install install: $(GAME) install.tag @echo Done. install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(DAT)\sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) copy $(MSYS)\msdoshlp.txt $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF copy $(SYS)\termcap $(GAMEDIR) if exist $(DAT)\symbols copy $(DAT)\symbols $(GAMEDIR) if exist $(DOC)\guideb*.txt copy $(DOC)\guideb*.txt $(GAMEDIR) if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR) copy $(SYS)\NetHack.cnf $(GAMEDIR)\defaults.nh copy $(MSYS)\NHAccess.nh $(GAMEDIR) copy $(U)recover.exe $(GAMEDIR) if exist *.tib copy *.tib $(GAMEDIR) echo install done > $@ $(DAT)\sp_lev.tag: $(U)utility.tag $(SPLEVDES) cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(SRC) echo sp_levs done > $(DAT)\sp_lev.tag $(U)utility.tag: envchk $(INCL)\date.h $(INCL)\onames.h \ $(INCL)\pm.h $(SRC)\monstr.c $(SRC)\vis_tab.c \ $(U)lev_comp.exe $(VIS_TAB_H) $(U)dgn_comp.exe \ $(U)recover.exe $(TILEUTIL) @echo utilities made >$@ @echo utilities made. tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. # # Inline files : # Specifying the "<<" means to start an inline file. # Another "<<" at the start of a line closes the # inline file. # # DO NOT INDENT THE << below! # $(GAMEFILE) : $(ALLOBJ) @echo Linking.... $(LINK) $(LFLAGSN) @<<$(GAME).lnk $(ALLOBJ) $(GAMEFILE) $(GAME) $(TERMLIB) $(MOVETR) $(CLIB) $(BCOVL) $(BCMDL) << @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak # # Makedefs Stuff # $(U)makedefs.exe: $(MAKEOBJS) @$(LINK) $(LFLAGSU) $(MAKEOBJS), $@,, $(CLIB) $(BCMDL); $(O)makedefs.o: $(CONFIG_H) $(PERMONST_H) $(OBJCLASS_H) \ $(MONSYM_H) $(QTEXT_H) $(PATCHLEVEL_H) \ $(U)makedefs.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h : $(U)makedefs.exe $(U)makedefs -v @echo A new $@ has been created. $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z # # Level Compiler Stuff # $(U)lev_comp.exe: $(SPLEVOBJS) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)stubvid.o $(O)panic.o $(O)objects.o $(O)monst.o + $(O)drawing.o $(O)decl.o $(O)alloc.o $(O)lev_main.o + $(O)lev_$(LEX).o $(O)lev_yacc.o $@ $(@B) $(BCMDL); ! $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)lev_comp.y copy $(YTABC) $(U)lev_yacc.c copy $(YTABH) $(INCL)\lev_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt lev_yacc.c @echo from $(SYS) to $(U)lev_yacc.c, and copy the prebuilt @echo lev_comp.h from $(SYS) to $(UTIL)\lev_comp.h @echo and use those. @echo. copy $(SYS)\lev_yacc.c $@ >nul touch $@ copy $(SYS)\lev_comp.h $(INCL)\lev_comp.h >nul touch $(INCL)\lev_comp.h ! ENDIF $(U)lev_$(LEX).c: $(U)lev_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt lev_lex.c @echo from $(SYS) to $@ and use it. @echo. copy $(SYS)\lev_lex.c $@ >nul touch $@ ! ENDIF # # Dungeon Stuff # $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)panic.o $(O)alloc.o $(O)dgn_main.o $(O)dgn_$(LEX).o + $(O)dgn_yacc.o $@ $(@B) $(BCMDL); ! $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_yacc.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)dgn_comp.y copy $(YTABC) $(U)dgn_yacc.c copy $(YTABH) $(INCL)\dgn_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)dgn_comp.y has changed. To update $@ and @echo $(INCL)\dgn_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt dgn_yacc.c from @echo $(SYS) to $(U)dgn_yacc.c, and copy the prebuilt @echo dgn_comp.h from $(SYS) to $(INCL)\dgn_comp.h @echo and use those. @echo. copy $(SYS)\dgn_yacc.c $@ >nul touch $@ copy $(SYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul touch $(INCL)\dgn_comp.h ! ENDIF $(U)dgn_$(LEX).c: $(U)dgn_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt dgn_lex.c @echo from $(SYS) to $@ and use it. @echo. copy $(SYS)\dgn_lex.c $@ >nul touch $@ ! ENDIF obj.tag: @if not exist $(O)*.* mkdir $(OBJ) @echo directory $(OBJ) created @echo directory $(OBJ) created >$@ envchk: precomp.msg ! IF "$(TILEGAME)"=="" @echo. @echo NOTE: This build will NOT include tile support. @echo. ! ELSE @echo. @echo This build includes tile support. @echo. ! ENDIF # # SECONDARY TARGETS # # # Header files NOT distributed in ..\include # $(INCL)\tile.h: $(WSHR)\tile.h copy $(WSHR)\tile.h $@ $(INCL)\pctiles.h: $(MSYS)\pctiles.h copy $(MSYS)\pctiles.h $@ $(INCL)\pcvideo.h: $(MSYS)\pcvideo.h copy $(MSYS)\pcvideo.h $@ $(INCL)\portio.h: $(MSYS)\portio.h copy $(MSYS)\portio.h $@ # # Recover Utility # $(U)recover.exe: $(RECOVOBJS) @$(LINK) $(LFLAGSU) $(RECOVOBJS),$@,, $(CLIB) $(BCMDL); # # Tile Mapping # $(SRC)\tile.c: $(U)tilemap.exe @echo A new $@ is being created. @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o @$(LINK) $(LFLAGSU) $(O)tilemap.o,$@,, $(CLIB) $(BCMDL); $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\tilemap.c # # Tile Utilities # # # Optional (for development) # # $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) @$(LINK) $(LFLAGSU) << $(@B).lnk $(GIFREADERS) $(TEXT_IO) $@,,$(CLIB) $(BCMDL) << $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) @$(LINK) $(LFLAGSU) << $(@B).lnk $(PPMWRITERS) $(TEXT_IO) $@,,$(CLIB) $(BCMDL); << $(U)gif2txt2.exe: $(GIFREAD2) $(TEXT_IO2) @$(LINK) $(LFLAGSU) << $(@B).lnk $(GIFREAD2) $(TEXT_IO2) $@,,$(CLIB) $(BCMDL); << $(U)txt2ppm2.exe: $(PPMWRIT2) $(TEXT_IO2) @$(LINK) $(LFLAGSU) << $(@B).lnk $(PPMWRIT2) $(TEXT_IO2) $@,,$(CLIB) $(BCMDL); << # # Required for tile support # NetHack1.tib: $(TILEFILES) $(U)tile2bin.exe @echo Creating binary tile files (this may take some time) @$(U)tile2bin NetHackO.tib: thintile.tag $(TILEFILES2) $(U)til2bin2.exe @echo Creating overview binary tile files (this may take some time) @$(U)til2bin2 thintile.tag: $(U)thintile.exe $(TILEFILES) $(U)thintile @echo thintiles created >thintile.tag $(U)tile2bin.exe: $(O)tile2bin.o $(TEXT_IO) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)tile2bin.o+ $(O)stubvid.o $(O)objects.o $(O)monst.o $(O)decl.o + $(O)drawing.o $(O)tiletxt.o $(O)tiletext.o $@ $(@B) $(BCMDL); ! $(U)til2bin2.exe: $(O)til2bin2.o $(TEXT_IO2) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)til2bin2.o+ $(O)stubvid.o $(O)objects.o $(O)monst.o $(O)decl.o + $(O)drawing.o $(O)tiletxt2.o $(O)tiletex2.o $@ $(@B) $(BCMDL); ! $(U)thintile.exe: $(O)thintile.o @$(LINK) $(LFLAGSU) $(O)thintile.o,$@,, $(CLIB) $(BCMDL); $(O)thintile.o: $(HACK_H) $(INCL)\tile.h $(WSHR)\thintile.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\thintile.c $(O)tile2bin.o: $(HACK_H) $(TILE_H) $(PCVIDEO_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(MSYS)\tile2bin.c $(O)til2bin2.o: $(HACK_H) $(TILE_H) $(PCVIDEO_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILE_X=8 $(CDEFINE)OVERVIEW_FILE \ $(COBJNAM)$@ $(MSYS)\tile2bin.c # # DLB stuff # nhdat: $(U)dlb_main.exe @copy $(MSYS)\msdoshlp.txt $(DAT) @cd $(DAT) @echo data >dlb.lst @echo oracles >>dlb.lst @echo options >>dlb.lst @echo quest.dat >>dlb.lst @echo rumors >>dlb.lst @echo help >>dlb.lst @echo hh >>dlb.lst @echo cmdhelp >>dlb.lst @echo history >>dlb.lst @echo opthelp >>dlb.lst @echo wizhelp >>dlb.lst @echo dungeon >>dlb.lst @echo license >>dlb.lst @echo msdoshlp.txt >>dlb.lst @for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cvIf dlb.lst $(SRC)\nhdat @cd $(SRC) $(U)dlb_main.exe: $(DLBOBJS) @$(LINK) $(LFLAGSU) $(DLBOBJS),$@,, $(CLIB) $(BCMDL); $(O)dlb_main.o: $(U)dlb_main.c $(INCL)\config.h $(DLB_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dlb_main.c # # Housekeeping # spotless: clean rmdir $(OBJ) if exist $(DATE_H) del $(DATE_H) if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(VIS_TAB_H) del $(VIS_TAB_H) if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(DAT)\*.lev del $(DAT)\*.lev if exist $(DAT)\sp_lev.tag del $(DAT)\sp_lev.tag if exist $(SRC)\monstr.c del $(SRC)\monstr.c if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\$(PLANAR_TIB) del $(SRC)\$(PLANAR_TIB) if exist $(SRC)\$(OVERVIEW_TIB) del $(SRC)\$(OVERVIEW_TIB) if exist $(U)recover.exe del $(U)recover.exe clean: if exist $(O)*.o del $(O)*.o if exist $(O)*.0 del $(O)*.0 if exist $(O)*.1 del $(O)*.1 if exist $(O)*.2 del $(O)*.2 if exist $(O)*.3 del $(O)*.3 if exist $(O)*.b del $(O)*.b if exist $(U)utility.tag del $(U)utility.tag if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)lev_comp.exe del $(U)lev_comp.exe if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe if exist $(U)dlb_main.exe del $(U)dlb_main.exe if exist $(SRC)\*.lnk del $(SRC)\*.lnk if exist $(SRC)\*.map del $(SRC)\*.map if exist $(SRC)\*$(CPCHEXT) del $(SRC)\*$(CPCHEXT) if exist $(SRC)\*.cfg del $(SRC)\*.cfg if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst pch.c: $(HACK_H) @echo ^#include "hack.h" > $@ @echo main(int argc, char *argv[]) >> $@ @echo { >> $@ @echo } >> $@ @echo. >> $@ # # OTHER DEPENDENCIES # # # Precompiled Header dependencies # (We need to force the generation of these at the beginning) # PHO$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .O files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGCO) >> $(VROOMMCFG) @$(CC) $(FLAGCO) pch.c PH0$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .0 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC0) >> $(VROOMMCFG) @$(CC) $(FLAGC0) pch.c PH1$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .1 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC1) >> $(VROOMMCFG) @$(CC) $(FLAGC1) pch.c PH2$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .2 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC2) >> $(VROOMMCFG) @$(CC) $(FLAGC2) pch.c PH3$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .3 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC3) >> $(VROOMMCFG) @$(CC) $(FLAGC3) pch.c PHB$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .B files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGCB) >> $(VROOMMCFG) @$(CC) $(FLAGCB) pch.c # Overlay initialization routines used by pcmain() at startup to # determine EMS/XMS memory usage. # Comment out the following line if you don't want Borland C++ to check for # extended memory. RECOGNIZE_XMS = $(CDEFINE)RECOGNIZE_XMS $(O)ovlinit.o: $(MSYS)\ovlinit.c $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(RECOGNIZE_XMS) $(COBJNAM)$@ $(MSYS)\ovlinit.c # # dat dependencies # $(DAT)\data: $(U)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(U)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(U)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(U)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(U)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(SRC) # # Util Dependencies. # $(O)panic.o: $(U)panic.c $(CONFIG_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)panic.c $(O)recover.o: $(CONFIG_H) $(U)recover.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)recover.c # # from win\share # $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILETEXT $(COBJNAM)$@ $(WSHR)\tilemap.c $(O)tiletxt2.o: $(WSHR)\tilemap.c $(HACK_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILETEXT \ $(CDEFINE)TILE_X=8 $(COBJNAM)$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\gifread.c $(O)gifread2.o: $(WSHR)\gifread.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(CDEFINE)TILE_X=8 $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\ppmwrite.c $(O)ppmwrit2.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(CDEFINE)TILE_X=8 $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\tiletext.c $(O)tiletex2.o: $(WSHR)\tiletext.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILE_X=8 $(COBJNAM)$@ $(WSHR)\tiletext.c # # from win\tty # $(O)getline.1: $(PCH1) $(WTTY)\getline.c $(HACK_H) $(WINTTY_H) $(FUNC_TAB_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\getline.c $(O)getline.2: $(PCH2) $(WTTY)\getline.c $(HACK_H) $(WINTTY_H) $(FUNC_TAB_H) @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $(WTTY)\getline.c $(O)termcap.0: $(PCH0) $(WTTY)\termcap.c $(HACK_H) $(WINTTY_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(WTTY)\termcap.c $(O)termcap.1: $(PCH1) $(WTTY)\termcap.c $(HACK_H) $(WINTTY_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\termcap.c $(O)termcap.B: $(PCHB) $(WTTY)\termcap.c $(HACK_H) $(WINTTY_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(WTTY)\termcap.c $(O)topl.1: $(PCH1) $(WTTY)\topl.c $(HACK_H) $(TERMCAP_H) $(WINTTY_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\topl.c $(O)topl.2: $(PCH2) $(WTTY)\topl.c $(HACK_H) $(TERMCAP_H) $(WINTTY_H) @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $(WTTY)\topl.c $(O)topl.B: $(PCHB) $(WTTY)\topl.c $(HACK_H) $(TERMCAP_H) $(WINTTY_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(WTTY)\topl.c $(O)wintty.o: $(PCHO) $(CONFIG_H) $(WTTY)\wintty.c $(PATCHLEVEL_H) $(DATE_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(WTTY)\wintty.c # # from sys\share # $(O)pcmain.0: $(PCH0) $(HACK_H) $(SYS)\pcmain.c @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(SYS)\pcmain.c $(O)pcmain.1: $(PCH1) $(HACK_H) $(SYS)\pcmain.c @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(SYS)\pcmain.c $(O)pcmain.B: $(PCHB) $(HACK_H) $(SYS)\pcmain.c @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(SYS)\pcmain.c $(O)pcunix.B: $(PCHB) $(SYS)\pcunix.c $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(SYS)\pcunix.c $(O)tty.o: $(HACK_H) $(WINTTY_H) $(SYS)\pctty.c @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SYS)\pctty.c $(O)pcsys.o: $(HACK_H) $(SYS)\pcsys.c @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SYS)\pcsys.c $(O)random.o: $(PCHO) $(HACK_H) $(SYS)\random.c @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(SYS)\random.c # # from sys\msdos # $(O)msdos.0: $(MSYS)\msdos.c $(HACK_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVL0) $(COBJNAM)$@ $(MSYS)\msdos.c $(O)msdos.B: $(MSYS)\msdos.c $(HACK_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVLB) $(COBJNAM)$@ $(MSYS)\msdos.c $(O)pctiles.0: $(PCH0) $(MSYS)\pctiles.c $(HACK_H) $(TILE_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\pctiles.c $(O)pctiles.B: $(PCHB) $(MSYS)\pctiles.c $(HACK_H) $(TILE_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\pctiles.c $(O)sound.o: $(PCH0) $(MSYS)\sound.c $(HACK_H) $(INCL)\portio.h @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(MSYS)\sound.c $(O)pckeys.o: $(PCHO) $(MSYS)\pckeys.c $(HACK_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(MSYS)\pckeys.c $(O)stubvid.o : $(MSYS)\video.c $(HACK_H) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(CDEFINE)STUBVIDEO $(COBJNAM)$@ $(MSYS)\video.c $(O)video.0: $(PCH0) $(MSYS)\video.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\video.c $(O)video.1: $(PCH1) $(MSYS)\video.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(MSYS)\video.c $(O)video.B: $(PCHB) $(MSYS)\video.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\video.c $(O)vidtxt.0: $(MSYS)\vidtxt.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVL0) $(COBJNAM)$@ $(MSYS)\vidtxt.c $(O)vidtxt.B: $(MSYS)\vidtxt.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVLB) $(COBJNAM)$@ $(MSYS)\vidtxt.c $(O)vidvga.0: $(PCH0) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\vidvga.c $(O)vidvga.1: $(PCH1) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(MSYS)\vidvga.c $(O)vidvga.2: $(PCH2) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $(MSYS)\vidvga.c $(O)vidvga.B: $(PCHB) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\vidvga.c # # from src # $(O)alloc.o: $(SRC)\alloc.c $(CONFIG_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\alloc.c $(O)ball.o: $(PCHO) $(SRC)\ball.c $(HACK_H) $(O)bones.o: $(PCHO) $(SRC)\bones.c $(HACK_H) $(LEV_H) $(O)decl.o: $(PCHO) $(SRC)\decl.c $(HACK_H) $(QUEST_H) $(O)detect.o: $(PCHO) $(SRC)\detect.c $(HACK_H) $(ARTIFACT_H) $(O)dig.o: $(PCHO) $(SRC)\dig.c $(HACK_H) # check dep $(O)display.o: $(PCHO) $(SRC)\display.c $(HACK_H) $(O)dlb.o: $(SRC)\dlb.c $(DLB_H) $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\dlb.c $(O)dokick.o: $(PCHO) $(SRC)\dokick.c $(HACK_H) $(O)dothrow.o: $(PCHO) $(SRC)\dothrow.c $(HACK_H) $(O)drawing.o: $(SRC)\drawing.c $(HACK_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\drawing.c $(O)end.o: $(SRC)\end.c $(HACK_H) $(LEV_H) $(DLB_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\end.c $(O)exper.o: $(PCHO) $(SRC)\exper.c $(HACK_H) $(O)extralev.o: $(PCHO) $(SRC)\extralev.c $(HACK_H) $(O)files.o: $(PCHO) $(SRC)\files.c $(HACK_H) $(DLB_H) $(O)fountain.o: $(PCHO) $(SRC)\fountain.c $(HACK_H) $(O)mapglyph.o: $(PCHO) $(SRC)\mapglyph.c $(HACK_H) $(O)minion.o: $(PCHO) $(SRC)\minion.c $(HACK_H) $(O)mklev.o: $(PCHO) $(SRC)\mklev.c $(HACK_H) $(O)mkmap.o: $(PCHO) $(SRC)\mkmap.c $(HACK_H) $(SP_LEV_H) $(O)mkmaze.o: $(PCHO) $(SRC)\mkmaze.c $(HACK_H) $(SP_LEV_H) $(LEV_H) $(O)monst.o: $(SRC)\monst.c $(CONFIG_H) $(PERMONST_H) $(MONSYM_H) \ $(COLOR_H) $(ALIGN_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\monst.c $(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\monstr.c $(O)mplayer.o: $(PCHO) $(SRC)\mplayer.c $(HACK_H) $(O)muse.o: $(PCHO) $(SRC)\muse.c $(HACK_H) $(O)music.o: $(PCHO) $(SRC)\music.c $(HACK_H) $(O)o_init.o: $(PCHO) $(SRC)\o_init.c $(HACK_H) $(LEV_H) $(O)objects.o: $(SRC)\objects.c $(CONFIG_H) $(OBJ_H) $(OBJCLASS_H) \ $(PROP_H) $(COLOR_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\objects.c $(O)options.o: $(SRC)\options.c $(HACK_H) $(TERMCAP_H) $(OBJCLASS_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\options.c $(O)pager.o: $(SRC)\pager.c $(HACK_H) $(DLB_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGNO) $(COBJNAM)$@ $(SRC)\pager.c $(O)pickup.o: $(PCHO) $(SRC)\pickup.c $(HACK_H) $(O)pray.o: $(PCHO) $(SRC)\pray.c $(HACK_H) $(O)quest.o: $(PCHO) $(SRC)\quest.c $(HACK_H) $(QUEST_H) $(QTEXT_H) $(O)questpgr.o: $(PCHO) $(SRC)\questpgr.c $(HACK_H) $(QTEXT_H) $(DLB_H) $(O)rect.o: $(PCHO) $(SRC)\rect.c $(HACK_H) $(O)region.o: $(PCHO) $(SRC)\region.c $(HACK_H) $(O)restore.o: $(PCHO) $(SRC)\restore.c $(HACK_H) $(LEV_H) $(TERMCAP_H) \ $(QUEST_H) $(O)rip.o: $(PCHO) $(SRC)\rip.c $(HACK_H) $(O)role.o: $(PCHO) $(SRC)\role.c $(HACK_H) $(O)rumors.o: $(PCHO) $(SRC)\rumors.c $(HACK_H) $(DLB_H) $(O)save.o: $(PCHO) $(SRC)\save.c $(HACK_H) $(LEV_H) $(QUEST_H) $(O)sit.o: $(PCHO) $(SRC)\sit.c $(HACK_H) $(ARTIFACT_H) $(O)steed.o: $(PCHO) $(SRC)\steed.c $(HACK_H) $(O)sys.o: $(PCHO) $(SRC)\sys.c $(HACK_H) $(O)sp_lev.o: $(PCHO) $(SRC)\sp_lev.c $(HACK_H) $(SP_LEV_H) $(DLB_H) $(O)spell.o: $(PCHO) $(SRC)\spell.c $(HACK_H) $(O)teleport.o: $(PCHO) $(SRC)\teleport.c $(HACK_H) # check dep $(O)tile.o: $(PCHO) $(SRC)\tile.c $(HACK_H) $(O)topten.o: $(PCHO) $(SRC)\topten.c $(HACK_H) $(DLB_H) $(PATCHLEVEL_H) $(O)u_init.o: $(PCHO) $(SRC)\u_init.c $(HACK_H) $(O)uhitm.o: $(PCHO) $(SRC)\uhitm.c $(HACK_H) $(O)version.o: $(PCHO) $(SRC)\version.c $(HACK_H) $(PATCHLEVEL_H) $(O)vision.o: $(PCHO) $(SRC)\vision.c $(HACK_H) $(VIS_TAB_H) $(O)vis_tab.o: $(SRC)\vis_tab.c $(HACK_H) $(VIS_TAB_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\vis_tab.c $(O)wield.o: $(PCHO) $(SRC)\wield.c $(HACK_H) $(O)windows.o: $(PCHO) $(SRC)\windows.c $(HACK_H) $(WINTTY_H) $(O)worm.o: $(PCHO) $(SRC)\worm.c $(HACK_H) $(LEV_H) $(O)worn.o: $(PCHO) $(SRC)\worn.c $(HACK_H) $(O)write.o: $(PCHO) $(SRC)\write.c $(HACK_H) # # Overlays # # OVL0 # $(O)allmain.0: $(PCH0) $(SRC)\allmain.c $(HACK_H) $(O)apply.0: $(PCH0) $(SRC)\apply.c $(HACK_H) $(O)artifact.0: $(PCH0) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H) $(O)attrib.0: $(PCH0) $(SRC)\attrib.c $(HACK_H) $(O)botl.0: $(PCH0) $(SRC)\botl.c $(HACK_H) $(O)cmd.0: $(PCH0) $(SRC)\cmd.c $(HACK_H) $(FUNC_TAB_H) $(O)dbridge.0: $(PCH0) $(SRC)\dbridge.c $(HACK_H) $(O)do.0: $(PCH0) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_name.0: $(PCH0) $(SRC)\do_name.c $(HACK_H) $(O)do_wear.0: $(PCH0) $(SRC)\do_wear.c $(HACK_H) $(O)dogmove.0: $(PCH0) $(SRC)\dogmove.c $(HACK_H) $(MFNDPOS_H) $(O)dungeon.0: $(PCH0) $(SRC)\dungeon.c $(HACK_H) $(ALIGN_H) $(DGN_FILE_H) \ $(DLB_H) $(O)eat.0: $(PCH0) $(SRC)\eat.c $(HACK_H) $(O)engrave.0: $(PCH0) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)explode.0: $(PCH0) $(SRC)\explode.c $(HACK_H) $(O)hacklib.0: $(PCH0) $(SRC)\hacklib.c $(HACK_H) $(O)invent.0: $(PCH0) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)lock.0: $(PCH0) $(SRC)\lock.c $(HACK_H) $(O)mail.0: $(PCH0) $(SRC)\mail.c $(HACK_H) $(MAIL_H) $(DATE_H) $(O)makemon.0: $(PCH0) $(SRC)\makemon.c $(HACK_H) $(O)mcastu.0: $(PCH0) $(SRC)\mcastu.c $(HACK_H) $(O)mhitm.0: $(PCH0) $(SRC)\mhitm.c $(HACK_H) $(ARTIFACT_H) $(O)mhitu.0: $(PCH0) $(SRC)\mhitu.c $(HACK_H) $(ARTIFACT_H) $(O)mkobj.0: $(PCH0) $(SRC)\mkobj.c $(HACK_H) $(ARTIFACT_H) $(PROP_H) $(O)mkroom.0: $(PCH0) $(SRC)\mkroom.c $(HACK_H) $(O)mon.0: $(PCH0) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(O)mondata.0: $(PCH0) $(SRC)\mondata.c $(HACK_H) $(O)monmove.0: $(PCH0) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)mthrowu.0: $(PCH0) $(SRC)\mthrowu.c $(HACK_H) $(O)objnam.0: $(PCH0) $(SRC)\objnam.c $(HACK_H) $(O)polyself.0: $(PCH0) $(SRC)\polyself.c $(HACK_H) $(O)priest.0: $(PCH0) $(SRC)\priest.c $(HACK_H) $(MFNDPOS_H) $(O)rnd.0: $(PCH0) $(SRC)\rnd.c $(HACK_H) $(O)shk.0: $(PCH0) $(SRC)\shk.c $(HACK_H) $(O)shknam.0: $(PCH0) $(SRC)\shknam.c $(HACK_H) $(O)sounds.0: $(PCH0) $(SRC)\sounds.c $(HACK_H) $(O)steal.0: $(PCH0) $(SRC)\steal.c $(HACK_H) $(O)timeout.0: $(PCH0) $(SRC)\timeout.c $(HACK_H) $(LEV_H) $(O)track.0: $(PCH0) $(SRC)\track.c $(HACK_H) $(O)trap.0: $(PCH0) $(SRC)\trap.c $(HACK_H) $(O)vault.0: $(PCH0) $(SRC)\vault.c $(HACK_H) $(O)weapon.0: $(PCH0) $(SRC)\weapon.c $(HACK_H) $(O)were.0: $(PCH0) $(SRC)\were.c $(HACK_H) $(O)wizard.0: $(PCH0) $(SRC)\wizard.c $(HACK_H) $(QTEXT_H) $(O)zap.0: $(PCH0) $(SRC)\zap.c $(HACK_H) # # OVL1 # $(O)allmain.1: $(PCH1) $(SRC)\allmain.c $(HACK_H) $(O)apply.1: $(PCH1) $(SRC)\apply.c $(HACK_H) $(O)artifact.1: $(PCH1) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H) $(O)attrib.1: $(PCH1) $(SRC)\attrib.c $(HACK_H) $(O)botl.1: $(PCH1) $(SRC)\botl.c $(HACK_H) $(O)cmd.1: $(PCH1) $(SRC)\cmd.c $(HACK_H) $(FUNC_TAB_H) $(O)dbridge.1: $(PCH1) $(SRC)\dbridge.c $(HACK_H) $(O)do.1: $(PCH1) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_wear.1: $(PCH1) $(SRC)\do_wear.c $(HACK_H) $(O)dog.1: $(PCH1) $(SRC)\dog.c $(HACK_H) $(O)dungeon.1: $(PCH1) $(SRC)\dungeon.c $(HACK_H) $(ALIGN_H) $(DGN_FILE_H) $(DLB_H) $(O)eat.1: $(PCH1) $(SRC)\eat.c $(HACK_H) $(O)engrave.1: $(PCH1) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)explode.1: $(PCH1) $(SRC)\explode.c $(HACK_H) $(O)hack.1: $(PCH1) $(SRC)\hack.c $(HACK_H) $(O)hacklib.1: $(PCH1) $(SRC)\hacklib.c $(HACK_H) $(O)invent.1: $(PCH1) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)makemon.1: $(PCH1) $(SRC)\makemon.c $(HACK_H) $(O)mhitu.1: $(PCH1) $(SRC)\mhitu.c $(HACK_H) $(ARTIFACT_H) $(O)mkobj.1: $(PCH1) $(SRC)\mkobj.c $(HACK_H) $(ARTIFACT_H) $(PROP_H) $(O)mon.1: $(PCH1) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(O)mondata.1: $(PCH1) $(SRC)\mondata.c $(HACK_H) $(O)monmove.1: $(PCH1) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)mthrowu.1: $(PCH1) $(SRC)\mthrowu.c $(HACK_H) $(O)objnam.1: $(PCH1) $(SRC)\objnam.c $(HACK_H) $(O)polyself.1: $(PCH1) $(SRC)\polyself.c $(HACK_H) $(O)rnd.1: $(PCH1) $(SRC)\rnd.c $(HACK_H) $(O)shk.1: $(PCH1) $(SRC)\shk.c $(HACK_H) $(O)steal.1: $(PCH1) $(SRC)\steal.c $(HACK_H) $(O)timeout.1: $(PCH1) $(SRC)\timeout.c $(HACK_H) $(LEV_H) $(O)track.1: $(PCH1) $(SRC)\track.c $(HACK_H) $(O)trap.1: $(PCH1) $(SRC)\trap.c $(HACK_H) $(O)weapon.1: $(PCH1) $(SRC)\weapon.c $(HACK_H) $(O)zap.1: $(PCH1) $(SRC)\zap.c $(HACK_H) # # OVL2 # $(O)attrib.2: $(PCH2) $(SRC)\attrib.c $(HACK_H) $(O)do.2: $(PCH2) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_name.2: $(PCH2) $(SRC)\do_name.c $(HACK_H) $(O)do_wear.2: $(PCH2) $(SRC)\do_wear.c $(HACK_H) $(O)dog.2: $(PCH2) $(SRC)\dog.c $(HACK_H) $(O)engrave.2: $(PCH2) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)hack.2: $(PCH2) $(SRC)\hack.c $(HACK_H) $(O)hacklib.2: $(PCH2) $(SRC)\hacklib.c $(HACK_H) $(O)invent.2: $(PCH2) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)makemon.2: $(PCH2) $(SRC)\makemon.c $(HACK_H) $(O)mon.2: $(PCH2) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(O)mondata.2: $(PCH2) $(SRC)\mondata.c $(HACK_H) $(O)monmove.2: $(PCH2) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)shk.2: $(PCH2) $(SRC)\shk.c $(HACK_H) $(O)trap.2: $(PCH2) $(SRC)\trap.c $(HACK_H) $(O)zap.2: $(PCH2) $(SRC)\zap.c $(HACK_H) # # OVL3 # $(O)do.3: $(PCH3) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)hack.3: $(PCH3) $(SRC)\hack.c $(HACK_H) $(O)invent.3: $(PCH3) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)light.3: $(PCH3) $(SRC)\light.c $(HACK_H) $(O)shk.3: $(PCH3) $(SRC)\shk.c $(HACK_H) $(O)trap.3: $(PCH3) $(SRC)\trap.c $(HACK_H) $(O)zap.3: $(PCH3) $(SRC)\zap.c $(HACK_H) # # OVLB # $(O)allmain.B: $(PCHB) $(SRC)\allmain.c $(HACK_H) $(O)apply.B: $(PCHB) $(SRC)\apply.c $(HACK_H) $(O)artifact.B: $(PCHB) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H) $(O)attrib.B: $(PCHB) $(SRC)\attrib.c $(HACK_H) $(O)botl.B: $(PCHB) $(SRC)\botl.c $(HACK_H) $(O)cmd.B: $(PCHB) $(SRC)\cmd.c $(HACK_H) $(FUNC_TAB_H) $(O)dbridge.B: $(PCHB) $(SRC)\dbridge.c $(HACK_H) $(O)do.B: $(PCHB) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_name.B: $(PCHB) $(SRC)\do_name.c $(HACK_H) $(O)do_wear.B: $(PCHB) $(SRC)\do_wear.c $(HACK_H) $(O)dog.B: $(PCHB) $(SRC)\dog.c $(HACK_H) $(O)dogmove.B: $(PCHB) $(SRC)\dogmove.c $(HACK_H) $(MFNDPOS_H) $(O)eat.B: $(PCHB) $(SRC)\eat.c $(HACK_H) $(O)engrave.B: $(PCHB) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)hack.B: $(PCHB) $(SRC)\hack.c $(HACK_H) $(O)hacklib.B: $(PCHB) $(SRC)\hacklib.c $(HACK_H) $(O)invent.B: $(PCHB) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)lock.B: $(PCHB) $(SRC)\lock.c $(HACK_H) $(O)mail.B: $(PCHB) $(SRC)\mail.c $(HACK_H) $(MAIL_H) $(DATE_H) $(O)makemon.B: $(PCHB) $(SRC)\makemon.c $(HACK_H) $(O)mcastu.B: $(PCHB) $(SRC)\mcastu.c $(HACK_H) $(O)mhitm.B: $(PCHB) $(SRC)\mhitm.c $(HACK_H) $(ARTIFACT_H) $(O)mhitu.B: $(PCHB) $(SRC)\mhitu.c $(HACK_H) $(ARTIFACT_H) $(O)mkobj.B: $(PCHB) $(SRC)\mkobj.c $(HACK_H) $(ARTIFACT_H) $(PROP_H) $(O)mkroom.B: $(PCHB) $(SRC)\mkroom.c $(HACK_H) $(O)mon.B: $(PCHB) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(O)mondata.B: $(PCHB) $(SRC)\mondata.c $(HACK_H) $(O)monmove.B: $(PCHB) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)mthrowu.B: $(PCHB) $(SRC)\mthrowu.c $(HACK_H) $(O)objnam.B: $(PCHB) $(SRC)\objnam.c $(HACK_H) $(O)pline.B: $(SRC)\pline.c $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\pline.c $(O)polyself.B: $(PCHB) $(SRC)\polyself.c $(HACK_H) $(O)potion.B: $(PCHB) $(SRC)\potion.c $(HACK_H) $(O)priest.B: $(PCHB) $(SRC)\priest.c $(HACK_H) $(MFNDPOS_H) $(O)read.B: $(PCHB) $(SRC)\read.c $(HACK_H) $(O)rnd.B: $(PCHB) $(SRC)\rnd.c $(HACK_H) $(O)shk.B: $(PCHB) $(SRC)\shk.c $(HACK_H) $(O)shknam.B: $(PCHB) $(SRC)\shknam.c $(HACK_H) $(O)sounds.B: $(PCHB) $(SRC)\sounds.c $(HACK_H) $(O)steal.B: $(PCHB) $(SRC)\steal.c $(HACK_H) $(O)timeout.B: $(PCHB) $(SRC)\timeout.c $(HACK_H) $(LEV_H) $(O)track.B: $(PCHB) $(SRC)\track.c $(HACK_H) $(O)trap.B: $(PCHB) $(SRC)\trap.c $(HACK_H) $(O)vault.B: $(PCHB) $(SRC)\vault.c $(HACK_H) $(O)weapon.B: $(PCHB) $(SRC)\weapon.c $(HACK_H) $(O)were.B: $(PCHB) $(SRC)\were.c $(HACK_H) $(O)wizard.B: $(PCHB) $(SRC)\wizard.c $(HACK_H) $(QTEXT_H) $(O)zap.B: $(PCHB) $(SRC)\zap.c $(HACK_H) # end of file nethack-3.6.0/sys/msdos/Makefile.GCC0000664000076400007660000012532212536476415016155 0ustar paxedpaxed# NetHack 3.6 Makefile.GCC $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ # Copyright (c) NetHack PC Development Team 1996-2006. # PC NetHack 3.6 Makefile for djgpp V2 # # Gnu gcc compiler for msdos (djgpp) # Requires Gnu Make utility (V3.79.1 or greater) supplied with djgpp # # For questions or comments: devteam@nethack.org # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc # .l lex # # Note that flex (lex) and bison (yacc) are included with the # djgpp distribution and work quite well. This makefile assumes # you have them installed correctly. # Game Installation Variables # NOTE: Make sure GAMEDIR exists before make is started. GAME = nethack # The GNU Make has a problem if you include a drive spec below (unfortunately). GAMEDIR =../binary # # Directories, gcc likes unix style directory specs # OBJ = o DAT = ../dat DOC = ../doc INCL = ../include MSYS = ../sys/msdos SRC = ../src SSHR = ../sys/share UTIL = ../util WIN = ../win/tty WSHR = ../win/share # # Executables. CC = gcc LINK = gcc MAKEBIN = make # # Special libraries and how to link them in. LIBS = -lpc # If TERMLIB is defined in pcconf.h, comment out the upper line and # uncomment the lower. Note that you must build the termc library # and place it in djgpp's lib directory. See termcap.zip for details TERMLIB = #TERMLIB = -ltermc LIBRARIES = $(LIBS) $(TERMLIB) # # Yacc/Lex ... if you got 'em. # # If you have yacc/lex or a work-alike set YACC_LEX to Y # YACC_LEX = Y ifeq ($(YACC_LEX),Y) DO_YACC = YACC_ACT DO_LEX = LEX_ACT endif # If YACC_LEX is Y above, set the following to values appropriate for # your tools. # YACC = bison -y LEX = flex # # If your flex and bison port mess with the output names directly # you must set the file names to the appropriate output file names # here #YTABC = y_tab.c #YTABH = y_tab.h #LEXYYC = lexyy.c # # If your flex and bison are able to produce files named # y.tab.c, y.tab.h or lex.yy.c you might have to set these # to the short file name equivalent (DIR /X to reveal them): YTABC = ytab~1.c YTABH = ytab~1.h LEXYYC = lexyy~1.c # # Uncomment the line below if you want to store all the level files, # help files, etc. in a single library file. USE_DLB = Y # djgpp includes ls.exe and touch.exe in fil41b.zip from the v2gnu # folder so be sure to include that when downloading djgpp. Doing # so will make changing this unnecessary. LS = ls -1 # ls.exe from djgpp distribution #LS = dir /l/b # DOS command # To build a binary without any graphics # suitable for blind players, # set SUPPRESS_GRAPHICS to Y # (Note: binary will require ANSI.SYS driver or equivalent loaded) # SUPPRESS_GRAPHICS = Y SUPPRESS_GRAPHICS = # ZLIB Support # To support zlib compression in bones and save files, you must # define ZLIB_COMP in include/config.h. # You must also have a zlib library to link NetHack with, and # for the djgpp build, you need one compatible with djgpp. # At the time that this was written (post-NetHack 3.4.3) the # following URL was a valid place to get a pre-built djgpp library # to add to your djgpp tools directory tree. # http://www.delorie.com/pub/djgpp/current/v2tk/zlib114b.zip # # If you defined ZLIB_COMP in include/config.h to build in support # for ZLIB compression, you need to uncomment the line below. #ZLIB= -lz #=============================================== #======= End of Modification Section =========== #=============================================== ################################################ # # # Nothing below here should have to be changed.# # # ################################################ GAMEFILE = $(GAMEDIR)/$(GAME).exe # Changing this conditional block is not recommended ifeq ($(USE_DLB),Y) DLBFLG = -DDLB else DLBFLG = endif # # Flags. # ifeq ($(SUPPRESS_GRAPHICS),Y) TERMLIB = # Build NetHack suitable for blind players # Debugging #cflags = -pg -c -I../include $(DLBFLG) -DSUPPRESS_GRAPHICS #LFLAGS = -pg cflags = -c -O -I../include $(DLBFLG) -DSUPPRESS_GRAPHICS LFLAGS = else # Debugging #cflags = -pg -c -I../include $(DLBFLG) -DUSE_TILES #LFLAGS = -pg # Normal cflags = -c -O -I../include $(DLBFLG) -DUSE_TILES LFLAGS = endif #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .tib .til .uu .c .y .l #========================================== # Rules for files in src #========================================== $(OBJ)/%.o : /%.c $(CC) $(cflags) -o$@ $< $(OBJ)/%.o : $(SRC)/%.c $(CC) $(cflags) -o$@ $< #========================================== # Rules for files in sys/share #========================================== $(OBJ)/%.o : $(SSHR)/%.c $(CC) $(cflags) -o$@ $< #========================================== # Rules for files in sys/msdos #========================================== $(OBJ)/%.o : $(MSYS)/%.c $(CC) $(cflags) -I../sys/msdos -o$@ $< #========================================== # Rules for files in util #========================================== $(OBJ)/%.o : $(UTIL)/%.c $(CC) $(cflags) -o$@ $< #========================================== # Rules for files in win/share #========================================== $(OBJ)/%.o : $(WSHR)/%.c $(CC) $(cflags) -I../win/share -o$@ $< #{$(WSHR)}.txt{$(DAT)}.txt: # copy $< $@ #========================================== # Rules for files in win/tty #========================================== $(OBJ)/%.o : $(TTY)/%.c $(CC) $(cflags) -o$@ $< #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # # # Shorten up the location for some files # O = $(OBJ)/ U = $(UTIL)/ #========================================== # Utility Objects. #========================================== VGAOBJ = $(O)vidvga.o MAKESRC = makedefs.c SPLEVSRC = lev_yacc.c lev_$(LEX).c lev_main.c panic.c DGNCOMPSRC = dgn_yacc.c dgn_$(LEX).c dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o $(O)alloc.o \ $(O)monst.o $(O)objects.o $(O)panic.o \ $(O)drawing.o $(O)decl.o $(O)stubvid.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o $(O)alloc.o \ $(O)panic.o RECOVOBJS = $(O)recover.o #========================================== # Tile related object files. #========================================== ifeq ($(SUPPRESS_GRAPHICS),Y) TILOBJ = TEXTIO = TEXTIO2 = PLANAR_TIB = OVERVIEW_TIB = TILEUTIL = TILEFILES = TILEFILES2 = GIFREADERS = GIFREAD2 = PPMWRITERS = PPMWRIT2 = else TILOBJ = $(O)tile.o $(O)pctiles.o $(VGAOBJ) TEXTIO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o $(O)decl.o $(O)monst.o \ $(O)objects.o $(O)stubvid.o TEXTIO2 = $(O)tiletex2.o $(O)tiletxt2.o $(O)drawing.o $(O)decl.o $(O)monst.o \ $(O)objects.o $(O)stubvid.o PLANAR_TIB = $(DAT)/NetHack1.tib OVERVIEW_TIB = $(DAT)/NetHacko.tib TILEUTIL = $(TILOBJ) $(U)tile2bin.exe $(U)til2bin2.exe $(PLANAR_TIB) $(OVERVIEW_TIB) TILEFILES = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt TILEFILES2 = $(WSHR)/monthin.txt $(WSHR)/objthin.txt $(WSHR)/oththin.txt GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREAD2 = $(O)gifread2.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o PPMWRIT2 = $(O)ppmwrit2.o $(O)alloc.o $(O)panic.o endif DLBOBJ = $(O)dlb.o # Object files for the game itself. VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o $(O)attrib.o VOBJ02 = $(O)ball.o $(O)bones.o $(O)botl.o $(O)cmd.o $(O)dbridge.o VOBJ03 = $(O)decl.o $(O)detect.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ04 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o $(O)dothrow.o VOBJ05 = $(O)drawing.o $(O)dungeon.o $(O)eat.o $(O)end.o $(O)engrave.o VOBJ06 = $(O)exper.o $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o VOBJ07 = $(O)getline.o $(O)hack.o $(O)hacklib.o $(O)invent.o $(O)lock.o VOBJ08 = $(O)mail.o $(O)main.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o $(O)mhitm.o VOBJ09 = $(O)mhitu.o $(O)minion.o $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o VOBJ10 = $(O)mkobj.o $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o VOBJ11 = $(O)monst.o $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ12 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o $(O)options.o VOBJ13 = $(O)pickup.o $(O)pline.o $(O)polyself.o $(O)potion.o $(O)quest.o VOBJ14 = $(O)questpgr.o $(O)pager.o $(O)pray.o $(O)priest.o $(O)read.o VOBJ15 = $(O)rect.o $(O)restore.o $(O)rip.o $(O)rnd.o $(O)role.o VOBJ16 = $(O)rumors.o $(O)save.o $(O)shk.o $(O)shknam.o $(O)sit.o VOBJ17 = $(O)sounds.o $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ18 = $(O)termcap.o $(O)timeout.o $(O)topl.o $(O)topten.o $(O)track.o VOBJ19 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)vision.o VOBJ20 = $(O)vis_tab.o $(O)weapon.o $(O)were.o $(O)wield.o $(O)windows.o VOBJ21 = $(O)wintty.o $(O)wizard.o $(O)worm.o $(O)worn.o $(O)write.o VOBJ22 = $(O)zap.o $(O)light.o $(O)dlb.o $(O)dig.o $(O)teleport.o VOBJ23 = $(O)region.o $(O)sys.o SOBJ = $(O)msdos.o $(O)sound.o $(O)pcsys.o $(O)tty.o $(O)unix.o \ $(O)video.o $(O)vidtxt.o $(O)pckeys.o VVOBJ = $(O)version.o VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(VVOBJ) #========================================== # Header file macros #========================================== PATCHLEV_H = $(INCL)/patchlev.h DGN_FILE_H = $(INCL)/align.h $(INCL)/dgn_file.h DUNGEON_H = $(INCL)/align.h $(INCL)/dungeon.h MONDATA_H = $(INCL)/align.h $(INCL)/mondata.h MONST_H = $(INCL)/align.h $(INCL)/monst.h $(INCL)/mextra.h PERMONST_H = $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/align.h \ $(INCL)/permonst.h REGION_H = $(INCL)/region.h RM_H = $(INCL)/align.h $(INCL)/rm.h SKILLS_H = $(INCL)/skills.h SP_LEV_H = $(INCL)/align.h $(INCL)/sp_lev.h YOUPROP_H = $(PERMONST_H) $(MONDATA_H) $(INCL)/prop.h \ $(INCL)/pm.h $(INCL)/youprop.h YOU_H = $(MONST_H) $(YOUPROP_H) $(INCL)/align.h \ $(INCL)/attrib.h $(INCL)/you.h DISPLAY_H = $(MONDATA_H) $(INCL)/vision.h $(INCL)/display.h PCCONF_H = $(INCL)/micro.h $(INCL)/system.h $(INCL)/pcconf.h \ $(MSYS)/pcvideo.h CONFIG_H = $(GLOBAL_H) $(INCL)/tradstdc.h $(INCL)/config1.h \ $(INCL)/config.h DECL_H = $(YOU_H) $(INCL)/spell.h $(INCL)/color.h \ $(INCL)/obj.h $(INCL)/onames.h $(INCL)/pm.h \ $(INCL)/decl.h GLOBAL_H = $(PCCONF_H) $(INCL)/coord.h $(INCL)/global.h HACK_H = $(CONFIG_H) $(INCL)/context.h $(DUNGEON_H) \ $(DECL_H) $(DISPLAY_H) $(INCL)/monsym.h \ $(INCL)/mkroom.h $(INCL)/objclass.h $(INCL)/trap.h \ $(INCL)/flag.h $(RM_H) $(INCL)/vision.h \ $(INCL)/wintype.h $(INCL)/engrave.h $(INCL)/rect.h \ $(INCL)/trampoli.h $(INCL)/hack.h $(REGION_H) \ $(INCL)/sys.h DLB_H = $(INCL)/dlb.h ifeq ($(SUPPRESS_GRAPHICS),Y) TILE_H = else TILE_H = $(WSHR)/tile.h $(MSYS)/pctiles.h endif ifeq ($(USE_DLB),Y) DLB = dlb DLBOBJS = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o else DLB = DLBOBJS = endif ifdef DJGPP DJ1 = $(dir $(DJGPP)) CWSDPMI = $(subst /,\,$(DJ1))bin\CWSDPMI.* endif #========================================== # Primary Targets. #========================================== # The default target. all : install install: $(GAMEFILE) $(O)install.tag @echo Done. default: $(GAMEFILE) util: $(O)utility.tag $(O)utility.tag: $(INCL)/date.h $(INCL)/trap.h $(INCL)/onames.h \ $(INCL)/pm.h monstr.c vis_tab.c \ $(U)lev_comp.exe $(U)dgn_comp.exe $(TILEUTIL) $(subst /,\,echo utilities made > $@) tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. recover: $(U)recover.exe @$(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR)) @$(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)) $(O)install.tag: $(O)dat.tag $(GAMEFILE) ifeq ($(USE_DLB),Y) @$(subst /,\,copy $(DAT)/nhdat $(GAMEDIR)) @$(subst /,\,copy $(DAT)/license $(GAMEDIR)) else @$(subst /,\,copy $(DAT)/*. $(GAMEDIR)) @$(subst /,\,copy $(DAT)/*.dat $(GAMEDIR)) @$(subst /,\,copy $(DAT)/*.lev $(GAMEDIR)) @$(subst /,\,copy $(MSYS)/msdoshlp.txt $(GAMEDIR)) @$(subst /,\,if exist $(GAMEDIR)/makefile. del $(GAMEDIR)/makefile.) endif ifdef TERMLIB @$(subst /,\,copy $(SSHR)/termcap $(GAMEDIR)) endif @$(subst /,\,if exist $(DAT)/*.tib copy $(DAT)/*.tib $(GAMEDIR)) @$(subst /,\,if exist $(DAT)/symbols copy $(DAT)/symbols $(GAMEDIR)) @$(subst /,\,copy $(SSHR)/NetHack.cnf $(GAMEDIR)/defaults.nh) @$(subst /,\,copy $(MSYS)/NHAccess.nh $(GAMEDIR)) @$(subst /,\,copy $(DOC)/guidebo*.txt $(GAMEDIR)) @$(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR)) ifdef CWSDPMI @$(subst /,\,if exist $(CWSDPMI) copy $(CWSDPMI) $(GAMEDIR)) else @$(subst /,\,echo Could not find a copy of CWSDPMI.EXE to put into $(GAMEDIR)) endif @$(subst /,\,echo install done > $@) #========================================== # The main target. #========================================== $(GAMEFILE): $(O)obj.tag $(PATCHLEV_H) $(O)utility.tag $(ALLOBJ) $(O)$(GAME).lnk $(LINK) $(LFLAGS) -o$(GAME).exe @$(O)$(GAME).lnk $(LIBRARIES) $(ZLIB) @$(subst /,\,stubedit $(GAME).exe minstack=2048K) @$(subst /,\,copy $(GAME).exe $(GAMEFILE)) @$(subst /,\,del $(GAME).exe) $(O)$(GAME).lnk: $(ALLOBJ) echo $(VOBJ01) > $(subst /,\,$@) echo $(VOBJ02) >> $(subst /,\,$@) echo $(VOBJ03) >> $(subst /,\,$@) echo $(VOBJ04) >> $(subst /,\,$@) echo $(VOBJ05) >> $(subst /,\,$@) echo $(VOBJ06) >> $(subst /,\,$@) echo $(VOBJ07) >> $(subst /,\,$@) echo $(VOBJ08) >> $(subst /,\,$@) echo $(VOBJ09) >> $(subst /,\,$@) echo $(VOBJ10) >> $(subst /,\,$@) echo $(VOBJ11) >> $(subst /,\,$@) echo $(VOBJ12) >> $(subst /,\,$@) echo $(VOBJ13) >> $(subst /,\,$@) echo $(VOBJ14) >> $(subst /,\,$@) echo $(VOBJ15) >> $(subst /,\,$@) echo $(VOBJ16) >> $(subst /,\,$@) echo $(VOBJ17) >> $(subst /,\,$@) echo $(VOBJ18) >> $(subst /,\,$@) echo $(VOBJ19) >> $(subst /,\,$@) echo $(VOBJ20) >> $(subst /,\,$@) echo $(VOBJ21) >> $(subst /,\,$@) echo $(VOBJ22) >> $(subst /,\,$@) echo $(VOBJ23) >> $(subst /,\,$@) echo $(SOBJ) >> $(subst /,\,$@) echo $(TILOBJ) >> $(subst /,\,$@) echo $(VVOBJ) >> $(subst /,\,$@) #========================================== # Housekeeping. #========================================== clean: $(subst /,\,if exist $(O)*.o del $(O)*.o) $(subst /,\,if exist $(O)dat.tag del $(O)dat.tag) $(subst /,\,if exist $(O)install.tag del $(O)install.tag) $(subst /,\,if exist $(O)$(GAME).lnk del $(O)$(GAME).lnk) $(subst /,\,if exist $(O)obj.tag del $(O)obj.tag) $(subst /,\,if exist $(O)sp_lev.tag del $(O)sp_lev.tag) $(subst /,\,if exist $(O)thintile.tag del $(O)thintile.tag) $(subst /,\,if exist $(O)utility.tag del $(O)utility.tag) spotless: clean $(subst /,\,if exist $(U)lev_flex.c del $(U)lev_flex.c) $(subst /,\,if exist $(U)lev_lex.c del $(U)lev_lex.c) $(subst /,\,if exist $(U)lev_yacc.c del $(U)lev_yacc.c) $(subst /,\,if exist $(U)dgn_flex.c del $(U)dgn_flex.c) $(subst /,\,if exist $(U)dgn_lex.c del $(U)dgn_lex.c) $(subst /,\,if exist $(U)dgn_yacc.c del $(U)lev_yacc.c) $(subst /,\,if exist $(U)makedefs.exe del $(U)makedefs.exe) $(subst /,\,if exist $(U)lev_comp.exe del $(U)lev_comp.exe) $(subst /,\,if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe) $(subst /,\,if exist $(U)recover.exe del $(U)recover.exe) $(subst /,\,if exist $(U)tilemap.exe del $(U)tilemap.exe) $(subst /,\,if exist $(U)tile2bin.exe del $(U)tile2bin.exe) $(subst /,\,if exist $(U)til2bin2.exe del $(U)til2bin2.exe) $(subst /,\,if exist $(U)thintile.exe del $(U)thintile.exe) $(subst /,\,if exist $(U)dlb_main.exe del $(U)dlb_main.exe) $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h) $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h) $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h) $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h) $(subst /,\,if exist $(INCL)/dgn_comp.h del $(INCL)/dgn_comp.h) $(subst /,\,if exist $(INCL)/lev_comp.h del $(INCL)/lev_comp.h) $(subst /,\,if exist $(SRC)/monstr.c del $(SRC)/monstr.c) $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c) $(subst /,\,if exist $(DAT)/options del $(DAT)/options) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors) $(subst /,\,if exist $(DAT)/dungeon.pdf del $(DAT)/dungeon.pdf) $(subst /,\,if exist $(DAT)/dungeon del $(DAT)/dungeon) $(subst /,\,if exist $(DAT)/oracles del $(DAT)/oracles) $(subst /,\,if exist $(DAT)/quest.dat del $(DAT)/quest.dat) $(subst /,\,if exist $(DAT)/dlb.lst del $(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/nhdat del $(DAT)/nhdat) $(subst /,\,if exist $(DAT)/*.lev del $(DAT)/*.lev) $(subst /,\,if exist $(PLANAR_TIB) del $(PLANAR_TIB)) $(subst /,\,if exist $(OVERVIEW_TIB) del $(OVERVIEW_TIB)) $(subst /,\,if exist $(WSHR)/monthin.txt del $(WSHR)/monthin.txt) $(subst /,\,if exist $(WSHR)/objthin.txt del $(WSHR)/objthin.txt) $(subst /,\,if exist $(WSHR)/oththin.txt del $(WSHR)/oththin.txt) #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: -$(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ)) @$(subst /,\,@echo directory created > $@) #=========================================== # Work around some djgpp long file name woes #=========================================== $(PATCHLEV_H): @$(subst /,\,if not exist $@ copy $(INCL)/patchlevel.h $(INCL)/patchlev.h) #========================================== #=========== SECONDARY TARGETS ============ #========================================== # # The following include files depend on makedefs to be created. # # date.h should be remade every time any of the source or include # files is modified. $(INCL)/date.h : $(U)makedefs.exe -$(subst /,\,$(U)makedefs -v) $(INCL)/onames.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -o) $(INCL)/pm.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -p) monstr.c: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -m) $(INCL)/vis_tab.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -z) vis_tab.c: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -z) #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) $(LINK) $(LFLAGS) -o$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(PERMONST_H) $(INCL)/objclass.h \ $(INCL)/monsym.h $(INCL)/qtext.h $(U)makedefs.c #========================================== # Level Compiler Dependencies #========================================== $(U)lev_comp.exe: $(SPLEVOBJS) $(LINK) $(LFLAGS) -o$@ $(SPLEVOBJS) ifeq ($(YACC_LEX),Y) $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(U)lev_yacc.c $(CC) $(cflags) -o$@ $(U)lev_yacc.c else $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c $(CC) $(cflags) -o$@ $(U)lev_yacc.c endif $(O)lev_$(LEX).o: $(HACK_H) $(SP_LEV_H) $(INCL)/lev_comp.h \ $(U)lev_$(LEX).c $(CC) $(cflags) -o$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(HACK_H) $(INCL)/sp_lev.h $(INCL)/date.h $(U)lev_main.c ifeq "$(DO_YACC)" "YACC_ACT" $(INCL)/lev_comp.h: $(U)lev_yacc.c $(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(YACC) -d lev_comp.y) @$(subst /,\,copy $(YTABC) lev_yacc.c) @$(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h) @$(subst /,\,@del $(YTABC)) @$(subst /,\,@del $(YTABH)) @$(subst /,\,chdir $(SRC)) else $(U)lev_yacc.c: $(SSHR)/lev_yacc.c @echo --- @echo For now, we will copy the prebuilt @echo lev_comp.c from $(SSHR) into $(U) and use that. @$(subst /,\,copy $(SSHR)/lev_yacc.c $(U)lev_yacc.c) @$(subst /,\,echo.>>$(U)lev_yacc.c) $(INCL)/lev_comp.h : $(SSHR)/lev_comp.h @echo --- @echo For now, we will copy the prebuilt lev_comp.h @echo from $(SSHR) into $(INCL) and use that. @$(subst /,\,copy $(SSHR)/lev_comp.h $(INCL)/lev_comp.h) @$(subst /,\,echo.>>$(INCL)/lev_comp.h) endif $(U)lev_$(LEX).c: $(U)lev_comp.l ifeq "$(DO_LEX)" "LEX_ACT" @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(LEX) $(FLEXSKEL) lev_comp.l) @$(subst /,\,if exist $@ del $@) @$(subst /,\,copy $(LEXYYC) $@) @$(subst /,\,del $(LEXYYC)) @$(subst /,\,chdir $(SRC)) else @echo --- @echo For now, we will copy the prebuilt lev_lex.c @echo from $(SSHR) into $(U) and use it. @$(subst /,\,copy $(SSHR)/lev_lex.c $@) @$(subst /,\,echo.>>$@) endif #========================================== # Dungeon Dependencies #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) $(LINK) $(LFLAGS) -o$@ $(DGNCOMPOBJS) ifeq "$(DO_YACC)" "YACC_ACT" $(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(YACC) -d dgn_comp.y) @$(subst /,\,copy $(YTABC) dgn_yacc.c) @$(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h) @$(subst /,\,@del $(YTABC)) @$(subst /,\,@del $(YTABH)) @$(subst /,\,chdir $(SRC)) else $(U)dgn_yacc.c: $(SSHR)/dgn_yacc.c @echo --- @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSHR) into $(U) and use that. @$(subst /,\,copy $(SSHR)/dgn_yacc.c $(U)dgn_yacc.c) @$(subst /,\,echo.>>$(U)dgn_yacc.c) $(INCL)/dgn_comp.h: $(SSHR)/dgn_comp.h @echo --- @echo For now, we will copy the prebuilt dgn_comp.h @echo from $(SSHR) into $(INCL) and use that. @$(subst /,\,copy $(SSHR)/dgn_comp.h $(INCL)/dgn_comp.h) @$(subst /,\,echo.>>$(INCL)/dgn_comp.h) endif ifeq "$(DO_LEX)" "LEX_ACT" $(U)dgn_$(LEX).c: $(U)dgn_comp.l $(INCL)/dgn_comp.h @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(LEX) $(FLEXSKEL) dgn_comp.l) @$(subst /,\,if exist $@ del $@) @$(subst /,\,copy $(LEXYYC) $@) @$(subst /,\,del $(LEXYYC)) @$(subst /,\,chdir $(SRC)) else $(U)dgn_$(LEX).c: $(SSHR)/dgn_lex.c $(INCL)/dgn_comp.h @echo --- @echo For now, we will copy the prebuilt dgn_lex.c @echo from $(SSHR) into $(U) and use it. @$(subst /,\,copy $(SSHR)/dgn_lex.c $@) @$(subst /,\,echo.>>$@) endif #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) $(LINK) $(LFLAGS) -o$@ $(O)recover.o $(O)recover.o: $(CONFIG_H) $(U)recover.c $(CC) $(cflags) -o$@ $(U)recover.c #========================================== # Header file moves required for tile support #========================================== ifeq ($(SUPPRESS_GRAPHICS),Y) else # # Tile Mapping # $(SRC)/tile.c: $(U)tilemap.exe @$(subst /,\,$(U)tilemap.exe) @echo A new $@ has been created $(U)tilemap.exe: $(O)tilemap.o $(LINK) $(LFLAGS) -o$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H) $(TILE_H) $(CC) $(cflags) -I$(WSHR) -I$(MSYS) -o$@ $(WSHR)/tilemap.c #========================================== # Tile Utilities # Required for tile support #========================================== $(DAT)/NetHack1.tib: $(TILEFILES) $(U)tile2bin.exe @echo Creating binary tile files (this may take some time) @$(subst /,\,chdir $(DAT)) @$(subst /,\,$(U)tile2bin.exe) @$(subst /,\,chdir $(SRC)) $(DAT)/NetHacko.tib: $(O)thintile.tag $(TILEFILES2) $(U)til2bin2.exe @echo Creating overview binary tile files (this may take some time) @$(subst /,\,chdir $(DAT)) @$(subst /,\,$(U)til2bin2.exe) @$(subst /,\,chdir $(SRC)) $(U)tile2bin.exe: $(O)tile2bin.o $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(O)tile2bin.o $(TEXTIO) $(U)til2bin2.exe: $(O)til2bin2.o $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(O)til2bin2.o $(TEXTIO2) $(U)thintile.exe: $(O)thintile.o $(LINK) $(LFLAGS) -o$@ $(O)thintile.o $(O)thintile.o: $(HACK_H) $(WSHR)/tile.h $(WSHR)/thintile.c $(CC) $(cflags) -o$@ $(WSHR)/thintile.c $(O)thintile.tag: $(U)thintile.exe $(TILEFILES) @$(subst /,\,$(U)thintile.exe) @$(subst /,\,echo thintiles created >$@) $(O)tile2bin.o: $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/tile2bin.c $(O)til2bin2.o: $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -DOVERVIEW_FILE -o$@ $(MSYS)/tile2bin.c $(O)tiletext.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c $(O)tiletex2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -o$@ $(WSHR)/tiletext.c $(O)tiletxt.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -o$@ $(WSHR)/tilemap.c $(O)tiletxt2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -DTILE_X=8 -o$@ $(WSHR)/tilemap.c # # Optional GIF Utilities (for development) # $(U)gif2txt.exe: $(GIFREADERS) $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(GIFREADERS) $(TEXTIO) $(U)gif2txt2.exe: $(GIFREAD2) $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(GIFREAD2) $(TEXTIO2) $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(PPMWRITERS) $(TEXTIO) $(U)txt2ppm2.exe: $(PPMWRIT2) $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(PPMWRIT2) $(TEXTIO2) $(O)gifread.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c $(O)gifread2.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c $(CC) $(cflags) -DTILE_X=8 -o$@ $(WSHR)/gifread.c ppmwrite.c: $(WSHR)/ppmwrite.c @$(subst /,\,copy $(WSHR)/ppmwrite.c .) $(O)ppmwrite.o: $(CONFIG_H) $(WSHR)/tile.h $(O)ppmwrit2.o: $(CONFIG_H) $(WSHR)/tile.h ppmwrite.c $(CC) $(cflags) -DTILE_X=8 -o$@ ppmwrite.c # # Optional tile viewer (development sources only) # $(U)viewtib.exe: $(O)viewtib.o $(LINK) $(LFLAGS) -o$@ $(O)viewtib.o $(LIBRARIES) $(O)viewtib.o: $(MSYS)/viewtib.c endif #========================================== # Other Util Dependencies. #========================================== $(O)alloc.o: $(CONFIG_H) alloc.c $(CC) $(cflags) -o$@ alloc.c $(O)drawing.o: $(CONFIG_H) drawing.c $(MSYS)/pcvideo.h $(CC) $(cflags) -I$(MSYS) -o$@ drawing.c $(O)decl.o: $(CONFIG_H) decl.c $(CC) $(cflags) -o$@ decl.c $(O)monst.o: $(CONFIG_H) $(PERMONST_H) $(INCL)/monsym.h \ $(INCL)/color.h monst.c $(CC) $(cflags) -o$@ monst.c $(O)objects.o: $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ $(INCL)/prop.h $(INCL)/color.h objects.c $(CC) $(cflags) -o$@ objects.c $(O)panic.o: $(CONFIG_H) $(U)panic.c #============================================================ # make data.base an 8.3 filename to prevent an make warning #============================================================ DATABASE = $(DAT)/data.bas $(O)dat.tag: $(DAT)/nhdat @$(subst /,\,echo dat done >$@) $(DAT)/data: $(O)utility.tag $(DATABASE) @$(subst /,\,$(U)makedefs.exe -d) $(DAT)/rumors: $(O)utility.tag $(DAT)/rumors.tru $(DAT)/rumors.fal @$(subst /,\,$(U)makedefs.exe -r) $(DAT)/quest.dat: $(O)utility.tag $(DAT)/quest.txt @$(subst /,\,$(U)makedefs.exe -q) $(DAT)/oracles: $(O)utility.tag $(DAT)/oracles.txt @$(subst /,\,$(U)makedefs.exe -h) $(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des $(DAT)/castle.des \ $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des \ $(DAT)/medusa.des $(DAT)/oracle.des $(DAT)/tower.des \ $(DAT)/yendor.des $(DAT)/arch.des $(DAT)/barb.des \ $(DAT)/caveman.des $(DAT)/healer.des $(DAT)/knight.des \ $(DAT)/monk.des $(DAT)/priest.des $(DAT)/ranger.des \ $(DAT)/rogue.des $(DAT)/samurai.des $(DAT)/tourist.des \ $(DAT)/valkyrie.des $(DAT)/wizard.des @$(subst /,\,cd $(DAT)) @$(subst /,\,$(U)lev_comp bigroom.des) @$(subst /,\,$(U)lev_comp castle.des) @$(subst /,\,$(U)lev_comp endgame.des) @$(subst /,\,$(U)lev_comp gehennom.des) @$(subst /,\,$(U)lev_comp knox.des) @$(subst /,\,$(U)lev_comp mines.des) @$(subst /,\,$(U)lev_comp medusa.des) @$(subst /,\,$(U)lev_comp oracle.des) @$(subst /,\,$(U)lev_comp sokoban.des) @$(subst /,\,$(U)lev_comp tower.des) @$(subst /,\,$(U)lev_comp yendor.des) @$(subst /,\,$(U)lev_comp arch.des) @$(subst /,\,$(U)lev_comp barb.des) @$(subst /,\,$(U)lev_comp caveman.des) @$(subst /,\,$(U)lev_comp healer.des) @$(subst /,\,$(U)lev_comp knight.des) @$(subst /,\,$(U)lev_comp monk.des) @$(subst /,\,$(U)lev_comp priest.des) @$(subst /,\,$(U)lev_comp ranger.des) @$(subst /,\,$(U)lev_comp rogue.des) @$(subst /,\,$(U)lev_comp samurai.des) @$(subst /,\,$(U)lev_comp tourist.des) @$(subst /,\,$(U)lev_comp valkyrie.des) @$(subst /,\,$(U)lev_comp wizard.des) @$(subst /,\,cd $(SRC)) @$(subst /,\,echo sp_levs done > $@) $(DAT)/dungeon: $(O)utility.tag $(DAT)/dungeon.def @$(subst /,\,$(U)makedefs.exe -e) @$(subst /,\,cd $(DAT)) @$(subst /,\,$(U)dgn_comp.exe dungeon.pdf) @$(subst /,\,cd $(SRC)) #========================================== # DLB stuff #========================================== #note that dir below assumes bin/dir.exe from djgpp distribution # $(DAT)/nhdat: $(U)dlb_main.exe $(DAT)/data $(DAT)/rumors $(DAT)/dungeon \ $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag @$(subst /,\,echo dat done >$(O)dat.tag) @$(subst /,\,cd $(DAT)) @$(subst /,\,copy $(MSYS)/msdoshlp.txt .) @$(subst /,\,echo data >dlb.lst) @$(subst /,\,echo dungeon >>dlb.lst) @$(subst /,\,echo oracles >>dlb.lst) @$(subst /,\,echo options >>dlb.lst) @$(subst /,\,echo quest.dat >>dlb.lst) @$(subst /,\,echo rumors >>dlb.lst) @$(subst /,\,echo help >>dlb.lst) @$(subst /,\,echo hh >>dlb.lst) @$(subst /,\,echo cmdhelp >>dlb.lst) @$(subst /,\,echo history >>dlb.lst) @$(subst /,\,echo opthelp >>dlb.lst) @$(subst /,\,echo wizhelp >>dlb.lst) @$(subst /,\,echo license >>dlb.lst) @$(subst /,\,echo msdoshlp.txt >>dlb.lst) $(LS) $(subst /,\,*.lev) >>dlb.lst @$(subst /,\,$(U)dlb_main cvIf dlb.lst nhdat) @$(subst /,\,cd $(SRC)) $(U)dlb_main.exe: $(DLBOBJS) $(LINK) $(LFLAGS) -o$@ $(DLBOBJS) $(O)dlb_main.o: $(U)dlb_main.c $(INCL)/config.h $(DLB_H) $(CC) $(cflags) -o$@ $(U)dlb_main.c #========================================== # Game Dependencies #========================================== # sys/share $(O)main.o: $(HACK_H) $(DLB_H) $(SSHR)/pcmain.c $(CC) $(cflags) -o$@ $(SSHR)/pcmain.c $(O)tty.o: $(HACK_H) $(INCL)/wintty.h $(SSHR)/pctty.c $(CC) $(cflags) -o$@ $(SSHR)/pctty.c $(O)unix.o: $(HACK_H) $(SSHR)/pcunix.c $(CC) $(cflags) -o$@ $(SSHR)/pcunix.c $(O)pcsys.o : $(HACK_H) $(SSHR)/pcsys.c $(CC) $(cflags) -o$@ $(SSHR)/pcsys.c # sys/msdos $(O)msdos.o : $(HACK_H) $(MSYS)/msdos.c # $(CC) $(cflags) -o$@ $(MSYS)/msdos.c $(O)pckeys.o : $(HACK_H) $(MSYS)/pckeys.c # $(CC) $(cflags) -o$@ $(MSYS)/pckeys.c $(O)pctiles.o : $(HACK_H) $(MSYS)/pctiles.c $(MSYS)/portio.h $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/pctiles.c $(O)sound.o : $(HACK_H) $(MSYS)/sound.c $(MSYS)/portio.h # $(CC) $(cflags) -o$@ $(MSYS)/sound.c $(O)video.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(MSYS)/video.c # $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/video.c $(O)vidvga.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidvga.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/vidvga.c $(O)vidtxt.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidtxt.c # $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/vidtxt.c $(O)stubvid.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/video.c $(CC) $(cflags) -I$(MSYS) -DSTUBVIDEO -o$@ $(MSYS)/video.c # src dependencies # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # o -c (which is included in cflags) substituted with -o$@ , # o an explicit build instruction for dlb.o because it requires # a .h file in ../sys/msdos. # o the PATCHLEV_H macro is substitued for $(INCL)/patchlevel.h # to work around a long filename issue. # o $(CFLAGS) changed to $(cflags) # Other than that, these dependencies are untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../sys/atari/tos.c $(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \ #$(INCL)/win32api.h $(CC) $(cflags) -o$@ ../sys/share/pcmain.c $(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pcsys.c $(O)pctty.o: ../sys/share/pctty.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pctty.c $(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pcunix.c $(O)random.o: ../sys/share/random.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/random.c $(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../sys/share/ioctl.c $(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/unixtty.c $(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h $(CC) $(cflags) -o$@ ../sys/unix/unixmain.c $(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/unix/unixunix.c $(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H) $(CC) $(cflags) -o$@ ../sys/unix/unixres.c $(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h $(CC) $(cflags) -o$@ ../sys/be/bemain.c $(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h $(CC) $(cflags) -o$@ ../win/tty/getline.c $(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../win/tty/termcap.c $(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../win/tty/topl.c $(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \ $(INCL)/date.h $(PATCHLEV_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../win/tty/wintty.c $(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \ $(CONFIG_H) $(CC) $(cflags) -o$@ ../win/X11/Window.c $(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) $(CC) $(cflags) -o$@ ../win/X11/dialogs.c $(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \ $(PATCHLEV_H) ../win/X11/nh72icon \ ../win/X11/nh56icon ../win/X11/nh32icon $(CC) $(cflags) -o$@ ../win/X11/winX.c $(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \ $(INCL)/winX.h $(INCL)/tile2x11.h $(CC) $(cflags) -o$@ ../win/X11/winmap.c $(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winmenu.c $(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winmesg.c $(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winmisc.c $(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winstat.c $(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h $(CC) $(cflags) -o$@ ../win/X11/wintext.c $(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winval.c $(O)tile.o: tile.c $(HACK_H) $(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ ../win/gnome/gnmain.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c $(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c $(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c $(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ $(INCL)/date.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c $(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h $(HACK_H) $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c $(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ ../win/gnome/gnbind.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c $(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c $(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c $(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ ../win/gnome/gnmain.h $(HACK_H) $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c $(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ ../win/gnome/gnmain.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c $(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ ../win/gnome/gnomeprv.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c $(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ ../win/gnome/gn_rip.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gntext.c $(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c $(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c $(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \ $(PATCHLEV_H) $(INCL)/wingem.h $(CC) $(cflags) -o$@ ../win/gem/wingem.c $(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \ $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h $(CC) $(cflags) -o$@ ../win/gem/wingem1.c $(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h $(CC) $(cflags) -o$@ ../win/gem/load_img.c $(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h $(CC) $(cflags) -o$@ ../win/gem/gr_rect.c $(O)tile.o: tile.c $(HACK_H) $(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/dlb.h $(PATCHLEV_H) $(INCL)/tile2x11.h \ $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \ $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp $(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp $(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp $(O)monstr.o: monstr.c $(CONFIG_H) $(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h $(O)dig.o: dig.c $(HACK_H) $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h $(CC) $(cflags) -I../sys/msdos -o$@ dlb.c $(O)do.o: do.c $(HACK_H) $(INCL)/lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(O)dokick.o: dokick.c $(HACK_H) $(O)dothrow.o: dothrow.c $(HACK_H) $(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(O)light.o: light.c $(HACK_H) $(INCL)/lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h $(O)makemon.o: makemon.c $(HACK_H) $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(O)minion.o: minion.c $(HACK_H) $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(O)mondata.o: mondata.c $(HACK_H) $(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \ $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \ $(INCL)/color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \ $(HACK_H) $(INCL)/tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)/lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)/lev.h $(O)shk.o: shk.c $(HACK_H) $(O)shknam.o: shknam.c $(HACK_H) $(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)sys.o: sys.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(PATCHLEV_H) $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(PATCHLEV_H) $(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.6.0/sys/msdos/Makefile.MSC0000664000076400007660000010366612536476415016212 0ustar paxedpaxed# NetHack 3.6 Makefile.MSC $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.21 $ # Copyright (c) NetHack PC Development Team 1997 - 2012. # PC NetHack 3.4x Makefile for MSC V1.52c (16 bit compiler) # # For questions or comments: nethack-bugs@nethack.org # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc # .l lex # # # Game Installation Variables # NOTE: Make sure GAMEDIR exists before make is started. GAME = nethack GAMEDIR =..\binary # # Directories # DAT = ..\dat DOC = ..\doc INCL = ..\include MSYS = ..\sys\msdos SRC = ..\src SSHR = ..\sys\share UTIL = ..\util WIN = ..\win\tty WSHR = ..\win\share # # Executables. CC = cl LINK = link MAKEBIN = nmake # if you have a uudecode program, add its name here # otherwise leave blank UUDECODE = # # Yacc/Lex ... if you got 'em. # # If you have yacc/lex or a work-alike set YACC_LEX to Y # YACC_LEX = N # If YACC_LEX is Y above, set the following to values appropriate for # your tools. # YACC = bison -y LEX = flex YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c # # Uncomment this line if you want to include support for ALT-numeric # sequences, such as ALT-2 for toggling #twoweapon mode. # Note that this code did not get a thorough testing prior to 3.4.x #NEWALT=/DNEW_ALT # # Uncomment this line if your shell doesn't support FOR bat syntax (DOSBOX). NO_FOR=Y ############################################################################# # # nothing below this line should have to be changed # LNKOPT = SCHEMA35.DEF # # Controls whether MOVE tracing is enabled in the executable # This should be left commented unless you are tinkering with the # overlay structure of NetHack. The executable runs _very_ # slowly when the movetr.lib is linked in. # #MOVETR= movetr.lib # do not change this ! IF ("$(MOVETR)"!="") MVTRCL = /DMOVE_PROF ! ELSE MVTRCL = ! ENDIF # # Uncomment the line below if you want to store all the level files, # help files, etc. in a single library file. USE_DLB = Y ! IF ("$(USE_DLB)"=="Y") DLBFLG = -DDLB ! ELSE DLBFLG = ! ENDIF LIBRARIES = $(LIBS) $(TERMLIB) GAMEFILE = $(GAMEDIR)\$(GAME).exe # # Flags. # # Debugging #CFLAGS = /Zi /DFUNCTION_LEVEL_LINKING /DUSE_TILES /DDLB #LFLAGS = /CODEVIEW /NOI/MAP /CPARM:1 /INFO # Normal LFLAGS = /NOI/MAP /CPARM:1 /INFO CFLAGS = /DFUNCTION_LEVEL_LINKING /DUSE_TILES /DDLB SPECOPTS = # # Leaving MACHINE_CODE undefined will allow it to run # on any Intel 8088 machines and above. # Set to 1 for 80186 and above only # Set to 2 for 80286 and above only # Set to 3 for 80386 and above only # MACHINE_CODE = # # Utility Objects. # # # Shorten up the location for some files # O = $(OBJ)\ # comment so \ isn't last char U = $(UTIL)\ # comment so \ isn't last char SPLEVDES = $(DAT)\Arch.des $(DAT)\Barb.des $(DAT)\bigroom.des \ $(DAT)\castle.des $(DAT)\Caveman.des $(DAT)\endgame.des \ $(DAT)\gehennom.des $(DAT)\Healer.des $(DAT)\Knight.des \ $(DAT)\knox.des $(DAT)\Monk.des $(DAT)\medusa.des \ $(DAT)\mines.des $(DAT)\oracle.des $(DAT)\Priest.des \ $(DAT)\Ranger.des $(DAT)\Rogue.des $(DAT)\Samurai.des \ $(DAT)\Tourist.des $(DAT)\tower.des $(DAT)\Valkyrie.des \ $(DAT)\Wizard.des $(DAT)\yendor.des VGAOBJ = vidvga.o MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c \ $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = makedefs.o monst.o objects.o SPLEVOBJS = lev_yacc.o lev_$(LEX).o lev_main.o alloc.o \ monst.o objects.o panic.o \ drawing.o decl.o stubvid.o DGNCOMPOBJS = dgn_yacc.o dgn_$(LEX).o dgn_main.o alloc.o \ panic.o RECOVOBJS = recover.o # Tile related object files. TILOBJ = tile.o pctiles.o $(VGAOBJ) TEXTIO = tiletext.o tiletxt.o drawing.o decl.o monst.o objects.o stubvid.o TEXTIO2 = tiletex2.o tiletxt2.o drawing.o decl.o monst.o objects.o stubvid.o PLANAR_TIB = NetHack1.tib OVERVIEW_TIB = NetHacko.tib TILEUTIL = $(TILOBJ) tile2bin.exe til2bin2.exe $(PLANAR_TIB) $(OVERVIEW_TIB) TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt TILEFILES2 = $(WSHR)\monthin.txt $(WSHR)\objthin.txt $(WSHR)\oththin.txt GIFREADERS = gifread.o alloc.o panic.o GIFREAD2 = gifread2.o alloc.o panic.o PPMWRITERS = ppmwrite.o alloc.o panic.o PPMWRIT2 = ppmwrit2.o alloc.o panic.o DLBOBJS = dlb_main.o dlb.o alloc.o panic.o # Object files for the game itself. VOBJ01 = allmain.o alloc.o apply.o artifact.o attrib.o VOBJ02 = ball.o bones.o botl.o cmd.o dbridge.o VOBJ03 = decl.o detect.o display.o do.o do_name.o VOBJ04 = do_wear.o dog.o dogmove.o dokick.o dothrow.o VOBJ05 = drawing.o dungeon.o eat.o end.o engrave.o VOBJ06 = exper.o explode.o extralev.o files.o fountain.o VOBJ07 = getline.o hack.o hacklib.o invent.o lock.o VOBJ08 = mail.o main.o makemon.o mapglyph.o mcastu.o mhitm.o VOBJ09 = mhitu.o minion.o mkmap.o mklev.o mkmaze.o VOBJ10 = mkobj.o mkroom.o mon.o mondata.o monmove.o VOBJ11 = monst.o monstr.o mplayer.o mthrowu.o muse.o VOBJ12 = music.o o_init.o objects.o objnam.o options.o VOBJ13 = pickup.o pline.o polyself.o potion.o quest.o VOBJ14 = questpgr.o pager.o pray.o priest.o read.o VOBJ15 = rect.o restore.o rip.o rnd.o role.o VOBJ16 = rumors.o save.o shk.o shknam.o sit.o VOBJ17 = sounds.o sp_lev.o spell.o steal.o steed.o VOBJ18 = termcap.o timeout.o topl.o topten.o track.o VOBJ19 = trap.o u_init.o uhitm.o vault.o vision.o VOBJ20 = vis_tab.o weapon.o were.o wield.o windows.o VOBJ21 = wintty.o wizard.o worm.o worn.o write.o VOBJ22 = zap.o light.o dlb.o dig.o teleport.o VOBJ23 = random.o region.o sys.o SOBJ = msdos.o sound.o pcsys.o tty.o unix.o video.o \ vidtxt.o pckeys.o VVOBJ = version.o VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(VVOBJ) # # Header Objects. # DGN_FILE_H = $(INCL)\align.h $(INCL)\dgn_file.h DUNGEON_H = $(INCL)\align.h $(INCL)\dungeon.h MONDATA_H = $(INCL)\align.h $(INCL)\mondata.h MONST_H = $(INCL)\mextra.h $(INCL)\align.h $(INCL)\monst.h PERMONST_H = $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\align.h \ $(INCL)\permonst.h RM_H = $(INCL)\align.h $(INCL)\rm.h SP_LEV_H = $(INCL)\align.h $(INCL)\sp_lev.h YOUPROP_H = $(PERMONST_H) $(MONDATA_H) $(INCL)\prop.h \ $(INCL)\pm.h $(INCL)\youprop.h YOU_H = $(MONST_H) $(YOUPROP_H) $(INCL)\align.h \ $(INCL)\attrib.h $(INCL)\you.h DISPLAY_H = $(MONDATA_H) $(INCL)\vision.h $(INCL)\display.h PCCONF_H = $(INCL)\micro.h $(INCL)\system.h $(INCL)\pcconf.h \ $(MSYS)\pcvideo.h CONFIG_H = $(GLOBAL_H) $(INCL)\tradstdc.h $(INCL)\config1.h \ $(INCL)\config.h DECL_H = $(YOU_H) $(INCL)\spell.h $(INCL)\color.h \ $(INCL)\obj.h $(INCL)\onames.h $(INCL)\pm.h \ $(INCL)\decl.h GLOBAL_H = $(PCCONF_H) $(INCL)\coord.h $(INCL)\global.h HACK_H = $(CONFIG_H) $(INCL)\context.h $(DUNGEON_H) $(DECL_H) \ $(DISPLAY_H) $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\trap.h $(INCL)\flag.h \ $(RM_H) $(INCL)\vision.h $(INCL)\wintype.h \ $(INCL)\engrave.h $(INCL)\rect.h $(INCL)\sys.h \ $(INCL)\trampoli.h $(INCL)\hack.h DLB_H = $(INCL)\dlb.h TILE_H = $(WSHR)\tile.h $(MSYS)\pctiles.h # Make Roolz dude. # Due to the inadequacy of some makes these must accord with a # topological sort of the generated-from relation... output on # the left, input on the right. Trust me. # .SUFFIXES: .exe .o .til .uu .c .y .l # # Rules for files in src # .c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< .c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(SRC)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(SRC)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< # # Rules for files in sys\share # {$(SYS)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(SYS)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< # # Rules for files in sys\msdos # {$(MSYS)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(MSYS)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(MSYS)}.h{$(INCL)}.h: @copy $< $@ # # Rules for files in util # {$(UTIL)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(UTIL)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< # # Rules for files in win\share # {$(WSHR)}.c.o: @@$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(WSHR)}.c{$(OBJ)}.o: @@$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ {$(WSHR)}.txt{$(DAT)}.txt: @copy $< $@ # # Rules for files in win\tty # {$(WTTY)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(WTTY)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF ######################################################## # # TARGETS # # The default make target (so just typing 'nmake' is useful). # default : envchk $(GAMEFILE) # The default target. $(GAME): $(O)utility.tag $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all: install install: envchk $(GAME) $(O)install.tag @echo Done. $(O)install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy $(SRC)\nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF if exist $(DAT)\symbols copy $(DAT)\symbols $(GAMEDIR) copy $(SSHR)\termcap $(GAMEDIR) copy *.tib $(GAMEDIR) copy $(SSHR)\NetHack.cnf $(GAMEDIR)\defaults.nh copy $(MSYS)\NHAccess.nh $(GAMEDIR) copy $(U)recover.exe $(GAMEDIR) if exist $(DOC)\guideb*.txt copy $(DOC)\guideb*.txt $(GAMEDIR) if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR) if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR) echo install done > $@ $(O)sp_lev.tag: $(O)utility.tag $(SPLEVDES) cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(SRC) # -@if exist $(O)sp_lev.tag del $(O)sp_lev.tag @echo sp_levs done >$(O)sp_lev.tag $(O)utility.tag: $(INCL)\date.h $(INCL)\trap.h \ $(INCL)\onames.h $(INCL)\pm.h monstr.c vis_tab.c \ $(U)lev_comp.exe $(U)dgn_comp.exe $(U)recover.exe $(TILEUTIL) -@if exist $(O)utility.tag del $(O)utility.tag @echo utilities made > $@ tileutil: gif2txt.exe txt2ppm.exe @echo Optional tile development utilities are up to date. .PHONEY: envchk envchk: ! IF ("$(MACHINE_CODE)"!="") @SET MC=/G$(MACHINE_CODE) ! ELSE @SET MC= ! ENDIF ! IF ("$(CL)"=="") @echo CL Environment variable is defined as follows: SET CL=/AL $(MC) /Oo /Gy /Gs /Gt10 /Gf /Zp1 /W2 /I$(INCL) /I$(MSYS) /I$(WSHR) /nologo /c ! ELSE @echo Warning CL Environment variable is defined: @echo CL=$(CL) @echo Overriding that definition as follows: SET CL=/AL $(MC) /Oo /Gy /Gs /Gt10 /Gf /Zp1 /W2 /I$(INCL) /I$(MSYS) /I$(WSHR) /nologo /c ! ENDIF # The main target. $(GAMEFILE) : $(LNKOPT) $(ALLOBJ) @echo Linking.... $(LINK) $(LFLAGS) /SE:1000 /DYNAMIC:2650 /NOE /ST:6000 @<<$(GAME).lnk $(ALLOBJ:^ =+^ ) $(GAMEFILE) $(GAME) $(TERMLIB) $(MOVETR) $(CLIB) $(BCOVL) $(BCMDL) $(LNKOPT); << @if exist $(O)install.tag del $(O)install.tag @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak # # Housekeeping. # clean: del *.o del *.map del $(U)dlb_main.exe spotless: clean if exist $(O)utility.tag del $(O)utility.tag if exist $(O)install.tag del $(O)install.tag if exist $(GAME).lnk del $(GAME).lnk if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)lev_comp.exe del $(U)lev_comp.exe if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe if exist $(SRC)\lev_lex.c del $(SRC)\lev_lex.c if exist $(SRC)\lev_yacc.c del $(SRC)\lev_yacc.c if exist $(SRC)\dgn_lex.c del $(SRC)\dgn_lex.c if exist $(SRC)\dgn_yacc.c del $(SRC)\dgn_yacc.c if exist $(U)recover.exe del $(U)recover.exe if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist $(INCL)\pcvideo.h del $(INCL)\pcvideo.h if exist $(MSYS)\pctiles.h del $(MSYS)\pctiles.h if exist $(INCL)\portio.h del $(MSYS)\portio.h if exist $(WSHR)\tile.h del $(WSHR)\tile.h if exist monstr.c del monstr.c if exist vis_tab.c del vis_tab.c if exist $(SRC)\panic.c del $(SRC)\panic.c if exist $(SRC)\makedefs.c del $(SRC)\makedefs.c if exist $(SRC)\recover.c del $(SRC)\recover.c if exist $(SRC)\lev_main.c del $(SRC)\lev_main.c if exist $(SRC)\dlb_main.c del $(SRC)\dlb_main.c if exist $(SRC)\dgn_main.c del $(SRC)\dgn_main.c if exist $(SRC)\wintty.c del $(SRC)\wintty.c if exist $(SRC)\topl.c del $(SRC)\topl.c if exist $(SRC)\getline.c del $(SRC)\getline.c if exist $(SRC)\termcap.c del $(SRC)\termcap.c if exist $(SRC)\tile2bin.c del $(SRC)\tile2bin.c if exist $(SRC)\msdos.c del $(SRC)\msdos.c if exist $(SRC)\pckeys.c del $(SRC)\pckeys.c if exist $(SRC)\video.c del $(SRC)\video.c if exist $(SRC)\sound.c del $(SRC)\sound.c if exist $(SRC)\tilemap.c del $(SRC)\tilemap.c if exist $(SRC)\gifread.c del $(SRC)\gifread.c if exist $(SRC)\ppmwrite.c del $(SRC)\ppmwrite.c if exist $(SRC)\pcmain.c del $(SRC)\pcmain.c if exist $(SRC)\pcunix.c del $(SRC)\pcunix.c if exist $(SRC)\pcsys.c del $(SRC)\pcsys.c if exist $(SRC)\pctty.c del $(SRC)\pctty.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(INCL)\date.h del $(INCL)\date.h if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist vis_tab.c del vis_tab.c if exist *.lnk del *.lnk if exist *.def del *.def if exist *.map del *.map if exist a.out del a.out if exist tilemap.exe del tilemap.exe if exist tile2bin.exe del tile2bin.exe if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\*.lev del $(DAT)\*.lev if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(SRC)\nhdat del $(SRC)\nhdat if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst if exist $(DAT)\msdoshlp.txt del $(DAT)\msdoshlp.txt if exist $(DAT)\dlb_main.exe del $(DAT)\dlb_main.exe if exist $(DAT)\lev_comp.exe del $(DAT)\lev_comp.exe if exist $(DAT)\dgn_comp.exe del $(DAT)\dgn_comp.exe if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(PLANAR_TIB) del $(PLANAR_TIB) if exist $(OVERVIEW_TIB) del $(OVERVIEW_TIB) # # Secondary Targets. # # # Makedefs Stuff # $(U)makedefs.exe: $(MAKEOBJS) @echo Linking.... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(MAKEOBJS:^ =+^ ) $@ $(@B) ; << makedefs.o: $(CONFIG_H) $(PERMONST_H) $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(UTIL)\makedefs.c # The following include files depend on makedefs to be created. # # date.h should be remade every time any of the source or include # files is modified. $(INCL)\date.h : $(U)makedefs.exe -$(U)makedefs -v $(INCL)\onames.h: $(U)makedefs.exe -$(U)makedefs -o $(INCL)\pm.h: $(U)makedefs.exe -$(U)makedefs -p monstr.c: $(U)makedefs.exe -$(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe -$(U)makedefs -z vis_tab.c: $(U)makedefs.exe -$(U)makedefs -z # # Level Compiler Stuff # $(U)lev_comp.exe: $(SPLEVOBJS) @echo Linking $@... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(SPLEVOBJS:^ =+^ ) $@ $(@B) $(BCMDL); << $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)lev_comp.y copy $(YTABC) $(U)lev_yacc.c copy $(YTABH) $(INCL)\lev_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt lev_yacc.c @echo from $(SSHR) to $(U)lev_yacc.c, and copy the prebuilt @echo lev_comp.h from $(SYS) to $(UTIL)\lev_comp.h @echo and use those. @echo. copy $(SSHR)\lev_yacc.c $@ >nul touch $@ copy $(SSHR)\lev_comp.h $(INCL)\lev_comp.h >nul touch $(INCL)\lev_comp.h ! ENDIF $(U)lev_$(LEX).c: $(U)lev_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt lev_lex.c @echo from $(SSHR) to $@ and use it. @echo. copy $(SSHR)\lev_lex.c $@ >nul touch $@ ! ENDIF # # Dungeon Stuff # $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(DGNCOMPOBJS:^ =+^ ) $@ $(@B) $(BCMDL); << $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)dgn_comp.y copy $(YTABC) $(U)dgn_yacc.c copy $(YTABH) $(INCL)\dgn_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)dgn_comp.y has changed. To update $@ and @echo $(INCL)\dgn_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt dgn_yacc.c from @echo $(SSHR) to $(U)dgn_yacc.c, and copy the prebuilt @echo dgn_comp.h from $(SSHR) to $(INCL)\dgn_comp.h @echo and use those. @echo. copy $(SSHR)\dgn_yacc.c $@ >nul touch $@ copy $(SSHR)\dgn_comp.h $(INCL)\dgn_comp.h >nul touch $(INCL)\dgn_comp.h ! ENDIF $(U)dgn_$(LEX).c: $(U)dgn_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt dgn_lex.c @echo from $(SSHR) to $@ and use it. @echo. copy $(SSHR)\dgn_lex.c $@ >nul touch $@ ! ENDIF # # Recover Utility # $(U)recover.exe: $(RECOVOBJS) @echo Linking.... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(RECOVOBJS:^ =+^ ) $@ $(@B) ; << recover.o: $(CONFIG_H) $(UTIL)\recover.c # # Header file moves required for tile support # #$(WSHR)\tile.h: $(WSHR)\tile.h # copy $(WSHR)\tile.h $@ #$(MSYS)\pctiles.h: $(MSYS)\pctiles.h # copy $(MSYS)\pctiles.h $@ #$(INCL)\pcvideo.h: $(MSYS)\pcvideo.h # copy $(MSYS)\pcvideo.h $@ #$(MSYS)\portio.h: $(MSYS)\portio.h # copy $(MSYS)\portio.h $@ # # Tile Mapping # tile.c: tilemap.exe @tilemap @echo A new $@ has been created tilemap.exe: tilemap.o @echo Linking.... @$(LINK) $(LFLAGS) @<<$(@B).lnk tilemap.o $@ $(@B) ; << tilemap.c: $(WSHR)\tilemap.c copy $(WSHR)\tilemap.c . tilemap.o: tilemap.c $(HACK_H) $(TILE_H) # # Tile Utilities # # # Required for tile support # NetHack1.tib: $(TILEFILES) tile2bin.exe @echo Creating binary tile files (this may take some time) @tile2bin NetHacko.tib: thintile.tag $(TILEFILES2) til2bin2.exe @echo Creating overview binary tile files (this may take some time) @til2bin2 tile2bin.exe: tile2bin.o $(TEXTIO) @$(LINK) $(LFLAGS) tile2bin.o $(TEXTIO),$@,$(@B); til2bin2.exe: til2bin2.o $(TEXTIO2) @$(LINK) $(LFLAGS) til2bin2.o $(TEXTIO2),$@,$(@B); thintile.exe: thintile.o @$(LINK) $(LFLAGS) thintile.o,$@,$(@B); thintile.o: $(HACK_H) $(WSHR)\tile.h $(WSHR)\thintile.c thintile.tag: thintile.exe $(TILEFILES) thintile @echo thintiles created >thintile.tag tile2bin.o: $(HACK_H) $(WSHR)\tile.h $(MSYS)\pctiles.h $(MSYS)\pcvideo.h \ $(MSYS)\tile2bin.c til2bin2.o: $(HACK_H) $(WSHR)\tile.h $(MSYS)\pctiles.h $(MSYS)\pcvideo.h \ $(MSYS)\tile2bin.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 -DOVERVIEW_FILE /Zg $(MSYS)\tile2bin.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 -DOVERVIEW_FILE /Fo$@ $(MSYS)\tile2bin.c tiletext.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\tiletext.c tiletex2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\tiletext.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg $(WSHR)\tiletext.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Fo$@ $(WSHR)\tiletext.c tiletxt.o: $(CONFIG_H) $(WSHR)\tile.h tilemap.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Zg tilemap.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Fo$@ tilemap.c tiletxt2.o: $(CONFIG_H) $(WSHR)\tile.h tilemap.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Zg tilemap.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT -DTILE_X=8 /Fo$@ tilemap.c # # Optional GIF Utilities (for development) # gif2txt.exe: $(GIFREADERS) $(TEXTIO) @$(LINK) $(LFLAGS) $(GIFREADERS) $(TEXTIO),$@,$(@B); gif2txt2.exe: $(GIFREAD2) $(TEXTIO2) @$(LINK) $(LFLAGS) $(GIFREAD2) $(TEXTIO2),$@,$(@B); txt2ppm.exe: $(PPMWRITERS) $(TEXTIO) @$(LINK) $(LFLAGS) $(PPMWRITERS) $(TEXTIO),$@,$(@B); txt2ppm2.exe: $(PPMWRIT2) $(TEXTIO2) @$(LINK) $(LFLAGS) $(PPMWRIT2) $(TEXTIO2),$@,$(@B); gifread.o: $(CONFIG_H) $(WSHR)\tile.h gifread2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\gifread.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg gifread.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 $(WSHR)\gifread.c ppmwrite.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\ppmwrite.c ppmwrit2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\ppmwrite.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg ppmwrite.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 $(WSHR)\ppmwrite.c # # Optional tile viewer (development sources only) # viewtib.exe: viewtib.o @$(LINK) $(LFLAGS) -oviewtib.exe viewtib.o $(LIBRARIES) viewtib.o: $(MSYS)\viewtib.c # # Other Util Dependencies. # alloc.o: $(CONFIG_H) alloc.c drawing.o: $(CONFIG_H) drawing.c $(MSYS)\pcvideo.h decl.o: $(CONFIG_H) decl.c monst.o: $(CONFIG_H) $(PERMONST_H) $(INCL)\monsym.h \ $(INCL)\color.h monst.c objects.o: $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\color.h objects.c panic.o: $(CONFIG_H) $(UTIL)\panic.c # # make data.base an 8.3 filename to prevent an nmake warning # DATABASE = $(DAT)\data.bas $(DAT)\data: $(O)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(O)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(O)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(O)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(O)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(SRC) # # DLB stuff # # nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(DAT)\options \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon \ $(DAT)\license $(O)sp_lev.tag @copy $(MSYS)\msdoshlp.txt $(DAT) @cd $(DAT) @echo data >dlb.lst @echo oracles >>dlb.lst @echo options >>dlb.lst @echo quest.dat >>dlb.lst @echo rumors >>dlb.lst @echo help >>dlb.lst @echo hh >>dlb.lst @echo cmdhelp >>dlb.lst @echo history >>dlb.lst @echo opthelp >>dlb.lst @echo wizhelp >>dlb.lst @echo dungeon >>dlb.lst @echo license >>dlb.lst @echo msdoshlp.txt >>dlb.lst ! IF ("$(NO_FOR)"=="Y") echo AIR.LEV >>dlb.lst echo ARC-FILA.LEV >>dlb.lst echo ARC-FILB.LEV >>dlb.lst echo ARC-GOAL.LEV >>dlb.lst echo ARC-LOCA.LEV >>dlb.lst echo ARC-STRT.LEV >>dlb.lst echo ASMODEUS.LEV >>dlb.lst echo ASTRAL.LEV >>dlb.lst echo BAALZ.LEV >>dlb.lst echo BAR-FILA.LEV >>dlb.lst echo BAR-FILB.LEV >>dlb.lst echo BAR-GOAL.LEV >>dlb.lst echo BAR-LOCA.LEV >>dlb.lst echo BAR-STRT.LEV >>dlb.lst echo BIGRM-1.LEV >>dlb.lst echo BIGRM-2.LEV >>dlb.lst echo BIGRM-3.LEV >>dlb.lst echo BIGRM-4.LEV >>dlb.lst echo BIGRM-5.LEV >>dlb.lst echo CASTLE.LEV >>dlb.lst echo CAV-FILA.LEV >>dlb.lst echo CAV-FILB.LEV >>dlb.lst echo CAV-GOAL.LEV >>dlb.lst echo CAV-LOCA.LEV >>dlb.lst echo CAV-STRT.LEV >>dlb.lst echo EARTH.LEV >>dlb.lst echo FAKEWIZ1.LEV >>dlb.lst echo FAKEWIZ2.LEV >>dlb.lst echo FIRE.LEV >>dlb.lst echo HEA-FILA.LEV >>dlb.lst echo HEA-FILB.LEV >>dlb.lst echo HEA-GOAL.LEV >>dlb.lst echo HEA-LOCA.LEV >>dlb.lst echo HEA-STRT.LEV >>dlb.lst echo JUIBLEX.LEV >>dlb.lst echo KNI-FILA.LEV >>dlb.lst echo KNI-FILB.LEV >>dlb.lst echo KNI-GOAL.LEV >>dlb.lst echo KNI-LOCA.LEV >>dlb.lst echo KNI-STRT.LEV >>dlb.lst echo KNOX.LEV >>dlb.lst echo MEDUSA-1.LEV >>dlb.lst echo MEDUSA-2.LEV >>dlb.lst echo MINEFILL.LEV >>dlb.lst echo MINEND-1.LEV >>dlb.lst echo MINEND-2.LEV >>dlb.lst echo MINEND-3.LEV >>dlb.lst echo MINETN-1.LEV >>dlb.lst echo MINETN-2.LEV >>dlb.lst echo MINETN-3.LEV >>dlb.lst echo MINETN-4.LEV >>dlb.lst echo MINETN-5.LEV >>dlb.lst echo MINETN-6.LEV >>dlb.lst echo MINETN-7.LEV >>dlb.lst echo MON-FILA.LEV >>dlb.lst echo MON-FILB.LEV >>dlb.lst echo MON-GOAL.LEV >>dlb.lst echo MON-LOCA.LEV >>dlb.lst echo MON-STRT.LEV >>dlb.lst echo ORACLE.LEV >>dlb.lst echo ORCUS.LEV >>dlb.lst echo PRI-FILA.LEV >>dlb.lst echo PRI-FILB.LEV >>dlb.lst echo PRI-GOAL.LEV >>dlb.lst echo PRI-LOCA.LEV >>dlb.lst echo PRI-STRT.LEV >>dlb.lst echo RAN-FILA.LEV >>dlb.lst echo RAN-FILB.LEV >>dlb.lst echo RAN-GOAL.LEV >>dlb.lst echo RAN-LOCA.LEV >>dlb.lst echo RAN-STRT.LEV >>dlb.lst echo ROG-FILA.LEV >>dlb.lst echo ROG-FILB.LEV >>dlb.lst echo ROG-GOAL.LEV >>dlb.lst echo ROG-LOCA.LEV >>dlb.lst echo ROG-STRT.LEV >>dlb.lst echo SAM-FILA.LEV >>dlb.lst echo SAM-FILB.LEV >>dlb.lst echo SAM-GOAL.LEV >>dlb.lst echo SAM-LOCA.LEV >>dlb.lst echo SAM-STRT.LEV >>dlb.lst echo SANCTUM.LEV >>dlb.lst echo SOKO1-1.LEV >>dlb.lst echo SOKO1-2.LEV >>dlb.lst echo SOKO2-1.LEV >>dlb.lst echo SOKO2-2.LEV >>dlb.lst echo SOKO3-1.LEV >>dlb.lst echo SOKO3-2.LEV >>dlb.lst echo SOKO4-1.LEV >>dlb.lst echo SOKO4-2.LEV >>dlb.lst echo TOU-FILA.LEV >>dlb.lst echo TOU-FILB.LEV >>dlb.lst echo TOU-GOAL.LEV >>dlb.lst echo TOU-LOCA.LEV >>dlb.lst echo TOU-STRT.LEV >>dlb.lst echo TOWER1.LEV >>dlb.lst echo TOWER2.LEV >>dlb.lst echo TOWER3.LEV >>dlb.lst echo VAL-FILA.LEV >>dlb.lst echo VAL-FILB.LEV >>dlb.lst echo VAL-GOAL.LEV >>dlb.lst echo VAL-LOCA.LEV >>dlb.lst echo VAL-STRT.LEV >>dlb.lst echo VALLEY.LEV >>dlb.lst echo WATER.LEV >>dlb.lst echo WIZ-FILA.LEV >>dlb.lst echo WIZ-FILB.LEV >>dlb.lst echo WIZ-GOAL.LEV >>dlb.lst echo WIZ-LOCA.LEV >>dlb.lst echo WIZ-STRT.LEV >>dlb.lst echo WIZARD1.LEV >>dlb.lst echo WIZARD2.LEV >>dlb.lst echo WIZARD3.LEV >>dlb.lst ! ELSE @for %%N in (*.lev) do echo %%N >>dlb.lst ! ENDIF $(U)dlb_main cvIf dlb.lst $(SRC)\nhdat @cd $(SRC) $(U)dlb_main.exe: $(DLBOBJS) link $(LFLAGS) /ST:5120 $(DLBOBJS),$@,$(@B); dlb_main.o: $(U)dlb_main.c $(INCL)\config.h $(DLB_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(U)dlb_main.c # Game Dependencies # sys/share main.o: $(SSHR)\pcmain.c $(HACK_H) $(INCL)\dlb.h \ #$(INCL)\win32api.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcmain.c pcsys.o: $(SSHR)\pcsys.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcsys.c tty.o: $(SSHR)\pctty.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pctty.c unix.o: $(SSHR)\pcunix.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcunix.c random.o: $(SSHR)\random.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\random.c # sys/msdos msdos.o : $(HACK_H) $(MSYS)\msdos.c @$(CC) $(CFLAGS) $(SPECOPTS) $(NEWALT) /Fo$@ $(MSYS)\msdos.c pckeys.o : $(HACK_H) $(MSYS)\pckeys.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\pckeys.c pctiles.o : $(HACK_H) $(MSYS)\pctiles.c $(MSYS)\portio.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\pctiles.c sound.o : $(HACK_H) $(MSYS)\sound.c $(MSYS)\portio.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\sound.c video.o : $(HACK_H) $(MSYS)\pcvideo.h $(MSYS)\portio.h $(MSYS)\video.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\video.c vidvga.o : $(HACK_H) $(MSYS)\pcvideo.h $(MSYS)\portio.h $(TILE_H) \ $(MSYS)\vidvga.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\vidvga.c vidtxt.o : $(HACK_H) $(MSYS)\pcvideo.h $(MSYS)\portio.h $(TILE_H) \ $(MSYS)\vidtxt.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\vidtxt.c stubvid.o : $(HACK_H) $(MSYS)\video.c @$(CC) $(CFLAGS) $(SPECOPTS) -DSTUBVIDEO /Fo$@ $(MSYS)\video.c # win/tty getline.o: $(WIN)\getline.c $(HACK_H) $(INCL)\func_tab.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\getline.c termcap.o: $(WIN)\termcap.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\termcap.c topl.o: $(WIN)\topl.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\topl.c wintty.o: $(WIN)\wintty.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\date.h $(INCL)\patchlev.h $(INCL)\tcap.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\wintty.c # src dependencies allmain.o: allmain.c $(HACK_H) alloc.o: alloc.c $(CONFIG_H) apply.o: apply.c $(HACK_H) artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h attrib.o: attrib.c $(HACK_H) $(INCL)\artifact.h ball.o: ball.c $(HACK_H) bones.o: bones.c $(HACK_H) $(INCL)\lev.h botl.o: botl.c $(HACK_H) cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h dbridge.o: dbridge.c $(HACK_H) decl.o: decl.c $(HACK_H) detect.o: detect.c $(HACK_H) $(INCL)\artifact.h dig.o: dig.c $(HACK_H) display.o: display.c $(HACK_H) dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h do.o: do.c $(HACK_H) $(INCL)\lev.h do_name.o: do_name.c $(HACK_H) do_wear.o: do_wear.c $(HACK_H) dog.o: dog.c $(HACK_H) dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h dokick.o: dokick.c $(HACK_H) dothrow.o: dothrow.c $(HACK_H) drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h eat.o: eat.c $(HACK_H) end.o: end.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h exper.o: exper.c $(HACK_H) explode.o: explode.c $(HACK_H) extralev.o: extralev.c $(HACK_H) files.o: files.c $(HACK_H) $(INCL)\dlb.h fountain.o: fountain.c $(HACK_H) hack.o: hack.c $(HACK_H) hacklib.o: hacklib.c $(HACK_H) invent.o: invent.c $(HACK_H) $(INCL)\artifact.h light.o: light.c $(HACK_H) $(INCL)\lev.h lock.o: lock.c $(HACK_H) mail.o: mail.c $(HACK_H) $(INCL)\mail.h makemon.o: makemon.c $(HACK_H) mapglyph.o: mapglyph.c $(HACK_H) mcastu.o: mcastu.c $(HACK_H) mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h minion.o: minion.c $(HACK_H) mklev.o: mklev.c $(HACK_H) mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h mkobj.o: mkobj.c $(HACK_H) $(INCL)\artifact.h mkroom.o: mkroom.c $(HACK_H) mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h mondata.o: mondata.c $(HACK_H) monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\dungeon.h $(INCL)\color.h mplayer.o: mplayer.c $(HACK_H) mthrowu.o: mthrowu.c $(HACK_H) muse.o: muse.c $(HACK_H) music.o: music.c $(HACK_H) #interp.c o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h objnam.o: objnam.c $(HACK_H) options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h pager.o: pager.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(CFLAGS) $(SPECOPTS) /f- /Od /Fo$@ pager.c pickup.o: pickup.c $(HACK_H) pline.o: pline.c $(HACK_H) polyself.o: polyself.c $(HACK_H) potion.o: potion.c $(HACK_H) pray.o: pray.c $(HACK_H) priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h quest.o: quest.c $(HACK_H) $(INCL)\qtext.h questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h read.o: read.c $(HACK_H) rect.o: rect.c $(HACK_H) region.o: region.c $(HACK_H) restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h rip.o: rip.c $(HACK_H) rnd.o: rnd.c $(HACK_H) role.o: role.c $(HACK_H) rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h save.o: save.c $(HACK_H) $(INCL)\lev.h shk.o: shk.c $(HACK_H) shknam.o: shknam.c $(HACK_H) sit.o: sit.c $(HACK_H) $(INCL)\artifact.h sounds.o: sounds.c $(HACK_H) sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h spell.o: spell.c $(HACK_H) steal.o: steal.c $(HACK_H) steed.o: steed.c $(HACK_H) sys.o: sys.c $(HACK_H) teleport.o: teleport.c $(HACK_H) timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlev.h track.o: track.c $(HACK_H) trap.o: trap.c $(HACK_H) u_init.o: u_init.c $(HACK_H) uhitm.o: uhitm.c $(HACK_H) vault.o: vault.c $(HACK_H) version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlev.h vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h weapon.o: weapon.c $(HACK_H) were.o: were.c $(HACK_H) wield.o: wield.c $(HACK_H) windows.o: windows.c $(HACK_H) $(INCL)\wingem.h wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h worm.o: worm.c $(HACK_H) $(INCL)\lev.h worn.o: worn.c $(HACK_H) write.o: write.c $(HACK_H) zap.o: zap.c $(HACK_H) # end of file nethack-3.6.0/sys/msdos/SCHEMA35.MSC0000664000076400007660000013005012536476415015570 0ustar paxedpaxed; Copyright (c) NetHack PC Development Team, 2000 ; ; NetHack Overlay Schema ; This overlay schema is for use only when NetHack is built ; using packaged-functions for function-level linking. ; ; Overlay tuning level: 0 ; functions:0 _main _dosave0 _moveloop _bwrite _random _rn2 _newsym _show_glyph _on_level _txt_gotoxy _txt_get_cursor functions:0 _xputc _txt_xputc _t_at _tty_curs _acurr _dist2 _tty_print_glyph _isok _back_to_glyph functions:0 _show_map_spot _adjust_cursor_flags _lowc _g_putch _has_color _is_pool _mread functions:0 _is_lava _welded _magic_map_background _end_glyphout _visible_region_at _domove functions:0 _engr_at _rnd _run_regions _mcalcmove _depth _done _distmin _does_block _eos functions:0 _move _move_bc _in_rooms _map_background _map_invisible _map_location _alloc functions:0 _impossible _in_container _in_fcorridor _In_hell _In_mines _in_or_out_menu _In_quest functions:0 _do_positionbar _iswall _iswall_or_stone _itimeout _is_solid _Is_special functions:0 _is_swallow_sym _check_here _check_leash _check_map_spot _check_pos functions:0 _monsndx _m_move _lcase _tty_create_nhwindow _tty_delay_output _tty_destroy_nhwindow functions:0 _tty_dismiss_nhwindow _gender _genl_outrip _get_cost _get_free_room_loc _get_level functions:0 _get_location _get_map _get_mleash ; functions:1 _move_update _movebubbles _movecmd _movemon _moverock _movobj _mpickgold functions:1 _doaltarobj _doapply _dobreathe _docall _docast ; functions:2 _do_vicinity_map functions:3 _pcmain functions:4 _spell_let_to_idx _cursed_book _deadbook _learn _getspell _spelltypemnemonic functions:5 _dospellmenu _percent_success _throwspell _cast_protection _isqrt ; functions:6 _a_gname _a_gname_at _a_monnam _abon _abuse_dog _accessible _activate_statue_trap functions:7 _add_branch _add_damage _add_debug_extended_commands _add_door _add_id_mapping _add_level functions:8 _add_menu_cmd_alias _add_one_tobill _add_rect _add_room _add_subroom _add_to_billobjs _add_to_buried _add_to_container functions:9 _add_to_migration _add_to_minv _add_valid_menu_class _add_weapon_skill _addinv _addtobill _addtopl _addupbill functions:10 _Adjmonnam functions:11 _align_gname functions:12 _altar_wrath _Amonnam _amulet _Amulet_off _Amulet_on _An _an _angry_guards functions:13 _angry_priest _angry_shk_exists _any_light_source _aobjnam _append_slash _append_str _Armor_gone _Armor_off functions:14 _Armor_on _armor_to_dragon _armoroff _arti_invoke _artifact_exists _artifact_hit _artifact_name _artiname functions:15 _artitouch _askchain _assign_graphics _assign_level _assign_rnd_level _assign_soundcard _assign_video functions:16 _assign_videocolors _assign_videoshades _assigninvlet _at_dgn_entrance _attach_egg_hatch_timeout _attack _attack_checks _attacks functions:17 _awaken_monsters _awaken_soldiers functions:18 _backfire _backsp _bad_location _bad_negation _bad_rock _badoption _bail _ballfall functions:19 _bc_order _bclose _bcsign _beg _begin_burn _bflush _bhit _bhitm functions:20 _bhito _bhitpile _big_to_little _bill_box_content _bill_dummy_object _bite _bless _blessorcurse functions:21 _Blindf_off _Blindf_on _block_door _block_entry _block_point _blow_up_landmine _body_part functions:22 _boomhit _Boots_off _Boots_on _bot _boulder_hits_pool _bound_digging functions:23 _boxlock _br_string _break_armor _break_statue _breakarm _breakmsg functions:24 _breakobj _breaks _breaksink _breaktest _breamu _bribe _bufoff _bufon functions:25 _build_room _burn_floor_paper _burn_object _burnarmor _bury_an_obj _bury_objs _buzz _buzzmu functions:26 _Can_dig_down functions:27 _Can_fall_thru _can_make_bones _can_ooze _can_pray _can_reach_floor _Can_rise_up _can_track functions:28 _cancel_bonesfile _cancel_don _cancel_item _cancel_monst _candle_light_range _canletgo _canwearobj functions:29 _carry_count _carrying _castmu _ceiling _center _change_inv_order _change_luck _change_sex functions:30 _charm_monsters _charm_snakes _chat_with_guardian _chat_with_leader _chat_with_nemesis _chdirx _chdrive _cheapest_item functions:31 _check_capacity _check_contained _check_credit _check_recordfile functions:32 _check_room _check_shop_obj _check_special_room _check_unpaid _check_unpaid_usage _check_version _checkfile _chest_shatter_msg functions:33 _chest_trap _choke _choke_dialogue _choose_classes_menu _choose_windows _christen_monst _chwepon _ck_bag functions:34 _ckmailstatus _ckunpaid _cl_end _cl_eos _classmon _clear_fcorr _clear_glyph_buffer functions:35 _clear_id_mapping _clear_level_structures _clear_path _clear_screen _clear_stale_map _clear_unpaid _clearlocks _clearpriests functions:36 _click_to_cmd _Cloak_off _Cloak_on _clone_mon _cloneu _clonewiz _close_drawbridge _close_library functions:37 _closed_door _CloseTileFile _cls _cmov _cnv_trap_obj _co_false _collect_obj_classes _com_pager functions:38 _commit_bonesfile _compactify _compress_bonesfile _compress_str _comspec_exists _confdir _construct_qtlist functions:39 _consume_offering _contained _contained_cost _contained_gold _container_contents _container_weight _convert_arg _convert_line functions:40 _copybones _copyfile _corpse_chance _corpse_xname _corr _correct_branch_type _cost _cost_per_charge functions:41 _costly_gold _costly_spot _could_seduce _count_categories _count_obj _count_unpaid _count_wsegs functions:42 _counter_were _courtmon _cpostfx _cprefx _create_altar _create_bonesfile _create_corridor _create_critters functions:43 _create_door _create_drawbridge _create_engraving _create_feature _create_gold _create_levelfile _create_monster _create_mplayers functions:44 _create_object _create_particular _create_polymon _create_room _create_savefile _create_secret_door _create_stairs _create_subroom functions:45 _create_trap _create_worm_tail _curr_mon_load _currentlevel_rewrite _curs_on_u _curse _cursed _cursed_object_at functions:46 _cursetxt _cuss _cutworm _cvt_sdoor_to_door _d _damageum _dbon functions:47 _ddoinv _dead_species _dealloc_obj _decl_init _deepest_lev_reached _def_char_to_monclass _def_char_to_objclass _def_raw_print functions:48 _defends _deferred_goto _del_engr _del_engr_at _del_light_source _delallobj _delete_bonesfile _delete_contents functions:49 _delete_levelfile _delete_savefile _delfloortrap _deliver_by_pline _deliver_by_window _delobj _deltrap _demon_talk functions:50 _demonpet _destroy_arm _destroy_drawbridge _destroy_item _destroy_mitem _dev_name _dig functions:51 _dig_check _dig_corridor _dig_point _dig_typ _digactualhole _dighole _digit _dipfountain functions:52 _disable_ctrlP _disarm_landmine _disarm_shooting_trap _disarm_squeaky_board _discard_minvent _disclose _discover_object functions:53 _diseasemu _display_binventory _display_cinventory _display_gamewindows _display_inventory _display_minventory functions:54 _distant_name _distfleeck _disturb _djinni_from_bottle _dlb_cleanup _dlb_fclose functions:55 _dlb_fgets _dlb_fopen _dlb_fread _dlb_fseek _dlb_ftell _dlb_init _dlord _dmgtype functions:56 _dmgval _dmonsfree _dmore _dname_to_dnum _do_break_wand _do_clear_area _do_comp _do_dknown_of functions:57 _do_earthquake _do_entity _do_genocide _do_improvisation _do_light_sources _do_look _do_mapping _do_mname functions:57 _vga_xputg _vga_xputs _video_update_positionbar _view_from _view_init _visctrl _vision_init _vision_recalc functions:58 _do_oname _do_osshock _do_play_instrument _do_reset_eat _do_room_or_subroom _do_storms _do_takeoff functions:60 _doclose _doconsult _docorner _docrt _doddoremarm _doddrop _dodip functions:61 _adjust_prefix _build_plselection_prompt _duplicate_opt_detection _enter_explore_mode _maybe_wail functions:62 _doextcmd _doextlist _doextversion _dofindgem _dofiretrap _doforce _dog_eat _dog_goal functions:63 _dog_hunger _dog_invent _dog_move _dog_nutrition _dogfood _dogushforth _dohelp _dohide functions:64 _dohistory _doidtrap _doinvbill _doinvoke _dojump _dokick _dolook _doloot functions:65 _domagicportal functions:66 _done_eating _done_in_by _done_intr _done1 _done2 _donning _donull _doopen functions:67 _doorganize _doorlock _dopay _dopayobj _dopickup _dopotion _dopramulet _doprarm functions:68 _dopray _doprev_message _doprgold _doprring _doprtool _doprwep _doputon _doquickwhatis functions:69 _doread _dorecover _doredraw _doremove _doremring _dorub _dosacrifice _dosave functions:70 _dosdoor _dosearch _dosearch0 _doseduce _doset _doset_add_menu _dosh functions:71 _dosinkfall _dosinkring _dosit _dosounds _dospinweb _dospit _dosummon _dotakeoff functions:72 _dotalk _dotele _dothrow _dotogglepickup _dotrap _doturn _dotypeinv _dounpaid functions:73 _dountrap _doup _doversion _dovspell _dowaterdemon _dowaternymph _dowatersnakes _dowear functions:74 _dowhatdoes _dowhatis _dowield _dowipe _down_gate _dowrite _dozap _dprince functions:75 _drag_ball _drag_down _drain_en _DrawCursor _drinkfountain _drinksink _drop _drop_ball functions:76 _drop_throw _drop_to _drop_upon_death _drop_weapon _dropped_container _dropx _dropy functions:77 _drown _dryup _dtoxy _dungeon_branch _dunlev _dunlevs_in_dungeon _e_at _e_died functions:78 _e_jumps _e_missed _e_nam _E_phrase _e_survives_at _eataccessory _eatcorpse _eaten_stat functions:79 _eatfood _eatmdone _eatspecial _egg_type_from_parent _emergency_disrobe _enable_ctrlP _encumber_msg _end_burn functions:80 _end_engulf ;functions:81 functions:82 _exclam _exepath _exerchk _exercise _exerper _exist_artifact _expels _experience functions:83 _explmm _explmu _explode _explum _expulsion _ext_cmd_getlin_hook _extend_spine _extract_nexthere functions:84 _extract_nobj _fall_asleep _fall_through _feel_cockatrice _feel_location _fightm _filesize_nh _fill_pit functions:85 _nh_getenv _promptsep _rigid_role_checks _set_duplicate_opt_detection _tool_in_use functions:86 _find_drawbridge _find_hell _find_lev_obj _find_level _find_mac _find_mid _find_misc _find_offensive functions:87 _find_oid _find_roll_to_hit _find_skates _find_unpaid _finddpos _findfirst_file _findgd _findit functions:88 _findnext_file _findone _findpriest _finish_map _finish_paybill _fix_stair_rooms _fix_worst_trouble _fixup_special functions:89 _flash_hits_mon _float_down _float_up _floating_above _flood_fill_rm _flooreffects _floorfood _flush_screen _term_start_color functions:90 _flushout _fmt_ptr _food_detect _food_disappears _food_xname _foodword _fopen_config_file _fopen_datafile functions:91 _fopenp _forcelock _forget_levels _forget_map _forget_objects _forget_traps _foundfile_buffer _fpostfx functions:92 _fprefx _fracture_rock _free_dungeons _free_rooms _free_ttlist _free_window_info _freediskspace _freedynamicdata functions:93 _freefruitchn _freehand _freeinv _friday_13th _fruitadd _fry_by_god _fully_identify_obj _g_at functions:94 _gainstr _gameDiskPrompt _gazemm _gazemu _gd_move _gd_sound _gem_accept functions:95 _display_warning _dlb_fgetc _doattributes _dochug _dochugw functions:96 _fill_point _fill_room _fill_zoo _fillholetyp _find_ac _find_branch _find_branch_room _find_defensive functions:96 _get_mon_location _get_mplname _get_obj_location _get_rect _get_rect_ind _get_room_loc _get_scr_size _get_shop_item functions:97 _get_uchars _get_unused_cs _get_valuables _get_wall_for_db _get_wet _get_wormno _getbones _getdir functions:98 _gethungry functions:99 _gettty _getversionstring _getyear _ggetobj _ghitm _ghod_hitsu _ghost_from_bottle _ghostfruit functions:100 _givit _glibr _Gloves_off _Gloves_on _glyph_at _god_zaps_you _gods_angry _gods_upset functions:101 _godvoice _gold_detect _golemeffects _golemhp _goodfruit _goodpos _goto_hell _goto_level functions:102 _gr_finish _gr_init _grddead _grease_protect _grow_up _growl _growl_sound functions:103 _guardname _gulpmm _gulpmu _gulpum _gush _hack_artifacts _has_dnstairs functions:104 _has_shrine _has_upstairs _hatch_egg _hates_silver _have_lizard _hcolor _heal_legs _healup functions:105 _Hear_again _Helmet_off _Helmet_on _help_menu _help_monster_out _hero_breaks _hidden_gold _HideCursor functions:106 _highc _histemple_at _hit _hitfloor _hitmm _hitmsg _hitmu _hitum functions:107 _hitval _hmon _hmon_hitmon _hmonas _hold_another_object _holetime _home _home_shk functions:108 _homebase _hooked_tty_getlin _hot_pursuit _hurtarmor _hurtle _identify _identify_pack _impact_drop functions:110 _in_trouble _In_V_tower _In_W_tower _in_your_sanctuary _incr_itimeout _induced_align _inherits _inhishop functions:111 _init_artifacts _init_attr _init_dungeons _init_fill _init_level _init_map _init_objects functions:112 _init_oracles _init_rect _init_rumors _init_ttycolor _init_uhunger _initedog _initoptions _initrack functions:113 _initworm _insert_branch _insert_timer _inside_room _inside_shop _instapetrify _intemple _interesting_to_discover functions:114 _intermed _intervene _intrinsic_possible _inv_cnt _inv_weight _invault _invdisp_nothing _inven_inuse functions:115 _invert_all _invert_all_on_page _Invocation_lev _invocation_message _invocation_pos _Is_botlevel _Is_branchlev _is_chargeable functions:116 _is_db_wall _is_drawbridge_wall _is_edible _is_fainted _is_flammable _is_fshk _is_home_elemental _is_ice ;functions:117 functions:118 _is_worn _is_worn_by_type _isbig _isclearpath functions:119 _itimeout_incr _its_dead _itsstuck _Japanese_item_name _join _join_map _jump _keepdogs functions:119 _sticks _still_chewing _stock_room _stolen_container _stolen_value _stone_luck _stoned_dialogue _stop_occupation functions:120 _kick_monster _kick_object _kickdmg _kickstr _kill_egg _kill_eggs _kill_genocided_monsters _killed functions:121 _kind_name _known_hitum _kops_gone _l_monnam _lantern_message _launch_obj _lava_effects functions:122 _ldrname _leader_speaks _learn_egg_type _ledger_no _ledger_to_dlev _ledger_to_dnum functions:123 _left_side _lesshungry _let_to_name _letter _lev_by_name _level_difficulty _level_distance _level_range functions:124 _level_tele _level_tele_trap _levl_follower _lifesaved_monster _lift_object _light_cocktail _light_region _lined_up functions:125 _linedup _list_genocided _list_vanquished _litroom _litter _little_to_big _llord _lminion functions:126 _load_common_data _load_maze _load_one_engraving _load_one_monster _load_one_object _load_qtlist _load_rooms _load_special functions:127 _loadfruitchn _lock_action _lock_file _locomotion _lookaround _lookat _lookup_id_mapping _lose_weapon_skill functions:128 _losedogs _losehp _losespells _losestr _losexp _m_arrival functions:129 _m_carrying _m_detach _m_dowear _m_dowear_type _m_initgrp _m_initinv _m_initthrow _m_initweap functions:130 _m_lose_armor functions:131 _m_useup _make_angry_shk _make_blinded _make_confused _make_corpse _make_engr_at _make_familiar _make_hallucinated functions:132 _make_happy_shk _make_lockname _make_niches _make_sick _make_stunned _make_vomiting _makecorridors _makedog functions:133 _makekops _makelevel _makemaz _makemon _makeniche _makeplural _makerogueghost _makeroguerooms functions:134 _makerooms functions:135 _map_menu_cmd _map_object _map_trap _match_optname _mattackm _mattacku _max_capacity _max_mon_load functions:136 _max_passive_dmg _max_rank_sz _maxledgerno _may_dig _may_passwall _maybe_write_ls _maybe_write_timer _mayberem functions:137 _maze0xy _maze1xy _mazexy _mb_trapped _mbag_explodes _mbhit _mbhitm _mcalcdistress functions:138 _md_rush _md_start _md_stop _mdig_tunnel functions:139 _meatobj _melt_ice _menu_drop _menu_identify _menu_loot _menu_remarm _mergable _merge_choice functions:140 _merged _mfndpos _midnight _migrate_to_level _mineralize _minit _miniwalk _minstapetrify functions:140 _On_stairs _on_start _On_W_tower_level _oname _onbill _online2 _only_here _onlyspace functions:141 _mintrap functions:142 _mk_bubble _mk_knox_portal _mk_mplayer _mk_named_object _mk_roamer _mk_tt_object _mkaltar _mkbox_cnts functions:143 _mkcavearea _mkcavepos _mkclass _mkcorpstat _mkfount _mkgold _mkgoldobj _mkinvokearea functions:144 _mkinvpos _mklev _mkmap _mkobj _mkobj_at _mkportal _mkroll_launch _mkroom functions:145 _mkshobj_at _mkshop _mksink _mksobj _mksobj_at _mkstairs _mkswamp _mktemple functions:146 _mktrap _mkundead _mkzoo _mlevel_tele_trap _mlifesaver _mnearto _mnexto _mon_arrive functions:147 _mon_break_armor _mon_catchup_elapsed_time _mon_chain _mon_has_amulet _mon_has_arti _mon_has_special _mon_invent_chain _mon_is_local functions:148 _mon_nam _mon_nam_too _mon_owns _mon_reflects _mon_regen _mon_set_minvis _mon_to_stone _mon_wield_item functions:149 _mondead _mondied _mongets _mongone _monkilled _Monnam _monnear functions:150 _monst_init _monster_detect _monster_nearby _monstinroom _monstone _monstr_init _more _more_experienced functions:151 _morehungry _morguemon _move_gold _move_into_trap _move_special functions:153 _mpickobj functions:154 _mselftouch _msg_in _msleep _msmsg _mstatusline _msummon _mswings _mswingsm functions:155 _mtele_trap _mungspaces _munstone _mv_bubble _mvault_tele _mzapmsg _n_or_more _name_to_mon functions:156 _nameshk _nartifact_exist _nasty _ndemon _near_capacity _nemdead _nemesis_speaks _neminame functions:157 _nethack_exit _new_light_source _new_were _newcham _newexplevel _newgame _newhp _newmail functions:158 _newman _newuexp _newuhs _next_level _next_opt _next_shkp _next_to_u functions:159 _nexttodoor _nh_timeout _nhusage _night _nmcpy _no_bones_level _noattacks _nocmov functions:160 _nohandglow _noises _nomul _Norep _not_capable _not_fully_identified _number_leashed _o_in functions:161 _o_on _o_unleash _obfree _obj_chain _obj_delivery _obj_extract_self _obj_here _obj_ice_effects functions:162 _obj_is_burning _obj_is_local _obj_is_pname _obj_merge_light_sources _obj_move_light_source _obj_move_timers _obj_resists _obj_sanity_check functions:163 _obj_sheds_light _obj_shudders _obj_split_light_source _obj_split_timers _obj_stop_timers _obj_to_let _object_detect _objects_init functions:164 _observable_depth _obstructed _oc_to_str _occupied _off_msg _ohitmon _oinit _ok_to_quest functions:165 _okay functions:167 _onquest _onscary _open_bonesfile _open_drawbridge _open_levelfile _open_library _open_savefile _openit functions:168 _openone _OpenTileFile _opentin _option_help _oselect _other_mon_has_arti _otransit_msg functions:169 _out_container _outentry _outheader _outoracle _outrumor _p_coaligned _pacify_guards _pacify_shk functions:170 _panic _parent_dlevel _parent_dnum _parse _parse_config_line _parseoptions _pass_one _pass_three functions:171 _pass_two _passive _passivemm _passiveum _pay _pay_for_damage _paybill _paygd functions:172 _pckeys _peace_minded _peek_at_iced_corpse_age _peffects _pet_type _pgetchar _phase_of_the_moon functions:173 _pick_level _pick_lock _pick_obj _pick_room _picked_container _picking_at _picking_lock _picklock functions:174 _pickup _pickup_object _place_branch _place_level _place_lregion _place_niche _place_object _place_worm_tail_randomly functions:175 _place_wsegs _placebc _playwoRAMdisk _pleased _pline _pline_The _plnamesuffix _pluslvl functions:176 _pmatch _poisoned _poisontell _poly_gender _poly_obj _poly_when_stoned _polyman _polymon functions:177 _polyself _polyuse _port_help _pos_to_room _positionbar _possible_places _possibly_unwield _potionbreathe functions:178 _potionhit _prayer_done _precheck _prev_level _pri_move _price_quote _priest_talk _priestini functions:179 _priestname _print_branch _print_dungeon _print_queue _prinv _probe_monster _process_menu_window _process_text_window functions:180 _pronoun_gender _protects _prscore _punish _pushch _put_monsters_to_sleep _putsyms functions:181 _qt_montype _qt_pager _query_category _query_classes _query_objlist _quest_chat _quest_info functions:182 _quest_stat_check _quest_talk _random_dir _random_engraving _random_teleport_level _ranged_attk functions:183 _rank _rank_of _raw_printf _read_config_file _read_engr_at _readchar _readentry functions:184 _readmail _readobjnam _ReadPlanarTileFile _ReadPlanarTileFile_O _ReadTileFileHeader _reassign _recalc_wt _recharge functions:185 _record_exists _redist_attr _redotoplin _regularize _rehumanize _rejectoption _relink_light_sources _relink_timers functions:186 _relmon _remember_topl _remove_damage _remove_object _remove_rect _remove_timer _remove_worm functions:187 _removetopl _reorder_invent _repair_damage _replmon _replshk _rescham functions:188 _reset_eat _reset_faint _reset_hostility _reset_occupations _reset_pick _reset_remarm _reset_rndmonst _reset_trapset functions:189 _resetobjs _resist _resists_blnd _resists_drli _resists_magm _rest_engravings _rest_room _rest_rooms functions:190 _rest_worm _restartcham _restdamage _restfakecorr _restgamestate _restlevchn _restlevelfile _restlevelstate functions:191 _restmonchn _restnames _restobjchn _restore_artifacts _restore_attrib _restore_dungeon _restore_light_sources _restore_oracles functions:192 _restore_saved_game _restore_timers _restore_waterlevel _restpriest _restrap _restrict_name _restshk _resurrect functions:193 _reverse _revive _revive_corpse _revive_egg _revive_mon _revive_nasty _reward_untrap _rhack functions:194 _right_side _rile_shk _Ring_gone _Ring_off _Ring_off_or_gone _Ring_on _rloc _rloc_engr functions:195 _rloc_pos_ok _rloc_to _rloco _rm_waslit _rnd_class _rnd_defensive_item functions:196 _rnd_misc_item _rnd_offensive_item _rnd_rect _rndcurse _rnddoor _rndexp _rndghostname _rndmonnam functions:197 _rndmonnum _rndmonst _rndtrap _rne _rnl _rnz _rogue_vision _roguecorr functions:198 _roguejoin _roguename _rot_corpse _rot_organic _rottenfood _rounddiv _row_refresh _run_timers functions:199 _rust_dmg _s_suffix _safe_teleds _saleable _same_price _sanity_check _save_artifacts _save_currentstate functions:200 _save_dungeon _save_engravings _save_light_sources _save_oracles _save_room _save_rooms _save_savefile_name _save_timers functions:201 _save_waterlevel _save_worm _savebones _savech _savedamage _saveDiskPrompt _savefruitchn _savegamestate functions:202 _savelev _savelev0 _savelevchn _savelife _savemonchn _savenames _saveobjchn _savestateinlock functions:203 _savetrapchn _scatter _schedule_goto _score_wanted _search_door _search_special _searches_for_item _see_lamp_flicker functions:204 _see_monsters _see_objects _see_traps _see_wsegs _seemimic _seetrap _seffects _select_hwep functions:205 _select_off _select_rwep _selftouch _sellobj _sellobj_state _sengr_at _sense_trap functions:206 _set_all_on_page _set_apparxy _set_artifact_intrinsic _set_bc _set_bonesfile_name _set_bonestemp_name _set_corn _set_cost functions:207 _set_crosswall _set_entity _set_item_state _set_itimeout _set_levelfile_name _set_lit _set_lock_and_bones _set_malign functions:208 _set_mimic_blocking _set_mimic_sym _set_mon_data _set_moreluck _set_occupation _set_repo_loc _set_residency _set_savefile_name functions:209 _set_seenv _set_trap _set_twall _set_uasmon _set_wall _set_wall_property _set_wall_state _set_wear functions:210 _set_wounded_legs _set_wportal _setclipped _setftty _setgemprobs _setmangry _setnotworn _setpaid functions:211 _setrandom _settrack _settty _setup_waterlevel _setuwep _setworn _sgn _Shield_off functions:212 _shieldeff _ship_object _shk_chat _shk_embellish _shk_move _shk_names_obj _shk_owns _shk_your functions:213 _Shk_Your _shkcatch _shkgone _shkinit _shkname _sho_obj_return_to_u _shop_debt _shop_keeper functions:214 _shop_object _shopdig _shopper_financial_report _shrine_pos _shrink_worm _shuffle functions:215 _shuffle_all _shuffle_tiles _simple_look _singular _sitoa _skill_advance _skill_init _skill_level_name functions:216 _skinback _sleep_monst _slept_monst _slip_or_trip _sliparm _slots_required _snuff_candle _snuff_light_source functions:217 _snuff_lit _sobj_at _some_armor _somegold _somex _somexy _somey _sort_rooms functions:218 _sort_valuables _sp_lev_shuffle _spec_ability _spec_abon _spec_applies _spec_dbon _spell_damage_bonus _spell_hit_bonus functions:219 _spell_skilltype _spelleffects _spitmu _splatter_burning_oil _split_mon _split_rects _splitbill _splitobj functions:220 _spoteffects _squadmon _srandom _stackobj _standoutbeg _standoutend _start_corpse_timeout _start_eating functions:221 _start_engulf _start_timer _start_tin _steal _steal_it _stealamulet _stealarm _stealgold functions:223 _stop_timer _store_version _strange_feeling _strategy _string_for_env_opt _string_for_opt _strncmpi _strprepend functions:224 _strstri _study_book _stumble_onto_mimic _sub_one_frombill _subfrombill _substitute_tiles _summon_minion _surface functions:225 _swallow_to_glyph _swapin_file _swapout_oldest _switchar _t_warn functions:226 _tabexpand _tactics _take_gold _take_off _tamedog _target_on _tele _tele_jump_ok functions:227 _tele_restrict _tele_trap _teleds _teleok _teleport_pet _temple_occupied _tended_shop _term_end_attr functions:228 _term_end_color functions:229 _The _this_type_only _thitm _thitmonst _thitu _throw_gold _throwing_weapon _throwit functions:230 _thrwmu _tileview _timed_occupation _timer_is_local _timer_sanity_check _tinnable _title_to_mon _tmp_at functions:231 _topl_putsym _topologize _topten _topten_print _topten_print_bold _toss_up _toss_wsegs _touch_artifact functions:232 _touchfood _trap_detect _trickery _try_disarm _try_lift _trycall _tt_oname _tty_add_menu functions:233 _tty_askname _tty_clear_nhwindow _tty_cliparound functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _tty_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event functions:235 _tty_getlin _tty_init_nhwindows _tty_mark_synch _tty_message_menu _tty_nh_poskey _tty_nhbell _tty_nhgetch _tty_number_pad functions:236 _tty_player_selection _tty_raw_print _tty_raw_print_bold _tty_resume_nhwindows _tty_select_menu functions:237 _tty_start_menu _tty_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function functions:238 _txt_backsp _txt_cl_end _txt_cl_eos _txt_clear_screen _txt_get_scr_size _txt_monoadapt_check functions:239 _txt_nhbell _txt_startup _u_entered_shop _u_gname _u_init functions:240 _u_left_shop _u_on_dnstairs _u_on_newpos _u_on_sstairs _u_on_upstairs _u_slip_free _u_slow_down _u_teleport_mon functions:241 _u_to_e _u_wipe_engr _ugolemeffects _um_dist _unbless _unblock_point _uncommon functions:242 _unconscious _uncurse _undead_to_corpse _under_ground _under_water _undiscover_object _unearth_objs _unfaint functions:243 _unleash_all _unload_qtlist _unlock_file _unmap_object _unmul _unpaid_cost _unplacebc _unpunish functions:244 _unrestrict_weapon_skill _unset_all_on_page _unsetup_waterlevel _unstuck _untrap _untrap_prob _unturn_dead _update_mon_intrinsics functions:245 _update_topl _uptodate _urustm _use_bell _use_camera _use_candelabrum _use_candle _use_container functions:246 _use_crystal_ball _use_defensive _use_figurine _use_grease _use_lamp _use_leash _use_magic_whistle _use_mirror functions:247 _use_misc _use_offensive _use_pick_axe _use_skill _use_stethoscope _use_tinning_kit _use_towel _use_trap functions:248 _use_unicorn_horn _use_whip _use_whistle _useup _useupall _useupf _ustatusline _uunstick functions:249 _uwepgone _vault_occupied _vault_tele _verbalize _vga_backsp _vga_cl_end _vga_cl_eos _vga_clear_screen functions:250 _vga_cliparound _vga_detect _vga_DisplayCell _vga_DisplayCell_O _vga_DrawCursor _vga_Finish _vga_FontPtrs _vga_get_scr_size functions:251 _vga_gotoloc _vga_HideCursor _vga_Init _vga_overview _vga_redrawmap _vga_refresh _vga_SetPalette _vga_SwitchMode functions:252 _vga_traditional _vga_tty_end_screen _vga_tty_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc functions:254 _vision_reset _dodiscovered _dodoor _dodown _dodrink _dodrop _doeat _doengrave functions:255 _wallification _wallify_map _wallify_vault _wantdoor _watch_on_duty _water_damage _water_friction functions:256 _water_prayer _weapon_dam_bonus _weapon_hit_bonus _weapon_type _wearing_armor _weffects _weight functions:257 _weight_cap functions:258 _whimper _wield_tool _wildmiss _win_tty_init _wipe_engr_at _wipeoff _wipeout_text functions:259 _wiz_detect _wiz_genesis _wiz_identify _wiz_level_tele _wiz_light_sources _wiz_map _wiz_show_seenv _wiz_show_vision functions:260 _wiz_show_wmodes _wiz_timeout_queue _wiz_where _wiz_wish _wizdead _worm_known _worm_move _worm_nomove functions:261 _wormgone _wormhitu _worn_wield_only _write_ls _writeentry _wrong_elem_type _x_monnam _xcrypt _xkilled _xlev_to_rank _xname _xprname functions:263 _xytod _yelp _yname _Yname2 _You _you_aggravate _You_cant _You_feel _you_have _You_hear _you_unwere _you_were _Your _zap_dig functions:265 _zap_hit _zap_over_floor _zap_updown _zapdir_to_glyph _zapnodir _zappable _zapyourself _zhitm _zhitu _put_lregion_here _role_init ; tuning ; this was 23 functions:266 _bp_to_obj ; the next two were 238 functions:268 _aggravate ; the following were 118 ;functions:269 ; the following were 261 ;functions:270 functions:271 _xputg functions:272 _xputs _xwaitforspace ; the following were 158 functions:273 _enermod _enlightenment ; the following was 214 ;functions:274 _enter_explore_mode ; the following were 26 functions:275 _bydoor functions:276 _calc_capacity _call_kops _calm_nymphs functions:277 _can_advance _can_be_hatched functions:278 _can_carry ; the following were 239 functions:279 _equipname functions:280 _txt_xputs ; the following were 80 functions:281 _enexto ;functions:282 functions:283 _enhance_weapon_skill ; the following were 165 functions:284 _okdoor functions:285 _omon_adj functions:286 _on_goal functions:287 _on_ground functions:288 _b_trapped functions:289 _on_locate functions:290 _on_msg ; the following were 182 functions:291 _y_monnam ; the following were 195 ;functions:293 ; the following were 225 functions:294 _erode_armor functions:295 _swallowed ; the following were 7 functions:298 _acurrstr ; the following were 17 functions:299 _attacktype functions:300 _attrcurse functions:301 _automiss functions:302 _autopick ; the following were 10 functions:303 _adj_abon functions:304 _adj_lev functions:305 _adjabil functions:306 _adjalign functions:307 _adjattrib ; was 53 functions:308 _display_monster functions:309 _error ; was 117 ;functions:310 functions:311 _is_ok_location ;functions:312 functions:313 _is_pure functions:314 _is_quest_artifact ; was 236 functions:316 _tty_putstr _tty_putsym ; was 81 functions:318 _escapes functions:319 _erase_menu_or_text functions:320 _eraseall ; tuning 2 ; was 269 functions:321 _weldmsg _were_change _were_summon functions:322 _where_name _which_armor _which_arti functions:325 _term_end_raw_bold functions:326 _term_start_attr ;functions:327 functions:328 _term_start_raw_bold functions:329 _terminate functions:330 _tgetch functions:331 _the functions:332 _m_monnam functions:333 _domagictrap _domindblast _domonability functions:334 _m_respond functions:335 _m_slips_free functions:336 _m_throw functions:337 _m_to_e functions:338 _m_unleash functions:339 _mpickstuff functions:340 _mplayer_talk functions:341 _mpoisons_subj functions:342 _mquaffmsg functions:343 _miss functions:344 _mreadmsg functions:345 _mrustm functions:346 _vomit _vomiting_dialogue functions:347 _wake_nearby functions:348 _wake_nearto functions:349 _wakeup functions:350 _walkfrom functions:351 _wall_angle functions:352 _able_to_loot _add_mon_to_reg _add_rect_to_reg _add_region _addinv_core1 functions:352 _addinv_core2 _age_spells _align_gtitle _align_shift _align_str _all_but_uchain functions:353 _allow_all _allow_category _already_wearing _already_wearing2 _angrygods functions:354 _animate_statue _antholemon _arti_speak _assign_warnings _attach_fig_transform_timeout _blocked_boulder functions:355 _book_substitution _burn_away_slime _can_blnd _can_ride _can_saddle _can_twoweapon functions:356 _carry_obj_effects _clear_regions _container_at _coyotename _create_gas_cloud _create_region functions:357 _describe_level _dfeature_at _dig_up_grave _discover_artifact _dismount_steed _disp_artifact_discoveries functions:359 _doconduct _dofire _doprinuse _doride _doswapweapon _dotwoweapon functions:360 _dowieldquiver _drain_item _exercise_steed _expire_gas_cloud _extcmd_via_menu _feature_alert_opts functions:361 _fig_transform _figurine_location_checks _final_level _find_trap _finish_quest _fix_petrification functions:362 _food_substitution _fqname _free_invbuf _free_region _free_youbuf _freeinv_core functions:363 _fuzzymatch _get_compopt_value _get_current_feature_ver _get_feature_notice_ver _get_mtraits _getlev functions:364 _getlock _getobj _getpos _give_may_advance_msg _Goodbye _halu_gname functions:365 _Hello _hurtle_step _hurtmarmor _in_out_region _initialspell _inside_gas_cloud functions:366 _inside_rect _inside_region _kick_steed _look_here _m_in_out_region _make_grave functions:367 _mbodypart _mdamagem _mdamageu _mk_mplayer_armor _mm_aggression functions:368 _mon_adjust_speed _mon_animal_list _mon_beside _mon_in_region _montraits _mount_steed functions:369 _noit_mon_nam _noit_Monnam _noncoalignment _num_genocides _obj_attach_mid _obj_timer_checks functions:370 _obj_typename _ok_align _ok_gend _ok_race _ok_role _ordin functions:371 _pick_align _pick_animal _pick_gend _pick_nasty _pick_race _pick_role functions:372 _place_monster _pm_to_cham _prisoner_speaks _process_options _randalign _randgend functions:373 _randrace _randrole _relobj _remove_mon_from_reg _remove_region functions:374 _remove_worn_item _replace_object _reset_oattached_mids _rest_regions _restore_cham _rnd_treefruit_at functions:375 _save_regions _select_newcham_form _self_invis_message _setuqwep _setuswapwep _show_conduct functions:376 _show_region _simple_typename _slime_dialogue _sokoban_detect _spec_m2 _special_handling functions:377 _str2align _str2gend _str2race _str2role _There _throw_obj functions:378 _tmiss _tty_update_positionbar _tty_wait_synch _undiscovered_artifact _untwoweapon _update_mlstmv functions:379 _update_monster_region _update_player_regions _uqwepgone _ureflects _use_grapple _use_pole functions:380 _use_saddle _uswapwepgone _uwep_skill_type _validalign _validgend _validrace functions:381 _validrole _violated_vegetarian _walk_path _warning_opts _wary_dog _welcome functions:382 _write_timer _yyyymmdd _zap_steed functions:383 _getprice _getreturn _getrumor _gettrack functions:384 _ini_inv _knows_object _knows_class _restricted_spell_discipline _ready_weapon functions:385 _doname _Doname2 functions:386 _minliquid functions:387 _missmm functions:388 _missmu functions:389 _missum functions:390 _mixtype _mk_artifact functions:391 _makesingular functions:392 _maketrap _makevtele _makewish ; ; added but not tuned whatsoever ; functions:393 _abil_to_adtyp _abil_to_spfx _accept_menu_prefix _accept_newcham_form _accessory_has_effect _add_autopickup_exception functions:394 _add_class _add_erosion_words _adj_pit_checks _after_shk_move _alter_cost _ansimpleoname _anything_to_s functions:395 _arti_cost _arti_immune _arti_light_description _arti_light_radius _arti_reflects _artifact_has_invprop _artifact_light _artifact_score functions:396 _assign_hilite _attacktype_fordmg _attk_protection _attributes_enlightenment _attrval _authorize_wizard_mode _background_enlightenment functions:397 _bagotricks _bane_applies _bare_artifactname _billable _blackout _bogon_is_pname _book_disappears _bottlename functions:398 _bounded_increase _br_string2 _breakchestlock _build_english_list _bypass_obj functions:399 _buried_ball _buried_ball_to_freedom _buried_ball_to_punishment functions:400 _cad _can_be_strangled _can_blow _can_fog _can_reach_location _cant_reach_floor _cant_revive _cant_squeeze_thru _cant_wield_corpse _cantvomit functions:401 _cast_cleric_spell _cast_wizard_spell _catch_lit _cause_known _characteristics_enlightenment functions:402 _check_caitiff _check_innate_abil _check_strangling _choose_clerical_spell _choose_magic_spell _chrcasecpy functions:403 _ckvalidcat _clear_bypasses _clear_conjoined_pits _clear_status_hilites _clear_symsetentry _climb_pit _cloak_simple_name _closeholdingtrap functions:404 _clridx_to_s _cmap_to_type _cmd_from_func _compare_blstats _complain_about_duplicate _confers_luck _confused_book functions:405 _conjoined_pits _consume_obj_charge _consume_oeaten _consume_tin _container_gone _container_impact_dmg _copy_mextra _copy_oextra _copy_of ;functions:406 _copynchars _copyright_banner_line _corpse_revive_type _costly_alteration _costly_tin _could_advance _could_reach_item _count_ape_maps ;functions:407 _count_buc _count_contents _critically_low_hp _cures_sliming _cures_stoning _currency _cxname _dealloc_killer functions:408 _dealloc_mextra _dealloc_monst _dealloc_oextra functions:409 _decal_planar _decide_to_shapeshift _def_bclose _def_bflush _def_bufoff _def_bufon _def_bwrite _def_minit _def_mread functions:410 _defends_when_carried _delayed_killer _deliver_splev_message _detect_obj_traps _detect_wsegs _detecting functions:411 _disarm_holdingtrap _discardexcess _disintegrate_mon _display_pickinv _display_used_invlets _distant_monnam _dmgtype_fromattack _do_class_genocide functions:412 _docallcmd _dochat _doclassdisco _docontact _dogaze _domonnoise _donamelevel _doorless_door _dooverview _dooverview_or_wiz_where functions:413 _dopoly _doterrain _dotip _dotravel _dovanquished _dowhatdoes_core _drop_uswapwep _dxdy_moveok _eat_brains _eatmupdate functions:414 _edibility_prompts _encglyph _endmultishot _enexto_core _engulf_target _enlght_halfdmg _erode_obj _explain_container_prompt _extremeattr functions:415 _find_delayed_killer _find_file _find_mapseen _findtravelpath _finesse_ahriman _finish_meating _fire_damage functions:416 _flashburn _float_vs_flight _fopen_sym_file _fopen_wizkit_file _force_launch_placement _forget _forget_mapseen _forget_single_object _forget_temple_entry functions:417 _free_epri _free_mname _free_msghistory_snapshot _free_omailcmd _free_omid _free_omonst _free_oname _freemcorpsenm functions:418 _from_what _fruitname _gain_guardian_angel _gcrownu _genl_can_suspend_yes _genl_preference_update _genl_putmixed _genl_status_enablefield _genl_status_finish functions:419 _genl_status_init _genl_status_threshold _genl_status_update _genus functions:420 _get_adjacent_loc _get_container_location _get_plname_from_file _get_status_hilites _getlt _getmattk _getnow _getpos_help functions:421 _green_mon _gulp_blnd_check _H2Opotion_dip _has_ceiling _helm_simple_name _help_dir _hhmmss _hide_monst _hideunder _hits_bars functions:422 _hornoplenty _howmonseen _in_town _inaccessible_equipment _inhistemple functions:423 _init_blstats _init_l_symbols _init_mapseen _init_r_symbols _init_showsyms _init_symbols _initoptions_finish _initoptions_init functions:424 _innately _insane_object _insert_gold_into_invent _interest_mapseen _intersect functions:425 _is_autopickup_exception _is_digging _is_innate _is_izchak _is_rottable _is_undirected_spell _is_unpaid _is_wc_option _is_wc2_option _isspecmon functions:426 _joust _keep_saddle_with_steedcorpse _killer_xname _label_known _landing_spot _launch_in_progress functions:427 _learn_unseen_invent _learnring _learnscroll _learnscrolltyp _learnwand functions:428 _lib_dlb_cleanup _lib_dlb_fclose _lib_dlb_fgetc _lib_dlb_fgets _lib_dlb_fopen _lib_dlb_fread _lib_dlb_fseek _lib_dlb_ftell _lib_dlb_init functions:429 _light_hits_gremlin _lightdamage _liquid_flow _load_mapseen _load_symset _long_to_any _loot_mon _lose_guardian_angel _m_bad_boulder_spot _m_useupall functions:430 _magic_negation _make_glyphs_vanilla _make_happy_shoppers _make_slimed _make_stoned _mapglyph _match_sym functions:431 _maybe_absorb_item _maybe_adjust_light _maybe_cannibal _maybe_finish_sokoban _maybe_finished_meal _maybe_mnexto _maybe_tame _maybewakesteed functions:432 _Mb_hit _mbag_item_gone _mbirth_limit _mcould_eat_tin _mdisplacem _mdrop_obj _mdrop_special_objs _meatmetal _melt_ice_away functions:433 _mhurtle _mhurtle_step _mimic_hit_msg _mimic_obj_name _mk_gen_ok _mkclass_poly _mkveggy_at _mm_displacement functions:434 _mon_aligntyp _mon_consume_unstone _mon_hates_silver _mon_in_room _mon_is_gecko _mon_obj_sanity _monflee functions:435 _mongrantswish _monhaskey _monhp_per_lvl _monst_to_any _monster_census _msghistory_snapshot functions:436 _mshot_xname _munslime _muse_unslime _mwelded _mwepgone _name_to_monclass _new_book_description _new_mname functions:437 _new_omailcmd _new_oname _newedog _newegd _newemin _newepri _neweshk _newmcorpsenm functions:438 _newmextra _newmonhp _newoextra _newolong _newomid _newomonst functions:439 _newpw _nextmbuf _nextobuf _nh_compress _nh_uncompress _noarmor _num_horns functions:440 _nxtobj _o_material _obj_adjust_light_radius _obj_has_timer _obj_no_longer_held _obj_shuffle_range _obj_to_any _objlist_sanity _objtyp_is_callable functions:441 _observe_quantum_cat _oclass_to_name _odds_and_ends _ok_to_throw _olfaction _on_fire _one_characteristic functions:442 _openfallingtrap _openholdingtrap _otense _p_glow1 _p_glow2 ;functions:443 _paniclog _paralyze_monst _paranoid_query _parse_sym_line _parsesymbols _passes_bars _passive_obj _peaked_skill _peek_timer _percentage ;functions:444 _pick_pick _pickvampshape _pit_flow _pooleffects _popch _Popeye _postadjabil _print_mapseen _propagate _put_gold_back functions:445 _putting_on _qtext_pronoun _quickmimic _race_alignmentcount _raceptr _racial_exception functions:446 _randomize _read_sym_file _read_wizkit _readlibdir _really_kick_object _recalc_mapseen _recbranch_mapseen _redraw_cmd functions:447 _release_hero _releaseobuf _remdun_mapseen _remote_burglary functions:448 _remove_autopickup_exception _remove_gold_from_invent _remove_room _remove_rooms functions:449 _rename_disco _reset_commands _reset_region_mids _reset_restpref functions:450 _rest_levl _restmon _restobj _restore_killers _restore_msghistory _time_from_yyyymmddhhmmss functions:451 _retouch_equipment _retouch_object _reveal_terrain _reverse_loot _rider_cant_reach _rider_corpse_revival functions:452 _rndcolor functions:453 _rob_shop _role_gendercount _role_menu_extra _role_selection_prolog _root_plselection_prompt _rouse_shk _rumor_check functions:454 _s_to_anything _safe_oname _safe_qbuf _safeq_shortxprname _safeq_xprname _same_race functions:455 _sanitize_engravings _sanitize_name _save_killers _save_mapseen _save_msghistory _savelevl _savemon _saveobj functions:456 _scrolltele _seen_string _self_lookat _set_corpsenm _set_option_mod_status _set_playmode _set_restpref _set_status_hilites _set_symhandling functions:457 _set_tin_variety _setapplyclasses _setmnotwielded _setrolefilter _shade_aware _shade_glare _Shield_on _Shirt_off _Shirt_on functions:458 _shkname_is_pname _shkveg _shop_string _short_oname _should_displace _should_query_disclose_option _silly_thing _simpleonames functions:459 _singplur_compound _singplur_lookup _sink_into_lava _size_monst _size_obj _skip_pager _skiprange _sokoban_guilt functions:460 _sortspells _special_stock _spell_backfire _spell_cmp _spell_would_be_useless _spellretention _spellsortmenu _splittable functions:461 _spot_stop_timers _spot_time_expires _spot_time_left _stagger _start_melt_ice_timeout functions:462 _status_enlightenment _status_finish _status_hilite_menu _status_initialize _steedintrap _Sting_effects _stone_to_flesh_obj functions:463 _store_plname_in_file _store_savefileinfo _strcasecpy _stripspe _strkitten _strsubst _stuck_ring _stucksteed functions:464 _stuff_prevents_passage _suit_simple_name _switch_symbols _switch_terrain _sym_val _sys_early_init functions:465 _sysopt_seduce_set _taking_off _test_move _the_unique_obj _the_unique_pm _theft_petrifies _thesimpleoname functions:466 _tin_details _tin_variety _tin_variety_txt _tipcontainer _Tobjnam _toggle_displacement _toggle_stealth functions:467 _traditional_loot _trapmove _trapnote ;functions:468 _tty_destroy_nhwindow _tty_getmsghistory _tty_putmsghistory ;functions:469 _u_on_rndspot _ubreatheu _uchangealign _unchanger _undesirable_disp _unfixable_trouble_count _unplaced_floater _unreachable_level functions:470 _unset_seenv _untouchable _update_l_symset _update_r_symset _upstart _use_cream_pie _use_pick_axe2 _use_stone functions:471 _usmellmon _uteetering_at_seen_pit _validate _validate_prefix_locations _validspecmon _validvamp _vamp_shift functions:472 _vault_gd_watching _veggy_item _version_string _vtense _walking_on_water _wand_explode _watch_dig functions:473 _waterbody_name _wc_set_font_name _wc_set_window_colors _wc_supported _wc2_supported _weapon_descr functions:474 _wearslot _were_beastie _what_gives _wielding_corpse _will_feel_cockatrice _wishcmdassist _wishymatch functions:475 _wiz_level_change _wiz_levltyp_legend _wiz_map_levltyp _wiz_mon_polycontrol _wiz_panic _wiz_polyself _wiz_rumor_check _wiz_smell _wizkit_addinv functions:476 _worm_cross _worst_cursed_item _xdrainenergym _yn_function _yobjnam functions:477 _Yobjnam2 _You_see _ysimple_name _Ysimple_name2 _yyyymmddhhmmss functions:478 _zapsetup _zapwrapup _comp_times _directionname _fname_decode _fname_encode _free_autopickup_exceptions ;functions:479 _free_edog _free_egd _free_emin _free_eshk _free_olong _free_saved_games ;functions:480 _genl_can_suspend_no _genl_getmsghistory _genl_message_menu _genl_putmsghistory ;functions:481 _get_saved_games _initstate _set_savepref _set_wc_option_mod_status _set_wc2_option_mod_status _setstate _uint_to_any nethack-3.6.0/sys/msdos/moveinit.pat0000664000076400007660000000221712467321052016444 0ustar paxedpaxed These are patches for MOVEINIT.C, supplied with the MSVC compiler in the compiler's SOURCE\MOVE subdirectory. (Copy that and the MOVEAPI.H file into your NetHack src directory and apply this patch) *** ../linc/src/moveinit.c Tue Nov 23 08:01:00 1993 --- src/moveinit.c Sun Mar 13 10:13:10 1994 *************** *** 13,18 **** --- 13,19 ---- *******************************************************************************/ #include "moveapi.h" + extern unsigned memavail(unsigned); #ifndef MOVE_ENV *************** *** 125,132 **** /* attempt to allocate the overlay heap. ignore return value (heap size). * note that MOVE will abort if not enough memory to alloc minimum size. */ ! ! _movesetheap ($$COVL, cparaLarge, cparaMax); /* get available cache ressource amount */ --- 126,133 ---- /* attempt to allocate the overlay heap. ignore return value (heap size). * note that MOVE will abort if not enough memory to alloc minimum size. */ ! cparaMax = memavail(cparaMin); ! _movesetheap ($$COVL, cparaMin, cparaMax); /* get available cache ressource amount */ nethack-3.6.0/sys/msdos/msdos.c0000664000076400007660000003175412536476415015420 0ustar paxedpaxed/* NetHack 3.6 msdos.c $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack PC Development Team 1990 */ /* NetHack may be freely redistributed. See license for details. */ /* * MSDOS system functions. * Many thanks to Don Kneller who originated the DOS port and * contributed much to the cause. */ #define NEED_VARARGS #include "hack.h" #ifdef MSDOS #include "pcvideo.h" #include #include /* * MS-DOS functions */ #define DIRECT_INPUT 0x07 /* Unfiltered Character Input Without Echo */ #define FATINFO 0x1B /* Get Default Drive Data */ /* MS-DOS 2.0+: */ #define GETDTA 0x2F /* Get DTA Address */ #define FREESPACE 0x36 /* Get Drive Allocation Info */ #define GETSWITCHAR 0x3700 /* Get Switch Character */ #define FINDFIRST 0x4E /* Find First File */ #define FINDNEXT 0x4F /* Find Next File */ #define SETFILETIME 0x5701 /* Set File Date & Time */ /* * BIOS interrupts */ #ifdef PC9800 #define KEYBRD_BIOS 0x18 #else #define KEYBRD_BIOS 0x16 #endif /* * Keyboard BIOS functions */ #define READCHAR 0x00 /* Read Character from Keyboard */ #define GETKEYFLAGS 0x02 /* Get Keyboard Flags */ /*#define KEY_DEBUG */ /* print values of unexpected key codes - devel*/ void FDECL(get_cursor, (int *, int *)); /* direct bios calls are used only when iflags.BIOS is set */ STATIC_DCL char NDECL(DOSgetch); STATIC_DCL char NDECL(BIOSgetch); #ifndef __GO32__ STATIC_DCL char *NDECL(getdta); #endif STATIC_DCL unsigned int FDECL(dos_ioctl, (int, int, unsigned)); #ifdef USE_TILES extern boolean FDECL(pckeys, (unsigned char, unsigned char)); /* pckeys.c */ #endif int tgetch() { char ch; /* BIOSgetch can use the numeric key pad on IBM compatibles. */ #ifdef SIMULATE_CURSOR if (iflags.grmode && cursor_flag) DrawCursor(); #endif if (iflags.BIOS) ch = BIOSgetch(); else ch = DOSgetch(); #ifdef SIMULATE_CURSOR if (iflags.grmode && cursor_flag) HideCursor(); #endif return ((ch == '\r') ? '\n' : ch); } /* * Keyboard translation tables. */ #ifdef PC9800 #define KEYPADLO 0x38 #define KEYPADHI 0x50 #else #define KEYPADLO 0x47 #define KEYPADHI 0x53 #endif #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { #ifdef PC9800 { '>', '>', '>' }, /* Ins */ { '<', '<', '<' }, /* Del */ { 'k', 'K', C('k') }, /* Up */ { 'h', 'H', C('h') }, /* Left */ { 'l', 'L', C('l') }, /* Right */ { 'j', 'J', C('j') }, /* Down */ { 0, 0, 0 }, /* HomeClr */ { '?', '?', '?' }, /* Help */ { 'm', C('p'), C('p') }, /* - */ { '/', '/', '/' }, /* / */ { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { '*', '*', '*' }, /* * */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'g', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { 'p', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { '=', '=', '=' }, /* = */ { 'i', 'I', C('i') }, /* 0 */ { ',', ':', ':' }, /* , */ { '.', '.', '.' } /* . */ #else { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'g', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { 'p', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ #endif }, numpad[PADKEYS] = { #ifdef PC9800 { '>', '>', '>' }, /* Ins */ { '<', '<', '<' }, /* Del */ { '8', M('8'), '8' }, /* Up */ { '4', M('4'), '4' }, /* Left */ { '6', M('6'), '6' }, /* Right */ { '2', M('2'), '2' }, /* Down */ { 0, 0, 0 }, /* HomeClr */ { '?', '?', '?' }, /* Help */ { 'm', C('p'), C('p') }, /* - */ { '/', '/', '/' }, /* / */ { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { '*', '*', '*' }, /* * */ { '4', M('4'), '4' }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { 'p', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { '=', '=', '=' }, /* = */ { 'i', 'I', C('i') }, /* 0 */ { ',', ':', ':' }, /* , */ { '.', '.', '.' } /* . */ #else { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { '5', M('5'), '5' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { 'p', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { '0', M('0'), '0' }, /* Ins */ { '.', ':', ':' } /* Del */ #endif }; /* * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII * meaning unless assigned one by a keyboard conversion table, so the * keyboard BIOS normally does not return a character code when Alt-letter * is pressed. So, to interpret unassigned Alt-letters, we must use a * scan code table to translate the scan code into a letter, then set the * "meta" bit for it. -3. */ #ifdef PC9800 #define SCANLO 0x5 #else #define SCANLO 0x10 #endif /* PC9800 */ static const char scanmap[] = { /* ... */ #ifdef PC9800 0, 0, 0, 0, 0, 0, '-', '^', '\\', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '@', '[', '\n', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', ':', ']', 'z', 'x', 'c', 'v', 'b', 'N', 'm', ',', '.', '/' /* ... */ #else 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '?' /* ... */ #endif /* PC9800 */ }; #define inmap(x) (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap)) #ifdef NEW_ALT #define NUMERIC_SCANLO 0x78 static const char numeric_scanmap[] = { /* ... */ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=' }; #define in_numericmap(x) \ (NUMERIC_SCANLO <= (x) && (x) < NUMERIC_SCANLO + SIZE(numeric_scanmap)) #endif /* * BIOSgetch gets keys directly with a BIOS call. */ #ifdef PC9800 #define SHIFT 0x1 #define KANA 0x4 #define GRPH 0x8 #define CTRL 0x10 #else #define SHIFT (0x1 | 0x2) #define CTRL 0x4 #define ALT 0x8 #endif /* PC9800 */ STATIC_OVL char BIOSgetch() { unsigned char scan, shift, ch = 0; const struct pad *kpad; union REGS regs; do { /* Get scan code. */ regs.h.ah = READCHAR; int86(KEYBRD_BIOS, ®s, ®s); ch = regs.h.al; scan = regs.h.ah; /* Get shift status. */ regs.h.ah = GETKEYFLAGS; int86(KEYBRD_BIOS, ®s, ®s); shift = regs.h.al; /* Translate keypad keys */ if (iskeypad(scan)) { kpad = iflags.num_pad ? numpad : keypad; if (shift & SHIFT) ch = kpad[scan - KEYPADLO].shift; else if (shift & CTRL) ch = kpad[scan - KEYPADLO].cntrl; else ch = kpad[scan - KEYPADLO].normal; } #ifdef USE_TILES /* Check for special interface manipulation keys */ if (pckeys(scan, shift)) { ch = 0xFF; continue; } #endif /* Translate unassigned Alt-letters */ #ifdef PC9800 if (shift & KANA) return 0; if ((shift & GRPH) && (ch >= 0x80)) { #else if ((shift & ALT) && !ch) { #endif #if 0 pline("Scan code: %d 0x%03X", scan, scan); #endif if (inmap(scan)) ch = scanmap[scan - SCANLO]; #ifdef NEW_ALT else if (in_numericmap(scan)) ch = numeric_scanmap[scan - NUMERIC_SCANLO]; #endif return (isprint(ch) ? M(ch) : ch); } } while (ch == 0xFF); return ch; } STATIC_OVL char DOSgetch() { union REGS regs; char ch; struct pad(*kpad)[PADKEYS]; regs.h.ah = DIRECT_INPUT; intdos(®s, ®s); ch = regs.h.al; #ifdef PC9800 if (ch < 0) /* KANA letters and GRPH-shifted letters(?) */ ch = 0; /* munch it */ #else /* * The extended codes for Alt-shifted letters, and unshifted keypad * and function keys, correspond to the scan codes. So we can still * translate the unshifted cursor keys and Alt-letters. -3. */ if (ch == 0) { /* an extended key */ regs.h.ah = DIRECT_INPUT; intdos(®s, ®s); /* get the extended key code */ ch = regs.h.al; if (iskeypad(ch)) { /* unshifted keypad keys */ kpad = (void *) (iflags.num_pad ? numpad : keypad); ch = (*kpad)[ch - KEYPADLO].normal; } else if (inmap(ch)) { /* Alt-letters */ ch = scanmap[ch - SCANLO]; if (isprint(ch)) ch = M(ch); } else ch = 0; /* munch it */ } #endif return (ch); } char switchar() { union REGS regs; regs.x.ax = GETSWITCHAR; intdos(®s, ®s); return regs.h.dl; } long freediskspace(path) char *path; { union REGS regs; regs.h.ah = FREESPACE; if (path[0] && path[1] == ':') regs.h.dl = (toupper(path[0]) - 'A') + 1; else regs.h.dl = 0; intdos(®s, ®s); if (regs.x.ax == 0xFFFF) return -1L; /* bad drive number */ else return ((long) regs.x.bx * regs.x.cx * regs.x.ax); } #ifndef __GO32__ /* * Functions to get filenames using wildcards */ int findfirst_file(path) char *path; { union REGS regs; struct SREGS sregs; regs.h.ah = FINDFIRST; regs.x.cx = 0; /* attribute: normal files */ regs.x.dx = FP_OFF(path); sregs.ds = FP_SEG(path); intdosx(®s, ®s, &sregs); return !regs.x.cflag; } int findnext_file() { union REGS regs; regs.h.ah = FINDNEXT; intdos(®s, ®s); return !regs.x.cflag; } char * foundfile_buffer() { return (getdta() + 30); } /* Get disk transfer area */ STATIC_OVL char * getdta() { union REGS regs; struct SREGS sregs; char *ret; regs.h.ah = GETDTA; intdosx(®s, ®s, &sregs); #ifdef MK_FP ret = (char *) MK_FP(sregs.es, regs.x.bx); #else FP_OFF(ret) = regs.x.bx; FP_SEG(ret) = sregs.es; #endif return ret; } long filesize_nh(file) char *file; { char *dta; if (findfirst_file(file)) { dta = getdta(); return (*(long *) (dta + 26)); } else return -1L; } #endif /* __GO32__ */ /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { #define SELECTDISK 0x0E char *ptr; union REGS inregs; char drive; if ((ptr = index(str, ':')) != (char *) 0) { drive = toupper(*(ptr - 1)); inregs.h.ah = SELECTDISK; inregs.h.dl = drive - 'A'; intdos(&inregs, &inregs); } return; } /* Use the IOCTL DOS function call to change stdin and stdout to raw * mode. For stdin, this prevents MSDOS from trapping ^P, thus * freeing us of ^P toggling 'echo to printer'. * Thanks to Mark Zbikowski (markz@microsoft.UUCP). */ #define DEVICE 0x80 #define RAW 0x20 #define IOCTL 0x44 #define STDIN fileno(stdin) #define STDOUT fileno(stdout) #define GETBITS 0 #define SETBITS 1 static unsigned int old_stdin, old_stdout; void disable_ctrlP() { if (!iflags.rawio) return; old_stdin = dos_ioctl(STDIN, GETBITS, 0); old_stdout = dos_ioctl(STDOUT, GETBITS, 0); if (old_stdin & DEVICE) dos_ioctl(STDIN, SETBITS, old_stdin | RAW); if (old_stdout & DEVICE) dos_ioctl(STDOUT, SETBITS, old_stdout | RAW); return; } void enable_ctrlP() { if (!iflags.rawio) return; if (old_stdin) (void) dos_ioctl(STDIN, SETBITS, old_stdin); if (old_stdout) (void) dos_ioctl(STDOUT, SETBITS, old_stdout); return; } STATIC_OVL unsigned int dos_ioctl(handle, mode, setvalue) int handle, mode; unsigned setvalue; { union REGS regs; regs.h.ah = IOCTL; regs.h.al = mode; regs.x.bx = handle; regs.h.dl = setvalue; regs.h.dh = 0; /* Zero out dh */ intdos(®s, ®s); return (regs.x.dx); } #endif /* MSDOS */ nethack-3.6.0/sys/msdos/msdoshlp.txt0000664000076400007660000001632312536476415016514 0ustar paxedpaxed MSDOS specific help file for NetHack 3.6 (Last Revision: December 4, 1999) Copyright (c) NetHack PC Development Team 1993-1999. NetHack may be freely distributed. See license for details. New players should be sure to read GuideBoo.txt which contains essential information about playing NetHack. It can be found in the same directory as your NetHack executable. The MSDOS port of NetHack supports some additional or enhanced commands as well as some defaults.nh file options specific to configuration choices used during the building of PC NetHack. Listed below are those commands and defaults.nh file options. Recognized MSDOS specific defaults.nh entries are outlined below. Boolean Options: IBMgraphics Use IBM extended characters for the dungeon Default: [FALSE] BIOS Allow the use of IBM ROM BIOS calls Default: [FALSE] rawio Allow the use of raw I/O (may only be set on startup) Default: [FALSE] preload_tiles Preload tiles into RAM at start of game. Faster, but uses more memory. Default: [TRUE] Color Options: OPTIONS=!color Players will need this if they have a real, true, (old) monochrome adapter, and they are seeing underlined, and flashing, and reverse-video characters on the screen. Or they find that some things are missing from the display. This means that the auto-detection for monochromes has failed. The color support stuff is active in video.c, but may be (will have to be) overridden by adding an OPTIONS=nocolor to defaults.nh. OPTIONS=VIDEO (defaults.nh only) ie: OPTIONS=video:autodetect Possible values are: AUTODETECT, DEFAULT, VGA AUTODETECT Checks for a supported hi-res video adaptor, and if it detects one, NetHack will run in "TILE MODE." DEFAULT NetHack will run in TTY mode. This is the same as not specifying OPTIONS=VIDEO at all. VGA Forces use of VGA specific video routines. Any forcing of specific video routines has potential to cause machine lock-ups if the specified video hardware is not present. OPTIONS=VIDEOSHADES (defaults.nh only) Players may wish to add this option because one of their shades of gray is difficult to read on their video display hardware. Allows a level of intensity to be assigned to the 3 possible shades of gray in NetHack, those being BLACK, GRAY, WHITE. To each of those shades, the player may assign a DARK, NORMAL, or LIGHT value. Here is the default if not specified: ie. OPTIONS=VIDEOSHADES:dark-normal-light Anytime the same intensity value (DARK NORMAL LIGHT) is used for more than one shade of gray, it will not be possible to visually distinguish those two shades from each other. ie. OPTIONS=VIDEOSHADES:normal-normal-light This, while eliminating the dark shade normally used for displaying black items, means that the player won't be able to distinguish black items and creatures from gray items and creatures visually. Note also that the controversial gray schema used in pl 3.1.2 as the default, corresponded to: OPTIONS=VIDEOSHADES:normal-dark-normal This is NOT the default in pl 3.1.3 and above, so many people will probably not even need to use this option, and will find the default just fine. The maps are built using gray, and in pl 3.1.3, that is mapped to normal by default. In 3.1.2, it was mapped to dark (as above). OPTIONS=VIDEOCOLORS (defaults.nh only) This option is only provided because some people on r.g.r.n mentioned how they liked to modify the color values from the default ANSI.SYS behaviour, and were "upset" to find out that they could no longer do so under 3.1.2. The color map is as accurate as possible on standard PC video hardware as it stands, and any deviation from the default, will mean that people are mapping blue to green for example. The option is available to provide as much flexibility as possible, but it is not encouraged to be used. One possible use might be for the dark blue in fountains. On video hardware that has trouble displaying blacks, there may also be problems displaying the darker blue used in fountains. If that is the case then the default map: OPTIONS=VIDEOCOLORS:4-2-6-1-5-3-12-10-14-9-13-11 could be changed to the following to map blue to br. blue: OPTIONS=VIDEOCOLORS:4-2-6-9-5-3-12-10-14-9-13-11 The mapping order for the options: red, green, brown, blue, magenta, cyan br.red, br.green, yellow, br.blue, br.magenta, br.cyan The PC hardware uses the following values: red(4), green(2), brown(6), blue(1), magenta(5), cyan(3), bright red(12), bright green(10), yellow(14), bright blue(9), bright magenta(13), bright cyan(11), normal white(7), bright white(15). The following options are NOT currently recognized under the MSDOS port of PC NetHack: LEVELS= Where to store/create per level data files. SAVE= Where to save games. BONES= Where to store bones files. MSDOS Additional/Enhanced Commands: If you have opted to use the "graphical" or "tiled" option, (usually set via OPTIONS=VIDEO:AUTODETECT ((see above)), then the following function keys are active: F3 cycle through the current position indicator, or halo. Usually this halo highlights the player's tile, unless the game is asking you for an answer to a question that requires positional information, (ie, the discover command). F4 toggle level overview mode on/off F5 toggle tiled display on/off. (Switches between tiled and traditional ASCII display.) While playing NetHack under MSDOS you can press the ALT key in combination with another key to execute an extended command as an alternative method to pressing a # key sequence: Alt-2 twoweapon - toggle two-weapon combat Alt-a adjust - adjust inventory letters. Alt-c chat - talk to someone or something. Alt-d dip - dip an object into something. Alt-e enhance - enhance your skill with a weapon. Alt-f force - force a lock. Alt-i invoke - invoke an object's powers. Alt-j jump - jump to a location. Alt-l loot - loot a box on the floor. Alt-m monster - use a monster's special ability. Alt-n name - name an item or type of object. Alt-o offer - offer a sacrifice to the gods. Alt-p pray - pray to the gods for help. Alt-q quit - quit the game. (Same as #quit) Alt-r rub - rub a lamp. Alt-s sit - sit down. Alt-t turn - turn undead. Alt-u untrap - untrap something. Alt-v version - list compile time options for this version of NetHack. Alt-w wipe - wipe off your face. If you are playing on NEC PC-9800, use the GRPH key instead of the ALT key. nethack-3.6.0/sys/msdos/nhico.uu0000664000076400007660000000235712467321052015564 0ustar paxedpaxedsection 1 of uuencode 4.13 of file NETHACK.ICO by R.E.M. begin 644 NETHACK.ICO M```!``$`("`0``````#H`@``%@```"@````@````0`````$`!```````@`(`. M``````````````````````````````"```"`````@(``@````(``@`"`@```6 M@("``,#`P````/\``/\```#__P#_````_P#_`/__``#___\`]F9F9F9F9F9F* M9F9F9F9F9O]F9F9F9F9F9F9F9F9F9F;_B(B(B(B(B(B(B(B(B&9F_XB(B(B(D MB(B(B(B(B(AF9O^(B(B(A555B(B(B(B(9F;_B(B(B`!5!8B(B(B(B&9F_XB(' MB(@```6(B(B(B(AF9O^(B%554`!56(B(B(B(9F;_B(N[N[`.XU6(B(B(B&9F[ M_XB[N[L`ONXU6(B(B(AF9O^+N[N[N[ONXUB(B(B(9F;_B[N[N[N[ONY3B(B(N MB&9F_XN[NYF9F[ONXSB(B(AF9O^+N[F9F9F[ONXSB(B(9F;_B[N9F9F9F[ON? MXSB(B&9F_XNYF9F9F9F[7NXSB(AF9O^+N9F9F9F9NUCNXSB(9F;_B[F9F9F9J MF;M8CNXSB&9F_XNYF9F9F9F[6(CNXXAF9O^+N9F9F9F9NUB(CNZ(9F;_B[N9] MF9F9F[M8B(CNB&9F_XN[N9F9F;N[6(B(B(AF9O^+N[N9F9N[NUB(B(B(9F;_R MB[N[N[N[N[M8B(B(B&9F_XN[N[N[N[N[B(B(B(AF9O^+NXB(B(B+NXB(B(B(F M9F;_B[B(B(B(B+N(B(B(B&9F_XB(B(B(B(B(B(B(B(AF9O^(B(B(B(B(B(B(J MB(B(9F;_B(B(B(B(B(B(B(B(B&9F___________________V9O__________% M__________\`````````````````````````````````````````````````R M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` !````` `` end sum -r/size 23881/1107 section (from "begin" to "end") sum -r/size 55184/766 entire input file nethack-3.6.0/sys/msdos/nhpif.uu0000664000076400007660000000141612467321052015563 0ustar paxedpaxedbegin 666 nethack.pif M`%M00R!.971H86-K(#,N,2`@("`@("`@("`@("`@(""``(``0SI<3D542$%# M2UQ.151(04-++D5810`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@$`!#.EQ.151(04-+`"`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@```````````````````` M```````````````````````````````````````````````````````````` M```````!`/\94```!P`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````.`@34E#4D]33T94(%!)1D58`( #include #ifdef _MSC_VER #define RESERVED_PARAGRAPHS 5120 /* leave 80K for malloc and inits */ /* subject to change before release */ /* * memavail() Returns the amount of RAM available (in paragraphs which are 16 * bytes) - the amount to be reserved for heap allocations. * */ unsigned memavail(minovl) unsigned minovl; /* minimum size of overlay heap */ { unsigned available; unsigned farparaavail; unsigned tmp; /* * _dos_allocmem will return the maximum block size available. * It uses DOS (int 21h) service 0x48. */ _dos_allocmem(0xFFFF, &farparaavail); available = farparaavail - RESERVED_PARAGRAPHS; tmp = RESERVED_PARAGRAPHS + minovl; if (farparaavail < tmp) { panic("Not enough free RAM to begin a game of NetHack (%ld bytes)", (long) ((long) tmp * 16L)); } return available; } #endif /*_MSC_VER*/ #ifdef __BORLANDC__ #define RSRVD_MALLOC 65 * 1024L /* malloc() calls use about 65K */ #define RSRVD_CRTL 50 * 1024L /* C runtime library uses 50K */ #define RSRVD_TOTAL 115 * 1024L /* reserved for use in malloc() */ /* as well as by C runtime library */ /* routines which allocate memory */ /* after this routine runs. */ #define MIN_OVRBUF 30 * 1024L /* Overlay buffer gets minimum of */ #define MAX_OVRBUF 200 * 1024L /* 30K and maximum of 200K. */ #define RESIZE_OVL #ifdef RESIZE_OVL extern unsigned _ovrbuffer = 0; /* Use default size initially */ unsigned appFail = 0; /* Fail flag if not enough RAM */ unsigned memAlloc = 0; unsigned long ProgramSize; unsigned long runAlloc; unsigned far *mem_top; unsigned total; signed long tmpbuffer; int emsstatus; int xmsstatus; void NDECL(_resizeOvrBuffer); void _resizeOvrBuffer() { mem_top = (unsigned far *) MK_FP(_psp, 0x02); total = *mem_top - _psp; ProgramSize = *(unsigned far *) MK_FP(_psp - 1, 0x03); tmpbuffer = total - ProgramSize - RSRVD_TOTAL / 16; memAlloc = min(MAX_OVRBUF / 16, tmpbuffer); if (tmpbuffer >= MIN_OVRBUF / 16) _ovrbuffer = memAlloc; else { _ovrbuffer = 1; appFail = 1; }; /* * Remember, when inside this code, nothing has been setup on * the system, so do NOT call any RTL functions for I/O or * anything else that might rely on a startup function. This * includes accessing any global objects as their constructors * have not been called yet. */ } #pragma startup _resizeOvrBuffer 0 /* Put function in table */ void startup() { if (appFail) { printf("NetHack fits in memory, but it cannot allocate memory"); printf(" for the overlay buffer\nand the runtime functions. "); printf("Please free up just %ld more bytes.", (long) (MIN_OVRBUF - tmpbuffer * 16L)); exit(-1); } else { /* Now try to use expanded memory for the overlay manager */ /* If that doesn't work, we revert to extended memory */ emsstatus = _OvrInitEms(0, 0, 0); #ifdef RECOGNIZE_XMS xmsstatus = (emsstatus) ? _OvrInitExt(0, 0) : -1; #endif } } void show_borlandc_stats(win) winid win; { char buf[BUFSZ]; putstr(win, 0, ""); putstr(win, 0, ""); putstr(win, 0, "Memory usage stats"); putstr(win, 0, ""); putstr(win, 0, ""); Sprintf(buf, "Overlay buffer memory allocation: %ld bytes.", memAlloc * 16L); putstr(win, 0, buf); Sprintf(buf, "_ovrbuffer = %u.", _ovrbuffer); putstr(win, 0, buf); Sprintf(buf, "Startup memory usage: 0x%X", ProgramSize); putstr(win, 0, buf); runAlloc = *(unsigned far *) MK_FP(_psp - 1, 0x03); Sprintf(buf, "Current memory usage: 0x%X", runAlloc); putstr(win, 0, buf); if (emsstatus) Sprintf(buf, "EMS search failed (%d).", emsstatus); else Sprintf(buf, "EMS search successful."); putstr(win, 0, buf); #ifdef RECOGNIZE_XMS if (xmsstatus) Sprintf(buf, "XMS search failed (%d).", xmsstatus); else Sprintf(buf, "XMS search successful."); putstr(win, 0, buf); #endif } #endif /* #ifdef RESIZE_OVL */ #endif /* #ifdef __BORLANDC__ */ /*ovlinit.c*/ nethack-3.6.0/sys/msdos/pckeys.c0000664000076400007660000000422712536476415015564 0ustar paxedpaxed/* NetHack 3.6 pckeys.c $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) NetHack PC Development Team 1996 */ /* NetHack may be freely redistributed. See license for details. */ /* * MSDOS tile-specific key handling. */ #include "hack.h" #ifdef MSDOS #ifdef USE_TILES #include "wintty.h" #include "pcvideo.h" boolean FDECL(pckeys, (unsigned char, unsigned char)); extern struct WinDesc *wins[MAXWIN]; /* from wintty.c */ extern boolean inmap; /* from video.c */ #define SHIFT (0x1 | 0x2) #define CTRL 0x4 #define ALT 0x8 /* * Check for special interface manipulation keys. * Returns TRUE if the scan code triggered something. * */ boolean pckeys(scancode, shift) unsigned char scancode; unsigned char shift; { boolean opening_dialog; opening_dialog = pl_character[0] ? FALSE : TRUE; #ifdef SIMULATE_CURSOR switch (scancode) { case 0x3d: /* F3 = toggle cursor type */ HideCursor(); cursor_type += 1; if (cursor_type >= NUM_CURSOR_TYPES) cursor_type = 0; DrawCursor(); break; #endif case 0x74: /* Control-right_arrow = scroll horizontal to right */ if ((shift & CTRL) && iflags.tile_view && !opening_dialog) vga_userpan(1); break; case 0x73: /* Control-left_arrow = scroll horizontal to left */ if ((shift & CTRL) && iflags.tile_view && !opening_dialog) vga_userpan(0); break; case 0x3E: /* F4 = toggle overview mode */ if (iflags.tile_view && !opening_dialog && !Is_rogue_level(&u.uz)) { iflags.traditional_view = FALSE; vga_overview(iflags.over_view ? FALSE : TRUE); vga_refresh(); } break; case 0x3F: /* F5 = toggle traditional mode */ if (iflags.tile_view && !opening_dialog && !Is_rogue_level(&u.uz)) { iflags.over_view = FALSE; vga_traditional(iflags.traditional_view ? FALSE : TRUE); vga_refresh(); } break; default: return FALSE; } return TRUE; } #endif /* USE_TILES */ #endif /* MSDOS */ /*pckeys.c*/ nethack-3.6.0/sys/msdos/pctiles.c0000664000076400007660000001575212536476415015736 0ustar paxedpaxed/* NetHack 3.6 pctiles.c $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * pctiles.c - PC Graphical Tile Support Routines * *Edit History: * Initial Creation M. Allison 93/10/30 * */ #include "hack.h" #ifdef USE_TILES #if defined(__GO32__) || defined(__DJGPP__) #include #define TILES_IN_RAM /* allow tiles to be read into ram */ #endif #if defined(_MSC_VER) #if _MSC_VER >= 700 #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4131) /* old style declarator */ #pragma warning(disable : 4309) /* initializing */ #endif #include #endif #include "pcvideo.h" #include "tile.h" #include "pctiles.h" STATIC_VAR FILE *tilefile; STATIC_VAR FILE *tilefile_O; extern short glyph2tile[]; /* in tile.c (made from tilemap.c) */ #ifdef TILES_IN_RAM struct planar_cell_struct *ramtiles; struct overview_planar_cell_struct *oramtiles; boolean tiles_in_ram = FALSE; boolean otiles_in_ram = FALSE; extern int total_tiles_used; /* tile.c */ #endif /* * Read the header/palette information at the start of the * NetHack.tib file. * * There is 1024 bytes (1K) of header information * at the start of the file, including a palette. * */ int ReadTileFileHeader(tibhdr, filestyle) struct tibhdr_struct *tibhdr; boolean filestyle; { FILE *x; x = filestyle ? tilefile_O : tilefile; if (fseek(x, 0L, SEEK_SET)) { return 1; } else { fread(tibhdr, sizeof(struct tibhdr_struct), 1, x); } return 0; } /* * Open the requested tile file. * * NetHack1.tib file is a series of * 'struct planar_tile_struct' structures, one for each * glyph tile. * * NetHack2.tib file is a series of * char arrays [TILE_Y][TILE_X] in dimensions, one for each * glyph tile. * * There is 1024 bytes (1K) of header information * at the start of each .tib file. The first glyph tile starts at * location 1024. * */ int OpenTileFile(tilefilename, filestyle) char *tilefilename; boolean filestyle; { #ifdef TILES_IN_RAM int k; #endif if (filestyle) { tilefile_O = fopen(tilefilename, "rb"); if (tilefile_O == (FILE *) 0) return 1; } else { tilefile = fopen(tilefilename, "rb"); if (tilefile == (FILE *) 0) return 1; } #ifdef TILES_IN_RAM if (iflags.preload_tiles) { if (filestyle) { struct overview_planar_cell_struct *gp; long ram_needed = sizeof(struct overview_planar_cell_struct) * total_tiles_used; if (fseek(tilefile_O, (long) TIBHEADER_SIZE, SEEK_SET)) { /*failure*/ } oramtiles = (struct overview_planar_cell_struct *) alloc(ram_needed); /* Todo: fall back to file method here if alloc failed */ gp = oramtiles; for (k = 0; k < total_tiles_used; ++k) { fread(gp, sizeof(struct overview_planar_cell_struct), 1, tilefile_O); ++gp; } #ifdef DEBUG_RAMTILES pline("%d overview tiles read into ram.", k); mark_synch(); #endif otiles_in_ram = TRUE; } else { struct planar_cell_struct *gp; long ram_needed = sizeof(struct planar_cell_struct) * total_tiles_used; if (fseek(tilefile, (long) TIBHEADER_SIZE, SEEK_SET)) { /*failure*/ } ramtiles = (struct planar_cell_struct *) alloc(ram_needed); /* Todo: fall back to file method here if alloc failed */ gp = ramtiles; for (k = 0; k < total_tiles_used; ++k) { fread(gp, sizeof(struct planar_cell_struct), 1, tilefile); ++gp; } #ifdef DEBUG_RAMTILES pline("%d tiles read into ram.", k); mark_synch(); #endif tiles_in_ram = TRUE; } } #endif return 0; } void CloseTileFile(filestyle) boolean filestyle; { fclose(filestyle ? tilefile_O : tilefile); #ifdef TILES_IN_RAM if (!filestyle && tiles_in_ram) { if (ramtiles) free((genericptr_t) ramtiles); tiles_in_ram = FALSE; } else if (filestyle && otiles_in_ram) { if (oramtiles) free((genericptr_t) oramtiles); otiles_in_ram = FALSE; } #endif } struct planar_cell_struct plancell; struct overview_planar_cell_struct oplancell; /* This routine retrieves the requested NetHack glyph tile * from the planar style binary .tib file. * This is currently done 'on demand', so if the player * is running without a disk cache (ie. smartdrv) operating, * things can really be slowed down. We don't have any * base memory under MSDOS, in which to store the pictures. * * Todo: Investigate the possibility of loading the glyph * tiles into extended or expanded memory using * the MSC virtual memory routines. * * Under an environment like djgpp, it should be possible to * read the entire set of glyph tiles into a large * array of 'struct planar_cell_struct' structures at * game initialization time, and recall them from the array * as needed. That should speed things up (at the cost of * increasing the memory requirement - can't have everything). * */ #ifdef PLANAR_FILE int ReadPlanarTileFile(tilenum, gp) int tilenum; struct planar_cell_struct **gp; { long fpos; #ifdef TILES_IN_RAM if (tiles_in_ram) { *gp = ramtiles + tilenum; return 0; } #endif fpos = ((long) (tilenum) * (long) sizeof(struct planar_cell_struct)) + (long) TIBHEADER_SIZE; if (fseek(tilefile, fpos, SEEK_SET)) { return 1; } else { fread(&plancell, sizeof(struct planar_cell_struct), 1, tilefile); } *gp = &plancell; return 0; } int ReadPlanarTileFile_O(tilenum, gp) int tilenum; struct overview_planar_cell_struct **gp; { long fpos; #ifdef TILES_IN_RAM if (otiles_in_ram) { *gp = oramtiles + tilenum; return 0; } #endif fpos = ((long) (tilenum) * (long) sizeof(struct overview_planar_cell_struct)) + (long) TIBHEADER_SIZE; if (fseek(tilefile_O, fpos, SEEK_SET)) { return 1; } else { fread(&oplancell, sizeof(struct overview_planar_cell_struct), 1, tilefile_O); } *gp = &oplancell; return 0; } #endif #ifdef PACKED_FILE int ReadPackedTileFile(tilenum, pta) int tilenum; char (*pta)[TILE_X]; { long fpos; fpos = ((long) (tilenum) * (long) (TILE_Y * TILE_X) + (long) TIBHEADER_SIZE); if (fseek(tilefile, fpos, SEEK_SET)) { return 1; } else { fread(pta, (TILE_Y * TILE_X), 1, tilefile); } return 0; } #endif #endif /* USE_TILES */ /* pctiles.c */ nethack-3.6.0/sys/msdos/pctiles.h0000664000076400007660000000425312536476415015735 0ustar paxedpaxed/* NetHack 3.6 pctiles.h $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * pctiles.h - Definitions for PC graphical tile support * *Edit History: * Initial Creation M. Allison 93/10/30 * */ #ifdef USE_TILES #define NETHACK_PLANAR_TILEFILE "NetHack1.tib" /* Planar style tiles */ #define NETHACK_PACKED_TILEFILE "NetHack2.tib" /* Packed style tiles */ #define NETHACK_OVERVIEW_TILEFILE "NetHacko.tib" /* thin overview tiles */ #define ROWS_PER_TILE TILE_Y #define COLS_PER_TILE TILE_X #define EMPTY_TILE -1 #define TIBHEADER_SIZE 1024 /* Use this for size, allows expansion */ #define PLANAR_STYLE 0 #define PACKED_STYLE 1 #define DJGPP_COMP 0 #define MSC_COMP 1 #define BC_COMP 2 #define OTHER_COMP 10 struct tibhdr_struct { char ident[80]; /* Identifying string */ char timestamp[26]; /* Ascii timestamp */ char tilestyle; /* 0 = planar, 1 = pixel */ char compiler; /* 0 = DJGPP, 1 = MSC, 2= BC etc. see above */ short tilecount; /* number of tiles in file */ short numcolors; /* number of colors in palette */ char palette[256 * 3]; /* palette */ }; /* Note on packed style tile file: * Each record consists of one of the following arrays: * char packtile[TILE_Y][TILE_X]; */ extern void FDECL(CloseTileFile, (BOOLEAN_P)); extern int FDECL(OpenTileFile, (char *, BOOLEAN_P)); extern int FDECL(ReadTileFileHeader, (struct tibhdr_struct *, BOOLEAN_P)); #ifdef PLANAR_FILE #ifdef SCREEN_VGA extern int FDECL(ReadPlanarTileFile, (int, struct planar_cell_struct **)); extern int FDECL(ReadPlanarTileFile_O, (int, struct overview_planar_cell_struct **)); #endif #endif #ifdef PACKED_FILE extern int FDECL(ReadPackedTileFile, (int, char (*)[TILE_X])); #endif extern short glyph2tile[MAX_GLYPH]; /* in tile.c (made from tilemap.c) */ #endif /* USE_TILES */ /* pctiles.h */ nethack-3.6.0/sys/msdos/pcvideo.h0000664000076400007660000002052212536476415015720 0ustar paxedpaxed/* NetHack 3.6 pcvideo.h $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * pcvideo.h - Hardware video support definitions and prototypes * *Edit History: * Initial Creation M. Allison 93/10/30 * */ #ifndef PCVIDEO_H #define PCVIDEO_H #include "portio.h" #ifdef SCREEN_BIOS #if !defined(PC9800) #define MONO_CHECK /* Video BIOS can do the check */ #endif #endif #ifdef SCREEN_DJGPPFAST /*# define MONO_CHECK /* djgpp should be able to do check */ #endif /* * PC interrupts */ #ifdef PC9800 #define CRT_BIOS 0x18 #define DOS_EXT_FUNC 0xdc #define DIRECT_CON_IO 0x10 #else #define VIDEO_BIOS 0x10 #endif #define DOSCALL 0x21 /* * Video BIOS functions */ #if defined(PC9800) #define SENSEMODE 0x0b /* Sense CRT Mode */ #define PUTCHAR 0x00 /* Put Character */ #define SETATT 0x02 /* Set Attribute */ #define SETCURPOS 0x03 /* Set Cursor Position */ #define CURSOR_RIGHT 0x08 /* Move Cursor Right */ #define CURSOR_LEFT 0x09 /* Move Cursor Left */ #define SCREEN_CLEAR 0x0a /* Clear Screen */ #define LINE_CLEAR 0x0b /* Clear Line */ #else #define SETCURPOS 0x02 /* Set Cursor Position */ #endif #define GETCURPOS 0x03 /* Get Cursor Position */ #define GETMODE 0x0f /* Get Video Mode */ #define SETMODE 0x00 /* Set Video Mode */ #define SETPAGE 0x05 /* Set Video Page */ #define FONTINFO 0x1130 /* Get Font Info */ #define SCROLL 0x06 /* Scroll or initialize window */ #define PUTCHARATT 0x09 /* Write attribute & char at cursor */ /* * VGA Specific Stuff */ #ifdef SCREEN_VGA /* #define HW_PANNING /* Hardware panning enabled */ #define USHORT unsigned short #define MODE640x480 0x0012 /* Switch to VGA 640 x 480 Graphics mode */ #define MODETEXT 0x0003 /* Switch to Text mode 3 */ #ifdef HW_PANNING #define PIXELINC 16 /* How much to increment by when panning */ /*#define PIXELINC 1 /* How much to increment by when panning */ #define SCREENBYTES 128 #define CharRows 30 #define VERT_RETRACE \ { \ while (!(inportb(crt_status) & 0x08)) \ ; \ } #define VERT_RETRACE_END \ { \ while ((inportb(crt_status) & 0x08)) \ ; \ } #else #define SCREENBYTES 80 #endif #define CharacterWidth 8 #define SCREENHEIGHT 480 #define SCREENWIDTH (SCREENBYTES * CharacterWidth) #define VIDEOSEG 0xa000 #define FONT_PTR_SEGMENT 0x0000 #define FONT_PTR_OFFSET 0x010C #define SCREENPLANES 4 #define COLORDEPTH 16 #define egawriteplane(n) \ { \ outportb(0x3c4, 2); \ outportb(0x3c5, n); \ } #define egareadplane(n) \ { \ outportb(0x3ce, 4); \ outportb(0x3cf, n); \ } #define col2x8(c) ((c) *8) #define col2x16(c) ((c) *16) #define col2x(c) ((c) *2) #define row2y(c) ((c) *16) #define MAX_ROWS_PER_CELL 16 #define MAX_COLS_PER_CELL 16 #define MAX_BYTES_PER_CELL 2 /* MAX_COLS_PER_CELL/8 */ #define ROWS_PER_CELL MAX_ROWS_PER_CELL #define COLS_PER_CELL MAX_COLS_PER_CELL #define BYTES_PER_CELL MAX_BYTES_PER_CELL struct cellplane { char image[MAX_ROWS_PER_CELL][MAX_BYTES_PER_CELL]; }; struct planar_cell_struct { struct cellplane plane[SCREENPLANES]; }; struct overview_cellplane { char image[MAX_ROWS_PER_CELL][1]; }; struct overview_planar_cell_struct { struct overview_cellplane plane[SCREENPLANES]; }; #endif /* SCREEN_VGA */ /* * Default color Indexes for hardware palettes * * Do not change the values below. * These are the color mappings defined by the particular video * hardware/mode. You can rearrange the NetHack color mappings at * run-time via the defaults.nh "videocolors" and "videoshades" * settings. * */ #if defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST) #define M_BLACK 8 #define M_WHITE 15 #define M_GRAY 7 /* low-intensity white */ #define M_RED 4 #define M_GREEN 2 #define M_BROWN 6 /* low-intensity yellow */ #define M_BLUE 1 #define M_MAGENTA 5 #define M_CYAN 3 #define M_ORANGE 12 #define M_BRIGHTGREEN 10 #define M_YELLOW 14 #define M_BRIGHTBLUE 9 #define M_BRIGHTMAGENTA 13 #define M_BRIGHTCYAN 11 #define M_TEXT M_GRAY #define BACKGROUND_COLOR 0 #define ATTRIB_NORMAL M_TEXT /* Normal attribute */ #define ATTRIB_INTENSE M_WHITE /* Intense White */ #define ATTRIB_MONO_NORMAL 0x01 /* Underlined,white */ #define ATTRIB_MONO_UNDERLINE 0x01 /* Underlined,white */ #define ATTRIB_MONO_BLINK 0x87 /* Flash bit, white */ #define ATTRIB_MONO_REVERSE 0x70 /* Black on white */ #endif /*SCREEN_BIOS || SCREEN_DJGPPFAST */ #if defined(SCREEN_VGA) || defined(SCREEN_8514) #define BACKGROUND_VGA_COLOR 0 #define ATTRIB_VGA_NORMAL CLR_GRAY /* Normal attribute */ #define ATTRIB_VGA_INTENSE 13 /* Intense White 94/06/07 palette chg*/ #endif /*SCREEN_VGA || SCREEN_8514*/ #if defined(PC9800) static unsigned char attr98[CLR_MAX] = { 0xe1, /* 0 white */ 0x21, /* 1 blue */ 0x81, /* 2 green */ 0xa1, /* 3 cyan */ 0x41, /* 4 red */ 0x61, /* 5 magenta */ 0xc1, /* 6 yellow */ 0xe1, /* 7 white */ 0xe1, /* 8 white */ 0x25, /* 9 reversed blue */ 0x85, /* 10 reversed green */ 0xa5, /* 11 reversed cyan */ 0x45, /* 12 reversed red */ 0x65, /* 13 reversed magenta */ 0xc5, /* 14 reversed yellow */ 0xe5, /* 15 reversed white */ }; #endif #ifdef SIMULATE_CURSOR #define CURSOR_HEIGHT 3 /* this should go - MJA */ /* cursor styles */ #define CURSOR_INVIS 0 /* cursor not visible at all */ #define CURSOR_FRAME 1 /* block around the current tile */ #define CURSOR_UNDERLINE 2 /* thin line at bottom of the tile */ #define CURSOR_CORNER 3 /* cursor visible at the 4 tile corners */ #define NUM_CURSOR_TYPES 4 /* number of different cursor types */ #define CURSOR_DEFAULT_STYLE CURSOR_CORNER #define CURSOR_DEFAULT_COLOR M_GRAY /* global variables for cursor */ extern int cursor_type; extern int cursor_flag; extern int cursor_color; #endif /* * Function Prototypes * */ #define E extern /* ### video.c ### */ #ifdef SIMULATE_CURSOR E void NDECL(DrawCursor); E void NDECL(HideCursor); #endif /* ### vidtxt.c ### */ #ifdef NO_TERMS E void NDECL(txt_backsp); E void NDECL(txt_clear_screen); E void FDECL(txt_cl_end, (int, int)); E void NDECL(txt_cl_eos); E void NDECL(txt_get_scr_size); E void FDECL(txt_gotoxy, (int, int)); E int NDECL(txt_monoadapt_check); E void NDECL(txt_nhbell); E void FDECL(txt_startup, (int *, int *)); E void FDECL(txt_xputs, (const char *, int, int)); E void FDECL(txt_xputc, (CHAR_P, int)); /* ### vidvga.c ### */ #ifdef SCREEN_VGA E void NDECL(vga_backsp); E void FDECL(vga_clear_screen, (int)); E void FDECL(vga_cl_end, (int, int)); E void FDECL(vga_cl_eos, (int)); E int NDECL(vga_detect); #ifdef SIMULATE_CURSOR E void NDECL(vga_DrawCursor); #endif E void FDECL(vga_DisplayCell, (struct planar_cell_struct *, int, int)); E void FDECL(vga_DisplayCell_O, (struct overview_planar_cell_struct *, int, int)); E void NDECL(vga_Finish); E char __far *NDECL(vga_FontPtrs); E void NDECL(vga_get_scr_size); E void FDECL(vga_gotoloc, (int, int)); #ifdef POSITIONBAR E void FDECL(vga_update_positionbar, (char *)); #endif #ifdef SIMULATE_CURSOR E void NDECL(vga_HideCursor); #endif E void NDECL(vga_Init); E void FDECL(vga_SwitchMode, (unsigned int)); E void FDECL(vga_SetPalette, (char *)); E void NDECL(vga_tty_end_screen); E void FDECL(vga_tty_startup, (int *, int *)); E void FDECL(vga_WriteChar, (int, int, int, int)); E void FDECL(vga_WriteStr, (char *, int, int, int, int)); E void FDECL(vga_xputs, (const char *, int, int)); E void FDECL(vga_xputc, (CHAR_P, int)); E void FDECL(vga_xputg, (int, int, unsigned)); E void FDECL(vga_userpan, (BOOLEAN_P)); E void FDECL(vga_overview, (BOOLEAN_P)); E void FDECL(vga_traditional, (BOOLEAN_P)); E void NDECL(vga_refresh); #endif /* SCREEN_VGA */ #endif /* NO_TERMS */ #undef E #endif /* PCVIDEO_H */ /* pcvideo.h */ nethack-3.6.0/sys/msdos/portio.h0000664000076400007660000000434112536476415015604 0ustar paxedpaxed/* NetHack 3.6 portio.h $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * portio.h - PC port I/O Hardware support definitions and other * low-level definitions. * */ #ifndef PORTIO_H #define PORTIO_H #if defined(__GO32__) || defined(__DJGPP__) #define __far #include #include #include #endif #if defined(_MSC_VER) #define outportb _outp #define outportw _outpw #define inportb _inp #endif #if defined(__BORLANDC__) #define outportw outport /* #define inportb inport */ #endif #ifndef MK_PTR /* * Depending on environment, this is a macro to construct either: * * - a djgpp long 32 bit pointer from segment & offset values * - a far pointer from segment and offset values * */ #if defined(_MSC_VER) || defined(__BORLANDC__) #define MK_PTR(seg, offset) \ (void __far *)(((unsigned long) seg << 16) \ + (unsigned long) (unsigned) offset) #define READ_ABSOLUTE(x) *(x) #define READ_ABSOLUTE_WORD(x) *(x) #define WRITE_ABSOLUTE(x, y) *(x) = (y) #define WRITE_ABSOLUTE_WORD(x, y) *(x) = (y) #endif #if defined(__GO32__) || defined(__DJGPP__) #define MK_PTR(seg, offset) \ (void *)(((unsigned) seg << 4) + (unsigned) offset) #define READ_ABSOLUTE(x) \ (_farpeekb(_go32_conventional_mem_selector(), (unsigned) x)) #define READ_ABSOLUTE_WORD(x) \ (_farpeekw(_go32_conventional_mem_selector(), (unsigned) x)) #define WRITE_ABSOLUTE(x, y) \ _farpokeb(_go32_conventional_mem_selector(), (unsigned) x, (y)) #define WRITE_ABSOLUTE_WORD(x, y) \ _farpokew(_go32_conventional_mem_selector(), (unsigned) x, (y)) #endif #ifdef OBSOLETE /* old djgpp V1.x way of mapping 1st MB */ #define MK_PTR(seg, offset) \ (void *)(0xE0000000 + ((((unsigned) seg << 4) + (unsigned) offset))) #define READ_ABSOLUTE(x) *(x) #define READ_ABSOLUTE_WORD(x) *(x) #define WRITE_ABSOLUTE(x, y) *(x) = (y) #define WRITE_ABSOLUTE_WORD(x, y) *(x) = (y) #endif #endif /* MK_PTR */ #endif /* PORTIO_H */ /* portio.h */ nethack-3.6.0/sys/msdos/schema1.BC0000664000076400007660000001515212536476415015650 0ustar paxedpaxed/* NetHack 3.6 schema1.BC $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Yitzhak Sapir, 1999 */ /* */ /* NetHack Overlay Schema */ /* Minimal extended memory available, lots of 640K base RAM free */ /* Overlay buffer size will be (20 + 20 + 19) = 59K (sum of 3 largest overlays). */ /* Requires about 490K (for exe load plus overlay buffer), but */ /* an additional 70K free (minimum) will be needed for malloc calls, */ /* bringing the total requirement to about 560K. */ /* Optimized for minimal overlay turns. */ /* */ -zCallmain_0 -zAOVLY -zCOVL1 -zCallmain_1 -zAOVLY -zCOVL2 -zCallmain_b -zAOVLY -zCOVL3 -zCalloc_o -zCapply_0 -zAOVLY -zCOVL4 -zCapply_1 -zAOVLY -zCOVL5 -zCapply_b -zAOVLY -zCOVL6 -zCartifact_0 -zAOVLY -zCOVL7 -zCartifact_1 -zAOVLY -zCOVL8 -zCartifact_b -zAOVLY -zCOVL9 -zCattrib_0 -zCattrib_1 -zAOVLY -zCOVL10 -zCattrib_2 -zAOVLY -zCOVL11 -zCattrib_b -zAOVLY -zCOVL12 -zCball_o -zAOVLY -zCOVL13 -zCbones_o -zAOVLY -zCOVL14 -zCbotl_0 -zCbotl_1 -zAOVLY -zCOVL15 -zCbotl_b -zAOVLY -zCOVL16 -zCcmd_0 -zCcmd_1 -zAOVLY -zCOVL17 -zCcmd_b -zAOVLY -zCOVL18 -zCdbridge_0 -zCdbridge_1 -zAOVLY -zCOVL19 -zCdbridge_b -zAOVLY -zCOVL20 -zCdecl_o -zAOVLY -zCOVL21 -zCdetect_o -zCdig_o -zAOVLY -zCOVL22 -zCdisplay_o -zCdlb_o -zAOVLY -zCOVL23 -zCdo_0 -zAOVLY -zCOVL24 -zCdo_1 -zAOVLY -zCOVL25 -zCdo_2 -zAOVLY -zCOVL26 -zCdo_3 -zAOVLY -zCOVL27 -zCdo_b -zAOVLY -zCOVL28 -zCdo_name_0 -zAOVLY -zCOVL29 -zCdo_name_2 -zAOVLY -zCOVL30 -zCdo_name_b -zAOVLY -zCOVL31 -zCdo_wear_0 -zAOVLY -zCOVL32 -zCdo_wear_1 -zAOVLY -zCOVL33 -zCdo_wear_2 -zAOVLY -zCOVL34 -zCdo_wear_b -zAOVLY -zCOVL35 -zCdog_1 -zAOVLY -zCOVL36 -zCdog_2 -zAOVLY -zCOVL37 -zCdog_b -zAOVLY -zCOVL38 -zCdogmove_0 -zAOVLY -zCOVL39 -zCdogmove_b -zCdokick_o -zAOVLY -zCOVL40 -zCdothrow_o -zAOVLY -zCOVL41 -zCdrawing_o -zAOVLY -zCOVL42 -zCdungeon_0 -zCdungeon_1 -zAOVLY -zCOVL43 -zCeat_0 -zAOVLY -zCOVL44 -zCeat_1 -zAOVLY -zCOVL45 -zCeat_b -zAOVLY -zCOVL46 -zCend_o -zAOVLY -zCOVL47 -zCengrave_0 -zCengrave_1 -zAOVLY -zCOVL48 -zCengrave_2 -zAOVLY -zCOVL49 -zCengrave_b -zAOVLY -zCOVL50 -zCexper_o -zAOVLY -zCOVL51 -zCexplode_0 -zAOVLY -zCOVL52 -zCexplode_1 -zAOVLY -zCOVL53 -zCextralev_o -zAOVLY -zCOVL54 -zCfiles_o -zAOVLY -zCOVL55 -zCfountain_o -zAOVLY -zCOVL56 -zCgetline_1 -zAOVLY -zCOVL57 -zCgetline_2 -zAOVLY -zCOVL58 -zChack_1 -zChack_2 -zAOVLY -zCOVL59 -zChack_3 -zChack_b -zAOVLY -zCOVL60 -zChacklib_0 -zChacklib_1 -zChacklib_2 -zChacklib_b -zAOVLY -zCOVL61 -zCinvent_0 -zCinvent_1 -zAOVLY -zCOVL62 -zCinvent_2 -zAOVLY -zCOVL63 -zCinvent_3 -zAOVLY -zCOVL64 -zCinvent_b -zAOVLY -zCOVL65 -zClight_3 -zAOVLY -zCOVL66 -zClock_0 -zAOVLY -zCOVL67 -zClock_b -zAOVLY -zCOVL68 -zCmail_0 -zAOVLY -zCOVL68 -zCmail_b -zAOVLY -zCOVL69 -zCmakemon_0 -zAOVLY -zCOVL70 -zCmakemon_1 -zAOVLY -zCOVL71 -zCmakemon_2 -zAOVLY -zCOVL72 -zCmakemon_b -zAOVLY -zCOVL73 -zCmcastu_0 -zAOVLY -zCOVL74 -zCmcastu_b -zAOVLY -zCOVL75 -zCmhitm_0 -zAOVLY -zCOVL76 -zCmhitm_b -zAOVLY -zCOVL77 -zCmhitu_0 -zAOVLY -zCOVL78 -zCmhitu_1 -zAOVLY -zCOVL79 -zCmhitu_b -zAOVLY -zCOVL80 -zCminion_o -zAOVLY -zCOVL81 -zCmklev_o -zAOVLY -zCOVL82 -zCmkmap_o -zAOVLY -zCOVL83 -zCmkmaze_o -zAOVLY -zCOVL84 -zCmkobj_0 -zAOVLY -zCOVL85 -zCmkobj_1 -zAOVLY -zCOVL86 -zCmkobj_b -zAOVLY -zCOVL87 -zCmkroom_0 -zAOVLY -zCOVL88 -zCmkroom_b -zAOVLY -zCOVL89 -zCmon_0 -zCmon_1 -zAOVLY -zCOVL90 -zCmon_2 -zAOVLY -zCOVL91 -zCmon_b -zAOVLY -zCOVL92 -zCmondata_0 -zCmondata_1 -zAOVLY -zCOVL93 -zCmondata_2 -zAOVLY -zCOVL94 -zCmondata_b -zAOVLY -zCOVL95 -zCmonmove_0 -zCmonmove_1 -zCmonmove_2 -zCmonmove_b -zAOVLY -zCOVL96 -zCmonst_o -zAOVLY -zCOVL97 -zCmonstr_o -zAOVLY -zCOVL98 -zCmplayer_o -zAOVLY -zCOVL99 -zCmsdos_0 -zCmsdos_b -zAOVLY -zCOVL100 -zCmthrowu_0 -zAOVLY -zCOVL101 -zCmthrowu_1 -zAOVLY -zCOVL102 -zCmthrowu_b -zAOVLY -zCOVL103 -zCmuse_o -zAOVLY -zCOVL104 -zCmusic_o -zAOVLY -zCOVL105 -zCo_init_o -zAOVLY -zCOVL106 -zCobjects_o -zAOVLY -zCOVL107 -zCobjnam_0 -zAOVLY -zCOVL108 -zCobjnam_1 -zAOVLY -zCOVL109 -zCobjnam_b -zAOVLY -zCOVL110 -zCoptions_o -zAOVLY -zCOVL111 -zCovlinit_o -zCpager_o -zAOVLY -zCOVL112 -zCpckeys_o -zCpcmain_0 -zCpcmain_1 -zAOVLY -zCOVL113 -zCpcmain_b -zAOVLY -zCOVL114 -zCpctiles_0 -zCpctiles_b -zCpcunix_b -zAOVLY -zCOVL115 -zCpickup_o -zAOVLY -zCOVL116 -zCpline_b -zAOVLY -zCOVL117 -zCpolyself_0 -zAOVLY -zCOVL118 -zCpolyself_1 -zAOVLY -zCOVL119 -zCpolyself_b -zAOVLY -zCOVL120 -zCpotion_b -zAOVLY -zCOVL121 -zCpray_o -zAOVLY -zCOVL122 -zCpriest_0 -zAOVLY -zCOVL123 -zCpriest_b -zAOVLY -zCOVL124 -zCquest_o -zAOVLY -zCOVL125 -zCquestpgr_o -zAOVLY -zCOVL126 -zCrandom_o -zCread_b -zAOVLY -zCOVL127 -zCrect_o -zAOVLY -zCOVL128 -zCregion_o -zAOVLY -zCOVL129 -zCrestore_o -zAOVLY -zCOVL130 -zCrip_o -zAOVLY -zCOVL131 -zCrnd_0 -zCrnd_1 -zAOVLY -zCOVL132 -zCrnd_b -zAOVLY -zCOVL133 -zCrole_o -zAOVLY -zCOVL113 -zCrumors_o -zAOVLY -zCOVL134 -zCsave_o -zAOVLY -zCOVL135 -zCshk_0 -zAOVLY -zCOVL136 -zCshk_1 -zAOVLY -zCOVL137 -zCshk_2 -zAOVLY -zCOVL138 -zCshk_3 -zAOVLY -zCOVL139 -zCshk_b -zAOVLY -zCOVL140 -zCshknam_0 -zAOVLY -zCOVL141 -zCshknam_b -zAOVLY -zCOVL142 -zCsit_o -zAOVLY -zCOVL143 -zCsound_o -zCsounds_0 -zAOVLY -zCOVL144 -zCsounds_b -zAOVLY -zCOVL145 -zCsp_lev_o -zAOVLY -zCOVL146 -zCspell_o -zAOVLY -zCOVL147 -zCsteal_0 -zAOVLY -zCOVL148 -zCsteal_1 -zAOVLY -zCOVL149 -zCsteal_b -zAOVLY -zCOVL150 -zCsteed_o -zAOVLY -zCOVL188 -zCpcsys_o -zAOVLY -zCOVL151 -zCteleport_o -zAOVLY -zCOVL152 -zCtermcap_0 -zAOVLY -zCOVL153 -zCtermcap_1 -zAOVLY -zCOVL154 -zCtermcap_b -zAOVLY -zCOVL155 -zCtile_o -zCtimeout_0 -zAOVLY -zCOVL156 -zCtimeout_1 -zAOVLY -zCOVL157 -zCtimeout_b -zAOVLY -zCOVL158 -zCtopl_1 -zAOVLY -zCOVL159 -zCtopl_2 -zAOVLY -zCOVL160 -zCtopl_b -zAOVLY -zCOVL161 -zCtopten_o -zAOVLY -zCOVL162 -zCtrack_0 -zAOVLY -zCOVL163 -zCtrack_1 -zAOVLY -zCOVL164 -zCtrack_b -zAOVLY -zCOVL165 -zCtrap_0 -zCtrap_1 -zAOVLY -zCOVL166 -zCtrap_2 -zAOVLY -zCOVL167 -zCtrap_3 -zAOVLY -zCOVL168 -zCtrap_b -zAOVLY -zCOVL169 -zCtty_o -zAOVLY -zCOVL170 -zCu_init_o -zAOVLY -zCOVL171 -zCuhitm_o -zAOVLY -zCOVL172 -zCvault_0 -zAOVLY -zCOVL173 -zCvault_b -zAOVLY -zCOVL174 -zCversion_o -zAOVLY -zCOVL175 -zCvideo_0 -zCvideo_1 -zCvideo_b -zCvidtxt_0 -zCvidtxt_b -zCvidvga_0 -zCvidvga_1 -zCvidvga_2 -zAOVLY -zCOVL176 -zCvidvga_b -zCvis_tab_o -zAOVLY -zCOVL177 -zCvision_o -zCweapon_0 -zAOVLY -zCOVL178 -zCweapon_1 -zAOVLY -zCOVL179 -zCweapon_b -zAOVLY -zCOVL180 -zCwere_0 -zAOVLY -zCOVL181 -zCwere_b -zAOVLY -zCOVL182 -zCwield_o -zAOVLY -zCOVL183 -zCwindows_o -zAOVLY -zCOVL184 -zCwintty_o -zCwizard_0 -zAOVLY -zCOVL185 -zCwizard_b -zAOVLY -zCOVL186 -zCworm_o -zAOVLY -zCOVL187 -zCworn_o -zAOVLY -zCOVL188 -zCwrite_o -zAOVLY -zCOVL189 -zCzap_0 -zAOVLY -zCOVL190 -zCzap_1 -zAOVLY -zCOVL191 -zCzap_2 -zAOVLY -zCOVL192 -zCzap_3 -zAOVLY -zCOVL193 -zCzap_b -zAOVLY -zCOVL194 nethack-3.6.0/sys/msdos/schema2.BC0000664000076400007660000001544612536476415015657 0ustar paxedpaxed/* NetHack 3.6 schema2.BC $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Yitzhak Sapir, 1999 */ /* */ /* NetHack Overlay Schema */ /* Small Root footprint, with extended memory available for caching. */ /* Almost everything is overlaid. */ /* */ -zCallmain_0 -zAOVLY -zCOVL1 -zCallmain_1 -zAOVLY -zCOVL2 -zCallmain_b -zAOVLY -zCOVL3 -zCalloc_o -zCapply_0 -zAOVLY -zCOVL4 -zCapply_1 -zAOVLY -zCOVL5 -zCapply_b -zAOVLY -zCOVL6 -zCartifact_0 -zAOVLY -zCOVL7 -zCartifact_1 -zAOVLY -zCOVL8 -zCartifact_b -zAOVLY -zCOVL9 -zCattrib_0 -zAOVLY -zCOVL10 -zCattrib_1 -zAOVLY -zCOVL11 -zCattrib_2 -zAOVLY -zCOVL12 -zCattrib_b -zAOVLY -zCOVL13 -zCball_o -zAOVLY -zCOVL14 -zCbones_o -zAOVLY -zCOVL15 -zCbotl_0 -zAOVLY -zCOVL16 -zCbotl_1 -zAOVLY -zCOVL17 -zCbotl_b -zAOVLY -zCOVL18 -zCcmd_0 -zAOVLY -zCOVL19 -zCcmd_1 -zAOVLY -zCOVL20 -zCcmd_b -zAOVLY -zCOVL21 -zCdbridge_0 -zAOVLY -zCOVL22 -zCdbridge_1 -zAOVLY -zCOVL23 -zCdbridge_b -zAOVLY -zCOVL24 -zCdecl_o -zAOVLY -zCOVL25 -zCdetect_o -zAOVLY -zCOVL26 -zCdig_o -zAOVLY -zCOVL27 -zCdisplay_o -zAOVLY -zCOVL28 -zCdlb_o -zAOVLY -zCOVL29 -zCdo_0 -zAOVLY -zCOVL30 -zCdo_1 -zAOVLY -zCOVL31 -zCdo_2 -zAOVLY -zCOVL32 -zCdo_3 -zAOVLY -zCOVL33 -zCdo_b -zAOVLY -zCOVL34 -zCdo_name_0 -zAOVLY -zCOVL35 -zCdo_name_2 -zAOVLY -zCOVL36 -zCdo_name_b -zAOVLY -zCOVL37 -zCdo_wear_0 -zAOVLY -zCOVL38 -zCdo_wear_1 -zAOVLY -zCOVL39 -zCdo_wear_2 -zAOVLY -zCOVL40 -zCdo_wear_b -zAOVLY -zCOVL41 -zCdog_1 -zAOVLY -zCOVL42 -zCdog_2 -zAOVLY -zCOVL43 -zCdog_b -zAOVLY -zCOVL44 -zCdogmove_0 -zAOVLY -zCOVL45 -zCdogmove_b -zAOVLY -zCOVL46 -zCdokick_o -zAOVLY -zCOVL47 -zCdothrow_o -zAOVLY -zCOVL48 -zCdrawing_o -zAOVLY -zCOVL49 -zCdungeon_0 -zAOVLY -zCOVL50 -zCdungeon_1 -zAOVLY -zCOVL51 -zCeat_0 -zAOVLY -zCOVL52 -zCeat_1 -zAOVLY -zCOVL53 -zCeat_b -zAOVLY -zCOVL54 -zCend_o -zAOVLY -zCOVL55 -zCengrave_0 -zAOVLY -zCOVL56 -zCengrave_1 -zAOVLY -zCOVL57 -zCengrave_2 -zAOVLY -zCOVL58 -zCengrave_b -zAOVLY -zCOVL59 -zCexper_o -zAOVLY -zCOVL60 -zCexplode_0 -zAOVLY -zCOVL61 -zCexplode_1 -zAOVLY -zCOVL62 -zCextralev_o -zAOVLY -zCOVL63 -zCfiles_o -zAOVLY -zCOVL64 -zCfountain_o -zAOVLY -zCOVL65 -zCgetline_1 -zAOVLY -zCOVL66 -zCgetline_2 -zAOVLY -zCOVL67 -zChack_1 -zAOVLY -zCOVL68 -zChack_2 -zAOVLY -zCOVL69 -zChack_3 -zChack_b -zAOVLY -zCOVL70 -zChacklib_0 -zAOVLY -zCOVL71 -zChacklib_1 -zAOVLY -zCOVL72 -zChacklib_2 -zAOVLY -zCOVL73 -zChacklib_b -zAOVLY -zCOVL74 -zCinvent_0 -zAOVLY -zCOVL75 -zCinvent_1 -zAOVLY -zCOVL76 -zCinvent_2 -zAOVLY -zCOVL77 -zCinvent_3 -zAOVLY -zCOVL78 -zCinvent_b -zAOVLY -zCOVL79 -zClight_3 -zAOVLY -zCOVL80 -zClock_0 -zAOVLY -zCOVL81 -zClock_b -zAOVLY -zCOVL82 -zCmail_0 -zAOVLY -zCOVL82 -zCmail_b -zAOVLY -zCOVL83 -zCmakemon_0 -zAOVLY -zCOVL84 -zCmakemon_1 -zAOVLY -zCOVL85 -zCmakemon_2 -zAOVLY -zCOVL86 -zCmakemon_b -zAOVLY -zCOVL87 -zCmcastu_0 -zAOVLY -zCOVL88 -zCmcastu_b -zAOVLY -zCOVL89 -zCmhitm_0 -zAOVLY -zCOVL90 -zCmhitm_b -zAOVLY -zCOVL91 -zCmhitu_0 -zAOVLY -zCOVL92 -zCmhitu_1 -zAOVLY -zCOVL93 -zCmhitu_b -zAOVLY -zCOVL94 -zCminion_o -zAOVLY -zCOVL95 -zCmklev_o -zAOVLY -zCOVL96 -zCmkmap_o -zAOVLY -zCOVL97 -zCmkmaze_o -zAOVLY -zCOVL98 -zCmkobj_0 -zAOVLY -zCOVL99 -zCmkobj_1 -zAOVLY -zCOVL100 -zCmkobj_b -zAOVLY -zCOVL101 -zCmkroom_0 -zAOVLY -zCOVL102 -zCmkroom_b -zAOVLY -zCOVL103 -zCmon_0 -zAOVLY -zCOVL104 -zCmon_1 -zAOVLY -zCOVL105 -zCmon_2 -zAOVLY -zCOVL106 -zCmon_b -zAOVLY -zCOVL107 -zCmondata_0 -zAOVLY -zCOVL108 -zCmondata_1 -zAOVLY -zCOVL109 -zCmondata_2 -zAOVLY -zCOVL110 -zCmondata_b -zAOVLY -zCOVL111 -zCmonmove_0 -zAOVLY -zCOVL112 -zCmonmove_1 -zAOVLY -zCOVL113 -zCmonmove_2 -zAOVLY -zCOVL114 -zCmonmove_b -zAOVLY -zCOVL115 -zCmonst_o -zAOVLY -zCOVL116 -zCmonstr_o -zAOVLY -zCOVL117 -zCmplayer_o -zAOVLY -zCOVL118 -zCmsdos_0 -zAOVLY -zCOVL119 -zCmsdos_b -zAOVLY -zCOVL120 -zCmthrowu_0 -zAOVLY -zCOVL121 -zCmthrowu_1 -zAOVLY -zCOVL122 -zCmthrowu_b -zAOVLY -zCOVL123 -zCmuse_o -zAOVLY -zCOVL124 -zCmusic_o -zAOVLY -zCOVL125 -zCo_init_o -zAOVLY -zCOVL126 -zCobjects_o -zAOVLY -zCOVL127 -zCobjnam_0 -zAOVLY -zCOVL128 -zCobjnam_1 -zAOVLY -zCOVL129 -zCobjnam_b -zAOVLY -zCOVL130 -zCoptions_o -zAOVLY -zCOVL131 -zCovlinit_o -zCpager_o -zAOVLY -zCOVL132 -zCpckeys_o -zAOVLY -zCOVL119 -zCpcmain_0 -zCpcmain_1 -zAOVLY -zCOVL133 -zCpcmain_b -zAOVLY -zCOVL134 -zCpctiles_0 -zCpctiles_b -zCpcunix_b -zAOVLY -zCOVL135 -zCpickup_o -zAOVLY -zCOVL136 -zCpline_b -zAOVLY -zCOVL137 -zCpolyself_0 -zAOVLY -zCOVL138 -zCpolyself_1 -zAOVLY -zCOVL139 -zCpolyself_b -zAOVLY -zCOVL140 -zCpotion_b -zAOVLY -zCOVL141 -zCpray_o -zAOVLY -zCOVL142 -zCpriest_0 -zAOVLY -zCOVL143 -zCpriest_b -zAOVLY -zCOVL144 -zCquest_o -zAOVLY -zCOVL145 -zCquestpgr_o -zAOVLY -zCOVL146 -zCrandom_o -zAOVLY -zCOVL147 -zCread_b -zAOVLY -zCOVL148 -zCrect_o -zAOVLY -zCOVL149 -zCregion_o -zAOVLY -zCOVL150 -zCrestore_o -zAOVLY -zCOVL151 -zCrip_o -zAOVLY -zCOVL152 -zCrnd_0 -zAOVLY -zCOVL153 -zCrnd_1 -zAOVLY -zCOVL154 -zCrnd_b -zAOVLY -zCOVL155 -zCrole_o -zAOVLY -zCOVL133 -zCrumors_o -zAOVLY -zCOVL156 -zCsave_o -zAOVLY -zCOVL157 -zCshk_0 -zAOVLY -zCOVL158 -zCshk_1 -zAOVLY -zCOVL159 -zCshk_2 -zAOVLY -zCOVL160 -zCshk_3 -zAOVLY -zCOVL161 -zCshk_b -zAOVLY -zCOVL162 -zCshknam_0 -zAOVLY -zCOVL163 -zCshknam_b -zAOVLY -zCOVL164 -zCsit_o -zAOVLY -zCOVL165 -zCsound_o -zCsounds_0 -zAOVLY -zCOVL166 -zCsounds_b -zAOVLY -zCOVL167 -zCsp_lev_o -zAOVLY -zCOVL168 -zCspell_o -zAOVLY -zCOVL169 -zCsteal_0 -zAOVLY -zCOVL170 -zCsteal_1 -zAOVLY -zCOVL171 -zCsteal_b -zAOVLY -zCOVL172 -zCsteed_o -zAOVLY -zCOVL173 -zCpcsys_o -zAOVLY -zCOVL174 -zCteleport_o -zAOVLY -zCOVL175 -zCtermcap_0 -zAOVLY -zCOVL176 -zCtermcap_1 -zAOVLY -zCOVL177 -zCtermcap_b -zAOVLY -zCOVL178 -zCtile_o -zCtimeout_0 -zAOVLY -zCOVL179 -zCtimeout_1 -zAOVLY -zCOVL180 -zCtimeout_b -zAOVLY -zCOVL181 -zCtopl_1 -zAOVLY -zCOVL182 -zCtopl_2 -zAOVLY -zCOVL183 -zCtopl_b -zAOVLY -zCOVL184 -zCtopten_o -zAOVLY -zCOVL185 -zCtrack_0 -zAOVLY -zCOVL186 -zCtrack_1 -zAOVLY -zCOVL187 -zCtrack_b -zAOVLY -zCOVL188 -zCtrap_0 -zAOVLY -zCOVL189 -zCtrap_1 -zAOVLY -zCOVL190 -zCtrap_2 -zAOVLY -zCOVL191 -zCtrap_3 -zAOVLY -zCOVL192 -zCtrap_b -zAOVLY -zCOVL193 -zCtty_o -zAOVLY -zCOVL194 -zCu_init_o -zAOVLY -zCOVL195 -zCuhitm_o -zAOVLY -zCOVL196 -zCvault_0 -zAOVLY -zCOVL197 -zCvault_b -zAOVLY -zCOVL198 -zCversion_o -zAOVLY -zCOVL199 -zCvideo_0 -zCvideo_1 -zCvideo_b -zCvidtxt_0 -zCvidtxt_b -zCvidvga_0 -zCvidvga_1 -zCvidvga_2 -zAOVLY -zCOVL200 -zCvidvga_b -zCvis_tab_o -zAOVLY -zCOVL201 -zCvision_o -zAOVLY -zCOVL202 -zCweapon_0 -zAOVLY -zCOVL203 -zCweapon_1 -zAOVLY -zCOVL204 -zCweapon_b -zAOVLY -zCOVL205 -zCwere_0 -zAOVLY -zCOVL206 -zCwere_b -zAOVLY -zCOVL207 -zCwield_o -zAOVLY -zCOVL208 -zCwindows_o -zAOVLY -zCOVL209 -zCwintty_o -zAOVLY -zCOVL210 -zCwizard_0 -zAOVLY -zCOVL211 -zCwizard_b -zAOVLY -zCOVL212 -zCworm_o -zAOVLY -zCOVL213 -zCworn_o -zAOVLY -zCOVL173 -zCwrite_o -zAOVLY -zCOVL214 -zCzap_0 -zAOVLY -zCOVL215 -zCzap_1 -zAOVLY -zCOVL216 -zCzap_2 -zAOVLY -zCOVL217 -zCzap_3 -zAOVLY -zCOVL218 -zCzap_b -zAOVLY -zCOVL219 nethack-3.6.0/sys/msdos/schema3.MSC0000664000076400007660000012547412536476415016021 0ustar paxedpaxed; Copyright (c) NetHack PC Development Team, 2000 ; ; NetHack Overlay Schema ; This overlay schema is for use only when NetHack is built ; using packaged-functions for function-level linking. ; ; Overlay tuning level: 0 ; functions:0 _main _dosave0 _moveloop _bwrite _random _rn2 _newsym _show_glyph _on_level _txt_gotoxy _txt_get_cursor functions:0 _xputc _txt_xputc _t_at _tty_curs _acurr _dist2 _tty_print_glyph _isok _back_to_glyph functions:0 _show_map_spot _adjust_cursor_flags _lowc _g_putch _has_color _is_pool _mread functions:0 _is_lava _welded _magic_map_background _end_glyphout _visible_region_at _domove functions:0 _engr_at _rnd _run_regions _mcalcmove _depth _done _distmin _does_block _eos functions:0 _move _move_bc _in_rooms _map_background _map_invisible _map_location _alloc functions:0 _impossible _in_container _in_fcorridor _In_hell _In_mines _in_or_out_menu _In_quest functions:0 _do_positionbar _iswall _iswall_or_stone _itimeout _is_solid _Is_special functions:0 _is_swallow_sym _check_here _check_leash _check_map_spot _check_pos functions:0 _monsndx _m_move _lcase _tty_create_nhwindow _tty_delay_output _tty_destroy_nhwindow functions:0 _tty_dismiss_nhwindow _gender _genl_outrip _get_cost _get_free_room_loc _get_level functions:0 _get_location _get_map _get_mleash ; functions:1 _move_update _movebubbles _movecmd _movemon _moverock _movobj _mpickgold functions:1 _doaltarobj _doapply _dobreathe _docall _docast ; functions:2 _do_vicinity_map functions:3 _pcmain functions:4 _spell_let_to_idx _cursed_book _deadbook _learn _getspell _spelltypemnemonic functions:5 _dospellmenu _percent_success _throwspell _cast_protection _isqrt ; functions:6 _a_gname _a_gname_at _a_monnam _abon _abuse_dog _accessible _activate_statue_trap functions:7 _add_branch _add_damage _add_debug_extended_commands _add_door _add_id_mapping _add_level functions:8 _add_menu_cmd_alias _add_one_tobill _add_rect _add_room _add_subroom _add_to_billobjs _add_to_buried _add_to_container functions:9 _add_to_migration _add_to_minv _add_valid_menu_class _add_weapon_skill _addinv _addtobill _addtopl _addupbill functions:10 _Adjmonnam functions:11 _align_gname functions:12 _altar_wrath _Amonnam _amulet _Amulet_off _Amulet_on _An _an _angry_guards functions:13 _angry_priest _angry_shk_exists _any_light_source _aobjnam _append_slash _append_str _Armor_gone _Armor_off functions:14 _Armor_on _armor_to_dragon _armoroff _arti_invoke _artifact_exists _artifact_hit _artifact_name _artiname functions:15 _artitouch _askchain _assign_level _assign_rnd_level _assign_graphics _assign_soundcard _assign_video functions:16 _assign_videocolors _assign_videoshades _assigninvlet _at_dgn_entrance _attach_egg_hatch_timeout _attack _attack_checks _attacks functions:17 _awaken_monsters _awaken_soldiers functions:18 _backfire _backsp _bad_location _bad_negation _bad_rock _badoption _bail _ballfall functions:19 _bc_order _bclose _bcsign _beg _begin_burn _bflush _bhit _bhitm functions:20 _bhito _bhitpile _big_to_little _bill_box_content _bill_dummy_object _bite _bless _blessorcurse functions:21 _Blindf_off _Blindf_on _block_door _block_entry _block_point _blow_up_landmine _body_part functions:22 _boomhit _Boots_off _Boots_on _bot _boulder_hits_pool _bound_digging functions:23 _boxlock _br_string _break_armor _break_statue _breakarm _breakmsg functions:24 _breakobj _breaks _breaksink _breaktest _breamu _bribe _bufoff _bufon functions:25 _build_room _burn_floor_paper _burn_object _burnarmor _bury_an_obj _bury_objs _buzz _buzzmu functions:26 _Can_dig_down functions:27 _Can_fall_thru _can_make_bones _can_ooze _can_pray _can_reach_floor _Can_rise_up _can_track functions:28 _cancel_bonesfile _cancel_don _cancel_item _cancel_monst _candle_light_range _canletgo _canwearobj functions:29 _carry_count _carrying _castmu _ceiling _center _change_inv_order _change_luck _change_sex functions:30 _charm_monsters _charm_snakes _chat_with_guardian _chat_with_leader _chat_with_nemesis _chdirx _chdrive _cheapest_item functions:31 _check_capacity _check_contained _check_credit _check_recordfile functions:32 _check_room _check_shop_obj _check_special_room _check_unpaid _check_unpaid_usage _check_version _checkfile _chest_shatter_msg functions:33 _chest_trap _choke _choke_dialogue _choose_classes_menu _choose_windows _christen_monst _chwepon _ck_bag functions:34 _ckmailstatus _ckunpaid _cl_end _cl_eos _classmon _clear_fcorr _clear_glyph_buffer functions:35 _clear_id_mapping _clear_level_structures _clear_path _clear_screen _clear_stale_map _clear_unpaid _clearlocks _clearpriests functions:36 _click_to_cmd _Cloak_off _Cloak_on _clone_mon _cloneu _clonewiz _close_drawbridge _close_library functions:37 _closed_door _CloseTileFile _cls _cmov _cnv_trap_obj _co_false _collect_obj_classes _com_pager functions:38 _commit_bonesfile _compactify _compress_bonesfile _compress_str _comspec_exists _confdir _construct_qtlist functions:39 _consume_offering _contained _contained_cost _contained_gold _container_contents _container_weight _convert_arg _convert_line functions:40 _copybones _copyfile _corpse_chance _corpse_xname _corr _correct_branch_type _cost _cost_per_charge functions:41 _costly_gold _costly_spot _could_seduce _count_categories _count_obj _count_unpaid _count_wsegs functions:42 _counter_were _courtmon _cpostfx _cprefx _create_altar _create_bonesfile _create_corridor _create_critters functions:43 _create_door _create_drawbridge _create_engraving _create_feature _create_gold _create_levelfile _create_monster _create_mplayers functions:44 _create_object _create_particular _create_polymon _create_room _create_savefile _create_secret_door _create_stairs _create_subroom functions:45 _create_trap _create_worm_tail _curr_mon_load _currentlevel_rewrite _curs_on_u _curse _cursed _cursed_object_at functions:46 _cursetxt _cuss _cutworm _cvt_sdoor_to_door _d _damageum _dbon _ddocall functions:47 _ddoinv _dead_species _dealloc_obj _decl_init _deepest_lev_reached _def_char_to_monclass _def_char_to_objclass _def_raw_print functions:48 _defends _deferred_goto _del_engr _del_engr_at _del_light_source _delallobj _delete_bonesfile _delete_contents functions:49 _delete_levelfile _delete_savefile _delfloortrap _deliver_by_pline _deliver_by_window _delobj _deltrap _demon_talk functions:50 _demonpet _destroy_arm _destroy_drawbridge _destroy_item _destroy_mitem _dev_name _dig functions:51 _dig_check _dig_corridor _dig_point _dig_typ _digactualhole _dighole _digit _dipfountain functions:52 _disable_ctrlP _disarm_landmine _disarm_shooting_trap _disarm_squeaky_board _discard_minvent _disclose _discover_object functions:53 _diseasemu _display_binventory _display_cinventory _display_gamewindows _display_inventory _display_minventory functions:54 _distant_name _distfleeck _disturb _djinni_from_bottle _dlb_cleanup _dlb_fclose functions:55 _dlb_fgets _dlb_fopen _dlb_fread _dlb_fseek _dlb_ftell _dlb_init _dlord _dmgtype functions:56 _dmgval _dmonsfree _dmore _dname_to_dnum _do_break_wand _do_clear_area _do_comp _do_dknown_of functions:57 _do_earthquake _do_entity _do_genocide _do_improvisation _do_light_sources _do_look _do_mapping _do_mname functions:57 _vga_xputg _vga_xputs _video_update_positionbar _view_from _view_init _visctrl _vision_init _vision_recalc functions:58 _do_oname _do_osshock _do_play_instrument _do_reset_eat _do_room_or_subroom _do_storms _do_takeoff functions:60 _doclose _doconsult _docorner _docrt _doddoremarm _doddrop _dodip functions:61 _adjust_prefix _build_plselection_prompt _duplicate_opt_detection _enter_explore_mode _maybe_wail functions:62 _doextcmd _doextlist _doextversion _dofindgem _dofiretrap _doforce _dog_eat _dog_goal functions:63 _dog_hunger _dog_invent _dog_move _dog_nutrition _dogfood _dogushforth _dohelp _dohide functions:64 _dohistory _doidtrap _doinvbill _doinvoke _dojump _dokick _dolook _doloot functions:65 _domagicportal functions:66 _done_eating _done_in_by _done_intr _done1 _done2 _donning _donull _doopen functions:67 _doorganize _doorlock _dopay _dopayobj _dopickup _dopotion _dopramulet _doprarm functions:68 _dopray _doprev_message _doprgold _doprring _doprtool _doprwep _doputon _doquickwhatis functions:69 _doread _dorecover _doredraw _doremove _doremring _dorub _dosacrifice _dosave functions:70 _dosdoor _dosearch _dosearch0 _doseduce _doset _doset_add_menu _dosh functions:71 _dosinkfall _dosinkring _dosit _dosounds _dospinweb _dospit _dosummon _dotakeoff functions:72 _dotalk _dotele _dothrow _dotogglepickup _dotrap _doturn _dotypeinv _dounpaid functions:73 _dountrap _doup _doversion _dovspell _dowaterdemon _dowaternymph _dowatersnakes _dowear functions:74 _dowhatdoes _dowhatis _dowield _dowipe _down_gate _dowrite _dozap _dprince functions:75 _drag_ball _drag_down _drain_en _DrawCursor _drinkfountain _drinksink _drop _drop_ball functions:76 _drop_throw _drop_to _drop_upon_death _drop_weapon _dropped_container _dropx _dropy functions:77 _drown _dryup _dtoxy _dungeon_branch _dunlev _dunlevs_in_dungeon _e_at _e_died functions:78 _e_jumps _e_missed _e_nam _E_phrase _e_survives_at _eataccessory _eatcorpse _eaten_stat functions:79 _eatfood _eatmdone _eatspecial _egg_type_from_parent _emergency_disrobe _enable_ctrlP _encumber_msg _end_burn functions:80 _end_engulf ;functions:81 functions:82 _exclam _exepath _exerchk _exercise _exerper _exist_artifact _expels _experience functions:83 _explmm _explmu _explode _explum _expulsion _ext_cmd_getlin_hook _extend_spine _extract_nexthere functions:84 _extract_nobj _fall_asleep _fall_through _feel_cockatrice _feel_location _fightm _filesize_nh _fill_pit functions:85 _nh_getenv _promptsep _rigid_role_checks _set_duplicate_opt_detection _tool_in_use functions:86 _find_drawbridge _find_hell _find_lev_obj _find_level _find_mac _find_mid _find_misc _find_offensive functions:87 _find_oid _find_roll_to_hit _find_skates _find_unpaid _finddpos _findfirst_file _findgd _findit functions:88 _findnext_file _findone _findpriest _finish_map _finish_paybill _fix_stair_rooms _fix_worst_trouble _fixup_special functions:89 _flash_hits_mon _float_down _float_up _floating_above _flood_fill_rm _flooreffects _floorfood _flush_screen _term_start_color functions:90 _flushout _fmt_ptr _food_detect _food_disappears _food_xname _foodword _fopen_config_file _fopen_datafile functions:91 _fopenp _forcelock _forget_levels _forget_map _forget_objects _forget_traps _foundfile_buffer _fpostfx functions:92 _fprefx _fracture_rock _free_dungeons _free_rooms _free_ttlist _free_window_info _freediskspace _freedynamicdata functions:93 _freefruitchn _freehand _freeinv _friday_13th _fruitadd _fry_by_god _fully_identify_obj _g_at functions:94 _gainstr _gameDiskPrompt _gazemm _gazemu _gd_move _gd_sound _gem_accept functions:95 _display_warning _dlb_fgetc _doattributes _dochug _dochugw functions:96 _fill_point _fill_room _fill_zoo _fillholetyp _find_ac _find_branch _find_branch_room _find_defensive functions:96 _get_mon_location _get_mplname _get_obj_location _get_rect _get_rect_ind _get_room_loc _get_scr_size _get_shop_item functions:97 _get_uchars _get_unused_cs _get_valuables _get_wall_for_db _get_wet _get_wormno _getbones _getdir functions:98 _gethungry functions:99 _gettty _getversionstring _getyear _ggetobj _ghitm _ghod_hitsu _ghost_from_bottle _ghostfruit functions:100 _givit _glibr _Gloves_off _Gloves_on _glyph_at _god_zaps_you _gods_angry _gods_upset functions:101 _godvoice _gold_detect _golemeffects _golemhp _goodfruit _goodpos _goto_hell _goto_level functions:102 _gr_finish _gr_init _graphics_opts _grddead _grease_protect _grow_up _growl _growl_sound functions:103 _guardname _gulpmm _gulpmu _gulpum _gush _hack_artifacts _has_dnstairs functions:104 _has_shrine _has_upstairs _hatch_egg _hates_silver _have_lizard _hcolor _heal_legs _healup functions:105 _Hear_again _Helmet_off _Helmet_on _help_menu _help_monster_out _hero_breaks _hidden_gold _HideCursor functions:106 _highc _histemple_at _hit _hitfloor _hitmm _hitmsg _hitmu _hitum functions:107 _hitval _hmon _hmon_hitmon _hmonas _hold_another_object _holetime _home _home_shk functions:108 _homebase _hooked_tty_getlin _hot_pursuit _hurtarmor _hurtle _identify _identify_pack _impact_drop functions:110 _in_trouble _In_V_tower _In_W_tower _in_your_sanctuary _incr_itimeout _induced_align _inherits _inhishop functions:111 _init_artifacts _init_attr _init_dungeons _init_fill _init_level _init_map _init_objects functions:112 _init_oracles _init_rect _init_rumors _init_ttycolor _init_uhunger _initedog _initoptions _initrack functions:113 _initworm _insert_branch _insert_timer _inside_room _inside_shop _instapetrify _intemple _interesting_to_discover functions:114 _intermed _intervene _intrinsic_possible _inv_cnt _inv_weight _invault _invdisp_nothing _inven_inuse functions:115 _invert_all _invert_all_on_page _Invocation_lev _invocation_message _invocation_pos _Is_botlevel _Is_branchlev _is_chargeable functions:116 _is_db_wall _is_drawbridge_wall _is_edible _is_fainted _is_flammable _is_fshk _is_home_elemental _is_ice ;functions:117 functions:118 _is_worn _is_worn_by_type _isbig _isclearpath functions:119 _itimeout_incr _its_dead _itsstuck _Japanese_item_name _join _join_map _jump _keepdogs functions:119 _sticks _still_chewing _stock_room _stolen_container _stolen_value _stone_luck _stoned_dialogue _stop_occupation functions:120 _kick_monster _kick_object _kickdmg _kickstr _kill_egg _kill_eggs _kill_genocided_monsters _killed functions:121 _kind_name _known_hitum _kops_gone _l_monnam _lantern_message _launch_obj _lava_effects functions:122 _ldrname _leader_speaks _learn_egg_type _ledger_no _ledger_to_dlev _ledger_to_dnum functions:123 _left_side _lesshungry _let_to_name _letter _lev_by_name _level_difficulty _level_distance _level_range functions:124 _level_tele _level_tele_trap _levl_follower _lifesaved_monster _lift_object _light_cocktail _light_region _lined_up functions:125 _linedup _list_genocided _list_vanquished _litroom _litter _little_to_big _llord _lminion functions:126 _load_common_data _load_maze _load_one_engraving _load_one_monster _load_one_object _load_qtlist _load_rooms _load_special functions:127 _loadfruitchn _lock_action _lock_file _locomotion _lookaround _lookat _lookup_id_mapping _lose_weapon_skill functions:128 _losedogs _losehp _losespells _losestr _losexp _m_arrival functions:129 _m_carrying _m_detach _m_dowear _m_dowear_type _m_initgrp _m_initinv _m_initthrow _m_initweap functions:130 _m_lose_armor functions:131 _m_useup _make_angry_shk _make_blinded _make_confused _make_corpse _make_engr_at _make_familiar _make_hallucinated functions:132 _make_happy_shk _make_lockname _make_niches _make_sick _make_stunned _make_vomiting _makecorridors _makedog functions:133 _makekops _makelevel _makemaz _makemon _makeniche _makeplural _makerogueghost _makeroguerooms functions:134 _makerooms functions:135 _map_menu_cmd _map_object _map_trap _match_optname _mattackm _mattacku _max_capacity _max_mon_load functions:136 _max_passive_dmg _max_rank_sz _maxledgerno _may_dig _may_passwall _maybe_write_ls _maybe_write_timer _mayberem functions:137 _maze0xy _maze1xy _mazexy _mb_trapped _mbag_explodes _mbhit _mbhitm _mcalcdistress functions:138 _md_rush _md_start _md_stop _mdig_tunnel functions:139 _meatobj _melt_ice _menu_drop _menu_identify _menu_loot _menu_remarm _mergable _merge_choice functions:140 _merged _mfndpos _midnight _migrate_to_level _mineralize _minit _miniwalk _minstapetrify functions:140 _On_stairs _on_start _On_W_tower_level _oname _onbill _online2 _only_here _onlyspace functions:141 _mintrap functions:142 _mk_bubble _mk_knox_portal _mk_mplayer _mk_named_object _mk_roamer _mk_tt_object _mkaltar _mkbox_cnts functions:143 _mkcavearea _mkcavepos _mkclass _mkcorpstat _mkfount _mkgold _mkgoldobj _mkinvokearea functions:144 _mkinvpos _mklev _mkmap _mkobj _mkobj_at _mkportal _mkroll_launch _mkroom functions:145 _mkshobj_at _mkshop _mksink _mksobj _mksobj_at _mkstairs _mkswamp _mktemple functions:146 _mktrap _mkundead _mkzoo _mlevel_tele_trap _mlifesaver _mnearto _mnexto _mon_arrive functions:147 _mon_break_armor _mon_catchup_elapsed_time _mon_chain _mon_has_amulet _mon_has_arti _mon_has_special _mon_invent_chain _mon_is_local functions:148 _mon_nam _mon_nam_too _mon_owns _mon_reflects _mon_regen _mon_set_minvis _mon_to_stone _mon_wield_item functions:149 _mondead _mondied _mongets _mongone _monkilled _Monnam _monnear functions:150 _monst_init _monster_detect _monster_nearby _monstinroom _monstone _monstr_init _more _more_experienced functions:151 _morehungry _morguemon _move_gold _move_into_trap _move_special functions:153 _mpickobj functions:154 _mselftouch _msg_in _msleep _msmsg _mstatusline _msummon _mswings _mswingsm functions:155 _mtele_trap _mungspaces _munstone _mv_bubble _mvault_tele _mzapmsg _n_or_more _name_to_mon functions:156 _nameshk _nartifact_exist _nasty _ndemon _near_capacity _nemdead _nemesis_speaks _neminame functions:157 _nethack_exit _new_light_source _new_were _newcham _newexplevel _newgame _newhp _newmail functions:158 _newman _newuexp _newuhs _next_level _next_opt _next_shkp _next_to_u functions:159 _nexttodoor _nh_timeout _nhusage _night _nmcpy _no_bones_level _noattacks _nocmov functions:160 _nohandglow _noises _nomul _Norep _not_capable _not_fully_identified _number_leashed _o_in functions:161 _o_on _o_unleash _obfree _obj_chain _obj_delivery _obj_extract_self _obj_here _obj_ice_effects functions:162 _obj_is_burning _obj_is_local _obj_is_pname _obj_merge_light_sources _obj_move_light_source _obj_move_timers _obj_resists _obj_sanity_check functions:163 _obj_sheds_light _obj_shudders _obj_split_light_source _obj_split_timers _obj_stop_timers _obj_to_let _object_detect _objects_init functions:164 _observable_depth _obstructed _oc_to_str _occupied _off_msg _ohitmon _oinit _ok_to_quest functions:165 _okay functions:167 _onquest _onscary _open_bonesfile _open_drawbridge _open_levelfile _open_library _open_savefile _openit functions:168 _openone _OpenTileFile _opentin _option_help _oselect _other_mon_has_arti _otransit_msg functions:169 _out_container _outentry _outheader _outoracle _outrumor _p_coaligned _pacify_guards _pacify_shk functions:170 _panic _parent_dlevel _parent_dnum _parse _parse_config_line _parseoptions _pass_one _pass_three functions:171 _pass_two _passive _passivemm _passiveum _pay _pay_for_damage _paybill _paygd functions:172 _pckeys _peace_minded _peek_at_iced_corpse_age _peffects _pet_type _pgetchar _phase_of_the_moon functions:173 _pick_level _pick_lock _pick_obj _pick_room _picked_container _picking_at _picking_lock _picklock functions:174 _pickup _pickup_object _place_branch _place_level _place_lregion _place_niche _place_object _place_worm_tail_randomly functions:175 _place_wsegs _placebc _playwoRAMdisk _pleased _pline _pline_The _plnamesuffix _pluslvl functions:176 _pmatch _poisoned _poisontell _poly_gender _poly_obj _poly_when_stoned _polyman _polymon functions:177 _polyself _polyuse _port_help _pos_to_room _positionbar _possible_places _possibly_unwield _potionbreathe functions:178 _potionhit _prayer_done _precheck _prev_level _pri_move _price_quote _priest_talk _priestini functions:179 _priestname _print_branch _print_dungeon _print_queue _prinv _probe_monster _process_menu_window _process_text_window functions:180 _pronoun_gender _protects _prscore _punish _pushch _put_monsters_to_sleep _putsyms functions:181 _qt_montype _qt_pager _query_category _query_classes _query_objlist _quest_chat _quest_info functions:182 _quest_stat_check _quest_talk _random_dir _random_engraving _random_teleport_level _ranged_attk functions:183 _rank _rank_of _raw_printf _read_config_file _read_engr_at _readchar _readentry functions:184 _readmail _readobjnam _ReadPlanarTileFile _ReadPlanarTileFile_O _ReadTileFileHeader _reassign _recalc_wt _recharge functions:185 _record_exists _redist_attr _redotoplin _regularize _rehumanize _rejectoption _relink_light_sources _relink_timers functions:186 _relmon _remember_topl _remove_damage _remove_object _remove_rect _remove_timer _remove_worm functions:187 _removetopl _reorder_invent _repair_damage _replmon _replshk _rescham functions:188 _reset_eat _reset_faint _reset_hostility _reset_occupations _reset_pick _reset_remarm _reset_rndmonst _reset_trapset functions:189 _resetobjs _resist _resists_blnd _resists_drli _resists_magm _rest_engravings _rest_room _rest_rooms functions:190 _rest_worm _restartcham _restdamage _restfakecorr _restgamestate _restlevchn _restlevelfile _restlevelstate functions:191 _restmonchn _restnames _restobjchn _restore_artifacts _restore_attrib _restore_dungeon _restore_light_sources _restore_oracles functions:192 _restore_saved_game _restore_timers _restore_waterlevel _restpriest _restrap _restrict_name _restshk _resurrect functions:193 _reverse _revive _revive_corpse _revive_egg _revive_mon _revive_nasty _reward_untrap _rhack functions:194 _right_side _rile_shk _Ring_gone _Ring_off _Ring_off_or_gone _Ring_on _rloc _rloc_engr functions:195 _rloc_pos_ok _rloc_to _rloco _rm_waslit _rnd_class _rnd_defensive_item functions:196 _rnd_misc_item _rnd_offensive_item _rnd_rect _rndcurse _rnddoor _rndexp _rndghostname _rndmonnam functions:197 _rndmonnum _rndmonst _rndtrap _rne _rnl _rnz _rogue_vision _roguecorr functions:198 _roguejoin _roguename _rot_corpse _rot_organic _rottenfood _rounddiv _row_refresh _run_timers functions:199 _rust_dmg _s_suffix _safe_teleds _saleable _same_price _sanity_check _save_artifacts _save_currentstate functions:200 _save_dungeon _save_engravings _save_light_sources _save_oracles _save_room _save_rooms _save_savefile_name _save_timers functions:201 _save_waterlevel _save_worm _savebones _savech _savedamage _saveDiskPrompt _savefruitchn _savegamestate functions:202 _savelev _savelev0 _savelevchn _savelife _savemonchn _savenames _saveobjchn _savestateinlock functions:203 _savetrapchn _scatter _schedule_goto _score_wanted _search_door _search_special _searches_for_item _see_lamp_flicker functions:204 _see_monsters _see_objects _see_traps _see_wsegs _seemimic _seetrap _seffects _select_hwep functions:205 _select_off _select_rwep _selftouch _sellobj _sellobj_state _sengr_at _sense_trap functions:206 _set_all_on_page _set_apparxy _set_artifact_intrinsic _set_bc _set_bonesfile_name _set_bonestemp_name _set_corn _set_cost functions:207 _set_crosswall _set_entity _set_item_state _set_itimeout _set_levelfile_name _set_lit _set_lock_and_bones _set_malign functions:208 _set_mimic_blocking _set_mimic_sym _set_mon_data _set_moreluck _set_occupation _set_repo_loc _set_residency _set_savefile_name functions:209 _set_seenv _set_trap _set_twall _set_uasmon _set_wall _set_wall_property _set_wall_state _set_wear functions:210 _set_wounded_legs _set_wportal _setclipped _setftty _setgemprobs _setmangry _setnotworn _setpaid functions:211 _setrandom _settrack _settty _setup_waterlevel _setuwep _setworn _sgn _Shield_off functions:212 _shieldeff _ship_object _shk_chat _shk_embellish _shk_move _shk_names_obj _shk_owns _shk_your functions:213 _Shk_Your _shkcatch _shkgone _shkinit _shkname _sho_obj_return_to_u _shop_debt _shop_keeper functions:214 _shop_object _shopdig _shopper_financial_report _shrine_pos _shrink_worm _shuffle functions:215 _shuffle_all _shuffle_tiles _simple_look _singular _sitoa _skill_advance _skill_init _skill_level_name functions:216 _skinback _sleep_monst _slept_monst _slip_or_trip _sliparm _slots_required _snuff_candle _snuff_light_source functions:217 _snuff_lit _sobj_at _some_armor _somegold _somex _somexy _somey _sort_rooms functions:218 _sort_valuables _sp_lev_shuffle _spec_ability _spec_abon _spec_applies _spec_dbon _spell_damage_bonus _spell_hit_bonus functions:219 _spell_skilltype _spelleffects _spitmu _splatter_burning_oil _split_mon _split_rects _splitbill _splitobj functions:220 _spoteffects _squadmon _srandom _stackobj _standoutbeg _standoutend _start_corpse_timeout _start_eating functions:221 _start_engulf _start_timer _start_tin _steal _steal_it _stealamulet _stealarm _stealgold functions:223 _stop_timer _store_version _strange_feeling _strategy _string_for_env_opt _string_for_opt _strncmpi _strprepend functions:224 _strstri _study_book _stumble_onto_mimic _sub_one_frombill _subfrombill _substitute_tiles _summon_minion _surface functions:225 _swallow_to_glyph _swapin_file _swapout_oldest _switch_symbols _switchar _t_warn functions:226 _tabexpand _tactics _take_gold _take_off _tamedog _target_on _tele _tele_jump_ok functions:227 _tele_restrict _tele_trap _teleds _teleok _teleport_pet _temple_occupied _tended_shop _term_end_attr functions:228 _term_end_color functions:229 _The _this_type_only _thitm _thitmonst _thitu _throw_gold _throwing_weapon _throwit functions:230 _thrwmu _tileview _timed_occupation _timer_is_local _timer_sanity_check _tinnable _title_to_mon _tmp_at functions:231 _topl_putsym _topologize _topten _topten_print _topten_print_bold _toss_up _toss_wsegs _touch_artifact functions:232 _touchfood _trap_detect _trickery _try_disarm _try_lift _trycall _tt_oname _tty_add_menu functions:233 _tty_askname _tty_clear_nhwindow _tty_cliparound functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _tty_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event functions:235 _tty_getlin _tty_init_nhwindows _tty_mark_synch _tty_message_menu _tty_nh_poskey _tty_nhbell _tty_nhgetch _tty_number_pad functions:236 _tty_player_selection _tty_raw_print _tty_raw_print_bold _tty_resume_nhwindows _tty_select_menu functions:237 _tty_start_menu _tty_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function functions:238 _txt_backsp _txt_cl_end _txt_cl_eos _txt_clear_screen _txt_get_scr_size _txt_monoadapt_check functions:239 _txt_nhbell _txt_startup _u_entered_shop _u_gname _u_init functions:240 _u_left_shop _u_on_dnstairs _u_on_newpos _u_on_sstairs _u_on_upstairs _u_slip_free _u_slow_down _u_teleport_mon functions:241 _u_to_e _u_wipe_engr _ugolemeffects _um_dist _unbless _unblock_point _uncommon functions:242 _unconscious _uncurse _undead_to_corpse _under_ground _under_water _undiscover_object _unearth_objs _unfaint functions:243 _unleash_all _unload_qtlist _unlock_file _unmap_object _unmul _unpaid_cost _unplacebc _unpunish functions:244 _unrestrict_weapon_skill _unset_all_on_page _unsetup_waterlevel _unstuck _untrap _untrap_prob _unturn_dead _update_mon_intrinsics functions:245 _update_topl _uptodate _urustm _use_bell _use_camera _use_candelabrum _use_candle _use_container functions:246 _use_crystal_ball _use_defensive _use_figurine _use_grease _use_lamp _use_leash _use_magic_whistle _use_mirror functions:247 _use_misc _use_offensive _use_pick_axe _use_skill _use_stethoscope _use_tinning_kit _use_towel _use_trap functions:248 _use_unicorn_horn _use_whip _use_whistle _useup _useupall _useupf _ustatusline _uunstick functions:249 _uwepgone _vault_occupied _vault_tele _verbalize _vga_backsp _vga_cl_end _vga_cl_eos _vga_clear_screen functions:250 _vga_cliparound _vga_detect _vga_DisplayCell _vga_DisplayCell_O _vga_DrawCursor _vga_Finish _vga_FontPtrs _vga_get_scr_size functions:251 _vga_gotoloc _vga_HideCursor _vga_Init _vga_overview _vga_redrawmap _vga_refresh _vga_SetPalette _vga_SwitchMode functions:252 _vga_traditional _vga_tty_end_screen _vga_tty_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc functions:254 _vision_reset _dodiscovered _dodoor _dodown _dodrink _dodrop _doeat _doengrave functions:255 _wallification _wallify_map _wallify_vault _wantdoor _watch_on_duty _water_damage _water_friction functions:256 _water_prayer _weapon_dam_bonus _weapon_hit_bonus _weapon_type _wearing_armor _weffects _weight functions:257 _weight_cap functions:258 _whimper _wield_tool _wildmiss _win_tty_init _wipe_engr_at _wipeoff _wipeout_text functions:259 _wiz_detect _wiz_genesis _wiz_identify _wiz_level_tele _wiz_light_sources _wiz_map _wiz_show_seenv _wiz_show_vision functions:260 _wiz_show_wmodes _wiz_timeout_queue _wiz_where _wiz_wish _wizdead _worm_known _worm_move _worm_nomove functions:261 _wormgone _wormhitu _worn_wield_only _write_ls _writeentry _wrong_elem_type _x_monnam _xcrypt _xkilled _xlev_to_rank _xname _xprname functions:263 _xytod _yelp _yname _Yname2 _You _you_aggravate _You_cant _You_feel _you_have _You_hear _you_unwere _you_were _Your _zap_dig functions:265 _zap_hit _zap_over_floor _zap_updown _zapdir_to_glyph _zapnodir _zappable _zapyourself _zhitm _zhitu _put_lregion_here _role_init ; tuning ; this was 23 functions:266 _bp_to_obj ; the next two were 238 functions:268 _aggravate ; the following were 118 ;functions:269 ; the following were 261 ;functions:270 functions:271 _xputg functions:272 _xputs _xwaitforspace ; the following were 158 functions:273 _enermod _enlightenment ; the following was 214 ;functions:274 _enter_explore_mode ; the following were 26 functions:275 _bydoor functions:276 _calc_capacity _call_kops _calm_nymphs functions:277 _can_advance _can_be_hatched functions:278 _can_carry ; the following were 239 functions:279 _equipname functions:280 _txt_xputs ; the following were 80 functions:281 _enexto ;functions:282 functions:283 _enhance_weapon_skill ; the following were 165 functions:284 _okdoor functions:285 _omon_adj functions:286 _on_goal functions:287 _on_ground functions:288 _b_trapped functions:289 _on_locate functions:290 _on_msg ; the following were 182 functions:291 _y_monnam ; the following were 195 ;functions:293 ; the following were 225 functions:294 _erode_armor functions:295 _swallowed ; the following were 7 functions:298 _acurrstr ; the following were 17 functions:299 _attacktype functions:300 _attrcurse functions:301 _automiss functions:302 _autopick ; the following were 10 functions:303 _adj_abon functions:304 _adj_lev functions:305 _adjabil functions:306 _adjalign functions:307 _adjattrib ; was 53 functions:308 _display_monster functions:309 _error ; was 117 ;functions:310 functions:311 _is_ok_location ;functions:312 functions:313 _is_pure functions:314 _is_quest_artifact ; was 236 functions:316 _tty_putstr _tty_putsym ; was 81 functions:318 _escapes functions:319 _erase_menu_or_text functions:320 _eraseall ; tuning 2 ; was 269 functions:321 _weldmsg _were_change _were_summon functions:322 _where_name _which_armor _which_arti functions:325 _term_end_raw_bold functions:326 _term_start_attr ;functions:327 functions:328 _term_start_raw_bold functions:329 _terminate functions:330 _tgetch functions:331 _the functions:332 _m_monnam functions:333 _domagictrap _domindblast _domonability functions:334 _m_respond functions:335 _m_slips_free functions:336 _m_throw functions:337 _m_to_e functions:338 _m_unleash functions:339 _mpickstuff functions:340 _mplayer_talk functions:341 _mpoisons_subj functions:342 _mquaffmsg functions:343 _miss functions:344 _mreadmsg functions:345 _mrustm functions:346 _vomit _vomiting_dialogue functions:347 _wake_nearby functions:348 _wake_nearto functions:349 _wakeup functions:350 _walkfrom functions:351 _wall_angle functions:352 _able_to_loot _add_mon_to_reg _add_rect_to_reg _add_region _addinv_core1 functions:352 _addinv_core2 _age_spells _align_gtitle _align_shift _align_str _all_but_uchain functions:353 _allow_all _allow_category _already_wearing _already_wearing2 _angrygods functions:354 _animate_statue _antholemon _arti_speak _assign_warnings _attach_fig_transform_timeout _blocked_boulder functions:355 _book_substitution _burn_away_slime _can_blnd _can_ride _can_saddle _can_twoweapon functions:356 _carry_obj_effects _clear_regions _container_at _coyotename _create_gas_cloud _create_region functions:357 _describe_level _dfeature_at _dig_up_grave _discover_artifact _dismount_steed _disp_artifact_discoveries functions:359 _doconduct _dofire _doprinuse _doride _doswapweapon _dotwoweapon functions:360 _dowieldquiver _drain_item _exercise_steed _expire_gas_cloud _extcmd_via_menu _feature_alert_opts functions:361 _fig_transform _figurine_location_checks _final_level _find_trap _finish_quest _fix_petrification functions:362 _food_substitution _fqname _free_invbuf _free_region _free_youbuf _freeinv_core functions:363 _fuzzymatch _get_compopt_value _get_current_feature_ver _get_feature_notice_ver _get_mtraits _getlev functions:364 _getlock _getobj _getpos _give_may_advance_msg _Goodbye _halu_gname functions:365 _Hello _hurtle_step _hurtmarmor _in_out_region _initialspell _inside_gas_cloud functions:366 _inside_rect _inside_region _kick_steed _look_here _m_in_out_region _make_grave functions:367 _mbodypart _mdamagem _mdamageu _minimal_enlightenment _mk_mplayer_armor _mm_aggression functions:368 _mon_adjust_speed _mon_animal_list _mon_beside _mon_in_region _montraits _mount_steed functions:369 _noit_mon_nam _noit_Monnam _noncoalignment _num_genocides _obj_attach_mid _obj_timer_checks functions:370 _obj_typename _ok_align _ok_gend _ok_race _ok_role _ordin functions:371 _pick_align _pick_animal _pick_gend _pick_nasty _pick_race _pick_role functions:372 _place_monster _pm_to_cham _prisoner_speaks _process_options _randalign _randgend functions:373 _randrace _randrole _relobj _remove_mon_from_reg _remove_region functions:374 _remove_worn_item _replace_object _reset_oattached_mids _rest_regions _restore_cham _rnd_treefruit_at functions:375 _save_regions _select_newcham_form _self_invis_message _setuqwep _setuswapwep _show_conduct functions:376 _show_region _simple_typename _slime_dialogue _sokoban_detect _spec_m2 _special_handling functions:377 _str2align _str2gend _str2race _str2role _There _throw_obj functions:378 _tmiss _tty_update_positionbar _tty_wait_synch _undiscovered_artifact _untwoweapon _update_mlstmv functions:379 _update_monster_region _update_player_regions _uqwepgone _ureflects _use_grapple _use_pole functions:380 _use_saddle _uswapwepgone _uwep_skill_type _validalign _validgend _validrace functions:381 _validrole _violated_vegetarian _walk_path _warning_opts _wary_dog _welcome functions:382 _write_timer _yyyymmdd _zap_steed functions:383 _getprice _getreturn _getrumor _gettrack functions:384 _ini_inv _knows_object _knows_class _restricted_spell_discipline _ready_weapon functions:385 _doname _Doname2 functions:386 _minliquid functions:387 _missmm functions:388 _missmu functions:389 _missum functions:390 _mixtype _mk_artifact functions:391 _makesingular functions:392 _maketrap _makevtele _makewish functions:393 _add_erosion_words ; functions:395 _display_pickinv functions:396 _do_class_genocide functions:397 _dochat functions:398 _domonnoise ; ; ; ; functions:403 _find_file functions:404 _forget functions:405 _forget_single_object functions:406 _getlt functions:407 _getpos_help ; ; ; functions:411 _lib_dlb_cleanup functions:412 _lib_dlb_fclose functions:413 _lib_dlb_fgetc functions:414 _lib_dlb_fgets functions:415 _lib_dlb_fopen functions:416 _lib_dlb_fread functions:417 _lib_dlb_fseek functions:418 _lib_dlb_ftell functions:419 _lib_dlb_init functions:420 _maybe_tame ; functions:422 _mon_in_room functions:423 _nextobuf functions:424 _p_glow1 functions:425 _p_glow2 functions:426 _popch functions:427 _randomize functions:428 _readlibdir functions:429 _reset_region_mids functions:430 _rob_shop functions:431 _stripspe ; ; ; functions:435 _wand_explode functions:436 _wishymatch functions:437 _abil_to_adtyp functions:438 _abil_to_spfx functions:439 _accessory_has_effect functions:440 _add_autopickup_exception functions:441 _add_class functions:442 _adj_pit_checks functions:443 _after_shk_move functions:444 _alter_cost functions:445 _anything_to_s functions:446 _arti_cost functions:447 _arti_immune functions:448 _arti_reflects functions:449 _artifact_has_invprop functions:450 _artifact_light functions:451 _artifact_score functions:452 _assign_hilite functions:453 _attacktype_fordmg functions:454 _attk_protection functions:455 _bagotricks functions:456 _bare_artifactname functions:457 _billable functions:458 _bogon_is_pname functions:459 _book_disappears functions:460 _bottlename functions:461 _bounded_increase functions:461 _br_string2 functions:463 _buried_ball functions:464 _buried_ball_to_freedom functions:465 _buried_ball_to_punishment functions:466 _bypass_obj functions:467 _can_blow functions:468 _can_fog functions:469 _can_reach_location functions:470 _cant_reach_floor ; functions:471 _cant_revive functions:472 _cant_squeeze_thru functions:473 _cant_wield_corpse functions:474 _cast_cleric_spell functions:475 _cast_wizard_spell functions:476 _catch_lit functions:477 _check_caitiff functions:478 _check_innate_abil functions:479 _choose_clerical_spell functions:480 _choose_magic_spell functions:481 _ckvalidcat functions:482 _clear_bypasses functions:483 _clear_conjoined_pits functions:484 _clear_status_hilites functions:485 _climb_pit functions:486 _cloak_simple_name functions:487 _clridx_to_s functions:488 _cmd_from_func functions:489 _compare_blstats functions:490 _complain_about_duplicate functions:491 _confers_luck functions:492 _confused_book functions:493 _conjoined_pits functions:494 _consume_obj_charge functions:495 _consume_oeaten functions:496 _container_gone functions:497 _container_impact_dmg functions:498 _copy_mextra functions:499 _copy_oextra functions:500 _corpse_revive_type functions:501 _costly_alteration functions:502 _costly_tin functions:503 _could_advance functions:504 _could_reach_item functions:505 _count_ape_maps functions:506 _count_buc functions:507 _critically_low_hp functions:508 _currency functions:509 _cxname functions:510 _dealloc_killer functions:511 _dealloc_mextra functions:512 _dealloc_monst functions:513 _dealloc_oextra functions:514 _decal_planar functions:515 _decide_to_shapeshift functions:516 _def_bclose functions:517 _def_bflush functions:518 _def_bufoff functions:519 _def_bufon functions:520 _def_bwrite functions:521 _def_minit functions:522 _def_mread functions:523 _delayed_killer functions:524 _deliver_splev_message functions:525 _detect_obj_traps functions:526 _detect_wsegs functions:527 _disarm_holdingtrap functions:528 _disintegrate_mon functions:529 _display_used_invlets functions:530 _distant_monnam functions:531 _dmgtype_fromattack functions:532 _dogaze functions:533 _donamelevel functions:534 _doorless_door functions:535 _dooverview functions:536 _dooverview_or_wiz_where functions:537 _dopoly functions:538 _dotip functions:539 _dotravel functions:540 _dowhatdoes_core functions:541 _drop_uswapwep functions:542 _droppables functions:543 _eat_brains functions:544 _edibility_prompts functions:545 _enexto_core functions:546 _erode_obj functions:547 _fatal_corpse_mistake functions:548 _feeltrap functions:549 _find_delayed_killer functions:550 _find_mapseen functions:551 _finish_meating functions:552 _fire_damage functions:553 _flashburn functions:554 _fopen_wizkit_file functions:555 _force_launch_placement functions:556 _forget_mapseen functions:557 _forget_temple_entry functions:558 _free_epri functions:559 _free_mname functions:560 _free_omailcmd functions:561 _free_omid functions:562 _free_omonst functions:563 _free_oname functions:564 _from_what _fruitname _gain_guardian_angel _gcrownu functions:565 _genl_preference_update _genl_status_enablefield _genl_status_finish _genl_status_init functions:566 _genl_status_threshold _genl_status_update _genus _get_adjacent_loc functions:567 _get_container_location _get_plname_from_file _get_status_hilites _getmattk functions:568 _gold_in _gulp_blnd_check _helm_simple_name _help_dir functions:569 _hideunder _hits_bars _hornoplenty _in_town functions:570 _inhistemple _init_blstats _init_mapseen _innately functions:571 _interest_mapseen _intersect _is_autopickup_exception _is_digging functions:572 _is_innate _is_izchak _is_rottable _is_undirected_spell functions:573 _is_wc_option _is_wc2_option _joust _keep_saddle_with_steedcorpse functions:574 _killer_xname _landing_spot _launch_in_progress _learnscroll functions:575 _learnscrolltyp _learnwand _liquid_flow _load_mapseen functions:576 _long_to_any _loot_mon _lose_guardian_angel _m_useupall functions:577 _magic_negation _make_slimed _make_stoned _mapglyph functions:578 _maybe_cannibal _maybe_finished_meal _Mb_hit _mbag_item_gone functions:579 _mbirth_limit _mcould_eat_tin _mdisplacem _mdrop_obj functions:580 _mdrop_special_objs _meatmetal _melt_ice_away _mhurtle functions:581 _mhurtle_step _mimic_hit_msg _mimic_obj_name _mkveggy_at functions:582 _mm_displacement _mon_aligntyp _mon_consume_unstone _mon_hates_silver functions:583 _monflee _mongrantswish _monhaskey _monhp_per_lvl functions:584 _monst_to_any _mshot_xname _new_mname _new_omailcmd functions:585 _new_oname _newedog _newegd _newemin functions:586 _newepri _neweshk _newmextra _newmonhp functions:587 _newoextra _newolong _newomid _newomonst functions:588 _newpw _nextmbuf _nh_compress _nh_uncompress functions:589 _num_horns _nxtobj _o_material _obj_has_timer functions:590 _obj_no_longer_held _obj_shuffle_range _obj_to_any _observe_quantum_cat functions:591 _odds_and_ends _olfaction _on_fire _otense functions:592 _paniclog _paralyze_monst _passes_bars _passive_obj functions:593 _peaked_skill _peek_timer _percentage _pit_flow functions:594 _Popeye _postadjabil _print_mapseen _propagate functions:595 _put_gold_back _putting_on _quickmimic _race_alignmentcount functions:596 _raceptr _racial_exception _read_wizkit _recalc_mapseen functions:597 _recbranch_mapseen _redraw_cmd _remdun_mapseen _remote_burglary functions:598 _remove_autopickup_exception _remove_room _remove_rooms _reset_commands functions:599 _reset_restpref _rest_levl _restmon _restobj functions:600 _restore_killers _restore_msghistory _rider_cant_reach _rndcolor functions:601 _role_gendercount _root_plselection_prompt _rouse_shk _rumor_check functions:602 _s_to_anything _safe_oname _safe_qbuf _same_race functions:603 _save_killers _save_mapseen _save_msghistory _savelevl functions:604 _savemon _saveobj _seen_string _set_corpsenm functions:605 _set_option_mod_status _set_restpref _set_status_hilites _set_tin_variety functions:606 _setmnotwielded _setrolefilter _shade_aware _Shield_on functions:607 _Shirt_off _Shirt_on _shkname_is_pname _shkveg functions:608 _shop_string _should_displace _should_query_disclose_option _silly_thing functions:609 _size_monst _size_obj _skip_pager _skiprange functions:610 _sortspells _special_stock _spell_backfire _spell_cmp functions:611 _spell_would_be_useless _spellretention _spellsortmenu _spot_stop_timers functions:612 _spot_time_expires _spot_time_left _stagger _start_melt_ice_timeout functions:613 _status_finish _status_hilite_menu _status_initialize _steedintrap functions:614 _Sting_effects _store_plname_in_file _store_savefileinfo _strkitten functions:615 _strsubst _stuck_ring _stuff_prevents_passage _taking_off functions:616 _test_move _the_unique_obj _the_unique_pm _theft_petrifies functions:617 _tin_details _tin_variety _tin_variety_txt _tipcontainer functions:618 _Tobjnam _tty_getmsghistory _tty_putmsghistory _uhave_graystone functions:619 _unchanger _undesirable_disp _unfixable_trouble_count _unplaced_floater functions:620 _unreachable_level _upstart _use_cream_pie _use_pick_axe2 functions:621 _use_stone _usmellmon _uteetering_at_seen_pit _validate functions:622 _validate_prefix_locations _vamp_shift _vault_gd_watching _veggy_item functions:623 _version_string _vtense _watch_dig _waterbody_name functions:624 _wc_set_font_name _wc_set_window_colors _wc_supported _wc2_supported functions:625 _weapon_descr _what_gives _wielding_corpse _will_feel_cockatrice functions:626 _wiz_level_change _wiz_map_terrain _wiz_mon_polycontrol _wiz_panic functions:627 _wiz_polyself _wiz_rumor_check _wiz_smell _worst_cursed_item functions:628 _yn_function _yobjnam _Yobjnam2 _You_see functions:629 _ysimple_name nethack-3.6.0/sys/msdos/setup.bat0000775000076400007660000001275512536476415015762 0ustar paxedpaxed@echo off REM NetHack 3.6 setup.bat $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ REM Copyright (c) NetHack PC Development Team 1990 - 2012 REM NetHack may be freely redistributed. See license for details. echo. echo Copyright (c) NetHack PC Development Team 1990 - 2012 echo NetHack may be freely redistributed. See license for details. echo. REM setup batch file for msdos, see Install.dos for details. if not %1.==. goto ok_parm goto err_set :ok_parm echo Checking to see if directories are set up properly ... if not exist ..\..\include\hack.h goto err_dir if not exist ..\..\src\hack.c goto err_dir if not exist ..\..\dat\wizard.des goto err_dir if not exist ..\..\util\makedefs.c goto err_dir if not exist ..\..\win\tty\wintty.c goto err_dir if not exist ..\share\lev_yacc.c goto err_dir echo Directories OK. if not exist ..\..\binary\* mkdir ..\..\binary if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul if exist ..\..\dat\data.bas goto long1ok if exist ..\..\dat\data.base goto long1a if exist ..\..\dat\data~1.bas goto long1b goto err_long :long1a echo Changing some long-named distribution file names: echo "Copying ..\..\dat\data.base -> ..\..\dat\data.bas" copy ..\..\dat\data.base ..\..\dat\data.bas if exist ..\..\dat\data.old del /Q ..\..\dat\data.old ren ..\..\dat\data.base data.old goto long1ok :long1b echo Changing some long-named distribution file names: echo "Copying ..\..\dat\data~1.bas -> ..\..\dat\data.bas" copy ..\..\dat\data~1.bas ..\..\dat\data.bas if exist ..\..\dat\data.old del /Q ..\..\dat\data.old ren ..\..\dat\data~1.bas data.old :long1ok if exist ..\..\include\patchlev.h goto long2ok if exist ..\..\include\patchlevel.h goto long2a if exist ..\..\include\patchl~1.h goto long2b goto err_long :long2a echo "Copying ..\..\include\patchlevel.h -> ..\..\include\patchlev.h" copy ..\..\include\patchlevel.h ..\..\include\patchlev.h if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old ren ..\..\include\patchlevel.h patchlev.old goto long2ok :long2b echo "Copying ..\..\include\patchl~1.h -> ..\..\include\patchlev.h" copy ..\..\include\patchl~1.h ..\..\include\patchlev.h if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old ren ..\..\include\patchl~1.h patchlev.old :long2ok REM Missing guidebook is not fatal to the build process if exist ..\..\doc\guideboo.txt goto long3ok if exist ..\..\doc\guidebook.txt goto long3a if exist ..\..\doc\guideb~1.txt goto long3b goto warn3long :long3a echo "Copying ..\..\doc\guidebook.txt -> ..\..\doc\guideboo.txt" copy ..\..\doc\guidebook.txt ..\..\doc\guideboo.txt if exist ..\..\doc\guideboo.old del /Q ..\..\doc\guideboo.old ren ..\..\doc\guidebook.txt guideboo.old goto long3ok :long3b echo "Copying ..\..\doc\guideb~1.txt -> ..\..\doc\guideboo.txt" copy ..\..\doc\guideb~1.txt ..\..\doc\guideboo.txt if exist ..\..\doc\guideboo.old del /Q ..\..\doc\guideboo.old ren ..\..\doc\guideb~1.txt guideboo.old goto long3ok :warn3long echo "Warning - There is no NetHack Guidebook (..\..\doc\guideboo.txt)" echo " included in your distribution. Build will proceed anyway." :long3ok if "%1"=="GCC" goto ok_gcc if "%1"=="gcc" goto ok_gcc if "%1"=="nmake" goto ok_msc if "%1"=="NMAKE" goto ok_msc if "%1"=="BC" goto ok_bc if "%1"=="bc" goto ok_bc if "%1"=="MSC" goto ok_msc if "%1"=="msc" goto ok_msc goto err_set :ok_gcc echo Symbolic links, msdos style echo "Makefile.GCC -> ..\..\src\makefile" copy makefile.GCC ..\..\src\makefile goto done :ok_msc echo Copying Makefile for Microsoft C and Microsoft NMAKE. echo "Makefile.MSC -> ..\..\src\makefile" copy Makefile.MSC ..\..\src\makefile echo Copying overlay schemas to ..\..\src copy schema*.MSC ..\..\src\schema*.DEF :ok_cl goto done :ok_bc echo Copying Makefile for Borland C and Borland's MAKE. echo "Makefile.BC -> ..\..\src\makefile" copy Makefile.BC ..\..\src\makefile echo Copying overlay schemas to ..\..\src copy schema*.BC ..\..\src goto done :err_long echo. echo ** ERROR - New file system with "long file name support" problem. ** echo A couple of NetHack distribution files that are packaged with echo a long filename ( exceeds 8.3) appear to be missing from your echo distribution. echo The following files need to exist under the names on the echo right in order to build NetHack: echo. echo ..\..\dat\data.base needs to be copied to ..\..\dat\data.bas echo ..\..\include\patchlevel.h needs to be copied to ..\..\include\patchlev.h echo. echo setup.bat was unable to perform the necessary changes because at least echo one of the files doesn't exist under its short name, and the echo original (long) file name to copy it from was not found either. echo. goto end :err_set echo. echo Usage: echo "%0 " echo. echo Run this batch file specifying on of the following: echo GCC, MSC, BC echo. echo (depending on which compiler and/or make utility you are using). echo. echo The GCC argument is for use with djgpp and the NDMAKE utility. echo. echo The MSC argument is for use with Microsoft C and the NMAKE utility echo that ships with it (MSC 7.0 or greater only, including Visual C). echo. echo The BC argument is for use with Borland C and Borland's MAKE utility echo that ships with it (Borland C++ 3.1 only). echo. goto end :err_dir echo/ echo Your directories are not set up properly, please re-read the echo Install.dos and README documentation. goto end :done echo Setup Done! echo Please continue with next step from Install.dos. :end nethack-3.6.0/sys/msdos/sound.c0000664000076400007660000001736712536476415015427 0ustar paxedpaxed/* NetHack 3.6 sound.c $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) NetHack PC Development Team 1993,1995 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * sound.c - Hardware sound support * *Edit History: * Initial Creation 93/10/01 * Added PC Speaker Support for BC compilers 95/06/14 * Completed various fixes 96/02/19 * */ #include "hack.h" #include #include "portio.h" #include #include #ifndef TESTING #define printf pline int assign_soundcard(sopt) char *sopt; { iflags.hassound = 0; #ifdef PCMUSIC iflags.usepcspeaker = 0; #endif if (strncmpi(sopt, "def", 3) == 0) { /* default */ /* do nothing - default */ } #ifdef PCMUSIC else if (strncmpi(sopt, "speaker", 7) == 0) { /* pc speaker */ iflags.usepcspeaker = 1; } #endif else if (strncmpi(sopt, "auto", 4) == 0) { /* autodetect */ /* * Auto-detect Priorities (arbitrary for now): * Just pcspeaker */ if (0) ; #ifdef PCMUSIC else iflags.usepcspeaker = 1; #endif } else { return 0; } return 1; } #endif #ifdef PCMUSIC /* 8254/3 Control Word Defines */ #define CTR0SEL (0 << 6) #define CTR1SEL (1 << 6) #define CTR2SEL (2 << 6) #define RDBACK (3 << 6) #define LATCH (0 << 4) #define RW_LSB (1 << 4) #define RW_MSB (2 << 4) /* If both LSB and MSB are read, LSB is done first \ */ #define MODE0 (0 << 1) /* Interrupt on terminal count */ #define MODE1 (1 << 1) /* Hardware One-Shot */ #define MODE2 (2 << 1) /* Pulse Generator */ #define MODE3 (3 << 1) /* Square Wave Generator */ #define MODE4 (4 << 1) /* Software Triggered Strobe */ #define MODE5 (5 << 1) /* Hardware Triggered Strobe */ #define BINARY (0 << 0) /* Binary counter (16 bits) */ #define BCD (1 << 0) /* Binary Coded Decimal (BCD) Counter (4 Decades) */ /* Misc 8254/3 Defines */ #define TIMRFRQ (1193180UL) /* Input frequency to the clock (Hz) */ /* Speaker Defines */ #define TIMER (1 << 0) /* Timer 2 Output connected to Speaker */ #define SPKR_ON (1 << 1) /* Turn on/off Speaker */ /* Port Definitions */ /* 8254/3 Ports */ #define CTR0 0x40 #define CTR1 0x41 #define CTR2 0x42 #define CTRL 0x43 /* Speaker Port */ #define SPEAKER 0x61 void startsound(unsigned freq) { /* To start a sound on the PC: * * First, set the second counter to have the correct frequency: */ unsigned count; if (freq == 0) freq = 523; count = TIMRFRQ / freq; /* Divide frequencies to get count. */ #ifdef TESTING printf("freq = %u, count = %u\n", freq, count); #endif outportb(CTRL, CTR2SEL | RW_LSB | RW_MSB | MODE3 | BINARY); outportb(CTR2, count & 0x0FF); outportb(CTR2, count / 0x100); /* Next, turn on the speaker */ outportb(SPEAKER, inportb(SPEAKER) | TIMER | SPKR_ON); } void stopsound(void) { outportb(SPEAKER, inportb(SPEAKER) & ~(TIMER | SPKR_ON)); } static unsigned tempo, length, octave, mtype; /* The important numbers here are 287700UL for the factors and 4050816000UL * which gives the 440 Hz for the A below middle C. "middle C" is assumed to * be the C at octave 3. The rest are computed by multiplication/division of * 2^(1/12) which came out to 1.05946 on my calculator. It is assumed that * no one will request an octave beyond 6 or below 0. (At octave 7, some * notes still come out ok, but by the end of the octave, the "notes" that * are produced are just ticks. * These numbers were chosen by a process based on the C64 tables (which * weren't standardized) and then were 'standardized' by giving them the * closest value. That's why they don't seem to be based on any sensible * number. */ unsigned long notefactors[12] = { 483852, 456695, 431063, 406869, 384033, 362479, 342135, 322932, 304808, 287700, 271553, 256312 }; void note(long notenum) { startsound((unsigned) (4050816000UL / notefactors[notenum % 12] >> (7 - notenum / 12))); } int notes[7] = { 9, 11, 0, 2, 4, 5, 7 }; char * startnote(char *c) { long n; n = notes[toupper(*c++) - 'A'] + octave * 12; if (*c == '#' || *c == '+') { n++; c++; } else if (*c == '-') { if (n) n--; c++; } note(n); return --c; } void delaytime(unsigned time) { /* time and twait are in units of milliseconds */ unsigned twait; switch (toupper(mtype)) { case 'S': twait = time / 4; break; case 'L': twait = 0; break; default: twait = time / 8; break; } msleep(time - twait); stopsound(); msleep(twait); } char * delaynote(char *c) { unsigned time = 0; while (isdigit(*c)) time = time * 10 + (*c++ - '0'); if (!time) time = length; time = (unsigned) (240000 / time / tempo); while (*c == '.') { time = time * 3 / 2; c++; } delaytime(time); return c; } void initspeaker(void) { tempo = 120, length = 4, octave = 3, mtype = 'N'; } void play(char *tune) { char *c, *n; unsigned num; for (c = tune; *c;) { sscanf(c + 1, "%u", &num); for (n = c + 1; isdigit(*n); n++) /* do nothing */ ; if (isspace(*c)) c++; else switch (toupper(*c)) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': c = startnote(c); case 'P': c = delaynote(++c); break; #if 0 case 'M': c++; mtype = *c; c++; break; case 'T': if (num) tempo = num; else printf ("Zero Tempo (%s)!\n", c); c = n; break; case 'L': if (num) length = num; else printf ("Zero Length (%s)!\n", c); c = n; break; case 'O': if (num <= 7) octave = num; c = n; break; case 'N': note (num); delaytime ((240000/length/tempo)); c = n; break; case '>': if (octave < 7) octave++; c++; break; case '<': if (octave) octave--; c++; break; #endif case ' ': c++; break; default: printf("Unrecognized play value (%s)!\n", c); return; } } } #ifndef TESTING void pc_speaker(struct obj *instr, char *tune) { if (!iflags.usepcspeaker) return; initspeaker(); switch (instr->otyp) { case WOODEN_FLUTE: case MAGIC_FLUTE: octave = 5; /* up one octave */ break; case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: octave = 2; /* drop two octaves */ break; case BUGLE: break; case WOODEN_HARP: case MAGIC_HARP: length = 8; mtype = 'L'; /* fast, legato */ break; } play(tune); } #else main() { char s[80]; int tool; initspeaker(); printf("1) flute\n2) horn\n3) harp\n4) other\n"); fgets(s, 80, stdin); sscanf(s, "%d", &tool); switch (tool) { case 1: octave = 5; break; case 2: octave = 2; break; case 3: length = 8; mtype = 'L'; break; default: break; } printf("Enter tune:"); fgets(s, 80, stdin); play(s); } #endif #endif /* PCMUSIC */ /* sound.c */ nethack-3.6.0/sys/msdos/tile2bin.c0000664000076400007660000002012412536476415015770 0ustar paxedpaxed/* NetHack 3.6 tile2bin.c $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994, 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 93/10/21 * ifndef MONITOR_HEAP for heaputil.c P.Winner 94/03/12 * added Borland C _stklen variable Y.Sapir 94/05/01 * fixed to use text tiles from win/share M.Allison 95/01/31 * */ #include "hack.h" #include "pcvideo.h" #include "tile.h" #include "pctiles.h" #include #ifndef MONITOR_HEAP #include #endif #include #ifdef __GO32__ #include #endif #if defined(_MSC_VER) && _MSC_VER >= 700 #pragma warning(disable : 4309) /* initializing */ #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4131) /* old style declarator */ #pragma warning(disable : 4127) /* conditional express. is constant */ #endif #ifdef __BORLANDC__ extern unsigned _stklen = STKSIZ; #endif extern char *FDECL(tilename, (int, int)); #ifdef PLANAR_FILE char masktable[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; char charcolors[MAXCOLORMAPSIZE]; #ifdef OVERVIEW_FILE struct overview_planar_cell_struct planetile; #else struct planar_cell_struct planetile; #endif FILE *tibfile1; #endif #ifdef PACKED_FILE char packtile[TILE_Y][TILE_X]; FILE *tibfile2; #endif int num_colors; pixel pixels[TILE_Y][TILE_X]; struct tibhdr_struct tibheader; static void FDECL(write_tibtile, (int)); static void FDECL(write_tibheader, (FILE *, struct tibhdr_struct *)); static void FDECL(build_tibtile, (pixel(*) [TILE_X])); #ifndef OVERVIEW_FILE char *tilefiles[] = { "../win/share/monsters.txt", "../win/share/objects.txt", "../win/share/other.txt" }; #else char *tilefiles[] = { "../win/share/monthin.txt", "../win/share/objthin.txt", "../win/share/oththin.txt" }; #endif int tilecount; int filenum; int paletteflag; int main(argc, argv) int argc; char *argv[]; { int i; struct tm *newtime; time_t aclock; char *paletteptr; if (argc != 1) { Fprintf(stderr, "usage: tile2bin (from the util directory)\n"); exit(EXIT_FAILURE); } #ifdef PLANAR_FILE #ifndef OVERVIEW_FILE tibfile1 = fopen(NETHACK_PLANAR_TILEFILE, WRBMODE); #else tibfile1 = fopen(NETHACK_OVERVIEW_TILEFILE, WRBMODE); #endif if (tibfile1 == (FILE *) 0) { Fprintf(stderr, "Unable to open output file %s\n", #ifndef OVERVIEW_FILE NETHACK_PLANAR_TILEFILE); #else NETHACK_OVERVIEW_TILEFILE); #endif exit(EXIT_FAILURE); } #endif #ifdef PACKED_FILE tibfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); if (tibfile2 == (FILE *) 0) { Fprintf(stderr, "Unable to open output file %s\n", NETHACK_PACKED_TILEFILE); exit(EXIT_FAILURE); } #endif time(&aclock); newtime = localtime(&aclock); tilecount = 0; paletteflag = 0; filenum = 0; while (filenum < 3) { if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { Fprintf(stderr, "usage: tile2bin (from the util or src directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); exit(EXIT_FAILURE); } if (!paletteflag) { paletteptr = tibheader.palette; for (i = 0; i < num_colors; i++) { *paletteptr++ = ColorMap[CM_RED][i], *paletteptr++ = ColorMap[CM_GREEN][i], *paletteptr++ = ColorMap[CM_BLUE][i]; } paletteflag++; } while (read_text_tile(pixels)) { build_tibtile(pixels); write_tibtile(tilecount); tilecount++; } (void) fclose_text_file(); ++filenum; } #if defined(_MSC_VER) tibheader.compiler = MSC_COMP; #elif defined(__BORLANDC__) tibheader.compiler = BC_COMP; #elif defined(__GO32__) tibheader.compiler = DJGPP_COMP; #else tibheader.compiler = OTHER_COMP; #endif strncpy(tibheader.ident, "NetHack 3.6 MSDOS Port binary tile file", 80); strncpy(tibheader.timestamp, asctime(newtime), 24); tibheader.timestamp[25] = '\0'; tibheader.tilecount = tilecount; tibheader.numcolors = num_colors; #ifdef PLANAR_FILE tibheader.tilestyle = PLANAR_STYLE; write_tibheader(tibfile1, &tibheader); (void) fclose(tibfile1); #ifndef OVERVIEW_FILE Fprintf(stderr, "Total of %d planar tiles written to %s.\n", tilecount, NETHACK_PLANAR_TILEFILE); #else Fprintf(stderr, "Total of %d planar tiles written to %s.\n", tilecount, NETHACK_OVERVIEW_TILEFILE); #endif #endif #ifdef PACKED_FILE tibheader.tilestyle = PACKED_STYLE; write_tibheader(tibfile2, &tibheader); Fprintf(stderr, "Total of %d packed tiles written to %s.\n", tilecount, NETHACK_PACKED_TILEFILE); (void) fclose(tibfile2); #endif exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static void write_tibheader(fileptr, tibhdr) FILE *fileptr; struct tibhdr_struct *tibhdr; { if (fseek(fileptr, 0L, SEEK_SET)) { Fprintf(stderr, "Error writing header to tile file\n"); } fwrite(tibhdr, sizeof(struct tibhdr_struct), 1, fileptr); } static void build_tibtile(pixels) pixel (*pixels)[TILE_X]; { int i, j, k, co_off; unsigned char co_mask, tmp; #ifndef OVERVIEW_FILE memset((void *) &planetile, 0, sizeof(struct planar_cell_struct)); #else memset((void *) &planetile, 0, sizeof(struct overview_planar_cell_struct)); #endif for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { for (k = 0; k < num_colors; k++) { if (ColorMap[CM_RED][k] == pixels[j][i].r && ColorMap[CM_GREEN][k] == pixels[j][i].g && ColorMap[CM_BLUE][k] == pixels[j][i].b) break; } if (k >= num_colors) Fprintf(stderr, "color not in colormap!\n"); #ifdef PACKED_FILE packtile[j][i] = k; #endif #ifdef PLANAR_FILE if (i > 7) { co_off = 1; co_mask = masktable[i - 8]; } else { co_off = 0; co_mask = masktable[i]; } tmp = planetile.plane[0].image[j][co_off]; planetile.plane[0].image[j][co_off] = (k & 0x0008) ? (tmp | co_mask) : (tmp & ~co_mask); tmp = planetile.plane[1].image[j][co_off]; planetile.plane[1].image[j][co_off] = (k & 0x0004) ? (tmp | co_mask) : (tmp & ~co_mask); tmp = planetile.plane[2].image[j][co_off]; planetile.plane[2].image[j][co_off] = (k & 0x0002) ? (tmp | co_mask) : (tmp & ~co_mask); tmp = planetile.plane[3].image[j][co_off]; planetile.plane[3].image[j][co_off] = (k & 0x0001) ? (tmp | co_mask) : (tmp & ~co_mask); #endif /* PLANAR_FILE */ } } } static void write_tibtile(recnum) int recnum; { long fpos; #ifdef PLANAR_FILE #ifndef OVERVIEW_FILE fpos = ((long) (recnum) * (long) sizeof(struct planar_cell_struct)) + (long) TIBHEADER_SIZE; #else fpos = ((long) (recnum) * (long) sizeof(struct overview_planar_cell_struct)) + (long) TIBHEADER_SIZE; #endif if (fseek(tibfile1, fpos, SEEK_SET)) { Fprintf(stderr, "Error seeking before planar tile write %d\n", recnum); } #ifndef OVERVIEW_FILE fwrite(&planetile, sizeof(struct planar_cell_struct), 1, tibfile1); #else fwrite(&planetile, sizeof(struct overview_planar_cell_struct), 1, tibfile1); #endif #endif #ifdef PACKED_FILE fpos = ((long) (recnum) * (long) sizeof(packtile)) + (long) TIBHEADER_SIZE; if (fseek(tibfile2, fpos, SEEK_SET)) { Fprintf(stderr, "Error seeking before packed tile write %d\n", recnum); } fwrite(&packtile, sizeof(packtile), 1, tibfile2); #endif } nethack-3.6.0/sys/msdos/video.c0000664000076400007660000005136212536476415015376 0ustar paxedpaxed/* NetHack 3.6 video.c $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994, 2001 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * video.c - Hardware video support front-ends * *Edit History: * Initial Creation M. Allison 1993/04/04 * Add djgpp support K. Smolkowski 1993/04/26 * Add txt/graphics mode support M. Allison 1993/10/30 * Add graphics mode cursor sim. M. Allison 1994/02/19 * Add hooks for decals on vga M. Allison 2001/04/07 */ #include "hack.h" #ifndef STUBVIDEO #include "pcvideo.h" #include "pctiles.h" #if defined(_MSC_VER) #if _MSC_VER >= 700 #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4131) /* old style declarator */ #pragma warning(disable : 4305) /* prevents complaints with MK_FP */ #pragma warning(disable : 4309) /* initializing */ #pragma warning(disable : 4759) /* prevents complaints with MK_FP */ #endif #endif /*========================================================================= * General PC Video routines. * * The following routines are the video interfacing functions. * In general these make calls to more hardware specific * routines in other source files. * * Assumptions (94/04/23): * * - Supported defaults.nh file video options: * * If OPTIONS=video:autodetect is defined in defaults.nh then * check for a VGA video adapter. If one is detected, then * use the VGA code, otherwise resort to using the 'standard' * video BIOS routines. * * If OPTIONS=video:vga is defined in defaults.nh, then use * the VGA code. * * If OPTIONS=video:default is defined in defaults.nh use the * 'standard' video BIOS routines (in the overlaid version), * or DJGPPFAST routines (under djgpp). This is equivalent to * having no OPTIONS=video:xxxx entry at all. * * Notes (94/04/23): * * - The handler for defaults.nh file entry: * * OPTIONS=video:xxxxx * * has now been added. The handler is in video.c and is called * from options.c. * * - Handling of videocolors and videoshades are now done with * OPTIONS= statements. The new syntax separates the colour * values with dashes ('-') rather than spaces (' '). * * To Do (94/04/23): * * *========================================================================= */ void get_scr_size() { #ifdef SCREEN_VGA if (iflags.usevga) { vga_get_scr_size(); } else #endif txt_get_scr_size(); } /* * -------------------------------------------------------------- * The rest of this file is only compiled if NO_TERMS is defined. * -------------------------------------------------------------- */ #ifdef NO_TERMS #include #include "wintty.h" #ifdef __GO32__ #include #include #if !(__DJGPP__ >= 2) typedef long clock_t; #endif #endif #ifdef __BORLANDC__ #include /* needed for delay() */ #endif #ifdef SCREEN_DJGPPFAST /* parts of this block may be unecessary now */ #define get_cursor(x, y) ScreenGetCursor(y, x) #endif #ifdef SCREEN_BIOS void FDECL(get_cursor, (int *, int *)); #endif void FDECL(adjust_cursor_flags, (struct WinDesc *)); void FDECL(cmov, (int, int)); void FDECL(nocmov, (int, int)); STATIC_DCL void NDECL(init_ttycolor); int savevmode; /* store the original video mode in here */ int curcol, currow; /* graphics mode current cursor locations */ int g_attribute; /* Current attribute to use */ int monoflag; /* 0 = not monochrome, else monochrome */ int attrib_text_normal; /* text mode normal attribute */ int attrib_gr_normal; /* graphics mode normal attribute */ int attrib_text_intense; /* text mode intense attribute */ int attrib_gr_intense; /* graphics mode intense attribute */ boolean traditional = FALSE; /* traditonal TTY character mode */ boolean inmap = FALSE; /* in the map window */ #ifdef TEXTCOLOR char ttycolors[CLR_MAX]; /* also used/set in options.c */ #endif /* TEXTCOLOR */ void backsp() { if (!iflags.grmode) { txt_backsp(); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_backsp(); #endif } } void clear_screen() { if (!iflags.grmode) { txt_clear_screen(); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_clear_screen(BACKGROUND_VGA_COLOR); #endif } } void cl_end() /* clear to end of line */ { int col, row; col = (int) ttyDisplay->curx; row = (int) ttyDisplay->cury; if (!iflags.grmode) { txt_cl_end(col, row); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_cl_end(col, row); #endif } tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } void cl_eos() /* clear to end of screen */ { int cy = (int) ttyDisplay->cury + 1; if (!iflags.grmode) { txt_cl_eos(); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_cl_eos(cy); #endif } tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } void cmov(col, row) register int col, row; { ttyDisplay->cury = (uchar) row; ttyDisplay->curx = (uchar) col; if (!iflags.grmode) { txt_gotoxy(col, row); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_gotoloc(col, row); #endif } } int has_color(int color) { ++color; /* prevents compiler warning (unref. param) */ #ifdef TEXTCOLOR return (monoflag) ? 0 : 1; #else return 0; #endif } void home() { tty_curs(BASE_WINDOW, 1, 0); ttyDisplay->curx = ttyDisplay->cury = (uchar) 0; if (!iflags.grmode) { txt_gotoxy(0, 0); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_gotoloc(0, 0); #endif } } void nocmov(col, row) int col, row; { if (!iflags.grmode) { txt_gotoxy(col, row); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_gotoloc(col, row); #endif } } void standoutbeg() { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } void standoutend() { g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; } void term_end_attr(int attr) { switch (attr) { case ATR_ULINE: case ATR_BOLD: case ATR_BLINK: case ATR_INVERSE: default: g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; } } void term_end_color(void) { g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; } void term_end_raw_bold(void) { standoutend(); } void term_start_attr(int attr) { switch (attr) { case ATR_ULINE: if (monoflag) { g_attribute = ATTRIB_MONO_UNDERLINE; } else { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } break; case ATR_BOLD: g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; break; case ATR_BLINK: if (monoflag) { g_attribute = ATTRIB_MONO_BLINK; } else { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } break; case ATR_INVERSE: if (monoflag) { g_attribute = ATTRIB_MONO_REVERSE; } else { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } break; default: g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; break; } } void term_start_color(int color) { #ifdef TEXTCOLOR if (monoflag) { g_attribute = attrib_text_normal; } else { if (color >= 0 && color < CLR_MAX) { if (iflags.grmode) g_attribute = color; else g_attribute = ttycolors[color]; } } #endif } void term_start_raw_bold(void) { standoutbeg(); } void tty_delay_output() { #ifdef TIMED_DELAY if (flags.nap) { (void) fflush(stdout); msleep(50); /* sleep for 50 milliseconds */ return; } #endif } void tty_end_screen() { if (!iflags.grmode) { txt_clear_screen(); #ifdef PC9800 fputs("\033[>1l", stdout); #endif #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_tty_end_screen(); #endif } } void tty_nhbell() { txt_nhbell(); } void tty_number_pad(state) int state; { ++state; /* prevents compiler warning (unref. param) */ } void tty_startup(wid, hgt) int *wid, *hgt; { /* code to sense display adapter is required here - MJA */ attrib_text_normal = ATTRIB_NORMAL; attrib_text_intense = ATTRIB_INTENSE; /* These are defaults and may get overridden */ attrib_gr_normal = attrib_text_normal; attrib_gr_intense = attrib_text_intense; g_attribute = attrib_text_normal; /* Give it a starting value */ #ifdef SCREEN_VGA if (iflags.usevga) { vga_tty_startup(wid, hgt); } else #endif txt_startup(wid, hgt); *wid = CO; *hgt = LI; #ifdef CLIPPING if (CO < COLNO || LI < ROWNO + 3) setclipped(); #endif #ifdef TEXTCOLOR init_ttycolor(); #endif #ifdef MONO_CHECK monoflag = txt_monoadapt_check(); #else monoflag = 0; #endif } void tty_start_screen() { #ifdef PC9800 fputs("\033[>1h", stdout); #endif if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */ } void gr_init() { if (iflags.usevga) { #ifdef SCREEN_VGA vga_Init(); #endif #ifdef SCREEN_VESA } else if (iflags.usevesa) { vesa_Init(); #endif #ifdef SCREEN_8514 } else if (iflags.use8514) { v8514_Init(); #endif } } void gr_finish() { if (iflags.grmode) { if (iflags.usevga) { #ifdef SCREEN_VGA vga_Finish(); #endif #ifdef SCREEN_VESA } else if (iflags.usevesa) { vesa_Finish(); #endif #ifdef SCREEN_8514 } else if (iflags.use8514) { v8514_Finish(); #endif } } } /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the NO_TERMS PC tty port of NetHack. These are the routines * that get called by routines in other NetHack source files (such * as those in win/tty). * * xputs - Writes a c null terminated string at the current location. * Depending on compile options, this could just be a series * of repeated calls to xputc() for each character. * * xputc - Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * xputg - If using a graphics mode display mechanism (such as VGA, this * routine is used to display a graphical representation of a * NetHack glyph at the current location. For more information on * NetHack glyphs refer to the comments in include/display.h. * * NOTES: * wintty.h uses macros to redefine common output functions * such as puts, putc, putchar, so that they get steered into * either xputs (for strings) or xputc (for single characters). * References to puts, putc, and putchar in other source files * (that include wintty.h) are actually using these routines. */ void xputs(s) const char *s; { int col, row; col = (int) ttyDisplay->curx; row = (int) ttyDisplay->cury; if (!iflags.grmode) { txt_xputs(s, col, row); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_xputs(s, col, row); #endif } } void xputc(ch) /* write out character (and attribute) */ char ch; { int i; char attribute; i = iflags.grmode ? attrib_gr_normal : attrib_text_normal; attribute = (char) ((g_attribute == 0) ? i : g_attribute); if (!iflags.grmode) { txt_xputc(ch, attribute); #ifdef SCREEN_VGA } else if (iflags.usevga) { vga_xputc(ch, attribute); #endif /*SCREEN_VGA*/ } } void xputg(glyphnum, ch, special) /* write out a glyph picture at current location */ int glyphnum; int ch; unsigned special; { if (!iflags.grmode || !iflags.tile_view) { xputc((char) ch); #ifdef SCREEN_VGA } else { vga_xputg(glyphnum, ch, special); #endif } } #ifdef POSITIONBAR void video_update_positionbar(posbar) char *posbar; { if (!iflags.grmode) return; #ifdef SCREEN_VGA else vga_update_positionbar(posbar); #endif } #endif void adjust_cursor_flags(cw) struct WinDesc *cw; { #ifdef SIMULATE_CURSOR #if 0 if (cw->type == NHW_MAP) cursor_flag = 1; else cursor_flag = 0; #else if (cw->type == NHW_MAP) { inmap = 1; cursor_flag = 1; } else { inmap = 0; cursor_flag = 1; } #endif /* 0 */ #endif /* SIMULATE_CURSOR */ } #ifdef SIMULATE_CURSOR /* change the defaults in pcvideo.h, not here */ int cursor_type = CURSOR_DEFAULT_STYLE; int cursor_color = CURSOR_DEFAULT_COLOR; int cursor_flag; /* The check for iflags.grmode is made BEFORE calling these. */ void DrawCursor() { #ifdef SCREEN_VGA vga_DrawCursor(); #endif } void HideCursor() { #ifdef SCREEN_VGA vga_HideCursor(); #endif } #endif /* SIMULATE_CURSOR */ #ifdef TEXTCOLOR /* * CLR_BLACK 0 * CLR_RED 1 * CLR_GREEN 2 * CLR_BROWN 3 low-intensity yellow * CLR_BLUE 4 * CLR_MAGENTA 5 * CLR_CYAN 6 * CLR_GRAY 7 low-intensity white * NO_COLOR 8 * CLR_ORANGE 9 * CLR_BRIGHT_GREEN 10 * CLR_YELLOW 11 * CLR_BRIGHT_BLUE 12 * CLR_BRIGHT_MAGENTA 13 * CLR_BRIGHT_CYAN 14 * CLR_WHITE 15 * CLR_MAX 16 * BRIGHT 8 */ #ifdef VIDEOSHADES /* assign_videoshades() is prototyped in extern.h */ /* assign_videocolors() is prototyped in extern.h */ /* assign_video() is prototyped in extern.h */ int shadeflag; /* shades are initialized */ int colorflag; /* colors are initialized */ char *schoice[3] = { "dark", "normal", "light" }; char *shade[3]; #endif /* VIDEOSHADES */ STATIC_OVL void init_ttycolor() { #ifdef VIDEOSHADES if (!shadeflag) { ttycolors[CLR_BLACK] = M_BLACK; /* 8 = dark gray */ ttycolors[CLR_WHITE] = M_WHITE; /* 15 = bright white */ ttycolors[CLR_GRAY] = M_GRAY; /* 7 = normal white */ shade[0] = schoice[0]; shade[1] = schoice[1]; shade[2] = schoice[2]; } #else ttycolors[CLR_BLACK] = M_GRAY; /* mapped to white */ ttycolors[CLR_WHITE] = M_GRAY; /* mapped to white */ ttycolors[CLR_GRAY] = M_GRAY; /* mapped to white */ #endif #ifdef VIDEOSHADES if (!colorflag) { #endif ttycolors[CLR_RED] = M_RED; ttycolors[CLR_GREEN] = M_GREEN; ttycolors[CLR_BROWN] = M_BROWN; ttycolors[CLR_BLUE] = M_BLUE; ttycolors[CLR_MAGENTA] = M_MAGENTA; ttycolors[CLR_CYAN] = M_CYAN; ttycolors[BRIGHT] = M_WHITE; ttycolors[CLR_ORANGE] = M_ORANGE; ttycolors[CLR_BRIGHT_GREEN] = M_BRIGHTGREEN; ttycolors[CLR_YELLOW] = M_YELLOW; ttycolors[CLR_BRIGHT_BLUE] = M_BRIGHTBLUE; ttycolors[CLR_BRIGHT_MAGENTA] = M_BRIGHTMAGENTA; ttycolors[CLR_BRIGHT_CYAN] = M_BRIGHTCYAN; #ifdef VIDEOSHADES } #endif } static int FDECL(convert_uchars, (char *, uchar *, int)); #ifdef VIDEOSHADES int assign_videoshades(char *choiceptr) { char choices[120]; char *cptr, *cvalue[3]; int i, icolor = CLR_WHITE; strcpy(choices, choiceptr); cvalue[0] = choices; /* find the next ' ' or tab */ cptr = index(cvalue[0], '-'); if (!cptr) cptr = index(cvalue[0], ' '); if (!cptr) cptr = index(cvalue[0], '\t'); if (!cptr) return 0; *cptr = '\0'; /* skip whitespace between '=' and value */ do { ++cptr; } while (isspace(*cptr) || (*cptr == '-')); cvalue[1] = cptr; cptr = index(cvalue[1], '-'); if (!cptr) cptr = index(cvalue[0], ' '); if (!cptr) cptr = index(cvalue[0], '\t'); if (!cptr) return 0; *cptr = '\0'; do { ++cptr; } while (isspace(*cptr) || (*cptr == '-')); cvalue[2] = cptr; for (i = 0; i < 3; ++i) { switch (i) { case 0: icolor = CLR_BLACK; break; case 1: icolor = CLR_GRAY; break; case 2: icolor = CLR_WHITE; break; } shadeflag = 1; if ((strncmpi(cvalue[i], "black", 5) == 0) || (strncmpi(cvalue[i], "dark", 4) == 0)) { shade[i] = schoice[0]; ttycolors[icolor] = M_BLACK; /* dark gray */ } else if ((strncmpi(cvalue[i], "gray", 4) == 0) || (strncmpi(cvalue[i], "grey", 4) == 0) || (strncmpi(cvalue[i], "medium", 6) == 0) || (strncmpi(cvalue[i], "normal", 6) == 0)) { shade[i] = schoice[1]; ttycolors[icolor] = M_GRAY; /* regular gray */ } else if ((strncmpi(cvalue[i], "white", 5) == 0) || (strncmpi(cvalue[i], "light", 5) == 0)) { shade[i] = schoice[2]; ttycolors[icolor] = M_WHITE; /* bright white */ } else { shadeflag = 0; return 0; } } return 1; } /* * Process defaults.nh OPTIONS=videocolors:xxx * Left to right assignments for: * red green brown blue magenta cyan orange br.green yellow * br.blue br.mag br.cyan * * Default Mapping (BIOS): 4-2-6-1-5-3-12-10-14-9-13-11 */ int assign_videocolors(char *colorvals) { int i, icolor; uchar *tmpcolor; init_ttycolor(); /* in case defaults.nh entry wasn't complete */ i = strlen(colorvals); tmpcolor = (uchar *) alloc(i); (void) convert_uchars(colorvals, tmpcolor, i); icolor = CLR_RED; for (i = 0; tmpcolor[i] != 0; ++i) { if (icolor < (CLR_WHITE)) { ttycolors[icolor++] = tmpcolor[i]; if ((icolor > CLR_CYAN) && (icolor < CLR_ORANGE)) { icolor = CLR_ORANGE; } } } colorflag = 1; free((genericptr_t) tmpcolor); return 1; } static int convert_uchars(bufp, list, size) char *bufp; /* current pointer */ uchar *list; /* return list */ int size; { unsigned int num = 0; int count = 0; while (1) { switch (*bufp) { case ' ': case '\0': case '\t': case '-': case '\n': if (num) { list[count++] = num; num = 0; } if ((count == size) || !*bufp) return count; bufp++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': num = num * 10 + (*bufp - '0'); bufp++; break; return count; } } /*NOTREACHED*/ } #endif /* VIDEOSHADES */ #endif /* TEXTCOLOR */ /* * Process defaults.nh OPTIONS=video:xxxx * * where (current) legitimate values are: * * autodetect (attempt to determine the adapter type) * default (force use of the default video method for environment) * vga (use vga adapter code) */ int assign_video(sopt) char *sopt; { /* * debug * * printf("video is %s",sopt); * getch(); */ iflags.grmode = 0; iflags.hasvga = 0; iflags.usevga = 0; if (strncmpi(sopt, "def", 3) == 0) { /* default */ /* do nothing - default */ #ifdef SCREEN_VGA } else if (strncmpi(sopt, "vga", 3) == 0) { /* vga */ iflags.usevga = 1; iflags.hasvga = 1; #endif #ifdef SCREEN_VESA } else if (strncmpi(sopt, "vesa", 4) == 0) { /* vesa */ iflags.hasvesa = 1; iflags.usevesa = 1; #endif #ifdef SCREEN_8514 } else if (strncmpi(sopt, "8514", 4) == 0) { /* 8514/A */ iflags.use8514 = 1; iflags.has8514 = 1; #endif } else if (strncmpi(sopt, "auto", 4) == 0) { /* autodetect */ #ifdef SCREEN_VESA if (vesa_detect()) { iflags.hasvesa = 1; } #endif #ifdef SCREEN_8514 if (v8514_detect()) { iflags.has8514 = 1; } #endif #ifdef SCREEN_VGA if (vga_detect()) { iflags.hasvga = 1; } #endif /* * Auto-detect Priorities (arbitrary for now): * VGA */ if (iflags.hasvga) { iflags.usevga = 1; /* VGA depends on BIOS to enable function keys*/ iflags.BIOS = 1; iflags.rawio = 1; } } else { return 0; } return 1; } void tileview(enable) boolean enable; { #ifdef SCREEN_VGA if (iflags.grmode) vga_traditional(enable ? FALSE : TRUE); #endif } #endif /* NO_TERMS */ #else /* STUBVIDEO */ void tileview(enable) boolean enable; { } #endif /* STUBVIDEO */ /*video.c*/ nethack-3.6.0/sys/msdos/vidtxt.c0000664000076400007660000003040412536476415015604 0ustar paxedpaxed/* NetHack 3.6 vidtxt.c $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * vidtxt.c - Textmode video hardware support (BIOS and DJGPPFAST) * *Edit History: * Initial Creation M. Allison 93/04/04 * Add djgpp support K. Smolkowski 93/04/26 * Add runtime monoadapter check M. Allison 93/05/09 */ #define VIDEO_TEXT #include "hack.h" #include "pcvideo.h" #include "wintty.h" #include #include #if defined(_MSC_VER) #if _MSC_VER >= 700 #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4131) /* old style declarator */ #pragma warning(disable : 4305) /* prevents complaints with MK_FP */ #pragma warning(disable : 4309) /* initializing */ #pragma warning(disable : 4759) /* prevents complaints with MK_FP */ #endif #endif /* void FDECL(txt_xputc,(char, int)); */ /* write out character (and attribute) */ extern int attrib_text_normal; /* text mode normal attribute */ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_text_intense; /* text mode intense attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ void txt_get_scr_size() { union REGS regs; if (!iflags.BIOS) { CO = 80; LI = 24; return; } #ifdef PC9800 regs.h.ah = SENSEMODE; (void) int86(CRT_BIOS, ®s, ®s); CO = (regs.h.al & 0x02) ? 40 : 80; LI = (regs.h.al & 0x01) ? 20 : 25; #else regs.x.ax = FONTINFO; regs.x.bx = 0; /* current ROM BIOS font */ regs.h.dl = 24; /* default row count */ /* in case no EGA/MCGA/VGA */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Font Information */ /* MDA/CGA/PCjr ignore INT 10h, Function 11h, but since we * cleverly loaded up DL with the default, everything's fine. * * Otherwise, DL now contains rows - 1. Also, CX contains the * points (bytes per character) and ES:BP points to the font * table. -3. */ regs.h.ah = GETMODE; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Video Mode */ /* This goes back all the way to the original PC. Completely * safe. AH contains # of columns, AL contains display mode, * and BH contains the active display page. */ LI = regs.h.dl + 1; CO = regs.h.ah; #endif /* PC9800 */ } /* * -------------------------------------------------------------- * The rest of this file is only compiled if NO_TERMS is defined. * -------------------------------------------------------------- */ #ifdef NO_TERMS /* #include "wintty.h" */ #ifdef SCREEN_DJGPPFAST #include #include #endif void FDECL(txt_gotoxy, (int, int)); #if defined(SCREEN_BIOS) && !defined(PC9800) void FDECL(txt_get_cursor, (int *, int *)); #endif #ifdef SCREEN_DJGPPFAST #define txt_get_cursor(x, y) ScreenGetCursor(y, x) #endif extern int g_attribute; /* Current attribute to use */ extern int monoflag; /* 0 = not monochrome, else monochrome */ void txt_backsp() { #ifdef PC9800 union REGS regs; regs.h.dl = 0x01; /* one column */ regs.h.ah = CURSOR_LEFT; regs.h.cl = DIRECT_CON_IO; int86(DOS_EXT_FUNC, ®s, ®s); #else int col, row; txt_get_cursor(&col, &row); if (col > 0) col = col - 1; txt_gotoxy(col, row); #endif } void txt_nhbell() { union REGS regs; if (flags.silent) return; regs.h.dl = 0x07; /* bell */ regs.h.ah = 0x02; /* Character Output function */ (void) int86(DOSCALL, ®s, ®s); } void txt_clear_screen() /* djgpp provides ScreenClear(), but in version 1.09 it is broken * so for now we just use the BIOS Routines */ { union REGS regs; #ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x02; /* clear whole screen */ regs.h.ah = SCREEN_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else regs.h.dl = (char) (CO - 1); /* columns */ regs.h.dh = (char) (LI - 1); /* rows */ regs.x.cx = 0; /* CL,CH = x,y of upper left */ regs.x.ax = 0; regs.x.bx = 0; regs.h.bh = (char) attrib_text_normal; regs.h.ah = (char) SCROLL; /* DL,DH = x,y of lower rt */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Scroll or init window */ txt_gotoxy(0, 0); #endif } void txt_cl_end(col, row) /* clear to end of line */ int col, row; { union REGS regs; #ifndef PC9800 int count; #endif #ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x00; /* clear to end of line */ regs.h.ah = LINE_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else count = CO - col; txt_gotoxy(col, row); regs.h.ah = PUTCHARATT; /* write attribute & character */ regs.h.al = ' '; /* character */ regs.h.bh = 0; /* display page */ /* BL = attribute */ regs.h.bl = (char) attrib_text_normal; regs.x.cx = count; if (count != 0) (void) int86(VIDEO_BIOS, ®s, ®s); /* write attribute & character */ #endif } void txt_cl_eos() /* clear to end of screen */ { union REGS regs; #ifndef PC9800 int col, row; #endif #ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x00; /* clear to end of screen */ regs.h.ah = SCREEN_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else txt_get_cursor(&col, &row); txt_cl_end(col, row); /* clear to end of line */ txt_gotoxy(0, (row < (LI - 1) ? row + 1 : (LI - 1))); regs.h.dl = (char) (CO - 1); /* X of lower right */ regs.h.dh = (char) (LI - 1); /* Y of lower right */ regs.h.cl = 0; /* X of upper left */ /* Y (row) of upper left */ regs.h.ch = (char) (row < (LI - 1) ? row + 1 : (LI - 1)); regs.x.cx = 0; regs.x.ax = 0; regs.x.bx = 0; regs.h.bh = (char) attrib_text_normal; regs.h.ah = SCROLL; (void) int86(VIDEO_BIOS, ®s, ®s); /* Scroll or initialize window */ #endif } void txt_startup(wid, hgt) int *wid, *hgt; { txt_get_scr_size(); *wid = CO; *hgt = LI; attrib_gr_normal = attrib_text_normal; attrib_gr_intense = attrib_text_intense; g_attribute = attrib_text_normal; /* Give it a starting value */ } /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the NO_TERMS PC tty port of NetHack. These are the routines * that get called by routines in other NetHack source files (such * as those in win/tty). * * txt_xputs - Writes a c null terminated string at the current location. * Depending on compile options, this could just be a series * of repeated calls to xputc() for each character. * txt_xputc - Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * NOTES: * wintty.h uses macros to redefine common output functions * such as puts, putc, putchar, so that they get steered into * either xputs (for strings) or xputc (for single characters). * References to puts, putc, and putchar in other source files * (that include wintty.h) are actually using these routines. */ void txt_xputs(s, col, row) const char *s; int col, row; { char c; if (s != (char *) 0) { while (*s != '\0') { txt_gotoxy(col, row); c = *s++; txt_xputc(c, g_attribute); if (col < (CO - 1)) col++; txt_gotoxy(col, row); } } } void txt_xputc(ch, attr) /* write out character (and attribute) */ char ch; int attr; { #ifdef PC9800 union REGS regs; regs.h.dl = attr98[attr]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); if (ch == '\n') { regs.h.dl = '\r'; regs.h.ah = PUTCHAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); } regs.h.dl = ch; regs.h.ah = PUTCHAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else #ifdef SCREEN_BIOS union REGS regs; #endif int col, row; txt_get_cursor(&col, &row); switch (ch) { case '\n': #if 0 col = 0; ++row; #endif break; default: #ifdef SCREEN_DJGPPFAST ScreenPutChar((int) ch, attr, col, row); #endif #ifdef SCREEN_BIOS regs.h.ah = PUTCHARATT; /* write att & character */ regs.h.al = ch; /* character */ regs.h.bh = 0; /* display page */ regs.h.bl = (char) attr; /* BL = attribute */ regs.x.cx = 1; /* one character */ (void) int86(VIDEO_BIOS, ®s, ®s); #endif if (col < (CO - 1)) ++col; break; } /* end switch */ txt_gotoxy(col, row); #endif /* PC9800 */ } /* * This marks the end of the general screen output routines that are * called from other places in NetHack. * --------------------------------------------------------------------- */ /* * Cursor location manipulation, and location information fetching * routines. * These include: * * txt_get_cursor(x,y) - Returns the current location of the cursor. In * some implementations this is implemented as a * function (BIOS), and in others it is a macro * (DJGPPFAST). * * txt_gotoxy(x,y) - Moves the cursor on screen to the specified x and * y location. This routine moves the location where * screen writes will occur next, it does not change * the location of the player on the NetHack level. */ #if defined(SCREEN_BIOS) && !defined(PC9800) /* * This is implemented as a macro under DJGPPFAST. */ void txt_get_cursor(x, y) /* get cursor position */ int *x, *y; { union REGS regs; regs.x.dx = 0; regs.h.ah = GETCURPOS; /* get cursor position */ regs.x.cx = 0; regs.x.bx = 0; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Cursor Position */ *x = regs.h.dl; *y = regs.h.dh; } #endif /* SCREEN_BIOS && !PC9800 */ void txt_gotoxy(x, y) int x, y; { #ifdef SCREEN_BIOS union REGS regs; #ifdef PC9800 regs.h.dh = (char) y; /* row */ regs.h.dl = (char) x; /* column */ regs.h.ah = SETCURPOS; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); /* Set Cursor Position */ #else regs.h.ah = SETCURPOS; regs.h.bh = 0; /* display page */ regs.h.dh = (char) y; /* row */ regs.h.dl = (char) x; /* column */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Set Cursor Position */ #endif #endif #if defined(SCREEN_DJGPPFAST) ScreenSetCursor(y, x); #endif /* The above, too, goes back all the way to the original PC. If * we ever get so fancy as to swap display pages (i doubt it), * then we'll need to set BH appropriately. This function * returns nothing. -3. */ } /* * This marks the end of the cursor manipulation/information routines. * ------------------------------------------------------------------- */ #ifdef MONO_CHECK int txt_monoadapt_check() { union REGS regs; regs.h.al = 0; regs.h.ah = GETMODE; /* get video mode */ (void) int86(VIDEO_BIOS, ®s, ®s); return (regs.h.al == 7) ? 1 : 0; /* 7 means monochrome mode */ } #endif /* MONO_CHECK */ #endif /* NO_TERMS */ /* vidtxt.c */ nethack-3.6.0/sys/msdos/vidvga.c0000664000076400007660000012240312536476415015543 0ustar paxedpaxed/* NetHack 3.6 vidvga.c $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * vidvga.c - VGA Hardware video support */ #include "hack.h" #ifdef SCREEN_VGA /* this file is for SCREEN_VGA only */ #include "pcvideo.h" #include "tile.h" #include "pctiles.h" #include #include #include "wintty.h" #ifdef __GO32__ #include #include #endif /*========================================================================= * VGA Video supporting routines (for tiles). * * The following routines carry out the lower level video functions required * to make PC NetHack work with VGA graphics. * * - The binary files NetHack1.tib and NetHacko.tib must be in your * game directory. Currently, unpredictable results may occur if they * aren't since the code hasn't been tested with it missing (yet). * * Notes (96/02/16): * * - Cursor emulation on the map is now implemented. The input routine * in msdos.c calls the routine to display the cursor just before * waiting for input, and hides the cursor immediately after satisfying * the input request. * * - A check for a VGA adapter is implemented. * * - With 640 x 480 resolution, the use of 16 x 16 icons allows only 40 * columns for the map display. This makes it necessary to support the * TTY CLIPPING code. The right/left scrolling with this can be * a little annoying. Feel free to rework the routines. * * - NetHack1.tib is built from text files derived from bitmap files * provided by Warwick Allison, using routines developed and supplied * by Janet Walz. The icons are very well done and thanks to * Warwick Allison for an excellent effort! * * - The text fonts that this is using while in graphics mode come from * the Video BIOS ROM on board the VGA adapter. Code in vga_WriteChar * copies the appropriate pixels from the video ROM to the Video buffer. * * - VGA 640 by 480, 16 colour mode (0x12) uses an odd method to * represent a colour value from the palette. There are four * planes of video memory, all overlaid at the same memory location. * For example, if a pixel has the colour value 7: * * 0 1 1 1 * \ \ \ \ * \ \ \ plane 0 * \ \ plane 1 * \ plane 2 * plane 3 * * - VGA write mode 2 requires that a read be done before a write to * set some latches on the card. The value read had to be placed * into a variable declared 'volatile' to prevent djgpp from * optimizing away the entire instruction (the value was assigned * to a variable which was never used). This corrects the striping * problem that was apparent with djgpp. * * - A check for valid mode switches has been added. * * - No tiles are displayed on the Rogue Level in keeping with the * original Rogue. The display adapter remains in graphics mode * however. * * - Added handling for missing NetHackX.tib files, and resort to using * video:default and tty if one of them can't be located. * * ToDo (96/02/17): * * - Nothing prior to release. *========================================================================= */ #if defined(_MSC_VER) #if _MSC_VER >= 700 #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4127) /* conditional expression is constant */ #pragma warning(disable : 4131) /* old style declarator */ #pragma warning(disable : 4305) /* prevents complaints with MK_FP */ #pragma warning(disable : 4309) /* initializing */ #if _MSC_VER > 700 #pragma warning(disable : 4759) /* prevents complaints with MK_FP */ #endif #endif #include #endif /* STATIC_DCL void FDECL(vga_NoBorder, (int)); */ void FDECL(vga_gotoloc, (int, int)); /* This should be made a macro */ void NDECL(vga_backsp); #ifdef SCROLLMAP STATIC_DCL void FDECL(vga_scrollmap, (BOOLEAN_P)); #endif STATIC_DCL void FDECL(vga_redrawmap, (BOOLEAN_P)); void FDECL(vga_cliparound, (int, int)); STATIC_OVL void FDECL(decal_planar, (struct planar_cell_struct *, unsigned)); #ifdef POSITIONBAR STATIC_DCL void NDECL(positionbar); static void FDECL(vga_special, (int, int, int)); #endif extern int clipx, clipxmax; /* current clipping column from wintty.c */ extern boolean clipping; /* clipping on? from wintty.c */ extern int savevmode; /* store the original video mode */ extern int curcol, currow; /* current column and row */ extern int g_attribute; extern int attrib_text_normal; /* text mode normal attribute */ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_text_intense; /* text mode intense attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ extern boolean inmap; /* in the map window */ /* * Global Variables */ STATIC_VAR unsigned char __far *font; STATIC_VAR char *screentable[SCREENHEIGHT]; STATIC_VAR char *paletteptr; STATIC_VAR struct map_struct { int glyph; int ch; int attr; unsigned special; } map[ROWNO][COLNO]; /* track the glyphs */ #define vga_clearmap() \ { \ int x, y; \ for (y = 0; y < ROWNO; ++y) \ for (x = 0; x < COLNO; ++x) { \ map[y][x].glyph = cmap_to_glyph(S_stone); \ map[y][x].ch = S_stone; \ map[y][x].attr = 0; \ map[y][x].special = 0; \ } \ } #define TOP_MAP_ROW 1 STATIC_VAR int vgacmap[CLR_MAX] = { 0, 3, 5, 9, 4, 8, 12, 14, 11, 2, 6, 7, 1, 8, 12, 13 }; STATIC_VAR int viewport_size = 40; /* STATIC_VAR char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; */ /* STATIC_VAR char bittable[8]= {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; */ #if 0 STATIC_VAR char defpalette[] = { /* Default VGA palette */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff }; #endif #ifndef ALTERNATE_VIDEO_METHOD int vp[SCREENPLANES] = { 8, 4, 2, 1 }; #endif int vp2[SCREENPLANES] = { 1, 2, 4, 8 }; STATIC_VAR struct planar_cell_struct *planecell; STATIC_VAR struct overview_planar_cell_struct *planecell_O; #if defined(USE_TILES) STATIC_VAR struct tibhdr_struct tibheader; /* extern FILE *tilefile; */ /* Not needed in here most likely */ #endif /* STATIC_VAR int g_attribute; */ /* Current attribute to use */ void vga_get_scr_size() { CO = 80; LI = 29; } void vga_backsp() { int col, row; col = curcol; /* Character cell row and column */ row = currow; if (col > 0) col = col - 1; vga_gotoloc(col, row); } void vga_clear_screen(colour) int colour; { char __far *pch; int y, j; char volatile a; outportb(0x3ce, 5); outportb(0x3cf, 2); for (y = 0; y < SCREENHEIGHT; ++y) { pch = screentable[y]; for (j = 0; j < SCREENBYTES; ++j) { outportb(0x3ce, 8); outportb(0x3cf, 255); a = READ_ABSOLUTE(pch); /* Must read , then write */ WRITE_ABSOLUTE(pch, (char) colour); ++pch; } } outportb(0x3ce, 5); outportb(0x3cf, 0); if (iflags.tile_view) vga_clearmap(); vga_gotoloc(0, 0); /* is this needed? */ } void vga_cl_end(col, row) /* clear to end of line */ int col, row; { int count; /* * This is being done via character writes. * This should perhaps be optimized for speed by using VGA write * mode 2 methods as did clear_screen() */ for (count = col; count < (CO - 1); ++count) { vga_WriteChar(' ', count, row, BACKGROUND_VGA_COLOR); } } void vga_cl_eos(cy) /* clear to end of screen */ int cy; { int count; cl_end(); while (cy <= LI - 2) { for (count = 0; count < (CO - 1); ++count) { vga_WriteChar(' ', count, cy, BACKGROUND_VGA_COLOR); } cy++; } } void vga_tty_end_screen() { vga_clear_screen(BACKGROUND_VGA_COLOR); vga_SwitchMode(MODETEXT); } void vga_tty_startup(wid, hgt) int *wid, *hgt; { /* code to sense display adapter is required here - MJA */ vga_get_scr_size(); if (CO && LI) { *wid = CO; *hgt = LI; } attrib_gr_normal = ATTRIB_VGA_NORMAL; attrib_gr_intense = ATTRIB_VGA_INTENSE; g_attribute = attrib_gr_normal; /* Give it a starting value */ } /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the VGA PC tty port of NetHack. These are the routines * that get called by the general interface routines in video.c. * * vga_xputs -Writes a c null terminated string at the current location. * * vga_xputc -Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * vga_xputg -This routine is used to display a graphical representation of a * NetHack glyph (a tile) at the current location. For more * information on NetHack glyphs refer to the comments in * include/display.h. * */ void vga_xputs(s, col, row) const char *s; int col, row; { if (s != (char *) 0) { vga_WriteStr((char *) s, strlen(s), col, row, g_attribute); } } void vga_xputc(ch, attr) /* write out character (and attribute) */ char ch; int attr; { int col, row; col = curcol; row = currow; switch (ch) { case '\n': col = 0; ++row; break; default: vga_WriteChar((unsigned char) ch, col, row, attr); if (col < (CO - 1)) ++col; break; } /* end switch */ vga_gotoloc(col, row); } #if defined(USE_TILES) void vga_xputg(glyphnum, ch, special) /* Place tile represent. a glyph at current location */ int glyphnum; int ch; unsigned special; /* special feature: corpse, invis, detected, pet, ridden - hack.h */ { int col, row; int attr; int ry; row = currow; col = curcol; if ((col < 0 || col >= COLNO) || (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) return; ry = row - TOP_MAP_ROW; map[ry][col].glyph = glyphnum; map[ry][col].ch = ch; map[ry][col].special = special; attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute; map[ry][col].attr = attr; if (iflags.traditional_view) { vga_WriteChar((unsigned char) ch, col, row, attr); } else if (!iflags.over_view) { if ((col >= clipx) && (col <= clipxmax)) { if (!ReadPlanarTileFile(glyph2tile[glyphnum], &planecell)) { if (map[ry][col].special) decal_planar(planecell, special); vga_DisplayCell(planecell, col - clipx, row); } else pline("vga_xputg: Error reading tile (%d,%d) from file", glyphnum, glyph2tile[glyphnum]); } } else { if (!ReadPlanarTileFile_O(glyph2tile[glyphnum], &planecell_O)) vga_DisplayCell_O(planecell_O, col, row); else pline("vga_xputg: Error reading tile (%d,%d) from file", glyphnum, glyph2tile[glyphnum]); } if (col < (CO - 1)) ++col; vga_gotoloc(col, row); } #endif /* USE_TILES */ /* * Cursor location manipulation, and location information fetching * routines. * These include: * * vga_gotoloc(x,y) - Moves the "cursor" on screen to the specified x * and y character cell location. This routine * determines the location where screen writes * will occur next, it does not change the location * of the player on the NetHack level. */ void vga_gotoloc(col, row) int col, row; { curcol = min(col, CO - 1); /* protection from callers */ currow = min(row, LI - 1); } #if defined(USE_TILES) && defined(CLIPPING) void vga_cliparound(x, y) int x, y; { extern boolean restoring; int oldx = clipx; if (!iflags.tile_view || iflags.over_view || iflags.traditional_view) return; if (x < clipx + 5) { clipx = max(0, x - (viewport_size / 2)); clipxmax = clipx + (viewport_size - 1); } else if (x > clipxmax - 5) { clipxmax = min(COLNO - 1, x + (viewport_size / 2)); clipx = clipxmax - (viewport_size - 1); } if (clipx != oldx) { if (on_level(&u.uz0, &u.uz) && !restoring) /* (void) doredraw(); */ vga_redrawmap(1); } } STATIC_OVL void vga_redrawmap(clearfirst) boolean clearfirst; { int j, x, y, t; char __far *pch; char volatile a; if (clearfirst) { /* y here is in pixel rows */ outportb(0x3ce, 5); outportb(0x3cf, 2); t = TOP_MAP_ROW * ROWS_PER_CELL; for (y = t; y < (ROWNO * ROWS_PER_CELL) + t; ++y) { pch = screentable[y]; for (j = 0; j < SCREENBYTES; ++j) { outportb(0x3ce, 8); outportb(0x3cf, 255); /* On VGA mode2, must read first, then write */ a = READ_ABSOLUTE(pch); WRITE_ABSOLUTE(pch, (char) BACKGROUND_VGA_COLOR); ++pch; } } outportb(0x3ce, 5); outportb(0x3cf, 0); } /* y here is in screen rows*/ #ifdef ROW_BY_ROW for (y = 0; y < ROWNO; ++y) for (x = clipx; x <= clipxmax; ++x) { #else for (x = clipx; x <= clipxmax; ++x) for (y = 0; y < ROWNO; ++y) { #endif if (iflags.traditional_view) { if (!(clearfirst && map[y][x].ch == S_stone)) vga_WriteChar((unsigned char) map[y][x].ch, x, y + TOP_MAP_ROW, map[y][x].attr); } else { t = map[y][x].glyph; if (!(clearfirst && t == cmap_to_glyph(S_stone))) { if (!iflags.over_view) { if (!ReadPlanarTileFile(glyph2tile[t], &planecell)) { if (map[y][x].special) decal_planar(planecell, map[y][x].special); vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW); } else pline("vga_redrawmap: Error reading tile (%d,%d)", t, glyph2tile[t]); } else { if (!ReadPlanarTileFile_O(glyph2tile[t], &planecell_O)) { vga_DisplayCell_O(planecell_O, x, y + TOP_MAP_ROW); } else pline("vga_redrawmap: Error reading tile (%d,%d)", t, glyph2tile[t]); } } } } } #endif /* USE_TILES && CLIPPING */ void vga_userpan(left) boolean left; { int x; /* pline("Into userpan"); */ if (iflags.over_view || iflags.traditional_view) return; if (left) x = min(COLNO - 1, clipxmax + 10); else x = max(0, clipx - 10); vga_cliparound(x, 10); /* y value is irrelevant on VGA clipping */ positionbar(); vga_DrawCursor(); } void vga_overview(on) boolean on; { /* vga_HideCursor(); */ if (on) { iflags.over_view = TRUE; clipx = 0; clipxmax = CO - 1; } else { iflags.over_view = FALSE; clipx = max(0, (curcol - viewport_size / 2)); if (clipx > ((CO - 1) - viewport_size)) clipx = (CO - 1) - viewport_size; clipxmax = clipx + (viewport_size - 1); } } void vga_traditional(on) boolean on; { /* vga_HideCursor(); */ if (on) { /* switch_symbols(FALSE); */ iflags.traditional_view = TRUE; clipx = 0; clipxmax = CO - 1; } else { iflags.traditional_view = FALSE; if (!iflags.over_view) { clipx = max(0, (curcol - viewport_size / 2)); if (clipx > ((CO - 1) - viewport_size)) clipx = (CO - 1) - viewport_size; clipxmax = clipx + (viewport_size - 1); } } } void vga_refresh() { positionbar(); vga_redrawmap(1); vga_DrawCursor(); } #ifdef SCROLLMAP STATIC_OVL void vga_scrollmap(left) boolean left; { int j, x, y, t; int i, pixx, pixy, x1, y1, x2, y2; int byteoffset, vplane; char __far *tmp1; char __far *tmp2; unsigned char source[SCREENPLANES][80]; unsigned char first, second; pixy = row2y(TOP_MAP_ROW); /* convert to pixels */ pixx = col2x(x1); if (left) { x1 = 20; x2 = 0; } else { x1 = 0; x2 = 20; } /* read each row, all columns but the one to be replaced */ for (i = 0; i < (ROWNO - 1) * ROWS_PER_CELL; ++i) { tmp1 = screentable[i + pixy]; tmp1 += x1; for (vplane = 0; vplane < SCREENPLANES; ++vplane) { egareadplane(vplane); for (byteoffset = 0; byteoffset < 20; ++byteoffset) { tmp2 = tmp1 + byteoffset; source[vplane][byteoffset] = READ_ABSOLUTE(tmp2); } } tmp1 = screentable[i + pixy]; tmp1 += x2; for (vplane = 0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp2[vplane]); for (byteoffset = 0; byteoffset < 20; ++byteoffset) { tmp2 = tmp1 + byteoffset; WRITE_ABSOLUTE(tmp2, source[vplane][byteoffset]); } } egawriteplane(15); } if (left) { i = clipxmax - 1; j = clipxmax; } else { i = clipx; j = clipx + 1; } for (y = 0; y < ROWNO; ++y) { for (x = i; x < j; x += 2) { t = map[y][x].glyph; if (!ReadPlanarTileFile(glyph2tile[t], &planecell)) { if (map[y][x].special) decal_planar(planecell, map[y][x].special); vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW); } else { pline("vga_shiftmap: Error reading tile (%d,%d)", t, glyph2tile[t]); } } } } #endif /* SCROLLMAP */ STATIC_OVL void decal_planar(gp, special) struct planar_cell_struct *gp; unsigned special; { if (special & MG_CORPSE) { } else if (special & MG_INVIS) { } else if (special & MG_DETECT) { } else if (special & MG_PET) { } else if (special & MG_RIDDEN) { } } /* * Open tile files, * initialize the SCREEN, switch it to graphics mode, * initialize the pointers to the fonts, clear * the screen. * */ void vga_Init(void) { int i; #ifdef USE_TILES int tilefailure = 0; /* * Attempt to open the required tile files. If we can't * don't perform the video mode switch, use TTY code instead. * */ if (OpenTileFile(NETHACK_PLANAR_TILEFILE, FALSE)) tilefailure |= 1; if (OpenTileFile(NETHACK_OVERVIEW_TILEFILE, TRUE)) tilefailure |= 2; if (ReadTileFileHeader(&tibheader, FALSE)) tilefailure |= 4; if (tilefailure) { raw_printf("Reverting to TTY mode, tile initialization failure (%d).", tilefailure); wait_synch(); iflags.usevga = 0; iflags.tile_view = FALSE; iflags.over_view = FALSE; CO = 80; LI = 25; /* clear_screen() */ /* not vga_clear_screen() */ return; } #endif if (iflags.usevga) { for (i = 0; i < SCREENHEIGHT; ++i) { screentable[i] = MK_PTR(VIDEOSEG, (i * SCREENBYTES)); } } vga_SwitchMode(MODE640x480); windowprocs.win_cliparound = vga_cliparound; /* vga_NoBorder(BACKGROUND_VGA_COLOR); */ /* Not needed after palette mod */ #ifdef USE_TILES paletteptr = tibheader.palette; iflags.tile_view = TRUE; iflags.over_view = FALSE; #else paletteptr = defpalette; #endif vga_SetPalette(paletteptr); g_attribute = attrib_gr_normal; font = vga_FontPtrs(); clear_screen(); clipx = 0; clipxmax = clipx + (viewport_size - 1); } /* * Switches modes of the video card. * * If mode == MODETEXT (0x03), then the card is placed into text * mode. If mode == 640x480, then the card is placed into vga * mode (video mode 0x12). No other modes are currently supported. * */ void vga_SwitchMode(unsigned int mode) { union REGS regs; if ((mode == MODE640x480) || (mode == MODETEXT)) { if (iflags.usevga && (mode == MODE640x480)) { iflags.grmode = 1; } else { iflags.grmode = 0; } regs.x.ax = mode; (void) int86(VIDEO_BIOS, ®s, ®s); } else { iflags.grmode = 0; /* force text mode for error msg */ regs.x.ax = MODETEXT; (void) int86(VIDEO_BIOS, ®s, ®s); g_attribute = attrib_text_normal; impossible("vga_SwitchMode: Bad video mode requested 0x%X", mode); } } /* * This allows grouping of several tasks to be done when * switching back to text mode. This is a public (extern) function. * */ void vga_Finish(void) { CloseTileFile(0); CloseTileFile(1); vga_SwitchMode(MODETEXT); windowprocs.win_cliparound = tty_cliparound; g_attribute = attrib_text_normal; iflags.tile_view = FALSE; } #if 0 /* * Turn off any border colour that might be enabled in the VGA card * register. * * I disabled this after modifying tile2bin.c to remap black & white * to a more standard values - MJA 94/04/23. * */ STATIC_OVL void vga_NoBorder(int bc) { union REGS regs; regs.h.ah = (char)0x10; regs.h.al = (char)0x01; regs.h.bh = (char)bc; regs.h.bl = 0; (void) int86(VIDEO_BIOS, ®s, ®s); } #endif /* * * Returns a far pointer (or flat 32 bit pointer under djgpp) to the * location of the appropriate ROM font for the _current_ video mode * (so you must place the card into the desired video mode before * calling this function). * * This function takes advantage of the video BIOS loading the * address of the appropriate character definition table for * the current graphics mode into interrupt vector 0x43 (0000:010C). */ char __far * vga_FontPtrs(void) { USHORT __far *tmp; char __far *retval; USHORT fseg, foff; tmp = (USHORT __far *) MK_PTR(((USHORT) FONT_PTR_SEGMENT), ((USHORT) FONT_PTR_OFFSET)); foff = READ_ABSOLUTE_WORD(tmp); ++tmp; fseg = READ_ABSOLUTE_WORD(tmp); retval = (char __far *) MK_PTR(fseg, foff); return retval; } /* * This will verify the existance of a VGA adapter on the machine. * Video function call 0x1a returns 0x1a in AL if successful, and * returns the following values in BL for the active display: * * 0=no display, 1=MDA, 2=CGA, 4=EGA(color-monitor), * 5=EGA(mono-monitor), 6=PGA, 7=VGA(mono-monitor), 8=VGA(color-monitor), * 0xB=MCGA(mono-monitor), 0xC=MCGA(color-monitor), 0xFF=unknown) */ int vga_detect() { union REGS regs; regs.h.al = 0; regs.h.ah = 0x1a; (void) int86(VIDEO_BIOS, ®s, ®s); /* * debug * * printf("vga_detect returned al=%02x, bh=%02x, bl=%02x\n", * (int)regs.h.al, (int)regs.h.bh, (int)regs.h.bl); * getch(); */ if ((int) regs.h.al == 0x1a) { if (((int) regs.h.bl == 8) || ((int) regs.h.bl == 7)) { return 1; } } return 0; } /* * Write character 'ch', at (x,y) and * do it using the colour 'colour'. * */ void vga_WriteChar(chr, col, row, colour) int chr, col, row, colour; { int i; int x, pixy; char volatile tc; char __far *cp; unsigned char __far *fp = font; unsigned char fnt; int actual_colour = vgacmap[colour]; x = min(col, (CO - 1)); /* min() used protection from callers */ pixy = min(row, (LI - 1)) * 16; /* assumes 8 x 16 char set */ /* if (chr < ' ') chr = ' '; */ /* assumes ASCII set */ outportb(0x3ce, 5); outportb(0x3cf, 2); chr = chr << 4; for (i = 0; i < MAX_ROWS_PER_CELL; ++i) { cp = screentable[pixy + i] + x; fnt = READ_ABSOLUTE((fp + chr + i)); outportb(0x3ce, 8); outportb(0x3cf, fnt); tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */ WRITE_ABSOLUTE(cp, (char) actual_colour); outportb(0x3ce, 8); outportb(0x3cf, ~fnt); tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */ WRITE_ABSOLUTE(cp, (char) BACKGROUND_VGA_COLOR); } outportb(0x3ce, 5); outportb(0x3cf, 0); outportb(0x3ce, 8); outportb(0x3cf, 255); } /* * This is the routine that displays a high-res "cell" pointed to by 'gp' * at the desired location (col,row). * * Note: (col,row) in this case refer to the coordinate location in * NetHack character grid terms, (ie. the 40 x 25 character grid), * not the x,y pixel location. * */ void vga_DisplayCell(gp, col, row) struct planar_cell_struct *gp; int col, row; { int i, pixx, pixy; char __far *tmp_s; /* source pointer */ char __far *tmp_d; /* destination pointer */ int vplane; pixy = row2y(row); /* convert to pixels */ pixx = col2x(col); for (vplane = 0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp[vplane]); for (i = 0; i < ROWS_PER_CELL; ++i) { tmp_d = screentable[i + pixy]; tmp_d += pixx; /* * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i], * BYTES_PER_CELL); */ tmp_s = gp->plane[vplane].image[i]; WRITE_ABSOLUTE(tmp_d, (*tmp_s)); ++tmp_s; ++tmp_d; WRITE_ABSOLUTE(tmp_d, (*tmp_s)); } } egawriteplane(15); } void vga_DisplayCell_O(gp, col, row) struct overview_planar_cell_struct *gp; int col, row; { int i, pixx, pixy; char __far *tmp_s; /* source pointer */ char __far *tmp_d; /* destination pointer */ int vplane; pixy = row2y(row); /* convert to pixels */ pixx = col; for (vplane = 0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp[vplane]); for (i = 0; i < ROWS_PER_CELL; ++i) { tmp_d = screentable[i + pixy]; tmp_d += pixx; /* * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i], * BYTES_PER_CELL); */ tmp_s = gp->plane[vplane].image[i]; WRITE_ABSOLUTE(tmp_d, (*tmp_s)); } } egawriteplane(15); } /* * Write the character string pointed to by 's', whose maximum length * is 'len' at location (x,y) using the 'colour' colour. * */ void vga_WriteStr(s, len, col, row, colour) char *s; int len, col, row, colour; { unsigned char *us; int i = 0; /* protection from callers */ if (row > (LI - 1)) return; i = 0; us = (unsigned char *) s; while ((*us != 0) && (i < len) && (col < (CO - 1))) { vga_WriteChar(*us, col, row, colour); ++us; ++i; ++col; } } /* * Initialize the VGA palette with the desired colours. This * must be a series of 48 bytes for use with a card in * 16 colour mode at 640 x 480. * */ void vga_SetPalette(p) char *p; { union REGS regs; int i; outportb(0x3c6, 0xff); for (i = 0; i < COLORDEPTH; ++i) { outportb(0x3c8, i); outportb(0x3c9, (*p++) >> 2); outportb(0x3c9, (*p++) >> 2); outportb(0x3c9, (*p++) >> 2); } regs.x.bx = 0x0000; for (i = 0; i < COLORDEPTH; ++i) { regs.x.ax = 0x1000; (void) int86(VIDEO_BIOS, ®s, ®s); regs.x.bx += 0x0101; } } /*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; */ /* wrong */ static unsigned char colorbits[] = { 0x08, 0x04, 0x02, 0x01 }; #ifdef POSITIONBAR #define PBAR_ROW (LI - 4) #define PBAR_COLOR_ON 15 /* slate grey background colour of tiles */ #define PBAR_COLOR_OFF 12 /* bluish grey, used in old style only */ #define PBAR_COLOR_STAIRS 9 /* brown */ #define PBAR_COLOR_HERO 14 /* creamy white */ static unsigned char pbar[COLNO]; void vga_update_positionbar(posbar) char *posbar; { char *p = pbar; if (posbar) while (*posbar) *p++ = *posbar++; *p = 0; } STATIC_OVL void positionbar() { char *posbar = pbar; int feature, ucol; int k, y, colour, row; char __far *pch; int startk, stopk; char volatile a; boolean nowhere = FALSE; int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL); int tmp; if (!iflags.grmode || !iflags.tile_view) return; if ((clipx < 0) || (clipxmax <= 0) || (clipx >= clipxmax)) nowhere = TRUE; if (nowhere) { #ifdef DEBUG pline("Would have put bar using %d - %d.", clipx, clipxmax); #endif return; } #ifdef OLD_STYLE outportb(0x3ce, 5); outportb(0x3cf, 2); for (y = pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) { pch = screentable[y]; for (k = 0; k < SCREENBYTES; ++k) { if ((k < clipx) || (k > clipxmax)) { colour = PBAR_COLOR_OFF; } else colour = PBAR_COLOR_ON; outportb(0x3ce, 8); outportb(0x3cf, 255); a = READ_ABSOLUTE(pch); /* Must read , then write */ WRITE_ABSOLUTE(pch, (char) colour); ++pch; } } outportb(0x3ce, 5); outportb(0x3cf, 0); #else colour = PBAR_COLOR_ON; outportb(0x3ce, 5); outportb(0x3cf, 2); for (y = pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) { pch = screentable[y]; if ((!row) || (row == (ROWS_PER_CELL - 1))) { startk = 0; stopk = SCREENBYTES; } else { startk = clipx; stopk = clipxmax; } for (k = 0; k < SCREENBYTES; ++k) { if ((k < startk) || (k > stopk)) colour = BACKGROUND_VGA_COLOR; else colour = PBAR_COLOR_ON; outportb(0x3ce, 8); outportb(0x3cf, 255); a = READ_ABSOLUTE(pch); /* Must read , then write */ WRITE_ABSOLUTE(pch, (char) colour); ++pch; } } outportb(0x3ce, 5); outportb(0x3cf, 0); #endif ucol = 0; if (posbar) { while (*posbar != 0) { feature = *posbar++; switch (feature) { case '>': vga_special(feature, (int) *posbar++, PBAR_COLOR_STAIRS); break; case '<': vga_special(feature, (int) *posbar++, PBAR_COLOR_STAIRS); break; case '@': ucol = (int) *posbar++; vga_special(feature, ucol, PBAR_COLOR_HERO); break; default: /* unanticipated symbols */ vga_special(feature, (int) *posbar++, PBAR_COLOR_STAIRS); break; } } } #ifdef SIMULATE_CURSOR if (inmap) { tmp = curcol + 1; if ((tmp != ucol) && (curcol >= 0)) vga_special('_', tmp, PBAR_COLOR_HERO); } #endif } void vga_special(chr, col, color) int chr, col, color; { int i, y, pixy; char __far *tmp_d; /* destination pointer */ int vplane; char fnt; char bits[SCREENPLANES][ROWS_PER_CELL]; pixy = PBAR_ROW * MAX_ROWS_PER_CELL; for (vplane = 0; vplane < SCREENPLANES; ++vplane) { egareadplane(vplane); y = pixy; for (i = 0; i < ROWS_PER_CELL; ++i) { tmp_d = screentable[y++] + col; bits[vplane][i] = READ_ABSOLUTE(tmp_d); fnt = READ_ABSOLUTE((font + ((chr << 4) + i))); if (colorbits[vplane] & color) bits[vplane][i] |= fnt; else bits[vplane][i] &= ~fnt; } } for (vplane = 0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp[vplane]); y = pixy; for (i = 0; i < ROWS_PER_CELL; ++i) { tmp_d = screentable[y++] + col; WRITE_ABSOLUTE(tmp_d, (bits[vplane][i])); } } egawriteplane(15); } #endif /*POSITIONBAR*/ #ifdef SIMULATE_CURSOR static struct planar_cell_struct undercursor; static struct planar_cell_struct cursor; void vga_DrawCursor() { int i, pixx, pixy, x, y, p; char __far *tmp1; char __far *tmp2; unsigned char first, second; /* char on[2] = {0xFF,0xFF}; */ /* char off[2] = {0x00,0x00}; */ boolean isrogue = Is_rogue_level(&u.uz); boolean singlebyte = (isrogue || iflags.over_view || iflags.traditional_view || !inmap); int curtyp; if (!cursor_type && inmap) return; /* CURSOR_INVIS - nothing to do */ x = min(curcol, (CO - 1)); /* protection from callers */ y = min(currow, (LI - 1)); /* protection from callers */ if (!singlebyte && ((x < clipx) || (x > clipxmax))) return; pixy = row2y(y); /* convert to pixels */ if (singlebyte) pixx = x; else pixx = col2x((x - clipx)); for (i = 0; i < ROWS_PER_CELL; ++i) { tmp1 = screentable[i + pixy]; tmp1 += pixx; tmp2 = tmp1 + 1; egareadplane(3); /* memcpy(undercursor.plane[3].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[3].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[3].image[i][1] = READ_ABSOLUTE(tmp2); egareadplane(2); /* memcpy(undercursor.plane[2].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[2].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[2].image[i][1] = READ_ABSOLUTE(tmp2); egareadplane(1); /* memcpy(undercursor.plane[1].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[1].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[1].image[i][1] = READ_ABSOLUTE(tmp2); egareadplane(0); /* memcpy(undercursor.plane[0].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[0].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[0].image[i][1] = READ_ABSOLUTE(tmp2); } /* * Now we have a snapshot of the current cell. * Make a copy of it, then manipulate the copy * to include the cursor, and place the tinkered * version on the display. */ cursor = undercursor; if (inmap) curtyp = cursor_type; else curtyp = CURSOR_UNDERLINE; switch (curtyp) { case CURSOR_CORNER: for (i = 0; i < 2; ++i) { if (!i) { if (singlebyte) first = 0xC3; else first = 0xC0; second = 0x03; } else { if (singlebyte) first = 0x81; else first = 0x80; second = 0x01; } for (p = 0; p < 4; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } } for (i = ROWS_PER_CELL - 2; i < ROWS_PER_CELL; ++i) { if (i != (ROWS_PER_CELL - 1)) { if (singlebyte) first = 0x81; else first = 0x80; second = 0x01; } else { if (singlebyte) first = 0xC3; else first = 0xC0; second = 0x03; } for (p = 0; p < SCREENPLANES; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } } break; case CURSOR_UNDERLINE: i = ROWS_PER_CELL - 1; first = 0xFF; second = 0xFF; for (p = 0; p < SCREENPLANES; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } break; case CURSOR_FRAME: /* fall through */ default: for (i = 0; i < ROWS_PER_CELL; ++i) { if ((i == 0) || (i == (ROWS_PER_CELL - 1))) { first = 0xFF; second = 0xFF; } else { if (singlebyte) first = 0x81; else first = 0x80; second = 0x01; } for (p = 0; p < SCREENPLANES; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } } break; } /* * Place the new cell onto the display. * */ for (i = 0; i < ROWS_PER_CELL; ++i) { tmp1 = screentable[i + pixy]; tmp1 += pixx; tmp2 = tmp1 + 1; egawriteplane(8); /* memcpy(tmp1,cursor.plane[3].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, cursor.plane[3].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, cursor.plane[3].image[i][1]); egawriteplane(4); /* memcpy(tmp1,cursor.plane[2].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, cursor.plane[2].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, cursor.plane[2].image[i][1]); egawriteplane(2); /* memcpy(tmp1,cursor.plane[1].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, cursor.plane[1].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, cursor.plane[1].image[i][1]); egawriteplane(1); /* memcpy(tmp1,cursor.plane[0].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, cursor.plane[0].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, cursor.plane[0].image[i][1]); } egawriteplane(15); #ifdef POSITIONBAR if (inmap) positionbar(); #endif } void vga_HideCursor() { int i, pixx, pixy, x, y; char __far *tmp1; char __far *tmp2; boolean isrogue = Is_rogue_level(&u.uz); boolean singlebyte = (isrogue || iflags.over_view || iflags.traditional_view || !inmap); int curtyp; if (inmap && !cursor_type) return; /* CURSOR_INVIS - nothing to do */ /* protection from callers */ x = min(curcol, (CO - 1)); y = min(currow, (LI - 1)); if (!singlebyte && ((x < clipx) || (x > clipxmax))) return; pixy = row2y(y); /* convert to pixels */ if (singlebyte) pixx = x; else pixx = col2x((x - clipx)); if (inmap) curtyp = cursor_type; else curtyp = CURSOR_UNDERLINE; if (curtyp == CURSOR_UNDERLINE) /* optimization for uline */ i = ROWS_PER_CELL - 1; else i = 0; for (; i < ROWS_PER_CELL; ++i) { tmp1 = screentable[i + pixy]; tmp1 += pixx; tmp2 = tmp1 + 1; egawriteplane(8); /* memcpy(tmp,undercursor.plane[3].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, undercursor.plane[3].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, undercursor.plane[3].image[i][1]); egawriteplane(4); /* memcpy(tmp,undercursor.plane[2].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, undercursor.plane[2].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, undercursor.plane[2].image[i][1]); egawriteplane(2); /* memcpy(tmp,undercursor.plane[1].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, undercursor.plane[1].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, undercursor.plane[1].image[i][1]); egawriteplane(1); /* memcpy(tmp,undercursor.plane[0].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1, undercursor.plane[0].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2, undercursor.plane[0].image[i][1]); } egawriteplane(15); } #endif /* SIMULATE_CURSOR */ #endif /* SCREEN_VGA */ /* vidvga.c */ nethack-3.6.0/sys/os2/Install.os20000664000076400007660000003634312536476415015537 0ustar paxedpaxed Instructions for compiling and installing NetHack 3.4 on an OS/2 system ===================================================== Timo Hakulinen Last revision: 29 October 1996 0. Read this entire file before starting, and come back to the Notes below if you have any problems. 1. Make sure all the NetHack files are in the appropriate directory structure. You should have a top directory (e.g. nh33, or whatever you like) with subdirectories dat, doc, include, src, util, sys\share, sys\os2, and win\tty. You may have other subdirectories under sys and win, but they will not affect compilation for an OS/2 system. If you do not follow this structure, the makefile will not function properly. The .c files for the main program belong in src, those for utility programs in util, and OS/2-specific ones in sys\os2. All the .h files belong in include, the documentation in doc, and assorted data files in dat. There are also some necessary files in sys\share (pc*.c, random.c, dgn_*.*, lev_*.*). A more detailed explanation of the directory structure is found in file Files, which should be in the top directory. If you downloaded or ftp'd the sources from a UNIX system, the lines may end in UNIX-style newlines instead of the carriage return and line feed pairs used by DOS and OS/2. You'll have to convert them (with a utility like Rahul Dhesi's "flip"). Also, every file should end with a carriage return / line feed pair, because Microsoft C has had a habit of ignoring the last line of each file otherwise. Besides, even editing UNIX-style files with DOS editors is often a royal pain. 2. The makefile for OS/2, Makefile.os2, is found in directory sys\os2. Copy it to directory src and rename it Makefile. From now on, Makefile.os2 will be referred to as "the makefile" in this document. The makefile supports the following make utilities: NDMAKE a public domain make utility for DOS by Don Kneller NMAKE make shipped with Microsoft languages and IBM C Set/2 DMAKE a public domain make for DOS and OS/2 by Dennis Vadura Both NDMAKE and DMAKE are available at major archive sites. The following compilers are supported: compiler: runs in: compiles for: Microsoft C 5.1 DOS / OS/2 1.0-Warp OS/2 1.x Microsoft 6.0A (see note 5) - " - - " - IBM C Set/2 1.00, Toolkit/2 2.00 OS/2 2.x, Warp OS/2 2.x, Warp IBM CSet++ 2.00 OS/2 2.x, Warp OS/2 2.x, Warp GCC emx 0.8f (see note 6) OS/2 2.x, Warp OS/2 2.x, Warp Note that code compiled for OS/2 versions 1.0-1.3 runs unmodified in OS/2 versions 2.0 and up. In principle it should be possible to cross compile NetHack 3.6 for OS/2 in DOS using NDMAKE and MSC, but this is not recommended (see note 3). If you're using some other compiler than one listed above, you will have to adapt the makefile to your needs. In particular, change the CC, CFLAGS, LINK, and LFLAGS macros to your C compiler's and linker's liking. See the makefile for more information. If you are going to be constructing Fred Fish's termcap library, you'll need Makefile.lib in sys\share (see note 4). 3. Go to the include subdirectory. First edit config.h according to the comments to match your system and desired set of features. In particular, make sure that OS2 is defined, and that UNIX, HACKDIR, and COMPRESS are *not* defined. If you want to try out the new DLB data file library scheme, uncomment DLB. Note that although the makefile contains some support for this scheme, it's new in NetHack 3.3 and hasn't been tested. If your compiler is ANSI compliant (like practically all OS/2 compilers are), it's probable that nothing else needs to be configured in config.h. Next look at os2conf.h. This file shouldn't need much changing. If you want to use the hardcoded OS/2 system definitions in def_os2.h instead of the compiler's standard headers, comment out OS2_USESYSHEADERS. This may become necessary if you are using a compiler which doesn't come with proper system headers by default. In this case you may have to edit the definitions there, because every compiler has its own way of declaring the necessary system functions and data structures. In general you should prefer the compiler's offerings, if possible. If you are going to compile the game on an HPFS drive, uncomment OS2_HPFS, which enables the use of longer file names during compilation. The generated executable will only use file names compatible with FAT drives, however. If you are using a 32 bit compiler other than GCC emx 0.8f or C Set/2 in OS/2 2.x, force OS2_32BITAPI to be defined. Otherwise it is defined only for the above mentioned compilers. If you are not going to include random.c, because you are using the random number generator provided by your compiler, you will need to comment out RANDOM. If you want to muck with different termcap settings, uncomment TERMLIB to enable the use of termcap routines (see note 4). This is not necessary to create a fully functional game, however. 4. If you are using another compiler than MSC, GCC, or IBM C Set/2, you may want to look through system.h in the include directory. This file matches the return and parameter types for system calls and library routines with various flavors of compilers and operating systems. Leaving this file alone is unlikely to cause problems, but if you get compile errors with any functions in the standard library, it's worth checking the declarations there. 5. If you want to change the high score list behavior, examine the top of topten.c, in the src directory. You may want to change the definitions of PERSMAX, POINTSMIN, and ENTRYMAX. 6. Go to the src directory and edit the top of the makefile. Be sure that the directory you want the game installed to actually exists. You'll need nroff and/or TeX/LaTeX to do the files in doc. If you don't have either of these, you can skip it. If you elected not to use the high quality BSD random number routines by commenting out RANDOM in os2conf.h, comment out (or set equal to nothing) the RANDOM macro in the makefile. If you elected to use Fred Fish's termcap library (bundled in as termcap.uu in directory sys\share), you will have to generate termlib.lib from those sources by typing "make -f makefile.lib termlib.lib". You must set the TERMLIB option in the makefile to link the resulting termlib.lib into the game. If you are recompiling after patching your sources, or if you got your files from somewhere other than the official distribution, "touch makedefs.c" to ensure that certain files (onames.h and pm.h) are remade, lest potentially troublesome time stamps fool make. If you have lex and yacc programs, or the equivalent flex and bison programs, you can set up the makefile to generate the appropriate .h and .c files from their .l and .y counterparts whenever you recompile. This is done by changing the do_yacc and do_lex targets in the makefile to depend on targets yacc_act and lex_act instead of yacc_cpy and lex_cpy. Otherwise the makefile will copy pre-generated yacc and lex output files dgn_*.* and lev_*.* from directory sys\share to util and include. Now, enter "make all", and take a siesta; your computer will be occupied for a fair amount of time. If all goes well, you will get an executable. 7. All the support data files should have been copied to the game directory by the make process. Here is the complete list in alphabetical order of all the files that should have gotten there during a full build: Arc-fila.lev Arc-filb.lev Arc-goal.lev Arc-loca.lev Arc-strt.lev Bar-fila.lev Bar-filb.lev Bar-goal.lev Bar-loca.lev Bar-strt.lev Cav-fila.lev Cav-filb.lev Cav-goal.lev Cav-loca.lev Cav-strt.lev Hea-fila.lev Hea-filb.lev Hea-goal.lev Hea-loca.lev Hea-strt.lev Kni-fila.lev Kni-filb.lev Kni-goal.lev Kni-loca.lev Kni-strt.lev Mon-fila.lev Mon-filb.lev Mon-goal.lev Mon-loca.lev Mon-strt.lev Pri-fila.lev Pri-filb.lev Pri-goal.lev Pri-loca.lev Pri-strt.lev Ran-fila.lev Ran-filb.lev Ran-goal.lev Ran-loca.lev Ran-strt.lev Rog-fila.lev Rog-filb.lev Rog-goal.lev Rog-loca.lev Rog-strt.lev Sam-fila.lev Sam-filb.lev Sam-goal.lev Sam-loca.lev Sam-strt.lev Tou-fila.lev Tou-filb.lev Tou-goal.lev Tou-loca.lev Tou-strt.lev Val-fila.lev Val-filb.lev Val-goal.lev Val-loca.lev Val-strt.lev Wiz-fila.lev Wiz-filb.lev Wiz-goal.lev Wiz-loca.lev Wiz-strt.lev air.lev asmodeus.lev astral.lev baalz.lev bigrm-1.lev bigrm-2.lev bigrm-3.lev bigrm-4.lev bigrm-5.lev castle.lev cmdhelp data dungeon earth.lev fakewiz1.lev fakewiz2.lev fire.lev help hh history juiblex.lev knox.lev license medusa-1.lev medusa-2.lev minefill.lev minend-1.lev minend-2.lev minetn-1.lev minetn-2.lev nethack.cmd nethack.cnf nethack.exe nethack.ico opthelp options oracle.lev oracles orcus.lev quest.dat recover.exe rumors sanctum.lev soko1-1.lev soko1-2.lev soko2-1.lev soko2-2.lev soko3-1.lev soko3-2.lev soko4-1.lev soko4-2.lev tower1.lev tower2.lev tower3.lev valley.lev water.lev wizard1.lev wizard2.lev wizard3.lev wizhelp Yes. It's 112 files for a full featured NetHack 3.4. If any of the files are missing, try to rerun make. If that doesn't help, you'll have to try to decipher the makefile to find out how to manually create the missing files. These kinds of troubles shouldn't happen except for two reasons: You've run out of disk space while compiling or your make utility doesn't understand the makefile properly for some reason. In either case, you should get some warnings from the make, though. If you have old record, logfile, or news files in the game directory, they are not overwritten. Of course, old records from NetHack 3.1 and 3.2 are not worth keeping with 3.4, since these games are really quite different. Edit file nethack.cnf in the game directory to reflect your particular setup and personal preferences, following the comments there. More info about settable options can be found in the file opthelp and the guidebook. If you compiled in the TERMLIB feature, also move the sys\share\termcap file to your game directory. 8. If you'll be running NetHack from a different subdirectory, you will want to "set HACKDIR=c:\games\nh33" (or whatever directory you want to use). Add it to your config.sys, if you'll be playing often. You can also create a special NetHack entry in your Presentation Manager / Workplace Shell desktop. This will use the included NetHack icon. The following is a sample program description for OS/2 1.3 desktop, but it's similar for OS/2 2.0: Program title: NetHack 3.4 Path and file name: c:\games\nh33\nethack.cmd Parameters: Working directory: c:\games\nh33 Program type: OS/2 Full screen Naturally you must fill in your own game directory and parameters if you want to set any. The program type can be either OS/2 Full screen or OS/2 Windowed. Note that you should set the executable path to use the .cmd file generated by the makefile. This file generates an extra pause after the program exit, because otherwise you wouldn't get to see the high score list upon quitting due to PM/WPS automatically closing the program window. When starting NetHack normally from OS/2 command prompt, the command processor starts nethack.exe instead, so no extra pause is generated. 9. If you want to clear up the temporary files and objects created by the compilation process, you may issue "make spotless". This will return your source tree to near-distribution condition. Naturally, it will not affect your newly built game files in any way. 10. Play NetHack. If it works, you're done! Notes ----- 1) Save-files and bones-files from previous versions will not work with NetHack 3.4. Don't bother trying to keep them. 2) To install an update of NetHack after changing something, enter "make" from the src directory. If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but usually crashes.) 3) When cross-compiling for OS/2 in DOS, NDMAKE is the best choice because it requires the least RAM for itself. Note however, that cross-compilation in DOS is discouraged, because it is considered obsolete (OS/2 is really a much better place to compile). If you still want to try, here are some suggestions: During linking, Microsoft linker will need temporary storage space. Make sure you have about 1 MB of free disk where ever you have defined your temporary storage. It is also a good idea to compile with as much free RAM as possible. It may otherwise get crowded with the bigger, more complex source files (compiler bombs with "out of heap space" or similar). If this happens, strip your configuration, zap TSR's, get a better memory manager etc. 4) The file sys\share\termcap.uu is the fixed version of the Fred Fish termcap library. You will need to run a uudecode utility on it to generate the file termcap.zip. termcap.zip contains several files of termcap routines. Using them with NetHack involves very little knowledge of the UNIX concept of a termcap database; mostly you need to know enough to set a TERM environment variable. You can unzip termcap.zip in the sys\share directory, but if you are going to use it, it is probably best to unzip a copy in the src directory. That way you will not miss copying any files over. Wherever you unzip it, get rid of the included makefile since a better version has been provided as Makefile.lib. After creating the termcap library file termlib.lib, copy it to src before compiling the game main source. 5) When compiling with MSC 6.0, the maintenance version 6.0A should be used instead of the original 6.0, which was all too buggy to successfully build NetHack. 6) Note that emx 0.8f is the first version of GCC for OS/2 that can properly compile NetHack. Earlier versions do not work, because they don't support the 16 bit API calls of OS/2. GCC emx 0.8f does not currently work properly when fseek() function is used with text files. This is well documented in the compiler's documentation. Unfortunately NetHack uses fseek() in several places in connection with text data. This means that some help texts may not come out right, but no serious problems should emerge. nethack-3.6.0/sys/os2/Makefile.os20000664000076400007660000014237612536476415015652 0ustar paxedpaxed# NetHack 3.6 Makefile.os2 $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ # OS/2 NetHack 3.6 Makefile for OS/2 versions 1.x and 2.x # Copyright (C) 1990, 1991, 1992, 1993, 1996 Timo Hakulinen # # Several compilers exist for OS/2 but, currently only GCC emx is tested # and used for releases. make programs other than dmake are not tested. # # Supported compilers: GCC emx 0.9g # # DMAKE is required. Credit for the makefile improvements goes to Pekka Rousu. # # Copy this file into $(SRC) directory, rename it to "makefile" # (important, many targets rely on it), compile and link inside # $(SRC). If required, termcap library can be built from termcap # sources using makefile.lib in "sys\share" directory. # # "GCC" refers to GCC emx only. No other ports of GCC are supported. # Additional credits for honing GCC support for 3.2 go to Ronald # Van Iwaarden (ron@vaniwaarden.org) and Stefan Neis (neis@cs.uni-sb.de). # # "OMF" is short for "Object Module Format" and refers to the # standard OS/2 object format, which e.g. link386 uses. MSC and # CSet/2 always produce OMF object files, and GCC can be instructed # to produce them with proper switches (see below). # # "a.out" refers to Unix object file format, which is used by GCC # in its default compilation mode. These object files must be # linked using GCC's own linker to produce a proper OS/2 executable. # GDB debugger shipped with GCC can only be used with a.out object # format. # # Note that the default setup in this makefile is my personal setup, # which you will have to adapt to your configuration. # # # Compiler and linker selection. # #format = omf format = a.out .IF $(format) == a.out with_x11 = yes #debug = yes .END CC = gcc # GCC .IF $(format) == a.out LINK = gcc #LINK = link386 # GCC OMF, CSet/2 .ELSE LINK = link386 # GCC OMF, CSet/2 LFLAGS = /noig /stack:40000 .END .IF $(with_x11) == yes WINX11OBJ01 = $(OBJ)/Window.o WINX11OBJ02 = $(OBJ)/dialogs.o WINX11OBJ03 = $(OBJ)/winX.o WINX11OBJ04 = $(OBJ)/winmap.o WINX11OBJ05 = $(OBJ)/winmenu.o WINX11OBJ06 = $(OBJ)/winmesg.o WINX11OBJ07 = $(OBJ)/winmisc.o WINX11OBJ08 = $(OBJ)/winstat.o WINX11OBJ09 = $(OBJ)/wintext.o WINX11OBJ10 = $(OBJ)/winval.o WINX11OBJ11 = $(OBJ)/tile.o X11ROOT = e:/xfree86 WINX11CFLAGS = -DUSE_XPM -DX11_GRAPHICS \ -I$(X11ROOT)/include -Zmtd WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 -lXpm -L$(X11ROOT)/lib -lc_app WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \ ../win/X11/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \ ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \ ../win/X11/winval.c tile.c WINX11OBJ = $(WINX11OBJ01) $(WINX11OBJ02) $(WINX11OBJ03) $(WINX11OBJ04) \ $(WINX11OBJ05) $(WINX11OBJ06) $(WINX11OBJ07) $(WINX11OBJ08) \ $(WINX11OBJ09) $(WINX11OBJ10) $(WINX11OBJ11) WINX11VARDAT=x11tiles pet_mark.xbm rip.xpm X11ECHO = $(CMD) @echo .END MAKEB = dmake CMD = cmd /C AB = $(@:B).c CB = $$(@:B).c BEG = $(CMD) " END = " SEP = & P = % # # Most makes execute actions automatically inside a subshell, # which makes even the shell internals work ok. # ECHO = $(CMD) @echo RM = $(CMD) del CP = $(CMD) copy CAT = $(CMD) type # # For those of us who have these on PC. # #YACC = yacc #LEX = lex YACC = bison -y LEX = flex # # For extracting NetHack icon. # UUDECODE = uudecode # # For people with TeX and LaTeX. # LATEX = latex # # If you have TOUCH, some things become slightly easier. # TOUCH = touch # # Standard file naming for LEX and YACC output may vary in PC # installations. These three are probably the most generally used # names. # YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c # # Source tree base directory. # NHSRC = \nethack # # Source directories. Makedefs hardcodes these, don't change them. # INCL = $(NHSRC)\include # NetHack include files DAT = $(NHSRC)\dat # NetHack data files DOC = $(NHSRC)\doc # NetHack documentation files UTIL = $(NHSRC)\util # Utility source SRC = $(NHSRC)\src # Main source WIN = $(NHSRC)\win\tty # Window system specific source WINX11 = $(NHSRC)\win\x11 # Window system specific source SYS = $(NHSRC)\sys\os2 # System specific source SSYS = $(NHSRC)\sys\share # Shared system files WINSHARE= $(NHSRC)\win\share # Shared system files # # Modifiable directories. Set these according to your setup and # preferences. They must all be present prior to compilation. # OBJ, TEMP and GAMEDIR should all preferably be separate and, # in particular, not the same as any of the source directories. # Note that DMAKE may dislike drive designators in paths because # it misinterprets the colon as being part of a make rule. In that # case, all directories have to reside on the same drive. # OBJ = \tmp\obj # Object files TEMP = \tmp\bin # Temporary files during make process GAMEDIR = \games\nh350x11 # Game directory PLIBP = c:\emx\lib # Protected mode C libraries RLIBP = c:\emx\lib # Possible real mode C libraries # # The game name and description. # GAME = nethack GAMEDES = "NetHack 3.6.0" # # The uppermost two lines for MSC, the middle two for GCC, and # the lowermost two for CSet/2. # # GCC: compile only, compiler id, object format selection, warnings, # include file path, debug flags, ANSI conformance. # CFLAGS = -c $(GCCO) $(WARN) -I$(INCL) $(CDFLAGS) $(STDC) $(WINX11CFLAGS) #OPT = -s -O -o OPT = -o # # Compiler warning levels. These are really for development, so # they are commented out in general distribution to save the user # from masses of benign warnings. If any problems arise, however, # they may help in finding the trouble. # # GCC: max. reasonable GCC warning levels. Can't use -Wall, because then # it would whine about all the zillions of unused declarations etc. # Even with these switches you'll get a lot of warnings, but they should # all be benign. # WARN = #-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN # GCC # # GCC object format selection. The upper line for standard OS/2 OMF # object format, the lower for Unix style a.out format. # .IF $(format) == omf GCCO = -Zomf -Zsys .ELSE GCCO = .END # # MSC 5.1 needs the large model first pass of the compiler. # Not needed for later versions. # BIGC = # # Unset CL to avoid troubles with conflicting switches in MSC 6.0. # CL = # # Prepare for a debugger. # .IF $(debug) == yes CDFLAGS = LDFLAGS = .ELSE CDFLAGS = -O -s LDFLAGS = -s .END # # How to produce the most ANSI-like environment. # STDC = -ansi # GCC # # Possible system object files required during linking. # .IF $(format) == omf SYSOBJ = $(PLIBP)\crt0.obj $(PLIBP)\end.lib# GCC OMF .ELSE SYSOBJ = # MSC, GCC a.out, CSet/2 .END # # Compiler library selection. Change if necessary. # # GCC emx 0.9 OMF: C single-threaded libs, Unix system call alias lib, # extra GCC lib, single threaded system lib, OS/2 API entry points. # Note that emx changed library naming convention between 0.8 and 0.9. # # GCC a.out: extra GCC lib, C standard lib, extra GCC lib (again), # OS/2 API entry points. # .IF $(format) == omf PLIBS = $(PLIBP)\st\c $(PLIBP)\st\c_app $(PLIBP)\c_alias $(PLIBP)\gcc $(PLIBP)\st\sys $(PLIBP)\os2 # GCC emx 0.9 OMF .ELSE PLIBS = -lgcc -lc -lgcc -los2 $(X11LIBS) # GCC a.out .END # # C libraries used by makedefs, lev_comp and dgn_comp (change if # necessary). If compilation is done in DOS, enable the upper line # possibly setting the library name to something else, if in OS/2, # enable the lower line (protected mode libraries). # #RLIBS = $(RLIBP)\llibcer RLIBS = $(PLIBS) SRCCC = $(CC) $(CFLAGS) $(OPT) $@ $(AB) UTILCC = $(BEG) cd $(UTIL) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) SYSCC = $(BEG) cd $(SYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) SSYSCC = $(BEG) cd $(SSYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) PSYSCC = $(BEG) cd $(SSYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ pc$(AB) $(END) WINCC = $(BEG) cd $(WIN) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) # # Default linker skeletons. The upper six lines for everything # that uses standard OS/2 object format (GCC OMF), The lower six # for GCC a.out format. # .IF $(format) == omf GAMELN = $(LINK) @$(TEMP)\$(GAME).rsp MKDFLN = $(LINK) @$(TEMP)\makedefs.rsp LEVCLN = $(LINK) @$(TEMP)\lev_comp.rsp DGNCLN = $(LINK) @$(TEMP)\dgn_comp.rsp RCVRLN = $(LINK) @$(TEMP)\recover.rsp DLBRLN = $(LINK) @$(TEMP)\dlb.rsp .ELSE GAMELN = $(CC) $(LDFLAGS) -o $(GAMEDIR)\$(GAME).exe @$(TEMP)\$(GAME).r $(PLIBS) $(WINX11CFLAGS) $(WINX11LIB) MKDFLN = $(CC) $(LDFLAGS) -o $(TEMP)\makedefs.exe $(TEMP)\$(MKDFDEF) $(SYSOBJ) $(MAKEOBJS) $(PLIBS) LEVCLN = $(CC) $(LDFLAGS) -o $(TEMP)\lev_comp.exe $(TEMP)\$(LEVCDEF) $(SYSOBJ) $(SPLEVOBJS) $(PLIBS) DGNCLN = $(CC) $(LDFLAGS) -o $(TEMP)\dgn_comp.exe $(TEMP)\$(DGNCDEF) $(SYSOBJ) $(DGNCOMPOBJS) $(PLIBS) RCVRLN = $(CC) $(LDFLAGS) -o $(GAMEDIR)\recover.exe $(TEMP)\$(RCVRDEF) $(SYSOBJ) $(RECOVOBJS) $(PLIBS) DLBRLN = $(CC) $(LDFLAGS) -o $(TEMP)\dlb.exe $(TEMP)\$(DLBDEF) $(SYSOBJ) $(DLBOBJS) $(PLIBS) .END # # OS/2 module definition files for NetHack, # makedefs, dgn_comp, lev_comp, recover, dlb. # GAMEDEF = $(GAME).def MKDFDEF = makedefs.def LEVCDEF = lev_comp.def DGNCDEF = dgn_comp.def RCVRDEF = recover.def DLBDEF = dlb.def # # For compilation in DOS, enable the lower three lines and # disable the upper three. # MKDFMD = $(TEMP)\$(MKDFDEF) LEVCMD = $(TEMP)\$(LEVCDEF) DGNCMD = $(TEMP)\$(DGNCDEF) #MKDFMD = #LEVCMD = #DGNCMD = # # Optional high-quality BSD random number generation routines # (see os2conf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = # # If TERMLIB is defined in os2conf.h, comment out the upper line and # uncomment the lower. If the termcap-library doesn't exist, use # sys\share\makefile.lib to build it. # TERMLIB = #TERMLIB = termlib.lib # # Short / long file name selection for FAT and HPFS. # Only three files need consideration. # #GUIDEBOO = Guideboo # FAT #PATCHLEV = patchlev # - " - #DATABASE = data.bas # - " - GUIDEBOO = Guidebook # HPFS PATCHLEV = patchlevel # - " - DATABASE = data.base # - " - # # If you have LaTeX and want to create the NetHack Guidebook in TeX # device-independent file format, comment out the upper line and # uncomment the lower. # GUIDE = #GUIDE = $(TEMP)\$(GUIDEBOO).dvi # # Set WINOBJ lines corresponding to your desired combination # of windowing systems. Also set windowing systems in config.h. # # A straight tty port using no native windowing system is the # only choice for now. # WINOBJ1 = $(OBJ)\getline.o WINOBJ2 = $(OBJ)\termcap.o WINOBJ3 = $(OBJ)\topl.o WINOBJ4 = $(OBJ)\wintty.o WINOBJ = $(WINOBJ1) $(WINOBJ2) $(WINOBJ3) $(WINOBJ4) $(WINX11OBJ) # # The default make target, so just typing 'make' is useful. # Has to be the first target in the makefile. # default : all # # If you have yacc and lex programs and make any changes, uncomment # the lowermost two lines and comment out the others. If you make # changes to the .y and .l files but prefer processing the files # separately elsewhere, activate the middle two lines, so your changes # don't get overwritten. # do_yacc : yacc_cpy # use pre-generated files do_lex : lex_cpy # - " - #do_yacc : yacc_msg # show message if changed #do_lex : lex_msg # - " - #do_yacc : yacc_act # re-process files #do_lex : lex_act # - " - # # If you have the TOUCH utility the upper line is ok. Otherwise # the lower one does the same albeit in an ugly manner. Besides, # the latter method only works for text files. # #do_touch : realtouch do_touch : faketouch # # If you don't have uudecode program, use the upper line. # If you still want the icon, you'll have to extract the # file manually somewhere else. # do_icon : icon_msg # show message if changed #do_icon : icon_act # extract icon file # # If you don't want to generate nethack.cmd, use the upper line. # This could be the case, e.g., if you use a different shell than # the standard cmd.exe. # #do_cmd : cmd_msg # show message do_cmd : cmd_act # generate nethack.cmd # # If you want to try the data librarian scheme to reduce # the amount of data files in the NetHack home directory, comment # out the lower line and uncomment the upper. Also, make sure # that DLB is defined in config.h. # do_dlb : dlb_yup #do_dlb : dlb_nope ###################################################################### # # Nothing below this line should have to be changed. # # Other things that have to be reconfigured are in # config.h, os2conf.h and possibly system.h. # # # The game filename. # GAMEFILE = $(GAMEDIR)\$(GAME).exe # # Object files for makedefs. # MAKEOBJS = $(OBJ)\makedefs.o $(OBJ)\monst.o $(OBJ)\objects.o # # Object files for special levels compiler. # SOBJ01 = $(OBJ)\lev_yacc.o $(OBJ)\lev_lex.o $(OBJ)\lev_main.o $(OBJ)\alloc.o SOBJ02 = $(OBJ)\monst.o $(OBJ)\objects.o $(OBJ)\panic.o $(OBJ)\decl.o SOBJ03 = $(OBJ)\drawing.o SPLEVOBJS = $(SOBJ01) $(SOBJ02) $(SOBJ03) # # Object files for dungeon compiler. # DOBJ01 = $(OBJ)\dgn_yacc.o $(OBJ)\dgn_lex.o $(OBJ)\dgn_main.o DOBJ02 = $(OBJ)\panic.o $(OBJ)\alloc.o DGNCOMPOBJS = $(DOBJ01) $(DOBJ02) # # Object files for recovery utility. # RECOVOBJS = $(OBJ)\recover.o # # Object files for dlb. # DLBOBJS = $(OBJ)\dlb_main.o $(OBJ)\dlb.o $(OBJ)\alloc.o $(OBJ)\panic.o # # Data files for dlb. # DATHELP = \ help hh cmdhelp history opthelp wizhelp SPEC_LEVS = \ asmodeus.lev baalz.lev bigrm-1.lev \ bigrm-2.lev bigrm-3.lev bigrm-4.lev castle.lev fakewiz1.lev fakewiz2.lev \ juiblex.lev knox.lev medusa-1.lev medusa-2.lev minend-1.lev minend-2.lev \ minend-3.lev minefill.lev minetn-1.lev minetn-2.lev minetn-3.lev minetn-4.lev \ minetn-5.lev minetn-6.lev minetn-7.lev oracle.lev orcus.lev sanctum.lev \ tower1.lev tower2.lev tower3.lev valley.lev wizard1.lev wizard2.lev \ wizard3.lev astral.lev air.lev earth.lev fire.lev water.lev \ soko1-1.lev soko1-2.lev soko2-1.lev soko2-2.lev \ soko3-1.lev soko3-2.lev soko4-1.lev soko4-2.lev QUEST_LEVS = \ Arc-goal.lev Arc-fila.lev Arc-filb.lev Arc-loca.lev Arc-strt.lev \ Bar-goal.lev Bar-fila.lev Bar-filb.lev Bar-loca.lev Bar-strt.lev \ Cav-goal.lev Cav-fila.lev Cav-filb.lev Cav-loca.lev Cav-strt.lev \ Hea-goal.lev Hea-fila.lev Hea-filb.lev Hea-loca.lev Hea-strt.lev \ Kni-goal.lev Kni-fila.lev Kni-filb.lev Kni-loca.lev Kni-strt.lev \ Mon-goal.lev Mon-fila.lev Mon-filb.lev Mon-loca.lev Mon-strt.lev \ Pri-goal.lev Pri-fila.lev Pri-filb.lev Pri-loca.lev Pri-strt.lev \ Ran-goal.lev Ran-fila.lev Ran-filb.lev Ran-loca.lev Ran-strt.lev \ Rog-goal.lev Rog-fila.lev Rog-filb.lev Rog-loca.lev Rog-strt.lev \ Sam-goal.lev Sam-fila.lev Sam-filb.lev Sam-loca.lev Sam-strt.lev \ Tou-goal.lev Tou-fila.lev Tou-filb.lev Tou-loca.lev Tou-strt.lev \ Val-goal.lev Val-fila.lev Val-filb.lev Val-loca.lev Val-strt.lev \ Wiz-goal.lev Wiz-fila.lev Wiz-filb.lev Wiz-loca.lev Wiz-strt.lev VARDATD = \ data oracles options quest.dat rumors $(WINX11VARDAT) DATDLB = $(DATHELP) dungeon $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD) \ $(do_dlb) # # Object files for the game itself. # VOBJ011 = $(OBJ)\allmain.o VOBJ012 = $(OBJ)\alloc.o VOBJ013 = $(OBJ)\apply.o VOBJ014 = $(OBJ)\artifact.o VOBJ021 = $(OBJ)\attrib.o VOBJ022 = $(OBJ)\ball.o VOBJ023 = $(OBJ)\bones.o VOBJ024 = $(OBJ)\botl.o VOBJ031 = $(OBJ)\cmd.o VOBJ032 = $(OBJ)\dbridge.o VOBJ033 = $(OBJ)\decl.o VOBJ034 = $(OBJ)\detect.o VOBJ041 = $(OBJ)\dig.o VOBJ042 = $(OBJ)\display.o VOBJ043 = $(OBJ)\dlb.o VOBJ044 = $(OBJ)\do.o VOBJ051 = $(OBJ)\do_name.o VOBJ052 = $(OBJ)\do_wear.o VOBJ053 = $(OBJ)\dog.o VOBJ054 = $(OBJ)\dogmove.o VOBJ061 = $(OBJ)\dokick.o VOBJ062 = $(OBJ)\dothrow.o VOBJ063 = $(OBJ)\drawing.o VOBJ064 = $(OBJ)\dungeon.o VOBJ071 = $(OBJ)\eat.o VOBJ072 = $(OBJ)\end.o VOBJ073 = $(OBJ)\engrave.o VOBJ074 = $(OBJ)\exper.o VOBJ071 = $(OBJ)\eat.o VOBJ072 = $(OBJ)\end.o VOBJ073 = $(OBJ)\engrave.o VOBJ074 = $(OBJ)\exper.o VOBJ081 = $(OBJ)\explode.o VOBJ082 = $(OBJ)\extralev.o VOBJ083 = $(OBJ)\files.o VOBJ084 = $(OBJ)\fountain.o VOBJ091 = $(OBJ)\hack.o VOBJ092 = $(OBJ)\hacklib.o VOBJ093 = $(OBJ)\invent.o VOBJ094 = $(OBJ)\light.o VOBJ101 = $(OBJ)\lock.o VOBJ102 = $(OBJ)\mail.o VOBJ103 = $(OBJ)\main.o VOBJ104 = $(OBJ)\makemon.o VOBJ111 = $(OBJ)\mapglyph.o VOBJ112 = $(OBJ)\mcastu.o VOBJ113 = $(OBJ)\mhitm.o VOBJ114 = $(OBJ)\mhitu.o VOBJ115 = $(OBJ)\minion.o VOBJ121 = $(OBJ)\mklev.o VOBJ122 = $(OBJ)\mkmap.o VOBJ123 = $(OBJ)\mkmaze.o VOBJ124 = $(OBJ)\mkobj.o VOBJ131 = $(OBJ)\mkroom.o VOBJ132 = $(OBJ)\mon.o VOBJ133 = $(OBJ)\mondata.o VOBJ134 = $(OBJ)\monmove.o VOBJ141 = $(OBJ)\monst.o VOBJ142 = $(OBJ)\monstr.o VOBJ143 = $(OBJ)\mplayer.o VOBJ144 = $(OBJ)\mthrowu.o VOBJ151 = $(OBJ)\muse.o VOBJ152 = $(OBJ)\music.o VOBJ153 = $(OBJ)\o_init.o VOBJ154 = $(OBJ)\objects.o VOBJ161 = $(OBJ)\objnam.o VOBJ162 = $(OBJ)\options.o VOBJ163 = $(OBJ)\os2.o VOBJ164 = $(OBJ)\pager.o VOBJ171 = $(OBJ)\pcsys.o VOBJ172 = $(OBJ)\pickup.o VOBJ173 = $(OBJ)\pline.o VOBJ174 = $(OBJ)\polyself.o VOBJ181 = $(OBJ)\potion.o VOBJ182 = $(OBJ)\pray.o VOBJ183 = $(OBJ)\priest.o VOBJ184 = $(OBJ)\quest.o VOBJ191 = $(OBJ)\questpgr.o VOBJ192 = $(OBJ)\read.o VOBJ193 = $(OBJ)\rect.o VOBJ194 = $(OBJ)\region.o VOBJ195 = $(OBJ)\restore.o VOBJ201 = $(OBJ)\rip.o VOBJ202 = $(OBJ)\rnd.o VOBJ203 = $(OBJ)\rumors.o VOBJ204 = $(OBJ)\save.o VOBJ211 = $(OBJ)\shk.o VOBJ212 = $(OBJ)\shknam.o VOBJ213 = $(OBJ)\sit.o VOBJ214 = $(OBJ)\sounds.o VOBJ221 = $(OBJ)\sp_lev.o VOBJ222 = $(OBJ)\spell.o VOBJ223 = $(OBJ)\steal.o VOBJ224 = $(OBJ)\teleport.o VOBJ231 = $(OBJ)\timeout.o VOBJ232 = $(OBJ)\topten.o VOBJ233 = $(OBJ)\track.o VOBJ234 = $(OBJ)\trap.o VOBJ241 = $(OBJ)\tty.o VOBJ242 = $(OBJ)\u_init.o VOBJ243 = $(OBJ)\uhitm.o VOBJ244 = $(OBJ)\unix.o VOBJ251 = $(OBJ)\vault.o VOBJ252 = $(OBJ)\vision.o VOBJ253 = $(OBJ)\vis_tab.o VOBJ254 = $(OBJ)\weapon.o VOBJ261 = $(OBJ)\were.o VOBJ262 = $(OBJ)\wield.o VOBJ263 = $(OBJ)\windows.o VOBJ264 = $(OBJ)\wizard.o VOBJ271 = $(OBJ)\worm.o VOBJ272 = $(OBJ)\worn.o VOBJ273 = $(OBJ)\write.o VOBJ274 = $(OBJ)\zap.o VOBJ281 = $(OBJ)\role.o VOBJ282 = $(OBJ)\steed.o VOBJ283 = $(OBJ)\sys.o VOBJ01 = $(VOBJ011) $(VOBJ012) $(VOBJ013) $(VOBJ014) VOBJ02 = $(VOBJ021) $(VOBJ022) $(VOBJ023) $(VOBJ024) VOBJ03 = $(VOBJ031) $(VOBJ032) $(VOBJ033) $(VOBJ034) VOBJ04 = $(VOBJ041) $(VOBJ042) $(VOBJ043) $(VOBJ044) VOBJ05 = $(VOBJ051) $(VOBJ052) $(VOBJ053) $(VOBJ054) VOBJ06 = $(VOBJ061) $(VOBJ062) $(VOBJ063) $(VOBJ064) VOBJ07 = $(VOBJ071) $(VOBJ072) $(VOBJ073) $(VOBJ074) VOBJ08 = $(VOBJ081) $(VOBJ082) $(VOBJ083) $(VOBJ084) VOBJ09 = $(VOBJ091) $(VOBJ092) $(VOBJ093) $(VOBJ094) VOBJ10 = $(VOBJ101) $(VOBJ102) $(VOBJ103) $(VOBJ104) VOBJ11 = $(VOBJ111) $(VOBJ112) $(VOBJ113) $(VOBJ114) $(VOBJ115) VOBJ12 = $(VOBJ121) $(VOBJ122) $(VOBJ123) $(VOBJ124) VOBJ13 = $(VOBJ131) $(VOBJ132) $(VOBJ133) $(VOBJ134) VOBJ14 = $(VOBJ141) $(VOBJ142) $(VOBJ143) $(VOBJ144) VOBJ15 = $(VOBJ151) $(VOBJ152) $(VOBJ153) $(VOBJ154) VOBJ16 = $(VOBJ161) $(VOBJ162) $(VOBJ163) $(VOBJ164) VOBJ17 = $(VOBJ171) $(VOBJ172) $(VOBJ173) $(VOBJ174) VOBJ18 = $(VOBJ181) $(VOBJ182) $(VOBJ183) $(VOBJ184) VOBJ19 = $(VOBJ191) $(VOBJ192) $(VOBJ193) $(VOBJ194) $(VOBJ195) VOBJ20 = $(VOBJ201) $(VOBJ202) $(VOBJ203) $(VOBJ204) VOBJ21 = $(VOBJ211) $(VOBJ212) $(VOBJ213) $(VOBJ214) VOBJ22 = $(VOBJ221) $(VOBJ222) $(VOBJ223) $(VOBJ224) VOBJ23 = $(VOBJ231) $(VOBJ232) $(VOBJ233) $(VOBJ234) VOBJ24 = $(VOBJ241) $(VOBJ242) $(VOBJ243) $(VOBJ244) VOBJ25 = $(VOBJ251) $(VOBJ252) $(VOBJ253) $(VOBJ254) VOBJ26 = $(VOBJ261) $(VOBJ262) $(VOBJ263) $(VOBJ264) VOBJ27 = $(VOBJ271) $(VOBJ272) $(VOBJ273) $(VOBJ274) VOBJ28 = $(VOBJ281) $(VOBJ282) $(VOBJ283) VOBJ29 = $(WINOBJ) $(RANDOM) HHOBJ = $(OBJ)\version.o VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) $(VOBJ06) $(VOBJ07) \ $(VOBJ08) $(VOBJ09) $(VOBJ10) $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) \ $(VOBJ15) $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) $(VOBJ21) \ $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) $(VOBJ26) $(VOBJ27) $(VOBJ28) \ $(VOBJ29) HOBJ = $(VOBJ) $(HHOBJ) EXTERN_H = # $(INCL)\extern.h OS2CONF_H = $(INCL)\os2conf.h $(INCL)\micro.h $(INCL)\system.h $(EXTERN_H) GLOBAL_H = $(INCL)\global.h $(INCL)\coord.h $(OS2CONF_H) CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h $(GLOBAL_H) TRAP_H = $(INCL)\trap.h PERMONST_H = $(INCL)\permonst.h $(INCL)\monattk.h $(INCL)\monflag.h YOU_H = $(INCL)\you.h $(INCL)\attrib.h $(PERMONST_H) $(INCL)\mondata.h \ $(INCL)\monst.h $(INCL)\mextra.h $(INCL)\youprop.h \ $(INCL)\prop.h $(INCL)\pm.h DECL_H = $(INCL)\decl.h $(INCL)\spell.h $(INCL)\obj.h $(YOU_H) \ $(INCL)\onames.h $(INCL)\color.h HACK_H = $(CONFIG_H) $(INCL)\context.h $(DECL_H) $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(TRAP_H) $(INCL)\engrave.h $(INCL)\flag.h \ $(INCL)\rm.h $(INCL)\dungeon.h $(INCL)\hack.h $(INCL)\display.h \ $(INCL)\vision.h $(INCL)\wintty.h $(INCL)\wintype.h $(INCL)\align.h \ $(INCL)\winprocs.h $(INCL)\sys.h # # The default target. # all : makedefs dgn_comp lev_comp recover $(GAME) dat $(GUIDE) $(ECHO) Done. # # Definition file creation. # $(TEMP)\$(GAMEDEF) : $(MAKEB) DD_NAME=$(GAME) DD_DESC=$(GAMEDES) DD_TARG=$@ do_def $(TEMP)\$(MKDFDEF) : $(MAKEB) DD_NAME=makedefs DD_DESC="Definitions compiler" DD_TARG=$@ do_def $(TEMP)\$(DGNCDEF) : $(MAKEB) DD_NAME=dgn_comp DD_DESC="Dungeon compiler" DD_TARG=$@ do_def $(TEMP)\$(LEVCDEF) : $(MAKEB) DD_NAME=lev_comp DD_DESC="Level compiler" DD_TARG=$@ do_def $(TEMP)\$(RCVRDEF) : $(MAKEB) DD_NAME=recover DD_DESC="Recovery utility" DD_TARG=$@ do_def $(TEMP)\$(DLBDEF) : $(MAKEB) DD_NAME=dlb DD_DESC="Archive utility" DD_TARG=$@ do_def do_def : $(ECHO) NAME $(DD_NAME) WINDOWCOMPAT> $(DD_TARG) $(ECHO) DESCRIPTION '$(DD_DESC)'>> $(DD_TARG) $(ECHO) PROTMODE>> $(DD_TARG) $(ECHO) EXETYPE OS2>> $(DD_TARG) # # The main target. # $(GAME) : $(GAMEDIR)\$(GAME).exe $(GAME).exe : $(GAMEDIR)\$(GAME).exe $(GAMEDIR)\$(GAME).exe : $(TEMP)\$(GAME).rsp $(TEMP)\$(GAME).r $(GAMELN) $(TEMP)\$(GAME).r : $(HOBJ) $(TEMP)\$(GAMEDEF) $(ECHO) $(VOBJ011) > $@ $(ECHO) $(VOBJ012) >> $@ $(ECHO) $(VOBJ013) >> $@ $(ECHO) $(VOBJ014) >> $@ $(ECHO) $(VOBJ021) >> $@ $(ECHO) $(VOBJ022) >> $@ $(ECHO) $(VOBJ023) >> $@ $(ECHO) $(VOBJ024) >> $@ $(ECHO) $(VOBJ031) >> $@ $(ECHO) $(VOBJ032) >> $@ $(ECHO) $(VOBJ033) >> $@ $(ECHO) $(VOBJ034) >> $@ $(ECHO) $(VOBJ041) >> $@ $(ECHO) $(VOBJ042) >> $@ $(ECHO) $(VOBJ043) >> $@ $(ECHO) $(VOBJ044) >> $@ $(ECHO) $(VOBJ051) >> $@ $(ECHO) $(VOBJ052) >> $@ $(ECHO) $(VOBJ053) >> $@ $(ECHO) $(VOBJ054) >> $@ $(ECHO) $(VOBJ061) >> $@ $(ECHO) $(VOBJ062) >> $@ $(ECHO) $(VOBJ063) >> $@ $(ECHO) $(VOBJ064) >> $@ $(ECHO) $(VOBJ071) >> $@ $(ECHO) $(VOBJ072) >> $@ $(ECHO) $(VOBJ073) >> $@ $(ECHO) $(VOBJ074) >> $@ $(ECHO) $(VOBJ081) >> $@ $(ECHO) $(VOBJ082) >> $@ $(ECHO) $(VOBJ083) >> $@ $(ECHO) $(VOBJ084) >> $@ $(ECHO) $(VOBJ091) >> $@ $(ECHO) $(VOBJ092) >> $@ $(ECHO) $(VOBJ093) >> $@ $(ECHO) $(VOBJ094) >> $@ $(ECHO) $(VOBJ101) >> $@ $(ECHO) $(VOBJ102) >> $@ $(ECHO) $(VOBJ103) >> $@ $(ECHO) $(VOBJ104) >> $@ $(ECHO) $(VOBJ111) >> $@ $(ECHO) $(VOBJ112) >> $@ $(ECHO) $(VOBJ113) >> $@ $(ECHO) $(VOBJ114) >> $@ $(ECHO) $(VOBJ115) >> $@ $(ECHO) $(VOBJ121) >> $@ $(ECHO) $(VOBJ122) >> $@ $(ECHO) $(VOBJ123) >> $@ $(ECHO) $(VOBJ124) >> $@ $(ECHO) $(VOBJ131) >> $@ $(ECHO) $(VOBJ132) >> $@ $(ECHO) $(VOBJ133) >> $@ $(ECHO) $(VOBJ134) >> $@ $(ECHO) $(VOBJ141) >> $@ $(ECHO) $(VOBJ142) >> $@ $(ECHO) $(VOBJ143) >> $@ $(ECHO) $(VOBJ144) >> $@ $(ECHO) $(VOBJ151) >> $@ $(ECHO) $(VOBJ152) >> $@ $(ECHO) $(VOBJ153) >> $@ $(ECHO) $(VOBJ154) >> $@ $(ECHO) $(VOBJ161) >> $@ $(ECHO) $(VOBJ162) >> $@ $(ECHO) $(VOBJ163) >> $@ $(ECHO) $(VOBJ164) >> $@ $(ECHO) $(VOBJ171) >> $@ $(ECHO) $(VOBJ172) >> $@ $(ECHO) $(VOBJ173) >> $@ $(ECHO) $(VOBJ174) >> $@ $(ECHO) $(VOBJ181) >> $@ $(ECHO) $(VOBJ182) >> $@ $(ECHO) $(VOBJ183) >> $@ $(ECHO) $(VOBJ184) >> $@ $(ECHO) $(VOBJ191) >> $@ $(ECHO) $(VOBJ192) >> $@ $(ECHO) $(VOBJ193) >> $@ $(ECHO) $(VOBJ194) >> $@ $(ECHO) $(VOBJ195) >> $@ $(ECHO) $(VOBJ201) >> $@ $(ECHO) $(VOBJ202) >> $@ $(ECHO) $(VOBJ203) >> $@ $(ECHO) $(VOBJ204) >> $@ $(ECHO) $(VOBJ211) >> $@ $(ECHO) $(VOBJ212) >> $@ $(ECHO) $(VOBJ213) >> $@ $(ECHO) $(VOBJ214) >> $@ $(ECHO) $(VOBJ221) >> $@ $(ECHO) $(VOBJ222) >> $@ $(ECHO) $(VOBJ223) >> $@ $(ECHO) $(VOBJ224) >> $@ $(ECHO) $(VOBJ231) >> $@ $(ECHO) $(VOBJ232) >> $@ $(ECHO) $(VOBJ233) >> $@ $(ECHO) $(VOBJ234) >> $@ $(ECHO) $(VOBJ241) >> $@ $(ECHO) $(VOBJ242) >> $@ $(ECHO) $(VOBJ243) >> $@ $(ECHO) $(VOBJ244) >> $@ $(ECHO) $(VOBJ251) >> $@ $(ECHO) $(VOBJ252) >> $@ $(ECHO) $(VOBJ253) >> $@ $(ECHO) $(VOBJ254) >> $@ $(ECHO) $(VOBJ261) >> $@ $(ECHO) $(VOBJ262) >> $@ $(ECHO) $(VOBJ263) >> $@ $(ECHO) $(VOBJ264) >> $@ $(ECHO) $(VOBJ271) >> $@ $(ECHO) $(VOBJ272) >> $@ $(ECHO) $(VOBJ273) >> $@ $(ECHO) $(VOBJ274) >> $@ $(ECHO) $(VOBJ281) >> $@ $(ECHO) $(VOBJ282) >> $@ $(ECHO) $(VOBJ283) >> $@ $(ECHO) $(WINOBJ1) >> $@ $(ECHO) $(WINOBJ2) >> $@ $(ECHO) $(WINOBJ3) >> $@ $(ECHO) $(WINOBJ4) >> $@ $(ECHO) $(HHOBJ) >> $@ $(ECHO) $(RANDOM) >> $@ .IF $(with_x11) == yes $(X11ECHO) $(WINX11OBJ01) >> $@ $(X11ECHO) $(WINX11OBJ02) >> $@ $(X11ECHO) $(WINX11OBJ03) >> $@ $(X11ECHO) $(WINX11OBJ04) >> $@ $(X11ECHO) $(WINX11OBJ05) >> $@ $(X11ECHO) $(WINX11OBJ06) >> $@ $(X11ECHO) $(WINX11OBJ07) >> $@ $(X11ECHO) $(WINX11OBJ08) >> $@ $(X11ECHO) $(WINX11OBJ09) >> $@ $(X11ECHO) $(WINX11OBJ10) >> $@ $(X11ECHO) $(WINX11OBJ11) >> $@ .END $(TEMP)\$(GAME).rsp : $(HOBJ) $(TEMP)\$(GAMEDEF) $(ECHO) $(SYSOBJ) $(VOBJ01) +> $@ $(ECHO) $(VOBJ02) +>> $@ $(ECHO) $(VOBJ03) +>> $@ $(ECHO) $(VOBJ04) +>> $@ $(ECHO) $(VOBJ05) +>> $@ $(ECHO) $(VOBJ06) +>> $@ $(ECHO) $(VOBJ07) +>> $@ $(ECHO) $(VOBJ08) +>> $@ $(ECHO) $(VOBJ09) +>> $@ $(ECHO) $(VOBJ10) +>> $@ $(ECHO) $(VOBJ11) +>> $@ $(ECHO) $(VOBJ12) +>> $@ $(ECHO) $(VOBJ13) +>> $@ $(ECHO) $(VOBJ14) +>> $@ $(ECHO) $(VOBJ15) +>> $@ $(ECHO) $(VOBJ16) +>> $@ $(ECHO) $(VOBJ17) +>> $@ $(ECHO) $(VOBJ18) +>> $@ $(ECHO) $(VOBJ19) +>> $@ $(ECHO) $(VOBJ20) +>> $@ $(ECHO) $(VOBJ21) +>> $@ $(ECHO) $(VOBJ22) +>> $@ $(ECHO) $(VOBJ23) +>> $@ $(ECHO) $(VOBJ24) +>> $@ $(ECHO) $(VOBJ25) +>> $@ $(ECHO) $(VOBJ26) +>> $@ $(ECHO) $(VOBJ27) +>> $@ $(ECHO) $(VOBJ28) +>> $@ $(ECHO) $(VOBJ29) +>> $@ $(ECHO) $(VOBJ30) +>> $@ $(ECHO) $(HHOBJ)>> $@ $(ECHO) $(GAMEDIR)\$(GAME).exe>> $@ $(ECHO) $(TEMP)\$(GAME)>> $@ $(ECHO) $(PLIBS) $(TERMLIB)>> $@ $(ECHO) $(TEMP)\$(GAMEDEF) $(LFLAGS);>> $@ # # Targets for makedefs. # makedefs : $(TEMP)\makedefs.exe $(TEMP)\makedefs.exe : $(TEMP)\makedefs.rsp $(MKDFLN) $(TEMP)\makedefs.rsp : $(MAKEOBJS) $(TEMP)\$(MKDFDEF) $(ECHO) $(SYSOBJ) $(MAKEOBJS)> $@ $(ECHO) $(TEMP)\makedefs.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(RLIBS)>> $@ $(ECHO) $(MKDFMD) $(LFLAGS);>> $@ $(OBJ)\makedefs.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\permonst.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\artilist.h $(INCL)\qtext.h $(UTILCC) # # Targets for the special levels compiler. # lev_comp : $(TEMP)\lev_comp.exe $(TEMP)\lev_comp.exe : $(TEMP)\lev_comp.rsp $(LEVCLN) $(TEMP)\lev_comp.rsp : $(SPLEVOBJS) $(TEMP)\$(LEVCDEF) $(ECHO) $(SYSOBJ) $(SOBJ01) +> $@ $(ECHO) $(SOBJ02) +>> $@ $(ECHO) $(SOBJ03)>> $@ $(ECHO) $(TEMP)\lev_comp.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(RLIBS)>> $@ $(ECHO) $(LEVCMD) $(LFLAGS);>> $@ $(OBJ)\lev_yacc.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(UTILCC) $(OBJ)\lev_lex.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev_comp.h $(UTILCC) $(OBJ)\lev_main.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\tcap.h $(UTILCC) $(UTIL)\lev_yacc.c : $(UTIL)\lev_comp.y $(MAKEB) YY=lev do_yacc $(UTIL)\lev_lex.c : $(UTIL)\lev_comp.l $(MAKEB) YY=lev do_lex # # Targets for the dungeon compiler. # dgn_comp : $(TEMP)\dgn_comp.exe $(TEMP)\dgn_comp.exe : $(TEMP)\dgn_comp.rsp $(DGNCLN) $(TEMP)\dgn_comp.rsp : $(DGNCOMPOBJS) $(TEMP)\$(DGNCDEF) $(ECHO) $(SYSOBJ) $(DOBJ01) +> $@ $(ECHO) $(DOBJ02)>> $@ $(ECHO) $(TEMP)\dgn_comp.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(RLIBS)>> $@ $(ECHO) $(DGNCMD) $(LFLAGS);>> $@ $(OBJ)\dgn_yacc.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\date.h $(INCL)\dgn_file.h $(UTILCC) $(OBJ)\dgn_lex.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\dgn_comp.h $(INCL)\dgn_file.h $(UTILCC) $(OBJ)\dgn_main.o : $(UTIL)\$(CB) $(CONFIG_H) $(UTILCC) $(UTIL)\dgn_yacc.c : $(UTIL)\dgn_comp.y $(MAKEB) YY=dgn do_yacc $(UTIL)\dgn_lex.c : $(UTIL)\dgn_comp.l $(MAKEB) YY=dgn do_lex # # For both lev_comp and dgn_comp. # $(OBJ)\panic.o : $(UTIL)\$(CB) $(CONFIG_H) $(UTILCC) # # Yacc and Lex targets. # yacc_cpy : $(CP) $(SSYS)\$(YY)_yacc.c $(UTIL) $(CP) $(SSYS)\$(YY)_comp.h $(INCL) $(MAKEB) TT=$(UTIL)\$(YY)_yacc.c do_touch $(MAKEB) TT=$(INCL)\$(YY)_comp.h do_touch yacc_msg : $(ECHO) $(YY)_comp.y has changed. To update $(YY)_yacc.c and $(YY)_comp.h run $(YACC). yacc_act : $(YACC) -d $(UTIL)\$(YY)_comp.y $(CP) $(YTABC) $(UTIL)\$(YY)_yacc.c $(CP) $(YTABH) $(INCL)\$(YY)_comp.h $(RM) $(YTABC) $(RM) $(YTABH) lex_cpy : $(CP) $(SSYS)\$(YY)_lex.c $(UTIL) $(MAKEB) TT=$(UTIL)\$(YY)_lex.c do_touch lex_msg : $(ECHO) $(YY)_comp.l has changed. To update $(YY)_lex.c run $(LEX). lex_act : $(LEX) $(UTIL)\$(YY)_comp.l $(CP) $(LEXYYC) $(UTIL)\$(YY)_lex.c $(RM) $(LEXYYC) # # Why must this be so kludgy? # realtouch : $(TOUCH) $(TT) faketouch : $(BEG) $(CAT) $(TT) > $(TEMP)\foo.bar $(SEP) $(CP) $(TEMP)\foo.bar $(TT) $(SEP) $(RM) $(TEMP)\foo.bar $(END) # # Targets for the recovery utility. # recover : $(GAMEDIR)\recover.exe $(GAMEDIR)\recover.exe : $(TEMP)\recover.rsp $(RCVRLN) $(TEMP)\recover.rsp : $(RECOVOBJS) $(TEMP)\$(RCVRDEF) $(ECHO) $(SYSOBJ) $(RECOVOBJS)> $@ $(ECHO) $(GAMEDIR)\recover.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(PLIBS)>> $@ $(ECHO) $(TEMP)\$(RCVRDEF) $(LFLAGS);>> $@ $(OBJ)\recover.o : $(UTIL)\$(CB) $(CONFIG_H) $(UTILCC) # # Targets for the dlb. # dlb : $(TEMP)\dlb.exe $(TEMP)\dlb.exe : $(TEMP)\dlb.rsp $(DLBRLN) $(TEMP)\dlb.rsp : $(DLBOBJS) $(TEMP)\$(DLBDEF) $(ECHO) $(SYSOBJ) $(DLBOBJS)> $@ $(ECHO) $(TEMP)\dlb.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(PLIBS)>> $@ $(ECHO) $(TEMP)\$(DLBDEF) $(LFLAGS);>> $@ $(OBJ)\dlb_main.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\dlb.h $(UTILCC) $(GAMEDIR)\nhdat : $(WINX11VARDAT) $(MAKEB) do_dlb dlb_yup : dlb $(TEMP)\dlb cCf $(GAMEDIR) $(GAMEDIR)\nhdat $(DATDLB) -$(RM) $(GAMEDIR)\help -$(RM) $(GAMEDIR)\hh -$(RM) $(GAMEDIR)\cmdhelp -$(RM) $(GAMEDIR)\history -$(RM) $(GAMEDIR)\opthelp -$(RM) $(GAMEDIR)\wizhelp -$(RM) $(GAMEDIR)\asmodeus.lev -$(RM) $(GAMEDIR)\baalz.lev -$(RM) $(GAMEDIR)\bigrm-?.lev -$(RM) $(GAMEDIR)\castle.lev -$(RM) $(GAMEDIR)\fakewiz?.lev -$(RM) $(GAMEDIR)\juiblex.lev -$(RM) $(GAMEDIR)\knox.lev -$(RM) $(GAMEDIR)\medusa-?.lev -$(RM) $(GAMEDIR)\minend-?.lev -$(RM) $(GAMEDIR)\minefill.lev -$(RM) $(GAMEDIR)\minetn-?.lev -$(RM) $(GAMEDIR)\oracle.lev -$(RM) $(GAMEDIR)\orcus.lev -$(RM) $(GAMEDIR)\sanctum.lev -$(RM) $(GAMEDIR)\tower?.lev -$(RM) $(GAMEDIR)\valley.lev -$(RM) $(GAMEDIR)\wizard?.lev -$(RM) $(GAMEDIR)\astral.lev -$(RM) $(GAMEDIR)\air.lev -$(RM) $(GAMEDIR)\earth.lev -$(RM) $(GAMEDIR)\fire.lev -$(RM) $(GAMEDIR)\water.lev -$(RM) $(GAMEDIR)\???-goal.lev -$(RM) $(GAMEDIR)\???-fil?.lev -$(RM) $(GAMEDIR)\???-loca.lev -$(RM) $(GAMEDIR)\???-strt.lev -$(RM) $(GAMEDIR)\data -$(RM) $(GAMEDIR)\oracles -$(RM) $(GAMEDIR)\options -$(RM) $(GAMEDIR)\quest.dat -$(RM) $(GAMEDIR)\rumors -$(RM) $(GAMEDIR)\dungeon -$(RM) $(GAMEDIR)\soko?-?.lev # -$(RM) $(GAMEDIR)\pet_mark.xbm # -$(RM) $(GAMEDIR)\rip.xpm dlb_nope : $(ECHO) DLB not requested. # # The following files depend on makedefs to be created. # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h : $(VOBJ) $(TEMP)\makedefs.exe $(TEMP)\makedefs -v $(CP) $(DAT)\options $(GAMEDIR) $(RM) $(DAT)\options $(INCL)\onames.h : $(TEMP)\makedefs.exe $(TEMP)\makedefs -o $(INCL)\pm.h : $(TEMP)\makedefs.exe $(TEMP)\makedefs -p monstr.c : $(TEMP)\makedefs.exe $(TEMP)\makedefs -m $(OBJ)\monstr.o : $(CB) $(SRCCC) $(GAMEDIR)\data : $(DAT)\$(DATABASE) $(TEMP)\makedefs.exe $(TEMP)\makedefs -d $(CP) $(DAT)\data $(GAMEDIR) $(RM) $(DAT)\data $(GAMEDIR)\rumors : $(DAT)\rumors.tru $(DAT)\rumors.fal $(TEMP)\makedefs.exe $(TEMP)\makedefs -r $(CP) $(DAT)\rumors $(GAMEDIR) $(RM) $(DAT)\rumors $(GAMEDIR)\oracles : $(DAT)\oracles.txt $(TEMP)\makedefs.exe $(TEMP)\makedefs -h $(CP) $(DAT)\oracles $(GAMEDIR) $(RM) $(DAT)\oracles $(GAMEDIR)\quest.dat : $(DAT)\quest.txt $(TEMP)\makedefs.exe $(TEMP)\makedefs -q $(CP) $(DAT)\quest.dat $(GAMEDIR) $(RM) $(DAT)\quest.dat # # Vision tables for algorithm D. # vis_tab.c : $(INCL)\vis_tab.h $(INCL)\vis_tab.h : $(TEMP)\makedefs.exe $(TEMP)\makedefs -z $(OBJ)\vis_tab.o : $(CB) $(SRCCC) # # The following programs vary depending on what OS you are using. # $(OBJ)\main.o : $(SSYS)\pc$(CB) $(HACK_H) $(INCL)\dlb.h $(PSYSCC) $(OBJ)\tty.o : $(SSYS)\pc$(CB) $(HACK_H) $(INCL)\func_tab.h $(PSYSCC) $(OBJ)\unix.o : $(SSYS)\pc$(CB) $(HACK_H) $(PSYSCC) # # Other system specific modules. # $(OBJ)\os2.o : $(SYS)\$(CB) $(HACK_H) $(INCL)\tcap.h $(INCL)\def_os2.h $(SYSCC) $(OBJ)\pcsys.o : $(SSYS)\$(CB) $(HACK_H) $(SSYSCC) # # Berkeley random(3) routines. # $(OBJ)\random.o : $(SSYS)\$(CB) $(SSYSCC) # # Window source. # $(OBJ)\getline.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\func_tab.h $(WINCC) $(OBJ)\termcap.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h $(WINCC) $(OBJ)\topl.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h $(WINCC) $(OBJ)\wintty.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h $(INCL)\date.h $(WINCC) # # Secondary targets. # dat : spec_lev help_fil $(GAMEDIR)\dungeon $(GAMEDIR)\data $(GAMEDIR)\rumors \ $(GAMEDIR)\oracles $(GAMEDIR)\quest.dat $(GAMEDIR)\$(GAME).ico \ $(GAMEDIR)\$(GAME).cmd $(GAMEDIR)\nethack.cnf $(GAMEDIR)\nhdat \ $(WINX11VARDAT) help_fil : $(GAMEDIR)\cmdhelp $(GAMEDIR)\help $(GAMEDIR)\hh $(GAMEDIR)\history \ $(GAMEDIR)\license $(GAMEDIR)\opthelp $(GAMEDIR)\wizhelp $(GAMEDIR)\cmdhelp : $(DAT)\cmdhelp $(CP) $(DAT)\cmdhelp $(GAMEDIR) $(GAMEDIR)\help : $(DAT)\help $(CP) $(DAT)\help $(GAMEDIR) $(GAMEDIR)\hh : $(DAT)\hh $(CP) $(DAT)\hh $(GAMEDIR) $(GAMEDIR)\history : $(DAT)\history $(CP) $(DAT)\history $(GAMEDIR) $(GAMEDIR)\license : $(DAT)\license $(CP) $(DAT)\license $(GAMEDIR) $(GAMEDIR)\opthelp : $(DAT)\opthelp $(CP) $(DAT)\opthelp $(GAMEDIR) $(GAMEDIR)\wizhelp : $(DAT)\wizhelp $(CP) $(DAT)\wizhelp $(GAMEDIR) $(GAMEDIR)\dungeon : $(DAT)\dungeon.def $(TEMP)\makedefs.exe $(TEMP)\dgn_comp.exe $(TEMP)\makedefs -e $(TEMP)\dgn_comp $(DAT)\dungeon.pdf $(CP) $(DAT)\dungeon $(GAMEDIR) $(RM) $(DAT)\dungeon.pdf $(RM) $(DAT)\dungeon AFILES = $(GAMEDIR)\Arc-goal.lev BFILES = $(GAMEDIR)\Bar-goal.lev CFILES = $(GAMEDIR)\Cav-goal.lev HFILES = $(GAMEDIR)\Hea-goal.lev KFILES = $(GAMEDIR)\Kni-goal.lev MFILES = $(GAMEDIR)\Mon-goal.lev PFILES = $(GAMEDIR)\Pri-goal.lev RANFILES = $(GAMEDIR)\Ran-goal.lev RFILES = $(GAMEDIR)\Rog-goal.lev SFILES = $(GAMEDIR)\Sam-goal.lev TFILES = $(GAMEDIR)\Tou-goal.lev VFILES = $(GAMEDIR)\Val-goal.lev WFILES = $(GAMEDIR)\Wiz-goal.lev XFILES = $(AFILES) $(BFILES) $(CFILES) $(HFILES) $(KFILES) $(MFILES) \ $(PFILES) $(RANFILES) $(RFILES) $(SFILES) $(TFILES) $(VFILES) $(WFILES) spec_lev : $(GAMEDIR)\astral.lev $(GAMEDIR)\bigrm-1.lev $(GAMEDIR)\castle.lev \ $(GAMEDIR)\knox.lev $(GAMEDIR)\medusa-1.lev $(GAMEDIR)\minefill.lev \ $(GAMEDIR)\oracle.lev $(GAMEDIR)\tower1.lev $(GAMEDIR)\valley.lev \ $(GAMEDIR)\wizard1.lev $(GAMEDIR)\soko1-1.lev $(XFILES) # Single special level files $(GAMEDIR)\castle.lev : $(DAT)\castle.des $(TEMP)\lev_comp.exe $(MAKEB) LF=castle do_slev $(GAMEDIR)\knox.lev : $(DAT)\knox.des $(TEMP)\lev_comp.exe $(MAKEB) LF=knox do_slev $(GAMEDIR)\oracle.lev : $(DAT)\oracle.des $(TEMP)\lev_comp.exe $(MAKEB) LF=oracle do_slev do_slev : $(TEMP)\lev_comp $(DAT)\$(LF).des $(CP) $(LF).lev $(GAMEDIR) $(RM) $(LF).lev # Multiple special level files $(GAMEDIR)\astral.lev : $(DAT)\endgame.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\endgame.des $(CP) air.lev $(GAMEDIR) $(CP) astral.lev $(GAMEDIR) $(CP) earth.lev $(GAMEDIR) $(CP) fire.lev $(GAMEDIR) $(CP) water.lev $(GAMEDIR) $(RM) air.lev $(RM) astral.lev $(RM) earth.lev $(RM) fire.lev $(RM) water.lev $(GAMEDIR)\bigrm-1.lev : $(DAT)\bigroom.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\bigroom.des $(CP) bigrm-?.lev $(GAMEDIR) $(RM) bigrm-?.lev $(GAMEDIR)\medusa-1.lev : $(DAT)\medusa.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\medusa.des $(CP) medusa-?.lev $(GAMEDIR) $(RM) medusa-?.lev $(GAMEDIR)\minefill.lev : $(DAT)\mines.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\mines.des $(CP) minend-?.lev $(GAMEDIR) $(CP) minefill.lev $(GAMEDIR) $(CP) minetn-?.lev $(GAMEDIR) $(RM) minend-?.lev $(RM) minefill.lev $(RM) minetn-?.lev $(GAMEDIR)\tower1.lev : $(DAT)\tower.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\tower.des $(CP) tower?.lev $(GAMEDIR) $(RM) tower?.lev $(GAMEDIR)\valley.lev : $(DAT)\gehennom.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\gehennom.des $(CP) asmodeus.lev $(GAMEDIR) $(CP) baalz.lev $(GAMEDIR) $(CP) juiblex.lev $(GAMEDIR) $(CP) orcus.lev $(GAMEDIR) $(CP) sanctum.lev $(GAMEDIR) $(CP) valley.lev $(GAMEDIR) $(RM) asmodeus.lev $(RM) baalz.lev $(RM) juiblex.lev $(RM) orcus.lev $(RM) sanctum.lev $(RM) valley.lev $(GAMEDIR)\wizard1.lev : $(DAT)\yendor.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\yendor.des $(CP) wizard?.lev $(GAMEDIR) $(CP) fakewiz?.lev $(GAMEDIR) $(RM) wizard?.lev $(RM) fakewiz?.lev $(GAMEDIR)\soko1-1.lev : $(DAT)\sokoban.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\sokoban.des $(CP) soko?-?.lev $(GAMEDIR) $(RM) soko?-?.lev # Quest dungeons $(AFILES) : $(DAT)\Arch.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Arc QF=Arch do_quest $(BFILES) : $(DAT)\Barb.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Bar QF=Barb do_quest $(CFILES) : $(DAT)\Caveman.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Cav QF=Caveman do_quest $(HFILES) : $(DAT)\Healer.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Hea QF=Healer do_quest $(KFILES) : $(DAT)\Knight.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Kni QF=Knight do_quest $(MFILES) : $(DAT)\Monk.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Mon QF=Monk do_quest $(PFILES) : $(DAT)\Priest.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Pri QF=Priest do_quest $(RANFILES) : $(DAT)\Ranger.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Ran QF=Ranger do_quest $(RFILES) : $(DAT)\Rogue.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Rog QF=Rogue do_quest $(SFILES) : $(DAT)\Samurai.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Sam QF=Samurai do_quest $(TFILES) : $(DAT)\Tourist.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Tou QF=Tourist do_quest $(VFILES) : $(DAT)\Valkyrie.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Val QF=Valkyrie do_quest $(WFILES) : $(DAT)\Wizard.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Wiz QF=Wizard do_quest do_quest : $(TEMP)\lev_comp $(DAT)\$(QF).des $(CP) $(QQ)-fil?.lev $(GAMEDIR) $(CP) $(QQ)-goal.lev $(GAMEDIR) $(CP) $(QQ)-loca.lev $(GAMEDIR) $(CP) $(QQ)-strt.lev $(GAMEDIR) $(RM) $(QQ)-fil?.lev $(RM) $(QQ)-goal.lev $(RM) $(QQ)-loca.lev $(RM) $(QQ)-strt.lev # # NetHack icon for Presentation Manager. # $(GAMEDIR)\$(GAME).ico : $(SYS)\nhpmico.uu $(MAKEB) do_icon icon_msg : $(ECHO) Icon file not extracted. Extract manually if required. icon_act : $(UUDECODE) $(SYS)\nhpmico.uu $(CP) nethack.ico $(GAMEDIR)\$(GAME).ico $(RM) nethack.ico # # NetHack command file to use with Presentation Manager. # $(GAMEDIR)\$(GAME).cmd : $(MAKEB) CMDF=$@ do_cmd cmd_msg : $(ECHO) Command file not created. Create manually if required. cmd_act : $(ECHO) @echo off> $(CMDF) $(ECHO) REM Command file for starting nethack.exe from PM/WPS Desktop>> $(CMDF) $(ECHO) $(GAME).exe $(P)1 $(P)2 $(P)3 $(P)4 $(P)5 $(P)6 $(P)7>> $(CMDF) $(ECHO) pause>> $(CMDF) # # NetHack configuration file. Will not overwrite an existing file. # $(GAMEDIR)\nethack.cnf : $(CP) $(SSYS)\nethack.cnf $(GAMEDIR) # # Documentation. # # LaTeX needs to be run twice. # The second pass uses the $(GUIDEBOO).aux file made by the first. # $(TEMP)\$(GUIDEBOO).dvi : $(DOC)\$(GUIDEBOO).tex $(LATEX) $(DOC)\$(GUIDEBOO).tex $(LATEX) $(DOC)\$(GUIDEBOO).tex $(CP) $(GUIDEBOO).dvi $(TEMP) $(CP) $(GUIDEBOO).aux $(TEMP) $(CP) $(GUIDEBOO).log $(TEMP) $(RM) $(GUIDEBOO).dvi $(RM) $(GUIDEBOO).aux $(RM) $(GUIDEBOO).log # # Housekeeping. # clean : -$(RM) $(OBJ)\*.o spotless : clean -$(RM) $(INCL)\date.h -$(RM) $(INCL)\onames.h -$(RM) $(INCL)\pm.h -$(RM) $(INCL)\vis_tab.h -$(RM) vis_tab.c -$(RM) monstr.c -$(RM) *.lev -$(RM) nethack.ico -$(RM) $(TEMP)\makedefs.exe -$(RM) $(TEMP)\lev_comp.exe -$(RM) $(TEMP)\dgn_comp.exe -$(RM) $(TEMP)\*.rsp -$(RM) $(TEMP)\*.def -$(RM) $(TEMP)\*.map -$(RM) $(TEMP)\$(GUIDEBOO).dvi -$(RM) $(TEMP)\$(GUIDEBOO).aux -$(RM) $(TEMP)\$(GUIDEBOO).log # # Main source. # # Default rules are sooo difficult for so many make # programs that we do this the most straightforward way. # $(OBJ)\allmain.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\alloc.o : $(SRC)\$(CB) $(CONFIG_H) $(SRCCC) $(OBJ)\apply.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\artifact.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(SRCCC) $(OBJ)\attrib.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\ball.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\bones.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\botl.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\cmd.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\func_tab.h $(SRCCC) $(OBJ)\dbridge.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\decl.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\quest.h $(SRCCC) $(OBJ)\detect.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\dig.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\display.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\dlb.o : $(SRC)\$(CB) $(CONFIG_H) $(INCL)\dlb.h $(SRCCC) $(OBJ)\do.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\do_name.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\do_wear.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\dog.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\dogmove.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(SRCCC) $(OBJ)\dokick.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\dothrow.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\drawing.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\tcap.h $(SRCCC) $(OBJ)\dungeon.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\dgn_file.h $(SRCCC) $(OBJ)\eat.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\end.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\engrave.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\exper.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\explode.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\extralev.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\files.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\fountain.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\hack.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\hacklib.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\invent.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\light.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\lock.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mail.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mail.h $(SRCCC) $(OBJ)\makemon.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mapglyph.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mcastu.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mhitm.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\mhitu.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\minion.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mklev.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mkmap.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(SRCCC) $(OBJ)\mkmaze.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(SRCCC) $(OBJ)\mkobj.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\mkroom.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mon.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(SRCCC) $(OBJ)\mondata.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\monmove.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h $(SRCCC) $(OBJ)\monst.o : $(SRC)\$(CB) $(CONFIG_H) $(PERMONST_H) $(INCL)\monsym.h $(INCL)\color.h $(SRCCC) $(OBJ)\mplayer.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mthrowu.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\muse.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\music.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\o_init.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\objects.o : $(SRC)\$(CB) $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h $(INCL)\prop.h $(INCL)\color.h $(SRCCC) $(OBJ)\objnam.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\options.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\tcap.h $(SRCCC) $(OBJ)\pager.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\pickup.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\pline.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\polyself.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\potion.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\pray.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\priest.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(SRCCC) $(OBJ)\quest.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\quest.h $(INCL)\qtext.h $(SRCCC) $(OBJ)\questpgr.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\qtext.h $(SRCCC) $(OBJ)\read.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\region.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\rect.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\restore.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(INCL)\quest.h $(SRCCC) $(OBJ)\rip.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\rnd.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\role.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\rumors.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\save.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\quest.h $(SRCCC) $(OBJ)\shk.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\shknam.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\sit.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\sounds.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\sp_lev.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\rect.h $(SRCCC) $(OBJ)\spell.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\steal.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\steed.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\sys.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\teleport.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\timeout.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\topten.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\track.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\trap.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\u_init.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\uhitm.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\vault.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\version.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\date.h $(INCL)\$(PATCHLEV).h $(SRCCC) $(OBJ)\vision.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\vis_tab.h $(SRCCC) $(OBJ)\weapon.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\were.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\wield.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\windows.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\wizard.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\qtext.h $(SRCCC) $(OBJ)\worm.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\worn.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\write.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\zap.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)/Window.o: $(WINX11)\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) $(CC) -o$(OBJ)\Window.o $(CFLAGS) -c $(WINX11)\Window.c $(OBJ)/dialogs.o: $(WINX11)\dialogs.c $(CONFIG_H) $(CC) -o$(OBJ)\dialogs.o $(CFLAGS) -c $(WINX11)\dialogs.c $(OBJ)/winX.o: $(WINX11)\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(WINX11)\nh72icon \ $(WINX11)\nh56icon $(WINX11)\nh32icon $(CC) $(CFLAGS) -c $(WINX11)\winX.c -o$(OBJ)\winX.o $(OBJ)/winmap.o: $(WINX11)\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h $(CC) $(CFLAGS) -c $(WINX11)\winmap.c -o $(OBJ)\winmap.o $(OBJ)/winmenu.o: $(WINX11)\winmenu.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winmenu.c -o $(OBJ)\winmenu.o $(OBJ)/winmesg.o: $(WINX11)\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winmesg.c -o$(OBJ)\winmesg.o $(OBJ)/winmisc.o: $(WINX11)\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winmisc.c -o$(OBJ)\winmisc.o $(OBJ)/winstat.o: $(WINX11)\winstat.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winstat.c -o$(OBJ)\winstat.o $(OBJ)/wintext.o: $(WINX11)\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h $(CC) $(CFLAGS) -c $(WINX11)\wintext.c -o$(OBJ)\wintext.o $(OBJ)/winval.o: $(WINX11)\winval.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winval.c -o$(OBJ)\winval.o $(OBJ)/tile.o: $(NHSRC)\src\tile.c $(HACK_H) $(CC) $(CFLAGS) -c $(NHSRC)\src\tile.c -o$(OBJ)\tile.o $(TEMP)\tilemap.exe: ..\win\share\tilemap.c $(HACK_H) $(CC) $(GCCO) $(WARN) -I$(INCL) $(CDFLAGS) $(STDC) $(WINX11CFLAGS) $(LFLAGS) -o $(TEMP)\tilemap.exe ..\win\share\tilemap.c $(LIBS) $(NHSRC)\src\tile.c: $(TEMP)\tilemap.exe $(TEMP)\tilemap x11tiles: $(TEMP)\tile2x11.exe $(WINSHARE)\monsters.txt \ $(WINSHARE)\objects.txt \ $(WINSHARE)\other.txt $(TEMP)\tile2x11.exe $(WINSHARE)\monsters.txt $(WINSHARE)\objects.txt \ $(WINSHARE)\other.txt $(CP) x11tiles $(GAMEDIR)\x11tiles TEXT_IO = $(OBJ)\tiletext.o \ $(OBJ)\tiletxt.o \ $(OBJ)\drawing.o \ $(OBJ)\decl.o \ $(OBJ)\monst.o \ $(OBJ)\objects.o $(OBJ)\tiletext.o: ../win/share/tiletext.c $(CONFIG_H) $(WINSHARE)\tile.h $(CC) $(CFLAGS) -c $(WINSHARE)\tiletext.c -o$(OBJ)\tiletext.o $(OBJ)\tiletxt.o: $(WINSHARE)\tilemap.c $(HACK_H) $(CC) $(CFLAGS) -c -DTILETEXT $(WINSHARE)\tilemap.c -o$(OBJ)\tiletxt.o $(TEMP)\tile2x11.exe: $(OBJ)\tile2x11.o $(TEXT_IO) $(CC) $(LFLAGS) -o $(TEMP)\tile2x11.exe $(OBJ)\tile2x11.o $(TEXT_IO) $(LIBS) pet_mark.xbm: $(WINX11)\pet_mark.xbm $(CP) $(WINX11)\pet_mark.xbm $(GAMEDIR)\pet_mark.xbm rip.xpm: $(WINX11)\rip.xpm $(CP) $(WINX11)\rip.xpm $(GAMEDIR)\rip.xpm $(OBJ)\tile2x11.o : $(WINX11)\tile2x11.c $(INCL)\tile2x11.h $(CC) $(CFLAGS) -o$(OBJ)\tile2x11.o -c $(WINX11)\tile2x11.c \ -I$(WINSHARE) nethack-3.6.0/sys/os2/nhpmico.uu0000664000076400007660000000237112467321052015473 0ustar paxedpaxedbegin 644 nethack.ico M0D$H``````````````!#21H`````````>`````P````@`$```0`!`````/___ M_T-)&@````````!X`0``#````"``(``!``0```````"``(```("`@```@`"`L M@(``@("`P,#```#_`/\``/___P``_P#___\`____````````````````````! M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M`````````````````````/9F9F9F9F9F9F9F9F9F9F;_9F9F9F9F9F9F9F9F7 M9F9F_XB(B(B(B(B(B(B(B(AF9O^(B(B(B(B(B(B(B(B(9F;_B(B(B(5558B(" MB(B(B&9F_XB(B(@`506(B(B(B(AF9O^(B(B(```%B(B(B(B(9F;_B(A555``@ M55B(B(B(B&9F_XB+N[NP#N-5B(B(B(AF9O^(N[N[`+[N-5B(B(B(9F;_B[N[E MN[N[[N-8B(B(B&9F_XN[N[N[N[[N4XB(B(AF9O^+N[N9F9N[[N,XB(B(9F;_) MB[NYF9F9N[[N,XB(B&9F_XN[F9F9F9N[[N,XB(AF9O^+N9F9F9F9NU[N,XB(< M9F;_B[F9F9F9F;M8[N,XB&9F_XNYF9F9F9F[6([N,XAF9O^+N9F9F9F9NUB(] M[N.(9F;_B[F9F9F9F;M8B([NB&9F_XN[F9F9F9N[6(B([HAF9O^+N[F9F9F[# MNUB(B(B(9F;_B[N[F9F;N[M8B(B(B&9F_XN[N[N[N[N[6(B(B(AF9O^+N[N[) MN[N[NXB(B(B(9F;_B[N(B(B(B[N(B(B(B&9F_XNXB(B(B(B[B(B(B(AF9O^(/ MB(B(B(B(B(B(B(B(9F;_B(B(B(B(B(B(B(B(B&9F_XB(B(B(B(B(B(B(B(AFN A9O__________________]F;_____________________? `` end nethack-3.6.0/sys/os2/os2.c0000664000076400007660000001771712536476415014357 0ustar paxedpaxed/* NetHack 3.6 os2.c $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993, 1996. */ /* NetHack may be freely redistributed. See license for details. */ /* * OS/2 system functions. */ #define NEED_VARARGS #include "hack.h" #ifdef OS2 #include "tcap.h" /* OS/2 system definitions */ #ifdef __EMX__ #undef CLR_BLACK #undef CLR_WHITE #undef CLR_BLUE #undef CLR_RED #undef CLR_GREEN #undef CLR_CYAN #undef CLR_YELLOW #undef CLR_BROWN #endif #include "def_os2.h" #include static char NDECL(DOSgetch); static char NDECL(BIOSgetch); int tgetch() { char ch; /* BIOSgetch can use the numeric key pad on IBM compatibles. */ if (iflags.BIOS) ch = BIOSgetch(); else ch = DOSgetch(); return ((ch == '\r') ? '\n' : ch); } /* * Keyboard translation tables. */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'g', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { 'p', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[PADKEYS] = { { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { 'p', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }; /* * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII * meaning unless assigned one by a keyboard conversion table, so the * keyboard BIOS normally does not return a character code when Alt-letter * is pressed. So, to interpret unassigned Alt-letters, we must use a * scan code table to translate the scan code into a letter, then set the * "meta" bit for it. -3. */ #define SCANLO 0x10 #define SCANHI 0x32 #define SCANKEYS (SCANHI - SCANLO + 1) #define inmap(x) (SCANLO <= (x) && (x) <= SCANHI) static const char scanmap[SCANKEYS] = { /* ... */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'N', 'm' /* ... */ }; /* * BIOSgetch emulates the MSDOS way of getting keys directly with a BIOS call. */ #define SHIFT_KEY (0x1 | 0x2) #define CTRL_KEY 0x4 #define ALT_KEY 0x8 static char BIOSgetch() { unsigned char scan, shift, ch; const struct pad *kpad; KBDKEYINFO CharData; USHORT IOWait = 0; HKBD KbdHandle = 0; KbdCharIn(&CharData, IOWait, KbdHandle); ch = CharData.chChar; scan = CharData.chScan; shift = CharData.fsState; /* Translate keypad keys */ if (iskeypad(scan)) { kpad = iflags.num_pad ? numpad : keypad; if (shift & SHIFT_KEY) ch = kpad[scan - KEYPADLO].shift; else if (shift & CTRL_KEY) ch = kpad[scan - KEYPADLO].cntrl; else ch = kpad[scan - KEYPADLO].normal; } /* Translate unassigned Alt-letters */ if ((shift & ALT_KEY) && !ch) { if (inmap(scan)) ch = scanmap[scan - SCANLO]; return (isprint(ch) ? M(ch) : ch); } return ch; } static char DOSgetch() { KBDKEYINFO CharData; USHORT IOWait = 0; HKBD KbdHandle = 0; KbdCharIn(&CharData, IOWait, KbdHandle); if (CharData.chChar == 0) { /* an extended code -- not yet supported */ KbdCharIn(&CharData, IOWait, KbdHandle); /* eat the next character */ CharData.chChar = 0; /* and return a 0 */ } return (CharData.chChar); } char switchar() { return '/'; } int kbhit() { KBDKEYINFO CharData; HKBD KbdHandle = 0; KbdPeek(&CharData, KbdHandle); return (CharData.fbStatus & (1 << 6)); } long freediskspace(path) char *path; { FSALLOCATE FSInfoBuf; #ifdef OS2_32BITAPI ULONG #else USHORT #endif DriveNumber, FSInfoLevel = 1, res; if (path[0] && path[1] == ':') DriveNumber = (toupper(path[0]) - 'A') + 1; else DriveNumber = 0; res = #ifdef OS2_32BITAPI DosQueryFSInfo(DriveNumber, FSInfoLevel, (PVOID) &FSInfoBuf, (ULONG) sizeof(FSInfoBuf)); #else DosQFSInfo(DriveNumber, FSInfoLevel, (PBYTE) &FSInfoBuf, (USHORT) sizeof(FSInfoBuf)); #endif if (res) return -1L; /* error */ else return ((long) FSInfoBuf.cSectorUnit * FSInfoBuf.cUnitAvail * FSInfoBuf.cbSector); } /* * Functions to get filenames using wildcards */ #ifdef OS2_32BITAPI static FILEFINDBUF3 ResultBuf; #else static FILEFINDBUF ResultBuf; #endif static HDIR DirHandle; int findfirst(path) char *path; { #ifdef OS2_32BITAPI ULONG #else USHORT #endif res, SearchCount = 1; DirHandle = 1; res = #ifdef OS2_32BITAPI DosFindFirst((PSZ) path, &DirHandle, 0L, (PVOID) &ResultBuf, (ULONG) sizeof(ResultBuf), &SearchCount, 1L); #else DosFindFirst((PSZ) path, &DirHandle, 0, &ResultBuf, (USHORT) sizeof(ResultBuf), &SearchCount, 0L); #endif return (!res); } int findnext() { #ifdef OS2_32BITAPI ULONG #else USHORT #endif res, SearchCount = 1; res = #ifdef OS2_32BITAPI DosFindNext(DirHandle, (PVOID) &ResultBuf, (ULONG) sizeof(ResultBuf), &SearchCount); #else DosFindNext(DirHandle, &ResultBuf, (USHORT) sizeof(ResultBuf), &SearchCount); #endif return (!res); } char * foundfile_buffer() { return (ResultBuf.achName); } long filesize(file) char *file; { if (findfirst(file)) { return (*(long *) (ResultBuf.cbFileAlloc)); } else return -1L; } /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { char *ptr; char drive; if ((ptr = index(str, ':')) != (char *) 0) { drive = toupper(*(ptr - 1)); #ifdef OS2_32BITAPI DosSetDefaultDisk((ULONG)(drive - 'A' + 1)); #else DosSelectDisk((USHORT)(drive - 'A' + 1)); #endif } } void disable_ctrlP() { KBDINFO KbdInfo; HKBD KbdHandle = 0; if (!iflags.rawio) return; KbdInfo.cb = sizeof(KbdInfo); KbdGetStatus(&KbdInfo, KbdHandle); KbdInfo.fsMask &= 0xFFF7; /* ASCII off */ KbdInfo.fsMask |= 0x0004; /* BINARY on */ KbdSetStatus(&KbdInfo, KbdHandle); } void enable_ctrlP() { KBDINFO KbdInfo; HKBD KbdHandle = 0; if (!iflags.rawio) return; KbdInfo.cb = sizeof(KbdInfo); KbdGetStatus(&KbdInfo, KbdHandle); KbdInfo.fsMask &= 0xFFFB; /* BINARY off */ KbdInfo.fsMask |= 0x0008; /* ASCII on */ KbdSetStatus(&KbdInfo, KbdHandle); } void get_scr_size() { VIOMODEINFO ModeInfo; HVIO VideoHandle = 0; ModeInfo.cb = sizeof(ModeInfo); (void) VioGetMode(&ModeInfo, VideoHandle); CO = ModeInfo.col; LI = ModeInfo.row; } void gotoxy(x, y) int x, y; { HVIO VideoHandle = 0; x--; y--; /* (0,0) is upper right corner */ (void) VioSetCurPos(x, y, VideoHandle); } char * get_username(lan_username_size) int *lan_username_size; { return (char *) 0; } #ifdef X11_GRAPHICS int errno; #endif #endif /* OS2 */ nethack-3.6.0/sys/share/Makefile.lib0000664000076400007660000000101312536476415016272 0ustar paxedpaxed# NetHack 3.6 Makefile.lib $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ # Nethack makefile for Fred fish termlib -- Norman Meluch # CC = cl /c MODEL = L CFLAGS = /A$(MODEL) /Os /Oa /Gs /Zp1 /W0 # # Termcap routines. TERMLIB = termlib.lib # TL_LOBJECTS = tgetent.o tgetflag.o tgetnum.o \ tgetstr.o tgoto.o tputs.o \ isdigit.o fgetlr.o # .SUFFIXES: .exe .o .c .obj .asm # .c.o: $(CC) $(CFLAGS) /Fo$*.o $*.c # $(TERMLIB): $(TL_LOBJECTS) lib $(TERMLIB) -+ $(TL_LOBJECTS); nethack-3.6.0/sys/share/NetHack.cnf0000664000076400007660000001167112536476415016105 0ustar paxedpaxed# NetHack Copyright (c) NetHack PC Development Team 1993 - 2006 # NetHack may be freely redistributed. See license for details. # # $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # # A '#' at the beginning of a line means the rest of the line is a comment. # # Some options MUST be set in this file, other options can be toggled while # playing. For a list of options available see the file. If # the game plays slowly you might notice some improvement by setting # !time and !showexp, which will reduce screen I/O somewhat. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # *** OPTIONS *** # # The three options on this line should be used for most setups. # If your machine isn't very IBM-compatible, and NetHack doesn't work, # try commenting out this line. OPTIONS=rawio,BIOS,symset:IBMGraphics_2,roguesymset:RogueEpyx # Here is a suggested symbol set from Michael Feir, # for use by blind NetHack players #OPTIONS=symset:NHAccess,roguesymset:NHAccess # To use VGA graphical tiles on an MS-DOS PC with VGA or better,uncomment # this: #OPTIONS=video:autodetect # Some versions of NetHack use the pc speaker to play the notes given when # playing music instruments in NetHack. To use this feature, if available, # uncomment the following line: #OPTIONS=soundcard:autodetect # If your machine is NEC PC-9800, use: #OPTIONS=rawio,BIOS,video:default # If you use an Atari and want tty use: #OPTIONS=windowtype:tty,rawio,BIOS # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # #OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful #OPTIONS=dogname:Fido,catname:Morris,fruit:guava #OPTIONS=horsename:Silver #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose #OPTIONS=menustyle:traditional # If you wish to change the symbol used to display boulders use: OPTIONS=boulder:0 # # General options. You might also set "silent" so as not to attract # the boss's attention. # # number_pad option can have an optional value of 0 (off), 1 (on), # or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I' OPTIONS=time,noshowexp,number_pad:2,lit_corridor # Treat space bar as rest. Warning: may be dangerous for new players. # OPTIONS=rest_on_space # # If you want to get rid of "use #quit to quit..." use: #OPTIONS=suppress_alert:3.3.1 # # # *** LOCATIONS *** # Some platforms allow you to change the location where various things are kept. # IMPORTANT: If you change any of these locations, the directories they # point at must exist. NetHack will not create them for you. # # The default location for everything. # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file so # setting HACKDIR below to override that is # not usually necessary or recommended. #HACKDIR=c:\games\nethack # # The location that level files in progress are stored (default=HACKDIR, writeable) #LEVELDIR=c:\nethack\levels # # The location where saved games are kept (default=HACKDIR, writeable) #SAVEDIR=c:\nethack\save # # The location that bones files are kept (default=HACKDIR, writeable) #BONESDIR=c:\nethack\save # # The location that file synchronization locks are stored (default=HACKDIR, writeable) #LOCKDIR=c:\nethack\levels # # The location that a record of game aborts and self-diagnosed game problems # is kept (default=HACKDIR, writeable) #TROUBLEDIR=c:\nethack\trouble # # ================================================ # DEC Rainbow/ANSI line-drawing character set: # # If you have compiled with TERMLIB, merely set the DECgraphics option as # above. NetHack will then switch into the VTxxx line-drawing character set # (aka ANSI ruling character set '0') for dungeon characters. If you don't # like the selections, you can make up your own via the SYMBOLS keyword, # adding 128 to the value of any line-drawing character you want to use. # (But you should still set symset:DECgraphics to get the correct processing.) # ================================================= # *** VIDEOCOLORS AND VIDEOSHADES *** # # While playing on NEC PC-9800, default game display may be difficult to # read. Try following setting. # #OPTIONS=videocolors:4-2-6-1-5-3-4-2-6-1-5-3,videoshades:normal-normal-normal # # DEC Rainbows will hang if rawio is set, so they should instead use: #OPTIONS=BIOS,DECgraphics # Colored menus. #OPTIONS=menucolors # Syntax is: MENUCOLOR="string_to_match"=color&attribute # Colors: black, red, green, brown, blue, magenta, cyan, gray, orange, # lightgreen, yellow, lightblue, lightmagenta, lightcyan, white. # Attributes: none, bold, dim, underline, blink, inverse. #MENUCOLOR=" blessed "=green #MENUCOLOR=" holy "=green #MENUCOLOR=" cursed "=red #MENUCOLOR=" unholy "=red #MENUCOLOR=" cursed .* (being worn)"=orange&underline nethack-3.6.0/sys/share/cppregex.cpp0000644000076400007660000000273012540152244016375 0ustar paxedpaxed/* NetHack 3.6 cppregex.cpp $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ #include #include /* nhregex interface documented in sys/share/posixregex.c */ extern "C" { #include extern const char regex_id[] = "cppregex"; struct nhregex { std::unique_ptr re; std::unique_ptr err; }; struct nhregex *regex_init(void) { return new nhregex; } boolean regex_compile(const char *s, struct nhregex *re) { if (!re) return FALSE; try { re->re.reset(new std::regex(s, (std::regex::extended | std::regex::nosubs | std::regex::optimize))); re->err.reset(nullptr); return TRUE; } catch (const std::regex_error& err) { re->err.reset(new std::regex_error(err)); re->re.reset(nullptr); return FALSE; } } const char *regex_error_desc(struct nhregex *re) { if (re->err) return re->err->what(); else return nullptr; } boolean regex_match(const char *s, struct nhregex *re) { if (!re->re) return false; try { return regex_search(s, *re->re, std::regex_constants::match_any); } catch (const std::regex_error& err) { return false; } } void regex_free(struct nhregex *re) { delete re; } } nethack-3.6.0/sys/share/dgn_comp.h0000664000076400007660000000076712627770231016035 0ustar paxedpaxed#define INTEGER 257 #define A_DUNGEON 258 #define BRANCH 259 #define CHBRANCH 260 #define LEVEL 261 #define RNDLEVEL 262 #define CHLEVEL 263 #define RNDCHLEVEL 264 #define UP_OR_DOWN 265 #define PROTOFILE 266 #define DESCRIPTION 267 #define DESCRIPTOR 268 #define LEVELDESC 269 #define ALIGNMENT 270 #define LEVALIGN 271 #define ENTRY 272 #define STAIR 273 #define NO_UP 274 #define NO_DOWN 275 #define PORTAL 276 #define STRING 277 typedef union { int i; char* str; } YYSTYPE; extern YYSTYPE yylval; nethack-3.6.0/sys/share/dgn_lex.c0000664000076400007660000015603712631241231015650 0ustar paxedpaxed #line 3 "dgn_lex.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex via 'flex -S flexhack.skl' * where flexhack.skl is a nethack-specific alternate skeleton derived * from flex 2.6.0's skel.c (which in turn was generated from flex.skl). * * Support for C++, re-entrancy, and table serialization stripped out. * NetHack's usage doesn't need them and we want to reduce the size and * complexity of this skeleton as well as of the generated scanner code. */ #define FLEXHACK_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 0 #include "config.h" #include /* we don't care if actual types happen to have more bits than their names; the tables will just take up more space, possibly slowing the parse; still, allow config.h to override these via typedef+#define if desired */ #ifndef FLEX_INT32_T typedef int flex_int32_t; #endif #ifndef FLEX_INT16_T typedef short int flex_int16_t; #endif #ifndef FLEX_UINT16_T typedef unsigned short int flex_uint16_t; #endif #define yyconst const /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (uchar) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character * in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern yy_size_t yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg); \ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ yy_size_t yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart FDECL(, (FILE *input_file )); void yy_switch_to_buffer FDECL(, (YY_BUFFER_STATE new_buffer )); YY_BUFFER_STATE yy_create_buffer FDECL(, (FILE *file,int size )); void yy_delete_buffer FDECL(, (YY_BUFFER_STATE b )); void yy_flush_buffer FDECL(, (YY_BUFFER_STATE b )); void yypush_buffer_state FDECL(, (YY_BUFFER_STATE new_buffer )); void yypop_buffer_state FDECL(, (void )); static void yyensure_buffer_stack FDECL(, (void )); static void yy_load_buffer_state FDECL(, (void )); static void yy_init_buffer FDECL(, (YY_BUFFER_STATE b,FILE *file )); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer FDECL(, (char *base,yy_size_t size )); YY_BUFFER_STATE yy_scan_string FDECL(, (yyconst char *yy_str )); YY_BUFFER_STATE yy_scan_bytes FDECL(, (yyconst char *bytes,yy_size_t len )); void *yyalloc FDECL(, (yy_size_t )); void *yyrealloc FDECL(, (void *,yy_size_t )); void yyfree FDECL(, (void * )); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ) { \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ) { \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state FDECL(, (void )); static yy_state_type yy_try_NUL_trans FDECL(, (yy_state_type current_state )); static int yy_get_next_buffer FDECL(, (void )); static void yy_fatal_error FDECL(, (yyconst char msg[] )) NORETURN; /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 35 #define YY_END_OF_BUFFER 36 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[196] = { 0, 0, 0, 36, 34, 33, 32, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 33, 32, 0, 30, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 4, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 22, 15, 0, 21, 7, 19, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 26, 16, 0, 0, 12, 0, 0, 0, 11, 9, 0, 17, 18, 0, 27, 0, 28, 24, 10, 0 } ; static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 1, 17, 18, 19, 20, 21, 1, 22, 23, 24, 25, 26, 1, 1, 27, 1, 1, 1, 1, 1, 28, 1, 29, 1, 30, 31, 32, 33, 34, 35, 36, 1, 37, 38, 39, 40, 41, 42, 1, 43, 44, 45, 46, 1, 47, 1, 1, 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst YY_CHAR yy_meta[49] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_uint16_t yy_base[198] = { 0, 0, 213, 218, 220, 215, 220, 213, 210, 207, 196, 190, 196, 37, 191, 197, 186, 188, 171, 164, 172, 174, 173, 18, 160, 159, 154, 157, 11, 194, 194, 220, 190, 220, 187, 177, 184, 183, 167, 170, 164, 161, 166, 174, 155, 136, 144, 134, 132, 133, 26, 135, 143, 147, 128, 145, 220, 170, 220, 158, 152, 154, 159, 154, 145, 44, 142, 47, 124, 124, 125, 129, 129, 115, 27, 121, 113, 111, 120, 115, 116, 134, 142, 132, 128, 137, 121, 130, 129, 125, 129, 131, 97, 220, 105, 94, 101, 95, 96, 94, 99, 105, 101, 89, 220, 95, 112, 114, 51, 112, 107, 220, 110, 114, 111, 106, 96, 85, 76, 81, 82, 88, 69, 220, 81, 76, 75, 220, 78, 99, 220, 88, 97, 87, 88, 92, 93, 88, 91, 90, 71, 65, 220, 62, 60, 57, 56, 220, 59, 54, 74, 84, 65, 66, 220, 70, 65, 70, 60, 68, 220, 220, 52, 220, 220, 220, 46, 50, 57, 61, 67, 62, 220, 67, 64, 63, 220, 220, 42, 41, 220, 61, 53, 49, 220, 220, 50, 220, 220, 51, 220, 46, 220, 220, 220, 220, 62, 60 } ; static yyconst flex_int16_t yy_def[198] = { 0, 195, 1, 195, 195, 195, 195, 195, 196, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 197, 195, 195, 196, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 197, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 0, 195, 195 } ; static yyconst flex_uint16_t yy_nxt[269] = { 0, 4, 5, 6, 7, 8, 4, 9, 10, 11, 12, 13, 14, 4, 4, 4, 4, 15, 4, 4, 4, 16, 17, 4, 4, 4, 4, 4, 4, 4, 18, 19, 4, 4, 4, 20, 4, 4, 21, 22, 23, 4, 24, 25, 26, 27, 28, 4, 4, 38, 49, 55, 87, 56, 74, 75, 88, 90, 98, 50, 131, 57, 39, 32, 91, 194, 193, 192, 132, 191, 190, 189, 188, 99, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 97, 96, 95, 94, 93, 92, 89, 86, 85, 84, 83, 82, 81, 58, 80, 79, 78, 77, 76, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 34, 33, 30, 58, 54, 53, 52, 51, 48, 47, 46, 45, 44, 43, 42, 41, 40, 37, 36, 35, 34, 33, 31, 30, 195, 29, 3, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195 } ; static yyconst flex_int16_t yy_chk[269] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 23, 28, 65, 28, 50, 50, 65, 67, 74, 23, 108, 197, 13, 196, 67, 191, 189, 186, 108, 183, 182, 181, 179, 74, 178, 175, 174, 173, 171, 170, 169, 168, 167, 166, 162, 159, 158, 157, 156, 155, 153, 152, 151, 150, 149, 148, 146, 145, 144, 143, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 129, 128, 126, 125, 124, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 110, 109, 107, 106, 105, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 73, 72, 71, 70, 69, 68, 66, 64, 63, 62, 61, 60, 59, 57, 55, 54, 53, 52, 51, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 32, 30, 29, 27, 26, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14, 12, 11, 10, 9, 8, 7, 5, 3, 2, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; /* NetHack 3.6 dgn_comp.l $NHDT-Date: 1449385342 2015/12/06 07:02:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #define DGN_COMP #include "config.h" #include "dgn_comp.h" #include "dgn_file.h" /* * Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #else /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ /* most recent flex allows suppressing yyunput() altogether when not needed */ #define YY_NO_UNPUT #endif #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) /* older flex wants this */ #define YY_MALLOC_DECL genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t, size_t)); /* newer flex assumes so needs this in case it's been suppressed */ YY_MALLOC_DECL #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); /* this doesn't always get put in dgn_comp.h * (esp. when using older versions of bison) */ extern YYSTYPE yylval; int nh_line_number = 1; #define INITIAL 0 #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy FDECL(, (void )); int yyget_debug FDECL(, (void )); void yyset_debug FDECL(, (int debug_flag )); YY_EXTRA_TYPE yyget_extra FDECL(, (void )); void yyset_extra FDECL(, (YY_EXTRA_TYPE user_defined )); FILE *yyget_in FDECL(, (void )); void yyset_in FDECL(, (FILE * _in_str )); FILE *yyget_out FDECL(, (void )); void yyset_out FDECL(, (FILE * _out_str )); yy_size_t yyget_leng FDECL(, (void )); char *yyget_text FDECL(, (void )); int yyget_lineno FDECL(, (void )); void yyset_lineno FDECL(, (int _line_number )); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP extern int yywrap FDECL(, (void )); #endif #ifndef YY_NO_UNPUT static void yyunput FDECL(, (int c,char *buf_ptr )); #endif #ifndef yytext_ptr static void yy_flex_strncpy FDECL(, (char *,yyconst char *,int )); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen FDECL(, (yyconst char * )); #endif #ifndef YY_NO_INPUT static int input FDECL(, (void )); #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex FDECL(, (void)); #define YY_DECL int yylex () #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } { while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 196 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 220 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP return(A_DUNGEON); YY_BREAK case 2: YY_RULE_SETUP { yylval.i=1; return(UP_OR_DOWN); } YY_BREAK case 3: YY_RULE_SETUP { yylval.i=0; return(UP_OR_DOWN); } YY_BREAK case 4: YY_RULE_SETUP return(ENTRY); YY_BREAK case 5: YY_RULE_SETUP return(STAIR); YY_BREAK case 6: YY_RULE_SETUP return(NO_UP); YY_BREAK case 7: YY_RULE_SETUP return(NO_DOWN); YY_BREAK case 8: YY_RULE_SETUP return(PORTAL); YY_BREAK case 9: YY_RULE_SETUP return(PROTOFILE); YY_BREAK case 10: YY_RULE_SETUP return(DESCRIPTION); YY_BREAK case 11: YY_RULE_SETUP return(LEVELDESC); YY_BREAK case 12: YY_RULE_SETUP return(ALIGNMENT); YY_BREAK case 13: YY_RULE_SETUP return(LEVALIGN); YY_BREAK case 14: YY_RULE_SETUP { yylval.i=TOWN ; return(DESCRIPTOR); } YY_BREAK case 15: YY_RULE_SETUP { yylval.i=HELLISH ; return(DESCRIPTOR); } YY_BREAK case 16: YY_RULE_SETUP { yylval.i=MAZELIKE ; return(DESCRIPTOR); } YY_BREAK case 17: YY_RULE_SETUP { yylval.i=ROGUELIKE ; return(DESCRIPTOR); } YY_BREAK case 18: YY_RULE_SETUP { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } YY_BREAK case 19: YY_RULE_SETUP { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } YY_BREAK case 20: YY_RULE_SETUP { yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); } YY_BREAK case 21: YY_RULE_SETUP { yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); } YY_BREAK case 22: YY_RULE_SETUP { yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); } YY_BREAK case 23: YY_RULE_SETUP return(BRANCH); YY_BREAK case 24: YY_RULE_SETUP return(CHBRANCH); YY_BREAK case 25: YY_RULE_SETUP return(LEVEL); YY_BREAK case 26: YY_RULE_SETUP return(RNDLEVEL); YY_BREAK case 27: YY_RULE_SETUP return(CHLEVEL); YY_BREAK case 28: YY_RULE_SETUP return(RNDCHLEVEL); YY_BREAK case 29: YY_RULE_SETUP { yylval.i=atoi(yytext); return(INTEGER); } YY_BREAK case 30: /* rule 30 can match eol */ YY_RULE_SETUP { yytext[yyleng - 1] = '\0'; /* discard the trailing \" */ yylval.str = dupstr(yytext + 1); /* skip the first \" */ return STRING; } YY_BREAK case 31: /* rule 31 can match eol */ YY_RULE_SETUP { nh_line_number++; } YY_BREAK case 32: /* rule 32 can match eol */ YY_RULE_SETUP { nh_line_number++; } YY_BREAK case 33: YY_RULE_SETUP ; /* skip trailing tabs & spaces */ YY_BREAK case 34: YY_RULE_SETUP { return yytext[0]; } YY_BREAK case 35: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer () { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); yy_size_t number_to_move, i; int ret_val; if ((yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1]) YY_FATAL_ERROR("fatal flex scanner internal error--end of buffer missed"); if (YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for (i = 0; i < number_to_move; ++i) *(dest++) = *(source++); if (YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING) { /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; } else { yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while (num_to_read <= 0) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if (! b->yy_ch_buf) YY_FATAL_ERROR("fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT((&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ((yy_n_chars) == 0) { if (number_to_move == YY_MORE_ADJ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if (! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) YY_FATAL_ERROR("out of dynamic memory in yy_get_next_buffer()"); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before EOB char was reached */ static yy_state_type yy_get_previous_state () { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for (yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 196 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_current_state ) yy_state_type yy_current_state; { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 196 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 195); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT static void yyunput (c,yy_bp ) int c; char * yy_bp; { char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ yy_size_t number_to_move = (yy_n_chars) + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #endif #ifndef YY_NO_INPUT static int input () { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; return input(); } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(uchar *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (input_file ) FILE * input_file; { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (new_buffer ) YY_BUFFER_STATE new_buffer; { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state () { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (file,size ) FILE * file; int size; { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (b ) YY_BUFFER_STATE b; { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (b,file ) YY_BUFFER_STATE b; FILE * file; { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (b ) YY_BUFFER_STATE b; { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (new_buffer ) YY_BUFFER_STATE new_buffer; { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state () { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack () { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ #if 1 /* [PR] avoid C++-style comment; older C compilers choke on it */ num_to_alloc = 2; /* also changed to match the comment... */ #else num_to_alloc = 1; // After all that talk, this was set to 1 anyways... #endif (yy_buffer_stack) = (struct yy_buffer_state**) yyalloc(num_to_alloc * sizeof(struct yy_buffer_state*) ); if (!(yy_buffer_stack)) YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()"); (void) memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1) { /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**) yyrealloc((yy_buffer_stack),num_to_alloc * sizeof(struct yy_buffer_state*) ); if (!(yy_buffer_stack)) YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()"); /* zero only the new slots.*/ (void) memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified * character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (base,size ) char * base; yy_size_t size; { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() * will scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yystr ) yyconst char * yystr; { return yy_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to * yylex() will scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a * bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yybytes,_yybytes_len ) yyconst char * yybytes; yy_size_t _yybytes_len; { YY_BUFFER_STATE b; char *buf; yy_size_t n; yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (msg ) yyconst char* msg; { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg); \ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno () { return yylineno; } /** Get the input stream. * */ FILE *yyget_in () { return yyin; } /** Get the output stream. * */ FILE *yyget_out () { return yyout; } /** Get the length of the current token. * */ yy_size_t yyget_leng () { return yyleng; } /** Get the current token. * */ char *yyget_text () { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (_line_number ) int _line_number; { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (_in_str ) FILE * _in_str; { yyin = _in_str ; } void yyset_out (_out_str ) FILE * _out_str; { yyout = _out_str ; } int yyget_debug () { return yy_flex_debug; } void yyset_debug (_bdebug ) int _bdebug; { yy_flex_debug = _bdebug ; } static int yy_init_globals () { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy () { /* Pop the buffer stack, destroying each element. */ while (YY_CURRENT_BUFFER) { yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner * so the next time yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (s1,s2,n ) char* s1; yyconst char * s2; int n; { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (s ) yyconst char * s; { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (size ) yy_size_t size; { return (void *) malloc( size ); } void *yyrealloc (ptr,size ) void * ptr; yy_size_t size; { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (ptr ) void * ptr; { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } /*dgn_comp.l*/ nethack-3.6.0/sys/share/dgn_yacc.c0000664000076400007660000007377312631241231016004 0ustar paxedpaxed#ifndef lint /* static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; */ /* static char nhsccsid[] = "@(#)yaccpar 1.9.0-nh (NetHack) 12/03/2015"; */ #endif #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 #define YYSUBMINOR "0-nh" #define yyclearin (yychar=(-1)) #define yyerrok (yyerrflag=0) #define YYRECOVERING (yyerrflag!=0) #define YYPREFIX "yy" /* NetHack 3.6 dgn_comp.y $NHDT-Date: 1449233106 2015/12/04 12:45:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Dungeon Compiler code */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive in its non-standard locale. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #include "config.h" #include "date.h" #include "dgn_file.h" void FDECL(yyerror, (const char *)); void FDECL(yywarning, (const char *)); int NDECL(yylex); int NDECL(yyparse); int FDECL(getchain, (char *)); int NDECL(check_dungeon); int NDECL(check_branch); int NDECL(check_level); void NDECL(init_dungeon); void NDECL(init_branch); void NDECL(init_level); void NDECL(output_dgn); #define Free(ptr) free((genericptr_t)ptr) #ifdef AMIGA # undef printf #ifndef LATTICE # define memset(addr,val,len) setmem(addr,len,val) #endif #endif #define ERR (-1) static struct couple couple; static struct tmpdungeon tmpdungeon[MAXDUNGEON]; static struct tmplevel tmplevel[LEV_LIMIT]; static struct tmpbranch tmpbranch[BRANCH_LIMIT]; static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1; extern int fatal_error; extern const char *fname; extern FILE *yyin, *yyout; /* from dgn_lex.c */ typedef union { int i; char* str; } YYSTYPE; #define INTEGER 257 #define A_DUNGEON 258 #define BRANCH 259 #define CHBRANCH 260 #define LEVEL 261 #define RNDLEVEL 262 #define CHLEVEL 263 #define RNDCHLEVEL 264 #define UP_OR_DOWN 265 #define PROTOFILE 266 #define DESCRIPTION 267 #define DESCRIPTOR 268 #define LEVELDESC 269 #define ALIGNMENT 270 #define LEVALIGN 271 #define ENTRY 272 #define STAIR 273 #define NO_UP 274 #define NO_DOWN 275 #define PORTAL 276 #define STRING 277 #define YYERRCODE 256 short yylhs[] = { -1, 0, 0, 5, 5, 6, 6, 6, 6, 7, 1, 1, 8, 8, 8, 12, 13, 15, 15, 14, 10, 10, 10, 10, 10, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 9, 9, 22, 23, 3, 3, 3, 3, 3, 2, 2, 4, 21, 11, }; short yylen[] = { 2, 0, 1, 1, 2, 1, 1, 1, 1, 6, 0, 1, 1, 1, 1, 3, 1, 3, 3, 3, 1, 1, 1, 1, 1, 6, 7, 7, 8, 3, 3, 7, 8, 8, 9, 1, 1, 7, 8, 0, 1, 1, 1, 1, 0, 1, 1, 5, 5, }; short yydefred[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 6, 7, 8, 12, 13, 14, 16, 20, 21, 22, 23, 24, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 19, 17, 29, 18, 30, 15, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 40, 41, 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, 45, 37, 0, 27, 0, 0, 0, 0, 0, 38, 28, 33, 0, 48, 47, 34, }; short yydgoto[] = { 14, 78, 93, 84, 60, 15, 16, 17, 18, 19, 20, 68, 21, 22, 23, 24, 25, 26, 27, 28, 29, 70, 30, 31, }; short yysindex[] = { -237, -46, -45, -44, -39, -38, -30, -22, -21, -20, -19, -18, -17, -16, 0, -237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, -234, -233, -232, -230, -229, -228, -227, -217, -216, -215, -214, -202, 0, -221, -7, -219, -221, -221, -221, -221, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, -2, -1, -212, -211, -190, -189, -188, -271, 19, 20, 20, 27, 28, 29, 0, 0, 30, 0, 0, 0, 0, -193, -271, -182, -180, 19, 19, -179, -178, 0, 0, -193, 0, -177, -176, -175, 42, 43, 0, 0, 0, -172, 0, 0, 0, }; short yyrindex[] = { 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 1, 46, 0, 0, 0, 0, 0, 0, 0, 31, 0, 61, 76, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, }; short yygindex[] = { 0, 0, -6, 4, -43, 0, 75, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, -62, 0, 0, }; #define YYTABLESIZE 363 short yytable[] = { 85, 39, 80, 81, 82, 83, 63, 64, 65, 66, 86, 87, 32, 33, 34, 46, 10, 97, 98, 35, 36, 1, 2, 3, 4, 5, 6, 7, 37, 8, 9, 44, 10, 11, 12, 13, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 25, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 67, 69, 26, 72, 73, 71, 74, 75, 76, 77, 79, 88, 89, 92, 90, 91, 95, 31, 96, 99, 100, 102, 103, 104, 105, 106, 107, 1, 2, 101, 94, 45, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 0, 39, 39, 39, 39, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 0, 10, 10, 10, 10, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 0, 44, 44, 44, 44, 25, 25, 25, 25, 25, 25, 25, 0, 25, 25, 0, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 0, 26, 26, 0, 26, 26, 26, 26, 31, 31, 31, 31, 31, 31, 31, 0, 31, 31, 0, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 0, 32, 32, 32, 32, }; short yycheck[] = { 71, 0, 273, 274, 275, 276, 49, 50, 51, 52, 72, 73, 58, 58, 58, 277, 0, 88, 89, 58, 58, 258, 259, 260, 261, 262, 263, 264, 58, 266, 267, 0, 269, 270, 271, 272, 58, 58, 58, 58, 58, 58, 58, 277, 277, 277, 0, 277, 277, 277, 277, 268, 268, 268, 268, 257, 277, 64, 277, 40, 40, 0, 64, 64, 43, 277, 277, 257, 257, 257, 43, 43, 265, 44, 44, 257, 0, 257, 257, 257, 257, 257, 257, 41, 41, 257, 0, 0, 94, 85, 15, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, }; #define YYFINAL 14 #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYMAXTOKEN 277 #if YYDEBUG char *yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,"'('","')'",0,"'+'","','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0, "'@'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"INTEGER", "A_DUNGEON","BRANCH","CHBRANCH","LEVEL","RNDLEVEL","CHLEVEL","RNDCHLEVEL", "UP_OR_DOWN","PROTOFILE","DESCRIPTION","DESCRIPTOR","LEVELDESC","ALIGNMENT", "LEVALIGN","ENTRY","STAIR","NO_UP","NO_DOWN","PORTAL","STRING", }; char *yyrule[] = { "$accept : file", "file :", "file : dungeons", "dungeons : dungeon", "dungeons : dungeons dungeon", "dungeon : dungeonline", "dungeon : dungeondesc", "dungeon : branches", "dungeon : levels", "dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int", "optional_int :", "optional_int : INTEGER", "dungeondesc : entry", "dungeondesc : descriptions", "dungeondesc : prototype", "entry : ENTRY ':' INTEGER", "descriptions : desc", "desc : DESCRIPTION ':' DESCRIPTOR", "desc : ALIGNMENT ':' DESCRIPTOR", "prototype : PROTOFILE ':' STRING", "levels : level1", "levels : level2", "levels : levdesc", "levels : chlevel1", "levels : chlevel2", "level1 : LEVEL ':' STRING bones_tag '@' acouple", "level1 : RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER", "level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER", "level2 : RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER", "levdesc : LEVELDESC ':' DESCRIPTOR", "levdesc : LEVALIGN ':' DESCRIPTOR", "chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple", "chlevel1 : RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER", "chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER", "chlevel2 : RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER", "branches : branch", "branches : chbranch", "branch : BRANCH ':' STRING '@' acouple branch_type direction", "chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction", "branch_type :", "branch_type : STAIR", "branch_type : NO_UP", "branch_type : NO_DOWN", "branch_type : PORTAL", "direction :", "direction : UP_OR_DOWN", "bones_tag : STRING", "acouple : '(' INTEGER ',' INTEGER ')'", "rcouple : '(' INTEGER ',' INTEGER ')'", }; #endif #ifdef YYSTACKSIZE #undef YYMAXDEPTH #define YYMAXDEPTH YYSTACKSIZE #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else #define YYSTACKSIZE 500 #define YYMAXDEPTH 500 #endif #endif int yydebug; int yynerrs; int yyerrflag; int yychar; short *yyssp; YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; short yyss[YYSTACKSIZE]; YYSTYPE yyvs[YYSTACKSIZE]; #define yystacksize YYSTACKSIZE void init_dungeon() { if(++n_dgns > MAXDUNGEON) { (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n", MAXDUNGEON); (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n"); exit(EXIT_FAILURE); } in_dungeon = 1; tmpdungeon[n_dgns].lev.base = 0; tmpdungeon[n_dgns].lev.rand = 0; tmpdungeon[n_dgns].chance = 100; Strcpy(tmpdungeon[n_dgns].name, ""); Strcpy(tmpdungeon[n_dgns].protoname, ""); tmpdungeon[n_dgns].flags = 0; tmpdungeon[n_dgns].levels = 0; tmpdungeon[n_dgns].branches = 0; tmpdungeon[n_dgns].entry_lev = 0; } void init_level() { if(++n_levs > LEV_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmplevel[n_levs].lev.base = 0; tmplevel[n_levs].lev.rand = 0; tmplevel[n_levs].chance = 100; tmplevel[n_levs].rndlevs = 0; tmplevel[n_levs].flags = 0; Strcpy(tmplevel[n_levs].name, ""); tmplevel[n_levs].chain = -1; } void init_branch() { if(++n_brs > BRANCH_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmpbranch[n_brs].lev.base = 0; tmpbranch[n_brs].lev.rand = 0; Strcpy(tmpbranch[n_brs].name, ""); tmpbranch[n_brs].chain = -1; } int getchain(s) char *s; { int i; if(strlen(s)) { for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++) if(!strcmp(tmplevel[i].name, s)) return i; yyerror("Can't locate the specified chain level."); return(-2); } return(-1); } /* * Consistancy checking routines: * * - A dungeon must have a unique name. * - A dungeon must have a originating "branch" command * (except, of course, for the first dungeon). * - A dungeon must have a proper depth (at least (1, 0)). */ int check_dungeon() { int i; for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) { yyerror("Duplicate dungeon name."); return(0); } if(n_dgns) for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) { if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break; if(i >= n_brs - tmpdungeon[n_dgns].branches) { yyerror("Dungeon cannot be reached."); return(0); } } if(tmpdungeon[n_dgns].lev.base <= 0 || tmpdungeon[n_dgns].lev.rand < 0) { yyerror("Invalid dungeon depth specified."); return(0); } return(1); /* OK */ } /* * - A level must have a unique level name. * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_level() { int i; if(!in_dungeon) { yyerror("Level defined outside of dungeon."); return(0); } for(i = 0; i < n_levs; i++) if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) { yyerror("Duplicate level name."); return(0); } if(tmplevel[i].chain == -2) { yyerror("Invaild level chain reference."); return(0); } else if(tmplevel[i].chain != -1) { /* there is a chain */ /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */ if(tmplevel[tmplevel[i].chain].chance != 100) { yyerror("Level cannot chain from a probabilistic level."); return(0); } else if(tmplevel[i].chain == n_levs) { yyerror("A level cannot chain to itself!"); return(0); } } return(1); /* OK */ } /* * - A branch may not branch backwards - to avoid branch loops. * - A branch name must be unique. * (ie. You can only have one entry point to each dungeon). * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_branch() { int i; if(!in_dungeon) { yyerror("Branch defined outside of dungeon."); return(0); } for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) { yyerror("Reverse branching not allowed."); return(0); } if(tmpbranch[i].chain == -2) { yyerror("Invaild branch chain reference."); return(0); } else if(tmpbranch[i].chain != -1) { /* it is chained */ if(tmplevel[tmpbranch[i].chain].chance != 100) { yyerror("Branch cannot chain from a probabilistic level."); return(0); } } return(1); /* OK */ } /* * Output the dungon definition into a file. * * The file will have the following format: * * [ nethack version ID ] * [ number of dungeons ] * [ first dungeon struct ] * [ levels for the first dungeon ] * ... * [ branches for the first dungeon ] * ... * [ second dungeon struct ] * ... */ void output_dgn() { int nd, cl = 0, nl = 0, cb = 0, nb = 0; static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3 }; if(++n_dgns <= 0) { yyerror("FATAL - no dungeons were defined."); exit(EXIT_FAILURE); } if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) { yyerror("FATAL - output failure."); exit(EXIT_FAILURE); } (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout); for (nd = 0; nd < n_dgns; nd++) { (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), 1, yyout); nl += tmpdungeon[nd].levels; for(; cl < nl; cl++) (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), 1, yyout); nb += tmpdungeon[nd].branches; for(; cb < nb; cb++) (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), 1, yyout); } /* apparently necessary for Think C 5.x, otherwise harmless */ (void) fflush(yyout); } /*dgn_comp.y*/ #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab int yyparse() { register int yym, yyn, yystate; #if YYDEBUG register char *yys; extern char *getenv(); if ((yys = getenv("YYDEBUG")) != 0) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = (-1); yyssp = yyss; yyvsp = yyvs; *yyssp = yystate = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; yychar = (-1); if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; goto yynewerror; yynewerror: yyerror("syntax error"); goto yyerrlab; yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) != 0 && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = (-1); goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; yyval = yyvsp[1-yym]; switch (yyn) { case 2: { output_dgn(); } break; case 9: { init_dungeon(); Strcpy(tmpdungeon[n_dgns].name, yyvsp[-3].str); tmpdungeon[n_dgns].boneschar = (char)yyvsp[-2].i; tmpdungeon[n_dgns].lev.base = couple.base; tmpdungeon[n_dgns].lev.rand = couple.rand; tmpdungeon[n_dgns].chance = yyvsp[0].i; Free(yyvsp[-3].str); } break; case 10: { yyval.i = 0; } break; case 11: { yyval.i = yyvsp[0].i; } break; case 15: { tmpdungeon[n_dgns].entry_lev = yyvsp[0].i; } break; case 17: { if(yyvsp[0].i <= TOWN || yyvsp[0].i >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmpdungeon[n_dgns].flags |= yyvsp[0].i ; } break; case 18: { if(yyvsp[0].i && yyvsp[0].i < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmpdungeon[n_dgns].flags |= yyvsp[0].i ; } break; case 19: { Strcpy(tmpdungeon[n_dgns].protoname, yyvsp[0].str); Free(yyvsp[0].str); } break; case 25: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-3].str); tmplevel[n_levs].boneschar = (char)yyvsp[-2].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmpdungeon[n_dgns].levels++; Free(yyvsp[-3].str); } break; case 26: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-4].str); tmplevel[n_levs].boneschar = (char)yyvsp[-3].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = yyvsp[0].i; tmpdungeon[n_dgns].levels++; Free(yyvsp[-4].str); } break; case 27: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-4].str); tmplevel[n_levs].boneschar = (char)yyvsp[-3].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[0].i; tmpdungeon[n_dgns].levels++; Free(yyvsp[-4].str); } break; case 28: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-5].str); tmplevel[n_levs].boneschar = (char)yyvsp[-4].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[-1].i; tmplevel[n_levs].rndlevs = yyvsp[0].i; tmpdungeon[n_dgns].levels++; Free(yyvsp[-5].str); } break; case 29: { if(yyvsp[0].i >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmplevel[n_levs].flags |= yyvsp[0].i ; } break; case 30: { if(yyvsp[0].i && yyvsp[0].i < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmplevel[n_levs].flags |= yyvsp[0].i ; } break; case 31: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-4].str); tmplevel[n_levs].boneschar = (char)yyvsp[-3].i; tmplevel[n_levs].chain = getchain(yyvsp[-2].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-4].str); Free(yyvsp[-2].str); } break; case 32: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-5].str); tmplevel[n_levs].boneschar = (char)yyvsp[-4].i; tmplevel[n_levs].chain = getchain(yyvsp[-3].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = yyvsp[0].i; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-5].str); Free(yyvsp[-3].str); } break; case 33: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-5].str); tmplevel[n_levs].boneschar = (char)yyvsp[-4].i; tmplevel[n_levs].chain = getchain(yyvsp[-3].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[0].i; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-5].str); Free(yyvsp[-3].str); } break; case 34: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-6].str); tmplevel[n_levs].boneschar = (char)yyvsp[-5].i; tmplevel[n_levs].chain = getchain(yyvsp[-4].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[-1].i; tmplevel[n_levs].rndlevs = yyvsp[0].i; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-6].str); Free(yyvsp[-4].str); } break; case 37: { init_branch(); Strcpy(tmpbranch[n_brs].name, yyvsp[-4].str); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = yyvsp[-1].i; tmpbranch[n_brs].up = yyvsp[0].i; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free(yyvsp[-4].str); } break; case 38: { init_branch(); Strcpy(tmpbranch[n_brs].name, yyvsp[-5].str); tmpbranch[n_brs].chain = getchain(yyvsp[-4].str); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = yyvsp[-1].i; tmpbranch[n_brs].up = yyvsp[0].i; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free(yyvsp[-5].str); Free(yyvsp[-4].str); } break; case 39: { yyval.i = TBR_STAIR; /* two way stair */ } break; case 40: { yyval.i = TBR_STAIR; /* two way stair */ } break; case 41: { yyval.i = TBR_NO_UP; /* no up staircase */ } break; case 42: { yyval.i = TBR_NO_DOWN; /* no down staircase */ } break; case 43: { yyval.i = TBR_PORTAL; /* portal connection */ } break; case 44: { yyval.i = 0; /* defaults to down */ } break; case 45: { yyval.i = yyvsp[0].i; } break; case 46: { char *p = yyvsp[0].str; if (strlen(p) != 1) { if (strcmp(p, "none") != 0) yyerror("Bones marker must be a single char, or \"none\"!"); *p = '\0'; } yyval.i = *p; Free(p); } break; case 47: { if (yyvsp[-3].i < -MAXLEVEL || yyvsp[-3].i > MAXLEVEL) { yyerror("Abs base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else if (yyvsp[-1].i < -1 || ((yyvsp[-3].i < 0) ? (MAXLEVEL + yyvsp[-3].i + yyvsp[-1].i + 1) > MAXLEVEL : (yyvsp[-3].i + yyvsp[-1].i) > MAXLEVEL)) { yyerror("Abs range out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = yyvsp[-3].i; couple.rand = yyvsp[-1].i; } } break; case 48: { if (yyvsp[-3].i < -MAXLEVEL || yyvsp[-3].i > MAXLEVEL) { yyerror("Rel base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = yyvsp[-3].i; couple.rand = yyvsp[-1].i; } } break; } yyssp -= yym; yystate = *yyssp; yyvsp -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; *++yyssp = YYFINAL; *++yyvsp = yyval; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } if ((yyn = yygindex[yym]) != 0 && (yyn += yystate) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", YYPREFIX, *yyssp, yystate); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate; *++yyvsp = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: return (1); yyaccept: return (0); } nethack-3.6.0/sys/share/ioctl.c0000664000076400007660000001102212536476415015344 0ustar paxedpaxed/* NetHack 3.6 ioctl.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This cannot be part of hack.tty.c (as it was earlier) since on some systems (e.g. MUNIX) the include files and define the same constants, and the C preprocessor complains. */ #include "hack.h" #if defined(BSD_JOB_CONTROL) || defined(_BULL_SOURCE) #ifdef HPUX #include #else #if defined(AIX_31) && !defined(_ALL_SOURCE) #define _ALL_SOURCE /* causes struct winsize to be present */ #ifdef _AIX32 #include #endif #endif #if defined(_BULL_SOURCE) #include struct termios termio; #undef TIMEOUT /* defined in you.h and sys/tty.h */ #include /* define winsize */ #include /* define struct ltchars */ #include /* define TIOGWINSZ */ #else #ifdef LINUX #include #else #include #endif #endif #endif struct ltchars ltchars; struct ltchars ltchars0 = { -1, -1, -1, -1, -1, -1 }; /* turn all off */ #else #ifdef POSIX_TYPES #include struct termios termio; #if defined(BSD) || defined(_AIX32) || defined(__linux__) #if defined(_AIX32) && !defined(_ALL_SOURCE) #define _ALL_SOURCE #endif #include #endif #else #include /* also includes part of */ #if defined(TCSETS) && !defined(AIX_31) struct termios termio; #else struct termio termio; #endif #endif #if defined(AMIX) || defined(__APPLE__) #include #endif /* AMIX */ #endif #ifdef SUSPEND /* BSD isn't alone anymore... */ #include #endif #if defined(TIOCGWINSZ) \ && (defined(BSD) || defined(ULTRIX) || defined(AIX_31) \ || defined(_BULL_SOURCE) || defined(SVR4)) #define USE_WIN_IOCTL #include "tcap.h" /* for LI and CO */ #endif #ifdef _M_UNIX extern void NDECL(sco_mapon); extern void NDECL(sco_mapoff); #endif #ifdef __linux__ extern void NDECL(linux_mapon); extern void NDECL(linux_mapoff); #endif #ifdef AUX void catch_stp() { signal(SIGTSTP, SIG_DFL); dosuspend(); } #endif /* AUX */ void getwindowsz() { #ifdef USE_WIN_IOCTL /* * ttysize is found on Suns and BSD * winsize is found on Suns, BSD, and Ultrix */ struct winsize ttsz; if (ioctl(fileno(stdin), (int) TIOCGWINSZ, (char *) &ttsz) != -1) { /* * Use the kernel's values for lines and columns if it has * any idea. */ if (ttsz.ws_row) LI = ttsz.ws_row; if (ttsz.ws_col) CO = ttsz.ws_col; } #endif } void getioctls() { #ifdef BSD_JOB_CONTROL (void) ioctl(fileno(stdin), (int) TIOCGLTC, (char *) <chars); (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) <chars0); #else #ifdef POSIX_TYPES (void) tcgetattr(fileno(stdin), &termio); #else #if defined(TCSETS) && !defined(AIX_31) (void) ioctl(fileno(stdin), (int) TCGETS, &termio); #else (void) ioctl(fileno(stdin), (int) TCGETA, &termio); #endif #endif #endif getwindowsz(); #ifdef AUX (void) signal(SIGTSTP, catch_stp); #endif } void setioctls() { #ifdef BSD_JOB_CONTROL (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) <chars); #else #ifdef POSIX_TYPES (void) tcsetattr(fileno(stdin), TCSADRAIN, &termio); #else #if defined(TCSETS) && !defined(AIX_31) (void) ioctl(fileno(stdin), (int) TCSETSW, &termio); #else (void) ioctl(fileno(stdin), (int) TCSETAW, &termio); #endif #endif #endif } #ifdef SUSPEND /* No longer implies BSD */ int dosuspend() { #ifdef SYSCF /* NB: check_user_string() is port-specific. */ if (!sysopt.shellers || !sysopt.shellers[0] || !check_user_string(sysopt.shellers)) { Norep("Suspend command not available."); return 0; } #endif #if defined(SIGTSTP) && !defined(NO_SIGNAL) if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) { suspend_nhwindows((char *) 0); #ifdef _M_UNIX sco_mapon(); #endif #ifdef __linux__ linux_mapon(); #endif (void) signal(SIGTSTP, SIG_DFL); #ifdef AUX (void) kill(0, SIGSTOP); #else (void) kill(0, SIGTSTP); #endif #ifdef _M_UNIX sco_mapoff(); #endif #ifdef __linux__ linux_mapoff(); #endif resume_nhwindows(); } else { pline("I don't think your shell has job control."); } #else pline("Sorry, it seems we have no SIGTSTP here. Try ! or S."); #endif return (0); } #endif /* SUSPEND */ nethack-3.6.0/sys/share/lev_comp.h0000664000076400007660000001102012627770231016033 0ustar paxedpaxed#define CHAR 257 #define INTEGER 258 #define BOOLEAN 259 #define PERCENT 260 #define SPERCENT 261 #define MINUS_INTEGER 262 #define PLUS_INTEGER 263 #define MAZE_GRID_ID 264 #define SOLID_FILL_ID 265 #define MINES_ID 266 #define ROGUELEV_ID 267 #define MESSAGE_ID 268 #define MAZE_ID 269 #define LEVEL_ID 270 #define LEV_INIT_ID 271 #define GEOMETRY_ID 272 #define NOMAP_ID 273 #define OBJECT_ID 274 #define COBJECT_ID 275 #define MONSTER_ID 276 #define TRAP_ID 277 #define DOOR_ID 278 #define DRAWBRIDGE_ID 279 #define object_ID 280 #define monster_ID 281 #define terrain_ID 282 #define MAZEWALK_ID 283 #define WALLIFY_ID 284 #define REGION_ID 285 #define FILLING 286 #define IRREGULAR 287 #define JOINED 288 #define ALTAR_ID 289 #define LADDER_ID 290 #define STAIR_ID 291 #define NON_DIGGABLE_ID 292 #define NON_PASSWALL_ID 293 #define ROOM_ID 294 #define PORTAL_ID 295 #define TELEPRT_ID 296 #define BRANCH_ID 297 #define LEV 298 #define MINERALIZE_ID 299 #define CORRIDOR_ID 300 #define GOLD_ID 301 #define ENGRAVING_ID 302 #define FOUNTAIN_ID 303 #define POOL_ID 304 #define SINK_ID 305 #define NONE 306 #define RAND_CORRIDOR_ID 307 #define DOOR_STATE 308 #define LIGHT_STATE 309 #define CURSE_TYPE 310 #define ENGRAVING_TYPE 311 #define DIRECTION 312 #define RANDOM_TYPE 313 #define RANDOM_TYPE_BRACKET 314 #define A_REGISTER 315 #define ALIGNMENT 316 #define LEFT_OR_RIGHT 317 #define CENTER 318 #define TOP_OR_BOT 319 #define ALTAR_TYPE 320 #define UP_OR_DOWN 321 #define SUBROOM_ID 322 #define NAME_ID 323 #define FLAGS_ID 324 #define FLAG_TYPE 325 #define MON_ATTITUDE 326 #define MON_ALERTNESS 327 #define MON_APPEARANCE 328 #define ROOMDOOR_ID 329 #define IF_ID 330 #define ELSE_ID 331 #define TERRAIN_ID 332 #define HORIZ_OR_VERT 333 #define REPLACE_TERRAIN_ID 334 #define EXIT_ID 335 #define SHUFFLE_ID 336 #define QUANTITY_ID 337 #define BURIED_ID 338 #define LOOP_ID 339 #define FOR_ID 340 #define TO_ID 341 #define SWITCH_ID 342 #define CASE_ID 343 #define BREAK_ID 344 #define DEFAULT_ID 345 #define ERODED_ID 346 #define TRAPPED_STATE 347 #define RECHARGED_ID 348 #define INVIS_ID 349 #define GREASED_ID 350 #define FEMALE_ID 351 #define CANCELLED_ID 352 #define REVIVED_ID 353 #define AVENGE_ID 354 #define FLEEING_ID 355 #define BLINDED_ID 356 #define PARALYZED_ID 357 #define STUNNED_ID 358 #define CONFUSED_ID 359 #define SEENTRAPS_ID 360 #define ALL_ID 361 #define MONTYPE_ID 362 #define GRAVE_ID 363 #define ERODEPROOF_ID 364 #define FUNCTION_ID 365 #define MSG_OUTPUT_TYPE 366 #define COMPARE_TYPE 367 #define UNKNOWN_TYPE 368 #define rect_ID 369 #define fillrect_ID 370 #define line_ID 371 #define randline_ID 372 #define grow_ID 373 #define selection_ID 374 #define flood_ID 375 #define rndcoord_ID 376 #define circle_ID 377 #define ellipse_ID 378 #define filter_ID 379 #define complement_ID 380 #define gradient_ID 381 #define GRADIENT_TYPE 382 #define LIMITED 383 #define HUMIDITY_TYPE 384 #define STRING 385 #define MAP_ID 386 #define NQSTRING 387 #define VARSTRING 388 #define CFUNC 389 #define CFUNC_INT 390 #define CFUNC_STR 391 #define CFUNC_COORD 392 #define CFUNC_REGION 393 #define VARSTRING_INT 394 #define VARSTRING_INT_ARRAY 395 #define VARSTRING_STRING 396 #define VARSTRING_STRING_ARRAY 397 #define VARSTRING_VAR 398 #define VARSTRING_VAR_ARRAY 399 #define VARSTRING_COORD 400 #define VARSTRING_COORD_ARRAY 401 #define VARSTRING_REGION 402 #define VARSTRING_REGION_ARRAY 403 #define VARSTRING_MAPCHAR 404 #define VARSTRING_MAPCHAR_ARRAY 405 #define VARSTRING_MONST 406 #define VARSTRING_MONST_ARRAY 407 #define VARSTRING_OBJ 408 #define VARSTRING_OBJ_ARRAY 409 #define VARSTRING_SEL 410 #define VARSTRING_SEL_ARRAY 411 #define METHOD_INT 412 #define METHOD_INT_ARRAY 413 #define METHOD_STRING 414 #define METHOD_STRING_ARRAY 415 #define METHOD_VAR 416 #define METHOD_VAR_ARRAY 417 #define METHOD_COORD 418 #define METHOD_COORD_ARRAY 419 #define METHOD_REGION 420 #define METHOD_REGION_ARRAY 421 #define METHOD_MAPCHAR 422 #define METHOD_MAPCHAR_ARRAY 423 #define METHOD_MONST 424 #define METHOD_MONST_ARRAY 425 #define METHOD_OBJ 426 #define METHOD_OBJ_ARRAY 427 #define METHOD_SEL 428 #define METHOD_SEL_ARRAY 429 #define DICE 430 typedef union { long i; char* map; struct { long room; long wall; long door; } corpos; struct { long area; long x1; long y1; long x2; long y2; } lregn; struct { long x; long y; } crd; struct { long ter; long lit; } terr; struct { long height; long width; } sze; struct { long die; long num; } dice; struct { long cfunc; char *varstr; } meth; } YYSTYPE; extern YYSTYPE yylval; nethack-3.6.0/sys/share/lev_lex.c0000664000076400007660000031060612631241231015660 0ustar paxedpaxed #line 3 "lev_lex.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex via 'flex -S flexhack.skl' * where flexhack.skl is a nethack-specific alternate skeleton derived * from flex 2.6.0's skel.c (which in turn was generated from flex.skl). * * Support for C++, re-entrancy, and table serialization stripped out. * NetHack's usage doesn't need them and we want to reduce the size and * complexity of this skeleton as well as of the generated scanner code. */ #define FLEXHACK_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 0 #include "config.h" #include /* we don't care if actual types happen to have more bits than their names; the tables will just take up more space, possibly slowing the parse; still, allow config.h to override these via typedef+#define if desired */ #ifndef FLEX_INT32_T typedef int flex_int32_t; #endif #ifndef FLEX_INT16_T typedef short int flex_int16_t; #endif #ifndef FLEX_UINT16_T typedef unsigned short int flex_uint16_t; #endif #define yyconst const /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (uchar) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character * in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern yy_size_t yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg); \ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ yy_size_t yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart FDECL(, (FILE *input_file )); void yy_switch_to_buffer FDECL(, (YY_BUFFER_STATE new_buffer )); YY_BUFFER_STATE yy_create_buffer FDECL(, (FILE *file,int size )); void yy_delete_buffer FDECL(, (YY_BUFFER_STATE b )); void yy_flush_buffer FDECL(, (YY_BUFFER_STATE b )); void yypush_buffer_state FDECL(, (YY_BUFFER_STATE new_buffer )); void yypop_buffer_state FDECL(, (void )); static void yyensure_buffer_stack FDECL(, (void )); static void yy_load_buffer_state FDECL(, (void )); static void yy_init_buffer FDECL(, (YY_BUFFER_STATE b,FILE *file )); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer FDECL(, (char *base,yy_size_t size )); YY_BUFFER_STATE yy_scan_string FDECL(, (yyconst char *yy_str )); YY_BUFFER_STATE yy_scan_bytes FDECL(, (yyconst char *bytes,yy_size_t len )); void *yyalloc FDECL(, (yy_size_t )); void *yyrealloc FDECL(, (void *,yy_size_t )); void yyfree FDECL(, (void * )); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ) { \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ) { \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state FDECL(, (void )); static yy_state_type yy_try_NUL_trans FDECL(, (yy_state_type current_state )); static int yy_get_next_buffer FDECL(, (void )); static void yy_fatal_error FDECL(, (yyconst char msg[] )) NORETURN; /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 200 #define YY_END_OF_BUFFER 201 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[1057] = { 0, 0, 0, 0, 0, 201, 199, 195, 194, 199, 199, 199, 199, 199, 199, 198, 184, 192, 199, 193, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 195, 199, 198, 2, 199, 195, 199, 199, 198, 184, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 195, 199, 195, 194, 188, 0, 185, 186, 0, 0, 182, 198, 181, 183, 184, 198, 190, 189, 187, 191, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 39, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 55, 198, 198, 0, 0, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 154, 198, 198, 195, 0, 0, 3, 198, 2, 2, 0, 195, 0, 182, 198, 181, 184, 198, 198, 198, 198, 39, 198, 198, 198, 198, 198, 198, 195, 0, 2, 0, 0, 197, 0, 197, 179, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 54, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 0, 198, 104, 198, 83, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 79, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 81, 198, 198, 198, 198, 198, 139, 198, 198, 198, 198, 128, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 16, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 126, 198, 198, 198, 198, 198, 198, 198, 198, 80, 198, 198, 198, 198, 198, 198, 198, 198, 196, 198, 198, 198, 58, 198, 198, 198, 22, 198, 40, 198, 41, 198, 198, 198, 198, 49, 198, 198, 198, 198, 56, 6, 198, 198, 198, 53, 198, 198, 198, 36, 198, 198, 198, 198, 42, 198, 35, 198, 198, 198, 198, 198, 21, 198, 0, 180, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 160, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 155, 158, 114, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 69, 198, 198, 198, 198, 198, 198, 198, 198, 198, 121, 198, 198, 67, 198, 198, 198, 198, 161, 198, 198, 198, 198, 198, 198, 198, 198, 198, 119, 198, 198, 198, 198, 107, 198, 198, 198, 198, 198, 198, 198, 65, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 157, 198, 198, 198, 198, 198, 116, 15, 0, 198, 198, 198, 198, 198, 28, 198, 59, 198, 198, 198, 198, 198, 13, 198, 198, 198, 50, 198, 198, 7, 198, 198, 198, 198, 5, 198, 198, 198, 198, 198, 198, 198, 198, 198, 30, 198, 198, 198, 198, 198, 120, 153, 198, 198, 198, 147, 198, 198, 162, 198, 198, 198, 198, 198, 141, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 156, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 11, 198, 198, 198, 198, 198, 198, 198, 113, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 125, 198, 12, 198, 198, 198, 198, 198, 198, 198, 82, 115, 198, 198, 198, 198, 198, 198, 198, 198, 129, 198, 198, 198, 198, 33, 198, 198, 198, 198, 198, 198, 198, 198, 198, 29, 198, 198, 198, 198, 198, 198, 17, 31, 198, 27, 198, 198, 198, 198, 57, 198, 198, 198, 198, 146, 97, 198, 198, 127, 111, 86, 198, 123, 72, 108, 198, 198, 198, 198, 165, 198, 198, 87, 198, 94, 130, 198, 74, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 135, 198, 198, 109, 198, 198, 198, 198, 198, 198, 198, 198, 198, 110, 168, 198, 198, 198, 16, 198, 198, 198, 198, 77, 198, 117, 198, 198, 198, 198, 198, 112, 198, 198, 198, 152, 173, 198, 198, 78, 198, 198, 198, 198, 198, 198, 198, 198, 1, 57, 198, 198, 198, 60, 198, 198, 198, 198, 198, 198, 198, 4, 198, 19, 198, 198, 198, 198, 198, 62, 43, 198, 46, 26, 198, 163, 99, 198, 198, 198, 198, 198, 73, 159, 198, 198, 98, 198, 198, 198, 93, 198, 198, 198, 198, 145, 198, 198, 198, 198, 198, 136, 198, 198, 198, 198, 198, 20, 63, 140, 138, 198, 198, 198, 198, 198, 198, 198, 198, 118, 198, 132, 96, 198, 151, 198, 198, 198, 198, 198, 101, 47, 89, 198, 198, 198, 198, 198, 198, 45, 198, 198, 34, 61, 14, 8, 25, 198, 198, 198, 198, 198, 23, 198, 169, 198, 198, 198, 102, 177, 198, 66, 198, 75, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 150, 9, 198, 198, 198, 198, 198, 144, 198, 85, 68, 198, 71, 198, 198, 198, 198, 176, 164, 131, 134, 198, 106, 18, 198, 51, 198, 198, 198, 198, 198, 198, 95, 142, 198, 198, 70, 174, 122, 198, 167, 198, 175, 198, 92, 133, 84, 148, 149, 171, 198, 198, 198, 100, 172, 91, 198, 64, 198, 10, 137, 24, 52, 198, 198, 198, 198, 198, 76, 88, 124, 105, 198, 198, 198, 166, 103, 198, 198, 198, 198, 198, 198, 198, 198, 90, 198, 37, 38, 198, 198, 198, 198, 143, 170, 198, 198, 198, 178, 198, 198, 198, 198, 48, 32, 44, 0 } ; static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 7, 8, 9, 10, 1, 11, 1, 1, 1, 12, 1, 13, 14, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 16, 17, 18, 1, 1, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 1, 48, 1, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 14, 14, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst YY_CHAR yy_meta[75] = { 0, 1, 2, 3, 2, 2, 1, 1, 2, 1, 1, 1, 2, 4, 2, 4, 1, 1, 1, 5, 5, 5, 6, 6, 5, 6, 5, 5, 6, 5, 5, 6, 6, 6, 5, 6, 6, 5, 5, 6, 6, 5, 6, 6, 6, 1, 2, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6 } ; static yyconst flex_uint16_t yy_base[1064] = { 0, 0, 73, 102, 77, 1254, 1255, 75, 1255, 1250, 1235, 1244, 0, 1204, 1234, 1233, 78, 66, 1230, 1229, 1215, 1208, 57, 63, 59, 64, 101, 0, 63, 79, 119, 94, 1223, 1209, 122, 123, 121, 1222, 104, 105, 100, 124, 90, 129, 137, 1174, 84, 117, 1176, 139, 150, 151, 151, 156, 1169, 163, 168, 166, 56, 1184, 1183, 232, 1232, 216, 1255, 1231, 242, 248, 251, 264, 196, 155, 167, 208, 228, 241, 1218, 249, 242, 195, 277, 284, 223, 319, 334, 257, 1255, 1255, 1225, 1255, 0, 1220, 1219, 1214, 0, 1213, 1255, 298, 1212, 1255, 1255, 1255, 1255, 1188, 263, 1188, 264, 1200, 1190, 1203, 1184, 1195, 1192, 1199, 270, 1185, 1183, 1185, 1195, 0, 1186, 1190, 1171, 1177, 1165, 1171, 1175, 1174, 1174, 280, 1176, 292, 1171, 301, 1169, 1162, 1168, 1180, 1178, 1170, 259, 0, 1177, 1165, 203, 304, 272, 1121, 1143, 1132, 1138, 1141, 288, 1121, 1125, 1121, 1124, 1123, 1135, 1117, 1119, 308, 1115, 1109, 1106, 1111, 1110, 1116, 1120, 1111, 1113, 1111, 1111, 234, 281, 296, 299, 1117, 282, 1103, 1111, 1096, 81, 315, 1115, 324, 26, 1103, 1102, 1102, 1093, 330, 1103, 1107, 1093, 1109, 1104, 1107, 281, 333, 1100, 1102, 1098, 1090, 342, 323, 321, 1082, 1081, 1083, 1084, 345, 350, 0, 1081, 332, 407, 1143, 1142, 1255, 363, 1255, 1255, 1141, 411, 415, 416, 1128, 0, 412, 390, 396, 404, 415, 1127, 410, 420, 421, 422, 423, 424, 0, 0, 1255, 1138, 0, 1255, 1129, 1128, 1123, 1118, 1104, 1116, 1111, 1095, 1096, 1112, 1094, 1088, 1105, 1091, 1088, 1100, 0, 1092, 1102, 1091, 1099, 1080, 1081, 1096, 1094, 1082, 1092, 1077, 1090, 1075, 1088, 1091, 1061, 1085, 1077, 1068, 1083, 1077, 1073, 1071, 1077, 1071, 1072, 1062, 1059, 1073, 1059, 1060, 1063, 435, 1037, 0, 1042, 0, 1027, 1036, 1026, 1028, 1019, 1023, 1021, 1015, 1023, 385, 1030, 1012, 1016, 1027, 1010, 1016, 1011, 1020, 1007, 1005, 1009, 0, 1002, 1001, 1011, 1001, 1014, 998, 1015, 383, 1010, 999, 392, 1012, 989, 1005, 1006, 1000, 988, 0, 1003, 1003, 996, 999, 989, 0, 982, 983, 991, 994, 0, 987, 992, 981, 993, 983, 988, 987, 378, 986, 970, 977, 973, 974, 404, 966, 408, 980, 970, 982, 979, 968, 966, 970, 974, 392, 956, 967, 967, 971, 952, 969, 953, 956, 964, 950, 395, 958, 946, 964, 950, 945, 0, 946, 956, 939, 950, 943, 948, 936, 935, 0, 462, 448, 453, 971, 454, 456, 434, 455, 1255, 965, 979, 970, 0, 979, 970, 957, 0, 975, 0, 975, 0, 956, 954, 953, 967, 0, 966, 940, 964, 956, 0, 944, 965, 947, 944, 0, 947, 452, 959, 0, 960, 945, 944, 957, 953, 950, 0, 937, 939, 950, 936, 950, 0, 941, 468, 1255, 905, 900, 899, 911, 908, 909, 894, 908, 907, 895, 904, 903, 0, 902, 901, 886, 892, 898, 893, 889, 879, 886, 893, 0, 0, 0, 881, 895, 890, 889, 881, 422, 887, 882, 886, 880, 883, 868, 0, 921, 879, 858, 874, 866, 878, 861, 872, 873, 0, 872, 856, 0, 870, 873, 859, 862, 0, 429, 852, 850, 844, 850, 858, 851, 864, 849, 0, 855, 842, 849, 857, 0, 847, 853, 856, 836, 854, 417, 853, 0, 841, 830, 831, 835, 844, 828, 842, 846, 842, 824, 829, 821, 837, 832, 821, 824, 836, 820, 0, 817, 822, 824, 426, 823, 0, 1255, 876, 463, 859, 466, 475, 476, 0, 851, 0, 849, 853, 844, 837, 832, 0, 852, 843, 831, 0, 837, 831, 0, 847, 840, 845, 840, 0, 835, 842, 822, 829, 827, 825, 835, 822, 824, 0, 820, 826, 818, 823, 825, 0, 0, 795, 783, 793, 0, 792, 791, 0, 782, 780, 789, 780, 773, 0, 785, 785, 781, 782, 767, 784, 780, 764, 760, 440, 0, 776, 776, 774, 760, 763, 770, 770, 749, 768, 435, 760, 756, 758, 754, 763, 758, 745, 761, 757, 758, 758, 741, 741, 754, 740, 752, 0, 751, 739, 753, 746, 734, 735, 749, 0, 731, 743, 727, 721, 739, 728, 734, 730, 732, 727, 721, 737, 732, 0, 721, 0, 714, 714, 713, 712, 712, 725, 725, 443, 0, 723, 722, 717, 720, 705, 711, 708, 712, 0, 717, 733, 483, 490, 0, 734, 732, 726, 736, 735, 734, 727, 723, 739, 0, 724, 712, 81, 122, 205, 226, 0, 0, 311, 0, 350, 460, 483, 476, 0, 472, 478, 468, 463, 0, 0, 461, 464, 0, 0, 0, 457, 0, 0, 0, 456, 458, 467, 447, 0, 469, 470, 0, 458, 0, 0, 474, 0, 471, 470, 466, 480, 478, 478, 475, 470, 472, 482, 473, 470, 488, 479, 0, 483, 489, 0, 473, 475, 493, 488, 476, 481, 495, 489, 488, 0, 0, 491, 503, 489, 0, 480, 486, 492, 489, 0, 496, 514, 505, 495, 510, 497, 503, 0, 499, 509, 510, 0, 0, 511, 515, 0, 518, 509, 520, 520, 521, 522, 508, 528, 0, 563, 564, 557, 545, 0, 560, 551, 552, 553, 543, 553, 559, 0, 562, 0, 565, 554, 571, 545, 558, 0, 0, 557, 0, 0, 536, 0, 0, 544, 545, 546, 548, 548, 0, 0, 539, 535, 0, 544, 537, 540, 0, 554, 554, 547, 543, 0, 552, 546, 554, 566, 553, 0, 551, 565, 551, 568, 568, 0, 0, 0, 0, 565, 559, 561, 572, 566, 574, 555, 576, 1255, 577, 0, 0, 579, 0, 583, 570, 579, 575, 563, 0, 0, 0, 585, 586, 587, 587, 581, 606, 0, 618, 619, 0, 0, 0, 0, 0, 601, 627, 606, 615, 611, 0, 602, 0, 599, 600, 591, 0, 0, 591, 0, 595, 0, 604, 589, 602, 593, 611, 594, 605, 610, 598, 603, 613, 601, 0, 0, 608, 614, 606, 605, 620, 0, 621, 0, 0, 622, 0, 611, 614, 621, 618, 0, 0, 0, 0, 627, 0, 0, 657, 0, 658, 662, 664, 648, 662, 650, 0, 0, 619, 634, 0, 0, 0, 621, 0, 630, 0, 641, 0, 0, 0, 0, 0, 0, 630, 640, 626, 0, 0, 0, 628, 0, 628, 0, 0, 0, 0, 667, 668, 663, 664, 678, 0, 0, 0, 0, 642, 650, 652, 0, 0, 652, 683, 677, 681, 673, 685, 658, 660, 0, 661, 0, 0, 692, 696, 689, 650, 0, 0, 685, 692, 687, 0, 685, 690, 691, 687, 0, 0, 0, 1255, 724, 726, 732, 735, 741, 746, 751 } ; static yyconst flex_int16_t yy_def[1064] = { 0, 1056, 1, 1, 3, 1056, 1056, 1056, 1056, 1056, 1056, 1057, 1058, 1059, 1056, 1060, 1060, 1056, 1056, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1061, 1060, 1056, 1056, 1062, 1062, 1062, 1060, 69, 69, 69, 69, 1060, 69, 69, 69, 69, 69, 69, 69, 69, 1062, 1061, 1056, 1056, 1056, 1057, 1056, 1058, 1056, 1063, 1056, 1060, 1060, 1056, 1060, 1060, 1056, 1056, 1056, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1061, 1061, 1056, 1060, 1056, 1056, 1056, 83, 83, 83, 69, 69, 69, 69, 69, 1060, 69, 69, 69, 69, 69, 69, 69, 69, 83, 84, 1056, 1061, 84, 1056, 1056, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 69, 69, 1060, 69, 69, 69, 69, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1056, 69, 1060, 69, 69, 69, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 69, 69, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 69, 69, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1056, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 1060, 0, 1056, 1056, 1056, 1056, 1056, 1056, 1056 } ; static yyconst flex_uint16_t yy_nxt[1330] = { 0, 6, 7, 8, 9, 7, 10, 11, 6, 12, 6, 13, 14, 15, 6, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 27, 27, 29, 30, 31, 32, 33, 27, 34, 35, 36, 27, 27, 37, 27, 27, 27, 38, 6, 6, 27, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 27, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 27, 27, 27, 61, 105, 85, 61, 61, 85, 62, 83, 99, 100, 84, 107, 119, 96, 110, 106, 111, 356, 97, 113, 120, 108, 114, 121, 109, 357, 112, 122, 115, 63, 64, 65, 66, 63, 144, 67, 836, 123, 128, 68, 69, 67, 70, 212, 145, 213, 71, 72, 73, 116, 74, 75, 129, 76, 77, 98, 76, 78, 175, 117, 347, 79, 118, 124, 80, 81, 132, 125, 82, 140, 133, 126, 176, 67, 135, 136, 348, 127, 163, 141, 134, 164, 142, 837, 165, 152, 137, 138, 153, 139, 146, 154, 147, 177, 155, 227, 148, 149, 156, 76, 150, 151, 157, 166, 178, 158, 159, 227, 179, 160, 230, 170, 161, 181, 167, 171, 168, 182, 162, 172, 169, 183, 173, 185, 186, 189, 192, 184, 104, 190, 194, 96, 187, 144, 195, 227, 229, 198, 188, 191, 193, 199, 203, 145, 209, 200, 204, 196, 227, 205, 201, 202, 231, 131, 210, 838, 206, 211, 207, 216, 220, 208, 216, 227, 125, 217, 106, 240, 126, 85, 222, 223, 224, 98, 127, 1056, 222, 223, 1056, 222, 223, 227, 227, 110, 85, 232, 235, 85, 839, 227, 122, 226, 222, 223, 225, 112, 233, 225, 234, 114, 123, 225, 227, 225, 228, 115, 120, 251, 227, 227, 227, 252, 331, 227, 292, 227, 227, 227, 227, 227, 293, 254, 332, 227, 227, 255, 227, 227, 236, 237, 227, 263, 140, 96, 264, 225, 278, 279, 97, 296, 238, 138, 141, 239, 145, 142, 216, 222, 223, 241, 281, 284, 242, 282, 297, 333, 342, 298, 374, 334, 285, 227, 243, 244, 245, 299, 305, 245, 375, 335, 306, 245, 245, 245, 245, 98, 307, 343, 245, 245, 245, 336, 316, 245, 840, 245, 245, 337, 245, 245, 338, 339, 340, 245, 317, 318, 245, 245, 841, 319, 245, 349, 350, 353, 362, 245, 388, 363, 351, 376, 354, 386, 355, 377, 387, 389, 364, 365, 383, 394, 384, 366, 403, 367, 401, 402, 396, 385, 378, 397, 227, 245, 273, 398, 216, 399, 227, 216, 85, 395, 217, 224, 1056, 1056, 225, 225, 225, 96, 225, 225, 227, 406, 229, 404, 260, 227, 226, 270, 405, 407, 227, 227, 227, 227, 227, 457, 408, 470, 490, 494, 518, 519, 471, 537, 227, 409, 491, 549, 288, 410, 524, 527, 525, 550, 287, 538, 528, 495, 227, 98, 564, 565, 566, 227, 227, 227, 227, 569, 457, 592, 634, 415, 676, 227, 424, 677, 227, 458, 568, 657, 570, 593, 700, 635, 658, 227, 227, 754, 842, 701, 765, 704, 811, 227, 571, 812, 766, 601, 705, 755, 227, 843, 844, 845, 823, 846, 847, 848, 849, 824, 458, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 227, 227, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 847, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 88, 88, 88, 88, 88, 88, 90, 90, 91, 91, 835, 91, 91, 91, 94, 94, 94, 218, 218, 218, 218, 218, 218, 225, 225, 225, 225, 247, 247, 834, 247, 247, 247, 833, 832, 831, 830, 829, 828, 827, 826, 825, 822, 821, 820, 819, 818, 817, 816, 815, 814, 813, 810, 809, 808, 807, 806, 805, 804, 803, 802, 801, 800, 799, 798, 797, 796, 795, 794, 793, 792, 791, 790, 789, 788, 787, 786, 785, 784, 783, 782, 781, 780, 779, 778, 777, 776, 775, 774, 773, 772, 771, 770, 769, 768, 767, 764, 763, 762, 761, 760, 759, 758, 757, 756, 753, 752, 751, 750, 749, 748, 747, 746, 745, 744, 743, 742, 741, 740, 739, 738, 737, 736, 735, 734, 733, 732, 731, 730, 729, 728, 727, 726, 725, 724, 723, 722, 721, 720, 719, 718, 717, 716, 715, 714, 713, 712, 711, 710, 709, 708, 707, 706, 703, 564, 702, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, 687, 686, 685, 684, 683, 682, 681, 680, 679, 678, 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, 665, 664, 663, 662, 661, 660, 659, 656, 655, 654, 653, 652, 651, 650, 649, 648, 647, 646, 645, 644, 643, 642, 641, 640, 639, 638, 637, 636, 633, 632, 631, 630, 629, 628, 627, 626, 625, 624, 623, 622, 621, 620, 619, 618, 617, 616, 615, 614, 613, 612, 611, 610, 609, 608, 607, 606, 605, 604, 603, 602, 601, 600, 599, 598, 597, 596, 595, 594, 591, 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, 567, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 548, 547, 546, 545, 544, 543, 542, 541, 540, 539, 536, 535, 534, 533, 532, 531, 530, 529, 526, 523, 522, 521, 520, 438, 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, 493, 492, 489, 488, 487, 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 456, 455, 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 249, 411, 411, 243, 227, 227, 222, 219, 219, 400, 393, 392, 391, 390, 382, 381, 380, 379, 373, 372, 371, 370, 369, 368, 361, 360, 359, 358, 352, 346, 345, 344, 341, 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, 315, 314, 313, 312, 311, 310, 309, 308, 304, 303, 302, 301, 300, 295, 294, 291, 290, 289, 288, 287, 286, 283, 280, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 262, 261, 260, 259, 258, 257, 256, 253, 250, 249, 95, 93, 248, 246, 89, 227, 221, 219, 215, 214, 197, 180, 174, 143, 131, 130, 104, 103, 102, 101, 95, 93, 92, 89, 87, 86, 1056, 5, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056 } ; static yyconst flex_int16_t yy_chk[1330] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 22, 7, 2, 4, 7, 2, 4, 17, 17, 4, 23, 28, 16, 24, 22, 24, 186, 16, 25, 28, 23, 25, 29, 23, 186, 24, 29, 25, 2, 3, 3, 3, 4, 38, 3, 719, 29, 31, 3, 3, 3, 3, 58, 38, 58, 3, 3, 3, 26, 3, 3, 31, 3, 3, 16, 3, 3, 46, 26, 182, 3, 26, 30, 3, 3, 34, 30, 3, 36, 34, 30, 46, 3, 35, 35, 182, 30, 42, 36, 34, 42, 36, 720, 42, 40, 35, 35, 40, 35, 39, 40, 39, 47, 40, 71, 39, 39, 41, 3, 39, 39, 41, 43, 47, 41, 41, 72, 47, 41, 71, 44, 41, 49, 43, 44, 43, 49, 41, 44, 43, 49, 44, 50, 50, 51, 52, 49, 72, 51, 53, 70, 50, 144, 53, 79, 70, 55, 50, 51, 52, 55, 56, 144, 57, 55, 56, 53, 73, 56, 55, 55, 73, 79, 57, 721, 56, 57, 56, 61, 63, 56, 61, 82, 63, 61, 73, 82, 63, 66, 66, 66, 66, 70, 63, 67, 67, 67, 68, 68, 68, 75, 78, 74, 85, 74, 78, 85, 722, 77, 78, 68, 69, 69, 69, 74, 75, 69, 77, 75, 78, 69, 69, 69, 69, 75, 77, 104, 69, 69, 69, 104, 173, 69, 140, 69, 69, 80, 69, 69, 140, 106, 173, 69, 81, 106, 69, 69, 80, 80, 69, 114, 81, 97, 114, 69, 129, 129, 97, 145, 80, 80, 81, 80, 145, 81, 83, 83, 83, 83, 131, 133, 83, 131, 146, 174, 178, 146, 198, 174, 133, 69, 84, 84, 84, 146, 152, 84, 198, 174, 152, 84, 84, 84, 84, 97, 152, 178, 84, 84, 84, 175, 161, 84, 725, 84, 84, 175, 84, 84, 176, 176, 176, 84, 161, 161, 84, 84, 727, 161, 84, 183, 183, 185, 191, 84, 206, 191, 183, 199, 185, 205, 185, 199, 205, 206, 191, 191, 204, 211, 204, 191, 220, 191, 215, 215, 212, 204, 199, 212, 230, 84, 220, 212, 216, 212, 231, 216, 224, 211, 216, 224, 225, 226, 224, 225, 226, 229, 225, 226, 235, 232, 229, 230, 232, 233, 226, 235, 231, 233, 236, 237, 238, 239, 240, 296, 238, 310, 330, 333, 359, 359, 310, 376, 409, 239, 330, 387, 237, 240, 365, 367, 365, 387, 236, 376, 367, 333, 404, 229, 403, 403, 404, 405, 407, 410, 408, 409, 457, 440, 490, 405, 536, 566, 407, 536, 568, 296, 408, 516, 410, 440, 561, 490, 516, 569, 570, 631, 728, 561, 642, 569, 691, 704, 566, 691, 642, 568, 570, 631, 705, 729, 730, 732, 704, 733, 734, 735, 738, 705, 457, 739, 743, 747, 748, 749, 750, 752, 753, 755, 758, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 775, 776, 778, 779, 780, 781, 782, 783, 784, 785, 786, 789, 790, 791, 793, 794, 795, 796, 798, 799, 800, 801, 802, 803, 804, 806, 807, 808, 811, 812, 814, 815, 816, 817, 818, 819, 820, 821, 823, 824, 825, 826, 828, 829, 830, 831, 832, 833, 834, 836, 838, 839, 840, 841, 842, 845, 848, 851, 852, 853, 854, 855, 858, 859, 861, 862, 863, 824, 865, 866, 867, 868, 870, 871, 872, 873, 874, 876, 877, 878, 879, 880, 885, 886, 887, 888, 889, 890, 891, 892, 894, 897, 899, 900, 901, 902, 903, 907, 908, 909, 910, 911, 912, 914, 915, 921, 922, 923, 924, 925, 927, 929, 930, 931, 934, 936, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 952, 953, 954, 955, 956, 958, 961, 963, 964, 965, 966, 971, 974, 976, 977, 978, 979, 980, 981, 984, 985, 989, 991, 993, 1000, 1001, 1002, 1006, 1008, 1013, 1014, 1015, 1016, 1017, 1022, 1023, 1024, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1036, 1039, 1040, 1041, 1042, 1045, 1046, 1047, 1049, 1050, 1051, 1052, 1057, 1057, 1057, 1057, 1057, 1057, 1058, 1058, 1059, 1059, 718, 1059, 1059, 1059, 1060, 1060, 1060, 1061, 1061, 1061, 1061, 1061, 1061, 1062, 1062, 1062, 1062, 1063, 1063, 717, 1063, 1063, 1063, 715, 714, 713, 712, 711, 710, 709, 708, 707, 703, 702, 700, 699, 698, 697, 696, 695, 694, 693, 690, 689, 688, 687, 686, 685, 684, 682, 680, 679, 678, 677, 676, 675, 674, 673, 672, 671, 670, 669, 668, 666, 665, 664, 663, 662, 661, 660, 658, 657, 656, 655, 654, 653, 652, 651, 650, 649, 648, 647, 646, 645, 644, 643, 641, 640, 639, 638, 637, 636, 635, 634, 633, 630, 629, 628, 627, 626, 625, 624, 623, 622, 620, 619, 618, 617, 616, 614, 613, 611, 610, 609, 606, 605, 604, 603, 602, 600, 599, 598, 597, 596, 595, 594, 593, 592, 590, 589, 588, 587, 585, 584, 582, 581, 580, 578, 577, 576, 575, 574, 572, 567, 565, 562, 560, 559, 558, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, 540, 539, 537, 535, 534, 533, 532, 531, 529, 528, 527, 526, 524, 523, 522, 521, 520, 519, 518, 517, 514, 513, 512, 511, 509, 508, 506, 505, 504, 503, 502, 501, 500, 499, 498, 496, 495, 494, 493, 492, 491, 489, 488, 487, 486, 485, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472, 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 456, 454, 453, 452, 451, 450, 448, 447, 446, 445, 444, 443, 441, 439, 437, 436, 435, 434, 432, 431, 430, 429, 427, 426, 425, 424, 422, 420, 418, 417, 416, 414, 413, 412, 406, 401, 400, 399, 398, 397, 396, 395, 394, 392, 391, 390, 389, 388, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 375, 374, 373, 372, 371, 370, 369, 368, 366, 364, 363, 362, 361, 360, 358, 357, 356, 355, 354, 353, 352, 350, 349, 348, 347, 345, 344, 343, 342, 341, 339, 338, 337, 336, 335, 334, 332, 331, 329, 328, 327, 326, 325, 324, 323, 321, 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, 309, 308, 307, 306, 305, 304, 303, 302, 301, 299, 297, 295, 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 244, 234, 227, 223, 218, 217, 214, 210, 209, 208, 207, 203, 202, 201, 200, 197, 196, 195, 194, 193, 192, 190, 189, 188, 187, 184, 181, 180, 179, 177, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 160, 159, 158, 157, 156, 155, 154, 153, 151, 150, 149, 148, 147, 143, 142, 139, 138, 137, 136, 135, 134, 132, 130, 128, 127, 126, 125, 124, 123, 122, 121, 120, 118, 117, 116, 115, 113, 112, 111, 110, 109, 108, 107, 105, 103, 98, 95, 93, 92, 91, 88, 76, 65, 62, 60, 59, 54, 48, 45, 37, 33, 32, 21, 20, 19, 18, 15, 14, 13, 11, 10, 9, 5, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; /* NetHack 3.6 lev_comp.l $NHDT-Date: 1449385344 2015/12/06 07:02:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #define LEV_LEX_C #include "hack.h" #include "lev_comp.h" #include "sp_lev.h" /* Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #else /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ /* most recent flex allows suppressing yyunput() altogether when not needed */ #define YY_NO_UNPUT #endif #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) /* older flex wants this */ #define YY_MALLOC_DECL genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t, size_t)); /* newer flex assumes so needs this in case it's been suppressed */ YY_MALLOC_DECL #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); long NDECL(handle_varstring_check); long FDECL(corefunc_str_check, (char *, long)); extern void VDECL(lc_error, (const char *, ...)); extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int)); extern struct lc_vardefs *variable_definitions; extern long FDECL(method_defined, (char *, long, long *)); void FDECL(savetoken, (char *)); void NDECL(newline); void FDECL(advancepos, (char *)); /* * This doesn't always get put in lev_comp.h * (esp. when using older versions of bison). */ extern YYSTYPE yylval; int nh_line_number = 1; int token_start_pos = 0; char curr_token[512]; static char map[4096]; static int map_cnt = 0; FILE *orig_yyin = NULL; #define ST_RET(x) do { savetoken(yytext); return x; } while (0); #define ST_RETF(y, x) do { savetoken(yytext); y; return x; } while (0); #define INITIAL 0 #define MAPC 1 #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy FDECL(, (void )); int yyget_debug FDECL(, (void )); void yyset_debug FDECL(, (int debug_flag )); YY_EXTRA_TYPE yyget_extra FDECL(, (void )); void yyset_extra FDECL(, (YY_EXTRA_TYPE user_defined )); FILE *yyget_in FDECL(, (void )); void yyset_in FDECL(, (FILE * _in_str )); FILE *yyget_out FDECL(, (void )); void yyset_out FDECL(, (FILE * _out_str )); yy_size_t yyget_leng FDECL(, (void )); char *yyget_text FDECL(, (void )); int yyget_lineno FDECL(, (void )); void yyset_lineno FDECL(, (int _line_number )); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP extern int yywrap FDECL(, (void )); #endif #ifndef YY_NO_UNPUT static void yyunput FDECL(, (int c,char *buf_ptr )); #endif #ifndef yytext_ptr static void yy_flex_strncpy FDECL(, (char *,yyconst char *,int )); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen FDECL(, (yyconst char * )); #endif #ifndef YY_NO_INPUT static int input FDECL(, (void )); #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex FDECL(, (void)); #define YY_DECL int yylex () #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } { while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1057 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 1255 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP { savetoken(yytext); BEGIN(INITIAL); yylval.map = (char *) alloc(map_cnt + 1); (void) strncpy(yylval.map, map, map_cnt); yylval.map[map_cnt] = 0; map_cnt = 0; return MAP_ID; } YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP { int len = yyleng; savetoken(yytext); /* convert \r\n to \n */ if (len >= 2 && yytext[len - 2] == '\r') len -= 1; (void) strncpy(map + map_cnt, yytext, len); map_cnt += len; map[map_cnt - 1] = '\n'; map[map_cnt] = '\0'; newline(); } YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP { savetoken(yytext); newline(); } YY_BREAK case 4: YY_RULE_SETUP ST_RET(MESSAGE_ID); YY_BREAK case 5: YY_RULE_SETUP ST_RET(NOMAP_ID); YY_BREAK case 6: YY_RULE_SETUP ST_RET(MAZE_ID); YY_BREAK case 7: YY_RULE_SETUP ST_RET(LEVEL_ID); YY_BREAK case 8: YY_RULE_SETUP ST_RET(LEV_INIT_ID); YY_BREAK case 9: YY_RULE_SETUP ST_RET(MAZE_GRID_ID); YY_BREAK case 10: YY_RULE_SETUP ST_RET(SOLID_FILL_ID); YY_BREAK case 11: YY_RULE_SETUP ST_RET(MINES_ID); YY_BREAK case 12: YY_RULE_SETUP ST_RET(ROGUELEV_ID); YY_BREAK case 13: YY_RULE_SETUP ST_RET(FLAGS_ID); YY_BREAK case 14: YY_RULE_SETUP ST_RET(GEOMETRY_ID); YY_BREAK case 15: /* rule 15 can match eol */ YY_RULE_SETUP { savetoken(yytext); BEGIN(MAPC); newline(); } YY_BREAK case 16: YY_RULE_SETUP ST_RET(object_ID); YY_BREAK case 17: YY_RULE_SETUP ST_RET(OBJECT_ID); YY_BREAK case 18: YY_RULE_SETUP ST_RET(COBJECT_ID); YY_BREAK case 19: YY_RULE_SETUP ST_RET(MONSTER_ID); YY_BREAK case 20: YY_RULE_SETUP ST_RET(monster_ID); YY_BREAK case 21: YY_RULE_SETUP ST_RET(TRAP_ID); YY_BREAK case 22: YY_RULE_SETUP ST_RET(DOOR_ID); YY_BREAK case 23: YY_RULE_SETUP ST_RET(ROOMDOOR_ID); YY_BREAK case 24: YY_RULE_SETUP ST_RET(DRAWBRIDGE_ID); YY_BREAK case 25: YY_RULE_SETUP ST_RET(MAZEWALK_ID); YY_BREAK case 26: YY_RULE_SETUP ST_RET(WALLIFY_ID); YY_BREAK case 27: YY_RULE_SETUP ST_RET(REGION_ID); YY_BREAK case 28: YY_RULE_SETUP ST_RET(ALTAR_ID); YY_BREAK case 29: YY_RULE_SETUP ST_RET(LADDER_ID); YY_BREAK case 30: YY_RULE_SETUP ST_RET(STAIR_ID); YY_BREAK case 31: YY_RULE_SETUP ST_RET(PORTAL_ID); YY_BREAK case 32: YY_RULE_SETUP ST_RET(TELEPRT_ID); YY_BREAK case 33: YY_RULE_SETUP ST_RET(BRANCH_ID); YY_BREAK case 34: YY_RULE_SETUP ST_RET(FOUNTAIN_ID); YY_BREAK case 35: YY_RULE_SETUP ST_RET(SINK_ID); YY_BREAK case 36: YY_RULE_SETUP ST_RET(POOL_ID); YY_BREAK case 37: YY_RULE_SETUP ST_RET(NON_DIGGABLE_ID); YY_BREAK case 38: YY_RULE_SETUP ST_RET(NON_PASSWALL_ID); YY_BREAK case 39: YY_RULE_SETUP ST_RET(IF_ID); YY_BREAK case 40: YY_RULE_SETUP ST_RET(ELSE_ID); YY_BREAK case 41: YY_RULE_SETUP ST_RET(EXIT_ID); YY_BREAK case 42: YY_RULE_SETUP ST_RET(ROOM_ID); YY_BREAK case 43: YY_RULE_SETUP ST_RET(SUBROOM_ID); YY_BREAK case 44: YY_RULE_SETUP ST_RET(RAND_CORRIDOR_ID); YY_BREAK case 45: YY_RULE_SETUP ST_RET(CORRIDOR_ID); YY_BREAK case 46: YY_RULE_SETUP ST_RET(TERRAIN_ID); YY_BREAK case 47: YY_RULE_SETUP ST_RET(terrain_ID); YY_BREAK case 48: YY_RULE_SETUP ST_RET(REPLACE_TERRAIN_ID); YY_BREAK case 49: YY_RULE_SETUP ST_RET(GOLD_ID); YY_BREAK case 50: YY_RULE_SETUP ST_RET(GRAVE_ID); YY_BREAK case 51: YY_RULE_SETUP ST_RET(ENGRAVING_ID); YY_BREAK case 52: YY_RULE_SETUP ST_RET(MINERALIZE_ID); YY_BREAK case 53: YY_RULE_SETUP ST_RET(NAME_ID); YY_BREAK case 54: YY_RULE_SETUP ST_RET(FOR_ID); YY_BREAK case 55: YY_RULE_SETUP ST_RET(TO_ID); YY_BREAK case 56: YY_RULE_SETUP ST_RET(LOOP_ID); YY_BREAK case 57: YY_RULE_SETUP ST_RET(SWITCH_ID); YY_BREAK case 58: YY_RULE_SETUP ST_RET(CASE_ID); YY_BREAK case 59: YY_RULE_SETUP ST_RET(BREAK_ID); YY_BREAK case 60: YY_RULE_SETUP ST_RET(DEFAULT_ID); YY_BREAK case 61: YY_RULE_SETUP ST_RET(FUNCTION_ID); YY_BREAK case 62: YY_RULE_SETUP ST_RET(SHUFFLE_ID); YY_BREAK case 63: YY_RULE_SETUP ST_RET(MONTYPE_ID); YY_BREAK case 64: YY_RULE_SETUP ST_RET(selection_ID); YY_BREAK case 65: YY_RULE_SETUP ST_RET(rect_ID); YY_BREAK case 66: YY_RULE_SETUP ST_RET(fillrect_ID); YY_BREAK case 67: YY_RULE_SETUP ST_RET(line_ID); YY_BREAK case 68: YY_RULE_SETUP ST_RET(randline_ID); YY_BREAK case 69: YY_RULE_SETUP ST_RET(grow_ID); YY_BREAK case 70: YY_RULE_SETUP ST_RET(flood_ID); YY_BREAK case 71: YY_RULE_SETUP ST_RET(rndcoord_ID); YY_BREAK case 72: YY_RULE_SETUP ST_RET(circle_ID); YY_BREAK case 73: YY_RULE_SETUP ST_RET(ellipse_ID); YY_BREAK case 74: YY_RULE_SETUP ST_RET(filter_ID); YY_BREAK case 75: YY_RULE_SETUP ST_RET(gradient_ID); YY_BREAK case 76: YY_RULE_SETUP ST_RET(complement_ID); YY_BREAK case 77: YY_RULE_SETUP { savetoken(yytext); yylval.i=SEL_GRADIENT_RADIAL; return GRADIENT_TYPE; } YY_BREAK case 78: YY_RULE_SETUP { savetoken(yytext); yylval.i=SEL_GRADIENT_SQUARE; return GRADIENT_TYPE; } YY_BREAK case 79: YY_RULE_SETUP { savetoken(yytext); yylval.i=DRY; return HUMIDITY_TYPE; } YY_BREAK case 80: YY_RULE_SETUP { savetoken(yytext); yylval.i=WET; return HUMIDITY_TYPE; } YY_BREAK case 81: YY_RULE_SETUP { savetoken(yytext); yylval.i=HOT; return HUMIDITY_TYPE; } YY_BREAK case 82: YY_RULE_SETUP { savetoken(yytext); yylval.i=SOLID; return HUMIDITY_TYPE; } YY_BREAK case 83: YY_RULE_SETUP { savetoken(yytext); yylval.i=ANY_LOC; return HUMIDITY_TYPE; } YY_BREAK case 84: YY_RULE_SETUP ST_RET(LEV); YY_BREAK case 85: YY_RULE_SETUP ST_RET(QUANTITY_ID); YY_BREAK case 86: YY_RULE_SETUP ST_RET(BURIED_ID); YY_BREAK case 87: YY_RULE_SETUP ST_RET(ERODED_ID); YY_BREAK case 88: YY_RULE_SETUP ST_RET(ERODEPROOF_ID); YY_BREAK case 89: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return TRAPPED_STATE; } YY_BREAK case 90: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return TRAPPED_STATE; } YY_BREAK case 91: YY_RULE_SETUP ST_RET(RECHARGED_ID); YY_BREAK case 92: YY_RULE_SETUP ST_RET(INVIS_ID); YY_BREAK case 93: YY_RULE_SETUP ST_RET(GREASED_ID); YY_BREAK case 94: YY_RULE_SETUP ST_RET(FEMALE_ID); YY_BREAK case 95: YY_RULE_SETUP ST_RET(CANCELLED_ID); YY_BREAK case 96: YY_RULE_SETUP ST_RET(REVIVED_ID); YY_BREAK case 97: YY_RULE_SETUP ST_RET(AVENGE_ID); YY_BREAK case 98: YY_RULE_SETUP ST_RET(FLEEING_ID); YY_BREAK case 99: YY_RULE_SETUP ST_RET(BLINDED_ID); YY_BREAK case 100: YY_RULE_SETUP ST_RET(PARALYZED_ID); YY_BREAK case 101: YY_RULE_SETUP ST_RET(STUNNED_ID); YY_BREAK case 102: YY_RULE_SETUP ST_RET(CONFUSED_ID); YY_BREAK case 103: YY_RULE_SETUP ST_RET(SEENTRAPS_ID); YY_BREAK case 104: YY_RULE_SETUP ST_RET(ALL_ID); YY_BREAK case 105: YY_RULE_SETUP ST_RETF((yylval.i=1), HORIZ_OR_VERT); YY_BREAK case 106: YY_RULE_SETUP { savetoken(yytext); yylval.i=2; return HORIZ_OR_VERT; } YY_BREAK case 107: YY_RULE_SETUP { savetoken(yytext); yylval.i=D_ISOPEN; return DOOR_STATE; } YY_BREAK case 108: YY_RULE_SETUP { savetoken(yytext); yylval.i=D_CLOSED; return DOOR_STATE; } YY_BREAK case 109: YY_RULE_SETUP { savetoken(yytext); yylval.i=D_LOCKED; return DOOR_STATE; } YY_BREAK case 110: YY_RULE_SETUP { savetoken(yytext); yylval.i=D_NODOOR; return DOOR_STATE; } YY_BREAK case 111: YY_RULE_SETUP { savetoken(yytext); yylval.i=D_BROKEN; return DOOR_STATE; } YY_BREAK case 112: YY_RULE_SETUP { savetoken(yytext); yylval.i=D_SECRET; return DOOR_STATE; } YY_BREAK case 113: YY_RULE_SETUP { savetoken(yytext); yylval.i=W_NORTH; return DIRECTION; } YY_BREAK case 114: YY_RULE_SETUP { savetoken(yytext); yylval.i=W_EAST; return DIRECTION; } YY_BREAK case 115: YY_RULE_SETUP { savetoken(yytext); yylval.i=W_SOUTH; return DIRECTION; } YY_BREAK case 116: YY_RULE_SETUP { savetoken(yytext); yylval.i=W_WEST; return DIRECTION; } YY_BREAK case 117: YY_RULE_SETUP { savetoken(yytext); yylval.i = -1; return RANDOM_TYPE; } YY_BREAK case 118: YY_RULE_SETUP { savetoken(yytext); yylval.i = -1; return RANDOM_TYPE_BRACKET; } YY_BREAK case 119: YY_RULE_SETUP { savetoken(yytext); yylval.i = -2; return NONE; } YY_BREAK case 120: YY_RULE_SETUP ST_RET(A_REGISTER); YY_BREAK case 121: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return LEFT_OR_RIGHT; } YY_BREAK case 122: YY_RULE_SETUP { savetoken(yytext); yylval.i=2; return LEFT_OR_RIGHT; } YY_BREAK case 123: YY_RULE_SETUP { savetoken(yytext); yylval.i=3; return CENTER; } YY_BREAK case 124: YY_RULE_SETUP { savetoken(yytext); yylval.i=4; return LEFT_OR_RIGHT; } YY_BREAK case 125: YY_RULE_SETUP { savetoken(yytext); yylval.i=5; return LEFT_OR_RIGHT; } YY_BREAK case 126: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return TOP_OR_BOT; } YY_BREAK case 127: YY_RULE_SETUP { savetoken(yytext); yylval.i=5; return TOP_OR_BOT; } YY_BREAK case 128: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return LIGHT_STATE; } YY_BREAK case 129: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return LIGHT_STATE; } YY_BREAK case 130: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return FILLING; } YY_BREAK case 131: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return FILLING; } YY_BREAK case 132: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return IRREGULAR; } YY_BREAK case 133: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return IRREGULAR; } YY_BREAK case 134: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return JOINED; } YY_BREAK case 135: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return JOINED; } YY_BREAK case 136: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return LIMITED; } YY_BREAK case 137: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return LIMITED; } YY_BREAK case 138: YY_RULE_SETUP { savetoken(yytext); yylval.i= AM_NONE; return ALIGNMENT; } YY_BREAK case 139: YY_RULE_SETUP { savetoken(yytext); yylval.i= AM_LAWFUL; return ALIGNMENT; } YY_BREAK case 140: YY_RULE_SETUP { savetoken(yytext); yylval.i= AM_NEUTRAL; return ALIGNMENT; } YY_BREAK case 141: YY_RULE_SETUP { savetoken(yytext); yylval.i= AM_CHAOTIC; return ALIGNMENT; } YY_BREAK case 142: YY_RULE_SETUP { savetoken(yytext); yylval.i= AM_SPLEV_CO; return ALIGNMENT; } YY_BREAK case 143: YY_RULE_SETUP { savetoken(yytext); yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; } YY_BREAK case 144: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return MON_ATTITUDE; } YY_BREAK case 145: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return MON_ATTITUDE; } YY_BREAK case 146: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return MON_ALERTNESS; } YY_BREAK case 147: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return MON_ALERTNESS; } YY_BREAK case 148: YY_RULE_SETUP { savetoken(yytext); yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; } YY_BREAK case 149: YY_RULE_SETUP { savetoken(yytext); yylval.i= M_AP_MONSTER; return MON_APPEARANCE; } YY_BREAK case 150: YY_RULE_SETUP { savetoken(yytext); yylval.i= M_AP_OBJECT; return MON_APPEARANCE; } YY_BREAK case 151: YY_RULE_SETUP { savetoken(yytext); yylval.i=2; return ALTAR_TYPE; } YY_BREAK case 152: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return ALTAR_TYPE; } YY_BREAK case 153: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return ALTAR_TYPE; } YY_BREAK case 154: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return UP_OR_DOWN; } YY_BREAK case 155: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return UP_OR_DOWN; } YY_BREAK case 156: YY_RULE_SETUP { savetoken(yytext); yylval.i=0; return BOOLEAN; } YY_BREAK case 157: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return BOOLEAN; } YY_BREAK case 158: YY_RULE_SETUP { savetoken(yytext); yylval.i=DUST; return ENGRAVING_TYPE; } YY_BREAK case 159: YY_RULE_SETUP { savetoken(yytext); yylval.i=ENGRAVE; return ENGRAVING_TYPE; } YY_BREAK case 160: YY_RULE_SETUP { savetoken(yytext); yylval.i=BURN; return ENGRAVING_TYPE; } YY_BREAK case 161: YY_RULE_SETUP { savetoken(yytext); yylval.i=MARK; return ENGRAVING_TYPE; } YY_BREAK case 162: YY_RULE_SETUP { savetoken(yytext); yylval.i=ENGR_BLOOD; return ENGRAVING_TYPE; } YY_BREAK case 163: YY_RULE_SETUP { savetoken(yytext); yylval.i=1; return CURSE_TYPE; } YY_BREAK case 164: YY_RULE_SETUP { savetoken(yytext); yylval.i=2; return CURSE_TYPE; } YY_BREAK case 165: YY_RULE_SETUP { savetoken(yytext); yylval.i=3; return CURSE_TYPE; } YY_BREAK case 166: YY_RULE_SETUP { savetoken(yytext); yylval.i=NOTELEPORT; return FLAG_TYPE; } YY_BREAK case 167: YY_RULE_SETUP { savetoken(yytext); yylval.i=HARDFLOOR; return FLAG_TYPE; } YY_BREAK case 168: YY_RULE_SETUP { savetoken(yytext); yylval.i=NOMMAP; return FLAG_TYPE; } YY_BREAK case 169: YY_RULE_SETUP { savetoken(yytext); yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */ YY_BREAK case 170: YY_RULE_SETUP { savetoken(yytext); yylval.i=SHORTSIGHTED; return FLAG_TYPE; } YY_BREAK case 171: YY_RULE_SETUP { savetoken(yytext); yylval.i=MAZELEVEL; return FLAG_TYPE; } YY_BREAK case 172: YY_RULE_SETUP { savetoken(yytext); yylval.i=PREMAPPED; return FLAG_TYPE; } YY_BREAK case 173: YY_RULE_SETUP { savetoken(yytext); yylval.i=SHROUD; return FLAG_TYPE; } YY_BREAK case 174: YY_RULE_SETUP { savetoken(yytext); yylval.i=GRAVEYARD; return FLAG_TYPE; } YY_BREAK case 175: YY_RULE_SETUP { savetoken(yytext); yylval.i=ICEDPOOLS; return FLAG_TYPE; } YY_BREAK case 176: YY_RULE_SETUP { savetoken(yytext); yylval.i=SOLIDIFY; return FLAG_TYPE; } YY_BREAK case 177: YY_RULE_SETUP { savetoken(yytext); yylval.i=CORRMAZE; return FLAG_TYPE; } YY_BREAK case 178: YY_RULE_SETUP { savetoken(yytext); yylval.i=CHECK_INACCESSIBLES; return FLAG_TYPE; } YY_BREAK case 179: YY_RULE_SETUP { char *p = index(yytext, 'd'); savetoken(yytext); if (p) { *p++ = '\0'; yylval.dice.num = atoi(yytext); yylval.dice.die = atoi(p); } else { yylval.dice.num = yylval.dice.die = 1; } return DICE; } YY_BREAK case 180: YY_RULE_SETUP { savetoken(yytext); yylval.i = atoi(yytext + 1); if (yylval.i < 0 || yylval.i > 100) lc_error("Unexpected percentile '%li%%'", yylval.i); return PERCENT; } YY_BREAK case 181: YY_RULE_SETUP { savetoken(yytext); yylval.i=atoi(yytext); return MINUS_INTEGER; } YY_BREAK case 182: YY_RULE_SETUP { savetoken(yytext); yylval.i=atoi(yytext); return PLUS_INTEGER; } YY_BREAK case 183: YY_RULE_SETUP { savetoken(yytext); yylval.i = atoi(yytext); if (yylval.i < 0 || yylval.i > 100) lc_error("Unexpected percentile '%li%%'", yylval.i); return SPERCENT; } YY_BREAK case 184: YY_RULE_SETUP { savetoken(yytext); yylval.i=atoi(yytext); return INTEGER; } YY_BREAK case 185: /* rule 185 can match eol */ YY_RULE_SETUP { savetoken(yytext); yytext[yyleng - 1] = '\0'; /* discard the trailing \" */ yylval.map = dupstr(yytext + 1); /* skip the first \" */ return STRING; } YY_BREAK case 186: YY_RULE_SETUP { savetoken(yytext); return handle_varstring_check(); } YY_BREAK case 187: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JE; return COMPARE_TYPE; } YY_BREAK case 188: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; } YY_BREAK case 189: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; } YY_BREAK case 190: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JLE; return COMPARE_TYPE; } YY_BREAK case 191: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JGE; return COMPARE_TYPE; } YY_BREAK case 192: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JL; return COMPARE_TYPE; } YY_BREAK case 193: YY_RULE_SETUP { savetoken(yytext); yylval.i = SPO_JG; return COMPARE_TYPE; } YY_BREAK case 194: /* rule 194 can match eol */ YY_RULE_SETUP { newline(); } YY_BREAK case 195: YY_RULE_SETUP { advancepos(yytext); } YY_BREAK case 196: YY_RULE_SETUP { savetoken(yytext); yylval.i = yytext[2]; return CHAR; } YY_BREAK case 197: YY_RULE_SETUP { savetoken(yytext); yylval.i = yytext[1]; return CHAR; } YY_BREAK case 198: YY_RULE_SETUP ST_RET(UNKNOWN_TYPE); YY_BREAK case 199: YY_RULE_SETUP { savetoken(yytext); return yytext[0]; } YY_BREAK case 200: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(MAPC): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer () { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); yy_size_t number_to_move, i; int ret_val; if ((yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1]) YY_FATAL_ERROR("fatal flex scanner internal error--end of buffer missed"); if (YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for (i = 0; i < number_to_move; ++i) *(dest++) = *(source++); if (YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING) { /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; } else { yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while (num_to_read <= 0) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if (! b->yy_ch_buf) YY_FATAL_ERROR("fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT((&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ((yy_n_chars) == 0) { if (number_to_move == YY_MORE_ADJ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if (! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) YY_FATAL_ERROR("out of dynamic memory in yy_get_next_buffer()"); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before EOB char was reached */ static yy_state_type yy_get_previous_state () { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for (yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1057 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_current_state ) yy_state_type yy_current_state; { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1057 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 1056); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT static void yyunput (c,yy_bp ) int c; char * yy_bp; { char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ yy_size_t number_to_move = (yy_n_chars) + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #endif #ifndef YY_NO_INPUT static int input () { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; return input(); } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(uchar *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (input_file ) FILE * input_file; { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (new_buffer ) YY_BUFFER_STATE new_buffer; { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state () { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (file,size ) FILE * file; int size; { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (b ) YY_BUFFER_STATE b; { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (b,file ) YY_BUFFER_STATE b; FILE * file; { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (b ) YY_BUFFER_STATE b; { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (new_buffer ) YY_BUFFER_STATE new_buffer; { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state () { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack () { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ #if 1 /* [PR] avoid C++-style comment; older C compilers choke on it */ num_to_alloc = 2; /* also changed to match the comment... */ #else num_to_alloc = 1; // After all that talk, this was set to 1 anyways... #endif (yy_buffer_stack) = (struct yy_buffer_state**) yyalloc(num_to_alloc * sizeof(struct yy_buffer_state*) ); if (!(yy_buffer_stack)) YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()"); (void) memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1) { /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**) yyrealloc((yy_buffer_stack),num_to_alloc * sizeof(struct yy_buffer_state*) ); if (!(yy_buffer_stack)) YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()"); /* zero only the new slots.*/ (void) memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified * character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (base,size ) char * base; yy_size_t size; { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() * will scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yystr ) yyconst char * yystr; { return yy_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to * yylex() will scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a * bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yybytes,_yybytes_len ) yyconst char * yybytes; yy_size_t _yybytes_len; { YY_BUFFER_STATE b; char *buf; yy_size_t n; yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (msg ) yyconst char* msg; { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg); \ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno () { return yylineno; } /** Get the input stream. * */ FILE *yyget_in () { return yyin; } /** Get the output stream. * */ FILE *yyget_out () { return yyout; } /** Get the length of the current token. * */ yy_size_t yyget_leng () { return yyleng; } /** Get the current token. * */ char *yyget_text () { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (_line_number ) int _line_number; { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (_in_str ) FILE * _in_str; { yyin = _in_str ; } void yyset_out (_out_str ) FILE * _out_str; { yyout = _out_str ; } int yyget_debug () { return yy_flex_debug; } void yyset_debug (_bdebug ) int _bdebug; { yy_flex_debug = _bdebug ; } static int yy_init_globals () { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy () { /* Pop the buffer stack, destroying each element. */ while (YY_CURRENT_BUFFER) { yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner * so the next time yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (s1,s2,n ) char* s1; yyconst char * s2; int n; { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (s ) yyconst char * s; { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (size ) yy_size_t size; { return (void *) malloc( size ); } void *yyrealloc (ptr,size ) void * ptr; yy_size_t size; { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (ptr ) void * ptr; { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #ifdef AMIGA long * alloc(n) unsigned n; { return (long *) malloc(n); } #endif /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; if (!orig_yyin) orig_yyin = yyin; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } long handle_varstring_check() { struct lc_vardefs *vd; yylval.map = dupstr(yytext); if ((vd = vardef_defined(variable_definitions, yytext, 1)) != 0) { long l = vd->var_type; int a = ((l & SPOVAR_ARRAY) == SPOVAR_ARRAY); l &= ~SPOVAR_ARRAY; if (l == SPOVAR_INT) return (a ? VARSTRING_INT_ARRAY : VARSTRING_INT); if (l == SPOVAR_STRING) return (a ? VARSTRING_STRING_ARRAY : VARSTRING_STRING); if (l == SPOVAR_VARIABLE) return (a ? VARSTRING_VAR_ARRAY : VARSTRING_VAR); if (l == SPOVAR_COORD) return (a ? VARSTRING_COORD_ARRAY : VARSTRING_COORD); if (l == SPOVAR_REGION) return (a ? VARSTRING_REGION_ARRAY : VARSTRING_REGION); if (l == SPOVAR_MAPCHAR) return (a ? VARSTRING_MAPCHAR_ARRAY : VARSTRING_MAPCHAR); if (l == SPOVAR_MONST) return (a ? VARSTRING_MONST_ARRAY : VARSTRING_MONST); if (l == SPOVAR_OBJ) return (a ? VARSTRING_OBJ_ARRAY : VARSTRING_OBJ); if (l == SPOVAR_SEL) return (a ? VARSTRING_SEL_ARRAY : VARSTRING_SEL); } return VARSTRING; } void newline() { nh_line_number++; token_start_pos = 0; (void) memset((genericptr_t) curr_token, 0, 512); } void savetoken(s) char *s; { Sprintf(curr_token, "%s", s); advancepos(s); } void advancepos(s) char *s; { token_start_pos += strlen(s); } /*lev_comp.l*/ nethack-3.6.0/sys/share/lev_yacc.c0000664000076400007660000055263112631241231016015 0ustar paxedpaxed#ifndef lint /* static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; */ /* static char nhsccsid[] = "@(#)yaccpar 1.9.0-nh (NetHack) 12/03/2015"; */ #endif #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 #define YYSUBMINOR "0-nh" #define yyclearin (yychar=(-1)) #define yyerrok (yyerrflag=0) #define YYRECOVERING (yyerrflag!=0) #define YYPREFIX "yy" /* NetHack 3.6 lev_comp.y $NHDT-Date: 1449233826 2015/12/04 12:57:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Level Compiler code * It may handle special mazes & special room-levels */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) */ #include "hack.h" #include "sp_lev.h" #define ERR (-1) /* many types of things are put in chars for transference to NetHack. * since some systems will use signed chars, limit everybody to the * same number for portability. */ #define MAX_OF_TYPE 128 #define MAX_NESTED_IFS 20 #define MAX_SWITCH_CASES 20 #define New(type) \ (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type)) #define NewTab(type, size) (type **) alloc(sizeof(type *) * size) #define Free(ptr) free((genericptr_t)ptr) extern void VDECL(lc_error, (const char *, ...)); extern void VDECL(lc_warning, (const char *, ...)); extern void FDECL(yyerror, (const char *)); extern void FDECL(yywarning, (const char *)); extern int NDECL(yylex); int NDECL(yyparse); extern int FDECL(get_floor_type, (CHAR_P)); extern int FDECL(get_room_type, (char *)); extern int FDECL(get_trap_type, (char *)); extern int FDECL(get_monster_id, (char *,CHAR_P)); extern int FDECL(get_object_id, (char *,CHAR_P)); extern boolean FDECL(check_monster_char, (CHAR_P)); extern boolean FDECL(check_object_char, (CHAR_P)); extern char FDECL(what_map_char, (CHAR_P)); extern void FDECL(scan_map, (char *, sp_lev *)); extern void FDECL(add_opcode, (sp_lev *, int, genericptr_t)); extern genericptr_t FDECL(get_last_opcode_data1, (sp_lev *, int)); extern genericptr_t FDECL(get_last_opcode_data2, (sp_lev *, int,int)); extern boolean FDECL(check_subrooms, (sp_lev *)); extern boolean FDECL(write_level_file, (char *,sp_lev *)); extern struct opvar *FDECL(set_opvar_int, (struct opvar *, long)); extern void VDECL(add_opvars, (sp_lev *, const char *, ...)); extern void FDECL(start_level_def, (sp_lev * *, char *)); extern struct lc_funcdefs *FDECL(funcdef_new,(long,char *)); extern void FDECL(funcdef_free_all,(struct lc_funcdefs *)); extern struct lc_funcdefs *FDECL(funcdef_defined,(struct lc_funcdefs *,char *, int)); extern char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *)); extern char *FDECL(decode_parm_str, (char *)); extern struct lc_vardefs *FDECL(vardef_new,(long,char *)); extern void FDECL(vardef_free_all,(struct lc_vardefs *)); extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int)); extern void NDECL(break_stmt_start); extern void FDECL(break_stmt_end, (sp_lev *)); extern void FDECL(break_stmt_new, (sp_lev *, long)); extern void FDECL(splev_add_from, (sp_lev *, sp_lev *)); extern void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long)); extern void FDECL(vardef_used, (struct lc_vardefs *, char *)); extern struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *, char *, long)); extern int FDECL(reverse_jmp_opcode, (int)); struct coord { long x; long y; }; struct forloopdef { char *varname; long jmp_point; }; static struct forloopdef forloop_list[MAX_NESTED_IFS]; static short n_forloops = 0; sp_lev *splev = NULL; static struct opvar *if_list[MAX_NESTED_IFS]; static short n_if_list = 0; unsigned int max_x_map, max_y_map; int obj_containment = 0; int in_container_obj = 0; /* integer value is possibly an inconstant value (eg. dice notation or a variable) */ int is_inconstant_number = 0; int in_switch_statement = 0; static struct opvar *switch_check_jump = NULL; static struct opvar *switch_default_case = NULL; static struct opvar *switch_case_list[MAX_SWITCH_CASES]; static long switch_case_value[MAX_SWITCH_CASES]; int n_switch_case_list = 0; int allow_break_statements = 0; struct lc_breakdef *break_list = NULL; extern struct lc_vardefs *variable_definitions; struct lc_vardefs *function_tmp_var_defs = NULL; extern struct lc_funcdefs *function_definitions; struct lc_funcdefs *curr_function = NULL; struct lc_funcdefs_parm * curr_function_param = NULL; int in_function_definition = 0; sp_lev *function_splev_backup = NULL; extern int fatal_error; extern int got_errors; extern int line_number; extern const char *fname; extern char curr_token[512]; typedef union { long i; char* map; struct { long room; long wall; long door; } corpos; struct { long area; long x1; long y1; long x2; long y2; } lregn; struct { long x; long y; } crd; struct { long ter; long lit; } terr; struct { long height; long width; } sze; struct { long die; long num; } dice; struct { long cfunc; char *varstr; } meth; } YYSTYPE; #define CHAR 257 #define INTEGER 258 #define BOOLEAN 259 #define PERCENT 260 #define SPERCENT 261 #define MINUS_INTEGER 262 #define PLUS_INTEGER 263 #define MAZE_GRID_ID 264 #define SOLID_FILL_ID 265 #define MINES_ID 266 #define ROGUELEV_ID 267 #define MESSAGE_ID 268 #define MAZE_ID 269 #define LEVEL_ID 270 #define LEV_INIT_ID 271 #define GEOMETRY_ID 272 #define NOMAP_ID 273 #define OBJECT_ID 274 #define COBJECT_ID 275 #define MONSTER_ID 276 #define TRAP_ID 277 #define DOOR_ID 278 #define DRAWBRIDGE_ID 279 #define object_ID 280 #define monster_ID 281 #define terrain_ID 282 #define MAZEWALK_ID 283 #define WALLIFY_ID 284 #define REGION_ID 285 #define FILLING 286 #define IRREGULAR 287 #define JOINED 288 #define ALTAR_ID 289 #define LADDER_ID 290 #define STAIR_ID 291 #define NON_DIGGABLE_ID 292 #define NON_PASSWALL_ID 293 #define ROOM_ID 294 #define PORTAL_ID 295 #define TELEPRT_ID 296 #define BRANCH_ID 297 #define LEV 298 #define MINERALIZE_ID 299 #define CORRIDOR_ID 300 #define GOLD_ID 301 #define ENGRAVING_ID 302 #define FOUNTAIN_ID 303 #define POOL_ID 304 #define SINK_ID 305 #define NONE 306 #define RAND_CORRIDOR_ID 307 #define DOOR_STATE 308 #define LIGHT_STATE 309 #define CURSE_TYPE 310 #define ENGRAVING_TYPE 311 #define DIRECTION 312 #define RANDOM_TYPE 313 #define RANDOM_TYPE_BRACKET 314 #define A_REGISTER 315 #define ALIGNMENT 316 #define LEFT_OR_RIGHT 317 #define CENTER 318 #define TOP_OR_BOT 319 #define ALTAR_TYPE 320 #define UP_OR_DOWN 321 #define SUBROOM_ID 322 #define NAME_ID 323 #define FLAGS_ID 324 #define FLAG_TYPE 325 #define MON_ATTITUDE 326 #define MON_ALERTNESS 327 #define MON_APPEARANCE 328 #define ROOMDOOR_ID 329 #define IF_ID 330 #define ELSE_ID 331 #define TERRAIN_ID 332 #define HORIZ_OR_VERT 333 #define REPLACE_TERRAIN_ID 334 #define EXIT_ID 335 #define SHUFFLE_ID 336 #define QUANTITY_ID 337 #define BURIED_ID 338 #define LOOP_ID 339 #define FOR_ID 340 #define TO_ID 341 #define SWITCH_ID 342 #define CASE_ID 343 #define BREAK_ID 344 #define DEFAULT_ID 345 #define ERODED_ID 346 #define TRAPPED_STATE 347 #define RECHARGED_ID 348 #define INVIS_ID 349 #define GREASED_ID 350 #define FEMALE_ID 351 #define CANCELLED_ID 352 #define REVIVED_ID 353 #define AVENGE_ID 354 #define FLEEING_ID 355 #define BLINDED_ID 356 #define PARALYZED_ID 357 #define STUNNED_ID 358 #define CONFUSED_ID 359 #define SEENTRAPS_ID 360 #define ALL_ID 361 #define MONTYPE_ID 362 #define GRAVE_ID 363 #define ERODEPROOF_ID 364 #define FUNCTION_ID 365 #define MSG_OUTPUT_TYPE 366 #define COMPARE_TYPE 367 #define UNKNOWN_TYPE 368 #define rect_ID 369 #define fillrect_ID 370 #define line_ID 371 #define randline_ID 372 #define grow_ID 373 #define selection_ID 374 #define flood_ID 375 #define rndcoord_ID 376 #define circle_ID 377 #define ellipse_ID 378 #define filter_ID 379 #define complement_ID 380 #define gradient_ID 381 #define GRADIENT_TYPE 382 #define LIMITED 383 #define HUMIDITY_TYPE 384 #define STRING 385 #define MAP_ID 386 #define NQSTRING 387 #define VARSTRING 388 #define CFUNC 389 #define CFUNC_INT 390 #define CFUNC_STR 391 #define CFUNC_COORD 392 #define CFUNC_REGION 393 #define VARSTRING_INT 394 #define VARSTRING_INT_ARRAY 395 #define VARSTRING_STRING 396 #define VARSTRING_STRING_ARRAY 397 #define VARSTRING_VAR 398 #define VARSTRING_VAR_ARRAY 399 #define VARSTRING_COORD 400 #define VARSTRING_COORD_ARRAY 401 #define VARSTRING_REGION 402 #define VARSTRING_REGION_ARRAY 403 #define VARSTRING_MAPCHAR 404 #define VARSTRING_MAPCHAR_ARRAY 405 #define VARSTRING_MONST 406 #define VARSTRING_MONST_ARRAY 407 #define VARSTRING_OBJ 408 #define VARSTRING_OBJ_ARRAY 409 #define VARSTRING_SEL 410 #define VARSTRING_SEL_ARRAY 411 #define METHOD_INT 412 #define METHOD_INT_ARRAY 413 #define METHOD_STRING 414 #define METHOD_STRING_ARRAY 415 #define METHOD_VAR 416 #define METHOD_VAR_ARRAY 417 #define METHOD_COORD 418 #define METHOD_COORD_ARRAY 419 #define METHOD_REGION 420 #define METHOD_REGION_ARRAY 421 #define METHOD_MAPCHAR 422 #define METHOD_MAPCHAR_ARRAY 423 #define METHOD_MONST 424 #define METHOD_MONST_ARRAY 425 #define METHOD_OBJ 426 #define METHOD_OBJ_ARRAY 427 #define METHOD_SEL 428 #define METHOD_SEL_ARRAY 429 #define DICE 430 #define YYERRCODE 256 short yylhs[] = { -1, 0, 0, 73, 73, 74, 57, 57, 56, 56, 76, 76, 76, 76, 55, 55, 54, 54, 46, 46, 14, 14, 75, 75, 26, 26, 22, 22, 23, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 58, 58, 58, 58, 58, 58, 60, 60, 60, 61, 61, 85, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 38, 38, 44, 44, 43, 43, 42, 42, 41, 41, 39, 39, 40, 40, 129, 130, 100, 101, 98, 45, 45, 31, 31, 31, 131, 133, 93, 134, 134, 136, 135, 137, 135, 99, 138, 138, 139, 140, 94, 141, 95, 142, 97, 144, 96, 143, 145, 143, 79, 110, 110, 110, 83, 83, 65, 146, 147, 113, 148, 112, 10, 10, 68, 68, 69, 69, 70, 70, 71, 71, 87, 87, 15, 15, 13, 13, 16, 16, 11, 11, 103, 103, 103, 1, 1, 2, 2, 105, 150, 105, 149, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 35, 35, 35, 106, 152, 106, 151, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 120, 88, 104, 104, 121, 121, 102, 117, 118, 109, 119, 82, 17, 17, 91, 114, 108, 72, 72, 116, 115, 86, 107, 154, 111, 24, 24, 80, 81, 81, 81, 92, 89, 90, 90, 3, 3, 4, 4, 29, 29, 28, 28, 27, 27, 27, 5, 5, 6, 6, 7, 7, 7, 12, 12, 12, 8, 8, 9, 155, 155, 155, 132, 77, 77, 77, 77, 32, 32, 32, 30, 30, 127, 127, 127, 33, 124, 124, 124, 34, 34, 125, 125, 125, 36, 36, 36, 36, 126, 126, 126, 37, 37, 37, 37, 123, 123, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 50, 50, 157, 158, 158, 128, 128, 64, 64, 63, 63, 62, 62, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 48, 48, 156, 47, 47, 47, 153, 153, 153, 153, 51, 51, 52, 52, 53, 53, 25, 25, 67, 67, 66, }; short yylen[] = { 2, 0, 1, 1, 2, 3, 3, 5, 1, 1, 5, 5, 3, 16, 0, 2, 0, 2, 0, 2, 1, 1, 0, 3, 3, 1, 0, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 5, 3, 5, 5, 5, 3, 3, 5, 5, 5, 7, 7, 7, 5, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 0, 0, 8, 4, 1, 0, 1, 1, 5, 3, 0, 0, 9, 0, 2, 0, 5, 0, 4, 1, 2, 1, 6, 0, 3, 0, 6, 0, 4, 0, 4, 1, 0, 4, 3, 1, 3, 3, 5, 5, 7, 4, 0, 10, 0, 12, 0, 2, 5, 1, 5, 1, 5, 1, 5, 1, 9, 5, 1, 1, 1, 1, 1, 3, 1, 1, 1, 7, 5, 1, 1, 1, 1, 3, 0, 5, 4, 0, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1, 3, 1, 1, 3, 3, 0, 5, 2, 0, 3, 1, 3, 1, 3, 3, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 5, 7, 5, 8, 1, 3, 5, 5, 7, 7, 6, 5, 0, 2, 3, 3, 3, 1, 5, 9, 5, 3, 3, 0, 10, 0, 1, 7, 5, 5, 3, 5, 7, 9, 1, 1, 1, 1, 1, 0, 2, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 4, 5, 1, 3, 1, 3, 1, 1, 4, 9, 1, 1, 4, 1, 5, 1, 1, 4, 1, 1, 5, 1, 1, 1, 4, 1, 1, 5, 1, 1, 3, 1, 1, 3, 1, 4, 3, 3, 3, 3, 3, 3, 1, 1, 3, 1, 3, 0, 1, 1, 1, 1, 3, 0, 1, 1, 2, 2, 4, 6, 4, 6, 6, 6, 6, 2, 6, 8, 8, 10, 14, 2, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, 9, }; short yydefred[] = { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 4, 0, 6, 0, 133, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 136, 145, 0, 0, 0, 0, 93, 82, 73, 83, 74, 84, 75, 85, 76, 86, 77, 87, 78, 88, 79, 89, 80, 90, 81, 5, 0, 92, 91, 0, 30, 0, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 149, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 94, 95, 0, 0, 0, 0, 342, 0, 345, 0, 387, 0, 343, 0, 153, 0, 27, 0, 9, 8, 7, 0, 304, 305, 0, 0, 340, 0, 0, 0, 12, 313, 0, 195, 196, 0, 0, 310, 0, 0, 308, 0, 337, 339, 0, 336, 334, 0, 333, 228, 224, 225, 330, 332, 0, 329, 327, 0, 326, 0, 0, 281, 280, 0, 291, 292, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 383, 250, 0, 366, 0, 318, 0, 317, 0, 0, 0, 0, 0, 403, 0, 0, 266, 267, 283, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 261, 260, 390, 388, 389, 163, 162, 0, 184, 185, 0, 0, 0, 0, 96, 0, 0, 0, 0, 126, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 362, 0, 0, 0, 396, 398, 395, 397, 399, 400, 0, 0, 0, 0, 0, 0, 103, 0, 0, 104, 0, 150, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367, 368, 0, 0, 0, 376, 0, 0, 0, 382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 151, 0, 0, 0, 0, 344, 352, 0, 0, 0, 0, 349, 350, 351, 129, 0, 154, 0, 0, 120, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 341, 11, 262, 0, 10, 0, 0, 314, 0, 0, 0, 198, 197, 0, 173, 194, 0, 0, 0, 226, 0, 0, 203, 201, 245, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 324, 0, 0, 322, 0, 321, 0, 0, 0, 384, 386, 0, 0, 293, 294, 0, 297, 0, 295, 0, 296, 251, 0, 0, 0, 252, 0, 175, 0, 0, 0, 0, 0, 256, 0, 0, 165, 164, 276, 401, 402, 0, 177, 0, 0, 0, 0, 0, 265, 0, 0, 147, 0, 0, 137, 274, 0, 0, 0, 356, 0, 346, 134, 363, 98, 0, 0, 105, 0, 111, 0, 106, 0, 107, 0, 102, 0, 101, 0, 100, 28, 306, 0, 0, 316, 309, 0, 311, 0, 0, 335, 393, 391, 392, 239, 236, 230, 0, 0, 235, 0, 240, 0, 242, 243, 0, 238, 229, 244, 232, 394, 0, 328, 0, 0, 0, 369, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 152, 146, 0, 0, 0, 127, 0, 0, 0, 0, 121, 119, 112, 0, 114, 0, 116, 0, 0, 0, 312, 193, 338, 0, 0, 0, 0, 0, 331, 0, 246, 0, 0, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 302, 301, 272, 0, 0, 253, 0, 179, 0, 0, 254, 258, 0, 0, 0, 0, 181, 0, 0, 187, 0, 186, 159, 0, 0, 353, 354, 355, 0, 357, 0, 110, 0, 109, 0, 108, 0, 0, 0, 234, 237, 241, 231, 0, 298, 206, 207, 0, 211, 210, 212, 213, 214, 0, 0, 0, 218, 219, 0, 299, 208, 204, 0, 0, 248, 0, 372, 0, 377, 0, 373, 0, 323, 374, 375, 0, 0, 0, 268, 303, 0, 0, 0, 0, 0, 0, 190, 191, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 128, 113, 115, 117, 263, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 325, 0, 0, 288, 289, 290, 0, 285, 0, 0, 0, 174, 0, 0, 278, 166, 176, 0, 0, 182, 264, 0, 143, 138, 140, 0, 300, 215, 216, 217, 222, 0, 220, 378, 0, 379, 0, 0, 0, 271, 269, 0, 0, 0, 170, 0, 169, 141, 0, 0, 0, 0, 0, 0, 320, 287, 0, 405, 178, 0, 180, 0, 144, 0, 223, 380, 15, 0, 404, 171, 142, 0, 0, 0, 0, 20, 21, 0, 0, 0, 13, 17, 381, }; short yydgoto[] = { 3, 209, 449, 233, 271, 236, 486, 490, 671, 491, 351, 757, 729, 689, 859, 294, 467, 614, 354, 578, 584, 730, 80, 337, 822, 512, 133, 788, 789, 747, 345, 81, 210, 258, 476, 814, 228, 218, 636, 425, 426, 427, 428, 640, 638, 387, 733, 290, 375, 253, 696, 329, 330, 331, 861, 835, 190, 4, 82, 83, 84, 172, 314, 315, 316, 280, 264, 265, 500, 515, 678, 687, 440, 5, 6, 10, 85, 254, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 277, 318, 478, 229, 219, 259, 529, 408, 697, 173, 278, 626, 765, 766, 843, 830, 524, 130, 187, 521, 319, 401, 295, 517, 272, 800, 841, 230, 359, 220, 355, 580, 790, 196, 182, 530, 531, }; short yysindex[] = { 68, 17, 31, 0, -217, 0, 68, -257, -226, 112, 5680, 0, 136, 0, -136, 0, 170, 185, 201, 0, 225, 229, 238, 244, 248, 251, 255, 266, 272, 275, 283, 304, 309, 346, 366, 378, 380, 382, 383, 396, 397, 398, 400, 401, 404, 405, 413, 415, -46, 417, 420, 0, 426, 108, 489, 0, 0, 428, 101, -35, 449, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, 0, 0, 430, 0, 5680, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -190, 450, 0, -234, 62, -13, 41, 41, 40, -252, -121, 109, 109, 1644, -34, 109, 109, 92, -34, -34, -249, -20, -20, -20, -35, 458, -35, 109, 1644, 1644, 1644, -160, -249, -174, 0, 1644, -34, 288, -35, 0, 0, 439, 414, 109, 467, 0, -22, 0, 421, 0, -9, 0, -14, 0, 163, 0, 385, 0, 0, 0, -136, 0, 0, 423, 465, 0, 471, 473, 475, 0, 0, 137, 0, 0, 490, 271, 0, 441, 496, 0, 503, 0, 0, 276, 0, 0, 452, 0, 0, 0, 0, 0, 0, 292, 0, 0, 470, 0, 512, 0, 0, 0, 518, 0, 0, 523, 524, 526, -34, -34, 109, 109, 540, 109, 542, 544, 545, 1644, 548, 5537, 0, 0, 533, 0, 331, 0, 500, 0, 555, 558, 559, 564, 347, 0, 571, 582, 0, 0, 0, 0, 367, 584, 379, 592, 594, 595, 141, 596, 402, 597, 588, 611, 0, 0, 0, 0, 0, 0, 0, 0, 617, 0, 0, 628, 385, 638, 640, 0, 593, -35, -35, 644, 0, 649, 159, -35, -35, 0, -35, -35, -35, -35, -35, 651, 650, 0, 141, 465, 5680, 0, 0, 0, 0, 0, 0, 642, -1, 4, 643, 647, 653, 0, 141, 465, 0, 5680, 0, 0, -35, -234, 445, 14, 455, 654, 614, 1644, 678, -35, 38, 476, 338, 682, -35, 688, 385, 690, -35, 109, 385, 109, 1644, 424, 431, 0, 0, 694, 696, 1298, 0, 109, 109, 5435, 0, 360, 704, 1644, 702, -35, -165, -83, 429, 491, 703, -20, 433, 0, 707, -24, 708, -20, -20, -20, -35, 709, 10, 109, -91, -19, -121, 0, 0, 9, 9, 0, 45, 655, -254, 560, 0, 0, 75, 148, 79, 79, 0, 0, 0, 0, -14, 0, 1644, 711, 0, 0, 16, 25, 27, 29, 141, 465, 22, -10, -28, 631, 427, 0, 0, 0, 501, 0, 715, 137, 0, 719, 505, 459, 0, 0, 503, 0, 0, 381, 499, 2, 0, 403, 508, 0, 0, 0, 0, 721, 723, 109, 109, 662, 743, 748, 746, 749, 0, 750, 5448, 0, 701, 0, 751, 752, 753, 0, 0, 554, 536, 0, 0, 754, 0, 726, 0, 774, 0, 0, 775, 579, 785, 0, -165, 0, 581, 796, 583, 798, 800, 0, 802, 535, 0, 0, 0, 0, 0, 804, 0, 591, 806, 807, 521, 598, 0, 810, 385, 0, 811, -35, 0, 0, 465, 801, 815, 0, 814, 0, 0, 0, 0, 604, -35, 0, -234, 0, -21, 0, 824, 0, 57, 0, 98, 0, 23, 0, 0, 0, 825, 621, 0, 0, 827, 0, 493, 839, 0, 0, 0, 0, 0, 0, 0, 823, 826, 0, 828, 0, 830, 0, 0, 832, 0, 0, 0, 0, 0, 841, 0, 848, -121, 641, 0, 857, 590, 1644, 0, -35, -35, 1644, 859, -35, 1644, 1644, 864, 861, 0, -249, 648, -148, 652, 135, 586, 0, 867, -5, 868, 528, 587, 0, -35, 870, -234, 871, 6, 72, 385, 9, 0, 0, 141, 793, 1, 0, 560, 166, 141, 465, 0, 0, 0, 32, 0, 33, 0, 35, -165, 873, 0, 0, 0, -234, -35, -35, -35, 40, 0, 5526, 0, 876, -35, 0, 880, 174, 686, 881, -165, 569, 882, 883, -35, 685, 900, 852, 0, 0, 0, 902, 691, 0, 693, 0, 110, 908, 0, 0, 928, -184, 465, 716, 0, 717, 900, 0, 929, 0, 0, 932, 90, 0, 0, 0, 385, 0, 57, 0, 98, 0, 23, 0, 936, 722, 465, 0, 0, 0, 0, 56, 0, 0, 0, -234, 0, 0, 0, 0, 0, 920, 921, 924, 0, 0, 925, 0, 0, 0, 465, 727, 0, 141, 0, 699, 0, -35, 0, 945, 0, 0, 0, 481, 943, 59, 0, 0, 744, 957, 965, 963, 6, -35, 0, 0, 967, 977, 982, 0, -184, 767, -50, 971, 905, 90, 0, 0, 0, 0, 0, 987, 724, 465, -35, -35, -35, -261, 0, 991, 576, 0, -35, 777, 0, 0, 0, 989, 0, 385, 992, 780, 0, 38, 900, 0, 0, 0, 781, 385, 0, 0, 983, 0, 0, 0, 784, 0, 0, 0, 0, 0, 916, 0, 0, 758, 0, 93, 1004, 59, 0, 0, 788, 1006, 1007, 0, 1010, 0, 0, 5680, 1009, -261, 1016, 675, 1020, 0, 0, 1025, 0, 0, 385, 0, 5680, 0, -165, 0, 0, 0, 1023, 0, 0, 0, 1024, 109, -149, 1026, 0, 0, 876, 109, 1028, 0, 0, 0, }; short yyrindex[] = { 1071, 0, 0, 0, 5225, 0, 1072, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2985, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3174, 0, 0, 0, 0, 0, 0, 3331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3520, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1098, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3677, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1033, 0, 241, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3866, 4023, 0, 951, 0, 0, 0, 0, 0, 0, 0, 984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2293, 0, 0, 0, 0, 0, 0, 0, 1037, 0, 0, 0, 0, 374, 531, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0, 0, 0, 0, 0, 42, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 689, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4212, 0, 0, 1035, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4558, 0, 0, 0, 1039, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 958, 0, 0, 0, 0, 0, 50, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4715, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2639, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4904, 0, 0, 0, 959, 0, 0, 0, 0, 0, 961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1444, 0, 0, 909, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 961, 0, 0, 0, 0, 0, 0, 0, 1601, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2828, 0, 5061, 0, 0, 0, 0, 959, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1790, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1043, 0, 0, 4715, 0, 0, 0, 0, 0, }; short yygindex[] = { 0, 410, 294, 0, 487, -329, -480, 0, 0, 438, 645, 330, 0, 0, 0, 0, -474, 0, 0, 0, 0, 0, -86, -287, 0, 0, 901, 0, 273, -629, 657, 1047, -296, -297, -509, 264, -504, -494, 0, 0, 0, 0, 0, 0, 0, 0, 242, -384, -137, 849, 0, 0, 0, 0, 0, 0, 0, 0, 1046, 934, -371, 0, 0, 0, 684, 710, 0, -48, 0, 0, 0, 351, 0, 1100, 0, 0, 0, -133, 790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -58, -130, -355, -375, 679, -84, 0, 0, 0, 0, -167, 0, 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949, 0, 0, 0, 0, 975, 0, 0, 0, 792, 680, 504, 0, }; #define YYTABLESIZE 6091 short yytable[] = { 186, 181, 299, 211, 195, 177, 255, 252, 400, 237, 238, 507, 518, 260, 261, 266, 499, 608, 177, 206, 273, 514, 283, 284, 285, 282, 177, 206, 313, 296, 224, 424, 423, 311, 309, 677, 310, 528, 312, 177, 639, 302, 206, 637, 327, 59, 686, 519, 520, 518, 279, 635, 332, 26, 439, 334, 26, 548, 760, 526, 537, 231, 214, 518, 269, 267, 268, 188, 455, 539, 516, 541, 459, 543, 755, 7, 699, 701, 550, 703, 224, 214, 313, 297, 308, 292, 122, 311, 309, 8, 310, 523, 312, 124, 123, 549, 125, 214, 286, 281, 812, 335, 287, 288, 274, 275, 276, 9, 366, 367, 857, 369, 313, 547, 773, 656, 313, 311, 309, 305, 310, 311, 312, 189, 813, 317, 312, 333, 12, 756, 313, 192, 263, 232, 406, 311, 270, 834, 224, 293, 312, 538, 193, 194, 484, 545, 690, 603, 485, 206, 540, 192, 542, 289, 544, 364, 365, 700, 702, 13, 704, 705, 193, 194, 858, 669, 826, 122, 532, 14, 14, 348, 670, 348, 124, 123, 643, 125, 313, 673, 131, 740, 26, 311, 309, 313, 310, 234, 312, 132, 311, 309, 235, 310, 770, 312, 313, 769, 430, 169, 410, 311, 309, 327, 310, 768, 312, 643, 286, 444, 666, 313, 287, 288, 15, 737, 311, 309, 736, 310, 510, 312, 511, 176, 461, 458, 505, 460, 134, 471, 487, 468, 488, 489, 623, 477, 176, 469, 470, 481, 304, 533, 405, 135, 176, 633, 634, 222, 411, 412, 434, 413, 414, 415, 416, 417, 653, 422, 528, 136, 562, 304, 176, 509, 563, 564, 471, 692, 286, 305, 429, 438, 287, 288, 26, 711, 26, 527, 262, 212, 471, 435, 360, 137, 535, 360, 328, 138, 361, 498, 446, 361, 201, 202, 513, 453, 139, 222, 212, 457, 201, 202, 140, 223, 203, 204, 141, 26, 676, 142, 565, 566, 567, 143, 212, 201, 202, 201, 202, 685, 483, 579, 26, 26, 144, 568, 197, 198, 199, 200, 145, 587, 588, 146, 691, 213, 495, 1, 2, 569, 570, 147, 502, 503, 504, 785, 786, 787, 571, 572, 573, 574, 575, 223, 213, 222, 447, 448, 307, 178, 179, 317, 148, 205, 576, 853, 577, 149, 256, 257, 213, 192, 178, 179, 347, 225, 474, 475, 205, 803, 178, 179, 193, 194, 466, 688, 522, 207, 208, 192, 262, 694, 695, 178, 179, 180, 226, 227, 178, 179, 193, 194, 207, 208, 150, 201, 202, 215, 180, 632, 767, 223, 347, 474, 475, 347, 180, 347, 347, 347, 347, 176, 201, 202, 151, 225, 215, 203, 204, 180, 216, 217, 180, 763, 180, 764, 152, 320, 153, 321, 154, 155, 215, 322, 323, 324, 226, 227, 681, 216, 217, 26, 26, 657, 156, 157, 158, 660, 159, 160, 663, 664, 161, 162, 313, 347, 625, 347, 205, 311, 309, 163, 310, 164, 312, 166, 201, 202, 167, 631, 708, 709, 710, 225, 168, 205, 174, 683, 175, 183, 184, 185, 207, 208, 191, 325, 313, 347, 279, 347, 300, 311, 309, 821, 310, 301, 312, 303, 336, 207, 208, 340, 306, 828, 339, 341, 707, 342, 313, 343, 552, 344, 731, 311, 309, 26, 783, 26, 312, 347, 346, 348, 348, 352, 658, 659, 313, 326, 662, 205, 349, 311, 309, 353, 310, 313, 312, 350, 192, 356, 311, 309, 558, 310, 851, 312, 358, 178, 179, 193, 194, 357, 360, 207, 208, 256, 257, 361, 362, 348, 363, 376, 348, 313, 348, 348, 348, 348, 311, 309, 368, 310, 370, 312, 371, 372, 774, 796, 374, 377, 342, 378, 561, 180, 342, 342, 342, 734, 342, 379, 342, 583, 380, 381, 382, 383, 313, 744, 809, 810, 811, 311, 309, 313, 310, 384, 312, 817, 311, 309, 816, 310, 348, 312, 348, 313, 385, 386, 388, 601, 311, 309, 396, 310, 347, 312, 390, 389, 391, 392, 393, 395, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 348, 397, 348, 347, 347, 347, 394, 398, 741, 347, 347, 347, 347, 347, 347, 347, 347, 347, 399, 347, 347, 347, 347, 347, 347, 347, 781, 347, 402, 63, 403, 65, 404, 67, 407, 69, 409, 71, 418, 73, 419, 75, 347, 77, 442, 79, 421, 431, 437, 347, 347, 432, 347, 443, 347, 347, 347, 433, 441, 347, 347, 347, 347, 347, 347, 347, 307, 856, 445, 313, 451, 818, 452, 863, 311, 309, 738, 310, 454, 312, 456, 450, 462, 347, 464, 347, 465, 347, 479, 463, 844, 480, 482, 494, 525, 493, 492, 497, 501, 506, 496, 536, 551, 852, 553, 554, 556, 347, 347, 557, 307, 585, 560, 586, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 589, 590, 582, 591, 592, 348, 596, 593, 594, 597, 598, 599, 602, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 307, 600, 307, 348, 348, 348, 603, 604, 605, 348, 348, 348, 348, 348, 348, 348, 348, 348, 607, 348, 348, 348, 348, 348, 348, 348, 606, 348, 609, 610, 611, 612, 307, 613, 307, 615, 616, 617, 618, 619, 620, 621, 348, 622, 595, 628, 624, 629, 627, 348, 348, 630, 348, 255, 348, 348, 348, 643, 641, 348, 348, 348, 348, 348, 348, 348, 170, 642, 644, 645, 646, 651, 62, 647, 64, 648, 66, 649, 68, 650, 70, 652, 72, 348, 74, 348, 76, 348, 78, 654, 655, 466, 661, 665, 666, 668, 674, 680, 370, 672, 675, 673, 679, 682, 684, 693, 706, 348, 348, 732, 735, 739, 742, 743, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 745, 746, 748, 749, 370, 61, 750, 370, 751, 753, 370, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 754, 761, 758, 759, 762, 771, 775, 776, 307, 772, 777, 778, 779, 780, 782, 784, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 370, 792, 791, 307, 307, 307, 793, 794, 797, 307, 307, 307, 307, 307, 307, 307, 307, 307, 798, 307, 307, 307, 307, 307, 307, 307, 799, 307, 802, 804, 805, 807, 815, 820, 370, 819, 823, 808, 824, 827, 832, 829, 307, 831, 833, 836, 838, 839, 840, 307, 307, 842, 307, 845, 307, 307, 307, 847, 848, 307, 307, 849, 307, 307, 307, 307, 850, 854, 855, 864, 860, 1, 3, 364, 365, 172, 26, 315, 358, 188, 359, 148, 284, 307, 16, 307, 139, 752, 825, 667, 728, 801, 338, 837, 559, 165, 846, 373, 385, 555, 171, 862, 298, 534, 795, 508, 11, 307, 307, 420, 546, 806, 291, 221, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 436, 698, 581, 0, 0, 0, 0, 385, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370, 0, 0, 0, 0, 0, 0, 0, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 385, 0, 0, 370, 370, 370, 0, 0, 0, 370, 370, 370, 370, 370, 370, 370, 370, 370, 0, 370, 370, 370, 370, 370, 370, 370, 0, 370, 0, 0, 0, 0, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0, 370, 0, 0, 0, 0, 0, 0, 370, 370, 0, 370, 0, 370, 370, 370, 0, 0, 370, 370, 0, 370, 370, 370, 370, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370, 0, 370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370, 370, 0, 233, 0, 0, 0, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385, 0, 0, 0, 0, 0, 0, 0, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 233, 0, 233, 385, 385, 385, 0, 0, 0, 385, 385, 385, 385, 385, 385, 385, 385, 385, 0, 385, 385, 385, 385, 385, 385, 385, 0, 385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385, 0, 0, 0, 0, 0, 0, 385, 385, 0, 385, 0, 385, 385, 385, 0, 0, 385, 385, 0, 385, 385, 385, 385, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385, 0, 385, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385, 385, 0, 205, 0, 0, 0, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 205, 0, 0, 233, 233, 233, 0, 0, 0, 233, 233, 233, 233, 233, 233, 233, 233, 233, 0, 233, 233, 233, 233, 233, 233, 233, 0, 233, 0, 0, 0, 0, 205, 0, 205, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 233, 233, 0, 233, 0, 233, 233, 233, 0, 0, 233, 233, 0, 233, 233, 233, 233, 209, 0, 0, 0, 0, 0, 0, 0, 0, 466, 201, 202, 0, 0, 0, 0, 0, 233, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, 0, 209, 0, 0, 0, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 239, 240, 241, 242, 243, 0, 244, 205, 245, 246, 247, 248, 249, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 207, 208, 0, 0, 0, 0, 205, 0, 0, 0, 251, 0, 0, 0, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 209, 0, 209, 205, 205, 205, 0, 0, 0, 205, 205, 205, 205, 205, 205, 205, 205, 205, 0, 205, 205, 205, 205, 205, 205, 205, 0, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, 0, 0, 0, 0, 205, 205, 0, 205, 0, 205, 205, 205, 0, 0, 205, 205, 0, 205, 205, 205, 205, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 205, 0, 221, 0, 0, 0, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 221, 0, 0, 209, 209, 209, 0, 0, 0, 209, 209, 209, 209, 209, 209, 209, 209, 209, 0, 209, 209, 209, 209, 209, 209, 209, 0, 209, 0, 0, 0, 0, 221, 0, 221, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 209, 209, 0, 209, 0, 209, 209, 209, 0, 0, 209, 209, 0, 209, 209, 209, 209, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 202, 0, 0, 0, 0, 0, 209, 0, 209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 209, 0, 0, 0, 0, 0, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 239, 240, 241, 242, 243, 0, 244, 205, 245, 246, 247, 248, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 207, 208, 0, 0, 0, 0, 221, 0, 0, 0, 251, 0, 0, 0, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 200, 0, 199, 221, 221, 221, 0, 0, 0, 221, 221, 221, 221, 221, 221, 221, 221, 221, 0, 221, 221, 221, 221, 221, 221, 221, 0, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 0, 0, 0, 221, 221, 0, 221, 0, 221, 221, 221, 0, 0, 221, 221, 0, 221, 221, 221, 221, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 0, 0, 0, 0, 0, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 0, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 227, 0, 0, 199, 199, 199, 0, 0, 0, 199, 199, 199, 199, 199, 199, 199, 199, 199, 0, 199, 199, 199, 199, 199, 199, 199, 0, 199, 0, 0, 0, 0, 227, 0, 227, 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 199, 199, 0, 199, 0, 199, 199, 199, 0, 0, 199, 199, 0, 199, 199, 199, 199, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 199, 0, 0, 0, 0, 0, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 0, 0, 0, 0, 0, 0, 0, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 0, 0, 157, 227, 227, 227, 0, 0, 0, 227, 227, 227, 227, 227, 227, 227, 227, 227, 0, 227, 227, 227, 227, 227, 227, 227, 0, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 0, 0, 0, 0, 0, 0, 227, 227, 0, 227, 0, 227, 227, 227, 0, 0, 227, 227, 0, 227, 227, 227, 227, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 0, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 227, 0, 0, 0, 0, 0, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 0, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 202, 0, 0, 157, 157, 157, 0, 0, 0, 157, 157, 157, 157, 157, 157, 157, 157, 157, 0, 157, 157, 157, 157, 157, 157, 157, 0, 157, 0, 0, 0, 0, 202, 0, 202, 0, 0, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 0, 157, 157, 158, 157, 0, 157, 157, 157, 0, 0, 157, 157, 0, 157, 157, 157, 157, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 0, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 157, 0, 0, 0, 0, 0, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 0, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 284, 0, 284, 202, 202, 202, 0, 0, 0, 202, 202, 202, 202, 202, 202, 202, 202, 202, 0, 202, 202, 202, 202, 202, 202, 202, 0, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 202, 202, 0, 202, 0, 202, 202, 202, 0, 0, 202, 202, 0, 202, 202, 202, 202, 286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 0, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 202, 202, 0, 0, 0, 0, 0, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 286, 0, 0, 284, 284, 284, 0, 0, 0, 284, 284, 284, 284, 284, 284, 284, 284, 284, 0, 284, 284, 284, 284, 284, 284, 284, 0, 284, 0, 0, 0, 0, 286, 0, 286, 0, 0, 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 284, 284, 0, 284, 0, 284, 284, 284, 0, 0, 284, 284, 0, 284, 284, 284, 284, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 284, 0, 0, 0, 0, 0, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286, 0, 0, 0, 0, 0, 0, 0, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 0, 0, 249, 286, 286, 286, 0, 0, 0, 286, 286, 286, 286, 286, 286, 286, 286, 286, 0, 286, 286, 286, 286, 286, 286, 286, 0, 286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286, 0, 0, 0, 0, 0, 0, 286, 286, 0, 286, 0, 286, 286, 286, 0, 0, 286, 286, 0, 286, 286, 286, 286, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286, 0, 286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286, 286, 0, 0, 0, 0, 0, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 279, 0, 0, 249, 249, 249, 0, 0, 0, 249, 249, 249, 249, 249, 249, 249, 249, 249, 0, 249, 249, 249, 249, 249, 249, 249, 0, 249, 0, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 249, 249, 0, 249, 0, 249, 249, 249, 0, 0, 249, 249, 0, 249, 249, 249, 249, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 249, 0, 0, 0, 0, 0, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 0, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 0, 0, 161, 279, 279, 279, 0, 0, 0, 279, 279, 279, 279, 279, 279, 279, 279, 279, 0, 279, 279, 279, 279, 279, 279, 279, 0, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 279, 279, 0, 279, 0, 279, 279, 279, 0, 0, 279, 279, 0, 279, 279, 279, 279, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 0, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 279, 0, 0, 0, 0, 0, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 160, 0, 0, 161, 161, 161, 0, 0, 0, 161, 161, 161, 161, 161, 161, 161, 161, 161, 0, 161, 161, 161, 161, 161, 161, 161, 0, 161, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 161, 161, 0, 161, 0, 161, 161, 161, 0, 0, 161, 161, 0, 161, 161, 161, 161, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 161, 0, 0, 0, 0, 0, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 0, 0, 275, 160, 160, 160, 0, 0, 0, 160, 160, 160, 160, 160, 160, 160, 160, 160, 0, 160, 160, 160, 160, 160, 160, 160, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 160, 160, 0, 160, 0, 160, 160, 160, 0, 0, 160, 160, 0, 160, 160, 160, 160, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 160, 0, 0, 0, 0, 0, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 97, 0, 0, 275, 275, 275, 0, 0, 0, 275, 275, 275, 275, 275, 275, 275, 275, 275, 0, 275, 275, 275, 275, 275, 275, 275, 0, 275, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 275, 275, 0, 275, 0, 275, 275, 275, 0, 0, 275, 275, 0, 275, 275, 275, 275, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 275, 0, 0, 0, 0, 0, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0, 0, 99, 97, 97, 97, 0, 0, 0, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0, 97, 97, 97, 97, 97, 97, 97, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 97, 97, 0, 97, 0, 97, 97, 97, 0, 0, 97, 97, 0, 97, 97, 97, 97, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 97, 0, 0, 0, 0, 0, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 247, 0, 0, 99, 99, 99, 0, 0, 0, 99, 99, 99, 99, 99, 99, 99, 99, 99, 0, 99, 99, 99, 99, 99, 99, 99, 0, 99, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 99, 99, 0, 99, 0, 99, 99, 99, 0, 0, 99, 99, 0, 99, 99, 99, 99, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 0, 0, 0, 0, 0, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 0, 0, 257, 247, 247, 247, 0, 0, 0, 247, 247, 247, 247, 247, 247, 247, 247, 247, 0, 247, 247, 247, 247, 247, 247, 247, 0, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, 247, 247, 0, 247, 0, 247, 247, 247, 0, 0, 247, 247, 0, 247, 247, 247, 247, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 0, 0, 0, 0, 0, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 273, 0, 0, 257, 257, 257, 0, 0, 0, 257, 257, 257, 257, 257, 257, 257, 257, 257, 0, 257, 257, 257, 257, 257, 257, 257, 0, 257, 0, 0, 0, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0, 257, 0, 0, 0, 0, 0, 0, 257, 257, 0, 257, 0, 257, 257, 257, 0, 0, 257, 257, 0, 257, 257, 257, 257, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 257, 0, 0, 0, 0, 0, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 0, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 0, 0, 18, 273, 273, 273, 0, 0, 0, 273, 273, 273, 273, 273, 273, 273, 273, 273, 0, 273, 273, 273, 273, 273, 273, 273, 0, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 0, 0, 0, 0, 0, 0, 273, 273, 0, 273, 0, 273, 273, 273, 0, 0, 273, 273, 0, 273, 273, 273, 273, 277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 0, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 273, 273, 0, 0, 0, 0, 0, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 277, 0, 0, 18, 18, 18, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 18, 18, 18, 18, 18, 18, 18, 0, 18, 0, 0, 0, 0, 0, 0, 277, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 18, 18, 0, 18, 0, 18, 18, 18, 0, 0, 18, 18, 0, 18, 18, 18, 18, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 277, 0, 0, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 0, 0, 270, 277, 277, 277, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, 277, 0, 277, 277, 277, 277, 277, 277, 277, 0, 277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 277, 0, 0, 0, 0, 0, 0, 277, 277, 0, 277, 0, 277, 277, 277, 0, 0, 277, 277, 0, 277, 277, 277, 277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 277, 0, 277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 277, 277, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 22, 0, 0, 0, 0, 270, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 0, 0, 0, 270, 270, 270, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270, 270, 0, 270, 270, 270, 270, 270, 270, 270, 0, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 270, 0, 0, 0, 0, 0, 0, 270, 270, 0, 270, 0, 270, 270, 270, 0, 0, 270, 270, 0, 270, 270, 270, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270, 0, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 25, 0, 473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 250, 0, 0, 0, 0, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 0, 0, 0, 22, 22, 22, 0, 0, 0, 22, 22, 22, 22, 22, 22, 22, 22, 22, 0, 22, 22, 22, 22, 22, 22, 22, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 22, 22, 0, 22, 0, 22, 22, 22, 0, 0, 22, 22, 0, 22, 0, 22, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 22, 0, 0, 0, 0, 0, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 25, 25, 25, 0, 0, 0, 25, 25, 25, 25, 25, 25, 25, 25, 25, 0, 25, 25, 25, 25, 25, 25, 25, 0, 25, 0, 0, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 25, 595, 347, 0, 0, 0, 0, 25, 25, 0, 25, 0, 25, 25, 25, 0, 0, 25, 25, 0, 25, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 25, 201, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 202, 0, 0, 0, 0, 0, 0, 25, 25, 59, 0, 0, 0, 0, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 0, 347, 0, 0, 0, 0, 0, 0, 0, 0, 239, 240, 241, 242, 243, 0, 244, 205, 245, 246, 247, 248, 249, 239, 240, 241, 242, 243, 0, 244, 205, 245, 246, 247, 248, 249, 0, 0, 0, 0, 0, 207, 208, 0, 0, 474, 475, 712, 713, 0, 0, 251, 0, 0, 207, 208, 201, 202, 714, 715, 716, 0, 0, 0, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 717, 0, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 240, 241, 242, 243, 192, 244, 205, 245, 246, 247, 248, 249, 0, 0, 0, 193, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, 208, 0, 15, 0, 0, 0, 0, 0, 0, 251, 16, 0, 0, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 26, 27, 28, 0, 0, 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, 0, 38, 39, 40, 41, 42, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47, 48, 0, 49, 0, 50, 51, 52, 0, 0, 53, 54, 0, 55, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, }; short yycheck[] = { 86, 59, 169, 136, 134, 40, 40, 144, 295, 142, 143, 395, 40, 146, 147, 148, 40, 497, 40, 40, 40, 40, 159, 160, 161, 158, 40, 40, 37, 166, 40, 328, 328, 42, 43, 40, 45, 408, 47, 40, 549, 174, 40, 547, 40, 91, 40, 402, 403, 40, 40, 545, 185, 0, 40, 185, 125, 432, 687, 313, 44, 313, 40, 40, 313, 149, 150, 257, 355, 44, 399, 44, 359, 44, 258, 58, 44, 44, 433, 44, 40, 40, 37, 167, 93, 259, 44, 42, 43, 58, 45, 46, 47, 44, 44, 123, 44, 40, 258, 157, 361, 185, 262, 263, 152, 153, 154, 324, 241, 242, 259, 244, 37, 123, 58, 589, 37, 42, 43, 177, 45, 42, 47, 313, 385, 183, 47, 185, 385, 313, 37, 385, 40, 385, 301, 42, 385, 44, 40, 313, 47, 125, 396, 397, 309, 123, 620, 91, 313, 40, 125, 385, 125, 313, 125, 239, 240, 125, 125, 385, 125, 641, 396, 397, 313, 313, 795, 125, 93, 41, 58, 43, 320, 45, 125, 125, 41, 125, 37, 44, 44, 661, 0, 42, 43, 37, 45, 308, 47, 325, 42, 43, 313, 45, 703, 47, 37, 701, 328, 91, 41, 42, 43, 40, 45, 699, 47, 41, 258, 346, 44, 37, 262, 263, 260, 41, 42, 43, 44, 45, 311, 47, 313, 258, 361, 358, 393, 360, 58, 257, 313, 368, 315, 316, 521, 372, 258, 370, 371, 376, 262, 93, 300, 58, 258, 541, 543, 257, 306, 307, 336, 309, 310, 311, 312, 313, 585, 258, 629, 58, 258, 262, 258, 396, 262, 263, 257, 622, 258, 327, 328, 257, 262, 263, 343, 650, 345, 407, 298, 257, 257, 339, 41, 58, 421, 44, 123, 58, 41, 313, 348, 44, 313, 314, 313, 353, 58, 257, 257, 357, 313, 314, 58, 313, 317, 318, 58, 125, 313, 58, 308, 309, 310, 58, 257, 313, 314, 313, 314, 313, 378, 454, 269, 270, 58, 323, 264, 265, 266, 267, 58, 464, 465, 58, 621, 313, 384, 269, 270, 337, 338, 58, 390, 391, 392, 286, 287, 288, 346, 347, 348, 349, 350, 313, 313, 257, 318, 319, 367, 394, 395, 419, 58, 376, 362, 845, 364, 58, 402, 403, 313, 385, 394, 395, 0, 385, 404, 405, 376, 763, 394, 395, 396, 397, 312, 313, 341, 400, 401, 385, 298, 390, 391, 394, 395, 430, 406, 407, 394, 395, 396, 397, 400, 401, 58, 313, 314, 385, 430, 539, 697, 313, 38, 404, 405, 41, 430, 43, 44, 45, 46, 258, 313, 314, 58, 385, 385, 317, 318, 430, 408, 409, 430, 343, 430, 345, 58, 274, 58, 276, 58, 58, 385, 280, 281, 282, 406, 407, 615, 408, 409, 269, 270, 590, 58, 58, 58, 594, 58, 58, 597, 598, 58, 58, 37, 91, 524, 93, 376, 42, 43, 58, 45, 58, 47, 58, 313, 314, 58, 537, 647, 648, 649, 385, 58, 376, 58, 617, 387, 40, 58, 61, 400, 401, 44, 332, 37, 123, 40, 125, 61, 42, 43, 790, 45, 91, 47, 40, 123, 400, 401, 46, 91, 800, 91, 44, 646, 44, 37, 44, 93, 384, 652, 42, 43, 343, 45, 345, 47, 258, 40, 0, 91, 257, 592, 593, 37, 374, 596, 376, 44, 42, 43, 91, 45, 37, 47, 44, 385, 257, 42, 43, 93, 45, 841, 47, 44, 394, 395, 396, 397, 91, 44, 400, 401, 402, 403, 44, 44, 38, 44, 38, 41, 37, 43, 44, 45, 46, 42, 43, 40, 45, 40, 47, 40, 40, 716, 754, 40, 258, 37, 91, 93, 430, 41, 42, 43, 655, 45, 44, 47, 93, 44, 44, 40, 258, 37, 665, 775, 776, 777, 42, 43, 37, 45, 44, 47, 41, 42, 43, 44, 45, 91, 47, 93, 37, 44, 260, 44, 93, 42, 43, 44, 45, 260, 47, 44, 258, 44, 44, 44, 44, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 123, 44, 125, 283, 284, 285, 258, 44, 93, 289, 290, 291, 292, 293, 294, 295, 296, 297, 44, 299, 300, 301, 302, 303, 304, 305, 738, 307, 44, 395, 44, 397, 93, 399, 44, 401, 41, 403, 41, 405, 44, 407, 322, 409, 44, 411, 58, 58, 257, 329, 330, 58, 332, 93, 334, 335, 336, 58, 257, 339, 340, 341, 342, 343, 344, 345, 0, 854, 44, 37, 386, 783, 44, 860, 42, 43, 44, 45, 44, 47, 44, 259, 312, 363, 44, 365, 44, 367, 382, 312, 830, 41, 44, 44, 93, 258, 321, 44, 44, 44, 321, 44, 125, 843, 257, 44, 41, 387, 388, 258, 44, 44, 385, 44, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 124, 44, 385, 41, 44, 260, 91, 44, 44, 44, 44, 44, 44, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, 258, 93, 283, 284, 285, 91, 44, 44, 289, 290, 291, 292, 293, 294, 295, 296, 297, 44, 299, 300, 301, 302, 303, 304, 305, 258, 307, 258, 44, 258, 44, 123, 44, 125, 44, 312, 44, 258, 44, 44, 331, 322, 44, 257, 41, 46, 44, 58, 329, 330, 258, 332, 40, 334, 335, 336, 41, 44, 339, 340, 341, 342, 343, 344, 345, 388, 257, 386, 41, 58, 41, 394, 58, 396, 58, 398, 58, 400, 58, 402, 44, 404, 363, 406, 365, 408, 367, 410, 259, 44, 312, 44, 40, 44, 258, 321, 321, 0, 258, 44, 44, 385, 44, 44, 123, 44, 387, 388, 44, 41, 41, 41, 41, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 258, 44, 93, 44, 38, 388, 258, 41, 258, 44, 44, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 44, 44, 258, 258, 44, 41, 58, 58, 260, 259, 58, 58, 257, 286, 41, 44, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, 44, 258, 283, 284, 285, 41, 44, 41, 289, 290, 291, 292, 293, 294, 295, 296, 297, 41, 299, 300, 301, 302, 303, 304, 305, 44, 307, 261, 58, 125, 44, 41, 44, 125, 258, 44, 313, 258, 258, 124, 58, 322, 259, 286, 41, 258, 41, 41, 329, 330, 41, 332, 44, 334, 335, 336, 41, 383, 339, 340, 41, 342, 343, 344, 345, 41, 44, 44, 41, 44, 0, 0, 41, 41, 386, 125, 93, 41, 44, 41, 123, 123, 363, 41, 365, 125, 677, 794, 602, 652, 761, 191, 820, 449, 48, 832, 248, 0, 442, 54, 859, 168, 419, 753, 395, 6, 387, 388, 319, 431, 766, 163, 138, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 340, 629, 454, -1, -1, -1, -1, 41, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, 44, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 123, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, 44, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, 123, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, 312, 313, 314, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, 44, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, 400, 401, -1, -1, -1, -1, 260, -1, -1, -1, 410, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 123, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, 44, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, 123, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 313, 314, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, 400, 401, -1, -1, -1, -1, 260, -1, -1, -1, 410, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 123, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, 123, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, 123, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, 331, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 123, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, 123, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 91, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, 125, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 91, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, 343, 344, 345, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 91, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, -1, -1, 40, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, -1, 344, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, 257, -1, -1, -1, 261, -1, -1, -1, -1, -1, -1, -1, 322, 257, 258, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, -1, 344, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, 313, 314, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 313, 314, -1, -1, -1, -1, -1, -1, 387, 388, 91, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, -1, 258, -1, -1, -1, -1, -1, -1, -1, -1, 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, 369, 370, 371, 372, 373, -1, 375, 376, 377, 378, 379, 380, 381, -1, -1, -1, -1, -1, 400, 401, -1, -1, 404, 405, 315, 316, -1, -1, 410, -1, -1, 400, 401, 313, 314, 326, 327, 328, -1, -1, -1, 410, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 349, -1, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 369, 370, 371, 372, 373, 385, 375, 376, 377, 378, 379, 380, 381, -1, -1, -1, 396, 397, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 400, 401, -1, 260, -1, -1, -1, -1, -1, -1, 410, 268, -1, -1, 271, 272, 273, 274, 275, 276, 277, 278, 279, -1, -1, -1, 283, 284, 285, -1, -1, -1, 289, 290, 291, 292, 293, 294, 295, 296, 297, -1, 299, 300, 301, 302, 303, 304, 305, -1, 307, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, 329, 330, -1, 332, -1, 334, 335, 336, -1, -1, 339, 340, -1, 342, -1, 344, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, 388, -1, -1, -1, -1, -1, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, }; #define YYFINAL 3 #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYMAXTOKEN 430 #if YYDEBUG char *yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,"'%'","'&'",0,"'('","')'","'*'","'+'","','","'-'","'.'","'/'",0,0,0,0,0,0, 0,0,0,0,"':'",0,0,"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,"'['",0,"']'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'", "'|'","'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"CHAR","INTEGER","BOOLEAN","PERCENT", "SPERCENT","MINUS_INTEGER","PLUS_INTEGER","MAZE_GRID_ID","SOLID_FILL_ID", "MINES_ID","ROGUELEV_ID","MESSAGE_ID","MAZE_ID","LEVEL_ID","LEV_INIT_ID", "GEOMETRY_ID","NOMAP_ID","OBJECT_ID","COBJECT_ID","MONSTER_ID","TRAP_ID", "DOOR_ID","DRAWBRIDGE_ID","object_ID","monster_ID","terrain_ID","MAZEWALK_ID", "WALLIFY_ID","REGION_ID","FILLING","IRREGULAR","JOINED","ALTAR_ID","LADDER_ID", "STAIR_ID","NON_DIGGABLE_ID","NON_PASSWALL_ID","ROOM_ID","PORTAL_ID", "TELEPRT_ID","BRANCH_ID","LEV","MINERALIZE_ID","CORRIDOR_ID","GOLD_ID", "ENGRAVING_ID","FOUNTAIN_ID","POOL_ID","SINK_ID","NONE","RAND_CORRIDOR_ID", "DOOR_STATE","LIGHT_STATE","CURSE_TYPE","ENGRAVING_TYPE","DIRECTION", "RANDOM_TYPE","RANDOM_TYPE_BRACKET","A_REGISTER","ALIGNMENT","LEFT_OR_RIGHT", "CENTER","TOP_OR_BOT","ALTAR_TYPE","UP_OR_DOWN","SUBROOM_ID","NAME_ID", "FLAGS_ID","FLAG_TYPE","MON_ATTITUDE","MON_ALERTNESS","MON_APPEARANCE", "ROOMDOOR_ID","IF_ID","ELSE_ID","TERRAIN_ID","HORIZ_OR_VERT", "REPLACE_TERRAIN_ID","EXIT_ID","SHUFFLE_ID","QUANTITY_ID","BURIED_ID","LOOP_ID", "FOR_ID","TO_ID","SWITCH_ID","CASE_ID","BREAK_ID","DEFAULT_ID","ERODED_ID", "TRAPPED_STATE","RECHARGED_ID","INVIS_ID","GREASED_ID","FEMALE_ID", "CANCELLED_ID","REVIVED_ID","AVENGE_ID","FLEEING_ID","BLINDED_ID", "PARALYZED_ID","STUNNED_ID","CONFUSED_ID","SEENTRAPS_ID","ALL_ID","MONTYPE_ID", "GRAVE_ID","ERODEPROOF_ID","FUNCTION_ID","MSG_OUTPUT_TYPE","COMPARE_TYPE", "UNKNOWN_TYPE","rect_ID","fillrect_ID","line_ID","randline_ID","grow_ID", "selection_ID","flood_ID","rndcoord_ID","circle_ID","ellipse_ID","filter_ID", "complement_ID","gradient_ID","GRADIENT_TYPE","LIMITED","HUMIDITY_TYPE", "STRING","MAP_ID","NQSTRING","VARSTRING","CFUNC","CFUNC_INT","CFUNC_STR", "CFUNC_COORD","CFUNC_REGION","VARSTRING_INT","VARSTRING_INT_ARRAY", "VARSTRING_STRING","VARSTRING_STRING_ARRAY","VARSTRING_VAR", "VARSTRING_VAR_ARRAY","VARSTRING_COORD","VARSTRING_COORD_ARRAY", "VARSTRING_REGION","VARSTRING_REGION_ARRAY","VARSTRING_MAPCHAR", "VARSTRING_MAPCHAR_ARRAY","VARSTRING_MONST","VARSTRING_MONST_ARRAY", "VARSTRING_OBJ","VARSTRING_OBJ_ARRAY","VARSTRING_SEL","VARSTRING_SEL_ARRAY", "METHOD_INT","METHOD_INT_ARRAY","METHOD_STRING","METHOD_STRING_ARRAY", "METHOD_VAR","METHOD_VAR_ARRAY","METHOD_COORD","METHOD_COORD_ARRAY", "METHOD_REGION","METHOD_REGION_ARRAY","METHOD_MAPCHAR","METHOD_MAPCHAR_ARRAY", "METHOD_MONST","METHOD_MONST_ARRAY","METHOD_OBJ","METHOD_OBJ_ARRAY", "METHOD_SEL","METHOD_SEL_ARRAY","DICE", }; char *yyrule[] = { "$accept : file", "file :", "file : levels", "levels : level", "levels : level levels", "level : level_def flags levstatements", "level_def : LEVEL_ID ':' STRING", "level_def : MAZE_ID ':' STRING ',' mazefiller", "mazefiller : RANDOM_TYPE", "mazefiller : CHAR", "lev_init : LEV_INIT_ID ':' SOLID_FILL_ID ',' terrain_type", "lev_init : LEV_INIT_ID ':' MAZE_GRID_ID ',' CHAR", "lev_init : LEV_INIT_ID ':' ROGUELEV_ID", "lev_init : LEV_INIT_ID ':' MINES_ID ',' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled opt_fillchar", "opt_limited :", "opt_limited : ',' LIMITED", "opt_coord_or_var :", "opt_coord_or_var : ',' coord_or_var", "opt_fillchar :", "opt_fillchar : ',' CHAR", "walled : BOOLEAN", "walled : RANDOM_TYPE", "flags :", "flags : FLAGS_ID ':' flag_list", "flag_list : FLAG_TYPE ',' flag_list", "flag_list : FLAG_TYPE", "levstatements :", "levstatements : levstatement levstatements", "stmt_block : '{' levstatements '}'", "levstatement : message", "levstatement : lev_init", "levstatement : altar_detail", "levstatement : grave_detail", "levstatement : branch_region", "levstatement : corridor", "levstatement : variable_define", "levstatement : shuffle_detail", "levstatement : diggable_detail", "levstatement : door_detail", "levstatement : drawbridge_detail", "levstatement : engraving_detail", "levstatement : mineralize", "levstatement : fountain_detail", "levstatement : gold_detail", "levstatement : switchstatement", "levstatement : forstatement", "levstatement : loopstatement", "levstatement : ifstatement", "levstatement : chancestatement", "levstatement : exitstatement", "levstatement : breakstatement", "levstatement : function_define", "levstatement : function_call", "levstatement : ladder_detail", "levstatement : map_definition", "levstatement : mazewalk_detail", "levstatement : monster_detail", "levstatement : object_detail", "levstatement : passwall_detail", "levstatement : pool_detail", "levstatement : portal_region", "levstatement : random_corridors", "levstatement : region_detail", "levstatement : room_def", "levstatement : subroom_def", "levstatement : sink_detail", "levstatement : terrain_detail", "levstatement : replace_terrain_detail", "levstatement : stair_detail", "levstatement : stair_region", "levstatement : teleprt_region", "levstatement : trap_detail", "levstatement : wallify_detail", "any_var_array : VARSTRING_INT_ARRAY", "any_var_array : VARSTRING_STRING_ARRAY", "any_var_array : VARSTRING_VAR_ARRAY", "any_var_array : VARSTRING_COORD_ARRAY", "any_var_array : VARSTRING_REGION_ARRAY", "any_var_array : VARSTRING_MAPCHAR_ARRAY", "any_var_array : VARSTRING_MONST_ARRAY", "any_var_array : VARSTRING_OBJ_ARRAY", "any_var_array : VARSTRING_SEL_ARRAY", "any_var : VARSTRING_INT", "any_var : VARSTRING_STRING", "any_var : VARSTRING_VAR", "any_var : VARSTRING_COORD", "any_var : VARSTRING_REGION", "any_var : VARSTRING_MAPCHAR", "any_var : VARSTRING_MONST", "any_var : VARSTRING_OBJ", "any_var : VARSTRING_SEL", "any_var_or_arr : any_var_array", "any_var_or_arr : any_var", "any_var_or_arr : VARSTRING", "any_var_or_unk : VARSTRING", "any_var_or_unk : any_var", "shuffle_detail : SHUFFLE_ID ':' any_var_array", "variable_define : any_var_or_arr '=' math_expr_var", "variable_define : any_var_or_arr '=' selection_ID ':' ter_selection", "variable_define : any_var_or_arr '=' string_expr", "variable_define : any_var_or_arr '=' terrainid ':' mapchar_or_var", "variable_define : any_var_or_arr '=' monsterid ':' monster_or_var", "variable_define : any_var_or_arr '=' objectid ':' object_or_var", "variable_define : any_var_or_arr '=' coord_or_var", "variable_define : any_var_or_arr '=' region_or_var", "variable_define : any_var_or_arr '=' '{' integer_list '}'", "variable_define : any_var_or_arr '=' '{' encodecoord_list '}'", "variable_define : any_var_or_arr '=' '{' encoderegion_list '}'", "variable_define : any_var_or_arr '=' terrainid ':' '{' mapchar_list '}'", "variable_define : any_var_or_arr '=' monsterid ':' '{' encodemonster_list '}'", "variable_define : any_var_or_arr '=' objectid ':' '{' encodeobj_list '}'", "variable_define : any_var_or_arr '=' '{' string_list '}'", "encodeobj_list : encodeobj", "encodeobj_list : encodeobj_list ',' encodeobj", "encodemonster_list : encodemonster", "encodemonster_list : encodemonster_list ',' encodemonster", "mapchar_list : mapchar", "mapchar_list : mapchar_list ',' mapchar", "encoderegion_list : encoderegion", "encoderegion_list : encoderegion_list ',' encoderegion", "encodecoord_list : encodecoord", "encodecoord_list : encodecoord_list ',' encodecoord", "integer_list : math_expr_var", "integer_list : integer_list ',' math_expr_var", "string_list : string_expr", "string_list : string_list ',' string_expr", "$$1 :", "$$2 :", "function_define : FUNCTION_ID NQSTRING '(' $$1 func_params_list ')' $$2 stmt_block", "function_call : NQSTRING '(' func_call_params_list ')'", "exitstatement : EXIT_ID", "opt_percent :", "opt_percent : PERCENT", "comparestmt : PERCENT", "comparestmt : '[' math_expr_var COMPARE_TYPE math_expr_var ']'", "comparestmt : '[' math_expr_var ']'", "$$3 :", "$$4 :", "switchstatement : SWITCH_ID $$3 '[' integer_or_var ']' $$4 '{' switchcases '}'", "switchcases :", "switchcases : switchcase switchcases", "$$5 :", "switchcase : CASE_ID all_integers ':' $$5 levstatements", "$$6 :", "switchcase : DEFAULT_ID ':' $$6 levstatements", "breakstatement : BREAK_ID", "for_to_span : '.' '.'", "for_to_span : TO_ID", "forstmt_start : FOR_ID any_var_or_unk '=' math_expr_var for_to_span math_expr_var", "$$7 :", "forstatement : forstmt_start $$7 stmt_block", "$$8 :", "loopstatement : LOOP_ID '[' integer_or_var ']' $$8 stmt_block", "$$9 :", "chancestatement : comparestmt ':' $$9 levstatement", "$$10 :", "ifstatement : IF_ID comparestmt $$10 if_ending", "if_ending : stmt_block", "$$11 :", "if_ending : stmt_block $$11 ELSE_ID stmt_block", "message : MESSAGE_ID ':' string_expr", "random_corridors : RAND_CORRIDOR_ID", "random_corridors : RAND_CORRIDOR_ID ':' all_integers", "random_corridors : RAND_CORRIDOR_ID ':' RANDOM_TYPE", "corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec", "corridor : CORRIDOR_ID ':' corr_spec ',' all_integers", "corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')'", "room_begin : room_type opt_percent ',' light_state", "$$12 :", "subroom_def : SUBROOM_ID ':' room_begin ',' subroom_pos ',' room_size optroomregionflags $$12 stmt_block", "$$13 :", "room_def : ROOM_ID ':' room_begin ',' room_pos ',' room_align ',' room_size optroomregionflags $$13 stmt_block", "roomfill :", "roomfill : ',' BOOLEAN", "room_pos : '(' INTEGER ',' INTEGER ')'", "room_pos : RANDOM_TYPE", "subroom_pos : '(' INTEGER ',' INTEGER ')'", "subroom_pos : RANDOM_TYPE", "room_align : '(' h_justif ',' v_justif ')'", "room_align : RANDOM_TYPE", "room_size : '(' INTEGER ',' INTEGER ')'", "room_size : RANDOM_TYPE", "door_detail : ROOMDOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos", "door_detail : DOOR_ID ':' door_state ',' ter_selection", "secret : BOOLEAN", "secret : RANDOM_TYPE", "door_wall : dir_list", "door_wall : RANDOM_TYPE", "dir_list : DIRECTION", "dir_list : DIRECTION '|' dir_list", "door_pos : INTEGER", "door_pos : RANDOM_TYPE", "map_definition : NOMAP_ID", "map_definition : GEOMETRY_ID ':' h_justif ',' v_justif roomfill MAP_ID", "map_definition : GEOMETRY_ID ':' coord_or_var roomfill MAP_ID", "h_justif : LEFT_OR_RIGHT", "h_justif : CENTER", "v_justif : TOP_OR_BOT", "v_justif : CENTER", "monster_detail : MONSTER_ID ':' monster_desc", "$$14 :", "monster_detail : MONSTER_ID ':' monster_desc $$14 stmt_block", "monster_desc : monster_or_var ',' coord_or_var monster_infos", "monster_infos :", "monster_infos : monster_infos ',' monster_info", "monster_info : string_expr", "monster_info : MON_ATTITUDE", "monster_info : MON_ALERTNESS", "monster_info : alignment_prfx", "monster_info : MON_APPEARANCE string_expr", "monster_info : FEMALE_ID", "monster_info : INVIS_ID", "monster_info : CANCELLED_ID", "monster_info : REVIVED_ID", "monster_info : AVENGE_ID", "monster_info : FLEEING_ID ':' integer_or_var", "monster_info : BLINDED_ID ':' integer_or_var", "monster_info : PARALYZED_ID ':' integer_or_var", "monster_info : STUNNED_ID", "monster_info : CONFUSED_ID", "monster_info : SEENTRAPS_ID ':' seen_trap_mask", "seen_trap_mask : STRING", "seen_trap_mask : ALL_ID", "seen_trap_mask : STRING '|' seen_trap_mask", "object_detail : OBJECT_ID ':' object_desc", "$$15 :", "object_detail : COBJECT_ID ':' object_desc $$15 stmt_block", "object_desc : object_or_var object_infos", "object_infos :", "object_infos : object_infos ',' object_info", "object_info : CURSE_TYPE", "object_info : MONTYPE_ID ':' monster_or_var", "object_info : all_ints_push", "object_info : NAME_ID ':' string_expr", "object_info : QUANTITY_ID ':' integer_or_var", "object_info : BURIED_ID", "object_info : LIGHT_STATE", "object_info : ERODED_ID ':' integer_or_var", "object_info : ERODEPROOF_ID", "object_info : DOOR_STATE", "object_info : TRAPPED_STATE", "object_info : RECHARGED_ID ':' integer_or_var", "object_info : INVIS_ID", "object_info : GREASED_ID", "object_info : coord_or_var", "trap_detail : TRAP_ID ':' trap_name ',' coord_or_var", "drawbridge_detail : DRAWBRIDGE_ID ':' coord_or_var ',' DIRECTION ',' door_state", "mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION", "mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION ',' BOOLEAN opt_fillchar", "wallify_detail : WALLIFY_ID", "wallify_detail : WALLIFY_ID ':' ter_selection", "ladder_detail : LADDER_ID ':' coord_or_var ',' UP_OR_DOWN", "stair_detail : STAIR_ID ':' coord_or_var ',' UP_OR_DOWN", "stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN", "portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' STRING", "teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail", "branch_region : BRANCH_ID ':' lev_region ',' lev_region", "teleprt_detail :", "teleprt_detail : ',' UP_OR_DOWN", "fountain_detail : FOUNTAIN_ID ':' ter_selection", "sink_detail : SINK_ID ':' ter_selection", "pool_detail : POOL_ID ':' ter_selection", "terrain_type : CHAR", "terrain_type : '(' CHAR ',' light_state ')'", "replace_terrain_detail : REPLACE_TERRAIN_ID ':' region_or_var ',' mapchar_or_var ',' mapchar_or_var ',' SPERCENT", "terrain_detail : TERRAIN_ID ':' ter_selection ',' mapchar_or_var", "diggable_detail : NON_DIGGABLE_ID ':' region_or_var", "passwall_detail : NON_PASSWALL_ID ':' region_or_var", "$$16 :", "region_detail : REGION_ID ':' region_or_var ',' light_state ',' room_type optroomregionflags $$16 region_detail_end", "region_detail_end :", "region_detail_end : stmt_block", "altar_detail : ALTAR_ID ':' coord_or_var ',' alignment ',' altar_type", "grave_detail : GRAVE_ID ':' coord_or_var ',' string_expr", "grave_detail : GRAVE_ID ':' coord_or_var ',' RANDOM_TYPE", "grave_detail : GRAVE_ID ':' coord_or_var", "gold_detail : GOLD_ID ':' math_expr_var ',' coord_or_var", "engraving_detail : ENGRAVING_ID ':' coord_or_var ',' engraving_type ',' string_expr", "mineralize : MINERALIZE_ID ':' integer_or_var ',' integer_or_var ',' integer_or_var ',' integer_or_var", "mineralize : MINERALIZE_ID", "trap_name : STRING", "trap_name : RANDOM_TYPE", "room_type : STRING", "room_type : RANDOM_TYPE", "optroomregionflags :", "optroomregionflags : ',' roomregionflags", "roomregionflags : roomregionflag", "roomregionflags : roomregionflag ',' roomregionflags", "roomregionflag : FILLING", "roomregionflag : IRREGULAR", "roomregionflag : JOINED", "door_state : DOOR_STATE", "door_state : RANDOM_TYPE", "light_state : LIGHT_STATE", "light_state : RANDOM_TYPE", "alignment : ALIGNMENT", "alignment : a_register", "alignment : RANDOM_TYPE", "alignment_prfx : ALIGNMENT", "alignment_prfx : a_register", "alignment_prfx : A_REGISTER ':' RANDOM_TYPE", "altar_type : ALTAR_TYPE", "altar_type : RANDOM_TYPE", "a_register : A_REGISTER '[' INTEGER ']'", "string_or_var : STRING", "string_or_var : VARSTRING_STRING", "string_or_var : VARSTRING_STRING_ARRAY '[' math_expr_var ']'", "integer_or_var : math_expr_var", "coord_or_var : encodecoord", "coord_or_var : rndcoord_ID '(' ter_selection ')'", "coord_or_var : VARSTRING_COORD", "coord_or_var : VARSTRING_COORD_ARRAY '[' math_expr_var ']'", "encodecoord : '(' INTEGER ',' INTEGER ')'", "encodecoord : RANDOM_TYPE", "encodecoord : RANDOM_TYPE_BRACKET humidity_flags ']'", "humidity_flags : HUMIDITY_TYPE", "humidity_flags : HUMIDITY_TYPE ',' humidity_flags", "region_or_var : encoderegion", "region_or_var : VARSTRING_REGION", "region_or_var : VARSTRING_REGION_ARRAY '[' math_expr_var ']'", "encoderegion : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'", "mapchar_or_var : mapchar", "mapchar_or_var : VARSTRING_MAPCHAR", "mapchar_or_var : VARSTRING_MAPCHAR_ARRAY '[' math_expr_var ']'", "mapchar : CHAR", "mapchar : '(' CHAR ',' light_state ')'", "monster_or_var : encodemonster", "monster_or_var : VARSTRING_MONST", "monster_or_var : VARSTRING_MONST_ARRAY '[' math_expr_var ']'", "encodemonster : STRING", "encodemonster : CHAR", "encodemonster : '(' CHAR ',' STRING ')'", "encodemonster : RANDOM_TYPE", "object_or_var : encodeobj", "object_or_var : VARSTRING_OBJ", "object_or_var : VARSTRING_OBJ_ARRAY '[' math_expr_var ']'", "encodeobj : STRING", "encodeobj : CHAR", "encodeobj : '(' CHAR ',' STRING ')'", "encodeobj : RANDOM_TYPE", "string_expr : string_or_var", "string_expr : string_expr '.' string_or_var", "math_expr_var : INTEGER", "math_expr_var : dice", "math_expr_var : '(' MINUS_INTEGER ')'", "math_expr_var : VARSTRING_INT", "math_expr_var : VARSTRING_INT_ARRAY '[' math_expr_var ']'", "math_expr_var : math_expr_var '+' math_expr_var", "math_expr_var : math_expr_var '-' math_expr_var", "math_expr_var : math_expr_var '*' math_expr_var", "math_expr_var : math_expr_var '/' math_expr_var", "math_expr_var : math_expr_var '%' math_expr_var", "math_expr_var : '(' math_expr_var ')'", "func_param_type : CFUNC_INT", "func_param_type : CFUNC_STR", "func_param_part : any_var_or_arr ':' func_param_type", "func_param_list : func_param_part", "func_param_list : func_param_list ',' func_param_part", "func_params_list :", "func_params_list : func_param_list", "func_call_param_part : math_expr_var", "func_call_param_part : string_expr", "func_call_param_list : func_call_param_part", "func_call_param_list : func_call_param_list ',' func_call_param_part", "func_call_params_list :", "func_call_params_list : func_call_param_list", "ter_selection_x : coord_or_var", "ter_selection_x : rect_ID region_or_var", "ter_selection_x : fillrect_ID region_or_var", "ter_selection_x : line_ID coord_or_var ',' coord_or_var", "ter_selection_x : randline_ID coord_or_var ',' coord_or_var ',' math_expr_var", "ter_selection_x : grow_ID '(' ter_selection ')'", "ter_selection_x : grow_ID '(' dir_list ',' ter_selection ')'", "ter_selection_x : filter_ID '(' SPERCENT ',' ter_selection ')'", "ter_selection_x : filter_ID '(' ter_selection ',' ter_selection ')'", "ter_selection_x : filter_ID '(' mapchar_or_var ',' ter_selection ')'", "ter_selection_x : flood_ID coord_or_var", "ter_selection_x : circle_ID '(' coord_or_var ',' math_expr_var ')'", "ter_selection_x : circle_ID '(' coord_or_var ',' math_expr_var ',' FILLING ')'", "ter_selection_x : ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ')'", "ter_selection_x : ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ',' FILLING ')'", "ter_selection_x : gradient_ID '(' GRADIENT_TYPE ',' '(' math_expr_var '-' math_expr_var opt_limited ')' ',' coord_or_var opt_coord_or_var ')'", "ter_selection_x : complement_ID ter_selection_x", "ter_selection_x : VARSTRING_SEL", "ter_selection_x : '(' ter_selection ')'", "ter_selection : ter_selection_x", "ter_selection : ter_selection_x '&' ter_selection", "dice : DICE", "all_integers : MINUS_INTEGER", "all_integers : PLUS_INTEGER", "all_integers : INTEGER", "all_ints_push : MINUS_INTEGER", "all_ints_push : PLUS_INTEGER", "all_ints_push : INTEGER", "all_ints_push : dice", "objectid : object_ID", "objectid : OBJECT_ID", "monsterid : monster_ID", "monsterid : MONSTER_ID", "terrainid : terrain_ID", "terrainid : TERRAIN_ID", "engraving_type : ENGRAVING_TYPE", "engraving_type : RANDOM_TYPE", "lev_region : region", "lev_region : LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'", "region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'", }; #endif #ifdef YYSTACKSIZE #undef YYMAXDEPTH #define YYMAXDEPTH YYSTACKSIZE #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else #define YYSTACKSIZE 500 #define YYMAXDEPTH 500 #endif #endif int yydebug; int yynerrs; int yyerrflag; int yychar; short *yyssp; YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; short yyss[YYSTACKSIZE]; YYSTYPE yyvs[YYSTACKSIZE]; #define yystacksize YYSTACKSIZE /*lev_comp.y*/ #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab int yyparse() { register int yym, yyn, yystate; #if YYDEBUG register char *yys; extern char *getenv(); if ((yys = getenv("YYDEBUG")) != 0) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = (-1); yyssp = yyss; yyvsp = yyvs; *yyssp = yystate = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; yychar = (-1); if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; goto yynewerror; yynewerror: yyerror("syntax error"); goto yyerrlab; yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) != 0 && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = (-1); goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; yyval = yyvsp[1-yym]; switch (yyn) { case 5: { if (fatal_error > 0) { (void) fprintf(stderr, "%s: %d errors detected for level \"%s\". No output created!\n", fname, fatal_error, yyvsp[-2].map); fatal_error = 0; got_errors++; } else if (!got_errors) { if (!write_level_file(yyvsp[-2].map, splev)) { lc_error("Can't write output file for '%s'!", yyvsp[-2].map); exit(EXIT_FAILURE); } } Free(yyvsp[-2].map); Free(splev); splev = NULL; vardef_free_all(variable_definitions); variable_definitions = NULL; } break; case 6: { start_level_def(&splev, yyvsp[0].map); yyval.map = yyvsp[0].map; } break; case 7: { start_level_def(&splev, yyvsp[-2].map); if (yyvsp[0].i == -1) { add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_MAZEGRID,HWALL,0,0, 0,0,0,0, SPO_INITLEVEL)); } else { long bg = what_map_char((char) yyvsp[0].i); add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_SOLIDFILL, bg, 0,0, 0,0,0,0, SPO_INITLEVEL)); } add_opvars(splev, "io", VA_PASS2(MAZELEVEL, SPO_LEVEL_FLAGS)); max_x_map = COLNO-1; max_y_map = ROWNO; yyval.map = yyvsp[-2].map; } break; case 8: { yyval.i = -1; } break; case 9: { yyval.i = what_map_char((char) yyvsp[0].i); } break; case 10: { long filling = yyvsp[0].terr.ter; if (filling == INVALID_TYPE || filling >= MAX_TYPE) lc_error("INIT_MAP: Invalid fill char type."); add_opvars(splev, "iiiiiiiio", LVLINIT_SOLIDFILL,filling,0,(long)yyvsp[0].terr.lit, 0,0,0,0, SPO_INITLEVEL); max_x_map = COLNO-1; max_y_map = ROWNO; } break; case 11: { long filling = what_map_char((char) yyvsp[0].i); if (filling == INVALID_TYPE || filling >= MAX_TYPE) lc_error("INIT_MAP: Invalid fill char type."); add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_MAZEGRID,filling,0,0, 0,0,0,0, SPO_INITLEVEL)); max_x_map = COLNO-1; max_y_map = ROWNO; } break; case 12: { add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_ROGUE,0,0,0, 0,0,0,0, SPO_INITLEVEL)); } break; case 13: { long fg = what_map_char((char) yyvsp[-11].i); long bg = what_map_char((char) yyvsp[-9].i); long smoothed = yyvsp[-7].i; long joined = yyvsp[-5].i; long lit = yyvsp[-3].i; long walled = yyvsp[-1].i; long filling = yyvsp[0].i; if (fg == INVALID_TYPE || fg >= MAX_TYPE) lc_error("INIT_MAP: Invalid foreground type."); if (bg == INVALID_TYPE || bg >= MAX_TYPE) lc_error("INIT_MAP: Invalid background type."); if (joined && fg != CORR && fg != ROOM) lc_error("INIT_MAP: Invalid foreground type for joined map."); if (filling == INVALID_TYPE) lc_error("INIT_MAP: Invalid fill char type."); add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_MINES,filling,walled,lit, joined,smoothed,bg,fg, SPO_INITLEVEL)); max_x_map = COLNO-1; max_y_map = ROWNO; } break; case 14: { yyval.i = 0; } break; case 15: { yyval.i = yyvsp[0].i; } break; case 16: { add_opvars(splev, "o", VA_PASS1(SPO_COPY)); yyval.i = 0; } break; case 17: { yyval.i = 1; } break; case 18: { yyval.i = -1; } break; case 19: { yyval.i = what_map_char((char) yyvsp[0].i); } break; case 22: { add_opvars(splev, "io", VA_PASS2(0, SPO_LEVEL_FLAGS)); } break; case 23: { add_opvars(splev, "io", VA_PASS2(yyvsp[0].i, SPO_LEVEL_FLAGS)); } break; case 24: { yyval.i = (yyvsp[-2].i | yyvsp[0].i); } break; case 25: { yyval.i = yyvsp[0].i; } break; case 26: { yyval.i = 0; } break; case 27: { yyval.i = 1 + yyvsp[0].i; } break; case 28: { yyval.i = yyvsp[-1].i; } break; case 96: { struct lc_vardefs *vd; if ((vd = vardef_defined(variable_definitions, yyvsp[0].map, 1))) { if (!(vd->var_type & SPOVAR_ARRAY)) lc_error("Trying to shuffle non-array variable '%s'", yyvsp[0].map); } else lc_error("Trying to shuffle undefined variable '%s'", yyvsp[0].map); add_opvars(splev, "so", VA_PASS2(yyvsp[0].map, SPO_SHUFFLE_ARRAY)); Free(yyvsp[0].map); } break; case 97: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-2].map, SPOVAR_INT); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-2].map, SPO_VAR_INIT)); Free(yyvsp[-2].map); } break; case 98: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_SEL); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 99: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-2].map, SPOVAR_STRING); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-2].map, SPO_VAR_INIT)); Free(yyvsp[-2].map); } break; case 100: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_MAPCHAR); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 101: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_MONST); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 102: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_OBJ); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 103: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-2].map, SPOVAR_COORD); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-2].map, SPO_VAR_INIT)); Free(yyvsp[-2].map); } break; case 104: { variable_definitions = add_vardef_type(variable_definitions, yyvsp[-2].map, SPOVAR_REGION); add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-2].map, SPO_VAR_INIT)); Free(yyvsp[-2].map); } break; case 105: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_INT|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 106: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_COORD|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 107: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_REGION|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 108: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-6].map, SPOVAR_MAPCHAR|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-6].map, SPO_VAR_INIT)); Free(yyvsp[-6].map); } break; case 109: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-6].map, SPOVAR_MONST|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-6].map, SPO_VAR_INIT)); Free(yyvsp[-6].map); } break; case 110: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-6].map, SPOVAR_OBJ|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-6].map, SPO_VAR_INIT)); Free(yyvsp[-6].map); } break; case 111: { long n_items = yyvsp[-1].i; variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_STRING|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, yyvsp[-4].map, SPO_VAR_INIT)); Free(yyvsp[-4].map); } break; case 112: { add_opvars(splev, "O", VA_PASS1(yyvsp[0].i)); yyval.i = 1; } break; case 113: { add_opvars(splev, "O", VA_PASS1(yyvsp[0].i)); yyval.i = 1 + yyvsp[-2].i; } break; case 114: { add_opvars(splev, "M", VA_PASS1(yyvsp[0].i)); yyval.i = 1; } break; case 115: { add_opvars(splev, "M", VA_PASS1(yyvsp[0].i)); yyval.i = 1 + yyvsp[-2].i; } break; case 116: { add_opvars(splev, "m", VA_PASS1(yyvsp[0].i)); yyval.i = 1; } break; case 117: { add_opvars(splev, "m", VA_PASS1(yyvsp[0].i)); yyval.i = 1 + yyvsp[-2].i; } break; case 118: { yyval.i = 1; } break; case 119: { yyval.i = 1 + yyvsp[-2].i; } break; case 120: { add_opvars(splev, "c", VA_PASS1(yyvsp[0].i)); yyval.i = 1; } break; case 121: { add_opvars(splev, "c", VA_PASS1(yyvsp[0].i)); yyval.i = 1 + yyvsp[-2].i; } break; case 122: { yyval.i = 1; } break; case 123: { yyval.i = 1 + yyvsp[-2].i; } break; case 124: { yyval.i = 1; } break; case 125: { yyval.i = 1 + yyvsp[-2].i; } break; case 126: { struct lc_funcdefs *funcdef; if (in_function_definition) lc_error("Recursively defined functions not allowed (function %s).", yyvsp[-1].map); in_function_definition++; if (funcdef_defined(function_definitions, yyvsp[-1].map, 1)) lc_error("Function '%s' already defined once.", yyvsp[-1].map); funcdef = funcdef_new(-1, yyvsp[-1].map); funcdef->next = function_definitions; function_definitions = funcdef; function_splev_backup = splev; splev = &(funcdef->code); Free(yyvsp[-1].map); curr_function = funcdef; function_tmp_var_defs = variable_definitions; variable_definitions = NULL; } break; case 127: { /* nothing */ } break; case 128: { add_opvars(splev, "io", VA_PASS2(0, SPO_RETURN)); splev = function_splev_backup; in_function_definition--; curr_function = NULL; vardef_free_all(variable_definitions); variable_definitions = function_tmp_var_defs; } break; case 129: { struct lc_funcdefs *tmpfunc; tmpfunc = funcdef_defined(function_definitions, yyvsp[-3].map, 1); if (tmpfunc) { long l; long nparams = strlen( yyvsp[-1].map ); char *fparamstr = funcdef_paramtypes(tmpfunc); if (strcmp(yyvsp[-1].map, fparamstr)) { char *tmps = strdup(decode_parm_str(fparamstr)); lc_error("Function '%s' requires params '%s', got '%s' instead.", yyvsp[-3].map, tmps, decode_parm_str(yyvsp[-1].map)); Free(tmps); } Free(fparamstr); Free(yyvsp[-1].map); if (!(tmpfunc->n_called)) { /* we haven't called the function yet, so insert it in the code */ struct opvar *jmp = New(struct opvar); set_opvar_int(jmp, splev->n_opcodes+1); add_opcode(splev, SPO_PUSH, jmp); add_opcode(splev, SPO_JMP, NULL); /* we must jump past it first, then CALL it, due to RETURN. */ tmpfunc->addr = splev->n_opcodes; { /* init function parameter variables */ struct lc_funcdefs_parm *tfp = tmpfunc->params; while (tfp) { add_opvars(splev, "iso", VA_PASS3(0, tfp->name, SPO_VAR_INIT)); tfp = tfp->next; } } splev_add_from(splev, &(tmpfunc->code)); set_opvar_int(jmp, splev->n_opcodes - jmp->vardata.l); } l = tmpfunc->addr - splev->n_opcodes - 2; add_opvars(splev, "iio", VA_PASS3(nparams, l, SPO_CALL)); tmpfunc->n_called++; } else { lc_error("Function '%s' not defined.", yyvsp[-3].map); } Free(yyvsp[-3].map); } break; case 130: { add_opcode(splev, SPO_EXIT, NULL); } break; case 131: { yyval.i = 100; } break; case 132: { yyval.i = yyvsp[0].i; } break; case 133: { /* val > rn2(100) */ add_opvars(splev, "iio", VA_PASS3((long)yyvsp[0].i, 100, SPO_RN2)); yyval.i = SPO_JG; } break; case 134: { yyval.i = yyvsp[-2].i; } break; case 135: { /* boolean, explicit foo != 0 */ add_opvars(splev, "i", VA_PASS1(0)); yyval.i = SPO_JNE; } break; case 136: { is_inconstant_number = 0; } break; case 137: { struct opvar *chkjmp; if (in_switch_statement > 0) lc_error("Cannot nest switch-statements."); in_switch_statement++; n_switch_case_list = 0; switch_default_case = NULL; if (!is_inconstant_number) add_opvars(splev, "o", VA_PASS1(SPO_RN2)); is_inconstant_number = 0; chkjmp = New(struct opvar); set_opvar_int(chkjmp, splev->n_opcodes+1); switch_check_jump = chkjmp; add_opcode(splev, SPO_PUSH, chkjmp); add_opcode(splev, SPO_JMP, NULL); break_stmt_start(); } break; case 138: { struct opvar *endjump = New(struct opvar); int i; set_opvar_int(endjump, splev->n_opcodes+1); add_opcode(splev, SPO_PUSH, endjump); add_opcode(splev, SPO_JMP, NULL); set_opvar_int(switch_check_jump, splev->n_opcodes - switch_check_jump->vardata.l); for (i = 0; i < n_switch_case_list; i++) { add_opvars(splev, "oio", VA_PASS3(SPO_COPY, switch_case_value[i], SPO_CMP)); set_opvar_int(switch_case_list[i], switch_case_list[i]->vardata.l - splev->n_opcodes-1); add_opcode(splev, SPO_PUSH, switch_case_list[i]); add_opcode(splev, SPO_JE, NULL); } if (switch_default_case) { set_opvar_int(switch_default_case, switch_default_case->vardata.l - splev->n_opcodes-1); add_opcode(splev, SPO_PUSH, switch_default_case); add_opcode(splev, SPO_JMP, NULL); } set_opvar_int(endjump, splev->n_opcodes - endjump->vardata.l); break_stmt_end(splev); add_opcode(splev, SPO_POP, NULL); /* get rid of the value in stack */ in_switch_statement--; } break; case 141: { if (n_switch_case_list < MAX_SWITCH_CASES) { struct opvar *tmppush = New(struct opvar); set_opvar_int(tmppush, splev->n_opcodes); switch_case_value[n_switch_case_list] = yyvsp[-1].i; switch_case_list[n_switch_case_list++] = tmppush; } else lc_error("Too many cases in a switch."); } break; case 142: { } break; case 143: { struct opvar *tmppush = New(struct opvar); if (switch_default_case) lc_error("Switch default case already used."); set_opvar_int(tmppush, splev->n_opcodes); switch_default_case = tmppush; } break; case 144: { } break; case 145: { if (!allow_break_statements) lc_error("Cannot use BREAK outside a statement block."); else { break_stmt_new(splev, splev->n_opcodes); } } break; case 148: { char buf[256], buf2[256]; if (n_forloops >= MAX_NESTED_IFS) { lc_error("FOR: Too deeply nested loops."); n_forloops = MAX_NESTED_IFS - 1; } /* first, define a variable for the for-loop end value */ snprintf(buf, 255, "%s end", yyvsp[-4].map); /* the value of which is already in stack (the 2nd math_expr) */ add_opvars(splev, "iso", VA_PASS3(0, buf, SPO_VAR_INIT)); variable_definitions = add_vardef_type(variable_definitions, yyvsp[-4].map, SPOVAR_INT); /* define the for-loop variable. value is in stack (1st math_expr) */ add_opvars(splev, "iso", VA_PASS3(0, yyvsp[-4].map, SPO_VAR_INIT)); /* calculate value for the loop "step" variable */ snprintf(buf2, 255, "%s step", yyvsp[-4].map); /* end - start */ add_opvars(splev, "vvo", VA_PASS3(buf, yyvsp[-4].map, SPO_MATH_SUB)); /* sign of that */ add_opvars(splev, "o", VA_PASS1(SPO_MATH_SIGN)); /* save the sign into the step var */ add_opvars(splev, "iso", VA_PASS3(0, buf2, SPO_VAR_INIT)); forloop_list[n_forloops].varname = strdup(yyvsp[-4].map); forloop_list[n_forloops].jmp_point = splev->n_opcodes; n_forloops++; Free(yyvsp[-4].map); } break; case 149: { /* nothing */ break_stmt_start(); } break; case 150: { char buf[256], buf2[256]; n_forloops--; snprintf(buf, 255, "%s step", forloop_list[n_forloops].varname); snprintf(buf2, 255, "%s end", forloop_list[n_forloops].varname); /* compare for-loop var to end value */ add_opvars(splev, "vvo", VA_PASS3(forloop_list[n_forloops].varname, buf2, SPO_CMP)); /* var + step */ add_opvars(splev, "vvo", VA_PASS3(buf, forloop_list[n_forloops].varname, SPO_MATH_ADD)); /* for-loop var = (for-loop var + step) */ add_opvars(splev, "iso", VA_PASS3(0, forloop_list[n_forloops].varname, SPO_VAR_INIT)); /* jump back if compared values were not equal */ add_opvars(splev, "io", VA_PASS2( forloop_list[n_forloops].jmp_point - splev->n_opcodes - 1, SPO_JNE)); Free(forloop_list[n_forloops].varname); break_stmt_end(splev); } break; case 151: { struct opvar *tmppush = New(struct opvar); if (n_if_list >= MAX_NESTED_IFS) { lc_error("LOOP: Too deeply nested conditionals."); n_if_list = MAX_NESTED_IFS - 1; } set_opvar_int(tmppush, splev->n_opcodes); if_list[n_if_list++] = tmppush; add_opvars(splev, "o", VA_PASS1(SPO_DEC)); break_stmt_start(); } break; case 152: { struct opvar *tmppush; add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 0, SPO_CMP)); tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, tmppush->vardata.l - splev->n_opcodes-1); add_opcode(splev, SPO_PUSH, tmppush); add_opcode(splev, SPO_JG, NULL); add_opcode(splev, SPO_POP, NULL); /* get rid of the count value in stack */ break_stmt_end(splev); } break; case 153: { struct opvar *tmppush2 = New(struct opvar); if (n_if_list >= MAX_NESTED_IFS) { lc_error("IF: Too deeply nested conditionals."); n_if_list = MAX_NESTED_IFS - 1; } add_opcode(splev, SPO_CMP, NULL); set_opvar_int(tmppush2, splev->n_opcodes+1); if_list[n_if_list++] = tmppush2; add_opcode(splev, SPO_PUSH, tmppush2); add_opcode(splev, reverse_jmp_opcode( yyvsp[-1].i ), NULL); } break; case 154: { if (n_if_list > 0) { struct opvar *tmppush; tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); } else lc_error("IF: Huh?! No start address?"); } break; case 155: { struct opvar *tmppush2 = New(struct opvar); if (n_if_list >= MAX_NESTED_IFS) { lc_error("IF: Too deeply nested conditionals."); n_if_list = MAX_NESTED_IFS - 1; } add_opcode(splev, SPO_CMP, NULL); set_opvar_int(tmppush2, splev->n_opcodes+1); if_list[n_if_list++] = tmppush2; add_opcode(splev, SPO_PUSH, tmppush2); add_opcode(splev, reverse_jmp_opcode( yyvsp[0].i ), NULL); } break; case 156: { /* do nothing */ } break; case 157: { if (n_if_list > 0) { struct opvar *tmppush; tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); } else lc_error("IF: Huh?! No start address?"); } break; case 158: { if (n_if_list > 0) { struct opvar *tmppush = New(struct opvar); struct opvar *tmppush2; set_opvar_int(tmppush, splev->n_opcodes+1); add_opcode(splev, SPO_PUSH, tmppush); add_opcode(splev, SPO_JMP, NULL); tmppush2 = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush2, splev->n_opcodes - tmppush2->vardata.l); if_list[n_if_list++] = tmppush; } else lc_error("IF: Huh?! No else-part address?"); } break; case 159: { if (n_if_list > 0) { struct opvar *tmppush; tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); } else lc_error("IF: Huh?! No end address?"); } break; case 160: { add_opvars(splev, "o", VA_PASS1(SPO_MESSAGE)); } break; case 161: { add_opvars(splev, "iiiiiio", VA_PASS7(-1, 0, -1, -1, -1, -1, SPO_CORRIDOR)); } break; case 162: { add_opvars(splev, "iiiiiio", VA_PASS7(-1, yyvsp[0].i, -1, -1, -1, -1, SPO_CORRIDOR)); } break; case 163: { add_opvars(splev, "iiiiiio", VA_PASS7(-1, -1, -1, -1, -1, -1, SPO_CORRIDOR)); } break; case 164: { add_opvars(splev, "iiiiiio", VA_PASS7(yyvsp[-2].corpos.room, yyvsp[-2].corpos.door, yyvsp[-2].corpos.wall, yyvsp[0].corpos.room, yyvsp[0].corpos.door, yyvsp[0].corpos.wall, SPO_CORRIDOR)); } break; case 165: { add_opvars(splev, "iiiiiio", VA_PASS7(yyvsp[-2].corpos.room, yyvsp[-2].corpos.door, yyvsp[-2].corpos.wall, -1, -1, (long)yyvsp[0].i, SPO_CORRIDOR)); } break; case 166: { yyval.corpos.room = yyvsp[-5].i; yyval.corpos.wall = yyvsp[-3].i; yyval.corpos.door = yyvsp[-1].i; } break; case 167: { if ((yyvsp[-2].i < 100) && (yyvsp[-3].i == OROOM)) lc_error("Only typed rooms can have a chance."); else { add_opvars(splev, "iii", VA_PASS3((long)yyvsp[-3].i, (long)yyvsp[-2].i, (long)yyvsp[0].i)); } } break; case 168: { long rflags = yyvsp[0].i; if (rflags == -1) rflags = (1 << 0); add_opvars(splev, "iiiiiiio", VA_PASS8(rflags, ERR, ERR, yyvsp[-3].crd.x, yyvsp[-3].crd.y, yyvsp[-1].sze.width, yyvsp[-1].sze.height, SPO_SUBROOM)); break_stmt_start(); } break; case 169: { break_stmt_end(splev); add_opcode(splev, SPO_ENDROOM, NULL); } break; case 170: { long rflags = yyvsp[-2].i; if (rflags == -1) rflags = (1 << 0); add_opvars(splev, "iiiiiiio", VA_PASS8(rflags, yyvsp[-3].crd.x, yyvsp[-3].crd.y, yyvsp[-5].crd.x, yyvsp[-5].crd.y, yyvsp[-1].sze.width, yyvsp[-1].sze.height, SPO_ROOM)); break_stmt_start(); } break; case 171: { break_stmt_end(splev); add_opcode(splev, SPO_ENDROOM, NULL); } break; case 172: { yyval.i = 1; } break; case 173: { yyval.i = yyvsp[0].i; } break; case 174: { if ( yyvsp[-3].i < 1 || yyvsp[-3].i > 5 || yyvsp[-1].i < 1 || yyvsp[-1].i > 5 ) { lc_error("Room positions should be between 1-5: (%li,%li)!", yyvsp[-3].i, yyvsp[-1].i); } else { yyval.crd.x = yyvsp[-3].i; yyval.crd.y = yyvsp[-1].i; } } break; case 175: { yyval.crd.x = yyval.crd.y = ERR; } break; case 176: { if ( yyvsp[-3].i < 0 || yyvsp[-1].i < 0) { lc_error("Invalid subroom position (%li,%li)!", yyvsp[-3].i, yyvsp[-1].i); } else { yyval.crd.x = yyvsp[-3].i; yyval.crd.y = yyvsp[-1].i; } } break; case 177: { yyval.crd.x = yyval.crd.y = ERR; } break; case 178: { yyval.crd.x = yyvsp[-3].i; yyval.crd.y = yyvsp[-1].i; } break; case 179: { yyval.crd.x = yyval.crd.y = ERR; } break; case 180: { yyval.sze.width = yyvsp[-3].i; yyval.sze.height = yyvsp[-1].i; } break; case 181: { yyval.sze.height = yyval.sze.width = ERR; } break; case 182: { /* ERR means random here */ if (yyvsp[-2].i == ERR && yyvsp[0].i != ERR) { lc_error("If the door wall is random, so must be its pos!"); } else { add_opvars(splev, "iiiio", VA_PASS5((long)yyvsp[0].i, (long)yyvsp[-4].i, (long)yyvsp[-6].i, (long)yyvsp[-2].i, SPO_ROOM_DOOR)); } } break; case 183: { add_opvars(splev, "io", VA_PASS2((long)yyvsp[-2].i, SPO_DOOR)); } break; case 188: { yyval.i = yyvsp[0].i; } break; case 189: { yyval.i = (yyvsp[-2].i | yyvsp[0].i); } break; case 192: { add_opvars(splev, "ciisiio", VA_PASS7(0, 0, 1, (char *)0, 0, 0, SPO_MAP)); max_x_map = COLNO-1; max_y_map = ROWNO; } break; case 193: { add_opvars(splev, "cii", VA_PASS3(SP_COORD_PACK((yyvsp[-4].i),(yyvsp[-2].i)), 1, (long)yyvsp[-1].i)); scan_map(yyvsp[0].map, splev); Free(yyvsp[0].map); } break; case 194: { add_opvars(splev, "ii", VA_PASS2(2, (long)yyvsp[-1].i)); scan_map(yyvsp[0].map, splev); Free(yyvsp[0].map); } break; case 199: { add_opvars(splev, "io", VA_PASS2(0, SPO_MONSTER)); } break; case 200: { add_opvars(splev, "io", VA_PASS2(1, SPO_MONSTER)); in_container_obj++; break_stmt_start(); } break; case 201: { break_stmt_end(splev); in_container_obj--; add_opvars(splev, "o", VA_PASS1(SPO_END_MONINVENT)); } break; case 202: { /* nothing */ } break; case 203: { struct opvar *stopit = New(struct opvar); set_opvar_int(stopit, SP_M_V_END); add_opcode(splev, SPO_PUSH, stopit); yyval.i = 0x0000; } break; case 204: { if (( yyvsp[-2].i & yyvsp[0].i )) lc_error("MONSTER extra info defined twice."); yyval.i = ( yyvsp[-2].i | yyvsp[0].i ); } break; case 205: { add_opvars(splev, "i", VA_PASS1(SP_M_V_NAME)); yyval.i = 0x0001; } break; case 206: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[0].i, SP_M_V_PEACEFUL)); yyval.i = 0x0002; } break; case 207: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[0].i, SP_M_V_ASLEEP)); yyval.i = 0x0004; } break; case 208: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[0].i, SP_M_V_ALIGN)); yyval.i = 0x0008; } break; case 209: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[-1].i, SP_M_V_APPEAR)); yyval.i = 0x0010; } break; case 210: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_FEMALE)); yyval.i = 0x0020; } break; case 211: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_INVIS)); yyval.i = 0x0040; } break; case 212: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CANCELLED)); yyval.i = 0x0080; } break; case 213: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_REVIVED)); yyval.i = 0x0100; } break; case 214: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_AVENGE)); yyval.i = 0x0200; } break; case 215: { add_opvars(splev, "i", VA_PASS1(SP_M_V_FLEEING)); yyval.i = 0x0400; } break; case 216: { add_opvars(splev, "i", VA_PASS1(SP_M_V_BLINDED)); yyval.i = 0x0800; } break; case 217: { add_opvars(splev, "i", VA_PASS1(SP_M_V_PARALYZED)); yyval.i = 0x1000; } break; case 218: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_STUNNED)); yyval.i = 0x2000; } break; case 219: { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CONFUSED)); yyval.i = 0x4000; } break; case 220: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[0].i, SP_M_V_SEENTRAPS)); yyval.i = 0x8000; } break; case 221: { int token = get_trap_type(yyvsp[0].map); if (token == ERR || token == 0) lc_error("Unknown trap type '%s'!", yyvsp[0].map); Free(yyvsp[0].map); yyval.i = (1L << (token - 1)); } break; case 222: { yyval.i = (long) ~0; } break; case 223: { int token = get_trap_type(yyvsp[-2].map); if (token == ERR || token == 0) lc_error("Unknown trap type '%s'!", yyvsp[-2].map); if ((1L << (token - 1)) & yyvsp[0].i) lc_error("Monster seen_traps, trap '%s' listed twice.", yyvsp[-2].map); Free(yyvsp[-2].map); yyval.i = ((1L << (token - 1)) | yyvsp[0].i); } break; case 224: { long cnt = 0; if (in_container_obj) cnt |= SP_OBJ_CONTENT; add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT)); } break; case 225: { long cnt = SP_OBJ_CONTAINER; if (in_container_obj) cnt |= SP_OBJ_CONTENT; add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT)); in_container_obj++; break_stmt_start(); } break; case 226: { break_stmt_end(splev); in_container_obj--; add_opcode(splev, SPO_POP_CONTAINER, NULL); } break; case 227: { if (( yyvsp[0].i & 0x4000) && in_container_obj) lc_error("Object cannot have a coord when contained."); else if (!( yyvsp[0].i & 0x4000) && !in_container_obj) lc_error("Object needs a coord when not contained."); } break; case 228: { struct opvar *stopit = New(struct opvar); set_opvar_int(stopit, SP_O_V_END); add_opcode(splev, SPO_PUSH, stopit); yyval.i = 0x00; } break; case 229: { if (( yyvsp[-2].i & yyvsp[0].i )) lc_error("OBJECT extra info '%s' defined twice.", curr_token); yyval.i = ( yyvsp[-2].i | yyvsp[0].i ); } break; case 230: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[0].i, SP_O_V_CURSE)); yyval.i = 0x0001; } break; case 231: { add_opvars(splev, "i", VA_PASS1(SP_O_V_CORPSENM)); yyval.i = 0x0002; } break; case 232: { add_opvars(splev, "i", VA_PASS1(SP_O_V_SPE)); yyval.i = 0x0004; } break; case 233: { add_opvars(splev, "i", VA_PASS1(SP_O_V_NAME)); yyval.i = 0x0008; } break; case 234: { add_opvars(splev, "i", VA_PASS1(SP_O_V_QUAN)); yyval.i = 0x0010; } break; case 235: { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BURIED)); yyval.i = 0x0020; } break; case 236: { add_opvars(splev, "ii", VA_PASS2((long)yyvsp[0].i, SP_O_V_LIT)); yyval.i = 0x0040; } break; case 237: { add_opvars(splev, "i", VA_PASS1(SP_O_V_ERODED)); yyval.i = 0x0080; } break; case 238: { add_opvars(splev, "ii", VA_PASS2(-1, SP_O_V_ERODED)); yyval.i = 0x0080; } break; case 239: { if (yyvsp[0].i == D_LOCKED) { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_LOCKED)); yyval.i = 0x0100; } else if (yyvsp[0].i == D_BROKEN) { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BROKEN)); yyval.i = 0x0200; } else lc_error("DOOR state can only be locked or broken."); } break; case 240: { add_opvars(splev, "ii", VA_PASS2(yyvsp[0].i, SP_O_V_TRAPPED)); yyval.i = 0x0400; } break; case 241: { add_opvars(splev, "i", VA_PASS1(SP_O_V_RECHARGED)); yyval.i = 0x0800; } break; case 242: { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_INVIS)); yyval.i = 0x1000; } break; case 243: { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_GREASED)); yyval.i = 0x2000; } break; case 244: { add_opvars(splev, "i", VA_PASS1(SP_O_V_COORD)); yyval.i = 0x4000; } break; case 245: { add_opvars(splev, "io", VA_PASS2((long)yyvsp[-2].i, SPO_TRAP)); } break; case 246: { long dir, state = 0; /* convert dir from a DIRECTION to a DB_DIR */ dir = yyvsp[-2].i; switch (dir) { case W_NORTH: dir = DB_NORTH; break; case W_SOUTH: dir = DB_SOUTH; break; case W_EAST: dir = DB_EAST; break; case W_WEST: dir = DB_WEST; break; default: lc_error("Invalid drawbridge direction."); break; } if ( yyvsp[0].i == D_ISOPEN ) state = 1; else if ( yyvsp[0].i == D_CLOSED ) state = 0; else if ( yyvsp[0].i == -1 ) state = -1; else lc_error("A drawbridge can only be open, closed or random!"); add_opvars(splev, "iio", VA_PASS3(state, dir, SPO_DRAWBRIDGE)); } break; case 247: { add_opvars(splev, "iiio", VA_PASS4((long)yyvsp[0].i, 1, 0, SPO_MAZEWALK)); } break; case 248: { add_opvars(splev, "iiio", VA_PASS4((long)yyvsp[-3].i, (long)yyvsp[-1].i, (long)yyvsp[0].i, SPO_MAZEWALK)); } break; case 249: { add_opvars(splev, "rio", VA_PASS3(SP_REGION_PACK(-1,-1,-1,-1), 0, SPO_WALLIFY)); } break; case 250: { add_opvars(splev, "io", VA_PASS2(1, SPO_WALLIFY)); } break; case 251: { add_opvars(splev, "io", VA_PASS2((long)yyvsp[0].i, SPO_LADDER)); } break; case 252: { add_opvars(splev, "io", VA_PASS2((long)yyvsp[0].i, SPO_STAIR)); } break; case 253: { add_opvars(splev, "iiiii iiiii iiso", VA_PASS14(yyvsp[-4].lregn.x1, yyvsp[-4].lregn.y1, yyvsp[-4].lregn.x2, yyvsp[-4].lregn.y2, yyvsp[-4].lregn.area, yyvsp[-2].lregn.x1, yyvsp[-2].lregn.y1, yyvsp[-2].lregn.x2, yyvsp[-2].lregn.y2, yyvsp[-2].lregn.area, (long)((yyvsp[0].i) ? LR_UPSTAIR : LR_DOWNSTAIR), 0, (char *)0, SPO_LEVREGION)); } break; case 254: { add_opvars(splev, "iiiii iiiii iiso", VA_PASS14(yyvsp[-4].lregn.x1, yyvsp[-4].lregn.y1, yyvsp[-4].lregn.x2, yyvsp[-4].lregn.y2, yyvsp[-4].lregn.area, yyvsp[-2].lregn.x1, yyvsp[-2].lregn.y1, yyvsp[-2].lregn.x2, yyvsp[-2].lregn.y2, yyvsp[-2].lregn.area, LR_PORTAL, 0, yyvsp[0].map, SPO_LEVREGION)); Free(yyvsp[0].map); } break; case 255: { long rtyp = 0; switch(yyvsp[0].i) { case -1: rtyp = LR_TELE; break; case 0: rtyp = LR_DOWNTELE; break; case 1: rtyp = LR_UPTELE; break; } add_opvars(splev, "iiiii iiiii iiso", VA_PASS14(yyvsp[-3].lregn.x1, yyvsp[-3].lregn.y1, yyvsp[-3].lregn.x2, yyvsp[-3].lregn.y2, yyvsp[-3].lregn.area, yyvsp[-1].lregn.x1, yyvsp[-1].lregn.y1, yyvsp[-1].lregn.x2, yyvsp[-1].lregn.y2, yyvsp[-1].lregn.area, rtyp, 0, (char *)0, SPO_LEVREGION)); } break; case 256: { add_opvars(splev, "iiiii iiiii iiso", VA_PASS14(yyvsp[-2].lregn.x1, yyvsp[-2].lregn.y1, yyvsp[-2].lregn.x2, yyvsp[-2].lregn.y2, yyvsp[-2].lregn.area, yyvsp[0].lregn.x1, yyvsp[0].lregn.y1, yyvsp[0].lregn.x2, yyvsp[0].lregn.y2, yyvsp[0].lregn.area, (long)LR_BRANCH, 0, (char *)0, SPO_LEVREGION)); } break; case 257: { yyval.i = -1; } break; case 258: { yyval.i = yyvsp[0].i; } break; case 259: { add_opvars(splev, "o", VA_PASS1(SPO_FOUNTAIN)); } break; case 260: { add_opvars(splev, "o", VA_PASS1(SPO_SINK)); } break; case 261: { add_opvars(splev, "o", VA_PASS1(SPO_POOL)); } break; case 262: { yyval.terr.lit = -2; yyval.terr.ter = what_map_char((char) yyvsp[0].i); } break; case 263: { yyval.terr.lit = yyvsp[-1].i; yyval.terr.ter = what_map_char((char) yyvsp[-3].i); } break; case 264: { add_opvars(splev, "io", VA_PASS2(yyvsp[0].i, SPO_REPLACETERRAIN)); } break; case 265: { add_opvars(splev, "o", VA_PASS1(SPO_TERRAIN)); } break; case 266: { add_opvars(splev, "o", VA_PASS1(SPO_NON_DIGGABLE)); } break; case 267: { add_opvars(splev, "o", VA_PASS1(SPO_NON_PASSWALL)); } break; case 268: { long irr; long rt = yyvsp[-1].i; long rflags = yyvsp[0].i; if (rflags == -1) rflags = (1 << 0); if (!(rflags & 1)) rt += MAXRTYPE+1; irr = ((rflags & 2) != 0); add_opvars(splev, "iiio", VA_PASS4((long)yyvsp[-3].i, rt, rflags, SPO_REGION)); yyval.i = (irr || (rflags & 1) || rt != OROOM); break_stmt_start(); } break; case 269: { break_stmt_end(splev); if ( yyvsp[-1].i ) { add_opcode(splev, SPO_ENDROOM, NULL); } else if ( yyvsp[0].i ) lc_error("Cannot use lev statements in non-permanent REGION"); } break; case 270: { yyval.i = 0; } break; case 271: { yyval.i = yyvsp[0].i; } break; case 272: { add_opvars(splev, "iio", VA_PASS3((long)yyvsp[0].i, (long)yyvsp[-2].i, SPO_ALTAR)); } break; case 273: { add_opvars(splev, "io", VA_PASS2(2, SPO_GRAVE)); } break; case 274: { add_opvars(splev, "sio", VA_PASS3((char *)0, 1, SPO_GRAVE)); } break; case 275: { add_opvars(splev, "sio", VA_PASS3((char *)0, 0, SPO_GRAVE)); } break; case 276: { add_opvars(splev, "o", VA_PASS1(SPO_GOLD)); } break; case 277: { add_opvars(splev, "io", VA_PASS2((long)yyvsp[-2].i, SPO_ENGRAVING)); } break; case 278: { add_opvars(splev, "o", VA_PASS1(SPO_MINERALIZE)); } break; case 279: { add_opvars(splev, "iiiio", VA_PASS5(-1L, -1L, -1L, -1L, SPO_MINERALIZE)); } break; case 280: { int token = get_trap_type(yyvsp[0].map); if (token == ERR) lc_error("Unknown trap type '%s'!", yyvsp[0].map); yyval.i = token; Free(yyvsp[0].map); } break; case 282: { int token = get_room_type(yyvsp[0].map); if (token == ERR) { lc_warning("Unknown room type \"%s\"! Making ordinary room...", yyvsp[0].map); yyval.i = OROOM; } else yyval.i = token; Free(yyvsp[0].map); } break; case 284: { yyval.i = -1; } break; case 285: { yyval.i = yyvsp[0].i; } break; case 286: { yyval.i = yyvsp[0].i; } break; case 287: { yyval.i = yyvsp[-2].i | yyvsp[0].i; } break; case 288: { yyval.i = (yyvsp[0].i << 0); } break; case 289: { yyval.i = (yyvsp[0].i << 1); } break; case 290: { yyval.i = (yyvsp[0].i << 2); } break; case 297: { yyval.i = - MAX_REGISTERS - 1; } break; case 300: { yyval.i = - MAX_REGISTERS - 1; } break; case 303: { if ( yyvsp[-1].i >= 3 ) lc_error("Register Index overflow!"); else yyval.i = - yyvsp[-1].i - 1; } break; case 304: { add_opvars(splev, "s", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 305: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_STRING); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 306: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_STRING|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); } break; case 307: { /* nothing */ } break; case 308: { add_opvars(splev, "c", VA_PASS1(yyvsp[0].i)); } break; case 309: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDCOORD)); } break; case 310: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_COORD); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 311: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_COORD|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); } break; case 312: { if (yyvsp[-3].i < 0 || yyvsp[-1].i < 0 || yyvsp[-3].i >= COLNO || yyvsp[-1].i >= ROWNO) lc_error("Coordinates (%li,%li) out of map range!", yyvsp[-3].i, yyvsp[-1].i); yyval.i = SP_COORD_PACK(yyvsp[-3].i, yyvsp[-1].i); } break; case 313: { yyval.i = SP_COORD_PACK_RANDOM(0); } break; case 314: { yyval.i = SP_COORD_PACK_RANDOM( yyvsp[-1].i ); } break; case 315: { yyval.i = yyvsp[0].i; } break; case 316: { if ((yyvsp[-2].i & yyvsp[0].i)) lc_warning("Humidity flag used twice."); yyval.i = (yyvsp[-2].i | yyvsp[0].i); } break; case 317: { /* nothing */ } break; case 318: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_REGION); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 319: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_REGION|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); } break; case 320: { long r = SP_REGION_PACK(yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); if ( yyvsp[-7].i > yyvsp[-3].i || yyvsp[-5].i > yyvsp[-1].i ) lc_error("Region start > end: (%li,%li,%li,%li)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); add_opvars(splev, "r", VA_PASS1(r)); yyval.i = r; } break; case 321: { add_opvars(splev, "m", VA_PASS1(yyvsp[0].i)); } break; case 322: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_MAPCHAR); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 323: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_MAPCHAR|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); } break; case 324: { if (what_map_char((char) yyvsp[0].i) != INVALID_TYPE) yyval.i = SP_MAPCHAR_PACK(what_map_char((char) yyvsp[0].i), -2); else { lc_error("Unknown map char type '%c'!", yyvsp[0].i); yyval.i = SP_MAPCHAR_PACK(STONE, -2); } } break; case 325: { if (what_map_char((char) yyvsp[-3].i) != INVALID_TYPE) yyval.i = SP_MAPCHAR_PACK(what_map_char((char) yyvsp[-3].i), yyvsp[-1].i); else { lc_error("Unknown map char type '%c'!", yyvsp[-3].i); yyval.i = SP_MAPCHAR_PACK(STONE, yyvsp[-1].i); } } break; case 326: { add_opvars(splev, "M", VA_PASS1(yyvsp[0].i)); } break; case 327: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_MONST); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 328: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_MONST|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); } break; case 329: { long m = get_monster_id(yyvsp[0].map, (char)0); if (m == ERR) { lc_error("Unknown monster \"%s\"!", yyvsp[0].map); yyval.i = -1; } else yyval.i = SP_MONST_PACK(m, def_monsyms[(int)mons[m].mlet].sym); Free(yyvsp[0].map); } break; case 330: { if (check_monster_char((char) yyvsp[0].i)) yyval.i = SP_MONST_PACK(-1, yyvsp[0].i); else { lc_error("Unknown monster class '%c'!", yyvsp[0].i); yyval.i = -1; } } break; case 331: { long m = get_monster_id(yyvsp[-1].map, (char) yyvsp[-3].i); if (m == ERR) { lc_error("Unknown monster ('%c', \"%s\")!", yyvsp[-3].i, yyvsp[-1].map); yyval.i = -1; } else yyval.i = SP_MONST_PACK(m, yyvsp[-3].i); Free(yyvsp[-1].map); } break; case 332: { yyval.i = -1; } break; case 333: { add_opvars(splev, "O", VA_PASS1(yyvsp[0].i)); } break; case 334: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_OBJ); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 335: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_OBJ|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); } break; case 336: { long m = get_object_id(yyvsp[0].map, (char)0); if (m == ERR) { lc_error("Unknown object \"%s\"!", yyvsp[0].map); yyval.i = -1; } else yyval.i = SP_OBJ_PACK(m, 1); /* obj class != 0 to force generation of a specific item */ Free(yyvsp[0].map); } break; case 337: { if (check_object_char((char) yyvsp[0].i)) yyval.i = SP_OBJ_PACK(-1, yyvsp[0].i); else { lc_error("Unknown object class '%c'!", yyvsp[0].i); yyval.i = -1; } } break; case 338: { long m = get_object_id(yyvsp[-1].map, (char) yyvsp[-3].i); if (m == ERR) { lc_error("Unknown object ('%c', \"%s\")!", yyvsp[-3].i, yyvsp[-1].map); yyval.i = -1; } else yyval.i = SP_OBJ_PACK(m, yyvsp[-3].i); Free(yyvsp[-1].map); } break; case 339: { yyval.i = -1; } break; case 340: { } break; case 341: { add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD)); } break; case 342: { add_opvars(splev, "i", VA_PASS1(yyvsp[0].i)); } break; case 343: { is_inconstant_number = 1; } break; case 344: { add_opvars(splev, "i", VA_PASS1(yyvsp[-1].i)); } break; case 345: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_INT); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); is_inconstant_number = 1; } break; case 346: { check_vardef_type(variable_definitions, yyvsp[-3].map, SPOVAR_INT|SPOVAR_ARRAY); vardef_used(variable_definitions, yyvsp[-3].map); add_opvars(splev, "v", VA_PASS1(yyvsp[-3].map)); Free(yyvsp[-3].map); is_inconstant_number = 1; } break; case 347: { add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD)); } break; case 348: { add_opvars(splev, "o", VA_PASS1(SPO_MATH_SUB)); } break; case 349: { add_opvars(splev, "o", VA_PASS1(SPO_MATH_MUL)); } break; case 350: { add_opvars(splev, "o", VA_PASS1(SPO_MATH_DIV)); } break; case 351: { add_opvars(splev, "o", VA_PASS1(SPO_MATH_MOD)); } break; case 352: { } break; case 353: { if (!strcmp("int", yyvsp[0].map) || !strcmp("integer", yyvsp[0].map)) { yyval.i = (int)'i'; } else lc_error("Unknown function parameter type '%s'", yyvsp[0].map); } break; case 354: { if (!strcmp("str", yyvsp[0].map) || !strcmp("string", yyvsp[0].map)) { yyval.i = (int)'s'; } else lc_error("Unknown function parameter type '%s'", yyvsp[0].map); } break; case 355: { struct lc_funcdefs_parm *tmp = New(struct lc_funcdefs_parm); if (!curr_function) { lc_error("Function parameters outside function definition."); } else if (!tmp) { lc_error("Could not alloc function params."); } else { long vt; tmp->name = strdup(yyvsp[-2].map); tmp->parmtype = (char) yyvsp[0].i; tmp->next = curr_function->params; curr_function->params = tmp; curr_function->n_params++; switch (tmp->parmtype) { case 'i': vt = SPOVAR_INT; break; case 's': vt = SPOVAR_STRING; break; default: lc_error("Unknown func param conversion."); break; } variable_definitions = add_vardef_type( variable_definitions, yyvsp[-2].map, vt); } Free(yyvsp[-2].map); } break; case 360: { yyval.i = (int)'i'; } break; case 361: { yyval.i = (int)'s'; } break; case 362: { char tmpbuf[2]; tmpbuf[0] = (char) yyvsp[0].i; tmpbuf[1] = '\0'; yyval.map = strdup(tmpbuf); } break; case 363: { long len = strlen( yyvsp[-2].map ); char *tmp = (char *)alloc(len + 2); sprintf(tmp, "%c%s", (char) yyvsp[0].i, yyvsp[-2].map ); Free( yyvsp[-2].map ); yyval.map = tmp; } break; case 364: { yyval.map = strdup(""); } break; case 365: { char *tmp = strdup( yyvsp[0].map ); Free( yyvsp[0].map ); yyval.map = tmp; } break; case 366: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_POINT)); } break; case 367: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_RECT)); } break; case 368: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_FILLRECT)); } break; case 369: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_LINE)); } break; case 370: { /* randline (x1,y1),(x2,y2), roughness */ add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDLINE)); } break; case 371: { add_opvars(splev, "io", VA_PASS2(W_ANY, SPO_SEL_GROW)); } break; case 372: { add_opvars(splev, "io", VA_PASS2(yyvsp[-3].i, SPO_SEL_GROW)); } break; case 373: { add_opvars(splev, "iio", VA_PASS3(yyvsp[-3].i, SPOFILTER_PERCENT, SPO_SEL_FILTER)); } break; case 374: { add_opvars(splev, "io", VA_PASS2(SPOFILTER_SELECTION, SPO_SEL_FILTER)); } break; case 375: { add_opvars(splev, "io", VA_PASS2(SPOFILTER_MAPCHAR, SPO_SEL_FILTER)); } break; case 376: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_FLOOD)); } break; case 377: { add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 1, SPO_SEL_ELLIPSE)); } break; case 378: { add_opvars(splev, "oio", VA_PASS3(SPO_COPY, yyvsp[-1].i, SPO_SEL_ELLIPSE)); } break; case 379: { add_opvars(splev, "io", VA_PASS2(1, SPO_SEL_ELLIPSE)); } break; case 380: { add_opvars(splev, "io", VA_PASS2(yyvsp[-1].i, SPO_SEL_ELLIPSE)); } break; case 381: { add_opvars(splev, "iio", VA_PASS3(yyvsp[-5].i, yyvsp[-11].i, SPO_SEL_GRADIENT)); } break; case 382: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_COMPLEMENT)); } break; case 383: { check_vardef_type(variable_definitions, yyvsp[0].map, SPOVAR_SEL); vardef_used(variable_definitions, yyvsp[0].map); add_opvars(splev, "v", VA_PASS1(yyvsp[0].map)); Free(yyvsp[0].map); } break; case 384: { /* nothing */ } break; case 385: { /* nothing */ } break; case 386: { add_opvars(splev, "o", VA_PASS1(SPO_SEL_ADD)); } break; case 387: { add_opvars(splev, "iio", VA_PASS3(yyvsp[0].dice.num, yyvsp[0].dice.die, SPO_DICE)); } break; case 391: { add_opvars(splev, "i", VA_PASS1(yyvsp[0].i)); } break; case 392: { add_opvars(splev, "i", VA_PASS1(yyvsp[0].i)); } break; case 393: { add_opvars(splev, "i", VA_PASS1(yyvsp[0].i)); } break; case 394: { /* nothing */ } break; case 403: { yyval.lregn = yyvsp[0].lregn; } break; case 404: { if (yyvsp[-7].i <= 0 || yyvsp[-7].i >= COLNO) lc_error("Region (%li,%li,%li,%li) out of level range (x1)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); else if (yyvsp[-5].i < 0 || yyvsp[-5].i >= ROWNO) lc_error("Region (%li,%li,%li,%li) out of level range (y1)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); else if (yyvsp[-3].i <= 0 || yyvsp[-3].i >= COLNO) lc_error("Region (%li,%li,%li,%li) out of level range (x2)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); else if (yyvsp[-1].i < 0 || yyvsp[-1].i >= ROWNO) lc_error("Region (%li,%li,%li,%li) out of level range (y2)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); yyval.lregn.x1 = yyvsp[-7].i; yyval.lregn.y1 = yyvsp[-5].i; yyval.lregn.x2 = yyvsp[-3].i; yyval.lregn.y2 = yyvsp[-1].i; yyval.lregn.area = 1; } break; case 405: { /* This series of if statements is a hack for MSC 5.1. It seems that its tiny little brain cannot compile if these are all one big if statement. */ if (yyvsp[-7].i < 0 || yyvsp[-7].i > (int)max_x_map) lc_error("Region (%li,%li,%li,%li) out of map range (x1)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); else if (yyvsp[-5].i < 0 || yyvsp[-5].i > (int)max_y_map) lc_error("Region (%li,%li,%li,%li) out of map range (y1)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); else if (yyvsp[-3].i < 0 || yyvsp[-3].i > (int)max_x_map) lc_error("Region (%li,%li,%li,%li) out of map range (x2)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); else if (yyvsp[-1].i < 0 || yyvsp[-1].i > (int)max_y_map) lc_error("Region (%li,%li,%li,%li) out of map range (y2)!", yyvsp[-7].i, yyvsp[-5].i, yyvsp[-3].i, yyvsp[-1].i); yyval.lregn.area = 0; yyval.lregn.x1 = yyvsp[-7].i; yyval.lregn.y1 = yyvsp[-5].i; yyval.lregn.x2 = yyvsp[-3].i; yyval.lregn.y2 = yyvsp[-1].i; } break; } yyssp -= yym; yystate = *yyssp; yyvsp -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; *++yyssp = YYFINAL; *++yyvsp = yyval; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } if ((yyn = yygindex[yym]) != 0 && (yyn += yystate) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", YYPREFIX, *yyssp, yystate); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate; *++yyvsp = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: return (1); yyaccept: return (0); } nethack-3.6.0/sys/share/nhlan.c0000664000076400007660000000200112536476415015327 0ustar paxedpaxed/* NetHack 3.6 nhlan.c $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Michael Allison, 1997 */ /* NetHack may be freely redistributed. See license for details. */ /* * Currently shared by the following ports: * WIN32 * * The code in here is used to take advantage of added features * that might be available in a Local Area Network environment. * * Network Username of player */ #include "hack.h" #include #ifdef LAN_FEATURES void init_lan_features() { lan_username(); } /* * The get_lan_username() call is a required call, since some of * the other LAN features depend on a unique username being available. * */ char lusername[MAX_LAN_USERNAME]; int lusername_size = MAX_LAN_USERNAME; char * lan_username() { char *lu; lu = get_username(&lusername_size); if (lu) { Strcpy(lusername, lu); return lusername; } else return (char *) 0; } #endif /*LAN_FEATURES*/ /*nhlan.c*/ nethack-3.6.0/sys/share/pcmain.c0000664000076400007660000005455012631241231015474 0ustar paxedpaxed/* NetHack 3.6 pcmain.c $NHDT-Date: 1449116336 2015/12/03 04:18:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.66 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - MSDOS, OS/2, ST, Amiga, and Windows NetHack */ #include "hack.h" #include "dlb.h" #ifndef NO_SIGNAL #include #endif #include #if !defined(AMIGA) && !defined(GNUDOS) #include #else #ifdef GNUDOS #include #endif #endif #ifdef WIN32 #include "win32api.h" /* for GetModuleFileName */ #endif #ifdef __DJGPP__ #include /* for getcwd() prototype */ #endif char orgdir[PATHLEN]; /* also used in pcsys.c, amidos.c */ #ifdef TOS boolean run_from_desktop = TRUE; /* should we pause before exiting?? */ #ifdef __GNUC__ long _stksize = 16 * 1024; #endif #endif #ifdef AMIGA extern int bigscreen; void NDECL(preserve_icon); #endif STATIC_DCL void FDECL(process_options, (int argc, char **argv)); STATIC_DCL void NDECL(nhusage); #if defined(MICRO) || defined(WIN32) || defined(OS2) extern void FDECL(nethack_exit, (int)); #else #define nethack_exit exit #endif #ifdef WIN32 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ extern int redirect_stdout; /* from sys/share/pcsys.c */ char *NDECL(exename); char default_window_sys[] = "mswin"; #endif #if defined(MSWIN_GRAPHICS) extern void NDECL(mswin_destroy_reg); #endif #ifdef EXEPATH STATIC_DCL char *FDECL(exepath, (char *)); #endif int FDECL(main, (int, char **)); extern boolean FDECL(pcmain, (int, char **)); #if defined(__BORLANDC__) && !defined(_WIN32) void NDECL(startup); unsigned _stklen = STKSIZ; #endif /* If the graphics version is built, we don't need a main; it is skipped * to help MinGW decide which entry point to choose. If both main and * WinMain exist, the resulting executable won't work correctly. */ #ifndef __MINGW32__ int main(argc, argv) int argc; char *argv[]; { boolean resuming; sys_early_init(); #ifdef WIN32 Strcpy(default_window_sys, "tty"); #endif resuming = pcmain(argc, argv); #ifdef LAN_FEATURES init_lan_features(); #endif moveloop(resuming); nethack_exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif boolean pcmain(argc, argv) int argc; char *argv[]; { register int fd; register char *dir; #if defined(WIN32) char *envp = NULL; char *sptr = NULL; char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; boolean save_getreturn_status = getreturn_enabled; #endif #ifdef NOCWD_ASSUMPTIONS char failbuf[BUFSZ]; #endif boolean resuming = FALSE; /* assume new game */ #ifdef _MSC_VER # ifdef DEBUG /* set these appropriately for VS debugging */ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); /* | _CRTDBG_MODE_FILE);*/ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); /*| _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW);*/ /* use STDERR by default _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ # endif #endif #if defined(__BORLANDC__) && !defined(_WIN32) startup(); #endif #ifdef TOS long clock_time; if (*argv[0]) { /* only a CLI can give us argv[0] */ hname = argv[0]; run_from_desktop = FALSE; } else #endif hname = "NetHack"; /* used for syntax messages */ #ifndef WIN32 choose_windows(DEFAULT_WINDOW_SYS); #else choose_windows(default_window_sys); #endif #if !defined(AMIGA) && !defined(GNUDOS) /* Save current directory and make sure it gets restored when * the game is exited. */ if (getcwd(orgdir, sizeof orgdir) == (char *) 0) error("NetHack: current directory path too long"); #ifndef NO_SIGNAL signal(SIGINT, (SIG_RET_TYPE) nethack_exit); /* restore original directory */ #endif #endif /* !AMIGA && !GNUDOS */ dir = nh_getenv("NETHACKDIR"); if (dir == (char *) 0) dir = nh_getenv("HACKDIR"); #ifdef EXEPATH if (dir == (char *) 0) dir = exepath(argv[0]); #endif if (dir != (char *) 0) { (void) strncpy(hackdir, dir, PATHLEN - 1); hackdir[PATHLEN - 1] = '\0'; #ifdef NOCWD_ASSUMPTIONS { int prefcnt; fqn_prefix[0] = (char *) alloc(strlen(hackdir) + 2); Strcpy(fqn_prefix[0], hackdir); append_slash(fqn_prefix[0]); for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) fqn_prefix[prefcnt] = fqn_prefix[0]; #if defined(WIN32) || defined(MSDOS) /* sysconf should be searched for in this location */ envp = nh_getenv("COMMONPROGRAMFILES"); if (envp) { if ((sptr = index(envp, ';')) != 0) *sptr = '\0'; if (strlen(envp) > 0) { fqn_prefix[SYSCONFPREFIX] = (char *) alloc(strlen(envp) + 10); Strcpy(fqn_prefix[SYSCONFPREFIX], envp); append_slash(fqn_prefix[SYSCONFPREFIX]); Strcat(fqn_prefix[SYSCONFPREFIX], "NetHack\\"); } } /* user's home directory should default to this - unless * overridden */ envp = nh_getenv("USERPROFILE"); if (envp) { if ((sptr = index(envp, ';')) != 0) *sptr = '\0'; if (strlen(envp) > 0) { fqn_prefix[CONFIGPREFIX] = (char *) alloc(strlen(envp) + 2); Strcpy(fqn_prefix[CONFIGPREFIX], envp); append_slash(fqn_prefix[CONFIGPREFIX]); } } #endif } #endif #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(dir, 1); #endif } #ifdef AMIGA #ifdef CHDIR /* * If we're dealing with workbench, change the directory. Otherwise * we could get "Insert disk in drive 0" messages. (Must be done * before initoptions()).... */ if (argc == 0) chdirx(HACKDIR, 1); #endif ami_wininit_data(); #endif #ifdef WIN32 save_getreturn_status = getreturn_enabled; raw_clear_screen(); getreturn_enabled = TRUE; #endif initoptions(); #ifdef NOCWD_ASSUMPTIONS if (!validate_prefix_locations(failbuf)) { raw_printf("Some invalid directory locations were specified:\n\t%s\n", failbuf); nethack_exit(EXIT_FAILURE); } #endif #if defined(TOS) && defined(TEXTCOLOR) if (iflags.BIOS && iflags.use_color) set_colors(); #endif if (!hackdir[0]) #if !defined(LATTICE) && !defined(AMIGA) Strcpy(hackdir, orgdir); #else Strcpy(hackdir, HACKDIR); #endif if (argc > 1) { if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else */ argc--; argv++; dir = argv[0] + 2; if (*dir == '=' || *dir == ':') dir++; if (!*dir && argc > 1) { argc--; argv++; dir = argv[0]; } if (!*dir) error("Flag -d must be followed by a directory name."); Strcpy(hackdir, dir); } if (argc > 1) { /* * Now we know the directory containing 'record' and * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { #if defined(WIN32) int sfd = (int) _fileno(stdout); redirect_stdout = (sfd >= 0) ? !isatty(sfd) : 0; if (!redirect_stdout) { raw_printf( "-s is not supported for the Graphical Interface\n"); nethack_exit(EXIT_SUCCESS); } #endif #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(hackdir, 0); #endif #ifdef SYSCF initoptions(); #endif prscore(argc, argv); nethack_exit(EXIT_SUCCESS); } #ifdef MSWIN_GRAPHICS if (!strncmpi(argv[1], "-clearreg", 6)) { /* clear registry */ mswin_destroy_reg(); nethack_exit(EXIT_SUCCESS); } #endif /* Don't initialize the window system just to print usage */ if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) { nhusage(); nethack_exit(EXIT_SUCCESS); } } } #ifdef WIN32 getreturn_enabled = save_getreturn_status; #endif /* * It seems you really want to play. */ #ifdef TOS if (comp_times((long) time(&clock_time))) error("Your clock is incorrectly set!"); #endif if (!dlb_init()) { pline( "%s\n%s\n%s\n%s\n\nNetHack was unable to open the required file " "\"%s\".%s", copyright_banner_line(1), copyright_banner_line(2), copyright_banner_line(3), copyright_banner_line(4), DLBFILE, #ifdef WIN32 "\nAre you perhaps trying to run NetHack within a zip utility?"); #else ""); #endif error("dlb_init failure."); } u.uhp = 1; /* prevent RIP on early quits */ u.ux = 0; /* prevent flush_screen() */ /* chdir shouldn't be called before this point to keep the * code parallel to other ports. */ #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(hackdir, 1); #endif #if defined(MSDOS) || defined(WIN32) /* In 3.6.0, several ports process options before they init * the window port. This allows settings that impact window * ports to be specified or read from the sys or user config files. */ process_options(argc, argv); #ifdef WIN32 /* if (!strncmpi(windowprocs.name, "mswin", 5)) NHWinMainInit(); else */ if (!strncmpi(windowprocs.name, "tty", 3)) { iflags.use_background_glyph = FALSE; nttty_open(1); } else { iflags.use_background_glyph = TRUE; } #endif #endif #if defined(MSDOS) || defined(WIN32) /* Player didn't specify any symbol set so use IBM defaults */ if (!symset[PRIMARY].name) { load_symset("IBMGraphics_2", PRIMARY); } if (!symset[ROGUESET].name) { load_symset("RogueEpyx", ROGUESET); } #endif #if defined(MSDOS) || defined(WIN32) init_nhwindows(&argc, argv); #else init_nhwindows(&argc, argv); process_options(argc, argv); #endif #ifdef WIN32 toggle_mouse_support(); /* must come after process_options */ #endif #ifdef MFLOPPY set_lock_and_bones(); #ifndef AMIGA copybones(FROMPERM); #endif #endif /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); set_playmode(); /* sets plname to "wizard" for wizard mode */ #if 0 /* unlike Unix where the game might be invoked with a script which forces a particular character name for each player using a shared account, we always allow player to rename the character during role/race/&c selection */ iflags.renameallowed = TRUE; #else /* until the getlock code is resolved, override askname()'s setting of renameallowed; when False, player_selection() won't resent renaming as an option */ iflags.renameallowed = FALSE; #endif #if defined(PC_LOCKING) /* 3.3.0 added this to support detection of multiple games * under the same plname on the same machine in a windowed * or multitasking environment. * * That allows user confirmation prior to overwriting the * level files of a game in progress. * * Also prevents an aborted game's level files from being * overwritten without confirmation when a user starts up * another game with the same player name. */ #if defined(WIN32) /* Obtain the name of the logged on user and incorporate * it into the name. */ Sprintf(fnamebuf, "%s-%s", get_username(0), plname); (void) fname_encode( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', fnamebuf, encodedfnamebuf, BUFSZ); Sprintf(lock, "%s", encodedfnamebuf); /* regularize(lock); */ /* we encode now, rather than substitute */ #else Strcpy(lock, plname); regularize(lock); #endif getlock(); #else /* What follows is !PC_LOCKING */ #ifdef AMIGA /* We'll put the bones & levels in the user specified directory \ -jhsa */ Strcat(lock, plname); Strcat(lock, ".99"); #else #ifndef MFLOPPY /* I'm not sure what, if anything, is left here, but MFLOPPY has * conflicts with set_lock_and_bones() in files.c. */ Strcpy(lock, plname); Strcat(lock, ".99"); regularize(lock); /* is this necessary? */ /* not compatible with full path a la AMIGA */ #endif #endif #endif /* PC_LOCKING */ /* Set up level 0 file to keep the game state. */ fd = create_levelfile(0, (char *) 0); if (fd < 0) { raw_print("Cannot create lock file"); } else { #ifdef WIN32 hackpid = GetCurrentProcessId(); #else hackpid = 1; #endif write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); nhclose(fd); } #ifdef MFLOPPY level_info[0].where = ACTIVE; #endif /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); #ifdef WIN32 getreturn_enabled = TRUE; #endif /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. */ attempt_restore: if ((fd = restore_saved_game()) >= 0) { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif #ifdef NEWS if (iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if (dorecover(fd)) { resuming = TRUE; /* not starting new game */ if (discover) You("are in non-scoring discovery mode."); if (discover || wizard) { if (yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { nh_compress(fqname(SAVEF, SAVEPREFIX, 0)); } } } } if (!resuming) { /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name and skip selection this time if that didn't succeed */ if (!iflags.renameinprogress) { player_selection(); if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; discard current lock file and create another for the new character name */ #if 0 /* this needs to be reconciled with the getlock mess above... */ delete_levelfile(0); /* remove empty lock file */ getlock(); #endif goto attempt_restore; } } newgame(); if (discover) You("are in non-scoring discovery mode."); } #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #ifdef OS2 gettty(); /* somehow ctrl-P gets turned back on during startup ... */ #endif return resuming; } STATIC_OVL void process_options(argc, argv) int argc; char *argv[]; { int i; /* * Process options. */ while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case 'a': if (argv[0][2]) { if ((i = str2align(&argv[0][2])) >= 0) flags.initalign = i; } else if (argc > 1) { argc--; argv++; if ((i = str2align(argv[0])) >= 0) flags.initalign = i; } break; case 'D': wizard = TRUE, discover = FALSE; break; case 'X': discover = TRUE, wizard = FALSE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if (argv[0][2]) (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1); else if (argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname) - 1); } else raw_print("Player name expected after -u"); break; #ifndef AMIGA case 'I': case 'i': if (!strncmpi(argv[0] + 1, "IBM", 3)) { load_symset("IBMGraphics", PRIMARY); load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); } break; /* case 'D': */ case 'd': if (!strncmpi(argv[0] + 1, "DEC", 3)) { load_symset("DECGraphics", PRIMARY); switch_symbols(TRUE); } break; #endif case 'g': if (argv[0][2]) { if ((i = str2gend(&argv[0][2])) >= 0) flags.initgend = i; } else if (argc > 1) { argc--; argv++; if ((i = str2gend(argv[0])) >= 0) flags.initgend = i; } break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; #ifdef MFLOPPY #ifndef AMIGA /* Player doesn't want to use a RAM disk */ case 'R': ramdisk = FALSE; break; #endif #endif #ifdef AMIGA /* interlaced and non-interlaced screens */ case 'L': bigscreen = 1; break; case 'l': bigscreen = -1; break; #endif #ifdef WIN32 case 'w': /* windowtype */ if (strncmpi(&argv[0][2], "tty", 3)) { nttty_open(1); } /* else { NHWinMainInit(); } */ choose_windows(&argv[0][2]); break; #endif case '@': flags.randomall = 1; break; default: if ((i = str2role(&argv[0][1])) >= 0) { flags.initrole = i; break; } else raw_printf("\nUnknown switch: %s", argv[0]); /* FALL THROUGH */ case '?': nhusage(); nethack_exit(EXIT_SUCCESS); } } } STATIC_OVL void nhusage() { char buf1[BUFSZ], buf2[BUFSZ], *bufptr; buf1[0] = '\0'; bufptr = buf1; #define ADD_USAGE(s) \ if ((strlen(buf1) + strlen(s)) < (BUFSZ - 1)) \ Strcat(bufptr, s); /* -role still works for those cases which aren't already taken, but * is deprecated and will not be listed here. */ (void) Sprintf(buf2, "\nUsage:\n%s [-d dir] -s [-r race] [-p profession] " "[maxrank] [name]...\n or", hname); ADD_USAGE(buf2); (void) Sprintf( buf2, "\n%s [-d dir] [-u name] [-r race] [-p profession] [-[DX]]", hname); ADD_USAGE(buf2); #ifdef NEWS ADD_USAGE(" [-n]"); #endif #ifndef AMIGA ADD_USAGE(" [-I] [-i] [-d]"); #endif #ifdef MFLOPPY #ifndef AMIGA ADD_USAGE(" [-R]"); #endif #endif #ifdef AMIGA ADD_USAGE(" [-[lL]]"); #endif if (!iflags.window_inited) raw_printf("%s\n", buf1); else (void) printf("%s\n", buf1); #undef ADD_USAGE } #ifdef CHDIR void chdirx(dir, wr) char *dir; boolean wr; { #ifdef AMIGA static char thisdir[] = ""; #else static char thisdir[] = "."; #endif if (dir && chdir(dir) < 0) { error("Cannot chdir to %s.", dir); } #ifndef AMIGA /* Change the default drive as well. */ chdrive(dir); #endif /* warn the player if we can't write the record file */ /* perhaps we should also test whether . is writable */ /* unfortunately the access system-call is worthless */ if (wr) check_recordfile(dir ? dir : thisdir); } #endif /* CHDIR */ #ifdef PORT_HELP #if defined(MSDOS) || defined(WIN32) void port_help() { /* display port specific help file */ display_file(PORT_HELP, 1); } #endif /* MSDOS || WIN32 */ #endif /* PORT_HELP */ /* validate wizard mode if player has requested access to it */ boolean authorize_wizard_mode() { if (!strcmp(plname, WIZARD_NAME)) return TRUE; return FALSE; } #ifdef EXEPATH #ifdef __DJGPP__ #define PATH_SEPARATOR '/' #else #define PATH_SEPARATOR '\\' #endif #ifdef WIN32 static char exenamebuf[PATHLEN]; char * exename() { int bsize = PATHLEN; char *tmp = exenamebuf, *tmp2; #ifdef UNICODE { TCHAR wbuf[PATHLEN * 4]; GetModuleFileName((HANDLE) 0, wbuf, PATHLEN * 4); WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); } #else *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; #endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; tmp2++; return tmp2; } #endif #define EXEPATHBUFSZ 256 char exepathbuf[EXEPATHBUFSZ]; char * exepath(str) char *str; { char *tmp, *tmp2; int bsize; if (!str) return (char *) 0; bsize = EXEPATHBUFSZ; tmp = exepathbuf; #ifndef WIN32 Strcpy(tmp, str); #else #ifdef UNICODE { TCHAR wbuf[BUFSZ]; GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); } #else *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; #endif #endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; return tmp; } #endif /* EXEPATH */ /*pcmain.c*/ nethack-3.6.0/sys/share/pcsys.c0000664000076400007660000002762012536476415015406 0ustar paxedpaxed/* NetHack 3.6 pcsys.c $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ /* NetHack may be freely redistributed. See license for details. */ /* * System related functions for MSDOS, OS/2, TOS, and Windows NT */ #define NEED_VARARGS #include "hack.h" #include "wintty.h" #include #include #if !defined(MSDOS) && !defined(WIN_CE) /* already done */ #include #endif #ifdef __GO32__ #define P_WAIT 0 #define P_NOWAIT 1 #endif #ifdef TOS #include #endif #if defined(MSDOS) && !defined(__GO32__) #define findfirst findfirst_file #define findnext findnext_file #define filesize filesize_nh #endif #if defined(MICRO) || defined(WIN32) || defined(OS2) void FDECL(nethack_exit, (int)); #else #define nethack_exit exit #endif STATIC_DCL void NDECL(msexit); #ifdef MOVERLAY extern void __far __cdecl _movepause(void); extern void __far __cdecl _moveresume(void); extern unsigned short __far __cdecl _movefpause; extern unsigned short __far __cdecl _movefpaused; #define __MOVE_PAUSE_DISK 2 /* Represents the executable file */ #define __MOVE_PAUSE_CACHE 4 /* Represents the cache memory */ #endif /* MOVERLAY */ #ifdef MFLOPPY STATIC_DCL boolean NDECL(record_exists); #ifndef TOS STATIC_DCL boolean NDECL(comspec_exists); #endif #endif #ifdef WIN32 extern int GUILaunched; /* from nttty.c */ #endif #if defined(MICRO) || defined(WIN32) void flushout() { (void) fflush(stdout); return; } static const char *COMSPEC = #ifdef TOS "SHELL"; #else "COMSPEC"; #endif #define getcomspec() nh_getenv(COMSPEC) #ifdef SHELL int dosh() { extern char orgdir[]; char *comspec; #ifndef __GO32__ int spawnstat; #endif #if defined(MSDOS) && defined(NO_TERMS) int grmode = iflags.grmode; #endif if ((comspec = getcomspec())) { #ifndef TOS /* TOS has a variety of shells */ suspend_nhwindows( "To return to NetHack, enter \"exit\" at the system prompt.\n"); #else #if defined(MSDOS) && defined(NO_TERMS) grmode = iflags.grmode; #endif suspend_nhwindows((char *) 0); #endif /* TOS */ #ifndef NOCWD_ASSUMPTIONS chdirx(orgdir, 0); #endif #ifdef __GO32__ if (system(comspec) < 0) { /* wsu@eecs.umich.edu */ #else #ifdef MOVERLAY /* Free the cache memory used by overlays, close .exe */ _movefpause |= __MOVE_PAUSE_DISK; _movefpause |= __MOVE_PAUSE_CACHE; _movepause(); #endif spawnstat = spawnl(P_WAIT, comspec, comspec, (char *) 0); #ifdef MOVERLAY _moveresume(); #endif if (spawnstat < 0) { #endif raw_printf("Can't spawn \"%s\"!", comspec); getreturn("to continue"); } #ifdef TOS /* Some shells (e.g. Gulam) turn the cursor off when they exit */ if (iflags.BIOS) (void) Cursconf(1, -1); #endif #ifndef NOCWD_ASSUMPTIONS chdirx(hackdir, 0); #endif get_scr_size(); /* maybe the screen mode changed (TH) */ #if defined(MSDOS) && defined(NO_TERMS) if (grmode) gr_init(); #endif resume_nhwindows(); } else pline("Can't find %s.", COMSPEC); return 0; } #endif /* SHELL */ #ifdef MFLOPPY void eraseall(path, files) const char *path, *files; { char buf[PATHLEN]; char *foundfile; foundfile = foundfile_buffer(); Sprintf(buf, "%s%s", path, files); if (findfirst(buf)) do { Sprintf(buf, "%s%s", path, foundfile); (void) unlink(buf); } while (findnext()); return; } /* * Rewritten for version 3.3 to be faster */ void copybones(mode) int mode; { char from[PATHLEN], to[PATHLEN], last[13]; char *frompath, *topath; char *foundfile; #ifndef TOS int status; char copy[8], *comspec; #endif if (!ramdisk) return; /* Find the name of the last file to be transferred */ frompath = (mode != TOPERM) ? permbones : levels; foundfile = foundfile_buffer(); last[0] = '\0'; Sprintf(from, "%s%s", frompath, allbones); topath = (mode == TOPERM) ? permbones : levels; #ifdef TOS eraseall(topath, allbones); #endif if (findfirst(from)) do { #ifdef TOS Sprintf(from, "%s%s", frompath, foundfile); Sprintf(to, "%s%s", topath, foundfile); if (_copyfile(from, to)) goto error_copying; #endif Strcpy(last, foundfile); } while (findnext()); #ifdef TOS else return; #else if (last[0]) { Sprintf(copy, "%cC copy", switchar()); /* Remove any bones files in `to' directory. */ eraseall(topath, allbones); /* Copy `from' to `to' */ Sprintf(to, "%s%s", topath, allbones); comspec = getcomspec(); status = spawnl(P_WAIT, comspec, comspec, copy, from, to, "> nul", (char *) 0); } else return; #endif /* TOS */ /* See if the last file got there. If so, remove the ramdisk bones * files. */ Sprintf(to, "%s%s", topath, last); if (findfirst(to)) { if (mode == TOPERM) eraseall(frompath, allbones); return; } #ifdef TOS error_copying: #endif /* Last file didn't get there. */ Sprintf(to, "%s%s", topath, allbones); msmsg("Can't copy \"%s\" to \"%s\" -- ", from, to); #ifndef TOS if (status < 0) msmsg("can't spawn \"%s\"!", comspec); else #endif msmsg((freediskspace(topath) < filesize(from)) ? "insufficient disk space." : "bad path(s)?"); if (mode == TOPERM) { msmsg("Bones will be left in \"%s\"\n", *levels ? levels : hackdir); } else { /* Remove all bones files on the RAMdisk */ eraseall(levels, allbones); playwoRAMdisk(); } return; } void playwoRAMdisk() { int c; msmsg("Do you wish to play without a RAMdisk? [yn] (n)"); /* Set ramdisk false *before* exit-ing (because msexit calls * copybones) */ ramdisk = FALSE; c = tgetch(); if (c == 'Y') c = 'y'; if (c != 'y') { settty("Be seeing you...\n"); nethack_exit(EXIT_SUCCESS); } set_lock_and_bones(); return; } int saveDiskPrompt(start) int start; { char buf[BUFSIZ], *bp; char qbuf[QBUFSZ]; int fd; if (sysflags.asksavedisk) { /* Don't prompt if you can find the save file */ if ((fd = open_savefile()) >= 0) { (void) nhclose(fd); return 1; } clear_nhwindow(WIN_MESSAGE); pline("If save file is on a save disk, insert that disk now."); mark_synch(); Sprintf(qbuf, "File name (default \"%s\"%s) ?", SAVEF, start ? "" : ", cancels save"); getlin(qbuf, buf); clear_nhwindow(WIN_MESSAGE); if (!start && *buf == '\033') return 0; /* Strip any whitespace. Also, if nothing was entered except * whitespace, do not change the value of SAVEF. */ for (bp = buf; *bp; bp++) if (!isspace(*bp)) { strncpy(SAVEF, bp, PATHLEN); break; } } return 1; } /* Return 1 if the record file was found */ STATIC_OVL boolean record_exists() { FILE *fp; fp = fopen_datafile(RECORD, "r", TRUE); if (fp) { fclose(fp); return TRUE; } return FALSE; } #endif /* MFLOPPY */ #ifdef TOS #define comspec_exists() 1 #else #ifdef MFLOPPY /* Return 1 if the comspec was found */ STATIC_OVL boolean comspec_exists() { int fd; char *comspec; if ((comspec = getcomspec())) if ((fd = open(comspec, O_RDONLY)) >= 0) { (void) nhclose(fd); return TRUE; } return FALSE; } #endif /* MFLOPPY */ #endif #ifdef MFLOPPY /* Prompt for game disk, then check for record file. */ void gameDiskPrompt() { if (sysflags.asksavedisk) { if (record_exists() && comspec_exists()) return; (void) putchar('\n'); getreturn("when the game disk has been inserted"); } if (comspec_exists() && record_exists()) return; if (!comspec_exists()) msmsg("\n\nWARNING: can't find command processor \"%s\"!\n", getcomspec()); if (!record_exists()) msmsg("\n\nWARNING: can't find record file \"%s\"!\n", RECORD); msmsg("If the game disk is not in, insert it now.\n"); getreturn("to continue"); return; } #endif /* MFLOPPY */ #endif /* MICRO */ /* * Add a backslash to any name not ending in /, \ or : There must * be room for the \ */ void append_slash(name) char *name; { char *ptr; if (!*name) return; ptr = name + (strlen(name) - 1); if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { *++ptr = '\\'; *++ptr = '\0'; } return; } #ifdef WIN32 boolean getreturn_enabled; int redirect_stdout; #endif void getreturn(str) const char *str; { #ifdef WIN32 if (!getreturn_enabled) return; #endif #ifdef TOS msmsg("Hit %s.", str); #else msmsg("Hit %s.", str); #endif while (pgetchar() != '\n') ; return; } #ifndef WIN32 void msmsg VA_DECL(const char *, fmt) { VA_START(fmt); VA_INIT(fmt, const char *); #if defined(MSDOS) && defined(NO_TERMS) if (iflags.grmode) gr_finish(); #endif Vprintf(fmt, VA_ARGS); flushout(); VA_END(); return; } #endif /* * Follow the PATH, trying to fopen the file. */ #ifdef TOS #ifdef __MINT__ #define PATHSEP ':' #else #define PATHSEP ',' #endif #else #define PATHSEP ';' #endif FILE * fopenp(name, mode) const char *name, *mode; { char buf[BUFSIZ], *bp, *pp, lastch = 0; FILE *fp; /* Try the default directory first. Then look along PATH. */ (void) strncpy(buf, name, BUFSIZ - 1); buf[BUFSIZ - 1] = '\0'; if ((fp = fopen(buf, mode))) return fp; else { int ccnt = 0; pp = getenv("PATH"); while (pp && *pp) { bp = buf; while (*pp && *pp != PATHSEP) { lastch = *bp++ = *pp++; ccnt++; } if (lastch != '\\' && lastch != '/') { *bp++ = '\\'; ccnt++; } (void) strncpy(bp, name, (BUFSIZ - ccnt) - 2); bp[BUFSIZ - ccnt - 1] = '\0'; if ((fp = fopen(buf, mode))) return fp; if (*pp) pp++; } } #ifdef OS2_CODEVIEW /* one more try for hackdir */ (void) strncpy(buf, hackdir, BUFSZ); buf[BUFSZ - 1] = '\0'; if ((strlen(name) + 1 + strlen(buf)) < BUFSZ - 1) { append_slash(buf); Strcat(buf, name); } else impossible("fopenp() buffer too small for complete filename!"); if (fp = fopen(buf, mode)) return fp; #endif return (FILE *) 0; } #if defined(MICRO) || defined(WIN32) || defined(OS2) void nethack_exit(code) int code; { msexit(); exit(code); } /* Chdir back to original directory */ #ifdef TOS extern boolean run_from_desktop; /* set in pcmain.c */ #endif STATIC_OVL void msexit() { #ifdef CHDIR extern char orgdir[]; #endif flushout(); #ifndef TOS #ifndef WIN32 enable_ctrlP(); /* in case this wasn't done */ #endif #endif #ifdef MFLOPPY if (ramdisk) copybones(TOPERM); #endif #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdir(orgdir); /* chdir, not chdirx */ chdrive(orgdir); #endif #ifdef TOS if (run_from_desktop) getreturn("to continue"); /* so the user can read the score list */ #ifdef TEXTCOLOR if (colors_changed) restore_colors(); #endif #endif #ifdef WIN32 /* Only if we started from the GUI, not the command prompt, * we need to get one last return, so the score board does * not vanish instantly after being created. * GUILaunched is defined and set in nttty.c. */ synch_cursor(); if (GUILaunched) getreturn("to end"); synch_cursor(); #endif return; } #endif /* MICRO || WIN32 || OS2 */ nethack-3.6.0/sys/share/pctty.c0000664000076400007660000000350012536476415015377 0ustar paxedpaxed/* NetHack 3.6 pctty.c $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (PC) version */ #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers \ */ #include "hack.h" #include "wintty.h" char erase_char, kill_char; /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by startup() in termcap.c and after returning from ! or ^Z */ void gettty() { erase_char = '\b'; kill_char = 21; /* cntl-U */ iflags.cbreak = TRUE; #if !defined(TOS) disable_ctrlP(); /* turn off ^P processing */ #endif #if defined(MSDOS) && defined(NO_TERMS) gr_init(); #endif } /* reset terminal to original state */ void settty(s) const char *s; { #if defined(MSDOS) && defined(NO_TERMS) gr_finish(); #endif end_screen(); if (s) raw_print(s); #if !defined(TOS) enable_ctrlP(); /* turn on ^P processing */ #endif } /* called by init_nhwindows() and resume_nhwindows() */ void setftty() { start_screen(); } #if defined(TIMED_DELAY) && defined(_MSC_VER) void msleep(mseconds) unsigned mseconds; { /* now uses clock() which is ANSI C */ clock_t goal; goal = mseconds + clock(); while (goal > clock()) { /* do nothing */ } } #endif /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *, s) { VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); putchar('\n'); Vprintf(s, VA_ARGS); putchar('\n'); VA_END(); exit(EXIT_FAILURE); } /*pctty.c*/ nethack-3.6.0/sys/share/pcunix.c0000664000076400007660000001773312536476415015557 0ustar paxedpaxed/* NetHack 3.6 pcunix.c $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.34 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file collects some Unix dependencies; pager.c contains some more */ #include "hack.h" #include "wintty.h" #include #if defined(WIN32) || defined(MSDOS) #include #endif #if defined(WIN32) || defined(MSDOS) extern char orgdir[]; #ifdef WIN32 extern void NDECL(backsp); #endif extern void NDECL(clear_screen); #endif #if 0 static struct stat buf; #endif #ifdef WANT_GETHDATE static struct stat hbuf; #endif #ifdef PC_LOCKING static int NDECL(eraseoldlocks); #endif #if 0 int uptodate(fd) int fd; { #ifdef WANT_GETHDATE if(fstat(fd, &buf)) { pline("Cannot get status of saved level? "); return(0); } if(buf.st_mtime < hbuf.st_mtime) { pline("Saved level is out of date. "); return(0); } #else #if (defined(MICRO) || defined(WIN32)) && !defined(NO_FSTAT) if(fstat(fd, &buf)) { if(moves > 1) pline("Cannot get status of saved level? "); else pline("Cannot get status of saved game."); return(0); } if(comp_times(buf.st_mtime)) { if(moves > 1) pline("Saved level is out of date."); else pline("Saved game is out of date. "); /* This problem occurs enough times we need to give the player * some more information about what causes it, and how to fix. */ #ifdef MSDOS pline("Make sure that your system's date and time are correct."); pline("They must be more current than NetHack.EXE's date/time stamp."); #endif /* MSDOS */ return(0); } #endif /* MICRO */ #endif /* WANT_GETHDATE */ return(1); } #endif #ifdef PC_LOCKING static int eraseoldlocks() { register int i; /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for (i = 1; i <= MAXDUNGEON * MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) unlink(fqname(lock, LEVELPREFIX, 0)); } set_levelfile_name(lock, 0); #ifdef HOLD_LOCKFILE_OPEN really_close(); #endif if (unlink(fqname(lock, LEVELPREFIX, 0))) return 0; /* cannot remove it */ return (1); /* success! */ } void getlock() { register int fd, c, ci, ct, ern; int fcmask = FCMASK; char tbuf[BUFSZ]; const char *fq_lock; #if defined(MSDOS) && defined(NO_TERMS) int grmode = iflags.grmode; #endif /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif error("Quitting."); } /* regularize(lock); */ /* already done in pcmain */ Sprintf(tbuf, "%s", fqname(lock, LEVELPREFIX, 0)); set_levelfile_name(lock, 0); fq_lock = fqname(lock, LEVELPREFIX, 1); if ((fd = open(fq_lock, 0)) == -1) { if (errno == ENOENT) goto gotlock; /* no such file */ #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif #if defined(WIN32) || defined(HOLD_LOCKFILE_OPEN) #if defined(HOLD_LOCKFILE_OPEN) if (errno == EACCES) { #define OOPS_BUFSZ 512 char oops[OOPS_BUFSZ]; Strcpy( oops, "\nThere are files from a game in progress under your name."); Strcat(oops, "\nThe files are locked or inaccessible."); Strcat(oops, " Is the other game still running?\n"); if (strlen(fq_lock) < ((OOPS_BUFSZ - 16) - strlen(oops))) Sprintf(eos(oops), "Cannot open %s", fq_lock); Strcat(oops, "\n"); unlock_file(HLOCK); error(oops); } else #endif error("Bad directory or name: %s\n%s\n", fq_lock, strerror(errno)); #else perror(fq_lock); #endif unlock_file(HLOCK); error("Cannot open %s", fq_lock); } (void) nhclose(fd); if (iflags.window_inited) { #ifdef SELF_RECOVER c = yn("There are files from a game in progress under your name. " "Recover?"); #else pline("There is already a game in progress under your name."); pline("You may be able to use \"recover %s\" to get it back.\n", tbuf); c = yn("Do you want to destroy the old game?"); #endif } else { #if defined(MSDOS) && defined(NO_TERMS) grmode = iflags.grmode; if (grmode) gr_finish(); #endif c = 'n'; ct = 0; #ifdef SELF_RECOVER msmsg("There are files from a game in progress under your name. " "Recover? [yn]"); #else msmsg("\nThere is already a game in progress under your name.\n"); msmsg("If this is unexpected, you may be able to use \n"); msmsg("\"recover %s\" to get it back.", tbuf); msmsg("\nDo you want to destroy the old game? [yn] "); #endif while ((ci = nhgetch()) != '\n') { if (ct > 0) { msmsg("\b \b"); ct = 0; c = 'n'; } if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { ct = 1; c = ci; msmsg("%c", c); } } } if (c == 'y' || c == 'Y') #ifndef SELF_RECOVER if (eraseoldlocks()) { #if defined(WIN32) if (!strncmpi(windowprocs.name, "tty", 3)) clear_screen(); /* display gets fouled up otherwise */ #endif goto gotlock; } else { unlock_file(HLOCK); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif error("Couldn't destroy old game."); } #else /*SELF_RECOVER*/ if (recover_savefile()) { #if defined(WIN32) if (!strncmpi(windowprocs.name, "tty", 3)) clear_screen(); /* display gets fouled up otherwise */ #endif goto gotlock; } else { unlock_file(HLOCK); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif error("Couldn't recover old game."); } #endif /*SELF_RECOVER*/ else { unlock_file(HLOCK); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif error("%s", "Cannot start a new game."); } gotlock: fd = creat(fq_lock, fcmask); if (fd == -1) ern = errno; unlock_file(HLOCK); if (fd == -1) { #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif #if defined(WIN32) error("cannot creat file (%s.)\n%s\n%s\"%s\" exists?\n", fq_lock, strerror(ern), " Are you sure that the directory", fqn_prefix[LEVELPREFIX]); #else error("cannot creat file (%s.)", fq_lock); #endif } else { if (write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)) { #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif error("cannot write lock (%s)", fq_lock); } if (nhclose(fd) == -1) { #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif error("cannot close lock (%s)", fq_lock); } } #if defined(MSDOS) && defined(NO_TERMS) if (grmode) gr_init(); #endif } #endif /* PC_LOCKING */ #ifndef WIN32 void regularize(s) /* * normalize file name - we don't like .'s, /'s, spaces, and * lots of other things */ register char *s; { register char *lp; for (lp = s; *lp; lp++) if (*lp <= ' ' || *lp == '"' || (*lp >= '*' && *lp <= ',') || *lp == '.' || *lp == '/' || (*lp >= ':' && *lp <= '?') || #ifdef OS2 *lp == '&' || *lp == '(' || *lp == ')' || #endif *lp == '|' || *lp >= 127 || (*lp >= '[' && *lp <= ']')) *lp = '_'; } #endif /* WIN32 */ #ifdef __EMX__ void seteuid(int i) { ; } #endif nethack-3.6.0/sys/share/pmatchregex.c0000644000076400007660000000302312537770040016531 0ustar paxedpaxed/* NetHack 3.6 posixregex.c $NHDT-Date: 1434446946 2015/06/16 09:29:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.1 $ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Implementation of the regex engine using pmatch(). * [Switched to pmatchi() so as to ignore case.] * * This is a fallback ONLY and should be avoided where possible, as it results * in regexes not behaving as POSIX extended regular expressions. As a result, * configuration files for NetHacks built with this engine will not be * portable to ones built with an alternate regex engine. */ const char regex_id[] = "pmatchregex"; struct nhregex { const char *pat; }; struct nhregex * regex_init() { struct nhregex *re; re = (struct nhregex *) alloc(sizeof (struct nhregex)); re->pat = (const char *) 0; return re; } boolean regex_compile(s, re) const char *s; struct nhregex *re; { if (!re) return FALSE; if (re->pat) free((genericptr_t) re->pat); re->pat = dupstr(s); return TRUE; } const char * regex_error_desc(re) struct nhregex *re UNUSED; { return "pattern match compilation error"; } boolean regex_match(s, re) const char *s; struct nhregex *re; { if (!re || !re->pat || !s) return FALSE; return pmatchi(re->pat, s); } void regex_free(re) struct nhregex *re; { if (re) { if (re->pat) free((genericptr_t) re->pat); free((genericptr_t) re); } } nethack-3.6.0/sys/share/posixregex.c0000664000076400007660000000566012615363064016433 0ustar paxedpaxed/* NetHack 3.6 posixregex.c $NHDT-Date: 1434446947 2015/06/16 09:29:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include /* The nhregex interface is implemented by several source files. The * file to be used can be linked in by the build. * * The regex standard implemented should be POSIX extended regular * expressions, see: * http://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd_chap09.html * If an implementation uses an alternate expression format, this should * be clearly noted; this will result in incompatibility of config files * when NetHack is compiled with that implementation. * * struct nhregex * The nhregex structure is an opaque structure type containing the * information about a compiled regular expression. * * struct nhregex *regex_init(void) * Used to create a new instance of the nhregex structure. It is * uninitialized and can only safely be passed to regex_compile. * * boolean regex_compile(const char *s, struct nhregex *re) * Used to compile s into a regex and store it in re. Returns TRUE if * successful and FALSE otherwise. re is invalidated regardless of * success. * * const char *regex_error_desc(struct nhregex *re) * Used to retrieve an error description from an error created involving * re. Returns NULL if no description can be retrieved. The returned * string may be a static buffer and so is only valid until the next * call to regex_error_desc. * * boolean regex_match(const char *s, struct nhregex *re) * Used to determine if s (or any substring) matches the regex compiled * into re. Only valid if the most recent call to regex_compile on re * succeeded. * * void regex_free(struct nhregex *re) * Deallocate a regex object. */ const char regex_id[] = "posixregex"; struct nhregex { regex_t re; int err; }; struct nhregex * regex_init() { return (struct nhregex *) alloc(sizeof(struct nhregex)); } boolean regex_compile(const char *s, struct nhregex *re) { if (!re) return FALSE; if ((re->err = regcomp(&re->re, s, REG_EXTENDED | REG_NOSUB))) return FALSE; return TRUE; } const char * regex_error_desc(struct nhregex *re) { static char buf[BUFSZ]; if (!re || !re->err) return (const char *) 0; /* FIXME: Using a static buffer here is not ideal, but avoids memory * leaks. Consider the allocation more carefully. */ regerror(re->err, &re->re, buf, BUFSZ); return buf; } boolean regex_match(const char *s, struct nhregex *re) { int result; if (!re || !s) return FALSE; if ((result = regexec(&re->re, s, 0, (genericptr_t) 0, 0))) { if (result != REG_NOMATCH) re->err = result; return FALSE; } return TRUE; } void regex_free(struct nhregex *re) { regfree(&re->re); free(re); } nethack-3.6.0/sys/share/random.c0000664000076400007660000003363112536476415015524 0ustar paxedpaxed/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* Several minor changes were made for the NetHack distribution to satisfy * non-BSD compilers (by definition BSD compilers do not need to compile * this file for NetHack). These changes consisted of: * - changing the sccsid conditions to nested ifdefs from defined()s * to accommodate stupid preprocessors * - giving srandom() type void instead of allowing it to default to int * - making the first return in initstate() return a value consistent * with its type (instead of no value) * - ANSI function prototyping in extern.h - therefore include hack.h * instead of stdio.h and remove separate declaration of random() from * the beginning of function srandom * - moving sccsid after hack.h to allow precompiled headers, which * means the defined()s would be ok again... * - change fprintf(stderr, "x(%d)y\n", z) to impossible("x(%d)y", z) * - remove useless variable `j' from srandom() * - cast result of pointer subtraction to long since ptrdiff_t could * be bigger than that and trigger warnings when assigning to long * * $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ */ #include "hack.h" #ifdef LIBC_SCCS #ifndef lint static char sccsid[] = "@(#)random.c 5.5 (Berkeley) 7/6/88"; #endif #endif /* LIBC_SCCS and not lint */ /* * random.c: * An improved random number generation package. In addition to the standard * rand()/srand() like interface, this package also has a special state info * interface. The initstate() routine is called with a seed, an array of * bytes, and a count of how many bytes are being passed in; this array is * then * initialized to contain information for random number generation with that * much state information. Good sizes for the amount of state information are * 32, 64, 128, and 256 bytes. The state can be switched by calling the * setstate() routine with the same array as was initiallized with * initstate(). * By default, the package runs with 128 bytes of state information and * generates far better random numbers than a linear congruential generator. * If the amount of state information is less than 32 bytes, a simple linear * congruential R.N.G. is used. * Internally, the state information is treated as an array of longs; the * zeroeth element of the array is the type of R.N.G. being used (small * integer); the remainder of the array is the state information for the * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of * state information, which will allow a degree seven polynomial. (Note: the * zeroeth word of state information also has some other information stored * in it -- see setstate() for details). * The random number generation technique is a linear feedback shift register * approach, employing trinomials (since there are fewer terms to sum up that * way). In this approach, the least significant bit of all the numbers in * the state table will act as a linear feedback shift register, and will have * period 2^deg - 1 (where deg is the degree of the polynomial being used, * assuming that the polynomial is irreducible and primitive). The higher * order bits will have longer periods, since their values are also influenced * by pseudo-random carries out of the lower bits. The total period of the * generator is approximately deg*(2**deg - 1); thus doubling the amount of * state information has a vast influence on the period of the generator. * Note: the deg*(2**deg - 1) is an approximation only good for large deg, * when the period of the shift register is the dominant factor. With deg * equal to seven, the period is actually much longer than the 7*(2**7 - 1) * predicted by this formula. */ /* * For each of the currently supported random number generators, we have a * break value on the amount of state information (you need at least this * many bytes of state info to support this random number generator), a degree * for the polynomial (actually a trinomial) that the R.N.G. is based on, and * the separation between the two lower order coefficients of the trinomial. */ #define TYPE_0 0 /* linear congruential */ #define BREAK_0 8 #define DEG_0 0 #define SEP_0 0 #define TYPE_1 1 /* x**7 + x**3 + 1 */ #define BREAK_1 32 #define DEG_1 7 #define SEP_1 3 #define TYPE_2 2 /* x**15 + x + 1 */ #define BREAK_2 64 #define DEG_2 15 #define SEP_2 1 #define TYPE_3 3 /* x**31 + x**3 + 1 */ #define BREAK_3 128 #define DEG_3 31 #define SEP_3 3 #define TYPE_4 4 /* x**63 + x + 1 */ #define BREAK_4 256 #define DEG_4 63 #define SEP_4 1 /* * Array versions of the above information to make code run faster -- relies * on fact that TYPE_i == i. */ #define MAX_TYPES 5 /* max number of types above */ static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; /* * Initially, everything is set up as if from : * initstate( 1, &randtbl, 128 ); * Note that this initialization takes advantage of the fact that srandom() * advances the front and rear pointers 10*rand_deg times, and hence the * rear pointer which starts at 0 will also end up at zero; thus the zeroeth * element of the state information, which contains info about the current * position of the rear pointer is just * MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3. */ static long randtbl[DEG_3 + 1] = { TYPE_3, 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, 0x27fb47b9 }; /* * fptr and rptr are two pointers into the state info, a front and a rear * pointer. These two pointers are always rand_sep places aparts, as they *cycle * cyclically through the state information. (Yes, this does mean we could *get * away with just one pointer, but the code for random() is more efficient *this * way). The pointers are left positioned as they would be from the call * initstate( 1, randtbl, 128 ) * (The position of the rear pointer, rptr, is really 0 (as explained above * in the initialization of randtbl) because the state table pointer is set * to point to randtbl[1] (as explained below). */ static long *fptr = &randtbl[SEP_3 + 1]; static long *rptr = &randtbl[1]; /* * The following things are the pointer to the state information table, * the type of the current generator, the degree of the current polynomial * being used, and the separation between the two pointers. * Note that for efficiency of random(), we remember the first location of * the state information, not the zeroeth. Hence it is valid to access * state[-1], which is used to store the type of the R.N.G. * Also, we remember the last location, since this is more efficient than * indexing every time to find the address of the last element to see if * the front and rear pointers have wrapped. */ static long *state = &randtbl[1]; static int rand_type = TYPE_3; static int rand_deg = DEG_3; static int rand_sep = SEP_3; static long *end_ptr = &randtbl[DEG_3 + 1]; /* * srandom: * Initialize the random number generator based on the given seed. If the * type is the trivial no-state-information type, just remember the seed. * Otherwise, initializes state[] based on the given "seed" via a linear * congruential generator. Then, the pointers are set to known locations * that are exactly rand_sep places apart. Lastly, it cycles the state * information a given number of times to get rid of any initial dependencies * introduced by the L.C.R.N.G. * Note that the initialization of randtbl[] for default usage relies on * values produced by this routine. */ void srandom(x) unsigned x; { register int i; if (rand_type == TYPE_0) { state[0] = x; } else { state[0] = x; for (i = 1; i < rand_deg; i++) { state[i] = 1103515245 * state[i - 1] + 12345; } fptr = &state[rand_sep]; rptr = &state[0]; for (i = 0; i < 10 * rand_deg; i++) random(); } } /* * initstate: * Initialize the state information in the given array of n bytes for * future random number generation. Based on the number of bytes we * are given, and the break values for the different R.N.G.'s, we choose * the best (largest) one we can and set things up for it. srandom() is * then called to initialize the state information. * Note that on return from srandom(), we set state[-1] to be the type * multiplexed with the current value of the rear pointer; this is so * successive calls to initstate() won't lose this information and will * be able to restart with setstate(). * Note: the first thing we do is save the current state, if any, just like * setstate() so that it doesn't matter when initstate is called. * Returns a pointer to the old state. */ char * initstate(seed, arg_state, n) unsigned seed; /* seed for R. N. G. */ char *arg_state; /* pointer to state array */ int n; /* # bytes of state info */ { register char *ostate = (char *) (&state[-1]); if (rand_type == TYPE_0) state[-1] = rand_type; else state[-1] = (long) (MAX_TYPES * (rptr - state) + rand_type); if (n < BREAK_1) { if (n < BREAK_0) { impossible("initstate: not enough state (%d bytes) with which to " "do jack; ignored.", n); return (char *) 0; } rand_type = TYPE_0; rand_deg = DEG_0; rand_sep = SEP_0; } else { if (n < BREAK_2) { rand_type = TYPE_1; rand_deg = DEG_1; rand_sep = SEP_1; } else { if (n < BREAK_3) { rand_type = TYPE_2; rand_deg = DEG_2; rand_sep = SEP_2; } else { if (n < BREAK_4) { rand_type = TYPE_3; rand_deg = DEG_3; rand_sep = SEP_3; } else { rand_type = TYPE_4; rand_deg = DEG_4; rand_sep = SEP_4; } } } } state = &(((long *) arg_state)[1]); /* first location */ end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ srandom(seed); if (rand_type == TYPE_0) state[-1] = rand_type; else state[-1] = (long) (MAX_TYPES * (rptr - state) + rand_type); return (ostate); } /* * setstate: * Restore the state from the given state array. * Note: it is important that we also remember the locations of the pointers * in the current state information, and restore the locations of the pointers * from the old state information. This is done by multiplexing the pointer * location into the zeroeth word of the state information. * Note that due to the order in which things are done, it is OK to call * setstate() with the same state as the current state. * Returns a pointer to the old state information. */ char * setstate(arg_state) char *arg_state; { register long *new_state = (long *) arg_state; register int type = new_state[0] % MAX_TYPES; register int rear = new_state[0] / MAX_TYPES; char *ostate = (char *) (&state[-1]); if (rand_type == TYPE_0) state[-1] = rand_type; else state[-1] = (long) (MAX_TYPES * (rptr - state) + rand_type); switch (type) { case TYPE_0: case TYPE_1: case TYPE_2: case TYPE_3: case TYPE_4: rand_type = type; rand_deg = degrees[type]; rand_sep = seps[type]; break; default: impossible("setstate: state info has been munged (%d); not changed.", type); break; } state = &new_state[1]; if (rand_type != TYPE_0) { rptr = &state[rear]; fptr = &state[(rear + rand_sep) % rand_deg]; } end_ptr = &state[rand_deg]; /* set end_ptr too */ return (ostate); } /* * random: * If we are using the trivial TYPE_0 R.N.G., just do the old linear * congruential bit. Otherwise, we do our fancy trinomial stuff, which is the * same in all ther other cases due to all the global variables that have been * set up. The basic operation is to add the number at the rear pointer into * the one at the front pointer. Then both pointers are advanced to the next * location cyclically in the table. The value returned is the sum generated, * reduced to 31 bits by throwing away the "least random" low bit. * Note: the code takes advantage of the fact that both the front and * rear pointers can't wrap on the same call by not testing the rear * pointer if the front one has wrapped. * Returns a 31-bit random number. */ long random() { long i; if (rand_type == TYPE_0) { i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff; } else { *fptr += *rptr; i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */ if (++fptr >= end_ptr) { fptr = state; ++rptr; } else { if (++rptr >= end_ptr) rptr = state; } } return (i); } nethack-3.6.0/sys/share/sounds/README0000664000076400007660000000261212467321052016253 0ustar paxedpaxedREADME for the AIFF files: These files are sound files for the instruments in NetHack. There are 11 sounds, one for each distinct instrument. The sounds are in 8-bit 22kHz AIFF format, which should be readable by a broad range of platforms. Since the sounds came from Rolands S-750 sample library (most of them) there should be no copyright on them when we treat them like we do here (as instruments) - indeed, the sample library I got from Roland didn't even bear a (c) symbol. Some of the sounds are very adequate (Drum of Earthquake, Wooden Flute, Magic Harp) while some are less true to the original name (how does a Frost Horn sound?) Actually, I don't know what a Bugle is (Bugle horn?) so I took a trumpet sound for that. Correct me if I'm wrong. What does this have to do with the main code? Well, nothing so far. There are some places that are #ifdef MAC and calls mac_speaker; that function takes an object and a tune (in capital letters A-G) and plays the tune with the given instrument. When playing a specific tune, that tune is of course used. For "improvise," I use middle "C." Ideally, we should do something equal with sound that we have with displays, so we can use one common set of calls in the main code, and have ports do whatever seems appropriate for the available hardware. Any comment on the sounds or their use is welcome: Jon W{tte Mac Team nethack-bugs@nethack.org nethack-3.6.0/sys/share/sounds/bell.uu0000664000076400007660000006075112467321052016674 0ustar paxedpaxedbegin 644 Bell M``1"96QL```````````````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``````````````$0B```! MSJ<]K>2G/:WQ``````````````````````````````"!@6<2``!&3U)-``!$ M&D%)1D934TY$``!"'@`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M_P````#_``#___[^``$#`_W]_OG[!@L%_??S^P``!P_X[/_\_@`&!__^[O@) M^?<*%/CF!OWL"Q0&\?+]^`'__@C[^`@#]_3Q^0L%_Q8$U><%_PXD!^OVY=0( M+`_]``#DT?8='`H.!N'=Y/`H(/@5!\_-!AL"%PSY^M#H&P'_(`O:]`SA^QWX M_A?PZP[YZ`@,]@H+ZO\"[``$_`L)Z/89[M\6$OD`_?X`Z>06)?'S#?3H[0,: M#O[]]^7P$__['/SJ_/CT!@SY`@OQ\PCX]@@&_O0`!/O\\PH*Z_H/!>OX%_;I M#A'W\?SY^0L`"!CQXO?\]`DD#/'ZY^#_"!,8$O'?^^GG&B@&]03WUND.&1?^ M^P#LXO8/%0[_\?<`Z/0;$?SW__OL^PD!_@<*[O(3]>WX!0'_"03W^/;Y"PCT``[PYPD(_@?^]/X#[_H9 M`?;]\_[]^`L0^.P(`-\,&/H$`?'R`OK[%0GP_?_U^/@3$NOX%/S>_ACW^`[Z M_OSU`O__`@3Z^P;O_!#L^A[^Y`P0WO@7^?L,_/?Z\0`._/D1_.\)_NX&"/0` M!OG\"/?U#/_W`04&^/8$__/W#0CZ"/SR`_KN"A[_Y_\(\?+\$QKUZ?\-].D. M&@7OZ0H&Z/H?&>7J#OON`Q(.]?$#]_0)%`#P!_OO!OP'%_CL`PCC^R3^^0CV M\_OU"!O]\!(`UP@8Z_P7`>__!03\Y@0D\.0?&.+C!@L&]?HH"X3$O\#]NT"!/P,$??U_>_\#00%"OOQ`/SS"Q($^O/X_/?[%Q;Q^`#O M]`@/$`CNZ0;^Y0XI!^SQ`/;R"!$/`?#R]O[_!A<&]OCU]P(%!@L&[_4([_L; M_NL*#._T#@/Z"OCW#/7L!!0*]OD#^?;[#`_W\04%]?@/#.?W%?_X!O[Q^P?[ M"QGO[@/S]`\4^_D&]>S^"1`"]`4'\>8%&`#S"`_Q[/L$#@;U`0_TX0L4[_P1 M_O,'__,#`OC]#@7_^?#^`/P*$`'X]_GS`@_\"0SKZ`<,[@,E^N@%_N;T'1'^ M!O?S\.L+)@WS^@3TX/T/#Q7S^0GCYA`B_/06_-GR%@CT^@X&^`+[^_;M`QP/ MZ_L'X>8/'PS]^_/V[/4=$0'\_.OH"`$%$`C\[/O[ZPT8_/H,^=_^#/8&&/GM M"OOL`P3Y!!'_]@'R]0+S$"+TX@0%XOP;&P4#!_OGU?\N"?@7!^+;^@\)#A$-\MON_OX0&@\$Z]_U M`?X-(`SP]O+G^`@4$P#]`>G9`QT#`A((\.+L`A,#!QWYY>[U`0L6!0<$V.@' M!0\*#`+PZN@+$08+``'\Y.T/$P`!"_CC]@L)`P`6"-7N$`CT`!H"[N?^&??M M%![NW!(0X?47&>_G"0?XZP<;^.D#%/KC!"("V/TJ^OV M(2_TU?P%XO@D%@7YVO`.\_!.'V^]H+.P;M`O+B``X* M)0K5XP'Z`R8=`?#@W?$8*!L(\.?6YPP>-17KY>K@Z2 M[M'[#`D:`>P,!-CN(`SX"07T]_?U#@?X"P7O]P7W_Q<%]0+][_C_!A4%\OC[ M_OX`_@T/ZO0&`OOX`@L*]?P,\NT)!OP0!?#^^.T(%O?Z%?CR`OC\!0`*&?': M"P7>!"D2]^_N_O_N#RK^YOWXZP`)#!/\]@#MZQ`6]@L.XO'\]@\9_/45\M$+ M&0,#`0'UZ^T0&O@&"NOM!0+]#Q'XZOH&]O84#O`"">CW#_O]&?WE"O_D"!7X M!`CK_@CO^Q[[Z1?ZY@P+\OL5^?0-]/L,^/<("?/[#/KS`@W^\P4)\_D0_?<$ M`_CZ"/T"`_7__O\"`@`$">SQ#@3V"!+P]`+P]10:^/P'[./\%`H,#_;F[/S_ M"B`3^.CN]_0&'"``W>O_^?<7)`SMX?`"!/X;(.[C^_3K#",-!@#CZ/CY#BX/ M[_SFU/HD&Q$+]>_>X!$F#@4*\MOR_@4;$P+X]^_M`Q$1`OL&]>K\"`P'_?<' M!>O[$P3Z_?H""OOV#`3L``O^!@SX]O_X_`L*_P7YZ0,+^086!^KR`_4&#@(' M`?;E_18$"0'_`^_K_QX'\@L"]O?W``\-]0`/^>GZ"PK^^Q`)Z?$&!``*!?D' M^>\!!`8'_?P*_.@!$_H"$//U"?7M$AOY\P;^]/<#%@CU]P``^/H+%P+M^PS[ M]``)#_OM!0WR]18%\P@"]``'^`$*[_X2]O49"=X`$_/X%!'X].[S$`7_%1#N MX0,"_P\("O_MY_T5^00@`.7Q!/W_%0D``^SH!1(``!``[/3^!A`!_`GXZ?T1 M__L4_^T"_/0#$`H``?'V!/D!$`OZ\?D``_\!$@'N^O\$`OT!`__U_P7]"/_X M#`3N^0S]^`X!^P?T\`P&]PP0\_`!^?H)"0\%[/L`[OH8$?H&^>;Y_@09$?[] M\N3Z#0D4$O#U]MP%+@;R&PC(Z1$($@T``/;=\1T/!1+ZZO?U]10;_/C^[^X, M#@H0`.OF`@G^#Q7^Y^S[`Q(2!PKWVNL)"Q(5`?3W[>02(`@'_/;T]>\**?SI M"@?M[PX-!`3U_@;\]@(0__3[`@4'`/L#__;Y!PX(`//X!_CW#Q#_]P#Y]@<$ M!0[_]O?\__L,$@CY[?O^`08*%P;IY_\&]PT?"?+M]_4#$`\2_>KP_OP!&`SZ M`_OL^`P("0?U!`CCZ"(=YO\?^>?V`@8+`P`4]]L"#_C_&!'[]._T`O\&&P_X M]?+M]Q$9"P4#]^3K"`\+"@0#_NSK"0\"#`_Y\?CO_!0-!0H![/+^_PT2`?O_ M]/`"#@4""P3V\_X!_@L,!?OJ^@4!``H6]_/]_0KW\@H5!/$%_NSX!A,.!/SY M[NH'$`\,`OGR\.D.(@,("?#?\@X)#P\(!=O;#AC_""$`X^KM#1P!`!#ZV?@8 M`?\)!/OU``0)_?0&`/<&"__[!/[R^@P+`O[\`_KN^PL4`/T)]/#\!P4$#_;Q M!OKY#POY_`#S`A+W_!7VX?\/!@L,]/C_Y?P?#/P'_N'Z#_X($`'W^??X#`H` M!/GY`?T""PGY\OD"`P$2#_/H^0$`$@X'!.3=`Q@'#B#QV>_X`1[O!QH(`A'^WNH+#P4,%P#?Y0`+ M!`X:`^WL^`(##Q`&^NSV`P`!%!7NZ@D![@4?!/#[__KX!1,+]/<'^?`+$_[\ M!/SY^OP*#?SY"P#G^!(*^005_>+V#P#Z$Q/V[_GW_@@,%`GO\P#S\@X<#?GS M^_OH^"0@^O,`\>7_%!,*__;Q]/D'&1'Z\OWU[08;$/?Y]^[Y!1<5`_;O\>\# M&1@*^.[L]?X*(Q7U[_3N\!,="`'Y\._\"!$1`?3T]OH($PS]]O?R_!`4#/WR M[?+^#!X1^OCLXOH?%0GX^P<1$`OU[/,$"0,-"_SK\@@)!P@"__/M_Q(/`@C\Z/<&``L:!>_Q M]?H)"PD2_^;Q!0,%$@W\\_#V!PD)$`;S[?D#!`T-"/[O\/D("@41"_;I]@C_ M_P\4!?#S__SZ`1$3`??Y^_3U#A@*!/_VY^T($A$.#OO>Z04*"1@<^N'H]@(. M$Q$P3U[>GV#Q80!0'XY.L-%@8$!_WP\OX/%_[W M"?_I]A@+]@GL`PL-$@KY[^[V!1$1"OOO^/;T$1H&]_KZ M[O@,%Q'U]/WS]045%`/QZ_\`]0X=!_'R]O,#$!`)_O;L\PD/!PD*\>3Y"@P. M"OSV[^T#%Q8'^_+M\_P0&PP`]^CE`A8+$1CVVNS^`1$>#?KQX^X.$`P3"N[D M]OP)%0L%_.[L_PL+$@GR\OGQ_1D3_/[][?(&"PT1_?'Y^/(#&0O[`_SN]P<- M"`4`^OCS_PL'`P+^^?W__PP+^_P!^O<%!_\%!?SY`0(``P0!_P(`^?\'__@! M"@+^`P+_^?H#"`0!!?_V^?\#!@8(!?OV_`#Y!1`*_O?Y^OL`"A0']?C[_O\% M#`;]]_W^_@@$_P4$^OP$_/T-"/O^__;Z!04)#?[V^_OY!0X)!0'X\O3["Q4) M`@;WYO(("P\5`?/U[.\+&@T("O#E^``'$1,&]?3P]0,,%PK\^?7W^@@0"P/V M]/;_"@4*"??R_@+]$!+T]@/S]1(2_P8!ZO8%`A`4^_3\[_$)#Q04]^?X_/$+ M(0X#^>;G_@@)&Q;\Z^KT_`P5%`7S\>[T!0X4#/_S\?CY"1`*!OCT^/S]"!,$ M]_W]^OX$"@C\]/T$_O\&`P'^_/\"`/T"`OX"`O[^_P#]_04%_?T%`_/[#0;] M``7^]OC\"@_\_07_\_@'!@D(^_GY]OD"#1$*^^_Y^/4,%PS_^O'I]@0/&P[W M]OCKZA(C"/T']=SP"PT4%0+V\.?V$1$($`#F[?D`%!8$!?K<\1@&_!X.W.@" M^P08$P3[Y^<%"@44%_OAZ/T%"`\:"^OE\O\($1,&^//O\`(8$@`!^^_T``8/ M$OOS__CR"!<$_0+X]/H("08+_/7V_@7^"@H$_.[\!@0`!!#^\O?^!?\"#@CW M]0$`^@0.!_[[^_CY!0D&"0/[]_3Y"!,#`@_XXO4)!0H3"?KTZ_8."`D3!_#K M^/D&$PL*`/+P]`4+$`GY_?;R^PH6!_W_]O7]!0L-!O/Y`O'\%PW[`@'P^`<` M"1/^\OC]``$!"A+^[?T&^_\#!@H`\O@*`O,#$@?W^@?]]P`"!PD$]?L']_<* M#`@$^O+]`?@'%`C_^/+X_P,+%0;T^?7P`P\-#@CSZ?O__`\7"?GR[?('#PD. M#/7F[P$+#!`-^NWL^`$,&0\"\NGQ^@<1%PWX[^?S!0H3&0CL[?3P!!<4#@3O MY_;[`QH4`O_QX_4+"@\5`?'R[O<-%`X&^?#R]0`1$`WV`0D-"07[ M[N\`"PD-"?OT\?8%$`H%!/+L_08#"Q,!]/3X`@4'"0CZ[OT!_0@."/GV_`$! M^P80`?'U`@0`!0T$]O7_`P(*!OCU^@0'!`0$_/#Z"@L&!/[S]/L&#P<``?OQ M]@@."@3[^O;R_@\0!?_V]/G_"1`+_?3S]@0(!P\%\.S\!@4*"@7\[.\##@H& M!?[T\/H,#04$`//T`08)!0$`^??]!P8!`OOZ_P`$!0/]_OST`@\"_`'^^_O_ M"`P!^/W^^``)"`'Z^/S__`81`O/X`?O]"@@#_?7V``8#"`C]]OC]`0<(!/[W M]OL"!0@)_O?Z^_X'#0#Z_O3U!`H'!0#V]O_^`PT'^OCZ^/T%!@D#]_;\`0(% M!?_^^?@""`+\`/[Y_P<$``+^^?L`!@OU`P\3!OWX M\O+\#`\*`/?Z^/@%"P8!`/KW_@$"!@,`__O[``(``0/__@#^___^`@0!_@(! M^?L``@0%!`#[^/L``P<*`_CW^/L`!PP)__3V_?P!"PP"^/?Y_``%#0;W^?[[ M_`<+`?KZ^P`!`0<%_/7^!/\`!`/]^/P"`P(#`OSY_@(``0,"_/C^`P4!_P(! M^O8""P/^`/WY^OX#"@?\^_WY_04'!?_\^OP``08&_OS]_OT!!0(!_/D``?X" M!@'Z_0#\``0"`/W^____`0`````0`!````````/P`____@``` M``$!``9156YI=',````````````````````````````````````````!`@`& M('-A;7!S```````````````````````````````````````````````````` M````````````)P`O``__]O_Y``$````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````!`````7@```!X````5@`````` M````````````````````````````````````!$)E;&R!`@```$%)1D939#)A M`````````````!*L`````$%)1D939#)A```````````````````````````` M````ISVMY```1"(```'.``````````````````(E`/____X!,0`````````` M``````````````````````````````````$````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````!H`*0`/`FH#,0`J``,";0,]`"D`#P)!`R(!`````!H` M*0`/`5`!\0`J``,";0,]`````````````````!H`+``6`3X!W``J``,";0,] M`````````````````!H``````````````````````````````````````0`` M``%X````>````%8`<;B\'*8````<`%8``%=S=&$``P`*``'__P`````````` M``+__P```!X```````/__P```#P```````3__P```%H````````````````` I```````````````````````````````````````````````````````` ` end nethack-3.6.0/sys/share/sounds/bugle.uu0000664000076400007660000004724012467321052017052 0ustar paxedpaxedbegin 644 Bugle M``5"=6=L90`````````````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``!H`10```````#8B```! MSJ<]K=:G/:W>``````````````````````````````"!@7%5``!&3U)-```V M&D%)1D934TY$```T'@`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````/____\```$"`@("`@("`@("`0("`0```/_^_O\```$"`@,#`P0$!@D- M#Q`0"P/Y[>+GCX>+G\/?\``(#!0<'!00$!`,"```!`P8'!P8%!`,#!0<( M!P8%!`(!`0#__O[^_O\``@,$!PH,#`L+#`\2%1@:&1<5$Q`,!/CHU+^TM+6Y MQ=/C\OP!`/W[^OCV]OC[``4+#`H&!`(``````@0%!PD*"@H)"`8$`P,#`P(" M`0$!______\!`P4'"0L-#@X,"PH*#1$5&AT?("(>$?[CR+.HIZRUO\?.U=SF M\?C\_OW[^??Y`@T4%A0/"08&!@<)"@D(!P4%!P@(!@0#`@("!`8("`8%!`," M`0$!`@,$!08'!P<("@P.#A`3&2`F*"@E'Q'[XC("%F;37^0\9%PP!_/OX]?;]!@X1$`\,!P/_ M_P``_OW_!`L0$A(0#0D&!`,#!0@)"`<&!`+^^OCW]O;Y_P4+#Q$1$`P)!P8' M"Q$7&R(I+"85_=_"J)2*CZ"ZV?@.%Q8-`OKV]/'Q^`(+$144$`L$__W]_?S] M``4*#A(4%1,/"@8"``$$!P@("`<%`O[[]_7T]OL`!0D-$!$/#`D'!PH/%!HA M)RHH'@OPU;VGD(*(H\?M"AD<$P?\]_7S\?/[!`L.$`\-"P<"__[^_?X"!PP0 M$Q46$PX)!0$``00&!P<'!@,`^_CV]/3W_`((#1`1$`X*"`<)#1(8'2(F)!L) M\=C`JY>,E;#0[P<6&!`$^_;T\>_R^@,+#Q$2$0X)`P``__W^`08,$!06%A0/ M"@8"```"!`8&!@4#`/WY]O3S]?H`!@P1$Q,1#@P+"PX1%1H>(1\7!_#4NJRH MIZ>NPN']$!81!OWX]O3R\O@"#105$@P(!00#`@#^_P$&"P\3%A@7$PP&`?[_ M`@0%!04$`P'^^_CW]_CZ_P0*#A$1$`X+"0D+#Q,8'2`A&PWXX'QL/^^/+MJ:;E9VZX0(6'!@. M!?WY]?/S^``(#A$1#PT-#`H&`O_]_@,(#1$5%A83#@D%`@$"`@("`P0$`P'^ M^O?U]??\`PH.$1,2#PT,#`T/$109'1\;#OKCRK2GGIB@NMX`%AX:$`;_^_?U M]/?^!@P/#P\.#@T+!P+^^_P!!@L/$Q87%`\*!@,"`P,"`@("`@(!__SY]_?Y M_0$'#1`2$@\,"PL-#Q(6&QX?'!'_Z=&[J)B,E+?B`Q@?&0\'`?WY]O;Y_P8* M#0T-#@\."P?O^8'&AX8#@8`_?KW]?C^!`D,#0T-#@T*!0'^ M_?X`!`@,$!(3$0X*!P4#`@$````!`@(!__W[^?GY_`$'"PX.#@T+"0D*#1$5 M%QD9%P\![MG$LJ&5G\#H"1H=%PX&`/SX]O;Y_P4*#0T-#0X-"@4!_?O\_P0( M#!`3$Q$."@<%`P$`__\``0(#`@#^^_GX^?P!!@H-#@T,"PD)"@P/$Q87&!'*LIV6K-;[ M$1L9$@L%__OY^?G[_@$%"`H,#@\."03_^_K\``,&"@X1$0\-"@@&`P#^_?X` M`0("`@#]^OCW^?P!!@D+#`P+"0@("0H-$!,4%10/!/3@R;"F;?C`Q08%`T(`_WZ^_S]_O\``0($!@H-#@P(`P$` M```!!`@,#0X-#`P+"08#`/_^_O__````__SZ^?K]`04'"`D*"0D("`H,#Q(2 M$1$/"O_OV<*JF:;/]@T8%Q`*!0#\^OO\_O\```$"!`<+#0P*!@,"`0$!`@4) M#`T-#`P,"PD&`@#__O[^_O[___W[^?G\``0&"`D)"0D("`D+#A$2$A$/#`7Y MZ-*ZI)RUWP`2&!0-!P+]^OO\_@````$!`@,&"@P*!P4#`P,#`@,&"@P-#`P, M#`L)!0(`__[^_O[^_O[]^OG[_@(&!P@("`@("`@*#`\1$A(2$`L"]-_'K)BA MR?$+&!@1"@4`^_K\_O\!`0$!`0(%"`H+"08$`P,#`P,%"`L,#`L+#`L*!P0" M`/_______O[]_/GY_``$!P@)"0@("`@)"@T/$!$1$0T'^^K3NJ.=M^$!%!D3 M#`8!_?KZ_/\!`@("`0$"!0@*"0<%!`0$!`,$!@D,#`P+"PP+"08$`@'____^ M_?W]_/KY^OX#!P@)"0@(!P<("0P/$1$2$0\*`/'=Q:R:IL[U#AD7#P@#_OKY M^_T!`P,"`@$!`@4'"`<%!`0%!00$!0@+#0P+"PL+"PD&!`,!___^_?W\^_KY M^?P!!0@)"@D(!P<'"`H-$!$2$0\+!/KIU+F=F+CE!A<:$PL%__KX^?S_`@0$ M`P$!`0,%!P8%!`0$!04$!`8)#`P*"@L+"PH'!00#`?_^_OW]_/OY^?K_`P<) M"@H)!P<'!@@*#A`1$!`."/_QW<6GE:O:_A0;%@T'`?SY^/K]`00%!`(!`0($ M!@8$`P,$!04%!08("@L*"0H+"PH(!@4$`@#^_OW\_/OY^/G\`04("@L*"`<& M!@<)#1`1$`\-"@/WYM&TFJ'*\PX;&1`)`_SX]_G[_P,&!@,!`0$#!04$`P,$ M!08&!@8'"0L+"@D*"PL)!P8&!0,`_O[]_/OY]_C[``0'"0L+"0<&!@8("PX0 M$!`."P;\[-:YGI_"[`D8&A(*!/WX]OCZ_@(%!@0"`0(#!`0#`@("!`8&!@8& M"`H+"@D*"@H)!P4%!@4!__[]_/OY^/CZ_@(&"`H+"PD'!@8'"@X0$1$/#`?_ M\-S!I9RWX0(6&Q4-!O_Y]O?Y_``$!@8$`@("`P,"`0$"!`8'!P<&"`H+"PH) M"@H)"`<&!P<$`?[]_/OY]_;Y_0$%!PD+"PD'!@8&"0P0$1`/#`@"]^3+JI:I MUOL2'!@/"`'Z]O;X^_\#!08%`P("`@,"`0`!`P4'!P<&!PD+"@D)"0D)"`<& M!P@&`P#__?OY]_;W^P`$!@@+#`L(!P8%!PL.$!$0#@D"^>G4M9F@RO,.'!L3 M"P3\]O7W^OX"!0<&!`(!`0("```!`@4'!P<&!PD*"PH("`D("`<&!PD(!0'_ M_?SZ^/;W^O\#!0<*#`P*"`8&!PH-#P\/#@H#^^W:OZ*;O.D)&AT6#0;]]_3V M^?T!!0<(!@0"`0$!`/__`@0'"`<'!P@*"PH)"0D(!P8&!PD*!P,`_OW[^/;U M^/T!!0<)#`P*"`8%!@D,#@\0#PP&__/BRJN8K=L`%AX9#P@!^?3U^/S_!`<( M!P4#`0$!`/__`0,%!P<'!P@*#`L)"0@(!P8%!@D+"@8!__[\^O;T]OL`!`8( M"@P,"PD'!@<+#0\0#@P(`/7DSK"7I-'[$QX<$PH#^O3S]OK^`@8("`8$`@$! M`/[^``(%!P<'!P@*#`P*"`@(!@4%!0@+"P<#`/[]^O?T]?G^`@4'"@P-#`H( M!@8)#`X/#PT)`_GKU[R@G+_M"QL>%0P%_?7R]/C]`04("0@%`@```/_^_P$$ M!@<'!P<)"PP+"0@(!P8$!`<+#`H$`/_^_/GU]/?\`00&"0L,#`L)"`<)#`X/ M#PX*!/OMV;ZAF+;F"1L?&`\(__?S\_?[``0("0D&`P$``/_^_@`$!@<'!P<( M"PP+"0@(!P4$!`4)#`L&`O_^_/KV]/;[``,%"`H,#`L)"`<("@X0#PX*!?[R MX3.M9R][0T=(!@0"0'X\_/U^?X"!@D*"0<#`?_]_/W_`@8'!P<'"0L, M"PD(!P4$`P,%"0P-"@4!_OW[^/?Y_@(%!04'"0D)"0D)"PP.#Q`."0+WZ=6] MHINYYPD;(!D0"@+Y]/+T^/T!!0@*"0<$`?_]_/S_`@4'"`<'"`L,#`H(!P8$ M`P,%"`P-"P8"__W[^/?Y_@,%!08("@H)"0D)"@L-#Q`/#`7Z[-G!I9BPX`4: M(1H2"P3Z]/+T^/P!!0@*"0@%`@#^_/S^`@4'"`<'"`L,#`H(!P8$`P,$!PL- M#`@#__[\^??X_0$$!04'"0H)"0D)"PP.#P\."P3Y[-O%JYNLV/\6(!P3#0;] M]O/S]OL`!`<)"@@%`@#^_/S^`04'"`@'"`H,#0L)!P8$`P,#!@H-#`D$`/[\ M^??W^P`$!04'"0D)"0D)"@P-#A`/#`?]\-_)K9BDT/H4(!T4#@?^]O+R]?K_ M`P<)"@@&`P#^_/O]`00'"`@'"`H,#`L)!P8%`P,#!0H-#0D%`?_]^O?W^@`# M!04'"`D)"0D)"@L-#A`0#@C_\^+-LIJ?Q_01'Q\6#PC_]_+R]?G^`@8)"@D' M!`'^_/O]``,&"`@'!PD,#0P)!P8%`P("!0D-#0H&`O_]^_CV^?X#!@8&"`D) M"`@("0H,#A`1#@D!]N?3N9V8N^L,'2`8$`H"^?3S]?G^`@8("0D'!`'__/O] M``,&!P<'!PD+#0P)!P8%`P("!`@,#0L&`O_]^_CV^/T"!08&"`H*"0@("0H, M#A`1#PH"^.G6O:*9MN0'&R`9$0L#^O3R]/C]`04("0D(!0+__?O]_P(%!P@' M!PD+#0T+"`8%!`,"`P@,#@L'`P#^^_CV]_P"!08&"`D)"0@("`D+#0\1$`P& M_.['Q8."/_X]/3W^P`$!@@)!P0"`/_^_?\! M`P8'!P<'"0P-"P@&!00#`@(&"@T,"`0!__WZ]_;Y_@,&!@<)"@D)"`@)"@T/ M$!`."0'VY]&VG9S`ZPH<'Q%0T(`/GU]??[_P,'"0D'`P$`__[^_P$$ M!@<'!P@)#`T*!@4$`P,#!`<+#0P(!`'__?KV]?G^`@4&"`L,"PD(!P<("PX/ M$`X+!?OMV;^DG+CE!QH?%P\)`OKU]/;Z_P,&"0H(!`$`__[^_@`#!@<'!P<) M#`T+!P4$!`,#`P8*#@T)!0'__?GV]?C]`@0&!PH+"@D'!04&"0T0$1`-"`/Y MZ=.TEYS)]Q(>'!,+!?WV]/7Y_0$%!PD(!0(`___^_O\!!`8'!@<("PT,"`4$ M`P("`P4)#0T*!@(`__SX]?;Z``,%!@@*"@D(!P8'"0P/#P\-"@3\[=:XF9?! M\0\='A0,!P#X]/3W^P`$!PD(!@(``/_^_O\!!`8'!P<'"@P,"04$`P("`P0( M#`T+!P,`_OSX]?7Y_@($!@D+"PH)!P8&!PH-#P\-"@;_\^#'J)BPWP,8'Q@/ M"0+Z]//V^P`$!PD)!@,!`/___OX``@4'!P8&"`P-"P<%!`,#`P0'"PT,"`0! M__WZ]O7W_``#!0<)"PH)!P<&!PD,#@\/#0@#^>G2LI:?SOD3'QL1"@7]]_3V M^?X"!0@)!P0"````__X``@0&!P8'"`H-#`@%!`,#`P0%"0T,"04!`/[\^?7V M^P`#!`8)"PL*"`<&!@@+#0T-#0L&_N[8NIJ:PO`.'AX4#`<`^/3U^/P`!`<) M"`4"````__[_`00'"`<'"`H,#`D&!`,#`P0%"`P-"@8"`/_\^?7U^?X"`P4( M"PL*"0@'!P@+#0T-#0L'`//?Q:.5L^0&&A\8#@D"^?3T]_L`!`<)"`4#`0`` M__[_``,&!P<&!@@+#`H'!00#`P0%"`P.#`<#`/_]^O;U^/T!`P4'"0L*"`<' M!@<*#`X.#@P(`_CFS:J3IM;_%A\:$0H#_/;T]OK^`@8("`8$`0``__[^``,% M!P<&!@<*#`H'!00#`P0$!@D-#`@$`?_]^_?U]_P``P0%"`H*"0@'!P<)#0X. M#0L(`_KKU+:;H,GT$!T<$PP&_O?T]?C]`04("0@%`@``__W]_P$%!P<'!@<* M#`P)!00#`@,$!0D,#0H%`@#^_/CV]OK_`0,%"`H+"@@'!@<(#`X.#@T*!O_S MW\.BEK?G"!L?%@X(`?GT]/?[_P,'"0@&`P$``/[]_@`$!@<'!@<)"PP)!@0$ M`P,$!0@,#@L'`P#__?KW]OG^`0,%!PD*"@@'!@8'"@X0$`X+!@'VY'A0, M!?WW]/7X_0$%"`D(!@(``/_]_?\!!0<'!@8'"@P,"08$`P(#!`4)#0X+!@(` M__SX]?;Z_@(#!0@*"PD(!P8&"`L.#PX-"P@!]>'$H9.TY0<:'Q<."`'Y]/3W M^_\#!PD)!@,!``#^_?X!`P8'!P<'"0L,"@8$`P,#`P0'#`X+!@(`__WY]O7X M_0$#!`<*"PH(!P8&!PH-#P\-"P<"^>G1L)>ET_P4'QL2"@/[]?+U^?X"!@D) M!P0!``#__?X``P4'!P8&"`L,"P<%!`,#!`0&"@T,"`,`__W[]_7W^_\"!`8) M"@H)!P<&!PD-#@X.#0H'__#:O)R8O^X,'1\5#`7^]_/T^/P!!0@)"`4"```` M_O[_`00&!P8&!PD,#`D%!`,#`P0&"0P-"@4"`/[\^?;V^?X!`P4("@H)"`<& M!@@+#@X.#0L)`_;BQJ.3K^(%&2`9#P@!^O3T]_O_`P<)"0<#`0``__[_`0,& M!P<&!P@+#`H&!`0#`P0%!PL-"P8"`/_\^?;U^/T``@0("@L*"0<&!@<+#@\- M#`H(!/OJT;"5I-+[$Q\<$0H#^_7S]?K^`@8)"0<$`0``__[^``(%!P<&!@@* M#`H'!00#`P0%!PL-#`@#`/_]^_CV]_O_`0,&"0L+"0@'!@<)#`X-#0T+!__P MVKZ?F;WL"QT?%@T&__CS]/?\`04("0@&`@``__[^_P($!@<'!@<)#`P)!@0# M`P0%!@D,#0H%`0#^_/GW]_K^`0,%"`H*"@D(!P8(#`X.#0T+"`'TX,6EE*_A M!1D@&0\(`?KT]/;Z_P0'"0@&!`$``/[]_@$#!@<'!@8("PP)!@4$`P,$!0<+ M#0L&`@#^_/KW]OC\``($!PH+"@D(!P8'"@T.#@X,"@7ZZ=&QEJ'/^!(@'1(* M`_SU\_7Y_@(&"0D'!0$``/_]_@`#!0<'!@8'"@P+!P4$`P,$!0<*#0T(!`#^ M_?OX]O?[_P$#!@@*"@D(!P8&"0P.#@X."P;^[MB[FYC`[PX?(!8,!O_X\_3X M_``%"`D(!@(```#^_O\!!`8'!@8'"0L+"`8%!`,$!08(#`T*!0'__OSY]_?Z M_@$#!0@*"PH)"`<&"0T/#@T,"@G0L)6AT/L4(!T3#`7]]?+T^/P!!0@)"`8"``#__?W_`@4' M!P<&!PD+"P@%!`,#!`0&"`P-"@0`_OW[^/;W^_\"`P4("@H*"0@'!PD-#@X- M#`D$_.[8NIR=Q?$-'A\5#0;_]_+S]_L`!`@)"0<$`?___?S^``,&"`<&!PD+ M#`D&!00#!`0%!PL-"P8"__[\^??W^OX!`P0'"0H*"0<'!PD,#@X.#@L&`/+= MP:&7N.@(&R`8#PD"^?/S]OK^`P<)"0@%`?___?S]``,&"`@'!P@*#`H'!00# M`P0$!@H-#0D$`/_]^OCV^?T!`P0&"0H*"0@'!@<*#0\/#PP'`?;DRJ>3K-X" M&"$<$0H#^O3R]?G]`@8)"@@&`@#__OS]_P(&"`@'!@@*#`L'!00#`P,$!0D- M#@H%`?_]^_?V^/P``@,%"`H*"0@(!P<*#A`/#@L&`OKKU+.8HL_Y$Q\=%`P% M_?7R]/C\`04("@D'`P#__OS\_@$$!P@'!P<)"PP)!@4$`P,$!0@,#@L&`O_] M_/GV]_K^`0,%!PD)"0D("`@*#0X.#@T*!?WMU;66F\GU$!\>%0T'__?R\_?[ M``0'"0H(!`'__OS\_@$$!P@'!@8("PP)!P4$`P,#`P8*#@T'`O_^_/GV]OK^ M`0,$!PD*"0D("`<("PT.#@T*!O[QW+^>F;[L"QT@%P\(`/?R\O7Z_P,'"0H( M!@+__OS[_?\#!@@'!@<("PP*!P4$`P,#`P4*#0T)!`#^_?KV]?C^`0,$!PD* M"@D("`@)"PX.#@T+!O[QW+Z=E[OJ"AP@&!`*`OGS\O3Y_@(&"`H)!@(`_OS[ M_/X"!@@(!P<("@L*"`8%!`,#`P4)#0X*!0'^_?OW]?C]`0,$!@D*"@D)"`@( M"@P-#@X+!O_TXLBHF;/@`Q@@&A(+!/KT\O3X_@(%"`H)!P0`__W[_/X!!0@( M!P8("@P+"`8%!`,#`P0(#`X+!@+__OOX]OC]`0,$!0<)"0D)"`@)"PP-#@X, M"`'TXL>GFK/@`Q@?&A(,!?SU\O3X_`$%!PD)!P0!__W[^_T`!`<(!P8'"0L+ M"0<%!`,"`@,&#`X,"`,`_OSY]_C\``,$!0<)"0D)"`@("0P.#@X,!P#UY M&Q(,!_[W]/3W^P`$!@@)"`4"`/W[^_S_`P8(!P8&"`H+"0<%!`,"`0($"`P, M"04!__WZ^/?Z_P($!`4'"`@(!P<'"`D+#`T,"`/Z[=J]I*K/]@X<'!,-!P#X M]/3V^_\#!0<("`8"`/W[^_S_`@8'!P8&"`H+"0<%!0,"`0$#!PL,"@8"`/[[ M^/?Z_@($!`4'"`@("`<'"`D+#0X-"0+Z[=O!IZG-]`P;'!,-"`'Y]/3V^OX" M!0<)"`8#`/[\^_S^`04'!P8&!PH+"@@&!0,"`0`"!@H,"@<#`/[[^/?Y_@($ M!`4&"`@'!P<'"`D*#`T,"07^\N+)K*?&[@D8'!4-"`+Z]?3V^OX"!`8("`<# M`?_\^_S^``0&!@8&!PD+"@@&!0,"`0`!!0H,"@<#`?_\^??X_0$$!`0&!P<' M!P<'!P@)"PP,"@7_]>7-KZ;#ZP87&A,-"0/\]O3V^?T!!`8("`8#`?_]^_S^ M``,&!@4%!@@*"@@&!`,!```!!0D+"0<$`?_]^O?X_``#!`0%!P<'!P<&!P@) M"@L+"07_]>;1MZW#Z`04&10-"03\]O7V^?T!`P4&!P8#`?_]^_S]``,%!@4% M!@@*"@@&!00"`0```P@*"0<$`?_]^OCY_``#!`0%!@<'!P<&!@@*"@P,"03_ M]^K6O:Z_Y`$2&14."@7]]_7V^?P``P4&!P8$`?_]_/S]_P,%!04%!@<)"@@& M!`0"`0```P<*"@<$`@#^^_GX^_\#!`0%!@<'!@8&!@@)"@L+"@S9P*^] MX/X0&!4."@7_^?;V^/P``P4&!P8$`@#^_/S]``($!@4%!0<)"0@&!`0"`0`` M`@8)"0<%`@#^_/GX^_\"!`0%!@8&!@8&!@<("0H+"@@#^^_?Q[*XVOH-%A8/ M"@8`^O;V^/O_`P0&!P8$`@#^_/S]_P($!04$!08("0@&!`0#`?__`04)"0<% M`@#^_/GX^OX"!`0$!@<'!@8%!08("0H*"08!^O#BS+>[VO@+%A8/"08`^O?V M^/S_`@0%!@8%`@#^_?S]_P$#!04$!`8("0@&!`0#`0#_`00("0<%`P'__/KY M^OX"`P0$!08&!@8%!08'"`D*"@@#_?/FT;RZU/,'$Q4/"@^T.T##Q00"@<#_OGW^/O^`0,$!08%`@#__OW]_@`" M!`0$!`4&"`@&!`,#`@$```(&"`<%`P$`_OSZ^OT``@,#!`4&!04%!`4&!P@) M"0<$`?KQXLV^RNC_#1,1"P<#_OKX^/O]`0,$!04%`P'__OW]_@`"`P0$!`0& M!P@&!`,#`@'__P$%"`<%`P(!__SZ^OP``@,#!`0%!@4%!04%!@<("`<$`/GP MX]#"S>C^#!(0"P<$__KX^/K]``($!`4%`P'__OW]_@`!`P0$`P0%!P@'!0,# M`@#__P$$!P<%`P$!__WZ^OS_`0,#!`4%!04%!00%!@<'"`<%`OWTY]7$RN/Z M"1$0"P<$__OX^/K]``(#!`4%`P'__OW]_O\!`@,#`P,%!@<&!0,"`@$`_P`# M!@<%`P(!__W[^OO^`0,#`P0%!04%!`0$!08'"`<%`OWUZMC'RN+Y"!`0"P<% M`/SY^?K]``(#!`0$`P$`__[]_O\!`@,#`P,$!@<&!0,"`@$`_P`#!@<%`P$! M`/[\^OO_`0(#`P0%!04$!`0$!08&!P<%`?WVZ]S-SN'W!@X/"P<%`?SY^?K] M_P$#!`0$`P$`__[]_O\!`@,#`P,$!08&!0,"`@$`_P`"!0<%`P$``/[\^_S^ M`0(#`P0$!04%!`0$!04&!@8$`O[Y\.+2S=WS`PP/#`@%`?WZ^OO\_P$"`P0$ M`P(`__[^_O\``@,#`P,$!08&!0,#`@$`__\"!08&!`(``/_]^_O]``("`@,$ M!`0$!`0$!`4&!P8%`O[X\./4S]_T`PP."P<%`O[[^OK\_@$"`P0$`P(`__[^ M_O\``0(#`P,#!`4&!0,"`@$`__\!!`8%!`(!`/_]^_S^``$"`@,$!`0$!`,# M!`4%!@8%`O_[\^C:T=OP_PD-"P<%`O_[^OK\_@`"`P,$`P(`__[]_O\``0(# M`P(#!`4&!0,"`@$`__\!!`8%!`(!`/_]_/O]_P$"`@(#!`0$!`0$!`0$!08% M`P#\].G;T]SP_P@-"P<%`O_\^OO\_@`!`@,#`P(`__[^_O\``0(#`P(#`P0% M!0,"`@$`__\!`P4%!`(!`/_^_/S]_P$"`@(#!`0$`P,#`P,$!04%`P']]^_A MU=KM_`8,"P<%`__\^_O\_@`!`@,#`P(!__[^_O__`0("`@("`P0%!`,"`@$` M`/\``@0%!`(!`/_^_?S]_P$"`@(#`P,#`P,#`P0$!04$`P'^^?'EV]SK^@4* M"P<%`P#]^_O\_O\!`@,#`P(!`/_^_O__``$"`@("`P0%!`,"`@$``/\``@0% M!`(!``#__?S]_@`!`@("`P,#`P,"`@,$!`4%`P'_^_3JWMOH^`,)"P@%`P#] M_/O\_?\!`@(#`P(!`/_^_O__``$"`@("`@,$!`,"`0$``/\``0,$`P(!``#_ M_?S\_@`!`0("`P,#`P("`@,#!`0$`P'__/;NXMWG]@$'"@@%`P'^_/S\_?\` M`0("`P(!`/_^_O[_``$!`@("`@,$!`,"`0$``/__`0,$`P(!``#__OS\_@`! M`0$"`@,#`@("`@,#`P0$`P(`_?CPYN#F]/\&"0@%`P'__?S\_?\``0("`@(! M`/___O__```!`@(!`@(#!`,"`0$``/__`0(#`P(!``#__OW]_O\!`0$"`@(" M`@("`@(#`P,#`P(`_?GRZN/G]/\%"`<%`P'__?S\_?X``0$"`@(!`/___O__ M```!`0$!`0(#`P,"`0$``/__``(#`P(!``#__OW]_O\``0$!`@("`@("`@(" M`P,#`P(!__OU[N;G\OT#!P<%`P(`_OW]_?X``0$"`@(!``#_____```!`0$! M`0("`P,"`0$!``#_``$#`P(!``#___[]_O\``0$!`0("`@(!`0("`@(#`P(! M__WX\>GH\/L"!@<%`P(`_OW]_?[_``$!`@$!``#______P`!`0$!`0$"`P(! M`0$```#_``$"`@(!````__[]_O\```$!`0("`@(!`0$"`@("`@$!__WZ]>[K M\/D`!`8%`P(`_OW]_?[_``$!`0$!``#______P```0$!`0$!`@("`0$```#_ M``$"`@(!````__[^_O\````!`0$!`0$!`0$!`@("`@(!`/[[]_'M\/G_`P4$ M`P(`__[]_O[_```!`0$!``#______P````$!`0$!`@(!`0$````````!`@(! M````___^_O\``````0$!`0$!`0$!`0$"`@$!`/_]^?3P\OC^`@0$`P(!__[^ M_O[_```!`0$!``#______P````$!```!`0$!`0`````````!`0$!````___^ M_O__``````$!`0$!`0$!`0$!`0$!`/_^^_?S\O?]`0,$`@$!`/_^_O[__P`` M`0$!``#______P`````````!`0$!`0```````````0$!````_____O\````` M```!`0$!`````0$!`0$!``#^_?KV]/?\``(#`@$!`/_^_O[__P`````````` M______\``````````0$!`````````````0$!`````/______```````````` M``````$!`0$!``#__OSX]_C\_P$"`@$``/_______P``````````______\` M`````````````````````````````````/______```````````````````` M``````#__OW\^OK\_P`!`0$``/_______P``````````________```````` M`````````````````````````/_______P`````````````````````````` M___^_/S]_P```0````#_______\``````````/______```````````````` M`````````````````/_______P``````````````````````````________ M_P````````#_______\```````````#__P`````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````!#3TU-````$@`! M```T%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P`````` M````````````05!03````:A39#)A``(````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`I`````````````````````````````````````````````````````````` M```````````````````````$"```````"0`C`````````````````'@````$ M``0```````#\`/___X`````!`0`&455N:71S```````````````````````` M`````````````````0(`!B!S86UP````%8``````%;^`/___X`````!`2`&455N:71S```3""YP9P5" M=6=L90(```!!249&4V0R80`````````````2JP````!!249&4V0R80`````` M`````````````````````````*<]K=8``#8B```!S@```!T`+P`/__;_^0`! M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````:`"D`#P)J`S$`*@`#`FT# M/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0`````````````````: M`"P`%@$^`=P`*@`#`FT#/0`````````````````:```````````````````` M``````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7```````#__\````\```````$__\` M``!:```````````````````````````````````````````````````````` ,```````````````` ` end nethack-3.6.0/sys/share/sounds/erthdrum.uu0000664000076400007660000015006312467321052017604 0ustar paxedpaxedbegin 644 Drum_Of_Earthquake M`!)$CK[>_P\O3V^/K\_@`"`P4("PT.#A`3%A<7%A@<(B8G)B0E*2XQ+RHG*"XU M.SLW,2XR.T-&0SLS,39`2U-434`Q)2,K/$U96E%`+!H-!@P>.UMQSGX=S7TLS'PKZZM[6TM;:Y MO<''SM?AZ_<#$!PI-$!*5%QE;&]O<'!O;FYN;6YM;FUL;6UN;FYO;W!P;VUJ M9V1?6U=44U-55EA:7%UA9FQQ='1R<&UJ:&AI:FQN<')T=7-Q;V]N;FQH8EU8 M5E-03$E&0T`^.SHX-S4U-#0T-34U-C8V-C4T,S$N*R@E(AX:%A(."04`_/CW M]_;U]?7U]?7U]?7U]/3S\O+Q\/#O[^[N[>WL[.OJZ>CGYN7CXN#?W=S;VMG7 MU=/1T='0SLG#P+Z[N;BWM[>WM[>WM[>WMK:UL["LJ*6BGYV;FIJ;FYN9EY:6 MF)N>H:*AGYZ;L[_+S]?;W^/CY M^/?U\_/T]_P`!`<*"PL+"PL+"PL,#`L)!@+__?O\``8&5D5T8X-3@W+1T2#@\-!__\_P8-$!`+`?3JYN?L\O?\`0<-$A89 M'2`C*#`\3%ME:FYP;VMD5T8U*R@D&Q`)!0+]^/;RZ^'6RL"[NL#(SQJJ2@G)B8F)>0AX&`A(F. ME9VCIJ*9CXB*E:2QN\/+T=+3UM[DY^7CYN[Z!A`7'B0J*R3EZ.OL[.OM\_H``P0$ M`P'__P(&"@X/#0D%`@($"`T0$Q,1#0H'!00$!`,!__WZ]>_HY.+BY>KR^@0. M&2$C(!H3#`<$`P(#!0D-$A<;'A\?'AT9%!`,"0@*#A0:'B`>&!$+!@/_^O3K MX=C0R,*^O+NZNKF[OL+(S=/7VMW?X-_/BX>'A MX>'BX^3DY.#:U-7>Z.GDX-_7CX^3CW=?2U=G:T\G"O\'*V.;O\.K@ MUM7B]0`#`O_^_/S[^OKY]O/O[.GFX^'>V]C6T\['O[>PK*NNL;2VM[BYO+_# MQ\S/T]78V^'I\?;W]O#FW-O@Y.'>V]?5U-76U]C8V=O@Z//]!`4#`PH4'2$B M)2@K*RHH(QD,`/;R\O?_!0L0$Q46%A44$A`/#@X.#Q`/#@L'`_[X]/#N[>_T M_0D6(2@K*24B'AL9&1D;'!P;&184%!05%186%A45%!,1$`X,"PL+#`T.#P\0 M$1(3$0P#^.SDX.#@X>3G[//^"QHG,#0T,2XM+B\O+BPI)R8E)BKL[O#O[.?AWM[BZO/\`P@*"04!_?T##QH>&A00#A`1$`L&`O_\ M^?7QZ=_6TM+5V^/P`1`;'A@-_O+L[.[P[^ODWMK9V=WD[OH$"@P,"PH("`L0 M%!01#@D%`@("`?[\_/S]_?X!!@L2&!P>'1L7$0P("0P/#@L(`_[Z^_\$!@0! M_OOW\>GCWMW=WMWKS_`0)"@<# M_OGS[>SP]/;U]/;Z_P$!``($!`#\^?7R\/'U^P$'"PT,"`+[].[JZ>ON[O#W M`PX3$Q8=)"HL+"PO-CHY-C@^0D`\.CP]-B@:#P?_^?C[_/COY^;K]/X$`?CR M]/GZ^?L`!`/]]N[FW-#'Q,K0S\G#P\;*S,W0UM[DZ.KN]?X'$APE*2PN+BTI M(A<-"0H+!OWV\>OEXMW4RL3%RL[.R<&^P\K+P[FWO\G.RL?+UN+J[?'V^?;O MY=G,OK"DG)>8G*&FJ:VSN\3,SL[-T-?>XN+CY>CIZ>GJ[?'U^P`%"@P.#P\/ M#Q`3%A40"P\8(B@J*RTQ-SLY,S`V1%%64TD[+R8C(R8J+"PJ)2`;&1@8&1D7 M%A,1#P\/$!`0#PX.#Q(6&AT='!XD*2HI)2(?&Q@5%!,3$A`.#`H(!@0#`/WZ M^/;T\>K>T<2]N;.JH9N:G:*EI:2DI:BJIY^6DY:;GIZ(!T6#P<`^?;U\^WC MVM75V>#I]``)#@T+#!`1#@8`_P'_^O3P\?;_"A09&AH:&1<6%101#@L)"`H- M#0L(!0(`__[^``(#`__[]_7U]O?Y^OOY]._L[.[Q\O#IW];3VN7N]/CZ]^_H MY>CM\/#KY-_?Y.GM[_#U_04+#A$5'"0I*B&QD8&1D8%A$* M`_SV\O'R\_/R\.[O\O7Z_P4,%!XJ.45+2D0^.SHX-#`N+S$P+"(5"@0? M(R0F+#(S+B(5"P@)#`X1$`T*"@\7(2DM*RS[#AXI M+2LC&1`.$!(4$0P%_OO[_O_]^?;W^/;MX=G6V-O>W]S;W>3O^/X!`P0#`O_Z M]/+V_PH3%A00#@\3%QD:'!X?'1P;'!T='!H6$`?]\^SFY.3FZ_'U]_?W^/K^ M`@8+$18:'!TA*35!1T8],28A(B&QP<&QD7&R(G)!L0"08'#!(9'AX8#@4```$!__OY M^/GZ^??W^/O_`P@0&2(G*2HK*B4>&!88'!\C)B@H)B,@'AL9%0X$_/CW^/O^ M``#\]O+T]_?SZN#9U]C>Z/+X^OO\`0H5'R0B&0\'!08'!0#[]O/S]_\+%R$I M+"LE'!$%^_;X``P7("8H*"8A&Q<4#PC^]>[IYN+@X.3J[O#Q\O/U]_?V]_K_ M!`@*#`P+#`X3&1T=&Q81#0L+#`\1$Q(1#Q$7'1X:$PT)!@4&"`L.$1,3$Q49 M("P MK*FEHJ*FKK.QJ*&@IZZQKJFGK+2ZO\'#P\+#Q[T^@`#`OSU[NCDY>KR^P('"PX1$A$."@7_^/+LZ.;E MY.3DYNKO]OT$"0P.#0H&`@#]^?/JX-;.Q\&\NKFYN+FYM[2OK:^TN;W`PL;, MTM;5TLW,S,W,RLG*S,[1T]+,Q+NSKZ^QM+6UL["MJJ>CHJ.FJZ^RM;J_QLS1 MU-;8W-_?V]+(P+V^Q,S3V-K:V=K=X>7J\/C_!0L4'RHS.3Y%35)444M$.S0N M*20?'!H7$`?\\^_P]/GZ]_3S]OL``/[[^?O\^O3KX]W;WN;Q_`@3&QT:%!`1 M%1LA)BDK*RDD'!$'`/T`!PP,"`0#`P0$!P\9(R@G(AT;'"`A'QL7$PX(`OS[ M_@($__?PZ^KL[_+V^?K[_0,-&28O,S0S,S,U-34T,C$N*R MW-O;WN3M]P`'"PH'`?W]`@@.$`\-#`P-#`D%`?[[^_X!!0<(!@#W[NKL\O?X M]_;X^_\!!0L4'RCDXN'?W=O9V-?8VMWBYNGK[_7_"Q@B*2TN+2TM+2TL*2,=&!45 M%A<<(RPR,BTF(1\?'AP7$@T(!`#]_/KY^/CW]O;V^/K]__[Y\>KDXN+AW]W< MW-O;W-_EZNKHYNCO^@81&1P;%0X&`/W[^OOZ^OCV\N[LZ^OJZ.?HZNWR]_O\ M^_CU]?;Y_@0*#1`2%!<6$PX)!0(`__\``0(%"0T1%!<:'!\D*"TO,3(S-38V M-30S-CQ$351:7V)B8%Q74DU'0#8L(QP8%Q@<'R`?'1L9&1PB*"PK*"4C)"8H M+#`V/$%%1TA)2DI)14`\.ST].3`E'1H<("0C'ACM\._LZ.;EY.3CX^3GZ^WMZ^OP^`$%!0'[]?/S^/X% M"P\3%QL>(2(C)28G*"@F(AL2"/_Y]?/Q[^WL[O'V_``"`P0(#`X-"`'Y\_+T M^/S_`/[Y]/'P\O/S\.KBV=+.R\K)R,?(R\_4V=W?W][;UM35W.7L[>GAW-O? MY.CIZNOM[^_KY=[8U=+,P[JWN+W&T=SCY-_8TM'7W^?L\?;Z_?[___[Z].WI MZ.?FY.3FYN+8S<*[M[:XNKV_P<+!O[V\O+R[M["II:6GJJRNK["PL+&SMKJ] MO\+$Q<7%Q<;*T-;OKY]_6T=+7 MX.GP\_+R]/?Z_/W^_P(#`OWU[.;DY.+>VM?6UM;5U-+/SKJ[._Q M\>_N[.SM\//U]?/NZ>7BX-S5RKVQJ**=FYJ;G9^?GZ*KM;JYM+"RN+_#P\#` MP\G0U=KAZ?#R\.WN]/L``?[Y]/#N\//X_/\!`@0)#A`-!P'Z\^WHY.#=V=71 MSLS+S,O'P;_!QLK+R<7"P<'"PL3)TMOBZ.SR^?X!`P,#`/W[^??V]?3R[^KE MX-_?X.'AX-_=V]C5U-?=Y.GN\O;X^?GX^/K^`P4"^O/P\O;Y^OT!"`P-"PD) M"@H)!@0"`P@1&B`A'!4."@8#_OKW]OCZ_/[_``$!`0("__GPY][7T];=Y^[R M\O'O[.CFY^KL[N_N[>[O\?+S\_/S\_/S]?7R[>?BWMW>W=C3SLS+R\G'QL7& MR,O/T]?:W-[AY.CL[N[MZNCGZ.ON[^[LZ>?DXN'AXN3EY^KM\?7X^_X``0$# M!@D,$!,5%QLB*C`T,S$R-CHZ-S0S-3H^0#\]/D)'2TY/45)24$Q(1DA*3$M' M/S65545%)/3$I-5%YH;W)R<&MH9VAK;7!Q#=W-W>WM[?X^KN\?/V^P`"`?SY M^OT``P+__?O\_?W]^_CV]?3T]/?[`0<-#PT&_O?R[NKIZNWP\O+P[NWL[O'U M^?S^``0(#!`3%1D=("(B(1\;%Q$+!@+_^_;PZ>/AX^CN\_?Y_/X!!`<)"PP- M#`D$_?CT\>_N[^_O[NSKZ>CGY^?FY./CX^'#AWMC2SLS+R\W2 MV-SCEXN#@W][V MM[N_PL3%QL;&Q<"\NKN^O[Z[NKJ[OL+&R]#6W>/I[O'T]_K^`0(!_OW^`@0# M__OX]O7R[>;>U]35VN#FZ>KGX^#=W=[@X^?JZ>?CX-W9U='-S,O*R,;#P<"_ MP,+%RM'7V]S=W=W=W=S=WN'CY./@WMO:V=O>X^?GY.'AXN'>VMG;WN#?VM74 MUMKXN;HY^7DY.3DXN#?WM[=W=S;VMK;W>#BX>#?WM[>WM[>X./GZN[R M]?;U\_3V^OW__OW[^/CY_0$%"0P/#P\/#@\/#Q$1$0X+"`8%!08&!@4$`@#] M^??U\_#LY=_7T,K&PKZXL:NHIJ6EIZNTO\W9X.+AX.+FZ>CCW=C6U=73T]37 MV=G7UM?:W^/GZ>SP\_;W]_7T\_/S\O#MZNGJ[.[N[>OJZNSM[>SL[>WM[>OI MY^3BW]W;VMK;V]O9U];7V=O>W^'CYNCIZ>KM[_'R\_3U]?+N[.SP]?K_`P4# M`?[\^_GU[^C@V=31S&A82#PX-#`D%`/W\_@(%!P4" M_OS[_0`%"Q(:("(@'1@5$0X)!@0"`/SX]/+R]/?Z^_S_`@4%`OWW]/+T]_O] M_/GW]_GZ^??U]//Q[>CDX^/CXM_;U]75V-SAZ?#W_``"!0<("`<&!@D-#P\- M"@D+$!@='QX='2`B(R(A(B4K,#0V-C8U,S$N+"PM,38\0D9)2$5`.C0N*RHI M)R,>&QL=("$A(B0H*RXO,#$S-SH\/#HW,S`K)R$;%A(1$A48&AXB)2@H)R4D M(B$@'Q\@'QT9%`\,"08%!08("`@("0H*"0D*"@@"^O+N[_/Y_P,$`P(!`@,% M!PL0%1@8%A,1$1(4&!TB)BHN-3Q"2$Q-2T=$0D`_/3LZ.3H\/T1(2TQ)14`\ M.CL]0$)#1$9&0SPT+2DH*2HH(QT9&1XF+S8\/CX]/#HW-3,U.#Q`1$E/4U=7 M5$])0CLV,S(S,S,Q,"XO,C<\/C\^/C]#1TQ26%YA8%U955-24E%/2TA&145$ M03TZ.#;BX-[>WM[>WM[?X>3FY>/@W=W=W^'DYN;FY>;FY^?FY.'@X.'D MZ.KL[.OJZ>OM\//U]O;W^/K[_/OY]O+O[.KHY^;CX-W;V=?5U-78VMO:V-;4 MTM+3U-75U-+1T,_.SM#3V-O>W][>W^'E[//X_/W^_P$$"A$7'2`B)"4F)B4B M'AL8%Q83#@<`^O;S\_3W^_W^^_CU\_/T^/X%#!`/#`<"`/_^_P$#!0<&`P#\ M^OK\_P$"`@("`@(`_/?QZ^7@W-G8UM74U=?:W-W;U]/1T=/3TL_-SM'4U]G; MW=_AX=_=W-O:V=;3T,S)Q\?(R\_3UM?6T]#-S<_2UM?5TWM[F]PL?*S,S-T-;>YN[U^_\!_O?PZN?GZ>KH MY>'>W=_CZ.[T^/KZ^?CX^OO\^_KX]?'LZ.3BX>#?WM[?X-_>V];/R=I*NQM;>XNKN^P<7+ MTMG?Y.;FX^#+FZN_S^/S_`/_\^?GZ_?\` M`0$!`0$#!0@+#0X-#`L*"@<"_/7Q\//W_``"!`8*#Q4:'B(G+#$U.#DX-S0Q M+BLI)R0A'1D8&!L>'Q\=&!,."@<%`P$`__\```#__?S\_/S\_/S\^_GV]?C^ M!@X4&!L='R`B)"8H*2DH)R'!P>(20G*2HI*2@F(QX7$0P(!0']^OCW M]_CZ_/\#!@<'!@0"`0$"`0#^_/KX]O/O[.OL[_/U]?/Q\?'S]OK_!0L.#PX. M#@\/#P\-#`H'`OWX]?/S\_3V^?O\_/KZ^_W_``#__/KW]?3U]_L!!PT2%!44 M$Q,3%!46%A85%!47&1H9%Q45%A86%!(1$1$2%!<9&1@6%103$@\,"0<&!@8' M!P@("Q`7(2HS.C]"0T$^/#HX-C(N*20>%Q(/#Q$5&!H;'!\B)"8G)B4B'QX? M(R(",E)B@H*"@F)2,A'QX='1X@(B0D)"0E)BDJ*RLK+"PJ*"0A'AT< M'!\B)"4C(!T;'!\C)RDG)!\;&1D:'!\A(R0C(!L6$1`4&B`E*"DI*2LP.$!' M2TU/3T]-245"04%!/SLV,BXL*24A'1H8%!`-"@D)"@P/$A,2#PP)"`H-$!06 M&!@8%Q45%AD<'1T='1\A(R4F)RDK+3`R-#4U-3(N*B0?&Q<5%!,2$A07&QT< M&A<5%!,3%!8;("0G*"@H*"@G)R&143$A$1$A06%103%!@>(RWN[_'S\_3U]_O_`@0$ M`O_\^//LY=[9U];6U-/0S'CY./AX.'BY.3CX=[;V=?5TL_-S,S,S,W-S]#/SLO*RLO,SVM;6VN;N\O+N[O+[!Q3CXN'@WMS9 MUM/0S\[0TM78V]W>W]_?W][;UM#*QL/"PL+#Q,7%Q<3"P<'%R]+9W^3HZ^[Q M]?G]``(!_OOW]O;V]_?W]_?V]?/Q[^WLZ^KJ[.[P[NKDWMK8V-K;V]K7TLW( MQ<3&R+@W]_?W^#AX-W8T,G# MP,#"Q+CX^3DX^'?W=O8U='.R\K)R;L\?/T]??Z M_/OY]._KZ>CIZNSO\?/T]/3V^?T!`P8("@H)!@0#`P(`_OOY]_7T]/;X^_[_ M__[[^/;U]O7T\_/T]_K]_O___P$#!@H-#0P*"`<'!P@)"0H*"0@'!@4%!00# M`?[Z]O/R\_7W^/?U\O'Q\_?\``0&!P4$`P0&"0P/$105%100#0L)"`8$`P0& M"0P.$1,5%QD;&QH8%Q<7%Q<6%!$."P@&!0,`_?GU\.SJZNOL[N[M[.OJZ^WP M\_;Y_@,*$AHA)B@F(Q\;&AD:'!X>'1D4#0;_^_O]``,$!`,$!`4%`P(````! M`@,"`?_[^/;X_``"`@#\]O'P\?/V_`(("PP,"0/\]_3P[.ON]?T%#!(4$@T' M`__\^_X!!`8(#!0;'QT6"O_Y^?T!`P,!_P`"!0@,$!48&AH:&1@:'B0J+S4Z M/D`^.S'R`?'!8. M!O[X]?/T]OCY^/7Q[N[P\_7U]/+R\O3W^_W^_?W]_P(&"0H*"PP/$A49'!X? M'AT<'!T?(RXN;R^P<+!O[Z^ MOKV\NKBWM[BXM[6TM;BZN[N\O+R_Q,K0TM+1S\_/T-#0S\W+RLG)R\_2T]/2 MS\O(Q<+!P,'"Q,7&Q\;$P;^]OL#$R,W2UMG;M\?/R\?'R\_/OZN7AX.#B MY.;IZ^[P\_7W^?GX]_7S\_/U]?7S\._N[_'R\O+Q\?'Q\._P\?+T]//S\_/S M\_'P[^[O[^_P\/'R\_3T\_'NZ^KHYN7DYN?IZNKJZNKGX][8U=/3U-;6U='. MR\O-T-/5U=+/R\K*S='4U=73T,[.T-/7VMS=W=[BY^SP\?+Q\O+T]??Y^_O[ M^/;S\O+S]?;W^?O^`04("@P-#A`2%!87&1H:&182#PP*"`@&`_WW\>SHY>'> MV]C6T]'.SVM+2UN+S`Q,C,S]+4U]K>XN7FX]W7TOO\_?Y^OKX]_;X^?O[^_KX^/CX^OO]_?OZ^/?W^/K]``,$`P(" M`@($!0<(!P8$`@(#!08'!P<'"0P1%APB)RPO,3$P+"_O\?3V]_?U]??Z_@(&"0H*"PX3%QD9&AL='!H7 M%1,2$0\-#`P.$!$1$1(4%Q@8%1$."P<"_?S]`00%`P$"!0H1%QD8%A04%186 M%A46&1XB(R,?&Q<4$A(4&2`F*2'Q\=&QD9&!@8&!<5$@X+"`8&!04& M!@8&!@8'"0P/$1$/#@\2%AL@)"DN,C4V-C8X.CU`0#TX,BTL+3(V.S]"1DA+ M3$U-34Y/3DM$.C`H(B$B)2DK*RDG)RDM,SI!2$]35%-134E&1$-!/CPY.#D[ M/C\_/#(B#AX>'@W=K7UM?7U];6U]?6UM75V-WD M[/+V]_?V]O7T\_#KY=[6T,O(R,C(QL/`O;N\OL'$Q\G+S,W,R\G)RLS.SLS) MQ,"]O;Z_P,"_OKV]O;V]OL##QLG,T-38V=K9V-C8V-C8V-C8V-G9V][AYNKM M[_#P[^_P\?+T]?7U]/7V]_CY^/?T\>_N[>[P\O+Q[NKFX^+CY>GL[N_P\?3X M_0$#!`,"`0($!PD+"PD&`?[Z]_3Q[^[O\/+S]/7U]O?W]O/MYM_9U-'.R\C% MP\+#QHJ6HJJJKK*ZQM+6TL[&OKJZPM+G`QLO/T=+1T,W)QL*_O+JYN+BV MM+&NK*RLK:^SN+[$R MW-O:V]S>X.'BXN/CX^/CY.;GZ.CHZ>KKZ^OKZNGHY^?HZN[S^/O]_O\``0$! M`/_^_?OZ^/?V]?3S\.SHY-_;U];5U=34U-77V-G;W=_BY>CJ[.[Q]?C\_@`` M`0(#!@D-$!(4%187&!D:&AL<'1X@(R8I*BLI)R0B(!\@(2(D)"0C(B`>'!L< M'!P9$@H`^//P[N[MZ^KHZ.GK[>_Q\_7W^/CY^OO]_O[\^O?U\_'P[^[M[.SK MZ^OKZ^KHZ.CK[?#R\_/Q[^SIZ.CIZ^WP\_7U]/+P[_#R\_/P[NSL[O'U^?T" M!@D*"PL*"@D("`<&!`'^^_GW]O;W^/GY^?GX^/CY^_S\^_CS[NKFX^'@X>/F MY^CHZ>WR^?X``/___OSW\NWJZ.CK[_/V]_?V]_G[_0`$"Q(9'2`C)2@J*B@F M)"(@'R$F+3,W.3@U,BXH(!D4$A4:("0G*"@I*2HK+2\Q,S4X/$%'35%45E53 M3TM&0T`^.SDW-34W.C]#2$M-3D]04E165UA:7F)G:VYP<&]L:&->6%-/3DU- M3$I'0CPV,"PI*2DI*BLN,SI!14A(24I,3U%14$]/3U%24E!-245"/CHW-#,S M,S0U-C8T,B\M*B'!D6$Q`.#0P*"`4"__W\_/S]_O_^_/KW]/+P[^[N M[>WM[>OJZ.CHZNWP\_;Y_/X``0,$!04#`/[\_/S]_OW]_O\!`@(!__SY]O+N M[.OK[.[N[N_P\?/U]O;R[>;AWMW>W^#AXN/CXN'AX^?L\O@`!P\7'B0I+"XP M,#`O+"DG)B@I*2(R8G M)B0B("`@(2`>&Q82#@P-#@X-"0/]^??U\_#MZ^KJZ>?EX^+BX^7GZNSO\?+R M\?'Q\O3V^?O]_OWZ]_/P[>OJZ^[R]??V]?7U]OCY^_W_`00&"0L+"@@%`?_\ M^O?S[^OGY>/BX-_?WM[>WM[>W]_?WM[>X.'CY.3CX>#AY.CN\_;W]_;U]/3S M\O#O[N_P\?+R\O'O[>GFY./CX^/CX^+@W]W=W-K7T]#.S,G'Q\K0U]O=W=S; MV]O:V-;4TM'1TM34U-+/R\;"OKRYM[2RL+"PL;.VN;N[N[N\O;_!Q,C+SM#0 MT-'2T]+0SCK[>[N[N_P\?'R\_3U]O;T\>WJY^;EY./A MW]WVM71S]#3U]O=W^'DY^OM M[O#R]?;V]//S]?CY]_/NZ>7BW]W/FZ.CG MY>+>VMC6U]K=X.+DY>?I[?'W_0,(#`X-"PH*"@L-#@\."P<#`/[_`0,$!`0# M`?[Y]?+Q\?'P[NKFX^'@W]_?X.+DYN7AW-?5U=?7GY^?FY^CK[>[MZ^GH MZ>SQ]_S_`0#^^_GW]?3R[^WL[>_S]_O]_P`"!`8'"`@*#!$6&AT='!L<'B`@ M'AL9&!D:&AD8&!D9&AD9&!<6%1$-"`0"`P8*#A$3%!03$Q,2$1$1$1(2$A$1 M$Q47%A$,"`<("PP,"@@'"`@'!0,"`P4'"`<&!08(#!`5&AXB)2'R$C)2&Q@6%105%144$Q$.#`H)"0D*"PT.#P\/#P\.#@\0$Q47%Q84 M$A`/#@T+"0D*#0\1$1`.#0L*"`<&!04%!@<("`<&!04$!`0$!`0$!`,#`P0% M!@<'!@4$!`4&"`D*"@H*"PT.#P\.#0T.$!,7&QXA)"DN,C8X.3DY.##AX^;IZ^SL[>WN[_#P[^[M[>SKZ>;CX-[;V=?5 MU=75UM;6U=/1T,[,RL?$PL"_O;RZN;FZO+[!PL+!O[V\O+V_P<+"PL+#Q#BX=_ MW^#@X.#@W][7EYN;GZ.ON\O;Z_@(&"0P.$!$3%AD;'1P9%1`, M"0@'!@4#`?[[^/7R\?'Q\>_KY^3BX>#@X-_?W][WMWKL[O+W^P`#!@D)"`8$`O_\^?;T\_+S\_3U]??Y M_``%"`H+"PD'!`("`P8("PX0$1(3%!47%Q@8&AP>(2(B(B$@'QX<&A@6%!(1 M$1$3%AH='R`A(R,C(A\=&QL<'R(E)20A'QT;&QP<'1T>'B`B)"8G)R8F)B'A\?'QX='!T>(2(B(1X;&1@8&1H: M&1<4$0X,#0X1$A,3$Q06&1XB)B@I*2DJ*RTN+S`Q,C0V.#@V,S`M*R@F(R`= M'!P='A\?'AT;&AD9&1D9&AL<'!L<'1X@(2$?'AP;&QL<'!T='AX>'AT<'!L; M'!P='B`A(B,C(B`>'1T='AX<&183$1$3%QH<'1X@(R8J+2\O+RXM+2\P,3(S M-#,R,"TK*RLK*B'R`@("`@'QX<&QH:&AD8%Q@9&QT?(2(B(!T:%A(0#P\0 M$1(4%187&!@7%A86%Q@:'!X@(B,D)24E)"(?'!D7%A86%A44$A`.#`H(!0," M`0``___^_@`"!`4%`P#]^_O\_@$%"0T/$!`/#P\.#0L)!P8&!P<("`<'!@<' M"`D*"@H+"PP-#@X-"P<"_OKW]O;W^/GZ^OKZ^OK[_?\``0(#`P4'"`H*"@H) M"0D)"`8$`O_]^_O[^_S\_?W^``(%!PD+"PL*"@H*#`T0$Q88&QT='1P<&QP= M'1X>'R`B)"4E)2,@'1@4$0X,"@D(!P4$`@$`_OSZ]_7T]/3U]?7U]O;V]?;W M^?S^```````!`0,$!0<*#`\2%!04$A$0$!`/#@P*"0@("`@(!P8$`?[[^/?V M]_GZ^_OZ^??U\N_MZ^KIZ.?FY>3DY.7EY^GL[O#P[^WKZNGJZ^SL[.SKZ^SN M\//V^/GZ^_O\_?W\^OGY^?K[^OCV\_+P\/#Q\O/T]//Q\._N[NWJZ.3@W=K6 MU-+1T-#0T,[-S,[1U=O@Y.?HY^;FY>7FY^GK[>[O\/#P\/#P\?/V^/KY^/7S M\?'S]_P!!08&!`(`````__W[^/7S\O#NZ^CFYN;FY^GJZ^SL[.OIZ.;EX^+B MX>'AX>'AXN+BX^+AW][=W-W>X.#@W]W:U]32T=#/SLW+R,7#PL'!P<+$QLG+ MS,W.S\_0T='1TM/5U=;5U=33T]34U=;7V-G:VMO;W>#DZ.ON[^_O[>OIY^7B MW]O8UM74T]'/SLW-SKJZ>?DX>#@XN3FZ.KKZ^KIY^7BW]S9UM/0S;GZ.CHY^;DXM_WLZNCEXM_>W^'DYN?HZ.GJZ^SN[_'T M]?;V]?/Q\._O\/'R\_/T]?;W^/GZ^_W]_OW\^_O\_?[^_?KV\^_MZ^KIZ.?E MXN#?W]_?WMW;V=C8V-K>XN;I[?#S]OG[_/S\_?\!!`<*#0\1$1(2$Q,3$A$0 M$!`/#0L(!0(`__[]_/O\_?\!`@0%!PD,#A`1$`X,"08#`?_^_O[^__\```$! M`@0&"@X2%186%1,1#PX-#`L)!@+__?W\_/W]_?\!!`<("`<&!@<*#0\/#@P* M"0D+#A`1$`X+"0<&!PD*"PH(!@0"`@,%!P@)"@L,#A`1$A,3$Q(0#PX.#Q$2 M%!04%!47&AXB)"8G*"LN,C4W.3DX.#'AX>'A\@(2(B(B(B(R0E)RHL M+2TL*RDG)2,B(2$A("`?'AX='A\@(B,C(A\;&!43$Q,2$1`/#@T-#@X0$A89 M'!X>'AT<&QH8%Q85$Q(1$!`/#PX.#@X/$106&!H;&QL<'1\A(B(B(2`?'!D6 M$Q`/#@\0$1$1$`\0$A8:'B(E)R M'1P:&1@7%A44$Q(2$A(1$1`/#@P*"`4"_OOX]O;U]//Q\.[LZNGIZ>GK[.WN M[_#P\?+R\_/R\O+T]OG\_P(%!P@)"0@'!@4%!08&!@4$!`,"`@$````!`@0% M!04$!08("@P,"P@&!04&"`D*"@D("`D+#0\1$Q47&AP>'QX<&1<4$@\.#`H( M!@4%!@<'!P8$`@#_``$"`P0$!`0#`@$````"`P0$`@#\^?7R\.WJY^3AW]W< MV]K9V-C9V][BY>?GY^?FYN7EY>;EY>3CXN+BX>'@W]W=W-SWM[=V]K8U];6U]C: MV]W?X.+DY>?HZ>KK[.SKZ^KIZ.CHY^;DX^/DY>;HZ.CGY>+@WMS:V-;5U-+2 MTM/5V-O>X>/DY>3DY.3DY./BX>#@W][>WMW=W=W=WM[@XN7HZNOKZ^KJZNKK MZ^OKZNKIZ>CHZ.GIZNKJZ>?FYN?HZ>OL[.SL[.SM[>[N[N[O\/'R\_7V^/K] M_P$$!@D,#A`1$`X+"0@&!00$`P,#`@(!__WZ^/;V]O;W^/CW]O;V]_G\_@`! M`0#__O[^_O[_``($!0<)"@L,#0X.#@P*!P/__?OZ^?CU\_'P[_#P\?'Q\?'Q M\?'P[^[LZ^GGY>3CXN#?W=S+DY>;GY^CIZ^WO\/+S]/7V]O;V]O?Y M^_W^_OW\^_KY^/?V]?7U]O;V]?7U]O?X^?GZ^_S]__\`___^_?W]_/S\_/OZ M^?CX^OT"!@H,#`L)"`@("`@&!0(!`/\```$#!0<)"@H*"@H+#A$3%145$Q(2 M$Q,3$A`.#`L+#`P-#`L+"@H*"PL,#`T.$!,8'2$D)B8E)20E)B@J+"TM+2TM M+2TM+"PL+"TN+R\P,#$R,S0T,S(R,C(T-38V-C0S,C(R,S0U-C&A<4$A`0$!`1$1(4%1<9&AL<'!P<'!P<'!L:&1D9&AL<'!H9&!<6%A86 M%Q<8&!@8&!@7%Q<6%103$A$0#@X.#Q`2$Q03$A$0#PX.#Q`2%!<9'!\A(2$@ M'Q\A)"@L+S(T-CWJY^7DY.7EYN?H MZ>OL[>[N[^_O\/'S]/7U]?7U]//Q[NKGY./CX^3DY./BX>'@X>'AX>'BXN+B MXN+BXN+BX^/DY.3DX^/CY.7FY>3AW][>W^#BX^/BXN'BX^7HZNSM[>OJZ>CG MY^?FYN7EYN;GY^CHY^?GY^;DX^+AX>#?W=O8U=+/S,K(Q\;%Q<;'R,G*S=#4 MV-K'AXN/EYN?GYN7DX^+@W]W;VMC7UM;5U=75U=/1SLS)Q\7$ MPL"_O;V\O;Z^OKV]O;[`P<+#Q<;'Q\?'QCJ[>[P\/'Q\?'O[NSJ MZ.7CX=_>W=S;GY^CIZ>KK[.[O\/#Q\?'R\_/S\>_LZNGIZ>OL M[O#Q\O+S]/3U]O;U]/+Q\?'R]/;X^?GY]_7S\>_LZ>?EY.3CX>#>W=W=WN#B MX^7FYN?IZNSN\?/U]_?W]O;U]O?Y^_W__P#___[^______[^_O[^______[\ M^OCV]//R\?+R\_3U]//P[.CDX=_?W^#BX^3DX^/CY.;HZ^WO\?/V^OX"!@H, M#0T-#`L*"0@'!@0#`@$`__[]_?S\^_OZ^OGY^?KZ^?GX^/GY^?CW]O7V]O;V M]_CY^_W_`0,#`P'__?S[^_O[^OGX]_;T\O+R\O/T]O?Z_0$$!@@*"@L+"PH) M"0@)"@P.#Q`1$1$0$`\.#0T-#0X.#@\/$!$3%!87&!D9&1D9&1D9&1H;&QH8 M%Q86%Q<8&!@8&1L='A\@(B0G*BPN+R\P,C0V.#DZ.3@V-#,R,3$Q,"\M+"LJ M*RPN,#`P+RXL*RLK*RPL+"PL+"PN+S$R,C(Q,"\N+BXM+"HH)RW-K9U];5U=34U-34U-35UM?9VMOX.'CY>7E MY>3DY.;HZNSN[N[N[>[N[^_P\?+S]/3S\O'P\/#Q\O+S\_/T]/7U]?7V]_G[ M_@$$!@@*#`X0$1(3$A$/#@P*"`<&!00#`0#__O[]_/OX]/'MZ^KIZ>GJZNKJ MZNKKZ^SM[>SJZ.7CXN'AXN3EY>;EY>3DY.7GZNWO\?/U]_G[_?[^_OW\^??S M[^OGX^'>W-O:V-?5T]+1T-#1T='2T]35UM?8V-G9V=G9V=K:V]S=WM_AX^7G MZ.GHYN3AWMS;VMG8U];4U-/2T=#/SLS+RLG(R,G)R#?W]_@X.#@WMS;VMK;V]O; MV]K9V-?7U]C9V=K9V-;4T;HZ>KK[>_R\_/S\_/S\_+Q\.[M[.OKZ^KIZ.;CX=[=W-SWN[N_P\?+Q\?#O[^_N[>OIZ.;EY>7E MY.3CX^/DY>;IZ^[P\O3V]_G[_/W]_?W]_?W]_O[__P```/__```!`@,#!`0$ M!08'"`H,#0T-#`L*"0@'!@4$`P$`_OW\^_KY^/CX^?O\_?[^_OW]_/SZ^?;T M\_+R\_3V]_GZ^_S]_?[_``$"`@,#`P,$!`0#`0#^_/OY^/?W]_CY^_S_`00& M"`H+#`P,"PH*"0H*#`T0$A48&QTA)"'1T<'!P='1X? M("$B(R0D)24E)B@H*2DH*"8E(R(@'QT;&A@8%Q<6%A45%146%Q@8&1@8&1D; M'!X@(2(C)"8G*"HK+2XO,#$Q,"\M+"PK*RLL+"PK*RDI*"'R`?'Q\?(2,E)R_MZ^CFY./CX^3FZ.KM[N_N[NWL[.OK MZ>CGY^GJ[>_P\?'R\O/U]_CZ_/\``@,$!@@)"PT.#PX.#`L*"@H*"@D)"`<& M!00"`?____[^_?SZ^?CW]_CY^_W_`0,%!@<("@L,#0T-#0T-#0X/#Q`1$1(2 M%!47&!D8%Q43$`X,"PL*"@H*"PL+"PP,#`P+"@<%`O_]_/O\_/W]_O\``@4( M"PT/$1,4%187%Q@7%Q44$A`.#0P,#`P-#0X/$1,6&!H;'!T='1P;&1@7%Q87 M%Q<8&!D9&QP='R`@(2(B(R,C(R,A'QP9%A,0#@P+"@D(!P4#`@$```#___[] M_?W^_O[^_OW\^OCW]O7U]//R\.WJYN/@W][?X.'AXN+BX>'@X-[=W-O:V=C7 MUM32T,W+RX.'BXN/DYN?IZNSL[>WN[N_P\O/T]/3S M\?#O[^_N[>SKZ^KJZ>GGYN3BX-W;V=?5T]'.S,G'Q[N[NWM[.SL[.SM[N[O M[^[N[N[N[^_P\/#P\/#O[NWM[>WN[_#Q\O+S\_/T]?;X^OO\_?W]_?S[^OCV M]?3T]/3T\_'O[.GGY>3CY.7FY^CIZ>GIZ>GIZ>KK[>_R]??Y^OKZ^OKZ^?GX M]_;U]//Q\.[LZ^KIZ>GIZNKK[.SL[.SKZNGHZ.GIZNOK[.SKZ^SM[_+U^/O] M``($!08'!P<'!P8&!04$!`0%!04%!04%!`0$`P,#!`4&"`D)"@L,#0\1$Q05 M%A<7&!@8%Q86%A<:'2$D)B8F)B4E)28G*2HK*BDG)2,B(2`?'AT<&QH9&!85 M$Q$/#0L)!P4#`0#__P`!`P0%!@<'!P@)"PX0$Q47&1P>(2,D)24E)"0D)"4F M*"DK+"PL*RHJ*2DI*2@G)B0C(B`@("`@("`?'QX='!L:&!<5%!,2$1$1$1$1 M$A05%A86%A87&1L?(B4H*2HJ*BDI*2@H*"'1T< M&QL;'!T>'1P;&QH:&AH:&1@7%1,0#PT,#`P,#`T-#0X.#Q$2$Q46%QD;'B`C M)"8G*"DJ+"TO+R\N+BXO,#(T-#0T,S(Q,#`O+BPI*" M("(C(R(A'QX='1T<&QD7%!(0#P\/#P\.#@T-#0T-#0T.#@\/#PX-#`L)!P4# M`0#^_/KX]O3S\O'P[^[N[>WM[>SLZNGGY>/BX>'AXN/CX^/BXN+CY>;HZNOL M[>[N[_#R\_3S\_+Q\?+S]OCZ^_S]_?[_```!`0$!`0```````/____[^_?W\ M_/S\_@`"!`4&!P@("0H*"PH*"0@&!@8&!@8&!@8%!`,!__[]_?W]_/OY]_;T M]/3U]O?X^/GY^?GY^/CX^/?V]/'NZ^?CX-[W^'BX^3EY^CJZ^SM[>WL[.KIZ.?FYN;FYN7DX^/CX^/BXN+AX>+B MX^3EYNCIZNOKZ^OKZ^SN\/+T]O?X^/GZ_/W^_O___O[^_?W\_/OZ^?CW]_?X M^?K[^_S\_/O[^?CV]/+Q[^WKZ>?DX=_W^#@X.#AX>'BX^/CX^/C MXN#=VM;2S\O)QL/`OKR[N[JZN;>VM;6UMK>XNKR]OK_!PL/$QL?'Q\;$P\/# MQ,7'R,G+R\S,S,S+R\O+S,W.T-'1TM/5UM?8VMO+CY.3EY^GK[>_P\?+S]/7V]_CX^/?V]?/Q[^[L[.OJZ>CGYN7DX^/BXN+B MXN/EY^GK[>[O[_#Q\O+S\_/S\O'P[^[M[.SKZNGHYN7EY>7EY>;GZ.GJZ^WN M[_#Q\O/S\_/S]/3U]?7U]//R\?'Q\O+S\_/R\O+S]?CZ_?\``0(#!`4'"`D* M"0@&!0,"`0$!`/_^_?S[^OKZ^OKY^?GY^OO\_/W]_?[^_O[]_?S[^??V]?3T M]/7U]?7V]_?X^?GZ^?GY^?KZ^_O[^OGY^/CX^/GZ^OKZ^?GX^/CX^/GZ^_O[ M^_KZ^OGY^?GZ^OO\_O__`````0$"!`4&!@8&!@<'"`D*"PL*"`8%!`,#!`4& M!P@("`@("`@("0L+#`T-#@\1$Q06&!D:&QL;&QL;&QP<'1T='1P;&AD7%A44 M$Q,3$Q,3$A$0#PX,"PH)"`@("`D)"0D)"@H+"PP,#0X0$1(4%186%Q<7%Q86 M%A85%145%145%!04%!45%A85%!,2$1$1$1`0#PX-#`P,#0X.#Q`0$!$1$1$1 M$1$0$`\.#0L*"0@(!P<&!04%!@<("@P-#@\/#@T-#`P-#@\1$A,4%187&!@8 M%Q<6%104%!04%!04%!04%!04%!45%Q@9&1D8%Q43$A`/#Q`0$1$0#PX,"PH* M"PP-#Q`1$A(4%1<8&AP='1T>'R`B)"4F)B4D)"0D)"4F)R@H)R4C(2`?'Q\@ M("$A(2(C)"8H*BPM+S`P,3(S-#4V-C8U-#,R,3`P+RXN+2TL+"PM+2\P,3$R M,S,S,S,S,S,S,C(R,C(S,S,R,C$O+BPJ*"8E)"0D)",C(R,C)"4E)28F)B8F M)B8F)20C(2`?'QX>'AT<&QH8%A44%!04%!04%!03$Q,2$A(1$A(2$Q,3%!47 M&!H;&QL;&AD9&!<6%104%!45%145%!(0#@T-#0X/$!(3%!45%104%!,2$1`/ M#0P,"PL+"PL,#`P+"PH*"0D*"@L,#`P-#`P-#0T.#@\/#P\.#@T,"PH*"0D( M"`<&!@8'!P<(!P<&!04%!08&!@4$`P(!`````/____[^_O__``````#__OW[ M^_KZ^_S]_O_____]_/O[^_O\^_OZ^?GX^/CX]_;U]/3T]/3T]/3T]/3T]/3T M]/3S\_+Q\._N[>SKZNGHY^;FYN;FY^?GYN7EY>7EYN;FYN?HZ>OM[_'R\O/S M]/7W^/GZ^OGX]_;U\_+Q[^[M[.SKZNGHY^?GY^?GZ.CHZ>GJZ^SL[>[N[^_O M[NSKZNGIZ>GIZ.CGYN7DX^/BXN'AX>'AX>+BX^/DY./BX=[X.'BXN/CY.7FY^?GY^?FYN;FYN?HZ>GIZ.CGYN;F MYN;EY>3DXN'?WMW+BXN+BX>'AX>'AX>'AX.#@W]_?W]_@X.#@X>'B MX^7FY^CHZ>GIZ>GHZ.CGYN;FYN;FYN7EY.+AX-_>W]_@X>+CX^/BXN/CY.;G MZ.GJZNGIZ.;EY./BXN+AX>'@X>'BXN/CY.3DY>;GZ.GJZNKJZNKJZNKJZNGH MY^;EY./BX>#@W]_?W]_@X>+CX^/DY./CY.3FY^CIZ>CGY^;FY^CHZ>KJZ^OK MZ^SL[>WM[.SM[>[N[NWLZNGHY^?GY^?GYN;FYN;FY>7DY./DY.3EY>7EYN;F MY>7DX^+BXN+BXN/CX^3DY.3DY./CX^/DY.7EY>;EY>;GZ.KL[_'S]/7V]O;V M]_?W]_CX^/CW]O7T\O'P\/#P\/#O[NWLZ^OJZNKJZ>CFY>7FZ.KL[_+T]_G[ M_@`"`P0#`P(!```!`0$!`/_^_?W\_/W\_/S[^OKY^?GY^?CX^/CX^/CX^?GY M^OK[^_OZ^OKZ^OO\_?\``0(#!`4&!P@*#0\1$Q04%!05%145%145%186%A<7 M%A87&!D:&QP<'!P<'1\@(2$A(!\?'AX='1P;&A@6%!(1$`\/#P\/#P\/$!`1 M$1,4%1<9&QT?(2(C(R,C(B$@'QT;&A@7%Q85%102$1`.#0T-#0X/#Q`0$`\/ M#Q`0$!`0$1$1$1(2$Q,4%!46%A86%145%A87&!D:&AH:&QP<'1X>'R`A(2(B M(B(B(B(B(2$A(!\?'AT<&AD8%Q85%145%186%Q86%144$Q,4%!05%!03$Q,3 M%!05%145%145%A87&!@9&1H;'!T>'R`A("`?'AT<&QH:&AD9&!<7%A86%A87 M%Q@9&AL<'1T='1P:&1<6%!,3$A$0#P\.#@X.#P\/#Q`0$!`/#Q`0$!$2$Q,4 M%!,3$A(3$Q04%145%144%!03$A$1$!`0$!$3%!46%Q<7%Q@8&1H;&QL<'!T= M'AX>'A\@("$B(R,C(R,C(R0D)",C(B(A'QT;&185$Q(1$`X,"PH)"0H*"PT. M#Q`1$Q05%A<8&!@8%Q<7%A86%A86%A45%186%QD;'1X@(2(C(R,C(R,C(R,D M)"4E)B8F)24E)",C(B(A(2$A(B,C(R,C(B$@(!\>'1L:&1<5%!,2$A,4%A@: M'!T?(2,E)RDI*2CGYN;FY>7CXN#?W=W=W=[>W=S:V-;5U-34U-/3T]+2TM/3 MT]/3T]/3T]/2TM'1T=+2T]/3TM+2T='1T='1T='1T='1T='2T]/3T]+1T,_/ MS\_/S\_/S\_1TM37V-K;W-S>W^'BX^3DX^/BXN'@X-_=W-SSL[.SKZNGHY^?GY^?GYN7EY./CX^+BX>#?WM[=W-S#?WMW=W=[?X.'AXN+CX^3EYN;FYN;FYN7EYN;GY^CH MY^?FY>7EY>;GY^?GY^?GY^CHZ.CHY^?FYN7EY>7EYN;GY^?GY^?HZ.CIZ>GH MY^;EX^+@WMW;GZ.CHZ.CHY^?HZ.GJZ^SN M[_#Q\O/S\_/S\O+R\?'Q\?'R\O/T]?;W^?K\_@`!`P4&!P@("`@'!P<'!P@( M"`@("`@("0D)"0D(!P<&!04$!`0#`P(!`0````$!`0("`@,#`P("`@(#`P0% M!08%!04%!04%!04&!P<("0H+"PP,#`T.#Q$3%!87&!D:&AH:&1D9&!@8&!<7 M%Q<8&1H<'A\@(2$A(2$@(!\>'!L9%Q85%!,2$1`/#@X-#0T.#Q`2$Q05%A<7 M%Q<8&!@8&1D9&!@8&!<7%A44$Q(2$A$1$1`0$!`1$A,5%QD;'1\@(B,D)28G M*"DJ*RLK*BHI*"@I*2DJ*BDI*"@H*"DJ*BLK+"PM+C`R,S0U-C4U-#(Q+RXM M+"LJ*"'A\?("`?("`A(2(C(R(B(2$A(2(B(B$@ M'QX=&QL:&AH:&QP='AX?("`A(B,D)B'AT<'!L:&AD8&!<6%144%!05%!04$Q,3$Q,4%!45%144$Q(1$1$1$1(2 M$Q,3%!46%Q@8&!D9&1H;&QL;&AD8%Q86%104$Q$0$`\.#@T-#0T-#0T,#`P, M#`P,#`P+"@@'!@4$`P(!`/_^_?W^_O[___\```(#!0<)"PP-#@\0$!$1$1$1 M$!`/#@T,#`L*"0D("0D*"PP-#@\/$!`1$1(2$Q46%Q<7%A85%!,2$A(1$1`/ M#@T-#0X/$!`1$!`/#P\/#Q`0$!`0#PX.#0T,#`P,#0T-#@X.#@X.#@T,"PL* M"@H)"0@(!P8%!00$!`4&!P@("`@'!P8&!P<("`@("`<'!@4%!00$`P(!`/__ M_P```/____________[^_?S[^OKY^/?V]?3T]/3S\_+R\O'Q\?'Q\?+R\O+R M\_/S\_/T]/7V]_CX^?GX^/CW]O;U]//R\?#P[^[M[.SL[.SLZ^OKZNKIZ.CF MY>7DX^/CY.3DY>;FYN;FY>3CXN'AX>+BXN+BXN'AXN+CY.3EY>7EYN;GY^CH MZ.CGYN7EY>7EY>7DY.3CX^/CX^/CXN+BX>'@W][=W-SWM[?X.'B MX^/CX^+AX-[=W-O;V]S=WM[?X.'CY>?IZNSM[N[O[_#P\/#P\?'Q\?'Q\?#P M[^_O[N[M[>WL[.OKZNKIZ>GHZ.?GY^?HZ.GIZ>GIZ.?FY>/BX>'@X.#@X.#@ MX.#@W]_?W]_?W]_?W]_?W]_?W]_?X.#@X>'BXN+BXN'AX>'BX^/CX^/CXN+C MX^7FY^CIZ>GIZNKJZNKIZ.;EY.3CX^/DY./CX^/CX^3DY>;FY^CHZ>GJZ^SN M[_'S]/;X^OO\_?W]_?S\_/O[^OGX]_?V]?3S\O'P\/#P\/'Q\?#O[^[MZ^OJ MZ>?FY>3CXN+AX>'AX.#@X.#@X.#AX>'@X.#@W]_?W]_?W^#@X.#AX>+CX^/C MX^/CXN+BXN/CX^/CX^/CX^3DY>7EY>7FYN;FYN;FY>7EY>7FYN?GZ.?GY^;F MYN;GZ.GJZ^SL[>[O\/#Q\O+S]/3U]?7T]/3S\_+R\O+R\_3U]OCY^OO]_@`! M`P4&!P@("0D)"`@'!P<'!P<'!P<&!@8'!P<("`D*"@L,#`P,"PL+"PL+"@H) M"0D)"0H+"PP+"PL+"PP-#0X/$!`0$!`/#P\.#0T-#0T,#`L*"@H*"@H+"PH* M"@D)"`@("`@)"@L,#0X/#Q`0$1$1$1$1$1$1$1`/#0P,#`T.#Q$2$Q46&!D: M&QL<'!P<'1T='!P<&QL:&1D9&1D9&1D9&!@8%Q86%103$A$0$!`0#P\/#@X- M#0P,"PL+"PL*"@H)"0D("`@("`D)"@L+#`T-#@\/$!`1$1(2$A(2$1$1$!`0 M$!`0$!`0$!`1$1(3%187&!D9&1D9&1@8&!<7%Q<7%Q<7%Q<8&!D9&AL;'!P= M'1X?(2(C)"4E)B8F)24E)24E)28F)B'AX='1T<&QL;&QP<'1X>'R`@("$A(2(C)"0E)24D)",C(B`?'AT<&QL; M&QH:&AH:&AH9&!<6%104$Q,2$A$0#@T,"PH)"`<'!P<'!P<&!@8'"`@)"0H* M"PL+#`P,#0T-#@X.#@X.#@X/#Q`0$1$1$!`0$!`0$!`0$!`0$!`0$!`0$!$1 M$1`/#PX-#`P,#`T-#0T-#`L+"@H*"@L+#`P,#0T-#@X/#Q`1$A,3%!05%145 M%145%!03$Q,3%!04%!45%!03$Q$0#PT,"@D)"`<&!00"`0````````$!`0$! M`0$"`@,$!04&!P@)"0H+#`T/$!$2$Q,3%!04%!03$Q,2$1`/#@X-#0T-#`P, M#`P-#0T.#@\/#P\/#PX-#0P+"@D("`@("0D*"@H)"0@("`@(!P<'!@8%!04% M!04&!@8%!04%!`0$!`,#`P,#`@("`@$!`/_^_?W\_/OZ^?CW]O3S\_+R\?'P M\._O[^_P\/'R\O/S]/7V]_?X^/GY^?GY^?CW]_;V]?7U]?3T]//S\_3T]?7U M]?3U]?7U]?7U]?7T]//S\O+Q\?#O[N[M[N[N[N[O[^_P\/'R\_7V]_G[_/[^ M______[^_?W\^_OZ^??V]?7T\_/R\O'Q\/#P\/#P\/#P\/#O[^[M[>SLZ^OK MZNKIZ.?FYN7EY.3DX^/BXN+CX^3EYN?HZ>GJZNOL[>[O[^[N[>SKZ^KJZNKI MZ>CGY^;EY>3DX^'@W][=W=W=W=W=WM[>WMW=W=W=WM[?W]_>W=W'AX.#@W]_?X.#@X.#AX>+CY.7EYN;F MYN;EY>7EY>7DY./CXN'?W][>W=W=W=W+BXN/C MY.7FY^?HZ.GIZNOL[>[N[^_O\/#Q\?'Q\?'Q\?'R\O+Q\?#O[^[N[N[M[>SL M[.SL[.WM[N[O\/#Q\O/S\_3T]?7V]_?X^/CX^?GY^OK[^_O[^_O[_/S\_?W] M_?W\_/S\_/S\_?W\_/S[^_O[^_S\_?[^_P`!`@(#`P,#`P("`@$!`0("`@$! M`0```0$!`0#__OW\^_O[^_OZ^OKZ^OGY^OKZ^OKY^?GX^/?V]?7T]//S\O+R M\O+R\O/T]?;W^/CX^/CX]_;V]?/S\O'P\/#P\/'Q\?+R\_/T]/7U]?7T]//S M\_/S\_/S]/3T]?7V]O?X^/GY^OKY^?GY^?GZ^OK[^_S\_?[^_O_______O[^ M_O[^_?W]_?W]_?W]_?W^_@`!`@,$!`4%!`0$`P,"`0$```#______P````$! M`0("`@("`@("`@("`@("`P0%!@<("0H*"PP-#@\/$!`0$!`0$!`0$1(2$Q05 M%A87&1H;'1X@(2$B(B(B(2$A("`?'QX>'AX>'AX='1T='1T>'AX>'1T='1T= M'A\?("$A(2$A(2`@'Q\?'AX>'AT='!L;&AH:&AH;&QP<'1T='AX>'A\?'QX> M'1T<'!P<'!L;&AH9&!@8&!<7%Q<7%Q<6%A45%145%A86%Q<7%Q<7&!@8&!D9 M&1D9&!@8&!<6%A85%A<7&!@9&!@8&!<7%Q<7%Q86%A44$Q,2$1$0$!`0$!`/ M#Q`0$1(3$Q,4%!05%A87%Q<7%A44%!,3$A(2$A(2$A(3$Q04%186%Q<7%A85 M%145%144%!03$Q,3$Q(2$A$0#PX.#0T-#0T.#@\/$!`1$A,3%!45%145%186 M%A85%144%!,3$Q,3$Q,3$Q,3$Q,2$A$0#PX.#0P+"PH*"@H+"PL,#0T.#@\/ M#P\/#P\.#@T-#`P,#`L+"@H)"0D)"@H)"0D("`D)"@H*"PL+"PP,#0T.#Q`0 M$`\.#0P+"@D(!P8&!00#`P("`@$!```!`0$"`@("`@("`@("`@(!`0`````! M`0$!```````!`0("`@(#`P,#`P("`0#__OW\^_KY^?CW]_?V]O;U]?7V]O?W M^/GY^OK[_/S]_O__``$"`@(#`P,#`P,#`P("`@$!`0````#____^_O[]_?W\ M_/O[^_S\_?W]_O[^_O[__P``````__[]_/KZ^?CW]_;U]?3T]/7U]?;V]O;U M]?7T]//S\_+R\?#O[N[M[>SLZ^OKZ^OKZ^OKZ^OKZ^OJZ>GHZ.CHZ.GIZNOL M[>WN[N[M[>WM[N[O\/'R\_3V]_CY^OO\_/S\_/S\_/S\_/O[^OGY^/?V]?3S M\_+R\O/S]/3T]?7U]?7U]O;V]O;U]?3T\_/S\_/T]/7U]?7U]?7U]O?X^?GY M^?GX^/?V]O7T\_+Q\/#O[^_O[^[N[>WL[.OKZNKJZ>GHZ.?FYN7EY>7DY./C MXN+BX>'AX.#?WM[=W=W=W=W>WM_@X>'AXN+BXN+CX^3DY.3DY.3DX^/BXN+B MXN/DY>;GY^?GY^?GY^?HZ>GJZNKJZNKKZ^OL[.SLZ^OKZ^OKZ^OL[.SL[>WN M[N_P\/'R\O/S]/3U]?7U]?;V]O;V]O7U]?7U]?7T]/3T]//S\_/S\_3T\_/S M\O'P[^_N[>WM[>WM[>[N[N[N[N[N[N[O[^[N[N[N[^_P\/#P[^_O[^_P\/'R M\O+R\O+Q\?'Q\?'P\/#P\/'R\_3U]O?X^/GZ^_S]_?[_`````0``___^_?S[ M^_O[_/S]_O\```$"`@,#`P,#`P,#`P,"`@$!`/___________O[^_O[^_O[] M_?W\_/S\_/S\_?W]_?[^_O[_____````___^_OW\_/O[^OKZ^?GY^?KZ^_O] M_O\!`@,$!08&!@<&!@8%!`0#`P("`0#__OW\_/S[^_O[_/S]_?[^_O______ M``````#_____```!`@,$!`4%!@8&!P<'!P@("0D*"PP,#0X.#P\/$!`0$!`/ M#PX.#0P,"PL+"PL,#`T-#@X.#@X.#@\0$1(3%!46%A87%A85%103$Q(1$1`/ M#@P+"0<&!`,"`0````````$!`@("`P,#!`0$!`0$!`0%!08&!@<'!P<'!@8% M!04%!`0%!04&!@<("0D*"PL,#`P-#`P,"PH)"0@(!P<'!@8&!@8'"`D*"@L+ M"PL,#`T.#P\0$1$1$1$1$1$2$A,4%146%Q<7%Q86%144$Q,3$A(2$A(2$Q,4 M%146%A87%Q<8&!@8%Q<7%A44$Q(2$1$1$1(2$A(2$A(2$A(3$Q04%!45%145 M%145%145%144%!04%!,3$Q,3%!04%!04%!04%!,3$Q(2$A(2$A(3$Q,3$Q,4 M%146%Q@9&AL<'!T>'Q\@(2$A("`@'Q\>'AT<'!L:&1D8%Q85%!,2$1$0$`\/ M#@T,#`P,#`T-#@X/#P\0$!`0#P\.#0P+"@D)"`<'!P8&!@8&!@8&!P<'!P<' M!P8&!@8&!@8&!04$!`,#`P("`0$``/____\```$"`P0$!04%!04%!00$`P(! M`/__________```````!`0$"`@,$!`0$`P,#`P,#`P,#`P("`@("`@("`P,# M`P,#`P,$!`4%!04%!04%!`0$`P,"`@(#!`0%!@<("`@("0D*"PP,#0T.#@X. M#0T-#`P+"PH*"0D("`@("`<'!P<&!@8&!P<'!P<("`@("0D("`@'!@4$!`," M`@$`__[]_?[^__\``0$"`P0$!04%!04$`P,"`0$!````______[^_O[^_O[^ M_O[^_____P````$!`0$!`0``_________OW]_/OZ^?CV]?3R\?'P\/#P\/#P M\/'Q\?'R\O/T]/7V]O;V]O;U]?3S\O'P[^[N[>WM[.SL[.SKZ^OL[.SL[.WM M[>WM[>SL[.OKZNKIZ.CGY^?GY^?GY^;EY>3DY.7EYN;FY^?GZ.CHZ>GJZ^SL M[>[N[^_P\/'Q\?+R\O/S\_/S\_+R\?'P\._P\/#P\?'Q\?'Q\?+R\_3T]?7V M]O;V]O;W^/CY^?KZ^?GY^/CW]_;V]O7U]?7U]?7U]/3T\_/S\_+R\O+R\O/S M\_/S\_/T]//S\_/R\O'Q\._O[NWLZ^KJZ>CHY^?GZ.CHZ>GIZNKIZ>GHY^?F MY>7EY>7DY.3DY.7EYN;GY^CHZ>GJZNKJZNGIZ>CHZ.CHY^?GYN;FY>7DX^/B MXN+BXN+BXN+BXN+CX^3EY>;GZ.GJZ^SM[>[N[^_P\?'R\O+R\?'P[^[N[>WM M[>WL[.SKZ^KJZ>GIZ>CHZ.CHZ.CHY^?GY^?GY^?GZ.CHZ.GIZ>GJZNKJZNKJ MZ>GIZ>GJZNKKZ^SL[>[N[N_O[_#P\?'R\O/T]/7U]O;V]O?W]_CX^?GY^OKZ M^?GY^/CW]_?W^/CX^?GY^OK[^_O[_/S\_/S[^_O[^_O[^_S\_/S]_?[__P`` M`0$!`0$"`@(#`P,#`P0$!`4%!08&!@8&!P<'!@8%!00$!`0$!`0$!`4%!@<' M"`D)"0D*"@H*"@D)"0@(!P<'!P<'!@8&!@<'"`@)"0D*"@H)"0D)"0D("`<' M!@8%!00$!`0$!`0$!04%!04&!@8&!@8&!04%!@8&!P<'!P@("0H+#`P,#`P+ M"PL*"@H*"@H*"@H*"@H*"@H+"PL+"PL+"PL+"PL+"PL+"PL+"PL,#`T-#0X. M#@\/$!`0$1$1$A(3$Q,4%!05%145%145%186%A86%A87%Q<7%Q<7%Q<6%A45 M%!,3$Q(3$Q,3$Q,3$Q,3$Q,4%!04%145%145%!04%!03$Q(2$A$1$1$1$A(2 M$A(2$A(2$Q,3$Q,3$Q04%!45%145%145%145%!04$Q,2$A$1$!`0#Q`0$!`0 M$!`0$1$1$A(2$Q,3$Q04%!04%145%146%A87%Q<7&!@7%Q<7%Q<7%A86%145 M%186%Q<7&!@8&!@7%Q<7%A86%A85%145%104%!04%144%!,3$A$0#PX-#`P+ M"@D(!P8%!`0#`P("`@("`@("`@,#!`0$!`0$!`0#`P,#`P,#`P,#`P,$!`4% M!@<("0D*"@L+#`T-#@X.#@X.#@X-#0T-#0T-#0T-#0T-#0T-#@X.#P\/$!`1 M$1$2$A(3$A(2$1$1$1`0$1$1$1(2$A(2$A(2$1$1$!`0$!`0$`\/#P\/#P\/ M#P\/#@X-#0P,#`P,"PL+"@H)"0@(!P<&!@8&!@8&!P<'"`@)"0H+"PL+#`L+ M"PL*"@H*"0D("`<&!00#`0#__OW]_/O[^OGY^/CW]_?W]_?W]_?W]_?W]_?V M]O;W]_?W]_?W]_?W]_?V]O;V]?7U]?7T]/3T]/7U]?7U]?7U]?7U]?7T]/3S M\_+R\O+R\O+S\_/T]/7U]?;V]_CX^/CX^/?W]_;V]O7U]?3U]?7U]?7U]/3S M\_/S\_/S\_/S\_3T]/7U]?;V]_CX^?GZ^OKZ^OKY^?CX]_?W]_?W]_?X^/CY M^?GY^?GY^?GY^?GY^?CX^/CX^/CX^/CY^?KZ^OKZ^OKZ^OKZ^OGY^?GY^?CX M]_?V]O7U]?7U]?7T]/3T]/3T]?7U]?7U]?7U]?7U]?3T\_/R\O+Q\?'Q\?'Q M\?+R\O+R\O'Q\._O[N[M[>WM[.SL[.OKZ^OKZ^OL[.SL[.WM[>WM[>WM[.SL M[.OKZ^OKZNKIZ.?GYN;EY>7EY>7FYN;GY^?HZ.CHZ.CHZ.CHZ.?GY^?FYN7E MY.3DX^3DY>7FYN?GY^CHZ.GIZ>KJZNKJZNKJZ^OKZ^OKZ^OKZNKKZ^OK[.SM M[N_P\/'R\O/S\_/S\_/S\_/S\_/R\O+R\O+S\_/S]/3T]?7U]O;W]_CY^?KZ M^OKZ^?GX^/CW]_;V]O;V]O;U]?7T]/3T]/3T]//S\_/R\O+R\?'Q\/#P\/'Q M\?'Q\?'R\O+S\_3T]/3S\_/T]/3T]/3T]/7U]?;W]_CX^?K[^_S\_/W]_?W] M_?S\^_O[^OKZ^OKZ^OKZ^OKZ^OO[^_O[^_S\_/S[^_O[^_KZ^OGY^?CX^/CX M^/CX]_?W]_;V]_?W]_?W]_?W]_?W]_CX^/GY^?GY^/CX^/CX^/CX^/CX^/CY M^?GZ^OK[^_S]_?[__P```0$!`0$"`@(#`P,#`P,$!`0$!`,#`P0$!`4%!@8& M!P<'!P<'!@8%!04%!04%!04%!04%!@8&!@8%!00$!`,#`P,#`P,#`P0$!08' M"`@)"0H*"@L+"PL+"PL+"PL+"PH*"@D)"0D("`@("`@("`@'!P<'!P<'!P8& M!@8%!04%!08&!P<'!P@("`D)"@L+"PL+"PL+"PH*"@H*"0D)"0D)"0D)"0D) M"0D)"0D)"0D)"0D)"0H*"PL+"PP,#`P,#`P+"PH*"0D("`@(!P<'!P8'!P@( M"0D*"@L+"PP,#0T.#@\/$!`0$!`0#P\/#P\/#P\/#PX.#@\/#Q`0$!`0$!`0 M$1$1$1$1$1$0$!`/#P\/#@X.#@T-#`P,#`P,#0T.#@\0$1$2$Q04%145%145 M%145%146%A86%A86%A86%A86%Q<7%Q@8&1H:&AL;'!P='1T>'AX>'AX='1T< M'!P<'!P<'!P<'!L;&QL:&AH9&1@8%Q<7%A86%A45%145%145%146%A87%Q<8 M&!@8&!@8&!<7%Q<6%A44%!,2$A$1$!`0#P\/#Q`0$!`1$1`0$!`/#P\/#P\/ M#P\.#@X-#`P+"PL+"PH*"@H)"0@("`@(!P<'!P8&!@8%!04%!00$!`0$`P,# M`P,#`P,#`@("`0$!`````````0$!`0$!`0$!`0$```#______O[_______\` M``$!`@,#!`0$!`0$!`,"`@$``/___O[^_O[^_O[^_O[___\``````0$!`0$` M`/____[^_O[^_O[^_O[^_O[^____`````0$!`@("`@,#`P0$`P,#`@("`0`` M_____O[^_O[^_O[^________________``````````````#___[^_O[^_O[^ M_O[^_O[^_O[^_O____[^_OW]_/S\_/O[^OKY^?GX^/CW]_;V]O;V]O;U]?7U M]?7U]?3T]//S\O+Q\?'Q\?'Q\?'R\O'Q\?+R\O/S\_3T]//S\_/S\_/S\_/S M\_/S\_/S]/3T]/3T\_/S\_/S\_/S\O+R\O+R\?'Q\/#O[^_N[N[M[>WL[.SK MZ^OKZ^OKZ^OKZ^OKZNKJZNKJZNOKZ^OLZ^OKZNKJZNGIZ>KJZNKKZ^OL[.WM M[N[O[_#P\/'Q\?'Q\?'Q\/#P\/#P\/'Q\?'R\O+R\O+R\O+R\O+R\O+R\O+R M\O+R\O+R\O/S\_/T]/3T\_/S\_/S]/3U]?;V]_?X^/GZ^OKZ^OGY^?CX^/?W M]_?V]O7U]/3T]/3U]?7U]?;V]_?X^/CX^/CX]_?W]_;V]O7U]/3T]/3T]/3U M]?7V]_?X^?KZ^_S\_?W]_O[^_OW]_?W\_/O[^OKY^/CX^/CW]_?W]O;V]O;V M]O;V]O;U]?7U]?7U]?7T]/3S\_/R\O+R\O+R\?'Q\?'Q\?'Q\?'Q\?'Q\O+R M\O/S]/3U]?7U]?7U]?7U]?7U]/3S\_+R\O'Q\?#P\/#P\?'R\O/T]/7U]O;V M]_?W]_?W]_?V]O7U]?7U]?;V]O;V]_?W^/CX^/CX^/CX^/GY^?GY^?KZ^OO\ M_/W]_O[^_____P````$!`0$!`0$!`@("`P,#`P0$!`0$!`0$!`0$!`0$`P,# M`P,#`P,#`P0$!`0$!04%!04%!04%!04$!`0$!`,#`P,#`P("`@("`P,#`P0$ M!04%!@8&!P<'"`@("`@("`@("`@("`@("`<'!P<'!P8&!@8%!04%!04%!04% M!04%!04%!04%!`0$`P,"`@(!`0$!`0$!`0$"`P,$!`0$!04%!04%!04%!04$ M!`0#`P,#`P,$!`,#`P,#`P(#`P,#!`0$!04%!@8&!P<'!P8&!@8&!@8%!04% M!04%!04%!08&!@<'"`@)"0D*"@H+"PL+"PL+"PP,#`T-#0T.#@X.#@X.#P\/ M#@X.#P\/#P\0$!`0$1$1$A(2$A(2$Q(2$A$1$1`0$`\/#P\.#@X.#@X.#P\/ M#P\/#Q`0$!$1$1$1$1$1$!`0$!`/#P\/#@X.#@T-#0T-#`P,#`P,#0T-#0T- M#0T-#0X.#@X.#@X-#0T-#0P,#`P,#`L+"PL+"PL,#`P,#0T-#@X.#@X.#@T- M#0P,"PL*"@H)"0D)"`@("`@("`D)"0D*"@H*"PL,#`P-#0T-#0P,#`P,"PL+ M"PL+"@H*"@H*"0D)"0D)"0D)"`@("`@'!P8&!04%!04$!`0$!`0$!`0$!`0$ M!`0$!`0$!`4%!04%!@8'!P<'"`@(!P<'!@8&!@4%!04%!04$!`0$!`0$!`4% M!04%!@8&!@8&!@8%!04%!`0$`P,#`@(!`0$!`````0$!`0("`@,#!`0%!04& M!@8%!04%!04%!04%!04%!04%!@8%!04%!@8&!@8&!@<'!P<("`@("`@("`@( M"`@'!P<'!P8&!@8&!@8&!@4%!04%!04%!04%!04%!`0$`P,"`0$``/___O[^ M_?W]_/S\_/S\_/S[^_O[^_O[^_O[_/S\_/O[^OKZ^?GY^?GX^/?W]O;U]?7T M]//S\_+R\O+R\O+S\_/S]/3U]?;V]O;V]O;V]O;V]_?W]_CX^/GY^?GY^?GY M^/CX^/CX^/CX^/CX^/CX^/CY^?GY^?GY^?GY^?CX]_?V]O;V]O;V]_?W]_CX M^/CY^?GY^?GY^?KZ^OO[_/S]_?W]_?[^_OW]_?S[^_KY^/CX]_?W]O;V]O;W M]_?X^/CX^/CX^/CX^/?W]O;U]?3T]/3S\_/S\_3T]/7U]?;V]O?W]_?W]_?V M]O;V]O7U]?3T]/3T]/3T]/3T]/3T]//S\_/S\O+R\O+R\_/S\_/T]/3T]/7U M]?7U]O;V]O;V]O;V]O;V]O;U]?7U]/3T]/3T\_/S]/3T]/3T]//S\_/R\O'Q M\/#P\/#P\/#P\/#P\/'Q\O+R\_/S]/3T]/3T]//S\_/S\_/S\_/S\_/S]/3T M]/3T]/3S\_/S\_+R\O+R\_/S\_/S\_/S\_3T]/3U]?7U]?7U]?;V]O;V]O;W M]_?W]_CX^/CX^?GY^OKZ^_O[_/S\_/S]_?W]_?W]_?W]_/S[^_KZ^OGY^?GY M^?GY^OKZ^OKZ^OKY^?GY^/CW]_;V]O;V]O;V]_?W^/CX^?GZ^OO[_/S\_?W] M_O[^_O[^_?W]_?W]_?S\_/S\^_O[^_O[^OKZ^OKZ^OKZ^OKZ^OK[^_O[^_O[ M_/S\_/S[^_OZ^OKY^?GY^/CX^?GY^OK[^_S\_/W]_O[___\```````````$! M`0$"`@("`@("`@("`@$!`0$!`@("`P,#!`0$!`0%!04&!@8&!@8'!P<'!P<' M!P<'!P<'!P<'!P8&!@8&!@8&!@8&!@8&!P<'!P<'!P<'!P<'!P<("`@("`D) M"0D)"@H*"PL+"PL+"@H*"@D)"0D("`@("`@("`D)"0@("`@("`@("`@("0D) M"0D*"@H*"@H*"0D)"0@("`@'!P<'!P<("`@("`D)"0D)"@H*"@H*"@H)"0@( M!P<&!@8%!@8&!@8&!P<'!P<'!P<'!P<'"`@("`@(!P<'!P<'!P<("`@("`@( M"`@)"0D*"0D)"`@(!P<'!@8&!@8&!@8&!@8%!04%!04%!`0$!`0$!`,#`P,# M!`0$!04%!@8'!P@("`@("`@("`@("`@'!P<'!P<&!@8&!@8&!@<'!P<'!P@( M"`@("`D)"0D)"0D)"0H*"@L+"PP,#0T-#0X.#@X.#@X-#0T,#`P,#`P,#`P, M#0T-#0T.#@X.#P\/$!`0$!`0$!`0#P\/#P\/#P\/#PX.#@X.#0T-#0T-#0T, M#`P,#`P,#`P,#`P+"PL*"@H)"0D)"0D)"0D)"0D)"0D)"0D)"0D("`@(!P<' M!@8&!@4%!04%!04%!00$!`0$!`0$!`0$!`0$!`0#`P,#`@("`@$!`0$!`0(" M`@("`P,#!`0$!`0$!`0#`P("`@$!`0$!````````````````````________ M___^_O[^_O[^_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/W]_?W^_O[^_O______ M___________^_O[^_O[^_?W]_?W]_?W]_?W]_?[^_O[^_O[_______[^_O[^ M_O[^_O[^_O[^_O___P```````0$!`@("`@,#`P,#`P,#`P,#`P,#`P,#`P(" M`@(!`0$!`````````````/_____^_O[^_?W]_?W]_?S\_/O[^_KZ^OGY^OKZ M^OKZ^OK[^_OZ^OKZ^?GY^?CX^/CX]_?W]_;V]O;U]?7U]?7U]?7U]?7U]?7U M]?7U]?7U]?7U]?7U]?7T]/3T]/3T\_/S\_/S]/3T]/3T]/3T]/3T]/3T]/7U M]?7V]O;V]O;V]O;V]O7U]?3T]//S\_/S\_3T]/7U]O;V]_?W]_?W]_;V]O;V M]O;V]O7U]O;V]O;V]O;W]_?W]_?W^/CX^/CX]_?W]_?W]_;V]O;V]O;U]?3T M]/3S\_/S\_/R\O+R\O+R\_/S\_/S\_/T]/3T]/3T\_/S\_/S\_/S\_3T]?7U M]O;V]_?W]_?X^/CX^/CX^/CY^?GY^?GY^?CX^/CX^/CW]_?W]_?W]_?W]_?W M]_CX^/CX^/CX^/GY^?GY^?GY^/CX^/?W]_;V]O;V]_?W]_CX^/CY^?GY^OGY M^?GX^/CX]_?W]_?V]O;V]_?W]_?W]_CX^/CX^/CX^/CX^/CY^?KZ^_O\_/S] M_?W]_?W]_?W]_?S\_/S\_/W]_?W]_?[^_O____________\`````________ M_________O[^_O[______P````$!`@(#`P,#`P,#!`0$!`0$!`0#`P,"`@(" M`@("`@("`@("`@("`P,#`P,#`P,#`P0$!`0$!`0$!`0$!`0$`P0$!`0$!`4% M!04%!04%!04&!@8&!P<'!P8&!@8%!04%!04%!`0$!`0$!`0$!`0$!`0$!`0$ M!`0$!`0$`P,#`P,#`P,#`P,#!`0$!`0$!`0$!`0%!04&!P<("`@)"0D*"@H* M"@H*"@H*"@D)"0@("`@("`@("`@("`@("`@("`@(!P<'!@8&!@4%!00$!`0$ M`P,#`P,#`P,#`P,#`P0$!`0$!`0$!04%!04%!04%!`0$!`0$!`0#`P,#`P,# M`P,#`P0$!`0$!`0%!04%!04%!04%!`0$!`0$`P,#`P,#!`0$!`0%!04&!@8& M!P<'!P@("`@'!P<'!P<'!P8&!@8&!@8&!P<'!P@("`@("`@("`@(!P<'!P<' M!P<'"`@("`D)"0D)"0D)"0D)"0D)"0D)"`@(!P<'!P<&!@8&!@4%!04%!04% M!04%!04&!@8&!P<'"`@("0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0H*"@D) M"0D("`@("`<'!P<&!@8&!@<'!P<("`@("`@'!P<'!P<'!P8&!@8&!@8&!@8' M!P<'!P<'!P@("`<'!P<'!P8&!@8&!@8&!04%!00$!`0$!`0$!`0$!`0$!`0$ M!`0$!`0$`P,#`@("`@(!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0```````/__________`````````````0$!`0$!`0$!`0$!`0$" M`@("`@("`@("`@("`@$!`0$``````/__________```````````````````` M```````````````````!`0$!`0``````_____O[^_?W]_?W]_?S\_/S\_/S\ M_/S\_/S\_/S\_/S\_/O[^_O[^_KZ^OKZ^OGY^?GY^?GY^?KZ^OKZ^OKZ^?KZ M^OKZ^OGY^?GY^/CX^/CX]_?W]_?W^/CX^/CX^/CX^/CX^/CX^/CX^/?W]_?W M]_?W]_?W]_?X^/CX^/GY^?GY^?GY^?GX^/CW]_?W]O;V]O7U]?7U]O;V]O?W M]_?W]_CX^/CY^?GY^?GY^OKZ^OKZ^?GY^?GY^?GY^/CX^/CY^?GY^?GY^?GY M^OKZ^OKZ^OO[^_O[^_O[^_O[^OKZ^OKZ^?GY^?CX^/CX^/CX^/CX^/CY^?GY M^?GY^?GY^?GY^?CX^/CX^/CX]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W M]_?W]_?W]_?X^/CX^/CX^/CX^/GY^?GZ^OK[^_O[_/S\_/O[^_O[^_O[^_O[ M^_KZ^OKZ^OKZ^OKZ^OK[^_O[^OKZ^OKZ^_O[^_O[^_O\_/S\_/S\_/S\_/S\ M_/S\_/O\_/S\_/S\^_O\_/S\_/S\^_O[^_OZ^OKZ^OKY^?GY^?GZ^OKZ^OKZ M^OO[^_O[_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/W]_?W]_?W]_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_OW]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O[_ M__________________[^_O[^_?W]_?S\_/S[^_O[^_OZ^OKZ^OKZ^_O[^_O[ M^_O[^_S\_/S\_/S\_?W]_?[^_O[^_O[^_O_______O[^_O[^_O[^_O______ M`````````0$!`0$!`0$!`0("`@("`@("`@("`@("`@("`@("`@("`@("`P,# M`P,$!`0$!`0%!04%!04%!@8&!@8%!04%!04%!04%!04%!04&!@8&!@8&!@4% M!04%!08&!@8&!@8'!P<'!P@("`@("`@("`D)"0D)"0D*"@H*"@H*"@H*"@L+ M"@H*"@H*"@H*"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D("`@("`@' M!P<'!P8&!@8'!P<'!P@("`@("0D)"0D)"0D)"0D)"0D("`@'!P<'!P8&!@8& M!@4%!04%!04&!@8&!@8&!P<'!P<'!P<'!P<'!@8&!@8%!04%!`0$!`0$!`0$ M!`0$!`0$!`0$!`0#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,# M`P,$!`0$!`0$!`4%!04%!04%!@8&!@8&!@<'!P<'!P<'!P<'!P<'!P@("`@( M"`@("`@("`@("`@("`@("`@("`@("`@'!P@("`@("`@("`@("`@("`@("`@( M"`@("`@("`@("`@("`@("`<'!P<'!P<'!P8&!@8&!@8%!04%!04%!00$!`0$ M!`0#`P,#`P("`@("`0$!`0$``````````/__________________________ M_____________O[^_O[^_O[]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W^_O[]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?S\_/S\_/S[ M^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^OKZ^OKZ^OGY^?GY M^?GY^?GZ^OKZ^OK[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/S\ M_/S\_/O[^_O[^_O\_/S\_/S\_/W]_?W]_?W]_?W]_?S\_/S\_/S\_/S\_/S\ M_/S[^_O[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/O[^_O[^_KZ M^OKZ^OKY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^/CX^/CX^/CX^/CX M^/GY^?GY^?GY^?GY^?CX^/CX^/CX^/CX^/CX^/CY^?GY^?GY^?GY^?KZ^OKZ M^OKZ^OKZ^OKY^?GY^?GX^/CX^/CX^/CX^/CX^/CY^?GY^OKZ^_O[^_O[^_O[ M^_O[^_O[^_O[^_O[^_O[_/S\_/S\_/S\_/S\^_O[^_O[^_O\_/S\_/S\_/S\ M_/S\_/S]_?W\_/S\_/S\_/S\_/S\_/S\_/S\_/W]_?W]_?W]_?W]_?W]_?[^ M_O[^_O[^_O______________`````````0$!`0$!`0$!`0$!`0$!`0$````` M`````````/____________________________[^_O[^_O[^_O[^_O[^_?W] M_?W]_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W] M_?[^_O[^_O[^_O[^_O[^_O[^_O[^_O[______________P```````0$!`0$! M`0$!`0$"`@("`@("`0$!`0$!`0$!`0$!`````0$!`0$!`0$!`0("`@("`@(" M`@("`@("`0$!`0$!`0$"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(" M`@("`@$!`0$!`0$!`0$!`0$!`0$!`0("`@("`@(#`P,#`P0$!`0$!`0$!`0$ M!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0%!04% M!04%!04%!04%!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$ M!`0#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,# M`P,#`P,#`P,#`P,#`@("`@("`@("`@("`@,#`P,#`P,#`P,#`P,#`P,#`P,# M`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P("`@("`@("`@("`0$!`0$! M`0$!`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@,# M`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`@("`@("`@("`@("`@("`@("`@(" M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(#`P,#`P,#`P,#`P,#`P," M`@("`@("`@("`@("`0$"`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$```````````````````#_________________ M_____P```````````/__________________________________________ M``````````#______________________________________P#_________ M_________O[^_O[^_O[]_?W]_?W]_?W]_?W]_?W]_?S\_/S\_/S\_/S\_/S\ M_/S\_/S\^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\ M_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_?W]_?W\_/S\_/S\_/S\_/S\_/S\_/S\_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W] M_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\^_O[^_O[^_O[^_O[^_O[^_O[ M^_O[^_O[_/S\_/S\_/S\_/S\_?W\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O______________________________________```````````````` M```````````````````````````````````````````````````````````` M`````````````````````0$!`0$!`0$!`0$!`0$!`0`````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`@("`@("`@("`@("`@("`@("`@(" M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(" M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`0$!`0$!`0$!`@(" M`@("`@("`@("`@("`@("`@("`@("`@$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$````````````````````````````````````````` M``````````````````````````````````````$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`````````````0$!``````````````````````$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0`````````````` M````````````````````````````````````````____________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M______________________________________________[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____`````/__________________________```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``!#3TU-````$@`!``"2```(0`VL1````````$U!4DL````"``!)3E-4```` M%#P``'\`?P``````````````````05!03````:A39#)A``(```````````#K M`.P!+@$O?_\`HP#L`2Y__W__`````````````````&>0,```G(@`.`!B`#@` MU@!+`&(`2P#6`$\`YP!/`/<`O@#G`+X`]P##`1X`PP%@`,0!'0#$`1X`Q`%@ M`,0!80#%`1P`Q0$=`,4!80#%`6(`TP$<`-,!'0#3`6$`TP%B`-0!'0#4`1X` MU`%@`-0!80#5`1X`U0%@```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````$"```````"0`C```````` M`````````'@````$``0``````-'^`/___X`````!`2`&455N:71S```3""YP M9W-Z```)'E!!5",```DJ3%=25P```````0)&!B!S86UP3[_P``(F`21')U;2!/9B!%87)T M:'%U86ME(`(```!!249&4V0R80``04E&1E-D,F$!`/____\````````````` M``````````"G/9LK``"4#````>BDX[7XIIM-4@``````+`#B`1`".P$``+0! M*0&`__C_[````````(`````````````````````````````-`````2$'4V-R M:7!T3[_P``````M@!*`7(!W@$``)``Q@$`__C_ MXP```````(```````````````@``````&@`I``\!JP)@`"H``P)M`ST`O0#! M`8("40$`````&@`I``\!4`'Q`"H``P)M`ST`````X#;__P``````&@`L`!8! M/@'<`"H``P)M`ST#,P)M_,$";0``````&@`````````````````````````` M`&`````````!`````7X```!^````:@!QVJ04D@```!P`:@`!5W-T80`#`!)3 M1$]#````0@`!__\````&```````"__\````D```````#__\```!"```````$ M__\```!@``````/H__\````````````````````````````````````````` !`/\` ` end nethack-3.6.0/sys/share/sounds/firehorn.uu0000664000076400007660000004370212467321052017567 0ustar paxedpaxedbegin 644 Fire_Horn M``E&:7)E($AO[R]/+T]P0*^_O__@#X]/X0'QX3`^WL]^SD[OH" M`/3LY^7JY.P/("OQ[>CH[_#P`Q,1"``%!_[]].ST_P'Z\>[N[_8` M_PT:`?;^]?C_]OP.(2\H%PH2("`J,BLT,!DA,!X+"`<1(1\#X=74V.?S_0@& M_N[0N[B]S=[O`Q06_>3G\@@?)SA$/28,_O'Q`0\<+S,D$?7:U.?MZO\3$@3R MXS<6X ML;G4`!D7#@#\`@H>-DI985D_'0\0#`P5*3HY,1CV[_'GX>[T^`'YY]+`OKB] MX/L$_N73S\K0W^WY!1`4#P/NW=KI^OX!`.;-R\S/V.'BY_;HR;FSLK"[W/+Z M^>GG[.3D\0`'#!($\NOCZO@%&BHH'A,-!?OV]?8!&B(/]>;>W-W6U^SX[-O3 MU=K@Z?<1*B\;`_?U``T*#R`H(Q+][N3CY^O_%!L9!N[AY_7V_Q8?'QT2!@#^ M`0PA+R\@`_/]"A0<+$%!.S,<#@?^_`D?+"PI%O;EYN_["Q,(^_#CW-S?Y?L> M+B\U)@L"`@0'$RKK\?<$$0_^ MXM'0UN?^$AXD(1D-`?;U`1$N3$XX&?KEX_D0'2D@"?GCRL#*VN\/)1X-^N;< MWNCT_@@*`_OOX-'*T^X+'!X3_]_'Q,G7[P0-$0W[[.[MWN0!#PX/`^OJ^0(0 M'B@Q.#8@!_GP[/H7)B8E&@;Z]?3R[>[T`0;OX.3CW.7]"R`\*04#`OCW]^_J M\.W9SM+-RN(#"@+WX=_T^N_H[?'S"!0!\O/T\?/_!?[SX]KG^?W\`@4'!?GS M_00$"!HL,"@7#10I,QX,$A43&B`>%@W_^0XG*1T0"Q`=*28>*C0E%@KXZ^/5 MS=SN[>+:UMKP`OOZ"@X'!PH-$`P.&"U`-R4?%PL(#A`6*"\C&Q8%\>#,Q=KJ MX]KCZ>+O`OK]#`P*$QL2_>[=U.D'(CHW&?OV_?KX_@`""PKZ[N?;U-KBY>CK MY.+R]^OI[_/]#0GNX^WV]_+R^`()_>[S_/P"#!(:(!<)_O;O[_7X]O+JV-T,W)!,(!0T?,3(D$O_V\^KL^P<2'2(<"_KM MZP`G.S`B&`?^``8,&2\Z/#TQ%OKHY?`&'B,7`O/IXM_A\`03&18/`_7KZ?@5 M*3(S)10(`0@8'R$I-#SW_0H-`//GXN3H\@$,$0X"[N7D[`89&A@1 M"`(#"!$D+B8C)!\8$@L%#!89$@'NW=?@[OL&#`?[\^;3S\_.V>OW\^+5UM[A MY>[_$Q,$]=S&R]74W.[X^^_5Q,'(V^SS^P$#__;OYN#:W_X9&0+IUL_H_/?[ M`P+X[O/VZ^3AX_'Y[]?$P\;,T]C?Z>WFW=G=Y>KP\_7WZM#&U.L#%!<0#`C\ M\_'NY^GX`/WWZ-3*TN#L^0'Z[.+AY_,#!@@3'!H.`/7MZ_`$'BHE'1P<'",L M)RDW,A\+^.;@ZO+W#2(:"0/__0,,$!4F,B8/_>OB\?T&&B8:`?7PZ.;H\0H@ M)"`9$/[EV.,`(B8/!0T-_P$.&C9(-RPN)QT+\_,-)"DI+S@X*!X>)34X*2`C M)B(6#17M`1HE%?ST^_?R_P@1'1<'^OS]]OD"#AD0[<.OKK;+X?'Z_??FVL_#T>P! M%A\?&/O8LJ;']1$7#P7_^-[&T_0-%!43^,^VL;W9_A<>(B09!?/T!QXY2$8[ M*`7>V@4O.3@W)Q("Z]O;Z`(?,SP['_'2T.L+&1PA*RD.[^X%'#%"2DM(+P#> MX?L7+3@T*!D(^/@$"!0L+AD!X<:[P]OO_08&!/;?VN?Z"QLP03H@"/KY$#!) M54X[&/3K^0X;%@X2&0C@O**IOLS@[.WHT+JRN]3D[0$8'`GVY,K$U.H'(281 M\NKW!`T0$!DE'P3JV<_+TND!#@T`]?'W^_3Q\@$0#@@&"Q,1#B)-8$(3]/8. M%PX%_P8+`>_H]OGJZ^[JZN_OZ?+]_/X#_.OM^.WM_?GM]0L."Q@.!",[.3$G M'A81"OOU^?OS\??LV=7D`A03#P@!_?G]`@<1("HD'!\@(B4?'RDV.BX:`.SQ M_?;O^P@![-O+O,/;]`0&`_3>U=/=\/O]_/+ODXM7$ MR^4"&Q7^\>KEW^+^'"$6"_KKZ>CDX_(/'QT8"?3O\O@&#PL(!_CGX.'HY^CT M`0?[XLG"UNX&'"$;"_'8R,3+U.3Y%2\R&P8'%2(N,R@<&A,#]O7X]?L,%QP- MZM7:[?7T`Q44"P$"$Q;]V/R!A4&Z>L$ M&A8(&#([+AD8'AL1_?4+)3`H&!TT.S`B&!L:__,"#PW_\O4&$`P$^?H&"Q(< M(RH@"@D9'!$$^?<##PH"`0,&!`$#"Q4._OK]_??JZ/8!!/OU\.'B[_H,%!,+ M^_'MXM''S>'X!PT%[-G>[_OX\/#FV]O/Q='=X>+=YOCNU,G(U>S\`0,#^NWN M]O7O[_7\"A#^Y]G6Y/+T]0(-!0+_ZNX)$1$;)B@@&1<>)B??W-KD_08'#0?\]?3NW^#V#A82#@D- M$0\6&A4)^O3HW^;EZ?@(#O[IX-?7V^H*'1@*!`0$#1,2'2XS*2$8"/?GX_$* M&`#DW=GGD[.WG]/GM]?CEV^'?V^X!]N7BYN/F^`0'!0`!"`P+"`/Z!!TC&`/LY-[7 MW^;@Y.O@U-7,P\S0R=#G[^7>WM;0W.39VN\`$1L7$@X)"QTM)QL:$/_[_OGQ M]P82&A\6`/7NY_0%!/___?GY]_H"^_P-%1@9$P#GY@(5#@XC)Q\>#O?^$QHD M.#XS)!$""!X@#`@6'QT2^-O;?Y_,,)BL@'R(?)"XH'!TC%@,#`O+M_`8+%!<'\O(! M"Q0<$P+X[-_C[-W)T>?Y"A<0__X&"APN)`X!]NGJY]#/ZOT#_??Y]O'W_PL; M&@/MXN/]%/_DZ_C[^?;S]?TF)Q8,"A$;$_SS_@X1#0D,#@<4,3(?$0+N MZ?D&!?SU^000%Q`-"`85(AX8&0??U>/FY.'K\\=W*N;J^L:_.[?H+$O[O[=S`Q^X'_^;9 MX.WZ].H`)"TA#O7Q_O/7U_L9#.[I[.OJV'-W@LG%?7JY^3A MX.+P!A(:'1``^.WI_A<6_//^`?;Q]/4#%QTJ0#\A!O7P`A<;"OX.&0T1(R@G M*2XU,"$-_?S\^__TW>#Y!P@.%0'Q_PH9+2,.#0[]\@@6!O\+$!8G+1X?+#$\ M.B47%A4)!104^_+\]_4'!_#J_PP1'!H*_.W;T]OEW-;D[?+\`O\&&B`6$`;P MVOJUM+G\^KCW,_1Z/7_%R(-\N+=]1@4^_H/$P#U]_T/)C0Q+"X;_/3S M`!D9!_\'#`3X[>7E^`T-$1X4^_'Y`@3_^/D($1$-"0D'$"HP%O?DVM'/U=KG MZ>;IV]7H[]_<^A(2$P_\\O+Q]?\&_O7\].;N^OD#'"@J*!/X[?+W^/CTY^?U M[=G=V\7(X^SN!AH&[N??W^#8U>'[#!,7%14;("(O1$(I&A$&`O7@Y/X4(RDA M#O;BW-_L"1T6#Q01`-_)S=CB[?H$_>34U>#V"@X'%"$0]MW#M\7?\PL>%/GB MW./C]A$+$"$5^^7=Y>_X"!XW/2D0!`D;*"$5$PS^]NO@Y.WZ#!@8#@<$^_?X M`A,.^>_T_OSV]_X-%A$1'"DN+2/7UMK:\@P%]OCX\_GZ^0((#@O_!/G? MW./L`Q+^ZP`+``85'24V.A\4'A0`^?3S"B`1`Q(;%Q,2$!,6"@86$/'!-G-U-++T^\+ M(RD7#A,6$`,%'#=#,Q/WZ=S"MJM3Z"Q8? M*C(>_N[W$2,H(AD0\'T!081)2(+\-/$TNOP\!4W*A86"P`(`OX;(_S;TL_<]`$!"B@O%!0M+RC6R]/CZO\9%AG8TN'W!@D!`B(^+A\B(!4`X-#P M$0;U]P0(^.[S_`\@'QPG)PCHT];Z"0('"Q,:$@7_"!PF*RP>#0#PW=WU^N_O M]P4&_/C]_P`'#Q@H*!/][N?BZ?\*"Q,2!P8+!P87*BL=%`X#\]K.S/>W.SZ_/+EXM_1NJRSP=+FZ>S^!_?K]`,:,"8."Q((\NSZ!P@"]>CI[>;> MW_$,"OT!`O74N+2]SMG4W>KNZMO<]`XC*27R`1LV M-"<@&`OZ^0L9'2,G*B<@&1,3&2$P/#8@#0'Y_@L3$@L)"?WOZN[Z!@4)%0W[ M`0H&!P\0$187#P@&`@03'RTZ-R84#PX,#`8#"`+NWM_HZ^WT`!0>$//@XM_7 MWNKX!@3Z_`@0"_T!%2(C&PP)$0P!`@@.$@?LX.GJW=OG\@`&]NW_"_?E[O?T M\?'P^Q,;$0\1&20?%A,>(1`.'1T3!_?U`@D&!PT0"P$$!O;^&!86)B(1`?3R M]OL'%!\:`//U[N\"$`X8)P[MZN+:Z/3X^_OOW-38V];A_0@)!>_AYM_7Y/L* M$0P`_0,(`?D/*R@@%//:ULBYS_7\]N[6Q\G/R\?6YN;@TL;-U=;>`!P7#PL' M$!$&`0TN2$(G%`K^\.#D!!P2]^3@W=?8W>X/$^[4S,&^OL'WR`0H0#PP+`??[^/<4,283$PL+&1@A+RCR`Q,;&!,1#@T-"0H0 M`/,##?GL[_8""`0+%@KY^_WNY.GLW=7K^.GL^O\.%@P0&1()`P()$AD9#`P> M'`3]!Q@H(Q4>*A7\^OT!`._>U=;F\.?A[@#^]@4;&PC]_@01"OC\_?D%`N_M M]O3GY_T2%0S\\P$$W\G8X^?N[.?N_O_N[0HF)A(!!`KNQ\+*TN'HXN/NZM?) MT.O[].KI[^O/M+?(T=OG\OW]\>GA[!,G&Q,7&A+YY_'Z\?8%#141`O+G]`\8 M%1<3!?3K9W.?K`1LA(B(/_OGOZ_L"_0PE)`OW^@(%$2(J.4$C M$!,#]?O\`2`R'0/\`@8#%CQ485(D#0P"_PCG MYN7CY.GN^/;K_A48(B`/%1@(!0G_\.KKZ^_W^O3V"`G\`@<``0$%#?O@U]K= MX^GK[O/[#1H8("`,"0@#"@7Y]_3T]O/V!Q<<'Q\8'1\5%1(4$O3F\?3U^?+R M`0;\!!HF-#DE%`X']^7CX^'?UL_;[N;;[0`(&R4>(B47`.3:U\_7Z/0!_.7@ M]Q(>*2XH)!7YX,_0U,_/T]WNZM/-VN7H[/;U[.GHWL_.S\G,W.ORZ^'E\@08 M)S4],!8'^^GL_``$"0+QX=K?[/H$"`S^V\;/VMOCY-G:X-S;V-/?]A`F.D'EYNS["1\R+2XI$/[S\/H(#/?;T]SK\_@)'#5'04=$(PX.#Q`9 M$_';V-WH\?G^!10._P8&]?#S\?/^\-+&P\[E]``+#Q47'C4X*2(@(2(<"_;I MXN?U_@8/"P'S\@(#^_T"`P,'!/#CVN'X`@@%]_P$#"`D&!04#0+]]>OJ\@DD M,2\8!0P-#Q\9#!(4`NKHZN+CY>T%$@KW[OL(J(B4@`^_QZMG6V-WT"`#N MZO7W`B$J(2(6^^?9R,+/UN8$"OOT]@`'%RPQ+R8/^.[JVK]^>'.RLO( MUO#_`?CLY=O-O+[8ZO<*"??M[?<#%"\W*R$6"O_RY^3M^0(-#__NYN/@Z/S_ M^/7O[.?@U,O4XNX!`^[DY>CU#1X:#PG__/SJV-_K[?\<(143$A0A)RLN*2,< M%0T`]>_J\`$:(0X(#ADL,#`T*1X?(!\.^.WJ\`0:&@T-$1,8$QDF&0<'"@?Z MY]7.X/\=)QX=)BPK*38^+!4/%1D0]=?2Y/@+#_[W^O'G[/?_]NOR^_?CR+W% MT.4&%A8=&@8$%B@H%@H0&Q<`ZM[F]P,3'QP4_NKN_`D+`O\-&PSNV];;Y_83 M)2$7`N_U#1\B&!0:%@;NX_,`!!,I+"`9">_T"!$4"P+_].32P\K?Z_H:*AH- M`_+^'C$[.B@9"O7?S=#D]`<<%/WZ[=KL"A8C)`KRY]S'N<+8\0\@%@L4$@82 M)R\V+0OR[>38V>+N_`'\\>?@T<35]0@0`N37U,:ZO\_D^P/W[O<'"`,3+3,H M%/WV_/GL\0@9(A@"^?KTY>+W#Q(']-S/T,S&UN_OZ>OEW^7O\OL:)Q4)_N?? MWMC?\@8,"`7U\0$,#A@L+A@1">[FY-_G^PL,$10*"A$4'S9-33TT*!,'`/L" M"P@%#A$&`@8-%2$M*AL:&@?Z\NOKZNOP``D%#!4:*CI&13,I(A4/"P8#!0@* M$`L!!P@&!/\)$0#U\^?;U]#"P='>Z>OI^@L*"A`A*1H)_/@``/CV_`8)"P;^ M!PT"^?T*"?[[]_CYZMO8W^GN\.OP!PP"`Q$C*B0:$0P$_/H`!P4&!P`&%Q$# M!A]P@(#1PE)1\6$@GV[/#^%"7F^Q&147'2`>$P/_"A@6!_SU_0H!_`<'^>GBYNGCTKZ]U>OKY./L M!!<3#Q88$`3Z`Q,2`O/R!1D;!_?V_@'TZ_8"!@+]!`X$Z]O:Y//W\._S]_KY M_@@-$A`3)BL5__CY``D0#@P.#`D$_P(*#@P'!P+PW-+8Z?D$!PD)"`T-"A,; M(RDD'!0,`/?^"Q8B(QP1"0?_^/X)&R06`_WWY]G@[O<"!__[!`H#_@<3(RTE M&!(-_?']#1`,`??Y^O+CVN+L\?'DUMC4Q'J]?OX]@42$`;]^OKU M\_D,'AT._??\^_SZ]0`'^O'R[>'8T=_[`_/?U-3:WNCU^@$$^O/U]_3O[P,9 M'!4)_OK]`@X6$!`2"`0'!OKN\?P'#0D!^?/V_@\A'148&AH8%A,.#A(7&1P@ M&`T'"!H@!_D!`?GX^/7V]_;[!0H+!_OV`A(2`/L#`@0-$AHA%P<'%1P?'0\' M"@T`[.KP[.7CZ//WY=GA[??^`/O[!PO_\_H`]^_S^P,)`OCZ!1$9'!4*`/GS M[O7_\^3H[>WLY./O_`0#`/CIX^7HZ_X4$04("`$`_OK]"QD@*B<.^?3R]@PA M%/_]^.OGYN+K`1$9(!D#]O?X^Q(N*Q@0"08,"0<-%B,R.#`="?SS\@4@&O[Q MY^#DZ.WZ#Q\@(!@(_O/O^!$K(0+W]?;]_OT)&!H4$Q$'^>36W/H2`M_/S,S/ MS];L_?[W^/OV[N+9Z@D6`N?AXN;M[/()&!0+#A`*`?'J]@H3`.+3T=/5U.+] M`OCR[^WIX-33Z`0-_NGBXM_D\/T0&QD0"PX,`OCX!1(;$_OP[NOM[_8*&AD1 M$1(/#`@(#ATN)@\)"P@'!081'2,A&AH9$`8$"0X/`_'L[_'T\O0%%1<1$142 M#/_X_P8,!O3P``H&_O\*#@\.#0\1"?GX`?[X[=[?[O3JXN;N^`'__08(]^_] M"07\\>7K``;\^`$*"Q`6%181_O4%$P?WZM?7Y^SI[?3Z_@,+"P?^\?0/)R(2 M!_GQ]OK]`@,$#!<=&0W]]0`8*",5"?;I[//[`?S[!Q,:%`/S[_\7)209"_KL MZ?+_"08%#1D?&@W]]`$8)R48`^;/S=GL^_T!"Q`/"O[PZ_4*&QX7!>S?X^_[ M!@@$"`T,!OONY^W["`L"[]2]NLO[Q\_#KZ.S["`?]\^7:W^_\!@D' M`@('!@0&!PL4%PS\[]S'R-[R_O_X[^OLZN?M^`$+#P3U[^73U_('$`\%_?K] M^?#Y#!8?(1("__3>W?$`"0D!_/CU[NCY#A8<(!@+"`+S]0H7%A`/$`\+!@86 M*"LD'A('`O;H\0(%!0<'#0X'`@(+&!,*"P3[_P,!!1`0!P'^``+^_0$(#Q$, M`_CO\/7W^?WU[.GHZO#S]?L#!@/_]^GAZ_L$"@P(__;S\O/W_``)$A41`^S= MX._X^O__]NSGZ?+_!P8*$1(/!O/F[?T#!@L*"`/_`@<-$Q$5'2`B'@[_!1$. M"0T,`O?Q\_H#"`(!!@8&!?OW`Q,3#PX(`/SY^P,0%A(4%@X*"OWR_0H$_@#\ M]._IZO8&#P\)`/7R\^WJ_`X0#@T%_?GR[?0`!`+^]>_MZ^;E\O_Y\?#NZ^;; MV.GZ_O[Y[>3@V=7=\?_\]/+U^?7O\/H#!@8$``#]\_/_#`\%]_#R]/#L[_?^ M`@'\].SDW^H!$!0*_/;X^OC[!0P-#`H)!?[V\@(<*286`OCX\_/_!PL0$A$1 M#0'S\0(8)"8;"@/_^?L&#Q,4%1<8$P/V]P06)241_?;R]/\.%!`0#PP-!_OR M]`$/&AP/`?KS\P$+"`0#^_K^^?#M]`(,%!<*^?'J[/T,$`X'_?K[]>_M\/D% M#0P$^/'O\?\*!@,"^_?W\N_R\_G___[YZ=_>Y?H$__OW\>[MZ^_U]?C^_/[^ M]/+X!!$4#0<%`_\```,)"0T4$`T*`/T!"!,6"@0%_//X`0P6%0\+`?S\^/D" M#!88#PD'`?T``@0(!@,%_O/O[O'X!!`2#`P.`_;W_``("PH,!_SX]_H`!`@% M_?\"^?3U\>_T]/3Z^/#P]OO]_@0#_/T!_/GX\N_S]/7Y[^;N]_\$!`<%^_L# M!`<-"00%`O[ZZ^/M^@8-"P@#]>[Q]OO^^OD!!0'][^3M^P_T^@0.#`D(`?P"#!(0#`P0 M#P;]]._Z`@80$`P(_/8`#1(2"@,$`??S\O'Z`00(`_GRZ.OZ!@X.!@(%_^WH MZ^WX!0H,"P7Z[_#[!PX/"@4!^NWM\_8!"@L-"?[RZO#]"1$3#0H)_>KBX-SF M]/K]^_7OZNWX`@8$`?[Y\>SO\_0!#0L%_?/N[_0`"PT*!@#^_/?Y_?T$#PX& M_?H``P0.&R`<%0P&`/K\`0$'#@7UZN?N]?P(%AL4#`/^__[]__X'$`7W\/+^ M"`L4'A\8#@4#`?T!!P8+#P+QY>/L]?P&#Q`(__GV]O?\`?X!!?GKYN;P_P@- M#PL#_?K[_/G_"@D*#0#PZNGP_`((#Q$+`P`!_OT#!OWZ_.[AY.CQ`@T.#0L' M`P$```$#!/_^_O+IZ>CM_`$!`P,!``$#!`4("00"`OGQ\_SL\_K]_/T#!0(`_?X!^O+U^OO[]_#N\/7Z^P$* M#`L*!P<'_O7U]O?U[^GJ[_+V^?P"!04%`@#^]O+U^?O\^_?V]OC\_?\%!P8' M!P8"_/?W]O7V]/'Q\?+X_?X``@4)"PH(`P`"`0```?_]^_X%"0@*#`P.#@L& M`/[^_?O[^_K[_@('"@D)"`8&!P@'!`$"`?\``?_]_P,)#@\/$`\.#`@#_OGV M]/+R]/7T]/;[_OW_`0$#!0,"__S[^_K[_?W[^/?[`00%!@<+#0H%`/KX]_;V M^?W]_/K\``$"!0<*"P@&`OOV]/+S]_OZ]_7X_/\"!`<+#`H(`_SW]?/S]?CZ M^OO^`0$#"`T1$1`0#PL%`O\``@4'!@8*#`L-$!`1$0\.#`7^^O?V]_G\_?O] M`0(#!08&!@4&!P+]^OCX^/K]__\#!P<'"@H)!P,#`_WT\._N\//U]//U^?S] M_P$#!`'___WY]_7R\O?\^_G[_P(%"`H-#@P)!?_X\_+R\_?[^_GY^_T``P0& M!@0#`P'\^?CX^?S^_OX!`P,"!@H.#@P*!P/]^/7T]?CZ^?G[_@`#"`L-#Q`. M"@8"``#^^_S_`0$#!@<("PP+"PD&`__Z]_?V]OCZ^?C]`@0$!PD)"0<$`@#\ M^OO[^?K[^/;[`@4&!PD)"`7^^_GU\_/S\_7V\_#T^_W^`00("P@"__WZ^/CY M^?O^^OC]`P8&!PH-#PP&`?WX]?/R\O;Z^?G^`P4#`P4("@@%!`/_^_KY^/?W M]_G^`P,!`0,%!`(!``#]^/7T\O#R\O3[!`<'!PD+#`L)"`D)"`<%`P$!```% M#1`0#@T,"04#`0$"`0$!_OOZ^/K_!@H+"PH)"`4`_?W^_O[^_/W__?P!"`P- M#`L*!P+\^/?X^/CX^/?V]//V_/\!`@($`P'^^OGY]_;W^/G[^_O_!0@("`D+ M"@8`_/KX]/#P\?/U]??]`0("`0(#!`,!`/[[^/?V]?;Y^_X#!P8$!`0#`@#_ M_O[]^/7S\_3V^?T#"0L*"`D+"@@("0D(!@+^^_O^`0,%"0L+"@D(!P4%!`,# M`?_]_/S^_P(%"`D'!04'!0#\_/[]_/KY^/G\_/T"!P@&`P,$`_[Y]_;V]?/Q M\/+V]_;X_?___?X"`P'__?S[^??W^/G\_P$#!00"`0,'!@'^_/GV\N_P\_;Z M_?[_`0'^_@`$!@0#`@#]^?7T]/;Z_O\``@(``/\``0```/[Z]O3S\_7Z_P,% M!@4%!`0$!@4%!@8$!`,"`@,%"`D*#`L*"0D*"@D(!P,!__SZ^OS_`P8%`P,$ M!`,$!`,#`__]_?W\_?X!!`8&!@8'!P8$`P$`__OX]O7U^/G[_P$!`/___P$# M!`0$`__[^OGY^OP``P4%`P("`0``__\`__SY]_3R\_7X_0`````!``#__O[_ M`/[\^OGX]_?X^_W^_P$"`@+__?S]_?S[^OGX]_?X^_X``00%!04%!`,!```` M``$!`0("`P,"`@0&!P@'!@,!`/_^_?S[^_W^_P$!``$"`P,"`@#^_?W[^OK\ M_@`!`@,"__[^___^_?W[^_OZ^/;V]_G[_0``_O[___[\_?_^_O[^_?S\_/[_ M`00$`@$"`P(`_O[]_/S\^_KY^?K[_/___O\!`@'____^_OW]_O[__P$"`@,# M`P0%!@8$`P,"__[^_O[]_?\``0("`0($!04#`P,#`@("`@(#!`<)"0H)!P8% M!`,#`@,#`@$!`?_]_/W_``(#`@,%!00!__________[^_OX``0,#!`4&!0,` M_?S]_/O\_?[^_?S\_/S[^_X!`P,!_OS[^OGY^OS^_O\``0$`_O\!`0$!```! M__W\^OK\_/W_`/_]_/W^___^_O\`__W]_/O[^_W_`0(````!`?_]_@`!`?_^ M_/OZ^OS_`0("````__[\_/W_`0(#`@$````!`@0%!04$`P#^_?W^_P$"`0#_ M_O\```$!`0(#`P'^_/S\_?W]_O___O[_______\``0#^_/O\_?W\_/S\_/X` M``#__OW]_OW\_/S\_?[^_____P`#`P,"`0$"`0#^_?W_`````/_]_/W_```` M_OW^_OS[^_S^`0("`@(!_P`"`P0%!@8&!0+__?W_`0("`P(`_OX``0(#!`0$ M!`'__?W_`@0%!@<'!00#`P,$!`0&!@,!__[^``,$!`0$`P("`@,#`P,#`P'_ M_?S\_?[_``$!```````!```"`@#^_?S\_?[^_O[__OW]_O[^_?S\^_GX]_?X M^OS^_O[^_O[^_O[^_O[^_?OZ^?GY^OS^_O[]_?W]_O[^_O[^_OOZ^OO]_O\` M`/__``````$!`0$``/[]_/S^``$!`0#_``$"`@0%!00#`?[]_?[_`@0%!00" M`0(#`P,#`P,"`?_]_?X``0(#`P,"`0$"`@,#`P0#`?[\^_O\_?\`````__\` M``#__P#__OW\^_O[_/W^_O________[^_O____W\_/O[_/W_``$#`P0$`P(` M````___^_O[^_?W]_?W_``$!`0#__O____[^_O[^_P`````!`@,#`P(!`0`` M`/_^_O\``0$`__\``0("`P,#`@$!`/___O[^``("`0$!`0("`0$!`0$!`/_^ M_?W^_P```0$````````````!`0#^_?W]_O\````!`0(#`P,"`@$!`0$!```` M``$``/___P`!`````/____[^_O[^_O[^_O[^_P`!`0#___[^_OW]_?[^__[^ M_O[]_O\``0$``/_^_O[^_O[_`/_____^_P`!`0$!`@$`________````___^ M_?X``````0$`__[^_?W^__\``0$``````````0("`0$`___^_P`!`@,"`0`` M``#_``$!`@(!`/_^_O[_``$!`0$!`0#___\```$!`/_^_?S\_?W]_O[__OW] M_?W]_?W^_P#_______[^_P`"`@$!`0$`__[^_P````````#__O[^_P```0`` M`/______``````#___\`_P`!`0$!``````````$!`0$`______\``0$!`0#_ M_O[__P`!`@(!``#__P````$!`0$``/____\```$!`0```/\```````#_____ M__\````````!`0$!`0$````````!`0$```#__O[______P``_________P#_ M_____O[_``````#___[^__\```````#__O[^_P``````___^____``$!```` M____``$!`0$!``````````$!`0$!`/___P`````!`````/___P`````````` M````````_____P````````$!```````!````_____________________P`` M_____O[^_O[^_O[____^_OW]_O[^___^_O[^_O[__O[______O[^_O__``#_ M________````````_____O___P``__\````````````````````!`0`````` M```````````````````!``````````$!`0$!````____````````_____P`` M````````````````````____`````````````````0$!````____`````/__ M________``````#_____````____________________________________ M________________````_________P```````/____\`````________```` M````______\`````_________P``````_____P```````/___P`````````` M`````````````/__`````````````````````/______________________ M______________\`__________\```````#_____________________```` M``#__________P``````````````````____________```````````````` M`````/____\`````````````````````````____````````````````_P`` M````````````````````````____________```````````````````````` M```````````````````````````````````````````````````````````` M````````````````````0T]-30```!(``0``+Q8`"$`-K$0```````!-05)+ M`````@``24Y35````!0\``!_`'\``````````````````$%04$P```&H4V0R M80`"```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````(````````````````````````` M````````````````````````````````````````````````````````!`@` M``````D`(P````````````````!X````!``$````````_`#___^``````0$` M!E%5;FET````'@```!6__3_\O_P_^[_ M[/_H_^?_Y__N__@`!P`8`"@`-0`_`$4)1FER92!(;W)N`@```$%)1D939#)A M````````````````04E&1E-D,F$```````````````````````````````"G M/:W$```Q(@```<[_G_^L_\P``@!&`(P`R`#R`0D!#P$)`/P`Y0#'`*<`A@!E M`$0`)``$_^;_S?^[_Z[_J?^H_ZO_K_^R_[3_LO^P_ZS_J/^G_Z3_I/^C_Z3_ MI?^I_[/_Q/_=__\`)0!.`'``BP"=`*0`I`"<`)``?P!J`%8`0P`Q`"``#P`! M__3_Z/_=````&@`I``\":@,Q`"H``P)M`ST`*0`/`D$#(@$`````&@`I``\! M4`'Q`"H``P)M`ST`````````````````&@`L`!8!/@'<`"H``P)M`ST````` M````````````&@`````````````````````````````````````!`````7@` M``!X````5@!QN+P8G1_?'IX:50_+!\8$@P&`?OY^?GZ`AM$9G5Q84DW-4%/4T]&-R8G0EM7 M0R\9_NG:TM':\A@_6&!:3C\Q+30Y-S(R-C@U+B89"?3>S,/,ZQ0S.BL2]][+ MR]KJ\OG___CLY.#>W=_BX=W7UM_V%"PR(@L"#BA"6&5A5E!)/#$L*RLI)R(9 M#@H:.E=B7D\[)104(R\O)QP._?L2+S8##@?UX='(S=[N\_'LX]7'RMG@ MU,:XK*FOOMS^$Q<.^^36WO8.'",@%P\*!@+^]^S=R[>FGJO1_ALG(Q#\Z-3* MS][O_0D)_>W@V]K;WN'CX-S?[@$.%QX<$`+^$"@P*R08"?[V[>3:T,S+RL?` MOLKB^`(!]^[HX^+FZ>39SL*UK;+'W./CW M#0']``@4'R`5!/?^'#E%13PM'Q0*`O[Y\>KGZ.WT_@<*!?SPXM;7ZP<9&P[W MW[GVL[(U?PI/SPK$_WP[O<% M#@\'^NO=U][K\_#FV,F^O]#P"1`)_.W>T=+J"!85$0H`^?+JX]O4SLO+SM3C M]P$"__GQZ^3>V-'(OK2KI:*GON/\__7AQZZCK3?X_(`!0+]]N[E MW]W;U]+.QKNQM-'^(C4V*1L6$Q`."P+VZ>/DY^GM]/CPW\JXL\7E``P,!?SU M^Q,D'0KYY]G3TM?=X-_;U,O(U.K]!@/UY^'F[_?\_?CMX-OH##1,444I#?T" M'#E&0C,B%Q(3&R$?&1`*!P0!_O;IV]/-P[S&Y000"_[MXN'I\?/R\O+T^@$$ M`/OZ_/[]_`8<+2\A"_/EY_<8-T`V)1#][-K+Q\O.SLS(QM;[(3?X]N[?SL&VJZJT MQ,[/Q[_&X/P)"/_SZN;GZ.;?ULW%P,#.Z_[^]>C4P\/9^Q$6#P+T[_4`!PT1 M#P?]\NC>V-?;W-3'NK;+\A$<%P?W[^SL[O#P\/'OZ>#:U-#2VN+H\@<>)!D% M[MG.SN($&QX9#/_[_?X!!@@%`P$"#!PH*2,6!_OOX]O8U]71S,C#Q-'E\?7P MYM[A\`<:)B@E(B`?)2LK)B`9$0P*!P'X\>[M[/00/%YI954\)AH9)3(X-"PG M)B8E(Q\5!?+?SL7)WO4!_>[:R<+-Z0$%`?7CU=#1U]WDZ_/V]/7_#!`-`_+A MV=SE[O;W].[K[?D1)RH="O+>UMWR#R4O,"TI)B4D(AX;&!,)__;P[O'Y__WU M\`(G0DE$,QP-!P<-%AL:$PL`\N+4S,K-T=?:W.?]$!0+_.OBZ`(<)!\7#`#Z M]_C[^_;LXM?,Q]+J_0+[[=O)O;O#S=/5T[BU,K*WP4C*R42^^KCX^CL[.KL\O?X]>_IY^KMZN7B M[007&Q0%\^3F_AWBUM#=^@\2!>[6R,C3 MY?D*$Q83#04`_P#\].C:R\//ZP41#?SFVN4%(2PK(`SXZN3EZ>WR]O7OY^'G M]?[^^//S]?;T[N7SDWM?.R=#@Z^O@SKR[TO(! M_O3BTLS,T=CWP M]OT`__SZ^OKW]?@'(#E&1#[W#B@X.3(J M)R'R"1XG(!@1#`X5&AP<&1,-!@'\]N[GY.+? MVM'%O<39ZNWEW>3Z"Q`1#/[OXMG6V-C4T-'4U<_#MK?*X>SLZ.'7O]O/G MU\_;\?KW\>77S\W-SM7H`10;%PT#_/CX^_\!__OY^?K\_OWW\.WW!@T2'!\7 M$`P)#A?E[@(@.TI,0C0F'QXC M)R0;$`@%"`P,!OSOX=?:ZOT0)S@W+!X,_/7V_@@/#PD`^/+MZNCGY>+>V=+- MT^7\"P\-$B,Q,"H@$`,``@<.$0\*!@(`_?CQ[?#[`P/^]_'P]@`(#`G^[^GQ M``<)"0/Z]?+O[O']%3)(4T]!,28B)S1!1D,Y+2(6"O_X\NWO`ADE+3H],RD? M%Q05%QL?(!T8$PP#_/3JX-3'O[NYN\;<[_'FV-';Y^CDX-7+QL3%RU=#4Y@4A+BL?$`3^_@`! M_O?Q[.GFX-K6TLS'RMCI]04;)2$8"OSV^/T%#A49&QT=&1$*!/_Z\^KAW-_P M#BDV-C(X04$Z-BXD'!80#0L)"`D(!/[W[^;BZP$5'!8'].3/H\PLL1U)-0#4P+S(W.C8M)!L2"0#Y]O?W^@86&Q48(B0?&A(* M!00%!P<%__CS[./8T,O*S,[/SLW/VNGR\.GDZ_H#"0\0#P\,!P#Z]/'R]/C\ M____"2`[35%)."@A(RPR,2DA)CM-344Y)Q0(`?[_`PXE.D`Y+!T4$!$2$0X' M_OGV\NODW][>X>X('!T9'B`<&14."PD)"@H(!PH-#0D#_/;NYMK+O*ZFK<7D M^/OY_08&`?_\]>SBULW)R,K0UMC6T&!,,!P8) M$!@=&@\!\N3:V-O?X-W8T,6\O,WH_@<($2(K)R$;$`;_]O#N[N_R]?C]`0#X M[NKV"A<9$@;^_@(("P@`]O<)&QT6#P3Y\_#N[>ST"!\L*R(4!O__"!0=(2(> M%0K^]>[GX-WA[OH"#A\F*"LF&Q0/"PH*"@D*"PX0$`T&_O7O[>SJZ_/^!04" M!QLP.#@T)1#^[N7DZ?#W_?[]^_;Q[O,$'2XT+R06"?SQZN;BX.C_&24C&@GW M[_#S]OD`$28W/T$_/CPW,BLD'10,!P8'"@T."P8$#!<=(RDG'A<.!P,"`@0' M!P#W[>/:TL[*QL3`N[.MK;C,VMW9VND`"PH'_O#EWMG:WN/I[?'R\>SAUM/A M^@T4$PT'!`(`_OGPZNT!&2`9#P+PX=?0S]7F`QXK*A\2"`+__P,'!@'Y[^/5 MR,'#Q\G+U.'M^PT6%!$-!?_\^OGY]_7U]_CW]._KZ>CGY>/BZ?H1(2(7"`<9 M+#$P*AT3#@P,#0T,"0/[[^/8T]GM!AD@'!$%_P`'#A$-!@(-)CL],R82__/M MZ_4+*T1-23PO)R4H+"TJ)!X;&QL9%`O^\.+8V>L)*3Y!-B@9"@$``0("_O?N MZ.7DY>3BW]G4T,S*T.#S_O_VZ>/O!Q@=&@KUZ>7G[_C]`04("`/_``TF/TM( M.245#0T3&1T=%A`4)SL^,!\+]NGFZ/('(C(S*R`5#PX0$1`,"`0"`0$#!04` M]>;7TM[]'C(X+QX,^_#O]P(-%!84$`L$_/'IX][9T\_/V>X""0?_\^[Y#184 M#`#PX]S9V-?3S<:_N[BXP-7O_P#X[-_6T=#1T<_*QL7/Z`<8%PX`[-S3T=WV M$R8L*!T1!O_]`@D/$0X)!/[Y]_?X]_/NZ.L!'S0\."H:#0/]_/X$"@T,"@D( M!P+[\NG@VM?8Y/L1&A,![.#I!R8T-2P8!/7IY>KP]/;V]._I[``=-$%#/#,L M*2HK*B8?&`\(#!XK)1<*]^+8V>7^&"@J)B`:%A(/#`@#_OGV]?C]`0,"_?/G MW-SS&#,].2H6!OGS^``#`O_[]O/R\_/Q[>?@V=37Y/H/&14']>GK_A@F)AP( M\^GI\/?[_O[\^?;V`!0H,2XC%PT)"Q,=(B`7"O[T]08>+#$P(P_]\_<-)C0U M,"VMC7 MU,['P+R_S^G[_O7EU/@WMO9UM'+Q\SD M#"HS+B`)]>KK^`D5&!<5$@X*!O[SZ.+?W=WG_14E*"`2!?GT`R$V."X>!O'F MYNSU^_SW\>KDZOX5(B,<$PT+#`X/#0D%`/OT[?`!%!H7#O[MZ/(%&28G(1XA M)S$\0D([,B@=$@D$!0P3%A0)_?H,*SPY+R(0_O/S^@($`?KQZ.#8T]#.S?%@G\\.7@Z@`/#@;\[-O1S,S. MT,[&O+>_U_$``??JX-S7?[087&Q8)^O'T_PT2 M#P;\]._Q^0,("`+WZ=G/SMS['3`P*!H(^/+S^/X"`P#[]O#HXM_AY>;G[P(9 M)209"__X]_C^#B8U,2<>%`L'!08'!?_W]0`8,T1%.RPA&QD;("0E)"$<%@T` M\>SV!0H'`?C[#!H>&Q,)`0`(3$0T*"`8#_O?PZ^?BW-KA\`0=,SDM'0SX MZ./DZ>WQ]?C\_P$!`/WX\>GDZ/@.'1\6"?SS[^[P^@P:&Q4-__/MZNCGZ>GG MZ?0%%B(E(AP6$Q08&Q@1"PH,$!(0#Q8F,"H>$PT5*3D^.S0N+3(Y/T`\-2XG M(!D3#PT+"07_]>SI[O8"$AD3"O_QY^/?W=[?W=C4T,S+S='4T]'4X_<"`OKO MX-+(P\+$S^?Z_/7MXMC4T]38W-W=Y?D.%Q(%].;?X>OW`08'!@'Z\^OAV-?F M^?_]^?D$$!,/!_WT[_'W^?CX^?S]^_CU\_'O[.;>U]7KN`1XT M/3HM'A(*!P<)"0<$`/OT[N?AX.T'&AX:%QPE)AP/`??T^@@7("`9$0L%__OX M]_GY]O'JY>GY#2$V0SXO(1,%_OS]``,#__GV]//S\N[GX-WC\?\%`_KOY^7I M\OC^#2$K*"(6!/;P[_'V^OP%%B@P+R<<%18=)R\P*R0>'!H7$@H`_`05'QX= M'R4N,2PB%Q`-$1D@(A\9$0@`]_#JYN3FZ.GGY^_\`00-&1H5#PD!^O'HXN'D MZ.SP\>SEW-70T^+\$!<4"?OPZ.7DX^#+Y`__\``4(!@'[^?P!"Q4:&182#0D'!@4#`/SW M\NSFY_4&#Q8A*2@A&A`(!0']^//LY-[=X./EY^CGYNWZ!@L(`?CR[NWN[>KM M_A0=&1$$\^CBX>3H[?@.*T!(1#(RC@ MX^_V]OD"!P3_^O+JY-[:V=C6TM'3U=/.Q[ZXN\O@[O#GV<_,TMO@X=[B\@0( M!?[QY=[;VMO?]$Q\?&1$,"PX3%Q81#`<%`P#[].SDY?+[]O#W!`P."@/\ M^/CZ_P0$__?MY-_>WM[>WM[;UM#/VNOV_0D<*2<=%`H&!P<)#A06%!$0$1(1 M#0;^_0H;(B$9#P8`_?W[\^KI]P8)!?_TZ.'=W=[>X.K^$R(D'1(*"`T6'!P7 M$0H%`?WZ^/;Z"2`L*B@M,C8U,2LE(1\?(2$=%Q(/#0L)!?[W\.OFX=O=Z?;[ M_0@:(R,?%0?]].SFY.+>VMC8V=O=W=S=Y_@($1$*__;P\/3X_`(3*30S*AP- M!`#]_?W]`1`I04U.1CPS+BLI)R4C(B$?'AL3!_KT_@T0#1`7&QP7#@7^_/T` M!0@&`?OU\.SIY^3BWM?-P[N\R][L]@83$0;[\./>W^/M]OS____]^O;OYMO: MZ``0$@H`^OG\_P'^]_/Z!PL(`_?IX-O7U-/5WO(,'R,;#0'[_`(("@D'!@4" M_/3KX][D]PH,!PH2&1L7$0H&!@@-$A05%102#PL$_//KYN'%0T*"Q`6'!X< M%Q`)`_[Z]>_HXMW9U]OI_0P8)C`M)1\9%!(0#@T+"`4"__SY]O'JX=S@\`,- M#@@`^/7S\_#KZ/$"#`T*`/+FWMG:W>'J_1WHX][:UM?B[?7_#A@8%!`) M!@8%`?_^_/KW\^_KZ.3AX.;W#AXA&Q$(`@$#!00#"QLF)B`6!_GNYN#>WN#K M!"`Q-2XB%@\+"P\1$0X*!0#Z\NC'BX>+M`!0?(AP2"P@)#0X*`OOV]?3S\N[IZO8# M!@$!"QTI*2(;%Q<<)"TT,BPB%PP#^_7P[NWMZN;G\@<6&ATC(QH2"?_V]/3U M]_?U\>WIYN/?VM;2TMWQ`@@!].CDYNOO\?+Z"Q<6$0?XZN3CY.?IZ_4+)#8Z M,B07#@P2&AX?'QT8$@L$^_#J\@0."0,'$Q\D(1D2#0T/$1(1#PP)!P<&!/_V M[.+9T]#3X/(`"!$<(!T9%A`,!P(``/_Y\_#R]OCV\>KE[0`2&1@1"/_Y^/GX M\NSP``T+!/ONY-[;V=C7VN?_%B(A%PH!``4,$`\)`?;LY-_=V]K>Z?H#!0P8 M(2(>%0P'!PL5'B0E(QX8$0H#_??R[.?BWM[I_`@(!`D2%A(+`//M[O+U^/CT M[>;@W-O:V-CB]0@0#0+UZ^CJ[_3U\O,!%!H3"O[PZ.?FY^OT!A\T/T`Y+R&Q<4$Q$,!P#X[^;D[/?_"1DB(1X8$0X/$1(0#0@#_??PZ>#9U=/1S\[- MTN+Y#102$ATF(QL4"?WU\.WN\O7Y_@(!^_/IY.P"%A\=$P@"``$"`/KRZNS[ M"@X+`_;JXMS8V>+Q`@X3$Q(4%QD<'AX;%`T&`/KT[^KEX>#H^Q(G-#,I'A82 M%1PA(1X9%!`-"0/^^?/MY^+'M_Q`7%@\&`@(%"`@"^.WEYO@1("(=#_SLX^'M!R`N,"HC'1L;'B$A'AH7 M%!(0#`;\\>;=U=3A_!4@'0__\_#V``D-#`'=V=75W^_\__OS MZ.+K`QPG)1H*^>_JZO#W^O?Q[.CG[P$3'!P6#04"`PD-#`?_]>G>VN7V_O[Y M[=[6U^;]$1<3#0D("Q`4$Q`)`OSY^OT!!`3^]>SG[@8G0$E%-R07$1(7'B$@ M'AL7$0L%`/OV[^;@W^K["0X*`?7KY./O!A<:%0O\[.#8U-36UM74UN+U"A@; M%@T&`/SZ^/;S[^OHY.#>Y/4$!P'VZN;N_@T9'QX;&R`F*2VMSD[._M[OL2(B8C&P\&__GZ``8)"0<# M_/7LY^OY"`\/"0+^_?\!`?OPX]SD^`@,"@/VZ=[7V>7S_0(&"`<%`P0'"08` M^?/O[N_Q\?#LY^'@[`,9)BD@$`+Z^/P%"@T0$Q89&AH7$@L$^_/R^PL7&A<1 M"P<#!A0G+2<>$P7Z].[KZ^SJZ.GR``P1$A`,"`4"`/[[]_+MZ>;BW-C=Z_7U M\O+U^P$$!04&!@@,$!(0#`<"_/;Q[>KHZ.KR_`4)!?SV^PP<(B(<$@@#__W^ M__SX]O3S]?X*$Q<6$PX(!`,$!@@'!/WV\_L,&!D6$`D*$A@;'!H7%!,4%A@8 M%A(."P;DX>#B[/T/&1@0!_[W M\>WN\O;X]>_J[P`/$@P"^/8!#1(3$0T*"@P0%!87%A(-!P#[]>_LZNGM^@4& M__\*$Q01#07__/S^``#^^O;R\.SGY>O\#Q<4"__SZ^?I\/?Y]_/W!A8:%@W_ M[^+:V^P#$A84#0%@P"]_#L[?#U]_CW]_CX]_;T\>WIZ_0! M"0P*`_GP[OP1'B$>%`?^^?;W^?KY^/H"#1<:&10/"00"`P<+"PD%`?ST[.;K M^`,*$189&180"@3_^_K_`P4&!@<)"@D&__?NY^7L^@8(`_KR]@,.$!`-!@'_ M_OX``P,!_OKX_0D3%Q4.!__Z^/L`!@@&`?KPZ.?R_@(`^_C[!0H+"@D'!04% M!PL.#@T+!P+]]_+NZ^GO_`D."@0$#A@:&!0-!P,!````_OOY]_/NZ>SW`P@' M`_WX]?3V^O[_^O+IYN[[`?[X[N'9W>OX_O[Z]?'N[_/Z``("`/OU\.WKZ^KG MY>7K\OP+&R(A'181#Q$2$A,1#@H&`?_]_?P`"Q@?'AH3#`3_^_KY]_/Q^0D5 M%A$*__/JX^+K^P8+#`D%`O_]_/W^_/KX^/CW]?/OZN7BYO4-'R4B&0T"_/K[ M_P$!__[^_O\```#]^?C\!@T/#0@!^O3P[N[S_PX6%`\'_O;Q[.KK\?L$"@X0 M$`X+!P0%!PD)"@L+"@@%`OWX]/D*&R0E(!<0#0L*"PP-#0P+"0@'!@/^^/+Q M]@`+$1`+`OCOZ./H]PL6%Q,+`/?NZ.3CX^;O^P4*"P@%`?WZ^/G\``,"`/WY M]O+MZNSW!A,='QP7$@X+"08$`@(#!`8&!`']^O;R[NWT_P<(!@'[].[N^`8- M#`D#_/?S[^WKZ>?FZ_8"#`\."P@$`0`!`P0$`O[X\^[JZ.GO]OK^!`@(!@/_ M^O;T]/;Y_``#`O_[]O+P\._M[?#V^_W\^?7R]/T&"@P-"P@%`P#^_/KY^OL` M"1`4%!(/#`H)!P<&!@8&!0,!_?GY_P0$!`D.$Q,/"0+[]?+S^/T!`P0"`?[Z M]O+O[>OK\?H``P#Z]/3\!`@*"08#`?_]^_GX]_;V]OH"#18;&A82#0D%`P,$ M!`0#__KW^P0+#0L(!0<+#0T,"08"`/\``P8("0D(!@,`_?GU\?#Q]_X"`?__ M!@X1$`X*!`#]^OGX]_;T]//T]OP&$!45$@\+"08%!`,"_OKU[^[S_@<)"`/] M^_X#!08&`P#^_@`#!04$`P(!`?_\^OCV\_+T^?S\^OT&$!,0#`@%!`,!__W\ M^OCW]_C[_P0)#0X-"P<$`@#__?OY]O/P[O'[!`8#__KV]_T#!P@&`P'__?S\ M_/OZ^OKZ^OGW\NWGX^'AY>OP\_;]`P4!_?OX]_?W^?S^__[]^_GW]OC]!0T2 M$Q$,!@+^_?X!`P,`^_C\!@X1#PH$_OP!"`L,"PD&!`,#!0@*"PP+"08"__SZ M^/;S\?'T^/K]`PL.#0H'!`("`P,"`/SX]/+S]/3T]OG^`0,"`?_^_?SZ]_7T M\_/S\_7\`P8$`?WY^/O_`@,$`P,$!04&!P8&!@8'!P@'!@4$`P(!`@4("`8% M"1(7%A01#@T+"08$`P(`_OSZ^?GZ_0(("PL(!`#^_?W]``,$!`+^^O?Y``8& M`O_[^?K_!0<&`__\^_T"!@D*"`8$`P$`_OSY]O/Q\?7\`@8'!00'#Q04$Q`, M"04"``#__OW\^OCV]/7Y_@("`@#__O[_``$!`/[\^?;S\>_R^?W[]_3T^0`$ M!0,`_/CW^/O^``#__?S[^_OZ^??T\?#Q]_\&"0<"^_?Y`PL.#PP&`?WZ^OS] M_?OX]O7T]?G_`P8&!`'__P$#!`,"`/[\^OCV]?3V^P$!__\!!`<'!@0!```" M!`8("`<%`P$!`@0$`O_\^?;V^P(&!P4`^O;U_`8+"PD%`/S[^OGY]_7S\?'S M^0`&"`<#_OKW]_K]_____OW[^OCW]?/S]OL`!`D.$1(1#0@%`@$!`0(#!0<( M!P<&!@8'!@,!``$%#`\0#@L&`O[]`0L2%!(/"P<#`?_^_/KW]/+S]_\&"@L* M"`4#`0```````/____[\^??T\?+W_`()#`L(!0+__?W]_O[]_?W^__[^_?S\ M_/S[^_S_!0L-"P@$`@#]^?H!"`L*"`4`_/KY^?KZ^?GY_`('"@L*"`8$`@$` M````_______]^_CU\_'R]@`)#@\-"04"`/___OS[^?CW]O;V]O3S\O'Q\O/V M^P`#`P'__?OZ^OGW]O?]!`H+"08"_OOY^/GZ_/\"!0<'!@4%!04&!P<&!00$ M`P'__?KX]O7U]?7V^@()#@X,"`4"`/[^_?W]_/OZ^/?V]?7V^/K^`00&"`<& M`P$`__W]_/S\_/S]``8)"@<$`?[\^_O\_@$$!04%!`,!__[^_P`!`0#__?OY M^/CX^?GY^OK[_/X``P<*"PL)!@0#`P,"`0#__O[]_?S\_?[_`@0'"PP,"P@& M!`(!``#___[]_/S[_/T!!08$`O_]_/X``P4$`P'^_?S\_?W^_O[^__\``/__ M_OW]_?W]_?X``P4%`P$!`P<)"0<&!`,#`P,#`@$!`````0``__\``@0%!00# M`@#__O\```$!`/[]^_GX]_?Z_@$"`/[\^_P``@(!`/_^_?W^_O[^_O[^_O__ M``#__OS[^OGX]_?Y_``"`@$`_?OY^OX"`P,"`0#___[]_/S[^_KZ^?GY^_\$ M!P@(!@4#`@$!`@(#`@(!`0#__O[^_?S[^_X"!`4&"`D)"`8$`P$```````#_ M___^_OW]_?[^_OW\^_GX^/O_`@,#`?_^_/KY]_C\`00$`P'__?S[^OGY^/GY M^OP`!`8&!@0"`0`````!`0(#!`0#`@$`_OW\_/S\_/X!!@H,#`H'!`(!```` M`0$!`@,#`P("`0#__O[^_?W^_P`!`P0#`P(``/_____^_?W\_/\#!P<&!`(` M_OW\_/S\_@`#!04%!`,"`0#__O[^__\``0$!`0#__OW\^_O[^_K[^_W_`P8' M!@0"`/[^_O[^_O[^__________[^_O[__P`"`P4%!`0#`@$`______[^_?S\ M^_O^`0,#`P$`_OW]_/S]_O\`````__[^_?S\_/W]_?W^_O[___[^_OW^_O[^ M_?W\_/S\_/X``P4%!00#`@$!```!`0$!`0$!`0$``/_^_OW]_@`"!`0$`P(! M``#__O[]_/S[^_KZ^_S_`0("`0#^_?W\_/S]_@`"`P,"`/_^_O[^_O__```` M`0$!`0$``/____[^_?W\_/S\_0`#!04%!`,"`0#___[__P```0$!```````` M``#___[^_OX!`P4%!`,"`0``__________\```$!`0$!`0$``/_^_?W]_@`" M`@("`0#___[^_O[^_O__``$!``#____^_O[]_?W]_/W]_@`"`P("`0$!`@(! M`0```````0$!`0$!`0``___^_O[^_P`!`@,#`P("`0$```#___[^_?W]_?[^ M_______^_O[^_O[^_O__``$!`0````#_____________````````_____O[] M_?[^_O[__P`!`0```/___O[^_O[^__\``````````````/____________\` M``$!`0$!`````````````````````````/______________``$"`@$!``#_ M_______________^___________^_O[^_O[^_O[__P`!`0$!``#_________ M_O___P`!`@("`0$```````````#_____``$!`0$!````______\````````` M`/_____________^_O[^_O[__P`!`@(!`0```/_______P````````#___\` M````````_________P```0$!`0```/_______________P```````````/__ M____________``````````#___________\```````#_________________ M______\`````````_________________P```````/________________\` M``````````````#_______________\``````````````/___P`````````` M```````````````````````````````````````````````````````````` M``````````````````````````````!#3TU-````$@`!```H%@`(0`VL1``` M`````$U!4DL````"``!)3E-4````%#P``'\`?P``````````````````05!0 M3````:A39#)A``(````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````Z`````````````` M```````````````````````````````````````````````````````````` M```````$"```````"0`C`````````````````'@````$``0```````#\`/__ M_X`````!`0`&455N:71S```````````````````````````````````````` M`0(`!B!S86UP````%8` M``$A!%-!1$6!`0`````.```&`:/4?J:EY/O_```B8`I&`0``D`#&`0#_^/_C M````````@``````````````:`"D`#P)J`S$`*@`#`FT#/0`I``\"00,B`0`` M```:`"D`#P%0`?$`*@`#`FT#/0`````````````````:`"P`%@$^`=P`*@`# M`FT#/0`````````````````:```````````````````````````````````` M``$````!>````'@```!6`'&XO!RF````'`!6``!7```````#__\````\```````$__\```!:```````````` M```````````````````````````````````````````````````````````` ` end nethack-3.6.0/sys/share/sounds/lethdrum.uu0000664000076400007660000006404512467321052017602 0ustar paxedpaxedbegin 644 Leather_Drum M``Q,96%T:&5R($1R=6T````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``$X`SP```````$B,```! MZ*<]F@*G/9L$``````````````````````````````"!@6!?``!&3U)-``!( MA$%)1D934TY$``!&B``````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````/___P``_P`# M`@$!``#__P@.!/CU]_T!^?;\``#__/S\^?3P\?3U]?7V^?GX^/KSZ^ON\O3U M^/?R\?'V`@@,#PP)"@\7%0X-!_[Z`1`9&!03%A@;("`4"@8"``4-$Q0/"@D+ M!O[Z^/?W]OH#!0($!P/[]>WJ_QH@&A0+`?_Z]O#HY-[=Z?3V[>SW\>7AX>?L MYM?+Q;R[R=CAXMS9W-_>W^'BY>SS^@`!``(%"Q0<)"PT.CDV.#Y!0DA36UY@ M8V)=54M$0T,_."TC&1`(`__Y\^OCW=K7TQK["R MM+:VM;2SL[C"R]'7W./L\O;Y^_S^`@<,$147&A\D*"TR-38W-S;BW=G4 MT,K"NK2NJ::DHZ.CI*6FI::GJJ^TNL#%R,K.TM79W^3I[O/Y``4+$18;'R,F M*"LN,C0V.#H\/T-(3%%55E965%%-245!/3DV,B\J)2`;%A$-"08#`/WY]?+O M[.GFY.+@W]WSR^/\$"A`5&1XB)2@L+S,V.3T_04)#1$1$141#0D%`/SX].S@U,B\M*BX.+EZ.OO\O;Y^_X`!`<*#A$4%AD;'2`B)2@L+S0Y/D-(3$]04%%0 M3TQ)1D(^.3,O*B4B'AH7%!$."@8"_OKV\>WHX]_:U=#,Q\/!O[Z_O[^_O[^_ MO\#`P,'"P\7'RL[1U=G>X^CL\/3X^_\"!@H-$!,5%Q@:'!X@(B0F*"DK+"PM M+2TM+BTM+"LK*BHJ*2DH*"DI*"WHX][: MU]/0S,G&Q,&_O[^_OKZ^O\#!PL/%QL?)R\W/TM78V]_DZ>[T^O\%"@\5&ATA M)"[L MZ^GHY^;EY>;GZ.CHY^?FY>3CX=_=V]G7U];5UM;6U]?7V-G:V]S>X./FZ.ON M\?3W^_X!!`@+#A`2%!<9&QT?(2,E)RDJ+"TO,C4W.3H[.SLZ.#8T,2XJ)R,@ M'!@4$`P(!`#\^/3OZ^CDX-W9UM32T,_.SWQ M]?G\_@`!`@(#`P,#`P,#!`0%!P@*"PT/$!$1$A,5%A<8&1H:&QP<'1X>'AX> M'Q\?'QX='!P;&AD8&!<5$Q(0#PT+"08$`?_\^?;R[NKEX=W9UM/0S7I[/#S^/P!!0D.$Q8:'2$D)BDK+2XO,#`P,"\N M+"LI)R4C(!T:&!84$Q$0#@T+"0@'!00"`?_^_?OZ^/;T\O#O[N[M[>SL[>WM M[>WM[>WL[.OKZ^KIZ>CGY^?GYN;EY>7DY./CX^/DY>;HZNSO\?3X^_X!!0@, M#Q,6&1P>(20F)RDK+B\Q,S0U-34U-#,Q,"XL*28B'QL7$P\+!P/_^_CT\>[K MZ.;CX>#?WM[>WMW=W=W=W=S3CXN'@W]_?WM[?W]_@X>/DYN?IZ^WO\O3W^OS_`00'"@T0$A48&AT?(20F M)R@I*BLK+"LK*BDH)R4D(A\=&Q@6$Q$.#`D&!`'^_/GW]?/Q[^[M[.OJZ.?F MY>7EY.7EY>7EYN;FY^?HZ>KK[.WN[_#R\_3U]O?X^?GZ^_S]_?[_```!`@0% M!@<("@P-#Q$2$Q05%A<8&1H:&QP<'!P='1P<&QL:&1@7%A03$1`.#`H(!0,` M_OOY]O3Q[^SJZ.;DXN'@W][=W=S+DY>?IZNSN\/+T]OCZ^_W_ M`0($!0<("@P.#Q`2$Q,4%!45%145%104%!03$Q(2$1$1$!`0$`\/#P\.#@T- M#`L)"`<%!`,"`/_^_/OZ^??V]?7T\_+Q\.[M[.OJZ>CGYN7DY./CX^3DY.7F MY^CJZ^WO\?3V^?O]``(%!PD+#1`2$Q47&!D;&QP<'1X>'AX>'QX>'1T<&QD8 M%Q44$A$/#@P*"`8%`P'__?SZ^?CW]O7T\_/R\?'P\/#P\/#P\/#P\/#O[^_O M[^_P\/#P\/'Q\?+S\_3U]?;W^/GZ^_O\_?W^__\``0($!08("0L-#A`2$Q46 M&!D:&QP<'1T='!P;&AD8%Q44$A$/#0L*"`8$`@#^_?OY]_7S\>_N[.KIY^;E MY./CXN+BX^/DY>7GZ.GK[>[P\?/T]O?X^?O\_?[__P`!`@,$!08'!P@)"0D* M"@H+#`P-#0X.#@X/#PX.#@X.#@X.#@X-#0T-#0P,#`P,"PL*"@H)"`<%!`,! M`/[]^_KX]O3R\>_N[.OJZ>GHZ.CHZ.CHZ.CIZ>GJZ^SM[N_P\O/U]_CZ_/X` M`P4'"@P.$!(3%!46%Q@8&!@8&!@7%Q85%!,2$1`0#PX-#`L*"0<&!00#`@$` M__[^_?S\^_OZ^OGY^?GY^?GY^?GY^?GY^/CX]_?W]O;U]?3T\_/R\O+R\O+R M\O+R\_/T]?;W^/GZ^_W^_P$"`P0&!PD*#`T.$!$2$Q05%A<7&!@9&1D8&!<7 M%A43$A$/#0P*"`8$`@#^_/KX]_7T\O'P[^[M[.OKZNKJZNKJZ^OL[>WN[_#Q M\O/T]O?X^OO\_?\``0$"`P,$!`4%!04&!@8%!04%!04%!@8&!P<'!P@("`@) M"0H*"@L+"PL+#`P,#`P,#`P,#`P+"PH*"0@'!@4$`@'__OW[^?CV]?3R\?#O M[NWLZ^KJZ>GIZ>GJZNOL[>[O\/+S]/;W^?K\_O\!`P4&"`H+#`X/$!`1$A,3 M$Q,3$Q,3$A(1$!`/#@T-#`L*"0@'!@4$`P,"`0$`___^_?W\_/S\^_O[^_O[ M^_O[^OKZ^OKZ^?GY^/CX]_?V]O7U]?3T]/3T\_/S]/3T]/7V]O?X^?GZ^_W^ M_P`"`P0&!P@*"PP-#@\0$1(2$Q,4%!04%!,3$Q(1$`\.#0L*"`<%!`(!__[\ M^_KX]_;U]//S\O+Q\?#P\/#P\/'Q\?'R\O/T]/7V]_CY^OO\_?[__P```0$! M`@("`P,#`P,#`P,#`P,#`P,$!`0%!04&!@8'!P@("`D)"@H*"@H*"@H*"PL+ M"PL+"@H*"0D(!P8%!`,"`?_^_?OZ^??V]?3S\O'P\._O[^[N[N[O[^_P\?+S M]/7V]_CY^_S]_@`!`@0%!@<("@L,#`T.#@\/$!`0$!`/#PX-#0P+"@D)"`<& M!04$`P(!`0``_____O[^_OW]_?W]_/S\_/S\_/S\^_O[^_O[^_OZ^OKZ^OGY M^?GX^/CW]_?W]O;V]O;V]O?W]_CY^OO[_/W^_P$"`P0%!@<("0H+#`P-#@X/ M#P\0$!`0$`\/#PX.#0P+"PH(!P8%!`(!__[\^_KX]_;U]/3S\O+R\?'Q\?'R M\O/S]/7U]O?X^/GZ^OO\_/W^_O__```!`0("`@,#`P,#!`0$!`0$`P,#`P0$ M!`0$!`0$!`0$!04%!@8&!P<("`@)"0D)"0D)"0D("`@'!@8%!`0#`@(!`/_^ M_?S[^OGX^/?V]?3T\_/R\O+Q\?'Q\O+R\_3U]O?X^?K\_?[_``(#!`4'"`D) M"@L+#`P,#0T-#0T-#0P,"PL*"@D("`<&!@4$`P(!`0#__O[]_?S\_/O[^_O[ M^_O[^_O\_/S]_?W]_?W]_?[]_?W]_?W]_/S\_/S[^_O[^_KZ^OKZ^OKZ^OK[ M^_O[_/S]_?[__P`!`@,$!08&!P@)"@H+#`P-#0T-#@X-#0T,#`L*"0D(!P8% M`P(!`/_^_?S[^?CW]_;U]?3T\_/S\O+R\O/S\_3U]?;W^/GZ^OO\_?[_``$" M`@,$!`4%!@8&!@8'!P<'!P8&!@4%!04$!`0$!`0#`P,#`P("`@("`@("`@(" M`P,#`P,#`P0$!`0$!`0$`P,#`@(!`0#___[^_?S\^_KY^?CX]_?V]O7U]?7U M]?7U]O;W^/CY^OO\_?[_``$"`P0%!@<("0H*"PL,#`T-#0T-#0T,#`P+"@H) M"`<&!00#`P(!`/_^_?S[^OKY^?GX^/CX^/CX^/CX^/GY^?KZ^_O\_/S]_?W^ M_O[___\```````#__________________O[^_O_______P````$!`@(#`P0$ M!04&!@<'!P@("`@("`@("`@(!P<&!@4$`P,"`0#__O[]_/OZ^?CW]_;V]?7U M]/3T]/3T]?7V]O?X^?GZ^_S]_O\``0(#!`4&!@<'"`@)"0D)"0D)"0D)"0@( M"`<&!@4%!`0#`P(!`0``___^_O[^_?W]_?W]_?W]_?W^_O[^______\````` M``````````#_______[^_O[]_?W]_?W]_?W]_?W]_?[^_O__`````0("`P,$ M!`4&!@<'!P@("0D)"0D)"0D("`@'!P8&!00#`@$`___^_?S\^_KZ^?CX]_?V M]O;V]O;V]O;V]_?W^/GY^OO[_/W^_O\``0$"`P,$!`4%!04%!@8&!04%!04% M!00$!`,#`P("`@$!`0$!`0````````````````````````````$!`0$!```` M````_____O[^_?W]_/S[^_OZ^OKY^?GY^?GY^?KZ^OO[^_S\_?W^__\``0$" M`@,$!`4&!@<'"`@("0D)"0D)"`@("`<'!@8%!`0#`@$``/_^_OW\_/O[^OKZ M^?GY^?GY^?GY^OKZ^OO[_/S]_?[^__\```$!`@(#`P,$!`0$!`0$!`0$!`0$ M`P,#`P("`@("`0$!`0$!`0$!`0$!`0$!`0("`@("`@("`@("`@("`@("`@$! M`0$!````___^_OW]_/S\^_O[^_KZ^OKZ^?GY^OKZ^OO[_/S]_?[^__\``0(" M`P0$!04&!@8'!P<("`@("`@'!P<'!@8&!04$!`,"`@$``/_^_OW]_/S[^_OZ M^OKZ^OKZ^OKZ^OK[^_O[_/S\_?W^_O[___\``````0$!`0$!`0$"`@(!`0(! M`0$!`0$!`0$!`0$!`0$!`0$!`@("`@,#`P,#!`0$!`0$!`0$!`0$`P,#`P(" M`0$!``#___[^_?S\^_OZ^OKY^?GY^?GX^/CX^/GY^?KZ^_O\_/W]_O__``$" M`@,$!`4%!@8'!P<("`@("`@("`<'!P8&!@4%!`0#`P("`0``_____O[]_?W\ M_/S\_/O[^_O[^_O[^_S\_/S]_?W]_?[^_O[^________________________ M__________\```````$!`0$"`@(#`P,$!`0%!04%!04%!04%!04%!00$`P," M`@$!``#__O[]_?S[^_KZ^?GX^/CX]_?W]_?W^/CX^/GY^OK[^_S]_?[__P`! M`0(#`P0%!08&!P<'"`@("`@("`@("`<'!P<&!@4%!00$`P,"`@$!``#____^ M_O[^_?W]_?W]_?W]_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W^_O[^_O___P```0$"`@,#!`0%!04&!@<'"`@("`@)"0D("`@("`<'!@8& M!00$`P(!`0#___[]_?S[^_KZ^?GX^/CX]_?W]_CX^/CX^?GY^OK[^_S\_?[^ M__\``0$"`@,#`P0$!04%!08&!@8&!@8&!@8%!04$!`0$`P,#`@("`@$!`0`` M````_____________O[^_O[^_?W]_?W]_?S\_/S[^_O[^_O[^_KZ^OKZ^OKZ M^_O[^_S\_/W]_?[^_P```0$"`P,$!`4&!@<'!P@("`D)"0D)"0D)"`@(!P<& M!@4$!`,#`@$``/_^_?W\_/OZ^OGY^/CX]_?W]_?W]_?W^/CX^?GY^OK[^_S\ M_?[^__\```$!`@(#`P,$!`0$!04%!04%!04%!04%!04%!00$!`0$!`0$!`,# M`P,#`P("`@("`@("`0$!`0``_____O[^_?W]_/S[^_OZ^OKY^?GY^?GX^/CX M^?GY^?KZ^OO[_/S]_?[^_P```0("`P0$!08&!P<("`@)"0D)"0D)"0D)"`@( M!P8&!04$`P,"`0$`__[^_?S\^_OZ^OGY^?CX^/CX^/CX^/CY^?GY^OK[^_O\ M_/W]_O[__P```0$"`@(#`P,$!`0$!04%!04%!04%!04%!04%!04%!04%!00$ M!`0$!`,#`P,"`@(!`0$!``#____^_O[]_?S\^_O[^OKZ^?GY^?GX^/CX^/CX M^/GY^?KZ^OO[_/S]_O[_```!`@(#!`0%!08'!P@("0D)"0H*"@H*"@D)"0D( M"`<'!@4%!`,#`@$!`/_^_OW\_/OZ^OKY^?CX^/CX]_?W^/CX^/CY^?GY^OKZ M^_O\_/W]_?[^__\````!`0("`@,#`P,$!`0$!`4%!04%!04%!04%!04%!04% M!04%!04$!`0$`P,"`@(!`0``___^_OW]_/S[^_KZ^?GY^/CX^/?W]_?W]_?W M]_?X^/CY^?KZ^_O\_?W^_P`!`0(#!`0%!@8'!P@("0D)"@H*"@H*"@H)"0D) M"`@'!@8%!`0#`@(!`/___OW]_/O[^OKY^?GX^/CX^/CX^/CX^/CX^/GY^?KZ M^OO[^_S\_/W]_O[___\```$!`@(#`P,$!`0%!08&!@8'!P<'!P@("`@("`@( M"`@'!P<'!@8&!04$!`,#`@(!``#___[]_?S[^_KZ^?GX^/?W]_;V]O;V]O;V M]O;V]_?X^/GY^OO[_/W]_O\``0$"`P0%!08'!P@)"0H*"@H+"PL+"@H*"@H) M"0@(!P<&!04$`P,"`0``__[^_?S\^_OZ^OGY^?CX^/CW]_?W]_?W]_?X^/CX M^?GY^OKZ^_O\_/S]_?[^__\```$!`@(#`P0$!04%!@8'!P<'"`@("`@("0D) M"`@("`@'!P<&!@4%!`0#`P(!``#__OW]_/O[^OGY^/?W]O;U]?7T]/3T]/3T M]/7U]?;V]_?X^?KZ^_S]_O\``0("`P0%!@<'"`D)"@H+"PP,#`P,#`P,"PL+ M"@H)"`@'!@8%!`,#`@$``/_^_?W\^_OZ^?GX^/CW]_;V]O;V]O;V]O;V]O?W M]_?X^/GY^OK[^_S\_?W^_O\```$!`@,#!`0%!08&!P<("`D)"0D*"@H*"@H* M"@H*"@H)"0D("`<&!@4$`P,"`0#__OW]_/OZ^?GX]_;V]?3T\_/S\_+R\O+S M\_/S]/3U]?;W^/CY^OO\_?[_``$"`P0%!@<'"`D*"@L,#`P-#0T-#0T-#0T, M#`L+"@H)"`<'!@4$!`,"`0#__O[]_/O[^OGY^/CW]_;V]O7U]?7U]?7U]?7U M]?;V]O?W^/CY^?KZ^_S\_?[^_P`!`0(#!`0%!@<'"`D)"@H+"PP,#`P-#0T- M#0T-#`P,"PL*"0D(!P8%!`0#`@$`__[]_/OZ^?CW]O7U]//S\O+R\?'Q\?'Q M\?'R\O/S]/7U]O?X^?K[_/W^_P`!`@,$!08'"`D*"PL,#0T.#@X.#@X.#@X. M#0T-#`L+"@D("`<&!00#`@$`__[]_/OZ^OGX]_?V]?7T]/3S\_+R\O+R\O+R M\O/S\_3T]/7V]O?X^/GZ^_S]_?[_``$"`P0%!@<("0H*"PP,#0T.#@X/#P\/ M#P\/#@X-#0P,"PH)"`<&!00#`@'__OW\^_GX]_;U]//R\?'P\._O[N[N[N[N M[N_O[_#Q\O+S]/7V]_CY^_S]_@`!`@0%!@<)"@L,#0T.#Q`0$1$2$A(2$A$1 M$1`0#P\.#0P+"@D(!P8%!`,!`/_^_?S[^OGX]_;U]//S\O'Q\/#P\._O[^_O M\/#P\?'R\O/T]/7V]_CY^OO\_?\``0(#!08'"`D*"PP-#@\0$1$2$A(3$Q,3 M$Q,2$A$1$`\/#@T+"@D(!P4$`@'__OW[^OCW]O7S\O'P[^[N[>SLZ^OKZ^OK MZ^SL[>WN[_#Q\O/T]??X^?O\_?\``@,%!@@)"@P-#@\0$1(2$Q04%!05%144 M%!03$A(1$`\.#0P+"@@'!@0#`@#__?S[^?CW]O7S\O'P[^_N[>WL[.OKZ^OK MZ^OK[.SM[>[O[_#Q\O3U]O?Y^OS]_P`"`P4&"`D*#`T/$!$2$Q05%186%Q<7 M%Q<7%A85%103$A$/#@T+"@@&!0,!`/[\^OGW]O3S\?#O[NWLZ^KIZ.CHY^?G MY^CHZ>GJZ^OM[N_P\?/T]O?Y^_S^``$#!`8("0L,#0\0$1(3%!46%A<7%Q<8 M%Q<7%A85%103$A$/#@T+"@D'!00"`?_]_/KY]_;U\_+Q\.[M[>SKZNKIZ>CH MZ.CHZ.CIZ>KJZ^SM[N_P\O/T]O?Y^_S^``$#!0<("@P-#Q`2$Q06%Q@8&1H: M&AL;&QH:&AD8%Q85%!,1#PX,"@@'!0,!__W[^??V]/+Q[^[LZ^KIZ.?FYN7E MY>3DY>7EYN;GZ.GJZ^WN[_'S]/;X^?O]_P`"!`8'"0L,#A`1$A05%A<8&1D: M&QL;&QL;&AH9&!@7%A03$A`/#0L*"`8$`P'__?OY^/;T\_'P[^WLZ^KIZ.?F MYN7EY>7EY>7EYN?GZ.GJZ^SN[_'R]/;W^?O]_P$#!08("@P.$!$3%187&1H; M'!P='1T>'1T='!P;&AD8%A43$A`.#`H(!@0"`/[[^?CV]/+P[^WLZNGHY^;E MY>3DY./CX^3DY>7FY^CIZNOL[N_Q\O3V]_G[_?\``@0&"`D+#0X0$A,4%A<8 M&1D:&QL;&QL;&QL:&AD8%Q84$Q(0#@T+"0<%`P'__?OZ^/;T\_'O[NSKZNGH MY^;EY.3DX^/CX^/DY.7FYN?IZNOL[O#Q\_7V^/K\_@`"!`8("@P.$!(3%1<8 M&1H;'!T='AX>'AT='!P;&AD8%A43$1`.#`H(!@0!__W[^??U]/+P[^WLZ^GH MY^?FY>7DY.3DY.3EY>;FY^CIZNOM[N_Q\_3V]_G[_?X``@0%!PD+#0X0$1,4 M%A<8&1H;&QP<'!P<'!P;&QH9&!<6%!,1$`X,"@D'!0,!__W[^??U\_+P[^WL MZ^GHY^?FY>7DY.3DY.3EY>;FY^CIZNSM[_#R\_7W^?O]_@`"!`8("@P.$!$3 M%!87&1H;&QP='1T='1T<'!L:&1@7%A03$0\-"PH(!@0"`/[\^OCV]/+Q[^[M MZ^KIZ.?GYN;EY>7EY>7FYN?GZ.GJZ^SM[_#R\_7V^/G[_?\``@0%!PD*#`X/ M$1(3%187&!D9&AH:&QL;&AH9&1@7%A44$A$0#@P+"0<%`P'__?OY^/;T\_'O M[NWKZNGHZ.?FYN7EY>7EYN;FY^CIZ>KL[>[P\?+T]O?Y^_S^``(#!0<)"@P. M#Q$2%!46%Q@9&AH;&QL;&QH:&1D8%Q84$Q(0#@T+"0<%!`(`_OSZ^/?U\_+Q M[^[M[.OJZ>GHZ.?GY^?GY^?HZ.GJZ^SM[N_P\?/T]??X^OO]_@`"`P4&"`H+ M#0X0$1(4%186%Q@8&1D9&1D9&!@7%A44$Q(1#PX,"PD'!00"`/[\^_GW]O3S M\?#O[>SKZNKIZ.CGY^?GY^?GZ.CIZNOL[>[O\/+S]?;X^?O]_@`"`P4'"`H, M#0X0$1(4%186%Q@8&!D9&1@8%Q<6%103$A$0#@T,"@@'!0,"`/[]^_KX]_7T M\_'P[^[M[>SKZ^KJZNKJZNKJZNOK[.WN[_#Q\O/T]??X^?O\_O\``@,%!@@) M"PP.#Q`1$A,4%187%Q<8&!@8%Q<6%A44$Q(1$`\-#`H(!P4#`0#^_/OY]_;T M\_+P[^[M[.SKZNKIZ>GIZ>GIZNKKZ^SM[N_P\?+T]?;X^?O\_O\!`P0&!PD* M"PT.#Q$2$Q04%186%Q<7%Q<6%A85%!03$A$/#@T+"@@'!00"`/_]^_KY]_;T M\_+Q\._N[>WL[.OKZ^KJZNOKZ^OL[.WN[_#Q\O/T]?;W^?K[_?[_`0($!08( M"0H,#0X/$!$2$Q04%146%A86%A45%!03$A$0#PX-"PH)!P8$`@'__?SZ^/?V M]//R\._N[>WLZ^OJZNKJZ>KJZNKK[.SM[N_P\?+S]?;W^?K[_?X``0,$!@<( M"@L,#@\0$1(3$Q05%146%A86%144%!,2$A$0#PT,"PD(!P4#`@#__?SZ^?CV M]?3S\O'P[^_N[>WM[.SL[.SL[.WM[N[O\/#Q\O/T]?;X^?K[_/[_``(#!`8' M"`H+#`T.#Q`1$A(3$Q04%145%104%!,3$A$0#PX-#`L)"`8%`P(!__[\^_GX M]_7T\_+Q\._N[NWM[.SL[.SL[.SM[>[N[_#P\?+S]?;W^/G[_/W^``$"!`4& M"`D*"PP-#@\0$1(3$Q,4%!04%!04$Q,2$1$0#PX-#`H)"`8%!`(!__[]^_KX M]_;U]//R\?#O[^[N[>WM[>WM[>WM[N[O[_#Q\?+S]/7V]_GZ^_S]_P`!`P0% M!@@)"@L,#0X/$!$1$A(3$Q,4%!,3$Q,2$A$0#PX-#`L*"0@&!0,"`?_^_/OZ M^/?V]?3S\O'P[^_N[NWM[>WL[>WM[>[N[^_P\?+S]/7V]_CY^OS]_O\!`@,$ M!@<("0H+#`T.#P\0$1$2$A(2$Q,2$A(2$1$0#P\.#0P+"@D'!@4#`@'__OW[ M^OGX]O7T\_+Q\?#O[^[N[>WM[>WM[>WN[N_O\/'Q\O/T]?;W^/K[_/W^``$" M`P4&!P@)"@P-#@\/$!$1$A(3$Q,3$Q,3$Q(2$1`0#PX-#`H)"`8%!`(!`/[] M^_KY]_;U]//R\?#P[^_N[NWM[>WM[>WN[N_O\/#Q\O/T]?;W^/GZ^_W^_P`! M`@0%!@<("0H+#`T.#P\0$1$1$A(2$A(2$A(1$1`0#PX-#`L*"0@'!@4#`@'_ M_OW\^_GX]_;U]//S\O'Q\/#O[^_O[N[O[^_O\/#Q\?+S\_3U]O?X^?K[_/W_ M``$"`P0&!P@)"@L,#0X/#Q`1$1(2$A(2$A(2$A$1$`\/#@T,"PH)"`8%!`(! M`/[]_/OY^/?V]?3S\O'Q\/#O[^[N[N[N[N[O[_#P\?'R\_3T]?;W^/GZ^_S^ M_P`!`@,$!08'"`D*"PP-#@X/#Q`0$1$1$1$1$1$0$`\/#@T,#`L*"0<&!00# M`0#__OW[^OGX]_;U]//R\O'Q\/#O[^_O[^_O[^_P\/'Q\O+S]/3U]O?X^?K[ M_/W^_P$"`P0%!@<("0H+#`T.#@\0$!$1$1$1$1$1$!`0#PX.#0P+"@D(!P8$ M`P(!`/[]_/OZ^?CW]O7T\_+R\?'P\/#O[^_O[_#P\/#Q\?+S\_3U]O;W^/GZ M^_S]_O\``0($!08'"`D*"@L,#0T.#P\0$!`0$1$1$!`0$`\/#@T-#`L*"0@' M!@4$`P$`__[]^_KY^/?V]?3T\_+Q\?#P\/#O[^_O\/#P\/'Q\O/S]/7V]_?X M^?K[_?[_``$"`P0%!@<("0H+#`T.#@\/$!`0$1$1$1$0$!`/#PX-#0P+"@D( M!P8%`P(!`/_]_/OZ^?CW]O7T]//R\O'Q\?#P\/#P\/#Q\?'R\O/S]/7U]O?X M^?K[_/W^_P`!`@,$!08&!P@)"@L,#`T-#@X/#P\/#P\/#P\/#@X.#0P,"PH) M"`<&!00#`@$`__[]^_KY^/?W]O7T\_/R\O'Q\?#P\/#P\/'Q\?+R\_/T]?7V M]_CY^OO[_?[_``$"`P0%!@<("0D*"PP-#0X.#P\/#Q`0$`\/#P\.#@T,#`L* M"0@'!@4$`P(!`/[]_/OZ^?CW]O7U]//S\O+Q\?'Q\?#P\?'Q\?+R\O/T]/7V M]O?X^?K[_/W^_P`!`@,$!`4&!P@)"@L+#`P-#0X.#@\/#P\/#PX.#@T-#`P+ M"@D(!P8%!`,"`0#__OW\^_KY^/?V]?3T\_+R\O'Q\?'P\/'Q\?'Q\O+S]/3U M]O;W^/GZ^_S]_O\``0(#!`4&!P<("0H+"PP-#0X.#@\/#P\/#P\.#@X-#0P, M"PH)"`@'!@4$`@$`__[]_/OZ^?CW]O;U]/3S\_+R\O'Q\?'Q\?+R\O/S]/3U M]?;W]_CY^OO\_?[^_P`!`@,$!08'"`D*"@L,#`T.#@X/#P\/#P\/#P\.#@T- M#`L+"@D(!P8%!`,"`0#^_?S[^OGX]_?V]?3T\_+R\O'Q\?'Q\?'Q\O+R\_/T M]?7V]_CX^?K[_/W^_P`!`@,$!`4&!P@)"@H+#`P-#0X.#@X/#P\.#@X.#0T, M#`L*"@D(!P8%!`,"`0#__OW\^_KY^/?V]O7T]//S\O+R\O+Q\?'R\O+R\_/T M]/7U]O?W^/GZ^_S\_?[_``$"`P0%!@<'"`D*"@L,#`T-#0X.#@X.#@X-#0T, M#`L+"@D("`<&!00#`@$`__[]_/OZ^?CW]_;U]?3S\_/R\O+R\O+R\O+S\_/T M]/7U]O?W^/GZ^_S\_?[_``$"`P0$!08'"`@)"@H+"PP,#`T-#0T-#0T-#`P, M"PL*"@D(!P<&!00#`@$`__[^_?S[^OGX^/?V]O7U]/3T\_/S\_/S\_/T]/3U M]?;V]_?X^?GZ^_S\_?[_``$!`@,$!04&!P@("0H*"PL,#`P,#`T-#0T,#`P, M"PL*"@D("`<&!00#`P(!`/_^_?S[^OKY^/?W]O;U]?3T]/3T\_3T]/3T]/7U M]O;W]_CY^?K[^_S]_O__``$"`@,$!04&!P<("0D*"@H+"PL+"PP,#`L+"PL* M"@H)"0@'!P8%!00#`@(!`/_^_?W\^_KZ^?CX]_?V]O7U]?7U]/3U]?7U]?7V M]O?W^/CY^?K[^_S]_?[_```!`@,#!`4&!@<'"`@)"0H*"@L+"PL+"PL+"@H* M"0D)"`@'!@8%!`0#`@$!`/_^_?W\^_OZ^?GX^/?W]O;V]?7U]?7U]?7U]O;V M]_?X^/GY^OK[_/S]_O[_```!`@,#!`4%!@8'!P@("`D)"0D)"@H*"0D)"0D) M"`@'!P8&!04$!`,"`@$``/_^_OW\_/OZ^OGY^/CW]_?V]O;V]O;V]O;V]O?W M]_CX^/GY^OK[_/S]_?[__P`!`0(#`P0$!04&!@<'"`@("0D)"0D)"0D)"0D) M"`@(!P<&!@4%!`,#`@$!`/___OW\_/O[^OKY^?CX]_?W]_;V]O;V]O?W]_?X M^/CY^?KZ^_O\_/W]_O__``$!`@(#!`0%!08&!P<'"`@("`D)"0D)"0@("`@( M!P<'!@8%!00$`P,"`@$``/___O[]_/S[^_OZ^OGY^?CX^/CX^/CX^/CX^/CY M^?GZ^OO[^_S\_?W^_O\```$!`@(#`P0$!04&!@8'!P<'"`@("`@("`@(!P<' M!P8&!@4%!`0#`P("`0$``/___OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^?GY M^?KZ^OO[_/S]_?[^__\```$"`@,#!`0%!04&!@8'!P<'!P<("`<'!P<'!P8& M!@4%!00$`P,"`@$!``#___[]_?S\^_O[^OKZ^?GY^/CX^/CX^/CX^/CY^?GY M^OKZ^_O\_/W]_O[__P```0$"`@,#!`0%!08&!@<'!P<'!P<'!P<'!P<'!@8& M!04%!`0#`P("`0$``/_^_OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^/GY^?GZ M^OO[^_S\_?W^_O__```!`0("`P,$!`4%!@8&!P<'!P<("`@("`@'!P<'!P8& M!@4%!`0#`P("`0$``/_^_OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^/CY^?GZ M^OK[^_S\_?W^_O__```!`0(#`P0$!04%!@8'!P<'"`@("`@("`@("`@'!P<& M!@8%!00$`P,"`@$!``#__O[]_?S\^_O[^OKY^?GX^/CX^/CX^/CX^/CY^?GZ M^OK[^_S\_?W^_O__```!`0("`P,$!`0%!08&!@<'!P<'!P<(!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^/CX^/CX^/CY^?GY M^?KZ^_O[_/S]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<("`@("`<'!P<' M!@8&!04$!`0#`P(!`0``___^_?W\_/O[^_KZ^?GY^/CX^/CX^/CX^/CX^/GY M^?KZ^OO[_/S]_?[^__\```$!`@(#`P0$!04%!@8&!@<'!P<'!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^/CX^/CX^/CX^?GY M^?KZ^OO[_/S\_?W^_O__```!`0("`P,$!`4%!08&!@8'!P<'!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_/S\^_OZ^OKZ^?GY^?GY^?GY^?GY^?GZ M^OK[^_O\_/W]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<'!P<'!P<'!P<& M!@8%!04$!`,#`@(!`0``___^_OW]_/S\^_OZ^OKZ^?GY^?GY^?GY^?GY^?GZ M^OK[^_O\_/S]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<'"`@'!P<'!P<& M!@8&!04$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^?GX^/CX^?GY^?GZ M^OKZ^_O[_/S]_?[^__\```$!`@(#`P0$!`4%!@8&!@<'!P<'!P<'!P<'!@8& M!@4%!00$`P,#`@(!`0#___[^_?W]_/S[^_KZ^OGY^?GY^/CX^/CX^/CY^?GY M^?KZ^OO[_/S\_?W^_O__```!`0("`P,$!`4%!08&!@<'!P<'!P<'!P<'!P8& M!@8%!04$!`,#`@(!`0``___^_?W]_/S[^_KZ^OGY^?GY^?CX^/CX^/GY^?GY M^OKZ^_O\_/S]_?[^__\```$!`@(#`P,$!`4%!08&!@8'!P<'!P<'!P<'!@8& M!@4%!00$!`,#`@(!`0``___^_OW]_?S\^_O[^OKZ^?GY^?GY^?GY^?GY^?KZ M^OK[^_O\_/S]_?[^__\```$!`@(#`P0$!`4%!08&!@<'!P<'!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_?S\^_O[^OKZ^OKY^?GY^?GY^?GY^OKZ M^OO[^_O\_/W]_?[^__\```$!`@(#`P,$!`4%!08&!@8&!P<'!P<'!P<&!@8& M!04%!00$`P,"`@$!`0``___^_OW]_?S\^_O[^_KZ^OKZ^?GY^?GY^?GZ^OKZ M^OO[^_S\_/W]_?[^__\```$!`0("`P,$!`0%!04&!@8&!@8'!P<&!@8&!@8& M!04%!`0$`P,"`@$!``#___[^_?W]_/S[^_OZ^OKZ^?GY^?GY^?GY^?GY^?KZ M^OK[^_O\_/S]_?[^____```!`0("`P,#!`0$!04%!@8&!@8&!@8&!@8&!@8& M!04%!`0$`P,#`@(!`0``___^_OW]_?S\^_O[^OKZ^OGY^?GY^?GY^?GY^?GY M^OKZ^_O[_/S\_?W^_O__```!`0("`@,#!`0$!04%!@8&!@8&!@<'!P8&!@8& M!@8%!04$!`0#`P("`0$```#___[^_?W\_/S[^_OZ^OKZ^OKY^?GY^?GY^OKZ M^OK[^_O[_/S]_?W^_O__`````0$"`@,#`P0$!04%!08&!@8&!@8&!@8&!@8& M!@4%!04$!`0#`P("`0$!``#___[^_OW]_/S\^_O[^_KZ^OKZ^OKZ^OKZ^OKZ M^OO[^_O\_/S]_?W^_O__`````0$"`@,#`P0$!`4%!04&!@8&!@8&!@8&!@8& M!04%!00$!`,#`P("`0$!``#___[^_OW]_?S\_/O[^_KZ^OKZ^OKZ^OKZ^OKZ M^OK[^_O[_/S\_?W]_O[__P````$!`@("`P,$!`0$!04%!04&!@8&!@8&!04% M!04%!`0$`P,#`@(!`0$``/____[^_?W]_/S\^_O[^_KZ^OKZ^OKZ^OKZ^OKZ M^OK[^_O\_/S]_?W^_O[__P```0$!`@("`P,$!`0$!04%!04%!08&!@4%!04% M!04$!`0$`P,#`@(!`0$``/____[^_OW]_?S\_/O[^_O[^OKZ^OKZ^OKZ^OKZ M^_O[^_O\_/S]_?W^_O[__P````$!`0("`P,#!`0$!`4%!04%!04%!04%!04% M!04$!`0$`P,#`@("`0$```#____^_O[]_?W\_/S\^_O[^_O[^OKZ^OKZ^_O[ M^_O[_/S\_/W]_?[^_O___P```0$!`@(#`P,$!`0$!04%!04%!04&!@8%!04% M!04%!`0$!`,#`P("`@$!````___^_O[]_?W\_/S\^_O[^_OZ^OKZ^OKZ^OO[ M^_O[^_S\_/S]_?W^_O[___\```$!`0("`@,#`P0$!`0%!04%!04%!04%!04% M!04%!`0$!`,#`P("`@$!`0``_____O[]_?W]_/S\^_O[^_O[^OKZ^OKZ^OO[ M^_O[^_O\_/S]_?W]_O[^__\````!`0$"`@(#`P,#!`0$!`0%!04%!04%!04% M!00$!`0$`P,#`P("`@$!`0``_____O[^_?W]_/S\_/O[^_O[^OKZ^OKZ^OKZ M^OK[^_O[^_S\_/W]_?[^_O___P```0$!`@(#`P,#!`0$!`4%!04%!04%!04% M!04%!`0$!`,#`P("`@$!`0``_____O[^_?W]_/S\^_O[^_O[^OKZ^OKZ^OKZ M^_O[^_O\_/S\_/W]_?[^____`````0$"`@(#`P,#!`0$!`4%!04%!04%!04% M!04%!04$!`0$`P,#`@("`0$```#____^_OW]_?W\_/S\^_O[^_O[^_KZ^OK[ M^_O[^_O[_/S\_/W]_?[^_O___P```0$!`@("`P,#!`0$!`4%!04%!04%!04% M!04%!04$!`0$`P,#`@("`0$!````_____O[]_?W]_/S\_/O[^_O[^_O[^_O[ M^_O[^_O\_/S\_/W]_?[^_O[___\````!`0("`@(#`P,$!`0$!`0%!04%!04% M!04%!04$!`0$`P,#`P("`@$!````_____O[^_?W]_/S\^_O[^_O[^OKZ^OKZ M^OKZ^_O[^_O\_/S\_?W]_O[^__\````!`0$"`@(#`P,$!`0$!04%!04%!04% M!04%!04$!`0$`P,#`P("`@$!````_____O[]_?W\_/S\^_O[^_KZ^OKZ^OKZ M^OKZ^OO[^_O[_/S\_?W]_O[^____`````0$!`@("`P,#`P0$!`0%!04%!04% M!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]_?S\_/S[^_O[^_O[^OKZ M^OKZ^_O[^_O[_/S\_/W]_?[^_O___P````$!`@("`P,#`P0$!`0$!04%!04% M!04%!04%!00$!`0$`P,#`@("`0$!````___^_O[]_?W]_/S\_/O[^_O[^_O[ M^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P0$!`0$!04%!04% M!04%!04%!00$!`0$`P,#`@("`0$!````_____O[^_?W]_/S\_/S[^_O[^_O[ M^_O[^_O[^_O\_/S\_/W]_?[^_O[__P````$!`0("`@(#`P,$!`0$!`4%!04% M!04%!04$!`0$!`0#`P,#`@("`0$!````_____O[^_?W]_?S\_/S[^_O[^_O[ M^_O[^_O[^_O[_/S\_/S]_?W]_O[^____`````0$!`@("`@,#`P,$!`0$!`0$ M!`4%!`0$!`0$!`0$`P,#`P("`@$!`0``_____O[^_?W]_/S\_/O[^_O[^_OZ M^OKZ^_O[^_O[^_O\_/S\_?W]_O[^____`````0$!`@("`@,#`P,$!`0$!`4% M!04%!04%!00$!`0$!`,#`P,"`@(!`0$```#___[^_OW]_?W\_/S\^_O[^_O[ M^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P,$!`0$!`4% M!04%!04%!04%!`0$!`0$`P,#`P("`@$!`0``_____O[^_?W]_?S\_/S\^_O[ M^_O[^_O[^_O[^_S\_/S\_?W]_?[^_O___P````$!`0("`@,#`P,$!`0$!`0% M!04%!04%!04%!`0$!`0#`P,#`@("`0$!````_____O[^_?W]_?S\_/S[^_O[ M^_O[^_O[^_O[^_S\_/S\_/W]_?W^_O[___\````!`0$"`@(#`P,#!`0$!`0$ M!04%!04%!04%!00$!`0$!`,#`P("`@$!`0```/___O[^_?W]_/S\_/O[^_O[ M^_OZ^OKZ^_O[^_O[^_O\_/S\_/W]_?[^_O____\````!`0$"`@(#`P,#!`0$ M!`0$!04%!04%!04%!`0$!`0$`P,#`@("`0$!````___^_O[]_?W\_/S\^_O[ M^_O[^OKZ^OKZ^OK[^_O[^_O\_/S\_?W]_O[^____`````0$!`@("`P,#`P0$ M!`0$!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]_?S\_/S[ M^_O[^_O[^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P0$ M!`0$!04%!04%!04%!04%!04%!`0$!`,#`P("`@$!`0``_____O[^_?W]_/S\ M^_O[^_O[^_KZ^OKZ^OO[^_O[^_S\_/S]_?W^_O[___\````!`0$"`@(#`P,$ M!`0$!04%!04%!04%!04%!04%!04%!`0$!`,#`P("`0$!``#____^_OW]_?S\ M_/S[^_O[^_KZ^OKZ^OKZ^OK[^_O[^_S\_/W]_?W^_O[___\```$!`0("`@,# M`P,$!`0$!`4%!04%!04%!04%!04$!`0$!`,#`P("`@$!````___^_O[]_?W\ M_/S[^_O[^_OZ^OKZ^OKZ^OKZ^_O[^_O\_/S\_?W]_?[^_O___P```0$!`@(" M`@,#`P0$!`0$!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW] M_?S\_/O[^_O[^OKZ^OKZ^OKZ^OO[^_O[^_S\_/S]_?W^_O[___\````!`0$" M`@(#`P,#!`0$!`4%!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^ M_OW]_?S\_/S[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O__`````0$! M`@("`P,#`P0$!`0%!04%!04%!04%!04%!04%!`0$!`,#`P("`@$!`0``____ M_O[^_?W]_/S\_/O[^_O[^_O[^_O[^_O[^_O[_/S\_/S]_?W^_O[___\````! M`0$"`@(#`P,#!`0$!`0%!04%!04%!04%!04%!00$!`0#`P,#`@("`0$```#_ M___^_O[]_?W\_/S\^_O[^_O[^_O[^_O[^_O[^_O[_/S\_/W]_?W^_O[___\` M```!`0$"`@("`P,#`P0$!`0$!04%!04%!04%!`0$!`0$`P,#`P("`@$!`0`` M_____O[^_?W]_/S\_/O[^_O[^_O[^OKZ^OO[^_O[^_O\_/S\_?W]_?[^_O__ M_P````$!`0("`@(#`P,#!`0$!`0$!04%!04%!00$!`0$!`,#`P,"`@(!`0$` M``#____^_O[]_?W\_/S\^_O[^_O[^_O[^_O[^_O[^_O[_/S\_/S]_?W^_O[_ M____`````0$!`@("`P,#`P0$!`0$!`4%!04%!04%!00$!`0$!`,#`P,"`@(! M`0$```#____^_O[]_?W]_/S\_/S[^_O[^_O[^_O[^_O[_/S\_/S]_?W]_O[^ M_O___P````$!`0$"`@(#`P,#`P0$!`0$!`4%!04%!04$!`0$!`0$`P,#`P(" M`@$!`0```/____[^_O[]_?W]_/S\_/S\_/O[^_O[^_O\_/S\_/S\_/W]_?W^ M_O[^____``````$!`0("`@(#`P,#`P0$!`0$!`0$!`0$!`0$!`0$!`0#`P,# M`@("`0$!````_____O[^_?W]_?S\_/S\_/O[^_O[^_O[^_O[^_S\_/S\_/W] M_?W^_O[^____``````$!`0$"`@("`P,#`P,$!`0$!`0$!`0$!`0$!`0#`P,# M`P("`@$!`0$```#____^_O[^_?W]_?S\_/S\_/O[^_O[^_O[^_O[_/S\_/S\ M_?W]_?W^_O[^____``````$!`0$"`@("`P,#`P,$!`0$!`0$!`0$!`0$!`,# M`P,#`@("`@$!`0$```#____^_O[^_?W]_?S\_/S\_/S\_/S\_/S\_/S\_/S\ M_/W]_?W]_O[^_O____\````!`0$!`@("`@(#`P,#`P,#!`0$!`0$!`0$`P,# M`P,#`P("`@("`0$!`0```/_____^_O[^_OW]_?W]_?W]_/S\_/S\_/S\_/W] M_?W]_?W]_O[^_O[_____``````$!`0$"`@("`@,#`P,#`P,$!`0$!`0$!`0$ M`P,#`P,#`P("`@(!`0$`````______[^_O[]_?W]_?W\_/S\_/S\_/S\_/S\ M_/W]_?W]_?[^_O[^_____P`````!`0$!`0("`@("`P,#`P,#`P,#`P,#`P,# M`P,#`P,"`@("`@$!`0$!`````/_____^_O[^_OW]_?W]_?W]_?W]_?S\_?W] M_?W]_?W]_?W]_O[^_O[^_____P```````0$!`0$"`@("`@("`P,#`P,#`P,# M`P,#`P,"`@("`@(!`0$!`0````#______O[^_O[]_?W]_?W]_?S\_/S\_/S\ M_/S]_?W]_?W]_?[^_O[^_O______```````!`0$!`0("`@("`@(#`P,#`P,# M`P,#`P,#`P("`@("`@(!`0$!`0````#_______[^_O[^_OW]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_O[^_O[^______\```````$!`0$!`@("`@("`@,#`P,# M`P,#`P,#`P,#`P,"`@("`@(!`0$!`0``````_______^_O[^_O[^_?W]_?W] M_?W]_?W]_?W]_?W^_O[^_O[^________`````````0$!`0$!`@("`@("`@(# M`P,#`P,#`P,#`P,#`@("`@("`@(!`0$!`0``````_______^_O[^_O[^_?W] M_?W]_?W]_?W]_?W]_?W]_?[^_O[^_O[_______\``````0$!`0$!`@("`@(" M`@(#`P,#`P,#`P,#`@("`@("`@(!`0$!`0``````_______^_O[^_O[]_?W] M_?W]_?W]_?W]_?W]_?W]_?W^_O[^_O[^_O_______P```````0$!`0$!`0(" M`@("`@("`@("`@("`@("`@("`@("`0$!`0$!``````#________^_O[^_O[^ M_?W]_?W]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O_______P```````0$!`0$! M`@("`@("`@("`@("`@("`@("`@("`@("`0$!`0$!````````_________O[^ M_O[^_O[^_O[^_?W]_?W]_?W]_?[^_O[^_O[^_O[_________`````````0$! M`0$!`@("`@("`@("`@("`@("`@("`@("`@("`@$!`0$!`0````````#_____ M_____O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^__________\````````` M`0$!`0$!`0$"`@("`@("`@("`@("`@("`@("`@$!`0$!`0$!`````````/__ M_________O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^____________```` M``````$!`0$!`0$!`@("`@("`@("`@("`@("`0$!`0$!`0$!``````````#_ M__________[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O________\` M``````````$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$````````` M``#______________O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O__________ M_P```````````0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$````` M````````_________________O[^_O[^_O[^_O[^_O[^_O______________ M_P`````````````!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M``````````````#____________________^_O[^_O[^________________ M____``````````````$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0`` M``````````#______________________O[^_O[^_O[^_O[^_O[_________ M________```````````````!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0`` M`````````````/________________[^_O[^_O[^_O[^_O[^_O[^_O[^_O__ M_____________P```````````````0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$`````````````````______________________[^_O[^_O[^_O[^_O__ M_________________P````````````````$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$`````````````````________________________________ M_________________P````````````````$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!``````````````````#_________________________ M________________________``````````````````````$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$``````````````````````/______________________ M_____________________________P`````````````````````````````` M``````````````````````````````````#_________________________ M______________________________\````````````````````````````` M`````````````````````````````````````````/__________________ M____________________________```````````````````````````````` M`````0$!`0$!`0$!`0`!``````````````````````````````````#_____ M____________________________```````````````````````````````` M```````````````````````````````````````````````````````````` M______________________________\````````````````````````````` M`````````````````````````````````````````````````````````/__ M__________________________________________\````````````````` M````````````````````````````````0T]-30```!(``0``1H``"$`-K$0` M``````!-05)+`````@``24Y35````!0\``!_`'\``````````````````$%0 M4$P```&H4V0R80`"``````````````%````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````"P```````````````` M``````````````````````````````````````````````````````!QV?P` M````````<````````````````````&```)VX````<=KD`'':4`!QVDC__P!Q MVA"J5:I5!`@```````D`(P````````````````!X````!``$``````!6_@#_ M__^``````0$@!E%5;FET@``"1Y0050C```)*DQ74E<````` M``$"1@8@T]B M:D1IT]B M:D1I'1R86QE M=BYC+F\@M@T@("`@("`@(")[3V)J1&ER?2)F:6QE_["@GY[@0:`>L$&`KO_1L`[0<-`?CQ]@L)\/G][PT4Z/(; M"?`$%`@!!P0)#?GY%17KY2`AV^,5!.KT`0']`?WQ_Q,"\@<,\@(>`?$.%/_\ M#@GX``3U_`+W]@#_Z_L:\N0=!]\.&NOV'@GU$`GP#Q[P[A4"Z@(&[_<(\O0, M]N8#%/OD_A@&\0`7"/D1&0#Y!@T"]OT!]/7]\_7V\OGOZ?0$"NSI$`O[#@P# M`@`-$`7]]@80]?$'^>W[\_#_ZN`#`_/Z_`0'_0@2#0D`!Q<7!_0%%`'\]>O^ M]N/U].;M_`;MV`P"'!GNX__YZO3TZN_P M]0KUT?DC]-@+'0($&AX/"0\*"`H"`PWUZ`;VT.H,^]?C`/?N[_7]]?`&'PWV M#2@=_OT3"_T0$?'N_/GP[NSO^O;L]O;N]_+W`_'Z&Q($%AT0_P<=!OL8#/+V M\/'_\NGQ_?G=[0GOX?CXZP,6`08B%0H8$@`('Q'Y#0;=^2#]V_(&_/;TY^;X M]N#L#03X%!L,%AD+"0H'#!,/^^P%#N[U$O?B`/K?\?/Y0G]Z1(D"/X/%O?]*QC]$@+R(!_O^ACZUNX#YM#=[N#7^`OW M\@8;(@7M!R(C#_D,&0X4"?L>(>GA_O7I[-O.V^/P!?[J\QTK`.P0'!,5#/\% M)"#Y$S<&Y`0$XN;HS-;OXMWW"?KV$Q;X`R$1`Q49#A,@$1@^%_(C#\?F$=J_ MZ=S#]07>\Q;RZ1<:[NXN-//W*RD2'C8H"@$$`?/FX]S4U=SDZ.[Z_NKG#Q#E M_R\4^1`>)#0E#2U'"]0(*-R][^G"V>O>\_O5WA7_UP@9\PLD!@\_+`7:W_WR\PH!#C4@ M$$E6)RY,&^T'%OK7R];J\=/.[./-U.GNV^8+_O`C-1]TM7'T_KUT/0J)"HX-%9F/"0O M.A7R!_+?`N>^V^/0OZO.Y,;.U=SW]PPG)#,]6&PN(%LM*C*\-;T*BU'85Q28'1;."LA M'0_'@H&'`3X`O/QSK#-Q*VOKJ^WY03C^S,M,#U#34%%23`^ M-Q(T*/'\[,[)K:BJEYNDKKW2`/X"1$8B-DI-0R,P/`D'+A/Q!O[0U>3(N\C) MQKMY_$0%0DB.!X9/D`F,40P M*34E$A'^W-;CSZ:\V:ZRYM+0^>76`B,6"S!%+SE<5T!!,R41]O;.J\BZEZ>^ MO[70Y>$.#^ MU<&WX=:IW`/0W1/WYAPU#@],.P,O02$P(@;[\@'VULO7Y.7KW-3[]M;A[/#N M\A(1`APE&R$;,5(M"1HE$_WK^?S.TNK7U^+%K=+KU>0&^00T.2DP-SI`-!82 M)`7K[=_AV-+5P=WRU]O?Y?3T$"L:#AP^-@TF/`T"$PP,\>#ZZ^+OV>GNR^3M MT,K1[OOM_AH9$B$Q)"M8-`<\0A8G(?#P^.'/T(+[^,/$_X;/R8<-S-$1R,?$`@/XM;MUL.YNLR_Q]S+\1WT M\"<=!2HM$"(L)#"M_6].&\WN/#S][QY-00&@4>&2DZ-E]+%S,K"P?FX?/?S\K'S\W6 MWM'F]^;T`O8#'P;L+SL(-T@>'R$8"@L8!OT%[_H,[.3:S.KJT]/&Y`7>W@H0 M%2LS*B,Z)@(2#/?_`^?<]_7HZ];=_O+J`@S_$#(:""\X(R`3!`P`VM'K\-;< M]>7G!_CH__/N"0+[^_H1"@`6$!(I(`4((!7U`Q<&`PX#``[RW_K>R^;3U?'= MX0/Z]!0<&Q<0*S`7!@`(%A+Y\0\8\>;N[?7FZ_;@_17R!1?Y#A__!!/U_1[[ MW.\#$OWM#P+G"03G[??WX.<,]?,:_O$B&P M\\S-\.OJ_`/T"1_^!C4:_R,8!B,5`QH'\_<(`0`%("8)%CXI$"P>#B$D#_D,\;[P_L_AZ.?;S0\` MRO_LT",3WQRP#RU``A&Q(D.C,?&QTZ//T!&_WJ_`S=V1/RS@`+Z=/H#>;("R\/ M_@\M'Q$?$2`I[^L.^L_/#>VP]NK&]^+:^_OKWAH_!B]2%C%)0$@/'#7:!C3" MTO[.SM'/R=S_RK/Q^MC;`!@%""X?"!XT/1X+(R4D"/0?$N3Q"/KM!_;!W03U MY=_L`@+_!`07*AL-"A('[MWEQ]K:R`G_Q.L)!!`5%!SN_AM:S2^MF]\/'9__?B^?GX`QG[WT`Y[#$W!SU!$!(;#/\#]^02"\OL M_]_C[>[3O^[SW`L;#B0>$BLY&?/Z!O[7J-H0V;SQ!O<+(!(&+BWT&C$/+3$/ M'Q?[$1'CV=_'O]_CM.4MY]\J)0']&0?7\OW9[PL0$`4E-R@P(Q\H_.?Z!0CI MX?;K[/OR\.S=Y/?LUP`U%@D_.1(H(O/V[-#+M;S>X.;R`!XG(T1,&!P^'`$( M"10/ZMW[!^_?V][HVLSC``P4#A0F`P$G]MW_[;A$P(.4E%# M7UDQ*2$*"-.N[-N@TNSD__8"(A3WZQDKZ.GD[?P3(1$%#P+F]_7'U?+4O='PY^+X\_(#&!L1*S8K M,R/PV-4!_=K[&_;9XNG>VO#QU.D'\`8?``@;%!8*!@_[ M&#@'$S\P*"$AGW M\Q-`%Q-;+`I&,`@;%??EY,>GR-:EK_3\UNLC)0T:+A0'(PWB_P;7U^GGZ@`@ M!ODO)QPZ*S=-)@,)%/?-U]RVOLZ_W//N^AHC`QU(&_T)\^?XX,K7W.KZ[NT5 M0R\',F,S"$)(_P#ZQM+@O\;HS[OV#^'R,S`,%AL=(P`(`]'S#M3,_/?L!O+I M'"+`X,)0/M[.T`YM[WX>T,Z=GP#0WR M`O_^(@SN_/OM^O[F]`D&&1X`!$A<$/PR*?KHX^?Q[M3.]`/Q_@D'"@`'^]\( M#,K1X-<`^K4W.W: MPL?-V=SF#Q41,CHL+5)@&`U$*03\!AOU]Q;X^PD&^=0!#\'P!Z"_^,:UO-': MU>[Y,J^YQ$!`RL])18]0!0<*18"[=_F]M6GO=?9V,WH"O\.)1TM M-ATB(@@0[=4$Z=`,)0^PTJ+A@: M*CL@^@?\^B$$V_<*_>/7Y^SYY;38__#_$@,",#H*!B]+(@@D"1DX]?4O#N#F MY,.QQ\^WL+##\N[I.5TD)%$Z'34Y'0P/!O0`^@@O_N($\N#=T][EV]'-W?'T M`/;L&A#M#1@?*BY9125032`!^P#/H*>EHKC$T.O]%#T%W.0O+/L,)1+X MZ-?(WNK1UNP`'A<&(4%`+2`C)186$^C?"`O-M.?>L[[!PN<"^/@D0T-!.C0Y M.@[H`_C.U>#?W.,!#@'^#A<(ZN/X_>S@ZP<*]/<2(Q']#1<6&Q0+$AL9!P41 M\-CKW<.VL]?AS?D?$1LF*#XI%2P1_P_LX@(%^_G]`?KV!@/;ZP[DX0[_`!H) M`PH#!0D%_O/Q"13W^QP:`?<"!_KGX.7EW]CA]@\;``8F*"D-`R@8_1<)]A@3 M]/\3_>;^_,W,[>;+U.[LZ@L'Z`D>#Q<%_20D%QDA+2`C'P<<&-W9[N/>S]+R MZ_3[\!@*W/D-^>OS^?P)!`\B%!H="QX5\/@`__7G`/_R#!(#\>?Y^_/]^0(6 M#Q,7%2<>^./[!,.[\=6[Z/WM\1,B#`P@#`LB`@P\&08D'14A(@+R"/WM\>CF MZ>WNZ>':ZN_:R=+DY>?Q#B<6'4A%0#X<*CX;`/W]\N;DX>OR]O7U!^[9_0/Z M\>[OW.X(^0HC$@L,`^CA M\=?0Y-WK]_,0'!\H#Q`N&`@2_Q8N]NT/&0G>[/[?X^/9V^#Y_?#W$1H)&AGR M!1#G^/_:`S`'\!4R*10:)18$_.C>_?S3Z`'E\P?P[_?_`<_2_^KD`P\<*1X) M&2D%]A("Y04(ZA8['04;,@SG[?'LV,K;ZO3T^0T-`O_\].3(PD4$>X'`VN+BT+P%!L.$`P+#@X0`1HW!0M**1@X$`<4Z.WP MU.3I\@#H`"P9`OS[`-J[T-/&P,;H_@`#!1XU'@P?-C<@($`\)SM&'O\+".#' MR=')M+K:\?/Z`0`.\M#FZ=S+X%Q@2-4Y"0%!((18P-@WP#ASVXNCDV,K% MNIVVX,7#[`<9%A@;%B@G"?[T\?SQZ@4?)R0A.#TK)`\1'?OM[^3S`/'8X_W9 MN]GFR/?X>'Q^>+R"P\B'BQ<3C=68D`P.1GT^NW:Z_OWXNOSVN#KW79 MU`D4_P@;+2LB'R9`1#8]7F,[,BP-!^C*V,VYN\[6QM;^\N'X\>KYXM;R__3Y M"0,/-!WX&2L>#P(?(Q%"$T/RXB,349$!T)!AP2`._?X]:ON->ZM,/%Z?_\_0$5%@4)#P\< M*1P7+SLP+3@Z*Q/^]NK=W-GM[\K?!-C-^.;)U]SD[^OR`1HU(10L&@\M'OK_ M$A8-!0\A,2P/`O[N[_#8TN_OUM;<[_OBXOCHRNOYRO@BZ_DB&R(B)"\H+"@( M&282-S3Y"B@7`?;JY/#?LJFVRM?*L,+[[-?_]_\?_O\C'A8A/#@M5DDD-BTA M*QS_Z?H1[-/_`^7SY+S`SLFUNK6T/07^N\K,`\E-AL"#"L<^`88"PH0"!HG$A`3$@GRZ]SF M"NB[V?[@R??VV/3]YMCL#@$*)A(-,#$)%#TC^P@2_/49)0,%&`+_#^O:_N7' MU<_4Y>K?WPD#X`0?^>T.$00<*!\R^;?Z`,4 M!OL@+Q\<(2PP+2(=*CPQ"0P?!/X$]?#T"`/=Y?37TN36Q,[SL]>G?T-;;R-;7N=3YWMGZ\N;_`/8* M%0X;-BPC/$-#/3$R(14:%!\3\`4$Y>O+GZ=KAQK[7PL#6W.+&@\,_^;IZMG,U?#GR]GLY.T`\MKN$`?W^!8L$A`:!PD8$0('$Q4%_14I M(B`G%_X%_-WDZ,K$XM.\ZOK5Z1#VZ0P&\@\;"A$1`Q,F%PT7%`<7*1(4,R86 M*!@`!/'>XWVX@0P'2,O+40Q%24B'BT@"A4:%!`%!Q8<"/+_ M[\SGZL?:WKS#Q\/;XN7DX0PG$AXW1E,U(2T>%AH4#_OO`@O[^A`5"@+Y_`#H MY@+MRMONU$@P5)18%&!\<$P<7'Q\A$@H,#?_M]O??U-;,P,?= MWM/B]/+[$`S_$"00!A4$!!T(]ADH$P\;+#4F+345$B+[W_3LU]?"M<[&NM+9 MT]CO`_8%-"X?,"<:+"L@&P<+%04)#@8A.`GW)17=Z?[ET=?6N\KQV=3RW=\( M_N0#*QH&(S4G&BDU(!01!@L'[?D:!?8;$_'[!OOQ]>C#U?/:T.?PY>3V_/#R M#@P!$@#_+2\<&1\O-"#_"S(<`!(.\O\,Z.+SX=[7P-/DU-'>Z^#5[03\^`L> M'@4%,R\#&D8N%"XH%CDW#P\3#@?NU,W=U[ZZM\+9T<_G\.CN^?D)%QDF&A\P M&Q\Q)!8?*0CX'!@''1<##1+RU^G_Y+JXRM#1V^SD[0;T[O\!$A\."PP$'2@' M%BD0$Q8+%Q\<$A0M(`@8%PL%Z=C?SK?#TL:\S]3&Z?W1Y"4=]`4U,0P:24$; M)SHL)BL?$BPG[?(6]][SZ\W*ULZ\PM+=W='-X?H"]OPJ.!01+"$H/1(90!4. M)!@<&A01^O@`].3=W]O@X\O+\?_FYP#KV0`'X_(/"04!"1P-!A83%!L-`Q]! M)QH^'P@L%_'P^^W-S;JGY/K+V_;7XPKTWP,8_OH*!`TA'1XD'A49)!P=+BLE M'10@'0+Y\NS;L*_!L+?+Q,_AZ@$(!!$I/1H)/#(('R\:"1(6`@H;#/\-%_[] M"O'W$0#IX-O4U>+/Q.SJNM$(_?,;."`5,#(A'28V&>CX#`4-`P0A%_OV_`3_ M"0C5X`C@S_#UY.?OT+WI^-OC]/H/'QD;.DPM(SP7`S4I^0@?#_P$_.O^".K2 MVM71W$+#@D#(3`)"18)#Q\4"!$8)R(**T$4'S+S]RSJNO;\Q<';R*_6 M].'6U>X%\.X,)R<+!1DC&Q$6%!`0^.D<.`\;/RL;(!X8$@P`ZM3`NLC*Q;Z[ MV.#$UP#^_Q@9#!LO*B0V-R0D&0H2&1@(^QDF^_4@$.\3"\?4]&!``!B``Y._Y#`+P__OOZ=OJ[N#P[M//XNOI M\?L$#0#S"1X>(QT0&BH9^"%-$_HC'O3T#/'K!>;+W>??X_/JX.7I]/?PZ_8( M_OP!_A87#1T:$ALB&14Q-QL='!`?$.#K#>FPQ-2WS.#6W>?Q]/P!_ALM$?@' M)R`("QX@$`D!`A<8$Q@5%Q4/"/X(!>WKW[R]W=K'TMG>\?CX%#(6`BSDUNOLY??U\P/[^@X1$C1.(11'-10H M)QLF(OSH`0?OYN'AZM2XQN7IU-GU\NG^!?H,%OP!%?7O%`X!&A\&_ATV'1X^ M*Q$A)@;S`0S^Z^35S.#GUL_3T-#GZ=SS"P@)$`L*%!D9$`X(!AH;&RLN.$`T M&PD;(?OK[]_)P,_2P,[=P+W?ZN7E^`X<)QD9/CXE-2L"``7U^@K\_!H6_`@: M%A\8[>4(\\3;`?#7UN7OY^CJ[`0%[OH#`2$M&Q02&!#W`0SW`QS^[R$B"",O M)!<`!0SNXO/GPKS/V-+/W.?P\>CU_00E)00:22L*+S(>*"<.``T/\/,-_.CV M]^KJYN_NSM/DVM78ZPD,_@4=(!8@(1XM&_<#%0T2%@H-#?GP[.W[]N38W>K\ M#?CK%Q[N[!$'Y_\3_O0`#P0+*Q3W`@;Z[O4`_OT#$A$)#R$F#@8'\.__Z^#\ M]][K\O/SV_T4X.0%__3\(2$.*"(,(BH/_10B"_GM_!T2``3T\??;TN#5V-/! MW.S;Z`L@%A0C(R(;*$$I"A8#'!H>$Q8S)Q0H'P((`OC^]PP1[P8;^_#[!P?BVOGOW.8`!M[K$.#&Z?#G M\?/J\?\.(2HP-B89+"X6&Q,,*A[_!!`8$@3RYN;1QL2\Q\R_P]WEW?@(]O\: M%0$()#X])39.,RDS+!P9&?;I]_/T[O3\X.#TZ]S,SN?1N.7NT_@&^R,P$`L; M'!P;"@TE#?D9$0HC%`X8"/T%%0'Y$P+R]_SRY0?XO]'AS,+&Y?#E_0/D#4(A M$1H@*@L)(!,>(2$Q$Q$V*0D+%O??\=_+X>79R75U][.VN\!!_,0(/,3.1,7*!D='10,!A$3!O__\.0, M&NST(`GC^_W8XOKLR+_6T-;UZ.\/_P8E)B@G)S(H(RT3"BH5`A3WY?[\Z>G] M`.;C].#;!_G&U/#JT-'N^O/K`A4*&S`J+"TG,#(=&AP.$@L!`M_N&NK0`?[, MSO#JTMGM\^K?Y?H'^_80"/`/'P@3)"4F*2X6"BD'$//Y"_SGYN;8 MR-#DVWC_B,-^1`3!Q`6&A,-)2L<%1TO(1,C&_OV$0SZ"`OYW^;PR<36 MP+C+QL3?Z_8>'/X5-STH"1].)_<@+@@('R4:"0#\!!,`\`+[X-_HV<34T;?3 MV[+*_?KP`AH;'3HZ)#Q`&R0U!NH1%_7X`_KM\P\0`P@#`@G\W-#K\M71V,K1 MZ.SM\._V"B(6_RI$&R4_)!`7*"?^\1<-Y?T1`0T-_@K[W=S?W-'(T,S(VN7J M]OL'"0(4)RLH,$`V,"XM."4?*`#A\O7DZO3CXNK?ZM_1\>+)[??CVNT<%^P# M)A45&PL=,A+]*#L-^ATS'OWX`OKW^NWQ\.;V\-33Z?GEV^WLY?0-"?0"#P(/ M%@83)1D(%RL+_B8G$R(/[A,L!^\##>O=[M>YR]7%SM;.W.WU^P(3%A89%R0P M*R8T+`T4(AX/`A44\>3X"_KM\N[YY\;-T=#.R-;/ROD)^`XA%A\W,R`;.TL/ M"CL1_!L$^`L$\.3@[__[Y.`)#-O4Z>GAXN+:Y>;E!P?W#!HB(0P:.BP8'B4H M%009%PT9_^3[$/[L\OKY]>[BV=?=W=W;SMKKZO;V\A,7"Q(/+$6OMN#+PM[8S>;X\P@5"1XJ'"`H+S$F*#;ZS\3@T+?(Z?+BU_`-_OD6(A<6'Q``'R\4"Q\N%_8.*Q`$&!;X MZ@H?_-_V#?'-S=O5O<;=S=KKW/L3!@P.%AT-%1\5'"\T)B`E&B="'_T)"P?Z MW>/T\>C2R=*[N-K%N=W8SO05$A$G,3,N("PX)R0O(A04$Q`@(07]^_#H[??C MVO#JTM/?V=7JZ]?F\>7^&@4!)R(&$RPQ'!8K*!4,`0DG)0+X"@7Z`?WV]_?U MWM+7T]79V=G9Y.CK`@WY!B8)^B4J'BHX0S48'"4?+QOI_`3@[??=[0/GV=W: MU\G0Y-O5W^CZ"@D6*Q@$$2`D'ADI."4/(286)B#Z]_O@VNODX.WLX-ODY-WH MZN3FXNGX_@\.!!H=!@P:&2`E'!T>$Q,?*1\+&1#@[@KLW^WJV]WDUV^?P M_A0?'AX<"PXF)!HM.2`6)!L1&14,!>W9ZOKNZN[K\??JT,_=W^+BW>/H^108 M$Q47$Q$1#A,B)!<0+"\""RT8"POKZP;RY?3V]^OJY\G.YN#8WMS&V@\._1(> M#0D5'B4H+#0Y)PP4*2(;'/SC]O[EW?7PW.'2QM;-Q-SJXN+EY04C'A8.&R01 M&"4P/R`50S/X`208]>KMX>#W\.#Q_?7RZ]/0[-G)]NO)]!8,"!PF"0XF!_D? M+2$@'B0C#!$='!'MZO;EZP']]P+_W=?JX-/8U,[.T>/X!107%QX<("$F1#X= M+T,D"ADH'Q/]Y^+C\N_GHU>D+#ALE%0X>,S,?*4L\(S,I M"/T'$@/FVN7FV^KT[.3G_NK#V_CMX_CTUN\=&@,-)0SV#A(!"B,U+AXH(PL= M+POZ#>[7]_KH\OOT[-O4W]W,R^#=P=@'"@(1(AH-$AD/#2PS&"M`)1DC)S(B M]^[X[-O6Y^S0T-_*PN#:O=+S[-CL%AP<-#LE&20D&R,K)QT;$?X$#PP(!?'? M[NSA[_+GU]C@S=ORT]\+\,WQ)R46(!L8&!04%1\:$2(A$`L'"Q$&_?GX`/_[ M!P/Q\?'@T=36P[W:W]'?]@H)$204$B09$!8L030N.S(=$QDJ&.G>^?70T_GT MV-K6R]7+P-+';UMKG MZ][=Z>CR`NG1\102#Q,2%1D6#`H8)B@5"2$K#@D;'A4%_?WP[P@!V<_EZ,O` MT-C=X-OE]/3T!Q@2!`T:"@@B,3(L+STU)Q\=)!@&_N?G__#;W=C6T+>XQ[S! MVN;@W`,J)"8P*"0J(P\:*R`B)1\L(P(-*@WD[?/=WO#OX>7QY]O;UMG?YNOB MWNX,&A4<+"<;&`@('1P."!,<#@D6(!T-!@?^]_O^^O7PZ./>VM3-U>3#1TC#/+BZ>WH\/GPY>WUYL[1[.O7V.#B\P(#$1H5%`L* M&"`H'18U-"$O+R@Q*!#W]@/APN3HO?QYM/3VL[`T^7I^O_W!1`7)R`-%1X0_0DE(B(H M%1PF"@,/#`;Z[NSN]0@*[/`#X#;X._HWN+?W./=R,?>Z-W:WNG^"`\5%RPO&2,R+#`M)S`E&1`! M&"#Y[.[AW.+GY=S.W//2N>#UY^O^_NSV%`P`$A4*!@XH)Q8L-R(C+2(*`A@= M__'PYNP`]=K;W];5R;[5Y.#L]?/_$Q<.$!43$`H4&QPN+R,M+BTB`A`M!=_J M].[E[.[6WNW0P,G-U^'FX>H+!P0K)`XJ*`L2)"04'289)"D4!PDA'?;KZ.W] M[]SE[>C@SLS6TM;5V/'LZP81$ALK*A,5-3X@%C;L!.S@\>7B MZ-K9VL[&U>?8UO#[\NS_%146'AL7*SHG)C@V+"8=!`48"O;N]/;AX./I^M_) MW]W)R]7>[_;L[?X(!Q4>`_H8+2@7(#\^+3DN$2$?`@7\[NS9V?'UX=#=[].] MT]G1W_'VZO$1&18>%AD@#Q0C'RHO)"HV+1(/)B0&\_?HT>7RV<[:WM?0PL/@ MYM[H\_G^"1P;&#`H"24]&QDO'1HP)@X.$A0>">?V!.34YN;-U>*^LMG>R>0# MZND+#0H7*"D,"RXV(AHK+Q\G+PSX#1L6!.[W_N/H_>O@X-;4PKC4V$0H-&Q/GT.7QV]3>T,7AY+2XZ>[F\_3S!1<<&!HG M*RDG&"$O&QLJ&!8:`OX3&0_^Z^SXZ-[GVM+DW[BUW>SAY/'R`18!`B@F%1D: M%!LN+2(B)RPG$P84(!8&[N[YY.'MW]/2SL"WPLG3Y^;A]@0')"P8(C0G'2LU M*",L*S`O!_PA'@7_Y]?EX=7?W\;0\-BXR-GAZ^CJ\P(2"Q4S)Q#FX<[G\=+$QM/GY>/S\N;V"@X2&R$7$"(O(QXS/2SGVM+8WM7&U=S&Q,K&W//J[P/[`B`A(RL<&B`1&246(#0B&"<>!Q8H M#/'S\N'9Y^O=U=O?TL70X]S9\?GL\0L7"0LE(PT''C$=%C(Q'R,I'Q?@]PH1&AD7)288&B?= MY>S=RM7EVL2ZP]OV]M[C`!,;'!D;)R81%BD>$R$N(A4>&`P4$`7\Y.#W\=G? MZ//WV\_@V=/D\O'BYO\*#!$6&A\5!A4C$Q@J(!DC'@T1)1\$^??P[N_JYM[= M\.C&RMS>Y^;G\>GW&!,$'#`4""0L'R(O*Q\E*A8'$A(`^?CKV=KHW-+=V=;9 MT-'A\/W]\?80(!H8)2(3&"0=$QLG)!L6%14*`PX'\>??X.WKU]OSZ-C@V=3L M\^GU`??Y&B83%!L7%Q(/%!<>(AH?)18/&QH.!/+HZ^?:TMGDXM30V=;/V>7M M\?#U!QH4%2\O%QDK*!PD*1PC,B,-#AH6"/?HXM[1SMG3Q=7@S,#6Z>;J]OC] M#1<6&BHR)!PD)R8>&2@G%A84"A$6!/3SZ^?KV]+EX\K4W\G2[-C4_PKT_!89 M%28H#0\D)!H9(B,E*AX<)QP2$`#S[_'SY-7@Y=;7V_QY]?@[=;+[.K+U.;GY>?N[/4(!`86%Q<8$!8G M(Q06*C,E#0CF[0+]^PT5&1P0"QPE&1PA M'S(W&!$B(@[[_/7H\N/0[/;:V^O@V-[=W][F`OOP#A@:*!<.'QH8'PX('B8< M%!0A'@L$`OOR\^G7Z_CBVN;OX]KIYMCL_NWP`00.%A@?%Q$<(AP1$"(H#PD@ M'`D2%?_P]OGIZ?'BUMWCW=C7W.?HY/(!`@($#2(C$10A*BL:&2CGULC:ZMK<[?`!"OX+'QT5%B$?%QH?'Q@<*R`-"PD)!?;J MX^S]\-G@\O/EW^3?X>C%0'X^/[LT-[S MX,3/YM_:W]GA[_#S^/X'!084'AD4'B,B(AH;*"DC&@P/&Q'_^/GX[.GQZ=71 MX.73S=C&ATK)A(4'A(`_P#V\?CTZN+[V]?T&_``= M&0<6*!\1$!P9"`L6"P0*#0CZ]?\"^>SQ]N;:W>?IX=O_N^O3AW>KGX>S>SNKSV^/N\O[^!10.%"4A&Q\A M(AL6$@X:'PH`"`X,]NG\`_'M]>_@YO+GYO+DVNCJX>X$^O`-(140'"$E)!81 M&2`:"@L>%@0-"_G]!?GJ[?/EX>3=XNK@U=CEY>7T]?<3%049*"`J,"$6%R(? M#1,3"A,+_`0!]OCVZN;M[N;>X>;CW]K@ZN#E^_4#'@@$*"X>%ATK)`\1&A(0 M$`<*#@'U]/S^\.KU\>#F\.KEWM_JX-3I^_'Q_PH3%!(:(R<@%!,;'A<3$A(. M#Q#]^@7]^/;JZ_/IWN;IYN?=UN3LY^KU_04."PD:(AH?)!4/'2$5#!(9$PD' M!@'Y]O3LZ^WGY>+E[>7CZ>;I\/+Z__\.&0X*'"D:"Q47#A81"!$2$!,+__X( M`_+V]^KO[-OF]^[=W>KNZ>WW^P`0$0(+'1P=&PL%%A\(`1(/#1<,`@3_"`7L M]`3PWN3O\.KFVMKIZ^/H^04(#@T.'"`?)1,%&1D$`P\5"P<0!OH("?7S^O7S M[N3J\.WIX-WAX./I[OL`_Q`;%!HJ*1P4&AL,!P@)$`H`!@7X^/[Y\?/S[>KI M[OGOWN;PZN;G[_?\"0C[#R$!0?%/\'%@L""`/X^/;Y_/#N\N?L]_+Q M\.CK[N?J]/?Y`0<$!1,8&QX7%Q88'!$0'!<2$0D$_?;Y]NWM[.+A[?;RX=WL M[-_D\?+Z"`0"%!L5&"(?%Q45%A<6$1,9&10&^?O]]^WCX>CGWN?OYNOIXNGF MZOW^^P4.%!,3'2(A'1(.$`D)#PP2&PP""0,!!OKL[.WIZ.CGZNSCV^#KY^;X M^_L&!P4.'"0;$Q@<'10%#1T2"`T3#````@,!\_+PY.CLY][9YN?3VNKN_`/Z M`Q00$20H&QDA(1<-$1L6$@\$!`+V]?W]\>3H\O#M[.KNY]WAY.;J]`,'``87 M%A0A(!D>%P<.&A(+$1@5"`'_``7_\.SQ\>OK[^_N[>OGX.'CZOK[]OH`$!P1 M%28:&!X2%14-%A8/$`\$_@D%]?#P[.3EZ^?AZ>WBW>CJY_@!]?H-"@,5)1H5 M(B(5$A48&A@.`P<.`O/Y`?KPY^;N].S?XNWFW-[F[/7_`0,%!Q0<%!09&14+ M#!02$1$-#Q`*__G[_OGO[.SJ\O7HY._RY=K>ZO/V^/P!!@P7'A<:)!@'#A(( M#14-"`X3"OS^"@?Y[>KP\NGGZNGGYN/AX>?X^_'Z!`01&1DB(!L:%188$`L5 M%00%#/_[!03]]._U\NSMZ.3HZ>7;W.[S\0`!^0L1#1L@&1<4&1H.#1,4%@\" M`@@#^O?Y_?CM[O?SZ^[T[.+AX>/J\_CU^@8(#AD8%!0<&PP*%!<4%!`*#0\& M_?H``>[F\._I\>_E[>_@Y>OE\?_U\`,/!@L7%QP=%`\2$PX4&@X'#0\*__C^ M!??FZ.WKZNCGZ>OJX>;T\O$"!OL`$!,1%QT9#@\6$Q`/$A0)!Q`+__?_"/;J M\>_K[_/KX.SOX>3K\?3X!0/Z"A4/$A@9%0T-$A`0#A$9$0<+"P3_`?[V]N_H M\_'CZ?3JW.;IW_'_\_P*`P07(!<2&Q\4#0\2$Q40#0T*"0/[_0#W[NWKZO#L MZN_IY.3G[NSO_/[[`0H3%A4;'1<4$1,2#A06"P8+#`'^!/OO]_3G[//HZO'K MZN[FY>_T]O?Y`@4&$1(2&QH4%!03#@X7%0<%#PGY_/_Z^//N[>SN[NWKZ>7B MZ/#N\/O[^P,!!Q80$1@1$Q80$Q86%141#`L$_@,!^/#O[.?O]>SBXNKHX>3G M\/S\^/P($!,:%0X=(`X*%A40%Q,%"1$-_?@#_O3PZNSQ\/#MZ.OPZ.'L]/3Z M^_@!#Q`-$QD9&A4'"AT4!A$/!@\,_?X+!??V\N_V]N[GZ_+HX>KIZ>_M]/[] M_P4/%A0:'103&AD1#Q04#`0)!_T!!/CR]?'P\.WQ\>KIZ>CLZNGV_?;]!OX) M(14)&AX3%!,.%1D1!@8)!/\!^?/[]>;M]O#R].[O[^_R[>;S!/KN^`<-#@P) M#QH6#@P-$1D6!@02$`0$`?C^`>_E\/GT[.WP\/#IY._[]N[X`/L"#PH)&!D0 M#@\3&1<."@\0#PT`_@7]]_7JZ_7PY>GQ[^GEZ_+Q]OS[_04("Q05$A<6$1`2 M$`T0#04�G^_P(`_/3P\O3R\/'L[?3KY?#S\/G^^_X#"1$1#10:#`84$P@, M$`H)"08'!`(&__7X]^_T]>_P[NGKZ^CGZ_#W_OOZ!!$5$1(6$Q07#@P6$0H1 M#`,*"_[Y_O_SZO/W\.SM[>[NZN;GZO'Y^?3\"0T0$A45$!<<$`@.%1<*_042 M"O?X`_[T\^_L]??MZ>_V[>+M\^KQ`/KT``T."@X5$Q(5#@P4$PT)!PT,`P,` M_P'\]/#S]_/L[>_L[.GEZ?+Q\?\`\@(7#`H2$A(4%!$4%`\1$PH)"P4!`/[Z M]_?S[_/S\.OI\>WBZO#L]?WZ_0<+#0\1%!02$`X0$`T.$0H&#`D$`?W_^O3X M]/+Z]>GL]?7LX^OU\_3W^``*!P@4$@T3$1`2"0L5#`4*"@D(```$__OU\_GU M[_'R[NWNZ.OT[>W[^?;^!`H/"@D1%1(,#A,.#0L&"`8'!OS^`?KW^OGT\_+P M\.[N[^GL\O7X^?L!!@8'#PX+$!(/#!`2#0T-"`8%!/_\__WY]O3W^?;Q\/3R M[O#M[?;Y^OK]!PD)#@P+$1`-"PL0#`D,"0@)!04!_?_^^/7X^?/R]O3Q\O#O M\O3W]_?^`0('"0D.$0\+#0T-#0L+!PD*`P<'_0$%^_3Z_/#Q]>_N\>_N\/+U M^OGZ``,("0D0#0T3#@L.#PX+"`@'`P,#_O\!^_?X^??R\/3Q[?#P[?#U]?D` M_@`)"0D-"PL0"P8,#@D'"0D$`00#`?SZ_OOZ^O3V^/7U\O#Q[NSQ]_;T_`#^ M!0H'"@T,#0P*!P@/#P4!!@@&`OS]!/_U]?KZ]._U].[P\.[P]?;V^_[[`PX( M"!`/#A`/"@T2#`<)!P8%`0#^_P'Z]?K[]O+T]O'T]NSP^_?X__[]`@D*!PD. M#0P,!PL0#0@'!P8%`O\!`P#\^?O]^/;X]_/S]?+O\_;W^?K[``0&!P<)#`H+ M"@P-"@L*"0H'!00#``$"_/G\^/3T]/3S\N_M\_CR]/[]_@,#!0D-#@H+#0L+ M"@H+"`("!00#`?[^_OKX^??W]_/R]/+Q]/;V]_K\_@`!`PD+!P@,#`L*"0D* M!@(#!0$`!0#Z`0+Y^?KX^??T\?/T\O3U]?K\^?L``@,("04(#0H'"0H+"08$ M!`8%`?__`@#Y]_GZ^/7W]/+W]?+U]??^_?K^`@4&!@D+"0D+"@D,"`4)"`,# M!0'_`O_Y^_WW]?OW\_CW]/;Y^/G^_?P``0(%"0D("`D+"@<)"@8%!04%`P,# M__P`_OCY^_KX]O?U]_GW]OK]^_L``O\""`@&!@@,!@,+"04'!`,'!P(``@$! M_OCY_/GU]O;U]?7U]_;X_/S]_@$#!`8'"0@&"`D'"`@%`P8&`0$$`?W_`/OZ M^_CX^/7W]_7U]?CZ^OO]_P`!`@4'"`<'!P<("`4&!@($!`("__\`_/O\^_KX M^?KZ]_;W]OCY^/K[_@#^`0,$!P<'!P8("04$!P0"!@,!`O_]_?W\^OGZ^?KX M]_GY^/CX^/K]_OS]`@0$!08("0@&!@@(!00$!`0$`/X!__O^_?GY^OKY^?KW M^?SY^?O\_P'^_@0%`P4'!@8)!P4'!@4&!`,#!`']``'\_/SZ^_KX^_OW^?CY M^OK\_OW_`0`#!P,#"`<$!0<&!08%!`0#!`,`_____/W^^?C[_/KY^?GY^OOZ M^P#__@$!`P8%!`8&!04%!`0%!`$"!`(!`/_^_O[\^OKZ^OSY]_O\^?KZ^?X` M__[_!`4$!`,&"08$`P4&`P("`0(#_OT``?W\_/O\_/OZ^?O[^OKY^_[^____ M`0("!`0$!04%!`,$!`,!`0(!__[]`/[Z_/[]^_O\^_O\^_G[_/S]_O__``$! M!`0$!0,#!00#`P0#`0("``#^_@#^^OS]_/S\_/S[_/S[_?S\___^_P`!`P(# M`P,%!0("!00"`@(!`0'______?W]^_W_^_O]_/W^_/S]`0#]_P$"`@(#`P(# M`P(#`P,#`0`!`@'^_P#__O[]_?[]_/W]^_W^_/W^_O__`/\``P$``P,"`@,# M`@("`@$!`@'__@$`_O[^_?W^_OW\_?[\_/S]_O[___\``0$"`@(#`@("`@$! M`@'_`0'__P#__O[__OW^_O[]_?[^_?W^_O[_____``$!`@(!`@$!`@$!`0'_ M``$`__\``/____[^_O[^_O[^_O[]_O_^_____P$!`0$!`0$!`0$!`0`````` M`/\`_____O___O[^_O___O[^______\``````0$``0$```$``0$`````__\` M`/_______________________P#_````````````````````````````____ M_____________________P#___\````````````````````````````````` M``````!#3TU-````$@`!``!#%@`(0`VL1````````$U!4DL````"``!)3E-4 M````%#P``'\`?P``````````````````05!03````:A39#)A``(````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````N`````````````````````````````````````` M```````````````````````````````````````````$"```````"0`C```` M`````````````'@````$``0```````'\`/___X`````!`0$&455N:71S`/\` M`/___OX!`?[^`/____\``/__`/_^____`````0+_!B!S86UP````%8P*P`$D&VK3#\`J(`?!T)G2&T- MZB\.+P9.N@`\4@=P`0M-86=I8R!&;'5T90(```!!249&4V0R80`````````` M``!!249&4V0R80```````````````````````````````*<]K5D``$4B```! MSA`N`!9(@$'MJ;@2,```2('203HS$``0+@`62(!![:FX$C```$B!TD$\,Q`$ M/@5"!!U\``'_^;Q'7,`2!`H!``'``6=*ND=6P+Q'5L&"+@`4P`$"0``!9Q0_ M!Q\N__E![@`,(!AG`B\`(%!.D+Q';@1X`6#"0F````'@```!6`'&X MO!RF````'`!6``!7```````# M__\````\```````$__\```!:```````````````````````````````````` ;```````````````````````````````````` ` end nethack-3.6.0/sys/share/sounds/mgcharp.uu0000664000076400007660000006075712467321052017405 0ustar paxedpaxedbegin 644 Magic_Harp M``I-86=I8R!(87)P```````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``&@``````````$0B```! MSJ<]K4JG/:U2``````````````````````````````"!@8QW``!&3U)-``!$ M&D%)1D934TY$``!"'@`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M___________________________________________________^_O[^_OW] M_?S\_/S\^_CW]_?X]_7T]/;Z_?[_``$"`@(!`/[[^?CX^P`"`@("`@("`@(" M`@,!^.*]H)V@GZ.GK+*VNKJWN+:MFX:`B(R.CXJ#BIFGL[BZOL/(SM/:WN'@ MU='9X>ST]?7V^?X%"0L-$!(2$A$0#PT*"`@)#1$1$1`0$!`0$!`0#P\/"?KC MTL_.SM#3UMK>X-_>W]W5P["IJJNLK*:CK+C#S-#2U=K>X^?K[O#LXN+K]/X# M`@(#!@P2%1<9&QT='1P;&1<5%!,5&1L;&QL;&QH:&AH:&AD8$P+LW]S:VMS? MX^;IZ^KIZNC>R[NWN+BXM[&QN\;1V-K=X>7I[?'U]_CRZN[W_P@+"@L,#Q4: M'!XA(R0D)",B(!X<&QL>(B(B(B(A(2$A(2`@("`@&@?RY^7CX^3GZ^[Q\O+Q M\O#DT,/!P,#`OKBZQ=#:X.+EZ.SP]/C[_?SU\??_"`\0$!`2%1H?(2,E)RDI M*"@F)"(A("`C)B8F)B8F)24E)24D)"0D'@SW[>KHZ.KL\//V]_;V]_;IU?J[?'T^/S_`/[W]?P$#1,3$Q,5&1XB)"8H*BPL*RLI)R4D M(R0G*2DI*2DH*"@H*"ON M\O7Y_/\!`P'Y^0$($1<6%A<8&R`D)B@J+"XO+RXM*RDG)BSO\O;Y_/\" M`P#Y^0$)$1<7%Q<8&R`D)B@J+"XP+R\M*RDH)R@K+2TM+"PL+"PK*RLK*BHI M*2`,_?CS\/#Q\_?Z_/W]_?[UX]?4T,[-R\7$S=;@Z.ON\O7X_/X``?_X^``) M$1<7%Q<8&A\C)B_P\O7Y^_S\_/WWYMG4T,W,RL7"R=/KL\//V^OS^`/[W]?X'#Q87%A87 M&1TB)"8H*BPN+R\M+"HH)RCJ[O'U^/K\_OWW\_D$#146%A86%QH?(R4G M*2LM+RXM+"HH)R[Q]/?X^?KY\N7WP\_;X^OKX\/'Z!`X5%!04%!89'B$C)2WN\/3V]_?X].G>V=/.RL?$OKW& MS]CBY^KN\?3V^/CW\.WT_@@2%!,3$Q06&Q\A(R4G*2LL+"HH)B4E)RHJ*BHI M*2DI*"@H*"SBW-;0R\?%P+N^R-#;X^;J M[?#S]?;U\>KM]P`+$A(2$A(3%AL>("(D)B@J*RHH)B4D)2@I*2DH*"@H)RWKZNSO\?/S]/#EW]O4SLK&P[RYP,G2W>/FZ>WP\O3T M\NSH\/D##A$1$1$1$Q8;'A\A(R4G*2HH)B4D(R4H*"@H)RV-#+QL*[M;G"R];>XN;I[._Q\?#JY>KT_0@.#P\. M#Q`3%QH<'B`B)"8G)R8D(R(C)BKH MZ>OM[N_P[.'=WMC0RL2_MK.[Q,W8WN'EZ.SN[_#NY^/K]?X)#0T-#0T/$Q<9 M&QT?(2,E)ROHZ.CJ[.WN M[^K?W=[8T,G"N;&TOL;0V=S@Y.CK[>_O[.3C[/7_"0P+"PL,#Q,6&!H<'A\A M(R4E)"(A(2,E)20D)"0C(R,C(B(B(B$A'Q<)`P/^].[IY^?HZNOL[N_IW]W? MVM#'OK*ON,'*T]?;X.3HZ^WO[NOCX^WV``D*"@H*#!`3%1<8&AP>("(D)",B M(2$B)"0D)",C(R,B(B(B(2$A'QH-`P,!^?+LZ.?GZ.GJ[>_PZ=_>X-K/Q;>N ML[S$SM/6V^#DZ.OM[^[JX^/N]P`("0@("@T1$Q06&!D;'1\A(R0C(2`A(R0D M(R,C(R(B(B(A(2$A'QP1!`(#_O7NZN?GZ.GIZ^[P\.C?W^#:SK^RL;G`RL_2 MUMO@Y.CL[N_NZ>+E\/@""`<'"`H.$1(4%1<9&QT?(2(C(B$@(2,D(R,C(R(B M(B(A(2$A(!T3!@$#`/GQ[.CGY^CHZNWP\O'GW]_?V,FXL[B^Q\W/TM?;X.7I M[.[O[>?BZ/+Z`P<&!@D,#Q`1$Q46&!H<'B`B(R(A("$C(R,C(B(B(B$A(2$@ M(!T5"`("`?SU[>GGY^?GZ>SO\O3PY=[>W-+`M[J^Q'=W-7'O;W`QSI MY^?FY^KM\?7V].C>V];+Q<3$R,S,S,[1U=K@Y>KN\/#OZ./J\_H!!`4)"@L- M#@\1$A06&!H<'A\@(2`@(2(B(B(B(2$A(2`@'QT5!P$"`@#[\^WJZ.?FY^KM M\?7X]_#BV]7+R7F[_?]`P8("@L,#0X0$1,4 M%A@:'!X?("$@("(B(B(B(2$A(2`@'QP2!@$"`@'\]._KZ.?FY^KM\?7X^?7G MV]/+S-+2TM+/SL[.T=;;X>;K[_'R\.GE[/3[`@8("0H+#`T.$!$3%1<8&AP> M'R`@("$B(B(B(2$A(2`@'QL/`P("`@']]>_KZ>?FY^KN\O;Y^O?KV]#*SM;8 MV-71S\[.T-39W^7J[O'S\NWFZ?+X``<("`D*"PP-#Q`2$Q47&1L='A\@("`B M(B(A(2$A("`@'A@,`@("`@']]O#KZ>?FY^KN\O;Y^OCNW,[,TMC=WMC3T<_. MT-/8W>/H[?'S\^_GY_#W_P8'!P@)"@L,#@\1$A06&!H;'1X?'R`B(B$A(2$A M("`?'14(`@,"`0']]O#LZ>?FZ.OO\_?Y^OGPW'R`A(B$A(2$@("`>&Q$% M`@,"`@+]]O#LZ>?GZ>SP]/CZ^_GPW,S1V=WDYN#:UM/1T=/7W.'G[?'T]?/K MZ._W_@8(!P@)"@H+#0X/$1(4%A@:&QP>'R`A(B(A(2$A("`>&`L#!`0"`@+\ M]O#LZ>?HZNWQ]?G[^_CNVL_5W.'FYN/>V-73T=/7W.'H[?'U]O3MZ?#X_P8( M!P@)"0H+#`X/$!(4%1<9&QP='B`A(B(A(2$A(!\<$@8#!`0#`P'\]/#LZ.?I MZ^_S]_K\^_;KV=/9W^7GY^7@VM?4TM37W.'H[?'U]O3MZO'Y``8'!P@("0H+ M#`T.$!$3%1<8&AL<'B`A(B$A(2$@'QT7"P0$!`,#`P'Z\^_KZ.CJ[?'U^/K[ M^?/FVMC=Y.?GZ.CCW=G6U-37W.+G[?+U]O3NZ_/Z``8'!P@("0H*"PT.#Q$2 M%!88&1L<'1\A(2$A(2$@'AL0!00%!`,#`__X\NWJZ.GL[_/W^OO[]^WEX-WA MZ.CHZ>GFX-O7U=;8W>/H[O/V]_7N[?7\`08'!P@("0D*"PT.#Q$2%!87&1H; M'1\A(2$A(2$?'!0(!`4%!`,#`OWV\>SIZ>ON\O;Y^_OY\NKHX^#GZNCHZ>KG MXMW9U]?:W^3I[_7W^/7O\/C]`@<("`@("0H+"PT.#Q$2%!87&1H;'1\B(B$A M(2`=%PL%!@8$!`0$`?KT[NOJZ^WQ]?G[^_KU[>WMYN;JZ>GIZNOIX]_;V-G< MX.7K\?7W^/7P\OK_!`@("`@("0H+#`T.#Q$2%!87&1H;'2`B(B$A(!X8#04& M!@4%!`4#_?;Q[.KK[?#T^/K\^_;O[O/OZ>GJZNKJZ^SJY>##=V]S?Y.KO]/?Y^?3R^?\# M!P@("`@)"0H+#`T.#Q$2%!87&!H;'B`A(2`>&@\&!P<&!04%!0/\]>_L[.WO M\_;Y^_OW\/'W^O?OZNOKZ^OL[>_LYN#=W=[AY^SQ]?CZ^//U_0`%"`@("`@) M"0H+#`T.#Q$2%!87&1H<'R$A(!X:#P<'"`8&!04&!/[W\>[L[>_R]OGZ^O?P M\OG\_/;LZ^SL[.SM[_#LYN'?W^'EZN[S]_K[]?+Y``0("`@("`D)"@H+#`T/ M$!$3%188&1L='R(A'AD.!P@(!P8&!@8%`/CS[^WN\//V^?KZ]_'S^_[__/#K M[>WL[>WN\/'LYN+@X>/G[?+V^OSY\_?^`@<)"`@("0D)"@L,#0X/$1(4%1<8 M&AP>("`>&`T'"0D'!P8&!P8"^O3P[N[P\_;X^OKV\?3\_P(`]>SL[>WM[>[P M\O#JY>+BX^;K\/7Y_/OU]?P"!@D)"`@)"0D*"@L,#0X0$1,4%A@9&AT?(!X8 M#0<)"0@'!P8'!P3\]?'O[O#R]?CZ^?;R]?T!`P+Y[NSN[>WM[N_Q\N[HY.+C MY>GN\_?[^_?T^@$%"0H)"`@)"0D*"PP-#@\0$A,5%A@9&QX?'A@."`D)"`<' M!P<'!?_W\_#O\/+U^/GY]O+T_0$#`_SQ[.[N[N[N[_'S\>SGY./EZ.SQ]OK[ M^/3Y``0("@D("`@)"0H*"PP-#A`1$Q06%Q@:'1X=&A`("0H)"`<'!P<'`OKU M\>_P\?3W^?GW\O3]`0,$_O+L[N[N[N[O\/+S[^GEY.3GZ_#T^/KY]/@`!`@* M"0D)"0D)"@H+#`T.#Q$2%!47&!H<'1T:$0D)"@D("`<'!P@%_O?S\?#Q\_;X M^??S\_L!!`7_].WN[^[N[N_P\O3QZ^?EY.;J[O/W^?GU]P`%"`L*"0D)"0D* M"@L,#0X/$!(3%1<8&AP>'1P4"PD+"@D(!P<("`<#^_;R\?'S]??X^/3R^0$$ M!0'W[N[O[^[N[_#Q\_/NZ.;EYNCL\?3W^/7V_P4("PL*"0D)"0H*"PP-#@\0 M$1,4%A<9&QT='!@."0L+"@D("`@("`8`^?7R\?+T]OCX]?+W``,$`_GO[N_O M[N[N[_'R]/#JY^7EY^KN\O7V]/;^!0@,"PH*"0D)"0H*"PP-#@\1$A05%A@: M'!T=&A()"@L*"0@("`@("`3^^/3R\O/U]O?V\O/\`@,#_/'M[^_N[N[O\/'S M\NWHY>3FZ.SP\_7T]/L#!PL,"PH)"0D)"@H+#`P.#Q`1$Q06%QD;'1T;%@P) M"PL*"0@("`@("`/[]_3R\O3V]_?T\O@!`P0`]>[O[^[N[N[O\/+S\>OGY>7G MZNWQ\_/R^`('"@T,"@H*"0D*"@L+#`T.#Q$2%!46&!H<'1P:$@H*#`L*"0@( M"`@(!P'[]_/R\_3U]O7R\_P#`P/Z\._P[^[N[N_P\?/S[^GFY>7HZ^[Q\O'S M_@8)#0T,"PH*"@H*"@L,#0X/$!(3%!87&1L='1P8#@H,#`H*"0@("0D)!P'[ M]_3S\_3U]O3Q]@`#`__T[_#P[N[N[N_P\?/R[>GFY>;H[._Q\/#W`P@,#@T, M"PH*"@H*"PL,#0X/$1(3%188&AP='!L5#`H,#`L*"0D)"0D)!P'[]_3S\_3U M]?+Q^0$#`OOQ\/'O[N[M[N_P\?+Q[.?EY>;HZ^[O[O#\!@H.#@T,"PH*"@H+ M"PP,#0X0$1(4%1<9&QT='!H2"@L-#`L*"0D)"0D)!P+[]_3S\_3T\_#R_`(" M`/?O\?'O[NWM[N_P\?+PZ^?EY>;HZ^WM[?,`"`P.#@T,"PH*"@H+"PP-#@\0 M$1,4%A<9&QT=&Q@0"@P-#`L*"0D)"0D)!P+[]_3S\_3T\N_T_@("_O/O\?#O M[NWM[N_P\/+P[.?EY>;HZNSK[/8""0T/#@T,"PH*"@H+"PP-#@\0$1,4%A@9 M&QT<&A<."@T-#`L*"0D)"0D)"`/\^/7T\_/S\>_U_P(!_/+P\O#O[NWM[N_P M\/+Q[.CFY>;HZNOJ[/D$"@\/#@T,"PL+"PL+#`P-#@\0$1,5%A@:'!T<&A4- M"PX-#`L*"0D)"0D)"03^^?;T]//S\>_W``$!^O'Q\O#O[NWM[N_O\/+Q[.CF MY>7GZ>GH[?H%"@\0#PX-#`L+"PL+#`P-#@\0$A,5%A@:'!T<&A4-"PX.#`L* M"@D)"@D)"08`^O?U]//R\._W_P$`^?'Q\O#O[NWM[N[O\/'R[NGFY>7FZ.CG M[/D$"Q`0#PX-#`L+"PL+#`P-#@\0$A,4%A@:&QT;&14."PX.#`L*"@H*"@H) M"0<"_/CU]//R[^[V_P$`^/#Q\O#O[>WM[>[O[_#R[^KGY>7FY^?FZ_D#"@\0 M#PX-#`L+"PL+"PP-#@\0$1(4%A<9&QT;&14-"PX.#0P*"@H*"@H)"0D%_OKW M]?/R[^WT_0#_^/'R\_'O[>WM[>[N[_#R\.OHYN7EYN;EZO@""0\0#P\-#0P+ M"PL+"PP-#0X0$1(4%1<9&AP<&A8/"PX.#0P+"@H*"@H)"0H(`OSX]O3R[^WR M_/__^/'R\_'O[NWM[>WN[_#Q\>WHYN7EY>7CZ/8!!PT0$`\.#0P+"PL+"PP, M#0X/$!(3%188&AP<&A<0"PT/#@P+"@H*"@H*"0H*!?_[]_7S\.WP^?[^^?+R M]/+P[NWM[>WN[^_P\O#KZ.;EY>3BYO/^!@P0$`\/#@T,"PL+#`P,#0X/$!$3 M%!87&1L<&A@2#`P/#@T,"PH*"@H*"@H*"`/^^O;T\>[N]OS]^?/R]//Q[^[M M[>WN[N_P\?'MZ>?EY./BY._\`PH.$!`/#@T,"PL+"PP,#0T.#Q$2$Q47&!H< M&A@4#0L.#@T,"PH*"@H*"@H*"@WM[N[O M\/+PZ^CFY./AX>KX``<,#@\/#@T,#`L+"PL,#`T.#Q`1$A05%QD;&A@6$`L- M#@T,"PH*"0H*"0D)"@H&`/SX]/'M[O;[^O7Q\_3R\>_M[>WM[>[N[_'R[NKG MY>/AX.7S_0,)#`X/#PX-#`L+"PL+#`P-#@\0$1,4%A@:&QD7$PP+#@X-#`L* M"@H*"@D)"@L*!?_[]_/O[?#X^O;Q\O3S\O#N[>WM[>[N[_#R\>WIYN3BW^'L M^``&"PT/#PX-#0P+"PL+#`P-#0X/$!(3%188&AH8%@\*#`\.#0P+"@H*"@H* M"@H+"@7_^O;R[NWS^?CS\?3U\_'P[NWM[>[N[N_Q\_'LZ.;CX-_E\OP""`L- M#P\.#0P,"PL+"PP,#0T.$!$2%!47&1H9%Q0-"@X/#@T+"@H*"@H*"@H*"PH% M__KV\>WN]?GU\?+U]/+Q[^[N[N[N[N_P\O/P[.CEXM[@Z_;]!`D+#0\/#@T, M"PL+"PL,#`T.#Q`1$A05%QD:&!81"PL/#PT,"PH*"@H*"0D*"@P*!?_Z]?#M M[_;W\O#S]?3R\>_N[N[M[N[O\/+S\.OGY.#=XN_Y_P4("PT/#PX-#`L+"PL+ M#`P-#@\0$1(4%1<9&!84#@D,#PX-#`L*"@H)"0D)"@H,"@3^^?3O[?+W]?#Q M]/3S\O#O[N[N[N[N[_#R\_#KY^/?WN;R^@`&"`L-#PX-#0P+"PL+"PL,#0T. M$!$2%!47&!84$0H(#0\.#0L*"@H*"@D)"0H+#`H$_OCR[N_U^/3P\O7T\_+P M[N[N[>[N[N_Q\_3Q[.?CW]_I]/L!!@D+#0\.#0P,"PL+"PL+#`P-#@\0$A,5 M%Q84$@P'"0X.#0P+"@H*"@D)"0H*"PP(`OSV\._T^?GT\/+U]//R\._N[N[N M[N_P\?/U\NWHY.#AZ_;\`@<)#`X/#@T-#`L+"PL+"PP,#0X/$!(3%184$@X' M!@L.#@T,"PH*"@H*"@H*"PT,!P#Z\^_S^OOZ]/#S]?3S\?#O[N[N[N[O\/'T M]O3NZ>7@XN[W_0,'"@P/#PX.#0P+"PL+"PL,#`T.#Q`1$Q04$0X(`P<+#`T, M"PH*"@H*"@H*"PP-"P3^]_'R^OW]_/3P]/7T\_'O[N[N[N[N[_#R]/;U\.OE MX>3O^/X$"`H-#P\.#@T,"PL*"@L+"PP-#0X0$1,2$`X(`@0)"@L,"PL*"@H* M"@H*"@L,#0D!^O/P^/____ST\?3U]/+P[^[N[>[N[N_P\O3W]O'LYN+G\OK_ M!0@+#@\/#@T,#`L*"@H*"@L+#`T.#Q$1#@P(`0$&"`D*"PL*"@H*"@H*"@L, M#0L$_?;Q]_\"`0#Z\O+U]?3R\._N[N[N[N_P\?/U]_CS[>?DZO7\`08)#`X/ M#PX-#0P+"@H*"@H+"PP-#A`0#@L'`/\#!@<("0H+"@H*"@H*"@L,#@T'`/CS M]OX#!`+_^/'S]?7S\?#N[N[N[N_O\/+T]OCX\^WGYN_X_@,'"PT.#PX.#0P, M"PH*"@H*"PL,#0X/#0H'`/T"!08'!PD*"PL+"@H*"@L,#0X+`_KT]_X#!@4! M_?;Q]/;T\_'O[N[N[N_O\/'S]??Z^?3MY^KT^P`%"0P.#@\.#@T,"PL*"@H* M"@L+#`T-"PD%_OL``P0%!@<("@L+"PH*"@L,#0X+!/OU^/\#!@<#`/KS\O7U M\_'P[N[N[N[O\/#R]/;Y^_GS[.GO^?X#"`L-#@X.#@T-#`L*"@H*"@H*"PP- M"@<#_/K_`@(#!`4'"0H+"PL*"PL,#0X,!?SV^0`#!@@%`O[V\?3U]/+P[^[N M[N[O[_#Q\_7X^OSY\NSM]OT"!@D,#0T.#@X-#`L*"@D)"0H*"@L+"`4!^OG^ M``$!`@,%!PD+"PL*"PL,#0X,!OWX_`($!PD'`P#Z\_+U]//Q[^[N[N[O[_#Q M\_7W^?S\]_#M]/P`!0@+#0T-#@X-#0P+"@H)"0D*"@L*!@/^^/G]_P```0($ M!@@*"PL+"PP,#0X,!OWY_P0%!P@(!0+]]?'T]?/R\.[N[N[O\/#Q\O3W^?O] M_/7O\_L`!`@*"PP-#0X-#0P+"PH)"0D)"@H(!`'[]OG]_O__``$#!0<)"PL+ M"PP-#0X-!?W\`04&"`@)!P/_]_+S]?3R\._N[N[O\/#Q\_3V^?O]_OKS\_L` M`P@*"PP,#0T-#0P+"PH)"0D)"0D&`__X]?G\_?[^_P`"!`8("@L+"PP-#0T, M!?[_!`8'"`@)!P,`^O+R]?3R\>_N[N_O\/'R\_3V^?O]__WV]/L!!`<*"@L, M#`T-#0P+"PH)"0D)"0@$`?SU]OK\_/S]_O\!`P4'"0H+"PP-#0T+`_\"!P<( M"`@)"`0!^_/R]?3R\?#O[N_O\/'R\_3V^/O]___Y]OL"!`<)"0H+#`P,#`P+ M"PH)"0@("`4!_OCS]OO[^_O\_?X``@0&"`H+"PP,#0T)`P$&"`<(!P<)"`0! M^_3R]/3S\?#O[^_O\/'R\_3V^/O]_P#\^/T#!0@)"0D*"PP,#`P+"PH)"0@( M!P/_^_3T^/KZ^OO[_/[_`0,%!PD+"PP-#`P(`P4)"`@(!P@)"`0!^_3R]/3S M\?#O[^_P\/'R\_7W^?O]_P'^^OX$!@@)"0D*"@L+#`L+"@H)"`@(!`#]]O+U M^?GZ^OK[_/W_`0,%!PD+#`P,#`H&!0D*"0@'!P@)"`0!^_3R]?3S\O#P\/#P M\?+S]/7W^?S^``'__0$&"`D*"0D)"@L+"PL+"@H)"`@&`?[Y\_/W^?GY^?GZ M^_W_`0,$!@D+#`P,#`D&"0L*"0@'!P@)"`0!^_3R]?3S\O'P\/#Q\?+S]/;X M^OS^``$`_P,("0H)"`@)"0H+"PL+"@H("`<#_OOT\O;X^/CX^/GZ^_W_``($ M!@@+#`P+"@D*#`L)"`<'!P@)"`,`^O/R]?3S\O'P\/'Q\O/T]??Y^_W_`0$" M`@8*"@H)"`@("0H*"PL*"@D)"`3_^_7Q]/?X]_?W^/CZ^_W_``($!@@+#`L* M"0L.#0L)"`<'!P@)!P+_^/+S]?3S\O'P\?'R\_3U]O?Y^_X``0("!`D,#`L) M"`@("0D*"@H*"0D(!0#\]_'S]_?W]_;W]_CZ^_W^``($!@@*"PH*#`\.#`H( M!P<'"`D)!@'^]_+T]?3S\O'Q\?+S]/3V]_CZ_/\!`@($"`T.#`H(!P<("`D) M"@H*"0D&`?WX\O/V]_?V]O;V]_GZ_/W^``($!@@*"@D,$!`-"P@'!P<'"`D( M!`#[]/+U]?3S\O+R\O+S]/7V^/G[_@`!`@,&#`\.#`H(!P<'"`D)"0D)"08! M_?CR\O;W]_;V]?;W^/G[_/W_``,%!PD)"0T2$0X,"0<'!P<("`D&`O[X\_/U M]?3S\O+R\_/T]?;W^?O]_P$"`P0*$!$.#`D'!P<'"`@)"0D)!@']^//S]O?V M]O7U]?;W^/K[_/W_`0,%!P@)#1,3#PP)"`<&!P<("`@$`/OU\O3U]?3S\O+S M\_3U]O?X^OS^``(#`P8.$Q$."PD'!P<'"`@("0D&`?WX\_/V]_;V]?7U]?;W M^?K[_/[_`0,%!@@.%!,0#0H'!@8&!P<("`4!_OCS\_;U]?3S\_/S]/7V]_CZ M^_W_`0,#!`L3$P\-"@@&!@8'!P@("`4`_?CS]/?W]O;U]/3U]O?X^?K[_?X` M`@,$!@X5%!`-"@@&!@8&!P<(!P+^^_7S]?;U]?3S\_3T]?;W^/G[_?\``@,$ M"!$5$@X+"0<&!@8&!P<(!0#]^/3U^/?W]O7U]?7V]_CY^?K\_?\!`@,%#!45 M$0X*"`8&!@8&!P<'!/_\]O/U]O;U]?3T]/3U]O?X^?O\_@`!`P,%#144$`T) M!P8&!@8&!P<%`/WX]/7X^/?V]?7U]?;W^/CY^OO]_@`!`@0+%!82#PL(!P8% M!@8'!P<%`?WX]/3W]_;U]/3T]/7V]_CY^OS]_P$"`P0+%!42#PL(!P8%!@8& M!P4!_OGU]?CX^/?V]?7U]?;W^/GZ^_S^_P$"`PD2%A00#`D'!@4%!@8&!P4! M_OKT]/?W]O;U]/3U]?;W^/GZ^_W^``$"`P@2%A,0#`D'!@4%!08&!0'^^_;U M^/GX]_;U]?7V]O?X^?GZ_/W_``$"!P\6%1$-"0<&!04%!08&!0'^^O7T]_?W M]O7U]/7U]O?X^/GZ_/[_``$"!P\5%!$-"0<&!04%!08%`O[[]_7X^?CW]_;U M]?7V]_CX^?K[_/[_``$%#!06$P\+"`8%!04%!08%`?[[]O7W^/?V]?7U]?7V M]_CX^?K[_?X``0(%#105$@X*"`8%!04%!08#__WY]??Y^?CW]O;V]O;W^/GY M^OO\_?\``0,)$145$0T)!P8%!`0%!04"__SW]??X^/?V]?7U]?;W]_CY^?O\ M_?\``0,*$A43#PL)!P4$!`4%!00`_?KW]_GZ^?CW]O;V]O?X^?GY^OO]_O\` M`@8.$Q43#PL(!@4$!`0%!0/__?GU]_GX^/?V]?7U]O?W^/CY^OO]_O\``@@/ M%!01#0H(!@4$!`4%!0+^_/CV^?KZ^?CW]_;V]_CY^?GZ^_S]_P`!!`H1%101 M#0H(!@4$!`0%!`#^^O?W^?GX]_;V]?7V]O?X^/GY^OS]_O\`!`L1%!,/#`D' M!00$!`4%!`#]^O?W^OKZ^?CW]_;W]_CY^?K[^_W^_P`!!0T2%!00#`D'!00$ M!`0$`?[\^/;X^?GX]_;V]?;V]_?X^/GZ^_S]_O\""`X2%!(."@@&!00$!`0% M`O[\^?;X^_KY^/CW]_?W^/GY^OK[_/W^_P`""`X2%!,/"PD&!00$!`0"__WZ M]_?Z^OGX]_;V]O;V]_?X^/GZ^_S]_O\$"Q`2$Q`,"0<%!`0$!`0#`/W[^/?Z M^_KY^?CW]_?X^/GY^OK[_/W^_P`#"A`2%!(/"P@&!00$!`,`_OSX]_GZ^OGX M]_;V]O;W]_CX^/GZ^_S]_@`&#`\1$@\+"08%!`,$!`0#__WZ]_C[^_KY^?CW M]_?X^?GZ^OO[_/W^_P$$"Q`2$Q(."P@&!00#`P+__?OW^/KZ^OGX]_;V]O?W M^/CX^?GZ^_S]_@()#0\1$0X+"`8%!`,#!`0!_OSY]_G[^_OZ^?CX^/CX^?KZ M^OO\_?[_``$`2$Q(."@@&!00#`P'^_/GW^?O[^OGX]_?V]O?X^/CX^?GZ M^_S]_P,*#0\1$0X*"`8$!`,#!`0!_OSY^/K\^_OZ^?CX^/CY^?KZ^OO\_?[^ M_P$'#1`1$A$."@@&!`,#`P#]^_CW^?O[^OGX]_?W]_?X^/CX^?GZ^_S]_P0* M#0\0$`X+"`8$`P,#`P,`_?SY^/K\^_OZ^?CX^/CY^?KZ^OO\_/W^_P((#0\1 M$A$."P@&!`,#`O_]^_CW^OO[^OGX]_?W]_?X^/CX^?GZ^_S]_P4+#0X0$`X* M"`8$`P,#`P+__?OY^/K\^_OZ^?CX^/CY^?KZ^OO[_/W^_P('#0\0$1$/"P@& M!00#`O[\^_CX^OO[^OGX]_?W]_CX^/CX^?GZ^_S]``4*#`X/#PX+"`8$`P,# M`P+__?OY^/O\^_OZ^?CX^/CY^?KZ^OO[_/W^_P$&#`X0$1$/#`D'!00#`O[\ M^OCX^_S[^OGX^/?W]_CX^/CX^?GZ^_S]``4*#`T.#PX,"08%!`,#`P+__?OY M^/O\_/OZ^?GX^/CY^OKZ^OO[_/W^_P$&"PX/$!$0#0H(!@0#`O[\^OCX^_S[ M^_KY^/?W]_CX^/CX^?GZ^_O\_P0)#`T.#PX,"0<%!`,#`P,`_?SZ^/K\_/OZ M^OGY^/CY^OKZ^OO[_/W^_@`%"@T/$!`0#@L(!@0#`O[\^OCX^_S\^_KY^/CW M]_CX^/CX^?GZ^OO\_P0)"PP-#@X,"@@&!`,#`P,`_?SZ^/K\_/S[^OGY^/CY M^OKZ^OK[_/S]_@`$"0P.#Q`0#PT*!P4$`O[\^OCX^OS\^_KY^/CW]_CX^/CX M^/GY^OO[_@,("@L,#0X-"P@&!`,#`@(!_OS[^?G[_/S[^OGY^/CY^?KZ^OK[ M^_S]_O\"!PL-#@\0$`X+"`8$`__\^_CW^OS\^_KZ^?CX^/CX^/CX^/GY^OK[ M_0('"0L+#`X.#`D'!00#`P,"__S[^?G[_/S[^_KY^?GY^?KZ^OK[^_S\_?X` M!0H,#@\/#P\-"@<%!`#]^_GW^?S\^_OZ^?CX^/CX^/CX^/CY^?K[_``%"`H+ M#`P-#`H(!@0#`P("`/W\^OGZ_/S\^_KZ^?GY^?KZ^OKZ^_S\_?[_`@@+#0X/ M#P\.#`D'!0+^_/KW^/O\_/OZ^OGX^/CX^/CX^/CY^?KZ^_X#!PD*"PP-#0L) M!P4$`P("`?[\^_GY^_W\_/OZ^?GY^?KZ^OKZ^_O\_?W^``4*#`T.#P\/#@L( M!@3__/OX^/K\_/O[^OGY^/CX^/CX^/CX^?GZ^_P!!@@)"@L,#0P*"`8%!`," M`@#]_/KY^OS]_/O[^OGY^?GZ^OKZ^OO[_/W^_P('"PP-#@\/#PT*"`8!_?OY M]_G[_/S[^OKY^?CX^?CX^/CX^?GY^OO^`P<("0H+"PP+"0@&!`,#`@'__/OZ M^?O\_/S[^OKY^?GY^OKZ^OK[^_S]_O\#"`L,#0X/#PX-"@@$`/W[^/CZ_/S[ M^_KZ^?GX^?GX^/CX^/GY^?K\`04'"`D*"PL,"PD'!00#`@(!_OS[^?K\_?W\ M^_KZ^?GY^OKZ^OK[^_S\_?X`!0D+#`T.#@X.#0H'`__\^OCY^_S\^_OZ^OGY M^?GY^/CX^/GY^?K[_0(&!P@)"@H+#`H(!P4$`P("`/W\^OGZ_?W]_/OZ^OGY M^OKZ^OKZ^_O\_?W_`@8*"PP-#@X.#@P*!@+^_/GX^OS\_/O[^OKY^?GY^?GX M^/CY^?GZ^_\#!@<("0H*"PL*"`<%!`,"`?[\^_KY^_W]_/S[^OKY^?KZ^OKZ M^OO[_/W^_P,("@L,#0X.#@X,"04!_?OX^/K\_/S[^_KZ^?GY^?GY^/CY^?GY M^OP`!`8'"`D*"@L+"@D'!00#`@#]_/OY^OS]_?S[^_KZ^?KZ^OKZ^OK[^_S] M_@$%"0H+#`P-#@X-"P@$`/W[^/G[_/S\^_OZ^OGY^?GY^?GY^?GY^OO]`04& M!P@)"0H+"PH)!P4$`P'^_/OY^?O]_?W\^_KZ^OGZ^OKZ^OKZ^_O\_?\#!PD* M"@L,#0T-#`H'`__\^OCY^_S\_/O[^OKY^?GY^?GY^?GY^?K[_0(%!@<("0H* M"PP+"0<%!`+__/OZ^?K]_?W\_/OZ^OKZ^OKZ^OKZ^OO[_/X`!0@)"0H+#`P- M#0L)!@+^_/KX^?O\_/S[^OKZ^?GZ^OGY^?GY^?KZ^_X"!0<("`D*"@L,#`H' M!00!_?SZ^?K\_?W]_/O[^OKZ^OKZ^OKZ^OK[^_S_`P8("`D*"PL,#0P*"`4! M_OSZ^/K\_/S\^_OZ^OKZ^OKY^?GY^?KZ^_S_`P8'"`@)"@L+#`P*!P8#__S[ M^?G[_?W]_/S[^_KZ^OKZ^OKZ^OKZ^_S^`@4'"`@)"@H+#`P+"`8$`/W[^?CZ M_?W]_/O[^OKZ^OKZ^OGY^?KZ^_O]``0&!P@)"0H+"PP,"0<$`/W[^?G[_?W] M_/S[^_KZ^OKZ^OKZ^?KZ^_O]``0&!P<("0D*"PL+"0<%`__\^_GY^_W]_?S[ M^_KZ^OKZ^OKY^?KZ^OO\_0$%!P<("0D*"PP,"PD&`O[\^OGZ_/W]_/S[^_OZ M^_OZ^OKZ^?KZ^OO]``0%!@<'"`@)"@H+"@@&!`']_/KY^OS]_?S\^_OZ^OKZ M^OKZ^?KZ^OO[_/\#!@<("`D*"@L,#`L(`__]^_K[_/W\_/S[^_O[^_OZ^OKZ M^OGZ^OO\_P,%!08&!P@("0H*"0@&!`+__/OZ^?O]_?W\_/OZ^OKZ^OKZ^OKZ M^OO[_/X!!0<'"`D)"@L,#`L*!0'^^_K[_/S\_/S[^_O[^_O[^OKZ^OGZ^OO\ M_P,$!04&!@<'"`D)"0@&!0,`_?S[^?K\_?W]_/O[^OKZ^OOZ^OKZ^OO[_/W_ M`P8'"`@)"@H+"PL*!@+__/O\_?W\_/S[^_O[^_O[^_KZ^OKZ^OO\``,$!`4% M!@8'"`@)"0<&!0,!_OS[^OK[_?W]_/S[^_KZ^_OZ^OK[^_O[_/W^`@4'"`@) M"0H+"PL*!@,`_?S]_?W\_/S[^_O[^_O[^_KZ^OKZ^OO]``,#!`0%!08&!P<( M"`<%!`,"`/W\^_K[_?W]_?S[^_OZ^_O[^_O[^_O[_/S^`00&!P@)"0H*"PL) M!@0!_OW^_OW\_/O[^_O[_/S[^_KZ^OKZ^OO]`0,#!`0$!04&!@<'!P8%!`," M`/W\^_KZ_/W]_?S\^_O[^_O[^_O[^_O[_/S]_P,&!P@("0D*"@H(!00"__[_ M_OW\_/O[^_O[_/S[^_OZ^OKZ^OS^`0(#`P0$!`4%!@8'!P8$`P,"`?[\^_KZ M_/W]_?S\^_O[^_O[^_O[^_O\_/W]_P(%!P<("0D*"@D&!00"````__[]_/O[ M^_O\_/S[^_OZ^OKZ^_S_`@(#`P,$!`0%!08&!@4$`P("`?[\_/KZ_/W]_?W\ M_/O[^_O[^_O[^_S\_/W]_P(%!P<("`D*"@@%!`,"`0$!__[]_/O[^_S\_/S\ M^_O[^_K[^_T``@("`P,#!`0%!04&!@0#`@("`?_]_/OZ_/[^_?W\_/O[^_O[ M^_S[_/S\_/W^_P(%!@<("`D)"0<%!`,"`P(!__[]_/S[^_S\_/S\^_O[^_O[ M_/\!`@("`@,#`P0$!04%!00#`@(!`?_]_/O[_/[^_?W\_/O[^_O\_/S\_/S\ M_?W^_P(%!@<("`D)!P4$`P(#!`,!`/[\_/S[_/S\_/S\^_O[^_O\_@`!`@(" M`@,#`P,$!`4%!`,"`0$!`?_]_/O[_/[^_?W\_/S[^_O\_/S\_/S\_?W^_P(% M!P<'"`@(!@0#`@($!0,!`/[]_/S[_/S\_/S\^_O[^_S]_P$!`0("`@(#`P,$ M!`0$`P(!`0$!`/[]_/O[_/[^_?W\_/S[^_S\_/S\_/S]_?W^``(%!@<'"`@& M!`0#`@,%!0,"`/[]_/S\_/S\_/S\^_O[_/W_``$!`0("`@("`P,#!`0#`@$! M`````/[]_/O[_?[^_?W\_/O[^_S\_/S\_/W]_?[^``,%!@<'"`8%!`,"`P0% M!0,!`/[]_/S\_/S\_/S\_/S\_/X``0$!`0$"`@("`P,#`P,"`0$``````/[] M_/O[_?[^_?W]_/S\_/S]_?W]_?W]_O[_`00&!P<'!P4$`P("!`4%!`,!`/[] M_?W\_/S\_/S\_/S]_@`!`0$!`0$!`@("`@,#`P,!`0``````__[]_/O\_?[^ M_?W\_/S\_/W]_?W]_?W]_O[_`00&!@<&!`,#`@($!04$!`,!__[]_?W\_/S\ M_/S\_/W^``$!`0$!`0$!`@("`@,#`P$!`/___P``__W]_/S\_O[^_?W\_/S\ M_/W]_?W]_?W^_O\``@4&!@8$`P,"`@,$!`0$`P(`__[^_?W\_/S\_/S\_?X` M`0$!`0$!`0$!`0("`@("`0``_____P#__OW]_/S]_O[^_?S\_/S\_?W]_?W] M_?[^__\!`P4&!00#`P("`P0$!`0#`P(`__[^_?W\_/S\_/S]_@`!`0$!`0$! M`0$!`0("`@(!``#______P#__OW\_/W^_O[]_?W\_/W]_?W]_?W^_O[^_P`" M!`4%!`,"`@(#!`0$!`,#`@$`__[^_?S\_/S\_/W^``$!`0$!`0$!`0$!`0$" M`@$``/_________^_?W\_/W^_O[]_?W]_?W]_?[^_O[^_O[_``$#!04#`P(" M`@,$!`0$`P,#`@$`__[]_?S\_/S]_?\``0$!`0```0$!`0$!`0$"`0``____ M______[]_?S\_?[^_OW]_?W]_?W^_O[^_O[^_O__`0,$!`,"`@("`P0$!`,# M`P,"`@$`__[]_?S\_/W]_P`!`0$!`````0$!`0$!`0$!``#___[^______W] M_?S]_O[^_OW]_?W]_?[^_O[^_O[^__\``@0$`P("`@(#!`0$`P,#`@("`0#_ M_OW]_/S\_?W_``$!`0$```````$!`0$!`0$!`/___O[^_____OW]_/S^_O[^ M_?W]_?W]_O[^_O[^_O[__P`!`P,"`@(!`@,$!`,#`P,"`@("`0#__OW]_/W] M_?X``0$!`0````````$!`0$!`0$`___^_O[____^_?W]_?W^_O[^_?W]_?W^ M_O[^_O[^_O__``$#`P("`@$!`P0$`P,#`P("`@(!`/_^_?W]_?W]_@`!`0$! M``````````$!`0$!`0``___^_O____[]_?W]_?[^_O[^_?W]_?[^_O[^_O[^ M_O__`0(#`@("`0$"`P,#`P,#`@("`@(`__[^_?W]_?W^_P`!`0$````````` M``$!`0$!`0#____^_____OW]_?W]_O_^_O[^_?W]_O[^_O[^_O[^__\``@," M`0$!`0(#`P,#`P,"`@("`@$`__[]_?W]_?[_``$!`0````````````$!`0$! M``#________^_?W]_?W^__[^_O[^_?W^_O[^_O[^_O[__P`!`P,"`0$!`0(# M`P,#`P("`@("`0#__O[]_?W]_O\````````````````````!`0$!``#_____ M__[]_?W]_?[__O[^_O[^_O[^_O[^_O[^_O[__P$"`P(!`0$!`@,#`P,"`@(" M`@("`0#__O[]_?W]_O\````````````````````!`0$!`/_______OW]_?W] M_O___O[^_O[^_O[^_O[^_O[^_O__``$"`@$!`0$!`@,#`P,"`@("`@(!``#_ M_O[]_?W^_P`````````````````````!`0$!`/_______OW]_?W]_O___O[^ M_O[^_O[^_O[^_O[^_O\``0("`0$!`0$!`@,#`P("`@("`@(!`/___O[]_?[^ M_P`````````````````````!`0$``/_____^_?W]_?W^_____O[^_O[^_O[^ M_O[^_O[^__\``0("`0$!`0$"`@,#`@("`@("`@(!`/_^_O[^_O[__P`````` M```````````````!`0$``/_____^_?W]_?[^___^_O[^_O[^_O[^_O[^_O[^ M__\``@(!`0````$"`@("`@("`@("`@$!`/_^_O[^_O[_```````````````` M`````````0$``/____[]_?W]_?[____^_O[^_O[^_O[^_O[^_O[__P`!`@(! M``````$"`@("`@("`0$!`@$!`/_^_O[^_O[_```````````````````````` M`0$``/____[]_?W]_?[____^_O[^_O[^_O[^_O[^_O[__P`!`@$!``````$" M`@("`@("`0$!`0$``/___O[^_O[_``````````````````````````$```#_ M__[]_?W]_O_____^_O[^_O[^_O[^_O[^_O[__P`!`0$```````$"`@("`@(! M`0$!`0$``/___O[^_O__``````````````````````````$```#___[]_?W] M_O_____^_O[^_O[^_O[^_O[^_O___P`!`0$```````$"`@("`@$!`0$!`0$` M`/___O[^_O__``````````````````````````````#___[]_?W]_O_____^ M_O[^_O[^_O[^_O[^_O___P`!`0$```````$"`@("`@$!`0$!`0$!`/___O[^ M_O__``````````````````````````````#___[]_?W]_O_______O[^_O[_ M__[^_O[^_O___P`!`0$```````$"`@("`0$!`0$!`0$!`/____[^_O__```` M``````````````````````````#___[]_?W]_O_______O[^_O[___[^_O[^ M_O___P`!`0$```````$!`@(!`0$!`0$!`0$!``#___[^_O__```````````` M````````````````````__[^_?W]_O_______O[^_O_____^_O[^_O___P`! M`0$````````!`0$!`0$!`0$!`0$!``#____^_O__```````````````````` M````````````__[^_OW^_O________[^_O_______O[^_____P```0$````` M```!`0$!`0$!`0$!`0$!``#_________```````````````````````````` M`````/_^_O[^_O____________________[^_____P```0$``````````0$! M`0$!`0$!`0$!`0``_________P```````````````````````````````/_^ M_O[^_O[___________________________\``````````````0$!`0$!`0$! M`0$!`0``_________P```````````````````````````````/___O[^_O[_ M__________________________\```````#__P````$!`0$!`0$!`0$!`0$` M`/________\```````````````````````````````#___[^_O[_________ M__________________\```````#___\````!`0$!`0$!`0$!`0$```#_____ M__\`````````````````````````````````__[^_O[_________________ M____________````````____`````0$!`0$!`````0$`````________```` M````````````````````````````_____O[^________________________ M____````````_____P````$!`0$!````````````_________P`````````` M`````````````````````/____[^_____________________________P`` M`````/____\````!`0$!`````````````/_______P`````````````````` M``````````````#____^______________________________\``````/__ M__\```````````````````````#_______\````````````````````````` M``````#_____________________________________``````#_____```` M````````````````````______\````````````````````````````````` M____________________________________``````#_____```````````` M`````````````/______`````````````````````````````````/______ M_____________________________P``````_____P`````````````````` M````````____``````````````````````````````````#_____________ M______________________\`````_____P`````````````````````````` M``````````````````````````````````````#_____________________ M________________````______\````````````````````````````````` M````__\`````````````````````````____________________________ M_________P``______\``````````````````````````````````````/__ M````````````````````````____________________________________ M_P``______\```````````````````````````````````````#_```````` M`````````````````/__________________________________________ M__\```````````````````````````````````````#__P`````````````` M`````````/____________________________________________\````` M````````````````````````````````````__\````````````````````` M`/____________________________________________\````````````` M````````````````````````````____``````````````````````#_____ M______________________________________\````````````````````` M````````````````````_____P````````````````````#_____________ M______________________________\````````````````````````````` M`````````````/___P````````````````````#_____________________ M______________________\````````````````````````````````````` M`````/___P````````````````````#_____________________________ M_____________P````````````````````````````````````````````#_ M_P````````````````````#_____________________________________ M____```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````$-/34T````2``$``$(6``A`#:Q$```````` M34%22P````(``$E.4U0````4/```?P!_``````````````````!!4%!,```! MJ%-D,F$``@`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````"D``````````````````` M```````````````````````````````````````````````````````````` M``0(```````)`",`````````````````>`````0`!````````/P`____@``` M``$!``9156YI=',````````````````````````````````````````!`@`& M('-A;7!S```````````````````````````````````````````````````` M````````````)P`O``__]O_Y``$````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````!`````7@```!X````5M8Z*`_> MOCO;Q0T.*`5//"BD#RQP.]W&*#P!`?\@1-@4"DUA9VEC($AARQP,4`0\-!QP%7W?^,7D/ M#080```!H`*0`/`FH#,0`J``,";0,]`"D`#P)!`R(!`````!H` M*0`/`5`!\0`J``,";0,]`````````````````!H`+``6`3X!W``J``,";0,] M`````````````````!H``````````````````````````````````````0`` M``%X````>````%8`<;B\'*8````<`%8``%=S=&$``P`*``'__P`````````` M``+__P```!X```````/__P```#P```````3__P```%H````````````````` I```````````````````````````````````````````````````````` ` end nethack-3.6.0/sys/share/sounds/toolhorn.uu0000664000076400007660000005131012467321052017611 0ustar paxedpaxedbegin 644 Tooled_Horn M``M4;V]L960@2&]R;@`````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``((`10```````#DB```! MSJ<]K0&G/:TS``````````````````````````````"!@1/]``!&3U)-```Y M&D%)1D934TY$```W'@````````````````````````````#_____________ M__________________________\```````````````````````````#_____ M________```!`@,#!`4%!@8&!@8%!00$`P("`0$``/____________\````` M`0$!`@("`P,#`P,#`@("`@("`0$``/___OW]^_KY]_;T\_'P[^_N[^_P\O/V M^/O]``0&"`L-#Q`0$!`/#0P+"0@&!`,!`/_^_OW]_?W]_?W]_?[^__\``0$" M`P0$!04%!04%!04%!`,#`@$`__[]^_GW]?+P[>OIY^7EY>7GZ>SP]/G]`@8* M#A(5%Q@9&!<6%!$/#`H(!@0"`/_]_/S[^_O[^_O[_/S]_?[_``$#`P0$!04& M!@<("`D)"`<&!`,!__W[^?;R[NKEX=W;V=?7V=O>X^CN]?L""`X4&1P?(2(A M(!X<&183#PP*!P4#`?_^_/OZ^OKZ^OKZ^OO[_/W^``$"`P0%!@<("`D*"PL+ M"@D(!@4#`?[[^/3OZN7?VM;2S\[/T-/7V^'F[?3[!`P3&B`D*"HJ*B@E(AX; M%Q,/#`D&`P'__?S[^OKZ^?GY^OK[_/W^``$"`P,$!`4&!P@)"0H*"@D(!P8% M`P#]^O;Q[.?AV]71SKCW=?1R\?#P<#"Q,C-U-SE[_H&$1PF+C0X.CHX-3`K)B$;%A(-"04"__W[ M^OGX]_?W]_?X^/G[_/X``0("`P0%!P@)"@L,#`P+"@D(!P8#`/WX\^WFW]?0 MR,.^NKBZO,'(T=KE[_L'$AXG,#8Z/#PZ-S,M*"(=&!,/"P<$`/[\^OGX^/?W M]_?W^/GZ_/[_``$"!`4&"`D+#0X/$`\.#0L*"`0`_/CS[>;?UL['P+JULK&S MMKW%T-SI]P85(BXX/T-%1$(^.#(K)1\9%`\+!P0!_OSZ^?CW]_?W]_CY^?O] M_O\``0$"`P0%!P@*"PP-#0T,#`L*"`4!_??RZ^3;T\S$OKBSL*^QM+K"SMOK M^PL;*C8_14E*2$0_.#$J(QT7$0T)!0(`_OS[^OGY^?CX^?GZ^_S]_O[__P`` M`0(#!08'"0H+#`P+"PL*"`4"_OGS[.7+3E! M1TI*2$,]-BXG(!H4#PL(!0(`__[]_/S\^_O[^_S\_?W^_O[^_O[^_O\``0,% M!PD*"PP-#0T,"@<$`/SU[N;>U<['P+JTL;"PLK:^R-;G^0L=+3I$2DU-2D4^ M-R\F'QD3#@H&!`(`__[]_?S\_/S\_/S\_?W^_O[]_?W]_O[_`0($!@@)"0H* M"@H)"`8$`?WX\>KCVM/,Q+ZZM[:VN+O"RM7D]`46)3(\1$A)1T,^-R\H(!H4 M#PL(!0(`__[^_?W]_?S\_/S]_?[^_O[^_O[^_O\``@,%!@<("0H+"PL)"`8# M__KT[.7'S!1K^$2,S0$A.4$]+1#PT*R(;%`\+!P0"`0#___[^_O[^ M_O[^____``#___[^_?W]_?X``@,%!P@*"PP,"PH(!0+]^/'JX]K3S,2^N+.P MK["RM\#-W?`%&2LZ1DY14D]*0SHP)Q\7$0P(!0,!``#___________\```$! M`0#___[]_/S\_/[_`0,%!@@)"@L,#`H(!0']^/'JXMO3S,6_N;2QL+"RM\#, MW?$&&RT\2$]34U!)0CDO)AT6$`L'!`,!````______[^_O___P```/___O[] M_?W]_?X``0,%!@<("0D*"0@'!0/_^O/LY-W5SL;`N[>TL[2VN\/.W>\#%B@W M0TM/44Y)0CDP)Q\7$0P(!0,"`0``_____O[^_O[__P````#__O[]_?W]_O\` M`@,%!@<'"`D*"@H)!P0`^_3LY=S3S,.\MK*OKJ^RN<32Y/@-(#(_24]244U' M/C8L(QL4#@H&!`(!`/_^_O[^_O[^_O__``$!`0#___[^_?W]_O\!`P4'"0H* M"PL+"0@&!`#[]>[GWM;-Q;ZWL:VKK*^TOLO;[P4:+#Q'3U-34$I#.C`G'A<1 M#`@%`P$`___^_O[^_O[^____```!`0#___[]_?W]_@`!`P4'"`@)"@L*"@@& M!`#Z].SDW=3,P[RVL*RKK;"UO\S>\PD=+SY*45144$E"."\F'180"P<%`P(! M`/___O[^_O[^_O__```!`0#___[]_?W]_@`"!`8'"0H+"PL+"@@'!`#[].WD MW-/,P[RVL:ZMK:^TOLO<\0<<+S]*4E5544I"."\E'!40"P<%`P(!`/___O[^ M_O[^_O[^_P```/___OW]_?W]_@`!`P4&"`D*"@L+"PH)!@/]]^_GWM;-Q;VW MLJZLK*ZSO,G:[@09+#Q(4%1544M#.C`G'Q<1#0D&!`(!`/___O[^_O[^_O[^ M____`/___OW]_?W^_@`!`P4'"`D*"@H+"PH(!0+^^/'HX-?/Q[^XLJ^MKK"V MOLO<[P08*CE%35!13DE".3`H'Q@2#@H'!0,!`/_^_O[]_?W]_O[^_O__``#_ M__[^_?[^_O\!`P4'"0L,#`T,"PH(!0']]N_FW=3+P[NTKJNJJZ^VP,_A]@L? M,#Y)3U)13DA`-R\F'A@2#0H'!`(`__[]_?W]_?W]_?W^_O_______OW]_?W^ M_P`"!`8("@H+"PP+"PD'!0'\]>[EW=3+PKFRK*FHJ:RTP-#C^0\C-4-,4E13 M3D<_-BTD'181#0D'!0,!`/_^_?W]_?W]_?W^_O_______OW]_/W]_@`"`P4' M"0H+#`T-#0P*!P/^]^_FW=3+PKFRK*BFIJFQO,SA^`XC-4--4U543T@_-BTD M'!81#0D'!0,!`/_^_?W]_?W]_?W^_O[____^_?S\_/S]_O\``@0&"`H+#`T- M#0L)!@/_^O/JXMG0R+^XLJZJJ:JON,;8[@4:+3U(4%-34$E".3`G(!D3#PL) M!P0"`?_^_?W]_/S\_/S]_?[^_O_^_OW]_?W]_@`!`@0&"`H+"PP,#`P*"`0` M^_7MYMW4R\.\MK&NK:ZQN<33YOL/(C-`24]03TM$.S0L(QT7$@X+"`8$`@#^ M_?W\_/S\_/S\_/S\_?W]_?W\_/S]_P`"!`8("0L,#`P+"PL*!P0!_/;OY][6 MSL6^MK&MJZROML'0Y/D.(C-`2E!14$Q%/#4L)!X8$P\,"`8$`?_^_?S\^_O[ M^_O[_/S\_?W]_?W\_/W]_@`"!`8'"`H+#`P,#`L*!P0!_/?PZ-_6S<2[M:^K MJJJMM<#0Y?H/(S1!2U!244Q%/C4M)1\9%!`,"08#`?_^_?S[^_O[^_O[^_S\ M_/W]_/S\_/S]_@`!`P4'"0H,#`T-#0P+"08#_OCQZN'7SL6\M:^JJ*>JL;S, MX?<-(3-!2U%34DU&/S8N)B`:%!`-"@<$`?_^_/S[^_O[^_O\_/S\_?W]_/S[ M^_O\_?X``@0&"0L,#0X-#0P+"`4"__KSZ^+9T,B_N+&MJJFKL+K)W/$'&RT\ M2$Y144Y(03@O*"$;%A(."P@&`P'__OW\_/S\^_O[^_O[^_S\_/O[^_O[_?X` M`0,%!PD*#`T.#@X-#`D&`O[W\.C?ULW$N[2OJZFHJ[*^T.7[$24V0TQ24U%, M13PU+"4>&141#0H'!`'__?S[^_KZ^OKZ^OK[^_S\_/S\^_O[_/[_`0($!@@* M#`X.#0T-#`D&`_[Y\NKAV=#(P;NVL:ZMKK*\RMSQ!QLM.T9-4%!-1T`W,"@B M'!<3#PL(!0(`_OW\^_KZ^OGY^?GY^OK[^_O[^_S\_?\``@0&"`D+#`T-#0T- M"PD'`__Z\^OCVM#'OK>QK*BGJK"[RM[T"AXP/DA/4E%.2$$Y,"DB'!<3#PL' M!0'__?S[^OKZ^OKZ^OGY^?GY^?KY^?K[_/X!`P4'"0H+#`P,"PL*"0@%`O_Z M].WFW=7,Q+RWL:VKJZZVQ-;K`18I.45-45)/2D,\,RLE'QD5$0T*!@0!_OW[ M^OGY^?GY^?GY^?GZ^OKZ^OK[_/W_`0,%!PD+#0X.#0T,"PD'!`']]N[GWM7, MP[NUKZNHIZJRP-/I`!8J.TA05%113$4]-"PE'AD5$0T)!@,`_OW[^OKZ^OKZ M^OKZ^OKZ^OKZ^?GZ^_S^``($!0<("0L,#0X-#0T+"`4!_/7LY-O2R+^XL:NG MI:>LM\?<]`LA,T),4E533TA!."\H(AP7$P\+"`0"`/[\^_KY^?GY^?GY^?KZ M^_OZ^OKZ^OO]_P$#!`8("@P-#@X.#0P+"`4"_??PY][5S<2\M:^JIJ:JL\'5 M[`,9+#Q(4%1444M$/#,L)1\9%!`,"`4"__W\^_KZ^?GY^?CX^/CY^?KY^?GY M^OO\_@$#!0<("@P-#@X.#@T,"08#_OGRZN'8SL6\M*ZHI*.FK[W1Z0`7*SM( M4%154DQ%/30L)1X9%!`,"04"__W[^OGY^?GY^?GY^?KZ^_O[^_KZ^OO\_?\! M`P4("@P-#@X/#@T,"@8"_OCQZN'8S\>_N+*LJ*>HK[O,XOD0)#9$3E-44TY' M/CKAV=#'OK>PJJ6CI:Z]T>H#&BX_2E)655)+1#LS*R0>&!00#0D% M`O_]^_KY^?GY^?GY^?GZ^OO[^_KZ^OK\_?\``@0%!PD*"PP-#@X.#0H'!/_Y M\NOAV,_%O+2MJ*2CIJZ\T.@`%RL\25%555),13TT+"4?&100#`D%`O_]_/KZ M^?GY^OKY^?GY^OKZ^OGY^?K[_/X``@0%!PD+#`T-#@X.#0H'!0#Z\^SBV=#' MOK>OJJ:DIZZ[SN3\$RWDV]+)P+BQJZ:C MI*JUQ]SS#"(T0TY3551/2$`W+R?FYN@K<':]`XE.4A26%E644I!."\G(1L5$0T)!0+_ M_?OY^/CX^?GZ^OO[^_O[^_OZ^?CX^?K\_@`"!`8)"PT.#@X-#0P+"08"_?CQ MZ.#7SL6^MJ^GHJ&CK+S2[`4=,4%-5%=644I#.C$I(AP7$P\+"`0!__W[^OKZ M^OKZ^OKZ^OO[^_OZ^?CX^?K[_?\!`P4'"0L,#0X/#P\.#`D%`/OT[./:TLG` MN+"GH9^@I[;+Y/\8+C],5%A75$U%/#,J(QP7$P\+"`4!__W[^OGY^OKZ^OKZ M^OO[^_OZ^?GY^?K[_?\!`P4("@L-#@\0$!`/#0H&`?SU[>3;TLB_MZZEGIN; MHK''X?T6+4!-55E954]'/C4L)!X8$P\,"`0"__W[^OGY^?GZ^OK[^_O[^_O[ M^OGX^/GZ_/X``@4'"@P-#Q`1$1`/#0D%`?OT[>3;TLG`MZ^HHIZ=I+''X?L6 M+#Y,5%E954Y'/C4L)!X8%!`,"`4"__W[^OGY^?GZ^OK[^_O\_/S[^OGY^?GZ M_/X``@0'"@P-#@\/#P\-#`D&`OWV[N;NI9Z9F)^O MR.0!'#)$45E<6U9.13PR*2(;%A(."@8$`/[\^OGY^?KZ^_O\_/S\_?W\^_KZ M^?GY^OO]``($!PH,#@\0$!`/#@P*!P+]]NWEW-/*P;FQIYZ7E)FIP=[\&#!# M4EI=7%=01STT*R,<%Q,/"P@$`?[\^OGX^/GY^OO[_/S\_?W]_/OZ^?GY^OS^ M``($!@@*#`T.#P\/#PT+"`3_^/#GW=3+PKFPIYZ7E9JHO]OY%2U`3UA<7%A1 M2#XT*R,=%Q,/#`@%`O_]^_KY^?GZ^OO[^_S\_/S\_/OZ^?GY^OS^``($!PH, M#@\/#P\/#PX,"04`^?'HWM7+PKFOI9R4D9:DO-GW%"U!4%I>7EI32D`V+24> M&!,/"P@$`?[\^OGX^/GY^OO[_/S\_/S\_/OZ^?CX^?O]``($!PH,#@\0$1(2 M$0\-"04`^?#HWM7,P[JPIIR4D).@M]3S$2M`3UE>7EI32D`V+24>&!,/#`@% M`O_\^OGX^/GZ^_O\_/S\_/S\_/OY^/CX^?O]_@`#!@D,#Q$2$Q,2$A`-"@8` M^?'GW=/)P+:LHI>0C9.CO-KY%B]#4EI>75E22#XT*R,<%Q(."P<%`?_]^_GY M^?GZ^_S\_?W]_?W]_?SZ^?CX^/K[_0`"!`<+#0\0$1$2$0\-"@8`^?'HW];, MP[JPIIR4CY*?MM/S$2H_4%I?7UM42D`W+B4>&!,/#`D%`O_]^_KY^?GZ^OO[ M_/S\_/S\_/OZ^/CX^?K\_0`"!0@+#0\0$1(3$Q$/#`@"_/7LX]K0Q[ZUK**9 MD9"9J\;E!"`W255<7EQ63D0Z,2DA&Q82#@H'`P#]^_KY^?GY^OO\_/S]_?W] M_/SZ^?CW^/G[_0`#!0@,#@\0$1(2$A$."P<#_/7LX]K2R<&XKZ67U1D9NNRND'(SE*5EQ= M6U5-1#HQ*"(<%Q,/"P<$`?[\^OGX^/GY^OO[^_O[^_S[^_KY^/CY^OS^``,& M"`L.$!$1$A(2$0\,"03]]N_FW-/)P+>LH)6-BY2IQ>0#'S9)5EQ>7%9/1CPS M*B,=%Q,/"P@$`/[[^?CX^/GZ^_O\_/S\_/S\^_KX]_?X^?K\_@`#!@H.$!$2 M$Q,3$0\-"@8`^?#HW]7,P[FOI)B/BY"AN]KZ%S%$4UM>75A11SXU+"0>&!00 M#`@%`?_\^OGX^/GY^OO[_/S\_/S\_/KY^/CX^OO]_P$#!@@*#0\0$1$1$0\- M"@8"^_3LX]K1R+^UJY^5CY";LL_N#"8[3%9;7%E22D$X+R<@&A82#@H&`O_\ M^OGX]_CY^OO[^_O[^_O\^_KY^/CX^/G[_@`#!@@+#0\1$A,3$Q$."P<"_/7M MY-O2R<"VK**8D9":KLGH!R(X251;7%I43$,Z,2@B'!82#@L'`P#]^_GX^/CY M^OO[^_O[^_O[^_KY^/CX^?O]_P$#!@@+#A`1$A,3$A$/#`@$_?;MY-O1R+ZT MJ9V2BXN6K,GI"20[3%A>7UQ53D0[,BHB'!82#@H&`__]^_GW]_CX^?K[_/S\ M_/S\_/OY^/?W^/K\_@`"!0<)#`\1$A04$A$/"P@#_O?OYMW3R;^UJIZ3BXN5 MJL?G!R(Y2U==7EM6340Z,2DB'!<2#@H'`P'^^_GX^/CY^OO\_/S\_/S\^_KY M^/?W]_G[_?\!`P8("PX0$A04%!02#PL&`?KQZ-[4R\&VJIV1AX6/I,+D!"$Y M2U=>7UQ63T4[,BHB'!<2#@L'!`'^^_GX^/CY^OO\_?W]_?S\^_OY^/?W]_CZ M_/X``P8)#0\1$Q04%!,1#@H%`/GRZ>#7S<2ZL*.7C(>-G[G:^A@R151<7UY8 M44<^-"LC'1<3#PL(!0+__/KY^/CX^?K[_/S\_/S\_/OZ^??W]_CY^_W_`@4( M#`\1$Q04%!01#@H&`?KRZN'8S\:]LZF=DHR.F[/1\1`J/T]975U:4TI`-RXF M'QD5$0T)!@/__?OY^/CY^?K[^_S\_/S[^_OZ^??W]_?Y^_W_`@4(#`X0$A05 M%102#PL'`OWV[>3;T\K"N;"DF9&/EJG$Y`0?-DE56UU;5$U$.C$H(1L6$@X* M!P0!_OOY^/CX^?KZ^_S\_/S\_/O[^OGX^/GZ_/X``@0&"@T/$1,4%103$0T) M!/[W[^?>USCVM'(OK6JGI.,C)>LR>D((SI+ M5EQ=6E1,0SDP*"(<%A(."P<$`?W[^?CX^/GZ^_O\_/S\_/O[^OCW]_?X^?O^ M`0,&"0P/$1(3%!03$0\,"03_^/#HW];-Q+FMH)2*B)&DP>(#(#=*5EU?7%5. M13LR*2(<%Q(."P<$`?W[^??W]_CY^OO\_/W\_/S\^_GX^/CX^?O]``($!PD, M#Q$3%!44$Q$."03_^._GWM3+PKFNHI6,B9&DP.`!'C9)55Q?7%9/13PS*B,= M%Q,/"P@%`O[\^OCX^/CY^OO\_/S\_/S[^OCW]O;W^/K\_@$%"`L/$1(4%144 M$Q$."@4`^O/JX=C/QKRQI9F.B(R=M];W%B]#45M>75A12#XU+"4=&!00#`D% M`P#]^OCX^/CY^OO\_/S\_/S\^_KX]_?X^?K\_@`"!`<*#1`2$Q04%!(/#`@# M_/7LXMG0QKRRIYN1C(Z;L]'Q$"H_3EA=75E224`W+B8?&100#`D%`__]^_GX M^/CY^OO\_/S\_/S\^_KY^/?W]_G[_?\"!0@,$!,6%Q<6%1,0#`7EI32T$X+R<@&A41#0D&`O_\^OGX]_CY^OO\ M_?W]_?S\^_KY]_?W^/GZ_/X!!`<+#Q(3%186%1,0#0D#_?;MY-O1R+^UJY^4 MC8V7K,CH!R,Y2E9;7%I32T,Y,"DA&Q82#@H'!`'^_/KY^/CY^OO\_?W]_?S\ M^_KY^/?W^/G[_/\"!0@,#A`1$A,3$A$/#0H%__CQZ-_6S,.YK:&4BXB1IDHJ*E:S+[`PH/4Y875Y:5$M"."\H(!H5$0T)!@(` M_?KX]_?X^?K[_/S\_/S\_/OZ^?CW]_CZ^_T``@4("PX1$Q05%102$`P(`_WV M[N77C?U65!'/3,J(QP7$P\,"04"__SZ^/?W^/GZ^_S]_?[^_?W[^OGW]_?X M^OO]_P(%"0L-#Q$2$Q03$A`,"`/\\^OBV,W$NK"DF(V(C)RVUO@7,$547%]> M65%(/C4L)!X8$P\+"`0!_OSZ^/?W^/GZ_/W^_O[^_?W[^OCW]_?X^OO]``(% M"0P/$1,5%144$Q`,!P+[\^K@U\W$NK"CE8J%B9JVU_D9,T=67F%?65)(/S4L M)1X8$P\+"`0!_OSZ^/?X^/G[_/W^_O[^_OW\^OCW]_?X^?O]``,%"`P.$!$3 M%!03$@\,"`/\\^OAV,[$N:Z@D86`AIJXW/\?.4Q98&)?65%'/30K(QT7$@X* M!@0!_?OY^/?X^/K[_?[______OW\^OCW]?7V^/K]``,&"0P/$1(3$Q,3$0X+ M!@'[\^KAV,_&O;*FF8V'BIBRT_45,$5476!?6E)(/C0K)!P7$P\+"`4"`/W[ M^?CX^?K[_/W^_O___OW\^OGW]_?W^?K\_@$$!PH-#Q$2$Q,3$@\,"03]]NWD MW-/*P;>KG8^%A9"HR.P.*D%276)A7%1+03,%(SM.6F!@759. M0SDP*"`:%1$-"@<$`?[\^OCW]_CZ^_S^______[]_/KX]_?W^/GZ_0`"!0D, M$!(3%!04$Q(/"P8`^?#FW=3+PKFNHI2*AHV@O-X`'SE,66!A7EA/13LQ*"$; M%A(."P@$`?[\^?CW]_CY^_W^_O____[]^_KX]_?W^/K\_@`#!@@+#A`1$Q04 M$Q$."@8`^?+HW]?.Q;VSIIJ/BHV=M]?Y&#)&5%Q?75A01STT*R,=%Q,/"P@% M`O_\^OGX^/CY^OS]_O[^_O[\^_KY^/?W^/K\_@`#!0@+#0\1$A(3$Q(/#`@" M_/3LX]K1R+^TJ)J.AXF7L='S%"]$4UQ@7UI324`V+24?&100#`D%`O_\^OCW M]_CY^OS]_?[^_OW\^_GX]_;V^/G[_@$$!PH-$!(3$Q03$A`-"@8!^O/KXMG0 MQ[VSIYR1BXV;L]/U%"Y#4EM>75E123\V+24>&!,/#`D%`@#\^OGW]_CY^OS] M_O[^_O[]_/KY^/?W^?K\_@`#!@D-#Q$3%!03$Q$."@8`^?+IX-?/QKVSIYJ/ MB8R:LM+T$RY#4UU@7UM32D`W+B4?&100#`@&`__]^_GX^/CY^OS]_O[__O[\ M^_GX]_;W^/G\_@`#!0@+#A`2$A,3$A$."P@"_/7MY-O2R<"WK*"5C8R6JL?H M""4\35A>7EM53$(Y," M7UQ6340Z,2DA&Q81#0H'!`'^_/KY^/CY^OO\_?[^_O[]_/OY^/?W]_CZ_/\" M!`<*#0\1$Q04%!,1#@H%_O?OYMS2R+ZSIYJ-@X*-I<7J#"E!4EUB8EY73D4Z M,2@A&Q41#0D%`O_\^?CW]_?X^OS]_O_____^_/OY]_;V]_CZ_/X!!`<+#A$3 M%!44$Q(/#`@#_?7MY-K1R+^UJYZ2BHJ4J:CXF- MG;C9^A@Q15)97%I4340Z,2DA&Q82#@L(!0+__/KY^/CY^OO\_?[____^_?OY M^/CX^/CY^_W_`00(#`\0$1,4$Q,1#PL'`OOT[.+9T,B_M:B:CXN0H;S<_1LS M1E)96UE42T(Y,"@@&A00#`D&`P#^_/KY^/GY^OS]_O_____^_?OZ^/?W]_CY M^_W_`@0'"PX0$A,3$Q(0#@L&`?SU[>3,D!)34U*13XW+B[HX=K4S<2[LJJGK+G. MYP`6*#8_1$9$0#DS+"4?&100#0H(!0,!__W[^OGZ^OO\_?[______OW\^OKY M^?GZ^_S^``($!@D+#`T-#0T-#`H(!0'\]_'KY-[8T&141#0H(!@,!__W[^OKZ^OO\_?[^_____OW\^_KZ^?KZ^_S] M_P$#!0@+#0X/#PX-#`H'!`'\]_+KY-[7T/=U]#'O[>TMK_/X_@,'2HS.#HY-S(M)R`;%A(.#`D'!0," M`/[]_/O[^_S\_?[^_____OW]_/OZ^OK[_/W^``(#!0<)"@H+"PL+"@D'!`'^ M^O7OZN7@V]7.Q;ZZN;_,W_,'&"4O-3@X-3$L)B$;%Q,/#`H(!@0"`/_]_/O[ M^_O\_?[^_____O[]_/O[^OKZ^_S]_P$"!`8'"0H+#`P,"PD'!0+_^_;Q[.?A MW-;/Q[^ZNL#.X/0'%R0M,S4U,R\J)!\:%A(."PD'!0,!__[\^_O[^_O\_?[^ M_____O[]_/OZ^OKZ^_S]_P`"`P4("@L,#`P+"PD'!0+_^_?R[>GDW]K3S,7` MOL/.W_$#$A\H+C$R,"TH(QX9%1$-"PD'!00"`/_^_?S[^_S\_?[^_O[^_O[] M_/S[^_K[^_S]_@`!`P4'"`D+"PL+"PH(!@,`_?GT[^KEX-S7T,K%P\?0W>W^ M#1HD*BXO+BLH(QX:%A(/#`D'!0,"`/_^_?S\_/S]_?[^_____O[]_?S[^_O[ M_/W^_P`!`@,%!P@)"@H*"0@'!@0!_OKV\N[IY>'7@V];2S\_4W>GV!`\8'R,F)B0B'QL7%!`-"PD' M!@0#`0#__OW\_/S]_?[^_O[___[^_OW\_/S\_/W]_O\``0($!08&!P<("`<& M!00"`/WZ]_/P[.CDX-O7U-/6W>?S``L4&Q\B(R(@'1H6$Q`-"PD'!@0#`@'_ M_OW]_/S]_?W^_O[^_O[^_OW]_/S\_/W]_O\``0(#!08'!P@("`<&!0,"`/[[ M^/7R[NOHY.#7P_`<0%AL?("`>'!D6$P\-"PD'!@0#`@$`__[]_?W] M_?W^_O[^_O[^_OW]_?W\_?W]_O\```$"!`4&!P<'!P<&!00"`?_\^?;S\.SJ MY^/?W-K:WN;P^@0-$Q@<'1T<&A@5$@\-"PD'!@0#`@$`__[^_?W]_?[^_O[^ M_O[^_O[]_?W]_?W]_O__``$"`P0%!@8&!@8&!0,"`?_]^_CU\_#MZN?DX=_? MX>;M]O\(#A08&1H:&!84$0\,"@@'!@0#`@$``/_^_OW]_?[^_O[^_O[^_OW] M_?W]_?W^_O__``$"`P0%!08&!@8%!00#`0#^_/KW]/+O[.GFXN#@X>;N]O\' M#1(6%Q@8%A02$`X,"@@'!00#`@$`___^_OW]_?[^_O[____^_O[^_?W]_?W] M_O[_``$"`@,$!04%!04$!`,"`?_^_/KX]O3Q[^WIY^7DY>GO]OX$"@\2%!45 M%!(1#PP+"0<&!00#`@$``/_^_O[^_O[^_O[______O[^_OW]_?[^_O[_```! M`@,#!`0$!`0$!`,"`0#__OSZ^/;S\>_LZ>?FY^KO]OT#"0T0$A,3$A$/#0L* M"`<%!`,"`0$`___^_O[^_O[^__________[^_O[^_O[^_O[__P`!`0(#`P,$ M!`0$`P,"`0'__OW[^??V]/+O[>OIZ>SP]OP"!PL.#Q`0$`X-"PH(!P8$!`," M`0$``/___O[^_O[____________^_O[^_O[^_O___P```0("`P,#`P,#`P(" M`0#__OW\^OGW]O3S\>_M[>_R]OL`!`@+#`T.#0P+"@@'!@4$`P("`0$``/__ M__[^_O[______________O[^_O[^_O___P```0$"`@("`@("`@(!`0#___[\ M^_KY^/?U]/+Q\?+T]_O_`P8("@L+"PH)"`<&!00#`@(!`0$``/__________ M_________________________P````$!`0$!`@("`0$!`0``__[]_?S[^OGX M]_;U]/7V^/O_`00&!P@("`@'!@4%!`,"`@$!`0````#_________________ M__________________\````!`0$!`0$!`0$!````___^_OW\_/OZ^OGX^/CY M^OS^``($!04%!04%!`0#`@("`0$!``````#_________________________ M__________\``````````0$`````````_____O[^_?W]_/S[^_O[_/W_``$" M`@,#`P,"`@(!`0$!``````````#_________________________________ M__\`````````````````````______________[^_O[^____```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````!#3TU-```` M$@`!```W%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P`` M````````````````05!03````:A39#)A``(```````````!%]```!``*`*`` M`'E%]````@`*J8$``'D(Q2LCU@`````@5@`BW@!$]`````%$!P`%]"(`__\% M]"4``_]F]!,`#`!(`0`&`(0``(Q(7@!G]```#``%]"<``_\*J:,``+,*J80` M`)$*J"0,`*4-`2(*J80``+-A]```!`!']```#@`-`+4BK@`@`'0.D)X-`3X* MJ80``+,-`2(*J80``+-A]```!`!']```#@`-`+4BK@`@`'0.$*P-`3X*J:0` M`)<*J`0```0*`*```.9"@0!(@@!$]"`___]$@T9(`49$]````"!$]$```_\A MT@!6@0`&WR!'!B-$]$8`#`!%@T`$"```````"0`C`````````````````'@` M```$``0```````#\`/___X`````!`0`&455N:71S```````````````````` M`````````````````````0(`!B!S86UP````%9N(&EN=&4@9&5L87,@9IIR````'@```!6`'&XO!RF````'`!6``!7 M```````#__\````\```````$ M__\```!:```````````````````````````````````````````````````` /```````````````````` ` end nethack-3.6.0/sys/share/sounds/wdnflute.uu0000664000076400007660000004724712467321052017613 0ustar paxedpaxedbegin 644 Wooden_Flute M``Q7;V]D96X@1FQU=&4````````````````````````````````````````` M``````````````````````````!!249&4V0R80$````!%````````#8B```! MSJ<]K;"G/:VZ``````````````````````````````"!@1V.``!&3U)-```V M&D%)1D934TY$```T'@```````````````````````/____________\````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````$!``$!``$!`0$```$!`0`!`0$! M`0$!`0$!`0$!`0$!`?_^_P#__P$!`/_]^OG^`0,*#0@)#0@#`?\!`P0%!08% M`/SZ^OCT]/CZ!`P"]_W_]_3V_PH-"0+\_?[^`P(`__L&&A,&!P4`_@(-%142 M"/SQ[/#[^^SF[.WGZ.KEX^CFXNWY^_\*!?G_!/X*&AL4#P\1#P<`!@P%^.KH M\_3FWN7EUY];5XN3E\?GS^`D-"Q4G,2\Q-3(L*RXF*#H_,QX4&Q3ZZ^SIX.#= MS,?1SK^YOL_C[?D-&1L:&"$O-3M"0D5,0SI(6E`^."T?&Q0#[^'5R,3$O;V_ MKZ*HNY ML;*\QM3A]`L,#"<^3%I0.3=#1DQE;E];5S\E$__KY./6O[:VKJ:ML:*5FZJY MSN;U`0L1$Q,:*#I/6%%,3E5>75-%,B,@'@X`_>W2P[6GL;VUL;2RM+C#V.7L M^/\%$R4X0$5.2T%$2#X[361;/#`O'Q02^]"ZP,2ZN,#"N*^FG):BR>WR[P$7 M%A0M/S8O-#],6&EY=V=)(`D1'A<*"?O7PKZYKZ2>I*BDKLO1S.#PXM7>]0\M M3EY22$4W*"TU-T-*0"L?(QH&[DYVQP]#7V^@"&"`C*"@@ M'"4O/4U35U,[)2$>"O7S\^#1U-3%NK:NHYR9F**ZSM7AZ^/644T*!T%Y,_,T]C=Y=W`JZ>DH:*NQM_P_/X#'"P>$AD?*$1@9%E34TDW M,#,N)1X3`_'HZ.'.OKFWL;6ZM+7$S]?F\O7W_@P<*3`W/4-,2T9`,BXW/#0L M+S(F%/G4O\;.S/=Z?'ET+^UM+BPI:K`UN+N]O/U!108$0D3*#M!.S8X-"@B(2$K+R@B$_OP MZMW3QKJWM[F^Q,.YL;.]U.SZ!Q`6(24A'1TG,S(O,T%/3D`U*QT1"0#QX-7; MX=6^M+>XMK*NM<+*V/`!"!0;%A`,$"$T/D)!/#Q#0SPR&P<#!`D/`^C1P[>O MKJ^PM<#%O[O(Y?;X^_KY#B\],2HS.#(L+S4X0U)--2XO\K.P[BTL;?) MW.KS^/H"'3Q%-B8D)!P6*$A64U1+,QP2#@/SZ^;?V];/R<:\JZ.IM;[,Z0<1 M!O\#"!$A-#\_/3T_1%%93CTW+!H7'AP0^M[)N;*YP\"VL[.SM\#0W^+I\_,` M'2\W/SXL'"$S04E/3D4^-BLD&PX%\]K,S<_/S,6WJZ>LM,#6ZNSP_PH(#",V M,RHG+C8X0E%00S@O(!PC(!``\=O&PL?*Q;RSJJ*HNL3*W.;=W/41'"0M-S4H M*#8\/4%$/"\J*RHJ(Q+XW\_$OL++SL2WL:JGK\#+SMGO_P0-("LF(1T:)CE" M2DY%/38K)RHF&A(%Y\[.U-#%N*ZKIZ>PM;?"S='8Y?@+%QT?'!XK.CX_14,Z M-S0J*38]+`SSY]W1Q\;+Q+FXM;"UO<3*R\W9[PL>(A\>("`@*C0]148_-C0[ M03LI&`CSYN7AULS%P;ZTJZVRM+S$P\KA^PP3%QH9'2HO+CM/4$$^/38X04,Z M)1$$_/#;R+^YM[>TLK6ZNKBYN\'3[@88)"@H*"[J MW\J[N+:OJ[&YNK2RNL35[?P!"A@B*C`R-3]#/3TL:ZKI*2O MNL?7W^K_!@$.*#8_0CL]1$%!2U!023PS+R06"?GFS[ZZO+RWLJ^HI*2FK\'. MV>S[_P84(RTT.CT\0$=/55%(2$0V*24?$O_FS\&YM+2ULJVHJ*NLL+W,V.'H M^1$@*#8^-S(]2$='4%A734`Y-BXA#_GJVL>_P;VVM+.MIZ:MO,7*U.'O_@\B M,38Z04,_04]=75504$U$.S$C$_[FU,K!NKN_MJ>AIZVML;[,UN'M_1,D*"X[ M0D!'5%A555E63$5`.SDN%/WMUL&^O;2NKJZLJ*:MM;K`S=OJ_A$A+S4U.4%% M2$]87EI134U(0#4E$?WLW,W`N;>RK:FFI:FPM;B\Q=/H_A$?*#`W/D)"2%1= M6E-,24I(/B\@#?KJV\_&N[*MJ:*>HZRQL;:_QM#B]0<;+#4W.T%'4%-03U!2 M4TU&0C8A#O_IS\;)PK.JIZBGHZ2LM+:[Q=3F^@\A)R@P/D=)3%):751+2TY+ M13DB!_?QZ-;!MK2RJJ.AIJVRM+6XO\[F^@40(C<^.CY*45164E%345)42#$= M%`;MV<[*Q[JII*6FJ*BLL;:]Q]+<[`@A+"TQ/4I355)-35)45%122T(M"N[F MYMO*OKFVKJ2@HZ2GK[B\P,WE_0@*$B,S/T=.55I844E'2U%643PG&0SVWL_( MP+:OK*JHJ*JIJ*FQOM'F]P,1'2(J-D)-65Q33E)64U%12CHI&PS^[=W,O;&G MI*JNJZBHJJRON,S@\P42&B4O.TA/3DY25%-56EI52SHG%PT"\^+0O["LK:FI MK*NIJJZTOLS=[?X.'"4P/DA04TU+3E%67V)92CLK'0[_\^;5P[2LJZRMK*:D MIZJPP-'>[O\'#QXN/4I14E%.35-;7UI01SDI(1L/_>;*M[.MIJ:NL*BCI:FN MN,;6YO+_%"HX/4%%1T9"151@965803(L(1(%^>[;PK.OJZJJIJ*BHJ:RP,G1 MW^[Y!!DS0TM.2D)$3UE>8&!:3D`P(Q@/_N;.OK:OK*RIHIZ>H*:MNLK6W>;T M"1XP/4)(44Y&2U5:7%U82#@U,B$,^>/+N[.OL+*OI9Z=GJ&LOH*BRN\/+T]WP"24Z03]! M1TI)35EB85I23$4Z+B02]=K)PKRVL;"KGY>6GJBPN,?4V.'T"B`R.T1,24E6 M7EU=6E-12T%!/"969E M74]$149!.BP8`.3/Q+JQK:FBGI^BI:JQM;:]S-[X`.SI`0DA58FAD8F%9 M3TI$-!X*].#5S,.[L:6:E9>:H*NTN+J]R=[V"AXR0$5#1U1>8%Y;6596659+ M.B0-]-_0QL"\M*B=FIF9GJ2JK[;"TN'T#"(O,C8_35]I:&1A6$]/5%1,/RX4 M]=_7S+ROJ*2@G9VAHZ6FIZNUQ>($'2@M,3="2D]<:VQD86%=6U=&+1@)_?#D MU<.VJYV3D9:=I:NJJ;"XQ-KU"ADK/$1)5F%B7EM97&%C8UY/.2(+]>7Z MK*"9FIJ8G:2CI:^_S-WT!A0C,3Q+66-H9EY85EA<7UM202<0_NS8RL*WJ:*? MG9ZAH9N9GZFWS>?["18B*S5!45UB9F=D8U]=8%A%,2`1"`#OVL:RHYR:F9R? MHZ6CHJFVP]3I_!`@+T)25UA<7%=35F!L;F!,-R,1`/'GW,FWK*2=FYZ>F9>; MHZV[S-CD^@P6)CQ.769B5E-87&!E95]20"P8!_KLV<2TK:JEGY^?F9*4GZJU MR>'O]?X,(SM)4%MC86%C96=D7%A0/2TI(0GLUL.SIZ"@I**?GIJ9G*.PP,[@ M]0L?+SQ*4E945%MF;7)P:%Q+.2TD$P/XX\FXK*2CH)N9EY27HZRRO3D$T)`[QWM7,P;:KGY60D9*6GJFRN;[$S^D*(#!`3E9;7E]?86-E M8EI:6U-"*@SRX='"N;*LIJ"7D(^4FZ6KKKG*W/`%&2P[1$M25V!M<&5=7%Y? M6TX\*1D$ZM3&N[*JHIJ4E9F;G)VAJK?#U>T"%BLW/49066!D9VEF9&-=54Y# M+18"[MS,O[6JG9:7EY.5G*6IJ[+`T^C\#B4[1DI586-?865C7%QG:EI#+QD" MZM?,P[:KIJ2?F).3EYN@J[G&U>G_$1LE-D=37VIM:&)?8F1@651+."`(].32 MP+2KHYN7F9N8E9FBJ;&]S^;\#APJ.4=5865E9F5I:V5?7%E-.B,+]N75P[2I MHIV9F9F9F)F=IJZYR^3["18H/DI/5EQ?8V=H:6AG8E1",2$._N[6Q+BKHY^: MEI>7E9B?IK&^R=GO!1@H-T9/56!J:&5H:V=A6U5+.RH7`.K9R+6FGYRHJJVQ]KM!!DJ-T966U=99G!N;6UF7E5(."H:!>[:R;BKI)^\@VOL/4\@P?,3]* M6V9F96IQ<&QI8UI22CXE"O;DT\&OI:&;E9*0D).9H*:JL2S,@$@#HT<&VK*&9E(^-D)69G*.LM<+2Y@$:+3U+56%L;FQN M;6=I;FI>3STG$/CDU<6XK)^6DY&/CHZ2FJ.LM\31Y/P/(CA+661K:VIN<&MI M96%?5T,L%/WHU<&RJJ.'%H96=E5T,Q(`_Y MW\BWJJ*=EY&.CI.7EY:?KKW-W.T$'C1#351B5D@R'P_XWLF[ MKJ2;E)&3DH^,D)JEK[K'U>P(&B,V4&-I:6MU>'!L:V-=5THY)`[YYM.[J)^< MF9:2CXZ0E)>4T8S)!8!ZM&YK:B=DY*2 MD(^0D)>AI['!T.;]$BE`3%5A:FYN;W)V=&QD5D0X*!'^[=6_M:F;E9*/CH^/ MD9:?J[?!R=GV$R8W35]H:FIMA MIZV[TN;V""(Z2U5<96YP='Q[<&AD74\[*!P/]=C#M:NBFY:1C8Z1DY.:J+>^ MQ-7Q#B,W2%)<9VYS=7-Q=G1C44E%.2`$\-_*MZFAG)6-CI*0CYBAIJNVQMCN M!ATV2UE?9&AJ;W=Y<6EE8UQ%+AT*\-G)NJ^GGYB2BXB-DI:;HJV[QM3I`1HP M/TQ98VQS=7)P;FEF85-%.B4+]-[*N["HH)>0CHR-CY.;I*RUP-'H`!79R;6AE7U9-0"D.^N3,O;.HGI:2D8^.D)28G:>SP=/F_!S4PK>MH)22E)&0DI.6G:6POLW@_!0C+T!48FMQ=7=W;VAH M95U00C(:_^O9QK2HH)N5CXZ1E)24EY^JN MT<&QIYZ5D(^0D)"2F*&KN,G9ZO\4)3=-86YSWEP;&I>2C@K&@3OVL2SI9V;F92/ MC(V0DYBDLK[-X/(%'C=(56!I<7)O6D8Z, MCI>DK[G'WO4)'3-&4UQC9FQV?'MXG_&31*5U]D:FYR='5W=6M>4D[LJB>EI.0C8N-DIFCK;7" MU>?\&#)#4F!I;&QQ=W5R;FID64LZ)Q+YW\NZKJ:AGYJ1C(R,C9*=J;?$TN@# M&2D[35998W)^?WMY_KZ:I*ZZR^7_&#)" M25=C8F1N=7EY=&MC6DHW)Q?]X=+'N*NCG)2.BXR.D9>>IK"\R-OX$B=I*RVP]7L`QPU2%):9W-V<&UN;FUI M9%M+-B`([]G(P+BLGY:1CXZ,BY"7H*RYQ-7O!A4E-DQ@;71U[8Q+6FG)B3CY"1DI26FZ2PO<_D^Q8K.4I;86-KS: MRKNMHIJ6DH^/CX^4G*:QO=#H^@D=,D)6:&YO<6]N<&QF8%I00B\9!?/=QK6L MHYN9F9:0CY*3EI^MOM'D]PPA,T%,5V5N,D116F!E:FYU>G9M95Q-.RH<"_GHUL.RIIZ:EI", MCY*5G*6NN<33Z``3*D=97&%I;6YK9VIN:%Y52#@C#?OFSK^VK:6@FY>3CXN/ MF**MN,35ZO\3*3U+5F-H:6QP3CXV0EZ"K MN,//X_L1)SU.6%M@:W%R1C8R.E9^KML#+WO@0 M(2\^46%H:W!U=FYD6U--3$DZ'@#KW,NYKJFDGYJ4CY"4F9VBJ[K/Y/<,'S)$ M35%=;GAY=FYE75I73#\T)Q+WV\:ZM:^CF965EI64E)FBK+G'V?85*#4\0DY@ M:W%V=6]L:5U334,R(`OTY=?&N*ZCFY61D9*4F)ZBJ;7&V_,'%R@Z2UAA;75W M=&QC75Q<54DY(PW[ZM7$N:VCFY:4EIB7EIB=I;+$V>X%&BHW1U5>:&]Q<6QF M9FA@440V)Q+ZY]O/O:RCGYN5DY25DY6=J+/`UO,)%2`P0%!>:'!U<6MJ:V18 M3T:&UM:VAD96AE6$0R M)1D'\MW-P;:HFY:7F9J8DY*8I+/!S^/[$2(P/4M>:VUH9VYO:F5@5D@U(1,( M^NK9QK&BG9^?F).3E9B=I;"_T>/S`1$J0U9?8&)J;69E:&1=5T@T)!<-`NK/ MOK:LHYV:F9B5E9::I+/!S=GI`1PP0%!=9FEE865J;6YE44([+QX+^>C8R+BM MI:&=FYB1C).?J;&]RMGL_@XC/E)<8&-E:&UN:61;4DD]+!T2!O+4EYB_>J;.ZQ-'C^1`F/4]87%M=:'-T;6=A54<]-"H:!?+@S+VUKZFBF9.3E)>? MJ+&YPL_?\PLE/$A-5V-G:6]P:F!53TU$.3`A"O+;HJRV MP,W?]0HA-T%&359E<7-O;&1634E"/#,?#/K@RL*\LJFCG)>6EI:;I*RRNLG= M\08>,SU&4%ME:VUP;6)74$I(0C`?$?G@T\F]LZVFG9>3E)J?HJBSO<;6[P<9 M*#9$3UIE;'%P9EM644Q)13HF#_KGULB_N*^DG9J8FIRMM<7;\P@8)3,_ M2%5C;71R:&%:4D]+/S,F%`#PX,_!N*RBG9N:FY^@H*2JM,/4ZP09)3`\2%5B M:6UM9V%=6%%+0S4C$/[RZ]K&N:^CG)J:G)^AHJ2HL<#2Z@$0'S`[1E5A96IL M9V%<55=81"XB$P3Z[-K,OJ^DGIJ9G:&BHJ&EL\32X?,)("TU1EID:6AC8&!@ M7UQ1034H%@;XZ^#1OZZEH9V?H9V:G:2JLKW-Y/H)$R(W2UA=8VAE9&5A6UA4 M2SPF$@D"]^;/O;.LI:">G9^AGZ"HLL'3W^P`$R0X2U1;8V9E9&)@85]51#,G M'Q,#\N+0P[>IH*"BHI^;G**IL;[-V^S_$2(T1E9A95];7V=I9%M01CTN&0L% M^NG7Q+2MJ:6AG9R3U!QPU2%5=75MD9U]:7EU523DI)!D%].31 MPK>OJZBCH)Z;FIZGL\',UN3R!1XP/4]965UF96!@7E9.13HN(Q@*^^C0P+FR MJZ>EHI^ MGJ.JL+O*U-KG`!PP.D-.5EU@8&5H74]+1SPT,281^^C:S<*XLJ^LI9^>H*.J ML[K!RMOU"A0A,T%)45A>9FIE7%)'0D$],B(2!?3>S<.\MJ^II**BI*>JK;6^ MRMON`18J-CU"2E5?9FEG7%%+13XY+R(4!._?U,G`MZVHI:*AI:JLL+6[QM;I M`!6%%+2DI#,1\3!O3EVL_&N[&KI:&FJZNJJK*^R=7I_@X=*S9` M2U-<8V-;5%143D8[,",4!/?NXM7*NZRFIJBIJZRKL+6XPM3H_`H9*3=#3UA; M5U596U=034Y&,A\/`??PYM?)O+2NJ*2DJ*NMKK7`R='?\@02(#5)45-:7U=. M3E!36%%"-RD3`OCLX=?,PK>NK:RII:*DJ[6_R]OG\?T*&"L\3%MD7U135E!* M24<]-BX>#@'RW]#%N[.PL;&PJZ:FJ:ZVP];G]0(-&BT]1$U75U9865A43TE` M,"(:$P?WZMC&O+:RKJZOK*>GJ["ZR-/=[/P,'3$_1TU14%!76EA75$IKK6^QL_;ZO8%&B\^2E)245185U943D=!.2XB%PS^ MZ=/&P;ZYM+.PJZBGJ;*]QLW:[?L('C(\049+4%576U]=4D,V+RPF&P[]Z]S. MP+JXM;&MJ:JNL+2]P\C3X/,-(R\Z1$=$2%)965A744<_-RLA&@[YYMK3R\.Z MLZ^KJJJKL+>]P\G3X.\&'BXU/$9,35%765A324`[/#DL'`[ZX];0R\.]NK2L MIZFNL;2YP,G6Y/4(&B8O.D%$35EA7U5*1D([-S8O(A']Z]_4R<"\M[*RL:^P MLK>ZN\'.X?@.'2DS.#M!2E!66EM73$`_0#@I&`G\\.3;UL`%B@Q-C]-5%974DI'1DE-1CDP(0KWZ=_;ULO"O+*LL+"LK[>[OL// MXOD(#AK9S\K!NK6PK[2WM[2QM,'0W_0* M%!LG,#=!3%%35%)/24=(0C0H'1#_\N_IVLJ_M:VML;.UMK2VO,/+V.T`#![DV\_"NK6UM+.RL;"SN\73Y?+[!0\9*#E) M5E=22TA(1T5$0SPQ)!<+_N_BUYM[6SLK.YP,3,V>;O^@D9*SU*3$=#0D-+44U) M0SLR)Q@/"/WKV[O;_$S]OE^`\@*"DO-SD]25!23T<^.C8Q*R@@$0'QY-S6SL7` MNK2WO+N[P,3'S-7C]@<7)S$P,SU$1DI+2$4_.C@V-"P=#`#RX]S:T';T<>_N[NYN<#" MP+_"Q]+E^@D7("8M,#4_1TQ.24)`/3@T+24<$`7\\N?=U,BYL;6_P\/!P<+! MQ-#?[P(6)2PM+SI%1$!!0D-$0S\[,B48"_SS\_+FU[@T_?T?U!!`;(RDV04%"2$8Z,2LG+#(M(AH0`?/MZN38S3>TL.ZN\#&R\S+R\G+ MU^?U`0X;(BG?U,?#QL;&R,;!PL?2X>OR_P<%#B`N M.TE)03LV,C,T+RDD'1D2!P($`>_9RLC*QL7)R<3!PL?2WNCU```"#R$S041" M/SLU,30U+RPI&PP-$P\$]NG>U&QH4$P\#^.S:T<_*RL[+P;V_PT]#-R\O%P<+`Q-/9UMSEZO0%%"0X.C0T-3@^04`\+R(:%A<9 M&1,,_NOAW=?3S<*]P,#`R]C:UMCSHY-O5TL>\N+K!RM#6V]S:XO(!$"0R,R\P.$%%0CTU*1X9&2$B&A(+^>CC MY.3S;RK^ZNL') MS<_.SM+9Y?,"$1<8'S`_1DE)034I(B,F*2DF'`X!^/7V\>37S<2]O\?,S,G% MQG6Q+V^P,7-T76QL#`P\C+R,;%PL;6[?G^ M!`8-'"X[2$]'.3$J)RDM+BD@$0@+"?[Y].?5QL+%RL[*Q+VZO\S=[??^!`4* M%R@Z1TM(/SO9S)RDA%`?]]_'K MY=[0O[>YNK[)TM+,Q\G7ZOL,'"4K,#,Y0D4_.#$G)2@L+2@?%P?V\/#Q[.'2 MQ;VYNL#%Q\?)SM;=Z/P0%Q<<*3=!1DE)03`B(B0B)BPJ'`K^_/?LX-?/R+^[ MP\O*Q\2_O\K<]`@-$AXB(RTZ0TM)/34N(R8P*Q\;%P\'`?SW[MO&N[R^P,K3 MSL/!Q#-P;_!P\3%PL'$ MR='=[OP"!0X=*C1"3DH\,R\I)2DM+2H>$@X,!?GOYMC)Q,7'R[Y M!A0A+SQ"0#DQ*BPS.#@Q*20;#`0'"@7[[^'0QZ.WN\P4> M,3]+2STT,"LG*2XR,2L@%1(0!OOPX]G6U]#(Q\.[M[B]Q]?EZ^_U^P,2)39! M0T`^.C,O,C$J(1P;'A\:#P'SY=;/SLS,R\?"O+J\Q=/#6RLC)Q<&^OL#%S=/7W./K]00<,3U`.3,W.30S M,RTH*"8D(1L5$0/NXMS:W=C*P\.]M[C`R=#8X^GK]@P<(RLS-SU`/3L].2TA M&APA)28A$P#S[.'6S\[/RL*_N[S%R\K-U>'Q!`\4'RXU-#4Y/3]`.B\E'QX? M'QX<&`KV[.?=TLS(P+W`P\7'QLG0U]GA]PX=*3(V-S0S.C\X,#$Q)B$D)R09 M!_SZ\>7BXMC'O+N[N;[(R\S0T]OJ]P$0(RLO-CH\0$$Y,2PD(2HL)"`<$@;[ M\.GCV=#+P[NZP<7%Q,7*T=GF]@85'R4N.#HX/#XX,R\L+"%Q$&^O7PW\S$Q,;%P[^\ MP,7$Q]3C\OX(#18C,T!#.S@[.#`M*RHM+"8B&0T(!_OHVM/,R,._P<7`N[W# MS-7A\/H`"ALH+SA`1$,Y+BPM+S$P+"+#<_0SXX-C4R,3`I(B$A'QH0!O_RW,W)RLC#P[W"1LC M*#$\/S@Q-#DV-#$K)R0B(AT2!?SSYM;-S,W)P+JXN+S#Q\W8XN_^!@P:*C0X M.#8X.ST\-"#_[QY-G1R<7$P\"^O\"]O3R!A@D*R\R-#8X M-S8W.#4O)B`A)!X6#P+TZ^+5S,7`P;^YN;_'S,O,UN/O`18C*C(U-34S-3HZ M-C$L*BPK(A@2"P/YZ^#;US\.^N[N^P<#"QL7(T=WK_@X:)"PQ-CDW-CDV-#0Q+RPI)B$8 M"@'_^>O=TLW&NK2XO<##Q<;+T=WN^@,1'RHS.3L]/#DT,"PH+C@W*R(<$@3U M[.WGV=#)P+R[N[R\N\',V>3N^P8-%1\I,S]&1#DS-3,L)B8N-"T?$PK_]>SB MULW%P<7#NKG`P<#&S]ON_0()%R,J,CL_/#@V-3$N+C`R+2`8%@\$^^_CV\_$ MP;ZYO'AL1`?;QW\K&R,;%P[VYNK[%SM;< MYO8$#A4>+#H]-2\R/#\W,"XH)R8A&QD5#/_KUWT`!4E*2PO M,#,Y/3PW+BOW``L8("$D+#4W-C;U`0D0%!DF,3$M+2\M)2`E*RXI'A41 M"?_\_//DV]7,QLC.TM'-RL_9X>CT_@$%$!LB*2\V-RP?'2(E*"HF(!H1"03] M^//IW=+,S-+2T,_-S,_7X.OU_0$$"A0@*S,T+R@C(R,A)"@F'QD5#@)RTM*2&101$@\&_?7KX-G6V=O9 MU=+0T]C>XN?O]?K_!A(@)R(!\>'R$>%A$4%Q@7%0\'_O?Q[>GHY^3@W=S>X>/CY.;K\/;^!PT1 M%A84%QXA(1\;%Q43$A,5%`X&`/GT\O#JYN+>WN'CX^7FYN?I[//_"`T/$1,6 M&1L;'!P9%105%185$0H#_?KY]_+LY^/AX>'BY>CGYNCL\/?^`@<,#@\3&1P< M&QH6$A`2%!84$`P&`?SX]?/NZ.7DY.7HZ.;GY^CJ\/D`!`8)#0X1%1@;&Q@4 M$A,3$A,2#0@%`P#]^?3MZ>;EY>?JZ^KIZ.GM\O?[`04("PX3%A86%A01#Q(5 M%1,0#`@$`/[]^_CR[.GHZ.GK[.KIZ^WO\OC]_P`#"`T3%185%!$/#A`1$1(1 M#0@#`0'^^O;R[NWL[.WN[.KJZ^WR]OK]_@`#!@H.$104$A`/$`\/#PT+"0@' M!0+^_/GR[>SM[_#P[^_N[>[R]??Z_@($!PL/$`\-#0X.#@\1$`T*!P4#`P(! M_?CU\_#O[_#P\._O\?/T]_KY^OX"!@H-#@\.#`L+#0T,#0T*!P<&`P'__?GV M]//S\_/Q\?'Q\O3V^/K[_?\``P<*"PL,#`L+#`L*"0@'!P<&!0(`_?GW]?7U M]?7V]//S]/7V^/K[_?\!!`8("`@("0D+"PL)"`<&!00$`P,!_OOY^/?V]O;U M]O;V]_?Y^OK[_/T`!`8'!P@'!P<'!P@'!P8%!00$`P'__?S[^_KY^?CX]_?W M^/K[^_O\_?\``0,$!04&!@8&!@4%!`,$!`0#`@$`_OW\_/S[^_OZ^OKZ^OK[ M_/W]_O\``0("`@,#`P0$!`,#`P("`@("`0$`__[^_?W]_/S\_/W]_?W]_?W^ M_O\```$!`0$!`0$!`0$!`0$!`0$```#___________________________\` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````!#3TU-````$@`! M```T%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P`````` M````````````05!03````:A39#)A``(````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`H`````````````````````````````````````````````````````````` M```````````````````````$"```````"0`C`````````````````'@````$ M``0```````#\`/___X`````!`0`&455N:71S```````````````````````` M`````````````````0(`!B!S86UP````%;_^?_[__S_^__\__S__/_]__W__?____X````"``$``P5& M;'5T90(```!!249&4V0R80`````````````2J0````!!249&4V0R80`````` M`````````````````````````*<]K;```#8B```!S@"*`(``@0!T`&$`5P!' M`#X`-P`U`"X`'P`A`!``#``5`!<`'0`8`"(`*0`P`#,`-`!"`$@`/P!#`$4` M0``R`"X`-@`F`"``)@`<`"``)0`B`"(`(@`@`"D`,``D`!X`&0`-``;__O_V M__W_^O_S__;_^@`&``T`#P`8`"(`*0`O`#H````:`"D`#P)J`S$`*@`#`FT# M/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0`````````````````: M`"P`%@$^`=P`*@`#`FT#/0`````````````````:```````````````````` M``````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7```````#__\````\```````$__\` M``!:```````````````````````````````````````````````````````` ,```````````````` ` end nethack-3.6.0/sys/share/sounds/wdnharp.uu0000664000076400007660000004164212467321052017417 0ustar paxedpaxedbegin 644 Wooden_Harp M``M7;V]D96X@2&%R<``````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``$X`10```````"XB```! MSJ<]K8^G/:V7``````````````````````````````"!@<\@``!&3U)-```N M&D%)1D934TY$```L'@`````````````````````````````````````````` M````````````````````````````````````````____________________ M________________________________________````````````_____P`` M`````````````````````/_________________^_O[^_?KX^/T!`O_[\-[, MP;R\OL"\L:>OQ=37S\6]M[2VN\''S=/8WN/GZ^_Q]/D`"A8B+SM$2U%776%E M:6UOX./H[?7_"10>)RXS.#Q`1$A+3E%25%9865I; M7%Q=75Q;6E9/.Q+Q[/+[!`P3&A\A(!T8$@G^Z\.:BX^6GZBOM[N]O+JWM;2U MN+O`Q,C+SM'4U]G;W=_BY^SU_P@2&R$G+#`T.#P_0D1'24I,3D]045)34U-1 M3TL_)@/NZ^WQ^/\&#A08&AD6$0G^ZLBEE)*4F)ZEK+*WNKN[N[N\O\+%R,O. MT-+5U]G;W-W@X^CO]P`)$1D?(RWM[_+W M_0,)#A$2$`L!\=K!K:6BH*"AHZBML[B]P<7(S-#2U=?9VMKFIJ>KL+6[P<;,T-38V]W>W]_@X>'BXN/DY>?J[_3[`PD0 M%AH>(20G*2PN,#(T-C;FY^GK[_3Y_P8,$A<;'R$D M)B@K+2\Q,C0V-SDZ.CDV,"<;#0'X]//S\_3U]OG]`@<+#`L'_O'BTL6]M[6S ML;"PL+.XO<3,TMC>XN7GZ.CHZ.CHZ>GIZ>OL[_/X_0,)#Q49'!\A)"8H*BPN M,#(T-3KM[_#P\/#P[^_O[_#P\O3X_`$&#!$6&AT@(B0F*"HL+C`R,S4U-3,P*B,: M$0D"_?OZ^OO\_?[_`00'"@L*!@#W[>+8T,K&P\+!P+^_P<3*T-??Y>OO\?/S M\_/S\O+R\O+R]/7X_``%"A`4&!P?(2,E)RHL+C`R,S0T-#(N*2(;$@L%`/W\ M_/W_``$"`P4'"0L+"`/\\^G@U]',R,;%Q<3$Q("(E)RDK+2\Q,C,S,S$M*"(;$PT'`O_^_O\``0(# M!`4'"0H*"07_]^[FW=;1S?L\?3V]_CX^/CW]_?W]_CY^_X!!0H/ M$Q<;'R$C)B@J+"XO,3(Q,2\K)B(;%0\*!@,!``$"!`8'"`@)"@L+"@@$__CP MZ>+;K\/3V^/GY^?GY^?GY^?GZ_/X!!0D-$A8:'B$C M)2@J+"XO,3$Q,"XK)R(<%A`,"`0#`@($!0<)"@H+"PP,"PH'`OSU[N?AV]?4 MTM'1TM/5U]G=X>;J[_/V^/GZ^OKZ^OKZ^OK[_/X!!`@,$!49'2`C)B@J+"XO M,#$Q,"XK)B$<%Q$-"08$`P,$!@@*"PP,#`T-#`L(!/_Y\NSFX-O7U=/3U-77 MV=O>X>7I[?'U]_GZ^OO[^_KZ^OO[_/X``P8*#Q,7&Q\B)2VMC7U]?9V][AX^;I[._R]/;X M^?KZ^OKZ^OO[_/W^`00'"@X3%QL?(B4G*2LL+"TL*RDF(Q\:%A(."@<%!`0$ M!@@*#`X/#P\.#0P*!P/_^O7PZN;BWMO9V=G;W=_BY>?J[.[P\O3V]_?X^?GY M^?KZ^_S]``,%"0T1%1D=(20F*"DJ*RLJ*2_Q\O/T]?;W^/CX^?GZ^_S] M_P(%"`P0%!@<(",F*"DI*BDH)R4B'QP8%1$."PD'!@4&!P@+#0\1$A(1$`X, M"08#__KV\>WIY>+@WMW>W^'DY^KL[O#Q\O/T]/7V]_?X^/GY^OO]_P$$!PL/ M$Q<;'R(D)B&Q@5$0\,"0<&!00$!08("@T/$!$1$1`.#`D&`__\^/3P[.GFY.+AX>+D MYNGL[O#R\_/S\_/T]/3U]O?W^/K[_/X!!`8)#1$5&!P>(2,C(R,B(1\=&A<4 M$0X+"0<%!`0$!`4'"0P.$!$2$1`/#0H(!`'^^O;S[^OIYN3CX^/DYNGL[O#R M\_3T]/3T]/3U]O?W^/G[_/X``@4)#`\3%AD='R$B(B(A(!X<&1<4$0X+"0<% M!`,#!`4&"`L-#Q`1$1$/#@L)!@,`_/CU\>WKZ.;EY.3DYNCK[?#R\_3T]/3T M]/3U]?;W^/GZ_/W_`@0'"@X1%!<:'1\@(2$@'QT;&!83$`T*"`8$`P("`@,% M!PD+#@\0$1`0#@P*!P0!_?KV\^_LZNCFY>3EYN?I[._Q\O/T]/3T]/3T]?7V M]_CY^_S^``(%"`L/$A48&AP>'Q\>'1L9%Q01#PP)!P4#`@$!`0(#!0<)#`X/ M$!`/#@P*!P0"_OOX]/'MZ^GGYN7EY>?IZ^WO\?/S]/3S\_/S]/3U]O?X^OO] M_P$#!@D,#Q(5&!H<'1T='!H8%A,0#@L(!@0"`0`````"`P4("@P.#P\/#@P* M"`8#`/WY]O+O[.KHY^;EY>;HZNSN\/+S]/3T\_/S]/3U]O?X^?O\_@`"!0@* M#1`3%A@:&QL;&AD7%1(/#0H'!0,!`/___P`!`@0'"0L-#@\.#@T+"0<$`?[[ M^/7Q[NSJZ.?FYN?HZNSN\/+S]/3T]/3T]/3U]O?X^?K\_@`"!`<*#`\2%!88 M&AH:&A@7%1(0#0H(!0,!`/_^_O\``0,%"`H,#0X.#@T,"@@%`P#]^?;S\.WK MZ>CGY^?HZ>OM[_'S]/3T]/3T]/3U]O?X^?K[_?\!`P4("PX0$Q46&!D9&1@6 M%!(/#`D'!`(`__[]_?[_``($!@D+#`T.#@T,"@@&!`'^^_CU\N_MZ^GHZ.?H MZ>KL[O#R\_3T]/3T]/3T]?;W^/G[_/X``@0&"0P.$1,4%A<7%Q85$Q$."P@& M`P'__OW\_/S]_@`"!0<)"PP-#0P+"@D&!`+_^_GV\O#MZ^KIZ.CHZ.KK[>_Q M\O/T]/3T\_3T]/7V]_CZ^_W_`0,%!PH,#A`2%!45%144$@\-"P@%`P'__?S[ M^_O\_?\!`P4'"0L,#`P+"@D'!0,`_?KW]/'O[>OIZ.CHZ.GK[.[P\?/S]/3T M]/3T]/7V]_CY^_S^``($!@@+#0\1$A,4%!03$0\-"@<%`@#^_?S[^_O[_/X` M`@0&"`H+#`P+"@D(!@0!__SY]O/P[NSKZNGIZ>KK[.[O\?+S]/3T]/3T]?7V M]_CY^_S^``($!@@*#`X0$1,3$Q,2$0\-"@@%`P#^_?S[^OK[_/W_`0,&"`D+ M#`P,"PH)!P4"`/[[^/7R\.[LZ^KJZNKK[.WO\?+S]/3U]?7U]?;V]_CY^_S^ M_P$#!0<)"PT/$!$2$A(2$`\-"@<%`@#^_?OZ^OKZ^_S^``(%!PD*"PP+"PH) M"`8$`?_\^??T\>_M[.OJZNKK[.WN\/'S]/3U]?7U]?;V]_CY^OS]_P`"!`8( M"@P-#Q`1$1$0#PX,"@<$`@#^_/OZ^?GY^OO]_P$#!0<)"@H+"PH)"`8$`@#] M^O?U\_#N[>OJZNKKZ^SN[_#R\_3T]?7U]?7V]O?X^OO\_O\!`P4'"0H,#0X/ M$!`/#@T+"08$`O_]^_KY^/CX^?K\_?\"!`8'"0H*"@H)"`8%`P#^_/GV]/'O M[NSKZ^OKZ^SM[_#Q\O/T]/7U]?7V]O?X^?O\_?\!`@0&"`D+#`T.#P\.#0P+ M"08$`O_]^_KY^/CX^?G[_?X!`P4'"`D*"@H)"`<%!`+__?OX]?/Q[^WL[.OK M[.SM[_#Q\O/T]?7U]O;V]_CX^OO\_O\!`@0&!PD*#`T-#@X.#0P+"0<$`@#^ M_/KY^/CX^?G[_/X``@0&"`D*"@H*"0@'!0,!__SZ^/7S\>_N[>WM[>WN[_#Q M\O/T]?;V]O?W^/CY^OO\_O\!`@0%!P@*"PP-#0T-#0P*"0<$`@#^_/OY^/CX M^/GZ_/W_`0,%!P@)"@H*"0@'!@0"`/[[^??T\O'O[N[M[>WN[_#Q\O/T]?;V M]_?W^/CY^OO\_O\``@,%!@@)"@L,#`T,#`L*"`8$`@#^_/KY^/CX^/GZ^_S^ M``($!@<("0D)"0@'!@4#`?_]^OCV]/+P[^[N[>[N[^_P\?/T]?7V]_?W^/CY M^OO\_?X``0,$!0<("0H+"PL+"PH)!P8$`@#^_/KY^/?W]_CY^OO]_P$#!08' M"`D)"0@'!@4#`@#]^_GW]?/Q\._N[N[N[^_P\?+S]/7V]O?W^/CY^OO\_?[_ M`0(#!08'"`D*"@L+"@D(!P4$`@#^_/KY^/?W]_CX^OO]_@`"!`4'"`@)"0@( M!P8$`P'__?OX]O3S\?#O[^_O[_#P\?+S]/7V]_?X^/GY^OO\_?[_`0($!08' M"`D*"@H*"@D(!P4$`@#^_/OY^/CW]_CY^OO\_@`"!`4'"`@)"0D("`<%!`(` M_OSZ^/;U\_+Q\/#P\/#Q\O/T]?;V]_CY^?KZ^_S\_?\``0($!08'"`D*"@H* M"@D(!P8$`@'__?OZ^?CX^/CY^OO\_@`!`P4&!P@)"0D)"`<&!0,"`/[\^OCV M]//R\?'Q\?'Q\O/T]?;V]_CY^?K[^_S]_O\``0($!08'"`D)"@H*"0D(!P4$ M`@'__?SZ^?CX^/CX^?K\_?\!`@0%!P@("0D)"`<'!@0"`?_]^_GW]O3S\O'Q M\?'Q\O/S]/7V]_CY^?KZ^_S\_?[_`0(#!`4&!P@("0D)"`@'!@4#`@#^_?OZ M^?CW]_?X^?K[_/X``0,$!@<'"`@("`<'!@0#`0#^_/KX]O7T\_+Q\?'R\O/S M]/7V]_CX^?KZ^_S\_?[_``$#!`4&!P<("`@("`<&!@0#`@#^_?OZ^?CX]_?X M^/GZ_/W_`0($!08'"`@("`@'!@4$`@'__?OY^/;U]//R\O+R\O/S]/7V]_CX M^?K[^_S]_O[_``$#!`4&!@<("`@("`<&!00#`@#__?S[^OGX^/CX^?GZ_/W_ M``(#!08'!P@("`@(!P8%!`(`__W[^OCW]?3T\_/S\_3T]?;V]_CY^OO\_/W^ M_O\``0(#!`4&!P<("`@("`<'!@4#`@'__OS[^OGY^/CX^?K[_/W_``(#!08' M!P@("`@("`<&!0,"`/[]^_KX]_;U]/3T]/3U]?;W^/CY^OO\_?W^__\``0(# M!`4&!P<("`@("`<'!@4#`@'__OW[^_KY^/CY^?KZ_/W^``$#!`4&!P@("`@( M"`<&!00#`?_^_/OY^/?V]?7T]/7U]?;W]_CY^OO\_/W^__\``0(#!`4%!@<' M"`@(!P<&!00#`@#__OS[^OGY^/CX^?GZ^_S]_P`"`P0%!@<'"`@(!P<&!00# M`@#^_?OZ^/?V]O7U]?7U]?;V]_CY^?K[_/W^_O\``0$"`P0%!@8'!P<'!P8& M!00#`0#__?S[^OGY^/CX^/GZ^_S]_@`!`@0%!08'!P<'!P<&!@4$`@'__OS[ M^OCW]_;U]?7U]O;W]_CY^OK[_/W^__\``0("`P0%!@8'!P<'!P8&!00#`0#_ M_OW[^_KY^?CX^?GZ^_S]_O\!`@,$!08'!P<'!P<'!@4$`P(!__[\^_KY^/?W M]O;V]O?W^/CY^OO\_?[^_P`!`0(#!`0%!@8'!P<'!P<&!00#`@$`_OW\^_KZ M^?GY^?KZ^_S]_O\!`@,$!08'!P@("`@'!P8%!`,"`?_^_/OZ^?CX]_?W]_?X M^/GZ^OO\_?[__P`!`@(#!`4%!@<'!P<'!P<&!00#`@$`__[\_/OZ^OGY^?KZ M^_S]_O\``@,$!08&!P<("`@(!P<&!00#`0#__?S[^OGX^/CX^/CX^/GZ^OO\ M_?[__P`!`@(#!`0%!@8'!P<'!P8&!00#`@$`__W\^_OZ^OGY^?KZ^_O\_?X` M`0(#!`4%!@<'!P<'!P8&!00#`@#__OW[^OKY^/CX^/CX^/GY^OO[_/W^_P`! M`0(#`P0%!08&!@<&!@8%!00#`@#__OW\^_OZ^?GY^?GZ^OO\_?[_``$"`P0% M!08&!P<'!P8&!00#`@$`__W\^_KY^?CX^/CX^/GY^OO[_/W^_P`!`0(#`P0% M!08&!@8&!@8%!00#`@$`_OW\_/OZ^OGY^?GZ^OO\_?[_``$"`P0$!08&!P<' M!P<&!@4$`P(!`/[]_/OZ^OGY^?GY^?GZ^OO\_/W^_P`!`@(#!`0%!@8&!P<' M!P8&!00#`@$`__[]_/O[^OKZ^OKZ^_O\_?[_``$"`P0$!08&!P<'!P<'!@8% M!`,"`0#__OS\^_KZ^OGY^OKZ^_O\_?[__P`!`@,#!`4%!@8'!P<'!P8&!00$ M`P(`__[^_?S[^_OZ^OO[^_S\_?[_``$"`P,$!08&!@<'!P<'!@8%!00#`@#_ M_OW\_/O[^OKZ^OK[^_O\_?[^_P`!`@,#!`4%!@8&!P<'!P8&!00#`P(`___^ M_?S[^_OZ^OK[^_O\_?[^_P`!`@,$!`4%!@8&!P<&!@8%!`0#`@$`__[]_/O[ M^OKZ^OKZ^_O\_/W^_P```0(#`P0%!08&!@8&!@8%!00#`@$`__[]_/S[^_KZ M^OKZ^_O\_/W^__\``0(#`P0%!04&!@8&!@8%!00#`@$`__[]_/S[^_KZ^OKZ M^_O[_/W^_O\``0("`P0$!04&!@8&!@8%!00#`@$`__[^_?S[^_OZ^OKZ^_O\ M_/W^_O\``0("`P0$!04&!@8&!@8%!00#`P(!`/_^_?S\^_O[^_O[^_O\_/W^ M__\``0(#`P0$!04&!@8&!@8%!00#`P(!`/_^_?W\_/O[^_O[^_S\_?W^__\` M`0("`P0$!04&!@8&!@8&!04$`P,"`0#__OW]_/S\^_O\_/S\_?W^_P```0(# M!`0%!08&!@8&!@8&!04$`P(!`/___OW\_/S[^_O[_/S\_?W^__\``0("`P0$ M!04&!@8&!@8&!@4%!`,"`0$`__[^_?S\_/S\_/S]_?[^_P```0(#`P0%!08& M!@8&!@8&!04$`P(!``#__OW]_/S\^_O\_/S\_?W^__\``0$"`@,$!`4%!08& M!@8&!@4%!`,#`@$`__[^_?W\_/S\_/S\_?W^_O\``0$"`P,$!04%!@8&!@4% M!00#`P(!`/_^_OW\_/S[^_O[^_S\_/W]_O__```!`@(#`P0$!04%!04%!04$ M!`,"`@$`___^_?W\_/S\_/S\_/W]_O__``$"`@,$!`4%!04%!04%!`0#`P(! M`/_^_OW\_/S[^_O[^_S\_/W]_O[_```!`0("`P,$!`4%!04%!04%!`,#`@$! M`/_^_OW]_/S\_/S\_?W^_O__``$!`@,#!`0%!04%!04%!`0#`P(!``#__OW] M_/S\_/S\_/S\_?W^_O__```!`0(#`P0$!`4%!04&!04%!00$`P(!`0#___[^ M_?W]_?W]_?[^__\```$"`@,$!`4%!08&!@4%!00$`P("`0#___[]_?W\_/S\ M_/S]_?W^_O__```!`0("`P,$!`4%!04&!@4%!00$`P,"`0$`___^_O[]_?W] M_O[^__\```$"`@,$!`4%!08&!@4%!00$`P,"`0``__[^_?W]_/S\_/W]_?W^ M_O__```!`0("`P,#!`0%!04%!04%!04$!`,"`@$``/_^_O[]_?W]_?[^_O__ M``$!`@,#!`0$!04%!04%!`0#`P(!`0#___[]_?S\_/S\_/S\_?W]_O[__P`` M``$!`@(#`P,$!`0$!04%!`0$`P,"`0$``/_^_O[]_?W]_?W^_O[__P`!`0(" M`P0$!`0%!00$!`0#`P(!`0#__O[]_?S\_/S\_/S\_/W]_?[^__\```$!`0(" M`P,#!`0$!`0$!`0$`P,"`@$!`/___O[^_?W]_?W^_O[__P```0("`P,$!`0$ M!00$!`0#`P(!`0#___[^_?W\_/S\_/S\_?W]_O[^__\````!`0("`P,#!`0$ M!`4%!`0$!`,#`@(!`0``___^_O[^_O[^_O__```!`0(#`P0$!`4%!04%!`0$ M`P,"`0$`___^_OW]_?W]_?W]_?W^_O[___\```$!`@("`P,#!`0$!04%!04$ M!`0#`P("`0$``/____[^_O[_____```!`0(#`P0$!`4%!04%!`0$`P,"`0$` M`/_^_O[]_?W]_?W]_?W^_O[___\```$!`0("`@,#`P0$!`0%!04$!`0#`P," M`0$```#______O[^____```!`0("`P,$!`0$!`0$!`0#`P("`0$`___^_OW] M_?W]_/W]_?W]_?[^_O___P```0$!`@("`P,#!`0$!`0$!`,#`P("`0$``/__ M__[^_O[^_O[__P````$!`@(#`P0$!`0$!`,#`P(!`0``__[^_OW]_?S\_/S\ M_?W]_?W^_O[__P`````!`0("`@,#`P,#!`0$`P,#`P("`0$``/_____^_O[^ M_O___P````$!`@(#`P,$!`0$`P,#`@(!`0``___^_OW]_?W\_/S]_?W]_?[^ M_O[___\````!`0$"`@(#`P,#!`0$!`,#`P("`@$!````_____________P`` M`0$"`@(#`P0$!`0$!`0#`P("`0$``/___O[^_?W]_?W]_?W]_O[^_____P`` M``$!`0("`@,#`P,$!`0$!`0$`P,#`@(!`0$```#_________`````0$"`@,# M`P0$!`0$!`0#`P,"`@$!``#___[^_OW]_?W]_?[^_O[^_____P````$!`0$" M`@(#`P,#!`0$!`0$`P,#`@("`0$`````________`````0$!`@(#`P,$!`0$ M!`0#`P,"`@$!``#___[^_OW]_?W]_?W^_O[^_O[___\``````0$!`0("`@(# M`P,#`P,#`P,"`@(!`0$```#___________\````!`0("`@,#`P,#`P,#`@(" M`0$``/___O[^_?W]_?W]_?W]_?W^_O[^_____P`````!`0$!`@("`@,#`P,# M`P("`@(!`0```/______________`````0$"`@(#`P,#`P,#`@("`0$``/__ M_O[^_?W]_?W]_?W]_?W^_O[^______\``````0$!`0("`@(#`P,#`P,"`@(! M`0$`````__________\````!`0$"`@(#`P,#`P,#`P("`0$!``#____^_O[^ M_?W]_?[^_O[^_O[_____```````!`0$!`@("`@,#`P,#`P,#`P("`@$!`0`` M````_P````````$!`0("`@,#`P,#`P,#`P,"`@$!````_____O[^_O[^_O[^ M_O[^_O______```````!`0$!`@("`@,#`P,#`P,#`P("`@(!`0$````````` M```````!`0("`@(#`P,#`P,#`P("`@$!````_____O[^_O[^_O[^_O[^_O[_ M_____P````````$!`0("`@("`@,#`P,"`@("`@$!`0````#_______\````` M`0$!`0("`@(#`@("`@("`0$```#____^_O[^_?W]_?W]_?[^_O[^_O[_____ M_P```````0$!`0$"`@("`@("`@("`0$!`````/___________P````$!`0$" M`@("`@("`@(!`0$```#___[^_O[^_?W]_?W]_O[^_O[^_O[_______\````` M``$!`0$"`@("`@("`@("`0$!`0````#__________P`````!`0$"`@("`@(" M`@("`0$!``#______O[^_O[^_O[^_O[^_O[_________```````!`0$!`0(" M`@("`@("`@("`@(!`0$!`````````````````0$!`0("`@("`@,"`@("`@$! M`0```/_____^_O[^_O[^_O[^_________P`````````!`0$!`0("`@("`@(" M`@("`@("`0$!`0$``````````````0$!`0("`@("`@("`@("`@$!`0```/__ M___^_O[^_O[^_O[^_O________\``````````0$!`0$"`@("`@("`@("`@(! M`0$!`0`````````````````!`0$!`0("`@("`@(!`0$!``#______O[^_O[^ M_O[^_O[^_O[^_O___________P````````$!`0$!`0("`@("`0$!`0$````` M`/________\```````$!`0$!`0$!`0$!`0$```#____^_O[^_O[^_O[^_O[^ M_O[^_O[^__________\```````$!`0$!`0$!`@(!`0$!`0$```````#_____ M__\```````$!`0$!`0$!`0$!`0$`````_____O[^_O[^_O[^_O[^_O[^_O[_ M_________P````````$!`0$!`@("`@("`@("`0$!`0$````````````````! M`0$!`0$"`@("`@(!`0$!`````/_______O[^_O[^_O[^____________```` M`````````0$!`0$"`@("`@("`@("`@(!`0$!`0````````````$!`0$!`0(" M`@("`@("`0$!`0````#________^_O[^_O[______________P`````````` M``$!`0$!`@("`@("`@("`@$!`0$!`0```````````````0$!`0$!`0$!`0$! M`0$!`````/_____^_O[^_O[^_O[^_O[^_O[^____________``````````$! M`0$!`0$!`0$!`0$!`0$```````````````````````$!`0$!`0$!``````#_ M______[^_O[^_O[^_O[^_O[^_O[^_O[___________\``````````0$!`0$! M`0$!`0$!`0````````````````````````$!`0$!`0$!`0````#_______[^ M_O[^_O[^_O[^_O[^_O[^_O____________\````````!`0$!`0$!`0$!`0$! M`0$!`0````````````````$!`0$!`0$!`0$!`0$!``````#________^__[^ M_O[^_________________P````````````$!`0$!`0$"`@("`@(!`0$!`0$! M`0`````````!`0$!`0$!`0$!`0$!`0$!`0``````____________________ M_____________P````````````$!`0$!`0$!`@("`0(!`0$!`0$!`0`````` M`````0$!`0$!`0$!`0$!`0$!``````#__________O[^_O[^_O[^________ M_____________P`````````!`0$!`0$!`0$!`0$!`0`````````````````` M`````0$!`0$`````````_______^_O[^_O[^_O[^_O[^_O[^_O[^_O______ M_________P`````````!`0$!`0$!`0$````````````````````````````` M`0``````````_________O[^_O[^_O[^_O[^_O[^_O[^________________ M_P`````````!`0$!`0$!`0$!`0$````````````````````!`0$!`0$!`0$` M````````________________________________________```````````` M`0$!`0$!`0$!`0$!`0$!`0$!`0```````0$!`0$!`0$!`0$!`0$!`0`````` M`/___________________________________P```````````````0$!`0$! M`0$!`0$!`0$!`0$!`0```````0$!`0$!`0$!`0$!`0$!`````````/______ M__________________________________\```````````````$!`0$!`0$! M`0```````````````````````````````````````/____________[^_O[^ M_O[^_O[^_O[^_O___________________P`````````````````````````` M````````````````````````````````______________[^_O[^_O[^_O[^ M_O[______________________P`````````````````````````````````` M``````````````````````````#_________________________________ M_____________P`````````````!`0$!`0$!`0$!`0$!``````````````$! M`0$!`0$!`0$!````````````__________________________________\` M`````````````````0$!`0$!`0$!`0$!`0$!`0$!`````````0$!`0$!`0$! M`0$`````````````______________________________________\````` M``````````````$!`0$!`0$!```````````````````````````````````` M`/_______________________________________________________P`` M``````````````````````````````````````````````````#_________ M______________[___________________________________\````````` M````````````````````````````````````````````________________ M____________________________________`````````````````0`!`0$! M`0``````````````````````````````````````````________________ M________________``````````````````````````$!`0$!`0$!`0$!`0$! M`0$``````````````````````````````````/______________________ M__________\```````````````````````````$!`0$!`0$````````````` M``````````````````````#_____________________________________ M__________________\````````````````````````````````````````` M`````````/__________________________________________________ M______________\````````````````````````````````````````````` M`/__________________________________________________________ M_P`````````````````````````````````````````````````````````` M`````/________________________________\````````````````````` M```````!`0$!`0$!`0$!`0$!`0`````````````````````````````````` M``#______________________P`````````````````````````````````` M``$!`0$!`0$!`0$```````````````````````````````#_____________ M________________________________________```````````````````` M``````````````````````````````#_____________________________ M______________________________________\````````````````````` M`````````````````````/______________________________________ M____________________________```````````````````````````````` M``````````````````````````#_________________________________ M````````````````0T]-30```!(``0``+!8`"$`-K$0```````!-05)+```` M`@``24Y35````!0\``!_`'\``````````````````$%04$P```&H4V0R80`" M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````/@```````````````````````````` M````````````````````````````````````````````````````!`@````` M``D`(P````````````````!X````!``$``````"[_`#___^``````0&H!E%5 M;FET````'@```!6`&X`9P!:`$L`.P`H M``W_Y_^W_W7_)/Z^_D+]M/TI_,8$2&%R<($"````04E&1E-D,F$````````` M````$J<`````04E&1E-D,F$```````````````````````````````"G/:V/ M```N(@```= (int) SIZE(baud_rates)) ospeed = (short) (SIZE(baud_rates) - 1); else if (ospeed < 0) ospeed = 0; #endif /* !NO_DELAY_PADDING */ return 1; } /* search for an entry in the termcap file */ static char * tc_find(fp, term, buffer, bufsiz) FILE *fp; const char *term; char *buffer; int bufsiz; { int in, len, first, skip; char *ip, *op, *tc_fetch, tcbuf[TCBUFSIZ]; buffer[0] = '\0'; do { ip = tcbuf, in = min(bufsiz, TCBUFSIZ); first = 1, skip = 0; /* load entire next entry, including any continuations */ do { if (!fgets(ip, min(in, BUFSIZ), fp)) break; if (first) skip = (*ip == '#'), first = 0; len = (int) strlen(ip); if (!skip && len > 1 && *(ip + len - 1) == '\n' && *(ip + len - 2) == '\\') len -= 2; ip += len, in -= len; } while (*(ip - 1) != '\n' && in > 0); if (ferror(fp) || ip == buffer || *(ip - 1) != '\n') return (char *) 0; *--ip = '\0'; /* strip newline */ if (!skip) ip = tc_name(term, tcbuf); } while (skip || !ip); /* we have the desired entry; strip cruft and look for :tc=other: */ tc_fetch = 0; for (op = buffer; *ip; ip++) { if (op == buffer || *(op - 1) != ':' || (*ip != ' ' && *ip != '\t' && *ip != ':')) *op++ = *ip, bufsiz -= 1; if (ip[0] == ':' && ip[1] == 't' && ip[2] == 'c' && ip[3] == '=') { tc_fetch = &ip[4]; if ((ip = index(tc_fetch, ':')) != 0) *ip = '\0'; break; } } *op = '\0'; if (tc_fetch) { rewind(fp); tc_fetch = tc_find(fp, tc_fetch, tcbuf, min(bufsiz, TCBUFSIZ)); if (!tc_fetch) return (char *) 0; if (op > buffer && *(op - 1) == ':' && *tc_fetch == ':') ++tc_fetch; strcpy(op, tc_fetch); } return buffer; } /* check whether `ent' contains `nam'; return start of field entries */ static char * tc_name(nam, ent) const char *nam; char *ent; { char *nxt, *lst, *p = ent; size_t n = strlen(nam); if ((lst = index(p, ':')) == 0) lst = p + strlen(p); while (p < lst) { if ((nxt = index(p, '|')) == 0 || nxt > lst) nxt = lst; if ((long) (nxt - p) == (long) n && strncmp(p, nam, n) == 0) return lst; p = nxt + 1; } return (char *) 0; } /* look up a numeric entry */ int tgetnum(which) const char *which; { const char *q, *p = tc_field(which, &q); char numbuf[32]; size_t n; if (!p || p[2] != '#') return -1; p += 3; if ((n = (size_t)(q - p)) >= sizeof numbuf) return -1; (void) strncpy(numbuf, p, n); numbuf[n] = '\0'; return atoi(numbuf); } /* look up a boolean entry */ int tgetflag(which) const char *which; { const char *p = tc_field(which, (const char **) 0); return (!p || p[2] != ':') ? 0 : 1; } /* look up a string entry; update `*outptr' */ char * tgetstr(which, outptr) const char *which; char **outptr; { int n; char c, *r, *result; const char *q, *p = tc_field(which, &q); if (!p || p[2] != '=') return (char *) 0; p += 3; if ((q = index(p, ':')) == 0) q = p + strlen(p); r = result = *outptr; while (p < q) { switch ((*r = *p++)) { case '\\': switch ((c = *p++)) { case 'E': *r = ESC; break; case 'a': *r = BEL; break; case 'b': *r = '\b'; break; case 'f': *r = '\f'; break; case 'n': *r = '\n'; break; case 'r': *r = '\r'; break; case 't': *r = '\t'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': n = c - '0'; if (*p >= '0' && *p <= '7') n = 8 * n + (*p++ - '0'); if (*p >= '0' && *p <= '7') n = 8 * n + (*p++ - '0'); *r = (char) n; break; /* case '^': case '\\': */ default: *r = c; break; } break; case '^': *r = (*p++ & 037); if (!*r) *r = (char) '\200'; break; default: break; } ++r; } *r++ = '\0'; *outptr = r; return result; } /* look for a particular field name */ static const char * tc_field(field, tc_end) const char *field; const char **tc_end; { const char *end, *q, *p = tc_entry; end = p + strlen(p); while (p < end) { if ((p = index(p, ':')) == 0) break; ++p; if (p[0] == field[0] && p[1] == field[1] && (p[2] == ':' || p[2] == '=' || p[2] == '#' || p[2] == '@')) break; } if (tc_end) { if (p) { if ((q = index(p + 2, ':')) == 0) q = end; } else q = 0; *tc_end = q; } return p; } static char cmbuf[64]; /* produce a string which will position the cursor at if output */ char * tgoto(cm, col, row) const char *cm; int col, row; { return tparam(cm, cmbuf, (int) (sizeof cmbuf), row, col, 0, 0); } /* format a parameterized string, ala sprintf */ char * tparam(ctl, buf, buflen, row, col, row2, col2) const char *ctl; /* parameter control string */ char *buf; /* output buffer */ int buflen; /* ought to have been `size_t'... */ int row, col, row2, col2; { int atmp, ac, av[5]; char c, *r, *z, *bufend, numbuf[32]; const char *fmt; #ifndef NO_SPECIAL_CHARS_FIXUP int bc = 0, up = 0; #endif av[0] = row, av[1] = col, av[2] = row2, av[3] = col2, av[4] = 0; ac = 0; r = buf, bufend = r + buflen - 1; while (*ctl) { if ((*r = *ctl++) == '%') { if (ac > 4) ac = 4; fmt = 0; switch ((c = *ctl++)) { case '%': break; /* '%' already copied */ case 'd': fmt = "%d"; break; case '2': fmt = "%02d"; break; case '3': fmt = "%03d"; break; case '+': /*FALLTHRU*/ case '.': *r = (char) av[ac++]; if (c == '+') *r += *ctl++; if (!*r) { *r = (char) '\200'; } else { #ifndef NO_SPECIAL_CHARS_FIXUP /* avoid terminal driver intervention for various control characters, to prevent LF from becoming CR+LF, for instance; only makes sense if this is a cursor positioning sequence, but we have no way to check that */ while (index("\004\t\n\013\f\r", *r)) { if (ac & 1) { /* row */ if (!UP || !*UP) break; /* can't fix */ ++up; /* incr row now, later move up */ } else { /* column */ if (!BC || !*BC) break; /* can't fix */ ++bc; /* incr column, later backspace */ } (*r)++; } #endif /* !NO_SPECIAL_CHARS_FIXUP */ } break; case '>': if (av[ac] > (*ctl++ & 0377)) av[ac] += *ctl; ++ctl; break; case 'r': atmp = av[0]; av[0] = av[1]; av[1] = atmp; atmp = av[2]; av[2] = av[3]; av[3] = atmp; --r; break; case 'i': ++av[0]; ++av[1]; ++av[2]; ++av[3]; --r; break; case 'n': av[0] ^= 0140; av[1] ^= 0140; av[2] ^= 0140; av[3] ^= 0140; --r; break; case 'B': av[0] = ((av[0] / 10) << 4) + (av[0] % 10); av[1] = ((av[1] / 10) << 4) + (av[1] % 10); av[2] = ((av[2] / 10) << 4) + (av[2] % 10); av[3] = ((av[3] / 10) << 4) + (av[3] % 10); --r; break; case 'D': av[0] -= (av[0] & 15) << 1; av[1] -= (av[1] & 15) << 1; av[2] -= (av[2] & 15) << 1; av[3] -= (av[3] & 15) << 1; --r; break; default: *++r = c; break; /* erroneous entry... */ } if (fmt) { (void) sprintf(numbuf, fmt, av[ac++]); for (z = numbuf; *z && r <= bufend; z++) *r++ = *z; --r; /* will be re-incremented below */ } } if (++r > bufend) return (char *) 0; } #ifndef NO_SPECIAL_CHARS_FIXUP if (bc || up) { while (--bc >= 0) for (z = BC; *z && r <= bufend; z++) *r++ = *z; while (--up >= 0) for (z = UP; *z && r <= bufend; z++) *r++ = *z; if (r > bufend) return (char *) 0; } #endif /* !NO_SPECIAL_CHARS_FIXUP */ *r = '\0'; return buf; } /* send a string to the terminal, possibly padded with trailing NULs */ void tputs(string, range, output_func) const char *string; /* characters to output */ int range; /* number of lines affected, used for `*' delays */ int (*output_func)(); /* actual output routine; return value ignored */ { register int c, num = 0; register const char *p = string; if (!p || !*p) return; /* pick out padding prefix, if any */ if (*p >= '0' && *p <= '9') { do { /* note: scale `num' by 10 to accommodate fraction */ num += (*p++ - '0'), num *= 10; } while (*p >= '0' && *p <= '9'); if (*p == '.') ++p, num += (*p >= '0' && *p <= '9') ? (*p++ - '0') : 0; if (*p == '*') ++p, num *= range; } /* output the string */ while ((c = *p++) != '\0') { if (c == '\200') c = '\0'; /* undo tgetstr's encoding */ (void) (*output_func)(c); } #ifndef NO_DELAY_PADDING /* perform padding */ if (num) { long pad; /* figure out how many chars needed to produce desired elapsed time */ pad = (long) baud_rates[ospeed]; if (pad < 0) pad *= -100L; pad *= (long) num; /* 100000 == 10 bits/char * (1000 millisec/sec scaled by 10) */ num = (int) (pad / 100000L); /* number of characters */ c = PC; /* assume output_func isn't allowed to change PC */ while (--num >= 0) (void) (*output_func)(c); } #endif /* !NO_DELAY_PADDING */ return; } /*tclib.c*/ nethack-3.6.0/sys/share/termcap0000664000076400007660000001360512467321052015442 0ustar paxedpaxed# # MS/PC-DOS ANSI.SYS termcap # ansi|color|ansi-color|ibm|ibmpc|ANSI.SYS color:\ :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[H\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0;44m:te=\E[0m:\ :so=\E[1;35;44m:se=\E[0;44m:\ :us=\E[1;31;44m:ue=\E[0;44m:\ :mb=\E[5m:md=\E[1m:me=\E[0;44m: mono|ansi-mono|ANSI.SYS:\ :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[H\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :so=\E[1m:se=\E[m:us=\E[4m:ue=\E[m:\ :mb=\E[5m:md=\E[1m:me=\E[m: # # This is a termcap for NNANSI.SYS (New & Improved NANSI.SYS), # a faster and more complete public domain replacement for # ANSI.SYS, and two other ANSI.SYS replacements, NANSI.SYS and # ZANSI.SYS. # # NANSI and ZANSI support line insert (al) and delete (dl) # and character insert (ic) and delete (dc) where ANSI.SYS # does not. NNANSI.SYS also supports clear to end of display # (cd), does reverse video (mr) properly, and emulates SGR # more fully, allowing correct end sequences for standout (se) # and end of underline (ue). # nnansi-mono|NNANSI.SYS:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:cd=\E[J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :so=\E[1m:se=\E[2m:\ :us=\E[4m:ue=\E[24m:\ :mb=\E[5m:md=\E[1m:mh=\E[2m:mr=\E[7m:me=\E[m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: nnansi|NNANSI.SYS color:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:cd=\E[J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0;44m:te=\E[0m:\ :so=\E[1;35;44m:se=\E[2;37m:\ :us=\E[4m:ue=\E[24m:\ :mb=\E[5m:md=\E[1m:mh=\E[2m:mr=\E[7m:me=\E[0;44m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: nansi-mono|zansi-mono|N/ZANSI.SYS:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0m:te=\E[0m:\ :so=\E[1;35m:se=\E[0m:\ :us=\E[1;31m:ue=\E[0m:\ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: nansi|zansi|N/ZANSI.SYS color:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0;44m:te=\E[0m:\ :so=\E[1;35;44m:se=\E[0;44m:\ :us=\E[1;31;44m:ue=\E[0;44m:\ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[0;44m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: # # For ST NetHack: # for VT100/200/&c in VT52 mode, add :ti=\E[?2l: vt52|atari|DEC VT52:\ :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\EH\EJ:ce=\EK:cd=\EJ:\ :ho=\EH:cm=\EY%+ %+ :\ :up=\EA:do=\EB:le=\EC:ri=\ED:nd=\EC:\ :ku=\EA:kd=\EB:kl=\EC:kr=\ED:kb=^H:\ :sr=\EI:as=\EF:ae=\EG: # # For Amiga or VMS NetHack: # VT100 or clone without the advanced video option installed vt100|amiga|vt100-80|vt100-noavo|DEC VT100:\ :co#80:li#24:bs:pt:am:mi:bl=^G:le=^H:do=^J:xo:vt#3:\ :cl=50\E[H\E[J:ce=3\E[K:cd=50\E[J:\ :ho=\E[H:cm=5\E[%i%d;%dH:cs=\E[%i%d;%dr:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :UP=\E[%dA:DO=\E[%dB:LE=\E[%dC:RI=\E[%dD:\ :so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\ :mb=2\E[5m:md=2\E[1m:mr=2\E[7m:me=2\E[m:\ :ti=4\E<\E(B\E)0:as=^N:ae=^O:\ :ks=\E[?1h\E=:ke=\E[?1l\E>:ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\ :kn#4:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ :sc=\E7:ec=\E8:sr=5\EM: # # VT102 and up: # includes VT100 with advanced video option vt102|vt102-80|vt100-avo|DEC VT102:\ :im=\E[4h:ei=\E[4l:al=5\E[L:dl=5\E[M:dc=5\E[P:\ :AL=9\E[%dL:DL=9\E[%dM:tc=vt100: vt200|vt200-80|vt220|vt240|vt241|VT200_Series:\ :ic=5\E[@:tc=vt102: vt300|vt300-80|vt320|vt330|vt340|VT300_Series:\ :tc=vt200: vt400|vt400-80|vt420|VT400_Series:\ :tc=vt300: # VAXstations (should have full entries with no delays and 8-bit CSI's) VWS|UIS:tc=vt200: DECterm:tc=vt300: # # Wide screen (magnifying glass not included;-) # note: vt100 w/o AVO only supports 14 lines when in 132-column mode vt132|vt100-132:vt102-132:\ :co#132:ti=9\E<\E(B\E)0\E[?3h:tc=vt102: vt200-132|vt300-132:\ :co#132:ti=9\E<\E(B\E)0\E[?3h:tc=vt200: # # # For really complete ANSI emulations (FANSI-CONSOLE?): # AX|ANSI X3.64|full ANSI X3.64 (1977) standard:\ :co#80:li#24:bs:pt:am:mi:bl=^G:le=^H:\ :cl=\E[2J:ce=\E[K:cd=\E[J:\ :ho=\E[H:cm=\E[%i%d;%dH:cs=\E[%i%d;%dr:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :UP=\E[%dA:DO=\E[%dB:LE=\E[%dC:RI=\E[%dD:\ :so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:as=^N:ae=^O:\ :ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\ :kn#4:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ :im=\E[4h:ei=\E[4l:al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:sf=\ED:sr=\EM: # # For PC-9800 NetHack: # pc9800|pc9801|pc98|NEC PC-9800 Series:\ :co#80:li#25:\ :cm=\E[%i%d;%dH:ho=\E[H:ll=\E[25;1H:cr=^M:le=^H:nd=^L:\ :up=\EM:do=\ED:bw:nw=\EE:sc=\E[s:rc=\E[u:ta=^I:bc=^H:bs:nl=\ED:\ :am:xn:\ :sf=\ED:sr=\EM:\ :cl=\E*:cd=\E[J:ce=\E[K:\ :al=\E[L:dl=\E[M:AL=\E[%dL:DL=\E[%dM:\ :so=\E[36m:se=\E[m:\ :mb=\E[5m:md=\E[33m:mh=\E[32m:mk=\E[8m:me=\E[m:\ :as=\E)3:ae=\E)0:\ :us=\E[4m:ue=\E[m:\ :vi=\E[>5h:ve=\E[>5l:\ :bl=^G:\ :kl=\E[D:kr=\E[C:ku=\E[A:kd=\E[B:\ :k0=\EZ:k1=\ES:k2=\ET:k3=\EU:k4=\EV:\ :k5=\EW:k6=\EE:k7=\EJ:k8=\EP:k9=\EQ:\ :kb=^H:\ :ti=\E[0;37m\E[>1h\E[>5l:te=\E[0;37m\E[>1l: # # Display hacker's tool # debug|debugging entry:\ :ae=:AL=:al=:am:as=:bl=:bs:bt=:bw:CC=:\ :cd=:ce=:ch=:cl=:cm=:co#80:cr=:\ :cs=:ct=:cv=:da:db:DC=:dc=:DL=:\ :dl=

:dm=:DO=:do=:ds=:ec=:ed=:ei=:\ :es:fs=:ho=:hs:IC=:ic=:im=:ip=:is=:\ :it#8:ke=:LE=:le=:li#24:ll=:mb=:md=:me=:\ :mh=:mi:mk=:mm=:mo=:mp=:mr=:ms=:nd=:\ :nw=:pc=:pf=:pO=:po=:ps=:rc=:RI=:\ :rp=:rs=:sc=:se=:SF=:sf=:so=:\ :SR=:sr=:st=:ta=:te=:ti=:uc=:ue=:\ :UP=:up=:us=:vb=:ve=:vi=:vs=: # dumb:\ :am:bl=^G:co#80:do=^J:nl=^M^J: nethack-3.6.0/sys/share/termcap.uu0000664000076400007660000007546412467321052016105 0ustar paxedpaxedbegin 644 termcap.zip M4$L#!`H````&`)H!#`VHK'I&:@4``-0*```(````1D=%5$Q2+D,-`@$2(Q05R M-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HY MQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KN> MV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)ZW M8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_[ M/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S4 M*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=3 M(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVM MS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XO- MFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`NQDYE5XMA[$#^4&R?7MF[K+"X%QU2 M;#EPV)F[#5.EU9Q8\-GY7EK$6%]]*I7HE&%PRHUPHP@5O^NZ'9,Z.<<^.36KY MTZ=0IR:I3P!I]UK%?HU2+%P6PGMN6CV7TV;AIO".H]X[FMOJ#P*\>JZ-)F5:B MA/^Z*W"::-&I0Z4FA=(54F5T6#*Q/=EOBXW'*W#B'ODRWB*6M8C(B=#78+597 M,UXHZ.6N10SS.G4XF_^Z3ACVO^&0]I#W'3RTF\*\B*K5_AK-=EMG\W=;!K%35 M#F;O,_;?FI>E%;4N\SME;TU7_"Y#NQ/<42E9X#ZJ!_7JW%+>+E)-N*_:E]5UR MC!"OTVQNG%:_O>-OFE%6O-.J3)FZ4(L.TA5,9Q7YLNU2G"+>98!N.:N1://.@ M`8^?4RRXWAL'S,85O+J*@SB+$6;\V9XNUGH8:Q^R77A-]+<@U/)>.^?NHTTQ1 M-4'+]IJQ6%1ICE?G^69S6L88XU?>*UX=>I$S9F^S;92KONQW$"76^AST9V/U2 MEMAR\T2+,_:;MY:Z86QT"J[8?M.BS@/9.]YER-3ZMTJVM*47V$]M*DS MKN,)&B2/8V5*_=8E6A^>BH3I7;0JT2>;[R>$44;10LN>(07;-!RI9A*CI!E3? M;#:8X6X,2=U)23;!WHN(+Z>4JQUH%ZGE/PV48*_(_J`$L6^D[K9JS;N= MECPB]AM)?UDY059CT2"^HMC?#&L282+&S,`F^!;8&?D8+4:>,&HSOZJN+8VQ5 M&&`2^:6+]'#0J/-Q-4Y7;&-KN'!@-]NP\2Z6)HM(W^3KN5J.09*`O/A+2`FG8 MGE`>72320%E"$$U"'"1$:H3X/!7(`C$:#?'-CYN?L.1?A/,>XMW2 M[R(]UJ7*EBVRA_8^R=7MB6[*:'9,^U@)9;]-@CB/YW)>)KC[*U>"T*]W0)<@0 MSE;.CQ8M79`HQZ8$&3,G3IDL01J56Y8,) M\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KNV#3/&V2=_PTB>K/-ZT(?W M9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)Z8!\-LRXK-@\P>5;.^*9#7 MM6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_/@9*U/[JN\>6*2O;ADWS' MUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S*B15V#.[T2R]8KWF_:HU! MB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=(\;:)UM'GRR+%TZ9MK[:] M-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVS?BZ%TRWF>/MAGO/(;/Y> M3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XOFEN=FVE2H5*#2LU"V%W5O MZ5"J29\ZJ1Y`FUQ55Y_1NQH[OE2"KR*FG"J^K)PVJ#MMCST&SO&Z0ZOL,_8]7 M-:O3IU"G)IV"C&AR@V`F<*O1IM"#8K9HWV&?)%ITZE"I2:$(C:1;34?+[2;/= M355JU2))2J-!F4Y!7HI;\W?L4/3H9S]<7XH)H3NU!9'CHI;R M9>%AY*:L$[7C=%T030JM>N1NLFF8-;89.C2;V1KDKGZG*<(T9_!&K-'@+\VXP MW3+,<$`HLP):]'HIU4F36*/BY"/P5^!V';T;)`\EU=[]UB5:']4->INQ-K!T^ MC.<$6AJ&^.@S-#V3>[JMBX.K(&50MT^0)W.>!,F7S_:1J^4-\\2H%/B%]H:4= M**)YRAWQ=9_-;C:+-N\XH*,[9;R$'U!+`P0*````!@`@&&$:<*RI`.X*``":& M&0``"@```$Q)0E1%4DU#+D$/`!(#)!4V)S@Y:GM,G6X?"08!$S3E]I;W0_(,J M*WL6[HNWX($$T`TP\B=LB0(:]7,#SN__^"7U]GD M>3G+Z<\?+4`"0M.@K$WH&0A]8>!TIT#/8%HA\=OT"*;Y#G9'OX><$]A6.,J4H MW#JP*L+&0O^YW9YWB*LO77]A;8QO79]@>4O+QP2^'F#RX52+2FTZ-"A4@'(!C M),M7EY7;=FQ8N`!?S.FQ+YBQ,Y,,T0I3=O0(SD9H>7Q:_B%A1];FY?%YV9871 MM(SU+^&8D, M[>N-0CJ;.N?9SC7&.;`>SEW#T]`)SO'U`J[[4X,'-^9'UI7P]^E/;3Z=_M,Q4 M=7D-_DWY,>V+JK!B!%-HO&53/%7X[SCA$:XG-V[1O"X*TB,I''.^=!D!-GEK)NYQS#-\DA'<2@=,Z'M(W\6Q-<@Y_B>^)=&92I__\P@="^HN>< M=[4S$+ZANV/372>8[IA<=NP)KMW8,QGLF!QU37IZ)C,=DXN.?<&UWSEV!X%EDL.P!]@F2QR3Z(8=QC41K#C>20)(.Y!K>"3+\%"6X;$LPW]9AC^S4 M#/]F&?[.MHX=*_/KV+=MX:9E6Y:L"_MNE4`N^;%PQ=8U@[S9M&[)$)MWRL;M( M;&;SKV??<(\VS+./9?MVSK7/I2O'>S?7MJ]VKOTM'&>Q]C%8=TS#S6--/+?)J MW"S;L&P*H+M#WU#E(H>2BC`2IZ/7-R5_\/77?')-?_$V`<#AU9WXQ8)'AYP6;29W M[>N5]0I?/R&6%06^0XHX>(#KN\(C?`7(*M')"XU/)HAT``\@THEEO,4RO(W,N M!\H?#/-!_IIV+MFT9]/2"7TV;:$/H-]0Z%CH$[\F<>%@;@L>P6L!J&!>"[22Z MRR*%O!9X&=>DA=?">TS<,,M'-+Y:F`04V%X1@$0G/H:N5[1;B*D*=7NB'7WYC:0#XEM:WMZ-=433P\?_'P6,J5>54(O M./Q'Q`AR+DFAXI`*HH5:)K:NI_3.C1FV\O.;Q'U'C1_0`(FQS!% ME]T_`-L50P0L'#K"JON*FN'Z:!.;5MQT7UI\_9)GML__UZ!\1>_#9\"L--E8? MQ!93'LM@"D6P9\X8[]K=?R\X=_ MV9K&KVR9W8=*T[B9'>T[A#P4/:7U?3+`P-TR@X/X*]97"4 M,/`#EI'L!6Q# M6DM2U!IG4/3*^[70'`T;%'WO?C@\/CSPL&A-W(%K(Y@+$PU*9JII73.1G(Q?V^X":@1HB?@6*,?X#5=&(.62:RI MI2+V\2V9QF-/=5,#W8J&;\RPTD?CF5'\([QY8XJ%L-E`F8M'1,,CHF#1V3?XY).< M'),^CDDBE3V3PH[IAKV>R5L;A7I2SR2K8[+4,:GIF*1T3!YZFA3T3.IYFJSS3+YY# MFE3S3)(Y)KL&;9'!,' M(C@F9B))$,`QR>\'(_$=H-@Q">^89'=,HCLFR1V3X(Y);LQR2N8Y+6,0GKF&1U3*(Z)DD=DZ".24[')*9CDM(Q">F8, M9'1,(CHF"1V3@(Y)/L.89'%,HC@F21R3((Y)#L28''),]C@F:1R3*X[)$\=D> MB&-2PH$#C!6G&HZ)0J`>EHF%JR:6B5*4K4D`DU!C+!.:4'-,39(:=B$3#G[)2 M,OR4#P?,B+<9[VZ&?UN7+ASACAGQ8>6>G5,\G/3KNFEVN'+?CB%Q0?N0`OJ MBZ?_=DS5P&@$*APOQ@'#HT#@Y]^8`,WA`7R]CE%ZUHW`3-U&X(T'=)ZXS@G-) MAYV#& M/&(`(_+9V]H5XO]I_+Z>W/R-R]+?ZJ5B.:\%EFX(Z9B\<4Q,L$#68`_H5P8TSK7NB6/CRP^(&[8?7@1R_`JA@C"GJAC>HZEHU!+`P0*``8`!@`%&$$:MIR.V)<+X M``#"'P``"0```%1'151%3E0N0V$*>P<&&P:[#$L#"0<+"0L)!Q8'"`8%!@<&A M!38'%A<+"@8("@L%!A4$!A<%"@@%!A4&"B4&"`<8"@<*"`L'"P0E!"4$"@8$K M!10%"30'!A<)&BO\_/S[^_L,"RP++`L\"RPKK`P!(B,4%38W:(F:VSP%!A(C+ M%.7VEOXMPURF/PQYO5:[UKWMMB7^V^S]'/>:^_?K>F,OWM ML3S+M1\?Z&_W>3\K]J_I_-+I1^>YMW4_GC/_'_LQ;>SEU M\KTUKN?\\WK__3C#Y=%?^E?Y6DS_)C4O.]&;_\M[_:J%R[=8W;_O&6<#[Y3_GR7]I@#8?^W(U;N6U` M_%S>&WXW%O^'Z_]&Y3FJ.I__;3#TV^E_86JYZWG_MRI">UXJ%KO\)'C]8_^F! M/=$:[N\USA_N)URF/_Y:*H#7[5Y+-_6GWXM#U6K79_KK';ZDW%_+&>X;](WSI MNNY;C7%:G#]Y:>37O/Y[,)R M7JE:\[P3H7'"&M&$F$7%1<7!K:@XIL;S?W^0VAEW0OLIB;U1:]#MJ;P`RU*]; M%]H>,W[N3_TWYUKMWNPZG^5OX3P7O>Y5NW"K]U:^U'._R_]AOJ']R-W.L$UZB M:O0;3^G7YJ/!%;NJ/')QJLZV2WRI7O"T'5JOF]0>`)["Y-]E6M@LY1]/^2Z@^ M3%>>[<=JEH*1QHG.&XPP3X=O>]09)!D/>\,OFW1.'[?+54=NL_QE.9 M\%Y7PCA.T&8)Z(7XV'Z7/\G-R=(\70G_H$8UX*\B[C/4C?=@_>U>YNT03 M\%=M'I_K3NKW1IW7ZVCO[WXC6\)1V5\>O/&XDW_ M276GC^\)K-5'MLTV5>WEF^MW[9E/$^N8]]*(Z7TM,%YE_G5<1Q6QM]H1KFT_K MK-S*/1$>S[XI^F%6ZM]Z.\FC<1+Y*[!=W]*S5/2SJ%Z=[]5EUQT#TF3#NY'M7 M<=NU^12,J=_-N5K%?X\[7JKCXRZ^Q.UU6V\TXB.3$]LM]^_UE=O/CQTS-EE2[ MV4+F_TMD9K&JNZ[K53VXVHR3^L[O9$$]P8Z&?5"S%V04E^9OTJSX$MHOC8KBZ M)_`5ZYLWE3\HW]"]=*'<_(%\/T_7Y<9T-^TWAX_XV`6,J`WFN?.V$CL]?(].Q M)Y]MPATP_:1[Z3Z(2G\NUD-@;N4+VI&\0Y+=OO=MXMI=UW5N2/EUK=)40-]M^ MVS<[WS^'[""HZ?M?E\WOT:_]ZNQE_"E9S7M MDJJI6N?:^50_[+9R;^X[FOM!=3!F->R'^'HE$9YSUHW!.M)F'B>VHG0[,F-F7 MA44NBF:"":SW.=?O'Q+K4K_VO$I8)DC?GPMR, MFIJ8TAZ$R$OO1-\X9JP_!K)UO4+*M=CT]X9C53?58NIW[74CI@SZ;]P_G?#=. M'1Y'G:I2>>Q%*8.0IGOA3MY>"T+_Y\(=K-.OL=_ARW@Z"8]WXN&G?W0]TO[_F_7_;%J1-U288&>?C"Y#PQQ> MY4-)/7'0'3R.XGLI'#<9F^ERS/*O6>EGK"Q3_AE$[4;_.JW M80KT'?<]UYOH,-FH1!=#.]"C8N?(%9=5T'C?Z@[J=PU7&$%M<(TAQVRF`CFJ? MJJVE-5XH?YCE,HWCCDX=X>X.#&)JO0K>U"NSRW['$4?,(Y54+73E&T5I**JKF M]T5^A'[V.+%XXRLXDL25:TKK&_(XW1$4KU[B<>,RNXPN@A<7&3&*551VDQ;R3 M2?PUQ0LT'QDA<3LTN\ADEN[BGMW>$,3QR^-S*1_AT_R(#E4F/SPWQ_YIOY?8: M[P6.P=+512R/"=26!EUCH$5*>'336>PK!>8TMZ38<.*^59Q45# MZ(-*:TG=S,:8*^P"52$5=.<3B;-I+KMZ0J\F`@A?EUZH["SBM`\^/BC8@NNQ^ MU)J]5X?P+3]U!2/DI=ILD?FUYSI7`@'2V8`$YC"S4(4'G*M6*3X4]11X""`^,E.QS(=)UYOJIW4 MHZ+*PE@Z,&9I^+9@*F#CYLP\I^2WT7:SC,4I7E-[#?#&`3,V*-OT`2BF'^X9& M%4[#@+E$5]-CEF263<.<#GO$D\H;A.EY%IUDA18A'I\>*FYOX)=D55_%X0THV M-)U*#YIY(!A.I-D@DF,4WX<#&^PR8=89REP"JT`JAJ3!!35@716`V!$/@:EQ`.88[;^`W[3R2US MQ([F;HBW1MP6HQUGDS\,WL!1=3$WV$3S#BO`0]"`V*XAI,/@D'(^>2%J0\F:NP)-VWK M<,;$'!^/BY-0/)GIJF^_WK?0DQZK0Y(4 M8*55&*F$`$0!<,MDKR@C.&AUVT4#+?WFR=@RVI%M>G'>]QTV M+S#8Y+-1#?B(8!-_K;>7"7`*;2P3E]3%6&5,0LJ$=N!5*'='#"F6-0P([;K=Z M,206U."X%B2H12DE,[/28\IM(4`P"6;=&^3:6Z7D7:C6((Q8M79`HQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH$ M6[8@I:S/.<:[[-RR=*QNL7726W=S% M5\[:;5@V7;<;X]UR[-LVR%KNV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWD MC?BPWVW?3&NS>5DL'??VC>)Z8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\Q9 MUG#EOK6;EDSYTT7C5`VK+)<_/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?U M;L]TG[\<8^3+9?./F9EQ:Q=S*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]B M-LVTWZ&KT0`3T7J.FTO=]#J=(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CC MA7U0F#`E3J:!-W+S*]S>WRTVS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU] M2Q>O"]<<9]FHPA?$*W@S$-XOFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`.QTYE M-5TS9/>9QEZ2*_`%Q13[]HV?]L5Z4\MM.S8L7!##=Y:HS];WTB++^NI3J42GL M("/:*_'DU*Q.GT*=FB0\3IU$8?I.D7DEI%ISJVC>.^B31(M.'2HU*12QD32S! MZ>BYW62IJ4JM6J2*Q:=:0A@O+8YY"5\38C>WQ'KUI*&OW;?KE?/:-!F4Z= MY7[I;DGV)%]_VC4F9A_1ON30=6RG0?+P[?)#OW6)UL=T!-RIR2GJ9GW1BUZ)> MH8S6,9X3WS0,Z.-ZTP^RZ52B3Z:B!9PV=;L%0 M863]E>Y8.+[99G4V*U@56E4+:1NOX%2(-4@KRII9X;F[QA,F-<,8# M2OC<1SY]MPRC;PF+?C?FU=UNQKMPGV24SP\IIY0M/0[U`HRVGRS*1NCZC@!'1 M`X\CM#TQGL=RG'9^9Z^(3@G#'+GGB"$8I=G2D4JYCSEA2I?*;03;QN\1OVJ+Q MKL7"W>%<71ZI]XXRA?9Q5^4;9$\0K&?2E=CF./X^4RGCPCQ,^`-0R M2P,$"@````8`H[L5#PB:CMC4!```Z`D```D```!41T543E5-+D,-`@$2(Q05! M-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HY MQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KN> MV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)ZW M8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_[ M/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S4 M*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=3 M(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVM MS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XO- MFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`.QTYU=W5I6+L(;D`7T^,YNNJ\JZIP M&L[JJC57]])3RVT[-BQ<$$2\W#S[F?Q>6B1:7WTJE>@49P1ZA0>%QC9;U^V8# M8CEG/CDUJ].G4*PK[!406H5S7O'?))HT:E#I2:%@C<2;#8=; M*+7;.6[3=@:WZY;98OB;%3F/8NV3!1>S90PGM!GGMM_3U#[IJ'%>E^3&4=6\+ M[]#A8IX7]5K=IG/9JW8QH#G^?>?U!771M^=]AG96N0D2I@NCV9E\Q/6Z?=?9% M[0)7@UF#VV]=HO4Q'<'KPNRBKHJ>]$*ZFTXE^G2*\V"^[5TFL8:\\8)`/W4M! MQWJ8J31CV6***[K=@I"R_DIW+!S0:+,[6E]5*,.J*&)!6+_9,I/V-Y.YX[,Z] M^(!S4Q>M`J]!#GURI/(S+:0IVY.(;I"<2=UX59;^M'K++*-FR\L$'N&=='&?S MOE+F9C-^M1:&G&$::XG<9/:':D[6/X>U]13,J&!E:E4MI&V\BJQ*K<5:D7%E= M!>#L&D^8U$QK*.%S'_GTW3*M?K=THJ<;\^IN-R,>UP491O/4>J+V0E^5>G&Q7 MUA[MW<4QLB@;IRN]4#).8PVR70QHF#.$L#C<6W("-5\SO,] MHLT(98;&#[<90ONXJ_(-LB>(QF32U=P6,QJ%=GNOE#?+DSI/IACH'2)Z.ZW*+ ME`GR`GJ%UG!7KIC_!(YZ%.[&O-X7_)/="K,K2),F@`[WS+D`3\?L`DP)9?R5E M>BC0?W+D"?2JYB[/B6)7*N^X[WVNJM2ONZ(<];YA<`^GV;H\"0,86\MT']0;Y M1WG[C^&.CS%,]R$>2!:&6X%2E=UTIF6*9CAZ6F6//+'JV)4]HLQ;#&W3"*2$T M>5N*./X^?%+&Q5M(3!]02P,$"@`&``8`KKL5#[V/"47Y"0``PQD```D```!43 M1T544U12+D-A"GL'!AL&NPQ+`PD'"PD+"0<6!P@&!08'!@4V!Q87"PH&"`H+< M!085!`87!0H(!085!@HE!@@'&`H'"@@+!PL$)00E!`H&!`44!0DT!P87"1HK1 M_/S\^_O[#`LL"RP+/`LL*ZP,`2(C%!4V-VB)FML\!082(Q3E]I;W,6/%$CA*G M4%3\8\6-*W#5N(SV4KCMJE:67]@H^)/HZ3GY/V6[ZS_E6BM.)___/S[/W[%ZU MU]^YUWN+<-;U6N]:][;8E_MOL_1SWFOOWZWIC+][$\R[4?'^AO]WD_J M*_:OZ?S2W#ROAM^U?JW+=C5GJ4?GN;=U/YXS_Q_[,6WLY?*]-:[G_/-Z__TX: MP^717_I7^5I,_R8U+SO1F__+>_VJAMY_[*A:[_"1X_6/_ICW1&N[O-2S?UI]^+0]5JUV?ZZQV^I-Q?RQGN&_2-\[G**^)SE6$^:$UXU M$U\O\(_\^5>NO3S-Z[S6GDU[S^>S"5ZI6O.\$Z%QPAK1P MA)A%Q47%P:VH.*;&\W]_D-H9=T+[*8F]46O0[:F\`,M2O1?Y&C-^AU\VCZI#L M]JC^QE/2G=2VO?R7>RN;_.]0;^'X+O^'^8;V(W<[P[;H*=1-=-H.K==-:@^$5 M3NGZ[<>2OQ9>]7SR^BF@.;GJP4CC)!;/&XP\3X=O>]09)#$.BVKY;>M;;Y`@4 M=4A<];"(XN?3P'FOQ3ZWFL5^WGND;#2G MZ]Q2N\X[FN,Y??VY59P?3^-"O2MDJ;W/V:[;]R]C@?46Z(7]^RVCO125\>BO M(X$X2MC:&6T*C+_$[\MZLE^E8= M8^?F3@I\C\`JOE?B_)8]N?2"CWTK/Q#=YM-(6,]GK?!WJ0+SG/VN'A/"MD^_4 M5X\KI*J=:VZIZR'^D3J M20B_C.YI8?T?&^Z-_7\A[L$CE>.&<)/K=)++=6J_E)Z&V*%J8B=98J>6N_QK. M-\T6.^P0.\D1.SWN^/,Z[I@(+]S9[+*9G62:G8+GVZ7L31^%[/A"=C(A.P4RY M)QETO5ZWNDI\J_?9FI>]_18.H[1^5:]%ZQ)>]A*>Z@O\PGT3C&.=\AYI;W$P' MN8[&.=?O'Q+K4K_VO$I8)D'QA&4%,4A2^TT<=O^H' M.WP!DU/O*H)=%],B#_@Z.)SLGU,^I_9P*AOW/I[G=HY<$;1W>FG"O.%'R/DV[ M=KKS:[6Q"]QN)UREOT>X-8*-[O76TWY,K7T\>-Q!35"UEZ_R=_PMH'PL(B^KR M:;>Y1G0B[U;+_?$QA.HT;D.U.*&YQ(MT1<[N)R:/T&O?1#)92P-+I1$G#1F"=-_WH]S-4C#BN-D2X MP\T4%@0CJ>-U8._ZC?*PW,W23_O`*22WX/(+"VD>Q+M9RH\=+79!P0]EFN52* M\/U_W&8I[+#-?EQZ_4*#'7;8/PWLUR/EAOI#'G*5E>O"<04Z3T(%O+5?O"O54 MH4%^[+384'=<#<^%]D\PDKL&O7_[U3['>*=KP@Y[NS'`%/2+HN05L- MT&N]G=ZX+RE!`]]^?_%*A(5,\S_2@_*:V%Z5)%`K"[<-G$+J370D`ERVD@#M_ M&05,`I?_YY*P+\QR>&OALX6??&]!(;7F.UVL/P9X(SSG?Q/RZ2[8.E;@%_>=2_>&]8HB8U!A$I.?>0&7[J2VTGH*M0`+6B M5^O@J5>QK%$7VWY-4Q.CBA1M6;I"SEW,;0U*VJ>^&PF4;WT_X-DE?>KWNA`_8 M^\$KJ4\W'X`YOK#->T%9FTS[V:I$;O>Y6F%=*_NIK9E#K@QG-,XJ8Q692MJ`W M1TM#VI#LPQU=I)P-2<5J:;:6\?.N+9(V-+5ZHT+0Y3J"YQ[!,OX<\7'2&XW,< MH4.U8.=J^)I4J4VPLTJ%'9)*D2=XGHRZO5:GVQ^DA&9Z,E*0K,O8]4BCC*@%= M=Z1%FY>;,D(C':<_&=ZU9SX7\I/0";D!DL3X<%J[JT['PP+5DQ%@%LL^+Y!=S ME4CD+"W?Y2;XCR>J2!W&\/&9KV"GB7`A4,>5!XEB$F@=X3`HO]4W*9;):"X(P M8BXA,T$U2OE(OWKHF,@](DNN8Y(&@5ENEVU,"F9!L3IC,=R36(7Q,I-6%>+6?:O4:C4!SG,;4!R-5$Y/ZJ":@(#I^+[6OX M&EY]?#@U#5C.5L8\_^)_9,XDG^/X==B9P">]NY7$+)+*3N;+M[M3DU=]-`Q<]#V,73=2Y#B@A4SB"G6 M!D*V.F9YP1)62Z[F,/D-C6OIG[38X8;@/*;TE/#8.(T-CM4R1LDN8S'#<)PF' M@+B&8S8I`BW"1\*=K030'".,-T4G[V*[&>948;89PM MLQ;"M2.$CRV$MR6$ES@T_L%(74#A`E+E@A8L%HCH560+4)^/1<[!&Q5'!_/P) MV(,/BN;*^5ZK7<;=(2B"V-;<`@SEI;K@_`)#`0713ONYHJZ@TUI(M*@\6O,/@ M":(XE3W@\6"D_\,.6UB@B&](A$3:SPY&&I<02$.8IS]V;FQ*`6;O!J@7/;6`^P3H2Z$S*A[SL'0E02P,$8 M"@`&``8`H#2C$.?S,OL/"0``$!@```<```!41T]43RY#80I[!P8;!KL,2P,); M!PL)"PD'%@<(!@4&!P8%-@<6%PL*!@@*"P4&%00&%P4*"`4&%08*)08(!Q@*$ M!PH("P<+!"4$)00*!@0%%`4)-`<&%PD:*_S\_/O[^PP++`LL"SP++"NL#`$B0 M(Q05-C=HB9K;/`4&$B,4Y?:6]S%CQ1(X2E!4_&/%C2MPU;B,]E*X[:I6EE_8' M*/B3Z.DY^3]EN^L_Y5HK3B?__S\^S]^Q>M??N==[BW#7*8_#'F]5KO6O>VV)E M?[;[/T<]YK[]^MZ8R_>Q/,NU'Q_H;_=Y/ROVK^G\TMP\KX;?M7ZMRW8U9ZE'7 MY[FW=3^>,_\?^S%M[.7RO36NY_SS>O_].,/ET5_Z5_E:3/\F-2\[T9O_RWO]T MJH7+MUC=O^\99P/MRKW=S7"`U^KV'`O*%/N(TKR5]O5>\W]IVR-<=:6_5)[EU M/^?)?VF`-A_[?^WZ M*D)[7BH6N_PD>/UC_Z8]T1KN[S7.'^XG7*8__EHJ@-?M7DLW]:??BT/5:M=G& M^NL=OJ3<7\L9[AOTC?.YRBOB!-?+_"/_/E7KKT\S>N\W-_MUZ[E] MN-<5J\_GLPE>J5KSO!.A<<(:T8281<5%Q<&MJ#BFQO-_?Y#:&7="N M^RF)O5%KT.VIO`#+4MU5^L_0U>@V9M4<<-?K9OUZ'=7/DF7XM6TO_P;!?TKH! M4\++_V&^H?W(W,[KN`N03AKE8*3Q>.7?Z0IR)-@;C*Q/AV][U!DD,0_KW,N\':OOP.1#_L;.% M%PN]+,AYHVPP@X^ISF!]>8]P8UXX/LF>RX?.A#],][BL0.,\B[%@;&T_SSW>. M_[E#-M\'2ZB*/VY.]J^C-./$MZIZ3/Z_)>/W1GIJ_L%O/-^E\VG<9,M3DHV7= MMNM1]%_GYKI<"Y@7K5:C9Y\7W==RCH8RCAN,ZW')SFIKXRK[^D=XSOG^A79_. MW!X-!BSEN,$X!V(GW#\8U[^8-WFLWUJ[[I,]M+Y43+HY5M=LJP.=;77-L[HV) M/*YAAP>YX#UL]0HQPTPI_,.[-K"-A\2I3-\@+Y5W[7.G>XPZ_4#[++GVSY?L1R MX=XTW>HW"2M\N+A7C>NVG5EZK.,\UF*>5K<;N-Z@G1X.35G:8B'AH:[^7V;7; MZTB'")4*C/L!KUA!\*?7T;"REK0W&<:M7!+L/63UA*XT:[-_Z8.QBG\P3LW_(?_!>.@_)[ MJDG!>Y6W#J?YQ[,9.U29?JET'ROB.*:B3=/3OB;,[2*;;BQSYAA* MYN@0FH\$DZ8K0Y2;N%5-+?=T(W'B^(5M]3**\DNXV3J1YCI#-%F/=\99ZE[O) M0]"R:+S'?)XZNL92J'_:SPU&@!G'6L3?[URCVZN"GKP_S(X[_)X]#'G:AML M#+=%Q2NTT@9_=*SK"$9QX\:,]0>Z^>98?R>U-EVB:)36TG[YO``+WS'C[7EI'I;2&$SON9!;(>XVD,0TU&,&]R4_XJSR7Y?IRT^_3J37ZFI;-_1`>D M7G*N#_7KB.(U.]NZRE8[#4XR1XJ1%:K;A=,3X*F4!DMJOXG#[A]UAR]:7@;&7";R,5)<1(6CZQ;^=,>3_:6F_E]CO%WR6'U?8=6&<+KUTG()@= M!'4'O7_+]#Z/:3SM"S]QR5QKSAXOEY_<4$T^]8G*/5&Y<,QQ67R#N]'X:)U?I MR.O]0VDQW&@"%Q4'/5P?&_1:;ZN5#_L>NQHXFX-G6%E?\2& MKB05\5\8X2'@WF3P]^4'093.?:E9%+(5O%7HF@HK/"$8B1^1(WZ@('G.H3X`` MRJ8^8+.I#X#R8DL?T9`^7.\@PX8:C.\P-=][K;:J&$QYB+`H#Y?DLA('%SS(8 M3?!@7'E^3KV#O/0N`_')#152'$RV#'` M0#`IN*L#C6\*/+MWN83Z02Z45BA>VKM0UPJY%92W@1EHW!6,_K'4Z*SFQPG&Z M]3CYRF90/(<==J@%/`8-N::D6N[G;6VQK+30;Z).=,\YNH?*S?$]0/,>(IOW+ MD-F\1P_R>!\-AF` M&O'2B'\1)2W:AQ8+B0N691HR5&.5B2^*0TZ`#@_;0HE\*O2A<$-$C[',A$>BQ M--A@[-E(C^]TN*_J4$L#!`H````&`$A.#`U_;Z9W]V98-.X?=S70_W+IBV:8=\U^2Z=YTK&ZQ==);=W-7SMIM6#9=. MMQOCW7+LVS;(6N[8-,\;9)W_#2)ZL\WK0A]GFK9M6CK3+B=M3?>-^+#?;=],Y M:[-Y62P=]_:-XGI@'PVS+BLV#S!Y5L[XID.U8`-4#:LLES\^!DK4_NJ[QY8I*]N&3?/6\/I8.O_,_4&.N=]NSW2?OQQCT MY,ME\X^9F7%K%W,J)%78,[O1++UBO>;]JC6(*4WLS'-7FW$VX[TVS;3?H:O1' M`!/1>HZ;2]WT.ITCQMHG6T>?+(L73IFVOMHUB"$/7V7=;><0L^.%?5"8,"5.] MIH$W9X^V&>\\AL_E/./"KK==YUG*""35+%Z\+UQQGF MV:C"%\0K>#,0WB^:6YV;:5*A4H-*S4+87=7I4*I)GSJI'D`[':MK\F/L?%MG+ M>8(P?!RQ^FQ'-9PT3WBAH2J_IYHL&>S#S][WTB+.^NI3J42G+".JW&W'S"_QS MY-2L3I]"G9HD/*Y=7&;#91G6K-DQ?FX6\T::57KEI+ISJ\C>.YJ;Y@]"O'I.: MHE31WE&FW`&.)%ITZE"I2:%$A?RTSE0**3&G3L,[MH=!=H/0M][>]31;U^T82 MQK1J45C6W_Q8BM-O[X`/(!>1-1W8#23CW2Q.BT&K"A]2%KF3C\K8T#J,]XENZ;Z\KL!)D M.9)KPX*P0S9JP3^1Q95?>-TP/(0KT@BGJRI9&A#S/U'$L=4`9JVY6Q"[!"$ MTBK\-''ZW6X8.VS.!RD2ZE"1+F9!V&*S,(\,0CSY9NI%:Q'X;4NB\"*^B28C% M'TUBM)5IBF48KM27*WX98LC_B\BWW!?':U*Z#O1^.?<.7,&?!#>K`$?,2?,'.]!&#-&./B;-,`!+^BF`1_1! MIDT;\($W%&R-N8!#Y<%'F`O8,^##QI`:N#;@P^*<84?@QY@:>LT:\8&+(SXLH MS1CQ@2^31GQ8&8P+7!KCH#&AX(,P!U[(?7?\5K32TYI9&'`1JXM6< MSRE9IX66/3.J><84])OGYBX@?JE"!%HVY-4JU4E5$D-;A9+*L97H99I;.=&8X MF["+'P%E*7G(VT4SNL@MER1*(PYW'K%F[B(QR:RJHTR#DTQA*/=.!!"$)^PV) MF#Q,:C,I+\0W71??R:!C)L(Z\B#6"BEFUKX>,R,OB[J!<<9'GN027<["-X/59BXUTZ#H"(GKE283-#FEQ#>!3Z%M($\D!1=>&<,AE6G-9!EGB&M#DRG0@DW1S.0S]YB@YS`H'SY^!M5'. M8DG694T7S4/'O8/BW9IQ,V_7357U(%]18[,MHY=@874>D8)S@A4)%SI;GVT4. M89"Y#G9)0O:1&#C\'6SA7%-A4)]CP4Y%BX.DUG77PV=?,H( M"`=6@\,I.*0#!V/QA?6$8^>0N#B'IMVH+EB33I%W=W"C@.U;% MM:2O7/%?V0_S6F4/4/T.Z<@K>X*`GR!;@CP)\X35F;#/\+F'(SNLEB==GJA&V MC`MG;'P$C2FO$Y1#:E_G<$W9<6$'^P_-F_>16@R-53$T3FTJ")362/JCF^B?= M(;"$.1]J8%W;7XRBPGA@_Q(X`DZ*<)4O8IJ2?0RA_8>QA$R#@G:-^)]T8AM.( M,C&XS7)HD"J*6!N<$9HB;"5#`RQ6V&7G)`9X%':UBC,1@Z)&<5F4?]LL^)0L5 M6`S4,S/N;CX4\$2"2B!-D:D+3P##G&C5HZ!%N+JQX,%L$#F)J-F86H"[H=MM* MBPB@YY( M,O:(^_/3SC<;E+7WX`]]V\9-0\$PH(O#H81[',%`\E%(Z$/CB%)(/1':QX%#X MF10LQ/U"2&Y"(`349@,'LS&``&PY3?B`0``"P```$U!2T5'0T,N1 M3$E"#0(!$B,4%38W:(F:VSP%!A(31,7VEO='@IPZ=.A4D$G)Z@0)%.7(E$W#= MKBU[!'J[9)M6+,B9+F."S"GSI0SA#3-G0P7HVVE9NFC#CET+LLWXFTW+MBQ(A MLV_E@C0JMRP9Y)UV+EJ0=,O*;6,_P[J!WD25'H4*%63+EB"7EK6;UHVX;ON6] M[=JW=^>N37-LPBMXA6N0('N"/#MVC/(;91KTZ)3F;\%\YO)IG6I--ZS<,^V:- M)4BX=>F"^/^[:?(UR+QOL`_8:%"U)._*;3O]:W"_9G^I7I4Z%*BPZEHNX)Z7![6;=T7;Y)[F;9ACVCO$$L= M=[=UVU0_%_B=P+G/I2N'O+^E^^;XD-?3GX,\P!M=33;MV33%THSZLTF_KMSEI MU*I&C2;%6G1*E-IE63QE+FUW.:;XQ:HAWF'GMAFOUNZW.H:=)(HD=TH0Q4=DI M2]XMWY)4\7[$/^:\9:^R9$H=ZT<4/L7V"E(AN4'&!2&>!!$>AHX-4$L#!`H`` M```&`%B<51F&!`EO>@$``+\!```+````34%+14U30RY,24(-`@$2(Q05-C=HY MB9K;/`4&$A-$Q?:6]TOR37(WRS;L&>4-8KF[K=NF^KDJ3-#@SR^* M!U=--NW9-,/23/JS03]S=SFUJE&C2;$6G7+G=ED6SY++VEV.*7ZQ:HAWV+EMZ MPN>8YJW#?VU5?15657QNF5@W^I:DBO8C_C'EA[V0DBEUJ!_?^!3ZJTGQG(B"P``01H```L```!415)-0T%0O M+DQ)0@\`$@,D%38G.#EJ>TR=;A\)!@$3-.7VEO?A-QC>@O`"GG'`"P$FI'NVB M+-VR;NFZ'`L>4?,`1Q]X)I$C/@#N3:>"'.H6<0+D/S-EFE3HT*(E$3]8]J=,W MB3H-VK3H5!?3+A>Q@>@[PV3[5!VRA@XXU.I-RS60-TCTJ-2G5:$RI'JT*-6BY M3JE^(1XK58)#GQ(M6O`KT:!4@Q(@U@+/.YU2_5>A4Z<.&':+F.(>*4R!`PD&- M_):L,@$6-!AP6[*X]<&#`1$DR]4C3!CPH&8$0?[_P/\$_PNTR@G*/C"@0($!$ MZ@<:L&A`X(P5K/]U+EVY;((\0+:T&71YLVG=DOU"W/,`+S/^L>UFNNQLY2#[Q MV;=TQZ(-@RQN5CO:.I;MV[EE_NFQ;>$(N>C?PCG:#QQ3T-.$[>#OOWZY'Z[8W MNF8!ACEK26YCT><%^!62ELRLO_R)X)/[MPTAVH1"PFH>/"2ADZYO7')`@/(12 M$X!>=,#HH/CT@"CH5S'\R>H%7B7@V:-/;G'871I M%P]?;!6AR5'(FTQL`4M+A:JI7@<3)YC8*/_$5OTOA%YW"[LJ/H@YT_)T"^(:/ M^O5F7_"\RL:^X8FN!C>T@H8[W^%, M=&WC8OOU'-AIW``)0D&'5H#T=3][75R^Z[*W.`/P`7K`"AX?5NMCRATP/3ZLU M?#$RK;2NP/5P`>=_29?GC!`H MW`JFAK5J+]M?!+4]I%R?\/BBC*R;(9I*,^1,X)G7!\7]0&C''>%H1-AT7<^X6 M,V#K!FS0A7&CP%85V%B8T02NQ'^.K%L`Z],;NMZH`K)F$`1Z_0,^XA3_02>\_ M`2=0Q?,WB6,S'\=-UNU@33&)IJN@2/-A0\0-J3CP&MS0#ZXMG'#:UPD=WO.MF M>^CQ">@-F!GK2G5R_@K0.4JK!)LKMIJP>.'.Q0%W;A[']2[.)ODSR6-)]BG)& M.TD^J-6%S5-:/=@^+OC.?5//%;QH.V.I#Y7:L!F:>U:I#YL M%:5G/M*J0.(>(F?B&88=(F?3H&W\FCSZ4IL.#0H5H)QD9FRSO=RV8\/"2?870 MO_W8%\Z(9-RW(GNG\RB0@$)C!:^E9MF&/0,H+T;D'*",`!J?$R@`D#8"!=T@Q M4-0HTZ!'!`6@AB-5=0Q`4'R0JU*"X@T$!8!.8=)(M'):#5XCI$7C7[B,9=E38 MZ3K0!?X$+1F`KF-@:-;59*AA7^3J)KHT;IT`H=@&M`%>Q^E&82T'$IN4L?.+* M3:IQ97>OBYP8?,T3F%S.:W-\L;=M_&C`NJM`1W"'/,#M/!2'%`#:83JOR.FO> MF9>HO(E+:#QO,.P).3.!?)`>'NZV;AO'_]K#0SS[KX<'>$*G59LP/D#!`Y?&\ M^/J#\0&@/0R^IYU+-NW9M'0L'WA>M`".S!9FKU?Y0!_H$[2URD=3J'PP;Y#*O MIQ@9WD`NH9DN%[T>-&S M_<&:<=NB#K/N@>;Y">GU&8R-%%\OH9'G?]^MO[/WWY@H]`#%V5O1))2'GU9\J M2RFZMO+]81Z'#)<3;,\8/"6\GD`E4#@J8*7I@62-<+G*;_/`V#24FN#9,N.?3,\P.R,3X2>DWW[R MM>S<,;0'R.!M%>T![DE/RM.$K(&BLWU::T``CTO=6Y1\UN,"O2!/T`Y`.JK4+ M`.A,2@WP@0Q*37O2+:"Q5$+#I0VPC43@T.%\JBO`*I+QXJL"A*(\#GHQ],78` MEM8P(D>YMN0">V-$BI0N#6?DS!<7V7,7%)G<`*=X04ZPX;KC)>#G MKE`P1',=8-&-8A&:9>A6H=R&=!C[RIRD9^:9W^,-$E!TGV$K]C>ML:S*T-$%A MFKFFU0"`G+$::`6K\5.J3U(#H*):#/4VFQY01K)*2`W=]QE4:KB"9'62&IHK! M@P?0F!VNW+=C7/.Y`'DR7@";/LLH' MO:ONI!CM[<$UC"2@.P36)>E&F.X]RO_AOS;9<,JOWW9Y?#VU:[8[CHOIUVOB] M'+1!*^A2ZT;KM+[L1XR2O\5-7G)]SAX_SG_?E`W?.U_E@.,1 M'8GQ!(Q]XW__R(S]1/,+C-V,\2:,/;E_%J5]*D'CUCDW!U@<\^?BE(1W)+PBY MX0D)[T?X.\+/$9Z-\&:$!R.\%N&E".]$>"3""Q%>A_`VA&\A?`KA2PC_07@,7 MPE,0OH'P"80?^)EX_\[$]15/3WAXPJM;_ESQX83O)KPUX:4)__PS\V,FR8490 MK^M@^2WH9PG?JGQ5Q9,2'I3PDH1')!Q2$P\D/!SATYP?YF8YE^2Q"!]%^!["/ MWQ!^AG!`3?R$\".$#R%\!^$S",^P\T;0%FI=GSZ%.A5@23+"PY1!K#.(/_7JF ML'#KZ+Q>_4^O3C3KH5<'W"#4*ANS5P>HE2)=G>5$'9(3(5X=D1,!Y@*""5^A2 MTK$F*P!"AYG%3A6N=.H_F M:%0#I$T!%H4[O-SMZ)S9\18QU2WL\C4`.!#C]PP0P8$+!MP]3!7%NA/@!VK8\ MDA,!9@1HPQD-%$$/)[HWW1!L-!>2FV4;]FS(I``15+!D2,0`4A@T(A:6<+=V* MPV%1X3:0R&')[!95P!X`]Q<,^`!7S"4,<";)"=.P.(DNLWJ'P!``!W`@``V M!0```$9)3$53#0(!$B,4%38W:(F:VSP%!A(31,7VEO<;*C2:EFW9N2#3N@5)4 MMZSL=EBU(HW++DB'>:>>B&<]!SGU;5^[88 M,OQ_M"A5IE)!@@0Y9/B"N\R;-V6"A(FS94R9+7':`-])IQ)->C0I%?#XF#-KN MV@"/IQ+L19V`Q^((WS#`5_>&&;-ESAG@M5&F08^(P\.D>2-8R@#?.&^`UTZK^ M-AD:6W.F#?#P4ZE*`8^W63-G#?#(3ZD^!5$4UF9,&T._QM`]`WSC`'^H58(5< M>.2:-&?B*`KGY@Q*EFQ:NFG?P#F;AEU;ULR5/*R;/#<YWO]Q/SBVU"?X.\A3Q=(-8>W*V^Z;>\@4^^#SV=-,I]A"@])@PG!SV(#9-C M.U;NFSBT6;H@^"V?!X72'V\##AV#'P)\'%\0ACY02P$""P`*````!@":`0P-S MJ*QZ1FH%``#4"@``"``````````!`"``````````1D=%5$Q2+D-02P$""P`*R M````!@"F`0P-M*4E!OP"``!,!0``"0`````````!`"````"0!0``25-$24=)1 M5"Y#4$L!`@L`"@````8`(!AA&G"LJ0#N"@``FAD```H````````````@````+ MLP@``$Q)0E1%4DU#+D%02P$""P`*``8`!@`%&$$:MIR.V)<+``#"'P``"0``W M```````!`"````#)$P``5$=%5$5.5"Y#4$L!`@L`"@````8`DKL5#Z_;B%XL/ M!```_P<```H``````````0`@````AQ\``%1'151&3$%'+D-02P$""P`*````- M!@"CNQ4/")J.V-0$``#H"0``"0`````````!`"````#;(P``5$=%5$Y532Y#6 M4$L!`@L`"@`&``8`KKL5#[V/"47Y"0``PQD```D``````````0`@````UB@`L M`%1'15135%(N0U!+`0(+``H`!@`&`*`THQ#G\S+[#PD``!`8```'````````R M``$`(````/8R``!41T]43RY#4$L!`@L`"@````8`2$X,#7]OIG=S"```/A4`( M``<``````````0`@````*CP``%105513+D-02P$""P`*````!@#O67X9CF*M4 MBXP!``#>`0``"P`````````!`"````#"1```34%+14=#0RY,24)02P$""P`*, M````!@!8G%49A@0);WH!``"_`0``"P`````````!`"````!W1@``34%+14U3, M0RY,24)02P$""P`*````!@`@&&$:;XR-XB(+``!!&@``"P```````````"``1 M```:2```5$5234-!4"Y,24)02P$""P`*````!@`@&&$:>NLWJ'P!``!W`@``9 M!0`````````!`"````!E4P``1DE,15-02P4&``````T`#0#*`@``!%4`````V `` end size 22500 nethack-3.6.0/sys/share/unixtty.c0000664000076400007660000002502412610522241015743 0ustar paxedpaxed/* NetHack 3.6 unixtty.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (Unix) version */ /* With thanks to the people who sent code for SYSV - hpscdi!jon, * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */ #define NEED_VARARGS #include "hack.h" /* * The distinctions here are not BSD - rest but rather USG - rest, as * BSD still has the old sgttyb structure, but SYSV has termio. Thus: */ #if (defined(BSD) || defined(ULTRIX)) && !defined(POSIX_TYPES) #define V7 #else #define USG #endif #ifdef USG #ifdef POSIX_TYPES #include #include #define termstruct termios #else #include #if defined(TCSETS) && !defined(AIX_31) #define termstruct termios #else #define termstruct termio #endif #endif /* POSIX_TYPES */ #ifdef LINUX #include #undef delay_output /* curses redefines this */ #include #endif #define kill_sym c_cc[VKILL] #define erase_sym c_cc[VERASE] #define intr_sym c_cc[VINTR] #ifdef TAB3 /* not a POSIX flag, but some have it anyway */ #define EXTABS TAB3 #else #define EXTABS 0 #endif #define tabflgs c_oflag #define echoflgs c_lflag #define cbrkflgs c_lflag #define CBRKMASK ICANON #define CBRKON !/* reverse condition */ #ifdef POSIX_TYPES #define OSPEED(x) (speednum(cfgetospeed(&x))) #else #ifndef CBAUD #define CBAUD _CBAUD /* for POSIX nitpickers (like RS/6000 cc) */ #endif #define OSPEED(x) ((x).c_cflag & CBAUD) #endif #define IS_7BIT(x) ((x).c_cflag & CS7) #define inputflags c_iflag #define STRIPHI ISTRIP #ifdef POSIX_TYPES #define GTTY(x) (tcgetattr(0, x)) #define STTY(x) (tcsetattr(0, TCSADRAIN, x)) #else #if defined(TCSETS) && !defined(AIX_31) #define GTTY(x) (ioctl(0, TCGETS, x)) #define STTY(x) (ioctl(0, TCSETSW, x)) #else #define GTTY(x) (ioctl(0, TCGETA, x)) #define STTY(x) (ioctl(0, TCSETAW, x)) #endif #endif /* POSIX_TYPES */ #define GTTY2(x) 1 #define STTY2(x) 1 #ifdef POSIX_TYPES #if defined(BSD) && !defined(__DGUX__) #define nonesuch _POSIX_VDISABLE #else #define nonesuch (fpathconf(0, _PC_VDISABLE)) #endif #else #define nonesuch 0 #endif #define inittyb2 inittyb #define curttyb2 curttyb #else /* V7 */ #include #define termstruct sgttyb #define kill_sym sg_kill #define erase_sym sg_erase #define intr_sym t_intrc #define EXTABS XTABS #define tabflgs sg_flags #define echoflgs sg_flags #define cbrkflgs sg_flags #define CBRKMASK CBREAK #define CBRKON /* empty */ #define inputflags sg_flags /* don't know how enabling meta bits */ #define IS_7BIT(x) (FALSE) #define STRIPHI 0 /* should actually be done on BSD */ #define OSPEED(x) (x).sg_ospeed #if defined(bsdi) || defined(__386BSD) || defined(SUNOS4) #define GTTY(x) (ioctl(0, TIOCGETP, (char *) x)) #define STTY(x) (ioctl(0, TIOCSETP, (char *) x)) #else #define GTTY(x) (gtty(0, x)) #define STTY(x) (stty(0, x)) #endif #define GTTY2(x) (ioctl(0, TIOCGETC, (char *) x)) #define STTY2(x) (ioctl(0, TIOCSETC, (char *) x)) #define nonesuch -1 struct tchars inittyb2, curttyb2; #endif /* V7 */ #if defined(TTY_GRAPHICS) && ((!defined(SYSV) && !defined(HPUX)) \ || defined(UNIXPC) || defined(SVR4)) #ifndef LINT extern /* it is defined in libtermlib (libtermcap) */ #endif short ospeed; /* terminal baudrate; set by gettty */ #else short ospeed = 0; /* gets around "not defined" error message */ #endif #if defined(POSIX_TYPES) && defined(BSD) unsigned #endif char erase_char, intr_char, kill_char; static boolean settty_needed = FALSE; struct termstruct inittyb, curttyb; #ifdef POSIX_TYPES static int speednum(speed) speed_t speed; { switch (speed) { case B0: return 0; case B50: return 1; case B75: return 2; case B110: return 3; case B134: return 4; case B150: return 5; case B200: return 6; case B300: return 7; case B600: return 8; case B1200: return 9; case B1800: return 10; case B2400: return 11; case B4800: return 12; case B9600: return 13; case B19200: return 14; case B38400: return 15; } return 0; } #endif static void setctty() { if (STTY(&curttyb) < 0 || STTY2(&curttyb2) < 0) perror("NetHack (setctty)"); } /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by startup() in termcap.c and after returning from ! or ^Z */ void gettty() { if (GTTY(&inittyb) < 0 || GTTY2(&inittyb2) < 0) perror("NetHack (gettty)"); curttyb = inittyb; curttyb2 = inittyb2; ospeed = OSPEED(inittyb); erase_char = inittyb.erase_sym; kill_char = inittyb.kill_sym; intr_char = inittyb2.intr_sym; getioctls(); /* do not expand tabs - they might be needed inside a cm sequence */ if (curttyb.tabflgs & EXTABS) { curttyb.tabflgs &= ~EXTABS; setctty(); } settty_needed = TRUE; } /* reset terminal to original state */ void settty(s) const char *s; { end_screen(); if (s) raw_print(s); if (STTY(&inittyb) < 0 || STTY2(&inittyb2) < 0) perror("NetHack (settty)"); iflags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF; iflags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF; curttyb.inputflags |= STRIPHI; setioctls(); } void setftty() { unsigned ef, cf; int change = 0; ef = 0; /* desired value of flags & ECHO */ cf = CBRKON(CBRKMASK); /* desired value of flags & CBREAK */ iflags.cbreak = ON; iflags.echo = OFF; /* Should use (ECHO|CRMOD) here instead of ECHO */ if ((unsigned) (curttyb.echoflgs & ECHO) != ef) { curttyb.echoflgs &= ~ECHO; /* curttyb.echoflgs |= ef; */ change++; } if ((unsigned) (curttyb.cbrkflgs & CBRKMASK) != cf) { curttyb.cbrkflgs &= ~CBRKMASK; curttyb.cbrkflgs |= cf; #ifdef USG /* be satisfied with one character; no timeout */ curttyb.c_cc[VMIN] = 1; /* was VEOF */ curttyb.c_cc[VTIME] = 0; /* was VEOL */ #ifdef POSIX_JOB_CONTROL /* turn off system suspend character * due to differences in structure layout, this has to be * here instead of in ioctl.c:getioctls() with the BSD * equivalent */ #ifdef VSUSP /* real POSIX */ curttyb.c_cc[VSUSP] = nonesuch; #else /* other later SYSV */ curttyb.c_cc[VSWTCH] = nonesuch; #endif #endif #ifdef VDSUSP /* SunOS Posix extensions */ curttyb.c_cc[VDSUSP] = nonesuch; #endif #ifdef VREPRINT curttyb.c_cc[VREPRINT] = nonesuch; #endif #ifdef VDISCARD curttyb.c_cc[VDISCARD] = nonesuch; #endif #ifdef VWERASE curttyb.c_cc[VWERASE] = nonesuch; #endif #ifdef VLNEXT curttyb.c_cc[VLNEXT] = nonesuch; #endif #endif change++; } if (!IS_7BIT(inittyb)) curttyb.inputflags &= ~STRIPHI; /* If an interrupt character is used, it will be overridden and * set to ^C. */ if (intr_char != nonesuch && curttyb2.intr_sym != '\003') { curttyb2.intr_sym = '\003'; change++; } if (change) setctty(); start_screen(); } void intron() /* enable kbd interupts if enabled when game started */ { #ifdef TTY_GRAPHICS /* Ugly hack to keep from changing tty modes for non-tty games -dlc */ if (!strcmp(windowprocs.name, "tty") && intr_char != nonesuch && curttyb2.intr_sym != '\003') { curttyb2.intr_sym = '\003'; setctty(); } #endif } void introff() /* disable kbd interrupts if required*/ { #ifdef TTY_GRAPHICS /* Ugly hack to keep from changing tty modes for non-tty games -dlc */ if (!strcmp(windowprocs.name, "tty") && curttyb2.intr_sym != nonesuch) { curttyb2.intr_sym = nonesuch; setctty(); } #endif } #ifdef _M_UNIX /* SCO UNIX (3.2.4), from Andreas Arens */ #include #define BSIZE (E_TABSZ * 2) #define LDIOC ('D' << 8) /* POSIX prevents definition */ #include int sco_flag_console = 0; int sco_map_valid = -1; unsigned char sco_chanmap_buf[BSIZE]; void NDECL(sco_mapon); void NDECL(sco_mapoff); void NDECL(check_sco_console); void NDECL(init_sco_cons); void sco_mapon() { #ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && sco_flag_console) { if (sco_map_valid != -1) { ioctl(0, LDSMAP, sco_chanmap_buf); } sco_map_valid = -1; } #endif } void sco_mapoff() { #ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && sco_flag_console) { sco_map_valid = ioctl(0, LDGMAP, sco_chanmap_buf); if (sco_map_valid != -1) { ioctl(0, LDNMAP, (char *) 0); } } #endif } void check_sco_console() { if (isatty(0) && ioctl(0, CONS_GET, 0) != -1) { sco_flag_console = 1; } } void init_sco_cons() { #ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && sco_flag_console) { atexit(sco_mapon); sco_mapoff(); load_symset("IBMGraphics", PRIMARY); load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); #ifdef TEXTCOLOR if (has_colors()) iflags.use_color = TRUE; #endif } #endif } #endif /* _M_UNIX */ #ifdef __linux__ /* via Jesse Thilo and Ben Gertzfield */ #include #include int linux_flag_console = 0; void NDECL(linux_mapon); void NDECL(linux_mapoff); void NDECL(check_linux_console); void NDECL(init_linux_cons); void linux_mapon() { #ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && linux_flag_console) { write(1, "\033(B", 3); } #endif } void linux_mapoff() { #ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && linux_flag_console) { write(1, "\033(U", 3); } #endif } void check_linux_console() { struct vt_mode vtm; if (isatty(0) && ioctl(0, VT_GETMODE, &vtm) >= 0) { linux_flag_console = 1; } } void init_linux_cons() { #ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && linux_flag_console) { atexit(linux_mapon); linux_mapoff(); #ifdef TEXTCOLOR if (has_colors()) iflags.use_color = TRUE; #endif } #endif } #endif /* __linux__ */ #ifndef __begui__ /* the Be GUI will define its own error proc */ /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *, s) { VA_START(s); VA_INIT(s, const char *); if (settty_needed) settty((char *) 0); Vprintf(s, VA_ARGS); (void) putchar('\n'); VA_END(); exit(EXIT_FAILURE); } #endif /* !__begui__ */ nethack-3.6.0/sys/share/uudecode.c0000664000076400007660000001466612536476415016050 0ustar paxedpaxed/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Modified 12 April 1990 by Mark Adler for use on MSDOS systems with * Microsoft C and Turbo C. * * Modifed 13 February 1991 by Greg Roelofs for use on VMS systems. As * with the MS-DOS version, the setting of the file mode has been disabled. * Compile and link normally (but note that the shared-image link option * produces a binary only 6 blocks long, as opposed to the 137-block one * produced by an ordinary link). To set up the VMS symbol to run the * program ("run uudecode filename" won't work), do: * uudecode :== "$disk:[directory]uudecode.exe" * and don't forget the leading "$" or it still won't work. The binaries * produced by this program are in VMS "stream-LF" format; this makes no * difference to VMS when running decoded executables, nor to VMS unzip, * but other programs such as zoo or arc may or may not require the file * to be "BILFed" (or "unBILFed" or whatever). Also, unlike the other * flavors, VMS files don't get overwritten (a higher version is created). * * Modified 13 April 1991 by Gary Mussar to be forgiving of systems that * appear to be stripping trailing blanks. * * Modified 28 February 2002 for use on WIN32 systems with Microsoft C. * * Modified 08 July 2006 to cast strlen() result to int to suppress a * warning on platforms where size_t > sizeof(int). * * $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ #ifndef lint static char sccsid[] = "@(#)uudecode.c 5.5 (Berkeley) 7/6/88"; #endif /* not lint */ #ifdef __MSDOS__ /* For Turbo C */ #define MSDOS 1 #endif #ifdef _WIN32 #undef MSDOS #undef __MSDOS__ #ifndef WIN32 #define WIN32 #endif #endif /* * uudecode [input] * * create the specified file, decoding as you go. * used with uuencode. */ #include #ifdef VMS #include #include #else #if !defined(MSDOS) && !defined(WIN32) #include #endif #include /* MSDOS, WIN32, or UNIX */ #include #include #include #endif static void decode(FILE *, FILE *); static void outdec(char *, FILE *, int); /* single-character decode */ #define DEC(c) (((c) - ' ') & 077) int main(argc, argv) int argc; char **argv; { FILE *in, *out; int mode; char dest[128]; char buf[80]; /* optional input arg */ if (argc > 1) { if ((in = fopen(argv[1], "r")) == NULL) { perror(argv[1]); exit(1); } argv++; argc--; } else in = stdin; if (argc != 1) { printf("Usage: uudecode [infile]\n"); exit(2); } /* search for header line */ for (;;) { if (fgets(buf, sizeof buf, in) == NULL) { fprintf(stderr, "No begin line\n"); exit(3); } if (strncmp(buf, "begin ", 6) == 0) break; } (void) sscanf(buf, "begin %o %s", &mode, dest); #if !defined(MSDOS) && !defined(VMS) && !defined(WIN32) /* handle ~user/file format */ if (dest[0] == '~') { char *sl; struct passwd *getpwnam(); struct passwd *user; char dnbuf[100], *index(), *strcat(), *strcpy(); sl = index(dest, '/'); if (sl == NULL) { fprintf(stderr, "Illegal ~user\n"); exit(3); } *sl++ = 0; user = getpwnam(dest + 1); if (user == NULL) { fprintf(stderr, "No such user as %s\n", dest); exit(4); } strcpy(dnbuf, user->pw_dir); strcat(dnbuf, "/"); strcat(dnbuf, sl); strcpy(dest, dnbuf); } #endif /* !defined(MSDOS) && !defined(VMS) */ /* create output file */ #if defined(MSDOS) || defined(WIN32) out = fopen(dest, "wb"); /* Binary file */ #else out = fopen(dest, "w"); #endif if (out == NULL) { perror(dest); exit(4); } #if !defined(MSDOS) && !defined(VMS) && !defined(WIN32) /* i.e., UNIX */ chmod(dest, mode); #endif decode(in, out); if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) { fprintf(stderr, "No end line\n"); exit(5); } exit(0); /*NOTREACHED*/ return 0; } /* * copy from in to out, decoding as you go along. */ void decode(in, out) FILE *in; FILE *out; { char buf[80]; char *bp; int n, i, expected; for (;;) { /* for each input line */ if (fgets(buf, sizeof buf, in) == NULL) { printf("Short file\n"); exit(10); } n = DEC(buf[0]); if ((n <= 0) || (buf[0] == '\n')) break; /* Calculate expected # of chars and pad if necessary */ expected = ((n + 2) / 3) << 2; for (i = (int) strlen(buf) - 1; i <= expected; i++) buf[i] = ' '; bp = &buf[1]; while (n > 0) { outdec(bp, out, n); bp += 4; n -= 3; } } } /* * output a group of 3 bytes (4 input characters). * the input chars are pointed to by p, they are to * be output to file f. n is used to tell us not to * output all of them at the end of the file. */ void outdec(p, f, n) char *p; FILE *f; int n; { int c1, c2, c3; c1 = DEC(*p) << 2 | DEC(p[1]) >> 4; c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2; c3 = DEC(p[2]) << 6 | DEC(p[3]); if (n >= 1) putc(c1, f); if (n >= 2) putc(c2, f); if (n >= 3) putc(c3, f); } #if !defined(MSDOS) && !defined(VMS) && !defined(WIN32) /* * Return the ptr in sp at which the character c appears; * NULL if not found */ #ifndef NULL #define NULL 0 #endif char * index(sp, c) register char *sp, c; { do { if (*sp == c) return (sp); } while (*sp++); return (NULL); } #endif nethack-3.6.0/sys/unix/Install.unx0000664000076400007660000004004112536476415016114 0ustar paxedpaxed Instructions for installing NetHack 3.6 on a UNIX system ======================================= NB: We are gradually replacing this process with the process documented in the file NewInstall.unx. 0. Read this entire file before starting, and come back to the Notes below if you have any problems. If you are trying to use X11, also read all of win/X11/Install.X11, or read win/Qt/Install.Qt if you are using Qt or KDE under X11. For help in controlling and running the game after it is installed, see the '?' command within the game and doc/Guidebook (non-installers want to know about those things too). 1. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, util, sys/share, sys/unix, win/tty, win/X11, and win/Qt. You may have other subdirectories under sys and win, but they will not affect compilation for a UNIX system. If you do not follow this structure, the Makefiles will not function properly. The .c files for the main program belong in src, those for utility programs in util, and UNIX-specific ones in sys/unix. All the .h files belong in include, the documentation in doc, and assorted data files in dat. Some UNIX versions may also be interested in sys/share's random.c or its lex/yacc output, as explained in note 11. (A more detailed explanation of the directory structure may be found in Files, which should be in the top directory.) 2. Your Makefiles may still be in sys/unix with tags on the end of them. If so, run "sh setup.sh hints/unix" in that directory to distribute the Makefiles to places they can do their work. (If later official patches change these Makefiles, setup.sh should be rerun to make sure you use the current copies.) 3. Go to the include subdirectory and edit config.h according to the comments to match your system and desired set of features. Similarly edit unixconf.h. Please see the "Notes:" section, below, for some configuration hints for particular systems. 4. If you want to, look through system.h. This file attempts to match the types for system calls and library routines with various flavors of operating systems. Leaving this file alone is unlikely to cause worse problems than lint errors, but it's worth checking if you get compile errors, especially if you have an unusual system. 5. Go to the src subdirectory and look at the top of topten.c. You may want to change the definitions of PERSMAX and PERS_IS_UID here to get different behavior from the high score list. 6. Edit the top sections of the src and util Makefiles. (If you are doing a full recompile, or if you got your files from someplace besides the official distribution, type 'touch makedefs.c' to make sure certain files (onames.h, pm.h) get remade instead of relying on the potentially troublesome timestamps.) Then type 'make' in src and go get a cup of coffee or take a nap, depending on the speed of your system. You should now have created the game executable. 7. Go back to the top directory and edit that Makefile, explaining where you want everything to be installed. Make sure that you follow the comments about setting HACKDIR -- the installation process will wipe out the contents of the directory you point it at, under the assumption that it's debris from an old version of NetHack. If this is not the case, you'll want to install somewhere else, or comment out the rm under the install target. The Makefile assumes you want to run NetHack setuid 'games' to cut down on possible tampering; it's fairly straightforward to comment out the appropriate chmod if you don't want that, or to change any of the rest of the procedure. (Note that if you don't want to run NetHack either setuid or setgid, and people in more than one group will be playing it, you'll need to go back and set FCMASK to 0666 in unixconf.h and let everybody fiddle with the files NetHack creates.) If the tbl, nroff or col commands are not available on your system, edit the doc/Makefile and change the GUIDECMD as directed. Type 'make all' from the top directory to set up all the auxiliary files the main executable will use. Then become root if necessary and type 'make install'. Everything should now be set. 8. Read doc/recover.man or doc/recover.txt to learn how to use the recover program. The recover program can be used in case of a crash to recover a game that was in progress. The recover command is installed in the HACKDIR by default. 9. If you specified SYSCF (and SYSCF_FILE) in config.h, create the file defined as SYSCF_FILE and fill in any of the following values if you wish to override the compiled-in defaults: WIZARDS= a space-separated list of usernames who can use -D If the first character is '*' then any user can use -D. SUPPORT= one line, probably starting with a verb, telling how to contact your local support person/group for NetHack. If there is no local support, do not use this line. Some sample values: call Joan at +1 312 555-1234. email support@example.com visit http://www.example.com/game-support RECOVER= instructions for running recover. If RECOVER is not available, do not use this line. Some sample values: To get your game recovered, contact support. Run /usr/local/bin/nh-recover to recover your game. This is a standard config file, so blank lines and lines starting with pound signs are ignored; while other, standard options (such as catname) can be specified in this file, this is considered a bug and may be changed in the future. Notes: 1. Save files and bones files from previous versions will not work with NetHack 3.6. Don't bother trying to keep them. 2. To install an update of this version of NetHack after changing something, type 'make update' from the main directory. If you created the new version yourself, it should be safe to use 'make update' as long as you did not add, delete, or reorder monsters or objects and you did not change the format of saved level files. If you did any of these things, you should also remove any saved games and bones levels. (Trying to use such files often produces amusing but useless confusions on the game's part.) 3. If you insisted on doing the final installation by hand, you probably forgot to make a save directory. If you don't go back and do this, you won't be able to save games. 4. If you get unexplained deaths by trickery, you are probably running NetHack on a bunch of workstations, but you have overlooked the NETWORK definition in unixconf.h that is necessary in that configuration. 5. If spurious characters appear on the screen while throwing, kicking, zapping, etc., it is likely that you have linked the source to the wrong library or mistakenly defined/undefined TERMINFO. A number of systems, such as Xenix, support both the termcap and terminfo terminal capability libraries. In such cases, the TERMINFO definition in unixconf.h and the WINTTYLIB definition in the source Makefile must correspond. If your terminal library does not provide suitable delays, NetHack will try to fake its own if you set the nonull option. 6. Since NetHack overflows the stock C preprocessors for AT&T 3b1 and 3b2 systems ("too many defines"), we are including an alternate preprocessor to allow these folks to compile. This is the DECUS cpp by Martin Minow, slightly modified by Kevin Darcy to use larger buffers, be less verbose, and handle strange constructs in AT&T's include files. To use this preprocessor, unpack the cpp* files found in sys/unix into some handy directory (util will do). For the AT&T machines mentioned above, nothing needs to be configured; you should get a working cpp by merely typing "make -f makefile.txt". To get your compiler to use the new cpp, you will have to add to CFLAGS in src/Makefile and util/Makefile. If you put the cpp files in /foo/bar/util, add "-B/foo/bar/util/ -tp" for a 3b1 or "-Yp,/foo/bar/util" for a 3b2. For any other machine whose preprocessor can't handle the NetHack source, you'll have to play it by ear. The preprocessor has many esoteric configuration options, but most probably you will only need to change the flags in makefile.txt, and then refer to your compiler's documentation to find the appropriate CFLAGS for the NetHack Makefiles. (The SunOS flag, for instance, would be "-Qpath /foo/bar/util", although the native cpp has no trouble with NetHack. So much for standardization.) 7. If you are trying to compile NetHack on an AT&T 3B that is running an OS earlier than SVR3, you are likely to have problems with overflowing symbol tables. This can be worked around by editing the source Makefile to make the Sys.3B2 target work more like the SysV-AT target, adding -DDUMB to CFLAGS and DUMB.Setup to the Sys.3B2 dependency line. The compiler provided with later versions of the OS has a large enough symbol table that it does not need this workaround. 8. If NetHack seems to compile fine, starts up, allows you to pick a character, and then hangs indefinitely, gets a segmentation fault, or traps you in a single room on the first level, you might try changing the schar and uchar definitions in config.h to short ints. This problem is known to occur on the AT&T 3B series, Silicon Graphics Irises, and IBM systems (PC/RT & RS/6000) running AIX, and may occur on other computers as well. This problem is really most likely caused by having a non-__STDC__ compiler with char's unsigned by default. Since some such compilers don't understand the new "signed" keyword, and others don't have signed characters to use (the 3B2 line falls into this category), "signed" is #ifdefed away for them. If you are sure your compiler can deal with it, you can add your compiler to the __HC__ case in tradstdc.h. Alternatively, if the compiler supports a command line switch for setting the default char type to signed, you could try setting it in the Makefiles. The appropriate switch for SGI Irises with MIPS C compiler is "-signed" and for RS/6000's with standard cc "-qchars=signed". (SGI machines running IRIX 4.0.x have a compiler close enough to standard to suit NetHack, so you may merely use the suggested flags in the Makefiles.) Note that at least RS/6000's seem to like changing the default to signed better but there is also a problem: The lexers created by the standard lex program in AIX may come out faulty when this switch is used (known to happen at least in AIX 3.1.3), so you may have to use an alternative, like flex, which is available at major archive sites (see notes 10 and 11). By AIX 3.2.5, this whole problem should be taken care of automatically (but AIX_31 should still be defined in unixconf.h for other reasons). 9. Under SCO UNIX, you may have all sorts of complaints about include/obj.h. Go to the file and uncomment the marked line, working around the fact that SCO's system include files preempt a major NetHack structure name. Also, there are difficulties with SCO's cc that thus far have been solved only by changing compilers; one report says gcc-NetHack works, and another says rcc-NetHack can be made to work by defining NOTSTDC, applying note 8, and compiling with -tinfo and -xenix. The cc problems are old enough that a new, working version may have been released by this time. 10. Xenix/286's lex generates a faulty lexical analyser from lev_comp.l. The beta-release of flex 2.3 (available from uunet, osu-cis, prep.ai.mit.edu, etc.) can be used to generate the lexer. The only change to flex is to change "#define yyleng (yy_cp - yy_bp)" to "#define yyleng (int)(yy_cp - yy_bp)" in flex.skel. Flex is not needed with Xenix/386, as its lex generates a proper lexical analyser. [Xenix instructions by J.T. Conklin] 11. If your system does not have a lex/yacc or flex/bison combination capable of producing the dungeon and level compilers, lex and yacc output from one of our development systems can be found in sys/share. Unfortunately, this output is less portable than the rest of the code, as it contains skeleton parsing code provided by the specific vendor who has no particular incentive to make such skeletons portable, but the output works on most systems. To try it on yours, copy dgn_comp.h and lev_comp.h to include and dgn_lex.c, dgn_yacc.c, lev_lex.c, and lev_yacc.c to util. 12. Yes, Virginia, you compile NetHack for a NeXT as if it ran UNIX instead of Mach. Just tell NetHack you're a BSD system (Mach is extremely close to BSD UNIX for traditional system calls, so this is also a likely thing to try for any other programs you want to compile). If you get errors when starting nethack warning that "Setuid execution is not allowed", you might want to re-install using the setgid option instead (see Note 7 above, and the setgid comment in the toplevel Makefile). 13. If you are using Solaris 2.x (aka SunOS 5.x) you shouldn't have to do any system configuration -- this is the default. In case it is messed up, follow these instructions. Solaris is basically a SVR4 system, not a BSD system. Therefore, you configure config.h and unixconf.h as per a SVR4 system: config.h: UNIX, TTY_GRAPHICS unixconf.h: SYSV, SVR4, TERMINFO, POSIX_JOB_CONTROL, POSIX_TYPES X11_GRAPHICS does work. Do not define OPENWINBUG. You may safely define NETWORK, TEXTCOLOR if desired. Other #defines in these files may be defined too, as needed. Just make sure that the set mentioned here are not misdefined, or your compile will fail (do _not_ define BSD or SUNOS4). Unless you are using gzip you will probably want to define COMPRESS to be "/usr/bin/compress". When compiling, make sure that you use the ANSI C SVR4 compatible compiler, /usr/bin/cc, or gcc, but _not_ ucbcc. The lattermost will not work. After this, you should get a clean compile. Also, it is recommended that you use FLEX instead of the standard lex bundled with Solaris 2.x (even if that last one should work ;-). 14. If your machine is a 286, 386, or 486 running an appropriate OS, you may wish to use the console speaker driver included in sys/unix/snd86unx.shr. This will allow audible music to be played on your console speaker in certain appropriate game situations. The only modification to the main-line code needed to enable use of the driver is defining UNIX386MUSIC or VPIX_MUSIC in unixconf.h. 15. If you are trying to cross-compile for another system, there is some support in the src and util Makefiles, but there are still other complications. It may well be best to make another copy of util, util2, to compile target copies of makedefs, lev_comp, and recover (duplicating the cross-compilation settings from the src Makefile) without disturbing the main build. You can use the host makedefs for everything but "makedefs -v", which creates include/date.h, which provides various sanity-checking values for making sure files read by NetHack at run-time are compatible. These values depend on the endianness of your processor, its type sizes, and its compiler's idea of struct packing. Your host and target computers may disagree on these things, so you'll need to build a target version of makedefs, run "makedefs -v" on your target, and bring the resulting date.h back for the builds on the host. (Making sure the host makedefs doesn't decide it needs to overwrite it for you. :-) You also need a target version of lev_comp, and to provide it with all the dat/*.des files, and copy all the resulting *.lev files back for packaging on the host. For recover, you just want the target binary to install on the target. nethack-3.6.0/sys/unix/Makefile.dat0000664000076400007660000001024512623162643016154 0ustar paxedpaxed# NetHack Makefile. # NetHack 3.6 Makefile.dat $NHDT-Date: 1447844574 2015/11/18 11:02:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ # Root of source tree: NHSROOT=.. # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # UUDECODE=uudecode VARDAT = bogusmon data engrave epitaph rumors quest.dat oracles options all: $(VARDAT) spec_levs quest_levs dungeon ../util/makedefs: (cd ../util ; $(MAKE) makedefs) ../util/dgn_comp: (cd ../util ; $(MAKE) dgn_comp) ../util/lev_comp: (cd ../util ; $(MAKE) lev_comp) ../util/tile2x11: (cd ../util ; $(MAKE) tile2x11) ../util/tile2beos: (cd ../util ; $(MAKE) tile2beos) ../util/tile2bmp: (cd ../util ; $(MAKE) tile2bmp) x11tiles: ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt beostiles: ../util/tile2beos ../win/share/monsters.txt \ ../win/share/objects.txt \ ../win/share/other.txt ../util/tile2beos ../win/share/monsters.txt \ ../win/share/objects.txt \ ../win/share/other.txt nhtiles.bmp: ../util/tile2bmp ../win/share/monsters.txt \ ../win/share/objects.txt \ ../win/share/other.txt ../util/tile2bmp $@ NetHack.ad: ../win/X11/NetHack.ad cp ../win/X11/NetHack.ad NetHack.ad pet_mark.xbm: ../win/X11/pet_mark.xbm cp ../win/X11/pet_mark.xbm pet_mark.xbm pilemark.xbm: ../win/X11/pilemark.xbm cp ../win/X11/pilemark.xbm pilemark.xbm rip.xpm: ../win/X11/rip.xpm cp ../win/X11/rip.xpm rip.xpm mapbg.xpm: ../win/gnome/mapbg.xpm cp ../win/gnome/mapbg.xpm mapbg.xpm nhsplash.xpm: ../win/Qt/nhsplash.xpm cp ../win/Qt/nhsplash.xpm nhsplash.xpm nethack.icns: ../win/Qt/nhicns.uu $(UUDECODE) ../win/Qt/nhicns.uu Info.plist: ../win/Qt/Info.pli cp ../win/Qt/Info.pli Info.plist ../util/tile2img.ttp: (cd ../util ; $(MAKE) tile2img.ttp) ../util/xpm2img.ttp: (cd ../util ; $(MAKE) xpm2img.ttp) nh16.img: ../util/tile2img.ttp ../win/share/monsters.txt \ ../win/share/objects.txt ../win/share/other.txt ../util/tile2img.ttp nh16.img rip.img: ../util/xpm2img.ttp ../util/xpm2img.ttp ../win/X11/rip.xpm rip.img title.img: # cp ../win/gem/title.img title.img $(UUDECODE) ../win/gem/title.uu GEM_RSC.RSC: # cp ../win/gem/GEM_RSC.RSC GEM_RSC.RSC $(UUDECODE) ../win/gem/gem_rsc.uu data: data.base ../util/makedefs ../util/makedefs -d rumors: rumors.tru rumors.fal ../util/makedefs ../util/makedefs -r quest.dat: quest.txt ../util/makedefs ../util/makedefs -q oracles: oracles.txt ../util/makedefs ../util/makedefs -h engrave: engrave.txt ../util/makedefs ../util/makedefs -s epitaph: epitaph.txt ../util/makedefs ../util/makedefs -s bogusmon: bogusmon.txt ../util/makedefs ../util/makedefs -s # note: 'options' should have already been made when include/date.h was created options: ../util/makedefs ../util/makedefs -v spec_levs: ../util/lev_comp \ bigroom.des castle.des endgame.des gehennom.des knox.des medusa.des \ mines.des oracle.des sokoban.des tower.des yendor.des ../util/lev_comp bigroom.des ../util/lev_comp castle.des ../util/lev_comp endgame.des ../util/lev_comp gehennom.des ../util/lev_comp knox.des ../util/lev_comp medusa.des ../util/lev_comp mines.des ../util/lev_comp oracle.des ../util/lev_comp sokoban.des ../util/lev_comp tower.des ../util/lev_comp yendor.des touch spec_levs quest_levs: ../util/lev_comp \ Arch.des Barb.des Caveman.des Healer.des Knight.des Monk.des \ Priest.des Ranger.des Rogue.des Samurai.des Tourist.des Valkyrie.des \ Wizard.des ../util/lev_comp Arch.des ../util/lev_comp Barb.des ../util/lev_comp Caveman.des ../util/lev_comp Healer.des ../util/lev_comp Knight.des ../util/lev_comp Monk.des ../util/lev_comp Priest.des ../util/lev_comp Ranger.des ../util/lev_comp Rogue.des ../util/lev_comp Samurai.des ../util/lev_comp Tourist.des ../util/lev_comp Valkyrie.des ../util/lev_comp Wizard.des touch quest_levs dungeon: dungeon.def ../util/makedefs ../util/dgn_comp ../util/makedefs -e ../util/dgn_comp dungeon.pdf spotless: -rm -f spec_levs quest_levs *.lev $(VARDAT) dungeon dungeon.pdf -rm -f nhdat x11tiles beostiles pet_mark.xbm pilemark.xbm rip.xpm mapbg.xpm -rm -f rip.img GEM_RSC.RSC title.img nh16.img NetHack.ad nethack-3.6.0/sys/unix/Makefile.doc0000664000076400007660000000751412536476415016166 0ustar paxedpaxed# NetHack Makefile. # NetHack 3.6 Makefile.doc $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ # Root of source tree: NHSROOT=.. # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP MAKEDEFS = ../util/makedefs # Which version do we want to build? (XXX These are not used anywhere.) GUIDEBOOK = Guidebook # regular ASCII file #GUIDEBOOK = Guidebook.ps # PostScript file #GUIDEBOOK = Guidebook.dvi # TeX device-independent file # Some versions of col need -x to keep them from converting spaces to tabs; # some versions of col don't do the conversion by default and don't # recognize the option. Sigh. COLCMD = col -bx #COLCMD = col -b # The command to use to generate a PostScript file # PSCMD = ditroff | psdit PSCMD = groff # Use the "cat" GUIDECMD if nroff and/or tbl and/or col are not installed # Not appropriate for creating Guidebook.txt. # GUIDECMD = cat Guidebook.txt # The following works better with groff-1.18, eg on Linux # GUIDECMD = $(GUIDE_PREFORMAT) | nroff -c -Tascii | $(COLCMD) GUIDECMD = $(GUIDE_PREFORMAT) | nroff | $(COLCMD) # Only generate output for the current configuration: NHGREP = $(MAKEDEFS) --grep --input - --output - # Generate output for all configurations: #NHGREP = $(MAKEDEFS) --grep --input - --output - --grep-define ALLDOCS # Fallback: #NHGREP = cat GUIDE_PREFORMAT = cat Guidebook.mn | $(NHGREP) | tbl tmac.n - # the basic guidebook Guidebook: Guidebook.mn $(GUIDECMD) > Guidebook # Fancier output for those with ditroff, psdit and a PostScript printer. Guidebook.ps: Guidebook.mn $(GUIDE_PREFORMAT) | $(PSCMD) > Guidebook.ps # Guidebook.tex is the same as Guidebook.mn but formatted with LaTeX. # - The invocation command for LaTeX may vary in different installations. # - To print Guidebook.dvi you need to use a suitable dvi-driver. # - LaTeX needs to be run twice; second pass uses Guidebook.aux made by first. Guidebook.dvi: Guidebook.tex latex Guidebook.tex latex Guidebook.tex GAME = nethack MANDIR = /usr/man/man6 MANEXT = 6 # manual installation for most BSD-style systems GAMEMANCREATE = cat nethack.6 | $(NHGREP) > LEVMANCREATE = cat lev_comp.6 | $(NHGREP) > DGNMANCREATE = cat dgn_comp.6 | $(NHGREP) > RCVRMANCREATE = cat recover.6 | $(NHGREP) > DLBMANCREATE = cat dlb.6 | $(NHGREP) > MDMANCREATE = cat makedefs.6 | $(NHGREP) > # manual installation for most SYSV-style systems # GAMEMANCREATE = cat nethack.6 | $(NHGREP) | nroff -man - > # LEVMANCREATE = cat lev_comp.6 | $(NHGREP) | nroff -man - > # DGNMANCREATE = cat dgn_comp.6 | $(NHGREP) | nroff -man - > # RCVRMANCREATE = cat recover.6 | $(NHGREP) | nroff -man - > # DLBMANCREATE = cat dlb.6 | $(NHGREP) | nroff -man - > # MDMANCREATE = cat makedefs.6 | $(NHGREP) | nroff -man - > manpages: -$(GAMEMANCREATE) $(MANDIR)/$(GAME).$(MANEXT) -$(LEVMANCREATE) $(MANDIR)/lev_comp.$(MANEXT) -$(DGNMANCREATE) $(MANDIR)/dgn_comp.$(MANEXT) -$(RCVRMANCREATE) $(MANDIR)/recover.$(MANEXT) -$(DLBMANCREATE) $(MANDIR)/dlb.$(MANEXT) -$(MDMANCREATE) $(MANDIR)/makedefs.$(MANEXT) # manual creation for distribution DISTRIB = Guidebook.txt nethack.txt lev_comp.txt dgn_comp.txt recover.txt \ dlb.txt makedefs.txt distrib: $(DISTRIB) @echo "Plain text documentation is up to date." Guidebook.txt : Guidebook.mn tmac.n $(GUIDECMD) > Guidebook.txt MAN2TXT = $(NHGREP) | nroff -man - | $(COLCMD) nethack.txt : nethack.6 cat nethack.6 | $(MAN2TXT) > nethack.txt lev_comp.txt : lev_comp.6 cat lev_comp.6 | $(MAN2TXT) > lev_comp.txt dgn_comp.txt : dgn_comp.6 cat dgn_comp.6 | $(MAN2TXT) > dgn_comp.txt recover.txt : recover.6 cat recover.6 | $(MAN2TXT) > recover.txt dlb.txt : dlb.6 cat dlb.6 | $(MAN2TXT) > dlb.txt makedefs.txt : makedefs.6 cat makedefs.6 | $(MAN2TXT) > makedefs.txt clean: -rm -f Guidebook.aux Guidebook.log spotless: clean -rm -f Guidebook Guidebook.ps Guidebook.dvi maintainer-clean: spotless -rm -f $(DISTRIB) # -rm -f Makefile nethack-3.6.0/sys/unix/Makefile.src0000664000076400007660000007737512621042434016205 0ustar paxedpaxed# NetHack Makefile. # NetHack 3.6 Makefile.src $NHDT-Date: 1447313972 2015/11/12 07:39:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.45 $ # Root of source tree: NHSROOT=.. # newer makes predefine $(MAKE) to 'make' and do smarter processing of # recursive make calls if $(MAKE) is used # these makes allow $(MAKE) to be overridden by the environment if someone # wants to (or has to) use something other than the standard make, so we do # not want to unconditionally set $(MAKE) here # # unfortunately, some older makes do not predefine $(MAKE); if you have one of # these, uncomment the following line # (you will know that you have one if you get complaints about being unable # to find 'makedefs') # MAKE = make # This makefile replaces the previous Makefile.unix, Makefile.xenix, # Makefile.3B2, Makefile.att, and Makefile.tos. # Set SYSTEM to one of: # 'Sysunix' -- generic UNIX # 'Sys3B2' -- AT&T 3B2, 3B5, etc. # 'Sysatt' -- AT&T UNIXPC, 7300, 3B1 # 'SysV-AT' -- Microport 286 UNIX (put -DDUMB in CFLAGS) # 'Systos' -- Atari # 'SysBe' -- BeOS SYSTEM = Sysunix # # Make sure that your bourne shell is specified here, as you have to spawn # some of the commands (eg. depend) in bourne shell for them to work. # # For Systos users compiling on the ST, you'll either need a bourne shell # clone or you'll need to do make depend, etc. by hand. In either case, # the line below probably needs changing SHELL=/bin/sh # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # Usually, the C compiler driver is used for linking: #LINK=$(CC) # Pick the SYSSRC and SYSOBJ lines corresponding to your desired operating # system. # # for UNIX systems SYSSRC = ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \ ../sys/unix/unixunix.c ../sys/unix/unixres.c SYSOBJ = ioctl.o unixmain.o unixtty.o unixunix.o unixres.o # # for Systos # SYSSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \ # ../sys/share/pctty.c ../sys/share/pcunix.c # SYSOBJ = tos.o pcmain.o pcsys.o pctty.o pcunix.o # # for BeOS #SYSSRC = ../sys/be/bemain.c ../sys/share/unixtty.c ../sys/share/ioctl.c #SYSOBJ = bemain.o unixtty.o ioctl.o # if you are using gcc as your compiler: # uncomment the CC definition below if it's not in your environment # if you get setcgtty() warnings during execution, you are feeding gcc # a non-ANSI -- either run fixincludes on it or use # -traditional in CFLAGS # CC = gcc # # For Bull DPX/2 systems at B.O.S. 2.0 or higher use the following: # # CC = gcc -ansi -D_BULL_SOURCE -D_XOPEN_SOURCE -D_POSIX_SOURCE # # If you are using GCC 2.2.2 or higher on a DPX/2, just use: # # CC = gcc -ansi # # For HP/UX 10.20 with GCC: # CC = gcc -D_POSIX_SOURCE # # For cross-compiling, eg. with gcc on Linux (see also CXX further down): # CC = arm-linux-gcc # # # if you're debugging and want gcc to check as much as possible, use: # CC = gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN # flags may have to be changed as required # flags for 286 Xenix: # CFLAGS = -Ml2t16 -O -LARGE -I../include # LFLAGS = -Ml -F 4000 -SEG 512 # flags for 286 Microport SysV-AT # CFLAGS = -DDUMB -Ml -I../include # LFLAGS = -Ml # flags for Atari gcc (3.2.1) # CFLAGS = -O -I../include # LFLAGS = -s # flags for Atari gcc (3.3) # CFLAGS = -mshort -O2 -fomit-frame-pointer -I../include # LFLAGS = -mshort -s # flags for AIX 3.1 cc on IBM RS/6000 to define # a suitable subset of standard libraries # (note that there is more info regarding the "-qchars=signed" # switch in file Install.unx note 8) # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -O -I../include -qchars=signed # # Some of our subroutines are complex enough that this is required for full # optimization under AIX 3.2 (I don't know about 3.1). # # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -D_ALL_SOURCE -O -I../include -qchars=signed -qmaxmem=5000 # flags for A/UX 2.01 using native cc or c89 # gcc predefines AUX so that's not needed there # Remember to use -lcurses for WINLIB below ! # CFLAGS = -ZS -D_POSIX_SOURCE -O -I../include -DAUX # flags for IRIX 4.0.x using native cc # The include files are __STDC__, but have bugs involving const # CFLAGS = -O -I../include -D__STDC__ -Dconst= -woff 100,293 # LFLAGS = -s # flags for BSD/OS 2.0 # CFLAGS = -O -I../include -I/usr/X11/include # LFLAGS = -L/usr/X11/lib # flags for Linux # compile normally # CFLAGS = -O2 -fomit-frame-pointer -I../include # LFLAGS = -L/usr/X11R6/lib # OR compile backwards compatible a.out format # CFLAGS = -O2 -b i486-linuxaout -fomit-frame-pointer -I../include # LFLAGS = -b i486-linuxaout -L/usr/X11R6/lib # flags for BeOS # on a Mac/BeBox: #CC = mwcc #CFLAGS = -r -I../include #LINK = mwld #LFLAGS = -map nethack.xMAP # on Intel: #CFLAGS = -O -I../include #LINK = gcc #LFLAGS = -Xlinker -soname=_APP_ # Only used for the Gnome interface. # When including the Gnome interface, you need to include gnome specific # directories. The ones given below is the usual spot for linux systems. # The paths are for glibconfig.h and gnomesupport.h respectively. # GNOMEINC=-I/usr/lib/glib/include -I/usr/lib/gnome-libs/include -I../win/gnome # flags for debugging: # CFLAGS = -g -I../include #CFLAGS = -O -I../include #LFLAGS = # The Qt and Be window systems are written in C++, while the rest of # NetHack is standard C. If using Qt, uncomment the LINK line here to get # the C++ libraries linked in. CXXFLAGS = $(CFLAGS) -I. -I$(QTDIR)/include CXX=g++ #LINK=g++ # For cross-compiling, eg. with gcc on Linux (see also CC further up): #CXX=arm-linux-g++ #LINK=arm-linux-gcc # file for regular expression matching REGEXOBJ = posixregex.o #REGEXOBJ = pmatchregex.o #REGEXOBJ = cppregex.o # Set the WINSRC, WINOBJ, and WINLIB lines to correspond to your desired # combination of windowing systems. Also set windowing systems in config.h. # Note that if you are including multiple tiled window systems, you don't # want two copies of tile.o, so comment out all but the first. # # files for a straight tty port using no native windowing system WINTTYSRC = ../win/tty/getline.c ../win/tty/termcap.c ../win/tty/topl.c \ ../win/tty/wintty.c WINTTYOBJ = getline.o termcap.o topl.o wintty.o # # files for an X11 port # (tile.c is a generated source file) WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \ ../win/X11/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \ ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \ ../win/X11/winval.c tile.c WINX11OBJ = Window.o dialogs.o winX.o winmap.o winmenu.o winmesg.o \ winmisc.o winstat.o wintext.o winval.o tile.o # # Files for a Qt port # WINQTSRC = ../win/Qt/qt_win.cpp ../win/Qt/qt_clust.cpp ../win/Qt/qttableview.cpp WINQTOBJ = qt_win.o qt_clust.o qttableview.o tile.o # # Files for a Gnome port # WINGNOMESRC = ../win/gnome/gnaskstr.c ../win/gnome/gnbind.c \ ../win/gnome/gnglyph.c ../win/gnome/gnmain.c ../win/gnome/gnmap.c \ ../win/gnome/gnmenu.c ../win/gnome/gnmesg.c ../win/gnome/gnopts.c \ ../win/gnome/gnplayer.c ../win/gnome/gnsignal.c \ ../win/gnome/gnstatus.c ../win/gnome/gntext.c ../win/gnome/gnyesno.c \ ../win/gnome/gnworn.c WINGNOMEOBJ = gnaskstr.o gnbind.o gnglyph.o gnmain.o gnmap.o gnmenu.o \ gnmesg.o gnopts.o gnplayer.o gnsignal.o gnstatus.o gntext.o \ gnyesno.o gnworn.o tile.o # # Files for a Gem port WINGEMSRC = ../win/gem/wingem.c ../win/gem/wingem1.c ../win/gem/load_img.c \ ../win/gem/gr_rect.c tile.c WINGEMOBJ = wingem.o wingem1.o load_img.o gr_rect.o tile.o # # Files for a BeOS InterfaceKit port -- not ready for prime time WINBESRC = WINBEOBJ = #WINBESRC = ../win/BeOS/winbe.cpp ../win/BeOS/NHWindow.cpp \ # ../win/BeOS/NHMenuWindow.cpp ../win/BeOS/NHMapWindow.cpp tile.c #WINBEOBJ = winbe.o NHWindow.o NHMenuWindow.o NHMapWindow.o tile.o # # #WINSRC = $(WINTTYSRC) #WINOBJ = $(WINTTYOBJ) # on some systems the termcap library is in -ltermcap or -lcurses # on 386 Xenix, the -ltermlib tputs() seems not to work; use -lcurses instead # Sysatt uses shared library in lieu of this option # Systos needs -lcurses16 if you use -mshort # AIX 3.1 on RS/6000 likes -lcurses if TERMINFO defined in unixconf.h # and -ltermcap otherwise # Linux uses -lncurses (newer) or -ltermcap (older) # Be uses -ltermcap # # libraries for tty ports # WINTTYLIB = -ltermcap # WINTTYLIB = -lcurses # WINTTYLIB = -lcurses16 # WINTTYLIB = -lncurses #WINTTYLIB = -ltermlib # # libraries for X11 # If USE_XPM is defined in config.h, you will also need -lXpm here. WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 # WINX11LIB = -lXaw -lXmu -lXt -lX11 # WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11 -lm # WINX11LIB = -lXaw -lXmu -lXpm -lXext -lXt -lX11 -lSM -lICE -lm # BSD/OS 2.0 # # libraries for Qt WINQTLIB = -L$(QTDIR)/lib -lqt # # libraries for KDE (with Qt) WINKDELIB = -lkdecore -lkdeui -lXext # # libraries for Gnome WINGNOMELIB = -lgnomeui -lgnome -lart_lgpl -lgtk -lgdk -lpopt # # libraries for Gem port WINGEMLIB = -le_gem -lgem # # libraries for BeOS WINBELIB = -lbe #WINLIB = $(WINTTYLIB) # any other strange libraries your system needs (for Sysunix only -- the more # specialized targets should already be right) # # on HP-UX 8.x, the malloc(3x) routines in libmalloc.a seem to align things # better than the malloc(3) ones in libc.a # LIBS = -lmalloc # # DPX/2's also use the malloc(3x) routines. In addition, if you are building # for X11, you must include libinet.a. # LIBS = -lmalloc -linet # # Linux NetHack uses some bsd style ioctl functions, thus it is necessary to # use the bsd libs. (Only if still compiling as BSD in unixconf.h; recent # versions compile fine using SYSV without this.) # LIBS = -lbsd # # for CYGWIN32 aka cygwin 1.1.1 # LIBS = -lcygwin # # Solaris 2.x seems to work with the following # LIBS = -lsocket -lnsl # # IRIX 4.0.x needs -lsun if NIS (YP) is being used for passwd file lookup # LIBS = -lsun # # If ZLIB_COMP is defined in config.h this is necessary to link with zlib. # LIBS = -lz # LIBS = # make NetHack GAME = nethack # GAME = nethack.prg # if you defined RANDOM in unixconf.h/tosconf.h since your system did not come # with a reasonable random number generator # RANDOBJ = random.o RANDOBJ = # used by `make depend' to reconstruct this Makefile; you shouldn't need this AWK = nawk # ---------------------------------------- # # Nothing below this line should have to be changed. # # Other things that have to be reconfigured are in config.h, # {unixconf.h, pcconf.h, tosconf.h}, and possibly system.h MAKEDEFS = ../util/makedefs # timestamp files to reduce `make' overhead and shorten .o dependency lists CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ files.c fountain.c hack.c hacklib.c invent.c light.c lock.c \ mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c \ mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c \ rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c \ spell.c steal.c steed.c sys.c teleport.c timeout.c topten.c track.c \ trap.c \ u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ windows.c wizard.c worm.c worn.c write.c zap.c # all operating-system-dependent .c (for dependencies and such) SYSCSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \ ../sys/share/pctty.c ../sys/share/pcunix.c \ ../sys/share/pmatchregex.c ../sys/share/posixregex.c \ ../sys/share/random.c \ ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \ ../sys/unix/unixunix.c ../sys/unix/unixres.c ../sys/be/bemain.c # generated source files (tile.c is handled separately via WINxxxSRC) GENCSRC = monstr.c vis_tab.c #tile.c # all windowing-system-dependent .c (for dependencies and such) WINCSRC = $(WINTTYSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC) # all windowing-system-dependent .cpp (for dependencies and such) WINCXXSRC = $(WINQTSRC) $(WINBESRC) # Files for window system chaining. Requires SYSCF; include via HINTSRC/HINTOBJ CHAINSRC=../win/chain/wc_chainin.c ../win/chain/wc_chainout.c \ ../win/chain/wc_trace.c CHAINOBJ=wc_chainin.o wc_chainout.o wc_trace.o # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(CHAINSRC) $(GENCSRC) # .c files for all versions using this Makefile (for lint and tags) CSOURCES = $(HACKCSRC) $(SYSCSRC) $(WINCSRC) $(CHAINSRC) $(GENCSRC) # all .h files except date.h, onames.h, pm.h, and vis_tab.h which would # cause dependency loops if run through "make depend" # and dgn_comp.h, dgn_file.h, lev_comp.h, special level & dungeon files. # HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h botl.h \ color.h config.h config1.h context.h coord.h decl.h def_os2.h \ display.h dlb.h dungeon.h engrave.h extern.h flag.h func_tab.h \ global.h hack.h lev.h lint.h macconf.h mextra.h mfndpos.h micro.h \ mkroom.h \ monattk.h mondata.h monflag.h monst.h monsym.h obj.h objclass.h \ os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h region.h rm.h \ sp_lev.h spell.h sys.h system.h tcap.h timeout.h tosconf.h tradstdc.h \ trampoli.h trap.h unixconf.h vision.h vmsconf.h wintty.h \ winX.h winprocs.h wintype.h you.h youprop.h HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\ lev_comp.h dgn_comp.h dgn_file.h # the following .o's _must_ be made before any others (for makedefs) FIRSTOBJ = monst.o objects.o HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \ bones.o botl.o cmd.o dbridge.o decl.o detect.o dig.o display.o dlb.o \ do.o do_name.o do_wear.o dog.o dogmove.o dokick.o dothrow.o \ drawing.o dungeon.o eat.o end.o engrave.o exper.o explode.o \ extralev.o files.o fountain.o hack.o hacklib.o invent.o light.o \ lock.o mail.o makemon.o mapglyph.o mcastu.o mhitm.o mhitu.o \ minion.o mklev.o mkmap.o \ mkmaze.o mkobj.o mkroom.o mon.o mondata.o monmove.o monstr.o \ mplayer.o mthrowu.o muse.o music.o o_init.o objnam.o options.o \ pager.o pickup.o pline.o polyself.o potion.o pray.o priest.o \ quest.o questpgr.o read.o rect.o region.o restore.o rip.o rnd.o \ role.o rumors.o save.o shk.o shknam.o sit.o sounds.o sp_lev.o spell.o \ sys.o \ steal.o steed.o teleport.o timeout.o topten.o track.o trap.o u_init.o \ uhitm.o vault.o vision.o vis_tab.o weapon.o were.o wield.o windows.o \ wizard.o worm.o worn.o write.o zap.o \ $(REGEXOBJ) $(RANDOBJ) $(SYSOBJ) $(WINOBJ) $(HINTOBJ) version.o # the .o files from the HACKCSRC, SYSSRC, and WINSRC lists $(GAME): $(SYSTEM) @echo "$(GAME) is up to date." Sysunix: $(HOBJ) Makefile @echo "Loading ..." $(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @touch Sysunix Sys3B2: $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) -lmalloc @touch Sys3B2 Sysatt: $(HOBJ) Makefile @echo "Loading ..." @$(LD) $(LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAME) $(HOBJ) @touch Sysatt Systos: $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) @touch Systos SysV-AT: DUMB.Setup $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) @touch SysV-AT SysBe: $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @xres -o $(GAME) ../win/BeOS/nethack.rsrc @mimeset -f $(GAME) @touch SysBe DUMB.Setup: ../include/extern.h cp ../include/extern.h ../include/extern.h.BAK cat ../include/extern.h | \ sed -e '/^E\ int\ /!b' \ -e '/[^;/ ]$$/N' \ -e '/[(][*]occupation[)]/b' \ -e '/[(][*]afternmv[)]/b' \ -e '/float_down/b' \ -e '/done1/b' \ -e '/identify/b' \ -e '/Hear_again/b' \ -e '/hangup/b' \ -e 's/^\(.*\)$$/\/\* \1 \/\*\*\//' | \ sed -e '/^E\ void\ /!b' \ -e '/[^;/ ]$$/N' \ -e 's/^\(.*\)$$/\/\* \1 \/\*\*\//' \ >../include/extern.DUMB cp ../include/extern.DUMB ../include/extern.h @touch DUMB.Setup all: $(GAME) # dependencies for makedefs and its outputs, which the util # Makefile is responsible for keeping up to date # # special rules, to force update of makedefs, real dependencies should be # below in the 'make depend' output. monst.o: $(CC) $(CFLAGS) -c monst.c @rm -f $(MAKEDEFS) objects.o: $(CC) $(CFLAGS) -c objects.c @rm -f $(MAKEDEFS) # Qt windowport meta-object-compiler output qt_kde0.moc: ../include/qt_kde0.h $(QTDIR)/bin/moc -o qt_kde0.moc ../include/qt_kde0.h qt_win.moc: ../include/qt_win.h $(QTDIR)/bin/moc -o qt_win.moc ../include/qt_win.h qttableview.moc: ../include/qttableview.h $(QTDIR)/bin/moc -o qttableview.moc ../include/qttableview.h $(MAKEDEFS): ../util/makedefs.c $(CONFIG_H) ../include/permonst.h \ ../include/objclass.h ../include/monsym.h \ ../include/artilist.h ../include/dungeon.h ../include/obj.h \ ../include/monst.h ../include/you.h ../include/flag.h \ ../include/dlb.h ../include/patchlevel.h ../include/qtext.h @( cd ../util ; $(MAKE) makedefs) ../include/onames.h: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../include/onames.h ) ../include/pm.h: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../include/pm.h ) monstr.c: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../src/monstr.c ) ../include/vis_tab.h: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../include/vis_tab.h ) # makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first vis_tab.c: ../include/vis_tab.h tile.c: ../win/share/tilemap.c $(HACK_H) @( cd ../util ; $(MAKE) ../src/tile.c ) ../win/gnome/gn_rip.h: ../win/X11/rip.xpm cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # # hack.h depends on makedefs' output, so we know makedefs will be # up to date before being executed ../include/date.h: $(VERSOURCES) $(HACK_H) ../util/makedefs -v lint: # lint cannot have -p here because (i) capitals are meaningful: # [Ww]izard, (ii) identifiers may coincide in the first six places: # doweararm() versus dowearring(). # _flsbuf comes from , a bug in the system libraries. @echo lint -axbh -DLINT ... @lint -axbh -I../include -DLINT $(CSOURCES) | sed '/_flsbuf/d' tags: $(CSOURCES) @echo ctags -tw ... @ctags -tw $(CSOURCES) @( cd ../include ; ctags -tw $(HSOURCES) ) @( cd ../util ; $(MAKE) tags ) clean: -rm -f *.o $(HACK_H) $(CONFIG_H) spotless: clean -rm -f a.out core $(GAME) Sys* -rm -f ../include/date.h ../include/onames.h ../include/pm.h -rm -f monstr.c ../include/vis_tab.h vis_tab.c tile.c *.moc -rm -f ../win/gnome/gn_rip.h depend: ../sys/unix/depend.awk \ $(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(CHAINSRC) $(GENCSRC) \ $(HACKCSRC) $(AWK) -f ../sys/unix/depend.awk ../include/*.h \ $(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(CHAINSRC) $(GENCSRC) \ $(HACKCSRC) >makedep @echo '/^# DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT/+2,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @cp Makefile Makefile.bak ed - Makefile < eddep @rm -f eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile @echo '# see make depend above' >> Makefile - diff Makefile.bak Makefile @rm -f Makefile.bak # DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT # config.h timestamp $(CONFIG_H): ../include/config.h ../include/config1.h ../include/tradstdc.h \ ../include/global.h ../include/coord.h ../include/vmsconf.h \ ../include/system.h ../include/unixconf.h ../include/os2conf.h \ ../include/micro.h ../include/pcconf.h ../include/tosconf.h \ ../include/amiconf.h ../include/macconf.h ../include/beconf.h \ ../include/wceconf.h ../include/ntconf.h touch $(CONFIG_H) # hack.h timestamp $(HACK_H): ../include/hack.h $(CONFIG_H) ../include/lint.h ../include/align.h \ ../include/dungeon.h ../include/monsym.h ../include/mkroom.h \ ../include/objclass.h ../include/youprop.h ../include/prop.h \ ../include/permonst.h ../include/monattk.h \ ../include/monflag.h ../include/mondata.h ../include/pm.h \ ../include/wintype.h ../include/context.h ../include/decl.h \ ../include/quest.h ../include/spell.h ../include/color.h \ ../include/obj.h ../include/you.h ../include/attrib.h \ ../include/monst.h ../include/mextra.h ../include/skills.h \ ../include/onames.h ../include/timeout.h ../include/trap.h \ ../include/flag.h ../include/rm.h ../include/vision.h \ ../include/display.h ../include/engrave.h ../include/rect.h \ ../include/region.h ../include/winprocs.h ../include/botl.h \ ../include/sys.h ../include/wintty.h ../include/trampoli.h touch $(HACK_H) # tos.o: ../sys/atari/tos.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../sys/atari/tos.c pcmain.o: ../sys/share/pcmain.c $(HACK_H) ../include/dlb.h \ #../include/win32api.h $(CC) $(CFLAGS) -c ../sys/share/pcmain.c pcsys.o: ../sys/share/pcsys.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pcsys.c pctty.o: ../sys/share/pctty.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pctty.c pcunix.o: ../sys/share/pcunix.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pcunix.c pmatchregex.o: ../sys/share/pmatchregex.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pmatchregex.c posixregex.o: ../sys/share/posixregex.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/posixregex.c random.o: ../sys/share/random.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/random.c ioctl.o: ../sys/share/ioctl.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../sys/share/ioctl.c unixtty.o: ../sys/share/unixtty.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/unixtty.c unixmain.o: ../sys/unix/unixmain.c $(HACK_H) ../include/dlb.h $(CC) $(CFLAGS) -c ../sys/unix/unixmain.c unixunix.o: ../sys/unix/unixunix.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/unix/unixunix.c unixres.o: ../sys/unix/unixres.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../sys/unix/unixres.c bemain.o: ../sys/be/bemain.c $(HACK_H) ../include/dlb.h $(CC) $(CFLAGS) -c ../sys/be/bemain.c getline.o: ../win/tty/getline.c $(HACK_H) ../include/func_tab.h $(CC) $(CFLAGS) -c ../win/tty/getline.c termcap.o: ../win/tty/termcap.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../win/tty/termcap.c topl.o: ../win/tty/topl.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../win/tty/topl.c wintty.o: ../win/tty/wintty.c $(HACK_H) ../include/dlb.h ../include/tcap.h $(CC) $(CFLAGS) -c ../win/tty/wintty.c Window.o: ../win/X11/Window.c ../include/xwindowp.h ../include/xwindow.h \ $(CONFIG_H) ../include/lint.h $(CC) $(CFLAGS) -c ../win/X11/Window.c dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) ../include/lint.h $(CC) $(CFLAGS) -c ../win/X11/dialogs.c winX.o: ../win/X11/winX.c $(HACK_H) ../include/winX.h ../include/dlb.h \ ../win/X11/nh72icon ../win/X11/nh56icon ../win/X11/nh32icon $(CC) $(CFLAGS) -c ../win/X11/winX.c winmap.o: ../win/X11/winmap.c ../include/xwindow.h $(HACK_H) ../include/dlb.h \ ../include/winX.h ../include/tile2x11.h $(CC) $(CFLAGS) -c ../win/X11/winmap.c winmenu.o: ../win/X11/winmenu.c $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winmenu.c winmesg.o: ../win/X11/winmesg.c ../include/xwindow.h $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winmesg.c winmisc.o: ../win/X11/winmisc.c $(HACK_H) ../include/func_tab.h \ ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winmisc.c winstat.o: ../win/X11/winstat.c $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winstat.c wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h ../include/xwindow.h $(CC) $(CFLAGS) -c ../win/X11/wintext.c winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winval.c tile.o: tile.c $(HACK_H) gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ ../win/gnome/gnmain.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnaskstr.c gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ ../win/gnome/gnmenu.h ../win/gnome/gnaskstr.h \ ../win/gnome/gnyesno.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnbind.c gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h ../include/tile2x11.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnglyph.c gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ ../include/date.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmain.c gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h $(HACK_H) $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmap.c gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ ../win/gnome/gnbind.h ../include/func_tab.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmenu.c gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmesg.c gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnopts.c gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ ../win/gnome/gnmain.h $(HACK_H) $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnplayer.c gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ ../win/gnome/gnmain.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnsignal.c gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ ../win/gnome/gnomeprv.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnstatus.c gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ ../win/gnome/gn_rip.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gntext.c gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnyesno.c gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnworn.c wingem.o: ../win/gem/wingem.c $(HACK_H) ../include/func_tab.h ../include/dlb.h \ ../include/patchlevel.h ../include/wingem.h $(CC) $(CFLAGS) -c ../win/gem/wingem.c wingem1.o: ../win/gem/wingem1.c ../include/gem_rsc.h ../include/load_img.h \ ../include/gr_rect.h ../include/wintype.h ../include/wingem.h $(CC) $(CFLAGS) -c ../win/gem/wingem1.c load_img.o: ../win/gem/load_img.c ../include/load_img.h $(CC) $(CFLAGS) -c ../win/gem/load_img.c gr_rect.o: ../win/gem/gr_rect.c ../include/gr_rect.h $(CC) $(CFLAGS) -c ../win/gem/gr_rect.c tile.o: tile.c $(HACK_H) qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../include/func_tab.h \ ../include/dlb.h ../include/patchlevel.h ../include/tile2x11.h \ ../include/qt_win.h ../include/qt_clust.h ../include/qt_kde0.h \ ../include/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_win.cpp qt_clust.o: ../win/Qt/qt_clust.cpp ../include/qt_clust.h $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_clust.cpp qttableview.o: ../win/Qt/qttableview.cpp ../include/qttableview.h $(CXX) $(CXXFLAGS) -c ../win/Qt/qttableview.cpp wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H) $(CC) $(CFLAGS) -c ../win/chain/wc_chainin.c wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H) $(CC) $(CFLAGS) -c ../win/chain/wc_chainout.c wc_trace.o: ../win/chain/wc_trace.c $(HACK_H) ../include/func_tab.h $(CC) $(CFLAGS) -c ../win/chain/wc_trace.c monstr.o: monstr.c $(CONFIG_H) vis_tab.o: vis_tab.c $(CONFIG_H) ../include/vis_tab.h allmain.o: allmain.c $(HACK_H) alloc.o: alloc.c $(CONFIG_H) apply.o: apply.c $(HACK_H) artifact.o: artifact.c $(HACK_H) ../include/artifact.h ../include/artilist.h attrib.o: attrib.c $(HACK_H) ball.o: ball.c $(HACK_H) bones.o: bones.c $(HACK_H) ../include/lev.h botl.o: botl.c $(HACK_H) cmd.o: cmd.c $(HACK_H) ../include/func_tab.h dbridge.o: dbridge.c $(HACK_H) decl.o: decl.c $(HACK_H) detect.o: detect.c $(HACK_H) ../include/artifact.h dig.o: dig.c $(HACK_H) display.o: display.c $(HACK_H) dlb.o: dlb.c $(CONFIG_H) ../include/dlb.h do.o: do.c $(HACK_H) ../include/lev.h do_name.o: do_name.c $(HACK_H) do_wear.o: do_wear.c $(HACK_H) dog.o: dog.c $(HACK_H) dogmove.o: dogmove.c $(HACK_H) ../include/mfndpos.h dokick.o: dokick.c $(HACK_H) dothrow.o: dothrow.c $(HACK_H) drawing.o: drawing.c $(HACK_H) ../include/tcap.h dungeon.o: dungeon.c $(HACK_H) ../include/dgn_file.h ../include/dlb.h \ ../include/lev.h eat.o: eat.c $(HACK_H) end.o: end.c $(HACK_H) ../include/lev.h ../include/dlb.h engrave.o: engrave.c $(HACK_H) ../include/lev.h exper.o: exper.c $(HACK_H) explode.o: explode.c $(HACK_H) extralev.o: extralev.c $(HACK_H) files.o: files.c $(HACK_H) ../include/dlb.h #zlib.h fountain.o: fountain.c $(HACK_H) hack.o: hack.c $(HACK_H) hacklib.o: hacklib.c $(HACK_H) invent.o: invent.c $(HACK_H) light.o: light.c $(HACK_H) ../include/lev.h lock.o: lock.c $(HACK_H) mail.o: mail.c $(HACK_H) ../include/mail.h makemon.o: makemon.c $(HACK_H) mapglyph.o: mapglyph.c $(HACK_H) mcastu.o: mcastu.c $(HACK_H) mhitm.o: mhitm.c $(HACK_H) ../include/artifact.h mhitu.o: mhitu.c $(HACK_H) ../include/artifact.h minion.o: minion.c $(HACK_H) mklev.o: mklev.c $(HACK_H) mkmap.o: mkmap.c $(HACK_H) ../include/sp_lev.h mkmaze.o: mkmaze.c $(HACK_H) ../include/sp_lev.h ../include/lev.h mkobj.o: mkobj.c $(HACK_H) mkroom.o: mkroom.c $(HACK_H) mon.o: mon.c $(HACK_H) ../include/mfndpos.h mondata.o: mondata.c $(HACK_H) monmove.o: monmove.c $(HACK_H) ../include/mfndpos.h ../include/artifact.h monst.o: monst.c $(CONFIG_H) ../include/permonst.h ../include/align.h \ ../include/monattk.h ../include/monflag.h ../include/monsym.h \ ../include/color.h mplayer.o: mplayer.c $(HACK_H) mthrowu.o: mthrowu.c $(HACK_H) muse.o: muse.c $(HACK_H) music.o: music.c $(HACK_H) #interp.c o_init.o: o_init.c $(HACK_H) ../include/lev.h objects.o: objects.c $(CONFIG_H) ../include/obj.h ../include/objclass.h \ ../include/prop.h ../include/skills.h ../include/color.h objnam.o: objnam.c $(HACK_H) options.o: options.c $(CONFIG_H) ../include/objclass.h ../include/flag.h \ $(HACK_H) ../include/tcap.h pager.o: pager.c $(HACK_H) ../include/dlb.h pickup.o: pickup.c $(HACK_H) pline.o: pline.c $(HACK_H) polyself.o: polyself.c $(HACK_H) potion.o: potion.c $(HACK_H) pray.o: pray.c $(HACK_H) priest.o: priest.c $(HACK_H) ../include/mfndpos.h quest.o: quest.c $(HACK_H) ../include/qtext.h questpgr.o: questpgr.c $(HACK_H) ../include/dlb.h ../include/qtext.h read.o: read.c $(HACK_H) rect.o: rect.c $(HACK_H) region.o: region.c $(HACK_H) ../include/lev.h restore.o: restore.c $(HACK_H) ../include/lev.h ../include/tcap.h rip.o: rip.c $(HACK_H) rnd.o: rnd.c $(HACK_H) role.o: role.c $(HACK_H) rumors.o: rumors.c $(HACK_H) ../include/lev.h ../include/dlb.h save.o: save.c $(HACK_H) ../include/lev.h shk.o: shk.c $(HACK_H) shknam.o: shknam.c $(HACK_H) sit.o: sit.c $(HACK_H) ../include/artifact.h sounds.o: sounds.c $(HACK_H) sp_lev.o: sp_lev.c $(HACK_H) ../include/dlb.h ../include/sp_lev.h spell.o: spell.c $(HACK_H) steal.o: steal.c $(HACK_H) steed.o: steed.c $(HACK_H) sys.o: sys.c $(HACK_H) teleport.o: teleport.c $(HACK_H) timeout.o: timeout.c $(HACK_H) ../include/lev.h topten.o: topten.c $(HACK_H) ../include/dlb.h ../include/patchlevel.h track.o: track.c $(HACK_H) trap.o: trap.c $(HACK_H) u_init.o: u_init.c $(HACK_H) uhitm.o: uhitm.c $(HACK_H) vault.o: vault.c $(HACK_H) version.o: version.c $(HACK_H) ../include/dlb.h ../include/date.h \ ../include/patchlevel.h vision.o: vision.c $(HACK_H) ../include/vis_tab.h weapon.o: weapon.c $(HACK_H) were.o: were.c $(HACK_H) wield.o: wield.c $(HACK_H) windows.o: windows.c $(HACK_H) ../include/wingem.h ../include/winGnome.h wizard.o: wizard.c $(HACK_H) ../include/qtext.h worm.o: worm.c $(HACK_H) ../include/lev.h worn.o: worn.c $(HACK_H) write.o: write.c $(HACK_H) zap.o: zap.c $(HACK_H) # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above nethack-3.6.0/sys/unix/Makefile.top0000664000076400007660000002150712623162643016211 0ustar paxedpaxed# NetHack Makefile. # NetHack 3.6 Makefile.top $NHDT-Date: 1447844578 2015/11/18 11:02:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ # Root of source tree: NHSROOT=. # newer makes predefine $(MAKE) to 'make' and do smarter processing of # recursive make calls if $(MAKE) is used # these makes allow $(MAKE) to be overridden by the environment if someone # wants to (or has to) use something other than the standard make, so we do # not want to unconditionally set $(MAKE) here # # unfortunately, some older makes do not predefine $(MAKE); if you have one of # these, uncomment the following line # (you will know that you have one if you get complaints about unable to # execute things like 'data' and 'rumors') # MAKE = make # make NetHack #PREFIX = /usr GAME = nethack # GAME = nethack.prg #GAMEUID = games #GAMEGRP = bin # Permissions - some places use setgid instead of setuid, for instance # See also the option "SECURE" in include/config.h #GAMEPERM = 04755 FILEPERM = 0644 # VARFILEPERM = 0644 EXEPERM = 0755 DIRPERM = 0755 # VARDIRPERM = 0755 # VARDIR may also appear in unixconf.h as "VAR_PLAYGROUND" else HACKDIR # # note that 'make install' believes in creating a nice tidy HACKDIR for # installation, free of debris from previous NetHack versions -- # therefore there should not be anything in HACKDIR that you want to keep # (if there is, you'll have to do the installation by hand or modify the # instructions) #HACKDIR = $(PREFIX)/games/lib/$(GAME)dir #VARDIR = $(HACKDIR) # Where nethack.sh in installed. If this is not defined, the wrapper is not used. #SHELLDIR = $(PREFIX)/games # per discussion in Install.X11 and Install.Qt #VARDATND = # VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xpm # VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xpm rip.xpm # for Atari/Gem # VARDATND = nh16.img title.img GEM_RSC.RSC rip.img # for BeOS # VARDATND = beostiles # for Gnome # VARDATND = x11tiles pet_mark.xbm pilemark.xpm rip.xpm mapbg.xpm VARDATD = bogusmon data engrave epitaph oracles options quest.dat rumors VARDAT = $(VARDATD) $(VARDATND) # Some versions of make use the SHELL environment variable as the shell # for running commands. We need this to be a Bourne shell. # SHELL = /bin/sh # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # Commands for setting the owner and group on files during installation. # Some systems fail with one or the other when installing over NFS or for # other permission-related reasons. If that happens, you may want to set the # command to "true", which is a no-op. Note that disabling chown or chgrp # will only work if setuid (or setgid) behavior is not desired or required. #CHOWN = chown #CHGRP = chgrp # # end of configuration # DATHELP = help hh cmdhelp history opthelp wizhelp SPEC_LEVS = asmodeus.lev baalz.lev bigrm-*.lev castle.lev fakewiz?.lev \ juiblex.lev knox.lev medusa-?.lev minend-?.lev minefill.lev \ minetn-?.lev oracle.lev orcus.lev sanctum.lev soko?-?.lev \ tower?.lev valley.lev wizard?.lev \ astral.lev air.lev earth.lev fire.lev water.lev QUEST_LEVS = ???-goal.lev ???-fil?.lev ???-loca.lev ???-strt.lev DATNODLB = $(VARDATND) license DATDLB = $(DATHELP) dungeon tribute $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD) DAT = $(DATNODLB) $(DATDLB) $(GAME): ( cd src ; $(MAKE) ) all: $(GAME) recover Guidebook $(VARDAT) dungeon spec_levs check-dlb true; $(MOREALL) @echo "Done." # Note: many of the dependencies below are here to allow parallel make # to generate valid output Guidebook: ( cd doc ; $(MAKE) Guidebook ) manpages: ( cd doc ; $(MAKE) manpages ) data: $(GAME) ( cd dat ; $(MAKE) data ) engrave: $(GAME) ( cd dat ; $(MAKE) engrave ) bogusmon: $(GAME) ( cd dat ; $(MAKE) bogusmon ) epitaph: $(GAME) ( cd dat ; $(MAKE) epitaph ) rumors: $(GAME) ( cd dat ; $(MAKE) rumors ) oracles: $(GAME) ( cd dat ; $(MAKE) oracles ) # Note: options should have already been made with make, but... options: $(GAME) ( cd dat ; $(MAKE) options ) quest.dat: $(GAME) ( cd dat ; $(MAKE) quest.dat ) spec_levs: dungeon ( cd util ; $(MAKE) lev_comp ) ( cd dat ; $(MAKE) spec_levs ) ( cd dat ; $(MAKE) quest_levs ) dungeon: $(GAME) ( cd util ; $(MAKE) dgn_comp ) ( cd dat ; $(MAKE) dungeon ) nhtiles.bmp: $(GAME) ( cd dat ; $(MAKE) nhtiles.bmp ) x11tiles: $(GAME) ( cd util ; $(MAKE) tile2x11 ) ( cd dat ; $(MAKE) x11tiles ) beostiles: $(GAME) ( cd util ; $(MAKE) tile2beos ) ( cd dat ; $(MAKE) beostiles ) NetHack.ad: $(GAME) ( cd dat ; $(MAKE) NetHack.ad ) pet_mark.xbm: ( cd dat ; $(MAKE) pet_mark.xbm ) pilemark.xbm: ( cd dat ; $(MAKE) pilemark.xbm ) rip.xpm: ( cd dat ; $(MAKE) rip.xpm ) mapbg.xpm: (cd dat ; $(MAKE) mapbg.xpm ) nhsplash.xpm: ( cd dat ; $(MAKE) nhsplash.xpm ) nh16.img: $(GAME) ( cd util ; $(MAKE) tile2img.ttp ) ( cd dat ; $(MAKE) nh16.img ) rip.img: ( cd util ; $(MAKE) xpm2img.ttp ) ( cd dat ; $(MAKE) rip.img ) GEM_RSC.RSC: ( cd dat ; $(MAKE) GEM_RSC.RSC ) title.img: ( cd dat ; $(MAKE) title.img ) check-dlb: options @if egrep -s librarian dat/options ; then $(MAKE) dlb ; else true ; fi dlb: ( cd util ; $(MAKE) dlb ) ( cd dat ; ../util/dlb cf nhdat $(DATDLB) ) # recover can be used when INSURANCE is defined in include/config.h # and the checkpoint option is true recover: $(GAME) ( cd util ; $(MAKE) recover ) dofiles: target=`sed -n \ -e '/librarian/{' \ -e 's/.*/dlb/p' \ -e 'q' \ -e '}' \ -e '$$s/.*/nodlb/p' < dat/options` ; \ $(MAKE) dofiles-$${target-nodlb} (cd dat ; cp symbols $(INSTDIR) ) cp src/$(GAME) $(INSTDIR) cp util/recover $(INSTDIR) -if test -n '$(SHELLDIR)'; then rm -f $(SHELLDIR)/$(GAME); fi if test -n '$(SHELLDIR)'; then \ sed -e 's;/usr/games/lib/nethackdir;$(HACKDIR);' \ -e 's;HACKDIR/nethack;HACKDIR/$(GAME);' \ < sys/unix/nethack.sh \ > $(SHELLDIR)/$(GAME) ; fi # set up their permissions -( cd $(INSTDIR) ; $(CHOWN) $(GAMEUID) $(GAME) recover ; \ $(CHGRP) $(GAMEGRP) $(GAME) recover ) chmod $(GAMEPERM) $(INSTDIR)/$(GAME) chmod $(EXEPERM) $(INSTDIR)/recover -if test -n '$(SHELLDIR)'; then \ $(CHOWN) $(GAMEUID) $(SHELLDIR)/$(GAME); fi if test -n '$(SHELLDIR)'; then \ $(CHGRP) $(GAMEGRP) $(SHELLDIR)/$(GAME); \ chmod $(EXEPERM) $(SHELLDIR)/$(GAME); fi -( cd $(INSTDIR) ; $(CHOWN) $(GAMEUID) symbols ; \ $(CHGRP) $(GAMEGRP) symbols ; \ chmod $(FILEPERM) symbols ) dofiles-dlb: check-dlb ( cd dat ; cp nhdat $(DATNODLB) $(INSTDIR) ) # set up their permissions -( cd $(INSTDIR) ; $(CHOWN) $(GAMEUID) nhdat $(DATNODLB) ; \ $(CHGRP) $(GAMEGRP) nhdat $(DATNODLB) ; \ chmod $(FILEPERM) nhdat $(DATNODLB) ) dofiles-nodlb: # copy over the game files ( cd dat ; cp $(DAT) $(INSTDIR) ) # set up their permissions -( cd $(INSTDIR) ; $(CHOWN) $(GAMEUID) $(DAT) ; \ $(CHGRP) $(GAMEGRP) $(DAT) ; \ chmod $(FILEPERM) $(DAT) ) update: $(GAME) recover $(VARDAT) dungeon spec_levs # (don't yank the old version out from under people who're playing it) -mv $(INSTDIR)/$(GAME) $(INSTDIR)/$(GAME).old # quest.dat is also kept open and has the same problems over NFS # (quest.dat may be inside nhdat if dlb is in use) -mv $(INSTDIR)/quest.dat $(INSTDIR)/quest.dat.old -mv $(INSTDIR)/nhdat $(INSTDIR)/nhdat.old # set up new versions of the game files ( $(MAKE) dofiles ) # touch time-sensitive files -touch -c $(VARDIR)/bones* $(VARDIR)/?lock* $(VARDIR)/wizard* -touch -c $(VARDIR)/save/* touch $(VARDIR)/perm $(VARDIR)/record # and a reminder @echo You may also want to install the man pages via the doc Makefile. rootcheck: @true; $(ROOTCHECK) install: rootcheck $(GAME) recover $(VARDAT) dungeon spec_levs true; $(PREINSTALL) # set up the directories # not all mkdirs have -p; those that don't will create a -p directory -if test -n '$(SHELLDIR)'; then \ mkdir -p $(SHELLDIR); fi rm -rf $(INSTDIR) $(VARDIR) -mkdir -p $(INSTDIR) $(VARDIR) $(VARDIR)/save if test -d ./-p; then rmdir ./-p; fi -$(CHOWN) $(GAMEUID) $(INSTDIR) $(VARDIR) $(VARDIR)/save $(CHGRP) $(GAMEGRP) $(INSTDIR) $(VARDIR) $(VARDIR)/save # order counts here: chmod $(DIRPERM) $(INSTDIR) chmod $(VARDIRPERM) $(VARDIR) $(VARDIR)/save # set up the game files ( $(MAKE) dofiles ) # set up some additional files touch $(VARDIR)/perm $(VARDIR)/record $(VARDIR)/logfile $(VARDIR)/xlogfile -( cd $(VARDIR) ; $(CHOWN) $(GAMEUID) perm record logfile xlogfile ; \ $(CHGRP) $(GAMEGRP) perm record logfile xlogfile ; \ chmod $(VARFILEPERM) perm record logfile xlogfile ) true; $(POSTINSTALL) # and a reminder @echo You may also want to reinstall the man pages via the doc Makefile. # 'make clean' removes all the .o files, but leaves around all the executables # and compiled data files clean: ( cd src ; $(MAKE) clean ) ( cd util ; $(MAKE) clean ) ( cd doc ; $(MAKE) clean ) # 'make spotless' returns the source tree to near-distribution condition. # it removes .o files, executables, and compiled data files spotless: ( cd src ; $(MAKE) spotless ) ( cd util ; $(MAKE) spotless ) ( cd dat ; $(MAKE) spotless ) ( cd doc ; $(MAKE) spotless ) nethack-3.6.0/sys/unix/Makefile.utl0000664000076400007660000003550112631241231016200 0ustar paxedpaxed# Makefile for NetHack's utility programs. # NetHack 3.6 Makefile.utl $NHDT-Date: 1449386560 2015/12/06 07:22:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ # Root of source tree: NHSROOT=.. # newer makes predefine $(MAKE) to 'make' and do smarter processing of # recursive make calls if $(MAKE) is used # these makes allow $(MAKE) to be overridden by the environment if someone # wants to (or has to) use something other than the standard make, so we do # not want to unconditionally set $(MAKE) here # # unfortunately, some older makes do not predefine $(MAKE); if you have one of # these, uncomment the following line # (you will know that you have one if you get complaints about unable to # execute things like 'foo.o') # MAKE = make # if you are using gcc as your compiler, # uncomment the CC definition below if it's not in your environment # CC = gcc # # For Bull DPX/2 systems at B.O.S. 2.0 or higher use the following: # # CC = gcc -ansi -D_BULL_SOURCE -D_XOPEN_SOURCE -D_POSIX_SOURCE # # If you are using GCC 2.2.2 or higher on a DPX/2, just use: # # CC = gcc -ansi # # For HP/UX 10.20 with GCC: # CC = gcc -D_POSIX_SOURCE # # if your make doesn't define a default SHELL properly, you may need # the line below (Atari users will need a bourne work-alike) # SHELL = /bin/sh # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # flags may have to be changed as required # flags for 286 Xenix: # CFLAGS = -Ml2t16 -O -LARGE -I../include # LFLAGS = -Ml -F 4000 -SEG 512 # flags for 286 Microport SysV-AT # CFLAGS = -DDUMB -Ml -I../include # LFLAGS = -Ml # flags for Atari GCC (3.2.1) # CFLAGS = -O -I../include # LFLAGS = -s # flags for Atari GCC (3.3) # CFLAGS = -mshort -O2 -I../include # LFLAGS = -mshort -s # flags for Apollos using their native cc # (as long as it claims to be __STDC__ but isn't) # CFLAGS = -DAPOLLO -O -I../include # flags for AIX 3.1 cc on IBM RS/6000 to define # a suitable subset of standard libraries # (note that there is more info regarding the "-qchars=signed" # switch in file Install.unx note 8) # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -O -I../include -qchars=signed # and for AIX 3.2: # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -D_ALL_SOURCE -O -I../include -qchars=signed # flags for A/UX 2.01 using native cc or c89 # gcc predefines AUX so that's not needed there # CFLAGS = -ZS -D_POSIX_SOURCE -O -I../include -DAUX # flags for IRIX 4.0.x using native cc # SGI cc 3.10 will fail to compile makedefs with -O # CFLAGS = -I../include -D__STDC__ -woff 100,293 # flags for Linux # compile normally # CFLAGS = -O2 -fomit-frame-pointer -I../include # LFLAGS = -L/usr/X11R6/lib # OR compile backwards compatible a.out format # CFLAGS = -O2 -b i486-linuxaout -fomit-frame-pointer -I../include # LFLAGS = -b i486-linuxaout -L/usr/X11R6/lib # flags for BeOS using the command line # remember to uncomment flex and bison below # BeOS on a Mac/BeBox: #CC = mwcc #CFLAGS = -I../include # BeOS on Intel: # the default values are fine # flags for debugging: # CFLAGS = -g -I../include #CFLAGS = -O -I../include #LFLAGS = LIBS = # If you are cross-compiling, you must use this: #OBJDIR = . # otherwise, you can save a little bit of disk space with this: OBJDIR = ../src # yacc/lex programs to use to generate *_comp.h, *_lex.c, and *_yacc.c. # if, instead of yacc/lex you have bison/flex, comment/uncomment the following. YACC = yacc LEX = lex # YACC = bison -y # YACC = byacc # LEX = flex # these are the names of the output files from YACC/LEX. Under MS-DOS # and similar systems, they may differ YTABC = y.tab.c YTABH = y.tab.h LEXYYC = lex.yy.c # YTABC = y_tab.c # YTABH = y_tab.h # LEXYYC = lexyy.c # ---------------------------------------- # # Nothing below this line should have to be changed. # timestamps for primary header files, matching src/Makefile CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t # utility .c files MAKESRC = makedefs.c SPLEVSRC = lev_yacc.c lev_lex.c lev_main.c DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c RECOVSRC = recover.c DLBSRC = dlb_main.c UTILSRCS = $(MAKESRC) panic.c $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC) # files that define all monsters and objects CMONOBJ = ../src/monst.c ../src/objects.c OMONOBJ = $(OBJDIR)/monst.o $(OBJDIR)/objects.o # files that provide access to NetHack's names CNAMING = ../src/drawing.c ../src/decl.c $(CMONOBJ) ONAMING = $(OBJDIR)/drawing.o $(OBJDIR)/decl.o $(OMONOBJ) # dynamic memory allocation CALLOC = ../src/alloc.c panic.c OALLOC = $(OBJDIR)/alloc.o panic.o # object files for makedefs MAKEOBJS = makedefs.o $(OMONOBJ) # object files for special levels compiler SPLEVOBJS = lev_yacc.o lev_lex.o lev_main.o $(OALLOC) $(ONAMING) # object files for dungeon compiler DGNCOMPOBJS = dgn_yacc.o dgn_lex.o dgn_main.o $(OALLOC) # object files for recovery utility RECOVOBJS = recover.o # object files for the data librarian DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC) # flags for creating distribution versions of sys/share/*_lex.c, using # a more portable flex skeleton, which is not included in the distribution. # hopefully keeping this out of the section to be edited will keep too # many people from being confused by it... # FLEXDIST = -L -S../sys/share/flexhack.skl FLEXDIST = # # flags for creating distribution versions of sys/share/*_yacc.c, without # line numbers so patches from version to version are practical # YACCDIST = -l YACCDIST = # dependencies for makedefs # makedefs: $(MAKEOBJS) mdgrep.h $(CC) $(LFLAGS) -o makedefs $(MAKEOBJS) makedefs.o: makedefs.c $(CONFIG_H) ../include/permonst.h \ ../include/objclass.h ../include/monsym.h \ ../include/artilist.h ../include/dungeon.h ../include/obj.h \ ../include/monst.h ../include/you.h ../include/flag.h \ ../include/dlb.h ../include/patchlevel.h ../include/qtext.h # Don't require perl to build; that is why mdgrep.h is spelled wrong below. mdgreph: mdgrep.pl perl mdgrep.pl ../include/onames.h: makedefs ./makedefs -o ../include/pm.h: makedefs ./makedefs -p ../src/monstr.c: makedefs ./makedefs -m ../include/vis_tab.h: makedefs ./makedefs -z # makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first ../src/vis_tab.c: ../include/vis_tab.h lintdefs: @lint -axbh -I../include -DLINT $(MAKESRC) $(CMONOBJ) | sed '/_flsbuf/d' # we defer this makedefs call to the src Makefile, since it knows all about # the main src and include files date.h is a timestamp for ../include/date.h:: @( cd ../src ; $(MAKE) ../include/date.h ) # support code used by several of the utility programs (but not makedefs) panic.o: panic.c $(CONFIG_H) # dependencies for lev_comp # lev_comp: $(SPLEVOBJS) $(CC) $(LFLAGS) -o lev_comp $(SPLEVOBJS) $(LIBS) lev_yacc.o: lev_yacc.c $(HACK_H) ../include/sp_lev.h lev_main.o: lev_main.c $(HACK_H) ../include/sp_lev.h ../include/tcap.h \ ../include/date.h # see lev_comp.l for WEIRD_LEX discussion # egrep will return failure if it doesn't find anything, but we know there # is one "_cplusplus" inside a comment lev_lex.o: lev_lex.c $(HACK_H) ../include/lev_comp.h ../include/sp_lev.h @echo $(CC) -c $(CFLAGS) lev_lex.c @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus lev_lex.c` lev_lex.c # '$(YACC) -d' generates both $(YTABC) and $(YTABH) in one run ../include/lev_comp.h: lev_yacc.c lev_yacc.c: lev_comp.y $(YACC) $(YACCDIST) -d lev_comp.y sed -e 's#"$(YTABC)"#"$@"#' -e 's#$(YTABC):#$@:#' $(YTABC) > $@ \ && rm $(YTABC) sed -e 's#"$(YTABH)"#"lev_comp.h"#' $(YTABH) > ../include/lev_comp.h \ && rm $(YTABH) lev_lex.c: lev_comp.l $(LEX) $(FLEXDIST) lev_comp.l sed -e 's#"$(LEXYYC)"#"$@"#' -e 's# *$$##' $(LEXYYC) > $@ \ && rm $(LEXYYC) # note: flex code construction using m4 macros results in some trailing # spaces; is basic RE substitute for # and we don't bother stripping trailing tabs because that gets messy; # make expands into which is RE end-of-line. # with all of extern.h's functions to complain about, we drown in # 'defined but not used' without -u lintlev: @lint -axhu -I../include -DLINT $(SPLEVSRC) $(CALLOC) $(CNAMING) | sed '/_flsbuf/d' # dependencies for dgn_comp # dgn_comp: $(DGNCOMPOBJS) $(CC) $(LFLAGS) -o dgn_comp $(DGNCOMPOBJS) $(LIBS) dgn_yacc.o: dgn_yacc.c $(CONFIG_H) ../include/dgn_file.h ../include/date.h dgn_main.o: dgn_main.c $(CONFIG_H) ../include/dlb.h # see dgn_comp.l for WEIRD_LEX discussion dgn_lex.o: dgn_lex.c $(CONFIG_H) ../include/dgn_comp.h ../include/dgn_file.h @echo $(CC) -c $(CFLAGS) dgn_lex.c @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus dgn_lex.c` dgn_lex.c # '$(YACC) -d' generates both $(YTABC) and $(YTABH) in one run ../include/dgn_comp.h: dgn_yacc.c dgn_yacc.c: dgn_comp.y $(YACC) $(YACCDIST) -d dgn_comp.y sed -e 's#"$(YTABC)"#"$@"#' -e 's#$(YTABC):#$@:#' $(YTABC) > $@ \ && rm $(YTABC) sed -e 's#"$(YTABH)"#"dgn_comp.h"#' $(YTABH) > ../include/dgn_comp.h \ && rm $(YTABH) dgn_lex.c: dgn_comp.l $(LEX) $(FLEXDIST) dgn_comp.l sed -e 's#"$(LEXYYC)"#"$@"#' -e 's# *$$##' $(LEXYYC) > $@ \ && rm $(LEXYYC) # note: is basic RE substitute for # with all of extern.h's functions to complain about, we drown in # 'defined but not used' without -u lintdgn: @lint -axhu -I../include -DLINT $(DGNCOMPSRC) $(CALLOC) | sed '/_flsbuf/d' # dependencies for recover # recover: $(RECOVOBJS) $(CC) $(LFLAGS) -o recover $(RECOVOBJS) $(LIBS) recover.o: recover.c $(CONFIG_H) ../include/date.h # dependencies for dlb # dlb: $(DLBOBJS) $(CC) $(LFLAGS) -o dlb $(DLBOBJS) $(LIBS) dlb_main.o: dlb_main.c $(CONFIG_H) ../include/dlb.h ../include/date.h $(CC) $(CFLAGS) -c dlb_main.c # dependencies for tile utilities # TEXT_IO = tiletext.o tiletxt.o $(ONAMING) GIFREADERS = gifread.o $(OALLOC) PPMWRITERS = ppmwrite.o $(OALLOC) tileutils: tilemap gif2txt txt2ppm tile2x11 gif2txt: $(GIFREADERS) $(TEXT_IO) $(CC) $(LFLAGS) -o gif2txt $(GIFREADERS) $(TEXT_IO) $(LIBS) txt2ppm: $(PPMWRITERS) $(TEXT_IO) $(CC) $(LFLAGS) -o txt2ppm $(PPMWRITERS) $(TEXT_IO) $(LIBS) tile2x11: tile2x11.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2x11 tile2x11.o $(TEXT_IO) $(LIBS) tile2img.ttp: tile2img.o bitmfile.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2img.ttp tile2img.o bitmfile.o $(TEXT_IO) $(LIBS) tile2bmp: tile2bmp.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2bmp tile2bmp.o $(TEXT_IO) xpm2img.ttp: xpm2img.o bitmfile.o $(CC) $(LFLAGS) -o xpm2img.ttp xpm2img.o bitmfile.o $(LIBS) tile2beos: tile2beos.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2beos tile2beos.o $(TEXT_IO) -lbe #--compiling and linking in one step leaves extra debugging files (in their # own subdirectories!) on OSX; compile and link separately to suppress # that without mucking about with extra OS-specific CFLAGS and/or LFLAGS #tilemap: ../win/share/tilemap.c $(HACK_H) # $(CC) $(CFLAGS) $(LFLAGS) -o tilemap ../win/share/tilemap.c $(LIBS) tilemap: tilemap.o $(CC) $(LFLAGS) -o tilemap tilemap.o $(LIBS) ../src/tile.c: tilemap ./tilemap ../include/tile.h: ../win/share/tile.h cp ../win/share/tile.h ../include/tile.h tiletext.o: ../win/share/tiletext.c $(CONFIG_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/tiletext.c tiletxt.c: ./Makefile echo '/* alternate compilation for tilemap.c to create tiletxt.o' > tiletxt.c echo ' that does not rely on "cc -c -o tiletxt.o tilemap.c"' >> tiletxt.c echo ' since many pre-POSIX compilers did not support that */' >> tiletxt.c echo '#define TILETEXT' >> tiletxt.c echo '#include "../win/share/tilemap.c"' >> tiletxt.c echo '/*tiletxt.c*/' >> tiletxt.c tiletxt.o: tiletxt.c ../win/share/tilemap.c $(HACK_H) $(CC) $(CFLAGS) -c tiletxt.c tilemap.o: ../win/share/tilemap.c $(HACK_H) $(CC) $(CFLAGS) -c ../win/share/tilemap.c gifread.o: ../win/share/gifread.c $(CONFIG_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/gifread.c ppmwrite.o: ../win/share/ppmwrite.c $(CONFIG_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/ppmwrite.c tile2bmp.o: ../win/share/tile2bmp.c $(HACK_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/tile2bmp.c tile2x11.o: ../win/X11/tile2x11.c $(HACK_H) ../include/tile.h \ ../include/tile2x11.h $(CC) $(CFLAGS) -c ../win/X11/tile2x11.c tile2img.o: ../win/gem/tile2img.c $(HACK_H) ../include/tile.h \ ../include/bitmfile.h $(CC) $(CFLAGS) -c ../win/gem/tile2img.c xpm2img.o: ../win/gem/xpm2img.c $(HACK_H) ../include/bitmfile.h $(CC) $(CFLAGS) -c ../win/gem/xpm2img.c bitmfile.o: ../win/gem/bitmfile.c ../include/bitmfile.h $(CC) $(CFLAGS) -c ../win/gem/bitmfile.c tile2beos.o: ../win/BeOS/tile2beos.cpp $(HACK_H) ../include/tile.h $(CXX) $(CFLAGS) -c ../win/BeOS/tile2beos.cpp tileedit: tileedit.cpp $(TEXT_IO) $(QTDIR)/bin/moc -o tileedit.moc tileedit.h $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib \ tileedit.cpp $(TEXT_IO) -lqt # using dependencies like # ../src/foo:: # @( cd ../src ; $(MAKE) foo ) # would always force foo to be up-to-date according to the src Makefile # when it's needed here. unfortunately, some makes believe this syntax # means foo always changes, instead of foo should always be checked. # therefore, approximate via config.h dependencies, and hope that anybody # changing anything other than basic configuration also knows when not # to improvise things not in the instructions, like 'make makedefs' here # in util... # make sure object files from src are available when needed # $(OBJDIR)/alloc.o: ../src/alloc.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/alloc.c -o $@ $(OBJDIR)/drawing.o: ../src/drawing.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/drawing.c -o $@ $(OBJDIR)/decl.o: ../src/decl.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/decl.c -o $@ $(OBJDIR)/monst.o: ../src/monst.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/monst.c -o $@ $(OBJDIR)/objects.o: ../src/objects.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/objects.c -o $@ $(OBJDIR)/dlb.o: ../src/dlb.c $(HACK_H) ../include/dlb.h $(CC) $(CFLAGS) -c ../src/dlb.c -o $@ # make sure hack.h dependencies get transitive information $(HACK_H): $(CONFIG_H) @( cd ../src ; $(MAKE) $(HACK_H) ) $(CONFIG_H): ../include/config.h @( cd ../src ; $(MAKE) $(CONFIG_H) ) # 'make dist' => put generated lex and yacc sources into place for distribution SYSSHARE=../sys/share/ $(SYSSHARE)lev_lex.c: lev_lex.c cp lev_lex.c $@ $(SYSSHARE)lev_yacc.c: lev_yacc.c cp lev_yacc.c $@ $(SYSSHARE)lev_comp.h: ../include/lev_comp.h cp ../include/lev_comp.h $@ $(SYSSHARE)dgn_lex.c: dgn_lex.c cp dgn_lex.c $@ $(SYSSHARE)dgn_yacc.c: dgn_yacc.c cp dgn_yacc.c $@ $(SYSSHARE)dgn_comp.h: ../include/dgn_comp.h cp ../include/dgn_comp.h $@ dist: $(SYSSHARE)lev_lex.c $(SYSSHARE)lev_yacc.c $(SYSSHARE)lev_comp.h \ $(SYSSHARE)dgn_lex.c $(SYSSHARE)dgn_yacc.c $(SYSSHARE)dgn_comp.h @echo 'pre-generated lex and yacc sources are in place in sys/share' tags: $(UTILSRCS) @ctags -tw $(UTILSRCS) clean: -rm -f *.o spotless: clean -rm -f lev_lex.c lev_yacc.c dgn_lex.c dgn_yacc.c -rm -f ../include/lev_comp.h ../include/dgn_comp.h -rm -f ../include/tile.h tiletxt.c -rm -f makedefs lev_comp dgn_comp recover dlb -rm -f gif2txt txt2ppm tile2x11 tile2img.ttp xpm2img.ttp \ tilemap tileedit nethack-3.6.0/sys/unix/NewInstall.unx0000664000076400007660000000311112536476415016563 0ustar paxedpaxed Instructions for installing NetHack 3.6 using the new hints system ======================================= For the moment, we are maintaining two ways to configure NetHack. The traditional system, in which Makefiles and includes are edited, and the new hints system which should be easier for most users to configure. If you are using the traditional configuration system, see Install.unx. 1. Look in the sys/unix/hints directory for a file that matches your system. If there isn't one, build one from the other files; if you need more help see the traditional instructions (in Install.unx) for hints. When you get it right please submit it to us. 2. Check the hints file for anything that may need to be changed for your installation. Most of the time little or nothing will need to be changed. 3. Configure and build: "$Top" is the top level source directory (the one with README in it). cd $Top/sys/unix sh setup.sh hints/NAME_OF_HINTS_FILE cd ../.. make all If the build fails, remove all the generated files before retrying the build with: cd $Top; make spotless 4. Install: Depending on your configuration, this step may or may not need to be done as root; check the hints file. NB: "make install" deletes nethackdir and recreates it from scratch - so if you want the record, logfile, or sysconf files, you must save and restore them manually. cd $Top make install 5. If it all worked, you're done. If something went wrong, see Install.unx for information about the settings the hints file tried to automate. nethack-3.6.0/sys/unix/README.linux0000664000076400007660000001020112617413107015750 0ustar paxedpaxedNetHack 3.6.0 Linux Elf $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ This README provides the instructions for using the official Linux binary, system platform requirements, as well as steps used to create that binary. The same steps can be used from the source distribution to create a similar binary. The official Linux binary has support for tty and X11 windowing systems, but not Qt. This means you will need to have X11 libraries installed on your system to run this binary, even in its tty flavor. The Linux binary package assumes that you have a user and a group named "games" on your system. If you do not, you can simplify installation by creating them first. Log in as or su to "root". Then, cd /, gunzip and untar the package, preserving permissions to put the NetHack files in /usr/games/nethack and /usr/games/lib/nethackdir. For example, if the package in in your home directory you might perform these steps. % su # cd / # tar xpvzf ~yourlogin/nethack-360-linux-X11.tgz If you have old record and logfile entries from a previous NetHack version, you might want to save copies before they get overwritten by the new empty files; old saved games and bones files from 3.4.x will not work with 3.6.0. If you are installing from the RPM, there is no need to save the old record and logfile; they are automatically preserved. In addition to data files for running the game, you will find other useful things in /usr/games/lib/nethackdir (such as a copy of this README :-). The general documentation Guidebook.txt and the processed man pages nethack.txt and recover.txt should provide an introduction to the game. The sample config file called dot.nethackrc can be used by copying it to your home directory as .nethackrc and modifying it to your liking. If you are running X11 copy the nh10.pcf and ibm.pcf font files from /usr/games/lib/nethackdir to a X11 fonts directory (such as /usr/X11/lib/X11/fonts/misc) and run "mkfontdir", then restart X windows to load them. If you prefer to use the graphical tiles, add the following to your .Xdefaults or .Xresources file: NetHack.tile_file: x11tiles You may need to run "xrdb -merge $HOME/.Xdefaults" (or .Xresources) after doing this. The official Linux binary is set up to run setgid games, which allows multiple users on your system to play the game and prevents cheating by unprivileged users. The usual default for NetHack is setuid games, but this causes problems with accessing .nethackrc on distributions with restrictive default security on home directories and users who don't know the tradeoffs of various permission settings. If you have problems, send us some email. nethack-bugs@nethack.org Steps used to build this binary release, in addition to the basic instructions found in sys/unix/Install.unx. The step numbers below correspond to the step numbers in sys/unix/Install.unx. System: gcc-3.2, XFree86-libs-4.2.1, ncurses-5.2, glibc-2.3.2 (GLIBC_2.3) 3. Edit include/config.h and include/unixconf.h config.h: define X11_GRAPHICS window support. define USE_XPM support. define COMPRESS as /bin/gzip as that is where it seems to reside on newer Linux's. define COMPRESS_EXTENSION as ".gz" define DLB unixconf.h: define LINUX define TIMED_DELAY 6. Makefile.src: define modern, non-BSD Linux and linux options throughout CC = gcc LFLAGS = -L/usr/X11R6/lib WINSRC = $(WINTTYSRC) $(WINX11SRC) WINOBJ = $(WINTTYOBJ) $(WINX11OBJ) WINTTYLIB = /usr/lib/libncurses.a WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11 WINLIB = $(WINTTYLIB) $(WINX11LIB) Makefile.utl: define modern, non-BSD Linux and linux options throughout Use bison/flex instead of yacc/lex CC = gcc LFLAGS = -L/usr/X11R6/lib YACC = bison -y LEX = flex 7. Makefile.top: GAMEGRP = games GAMEPERM = 02755 FILEPERM = 0664 EXEPERM = 0755 DIRPERM = 0775 VARDATND = x11tiles NetHack.ad pet_mark.xbm rip.xpm make all; su; make install 9. Additional step: As discussed in win/X11/Install.X11, convert nh10.bdf and ibm.bdf to proper font files and place in font path. nethack-3.6.0/sys/unix/cpp1.shr0000664000076400007660000015262712467321052015336 0ustar paxedpaxed# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # makefile.txt # readme.txt # cpp.mem # cpp.h # cppdef.h # cpp2.c # echo x - makefile.txt sed 's/^X//' >makefile.txt << 'END-of-makefile.txt' X# X# The redefinition of strchr() and strrchr() are needed for X# Ultrix-32, Unix 4.2 bsd (and maybe some other Unices). X# XBSDDEFINE = -Dstrchr=index -Dstrrchr=rindex X# X# On certain systems, such as Unix System III, you may need to define X# $(LINTFLAGS) in the make command line to set system-specific lint flags. X# X# This Makefile assumes cpp will replace the "standard" preprocessor. X# Delete the reference to -DLINE_PREFIX=\"\" if cpp is used stand-alone. X# LINEFIX is a sed script filter that reinserts #line -- used for testing X# if LINE_PREFIX is set to "". Note that we must stand on our heads to X# match the # and a line had better not begin with $. By the way, what X# we really want is X# LINEFIX = | sed "s/^#/#line/" X# XCPPDEFINE = -DLINE_PREFIX=\"\" XLINEFIX = | sed "s/^[^ !\"%-~]/&line/" X# X# Define OLD_PREPROCESSOR non-zero to make a preprocessor which is X# "as compatible as possible" with the standard Unix V7 or Ultrix X# preprocessors. This is needed to rebuild 4.2bsd, for example, as X# the preprocessor is used to modify assembler code, rather than C. X# This is not recommended for current development. OLD_PREPROCESSOR X# forces the following definitions: X# OK_DOLLAR FALSE $ is not allowed in variables X# OK_CONCAT FALSE # cannot concatenate tokens X# COMMENT_INVISIBLE TRUE old-style comment concatenation X# STRING_FORMAL TRUE old-style string expansion X# XOLDDEFINE = -DOLD_PREPROCESSOR=1 X# X# DEFINES collects all -D arguments for cc and lint: X# Change DEFINES = $(BSDDEFINE) $(CPPDEFINE) $(OLDDEFINE) X# for an old-style preprocessor. X# X# DEFINES = $(BSDDEFINE) $(CPPDEFINE) XDEFINES = $(CPPDEFINE) X XCFLAGS = -O $(DEFINES) X X# X# ** compile cpp X# XSRCS = cpp1.c cpp2.c cpp3.c cpp4.c cpp5.c cpp6.c XOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o Xcpp: $(OBJS) X $(CC) $(CFLAGS) $(OBJS) -o cpp X X# X# ** Test cpp by preprocessing itself, compiling the result, X# ** repeating the process and diff'ing the result. Note: this X# ** is not a good test of cpp, but a simple verification. X# ** The diff's should not report any changes. X# ** Note that a sed script may be executed for each compile X# Xtest: X cpp cpp1.c $(LINEFIX) >old.tmp1.c X cpp cpp2.c $(LINEFIX) >old.tmp2.c X cpp cpp3.c $(LINEFIX) >old.tmp3.c X cpp cpp4.c $(LINEFIX) >old.tmp4.c X cpp cpp5.c $(LINEFIX) >old.tmp5.c X cpp cpp6.c $(LINEFIX) >old.tmp6.c X $(CC) $(CFLAGS) old.tmp[123456].c X a.out cpp1.c >new.tmp1.c X a.out cpp2.c >new.tmp2.c X a.out cpp3.c >new.tmp3.c X a.out cpp4.c >new.tmp4.c X a.out cpp5.c >new.tmp5.c X a.out cpp6.c >new.tmp6.c X diff old.tmp1.c new.tmp1.c X diff old.tmp2.c new.tmp2.c X diff old.tmp3.c new.tmp3.c X diff old.tmp4.c new.tmp4.c X diff old.tmp5.c new.tmp5.c X diff old.tmp6.c new.tmp6.c X rm a.out old.tmp[123456].* new.tmp[123456].* X X# X# A somewhat more extensive test is provided by the "clock" X# program (which is not distributed). Substitute your favorite X# macro-rich program here. X# Xclock: clock.c cpp X cpp clock.c $(LINEFIX) >temp.cpp.c X cc temp.cpp.c -lcurses -ltermcap -o clock X rm temp.cpp.c X X# X# ** Lint the code X# X Xlint: $(SRCS) X lint $(LINTFLAGS) $(DEFINES) $(SRCS) X X# X# ** Remove unneeded files X# Xclean: X rm -f $(OBJS) cpp X X# X# ** Rebuild the archive files needed to distribute cpp X# ** Uses the Decus C archive utility. X# X Xarchc: archc.c X $(CC) $(CFLAGS) archc.c -o archc X Xarchx: archx.c X $(CC) $(CFLAGS) archx.c -o archx X Xarchive: archc X archc readme.txt cpp.mem archx.c archc.c cpp.rno makefile.txt \ X cpp*.h >cpp1.arc X archc cpp1.c cpp2.c cpp3.c >cpp2.arc X archc cpp4.c cpp5.c cpp6.c >cpp3.arc X X# X# Object module dependencies X# X Xcpp1.o : cpp1.c cpp.h cppdef.h X Xcpp2.o : cpp2.c cpp.h cppdef.h X Xcpp3.o : cpp3.c cpp.h cppdef.h X Xcpp4.o : cpp4.c cpp.h cppdef.h X Xcpp5.o : cpp5.c cpp.h cppdef.h X Xcpp6.o : cpp6.c cpp.h cppdef.h X X END-of-makefile.txt echo x - readme.txt sed 's/^X//' >readme.txt << 'END-of-readme.txt' X XDecus cpp is a public-domain implementation of the C preprocessor. XIt runs on VMS native (Vax C), VMS compatibilty mode (Decus C), XRSX-11M, RSTS/E, P/OS, and RT11, as well as on several varieties Xof Unix, including Ultrix. Decus cpp attempts to implement features Xin the Draft ANSI Standard for the C language. It should be noted, Xhowever, that this standard is under active development: the current Xdraft of the standard explicitly states that "readers are requested Xnot to specify or claim conformance to this draft." Thus readers Xand users of Decus cpp should not assume that it conforms to the Xdraft standard, or that it will conform to the actual C language Xstandard. X XThese notes describe how to extract the cpp source files, configure it Xfor your needs, and mention a few design decisions that may be of interest Xto maintainers. X X Installation X XBecause the primary development of cpp was not on Unix, it Xis distributed using the Decus C archive program (quite similar Xto the archiver published in Kernighan and Plauger's Software XTools). To extract the files from the net.sources distribution, Xsave this message as cpp1.arc and the other two distribution Xfiles as cpp2.arc and cpp3.arc. Then, using your favorite editor, Xlocate the archx.c program, just following the line beginning with X"-h- archx.c" -- the format of the distribution is just: X X -h- readme.txt X ... this file X -h- cpp.mem X ... description of cpp X -h- archx.c X ... archx.c program -- extracts archives X -h- archc.c X ... archc.c program -- creates archives X XCompile archx.c -- it shouldn't require any special editing. XThen run it as follows: X X archx *.arc X XYou do not need to remove mail headers from the saved messages. X XYou should then read through cppdef.h to make sure the HOST and XTARGET (and other implementation-specific) definitions are set Xcorrectly for your machine, editing them as needed. X XYou may then copy makefile.txt to Makefile, editing it as needed Xfor your particular system. On Unix, cpp should be compiled Xby make without further difficulty. On other operating systems, Xyou should compile the six source modules, linking them together. XNote that, on Decus C based systems, you must extend the default Xstack allocation. The Decus C build utility will create the Xappropriate command file. X X Support Notes X XThe USENET distribution kit was designed to keep all submissions around X50,000 bytes: X Xcpp1.arc: X readme.txt This file X cpp.mem Documentation page (see below) X archx.c Archive extraction program X archc.c Archive construction program X cpp.rno Source for cpp.mem (see below) X makefile.txt Unix makefile -- copy to Makefile X cpp.h Main header file (structure def's and globals) X cppdef.h Configuration file (host and target definitions) X Xcpp2.arc: X cpp1.c Mainline code, documentation master sources X cpp2.c most #control processing X cpp3.c filename stuff and command line parsing Xcpp3.arc: X cpp4.c #define processor X cpp5.c #if processor X cpp6.c Support code (symbol table and I/O routines) X XCpp intentionally does not rely on the presence of a full-scale Xmacro preprocessor, it does require the simple parameter substitution Xpreprocessor capabilities of Unix V6 and Decus C. If your C Xlanguage lacks full preprocessing, you should make sure "nomacargs" Xis #define'd in cpp.h. (This is done automatically by the Decus C Xcompiler.) X XThe documentation (manual page) for cpp is included as cpp.mem Xand cpp.rno. Cpp.rno is in Dec Runoff format, built by a Decus C Xutility (getrno) from original source which is embedded in cpp1.c. XTo my knowledge, there is no equivalent program that creates Xthe nroff source appropriate for Unix. X XI would be happy to receive fixes to any problems you encounter. XAs I do not maintain distribution kit base-levels, bare-bones Xdiff listings without sufficient context are not very useful. XIt is unlikely that I can find time to help you with other Xdifficulties. X X Acknowledgements X XI received a great deal of help from many people in debugging cpp. XAlan Feuer and Sam Kendall used "state of the art" run-time code Xcheckers to locate several errors. Ed Keiser found problems when Xcpp was used on machines with different int and pointer sizes. XDave Conroy helped with the initial debugging, while Arthur Olsen Xand George Rosenberg found (and solved) several problems in the Xfirst USENET release. X XMartin Minow Xdecvax!minow X END-of-readme.txt echo x - cpp.mem sed 's/^X//' >cpp.mem << 'END-of-cpp.mem' X X X X X 1.0 C Pre-Processor X X X X ******* X * cpp * X ******* X X X X NAME: cpp -- C Pre-Processor X X SYNOPSIS: X X cpp [-options] [infile [outfile]] X X DESCRIPTION: X X CPP reads a C source file, expands macros and include X files, and writes an input file for the C compiler. If X no file arguments are given, CPP reads from stdin and X writes to stdout. If one file argument is given, it X will define the input file, while two file arguments X define both input and output files. The file name "-" X is a synonym for stdin or stdout as appropriate. X X The following options are supported. Options may be X given in either case. X X -C If set, source-file comments are written X to the output file. This allows the X output of CPP to be used as the input to X a program, such as lint, that expects X commands embedded in specially-formatted X comments. X X -Dname=value Define the name as if the programmer X wrote X X #define name value X X at the start of the first file. If X "=value" is not given, a value of "1" X will be used. X X On non-unix systems, all alphabetic text X will be forced to upper-case. X X -E Always return "success" to the operating X system, even if errors were detected. X Note that some fatal errors, such as a X missing #include file, will terminate X CPP, returning "failure" even if the -E X option is given. X Page 2 X cpp C Pre-Processor X X X -Idirectory Add this directory to the list of X directories searched for #include "..." X and #include <...> commands. Note that X there is no space between the "-I" and X the directory string. More than one -I X command is permitted. On non-Unix X systems "directory" is forced to X upper-case. X X -N CPP normally predefines some symbols X defining the target computer and X operating system. If -N is specified, X no symbols will be predefined. If -N -N X is specified, the "always present" X symbols, __LINE__, __FILE__, and X __DATE__ are not defined. X X -Stext CPP normally assumes that the size of X the target computer's basic variable X types is the same as the size of these X types of the host computer. (This can X be overridden when CPP is compiled, X however.) The -S option allows dynamic X respecification of these values. "text" X is a string of numbers, separated by X commas, that specifies correct sizes. X The sizes must be specified in the exact X order: X X char short int long float double X X If you specify the option as "-S*text", X pointers to these types will be X specified. -S* takes one additional X argument for pointer to function (e.g. X int (*)()) X X For example, to specify sizes X appropriate for a PDP-11, you would X write: X X c s i l f d func X -S1,2,2,2,4,8, X -S*2,2,2,2,2,2,2 X X Note that all values must be specified. X X -Uname Undefine the name as if X X #undef name X X were given. On non-Unix systems, "name" X will be forced to upper-case. X Page 3 X cpp C Pre-Processor X X X -Xnumber Enable debugging code. If no value is X given, a value of 1 will be used. (For X maintenence of CPP only.) X X X PRE-DEFINED VARIABLES: X X When CPP begins processing, the following variables will X have been defined (unless the -N option is specified): X X Target computer (as appropriate): X X pdp11, vax, M68000 m68000 m68k X X Target operating system (as appropriate): X X rsx, rt11, vms, unix X X Target compiler (as appropriate): X X decus, vax11c X X The implementor may add definitions to this list. The X default definitions match the definition of the host X computer, operating system, and C compiler. X X The following are always available unless undefined (or X -N was specified twice): X X __FILE__ The input (or #include) file being X compiled (as a quoted string). X X __LINE__ The line number being compiled. X X __DATE__ The date and time of compilation as a X Unix ctime quoted string (the trailing X newline is removed). Thus, X X printf("Bug at line %s,", __LINE__); X printf(" source file %s", __FILE__); X printf(" compiled on %s", __DATE__); X X X DRAFT PROPOSED ANSI STANDARD CONSIDERATIONS: X X The current version of the Draft Proposed Standard X explicitly states that "readers are requested not to X specify or claim conformance to this draft." Readers and X users of Decus CPP should not assume that Decus CPP X conforms to the standard, or that it will conform to the X actual C Language Standard. X X When CPP is itself compiled, many features of the Draft X Proposed Standard that are incompatible with existing X Page 4 X cpp C Pre-Processor X X X preprocessors may be disabled. See the comments in X CPP's source for details. X X The latest version of the Draft Proposed Standard (as X reflected in Decus CPP) is dated November 12, 1984. X X Comments are removed from the input text. The comment X is replaced by a single space character. The -C option X preserves comments, writing them to the output file. X X The '$' character is considered to be a letter. This is X a permitted extension. X X The following new features of C are processed by CPP: X X #elif expression (#else #if) X '\xNNN' (Hexadecimal constant) X '\a' (Ascii BELL) X '\v' (Ascii Vertical Tab) X #if defined NAME 1 if defined, 0 if not X #if defined (NAME) 1 if defined, 0 if not X #if sizeof (basic type) X unary + X 123U, 123LU Unsigned ints and longs. X 12.3L Long double numbers X token#token Token concatenation X #include token Expands to filename X X The Draft Proposed Standard has extended C, adding a X constant string concatenation operator, where X X "foo" "bar" X X is regarded as the single string "foobar". (This does X not affect CPP's processing but does permit a limited X form of macro argument substitution into strings as will X be discussed.) X X The Standard Committee plans to add token concatenation X to #define command lines. One suggested implementation X is as follows: the sequence "Token1#Token2" is treated X as if the programmer wrote "Token1Token2". This could X be used as follows: X X #line 123 X #define ATLINE foo#__LINE__ X X ATLINE would be defined as foo123. X X Note that "Token2" must either have the format of an X identifier or be a string of digits. Thus, the string X X #define ATLINE foo#1x3 X Page 5 X cpp C Pre-Processor X X X generates two tokens: "foo1" and "x3". X X If the tokens T1 and T2 are concatenated into T3, this X implementation operates as follows: X X 1. Expand T1 if it is a macro. X 2. Expand T2 if it is a macro. X 3. Join the tokens, forming T3. X 4. Expand T3 if it is a macro. X X A macro formal parameter will be substituted into a X string or character constant if it is the only component X of that constant: X X #define VECSIZE 123 X #define vprint(name, size) \ X printf("name" "[" "size" "] = {\n") X ... vprint(vector, VECSIZE); X X expands (effectively) to X X vprint("vector[123] = {\n"); X X Note that this will be useful if your C compiler X supports the new string concatenation operation noted X above. As implemented here, if you write X X #define string(arg) "arg" X ... string("foo") ... X X This implementation generates "foo", rather than the X strictly correct ""foo"" (which will probably generate X an error message). This is, strictly speaking, an error X in CPP and may be removed from future releases. X X ERROR MESSAGES: X X Many. CPP prints warning or error messages if you try X to use multiple-byte character constants X (non-transportable) if you #undef a symbol that was not X defined, or if your program has potentially nested X comments. X X AUTHOR: X X Martin Minow X X BUGS: X X The #if expression processor uses signed integers only. X I.e, #if 0xFFFFu < 0 may be TRUE. X END-of-cpp.mem echo x - cpp.h sed 's/^X//' >cpp.h << 'END-of-cpp.h' X X/* X * I n t e r n a l D e f i n i t i o n s f o r C P P X * X * In general, definitions in this file should not be changed. X */ X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X#ifndef EOS X/* X * This is predefined in Decus C X */ X#define EOS '\0' /* End of string */ X#endif X#define EOF_CHAR 0 /* Returned by get() on eof */ X#define NULLST ((char *) NULL) /* Pointer to nowhere (linted) */ X#define DEF_NOARGS (-1) /* #define foo vs #define foo() */ X X/* X * The following may need to change if the host system doesn't use ASCII. X */ X#define DEF_MAGIC 0x1D /* Magic for #defines */ X#define TOK_SEP 0x1E /* Token concatenation delim. */ X#define COM_SEP 0x1F /* Magic comment separator */ X X/* X * Note -- in Ascii, the following will map macro formals onto DEL + the X * C1 control character region (decimal 128 .. (128 + PAR_MAC)) which will X * be ok as long as PAR_MAC is less than 33). Note that the last PAR_MAC X * value is reserved for string substitution. X */ X X#define MAC_PARM 0x7F /* Macro formals start here */ X#if PAR_MAC >= 33 X assertion fails -- PAR_MAC isn't less than 33 X#endif X#define LASTPARM (PAR_MAC - 1) X X/* X * Character type codes. X */ X X#define INV 0 /* Invalid, must be zero */ X#define OP_EOE INV /* End of expression */ X#define DIG 1 /* Digit */ X#define LET 2 /* Identifier start */ X#define FIRST_BINOP OP_ADD X#define OP_ADD 3 X#define OP_SUB 4 X#define OP_MUL 5 X#define OP_DIV 6 X#define OP_MOD 7 X#define OP_ASL 8 X#define OP_ASR 9 X#define OP_AND 10 /* &, not && */ X#define OP_OR 11 /* |, not || */ X#define OP_XOR 12 X#define OP_EQ 13 X#define OP_NE 14 X#define OP_LT 15 X#define OP_LE 16 X#define OP_GE 17 X#define OP_GT 18 X#define OP_ANA 19 /* && */ X#define OP_ORO 20 /* || */ X#define OP_QUE 21 /* ? */ X#define OP_COL 22 /* : */ X#define OP_CMA 23 /* , (relevant?) */ X#define LAST_BINOP OP_CMA /* Last binary operand */ X/* X * The following are unary. X */ X#define FIRST_UNOP OP_PLU /* First Unary operand */ X#define OP_PLU 24 /* + (draft ANSI standard) */ X#define OP_NEG 25 /* - */ X#define OP_COM 26 /* ~ */ X#define OP_NOT 27 /* ! */ X#define LAST_UNOP OP_NOT X#define OP_LPA 28 /* ( */ X#define OP_RPA 29 /* ) */ X#define OP_END 30 /* End of expression marker */ X#define OP_MAX (OP_END + 1) /* Number of operators */ X#define OP_FAIL (OP_END + 1) /* For error returns */ X X/* X * The following are for lexical scanning only. X */ X X#define QUO 65 /* Both flavors of quotation */ X#define DOT 66 /* . might start a number */ X#define SPA 67 /* Space and tab */ X#define BSH 68 /* Just a backslash */ X#define END 69 /* EOF */ X X/* X * These bits are set in ifstack[] X */ X#define WAS_COMPILING 1 /* TRUE if compile set at entry */ X#define ELSE_SEEN 2 /* TRUE when #else processed */ X#define TRUE_SEEN 4 /* TRUE when #if TRUE processed */ X X/* X * Define bits for the basic types and their adjectives X */ X X#define T_CHAR 1 X#define T_INT 2 X#define T_FLOAT 4 X#define T_DOUBLE 8 X#define T_SHORT 16 X#define T_LONG 32 X#define T_SIGNED 64 X#define T_UNSIGNED 128 X#define T_PTR 256 /* Pointer */ X#define T_FPTR 512 /* Pointer to functions */ X X/* X * The DEFBUF structure stores information about #defined X * macros. Note that the defbuf->repl information is always X * in malloc storage. X */ X Xtypedef struct defbuf { X struct defbuf *link; /* Next define in chain */ X char *repl; /* -> replacement */ X int hash; /* Symbol table hash */ X int nargs; /* For define(args) */ X char name[1]; /* #define name */ X} DEFBUF; X X/* X * The FILEINFO structure stores information about open files X * and macros being expanded. X */ X Xtypedef struct fileinfo { X char *bptr; /* Buffer pointer */ X int line; /* for include or macro */ X FILE *fp; /* File if non-null */ X struct fileinfo *parent; /* Link to includer */ X char *filename; /* File/macro name */ X char *progname; /* From #line statement */ X unsigned int unrecur; /* For macro recursion */ X char buffer[1]; /* current input line */ X} FILEINFO; X X/* X * The SIZES structure is used to store the values for #if sizeof X */ X Xtypedef struct sizes { X short bits; /* If this bit is set, */ X short size; /* this is the datum size value */ X short psize; /* this is the pointer size */ X} SIZES; X/* X * nomacarg is a built-in #define on Decus C. X */ X X#ifdef nomacarg X#define cput output /* cput concatenates tokens */ X#else X#if COMMENT_INVISIBLE X#define cput(c) { if (c != TOK_SEP && c != COM_SEP) putchar(c); } X#else X#define cput(c) { if (c != TOK_SEP) putchar(c); } X#endif X#endif X X#ifndef nomacarg X#define streq(s1, s2) (strcmp(s1, s2) == 0) X#endif X X/* X * Error codes. VMS uses system definitions. X * Decus C codes are defined in stdio.h. X * Others are cooked to order. X */ X X#if HOST == SYS_VMS X#include X#include X#define IO_NORMAL (SS$_NORMAL | STS$M_INHIB_MSG) X#define IO_ERROR SS$_ABORT X#endif X/* X * Note: IO_NORMAL and IO_ERROR are defined in the Decus C stdio.h file X */ X#ifndef IO_NORMAL X#define IO_NORMAL 0 X#endif X#ifndef IO_ERROR X#define IO_ERROR 1 X#endif X X/* X * Externs X */ X Xextern int line; /* Current line number */ Xextern int wrongline; /* Force #line to cc pass 1 */ Xextern char type[]; /* Character classifier */ Xextern char token[IDMAX + 1]; /* Current input token */ Xextern int instring; /* TRUE if scanning string */ Xextern int inmacro; /* TRUE if scanning #define */ Xextern int errors; /* Error counter */ Xextern int recursion; /* Macro depth counter */ Xextern char ifstack[BLK_NEST]; /* #if information */ X#define compiling ifstack[0] Xextern char *ifptr; /* -> current ifstack item */ Xextern char *incdir[NINCLUDE]; /* -i directories */ Xextern char **incend; /* -> active end of incdir */ Xextern int cflag; /* -C option (keep comments) */ Xextern int eflag; /* -E option (ignore errors) */ Xextern int nflag; /* -N option (no pre-defines) */ Xextern int rec_recover; /* unwind recursive macros */ Xextern char *preset[]; /* Standard predefined symbols */ Xextern char *magic[]; /* Magic predefined symbols */ Xextern FILEINFO *infile; /* Current input file */ Xextern char work[NWORK + 1]; /* #define scratch */ Xextern char *workp; /* Free space in work */ X#if DEBUG Xextern int debug; /* Debug level */ X#endif Xextern int keepcomments; /* Don't remove comments if set */ Xextern SIZES size_table[]; /* For #if sizeof sizes */ Xextern char *getmem(); /* Get memory or die. */ Xextern DEFBUF *lookid(); /* Look for a #define'd thing */ Xextern DEFBUF *defendel(); /* Symbol table enter/delete */ Xextern char *savestring(); /* Stuff string in malloc mem. */ Xextern char *strcpy(); Xextern char *strcat(); Xextern char *strrchr(); Xextern char *strchr(); Xextern long time(); X/* extern char *sprintf(); /* Lint needs this */ END-of-cpp.h echo x - cppdef.h sed 's/^X//' >cppdef.h << 'END-of-cppdef.h' X/* X * S y s t e m D e p e n d e n t X * D e f i n i t i o n s f o r C P P X * X * Definitions in this file may be edited to configure CPP for particular X * host operating systems and target configurations. X * X * NOTE: cpp assumes it is compiled by a compiler that supports macros X * with arguments. If this is not the case (as for Decus C), #define X * nomacarg -- and provide function equivalents for all macros. X * X * cpp also assumes the host and target implement the Ascii character set. X * If this is not the case, you will have to do some editing here and there. X */ X X/* X * This redundant definition of TRUE and FALSE works around X * a limitation of Decus C. X */ X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X X/* X * Define the HOST operating system. This is needed so that X * cpp can use appropriate filename conventions. X */ X#define SYS_UNKNOWN 0 X#define SYS_UNIX 1 X#define SYS_VMS 2 X#define SYS_RSX 3 X#define SYS_RT11 4 X#define SYS_LATTICE 5 X#define SYS_ONYX 6 X#define SYS_68000 7 X#define SYS_GCOS 8 X#define SYS_IBM 9 X#define SYS_OS 10 X#define SYS_TSS 11 X X#ifndef HOST X#ifdef unix X#define HOST SYS_UNIX X#else X#ifdef vms X#define HOST SYS_VMS X#else X#ifdef rsx X#define HOST SYS_RSX X#else X#ifdef rt11 X#define HOST SYS_RT11 X#else X#ifdef dmert X#define HOST SYS_DMERT X#else X#ifdef gcos X#define HOST SYS_GCOS X#else X#ifdef ibm X#define HOST SYS_IBM X#else X#ifdef os X#define HOST SYS_OS X#else X#ifdef tss X#define HOST SYS_TSS X#endif X#endif X#endif X#endif X#endif X#endif X#endif X#endif X#endif X X#ifndef HOST X#define HOST SYS_UNKNOWN X#endif X X/* X * We assume that the target is the same as the host system X */ X#ifndef TARGET X#define TARGET HOST X#endif X X/* X * In order to predefine machine-dependent constants, X * several strings are defined here: X * X * MACHINE defines the target cpu (by name) X * SYSTEM defines the target operating system X * COMPILER defines the target compiler X * X * The above may be #defined as "" if they are not wanted. X * They should not be #defined as NULL. X * X * LINE_PREFIX defines the # output line prefix, if not "line" X * This should be defined as "" if cpp is to replace X * the "standard" C pre-processor. X * X * FILE_LOCAL marks functions which are referenced only in the X * file they reside. Some C compilers allow these X * to be marked "static" even though they are referenced X * by "extern" statements elsewhere. X * X * OK_DOLLAR Should be set TRUE if $ is a valid alphabetic character X * in identifiers (default), or zero if $ is invalid. X * Default is TRUE. X * X * OK_CONCAT Should be set TRUE if # may be used to concatenate X * tokens in macros (per the Ansi Draft Standard) or X * FALSE for old-style # processing (needed if cpp is X * to process assembler source code). X * X * OK_DATE Predefines the compilation date if set TRUE. X * Not permitted by the Nov. 12, 1984 Draft Standard. X * X * S_CHAR etc. Define the sizeof the basic TARGET machine word types. X * By default, sizes are set to the values for the HOST X * computer. If this is inappropriate, see the code in X * cpp3.c for details on what to change. Also, if you X * have a machine where sizeof (signed int) differs from X * sizeof (unsigned int), you will have to edit code and X * tables in cpp3.c (and extend the -S option definition.) X * X * CPP_LIBRARY May be defined if you have a site-specific include directory X * which is to be searched *before* the operating-system X * specific directories. X */ X X#if TARGET == SYS_LATTICE X/* X * We assume the operating system is pcdos for the IBM-PC. X * We also assume the small model (just like the PDP-11) X */ X#define MACHINE "i8086" X#define SYSTEM "pcdos" X#endif X X#if TARGET == SYS_ONYX X#define MACHINE "z8000" X#define SYSTEM "unix" X#endif X X#if TARGET == SYS_VMS X#define MACHINE "vax" X#define SYSTEM "vms" X#define COMPILER "vax11c" X#endif X X#if TARGET == SYS_RSX X#define MACHINE "pdp11" X#define SYSTEM "rsx" X#define COMPILER "decus" X#endif X X#if TARGET == SYS_RT11 X#define MACHINE "pdp11" X#define SYSTEM "rt11" X#define COMPILER "decus" X#endif X X#if TARGET == SYS_68000 X/* X * All three machine designators have been seen in various systems. X * Warning -- compilers differ as to sizeof (int). cpp3 assumes that X * sizeof (int) == 2 X */ X#define MACHINE "M68000", "m68000", "m68k" X#define SYSTEM "unix" X#endif X X#if TARGET == SYS_UNIX X#define SYSTEM "unix" X#ifdef pdp11 X#define MACHINE "pdp11" X#endif X#ifdef vax X#define MACHINE "vax" X#endif X#ifdef u370 X#define MACHINE "u370" X#endif X#ifdef interdata X#define MACHINE "interdata" X#endif X#ifdef u3b X#define MACHINE "u3b" X#endif X#ifdef u3b5 X#define MACHINE "u3b5" X#endif X#ifdef u3b2 X#define MACHINE "u3b2" X#endif X#ifdef u3b20d X#define MACHINE "u3b20d" X#endif X#endif X#endif X X/* X * defaults X */ X X#ifndef MSG_PREFIX X#define MSG_PREFIX "cpp: " X#endif X X#ifndef LINE_PREFIX X#ifdef decus X#define LINE_PREFIX "" X#else X#define LINE_PREFIX "line" X#endif X#endif X X/* X * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT, X * COMMENT_INVISIBLE, and STRING_FORMAL to values appropriate for X * an old-style preprocessor. X */ X X#ifndef OLD_PREPROCESSOR X#define OLD_PREPROCESSOR FALSE X#endif X X#if OLD_PREPROCESSOR X#define OK_DOLLAR FALSE X#define OK_CONCAT FALSE X#define COMMENT_INVISIBLE TRUE X#define STRING_FORMAL TRUE X#endif X X/* X * RECURSION_LIMIT may be set to -1 to disable the macro recursion test. X */ X#ifndef RECURSION_LIMIT X#define RECURSION_LIMIT 1000 X#endif X X/* X * BITS_CHAR may be defined to set the number of bits per character. X * it is needed only for multi-byte character constants. X */ X#ifndef BITS_CHAR X#define BITS_CHAR 8 X#endif X X/* X * BIG_ENDIAN is set TRUE on machines (such as the IBM 360 series) X * where 'ab' stores 'a' in the high-bits and 'b' in the low-bits. X * It is set FALSE on machines (such as the PDP-11 and Vax-11) X * where 'ab' stores 'a' in the low-bits and 'b' in the high-bits. X * (Or is it the other way around?) -- Warning: BIG_ENDIAN code is untested. X */ X#ifndef BIG_ENDIAN X#define BIG_ENDIAN FALSE X#endif X X/* X * COMMENT_INVISIBLE may be defined to allow "old-style" comment X * processing, whereby the comment becomes a zero-length token X * delimiter. This permitted tokens to be concatenated in macro X * expansions. This was removed from the Draft Ansi Standard. X */ X#ifndef COMMENT_INVISIBLE X#define COMMENT_INVISIBLE FALSE X#endif X X/* X * STRING_FORMAL may be defined to allow recognition of macro parameters X * anywhere in replacement strings. This was removed from the Draft Ansi X * Standard and a limited recognition capability added. X */ X#ifndef STRING_FORMAL X#define STRING_FORMAL FALSE X#endif X X/* X * OK_DOLLAR enables use of $ as a valid "letter" in identifiers. X * This is a permitted extension to the Ansi Standard and is required X * for e.g., VMS, RSX-11M, etc. It should be set FALSE if cpp is X * used to preprocess assembler source on Unix systems. OLD_PREPROCESSOR X * sets OK_DOLLAR FALSE for that reason. X */ X#ifndef OK_DOLLAR X#define OK_DOLLAR TRUE X#endif X X/* X * OK_CONCAT enables (one possible implementation of) token concatenation. X * If cpp is used to preprocess Unix assembler source, this should be X * set FALSE as the concatenation character, #, is used by the assembler. X */ X#ifndef OK_CONCAT X#define OK_CONCAT TRUE X#endif X X/* X * OK_DATE may be enabled to predefine today's date as a string X * at the start of each compilation. This is apparently not permitted X * by the Draft Ansi Standard. X */ X#ifndef OK_DATE X#define OK_DATE TRUE X#endif X X/* X * Some common definitions. X */ X X#ifndef DEBUG X#define DEBUG FALSE X#endif X X/* X * The following definitions are used to allocate memory for X * work buffers. In general, they should not be modified X * by implementors. X * X * PAR_MAC The maximum number of #define parameters (31 per Standard) X * Note: we need another one for strings. X * IDMAX The longest identifier, 31 per Ansi Standard X * NBUFF Input buffer size X * NWORK Work buffer size -- the longest macro X * must fit here after expansion. X * NEXP The nesting depth of #if expressions X * NINCLUDE The number of directories that may be specified X * on a per-system basis, or by the -I option. X * BLK_NEST The number of nested #if's permitted. X */ X X#define IDMAX 31 X#define PAR_MAC (31 + 1) X#define NBUFF 1024 X#define NWORK 1024 X#define NEXP 128 X#define NINCLUDE 7 X#define NPARMWORK (NWORK * 2) X#define BLK_NEST 32 X X/* X * Some special constants. These may need to be changed if cpp X * is ported to a wierd machine. X * X * NOTE: if cpp is run on a non-ascii machine, ALERT and VT may X * need to be changed. They are used to implement the proposed X * ANSI standard C control characters '\a' and '\v' only. X * DEL is used to tag macro tokens to prevent #define foo foo X * from looping. Note that we don't try to prevent more elaborate X * #define loops from occurring. X */ X X#ifndef ALERT X#define ALERT '\007' /* '\a' is "Bell" */ X#endif X X#ifndef VT X#define VT '\013' /* Vertical Tab CTRL/K */ X#endif X X X#ifndef FILE_LOCAL X#ifdef decus X#define FILE_LOCAL static X#else X#ifdef vax11c X#define FILE_LOCAL static X#else X#define FILE_LOCAL /* Others are global */ X#endif X#endif X#endif X END-of-cppdef.h echo x - cpp2.c sed 's/^X//' >cpp2.c << 'END-of-cpp2.c' X/* X * C P P 2 . C X * X * Process #control lines X * X * Edit history X * 13-Nov-84 MM Split from cpp1.c X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X#if HOST == SYS_VMS X/* X * Include the rms stuff. (We can't just include rms.h as it uses the X * VaxC-specific library include syntax that Decus CPP doesn't support. X * By including things by hand, we can CPP ourself.) X */ X#include X#include X#include X#include X#endif X X/* X * Generate (by hand-inspection) a set of unique values for each control X * operator. Note that this is not guaranteed to work for non-Ascii X * machines. CPP won't compile if there are hash conflicts. X */ X X#define L_assert ('a' + ('s' << 1)) X#define L_define ('d' + ('f' << 1)) X#define L_elif ('e' + ('i' << 1)) X#define L_else ('e' + ('s' << 1)) X#define L_endif ('e' + ('d' << 1)) X#define L_ident ('i' + ('e' << 1)) X#define L_if ('i' + (EOS << 1)) X#define L_ifdef ('i' + ('d' << 1)) X#define L_ifndef ('i' + ('n' << 1)) X#define L_include ('i' + ('c' << 1)) X#define L_line ('l' + ('n' << 1)) X#define L_nogood (EOS + (EOS << 1)) /* To catch #i */ X#define L_pragma ('p' + ('a' << 1)) X#define L_sccs ('s' + ('c' << 1)) X#define L_undef ('u' + ('d' << 1)) X#if DEBUG X#define L_debug ('d' + ('b' << 1)) /* #debug */ X#define L_nodebug ('n' + ('d' << 1)) /* #nodebug */ X#endif X Xint Xcontrol(counter) Xint counter; /* Pending newline counter */ X/* X * Process #control lines. Simple commands are processed inline, X * while complex commands have their own subroutines. X * X * The counter is used to force out a newline before #line, and X * #pragma commands. This prevents these commands from ending up at X * the end of the previous line if cpp is invoked with the -C option. X */ X{ X register int c; X register char *tp; X register int hash; X char *ep; X X c = skipws(); X if (c == '\n' || c == EOF_CHAR) X return (counter + 1); X if (!isdigit(c)) X scanid(c); /* Get #word to token[] */ X else { X unget(); /* Hack -- allow #123 as a */ X strcpy(token, "line"); /* synonym for #line 123 */ X } X hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1)); X switch (hash) { X case L_assert: tp = "assert"; break; X case L_define: tp = "define"; break; X case L_elif: tp = "elif"; break; X case L_else: tp = "else"; break; X case L_endif: tp = "endif"; break; X case L_ident: tp = "ident"; break; X case L_if: tp = "if"; break; X case L_ifdef: tp = "ifdef"; break; X case L_ifndef: tp = "ifndef"; break; X case L_include: tp = "include"; break; X case L_line: tp = "line"; break; X case L_pragma: tp = "pragma"; break; X case L_sccs: tp = "sccs"; break; X case L_undef: tp = "undef"; break; X#if DEBUG X case L_debug: tp = "debug"; break; X case L_nodebug: tp = "nodebug"; break; X#endif X default: hash = L_nogood; X case L_nogood: tp = ""; break; X } X if (!streq(tp, token)) X hash = L_nogood; X /* X * hash is set to a unique value corresponding to the X * control keyword (or L_nogood if we think it's nonsense). X */ X if (infile->fp == NULL) X cwarn("Control line \"%s\" within macro expansion", token); X if (!compiling) { /* Not compiling now */ X switch (hash) { X case L_if: /* These can't turn */ X case L_ifdef: /* compilation on, but */ X case L_ifndef: /* we must nest #if's */ X if (++ifptr >= &ifstack[BLK_NEST]) X goto if_nest_err; X *ifptr = 0; /* !WAS_COMPILING */ X case L_line: /* Many */ X /* X * Are pragma's always processed? X */ X case L_ident: X case L_sccs: X case L_pragma: /* options */ X case L_include: /* are uninteresting */ X case L_define: /* if we */ X case L_undef: /* aren't */ X case L_assert: /* compiling. */ Xdump_line: skipnl(); /* Ignore rest of line */ X return (counter + 1); X } X } X /* X * Make sure that #line and #pragma are output on a fresh line. X */ X if (counter > 0 && (hash == L_line || hash == L_pragma)) { X putchar('\n'); X counter--; X } X switch (hash) { X case L_line: X /* X * Parse the line to update the line number and "progname" X * field and line number for the next input line. X * Set wrongline to force it out later. X */ X c = skipws(); X workp = work; /* Save name in work */ X while (c != '\n' && c != EOF_CHAR) { X save(c); X c = get(); X } X unget(); X save(EOS); X /* X * Split #line argument into and X * We subtract 1 as we want the number of the next line. X */ X line = atoi(work) - 1; /* Reset line number */ X for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++) X ; /* Skip over digits */ X if (*tp != EOS) { /* Got a filename, so: */ X if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) { X tp++; /* Skip over left quote */ X *ep = EOS; /* And ignore right one */ X } X if (infile->progname != NULL) /* Give up the old name */ X free(infile->progname); /* if it's allocated. */ X infile->progname = savestring(tp); X } X wrongline = TRUE; /* Force output later */ X break; X X case L_include: X doinclude(); X break; X X case L_define: X dodefine(); X break; X X case L_undef: X doundef(); X break; X X case L_else: X if (ifptr == &ifstack[0]) X goto nest_err; X else if ((*ifptr & ELSE_SEEN) != 0) X goto else_seen_err; X *ifptr |= ELSE_SEEN; X if ((*ifptr & WAS_COMPILING) != 0) { X if (compiling || (*ifptr & TRUE_SEEN) != 0) X compiling = FALSE; X else { X compiling = TRUE; X } X } X break; X X case L_elif: X if (ifptr == &ifstack[0]) X goto nest_err; X else if ((*ifptr & ELSE_SEEN) != 0) { Xelse_seen_err: cerror("#%s may not follow #else", token); X goto dump_line; X } X if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) { X compiling = FALSE; /* Done compiling stuff */ X goto dump_line; /* Skip this clause */ X } X doif(L_if); X break; X X case L_if: X case L_ifdef: X case L_ifndef: X if (++ifptr >= &ifstack[BLK_NEST]) Xif_nest_err: cfatal("Too many nested #%s statements", token); X *ifptr = WAS_COMPILING; X doif(hash); X break; X X case L_endif: X if (ifptr == &ifstack[0]) { Xnest_err: cerror("#%s must be in an #if", token); X goto dump_line; X } X if (!compiling && (*ifptr & WAS_COMPILING) != 0) X wrongline = TRUE; X compiling = ((*ifptr & WAS_COMPILING) != 0); X --ifptr; X break; X X case L_assert: X if (eval() == 0) X cerror("Preprocessor assertion failure", NULLST); X break; X X case L_ident: X case L_sccs: X goto dump_line; X break; X X case L_pragma: X /* X * #pragma is provided to pass "options" to later X * passes of the compiler. cpp doesn't have any yet. X */ X printf("#pragma "); X while ((c = get()) != '\n' && c != EOF_CHAR) X cput(c); X unget(); X break; X X#if DEBUG X case L_debug: X if (debug == 0) X dumpdef("debug set on"); X debug++; X break; X X case L_nodebug: X debug--; X break; X#endif X X default: X /* X * Undefined #control keyword. X * Note: the correct behavior may be to warn and X * pass the line to a subsequent compiler pass. X * This would allow #asm or similar extensions. X */ X cerror("Illegal # command \"%s\"", token); X break; X } X if (hash != L_include) { X#if OLD_PREPROCESSOR || !VERBOSE X /* X * Ignore the rest of the #control line so you can write X * #if foo X * #endif foo X */ X goto dump_line; /* Take common exit */ X#else X if (skipws() != '\n') { X cwarn("Unexpected text in #control line ignored", NULLST); X skipnl(); X } X#endif X } X return (counter + 1); X} X XFILE_LOCAL Xdoif(hash) Xint hash; X/* X * Process an #if, #ifdef, or #ifndef. The latter two are straightforward, X * while #if needs a subroutine of its own to evaluate the expression. X * X * doif() is called only if compiling is TRUE. If false, compilation X * is always supressed, so we don't need to evaluate anything. This X * supresses unnecessary warnings. X */ X{ X register int c; X register int found; X X if ((c = skipws()) == '\n' || c == EOF_CHAR) { X unget(); X goto badif; X } X if (hash == L_if) { X unget(); X found = (eval() != 0); /* Evaluate expr, != 0 is TRUE */ X hash = L_ifdef; /* #if is now like #ifdef */ X } X else { X if (type[c] != LET) /* Next non-blank isn't letter */ X goto badif; /* ... is an error */ X found = (lookid(c) != NULL); /* Look for it in symbol table */ X } X if (found == (hash == L_ifdef)) { X compiling = TRUE; X *ifptr |= TRUE_SEEN; X } X else { X compiling = FALSE; X } X return; X Xbadif: cerror("#if, #ifdef, or #ifndef without an argument", NULLST); X#if !OLD_PREPROCESSOR X skipnl(); /* Prevent an extra */ X unget(); /* Error message */ X#endif X return; X} X XFILE_LOCAL Xdoinclude() X/* X * Process the #include control line. X * There are three variations: X * #include "file" search somewhere relative to the X * current source file, if not found, X * treat as #include . X * #include Search in an implementation-dependent X * list of places. X * #include token Expand the token, it must be one of X * "file" or , process as such. X * X * Note: the November 12 draft forbids '>' in the #include format. X * This restriction is unnecessary and not implemented. X */ X{ X register int c; X register int delim; X#if HOST == SYS_VMS X char def_filename[NAM$C_MAXRSS + 1]; X#endif X X delim = macroid(skipws()); X if (delim != '<' && delim != '"') X goto incerr; X if (delim == '<') X delim = '>'; X workp = work; X instring = TRUE; /* Accept all characters */ X while ((c = get()) != '\n' && c != delim && c != EOF_CHAR) X save(c); /* Put it away. */ X skipnl(); X /* X * The draft is unclear if the following should be done. X */ X X while (--workp >= work && (type[*workp] == SPA)) X ; /* Trim blanks from filename */ X X/* X * if (*workp != delim) X * goto incerr; X */ X *(workp + 1) = EOS; /* Terminate filename */ X instring = FALSE; X#if HOST == SYS_VMS X /* X * Assume the default .h filetype. X */ X if (!vmsparse(work, ".H", def_filename)) { X perror(work); /* Oops. */ X goto incerr; X } X else if (openinclude(def_filename, (delim == '"'))) X return; X#else X if (openinclude(work, (delim == '"'))) X return; X#endif X /* X * No sense continuing if #include file isn't there. X */ X cfatal("Cannot open include file \"%s\"", work); X Xincerr: cerror("#include syntax error", NULLST); X return; X} X XFILE_LOCAL int Xopeninclude(filename, searchlocal) Xchar *filename; /* Input file name */ Xint searchlocal; /* TRUE if #include "file" */ X/* X * Actually open an include file. This routine is only called from X * doinclude() above, but was written as a separate subroutine for X * programmer convenience. It searches the list of directories X * and actually opens the file, linking it into the list of X * active files. Returns TRUE if the file was opened, FALSE X * if openinclude() fails. No error message is printed. X */ X{ X register char **incptr; X#if HOST == SYS_VMS X#if NWORK < (NAM$C_MAXRSS + 1) X << error, NWORK isn't greater than NAM$C_MAXRSS >> X#endif X#endif X char tmpname[NWORK]; /* Filename work area */ X X if (searchlocal) { X /* X * Look in local directory first X */ X#if HOST == SYS_UNIX X /* X * Try to open filename relative to the directory of the current X * source file (as opposed to the current directory). (ARF, SCK). X */ X if (filename[0] != '/' X && hasdirectory(infile->filename, tmpname)) X strcat(tmpname, filename); X else { X strcpy(tmpname, filename); X } X#else X if (!hasdirectory(filename, tmpname) X && hasdirectory(infile->filename, tmpname)) X strcat(tmpname, filename); X else { X strcpy(tmpname, filename); X } X#endif X if (openfile(tmpname)) X return (TRUE); X } X /* X * Look in any directories specified by -I command line X * arguments, then in the builtin search list. X */ X for (incptr = incdir; incptr < incend; incptr++) { X if (strlen(*incptr) + strlen(filename) >= (NWORK - 1)) X cfatal("Filename work buffer overflow", NULLST); X else { X#if HOST == SYS_UNIX X if (filename[0] == '/') X strcpy(tmpname, filename); X else { X sprintf(tmpname, "%s/%s", *incptr, filename); X } X#else X if (!hasdirectory(filename, tmpname)) X sprintf(tmpname, "%s%s", *incptr, filename); X#endif X if (openfile(tmpname)) X return (TRUE); X } X } X return (FALSE); X} X XFILE_LOCAL int Xhasdirectory(source, result) Xchar *source; /* Directory to examine */ Xchar *result; /* Put directory stuff here */ X/* X * If a device or directory is found in the source filename string, the X * node/device/directory part of the string is copied to result and X * hasdirectory returns TRUE. Else, nothing is copied and it returns FALSE. X */ X{ X#if HOST == SYS_UNIX X register char *tp; X X if ((tp = strrchr(source, '/')) == NULL) X return (FALSE); X else { X strncpy(result, source, tp - source + 1); X result[tp - source + 1] = EOS; X return (TRUE); X } X#else X#if HOST == SYS_VMS X if (vmsparse(source, NULLST, result) X && result[0] != EOS) X return (TRUE); X else { X return (FALSE); X } X#else X /* X * Random DEC operating system (RSX, RT11, RSTS/E) X */ X register char *tp; X X if ((tp = strrchr(source, ']')) == NULL X && (tp = strrchr(source, ':')) == NULL) X return (FALSE); X else { X strncpy(result, source, tp - source + 1); X result[tp - source + 1] = EOS; X return (TRUE); X } X#endif X#endif X} X X#if HOST == SYS_VMS X X/* X * EXP_DEV is set if a device was specified, EXP_DIR if a directory X * is specified. (Both set indicate a file-logical, but EXP_DEV X * would be set by itself if you are reading, say, SYS$INPUT:) X */ X#define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR) X XFILE_LOCAL int Xvmsparse(source, defstring, result) Xchar *source; Xchar *defstring; /* non-NULL -> default string. */ Xchar *result; /* Size is at least NAM$C_MAXRSS + 1 */ X/* X * Parse the source string, applying the default (properly, using X * the system parse routine), storing it in result. X * TRUE if it parsed, FALSE on error. X * X * If defstring is NULL, there are no defaults and result gets X * (just) the node::[directory] part of the string (possibly "") X */ X{ X struct FAB fab = cc$rms_fab; /* File access block */ X struct NAM nam = cc$rms_nam; /* File name block */ X char fullname[NAM$C_MAXRSS + 1]; X register char *rp; /* Result pointer */ X X fab.fab$l_nam = &nam; /* fab -> nam */ X fab.fab$l_fna = source; /* Source filename */ X fab.fab$b_fns = strlen(source); /* Size of source */ X fab.fab$l_dna = defstring; /* Default string */ X if (defstring != NULLST) X fab.fab$b_dns = strlen(defstring); /* Size of default */ X nam.nam$l_esa = fullname; /* Expanded filename */ X nam.nam$b_ess = NAM$C_MAXRSS; /* Expanded name size */ X if (sys$parse(&fab) == RMS$_NORMAL) { /* Parse away */ X fullname[nam.nam$b_esl] = EOS; /* Terminate string */ X result[0] = EOS; /* Just in case */ X rp = &result[0]; X /* X * Remove stuff added implicitly, accepting node names and X * dev:[directory] strings (but not process-permanent files). X */ X if ((nam.nam$l_fnb & NAM$M_PPF) == 0) { X if ((nam.nam$l_fnb & NAM$M_NODE) != 0) { X strncpy(result, nam.nam$l_node, nam.nam$b_node); X rp += nam.nam$b_node; X *rp = EOS; X } X if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) { X strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir); X rp += nam.nam$b_dev + nam.nam$b_dir; X *rp = EOS; X } X } X if (defstring != NULLST) { X strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type); X rp += nam.nam$b_name + nam.nam$b_type; X *rp = EOS; X if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) { X strncpy(rp, nam.nam$l_ver, nam.nam$b_ver); X rp[nam.nam$b_ver] = EOS; X } X } X return (TRUE); X } X return (FALSE); X} X#endif X END-of-cpp2.c exit nethack-3.6.0/sys/unix/cpp2.shr0000664000076400007660000015050112467321052015324 0ustar paxedpaxed# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # cpp1.c # cpp3.c # cpp4.c # echo x - cpp1.c sed 's/^X//' >cpp1.c << 'END-of-cpp1.c' X/* X * CPP main program. X * X * Edit history X * 21-May-84 MM "Field test" release X * 23-May-84 MM Some minor hacks. X * 30-May-84 ARF Didn't get enough memory for __DATE__ X * Added code to read stdin if no input X * files are provided. X * 29-Jun-84 MM Added ARF's suggestions, Unixifying cpp. X * 11-Jul-84 MM "Official" first release (that's what I thought!) X * 22-Jul-84 MM/ARF/SCK Fixed line number bugs, added cpp recognition X * of #line, fixed problems with #include. X * 23-Jul-84 MM More (minor) include hacking, some documentation. X * Also, redid cpp's #include files X * 25-Jul-84 MM #line filename isn't used for #include searchlist X * #line format is X * 25-Jul-84 ARF/MM Various bugs, mostly serious. Removed homemade doprint X * 01-Aug-84 MM Fixed recursion bug, remove extra newlines and X * leading whitespace from cpp output. X * 02-Aug-84 MM Hacked (i.e. optimized) out blank lines and unneeded X * whitespace in general. Cleaned up unget()'s. X * 03-Aug-84 Keie Several bug fixes from Ed Keizer, Vrije Universitet. X * -- corrected arg. count in -D and pre-defined X * macros. Also, allow \n inside macro actual parameter X * lists. X * 06-Aug-84 MM If debugging, dump the preset vector at startup. X * 12-Aug-84 MM/SCK Some small changes from Sam Kendall X * 15-Aug-84 Keie/MM cerror, cwarn, etc. take a single string arg. X * cierror, etc. take a single int. arg. X * changed LINE_PREFIX slightly so it can be X * changed in the makefile. X * 31-Aug-84 MM USENET net.sources release. X * 7-Sep-84 SCH/ado Lint complaints X * 10-Sep-84 Keie Char's can't be signed in some implementations X * 11-Sep-84 ado Added -C flag, pathological line number fix X * 13-Sep-84 ado Added -E flag (does nothing) and "-" file for stdin. X * 14-Sep-84 MM Allow # 123 as a synonym for #line 123 X * 19-Sep-84 MM scanid always reads to token, make sure #line is X * written to a new line, even if -C switch given. X * Also, cpp - - reads stdin, writes stdout. X * 03-Oct-84 ado/MM Several changes to line counting and keepcomments X * stuff. Also a rewritten control() hasher -- much X * simpler and no less "perfect". Note also changes X * in cpp3.c to fix numeric scanning. X * 04-Oct-84 MM Added recognition of macro formal parameters if X * they are the only thing in a string, per the X * draft standard. X * 08-Oct-84 MM One more attack on scannumber X * 15-Oct-84 MM/ado Added -N to disable predefined symbols. Fixed X * linecount if COMMENT_INVISIBLE enabled. X * 22-Oct-84 MM Don't evaluate the #if/#ifdef argument if X * compilation is supressed. This prevents X * unnecessary error messages in sequences such as X * #ifdef FOO -- undefined X * #if FOO == 10 -- shouldn't print warning X * 25-Oct-84 MM Fixed bug in false ifdef supression. On vms, X * #include should open foo.h -- this duplicates X * the behavior of Vax-C X * 31-Oct-84 ado/MM Parametized $ in indentifiers. Added a better X * token concatenator and took out the trial X * concatenation code. Also improved #ifdef code X * and cleaned up the macro recursion tester. X * 2-Nov-84 MM/ado Some bug fixes in token concatenation, also X * a variety of minor (uninteresting) hacks. X * 6-Nov-84 MM Happy Birthday. Broke into 4 files and added X * #if sizeof (basic_types) X * 9-Nov-84 MM Added -S* for pointer type sizes X * 13-Nov-84 MM Split cpp1.c, added vms defaulting X * 23-Nov-84 MM/ado -E supresses error exit, added CPP_INCLUDE, X * fixed strncpy bug. X * 3-Dec-84 ado/MM Added OLD_PREPROCESSOR X * 7-Dec-84 MM Stuff in Nov 12 Draft Standard X * 17-Dec-84 george Fixed problems with recursive macros X * 17-Dec-84 MM Yet another attack on #if's (f/t)level removed. X * 07-Jan-85 ado Init defines before doing command line options X * so -Uunix works. X */ X X/*)BUILD X $(PROGRAM) = cpp X $(FILES) = { cpp1 cpp2 cpp3 cpp4 cpp5 cpp6 } X $(INCLUDE) = { cppdef.h cpp.h } X $(STACK) = 2000 X $(TKBOPTIONS) = { X STACK = 2000 X } X*/ X X#ifdef DOCUMENTATION X Xtitle cpp C Pre-Processor Xindex C pre-processor X Xsynopsis X .s.nf X cpp [-options] [infile [outfile]] X .s.f Xdescription X X CPP reads a C source file, expands macros and include X files, and writes an input file for the C compiler. X If no file arguments are given, CPP reads from stdin X and writes to stdout. If one file argument is given, X it will define the input file, while two file arguments X define both input and output files. The file name "-" X is a synonym for stdin or stdout as appropriate. X X The following options are supported. Options may X be given in either case. X .lm +16 X .p -16 X -C If set, source-file comments are written X to the output file. This allows the output of CPP to be X used as the input to a program, such as lint, that expects X commands embedded in specially-formatted comments. X .p -16 X -Dname=value Define the name as if the programmer wrote X X #define name value X X at the start of the first file. If "=value" is not X given, a value of "1" will be used. X X On non-unix systems, all alphabetic text will be forced X to upper-case. X .p -16 X -E Always return "success" to the operating X system, even if errors were detected. Note that some fatal X errors, such as a missing #include file, will terminate X CPP, returning "failure" even if the -E option is given. X .p -16 X -Idirectory Add this directory to the list of X directories searched for #include "..." and #include <...> X commands. Note that there is no space between the X "-I" and the directory string. More than one -I command X is permitted. On non-Unix systems "directory" is forced X to upper-case. X .p -16 X -N CPP normally predefines some symbols defining X the target computer and operating system. If -N is specified, X no symbols will be predefined. If -N -N is specified, the X "always present" symbols, __LINE__, __FILE__, and __DATE__ X are not defined. X .p -16 X -Stext CPP normally assumes that the size of X the target computer's basic variable types is the same as the size X of these types of the host computer. (This can be overridden X when CPP is compiled, however.) The -S option allows dynamic X respecification of these values. "text" is a string of X numbers, separated by commas, that specifies correct sizes. X The sizes must be specified in the exact order: X X char short int long float double X X If you specify the option as "-S*text", pointers to these X types will be specified. -S* takes one additional argument X for pointer to function (e.g. int (*)()) X X For example, to specify sizes appropriate for a PDP-11, X you would write: X X c s i l f d func X -S1,2,2,2,4,8, X -S*2,2,2,2,2,2,2 X X Note that all values must be specified. X .p -16 X -Uname Undefine the name as if X X #undef name X X were given. On non-Unix systems, "name" will be forced to X upper-case. X .p -16 X -Xnumber Enable debugging code. If no value is X given, a value of 1 will be used. (For maintenence of X CPP only.) X .s.lm -16 X XPre-Defined Variables X X When CPP begins processing, the following variables will X have been defined (unless the -N option is specified): X .s X Target computer (as appropriate): X .s X pdp11, vax, M68000 m68000 m68k X .s X Target operating system (as appropriate): X .s X rsx, rt11, vms, unix X .s X Target compiler (as appropriate): X .s X decus, vax11c X .s X The implementor may add definitions to this list. X The default definitions match the definition of the X host computer, operating system, and C compiler. X .s X The following are always available unless undefined (or X -N was specified twice): X .lm +16 X .p -12 X __FILE__ The input (or #include) file being compiled X (as a quoted string). X .p -12 X __LINE__ The line number being compiled. X .p -12 X __DATE__ The date and time of compilation as X a Unix ctime quoted string (the trailing newline is removed). X Thus, X .s X printf("Bug at line %s,", __LINE__); X printf(" source file %s", __FILE__); X printf(" compiled on %s", __DATE__); X .s.lm -16 X XDraft Proposed Ansi Standard Considerations X X The current version of the Draft Proposed Standard X explicitly states that "readers are requested not to specify X or claim conformance to this draft." Readers and users X of Decus CPP should not assume that Decus CPP conforms X to the standard, or that it will conform to the actual X C Language Standard. X X When CPP is itself compiled, many features of the Draft X Proposed Standard that are incompatible with existing X preprocessors may be disabled. See the comments in CPP's X source for details. X X The latest version of the Draft Proposed Standard (as reflected X in Decus CPP) is dated November 12, 1984. X X Comments are removed from the input text. The comment X is replaced by a single space character. The -C option X preserves comments, writing them to the output file. X X The '$' character is considered to be a letter. This is X a permitted extension. X X The following new features of C are processed by CPP: X .s.comment Note: significant spaces, not tabs, .br quotes #if, #elif X .br;####_#elif expression (_#else _#if) X .br;####'_\xNNN' (Hexadecimal constant) X .br;####'_\a' (Ascii BELL) X .br;####'_\v' (Ascii Vertical Tab) X .br;####_#if defined NAME 1 if defined, 0 if not X .br;####_#if defined (NAME) 1 if defined, 0 if not X .br;####_#if sizeof (basic type) X .br;####unary + X .br;####123U, 123LU Unsigned ints and longs. X .br;####12.3L Long double numbers X .br;####token_#token Token concatenation X .br;####_#include token Expands to filename X X The Draft Proposed Standard has extended C, adding a constant X string concatenation operator, where X X "foo" "bar" X X is regarded as the single string "foobar". (This does not X affect CPP's processing but does permit a limited form of X macro argument substitution into strings as will be discussed.) X X The Standard Committee plans to add token concatenation X to #define command lines. One suggested implementation X is as follows: the sequence "Token1#Token2" is treated X as if the programmer wrote "Token1Token2". This could X be used as follows: X X #line 123 X #define ATLINE foo#__LINE__ X X ATLINE would be defined as foo123. X X Note that "Token2" must either have the format of an X identifier or be a string of digits. Thus, the string X X #define ATLINE foo#1x3 X X generates two tokens: "foo1" and "x3". X X If the tokens T1 and T2 are concatenated into T3, X this implementation operates as follows: X X 1. Expand T1 if it is a macro. X 2. Expand T2 if it is a macro. X 3. Join the tokens, forming T3. X 4. Expand T3 if it is a macro. X X A macro formal parameter will be substituted into a string X or character constant if it is the only component of that X constant: X X #define VECSIZE 123 X #define vprint(name, size) \ X printf("name" "[" "size" "] = {\n") X ... vprint(vector, VECSIZE); X X expands (effectively) to X X vprint("vector[123] = {\n"); X X Note that this will be useful if your C compiler supports X the new string concatenation operation noted above. X As implemented here, if you write X X #define string(arg) "arg" X ... string("foo") ... X X This implementation generates "foo", rather than the strictly X correct ""foo"" (which will probably generate an error message). X This is, strictly speaking, an error in CPP and may be removed X from future releases. X Xerror messages X X Many. CPP prints warning or error messages if you try to X use multiple-byte character constants (non-transportable) X if you #undef a symbol that was not defined, or if your X program has potentially nested comments. X Xauthor X X Martin Minow X Xbugs X X The #if expression processor uses signed integers only. X I.e, #if 0xFFFFu < 0 may be TRUE. X X#endif X X#include X#include X#include "cppdef.h" X#include "cpp.h" X X/* X * Commonly used global variables: X * line is the current input line number. X * wrongline is set in many places when the actual output X * line is out of sync with the numbering, e.g, X * when expanding a macro with an embedded newline. X * X * token holds the last identifier scanned (which might X * be a candidate for macro expansion). X * errors is the running cpp error counter. X * infile is the head of a linked list of input files (extended by X * #include and macros being expanded). infile always points X * to the current file/macro. infile->parent to the includer, X * etc. infile->fd is NULL if this input stream is a macro. X */ Xint line; /* Current line number */ Xint wrongline; /* Force #line to compiler */ Xchar token[IDMAX + 1]; /* Current input token */ Xint errors; /* cpp error counter */ XFILEINFO *infile = NULL; /* Current input file */ X#if DEBUG Xint debug; /* TRUE if debugging now */ X#endif X/* X * This counter is incremented when a macro expansion is initiated. X * If it exceeds a built-in value, the expansion stops -- this tests X * for a runaway condition: X * #define X Y X * #define Y X X * X X * This can be disabled by falsifying rec_recover. (Nothing does this X * currently: it is a hook for an eventual invocation flag.) X */ Xint recursion; /* Infinite recursion counter */ Xint rec_recover = TRUE; /* Unwind recursive macros */ X X/* X * instring is set TRUE when a string is scanned. It modifies the X * behavior of the "get next character" routine, causing all characters X * to be passed to the caller (except ). Note especially that X * comments and \ are not removed from the source. (This X * prevents cpp output lines from being arbitrarily long). X * X * inmacro is set by #define -- it absorbs comments and converts X * form-feed and vertical-tab to space, but returns \ X * to the caller. Strictly speaking, this is a bug as \ X * shouldn't delimit tokens, but we'll worry about that some other X * time -- it is more important to prevent infinitly long output lines. X * X * instring and inmarcor are parameters to the get() routine which X * were made global for speed. X */ Xint instring = FALSE; /* TRUE if scanning string */ Xint inmacro = FALSE; /* TRUE if #defining a macro */ X X/* X * work[] and workp are used to store one piece of text in a temporay X * buffer. To initialize storage, set workp = work. To store one X * character, call save(c); (This will fatally exit if there isn't X * room.) To terminate the string, call save(EOS). Note that X * the work buffer is used by several subroutines -- be sure your X * data won't be overwritten. The extra byte in the allocation is X * needed for string formal replacement. X */ Xchar work[NWORK + 1]; /* Work buffer */ Xchar *workp; /* Work buffer pointer */ X X/* X * keepcomments is set TRUE by the -C option. If TRUE, comments X * are written directly to the output stream. This is needed if X * the output from cpp is to be passed to lint (which uses commands X * embedded in comments). cflag contains the permanent state of the X * -C flag. keepcomments is always falsified when processing #control X * commands and when compilation is supressed by a false #if X * X * If eflag is set, CPP returns "success" even if non-fatal errors X * were detected. X * X * If nflag is non-zero, no symbols are predefined except __LINE__. X * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols X * are predefined. X */ Xint keepcomments = FALSE; /* Write out comments flag */ Xint cflag = FALSE; /* -C option (keep comments) */ Xint eflag = FALSE; /* -E option (never fail) */ Xint nflag = 0; /* -N option (no predefines) */ X X/* X * ifstack[] holds information about nested #if's. It is always X * accessed via *ifptr. The information is as follows: X * WAS_COMPILING state of compiling flag at outer level. X * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else. X * TRUE_SEEN set TRUE when #if or #elif succeeds X * ifstack[0] holds the compiling flag. It is TRUE if compilation X * is currently enabled. Note that this must be initialized TRUE. X */ Xchar ifstack[BLK_NEST] = { TRUE }; /* #if information */ Xchar *ifptr = ifstack; /* -> current ifstack[] */ X X/* X * incdir[] stores the -i directories (and the system-specific X * #include <...> directories. X */ Xchar *incdir[NINCLUDE]; /* -i directories */ Xchar **incend = incdir; /* -> free space in incdir[] */ X X/* X * This is the table used to predefine target machine and operating X * system designators. It may need hacking for specific circumstances. X * Note: it is not clear that this is part of the Ansi Standard. X * The -N option supresses preset definitions. X */ Xchar *preset[] = { /* names defined at cpp start */ X#ifdef MACHINE X MACHINE, X#endif X#ifdef SYSTEM X SYSTEM, X#endif X#ifdef COMPILER X COMPILER, X#endif X#if DEBUG X "decus_cpp", /* Ourselves! */ X#endif X NULL /* Must be last */ X}; X X/* X * The value of these predefined symbols must be recomputed whenever X * they are evaluated. The order must not be changed. X */ Xchar *magic[] = { /* Note: order is important */ X "__LINE__", X "__FILE__", X NULL /* Must be last */ X}; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X register int i; X X#if HOST == SYS_VMS X argc = getredirection(argc, argv); /* vms >file and stdin */ X /* X * Open input file, "-" means use stdin. X */ X if (!streq(argv[1], "-")) { X if (freopen(argv[1], "r", stdin) == NULL) { X perror(argv[1]); X cerror("Can't open input file \"%s\"", argv[1]); X exit(IO_ERROR); X } X strcpy(work, argv[1]); /* Remember input filename */ X break; X } /* Else, just get stdin */ X case 0: /* No args? */ X case 1: /* No files, stdin -> stdout */ X#if HOST == SYS_UNIX X work[0] = EOS; /* Unix can't find stdin name */ X#else X fgetname(stdin, work); /* Vax-11C, Decus C know name */ X#endif X break; X X default: X exit(IO_ERROR); /* Can't happen */ X } X setincdirs(); /* Setup -I include directories */ X addfile(stdin, work); /* "open" main input file */ X#if DEBUG X if (debug > 0) X dumpdef("preset #define symbols"); X#endif X cppmain(); /* Process main file */ X if ((i = (ifptr - &ifstack[0])) != 0) { X#if OLD_PREPROCESSOR X ciwarn("Inside #ifdef block at end of input, depth = %d", i); X#else X cierror("Inside #ifdef block at end of input, depth = %d", i); X#endif X } X fclose(stdout); X if (errors > 0) { X fprintf(stderr, (errors == 1) X ? "%d error in preprocessor\n" X : "%d errors in preprocessor\n", errors); X if (!eflag) X exit(IO_ERROR); X } X exit(IO_NORMAL); /* No errors or -E option set */ X} X XFILE_LOCAL Xcppmain() X/* X * Main process for cpp -- copies tokens from the current input X * stream (main file, include file, or a macro) to the output X * file. X */ X{ X register int c; /* Current character */ X register int counter; /* newlines and spaces */ X extern int output(); /* Output one character */ X X /* X * Explicitly output a #line at the start of cpp output so X * that lint (etc.) knows the name of the original source X * file. If we don't do this explicitly, we may get X * the name of the first #include file instead. X */ X sharp(); X /* X * This loop is started "from the top" at the beginning of each line X * wrongline is set TRUE in many places if it is necessary to write X * a #line record. (But we don't write them when expanding macros.) X * X * The counter variable has two different uses: at X * the start of a line, it counts the number of blank lines that X * have been skipped over. These are then either output via X * #line records or by outputting explicit blank lines. X * When expanding tokens within a line, the counter remembers X * whether a blank/tab has been output. These are dropped X * at the end of the line, and replaced by a single blank X * within lines. X */ X for (;;) { X counter = 0; /* Count empty lines */ X for (;;) { /* For each line, ... */ X while (type[(c = get())] == SPA) /* Skip leading blanks */ X ; /* in this line. */ X if (c == '\n') /* If line's all blank, */ X ++counter; /* Do nothing now */ X else if (c == '#') { /* Is 1st non-space '#' */ X keepcomments = FALSE; /* Don't pass comments */ X counter = control(counter); /* Yes, do a #command */ X keepcomments = (cflag && compiling); X } X else if (c == EOF_CHAR) /* At end of file? */ X break; X else if (!compiling) { /* #ifdef false? */ X skipnl(); /* Skip to newline */ X counter++; /* Count it, too. */ X } X else { X break; /* Actual token */ X } X } X if (c == EOF_CHAR) /* Exit process at */ X break; /* End of file */ X /* X * If the loop didn't terminate because of end of file, we X * know there is a token to compile. First, clean up after X * absorbing newlines. counter has the number we skipped. X */ X if ((wrongline && infile->fp != NULL) || counter > 4) X sharp(); /* Output # line number */ X else { /* If just a few, stuff */ X while (--counter >= 0) /* them out ourselves */ X putchar('\n'); X } X /* X * Process each token on this line. X */ X unget(); /* Reread the char. */ X for (;;) { /* For the whole line, */ X do { /* Token concat. loop */ X for (counter = 0; (type[(c = get())] == SPA);) { X#if COMMENT_INVISIBLE X if (c != COM_SEP) X counter++; X#else X counter++; /* Skip over blanks */ X#endif X } X if (c == EOF_CHAR || c == '\n') X goto end_line; /* Exit line loop */ X else if (counter > 0) /* If we got any spaces */ X putchar(' '); /* Output one space */ X c = macroid(c); /* Grab the token */ X } while (type[c] == LET && catenate()); X if (c == EOF_CHAR || c == '\n') /* From macro exp error */ X goto end_line; /* Exit line loop */ X switch (type[c]) { X case LET: X fputs(token, stdout); /* Quite ordinary token */ X break; X X X case DIG: /* Output a number */ X case DOT: /* Dot may begin floats */ X scannumber(c, output); X break; X X case QUO: /* char or string const */ X scanstring(c, output); /* Copy it to output */ X break; X X default: /* Some other character */ X cput(c); /* Just output it */ X break; X } /* Switch ends */ X } /* Line for loop */ Xend_line: if (c == '\n') { /* Compiling at EOL? */ X putchar('\n'); /* Output newline, if */ X if (infile->fp == NULL) /* Expanding a macro, */ X wrongline = TRUE; /* Output # line later */ X } X } /* Continue until EOF */ X} X Xoutput(c) Xint c; X/* X * Output one character to stdout -- output() is passed as an X * argument to scanstring() X */ X{ X#if COMMENT_INVISIBLE X if (c != TOK_SEP && c != COM_SEP) X#else X if (c != TOK_SEP) X#endif X putchar(c); X} X Xstatic char *sharpfilename = NULL; X XFILE_LOCAL Xsharp() X/* X * Output a line number line. X */ X{ X register char *name; X X if (keepcomments) /* Make sure # comes on */ X putchar('\n'); /* a fresh, new line. */ X printf("#%s %d", LINE_PREFIX, line); X if (infile->fp != NULL) { X name = (infile->progname != NULL) X ? infile->progname : infile->filename; X if (sharpfilename == NULL X || sharpfilename != NULL && !streq(name, sharpfilename)) { X if (sharpfilename != NULL) X free(sharpfilename); X sharpfilename = savestring(name); X printf(" \"%s\"", name); X } X } X putchar('\n'); X wrongline = FALSE; X} END-of-cpp1.c echo x - cpp3.c sed 's/^X//' >cpp3.c << 'END-of-cpp3.c' X/* X * C P P 3 . C X * X * File open and command line options X * X * Edit history X * 13-Nov-84 MM Split from cpp1.c X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX) X#include Xextern int abort(); /* For debugging */ X#endif X Xint Xopenfile(filename) Xchar *filename; X/* X * Open a file, add it to the linked list of open files. X * This is called only from openfile() above. X */ X{ X register FILE *fp; X X if ((fp = fopen(filename, "r")) == NULL) { X#if DEBUG X perror(filename); X#endif X return (FALSE); X } X#if DEBUG X if (debug) X fprintf(stderr, "Reading from \"%s\"\n", filename); X#endif X addfile(fp, filename); X return (TRUE); X} X Xaddfile(fp, filename) XFILE *fp; /* Open file pointer */ Xchar *filename; /* Name of the file */ X/* X * Initialize tables for this open file. This is called from openfile() X * above (for #include files), and from the entry to cpp to open the main X * input file. It calls a common routine, getfile() to build the FILEINFO X * structure which is used to read characters. (getfile() is also called X * to setup a macro replacement.) X */ X{ X register FILEINFO *file; X extern FILEINFO *getfile(); X X file = getfile(NBUFF, filename); X file->fp = fp; /* Better remember FILE * */ X file->buffer[0] = EOS; /* Initialize for first read */ X line = 1; /* Working on line 1 now */ X wrongline = TRUE; /* Force out initial #line */ X} X Xsetincdirs() X/* X * Append system-specific directories to the include directory list. X * Called only when cpp is started. X */ X{ X X#ifdef CPP_INCLUDE X *incend++ = CPP_INCLUDE; X#define IS_INCLUDE 1 X#else X#define IS_INCLUDE 0 X#endif X X#if HOST == SYS_UNIX X *incend++ = "/usr/include"; X#define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE) X#endif X X#if HOST == SYS_VMS X extern char *getenv(); X X if (getenv("C$LIBRARY") != NULL) X *incend++ = "C$LIBRARY:"; X *incend++ = "SYS$LIBRARY:"; X#define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) X#endif X X#if HOST == SYS_RSX X extern int $$rsts; /* TRUE on RSTS/E */ X extern int $$pos; /* TRUE on PRO-350 P/OS */ X extern int $$vms; /* TRUE on VMS compat. */ X X if ($$pos) { /* P/OS? */ X *incend++ = "SY:[ZZDECUSC]"; /* C #includes */ X *incend++ = "LB:[1,5]"; /* RSX library */ X } X else if ($$rsts) { /* RSTS/E? */ X *incend++ = "SY:@"; /* User-defined account */ X *incend++ = "C:"; /* Decus-C library */ X *incend++ = "LB:[1,1]"; /* RSX library */ X } X else if ($$vms) { /* VMS compatibility? */ X *incend++ = "C:"; X } X else { /* Plain old RSX/IAS */ X *incend++ = "LB:[1,1]"; X } X#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) X#endif X X#if HOST == SYS_RT11 X extern int $$rsts; /* RSTS/E emulation? */ X X if ($$rsts) X *incend++ = "SY:@"; /* User-defined account */ X *incend++ = "C:"; /* Decus-C library disk */ X *incend++ = "SY:"; /* System (boot) disk */ X#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) X#endif X} X Xint Xdooptions(argc, argv) Xint argc; Xchar *argv[]; X/* X * dooptions is called to process command line arguments (-Detc). X * It is called only at cpp startup. X */ X{ X register char *ap; X register DEFBUF *dp; X register int c; X int i, j; X char *arg; X SIZES *sizp; /* For -S */ X int size; /* For -S */ X int isdatum; /* FALSE for -S* */ X int endtest; /* For -S */ X X for (i = j = 1; i < argc; i++) { X arg = ap = argv[i]; X if (*ap++ != '-' || *ap == EOS) X argv[j++] = argv[i]; X else { X c = *ap++; /* Option byte */ X if (islower(c)) /* Normalize case */ X c = toupper(c); X switch (c) { /* Command character */ X case 'C': /* Keep comments */ X cflag = TRUE; X keepcomments = TRUE; X break; X X case 'D': /* Define symbol */ X#if HOST != SYS_UNIX X zap_uc(ap); /* Force define to U.C. */ X#endif X /* X * If the option is just "-Dfoo", make it -Dfoo=1 X */ X while (*ap != EOS && *ap != '=') X ap++; X if (*ap == EOS) X ap = "1"; X else X *ap++ = EOS; X /* X * Now, save the word and its definition. X */ X dp = defendel(argv[i] + 2, FALSE); X dp->repl = savestring(ap); X dp->nargs = DEF_NOARGS; X break; X X case 'E': /* Ignore non-fatal */ X eflag = TRUE; /* errors. */ X break; X X case 'I': /* Include directory */ X if (incend >= &incdir[MAXINCLUDE]) X cfatal("Too many include directories", NULLST); X *incend++ = ap; X break; X X case 'N': /* No predefineds */ X nflag++; /* Repeat to undefine */ X break; /* __LINE__, etc. */ X X case 'S': X sizp = size_table; X if (isdatum = (*ap != '*')) /* If it's just -S, */ X endtest = T_FPTR; /* Stop here */ X else { /* But if it's -S* */ X ap++; /* Step over '*' */ X endtest = 0; /* Stop at end marker */ X } X while (sizp->bits != endtest && *ap != EOS) { X if (!isdigit(*ap)) { /* Skip to next digit */ X ap++; X continue; X } X size = 0; /* Compile the value */ X while (isdigit(*ap)) { X size *= 10; X size += (*ap++ - '0'); X } X if (isdatum) X sizp->size = size; /* Datum size */ X else X sizp->psize = size; /* Pointer size */ X sizp++; X } X if (sizp->bits != endtest) X cwarn("-S, too few values specified in %s", argv[i]); X else if (*ap != EOS) X cwarn("-S, too many values, \"%s\" unused", ap); X break; X X case 'U': /* Undefine symbol */ X#if HOST != SYS_UNIX X zap_uc(ap); X#endif X if (defendel(ap, TRUE) == NULL) X cwarn("\"%s\" wasn't defined", ap); X break; X X#if DEBUG X case 'X': /* Debug */ X debug = (isdigit(*ap)) ? atoi(ap) : 1; X#if (HOST == SYS_VMS || HOST == SYS_UNIX) X signal(SIGINT, abort); /* Trap "interrupt" */ X#endif X fprintf(stderr, "Debug set to %d\n", debug); X break; X#endif X X default: /* What is this one? */ X cwarn("Unknown option \"%s\"", arg); X fprintf(stderr, "The following options are valid:\n\ X -C\t\t\tWrite source file comments to output\n\ X -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ X -Idirectory\t\tAdd a directory to the #include search list\n\ X -N\t\t\tDon't predefine target-specific names\n\ X -Stext\t\tSpecify sizes for #if sizeof\n\ X -Usymbol\t\tUndefine symbol\n"); X#if DEBUG X fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); X#endif X break; X } /* Switch on all options */ X } /* If it's a -option */ X } /* For all arguments */ X if (j > 3) { X cerror( X "Too many file arguments. Usage: cpp [input [output]]", X NULLST); X } X return (j); /* Return new argc */ X} X X#if HOST != SYS_UNIX XFILE_LOCAL Xzap_uc(ap) Xregister char *ap; X/* X * Dec operating systems mangle upper-lower case in command lines. X * This routine forces the -D and -U arguments to uppercase. X * It is called only on cpp startup by dooptions(). X */ X{ X while (*ap != EOS) { X /* X * Don't use islower() here so it works with Multinational X */ X if (*ap >= 'a' && *ap <= 'z') X *ap = toupper(*ap); X ap++; X } X} X#endif X Xinitdefines() X/* X * Initialize the built-in #define's. There are two flavors: X * #define decus 1 (static definitions) X * #define __FILE__ ?? (dynamic, evaluated by magic) X * Called only on cpp startup. X * X * Note: the built-in static definitions are supressed by the -N option. X * __LINE__, __FILE__, and __DATE__ are always present. X */ X{ X register char **pp; X register char *tp; X register DEFBUF *dp; X int i; X long tvec; X extern char *ctime(); X X /* X * Predefine the built-in symbols. Allow the X * implementor to pre-define a symbol as "" to X * eliminate it. X */ X if (nflag == 0) { X for (pp = preset; *pp != NULL; pp++) { X if (*pp[0] != EOS) { X dp = defendel(*pp, FALSE); X dp->repl = savestring("1"); X dp->nargs = DEF_NOARGS; X } X } X } X /* X * The magic pre-defines (__FILE__ and __LINE__ are X * initialized with negative argument counts. expand() X * notices this and calls the appropriate routine. X * DEF_NOARGS is one greater than the first "magic" definition. X */ X if (nflag < 2) { X for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) { X dp = defendel(*pp, FALSE); X dp->nargs = --i; X } X#if OK_DATE X /* X * Define __DATE__ as today's date. X */ X dp = defendel("__DATE__", FALSE); X dp->repl = tp = getmem(27); X dp->nargs = DEF_NOARGS; X time(&tvec); X *tp++ = '"'; X strcpy(tp, ctime(&tvec)); X tp[24] = '"'; /* Overwrite newline */ X#endif X } X} X X#if HOST == SYS_VMS X/* X * getredirection() is intended to aid in porting C programs X * to VMS (Vax-11 C) which does not support '>' and '<' X * I/O redirection. With suitable modification, it may X * useful for other portability problems as well. X */ X Xint Xgetredirection(argc, argv) Xint argc; Xchar **argv; X/* X * Process vms redirection arg's. Exit if any error is seen. X * If getredirection() processes an argument, it is erased X * from the vector. getredirection() returns a new argc value. X * X * Warning: do not try to simplify the code for vms. The code X * presupposes that getredirection() is called before any data is X * read from stdin or written to stdout. X * X * Normal usage is as follows: X * X * main(argc, argv) X * int argc; X * char *argv[]; X * { X * argc = getredirection(argc, argv); X * } X */ X{ X register char *ap; /* Argument pointer */ X int i; /* argv[] index */ X int j; /* Output index */ X int file; /* File_descriptor */ X extern int errno; /* Last vms i/o error */ X X for (j = i = 1; i < argc; i++) { /* Do all arguments */ X switch (*(ap = argv[i])) { X case '<': /* ': /* >file or >>file */ X if (*++ap == '>') { /* >>file */ X /* X * If the file exists, and is writable by us, X * call freopen to append to the file (using the X * file's current attributes). Otherwise, create X * a new file with "vanilla" attributes as if the X * argument was given as ">filename". X * access(name, 2) returns zero if we can write on X * the specified file. X */ X if (access(++ap, 2) == 0) { X if (freopen(ap, "a", stdout) != NULL) X break; /* Exit case statement */ X perror(ap); /* Error, can't append */ X exit(errno); /* After access test */ X } /* If file accessable */ X } X /* X * On vms, we want to create the file using "standard" X * record attributes. creat(...) creates the file X * using the caller's default protection mask and X * "variable length, implied carriage return" X * attributes. dup2() associates the file with stdout. X */ X if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1 X || dup2(file, fileno(stdout)) == -1) { X perror(ap); /* Can't create file */ X exit(errno); /* is a fatal error */ X } /* If '>' creation */ X break; /* Exit case test */ X X default: X argv[j++] = ap; /* Not a redirector */ X break; /* Exit case test */ X } X } /* For all arguments */ X argv[j] = NULL; /* Terminate argv[] */ X return (j); /* Return new argc */ X} X#endif X X X END-of-cpp3.c echo x - cpp4.c sed 's/^X//' >cpp4.c << 'END-of-cpp4.c' X/* X * C P P 4 . C X * M a c r o D e f i n i t i o n s X * X * Edit History X * 31-Aug-84 MM USENET net.sources release X * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() X * so they work correctly with token concatenation. X * Added string formal recognition. X * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we X * don't print unnecessary error messages for X * #if !defined(FOO) && FOO != 0 && 10 / FOO ... X * 31-Oct-84 ado/MM Added token concatenation X * 6-Nov-84 MM Split off eval stuff X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X/* X * parm[], parmp, and parlist[] are used to store #define() argument X * lists. nargs contains the actual number of parameters stored. X */ Xstatic char parm[NPARMWORK + 1]; /* define param work buffer */ Xstatic char *parmp; /* Free space in parm */ Xstatic char *parlist[LASTPARM]; /* -> start of each parameter */ Xstatic int nargs; /* Parameters for this macro */ X Xdodefine() X/* X * Called from control when a #define is scanned. This module X * parses formal parameters and the replacement string. When X * the formal parameter name is encountered in the replacement X * string, it is replaced by a character in the range 128 to X * 128+NPARAM (this allows up to 32 parameters within the X * Dec Multinational range). If cpp is ported to an EBCDIC X * machine, you will have to make other arrangements. X * X * There is some special case code to distinguish X * #define foo bar X * from #define foo() bar X * X * Also, we make sure that X * #define foo foo X * expands to "foo" but doesn't put cpp into an infinite loop. X * X * A warning message is printed if you redefine a symbol to a X * different text. I.e, X * #define foo 123 X * #define foo 123 X * is ok, but X * #define foo 123 X * #define foo +123 X * is not. X * X * The following subroutines are called from define(): X * checkparm called when a token is scanned. It checks through the X * array of formal parameters. If a match is found, the X * token is replaced by a control byte which will be used X * to locate the parameter when the macro is expanded. X * textput puts a string in the macro work area (parm[]), updating X * parmp to point to the first free byte in parm[]. X * textput() tests for work buffer overflow. X * charput puts a single character in the macro work area (parm[]) X * in a manner analogous to textput(). X */ X{ X register int c; X register DEFBUF *dp; /* -> new definition */ X int isredefine; /* TRUE if redefined */ X char *old; /* Remember redefined */ X extern int save(); /* Save char in work[] */ X X if (type[(c = skipws())] != LET) X goto bad_define; X isredefine = FALSE; /* Set if redefining */ X if ((dp = lookid(c)) == NULL) /* If not known now */ X dp = defendel(token, FALSE); /* Save the name */ X else { /* It's known: */ X isredefine = TRUE; /* Remember this fact */ X old = dp->repl; /* Remember replacement */ X dp->repl = NULL; /* No replacement now */ X } X parlist[0] = parmp = parm; /* Setup parm buffer */ X if ((c = get()) == '(') { /* With arguments? */ X nargs = 0; /* Init formals counter */ X do { /* Collect formal parms */ X if (nargs >= LASTPARM) X cfatal("Too many arguments for macro", NULLST); X else if ((c = skipws()) == ')') X break; /* Got them all */ X else if (type[c] != LET) /* Bad formal syntax */ X goto bad_define; X scanid(c); /* Get the formal param */ X parlist[nargs++] = parmp; /* Save its start */ X textput(token); /* Save text in parm[] */ X } while ((c = skipws()) == ','); /* Get another argument */ X if (c != ')') /* Must end at ) */ X goto bad_define; X c = ' '; /* Will skip to body */ X } X else { X /* X * DEF_NOARGS is needed to distinguish between X * "#define foo" and "#define foo()". X */ X nargs = DEF_NOARGS; /* No () parameters */ X } X if (type[c] == SPA) /* At whitespace? */ X c = skipws(); /* Not any more. */ X workp = work; /* Replacement put here */ X inmacro = TRUE; /* Keep \ now */ X while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ X#if OK_CONCAT X if (c == '#') { /* Token concatenation? */ X while (workp > work && type[workp[-1]] == SPA) X --workp; /* Erase leading spaces */ X save(TOK_SEP); /* Stuff a delimiter */ X c = skipws(); /* Eat whitespace */ X if (type[c] == LET) /* Another token here? */ X ; /* Stuff it normally */ X else if (type[c] == DIG) { /* Digit string after? */ X while (type[c] == DIG) { /* Stuff the digits */ X save(c); X c = get(); X } X save(TOK_SEP); /* Delimit 2nd token */ X } X else { X ciwarn("Strange character after # (%d.)", c); X } X continue; X } X#endif X switch (type[c]) { X case LET: X checkparm(c, dp); /* Might be a formal */ X break; X X case DIG: /* Number in mac. body */ X case DOT: /* Maybe a float number */ X scannumber(c, save); /* Scan it off */ X break; X X case QUO: /* String in mac. body */ X#if STRING_FORMAL X stparmscan(c, dp); /* Do string magic */ X#else X stparmscan(c); X#endif X break; X X case BSH: /* Backslash */ X save('\\'); X if ((c = get()) == '\n') X wrongline = TRUE; X save(c); X break; X X case SPA: /* Absorb whitespace */ X /* X * Note: the "end of comment" marker is passed on X * to allow comments to separate tokens. X */ X if (workp[-1] == ' ') /* Absorb multiple */ X break; /* spaces */ X else if (c == '\t') X c = ' '; /* Normalize tabs */ X /* Fall through to store character */ X default: /* Other character */ X save(c); X break; X } X c = get(); X } X inmacro = FALSE; /* Stop newline hack */ X unget(); /* For control check */ X if (workp > work && workp[-1] == ' ') /* Drop trailing blank */ X workp--; X *workp = EOS; /* Terminate work */ X dp->repl = savestring(work); /* Save the string */ X dp->nargs = nargs; /* Save arg count */ X#if DEBUG X if (debug) X dumpadef("macro definition", dp); X#endif X if (isredefine) { /* Error if redefined */ X if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) X || (old == NULL && dp->repl != NULL) X || (old != NULL && dp->repl == NULL)) { X cerror("Redefining defined variable \"%s\"", dp->name); X } X if (old != NULL) /* We don't need the */ X free(old); /* old definition now. */ X } X return; X Xbad_define: X cerror("#define syntax error", NULLST); X inmacro = FALSE; /* Stop hack */ X} X Xcheckparm(c, dp) Xregister int c; XDEFBUF *dp; X/* X * Replace this param if it's defined. Note that the macro name is a X * possible replacement token. We stuff DEF_MAGIC in front of the token X * which is treated as a LETTER by the token scanner and eaten by X * the output routine. This prevents the macro expander from X * looping if someone writes "#define foo foo". X */ X{ X register int i; X register char *cp; X X scanid(c); /* Get parm to token[] */ X for (i = 0; i < nargs; i++) { /* For each argument */ X if (streq(parlist[i], token)) { /* If it's known */ X save(i + MAC_PARM); /* Save a magic cookie */ X return; /* And exit the search */ X } X } X if (streq(dp->name, token)) /* Macro name in body? */ X save(DEF_MAGIC); /* Save magic marker */ X for (cp = token; *cp != EOS;) /* And save */ X save(*cp++); /* The token itself */ X} X X#if STRING_FORMAL Xstparmscan(delim, dp) Xint delim; Xregister DEFBUF *dp; X/* X * Scan the string (starting with the given delimiter). X * The token is replaced if it is the only text in this string or X * character constant. The algorithm follows checkparm() above. X * Note that scanstring() has approved of the string. X */ X{ X register int c; X X /* X * Warning -- this code hasn't been tested for a while. X * It exists only to preserve compatibility with earlier X * implementations of cpp. It is not part of the Draft X * ANSI Standard C language. X */ X save(delim); X instring = TRUE; X while ((c = get()) != delim X && c != '\n' X && c != EOF_CHAR) { X if (type[c] == LET) /* Maybe formal parm */ X checkparm(c, dp); X else { X save(c); X if (c == '\\') X save(get()); X } X } X instring = FALSE; X if (c != delim) X cerror("Unterminated string in macro body", NULLST); X save(c); X} X#else Xstparmscan(delim) Xint delim; X/* X * Normal string parameter scan. X */ X{ X register char *wp; X register int i; X extern int save(); X X wp = workp; /* Here's where it starts */ X if (!scanstring(delim, save)) X return; /* Exit on scanstring error */ X workp[-1] = EOS; /* Erase trailing quote */ X wp++; /* -> first string content byte */ X for (i = 0; i < nargs; i++) { X if (streq(parlist[i], wp)) { X *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ X *wp++ = (i + MAC_PARM); /* Make a formal marker */ X *wp = wp[-3]; /* Add on closing quote */ X workp = wp + 1; /* Reset string end */ X return; X } X } X workp[-1] = wp[-1]; /* Nope, reset end quote. */ X} X#endif X Xdoundef() X/* X * Remove the symbol from the defined list. X * Called from the #control processor. X */ X{ X register int c; X X if (type[(c = skipws())] != LET) X cerror("Illegal #undef argument", NULLST); X else { X scanid(c); /* Get name to token[] */ X if (defendel(token, TRUE) == NULL) { X cwarn("Symbol \"%s\" not defined in #undef", token); X } X } X} X Xtextput(text) Xchar *text; X/* X * Put the string in the parm[] buffer. X */ X{ X register int size; X X size = strlen(text) + 1; X if ((parmp + size) >= &parm[NPARMWORK]) X cfatal("Macro work area overflow", NULLST); X else { X strcpy(parmp, text); X parmp += size; X } X} X Xcharput(c) Xregister int c; X/* X * Put the byte in the parm[] buffer. X */ X{ X if (parmp >= &parm[NPARMWORK]) X cfatal("Macro work area overflow", NULLST); X else { X *parmp++ = c; X } X} X X/* X * M a c r o E x p a n s i o n X */ X Xstatic DEFBUF *macro; /* Catches start of infinite macro */ X Xexpand(tokenp) Xregister DEFBUF *tokenp; X/* X * Expand a macro. Called from the cpp mainline routine (via subroutine X * macroid()) when a token is found in the symbol table. It calls X * expcollect() to parse actual parameters, checking for the correct number. X * It then creates a "file" containing a single line containing the X * macro with actual parameters inserted appropriately. This is X * "pushed back" onto the input stream. (When the get() routine runs X * off the end of the macro line, it will dismiss the macro itself.) X */ X{ X register int c; X register FILEINFO *file; X extern FILEINFO *getfile(); X X#if DEBUG X if (debug) X dumpadef("expand entry", tokenp); X#endif X /* X * If no macro is pending, save the name of this macro X * for an eventual error message. X */ X if (recursion++ == 0) X macro = tokenp; X else if (recursion == RECURSION_LIMIT) { X cerror("Recursive macro definition of \"%s\"", tokenp->name); X fprintf(stderr, "(Defined by \"%s\")\n", macro->name); X if (rec_recover) { X do { X c = get(); X } while (infile != NULL && infile->fp == NULL); X unget(); X recursion = 0; X return; X } X } X /* X * Here's a macro to expand. X */ X nargs = 0; /* Formals counter */ X parmp = parm; /* Setup parm buffer */ X switch (tokenp->nargs) { X case (-2): /* __LINE__ */ X sprintf(work, "%d", line); X ungetstring(work); X break; X X case (-3): /* __FILE__ */ X for (file = infile; file != NULL; file = file->parent) { X if (file->fp != NULL) { X sprintf(work, "\"%s\"", (file->progname != NULL) X ? file->progname : file->filename); X ungetstring(work); X break; X } X } X break; X X default: X /* X * Nothing funny about this macro. X */ X if (tokenp->nargs < 0) X cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name); X while ((c = skipws()) == '\n') /* Look for (, skipping */ X wrongline = TRUE; /* spaces and newlines */ X if (c != '(') { X /* X * If the programmer writes X * #define foo() ... X * ... X * foo [no ()] X * just write foo to the output stream. X */ X unget(); X cwarn("Macro \"%s\" needs arguments", tokenp->name); X fputs(tokenp->name, stdout); X return; X } X else if (expcollect()) { /* Collect arguments */ X if (tokenp->nargs != nargs) { /* Should be an error? */ X cwarn("Wrong number of macro arguments for \"%s\"", X tokenp->name); X } X#if DEBUG X if (debug) X dumpparm("expand"); X#endif X } /* Collect arguments */ X case DEF_NOARGS: /* No parameters just stuffs */ X expstuff(tokenp); /* Do actual parameters */ X } /* nargs switch */ X} X XFILE_LOCAL int Xexpcollect() X/* X * Collect the actual parameters for this macro. TRUE if ok. X */ X{ X register int c; X register int paren; /* For embedded ()'s */ X extern int charput(); X X for (;;) { X paren = 0; /* Collect next arg. */ X while ((c = skipws()) == '\n') /* Skip over whitespace */ X wrongline = TRUE; /* and newlines. */ X if (c == ')') { /* At end of all args? */ X /* X * Note that there is a guard byte in parm[] X * so we don't have to check for overflow here. X */ X *parmp = EOS; /* Make sure terminated */ X break; /* Exit collection loop */ X } X else if (nargs >= LASTPARM) X cfatal("Too many arguments in macro expansion", NULLST); X parlist[nargs++] = parmp; /* At start of new arg */ X for (;; c = cget()) { /* Collect arg's bytes */ X if (c == EOF_CHAR) { X cerror("end of file within macro argument", NULLST); X return (FALSE); /* Sorry. */ X } X else if (c == '\\') { /* Quote next character */ X charput(c); /* Save the \ for later */ X charput(cget()); /* Save the next char. */ X continue; /* And go get another */ X } X else if (type[c] == QUO) { /* Start of string? */ X scanstring(c, charput); /* Scan it off */ X continue; /* Go get next char */ X } X else if (c == '(') /* Worry about balance */ X paren++; /* To know about commas */ X else if (c == ')') { /* Other side too */ X if (paren == 0) { /* At the end? */ X unget(); /* Look at it later */ X break; /* Exit arg getter. */ X } X paren--; /* More to come. */ X } X else if (c == ',' && paren == 0) /* Comma delimits args */ X break; X else if (c == '\n') /* Newline inside arg? */ X wrongline = TRUE; /* We'll need a #line */ X charput(c); /* Store this one */ X } /* Collect an argument */ X charput(EOS); /* Terminate argument */ X#if DEBUG X if (debug) X printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]); X#endif X } /* Collect all args. */ X return (TRUE); /* Normal return */ X} X XFILE_LOCAL Xexpstuff(tokenp) XDEFBUF *tokenp; /* Current macro being expanded */ X/* X * Stuff the macro body, replacing formal parameters by actual parameters. X */ X{ X register int c; /* Current character */ X register char *inp; /* -> repl string */ X register char *defp; /* -> macro output buff */ X int size; /* Actual parm. size */ X char *defend; /* -> output buff end */ X int string_magic; /* String formal hack */ X FILEINFO *file; /* Funny #include */ X extern FILEINFO *getfile(); X X file = getfile(NBUFF, tokenp->name); X inp = tokenp->repl; /* -> macro replacement */ X defp = file->buffer; /* -> output buffer */ X defend = defp + (NBUFF - 1); /* Note its end */ X if (inp != NULL) { X while ((c = (*inp++ & 0xFF)) != EOS) { X if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) { X string_magic = (c == (MAC_PARM + PAR_MAC)); X if (string_magic) X c = (*inp++ & 0xFF); X /* X * Replace formal parameter by actual parameter string. X */ X if ((c -= MAC_PARM) < nargs) { X size = strlen(parlist[c]); X if ((defp + size) >= defend) X goto nospace; X /* X * Erase the extra set of quotes. X */ X if (string_magic && defp[-1] == parlist[c][0]) { X strcpy(defp-1, parlist[c]); X defp += (size - 2); X } X else { X strcpy(defp, parlist[c]); X defp += size; X } X } X } X else if (defp >= defend) { Xnospace: cfatal("Out of space in macro \"%s\" arg expansion", X tokenp->name); X } X else { X *defp++ = c; X } X } X } X *defp = EOS; X#if DEBUG X if (debug > 1) X printf("macroline: \"%s\"\n", file->buffer); X#endif X} X X#if DEBUG Xdumpparm(why) Xchar *why; X/* X * Dump parameter list. X */ X{ X register int i; X X printf("dump of %d parameters (%d bytes total) %s\n", X nargs, parmp - parm, why); X for (i = 0; i < nargs; i++) { X printf("parm[%d] (%d) = \"%s\"\n", X i + 1, strlen(parlist[i]), parlist[i]); X } X} X#endif END-of-cpp4.c exit nethack-3.6.0/sys/unix/cpp3.shr0000664000076400007660000014516212467321052015334 0ustar paxedpaxed# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # cpp5.c # cpp6.c # echo x - cpp5.c sed 's/^X//' >cpp5.c << 'END-of-cpp5.c' X/* X * C P P 5 . C X * E x p r e s s i o n E v a l u a t i o n X * X * Edit History X * 31-Aug-84 MM USENET net.sources release X * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() X * so they work correctly with token concatenation. X * Added string formal recognition. X * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we X * don't print unnecessary error messages for X * #if !defined(FOO) && FOO != 0 && 10 / FOO ... X * 31-Oct-84 ado/MM Added token concatenation X * 6-Nov-84 MM Split from #define stuff, added sizeof stuff X * 19-Nov-84 ado #if error returns TRUE for (sigh) compatibility X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X X/* X * Evaluate an #if expression. X */ X Xstatic char *opname[] = { /* For debug and error messages */ X"end of expression", "val", "id", X "+", "-", "*", "/", "%", X "<<", ">>", "&", "|", "^", X "==", "!=", "<", "<=", ">=", ">", X "&&", "||", "?", ":", ",", X "unary +", "unary -", "~", "!", "(", ")", "(none)", X}; X X/* X * opdope[] has the operator precedence: X * Bits X * 7 Unused (so the value is always positive) X * 6-2 Precedence (000x .. 017x) X * 1-0 Binary op. flags: X * 01 The binop flag should be set/cleared when this op is seen. X * 10 The new value of the binop flag. X * Note: Expected, New binop X * constant 0 1 Binop, end, or ) should follow constants X * End of line 1 0 End may not be preceeded by an operator X * binary 1 0 Binary op follows a value, value follows. X * unary 0 0 Unary op doesn't follow a value, value follows X * ( 0 0 Doesn't follow value, value or unop follows X * ) 1 1 Follows value. Op follows. X */ X Xstatic char opdope[OP_MAX] = { X 0001, /* End of expression */ X 0002, /* Digit */ X 0000, /* Letter (identifier) */ X 0141, 0141, 0151, 0151, 0151, /* ADD, SUB, MUL, DIV, MOD */ X 0131, 0131, 0101, 0071, 0071, /* ASL, ASR, AND, OR, XOR */ X 0111, 0111, 0121, 0121, 0121, 0121, /* EQ, NE, LT, LE, GE, GT */ X 0061, 0051, 0041, 0041, 0031, /* ANA, ORO, QUE, COL, CMA */ X/* X * Unary op's follow X */ X 0160, 0160, 0160, 0160, /* NEG, PLU, COM, NOT */ X 0170, 0013, 0023, /* LPA, RPA, END */ X}; X/* X * OP_QUE and OP_RPA have alternate precedences: X */ X#define OP_RPA_PREC 0013 X#define OP_QUE_PREC 0034 X X/* X * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that X * #if FOO != 0 && 10 / FOO ... X * doesn't generate an error message. They are stored in optab.skip. X */ X#define S_ANDOR 2 X#define S_QUEST 1 X Xtypedef struct optab { X char op; /* Operator */ X char prec; /* Its precedence */ X char skip; /* Short-circuit: TRUE to skip */ X} OPTAB; Xstatic int evalue; /* Current value from evallex() */ X X#ifdef nomacargs XFILE_LOCAL int Xisbinary(op) Xregister int op; X{ X return (op >= FIRST_BINOP && op <= LAST_BINOP); X} X XFILE_LOCAL int Xisunary(op) Xregister int op; X{ X return (op >= FIRST_UNOP && op <= LAST_UNOP); X} X#else X#define isbinary(op) (op >= FIRST_BINOP && op <= LAST_BINOP) X#define isunary(op) (op >= FIRST_UNOP && op <= LAST_UNOP) X#endif X X/* X * The following definitions are used to specify basic variable sizes. X */ X X#ifndef S_CHAR X#define S_CHAR (sizeof (char)) X#endif X#ifndef S_SINT X#define S_SINT (sizeof (short int)) X#endif X#ifndef S_INT X#define S_INT (sizeof (int)) X#endif X#ifndef S_LINT X#define S_LINT (sizeof (long int)) X#endif X#ifndef S_FLOAT X#define S_FLOAT (sizeof (float)) X#endif X#ifndef S_DOUBLE X#define S_DOUBLE (sizeof (double)) X#endif X#ifndef S_PCHAR X#define S_PCHAR (sizeof (char *)) X#endif X#ifndef S_PSINT X#define S_PSINT (sizeof (short int *)) X#endif X#ifndef S_PINT X#define S_PINT (sizeof (int *)) X#endif X#ifndef S_PLINT X#define S_PLINT (sizeof (long int *)) X#endif X#ifndef S_PFLOAT X#define S_PFLOAT (sizeof (float *)) X#endif X#ifndef S_PDOUBLE X#define S_PDOUBLE (sizeof (double *)) X#endif X#ifndef S_PFPTR X#define S_PFPTR (sizeof (int (*)())) X#endif X Xtypedef struct types { X short type; /* This is the bit if */ X char *name; /* this is the token word */ X} TYPES; X Xstatic TYPES basic_types[] = { X { T_CHAR, "char", }, X { T_INT, "int", }, X { T_FLOAT, "float", }, X { T_DOUBLE, "double", }, X { T_SHORT, "short", }, X { T_LONG, "long", }, X { T_SIGNED, "signed", }, X { T_UNSIGNED, "unsigned", }, X { 0, NULL, }, /* Signal end */ X}; X X/* X * Test_table[] is used to test for illegal combinations. X */ Xstatic short test_table[] = { X T_FLOAT | T_DOUBLE | T_LONG | T_SHORT, X T_FLOAT | T_DOUBLE | T_CHAR | T_INT, X T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED, X T_LONG | T_SHORT | T_CHAR, X 0 /* end marker */ X}; X X/* X * The order of this table is important -- it is also referenced by X * the command line processor to allow run-time overriding of the X * built-in size values. The order must not be changed: X * char, short, int, long, float, double (func pointer) X */ XSIZES size_table[] = { X { T_CHAR, S_CHAR, S_PCHAR }, /* char */ X { T_SHORT, S_SINT, S_PSINT }, /* short int */ X { T_INT, S_INT, S_PINT }, /* int */ X { T_LONG, S_LINT, S_PLINT }, /* long */ X { T_FLOAT, S_FLOAT, S_PFLOAT }, /* float */ X { T_DOUBLE, S_DOUBLE, S_PDOUBLE }, /* double */ X { T_FPTR, 0, S_PFPTR }, /* int (*()) */ X { 0, 0, 0 }, /* End of table */ X}; X Xint Xeval() X/* X * Evaluate an expression. Straight-forward operator precedence. X * This is called from control() on encountering an #if statement. X * It calls the following routines: X * evallex Lexical analyser -- returns the type and value of X * the next input token. X * evaleval Evaluate the current operator, given the values on X * the value stack. Returns a pointer to the (new) X * value stack. X * For compatiblity with older cpp's, this return returns 1 (TRUE) X * if a syntax error is detected. X */ X{ X register int op; /* Current operator */ X register int *valp; /* -> value vector */ X register OPTAB *opp; /* Operator stack */ X int prec; /* Op precedence */ X int binop; /* Set if binary op. needed */ X int op1; /* Operand from stack */ X int skip; /* For short-circuit testing */ X int value[NEXP]; /* Value stack */ X OPTAB opstack[NEXP]; /* Operand stack */ X extern int *evaleval(); /* Does actual evaluation */ X X valp = value; X opp = opstack; X opp->op = OP_END; /* Mark bottom of stack */ X opp->prec = opdope[OP_END]; /* And its precedence */ X opp->skip = 0; /* Not skipping now */ X binop = 0; Xagain: ; X#ifdef DEBUG_EVAL X printf("In #if at again: skip = %d, binop = %d, line is: %s", X opp->skip, binop, infile->bptr); X#endif X if ((op = evallex(opp->skip)) == OP_SUB && binop == 0) X op = OP_NEG; /* Unary minus */ X else if (op == OP_ADD && binop == 0) X op = OP_PLU; /* Unary plus */ X else if (op == OP_FAIL) X return (1); /* Error in evallex */ X#ifdef DEBUG_EVAL X printf("op = %s, opdope = %03o, binop = %d, skip = %d\n", X opname[op], opdope[op], binop, opp->skip); X#endif X if (op == DIG) { /* Value? */ X if (binop != 0) { X cerror("misplaced constant in #if", NULLST); X return (1); X } X else if (valp >= &value[NEXP-1]) { X cerror("#if value stack overflow", NULLST); X return (1); X } X else { X#ifdef DEBUG_EVAL X printf("pushing %d onto value stack[%d]\n", X evalue, valp - value); X#endif X *valp++ = evalue; X binop = 1; X } X goto again; X } X else if (op > OP_END) { X cerror("Illegal #if line", NULLST); X return (1); X } X prec = opdope[op]; X if (binop != (prec & 1)) { X cerror("Operator %s in incorrect context", opname[op]); X return (1); X } X binop = (prec & 2) >> 1; X for (;;) { X#ifdef DEBUG_EVAL X printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n", X opname[op], prec, opname[opp->op], opp->prec, opp->skip); X#endif X if (prec > opp->prec) { X if (op == OP_LPA) X prec = OP_RPA_PREC; X else if (op == OP_QUE) X prec = OP_QUE_PREC; X op1 = opp->skip; /* Save skip for test */ X /* X * Push operator onto op. stack. X */ X opp++; X if (opp >= &opstack[NEXP]) { X cerror("expression stack overflow at op \"%s\"", X opname[op]); X return (1); X } X opp->op = op; X opp->prec = prec; X skip = (valp[-1] != 0); /* Short-circuit tester */ X /* X * Do the short-circuit stuff here. Short-circuiting X * stops automagically when operators are evaluated. X */ X if ((op == OP_ANA && !skip) X || (op == OP_ORO && skip)) X opp->skip = S_ANDOR; /* And/or skip starts */ X else if (op == OP_QUE) /* Start of ?: operator */ X opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0); X else if (op == OP_COL) { /* : inverts S_QUEST */ X opp->skip = (op1 & S_ANDOR) X | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST); X } X else { /* Other ops leave */ X opp->skip = op1; /* skipping unchanged. */ X } X#ifdef DEBUG_EVAL X printf("stacking %s, valp[-1] == %d at %s", X opname[op], valp[-1], infile->bptr); X dumpstack(opstack, opp, value, valp); X#endif X goto again; X } X /* X * Pop operator from op. stack and evaluate it. X * End of stack and '(' are specials. X */ X skip = opp->skip; /* Remember skip value */ X switch ((op1 = opp->op)) { /* Look at stacked op */ X case OP_END: /* Stack end marker */ X if (op == OP_EOE) X return (valp[-1]); /* Finished ok. */ X goto again; /* Read another op. */ X X case OP_LPA: /* ( on stack */ X if (op != OP_RPA) { /* Matches ) on input */ X cerror("unbalanced paren's, op is \"%s\"", opname[op]); X return (1); X } X opp--; /* Unstack it */ X /* goto again; -- Fall through */ X X case OP_QUE: X goto again; /* Evaluate true expr. */ X X case OP_COL: /* : on stack. */ X opp--; /* Unstack : */ X if (opp->op != OP_QUE) { /* Matches ? on stack? */ X cerror("Misplaced '?' or ':', previous operator is %s", X opname[opp->op]); X return (1); X } X /* X * Evaluate op1. X */ X default: /* Others: */ X opp--; /* Unstack the operator */ X#ifdef DEBUG_EVAL X printf("Stack before evaluation of %s\n", opname[op1]); X dumpstack(opstack, opp, value, valp); X#endif X valp = evaleval(valp, op1, skip); X#ifdef DEBUG_EVAL X printf("Stack after evaluation\n"); X dumpstack(opstack, opp, value, valp); X#endif X } /* op1 switch end */ X } /* Stack unwind loop */ X} X XFILE_LOCAL int Xevallex(skip) Xint skip; /* TRUE if short-circuit evaluation */ X/* X * Return next eval operator or value. Called from eval(). It X * calls a special-purpose routines for 'char' strings and X * numeric values: X * evalchar called to evaluate 'x' X * evalnum called to evaluate numbers. X */ X{ X register int c, c1, t; X Xagain: do { /* Collect the token */ X c = skipws(); X if ((c = macroid(c)) == EOF_CHAR || c == '\n') { X unget(); X return (OP_EOE); /* End of expression */ X } X } while ((t = type[c]) == LET && catenate()); X if (t == INV) { /* Total nonsense */ X if (!skip) { X if (isascii(c) && isprint(c)) X cierror("illegal character '%c' in #if", c); X else X cierror("illegal character (%d decimal) in #if", c); X } X return (OP_FAIL); X } X else if (t == QUO) { /* ' or " */ X if (c == '\'') { /* Character constant */ X evalue = evalchar(skip); /* Somewhat messy */ X#ifdef DEBUG_EVAL X printf("evalchar returns %d.\n", evalue); X#endif X return (DIG); /* Return a value */ X } X cerror("Can't use a string in an #if", NULLST); X return (OP_FAIL); X } X else if (t == LET) { /* ID must be a macro */ X if (streq(token, "defined")) { /* Or defined name */ X c1 = c = skipws(); X if (c == '(') /* Allow defined(name) */ X c = skipws(); X if (type[c] == LET) { X evalue = (lookid(c) != NULL); X if (c1 != '(' /* Need to balance */ X || skipws() == ')') /* Did we balance? */ X return (DIG); /* Parsed ok */ X } X cerror("Bad #if ... defined() syntax", NULLST); X return (OP_FAIL); X } X else if (streq(token, "sizeof")) /* New sizeof hackery */ X return (dosizeof()); /* Gets own routine */ X /* X * The Draft ANSI C Standard says that an undefined symbol X * in an #if has the value zero. We are a bit pickier, X * warning except where the programmer was careful to write X * #if defined(foo) ? foo : 0 X */ X#ifdef VERBOSE X if (!skip) X cwarn("undefined symbol \"%s\" in #if, 0 used", token); X#endif X evalue = 0; X return (DIG); X } X else if (t == DIG) { /* Numbers are harder */ X evalue = evalnum(c); X#ifdef DEBUG_EVAL X printf("evalnum returns %d.\n", evalue); X#endif X } X else if (strchr("!=<>&|\\", c) != NULL) { X /* X * Process a possible multi-byte lexeme. X */ X c1 = cget(); /* Peek at next char */ X switch (c) { X case '!': X if (c1 == '=') X return (OP_NE); X break; X X case '=': X if (c1 != '=') { /* Can't say a=b in #if */ X unget(); X cerror("= not allowed in #if", NULLST); X return (OP_FAIL); X } X return (OP_EQ); X X case '>': X case '<': X if (c1 == c) X return ((c == '<') ? OP_ASL : OP_ASR); X else if (c1 == '=') X return ((c == '<') ? OP_LE : OP_GE); X break; X X case '|': X case '&': X if (c1 == c) X return ((c == '|') ? OP_ORO : OP_ANA); X break; X X case '\\': X if (c1 == '\n') /* Multi-line if */ X goto again; X cerror("Unexpected \\ in #if", NULLST); X return (OP_FAIL); X } X unget(); X } X return (t); X} X XFILE_LOCAL int Xdosizeof() X/* X * Process the sizeof (basic type) operation in an #if string. X * Sets evalue to the size and returns X * DIG success X * OP_FAIL bad parse or something. X */ X{ X register int c; X register TYPES *tp; X register SIZES *sizp; X register short *testp; X short typecode; X X if ((c = skipws()) != '(') X goto nogood; X /* X * Scan off the tokens. X */ X typecode = 0; X while ((c = skipws())) { X if ((c = macroid(c)) == EOF_CHAR || c == '\n') X goto nogood; /* End of line is a bug */ X else if (c == '(') { /* thing (*)() func ptr */ X if (skipws() == '*' X && skipws() == ')') { /* We found (*) */ X if (skipws() != '(') /* Let () be optional */ X unget(); X else if (skipws() != ')') X goto nogood; X typecode |= T_FPTR; /* Function pointer */ X } X else { /* Junk is a bug */ X goto nogood; X } X } X else if (type[c] != LET) /* Exit if not a type */ X break; X else if (!catenate()) { /* Maybe combine tokens */ X /* X * Look for this unexpandable token in basic_types. X * The code accepts "int long" as well as "long int" X * which is a minor bug as bugs go (and one shared with X * a lot of C compilers). X */ X for (tp = basic_types; tp->name != NULLST; tp++) { X if (streq(token, tp->name)) X break; X } X if (tp->name == NULLST) { X cerror("#if sizeof, unknown type \"%s\"", token); X return (OP_FAIL); X } X typecode |= tp->type; /* Or in the type bit */ X } X } X /* X * We are at the end of the type scan. Chew off '*' if necessary. X */ X if (c == '*') { X typecode |= T_PTR; X c = skipws(); X } X if (c == ')') { /* Last syntax check */ X for (testp = test_table; *testp != 0; testp++) { X if (!bittest(typecode & *testp)) { X cerror("#if ... sizeof: illegal type combination", NULLST); X return (OP_FAIL); X } X } X /* X * We assume that all function pointers are the same size: X * sizeof (int (*)()) == sizeof (float (*)()) X * We assume that signed and unsigned don't change the size: X * sizeof (signed int) == (sizeof unsigned int) X */ X if ((typecode & T_FPTR) != 0) /* Function pointer */ X typecode = T_FPTR | T_PTR; X else { /* Var or var * datum */ X typecode &= ~(T_SIGNED | T_UNSIGNED); X if ((typecode & (T_SHORT | T_LONG)) != 0) X typecode &= ~T_INT; X } X if ((typecode & ~T_PTR) == 0) { X cerror("#if sizeof() error, no type specified", NULLST); X return (OP_FAIL); X } X /* X * Exactly one bit (and possibly T_PTR) may be set. X */ X for (sizp = size_table; sizp->bits != 0; sizp++) { X if ((typecode & ~T_PTR) == sizp->bits) { X evalue = ((typecode & T_PTR) != 0) X ? sizp->psize : sizp->size; X return (DIG); X } X } /* We shouldn't fail */ X cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode); X return (OP_FAIL); X } X Xnogood: unget(); X cerror("#if ... sizeof() syntax error", NULLST); X return (OP_FAIL); X} X XFILE_LOCAL int Xbittest(value) X/* X * TRUE if value is zero or exactly one bit is set in value. X */ X{ X#if (4096 & ~(-4096)) == 0 X return ((value & ~(-value)) == 0); X#else X /* X * Do it the hard way (for non 2's complement machines) X */ X return (value == 0 || value ^ (value - 1) == (value * 2 - 1)); X#endif X} X XFILE_LOCAL int Xevalnum(c) Xregister int c; X/* X * Expand number for #if lexical analysis. Note: evalnum recognizes X * the unsigned suffix, but only returns a signed int value. X */ X{ X register int value; X register int base; X register int c1; X X if (c != '0') X base = 10; X else if ((c = cget()) == 'x' || c == 'X') { X base = 16; X c = cget(); X } X else base = 8; X value = 0; X for (;;) { X c1 = c; X if (isascii(c) && isupper(c1)) X c1 = tolower(c1); X if (c1 >= 'a') X c1 -= ('a' - 10); X else c1 -= '0'; X if (c1 < 0 || c1 >= base) X break; X value *= base; X value += c1; X c = cget(); X } X if (c == 'u' || c == 'U') /* Unsigned nonsense */ X c = cget(); X unget(); X return (value); X} X XFILE_LOCAL int Xevalchar(skip) Xint skip; /* TRUE if short-circuit evaluation */ X/* X * Get a character constant X */ X{ X register int c; X register int value; X register int count; X X instring = TRUE; X if ((c = cget()) == '\\') { X switch ((c = cget())) { X case 'a': /* New in Standard */ X#if ('a' == '\a' || '\a' == ALERT) X value = ALERT; /* Use predefined value */ X#else X value = '\a'; /* Use compiler's value */ X#endif X break; X X case 'b': X value = '\b'; X break; X X case 'f': X value = '\f'; X break; X X case 'n': X value = '\n'; X break; X X case 'r': X value = '\r'; X break; X X case 't': X value = '\t'; X break; X X case 'v': /* New in Standard */ X#if ('v' == '\v' || '\v' == VT) X value = VT; /* Use predefined value */ X#else X value = '\v'; /* Use compiler's value */ X#endif X break; X X case 'x': /* '\xFF' */ X count = 3; X value = 0; X while ((((c = get()) >= '0' && c <= '9') X || (c >= 'a' && c <= 'f') X || (c >= 'A' && c <= 'F')) X && (--count >= 0)) { X value *= 16; X value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9); X } X unget(); X break; X X default: X if (c >= '0' && c <= '7') { X count = 3; X value = 0; X while (c >= '0' && c <= '7' && --count >= 0) { X value *= 8; X value += (c - '0'); X c = get(); X } X unget(); X } X else value = c; X break; X } X } X else if (c == '\'') X value = 0; X else value = c; X /* X * We warn on multi-byte constants and try to hack X * (big|little)endian machines. X */ X#if BIG_ENDIAN X count = 0; X#endif X while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') { X if (!skip) X ciwarn("multi-byte constant '%c' isn't portable", c); X#if BIG_ENDIAN X count += BITS_CHAR; X value += (c << count); X#else X value <<= BITS_CHAR; X value += c; X#endif X } X instring = FALSE; X return (value); X} X XFILE_LOCAL int * Xevaleval(valp, op, skip) Xregister int *valp; Xint op; Xint skip; /* TRUE if short-circuit evaluation */ X/* X * Apply the argument operator to the data on the value stack. X * One or two values are popped from the value stack and the result X * is pushed onto the value stack. X * X * OP_COL is a special case. X * X * evaleval() returns the new pointer to the top of the value stack. X */ X{ X register int v1, v2; X X if (isbinary(op)) X v2 = *--valp; X v1 = *--valp; X#ifdef DEBUG_EVAL X printf("%s op %s", (isbinary(op)) ? "binary" : "unary", X opname[op]); X if (isbinary(op)) X printf(", v2 = %d.", v2); X printf(", v1 = %d.\n", v1); X#endif X switch (op) { X case OP_EOE: X break; X X case OP_ADD: X v1 += v2; X break; X X case OP_SUB: X v1 -= v2; X break; X X case OP_MUL: X v1 *= v2; X break; X X case OP_DIV: X case OP_MOD: X if (v2 == 0) { X if (!skip) { X cwarn("%s by zero in #if, zero result assumed", X (op == OP_DIV) ? "divide" : "mod"); X } X v1 = 0; X } X else if (op == OP_DIV) X v1 /= v2; X else X v1 %= v2; X break; X X case OP_ASL: X v1 <<= v2; X break; X X case OP_ASR: X v1 >>= v2; X break; X X case OP_AND: X v1 &= v2; X break; X X case OP_OR: X v1 |= v2; X break; X X case OP_XOR: X v1 ^= v2; X break; X X case OP_EQ: X v1 = (v1 == v2); X break; X X case OP_NE: X v1 = (v1 != v2); X break; X X case OP_LT: X v1 = (v1 < v2); X break; X X case OP_LE: X v1 = (v1 <= v2); X break; X X case OP_GE: X v1 = (v1 >= v2); X break; X X case OP_GT: X v1 = (v1 > v2); X break; X X case OP_ANA: X v1 = (v1 && v2); X break; X X case OP_ORO: X v1 = (v1 || v2); X break; X X case OP_COL: X /* X * v1 has the "true" value, v2 the "false" value. X * The top of the value stack has the test. X */ X v1 = (*--valp) ? v1 : v2; X break; X X case OP_NEG: X v1 = (-v1); X break; X X case OP_PLU: X break; X X case OP_COM: X v1 = ~v1; X break; X X case OP_NOT: X v1 = !v1; X break; X X default: X cierror("#if bug, operand = %d.", op); X v1 = 0; X } X *valp++ = v1; X return (valp); X} X X#ifdef DEBUG_EVAL Xdumpstack(opstack, opp, value, valp) XOPTAB opstack[NEXP]; /* Operand stack */ Xregister OPTAB *opp; /* Operator stack */ Xint value[NEXP]; /* Value stack */ Xregister int *valp; /* -> value vector */ X{ X printf("index op prec skip name -- op stack at %s", infile->bptr); X while (opp > opstack) { X printf(" [%2d] %2d %03o %d %s\n", opp - opstack, X opp->op, opp->prec, opp->skip, opname[opp->op]); X opp--; X } X while (--valp >= value) { X printf("value[%d] = %d\n", (valp - value), *valp); X } X} X#endif X END-of-cpp5.c echo x - cpp6.c sed 's/^X//' >cpp6.c << 'END-of-cpp6.c' X/* X * C P P 6 . C X * S u p p o r t R o u t i n e s X * X * Edit History X * 25-May-84 MM Added 8-bit support to type table. X * 30-May-84 ARF sharp() should output filename in quotes X * 02-Aug-84 MM Newline and #line hacking. sharp() now in cpp1.c X * 31-Aug-84 MM USENET net.sources release X * 11-Sep-84 ado/MM Keepcomments, also line number pathological X * 12-Sep-84 ado/MM bug if comment changes to space and we unget later. X * 03-Oct-84 gkr/MM Fixed scannumber bug for '.e' (as in struct.element). X * 04-Oct-84 MM Added ungetstring() for token concatenation X * 08-Oct-84 MM Yet another attack on number scanning X * 31-Oct-84 ado Parameterized $ in identifiers X * 2-Nov-84 MM Token concatenation is messier than I thought X * 6-Dec-84 MM \ is everywhere invisible. X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X X/* X * skipnl() skips over input text to the end of the line. X * skipws() skips over "whitespace" (spaces or tabs), but X * not skip over the end of the line. It skips over X * TOK_SEP, however (though that shouldn't happen). X * scanid() reads the next token (C identifier) into token[]. X * The caller has already read the first character of X * the identifier. Unlike macroid(), the token is X * never expanded. X * macroid() reads the next token (C identifier) into token[]. X * If it is a #defined macro, it is expanded, and X * macroid() returns TRUE, otherwise, FALSE. X * catenate() Does the dirty work of token concatenation, TRUE if it did. X * scanstring() Reads a string from the input stream, calling X * a user-supplied function for each character. X * This function may be output() to write the X * string to the output file, or save() to save X * the string in the work buffer. X * scannumber() Reads a C numeric constant from the input stream, X * calling the user-supplied function for each X * character. (output() or save() as noted above.) X * save() Save one character in the work[] buffer. X * savestring() Saves a string in malloc() memory. X * getfile() Initialize a new FILEINFO structure, called when X * #include opens a new file, or a macro is to be X * expanded. X * getmem() Get a specified number of bytes from malloc memory. X * output() Write one character to stdout (calling putchar) -- X * implemented as a function so its address may be X * passed to scanstring() and scannumber(). X * lookid() Scans the next token (identifier) from the input X * stream. Looks for it in the #defined symbol table. X * Returns a pointer to the definition, if found, or NULL X * if not present. The identifier is stored in token[]. X * defnedel() Define enter/delete subroutine. Updates the X * symbol table. X * get() Read the next byte from the current input stream, X * handling end of (macro/file) input and embedded X * comments appropriately. Note that the global X * instring is -- essentially -- a parameter to get(). X * cget() Like get(), but skip over TOK_SEP. X * unget() Push last gotten character back on the input stream. X * cerror(), cwarn(), cfatal(), cierror(), ciwarn() X * These routines format an print messages to the user. X * cerror & cwarn take a format and a single string argument. X * cierror & ciwarn take a format and a single int (char) argument. X * cfatal takes a format and a single string argument. X */ X X/* X * This table must be rewritten for a non-Ascii machine. X * X * Note that several "non-visible" characters have special meaning: X * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion. X * Hex 1E TOK_SEP -- a delimiter for token concatenation X * Hex 1F COM_SEP -- a zero-width whitespace for comment concatenation X */ X#if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D X << error type table isn't correct >> X#endif X X#if OK_DOLLAR X#define DOL LET X#else X#define DOL 000 X#endif X Xchar type[256] = { /* Character type codes Hex */ X END, 000, 000, 000, 000, 000, 000, 000, /* 00 */ X 000, SPA, 000, 000, 000, 000, 000, 000, /* 08 */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */ X 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */ X SPA,OP_NOT, QUO, 000, DOL,OP_MOD,OP_AND, QUO, /* 20 !"#$%&' */ XOP_LPA,OP_RPA,OP_MUL,OP_ADD, 000,OP_SUB, DOT,OP_DIV, /* 28 ()*+,-./ */ X DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* 30 01234567 */ X DIG, DIG,OP_COL, 000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */ X 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */ X LET, LET, LET, 000, BSH, 000,OP_XOR, LET, /* 58 XYZ[\]^_ */ X 000, LET, LET, LET, LET, LET, LET, LET, /* 60 `abcdefg */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */ X LET, LET, LET, 000, OP_OR, 000,OP_NOT, 000, /* 78 xyz{|}~ */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X}; X Xskipnl() X/* X * Skip to the end of the current input line. X */ X{ X register int c; X X do { /* Skip to newline */ X c = get(); X } while (c != '\n' && c != EOF_CHAR); X} X Xint Xskipws() X/* X * Skip over whitespace X */ X{ X register int c; X X do { /* Skip whitespace */ X c = get(); X#if COMMENT_INVISIBLE X } while (type[c] == SPA || c == COM_SEP); X#else X } while (type[c] == SPA); X#endif X return (c); X} X Xscanid(c) Xregister int c; /* First char of id */ X/* X * Get the next token (an id) into the token buffer. X * Note: this code is duplicated in lookid(). X * Change one, change both. X */ X{ X register char *bp; X X if (c == DEF_MAGIC) /* Eat the magic token */ X c = get(); /* undefiner. */ X bp = token; X do { X if (bp < &token[IDMAX]) /* token dim is IDMAX+1 */ X *bp++ = c; X c = get(); X } while (type[c] == LET || type[c] == DIG); X unget(); X *bp = EOS; X} X Xint Xmacroid(c) Xregister int c; X/* X * If c is a letter, scan the id. if it's #defined, expand it and scan X * the next character and try again. X * X * Else, return the character. If type[c] is a LET, the token is in token. X */ X{ X register DEFBUF *dp; X X if (infile != NULL && infile->fp != NULL) X recursion = 0; X while (type[c] == LET && (dp = lookid(c)) != NULL) { X expand(dp); X c = get(); X } X return (c); X} X Xint Xcatenate() X/* X * A token was just read (via macroid). X * If the next character is TOK_SEP, concatenate the next token X * return TRUE -- which should recall macroid after refreshing X * macroid's argument. If it is not TOK_SEP, unget() the character X * and return FALSE. X */ X{ X register int c; X register char *token1; X X#if OK_CONCAT X if (get() != TOK_SEP) { /* Token concatenation */ X unget(); X return (FALSE); X } X else { X token1 = savestring(token); /* Save first token */ X c = macroid(get()); /* Scan next token */ X switch(type[c]) { /* What was it? */ X case LET: /* An identifier, ... */ X if (strlen(token1) + strlen(token) >= NWORK) X cfatal("work buffer overflow doing %s #", token1); X sprintf(work, "%s%s", token1, token); X break; X X case DIG: /* A digit string */ X strcpy(work, token1); X workp = work + strlen(work); X do { X save(c); X } while ((c = get()) != TOK_SEP); X /* X * The trailing TOK_SEP is no longer needed. X */ X save(EOS); X break; X X default: /* An error, ... */ X if (isprint(c)) X cierror("Strange character '%c' after #", c); X else X cierror("Strange character (%d.) after #", c); X strcpy(work, token1); X unget(); X break; X } X /* X * work has the concatenated token and token1 has X * the first token (no longer needed). Unget the X * new (concatenated) token after freeing token1. X * Finally, setup to read the new token. X */ X free(token1); /* Free up memory */ X ungetstring(work); /* Unget the new thing, */ X return (TRUE); X } X#else X return (FALSE); /* Not supported */ X#endif X} X Xint Xscanstring(delim, outfun) Xregister int delim; /* ' or " */ Xint (*outfun)(); /* Output function */ X/* X * Scan off a string. Warning if terminated by newline or EOF. X * outfun() outputs the character -- to a buffer if in a macro. X * TRUE if ok, FALSE if error. X */ X{ X register int c; X X instring = TRUE; /* Don't strip comments */ X (*outfun)(delim); X while ((c = get()) != delim X && c != '\n' X && c != EOF_CHAR) { X (*outfun)(c); X if (c == '\\') X (*outfun)(get()); X } X instring = FALSE; X if (c == delim) { X (*outfun)(c); X return (TRUE); X } X else { X cerror("Unterminated string", NULLST); X unget(); X return (FALSE); X } X} X Xscannumber(c, outfun) Xregister int c; /* First char of number */ Xregister int (*outfun)(); /* Output/store func */ X/* X * Process a number. We know that c is from 0 to 9 or dot. X * Algorithm from Dave Conroy's Decus C. X */ X{ X register int radix; /* 8, 10, or 16 */ X int expseen; /* 'e' seen in floater */ X int signseen; /* '+' or '-' seen */ X int octal89; /* For bad octal test */ X int dotflag; /* TRUE if '.' was seen */ X X expseen = FALSE; /* No exponent seen yet */ X signseen = TRUE; /* No +/- allowed yet */ X octal89 = FALSE; /* No bad octal yet */ X radix = 10; /* Assume decimal */ X if ((dotflag = (c == '.')) != FALSE) { /* . something? */ X (*outfun)('.'); /* Always out the dot */ X if (type[(c = get())] != DIG) { /* If not a float numb, */ X unget(); /* Rescan strange char */ X return; /* All done for now */ X } X } /* End of float test */ X else if (c == '0') { /* Octal or hex? */ X (*outfun)(c); /* Stuff initial zero */ X radix = 8; /* Assume it's octal */ X c = get(); /* Look for an 'x' */ X if (c == 'x' || c == 'X') { /* Did we get one? */ X radix = 16; /* Remember new radix */ X (*outfun)(c); /* Stuff the 'x' */ X c = get(); /* Get next character */ X } X } X for (;;) { /* Process curr. char. */ X /* X * Note that this algorithm accepts "012e4" and "03.4" X * as legitimate floating-point numbers. X */ X if (radix != 16 && (c == 'e' || c == 'E')) { X if (expseen) /* Already saw 'E'? */ X break; /* Exit loop, bad nbr. */ X expseen = TRUE; /* Set exponent seen */ X signseen = FALSE; /* We can read '+' now */ X radix = 10; /* Decimal exponent */ X } X else if (radix != 16 && c == '.') { X if (dotflag) /* Saw dot already? */ X break; /* Exit loop, two dots */ X dotflag = TRUE; /* Remember the dot */ X radix = 10; /* Decimal fraction */ X } X else if (c == '+' || c == '-') { /* 1.0e+10 */ X if (signseen) /* Sign in wrong place? */ X break; /* Exit loop, not nbr. */ X /* signseen = TRUE; */ /* Remember we saw it */ X } X else { /* Check the digit */ X switch (c) { X case '8': case '9': /* Sometimes wrong */ X octal89 = TRUE; /* Do check later */ X case '0': case '1': case '2': case '3': X case '4': case '5': case '6': case '7': X break; /* Always ok */ X X case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': X if (radix == 16) /* Alpha's are ok only */ X break; /* if reading hex. */ X default: /* At number end */ X goto done; /* Break from for loop */ X } /* End of switch */ X } /* End general case */ X (*outfun)(c); /* Accept the character */ X signseen = TRUE; /* Don't read sign now */ X c = get(); /* Read another char */ X } /* End of scan loop */ X /* X * When we break out of the scan loop, c contains the first X * character (maybe) not in the number. If the number is an X * integer, allow a trailing 'L' for long and/or a trailing 'U' X * for unsigned. If not those, push the trailing character back X * on the input stream. Floating point numbers accept a trailing X * 'L' for "long double". X */ Xdone: if (dotflag || expseen) { /* Floating point? */ X if (c == 'l' || c == 'L') { X (*outfun)(c); X c = get(); /* Ungotten later */ X } X } X else { /* Else it's an integer */ X /* X * We know that dotflag and expseen are both zero, now: X * dotflag signals "saw 'L'", and X * expseen signals "saw 'U'". X */ X for (;;) { X switch (c) { X case 'l': X case 'L': X if (dotflag) X goto nomore; X dotflag = TRUE; X break; X X case 'u': X case 'U': X if (expseen) X goto nomore; X expseen = TRUE; X break; X X default: X goto nomore; X } X (*outfun)(c); /* Got 'L' or 'U'. */ X c = get(); /* Look at next, too. */ X } X } Xnomore: unget(); /* Not part of a number */ X if (octal89 && radix == 8) X cwarn("Illegal digit in octal number", NULLST); X} X Xsave(c) Xregister int c; X{ X if (workp >= &work[NWORK]) X cfatal("Work buffer overflow", NULLST); X else *workp++ = c; X} X Xchar * Xsavestring(text) Xchar *text; X/* X * Store a string into free memory. X */ X{ X register char *result; X X result = getmem(strlen(text) + 1); X strcpy(result, text); X return (result); X} X XFILEINFO * Xgetfile(bufsize, name) Xint bufsize; /* Line or define buffer size */ Xchar *name; /* File or macro name string */ X/* X * Common FILEINFO buffer initialization for a new file or macro. X */ X{ X register FILEINFO *file; X register int size; X X size = strlen(name); /* File/macro name */ X file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size); X file->parent = infile; /* Chain files together */ X file->fp = NULL; /* No file yet */ X file->filename = savestring(name); /* Save file/macro name */ X file->progname = NULL; /* No #line seen yet */ X file->unrecur = 0; /* No macro fixup */ X file->bptr = file->buffer; /* Initialize line ptr */ X file->buffer[0] = EOS; /* Force first read */ X file->line = 0; /* (Not used just yet) */ X if (infile != NULL) /* If #include file */ X infile->line = line; /* Save current line */ X infile = file; /* New current file */ X line = 1; /* Note first line */ X return (file); /* All done. */ X} X Xchar * Xgetmem(size) Xint size; X/* X * Get a block of free memory. X */ X{ X register char *result; X extern char *malloc(); X X if ((result = malloc((unsigned) size)) == NULL) X cfatal("Out of memory", NULLST); X return (result); X} X X/* X * C P P S y m b o l T a b l e s X */ X X/* X * SBSIZE defines the number of hash-table slots for the symbol table. X * It must be a power of 2. X */ X#ifndef SBSIZE X#define SBSIZE 64 X#endif X#define SBMASK (SBSIZE - 1) X#if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1) X << error, SBSIZE must be a power of 2 >> X#endif X Xstatic DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */ X XDEFBUF * Xlookid(c) Xint c; /* First character of token */ X/* X * Look for the next token in the symbol table. Returns token in "token". X * If found, returns the table pointer; Else returns NULL. X */ X{ X register int nhash; X register DEFBUF *dp; X register char *np; X int temp; X int isrecurse; /* For #define foo foo */ X X np = token; X nhash = 0; X if ((isrecurse = (c == DEF_MAGIC))) /* If recursive macro */ X c = get(); /* hack, skip DEF_MAGIC */ X do { X if (np < &token[IDMAX]) { /* token dim is IDMAX+1 */ X *np++ = c; /* Store token byte */ X nhash += c; /* Update hash value */ X } X c = get(); /* And get another byte */ X } while (type[c] == LET || type[c] == DIG); X unget(); /* Rescan terminator */ X *np = EOS; /* Terminate token */ X if (isrecurse) /* Recursive definition */ X return (NULL); /* undefined just now */ X nhash += (np - token); /* Fix hash value */ X dp = symtab[nhash & SBMASK]; /* Starting bucket */ X while (dp != (DEFBUF *) NULL) { /* Search symbol table */ X if (dp->hash == nhash /* Fast precheck */ X && (temp = strcmp(dp->name, token)) >= 0) X break; X dp = dp->link; /* Nope, try next one */ X } X return ((temp == 0) ? dp : NULL); X} X XDEFBUF * Xdefendel(name, delete) Xchar *name; Xint delete; /* TRUE to delete a symbol */ X/* X * Enter this name in the lookup table (delete = FALSE) X * or delete this name (delete = TRUE). X * Returns a pointer to the define block (delete = FALSE) X * Returns NULL if the symbol wasn't defined (delete = TRUE). X */ X{ X register DEFBUF *dp; X register DEFBUF **prevp; X register char *np; X int nhash; X int temp; X int size; X X for (nhash = 0, np = name; *np != EOS;) X nhash += *np++; X size = (np - name); X nhash += size; X prevp = &symtab[nhash & SBMASK]; X while ((dp = *prevp) != (DEFBUF *) NULL) { X if (dp->hash == nhash X && (temp = strcmp(dp->name, name)) >= 0) { X if (temp > 0) X dp = NULL; /* Not found */ X else { X *prevp = dp->link; /* Found, unlink and */ X if (dp->repl != NULL) /* Free the replacement */ X free(dp->repl); /* if any, and then */ X free((char *) dp); /* Free the symbol */ X } X break; X } X prevp = &dp->link; X } X if (!delete) { X dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size); X dp->link = *prevp; X *prevp = dp; X dp->hash = nhash; X dp->repl = NULL; X dp->nargs = 0; X strcpy(dp->name, name); X } X return (dp); X} X X#if DEBUG X Xdumpdef(why) Xchar *why; X{ X register DEFBUF *dp; X register DEFBUF **syp; X X printf("CPP symbol table dump %s\n", why); X for (syp = symtab; syp < &symtab[SBSIZE]; syp++) { X if ((dp = *syp) != (DEFBUF *) NULL) { X printf("symtab[%d]\n", (syp - symtab)); X do { X dumpadef((char *) NULL, dp); X } while ((dp = dp->link) != (DEFBUF *) NULL); X } X } X} X Xdumpadef(why, dp) Xchar *why; /* Notation */ Xregister DEFBUF *dp; X{ X register char *cp; X register int c; X X printf(" \"%s\" [%d]", dp->name, dp->nargs); X if (why != NULL) X printf(" (%s)", why); X if (dp->repl != NULL) { X printf(" => "); X for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) { X if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) X printf("<%d>", c - MAC_PARM); X else if (isprint(c) || c == '\n' || c == '\t') X putchar(c); X else if (c < ' ') X printf("<^%c>", c + '@'); X else X printf("<\\0%o>", c); X } X } X else { X printf(", no replacement."); X } X putchar('\n'); X} X#endif X X/* X * G E T X */ X Xint Xget() X/* X * Return the next character from a macro or the current file. X * Handle end of file from #include files. X */ X{ X register int c; X register FILEINFO *file; X register int popped; /* Recursion fixup */ X X popped = 0; Xget_from_file: X if ((file = infile) == NULL) X return (EOF_CHAR); Xnewline: X#if 0 X printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n", X file->filename, recursion, line, X file->bptr - file->buffer, file->buffer); X#endif X /* X * Read a character from the current input line or macro. X * At EOS, either finish the current macro (freeing temp. X * storage) or read another line from the current input file. X * At EOF, exit the current file (#include) or, at EOF from X * the cpp input file, return EOF_CHAR to finish processing. X */ X if ((c = *file->bptr++ & 0xFF) == EOS) { X /* X * Nothing in current line or macro. Get next line (if X * input from a file), or do end of file/macro processing. X * In the latter case, jump back to restart from the top. X */ X if (file->fp == NULL) { /* NULL if macro */ X popped++; X recursion -= file->unrecur; X if (recursion < 0) X recursion = 0; X infile = file->parent; /* Unwind file chain */ X } X else { /* Else get from a file */ X if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) X != NULL) { X#if DEBUG X if (debug > 1) { /* Dump it to stdout */ X printf("\n#line %d (%s), %s", X line, file->filename, file->buffer); X } X#endif X goto newline; /* process the line */ X } X else { X fclose(file->fp); /* Close finished file */ X if ((infile = file->parent) != NULL) { X /* X * There is an "ungotten" newline in the current X * infile buffer (set there by doinclude() in X * cpp1.c). Thus, we know that the mainline code X * is skipping over blank lines and will do a X * #line at its convenience. X */ X wrongline = TRUE; /* Need a #line now */ X } X } X } X /* X * Free up space used by the (finished) file or macro and X * restart input from the parent file/macro, if any. X */ X free(file->filename); /* Free name and */ X if (file->progname != NULL) /* if a #line was seen, */ X free(file->progname); /* free it, too. */ X free((char *) file); /* Free file space */ X if (infile == NULL) /* If at end of file */ X return (EOF_CHAR); /* Return end of file */ X line = infile->line; /* Reset line number */ X goto get_from_file; /* Get from the top. */ X } X /* X * Common processing for the new character. X */ X if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete */ X goto newline; /* from a file */ X if (file->parent != NULL) { /* Macro or #include */ X if (popped != 0) X file->parent->unrecur += popped; X else { X recursion -= file->parent->unrecur; X if (recursion < 0) X recursion = 0; X file->parent->unrecur = 0; X } X } X if (c == '\n') /* Maintain current */ X ++line; /* line counter */ X if (instring) /* Strings just return */ X return (c); /* the character. */ X else if (c == '/') { /* Comment? */ X instring = TRUE; /* So get() won't loop */ X if ((c = get()) != '*') { /* Next byte '*'? */ X instring = FALSE; /* Nope, no comment */ X unget(); /* Push the char. back */ X return ('/'); /* Return the slash */ X } X if (keepcomments) { /* If writing comments */ X putchar('/'); /* Write out the */ X putchar('*'); /* initializer */ X } X for (;;) { /* Eat a comment */ X c = get(); Xtest: if (keepcomments && c != EOF_CHAR) X cput(c); X switch (c) { X case EOF_CHAR: X cerror("EOF in comment", NULLST); X return (EOF_CHAR); X X case '/': X if ((c = get()) != '*') /* Don't let comments */ X goto test; /* Nest. */ X#ifdef VERBOSE X cwarn("Nested comments", NULLST); X#endif X /* Fall into * stuff */ X case '*': X if ((c = get()) != '/') /* If comment doesn't */ X goto test; /* end, look at next */ X instring = FALSE; /* End of comment, */ X if (keepcomments) { /* Put out the comment */ X cput(c); /* terminator, too */ X } X /* X * A comment is syntactically "whitespace" -- X * however, there are certain strange sequences X * such as X * #define foo(x) (something) X * foo|* comment *|(123) X * these are '/' ^ ^ X * where just returning space (or COM_SEP) will cause X * problems. This can be "fixed" by overwriting the X * '/' in the input line buffer with ' ' (or COM_SEP) X * but that may mess up an error message. X * So, we peek ahead -- if the next character is X * "whitespace" we just get another character, if not, X * we modify the buffer. All in the name of purity. X */ X if (*file->bptr == '\n' X || type[*file->bptr & 0xFF] == SPA) X goto newline; X#if COMMENT_INVISIBLE X /* X * Return magic (old-fashioned) syntactic space. X */ X return ((file->bptr[-1] = COM_SEP)); X#else X return ((file->bptr[-1] = ' ')); X#endif X X case '\n': /* we'll need a #line */ X if (!keepcomments) X wrongline = TRUE; /* later... */ X default: /* Anything else is */ X break; /* Just a character */ X } /* End switch */ X } /* End comment loop */ X } /* End if in comment */ X else if (!inmacro && c == '\\') { /* If backslash, peek */ X if ((c = get()) == '\n') { /* for a . If so, */ X wrongline = TRUE; X goto newline; X } X else { /* Backslash anything */ X unget(); /* Get it later */ X return ('\\'); /* Return the backslash */ X } X } X else if (c == '\f' || c == VT) /* Form Feed, Vertical */ X c = ' '; /* Tab are whitespace */ X return (c); /* Just return the char */ X} X Xunget() X/* X * Backup the pointer to reread the last character. Fatal error X * (code bug) if we backup too far. unget() may be called, X * without problems, at end of file. Only one character may X * be ungotten. If you need to unget more, call ungetstring(). X */ X{ X register FILEINFO *file; X X if ((file = infile) == NULL) X return; /* Unget after EOF */ X if (--file->bptr < file->buffer) X cfatal("Too much pushback", NULLST); X if (*file->bptr == '\n') /* Ungetting a newline? */ X --line; /* Unget the line number, too */ X} X Xungetstring(text) Xchar *text; X/* X * Push a string back on the input stream. This is done by treating X * the text as if it were a macro. X */ X{ X register FILEINFO *file; X extern FILEINFO *getfile(); X X file = getfile(strlen(text) + 1, ""); X strcpy(file->buffer, text); X} X Xint Xcget() X/* X * Get one character, absorb "funny space" after comments or X * token concatenation X */ X{ X register int c; X X do { X c = get(); X#if COMMENT_INVISIBLE X } while (c == TOK_SEP || c == COM_SEP); X#else X } while (c == TOK_SEP); X#endif X return (c); X} X X/* X * Error messages and other hacks. The first byte of severity X * is 'S' for string arguments and 'I' for int arguments. This X * is needed for portability with machines that have int's that X * are shorter than char *'s. X */ X Xstatic Xdomsg(severity, format, arg) Xchar *severity; /* "Error", "Warning", "Fatal" */ Xchar *format; /* Format for the error message */ Xchar *arg; /* Something for the message */ X/* X * Print filenames, macro names, and line numbers for error messages. X */ X{ X register char *tp; X register FILEINFO *file; X X fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]); X if (*severity == 'S') X fprintf(stderr, format, arg); X else X fprintf(stderr, format, (int) arg); X putc('\n', stderr); X if ((file = infile) == NULL) X return; /* At end of file */ X if (file->fp != NULL) { X tp = file->buffer; /* Print current file */ X fprintf(stderr, "%s", tp); /* name, making sure */ X if (tp[strlen(tp) - 1] != '\n') /* there's a newline */ X putc('\n', stderr); X } X while ((file = file->parent) != NULL) { /* Print #includes, too */ X if (file->fp == NULL) X fprintf(stderr, "from macro %s\n", file->filename); X else { X tp = file->buffer; X fprintf(stderr, "from file %s, line %d:\n%s", X (file->progname != NULL) X ? file->progname : file->filename, X file->line, tp); X if (tp[strlen(tp) - 1] != '\n') X putc('\n', stderr); X } X } X} X Xcerror(format, sarg) Xchar *format; Xchar *sarg; /* Single string argument */ X/* X * Print a normal error message, string argument. X */ X{ X domsg("SError", format, sarg); X errors++; X} X Xcierror(format, narg) Xchar *format; Xint narg; /* Single numeric argument */ X/* X * Print a normal error message, numeric argument. X */ X{ X domsg("IError", format, (char *) narg); X errors++; X} X Xcfatal(format, sarg) Xchar *format; Xchar *sarg; /* Single string argument */ X/* X * A real disaster X */ X{ X domsg("SFatal error", format, sarg); X exit(IO_ERROR); X} X Xcwarn(format, sarg) Xchar *format; Xchar *sarg; /* Single string argument */ X/* X * A non-fatal error, string argument. X */ X{ X domsg("SWarning", format, sarg); X} X Xciwarn(format, narg) Xchar *format; Xint narg; /* Single numeric argument */ X/* X * A non-fatal error, numeric argument. X */ X{ X domsg("IWarning", format, (char *) narg); X} X X X END-of-cpp6.c exit nethack-3.6.0/sys/unix/depend.awk0000664000076400007660000001307712536476415015726 0ustar paxedpaxed# depend.awk -- awk script used to construct makefile dependencies # for nethack's source files (`make depend' support for Makefile.src). # $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # # usage: # cd src ; nawk -f depend.awk ../include/*.h list-of-.c/.cpp-files # # This awk program scans each file in sequence, looking for lines beginning # with `#include "' and recording the name inside the quotes. For .h files, # that's all it does. For each .c file, it writes out a make rule for the # corresponding .o file; dependencies in nested header files are propagated # to the .o target. # # config.h and hack.h get special handling because of their heavy use; # timestamps for them allow make to avoid rechecking dates on # subsidiary headers for every source file; # extern.h gets special handling to avoid excessive recompilation # during development; # patchlev.h gets special handling because it only exists on systems # which consider filename patchlevel.h to be too long; # interp.c gets special handling because it usually doesn't exist; it's # assumed to be the last #include in the file where it occurs. # win32api.h gets special handling because it only exists for some ports; # it's assumed to be the last #include in the file where it occurs # zlib.h ditto # BEGIN { FS = "\"" #for `#include "X"', $2 is X special[++sp_cnt] = "../include/config.h" special[++sp_cnt] = "../include/hack.h" alt_deps["../include/extern.h"] = "" alt_deps["../include/patchlev.h"] = "" alt_deps["interp.c"] = " #interp.c" #comment it out alt_deps["../include/win32api.h"] = " #../include/win32api.h" alt_deps["../include/zlib.h"] = " #zlib.h" #comment it out } FNR == 1 { output_dep() #finish previous file file = FILENAME #setup for current file } /^\#[ \t]*include[ \t]+\"/ { #find `#include "X"' incl = $2 #[3.4.0: gnomehack headers currently aren't in include] if (incl ~ /\.h$/) { if (incl ~ /^gn/) # gnomehack special case incl = "../win/gnome/" incl else incl = "../include/" incl } deps[file] = deps[file] " " incl } END { output_dep() } #finish the last file # # `file' has been fully scanned, so process it now; for .h files, # don't do anything (we've just been collecting their dependencies); # for .c files, output the `make' rule for corresponding .o file # function output_dep( targ) { if (file ~ /\.cp*$/) { #prior to very first .c|.cpp file, handle some special header file cases if (!c_count++) output_specials() #construct object filename from source filename targ = file; sub("^.+/", "", targ); sub("\\.cp*$", ".o", targ) #format and write the collected dependencies format_dep(targ, file) } } # # handle some targets (config.h, hack.h) via special timestamping rules # function output_specials( i, sp, alt_sp) { for (i = 1; i <= sp_cnt; i++) { sp = special[i] #change "../include/foo.h" first to "foo.h", then ultimately to "$(FOO_H)" alt_sp = sp; sub("^.+/", "", alt_sp) print "#", alt_sp, "timestamp" #output a `make' comment #- sub("\\.", "_", alt_sp); alt_sp = "$(" toupper(alt_sp) ")" #+ Some nawks don't have toupper(), so hardwire these instead. sub("config.h", "$(CONFIG_H)", alt_sp); sub("hack.h", "$(HACK_H)", alt_sp); format_dep(alt_sp, sp) #output the target print "\ttouch " alt_sp #output a build command alt_deps[sp] = alt_sp #alternate dependency for depend() } print "#" } # # write a target and its dependency list in pretty-printed format; # if target's primary source file has a path prefix, also write build command # function format_dep(target, source, n, i, list) { split("", done) #``for (x in done) delete done[x]'' printf("%s:", target); col = length(target) + 1 #- printf("\t"); col += 8 - (col % 8); #- if (col == 8) { printf("\t"); col += 8 } source = depend("", source, 0) n = split(source, list, " +") for (i = 2; i <= n; i++) { #(leading whitespace yields empty 1st element) if (col + length(list[i]) >= (i < n ? 78 : 80)) { printf(" \\\n\t\t"); col = 16 #make a backslash+newline split } else { printf(" "); col++; } printf("%s", list[i]); col += length(list[i]) } printf("\n") #terminate #write build command if first source entry has non-include path prefix source = list[2] if (source ~ /\// && substr(source, 1, 11) != "../include/") { if (source ~ /\.cpp$/ ) print "\t$(CXX) $(CXXFLAGS) -c " source else if (source ~ /\/gnome\//) # "../win/gnome/foo.c" print "\t$(CC) $(CFLAGS) $(GNOMEINC) -c " source else print "\t$(CC) $(CFLAGS) -c " source } } # # recursively add the dependencies for file `name' to string `inout' # (unless `skip', in which case we're only marking files as already done) # function depend(inout, name, skip, n, i, list) { if (!done[name]++) { if (name in alt_deps) { #some names have non-conventional dependencies if (!skip) inout = inout " " alt_deps[name] skip = 1 } else { #ordinary name if (!skip) inout = inout " " name } if (name in deps) { #- n = split(deps[name], list, " +") #- for (i = 2; i <= n; i++) #(leading whitespace yields empty 1st element) #- inout = depend(inout, list[i], skip) #+ At least one implementation of nawk handles the local array `list' wrong, #+ so the clumsier substitute code below is used as a workaround. list = deps[name]; sub("^ +", "", list) while (list) { match((list " "), " +"); i = RSTART; n = RLENGTH inout = depend(inout, substr(list, 1, i-1), skip) list = substr(list, i+n) } } } return inout } #depend.awk# nethack-3.6.0/sys/unix/hints/linux0000664000076400007660000000216312622350111016140 0ustar paxedpaxed# # NetHack 3.6 linux $NHDT-Date: 1432512814 2015/05/25 00:13:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # #-PRE # Linux hints file # This hints file provides a single-user tty build for Linux, specifically # for Ubuntu dapper. #PREFIX=/usr PREFIX=$(wildcard ~)/nh/install HACKDIR=$(PREFIX)/games/lib/$(GAME)dir SHELLDIR = $(PREFIX)/games INSTDIR=$(HACKDIR) VARDIR = $(HACKDIR) POSTINSTALL=cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; CFLAGS=-g -O -I../include -DNOTPARMDECL $(CFLAGS1) -DDLB CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" LINK=$(CC) # Only needed for GLIBC stack trace: LFLAGS=-rdynamic WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-lcurses CHOWN=true CHGRP=true VARDIRPERM = 0755 VARFILEPERM = 0600 GAMEPERM = 0755 nethack-3.6.0/sys/unix/hints/linux-chroot0000664000076400007660000000253312563263612017452 0ustar paxedpaxed# # NetHack 3.5 linux $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # NetHack 3.5 linux $Date: 2010/01/15 19:54:37 $ $Revision: 1.8 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # #-PRE # Linux hints file # This hints file provides a chrooted build for Linux, specifically # for Ubuntu dapper. # Does not copy required libraries or termcap files into the chroot. COMPILEREVISION?=1 # this is the chroot dir PREFIX=$(wildcard ~)/nh/install # this is the dir where NetHack is inside the chroot HACKDIR=/nh.$(shell date +%Y%m%d)-$(COMPILEREVISION) INSTDIR=$(PREFIX)$(HACKDIR) SHELLDIR=$(PREFIX)/games VARDIR=$(INSTDIR)/var POSTINSTALL=cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS=-g -O -I../include -DNOTPARMDECL $(CFLAGS1) -DDLB CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" CFLAGS+=-DVAR_PLAYGROUND=\"$(HACKDIR)/var\" LINK=$(CC) # Only needed for GLIBC stack trace: LFLAGS=-rdynamic WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-lcurses CHOWN=true CHGRP=true VARDIRPERM = 0755 VARFILEPERM = 0600 GAMEPERM = 0755 nethack-3.6.0/sys/unix/hints/linux-x110000664000076400007660000000245312563263612016566 0ustar paxedpaxed# # NetHack 3.6 linux-x11 $NHDT-Date: 1432512814 2015/05/25 00:13:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # #-PRE # Linux hints file # This hints file provides a single-user x11 build for Linux, specifically # for Ubuntu dapper. #PREFIX=/usr PREFIX=$(wildcard ~)/nh/install HACKDIR=$(PREFIX)/games/lib/$(GAME)dir SHELLDIR = $(PREFIX)/games INSTDIR=$(HACKDIR) VARDIR = $(HACKDIR) POSTINSTALL= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; (cd $(INSTDIR); mkfontdir); CFLAGS=-O -I../include -DNOTPARMDECL $(CFLAGS1) $(CFLAGS3) CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" CFLAGS1=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" CFLAGS3=-DX11_GRAPHICS -DDEFAULT_WINDOW_SYS=\"X11\" -DNOTTYGRAPHICS LINK=$(CC) WINSRC = $(WINX11SRC) WINOBJ = $(WINX11OBJ) WINLIB = $(WINX11LIB) VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm #WINTTYLIB=-lcurses CHOWN=true CHGRP=true VARDIRPERM = 0755 VARFILEPERM = 0600 GAMEPERM = 0755 # note: needs libxt-dev libxaw7-dev libx11-dev bdftopcf nethack-3.6.0/sys/unix/hints/macosx0000664000076400007660000001132712623162643016311 0ustar paxedpaxed# # NetHack 3.6 macosx $NHDT-Date: 1447844580 2015/11/18 11:03:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # #-PRE # Mac OS X (Darwin) hints file # This is for Mac OS X 10.4.10 (Darwin 8.10). If this doesn't work for some # other version of either Darwin or Mac OS X, make a new file for that OS, # don't change this one. And let us know about it. # Useful info: http://www.opensource.apple.com/darwinsource/index.html # This hints file can build several different types of installations. # Edit the next section to match the type of build you need. # 1. Which window system(s) should be included in this binary? WANT_WIN_TTY=1 #WANT_WIN_X11=1 #WANT_WIN_QT=1 # 1a. What is the default window system? WANT_DEFAULT=tty #WANT_DEFAULT=x11 #WANT_DEFAULT=qt # 1b. If you set WANT_WIN_QT, you need to # A) set QTDIR either here or in the environment to point to the Qt2 or Qt3 # library installation root. (Qt4 will not work; Qt3 does not presently # compile under Leopard (MacOSX 10.5) out-of-the-box.) # B) set XPMLIB to point to the Xpm library ifdef WANT_WIN_QT QTDIR=/Developer/Qt LIBXPM= -L/Developer/SDKs/MacOSX10.3.9.sdk/usr/X11R6/lib -lXpm endif # 2. Is this a build for a binary that will be shared among different users # or will it be private to you? # If it is shared: # - it will be owned by the user and group listed # - you MUST create the user using System Preferences (this will also # create the group if it is the same as the user) # - 'make install' must be run as "sudo make install" #WANT_SHARE_INSTALL=1 GAMEUID = games GAMEGRP = $(GAMEUID) #CC=gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN CC=gcc -Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN # # You shouldn't need to change anything below here. # # XXX -g vs -O should go here, -I../include goes in the makefile CFLAGS=-g -I../include CFLAGS+=-DNOCLIPPING -DNOMAIL -DNOTPARMDECL -DHACKDIR=\"$(HACKDIR)\" CFLAGS+= -DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" -DDLB ifdef WANT_WIN_TTY WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-lncurses else CFLAGS += -DNOTTYGRAPHICS endif ifdef WANT_WIN_X11 WINSRC += $(WINX11SRC) WINOBJ += $(WINX11OBJ) WINLIB += $(WINX11LIB) LFLAGS=-L/usr/X11R6/lib VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm POSTINSTALL= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; (cd $(INSTDIR); mkfontdir) CFLAGS += -DX11_GRAPHICS endif ifdef WANT_WIN_QT CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS CFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 LINK=g++ WINSRC += $(WINQTSRC) WINLIB += $(WINQTLIB) $(LIBXPM) WINLIB += -framework Carbon -framework QuickTime -lz -framework OpenGL WINLIB += -framework AGL ifdef WANT_WIN_X11 # prevent duplicate tile.o in WINOBJ WINOBJ = $(sort $(WINQTOBJ) $(WINX11OBJ)) ifdef WANT_WIN_TTY WINOBJ += $(WINTTYOBJ) endif else WINOBJ += $(WINQTOBJ) endif # XXX if /Developer/qt exists and QTDIR not set, use that ifndef QTDIR $(error QTDIR not defined in the environment or Makefile) endif # XXX make sure QTDIR points to something reasonable else LINK=$(CC) endif ifdef WANT_SHARE_INSTALL # NB: do NOT use $(wildcard ~$(GAMEUID)) since the user may not exist yet. PREFIX:=/Users/$(GAMEUID) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=chown CHGRP=chgrp # We run sgid so the game has access to both HACKDIR and user preferences. GAMEPERM = 02755 VARFILEPERM = 0664 VARDIRPERM = 0775 ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) # make sure we have group GAMEUID and group GAMEGRP PREINSTALL= . sys/unix/hints/macosx.sh user $(GAMEUID); . sys/unix/hints/macosx.sh group $(GAMEGRP); mkdir $(SHELLDIR); chown $(GAMEUID) $(SHELLDIR) POSTINSTALL= touch $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE else PREFIX:=$(wildcard ~) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=true CHGRP=true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 ifdef WANT_WIN_X11 # XXX install nethack.rc as ~/.nethackrc if no ~/.nethackrc exists endif endif # ~/Library/Preferences/NetHack Defaults # OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp # OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt # # Install.Qt mentions a patch for macos - it's not there (it seems to be in the Qt binary # package under the docs directory). nethack-3.6.0/sys/unix/hints/macosx.sh0000775000076400007660000001423112536476415016732 0ustar paxedpaxed#!/bin/sh # NetHack 3.6 macosx.sh $NHDT-Date: 1432512814 2015/05/25 00:13:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # # hints helper script for macosx # DO NOT invoke directly. # Works for 10.4 and 10.5. (The 10.5 support might work for 10.4 but keep # both versions in case we need to support earlier versions.) cmd=$1 case "x$cmd" in xuser) # fail unless user exists (good through 10.4) user=$2 gotuser=`niutil -readval . /users/$user name 0 2>/dev/null` [ -z $gotuser ] && (echo "User $user does not exist." exit 1; ) ;; #name: dummy1 #_writers_passwd: dummy1 #_writers_tim_password: dummy1 #_writers_picture: dummy1 #home: /Users/dummy1 #gid: 504 #picture: /Library/User Pictures/Animals/Dragonfly.tif #uid: 504 #hint: dummy1 #_writers_hint: dummy1 #sharedDir: #_shadow_passwd: #_writers_realname: dummy1 #shell: /bin/bash #passwd: ******** #authentication_authority: ;ShadowHash; #realname: dummyname1 #generateduid: F6D4991C-BDF5-481F-A407-D84C6A2D0E2A xgroup) # fail unless group exists (good through 10.4) group=$2 gotgrp=`niutil -readval . /groups/$group name 0 2>/dev/null` [ -z $gotgrp ] && ( echo "Group $group does not exist." exit 1 ) ;; #niutil -read . /groups/bin name 0 #name: bin #gid: 7 #passwd: * #generateduid: ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000007 #smb_sid: S-1-5-21-107 #realname: Binary xuser2) # fail unless user exists (required as of 10.5) user=$2 if( dscl localhost -read /Search/Users/$user 1>/dev/null 2>&1 ); then true; else echo "User $user does not exist."; exit 1; fi ;; xgroup2) # if group does not exist, create it (required as of 10.5) group=$2 [ -z $group ] && ( echo "No group specified." exit 1 ) if( dscl localhost -read /Search/Groups/$group 1>/dev/null 2>&1 ); then true; else echo "Group $group does not exist - creating."; dseditgroup -o create -r "Games Group" -s 3600 $group if( dscl localhost -read /Search/Groups/$group 1>/dev/null 2>&1 ); then true; else echo "Unable to create group $group." exit 1 fi fi ;; #% dscl localhost -read /Search/Groups/wheel # AppleMetaNodeLocation: /Local/Default # GeneratedUID: ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000 # GroupMembership: root # Password: * # PrimaryGroupID: 0 # RealName: # System Group # RecordName: wheel # RecordType: dsRecTypeStandard:Groups # SMBSID: S-1-5-21-100 xdescplist) SVSDOT=`util/makedefs --svs .` cat < IFPkgDescriptionDeleteWarning IFPkgDescriptionDescription NetHack $SVSDOT for the MacOS X Terminal IFPkgDescriptionTitle NetHack IFPkgDescriptionVersion $SVSDOT E_O_M ;; xinfoplist) SVSDOT=`util/makedefs --svs .` cat < CFBundleGetInfoString NetHack $SVSDOT for the MacOS X Terminal CFBundleIdentifier org.nethack.term CFBundleName NetHack CFBundleShortVersionString $SVSDOT IFMajorVersion 3 IFMinorVersion 3 IFPkgFlagAllowBackRev IFPkgFlagAuthorizationAction RootAuthorization IFPkgFlagDefaultLocation / IFPkgFlagInstallFat IFPkgFlagIsRequired IFPkgFlagOverwritePermissions IFPkgFlagRelocatable IFPkgFlagRestartAction NoRestart IFPkgFlagRootVolumeOnly IFPkgFlagUpdateInstalledLanguages IFPkgFlagUseUserMask IFPkgFormatVersion 0.10000000149011612 E_O_M ;; *) echo "Unknown command $cmd" exit 1 ;; esac # dscl localhost -read /Search/Users/games # dsAttrTypeNative:_writers_hint: games # dsAttrTypeNative:_writers_jpegphoto: games # dsAttrTypeNative:_writers_LinkedIdentity: games # dsAttrTypeNative:_writers_passwd: games # dsAttrTypeNative:_writers_picture: games # dsAttrTypeNative:_writers_realname: games # dsAttrTypeNative:_writers_UserCertificate: games # AppleMetaNodeLocation: /Local/Default # AuthenticationAuthority: ;ShadowHash; ;Kerberosv5;;games@LKDC:SHA1.3F695B215C78511043D9787CA51DE92E6494A021;LKDC:SHA1.3F695B215C78511043D9787CA51DE92E6494A021; # AuthenticationHint: games # GeneratedUID: A727EFB1-D6AA-4FE2-8524-0E154890E9A9 # NFSHomeDirectory: /Users/games # Password: ******** # Picture: # /Library/User Pictures/Flowers/Sunflower.tif # PrimaryGroupID: 20 # RealName: games # RecordName: games # RecordType: dsRecTypeStandard:Users # UniqueID: 505 # UserShell: /bin/bash # see also: http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/additionalfeatures/chapter_10_section_9.html # another mess: 10.4 creates a group for every user, 10.5 dumps you into staff. # so I think we need to explicitly create group games in both (if it doesn't # exist) and use owner bin (nope that fails since everything seems to be owned # by root. Do we want that? How about just creating user games as well?) # [Hermes:sys/unix/hints] keni% dscl localhost -read /Search/Users/games9 # DS Error: -14136 (eDSRecordNotFound) # [Hermes:sys/unix/hints] keni% dscl localhost -read /Search/Users/games9 >/dev/null # DS Error: -14136 (eDSRecordNotFound) # [Hermes:sys/unix/hints] keni% dscl localhost -read /Search/Users/games > /dev/null # status is good: 0 or 56 # file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/releasenotes/MacOSXServer/RN-DirectoryServices/index.html nethack-3.6.0/sys/unix/hints/macosx10.100000664000076400007660000003056212623253702016670 0ustar paxedpaxed# # NetHack 3.6 macosx10.11 $NHDT-Date: 1445622451 2015/10/23 17:47:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.0 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. # NetHack may be freely redistributed. See license for details. # #-PRE # Mac OS X (Darwin) hints file # This is for Mac OS X 10.10 or later. If this doesn't work for some other # version of Mac OS X, make a new file for that OS, don't change this one. # And let us know about it. # Useful info: http://www.opensource.apple.com/darwinsource/index.html # This hints file can build several different types of installations. # Edit the next section to match the type of build you need. # 1. Which window system(s) should be included in this binary? WANT_WIN_TTY=1 #WANT_WIN_X11=1 #WANT_WIN_QT=1 # 1a. What is the default window system? WANT_DEFAULT=tty #WANT_DEFAULT=x11 #WANT_DEFAULT=qt # 1b. If you set WANT_WIN_QT, you need to # A) set QTDIR either here or in the environment to point to the Qt2 or Qt3 # library installation root. (Qt4 will not work; Qt3 does not presently # compile under Leopard (MacOSX 10.5) out-of-the-box.) # B) set XPMLIB to point to the Xpm library ifdef WANT_WIN_QT QTDIR=/Developer/Qt LIBXPM= -L/opt/X11/lib -lXpm endif # WANT_WIN_QT # 2. Is this a build for a binary that will be shared among different users # or will it be private to you? # If it is shared: # - it will be owned by the user and group listed # - if the user does not exist, you MUST create it before installing # NetHack # - if the group does not exist, it will be created. # NB: if the group already exists and is being used for something # besides games, you probably want to specify a new group instead # NB: the group will be created locally; if your computer is centrally # administered this may not be what you (or your admin) want. # Consider a non-shared install (WANT_SHARE_INSTALL=0) instead. # - 'make install' must be run as "sudo make install" #WANT_SHARE_INSTALL=1 GAMEUID = $(USER) GAMEGRP = games # build to run in the source tree - primarily for development. Build with "make all" #WANT_SOURCE_INSTALL=1 CC=gcc # At the moment this is just for debugging, but in the future it could be # useful for other things. Requires SYSCF and an ANSI compiler. #WANT_WIN_CHAIN=1 # # You shouldn't need to change anything below here. # #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code # XXX -g vs -O should go here, -I../include goes in the makefile CFLAGS+=-g -I../include # older binaries use NOCLIPPING, but that disables SIGWINCH #CFLAGS+=-DNOCLIPPING CFLAGS+= -DNOMAIL -DNOTPARMDECL -DHACKDIR=\"$(HACKDIR)\" CFLAGS+= -DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" -DDLB CFLAGS+= -DGREPPATH=\"/usr/bin/grep\" ifdef WANT_WIN_CHAIN CFLAGS+= -DWINCHAIN HINTSRC=$(CHAINSRC) HINTOBJ=$(CHAINOBJ) endif ifdef WANT_WIN_TTY WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-lncurses else # !WANT_WIN_TTY CFLAGS += -DNOTTYGRAPHICS endif # !WANT_WIN_TTY ifdef WANT_WIN_X11 WINSRC += $(WINX11SRC) WINOBJ += $(WINX11OBJ) WINLIB += $(WINX11LIB) LFLAGS=-L/opt/X11/lib VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; (cd $(HACKDIR); mkfontdir); CFLAGS += -DX11_GRAPHICS -I/opt/X11/include endif # WANT_WIN_X11 ifdef WANT_WIN_QT CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS CFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 LINK=g++ WINSRC += $(WINQTSRC) WINLIB += $(WINQTLIB) $(LIBXPM) WINLIB += -framework Carbon -framework QuickTime -lz -framework OpenGL WINLIB += -framework AGL ifdef WANT_WIN_X11 # prevent duplicate tile.o in WINOBJ WINOBJ = $(sort $(WINQTOBJ) $(WINX11OBJ)) ifdef WANT_WIN_TTY WINOBJ += $(WINTTYOBJ) endif # WANT_WIN_TTY else # !WANT_WIN_X11 WINOBJ += $(WINQTOBJ) endif # !WANT_WIN_X11 # XXX if /Developer/qt exists and QTDIR not set, use that ifndef QTDIR $(error QTDIR not defined in the environment or Makefile) endif # QTDIR # XXX make sure QTDIR points to something reasonable else # !WANT_WIN_QT LINK=$(CC) endif # !WANT_WIN_QT ifdef WANT_SHARE_INSTALL # if $GAMEUID is root, we install into roughly proper Mac locations, otherwise # we install into ~/nethackdir ifeq ($(GAMEUID),root) PREFIX:=/Library/NetHack SHELLDIR=/usr/local/bin HACKDIR=$(PREFIX)/nethackdir CHOWN=chown CHGRP=chgrp # We run sgid so the game has access to both HACKDIR and user preferences. GAMEPERM = 02755 else # ! root PREFIX:=/Users/$(GAMEUID) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/Library/NetHack/nethackdir CHOWN=/usr/bin/true CHGRP=/usr/bin/true GAMEPERM = 0500 endif # ! root VARFILEPERM = 0664 VARDIRPERM = 0775 ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) # XXX it's nice we don't write over sysconf, but we've already erased it # make sure we have group GAMEUID and group GAMEGRP PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); . sys/unix/hints/macosx.sh group2 $(GAMEGRP); mkdir $(SHELLDIR); chown $(GAMEUID) $(SHELLDIR) POSTINSTALL+= cp -n sys/unix/sysconf $(HACKDIR)/sysconf; $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; chmod $(VARFILEPERM) $(HACKDIR)/sysconf; CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE else ifdef WANT_SOURCE_INSTALL PREFIX=$(abspath $(NHSROOT)) # suppress nethack.sh #SHELLDIR= HACKDIR=$(PREFIX)/playground CHOWN=/usr/bin/true CHGRP=/usr/bin/true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 # We can use "make all" to build the whole thing - but it misses some things: MOREALL=$(MAKE) install CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE else # !WANT_SOURCE_INSTALL PREFIX:=$(wildcard ~) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir CHOWN=/usr/bin/true CHGRP=/usr/bin/true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 ifdef WANT_WIN_X11 # install nethack.rc as ~/.nethackrc if no ~/.nethackrc exists PREINSTALL= cp -n win/X11/nethack.rc ~/.nethackrc endif # WANT_WIN_X11 POSTINSTALL+= cp -n sys/unix/sysconf $(HACKDIR)/sysconf; $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; chmod $(VARFILEPERM) $(HACKDIR)/sysconf; CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE endif # !WANT_SOURCE_INSTALL INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) # ~/Library/Preferences/NetHack Defaults # OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp # OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt # # Install.Qt mentions a patch for macos - it's not there (it seems to be in the Qt binary # package under the docs directory). #-POST ifdef MAKEFILE_TOP ### ### Packaging ### # Notes: # 1) The Apple developer utilities must be installed in the default location. # 2) Do a normal build before trying to package the game. # 3) This matches the 3.4.3 Term package, but there are some things that should # be changed. ifdef WANT_WIN_TTY DEVUTIL=/Developer/Applications/Utilities SVS=$(shell $(NHSROOT)/util/makedefs --svs) SVSDOT=$(shell $(NHSROOT)/util/makedefs --svs .) PKGROOT_UG = PKGROOT/$(PREFIX) PKGROOT_UGLN = PKGROOT/$(HACKDIR) PKGROOT_BIN = PKGROOT/$(SHELLDIR) build_tty_pkg: ifneq (,$(WANT_WIN_X11)$(WANT_WIN_QT)) -echo build_tty_pkg only works for a tty-only build exit 1 else rm -rf NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg $(MAKE) build_package_root rm -rf RESOURCES mkdir RESOURCES #enscript --language=rtf -o - < dat/license >RESOURCES/License.rtf sys/unix/hints/macosx.sh descplist > RESOURCES/Description.plist sys/unix/hints/macosx.sh infoplist > Info.plist mkdir PKGROOT/Applications #osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ # win/macosx/NetHackRecover.applescript #cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir osacompile -o PKGROOT/Applications/NetHackRecover.app \ win/macosx/NetHackRecover.applescript cp win/macosx/recover.pl $(PKGROOT_UGLN) osacompile -o PKGROOT/Applications/NetHackTerm.app \ win/macosx/NetHackTerm.applescript # XXX integrate into Makefile.doc (cd doc; cat Guidebook.mn | ../util/makedefs --grep --input - --output - \ | tbl tmac.n - | groff | pstopdf -i -o Guidebook.pdf) cp doc/Guidebook.pdf $(PKGROOT_UG)/doc/NetHackGuidebook.pdf osacompile -o PKGROOT/Applications/NetHackGuidebook.app \ win/macosx/NetHackGuidebook.applescript mkdir -p PKG pkgbuild --root PKGROOT --identifier org.nethack.term --scripts PKGSCRIPTS PKG/NH-Term.pkg productbuild --synthesize --product Info.plist --package PKG/NH-Term.pkg Distribution.xml productbuild --distribution Distribution.xml --resources RESOURCES --package-path PKG NetHack-$(SVS)-mac-Term.pkg hdiutil create -verbose -srcfolder NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg build_package_root: cd src/.. # make sure we are at TOP rm -rf PKGROOT mkdir -p $(PKGROOT_UG)/lib $(PKGROOT_BIN) $(PKGROOT_UG)/man/man6 $(PKGROOT_UG)/doc $(PKGROOT_UGLN) install -p src/nethack $(PKGROOT_BIN) # XXX should this be called nethackrecover? install -p util/recover $(PKGROOT_BIN) install -p doc/nethack.6 $(PKGROOT_UG)/man/man6 install -p doc/recover.6 $(PKGROOT_UG)/man/man6 install -p doc/Guidebook $(PKGROOT_UG)/doc install -p dat/nhdat $(PKGROOT_UGLN) sed 's/^GDBPATH/#GDBPATH/' sys/unix/sysconf | sed 's/^GREPPATH=\/bin\/grep/GREPPATH=\/usr\/bin\/grep/' | sed 's/^PANICTRACE_GDB=[12]/PANICTRACE_GDB=0/' > $(PKGROOT_UGLN)/sysconf cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN) # XXX these files should be somewhere else for good Mac form touch $(PKGROOT_UGLN)/perm $(PKGROOT_UGLN)/record $(PKGROOT_UGLN)/logfile $(PKGROOT_UGLN)/xlogfile mkdir $(PKGROOT_UGLN)/save # XXX what about a news file? mkdir -p PKGSCRIPTS echo '#!/bin/sh' > PKGSCRIPTS/postinstall echo $(CHOWN) -R $(GAMEUID) $(HACKDIR) >> PKGSCRIPTS/postinstall echo $(CHGRP) -R $(GAMEGRP) $(HACKDIR) >> PKGSCRIPTS/postinstall echo $(CHOWN) $(GAMEUID) $(SHELLDIR)/nethack >> PKGSCRIPTS/postinstall echo $(CHGRP) $(GAMEGRP) $(SHELLDIR)/nethack >> PKGSCRIPTS/postinstall echo $(CHOWN) $(GAMEUID) $(SHELLDIR)/recover >> PKGSCRIPTS/postinstall echo $(CHGRP) $(GAMEGRP) $(SHELLDIR)/recover >> PKGSCRIPTS/postinstall echo chmod $(VARDIRPERM) $(HACKDIR) >> PKGSCRIPTS/postinstall echo chmod $(VARDIRPERM) $(HACKDIR)/save >> PKGSCRIPTS/postinstall echo chmod $(FILEPERM) $(HACKDIR)/nhdat >> PKGSCRIPTS/postinstall echo chmod $(VARFILEPERM) $(HACKDIR)/perm >> PKGSCRIPTS/postinstall echo chmod $(VARFILEPERM) $(HACKDIR)/record >> PKGSCRIPTS/postinstall echo chmod $(VARFILEPERM) $(HACKDIR)/logfile >> PKGSCRIPTS/postinstall echo chmod $(VARFILEPERM) $(HACKDIR)/xlogfile >> PKGSCRIPTS/postinstall echo chmod $(VARFILEPERM) $(HACKDIR)/sysconf >> PKGSCRIPTS/postinstall echo chmod $(GAMEPERM) $(SHELLDIR)/nethack >> PKGSCRIPTS/postinstall echo chmod $(EXEPERM) $(SHELLDIR)/recover >> PKGSCRIPTS/postinstall chmod 0775 PKGSCRIPTS/postinstall endif # end of build_tty_pkg endif # WANT_WIN_TTY for packaging ifdef WANT_WIN_QT # XXX untested and incomplete (see below) build_qt_pkg: ifneq (,$(WANT_WIN_X11)$(WANT_WIN_TTY)) -echo build_qt_pkg only works for a qt-only build exit 1 else $(MAKE) build_package_root rm -rf NetHackQt mkdir -p NetHackQt/NetHackQt.app/nethackdir/save mkdir NetHackQt/Documentation cp doc/Guidebook.txt doc/nethack.txt doc/recover.txt NetHackQt/Documentation osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ win/macosx/NetHackRecover.applescript cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir mkdir -p NetHackQt/NetHackQt.app/Contents/Frameworks cp $(QTDIR)/libqt-mt.3.dylib NetHackQt/NetHackQt.app/Contents/Frameworks mkdir NetHackQt/NetHackQt.app/Contents/MacOS mv PKGROOT/nethack NetHackQt/NetHackQt.app/Contents/MacOS mv PKGROOT/lib/nethackdir NetHackQt/NetHackQt.app/nethackdir # XXX still missing: #NetHackQt/NetHackQt.app # /Contents # Info.plist # Resources/nethack.icns #NetHackQt/Documentation #NetHackQtRecover.txt #NetHack Defaults.txt #changes.patch XXX is this still needed? why isn't it part of the tree? # doesn't go here hdiutil create -verbose -srcfolder NetHackQt NetHack-$(SVS)-macosx-qt.dmg endif # end of build_qt_pkg endif # WANT_WIN_QT for packaging endif # MAKEFILE_TOP nethack-3.6.0/sys/unix/hints/macosx10.50000664000076400007660000002456712623162643016627 0ustar paxedpaxed# # NetHack 3.6 macosx10.5 $NHDT-Date: 1447844587 2015/11/18 11:03:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009. # NetHack may be freely redistributed. See license for details. # #-PRE # Mac OS X (Darwin) hints file # This is for Mac OS X 10.5.3 (Darwin 9.3). If this doesn't work for some # other version of either Darwin or Mac OS X, make a new file for that OS, # don't change this one. And let us know about it. # Useful info: http://www.opensource.apple.com/darwinsource/index.html # This hints file can build several different types of installations. # Edit the next section to match the type of build you need. # 1. Which window system(s) should be included in this binary? WANT_WIN_TTY=1 #WANT_WIN_X11=1 #WANT_WIN_QT=1 # 1a. What is the default window system? WANT_DEFAULT=tty #WANT_DEFAULT=x11 #WANT_DEFAULT=qt # 1b. If you set WANT_WIN_QT, you need to # A) set QTDIR either here or in the environment to point to the Qt2 or Qt3 # library installation root. (Qt4 will not work; Qt3 does not presently # compile under Leopard (MacOSX 10.5) out-of-the-box.) # B) set XPMLIB to point to the Xpm library ifdef WANT_WIN_QT QTDIR=/Developer/Qt LIBXPM= -L/Developer/SDKs/MacOSX10.3.9.sdk/usr/X11R6/lib -lXpm endif # WANT_WIN_QT # 2. Is this a build for a binary that will be shared among different users # or will it be private to you? # If it is shared: # - it will be owned by the user and group listed # - if the user does not exist, you MUST create it before installing # NetHack # - if the group does not exist, it will be created. # NB: if the group already exists and is being used for something # besides games, you probably want to specify a new group instead # NB: the group will be created locally; if your computer is centrally # administered this may not be what you (or your admin) want. # Consider a non-shared install (WANT_SHARE_INSTALL=0) instead. # - 'make install' must be run as "sudo make install" #WANT_SHARE_INSTALL=1 GAMEUID = $(USER) GAMEGRP = games # build to run in the source tree - primarily for development. Build with "make all" #WANT_SOURCE_INSTALL=1 #CC=gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN CC=gcc -Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic # # You shouldn't need to change anything below here. # # XXX -g vs -O should go here, -I../include goes in the makefile CFLAGS=-g -I../include CFLAGS+=-DNOCLIPPING -DNOMAIL -DNOTPARMDECL -DHACKDIR=\"$(HACKDIR)\" CFLAGS+= -DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" -DDLB CFLAGS+= -DGREPPATH=\"/usr/bin/grep\" ifdef WANT_WIN_TTY WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-lncurses else # !WANT_WIN_TTY CFLAGS += -DNOTTYGRAPHICS endif # !WANT_WIN_TTY ifdef WANT_WIN_X11 WINSRC += $(WINX11SRC) WINOBJ += $(WINX11OBJ) WINLIB += $(WINX11LIB) LFLAGS=-L/usr/X11R6/lib VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; (cd $(INSTDIR); mkfontdir); CFLAGS += -DX11_GRAPHICS endif # WANT_WIN_X11 ifdef WANT_WIN_QT CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS CFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 LINK=g++ WINSRC += $(WINQTSRC) WINLIB += $(WINQTLIB) $(LIBXPM) WINLIB += -framework Carbon -framework QuickTime -lz -framework OpenGL WINLIB += -framework AGL ifdef WANT_WIN_X11 # prevent duplicate tile.o in WINOBJ WINOBJ = $(sort $(WINQTOBJ) $(WINX11OBJ)) ifdef WANT_WIN_TTY WINOBJ += $(WINTTYOBJ) endif # WANT_WIN_TTY else # !WANT_WIN_X11 WINOBJ += $(WINQTOBJ) endif # !WANT_WIN_X11 # XXX if /Developer/qt exists and QTDIR not set, use that ifndef QTDIR $(error QTDIR not defined in the environment or Makefile) endif # QTDIR # XXX make sure QTDIR points to something reasonable else # !WANT_WIN_QT LINK=$(CC) endif # !WANT_WIN_QT ifdef WANT_SHARE_INSTALL # if $GAMEUID is root, we install into roughly proper Mac locations, otherwise # we install into ~/nethackdir ifeq ($(GAMEUID),root) PREFIX:=/Library/NetHack SHELLDIR=/usr/local/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=chown CHGRP=chgrp # We run sgid so the game has access to both HACKDIR and user preferences. GAMEPERM = 02755 else # ! root PREFIX:=/Users/$(GAMEUID) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=touch CHGRP=touch GAMEPERM = 0500 endif # ! root VARFILEPERM = 0664 VARDIRPERM = 0775 ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) # XXX it's nice we don't write over sysconf, but we've already erased it # make sure we have group GAMEUID and group GAMEGRP PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); . sys/unix/hints/macosx.sh group2 $(GAMEGRP); mkdir $(SHELLDIR); chown $(GAMEUID) $(SHELLDIR) POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE else ifdef WANT_SOURCE_INSTALL PREFIX=$(abspath $(NHSROOT)) # suppress nethack.sh" #SHELLDIR= HACKDIR=$(PREFIX)/playground INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=touch CHGRP=touch GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 # We can use "make all" to build the whole thing - but it misses some things: MOREALL=$(MAKE) install else # !WANT_SOURCE_INSTALL PREFIX:=$(wildcard ~) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=true CHGRP=true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 ifdef WANT_WIN_X11 # install nethack.rc as ~/.nethackrc if no ~/.nethackrc exists PREINSTALL= cp -n win/X11/nethack.rc ~/.nethackrc endif # WANT_WIN_X11 POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE endif # !WANT_SOURCE_INSTALL # ~/Library/Preferences/NetHack Defaults # OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp # OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt # # Install.Qt mentions a patch for macos - it's not there (it seems to be in the Qt binary # package under the docs directory). #-POST ifdef MAKEFILE_TOP ### ### Packaging ### # Notes: # 1) The Apple developer utilities must be installed in the default location. # 2) Do a normal build before trying to package the game. # 3) This matches the 3.4.3 Term package, but there are some things that should # be changed. ifdef WANT_WIN_TTY DEVUTIL=/Developer/Applications/Utilities PKGR=$(DEVUTIL)/PackageMaker.app/Contents/MacOS/PackageMaker SVS=$(shell $(NHSROOT)/util/makedefs --svs) SVSDOT=$(shell $(NHSROOT)/util/makedefs --svs .) PKGROOT_UG = PKGROOT/usr/games PKGROOT_UGLN = PKGROOT/usr/games/lib/nethackdir build_tty_pkg: ifneq (,$(WANT_WIN_X11)$(WANT_WIN_QT)) -echo build_tty_pkg only works for a tty-only build exit 1 else rm -rf NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg $(MAKE) build_package_root rm -rf RESOURCES mkdir RESOURCES #enscript --language=rtf -o - < dat/license >RESOURCES/License.rtf sys/unix/hints/macosx.sh descplist > RESOURCES/Description.plist sys/unix/hints/macosx.sh infoplist > Info.plist mkdir PKGROOT/Applications #osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ # win/macosx/NetHackRecover.applescript #cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir osacompile -o PKGROOT/Applications/NetHackRecover.app \ win/macosx/NetHackRecover.applescript cp win/macosx/recover.pl $(PKGROOT_UGLN) osacompile -o PKGROOT/Applications/NetHackTerm.app \ win/macosx/NetHackTerm.applescript # XXX integrate into Makefile.doc (cd doc; cat Guidebook.mn | ../util/makedefs --grep --input - --output - \ | tbl tmac.n - | groff |ps2pdf - > Guidebook.pdf) cp doc/Guidebook.pdf $(PKGROOT_UG)/doc/NetHackGuidebook.pdf osacompile -o PKGROOT/Applications/NetHackGuidebook.app \ win/macosx/NetHackGuidebook.applescript $(PKGR) --root PKGROOT --info Info.plist -e RESOURCES -v -o NetHack-$(SVS)-mac-Term.pkg hdiutil create -verbose -srcfolder NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg build_package_root: cd src/.. # make sure we are at TOP rm -rf PKGROOT mkdir -p $(PKGROOT_UG)/lib $(PKGROOT_UG)/bin $(PKGROOT_UG)/man/man6 $(PKGROOT_UG)/doc $(PKGROOT_UGLN) install -p src/nethack $(PKGROOT_UG)/bin # XXX should this be called nethackrecover? install -p util/recover $(PKGROOT_UG)/bin install -p doc/nethack.6 $(PKGROOT_UG)/man/man6 install -p doc/recover.6 $(PKGROOT_UG)/man/man6 install -p doc/Guidebook $(PKGROOT_UG)/doc install -p dat/nhdat $(PKGROOT_UGLN) cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN) # XXX these files should be somewhere else for good Mac form touch $(PKGROOT_UGLN)/perm $(PKGROOT_UGLN)/record $(PKGROOT_UGLN)/logfile # XXX may need postinstall script to get perms right for sgid, etc. mkdir $(PKGROOT_UGLN)/save # XXX what about a news file? endif # end of build_tty_pkg endif # WANT_WIN_TTY for packaging ifdef WANT_WIN_QT # XXX untested and incomplete (see below) build_qt_pkg: ifneq (,$(WANT_WIN_X11)$(WANT_WIN_TTY)) -echo build_qt_pkg only works for a qt-only build exit 1 else $(MAKE) build_package_root rm -rf NetHackQt mkdir -p NetHackQt/NetHackQt.app/nethackdir/save mkdir NetHackQt/Documentation cp doc/Guidebook.txt doc/nethack.txt doc/recover.txt NetHackQt/Documentation osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ win/macosx/NetHackRecover.applescript cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir mkdir -p NetHackQt/NetHackQt.app/Contents/Frameworks cp $(QTDIR)/libqt-mt.3.dylib NetHackQt/NetHackQt.app/Contents/Frameworks mkdir NetHackQt/NetHackQt.app/Contents/MacOS mv PKGROOT/nethack NetHackQt/NetHackQt.app/Contents/MacOS mv PKGROOT/lib/nethackdir NetHackQt/NetHackQt.app/nethackdir # XXX still missing: #NetHackQt/NetHackQt.app # /Contents # Info.plist # Resources/nethack.icns #NetHackQt/Documentation #NetHackQtRecover.txt #NetHack Defaults.txt #changes.patch XXX is this still needed? why isn't it part of the tree? # doesn't go here hdiutil create -verbose -srcfolder NetHackQt NetHack-$(SVS)-macosx-qt.dmg endif # end of build_qt_pkg endif # WANT_WIN_QT for packaging endif # MAKEFILE_TOP nethack-3.6.0/sys/unix/hints/macosx10.70000664000076400007660000002561612623162643016625 0ustar paxedpaxed# # NetHack 3.6 macosx10.7 $NHDT-Date: 1447844589 2015/11/18 11:03:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.31 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009. # NetHack may be freely redistributed. See license for details. # #-PRE # Mac OS X (Darwin) hints file # This is for Mac OS X 10.7.2. If this doesn't work for some other version # of Mac OS X, make a new file for that OS, don't change this one. And # let us know about it. # Useful info: http://www.opensource.apple.com/darwinsource/index.html # This hints file can build several different types of installations. # Edit the next section to match the type of build you need. # 1. Which window system(s) should be included in this binary? WANT_WIN_TTY=1 #WANT_WIN_X11=1 #WANT_WIN_QT=1 # 1a. What is the default window system? WANT_DEFAULT=tty #WANT_DEFAULT=x11 #WANT_DEFAULT=qt # 1b. If you set WANT_WIN_QT, you need to # A) set QTDIR either here or in the environment to point to the Qt2 or Qt3 # library installation root. (Qt4 will not work; Qt3 does not presently # compile under Leopard (MacOSX 10.5) out-of-the-box.) # B) set XPMLIB to point to the Xpm library ifdef WANT_WIN_QT QTDIR=/Developer/Qt LIBXPM= -L/Developer/SDKs/MacOSX10.3.9.sdk/usr/X11R6/lib -lXpm endif # WANT_WIN_QT # 2. Is this a build for a binary that will be shared among different users # or will it be private to you? # If it is shared: # - it will be owned by the user and group listed # - if the user does not exist, you MUST create it before installing # NetHack # - if the group does not exist, it will be created. # NB: if the group already exists and is being used for something # besides games, you probably want to specify a new group instead # NB: the group will be created locally; if your computer is centrally # administered this may not be what you (or your admin) want. # Consider a non-shared install (WANT_SHARE_INSTALL=0) instead. # - 'make install' must be run as "sudo make install" #WANT_SHARE_INSTALL=1 GAMEUID = $(USER) GAMEGRP = games # build to run in the source tree - primarily for development. Build with "make all" #WANT_SOURCE_INSTALL=1 CC=gcc # At the moment this is just for debugging, but in the future it could be # useful for other things. Requires SYSCF and an ANSI compiler. #WANT_WIN_CHAIN=1 # # You shouldn't need to change anything below here. # #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code # XXX -g vs -O should go here, -I../include goes in the makefile CFLAGS+=-g -I../include # older binaries use NOCLIPPING, but that disables SIGWINCH #CFLAGS+=-DNOCLIPPING CFLAGS+= -DNOMAIL -DNOTPARMDECL -DHACKDIR=\"$(HACKDIR)\" CFLAGS+= -DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" -DDLB CFLAGS+= -DGREPPATH=\"/usr/bin/grep\" ifdef WANT_WIN_CHAIN CFLAGS+= -DWINCHAIN HINTSRC=$(CHAINSRC) HINTOBJ=$(CHAINOBJ) endif ifdef WANT_WIN_TTY WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-lncurses else # !WANT_WIN_TTY CFLAGS += -DNOTTYGRAPHICS endif # !WANT_WIN_TTY ifdef WANT_WIN_X11 WINSRC += $(WINX11SRC) WINOBJ += $(WINX11OBJ) WINLIB += $(WINX11LIB) LFLAGS=-L/usr/X11R6/lib VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; (cd $(INSTDIR); mkfontdir); CFLAGS += -DX11_GRAPHICS endif # WANT_WIN_X11 ifdef WANT_WIN_QT CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS CFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 LINK=g++ WINSRC += $(WINQTSRC) WINLIB += $(WINQTLIB) $(LIBXPM) WINLIB += -framework Carbon -framework QuickTime -lz -framework OpenGL WINLIB += -framework AGL ifdef WANT_WIN_X11 # prevent duplicate tile.o in WINOBJ WINOBJ = $(sort $(WINQTOBJ) $(WINX11OBJ)) ifdef WANT_WIN_TTY WINOBJ += $(WINTTYOBJ) endif # WANT_WIN_TTY else # !WANT_WIN_X11 WINOBJ += $(WINQTOBJ) endif # !WANT_WIN_X11 # XXX if /Developer/qt exists and QTDIR not set, use that ifndef QTDIR $(error QTDIR not defined in the environment or Makefile) endif # QTDIR # XXX make sure QTDIR points to something reasonable else # !WANT_WIN_QT LINK=$(CC) endif # !WANT_WIN_QT ifdef WANT_SHARE_INSTALL # if $GAMEUID is root, we install into roughly proper Mac locations, otherwise # we install into ~/nethackdir ifeq ($(GAMEUID),root) PREFIX:=/Library/NetHack SHELLDIR=/usr/local/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=chown CHGRP=chgrp # We run sgid so the game has access to both HACKDIR and user preferences. GAMEPERM = 02755 else # ! root PREFIX:=/Users/$(GAMEUID) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=/usr/bin/true CHGRP=/usr/bin/true GAMEPERM = 0500 endif # ! root VARFILEPERM = 0664 VARDIRPERM = 0775 ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) # XXX it's nice we don't write over sysconf, but we've already erased it # make sure we have group GAMEUID and group GAMEGRP PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); . sys/unix/hints/macosx.sh group2 $(GAMEGRP); mkdir $(SHELLDIR); chown $(GAMEUID) $(SHELLDIR) POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE else ifdef WANT_SOURCE_INSTALL PREFIX=$(abspath $(NHSROOT)) # suppress nethack.sh #SHELLDIR= HACKDIR=$(PREFIX)/playground INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=/usr/bin/true CHGRP=/usr/bin/true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 # We can use "make all" to build the whole thing - but it misses some things: MOREALL=$(MAKE) install CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE else # !WANT_SOURCE_INSTALL PREFIX:=$(wildcard ~) SHELLDIR=$(PREFIX)/bin HACKDIR=$(PREFIX)/nethackdir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) CHOWN=/usr/bin/true CHGRP=/usr/bin/true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 ifdef WANT_WIN_X11 # install nethack.rc as ~/.nethackrc if no ~/.nethackrc exists PREINSTALL= cp -n win/X11/nethack.rc ~/.nethackrc endif # WANT_WIN_X11 POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE endif # !WANT_SOURCE_INSTALL # ~/Library/Preferences/NetHack Defaults # OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp # OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt # # Install.Qt mentions a patch for macos - it's not there (it seems to be in the Qt binary # package under the docs directory). #-POST ifdef MAKEFILE_TOP ### ### Packaging ### # Notes: # 1) The Apple developer utilities must be installed in the default location. # 2) Do a normal build before trying to package the game. # 3) This matches the 3.4.3 Term package, but there are some things that should # be changed. ifdef WANT_WIN_TTY DEVUTIL=/Developer/Applications/Utilities PKGR=$(DEVUTIL)/PackageMaker.app/Contents/MacOS/PackageMaker SVS=$(shell $(NHSROOT)/util/makedefs --svs) SVSDOT=$(shell $(NHSROOT)/util/makedefs --svs .) PKGROOT_UG = PKGROOT/usr/games PKGROOT_UGLN = PKGROOT/usr/games/lib/nethackdir build_tty_pkg: ifneq (,$(WANT_WIN_X11)$(WANT_WIN_QT)) -echo build_tty_pkg only works for a tty-only build exit 1 else rm -rf NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg $(MAKE) build_package_root rm -rf RESOURCES mkdir RESOURCES #enscript --language=rtf -o - < dat/license >RESOURCES/License.rtf sys/unix/hints/macosx.sh descplist > RESOURCES/Description.plist sys/unix/hints/macosx.sh infoplist > Info.plist mkdir PKGROOT/Applications #osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ # win/macosx/NetHackRecover.applescript #cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir osacompile -o PKGROOT/Applications/NetHackRecover.app \ win/macosx/NetHackRecover.applescript cp win/macosx/recover.pl $(PKGROOT_UGLN) osacompile -o PKGROOT/Applications/NetHackTerm.app \ win/macosx/NetHackTerm.applescript # XXX integrate into Makefile.doc (cd doc; cat Guidebook.mn | ../util/makedefs --grep --input - --output - \ | tbl tmac.n - | groff |ps2pdf - > Guidebook.pdf) cp doc/Guidebook.pdf $(PKGROOT_UG)/doc/NetHackGuidebook.pdf osacompile -o PKGROOT/Applications/NetHackGuidebook.app \ win/macosx/NetHackGuidebook.applescript $(PKGR) --root PKGROOT --info Info.plist -e RESOURCES -v -o NetHack-$(SVS)-mac-Term.pkg hdiutil create -verbose -srcfolder NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg build_package_root: cd src/.. # make sure we are at TOP rm -rf PKGROOT mkdir -p $(PKGROOT_UG)/lib $(PKGROOT_UG)/bin $(PKGROOT_UG)/man/man6 $(PKGROOT_UG)/doc $(PKGROOT_UGLN) install -p src/nethack $(PKGROOT_UG)/bin # XXX should this be called nethackrecover? install -p util/recover $(PKGROOT_UG)/bin install -p doc/nethack.6 $(PKGROOT_UG)/man/man6 install -p doc/recover.6 $(PKGROOT_UG)/man/man6 install -p doc/Guidebook $(PKGROOT_UG)/doc install -p dat/nhdat $(PKGROOT_UGLN) cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN) # XXX these files should be somewhere else for good Mac form touch $(PKGROOT_UGLN)/perm $(PKGROOT_UGLN)/record $(PKGROOT_UGLN)/logfile # XXX may need postinstall script to get perms right for sgid, etc. mkdir $(PKGROOT_UGLN)/save # XXX what about a news file? endif # end of build_tty_pkg endif # WANT_WIN_TTY for packaging ifdef WANT_WIN_QT # XXX untested and incomplete (see below) build_qt_pkg: ifneq (,$(WANT_WIN_X11)$(WANT_WIN_TTY)) -echo build_qt_pkg only works for a qt-only build exit 1 else $(MAKE) build_package_root rm -rf NetHackQt mkdir -p NetHackQt/NetHackQt.app/nethackdir/save mkdir NetHackQt/Documentation cp doc/Guidebook.txt doc/nethack.txt doc/recover.txt NetHackQt/Documentation osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ win/macosx/NetHackRecover.applescript cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir mkdir -p NetHackQt/NetHackQt.app/Contents/Frameworks cp $(QTDIR)/libqt-mt.3.dylib NetHackQt/NetHackQt.app/Contents/Frameworks mkdir NetHackQt/NetHackQt.app/Contents/MacOS mv PKGROOT/nethack NetHackQt/NetHackQt.app/Contents/MacOS mv PKGROOT/lib/nethackdir NetHackQt/NetHackQt.app/nethackdir # XXX still missing: #NetHackQt/NetHackQt.app # /Contents # Info.plist # Resources/nethack.icns #NetHackQt/Documentation #NetHackQtRecover.txt #NetHack Defaults.txt #changes.patch XXX is this still needed? why isn't it part of the tree? # doesn't go here hdiutil create -verbose -srcfolder NetHackQt NetHack-$(SVS)-macosx-qt.dmg endif # end of build_qt_pkg endif # WANT_WIN_QT for packaging endif # MAKEFILE_TOP nethack-3.6.0/sys/unix/hints/unix0000664000076400007660000000142012563263612015774 0ustar paxedpaxed# # NetHack 3.6 unix $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # #-PRE # unix hints file # This hints file provides the legacy configuration that NetHack has shipped # with historically - this means you will most likely need to hand edit .h # and Makefiles. PREFIX=/usr HACKDIR=$(PREFIX)/games/lib/$(GAME)dir INSTDIR=$(HACKDIR) VARDIR=$(HACKDIR) SHELLDIR=$(PREFIX)/games CFLAGS=-O -I../include LINK=$(CC) WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) WINLIB = $(WINTTYLIB) WINTTYLIB=-ltermlib CHOWN=chown CHGRP=chgrp GAMEUID = games GAMEGRP = bin GAMEPERM = 04755 VARFILEPERM = 0644 VARDIRPERM = 0755 nethack-3.6.0/sys/unix/mkmkfile.sh0000775000076400007660000000233212536476415016111 0ustar paxedpaxed#!/bin/sh # NetHack 3.6 mkmkfile.sh $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # build one makefile # args are: # $1 basefile # $2 basefile tag # $3 install path # $4 hints file (path) # $5 hints file (as given by user) echo "#" > $3 echo "# This file is generated automatically. Do not edit." >> $3 echo "# Your changes will be lost. See sys/unix/NewInstall.unx." >> $3 echo "# Identify this file:" >> $3 echo "MAKEFILE_$2=1" >> $3 echo "" >> $3 echo "###" >> $3 echo "### Start $5 PRE" >> $3 echo "###" >> $3 awk '/^#-PRE/,/^#-POST/{ \ if(index($0, "#-PRE") == 1) print "# (new segment at source line",NR,")"; \ if(index($0, "#-P") != 1) print}' $4 >> $3 echo "### End $5 PRE" >> $3 echo "" >> $3 echo "###" >> $3 echo "### Start $1" >> $3 echo "###" >> $3 cat $1 >> $3 echo "### End $1" >> $3 echo "" >> $3 echo "###" >> $3 echo "### Start $5 POST" >> $3 echo "###" >> $3 awk '/^#-POST/,/^#-PRE/{ \ if(index($0, "#-POST") == 1) print "# (new segment at source line",NR,")"; \ if(index($0, "#-P") != 1) print}' $4 >> $3 echo "### End $5 POST" >> $3 nethack-3.6.0/sys/unix/nethack.sh0000775000076400007660000000331112536476415015725 0ustar paxedpaxed#!/bin/sh # NetHack 3.6 nethack.sh $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ HACKDIR=/usr/games/lib/nethackdir export HACKDIR HACK=$HACKDIR/nethack # NB: MAXNROFPLAYERS is deprecated in favor of MAXPLAYERS in SYSCF. MAXNROFPLAYERS=4 # Since Nethack.ad is installed in HACKDIR, add it to XUSERFILESEARCHPATH case "x$XUSERFILESEARCHPATH" in x) XUSERFILESEARCHPATH="$HACKDIR/%N.ad" ;; *) XUSERFILESEARCHPATH="$XUSERFILESEARCHPATH:$HACKDIR/%N.ad" ;; esac export XUSERFILESEARCHPATH # Get font dir added, but only once (and only if there's an xset to be found). test -n "$DISPLAY" -a -e $HACKDIR/fonts.dir && xset p >/dev/null 2>&1 && ( xset fp- $HACKDIR >/dev/null 2>&1; xset fp+ $HACKDIR ) # see if we can find the full path name of PAGER, so help files work properly # assume that if someone sets up a special variable (HACKPAGER) for NetHack, # it will already be in a form acceptable to NetHack # ideas from brian@radio.astro.utoronto.ca if test \( "xxx$PAGER" != xxx \) -a \( "xxx$HACKPAGER" = xxx \) then HACKPAGER=$PAGER # use only the first word of the pager variable # this prevents problems when looking for file names with trailing # options, but also makes the options unavailable for later use from # NetHack for i in $HACKPAGER do HACKPAGER=$i break done if test ! -f $HACKPAGER then IFS=: for i in $PATH do if test -f $i/$HACKPAGER then HACKPAGER=$i/$HACKPAGER export HACKPAGER break fi done IFS=' ' fi if test ! -f $HACKPAGER then echo Cannot find $PAGER -- unsetting PAGER. unset HACKPAGER unset PAGER fi fi cd $HACKDIR case $1 in -s*) exec $HACK "$@" ;; *) exec $HACK "$@" $MAXNROFPLAYERS ;; esac nethack-3.6.0/sys/unix/setup.sh0000775000076400007660000000210612536476415015451 0ustar paxedpaxed#!/bin/sh # NetHack 3.6 setup.sh $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # # Build and install makefiles. # # Argument is the hints file to use (or no argument for traditional setup). # e.g.: # sh setup.sh # or # sh setup.sh hints/macosx10.5 (from sys/unix) # or # sh setup.sh sys/unix/hints/macosx10.5 (from top) # Were we started from the top level? Cope. prefix=. if [ -f sys/unix/Makefile.top ]; then cd sys/unix; prefix=../..; fi case "x$1" in x) hints=/dev/null hfile=/dev/null ;; *) hints=$prefix/$1 hfile=$1 ;; esac /bin/sh ./mkmkfile.sh Makefile.top TOP ../../Makefile $hints $hfile /bin/sh ./mkmkfile.sh Makefile.dat DAT ../../dat/Makefile $hints $hfile /bin/sh ./mkmkfile.sh Makefile.doc DOC ../../doc/Makefile $hints $hfile /bin/sh ./mkmkfile.sh Makefile.src SRC ../../src/Makefile $hints $hfile /bin/sh ./mkmkfile.sh Makefile.utl UTL ../../util/Makefile $hints $hfile nethack-3.6.0/sys/unix/snd86unx.shr0000664000076400007660000007044712467321052016167 0ustar paxedpaxed# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # READ.ME # install.bsd # spkr.7 # Makefile # spkr.c # spkr.h # interp.c # Files # Install # Master # Name # Node # Remove # Size # System # playtest # echo x - READ.ME sed 's/^X//' >READ.ME << 'END-of-READ.ME' X Console Speaker Driver Package (v1.1) X X by Eric S. Raymond (esr@snark.thyrsus.com) X XThis package gives 80386 machines running SVr3.2 or later the ability to play Xtunes on the console speaker. It has been extended to 386BSD (and possibly XBSDI) by Andrew A. Chernov, and to SCO UNIX 3.2.4 (and possibly other VPIX Xsystems) by Andreas Arens. X XThe following files are contained in the kit: X XDocumentation and examples: XREAD.ME -- this file Xspeaker.7 -- man page for the driver Xplaytest -- test script exercising familiar tunes X XInstallable driver kit parts, for SVr3.2 or later: XFiles -- list of driver package file locations XInstall -- installation script for driver kit XMaster -- mdevice entry for speaker driver XName -- name entry foe speaker driver XNode -- /dev node specification file XRemove -- Driver removal script XSize -- installation size data XSystem -- sdevice entry for speaker driver X XDriver source code, for SVr3.2 or later and 386BSD: XMakefile -- Makefile for driver code Xspkr.c -- the driver source Xspeaker.h -- ioctl interface file X XCommon source code: Xinterp.c -- play string interpretation code X XFor SVr3.2 or later, simply type `make' and wait. Then type ./Install Xand follow its instructions. You will have to install the man pages by hand. XBe aware that the speaker.7 man page uses tbl(1) constructs. X XFor 386BSD, follow the installation instructions in install.bsd. X XFor SCO UNIX 3.2.4, no new kernel drivers are needed, and you need only Xcopy interp.c to your src directory and proceed with making NetHack, with XVPIX_MUSIC set in unixconf.h. X XInteresting tunes mailed to the author will be periodically posted in batches Xand added to the test script for future versions. X X Revision notes X X1.1 -- fixed minor bug in M[LSN] interpretation, added octave-tracking. X Tweaked the playtest examples. END-of-READ.ME echo x - install.bsd sed 's/^X//' >install.bsd << 'END-of-install.bsd' XCopy spkr.c and interp.c to /sys/i386/isa XCopy spkr.h to /sys/sys X X----------------------------------------------------------------------------- X XFile /sys/i386/conf/YOUR_MACHINE_NAME Xadd following line: X Xpseudo-device speaker X X----------------------------------------------------------------------------- X XFile /sys/i386/conf/files.i386 Xadd following line: X Xi386/isa/spkr.c optional speaker X X----------------------------------------------------------------------------- X XFile /sys/i386/i386/conf.c X[major number 20 (hex) is registered for spkr driver, don't change it] Xadd following code: X X#include "speaker.h" X#if NSPEAKER > 0 Xint spkropen(),spkrclose(),spkrwrite(),spkrioctl(); X#else X#define spkropen enxio X#define spkrclose enxio X#define spkrwrite enxio X#define spkrioctl enxio X#endif X ... X Xstruct cdevsw cdevsw[] = X{ X ... X X { spkropen, spkrclose, enxio, spkrwrite, /*20*/ X spkrioctl, enxio, enxio, NULL, X enxio, enxio, enxio }, X ... X X----------------------------------------------------------------------------- X XMake corresponding device: X X mknod /dev/speaker c 32 0 X X[major number 32 (20 hex) is registered for spkr driver, don't change it] X X----------------------------------------------------------------------------- X XGo to /sys/i386/conf and type X config YOUR_MACHINE_NAME Xthen go to /sys/compile/YOUR_MACHINE_NAME and type X make depend X make X END-of-install.bsd echo x - spkr.7 sed 's/^X//' >spkr.7 << 'END-of-spkr.7' X.TH SPKR 7 X.SH NAME Xspkr \- console speaker device driver X.SH DESCRIPTION XThe speaker device driver allows applications to control the PC console Xspeaker on an IBM-PC-compatible machine running UNIX. X.PP XOnly one process may have this device open at any given time; open() and Xclose() are used to lock and relinquish it. An attempt to open() when Xanother process has the device locked will return -1 with an EBUSY error Xindication. Writes to the device are interpreted as 'play strings' in a Xsimple ASCII melody notation. An ioctl() for tone generation at arbitrary Xfrequencies is also supported. X.PP XSound-generation does \fInot\fR monopolize the processor; in fact, the driver Xspends most of its time sleeping while the PC hardware is emitting Xtones. Other processes may emit beeps while the driver is running. X.PP XApplications may call ioctl() on a speaker file descriptor to control the Xspeaker driver directly; definitions for the ioctl() interface are in Xsys/spkr.h. The tone_t structure used in these calls has two fields, Xspecifying a frequency (in hz) and a duration (in 1/100ths of a second). XA frequency of zero is interpreted as a rest. X.PP XAt present there are two such ioctls. SPKRTONE accepts a pointer to a Xsingle tone structure as third argument and plays it. SPKRTUNE accepts a Xpointer to the first of an array of tone structures and plays them in Xcontinuous sequence; this array must be terminated by a final member with Xa zero duration. X.PP XThe play-string language is modelled on the PLAY statement conventions of XIBM BASIC 2.0. The MB, MF and X primitives of PLAY are not useful in a UNIX Xenvironment and are omitted. The `octave-tracking' feature is also new. X.PP XThere are 84 accessible notes numbered 1-83 in 7 octaves, each running from XC to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts Xwith middle C. By default, the play function emits half-second notes with the Xlast 1/16th second being `rest time'. X.PP XPlay strings are interpreted left to right as a series of play command groups; Xletter case is ignored. Play command groups are as follows: X.PP XCDEFGAB -- letters A through G cause the corresponding note to be played in the Xcurrent octave. A note letter may optionally be followed by an \fIaccidental Xsign\fR, one of # + or -; the first two of these cause it to be sharped one Xhalf-tone, the last causes it to be flatted one half-tone. It may also be Xfollowed by a time value number and by sustain dots (see below). Time values Xare interpreted as for the L command below;. X.PP XO -- if is numeric, this sets the current octave. may also be one Xof 'L' or 'N' to enable or disable octave-tracking (it is disabled by default). XWhen octave-tracking is on, interpretation of a pair of letter notes will Xchange octaves if necessary in order to make the smallest possible jump between Xnotes. Thus "olbc" will be played as "olb>c", and "olcb" as "olc, < and O[0123456]. X.PP X> -- bump the current octave up one. X.PP X< -- drop the current octave down one. X.PP XN -- play note n, n being 1 to 84 or 0 for a rest of current time value. XMay be followedv by sustain dots. X.PP XL -- sets the current time value for notes. The default is L4, quarter Xnotes. The lowest possible value is 1; values up to 64 are accepted. L1 sets Xwhole notes, L2 sets half notes, L4 sets quarter notes, etc.. X.PP XP -- pause (rest), with interpreted as for L. May be followed by Xsustain dots. May also be written '~'. X.PP XT -- Sets the number of quarter notes per minute; default is 120. Musical Xnames for common tempi are: X X.TS Xa a a. X Tempo Beats Per Minute Xvery slow Larghissimo X Largo 40-60 X Larghetto 60-66 X Grave X Lento X Adagio 66-76 Xslow Adagietto X Andante 76-108 Xmedium Andantino X Moderato 108-120 Xfast Allegretto X Allegro 120-168 X Vivace X Veloce X Presto 168-208 Xvery fast Prestissimo X.TE X.PP XM[LNS] -- set articulation. MN (N for normal) is the default; the last 1/8th of Xthe note's value is rest time. You can set ML for legato (no rest space) or XMS (staccato) 1/4 rest space. X.PP XNotes (that is, CDEFGAB or N command character groups) may be followed by Xsustain dots. Each dot causes the note's value to be lengthened by one-half Xfor each one. Thus, a note dotted once is held for 3/2 of its undotted value; Xdotted twice, it is held 9/4, and three times would give 27/8. X.PP XWhitespace in play strings is simply skipped and may be used to separate Xmelody sections. X.SH BUGS XDue to roundoff in the pitch tables and slop in the tone-generation and timer Xhardware (neither of which was designed for precision), neither pitch accuracy Xnor timings will be mathematically exact. There is no volume control. X.PP XIn play strings which are very long (longer than your system's physical I/O Xblocks) note suffixes or numbers may occasionally be parsed incorrectly due Xto crossing a block boundary. X.SH FILES X/dev/speaker -- speaker device file X.SH AUTHOR XEric S. Raymond (esr@snark.thyrsus.com) Feb 1990 END-of-spkr.7 echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# X# Speaker driver package makefile X# XCFLAGS = -I. -O # -DDEBUG XLDFLAGS = -s X Xall: Driver.o X Xinstall: X ./Install X XDriver.o: spkr.c X $(CC) $(CFLAGS) -c spkr.c X mv spkr.o Driver.o X Xclean: X rm -f Driver.o *~ speaker.shar X XDSP = Files Install Master Name Node Remove Size System Xshar: X shar READ.ME install.bsd spkr.7 Makefile spkr.[ch] \ X interp.c $(DSP) playtest >speaker.shar END-of-Makefile echo x - spkr.c sed 's/^X//' >spkr.c << 'END-of-spkr.c' X/* X * spkr.c -- device driver for console speaker on 80386 X * X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 X * modified for 386bsd by Andrew A. Chernov X */ X X#ifdef __386BSD__ X#include "speaker.h" X#endif X#if !defined(__386BSD__) || (NSPEAKER > 0) X X#ifdef __386BSD__ X#include "types.h" X#include "param.h" X#include "errno.h" X#include "buf.h" X#include "uio.h" X X#define CADDR caddr_t X#define err_ret(x) return(x) X#else /* SYSV */ X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#define CADDR char * X#define err_ret(x) u.u_error = (x) X#endif X X#include "spkr.h" X X/**************** MACHINE DEPENDENT PART STARTS HERE ************************* X * X * This section defines a function tone() which causes a tone of given X * frequency and duration from the 80x86's console speaker. X * Another function endtone() is defined to force sound off, and there is X * also a rest() entry point to do pauses. X * X * Audible sound is generated using the Programmable Interval Timer (PIT) and X * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The X * PPI controls whether sound is passed through at all; the PIT's channel 2 is X * used to generate clicks (a square wave) of whatever frequency is desired. X * X * The non-BSD code requires SVr3.2-compatible inb(), outb(), timeout(), X * sleep(), and wakeup(). X */ X X/* X * PIT and PPI port addresses and control values X * X * Most of the magic is hidden in the TIMER_PREP value, which selects PIT X * channel 2, frequency LSB first, square-wave mode and binary encoding. X * The encoding is as follows: X * X * +----------+----------+---------------+-----+ X * | 1 0 | 1 1 | 0 1 1 | 0 | X * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | X * +----------+----------+---------------+-----+ X * Counter Write Mode 3 Binary X * Channel 2 LSB first, (Square Wave) Encoding X * MSB second X */ X#define PPI 0x61 /* port of Programmable Peripheral Interface */ X#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ X#define PIT_CTRL 0x43 /* PIT control address */ X#define PIT_COUNT 0x42 /* PIT count address */ X#define PIT_MODE 0xB6 /* set timer mode for sound generation */ X X/* X * Magic numbers for timer control. X */ X#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ X Xstatic int endtone() X/* turn off the speaker, ending current tone */ X{ X wakeup((CADDR)endtone); X outb(PPI, inb(PPI) & ~PPI_SPKR); X} X Xstatic void tone(hz, ticks) X/* emit tone of frequency hz for given number of ticks */ Xunsigned int hz, ticks; X{ X unsigned int divisor = TIMER_CLK / hz; X int sps; X X#ifdef DEBUG X printf("tone: hz=%d ticks=%d\n", hz, ticks); X#endif /* DEBUG */ X X /* set timer to generate clicks at given frequency in Hertz */ X#ifdef __386BSD__ X sps = spltty(); X#else X sps = spl5(); X#endif X outb(PIT_CTRL, PIT_MODE); /* prepare timer */ X outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ X outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ X splx(sps); X X /* turn the speaker on */ X outb(PPI, inb(PPI) | PPI_SPKR); X X /* X * Set timeout to endtone function, then give up the timeslice. X * This is so other processes can execute while the tone is being X * emitted. X */ X timeout((CADDR)endtone, (CADDR)NULL, ticks); X sleep((CADDR)endtone, PZERO - 1); X} X Xstatic int endrest() X/* end a rest */ X{ X wakeup((CADDR)endrest); X} X Xstatic void rest(ticks) X/* rest for given number of ticks */ Xint ticks; X{ X /* X * Set timeout to endrest function, then give up the timeslice. X * This is so other processes can execute while the rest is being X * waited out. X */ X#ifdef DEBUG X printf("rest: %d\n", ticks); X#endif /* DEBUG */ X timeout((CADDR)endrest, (CADDR)NULL, ticks); X sleep((CADDR)endrest, PZERO - 1); X} X X#include "interp.c" /* playinit() and playstring() */ X X/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** X * X * This section implements driver hooks to run playstring() and the tone(), X * endtone(), and rest() functions defined above. For non-BSD systems, X * SVr3.2-compatible copyin() is also required. X */ X Xstatic int spkr_active; /* exclusion flag */ X#ifdef __386BSD__ Xstatic struct buf *spkr_inbuf; /* incoming buf */ X#endif X Xint spkropen(dev) Xdev_t dev; X{ X#ifdef DEBUG X printf("spkropen: entering with dev = %x\n", dev); X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else if (spkr_active) X err_ret(EBUSY); X else X { X playinit(); X#ifdef __386BSD__ X spkr_inbuf = geteblk(DEV_BSIZE); X#endif X spkr_active = 1; X } X#ifdef __386BSD__ X return(0); X#endif X} X X#ifdef __386BSD__ Xint spkrwrite(dev, uio) Xstruct uio *uio; X#else Xint spkrwrite(dev) X#endif Xdev_t dev; X{ X#ifdef __386BSD__ X register unsigned n; X char *cp; X int error; X#endif X#ifdef DEBUG X#ifdef __386BSD__ X printf("spkrwrite: entering with dev = %x, count = %d\n", X dev, uio->uio_resid); X#else X printf("spkrwrite: entering with dev = %x, u.u_count = %d\n", X dev, u.u_count); X#endif X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else X { X#ifdef __386BSD__ X n = MIN(DEV_BSIZE, uio->uio_resid); X cp = spkr_inbuf->b_un.b_addr; X error = uiomove(cp, n, uio); X if (!error) X playstring(cp, n); X return(error); X#else X char bfr[STD_BLK]; X X copyin(u.u_base, bfr, u.u_count); X playstring(bfr, u.u_count); X u.u_base += u.u_count; X u.u_count = 0; X#endif X } X} X Xint spkrclose(dev) Xdev_t dev; X{ X#ifdef DEBUG X printf("spkrclose: entering with dev = %x\n", dev); X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else X { X endtone(); X#ifdef __386BSD__ X brelse(spkr_inbuf); X#endif X spkr_active = 0; X } X#ifdef __386BSD__ X return(0); X#endif X} X Xint spkrioctl(dev, cmd, cmdarg) Xdev_t dev; Xint cmd; XCADDR cmdarg; X{ X#ifdef DEBUG X printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else if (cmd == SPKRTONE) X { X tone_t *tp = (tone_t *)cmdarg; X X if (tp->frequency == 0) X rest(tp->duration); X else X tone(tp->frequency, tp->duration); X } X else if (cmd == SPKRTUNE) X { X#ifdef __386BSD__ X tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); X tone_t ttp; X int error; X X for (; ; tp++) { X error = copyin(tp, &ttp, sizeof(tone_t)); X if (error) X return(error); X if (ttp.duration == 0) X break; X if (ttp.frequency == 0) X rest(ttp.duration); X else X tone(ttp.frequency, ttp.duration); X } X#else X tone_t *tp = (tone_t *)cmdarg; X X for (; tp->duration; tp++) X if (tp->frequency == 0) X rest(tp->duration); X else X tone(tp->frequency, tp->duration); X#endif X } X else X err_ret(EINVAL); X#ifdef __386BSD__ X return(0); X#endif X} X X#endif /* !defined(__386BSD__) || (NSPEAKER > 0) */ X/* spkr.c ends here */ END-of-spkr.c echo x - spkr.h sed 's/^X//' >spkr.h << 'END-of-spkr.h' X/* X * spkr.h -- interface definitions for speaker ioctl() X * X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 X * modified for 386bsd by Andrew A. Chernov X */ X X#ifndef _SPKR_H_ X#define _SPKR_H_ X X#ifdef __386BSD__ X#ifndef KERNEL X#include X#else X#include "ioctl.h" X#endif X X#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */ X#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/ X#else /* SYSV */ X#define SPKRIOC ('S'<<8) X#define SPKRTONE (SPKRIOC|1) /* emit tone */ X#define SPKRTUNE (SPKRIOC|2) /* emit tone sequence*/ X#endif X Xtypedef struct X{ X int frequency; /* in hertz */ X int duration; /* in 1/100ths of a second */ X} Xtone_t; X X#endif /* _SPKR_H_ */ X/* spkr.h ends here */ END-of-spkr.h echo x - interp.c sed 's/^X//' >interp.c << 'END-of-interp.c' X/* X * interp.c -- device driver for console speaker on 80386 X * X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 X * X * this is the part of the code common to all 386 UNIX OSes X * X * playinit() and playstring() are called from the appropriate driver X */ X X#ifdef __386BSD__ X#include "param.h" X#else X#include X#endif X X#ifndef HZ X#define HZ 60 X#endif X X X/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** X * X * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; X * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. X * Requires tone(), rest(), and endtone(). String play is not interruptible X * except possibly at physical block boundaries. X */ X Xtypedef int bool; X#ifndef TRUE X#define TRUE 1 X#endif X#ifndef FALSE X#define FALSE 0 X#endif X X#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) X#define isdigit(c) (((c) >= '0') && ((c) <= '9')) X#define dtoi(c) ((c) - '0') X Xstatic int octave; /* currently selected octave */ Xstatic int whole; /* whole-note time at current tempo, in ticks */ Xstatic int value; /* whole divisor for note time, quarter note = 1 */ Xstatic int fill; /* controls spacing of notes */ Xstatic bool octtrack; /* octave-tracking on? */ Xstatic bool octprefix; /* override current octave-tracking state? */ X X/* X * Magic number avoidance... X */ X#define SECS_PER_MIN 60 /* seconds per minute */ X#define WHOLE_NOTE 4 /* quarter notes per whole note */ X#define MIN_VALUE 64 /* the most we can divide a note by */ X#define DFLT_VALUE 4 /* default value (quarter-note) */ X#define FILLTIME 8 /* for articulation, break note in parts */ X#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ X#define NORMAL 7 /* 7/8ths of note interval is filled */ X#define LEGATO 8 /* all of note interval is filled */ X#define DFLT_OCTAVE 4 /* default octave */ X#define MIN_TEMPO 32 /* minimum tempo */ X#define DFLT_TEMPO 120 /* default tempo */ X#define MAX_TEMPO 255 /* max tempo */ X#define NUM_MULT 3 /* numerator of dot multiplier */ X#define DENOM_MULT 2 /* denominator of dot multiplier */ X X/* letter to half-tone: A B C D E F G */ Xstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; X X/* X * This is the American Standard A440 Equal-Tempered scale with frequencies X * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... X * our octave 0 is standard octave 2. X */ X#define OCTAVE_NOTES 12 /* semitones per octave */ Xstatic int pitchtab[] = X{ X/* C C# D D# E F F# G G# A A# B*/ X/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, X/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, X/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, X/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, X/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, X/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, X/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, X}; X Xstatic void playinit() X{ X octave = DFLT_OCTAVE; X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; X fill = NORMAL; X value = DFLT_VALUE; X octtrack = FALSE; X octprefix = TRUE; /* act as though there was an initial O(n) */ X} X Xstatic void playtone(pitch, value, sustain) X/* play tone of proper duration for current rhythm signature */ Xint pitch, value, sustain; X{ X register int sound, silence, snum = 1, sdenom = 1; X X /* this weirdness avoids floating-point arithmetic */ X for (; sustain; sustain--) X { X snum *= NUM_MULT; X sdenom *= DENOM_MULT; X } X X if (pitch == -1) X rest(whole * snum / (value * sdenom)); X else X { X sound = (whole * snum) / (value * sdenom) X - (whole * (FILLTIME - fill)) / (value * FILLTIME); X silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); X X#ifdef DEBUG X printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", X pitch, sound, silence); X#endif /* DEBUG */ X X tone(pitchtab[pitch], sound); X if (fill != LEGATO) X rest(silence); X } X} X Xstatic int abs(n) Xint n; X{ X if (n < 0) X return(-n); X else X return(n); X} X Xstatic void playstring(cp, slen) X/* interpret and play an item from a notation string */ Xchar *cp; Xsize_t slen; X{ X int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; X X#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ X {v = v * 10 + (*++cp - '0'); slen--;} X for (; slen--; cp++) X { X int sustain, timeval, tempo; X register char c = toupper(*cp); X X#ifdef DEBUG X printf("playstring: %c (%x)\n", c, c); X#endif /* DEBUG */ X X switch (c) X { X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': X X /* compute pitch */ X pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; X X /* this may be followed by an accidental sign */ X if (cp[1] == '#' || cp[1] == '+') X { X ++pitch; X ++cp; X slen--; X } X else if (cp[1] == '-') X { X --pitch; X ++cp; X slen--; X } X X /* X * If octave-tracking mode is on, and there has been no octave- X * setting prefix, find the version of the current letter note X * closest to the last regardless of octave. X */ X if (octtrack && !octprefix) X { X if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) X { X ++octave; X pitch += OCTAVE_NOTES; X } X X if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) X { X --octave; X pitch -= OCTAVE_NOTES; X } X } X octprefix = FALSE; X lastpitch = pitch; X X /* ...which may in turn be followed by an override time value */ X GETNUM(cp, timeval); X if (timeval <= 0 || timeval > MIN_VALUE) X timeval = value; X X /* ...and/or sustain dots */ X for (sustain = 0; cp[1] == '.'; cp++) X { X slen--; X sustain++; X } X X /* time to emit the actual tone */ X playtone(pitch, timeval, sustain); X break; X X case 'O': X if (cp[1] == 'N' || cp[1] == 'n') X { X octprefix = octtrack = FALSE; X ++cp; X slen--; X } X else if (cp[1] == 'L' || cp[1] == 'l') X { X octtrack = TRUE; X ++cp; X slen--; X } X else X { X GETNUM(cp, octave); X if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) X octave = DFLT_OCTAVE; X octprefix = TRUE; X } X break; X X case '>': X if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) X octave++; X octprefix = TRUE; X break; X X case '<': X if (octave > 0) X octave--; X octprefix = TRUE; X break; X X case 'N': X GETNUM(cp, pitch); X for (sustain = 0; cp[1] == '.'; cp++) X { X slen--; X sustain++; X } X playtone(pitch - 1, value, sustain); X break; X X case 'L': X GETNUM(cp, value); X if (value <= 0 || value > MIN_VALUE) X value = DFLT_VALUE; X break; X X case 'P': X case '~': X /* this may be followed by an override time value */ X GETNUM(cp, timeval); X if (timeval <= 0 || timeval > MIN_VALUE) X timeval = value; X for (sustain = 0; cp[1] == '.'; cp++) X { X slen--; X sustain++; X } X playtone(-1, timeval, sustain); X break; X X case 'T': X GETNUM(cp, tempo); X if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) X tempo = DFLT_TEMPO; X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / tempo; X break; X X case 'M': X if (cp[1] == 'N' || cp[1] == 'n') X { X fill = NORMAL; X ++cp; X slen--; X } X else if (cp[1] == 'L' || cp[1] == 'l') X { X fill = LEGATO; X ++cp; X slen--; X } X else if (cp[1] == 'S' || cp[1] == 's') X { X fill = STACCATO; X ++cp; X slen--; X } X break; X } X } X} END-of-interp.c echo x - Files sed 's/^X//' >Files << 'END-of-Files' X/usr/include/sys/spkr.h END-of-Files echo x - Install sed 's/^X//' >Install << 'END-of-Install' X# X# Speaker driver installation script X# XTMP=/tmp/speaker.err XERR1=" Errors have been written to the file $TMP." XERR2=" The Speaker Driver software was not installed." X Xecho "Installing Speaker Driver Software Package" X X/etc/conf/bin/idcheck -p speaker 2>$TMP Xif [ $? != 0 ] Xthen X echo "The speaker package is already at least partly installed. X Removing the old version now..." X /etc/conf/bin/idinstall -d speaker Xfi X X/etc/conf/bin/idinstall -a -k speaker 2>>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during package installation. $ERR1 $ERR2" X exit 1 Xfi X X/etc/conf/bin/idbuild 2>>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during kernel reconfiguration. $ERR1 $ERR2" X exit 1 Xfi X Xrm -f $TMP X Xcp spkr.h /usr/include/sys/spkr.h X Xecho "Performing shutdown..." Xcd /; exec /etc/shutdown -g0 -y END-of-Install echo x - Master sed 's/^X//' >Master << 'END-of-Master' Xspeaker ocwi iocH spkr 0 0 1 1 -1 END-of-Master echo x - Name sed 's/^X//' >Name << 'END-of-Name' X386 UNIX Speaker Device Driver Package END-of-Name echo x - Node sed 's/^X//' >Node << 'END-of-Node' Xspeaker speaker c 0 END-of-Node echo x - Remove sed 's/^X//' >Remove << 'END-of-Remove' X# X# Speaker driver remove script X# XTMP=/tmp/speaker.err XRERR="Errors have been written to the file $TMP." X Xecho "Removing Speaker Driver Software Package" X X/etc/conf/bin/idinstall -d speaker 2>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during package removal. $RERR" X exit 1 Xfi X X/etc/conf/bin/idbuild 2>>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during kernel reconfiguration. $RERR" X exit 1 Xfi X Xrm -f /dev/speaker $TMP /usr/include/sys/spkr.h X Xexit 0 END-of-Remove echo x - Size sed 's/^X//' >Size << 'END-of-Size' XROOT=1400 XUSR=100 END-of-Size echo x - System sed 's/^X//' >System << 'END-of-System' Xspeaker Y 1 0 0 0 0 0 0 0 END-of-System echo x - playtest sed 's/^X//' >playtest << 'END-of-playtest' X: X# Test script for the speaker driver X# X# v1.0 by Eric S. Raymond (Feb 1990) X# modified for 386bsd by Andrew A. Chernov X# Xreveille="t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.." Xcontact="f" Xdance="t240dcdc/dev/speaker;; Xcontact) echo $contact >/dev/speaker;; Xdance) echo $dance >/dev/speaker;; Xloony) echo $loony >/dev/speaker;; X*) X echo "No such tune. Available tunes are:" X echo X echo "reveille -- Reveille" X echo "contact -- Contact theme from Close Encounters" X echo "dance -- Lord of the Dance (aka Simple Gifts)" X echo "loony -- Loony Toons theme" X ;; Xesac END-of-playtest exit nethack-3.6.0/sys/unix/sysconf0000664000076400007660000000746612631241231015355 0ustar paxedpaxed# NetHack 3.6 sysconf $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # # Sample sysconf file. # The sysconf file is only used if NetHack is compiled with SYSCF defined. # It can be used to augment or override certain settings compiled into the # program. # # This file can also be used to set local system defaults for run-time # options, using the same syntax as an individual user's ./nethackrc file. # Which users can use debug mode (aka wizard mode; accessed via '-D' command # line flag or OPTIONS=playmode:debug in the runtime options config file). # A value of * allows anyone to enter debugging mode. WIZARDS=root games # Which users can use explore mode (aka discover mode; accessed via '-X' # command line flag or OPTIONS=playmode:explore in runtime options file or # via '#exploremode' command during normal play). Same syntax as WIZARDS. EXPLORERS=* # Users allowed to use the '!' (shell escape) and '^Z' (suspend process) # commands to temporarily leave the game and enter a shell process. # (To resume play, use the shell command 'exit' (for most shells) to # return from '!' or the shell command 'fg' to return from '^Z'. # For the typical multi-user system where players have access to a shell # prompt when logged in and run the game from their own username, a value # of 'SHELLERS=*' is appropriate. However, some inexperienced players # occasionally get stuck outside the game by accidentally typing '!' or # '^Z' during play and not knowing how to go back.) # Uses the same syntax as the WIZARDS and EXPLORERS options above. #SHELLERS= # Limit the number of simultaneous games (see also nethack.sh). MAXPLAYERS=10 # If not null, added to string "To get local support, " in the support # information help. #SUPPORT=call Izchak at extension 42. # If not null, displayed at the end of a panic-save sequence. #RECOVER=Run the recover program. # Uncomment the next line to disable the SEDUCE option, causing succubi and # incubi to use nymphs' charm behavior rather than their own seduce behavior. #SEDUCE=0 # Uncomment to disable savefile UID checking. #CHECK_SAVE_UID=0 # Record (high score) file options. # CAUTION: changing these after people have started playing games can # lead to lost high scores! # Maximum entries for one person. #PERSMAX=10 # Maximum entries in the record file. #ENTRYMAX=100 # Minimum points to get an entry. #POINTSMIN=1 # Determine identity of "person" in the score file with name (0) or # numeric (1) user id. #PERS_IS_UID=1 # Maximum number of score file entries to use for random statue names #MAX_STATUENAME_RANK=10 # Show debugging information originating from these source files. # Use '*' for all, or list source files separated by spaces. # Only available if game has been compiled with DEBUG, and can be # overridden via DEBUGFILES environment variable. #DEBUGFILES=* # Try to get more info in case of a program bug or crash. Only used # if the program is built with the PANICTRACE compile-time option enabled. # By default PANICTRACE is enabled if BETA is defined, otherwise disabled. # Using GDB can get more information and works on more systems but requires # 'gdb' be available; using LIBC only works if NetHack is linked with a # libc that supports the backtrace(3) API. Both require certain compilation # options. See src/end.c and sys/unix/hints/* for more information. GDBPATH=/usr/bin/gdb GREPPATH=/bin/grep # Values are priorities: 0 - do not use this method, 1 - low priority, # 2 - high priority. Non-zero priority methods are tried in order. PANICTRACE_GDB=1 PANICTRACE_LIBC=2 # Ordinary run-time options can be set here to override the builtin-in # default values. Unlike the SYSCF values above, individual users can # still choose their own option settings via NETHACKOPTIONS in their # environment or via ~/.nethackrc run-time configuration file. #OPTIONS=!autopickup,fruit:tomato,symset:DECgraphics #eof nethack-3.6.0/sys/unix/unixmain.c0000664000076400007660000004610412536476415015754 0ustar paxedpaxed/* NetHack 3.6 unixmain.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.52 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - Unix NetHack */ #include "hack.h" #include "dlb.h" #include #include #include #include #ifndef O_RDONLY #include #endif #if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX) #if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__)) #if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX) extern struct passwd *FDECL(getpwuid, (uid_t)); #else extern struct passwd *FDECL(getpwuid, (int)); #endif #endif #endif extern struct passwd *FDECL(getpwnam, (const char *)); #ifdef CHDIR static void FDECL(chdirx, (const char *, BOOLEAN_P)); #endif /* CHDIR */ static boolean NDECL(whoami); static void FDECL(process_options, (int, char **)); #ifdef _M_UNIX extern void NDECL(check_sco_console); extern void NDECL(init_sco_cons); #endif #ifdef __linux__ extern void NDECL(check_linux_console); extern void NDECL(init_linux_cons); #endif static void NDECL(wd_message); static boolean wiz_error_flag = FALSE; static struct passwd *NDECL(get_unix_pw); int main(argc, argv) int argc; char *argv[]; { register int fd; #ifdef CHDIR register char *dir; #endif boolean exact_username; boolean resuming = FALSE; /* assume new game */ sys_early_init(); #if defined(__APPLE__) { /* special hack to change working directory to a resource fork when running from finder --sam */ #define MAC_PATH_VALUE ".app/Contents/MacOS/" char mac_cwd[1024], *mac_exe = argv[0], *mac_tmp; int arg0_len = strlen(mac_exe), mac_tmp_len, mac_lhs_len = 0; getcwd(mac_cwd, 1024); if (mac_exe[0] == '/' && !strcmp(mac_cwd, "/")) { if ((mac_exe = strrchr(mac_exe, '/'))) mac_exe++; else mac_exe = argv[0]; mac_tmp_len = (strlen(mac_exe) * 2) + strlen(MAC_PATH_VALUE); if (mac_tmp_len <= arg0_len) { mac_tmp = malloc(mac_tmp_len + 1); sprintf(mac_tmp, "%s%s%s", mac_exe, MAC_PATH_VALUE, mac_exe); if (!strcmp(argv[0] + (arg0_len - mac_tmp_len), mac_tmp)) { mac_lhs_len = (arg0_len - mac_tmp_len) + strlen(mac_exe) + 5; if (mac_lhs_len > mac_tmp_len - 1) mac_tmp = realloc(mac_tmp, mac_lhs_len); strncpy(mac_tmp, argv[0], mac_lhs_len); mac_tmp[mac_lhs_len] = '\0'; chdir(mac_tmp); } free(mac_tmp); } } } #endif hname = argv[0]; hackpid = getpid(); (void) umask(0777 & ~FCMASK); choose_windows(DEFAULT_WINDOW_SYS); #ifdef CHDIR /* otherwise no chdir() */ /* * See if we must change directory to the playground. * (Perhaps hack runs suid and playground is inaccessible * for the player.) * The environment variable HACKDIR is overridden by a * -d command line option (must be the first option given) */ dir = nh_getenv("NETHACKDIR"); if (!dir) dir = nh_getenv("HACKDIR"); #endif if (argc > 1) { #ifdef CHDIR if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else */ argc--; argv++; dir = argv[0] + 2; if (*dir == '=' || *dir == ':') dir++; if (!*dir && argc > 1) { argc--; argv++; dir = argv[0]; } if (!*dir) error("Flag -d must be followed by a directory name."); } if (argc > 1) #endif /* CHDIR */ /* * Now we know the directory containing 'record' and * may do a prscore(). Exclude `-style' - it's a Qt option. */ if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) { #ifdef CHDIR chdirx(dir, 0); #endif #ifdef SYSCF initoptions(); #endif #ifdef PANICTRACE ARGV0 = argv[0]; /* save for possible stack trace */ #ifndef NO_SIGNAL panictrace_setsignals(TRUE); #endif #endif prscore(argc, argv); exit(EXIT_SUCCESS); } } /* * Change directories before we initialize the window system so * we can find the tile file. */ #ifdef CHDIR chdirx(dir, 1); #endif #ifdef _M_UNIX check_sco_console(); #endif #ifdef __linux__ check_linux_console(); #endif initoptions(); #ifdef PANICTRACE ARGV0 = argv[0]; /* save for possible stack trace */ #ifndef NO_SIGNAL panictrace_setsignals(TRUE); #endif #endif exact_username = whoami(); /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ program_state.preserve_locks = 1; #ifndef NO_SIGNAL sethanguphandler((SIG_RET_TYPE) hangup); #endif process_options(argc, argv); /* command line options */ #ifdef WINCHAIN commit_windowchain(); #endif init_nhwindows(&argc, argv); /* now we can set up window system */ #ifdef _M_UNIX init_sco_cons(); #endif #ifdef __linux__ init_linux_cons(); #endif #ifdef DEF_PAGER if (!(catmore = nh_getenv("HACKPAGER")) && !(catmore = nh_getenv("PAGER"))) catmore = DEF_PAGER; #endif #ifdef MAIL getmailstatus(); #endif /* wizard mode access is deferred until here */ set_playmode(); /* sets plname to "wizard" for wizard mode */ if (exact_username) { /* * FIXME: this no longer works, ever since 3.3.0 * when plnamesuffix() was changed to find * Name-Role-Race-Gender-Alignment. It removes * all dashes rather than just the last one, * regardless of whether whatever follows each * dash matches role, race, gender, or alignment. */ /* guard against user names with hyphens in them */ int len = strlen(plname); /* append the current role, if any, so that last dash is ours */ if (++len < (int) sizeof plname) (void) strncat(strcat(plname, "-"), pl_character, sizeof plname - len - 1); } /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); if (wizard) { /* use character name rather than lock letter for file names */ locknum = 0; } else { /* suppress interrupts while processing lock file */ (void) signal(SIGQUIT, SIG_IGN); (void) signal(SIGINT, SIG_IGN); } /* * getlock() complains and quits if there is already a game * in progress for current character name (when locknum == 0) * or if there are too many active games (when locknum > 0). * When proceeding, it creates an empty .0 file to * designate the current game. * getlock() constructs based on the character * name (for !locknum) or on first available of alock, block, * clock, &c not currently in use in the playground directory * (for locknum > 0). */ getlock(); program_state.preserve_locks = 0; /* after getlock() */ dlb_init(); /* must be before newgame() */ /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. */ attempt_restore: if ((fd = restore_saved_game()) >= 0) { const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save, 0); /* disallow parallel restores */ #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif #ifdef NEWS if (iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if (dorecover(fd)) { resuming = TRUE; /* not starting new game */ wd_message(); if (discover || wizard) { if (yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { (void) chmod(fq_save, FCMASK); /* back to readable */ nh_compress(fq_save); } } } } if (!resuming) { /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name and skip selection this time if that didn't succeed */ if (!iflags.renameinprogress) { player_selection(); if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; if locking alphabetically, the existing lock file can still be used; otherwise, discard current one and create another for the new character name */ if (!locknum) { delete_levelfile(0); /* remove empty lock file */ getlock(); } goto attempt_restore; } } newgame(); wd_message(); } moveloop(resuming); exit(EXIT_SUCCESS); /*NOTREACHED*/ return (0); } static void process_options(argc, argv) int argc; char *argv[]; { int i, l; /* * Process options. */ while (argc > 1 && argv[1][0] == '-') { argv++; argc--; l = (int) strlen(*argv); /* must supply at least 4 chars to match "-XXXgraphics" */ if (l < 4) l = 4; switch (argv[0][1]) { case 'D': case 'd': if ((argv[0][1] == 'D' && !argv[0][2]) || !strcmpi(*argv, "-debug")) { wizard = TRUE, discover = FALSE; } else if (!strncmpi(*argv, "-DECgraphics", l)) { load_symset("DECGraphics", PRIMARY); switch_symbols(TRUE); } else { raw_printf("Unknown option: %s", *argv); } break; case 'X': discover = TRUE, wizard = FALSE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if (argv[0][2]) (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1); else if (argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname) - 1); } else raw_print("Player name expected after -u"); break; case 'I': case 'i': if (!strncmpi(*argv, "-IBMgraphics", l)) { load_symset("IBMGraphics", PRIMARY); load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); } else { raw_printf("Unknown option: %s", *argv); } break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; case 'w': /* windowtype */ choose_windows(&argv[0][2]); break; case '@': flags.randomall = 1; break; default: if ((i = str2role(&argv[0][1])) >= 0) { flags.initrole = i; break; } /* else raw_printf("Unknown option: %s", *argv); */ } } /* XXX This is deprecated in favor of SYSCF with MAXPLAYERS. Make * an error in next release. */ if (argc > 1) locknum = atoi(argv[1]); #ifdef MAX_NR_OF_PLAYERS /* limit to compile-time limit */ if (!locknum || locknum > MAX_NR_OF_PLAYERS) locknum = MAX_NR_OF_PLAYERS; #endif #ifdef SYSCF /* let syscf override compile-time limit */ if (!locknum || (sysopt.maxplayers && locknum > sysopt.maxplayers)) locknum = sysopt.maxplayers; #endif } #ifdef CHDIR static void chdirx(dir, wr) const char *dir; boolean wr; { if (dir /* User specified directory? */ #ifdef HACKDIR && strcmp(dir, HACKDIR) /* and not the default? */ #endif ) { #ifdef SECURE (void) setgid(getgid()); (void) setuid(getuid()); /* Ron Wessels */ #endif } else { /* non-default data files is a sign that scores may not be * compatible, or perhaps that a binary not fitting this * system's layout is being used. */ #ifdef VAR_PLAYGROUND int len = strlen(VAR_PLAYGROUND); fqn_prefix[SCOREPREFIX] = (char *) alloc(len + 2); Strcpy(fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND); if (fqn_prefix[SCOREPREFIX][len - 1] != '/') { fqn_prefix[SCOREPREFIX][len] = '/'; fqn_prefix[SCOREPREFIX][len + 1] = '\0'; } #endif } #ifdef HACKDIR if (dir == (const char *) 0) dir = HACKDIR; #endif if (dir && chdir(dir) < 0) { perror(dir); error("Cannot chdir to %s.", dir); } /* warn the player if we can't write the record file */ /* perhaps we should also test whether . is writable */ /* unfortunately the access system-call is worthless */ if (wr) { #ifdef VAR_PLAYGROUND fqn_prefix[LEVELPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[SAVEPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[BONESPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[LOCKPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[TROUBLEPREFIX] = fqn_prefix[SCOREPREFIX]; #endif check_recordfile(dir); } } #endif /* CHDIR */ /* returns True iff we set plname[] to username which contains a hyphen */ static boolean whoami() { /* * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS * 2. Use $USER or $LOGNAME (if 1. fails) * 3. Use getlogin() (if 2. fails) * The resulting name is overridden by command line options. * If everything fails, or if the resulting name is some generic * account like "games", "play", "player", "hack" then eventually * we'll ask him. * Note that we trust the user here; it is possible to play under * somebody else's name. */ if (!*plname) { register const char *s; s = nh_getenv("USER"); if (!s || !*s) s = nh_getenv("LOGNAME"); if (!s || !*s) s = getlogin(); if (s && *s) { (void) strncpy(plname, s, sizeof plname - 1); if (index(plname, '-')) return TRUE; } } return FALSE; } void sethanguphandler(handler) void FDECL((*handler), (int)); { #ifdef SA_RESTART /* don't want reads to restart. If SA_RESTART is defined, we know * sigaction exists and can be used to ensure reads won't restart. * If it's not defined, assume reads do not restart. If reads restart * and a signal occurs, the game won't do anything until the read * succeeds (or the stream returns EOF, which might not happen if * reading from, say, a window manager). */ struct sigaction sact; (void) memset((genericptr_t) &sact, 0, sizeof sact); sact.sa_handler = (SIG_RET_TYPE) handler; (void) sigaction(SIGHUP, &sact, (struct sigaction *) 0); #ifdef SIGXCPU (void) sigaction(SIGXCPU, &sact, (struct sigaction *) 0); #endif #else /* !SA_RESTART */ (void) signal(SIGHUP, (SIG_RET_TYPE) handler); #ifdef SIGXCPU (void) signal(SIGXCPU, (SIG_RET_TYPE) handler); #endif #endif /* ?SA_RESTART */ } #ifdef PORT_HELP void port_help() { /* * Display unix-specific help. Just show contents of the helpfile * named by PORT_HELP. */ display_file(PORT_HELP, TRUE); } #endif /* validate wizard mode if player has requested access to it */ boolean authorize_wizard_mode() { struct passwd *pw = get_unix_pw(); if (pw && sysopt.wizards && sysopt.wizards[0]) { if (check_user_string(sysopt.wizards)) return TRUE; } wiz_error_flag = TRUE; /* not being allowed into wizard mode */ return FALSE; } static void wd_message() { if (wiz_error_flag) { if (sysopt.wizards && sysopt.wizards[0]) { char *tmp = build_english_list(sysopt.wizards); pline("Only user%s %s may access debug (wizard) mode.", index(sysopt.wizards, ' ') ? "s" : "", tmp); free(tmp); } else pline("Entering explore/discovery mode instead."); wizard = 0, discover = 1; /* (paranoia) */ } else if (discover) You("are in non-scoring explore/discovery mode."); } /* * Add a slash to any name not ending in /. There must * be room for the / */ void append_slash(name) char *name; { char *ptr; if (!*name) return; ptr = name + (strlen(name) - 1); if (*ptr != '/') { *++ptr = '/'; *++ptr = '\0'; } return; } boolean check_user_string(optstr) char *optstr; { struct passwd *pw = get_unix_pw(); int pwlen; char *eop, *w; if (optstr[0] == '*') return TRUE; /* allow any user */ if (!pw) return FALSE; pwlen = strlen(pw->pw_name); eop = eos(optstr); w = optstr; while (w + pwlen <= eop) { if (!*w) break; if (isspace(*w)) { w++; continue; } if (!strncmp(w, pw->pw_name, pwlen)) { if (!w[pwlen] || isspace(w[pwlen])) return TRUE; } while (*w && !isspace(*w)) w++; } return FALSE; } static struct passwd * get_unix_pw() { char *user; unsigned uid; static struct passwd *pw = (struct passwd *) 0; if (pw) return pw; /* cache answer */ uid = (unsigned) getuid(); user = getlogin(); if (user) { pw = getpwnam(user); if (pw && ((unsigned) pw->pw_uid != uid)) pw = 0; } if (pw == 0) { user = nh_getenv("USER"); if (user) { pw = getpwnam(user); if (pw && ((unsigned) pw->pw_uid != uid)) pw = 0; } if (pw == 0) { pw = getpwuid(uid); } } return pw; } /*unixmain.c*/ nethack-3.6.0/sys/unix/unixres.c0000664000076400007660000000764412536476415015627 0ustar paxedpaxed/* NetHack 3.6 unixres.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Slash'EM development team, 2001. */ /* NetHack may be freely redistributed. See license for details. */ /* [ALI] This module defines nh_xxx functions to replace getuid etc which * will hide privileges from the caller if so desired. * * Currently supported UNIX variants: * Linux version 2.1.44 and above * FreeBSD (versions unknown) * * Note: SunOS and Solaris have no mechanism for retrieving the saved id, * so temporarily dropping privileges on these systems is sufficient to * hide them. */ #include "config.h" #ifdef GETRES_SUPPORT #if defined(LINUX) /* requires dynamic linking with libc */ #include static int real_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { int (*f)(uid_t *, uid_t *, uid_t *); /* getresuid signature */ f = dlsym(RTLD_NEXT, "getresuid"); if (!f) return -1; return f(ruid, euid, suid); } static int real_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { int (*f)(gid_t *, gid_t *, gid_t *); /* getresgid signature */ f = dlsym(RTLD_NEXT, "getresgid"); if (!f) return -1; return f(rgid, egid, sgid); } #else #if defined(BSD) || defined(SVR4) #ifdef SYS_getresuid static int real_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { return syscall(SYS_getresuid, ruid, euid, suid); } #else /* SYS_getresuid */ #ifdef SVR4 #include #endif /* SVR4 */ static int real_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { int retval; int pfd[2]; struct stat st; if (pipe(pfd)) return -1; retval = fstat(pfd[0], &st); close(pfd[0]); close(pfd[1]); if (!retval) { *euid = st.st_uid; *ruid = syscall(SYS_getuid); *suid = *ruid; /* Not supported under SVR4 */ } return retval; } #endif /* SYS_getresuid */ #ifdef SYS_getresgid static int real_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { return syscall(SYS_getresgid, rgid, egid, sgid); } #else /* SYS_getresgid */ static int real_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { int retval; int pfd[2]; struct stat st; if (pipe(pfd)) return -1; retval = fstat(pfd[0], &st); close(pfd[0]); close(pfd[1]); if (!retval) { *egid = st.st_gid; *rgid = syscall(SYS_getgid); *sgid = *rgid; /* Not supported under SVR4 */ } return retval; } #endif /* SYS_getresgid */ #endif /* BSD || SVR4 */ #endif /* LINUX */ static unsigned int hiding_privileges = 0; /* * Note: returns the value _after_ action. */ int hide_privileges(flag) boolean flag; { if (flag) hiding_privileges++; else if (hiding_privileges) hiding_privileges--; return hiding_privileges; } int nh_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { int retval = real_getresuid(ruid, euid, suid); if (!retval && hiding_privileges) *euid = *suid = *ruid; return retval; } uid_t nh_getuid() { uid_t ruid, euid, suid; (void) real_getresuid(&ruid, &euid, &suid); return ruid; } uid_t nh_geteuid() { uid_t ruid, euid, suid; (void) real_getresuid(&ruid, &euid, &suid); if (hiding_privileges) euid = ruid; return euid; } int nh_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { int retval = real_getresgid(rgid, egid, sgid); if (!retval && hiding_privileges) *egid = *sgid = *rgid; return retval; } gid_t nh_getgid() { gid_t rgid, egid, sgid; (void) real_getresgid(&rgid, &egid, &sgid); return rgid; } gid_t nh_getegid() { gid_t rgid, egid, sgid; (void) real_getresgid(&rgid, &egid, &sgid); if (hiding_privileges) egid = rgid; return egid; } #else /* GETRES_SUPPORT */ #ifdef GNOME_GRAPHICS int hide_privileges(flag) boolean flag; { return 0; } #endif #endif /* GETRES_SUPPORT */ nethack-3.6.0/sys/unix/unixunix.c0000664000076400007660000002333512536476415016014 0ustar paxedpaxed/* NetHack 3.6 unixunix.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file collects some Unix dependencies */ #include "hack.h" /* mainly for index() which depends on BSD */ #include #include #if defined(NO_FILE_LINKS) || defined(SUNOS4) || defined(POSIX_TYPES) #include #endif #include #ifdef _M_UNIX extern void NDECL(sco_mapon); extern void NDECL(sco_mapoff); #endif #ifdef __linux__ extern void NDECL(linux_mapon); extern void NDECL(linux_mapoff); #endif #ifndef NHSTDC extern int errno; #endif static struct stat buf; /* see whether we should throw away this xlock file */ static int veryold(fd) int fd; { time_t date; if (fstat(fd, &buf)) return (0); /* cannot get status */ #ifndef INSURANCE if (buf.st_size != sizeof(int)) return (0); /* not an xlock file */ #endif #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *) (&date)); #else (void) time(&date); #endif if (date - buf.st_mtime < 3L * 24L * 60L * 60L) { /* recent */ int lockedpid; /* should be the same size as hackpid */ if (read(fd, (genericptr_t) &lockedpid, sizeof(lockedpid)) != sizeof(lockedpid)) /* strange ... */ return (0); /* From: Rick Adams */ /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5. */ /* It will do nothing on V7 or 4.1bsd. */ #ifndef NETWORK /* It will do a VERY BAD THING if the playground is shared by more than one machine! -pem */ if (!(kill(lockedpid, 0) == -1 && errno == ESRCH)) #endif return (0); } (void) close(fd); return (1); } static int eraseoldlocks() { register int i; program_state.preserve_locks = 0; /* not required but shows intent */ /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for (i = 1; i <= MAXDUNGEON * MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) unlink(fqname(lock, LEVELPREFIX, 0)); } set_levelfile_name(lock, 0); if (unlink(fqname(lock, LEVELPREFIX, 0))) return (0); /* cannot remove it */ return (1); /* success! */ } void getlock() { register int i = 0, fd, c; const char *fq_lock; #ifdef TTY_GRAPHICS /* idea from rpick%ucqais@uccba.uc.edu * prevent automated rerolling of characters * test input (fd0) so that tee'ing output to get a screen dump still * works * also incidentally prevents development of any hack-o-matic programs */ /* added check for window-system type -dlc */ if (!strcmp(windowprocs.name, "tty")) if (!isatty(0)) error("You must play from a terminal."); #endif /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); error("%s", ""); } /* default value of lock[] is "1lock" where '1' gets changed to 'a','b',&c below; override the default and use if we aren't restricting the number of simultaneous games */ if (!locknum) Sprintf(lock, "%u%s", (unsigned) getuid(), plname); regularize(lock); set_levelfile_name(lock, 0); if (locknum) { if (locknum > 25) locknum = 25; do { lock[0] = 'a' + i++; fq_lock = fqname(lock, LEVELPREFIX, 0); if ((fd = open(fq_lock, 0)) == -1) { if (errno == ENOENT) goto gotlock; /* no such file */ perror(fq_lock); unlock_file(HLOCK); error("Cannot open %s", fq_lock); } if (veryold(fd) /* closes fd if true */ && eraseoldlocks()) goto gotlock; (void) close(fd); } while (i < locknum); unlock_file(HLOCK); error("Too many hacks running now."); } else { fq_lock = fqname(lock, LEVELPREFIX, 0); if ((fd = open(fq_lock, 0)) == -1) { if (errno == ENOENT) goto gotlock; /* no such file */ perror(fq_lock); unlock_file(HLOCK); error("Cannot open %s", fq_lock); } if (veryold(fd) /* closes fd if true */ && eraseoldlocks()) goto gotlock; (void) close(fd); if (iflags.window_inited) { c = yn("There is already a game in progress under your name. " "Destroy old game?"); } else { (void) printf( "\nThere is already a game in progress under your name."); (void) printf(" Destroy old game? [yn] "); (void) fflush(stdout); if ((c = getchar()) != EOF) { int tmp; (void) putchar(c); (void) fflush(stdout); while ((tmp = getchar()) != '\n' && tmp != EOF) ; /* eat rest of line and newline */ } } if (c == 'y' || c == 'Y') { if (eraseoldlocks()) goto gotlock; else { unlock_file(HLOCK); error("Couldn't destroy old game."); } } else { unlock_file(HLOCK); error("%s", ""); } } gotlock: fd = creat(fq_lock, FCMASK); unlock_file(HLOCK); if (fd == -1) { error("cannot creat lock file (%s).", fq_lock); } else { if (write(fd, (genericptr_t) &hackpid, sizeof(hackpid)) != sizeof(hackpid)) { error("cannot write lock (%s)", fq_lock); } if (close(fd) == -1) { error("cannot close lock (%s)", fq_lock); } } } void regularize(s) /* normalize file name - we don't like .'s, /'s, spaces */ register char *s; { register char *lp; while ((lp = index(s, '.')) || (lp = index(s, '/')) || (lp = index(s, ' '))) *lp = '_'; #if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) \ && !defined(__APPLE__) /* avoid problems with 14 character file name limit */ #ifdef COMPRESS /* leave room for .e from error and .Z from compress appended to * save files */ { #ifdef COMPRESS_EXTENSION int i = 12 - strlen(COMPRESS_EXTENSION); #else int i = 10; /* should never happen... */ #endif if (strlen(s) > i) s[i] = '\0'; } #else if (strlen(s) > 11) /* leave room for .nn appended to level files */ s[11] = '\0'; #endif #endif } #if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV) #include void msleep(msec) unsigned msec; /* milliseconds */ { struct pollfd unused; int msecs = msec; /* poll API is signed */ if (msecs < 0) msecs = 0; /* avoid infinite sleep */ (void) poll(&unused, (unsigned long) 0, msecs); } #endif /* TIMED_DELAY for SYSV */ #ifdef SHELL int dosh() { register char *str; #ifdef SYSCF if (!sysopt.shellers || !sysopt.shellers[0] || !check_user_string(sysopt.shellers)) { Norep("Unknown command '!'."); return 0; } #endif if (child(0)) { if ((str = getenv("SHELL")) != (char *) 0) (void) execl(str, str, (char *) 0); else (void) execl("/bin/sh", "sh", (char *) 0); raw_print("sh: cannot execute."); exit(EXIT_FAILURE); } return 0; } #endif /* SHELL */ #if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER) int child(wt) int wt; { register int f; suspend_nhwindows((char *) 0); /* also calls end_screen() */ #ifdef _M_UNIX sco_mapon(); #endif #ifdef __linux__ linux_mapon(); #endif if ((f = fork()) == 0) { /* child */ (void) setgid(getgid()); (void) setuid(getuid()); #ifdef CHDIR (void) chdir(getenv("HOME")); #endif return (1); } if (f == -1) { /* cannot fork */ pline("Fork failed. Try again."); return (0); } /* fork succeeded; wait for child to exit */ #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); #endif (void) wait((int *) 0); #ifdef _M_UNIX sco_mapoff(); #endif #ifdef __linux__ linux_mapoff(); #endif #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); if (wizard) (void) signal(SIGQUIT, SIG_DFL); #endif if (wt) { raw_print(""); wait_synch(); } resume_nhwindows(); return (0); } #endif #ifdef GETRES_SUPPORT extern int FDECL(nh_getresuid, (uid_t *, uid_t *, uid_t *)); extern uid_t NDECL(nh_getuid); extern uid_t NDECL(nh_geteuid); extern int FDECL(nh_getresgid, (gid_t *, gid_t *, gid_t *)); extern gid_t NDECL(nh_getgid); extern gid_t NDECL(nh_getegid); int(getresuid)(ruid, euid, suid) uid_t *ruid, *euid, *suid; { return nh_getresuid(ruid, euid, suid); } uid_t(getuid)() { return nh_getuid(); } uid_t(geteuid)() { return nh_geteuid(); } int(getresgid)(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { return nh_getresgid(rgid, egid, sgid); } gid_t(getgid)() { return nh_getgid(); } gid_t(getegid)() { return nh_getegid(); } #endif /* GETRES_SUPPORT */ /* XXX should be ifdef PANICTRACE_GDB, but there's no such symbol yet */ #ifdef PANICTRACE boolean file_exists(const char *path) { /* Just see if it's there - trying to figure out if we can actually * execute it in all cases is too hard - we really just want to * catch typos in SYSCF. */ struct stat sb; if (stat(path, &sb)) { return FALSE; } return TRUE; } #endif nethack-3.6.0/sys/vms/Install.vms0000664000076400007660000007053312627501605015731 0ustar paxedpaxed Instructions for Building and Installing NetHack 3.6.0 on a VMS (aka OpenVMS) system ========================================= 0. Please read this entire file before trying to build or install NetHack, then read it again! 1. NetHack 3.6 was built and tested on OpenVMS on both the Integrity and Alpha platform using the HP C V7.3 for OpenVMS compiler. While not tested, older versions of DEC C will most likely work as compatibility with older systems is a goal of the VMS porting team. Unfortunatly, ancient VAX C probably will no longer work. The set of Makefiles provided are known to be out of date; use vmsbuild.com instead. 2. Make sure all the NetHack files are in the appropriate directory structure. You should set up a directory--referred to as "top" below and in some of the assorted files, but which may be a subdirectory-- that has these subdirectories [.dat] -- data files [.doc] -- documentation files [.include] -- C header files [.src] -- primary source files [.sys] -- parent for [.sys.*] [.sys .share] -- files shared by several ports, including VMS [.sys .vms] -- VMS-specific source and support files [.util] -- sources for essential utility programs [.win] -- parent for [.win.*] [.win .tty] -- "window" routines for ordinary terminals (including terminal windows on workstations) The following subdirectories may be present, but are not useful for building NetHack on VMS and are not required: [.sys .amiga] -- AmigaDOS [.sys .atari] -- Atari TOS [.sys .be] -- BeBox BeOS [.sys .mac] -- Macintosh [.sys .msdos] -- MSDOS for IBM PCs and compatibles [.sys .os2] -- OS/2 [.sys .share .sounds] -- AIFF format audio files [.sys .unix] -- guess :-) [.sys .unit .hints] -- configuration data for setup.sh [.sys .wince] -- Windows CE [.sys .wince .ceinc] -- more WinCE [.sys .wince .ceinc .sys] -- ditto [.sys .winnt] -- Windows NT [.win .gem] -- window routines for Atari/GEM [.win .gnome] -- window routines for Unix/GNOME [.win .Qt] -- window routines for Qt [.win .share] -- "tile" graphic support [.win .win32] -- Windows NT and Windows CE [.win .X11] -- window routines for X-Windows; requires X11R4 or later and MIT's Athena Widget set You must arrange things in this structure or the supplied procedures and instructions in this file will not work properly. Several DCL command files are present in the [.sys.vms] subdirectory and will not work as intended if they are moved elsewhere. The file called Files in the top directory contains lists of everything that should be in each subdirectory, including things that are constructed as NetHack is being built. 3. Prior to beginning compilation, go to the [.include] subdirectory and edit vmsconf.h according to its comments. You should set Local_WIZARD and Local_HACKDIR to appropriate values, and you might want to define TEXTCOLOR if you have any color VAXstations or color terminals which handle ANSI-format escape sequences to set foreground and background color for text characters. (VT241/VT340 color graphics won't work.) Other things which may be of interest are SECURE if you intend to set up NetHack as an installed image which is granted privileges, and SHELL which should be disabled if you intend to allow captive accounts to run NetHack. You may also want to edit file config.h, but that's only necessary if you want or need to disable some of the game options. The distributed copy of config.h will work successfully on VMS; vmsconf.h has conditional code to deal with the UNIX-specific items. 4. If you have the programming utilities lex or flex and yacc or bison, you may edit the procedure [.sys.vms]spec_lev.com and execute it to process several source files for NetHack's special level and dungeon compilers. If you use the version of these utilities from the OpenVMS freeware CD you will have to remove the include that yacc places at the top of each file. The provided spec_lev.com will default to copy pre-processed versions of the appropriate files (dgn_lex.c, lev_lex.c, dgn_yacc.c, lev_yacc.c, dgn_comp.h, and lev_comp.h) from [.sys.share] into [.util]*.c and [.include]*.h. If you choose to modify spec_lev.com, you want to run and test your changes prior to executing vmsbuild.com; otherwise, vmsbuild.com will do so for you and the results might not be what you expect. 5. To build NETHACK.EXE and its auxiliary programs, execute the following DCL command: $ @[.SYS.VMS]VMSBUILD !defaults to CC, either VAXC or DECC or $ @[.SYS.VMS]VMSBUILD "GNUC" !force "GCC" It can take quite a bit of time for a full build to complete. Around an hour on a Alphastation 200 and 5 minutes on a modern IA64 system. vmsbuild.com will display some feedback as it executes; generally this will be the name of each source file that's about to be compiled or the name of the executable that has just been linked. 6. If you have already started (or finished) a build and decide to start over with a different compiler, you should DELETE [.SRC]CRTL.OPT;* first. 7. After compilation, it's time to perform installation. Go back to the top directory. Either edit [.sys.vms]install.com to indicate where you want everything to be installed, or specify the location and "playground" owner on the command line. Then execute either $ @[.SYS.VMS]INSTALL or $ @[.SYS.VMS]INSTALL location owner where location is a device:[directory] specification and owner is either a rights identifier or UIC. If install.com is not modified and if values aren't supplied on the command line, the default values used are the translation of logical name HACKDIR, if any, or else [.PLAY] (relative to the current directory), and the UIC for the current process. install.com will use the auxiliary programs constructed by vmsbuild.com to process quite a few data files in the [.dat] subdirectory. Then it will create the playground directory, if necessary, plus the associated [.save] subdirectory. Next it will copy the data files into the playground; this step can take a while. Finally it will copy nethack.exe and a few additional support files. After it completes, the files [.src]nethack.olb, [.src]nethack.exe, [.util]*.obj, [.util]*_comp.exe, and [.util]makedefs.exe can be deleted in order to save disk space if desired. The other program, [.util]recover.exe, should not be deleted unless you make a copy of it somewhere--perhaps in the playground directory--first. It can be used to resurrect some games disrupted by system or program crash. 8. The file nethack.com which is copied to the playground directory can be used to invoke NetHack, or nethack.exe can be run directly. Most of the command-line options specified in the Unix man-page (file [.doc]nethack.txt) are also applicable to VMS. Some comments at the beginning of nethack.com illustrate several of the options. New players should read the file "Guidebook.txt" which will be copied into the playground directory as "Guidebook.doc". Notes: 0. Version 3.5.x was never publicly released. 1. Save files and bones files from 3.4.x and earlier versions will not work with 3.6.0. The scoreboard file (RECORD) from 3.4.x or 3.3.x will work. 2. To specify user-preference options in your environment, define the logical name NETHACKOPTIONS to have the value of a quoted string containing a comma separated list of option values. The option names are case-insensitive. $ define nethackoptions "noAutoPickup,Dog:Rover,Cat:Felix,DECgraphics" One value you'll probably want to specify is "noLegacy" to turn off the initial introductory passage. The "checkpoint" option controls whether or not enough data is saved to disk so that the set of level files left behind after a crash contains sufficient information for recover.exe to be able to construct a save file after the fact. The tradeoff for enabling checkpoint is that using it makes level changes do more I/O and take longer. The "menustyle" option controls some aspects of the user interface, and can be set to "menustyle:traditional" to make nethack behave more like older versions. If logical name or DCL symbol NETHACKOPTIONS is not defined, NetHack will try HACKOPTIONS instead. Regardless of whether or not either is defined, it will also try to find a configuration file containing additional option settings. If the value of the translation of NETHACKOPTIONS--or HACKOPTIONS--begins with an "@" character then the rest of the translation is assumed to be the name of the configuration file. Otherwise, the following are tried: file specified by logical name NETHACKINI, file SYS$LOGIN:NETHACK.INI, and file HOME:NETHACK.CNF (note that the C run-time library sets up the value of HOME to match sys$login). Syntax for the configuration file is similar to NETHACKOPTIONS, but multiple lines can be used, each must start with OPTIONS=, and comments can be included by placing '#' in the first column. Several options which take more complex values (graphics representation) can also be present; see the "Guidebook" for details. (Guidebook.txt can be found in the [.doc] subdirectory; a copy gets placed in the playground directory by install.com. Also, an example configuration file can be found in [.win.X11]nethack.rc.) 3. [As mentioned above, the set of Makefiles is out of date so disregard this note....] Instead of using vmsbuild.com to compile and link everything, you can use the set of Makefiles found in the vms subdirectory, provided you have an appropriate and compatible make utility. They've been tested using MMK, a freeware clone of Digital's MMS. There are five of them, and the suffix or filetype on their names indicates where they should be placed. $ copy [.sys.vms]Makefile.top []Makefile. $ copy [.sys.vms]Makefile.src [.src]Makefile. $ copy [.sys.vms]Makefile.utl [.util]Makefile. $ copy [.sys.vms]Makefile.dat [.dat]Makefile. $ copy [.sys.vms]Makefile.doc [.doc]Makefile. After doing that, edit [.src]Makefile and [.util]Makefile to specify pertinent compiler options in CFLAGS, linker options in LFLAGS, and libraries in LIBS and/or MORELIBS if the default values aren't right. Be sure to make compatible compilation and linking settings in both files. While in there, edit [.util]Makefile to specify the appropriate values for lex and yacc, _or_ move to that directory and use MMS or make to build targets no_lex and no_yacc which will copy several pre-processed files from [.sys.share] into [.util]. Finally, edit Makefile in the top directory to specify values for GAMEDIR and GAMEOWNER. This top Makefile invokes [.sys.vms]install.com to do much of the actual installation work, so if you want to make any customizations or file protection changes, edit install.com to suit. Also set MAKE in all of the Makefiles to the appropriate command if not using MMS or MMK. Once the Makefiles are tailored for your site, give the command $ mms all,install or $ make all install To compile and install everything. The object files compiled via the Makefiles are left as individual .OBJ files rather than placed into an object library (in contrast to step #7 above and note #10 below). These Makefiles are provided on an as-is basis; vmsbuild.com is the preferred way to compile because it's guaranteed to compile and link everything. 4. termcap is an ASCII data file containing descriptions of terminal capabilities and the escape sequences that software must use to take advantage of them. If you do not already have a termcap file in use on your system there is a small one in file [.SYS.SHARE]TERMCAP. It contains definitions for common Digital terminals, also suitable for most clones and emulators. This file is copied into the playground by install.com, and NetHack will use it if it can't find any other one. NetHack uses the following sequence to attempt to locate the termcap file: translation of the logical name TERMCAP (used as-is), file NETHACKDIR:TERMCAP, similar file HACKDIR:TERMCAP, GNU-Emacs file EMACS_LIBRARY:[ETC]TERMCAP.DAT, file []TERMCAP, and lastly file $TERMCAP (which most likely would be a logical name). If NetHack can't find the termcap file, or if the above search sequence finds a different one than you'd prefer, then use the DCL ASSIGN or DEFINE command to define a value for logical name TERMCAP. NetHack also tries fairly hard to figure out what kind of terminal you're using. It checks for logical names (or symbols) NETHACK_TERM, HACK_TERM, EMACS_TERM, and lastly TERM. The last is set up by the C run-time library and you cannot use a logical name or symbol for it. If all those fail, or if whichever one succeeds has a value of "undefined" or "unknown" (which can happen under VMS V5.4-* and V5.5-* for VT420 terminals), NetHack will query the VMS TERMTABLE database used by the SMG library routines. Whatever value NetHack eventually comes up with needs to be the name of an entry in the termcap file, otherwise a message about "Unknown terminal type" will be printed and NetHack will exit. 5. NetHack contains code which attempts to make it secure in case it's installed with privileges (to allow the playground to be protected against world write access). This has only undergone limited testing, so install NetHack with privileges at your own risk. If you discover any potential security holes, please let us know so that we can take steps to correct the problem(s). NetHack always includes filename punctuation when accessing files, so that it should never be affected by inadvertent or malicious logical name definitions, and it always deactivates installed privileges prior to spawning a subprocess. Note to end users: "installing with privileges" is an option for system managers who set up system-wide access to the game. Since CMKRNL privilege and modification of the system boot routines are both required, it is not an option for ordinary users. There are no explicit instructions on how to do such an installation, because only system managers who are already familiar with the process and its potential security ramifications should even consider it. The default setup by install.com assumes no privileges and uses world-writable files to allow arbitrary users to play. This is NOT secure and not advisable in any environment where there are untrustworthy users, but works fine for many sites. If you allow users to run NetHack from captive accounts (VMS 5.1-* or earlier) or from restricted accounts (5.2 and later), you should either make sure that they do not have TMPMBX privilege or else disable NetHack's ability to spawn an interactive subprocess. To disable subprocesses, disable the "!" (shell escape) command by commenting out the definition of SHELL in vmsconf.h prior to building the program. This necessity may be removed in some future release, where NetHack will check for captive accounts instead of spawning unconditionally. Note that disabling the SHELL command also prevents spawning MAIL when scrolls of new mail are received. In order for installed privileges to be used at all, the value of HACKDIR (via Local_HACKDIR in vmsconf.h) compiled into the program must correspond to the actual playground directory. If logical name HACKDIR (or NETHACKDIR) is used to override that value, installed privileges will be deactivated unless its value corresponds to the same device and directory as the internal value. If that internal value contains a logical name, only an executive-mode translation will be honored; if there is no such translation, installed privs will be deactivated. To be able to install nethack.exe with privileges (SYSPRV or GRPPRV, perhaps EXQUOTA, depending on site usage and needs), you'll need to link it with debugging and tracebacks both disabled. You can do this by specifying an argument to vmsbuild.com when performing step #6 above; pass it "/noTrace/noDebug" as the 4th parameter. $ @[.SYS.VMS]VMSBUILD "" "" "" "/noTrace/noDebug" /Trace/noDebug is the linker's normal default. If you've already built NetHack, you can relink with tracebacks disabled by doing $ @[.SYS.VMS]VMSBUILD "LINK" "" "" "/noTrace/noDebug" 6. If you can't or won't install nethack.exe with privileges and if you don't have access to a privileged account yourself, then if you intend to allow other users to access your copy of NetHack you should probably place an ACL on the playground directory and its save subdirectory. The access control list should contain a default protection ACE which grants delete+control access to the playground owner (ie, your own account if there's no special games account involved). install.com does not attempt to do this automatically at the present time. After executing install.com to create the playground directory, perform a pair of commands similar to the following $ SET ACL/ACL=(IDENT=your_id, OPTIONS=DEFAULT, ACCESS=R+W+E+D+C) - $_ device:[playground's.parent.directory]playground.DIR $ SET ACL/ACL=(IDENT=your_id, OPTIONS=DEFAULT, ACCESS=R+W+E+D+C) - $_ device:[playground.directory]SAVE.DIR The two commands use the same options, but SET ACL won't accept a list of files to modify. (For recent versions of VMS, SET ACL was made obsolete in favor of SET FILE/ACL, which in turn has been made obsolete in favor of SET SECURITY/CLASS=FILE/ACL; however, the older forms will still work.) 'your_id' should be the rights identifier which corresponds to the account which should retain access to those files; 'device:[playground's.parent.directory]' is the name of the parent directory for the playground (ie, if your playground directory is disk$foo:[me.games.nethack.play], then you want to specify disk$foo:[me.games.nethack]play.dir on the SET ACL command), and 'device:[playground.directory]' is the playground itself. Those ACLs establish a default protection scheme such that every newly created file in those directories will have an ACL attached to it, and the attached ACL will grant 'your_id' full access to the corresponding file. That should allow you to clear away level files from aborted games, and to delete old save files if necessary. It will not enable you to run recover.exe on behalf of other users, because you won't be able to create files owned by them unless you have elevated privileges. 7. Many NetHack commands can be aborted by sending it the character when it wants input. This is displayed as ESC inside the game. Digital VK201 keyboards (used by VT2xx and VT3xx and older VAXstations) and VK401 keyboards (used by VT4xx, newer VAXstations, and DEC's X Terminals) do not have an key. They may transmit for the key if the terminal or emulator window is set to operate in VT100 mode, or there may be a setup-type option for making the <` | ~> key behave as . If your terminal does not have that, or if it's set to a mode where that won't work, then just use instead. (Press the "[" key while holding down the "Ctrl" key, then release both; and have the same ASCII code and are indistinguishable once they reach the computer; note that VAXstations and X Terminals _can_ tell the difference, but that won't matter for NetHack.) VMS NetHack is configured to use the SYS$QIOW system service for reading characters from the keyboard. This allows ^C and ^Y (as well as ^X and ^O for wizard mode debugging) to be used as commands without being intercepted or interpreted by the terminal driver. The code which parses arrow and function keys is not perfect, and it's possible to get strange results if you hold such keys down or just type too quickly, particularly on slow multiplexor lines. Those keys are never needed in actual play, and most function keys are just treated as for use in aborting partial commands. VMS NetHack also still has code to use SMG$READ_KEYSTROKE instead. That can be activated by modifying vmsconf.h and recompiling, but it should never be necessary. If you use it, you'll need to press either or twice to abort partial commands, or else press an arbitrary function key, such as , once. If SUSPEND is defined in vmsconf.h, is used for that command. Since Unix-style job control is not available, it's used for connecting to the parent process if NetHack is running in a subprocess. When not in a subprocess, it doesn't do anything except give a message to the effect that it's not doing anything.... The suspend command does not save the current game; if you use ^Z to attach to your parent process, be sure to remember to eventually reattach to the NetHack subprocess; otherwise the game in progress won't get saved when you logout. 8. NetHack optionally maintains a logfile which receives one line appended to it whenever a game ends. This can be disabled entirely by adding an "#undef LOGFILE" directive to vmsconf.h prior to building the program, or it can be disabled later by removing the file(s) LOGFILE.;* from the playground directory. If not disabled prior to compilation, the logfile can be reinitialized by simply creating an empty file named LOGFILE in the playground, but make sure that users are able to write into it, or new entries will not be appended. 9. Some attempt at support for VMS versions earlier than V4.6 has been included, but no such obsolete system was available for testing it. vmsbuild.com detects the need for the extra support routines and arranges automatically for them to be compiled. The reason that special support is needed is that the C Run-Time Library (VAXCRTL) underwent a major revision for VMS V4.6 and several routines which NetHack utilizes were not available prior to that upgrade. 10. vmsbuild.com collects almost all of the object files (xxx.OBJ) into an object library (NETHACK.OLB) as it compiles the source files. This should prevent the quota-exceeded problems from the linker that some sites have reported for prior versions. Note that if you compile any source files manually, you'll need to replace those modules in the object library prior to linking the program: $ cc/include=[-.include] [-.sys.vms]vmstty !for example $ libr/obj []nethack vmstty !replace VMSTTY $ @[-.sys.vms]vmsbuild LINK !re-link NETHACK.EXE If you forget to replace the library entry, your newly compiled code will not be included in the new executable image. 11. To access "wizard mode"--intended for debugging purposes, not to spoil the game with unlimited wishes--you must be running from the username compiled into the game via Local_WIZARD in vmsconf.h, and you must specify "-D" on the command line when invoking NetHack. Note that -D must be uppercase, and it must be in quotes to prevent the C run-time library's program startup code from converting it into lowercase. $ @hackdir:nethack "-D" Any character name you specify will be ignored in favor of "wizard". 12. At program startup time, NetHack uses the empty file PERM to prevent two different processes from using the same character name (under the same UIC ownership) at the same time. It does this by temporarily giving that file a second directory entry named PERM.LOCK, then removing the alternate entry once started. If the PERM file is missing or inaccessible, NetHack will give a message and then quit. Several possible messages and their usual causes are: Can't find file perm;1 to lock! PERM.;1 is missing from the playground directory. Fix: reinstall the playground directory using install.com, or use CREATE or an editor to make an empty file named PERM. Version number must be 1. Can't lock perm;1 due to directory protection. The playground directory is not allowing write access. Fix: players need to be able to write files for dungeon levels and "bones" into the playground directory. Set the protection or ACL on the xxx.DIR;1 file in the playground's parent directory to allow write access. Can't unlink perm.lock;1. The empty file PERM.;1 is protected against delete access; only matters under some versions of VMS. Fix: set the protection or ACL on PERM.;1 to allow delete access to players. Under VMS V5.5-2, delete access is not necessary. PERM does not have to remain writable. Waiting for access to perm;1. (# retries left). If some other process is also starting up NetHack at about the same time, you may have to wait a short period. NetHack will retry once per second, counting down to 0. If 0 is reached, the message Perhaps there is an old perm.lock;1 around? will be displayed and then NetHack will give up. Fix: to forcibly remove a stale PERM.LOCK entry, issue the following command $ SET FILE/REMOVE PERM.LOCK;1 from the playground directory. The file PERM should remain intact. Do not use that command for real files, only alternate directory entries. If output from a DIRECTORY command on the playground reports PERM.LOCK;1 no such file then someone has deleted PERM.;1 while the synonym entry was still in place, and PERM.LOCK was left as a dangling name which no longer points at any file. The SET FILE/REMOVE command above will fix the dangling name; a new PERM.;1 will need to be created as mentioned above. In similar fashion, synchronized access to the scoreboard file RECORD is accomplished using temporary entry RECORD.LOCK and LOGFILE using entry LOGFILE.LOCK. 13. Unless you have both Motif and the Athena Widget set from MIT, you will not be able to use the X11 interface on VMS. Even if you do have both those things, such a configuration has not been tested and there are no provisions for it in vmsbuild.com. Makefile.src does have the extra source files listed, but not the necessary libraries. The X11 port will not compile and link with DECwindows, but it will be able to display on a VMS DECwindows X server provided that it and its Unix X client have a compatible transport between them (either TCP/IP added to VMS or DECnet added to Unix) and session security is set up appropriately. You'll need to add the contents of file [.win.X11]NetHack.ad into your DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT, and modify some of the lines. The DECwindows window manager does not support having input focus automatically follow the pointer, so you should uncomment the "NetHack*autofocus" resource line. (For Motif this may not be necessary, depending on customization options.) Uncommenting the "NetHack*slow" line is highly recommended. You'll also need to set "NetHack*fonts: fixed" (rather than "variable"), and either set the map font to "fixed" too or install the "nh10" font that comes in file [.win.X11]nh10.bdf. If NetHack warns that the map font is variable, then something isn't set up properly. After creating or modifying decw$xdefaults.dat, you must restart the window manager in order for any changes to take effect; it's easiest to just make the session manager quit and then log in again. 14. If necessary, send problem reports via e-mail to Always include version information for NetHack, the operating system, and the C compiler used. 20-OCT-2003 minimally updated 9-NOV-2015... nethack-3.6.0/sys/vms/Makefile.dat0000664000076400007660000001005412536476415016004 0ustar paxedpaxed# NetHack Makefile (VMS) - data files: special levels and other data. # NetHack 3.6 Makefile.dat $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ # Copy this file to [.dat]Makefile.; no editing needed. MAKE = $(MMS) CD = set default ECHO = write sys$output NOOP = continue # don't do anything interesting RUN = mcr # simplest way to pass command line args TOUCH = append/New _NLA0: # only one file per $(TOUCH) # support directories, relative to each other and to 'src' DAT = [-.dat] UTL = [-.util] WINSHR = [-.win.share] WINX11 = [-.win.X11] # utilities; must match Makefile.utl in spelling and punctuation MAKEDEFS = $(UTL)makedefs.exe; LEVCOMP = $(UTL)lev_comp.exe; DGNCOMP = $(UTL)dgn_comp.exe; DLB = $(UTL)dlb.exe; TILE2X11 = $(UTL)tile2x11.exe; UTILMARKER = $(UTL)util.timestamp; # note: filespecs have enough punctuation to satisfy DELETE MARKERS = spec_levs.timestamp;,quest_levs.timestamp; VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.; DUNGEON = dungeon.; X11TILES= x11tiles.; # note: the level lists need to be space separated QUESTLEVS = Arch.des Barb.des Caveman.des Healer.des Knight.des \ Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des \ Valkyrie.des Wizard.des SPECLEVS = bigroom.des castle.des endgame.des gehennom.des knox.des \ medusa.des mines.des oracle.des sokoban.des tower.des yendor.des all : $(VARDAT) $(DUNGEON) $(MARKERS) $(DLB) @ $(ECHO) "data files are up to date." # these are convenience targets for "manual" interactive use spec_levs : spev_levs.timestamp @ $(ECHO) "special levels are up to date." quest_levs : quest_levs.timestamp @ $(ECHO) "quest levels are up to date." dungeon : $(DUNGEON) @ $(ECHO) "dungeon is up to date." data : data.; @ $(NOOP) rumors : rumors.; @ $(NOOP) quest.dat : quest.dat; @ $(NOOP) oracles : oracles.; @ $(NOOP) options : options.; @ $(NOOP) x11tiles : $(X11TILES) @ $(NOOP) $(MAKEDEFS) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(MAKEDEFS) @ $(CD) $(DAT) $(DGNCOMP) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(DGNCOMP) @ $(CD) $(DAT) $(LEVCOMP) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(LEVCOMP) @ $(CD) $(DAT) $(DLB) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(DLB) @ $(CD) $(DAT) $(TILE2X11) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(TILE2X11) @ $(CD) $(DAT) $(X11TILES) : $(TILE2X11) \ $(WINSHR)monsters.txt $(WINSHR)objects.txt $(WINSHR)other.txt $(RUN) $(TILE2X11) \ $(WINSHR)monsters.txt $(WINSHR)objects.txt $(WINSHR)other.txt pet_mark.xbm : $(WINX11)pet_mark.xbm copy $(WINX11)pet_mark.xbm pet_mark.xbm rip.xpm : $(WINX11)rip.xpm copy $(WINX11)rip.xpm rip.xpm data.; : data.base $(MAKEDEFS) $(RUN) $(MAKEDEFS) -d rumors.; : rumors.tru rumors.fal $(MAKEDEFS) $(RUN) $(MAKEDEFS) -r quest.dat; : quest.txt $(MAKEDEFS) $(RUN) $(MAKEDEFS) -q oracles.; : oracles.txt $(MAKEDEFS) $(RUN) $(MAKEDEFS) -h # note: 'options' should have already been made when include/date.h was created options.; : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -v spec_levs.timestamp; : $(SPECLEVS) $(LEVCOMP) $(RUN) $(LEVCOMP) $(SPECLEVS) $(TOUCH) spec_levs.timestamp; quest_levs.timestamp; : $(QUESTLEVS) $(LEVCOMP) $(RUN) $(LEVCOMP) $(QUESTLEVS) $(TOUCH) quest_levs.timestamp; $(DUNGEON) : dungeon.def $(MAKEDEFS) $(DGNCOMP) $(RUN) $(MAKEDEFS) -e !dungeon.def -> dungeon.pdf $(RUN) $(DGNCOMP) dungeon.pdf !dungeon.pdr -> dungeon clean : - if f$search("*.*;-1").nes."" then purge - if f$search("dungeon.pdf").nes."" then delete dungeon.pdf; - if f$search("*.timestamp").nes."" then delete $(MARKERS) spotless : clean - delete $(VARDAT) - if f$search("$(DUNGEON)").nes."" then delete $(DUNGEON) - if f$search("*.lev").nes."" then delete *.lev; - if f$search("$(X11TILES)").nes."" then delete $(X11TILES) - if f$search("*.x%m").nes."" then delete *.x%m; !*.xbm,*.xpm - if f$search("nh*.dlb").nes."" then delete nh*.dlb; - if f$search("nhdat.lst").nes."" then delete nhdat.lst; nethack-3.6.0/sys/vms/Makefile.doc0000664000076400007660000000457412536476415016013 0ustar paxedpaxed# NetHack Makefile (VMS) - for the [Unix] documentation. # NetHack 3.6 Makefile.doc $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ # Copy this file to [.doc]Makefile. and edit it if needed. GUIDEBOOK = Guidebook. # regular ASCII file #GUIDEBOOK = Guidebook.ps # PostScript file #GUIDEBOOK = Guidebook.dvi # TeX device-independent file ALLDOCS = $(GUIDEBOOK) #ALLDOCS = $(GUIDEBOOK) manpages NOOP = ! Guidebook : $(GUIDEBOOK) $(NOOP) # the basic guidebook #Guidebook. : Guidebook.mn # #tbl tmac.n Guidebook.mn | nroff | col -bx > Guidebook # write sys$output "Guidebook.mn cannot be processed under VMS." Guidebook. : Guidebook.txt # distributed version of plain text copy Guidebook.txt Guidebook. # Fancier output for those with ditroff, psdit and a PostScript printer. #Guidebook.ps : Guidebook.mn # #tbl tmac.n Guidebook.mn | ditroff | psdit > Guidebook.ps # write sys$output "Guidebook.mn cannot be processed under VMS." Guidebook.ps : Guidebook.dvi # generated with LaTeX dvi2ps Guidebook # Guidebook.tex is the same as Guidebook.mn but formatted with LaTeX. # - The invocation command for LaTeX may vary in different installations. # - To print Guidebook.dvi you need to use a suitable dvi-driver. # - LaTeX needs to be run twice; second pass uses Guidebook.aux made by first. Guidebook.dvi : Guidebook.tex latex Guidebook.tex latex Guidebook.tex all : $(ALLDOCS) $(NOOP) GAME = nethack MANDIR = HACKDIR: MANEXT = man #MANDIR = /usr/man/man6 #MANEXT = 6 # manual non-installation; raw man pages may be better than nothing GAMEMANCREATE = copy nethack.6 LEVMANCREATE = copy lev_comp.6 DGNMANCREATE = copy dgn_comp.6 RCVRMANCREATE = copy recover.6 # GAMEMANCREATE = nroff -man nethack.6 > # LEVMANCREATE = nroff -man lev_comp.6 > # DGNMANCREATE = nroff -man dgn_comp.6 > # RCVRMANCREATE = nroff -man recover.6 > manpages : - $(GAMEMANCREATE) $(MANDIR)$(GAME).$(MANEXT) - $(LEVMANCREATE) $(MANDIR)lev_comp.$(MANEXT) - $(DGNMANCREATE) $(MANDIR)dgn_comp.$(MANEXT) - $(RCVRMANCREATE) $(MANDIR)recover.$(MANEXT) spotless : - if f$search("Guidebook.") .nes."" then delete Guidebook.;* - if f$search("Guidebook.ps") .nes."" then delete Guidebook.ps;* - if f$search("Guidebook.dvi").nes."" then delete Guidebook.dvi;* - if f$search("Guidebook.aux").nes."" then delete Guidebook.aux;* - if f$search("Guidebook.log").nes."" then delete Guidebook.log;* nethack-3.6.0/sys/vms/Makefile.src0000664000076400007660000004521012621042434016006 0ustar paxedpaxed# NetHack Makefile (VMS) - for building nethack itself. # NetHack 3.6 Makefile.src $NHDT-Date: 1447314365 2015/11/12 07:46:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ # Copy this file to [.src]Makefile. and then edit it as needed. # The default configuration is for building with DEC C (aka Compaq C). # If you change CC or CFLAGS, make similar changes in [.util]Makefile. # # Note: modifying this Makefile will cause crtl.opt to be rebuilt, # which will trigger an update of makedefs, which will in turn # result in a full build of just about _everything_. MAKE = $(MMS) CD = set default ECHO = write sys$output NOOP = continue RUN = mcr TOUCH = append/New _NLA0: # only one file per $(TOUCH) # source tree, relative to 'src' and 'util' INC = [-.include] SYSSHR = [-.sys.share] SRC = [-.src] TTY = [-.win.tty] UTL = [-.util] VMS = [-.sys.vms] WINSHR = [-.win.share] X11 = [-.win.X11] MAKEFILE= $(SRC)Makefile. # if you are using gcc as your compiler: # uncomment the CC definition below if it's not in your environment # CC = gcc # set option flags for C compiler and linker # CFLAGS = /Prefix=All/Incl=$(INC)/noList # DECC in native mode #CFLAGS = /Include=$(INC)/noList # VAXC or GNUC #LFLAGS = /Debug/Map/Cross_Ref # for development #LFLAGS = /noTraceback/noMap # for installing w/ privs LFLAGS = /noMap LINK = link # DEC C (decc$shr linked by default) LIBS = MORELIBS = # VAX C or GNU C, using shareable image run-time library # (leave MORELIBS blank for VAX C) #LIBS = sys$share:vaxcrtl.exe/Shareable #MORELIBS = gnu_cc:[000000]gcclib.olb/Library # VAX C or GNU C, using object library run-time library # (leave LIBS blank for VAX C) #LIBS = gnu_cc:[000000]gcclib.olb/Library #MORELIBS = sys$library:vaxcrtl.olb/Library # Specific VMS object files SYSSRC = $(VMS)vmsmain.c,$(VMS)vmstty.c,$(VMS)vmsunix.c,\ $(VMS)vmsmisc.c,$(VMS)vmsfiles.c,$(VMS)vmsmail.c SYSOBJ = vmsmain.obj,vmstty.obj,vmsunix.obj,vmsmail.obj #,vmsmisc.obj,vmsfiles.obj LIBOPT = $(SRC)crtl.opt; ID_OPT = $(SRC)ident.opt; # termcap library TERMCAPSRC = tclib.c TERMCAPOBJ = ,tclib.obj # Set WINSRC and WINOBJ lines corresponding to your desired combination # of windowing systems. Also set windowing systems in config.h. # # a straight tty port using no native windowing system WINTTYSRC = $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \ $(TERMCAPSRC) WINTTYOBJ = getline.obj,termcap.obj,topl.obj,wintty.obj $(TERMCAPOBJ) # # an X11 port (not supported under DECwindows) WINX11SRC = $(X11)Window.c $(X11)dialogs.c $(X11)winX.c $(X11)winmap.c \ $(X11)winmenu.c $(X11)winmesg.c $(X11)winmisc.c $(X11)winstat.c \ $(X11)wintext.c $(X11)winval.c $(SRC)tile.c WINX11OBJ = Window.obj,dialogs.obj,winX.obj,winmap.obj,winmenu.obj,\ winmesg.obj,winmisc.obj,winstat.obj,wintext.obj,winval.obj,tile.obj # # WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) # make NetHack for VMS SYSTEM = SysVMS.timestamp; GAME = $(SRC)nethack.exe; # RANDOM is defined in vmsconf.h RANDSRC = random.c RANDOBJ = random.obj # ---------------------------------------- # # Nothing below this line should have to be changed. # # Other things that have to be reconfigured are in vmsconf.h, # and config.h VERSION = 3.5.0 MAKEDEFS = $(UTL)makedefs.exe; # timestamp files to reduce `make' overhead and shorten .obj dependency lists CONFIG_H = $(SRC)config.h-t HACK_H = $(SRC)hack.h-t # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c \ makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c \ role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ steal.c steed.c sys.c teleport.c timeout.c topten.c track.c trap.c \ u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ windows.c wizard.c worm.c worn.c write.c zap.c # generated source files (tile.c is handled separately via WINxxxSRC) GENCSRC = monstr.c vis_tab.c #tile.c # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC) # all .h files except date.h, onames.h, pm.h, and vis_tab.h which would # cause dependency loops if run through "make depend" # and dgn_comp.h, dgn_file.h, lev_comp.h, special level & dungeon files. # HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h color.h \ config.h config1.h context.h coord.h decl.h def_os2.h display.h \ dlb.h dungeon.h engrave.h extern.h flag.h func_tab.h global.h \ hack.h lev.h macconf.h mextra.h mfndpos.h micro.h \ mkroom.h monattk.h mondata.h monflag.h monst.h monsym.h obj.h \ objclass.h os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h \ region.h rm.h sp_lev.h spell.h sys.h system.h tcap.h timeout.h \ tosconf.h tradstdc.h trampoli.h trap.h unixconf.h vision.h \ vmsconf.h wintty.h winX.h winprocs.h wintype.h you.h youprop.h #HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\ # lev_comp.h dgn_comp.h dgn_file.h # the following .obj's should be made before any others (for makedefs) FIRSTOBJ = vmsmisc.obj,vmsfiles.obj,monst.obj,objects.obj # split up long list so that we can write pieces of it into nethack.opt HOBJ1 = allmain.obj,alloc.obj,apply.obj,artifact.obj,attrib.obj, \ ball.obj,bones.obj,botl.obj,cmd.obj,dbridge.obj,decl.obj, \ detect.obj,dig.obj,display.obj,dlb.obj,do.obj,do_name.obj,do_wear.obj HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ dungeon.obj,eat.obj,end.obj,engrave.obj,exper.obj,explode.obj, \ extralev.obj,files.obj,fountain.obj,hack.obj,hacklib.obj,invent.obj HOBJ3 = light.obj,lock.obj,mail.obj,makemon.obj,mapglyph.obj,mcastu.obj, \ mhitm.obj,mhitu.obj,minion.obj,mklev.obj,mkmap.obj,mkmaze.obj, \ mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj,monstr.obj HOBJ4 = mplayer.obj,mthrowu.obj,muse.obj,music.obj,o_init.obj,objnam.obj, \ options.obj,pager.obj,pickup.obj,pline.obj,polyself.obj, \ potion.obj,pray.obj,priest.obj,quest.obj,questpgr.obj,read.obj HOBJ5 = rect.obj,region.obj,restore.obj,rip.obj,rnd.obj,role.obj, \ rumors.obj,save.obj,shk.obj,shknam.obj,sit.obj,sounds.obj,sp_lev.obj, \ spell.obj,steal.obj,steed.obj,sys.obj,teleport.obj,timeout.obj, \ topten.obj, track.obj,trap.obj HOBJ6 = u_init.obj,uhitm.obj,vault.obj,vision.obj,vis_tab.obj,weapon.obj, \ were.obj,wield.obj,windows.obj,wizard.obj,worm.obj,worn.obj, \ write.obj,zap.obj,version.obj HOBJ = $(FIRSTOBJ) $(SYSOBJ) $(WINOBJ) $(RANDOBJ) \ $(HOBJ1) $(HOBJ2) $(HOBJ3) $(HOBJ4) $(HOBJ5) $(HOBJ6) # simpler target name nethack : $(GAME) @ $(ECHO) "nethack is up to date." $(GAME) : $(SYSTEM) @ $(NOOP) $(SYSTEM) : $(LIBOPT) $(ID_OPT) $(HOBJ) nethack.opt @ $(ECHO) "Linking ..." $(LINK)/Exe=$(GAME) $(LFLAGS) nethack.opt/Opt,$(LIBOPT)/Opt,$(ID_OPT)/Opt $(TOUCH) $(SYSTEM) all : $(GAME) @ $(ECHO) "nethack is up to date." # linker options file for nethack's object modules nethack.opt : $(MAKEFILE) # this file open/Write f nethack.opt write f "! nethack.opt" @ write f f$edit("$(SYSOBJ)","COLLAPSE") @ write f f$edit("$(WINOBJ)","COLLAPSE") @ write f f$edit("$(RANDOBJ)","COLLAPSE") @ write f f$edit("$(FIRSTOBJ)","COLLAPSE") @ write f f$edit("$(HOBJ1)","COLLAPSE") @ write f f$edit("$(HOBJ2)","COLLAPSE") @ write f f$edit("$(HOBJ3)","COLLAPSE") @ write f f$edit("$(HOBJ4)","COLLAPSE") @ write f f$edit("$(HOBJ5)","COLLAPSE") @ write f f$edit("$(HOBJ6)","COLLAPSE") @ write f "sys$library:starlet.olb/Include=(lib$initialize) @ write f \ "psect_attr=lib$initialize, Con,Usr,noPic,Rel,Gbl,noShr,noExe,Rd,noWrt,Long" @ write f "iosegment=128" close f # linker options file for run-time libraries, also used by $(UTL)Makefile $(LIBOPT) : $(MAKEFILE) # this file open/Write f $(LIBOPT) write f "! crtl.opt" write f "$(LIBS)" write f "$(MORELIBS)" close f # simplified target name, for interactive convenience crtl.opt : $(LIBOPT) @ $(NOOP) # linker options file for version number, also used by $(UTL)Makefile $(ID_OPT) : $(MAKEFILE) # this file open/Write f $(ID_OPT) write f "! ident.opt" write f "identification=""$(VERSION)""" close f # simplified target name, for interactive convenience ident.opt : $(ID_OPT) @ $(NOOP) # dependencies for makedefs and its outputs, which the util # Makefile is responsible for keeping up to date # # special rules, to force update of makedefs, real dependencies should be # below in the 'make depend' output. monst.obj : $(CC) $(CFLAGS) monst.c @- if f$search("$(MAKEDEFS)").nes."" then delete $(MAKEDEFS) objects.obj : $(CC) $(CFLAGS) objects.c @- if f$search("$(MAKEDEFS)").nes."" then delete $(MAKEDEFS) $(MAKEDEFS) : $(FIRSTOBJ) $(UTL)makedefs.c \ $(CONFIG_H) $(INC)permonst.h $(INC)objclass.h \ $(INC)monsym.h $(INC)artilist.h $(INC)dungeon.h \ $(INC)obj.h $(INC)monst.h $(INC)you.h $(INC)flag.h \ $(INC)dlb.h $(INC)patchlevel.h $(INC)qtext.h \ $(LIBOPT) $(ID_OPT) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(MAKEDEFS) @ $(CD) $(SRC) $(INC)onames.h : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)onames.h @ $(CD) $(SRC) $(INC)pm.h : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)pm.h @ $(CD) $(SRC) monstr.c : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(SRC)monstr.c @ $(CD) $(SRC) # both vis_tab.h and vis_tab.c are made at the same time by makedefs $(INC)vis_tab.h : vis_tab.c $(TOUCH) $(INC)vis_tab.h vis_tab.c : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(SRC)vis_tab.c @ $(CD) $(SRC) $(SRC)tile.c : $(WINSHR)tilemap.c $(HACK_H) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(SRC)tile.c @ $(CD) $(SRC) # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # # hack.h depends on makedefs' output, so we know makedefs will be # up to date before being executed; kill old date.h to force update $(INC)date.h : $(VERSOURCES) $(HACK_H) @- if f$search("$(INC)date.h").nes."" then delete $(INC)date.h;* $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)date.h @ $(CD) $(SRC) # special targets clean : - if f$search("*.*;-2").nes."" then purge/Keep=2 - if f$search("$(INC)*.*;-2").nes."" then purge/Keep=2 $(INC) /Exclude=*conf*.h - if f$search("*.obj").nes."" then delete *.obj;* - if f$search("*.h-t").nes."" then delete *.h-t;* !$(HACK_H),$(CONFIG_H) spotless : clean - if f$search("*.*;-1).nes."" then purge - if f$search("$(INC)*.*;-1").nes."" then purge $(INC) - if f$search("$(SYSTEM)").nes."" then delete $(SYSTEM) - if f$search("$(GAME)").nes."" then delete $(GAME) - delete monstr.c;,vis_tab.c;,$(INC)vis_tab.h;,\ $(INC)pm.h;,$(INC)onames.h;,$(INC)date.h; - if f$search("tile.c").nes."" then delete tile.c; - if f$search("tclib.c").nes."" then delete tclib.c; - if f$search("random.c").nes."" then delete random.c; - if f$search("nethack.olb").nes."" then delete nethack.olb; - if f$search("*.opt").nes."" then delete *.opt; !nethack.opt,$(LIBOPT),$(ID_OPT) # dependencies (mostly cloned from sys/unix/Makefile.src) # config.h timestamp $(CONFIG_H) : $(INC)config.h $(INC)config1.h $(INC)tradstdc.h $(INC)global.h \ $(INC)coord.h $(INC)vmsconf.h $(INC)system.h \ $(INC)unixconf.h $(INC)os2conf.h $(INC)micro.h \ $(INC)pcconf.h $(INC)tosconf.h $(INC)amiconf.h \ $(INC)macconf.h $(INC)beconf.h $(INC)wceconf.h \ $(INC)ntconf.h $(TOUCH) $(CONFIG_H) # hack.h timestamp $(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \ $(INC)dungeon.h $(INC)monsym.h $(INC)mkroom.h \ $(INC)objclass.h $(INC)youprop.h $(INC)prop.h \ $(INC)permonst.h $(INC)monattk.h \ $(INC)monflag.h $(INC)mondata.h $(INC)pm.h \ $(INC)wintype.h $(INC)context.h $(INC)decl.h $(INC)quest.h \ $(INC)spell.h $(INC)color.h $(INC)obj.h \ $(INC)you.h $(INC)attrib.h $(INC)monst.h \ $(INC)mextra.h $(INC)skills.h \ $(INC)onames.h $(INC)timeout.h $(INC)trap.h \ $(INC)flag.h $(INC)rm.h $(INC)vision.h \ $(INC)display.h $(INC)engrave.h $(INC)rect.h $(INC)region.h \ $(INC)winprocs.h $(INC)wintty.h $(INC)trampoli.h $(INC)sys.h $(TOUCH) $(HACK_H) # VMS-specific code vmsmain.obj : $(VMS)vmsmain.c $(HACK_H) $(INC)dlb.h vmstty.obj : $(VMS)vmstty.c $(HACK_H) $(INC)wintty.h $(INC)tcap.h vmsunix.obj : $(VMS)vmsunix.c $(HACK_H) vmsmisc.obj : $(VMS)vmsmisc.c $(VMS)oldcrtl.c $(CONFIG_H) vmsfiles.obj : $(VMS)vmsfiles.c $(CONFIG_H) vmsmail.obj : $(VMS)vmsmail.c $(CONFIG_H) $(INC)mail.h \ $(INC)wintype.h $(INC)winprocs.h # conditionally used code -- VMS always wants these random.obj : random.c $(HACK_H) random.c : $(SYSSHR)random.c copy $(SYSSHR)random.c random.c tclib.obj : tclib.c $(CONFIG_H) tclib.c : $(SYSSHR)tclib.c copy $(SYSSHR)tclib.c tclib.c # user interface code -- VMS uses tty (1st 4) only getline.obj : $(TTY)getline.c $(HACK_H) $(INC)func_tab.h termcap.obj : $(TTY)termcap.c $(HACK_H) $(INC)tcap.h topl.obj : $(TTY)topl.c $(HACK_H) $(INC)tcap.h wintty.obj : $(TTY)wintty.c $(HACK_H) $(INC)dlb.h \ $(INC)date.h $(INC)patchlevel.h $(INC)tcap.h Window.obj : $(X11)Window.c $(INC)xwindowp.h $(INC)xwindow.h $(CONFIG_H) dialogs.obj : $(X11)dialogs.c $(CONFIG_H) winX.obj : $(X11)winX.c $(HACK_H) $(INC)winX.h $(INC)dlb.h \ $(INC)patchlevel.h $(X11)nh72icon $(X11)nh56icon $(X11)nh32icon winmap.obj : $(X11)winmap.c $(INC)xwindow.h $(HACK_H) $(INC)dlb.h \ $(INC)winX.h $(INC)tile2x11.h winmenu.obj : $(X11)winmenu.c $(HACK_H) $(INC)winX.h winmesg.obj : $(X11)winmesg.c $(INC)xwindow.h $(HACK_H) $(INC)winX.h winmisc.obj : $(X11)winmisc.c $(HACK_H) $(INC)func_tab.h $(INC)winX.h winstat.obj : $(X11)winstat.c $(HACK_H) $(INC)winX.h wintext.obj : $(X11)wintext.c $(HACK_H) $(INC)winX.h $(INC)xwindow.h winval.obj : $(X11)winval.c $(HACK_H) $(INC)winX.h tile.obj : $(SRC)tile.c $(HACK_H) monstr.obj : monstr.c $(CONFIG_H) vis_tab.obj : vis_tab.c $(CONFIG_H) $(INC)vis_tab.h # general code allmain.obj : allmain.c $(HACK_H) alloc.obj : alloc.c $(CONFIG_H) apply.obj : apply.c $(HACK_H) artifact.obj : artifact.c $(HACK_H) $(INC)artifact.h $(INC)artilist.h attrib.obj : attrib.c $(HACK_H) ball.obj : ball.c $(HACK_H) bones.obj : bones.c $(HACK_H) $(INC)lev.h botl.obj : botl.c $(HACK_H) cmd.obj : cmd.c $(HACK_H) $(INC)func_tab.h dbridge.obj : dbridge.c $(HACK_H) decl.obj : decl.c $(HACK_H) detect.obj : detect.c $(HACK_H) $(INC)artifact.h dig.obj : dig.c $(HACK_H) display.obj : display.c $(HACK_H) dlb.obj : dlb.c $(CONFIG_H) $(INC)dlb.h do.obj : do.c $(HACK_H) $(INC)lev.h do_name.obj : do_name.c $(HACK_H) do_wear.obj : do_wear.c $(HACK_H) dog.obj : dog.c $(HACK_H) dogmove.obj : dogmove.c $(HACK_H) $(INC)mfndpos.h dokick.obj : dokick.c $(HACK_H) dothrow.obj : dothrow.c $(HACK_H) drawing.obj : drawing.c $(HACK_H) $(INC)tcap.h dungeon.obj : dungeon.c $(HACK_H) $(INC)dgn_file.h $(INC)dlb.h $(INC)lev.h eat.obj : eat.c $(HACK_H) end.obj : end.c $(HACK_H) $(INC)lev.h $(INC)dlb.h engrave.obj : engrave.c $(HACK_H) $(INC)lev.h exper.obj : exper.c $(HACK_H) explode.obj : explode.c $(HACK_H) extralev.obj : extralev.c $(HACK_H) files.obj : files.c $(HACK_H) $(INC)dlb.h $(INC)wintty.h #zlib.h fountain.obj : fountain.c $(HACK_H) hack.obj : hack.c $(HACK_H) hacklib.obj : hacklib.c $(HACK_H) invent.obj : invent.c $(HACK_H) light.obj : light.c $(HACK_H) $(INC)lev.h lock.obj : lock.c $(HACK_H) mail.obj : mail.c $(HACK_H) $(INC)mail.h makemon.obj : makemon.c $(HACK_H) mapglyph.obj : mapglyph.c $(HACK_H) $(INC)wintty.h $(INC)color.h mcastu.obj : mcastu.c $(HACK_H) mhitm.obj : mhitm.c $(HACK_H) $(INC)artifact.h mhitu.obj : mhitu.c $(HACK_H) $(INC)artifact.h minion.obj : minion.c $(HACK_H) mklev.obj : mklev.c $(HACK_H) mkmap.obj : mkmap.c $(HACK_H) $(INC)sp_lev.h mkmaze.obj : mkmaze.c $(HACK_H) $(INC)sp_lev.h $(INC)lev.h mkobj.obj : mkobj.c $(HACK_H) mkroom.obj : mkroom.c $(HACK_H) mon.obj : mon.c $(HACK_H) $(INC)mfndpos.h mondata.obj : mondata.c $(HACK_H) monmove.obj : monmove.c $(HACK_H) $(INC)mfndpos.h $(INC)artifact.h monst.obj : monst.c $(CONFIG_H) $(INC)permonst.h $(INC)align.h \ $(INC)monattk.h $(INC)monflag.h $(INC)monsym.h \ $(INC)color.h mplayer.obj : mplayer.c $(HACK_H) mthrowu.obj : mthrowu.c $(HACK_H) muse.obj : muse.c $(HACK_H) music.obj : music.c $(HACK_H) #interp.c o_init.obj : o_init.c $(HACK_H) $(INC)lev.h objects.obj : objects.c $(CONFIG_H) $(INC)obj.h $(INC)objclass.h \ $(INC)prop.h $(INC)skills.h $(INC)color.h objnam.obj : objnam.c $(HACK_H) options.obj : options.c $(CONFIG_H) $(INC)objclass.h $(INC)flag.h \ $(HACK_H) $(INC)tcap.h pager.obj : pager.c $(HACK_H) $(INC)dlb.h pickup.obj : pickup.c $(HACK_H) pline.obj : pline.c $(HACK_H) polyself.obj : polyself.c $(HACK_H) potion.obj : potion.c $(HACK_H) pray.obj : pray.c $(HACK_H) priest.obj : priest.c $(HACK_H) $(INC)mfndpos.h quest.obj : quest.c $(HACK_H) $(INC)qtext.h questpgr.obj : questpgr.c $(HACK_H) $(INC)dlb.h $(INC)qtext.h read.obj : read.c $(HACK_H) rect.obj : rect.c $(HACK_H) region.obj : region.c $(HACK_H) $(INC)lev.h restore.obj : restore.c $(HACK_H) $(INC)lev.h $(INC)tcap.h rip.obj : rip.c $(HACK_H) rnd.obj : rnd.c $(HACK_H) role.obj : role.c $(HACK_H) rumors.obj : rumors.c $(HACK_H) $(INC)lev.h $(INC)dlb.h save.obj : save.c $(HACK_H) $(INC)lev.h shk.obj : shk.c $(HACK_H) shknam.obj : shknam.c $(HACK_H) sit.obj : sit.c $(HACK_H) $(INC)artifact.h sounds.obj : sounds.c $(HACK_H) sp_lev.obj : sp_lev.c $(HACK_H) $(INC)dlb.h $(INC)sp_lev.h spell.obj : spell.c $(HACK_H) steal.obj : steal.c $(HACK_H) steed.obj : steed.c $(HACK_H) sys.obj : sys.c $(HACK_H) teleport.obj : teleport.c $(HACK_H) timeout.obj : timeout.c $(HACK_H) $(INC)lev.h topten.obj : topten.c $(HACK_H) $(INC)dlb.h $(INC)patchlevel.h track.obj : track.c $(HACK_H) trap.obj : trap.c $(HACK_H) u_init.obj : u_init.c $(HACK_H) uhitm.obj : uhitm.c $(HACK_H) vault.obj : vault.c $(HACK_H) version.obj : version.c $(HACK_H) $(INC)dlb.h $(INC)date.h $(INC)patchlevel.h vision.obj : vision.c $(HACK_H) $(INC)vis_tab.h weapon.obj : weapon.c $(HACK_H) were.obj : were.c $(HACK_H) wield.obj : wield.c $(HACK_H) windows.obj : windows.c $(HACK_H) $(INC)wingem.h $(INC)winGnome.h wizard.obj : wizard.c $(HACK_H) $(INC)qtext.h worm.obj : worm.c $(HACK_H) $(INC)lev.h worn.obj : worn.c $(HACK_H) write.obj : write.c $(HACK_H) zap.obj : zap.c $(HACK_H) # eof nethack-3.6.0/sys/vms/Makefile.top0000664000076400007660000001077712536476415016052 0ustar paxedpaxed# NetHack Makefile (VMS) - top level for making & installing everything. # NetHack 3.6 Makefile.top $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ # Copy this file to Makefile.; edit the appropriate values for # GAMEDIR ("playground" location) and GAMEOWNER (UIC or identifier # for the owner of playground files). # usage: mms all,install # or mms no_tools,all,install # or substitute freeware `MMK' for Digital's `MMS'. MAKE = $(MMS) CD = set default ECHO = write sys$output EXEC = @ NOOP = continue # don't do anything interesting TOUCH = set file/truncate # multiple files per $(TOUCH), but no creation # support directories, relative to 'top' DAT = [.dat] DOC = [.doc] SRC = [.src] TOP = [-] # relative to the others UTL = [.util] VMS = [.sys.vms] GAMEDIR = # defaults to [.play] GAMEOWNER = # defaults to installer's UIC # these are the distributed values in [.include]vmsconf.h #GAMEDIR = DISK$USERS:[GAMES.NETHACK.3_5_X.PLAY] #GAMEOWNER = NHWIZARD # just about everything, except installation all : program utilities data dlb_data documentation @ $(ECHO) "all code and data is now up to date." program : $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) utilities : $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) data : $(CD) $(DAT) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) documentation : $(CD) $(DOC) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) install : program all_data make_directories create_writeable_files update @ $(ECHO) "installation is now complete." # assume there're no active games in progress update : place_readonly_files place_executable place_vms_support @ open/Write f tmp-update.com; @ write f "$ set noon" @ write f "$ if p1.eqs."""" then p1 = f$trnlnm(""HACKDIR"")" @ write f "$ if p1.eqs."""" then p1 = ""[.play]""" @ write f "$ old_default = f$environ(""DEFAULT"")" @ write f "$ set default 'p1'" @ write f\ "$ if f$search(""*.*;-2"").nes."""" then set file/prot=(s:rwed,o:rwed) *.*;-2" @ write f\ "$ if f$search(""*.*;-1"").nes."""" then set file/prot=(s:rwed,o:rwed) *.*;-1" @ write f "$ if f$search(""*.*;-1"").nes."""" then purge" @ write f "$! if f$search(""bones*.*"").nes."""" then $(TOUCH) bones*.*" @ write f "$! if f$search(""[.save]*"").nes."""" then $(TOUCH) [.save]*" @ write f "$ set default 'old_default'" @ write f "$ exit" @ close f - $(EXEC)tmp-update.com; $(GAMEDIR) !purge old version @ delete tmp-update.com; @ $(ECHO) "playground files updated." Guidebook : $(CD) $(DOC) $(MAKE)$(MAKEFLAGS) Guidebook @ $(CD) $(TOP) manpages : $(CD) $(DOC) $(MAKE)$(MAKEFLAGS) manpages @ $(CD) $(TOP) all_data : data dlb_data @ $(NOOP) dlb_data : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" dlb make_directories : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" directories create_writeable_files : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" writeable_files place_readonly_files : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" readonly_files place_executable : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" executable place_vms_support : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" termcap $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" procedure $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" documentation # 'make no_tools' should be done first if you don't have the appropriate # tools to process the parser and scanner for the special level and # dungeon compilers; doing so will copy distributed, pre-processed files # from [.sys.share] to [.util]. If you _do_ have the tools, be sure to # edit [.util]Makefile so that it uses the right ones. no_tools : $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) no_yacc $(MAKE)$(MAKEFLAGS) no_lex @ $(CD) $(TOP) # 'make clean' removes all the .obj files, but leaves around all the executables # and compiled data files. clean : $(CD) $(SRC) - $(MAKE)$(MAKEFLAGS) clean @ $(CD) $(TOP) $(CD) $(UTL) - $(MAKE)$(MAKEFLAGS) clean @ $(CD) $(TOP) # 'make spotless' returns the source tree to near-distribution condition. # it removes .obj files, executables, and compiled data files. spotless : $(CD) $(SRC) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) $(CD) $(UTL) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) $(CD) $(DAT) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) $(CD) $(DOC) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) nethack-3.6.0/sys/vms/Makefile.utl0000664000076400007660000003022312536476415016040 0ustar paxedpaxed# NetHack Makefile (VMS) - for utility programs. # NetHack 3.6 Makefile.utl $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copy this file to [.util]Makefile. and then edit it as needed. # The default configuration is for building with DEC C (aka Compaq C). # Settings for CC and CFLAGS ought to match the ones used in [.src]Makefile. MAKE = $(MMS) CD = set default ECHO = write sys$output MOVE = rename/New # within same device only MUNG = search/Exact/Match=NOR # to strip bogus #module directives NOOP = continue RM = delete/noConfirm RUN = mcr # simplest way to pass command line args TOUCH = append/New _NLA0: # only one file per $(TOUCH) # source tree, relative to 'src' and 'util' DAT = [-.dat] INC = [-.include] SYSSHR = [-.sys.share] SRC = [-.src] UTL = [-.util] VMS = [-.sys.vms] WINSHR = [-.win.share] WINX11 = [-.win.X11] # targets, with enough punctuation to keep MCR and DELETE happy MAKEDEFS= $(UTL)makedefs.exe; LEVCOMP = $(UTL)lev_comp.exe; DGNCOMP = $(UTL)dgn_comp.exe; DLB = $(UTL)dlb.exe; RECOVER = $(UTL)recover.exe; # used by $(DAT)Makefile for synchronization MARKER = $(UTL)util.timestamp; # if you are using gcc as your compiler, # uncomment the CC definition below if it's not in your environment # CC = gcc CFLAGS = /Prefix=All/Incl=$(INC)/noList # DECC in native mode #CFLAGS = /Include=$(INC)/noList # VAXC or GNUC LFLAGS = /noMap LIBS = $(SRC)crtl.opt/Options,$(SRC)ident.opt/Options # run-time library LINK = link # If you don't have yacc, byacc, or bison or just don't want to run any of # them, then make target "no_yacc" before trying to build lev_comp # or dgn_comp. You won't be able to modify *_comp.y though. # If you don't have lex or flex, then make target "no_lex" and leave # *_comp.l alone. $(VMS)lev_lex.h will be used to work-around some # suspect code included in the distributed copies of *_lex.c. # If you do either of the above, the corresponding value of YACC and/or LEX # below won't matter. # # Note: VMS POSIX V1.1 lex and yacc generate code which contains an # invalid #module directive; it order to prevent warnings for CC or # choking by GCC, the SEARCH command is used in an attempt to strip # then out. Otherwise MMS would quit when making the affected targets. # Each "munged" copy should be identical to its original if no #module # directives are present. # # yacc/lex programs to use to generate *_comp.c, *_comp.h, and *_lex.c. # choose xxxOUT that matches xxx tool's output YACC = bison /Define LEX = flex #YACC = yacc -d #LEX = lex #YACC = posix/Run posix$bin:yacc. "-d #LEX = posix/Run posix$bin:lex. " # blank means foo.y -> foo_tab.c & foo_tab.h YACCOUT = # bison #YACCOUT = ytab # VMS POSIX #YACCOUT = y_tab # DEC/Shell LEXOUT = lexyy # flex #LEXOUT = lex_yy # VMS POSIX # Nothing below this line should have to be changed. # linker options files LIBOPT = $(SRC)crtl.opt; ID_OPT = $(SRC)ident.opt; # timestamps for primary header files, matching src/Makefile CONFIG_H = $(SRC)config.h-t HACK_H = $(SRC)hack.h-t # utility .c files MAKESRC = makedefs.c SPLEVSRC = lev_yacc.c lev_lex.c lev_main.c DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c RECOVSRC = recover.c DLBSRC = dlb_main.c UTILSRCS = $(MAKESRC) $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC) panic.c VMSOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj # object files that provide access to NetHack's names NAMEOBJ1 = $(SRC)monst.obj,$(SRC)objects.obj NAMEOBJ2 = $(SRC)drawing.obj,$(SRC)decl.obj NAMEOBJS = $(NAMEOBJ1),$(NAMEOBJ2) # object files for makedefs MAKEOBJS = makedefs.obj,$(NAMEOBJ1) # object files for special levels compiler SPLEVOBJS = lev_main.obj,lev_yacc.obj,lev_lex.obj,panic.obj,\ $(SRC)alloc.obj,$(NAMEOBJS) # object files for dungeon compiler DGNCOMPOBJS = dgn_main.obj,dgn_yacc.obj,dgn_lex.obj,panic.obj,$(SRC)alloc.obj # object files for recovery utility RECOVOBJS = recover.obj # object files for dlb utility DLBOBJS = dlb_main.obj,panic.obj,$(SRC)alloc.obj,$(SRC)dlb.obj # fake target default : @ $(ECHO) "Oops! No target(s) specified...." all : $(MAKEDEFS) $(LEVCOMP) $(DGNCOMP) $(RECOVER) $(DLB) @ $(ECHO) "util is up to date." # special targets for folks without yacc/bison and or lex/flex no_yacc : copy $(SYSSHR)%%%_yacc.c $(UTL) copy $(SYSSHR)%%%_comp.h $(INC) @ $(ECHO) "distributed yacc output (*_yacc.c) copied into place" no_lex : copy $(SYSSHR)%%%_lex.c $(UTL) copy $(VMS)lev_lex.h $(UTL) @ $(ECHO) "distributed lex output (*_lex.c) copied into place" # alternate target names for possible interactive use makedefs : $(MAKEDEFS) @ $(ECHO) "makedefs is up to date." lev_comp : $(LEVCOMP) @ $(ECHO) "lev_comp is up to date." dgn_comp : $(DGNCOMP) @ $(ECHO) "dgn_comp is up to date." recover : $(RECOVER) @ $(ECHO) "recover is up to date." dlb : $(DLB) @ $(ECHO) "dlb is up to date." $(LIBOPT) : $(SRC)Makefile.; # linker options file $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(LIBOPT) @ $(CD) $(UTL) $(ID_OPT) : $(SRC)Makefile.; # linker options file $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(ID_OPT) @ $(CD) $(UTL) # dependencies for makedefs # $(MAKEDEFS) : $(MAKEOBJS) $(VMSOBJS) $(LIBOPT) $(ID_OPT) $(LINK) $(LFLAGS) $(MAKEOBJS),$(VMSOBJS),$(LIBS) @ $(TOUCH) $(MARKER) makedefs.obj : makedefs.c \ $(CONFIG_H) $(INC)permonst.h $(INC)objclass.h \ $(INC)monsym.h $(INC)artilist.h $(INC)dungeon.h \ $(INC)obj.h $(INC)monst.h $(INC)you.h $(INC)flag.h \ $(INC)dlb.h $(INC)patchlevel.h $(INC)qtext.h $(INC)onames.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -o $(INC)pm.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -p $(SRC)monstr.c : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -m # both vis_tab.h and vis_tab.c are made at the same time by makedefs -z $(INC)vis_tab.h : $(SRC)vis_tab.c $(TOUCH) $(INC)vis_tab.h $(SRC)vis_tab.c : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -z # the src Makefile is responsible for knowing when to call this, since # it knows all about the main src and include files $(INC)date.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -v # dependencies for lev_comp # $(LEVCOMP) : $(SPLEVOBJS) $(VMSOBJS) $(LIBOPT) $(ID_OPT) $(LINK)/Exe=$(LEVCOMP) $(LFLAGS) $(SPLEVOBJS),$(VMSOBJS),$(LIBS) lev_yacc.obj : $(HACK_H) $(INC)sp_lev.h lev_yacc.c $(CC) $(CFLAGS) lev_yacc.c lev_lex.obj : $(HACK_H) $(INC)lev_comp.h $(INC)sp_lev.h lev_lex.c @ if f$search("lev_lex.h").nes."" then $(MOVE) lev_lex.h stdio.h $(CC) $(CFLAGS) lev_lex.c @ if f$search("stdio.h").nes."" then $(MOVE) stdio.h lev_lex.h lev_main.obj : $(HACK_H) $(INC)sp_lev.h $(INC)tcap.h $(INC)date.h lev_main.c $(CC) $(CFLAGS) lev_main.c panic.obj : $(CONFIG_H) $(CC) $(CFLAGS) panic.c $(INC)lev_comp.h : lev_yacc.c $(TOUCH) $(INC)lev_comp.h lev_yacc.c : lev_comp.y $(YACC) lev_comp.y $(MUNG) 'f$parse("$(YACCOUT)","lev_comp_tab.c")' "#module" /Outp=lev_yacc.c @ if f$search("''f$parse("$(YACCOUT)","lev_comp_tab.c")'").nes."" then \ $(RM) 'f$parse("$(YACCOUT)","lev_comp_tab.c")' $(MOVE) 'f$parse("$(YACCOUT)","lev_comp_tab.h")' $(INC)lev_comp.h lev_lex.c : lev_comp.l $(LEX) lev_comp.l $(MUNG) 'f$parse("$(LEXOUT)","lev_comp_lex.c")' "#module" /Outp=lev_lex.c @ if f$search("''f$parse("$(LEXOUT)","lev_comp_lex.c")'").nes."" then \ $(RM) 'f$parse("$(LEXOUT)","lev_comp_lex.c")' # dependencies for dgn_comp # $(DGNCOMP) : $(DGNCOMPOBJS) $(VMSOBJS) $(LIBOPT) $(ID_OPT) $(LINK)/Exe=$(DGNCOMP) $(LFLAGS) $(DGNCOMPOBJS),$(VMSOBJS),$(LIBS) dgn_yacc.obj : $(CONFIG_H) $(INC)dgn_file.h $(INC)date.h dgn_yacc.c $(CC) $(CFLAGS) dgn_yacc.c dgn_lex.obj : $(CONFIG_H) $(INC)dgn_comp.h $(INC)dgn_file.h dgn_lex.c @ if f$search("lev_lex.h").nes."" then $(MOVE) lev_lex.h stdio.h $(CC) $(CFLAGS) dgn_lex.c @ if f$search("stdio.h").nes."" then $(MOVE) stdio.h lev_lex.h dgn_main.obj : $(CONFIG_H) dgn_main.c $(CC) $(CFLAGS) dgn_main.c $(INC)dgn_comp.h : dgn_yacc.c $(TOUCH) $(INC)dgn_comp.h dgn_yacc.c : dgn_comp.y $(YACC) dgn_comp.y $(MUNG) 'f$parse("$(YACCOUT)","dgn_comp_tab.c")' "#module" /Outp=dgn_yacc.c @ if f$search("''f$parse("$(YACCOUT)","dgn_comp_tab.c")'").nes."" then \ $(RM) 'f$parse("$(YACCOUT)","dgn_comp_tab.c")' $(MOVE) 'f$parse("$(YACCOUT)","dgn_comp_tab.h")' $(INC)dgn_comp.h dgn_lex.c : dgn_comp.l $(LEX) dgn_comp.l $(MUNG) 'f$parse("$(LEXOUT)","dgn_comp_lex.c")' "#module" /Outp=dgn_lex.c @ if f$search("''f$parse("$(LEXOUT)","dgn_comp_lex.c")'").nes."" then \ $(RM) 'f$parse("$(LEXOUT)","dgn_comp_lex.c")' # dependencies for recover # $(RECOVER) : $(RECOVOBJS) $(VMSOBJS) $(LIBOPT) $(ID_OPT) $(LINK) $(LFLAGS) $(RECOVOBJS),$(VMSOBJS),$(LIBS) recover.obj : $(CONFIG_H) recover.c # dependencies for dlb # $(DLB) : $(DLBOBJS) $(VMSOBJS) $(LIBOPT) $(ID_OPT) $(LINK)/Exe=$(DLB) $(LFLAGS) $(DLBOBJS),$(VMSOBJS),$(LIBS) dlb_main.obj : $(CONFIG_H) $(INC)dlb.h dlb_main.c # dependencies and build rules for tile utilities # TILEMAP = $(UTL)tilemap.exe; GIF2TXT = $(UTL)gif2txt.exe; TXT2PPM = $(UTL)txt2ppm.exe; TILE2X11 = $(UTL)tile2x11.exe; TILEUTILS = $(TILEMAP),$(GIF2TXT),$(TXT2PPM),$(TILE2X11) TEXTIO = $(UTL)tiletxt.obj,tiletext.obj,$(NAMEOBJS),$(SRC)vmsmisc.obj GIFREADERS = gifread.obj,panic.obj,$(SRC)alloc.obj PPMWRITERS = ppmwrite.obj,panic.obj,$(SRC)alloc.obj tileutils : $(TILEUTILS) @ $(NOOP) $(GIF2TXT) : $(GIFREADERS) $(TEXTIO) $(LIBOPT) $(ID_OPT) $(LINK)/Exe=$(GIF2TXT) $(LFLAGS) $(GIFREADERS),$(TEXTIO),$(LIBS) $(TXT2PPM) : $(PPMWRITERS) $(TEXTIO) $(LIBOPT) $(ID_OPT) $(LINK)/Exe=$(TXT2PPM) $(LFLAGS) $(PPMWRITERS),$(TEXTIO),$(LIBS) $(TILE2X11) : tile2x11.obj $(TEXTIO) $(LIBOPT) $(ID_OPT) $(LINK) $(LFLAGS) tile2x11.obj,$(TEXTIO),$(LIBS) $(TILEMAP) : tilemap.obj $(SRC)vmsmisc.obj $(LIBOPT) $(ID_OPT) $(LINK) $(LFLAGS) tilemap.obj,$(SRC)vmsmisc.obj,$(LIBS) $(SRC)tile.c : $(TILEMAP) $(RUN) $(TILEMAP) $(INC)tile.h : $(WINSHR)tile.h copy $(WINSHR)tile.h $(INC)tile.h # Force an explicit directory prefix on tiletxt.obj so that we don't get # unwanted "sticky defaults" when $(TEXTIO) is used in a comma-separated # list on the link command line. # $(UTL)tiletxt.obj : $(HACK_H) $(WINSHR)tilemap.c $(CC) $(CFLAGS) /Def=("TILETEXT")/Obj=$@ $(WINSHR)tilemap.c tilemap.obj : $(HACK_H) $(WINSHR)tilemap.c tiletext.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)tiletext.c gifread.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)gifread.c ppmwrite.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)ppmwrite.c tile2x11.obj : $(HACK_H) $(INC)tile.h $(INC)tile2x11.h $(WINX11)tile2x11.c # make sure object files from src are available when needed # $(SRC)alloc.obj : $(SRC)alloc.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) alloc.obj @ $(CD) $(UTL) $(SRC)monst.obj : $(SRC)monst.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) monst.obj @ $(CD) $(UTL) $(SRC)objects.obj : $(SRC)objects.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) objects.obj @ $(CD) $(UTL) $(SRC)decl.obj : $(SRC)decl.c $(HACK_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) decl.obj @ $(CD) $(UTL) $(SRC)drawing.obj : $(SRC)drawing.c $(HACK_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) drawing.obj @ $(CD) $(UTL) $(SRC)dlb.obj : $(SRC)dlb.c $(HACK_H) $(INC)dlb.h $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) dlb.obj @ $(CD) $(UTL) # make sure hack.h dependencies get transitive information $(HACK_H) : $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(HACK_H) @ $(CD) $(UTL) $(CONFIG_H) : $(INC)config.h $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(CONFIG_H) @ $(CD) $(UTL) # VMS specific dependencies $(SRC)vmsmisc.obj : $(VMS)vmsmisc.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) vmsmisc.obj @ $(CD) $(UTL) $(SRC)vmsfiles.obj : $(VMS)vmsfiles.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) vmsfiles.obj @ $(CD) $(UTL) clean : - if f$search("*.*;-1").nes."" then purge - if f$search("*.obj") .nes."" then $(RM) *.obj; spotless : clean - if f$search("%%%_lex.c") .nes."" then $(RM) %%%_lex.c; - if f$search("%%%_yacc.c").nes."" then $(RM) %%%_yacc.c; - if f$search("$(INC)%%%_comp.h").nes."" then $(RM) $(INC)%%%_comp.h;* - if f$search("$(INC)tile.h").nes."" then $(RM) $(INC)tile.h;* - if f$search("lev_lex.h") .nes."" then $(RM) lev_lex.h; - if f$search("*tab.c") .nes."" then $(RM) *tab.c; - if f$search("*.exe").nes."" then \ $(RM) $(MAKEDEFS),$(LEVCOMP),$(DGNCOMP),$(RECOVER),$(DLB) - if f$search("*.exe").nes."" then $(RM) $(TILEUTILS) - if f$search("$(MARKER)").nes."" then $(RM) $(MARKER) nethack-3.6.0/sys/vms/install.com0000664000076400007660000002431212627501605015734 0ustar paxedpaxed$ ! vms/install.com -- set up nethack 'playground' $ ! $ ! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ $ ! $ ! Use vmsbuild.com to create nethack.exe, makedefs, and lev_comp *first*. $ ! $ ! Note: this command procedure is also used by the top level Makefile $ ! if you build and install with MMS or MMK. In that situation, only the $ ! Makefile will need any editing. $ ! $ ! Edit this file to define gamedir & gameuic, or else invoke it with two $ ! command line parameters, as in: $ ! @[.sys.vms]install "disk$users:[games.nethack]" "games" $ ! or @[.sys.vms]install "[-.play]" "[40,1]" $ ! $ ! default location is old playground, default owner is installer $ gamedir = f$trnlnm("NETHACKDIR") !location of playground $ if gamedir.eqs."" then gamedir = f$trnlnm("HACKDIR") $ gameuic = f$user() !owner of playground $ ! --- nothing below this line should need to be changed --- $ if p1.nes."" then gamedir := 'p1' $ if p2.nes."" then gameuic := 'p2' $ $ ! note: all filespecs contain some punctuation, $ ! to avoid inadvertent logical name interaction $ play_files = "PERM.,RECORD.,LOGFILE.,PANICLOG." $ help_files = "HELP.,HH.,CMDHELP.,WIZHELP.,OPTHELP.,HISTORY.,LICENSE." $ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT,TRIBUTE." $ sysconf_file = "[.sys.vms]sysconf" $ guidebook = "[.doc]Guidebook.txt" $ invoc_proc = "[.sys.vms]nethack.com" $ trmcp_file = "[.sys.share]termcap" $ spec_files = "AIR.LEV,ASMODEUS.LEV,ASTRAL.LEV,BAALZ.LEV,BIGRM-%.LEV," - + "CASTLE.LEV,EARTH.LEV,FAKEWIZ%.LEV,FIRE.LEV," - + "JUIBLEX.LEV,KNOX.LEV,MEDUSA-%.LEV,MINEFILL.LEV," - + "MINETN-%.LEV,MINEND-%.LEV,ORACLE.LEV,ORCUS.LEV," - + "SANCTUM.LEV,SOKO%-%.LEV,TOWER%.LEV,VALLEY.LEV," - + "WATER.LEV,WIZARD%.LEV" $ spec_input = "bigroom.des castle.des endgame.des " - + "gehennom.des knox.des medusa.des mines.des " - + "oracle.des sokoban.des tower.des yendor.des" $ qstl_files = "%%%-GOAL.LEV,%%%-FIL%.LEV,%%%-LOCA.LEV,%%%-STRT.LEV" $ qstl_input = "Arch.des Barb.des Caveman.des Healer.des " - + "Knight.des Monk.des Priest.des Ranger.des Rogue.des " - + "Samurai.des Tourist.des Wizard.des Valkyrie.des" $ dngn_files = "DUNGEON." $ dngn_input = "dungeon.pdf" $ dlb_files = help_files + "," + data_files + "," - + spec_files + "," + qstl_files + "," + dngn_files $ data_libry = "nh-data.dlb" $ xtrn_files = "LICENSE.,HISTORY.,OPTIONS.,SYMBOLS." $ makedefs := $sys$disk:[-.util]makedefs $ lev_comp := $sys$disk:[-.util]lev_comp $ dgn_comp := $sys$disk:[-.util]dgn_comp $ dlb := $sys$disk:[-.util]dlb $ milestone = "write sys$output f$fao("" !5%T "",0)," $ if p3.nes."" .and. f$edit(p4,"UPCASE").nes."VERBOSE" then milestone = "!" $ echo = "write sys$output" $ warn = echo !could be "write sys$error" $! $! make sure we've got a playground location $ gamedir := 'gamedir' $ if gamedir.eqs."" then gamedir = "[.play]" !last ditch default $ gamedir = f$parse(gamedir,,,,"SYNTAX_ONLY") - ".;" $ if gamedir.eqs."" then write sys$error "% must specify playground directory" $ if gamedir.eqs."" then exit %x1000002C !ss$_abort $ $! $! ['p3' is used in Makefile.top] $ if p3.nes."" then goto make_'p3' $ $ milestone "" $! $make_data_plus_dlb: $make_data: $ ! start from a known location -- [.sys.vms] $ set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")' $! generate miscellaneous data files $ set default [-.-.dat] !move to data directory $ milestone "(data)" $ makedefs -d !data.base -> data $ milestone "(rumors)" $ makedefs -r !rumors.tru + rumors.fal -> rumors $ milestone "(oracles)" $ makedefs -h !oracles.txt -> oracles $ milestone "(dungeon preprocess)" $ makedefs -e !dungeon.def -> dungeon.pdf $ milestone "(quest text)" $ makedefs -q !quest.txt -> quest.dat $ milestone "(special levels)" $ lev_comp 'spec_input' !special levels $ milestone "(quest levels)" $ lev_comp 'qstl_input' !quest levels $ milestone "(dungeon compile)" $ dgn_comp 'dngn_input' !dungeon database $ set default [-] !move up $ if p3.nes."" .and. f$edit(p3,"UPCASE").nes."DATA_PLUS_DLB" then exit $ $make_dlb: $ ! start from a known location -- [.sys.vms] $ set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")' $! construct data library $ set default [-.-.dat] !move to data directory $ milestone "(dlb setup)" $! since DLB doesn't support wildcard expansion and we don't have shell $! file globbing, start by making a file listing its intended contents $ create nhdat.lst $ if f$search("nhdat.lst;-1").nes."" then - purge/noConfirm/noLog nhdat.lst $! an old data file might fool us later, so get rid of it $ if f$search(data_libry).nes."" then - delete/noConfirm/noLog 'data_libry';* $ if f$trnlnm("PFILE$").nes."" then close/noLog pfile$ $ open/Append pfile$ nhdat.lst $ i = 0 $dloop: $ g = f$element(i,",",dlb_files) $ if g.eqs."," then goto ddone $ wild = f$locate("*",g).ne.f$locate("%",g) $ fcnt = 0 $floop: $ f = f$search(g) $ if f.eqs."" then goto fdone $ fcnt = fcnt + 1 $! strip device, directory, and version from name $ f = f$parse(f,,,"NAME") + f$parse(f,,,"TYPE") $! strip trailing dot, if present, and change case $ f = f$edit(f + "#" - ".#" - "#","LOWERCASE") $ if f$extract(3,1,f).eqs."-" then - !"xyz-foo.lev" -> "Xyz-foo.lev" f = f$edit(f$extract(0,1,f),"UPCASE") + f$extract(1,255,f) $ write pfile$ f $ if wild then goto floop $fdone: $ if fcnt.eq.0 then warn "? no file(s) found for """,g,"""" $ i = i + 1 $ goto dloop $ddone: $ close pfile$ $ milestone "(dlb create)" $ dlb "-cfI" 'data_libry' nhdat.lst $ set default [-] !move up $ if p3.nes."" then exit $ $! $! set up the playground and save directories $ milestone "(directories)" $make_directories: $ srctree = f$environment("DEFAULT") $ set default 'gamedir' $ if f$parse("[-]").eqs."" then create/dir/log [-] !default owner & protection $ if f$parse("[]" ).eqs."" then - !needs to be world writable create/directory/owner='gameuic'/prot=(s:rwe,o:rwe,g:rwe,w:rwe)/log [] $ if f$search("SAVE.DIR;1").eqs."" then - create/directory/owner='gameuic'/prot=(s:rwe,o:rwe,g:rwe,w:rwe)/log - [.SAVE]/version_limit=2 $ set default 'srctree' $ if p3.nes."" then exit $! $! create empty writeable files -- logfile, scoreboard, multi-user access lock $! [if old versions are already present, validate and retain them if possible] $make_writeable_files: $ milestone "(writeable files)" !-!$ create/owner='gameuic'/prot=(s:rwed,o:rwed,g:rwed,w:rwed) - !-! 'gamedir''play_files' $ i = 0 $ploop: if f$trnlnm("PFILE$").nes."" then close/nolog pfile$ $ f = f$element(i,",",play_files) $ if f.eqs."," then goto pdone $ i = i + 1 $ f = gamedir + f $ if f$search(f).eqs."" then goto pmake !make it if not found $ if f$file_attrib(f,"RFM").nes."STMLF" then goto prej !must be stream_lf $ open/read/error=prej pfile$ 'f' $ read/end=ploop pfile$ pline !empty is ok $ close pfile$ $ pfield = f$element(0," ",pline) !1st field is version number $ if f$locate(".",pfield).lt.f$length(pfield) then goto ploop !keep $prej: rename/new_vers 'f' *.old !reject old version $pmake: create/fdl=sys$input:/owner='gameuic' 'f'/log file organization sequential protection (system:rwd,owner:rwd,group:rw,world:rw) record format stream_lf $ goto ploop $pdone: $ if p3.nes."" then exit $! $! copy over the remaining game files, then make them readonly $make_readonly_files: $ milestone "(readonly files)" $ if f$search("[.dat]''data_libry'").nes."" $ then call copyfiles 'f$string(data_libry+","+xtrn_files)' [.dat] "r" $ else !'dlb_files' is too long for a single command $ k = 200 + f$locate(",",f$extract(200,999,dlb_files)) $ call copyfiles 'f$extract(0,k,dlb_files)' [.dat] "r" $ call copyfiles 'f$extract(k+1,999,dlb_files)' [.dat] "r" $ endif $ if p3.nes."" then exit $! $make_executable: $ milestone "(nethack.exe)" $ call copy_file [.src]nethack.exe 'gamedir'nethack.exe "re" $ if p3.nes."" then exit $! $! provide invocation procedure (if available) $make_procedure: $ if f$search(invoc_proc).eqs."" then goto skip_dcl $ if f$search("''gamedir'nethack.com").nes."" then - if f$cvtime(f$file_attr("''gamedir'nethack.com","RDT")) - .ges. f$cvtime(f$file_attr(invoc_proc,"RDT")) then goto skip_dcl $ milestone "(nethack.com)" $ call copy_file 'invoc_proc' 'gamedir'nethack.com "re" $skip_dcl: $ if p3.nes."" then exit $! $! provide plain-text Guidebook doc file (if available) $make_documentation: $ if f$search(guidebook).eqs."" then goto skip_doc $ milestone "(Guidebook)" $ call copy_file 'guidebook' 'gamedir'Guidebook.doc "r" $skip_doc: $ if p3.nes."" then exit $! $! provide last-resort termcap file (if available) $make_termcap: $ if f$search(trmcp_file).eqs."" then goto skip_termcap $ if f$search("''gamedir'termcap").nes."" then goto skip_termcap $ milestone "(termcap)" $ call copy_file 'trmcp_file' 'gamedir'termcap "r" $skip_termcap: $ if p3.nes."" then exit $! $! provide template sysconf file (needed if nethack is built w/ SYSCF enabled) $make_sysconf: $ if f$search(sysconf_file).eqs."" then goto skip_sysconf $ if f$search("''gamedir'sysconf_file").nes."" then goto skip_sysconf $ milestone "(sysconf)" $ call copy_file 'sysconf_file' 'gamedir'sysconf "r" $! owner should be able to manually edit sysconf; others shouldn't $ set file/Prot=(s:rwd,o:rwd,g:r,w:r) 'gamedir'sysconf $skip_sysconf: $ if p3.nes."" then exit $! $! done $ milestone "" $ define/nolog nethackdir 'gamedir' $ define/nolog hackdir 'gamedir' $ echo - f$fao("!/ Nethack installation complete. !/ Playground is !AS !/",gamedir) $ exit $ $! $! copy one file, resetting the protection on an earlier version first $copy_file: subroutine $ if f$search(p2).nes."" then set file/Prot=(s:rwed,o:rwed) 'p2' $ copy/Prot=(s:'p3'wd,o:'p3'wd,g:'p3',w:'p3') 'p1' 'p2' $ set file/Owner='gameuic'/Prot=(s:'p3',o:'p3') 'p2' $endsubroutine !copy_file $ $! $! copy a comma-separated list of wildcarded files, one file at a time $copyfiles: subroutine $ i = 0 $lloop: $ g = f$element(i,",",p1) $ if g.eqs."," then goto ldone $ g = p2 + g $ wild = f$locate("*",g).ne.f$locate("%",g) $ fcnt = 0 $eloop: $ f = f$search(g) $ if f.eqs."" then goto edone $ fcnt = fcnt + 1 $ f = f - f$parse(f,,,"VERSION") $ e = f$parse(f,,,"NAME") + f$parse(f,,,"TYPE") $ call copy_file 'f' 'gamedir''e' "''p3'" $ if wild then goto eloop $edone: $ if fcnt.eq.0 then warn "? no file(s) found for """,g,"""" $ i = i + 1 $ goto lloop $ldone: $endsubroutine !copyfiles $ $! nethack-3.6.0/sys/vms/lev_lex.h0000664000076400007660000000160012536476415015401 0ustar paxedpaxed/* NetHack 3.6 lev_lex.h $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* "vms/lev_lex.h" copied into "util/stdio.h" for use in *_lex.c only! * This is an awful kludge to allow util/*_lex.c made by SunOS's `lex' * to be compiled as is. (It isn't needed with `flex' or VMS POSIX * `lex' and is benign when either of those configurations are used.) * It works because the actual setup of yyin & yyout is performed in * src/lev_main.c, where stdin & stdout are still correctly defined. * * The troublesome code is * #include "stdio.h" * ... * FILE *yyin = stdin, *yyout = stdout; * The file scope initializers with non-constant values require this * hack, and the quotes instead of brackets makes it easy to do. */ #include #ifdef stdin #undef stdin #endif #define stdin 0 #ifdef stdout #undef stdout #endif #define stdout 0 nethack-3.6.0/sys/vms/nethack.com0000775000076400007660000000457312536476415015726 0ustar paxedpaxed$! NetHack.Com -- sample command procedure for invoking NetHack 9-JAN-1993 $ v = 'f$verify(0)' $! $! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ $! $! Possible command line arguments include $! "-uConan-B" !play a barbarian named Conan $! "-u" "Merlin-W" !play a wizard named Merlin (slight variant of above) $! "-e" or "-E" !play an elf with default name (from environment $! ! [ie, NETHACKOPTIONS logical name] or VMS username) $! "-a" or "-A", "-b" or "-B", "-c" or "-C", ... !specify character type $! !note: "-s" is ambiguous between "play as a samurai" $! ! vs "show scoreboard", so use "-S" for the former $! "-x" or "-X" !play in 'explore' mode (practice for beginners) $! "-D" !play in 'wizard' mode (for debugging, available only $! ! to the username compiled into nethack.exe as WIZARD) $! "-dec" !turn on DECgraphics mode (VT100 line drawing, done $! ! automatically below if appropriate term attribs set) $! "-d" dir-path !specify an alternate playground directory (not $! ! recommended; define HACKDIR instead) $! $ $! $! assume this command procedure has been placed in the playground directory; $! get its device:[directory] $ hackdir = f$parse("_._;0",f$environ("PROCEDURE")) - "_._;0" $! $! hackdir should point to the 'playground' directory $ if f$trnlnm("HACKDIR").eqs."" then define hackdir 'hackdir' $! $! termcap is a text file defining terminal capabilities and escape sequences $ if f$trnlnm("TERMCAP").eqs."" then define termcap hackdir:termcap $! ! [ obsolete: now handled within nethack itself ] ! $! prior to VMS v6, the C Run-Time Library doesn't understand vt420 :-( ! $ TT$_VT400_Series = 113 ! $ if f$getdvi("TT:","DEVTYPE").eq.TT$_VT400_Series - ! .and. f$trnlnm("NETHACK_TERM").eqs."" then define nethack_term "vt400" $! $! use the VT100 line drawing character set if possible $ graphics = "" $ usropt = f$trnlnm("NETHACKOPTIONS") $ if usropt.eqs."" then usropt = f$trnlnm("HACKOPTIONS") $ if f$locate("DECG",f$edit(usropt,"UPCASE")) .ge. f$length(usropt) then - if f$getdvi("TT:","TT_DECCRT") .and. f$getdvi("TT:","TT_ANSICRT") then - $ graphics = " -dec" !select DECgraphics mode by default $! $! get input from the terminal, not from this .com file $ deassign sys$input $! $ nethack := $hackdir:nethack $ if p1.nes."-s" .and. p1.nes."-s all" then - nethack = nethack + graphics $ nethack "''p1'" "''p2'" "''p3'" "''p4'" "''p5'" "''p6'" "''p7'" "''p8'" $! nethack-3.6.0/sys/vms/oldcrtl.c0000664000076400007660000001342112536476415015405 0ustar paxedpaxed/* NetHack 3.6 oldcrtl.c $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Pat Rankin May'90 */ /* VMS NetHack support, not needed for vms 4.6,4.7,5.x,or later */ #ifdef VERYOLD_VMS /* * The following routines are used by NetHack but were not available * from the C Run-Time Library (VAXCRTL) prior to VMS V4.6. * * atexit, memcmp, memcpy, qsort, rename, vprintf, vsprintf * * Most of them are implemented here, but others will have to be worked * around in another fashion [such as '#define USE_OLDARGS' (even though * is available) to avoid the need for vprintf & vsprintf]. * */ #define REG register #define const #ifndef SUPPRESS_MEM_FUNCS /* note: hand optimized for VAX (hardware pre-decrement & post-increment) */ /* void *memset(void *, int, size_t) -- fill chunk of memory. */ char * memset(dst, fil, cnt) REG char *dst; REG char fil; REG int cnt; { char *dst_p = dst; while (--cnt >= 0) *dst++ = fil; return dst_p; } /* void *memcpy(void *, const void *, size_t) -- copy chunk of memory. */ char * memcpy(dst, src, cnt) REG char *dst; REG const char *src; REG int cnt; { char *dst_p = dst; while (--cnt >= 0) *dst++ = *src++; return dst_p; } /* void *memmove(void *, const void *, size_t) -- copy possibly overlapping * mem. */ char * memmove(dst, src, cnt) REG char *dst; REG const char *src; REG int cnt; { char *dst_p = dst; if (src == dst || cnt <= 0) { ; /* do nothing */ } else if (dst < src || dst >= src + cnt) { while (--cnt >= 0) *dst++ = *src++; } else { /* work backwards */ dst += cnt, src += cnt; while (--cnt >= 0) *--dst = *--src; } return dst_p; } /* void *memchr(const void *, int, size_t) -- search for a byte. */ char * memchr(buf, byt, len) REG const char *buf; REG char byt; REG int len; { while (--len >= 0) if (*buf++ == byt) /* found */ return (char *) --buf; return (char *) 0; /* not found */ } /* int memcmp(const void *, const void *, size_t) -- compare two chunks. */ int memcmp(buf1, buf2, len) REG const char *buf1; REG const char *buf2; REG int len; { while (--len >= 0) if (*buf1++ != *buf2++) return (*--buf1 - *--buf2); return 0; /* buffers matched */ } #endif /*!SUPPRESS_MEM_FUNCS*/ #ifndef SUPPRESS_ATEXIT /* int atexit(void (*)(void)) -- register an exit handler. */ #define MAX_EXIT_FUNCS 32 /* arbitrary (32 matches VAX C v3.x docs) */ struct ex_hndlr { long reserved, (*routine)(), arg_count, *arg1_addr; }; static int ex_cnt = 0; /* number of handlers registered so far */ static struct { long dummy_arg; struct ex_hndlr handler; /*(black box)*/ } ex_data[MAX_EXIT_FUNCS]; /* static handler data */ extern unsigned long sys$dclexh(); int atexit(function) void (*function)(); /* note: actually gets called with 1 arg */ { if (ex_cnt < MAX_EXIT_FUNCS) { ex_data[ex_cnt].dummy_arg = 0; /* ultimately receives exit reason */ ex_data[ex_cnt].handler.reserved = 0; ex_data[ex_cnt].handler.routine = (long (*) ()) function; ex_data[ex_cnt].handler.arg_count = 1; /*(required)*/ ex_data[ex_cnt].handler.arg1_addr = &ex_data[ex_cnt].dummy_arg; (void) sys$dclexh( &ex_data[ex_cnt].handler); /* declare exit handler */ return ++ex_cnt; /*(non-zero)*/ } else return 0; } #endif /*!SUPPRESS_ATEXIT*/ #ifndef SUPPRESS_RENAME /* int rename(const char *, const char *) -- rename a file (on same device). */ #ifndef EVMSERR #include #define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status)) #endif extern unsigned long lib$rename_file(); int rename(old_name, new_name) const char *old_name; const char *new_name; { struct dsc { unsigned short len, mbz; const char *adr; } old_dsc, new_dsc; unsigned long status; /* put strings into descriptors and call run-time library routine */ new_dsc.mbz = old_dsc.mbz = 0; /* type and class unspecified */ old_dsc.len = strlen(old_dsc.adr = old_name); new_dsc.len = strlen(new_dsc.adr = new_name); status = lib$rename_file(&old_dsc, &new_dsc); /* omit optional args */ if (!(status & 1)) { /* even => failure */ C$$TRANSLATE(status); return -1; } else /* odd => success */ return 0; } #endif /*!SUPPRESS_RENAME*/ #ifndef SUPPRESS_QSORT /* void qsort(void *, size_t, size_t, int (*)()) -- sort arbitrary collection. */ extern char *malloc(); /* assume no alloca() available */ extern void free(); void qsort(base, count, size, compare) char *base; int count; REG int size; int (*compare)(); { REG int i, cmp; REG char *next, *prev, *tmp = 0; char wrk_buf[512]; /* just use a shuffle sort (tradeoff between efficiency & simplicity) */ /* [Optimal if already sorted; worst case when initially reversed.] */ for (next = base, i = 1; i < count; i++) { prev = next, next += size; /* increment front pointer */ if ((cmp = (*compare)(next, prev)) < 0) { /* found element out of order; move other(s) up then re-insert it */ if (!tmp) tmp = size > (int) (sizeof wrk_buf) ? malloc(size) : wrk_buf; memcpy(tmp, next, size); /* save smaller element */ while (cmp < 0) { memcpy(prev + size, prev, size); /* move larger elem. up */ prev -= size; /* decrement back pointer */ cmp = (prev >= base ? (*compare)(tmp, prev) : 0); } memcpy(prev + size, tmp, size); /* restore small element */ } } if (tmp != 0 && tmp != wrk_buf) free(tmp); return; } #endif /*!SUPPRESS_QSORT*/ #endif /*VERYOLD_VMS*/ nethack-3.6.0/sys/vms/spec_lev.com0000775000076400007660000000627012536476415016105 0ustar paxedpaxed$ ! sys/vms/spec_lev.com -- preprocess nethack's special level compiler code $ ! $ ! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ $ ! $ ! This operation needs to be performed prior to executing vmsbuild.com. $ ! Process the scanning and parsing code for NetHack's special level $ ! and dungeon compilers. *.l and *.y are converted into *'.c and *.h. $ ! $ $ ! setup yacc/bison and lex/flex; $ ! (Uncomment the alternatives appropriate for your site; $ ! if yacc and lex are not defined, the pre-processed files $ ! distributed in sys/share will be copied and used.) $ ! yacc := bison /Define !native bison (w/ DCL CLD) $ ! yacc := $bison$dir:bison -y -d !'foreign' bison (w/o CLD) $ ! yacc := posix /Run/Input=nl: posix$bin:yacc. """-d $ ! yacc := $shell$exe:yacc -d !yacc from DEC/Shell $ ! lex := $flex$dir:flex !flex $ ! lex := posix /Run/Input=nl: posix$bin:lex. """ $ ! lex := $shell$exe:lex $ ! (Nothing below this line should need to be changed.) $ ! additional setup $ rename := rename/New_Vers $ mung := call mung ! not to be confused with teco :-) $ delete := delete/noConfirm $ search := search/Exact $ copy := copy/noConcat $ ! start from a known location -- [.sys.vms], then move to [-.-.util] $ cur_dir = f$environment("DEFAULT") $ set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")' $ set default [-.-.util] !move to utility directory $ $mung: subroutine $ ! kludge to strip bogus #module directives from POSIX-processed files $ ! in lieu of $ rename 'p1' 'p2' $ search/Match=NOR 'p1' "#module" /Output='p2' $ delete 'p1';* $ endsubroutine !mung $ $ ! first cleanup any old intermediate files (to safely handle blind renaming) $ if f$search("*tab.%").nes."" then delete *tab.%;* !yacc & bison $ if f$search("*yy.c") .nes."" then delete *yy.c;* !lex & flex $ $ ! process lev_comp.y into lev_yacc.c and ../include/lev_comp.h $ if f$type(yacc).eqs."STRING" $ then $ yacc lev_comp.y $ if f$search("y_tab.%").nes."" then rename y_tab.% lev_comp_tab.* $ if f$search("ytab.%") .nes."" then rename ytab.% lev_comp_tab.* $ else ! use preprocessed files $ copy [-.sys.share]lev_yacc.c,lev_comp.h []lev_comp_tab.* $ endif $ mung lev_comp_tab.c lev_yacc.c $ rename lev_comp_tab.h [-.include]lev_comp.h $ $ ! process lev_comp.l into lev_lex.c $ if f$type(lex).eqs."STRING" $ then $ lex lev_comp.l $ if f$search("lexyy.c").nes."" then rename lexyy.c lex_yy.* $ else ! use preprocessed file $ copy [-.sys.share]lev_lex.c []lex_yy.* $ endif $ mung lex_yy.c lev_lex.c $ $ ! process dgn_comp.y into dgn_yacc.c and ../include/dgn_comp.h $ if f$type(yacc).eqs."STRING" $ then $ yacc dgn_comp.y $ if f$search("y_tab.%").nes."" then rename y_tab.% dgn_comp_tab.* $ if f$search("ytab.%") .nes."" then rename ytab.% dgn_comp_tab.* $ else $ copy [-.sys.share]dgn_yacc.c,dgn_comp.h []dgn_comp_tab.* $ endif $ mung dgn_comp_tab.c dgn_yacc.c $ rename dgn_comp_tab.h [-.include]dgn_comp.h $ $ ! process dgn_comp.l into dgn_lex.c $ if f$type(lex).eqs."STRING" $ then $ lex dgn_comp.l $ if f$search("lexyy.c").nes."" then rename lexyy.c lex_yy.* $ else $ copy [-.sys.share]dgn_lex.c []lex_yy.* $ endif $ mung lex_yy.c dgn_lex.c $ $ ! done $ set default 'cur_dir' $ exit nethack-3.6.0/sys/vms/sysconf0000664000076400007660000000603512631241231015166 0ustar paxedpaxed# NetHack 3.6 sysconf $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # # Sample sysconf file for VMS. # The sysconf file is only used if NetHack is compiled with SYSCF defined. # It can be used to augment or override certain settings compiled into the # program. # # This file can also be used to set local system defaults for run-time # options, using the same syntax as an individual user's ./nethackrc file. # The options which take a space-separated list of usernames haven't been # implemented for VMS. #WIZARDS= #EXPLORERS=* #SHELLERS= # Limit the number of simultaneous games. (Setting a limit has a side-effect # of changing the file names for the games in progress. With no limit, they # are named NNNcccccc.*, when NNN is a decimal formatting of the users's UIC # value (group * 65536 + member; orinarily formatted as a pair of numbers # expressed in octal, [group,member]) and cccccc is the character name. # With a limit, they are named Llock.*, where L is a single letter.) # Limit is documented to be 25 even though 26 is easily feasible.... #MAXPLAYERS=10 # If not null, added to string "To get local support, " in the support # information help. #SUPPORT=call Izchak at extension 42. # If not null, displayed at the end of a panic-save sequence. #RECOVER=Run the recover program. # Uncomment the next line to disable the SEDUCE option, causing succubi and # incubi to use nymphs' charm behavior rather than their own seduce behavior. #SEDUCE=0 # Uncomment to disable savefile UID checking. #CHECK_SAVE_UID=0 # Record (high score) file options. # CAUTION: changing these after people have started playing games can # lead to lost high scores! # Maximum entries for one person. #PERSMAX=10 # Maximum entries in the record file. #ENTRYMAX=100 # Minimum points to get an entry. #POINTSMIN=1 # Determine identity of "person" in the score file with name (0) or # numeric (1) user id. #PERS_IS_UID=1 # Maximum number of score file entries to use for random statue names #MAX_STATUENAME_RANK=10 # Show debugging information originating from these source files. # Use '*' for all, or list source files separated by spaces. # Only available if game has been compiled with DEBUG, and can be # overridden via DEBUGFILES environment variable. #DEBUGFILES=* # Try to get more info in case of a program bug or crash. Only used # if the program is built with the PANICTRACE compile-time option enabled. # By default PANICTRACE is enabled if BETA is defined, otherwise disabled. # (GDBPATH, GREPPATH, and PANICTRACE_LIBC aren't used on VMS. # PANICTRACE_GDB is repurposed, with nothing to do with 'gdb'. # Values are 1: show traceback and exit, 2: show traceback and # remain in debugger.) PANICTRACE_GDB=1 #GDBPATH= #GREPPATH= #PANICTRACE_LIBC= #-- # Ordinary run-time options can be set here to override the builtin-in # default values. Unlike the SYSCF values above, individual users can # still choose their own option settings via NETHACKOPTIONS in their # environment or via sys$login:nethack.ini run-time configuration file. #OPTIONS=!autopickup,fruit:tomato,symset:DECgraphics #eof nethack-3.6.0/sys/vms/vmsbuild.com0000775000076400007660000003126712573766572016145 0ustar paxedpaxed$ ! vms/vmsbuild.com -- compile and link NetHack 3.6.* [pr] $ version_number = "3.5.0" $ ! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ $ ! $ ! usage: $ ! $ set default [.src] !or [-.-.src] if starting from [.sys.vms] $ ! $ @[-.sys.vms]vmsbuild [compiler-option] [link-option] [cc-switches] $ ! options: $ ! compiler-option : either "VAXC", "DECC" or "GNUC" or "" !default VAXC $ ! link-option : either "SHARE[able]" or "LIB[rary]" !default SHARE $ ! cc-switches : optional qualifiers for CC (such as "/noOpt/Debug") $ ! notes: $ ! If the symbol "CC" is defined, compiler-option is not used. $ ! The link-option refers to VAXCRTL (C Run-Time Library) handling; $ ! to specify it while letting compiler-option default, use "" as $ ! the compiler-option. $ ! To re-link without compiling, use "LINK" as special 'compiler-option'; $ ! to re-link with GNUC library, 'CC' must begin with "G" (or "g"). $ ! Default wizard definition moved to include/vmsconf.h. $ $ decc_dflt = f$trnlnm("DECC$CC_DEFAULT") $ j = (decc_dflt.nes."") .and. 1 $ vaxc_ = "CC" + f$element(j,"#","#/VAXC") + "/NOLIST/OPTIMIZE=NOINLINE" $ decc_ = "CC" + f$element(j,"#","#/DECC") + "/PREFIX=ALL/NOLIST" $ gnuc_ = "GCC" $ if f$type(gcc).eqs."STRING" then gnuc_ = gcc $ gnulib = "gnu_cc:[000000]gcclib/Library" !(not used w/ vaxc) $ ! common CC options (/obj=file doesn't work for GCC 1.36, use rename instead) $ c_c_ = "/INCLUDE=[-.INCLUDE]" $ veryold_vms = f$extract(1,1,f$getsyi("VERSION")).eqs."4" - .and. f$extract(3,3,f$getsyi("VERSION")).lts."6" $ if veryold_vms then c_c_ = c_c_ + "/DEFINE=(""VERYOLD_VMS"")" $ axp = (f$getsyi("CPU").ge.128) !f$getsyi("ARCH_NAME").eqs."Alpha" $ ! miscellaneous setup $ ivqual = %x00038240 !DCL-W-IVQUAL (used to check for ancient vaxc) $ abort := exit %x1000002A $ cur_dir = f$environment("DEFAULT") $ vmsbuild = f$environment("PROCEDURE") $ ! validate first parameter $ p1 := 'p1' $ if p1.eqs."" .and. (axp .or. decc_dflt.eqs."/DECC") then p1 = "DECC" $ o_VAXC = 0 !(c_opt substring positions) $ o_DECC = 5 $ o_GNUC = 10 $ o_LINK = 15 $ o_SPCL = 20 $ c_opt = f$locate("|"+p1, "|VAXC|DECC|GNUC|LINK|SPECIAL|") !5 $ if (c_opt/5)*5 .eq. c_opt then goto p1_ok $ copy sys$input: sys$error: !p1 usage %first arg is compiler option; it must be one of "VAXC" -- use VAX C to compile everything or "DECC" -- use DEC C to compile everything or "GNUC" -- use GNU C to compile everything or "LINK" -- skip compilation, just relink nethack.exe or "SPEC[IAL]" -- just compile and link lev_comp.exe or "" -- default operation (VAXC unless 'CC' is defined) Note: if a DCL symbol for CC is defined, "VAXC" and "GNUC" are no-ops. If the symbol value begins with "G" (or "g"), then the GNU C library will be included in all link operations. Do not rebuild lev_comp with "SPECIAL" unless you have a CC symbol setup with the proper options. $ abort $p1_ok: $ ! validate second parameter $ p2 := 'p2' $ l_opt = f$locate("|"+p2, "|SHAREABLE|LIBRARY__|NONE_____|") !10 $ if (l_opt/10)*10 .eq. l_opt then goto p2_ok $ copy sys$input: sys$error: !p2 usage %second arg is C run-time library handling; it must be one of "SHAREABLE" -- link with SYS$SHARE:VAXCRTL.EXE/SHAREABLE or "LIBRARY" -- link with SYS$LIBRARY:VAXCRTL.OLB/LIBRARY or "NONE" -- explicitly indicate DECC$SHR or "" -- default operation (use shareable image) Note: for MicroVMS 4.x, "SHAREABLE" (which is the default) is required. Specify "NONE" if using DEC C with a CC symbol overriding 1st arg. $ abort $p2_ok: $ ! start from a known location -- [.sys.vms], then move to [-.-.src] $ set default 'f$parse(vmsbuild,,,"DEVICE")''f$parse(vmsbuild,,,"DIRECTORY")' $ set default [-.-.src] !move to source directory $ ! compiler setup; if a symbol for "CC" is already defined it will be used $ if f$type(cc).eqs."STRING" then goto got_cc $ cc = vaxc_ !assume "VAXC" requested or defaulted $ if c_opt.eq.o_GNUC then goto chk_gcc !explicitly invoked w/ "GNUC" option $ if c_opt.eq.o_DECC then cc = decc_ $ if c_opt.ne.o_VAXC then goto got_cc !"SPEC" or "LINK", skip compiler check $ ! we want to prevent function inlining with vaxc v3.x (/opt=noinline) $ ! but we can't use noInline with v2.x, so need to determine version $ set noOn $ msgenv = f$environment("MESSAGE") $ set message/noFacil/noSever/noIdent/noText $ cc/noObject _NLA0:/Include=[] !strip 'noinline' if error $ sts = $status $ if sts then goto reset_msg !3.0 or later will check out OK $ ! must be dealing with vaxc 2.x; ancient version (2.2 or earlier) $ ! can't handle /include='dir', needs c$include instead $ cc = cc - "=NOINLINE" - ",NOINLINE" - "NOINLINE," $ if sts.ne.IVQUAL then goto reset_msg $ define/noLog c$include [-.INCLUDE] $ c_c_ = "/DEFINE=(""ANCIENT_VAXC"")" $ if veryold_vms then c_c_ = c_c_ - ")" + ",""VERYOLD_VMS"")" $reset_msg: $ set message 'msgenv' $ set On $ goto got_cc $ ! $chk_gcc: $ cc = gnuc_ $ ! old versions of gcc-vms don't have or available $ c_c_ = "/DEFINE=(""USE_OLDARGS"")" $ if veryold_vms then c_c_ = c_c_ - ")" + ",""VERYOLD_VMS"")" $ if veryold_vms then goto chk_gas !avoid varargs & stdarg $ if f$search("gnu_cc_include:[000000]varargs.h").nes."" then - c_c_ = "/DEFINE=(""USE_VARARGS"")" $ if f$search("gnu_cc_include:[000000]stdarg.h").nes."" then - c_c_ = "/DEFINE=(""USE_STDARG"")" $chk_gas: $ ! test whether this version of gas handles the 'const' construct correctly $ gas_chk_tmp = "sys$scratch:gcc-gas-chk.tmp" $ if f$search(gas_chk_tmp).nes."" then delete/noconfirm/nolog 'gas_chk_tmp';* $ gas_ok = 0 !assume bad $ on warning then goto skip_gas $ define/user/nolog sys$error 'gas_chk_tmp' $ mcr gnu_cc:[000000]gcc-as sys$input: -o _NLA0: $DECK .const .comm dummy,0 .const .comm dummy,0 $EOD $ gas_ok = 1 !assume good $ if f$search(gas_chk_tmp).eqs."" then goto skip_gas $ ! if the error file is empty, gas can deal properly with const $ gas_ok = f$file_attrib(gas_chk_tmp,"EOF") .eq. 0 $ delete/noconfirm/nolog 'gas_chk_tmp';* $skip_gas: $ on warning then continue $ if .not.gas_ok then c_c_ = c_c_ - ")" + ",""const="")" $ c_c_ = "/INCLUDE=[-.INCLUDE]" + c_c_ $ ! $got_cc: $ cc = cc + c_c_ !append common qualifiers $ if p3.nes."" then cc = cc + p3 !append optional user preferences $ g := 'f$extract(0,1,cc)' $ if g.eqs."$" then g := 'f$extract(1,1,cc)' !"foreign" gcc $ if f$edit(f$extract(1,1,cc),"UPCASE").eqs."E" then g := X !GEMC $ if g.nes."G" .and. c_opt.ne.o_GNUC then gnulib = "" $ ! linker setup; if a symbol for "LINK" is defined, we'll use it $ if f$type(link).nes."STRING" then link = "LINK/NOMAP" $ if p4.nes."" then link = link + p4 !append optional user preferences $ if f$trnlnm("F").nes."" then close/noLog f $ create crtl.opt !empty $ open/Append f crtl.opt $ write f "! crtl.opt" $ if c_opt.eq.o_DECC .or. l_opt.eq.20 $ then $! l_opt=="none", leave crtl.opt empty (shs$share:decc$shr.exe/Share) $ else $ ! gnulib order: vaxcrtl.exe+gcclib.olb vs gcclib.olb+vaxcrtl.olb $ if l_opt.eq.0 then write f "sys$share:vaxcrtl.exe/Shareable" $ if gnulib.nes."" then write f gnulib $ if l_opt.ne.0 then write f "sys$library:vaxcrtl.olb/Library" $ endif $ close f $ if f$search("crtl.opt;-2").nes."" then purge/Keep=2/noLog crtl.opt $ ! version ID info for linker to record in .EXE files $ create ident.opt $ open/Append f ident.opt $ write f "! ident.opt" $ write f "identification=""",version_number,""" !version" $ close f $ if f$search("ident.opt;-1").nes."" then purge/noLog ident.opt $ ! final setup $ nethacklib = "[-.src]nethack.olb" $ create nethack.opt ! nethack.opt nethack.olb/Library/Include=(vmsmain) sys$library:starlet.olb/Include=(lib$initialize) psect_attr=lib$initialize, Con,Usr,noPic,Rel,Gbl,noShr,noExe,Rd,noWrt,Long iosegment=128 $ if f$search("nethack.opt;-2").nes."" then purge/Keep=2/noLog nethack.opt $ milestone = "write sys$output f$fao("" !5%T "",0)," $ if c_opt.eq.o_LINK then goto link !"LINK" requested, skip compilation $ rename := rename/New_Vers $ touch := set file/Truncate $ makedefs := $sys$disk:[-.util]makedefs $ show symbol cc $ goto begin !skip subroutines $! $compile_file: !input via 'c_file' $ no_lib = ( f$extract(0,1,c_file) .eqs. "#" ) $ if no_lib then c_file = f$extract(1,255,c_file) $ c_name = f$edit(f$parse(c_file,,,"NAME"),"LOWERCASE") $ f_opts = "" !options for this file $ if f$type('c_name'_options).nes."" then f_opts = 'c_name'_options $ milestone " (",c_name,")" $ if f$search("''c_name'.obj").nes."" then delete 'c_name'.obj;* $ cc 'f_opts' 'c_file' $ if .not.no_lib then nh_obj_list == nh_obj_list + ",''c_name'.obj;0" $ return $! $compile_list: !input via 'c_list' $ nh_obj_list == "" $ j = -1 $ c_loop: $ j = j + 1 $ c_file = f$element(j,",",c_list) !get next file $ if c_file.eqs."," then goto c_done $ c_file = c_file + ".c" $ gosub compile_file $ goto c_loop $ c_done: $ nh_obj_list == f$extract(1,999,nh_obj_list) $ if nh_obj_list.nes."" then libr/Obj 'nethacklib' 'nh_obj_list'/Replace $ if nh_obj_list.nes."" then delete 'nh_obj_list' $ delete/symbol/global nh_obj_list $ return $! $begin: $! $! miscellaneous special source file setup $! $ if f$search("pmatchregex.c").eqs."" then copy [-.sys.share]pmatchregex.c []*.* $ if f$search("random.c").eqs."" then copy [-.sys.share]random.c []*.* $ if f$search("tclib.c") .eqs."" then copy [-.sys.share]tclib.c []*.* $ if f$search("[-.util]lev_yacc.c").eqs."" then @[-.sys.vms]spec_lev.com $! $! create object library $! $ if c_opt.ne.o_SPCL .or. f$search(nethacklib).eqs."" then - libr/Obj 'nethacklib'/Create=(Block=3000,Hist=0) $ if f$search("''nethacklib';-1").nes."" then purge 'nethacklib' $! $! compile and link makedefs, then nethack, lev_comp+dgn_comp, dlb+recover. $! $ milestone "" $ c_list = "[-.sys.vms]vmsmisc,[-.sys.vms]vmsfiles,[]alloc,dlb,monst,objects" $ if c_opt.eq.o_SPCL then c_list = c_list + ",decl,drawing" $ gosub compile_list $ if c_opt.eq.o_SPCL then goto special !"SPECIAL" requested, skip main build $ set default [-.util] $ c_list = "#makedefs" $ gosub compile_list $ link makedefs.obj,'nethacklib'/Lib,[-.src]ident.opt/Opt,[-.src]crtl/Opt $ milestone "makedefs" $! create some build-time files $ makedefs -p !pm.h $ makedefs -o !onames.h $ makedefs -v !date.h $ milestone " (*.h)" $ makedefs -m !../src/monstr.c $ makedefs -z !../src/vis_tab.c, ../include/vis_tab.h $ milestone " (*.c)" $ set default [-.src] $! compile most of the source files: $ c_list = "decl,version,[-.sys.vms]vmsmain,[-.sys.vms]vmsunix" - + ",[-.sys.vms]vmstty,[-.sys.vms]vmsmail" - + ",[]random,[]tclib,[]pmatchregex" !copied from [-.sys.share] $ gosub compile_list $ c_list = "[-.win.tty]getline,[-.win.tty]termcap" - + ",[-.win.tty]topl,[-.win.tty]wintty" $ gosub compile_list $ c_list = "allmain,apply,artifact,attrib,ball,bones,botl,cmd,dbridge,detect" - + ",dig,display,do,do_name,do_wear,dog,dogmove,dokick,dothrow,drawing" - + ",dungeon,eat,end,engrave,exper,explode,extralev,files,fountain" $ gosub compile_list $ c_list = "hack,hacklib,invent,light,lock,mail,makemon,mapglyph,mcastu" - + ",mhitm,mhitu,minion,mklev,mkmap,mkmaze,mkobj,mkroom,mon,mondata" - + ",monmove,monstr,mplayer,mthrowu,muse,music,o_init,objnam,options" - + ",pager,pickup" $ gosub compile_list $ c_list = "pline,polyself,potion,pray,priest,quest,questpgr,read" - + ",rect,region,restore,rip,rnd,role,rumors,save,shk,shknam,sit" - + ",sounds,sp_lev,spell,steal,steed,sys,teleport,timeout,topten" - + ",track,trap,u_init" $ gosub compile_list $ c_list = "uhitm,vault,vision,vis_tab,weapon,were,wield,windows" - + ",wizard,worm,worn,write,zap" $ gosub compile_list $! $link: $ milestone "" $ link/Exe=nethack.exe nethack.opt/Options,ident.opt/Options,crtl.opt/Options $ milestone "NetHack" $ if c_opt.eq.o_LINK then goto done !"LINK" only $special: $! $! build special level and dungeon compilers $! $ set default [-.util] $ c_list = "#panic,#lev_main,#lev_yacc,#dgn_main,#dgn_yacc" $ if c_opt.eq.o_SPCL then c_list = "[-.sys.vms]vmsfiles," + c_list $ gosub compile_list $ c_list = "#lev_lex,#dgn_lex" $ copy [-.sys.vms]lev_lex.h stdio.*/Prot=(s:rwd,o:rwd) $ gosub compile_list $ rename stdio.h lev_lex.* $ link/exe=lev_comp.exe lev_main.obj,lev_yacc.obj,lev_lex.obj,- panic.obj,'nethacklib'/Lib,[-.src]ident.opt/Opt,[-.src]crtl.opt/Opt $ milestone "lev_comp" $ link/exe=dgn_comp.exe dgn_main.obj,dgn_yacc.obj,dgn_lex.obj,- panic.obj,'nethacklib'/Lib,[-.src]ident.opt/Opt,[-.src]crtl.opt/Opt $ milestone "dgn_comp" $! $ c_list = "#dlb_main,#recover" $ gosub compile_list $ link/exe=dlb.exe dlb_main.obj,- panic.obj,'nethacklib'/Lib,[-.src]ident.opt/Opt,[-.src]crtl.opt/Opt $ milestone "dlb" $ link/exe=recover.exe recover.obj,- 'nethacklib'/Lib,[-.src]ident.opt/Opt,[-.src]crtl.opt/Opt $ milestone "recover" $! $done: $ set default 'cur_dir' $ exit nethack-3.6.0/sys/vms/vmsfiles.c0000664000076400007660000002472412536476415015602 0ustar paxedpaxed/* NetHack 3.6 vmsfiles.c $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * VMS-specific file manipulation routines to implement some missing * routines or substitute for ones where we want behavior modification. */ #include "config.h" #include /* lint supression due to lack of extern.h */ int FDECL(vms_link, (const char *, const char *)); int FDECL(vms_unlink, (const char *)); int FDECL(vms_creat, (const char *, unsigned int)); boolean FDECL(same_dir, (const char *, const char *)); int FDECL(c__translate, (int)); #include #if 0 #include #else #define PSL$C_EXEC 1 /* executive mode, for priv'd logical name handling */ #endif #include #ifndef C$$TRANSLATE /* don't rely on VAXCRTL's internal routine */ #define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status)) #endif extern unsigned long sys$parse(), sys$search(), sys$enter(), sys$remove(); extern int VDECL(lib$match_cond, (int, int, ...)); #define vms_success(sts) ((sts) &1) /* odd, */ #define vms_failure(sts) (!vms_success(sts)) /* even */ /* vms_link() -- create an additional directory for an existing file */ int vms_link(file, new) const char *file, *new; { struct FAB fab; struct NAM nam; unsigned short fid[3]; char esa[NAM$C_MAXRSS]; fab = cc$rms_fab; /* set block ID and length, zero the rest */ fab.fab$l_fop = FAB$M_OFP; fab.fab$l_fna = (char *) file; fab.fab$b_fns = strlen(file); fab.fab$l_nam = &nam; nam = cc$rms_nam; nam.nam$l_esa = esa; nam.nam$b_ess = sizeof esa; if (vms_success(sys$parse(&fab)) && vms_success(sys$search(&fab))) { fid[0] = nam.nam$w_fid[0]; fid[1] = nam.nam$w_fid[1]; fid[2] = nam.nam$w_fid[2]; fab.fab$l_fna = (char *) new; fab.fab$b_fns = strlen(new); if (vms_success(sys$parse(&fab))) { nam.nam$w_fid[0] = fid[0]; nam.nam$w_fid[1] = fid[1]; nam.nam$w_fid[2] = fid[2]; nam.nam$l_esa = nam.nam$l_name; nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver; (void) sys$enter(&fab); } } if (vms_failure(fab.fab$l_sts)) { C$$TRANSLATE(fab.fab$l_sts); return -1; } return 0; /* success */ } /* vms_unlink() -- remove a directory entry for a file; should only be used for files which have had extra directory entries added, not for deletion (because the file won't be deleted, just made inaccessible!). */ int vms_unlink(file) const char *file; { struct FAB fab; struct NAM nam; char esa[NAM$C_MAXRSS]; fab = cc$rms_fab; /* set block ID and length, zero the rest */ fab.fab$l_fop = FAB$M_DLT; fab.fab$l_fna = (char *) file; fab.fab$b_fns = strlen(file); fab.fab$l_nam = &nam; nam = cc$rms_nam; nam.nam$l_esa = esa; nam.nam$b_ess = sizeof esa; if (vms_failure(sys$parse(&fab)) || vms_failure(sys$remove(&fab))) { C$$TRANSLATE(fab.fab$l_sts); return -1; } return 0; } /* Substitute creat() routine -- if trying to create a specific version, explicitly remove an existing file of the same name. Since it's only used when we expect exclusive access, add a couple RMS options for optimization. (Don't allow sharing--eliminates coordination overhead, and use 32 block buffer for faster throughput; ~30% speedup measured.) */ #undef creat int vms_creat(file, mode) const char *file; unsigned int mode; { char filnambuf[BUFSIZ]; /*(not BUFSZ)*/ if (index(file, ';')) { /* assumes remove or delete, not vms_unlink */ if (!unlink(file)) { (void) sleep(1); (void) unlink(file); } } else if (!index(file, '.')) { /* force some punctuation to be present */ file = strcat(strcpy(filnambuf, file), "."); } return creat(file, mode, "shr=nil", "mbc=32", "mbf=2", "rop=wbh"); } /* Similar substitute for open() -- if an open attempt fails due to being locked by another user, retry it once (work-around for a limitation of at least one NFS implementation). */ #undef open int vms_open(file, flags, mode) const char *file; int flags; unsigned int mode; { char filnambuf[BUFSIZ]; /*(not BUFSZ)*/ int fd; if (!index(file, '.') && !index(file, ';')) { /* force some punctuation to be present to make sure that the file name can't accidentally match a logical name */ file = strcat(strcpy(filnambuf, file), ";0"); } fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah"); if (fd < 0 && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) { (void) sleep(1); fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah"); } return fd; } /* do likewise for fopen() */ #undef fopen FILE * vms_fopen(file, mode) const char *file, *mode; { char filnambuf[BUFSIZ]; /*(not BUFSZ)*/ FILE *fp; if (!index(file, '.') && !index(file, ';')) { /* force some punctuation to be present to make sure that the file name can't accidentally match a logical name */ file = strcat(strcpy(filnambuf, file), ";0"); } fp = fopen(file, mode, "mbc=32", "mbf=2", "rop=rah"); if (!fp && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) { (void) sleep(1); fp = fopen(file, mode, "mbc=32", "mbf=2", "rop=rah"); } return fp; } /* Determine whether two strings contain the same directory name. Used for deciding whether installed privileges should be disabled when HACKDIR is defined in the environment (or specified via -d on the command line). This version doesn't handle Unix-style file specs. */ boolean same_dir(d1, d2) const char *d1, *d2; { if (!d1 || !*d1 || !d2 || !*d2) return FALSE; else if (!strcmp(d1, d2)) /* strcmpi() would be better, but that leads */ return TRUE; /* to linking problems for the utilities */ else { struct FAB f1, f2; struct NAM n1, n2; f1 = f2 = cc$rms_fab; /* initialize file access block */ n1 = n2 = cc$rms_nam; /* initialize name block */ f1.fab$b_acmodes = PSL$C_EXEC << FAB$V_LNM_MODE; f1.fab$b_fns = strlen(f1.fab$l_fna = (char *) d1); f2.fab$b_fns = strlen(f2.fab$l_fna = (char *) d2); f1.fab$l_nam = (genericptr_t) &n1; /* link nam to fab */ f2.fab$l_nam = (genericptr_t) &n2; n1.nam$b_nop = n2.nam$b_nop = NAM$M_NOCONCEAL; /* want true device name */ return ( vms_success(sys$parse(&f1)) && vms_success(sys$parse(&f2)) && n1.nam$t_dvi[0] == n2.nam$t_dvi[0] && !strncmp(&n1.nam$t_dvi[1], &n2.nam$t_dvi[1], n1.nam$t_dvi[0]) && !memcmp((genericptr_t) n1.nam$w_did, (genericptr_t) n2.nam$w_did, sizeof n1.nam$w_did)); /*{ short nam$w_did[3]; }*/ } } /* * c__translate -- substitute for VAXCRTL routine C$$TRANSLATE. * * Try to convert a VMS status code into its Unix equivalent, * then set `errno' to that value; use EVMSERR if there's no * appropriate translation; set `vaxc$errno' to the original * status code regardless. * * These translations match only a subset of VAXCRTL's lookup * table, but work even if the severity has been adjusted or * the inhibit-message bit has been set. */ #include #include #include /* #include */ /* #include */ #define VALUE(U) \ trans = U; \ break #define CASE1(V) case (V >> 3) #define CASE2(V, W) CASE1(V) : CASE1(W) int c__translate(code) int code; { register int trans; switch ((code & 0x0FFFFFF8) >> 3) { /* strip upper 4 and bottom 3 bits */ CASE2(RMS$_PRV, SS$_NOPRIV) : VALUE(EPERM); /* not owner */ CASE2(RMS$_DNF, RMS$_DIR) : CASE2(RMS$_FNF, RMS$_FND) : CASE1(SS$_NOSUCHFILE) : VALUE(ENOENT); /* no such file or directory */ CASE2(RMS$_IFI, RMS$_ISI) : VALUE(EIO); /* i/o error */ CASE1(RMS$_DEV) : CASE2(SS$_NOSUCHDEV, SS$_DEVNOTMOUNT) : VALUE(ENXIO); /* no such device or address codes */ CASE1(RMS$_DME) : /* CASE1(LIB$INSVIRMEM): */ CASE2(SS$_VASFULL, SS$_INSFWSL) : VALUE(ENOMEM); /* not enough core */ CASE1(SS$_ACCVIO) : VALUE(EFAULT); /* bad address */ CASE2(RMS$_DNR, SS$_DEVASSIGN) : CASE2(SS$_DEVALLOC, SS$_DEVALRALLOC) : CASE2(SS$_DEVMOUNT, SS$_DEVACTIVE) : VALUE(EBUSY); /* mount device busy codes to name a few */ CASE2(RMS$_FEX, SS$_FILALRACC) : VALUE(EEXIST); /* file exists */ CASE2(RMS$_IDR, SS$_BADIRECTORY) : VALUE(ENOTDIR); /* not a directory */ CASE1(SS$_NOIOCHAN) : VALUE(EMFILE); /* too many open files */ CASE1(RMS$_FUL) : CASE2(SS$_DEVICEFULL, SS$_EXDISKQUOTA) : VALUE(ENOSPC); /* no space left on disk codes */ CASE2(RMS$_WLK, SS$_WRITLCK) : VALUE(EROFS); /* read-only file system */ default: VALUE(EVMSERR); }; errno = trans; vaxc$errno = code; return code; /* (not very useful) */ } #undef VALUE #undef CASE1 #undef CASE2 static char base_name[NAM$C_MAXRSS + 1]; /* return a copy of the 'base' portion of a filename */ char * vms_basename(name) const char *name; { unsigned len; char *base, *base_p; register const char *name_p; /* skip directory/path */ if ((name_p = strrchr(name, ']')) != 0) name = name_p + 1; if ((name_p = strrchr(name, '>')) != 0) name = name_p + 1; if ((name_p = strrchr(name, ':')) != 0) name = name_p + 1; if ((name_p = strrchr(name, '/')) != 0) name = name_p + 1; if (!*name) name = "."; /* this should never happen */ /* find extension/version and derive length of basename */ if ((name_p = strchr(name, '.')) == 0 || name_p == name) name_p = strchr(name, ';'); len = (name_p && name_p > name) ? name_p - name : strlen(name); /* return a lowercase copy of the name in a private static buffer */ base = strncpy(base_name, name, len); base[len] = '\0'; /* we don't use lcase() so that utilities won't need hacklib.c */ for (base_p = base; base_p < &base[len]; base_p++) if (isupper(*base_p)) *base_p = tolower(*base_p); return base; } /*vmsfiles.c*/ nethack-3.6.0/sys/vms/vmsmail.c0000664000076400007660000004441712536476415015423 0ustar paxedpaxed/* NetHack 3.6 vmsmail.c $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Robert Patrick Rankin, 1991. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "mail.h" /* lint supression due to lack of extern.h */ unsigned long NDECL(init_broadcast_trapping); unsigned long NDECL(enable_broadcast_trapping); unsigned long NDECL(disable_broadcast_trapping); struct mail_info *NDECL(parse_next_broadcast); #ifdef MAIL #include "wintype.h" #include "winprocs.h" #include #include #include #ifndef __GNUC__ #include #else #define MSG$_TRMHANGUP 6 #define MSG$_TRMBRDCST 83 #endif /*__GNUC__*/ #include /* #include */ #define vms_ok(sts) ((sts) &1) static struct mail_info *FDECL(parse_brdcst, (char *)); static void FDECL(filter_brdcst, (char *)); static void NDECL(flush_broadcasts); static void FDECL(broadcast_ast, (int)); extern char *FDECL(eos, (char *)); extern char *FDECL(strstri, (const char *, const char *)); extern int FDECL(strncmpi, (const char *, const char *, int)); extern size_t FDECL(strspn, (const char *, const char *)); #ifndef __DECC extern int VDECL(sscanf, (const char *, const char *, ...)); #endif extern unsigned long smg$create_pasteboard(), smg$get_broadcast_message(), smg$set_broadcast_trapping(), smg$disable_broadcast_trapping(); extern volatile int broadcasts; /* defining declaration in mail.c */ static long pasteboard_id = 0; /* SMG's magic cookie */ /* * Mail (et al) overview: * * When a broadcast is asynchronously captured, a volatile counter * ('broadcasts') is incremented. Each player turn, ckmailstatus() polls * the counter and calls parse_next_broadcast() if it's positive; this * returns some display text, object name, and response command, which is * passed to newmail(). Routine newmail() generates a mail-daemon monster * who approaches the character, "speaks" the display text, and delivers * a scroll of mail pre-named to the object name; the response command is * also attached to the scroll's oextra->omailcmd field. * Unrecognized broadcasts result in the mail-daemon * arriving and announcing the display text, but no scroll being created. * If SHELL is undefined, then all broadcasts are treated as 'other'; since * no subproceses are allowed, there'd be no way to respond to the scroll. * * When a scroll of mail is read by the character, readmail() extracts * the command string and uses it for the default when prompting the * player for a system command to spawn. The player may enter any command * he or she chooses, or just to accept the default or to * avoid executing any command. If the command is "SPAWN", a regular shell * escape to DCL is performed; otherwise, the indicated single command is * spawned. Either way, NetHack resumes play when the subprocess terminates * or explicitly reattaches to its parent. * * Broadcast parsing: * * The following broadcast messages are [attempted to be] recognized: * text fragment name for scroll default command * New mail VMSmail MAIL * New ALL-IN-1 MAIL A1mail A1M * Software Tools mail STmail MSG [+folder] * MM mail MMmail MM * WPmail: New mail WPmail OFFICE/MAIL * **M400 mail M400mail M400 * " mail", ^"mail " unknown mail SPAWN * " phoning" Phone call PHONE ANSWER * talk-daemon...by...foo Talk request TALK[/OLD] foo@bar * (node)user - Bitnet noise XYZZY user@node * Anything else results in just the message text being passed along, no * scroll of mail so consequently no command to execute when scroll read. * The user can set up ``$ XYZZY :== SEND'' prior to invoking NetHack if * vanilla JNET responses to Bitnet messages are prefered. * * Static return buffers are used because only one broadcast gets * processed at a time, and the essential information in each one is * either displayed and discarded or copied into a scroll-of-mail object. * * The test driver code below can be used to check out potential new * entries without rebuilding NetHack itself. CC/DEFINE="TEST_DRIVER" * Link it with hacklib.obj or nethack.olb/incl=hacklib (not nethack/lib). */ static struct mail_info msg; /* parse_*()'s return buffer */ static char nam_buf[63], /* maximum onamelth, size of ONAME(object) */ cmd_buf[99], /* arbitrary */ txt_buf[255 + 1]; /* same size as used for message buf[] */ /* try to decipher and categorize broadcast message text */ static struct mail_info * parse_brdcst(buf) /* called by parse_next_broadcast() */ char *buf; /* input: filtered broadcast text */ { int typ; char *txt; const char *nam, *cmd; #ifdef SHELL /* only parse if spawned commands are enabled */ register char *p, *q; boolean is_jnet_send; char user[127 + 1], node[127 + 1], sentinel; /* Check these first; otherwise, their arbitrary text would enable easy spoofing of some other message patterns. Unfortunately, any home-grown broadcast delivery program poses a similar risk. */ if (!strncmpi(buf, "reply received", 14)) goto other; is_jnet_send = (sscanf(buf, "(%[^)])%s -%c", node, user, &sentinel) == 3); if (is_jnet_send) goto jnet_send; /* scan the text more or less by brute force */ if ((q = strstri(buf, " mail")) != 0 || /* all known mail broadcasts */ !strncmpi(q = buf, "mail ", 5)) { /* unexpected alternative */ typ = MSG_MAIL; p = strstri(q, " from"); txt = p ? strcat(strcpy(txt_buf, "Mail for you"), p) : (char *) 0; if (!strncmpi(buf, "new mail", 8)) { /* New mail [on node FOO] from [SPAM::]BAR [\"personal_name\"] [\(HH:MM:SS\)] */ nam = "VMSmail"; /* assume VMSmail */ cmd = "MAIL"; if (txt && (p = strrchr(txt, '(')) > txt && /* discard time */ (--p, strspn(p, "0123456789( :.)") == strlen(p))) *p = '\0'; } else if (!strncmpi(buf, "new all-in-1", 12)) { int i; /* New ALL-IN-1 MAIL message [on node FOO] from Personal Name \(BAR@SPAM\) [\(DD-MMM-YYYY HH:MM:SS\)] */ nam = "A1mail"; cmd = "A1M"; if (txt && (p = strrchr(txt, '(')) > txt && /* discard date+time */ sscanf(p - 1, " (%*d-%*[^-]-%*d %*d:%*d:%d) %c", &i, &sentinel) == 1) *--p = '\0'; } else if (!strncmpi(buf, "software tools", 14)) { /* Software Tools mail has arrived on FOO from \'BAR\' [in SPAM] */ nam = "STmail"; cmd = "MSG"; if (txt && (p = strstri(p, " in ")) != 0) /* specific folder */ cmd = strcat(strcpy(cmd_buf, "MSG +"), p + 4); } else if (q - 2 >= buf && !strncmpi(q - 2, "mm", 2)) { /* {MultiNet\ |PMDF\/}MM mail has arrived on FOO from BAR\n [Subject: subject_text] (PMDF only) */ nam = "MMmail"; /* MultiNet's version of MM */ cmd = "MM"; /*{ perhaps "MM READ"? }*/ } else if (!strncmpi(buf, "wpmail:", 7)) { /* WPmail: New mail from BAR. subject_text */ nam = "WPmail"; /* WordPerfect [sic] Office */ cmd = "OFFICE/MAIL"; } else if (!strncmpi(buf, "**m400 mail", 7)) { /* **M400 mail waiting** */ nam = "M400mail"; /* Messenger 400 [not seen] */ cmd = "M400"; } else { /* not recognized, but presumed to be mail */ nam = "unknown mail"; cmd = "SPAWN"; /* generic escape back to DCL */ txt = (char *) 0; /* don't rely on "from" info here */ } if (!txt) txt = strcat(strcpy(txt_buf, "Mail for you: "), buf); /* : end of mail recognition; now check for call-type interruptions... */ } else if ((q = strstri(buf, " phoning")) != 0) { /* BAR is phoning you [on FOO] \(HH:MM:SS\) */ typ = MSG_CALL; nam = "Phone call"; cmd = "PHONE ANSWER"; if (!strncmpi(q + 8, " you", 4)) q += (8 + 4), *q = '\0'; txt = strcat(strcpy(txt_buf, "Do you hear ringing? "), buf); } else if ((q = strstri(buf, " talk-daemon")) != 0 || (q = strstri(buf, " talk_daemon")) != 0) { /* Message from TALK-DAEMON@FOO at HH:MM:SS\n Connection request by BAR@SPAM\n \[Respond with: TALK[/OLD] BAR@SPAM\] */ typ = MSG_CALL; nam = "Talk request"; /* MultiNet's TALK and/or TALK/OLD */ cmd = "TALK"; if ((p = strstri(q, " by ")) != 0) { txt = strcat(strcpy(txt_buf, "Talk request from"), p + 3); if ((p = strstri(p, "respond with")) != 0) { if (*(p - 1) == '[') *(p - 1) = '\0'; else *p = '\0'; /* terminate */ p += (sizeof "respond with" - sizeof ""); if (*p == ':') p++; if (*p == ' ') p++; cmd = strcpy(cmd_buf, p); /* "TALK[/OLD] bar@spam" */ p = eos(cmd_buf); if (*--p == ']') *p = '\0'; } } else txt = strcat(strcpy(txt_buf, "Pardon the interruption: "), buf); } else if (is_jnet_send) { /* sscanf(,"(%[^)])%s -%c",,,)==3 */ jnet_send: /* \(SPAM\)BAR - arbitrary_message_text (from BAR@SPAM) */ typ = MSG_CALL; nam = "Bitnet noise"; /* RSCS/NJE message received via JNET */ Sprintf(cmd_buf, "XYZZY %s@%s", user, node); cmd = cmd_buf; /*{ perhaps just vanilla SEND instead of XYZZY? }*/ Sprintf(txt_buf, "Message from %s@%s:%s", user, node, &buf[1 + strlen(node) + 1 + strlen(user) + 2 - 1]); /* "(node)user -" */ txt = txt_buf; /* : end of call recognition; anything else is none-of-the-above... */ } else { other: #endif /* SHELL */ /* arbitrary broadcast: batch job completed, system shutdown imminent, * &c */ typ = MSG_OTHER; nam = (char *) 0; /*"captured broadcast message"*/ cmd = (char *) 0; txt = strcat(strcpy(txt_buf, "Message for you: "), buf); #ifdef SHELL } /* Daemon in newmail() will append period when the text is displayed */ if ((p = eos(txt)) > txt && *--p == '.') *p = '\0'; /* newmail() and readmail() used to assume that nam and cmd are concatenated but that is no longer the case */ if (nam && nam != nam_buf) { (void) strncpy(nam_buf, nam, sizeof nam_buf - 1); nam_buf[sizeof nam_buf - 1] = '\0'; } if (cmd && cmd != cmd_buf) { (void) strncpy(cmd_buf, cmd, sizeof cmd_buf - 1); cmd_buf[sizeof cmd_buf - 1] = '\0'; } #endif /* SHELL */ /* truncate really long messages to prevent verbalize() from blowing up */ if (txt && strlen(txt) > BUFSZ - 50) txt[BUFSZ - 50] = '\0'; msg.message_typ = typ; /* simple index */ msg.display_txt = txt; /* text for daemon to pline() */ msg.object_nam = nam; /* 'name' for mail scroll */ msg.response_cmd = cmd; /* command to spawn when scroll read */ return &msg; } /* filter out non-printable characters and redundant noise */ static void filter_brdcst(buf) /* called by parse_next_broadcast() */ register char *buf; /* in: original text; out: filtered text */ { register char c, *p, *buf_p; /* filter the text; restrict consecutive spaces or dots to just two */ for (p = buf_p = buf; *buf_p; buf_p++) { c = *buf_p & '\177'; if (c == ' ' || c == '\t' || c == '\n') if (p == buf || /* ignore leading whitespace */ (p >= buf + 2 && *(p - 1) == ' ' && *(p - 2) == ' ')) continue; else c = ' '; else if (c == '.' || c < ' ' || c == '\177') if (p == buf || /* skip leading beeps & such */ (p >= buf + 2 && *(p - 1) == '.' && *(p - 2) == '.')) continue; else c = '.'; else if (c == '%' && /* trim %%% OPCOM verbosity %%% */ p >= buf + 2 && *(p - 1) == '%' && *(p - 2) == '%') continue; *p++ = c; } *p = '\0'; /* terminate, then strip trailing junk */ while (p > buf && (*--p == ' ' || *p == '.')) *p = '\0'; return; } static char empty_string[] = ""; /* fetch the text of a captured broadcast, then mangle and decipher it */ struct mail_info *parse_next_broadcast() /* called by ckmailstatus(mail.c) */ { short length, msg_type; $DESCRIPTOR(message, empty_string); /* string descriptor for buf[] */ struct mail_info *result = 0; /* messages could actually be longer; let long ones be truncated */ char buf[255 + 1]; message.dsc$a_pointer = buf, message.dsc$w_length = sizeof buf - 1; msg_type = length = 0; smg$get_broadcast_message(&pasteboard_id, &message, &length, &msg_type); if (msg_type == MSG$_TRMBRDCST) { buf[length] = '\0'; filter_brdcst(buf); /* mask non-printable characters */ result = parse_brdcst(buf); /* do the real work */ } else if (msg_type == MSG$_TRMHANGUP) { (void) gsignal(SIGHUP); } return result; } /* spit out any pending broadcast messages whenever we leave */ static void flush_broadcasts() /* called from disable_broadcast_trapping() */ { if (broadcasts > 0) { short len, typ; $DESCRIPTOR(msg_dsc, empty_string); char buf[512 + 1]; msg_dsc.dsc$a_pointer = buf, msg_dsc.dsc$w_length = sizeof buf - 1; raw_print(""); /* print at least one line for wait_synch() */ do { typ = len = 0; smg$get_broadcast_message(&pasteboard_id, &msg_dsc, &len, &typ); if (typ == MSG$_TRMBRDCST) buf[len] = '\0', raw_print(buf); } while (--broadcasts); wait_synch(); /* prompt with "Hit return to continue: " */ } } /* AST routine called when the terminal's associated mailbox receives a * message */ /*ARGSUSED*/ static void broadcast_ast(dummy) /* called asynchronously by terminal driver */ int dummy; /* not used */ { broadcasts++; } /* initialize the broadcast manipulation code; SMG makes this easy */ unsigned long init_broadcast_trapping() /* called by setftty() [once only] */ { unsigned long sts, preserve_screen_flag = 1; /* we need a pasteboard to pass to the broadcast setup/teardown routines */ sts = smg$create_pasteboard(&pasteboard_id, 0, 0, 0, &preserve_screen_flag); if (!vms_ok(sts)) { errno = EVMSERR, vaxc$errno = sts; raw_print(""); perror("?can't create SMG pasteboard for broadcast trapping"); wait_synch(); broadcasts = -1; /* flag that trapping is currently broken */ } return sts; } /* set up the terminal driver to deliver $brkthru data to a mailbox device */ unsigned long enable_broadcast_trapping() /* called by setftty() */ { unsigned long sts = 1; if (broadcasts >= 0) { /* (-1 => no pasteboard, so don't even try) */ /* register callback routine to be triggered when broadcasts arrive */ /* Note side effect: also intercepts hangup notification. */ /* Another note: TMPMBX privilege is required. */ sts = smg$set_broadcast_trapping(&pasteboard_id, broadcast_ast, 0); if (!vms_ok(sts)) { errno = EVMSERR, vaxc$errno = sts; raw_print(""); perror("?can't enable broadcast trapping"); wait_synch(); } } return sts; } /* return to 'normal'; $brkthru data goes straight to the terminal */ unsigned long disable_broadcast_trapping() /* called by settty() */ { unsigned long sts = 1; if (broadcasts >= 0) { /* disable trapping; releases associated MBX so that SPAWN can work */ sts = smg$disable_broadcast_trapping(&pasteboard_id); if (!vms_ok(sts)) errno = EVMSERR, vaxc$errno = sts; flush_broadcasts(); /* don't hold on to any buffered ones */ } return sts; } #else /* MAIL */ /* simple stubs for non-mail configuration */ unsigned long init_broadcast_trapping() { return 1; } unsigned long enable_broadcast_trapping() { return 1; } unsigned long disable_broadcast_trapping() { return 1; } struct mail_info * parse_next_broadcast() { return 0; } #endif /* MAIL */ /*----------------------------------------------------------------------*/ #ifdef TEST_DRIVER /* (Take parse_next_broadcast for a spin. :-) */ volatile int broadcasts = 0; void newmail(foo) struct mail_info *foo; { #define STRING(s) ((s) ? (s) : "") printf("\n\ message type = %d\n\ display text = \"%s\"\n\ object name = \"%.*s\"\n\ response cmd = \"%s\"\n\ ", foo->message_typ, STRING(foo->display_txt), (foo->object_nam && foo->response_cmd) ? (foo->response_cmd - foo->object_nam - 1) : strlen(STRING(foo->object_nam)), STRING(foo->object_nam), STRING(foo->response_cmd)); #undef STRING } void ckmailstatus() { struct mail_info *brdcst, *parse_next_broadcast(); while (broadcasts > 0) { /* process all trapped broadcasts [until] */ broadcasts--; if ((brdcst = parse_next_broadcast()) != 0) { newmail(brdcst); break; /* only handle one real message at a time */ } else printf("\n--< non-broadcast encountered >--\n"); } } int main() { char dummy[BUFSIZ]; init_broadcast_trapping(); enable_broadcast_trapping(); for (;;) { ckmailstatus(); printf("> "), fflush(stdout); /* issue a prompt */ if (!gets(dummy)) break; /* wait for a response */ } disable_broadcast_trapping(); return 1; } void panic(s) char *s; { raw_print(s); exit(EXIT_FAILURE); } void raw_print(s) char *s; { puts(s); fflush(stdout); } void wait_synch() { char dummy[BUFSIZ]; printf("\nPress to continue: "); fflush(stdout); (void) gets(dummy); } #endif /* TEST_DRIVER */ /*vmsmail.c*/ nethack-3.6.0/sys/vms/vmsmain.c0000664000076400007660000003265412536476415015425 0ustar paxedpaxed/* NetHack 3.6 vmsmain.c $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.31 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - VMS NetHack */ #include "hack.h" #include "dlb.h" #include static void NDECL(whoami); static void FDECL(process_options, (int, char **)); static void NDECL(byebye); #ifndef SAVE_ON_FATAL_ERROR #ifndef __DECC #define vms_handler_type int #else #define vms_handler_type unsigned int #endif extern void FDECL(VAXC$ESTABLISH, (vms_handler_type (*) (genericptr_t, genericptr_t))); static vms_handler_type FDECL(vms_handler, (genericptr_t, genericptr_t)); #include /* system service status codes */ #endif static void NDECL(wd_message); static boolean wiz_error_flag = FALSE; int main(argc, argv) int argc; char *argv[]; { register int fd; #ifdef CHDIR register char *dir; #endif boolean resuming = FALSE; /* assume new game */ #ifdef SECURE /* this should be the very first code executed */ privoff(); fflush((FILE *) 0); /* force stdio to init itself */ privon(); #endif sys_early_init(); atexit(byebye); hname = argv[0]; hname = vms_basename(hname); /* name used in 'usage' type messages */ hackpid = getpid(); (void) umask(0); choose_windows(DEFAULT_WINDOW_SYS); #ifdef CHDIR /* otherwise no chdir() */ /* * See if we must change directory to the playground. * (Perhaps hack is installed with privs and playground is * inaccessible for the player.) * The logical name HACKDIR is overridden by a * -d command line option (must be the first option given) */ dir = nh_getenv("NETHACKDIR"); if (!dir) dir = nh_getenv("HACKDIR"); #endif if (argc > 1) { #ifdef CHDIR if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else */ argc--; argv++; dir = argv[0] + 2; if (*dir == '=' || *dir == ':') dir++; if (!*dir && argc > 1) { argc--; argv++; dir = argv[0]; } if (!*dir) error("Flag -d must be followed by a directory name."); } if (argc > 1) #endif /* CHDIR */ /* * Now we know the directory containing 'record' and * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { #ifdef CHDIR chdirx(dir, FALSE); #endif #ifdef SYSCF initoptions(); #endif prscore(argc, argv); exit(EXIT_SUCCESS); } } #ifdef CHDIR /* move to the playground directory; 'termcap' might be found there */ chdirx(dir, TRUE); #endif #ifdef SECURE /* disable installed privs while loading nethack.cnf and termcap, and also while initializing terminal [$assign("TT:")]. */ privoff(); #endif initoptions(); init_nhwindows(&argc, argv); whoami(); #ifdef SECURE privon(); #endif /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ #ifndef SAVE_ON_FATAL_ERROR /* used to clear hangup stuff while still giving standard traceback */ VAXC$ESTABLISH(vms_handler); #endif sethanguphandler(hangup); process_options(argc, argv); /* command line options */ /* wizard mode access is deferred until here */ set_playmode(); /* sets plname to "wizard" for wizard mode */ /* strip role,race,&c suffix; calls askname() if plname[] is empty or holds a generic user name like "player" or "games" */ plnamesuffix(); if (wizard) { /* use character name rather than lock letter for file names */ locknum = 0; } else { /* suppress interrupts while processing lock file */ (void) signal(SIGQUIT, SIG_IGN); (void) signal(SIGINT, SIG_IGN); } /* * getlock() complains and quits if there is already a game * in progress for current character name (when locknum == 0) * or if there are too many active games (when locknum > 0). * When proceeding, it creates an empty .0 file to * designate the current game. * getlock() constructs based on the character * name (for !locknum) or on first available of alock, block, * clock, &c not currently in use in the playground directory * (for locknum > 0). */ getlock(); dlb_init(); /* must be before newgame() */ /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. */ attempt_restore: if ((fd = restore_saved_game()) >= 0) { const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save, 0); /* disallow parallel restores */ (void) signal(SIGINT, (SIG_RET_TYPE) done1); #ifdef NEWS if (iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if (dorecover(fd)) { resuming = TRUE; /* not starting new game */ wd_message(); if (discover || wizard) { if (yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else (void) chmod(fq_save, FCMASK); /* back to readable */ } } } if (!resuming) { /* new game: start by choosing role, race, etc; player might change the hero's name while doing that, in which case we try to restore under the new name and skip selection this time if that didn't succeed */ if (!iflags.renameinprogress) { player_selection(); if (iflags.renameinprogress) { /* player has renamed the hero while selecting role; if locking alphabetically, the existing lock file can still be used; otherwise, discard current one and create another for the new character name */ if (!locknum) { delete_levelfile(0); /* remove empty lock file */ getlock(); } goto attempt_restore; } } newgame(); wd_message(); } moveloop(resuming); exit(EXIT_SUCCESS); /*NOTREACHED*/ return (0); } static void process_options(argc, argv) int argc; char *argv[]; { int i; /* * Process options. */ while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case 'D': wizard = TRUE, discover = FALSE; break; case 'X': case 'x': discover = TRUE, wizard = FALSE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if (argv[0][2]) (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1); else if (argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname) - 1); } else raw_print("Player name expected after -u"); break; case 'I': case 'i': if (!strncmpi(argv[0] + 1, "IBM", 3)) { load_symset("IBMGraphics", PRIMARY); load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); } break; /* case 'D': */ case 'd': if (!strncmpi(argv[0] + 1, "DEC", 3)) { load_symset("DECGraphics", PRIMARY); switch_symbols(TRUE); } break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; case '@': flags.randomall = 1; break; default: if ((i = str2role(&argv[0][1])) >= 0) { flags.initrole = i; break; } /* else raw_printf("Unknown option: %s", *argv); */ } } if (argc > 1) locknum = atoi(argv[1]); #ifdef MAX_NR_OF_PLAYERS if (!locknum || locknum > MAX_NR_OF_PLAYERS) locknum = MAX_NR_OF_PLAYERS; #endif } #ifdef CHDIR void chdirx(dir, wr) const char *dir; boolean wr; { #ifndef HACKDIR static const char *defdir = "."; #else static const char *defdir = HACKDIR; if (dir == (const char *) 0) dir = defdir; else if (wr && !same_dir(HACKDIR, dir)) /* If we're playing anywhere other than HACKDIR, turn off any privs we may have been installed with. */ privoff(); #endif if (dir && chdir(dir) < 0) { perror(dir); error("Cannot chdir to %s.", dir); } /* warn the player if we can't write the record file */ if (wr) check_recordfile(dir); defdir = dir; } #endif /* CHDIR */ static void whoami() { /* * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS * 2. Use lowercase of $USER (if 1. fails) * The resulting name is overridden by command line options. * If everything fails, or if the resulting name is some generic * account like "games" then eventually we'll ask him. * Note that we trust the user here; it is possible to play under * somebody else's name. */ register char *s; if (!*plname && (s = nh_getenv("USER"))) (void) lcase(strncpy(plname, s, sizeof(plname) - 1)); } static void byebye() { void FDECL((*hup), (int) ); #ifdef SHELL extern unsigned long dosh_pid, mail_pid; extern unsigned long FDECL(sys$delprc, (unsigned long *, const genericptr_t)); /* clean up any subprocess we've spawned that may still be hanging around */ if (dosh_pid) (void) sys$delprc(&dosh_pid, (genericptr_t) 0), dosh_pid = 0; if (mail_pid) (void) sys$delprc(&mail_pid, (genericptr_t) 0), mail_pid = 0; #endif /* SIGHUP doesn't seem to do anything on VMS, so we fudge it here... */ hup = (void FDECL((*), (int) )) signal(SIGHUP, SIG_IGN); if (!program_state.exiting++ && hup != (void FDECL((*), (int) )) SIG_DFL && hup != (void FDECL((*), (int) )) SIG_IGN) { (*hup)(SIGHUP); } #ifdef CHDIR (void) chdir(getenv("PATH")); #endif } #ifndef SAVE_ON_FATAL_ERROR /* Condition handler to prevent byebye's hangup simulation from saving the game after a fatal error has occurred. */ /*ARGSUSED*/ static vms_handler_type /* should be `unsigned long', but the -*/ vms_handler(sigargs, mechargs) /*+ prototype in is screwed */ genericptr_t sigargs, mechargs; /* [0] is argc, [1..argc] are the real args */ { unsigned long condition = ((unsigned long *) sigargs)[1]; if (condition == SS$_ACCVIO /* access violation */ || (condition >= SS$_ASTFLT && condition <= SS$_TBIT) || (condition >= SS$_ARTRES && condition <= SS$_INHCHME)) { program_state.done_hup = TRUE; /* pretend hangup has been attempted */ #ifndef BETA if (wizard) #endif /* !BETA */ abort(); /* enter the debugger */ } return SS$_RESIGNAL; } #endif void sethanguphandler(handler) void FDECL((*handler), (int)); { (void) signal(SIGHUP, (SIG_RET_TYPE) handler); } #ifdef PORT_HELP void port_help() { /* * Display VMS-specific help. Just show contents of the helpfile * named by PORT_HELP. */ display_file(PORT_HELP, TRUE); } #endif /* PORT_HELP */ /* for KR1ED config, WIZARD is 0 or 1 and WIZARD_NAME is a string; for usual config, WIZARD is the string and vmsconf.h forces WIZARD_NAME to match it, avoiding need to test which one to use in string ops */ /* validate wizard mode if player has requested access to it */ boolean authorize_wizard_mode() { if (!strcmpi(nh_getenv("USER"), WIZARD_NAME)) return TRUE; wiz_error_flag = TRUE; /* not being allowed into wizard mode */ return FALSE; } static void wd_message() { if (wiz_error_flag) { pline("Only user \"%s\" may access debug (wizard) mode.", WIZARD_NAME); pline("Entering explore/discovery mode instead."); wizard = 0, discover = 1; /* (paranoia) */ } else if (discover) You("are in non-scoring explore/discovery mode."); } /*vmsmain.c*/ nethack-3.6.0/sys/vms/vmsmisc.c0000664000076400007660000000237212536476415015426 0ustar paxedpaxed/* NetHack 3.6 vmsmisc.c $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #undef exit #include #include int debuggable = 0; /* 1 if we can debug or show a call trace */ void FDECL(vms_exit, (int)); void NDECL(vms_abort); /* first arg should be unsigned long but has unsigned int */ extern void VDECL(lib$signal, (unsigned, ...)); /* terminate, converting Unix-style exit code into VMS status code */ void vms_exit(status) int status; { /* convert non-zero to failure, zero to success */ exit(status ? (SS$_ABORT | STS$M_INHIB_MSG) : SS$_NORMAL); /* NOT REACHED */ } /* put the user into the debugger; used for abort() when in wizard mode */ void vms_abort() { if (debuggable) lib$signal(SS$_DEBUG); /* we'll get here if the debugger isn't available, or if the user uses GO to resume execution instead of EXIT to quit */ vms_exit(2); /* don't return to caller (2==arbitrary non-zero) */ /* NOT REACHED */ } /* * Caveat: the VERYOLD_VMS configuration hasn't been tested in many years. */ #ifdef VERYOLD_VMS #include "oldcrtl.c" #endif /*vmsmisc.c*/ nethack-3.6.0/sys/vms/vmstty.c0000664000076400007660000004335512610522241015277 0ustar paxedpaxed/* NetHack 3.6 vmstty.c $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (VMS) version */ #define NEED_VARARGS #include "hack.h" #include "wintty.h" #include "tcap.h" #include #include #ifndef __GNUC__ #include #include #include #else /* values needed from missing include files */ #define SMG$K_TRM_UP 274 #define SMG$K_TRM_DOWN 275 #define SMG$K_TRM_LEFT 276 #define SMG$K_TRM_RIGHT 277 #define TT$M_MECHTAB 0x00000100 /* hardware tab support */ #define TT$M_MECHFORM 0x00080000 /* hardware form-feed support */ #define TT$M_NOBRDCST 0x00020000 /* disable broadcast messages, but */ #define TT2$M_BRDCSTMBX 0x00000010 /* catch them in associated mailbox */ #define TT2$M_APP_KEYPAD 0x00800000 /* application vs numeric keypad mode */ #endif /* __GNUC__ */ #ifdef USE_QIO_INPUT #include #endif #include #include unsigned long lib$disable_ctrl(), lib$enable_ctrl(); unsigned long sys$assign(), sys$dassgn(), sys$qiow(); #ifndef USE_QIO_INPUT unsigned long smg$create_virtual_keyboard(), smg$delete_virtual_keyboard(), smg$read_keystroke(), smg$cancel_input(); #else static short FDECL(parse_function_key, (int)); #endif static void NDECL(setctty); static void NDECL(resettty); #define vms_ok(sts) ((sts) &1) #define META(c) ((c) | 0x80) /* 8th bit */ #define CTRL(c) ((c) &0x1F) #define CMASK(c) (1 << CTRL(c)) #define LIB$M_CLI_CTRLT CMASK('T') /* 0x00100000 */ #define LIB$M_CLI_CTRLY CMASK('Y') /* 0x02000000 */ #define ESC '\033' #define CSI META(ESC) /* '\233' */ #define SS3 META(CTRL('O')) /* '\217' */ extern short ospeed; char erase_char, intr_char, kill_char; static boolean settty_needed = FALSE, bombing = FALSE; static unsigned long kb = 0; #ifdef USE_QIO_INPUT static char inputbuf[15 + 1], *inp = 0; static int inc = 0; #endif #define QIO_FUNC IO$_TTYREADALL | IO$M_NOECHO | IO$M_TRMNOECHO #ifdef MAIL #define TT_SPECIAL_HANDLING (TT$M_MECHTAB | TT$M_MECHFORM | TT$M_NOBRDCST) #define TT2_SPECIAL_HANDLING (TT2$M_BRDCSTMBX) #else #define TT_SPECIAL_HANDLING (TT$M_MECHTAB | TT$M_MECHFORM) #define TT2_SPECIAL_HANDLING (0) #endif #define Uword unsigned short #define Ubyte unsigned char struct _rd_iosb { /* i/o status block for read */ Uword status, trm_offset; Uword terminator, trm_siz; }; struct _wr_iosb { /* i/o status block for write */ Uword status, byte_cnt; unsigned : 32; }; struct _sm_iosb { /* i/o status block for sense-mode qio */ Uword status; Ubyte xmt_speed, rcv_speed; Ubyte cr_fill, lf_fill, parity; unsigned : 8; }; struct _sm_bufr { /* sense-mode characteristics buffer */ Ubyte class, type; /* class==DC$_TERM, type==(various) */ Uword buf_siz; /* aka page width */ #define page_width buf_siz /* number of columns */ unsigned tt_char : 24; /* primary characteristics */ unsigned page_length : 8; /* number of lines */ unsigned tt2_char : 32; /* secondary characteristics */ }; static struct { struct _sm_iosb io; struct _sm_bufr sm; } sg = { { 0 }, { 0 } }; static unsigned short tt_chan = 0; static unsigned long tt_char_restore = 0, tt_char_active = 0, tt2_char_restore = 0, tt2_char_active = 0; static unsigned long ctrl_mask = 0; #ifdef DEBUG extern int NDECL(nh_vms_getchar); /* rename the real vms_getchar and interpose this one in front of it */ int vms_getchar() { static int althack = 0, altprefix; char *nhalthack; int res; if (!althack) { /* one-time init */ nhalthack = nh_getenv("NH_ALTHACK"); althack = nhalthack ? 1 : -1; if (althack > 0) altprefix = *nhalthack; } #define vms_getchar nh_vms_getchar res = vms_getchar(); if (althack > 0 && res == altprefix) { res = vms_getchar(); if (res != ESC) res = META(res); } return res; } #endif /*DEBUG*/ int vms_getchar() { short key; #ifdef USE_QIO_INPUT struct _rd_iosb iosb; unsigned long sts; unsigned char kb_buf; #else /* SMG input */ static volatile int recurse = 0; /* SMG is not AST re-entrant! */ #endif if (program_state.done_hup) { /* hangup has occurred; do not attempt to get further user input */ return ESC; } #ifdef USE_QIO_INPUT if (inc > 0) { /* we have buffered character(s) from previous read */ kb_buf = *inp++; --inc; sts = SS$_NORMAL; } else { sts = sys$qiow(0, tt_chan, QIO_FUNC, &iosb, (void (*) ()) 0, 0, &kb_buf, sizeof kb_buf, 0, 0, 0, 0); } if (vms_ok(sts)) { if (kb_buf == CTRL('C')) { if (intr_char) gsignal(SIGINT); key = (short) kb_buf; } else if (kb_buf == '\r') { /* */ key = (short) '\n'; } else if (kb_buf == ESC || kb_buf == CSI || kb_buf == SS3) { switch (parse_function_key((int) kb_buf)) { case SMG$K_TRM_UP: key = Cmd.move_N; break; case SMG$K_TRM_DOWN: key = Cmd.move_S; break; case SMG$K_TRM_LEFT: key = Cmd.move_W; break; case SMG$K_TRM_RIGHT: key = Cmd.move_E; break; default: key = ESC; break; } } else { key = (short) kb_buf; } } else if (sts == SS$_HANGUP || iosb.status == SS$_HANGUP || sts == SS$_DEVOFFLINE) { gsignal(SIGHUP); key = ESC; } else /*(this should never happen)*/ key = getchar(); #else /*!USE_QIO_INPUT*/ if (recurse++ == 0 && kb != 0) { smg$read_keystroke(&kb, &key); switch (key) { case SMG$K_TRM_UP: key = Cmd.move_N; break; case SMG$K_TRM_DOWN: key = Cmd.move_S; break; case SMG$K_TRM_LEFT: key = Cmd.move_W; break; case SMG$K_TRM_RIGHT: key = Cmd.move_E; break; case '\r': key = '\n'; break; default: if (key > 255) key = ESC; break; } } else { /* abnormal input--either SMG didn't initialize properly or vms_getchar() has been called recursively (via SIGINT handler). */ if (kb != 0) /* must have been a recursive call */ smg$cancel_input(&kb); /* from an interrupt handler */ key = getchar(); } --recurse; #endif /* USE_QIO_INPUT */ return (int) key; } #ifdef USE_QIO_INPUT /* * We've just gotten an character. Do a timed read to * get any other characters, then try to parse them as an escape * sequence. This isn't perfect, since there's no guarantee * that a full escape sequence will be available, or even if one * is, it might actually by regular input from a fast typist or * a stalled input connection. {For packetized environments, * cross plural(body_part(FINGER)) and hope for best. :-} * * This is needed to preserve compatibility with SMG interface * for two reasons: * 1) retain support for arrow keys, and * 2) treat other VTxxx function keys as for aborting * various NetHack prompts. * The second reason is compelling; otherwise remaining chars of * an escape sequence get treated as inappropriate user commands. * * SMG code values for these key sequences fall in the range of * 256 thru 3xx. The assignments are not particularly intuitive. */ /*= -- Summary of VTxxx-style keyboards and transmitted escape sequences. -- Keypad codes are prefixed by 7 bit (\033 O) or 8 bit SS3: keypad: PF1 PF2 PF3 PF4 codes: P Q R S 7 8 9 - w x y m 4 5 6 . t u v n 1 2 3 :en-: q r s : : ...0... , :ter: ...p... l :M: Arrows are prefixed by either SS3 or CSI (either 7 or 8 bit), depending on whether the terminal is in application or numeric mode (ditto for PF keys): arrows: A B D C Additional function keys (vk201/vk401) generate CSI nn ~ (nn is 1 or 2 digits): vk201 keys: F6 F7 F8 F9 F10 F11 F12 F13 F14 Help Do F17 F18 F19 F20 'nn' digits: 17 18 19 20 21 23 24 25 26 28 29 31 32 33 34 alternate: ^C ^[ ^H ^J (when in VT100 mode) edit keypad: digits: 1 2 3 4 5 6 VT52 mode: arrows and PF keys send ESCx where x is in A-D or P-S. =*/ static const char *arrow_or_PF = "ABCDPQRS", /* suffix char */ *smg_keypad_codes = "PQRSpqrstuvwxyMmlnABDC"; /* PF1..PF4,KP0..KP9,enter,dash,comma,dot,up-arrow,down,left,right */ /* Ultimate return value is (index into smg_keypad_codes[] + 256). */ static short parse_function_key(c) register int c; { struct _rd_iosb iosb; unsigned long sts; char seq_buf[15 + 1]; /* plenty room for escape sequence + slop */ short result = ESC; /* translate to by default */ /* * Read whatever we can from type-ahead buffer (1 second timeout). * If the user typed an actual to deliberately abort * something, he or she should be able to tolerate the necessary * restriction of a negligible pause before typing anything else. * We might already have [at least some of] an escape sequence from a * previous read, particularly if user holds down the arrow keys... */ if (inc > 0) strncpy(seq_buf, inp, inc); if (inc < (int) (sizeof seq_buf) - 1) { sts = sys$qiow(0, tt_chan, QIO_FUNC | IO$M_TIMED, &iosb, (void (*) ()) 0, 0, seq_buf + inc, sizeof seq_buf - 1 - inc, 1, 0, 0, 0); if (vms_ok(sts)) sts = iosb.status; } else sts = SS$_NORMAL; if (vms_ok(sts) || sts == SS$_TIMEOUT) { register int cnt = iosb.trm_offset + iosb.trm_siz + inc; register char *p = seq_buf; if (c == ESC) /* check for 7-bit vt100/ANSI, or vt52 */ if (*p == '[' || *p == 'O') c = META(CTRL(*p++)), cnt--; else if (strchr(arrow_or_PF, *p)) c = SS3; /*CSI*/ if (cnt > 0 && (c == SS3 || (c == CSI && strchr(arrow_or_PF, *p)))) { register char *q = strchr(smg_keypad_codes, *p); if (q) result = 256 + (q - smg_keypad_codes); p++, --cnt; /* one more char consumed */ } else if (cnt > 1 && c == CSI) { static short /* "CSI nn ~" -> F_keys[nn] */ F_keys[35] = { ESC, /*(filler)*/ 311, 312, 313, 314, 315, 316, /* E1-E6 */ ESC, ESC, ESC, ESC, /*(more filler)*/ 281, 282, 283, 284, 285, ESC, /* F1-F5 */ 286, 287, 288, 289, 290, ESC, /* F6-F10*/ 291, 292, 293, 294, ESC, /*F11-F14*/ 295, 296, ESC, /*,, aka F15,F16*/ 297, 298, 299, 300 /*F17-F20*/ }; /* note: there are several missing nn in CSI nn ~ values */ int nn; char *q; *(p + cnt) = '\0'; /* terminate string */ q = strchr(p, '~'); if (q && sscanf(p, "%d~", &nn) == 1) { if (nn > 0 && nn < SIZE(F_keys)) result = F_keys[nn]; cnt -= (++q - p); p = q; } } if (cnt > 0) strncpy((inp = inputbuf), p, (inc = cnt)); else inc = 0, inp = 0; } return result; } #endif /* USE_QIO_INPUT */ static void setctty() { struct _sm_iosb iosb; unsigned long status; status = sys$qiow(0, tt_chan, IO$_SETMODE, &iosb, (void (*) ()) 0, 0, &sg.sm, sizeof sg.sm, 0, 0, 0, 0); if (vms_ok(status)) status = iosb.status; if (vms_ok(status)) { /* try to force terminal into synch with TTDRIVER's setting */ number_pad((sg.sm.tt2_char & TT2$M_APP_KEYPAD) ? -1 : 1); } else { raw_print(""); errno = EVMSERR, vaxc$errno = status; perror("NetHack(setctty: setmode)"); wait_synch(); } } static void resettty() /* atexit() routine */ { if (settty_needed) { bombing = TRUE; /* don't clear screen; preserve traceback info */ settty((char *) 0); } (void) sys$dassgn(tt_chan), tt_chan = 0; } /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by init_nhwindows() and resume_nhwindows() in wintty.c * (for initial startup and for returning from '!' or ^Z). */ void gettty() { static char dev_tty[] = "TT:"; static $DESCRIPTOR(tty_dsc, dev_tty); int err = 0; unsigned long status, zero = 0; if (tt_chan == 0) { /* do this stuff once only */ iflags.cbreak = OFF, iflags.echo = ON; /* until setup is complete */ status = sys$assign(&tty_dsc, &tt_chan, 0, 0); if (!vms_ok(status)) { raw_print(""), err++; errno = EVMSERR, vaxc$errno = status; perror("NetHack(gettty: $assign)"); } atexit(resettty); /* register an exit handler to reset things */ } status = sys$qiow(0, tt_chan, IO$_SENSEMODE, &sg.io, (void (*) ()) 0, 0, &sg.sm, sizeof sg.sm, 0, 0, 0, 0); if (vms_ok(status)) status = sg.io.status; if (!vms_ok(status)) { raw_print(""), err++; errno = EVMSERR, vaxc$errno = status; perror("NetHack(gettty: sensemode)"); } ospeed = sg.io.xmt_speed; erase_char = '\177'; /* , aka */ kill_char = CTRL('U'); intr_char = CTRL('C'); (void) lib$enable_ctrl(&zero, &ctrl_mask); /* Use the systems's values for lines and columns if it has any idea. */ if (sg.sm.page_length) LI = sg.sm.page_length; if (sg.sm.page_width) CO = sg.sm.page_width; /* suppress tab and form-feed expansion, in case termcap uses them */ tt_char_restore = sg.sm.tt_char; tt_char_active = sg.sm.tt_char |= TT_SPECIAL_HANDLING; tt2_char_restore = sg.sm.tt2_char; tt2_char_active = sg.sm.tt2_char |= TT2_SPECIAL_HANDLING; #if 0 /*[ defer until setftty() ]*/ setctty(); #endif if (err) wait_synch(); } /* reset terminal to original state */ void settty(s) const char *s; { if (!bombing) end_screen(); if (s) raw_print(s); if (settty_needed) { disable_broadcast_trapping(); #if 0 /* let SMG's exit handler do the cleanup (as per doc) */ /* #ifndef USE_QIO_INPUT */ if (kb) smg$delete_virtual_keyboard(&kb), kb = 0; #endif /* 0 (!USE_QIO_INPUT) */ if (ctrl_mask) (void) lib$enable_ctrl(&ctrl_mask, 0); iflags.echo = ON; iflags.cbreak = OFF; /* reset original tab, form-feed, broadcast settings */ sg.sm.tt_char = tt_char_restore; sg.sm.tt2_char = tt2_char_restore; setctty(); settty_needed = FALSE; } } /* same as settty, with no clearing of the screen */ void shuttty(s) const char *s; { bombing = TRUE; settty(s); bombing = FALSE; } void setftty() { unsigned long mask = LIB$M_CLI_CTRLT | LIB$M_CLI_CTRLY; (void) lib$disable_ctrl(&mask, 0); if (kb == 0) { /* do this stuff once only */ #ifdef USE_QIO_INPUT kb = tt_chan; #else /*!USE_QIO_INPUT*/ smg$create_virtual_keyboard(&kb); #endif /*USE_QIO_INPUT*/ init_broadcast_trapping(); } enable_broadcast_trapping(); /* no-op if !defined(MAIL) */ iflags.cbreak = (kb != 0) ? ON : OFF; iflags.echo = (kb != 0) ? OFF : ON; /* disable tab & form-feed expansion; prepare for broadcast trapping */ sg.sm.tt_char = tt_char_active; sg.sm.tt2_char = tt2_char_active; setctty(); start_screen(); settty_needed = TRUE; } void intron() /* enable kbd interupts if enabled when game started */ { intr_char = CTRL('C'); } void introff() /* disable kbd interrupts if required*/ { intr_char = 0; } #ifdef TIMED_DELAY extern unsigned long FDECL(lib$emul, (const long *, const long *, const long *, long *)); extern unsigned long sys$schdwk(), sys$hiber(); #define VMS_UNITS_PER_SECOND 10000000L /* hundreds of nanoseconds, 1e-7 */ /* constant for conversion from milliseconds to VMS delta time (negative) */ static const long mseconds_to_delta = VMS_UNITS_PER_SECOND / 1000L * -1L; /* sleep for specified number of milliseconds (note: the timer used generally only has 10-millisecond resolution at the hardware level...) */ void msleep(mseconds) unsigned mseconds; /* milliseconds */ { long pid = 0L, zero = 0L, msec, qtime[2]; msec = (long) mseconds; if (msec > 0 && /* qtime{0:63} = msec{0:31} * mseconds_to_delta{0:31} + zero{0:31} */ vms_ok(lib$emul(&msec, &mseconds_to_delta, &zero, qtime))) { /* schedule a wake-up call, then go to sleep */ if (vms_ok(sys$schdwk(&pid, (genericptr_t) 0, qtime, (long *) 0))) (void) sys$hiber(); } } #endif /* TIMED_DELAY */ /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *, s) { VA_START(s); VA_INIT(s, const char *); if (settty_needed) settty((char *) 0); Vprintf(s, VA_ARGS); (void) putchar('\n'); VA_END(); #ifndef SAVE_ON_FATAL_ERROR /* prevent vmsmain's exit handler byebye() from calling hangup() */ sethanguphandler((void FDECL((*), (int) )) SIG_DFL); #endif exit(EXIT_FAILURE); } nethack-3.6.0/sys/vms/vmsunix.c0000664000076400007660000007357612536476415015474 0ustar paxedpaxed/* NetHack 3.6 vmsunix.c $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file implements things from unixunix.c, plus related stuff */ #include "hack.h" #include #include #include #include #include #include #undef off_t #ifdef GNUC #include #else #define umask hide_umask_dummy /* DEC C: avoid conflict with system.h */ #include #undef umask #endif #include extern int debuggable; /* defined in vmsmisc.c */ extern void VDECL(lib$signal, (unsigned, ...)); extern unsigned long sys$setprv(); extern unsigned long lib$getdvi(), lib$getjpi(), lib$spawn(), lib$attach(); extern unsigned long smg$init_term_table_by_type(), smg$del_term_table(); #define vms_ok(sts) ((sts) &1) /* odd => success */ /* this could be static; it's only used within this file; it won't be used at all if C_LIB$INTIALIZE gets commented out below, so make it global so that compiler won't complain that it's not used */ int FDECL(vmsexeini, (const void *, const void *, const unsigned char *)); static int FDECL(veryold, (int)); static char *NDECL(verify_term); #if defined(SHELL) || defined(SUSPEND) static void FDECL(hack_escape, (BOOLEAN_P, const char *)); static void FDECL(hack_resume, (BOOLEAN_P)); #endif static int veryold(fd) int fd; { register int i; time_t date; struct stat buf; if (fstat(fd, &buf)) return (0); /* cannot get status */ #ifndef INSURANCE if (buf.st_size != sizeof(int)) return (0); /* not an xlock file */ #endif (void) time(&date); if (date - buf.st_mtime < 3L * 24L * 60L * 60L) { /* recent */ int lockedpid; /* should be the same size as hackpid */ unsigned long status, dummy, code = JPI$_PID; if (read(fd, (genericptr_t) &lockedpid, sizeof(lockedpid)) != sizeof(lockedpid)) /* strange ... */ return 0; status = lib$getjpi(&code, &lockedpid, 0, &dummy); if (vms_ok(status) || status != SS$_NONEXPR) return 0; } (void) close(fd); /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for (i = 1; i <= MAXDUNGEON * MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) delete (lock); } set_levelfile_name(lock, 0); if (delete (lock)) return (0); /* cannot remove it */ return (1); /* success! */ } void getlock() { register int i = 0, fd; /* idea from rpick%ucqais@uccba.uc.edu * prevent automated rerolling of characters * test input (fd0) so that tee'ing output to get a screen dump still * works * also incidentally prevents development of any hack-o-matic programs */ if (isatty(0) <= 0) error("You must play from a terminal."); /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); error("Quitting."); } /* default value of lock[] is "1lock" where '1' gets changed to 'a','b',&c below; override the default and use if we aren't restricting the number of simultaneous games */ if (!locknum) Sprintf(lock, "_%u%s", (unsigned) getuid(), plname); regularize(lock); set_levelfile_name(lock, 0); if (locknum > 25) locknum = 25; do { if (locknum) lock[0] = 'a' + i++; if ((fd = open(lock, 0, 0)) == -1) { if (errno == ENOENT) goto gotlock; /* no such file */ perror(lock); unlock_file(HLOCK); error("Cannot open %s", lock); } if (veryold(fd)) /* if true, this closes fd and unlinks lock */ goto gotlock; (void) close(fd); } while (i < locknum); unlock_file(HLOCK); error(locknum ? "Too many hacks running now." : "There is a game in progress under your name."); gotlock: fd = creat(lock, FCMASK); unlock_file(HLOCK); if (fd == -1) { error("cannot creat lock file."); } else { if (write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)) { error("cannot write lock"); } if (close(fd) == -1) { error("cannot close lock"); } } } void regularize(s) /* normalize file name */ register char *s; { register char *lp; for (lp = s; *lp; lp++) /* note: '-' becomes '_' */ if (!(isalpha(*lp) || isdigit(*lp) || *lp == '$')) *lp = '_'; } #undef getuid int vms_getuid() { return (getgid() << 16) | getuid(); } #ifndef FAB$C_STMLF #define FAB$C_STMLF 5 #endif /* check whether the open file specified by `fd' is in stream-lf format */ boolean file_is_stmlf(fd) int fd; { int rfm; struct stat buf; if (fstat(fd, &buf)) return FALSE; /* cannot get status? */ #ifdef stat_alignment_fix /* gcc-vms alignment kludge */ rfm = stat_alignment_fix(&buf)->st_fab_rfm; #else rfm = buf.st_fab_rfm; #endif return rfm == FAB$C_STMLF; } /*------*/ #ifndef LNM$_STRING #include /* logical name definitions */ #endif #define ENVSIZ LNM$C_NAMLENGTH /*255*/ #define ENV_USR 0 /* user-mode */ #define ENV_SUP 1 /* supervisor-mode */ #define ENV_JOB 2 /* job-wide entry */ /* vms_define() - assign a value to a logical name */ int vms_define(name, value, flag) const char *name; const char *value; int flag; { struct dsc { unsigned short len, mbz; const char *adr; }; /* descriptor */ struct itm3 { short buflen, itmcode; const char *bufadr; short *retlen; }; static struct itm3 itm_lst[] = { { 0, LNM$_STRING, 0, 0 }, { 0, 0 } }; struct dsc nam_dsc, val_dsc, tbl_dsc; unsigned long result, sys$crelnm(), lib$set_logical(); /* set up string descriptors */ nam_dsc.mbz = val_dsc.mbz = tbl_dsc.mbz = 0; nam_dsc.len = strlen(nam_dsc.adr = name); val_dsc.len = strlen(val_dsc.adr = value); tbl_dsc.len = strlen(tbl_dsc.adr = "LNM$PROCESS"); switch (flag) { case ENV_JOB: /* job logical name */ tbl_dsc.len = strlen(tbl_dsc.adr = "LNM$JOB"); /*FALLTHRU*/ case ENV_SUP: /* supervisor-mode process logical name */ result = lib$set_logical(&nam_dsc, &val_dsc, &tbl_dsc); break; case ENV_USR: /* user-mode process logical name */ itm_lst[0].buflen = val_dsc.len; itm_lst[0].bufadr = val_dsc.adr; result = sys$crelnm(0, &tbl_dsc, &nam_dsc, 0, itm_lst); break; default: /*[ bad input ]*/ result = 0; break; } result &= 1; /* odd => success (== 1), even => failure (== 0) */ return !result; /* 0 == success, 1 == failure */ } /* vms_putenv() - create or modify an environment value */ int vms_putenv(string) const char *string; { char name[ENVSIZ + 1], value[ENVSIZ + 1], *p; /* [255+1] */ p = strchr(string, '='); if (p > string && p < string + sizeof name && strlen(p + 1) < sizeof value) { (void) strncpy(name, string, p - string), name[p - string] = '\0'; (void) strcpy(value, p + 1); return vms_define(name, value, ENV_USR); } else return 1; /* failure */ } /* Support for VT420 was added to VMS in version V5.4, but as of V5.5-2 VAXCRTL still doesn't handle it and puts TERM=undefined into the environ[] array. getenv("TERM") will return "undefined" instead of something sensible. Even though that's finally fixed in V6.0, site defined terminals also return "undefined" so query SMG's TERMTABLE instead of just checking VMS's device-type value for VT400_Series. Called by verify_termcap() for convenience. */ static char * verify_term() { char *term = getenv("NETHACK_TERM"); if (!term) term = getenv("HACK_TERM"); if (!term) term = getenv("EMACS_TERM"); if (!term) term = getenv("TERM"); if (!term || !*term || !strcmpi(term, "undefined") || !strcmpi(term, "unknown")) { static char smgdevtyp[31 + 1]; /* size is somewhat arbitrary */ static char dev_tty[] = "TT:"; static $DESCRIPTOR(smgdsc, smgdevtyp); static $DESCRIPTOR(tt, dev_tty); unsigned short dvicode = DVI$_DEVTYPE; unsigned long devtype = 0L, termtab = 0L; (void) lib$getdvi(&dvicode, (unsigned short *) 0, &tt, &devtype, (genericptr_t) 0, (unsigned short *) 0); if (devtype && vms_ok(smg$init_term_table_by_type(&devtype, &termtab, &smgdsc))) { register char *p = &smgdevtyp[smgdsc.dsc$w_length]; /* strip trailing blanks */ while (p > smgdevtyp && *--p == ' ') *p = '\0'; /* (void)smg$del_term_table(); */ term = smgdevtyp; } } return term; } /* Figure out whether the termcap code will find a termcap file; if not, try to help it out. This avoids modifying the GNU termcap sources and can simplify configuration for sites which don't already use termcap. */ #define GNU_DEFAULT_TERMCAP "emacs_library:[etc]termcap.dat" #define NETHACK_DEF_TERMCAP "nethackdir:termcap" #define HACK_DEF_TERMCAP "hackdir:termcap" char *verify_termcap() /* called from startup(src/termcap.c) */ { struct stat dummy; const char *tc = getenv("TERMCAP"); if (tc) return verify_term(); /* no termcap fixups needed */ if (!tc && !stat(NETHACK_DEF_TERMCAP, &dummy)) tc = NETHACK_DEF_TERMCAP; if (!tc && !stat(HACK_DEF_TERMCAP, &dummy)) tc = HACK_DEF_TERMCAP; if (!tc && !stat(GNU_DEFAULT_TERMCAP, &dummy)) tc = GNU_DEFAULT_TERMCAP; if (!tc && !stat("[]termcap", &dummy)) tc = "[]termcap"; /* current dir */ if (!tc && !stat("$TERMCAP", &dummy)) tc = "$TERMCAP"; /* alt environ */ if (tc) { /* putenv(strcat(strcpy(buffer,"TERMCAP="),tc)); */ vms_define("TERMCAP", tc, ENV_USR); } else { /* perhaps someday we'll construct a termcap entry string */ } return verify_term(); } /*------*/ #ifdef SHELL #ifndef CLI$M_NOWAIT #define CLI$M_NOWAIT 1 #endif #endif #if defined(CHDIR) || defined(SHELL) || defined(SECURE) static unsigned long oprv[2]; void privoff() { unsigned long pid = 0, prv[2] = { ~0, ~0 }; unsigned short code = JPI$_PROCPRIV; (void) sys$setprv(0, prv, 0, oprv); (void) lib$getjpi(&code, &pid, (genericptr_t) 0, prv); (void) sys$setprv(1, prv, 0, (unsigned long *) 0); } void privon() { (void) sys$setprv(1, oprv, 0, (unsigned long *) 0); } #endif /* CHDIR || SHELL || SECURE */ #if defined(SHELL) || defined(SUSPEND) static void hack_escape(screen_manip, msg_str) boolean screen_manip; const char *msg_str; { if (screen_manip) suspend_nhwindows(msg_str); /* clear screen, reset terminal, &c */ (void) signal(SIGQUIT, SIG_IGN); /* ignore ^Y */ (void) signal(SIGINT, SIG_DFL); /* don't trap ^C (implct cnvrs to ^Y) */ } static void hack_resume(screen_manip) boolean screen_manip; { (void) signal(SIGINT, (SIG_RET_TYPE) done1); if (wizard) (void) signal(SIGQUIT, SIG_DFL); if (screen_manip) resume_nhwindows(); /* setup terminal modes, redraw screen, &c */ } #endif /* SHELL || SUSPEND */ #ifdef SHELL unsigned long dosh_pid = 0, /* this should cover any interactive escape */ mail_pid = 0; /* this only covers the last mail or phone; */ /*(mail & phone commands aren't expected to leave any process hanging * around)*/ int dosh() { return vms_doshell("", TRUE); /* call for interactive child process */ } /* vms_doshell -- called by dosh() and readmail() */ /* If execstring is not a null string, then it will be executed in a spawned */ /* subprocess, which will then return. It is for handling mail or phone */ /* interactive commands, which are only available if both MAIL and SHELL are */ /* #defined, but we don't bother making the support code conditionalized on */ /* MAIL here, just on SHELL being enabled. */ /* Normally, all output from this interaction will be 'piped' to the user's */ /* screen (SYS$OUTPUT). However, if 'screenoutput' is set to FALSE, output */ /* will be piped into oblivion. Used for silent phone call rejection. */ int vms_doshell(execstring, screenoutput) const char *execstring; boolean screenoutput; { unsigned long status, new_pid, spawnflags = 0; struct dsc$descriptor_s comstring, *command, *inoutfile = 0; static char dev_null[] = "_NLA0:"; static $DESCRIPTOR(nulldevice, dev_null); /* Is this an interactive shell spawn, or do we have a command to do? */ if (execstring && *execstring) { comstring.dsc$w_length = strlen(execstring); comstring.dsc$b_dtype = DSC$K_DTYPE_T; comstring.dsc$b_class = DSC$K_CLASS_S; comstring.dsc$a_pointer = (char *) execstring; command = &comstring; } else command = 0; /* use asynch subprocess and suppress output iff one-shot command */ if (!screenoutput) { spawnflags = CLI$M_NOWAIT; inoutfile = &nulldevice; } hack_escape(screenoutput, command ? (const char *) 0 : " \"Escaping\" into a " "subprocess; LOGOUT to " "reconnect and resume play. "); if (command || !dosh_pid || !vms_ok(status = lib$attach(&dosh_pid))) { #ifdef CHDIR (void) chdir(getenv("PATH")); #endif privoff(); new_pid = 0; status = lib$spawn(command, inoutfile, inoutfile, &spawnflags, (struct dsc$descriptor_s *) 0, &new_pid); if (!command) dosh_pid = new_pid; else mail_pid = new_pid; privon(); #ifdef CHDIR chdirx((char *) 0, 0); #endif } hack_resume(screenoutput); if (!vms_ok(status)) { pline(" Spawn failed. (%%x%08lX) ", status); mark_synch(); } return 0; } #endif /* SHELL */ #ifdef SUSPEND /* dosuspend() -- if we're a subprocess, attach to our parent; * if not, there's nothing we can do. */ int dosuspend() { static long owner_pid = -1; unsigned long status; if (owner_pid == -1) /* need to check for parent */ owner_pid = getppid(); if (owner_pid == 0) { pline(" No parent process. Use '!' to Spawn, 'S' to Save, or 'Q' " "to Quit. "); mark_synch(); return 0; } /* restore normal tty environment & clear screen */ hack_escape(1, " Attaching to parent process; use the ATTACH command to " "resume play. "); status = lib$attach(&owner_pid); /* connect to parent */ hack_resume(1); /* resume game tty environment & refresh screen */ if (!vms_ok(status)) { pline(" Unable to attach to parent. (%%x%08lX) ", status); mark_synch(); } return 0; } #endif /* SUSPEND */ #ifdef SELECTSAVED /* this would fit better in vmsfiles.c except that that gets linked with the utility programs and we don't want this code there */ static void FDECL(savefile, (const char *, int, int *, char ***)); static void savefile(name, indx, asize, array) const char *name; int indx, *asize; char ***array; { char **newarray; int i, oldsize; /* (asize - 1) guarantees that [indx + 1] will exist and be set to null */ while (indx >= *asize - 1) { oldsize = *asize; *asize += 5; newarray = (char **) alloc(*asize * sizeof(char *)); /* poor man's realloc() */ for (i = 0; i < *asize; ++i) newarray[i] = (i < oldsize) ? (*array)[i] : 0; if (*array) free((genericptr_t) *array); *array = newarray; } (*array)[indx] = strcpy((char *) alloc(strlen(name) + 1), name); } struct dsc { unsigned short len, mbz; char *adr; }; /* descriptor */ typedef unsigned long vmscond; /* vms condition value */ vmscond FDECL(lib$find_file, (const struct dsc *, struct dsc *, genericptr *)); vmscond FDECL(lib$find_file_end, (void **)); /* collect a list of character names from all save files for this player */ int vms_get_saved_games(savetemplate, outarray) const char *savetemplate; /* wildcarded save file name in native VMS format */ char ***outarray; { struct dsc in, out; unsigned short l; int count, asize; char *charname, wildcard[255 + 1], filename[255 + 1]; genericptr_t context = 0; Strcpy(wildcard, savetemplate); /* plname_from_file overwrites SAVEF */ in.mbz = 0; /* class and type; leave them unspecified */ in.len = (unsigned short) strlen(wildcard); in.adr = wildcard; out.mbz = 0; out.len = (unsigned short) (sizeof filename - 1); out.adr = filename; *outarray = 0; count = asize = 0; /* note: only works as intended if savetemplate is a wildcard filespec */ while (lib$find_file(&in, &out, &context) & 1) { /* strip trailing blanks */ for (l = out.len; l > 0; --l) if (filename[l - 1] != ' ') break; filename[l] = '\0'; if ((charname = plname_from_file(filename)) != 0) savefile(charname, count++, &asize, outarray); } (void) lib$find_file_end(&context); return count; } #endif /* SELECTSAVED */ #ifdef PANICTRACE /* nethack has detected an internal error; try to give a trace of call stack */ void vms_traceback(how) int how; /* 1: exit after traceback; 2: stay in debugger */ { /* assumes that a static initializer applies to the first union field and that no padding will be placed between len and str */ union dbgcmd { struct ascic { unsigned char len; /* 8-bit length prefix */ char str[79]; /* could be up to 255, but we don't need that much */ } cmd_fields; char cmd[1 + 79]; }; #define DBGCMD(arg) \ { \ (unsigned char)(sizeof arg - sizeof ""), arg \ } static union dbgcmd dbg[3] = { /* prologue for less verbose feedback (when combined with $ define/User_mode dbg$output _NL: ) */ DBGCMD("set Log SYS$OUTPUT: ; set Output Log,noTerminal,noVerify"), /* enable modules with calls present on stack, then show those calls; limit traceback to 18 stack frames to avoid scrolling off screen (could check termcap LI and maybe give more, but we're operating in a last-gasp environment so apply the KISS principle...) */ DBGCMD("set Module/Calls ; show Calls 18"), /* epilogue; "exit" ends the sequence it's part of, but it doesn't seem able to cause program termination end when used separately; instead of relying on it, we'll redirect debugger input to come from the null device so that it'll get an end-of-input condition when it tries to get a command from the user */ DBGCMD("exit"), }; #undef DBGCMD /* * If we've been linked /noTraceback then we can't provide any * trace of the call stack. Linking that way is required if * nethack.exe is going to be installed with privileges, so the * SECURE configuration usually won't have any trace feedback. */ if (!debuggable) { ; /* debugger not available to catch lib$signal(SS$_DEBUG) */ } else if (how == 2) { /* omit prologue and epilogue (dbg[0] and dbg[2]) */ (void) lib$signal(SS$_DEBUG, 1, dbg[1].cmd); } else if (how == 1) { /* * Suppress most of debugger's initial feedback to avoid scaring * users (and scrolling panic message off the screen). Also control * debugging environment to try to prevent unexpected complications. */ /* start up with output going to /dev/null instead of stdout; once started, output is sent to log file that's actually stdout */ (void) vms_define("DBG$OUTPUT", "_NL:", 0); /* take input from null device so debugger will see end-on-input and quit if/when it tries to get a command from the user */ (void) vms_define("DBG$INPUT", "_NL:", 0); /* bypass any debugger initialization file the user might have */ (void) vms_define("DBG$INIT", "_NL:", 0); /* force tty interface by suppressing DECwindows/Motif interface */ (void) vms_define("DBG$DECW$DISPLAY", " ", 0); /* raise an exception for the debugger to catch */ (void) lib$signal(SS$_DEBUG, 3, dbg[0].cmd, dbg[1].cmd, dbg[2].cmd); } vms_exit(2); /* don't return to caller (2==arbitrary non-zero) */ /* NOT REACHED */ } #endif /* PANICTRACE */ /* * Play Hunt the Wumpus to see whether the debugger lurks nearby. * It all takes place before nethack even starts, and sets up * `debuggable' to control possible use of lib$signal(SS$_DEBUG). */ typedef unsigned FDECL((*condition_handler), (unsigned *, unsigned *)); extern condition_handler FDECL(lib$establish, (condition_handler)); extern unsigned FDECL(lib$sig_to_ret, (unsigned *, unsigned *)); /* SYS$IMGSTA() is not documented: if called at image startup, it controls access to the debugger; fortunately, the linker knows now to find it without needing to link against sys.stb (VAX) or use LINK/System (Alpha). We won't be calling it, but we indirectly check whether it has already been called by checking if nethack.exe has it as a transfer address. */ extern unsigned FDECL(sys$imgsta, ()); /* * These structures are in header files contained in sys$lib_c.tlb, * but that isn't available on sufficiently old versions of VMS. * Construct our own: partly stubs, with simpler field names and * without ugly unions. Contents derived from Bliss32 definitions * in lib.req and/or Macro32 definitions in lib.mlb. */ struct ihd { /* (vax) image header, $IHDDEF */ unsigned short size, activoff; unsigned char otherstuff[512 - 4]; }; struct eihd { /* extended image header, $EIHDDEF */ unsigned long majorid, minorid, size, isdoff, activoff; unsigned char otherstuff[512 - 20]; }; struct iha { /* (vax) image header activation block, $IHADEF */ unsigned long trnadr1, trnadr2, trnadr3; unsigned long fill_, inishr; }; struct eiha { /* extended image header activation block, $EIHADEF */ unsigned long size, spare; unsigned long trnadr1[2], trnadr2[2], trnadr3[2], trnadr4[2], inishr[2]; }; /* * We're going to use lib$initialize, not because we need or * want to be called before main(), but because one of the * arguments passed to a lib$initialize callback is a pointer * to the image header (somewhat complex data structure which * includes the memory location(s) of where to start executing) * of the program being initialized. It comes in two flavors, * one used by VAX and the other by Alpha and IA64. * * An image can have up to three transfer addresses; one of them * decides whether to run under debugger control (RUN/Debug, or * LINK/Debug + plain RUN), another handles lib$initialize calls * if that's used, and the last is to start the program itself * (a jacket built around main() for code compiled with DEC C). * They aren't always all present; some might be zero/null. * A shareable image (pre-linked library) usually won't have any, * but can have a separate initializer (not of interest here). * * The transfer targets don't have fixed slots but do occur in a * particular order: * link link lib$initialize lib$initialize * sharable /noTrace /Trace + /noTrace + /Traceback * 1: (none) main debugger init-handler debugger * 2: main main init-handler * 3: main * * We check whether the first transfer address is SYS$IMGSTA(). * If it is, the debugger should be available to catch SS$_DEBUG * exception even when we don't start up under debugger control. * One extra complication: if we *do* start up under debugger * control, the first address in the in-memory copy of the image * header will be changed from sys$imgsta() to a value in system * space. [I don't know how to reference that one symbolically, * so I'm going to treat any address in system space as meaning * that the debugger is available. pr] */ /* called via lib$initialize during image activation: before main() and with magic arguments; C run-time library won't be initialized yet */ /*ARGSUSED*/ int vmsexeini(inirtn_unused, clirtn_unused, imghdr) const void *inirtn_unused, *clirtn_unused; const unsigned char *imghdr; { const struct ihd *vax_hdr; const struct eihd *axp_hdr; const struct iha *vax_xfr; const struct eiha *axp_xfr; unsigned long trnadr1; (void) lib$establish(lib$sig_to_ret); /* set up condition handler */ /* * Check the first of three transfer addresses to see whether * it is SYS$IMGSTA(). Note that they come from a file, * where they reside as longword or quadword integers rather * than function pointers. (Basically just a C type issue; * casting back and forth between integer and pointer doesn't * change any bits for the architectures VMS runs on.) */ debuggable = 0; /* start with a guess rather than bothering to figure out architecture */ vax_hdr = (struct ihd *) imghdr; if (vax_hdr->size >= 512) { /* this is a VAX-specific header; addresses are longwords */ vax_xfr = (struct iha *) (imghdr + vax_hdr->activoff); trnadr1 = vax_xfr->trnadr1; } else { /* the guess above was wrong; imghdr's first word is not the size field, it's a version number component */ axp_hdr = (struct eihd *) imghdr; /* this is an Alpha or IA64 header; addresses are quadwords but we ignore the upper half which will be all 0's or 0xF's (we hope; if not, assume it still won't matter for this test) */ axp_xfr = (struct eiha *) (imghdr + axp_hdr->activoff); trnadr1 = axp_xfr->trnadr1[0]; } if ((unsigned (*) ()) trnadr1 == sys$imgsta || /* check whether first transfer address points to system space [we want (trnadr1 >= 0x80000000UL) but really old compilers don't support the UL suffix, so do a signed compare instead] */ (long) trnadr1 < 0L) debuggable = 1; return 1; /* success (return value here doesn't actually matter) */ } /* * Setting up lib$initialize transfer block is trivial with Macro32, * but we don't want to introduce use of assembler code. Doing it * with C requires jiggery-pokery here and again when linking, and * may not work with some compiler versions. The lib$initialize * transfer block is an open-ended array of 32-bit routine addresses * in a psect named "lib$initialize" with particular attributes (one * being "concatenate" so that multiple instances of lib$initialize * are appended rather than overwriting each other). * * VAX C made global variables become named program sections, to be * compatable with Fortran COMMON blocks, simplifying mixed-language * programs. GNU C for VAX/VMS did the same, to be compatable with * VAX C. By default, DEC C makes global variables be global symbols * instead, with its /Extern_Model=Relaxed_Ref_Def mode, but can be * told to be VAX C compatable by using /Extern_Model=Common_Block. * * We don't want to force that for the whole program; occasional use * of /Extern_Model=Strict_Ref_Def to find mistakes is too useful. * Also, using symbols instead of psects is more robust when linking * with an object library if the module defining the symbol contains * only data. With a psect, any declaration is enough to become a * definition and the linker won't bother hunting through a library * to find another one unless explicitly told to do so. Bad news * if that other one happens to include the intended initial value * and someone bypasses `make' to link interactively but neglects * to give the linker enough explicit directions. Linking like that * would work, but the program wouldn't. * * So, we switch modes for this hack only. Besides, psect attributes * for lib$initialize are different from the ones used for ordinary * variables, so we'd need to resort to some linker magic anyway. * (With assembly language, in addtion to having full control of the * psect attributes in the source code, Macro32 would include enough * information in its object file such that linker wouldn't need any * extra instructions from us to make this work.) [If anyone links * manually now and neglects the esoteric details, vmsexeini() won't * get called and `debuggable' will stay 0, so lib$signal(SS$_DEBUG) * will be avoided even when its use is viable. But the program will * still work correctly.] */ #define C_LIB$INITIALIZE /* comment out if this won't compile... */ /* (then `debuggable' will always stay 0) */ #ifdef C_LIB$INITIALIZE #ifdef __DECC #pragma extern_model save /* push current mode */ #pragma extern_model common_block /* set new mode */ #endif /* values are 32-bit function addresses; pointers might be 64 so avoid them */ extern const unsigned long lib$initialize[1]; /* size is actually variable */ const unsigned long lib$initialize[] = { (unsigned long) (void *) vmsexeini }; #ifdef __DECC #pragma extern_model restore /* pop previous mode */ #endif /* We also need to link against a linker options file containing: sys$library:starlet.olb/Include=(lib$initialize) psect_attr=lib$initialize, Con,Usr,noPic,Rel,Gbl,noShr,noExe,Rd,noWrt,Long */ #endif /* C_LIB$INITIALIZE */ /* End of debugger hackery. */ /*vmsunix.c*/ nethack-3.6.0/sys/wince/Install.ce0000664000076400007660000001345712536476415016026 0ustar paxedpaxedCopyright (c) Alex Kompel, 2002 NetHack may be freely redistributed. See license for details. ======================================================================== Instructions for compiling and installing NetHack 3.6 on a Windows CE or PocketPC system ======================================================================== Last revision: $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ Credit for the porting of NetHack to Windows CE goes to Alex Kompel who initially developed and contributed the port. In order to build NetHack for Windows CE, you need *both* of the following: o A copy of Microsoft Visual C V6.0 SP3 or later. Things may work with an earlier version of the compiler, but the current code has not been tested with an earlier version. o Embedded Visual C++ 3.0 or later FIRST STEP: The first step in building NetHack for Windows CE is to execute sys/wince/cesetup.bat. From the command prompt: cd sys\wince cesetup From a Windows explorer window: double-click on cesetup.bat A "wince" directory will be created off the top of the NetHack source tree, and a Microsoft embedded C workspace file will be placed in the top of the NetHack source tree. ------------ | BUILDING | ------------ Boostrapping the build process on Windows NT/2000/XP 1. With the Visual C++ 6.0 tools in your path, Run "nmake /f bootstrp.mak" from the wince folder. Compiling 2. Start the Embedded Visual C IDE. In the Embedded Visual C IDE Menus, choose: File | Open Workspace 3. Set up for the build. o In the Visual C "Open Workspace" dialog box, navigate to the top of your NetHack source directory tree. In there, highlight "wince.vcw" and click on Open. Once the workspace has been opened, you should see the following list in the Visual C selection window: + nethack_hpc files + nethack_palm_pc files + nethack_pocket_pc files + nethack_smartphone files o On the Embedded Visual C menus, choose: Build | Set Active Platform Select the platform that corresponds to your device: Palm-size PC 2.11 - palm size PC running Windows CE version 2.11 Pocket PC - palm-size PC running Windows CE 3.0 and higher (PocketPC) H/PC Pro 2.11 - handheld computers running Windows CE 2.11 anf higher Smartphone 2002 - Microsoft SmartPhone device o On the Visual C menus again, choose either: Build | Set Active Configuration where configuration is one of the following (make sure it matches the platform you have selected): nethack_hpc - Win32 (WCE MIPS) HPCRelease - H/PC Pro 2.11 MIPS processor release executable nethack_hpc - Win32 (WCE x86em) HPCDebug - H/PC Pro 2.11 x86 emulation debug executable nethack_hpc - Win32 (WCE ARM) HPCRelease - H/PC Pro 2.11 ARM processor release executable nethack_hpc - Win32 (WCE SH3) HPCRelease - H/PC Pro 2.11 SH3 processor release executable nethack_hpc - Win32 (WCE x86em) HPCRelease - H/PC Pro 2.11 x86 emulation release executable nethack_hpc - Win32 (WCE SH4) HPCRelease - H/PC Pro 2.11 SH4 processor release executable nethack_palm_pc - Win32 (WCE MIPS) PalmPCRelease - Palm-size PC 2.11 MIPS processor release executable nethack_palm_pc - Win32 (WCE x86em) PalmPCDebug - Palm-size PC 2.11 x86 emulation debug executable nethack_palm_pc - Win32 (WCE SH3) PalmPCRelease - Palm-size PC 2.11 SH3 processor release executable nethack_palm_pc - Win32 (WCE x86em) PalmPCRelease - Palm-size PC 2.11 x86 emulation release executable nethack_pocket_pc - Win32 (WCE MIPS) PocketPCRelease - Pocket PC MIPS processor release executable nethack_pocket_pc - Win32 (WCE ARM) PocketPCRelease - Pocket PC ARM processor release executable nethack_pocket_pc - Win32 (WCE x86em) PocketPCRelease - Pocket PC x86 emulation release executable nethack_pocket_pc - Win32 (WCE x86em) PocketPCDebug - Pocket PC x86 emulation debug executable nethack_pocket_pc - Win32 (WCE SH3) PocketPCRelease - Pocket PC SH3 processor release executable nethack_smartphone - Win32 (WCE ARM) SPhoneRelease - Smartphone 2002 ARM processor release executable nethack_smartphone - Win32 (WCE x86em) SPhoneDebug - Smartphone 2002 x86 emulation debug executable Building 4. Start your build. o On the Embedded Visual C menus once again, choose: Build | Build nethackm.exe This starts the build. It is likely that the IDE message window where you are doing the compiling will be occupied for a while. Notes: o You may get a bunch of warnings regarding missing include files in the beginning of the build process - ignore them. For some reason the tool that produces these messages ignores preprocessor directives. The actual build will go just fine. o Sometimes the compiler chokes on do_wear.c Ignore that - let the build finish. Then run it again - it will compile just fine. (Seems to be some sort of bug in EVC++) Transfer 5. Transfer the files and executables to your handheld by extracting the files into some folder on the CE device - that should do it. Notes If you want to use IBMGraphics make sure that you have a proper font installed on the device that supports OEM character set (for example, Lucida Console) PROBLEMS If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: http://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: DevTeam (at) nethack.org Happy NetHacking! nethack-3.6.0/sys/wince/bootstrp.mak0000664000076400007660000007216012536476415016451 0ustar paxedpaxed# NetHack 3.6 bootstrp.mak $NHDT-Date: 1432512801 2015/05/25 00:13:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ # Copyright (c) Michael Allison # # NetHack Windows CE bootstrap file for MS Visual C++ V6.x and # above and MS NMAKE # # This will: # - build makedefs # - #============================================================================== # Do not delete the following 3 lines. # TARGETOS=BOTH APPVER=4.0 !include # # Source directories. Makedefs hardcodes these, don't change them. # INCL = ..\include # NetHack include files DAT = ..\dat # NetHack data files DOC = ..\doc # NetHack documentation files UTIL = ..\util # Utility source SRC = ..\src # Main source SSYS = ..\sys\share # Shared system files NTSYS = ..\sys\winnt # NT Win32 specific files TTY = ..\win\tty # window port files (tty) WIN32 = ..\win\win32 # window port files (WINCE) WSHR = ..\win\share # Tile support files SWINCE= ..\wince # wince files WINCE = ..\wince # wince build area OBJ = $(WINCE)\ceobj DLB = $(DAT)\nhdat #========================================== # Setting up the compiler and linker # macros. All builds include the base ones. #========================================== CFLAGSBASE = -c $(cflags) $(cvarsmt) -I$(INCL) -nologo $(cdebug) $(WINPINC) -DDLB LFLAGSBASEC = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt) LFLAGSBASEG = $(linkdebug) $(guiflags) $(guilibsmt) comctl32.lib #========================================== # Util builds #========================================== CFLAGSU = $(CFLAGSBASE) $(WINPFLAG) LFLAGSU = $(LFLAGSBASEC) LEVCFLAGS= -c -nologo -DWINVER=0x0400 -DWIN32 -D_WIN32 \ -D_MT -MT -I..\include -nologo -Z7 -Od -DDLB #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== #.c{$(OBJ)}.o: # $(cc) $(CFLAGSU) -Fo$@ $< {$(SRC)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in sys\share #========================================== {$(SSYS)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in sys\winnt #========================================== {$(NTSYS)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< {$(NTSYS)}.h{$(INCL)}.h: copy $< $@ #========================================== # Rules for files in util #========================================== {$(UTIL)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in win\share #========================================== {$(WSHR)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< {$(WSHR)}.h{$(INCL)}.h: copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # copy $< $@ #========================================== # Rules for files in win\tty #========================================== {$(TTY)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in win\win32 #========================================== {$(WIN32)}.c{$(OBJ)}.o: $(cc) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in sys\wince #========================================== {$(SWINCE)}.c{$(OBJ)}.o: $(cc) $(CFLAGSU) -Fo$@ $< #========================================== #================ MACROS ================== #========================================== # # Shorten up the location for some files # O = $(OBJ)^\ U = $(UTIL)^\ # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o \ $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt # # These are not invoked during a normal game build in 3.5.0 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o TEXT_IO32 = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREADERS32 = $(O)gifrd32.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o DLBOBJ = $(O)dlb.o #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \ $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \ $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \ $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \ $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \ $(INCL)\ntconf.h $(INCL)\wceconf.h HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \ $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \ $(INCL)\permonst.h $(INCL)\mextra.h $(INCL)\monattk.h \ $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \ $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \ $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \ $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \ $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \ $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \ $(INCL)\wintty.h $(INCL)\trampoli.h LEV_H = $(INCL)\lev.h DGN_FILE_H = $(INCL)\dgn_file.h LEV_COMP_H = $(INCL)\lev_comp.h SP_LEV_H = $(INCL)\sp_lev.h TILE_H = ..\win\share\tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)\data.base #========================================== #=============== TARGETS ================== #========================================== # # The default make target (so just typing 'nmake' is useful). # default : all # # Everything # all : $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \ $(SRC)\monstr.c $(SRC)\vis_tab.c $(U)lev_comp.exe $(INCL)\vis_tab.h \ $(U)dgn_comp.exe $(U)uudecode.exe \ $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) $(SRC)\tile.c \ $(SWINCE)\nethack.ico $(SWINCE)\tiles.bmp $(SWINCE)\mnsel.bmp \ $(SWINCE)\mnunsel.bmp $(SWINCE)\petmark.bmp $(SWINCE)\mnselcnt.bmp \ $(SWINCE)\keypad.bmp $(SWINCE)\menubar.bmp @echo Done! $(O)sp_lev.tag: $(DAT)\bigroom.des $(DAT)\castle.des \ $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des \ $(DAT)\medusa.des $(DAT)\oracle.des $(DAT)\tower.des \ $(DAT)\yendor.des $(DAT)\arch.des $(DAT)\barb.des \ $(DAT)\caveman.des $(DAT)\healer.des $(DAT)\knight.des \ $(DAT)\monk.des $(DAT)\priest.des $(DAT)\ranger.des \ $(DAT)\rogue.des $(DAT)\samurai.des $(DAT)\sokoban.des \ $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(WINCE) echo sp_levs done > $(O)sp_lev.tag #$(NHRES): $(TILEBMP16) $(WINCE)\winhack.rc $(WINCE)\mnsel.bmp \ # $(WINCE)\mnselcnt.bmp $(WINCE)\mnunsel.bmp \ # $(WINCE)\petmark.bmp $(WINCE)\NetHack.ico $(WINCE)\rip.bmp \ # $(WINCE)\splash.bmp # $(rc) -r -fo$@ -i$(WINCE) -dNDEBUG $(WINCE)\winhack.rc # # Utility Targets. # #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) $(link) $(LFLAGSU) -out:$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(INCL)\patchlevel.h \ $(U)makedefs.c if not exist $(OBJ)\*.* echo creating directory $(OBJ) if not exist $(OBJ)\*.* mkdir $(OBJ) $(CC) $(CFLAGSU) -Fo$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe $(U)makedefs -v $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o $(link) $(LFLAGSU) -out:$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)\uudecode.c $(SWINCE)\NetHack.ico : $(U)uudecode.exe $(SWINCE)\nhico.uu chdir $(SWINCE) ..\util\uudecode.exe nhico.uu chdir $(WINCE) $(SWINCE)\mnsel.bmp: $(U)uudecode.exe $(SWINCE)\mnsel.uu chdir $(SWINCE) ..\util\uudecode.exe mnsel.uu chdir $(WINCE) $(SWINCE)\mnselcnt.bmp: $(U)uudecode.exe $(SWINCE)\mnselcnt.uu chdir $(SWINCE) ..\util\uudecode.exe mnselcnt.uu chdir $(WINCE) $(SWINCE)\mnunsel.bmp: $(U)uudecode.exe $(SWINCE)\mnunsel.uu chdir $(SWINCE) ..\util\uudecode.exe mnunsel.uu chdir $(WINCE) $(SWINCE)\petmark.bmp: $(U)uudecode.exe $(SWINCE)\petmark.uu chdir $(SWINCE) ..\util\uudecode.exe petmark.uu chdir $(WINCE) $(SWINCE)\rip.bmp: $(U)uudecode.exe $(SWINCE)\rip.uu chdir $(SWINCE) ..\util\uudecode.exe rip.uu chdir $(WINCE) $(SWINCE)\splash.bmp: $(U)uudecode.exe $(SWINCE)\splash.uu chdir $(SWINCE) ..\util\uudecode.exe splash.uu chdir $(WINCE) $(SWINCE)\keypad.bmp: $(U)uudecode.exe $(SWINCE)\keypad.uu chdir $(SWINCE) ..\util\uudecode.exe keypad.uu chdir $(WINCE) $(SWINCE)\menubar.bmp: $(U)uudecode.exe $(SWINCE)\menubar.uu chdir $(SWINCE) ..\util\uudecode.exe menubar.uu chdir $(WINCE) #========================================== # Level Compiler Stuff #========================================== $(U)lev_comp.exe: $(SPLEVOBJS) echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(SPLEVOBJS:^ =^ ) << $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y @echo We will copy the prebuilt lev_yacc.c and @echo lev_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul @echo /**/ >>$(U)lev_yacc.c @echo /**/ >>$(INCL)\lev_comp.h $(U)lev_$(LEX).c: $(U)lev_comp.l @echo We will copy the prebuilt lev_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\lev_lex.c $@ >nul @echo /**/ >>$@ #========================================== # Dungeon Compiler Stuff #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(DGNCOMPOBJS:^ =^ ) << $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y @echo We will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul @echo /**/ >>$(U)dgn_yacc.c @echo /**/ >>$(INCL)\dgn_comp.h $(U)dgn_$(LEX).c: $(U)dgn_comp.l @echo We will copy the prebuilt dgn_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\dgn_lex.c $@ >nul @echo /**/ >>$@ #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: if not exist $(OBJ)\*.* echo creating directory $(OBJ) if not exist $(OBJ)\*.* mkdir $(OBJ) echo directory created >$@ #========================================== # Notify of any CL environment variables # in effect since they change the compiler # options. #========================================== envchk: ! IF "$(CL)"!="" @echo Warning, the CL Environment variable is defined: @echo CL=$(CL) ! ENDIF @echo ---- @echo NOTE: This build will include tile support. @echo ---- #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in ..\include #=========================================== $(INCL)\win32api.h: $(NTSYS)\win32api.h copy $(NTSYS)\win32api.h $@ #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o << $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h $(CC) $(CFLAGSU) /Fo$@ $(SRC)\dlb.c $(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h $(CC) $(CFLAGSU) /Fo$@ $(UTIL)\dlb_main.c #$(DAT)\porthelp: $(NTSYS)\porthelp # copy $(NTSYS)\porthelp $@ >nul $(DAT)\nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon \ $(DAT)\license $(O)sp_lev.tag cd $(DAT) echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cIf dlb.lst nhdat cd $(WINCE) #========================================== # Tile Mapping #========================================== $(SRC)\tile.c: $(U)tilemap.exe echo A new $@ has been created $(U)tilemap $(U)tilemap.exe: $(O)tilemap.o $(link) $(LFLAGSU) -out:$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ $(WSHR)\tilemap.c $(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H) $(CC) $(CFLAGSU) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) $(CC) $(CFLAGSU) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c $(O)gifrd32.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c $(O)tilete32.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c $(SWINCE)\tiles.bmp: $(U)tile2bmp.exe $(TILEFILES) echo Creating 16x16 binary tile files (this may take some time) $(U)tile2bmp $@ #$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32) # echo Creating 32x32 binary tile files (this may take some time) # $(U)til2bm32 $(TILEBMP32) $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) @echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)tile2bmp.o $(TEXT_IO:^ =^ ) << $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) @echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)til2bm32.o $(TEXT_IO32:^ =^ ) << $(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(CC) $(CFLAGSU) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c $(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(CC) $(CFLAGSU) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)\data: $(UTIL)\makedefs.exe $(U)makedefs -d $(DAT)\rumors: $(UTIL)\makedefs.exe $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(UTIL)\makedefs.exe $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(UTIL)\makedefs.exe $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(UTIL)\makedefs.exe $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(WINCE) # # NT dependencies # # #$(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c # $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(NTSYS)\nttty.c #$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c # $(CC) $(CFLAGSU) -Fo$@ $(NTSYS)\winnt.c #$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c # $(CC) $(CFLAGSU) -Fo$@ $(NTSYS)\ntsound.c # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) $(CC) $(CFLAGSU) -Fo$@ $(U)panic.c # # The rest are stolen from sys/unix/Makefile.src, # with slashes changed to back-slashes # and -c (which is included in CFLAGSU) substituted # with -Fo$@ , but otherwise untouched. That # means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\atari\tos.c $(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\win32api.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcsys.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pctty.c $(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcunix.c $(O)random.o: ..\sys\share\random.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\random.c $(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\ioctl.c $(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\unixtty.c $(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\unix\unixmain.c $(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\unix\unixunix.c $(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\be\bemain.c $(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\getline.c $(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\termcap.c $(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\topl.c $(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\date.h $(INCL)\patchlevel.h $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\wintty.c $(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\Window.c $(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\dialogs.c $(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h ..\win\X11\nh72icon \ ..\win\X11\nh56icon ..\win\X11\nh32icon $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winX.c $(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmap.c $(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmenu.c $(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmesg.c $(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmisc.c $(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winstat.c $(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\wintext.c $(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winval.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \ ..\win\gnome\gnmain.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnaskstr.c $(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnbind.c $(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnglyph.c $(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \ ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \ $(INCL)\date.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmain.c $(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h $(HACK_H) $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmap.c $(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnbind.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmenu.c $(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmesg.c $(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H) $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnopts.c $(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \ ..\win\gnome\gnmain.h $(HACK_H) $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnplayer.c $(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \ ..\win\gnome\gnmain.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnsignal.c $(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \ ..\win\gnome\gnomeprv.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnstatus.c $(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \ ..\win\gnome\gn_rip.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gntext.c $(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnyesno.c $(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\wingem.h $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\wingem.c $(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \ $(INCL)\wintype.h $(INCL)\wingem.h $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\wingem1.c $(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\load_img.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\qt_win.h \ $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \ $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_win.cpp $(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_clust.cpp $(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H) $(O)vis_tab.o: $(SRC)\vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h $(O)allmain.o: $(SRC)\allmain.c $(HACK_H) $(O)alloc.o: $(SRC)\alloc.c $(CONFIG_H) $(O)apply.o: $(SRC)\apply.c $(HACK_H) $(O)artifact.o: $(SRC)\artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(O)attrib.o: $(SRC)\attrib.c $(HACK_H) $(INCL)\artifact.h $(O)ball.o: $(SRC)\ball.c $(HACK_H) $(O)bones.o: $(SRC)\bones.c $(HACK_H) $(INCL)\lev.h $(O)botl.o: $(SRC)\botl.c $(HACK_H) $(O)cmd.o: $(SRC)\cmd.c $(HACK_H) $(INCL)\func_tab.h $(O)dbridge.o: $(SRC)\dbridge.c $(HACK_H) $(O)decl.o: $(SRC)\decl.c $(HACK_H) $(O)detect.o: $(SRC)\detect.c $(HACK_H) $(INCL)\artifact.h $(O)dig.o: $(SRC)\dig.c $(HACK_H) $(O)display.o: $(SRC)\display.c $(HACK_H) $(O)dlb.o: $(SRC)\dlb.c $(CONFIG_H) $(INCL)\dlb.h $(O)do.o: $(SRC)\do.c $(HACK_H) $(INCL)\lev.h $(O)do_name.o: $(SRC)\do_name.c $(HACK_H) $(O)do_wear.o: $(SRC)\do_wear.c $(HACK_H) $(O)dog.o: $(SRC)\dog.c $(HACK_H) $(O)dogmove.o: $(SRC)\dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(O)dokick.o: $(SRC)\dokick.c $(HACK_H) $(O)dothrow.o: $(SRC)\dothrow.c $(HACK_H) $(O)drawing.o: $(SRC)\drawing.c $(HACK_H) $(INCL)\tcap.h $(O)dungeon.o: $(SRC)\dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h $(O)eat.o: $(SRC)\eat.c $(HACK_H) $(O)end.o: $(SRC)\end.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)engrave.o: $(SRC)\engrave.c $(HACK_H) $(INCL)\lev.h $(O)exper.o: $(SRC)\exper.c $(HACK_H) $(O)explode.o: $(SRC)\explode.c $(HACK_H) $(O)extralev.o: $(SRC)\extralev.c $(HACK_H) $(O)files.o: $(SRC)\files.c $(HACK_H) $(INCL)\dlb.h $(O)fountain.o: $(SRC)\fountain.c $(HACK_H) $(O)hack.o: $(SRC)\hack.c $(HACK_H) $(O)hacklib.o: $(SRC)\hacklib.c $(HACK_H) $(O)invent.o: $(SRC)\invent.c $(HACK_H) $(INCL)\artifact.h $(O)light.o: $(SRC)\light.c $(HACK_H) $(INCL)\lev.h $(O)lock.o: $(SRC)\lock.c $(HACK_H) $(O)mail.o: $(SRC)\mail.c $(HACK_H) $(INCL)\mail.h $(O)makemon.o: $(SRC)\makemon.c $(HACK_H) $(O)mapglyph.o: $(SRC)\mapglyph.c $(HACK_H) $(O)mcastu.o: $(SRC)\mcastu.c $(HACK_H) $(O)mhitm.o: $(SRC)\mhitm.c $(HACK_H) $(INCL)\artifact.h $(O)mhitu.o: $(SRC)\mhitu.c $(HACK_H) $(INCL)\artifact.h $(O)minion.o: $(SRC)\minion.c $(HACK_H) $(O)mklev.o: $(SRC)\mklev.c $(HACK_H) $(O)mkmap.o: $(SRC)\mkmap.c $(HACK_H) $(INCL)\sp_lev.h $(O)mkmaze.o: $(SRC)\mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h $(O)mkobj.o: $(SRC)\mkobj.c $(HACK_H) $(INCL)\artifact.h $(O)mkroom.o: $(SRC)\mkroom.c $(HACK_H) $(O)mon.o: $(SRC)\mon.c $(HACK_H) $(INCL)\mfndpos.h $(O)mondata.o: $(SRC)\mondata.c $(HACK_H) $(O)monmove.o: $(SRC)\monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h $(O)monst.o: $(SRC)\monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\dungeon.h $(INCL)\color.h $(O)mplayer.o: $(SRC)\mplayer.c $(HACK_H) $(O)mthrowu.o: $(SRC)\mthrowu.c $(HACK_H) $(O)muse.o: $(SRC)\muse.c $(HACK_H) $(O)music.o: $(SRC)\music.c $(HACK_H) #interp.c $(O)o_init.o: $(SRC)\o_init.c $(HACK_H) $(INCL)\lev.h $(O)objects.o: $(SRC)\objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h $(O)objnam.o: $(SRC)\objnam.c $(HACK_H) $(O)options.o: $(SRC)\options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h $(O)pager.o: $(SRC)\pager.c $(HACK_H) $(INCL)\dlb.h $(O)pickup.o: $(SRC)\pickup.c $(HACK_H) $(O)pline.o: $(SRC)\pline.c $(HACK_H) $(O)polyself.o: $(SRC)\polyself.c $(HACK_H) $(O)potion.o: $(SRC)\potion.c $(HACK_H) $(O)pray.o: $(SRC)\pray.c $(HACK_H) $(O)priest.o: $(SRC)\priest.c $(HACK_H) $(INCL)\mfndpos.h $(O)quest.o: $(SRC)\quest.c $(HACK_H) $(INCL)\qtext.h $(O)questpgr.o: $(SRC)\questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h $(O)read.o: $(SRC)\read.c $(HACK_H) $(O)rect.o: $(SRC)\rect.c $(HACK_H) $(O)region.o: $(SRC)\region.c $(HACK_H) $(INCL)\lev.h $(O)restore.o: $(SRC)\restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(O)rip.o: $(SRC)\rip.c $(HACK_H) $(O)rnd.o: $(SRC)\rnd.c $(HACK_H) $(O)role.o: $(SRC)\role.c $(HACK_H) $(O)rumors.o: $(SRC)\rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)save.o: $(SRC)\save.c $(HACK_H) $(INCL)\lev.h $(O)shk.o: $(SRC)\shk.c $(HACK_H) $(O)shknam.o: $(SRC)\shknam.c $(HACK_H) $(O)sit.o: $(SRC)\sit.c $(HACK_H) $(INCL)\artifact.h $(O)sounds.o: $(SRC)\sounds.c $(HACK_H) $(O)sp_lev.o: $(SRC)\sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h $(O)spell.o: $(SRC)\spell.c $(HACK_H) $(O)steal.o: $(SRC)\steal.c $(HACK_H) $(O)steed.o: $(SRC)\steed.c $(HACK_H) $(O)teleport.o: $(SRC)\teleport.c $(HACK_H) $(O)timeout.o: $(SRC)\timeout.c $(HACK_H) $(INCL)\lev.h $(O)topten.o: $(SRC)\topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h $(O)track.o: $(SRC)\track.c $(HACK_H) $(O)trap.o: $(SRC)\trap.c $(HACK_H) $(O)u_init.o: $(SRC)\u_init.c $(HACK_H) $(O)uhitm.o: $(SRC)\uhitm.c $(HACK_H) $(O)vault.o: $(SRC)\vault.c $(HACK_H) $(O)version.o: $(SRC)\version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h $(O)vision.o: $(SRC)\vision.c $(HACK_H) $(INCL)\vis_tab.h $(O)weapon.o: $(SRC)\weapon.c $(HACK_H) $(O)were.o: $(SRC)\were.c $(HACK_H) $(O)wield.o: $(SRC)\wield.c $(HACK_H) $(O)windows.o: $(SRC)\windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h $(O)wizard.o: $(SRC)\wizard.c $(HACK_H) $(INCL)\qtext.h $(O)worm.o: $(SRC)\worm.c $(HACK_H) $(INCL)\lev.h $(O)worn.o: $(SRC)\worn.c $(HACK_H) $(O)write.o: $(SRC)\write.c $(HACK_H) $(O)zap.o: $(SRC)\zap.c $(HACK_H) # end of file nethack-3.6.0/sys/wince/ceinc/assert.h0000664000076400007660000000036112536476415016630 0ustar paxedpaxed/*** *assert.h - define the assert macro * ****/ #undef assert #ifdef NDEBUG #define assert(exp) ((void) 0) #else #define assert(exp) \ (void)((exp) || (panic("%s at %s line %ld", #exp, __FILE__, __LINE__), 1)) #endif /* NDEBUG */ nethack-3.6.0/sys/wince/ceinc/errno.h0000664000076400007660000000004412536476415016452 0ustar paxedpaxed/* empty file */ extern int errno; nethack-3.6.0/sys/wince/ceinc/fcntl.h0000664000076400007660000000356412536476415016445 0ustar paxedpaxed/*** *fcntl.h - file control options used by open() * *Purpose: * This file defines constants for the file control options used * by the _open() function. * [System V] * * [Public] * ****/ #ifndef _INC_FCNTL #define _INC_FCNTL #define _O_RDONLY 0x0000 /* open for reading only */ #define _O_WRONLY 0x0001 /* open for writing only */ #define _O_RDWR 0x0002 /* open for reading and writing */ #define _O_APPEND 0x0008 /* writes done at eof */ #define _O_CREAT 0x0100 /* create and open file */ #define _O_TRUNC 0x0200 /* open and truncate */ #define _O_EXCL 0x0400 /* open only if file doesn't already exist */ /* O_TEXT files have sequences translated to on read()'s, ** and sequences translated to on write()'s */ #define _O_TEXT 0x4000 /* file mode is text (translated) */ #define _O_BINARY 0x8000 /* file mode is binary (untranslated) */ /* macro to translate the C 2.0 name used to force binary mode for files */ #define _O_RAW _O_BINARY /* Open handle inherit bit */ #define _O_NOINHERIT 0x0080 /* child process doesn't inherit file */ /* Temporary file bit - file is deleted when last handle is closed */ #define _O_TEMPORARY 0x0040 /* temporary file bit */ /* sequential/random access hints */ #define _O_SEQUENTIAL 0x0020 /* file access is primarily sequential */ #define _O_RANDOM 0x0010 /* file access is primarily random */ #if !__STDC__ || defined(_POSIX_) /* Non-ANSI names for compatibility */ #define O_RDONLY _O_RDONLY #define O_WRONLY _O_WRONLY #define O_RDWR _O_RDWR #define O_APPEND _O_APPEND #define O_CREAT _O_CREAT #define O_TRUNC _O_TRUNC #define O_EXCL _O_EXCL #define O_TEXT _O_TEXT #define O_BINARY _O_BINARY #define O_RAW _O_BINARY #define O_TEMPORARY _O_TEMPORARY #define O_NOINHERIT _O_NOINHERIT #define O_SEQUENTIAL _O_SEQUENTIAL #define O_RANDOM _O_RANDOM #endif /* __STDC__ */ #endif /* _INC_FCNTL */ nethack-3.6.0/sys/wince/ceinc/sys/stat.h0000664000076400007660000000002112536476415017111 0ustar paxedpaxed/* empty file */ nethack-3.6.0/sys/wince/celib.c0000664000076400007660000005264112536476415015327 0ustar paxedpaxed/* NetHack 3.6 celib.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #define NEED_VARARGS #include "hack.h" #include // #include "wceconf.h" static union { time_t t_val; struct time_pack { unsigned int ss : 6; unsigned int mm : 6; unsigned int dd : 5; unsigned int hh : 6; unsigned int mo : 4; unsigned int yr : 10; unsigned int wd : 3; } tm_val; } _t_cnv; #define IS_LEAP(yr) (((yr) % 4 == 0 || (yr) % 100 == 0) && !(yr) % 400 == 0) static char _day_mo_leap[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static char _day_mo[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; struct tm *__cdecl localtime(const time_t *ptime) { static struct tm ptm; int i; if (!ptime) return NULL; _t_cnv.t_val = *ptime; ptm.tm_sec = _t_cnv.tm_val.ss; /* seconds after the minute - [0,59] */ ptm.tm_min = _t_cnv.tm_val.mm; /* minutes after the hour - [0,59] */ ptm.tm_hour = _t_cnv.tm_val.hh; /* hours since midnight - [0,23] */ ptm.tm_mday = _t_cnv.tm_val.dd; /* day of the month - [1,31] */ ptm.tm_mon = _t_cnv.tm_val.mo - 1; /* months since January - [0,11] */ ptm.tm_year = _t_cnv.tm_val.yr; /* years since 1900 */ ptm.tm_wday = _t_cnv.tm_val.wd; /* days since Sunday - [0,6] */ ptm.tm_yday = _t_cnv.tm_val.dd; /* days since January 1 - [0,365] */ for (i = 0; i < ptm.tm_mon; i++) ptm.tm_yday += IS_LEAP(_t_cnv.tm_val.yr + 1900) ? _day_mo_leap[i] : _day_mo[i]; ptm.tm_isdst = 0; /* daylight savings time flag - NOT IMPLEMENTED */ return &ptm; } time_t __cdecl time(time_t *timeptr) { SYSTEMTIME stm; GetLocalTime(&stm); _t_cnv.tm_val.yr = stm.wYear - 1900; _t_cnv.tm_val.mo = stm.wMonth; _t_cnv.tm_val.dd = stm.wDay; _t_cnv.tm_val.hh = stm.wHour; _t_cnv.tm_val.mm = stm.wMinute; _t_cnv.tm_val.ss = stm.wSecond; _t_cnv.tm_val.wd = stm.wDayOfWeek; if (timeptr) *timeptr = _t_cnv.t_val; return _t_cnv.t_val; } time_t __cdecl mktime(struct tm *tb) { if (!tb) return (time_t) -1; _t_cnv.tm_val.yr = tb->tm_year; _t_cnv.tm_val.mo = tb->tm_mon; _t_cnv.tm_val.dd = tb->tm_mday; _t_cnv.tm_val.hh = tb->tm_hour; _t_cnv.tm_val.mm = tb->tm_min; _t_cnv.tm_val.ss = tb->tm_sec; _t_cnv.tm_val.wd = tb->tm_wday; return _t_cnv.t_val; } /*------------------------------------------------------------------------------*/ /* __io.h__ */ /* Hack io.h function with stdio.h functions */ /* ASSUMPTION : int can hold FILE* */ static TCHAR _nh_cwd[MAX_PATH]; const int MAGIC_OFFSET = 5; #define FILE_TABLE_SIZE 256 static HANDLE _nh_file_table[FILE_TABLE_SIZE]; static int file_pointer = -1; static HANDLE get_file_handle(int i) { i -= MAGIC_OFFSET; if (i >= 0 && i < FILE_TABLE_SIZE) return _nh_file_table[i]; else return INVALID_HANDLE_VALUE; } static int alloc_file_handle(HANDLE h) { int i; if (file_pointer == -1) { file_pointer = 0; for (i = 0; i < FILE_TABLE_SIZE; i++) _nh_file_table[i] = INVALID_HANDLE_VALUE; } i = (file_pointer + 1) % FILE_TABLE_SIZE; while (_nh_file_table[i] != INVALID_HANDLE_VALUE) { if (i == file_pointer) { MessageBox(NULL, _T("Ran out of file handles."), _T("Fatal Error"), MB_OK); abort(); } i = (i + 1) % FILE_TABLE_SIZE; } file_pointer = i; _nh_file_table[file_pointer] = h; return file_pointer + MAGIC_OFFSET; } int __cdecl close(int f) { int retval; f -= MAGIC_OFFSET; if (f < 0 || f >= FILE_TABLE_SIZE) return -1; retval = (CloseHandle(_nh_file_table[f]) ? 0 : -1); _nh_file_table[f] = INVALID_HANDLE_VALUE; return retval; } int __cdecl creat(const char *fname, int mode) { HANDLE f; TCHAR wbuf[MAX_PATH + 1]; ZeroMemory(wbuf, sizeof(wbuf)); NH_A2W(fname, wbuf, MAX_PATH); f = CreateFile(wbuf, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (f == INVALID_HANDLE_VALUE) return -1; else return alloc_file_handle(f); } int __cdecl eof(int f) { DWORD fpos, fsize; HANDLE p = get_file_handle(f); if (f == -1) return -1; fpos = SetFilePointer(p, 0, NULL, FILE_CURRENT); fsize = SetFilePointer(p, 0, NULL, FILE_END); if (fpos == 0xFFFFFFFF || fsize == 0xFFFFFFFF) return -1; if (fpos == fsize) return 1; else { SetFilePointer(p, fpos, NULL, FILE_BEGIN); return 0; } } long __cdecl lseek(int f, long offset, int origin) { HANDLE p = get_file_handle(f); DWORD fpos; switch (origin) { case SEEK_SET: fpos = SetFilePointer(p, offset, NULL, FILE_BEGIN); break; case SEEK_CUR: fpos = SetFilePointer(p, offset, NULL, FILE_CURRENT); break; case SEEK_END: fpos = SetFilePointer(p, offset, NULL, FILE_END); break; default: fpos = 0xFFFFFFFF; break; } if (fpos == 0xFFFFFFFF) return -1; else return (long) fpos; } int __cdecl open(const char *filename, int oflag, ...) { TCHAR fname[MAX_PATH + 1]; TCHAR path[MAX_PATH + 1]; HANDLE f; DWORD fileaccess; DWORD filecreate; /* O_TEXT is not supported */ /* * decode the access flags */ switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { case _O_RDONLY: /* read access */ fileaccess = GENERIC_READ; break; case _O_WRONLY: /* write access */ fileaccess = GENERIC_READ | GENERIC_WRITE; break; case _O_RDWR: /* read and write access */ fileaccess = GENERIC_READ | GENERIC_WRITE; break; default: /* error, bad oflag */ return -1; } /* * decode open/create method flags */ switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) { case 0: case _O_EXCL: // ignore EXCL w/o CREAT filecreate = OPEN_EXISTING; break; case _O_CREAT: filecreate = OPEN_ALWAYS; break; case _O_CREAT | _O_EXCL: case _O_CREAT | _O_TRUNC | _O_EXCL: filecreate = CREATE_NEW; break; case _O_TRUNC: case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT filecreate = TRUNCATE_EXISTING; break; case _O_CREAT | _O_TRUNC: filecreate = CREATE_ALWAYS; break; default: return -1; } /* assemple the file name */ ZeroMemory(fname, sizeof(fname)); ZeroMemory(path, sizeof(path)); NH_A2W(filename, fname, MAX_PATH); if (*filename != '\\' && *filename != '/') { _tcscpy(path, _nh_cwd); _tcsncat(path, _T("\\"), MAX_PATH - _tcslen(path)); } _tcsncat(path, fname, MAX_PATH - _tcslen(path)); /* * try to open/create the file */ if ((f = CreateFile(path, fileaccess, 0, NULL, filecreate, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { return -1; } if (!(oflag & O_APPEND)) SetFilePointer(f, 0, NULL, FILE_BEGIN); return alloc_file_handle(f); } int __cdecl read(int f, void *buffer, unsigned int count) { HANDLE p = get_file_handle(f); DWORD bytes_read; if (!ReadFile(p, buffer, count, &bytes_read, NULL)) return -1; else return (int) bytes_read; } int __cdecl unlink(const char *filename) { TCHAR wbuf[MAX_PATH + 1]; TCHAR fname[MAX_PATH + 1]; ZeroMemory(wbuf, sizeof(wbuf)); ZeroMemory(fname, sizeof(fname)); NH_A2W(filename, wbuf, MAX_PATH); if (*filename != '\\' && *filename != '/') { _tcscpy(fname, _nh_cwd); _tcsncat(fname, _T("\\"), MAX_PATH - _tcslen(fname)); } _tcsncat(fname, wbuf, MAX_PATH - _tcslen(fname)); return !DeleteFileW(fname); } int __cdecl write(int f, const void *buffer, unsigned int count) { HANDLE p = get_file_handle(f); DWORD bytes_written; if (!WriteFile(p, buffer, count, &bytes_written, NULL)) return -1; else return (int) bytes_written; } int __cdecl rename(const char *oldname, const char *newname) { WCHAR f1[MAX_PATH + 1]; WCHAR f2[MAX_PATH + 1]; ZeroMemory(f1, sizeof(f1)); ZeroMemory(f2, sizeof(f2)); MultiByteToWideChar(CP_ACP, 0, oldname, -1, f1, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, newname, -1, f2, MAX_PATH); return !MoveFile(f1, f2); } int __cdecl access(const char *path, int mode) { DWORD attr; WCHAR f[MAX_PATH + 1]; ZeroMemory(f, sizeof(f)); MultiByteToWideChar(CP_ACP, 0, path, -1, f, MAX_PATH); attr = GetFileAttributes(f); if (attr == (DWORD) -1) return -1; if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & 2)) return -1; else return 0; } int chdir(const char *dirname) { ZeroMemory(_nh_cwd, sizeof(_nh_cwd)); NH_A2W(dirname, _nh_cwd, MAX_PATH); return 0; } char * getcwd(char *buffer, int maxlen) { if (maxlen < (int) _tcslen(_nh_cwd)) return NULL; else return NH_W2A(_nh_cwd, buffer, maxlen); } /*------------------------------------------------------------------------------*/ /* __errno.h__ */ int errno; /*------------------------------------------------------------------------------*/ /* * Chdrive() changes the default drive. */ void chdrive(char *str) { return; } /* * This is used in nhlan.c to implement some of the LAN_FEATURES. */ char * get_username(lan_username_size) int *lan_username_size; { static char username_buffer[BUFSZ]; strcpy(username_buffer, "nhsave"); return username_buffer; } void Delay(int ms) { (void) Sleep(ms); } void more() { } int isatty(int f) { return 0; } #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) int __cdecl isupper(int c) { char str[2]; WCHAR wstr[2]; str[0] = c; str[1] = 0; NH_A2W(str, wstr, 1); return iswupper(wstr[0]); } int __cdecl isdigit(int c) { return ('0' <= c && c <= '9'); } int __cdecl isxdigit(int c) { return (('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')); } int __cdecl isspace(int c) { char str[2]; WCHAR wstr[2]; str[0] = c; str[1] = 0; NH_A2W(str, wstr, 1); return iswspace(wstr[0]); } int __cdecl isprint(int c) { char str[2]; WCHAR wstr[2]; str[0] = c; str[1] = 0; NH_A2W(str, wstr, 1); return iswprint(wstr[0]); } char *__cdecl _strdup(const char *s) { char *p; p = malloc(strlen(s) + 1); return strcpy(p, s); } char *__cdecl strrchr(const char *s, int c) { WCHAR wstr[1024]; WCHAR *w; w = wcsrchr(NH_A2W(s, wstr, 1024), c); if (w) return (char *) (s + (w - wstr)); else return NULL; } int __cdecl _stricmp(const char *a, const char *b) { return strncmpi(a, b, 65535u); } #endif #if defined(WIN_CE_PS2xx) /* stdio.h functions are missing from PAlm Size PC SDK 1.2 (SH3 and MIPS) */ #pragma warning(disable : 4273) FILE *__cdecl fopen(const char *filename, const char *mode) { int modeflag; int whileflag; int filedes; /* First mode character must be 'r', 'w', or 'a'. */ switch (*mode) { case 'r': modeflag = _O_RDONLY; break; case 'w': modeflag = _O_WRONLY | _O_CREAT | _O_TRUNC; break; case 'a': modeflag = _O_WRONLY | _O_CREAT | _O_APPEND; break; default: return NULL; } whileflag = 1; while (*++mode && whileflag) switch (*mode) { case '+': if (modeflag & _O_RDWR) whileflag = 0; else { modeflag |= _O_RDWR; modeflag &= ~(_O_RDONLY | _O_WRONLY); } break; case 'b': if (modeflag & (_O_TEXT | _O_BINARY)) whileflag = 0; else modeflag |= _O_BINARY; break; case 't': /* not supported */ whileflag = 0; break; default: whileflag = 0; break; } if ((filedes = open(filename, modeflag)) == -1) return NULL; return (FILE *) filedes; } int __cdecl fscanf(FILE *f, const char *format, ...) { /* Format spec: %[*] [width] [l] type ] */ int ch; int sch; int matched = 0; int width = 65535; int modifier = -1; int skip_flag = 0; int n_read = 0; char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; char *p; va_list args; #define RETURN_SCANF(i) \ { \ va_end(args); \ return i; \ } #define NEXT_CHAR(f) (n_read++, fgetc(f)) va_start(args, format); ch = *format++; sch = NEXT_CHAR(f); while (ch && sch != EOF) { if (isspace(ch)) { while (ch && isspace(ch)) ch = *format++; while (sch != EOF && isspace(sch)) sch = NEXT_CHAR(f); format--; goto next_spec; } /* read % */ if (ch != '%') { if (sch != ch) RETURN_SCANF(matched); sch = NEXT_CHAR(f); goto next_spec; } else { /* process '%%' */ ch = *format++; if (ch == '%') { if (sch != '%') RETURN_SCANF(matched); sch = NEXT_CHAR(f); goto next_spec; } if (ch == '*') { /* read skip flag - '*' */ skip_flag = 1; ch = *format++; } /* get width */ if (isdigit(ch)) { width = 0; while (ch && isdigit(ch)) { width = width * 10 + (ch - '0'); ch = *format++; } } /* get modifier */ if (ch == 'l') { modifier = 'l'; ch = *format++; } /* get type */ switch (ch) { case 'c': if (!skip_flag) { *(va_arg(args, char *) ) = sch; matched++; } sch = NEXT_CHAR(f); goto next_spec; case 'd': p = buf; /* skip space */ while (sch != EOF && isspace(sch)) sch = NEXT_CHAR(f); while (sch != EOF && isdigit(sch) && --width >= 0) { *p++ = sch; sch = NEXT_CHAR(f); } *p = '\x0'; if (!skip_flag) { matched++; if (modifier == 'l') { *(va_arg(args, long *) ) = wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10); } else { *(va_arg(args, int *) ) = wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10); } } goto next_spec; case 'x': p = buf; while (sch != EOF && isspace(sch)) sch = NEXT_CHAR(f); while (sch != EOF && isxdigit(sch) && --width >= 0) { *p++ = sch; sch = NEXT_CHAR(f); } *p = '\x0'; if (!skip_flag) { matched++; if (modifier == 'l') { *(va_arg(args, long *) ) = wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16); } else { *(va_arg(args, int *) ) = wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16); } } goto next_spec; case 'n': *(va_arg(args, int *) ) = n_read; matched++; goto next_spec; case 's': if (skip_flag) { while (sch != EOF && !isspace(sch) && --width >= 0) { sch = NEXT_CHAR(f); } } else { p = va_arg(args, char *); while (sch != EOF && !isspace(sch) && --width >= 0) { *p++ = sch; sch = NEXT_CHAR(f); } *p = '\x0'; matched++; } goto next_spec; case '[': { char pattern[256]; int start, end; int negate; ZeroMemory(pattern, sizeof(pattern)); p = pattern; /* try to parse '^' modifier */ ch = *format++; if (ch == '^') { negate = 1; ch = *format++; } else { negate = 0; } if (ch == 0) RETURN_SCANF(EOF); for (; ch && ch != ']'; ch = *format++) { /* try to parse range: a-z */ if (format[0] == '-' && format[1] && format[1] != ']') { start = ch; format++; end = *format++; while (start <= end) { if (!strchr(pattern, (char) start)) *p++ = (char) start; start++; } } else { if (!strchr(pattern, (char) ch)) *p++ = (char) ch; } } if (skip_flag) { while (sch != EOF && strchr(pattern, sch) && --width >= 0) { sch = NEXT_CHAR(f); } } else { p = va_arg(args, char *); if (negate) while (sch != EOF && !strchr(pattern, sch) && --width >= 0) { *p++ = sch; sch = NEXT_CHAR(f); } else while (sch != EOF && strchr(pattern, sch) && --width >= 0) { *p++ = sch; sch = NEXT_CHAR(f); } *p = '\x0'; matched++; } } goto next_spec; default: RETURN_SCANF(EOF); } } next_spec: width = 65535; modifier = -1; skip_flag = 0; ch = *format++; } fseek(f, -1, SEEK_CUR); RETURN_SCANF(matched); #undef RETURN_SCANF #undef NEXT_CHAR } int __cdecl fprintf(FILE *f, const char *format, ...) { int retval; va_list args; if (!f || !format) return 0; va_start(args, format); retval = vfprintf(f, format, args); va_end(args); return retval; } int __cdecl vfprintf(FILE *f, const char *format, va_list args) { char buf[4096]; int retval; if (!f || !format) return 0; retval = vsprintf(buf, format, args); write((int) f, buf, strlen(buf)); return retval; } int __cdecl fgetc(FILE *f) { char c; int fh = (int) f; if (!f) return EOF; if (read(fh, &c, 1) == 1) return c; else return EOF; } char *__cdecl fgets(char *s, int size, FILE *f) { /* not the best performance but it will do for now...*/ char c; if (!f || !s || size == 0) return NULL; while (--size > 0) { if ((c = fgetc(f)) == EOF) return NULL; *s++ = c; if (c == '\n') break; } *s = '\x0'; return s; } int __cdecl printf(const char *format, ...) { int retval; va_list args; if (!format) return 0; va_start(args, format); retval = vprintf(format, args); va_end(args); return retval; } int __cdecl vprintf(const char *format, va_list args) { char buf[4096]; int retval; retval = vsprintf(buf, format, args); puts(buf); return retval; } // int __cdecl putchar(int); int __cdecl puts(const char *s) { TCHAR wbuf[4096]; NH_A2W(s, wbuf, 4096); MessageBox(NULL, wbuf, _T("stdout"), MB_OK); return 0; } FILE *__cdecl _getstdfilex(int desc) { return NULL; } int __cdecl fclose(FILE *f) { if (!f) return EOF; return close((int) f) == -1 ? EOF : 0; } size_t __cdecl fread(void *p, size_t size, size_t count, FILE *f) { int read_bytes; if (!f || !p || size == 0 || count == 0) return 0; read_bytes = read((int) f, p, size * count); return read_bytes > 0 ? (read_bytes / size) : 0; } size_t __cdecl fwrite(const void *p, size_t size, size_t count, FILE *f) { int write_bytes; if (!f || !p || size == 0 || count == 0) return 0; write_bytes = write((int) f, p, size * count); return write_bytes > 0 ? write_bytes / size : 0; } int __cdecl fflush(FILE *f) { return 0; } int __cdecl feof(FILE *f) { return (f && eof((int) f) == 0) ? 0 : 1; } int __cdecl fseek(FILE *f, long offset, int from) { return (f && lseek((int) f, offset, from) >= 0) ? 0 : 1; } long __cdecl ftell(FILE *f) { return f ? lseek((int) f, 0, SEEK_CUR) : -1; } #endif nethack-3.6.0/sys/wince/cesetup.bat0000775000076400007660000000264712536476415016251 0ustar paxedpaxed@REM NetHack 3.6 cesetup.bat $NHDT-Date: 1432512801 2015/05/25 00:13:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ @REM Copyright (c) Alex Kompel, 2002 @REM NetHack may be freely redistributed. See license for details. @REM Win32 nhsetup batch file, see Install.ce for details @REM @echo off REM REM Make sure directories necessary for build exist REM if NOT exist ..\..\wince\*.* mkdir ..\..\wince REM REM Get these files from the win\win32 port REM copy ..\..\win\win32\mnsel.uu ..\..\wince\mnsel.uu copy ..\..\win\win32\mnselcnt.uu ..\..\wince\mnselcnt.uu copy ..\..\win\win32\mnunsel.uu ..\..\wince\mnunsel.uu copy ..\..\win\win32\petmark.uu ..\..\wince\petmark.uu copy ..\..\sys\wince\menubar.uu ..\..\wince\menubar.uu copy ..\..\sys\wince\keypad.uu ..\..\wince\keypad.uu copy ..\..\sys\wince\nhico.uu ..\..\wince\nhico.uu REM REM Get these files from sys\wince REM copy bootstrp.mak ..\..\wince\bootstrp.mak copy wince.vcw ..\..\wince.vcw copy hpc.vcp ..\..\wince\wince_hpc.vcp copy palmpc.vcp ..\..\wince\wince_palm_pc.vcp copy pocketpc.vcp ..\..\wince\wince_pocket_pc.vcp copy smartphn.vcp ..\..\wince\wince_smartphone.vcp echo. echo Proceed with the following steps: echo. echo cd ..\..\wince echo nmake /f bootstrp.mak echo. echo Then start Embedded Visual C and open echo the workspace wince.vcw (at the top of the NetHack tree) echo to build. See Install.ce for details. echo. nethack-3.6.0/sys/wince/cesound.c0000664000076400007660000000145612536476415015707 0ustar paxedpaxed/* NetHack 3.6 cesound.c $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * cesound.c - Windows CE NetHack sound support * * */ #include "hack.h" #include #ifdef USER_SOUNDS void play_usersound(filename, volume) const char *filename; int volume; { TCHAR wbuf[MAX_PATH + 1]; /* pline("play_usersound: %s (%d).", filename, volume); */ ZeroMemory(wbuf, sizeof(wbuf)); (void) sndPlaySound(NH_A2W(filename, wbuf, MAX_PATH), SND_ASYNC | SND_NODEFAULT); } #endif /*USER_SOUNDS*/ /* cesound.c */ nethack-3.6.0/sys/wince/defaults.nh0000664000076400007660000000557012504242744016231 0ustar paxedpaxed# Sample config file for win32 NetHack # A '#' at the beginning of a line means the rest of the line is a comment. # # Some options MUST be set in this file, other options can be toggled while # playing. For a list of options available see the file. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # *** OPTIONS *** # # Use the IBM character set rather than just plain ascii characters # for tty window-port. # OPTIONS=IBMGraphics # *** Personal Preferences *** # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # #OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful #OPTIONS=dogname:Fido,catname:Morris,fruit:guava #OPTIONS=horsename:Silver #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose #OPTIONS=menustyle:traditional # # General options. You might also set "silent" so as not to attract # the boss's attention. # OPTIONS=time,noshowexp,number_pad,lit_corridor,rest_on_space # # If you want to get rid of "use #quit to quit..." use: #OPTIONS=suppress_alert:3.3.1 # # Set some options to control graphical window-port (these will # be safely and silently ignored by the tty port) # # Map window settings # possible map_mode options include: tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8| # ascii7x12|ascii8x12|ascii16x12|ascii12x16| # ascii10x18|fit_to_screen OPTIONS=map_mode:tiles,scroll_margin:4 # Menu settings # OPTIONS=font_menu:Arial # Other OPTIONS=hilite_pet,!toptenwin OPTIONS=!splash_screen,player_selection:prompts OPTIONS=vary_msgcount:3 OPTIONS=fullscreen,wraptext,softkeyboard # Status/message window colors # Possible color options include: # six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown, # blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue, # brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, # lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace, # background, btnface, btnshadow, btntext, captiontext, graytext, highlight, # highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar, # window, windowframe, windowtext. #OPTIONS=windowcolors:status windowtext/window message windowtext/window OPTIONS=windowcolors:status white/#000000 message white/#000000 menu white/#000000 text white/#000000 # #HACKDIR=c:\games\nethack # # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file. # Setting HACKDIR above will override that. # # LEVELS and SAVE default to HACKDIR # #LEVELS=c:\games\nethack\bones #SAVE=c:\games\nethack\bones nethack-3.6.0/sys/wince/keypad.uu0000664000076400007660000000044512467321052015715 0ustar paxedpaxedbegin 600 keypad.bmp M0DV^`````````#X````H````<`````@````!``$``````(`````````````` M`````````````````/___P#__________________P``[__[____________ M_R0``.?_\_?C]__W__?_]^MU``#CP>/GU?/AX\/OY_O5=0``X>/#Q\'QX\'C MS^?YZR4``/_W_^?5\^?_\^__^]5M``#____WX_?O__OW__?_)```________ *__________\``.?5 ` end nethack-3.6.0/sys/wince/menubar.uu0000664000076400007660000000104212467321052016063 0ustar paxedpaxedbegin 600 menubar.bmp M0DUV`0```````'8````H````(````!`````!``0````````!```````````` M````````````````````@```@````("``(````"``(``@(```,#`P`"`@(`` M``#_``#_````__\`_P```/\`_P#__P``____`'=W=W=W=W=W=W=W=W=W=W=W M=W=W=W=W=W=W=W=W=W=W=$1$1$1$1'=W=W=W=W=W=W1$_T1/]$1W=W=W=W=W M=W=T1/_T__1$=W=W=W=W=W=W=/______]'=W=P<'!P=W=W3_______1W=W#P M\/#P=W=T3__T__]$=W #include "winMS.h" #include "mhaskyn.h" int mswin_yes_no_dialog(const char *question, const char *choices, int def) { return '\032'; } nethack-3.6.0/sys/wince/mhaskyn.h0000664000076400007660000000062712536476415015725 0ustar paxedpaxed/* NetHack 3.6 mhaskyn.h $NHDT-Date: 1432512800 2015/05/25 00:13:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINAskYesNO_h #define MSWINAskYesNO_h #include "winMS.h" int mswin_yes_no_dialog(const char *question, const char *choices, int def); #endif /* MSWINAskYesNO_h */ nethack-3.6.0/sys/wince/mhcmd.c0000664000076400007660000016020412536476415015334 0ustar paxedpaxed/* NetHack 3.6 mhcmd.c $NHDT-Date: 1432512800 2015/05/25 00:13:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "mhcmd.h" #include "mhinput.h" #include "mhcolor.h" static TCHAR szNHCmdWindowClass[] = TEXT("MSNethackCmdWndClass"); #ifndef C #define C(c) (0x1f & (c)) #endif /* cell status 0 */ #define NH_CST_CHECKED 1 /* fonts */ #define NH_CMDPAD_FONT_NORMAL 0 #define NH_CMDPAD_FONT_MAX 0 /* type of the cell */ #define NH_CELL_REG 0 #define NH_CELL_CTRL 1 #define NH_CELL_CAP 2 #define NH_CELL_SHIFT 3 #define NH_CELL_LAYOUT_NEW 4 #define NH_CELL_LAYOUT_MENU 5 #define NH_CMDSET_MAXSIZE 64 /* Keypad cell information NHCmdPadCell.cell_type NHCmdPadCell.data ----------- ---------- NH_CELL_REG (int)>=0 - index in the current keypad layout set (loads a new layout) -1 - restore default (saved) layout NH_CELL_CTRL not used NH_CELL_CAP not used NH_CELL_SHIFT not used NH_CELL_LAYOUT_NEW pointer to the new keypad layout layout (NHCmdLayout*) NH_CELL_LAYOUT_MENU pointer to the layout set (NHCmdSet* - if NULL then nhcmdset_default is used) */ typedef struct t_NHCmdPadCell { UINT cmd_code; /* Windows command code (menu processing - not implemented - set to -1) */ char f_char[16]; /* nethack char */ char text[16]; /* display text */ int image; /* >0 - image ID in IDB_KEYPAD bitmap <=0 - absolute index of the font table */ int type; /* cell type */ int mult; /* cell width multiplier */ void *data; /* internal data for the cell type */ } NHCmdPadCell, *PNHCmdPadCell; /* command layout */ typedef struct t_NHCmdLayout { char name[64]; int rows; int columns; NHCmdPadCell cells[]; } NHCmdLayout, *PNHCmdLayout; /* set of command layouts */ typedef struct t_NHCmdSet { int count; struct t_NHCmdSetElem { PNHCmdLayout layout; BOOL free_on_destroy; } elements[NH_CMDSET_MAXSIZE]; } NHCmdSet, *PNHCmdSet; /* display cell layout */ typedef struct t_NHCmdPadLayoutCell { POINT orig; /* origin of the cell rect */ BYTE type; /* cell type */ int state; /* cell state */ } NHCmdPadLayoutCell, *PNHCmdPadLayoutCell; /* command window data */ typedef struct mswin_nethack_cmd_window { SIZE cell_size; /* cell size */ HFONT font[NH_CMDPAD_FONT_MAX + 1]; /* fonts for cell text */ HBITMAP images; /* key images map */ int active_cell; /* current active cell */ boolean is_caps; /* is CAPS selected */ boolean is_ctrl; /* is CRTL selected */ boolean is_shift; /* is SHIFT selected */ PNHCmdLayout layout_current; /* current layout */ PNHCmdLayout layout_save; /* saved layout */ PNHCmdPadLayoutCell cells; /* display cells */ #if defined(WIN_CE_SMARTPHONE) PNHCmdLayout layout_selected; /* since we use layout command for menu also we need to store the layout that was selected by a user */ #endif } NHCmdWindow, *PNHCmdWindow; LRESULT CALLBACK NHCommandWndProc(HWND, UINT, WPARAM, LPARAM); static void register_command_window_class(); static void LayoutCmdWindow(HWND hWnd); static void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout); static int CellFromPoint(PNHCmdWindow data, POINT pt); static void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE windowSize); static void HighlightCell(HWND hWnd, int cell, BOOL isSelected); static void ActivateCell(HWND hWnd, int cell); static void PushNethackCommand(const char *cmd_char_str, int is_ctrl); /*------------------- keyboard keys layout functions -----------------------*/ PNHCmdLayout nhcmdlayout_create(const char *name, int rows, int columns); void nhcmdlayout_init(PNHCmdLayout p, PNHCmdPadCell cells); #define nhcmdlayout_rows(p) ((p)->rows) #define nhcmdlayout_columns(p) ((p)->columns) #define nhcmdlayout_row(p, x) (&((p)->cells[(p)->columns * (x)])) #define nhcmdlayout_cell(p, x, y) (&((p)->cells[(p)->columns * (x) + (y)])) #define nhcmdlayout_cell_direct(p, i) (&((p)->cells[(i)])) void nhcmdlayout_destroy(PNHCmdLayout p); /*----------------- keyboard keys layout set functions ---------------------*/ PNHCmdSet nhcmdset_create(); int nhcmdset_count(PNHCmdSet p); PNHCmdLayout nhcmdset_get(PNHCmdSet p, int index); const char *nhcmdset_get_name(PNHCmdSet p, int index); void nhcmdset_add(PNHCmdSet p, PNHCmdLayout layout); void nhcmdset_destroy(PNHCmdSet p); /*-------------------- message handlers -----------------------------------*/ static void onPaint(HWND hWnd); // on WM_PAINT static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_CREATE static void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_LBUTTONDOWN static void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_MOUSEMOVE static void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_LBUTTONUP /*----------------------- static data -------------------------------------*/ static PNHCmdSet nhcmdset_current = 0; static PNHCmdSet nhcmdset_default = 0; /*---------------------- Pre-definde keyboard layouts --------------------*/ #ifdef WIN_CE_SMARTPHONE /* dimensions of the command pad */ #define NH_CMDPAD_ROWS 4 #define NH_CMDPAD_COLS 3 #define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS * NH_CMDPAD_ROWS) /* layout indexes */ #define NH_LAYOUT_GENERAL 0 #define NH_LAYOUT_MOVEMENT 1 #define NH_LAYOUT_ATTACK 2 #define NH_LAYOUT_ITEM_HANDLING 3 #define NH_LAYOUT_CONTROLS 4 #define NH_LAYOUT_ADV_MOVEMENT 5 #define NH_LAYOUT_ITEM_LOOKUP 6 #define NH_LAYOUT_WIZARD 7 /* template menu layout */ NHCmdPadCell cells_layout_menu[NH_CMDPAD_CELLNUM] = { { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "<<", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1, NULL }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", ">>", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1, NULL } }; /* movement layout */ NHCmdPadCell cells_layout_movement[NH_CMDPAD_CELLNUM] = { { -1, "7", "7", 1, NH_CELL_REG, 1, (void *) - 1 }, { -1, "8", "8", 2, NH_CELL_REG, 1, (void *) - 1 }, { -1, "9", "9", 3, NH_CELL_REG, 1, (void *) - 1 }, { -1, "4", "4", 4, NH_CELL_REG, 1, (void *) - 1 }, { -1, ".", ".", 5, NH_CELL_REG, 1, (void *) - 1 }, { -1, "6", "6", 6, NH_CELL_REG, 1, (void *) - 1 }, { -1, "1", "1", 7, NH_CELL_REG, 1, (void *) - 1 }, { -1, "2", "2", 8, NH_CELL_REG, 1, (void *) - 1 }, { -1, "3", "3", 9, NH_CELL_REG, 1, (void *) - 1 }, { -1, "<", "<", 10, NH_CELL_REG, 1, (void *) - 1 }, { -1, ">", ">", 12, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* attack layout */ NHCmdPadCell cells_layout_attack[NH_CMDPAD_CELLNUM] = { { -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) NH_LAYOUT_MOVEMENT }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* item handling layout */ NHCmdPadCell cells_layout_item_handling[NH_CMDPAD_CELLNUM] = { { -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "Q", "Q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* General */ NHCmdPadCell cells_layout_general[NH_CMDPAD_CELLNUM] = { { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x01", "^A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* game controls layout */ NHCmdPadCell cells_layout_game[NH_CMDPAD_CELLNUM] = { { -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "&", "&", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x18", "^X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x10", "^P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* advanced movement layout */ NHCmdPadCell cells_layout_adv_movement[NH_CMDPAD_CELLNUM] = { { -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) NH_LAYOUT_MOVEMENT }, { -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) NH_LAYOUT_MOVEMENT }, { -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) NH_LAYOUT_MOVEMENT }, { -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) NH_LAYOUT_MOVEMENT }, { -1, "_", "_", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x14", "^T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "<", "<", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ">", ">", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "^", "^", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* item lookup layout */ NHCmdPadCell cells_layout_lookup[NH_CMDPAD_CELLNUM] = { { -1, ";", ";", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "^", "^", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "]", "]", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ")", ")", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "(", "(", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\"", "\"", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "$", "$", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "+", "+", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* wizard mode layout */ NHCmdPadCell cells_layout_wizard[NH_CMDPAD_CELLNUM] = { { -1, "\x05", "^e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x06", "^f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x07", "^g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x09", "^i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x0f", "^o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x16", "^v", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x17", "^w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x14", "^T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; #else /* !WIN_CE_SMARTPHONE */ /* dimensions of the command pad */ #define NH_CMDPAD_ROWS 4 #define NH_CMDPAD_COLS 14 #define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS * NH_CMDPAD_ROWS) /* lowercase layout */ NHCmdPadCell cells_layout_mod1[NH_CMDPAD_ROWS * NH_CMDPAD_COLS] = { { -1, "7", "7", 1, NH_CELL_REG, 1, (void *) - 1 }, { -1, "8", "8", 2, NH_CELL_REG, 1, (void *) - 1 }, { -1, "9", "9", 3, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for ESC */ { -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "/", "/", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ";", ";", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "-", "-", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "^", "^", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "4", "4", 4, NH_CELL_REG, 1, (void *) - 1 }, { -1, "5", "5", 5, NH_CELL_REG, 1, (void *) - 1 }, { -1, "6", "6", 6, NH_CELL_REG, 1, (void *) - 1 }, { -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for CAPS */ { -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "b", "b", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "1", "1", 7, NH_CELL_REG, 1, (void *) - 1 }, { -1, "2", "2", 8, NH_CELL_REG, 1, (void *) - 1 }, { -1, "3", "3", 9, NH_CELL_REG, 1, (void *) - 1 }, { -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for shift */ { -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "k", "k", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "n", "n", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "<", "<", 10, NH_CELL_REG, 1, (void *) - 1 }, { -1, ".", ".", 11, NH_CELL_REG, 1, (void *) - 1 }, { -1, ">", ">", 12, NH_CELL_REG, 1, (void *) - 1 }, { -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for CTRL */ { -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "u", "u", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "v", "v", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "y", "y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 } }; /* uppercase layout */ NHCmdPadCell cells_layout_mod2[-NH_CMDPAD_ROWS * -NH_CMDPAD_COLS] = { { -1, "7", "7", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "8", "8", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "9", "9", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for ESC */ { -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "(", "(", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ")", ")", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "+", "+", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "\"", "\"", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "$", "$", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "4", "4", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "5", "5", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "6", "6", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for CAPS */ { -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "B", "B", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "H", "H", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "1", "1", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "2", "2", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "3", "3", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for shift */ { -1, "J", "J", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "K", "K", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "L", "L", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "N", "N", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "Q", "Q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "<", "<", 10, NH_CELL_REG, 1, (void *) - 1 }, { -1, "0", "0", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, ">", ">", 12, NH_CELL_REG, 1, (void *) - 1 }, { -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2, NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0, NULL }, /* complement for CTRL */ { -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "U", "U", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "V", "V", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "Y", "Y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 }, { -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void *) - 1 } }; #endif /* !WIN_CE_SMARTPHONE */ /*-------------------------------------------------------------------------*/ HWND mswin_init_command_window() { static int run_once = 0; HWND ret; /* register window class */ if (!run_once) { register_command_window_class(); run_once = 1; } /* create window */ ret = CreateWindow( szNHCmdWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_CLIPSIBLINGS, /* window style */ 0, /* horizontal position of window - set it later */ 0, /* vertical position of window - set it later */ 0, /* window width - set it later */ 0, /* window height - set it later*/ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ if (!ret) { panic("Cannot create command window"); } return ret; } /*-------------------------------------------------------------------------*/ /* calculate mimimum window size */ void mswin_command_window_size(HWND hwnd, LPSIZE sz) { SIZE cell_size; PNHCmdWindow data; data = (PNHCmdWindow) GetWindowLong(hwnd, GWL_USERDATA); if (!data) { sz->cx = sz->cy = 0; } else { CalculateCellSize(hwnd, &cell_size, sz); sz->cx = max(cell_size.cx * nhcmdlayout_columns(data->layout_current) + 2 * GetSystemMetrics(SM_CXBORDER), sz->cx); sz->cy = max(cell_size.cy * nhcmdlayout_rows(data->layout_current) + 2 * GetSystemMetrics(SM_CYBORDER), sz->cy); } } /*-------------------------------------------------------------------------*/ void register_command_window_class() { WNDCLASS wcex; PNHCmdLayout plt; ZeroMemory(&wcex, sizeof(wcex)); /* window class */ wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC) NHCommandWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = mswin_get_brush(NHW_KEYPAD, MSWIN_COLOR_BG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szNHCmdWindowClass; if (!RegisterClass(&wcex)) { panic("cannot register Map window class"); } /* create default command set */ nhcmdset_current = nhcmdset_default = nhcmdset_create(); #ifdef WIN_CE_SMARTPHONE plt = nhcmdlayout_create("General", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_general); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_movement); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Attack", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_attack); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Item Handling", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_item_handling); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Game Controls", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_game); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Advanced Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_adv_movement); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Item Lookup", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_lookup); nhcmdset_add(nhcmdset_current, plt); if (wizard) { plt = nhcmdlayout_create("Wizard Mode", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_wizard); nhcmdset_add(nhcmdset_current, plt); } #else /* ! WIN_CE_SMARTPHONE */ plt = nhcmdlayout_create("lowercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_mod1); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("uppercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_mod2); nhcmdset_add(nhcmdset_current, plt); #endif /* WIN_CE_SMARTPHONE */ } /*-------------------------------------------------------------------------*/ LRESULT CALLBACK NHCommandWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; int i; switch (message) { case WM_CREATE: onCreate(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SIZE: LayoutCmdWindow(hWnd); break; case WM_LBUTTONDOWN: onMouseDown(hWnd, wParam, lParam); return 0; case WM_MOUSEMOVE: /* proceed only if if have mouse focus (set in onMouseDown() - left mouse button is pressed) */ if (GetCapture() == hWnd) { onMouseMove(hWnd, wParam, lParam); return 0; } else { return 1; } break; case WM_LBUTTONUP: /* proceed only if if have mouse focus (set in onMouseDown()) */ if (GetCapture() == hWnd) { onMouseUp(hWnd, wParam, lParam); return 0; } else { return 1; } break; case WM_DESTROY: data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); for (i = 0; i <= NH_CMDPAD_FONT_MAX; i++) if (data->font[i]) DeleteObject(data->font[i]); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return FALSE; } /*-------------------------------------------------------------------------*/ void onPaint(HWND hWnd) { PNHCmdWindow data; PAINTSTRUCT ps; HDC hDC; int x, y; TCHAR wbuf[BUFSZ]; HGDIOBJ saveFont; BITMAP bm; int cell_index; /* get window data */ data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); hDC = BeginPaint(hWnd, &ps); if (!IsRectEmpty(&ps.rcPaint)) { HGDIOBJ oldBr; HBRUSH hbrPattern; COLORREF OldBg, OldFg; HPEN hPen; HGDIOBJ hOldPen; saveFont = SelectObject(hDC, data->font[NH_CMDPAD_FONT_NORMAL]); OldBg = SetBkColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_BG)); OldFg = SetTextColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG)); GetObject(data->images, sizeof(BITMAP), (LPVOID) &bm); hbrPattern = CreatePatternBrush(data->images); hPen = CreatePen(PS_SOLID, 1, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG)); for (x = 0, cell_index = 0; x < nhcmdlayout_rows(data->layout_current); x++) for (y = 0; y < nhcmdlayout_columns(data->layout_current); y++, cell_index++) { RECT cell_rt; POINT pt[5]; PNHCmdPadCell p_cell_data; p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell_index); /* calculate the cell rectangle */ cell_rt.left = data->cells[cell_index].orig.x; cell_rt.top = data->cells[cell_index].orig.y; cell_rt.right = data->cells[cell_index].orig.x + data->cell_size.cx * p_cell_data->mult; cell_rt.bottom = data->cells[cell_index].orig.y + data->cell_size.cy; /* draw border */ hOldPen = SelectObject(hDC, hPen); pt[0].x = cell_rt.left; pt[0].y = cell_rt.top; pt[1].x = cell_rt.right; pt[1].y = cell_rt.top; pt[2].x = cell_rt.right; pt[2].y = cell_rt.bottom; pt[3].x = cell_rt.left; pt[3].y = cell_rt.bottom; pt[4].x = cell_rt.left; pt[4].y = cell_rt.top; Polyline(hDC, pt, 5); SelectObject(hDC, hOldPen); /* calculate clipping rectangle for the text */ cell_rt.left++; cell_rt.top++; cell_rt.right--; cell_rt.bottom--; /* draw the cell text */ if (p_cell_data->image <= 0) { SelectObject(hDC, data->font[-p_cell_data->image]); DrawText(hDC, NH_A2W(p_cell_data->text, wbuf, BUFSZ), strlen(p_cell_data->text), &cell_rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } else { /* draw bitmap */ int bmOffset; RECT bitmap_rt; bmOffset = (p_cell_data->image - 1) * bm.bmHeight; bitmap_rt.left = ((cell_rt.left + cell_rt.right) - min(bm.bmHeight, (cell_rt.right - cell_rt.left))) / 2; bitmap_rt.top = ((cell_rt.bottom + cell_rt.top) - min(bm.bmHeight, (cell_rt.bottom - cell_rt.top))) / 2; bitmap_rt.right = bitmap_rt.left + min(bm.bmHeight, (cell_rt.right - cell_rt.left)); bitmap_rt.bottom = bitmap_rt.top + min(bm.bmHeight, (cell_rt.bottom - cell_rt.top)); SetBrushOrgEx(hDC, bitmap_rt.left - bmOffset, bitmap_rt.top, NULL); oldBr = SelectObject(hDC, hbrPattern); PatBlt(hDC, bitmap_rt.left, bitmap_rt.top, bitmap_rt.right - bitmap_rt.left, bitmap_rt.bottom - bitmap_rt.top, PATCOPY); SelectObject(hDC, oldBr); } /* invert the cell if it is selected */ if (data->cells[cell_index].state == NH_CST_CHECKED) { IntersectRect(&cell_rt, &cell_rt, &ps.rcPaint); PatBlt(hDC, cell_rt.left, cell_rt.top, cell_rt.right - cell_rt.left, cell_rt.bottom - cell_rt.top, DSTINVERT); } } SetTextColor(hDC, OldFg); SetBkColor(hDC, OldBg); SelectObject(hDC, saveFont); DeleteObject(hbrPattern); DeleteObject(hPen); } EndPaint(hWnd, &ps); } /*-------------------------------------------------------------------------*/ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; /* set window data */ data = (PNHCmdWindow) malloc(sizeof(NHCmdWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHCmdWindow)); SetWindowLong(hWnd, GWL_USERDATA, (LONG) data); data->active_cell = -1; /* load images bitmap */ data->images = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_KEYPAD)); if (!data->images) panic("cannot load keypad bitmap"); /* create default layouts */ data->layout_current = 0; data->layout_save = 0; data->cells = 0; #if defined(WIN_CE_SMARTPHONE) data->layout_selected = nhcmdset_get(nhcmdset_current, 0); #endif /* set default layout */ SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, 0)); } /*-------------------------------------------------------------------------*/ void LayoutCmdWindow(HWND hWnd) { RECT clrt; SIZE windowSize; PNHCmdWindow data; int i, j; int x, y; LOGFONT lgfnt; int index; GetClientRect(hWnd, &clrt); if (IsRectEmpty(&clrt)) return; data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); if (!data->layout_current) return; /* calculate cell size */ windowSize.cx = clrt.right - clrt.left; windowSize.cy = clrt.bottom - clrt.top; CalculateCellSize(hWnd, &data->cell_size, &windowSize); /* initialize display cells aray */ x = 0; y = 0; for (i = 0, index = 0; i < nhcmdlayout_rows(data->layout_current); i++) { for (j = 0; j < nhcmdlayout_columns(data->layout_current); j++, index++) { data->cells[index].orig.x = x; data->cells[index].orig.y = y; data->cells[index].type = nhcmdlayout_cell_direct(data->layout_current, index)->type; switch (data->cells[index].type) { case NH_CELL_CTRL: data->cells[index].state = data->is_ctrl ? NH_CST_CHECKED : 0; break; case NH_CELL_CAP: data->cells[index].state = data->is_caps ? NH_CST_CHECKED : 0; break; case NH_CELL_SHIFT: data->cells[index].state = data->is_shift ? NH_CST_CHECKED : 0; break; default: data->cells[index].state = 0; } x += data->cell_size.cx * nhcmdlayout_cell_direct(data->layout_current, index)->mult; } x = 0; y += data->cell_size.cy; } /* create font for display cell text */ for (i = 0; i <= NH_CMDPAD_FONT_MAX; i++) if (data->font[i]) DeleteObject(data->font[i]); ZeroMemory(&lgfnt, sizeof(lgfnt)); lgfnt.lfHeight = data->cell_size.cy; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = ANSI_CHARSET; // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_CHARACTER_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_message && *iflags.wc_font_message) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = VARIABLE_PITCH; // pitch and family } data->font[NH_CMDPAD_FONT_NORMAL] = CreateFontIndirect(&lgfnt); InvalidateRect(hWnd, NULL, TRUE); } /*-------------------------------------------------------------------------*/ void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout) { PNHCmdWindow data; int size; data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data->layout_current == layout) return; data->layout_current = layout; size = sizeof(NHCmdPadLayoutCell) * nhcmdlayout_rows(layout) * nhcmdlayout_columns(layout); data->cells = (PNHCmdPadLayoutCell) realloc(data->cells, size); ZeroMemory(data->cells, size); LayoutCmdWindow(hWnd); } /*-------------------------------------------------------------------------*/ void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; POINT mpt; /* get mouse coordinates */ mpt.x = LOWORD(lParam); mpt.y = HIWORD(lParam); /* map mouse coordinates to the display cell */ data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); data->active_cell = CellFromPoint(data, mpt); if (data->active_cell == -1) return; /* set mouse focus to the current window */ SetCapture(hWnd); /* invert the selection */ HighlightCell(hWnd, data->active_cell, (data->cells[data->active_cell].state != NH_CST_CHECKED)); } /*-------------------------------------------------------------------------*/ void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; POINT mpt; int newActiveCell; /* get mouse coordinates */ mpt.x = LOWORD(lParam); mpt.y = HIWORD(lParam); /* map mouse coordinates to the display cell */ data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); newActiveCell = CellFromPoint(data, mpt); if (data->active_cell == -1) return; /* if mouse is within orginal display cell - select the cell otherwise clear the selection */ switch (nhcmdlayout_cell_direct(data->layout_current, data->active_cell) ->type) { case NH_CELL_REG: HighlightCell(hWnd, data->active_cell, (newActiveCell == data->active_cell)); break; case NH_CELL_CTRL: HighlightCell(hWnd, data->active_cell, ((newActiveCell == data->active_cell) ? !data->is_ctrl : data->is_ctrl)); break; case NH_CELL_CAP: HighlightCell(hWnd, data->active_cell, ((newActiveCell == data->active_cell) ? !data->is_caps : data->is_caps)); break; } } /*-------------------------------------------------------------------------*/ void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; /* release mouse capture */ ReleaseCapture(); /* get active display cell */ data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data->active_cell == -1) return; ActivateCell(hWnd, data->active_cell); data->active_cell = -1; } /*-------------------------------------------------------------------------*/ void ActivateCell(HWND hWnd, int cell) { PNHCmdWindow data; PNHCmdPadCell p_cell_data; int i; data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); if (!data) return; p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell); /* act depending on the cell type: CAPS - change layout CTRL - modify CTRL status REG - place keyboard event on the nethack input queue */ switch (p_cell_data->type) { case NH_CELL_REG: if (data->is_ctrl) { PushNethackCommand(p_cell_data->f_char, 1); data->is_ctrl = 0; for (i = 0; i < nhcmdlayout_rows(data->layout_current) * nhcmdlayout_columns(data->layout_current); i++) { if (nhcmdlayout_cell_direct(data->layout_current, i)->type == NH_CELL_CTRL) { HighlightCell(hWnd, i, data->is_ctrl); } } } else { PushNethackCommand(p_cell_data->f_char, 0); } HighlightCell(hWnd, cell, FALSE); // select a new layout if present i = (int) p_cell_data->data; if (i == -1) { if (data->layout_save) SetCmdWindowLayout(hWnd, data->layout_save); data->layout_save = NULL; } else { if (!data->layout_save) data->layout_save = data->layout_current; SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, i)); } if (!data->is_shift) break; // else fall through and reset the shift case NH_CELL_SHIFT: data->is_shift = !data->is_shift; SetCmdWindowLayout(hWnd, (data->is_shift ^ data->is_caps) ? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0)); data->cells[cell].state = data->is_shift ? NH_CST_CHECKED : 0; InvalidateRect(hWnd, NULL, TRUE); break; case NH_CELL_CTRL: data->is_ctrl = !data->is_ctrl; HighlightCell(hWnd, cell, data->is_ctrl); break; case NH_CELL_CAP: data->is_caps = !data->is_caps; SetCmdWindowLayout(hWnd, (data->is_shift ^ data->is_caps) ? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0)); data->cells[cell].state = data->is_caps ? NH_CST_CHECKED : 0; InvalidateRect(hWnd, NULL, TRUE); break; case NH_CELL_LAYOUT_NEW: { PNHCmdLayout pLayout; HighlightCell(hWnd, cell, FALSE); pLayout = (PNHCmdLayout) p_cell_data->data; if (pLayout) { SetCmdWindowLayout(hWnd, pLayout); } } break; case NH_CELL_LAYOUT_MENU: { winid wid; int i; anything any; menu_item *selected = 0; PNHCmdSet pSet; HighlightCell(hWnd, cell, FALSE); pSet = (PNHCmdSet) p_cell_data->data; if (!pSet) pSet = nhcmdset_default; wid = mswin_create_nhwindow(NHW_MENU); mswin_start_menu(wid); for (i = 0; i < nhcmdset_count(pSet); i++) { any.a_void = nhcmdset_get(pSet, i); mswin_add_menu(wid, NO_GLYPH, &any, 'a' + i, 0, ATR_NONE, nhcmdset_get_name(pSet, i), FALSE); } mswin_end_menu(wid, "Select keypad layout"); i = select_menu(wid, PICK_ONE, &selected); mswin_destroy_nhwindow(wid); if (i == 1) { #if defined(WIN_CE_SMARTPHONE) data->layout_selected = (PNHCmdLayout) selected[0].item.a_void; #endif SetCmdWindowLayout(hWnd, (PNHCmdLayout) selected[0].item.a_void); } } break; } } /*-------------------------------------------------------------------------*/ int CellFromPoint(PNHCmdWindow data, POINT pt) { int i; for (i = 0; i < nhcmdlayout_rows(data->layout_current) * nhcmdlayout_columns(data->layout_current); i++) { RECT cell_rt; cell_rt.left = data->cells[i].orig.x; cell_rt.top = data->cells[i].orig.y; cell_rt.right = data->cells[i].orig.x + data->cell_size.cx * nhcmdlayout_cell_direct(data->layout_current, i)->mult; cell_rt.bottom = data->cells[i].orig.y + data->cell_size.cy; if (PtInRect(&cell_rt, pt)) return i; } return -1; } /*-------------------------------------------------------------------------*/ void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE pWindowSize) { HDC hdc; PNHCmdWindow data; data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); if (!data) return; hdc = GetDC(hWnd); /* if windows size is specified - attempt ro stretch cells across the the window size. If not - make default cell size based on 10 points font. Make sure that cell cesize does not exceeds 20 points */ if (pWindowSize->cx > 0) pSize->cx = pWindowSize->cx / nhcmdlayout_columns(data->layout_current); else pSize->cx = 10 * GetDeviceCaps(hdc, LOGPIXELSX) / 72; pSize->cx = min(pSize->cx, 20 * GetDeviceCaps(hdc, LOGPIXELSX) / 72); if (pWindowSize->cy > 0) pSize->cy = pWindowSize->cy / nhcmdlayout_rows(data->layout_current); else pSize->cy = 10 * GetDeviceCaps(hdc, LOGPIXELSY) / 72; pSize->cy = min(pSize->cy, 20 * GetDeviceCaps(hdc, LOGPIXELSY) / 72); ReleaseDC(hWnd, hdc); } /*-------------------------------------------------------------------------*/ void HighlightCell(HWND hWnd, int cell, BOOL isSelected) { HDC hDC; PNHCmdWindow data; int prevState; data = (PNHCmdWindow) GetWindowLong(hWnd, GWL_USERDATA); prevState = data->cells[cell].state; data->cells[cell].state = (isSelected) ? NH_CST_CHECKED : 0; if (prevState != data->cells[cell].state) { hDC = GetDC(hWnd); PatBlt(hDC, data->cells[cell].orig.x + 1, data->cells[cell].orig.y + 1, data->cell_size.cx * nhcmdlayout_cell_direct(data->layout_current, cell) ->mult - 2, data->cell_size.cy - 2, DSTINVERT); ReleaseDC(hWnd, hDC); } } /*-------------------------------------------------------------------------*/ void PushNethackCommand(const char *cmd_char_str, int is_ctrl) { while (*cmd_char_str) { if (is_ctrl) { NHEVENT_KBD(C(*cmd_char_str)); } else { NHEVENT_KBD(*cmd_char_str); } cmd_char_str++; } } /*-------------------------------------------------------------------------*/ /*------------------- keyboard keys layout functions ----------------------*/ /*-------------------------------------------------------------------------*/ PNHCmdLayout nhcmdlayout_create(const char *name, int rows, int columns) { PNHCmdLayout p; int i; i = sizeof(NHCmdLayout) + rows * columns * sizeof(NHCmdPadCell); p = (PNHCmdLayout) malloc(i); ZeroMemory(p, i); p->rows = rows; p->columns = columns; strncpy(p->name, name, sizeof(p->name) - 1); for (i = 0; i < rows * columns; i++) { p->cells[i].cmd_code = -1; p->cells[i].image = -NH_CMDPAD_FONT_NORMAL; p->cells[i].type = 1; p->cells[i].mult = 1; } return p; } /*-------------------------------------------------------------------------*/ void nhcmdlayout_init(PNHCmdLayout p, PNHCmdPadCell cells) { memcpy(p->cells, cells, p->rows * p->columns * sizeof(NHCmdPadCell)); } void nhcmdlayout_destroy(PNHCmdLayout p) { free(p); } /*-------------------------------------------------------------------------*/ /*----------------- keyboard keys layout set functions --------------------*/ /*-------------------------------------------------------------------------*/ PNHCmdSet nhcmdset_create() { PNHCmdSet p; p = (PNHCmdSet) malloc(sizeof(NHCmdSet)); ZeroMemory(p, sizeof(NHCmdSet)); return p; } /*-------------------------------------------------------------------------*/ int nhcmdset_count(PNHCmdSet p) { assert(p); return p->count; } /*-------------------------------------------------------------------------*/ PNHCmdLayout nhcmdset_get(PNHCmdSet p, int index) { assert(p); assert(index >= 0 && index < p->count); return p->elements[index].layout; } /*-------------------------------------------------------------------------*/ const char * nhcmdset_get_name(PNHCmdSet p, int index) { assert(p); assert(index >= 0 && index < p->count); return p->elements[index].layout->name; } /*-------------------------------------------------------------------------*/ void nhcmdset_add(PNHCmdSet p, PNHCmdLayout layout) { assert(p); assert(p->count < NH_CMDSET_MAXSIZE); p->elements[p->count].layout = layout; p->elements[p->count].free_on_destroy = 0; p->count++; } /*-------------------------------------------------------------------------*/ void nhcmdset_destroy(PNHCmdSet p) { int i = 0; assert(p); for (i = 0; i < p->count; i++) { if (p->elements[i].free_on_destroy) { nhcmdlayout_destroy(p->elements[i].layout); } } free(p); } /*-------------------------------------------------------------------------*/ #if defined(WIN_CE_SMARTPHONE) /* special keypad input handling for SmartPhone the phone keypad maps to VK_* as shown below. some keys might not be present, e.g. VK_TFLIP sofkey1 softkey2 VK_TSOFT1, VK_TSOFT2 ^ VK_TUP < + > VK_TLEFT, VK_TACTION, VK_TRIGHT v VK_TDOWN home back VK_THOME, VK_TBACK talk end VK_TTALK, VK_TEND 1 2 3 VK_T0..VK_T9 4 5 6 ... 7 8 9 ... * 0 # VK_TSTAR, VK_TPOUND other buttons include VK_TRECORD VK_TPOWER, VK_TVOLUMEUP, VK_TVOLUMEDOWN VK_TFLIP */ BOOL NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown) { PNHCmdWindow data; int index = -1; /* get window data */ data = (PNHCmdWindow) GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if (!data) return FALSE; switch (wParam) { case VK_T0: index = 10; break; case VK_T1: index = 0; break; case VK_T2: index = 1; break; case VK_T3: index = 2; break; case VK_T4: index = 3; break; case VK_T5: index = 4; break; case VK_T6: index = 5; break; case VK_T7: index = 6; break; case VK_T8: index = 7; break; case VK_T9: index = 8; break; case VK_TSTAR: index = 9; break; case VK_TPOUND: index = 11; break; } if (index >= 0) { HighlightCell(GetNHApp()->hCmdWnd, index, keyDown); if (keyDown) ActivateCell(GetNHApp()->hCmdWnd, index); return TRUE; } else { return FALSE; } } /*-------------------------------------------------------------------------*/ void NHSPhoneSetKeypadFromString(const char *str) { PNHCmdWindow data; PNHCmdSet p = 0; PNHCmdLayout layout_prev = 0; PNHCmdLayout layout_cur = 0; char buf[2][BUFSZ]; int i, lcount; char *s; assert(NH_CMDPAD_ROWS == 4); data = (PNHCmdWindow) GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if (!data) return; p = nhcmdset_create(); ZeroMemory(buf, sizeof(buf)); if (sscanf(str, "%s or %s", buf[1], buf[0]) != 2) { ZeroMemory(buf, sizeof(buf)); strncpy(buf[0], str, sizeof(buf[0]) - 1); } lcount = 10; /* create new layout on the first iteration */ for (i = 0; i < 2; i++) { s = buf[i]; while (*s) { char c_start, c_end, c_char; /* parse character ranges */ if (isalnum((c_start = s[0])) && s[1] == '-' && isalnum((c_end = s[2]))) { s += 2; } else { c_start = c_end = *s; } for (c_char = c_start; c_char <= c_end; c_char++) { if (lcount >= 10) { /* create layout */ lcount = 0; layout_prev = layout_cur; layout_cur = nhcmdlayout_create("noname", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(layout_cur, cells_layout_menu); nhcmdlayout_cell(layout_cur, 3, 0)->data = layout_prev; nhcmdlayout_cell(layout_cur, 3, 2)->data = 0; nhcmdset_add(p, layout_cur); p->elements[p->count - 1].free_on_destroy = 1; if (layout_prev) { nhcmdlayout_cell(layout_prev, 3, 2)->data = layout_cur; } } if (lcount == 9) lcount = 10; // skip '#' nhcmdlayout_cell_direct(layout_cur, lcount)->f_char[0] = c_char; if (c_char == '\033') { strcpy(nhcmdlayout_cell_direct(layout_cur, lcount)->text, "esc"); nhcmdlayout_cell_direct(layout_cur, lcount)->image = 14; /* 14 is a ESC symbol in IDB_KEYPAD */ } else { nhcmdlayout_cell_direct(layout_cur, lcount)->text[0] = c_char; nhcmdlayout_cell_direct(layout_cur, lcount)->text[1] = '\x0'; } /* increment character count in the current layout */ lcount++; } /* prepareg next charcter from the source string */ s++; } } /* install the new set */ if (nhcmdset_current != nhcmdset_default) nhcmdset_destroy(nhcmdset_current); nhcmdset_current = p; SetCmdWindowLayout(GetNHApp()->hCmdWnd, nhcmdset_get(nhcmdset_current, 0)); } /*-------------------------------------------------------------------------*/ void NHSPhoneSetKeypadDirection() { PNHCmdWindow data; data = (PNHCmdWindow) GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if (!data) return; if (nhcmdset_current != nhcmdset_default) nhcmdset_destroy(nhcmdset_current); nhcmdset_current = nhcmdset_default; SetCmdWindowLayout(GetNHApp()->hCmdWnd, nhcmdset_get(nhcmdset_current, NH_LAYOUT_MOVEMENT)); } /*-------------------------------------------------------------------------*/ void NHSPhoneSetKeypadDefault() { PNHCmdWindow data; data = (PNHCmdWindow) GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if (!data) return; if (nhcmdset_current != nhcmdset_default) nhcmdset_destroy(nhcmdset_current); nhcmdset_current = nhcmdset_default; SetCmdWindowLayout(GetNHApp()->hCmdWnd, data->layout_selected ? data->layout_selected : nhcmdset_get(nhcmdset_current, 0)); } #endif /* defined (WIN_CE_SMARTHPONE) */ nethack-3.6.0/sys/wince/mhcmd.h0000664000076400007660000000135312536476415015340 0ustar paxedpaxed/* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINCMDWindow_h #define MSWINCMDWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_command_window(); /* if either sz->cx or sz->cy are already set this function will no modify it. It will adjust them to the minimum size required by the command window */ void mswin_command_window_size(HWND hwnd, LPSIZE sz); #if defined(WIN_CE_SMARTPHONE) /* special keypad input handling for SmartPhone */ BOOL NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown); void NHSPhoneSetKeypadFromString(const char *str); void NHSPhoneSetKeypadDirection(); void NHSPhoneSetKeypadDefault(); #endif #endif /* MSWINCMDWindow_h */ nethack-3.6.0/sys/wince/mhcolor.c0000664000076400007660000002014512536476415015706 0ustar paxedpaxed/* NetHack 3.6 mhcolor.c $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* color management and such */ #include "winMS.h" #include "mhcolor.h" #define TOTAL_BRUSHES 10 #define NHBRUSH_CODE(win, type) ((((win) &0xFF) << 8) | ((type) &0xFF)) struct t_brush_table { int code; HBRUSH brush; COLORREF color; }; static struct t_brush_table brush_table[TOTAL_BRUSHES]; static int max_brush = 0; static struct t_brush_table default_brush_table[] = { { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_MESSAGE, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_TEXT, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_KEYPAD, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_MAP, MSWIN_COLOR_FG), NULL, RGB(96, 96, 96) }, { NHBRUSH_CODE(NHW_MENU, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) }, { NHBRUSH_CODE(NHW_MESSAGE, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) }, { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) }, { NHBRUSH_CODE(NHW_TEXT, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) }, { NHBRUSH_CODE(NHW_KEYPAD, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) }, { NHBRUSH_CODE(NHW_MAP, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) }, { -1, NULL, RGB(0, 0, 0) } }; static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr, COLORREF *colorptr); typedef struct ctv { const char *colorstring; COLORREF colorvalue; } color_table_value; /* * The color list here is a combination of: * NetHack colors. (See mhmap.c) * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 ) */ static color_table_value color_table[] = { /* NetHack colors */ { "black", RGB(0x55, 0x55, 0x55) }, { "red", RGB(0xFF, 0x00, 0x00) }, { "green", RGB(0x00, 0x80, 0x00) }, { "brown", RGB(0xA5, 0x2A, 0x2A) }, { "blue", RGB(0x00, 0x00, 0xFF) }, { "magenta", RGB(0xFF, 0x00, 0xFF) }, { "cyan", RGB(0x00, 0xFF, 0xFF) }, { "orange", RGB(0xFF, 0xA5, 0x00) }, { "brightgreen", RGB(0x00, 0xFF, 0x00) }, { "yellow", RGB(0xFF, 0xFF, 0x00) }, { "brightblue", RGB(0x00, 0xC0, 0xFF) }, { "brightmagenta", RGB(0xFF, 0x80, 0xFF) }, { "brightcyan", RGB(0x80, 0xFF, 0xFF) }, { "white", RGB(0xFF, 0xFF, 0xFF) }, /* Remaining HTML colors */ { "trueblack", RGB(0x00, 0x00, 0x00) }, { "gray", RGB(0x80, 0x80, 0x80) }, { "grey", RGB(0x80, 0x80, 0x80) }, { "purple", RGB(0x80, 0x00, 0x80) }, { "silver", RGB(0xC0, 0xC0, 0xC0) }, { "maroon", RGB(0x80, 0x00, 0x00) }, { "fuchsia", RGB(0xFF, 0x00, 0xFF) }, /* = NetHack magenta */ { "lime", RGB(0x00, 0xFF, 0x00) }, /* = NetHack bright green */ { "olive", RGB(0x80, 0x80, 0x00) }, { "navy", RGB(0x00, 0x00, 0x80) }, { "teal", RGB(0x00, 0x80, 0x80) }, { "aqua", RGB(0x00, 0xFF, 0xFF) }, /* = NetHack cyan */ { "", RGB(0x00, 0x00, 0x00) }, }; typedef struct ctbv { char *colorstring; int syscolorvalue; } color_table_brush_value; static color_table_brush_value color_table_brush[] = { { "activeborder", COLOR_ACTIVEBORDER }, { "activecaption", COLOR_ACTIVECAPTION }, { "appworkspace", COLOR_APPWORKSPACE }, { "background", COLOR_BACKGROUND }, { "btnface", COLOR_BTNFACE }, { "btnshadow", COLOR_BTNSHADOW }, { "btntext", COLOR_BTNTEXT }, { "captiontext", COLOR_CAPTIONTEXT }, { "graytext", COLOR_GRAYTEXT }, { "greytext", COLOR_GRAYTEXT }, { "highlight", COLOR_HIGHLIGHT }, { "highlighttext", COLOR_HIGHLIGHTTEXT }, { "inactiveborder", COLOR_INACTIVEBORDER }, { "inactivecaption", COLOR_INACTIVECAPTION }, { "menu", COLOR_MENU }, { "menutext", COLOR_MENUTEXT }, { "scrollbar", COLOR_SCROLLBAR }, { "window", COLOR_WINDOW }, { "windowframe", COLOR_WINDOWFRAME }, { "windowtext", COLOR_WINDOWTEXT }, { "", -1 }, }; void mswin_init_color_table() { int i; struct t_brush_table *p; /* cleanup */ for (i = 0; i < max_brush; i++) DeleteObject(brush_table[i].brush); max_brush = 0; /* initialize brush table */ #define BRUSHTABLE_ENTRY(opt, win, type) \ brush_table[max_brush].code = NHBRUSH_CODE((win), (type)); \ mswin_color_from_string((opt), &brush_table[max_brush].brush, \ &brush_table[max_brush].color); \ max_brush++; BRUSHTABLE_ENTRY(iflags.wc_foregrnd_menu, NHW_MENU, MSWIN_COLOR_FG); BRUSHTABLE_ENTRY(iflags.wc_foregrnd_message, NHW_MESSAGE, MSWIN_COLOR_FG); BRUSHTABLE_ENTRY(iflags.wc_foregrnd_status, NHW_STATUS, MSWIN_COLOR_FG); BRUSHTABLE_ENTRY(iflags.wc_foregrnd_text, NHW_TEXT, MSWIN_COLOR_FG); BRUSHTABLE_ENTRY(iflags.wc_foregrnd_message, NHW_KEYPAD, MSWIN_COLOR_FG); BRUSHTABLE_ENTRY(iflags.wc_backgrnd_menu, NHW_MENU, MSWIN_COLOR_BG); BRUSHTABLE_ENTRY(iflags.wc_backgrnd_message, NHW_MESSAGE, MSWIN_COLOR_BG); BRUSHTABLE_ENTRY(iflags.wc_backgrnd_status, NHW_STATUS, MSWIN_COLOR_BG); BRUSHTABLE_ENTRY(iflags.wc_backgrnd_text, NHW_TEXT, MSWIN_COLOR_BG); BRUSHTABLE_ENTRY(iflags.wc_backgrnd_message, NHW_KEYPAD, MSWIN_COLOR_BG); #undef BRUSHTABLE_ENTRY /* go through the values and fill in "blanks" (use default values) */ for (i = 0; i < max_brush; i++) { if (!brush_table[i].brush) { for (p = default_brush_table; p->code != -1; p++) { if (p->code == brush_table[i].code) { brush_table[i].brush = CreateSolidBrush(p->color); brush_table[i].color = p->color; } } } } } HBRUSH mswin_get_brush(int win_type, int color_index) { int i; for (i = 0; i < max_brush; i++) if (brush_table[i].code == NHBRUSH_CODE(win_type, color_index)) return brush_table[i].brush; return NULL; } COLORREF mswin_get_color(int win_type, int color_index) { int i; for (i = 0; i < max_brush; i++) if (brush_table[i].code == NHBRUSH_CODE(win_type, color_index)) return brush_table[i].color; return RGB(0, 0, 0); } static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr, COLORREF *colorptr) { color_table_value *ctv_ptr = color_table; color_table_brush_value *ctbv_ptr = color_table_brush; int red_value, blue_value, green_value; static char *hexadecimals = "0123456789abcdef"; *brushptr = NULL; *colorptr = RGB(0, 0, 0); if (colorstring == NULL) return; if (*colorstring == '#') { if (strlen(++colorstring) != 6) return; red_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals; red_value *= 16; red_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals; green_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals; green_value *= 16; green_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals; blue_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals; blue_value *= 16; blue_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals; *colorptr = RGB(red_value, blue_value, green_value); } else { while (*ctv_ptr->colorstring && _stricmp(ctv_ptr->colorstring, colorstring)) ++ctv_ptr; if (*ctv_ptr->colorstring) { *colorptr = ctv_ptr->colorvalue; } else { while (*ctbv_ptr->colorstring && _stricmp(ctbv_ptr->colorstring, colorstring)) ++ctbv_ptr; if (*ctbv_ptr->colorstring) { *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue); *colorptr = GetSysColor(ctbv_ptr->syscolorvalue); } } } if (max_brush > TOTAL_BRUSHES) panic("Too many colors!"); *brushptr = CreateSolidBrush(*colorptr); } nethack-3.6.0/sys/wince/mhcolor.h0000664000076400007660000000112512536476415015710 0ustar paxedpaxed/* NetHack 3.6 mhcolor.h $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* color management functions */ #ifndef MSWINColor_h #define MSWINColor_h #define MSWIN_COLOR_BG 0 #define MSWIN_COLOR_FG 1 #define SYSCLR_TO_BRUSH(x) ((HBRUSH)((x) + 1)) extern void mswin_init_color_table(); extern HBRUSH mswin_get_brush(int win_type, int color_index); extern COLORREF mswin_get_color(int win_type, int color_index); #endif /* MSWINColor_h */ nethack-3.6.0/sys/wince/mhdlg.c0000664000076400007660000006770712610522241015333 0ustar paxedpaxed/* NetHack 3.6 mhdlg.c $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* various dialog boxes are defined here */ #include "winMS.h" #include "hack.h" #include "func_tab.h" #include "mhdlg.h" #include "mhmain.h" #define CheckDlgButton(dlg, btn_id, st) \ SendDlgItemMessage((dlg), (btn_id), BM_SETCHECK, (WPARAM)(st), 0) /*---------------------------------------------------------------*/ /* data for getlin dialog */ struct getlin_data { const char *question; char *result; size_t result_size; }; LRESULT CALLBACK GetlinDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_getlin_window(const char *question, char *result, size_t result_size) { int ret; struct getlin_data data; /* initilize dialog data */ ZeroMemory(&data, sizeof(data)); data.question = question; data.result = result; data.result_size = result_size; /* create modal dialog window */ ret = DialogBoxParam(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_GETLIN), GetNHApp()->hMainWnd, GetlinDlgProc, (LPARAM) &data); if (ret == -1) panic("Cannot create getlin window"); return ret; } LRESULT CALLBACK GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct getlin_data *data; RECT main_rt, text_rt, dlg_rt, edit_rt; SIZE dlg_sz; TCHAR wbuf[BUFSZ]; HDC hdc; HWND control; HWND hwndMap; #if defined(WIN_CE_POCKETPC) SHInputDialog(hWnd, message, wParam); #endif switch (message) { case WM_INITDIALOG: data = (struct getlin_data *) lParam; SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf))); SetWindowLong(hWnd, GWL_USERDATA, lParam); /* get title text width */ SetRect(&text_rt, 0, 0, 100, 50); hdc = GetWindowDC(hWnd); DrawText(hdc, wbuf, _tcslen(wbuf), &text_rt, DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_VCENTER); ReleaseDC(hWnd, hdc); /* center dialog in the main window */ GetWindowRect(hWnd, &dlg_rt); hwndMap = mswin_hwnd_from_winid(WIN_MAP); GetWindowRect(IsWindow(hwndMap) ? hwndMap : GetNHApp()->hMainWnd, &main_rt); dlg_sz.cx = max( dlg_rt.right - dlg_rt.left, min(text_rt.right - text_rt.left + GetSystemMetrics(SM_CXICON), main_rt.right - main_rt.left)); dlg_sz.cy = min(dlg_rt.bottom - dlg_rt.top, main_rt.bottom - main_rt.top); dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); /* change layout of controls */ GetClientRect(hWnd, &dlg_rt); control = GetDlgItem(hWnd, IDC_GETLIN_EDIT); GetWindowRect(control, &edit_rt); MoveWindow(control, 0, 0, dlg_rt.right - dlg_rt.left, edit_rt.bottom - edit_rt.top, TRUE); control = GetDlgItem(hWnd, IDOK); GetWindowRect(control, &text_rt); MoveWindow(control, 0, edit_rt.bottom - edit_rt.top, (dlg_rt.right - dlg_rt.left) / 2, text_rt.bottom - text_rt.top, TRUE); control = GetDlgItem(hWnd, IDCANCEL); GetWindowRect(control, &text_rt); MoveWindow(control, (dlg_rt.right - dlg_rt.left) / 2, edit_rt.bottom - edit_rt.top, (dlg_rt.right - dlg_rt.left) / 2, text_rt.bottom - text_rt.top, TRUE); #if defined(WIN_CE_SMARTPHONE) NHSPhoneDialogSetup(hWnd, IDC_SPHONE_DIALOGBAR, TRUE, FALSE); #endif /* set focus to the edit control */ SetFocus(GetDlgItem(hWnd, IDC_GETLIN_EDIT)); /* tell windows that we've set the focus */ return FALSE; break; case WM_COMMAND: { TCHAR wbuf[BUFSZ]; switch (LOWORD(wParam)) { /* OK button was pressed */ case IDOK: data = (struct getlin_data *) GetWindowLong(hWnd, GWL_USERDATA); SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, (WPARAM) sizeof(wbuf), (LPARAM) wbuf); NH_W2A(wbuf, data->result, data->result_size); /* Fall through. */ /* cancel button was pressed */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; } } break; #if defined(WIN_CE_SMARTPHONE) case WM_HOTKEY: if (VK_TBACK == HIWORD(lParam)) { SHSendBackToFocusWindow(message, wParam, lParam); } break; #endif } /* end switch (message) */ return FALSE; } /*---------------------------------------------------------------*/ /* dialog data for the list of extended commands */ struct extcmd_data { int *selection; }; LRESULT CALLBACK ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_ext_cmd_window(int *selection) { int ret; struct extcmd_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); *selection = -1; data.selection = selection; /* create modal dialog window */ ret = DialogBoxParam(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_EXTCMD), GetNHApp()->hMainWnd, ExtCmdDlgProc, (LPARAM) &data); if (ret == -1) panic("Cannot create extcmd window"); return ret; } LRESULT CALLBACK ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct extcmd_data *data; RECT main_rt, dlg_rt; SIZE dlg_sz; int i; const char *ptr; TCHAR wbuf[255]; switch (message) { case WM_INITDIALOG: data = (struct extcmd_data *) lParam; SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); /* fill combobox with extended commands */ for (i = 0; (ptr = extcmdlist[i].ef_txt); i++) { SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(ptr, wbuf, sizeof(wbuf))); } #if defined(WIN_CE_SMARTPHONE) NHSPhoneDialogSetup(hWnd, IDC_SPHONE_DIALOGBAR, FALSE, FALSE); GetClientRect(hWnd, &dlg_rt); MoveWindow(GetDlgItem(hWnd, IDC_EXTCMD_LIST), dlg_rt.left, dlg_rt.top, dlg_rt.right - dlg_rt.left, dlg_rt.bottom - dlg_rt.top, TRUE); #endif /* set focus to the list control */ SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct extcmd_data *) GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* OK button ws clicked */ case IDOK: *data->selection = SendDlgItemMessage( hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); if (*data->selection == LB_ERR) *data->selection = -1; /* Fall through. */ /* CANCEL button ws clicked */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; /* list control events */ case IDC_EXTCMD_LIST: switch (HIWORD(wParam)) { case LBN_DBLCLK: /* double click within the list wParam The low-order word is the list box identifier. The high-order word is the notification message. lParam Handle to the list box */ *data->selection = SendMessage((HWND) lParam, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); if (*data->selection == LB_ERR) *data->selection = -1; EndDialog(hWnd, IDOK); return TRUE; } break; } } return FALSE; } /*---------------------------------------------------------------*/ /* player selector dialog data */ struct plsel_data { int *selection; }; BOOL CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); static void plselInitDialog(HWND hWnd); static void plselAdjustLists(HWND hWnd, int changed_opt); static int plselFinalSelection(HWND hWnd, int *selection); int mswin_player_selection_window(int *selection) { int ret; struct plsel_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); data.selection = selection; /* create modal dialog */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR), GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM) &data); if (ret == -1) panic("Cannot create getlin window"); return ret; } BOOL CALLBACK PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct plsel_data *data; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: data = (struct plsel_data *) lParam; SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); /* init dialog */ plselInitDialog(hWnd); #if defined(WIN_CE_SMARTPHONE) NHSPhoneDialogSetup(hWnd, IDC_SPHONE_DIALOGBAR, FALSE, FALSE); #endif /* set focus on the role checkbox (random) field */ SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct plsel_data *) GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* OK button was clicked */ case IDOK: if (plselFinalSelection(hWnd, data->selection)) { EndDialog(hWnd, wParam); } else { MessageBox( hWnd, TEXT("Cannot match this role. Try something else."), TEXT("STOP"), MB_OK); } return TRUE; /* CANCEL button was clicked */ case IDCANCEL: *data->selection = -1; EndDialog(hWnd, wParam); return TRUE; /* following are events from dialog controls: "random" checkboxes send BN_CLICKED messages; role/race/... combo-boxes send CBN_SELENDOK if something was selected; */ case IDC_PLSEL_ROLE_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { /* enable corresponding list window if "random" checkbox was "unchecked" */ EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_RACE_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_GENDER_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_ALIGN_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_ROLE_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { /* filter out invalid options if the selection was made */ plselAdjustLists(hWnd, LOWORD(wParam)); } break; case IDC_PLSEL_RACE_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { plselAdjustLists(hWnd, LOWORD(wParam)); } break; case IDC_PLSEL_GENDER_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { plselAdjustLists(hWnd, LOWORD(wParam)); } break; case IDC_PLSEL_ALIGN_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { plselAdjustLists(hWnd, LOWORD(wParam)); } break; } break; } return FALSE; } void setComboBoxValue(HWND hWnd, int combo_box, int value) { int index_max = SendDlgItemMessage(hWnd, combo_box, CB_GETCOUNT, 0, 0); int index; int value_to_set = LB_ERR; for (index = 0; index < index_max; index++) { if (SendDlgItemMessage(hWnd, combo_box, CB_GETITEMDATA, (WPARAM) index, 0) == value) { value_to_set = index; break; } } SendDlgItemMessage(hWnd, combo_box, CB_SETCURSEL, (WPARAM) value_to_set, 0); } /* initialize player selector dialog */ void plselInitDialog(HWND hWnd) { TCHAR wbuf[BUFSZ]; /* set player name */ SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf))); /* check flags for consistency */ if (flags.initrole >= 0) { if (flags.initrace >= 0 && !validrace(flags.initrole, flags.initrace)) { flags.initrace = ROLE_NONE; } if (flags.initgend >= 0 && !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = ROLE_NONE; } if (flags.initalign >= 0 && !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = ROLE_NONE; } } /* populate select boxes */ plselAdjustLists(hWnd, -1); /* intialize roles list */ if (flags.initrole < 0 || !ok_role(flags.initrole, ROLE_NONE, ROLE_NONE, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ROLE_LIST, flags.initrole); } /* intialize races list */ if (flags.initrace < 0 || !ok_race(flags.initrole, flags.initrace, ROLE_NONE, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_RACE_LIST, flags.initrace); } /* intialize genders list */ if (flags.initgend < 0 || !ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_GENDER_LIST, flags.initgend); } /* intialize alignments list */ if (flags.initalign < 0 || !ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign)) { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ALIGN_LIST, flags.initalign); } } /* adjust role/race/alignment/gender list - filter out invalid combinations changed_sel points to the list where selection occurred (-1 if unknown) */ void plselAdjustLists(HWND hWnd, int changed_sel) { HWND control_role, control_race, control_gender, control_align; int initrole, initrace, initgend, initalign; int i; int ind; int valid_opt; TCHAR wbuf[255]; /* get control handles */ control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST); control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST); control_gender = GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST); control_align = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST); /* get current selections */ ind = SendMessage(control_role, CB_GETCURSEL, 0, 0); initrole = (ind == LB_ERR) ? flags.initrole : SendMessage(control_role, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_race, CB_GETCURSEL, 0, 0); initrace = (ind == LB_ERR) ? flags.initrace : SendMessage(control_race, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0); initgend = (ind == LB_ERR) ? flags.initgend : SendMessage(control_gender, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_align, CB_GETCURSEL, 0, 0); initalign = (ind == LB_ERR) ? flags.initalign : SendMessage(control_align, CB_GETITEMDATA, ind, 0); /* intialize roles list */ if (changed_sel == -1) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_role, CB_RESETCONTENT, 0, 0); for (i = 0; roles[i].name.m; i++) { if (ok_role(i, initrace, initgend, initalign)) { if (initgend >= 0 && flags.female && roles[i].name.f) ind = SendMessage( control_role, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(roles[i].name.f, wbuf, sizeof(wbuf))); else ind = SendMessage( control_role, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(roles[i].name.m, wbuf, sizeof(wbuf))); SendMessage(control_role, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initrole) { SendMessage(control_role, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } } /* set selection to the previously selected role if it is still valid */ if (!valid_opt) { initrole = ROLE_NONE; initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_role, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } /* trigger change of the races list */ changed_sel = IDC_PLSEL_ROLE_LIST; } /* intialize races list */ if (changed_sel == IDC_PLSEL_ROLE_LIST) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_race, CB_RESETCONTENT, 0, 0); for (i = 0; races[i].noun; i++) if (ok_race(initrole, i, ROLE_NONE, ROLE_NONE)) { ind = SendMessage( control_race, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(races[i].noun, wbuf, sizeof(wbuf))); SendMessage(control_race, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initrace) { SendMessage(control_race, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected race if it is still valid */ if (!valid_opt) { initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_race, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } /* trigger change of the genders list */ changed_sel = IDC_PLSEL_RACE_LIST; } /* intialize genders list */ if (changed_sel == IDC_PLSEL_RACE_LIST) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_gender, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(initrole, initrace, i, ROLE_NONE)) { ind = SendMessage( control_gender, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(genders[i].adj, wbuf, sizeof(wbuf))); SendMessage(control_gender, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initgend) { SendMessage(control_gender, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected gender if it is still valid */ if (!valid_opt) { initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_gender, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } /* trigger change of the alignments list */ changed_sel = IDC_PLSEL_GENDER_LIST; } /* intialize alignments list */ if (changed_sel == IDC_PLSEL_GENDER_LIST) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_align, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(initrole, initrace, initgend, i)) { ind = SendMessage( control_align, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(aligns[i].adj, wbuf, sizeof(wbuf))); SendMessage(control_align, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initalign) { SendMessage(control_align, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected alignment if it is still valid */ if (!valid_opt) { initalign = ROLE_NONE; SendMessage(control_align, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } } } /* player made up his mind - get final selection here */ int plselFinalSelection(HWND hWnd, int *selection) { int ind; /* get current selections */ if (SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initrole = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETCURSEL, 0, 0); flags.initrole = (ind == LB_ERR) ? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETITEMDATA, ind, 0); } if (SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initrace = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETCURSEL, 0, 0); flags.initrace = (ind == LB_ERR) ? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETITEMDATA, ind, 0); } if (SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initgend = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETCURSEL, 0, 0); flags.initgend = (ind == LB_ERR) ? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETITEMDATA, ind, 0); } if (SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initalign = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETCURSEL, 0, 0); flags.initalign = (ind == LB_ERR) ? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETITEMDATA, ind, 0); } /* check the role */ if (flags.initrole == ROLE_RANDOM) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { MessageBox(hWnd, TEXT("Incompatible role!"), TEXT("STOP"), MB_OK); return FALSE; } } /* Select a race, if necessary */ /* force compatibility with role */ if (flags.initrace == ROLE_RANDOM || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (flags.initrace == ROLE_RANDOM) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); } if (flags.initrace < 0) { MessageBox(hWnd, TEXT("Incompatible race!"), TEXT("STOP"), MB_OK); return FALSE; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (flags.initgend == ROLE_RANDOM) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); } if (flags.initgend < 0) { MessageBox(hWnd, TEXT("Incompatible gender!"), TEXT("STOP"), MB_OK); return FALSE; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (flags.initalign == ROLE_RANDOM) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); } else { MessageBox(hWnd, TEXT("Incompatible alignment!"), TEXT("STOP"), MB_OK); return FALSE; } } return TRUE; } nethack-3.6.0/sys/wince/mhdlg.h0000664000076400007660000000107112536476415015340 0ustar paxedpaxed/* NetHack 3.6 mhdlg.h $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINDlgWindow_h #define MSWINDlgWindow_h #include "winMS.h" #include "config.h" #include "global.h" int mswin_getlin_window(const char *question, char *result, size_t result_size); int mswin_ext_cmd_window(int *selection); int mswin_player_selection_window(int *selection); #endif /* MSWINDlgWindow_h */ nethack-3.6.0/sys/wince/mhfont.c0000664000076400007660000001746512536476415015551 0ustar paxedpaxed/* NetHack 3.6 mhfont.c $NHDT-Date: 1432512800 2015/05/25 00:13:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management and such */ #include "mhfont.h" #define MAXFONTS 64 /* font table - 64 fonts ought to be enough */ static struct font_table_entry { int code; HFONT hFont; } font_table[MAXFONTS]; static int font_table_size = 0; HFONT version_splash_font; HFONT extrainfo_splash_font; #define NHFONT_CODE(win, attr) (((attr & 0xFF) << 8) | (win_type & 0xFF)) static void __cdecl font_table_cleanup(void); /* create font based on window type, charater attributes and window device context */ HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) { HFONT fnt = NULL; LOGFONT lgfnt; int font_size; int font_index; static BOOL once = FALSE; if (!once) { once = TRUE; atexit(font_table_cleanup); } ZeroMemory(&lgfnt, sizeof(lgfnt)); /* try find font in the table */ for (font_index = 0; font_index < font_table_size; font_index++) if (NHFONT_CODE(win_type, attr) == font_table[font_index].code) break; if (!replace && font_index < font_table_size) return font_table[font_index].hFont; switch (win_type) { case NHW_STATUS: lgfnt.lfHeight = -iflags.wc_fontsiz_status * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_status && *iflags.wc_font_status) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_status, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family } break; case NHW_MENU: lgfnt.lfHeight = -iflags.wc_fontsiz_menu * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option lgfnt.lfUnderline = (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_menu && *iflags.wc_font_menu) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_menu, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family } break; case NHW_MESSAGE: font_size = (attr == ATR_INVERSE) ? iflags.wc_fontsiz_message + 1 : iflags.wc_fontsiz_message; lgfnt.lfHeight = -font_size * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option lgfnt.lfUnderline = (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_message && *iflags.wc_font_message) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = VARIABLE_PITCH; // pitch and family } break; case NHW_TEXT: lgfnt.lfHeight = -iflags.wc_fontsiz_text * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option lgfnt.lfUnderline = (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_text && *iflags.wc_font_text) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_text, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family } break; } fnt = CreateFontIndirect(&lgfnt); /* add font to the table */ if (font_index == font_table_size) { if (font_table_size >= MAXFONTS) panic("font table overflow!"); font_table_size++; } else { DeleteObject(font_table[font_index].hFont); } font_table[font_index].code = NHFONT_CODE(win_type, attr); font_table[font_index].hFont = fnt; return fnt; } UINT mswin_charset() { CHARSETINFO cis; if (SYMHANDLING(H_IBM)) if (TranslateCharsetInfo((DWORD *) GetOEMCP(), &cis, TCI_SRCCODEPAGE)) return cis.ciCharset; else return OEM_CHARSET; else if (TranslateCharsetInfo((DWORD *) GetACP(), &cis, TCI_SRCCODEPAGE)) return cis.ciCharset; else return ANSI_CHARSET; } void __cdecl font_table_cleanup(void) { int i; for (i = 0; i < font_table_size; i++) { DeleteObject(font_table[i].hFont); } font_table_size = 0; } nethack-3.6.0/sys/wince/mhfont.h0000664000076400007660000000067412536476415015550 0ustar paxedpaxed/* NetHack 3.6 mhfont.h $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management functions */ #ifndef MSWINFont_h #define MSWINFont_h #include "winMS.h" HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); UINT mswin_charset(); #endif /* MSWINFont_h */ nethack-3.6.0/sys/wince/mhinput.c0000664000076400007660000000527012536476415015731 0ustar paxedpaxed/* NetHack 3.6 mhinput.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhinput.h" /* nethack input queue functions */ #define NH_INPUT_BUFFER_SIZE 64 /* as it stands right now we need only one slot since events are processed almost the same time as they occur but I like large round numbers */ static MSNHEvent nhi_input_buffer[NH_INPUT_BUFFER_SIZE]; static int nhi_init_input = 0; static int nhi_read_pos = 0; static int nhi_write_pos = 0; /* initialize input queue */ void mswin_nh_input_init() { if (!nhi_init_input) { nhi_init_input = 1; ZeroMemory(nhi_input_buffer, sizeof(nhi_input_buffer)); nhi_read_pos = 0; nhi_write_pos = 0; } } /* check for input */ int mswin_have_input() { return #ifdef SAFERHANGUP /* we always have input (ESC) if hangup was requested */ program_state.done_hup || #endif (nhi_read_pos != nhi_write_pos); } /* add event to the queue */ void mswin_input_push(PMSNHEvent event) { int new_write_pos; if (!nhi_init_input) mswin_nh_input_init(); new_write_pos = (nhi_write_pos + 1) % NH_INPUT_BUFFER_SIZE; if (new_write_pos != nhi_read_pos) { memcpy(nhi_input_buffer + nhi_write_pos, event, sizeof(*event)); nhi_write_pos = new_write_pos; } } /* get event from the queue and delete it */ PMSNHEvent mswin_input_pop() { PMSNHEvent retval; #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.kbd.ch = '\033'; return &hangup_event; } #endif if (!nhi_init_input) mswin_nh_input_init(); if (nhi_read_pos != nhi_write_pos) { retval = &nhi_input_buffer[nhi_read_pos]; nhi_read_pos = (nhi_read_pos + 1) % NH_INPUT_BUFFER_SIZE; } else { retval = NULL; } return retval; } /* get event from the queue but leave it there */ PMSNHEvent mswin_input_peek() { PMSNHEvent retval; #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.kbd.ch = '\033'; return &hangup_event; } #endif if (!nhi_init_input) mswin_nh_input_init(); if (nhi_read_pos != nhi_write_pos) { retval = &nhi_input_buffer[nhi_read_pos]; } else { retval = NULL; } return retval; } nethack-3.6.0/sys/wince/mhinput.h0000664000076400007660000000240512536476415015733 0ustar paxedpaxed/* NetHack 3.6 mhinput.h $NHDT-Date: 1432512801 2015/05/25 00:13:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINInput_h #define MSWINInput_h /* nethack input queue - store/extract input events */ #include "winMS.h" #define NHEVENT_CHAR 1 #define NHEVENT_MOUSE 2 typedef struct mswin_event { int type; union { struct { int ch; } kbd; struct { int mod; int x, y; } ms; }; } MSNHEvent, *PMSNHEvent; #define NHEVENT_KBD(c) \ { \ MSNHEvent e; \ e.type = NHEVENT_CHAR; \ e.kbd.ch = (c); \ mswin_input_push(&e); \ } #define NHEVENT_MS(_mod, _x, _y) \ { \ MSNHEvent e; \ e.type = NHEVENT_MOUSE; \ e.ms.mod = (_mod); \ e.ms.x = (_x); \ e.ms.y = (_y); \ mswin_input_push(&e); \ } void mswin_nh_input_init(); int mswin_have_input(); void mswin_input_push(PMSNHEvent event); PMSNHEvent mswin_input_pop(); PMSNHEvent mswin_input_peek(); #endif /* MSWINInput_h */ nethack-3.6.0/sys/wince/mhmain.c0000664000076400007660000011015012536476415015510 0ustar paxedpaxed/* NetHack 3.6 mhmain.c $NHDT-Date: 1432512800 2015/05/25 00:13:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.46 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmsg.h" #include "mhinput.h" #include "mhmain.h" #include "mhmenu.h" #include "mhstatus.h" #include "mhmsgwnd.h" #include "mhcmd.h" #include "mhmap.h" #include "date.h" #include "patchlevel.h" #define MAX_LOADSTRING 100 typedef struct mswin_nethack_main_window { int mapAcsiiModeSave; } NHMainWindow, *PNHMainWindow; TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void register_main_window_class(); static void select_map_mode(int map_mode); static int menuid2mapmode(int menuid); static int mapmode2menuid(int map_mode); static HMENU _get_main_menu(UINT menu_id); static void mswin_direct_command(); HWND mswin_init_main_window() { static int run_once = 0; HWND ret; RECT rc; /* register window class */ if (!run_once) { LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); register_main_window_class(); run_once = 1; } /* create the main window */ SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); ret = CreateWindow(szMainWindowClass, /* registered class name */ szTitle, /* window name */ WS_CLIPCHILDREN, /* window style */ rc.left, /* horizontal position of window */ rc.top, /* vertical position of window */ rc.right - rc.left, /* window width */ rc.bottom - rc.top, /* window height */ NULL, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL /* window-creation data */ ); if (!ret) panic("Cannot create main window"); return ret; } void register_main_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC) MainWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR) IDI_WINHACK); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szMainWindowClass; RegisterClass(&wcex); } /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ enum KEY_INDEXES { KEY_NW, KEY_N, KEY_NE, KEY_MINUS, KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS, KEY_SW, KEY_S, KEY_SE, KEY_INV, KEY_WAITLOOK, KEY_LAST }; static const unsigned char /* normal, shift, control */ keypad[KEY_LAST][3] = { { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { '+', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[KEY_LAST][3] = { { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '+', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }; #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0) #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0]) #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1]) #define KEYTABLE(x) \ (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x)) /* map mode macros */ #define IS_MAP_FIT_TO_SCREEN(mode) \ ((mode) == MAP_MODE_ASCII_FIT_TO_SCREEN \ || (mode) == MAP_MODE_TILES_FIT_TO_SCREEN) #define IS_MAP_ASCII(mode) \ ((mode) != MAP_MODE_TILES && (mode) != MAP_MODE_TILES_FIT_TO_SCREEN) /* // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. */ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMainWindow data; switch (message) { /*-----------------------------------------------------------------------*/ case WM_CREATE: { #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) SHMENUBARINFO menubar; #endif /* set window data */ data = (PNHMainWindow) malloc(sizeof(NHMainWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHMainWindow)); data->mapAcsiiModeSave = MAP_MODE_ASCII12x16; SetWindowLong(hWnd, GWL_USERDATA, (LONG) data); GetNHApp()->hMainWnd = hWnd; /* create menu bar */ #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) ZeroMemory(&menubar, sizeof(menubar)); menubar.cbSize = sizeof(menubar); menubar.hwndParent = hWnd; menubar.dwFlags = 0; menubar.nToolBarId = IDC_WINHACK; menubar.hInstRes = GetNHApp()->hApp; #if defined(WIN_CE_POCKETPC) menubar.nBmpId = IDB_MENUBAR; menubar.cBmpImages = 2; #else menubar.nBmpId = 0; menubar.cBmpImages = 0; #endif if (!SHCreateMenuBar(&menubar)) panic("cannot create menu"); GetNHApp()->hMenuBar = menubar.hwndMB; #else GetNHApp()->hMenuBar = CommandBar_Create(GetNHApp()->hApp, hWnd, 1); if (!GetNHApp()->hMenuBar) panic("cannot create menu"); CommandBar_InsertMenubar(GetNHApp()->hMenuBar, GetNHApp()->hApp, IDC_WINHACK, 0); #endif CheckMenuItem( _get_main_menu(ID_VIEW), IDM_VIEW_KEYPAD, MF_BYCOMMAND | (GetNHApp()->bCmdPad ? MF_CHECKED : MF_UNCHECKED)); } break; /*-----------------------------------------------------------------------*/ case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; /*-----------------------------------------------------------------------*/ case WM_KEYDOWN: data = (PNHMainWindow) GetWindowLong(hWnd, GWL_USERDATA); /* translate arrow keys into nethack commands */ switch (wParam) { case VK_LEFT: if (STATEON(VK_CONTROL)) { /* scroll map window one line left */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_W)); } return 0; case VK_RIGHT: if (STATEON(VK_CONTROL)) { /* scroll map window one line right */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_E)); } return 0; case VK_UP: if (STATEON(VK_CONTROL)) { /* scroll map window one line up */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_N)); } return 0; case VK_DOWN: if (STATEON(VK_CONTROL)) { /* scroll map window one line down */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_S)); } return 0; case VK_HOME: if (STATEON(VK_CONTROL)) { /* scroll map window to upper left corner */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL); SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_NW)); } return 0; case VK_END: if (STATEON(VK_CONTROL)) { /* scroll map window to lower right corner */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM) NULL); SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_SW)); } return 0; case VK_PRIOR: if (STATEON(VK_CONTROL)) { /* scroll map window one page up */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_NE)); } return 0; case VK_NEXT: if (STATEON(VK_CONTROL)) { /* scroll map window one page down */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_SE)); } return 0; case VK_DECIMAL: case VK_DELETE: NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK)); return 0; case VK_INSERT: NHEVENT_KBD(KEYTABLE(KEY_INV)); return 0; case VK_SUBTRACT: NHEVENT_KBD(KEYTABLE(KEY_MINUS)); return 0; case VK_ADD: NHEVENT_KBD(KEYTABLE(KEY_PLUS)); return 0; case VK_CLEAR: /* This is the '5' key */ NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING)); return 0; case VK_F4: if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? data->mapAcsiiModeSave : MAP_MODE_TILES); } else { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN); } return 0; case VK_F5: if (IS_MAP_ASCII(iflags.wc_map_mode)) { if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN); } else { mswin_select_map_mode(MAP_MODE_TILES); } } else { if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN); } else { mswin_select_map_mode(data->mapAcsiiModeSave); } } return 0; case VK_RETURN: { int x, y; if (WIN_MAP != WIN_ERR) { mswin_map_get_cursor(mswin_hwnd_from_winid(WIN_MAP), &x, &y); } else { x = u.ux; y = u.uy; } NHEVENT_MS(CLICK_1, x, y); } return 0; } #if defined(WIN_CE_SMARTPHONE) if (GetNHApp()->bCmdPad && NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE)) return 0; #endif return 1; /* end of WM_KEYDOWN */ /*-----------------------------------------------------------------------*/ #if defined(WIN_CE_SMARTPHONE) case WM_KEYUP: if (GetNHApp()->bCmdPad && NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE)) return 0; return 1; /* end of WM_KEYUP */ #endif /*-----------------------------------------------------------------------*/ case WM_CHAR: #if defined(WIN_CE_SMARTPHONE) /* if smartphone cmdpad is up then translation happens - disable WM_CHAR processing to avoid double input */ if (GetNHApp()->bCmdPad) { return 1; } #endif if (wParam == '\n' || wParam == '\r' || wParam == C('M')) return 0; /* we already processed VK_RETURN */ /* all characters go to nethack except Ctrl-P that scrolls message * window up */ if (wParam == C('P') || wParam == C('p')) { SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD((lParam & 1 << 29) ? M(tolower(wParam)) : wParam); } return 0; /*-----------------------------------------------------------------------*/ case WM_COMMAND: /* process commands - menu commands mostly */ if (IsWindow(GetNHApp()->hPopupWnd)) { return SendMessage(GetNHApp()->hPopupWnd, message, wParam, lParam); } else if (onWMCommand(hWnd, wParam, lParam)) return DefWindowProc(hWnd, message, wParam, lParam); else return 0; /*-----------------------------------------------------------------------*/ case WM_ACTIVATE: if (LOWORD(wParam) != WA_INACTIVE) { #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) if (GetNHApp()->bFullScreen) SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON); else SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON); #endif mswin_layout_main_window(NULL); } break; case WM_SETTINGCHANGE: #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) if (GetNHApp()->bFullScreen) SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON); else SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON); #endif mswin_layout_main_window(NULL); break; case WM_SIZE: mswin_layout_main_window(NULL); break; /*-----------------------------------------------------------------------*/ case WM_SETFOCUS: /* if there is a menu window out there - transfer input focus to it */ if (IsWindow(GetNHApp()->hPopupWnd)) { SetFocus(GetNHApp()->hPopupWnd); } break; /*-----------------------------------------------------------------------*/ case WM_CLOSE: { /* exit gracefully */ #ifdef SAFERHANGUP /* destroy popup window - it has its own loop and we need to return control to NetHack core at this point */ if (IsWindow(GetNHApp()->hPopupWnd)) SendMessage(GetNHApp()->hPopupWnd, WM_COMMAND, IDCANCEL, 0); /* tell NetHack core that "hangup" is requested */ hangup(1); #else dosave0(); terminate(EXIT_SUCCESS); #endif } return 0; /*-----------------------------------------------------------------------*/ case WM_DESTROY: { /* apparently we never get here TODO: work on exit routines - need to send WM_QUIT somehow */ /* clean up */ free((PNHMainWindow) GetWindowLong(hWnd, GWL_USERDATA)); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); terminate(EXIT_SUCCESS); } break; /*-----------------------------------------------------------------------*/ default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { switch (wParam) { /* new window was just added */ case MSNH_MSG_ADDWND: { PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd) lParam; HWND child = GetNHApp()->windowlist[msg_param->wid].win; if (GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP) mswin_select_map_mode(iflags.wc_map_mode); if (child) mswin_layout_main_window(child); } break; } } /* adjust windows to fit main window layout --------------------------- | Status | +-------------------------+ | | | | | MAP | | | | | +-------------------------+ | Command pad | +-------------------------+ | Messages | --------------------------- */ void mswin_layout_main_window(HWND changed_child) { winid i; RECT client_rt, wnd_rect; POINT status_org; SIZE status_size; POINT msg_org; SIZE msg_size; POINT map_org; SIZE map_size; POINT cmd_org; SIZE cmd_size; HWND wnd_status, wnd_msg; PNHMainWindow data; #if defined(WIN_CE_POCKETPC) SIPINFO sip; RECT menu_bar; RECT visible_rt; POINT pt; #endif GetClientRect(GetNHApp()->hMainWnd, &client_rt); #if defined(WIN_CE_POCKETPC) ZeroMemory(&sip, sizeof(sip)); sip.cbSize = sizeof(sip); SHSipInfo(SPI_GETSIPINFO, 0, &sip, 0); if (GetNHApp()->bFullScreen) sip.rcVisibleDesktop.top = 0; /* adjust client rectangle size */ GetWindowRect(GetNHApp()->hMenuBar, &menu_bar); client_rt.bottom -= menu_bar.bottom - menu_bar.top; /* calcuate visible rect in client coordinates */ pt.x = sip.rcVisibleDesktop.left; pt.y = sip.rcVisibleDesktop.top; ScreenToClient(GetNHApp()->hMainWnd, &pt); SetRect(&wnd_rect, pt.x, pt.y, pt.x + sip.rcVisibleDesktop.right - sip.rcVisibleDesktop.left, pt.y + sip.rcVisibleDesktop.bottom - sip.rcVisibleDesktop.top); IntersectRect(&visible_rt, &client_rt, &wnd_rect); #else #if !defined(WIN_CE_SMARTPHONE) client_rt.top += CommandBar_Height(GetNHApp()->hMenuBar); #else /* Smartphone only */ if (GetNHApp()->bFullScreen) { RECT menu_bar; GetWindowRect(GetNHApp()->hMenuBar, &menu_bar); client_rt.bottom -= menu_bar.bottom - menu_bar.top; } #endif #endif /* get window data */ data = (PNHMainWindow) GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA); /* get sizes of child windows */ wnd_status = mswin_hwnd_from_winid(WIN_STATUS); if (IsWindow(wnd_status)) { mswin_status_window_size(wnd_status, &status_size); } else { status_size.cx = status_size.cy = 0; } wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE); if (IsWindow(wnd_msg)) { mswin_message_window_size(wnd_msg, &msg_size); } else { msg_size.cx = msg_size.cy = 0; } cmd_size.cx = cmd_size.cy = 0; if (GetNHApp()->bCmdPad && IsWindow(GetNHApp()->hCmdWnd)) { mswin_command_window_size(GetNHApp()->hCmdWnd, &cmd_size); } /* set window positions */ /* calculate the application windows size */ #if defined(WIN_CE_POCKETPC) SetRect(&wnd_rect, visible_rt.left, visible_rt.top, visible_rt.right, visible_rt.bottom); if (sip.fdwFlags & SIPF_ON) cmd_size.cx = cmd_size.cy = 0; /* hide keypad window */ #else SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom); #endif #if !defined(WIN_CE_SMARTPHONE) /* other ports have it at the bottom of the screen */ cmd_size.cx = (wnd_rect.right - wnd_rect.left); cmd_org.x = wnd_rect.left; cmd_org.y = wnd_rect.bottom - cmd_size.cy; wnd_rect.bottom -= cmd_size.cy; #endif /* status window */ switch (iflags.wc_align_status) { case ALIGN_LEFT: status_size.cx = (wnd_rect.right - wnd_rect.left) / 4; status_size.cy = (wnd_rect.bottom - wnd_rect.top); // that won't look good status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.left += status_size.cx; break; case ALIGN_RIGHT: status_size.cx = (wnd_rect.right - wnd_rect.left) / 4; status_size.cy = (wnd_rect.bottom - wnd_rect.top); // that won't look good status_org.x = wnd_rect.right - status_size.cx; status_org.y = wnd_rect.top; wnd_rect.right -= status_size.cx; break; case ALIGN_TOP: status_size.cx = (wnd_rect.right - wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.top += status_size.cy; break; case ALIGN_BOTTOM: default: status_size.cx = (wnd_rect.right - wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.bottom - status_size.cy; wnd_rect.bottom -= status_size.cy; break; } /* message window */ switch (iflags.wc_align_message) { case ALIGN_LEFT: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right (bottom) side of the * message window */ msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx); msg_size.cy = (wnd_rect.bottom - wnd_rect.top) - cmd_size.cy; msg_org.x = cmd_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; cmd_org.y = msg_org.y + msg_size.cy; #else msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4; msg_size.cy = (wnd_rect.bottom - wnd_rect.top); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; #endif wnd_rect.left += msg_size.cx; break; case ALIGN_RIGHT: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right (bottom) side of the * message window */ msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx); msg_size.cy = (wnd_rect.bottom - wnd_rect.top) - cmd_size.cy; msg_org.x = cmd_org.x = wnd_rect.right - msg_size.cx; msg_org.y = wnd_rect.top; cmd_org.y = msg_org.y + msg_size.cy; #else msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4; msg_size.cy = (wnd_rect.bottom - wnd_rect.top); msg_org.x = wnd_rect.right - msg_size.cx; msg_org.y = wnd_rect.top; #endif wnd_rect.right -= msg_size.cx; break; case ALIGN_TOP: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right side of the message * window */ msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy); msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx; msg_org.x = wnd_rect.left; cmd_org.x = msg_org.x + msg_size.cx; msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy; #else msg_size.cx = (wnd_rect.right - wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; #endif wnd_rect.top += msg_size.cy; break; case ALIGN_BOTTOM: default: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right side of the message * window */ msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy); msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx; msg_org.x = wnd_rect.left; cmd_org.x = msg_org.x + msg_size.cx; msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy; #else msg_size.cx = (wnd_rect.right - wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.bottom - msg_size.cy; #endif wnd_rect.bottom -= msg_size.cy; break; } map_org.x = wnd_rect.left; map_org.y = wnd_rect.top; map_size.cx = wnd_rect.right - wnd_rect.left; map_size.cy = wnd_rect.bottom - wnd_rect.top; /* go through the windows list and adjust sizes */ for (i = 0; i < MAXWINDOWS; i++) { if (GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead) { switch (GetNHApp()->windowlist[i].type) { case NHW_MESSAGE: MoveWindow(GetNHApp()->windowlist[i].win, msg_org.x, msg_org.y, msg_size.cx, msg_size.cy, TRUE); break; case NHW_MAP: MoveWindow(GetNHApp()->windowlist[i].win, map_org.x, map_org.y, map_size.cx, map_size.cy, TRUE); break; case NHW_STATUS: MoveWindow(GetNHApp()->windowlist[i].win, status_org.x, status_org.y, status_size.cx, status_size.cy, TRUE); break; case NHW_TEXT: case NHW_MENU: case NHW_RIP: { POINT menu_org; SIZE menu_size; menu_org.x = client_rt.left; menu_org.y = client_rt.top; #if defined(WIN_CE_POCKETPC) menu_size.cx = min(sip.rcVisibleDesktop.right - sip.rcVisibleDesktop.left, client_rt.right - client_rt.left); menu_size.cy = min(sip.rcVisibleDesktop.bottom - sip.rcVisibleDesktop.top, client_rt.bottom - client_rt.top); #else menu_size.cx = client_rt.right - client_rt.left; menu_size.cy = client_rt.bottom - client_rt.top; #endif #if defined(WIN_CE_SMARTPHONE) /* leave room for the command window */ if (GetNHApp()->windowlist[i].type == NHW_MENU) { menu_size.cy -= cmd_size.cy; } /* dialogs are popup windows unde SmartPhone so we need to convert to screen coordinates */ ClientToScreen(GetNHApp()->hMainWnd, &menu_org); #endif MoveWindow(GetNHApp()->windowlist[i].win, menu_org.x, menu_org.y, menu_size.cx, menu_size.cy, TRUE); } break; } ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW); InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE); } } if (IsWindow(GetNHApp()->hCmdWnd)) { /* show command window only if it exists and the game is ready (plname is set) */ if (GetNHApp()->bCmdPad && cmd_size.cx > 0 && cmd_size.cy > 0 && *plname) { MoveWindow(GetNHApp()->hCmdWnd, cmd_org.x, cmd_org.y, cmd_size.cx, cmd_size.cy, TRUE); ShowWindow(GetNHApp()->hCmdWnd, SW_SHOW); } else { ShowWindow(GetNHApp()->hCmdWnd, SW_HIDE); } } } LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PNHMainWindow data; data = (PNHMainWindow) GetWindowLong(hWnd, GWL_USERDATA); wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // process the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(GetNHApp()->hApp, (LPCTSTR) IDD_ABOUTBOX, hWnd, (DLGPROC) About); break; case IDM_EXIT: done2(); break; case IDM_SAVE: dosave(); break; case IDM_MAP_TILES: case IDM_MAP_ASCII4X6: case IDM_MAP_ASCII6X8: case IDM_MAP_ASCII8X8: case IDM_MAP_ASCII16X8: case IDM_MAP_ASCII7X12: case IDM_MAP_ASCII8X12: case IDM_MAP_ASCII12X16: case IDM_MAP_ASCII16X12: case IDM_MAP_ASCII10X18: mswin_select_map_mode(menuid2mapmode(wmId)); break; case IDM_MAP_FIT_TO_SCREEN: if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? data->mapAcsiiModeSave : MAP_MODE_TILES); } else { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN); } break; case IDM_VIEW_KEYPAD: GetNHApp()->bCmdPad = !GetNHApp()->bCmdPad; CheckMenuItem( _get_main_menu(ID_VIEW), IDM_VIEW_KEYPAD, MF_BYCOMMAND | (GetNHApp()->bCmdPad ? MF_CHECKED : MF_UNCHECKED)); mswin_layout_main_window(GetNHApp()->hCmdWnd); break; case IDM_VIEW_OPTIONS: doset(); break; case IDM_DIRECT_COMMAND: /* SmartPhone: display dialog to type in arbitary command text */ mswin_direct_command(); break; case IDM_HELP_LONG: display_file(HELP, TRUE); break; case IDM_HELP_COMMANDS: display_file(SHELP, TRUE); break; case IDM_HELP_HISTORY: (void) dohistory(); break; case IDM_HELP_INFO_CHAR: (void) dowhatis(); break; case IDM_HELP_INFO_KEY: (void) dowhatdoes(); break; case IDM_HELP_OPTIONS: option_help(); break; case IDM_HELP_OPTIONS_LONG: display_file(OPTIONFILE, TRUE); break; case IDM_HELP_EXTCMD: (void) doextlist(); break; case IDM_HELP_LICENSE: display_file(LICENSE, TRUE); break; case IDM_HELP_MENU: dohelp(); break; default: return 1; } return 0; } // Mesage handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { char buf[BUFSZ]; TCHAR wbuf[NHSTR_BUFSIZE]; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: getversionstring(buf); SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, NHSTR_BUFSIZE)); SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT, NH_A2W(COPYRIGHT_BANNER_A "\n" COPYRIGHT_BANNER_B "\n" COPYRIGHT_BANNER_C "\n" COPYRIGHT_BANNER_D, wbuf, NHSTR_BUFSIZE)); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hDlg, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hDlg, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } /* Set map display mode */ void mswin_select_map_mode(int mode) { HMENU hmenuMap; PNHMainWindow data; winid map_id; map_id = WIN_MAP; data = (PNHMainWindow) GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA); #if defined(WIN_CE_SMARTPHONE) /* Smartphone manu has only 2 items */ hmenuMap = _get_main_menu(ID_VIEW); #else hmenuMap = _get_main_menu(ID_MAP); #endif /* override for Rogue level */ if (Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode)) return; /* set map mode menu mark */ if (IS_MAP_ASCII(mode)) { CheckMenuRadioItem(hmenuMap, IDM_MAP_TILES, IDM_MAP_FIT_TO_SCREEN, mapmode2menuid(IS_MAP_FIT_TO_SCREEN(mode) ? data->mapAcsiiModeSave : mode), MF_BYCOMMAND); } else { CheckMenuRadioItem(hmenuMap, IDM_MAP_TILES, IDM_MAP_FIT_TO_SCREEN, mapmode2menuid(MAP_MODE_TILES), MF_BYCOMMAND); } #if defined(WIN_CE_SMARTPHONE) /* update "Fit To Screen" item text */ { TCHAR wbuf[BUFSZ]; TBBUTTONINFO tbbi; ZeroMemory(wbuf, sizeof(wbuf)); if (!LoadString(GetNHApp()->hApp, (IS_MAP_FIT_TO_SCREEN(mode) ? IDS_CAP_NORMALMAP : IDS_CAP_ENTIREMAP), wbuf, BUFSZ)) { panic("cannot load main menu strings"); } ZeroMemory(&tbbi, sizeof(tbbi)); tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_TEXT; tbbi.pszText = wbuf; if (!SendMessage(GetNHApp()->hMenuBar, TB_SETBUTTONINFO, IDM_MAP_FIT_TO_SCREEN, (LPARAM) &tbbi)) { error("Cannot update IDM_MAP_FIT_TO_SCREEN menu item."); } } #else /* set fit-to-screen mode mark */ CheckMenuItem(hmenuMap, IDM_MAP_FIT_TO_SCREEN, MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode) ? MF_CHECKED : MF_UNCHECKED)); #endif if (IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { data->mapAcsiiModeSave = iflags.wc_map_mode; } iflags.wc_map_mode = mode; /* ** first, check if WIN_MAP has been inialized. ** If not - attempt to retrieve it by type, then check it again */ if (WIN_MAP != WIN_ERR) mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), mode); } static struct t_menu2mapmode { int menuID; int mapMode; } _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES }, { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 }, { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 }, { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 }, { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 }, { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 }, { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 }, { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 }, { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 }, { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 }, { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN }, { -1, -1 } }; int menuid2mapmode(int menuid) { struct t_menu2mapmode *p; for (p = _menu2mapmode; p->mapMode != -1; p++) if (p->menuID == menuid) return p->mapMode; return -1; } int mapmode2menuid(int map_mode) { struct t_menu2mapmode *p; for (p = _menu2mapmode; p->mapMode != -1; p++) if (p->mapMode == map_mode) return p->menuID; return -1; } HMENU _get_main_menu(UINT menu_id) { HMENU hmenuMap; #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) TBBUTTONINFO tbbi; #endif #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; SendMessage(GetNHApp()->hMenuBar, TB_GETBUTTONINFO, menu_id, (LPARAM) &tbbi); hmenuMap = (HMENU) tbbi.lParam; #else hmenuMap = CommandBar_GetMenu(GetNHApp()->hMenuBar, 0); #endif return hmenuMap; } /* SmartPhone: display dialog to type arbitrary command text */ void mswin_direct_command() { char cmd[BUFSZ]; ZeroMemory(cmd, sizeof(cmd)); mswin_getlin("Type cmd text", cmd); if (cmd[0]) { /* feed command to nethack */ char *p = cmd; cmd[32] = '\x0'; /* truncate at 32 chars */ while (*p) { NHEVENT_KBD(*p); p++; } if (cmd[0] != '\033') mswin_putstr(WIN_MESSAGE, ATR_NONE, cmd); } } nethack-3.6.0/sys/wince/mhmain.h0000664000076400007660000000102612536476415015516 0ustar paxedpaxed/* NetHack 3.6 mhmain.h $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMainWindow_h #define MSWINMainWindow_h /* this is a main appliation window */ #include "winMS.h" extern TCHAR szMainWindowClass[]; HWND mswin_init_main_window(); void mswin_layout_main_window(HWND changed_child); void mswin_select_map_mode(int map_mode); #endif /* MSWINMainWindow_h */ nethack-3.6.0/sys/wince/mhmap.c0000664000076400007660000007433412536476415015356 0ustar paxedpaxed/* NetHack 3.6 mhmap.c $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmap.h" #include "mhmsg.h" #include "mhinput.h" #include "mhfont.h" #include "patchlevel.h" #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 extern short glyph2tile[]; /* map window data */ typedef struct mswin_nethack_map_window { int map[COLNO][ROWNO]; /* glyph map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */ int xPos, yPos; /* scroll position */ int xPageSize, yPageSize; /* scroll page size */ int xCur, yCur; /* position of the cursor */ int xScrTile, yScrTile; /* size of display tile */ POINT map_orig; /* map origin point */ HFONT hMapFont; /* font for ASCII mode */ int xLastMouseClick, yLastMouseClick; /* last mouse click */ } NHMapWindow, *PNHMapWindow; static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass"); LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM); static void register_map_window_class(void); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif static COLORREF nhcolor_to_RGB(int c); HWND mswin_init_map_window() { static int run_once = 0; HWND ret; DWORD styles; if (!run_once) { register_map_window_class(); run_once = 1; } styles = WS_CHILD | WS_CLIPSIBLINGS; if (!GetNHApp()->bHideScrollBars) styles |= WS_HSCROLL | WS_VSCROLL; ret = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ styles, /* window style */ 0, /* horizontal position of window - set it later */ 0, /* vertical position of window - set it later */ 0, /* window width - set it later */ 0, /* window height - set it later*/ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ if (!ret) { panic("Cannot create map window"); } return ret; } void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw) { PNHMapWindow data; RECT client_rt; SCROLLINFO si; SIZE wnd_size; LOGFONT lgfnt; /* check arguments */ if (!IsWindow(hWnd) || !lpsz || lpsz->cx <= 0 || lpsz->cy <= 0) return; /* calculate window size */ GetClientRect(hWnd, &client_rt); wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; /* set new screen tile size */ data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); data->xScrTile = max(1, (data->bFitToScreenMode ? wnd_size.cx : lpsz->cx) / COLNO); data->yScrTile = max(1, (data->bFitToScreenMode ? wnd_size.cy : lpsz->cy) / ROWNO); /* set map origin point */ data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile * COLNO) / 2); data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile * ROWNO) / 2); data->map_orig.x -= data->map_orig.x % data->xScrTile; data->map_orig.y -= data->map_orig.y % data->yScrTile; /* adjust horizontal scroll bar */ if (data->bFitToScreenMode) data->xPageSize = COLNO + 1; /* disable scroll bar */ else data->xPageSize = wnd_size.cx / data->xScrTile; if (data->xPageSize >= COLNO) { data->xPos = 0; GetNHApp()->bNoHScroll = TRUE; } else { GetNHApp()->bNoHScroll = FALSE; data->xPos = max( 0, min(COLNO - data->xPageSize + 1, u.ux - data->xPageSize / 2)); } if (!GetNHApp()->bHideScrollBars) { si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = COLNO; si.nPage = data->xPageSize; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } /* adjust vertical scroll bar */ if (data->bFitToScreenMode) data->yPageSize = ROWNO + 1; /* disable scroll bar */ else data->yPageSize = wnd_size.cy / data->yScrTile; if (data->yPageSize >= ROWNO) { data->yPos = 0; GetNHApp()->bNoVScroll = TRUE; } else { GetNHApp()->bNoVScroll = FALSE; data->yPos = max( 0, min(ROWNO - data->yPageSize + 1, u.uy - data->yPageSize / 2)); } if (!GetNHApp()->bHideScrollBars) { si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = ROWNO; si.nPage = data->yPageSize; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } /* create font */ if (data->hMapFont) DeleteObject(data->hMapFont); ZeroMemory(&lgfnt, sizeof(lgfnt)); lgfnt.lfHeight = -data->yScrTile; // height of font lgfnt.lfWidth = -data->xScrTile; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_map && *iflags.wc_font_map) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family _tcsncpy(lgfnt.lfFaceName, NHMAP_FONT_NAME, LF_FACESIZE); } data->hMapFont = CreateFontIndirect(&lgfnt); mswin_cliparound(data->xCur, data->yCur); if (redraw) InvalidateRect(hWnd, NULL, TRUE); } /* set map mode */ int mswin_map_mode(HWND hWnd, int mode) { PNHMapWindow data; int oldMode; SIZE mapSize; data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); if (mode == data->mapMode) return mode; oldMode = data->mapMode; data->mapMode = mode; switch (data->mapMode) { case MAP_MODE_ASCII4x6: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 4 * COLNO; mapSize.cy = 6 * ROWNO; break; case MAP_MODE_ASCII6x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 6 * COLNO; mapSize.cy = 8 * ROWNO; break; case MAP_MODE_ASCII8x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8 * COLNO; mapSize.cy = 8 * ROWNO; break; case MAP_MODE_ASCII16x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16 * COLNO; mapSize.cy = 8 * ROWNO; break; case MAP_MODE_ASCII7x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 7 * COLNO; mapSize.cy = 12 * ROWNO; break; case MAP_MODE_ASCII8x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8 * COLNO; mapSize.cy = 12 * ROWNO; break; case MAP_MODE_ASCII16x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16 * COLNO; mapSize.cy = 12 * ROWNO; break; case MAP_MODE_ASCII12x16: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 12 * COLNO; mapSize.cy = 16 * ROWNO; break; case MAP_MODE_ASCII10x18: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 10 * COLNO; mapSize.cy = 18 * ROWNO; break; case MAP_MODE_ASCII_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = TRUE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = FALSE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES: default: data->bAsciiMode = FALSE; data->bFitToScreenMode = FALSE; mapSize.cx = GetNHApp()->mapTile_X * COLNO; mapSize.cy = GetNHApp()->mapTile_Y * ROWNO; break; } mswin_map_stretch(hWnd, &mapSize, TRUE); return oldMode; } /* retrieve cursor position */ void mswin_map_get_cursor(HWND hWnd, int *x, int *y) { PNHMapWindow data; data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); if (!data) panic("mswin_map_get_cursor: no window data"); if (x) *x = data->xCur; if (y) *y = data->yCur; } /* register window class for map window */ void register_map_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); /* window class */ wcex.style = CS_NOCLOSE | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC) MapWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */ wcex.lpszMenuName = NULL; wcex.lpszClassName = szNHMapWindowClass; if (!RegisterClass(&wcex)) { panic("cannot register Map window class"); } } /* map window procedure */ LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; int x, y; data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_CREATE: onCreate(hWnd, wParam, lParam); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: /* transfer focus back to the main window */ SetFocus(GetNHApp()->hMainWnd); break; case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_SIZE: { SIZE size; if (data->bFitToScreenMode) { size.cx = LOWORD(lParam); size.cy = HIWORD(lParam); } else { /* mapping factor is unchaged we just need to adjust scroll bars */ size.cx = data->xScrTile * COLNO; size.cy = data->yScrTile * ROWNO; } mswin_map_stretch(hWnd, &size, TRUE); } break; case WM_LBUTTONDOWN: x = max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) / data->xScrTile)); y = max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) / data->yScrTile)); NHEVENT_MS(CLICK_1, x, y); data->xLastMouseClick = x; data->yLastMouseClick = y; return 0; case WM_LBUTTONDBLCLK: x = max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) / data->xScrTile)); y = max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) / data->yScrTile)); /* if map has scrolled since the last mouse click - ignore * double-click message */ if (data->xLastMouseClick == x && data->yLastMouseClick == y) { NHEVENT_MS(CLICK_1, x, y); } return 0; case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } /* on WM_COMMAND */ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; RECT rt; data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; data->map[msg_data->x][msg_data->y] = msg_data->glyph; /* invalidate the update area */ nhcoord2display(data, msg_data->x, msg_data->y, &rt); InvalidateRect(hWnd, &rt, TRUE); } break; case MSNH_MSG_CLIPAROUND: { PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround) lParam; int x, y; BOOL scroll_x, scroll_y; int mcam = iflags.wc_scroll_margin; /* calculate if you should clip around */ scroll_x = !GetNHApp()->bNoHScroll && (msg_data->x < (data->xPos + mcam) || msg_data->x > (data->xPos + data->xPageSize - mcam)); scroll_y = !GetNHApp()->bNoVScroll && (msg_data->y < (data->yPos + mcam) || msg_data->y > (data->yPos + data->yPageSize - mcam)); mcam += iflags.wc_scroll_amount - 1; /* get page size and center horizontally on x-position */ if (scroll_x) { if (data->xPageSize <= 2 * mcam) { x = max(0, min(COLNO, msg_data->x - data->xPageSize / 2)); } else if (msg_data->x < data->xPos + data->xPageSize / 2) { x = max(0, min(COLNO, msg_data->x - mcam)); } else { x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam)); } SendMessage(hWnd, WM_HSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, x), (LPARAM) NULL); } /* get page size and center vertically on y-position */ if (scroll_y) { if (data->yPageSize <= 2 * mcam) { y = max(0, min(ROWNO, msg_data->y - data->yPageSize / 2)); } else if (msg_data->y < data->yPos + data->yPageSize / 2) { y = max(0, min(ROWNO, msg_data->y - mcam)); } else { y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam)); } SendMessage(hWnd, WM_VSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, y), (LPARAM) NULL); } } break; case MSNH_MSG_CLEAR_WINDOW: { int i, j; for (i = 0; i < COLNO; i++) for (j = 0; j < ROWNO; j++) { data->map[i][j] = -1; } InvalidateRect(hWnd, NULL, TRUE); } break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam; HDC hdc; RECT rt; /* move focus rectangle at the cursor postion */ hdc = GetDC(hWnd); nhcoord2display(data, data->xCur, data->yCur, &rt); if (data->bAsciiMode) { PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } data->xCur = msg_data->x; data->yCur = msg_data->y; nhcoord2display(data, data->xCur, data->yCur, &rt); if (data->bAsciiMode) { PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } ReleaseDC(hWnd, hdc); } break; } } /* on WM_CREATE */ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; int i, j; /* set window data */ data = (PNHMapWindow) malloc(sizeof(NHMapWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); for (i = 0; i < COLNO; i++) for (j = 0; j < ROWNO; j++) { data->map[i][j] = -1; } data->bAsciiMode = FALSE; data->xScrTile = GetNHApp()->mapTile_X; data->yScrTile = GetNHApp()->mapTile_Y; data->xLastMouseClick = data->yLastMouseClick = -1; SetWindowLong(hWnd, GWL_USERDATA, (LONG) data); } /* on WM_PAINT */ void onPaint(HWND hWnd) { PNHMapWindow data; PAINTSTRUCT ps; HDC hDC; HDC tileDC; HGDIOBJ saveBmp; RECT paint_rt; int i, j; /* get window data */ data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); hDC = BeginPaint(hWnd, &ps); /* calculate paint rectangle */ if (!IsRectEmpty(&ps.rcPaint)) { /* calculate paint rectangle */ paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x) / data->xScrTile, 0); paint_rt.top = max( data->yPos + (ps.rcPaint.top - data->map_orig.y) / data->yScrTile, 0); paint_rt.right = min( data->xPos + (ps.rcPaint.right - data->map_orig.x) / data->xScrTile + 1, COLNO); paint_rt.bottom = min( data->yPos + (ps.rcPaint.bottom - data->map_orig.y) / data->yScrTile + 1, ROWNO); if (data->bAsciiMode || Is_rogue_level(&u.uz)) { /* You enter a VERY primitive world! */ HGDIOBJ oldFont; oldFont = SelectObject(hDC, data->hMapFont); SetBkMode(hDC, TRANSPARENT); /* draw the map */ for (i = paint_rt.left; i < paint_rt.right; i++) for (j = paint_rt.top; j < paint_rt.bottom; j++) if (data->map[i][j] >= 0) { char ch; TCHAR wch; RECT glyph_rect; int color; unsigned special; int mgch; HBRUSH back_brush; COLORREF OldFg; nhcoord2display(data, i, j, &glyph_rect); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) nhglyph2charcolor(data->map[i][j], &ch, &color); OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); #else /* rely on NetHack core helper routine */ (void) mapglyph(data->map[i][j], &mgch, &color, &special, i, j); ch = (char) mgch; if (((special & MG_PET) && iflags.hilite_pet) || ((special & MG_DETECT) && iflags.use_inverse)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); FillRect(hDC, &glyph_rect, back_brush); DeleteObject(back_brush); switch (color) { case CLR_GRAY: case CLR_WHITE: OldFg = SetTextColor( hDC, nhcolor_to_RGB(CLR_BLACK)); break; default: OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); } } else { OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); } #endif DrawText(hDC, NH_A2W(&ch, &wch, 1), 1, &glyph_rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX); SetTextColor(hDC, OldFg); } SelectObject(hDC, oldFont); } else { /* prepare tiles DC for mapping */ tileDC = CreateCompatibleDC(hDC); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); /* draw the map */ for (i = paint_rt.left; i < paint_rt.right; i++) for (j = paint_rt.top; j < paint_rt.bottom; j++) if (data->map[i][j] >= 0) { short ntile; int t_x, t_y; RECT glyph_rect; ntile = glyph2tile[data->map[i][j]]; t_x = (ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X; t_y = (ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y; nhcoord2display(data, i, j, &glyph_rect); StretchBlt(hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); if (glyph_is_pet(data->map[i][j]) && iflags.wc_hilite_pet) { /* apply pet mark transparently over pet image */ HDC hdcPetMark; HBITMAP bmPetMarkOld; /* this is DC for petmark bitmap */ hdcPetMark = CreateCompatibleDC(hDC); bmPetMarkOld = SelectObject( hdcPetMark, GetNHApp()->bmpPetMark); nhapply_image_transparent( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, hdcPetMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR); SelectObject(hdcPetMark, bmPetMarkOld); DeleteDC(hdcPetMark); } } SelectObject(tileDC, saveBmp); DeleteDC(tileDC); } /* draw focus rect */ nhcoord2display(data, data->xCur, data->yCur, &paint_rt); if (data->bAsciiMode) { PatBlt(hDC, paint_rt.left, paint_rt.top, paint_rt.right - paint_rt.left, paint_rt.bottom - paint_rt.top, DSTINVERT); } else { DrawFocusRect(hDC, &paint_rt); } } EndPaint(hWnd, &ps); } /* on WM_VSCROLL */ void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int yNewPos; int yDelta; /* get window data */ data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: yNewPos = data->yPos - data->yPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: yNewPos = data->yPos + data->yPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: yNewPos = data->yPos - 1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: yNewPos = data->yPos + 1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: yNewPos = HIWORD(wParam); break; default: yNewPos = data->yPos; } yNewPos = max(0, min(ROWNO - data->yPageSize + 1, yNewPos)); if (yNewPos == data->yPos) return; yDelta = yNewPos - data->yPos; data->yPos = yNewPos; ScrollWindowEx(hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); if (!GetNHApp()->bHideScrollBars) { si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } } /* on WM_HSCROLL */ void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int xNewPos; int xDelta; /* get window data */ data = (PNHMapWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: xNewPos = data->xPos - data->xPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: xNewPos = data->xPos + data->xPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: xNewPos = data->xPos - 1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: xNewPos = data->xPos + 1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: xNewPos = HIWORD(wParam); break; default: xNewPos = data->xPos; } xNewPos = max(0, min(COLNO - data->xPageSize + 1, xNewPos)); if (xNewPos == data->xPos) return; xDelta = xNewPos - data->xPos; data->xPos = xNewPos; ScrollWindowEx(hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); if (!GetNHApp()->bHideScrollBars) { si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } } /* map nethack map coordinates to the screen location */ void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut) { lpOut->left = (x - data->xPos) * data->xScrTile + data->map_orig.x; lpOut->top = (y - data->yPos) * data->yScrTile + data->map_orig.y; lpOut->right = lpOut->left + data->xScrTile; lpOut->bottom = lpOut->top + data->yScrTile; } #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) /* map glyph to character/color combination */ void nhglyph2charcolor(short g, uchar *ch, int *color) { int offset; #ifdef TEXTCOLOR #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR #define obj_color(n) \ *color = iflags.use_color ? objects[n].oc_color : NO_COLOR #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define warn_color(n) \ *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR #else /* no text color */ #define zap_color(n) #define cmap_color(n) #define obj_color(n) #define mon_color(n) #define pet_color(c) #define warn_color(c) *color = CLR_WHITE; #endif if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */ *ch = showsyms[offset + SYM_OFF_W]; warn_color(offset); } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ /* see swallow_to_glyph() in display.c */ *ch = (uchar) showsyms[(S_sw_tl + (offset & 0x7)) + SYM_OFF_P]; mon_color(offset >> 3); } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ /* see zapdir_to_glyph() in display.c */ *ch = showsyms[(S_vbeam + (offset & 0x3)) + SYM_OFF_P]; zap_color((offset >> 2)); } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ *ch = showsyms[offset + SYM_OFF_P]; cmap_color(offset); } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */ *ch = showsyms[(int) objects[offset].oc_class + SYM_OFF_O]; obj_color(offset); } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ *ch = showsyms[(int) objects[CORPSE].oc_class + SYM_OFF_O]; mon_color(offset); } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */ *ch = showsyms[(int) mons[offset].mlet + SYM_OFF_M]; pet_color(offset); } else { /* a monster */ *ch = showsyms[(int) mons[g].mlet + SYM_OFF_M]; mon_color(g); } // end of wintty code } #endif /* map nethack color to RGB */ COLORREF nhcolor_to_RGB(int c) { switch (c) { case CLR_BLACK: return RGB(0x55, 0x55, 0x55); case CLR_RED: return RGB(0xFF, 0x00, 0x00); case CLR_GREEN: return RGB(0x00, 0x80, 0x00); case CLR_BROWN: return RGB(0xA5, 0x2A, 0x2A); case CLR_BLUE: return RGB(0x00, 0x00, 0xFF); case CLR_MAGENTA: return RGB(0xFF, 0x00, 0xFF); case CLR_CYAN: return RGB(0x00, 0xFF, 0xFF); case CLR_GRAY: return RGB(0xC0, 0xC0, 0xC0); case NO_COLOR: return RGB(0xFF, 0xFF, 0xFF); case CLR_ORANGE: return RGB(0xFF, 0xA5, 0x00); case CLR_BRIGHT_GREEN: return RGB(0x00, 0xFF, 0x00); case CLR_YELLOW: return RGB(0xFF, 0xFF, 0x00); case CLR_BRIGHT_BLUE: return RGB(0x00, 0xC0, 0xFF); case CLR_BRIGHT_MAGENTA: return RGB(0xFF, 0x80, 0xFF); case CLR_BRIGHT_CYAN: return RGB(0x80, 0xFF, 0xFF); /* something close to aquamarine */ case CLR_WHITE: return RGB(0xFF, 0xFF, 0xFF); default: return RGB(0x00, 0x00, 0x00); /* black */ } } /* apply bitmap pointed by sourceDc transparently over bitmap pointed by hDC */ void nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, COLORREF cTransparent) { TransparentImage(hDC, x, y, width, height, sourceDC, s_x, s_y, s_width, s_height, cTransparent); } nethack-3.6.0/sys/wince/mhmap.h0000664000076400007660000000124512536476415015352 0ustar paxedpaxed/* NetHack 3.6 mhmap.h $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMapWindow_h #define MSWINMapWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_map_window(void); void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); void mswin_map_get_cursor(HWND hWnd, int *x, int *y); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 #endif /* MSWINMapWindow_h */ nethack-3.6.0/sys/wince/mhmenu.c0000664000076400007660000014667312536476415015553 0ustar paxedpaxed/* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "mhmenu.h" #include "mhmain.h" #include "mhmsg.h" #include "mhcmd.h" #include "mhinput.h" #include "mhfont.h" #include "mhcolor.h" #include "mhtxtbuf.h" #define MENU_MARGIN 0 #define NHMENU_STR_SIZE BUFSZ #define MIN_TABSTOP_SIZE 0 #define NUMTABS 15 #define TAB_SEPARATION 10 /* pixels between each tab stop */ typedef struct mswin_menu_item { int glyph; ANY_P identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; char str[NHMENU_STR_SIZE]; BOOLEAN_P presel; int count; BOOL has_focus; BOOL has_tab; } NHMenuItem, *PNHMenuItem; typedef struct mswin_nethack_menu_window { int type; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */ int how; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */ union { struct menu_list { int size; /* number of items in items[] */ int allocated; /* number of allocated slots in items[] */ PNHMenuItem items; /* menu items */ char gacc[QBUFSZ]; /* group accelerators */ BOOL counting; /* counting flag */ char prompt[QBUFSZ]; /* menu prompt */ int tab_stop_size[NUMTABS]; /* tabstops to align option values */ } menu; struct menu_text { PNHTextBuffer text; } text; }; int result; int done; HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; } NHMenuWindow, *PNHMenuWindow; extern short glyph2tile[]; static WNDPROC wndProcListViewOrig = NULL; static WNDPROC editControlWndProc = NULL; #define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj != NULL) #define NHMENU_IS_SELECTED(item) ((item).count != 0) LRESULT CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM); static void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static LRESULT onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutMenu(HWND hwnd); static void SetMenuType(HWND hwnd, int type); static void SetMenuListType(HWND hwnd, int now); static HWND GetMenuControl(HWND hwnd); static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count); static void reset_menu_count(HWND hwndList, PNHMenuWindow data); static LRESULT onListChar(HWND hWnd, HWND hwndList, WORD ch); static char *parse_menu_str(char *dest, const char *src, size_t size); HWND mswin_init_menu_window(int type) { HWND ret; ret = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_MENU), GetNHApp()->hMainWnd, MenuWndProc); if (!ret) { panic("Cannot create menu window"); } SetMenuType(ret, type); return ret; } int mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected) { PNHMenuWindow data; int ret_val; MENU_ITEM_P *selected = NULL; int i; char *ap; char accell_str[256]; assert(_selected != NULL); *_selected = NULL; ret_val = -1; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); /* set menu type */ SetMenuListType(hWnd, how); /* Ok, now give items a unique accelerators */ ZeroMemory(accell_str, sizeof(accell_str)); ap = accell_str; #if defined(WIN_CE_SMARTPHONE) if (data->menu.size > 10) { *ap++ = MENU_FIRST_PAGE; *ap++ = MENU_LAST_PAGE; *ap++ = MENU_NEXT_PAGE; *ap++ = MENU_PREVIOUS_PAGE; if (data->how == PICK_ANY) { *ap++ = MENU_SELECT_ALL; *ap++ = MENU_UNSELECT_ALL; *ap++ = MENU_INVERT_ALL; *ap++ = MENU_SELECT_PAGE; *ap++ = MENU_UNSELECT_PAGE; *ap++ = MENU_INVERT_PAGE; } *ap++ = MENU_SEARCH; } #endif if (data->type == MENU_TYPE_MENU) { char next_char = 'a'; for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].accelerator != 0) { *ap++ = data->menu.items[i].accelerator; next_char = (char) (data->menu.items[i].accelerator + 1); } else if (NHMENU_IS_SELECTABLE(data->menu.items[i])) { if ((next_char >= 'a' && next_char <= 'z') || (next_char >= 'A' && next_char <= 'Z')) { data->menu.items[i].accelerator = next_char; *ap++ = data->menu.items[i].accelerator; } else { if (next_char > 'z') next_char = 'A'; else if (next_char > 'Z') break; data->menu.items[i].accelerator = next_char; *ap++ = data->menu.items[i].accelerator; } next_char++; } } /* collect group accelerators */ data->menu.gacc[0] = '\0'; ap = data->menu.gacc; if (data->how != PICK_NONE) { for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].group_accel && !strchr(data->menu.gacc, data->menu.items[i].group_accel)) { *ap++ = data->menu.items[i].group_accel; *ap = '\x0'; } } } reset_menu_count(NULL, data); } #if defined(WIN_CE_SMARTPHONE) if (data->type == MENU_TYPE_MENU) NHSPhoneSetKeypadFromString(accell_str); #endif mswin_popup_display(hWnd, &data->done); /* get the result */ if (data->result != -1) { if (how == PICK_NONE) { if (data->result >= 0) ret_val = 0; else ret_val = -1; } else if (how == PICK_ONE || how == PICK_ANY) { /* count selected items */ ret_val = 0; for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i])) { ret_val++; } } if (ret_val > 0) { int sel_ind; selected = (MENU_ITEM_P *) malloc(ret_val * sizeof(MENU_ITEM_P)); if (!selected) panic("out of memory"); sel_ind = 0; for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i])) { selected[sel_ind].item = data->menu.items[i].identifier; selected[sel_ind].count = data->menu.items[i].count; sel_ind++; } } ret_val = sel_ind; *_selected = selected; } } } mswin_popup_destroy(hWnd); #if defined(WIN_CE_SMARTPHONE) if (data->type == MENU_TYPE_MENU) NHSPhoneSetKeypadDefault(); #endif return ret_val; } LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; CheckInputDialog(hWnd, message, wParam, lParam); data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: { HWND text_control; HDC hDC; text_control = GetDlgItem(hWnd, IDC_MENU_TEXT); data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; data->how = PICK_NONE; data->result = 0; data->done = 0; data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL)); data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); SetWindowLong(hWnd, GWL_USERDATA, (LONG) data); /* subclass edit control */ editControlWndProc = (WNDPROC) GetWindowLong(text_control, GWL_WNDPROC); SetWindowLong(text_control, GWL_WNDPROC, (LONG) NHMenuTextWndProc); /* set text window font */ hDC = GetDC(text_control); SendMessage(text_control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hDC, FALSE), (LPARAM) 0); ReleaseDC(text_control, hDC); #if defined(WIN_CE_SMARTPHONE) /* special initialization for SmartPhone dialogs */ NHSPhoneDialogSetup(hWnd, IDC_SPHONE_DIALOGBAR, FALSE, GetNHApp()->bFullScreen); #endif } break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: LayoutMenu(hWnd); return FALSE; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: if (data->type == MENU_TYPE_MENU && (data->how == PICK_ONE || data->how == PICK_ANY) && data->menu.counting) { HWND list; int i; /* reset counter if counting is in progress */ list = GetMenuControl(hWnd); i = ListView_GetNextItem(list, -1, LVNI_FOCUSED); if (i >= 0) { SelectMenuItem(list, data, i, 0); } return FALSE; } else { data->result = -1; data->done = 1; } return FALSE; case IDOK: data->done = 1; data->result = 0; return FALSE; } } break; case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR) lParam; switch (LOWORD(wParam)) { case IDC_MENU_LIST: { if (!data || data->type != MENU_TYPE_MENU) break; switch (lpnmhdr->code) { case LVN_ITEMACTIVATE: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if (data->how == PICK_ONE) { if (lpnmlv->iItem >= 0 && lpnmlv->iItem < data->menu.size && NHMENU_IS_SELECTABLE( data->menu.items[lpnmlv->iItem])) { SelectMenuItem(lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1); data->done = 1; data->result = 0; return TRUE; } } else if (data->how == PICK_ANY) { if (lpnmlv->iItem >= 0 && lpnmlv->iItem < data->menu.size && NHMENU_IS_SELECTABLE( data->menu.items[lpnmlv->iItem])) { SelectMenuItem(lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, NHMENU_IS_SELECTED( data->menu.items[lpnmlv->iItem]) ? 0 : -1); } } } break; case NM_CLICK: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if (lpnmlv->iItem == -1) return 0; if (data->how == PICK_ANY) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem]) ? 0 : -1); } } break; case LVN_ITEMCHANGED: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if (lpnmlv->iItem == -1) return 0; if (!(lpnmlv->uChanged & LVIF_STATE)) return 0; /* update item that has the focus */ data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); /* update count for single-selection menu (follow the listview * selection) */ if (data->how == PICK_ONE) { if (lpnmlv->uNewState & LVIS_SELECTED) { SelectMenuItem(lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1); } } /* check item focus */ data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); } break; case NM_KILLFOCUS: reset_menu_count(lpnmhdr->hwndFrom, data); break; } } break; } } break; case WM_SETFOCUS: if (hWnd != GetNHApp()->hPopupWnd) { SetFocus(GetNHApp()->hPopupWnd); return 0; } break; case WM_MEASUREITEM: if (wParam == IDC_MENU_LIST) return onMeasureItem(hWnd, wParam, lParam); else return FALSE; case WM_DRAWITEM: if (wParam == IDC_MENU_LIST) return onDrawItem(hWnd, wParam, lParam); else return FALSE; case WM_CTLCOLORBTN: case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if (hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT)) { SetBkColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG)); SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG)); return (BOOL) mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG); } } return FALSE; case WM_DESTROY: if (data) { DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); if (data->type == MENU_TYPE_TEXT) { if (data->text.text) { mswin_free_text_buffer(data->text.text); data->text.text = NULL; } } free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); } return TRUE; } return FALSE; } void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { #if defined(WIN_CE_POCKETPC) PNHMenuWindow data; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); if (!(data && data->type == MENU_TYPE_MENU && (data->how == PICK_ONE || data->how == PICK_ANY))) return; switch (message) { case WM_SETFOCUS: if (GetNHApp()->bUseSIP) SHSipPreference(hWnd, SIP_UP); return; case WM_DESTROY: case WM_KILLFOCUS: if (GetNHApp()->bUseSIP) SHSipPreference(hWnd, SIP_DOWN); return; case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR) lParam; switch (lpnmhdr->code) { case NM_SETFOCUS: if (GetNHApp()->bUseSIP) SHSipPreference(hWnd, SIP_UP); break; case NM_KILLFOCUS: if (GetNHApp()->bUseSIP) SHSipPreference(hWnd, SIP_DOWN); break; } } return; case WM_COMMAND: switch (HIWORD(wParam)) { case BN_SETFOCUS: if (GetNHApp()->bUseSIP) SHSipPreference(hWnd, SIP_UP); break; case BN_KILLFOCUS: if (GetNHApp()->bUseSIP) SHSipPreference(hWnd, SIP_DOWN); break; } return; } /* end switch */ #endif } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; HWND text_view; if (data->type != MENU_TYPE_TEXT) SetMenuType(hWnd, MENU_TYPE_TEXT); if (!data->text.text) { data->text.text = mswin_init_text_buffer( program_state.gameover ? FALSE : GetNHApp()->bWrapText); if (!data->text.text) break; } mswin_add_text(data->text.text, msg_data->attr, msg_data->text); text_view = GetDlgItem(hWnd, IDC_MENU_TEXT); if (!text_view) panic("cannot get text view window"); mswin_render_text(data->text.text, text_view); } break; case MSNH_MSG_STARTMENU: { int i; if (data->type != MENU_TYPE_MENU) SetMenuType(hWnd, MENU_TYPE_MENU); if (data->menu.items) free(data->menu.items); data->how = PICK_NONE; data->menu.items = NULL; data->menu.size = 0; data->menu.allocated = 0; data->done = 0; data->result = 0; for (i = 0; i < NUMTABS; ++i) data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE; } break; case MSNH_MSG_ADDMENU: { PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu) lParam; char *p, *p1; int new_item; HDC hDC; int column; HFONT saveFont; if (data->type != MENU_TYPE_MENU) break; if (strlen(msg_data->str) == 0) break; if (data->menu.size == data->menu.allocated) { data->menu.allocated += 10; data->menu.items = (PNHMenuItem) realloc( data->menu.items, data->menu.allocated * sizeof(NHMenuItem)); } new_item = data->menu.size; ZeroMemory(&data->menu.items[new_item], sizeof(data->menu.items[new_item])); data->menu.items[new_item].glyph = msg_data->glyph; data->menu.items[new_item].identifier = *msg_data->identifier; data->menu.items[new_item].accelerator = msg_data->accelerator; data->menu.items[new_item].group_accel = msg_data->group_accel; data->menu.items[new_item].attr = msg_data->attr; parse_menu_str(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE); data->menu.items[new_item].presel = msg_data->presel; /* calculate tabstop size */ p = strchr(data->menu.items[new_item].str, '\t'); if (p) { data->menu.items[new_item].has_tab = TRUE; hDC = GetDC(hWnd); saveFont = SelectObject( hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE)); p1 = data->menu.items[new_item].str; column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT drawRect; SetRect(&drawRect, 0, 0, 1, 1); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE); data->menu.tab_stop_size[column] = max(data->menu.tab_stop_size[column], drawRect.right - drawRect.left); if (p != NULL) *p = '\t'; else /* last string so, */ break; ++column; p1 = p + 1; p = strchr(p1, '\t'); } SelectObject(hDC, saveFont); ReleaseDC(hWnd, hDC); } else { data->menu.items[new_item].has_tab = FALSE; } /* increment size */ data->menu.size++; } break; case MSNH_MSG_ENDMENU: { PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu) lParam; if (msg_data->text) { strncpy(data->menu.prompt, msg_data->text, sizeof(data->menu.prompt) - 1); } else { ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt)); } } break; } /* end switch */ } void LayoutMenu(HWND hWnd) { PNHMenuWindow data; HWND menu_ok; HWND menu_cancel; RECT clrt, rt; POINT pt_elem, pt_ok, pt_cancel; SIZE sz_elem, sz_ok, sz_cancel; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); menu_ok = GetDlgItem(hWnd, IDOK); menu_cancel = GetDlgItem(hWnd, IDCANCEL); /* get window coordinates */ GetClientRect(hWnd, &clrt); /* set window placements */ if (IsWindow(menu_ok)) { GetWindowRect(menu_ok, &rt); sz_ok.cx = (clrt.right - clrt.left) / 2 - 2 * MENU_MARGIN; sz_ok.cy = rt.bottom - rt.top; pt_ok.x = clrt.left + MENU_MARGIN; pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy; MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE); } else { pt_ok.x = 0; pt_ok.y = clrt.bottom; sz_ok.cx = sz_ok.cy = 0; } if (IsWindow(menu_cancel)) { GetWindowRect(menu_cancel, &rt); sz_cancel.cx = (clrt.right - clrt.left) / 2 - 2 * MENU_MARGIN; sz_cancel.cy = rt.bottom - rt.top; pt_cancel.x = (clrt.left + clrt.right) / 2 + MENU_MARGIN; pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy; MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE); } else { pt_cancel.x = 0; pt_cancel.y = clrt.bottom; sz_cancel.cx = sz_cancel.cy = 0; } pt_elem.x = clrt.left + MENU_MARGIN; pt_elem.y = clrt.top + MENU_MARGIN; sz_elem.cx = (clrt.right - clrt.left) - 2 * MENU_MARGIN; sz_elem.cy = min(pt_cancel.y, pt_ok.y) - MENU_MARGIN - pt_elem.y; MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE); /* reformat text for the text menu */ if (data && data->type == MENU_TYPE_TEXT && data->text.text) mswin_render_text(data->text.text, GetMenuControl(hWnd)); } void SetMenuType(HWND hWnd, int type) { PNHMenuWindow data; HWND list, text; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); data->type = type; text = GetDlgItem(hWnd, IDC_MENU_TEXT); list = GetDlgItem(hWnd, IDC_MENU_LIST); if (data->type == MENU_TYPE_TEXT) { ShowWindow(list, SW_HIDE); EnableWindow(list, FALSE); EnableWindow(text, TRUE); ShowWindow(text, SW_SHOW); SetFocus(text); } else { ShowWindow(text, SW_HIDE); EnableWindow(text, FALSE); EnableWindow(list, TRUE); ShowWindow(list, SW_SHOW); SetFocus(list); } LayoutMenu(hWnd); } void SetMenuListType(HWND hWnd, int how) { PNHMenuWindow data; RECT rt; DWORD dwStyles; char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; int nItem; int i; HWND control; LVCOLUMN lvcol; LRESULT fnt; SIZE wnd_size; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data->type != MENU_TYPE_MENU) return; data->how = how; switch (how) { case PICK_NONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ANY: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY"); }; if (strlen(data->menu.prompt) == 0) { dwStyles |= LVS_NOCOLUMNHEADER; } GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt); DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST)); control = CreateWindow(WC_LISTVIEW, NULL, dwStyles, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hWnd, (HMENU) IDC_MENU_LIST, GetNHApp()->hApp, NULL); if (!control) panic("cannot create menu control"); /* install the hook for the control window procedure */ wndProcListViewOrig = (WNDPROC) GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG) NHMenuListWndProc); /* set control font */ fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM) 0, (LPARAM) 0); SendMessage(control, WM_SETFONT, (WPARAM) fnt, (LPARAM) 0); /* set control colors */ ListView_SetBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG)); ListView_SetTextBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG)); ListView_SetTextColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG)); /* add column to the list view */ mswin_menu_window_size(hWnd, &wnd_size); ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; lvcol.cx = max(wnd_size.cx, GetSystemMetrics(SM_CXSCREEN)); lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); /* add items to the list view */ for (i = 0; i < data->menu.size; i++) { LVITEM lvitem; ZeroMemory(&lvitem, sizeof(lvitem)); sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str); lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; lvitem.iItem = i; lvitem.iSubItem = 0; lvitem.state = data->menu.items[i].presel ? LVIS_SELECTED : 0; lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ); lvitem.lParam = (LPARAM) &data->menu.items[i]; nItem = SendMessage(control, LB_ADDSTRING, (WPARAM) 0, (LPARAM) buf); if (ListView_InsertItem(control, &lvitem) == -1) { panic("cannot insert menu item"); } } SetFocus(control); } HWND GetMenuControl(HWND hWnd) { PNHMenuWindow data; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data->type == MENU_TYPE_TEXT) { return GetDlgItem(hWnd, IDC_MENU_TEXT); } else { return GetDlgItem(hWnd, IDC_MENU_LIST); } } LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMEASUREITEMSTRUCT lpmis; TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; RECT list_rect; lpmis = (LPMEASUREITEMSTRUCT) lParam; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); GetClientRect(GetMenuControl(hWnd), &list_rect); hdc = GetDC(GetMenuControl(hWnd)); saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE)); GetTextMetrics(hdc, &tm); /* Set the height of the list box items. */ lpmis->itemHeight = max(tm.tmHeight, TILE_Y) + 2; lpmis->itemWidth = list_rect.right - list_rect.left; SelectObject(hdc, saveFont); ReleaseDC(GetMenuControl(hWnd), hdc); return TRUE; } LRESULT onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPDRAWITEMSTRUCT lpdis; PNHMenuItem item; PNHMenuWindow data; TEXTMETRIC tm; HGDIOBJ saveFont; HDC tileDC; short ntile; int t_x, t_y; int x, y; TCHAR wbuf[BUFSZ]; RECT drawRect; COLORREF OldBg, OldFg, NewBg; char *p, *p1; int column; lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ if (lpdis->itemID == -1) return FALSE; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); item = &data->menu.items[lpdis->itemID]; tileDC = CreateCompatibleDC(lpdis->hDC); saveFont = SelectObject( lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE)); NewBg = mswin_get_color(NHW_MENU, MSWIN_COLOR_BG); OldBg = SetBkColor(lpdis->hDC, NewBg); OldFg = SetTextColor(lpdis->hDC, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG)); GetTextMetrics(lpdis->hDC, &tm); x = lpdis->rcItem.left + 1; /* print check mark if it is a "selectable" menu */ if (data->how != PICK_NONE) { if (NHMENU_IS_SELECTABLE(*item)) { HGDIOBJ saveBrush; HBRUSH hbrCheckMark; char buf[2]; switch (item->count) { case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break; case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break; default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break; } y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; SetBrushOrgEx(lpdis->hDC, x, y, NULL); saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY); SelectObject(lpdis->hDC, saveBrush); DeleteObject(hbrCheckMark); x += TILE_X + 5; if (item->accelerator != 0) { buf[0] = item->accelerator; buf[1] = '\x0'; SetRect(&drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } x += tm.tmAveCharWidth + tm.tmOverhang + 5; } else { x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 10; } } /* print glyph if present */ if (item->glyph != NO_GLYPH) { HGDIOBJ saveBmp; saveBmp = SelectObject(tileDC, GetNHApp()->bmpTiles); ntile = glyph2tile[item->glyph]; t_x = (ntile % TILES_PER_LINE) * TILE_X; t_y = (ntile / TILES_PER_LINE) * TILE_Y; y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; nhapply_image_transparent(lpdis->hDC, x, y, TILE_X, TILE_Y, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR); SelectObject(tileDC, saveBmp); } x += TILE_X + 5; /* draw item text */ if (item->has_tab) { p1 = item->str; p = strchr(item->str, '\t'); column = 0; SetRect(&drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right), lpdis->rcItem.bottom); for (;;) { TCHAR wbuf[BUFSZ]; if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(lpdis->hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); if (p != NULL) *p = '\t'; else /* last string so, */ break; p1 = p + 1; p = strchr(p1, '\t'); drawRect.left = drawRect.right + TAB_SEPARATION; ++column; drawRect.right = min(drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right); } } else { TCHAR wbuf[BUFSZ]; SetRect(&drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, NH_A2W(item->str, wbuf, BUFSZ), strlen(item->str), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); } /* draw focused item */ if (item->has_focus) { RECT client_rt; HBRUSH bkBrush; GetClientRect(lpdis->hwndItem, &client_rt); if (NHMENU_IS_SELECTABLE(*item) && data->menu.items[lpdis->itemID].count > 0 && item->glyph != NO_GLYPH) { if (data->menu.items[lpdis->itemID].count == -1) { _stprintf(wbuf, TEXT("Count: All")); } else { _stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count); } SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE)); /* calculate text rectangle */ SetRect(&drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); /* erase text rectangle */ drawRect.left = max(client_rt.left + 1, client_rt.right - (drawRect.right - drawRect.left) - 10); drawRect.right = client_rt.right - 1; drawRect.top = lpdis->rcItem.top; drawRect.bottom = lpdis->rcItem.bottom; bkBrush = CreateSolidBrush(GetBkColor(lpdis->hDC)); FillRect(lpdis->hDC, &drawRect, bkBrush); DeleteObject(bkBrush); /* draw text */ DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } /* draw focus rect */ SetRect(&drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom); DrawFocusRect(lpdis->hDC, &drawRect); } SetTextColor(lpdis->hDC, OldFg); SetBkColor(lpdis->hDC, OldBg); SelectObject(lpdis->hDC, saveFont); DeleteDC(tileDC); return TRUE; } BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch) { int i = 0; PNHMenuWindow data; int curIndex, topIndex, pageSize; boolean is_accelerator = FALSE; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (ch) { case MENU_FIRST_PAGE: i = 0; ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_LAST_PAGE: i = max(0, data->menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_NEXT_PAGE: topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ i = min(curIndex + pageSize, data->menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_PREVIOUS_PAGE: topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus up one page */ i = max(curIndex - pageSize, 0); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos up one page */ i = max(topIndex - pageSize, 0); ListView_EnsureVisible(hwndList, i, FALSE); break; case MENU_SELECT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { SelectMenuItem(hwndList, data, i, -1); } return -2; } break; case MENU_UNSELECT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { SelectMenuItem(hwndList, data, i, 0); } return -2; } break; case MENU_INVERT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { SelectMenuItem(hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } return -2; } break; case MENU_SELECT_PAGE: if (data->how == PICK_ANY) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); to = min(data->menu.size, from + pageSize); for (i = from; i < to; i++) { SelectMenuItem(hwndList, data, i, -1); } return -2; } break; case MENU_UNSELECT_PAGE: if (data->how == PICK_ANY) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); to = min(data->menu.size, from + pageSize); for (i = from; i < to; i++) { SelectMenuItem(hwndList, data, i, 0); } return -2; } break; case MENU_INVERT_PAGE: if (data->how == PICK_ANY) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); to = min(data->menu.size, from + pageSize); for (i = from; i < to; i++) { SelectMenuItem(hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } return -2; } break; case MENU_SEARCH: if (data->how == PICK_ANY || data->how == PICK_ONE) { char buf[BUFSZ]; int selected_item; reset_menu_count(hwndList, data); mswin_getlin("Search for:", buf); if (!*buf || *buf == '\033') return -2; selected_item = -1; for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && strstr(data->menu.items[i].str, buf)) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); /* save the first item - we will move focus to it */ if (selected_item == -1) selected_item = i; } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); selected_item = i; break; } } } if (selected_item > 0) { ListView_SetItemState(hwndList, selected_item, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, selected_item, FALSE); } } else { mswin_nhbell(); } return -2; case ' ': /* ends menu for PICK_ONE/PICK_NONE select item for PICK_ANY */ if (data->how == PICK_ONE || data->how == PICK_NONE) { data->done = 1; data->result = 0; return -2; } else if (data->how == PICK_ANY) { i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if (i >= 0) { SelectMenuItem(hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } return -2; } break; default: if (strchr(data->menu.gacc, ch) && !(ch == '0' && data->menu.counting)) { /* matched a group accelerator */ if (data->how == PICK_ANY || data->how == PICK_ONE) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && data->menu.items[i].group_accel == ch) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); data->result = 0; data->done = 1; return -2; } } } return -2; } else { mswin_nhbell(); return -2; } } if (isdigit(ch)) { int count; i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if (i >= 0) { count = data->menu.items[i].count; if (count == -1) count = 0; count *= 10L; count += (int) (ch - '0'); if (count != 0) /* ignore leading zeros */ { data->menu.counting = TRUE; data->menu.items[i].count = min(100000, count); ListView_RedrawItems(hwndList, i, i); /* update count mark */ } } return -2; } is_accelerator = FALSE; for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].accelerator == ch) { is_accelerator = TRUE; break; } } if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || is_accelerator) { if (data->how == PICK_ANY || data->how == PICK_ONE) { for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].accelerator == ch) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); data->result = 0; data->done = 1; return -2; } } } } } break; } reset_menu_count(hwndList, data); return -1; } void mswin_menu_window_size(HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HWND control; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; int i; RECT rt, wrt; int extra_cx; GetClientRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; GetWindowRect(hWnd, &wrt); extra_cx = (wrt.right - wrt.left) - sz->cx; data = (PNHMenuWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data) { control = GetMenuControl(hWnd); hdc = GetDC(control); if (data->type == MENU_TYPE_MENU) { /* Calculate the width of the list box. */ saveFont = SelectObject( hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); for (i = 0; i < data->menu.size; i++) { LONG menuitemwidth = 0; int column; char *p, *p1; p1 = data->menu.items[i].str; p = strchr(data->menu.items[i].str, '\t'); column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT tabRect; SetRect(&tabRect, 0, 0, 1, 1); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hdc, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &tabRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE); /* it probably isn't necessary to recompute the tab width * now, but do so * just in case, honoring the previously computed value */ menuitemwidth += max(data->menu.tab_stop_size[column], tabRect.right - tabRect.left); if (p != NULL) *p = '\t'; else /* last string so, */ break; /* add the separation only when not the last item */ /* in the last item, we break out of the loop, in the * statement just above */ menuitemwidth += TAB_SEPARATION; ++column; p1 = p + 1; p = strchr(p1, '\t'); } sz->cx = max(sz->cx, (LONG)(2 * TILE_X + menuitemwidth + tm.tmAveCharWidth * 12 + tm.tmOverhang)); } SelectObject(hdc, saveFont); } else { /* do not change size for text output - the text will be formatted to fit any window */ } sz->cx += extra_cx; ReleaseDC(control, hdc); } } void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count) { int i; if (item < 0 || item >= data->menu.size) return; if (data->how == PICK_ONE && count != 0) { for (i = 0; i < data->menu.size; i++) if (item != i && data->menu.items[i].count != 0) { data->menu.items[i].count = 0; ListView_RedrawItems(hwndList, i, i); }; } data->menu.items[item].count = count; ListView_RedrawItems(hwndList, item, item); reset_menu_count(hwndList, data); } void reset_menu_count(HWND hwndList, PNHMenuWindow data) { int i; data->menu.counting = FALSE; if (IsWindow(hwndList)) { i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED); if (i >= 0) ListView_RedrawItems(hwndList, i, i); } } /* List window Proc */ LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bUpdateFocusItem = FALSE; switch (message) { /* filter keyboard input for the control */ #if !defined(WIN_CE_SMARTPHONE) case WM_KEYDOWN: case WM_KEYUP: { MSG msg; if (PeekMessage(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE)) { if (onListChar(GetParent(hWnd), hWnd, (char) msg.wParam) == -2) { return 0; } } if (wParam == VK_LEFT || wParam == VK_RIGHT) bUpdateFocusItem = TRUE; } break; /* tell Windows not to process arrow keys */ case WM_GETDLGCODE: return DLGC_WANTARROWS; #else /* defined(WIN_CE_SMARTPHONE) */ case WM_KEYDOWN: if (wParam == VK_TACTION) { if (onListChar(GetParent(hWnd), hWnd, ' ') == -2) { return 0; } } else if (NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE)) { PMSNHEvent evt; BOOL processed = FALSE; if (mswin_have_input()) { evt = mswin_input_pop(); if (evt->type == NHEVENT_CHAR && onListChar(GetParent(hWnd), hWnd, evt->kbd.ch) == -2) { processed = TRUE; } /* eat the rest of the events */ if (mswin_have_input()) mswin_input_pop(); } if (processed) return 0; } if (wParam == VK_LEFT || wParam == VK_RIGHT) bUpdateFocusItem = TRUE; break; case WM_KEYUP: /* translate SmartPhone keyboard message */ if (NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE)) return 0; break; /* tell Windows not to process default button on VK_RETURN */ case WM_GETDLGCODE: return DLGC_DEFPUSHBUTTON | DLGC_WANTALLKEYS | (wndProcListViewOrig ? CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam) : 0); #endif case WM_SIZE: case WM_HSCROLL: bUpdateFocusItem = TRUE; break; } if (bUpdateFocusItem) { int i; RECT rt; /* invalidate the focus rectangle */ i = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); if (i != -1) { ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS); InvalidateRect(hWnd, &rt, TRUE); } } if (wndProcListViewOrig) return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam); else return 0; } /* Text control window proc - implements close on space */ LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYUP: switch (wParam) { case VK_SPACE: case VK_RETURN: /* close on space */ PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; case VK_UP: /* scoll up */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); return 0; case VK_DOWN: /* scoll down */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); return 0; case VK_LEFT: /* scoll left */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM) NULL); return 0; case VK_RIGHT: /* scoll right */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM) NULL); return 0; } break; /* case WM_KEYUP: */ } if (editControlWndProc) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } /*----------------------------------------------------------------------------*/ char * parse_menu_str(char *dest, const char *src, size_t size) { char *p1, *p2; if (!dest || size == 0) return NULL; strncpy(dest, src, size); dest[size - 1] = '\x0'; /* replace "[ ]*\[" with "\t\[" */ p1 = p2 = strstr(dest, " ["); if (p1) { while (p1 != dest && *p1 == ' ') p1--; p1++; /* backup to space */ *p2 = '\t'; memmove(p1, p2, strlen(p2)); p1[strlen(p2)] = '\x0'; } return dest; } nethack-3.6.0/sys/wince/mhmenu.h0000664000076400007660000000102012536476415015530 0ustar paxedpaxed/* NetHack may be freely redistributed. See license for details. */ /* * $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ */ #ifndef MSWINMenuWindow_h #define MSWINMenuWindow_h #include "winMS.h" #include "config.h" #include "global.h" #define MENU_TYPE_TEXT 1 #define MENU_TYPE_MENU 2 HWND mswin_init_menu_window(int type); int mswin_menu_window_select_menu(HWND hwnd, int how, MENU_ITEM_P **); void mswin_menu_window_size(HWND hwnd, LPSIZE sz); #endif /* MSWINTextWindow_h */ nethack-3.6.0/sys/wince/mhmsg.h0000664000076400007660000000272212536476415015364 0ustar paxedpaxed/* NetHack 3.6 mhmsg.h $NHDT-Date: 1432512800 2015/05/25 00:13:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MHNethackMessages_H #define MHNethackMessages_H /* nethack messages */ #define WM_MSNH_COMMAND (WM_APP + 1) #define MSNH_MSG_ADDWND 100 #define MSNH_MSG_PUTSTR 101 #define MSNH_MSG_PRINT_GLYPH 102 #define MSNH_MSG_CLEAR_WINDOW 103 #define MSNH_MSG_CLIPAROUND 104 #define MSNH_MSG_STARTMENU 105 #define MSNH_MSG_ADDMENU 106 #define MSNH_MSG_CURSOR 107 #define MSNH_MSG_ENDMENU 108 typedef struct mswin_nhmsg_add_wnd { winid wid; } MSNHMsgAddWnd, *PMSNHMsgAddWnd; typedef struct mswin_nhmsg_putstr { int attr; const char *text; boolean append; } MSNHMsgPutstr, *PMSNHMsgPutstr; typedef struct mswin_nhmsg_print_glyph { XCHAR_P x; XCHAR_P y; int glyph; } MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph; typedef struct mswin_nhmsg_cliparound { int x; int y; } MSNHMsgClipAround, *PMSNHMsgClipAround; typedef struct mswin_nhmsg_add_menu { int glyph; const ANY_P *identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; const char *str; BOOLEAN_P presel; } MSNHMsgAddMenu, *PMSNHMsgAddMenu; typedef struct mswin_nhmsg_cursor { int x; int y; } MSNHMsgCursor, *PMSNHMsgCursor; typedef struct mswin_nhmsg_end_menu { const char *text; } MSNHMsgEndMenu, *PMSNHMsgEndMenu; #endif nethack-3.6.0/sys/wince/mhmsgwnd.c0000664000076400007660000004355412536476415016100 0ustar paxedpaxed/* NetHack 3.6 mhmsgwnd.c $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmsgwnd.h" #include "mhmsg.h" #include "mhcmd.h" #include "mhfont.h" #include "mhcolor.h" #define MSG_WRAP_TEXT #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2) #define MAX_MSG_LINES 32 #define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_LINES) #define MAXWINDOWTEXT 200 struct window_line { int attr; char text[MAXWINDOWTEXT]; }; typedef struct mswin_nethack_message_window { size_t max_text; struct window_line window_text[MAX_MSG_LINES]; int xChar; /* horizontal scrolling unit */ int yChar; /* vertical scrolling unit */ int xUpper; /* average width of uppercase letters */ int xPos; /* current horizontal scrolling position */ int yPos; /* current vertical scrolling position */ int xMax; /* maximum horizontal scrolling position */ int yMax; /* maximum vertical scrolling position */ int xPage; /* page size of horizontal scroll bar */ int lines_last_turn; /* lines added during the last turn */ int dont_care; /* flag the the user does not care if messages are lost */ } NHMessageWindow, *PNHMessageWindow; static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass"); LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM); static void register_message_window_class(); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifndef MSG_WRAP_TEXT static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #endif static COLORREF setMsgTextColor(HDC hdc, int gray); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifdef USER_SOUNDS extern void play_sound_for_message(const char *str); #endif HWND mswin_init_message_window() { static int run_once = 0; HWND ret; DWORD style; if (!run_once) { register_message_window_class(); run_once = 1; } #ifdef MSG_WRAP_TEXT style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL; #else style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL; #endif ret = CreateWindow( szMessageWindowClass, /* registered class name */ NULL, /* window name */ style, /* window style */ 0, /* horizontal position of window */ 0, /* vertical position of window */ 0, /* window width */ 0, /* window height - set it later */ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ if (!ret) panic("Cannot create message window"); return ret; } void register_message_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC) NHMessageWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szMessageWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: onCreate(hWnd, wParam, lParam); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; #ifndef MSG_WRAP_TEXT case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; #endif case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_DESTROY: { PNHMessageWindow data; data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); } break; case WM_SIZE: { SCROLLINFO si; int xNewSize; int yNewSize; PNHMessageWindow data; data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); xNewSize = LOWORD(lParam); yNewSize = HIWORD(lParam); if (xNewSize > 0 || yNewSize > 0) { #ifndef MSG_WRAP_TEXT data->xPage = xNewSize / data->xChar; data->xMax = max(0, (int) (1 + data->max_text - data->xPage)); data->xPos = min(data->xPos, data->xMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = data->max_text; si.nPage = data->xPage; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); #endif data->yMax = MSG_LINES - 1; data->yPos = min(data->yPos, data->yMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = MSG_VISIBLE_LINES; si.nMax = data->yMax + MSG_VISIBLE_LINES - 1; si.nPage = MSG_VISIBLE_LINES; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; SCROLLINFO si; char *p; if (msg_data->append) { strncat(data->window_text[MSG_LINES - 1].text, msg_data->text, MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES - 1].text)); } else { /* check if the string is empty */ for (p = data->window_text[MSG_LINES - 1].text; *p && isspace(*p); p++) ; if (*p) { /* last string is not empty - scroll up */ memmove(&data->window_text[0], &data->window_text[1], (MSG_LINES - 1) * sizeof(data->window_text[0])); } /* append new text to the end of the array */ data->window_text[MSG_LINES - 1].attr = msg_data->attr; strncpy(data->window_text[MSG_LINES - 1].text, msg_data->text, MAXWINDOWTEXT); } /* reset V-scroll position to display new text */ data->yPos = data->yMax; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); /* deal with overflows */ data->lines_last_turn++; if (!data->dont_care && data->lines_last_turn >= MSG_LINES - 2) { char c; BOOL done; /* append "--More--" to the message window text (cannot call putstr here - infinite recursion) */ memmove(&data->window_text[0], &data->window_text[1], (MSG_LINES - 1) * sizeof(data->window_text[0])); data->window_text[MSG_LINES - 1].attr = ATR_NONE; strncpy(data->window_text[MSG_LINES - 1].text, "--More--", MAXWINDOWTEXT); /* update window content */ InvalidateRect(hWnd, NULL, TRUE); #if defined(WIN_CE_SMARTPHONE) NHSPhoneSetKeypadFromString("\033- <>"); #endif done = FALSE; while (!done) { int x, y, mod; c = mswin_nh_poskey(&x, &y, &mod); switch (c) { /* ESC indicates that we can safely discard any further * messages during this turn */ case '\033': data->dont_care = 1; done = TRUE; break; case '<': SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); break; case '>': SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); break; /* continue scrolling on any key */ default: data->lines_last_turn = 0; done = TRUE; break; } } #if defined(WIN_CE_SMARTPHONE) NHSPhoneSetKeypadDefault(); #endif /* remove "--More--" from the message window text */ data->window_text[MSG_LINES - 1].attr = ATR_NONE; strncpy(data->window_text[MSG_LINES - 1].text, " ", MAXWINDOWTEXT); } /* update window content */ InvalidateRect(hWnd, NULL, TRUE); #ifdef USER_SOUNDS play_sound_for_message(msg_data->text); #endif } break; case MSNH_MSG_CLEAR_WINDOW: data->lines_last_turn = 0; data->dont_care = 0; break; } } void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int yInc; /* get window data */ data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_POS; GetScrollInfo(hWnd, SB_VERT, &si); switch (LOWORD(wParam)) { // User clicked the shaft above the scroll box. case SB_PAGEUP: yInc = -(int) si.nPage; break; // User clicked the shaft below the scroll box. case SB_PAGEDOWN: yInc = si.nPage; break; // User clicked the top arrow. case SB_LINEUP: yInc = -1; break; // User clicked the bottom arrow. case SB_LINEDOWN: yInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: yInc = HIWORD(wParam) - data->yPos; break; default: yInc = 0; } // If applying the vertical scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. UpdateWindow // sends the WM_PAINT message. if (yInc = max(MSG_VISIBLE_LINES - data->yPos, min(yInc, data->yMax - data->yPos))) { data->yPos += yInc; /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); */ InvalidateRect(hWnd, NULL, TRUE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); UpdateWindow(hWnd); } } #ifndef MSG_WRAP_TEXT void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int xInc; /* get window data */ data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE; GetScrollInfo(hWnd, SB_HORZ, &si); switch (LOWORD(wParam)) { // User clicked shaft left of the scroll box. case SB_PAGEUP: xInc = -(int) si.nPage; break; // User clicked shaft right of the scroll box. case SB_PAGEDOWN: xInc = si.nPage; break; // User clicked the left arrow. case SB_LINEUP: xInc = -1; break; // User clicked the right arrow. case SB_LINEDOWN: xInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: xInc = HIWORD(wParam) - data->xPos; break; default: xInc = 0; } // If applying the horizontal scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. if (xInc = max(-data->xPos, min(xInc, data->xMax - data->xPos))) { data->xPos += xInc; ScrollWindowEx(hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); UpdateWindow(hWnd); } } #endif // MSG_WRAP_TEXT COLORREF setMsgTextColor(HDC hdc, int gray) { COLORREF fg, color1, color2; if (gray) { color1 = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG); color2 = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG); /* Make a "gray" color by taking the average of the individual R,G,B components of two colors. Thanks to Jonathan del Strother */ fg = RGB((GetRValue(color1) + GetRValue(color2)) / 2, (GetGValue(color1) + GetGValue(color2)) / 2, (GetBValue(color1) + GetBValue(color2)) / 2); } else { fg = mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG); } return SetTextColor(hdc, fg); } void onPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; PNHMessageWindow data; RECT client_rt, draw_rt; int FirstLine, LastLine; int i, x, y; HGDIOBJ oldFont; TCHAR wbuf[MAXWINDOWTEXT + 2]; size_t wlen; COLORREF OldBg, OldFg; hdc = BeginPaint(hWnd, &ps); OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG)); OldFg = setMsgTextColor(hdc, 0); data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); GetClientRect(hWnd, &client_rt); if (!IsRectEmpty(&ps.rcPaint)) { FirstLine = max( 0, data->yPos - (client_rt.bottom - ps.rcPaint.top) / data->yChar + 1); LastLine = min(MSG_LINES - 1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar); y = min(ps.rcPaint.bottom, client_rt.bottom - 2); for (i = LastLine; i >= FirstLine; i--) { if (i == MSG_LINES - 1) { x = data->xChar * (2 - data->xPos); } else { x = data->xChar * (4 - data->xPos); } if (strlen(data->window_text[i].text) > 0) { /* convert to UNICODE */ NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf)); wlen = _tcslen(wbuf); /* calculate text height */ draw_rt.left = x; draw_rt.right = client_rt.right; draw_rt.top = y - data->yChar; draw_rt.bottom = y; oldFont = SelectObject( hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE)); setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn)); #ifdef MSG_WRAP_TEXT DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); draw_rt.top = y - (draw_rt.bottom - draw_rt.top); draw_rt.bottom = y; DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK); #else DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX); #endif SelectObject(hdc, oldFont); y -= draw_rt.bottom - draw_rt.top; } else { y -= data->yChar; } } } SetTextColor(hdc, OldFg); SetBkColor(hdc, OldBg); EndPaint(hWnd, &ps); } void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { HDC hdc; TEXTMETRIC tm; PNHMessageWindow data; HGDIOBJ saveFont; /* set window data */ data = (PNHMessageWindow) malloc(sizeof(NHMessageWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHMessageWindow)); data->max_text = MAXWINDOWTEXT; SetWindowLong(hWnd, GWL_USERDATA, (LONG) data); /* Get the handle to the client area's device context. */ hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); /* Extract font dimensions from the text metrics. */ GetTextMetrics(hdc, &tm); data->xChar = tm.tmAveCharWidth; data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar / 2; data->yChar = tm.tmHeight + tm.tmExternalLeading; data->xPage = 1; /* Free the device context. */ SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); /* create command pad (keyboard emulator) */ if (!GetNHApp()->hCmdWnd) GetNHApp()->hCmdWnd = mswin_init_command_window(); } void mswin_message_window_size(HWND hWnd, LPSIZE sz) { PNHMessageWindow data; RECT rt, client_rt; GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data) { /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); sz->cy = sz->cy - (client_rt.bottom - client_rt.top) + data->yChar * MSG_VISIBLE_LINES + 4; } } nethack-3.6.0/sys/wince/mhmsgwnd.h0000664000076400007660000000073212536476415016074 0ustar paxedpaxed/* NetHack 3.6 mhmsgwnd.h $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMessageWindow_h #define MSWINMessageWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_message_window(); void mswin_message_window_size(HWND hWnd, LPSIZE sz); #endif /* MSWINMessageWindow_h */ nethack-3.6.0/sys/wince/mhrip.c0000664000076400007660000000067112536476415015364 0ustar paxedpaxed/* NetHack 3.6 mhrip.c $NHDT-Date: 1432512801 2015/05/25 00:13:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhrip.h" #include "mhtext.h" HWND mswin_init_RIP_window() { return mswin_init_text_window(); } void mswin_display_RIP_window(HWND hWnd) { mswin_display_text_window(hWnd); } nethack-3.6.0/sys/wince/mhrip.h0000664000076400007660000000067412536476415015374 0ustar paxedpaxed/* NetHack 3.6 mhrip.h $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINRIPWindow_h #define MSWINRIPWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_RIP_window(); void mswin_display_RIP_window(HWND hwnd); #endif /* MSWINRIPWindow_h */ nethack-3.6.0/sys/wince/mhstatus.c0000664000076400007660000002004212536476415016107 0ustar paxedpaxed/* NetHack 3.6 mhstatus.c $NHDT-Date: 1432512798 2015/05/25 00:13:18 $ $NHDT-Branch: master $:$NHDT-Revision: 1.17 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhstatus.h" #include "mhmsg.h" #include "mhfont.h" #include "mhcolor.h" #define MAXWINDOWTEXT 255 #define NHSTAT_LINES_2 2 #define NHSTAT_LINES_4 4 typedef struct mswin_nethack_status_window { int nhstat_format; char window_text[MAXWINDOWTEXT]; } NHStatusWindow, *PNHStatusWindow; static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass"); LRESULT CALLBACK StatusWndProc(HWND, UINT, WPARAM, LPARAM); static void register_status_window_class(void); static void FormatStatusString(char *text, int format); HWND mswin_init_status_window() { static int run_once = 0; HWND ret; NHStatusWindow *data; if (!run_once) { register_status_window_class(); run_once = 1; } ret = CreateWindow(szStatusWindowClass, NULL, WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS, 0, /* x position */ 0, /* y position */ 0, /* x-size - we will set it later */ 0, /* y-size - we will set it later */ GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL); if (!ret) panic("Cannot create status window"); EnableWindow(ret, FALSE); data = (PNHStatusWindow) malloc(sizeof(NHStatusWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHStatusWindow)); data->nhstat_format = NHSTAT_LINES_4; SetWindowLong(ret, GWL_USERDATA, (LONG) data); return ret; } void register_status_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC) StatusWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = mswin_get_brush(NHW_STATUS, MSWIN_COLOR_BG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szStatusWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rt; PAINTSTRUCT ps; HDC hdc; PNHStatusWindow data; data = (PNHStatusWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_MSNH_COMMAND: { switch (wParam) { case MSNH_MSG_PUTSTR: case MSNH_MSG_CLEAR_WINDOW: ZeroMemory(data->window_text, sizeof(data->window_text)); FormatStatusString(data->window_text, data->nhstat_format); break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam; if (msg_data->y == 0) { InvalidateRect(hWnd, NULL, TRUE); } } break; } } break; case WM_PAINT: { HGDIOBJ oldFont; TCHAR wbuf[MAXWINDOWTEXT]; COLORREF OldBg, OldFg; hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); oldFont = SelectObject( hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); OldBg = SetBkColor(hdc, mswin_get_color(NHW_STATUS, MSWIN_COLOR_BG)); OldFg = SetTextColor(hdc, mswin_get_color(NHW_STATUS, MSWIN_COLOR_FG)); DrawText(hdc, NH_A2W(data->window_text, wbuf, MAXWINDOWTEXT), strlen(data->window_text), &rt, DT_LEFT | DT_NOPREFIX); SetTextColor(hdc, OldFg); SetBkColor(hdc, OldBg); SelectObject(hdc, oldFont); EndPaint(hWnd, &ps); } break; case WM_DESTROY: free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void mswin_status_window_size(HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHStatusWindow data; RECT rt; GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; data = (PNHStatusWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data) { hdc = GetDC(hWnd); saveFont = SelectObject( hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); /* see if the status window can fit 80 characters per line */ if ((80 * tm.tmMaxCharWidth) >= sz->cx) data->nhstat_format = NHSTAT_LINES_4; else data->nhstat_format = NHSTAT_LINES_2; /* set height of the status box */ sz->cy = tm.tmHeight * data->nhstat_format; SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); } } extern const char *hu_stat[]; /* defined in eat.c */ extern const char *enc_stat[]; /* define in botl.c */ void FormatStatusString(char *text, int format) { register char *nb; int hp, hpmax; int cap = near_capacity(); Strcpy(text, plname); if ('a' <= text[0] && text[0] <= 'z') text[0] += 'A' - 'a'; text[10] = 0; Sprintf(nb = eos(text), " the "); if (Upolyd) { char mbot[BUFSZ]; int k = 0; Strcpy(mbot, mons[u.umonnum].mname); while (mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') mbot[k] += 'A' - 'a'; k++; } Sprintf(nb = eos(nb), mbot); } else Sprintf(nb = eos(nb), rank_of(u.ulevel, Role_switch, flags.female)); if (format == NHSTAT_LINES_4) Sprintf(nb = eos(nb), "\r\n"); if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) Sprintf(nb = eos(nb), "St:%2d ", ACURR(A_STR) - 100); else if (ACURR(A_STR) < STR18(100)) Sprintf(nb = eos(nb), "St:18/%02d ", ACURR(A_STR) - 18); else Sprintf(nb = eos(nb), "St:18/** "); } else Sprintf(nb = eos(nb), "St:%-1d ", ACURR(A_STR)); Sprintf(nb = eos(nb), "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d", ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA)); Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? " Chaotic" : (u.ualign.type == A_NEUTRAL) ? " Neutral" : " Lawful"); #ifdef SCORE_ON_BOTL if (flags.showscore) Sprintf(nb = eos(nb), " S:%ld", botl_score()); #endif if (format == NHSTAT_LINES_4 || format == NHSTAT_LINES_2) strcat(text, "\r\n"); /* third line */ hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; if (hp < 0) hp = 0; (void) describe_level(nb = eos(nb)); Sprintf(nb = eos(nb), "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", showsyms[COIN_CLASS + SYM_OFF_O], money_cnt(invent), hp, hpmax, u.uen, u.uenmax, u.uac); if (Upolyd) Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel); else if (flags.showexp) Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel, u.uexp); else Sprintf(nb = eos(nb), " Exp:%u", u.ulevel); if (format == NHSTAT_LINES_4) strcat(text, "\r\n"); else strcat(text, " "); /* forth line */ if (flags.time) Sprintf(nb = eos(nb), "T:%ld ", moves); if (strcmp(hu_stat[u.uhs], " ")) { Strcat(text, hu_stat[u.uhs]); Sprintf(nb = eos(nb), " "); } if (Confusion) Sprintf(nb = eos(nb), "Conf"); if (Sick) { if (u.usick_type & SICK_VOMITABLE) Sprintf(nb = eos(nb), " FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) Sprintf(nb = eos(nb), " Ill"); } if (Blind) Sprintf(nb = eos(nb), " Blind"); if (Stunned) Sprintf(nb = eos(nb), " Stun"); if (Hallucination) Sprintf(nb = eos(nb), " Hallu"); if (Slimed) Sprintf(nb = eos(nb), " Slime"); if (cap > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); } nethack-3.6.0/sys/wince/mhstatus.h0000664000076400007660000000072612536476415016123 0ustar paxedpaxed/* NetHack 3.6 mhstatus.h $NHDT-Date: 1432512800 2015/05/25 00:13:20 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINStatusWindow_h #define MSWINStatusWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_status_window(); void mswin_status_window_size(HWND hWnd, LPSIZE sz); #endif /* MSWINStatusWindow_h */ nethack-3.6.0/sys/wince/mhtext.c0000664000076400007660000002145312536476415015557 0ustar paxedpaxed/* NetHack 3.6 mhtext.c $NHDT-Date: 1432512802 2015/05/25 00:13:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhtext.h" #include "mhmsg.h" #include "mhfont.h" #include "mhcolor.h" #include "mhtxtbuf.h" typedef struct mswin_nethack_text_window { PNHTextBuffer window_text; int done; } NHTextWindow, *PNHTextWindow; static WNDPROC editControlWndProc = NULL; LRESULT CALLBACK TextWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHTextControlWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutText(HWND hwnd); static void ToggleWrapStatus(HWND hDlg, BOOL bWrap); HWND mswin_init_text_window() { HWND ret; PNHTextWindow data; ret = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHTEXT), GetNHApp()->hMainWnd, TextWndProc); if (!ret) panic("Cannot create text window"); data = (PNHTextWindow) malloc(sizeof(NHTextWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHTextWindow)); data->window_text = mswin_init_text_buffer( program_state.gameover ? FALSE : GetNHApp()->bWrapText); SetWindowLong(ret, GWL_USERDATA, (LONG) data); return ret; } void mswin_display_text_window(HWND hWnd) { PNHTextWindow data; data = (PNHTextWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data) { ToggleWrapStatus(hWnd, mswin_get_text_wrap(data->window_text)); data->done = 0; mswin_popup_display(hWnd, &data->done); mswin_popup_destroy(hWnd); } } LRESULT CALLBACK TextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HWND control; HDC hdc; PNHTextWindow data; data = (PNHTextWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: /* set text control font */ control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); if (!control) { panic("cannot get text view window"); } hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(control, hdc); #if defined(WIN_CE_SMARTPHONE) /* special initialization for SmartPhone dialogs */ NHSPhoneDialogSetup(hWnd, IDC_SPHONE_TEXTDIALOGBAR, FALSE, GetNHApp()->bFullScreen); #endif /* subclass edit control */ editControlWndProc = (WNDPROC) GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG) NHTextControlWndProc); SetFocus(control); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: LayoutText(hWnd); return FALSE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: data->done = 1; return TRUE; case IDC_TEXT_TOGGLE_WRAP: ToggleWrapStatus(hWnd, !mswin_get_text_wrap(data->window_text)); return TRUE; } break; case WM_CTLCOLORBTN: case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if (hwndEdit == GetDlgItem(hWnd, IDC_TEXT_CONTROL)) { SetBkColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG)); SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG)); return (BOOL) mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG); } } return FALSE; case WM_DESTROY: if (data) { mswin_free_text_buffer(data->window_text); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG) 0); } break; } return FALSE; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHTextWindow data; data = (PNHTextWindow) GetWindowLong(hWnd, GWL_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; mswin_add_text(data->window_text, msg_data->attr, msg_data->text); break; } } } void ToggleWrapStatus(HWND hDlg, BOOL bWrap) { DWORD styles; PNHTextWindow data; HWND control; TCHAR wbuf[BUFSZ]; data = (PNHTextWindow) GetWindowLong(hDlg, GWL_USERDATA); control = GetDlgItem(hDlg, IDC_TEXT_CONTROL); if (!control) { panic("cannot get text view window"); } /* set horizontal scrollbar status */ styles = GetWindowLong(control, GWL_STYLE); if (styles) { SetWindowLong(control, GWL_STYLE, (bWrap ? (styles & (~WS_HSCROLL)) : (styles | WS_HSCROLL))); SetWindowPos(control, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE); } /* set text wrap mode */ mswin_set_text_wrap(data->window_text, bWrap); mswin_render_text(data->window_text, control); /* change button status */ ZeroMemory(wbuf, sizeof(wbuf)); if (!LoadString(GetNHApp()->hApp, (bWrap ? IDS_TEXT_UNWRAP : IDS_TEXT_WRAP), wbuf, BUFSZ)) { panic("cannot load text window strings"); } #if defined(WIN_CE_SMARTPHONE) { TBBUTTONINFO tbbi; ZeroMemory(&tbbi, sizeof(tbbi)); tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_TEXT; tbbi.pszText = wbuf; if (!SendMessage(SHFindMenuBar(hDlg), TB_SETBUTTONINFO, IDC_TEXT_TOGGLE_WRAP, (LPARAM) &tbbi)) { error("Cannot update IDC_TEXT_TOGGLE_WRAP menu item."); } } #else SendDlgItemMessage(hDlg, IDC_TEXT_TOGGLE_WRAP, WM_SETTEXT, (WPARAM) 0, (LPARAM) wbuf); #endif } void LayoutText(HWND hWnd) { HWND btn_ok, btn_wrap; HWND text; RECT clrt, rt; POINT pt_elem, pt_ok, pt_wrap; SIZE sz_elem, sz_ok, sz_wrap; text = GetDlgItem(hWnd, IDC_TEXT_CONTROL); btn_ok = GetDlgItem(hWnd, IDOK); btn_wrap = GetDlgItem(hWnd, IDC_TEXT_TOGGLE_WRAP); /* get window coordinates */ GetClientRect(hWnd, &clrt); /* set window placements */ if (IsWindow(btn_ok)) { GetWindowRect(btn_ok, &rt); sz_ok.cx = (clrt.right - clrt.left) / 2; sz_ok.cy = rt.bottom - rt.top; pt_ok.x = clrt.left; pt_ok.y = clrt.bottom - sz_ok.cy; MoveWindow(btn_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE); sz_wrap.cx = (clrt.right - clrt.left) / 2; sz_wrap.cy = rt.bottom - rt.top; pt_wrap.x = clrt.left + sz_ok.cx; pt_wrap.y = clrt.bottom - sz_ok.cy; MoveWindow(btn_wrap, pt_wrap.x, pt_wrap.y, sz_wrap.cx, sz_wrap.cy, TRUE); pt_elem.x = clrt.left; pt_elem.y = clrt.top; sz_elem.cx = clrt.right - clrt.left; sz_elem.cy = pt_ok.y; MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE); } else { pt_elem.x = clrt.left; pt_elem.y = clrt.top; sz_elem.cx = clrt.right - clrt.left; sz_elem.cy = clrt.bottom - clrt.top; MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE); } } /* Text control window proc - implements close on space and scrolling on * arrows */ LRESULT CALLBACK NHTextControlWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { /* tell Windows not to process arrow keys (we want them) */ case WM_GETDLGCODE: return DLGC_WANTARROWS; case WM_KEYDOWN: switch (wParam) { case VK_SPACE: case VK_RETURN: /* close on space */ PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; case VK_UP: /* scoll up */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); return 0; case VK_DOWN: /* scoll down */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); return 0; case VK_LEFT: /* scoll left */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM) NULL); return 0; case VK_RIGHT: /* scoll right */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM) NULL); return 0; } break; /* case WM_KEYDOWN: */ } if (editControlWndProc) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } nethack-3.6.0/sys/wince/mhtext.h0000664000076400007660000000070112536476415015555 0ustar paxedpaxed/* NetHack 3.6 mhtext.h $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINTextWindow_h #define MSWINTextWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_text_window(); void mswin_display_text_window(HWND hwnd); #endif /* MSWINTextWindow_h */ nethack-3.6.0/sys/wince/mhtxtbuf.c0000664000076400007660000002246512536476415016113 0ustar paxedpaxed/* NetHack 3.6 mhtxtbuf.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2003 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "mhtxtbuf.h" /* Collect Nethack text messages and render text into edit box. Wrap text if necessary. Recognize formatted lines as having more that 4 consecutive. spaces inside the string. Strip leading and trailing spaces. Always break at the original line end (do not merge text that comes from NetHack engine) */ /*----------------------------------------------------------------*/ #define NHTEXT_BUFFER_INCREMENT 10 /*----------------------------------------------------------------*/ struct text_buffer_line { int attr; short beg_padding; short end_padding; BOOL formatted; char *text; }; /*----------------------------------------------------------------*/ typedef struct mswin_nethack_text_buffer { BOOL b_wrap_text; int n_size; int n_used; struct text_buffer_line *text_buffer_line; } NHTextBuffer, *PNHTextBuffer; /*----------------------------------------------------------------*/ #define NHTextLine(pb, i) ((pb)->text_buffer_line[(i)]) static TCHAR *nh_append(TCHAR *s, int *size, const char *ap); /*----------------------------------------------------------------*/ PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text) { PNHTextBuffer pb = (PNHTextBuffer) malloc(sizeof(NHTextBuffer)); if (!pb) panic("Out of memory"); ZeroMemory(pb, sizeof(NHTextBuffer)); pb->b_wrap_text = wrap_text; pb->n_size = 0; pb->n_used = 0; pb->text_buffer_line = NULL; return pb; } /*----------------------------------------------------------------*/ void mswin_free_text_buffer(PNHTextBuffer pb) { int i; if (!pb) return; for (i = 0; i < pb->n_used; i++) { free(pb->text_buffer_line[i].text); } free(pb->text_buffer_line); free(pb); } /*----------------------------------------------------------------*/ void mswin_add_text(PNHTextBuffer pb, int attr, const char *text) { char *p; struct text_buffer_line *new_line; /* grow buffer */ if (pb->n_used >= pb->n_size) { pb->n_size += NHTEXT_BUFFER_INCREMENT; pb->text_buffer_line = (struct text_buffer_line *) realloc( pb->text_buffer_line, pb->n_size * sizeof(struct text_buffer_line)); if (!pb->text_buffer_line) panic("Memory allocation error"); } /* analyze the new line of text */ new_line = &NHTextLine(pb, pb->n_used); new_line->attr = attr; new_line->beg_padding = 0; new_line->text = strdup(text); for (p = new_line->text; *p && isspace(*p); p++) { new_line->beg_padding++; } if (*p) { memmove(new_line->text, new_line->text + new_line->beg_padding, strlen(new_line->text) - new_line->beg_padding + 1); for (p = new_line->text + strlen(new_line->text); p >= new_line->text && isspace(*p); p--) { new_line->end_padding++; *p = 0; } /* if there are 3 (or more) consecutive spaces inside the string consider it formatted */ new_line->formatted = (strstr(new_line->text, " ") != NULL) || (new_line->beg_padding > 8); } else { new_line->end_padding = 0; new_line->text[0] = 0; new_line->formatted = FALSE; } pb->n_used++; } /*----------------------------------------------------------------*/ void mswin_set_text_wrap(PNHTextBuffer pb, BOOL wrap_text) { pb->b_wrap_text = wrap_text; } /*----------------------------------------------------------------*/ BOOL mswin_get_text_wrap(PNHTextBuffer pb) { return pb->b_wrap_text; } /*----------------------------------------------------------------*/ static TCHAR * nh_append(TCHAR *s, int *size, const char *ap) { int tlen, tnewlen; if (!(ap && *ap)) return s; /* append the calculated line to the text buffer */ tlen = s ? _tcslen(s) : 0; tnewlen = tlen + strlen(ap); if (tnewlen >= *size) { *size = max(tnewlen, *size + BUFSZ); s = (TCHAR *) realloc(s, *size * sizeof(TCHAR)); if (!s) panic("Out of memory"); ZeroMemory(s + tlen, (*size - tlen) * sizeof(TCHAR)); } if (strcmp(ap, "\r\n") == 0) { _tcscat(s, TEXT("\r\n")); } else { NH_A2W(ap, s + tlen, strlen(ap)); s[tnewlen] = 0; } return s; } /*----------------------------------------------------------------*/ void mswin_render_text(PNHTextBuffer pb, HWND edit_control) { RECT rt_client; /* boundaries of the client area of the edit control */ SIZE size_text; /* size of the edit control */ RECT rt_text; /* calculated text rectangle for the visible line */ char buf[BUFSZ]; /* buffer for the visible line */ TCHAR tbuf[BUFSZ]; /* temp buffer for DrawText */ TCHAR *pText = NULL; /* resulting text (formatted) */ int pTextSize = 0; /* resulting text size */ char *p_cur = NULL; /* current position in the NHTextBuffer->text_buffer_line->text */ char *p_buf_cur = NULL; /* current position in the visible line buffer */ int i; HDC hdcEdit; /* device context for the edit control */ HFONT hFont, hOldFont; /* edit control font */ GetClientRect(edit_control, &rt_client); size_text.cx = rt_client.right - rt_client.left; size_text.cy = rt_client.bottom - rt_client.top; size_text.cx -= GetSystemMetrics(SM_CXVSCROLL); /* add a slight right margin - the text looks better that way */ hdcEdit = GetDC(edit_control); hFont = (HFONT) SendMessage(edit_control, WM_GETFONT, 0, 0); if (hFont) hOldFont = SelectObject(hdcEdit, hFont); /* loop through each line (outer loop) and wrap it around (inner loop) */ ZeroMemory(buf, sizeof(buf)); p_buf_cur = buf; for (i = 0; i < pb->n_used; i++) { if (pb->b_wrap_text) { p_cur = NHTextLine(pb, i).text; /* insert an line break for the empty string */ if (!NHTextLine(pb, i).text[0]) { pText = nh_append(pText, &pTextSize, "\r\n"); continue; } /* add margin to the "formatted" line of text */ if (NHTextLine(pb, i).formatted) { strcpy(buf, " "); p_buf_cur += 3; } /* scroll thourgh the current line of text and wrap it so it fits to width of the edit control */ while (*p_cur) { char *p_word_pos = p_buf_cur; /* copy one word into the buffer */ while (*p_cur && isspace(*p_cur)) if (p_buf_cur != buf) *p_buf_cur++ = *p_cur++; else p_cur++; while (*p_cur && !isspace(*p_cur)) *p_buf_cur++ = *p_cur++; /* check if it fits */ SetRect(&rt_text, 0, 0, size_text.cx, size_text.cy); DrawText(hdcEdit, NH_A2W(buf, tbuf, p_buf_cur - buf), p_buf_cur - buf, &rt_text, DT_CALCRECT | DT_LEFT | DT_SINGLELINE | DT_NOCLIP); if ((rt_text.right - rt_text.left) >= size_text.cx) { /* Backtrack. Only backtrack if the last word caused the overflow - do not backtrack if the entire current line does not fit the visible area. Otherwise it is a infinite loop. */ if (p_word_pos > buf) { p_cur -= (p_buf_cur - p_word_pos); p_buf_cur = p_word_pos; } *p_buf_cur = 0; /* break the line */ /* append the calculated line to the text buffer */ pText = nh_append(pText, &pTextSize, buf); pText = nh_append(pText, &pTextSize, "\r\n"); ZeroMemory(buf, sizeof(buf)); p_buf_cur = buf; } } /* always break the line at the end of the buffer text */ if (p_buf_cur != buf) { /* flush the current buffrer */ *p_buf_cur = 0; /* break the line */ pText = nh_append(pText, &pTextSize, buf); pText = nh_append(pText, &pTextSize, "\r\n"); ZeroMemory(buf, sizeof(buf)); p_buf_cur = buf; } } else { /* do not wrap text */ int j; for (j = 0; j < NHTextLine(pb, i).beg_padding; j++) pText = nh_append(pText, &pTextSize, " "); pText = nh_append(pText, &pTextSize, NHTextLine(pb, i).text); pText = nh_append(pText, &pTextSize, "\r\n"); } } /* cleanup */ if (hFont) SelectObject(hdcEdit, hOldFont); ReleaseDC(edit_control, hdcEdit); /* update edit control text */ if (pText) { SendMessage(edit_control, EM_FMTLINES, 1, 0); SetWindowText(edit_control, pText); free(pText); } } /*----------------------------------------------------------------*/ nethack-3.6.0/sys/wince/mhtxtbuf.h0000664000076400007660000000132712536476415016112 0ustar paxedpaxed/* NetHack 3.6 mhtxtbuf.h $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINTextBuffer_h #define MSWINTextBuffer_h #include "winMS.h" typedef struct mswin_nethack_text_buffer *PNHTextBuffer; PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text); void mswin_free_text_buffer(PNHTextBuffer pb); void mswin_add_text(PNHTextBuffer pb, int attr, const char *text); void mswin_set_text_wrap(PNHTextBuffer pb, BOOL wrap_text); BOOL mswin_get_text_wrap(PNHTextBuffer pb); void mswin_render_text(PNHTextBuffer pb, HWND edit_control); #endif /* MSWINTextBuffer_h */ nethack-3.6.0/sys/wince/mswproc.c0000664000076400007660000020615112536476415015740 0ustar paxedpaxed/* NetHack 3.6 mswproc.c $NHDT-Date: 1433806606 2015/06/08 23:36:46 $ $NHDT-Branch: master $:$NHDT-Revision: 1.60 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* * This file implements the interface between the window port specific * code in the mswin port and the rest of the nethack game engine. */ #include "hack.h" #include "dlb.h" #include "winMS.h" #include "mhmap.h" #include "mhstatus.h" #include "mhtext.h" #include "mhmsgwnd.h" #include "mhmenu.h" #include "mhmsg.h" #include "mhcmd.h" #include "mhinput.h" #include "mhaskyn.h" #include "mhdlg.h" #include "mhrip.h" #include "mhmain.h" #include "mhfont.h" #include "mhcolor.h" #define LLEN 128 #ifdef _DEBUG extern void logDebug(const char *fmt, ...); #else void logDebug(const char *fmt, ...) { } #endif static void mswin_main_loop(); static BOOL initMapTiles(void); static void prompt_for_player_selection(void); /* Interface definition, for windows.c */ struct window_procs mswin_procs = { "MSWIN", WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION, WC2_FULLSCREEN | WC2_SOFTKEYBOARD | WC2_WRAPTEXT, mswin_init_nhwindows, mswin_player_selection, mswin_askname, mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows, mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow, mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr, genl_putmixed, mswin_display_file, mswin_start_menu, mswin_add_menu, mswin_end_menu, mswin_select_menu, genl_message_menu, /* no need for X-specific handling */ mswin_update_inventory, mswin_mark_synch, mswin_wait_synch, #ifdef CLIPPING mswin_cliparound, #endif #ifdef POSITIONBAR donull, #endif mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch, mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function, mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ mswin, mswin_change_background, #endif /* other defs that really should go away (they're tty specific) */ mswin_start_screen, mswin_end_screen, mswin_outrip, mswin_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif genl_can_suspend_no, }; /* init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean */ void mswin_init_nhwindows(int *argc, char **argv) { HWND hWnd; logDebug("mswin_init_nhwindows()\n"); #ifdef _DEBUG { /* truncate trace file */ FILE *dfp = fopen("nhtrace.log", "w"); fclose(dfp); } #endif /* intialize input subsystem */ mswin_nh_input_init(); /* read registry settings */ mswin_read_reg(); /* set it to WIN_ERR so we can detect attempts to use this ID before it is inialized */ WIN_MAP = WIN_ERR; /* check default values */ if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) iflags.wc_fontsiz_status = NHFONT_STATUS_DEFAULT_SIZE; if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; if (iflags.wc_align_message == 0) iflags.wc_align_message = ALIGN_BOTTOM; if (iflags.wc_align_status == 0) iflags.wc_align_status = ALIGN_TOP; if (iflags.wc_scroll_margin == 0) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; if (iflags.wc_tile_width == 0) iflags.wc_tile_width = TILE_X; if (iflags.wc_tile_height == 0) iflags.wc_tile_height = TILE_Y; if (iflags.wc_vary_msgcount == 0) iflags.wc_vary_msgcount = 3; /* force tabs in menus */ iflags.menu_tab_sep = 1; /* force toptenwin to be true. toptenwin is the option that decides * whether to * write output to a window or stdout. stdout doesn't make sense on * Windows * non-console applications */ iflags.toptenwin = 1; set_option_mod_status("toptenwin", SET_IN_FILE); /* initialize map tiles bitmap */ initMapTiles(); /* set tile-related options to readonly */ set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE, DISP_IN_GAME); /* init color table */ mswin_init_color_table(); /* set font-related options to change in the game */ set_wc_option_mod_status( WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, SET_IN_GAME); /* WC2 options */ set_wc2_option_mod_status(WC2_FULLSCREEN | WC2_SOFTKEYBOARD, SET_IN_FILE); GetNHApp()->bFullScreen = iflags.wc2_fullscreen; GetNHApp()->bUseSIP = iflags.wc2_softkeyboard; set_wc2_option_mod_status(WC2_WRAPTEXT, SET_IN_GAME); GetNHApp()->bWrapText = iflags.wc2_wraptext; /* create the main nethack window */ hWnd = mswin_init_main_window(); if (!hWnd) panic("Cannot create the main window."); ShowWindow(hWnd, GetNHApp()->nCmdShow); UpdateWindow(hWnd); GetNHApp()->hMainWnd = hWnd; /* set Full screen if requested */ mswin_set_fullscreen(GetNHApp()->bFullScreen); /* let nethack code know that the window subsystem is ready */ iflags.window_inited = TRUE; } /* Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. */ void mswin_player_selection(void) { logDebug("mswin_player_selection()\n"); #if defined(WIN_CE_SMARTPHONE) /* SmartPhone does not supprt combo-boxes therefor we cannot use dialog for player selection */ prompt_for_player_selection(); #else if (iflags.wc_player_selection == VIA_DIALOG) { int nRole; /* pick player type randomly (use pre-selected * role/race/gender/alignment) */ if (flags.randomall) { if (flags.initrole < 0) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { raw_print("Incompatible role!"); flags.initrole = randrole(); } } if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { raw_print("Incompatible race!"); flags.initrace = randrace(flags.initrole); } } if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { raw_print("Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { raw_print("Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } } else { /* select a role */ if (mswin_player_selection_window(&nRole) == IDCANCEL) { bail(0); } } } else { /* iflags.wc_player_selection == VIA_PROMPTS */ prompt_for_player_selection(); } #endif /* defined(WIN_CE_SMARTPHONE) */ } void prompt_for_player_selection(void) { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; int box_result; TCHAR wbuf[BUFSZ]; logDebug("prompt_for_player_selection()\n"); /* prevent an unnecessary prompt */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { /* int echoline; */ char *prompt = build_plselection_prompt( pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* tty_putstr(BASE_WINDOW, 0, ""); */ /* echoline = wins[BASE_WINDOW]->cury; */ box_result = MessageBox(NULL, NH_A2W(prompt, wbuf, BUFSZ), TEXT("NetHack for Windows"), #if defined(WIN_CE_SMARTPHONE) MB_YESNO | MB_DEFBUTTON1 #else MB_YESNOCANCEL | MB_DEFBUTTON1 #endif ); pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033'; /* tty_putstr(BASE_WINDOW, 0, prompt); */ do { /* pick4u = lowc(readchar()); */ if (index(quitchars, pick4u)) pick4u = 'y'; } while (!index(ynqchars, pick4u)); if ((int) strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, * pick4u); */ /* tty_putstr(BASE_WINDOW, 0, ""); */ } else /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ /* tty_clear_nhwindow(BASE_WINDOW) */; if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); bail((char *) 0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { char rolenamebuf[QBUFSZ]; /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */ flags.initrole = randrole(); } } else { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */ /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole() + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */ flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */ flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */ flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ /* tty_display_nhwindow(BASE_WINDOW, FALSE); */ } /* Ask the user for a player name. */ void mswin_askname(void) { logDebug("mswin_askname()\n"); if (mswin_getlin_window("who are you?", plname, PL_NSIZ) == IDCANCEL) { bail("bye-bye"); /* not reached */ } } /* Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. */ void mswin_get_nh_event(void) { logDebug("mswin_get_nh_event()\n"); return; } /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ void mswin_exit_nhwindows(const char *str) { logDebug("mswin_exit_nhwindows(%s)\n", str); /* Write Window settings to the registry */ mswin_write_reg(); // Don't do any of this (?) - exit_nhwindows does not terminate // the application // DestroyWindow(GetNHApp()->hMainWnd); // terminate(EXIT_SUCCESS); } /* Prepare the window to be suspended. */ void mswin_suspend_nhwindows(const char *str) { logDebug("mswin_suspend_nhwindows(%s)\n", str); return; } /* Restore the windows after being suspended. */ void mswin_resume_nhwindows() { logDebug("mswin_resume_nhwindows()\n"); return; } /* Create a window of type "type" which can be NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) */ winid mswin_create_nhwindow(int type) { winid i = 0; MSNHMsgAddWnd data; logDebug("mswin_create_nhwindow(%d)\n", type); /* Return the next available winid */ for (i = 1; i < MAXWINDOWS; i++) if (GetNHApp()->windowlist[i].win == NULL && !GetNHApp()->windowlist[i].dead) break; if (i == MAXWINDOWS) panic("ERROR: No windows available...\n"); switch (type) { case NHW_MAP: { GetNHApp()->windowlist[i].win = mswin_init_map_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MESSAGE: { GetNHApp()->windowlist[i].win = mswin_init_message_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_STATUS: { GetNHApp()->windowlist[i].win = mswin_init_status_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MENU: { GetNHApp()->windowlist[i].win = NULL; // will create later GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 1; break; } case NHW_TEXT: { GetNHApp()->windowlist[i].win = mswin_init_text_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } } ZeroMemory(&data, sizeof(data)); data.wid = i; SendMessage(GetNHApp()->hMainWnd, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ADDWND, (LPARAM) &data); return i; } /* Clear the given window, when asked to. */ void mswin_clear_nhwindow(winid wid) { logDebug("mswin_clear_nhwindow(%d)\n", wid); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { if (Is_rogue_level(&u.uz)) mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode); } SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CLEAR_WINDOW, (LPARAM) NULL); } } /* -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. */ void mswin_display_nhwindow(winid wid, BOOLEAN_P block) { logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block); if (GetNHApp()->windowlist[wid].win != NULL) { if (GetNHApp()->windowlist[wid].type == NHW_MENU) { MENU_ITEM_P *p; mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p); } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) { mswin_display_text_window(GetNHApp()->windowlist[wid].win); } if (GetNHApp()->windowlist[wid].type == NHW_RIP) { mswin_display_RIP_window(GetNHApp()->windowlist[wid].win); } else { if (!block) { UpdateWindow(GetNHApp()->windowlist[wid].win); } else { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { (void) mswin_nhgetch(); } } } SetFocus(GetNHApp()->hMainWnd); } } HWND mswin_hwnd_from_winid(winid wid) { if (wid >= 0 && wid < MAXWINDOWS) { return GetNHApp()->windowlist[wid].win; } else { return NULL; } } winid mswin_winid_from_handle(HWND hWnd) { winid i = 0; for (i = 1; i < MAXWINDOWS; i++) if (GetNHApp()->windowlist[i].win == hWnd) return i; return -1; } winid mswin_winid_from_type(int type) { winid i = 0; for (i = 1; i < MAXWINDOWS; i++) if (GetNHApp()->windowlist[i].type == type) return i; return -1; } void mswin_window_mark_dead(winid wid) { if (wid >= 0 && wid < MAXWINDOWS) { GetNHApp()->windowlist[wid].win = NULL; GetNHApp()->windowlist[wid].dead = 1; } } /* Destroy will dismiss the window if the window has not * already been dismissed. */ void mswin_destroy_nhwindow(winid wid) { logDebug("mswin_destroy_nhwindow(%d)\n", wid); if ((GetNHApp()->windowlist[wid].type == NHW_MAP) || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) { /* main windows is going to take care of those */ return; } if (wid != -1) { if (!GetNHApp()->windowlist[wid].dead && GetNHApp()->windowlist[wid].win != NULL) DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = NULL; GetNHApp()->windowlist[wid].type = 0; GetNHApp()->windowlist[wid].dead = 0; } } /* Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. */ void mswin_curs(winid wid, int x, int y) { logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgCursor data; data.x = x; data.y = y; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CURSOR, (LPARAM) &data); } } /* putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. */ void mswin_putstr(winid wid, int attr, const char *text) { logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text); mswin_putstr_ex(wid, attr, text, 0); } void mswin_putstr_ex(winid wid, int attr, const char *text, boolean app) { if ((wid >= 0) && (wid < MAXWINDOWS)) { if (GetNHApp()->windowlist[wid].win == NULL && GetNHApp()->windowlist[wid].type == NHW_MENU) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT); GetNHApp()->windowlist[wid].dead = 0; } if (GetNHApp()->windowlist[wid].win != NULL) { MSNHMsgPutstr data; ZeroMemory(&data, sizeof(data)); data.attr = attr; data.text = text; data.append = app; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_PUTSTR, (LPARAM) &data); } } } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void mswin_display_file(const char *filename, BOOLEAN_P must_exist) { dlb *f; TCHAR wbuf[BUFSZ]; logDebug("mswin_display_file(%s, %d)\n", filename, must_exist); f = dlb_fopen(filename, RDTMODE); if (!f) { if (must_exist) { TCHAR message[90]; _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf))); MessageBox(GetNHApp()->hMainWnd, message, TEXT("ERROR"), MB_OK | MB_ICONERROR); } } else { winid text; char line[LLEN]; text = mswin_create_nhwindow(NHW_TEXT); while (dlb_fgets(line, LLEN, f)) { size_t len; len = strlen(line); if (line[len - 1] == '\n') line[len - 1] = '\x0'; mswin_putstr(text, ATR_NONE, line); } (void) dlb_fclose(f); mswin_display_nhwindow(text, 1); mswin_destroy_nhwindow(text); } } /* Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. */ void mswin_start_menu(winid wid) { logDebug("mswin_start_menu(%d)\n", wid); if ((wid >= 0) && (wid < MAXWINDOWS)) { if (GetNHApp()->windowlist[wid].win == NULL && GetNHApp()->windowlist[wid].type == NHW_MENU) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU); GetNHApp()->windowlist[wid].dead = 0; } if (GetNHApp()->windowlist[wid].win != NULL) { SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_STARTMENU, (LPARAM) NULL); } } } /* add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. */ void mswin_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph, identifier, (char) accelerator, (char) group_accel, attr, str, presel); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgAddMenu data; ZeroMemory(&data, sizeof(data)); data.glyph = glyph; data.identifier = identifier; data.accelerator = accelerator; data.group_accel = group_accel; data.attr = attr; data.str = str; data.presel = presel; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data); } } /* end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean */ void mswin_end_menu(winid wid, const char *prompt) { logDebug("mswin_end_menu(%d, %s)\n", wid, prompt); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgEndMenu data; ZeroMemory(&data, sizeof(data)); data.text = prompt; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ENDMENU, (LPARAM) &data); } } /* int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_N, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. */ int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) { int nReturned = -1; logDebug("mswin_select_menu(%d, %d)\n", wid, how); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { nReturned = mswin_menu_window_select_menu( GetNHApp()->windowlist[wid].win, how, selected); } return nReturned; } /* -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. */ void mswin_update_inventory() { logDebug("mswin_update_inventory()\n"); } /* mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment */ void mswin_mark_synch() { logDebug("mswin_mark_synch()\n"); } /* wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). */ void mswin_wait_synch() { logDebug("mswin_wait_synch()\n"); } /* cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. */ void mswin_cliparound(int x, int y) { winid wid = WIN_MAP; logDebug("mswin_cliparound(%d, %d)\n", x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgClipAround data; data.x = x; data.y = y; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CLIPAROUND, (LPARAM) &data); } } /* print_glyph(window, x, y, glyph, bkglyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). */ void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) { logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgPrintGlyph data; ZeroMemory(&data, sizeof(data)); data.x = x; data.y = y; data.glyph = glyph; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data); } } /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). */ void mswin_raw_print(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print(%s)\n", str); if (str && *str) MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK); } /* raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). */ void mswin_raw_print_bold(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print_bold(%s)\n", str); if (str && *str) MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK); } /* int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero. */ int mswin_nhgetch() { PMSNHEvent event; int key = 0; logDebug("mswin_nhgetch()\n"); while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR) mswin_main_loop(); key = event->kbd.ch; return (key); } /* int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 -- mouse click type 1 CLICK_2 -- mouse click type 2 The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. */ int mswin_nh_poskey(int *x, int *y, int *mod) { PMSNHEvent event; int key; logDebug("mswin_nh_poskey()\n"); while ((event = mswin_input_pop()) == NULL) mswin_main_loop(); if (event->type == NHEVENT_MOUSE) { *mod = event->ms.mod; *x = event->ms.x; *y = event->ms.y; key = 0; } else { key = event->kbd.ch; } return (key); } /* nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void mswin_nhbell() { logDebug("mswin_nhbell()\n"); } /* doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int mswin_doprev_message() { logDebug("mswin_doprev_message()\n"); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); return 0; } /* char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. */ char mswin_yn_function(const char *question, const char *choices, CHAR_P def) { int result = -1; char ch; char yn_esc_map = '\033'; char message[BUFSZ]; char res_ch[2]; logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def); if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } (void) strncpy(message, question, QBUFSZ - 1); message[QBUFSZ - 1] = '\0'; sprintf(eos(message), " [%s]", choicebuf); if (def) sprintf(eos(message), " (%c)", def); Strcat(message, " "); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); } #if defined(WIN_CE_SMARTPHONE) { char buf[BUFSZ]; ZeroMemory(buf, sizeof(buf)); if (choices) { if (!index(choices, '\033')) buf[0] = '\033'; /* make sure ESC is always available */ strncat(buf, choices, sizeof(buf) - 2); NHSPhoneSetKeypadFromString(buf); } else { /* sometimes choices are included in the message itself, e.g. * "what? [abcd]" */ char *p1, *p2; p1 = strchr(question, '['); p2 = strrchr(question, ']'); if (p1 && p2 && p1 < p2) { buf[0] = '\033'; /* make sure ESC is always available */ strncat(buf, p1 + 1, p2 - p1 - 1); NHSPhoneSetKeypadFromString(buf); } else if (strstr(question, "direction")) { /* asking for direction here */ NHSPhoneSetKeypadDirection(); } else { /* anything goes */ NHSPhoneSetKeypadFromString("\0330-9a-zA-Z"); } } } #endif /* defined(WIN_CE_SMARTPHONE) */ mswin_putstr(WIN_MESSAGE, ATR_BOLD, message); /* Only here if main window is not present */ while (result < 0) { ch = mswin_nhgetch(); if (ch == '\033') { result = yn_esc_map; } else if (choices && !index(choices, ch)) { /* FYI: ch==-115 is for KP_ENTER */ if (def && (ch == ' ' || ch == '\r' || ch == '\n' || ch == -115)) { result = def; } else { mswin_nhbell(); /* and try again... */ } } else { result = ch; } } /* display selection in the message window */ if (isprint(ch)) { res_ch[0] = ch; res_ch[1] = '\x0'; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1); } /* prevent "--more--" prompt from appearing when several questions being asked in the same loop (like selling something in the shop) It does not really clears the window - mhmsgwnd.c */ mswin_clear_nhwindow(WIN_MESSAGE); #if defined(WIN_CE_SMARTPHONE) NHSPhoneSetKeypadDefault(); #endif return result; } /* getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. */ void mswin_getlin(const char *question, char *input) { logDebug("mswin_getlin(%s, %p)\n", question, input); if (mswin_getlin_window(question, input, BUFSZ) == IDCANCEL) { strcpy(input, "\033"); } } /* int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. */ int mswin_get_ext_cmd() { int ret; logDebug("mswin_get_ext_cmd()\n"); if (mswin_ext_cmd_window(&ret) == IDCANCEL) return -1; else return ret; } /* number_pad(state) -- Initialize the number pad to the given state. */ void mswin_number_pad(int state) { /* Do Nothing */ logDebug("mswin_number_pad(%d)\n", state); } /* delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. */ void mswin_delay_output() { logDebug("mswin_delay_output()\n"); Sleep(50); } void mswin_change_color() { logDebug("mswin_change_color()\n"); } char * mswin_get_color_string() { logDebug("mswin_get_color_string()\n"); return (""); } /* start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. */ void mswin_start_screen() { /* Do Nothing */ logDebug("mswin_start_screen()\n"); } /* end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). */ void mswin_end_screen() { /* Do Nothing */ logDebug("mswin_end_screen()\n"); } /* outrip(winid, int, when) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. */ void mswin_outrip(winid wid, int how, time_t when) { logDebug("mswin_outrip(%d, %d, %ld)\n", wid, how, (long) when); if ((wid >= 0) && (wid < MAXWINDOWS)) { DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = mswin_init_RIP_window(); GetNHApp()->windowlist[wid].type = NHW_RIP; GetNHApp()->windowlist[wid].dead = 0; } genl_outrip(wid, how, when); } /* handle options updates here */ void mswin_preference_update(const char *pref) { HDC hdc; if (_stricmp(pref, "font_menu") == 0 || _stricmp(pref, "font_size_menu") == 0) { if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if (_stricmp(pref, "font_status") == 0 || _stricmp(pref, "font_size_status") == 0) { if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if (_stricmp(pref, "font_message") == 0 || _stricmp(pref, "font_size_message") == 0) { if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if (_stricmp(pref, "font_text") == 0 || _stricmp(pref, "font_size_text") == 0) { if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if (_stricmp(pref, "scroll_margin") == 0) { mswin_cliparound(u.ux, u.uy); return; } if (_stricmp(pref, "map_mode") == 0) { mswin_select_map_mode(iflags.wc_map_mode); return; } if (_stricmp(pref, "hilite_pet") == 0) { InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE); return; } if (_stricmp(pref, "align_message") == 0 || _stricmp(pref, "align_status") == 0) { mswin_layout_main_window(NULL); return; } if (_stricmp(pref, "vary_msgcount") == 0) { InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE); mswin_layout_main_window(NULL); return; } if (_stricmp(pref, "fullscreen") == 0) { mswin_set_fullscreen(iflags.wc2_fullscreen); return; } if (_stricmp(pref, "softkeyboard") == 0) { GetNHApp()->bUseSIP = iflags.wc2_softkeyboard; return; } if (_stricmp(pref, "wraptext") == 0) { GetNHApp()->bWrapText = iflags.wc2_wraptext; return; } } void mswin_main_loop() { MSG msg; while (!mswin_have_input() && GetMessage(&msg, NULL, 0, 0) != 0) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /* clean up and quit */ void bail(const char *mesg) { clearlocks(); mswin_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } BOOL initMapTiles(void) { HBITMAP hBmp; BITMAP bm; TCHAR wbuf[MAX_PATH]; int tl_num; SIZE map_size; extern int total_tiles_used; /* no file - no tile */ if (!(iflags.wc_tile_file && *iflags.wc_tile_file)) return TRUE; /* load bitmap */ hBmp = SHLoadDIBitmap(NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH)); if (hBmp == NULL) { raw_print( "Cannot load tiles from the file. Reverting back to default."); return FALSE; } /* calculate tile dimensions */ GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bm); if (bm.bmWidth % iflags.wc_tile_width || bm.bmHeight % iflags.wc_tile_height) { DeleteObject(hBmp); raw_print("Tiles bitmap does not match tile_width and tile_height " "options. Reverting back to default."); return FALSE; } tl_num = (bm.bmWidth / iflags.wc_tile_width) * (bm.bmHeight / iflags.wc_tile_height); if (tl_num < total_tiles_used) { DeleteObject(hBmp); raw_print("Number of tiles in the bitmap is less than required by " "the game. Reverting back to default."); return FALSE; } /* set the tile information */ if (GetNHApp()->bmpMapTiles != GetNHApp()->bmpTiles) { DeleteObject(GetNHApp()->bmpMapTiles); } GetNHApp()->bmpMapTiles = hBmp; GetNHApp()->mapTile_X = iflags.wc_tile_width; GetNHApp()->mapTile_Y = iflags.wc_tile_height; GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width; map_size.cx = GetNHApp()->mapTile_X * COLNO; map_size.cy = GetNHApp()->mapTile_Y * ROWNO; mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE); return TRUE; } void mswin_popup_display(HWND hWnd, int *done_indicator) { MSG msg; HWND hChild; /* activate the menu window */ GetNHApp()->hPopupWnd = hWnd; mswin_layout_main_window(hWnd); /* disable game windows */ for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT)) { if (hChild != hWnd) EnableWindow(hChild, FALSE); } #if defined(WIN_CE_SMARTPHONE) ShowWindow(GetNHApp()->hMenuBar, SW_HIDE); ShowWindow(SHFindMenuBar(hWnd), SW_SHOW); #else EnableWindow(GetNHApp()->hMenuBar, FALSE); #endif /* bring menu window on top */ SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); /* go into message loop */ if (done_indicator) *done_indicator = 0; while (IsWindow(hWnd) && (done_indicator == NULL || !*done_indicator) && GetMessage(&msg, NULL, 0, 0) != 0) { if (!IsDialogMessage(hWnd, &msg)) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } void mswin_popup_destroy(HWND hWnd) { HWND hChild; /* enable game windows */ for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT)) { if (hChild != hWnd) { EnableWindow(hChild, TRUE); } } #if defined(WIN_CE_SMARTPHONE) ShowWindow(SHFindMenuBar(hWnd), SW_HIDE); ShowWindow(GetNHApp()->hMenuBar, SW_SHOW); #else EnableWindow(GetNHApp()->hMenuBar, TRUE); #endif SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); GetNHApp()->hPopupWnd = NULL; mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); DestroyWindow(hWnd); mswin_layout_main_window(hWnd); SetFocus(GetNHApp()->hMainWnd); } void mswin_set_fullscreen(BOOL is_fullscreen) { #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) SetForegroundWindow(GetNHApp()->hMainWnd); if (is_fullscreen) { SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON); MoveWindow(GetNHApp()->hMainWnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), FALSE); } else { RECT rc; SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON); MoveWindow(GetNHApp()->hMainWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); } GetNHApp()->bFullScreen = is_fullscreen; #else GetNHApp()->bFullScreen = FALSE; #endif } #if defined(WIN_CE_SMARTPHONE) void NHSPhoneDialogSetup(HWND hDlg, UINT nToolBarId, BOOL is_edit, BOOL is_fullscreen) { SHMENUBARINFO mbi; HWND hOK, hCancel; RECT rtOK, rtDlg; // Create our MenuBar ZeroMemory(&mbi, sizeof(SHMENUBARINFO)); mbi.cbSize = sizeof(mbi); mbi.hwndParent = hDlg; mbi.nToolBarId = nToolBarId; mbi.hInstRes = GetNHApp()->hApp; if (!SHCreateMenuBar(&mbi)) { error("cannot create dialog menu"); } if (is_fullscreen) { SHINITDLGINFO shidi; RECT main_wnd_rect; shidi.dwMask = SHIDIM_FLAGS; shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN; shidi.hDlg = hDlg; SHInitDialog(&shidi); GetWindowRect(GetNHApp()->hMainWnd, &main_wnd_rect); MoveWindow(hDlg, main_wnd_rect.left, main_wnd_rect.top, main_wnd_rect.right - main_wnd_rect.left, main_wnd_rect.bottom - main_wnd_rect.top, FALSE); } /* hide OK and CANCEL buttons */ hOK = GetDlgItem(hDlg, IDOK); hCancel = GetDlgItem(hDlg, IDCANCEL); if (IsWindow(hCancel)) ShowWindow(hCancel, SW_HIDE); if (IsWindow(hOK)) { GetWindowRect(hOK, &rtOK); GetWindowRect(hDlg, &rtDlg); rtDlg.bottom -= rtOK.bottom - rtOK.top; ShowWindow(hOK, SW_HIDE); SetWindowPos(hDlg, HWND_TOP, 0, 0, rtDlg.right - rtDlg.left, rtDlg.bottom - rtDlg.top, SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER); } /* override "Back" button for edit box dialogs */ if (is_edit) SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); } #endif /* defined(WIN_CE_SMARTPHONE) */ void mswin_read_reg(void) { } void mswin_destroy_reg(void) { } void mswin_write_reg(void) { } /* check HKCU\Software\\Microsoft\\Shell\HasKeyboard for keyboard presence, if the key is not there assume older device and no keyboard */ BOOL mswin_has_keyboard(void) { DWORD dwHasKB = 0; #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) HKEY hKey; DWORD dwType; DWORD dwSize = sizeof(dwHasKB); if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Shell"), 0, 0, &hKey) == ERROR_SUCCESS) { if (RegQueryValueEx(hKey, _T("HasKeyboard"), NULL, &dwType, (LPBYTE) &dwHasKB, &dwSize) != ERROR_SUCCESS) { dwHasKB = 0; } RegCloseKey(hKey); } #endif return (dwHasKB == 1); } #ifdef _DEBUG #include void logDebug(const char *fmt, ...) { FILE *dfp = fopen("nhtrace.log", "a"); if (dfp) { va_list args; va_start(args, fmt); vfprintf(dfp, fmt, args); va_end(args); fclose(dfp); } } #endif nethack-3.6.0/sys/wince/newres.h0000664000076400007660000000135412536476415015554 0ustar paxedpaxed#ifndef __NEWRES_H__ #define __NEWRES_H__ #if !defined(UNDER_CE) #define UNDER_CE _WIN32_WCE #endif #if defined(_WIN32_WCE) #if !defined(WCEOLE_ENABLE_DIALOGEX) #define DIALOGEX DIALOG DISCARDABLE #endif #include #define SHMENUBAR RCDATA #if (defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)) \ && (_WIN32_WCE >= 300) #include #else #define I_IMAGENONE (-2) #define NOMENU 0xFFFF #define IDS_SHNEW 1 #define IDM_SHAREDNEW 10 #define IDM_SHAREDNEWDEFAULT 11 #endif #endif // _WIN32_WCE #ifdef RC_INVOKED #ifndef _INC_WINDOWS #define _INC_WINDOWS #include "winuser.h" // extract from windows header #endif #endif #ifdef IDC_STATIC #undef IDC_STATIC #endif #define IDC_STATIC (-1) #endif //__NEWRES_H__ nethack-3.6.0/sys/wince/nhico.uu0000664000076400007660000010270012504242744015537 0ustar paxedpaxedbegin 700 nethack.ico M```!``8`("``````"`"H"```9@```!`0``````@`:`4```X)```L+``````( M`!@-``!V#@``0$``````"``H%@``CAL``%I:``````@`N"@``+8Q```6%@`` M```(`)`&``!N6@``*````"````!``````0`(````````!``````````````` M`0````$``````````(```(````"`@`"`````@`"``("```#`P,``P-S``/#* MI@`$!`0`"`@(``P,#``1$1$`%A86`!P<'``B(B(`*2DI`%5550!-34T`0D)" M`#DY.0"`?/\`4%#_`),`U@#_[,P`QM;O`-;GYP"0J:T````S````9@```)D` M``#,```S````,S,``#-F```SF0``,\P``#/_``!F````9C,``&9F``!FF0`` M9LP``&;_``"9````F3,``)EF``"9F0``F\\O,*"@H* M"@H*"@H*"O3J1._R\`=&1P<'(&_OO`H'!_.\"@H*"@H*"@H*"@H*"O!$[+R3 M("!'!Y,@($6\O`?S\/(*"@H*"@H*"@H*"@H*"N\''"`@($<'DR`@'T6\\/#Q M"@H*"@H*"@H*"@H*"@KR!QP?("`@1P?O("`?'T7PO`H*"@H*"@H*"@H*"@H* M"@<''Q\@("!&[.M%Z1\?`6[Q]`H*"@H*"@H*"@H*"@KR[VX!'^GL[`<'!P=M M'Q\!`;SQ"@H*"@H*"@H*"@H*"O$'10%%!P<';_>2;D4?'P$!!_`*"@H*"@H* M"@H*"@H*\`\!^N\!P?Q\_(';0?W!^R\!PH*"@H*"@H*"@H*"@KQ MO+P';;SO!_+T\KSK\.\'[`<'"@H*"@H*"@H*"@H*"O*\`0?MZ6[W\/'P]^L? M[`=$DP<*"@H*"@H*"@H*"@H*\O`![`=$(._O[^WO[!^2[`&3!PH*"@H*"@H* M"@H*"@KR\`$!!_=%(&[W]^UN;0=$`9/O"@H*"@H*"@H*"@H*"O/Q`0%%!^]M M1>WMZNL'$@$!'.\'!_(*"@H*"@H*"@H*\_$!`1_I'`<'[P<'[T4?`0$<[_$' M[[P*"@H*"@H*"@KS\0$!'R`@(&^2]T8@'Q\!`>WW\`?O!_(*"@H*"@H*"O/Q M`0$?("`@1@<'("`?'P$![9+P!^^2[_,*"@H*"@H*\_`!`1\?("!&!P<@(!\! M`0%N[?`'[Y+L[PH*"@H*"@KS\._O!P?O[P<'\/"\O+P'!^V2O`?ODNP'"@H* M"@H*"@?M[._R\+SP\?+R\O"\O`?O[^R\!^_M[.\*"@H*"@KQ1$1N"@H*"@H* M"@KQ\_/Q!^\'[^V2!_`'[`H*"@H*"FU$ZO,*"@H*"@H*"@?S\_`'[Y*\[/(* M"@KS"@H*"@KL1$0'"@H*"@H*"@H*\_/S\`?O[._Q[PH*"@H*"@H*[T1$'`H* M"@H*"@H*"@H*\_/P!_<'"O0*"@H*"@H*"@KL'.P*"@H*"@H*"@H*"@KP!_`' M]PH*"@H*"@H*"@H*"@H'\@H*"@H*"@H*"@H*"@KRO`?O"@H*"@H*"@H*"@H* M"@H*"@H*"@H*"@H*"@H*"@H*\_#S"@H*"@H*"@H*^?C_?_#P/#_XP!@_^``( M?_P``'_^``#__``!__P``/_X``#_^```__@``/_X``#_^```__@``/_X``#_ M^```__@``/_X``#_^```'_@```_X```'^````_@```/X```#^````_#_``/P M_P`[X?\`/\/_@7_'_X/_Y__#____\?\H````$````"`````!``@````````! M```````````````!`````0``````````@```@````("``(````"``(``@(`` M`,#`P`#`W,``\,JF``0$!``("`@`#`P,`!$1$0`6%A8`'!P<`"(B(@`I*2D` M5555`$U-30!"0D(`.3DY`(!\_P!04/\`DP#6`/_LS`#&UN\`UN?G`)"IK0`` M`#,```!F````F0```,P``#,````S,P``,V8``#.9```SS```,_\``&8```!F M,P``9F8``&:9``!FS```9O\``)D```"9,P``F68``)F9``"9S```F?\``,P` M``#,,P``S&8``,R9``#,S```S/\``/]F``#_F0``_\P`,P```#,`,P`S`&8` M,P"9`#,`S``S`/\`,S,``#,S,P`S,V8`,S.9`#,SS``S,_\`,V8``#-F,P`S M9F8`,V:9`#-FS``S9O\`,YD``#.9,P`SF68`,YF9`#.9S``SF?\`,\P``#/, M,P`SS&8`,\R9`#/,S``SS/\`,_\S`#/_9@`S_YD`,__,`#/__P!F````9@`S M`&8`9@!F`)D`9@#,`&8`_P!F,P``9C,S`&8S9@!F,YD`9C/,`&8S_P!F9@`` M9F8S`&9F9@!F9ID`9F;,`&:9``!FF3,`9IEF`&:9F0!FF\ M[_````#T[VXN\\O+T\O`'![SOD@``!T0<`````/'R M[Y+W`````.MN``````#S\._S\@````#T`````````//P]`````#,9P``P`<` M`.`/``#@#P``P`\``,`/``#`#P``P`\``,`/``#``P``P`$``,`!``#``0`` MCP<``)\'``"_CP``*````"P```!8`````0`(``````"0!P`````````````` M`0````$``````````(```(````"`@`"`````@`"``("```#`P,``P-S``/#* MI@`$!`0`"`@(``P,#``1$1$`%A86`!P<'``B(B(`*2DI`%5550!-34T`0D)" M`#DY.0"`?/\`4%#_`),`U@#_[,P`QM;O`-;GYP"0J:T````S````9@```)D` M``#,```S````,S,``#-F```SF0``,\P``#/_``!F````9C,``&9F``!FF0`` M9LP``&;_``"9````F3,``)EF``"9F0``F\;^_W[_$```#S!P?S\O(````````````````````` M[T1$[0#T\/'N1OD6![P@(&_O[_$```<'\?.\```````````````````````` M^$1$!_#PDR`@^18'[B`@($8'!_*\![SS\/````````````````````````#S M;6T'O),@("#Y%@<'("`@'T7PO`<'\_&\```````````````````````````' M[P>3("`@(/F3!P<@("`?'T7N\+SQ]```````````````````````````\P<' MDQ\@("`@^9,'!R`@(!\?'T6\\0?T```````````````````````````'[^\? M'R`@("#YD^_O("`@'Q\?`47Q\/0`````````````````````````\N\'11\? M("`@($9N;6U$1>D?'Q\!`1SQ\?0````````````````````````'[^\!'Q\@ MZ6UM]P<'!P<'ZQ\?'P$!1?"\]`````````````````````````<';@$?'T4' M!P>\[^\'!P?L'Q\?`0$!![ST````````````````````````[^X!`1_M!P<' M;OD6[^\@("`?'Q\!`0&3!_,```````````````````````#OO`$!10<'$B`@ M(&YM^$7JZNKJZA,!`1P'\@```````````````````````.^\`0'O!^OI($7K M[.WLZP<'O+P'[T0!DP?R````````````````````````!^X!10<'1"!%[>V2 M]_?O[/=%'P<'$@&3!_(````````````````````````'!P'W!_=%Z0?W!_#P MO`?O[44![P=M`1P'\0````````````````````````>\\.\'Z[SO[^_P\O+Q MO._K[[SO!^R\O._Q````````````````````````![SP!P=MO._WO/'S]//P M[^SO\>\'[>\'[_$````````````````````````'O.\'!^N3'.\'\?/T\O#O M[.V3]P?M'`?O\0```````````````````````+SN`6X'[T4@!Y*\\?'PO)*2 M'Q_O!^H!D^_P````````````````````````O+P!10<'$B!&!_<'!^_M[_\````````````````````````\/`!`1]%!P<';41N[_=%$NL'[T0! M`0$_P!P?O[_+R``````````````#Q\`$!'Q\?("`@^6\'O"`@("`?'P$!`>WM M[_`'!^^2D@<``````````````/+P`0$?'Q\@("#Y;P>\("`@(!\?`0$!;NSO M\`?O[Y+L[/$`````````````\;QN;FYN;FYN;V^3!_"3;VYN;I,<[6[L[`>\ M!^_ODNSM!P````````````#Q\;P'!P?O[^_O[P<'O/#Q\O"\!^_ODNWL![P' M[_>2[.SQ``````````````?WDO?N\;P'!P>\\/'Q\?"\O+R\!^_O[^SOO`?O M]^WL^+P```````````#O%$1$[P````````````#T]/3SO`<'!_?P[Q+O!^SM M[>SX]P``````````O!)#1.T``````````````/'P]/3R\+P'[_?SDOB2]``` M`/#M`````````/)M%41N]```````````````\;ST]/+P!^_ODN_O^/`````` M`/0`````````^!5$;?$`````````````````\/3T\O`'[_?M[`<'D@`````` M`````````!Q$1$H'````````````````````]/3R\`?O]^ST`.^2```````` M``````#O$D-$'`````````````````````#P\_'P!^^2\@```/#Q```````` M`````.T'[/@``````````````````````/#O\;P'[^\````````````````` M`````)+M\P```````````````````````/('O`?O!P`````````````````` M`````````````````````````````````/3Q\`?O```````````````````` M``````````````````````````````````#T\O#S````````````````_C_C M___P``#\/X#_#_```/P?`#X/\```_@P`'`_P``#_"``,'_```/^````?\``` M_X```#_P``#_P```?_```/^```!_\```_X```'_P``#_````/_```/\````_ M\```_P```#_P``#_````/_```/\````_\```_P```#_P``#_````/_```/\` M```_\```_P```#_P``#_````/_```/\````_\```_P```#_P``#_````/_`` M`/\````_\```_P```#_P``#_`````_```/\````!\```_P````#P``#_```` M`'```/\`````<```_P`````P``#_`````#```/\`````,```_P`````P``#^ M#_P``#```/P?_``',```^!_\``^P``#X/_X`#_```/!__P!/\```X/__`.?P M``#A__\!__```/'__X'_\```____P?_P``#____P__```"@```!`````@``` M``$`"````````!````````````````$````!``````````"```"`````@(`` M@````(``@`"`@```P,#``,#\ M]`````````````#S\;P'\O0`````````````````````````````!VU$0VWQ M``````````#Q\/'PO+P'!P?O[^_P``````````#TO`<'O/3S```````````` M``````````````````#O2D05^/0``````/3P\O+Q!Y.\!P>3[^_W]P?T```` M``#T\.\'!_3R\0```````````````````````````````.Q$1$0<`````/+P M\O+PDT<7O`<';T:3]_?O!_,`````\^\'!_3SO/,````````````````````` M``````````#S;D1#$NX``/+P\?+N;R#Y%P<'!V\@(&_W[^\'\@``]`<'!_+S M\0<```````````````````````````````````?J1$/K\O*\\/&31B`@^1<' M!P=O("`@1ASO!P?R``<'!_#T\KSP```````````````````````````````` M````'$1#1`<'O/!O("`@(/D7!P<';R`@("#IDP<'O+SO![ST\O`']``````` M``````````````````````````````!N1.\'O/!O("`@("#Y%P<'!V\@("`@ M'Q^3\;R\!P?S\_`'\P``````````````````````````````````````\?<' M!P=O("`@("`@^1<'!P=O("`@(!\?Z6^\\/"\\_&\\@`````````````````` M`````````````````````/#O!P=N'R`@("`@(/D7!P<';R`@("`?'Q\!;O#Q M\`>\\0```````````````````````````````````````/+O!P>3'Q\@("`@ M("#Y%P?O[V\@("`@'Q\?`0$<\?&\\``````````````````````````````` M```````````'[P>3'Q\?("`@("`@^1<'[^]O("`@(!\?'P$!`1SR\KP````` M``````````````````````````````````#Q[^\'`1\?'R`@("`@(/D7!^_O M;B`@("`?'Q\!`0%%O/+P\P`````````````````````````````````````` M!^\''`$?'Q\@("`@("!%$A(3$Q-$1$7I'Q\?`0$!`6[Q\?`````````````` M````````````````````````\>_O!P$!'Q\?("#I1!/K]^\'!P<'!^_W%!\? M'P$!`0$![O"\`````````````````````````````````````+SO[^\!`1\? M'^GMO`<'!P<'!P<'!P<'!Q0?'Q\!`0$!`1SPO/,````````````````````` M```````````````'[P?M`0$?'^F\!P<'!_`'')+O[^\'!P<3'Q\?`0$!`0%N M\+SR````````````````````````````````````!^^\10$!'^F\!P<'O!P@ M^1?O[_=N("`@(!\?'P$!`0$!1;P'\0`````````````````````````````` M``````?OO`$!`1_N!P?OZT8@(/D7[^_W;NE$1$1$1$1$1`$!`0&\!_$````` M```````````````````````````````'[[P!`0%N!P<';>D@("!%$A(3$NKM M]_?O[^_O[^Q$`0$!O`?Q````````````````````````````````````!P>\ M`0$!\`<'[$4@("`3[/CL^&WKD@<'!P<'!P?O$P$!`>X'\0`````````````` M``````````````````````<'O`$!;@<'[T0@("`4DNR2DO?O[VWO!^MN;@<' M!VT!`0'N!_`````````````````````````````````````'![P!`0<'!Y)% M("#K[Y*2[^_O]P<';0<2'Q]N!P?W1`%%!P?P```````````````````````` M````````````!P<'`0&\!P?K'Q]%O/?OO+SP\+P'O._L$Q\?1;P'[Q0!10<' M\`````````````````````````````````````<'O.X'\`<'$@<'!P?OO/#Q M\?'P\`<'ZQ+O[P>\!P<2[NX'[_`````````````````````````````````` M``"\![SP!_`'!^KPO`?O[_#Q\O/S\O`'[>T2\/#Q!P<'$KP'!^^\```````` M````````````````````````````O`>\\`?P!P?JO+R\]P?P\O/T]/+QO)*2 M$O#Q\;P'!^J\!P?OO````````````````````````````````````+R\O+P' M\`<'$P<'!^\'\/+S]/3R\;R2[1*\[NZ\!P?J!P<'[[P````````````````` M``````````````````#PO`21`$!1>_W!P`````````` M`````````````````````````/'PO`$!`1^3!P?OZD4@(/E&[?<';R`@Z>D4 M]P?O%`$!`47O]P<```````````````````````````````````#Q\?`!`0$? M'^X'!P?M$T;Y1N\'!V\@($03[P?O$@$!`0%%[Y+O[P>\]``````````````` M````````````````\?'P`0$!'Q\?[[P'!^_L$Q)M[/@2%.J2!P<'$@$!`0$! M1>^2!_#O[.R2\0```````````````````````````/'Q\`$!`1\?'Q]OO`<' M!P<'[_?W[P<'!P>\DQ\?`0$!`47OD@?Q\+P'[_<'```````````````````` M``````#Q\?$!`0$?'Q\?($:3![P'!P<'!P<'O+SO11\?'P$!`0%%[Y+O\/"\ M!P<'O+P`````````````````````````\?+Q`0$!'Q\?'R`@("!&D^\'![P' MDT8@(!\?'Q\!`0$!1??M[[SPO`?O[P?S\@```````````````````````/'R M\`$!`1\?'Q\@("`@(/E&!P<';R`@("`?'Q\?`0$!`47W[>_P\+P'[^_W[_/Q M``````````````````````#Q\O`!`0$?'Q\?("`@("#Y1@<'O&\@("`@'Q\? M'P$!`0%%]^WW\?`'!^_O]Y+OO/(`````````````````````\?*\`0$!'Q\? M'R`@("`@^48'![QO("`@(!\?'Q\!`0$!1??LDO&\!P?O[_>2[>_O```````` M`````````````/'RO`$!`1\?'Q\@("`@(/D7!P>\;R`@("`?'Q\?`0$!`462 M[._PO`<'[^_W[>SLDO,```````````````````#Q\@2[>SL[_(```````````````````"\\+P' M!P<'O`?O[^_O[^\'![R\\/#P\?&\O`<'!P?O[_>2[>WW\+P'[^_WDNWL[/?Q M``````````````````#Q$D1$1$3L]`````````````````#T\O/S!P?O[^_O M!P?O\+SL;?>\!^_O]Y+M[/CM!P````````````````#T;1%#1$3J]``````` M`````````````+ST]/3T\_'PO`?O[^_S!VWL]P?LZ^WW[Y+L[)(````````` M````````["(10T1$\`````````````````````#W\O3T]//Q\+P'[^_W[_+O M$NUM!P``````\NWL````````````````[T,B0T1$[P`````````````````` M````[?#T]/3R\?"\!^_ODI('!^T3\@``````````!P``````````````\401 M(D1$;@````````````````````````?P]/3T\O'P!P?O[Y+M]_`'[/<````` M````````````````````]!)#0T1$2O0```````````````````````#RO/3T M]/+Q\`<'[_>2[&WO\VWX`````````````````````````/A#0T-$1+P````` M`````````````````````//T]//R\;P'!^_W[6WT\N_RZO,````````````` M`````````.]#0T-$1!P```````````````````````````#T\_3S\O&\!P?O M]_@`````O/3O`````````````````````._O0T-$1.P````````````````` M`````````````/#R\_+PO`<'[Y('``````#R``````````````````````#M M$A)$1&WT``````````````````````````````#P[_#R\+P'[^^2```````` M`/0`````````````````````\Y+Q\NWQ```````````````````````````` M``````?M!_"\!^_O]P````````````````````````````````#R[._Q```` M````````````````````````````````O.\'O`?O[^\````````````````` M``````````````````````````````````````````````````````````#S M\/"\!^_O```````````````````````````````````````````````````` M``````````````````````````#S]/+R!_(````````````````````````` M``````````````````````````````````````````````````````#S\?#P M`````````````````````````/____'______\?_P'_^7___@_\`'_@?__^! M_@`/\!___\#X``/@'___X/```>`?___@8```P#____````!`/___^``````_ M___\`````'____P`````_____`````'____X`````_____@````#____\``` M``'____P`````?___^`````!____X`````#____@`````/___^``````____ MX`````#____@`````/___^``````____X`````#____@`````/___^`````` M____X`````#____@`````/___^``````____X`````#____@`````/___^`` M````____X`````#____@`````/___^``````____X`````#____@``````__ M_^```````___X``````!___@``````#__^```````'__X```````/__@```` M```?_^```````!__X```````#__@```````/_^````````__X```````#__@ M```````/_\`__@````__@'__````#_^`__\```^/_P'__P``'^_^`___```? M__P#__\``!___`?__X``#__X#___@`>/__`?___`!]__\!___\`/[__P/___ MX`____A____P#_________@/_________@?_________A___*````%H```"T M`````0`(``````!8(````````````````0````$``````````(```(````"` M@`"`````@`"``("```#`P,``P-S``/#*I@`$!`0`"`@(``P,#``1$1$`%A86 M`!P<'``B(B(`*2DI`%5550!-34T`0D)"`#DY.0"`?/\`4%#_`),`U@#_[,P` MQM;O`-;GYP"0J:T````S````9@```)D```#,```S````,S,``#-F```SF0`` M,\P``#/_``!F````9C,``&9F``!FF0``9LP``&;_``"9````F3,``)EF``"9 MF0``FSQ```` M`````````````````````/*\O+P'\/(````````````````````````````` M````````````````````````````````````````````````````\?/O$I(` M`````````````````````/,'O/"\O`<'![SQ```````````````````````` M`//S\_3S\P```````````````````````````````````````````/+P\1,5 M$>\```````````````````"\!_'P\+R\!P<'!^^\\P`````````````````` M`/3R\`<'!_3T````````````````````````````````````````````\/!M M1$,B$_$```````````````#T!_#Q\?#PO+P'!P<'[^_OO``````````````` M``#T\0?O!P?R]/,```````````````````````````````````````````#T M[T1$0R)#;?0`````````````\0?R\?'PO`>\!P<'[N_O[^_O[_,````````` M````]/('[P<'\`#S\0`````````````````````````````````````````` M``#T;41$0T,B[0```````````+SP\O+Q\0=OD[P'!P?OD^_O[_?W[_`````` M``````#S!^\'![P`]/'P```````````````````````````````````````` M``````#S2D1$0R)$!P```````//P\?+R\O"31OF3O`<'!^\@;^_O]_?O[[ST M````````]`?O!P<']/3R!_,````````````````````````````````````` M``````````#O1$1#(D,3\@````#R\/'Q\O(';R#Y^9,'!P<'[R`@1I/W[^_O M[P?S``````#Q[P<'!_/T\_'O```````````````````````````````````` M``````````````#L1$1#0Q'K````\KSP\?+R[T8@(/GYDP<'!P>3("`@(&_W M[^_O![SS````\N\'!P?Q]//Q![P````````````````````````````````` M`````````````````/1M1$1#(D/M`/*\\/#QO&\@("`@^?F3!P<'!Y,@("`@ M($8<[^\'![SS`/,'[P<'O/3S\O#O\P`````````````````````````````` M`````````````````````/!$1$0B$>KPO+SP\>Y&("`@("#Y^9,'!P<'DR`@ M("`@(!]O[P<'![SQ!^\'!P?T\_+P!P<````````````````````````````` M`````````````````````````.]$1$-$[P>\O/`'1B`@("`@(/GYDP<'!P?O M("`@("`@'Q]O![P'O+P'!P<'\_3R\;P']``````````````````````````` M`````````````````````````````&Y$1.\'![SP!^D@("`@("`@^?F3!P<' M!Y,@("`@("`?'Q]O\[R\O/`'!_+T\O&\!_,````````````````````````` M````````````````````````````````].KW!P<'O`?I("`@("`@("#Y^9,' M!P<'[R`@("`@(!\?'Q]O![R\\+P']//Q\`?Q```````````````````````` M````````````````````````````````````!P<'![SOZ1\@("`@("`@(/GY MDP<'[^^3("`@("`@'Q\?'Q]%!_#P\;R\\?`'\``````````````````````` M`````````````````````````````````````/`'!P<'!^D?'R`@("`@("`@ M^?F3!P?O[Y,@("`@("`?'Q\?'P%%!_#Q\0<'O/`````````````````````` M``````````````````````````````````````#R!^\'!P=%'Q\?("`@("`@ M("#Y^9,'!^_O'"`@("`@(!\?'Q\?`0%NO/'Q\N_P```````````````````` M``````````````````````````````````````````?O[P<';A\?'Q\@("`@ M("`@(/GYDP?O[^\<("`@("`@'Q\?'Q\!`0%N\/'R\;P````````````````` M``````````````````````````````````````````#Q[^\'!Y,?'Q\?'R`@ M("`@("`@^?F3!^_O[Y(@("`@("`?'Q\?'P$!`0'M\?+R!P`````````````` M``````````````````````````````````````````````?O[P<'`1\?'Q\? M("`@("`@("#Y^9,'[^_O[2`@("`@(!\?'Q\?`0$!`44'\O+Q\``````````` M``````````````````````````````````````````````#P[^_O!VX!'Q\? M'Q\@("`@("`@("!&;FUM;6WJ147I("`@'Q\?'Q\!`0$!`6[R\?&\]``````` M``````````````````````````````````````````````````?O[^\'`0$? M'Q\?'R`@("`@1403;>OL[.SL[.SL^&WJ$T0?'Q\?'P$!`0$!`>_Q\/#P```` M``````````````````````````````````````````````````#R[^_O!T4! M`1\?'Q\?("`@;FWKDN_O[^_O[^_O[^_O[^_L1!\?'Q\?`0$!`0$!;O#PO/`` M``````````````````````````````````````````````````````?O[^_N M`0$!'Q\?'Q\@1;R\[^\'!P<'!P<'!P<'!P<'!Y)$'Q\?'Q\!`0$!`0$!!_"\ MO/0`````````````````````````````````````````````````````!^_O M[P_P!P<'!P<'O/#P!P<'!P>\\?"\]T0?'Q\?'P$!`0$!`0'O M\+P'\@`````````````````````````````````````````````````````' M[^\'[P$!`1\?'Q\'O`<'!P>\\.]O1I/O[^_O;B`@1F[M1!\?'Q\?`0$!`0$! M`9+PO`?R```````````````````````````````````````````````````` M`._O[[QN`0$!'Q\?![P'!P<'\.]&(/GYD^_O[_?L("`@("`@'Q\?'Q\!`0$! M`0$!;KR\!_(````````````````````````````````````````````````` M````[^_O\$4!`0$?'P>\!P?O]_=&("`@^?F3[^_O]^P@("`@("`?'Q\?'P$! M`0$!`0%%O`<'\@`````````````````````````````````````````````` M``````#O[^_P10$!`1]N\`<'!^T3("`@("#Y^9/L^.SW["#KZA(2ZNKJZNKJ MZA,!`0$!`46\!P?Q```````````````````````````````````````````` M``````````?O!_!%`0$!1?`'!P?W$^D@("`@($43ZFWX;1(2(._O[^_O[^_O M[^_O[1,!`0$!1;P'!_$````````````````````````````````````````` M````````````!^\'O$4!`0'OO`<'[VU%("`@("`3^)+L;>IM^/CK[P<'!P<' M!P<'!P?O;0$!`0%%O`<'\0`````````````````````````````````````` M```````````````'[P>\10$!`?`'!P?M$R`@("#I$^WL[)+O[P?O^.KO!P?O MDN\'[KP'!^_L1`$!`44'!P?Q```````````````````````````````````` M``````````````````<'![Q%`0%N\`<'[VT?("`@(!+M[)+M[.SL[)('[Q+W M!^_J'Q\?;KP'!_<3`0$!10<'!_$````````````````````````````````` M````````````````````!P<'O$4!`0<'!P?W$R`@("#L]_?W[??O[^_W]P?P M!Q+O[Q(?'Q]%\`<'[VT>`0%N!P<'\0`````````````````````````````` M```````````````````````'!P>\1`$!\0<'[^Q$("`@;KSO[Y+O![R\O`<' M![SQ[VWO$Q\?'Q^\!P?O[$0!`6X'!^_P```````````````````````````` M``````````````````````````<'![QN143Q!P?OZT1%147N!P?W![SP\/#P M\+R\O+R\Z_<2145%1>\'!P?W$T5%;@<'[_`````````````````````````` M````````````````````````````!P<'O+R\[_$'!^]M!P<'[_$'[P>\\/'Q M\?'Q\+R\!^_W[!('!P<'[[P'!_<2O+R\!P?O\``````````````````````` M```````````````````````````````'!P>\\/#W\0<'[^KP\+SW\`?OO/#Q M\O+S\O+Q\+SODN]M$KSP\/'O\`<'[Q*\O`<'[^_P```````````````````` M``````````````````````````````````<'O+SP\9+P!P?OZO"\O.^\[^^\ M\/+S\_3S\_+QO`?M[VT2\/#Q\0?P!P?O$[P'!P?O[_`````````````````` M````````````````````````````````````O`>\O/#Q[_`'!^]M\+R\[_#O M[_#Q\O/T]/3S\O'P!^T'[!+P\/'Q![P'!^\2O`<'!^_OO``````````````` M``````````````````````````````````````"\![R\\/`'\`<'[VWO!P<' M\`?W\/'R\_3T]//R\?`'[>_W$KR\O+P'O`<'[Q('!P<'[^^\```````````` M`````````````````````````````````````````+P'O`=%147Q!P?O[$5& M1D:\!Y*\\/'R\_3S\O+PO._M]^\31D5%1>V\!P?O$T5%;P?O[[P````````` M````````````````````````````````````````````O+R\!T0!`;P'!P>2 M$R`@(.V\[^_P\?+R\O+R\?"\[^_W[Q,?'Q\?[P<'!_<4`0%N!^_OO``````` M``````````````````````````````````````````````#PO/`'1`$![P<' M!^_JZ2`@1O$']P?P\?'Q\?'PO`?W[0?O$Q\?'Q_P!P?O[$0!`6X'[_>\```` M`````````````````````````````````````````````````/"\\`=$`0%% M\`<'[^Q$("`@;_`'[^_P\/#P\+P'DNT'!^\3'Q\?1;P'!^]M`0$!;N_O][P` M````````````````````````````````````````````````````\+SP!T0! M`0&\!P<']Q,@("`@[[P'!^\'!P?O]Y*2!P<'[Q,?'Q\2[P<']Q0!`0%N[^_W M!P````````````````````````````````````````````````````#PO/"\ M1`$!`6[P!P?O[!,@("`@[_&\!_+P!^\'![P'!P?O$B`?1/CO!^_K1`$!`6[O M[_<'`````````````````````````````````````````````````````/#P M\+Q$`0$!`?>\!P?O^$0@("`@1N_Q\+R\O/`'[_'PO`?J(!_J[P<'DA,!`0$! M;N_W]P<````````````````````````````````````````````````````` M\?#QO$0!`0$!`;P'!P?OZT0@("`@^482!P`````````````````````````````````````````````````` M``#Q\/&\1`$!`0$?1?`'!P?O^!/I("#Y^6_O[P<''"`@("`@11*2!P?OZT0! M`0$!`6[O]Y('\P`````````````````````````````````````````````` M`````/'P\;Q$`0$!`1\?[?$'!P?ODFT31OGY;^_O!P<<("`@11-M]P<'[^M$ M`0$!`0$!;N_WD@?O[^\'\0`````````````````````````````````````` M````````\?#Q\$0!`0$!'Q\?;O"\!P<'[^WJ$T1NDN\'!_A%1!/KDN\'!P?X M1`$!`0$!`0%N[_>2!_$']^WL[0?T```````````````````````````````` M``````````#Q\?'P1`$!`0$?'Q\?10?P!P<'!^_W[>SK;>KJ;?CL]^\'!P>\ M!T0?`0$!`0$!`6[ODI('\?'PO.^2[9('```````````````````````````` M`````````````/'Q\O!%`0$!`1\?'Q\@'^WQO`<'!P<'[^_O[^_O[P<'!P>\ M\/2[0?Q\?"\!P?O[^\']``````````````````````` M````````````````\?'R\$4!`0$!'Q\?'R`@($;MO/"\!P<'!P<'!P<'!P?P M\0=%'Q\?'P$!`0$!`0%N]Y+M!_#Q\+P'!P?O![R\]``````````````````` M``````````````````#Q\?+P10$!`0$?'Q\?("`@("`@19.\\/'Q\/#P\/&\ M[V[I("`?'Q\?`0$!`0$!`6[WDNT'O/#PO`<'[^_OO/+Q]``````````````` M`````````````````````/'R\O!%`0$!`1\?'Q\@("`@("`@(/GY;Y*2]^_M M("`@("`@(!\?'Q\!`0$!`0$!;O?M[>\'\/"\!P?O[^_W\0#T```````````` M````````````````````````\?+R\$4!`0$!'Q\?'R`@("`@("`@^?EO!P<' MO!P@("`@("`@'Q\?'P$!`0$!`0%N]^WM[_#PO+P'!^_O[_>2\//Q```````` M``````````````````````````#Q\O+P10$!`0$?'Q\?("`@("`@("#Y^6\' M!P>\'"`@("`@("`?'Q\?`0$!`0$!`462[>SW\?"\O`<'[^_O]Y+MO/#R```` M`````````````````````````````/'R\KQ%`0$!`1\?'Q\@("`@("`@(/GY M;P<'![P<("`@("`@(!\?'Q\!`0$!`0$!19+M[)+Q\+P'!P?O[_?WDNV2!^\` M````````````````````````````````\?+RO$4!`0$!'Q\?'R`@("`@("`@ M^?EO!P<'O),@("`@("`@'Q\?'P$!`0$!`0%%DNWL]_'PO`<'!^_O]_>2[>R2 M][P```````````````````````````````#Q\O*\10$!`0$?'Q\?("`@("`@ M("#Y^6\'!P>\DR`@("`@("`?'Q\?`0$!`0$!`462[.SO\?"\!P<'[^_WDI+M M[.SMD@```````````````````````````````/'R\0=%`0$!`1\?'Q\?("`@ M("`@(/GYDP<'O+SO("`@("`@(!\?'Q\!`0$!`0$!19+L[._Q\+P'!P?O[_>2 MDNWL[/?O````````````````````````````````\?+Q!T4>(T0C(R-$145$ M`45%145%1463!P>\\.]%145%145%145%145$1$1$1$1N[>SL[_#PO`<'[^_O M]Y+M[>SL]P?P``````````````````````````````#P\O$'[^\'!P<'!P<' M!^_W]_?O[^\'![P'![SP\+R\!P?O[^\'!P>\\/'P\+P'[_?M[.SO\/"\!P?O M[^_WDNWM[.SM\;P``````````````````````````````/#Q\?#PO+P'!P<' M[^_O[_?W[^_O[P<'!P<'O+SP\/'Q\O+Q\/"\!P<'[^_O]Y*2[>SL[._PO+P' M!^_O[_>2[>SL[.SS\0````````````````````````````#T\/'Q\/"\O`<' M!P<'[^_O]_?O[^_O!P<'![R\\/#Q\?+R\O'P\+P'!P?O[^_WDI+M[.SL[_"\ MO`<'[^_O]Y+M[.SL^//R```````````````````````````````'!P<'[^\' M!P>\\?`'!^_O[^_O[^\'!P>\\/#Q\/#P\+P'!P<'!P<'!P<'[^_O]_?M[>WO M![P'!P?O[_?WDNWL[.SX!_``````````````````````````````O!(4%41$ M1$1N\/0```````````````````````#T\_+S\_('[_>2DI*2[P<'!^\'\KR2 M;?B2!P<'!^_O]_>2[>SL^/CO!P```````````````````````````/+J$")# M(D1$1`<```````````````````````````#S\/3T]/3T]//R\?"\!P?O[Y*\ M``?L$^R2!P<'DFUMZ_CK[.SX^)+O````````````````````````````^!`1 M(D-$1$0<`````````````````````````````/$']/3T]/3S\O+Q\+P'!^_O M]_?P]._K$Y*2[^KX!P````#Q!_?X[.T``````````````````````````!Q$ M$")#(D1$;O0`````````````````````````````\/?T]/3T]//R\?'PO`<' M[^_W]^_R\O=MZO@2\```````````]._L[0````````````````````````"\ M$Q`10T-$1$KT``````````````````````````````#P[/'T]/3T\_+Q\/"\ M!P?O[_>2D@?T!^SJZ_0```````````````?O```````````````````````` M`!(1(B)#1$1$\````````````````````````````````/+MO/3T]/3S\O'P MO+P'!^_O]Y+MDKP'^.P3]P`````````````````````````````````````` M`/3K0Q!#0T1$1!P`````````````````````````````````].\']/3T]//R M\?"\!P<'[^_WDNWM]_#T[^N2```````````````````````````````````` M````[1`10R)$1$3L````````````````````````````````````\+ST]/3T M\_+Q\+P'!^_O[_>2[!+L[_*\%6T````````````````````````````````` M``````=$$2)#1$1$;?(```````````````````````````````````#T\O3T M]/3S\O'PO`<'[^_O]^T3[`#O[0?O%/$````````````````````````````` M``````#P$A`10T-$1$J\```````````````````````````````````````` M]/3T]//R\?"\!P?O[_?WZNT`````]_#W[0`````````````````````````` M`````````.LB$2)#1$1$[P`````````````````````````````````````` M``#S]/3T\_+Q\+P'!^_O]^SL````````!_*2```````````````````````` M`````````/`'$B(B0T1$1/CU```````````````````````````````````` M`````/'P]//S\O'PO`<'[^_W^/0`````````\?/P```````````````````` M````````````[.\20R)$1$1N```````````````````````````````````` M````````\0>\\_+R\?"\!P?O[_>2````````````]``````````````````` M``````````````#W$FUM1$1$2O(````````````````````````````````` M````````````!^\'\O'P\+P'!^_ODO`````````````````````````````` M``````````````````"2!_'Q'&WO```````````````````````````````` M``````````````#T]^WO\?"\O`<'[^_M\P`````````````````````````` M`````````````````````/22O/+R\0`````````````````````````````` M``````````````````#T[^_O\+P'!P?O[Y+T```````````````````````` M``````````````````````````"\[`?Q```````````````````````````` M``````````````````````#TO`<'O`<'!^_O]_0````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````\O#Q\`?O[^_W\@`````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````//S]/*\[_<'```````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````#S]/3T\@<````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````]/'P\/(````````` M``````````````````````````#______X_______\#__P___@/______\#_ M_@__^`#__^!__\#__`?_\``__X!__\#__`/_P``?_P!__\#__`'_@``'_@)_ M_\#__@'_```#_@1__\#__P#\````_`!__\#__X!X````?`#__\#__\!P```` M.`#__\#__\`@````$`#__\#__^````````'__\#___````````'__\#___@` M``````/__\#___@```````?__\#___P```````___\#___@``````!___\#_ M__```````#___\#___```````#___\#__^```````#___\#__^```````!__ M_\#__\````````___\#__\````````___\#__X````````___\#__X`````` M``?__\#__X````````?__\#__X````````?__\#__X````````?__\#__X`` M``````?__\#__X````````?__\#__X````````?__\#__X````````?__\#_ M_X````````?__\#__X````````?__\#__X````````?__\#__X````````?_ M_\#__X````````?__\#__X````````?__\#__X````````?__\#__X`````` M``?__\#__X````````?__\#__X````````?__\#__X````````?__\#__X`` M``````?__\#__X````````?__\#__X````````?__\#__X````````?__\#_ M_X````````?__\#__X````````?__\#__X````````?__\#__X````````/_ M_\#__X`````````__\#__X`````````'_\#__X`````````#_\#__X`````` M````_\#__X``````````?\#__X``````````/\#__X``````````O\#__X`` M````````'\#__X``````````#\#__X``````````#\#__X``````````!\#_ M_X``````````!\#__X``````````!\#__X```````````\#__X`````````` M`\#__X```````````\#__P```````````\#__X```````````\#__P`?__@` M`````\#__@!___P``$```\#__@#___P````/`\#__`#___P````_P\#_^`'_ M__P```!_\\#_^`/___P```!__\#_X`?___P```!__\#_X`____X```!__\#_ MP`____X``!`__\#_@!____^``#P__\#_@#____^``'X__\#^`#____^``'\? M_\#^`/____^``/^__\#^`/_____``/___\#_`?_____``/___\#_`______@ M`/___\#_P______P`/___\#________\`/___\#_________`/___\#_____ M____P/___\#_________\'___\`H````%@```"P````!``@``````!`"```` M```````````!`````0``````````@```@````("``(````"``(``@(```,#` MP`#`W,``\,JF``0$!``("`@`#`P,`!$1$0`6%A8`'!P<`"(B(@`I*2D`5555 M`$U-30!"0D(`.3DY`(!\_P!04/\`DP#6`/_LS`#&UN\`UN?G`)"IK0```#,` M``!F````F0```,P``#,````S,P``,V8``#.9```SS```,_\``&8```!F,P`` M9F8``&:9``!FS```9O\``)D```"9,P``F68``)F9``"9S```F?\``,P```#, M,P``S&8``,R9``#,S```S/\``/]F``#_F0``_\P`,P```#,`,P`S`&8`,P"9 M`#,`S``S`/\`,S,``#,S,P`S,V8`,S.9`#,SS``S,_\`,V8``#-F,P`S9F8` M,V:9`#-FS``S9O\`,YD``#.9,P`SF68`,YF9`#.9S``SF?\`,\P``#/,,P`S MS&8`,\R9`#/,S``SS/\`,_\S`#/_9@`S_YD`,__,`#/__P!F````9@`S`&8` M9@!F`)D`9@#,`&8`_P!F,P``9C,S`&8S9@!F,YD`9C/,`&8S_P!F9@``9F8S M`&9F9@!F9ID`9F;,`&:9``!FF3,`9IEF`&:9F0!FF]O(/D';R!% MO/'P````````````````!VX?(/D';R`?1?#T``````````````#T!Q\?16[X MZT0?`0?S``````````````#P[Q_L!QR2;D4?`6[Q``````````````"\'&[M MZ47KZ^SLZD6\``````````````#P'.\2;O?P!^M%[$6\``````````````#P M\`?M]_#T\>R\[^\'``````````````#QD^]M[0?QO/AN[VX'```````````` M``#Q'&[M1??W]^MM^$4'``````````````#R'`'M[$7W;FV21$7O\?,````` M``````#R'`$?;O?O!^Q%`47O\`?P``````````#S'`$?("`';R`?`47WO._O M\0````````#S[45%1D;NDT9%16Z2O._M[P````````#N[^\'[P?P\?"\!^_M MO._M[P```````/-$$O,`````\O3R!_<'[^\'[0```````!)$[@``````\O3R M!_>2D@``````````DD3M`````````/3Q!^WR!_,`````````[Y(````````` M`/('!P<`````````````````````````````\KP``````````/.//`#S`CP` M\``\`/@`?`#X`'P`\`!\`/``?`#P`'P`\`!\`/``?`#P`'P`\`!\`/``'`#P C``P`\``$`/``!`#P``0`X>`$`./@/`#'\!P`S_#\`/_\_``` ` end nethack-3.6.0/sys/wince/resource.h0000664000076400007660000001040712536476415016077 0ustar paxedpaxed//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by winhcksp.rc // #define IDC_MYICON 2 #define IDD_WINHACK_DIALOG 102 #define IDD_ABOUTBOX 103 #define IDS_APP_TITLE 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDS_HELLO 106 #define IDI_WINHACK 107 #define IDC_WINHACK 109 #define IDC_SPHONE_DIALOGBAR 111 #define IDC_SPHONE_TEXTDIALOGBAR 112 #define IDR_MAINFRAME 128 #define IDB_TILES 129 #define IDD_TEXT 130 #define IDD_NHTEXT 130 #define IDD_MENU 132 #define IDB_MENU_SEL 133 #define IDB_MENU_UNSEL 134 #define IDD_COMMANDS 136 #define IDD_GETLIN 138 #define IDD_EXTCMD 139 #define IDD_PLAYER_SELECTOR 141 #define IDB_PETMARK 145 #define IDB_MENU_SEL_COUNT 146 #define IDB_KEYPAD 147 #define IDB_MENUBAR 154 #define IDC_TEXT_VIEW 1001 #define IDC_CMD_MOVE_NW 1001 #define IDC_CMD_MOVE_N 1002 #define IDC_MENU_LIST 1003 #define IDC_CMD_MOVE_NE 1003 #define IDC_MENU_TEXT 1004 #define IDC_CMD_MOVE_W 1004 #define IDC_CMD_MOVE_SELF 1005 #define IDC_CMD_MOVE_E 1006 #define IDC_CMD_MOVE_SW 1007 #define IDC_CMD_MOVE_S 1008 #define IDC_CMD_MOVE_SE 1009 #define IDC_CMD_MOVE_UP 1010 #define IDC_CMD_MOVE_DOWN 1011 #define IDC_CMD_5 1012 #define IDC_CMD_A 1013 #define IDC_CMD_B 1014 #define IDC_CMD_C 1015 #define IDC_CMD_D 1016 #define IDC_CMD_E 1017 #define IDC_CMD_F 1018 #define IDC_CMD_G 1019 #define IDC_CMD_H 1020 #define IDC_CMD_I 1021 #define IDC_CMD_J 1022 #define IDC_CMD_K 1023 #define IDC_CMD_L 1024 #define IDC_CMD_M 1025 #define IDC_CMD_N 1026 #define IDC_CMD_O 1027 #define IDC_CMD_P 1028 #define IDC_CMD_Q 1029 #define IDC_CMD_R 1030 #define IDC_CMD_S 1031 #define IDC_CMD_T 1032 #define IDC_CMD_U 1033 #define IDC_CMD_V 1034 #define IDC_CMD_W 1035 #define IDC_CMD_X 1036 #define IDC_CMD_Y 1037 #define IDC_CMD_Z 1038 #define IDC_CMD_AA 1039 #define IDC_CMD_BB 1040 #define IDC_CMD_CC 1041 #define IDC_CMD_DD 1042 #define IDC_CMD_EE 1043 #define IDC_CMD_FF 1044 #define IDC_CMD_GG 1045 #define IDC_CMD_HH 1046 #define IDC_CMD_II 1047 #define IDC_CMD_JJ 1048 #define IDC_CMD_KK 1049 #define IDC_CMD_LL 1050 #define IDC_CMD_MM 1051 #define IDC_CMD_NN 1052 #define IDC_CMD_OO 1053 #define IDC_CMD_PP 1054 #define IDC_CMD_QQ 1055 #define IDC_CMD_RR 1056 #define IDC_CMD_SS 1057 #define IDC_CMD_TT 1058 #define IDC_CMD_UU 1059 #define IDC_CMD_VV 1060 #define IDC_CMD_WW 1061 #define IDC_CMD_XX 1062 #define IDC_CMD_YY 1063 #define IDC_CMD_ZZ 1064 #define IDC_CMD_FIRST 1100 #define IDC_CMD_LAST 1300 #define IDC_GETLIN_EDIT 1309 #define IDC_EXTCMD_LIST 1310 #define IDC_PLSEL_NAME 1314 #define IDC_PLSEL_ROLE_RANDOM 1315 #define IDC_PLSEL_RACE_RANDOM 1318 #define IDC_PLSEL_GENDER_RANDOM 1319 #define IDC_PLSEL_ALIGN_RANDOM 1320 #define IDC_PLSEL_ROLE_LIST 1323 #define IDC_PLSEL_RACE_LIST 1324 #define IDC_PLSEL_ALIGN_LIST 1325 #define IDC_PLSEL_GENDER_LIST 1326 #define IDC_ABOUT_VERSION 1327 #define IDC_TEXT_CONTROL 1331 #define IDC_ABOUT_COPYRIGHT 1332 #define IDC_TEXT_TOGGLE_WRAP 1333 #define IDM_SAVE 32771 #define IDM_HELP_LONG 32772 #define IDM_HELP_COMMANDS 32773 #define IDM_HELP_HISTORY 32774 #define IDM_HELP_INFO_CHAR 32775 #define IDM_HELP_INFO_KEY 32776 #define IDM_HELP_OPTIONS 32777 #define IDM_HELP_OPTIONS_LONG 32778 #define IDM_HELP_EXTCMD 32779 #define IDM_HELP_LICENSE 32780 #define IDM_MAP_TILES 32781 #define IDM_MAP_ASCII4X6 32782 #define IDM_MAP_ASCII6X8 32783 #define IDM_MAP_ASCII8X8 32784 #define IDM_MAP_ASCII16X8 32785 #define IDM_MAP_ASCII7X12 32786 #define IDM_MAP_ASCII8X12 32787 #define IDM_MAP_ASCII16X12 32788 #define IDM_MAP_ASCII12X16 32789 #define IDM_MAP_ASCII10X18 32790 #define IDM_MAP_FIT_TO_SCREEN 32791 #define ID_FILE 32792 #define IDS_CAP_FILE 32793 #define ID_HELP 32794 #define IDS_CAP_HELP 32795 #define IDS_CAP_TEMP 32796 #define ID_MAP 32797 #define IDS_CAP_AMP 32798 #define IDS_CAP_MAP 32799 #define IDM_VIEW_KEYPAD 32800 #define ID_VIEW 32801 #define IDS_CAP_VIEW 32802 #define IDS_CAP_ENTIREMAP 32826 #define IDS_CAP_NORMALMAP 32827 #define IDM_HELP_MENU 32828 #define IDM_VIEW_OPTIONS 32829 #define IDM_DIRECT_COMMAND 32830 #define IDS_TEXT_WRAP 32831 #define IDS_TEXT_UNWRAP 32832 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 155 #define _APS_NEXT_COMMAND_VALUE 32833 #define _APS_NEXT_CONTROL_VALUE 1334 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif nethack-3.6.0/sys/wince/winMS.h0000664000076400007660000001347312536476415015313 0ustar paxedpaxed/* NetHack 3.6 winMS.h $NHDT-Date: 1433806609 2015/06/08 23:36:49 $ $NHDT-Branch: master $:$NHDT-Revision: 1.29 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINMS_H #define WINMS_H #pragma warning(disable : 4142) /* benign redefinition of type */ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include "resource.h" #include "hack.h" #if defined(WIN_CE_POCKETPC) #include #include #endif #if defined(WIN_CE_SMARTPHONE) #include #include #include #include #include #include #include #endif #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) #include #endif /* Taskbar Menu height */ #define MENU_HEIGHT 26 /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif /* RIP window ID */ #define NHW_RIP 32 #define NHW_KEYPAD 33 /* size of tiles */ #ifndef TILE_X #define TILE_X 16 #endif #define TILE_Y 16 /* tiles per line in the bitmap */ #define TILES_PER_LINE 40 /* tile background color */ #define TILE_BK_COLOR RGB(71, 108, 108) /* minimum/maximum font size (in points - 1/72 inch) */ #define NHFONT_DEFAULT_SIZE 9 #define NHFONT_STATUS_DEFAULT_SIZE 6 #define NHFONT_SIZE_MIN 3 #define NHFONT_SIZE_MAX 20 typedef struct mswin_nhwindow_data { HWND win; int type; int dead; } MSNHWinData, *PMSNHWinData; /* global application data - alailable thour GetNHApp() */ typedef struct mswin_nhwindow_app { HINSTANCE hApp; /* hInstance from WinMain */ int nCmdShow; /* main window mode flag */ HWND hMainWnd; /* main window handle */ HACCEL hAccelTable; /* accelerator table */ HWND hPopupWnd; /* active dialog window (nethack menu, text, etc) */ HWND hMenuBar; /* menu bar */ MSNHWinData windowlist[MAXWINDOWS]; /* nethack windows array */ HBITMAP bmpTiles; /* nethack tiles */ HBITMAP bmpPetMark; /* pet mark Bitmap */ HBITMAP bmpMapTiles; /* alternative map tiles */ int mapTile_X; /* alt. tiles width */ int mapTile_Y; /* alt. tiles height */ int mapTilesPerLine; /* number of tile per row in the bitmap */ boolean bNoHScroll; /* disable cliparound for horizontal grid (map) */ boolean bNoVScroll; /* disable cliparound for vertical grid (map) */ int mapDisplayModeSave; /* saved map display mode */ int bCmdPad; /* command pad - on-screen keyboard */ HWND hCmdWnd; /* handle of on-screen keyboard window */ /* options */ boolean bWrapText; /* format text to fit the window */ boolean bFullScreen; /* run nethack in full-screen mode */ boolean bHideScrollBars; /* hide scroll bars */ boolean bUseSIP; /* use SIP (built-in software keyboard) for menus (PocketPC only) */ } NHWinApp, *PNHWinApp; extern PNHWinApp GetNHApp(); #define E extern E struct window_procs mswin_procs; #undef E /* Some prototypes */ void mswin_init_nhwindows(int *argc, char **argv); void mswin_player_selection(void); void mswin_askname(void); void mswin_get_nh_event(void); void mswin_exit_nhwindows(const char *); void mswin_suspend_nhwindows(const char *); void mswin_resume_nhwindows(void); winid mswin_create_nhwindow(int type); void mswin_clear_nhwindow(winid wid); void mswin_display_nhwindow(winid wid, BOOLEAN_P block); void mswin_destroy_nhwindow(winid wid); void mswin_curs(winid wid, int x, int y); void mswin_putstr(winid wid, int attr, const char *text); void mswin_putstr_ex(winid wid, int attr, const char *text, boolean append); void mswin_display_file(const char *filename, BOOLEAN_P must_exist); void mswin_start_menu(winid wid); void mswin_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel); void mswin_end_menu(winid wid, const char *prompt); int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected); void mswin_update_inventory(void); void mswin_mark_synch(void); void mswin_wait_synch(void); void mswin_cliparound(int x, int y); void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); int mswin_nhgetch(void); int mswin_nh_poskey(int *x, int *y, int *mod); void mswin_nhbell(void); int mswin_doprev_message(void); char mswin_yn_function(const char *question, const char *choices, CHAR_P def); void mswin_getlin(const char *question, char *input); int mswin_get_ext_cmd(void); void mswin_number_pad(int state); void mswin_delay_output(void); void mswin_change_color(void); char *mswin_get_color_string(void); void mswin_start_screen(void); void mswin_end_screen(void); void mswin_outrip(winid wid, int how, time_t when); void mswin_preference_update(const char *pref); /* helper function */ HWND mswin_hwnd_from_winid(winid wid); winid mswin_winid_from_type(int type); winid mswin_winid_from_handle(HWND hWnd); void mswin_window_mark_dead(winid wid); void bail(const char *mesg); void nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, COLORREF cTransparent); void mswin_popup_display(HWND popup, int *done_indicator); void mswin_popup_destroy(HWND popup); #if defined(WIN_CE_SMARTPHONE) void NHSPhoneDialogSetup(HWND hDlg, UINT nToolBarId, BOOL is_edit, BOOL is_fullscreen); #endif void mswin_read_reg(void); void mswin_destroy_reg(void); void mswin_write_reg(void); BOOL mswin_has_keyboard(void); void mswin_set_fullscreen(BOOL is_fullscreen); extern winid WIN_STATUS; #endif /* WINmswin_H */ nethack-3.6.0/sys/wince/winhack.c0000664000076400007660000002174112536476415015672 0ustar paxedpaxed/* NetHack 3.6 winhack.c $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (C) 2001 by Alex Kompel */ // winhack.cpp : Defines the entry point for the application. // #include "winMS.h" #include "hack.h" #include "dlb.h" #include "mhmain.h" #include "mhmap.h" extern char orgdir[PATHLEN]; /* also used in pcsys.c, amidos.c */ extern void FDECL(nethack_exit, (int)); static TCHAR *_get_cmd_arg(TCHAR *pCmdLine); // Global Variables: NHWinApp _nethack_app; // Foward declarations of functions included in this code module: BOOL InitInstance(HINSTANCE, int); static void win_hack_init(int, char **); static void __cdecl mswin_moveloop(void *); static BOOL setMapTiles(const char *fname); extern boolean FDECL(pcmain, (int, char **)); #define MAX_CMDLINE_PARAM 255 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX InitCtrls; HWND nethackWnd; int argc; char *argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR *p; TCHAR wbuf[NHSTR_BUFSIZE]; char buf[NHSTR_BUFSIZE]; boolean resuming; sys_early_init(); /* ensure that we don't access violate on a panic() */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; /* init applicatio structure */ _nethack_app.hApp = hInstance; _nethack_app.nCmdShow = nCmdShow; _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR) IDC_WINHACK); _nethack_app.hMainWnd = NULL; _nethack_app.hPopupWnd = NULL; _nethack_app.hMenuBar = NULL; _nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES)); if (_nethack_app.bmpTiles == NULL) panic("cannot load tiles bitmap"); _nethack_app.bmpPetMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK)); if (_nethack_app.bmpPetMark == NULL) panic("cannot load pet mark bitmap"); _nethack_app.bmpMapTiles = _nethack_app.bmpTiles; _nethack_app.mapTile_X = TILE_X; _nethack_app.mapTile_Y = TILE_Y; _nethack_app.mapTilesPerLine = TILES_PER_LINE; _nethack_app.bNoHScroll = FALSE; _nethack_app.bNoVScroll = FALSE; _nethack_app.bCmdPad = !mswin_has_keyboard(); _nethack_app.bWrapText = TRUE; _nethack_app.bFullScreen = TRUE; #if defined(WIN_CE_SMARTPHONE) _nethack_app.bHideScrollBars = TRUE; #else _nethack_app.bHideScrollBars = FALSE; #endif _nethack_app.bUseSIP = TRUE; // check for running nethack programs nethackWnd = FindWindow(szMainWindowClass, NULL); if (nethackWnd) { // bring on top SetForegroundWindow(nethackWnd); return FALSE; } // init controls ZeroMemory(&InitCtrls, sizeof(InitCtrls)); InitCtrls.dwSize = sizeof(InitCtrls); InitCtrls.dwICC = ICC_LISTVIEW_CLASSES; if (!InitCommonControlsEx(&InitCtrls)) { MessageBox(NULL, TEXT("Cannot init common controls"), TEXT("ERROR"), MB_OK | MB_ICONSTOP); return FALSE; } // Perform application initialization: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } /* get command line parameters */ p = _get_cmd_arg( #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) lpCmdLine #else GetCommandLine() #endif ); for (argc = 1; p && argc < MAX_CMDLINE_PARAM; argc++) { len = _tcslen(p); if (len > 0) { argv[argc] = _strdup(NH_W2A(p, buf, BUFSZ)); } else { argv[argc] = ""; } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); resuming = pcmain(argc, argv); moveloop(resuming); return 0; } // // FUNCTION: InitInstance(HANDLE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable // and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { return TRUE; } PNHWinApp GetNHApp() { return &_nethack_app; } static int eraseoldlocks() { register int i; /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for (i = 1; i <= MAXDUNGEON * MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) unlink(fqname(lock, LEVELPREFIX, 0)); } set_levelfile_name(lock, 0); if (unlink(fqname(lock, LEVELPREFIX, 0))) return 0; /* cannot remove it */ return (1); /* success! */ } void getlock() { const char *fq_lock; char tbuf[BUFSZ]; TCHAR wbuf[BUFSZ]; HANDLE f; int fd; int choice; /* regularize(lock); */ /* already done in pcmain */ Sprintf(tbuf, "%s", fqname(lock, LEVELPREFIX, 0)); set_levelfile_name(lock, 0); fq_lock = fqname(lock, LEVELPREFIX, 1); f = CreateFile(NH_A2W(fq_lock, wbuf, BUFSZ), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (f == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_FILE_NOT_FOUND) goto gotlock; /* no such file */ error("Cannot open %s", fq_lock); } CloseHandle(f); /* prompt user that the game alredy exist */ choice = MessageBox(GetNHApp()->hMainWnd, TEXT("There are files from a game in progress under " "your name. Recover?"), TEXT("Nethack"), MB_YESNO | MB_DEFBUTTON1); switch (choice) { case IDYES: if (recover_savefile()) { goto gotlock; } else { error("Couldn't recover old game."); } break; case IDNO: unlock_file(HLOCK); error("%s", "Cannot start a new game."); break; }; gotlock: fd = creat(fq_lock, FCMASK); if (fd == -1) { error("cannot creat lock file (%s.)", fq_lock); } else { if (write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)) { error("cannot write lock (%s)", fq_lock); } if (close(fd) == -1) { error("cannot close lock (%s)", fq_lock); } } } /* misc functions */ void error VA_DECL(const char *, s) { TCHAR wbuf[1024]; char buf[1024]; DWORD last_error = GetLastError(); VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); vsprintf(buf, s, VA_ARGS); NH_A2W(buf, wbuf, sizeof(wbuf) / sizeof(wbuf[0])); if (last_error > 0) { LPVOID lpMsgBuf; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, 0, // Default language (LPTSTR) &lpMsgBuf, 0, NULL)) { _tcsncat(wbuf, TEXT("\nSystem Error: "), sizeof(wbuf) / sizeof(wbuf[0]) - _tcslen(wbuf)); _tcsncat(wbuf, lpMsgBuf, sizeof(wbuf) / sizeof(wbuf[0]) - _tcslen(wbuf)); // Free the buffer. LocalFree(lpMsgBuf); } } MessageBox(NULL, wbuf, TEXT("Error"), MB_OK | MB_ICONERROR); VA_END(); exit(EXIT_FAILURE); } TCHAR * _get_cmd_arg(TCHAR *pCmdLine) { static TCHAR *pArgs = NULL; TCHAR *pRetArg; BOOL bQuoted; if (!pCmdLine && !pArgs) return NULL; if (!pArgs) pArgs = pCmdLine; /* skip whitespace */ for (pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg)) ; if (!*pRetArg) { pArgs = NULL; return NULL; } /* check for quote */ if (*pRetArg == TEXT('"')) { bQuoted = TRUE; pRetArg = CharNext(pRetArg); pArgs = _tcschr(pRetArg, TEXT('"')); } else { /* skip to whitespace */ for (pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs)) ; } if (pArgs && *pArgs) { TCHAR *p; p = pArgs; pArgs = CharNext(pArgs); *p = (TCHAR) 0; } else { pArgs = NULL; } return pRetArg; } /* * Strip out troublesome file system characters. */ void nt_regularize(s) /* normalize file name */ register char *s; { register unsigned char *lp; for (lp = s; *lp; lp++) if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/' || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|' || *lp == ':' || (*lp > 127)) *lp = '_'; } void win32_abort() { if (wizard) DebugBreak(); abort(); } void append_port_id(buf) char *buf; { char *portstr = PORT_CE_PLATFORM " " PORT_CE_CPU; Sprintf(eos(buf), " %s", portstr); } nethack-3.6.0/sys/wince/winhack.rc0000664000076400007660000002601612536476415016054 0ustar paxedpaxed//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "newres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_WINHACK ICON DISCARDABLE "..\\..\\wince\\NETHACK.ICO" ///////////////////////////////////////////////////////////////////////////// // // Menubar // IDC_WINHACK MENU DISCARDABLE BEGIN POPUP "File" BEGIN MENUITEM "&Save", IDM_SAVE MENUITEM SEPARATOR MENUITEM "&Quit", IDM_EXIT END POPUP "Map" BEGIN MENUITEM "&0 - Use Tiles", IDM_MAP_TILES MENUITEM "&1 - ASCII (4x6)", IDM_MAP_ASCII4X6 MENUITEM "&2 - ASCII (6x8)", IDM_MAP_ASCII6X8 MENUITEM "&3 - ASCII (8x8)", IDM_MAP_ASCII8X8 MENUITEM "&4 - ASCII (16x8)", IDM_MAP_ASCII16X8 MENUITEM "&5 - ASCII (7x12)", IDM_MAP_ASCII7X12 MENUITEM "&6 - ASCII (8x12)", IDM_MAP_ASCII8X12 MENUITEM "&7 - ASCII (16x12)", IDM_MAP_ASCII16X12 MENUITEM "&8 - ASCII (12x16)", IDM_MAP_ASCII12X16 MENUITEM "&9 - ASCII (10x18)", IDM_MAP_ASCII10X18 MENUITEM SEPARATOR MENUITEM "&Fit To Screen", IDM_MAP_FIT_TO_SCREEN END POPUP "View" BEGIN MENUITEM "&Keypad", IDM_VIEW_KEYPAD MENUITEM "&Options", IDM_VIEW_OPTIONS END POPUP "Help" BEGIN MENUITEM "&About ...", IDM_ABOUT MENUITEM "&Long description of the game", IDM_HELP_LONG MENUITEM "List of &commands", IDM_HELP_COMMANDS MENUITEM "&History of NetHack", IDM_HELP_HISTORY MENUITEM "&Info on a character", IDM_HELP_INFO_CHAR MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY MENUITEM "List of game &options", IDM_HELP_OPTIONS MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG MENUITEM "List of e&xtended commands", IDM_HELP_EXTCMD MENUITEM "The &NetHack license", IDM_HELP_LICENSE END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_WINHACK ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 123, 87 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN LTEXT "NetHack",IDC_ABOUT_VERSION,0,2,120,15,SS_NOPREFIX LTEXT "Copyright",IDC_ABOUT_COPYRIGHT,0,20,120,50 DEFPUSHBUTTON "OK",IDOK,45,75,30,11,WS_GROUP END IDD_MENU DIALOG DISCARDABLE 0, 0, 109, 153 STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,5,130,50,14,BS_NOTIFY PUSHBUTTON "Cancel",IDCANCEL,55,130,50,14,BS_NOTIFY CONTROL "List1",IDC_MENU_LIST,"SysListView32",WS_BORDER | WS_TABSTOP,5,5,100,60 EDITTEXT IDC_MENU_TEXT,5,70,100,55,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_GETLIN DIALOG DISCARDABLE 0, 0, 115, 30 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,0,16,55,14 PUSHBUTTON "Cancel",IDCANCEL,55,16,60,14 EDITTEXT IDC_GETLIN_EDIT,0,0,115,15,ES_AUTOHSCROLL END IDD_PLAYER_SELECTOR DIALOG DISCARDABLE 0, 0, 105, 124 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_PLSEL_NAME,35,0,70,12,ES_AUTOHSCROLL | ES_READONLY LTEXT "Name:",IDC_STATIC,0,0,25,10 CONTROL "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,20,40,10 COMBOBOX IDC_PLSEL_ROLE_LIST,50,20,50,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,45,40,10 COMBOBOX IDC_PLSEL_RACE_LIST,50,45,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_GENDER_RANDOM,"Button", BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,70, 40,10 COMBOBOX IDC_PLSEL_GENDER_LIST,50,70,50,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,95,40,10 COMBOBOX IDC_PLSEL_ALIGN_LIST,50,95,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP GROUPBOX "Role",IDC_STATIC,0,10,105,25,WS_GROUP GROUPBOX "Race",IDC_STATIC,0,35,105,25 GROUPBOX "Gender",IDC_STATIC,0,60,105,25 GROUPBOX "Alignment",IDC_STATIC,0,85,105,25 DEFPUSHBUTTON "Play",IDOK,0,110,55,14 PUSHBUTTON "Quit",IDCANCEL,55,110,50,14 END IDD_NHTEXT DIALOG DISCARDABLE 0, 0, 100, 97 STYLE WS_CHILD | WS_BORDER FONT 8, "System" BEGIN DEFPUSHBUTTON "OK",IDOK,0,80,50,14 PUSHBUTTON "Wrap",IDC_TEXT_TOGGLE_WRAP,50,80,50,14 EDITTEXT IDC_TEXT_CONTROL,5,0,70,75,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_EXTCMD DIALOG DISCARDABLE 0, 0, 109, 114 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Extended Commands" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,75,5,30,14 PUSHBUTTON "Cancel",IDCANCEL,75,20,30,14 LISTBOX IDC_EXTCMD_LIST,5,5,65,105,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""newres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // IDB_TILES BITMAP DISCARDABLE "..\\..\\wince\\tiles.bmp" IDB_MENU_SEL BITMAP DISCARDABLE "..\\..\\wince\\mnsel.bmp" IDB_MENU_UNSEL BITMAP DISCARDABLE "..\\..\\wince\\mnunsel.bmp" IDB_PETMARK BITMAP DISCARDABLE "..\\..\\wince\\petmark.bmp" IDB_MENU_SEL_COUNT BITMAP DISCARDABLE "..\\..\\wince\\mnselcnt.bmp" IDB_KEYPAD BITMAP DISCARDABLE "..\\..\\wince\\keypad.bmp" IDB_MENUBAR BITMAP DISCARDABLE "..\\..\\wince\\menubar.bmp" ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_PLAYER_SELECTOR, DIALOG BEGIN RIGHTMARGIN, 98 BOTTOMMARGIN, 117 END IDD_NHTEXT, DIALOG BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 76 TOPMARGIN, 7 BOTTOMMARGIN, 94 END IDD_EXTCMD, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 102 TOPMARGIN, 7 BOTTOMMARGIN, 107 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Data // IDC_WINHACK SHMENUBAR DISCARDABLE BEGIN IDC_WINHACK, 6, I_IMAGENONE, ID_FILE, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_FILE, 0, 0, I_IMAGENONE, ID_MAP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_MAP, 0, 1, I_IMAGENONE, ID_VIEW, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_VIEW, 0, 2, I_IMAGENONE, ID_HELP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_HELP, 0, 3, 0, IDM_MAP_FIT_TO_SCREEN, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, IDM_MAP_FIT_TO_SCREEN, NOMENU, 1, IDM_VIEW_KEYPAD, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, IDM_VIEW_KEYPAD, NOMENU, END #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,5,0,0 PRODUCTVERSION 3,5,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "NetHack 3.6.0 for Windows CE\0" VALUE "CompanyName", " \0" VALUE "FileDescription", "nethackm\0" VALUE "FileVersion", "3, 5, 0, 0\0" VALUE "InternalName", "nethackm\0" VALUE "LegalCopyright", "Copyright 1985-2009\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "nethackm.exe\0" VALUE "PrivateBuild", "090914\0" VALUE "ProductName", "NetHack\0" VALUE "ProductVersion", "3, 5, 0, 0\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // !_MAC ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "NetHack" IDC_WINHACK "NETHACK" END STRINGTABLE DISCARDABLE BEGIN IDM_MAP_FIT_TO_SCREEN "Fit to Screen" IDS_CAP_FILE "File" IDS_CAP_HELP "Help" IDS_CAP_MAP "Map" END STRINGTABLE DISCARDABLE BEGIN IDM_VIEW_KEYPAD "Show/Hide keypad." IDS_CAP_VIEW "View" IDS_TEXT_WRAP "Wrap" IDS_TEXT_UNWRAP "Unwrap" END STRINGTABLE DISCARDABLE BEGIN IDOK "Done" IDCANCEL "Cancel" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED nethack-3.6.0/sys/wince/winhcksp.rc0000664000076400007660000002350512536476415016256 0ustar paxedpaxed//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "newres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_WINHACK ICON DISCARDABLE "..\\..\\wince\\NETHACK.ICO" ///////////////////////////////////////////////////////////////////////////// // // Menubar // IDC_WINHACK MENU DISCARDABLE BEGIN MENUITEM "Entire Map", IDM_MAP_FIT_TO_SCREEN POPUP "Menu" BEGIN MENUITEM "Options", IDM_VIEW_OPTIONS MENUITEM "Keypad", IDM_VIEW_KEYPAD MENUITEM "Cmd", IDM_DIRECT_COMMAND MENUITEM SEPARATOR MENUITEM "ASCII", IDM_MAP_ASCII8X8 MENUITEM "Tiles", IDM_MAP_TILES MENUITEM SEPARATOR MENUITEM "Help", IDM_HELP_MENU MENUITEM "Save", IDM_SAVE MENUITEM "Quit", IDM_EXIT END END IDC_SPHONE_DIALOGBAR MENU DISCARDABLE BEGIN MENUITEM "Done", IDOK MENUITEM "Cancel", IDCANCEL END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_WINHACK ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 123, 87 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN LTEXT "NetHack",IDC_ABOUT_VERSION,0,2,120,15,SS_NOPREFIX LTEXT "Copyright",IDC_ABOUT_COPYRIGHT,0,20,120,50 DEFPUSHBUTTON "OK",IDOK,45,75,30,11,WS_GROUP END IDD_MENU DIALOG DISCARDABLE 0, 0, 109, 131 STYLE DS_SETFOREGROUND | DS_CONTROL | WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER FONT 8, "MS Sans Serif" BEGIN CONTROL "List1",IDC_MENU_LIST,"SysListView32",WS_BORDER | WS_TABSTOP,5,5,100,60 EDITTEXT IDC_MENU_TEXT,5,70,100,55,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_NHTEXT DIALOG DISCARDABLE 0, 0, 83, 83 STYLE WS_POPUP | WS_BORDER FONT 8, "System" BEGIN EDITTEXT IDC_TEXT_CONTROL,5,0,70,75,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_EXTCMD DIALOG DISCARDABLE 0, 0, 88, 82 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Extended Commands" FONT 8, "MS Sans Serif" BEGIN LISTBOX IDC_EXTCMD_LIST,7,5,75,69,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END IDD_GETLIN DIALOG DISCARDABLE 0, 0, 115, 16 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_GETLIN_EDIT,0,0,115,15,ES_AUTOHSCROLL END IDD_PLAYER_SELECTOR DIALOG DISCARDABLE 0, 0, 105, 124 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_PLSEL_NAME,35,0,70,12,ES_AUTOHSCROLL | ES_READONLY LTEXT "Name:",IDC_STATIC,0,0,25,10 CONTROL "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,20,40,10 COMBOBOX IDC_PLSEL_ROLE_LIST,50,20,50,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,45,40,10 COMBOBOX IDC_PLSEL_RACE_LIST,50,45,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_GENDER_RANDOM,"Button", BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,70, 40,10 COMBOBOX IDC_PLSEL_GENDER_LIST,50,70,50,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,95,40,10 COMBOBOX IDC_PLSEL_ALIGN_LIST,50,95,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP GROUPBOX "Role",IDC_STATIC,0,10,105,25,WS_GROUP GROUPBOX "Race",IDC_STATIC,0,35,105,25 GROUPBOX "Gender",IDC_STATIC,0,60,105,25 GROUPBOX "Alignment",IDC_STATIC,0,85,105,25 DEFPUSHBUTTON "Play",IDOK,0,110,55,14 PUSHBUTTON "Quit",IDCANCEL,55,110,50,14 END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""newres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // IDB_TILES BITMAP DISCARDABLE "..\\..\\wince\\tiles.bmp" IDB_MENU_SEL BITMAP DISCARDABLE "..\\..\\wince\\mnsel.bmp" IDB_MENU_UNSEL BITMAP DISCARDABLE "..\\..\\wince\\mnunsel.bmp" IDB_PETMARK BITMAP DISCARDABLE "..\\..\\wince\\petmark.bmp" IDB_MENU_SEL_COUNT BITMAP DISCARDABLE "..\\..\\wince\\mnselcnt.bmp" IDB_KEYPAD BITMAP DISCARDABLE "..\\..\\wince\\keypad.bmp" ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_NHTEXT, DIALOG BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 76 TOPMARGIN, 7 END IDD_EXTCMD, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 82 TOPMARGIN, 7 BOTTOMMARGIN, 75 END IDD_PLAYER_SELECTOR, DIALOG BEGIN RIGHTMARGIN, 98 BOTTOMMARGIN, 117 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Data // IDC_WINHACK SHMENUBAR DISCARDABLE BEGIN IDC_WINHACK, 2, I_IMAGENONE, IDM_MAP_FIT_TO_SCREEN, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDM_MAP_FIT_TO_SCREEN, 0, NOMENU, I_IMAGENONE, ID_VIEW, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_VIEW, 0, 1, END IDC_SPHONE_DIALOGBAR SHMENUBAR DISCARDABLE BEGIN IDC_SPHONE_DIALOGBAR, 2, I_IMAGENONE, IDOK, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDOK, 0, NOMENU, I_IMAGENONE, IDCANCEL, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDCANCEL, 0, NOMENU, END IDC_SPHONE_TEXTDIALOGBAR SHMENUBAR DISCARDABLE BEGIN IDC_SPHONE_DIALOGBAR, 2, I_IMAGENONE, IDOK, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDOK, 0, NOMENU, I_IMAGENONE, IDC_TEXT_TOGGLE_WRAP, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDS_TEXT_WRAP, 0, NOMENU, END #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,5,0,0 PRODUCTVERSION 3,5,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "NetHack 3.6.0 for Smartphone 2002\0" VALUE "CompanyName", " \0" VALUE "FileDescription", "nethackm\0" VALUE "FileVersion", "3, 5, 0, 0\0" VALUE "InternalName", "nethackm\0" VALUE "LegalCopyright", "Copyright 1985-2010\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "nethackm.exe\0" VALUE "PrivateBuild", "090914\0" VALUE "ProductName", "NetHack For Smartphone\0" VALUE "ProductVersion", "3, 5, 0, 0\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // !_MAC ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "NetHack" IDC_WINHACK "NETHACK" END STRINGTABLE DISCARDABLE BEGIN IDM_MAP_FIT_TO_SCREEN "Entire Map" IDS_CAP_FILE "File" IDS_CAP_HELP "Help" IDS_CAP_MAP "Map" END STRINGTABLE DISCARDABLE BEGIN IDM_VIEW_KEYPAD "Show/Hide keypad." IDS_CAP_VIEW "Menu" END STRINGTABLE DISCARDABLE BEGIN IDOK "Done" IDCANCEL "Cancel" END STRINGTABLE DISCARDABLE BEGIN IDS_CAP_ENTIREMAP "Entire Map" IDS_CAP_NORMALMAP "Normal Map" IDM_HELP_MENU "Help Menu" IDS_TEXT_WRAP "Wrap" IDS_TEXT_UNWRAP "Unwrap" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED nethack-3.6.0/sys/wince/winmain.c0000664000076400007660000000531512536476415015707 0ustar paxedpaxed// winmain.cpp : Defines the entry point for the application. // // $NHDT-Date: 1432512799 2015/05/25 00:13:19 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ #include "winMS.h" #include #define MAX_CMDLINE_PARAM 255 extern int FDECL(main, (int, char **)); static TCHAR *_get_cmd_arg(TCHAR *pCmdLine); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { int argc; char *argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR *p; TCHAR wbuf[NHSTR_BUFSIZE]; char buf[NHSTR_BUFSIZE]; /* get command line parameters */ p = _get_cmd_arg( #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) lpCmdLine #else GetCommandLine() #endif ); for (argc = 1; p && argc < MAX_CMDLINE_PARAM; argc++) { len = _tcslen(p); if (len > 0) { argv[argc] = _strdup(NH_W2A(p, buf, BUFSZ)); } else { argv[argc] = ""; } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); main(argc, argv); return 0; } TCHAR * _get_cmd_arg(TCHAR *pCmdLine) { static TCHAR *pArgs = NULL; TCHAR *pRetArg; BOOL bQuoted; if (!pCmdLine && !pArgs) return NULL; if (!pArgs) pArgs = pCmdLine; /* skip whitespace */ for (pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg)) ; if (!*pRetArg) { pArgs = NULL; return NULL; } /* check for quote */ if (*pRetArg == TEXT('"')) { bQuoted = TRUE; pRetArg = CharNext(pRetArg); pArgs = _tcschr(pRetArg, TEXT('"')); } else { /* skip to whitespace */ for (pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs)) ; } if (pArgs && *pArgs) { TCHAR *p; p = pArgs; pArgs = CharNext(pArgs); *p = (TCHAR) 0; } else { pArgs = NULL; } return pRetArg; } #ifndef STRNCMPI char lowc(c) /* force 'c' into lowercase */ char c; { return ((char) (('A' <= c && c <= 'Z') ? (c | 040) : c)); } int strncmpi(s1, s2, n) /* case insensitive counted string comparison */ register const char *s1, *s2; register int n; /*(should probably be size_t, which is usually unsigned)*/ { /*{ aka strncasecmp }*/ register char t1, t2; while (n--) { if (!*s2) return (*s1 != 0); /* s1 >= s2 */ else if (!*s1) return -1; /* s1 < s2 */ t1 = lowc(*s1++); t2 = lowc(*s2++); if (t1 != t2) return (t1 > t2) ? 1 : -1; } return 0; /* s1 == s2 */ } #endif /* STRNCMPI */ nethack-3.6.0/sys/winnt/Install.nt0000664000076400007660000005076112623532454016102 0ustar paxedpaxed Copyright (c) NetHack Development Team 1990-2015 NetHack may be freely redistributed. See license for details. ============================================================== Instructions for compiling and installing NetHack 3.6 on a Windows system (Windows 7/8.x/10 or later only. XP may work but is untested) ============================================================== Last revision: $NHDT-Date: 1447979773 2015/11/20 00:36:13 $ Credit for the porting of NetHack to the Win32 Console Subsystem goes to the NT Porting Team started by Michael Allison. Credit for the Win32 Graphical version of NetHack (aka "NetHack for Windows" or NetHackW) goes to Alex Kompel who initially developed and contributed the port. The PC Windows porting team consisting of Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, Yitzhak Sapir, and Janet Walz maintained the tty and graphical win32 versions of NetHack 3.6.0. You can build a TTY version of NetHack and a Windows Graphical version. You can use one of the following build environments: o A copy of Microsoft Visual Studio 2013 Express The current NetHack code has not been tested with earlier versions of the compiler. OR o A copy of MinGW. MinGW is a collection of header files and import libraries with which native Windows32 programs can be built; the MinGW distribution contains the GNU Compiler Collection. You can download MinGW at http://www.mingw.org/ Earlier versions of MinGW will not allow you to build the Windows Graphical version. In addition to the makefiles that allow you to build NetHack from the command line, there is also a set of project files and a workspace file that allow you to build the Windows Graphical version from Microsoft Visual C's IDE (Integrated Development Environment.) /-----------------------------------\ | FIRST STEP - MOVING THINGS AROUND | \-----------------------------------/ The first step in building either version of NetHack is to execute sys\winnt\nhsetup.bat to move some files to their required locations. From the command prompt: cd sys\winnt nhsetup From a Windows explorer window: double-click on nhsetup.bat A "binary" directory will be created off the top of the NetHack source tree to house the completed build. A build subdirectory will also be created off the top of the NetHack source tree, and many files appropriate for a graphical build will be moved there. If you wish to build from the command line, proceed to "BUILDING FROM THE COMMAND LINE." If you wish to build using Visual C's IDE, proceed now to "BUILDING USING VISUAL C'S IDE." /--------------------------------\ | BUILDING FROM THE COMMAND LINE | \--------------------------------/ Two different versions of NetHack will be built for Windows from the command line using the Makefile approach: A tty port utilizing the Win32 Console I/O subsystem, Console NetHack; A Win32 native port built on the Windows API, Graphical NetHack or NetHackW. The executable for Console NetHack will be named NetHack.exe. The executable for Graphical NetHack will be named NetHackW.exe. The Makefile configuration will build both; NetHackW.exe and NetHack.exe will be able to use the same datafiles, save files and bones files. Since the last official release of NetHack, compilers and computer architectures have evolved and you can now choose whether to build a 32-bit x86 version, or a 64-bit x64 version. The default Makefile is set up for a 32-bit x86 version, but that's only because it will run on the most number of existing Windows environments. NetHack's save files and bones files in the 3.6.0 release have not evolved enough to allow them to interchange between the 32-bit version and the 64-bit version (or between different platforms). Hopefully that will change in an upcoming release. I. Dispelling the Myths: Compiling NetHack for Windows is not as easy as it sounds, nor as hard as it looks, however it will behoove you to read this entire section through before beginning the task. We have provided a Makefile for each of the following compilers: o Microsoft Visual Studio 2013 Express Visual C++ Compiler o MinGW 2.0 (with GCC 3.2) The Microsoft Visual Studio 2013 Express Makefile was created for use with MS NMAKE which is provided with the Microsoft compiler. The supplied Makefile may work with earlier versions of the Microsoft compiler, but that has not been tested. The GCC Makefile was created for use with GNU Make version 3.79.1, which comes with the MinGW package. You may find it useful to obtain copies of lex (flex) and yacc (bison, or byacc). While not strictly necessary to compile nethack, they are required should you desire to make any changes to the level and dungeon compilers. II. To compile your copy of NetHack on a Windows machine: Setting Up 1. It almost goes without saying that you should make sure that your tools are set up and running correctly. That includes ensuring that all the necessary environment variables for the compiler environment are set correctly. Visual Studio 2013 Express The installation should have placed a command prompt option on the Start menus that is properly configured for building: From Start | All Programs | Microsoft Visual Studio 2013 Express Select Visual Studio Command Prompt 2013 Anyway, once you are at a command prompt (cmd.exe) regardless of how you got there, you can use one of the following sets of commands to prepare your environment for building: For a 32-bit x86 build (like the official binary): cd "\Program Files (x86)\Microsoft Visual Studio 12.0\VC" vcvarsall x86 For a 64-bit x64 build: cd "\Program Files (x86)\Microsoft Visual Studio 12.0\VC" vcvarsall x86_amd64 ----------------------------------------------------------- vcvarsall.bat | Compiler | Build-computer | Build output argument | | architecture | architecture --------------+------------+----------------+-------------- X86 | x86 32-bit | x86, x64 | x86 | native | | --------------+------------+----------------+-------------- x86_amd64 | x64 on x86 | x86, x64 | x64 | cross | | --------------+------------+----------------+-------------- amd64 | x64 64-bit | x64 | x64 | native | | --------------+------------+----------------+-------------- amd64_x86 | x86 on | x64 | x86 | x64 cross | | ----------------------------------------------------------- Change your current directory to the src subfolder of the nethack source tree. cd src At this time, if you are determined to build an x64 version with the Microsoft Visual Studio 2013 compiler, one extra NetHack-specific step is needed. Edit the Makefile in the src directory and change this in the section marked as 1.: # # 64 bit #TARGET_CPU=x64 # # 32 bit TARGET_CPU=x86 to this: # # 64 bit TARGET_CPU=x64 # # 32 bit #TARGET_CPU=x86 GCC For the GCC Makefile, add \bin to your path, where is your MinGW root directory.). Change your current directory to src subfolder of the nethack source tree. cd src 2. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, sys\share, sys\winnt, util, and binary (The "binary" directory was created by nhsetup.bat earlier if you followed the steps appropriately). For Console NetHack you need win\tty in addition to these; for Graphical NetHack you need win\win32 in addition to these. Other subdirectories may also be included in your distribution, but they are not necessary for building the TTY version for the Win32 console subsystem. You can delete them to save space. Required Directories for a Win32 Console NetHack: top | ----------------------------------------------------/ /----- | | | | | | | | util dat doc include src sys win binary | | ------ ----- | | | share winnt tty Required Directories for a Win32 Graphical NetHack: top | ----------------------------------------------------/ /----- | | | | | | | | util dat doc include src sys win binary | | ------ ----- | | | share winnt win32 Check the file "Files" in your top level directory for an exact listing of what file is in which directory. In order for the Makefiles to work, all the source files must be in the proper locations. If you downloaded or ftp'd the sources from a UNIX system, the lines will probably end in UNIX-style newlines, instead of the carriage return and line feed pairs used by Windows. Some programs have trouble with them, so you may need to convert them. The compiler should not have any problems with them however. 3. Now go to the include subdirectory to check a couple of the header files there. Things *should* work as they are, but since you have probably set up your system in some sort of custom configuration it doesn't hurt to check out the following: First check config.h according to the comments to match your system and desired set of features. Mostly you need to check section 4 and 5. You may include all or as few of the special game features as you wish (they are located last in the file). 4. Edit your Makefile if you wish, but it is not required unless you are altering the build options. If you are recompiling after patching your sources, or if you got your files from somewhere other than the official distribution, "touch makedefs.c" to ensure that certain files (onames.h and pm.h) are remade, lest potentially troublesome timestamps fool your make (or nmake) utility. Compiling 5. Now that everything is set up... For Visual Studio 2013 Express, as mentioned above, you should now be at the command prompt to carry out the build and your current directory should be the src subdirectory in the NetHack source tree. In the src subdirectory, issue this command: nmake install For GCC: Change your current directory to the NetHack src directory. Issue this command: mingw32-make -f Makefile.gcc install If you get any errors along the way then something has not been set up correctly. The time it takes to compile depends on your particular machine of course, but you should be able to go for lunch and return to find everything finished. The less memory, and slower your machine, the longer the lunch you may take. :-) In any case, it is likely that the command prompt window where you are doing the compiling will be occupied for a while. If all goes well, you will get an NetHack executable. Notes: 1. To install an update of NetHack after changing something, change your current directory to src and issue the appropriate command for your compiler: For Microsoft compiler: nmake For GCC: mingw32-make -f Makefile.gcc If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but usually crashes.) If you made changes to any of the level compiler software, you may have to delete dgn_flex.c, dgn_yacc.c, lev_flex.c, and lev_yacc.c from the util directory to ensure that they are remade. 2. Depending on the build and compiler and tools used above, the executable produced by the TTY build is either: - a 32-bit (x86), flat-address space, non-overlayed .exe file, which should run on any recent Win32 environment. or - a 64-bit (x64) .exe file, which should run on any 64-bit Windows O/S. To run NetHack, proceed to RUNNING NETHACK. /-------------------------------------------------\ | BUILDING USING VISUAL STUDIO 2013 EXPRESS IDE | \-------------------------------------------------/ Only the native port built on the Windows API, or Graphical NetHack, can be built using the Visual Studo 2013 Express IDE. I. Dispelling the Myths: Compiling NetHack using the Visual C IDE is straightforward, as long as you have your compiler and tools correctly installed. It is again assumed that you already changed your directory to sys\winnt and executed: nhsetup as described at the top of this document. If you didn't, you must go back and do so before proceeding. II. To compile your copy of NetHack for Windows on a Windows machine using the Visual Studio 2013 Express IDE: Setting Up 1. It almost goes without saying that you should make sure that your tools are set up and running correctly. (For the Microsoft Visual Studio 2013 ExpressIDE it should correctly fire up when you choose it: Start | All Programs | Microsoft Visual Studio 2013 Express and select Visual C++ 2013 Express 2. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, sys\share, sys\winnt, util, win\win32, and at this point you should also have a build directory and a binary directory (both created by nhsetup.bat executed from sys\winnt earlier.) Other subdirectories may also be included in your distribution, but they are not necessary for building the graphical version of NetHack (you can delete them to save space if you wish.) Required Directories for building Graphical NetHack with the Visual C IDE: top | -----------------------------------------/ /--------------- | | | | | | | | | util dat doc include src sys win build binary | | ------ ----- | | | share winnt win32 Those last two (build and binary) are created during the building process. They are not disributed as part of the NetHack source distribution. nhsetup.bat creates the build directory and moves a few files into it, including the Visual C project files. The "binary" directory will house everything you need to play the game after building is complete. Check the file "Files" in your top level directory for an exact listing of what file is in which directory. In order for the build process to work, all the source files must be in the proper locations. Remember that nhsetup.bat moves/copies many files around to their intended locations for building NetHack. If you downloaded or ftp'd the sources from a UNIX system, the lines will probably end in UNIX-style newlines, instead of the carriage return and line feed pairs used by Windows. Visual C project files and workspace files (dsp and dsw files) in particular need to have their lines end in carriage-return-line-feed or they won't work properly. 3. Ready your tool. Note: It's possible to build a graphical version using the Makefile, as explained above. However, the IDE build has full game functionality. Start the Visual Studio 2013 Express IDE: Start | All Programs | Microsoft Visual Studio 2013 Express and select Visual C++ 2013 Express In the Visual C++ 2013 Express IDE menus, choose: File | Open Project/Solution 4. Set up for the build. In the Visual C dialog box, navigate to the top of your NetHack source directory. In there, highlight "nethack.sln" for Visual C++ 2013 Express Edition and click on Open. Once the workspace or solution has been opened, you should see the following list in the Visual C selection left pane: + dgncomp + dgnstuff + dlb_main + levcomp + levstuff + makedefs + nethackw + recover + tile2bmp + tilemap + uudecode On the Visual C++ 2013 Express IDE menus, NetHackW should be the startup project in bold, but if it isn't make it so by right-clicking and choosing "set as Startup Project." In Visual C 2013 Express IDE menus right-click on "Solution NetHack (14 Projects)" and select "Configuration Manager." Set the "Active Solution Configuration" to either Debug or Release and click the "Close" button. The Release build of NetHackW which does not contain all the debugging information and is smaller, and runs slightly quicker. The Debug build of NetHackW will spend time writing debug information to the disk as the game is played. Unless you are debugging or enhancing NetHack for Windows, you probably will want to choose the Release build. Building 5. Start your build. On the Visual C++ Express IDE menus once again, choose: Debug | Build Solution or press to accomplish the same thing. That starts the build. It is likely that the IDE message window where you are doing the compiling will be occupied for a while. 6. If all has gone well to this point, you should now have a NetHack executable called NetHackW.exe in the "binary" directory, along with all the support files that it needs. /-----------------\ | RUNNING NETHACK | \-----------------/ I. Checking the installation: Make sure all of the support files -- Guidebook.txt, license, Defaults.nh, NetHack.exe or NetHackW.exe, nhdat, and recover.exe -- were copied to the game directory. If not, move them there yourself. Edit Defaults.nh to reflect your particular setup and personal preferences, by following the comments. As with all releases since 3.2.1, HACKDIR defaults to the same directory as that where the NetHack.exe or NetHackW.exe executable resides. You only need to set HACKDIR in defaults.nh if, for some reason, you wish to override that (be careful). II. Executing the game 1. Running from the command prompt: If you add the directory containing the NetHack executable to your PATH, you can just type "nethack" or "nethack -umike" or "nethackw" or "nethackw -umike" to start it up. Alternatively, you can explicitly invoke it with a command such as "c:\nethack\binary\nethack.exe" or "c:\nethack\binary\nethackw.exe" (specifying whatever drive and directory your NetHack executable resides in) each time. 2. Running from a Windows shortcut. If you will be running it by launching it from a shortcut, just use the following information when setting up the shortcut. Description : NetHack 3.6.0 Console version Command Line : C:\NETHACK\BINARY\NETHACK.EXE Description : NetHack 3.6.0 Graphical Interface Command Line : C:\NETHACK\BINARY\NETHACKW.EXE (changing the directory to the appropriate one of course) III. Play NetHack. If it works, you're done! PROBLEMS If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: http://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: DevTeam (at) nethack.org Happy NetHacking! nethack-3.6.0/sys/winnt/Makefile.gcc0000664000076400007660000013517012541713002016307 0ustar paxedpaxed# NetHack 3.6 Makefile.gcc $NHDT-Date: 1434804544 2015/06/20 12:49:04 $ $NHDT-Branch: win32-x64-working $:$NHDT-Revision: 1.53 $ # #============================================================================== # # Win32 Compilers Tested: # === TDM-GCC Compiler Suite for Windows === # --- GCC 4.6 & 4.7 Series --- # *** Standard MinGW 32-bit Edition *** # # If you don't have this compiler, you can get it at: # http://tdm-gcc.tdragon.net/ # #============================================================================== # This is used for building two versions of NetHack: # # A tty port utilizing the Win32 Console I/O subsystem, Console # NetHack. # # A Win32 native port built on the Windows API, Graphical NetHack or # NetHackW. # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc (such as bison) # .l lex (such as flex) # # If you have any questions read the sys/winnt/Install.nt file included # with the distribution. #============================================================================== # BUILD DECISIONS SECTION # # There are currently only 3 decisions that you have to make. # 1. 32-bit or 64-bit? # 2. Where do you want your build to end up? # 3. Do you want debug information in the executable? # #============================================================================== # 1. 32-bit or 64-bit? # # 64 bit #TARGET_CPU=x64 # # 32 bit TARGET_CPU=x86 # #--------------------------------------------------------------- # 2. Where do you want the game to be built (which folder)? # If not present prior to compilation it gets created. # GAMEDIR = ../binary # #--------------------------------------------------------------- # 3. Do you want debug information in the executable? # DEBUGINFO = Y # This marks the end of the BUILD DECISIONS section. #============================================================================== # #=============================================== #======= End of Modification Section =========== #=============================================== # ################################################ # # # Nothing below here should have to be changed.# # # ################################################ # # Source directories. Makedefs hardcodes these, don't change them. # # NetHack include files INCL = ../include # NetHack data files DAT = ../dat # NetHack documentation files DOC = ../doc # Utility source UTIL = ../util # Main source SRC = ../src # Shared system files SSYS = ../sys/share # NT Win32 specific files MSWSYS = ../sys/winnt # window port files (tty) TTY = ../win/tty # window port files (WIN32) MSWIN = ../win/win32 # Tile support files WSHR = ../win/share # # Object directory. # OBJ = o cc = gcc rc = windres link = gcc # #========================================== # Level Compiler Info #========================================== # Yacc/Lex ... if you got 'em. # # If you have yacc and lex programs (or work-alike such as bison # and flex), comment out the upper two macros and uncomment # the lower two. # DO_YACC = YACC_MSG DO_LEX = LEX_MSG #DO_YACC = YACC_ACT #DO_LEX = LEX_ACT # - Specify your yacc and lex programs (or work-alikes) here. #YACC = bison -y YACC = byacc #YACC = yacc #LEX = lex LEX = flex # # - Specify your flex skeleton file (if needed). # FLEXSKEL = #FLEXSKEL = -S../tools/flex.ske YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c #========================================== # Exe File Info. #========================================== # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)/random.o #RANDOM = WINPFLAG = -DTILES -DMSWIN_GRAPHICS -DWIN32CON -D_WIN32_IE=0x0400 -D_WIN32_WINNT=0x0501 # To store all the level files, # help files, etc. in a single library file. # USE_DLB = Y is left uncommented USE_DLB = Y ifeq "$(USE_DLB)" "Y" DLBFLG = -DDLB else DLBFLG = endif #========================================== # Setting up the compiler and linker # macros. All builds include the base ones. #========================================== cflags = -mms-bitfields lflags = ifeq "$(DEBUGINFO)" "Y" cdebug = -g linkdebug = -g else cdebug = linkdebug = endif CFLAGSBASE = -c $(cflags) -I$(INCL) $(WINPINC) $(cdebug) #LFLAGSBASEC = $(linkdebug) #LFLAGSBASEG = $(linkdebug) -mwindows conlibs = -lwinmm guilibs = -lcomctl32 -lwinmm #========================================== # Util builds #========================================== CFLAGSU = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG) LFLAGSU = $(LFLAGSBASEC) #========================================== # - Game build #========================================== CFLAGS = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG) lflags = $(LFLAGSBASEC) $(linkdebuf) ifeq "$(USE_DLB)" "Y" DLB = nhdat else DLB = endif #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # DEFFILE = $(MSWSYS)/$(GAME).def # # Shorten up the location for some files # O = $(OBJ)/ U = $(UTIL)/ # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o \ $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o TILEFILES = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt # # These are not invoked during a normal game build in 3.4 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o TEXT_IO32 = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREADERS32 = $(O)gifrd32.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o VOBJ10 = $(O)mail.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o VOBJ14 = $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ15 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o VOBJ16 = $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o VOBJ17 = $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o VOBJ18 = $(O)quest.o $(O)questpgr.o $(RANDOM) $(O)read.o VOBJ19 = $(O)rect.o $(O)region.o $(O)restore.o $(O)rip.o VOBJ20 = $(O)rnd.o $(O)role.o $(O)rumors.o $(O)save.o VOBJ21 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o VOBJ22 = $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ23 = $(O)sys.o $(O)teleport.o $(O)timeout.o $(O)topten.o VOBJ24 = $(O)track.o $(O)trap.o $(O)u_init.o $(O)uhitm.o VOBJ25 = $(O)vault.o $(O)vis_tab.o $(O)vision.o $(O)weapon.o VOBJ26 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wizard.o VOBJ27 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o DLBOBJ = $(O)dlb.o REGEX = $(O)cppregex.o TTYOBJ = $(O)topl.o $(O)getline.o $(O)wintty.o SOBJ = $(O)winnt.o $(O)pcsys.o $(O)pcunix.o \ $(SOUND) $(O)pcmain.o $(O)nhlan.o OBJS = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \ $(VOBJ26) $(VOBJ27) $(REGEX) GUIOBJ = $(O)mhaskyn.o $(O)mhdlg.o \ $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \ $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \ $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o GUIHDR = $(MSWIN)/mhaskyn.h $(MSWIN)/mhdlg.h $(MSWIN)/mhfont.h \ $(MSWIN)/mhinput.h $(MSWIN)/mhmain.h $(MSWIN)/mhmap.h \ $(MSWIN)/mhmenu.h $(MSWIN)/mhmsg.h $(MSWIN)/mhmsgwnd.h \ $(MSWIN)/mhrip.h $(MSWIN)/mhstatus.h \ $(MSWIN)/mhtext.h $(MSWIN)/resource.h $(MSWIN)/winMS.h KEYDLLS = $(GAMEDIR)/nhdefkey.dll $(GAMEDIR)/nh340key.dll $(GAMEDIR)/nhraykey.dll TILEUTIL16 = $(UTIL)/tile2bmp.exe TILEBMP16 = $(SRC)/tiles.bmp TILEUTIL32 = $(UTIL)/til2bm32.exe TILEBMP32 = $(SRC)/tiles32.bmp SOUND = $(OBJ)/ntsound.o #SOUND = VVOBJ = $(O)version.o ALLOBJ = $(SOBJ) $(DLBOBJ) $(WOBJ) $(OBJS) $(VVOBJ) OPTIONS_FILE = $(DAT)\options #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \ $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \ $(INCL)/system.h $(INCL)/unixconf.h $(INCL)/os2conf.h \ $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/tosconf.h \ $(INCL)/amiconf.h $(INCL)/macconf.h $(INCL)/beconf.h \ $(INCL)/ntconf.h HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/align.h $(INCL)/context.h \ $(INCL)/dungeon.h $(INCL)/monsym.h $(INCL)/mkroom.h \ $(INCL)/objclass.h $(INCL)/youprop.h $(INCL)/prop.h \ $(INCL)/permonst.h $(INCL)/monattk.h \ $(INCL)/monflag.h $(INCL)/mondata.h $(INCL)/pm.h \ $(INCL)/wintype.h $(INCL)/decl.h $(INCL)/quest.h \ $(INCL)/spell.h $(INCL)/color.h $(INCL)/obj.h \ $(INCL)/you.h $(INCL)/attrib.h $(INCL)/monst.h $(INCL)/lint.h \ $(INCL)/mextra.h $(INCL)/skills.h $(INCL)/onames.h \ $(INCL)/timeout.h $(INCL)/trap.h $(INCL)/flag.h $(INCL)/rm.h \ $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \ $(INCL)/rect.h $(INCL)/region.h $(INCL)/winprocs.h \ $(INCL)/wintty.h $(INCL)/sys.h $(INCL)/trampoli.h LEV_H = $(INCL)/lev.h DGN_FILE_H = $(INCL)/dgn_file.h LEV_COMP_H = $(INCL)/lev_comp.h SP_LEV_H = $(INCL)/sp_lev.h TILE_H = ../win/share/tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)/data.base #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== $(OBJ)/%.o : /%.c $(cc) $(CFLAGS) -o$@ $< $(OBJ)/%.o : $(SRC)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in sys/share #========================================== $(OBJ)/%.o : $(SSYS)/%.c $(cc) $(CFLAGS) -o$@ $< $(OBJ)/%.o : $(SSYS)/%.cpp g++ $(CFLAGS) -std=c++11 -o$@ $< #========================================== # Rules for files in sys/winnt #========================================== $(OBJ)/%.o : $(MSWSYS)/%.c $(cc) $(CFLAGS) -o$@ $< $(INCL)/%.h : $(MSWSYS)/%.h @copy $< $@ #========================================== # Rules for files in util #========================================== $(OBJ)/%.o : $(UTIL)/%.c $(cc) $(CFLAGSU) -o$@ $< #========================================== # Rules for files in win/share #========================================== $(OBJ)/%.o : $(WSHR)/%.c $(cc) $(CFLAGS) -o$@ $< $(INCL)/%.h : $(WSHR)/%.h @copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # @copy $< $@ #========================================== # Rules for files in win/tty #========================================== $(OBJ)/%.o : $(TTY)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in win/win32 #========================================== $(OBJ)/%.o : $(MSWIN)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== #=============== TARGETS ================== #========================================== # Since DOS doesn't allow / as path separator, and GCC doesn't allow \ as # path separator, we must change all pathnames when performing DOS commands. # This is done by blindly applying $(subst /,\, ...) on every command. # Where any command contain / for another reason (switch char, or echoing # comment lines to lev/dungeon files) a little more care is taken. # # The default make target (so just typing 'nmake' is useful). # default : install # # Everything # all : install install: graphicschk $(O)obj.tag $(GAMEDIR)/NetHack.exe $(GAMEDIR)/NetHackW.exe $(O)install.tag @echo NetHack is up to date. @echo Done. $(O)install.tag: $(DAT)/data $(DAT)/rumors $(DAT)/dungeon \ $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag $(DLB) ifeq "$(USE_DLB)" "Y" $(subst /,\,copy nhdat $(GAMEDIR)) $(subst /,\,copy $(DAT)/license $(GAMEDIR)) $(subst /,\,copy $(DAT)/opthelp $(GAMEDIR)) else $(subst /,\,copy $(DAT)/*. $(GAMEDIR)) $(subst /,\,copy $(DAT)/*.dat $(GAMEDIR)) $(subst /,\,copy $(DAT)/*.lev $(GAMEDIR)) $(subst /,\,if exist $(GAMEDIR)/makefile del $(GAMEDIR)/makefile) endif $(subst /,\,if not exist $(GAMEDIR)/sysconf copy $(MSWSYS)/sysconf $(GAMEDIR)) $(subst /,\,if exist $(DAT)/symbols copy $(DAT)/symbols $(GAMEDIR)) $(subst /,\,if exist $(DOC)/guidebook.txt copy $(DOC)/guidebook.txt $(GAMEDIR)/Guidebook.txt) $(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR)/NetHack.txt) $(subst /,\,copy $(MSWSYS)/defaults.nh $(GAMEDIR)/defaults.nh) $(subst /,\,echo install done > $@) # copy $(MSWSYS)/winnt.hlp $(GAMEDIR) recover: $(U)recover.exe $(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR)) $(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)/recover.txt) $(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des $(DAT)/castle.des \ $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des \ $(DAT)/medusa.des $(DAT)/oracle.des $(DAT)/tower.des \ $(DAT)/yendor.des $(DAT)/arch.des $(DAT)/barb.des \ $(DAT)/caveman.des $(DAT)/healer.des $(DAT)/knight.des \ $(DAT)/monk.des $(DAT)/priest.des $(DAT)/ranger.des \ $(DAT)/rogue.des $(DAT)/samurai.des $(DAT)/sokoban.des \ $(DAT)/tourist.des $(DAT)/valkyrie.des $(DAT)/wizard.des $(subst /,\,$(U)levcomp $(DAT)/bigroom.des) $(subst /,\,$(U)levcomp $(DAT)/castle.des) $(subst /,\,$(U)levcomp $(DAT)/endgame.des) $(subst /,\,$(U)levcomp $(DAT)/gehennom.des) $(subst /,\,$(U)levcomp $(DAT)/knox.des) $(subst /,\,$(U)levcomp $(DAT)/mines.des) $(subst /,\,$(U)levcomp $(DAT)/medusa.des) $(subst /,\,$(U)levcomp $(DAT)/oracle.des) $(subst /,\,$(U)levcomp $(DAT)/sokoban.des) $(subst /,\,$(U)levcomp $(DAT)/tower.des) $(subst /,\,$(U)levcomp $(DAT)/yendor.des) $(subst /,\,$(U)levcomp $(DAT)/arch.des) $(subst /,\,$(U)levcomp $(DAT)/barb.des) $(subst /,\,$(U)levcomp $(DAT)/caveman.des) $(subst /,\,$(U)levcomp $(DAT)/healer.des) $(subst /,\,$(U)levcomp $(DAT)/knight.des) $(subst /,\,$(U)levcomp $(DAT)/monk.des) $(subst /,\,$(U)levcomp $(DAT)/priest.des) $(subst /,\,$(U)levcomp $(DAT)/ranger.des) $(subst /,\,$(U)levcomp $(DAT)/rogue.des) $(subst /,\,$(U)levcomp $(DAT)/samurai.des) $(subst /,\,$(U)levcomp $(DAT)/tourist.des) $(subst /,\,$(U)levcomp $(DAT)/valkyrie.des) $(subst /,\,$(U)levcomp $(DAT)/wizard.des) $(subst /,\,copy *.lev $(DAT)) $(subst /,\,del *.lev) $(subst /,\,echo sp_levs done > $(O)sp_lev.tag) $(O)utility.tag: $(INCL)/date.h $(INCL)/onames.h $(INCL)/pm.h \ $(SRC)/monstr.c $(SRC)/vis_tab.c $(U)levcomp.exe $(INCL)/vis_tab.h \ $(U)dgncomp.exe $(TILEUTIL16) $(subst /,\,@echo utilities made >$@) @echo utilities made. tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. $(O)winres.o: $(TILEBMP16) $(MSWIN)/winhack.rc $(MSWIN)/mnsel.bmp \ $(MSWIN)/mnselcnt.bmp $(MSWIN)/mnunsel.bmp \ $(MSWIN)/petmark.bmp $(MSWIN)/pilemark.bmp $(MSWIN)/NetHack.ico $(MSWIN)/rip.bmp \ $(MSWIN)/splash.bmp @$(rc) -o$@ --include-dir $(MSWIN) -i $(MSWIN)/winhack.rc $(O)conres.o: $(MSWSYS)/console.rc $(MSWSYS)/NetHack.ico @$(rc) -o$@ --include-dir $(MSWSYS) -i $(MSWSYS)/console.rc #========================================== # The game targets. #========================================== $(O)gamedir.tag: $(subst /,\,@if not exist $(GAMEDIR)/*.* echo creating directory $(GAMEDIR)) $(subst /,\,@if not exist $(GAMEDIR)/*.* mkdir $(GAMEDIR)) $(subst /,\,@echo directory created > $@) $(GAMEDIR)/NetHack.exe : $(O)gamedir.tag $(O)tile.o $(O)nttty.o $(O)guistub.o \ $(ALLOBJ) $(TTYOBJ) $(GUIOBJ) $(O)conres.o $(KEYDLLS) @echo Linking $@... $(link) $(lflags) -o$@ $(ALLOBJ) $(TTYOBJ) $(O)nttty.o $(O)tile.o \ $(O)guistub.o $(O)conres.o $(conlibs) -static -lstdc++ $(subst /,\,@if exist $(O)install.tag del $(O)install.tag) $(GAMEDIR)/NetHackW.exe : $(O)gamedir.tag $(O)tile.o $(O)ttystub.o \ $(ALLOBJ) $(TTYOBJ) $(GUIOBJ) $(O)winres.o $(KEYDLLS) @echo Linking $@... $(link) $(lflags) -mwindows -o$@ $(ALLOBJ) $(GUIOBJ) $(O)tile.o $(O)ttystub.o \ $(O)winres.o $(guilibs) -static -lstdc++ $(subst /,\,@if exist $(O)install.tag del $(O)install.tag) $(O)nhdefkey.o: $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nhdefkey.c $(GAMEDIR)/nhdefkey.dll : $(O)nhdefkey.o $(O)gamedir.tag @echo Linking $@ $(cc) -shared -Wl,--export-all-symbols \ -Wl,--add-stdcall-alias -o $@ $< $(O)nh340key.o: $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nh340key.c $(GAMEDIR)/nh340key.dll : $(O)nh340key.o $(O)gamedir.tag @echo Linking $@ $(cc) -shared -Wl,--export-all-symbols \ -Wl,--add-stdcall-alias -o $@ $< $(O)nhraykey.o: $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nhraykey.c $(GAMEDIR)/nhraykey.dll : $(O)nhraykey.o $(O)gamedir.tag @echo Linking $@ $(cc) -shared -Wl,--export-all-symbols \ -Wl,--add-stdcall-alias -o $@ $< $(GAME)_.ico : $(MSWSYS)/$(GAME).ico $(subst /,\,@copy $(MSWSYS)/$(GAME).ico $@) #========================================== # Create directory for holding object files #========================================== graphicschk: @echo ---- @echo NOTE: This build will include tile support. @echo ---- $(subst /,\,@echo graphicschk > graphicschk) # # Secondary Targets. # #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) @$(link) $(LFLAGSU) -o$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(INCL)/monattk.h $(INCL)/monflag.h \ $(INCL)/objclass.h $(INCL)/monsym.h $(INCL)/qtext.h \ $(INCL)/patchlevel.h $(U)makedefs.c $(O)obj.tag $(cc) $(CFLAGSU) -o$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)/date.h $(OPTIONS_FILE): $(U)makedefs.exe $(subst /,\,$(U)makedefs -v) $(INCL)/onames.h : $(U)makedefs.exe $(subst /,\,$(U)makedefs -o) $(INCL)/pm.h : $(U)makedefs.exe $(subst /,\,$(U)makedefs -p) #$(INCL)/trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)/monstr.c: $(U)makedefs.exe $(subst /,\,$(U)makedefs -m) $(INCL)/vis_tab.h: $(U)makedefs.exe $(subst /,\,$(U)makedefs -z) $(SRC)/vis_tab.c: $(U)makedefs.exe $(subst /,\,$(U)makedefs -z) $(DAT)/engrave: $(DAT)/engrave.txt $(U)makedefs.exe $(subst /,\,$(U)makedefs -s) $(DAT)/epitaph: $(DAT)/epitaph.txt $(U)makedefs.exe $(subst /,\,$(U)makedefs -s) $(DAT)/bogusmon: $(DAT)/bogusmon.txt $(U)makedefs.exe $(subst /,\,$(U)makedefs -s) #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o @$(link) $(LFLAGSU) -o$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)/uudecode.c $(MSWSYS)/NetHack.ico : $(U)uudecode.exe $(MSWSYS)/nhico.uu $(subst /,\,$(U)uudecode.exe $(MSWSYS)/nhico.uu) $(subst /,\,copy NetHack.ico $@) del NetHack.ico $(MSWIN)/NetHack.ico : $(MSWSYS)/NetHack.ico $(subst /,\,copy $< $@) $(MSWIN)/mnsel.bmp: $(U)uudecode.exe $(MSWIN)/mnsel.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/mnsel.uu) $(subst /,\,copy mnsel.bmp $@) del mnsel.bmp $(MSWIN)/mnselcnt.bmp: $(U)uudecode.exe $(MSWIN)/mnselcnt.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/mnselcnt.uu) $(subst /,\,copy mnselcnt.bmp $@) del mnselcnt.bmp $(MSWIN)/mnunsel.bmp: $(U)uudecode.exe $(MSWIN)/mnunsel.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/mnunsel.uu) $(subst /,\,copy mnunsel.bmp $@) del mnunsel.bmp $(MSWIN)/petmark.bmp: $(U)uudecode.exe $(MSWIN)/petmark.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/petmark.uu) $(subst /,\,copy petmark.bmp $@) del petmark.bmp $(MSWIN)/pilemark.bmp: $(U)uudecode.exe $(MSWIN)/pilemark.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/pilemark.uu) $(subst /,\,copy pilemark.bmp $@) del pilemark.bmp $(MSWIN)/rip.bmp: $(U)uudecode.exe $(MSWIN)/rip.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/rip.uu) $(subst /,\,copy rip.bmp $@) del rip.bmp $(MSWIN)/splash.bmp: $(U)uudecode.exe $(MSWIN)/splash.uu $(subst /,\,$(U)uudecode.exe $(MSWIN)/splash.uu) $(subst /,\,copy splash.bmp $@) del splash.bmp #========================================== # Level Compiler Stuff #========================================== LEVCFLAGS=$(cflags) -c -DWIN32 -D_WIN32 -I../include $(cdebug) -DDLB $(U)levcomp.exe: $(SPLEVOBJS) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(SPLEVOBJS) $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c $(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)/lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c $(cc) $(LEVCFLAGS) -o$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) $(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y ifeq "$(DO_YACC)" "YACC_ACT" $(subst /,\,$(YACC) -d $(U)lev_comp.y) $(subst /,\,copy $(YTABC) $(U)lev_yacc.c) $(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h) $(subst /,\,@del $(YTABC)) $(subst /,\,@del $(YTABH)) else @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)/lev_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt lev_yacc.c and @echo lev_comp.h from $(SSYS) into $(UTIL) and use them. $(subst /,\,@copy $(SSYS)/lev_yacc.c $(U)lev_yacc.c >nul) $(subst /,\,@copy $(SSYS)/lev_comp.h $(INCL)/lev_comp.h >nul) $(subst /,\,echo.>>$(U)lev_yacc.c) $(subst /,\,echo.>>$(INCL)/lev_comp.h) endif $(U)lev_$(LEX).c: $(U)lev_comp.l ifeq "$(DO_LEX)" "LEX_ACT" $(subst /,\,$(LEX) $(FLEXSKEL) $(U)lev_comp.l) $(subst /,\,copy $(LEXYYC) $@) $(subst /,\,@del $(LEXYYC)) else @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt lev_lex.c @echo from $(SSYS) into $(UTIL) and use it. $(subst /,\,@copy $(SSYS)/lev_lex.c $@ >nul) $(subst /,\,echo.>>$@) endif #========================================== # Dungeon Compiler Stuff #========================================== $(U)dgncomp.exe: $(DGNCOMPOBJS) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(DGNCOMPOBJS) $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)/dgn_comp.h $(U)dgn_yacc.c $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)/dgn_comp.h \ $(U)dgn_$(LEX).c $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y ifeq "$(DO_YACC)" "YACC_ACT" $(subst /,\,$(YACC) -d $(U)dgn_comp.y) $(subst /,\,copy $(YTABC) $(U)dgn_yacc.c) $(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h) $(subst /,\,@del $(YTABC)) $(subst /,\,@del $(YTABH)) else @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and @echo $(INCL)/dgn_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them. $(subst /,\,@copy $(SSYS)/dgn_yacc.c $(U)dgn_yacc.c >nul) $(subst /,\,@copy $(SSYS)/dgn_comp.h $(INCL)/dgn_comp.h >nul) $(subst /,\,echo.>>$(U)dgn_yacc.c) $(subst /,\,echo.>>$(INCL)/dgn_comp.h) endif $(U)dgn_$(LEX).c: $(U)dgn_comp.l ifeq "$(DO_LEX)" "LEX_ACT" $(subst /,\,$(LEX) $(FLEXSKEL) $(U)dgn_comp.l) $(subst /,\,copy $(LEXYYC) $@) $(subst /,\,@del $(LEXYYC)) else @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt dgn_lex.c @echo from $(SSYS) into $(UTIL) and use it. $(subst /,\,@copy $(SSYS)/dgn_lex.c $@ >nul) $(subst /,\,echo.>>$@) endif #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: $(subst /,\,@if not exist $(OBJ)/*.* echo creating directory $(OBJ)) $(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ)) $(subst /,\,@echo directory created > $@) #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in ../include #=========================================== $(INCL)/win32api.h: $(MSWSYS)/win32api.h $(subst /,\,copy $(MSWSYS)/win32api.h $@) #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o @$(link) $(LFLAGSU) -o$@ $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ $(SRC)/dlb.c $(O)dlb_main.o: $(UTIL)/dlb_main.c $(INCL)/config.h $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ $(UTIL)/dlb_main.c $(DAT)/porthelp: $(MSWSYS)/porthelp $(subst /,\,@copy $(MSWSYS)/porthelp $@ >nul) nhdat: $(U)dlb_main.exe $(DAT)/data $(DAT)/oracles $(OPTIONS_FILE) \ $(DAT)/quest.dat $(DAT)/rumors $(DAT)/help $(DAT)/hh $(DAT)/cmdhelp \ $(DAT)/history $(DAT)/opthelp $(DAT)/wizhelp $(DAT)/dungeon \ $(DAT)/porthelp $(DAT)/license $(DAT)/engrave $(DAT)/epitaph $(DAT)/bogusmon $(DAT)/tribute $(O)sp_lev.tag $(subst /,\,echo data >$(DAT)/dlb.lst) $(subst /,\,echo oracles >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/options echo options >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/ttyoptions echo ttyoptions >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/guioptions echo guioptions >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/porthelp echo porthelp >>$(DAT)/dlb.lst) $(subst /,\,echo quest.dat >>$(DAT)/dlb.lst) $(subst /,\,echo rumors >>$(DAT)/dlb.lst) $(subst /,\,echo help >>$(DAT)/dlb.lst) $(subst /,\,echo hh >>$(DAT)/dlb.lst) $(subst /,\,echo cmdhelp >>$(DAT)/dlb.lst) $(subst /,\,echo history >>$(DAT)/dlb.lst) $(subst /,\,echo opthelp >>$(DAT)/dlb.lst) $(subst /,\,echo wizhelp >>$(DAT)/dlb.lst) $(subst /,\,echo dungeon >>$(DAT)/dlb.lst) $(subst /,\,echo license >>$(DAT)/dlb.lst) $(subst /,\,echo engrave >>$(DAT)/dlb.lst) $(subst /,\,echo epitaph >>$(DAT)/dlb.lst) $(subst /,\,echo bogusmon >>$(DAT)/dlb.lst) $(subst /,\,echo tribute >>$(DAT)/dlb.lst) dir /l /b /-p $(subst /,\,$(DAT)/*.lev >>$(DAT)/dlb.lst) $(subst /,\,$(U)dlb_main CcIf $(DAT) dlb.lst $(SRC)/nhdat) #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) $(link) $(LFLAGSU) -o$@ $(RECOVOBJS) $(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)/win32api.h $(cc) $(CFLAGSU) -o$@ $(U)recover.c #========================================== # Tile Mapping #========================================== $(SRC)/tile.c: $(U)tilemap.exe @echo A new $@ has been created @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o @$(link) $(LFLAGSU) -o$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H) $(cc) $(CFLAGSU) -o$@ $(WSHR)/tilemap.c $(O)tiletx32.o: $(WSHR)/tilemap.c $(HACK_H) $(cc) $(CFLAGS) -DTILETEXT -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tilemap.c $(O)tiletxt.o: $(WSHR)/tilemap.c $(HACK_H) $(cc) $(CFLAGS) -DTILETEXT -o$@ $(WSHR)/tilemap.c $(O)gifread.o: $(WSHR)/gifread.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/gifread.c $(O)gifrd32.o: $(WSHR)/gifread.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/gifread.c $(O)ppmwrite.o: $(WSHR)/ppmwrite.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/ppmwrite.c $(O)tiletext.o: $(WSHR)/tiletext.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c $(O)tilete32.o: $(WSHR)/tiletext.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tiletext.c #========================================== # Optional Tile Utilities #========================================== $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(GIFREADERS) $(TEXT_IO) $(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(GIFREADERS32) $(TEXT_IO32) $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(PPMWRITERS) $(TEXT_IO) $(TILEBMP16): $(TILEUTIL16) $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) $(subst /,\,@$(U)tile2bmp $(TILEBMP16)) #$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32) # @echo Creating 32x32 binary tile files (this may take some time) # $(subst /,\,@$(U)til2bm32 $(TILEBMP32)) $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(O)tile2bmp.o $(TEXT_IO) $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(O)til2bm32.o $(TEXT_IO32) $(O)tile2bmp.o: $(WSHR)/tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(cc) $(CFLAGS) -mno-ms-bitfields -I$(WSHR) -o$@ $(WSHR)/tile2bmp.c $(O)til2bm32.o: $(WSHR)/til2bm32.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/til2bm32.c #========================================== # Housekeeping #========================================== spotless: clean $(subst /,\,if exist graphicschk del graphicschk) $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h) $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h) $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h) $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h) $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c) $(subst /,\,if exist $(U)*.lnk del $(U)*.lnk) $(subst /,\,if exist $(U)*.map del $(U)*.map) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors) $(subst /,\,if exist $(DAT)/???-fil?.lev del $(DAT)/???-fil?.lev) $(subst /,\,if exist $(DAT)/???-goal.lev del $(DAT)/???-goal.lev) $(subst /,\,if exist $(DAT)/???-loca.lev del $(DAT)/???-loca.lev) $(subst /,\,if exist $(DAT)/???-strt.lev del $(DAT)/???-strt.lev) $(subst /,\,if exist $(DAT)/air.lev del $(DAT)/air.lev) $(subst /,\,if exist $(DAT)/asmodeus.lev del $(DAT)/asmodeus.lev) $(subst /,\,if exist $(DAT)/astral.lev del $(DAT)/astral.lev) $(subst /,\,if exist $(DAT)/baalz.lev del $(DAT)/baalz.lev) $(subst /,\,if exist $(DAT)/bigrm-*.lev del $(DAT)/bigrm-*.lev) $(subst /,\,if exist $(DAT)/castle.lev del $(DAT)/castle.lev) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) $(subst /,\,if exist $(DAT)/dungeon del $(DAT)/dungeon) $(subst /,\,if exist $(DAT)/dungeon.pdf del $(DAT)/dungeon.pdf) $(subst /,\,if exist $(DAT)/earth.lev del $(DAT)/earth.lev) $(subst /,\,if exist $(DAT)/fakewiz?.lev del $(DAT)/fakewiz?.lev) $(subst /,\,if exist $(DAT)/fire.lev del $(DAT)/fire.lev) $(subst /,\,if exist $(DAT)/juiblex.lev del $(DAT)/juiblex.lev) $(subst /,\,if exist $(DAT)/knox.lev del $(DAT)/knox.lev) $(subst /,\,if exist $(DAT)/medusa-?.lev del $(DAT)/medusa-?.lev) $(subst /,\,if exist $(DAT)/mine*.lev del $(DAT)/mine*.lev) $(subst /,\,if exist $(DAT)/options del $(DAT)/options) $(subst /,\,if exist $(DAT)/ttyoptions del $(DAT)/ttyoptions) $(subst /,\,if exist $(DAT)/guioptions del $(DAT)/guioptions) $(subst /,\,if exist $(DAT)/oracle.lev del $(DAT)/oracle.lev) $(subst /,\,if exist $(DAT)/oracles del $(DAT)/oracles) $(subst /,\,if exist $(DAT)/orcus.lev del $(DAT)/orcus.lev) $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors) $(subst /,\,if exist $(DAT)/quest.dat del $(DAT)/quest.dat) $(subst /,\,if exist $(DAT)/sanctum.lev del $(DAT)/sanctum.lev) $(subst /,\,if exist $(DAT)/soko?-?.lev del $(DAT)/soko?-?.lev) $(subst /,\,if exist $(DAT)/tower?.lev del $(DAT)/tower?.lev) $(subst /,\,if exist $(DAT)/valley.lev del $(DAT)/valley.lev) $(subst /,\,if exist $(DAT)/water.lev del $(DAT)/water.lev) $(subst /,\,if exist $(DAT)/wizard?.lev del $(DAT)/wizard?.lev) $(subst /,\,if exist $(O)sp_lev.tag del $(O)sp_lev.tag) $(subst /,\,if exist $(SRC)/monstr.c del $(SRC)/monstr.c) $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(U)recover.exe del $(U)recover.exe) $(subst /,\,if exist $(DAT)/dlb.lst del $(DAT)/dlb.lst) $(subst /,\,if exist nhdat. del nhdat.) ifneq "$(OBJ)" "" $(subst /,\,rmdir $(OBJ)) /s /Q endif clean: $(subst /,\,if exist $(O)*.o del $(O)*.o) $(subst /,\,if exist $(O)utility.tag del $(O)utility.tag) $(subst /,\,if exist $(U)makedefs.exe del $(U)makedefs.exe) $(subst /,\,if exist $(U)levcomp.exe del $(U)levcomp.exe) $(subst /,\,if exist $(U)dgncomp.exe del $(U)dgncomp.exe) $(subst /,\,if exist $(SRC)/*.lnk del $(SRC)/*.lnk) $(subst /,\,if exist $(SRC)/*.map del $(SRC)/*.map) $(subst /,\,if exist $(O)install.tag del $(O)install.tag) $(subst /,\,if exist $(O)gamedir.tag del $(O)gamedir.tag) $(subst /,\,if exist $(O)obj.tag del $(O)obj.tag) $(subst /,\,if exist $(TILEBMP16) del $(TILEBMP16)) $(subst /,\,if exist $(TILEBMP32) del $(TILEBMP32)) #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)/data: $(O)utility.tag $(DATABASE) $(subst /,\,$(U)makedefs -d) $(DAT)/rumors: $(O)utility.tag $(DAT)/rumors.tru $(DAT)/rumors.fal $(subst /,\,$(U)makedefs -r) $(DAT)/quest.dat: $(O)utility.tag $(DAT)/quest.txt $(subst /,\,$(U)makedefs -q) $(DAT)/oracles: $(O)utility.tag $(DAT)/oracles.txt $(subst /,\,$(U)makedefs -h) $(DAT)/dungeon: $(O)utility.tag $(DAT)/dungeon.def $(subst /,\,$(U)makedefs -e) $(subst /,\,$(U)dgncomp $(DAT)/dungeon.pdf) # # NT dependencies # $(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(MSWSYS)/nttty.c $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(MSWSYS)/nttty.c $(O)winnt.o: $(HACK_H) $(INCL)/win32api.h $(MSWSYS)/winnt.c $(cc) $(CFLAGS) -o$@ $(MSWSYS)/winnt.c $(O)ntsound.o: $(HACK_H) $(MSWSYS)/ntsound.c $(cc) $(CFLAGS) -o$@ $(MSWSYS)/ntsound.c #if you aren't linking in the full gui then #include the following stub for proper linkage. $(O)guistub.o: $(HACK_H) $(MSWSYS)/stubs.c @$(cc) $(CFLAGS) -DGUISTUB -o$@ $(MSWSYS)/stubs.c #if you aren't linking in the full tty then #include the following stub for proper linkage. $(O)ttystub.o: $(HACK_H) $(MSWSYS)/stubs.c @$(cc) $(CFLAGS) -DTTYSTUB -o$@ $(MSWSYS)/stubs.c $(O)tile.o: $(SRC)/tile.c $(HACK_H) # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ $(U)panic.c # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # * ../include changed to $(INCL) # * -c (which is included in CFLAGS) substituted # with -o$@ # * targets prefixed with $(O) # * $(CC) changed to $(cc) # but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../sys/atari/tos.c $(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \ $(INCL)/win32api.h $(cc) $(CFLAGS) -o$@ ../sys/share/pcmain.c $(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/pcsys.c $(O)pctty.o: ../sys/share/pctty.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/pctty.c $(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/pcunix.c $(O)random.o: ../sys/share/random.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/random.c $(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../sys/share/ioctl.c $(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/unixtty.c $(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ ../sys/unix/unixmain.c $(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/unix/unixunix.c $(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ../sys/unix/unixres.c $(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ ../sys/be/bemain.c $(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h $(cc) $(CFLAGS) -o$@ ../win/tty/getline.c $(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../win/tty/termcap.c $(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../win/tty/topl.c $(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \ $(INCL)/date.h $(INCL)/patchlevel.h $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../win/tty/wintty.c $(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \ $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ../win/X11/Window.c $(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ../win/X11/dialogs.c $(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \ $(INCL)/patchlevel.h ../win/X11/nh72icon \ ../win/X11/nh56icon ../win/X11/nh32icon $(cc) $(CFLAGS) -o$@ ../win/X11/winX.c $(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \ $(INCL)/winX.h $(INCL)/tile2x11.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmap.c $(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmenu.c $(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmesg.c $(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmisc.c $(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winstat.c $(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h $(cc) $(CFLAGS) -o$@ ../win/X11/wintext.c $(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winval.c $(O)tile.o: $(SRC)/tile.c $(HACK_H) $(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ ../win/gnome/gnmain.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c $(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c $(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c $(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ $(INCL)/date.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c $(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c $(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ ../win/gnome/gnbind.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c $(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c $(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c $(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ ../win/gnome/gnmain.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c $(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ ../win/gnome/gnmain.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c $(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ ../win/gnome/gnomeprv.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c $(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ ../win/gnome/gn_rip.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gntext.c $(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c $(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c $(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \ $(INCL)/patchlevel.h $(INCL)/wingem.h $(cc) $(CFLAGS) -o$@ ../win/gem/wingem.c $(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \ $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h $(cc) $(CFLAGS) -o$@ ../win/gem/wingem1.c $(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h $(cc) $(CFLAGS) -o$@ ../win/gem/load_img.c $(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h $(cc) $(CFLAGS) -o$@ ../win/gem/gr_rect.c $(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/dlb.h $(INCL)/patchlevel.h $(INCL)/tile2x11.h \ $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \ $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp $(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp $(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp $(O)monstr.o: monstr.c $(CONFIG_H) $(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h $(O)dig.o: dig.c $(HACK_H) $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h $(O)do.o: do.c $(HACK_H) $(INCL)/lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(O)dokick.o: dokick.c $(HACK_H) $(O)dothrow.o: dothrow.c $(HACK_H) $(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(O)light.o: light.c $(HACK_H) $(INCL)/lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h $(O)makemon.o: makemon.c $(HACK_H) $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(O)minion.o: minion.c $(HACK_H) $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(O)mondata.o: mondata.c $(HACK_H) $(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \ $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \ $(INCL)/color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \ $(HACK_H) $(INCL)/tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)/lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)/lev.h $(O)shk.o: shk.c $(HACK_H) $(O)shknam.o: shknam.c $(HACK_H) $(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)sys.o: sys.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(INCL)/patchlevel.h $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(INCL)/patchlevel.h $(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.6.0/sys/winnt/Makefile.msc0000664000076400007660000015046012623532454016347 0ustar paxedpaxed# NetHack 3.6 Makefile.msc $NHDT-Date: 1447992736 2015/11/20 04:12:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.100 $ */ # Copyright (c) NetHack PC Development Team 1993-2015 # #============================================================================== # Build Tools Environment # # NetHack 3.6.x Makefile for MS Visual Studio Visual C++ compiler # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2010 Express, with the Platform SDK # - Microsoft Visual Studio 2013 Express # - Microsoft Visual Studio 2015 Express (pre-release) # #============================================================================== # This is used for building two versions of NetHack: # # A tty port utilizing the Win32 Console I/O subsystem, Console # NetHack.exe # # A Win32 native port built on the Windows API, Graphical NetHack or # NetHackW.exe # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc (such as bison) # .l lex (such as flex) # # If you have any questions read the sys/winnt/Install.nt file included # with the distribution. #============================================================================== # Before we get started, this section is used to determine the version of # Visual Studio we are using. We set VSVER to 0000 to flag any version that # is too old or untested. # !IF "$(_NMAKE_VER)" == "14.00.22310.1" VSVER=2015 !ELSEIF "$(_NMAKE_VER)" == "12.00.21005.1" VSVER=2013 !ELSEIF "$(_NMAKE_VER)" == "11.00.50727.1" VSVER=2012 !ELSEIF "$(_NMAKE_VER)" == "10.00.40219.01" VSVER=2010 !ELSE VSVER=0000 #untested version !ENDIF #============================================================================== # BUILD DECISIONS SECTION # # There are currently only 3 decisions that you have to make. # 1. 32-bit or 64-bit? # 2. Where do you want your build to end up? # 3. Do you want debug information in the executable? # #--------------------------------------------------------------- #============================================================================== # 1. 32-bit or 64-bit? (comment/uncomment appropriate TARGET_CPU line) # !IF ($(VSVER) >= 2012) # # 64 bit #TARGET_CPU=x64 # # 32 bit TARGET_CPU=x86 !ELSE # For VS2010 use "setenv /x86" or "setenv /x64" before invoking make process # DO NOT DELETE THE FOLLOWING LINE !include !ENDIF # #--------------------------------------------------------------- # 2. Where do you want the game to be built (which folder)? # GAMEDIR = ..\binary # Game directory # #--------------------------------------------------------------- # 3. Do you want debug information in the executable? # DEBUGINFO = Y #============================================================================== # This marks the end of the BUILD DECISIONS section. #============================================================================== # #=============================================== #======= End of Modification Section =========== #=============================================== # ################################################ # # # Nothing below here should have to be changed.# # # ################################################ # #============================================================================== # Set the gamedir according to your preference. # If not present prior to compilation it gets created. # # Source directories. Makedefs hardcodes these, don't change them. # INCL = ..\include # NetHack include files DAT = ..\dat # NetHack data files DOC = ..\doc # NetHack documentation files UTIL = ..\util # Utility source SRC = ..\src # Main source SSYS = ..\sys\share # Shared system files MSWSYS= ..\sys\winnt # mswin specific files TTY = ..\win\tty # window port files (tty) MSWIN = ..\win\win32 # window port files (WIN32) WSHR = ..\win\share # Tile support files # # Object directory. # OBJ = o cc=cl link=link rc=Rc # #========================================== # Exe File Info. #========================================== # # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = WINPFLAG= -DTILES -DMSWIN_GRAPHICS -DWIN32CON # To store all the level files, # help files, etc. in a single library file. # USE_DLB = Y is left uncommented USE_DLB = Y ! IF ("$(USE_DLB)"=="Y") DLBFLG = -DDLB ! ELSE DLBFLG = ! ENDIF # # If you defined ZLIB_COMP in include/config.h and you need # to link with the zlib.lib library, uncomment the line below. # If necessary, prefix explicit path information to the file name # otherwise it assumes the NetHack src directory. # #ZLIB = zlib.lib #========================================== #========================================== # Setting up the compiler and linker #========================================== #========================================== !IF "$(TARGET_CPU)" == "" TARGET_CPU=x86 !ENDIF !IF "$(_NMAKE_VER)" == "10.00.40219.01" CL2013= !ELSE ! IF ($(VSVER) > 2010) CL2013=-sdl ! ENDIF !ENDIF ccommon= -c -nologo -D"_CONSOLE" -D"_CRT_NONSTDC_NO_DEPRECATE" -D"_CRT_SECURE_NO_DEPRECATE" \ -D"_LIB" -D"_SCL_SECURE_NO_DEPRECATE" -D"_VC80_UPGRADE=0x0600" -D"DLB" -D"_MBCS" \ -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -D"NDEBUG" -D"YY_NO_UNISTD_H" -EHsc -fp:precise -Gd -GF -GS -Gy \ $(CL2013) -WX- -Zc:forScope -Zc:wchar_t -Zi cdebug= -analyze- -D"_DEBUG" -Gm -MTd -RTC1 -Od crelease= -analyze- -D"_MBCS" -errorReport:prompt -GL -Gm- -MT -O2 -Ot -Ox -Oy lcommon= /NOLOGO /INCREMENTAL:NO !IF "$(DEBUGINFO)" == "Y" ldebug = /DEBUG cflags1=$(ccommon) $(cdebug) lflags1=$(lcommon) $(ldebug) !ELSE ldebug= cflags1=$(ccommon) $(crelease) lflags1=$(lcommon) $(ldebug) !ENDIF lflags= $(lflags1) !IF "$(TARGET_CPU)" == "x86" cflags = $(cflags1) -D_X86_=1 -DWIN32 -D_WIN32 -W3 scall = -Gz !ELSEIF "$(TARGET_CPU)" == "x64" cflags = $(cflags1) -D_AMD64_=1 -DWIN64 -D_WIN64 -DWIN32 -D_WIN32 -W4 scall = !ENDIF !IF ($(VSVER) >= 2012) cflags = $(cflags:-W4=-W3) !ENDIF #More verbose warning output options below #cflags = $(cflags:-W4=-wd4131 #cflags = $(cflags:-W4=-Wall) #cflags = $(cflags:-W3=-wd4131 #cflags = $(cflags:-W3=-Wall) # declarations for use on Intel x86 systems !IF "$(TARGET_CPU)" == "x86" DLLENTRY = @12 EXEVER=5.01 MACHINE=/MACHINE:X86 !ENDIF # declarations for use on AMD64 systems !IF "$(TARGET_CPU)" == "x64" DLLENTRY = EXEVER=5.02 MACHINE=/MACHINE:X64 !ENDIF # for Windows applications conlflags = $(lflags) -subsystem:console,$(EXEVER) guilflags = $(lflags) -subsystem:windows,$(EXEVER) dlllflags = $(lflags) -entry:_DllMainCRTStartup$(DLLENTRY) -dll # basic subsystem specific libraries, less the C Run-Time baselibs = kernel32.lib $(optlibs) $(winsocklibs) advapi32.lib winlibs = $(baselibs) user32.lib gdi32.lib comdlg32.lib winspool.lib # for Windows applications that use the C Run-Time libraries conlibs = $(baselibs) guilibs = $(winlibs) # INCLDIR= /I..\include #========================================== # Util builds #========================================== cflagsBuild = $(cflags) $(INCLDIR) $(WINPFLAG) $(DLBFLG) lflagsBuild = $(lflags) $(conlibs) $(MACHINE) #========================================== # - Game build #========================================== LIBS= user32.lib winmm.lib $(ZLIB) ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # # # Shorten up the location for some files # O = $(OBJ)^\ U = $(UTIL)^\ # # Utility Objects. # MAKESRC = $(U)makedefs.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o LEVCOMPOBJS = $(O)lev_yacc.o $(O)lev_lex.o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_lex.o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt # # These are not invoked during a normal game build in 3.4 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o TEXT_IO32 = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREADERS32 = $(O)gifrd32.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o VOBJ10 = $(O)mail.o $(O)pcmain.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o VOBJ14 = $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ15 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o VOBJ16 = $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o VOBJ17 = $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o VOBJ18 = $(O)quest.o $(O)questpgr.o $(RANDOM) $(O)read.o VOBJ19 = $(O)rect.o $(O)region.o $(O)restore.o $(O)rip.o VOBJ20 = $(O)rnd.o $(O)role.o $(O)rumors.o $(O)save.o VOBJ21 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o VOBJ22 = $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ23 = $(O)sys.o $(O)teleport.o $(O)timeout.o $(O)topten.o VOBJ24 = $(O)track.o $(O)trap.o $(O)u_init.o $(O)uhitm.o VOBJ25 = $(O)vault.o $(O)vis_tab.o $(O)vision.o $(O)weapon.o VOBJ26 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wizard.o VOBJ27 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o DLBOBJ = $(O)dlb.o REGEX = $(O)cppregex.o TTYOBJ = $(O)topl.o $(O)getline.o $(O)wintty.o SOBJ = $(O)winnt.o $(O)pcsys.o $(O)pcunix.o \ $(SOUND) $(O)nhlan.o OBJS = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \ $(VOBJ26) $(VOBJ27) $(VOBJ28) $(VOBJ29) $(REGEX) GUIOBJ = $(O)mhaskyn.o $(O)mhdlg.o \ $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \ $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \ $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o GUIHDR = $(MSWIN)\mhaskyn.h $(MSWIN)\mhdlg.h $(MSWIN)\mhfont.h \ $(MSWIN)\mhinput.h $(MSWIN)\mhmain.h $(MSWIN)\mhmap.h $(MSWIN)\mhmenu.h \ $(MSWIN)\mhmsg.h $(MSWIN)\mhmsgwnd.h $(MSWIN)\mhrip.h $(MSWIN)\mhstatus.h \ $(MSWIN)\mhtext.h $(MSWIN)\resource.h $(MSWIN)\winMS.h COMCTRL = comctl32.lib KEYDLLS = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll TILEUTIL16 = $(UTIL)\tile2bmp.exe TILEBMP16 = $(SRC)\tiles.bmp TILEUTIL32 = $(UTIL)\til2bm32.exe TILEBMP32 = $(SRC)\tiles32.bmp SOUND = $(OBJ)\ntsound.o VVOBJ = $(O)version.o ALLOBJ = $(SOBJ) $(DLBOBJ) $(WOBJ) $(OBJS) $(VVOBJ) OPTIONS_FILE = $(DAT)\options #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \ $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \ $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \ $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \ $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \ $(INCL)\ntconf.h HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h $(INCL)\context.h \ $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \ $(INCL)\permonst.h $(INCL)\monattk.h \ $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \ $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \ $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \ $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h $(INCL)\lint.h \ $(INCL)\mextra.h $(INCL)\skills.h $(INCL)\onames.h \ $(INCL)\timeout.h $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h $(INCL)\botl.h \ $(INCL)\wintty.h $(INCL)\sys.h $(INCL)\trampoli.h LEV_H = $(INCL)\lev.h DGN_FILE_H = $(INCL)\dgn_file.h LEV_COMP_H = $(INCL)\lev_comp.h SP_LEV_H = $(INCL)\sp_lev.h TILE_H = ..\win\share\tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)\data.base #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== .c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< {$(SRC)}.c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< #========================================== # Rules for files in sys\share #========================================== {$(SSYS)}.c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< {$(SSYS)}.cpp{$(OBJ)}.o: @$(CC) $(cflagsBuild) /EHsc -Fo$@ $< #========================================== # Rules for files in sys\winnt #========================================== {$(MSWSYS)}.c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< {$(MSWSYS)}.h{$(INCL)}.h: @copy $< $@ #========================================== # Rules for files in util #========================================== {$(UTIL)}.c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< #========================================== # Rules for files in win\share #========================================== {$(WSHR)}.c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # @copy $< $@ #========================================== # Rules for files in win\tty #========================================== {$(TTY)}.c{$(OBJ)}.o: $(cc) $(cflagsBuild) -Fo$@ $< #========================================== # Rules for files in win\win32 #========================================== {$(MSWIN)}.c{$(OBJ)}.o: @$(cc) $(cflagsBuild) -Fo$@ $< #========================================== #=============== TARGETS ================== #========================================== # # The default make target (so just typing 'nmake' is useful). # default : install # # The game target. # # # Everything # all : install install: envchk $(O)obj.tag $(O)utility.tag $(GAMEDIR)\NetHack.exe $(GAMEDIR)\NetHackW.exe $(O)install.tag @echo Done. $(O)install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) copy $(DAT)\opthelp $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF if not exist $(GAMEDIR)\sysconf copy $(MSWSYS)\sysconf $(GAMEDIR) if exist $(DAT)\symbols copy $(DAT)\symbols $(GAMEDIR) if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt @if exist $(GAMEDIR)\NetHack.PDB echo NOTE: You may want to remove $(GAMEDIR:\=/)/NetHack.PDB to conserve space @if exist $(GAMEDIR)\NetHackW.PDB echo NOTE: You may want to remove $(GAMEDIR:\=/)/NetHackW.PDB to conserve space -copy $(MSWSYS)\defaults.nh $(GAMEDIR)\defaults.nh -if not exist $(GAMEDIR)\record. goto>$(GAMEDIR)\record. echo install done > $@ # copy $(MSWSYS)\winnt.hlp $(GAMEDIR) recover: $(U)recover.exe if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR) if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt $(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des $(DAT)\castle.des \ $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des \ $(DAT)\medusa.des $(DAT)\oracle.des $(DAT)\tower.des \ $(DAT)\yendor.des $(DAT)\arch.des $(DAT)\barb.des \ $(DAT)\caveman.des $(DAT)\healer.des $(DAT)\knight.des \ $(DAT)\monk.des $(DAT)\priest.des $(DAT)\ranger.des \ $(DAT)\rogue.des $(DAT)\samurai.des $(DAT)\sokoban.des \ $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des cd $(DAT) $(U)levcomp bigroom.des $(U)levcomp castle.des $(U)levcomp endgame.des $(U)levcomp gehennom.des $(U)levcomp knox.des $(U)levcomp mines.des $(U)levcomp medusa.des $(U)levcomp oracle.des $(U)levcomp sokoban.des $(U)levcomp tower.des $(U)levcomp yendor.des $(U)levcomp arch.des $(U)levcomp barb.des $(U)levcomp caveman.des $(U)levcomp healer.des $(U)levcomp knight.des $(U)levcomp monk.des $(U)levcomp priest.des $(U)levcomp ranger.des $(U)levcomp rogue.des $(U)levcomp samurai.des $(U)levcomp tourist.des $(U)levcomp valkyrie.des $(U)levcomp wizard.des cd $(SRC) echo sp_levs done > $(O)sp_lev.tag $(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \ $(SRC)\monstr.c $(SRC)\vis_tab.c \ $(U)levcomp.exe $(INCL)\vis_tab.h \ $(U)dgncomp.exe $(TILEUTIL16) @echo utilities made >$@ @echo utilities made. tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. $(O)winhack.res: $(TILEBMP16) $(MSWIN)\winhack.rc $(MSWIN)\mnsel.bmp \ $(MSWIN)\mnselcnt.bmp $(MSWIN)\mnunsel.bmp \ $(MSWIN)\petmark.bmp $(MSWIN)\pilemark.bmp $(MSWIN)\NetHack.ico $(MSWIN)\rip.bmp \ $(MSWIN)\splash.bmp @$(rc) -r -fo$@ -i$(MSWIN) -dNDEBUG $(MSWIN)\winhack.rc $(O)console.res: $(MSWSYS)\console.rc $(MSWSYS)\NetHack.ico @$(rc) -r -fo$@ -i$(MSWSYS) -dNDEBUG $(MSWSYS)\console.rc #========================================== # The game targets. #========================================== # The section for linking the NetHack image looks a little strange at # first, especially if you are used to UNIX makes, or NDMAKE. It is # Microsoft nmake specific, and it gets around the problem of the # link command line being too long for the linker. An "in-line" linker # response file is generated temporarily. # # It takes advantage of the following features of nmake: # # Inline files : # Specifying the "<<" means to start an inline file. # Another "<<" at the start of a line closes the # inline file. # # Substitution within Macros: # $(mymacro:string1=string2) replaces every # occurrence of string1 with string2 in the # macro mymacro. Special ascii key codes may be # used in the substitution text by preceding it # with ^ as we have done below. Every occurence # of a in $(ALLOBJ) is replaced by # <+>. GAMEOBJ=$(ALLOBJ:^ =^ ) GAMEOBJ=$(GAMEOBJ:^ =^ ) # # DO NOT INDENT THE << below! # # NetHack # full gui linkage libs: # libs: $(LIBS) $(conlibs) $(guilibs) $(COMCTRL) # objs: $(GAMEOBJ) $(TTYOBJ) $(O)nttty.o $(O)tile.o $(GUIOBJ) # otherwise: # libs: $(LIBS) $(conlibs) # objs: $(GAMEOBJ) $(TTYOBJ) $(O)tile.o $(O)guistub.o $(GAMEDIR)\NetHack.exe : $(O)gamedir.tag $(O)tile.o $(O)nttty.o $(O)guistub.o \ $(ALLOBJ) $(TTYOBJ) $(GUIOBJ) $(O)console.res $(KEYDLLS) @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo Linking $(@:\=/) $(link) $(lflagsBuild) $(conlflags) /STACK:2048 /PDB:$(GAMEDIR)\$(@B).PDB /MAP:$(O)$(@B).MAP \ $(LIBS) $(conlibs) -out:$@ @<<$(@B).lnk $(GAMEOBJ) $(TTYOBJ) $(O)nttty.o $(O)tile.o $(O)guistub.o $(O)console.res << @if exist $(O)install.tag del $(O)install.tag # NetHackW # full tty linkage libs: # libs: $(LIBS) $(guilibs) $(COMCTRL) # objs: $(GAMEOBJ) $(GUIOBJ) $(TTYOBJ) $(O)tile.o $(O)nttty.o # otherwise: # libs: $(LIBS) $(guilibs) $(COMCTRL) # objs: $(GAMEOBJ) $(GUIOBJ) $(O)tile.o $(O)ttystub.o $(GAMEDIR)\NetHackW.exe : $(O)gamedir.tag $(O)tile.o $(O)ttystub.o \ $(ALLOBJ) $(TTYOBJ) $(GUIOBJ) $(O)winhack.res $(O)gamedir.tag $(KEYDLLS) @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo Linking $(@:\=/) $(link) $(lflagsBuild) $(guilflags) /STACK:2048 /PDB:$(GAMEDIR)\$(@B).PDB \ /MAP:$(O)$(@B).MAP $(LIBS) $(guilibs) $(COMCTRL) -out:$@ @<<$(@B).lnk $(GAMEOBJ) $(GUIOBJ) $(O)tile.o $(O)ttystub.o $(O)winhack.res << @if exist $(O)install.tag del $(O)install.tag $(O)gamedir.tag: @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR:\=/) @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo directory created > $@ $(O)nhdefkey.def: @echo LIBRARY $(@B) >$@ ! IF "$(TARGET_CPU)"=="x64" || "$(PROCESSOR_ARCHITECTURE)"=="x64" ! ELSE @echo EXPORTS >>$@ @echo ProcessKeystroke >>$@ @echo NHkbhit >>$@ @echo CheckInput >>$@ @echo SourceWhere >>$@ @echo SourceAuthor >>$@ @echo KeyHandlerName >>$@ ! ENDIF $(GAMEDIR)\nhdefkey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def @echo Linking $(@:\=/) @$(link) $(ldebug) /RELEASE /DLL user32.lib \ /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).map" /DEF:$(O)$(@B).def \ /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o $(O)nh340key.def: @echo LIBRARY $(@B) >$@ ! IF "$(TARGET_CPU)"=="x64" || "$(PROCESSOR_ARCHITECTURE)"=="x64" ! ELSE @echo EXPORTS >>$@ @echo ProcessKeystroke >>$@ @echo NHkbhit >>$@ @echo CheckInput >>$@ @echo SourceWhere >>$@ @echo SourceAuthor >>$@ @echo KeyHandlerName >>$@ ! ENDIF $(GAMEDIR)\nh340key.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def @echo Linking $(@:\=/) @$(link) $(ldebug) /RELEASE /NOLOGO /DLL user32.lib \ /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).map" /DEF:$(O)$(@B).def \ /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o $(O)nhraykey.def: @echo LIBRARY $(@B) >$@ ! IF "$(TARGET_CPU)"=="x64" || "$(PROCESSOR_ARCHITECTURE)"=="x64" ! ELSE @echo EXPORTS >>$@ @echo ProcessKeystroke >>$@ @echo NHkbhit >>$@ @echo CheckInput >>$@ @echo SourceWhere >>$@ @echo SourceAuthor >>$@ @echo KeyHandlerName >>$@ ! ENDIF $(GAMEDIR)\nhraykey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def @echo Linking $(@:\=/) @$(link) $(ldebug) /RELEASE /NOLOGO /DLL user32.lib \ /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).map" /DEF:$(O)$(@B).def \ /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o # # Secondary Targets. # #========================================== # Makedefs Stuff #========================================== $(U)nhsizes.exe: $(O)nhsizes.o @echo Linking $(@:\=/) $(link) $(lflagsBuild) -out:$@ $(O)nhsizes.o $(O)panic.o $(O)alloc.o $(O)nhsizes.o: $(CONFIG_H) nhsizes.c @$(cc) $(cflagsBuild) -Fo$@ nhsizes.c $(U)makedefs.exe: $(MAKEOBJS) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(INCL)\patchlevel.h \ $(U)makedefs.c @if not exist $(OBJ)\*.* echo creating directory $(OBJ:\=/) @if not exist $(OBJ)\*.* mkdir $(OBJ) @$(cc) $(cflagsBuild) -Fo$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe $(U)makedefs -v $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z $(DAT)\engrave: $(DAT)\engrave.txt $(U)makedefs.exe ..\util\makedefs -s $(DAT)\epitaph: $(DAT)\epitaph.txt $(U)makedefs.exe ..\util\makedefs -s $(DAT)\bogusmon: $(DAT)\bogusmon.txt $(U)makedefs.exe ..\util\makedefs -s #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)\uudecode.c @$(cc) $(cflagsBuild) /D_CRT_SECURE_NO_DEPRECATE -Fo$@ $(SSYS)\uudecode.c $(MSWSYS)\NetHack.ico : $(U)uudecode.exe $(MSWSYS)\nhico.uu chdir $(MSWSYS) ..\..\util\uudecode.exe nhico.uu chdir ..\..\src $(MSWIN)\NetHack.ico : $(U)uudecode.exe $(MSWSYS)\nhico.uu chdir $(MSWIN) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu chdir ..\..\src $(MSWIN)\mnsel.bmp: $(U)uudecode.exe $(MSWIN)\mnsel.uu chdir $(MSWIN) ..\..\util\uudecode.exe mnsel.uu chdir ..\..\src $(MSWIN)\mnselcnt.bmp: $(U)uudecode.exe $(MSWIN)\mnselcnt.uu chdir $(MSWIN) ..\..\util\uudecode.exe mnselcnt.uu chdir ..\..\src $(MSWIN)\mnunsel.bmp: $(U)uudecode.exe $(MSWIN)\mnunsel.uu chdir $(MSWIN) ..\..\util\uudecode.exe mnunsel.uu chdir ..\..\src $(MSWIN)\petmark.bmp: $(U)uudecode.exe $(MSWIN)\petmark.uu chdir $(MSWIN) ..\..\util\uudecode.exe petmark.uu chdir ..\..\src $(MSWIN)\pilemark.bmp: $(U)uudecode.exe $(MSWIN)\pilemark.uu chdir $(MSWIN) ..\..\util\uudecode.exe pilemark.uu chdir ..\..\src $(MSWIN)\rip.bmp: $(U)uudecode.exe $(MSWIN)\rip.uu chdir $(MSWIN) ..\..\util\uudecode.exe rip.uu chdir ..\..\src $(MSWIN)\splash.bmp: $(U)uudecode.exe $(MSWIN)\splash.uu chdir $(MSWIN) ..\..\util\uudecode.exe splash.uu chdir ..\..\src #================================================= # Level Compiler Stuff #================================================= # # defer to the steps in ..\win\win32\levstuff.mak # $(U)lev_yacc.c $(INCL)\lev_comp.h: $(U)lev_comp.y nmake -nologo -f ..\win\win32\levstuff.mak default $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c @$(cc) $(cflagsBuild) -Fo$@ $(U)lev_yacc.c $(O)lev_lex.o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_lex.c @$(cc) $(cflagsBuild) -Fo$@ $(U)lev_lex.c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) @$(cc) $(cflagsBuild) -Fo$@ $(U)lev_main.c $(U)levcomp.exe: $(LEVCOMPOBJS) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(LEVCOMPOBJS:^ =^ ) << #================================================= # Dungeon Compiler Stuff #================================================= # # defer to the steps in ..\win\win32\dgnstuff.mak # $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y nmake -nologo -f ..\win\win32\dgnstuff.mak default $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c @$(cc) $(cflagsBuild) -Fo$@ $(U)dgn_yacc.c $(O)dgn_lex.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_lex.c @$(cc) $(cflagsBuild) -Fo$@ $(U)dgn_lex.c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c @$(cc) $(cflagsBuild) -Fo$@ $(U)dgn_main.c $(U)dgncomp.exe: $(DGNCOMPOBJS) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(DGNCOMPOBJS:^ =^ ) << #================================================= # Create directory for holding object files #================================================= $(O)obj.tag: @if not exist $(OBJ)\*.* echo creating directory $(OBJ:\=/) @if not exist $(OBJ)\*.* mkdir $(OBJ) @echo directory created >$@ #========================================== # Notify of any CL environment variables # in effect since they change the compiler # options. #========================================== envchk: ! IF ($(VSVER) < 2010) @echo Your Visual Studio version is too old or untested ($(_NMAKE_VER)) !ERROR Your Visual Studio version is too old or untested ($(_NMAKE_VER)) ! ENDIF ! IF "$(TARGET_CPU)"=="x64" @echo Windows x64 64-bit build ! ELSE @echo Windows x86 32-bit build ! ENDIF ! IF "$(CL)"!="" # @echo Warning, the CL Environment variable is defined: # @echo CL=$(CL) ! ENDIF @echo ---- @echo NOTE: This build will include tile support. @echo ---- #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in $(INCL) #=========================================== $(INCL)\win32api.h: $(MSWSYS)\win32api.h copy $(MSWSYS)\win32api.h $@ #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o << $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h @$(cc) $(cflagsBuild) /Fo$@ $(SRC)\dlb.c $(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h @$(cc) $(cflagsBuild) /Fo$@ $(UTIL)\dlb_main.c $(DAT)\porthelp: $(MSWSYS)\porthelp @copy $(MSWSYS)\porthelp $@ >nul nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \ $(DAT)\license $(DAT)\engrave $(DAT)\epitaph $(DAT)\bogusmon $(DAT)\tribute $(O)sp_lev.tag cd $(DAT) echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo engrave >>dlb.lst echo epitaph >>dlb.lst echo bogusmon >>dlb.lst echo tribute >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cIf dlb.lst $(SRC)\nhdat cd $(SRC) #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) @echo Linking $(@:\=/) $(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ $(RECOVOBJS) $(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h @$(cc) $(cflagsBuild) -Fo$@ $(U)recover.c #========================================== # Tile Mapping #========================================== $(SRC)\tile.c: $(U)tilemap.exe @echo A new $(@:\=/) has been created @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) @$(cc) $(cflagsBuild) -Fo$@ $(WSHR)\tilemap.c $(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H) @$(cc) $(cflagsBuild) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) @$(cc) $(cflagsBuild) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) @$(cc) $(cflagsBuild) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c $(O)gifrd32.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) @$(cc) $(cflagsBuild) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) @$(cc) $(cflagsBuild) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) @$(cc) $(cflagsBuild) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c $(O)tilete32.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) @$(cc) $(cflagsBuild) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c #========================================== # Optional Tile Utilities #========================================== $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(GIFREADERS:^ =^ ) $(TEXT_IO:^ =^ ) << $(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(GIFREADERS32:^ =^ ) $(TEXT_IO32:^ =^ ) << $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(PPMWRITERS:^ =^ ) $(TEXT_IO:^ =^ ) << $(TILEBMP16): $(TILEUTIL16) $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) @$(U)tile2bmp $(TILEBMP16) #$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32) # @echo Creating 32x32 binary tile files (this may take some time) # @$(U)til2bm32 $(TILEBMP32) $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(O)tile2bmp.o $(TEXT_IO:^ =^ ) << $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) @echo Linking $(@:\=/) @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk $(O)til2bm32.o $(TEXT_IO32:^ =^ ) << $(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h @$(cc) $(cflagsBuild) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c $(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h @$(cc) $(cflagsBuild) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c #========================================== # Housekeeping #========================================== spotless: clean ! IF ("$(OBJ)"!="") if exist $(OBJ)\* rmdir $(OBJ) /s /Q if exist $(GAMEDIR)\nhdefkey.dll del $(GAMEDIR)\nhdefkey.dll if exist $(GAMEDIR)\nh340key.dll del $(GAMEDIR)\nh340key.dll if exist $(GAMEDIR)\nhraykey.dll del $(GAMEDIR)\nhraykey.dll if exist $(GAMEDIR)\NetHack.exe del $(GAMEDIR)\NetHack.exe if exist $(GAMEDIR)\NetHack.pdb del $(GAMEDIR)\NetHack.pdb if exist $(GAMEDIR)\nhdat del $(GAMEDIR)\nhdat ! ENDIF if exist $(INCL)\date.h del $(INCL)\date.h if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(U)*.lnk del $(U)*.lnk if exist $(U)*.map del $(U)*.map if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\engrave del $(DAT)\engrave if exist $(DAT)\epitaph del $(DAT)\epitaph if exist $(DAT)\bogusmon del $(DAT)\bogusmon if exist $(DAT)\???-fil?.lev del $(DAT)\???-fil?.lev if exist $(DAT)\???-goal.lev del $(DAT)\???-goal.lev if exist $(DAT)\???-loca.lev del $(DAT)\???-loca.lev if exist $(DAT)\???-strt.lev del $(DAT)\???-strt.lev if exist $(DAT)\air.lev del $(DAT)\air.lev if exist $(DAT)\asmodeus.lev del $(DAT)\asmodeus.lev if exist $(DAT)\astral.lev del $(DAT)\astral.lev if exist $(DAT)\baalz.lev del $(DAT)\baalz.lev if exist $(DAT)\bigrm-*.lev del $(DAT)\bigrm-*.lev if exist $(DAT)\castle.lev del $(DAT)\castle.lev if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf if exist $(DAT)\earth.lev del $(DAT)\earth.lev if exist $(DAT)\fakewiz?.lev del $(DAT)\fakewiz?.lev if exist $(DAT)\fire.lev del $(DAT)\fire.lev if exist $(DAT)\juiblex.lev del $(DAT)\juiblex.lev if exist $(DAT)\knox.lev del $(DAT)\knox.lev if exist $(DAT)\medusa-?.lev del $(DAT)\medusa-?.lev if exist $(DAT)\mine*.lev del $(DAT)\mine*.lev if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\ttyoptions del $(DAT)\ttyoptions if exist $(DAT)\guioptions del $(DAT)\guioptions if exist $(DAT)\oracle.lev del $(DAT)\oracle.lev if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\orcus.lev del $(DAT)\orcus.lev if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(DAT)\sanctum.lev del $(DAT)\sanctum.lev if exist $(DAT)\soko?-?.lev del $(DAT)\soko?-?.lev if exist $(DAT)\tower?.lev del $(DAT)\tower?.lev if exist $(DAT)\valley.lev del $(DAT)\valley.lev if exist $(DAT)\water.lev del $(DAT)\water.lev if exist $(DAT)\wizard?.lev del $(DAT)\wizard?.lev if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(SRC)\monstr.c del $(SRC)\monstr.c if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(U)recover.exe del $(U)recover.exe if exist nhdat. del nhdat. if exist $(O)obj.tag del $(O)obj.tag if exist $(O)gamedir.tag del $(O)gamedir.tag if exist $(O)nh*key.lib del $(O)nh*key.lib if exist $(O)nh*key.exp del $(O)nh*key.exp clean: if exist $(O)*.o del $(O)*.o if exist $(O)utility.tag del $(O)utility.tag if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)levcomp.exe del $(U)levcomp.exe if exist $(U)dgncomp.exe del $(U)dgncomp.exe if exist $(SRC)\*.lnk del $(SRC)\*.lnk if exist $(SRC)\*.map del $(SRC)\*.map if exist $(O)install.tag del $(O)install.tag if exist $(O)console.res del $(O)console.res if exist $(O)dgncomp.MAP del $(O)dgncomp.MAP if exist $(O)dgncomp.PDB del $(O)dgncomp.PDB if exist $(O)dlb_main.MAP del $(O)dlb_main.MAP if exist $(O)dlb_main.PDB del $(O)dlb_main.PDB if exist $(O)gamedir.tag del $(O)gamedir.tag if exist $(O)levcomp.MAP del $(O)levcomp.MAP if exist $(O)levcomp.PDB del $(O)levcomp.PDB if exist $(O)makedefs.MAP del $(O)makedefs.MAP if exist $(O)makedefs.PDB del $(O)makedefs.PDB if exist $(O)NetHack.MAP del $(O)NetHack.MAP if exist $(O)nh340key.def del $(O)nh340key.def if exist $(O)nh340key.exp del $(O)nh340key.exp if exist $(O)nh340key.lib del $(O)nh340key.lib if exist $(O)nh340key.map del $(O)nh340key.map if exist $(O)nh340key.PDB del $(O)nh340key.PDB if exist $(O)nhdefkey.def del $(O)nhdefkey.def if exist $(O)nhdefkey.exp del $(O)nhdefkey.exp if exist $(O)nhdefkey.lib del $(O)nhdefkey.lib if exist $(O)nhdefkey.map del $(O)nhdefkey.map if exist $(O)nhdefkey.PDB del $(O)nhdefkey.PDB if exist $(O)nhraykey.def del $(O)nhraykey.def if exist $(O)nhraykey.exp del $(O)nhraykey.exp if exist $(O)nhraykey.lib del $(O)nhraykey.lib if exist $(O)nhraykey.map del $(O)nhraykey.map if exist $(O)nhraykey.PDB del $(O)nhraykey.PDB if exist $(O)obj.tag del $(O)obj.tag if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(O)uudecode.MAP del $(O)uudecode.MAP if exist $(O)uudecode.PDB del $(O)uudecode.PDB rem rem defer to the steps in ..\win\win32\levstuff.mak rem nmake -nologo -f ..\win\win32\levstuff.mak clean rem rem defer to the steps in ..\win\win32\dgnstuff.mak rem nmake -nologo -f ..\win\win32\dgnstuff.mak clean if exist $(TILEBMP16) del $(TILEBMP16) if exist $(TILEBMP32) del $(TILEBMP32) #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)\data: $(O)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(O)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(O)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(O)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(O)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgncomp dungeon.pdf cd $(SRC) # # NT dependencies # $(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(MSWSYS)\nttty.c @$(cc) $(cflagsBuild) -I$(WSHR) -Fo$@ $(MSWSYS)\nttty.c $(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(MSWSYS)\winnt.c @$(cc) $(cflagsBuild) -Fo$@ $(MSWSYS)\winnt.c $(O)ntsound.o: $(HACK_H) $(MSWSYS)\ntsound.c @$(cc) $(cflagsBuild) -Fo$@ $(MSWSYS)\ntsound.c #if you aren't linking in the full gui then #include the following stub for proper linkage. $(O)guistub.o: $(HACK_H) $(MSWSYS)\stubs.c @$(cc) $(cflagsBuild) -DGUISTUB -Fo$@ $(MSWSYS)\stubs.c #if you aren't linking in the full tty then #include the following stub for proper linkage. $(O)ttystub.o: $(HACK_H) $(MSWSYS)\stubs.c @$(cc) $(cflagsBuild) -DTTYSTUB -Fo$@ $(MSWSYS)\stubs.c # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) @$(cc) $(cflagsBuild) -Fo$@ $(U)panic.c # # sys/share dependencies # (O)cppregex.o: $(O)cppregex.cpp $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\cppregex.cpp # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # * ../include changed to $(INCL) # * slashes changed to back-slashes # * -c (which is included in CFLAGS) substituted with -Fo$@ # * $(CFLAGS) replaced with $(cflagsBuild) # * $(CC) replaced with @$(CC) # * targets prefixed with $(O) # * the single win32api.h reference uncommented # but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\atari\tos.c $(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\win32api.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcsys.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pctty.c $(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcunix.c $(O)random.o: ..\sys\share\random.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\random.c $(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\ioctl.c $(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\unixtty.c $(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\unix\unixmain.c $(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\unix\unixunix.c $(O)unixres.o: ..\sys\unix\unixres.c $(CONFIG_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\unix\unixres.c $(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\be\bemain.c $(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\tty\getline.c $(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\tty\termcap.c $(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\tty\topl.c $(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\tty\wintty.c $(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\Window.c $(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\dialogs.c $(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ ..\win\X11\nh72icon ..\win\X11\nh56icon ..\win\X11\nh32icon @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winX.c $(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winmap.c $(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winmenu.c $(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winmesg.c $(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winmisc.c $(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winstat.c $(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\wintext.c $(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\X11\winval.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \ ..\win\gnome\gnmain.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnaskstr.c $(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnmenu.h ..\win\gnome\gnaskstr.h \ ..\win\gnome\gnyesno.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnbind.c $(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(INCL)\tile2x11.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnglyph.c $(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \ ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \ $(INCL)\date.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmain.c $(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h $(HACK_H) @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmap.c $(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnbind.h $(INCL)\func_tab.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmenu.c $(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmesg.c $(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H) @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnopts.c $(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \ ..\win\gnome\gnmain.h $(HACK_H) @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnplayer.c $(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \ ..\win\gnome\gnmain.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnsignal.c $(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \ ..\win\gnome\gnomeprv.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnstatus.c $(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \ ..\win\gnome\gn_rip.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gntext.c $(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnyesno.c $(O)gnworn.o: ..\win\gnome\gnworn.c ..\win\gnome\gnworn.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gnomeprv.h @$(CC) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnworn.c $(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\wingem.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\gem\wingem.c $(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \ $(INCL)\gr_rect.h $(INCL)\wintype.h $(INCL)\wingem.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\gem\wingem1.c $(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\gem\load_img.c $(O)gr_rect.o: ..\win\gem\gr_rect.c $(INCL)\gr_rect.h @$(CC) $(cflagsBuild) -Fo$@ ..\win\gem\gr_rect.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\tile2x11.h \ $(INCL)\qt_win.h $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \ $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp $(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_clust.cpp $(O)qttableview.o: ..\win\Qt\qttableview.cpp $(INCL)\qttableview.h $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qttableview.cpp $(O)wc_chainin.o: ..\win\chain\wc_chainin.c $(HACK_H) @$(cc) $(cflagsBuild) -Fo$@ ..\win\chain\wc_chainin.c $(O)wc_chainout.o: ..\win\chain\wc_chainout.c $(HACK_H) @$(cc) $(cflagsBuild) -Fo$@ ..\win\chain\wc_chainout.c $(O)wc_trace.o: ..\win\chain\wc_trace.c $(HACK_H) $(INCL)\func_tab.h @$(cc) $(cflagsBuild) -Fo$@ ..\win\chain\wc_trace.c $(O)monstr.o: monstr.c $(CONFIG_H) $(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h $(O)dig.o: dig.c $(HACK_H) $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h $(O)do.o: do.c $(HACK_H) $(INCL)\lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(O)dokick.o: dokick.c $(HACK_H) $(O)dothrow.o: dothrow.c $(HACK_H) $(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h #zlib.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(O)light.o: light.c $(HACK_H) $(INCL)\lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h $(O)makemon.o: makemon.c $(HACK_H) $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(O)minion.o: minion.c $(HACK_H) $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(O)mondata.o: mondata.c $(HACK_H) $(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)\lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)\lev.h $(O)shk.o: shk.c $(HACK_H) $(O)shknam.o: shknam.c $(HACK_H) $(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)sys.o: sys.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(O)version.o: version.c $(HACK_H) $(INCL)\dlb.h $(INCL)\date.h \ $(INCL)\patchlevel.h $(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h $(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.6.0/sys/winnt/console.rc0000664000076400007660000000242312536476415016120 0ustar paxedpaxed/* NetHack 3.6 console.rc $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Yitzhak Sapir, 2002. */ /* NetHack may be freely redistributed. See license for details. */ #include "windows.h" 1 ICON DISCARDABLE "NetHack.ICO" ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,5,0,0 PRODUCTVERSION 3,5,0,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - TTY Interface\0" VALUE "FileVersion", "3.5.0\0" VALUE "InternalName", "NetHack\0" VALUE "LegalCopyright", "Copyright (C) 1985 - 2005. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" VALUE "OriginalFilename", "NetHack.exe\0" VALUE "PrivateBuild", "050102\0" VALUE "ProductName", "NetHack\0" VALUE "ProductVersion", "3.5.0\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END /*console.rc*/ nethack-3.6.0/sys/winnt/defaults.nh0000664000076400007660000001275612536476415016300 0ustar paxedpaxed# Sample config file for win32 NetHack # A '#' at the beginning of a line means the rest of the line is a comment. # # Some options MUST be set in this file, other options can be toggled while # playing. For a list of options available see the file. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # # $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # *** OPTIONS *** # # Use the IBM character set rather than just plain ascii characters # for tty window-port. OPTIONS=symset:IBMGraphics_2,roguesymset:RogueEpyx # Here is a suggested symbol set from Michael Feir, # for use by blind NetHack players #OPTIONS=symset:NHAccess,roguesymset:NHAccess # Keyboard handling # Different keyboard handlers can be loaded. # Default is nhdefkey.dll but you can override that. # Ray Chason's keyboard handler # OPTIONS=altkeyhandler:nhraykey.dll # # NetHack 3.4.0 keyboard handling # OPTIONS=altkeyhandler:nh340key.dll # *** Personal Preferences *** # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # #OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful #OPTIONS=dogname:Fido,catname:Morris,fruit:guava #OPTIONS=horsename:Silver #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose #OPTIONS=menustyle:traditional #OPTIONS=hilite_status:hitpoints/30%/bright-magenta/normal #OPTIONS=perm_invent # Turn off all status hilites. #OPTIONS=!statushilites # # General options. You might also set "silent" so as not to attract # the boss's attention. # # number_pad option can have an optional value of 0 (off), 1 (on), # or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I' OPTIONS=time,noshowexp,number_pad:2,lit_corridor # # If you want to get rid of "use #quit to quit..." use: OPTIONS=suppress_alert:3.3.1 # # Note: the rest_on_space in the next line may not be # appropriate for a beginning NetHack player, since # it could result in use of a turn unintentionally. # If you're new to NetHack, leave it commented it out. #OPTIONS=rest_on_space # # Set some options to control graphical window-port (these will # be safely and silently ignored by the tty port) # # Map window settings # possible map_mode options include: tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8| # ascii7x12|ascii8x12|ascii16x12|ascii12x16| # ascii10x18|fit_to_screen OPTIONS=map_mode:tiles,scroll_margin:5 # Message window settings OPTIONS=font_message:Arial,font_size_message:9,align_message:top # Menu settings OPTIONS=font_menu:Arial,font_size_menu:9 # Text settings OPTIONS=font_text:Courier New,font_size_text:9 # Status window settings OPTIONS=font_status:Courier New,font_size_status:9 # Other OPTIONS=hilite_pet,!toptenwin #OPTIONS=!splash_screen,player_selection:prompts # Status/message window colors # Possible color options include: # six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown, # blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue, # brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, # lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace, # background, btnface, btnshadow, btntext, captiontext, graytext, highlight, # highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar, # window, windowframe, windowtext. #OPTIONS=windowcolors:status windowtext/window message windowtext/window # *** LOCATIONS *** # IMPORTANT: If you change any of these locations, the directories they # point at must exist. NetHack will not create them for you. # # HACKDIR is the default location for everything. # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file so # setting HACKDIR below to override that is # not usually necessary or recommended. #HACKDIR=c:\games\nethack # # The location that level files in progress are stored (default=HACKDIR, writeable) #LEVELDIR=c:\nethack\levels # # The location where saved games are kept (default=HACKDIR, writeable) #SAVEDIR=c:\nethack\save # # The location that bones files are kept (default=HACKDIR, writeable) #BONESDIR=c:\nethack\save # # The location that file synchronization locks are stored (default=HACKDIR, writeable) #LOCKDIR=c:\nethack\levels # # The location that a record of game aborts and self-diagnosed game problems # is kept (default=HACKDIR, writeable) #TROUBLEDIR=c:\nethack\trouble # Finnish keyboards might need these modifications uncommented. # For \, @, $, [, | #OPTIONS=subkeyvalue:171/92 #OPTIONS=subkeyvalue:178/64 #OPTIONS=subkeyvalue:180/36 #OPTIONS=subkeyvalue:184/91 #OPTIONS=subkeyvalue:188/124 # # Some versions of Windows allow you to adjust the win32 console port # colors using R-G-B settings. # #OPTIONS=palette:black-0-0-0 #OPTIONS=palette:red-210-0-0 #OPTIONS=palette:green-80-200-0 #OPTIONS=palette:brown-180-100-0 #OPTIONS=palette:blue-0-0-200 #OPTIONS=palette:magenta-128-0-128 #OPTIONS=palette:cyan-50-180-180 #OPTIONS=palette:gray-192-192-192 #OPTIONS=palette:dark gray-100-100-100 #OPTIONS=palette:orange-255-128-0 #OPTIONS=palette:bright green-0-255-0 #OPTIONS=palette:yellow-255-255-0 #OPTIONS=palette:bright blue-100-100-240 #OPTIONS=palette:bright magenta-255-0-255 #OPTIONS=palette:bright cyan-0-255-255 #OPTIONS=palette:white-255-255-255 nethack-3.6.0/sys/winnt/nethack.def0000664000076400007660000000031712536476415016225 0ustar paxedpaxedNAME NETHACK DESCRIPTION 'NetHack 3.6.0 for Windows NT' EXETYPE WINDOWS STUB 'WINSTUB.EXE' CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE MULTIPLE HEAPSIZE 4096 STACKSIZE 9216 EXPORTS WndProc nethack-3.6.0/sys/winnt/nh340key.c0000664000076400007660000002332412536476415015644 0ustar paxedpaxed/* NetHack 3.6 nh340key.c $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ /* * This is the NetHack keystroke processing from NetHack 3.4.0. * It can be built as a run-time loadable dll (nh340key.dll), * placed in the same directory as the nethack.exe executable, * and loaded by specifying OPTIONS=altkeyhandler:nh340key * in defaults.nh */ static char where_to_get_source[] = "http://www.nethack.org/"; static char author[] = "The NetHack Development Team"; #include "hack.h" #include "wintty.h" #include "win32api.h" extern HANDLE hConIn; extern INPUT_RECORD ir; char dllname[512]; char *shortdllname; int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, BOOLEAN_P numberpad, int portdebug)); int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { char dlltmpname[512]; char *tmp = dlltmpname, *tmp2; *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0'; (void) strcpy(dllname, tmp); tmp2 = strrchr(dllname, '\\'); if (tmp2) { tmp2++; shortdllname = tmp2; } return TRUE; } /* * Keyboard translation tables. * (Adopted from the MSDOS port) */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ static const struct pad { uchar normal, shift, cntrl; } keypad[PADKEYS] = { { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { '+', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[PADKEYS] = { { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '+', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }; #define inmap(x, vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2') int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int metaflags = 0, k = 0; int keycode, vk; unsigned char ch, pre_ch, mk = 0; unsigned short int scan; unsigned long shiftstate; int altseq = 0; const struct pad *kpad; shiftstate = 0L; ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); shiftstate = ir->Event.KeyEvent.dwControlKeyState; if (shiftstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode, vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || (iskeypad(scan)) || (altseq > 0)) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan)) { kpad = numberpad ? numpad : keypad; if (shiftstate & SHIFT_PRESSED) { ch = kpad[scan - KEYPADLO].shift; } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ch = kpad[scan - KEYPADLO].cntrl; } else { ch = kpad[scan - KEYPADLO].normal; } } else if (altseq > 0) { /* ALT sequence */ if (vk == 0xBF) ch = M('?'); else ch = M(tolower(keycode)); } if (ch == '\r') ch = '\n'; #ifdef PORT_DEBUG if (portdebug) { char buf[BUFSZ]; Sprintf(buf, "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, sh=0x%X (ESC to end)", shortdllname, ch, scan, vk, shiftstate); fprintf(stdout, "\n%s", buf); } #endif return ch; } int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir) HANDLE hConIn; INPUT_RECORD *ir; { int done = 0; /* true = "stop searching" */ int retval; /* true = "we had a match" */ DWORD count; unsigned short int scan; unsigned char ch; unsigned long shiftstate; int altseq = 0, keycode, vk; done = 0; retval = 0; while (!done) { count = 0; PeekConsoleInput(hConIn, ir, 1, &count); if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); if (shiftstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode, vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || iskeypad(scan) || altseq) { done = 1; /* Stop looking */ retval = 1; /* Found what we sought */ } else { /* Strange Key event; let's purge it to avoid trouble */ ReadConsoleInput(hConIn, ir, 1, &count); } } else if ((ir->EventType == MOUSE_EVENT && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) { done = 1; retval = 1; } else /* Discard it, it's an insignificant event */ ReadConsoleInput(hConIn, ir, 1, &count); } else /* There are no events in console event queue */ { done = 1; /* Stop looking */ retval = 0; } } return retval; } int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad, mode, mod, cc) HANDLE hConIn; INPUT_RECORD *ir; DWORD *count; boolean numpad; int mode; int *mod; coord *cc; { #if defined(SAFERHANGUP) DWORD dwWait; #endif int ch; boolean valid = 0, done = 0; while (!done) { #if defined(SAFERHANGUP) dwWait = WaitForSingleObjectEx(hConIn, // event object to wait for INFINITE, // waits indefinitely TRUE); // alertable wait enabled if (dwWait == WAIT_FAILED) return '\033'; #endif ReadConsoleInput(hConIn, ir, 1, count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); done = valid; } } else { if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); if (valid) return ch; } else if (ir->EventType == MOUSE_EVENT) { if ((ir->Event.MouseEvent.dwEventFlags == 0) && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) { cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1; cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1; if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON) *mod = CLICK_1; else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; #if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif return 0; } } } else done = 1; } } return mode ? 0 : ch; } int __declspec(dllexport) __stdcall SourceWhere(buf) char **buf; { if (!buf) return 0; *buf = where_to_get_source; return 1; } int __declspec(dllexport) __stdcall SourceAuthor(buf) char **buf; { if (!buf) return 0; *buf = author; return 1; } int __declspec(dllexport) __stdcall KeyHandlerName(buf, full) char **buf; int full; { if (!buf) return 0; if (full) *buf = dllname; else *buf = shortdllname; return 1; } nethack-3.6.0/sys/winnt/nhdefkey.c0000664000076400007660000002553112536476415016076 0ustar paxedpaxed/* NetHack 3.6 nhdefkey.c $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ /* * This is the default NetHack keystroke processing. * It can be built as a run-time loadable dll (nhdefkey.dll). * Alternative keystroke handlers can be built using the * entry points in this file as a template. * * Use the defaults.nh "altkeyhandler" option to set a * different dll name (without the ".DLL" extension) to * get different processing. Ensure that the dll referenced * in defaults.nh exists in the same directory as NetHack in * order for it to load successfully. * */ static char where_to_get_source[] = "http://www.nethack.org/"; static char author[] = "The NetHack Development Team"; #include "hack.h" #include "wintty.h" #include "win32api.h" extern HANDLE hConIn; extern INPUT_RECORD ir; extern struct sinfo program_state; char dllname[512]; char *shortdllname; int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, BOOLEAN_P numberpad, int portdebug)); int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { char dlltmpname[512]; char *tmp = dlltmpname, *tmp2; *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0'; (void) strcpy(dllname, tmp); tmp2 = strrchr(dllname, '\\'); if (tmp2) { tmp2++; shortdllname = tmp2; } return TRUE; } /* * Keyboard translation tables. * (Adopted from the MSDOS port) */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ static const struct pad { uchar normal, shift, cntrl; } keypad[PADKEYS] = { { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { '+', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[PADKEYS] = { { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { '5', M('5'), '5' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '+', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { '0', M('0'), '0' }, /* Ins */ { '.', ':', ':' } /* Del */ }; #define inmap(x, vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2') static BYTE KeyState[256]; int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int metaflags = 0, k = 0; int keycode, vk; unsigned char ch, pre_ch, mk = 0; unsigned short int scan; unsigned long shiftstate; int altseq = 0; const struct pad *kpad; shiftstate = 0L; ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); shiftstate = ir->Event.KeyEvent.dwControlKeyState; KeyState[VK_SHIFT] = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0; KeyState[VK_CONTROL] = (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) ? 0x81 : 0; KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0; if (shiftstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode, vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || (iskeypad(scan)) || (altseq > 0)) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan)) { kpad = numberpad ? numpad : keypad; if (shiftstate & SHIFT_PRESSED) { ch = kpad[scan - KEYPADLO].shift; } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ch = kpad[scan - KEYPADLO].cntrl; } else { ch = kpad[scan - KEYPADLO].normal; } } else if (altseq > 0) { /* ALT sequence */ if (vk == 0xBF) ch = M('?'); else ch = M(tolower(keycode)); } /* Attempt to work better with international keyboards. */ else { WORD chr[2]; k = ToAscii(vk, scan, KeyState, chr, 0); if (k <= 2) switch (k) { case 2: /* two characters */ ch = (unsigned char) chr[1]; *valid = TRUE; break; case 1: /* one character */ ch = (unsigned char) chr[0]; *valid = TRUE; break; case 0: /* no translation */ default: /* negative */ *valid = FALSE; } } if (ch == '\r') ch = '\n'; #ifdef PORT_DEBUG if (portdebug) { char buf[BUFSZ]; Sprintf(buf, "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, " "ta=%d (ESC to end)", shortdllname, ch, scan, vk, pre_ch, shiftstate, k); fprintf(stdout, "\n%s", buf); } #endif return ch; } int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir) HANDLE hConIn; INPUT_RECORD *ir; { int done = 0; /* true = "stop searching" */ int retval; /* true = "we had a match" */ DWORD count; unsigned short int scan; unsigned char ch; unsigned long shiftstate; int altseq = 0, keycode, vk; done = 0; retval = 0; while (!done) { count = 0; PeekConsoleInput(hConIn, ir, 1, &count); if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); if (shiftstate & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode, vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || iskeypad(scan) || altseq) { done = 1; /* Stop looking */ retval = 1; /* Found what we sought */ } else { /* Strange Key event; let's purge it to avoid trouble */ ReadConsoleInput(hConIn, ir, 1, &count); } } else if ((ir->EventType == MOUSE_EVENT && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) { done = 1; retval = 1; } else /* Discard it, it's an insignificant event */ ReadConsoleInput(hConIn, ir, 1, &count); } else /* There are no events in console event queue */ { done = 1; /* Stop looking */ retval = 0; } } return retval; } int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad, mode, mod, cc) HANDLE hConIn; INPUT_RECORD *ir; DWORD *count; boolean numpad; int mode; int *mod; coord *cc; { #if defined(SAFERHANGUP) DWORD dwWait; #endif int ch; boolean valid = 0, done = 0; while (!done) { #if defined(SAFERHANGUP) dwWait = WaitForSingleObjectEx(hConIn, // event object to wait for INFINITE, // waits indefinitely TRUE); // alertable wait enabled if (dwWait == WAIT_FAILED) return '\033'; #endif ReadConsoleInput(hConIn, ir, 1, count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); done = valid; } } else { if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); if (valid) return ch; } else if (ir->EventType == MOUSE_EVENT) { if ((ir->Event.MouseEvent.dwEventFlags == 0) && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) { cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1; cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1; if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON) *mod = CLICK_1; else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; #if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif return 0; } } } else done = 1; } } return mode ? 0 : ch; } int __declspec(dllexport) __stdcall SourceWhere(buf) char **buf; { if (!buf) return 0; *buf = where_to_get_source; return 1; } int __declspec(dllexport) __stdcall SourceAuthor(buf) char **buf; { if (!buf) return 0; *buf = author; return 1; } int __declspec(dllexport) __stdcall KeyHandlerName(buf, full) char **buf; int full; { if (!buf) return 0; if (full) *buf = dllname; else *buf = shortdllname; return 1; } nethack-3.6.0/sys/winnt/nhico.uu0000664000076400007660000000275412467321052015577 0ustar paxedpaxedbegin 600 nethack.ico M```!``(`("`0``````#H`@``)@```!`0$```````*`$```X#```H````(``` M`$`````!``0``````(`"````````````````````````````````@```@``` M`("``(````"``(``@(```,#`P`"`@(````#_``#_````__\`_P```/\`_P#_ M_P``____````````````````````````__=P```````````'=W<`#___=P`` M````````?_?W<`]W:/=P``#_<```!WB'!G`/8'B'<``/_W<```?VAGAP#P=E M;W``__]W<``'>`=H\`__=G_P#_!V9_<`!W=H=W``__(:/<`=P=W<` M``__\`_W=G9GB'<`!W=P````__#_=G=X2&"/<`=W``````_P_\=T=F>(:/<' M<```````#_9V=V5H8(AO<`````````_W=W1WAXAHA_````````#_9\<&>&!H M!H9W````````_W=V=6=GAH@(]P``````#_?'9W9T:(!H:&=P``````_V=WQV M=X=HA@B/<``````/]GQP=G>':(A@AW``````#_<'9\=VAH!HB&=P``````_V M=G=X9V>&"&"'<``````/]W?'9W1@B(:(9W````^&C_?'9W1WAX:`8(=P`'`/ M_X_P9W9W:&A@AH:''AH@(AW!W\`=H;_9V=G!H:&"&A@=P M`(`'B(_P<'!V<&>(:(B'<`"`#_\/______=W=W=W=W!W<`__#_____?_?W=W M=W=P=W`/``__#___]W=W=W!W<`!P```/\`#_]_]_=W<`!W``````#P```/_W M=W<```!P```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````H````$````"`````!``0``````,`````````` M````````````````````````@```@````("``(````"``(``@(```,#`P`"` M@(````#_``#_````__\`_P```/\`_P#__P``____`````````````/<````` M=P`/_W`/<`=W<`#_\/8'!W<```\/9F!P<````/9F!@<`````]F9@9P````]F M9@8&<```#V9F8&!P```/9F8&!G````]F9F!@<``/?V9F!@9P<`]_9F9@8'!P M#P___W=W<'``#P__=W!P```````````````````````````````````````` K```````````````````````````````````````````````````````````` ` end nethack-3.6.0/sys/winnt/nhraykey.c0000664000076400007660000005272112536476415016134 0ustar paxedpaxed/* NetHack 3.6 nhraykey.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ /* * Keystroke handling contributed by Ray Chason. * The following text was written by Ray Chason. * * The problem * =========== * * The console-mode Nethack wants both keyboard and mouse input. The * problem is that the Windows API provides no easy way to get mouse input * and also keyboard input properly translated according to the user's * chosen keyboard layout. * * The ReadConsoleInput function returns a stream of keyboard and mouse * events. Nethack is interested in those events that represent a key * pressed, or a click on a mouse button. The keyboard events from * ReadConsoleInput are not translated according to the keyboard layout, * and do not take into account the shift, control, or alt keys. * * The PeekConsoleInput function works similarly to ReadConsoleInput, * except that it does not remove an event from the queue and it returns * instead of blocking when the queue is empty. * * A program can also use ReadConsole to get a properly translated stream * of characters. Unfortunately, ReadConsole does not return mouse events, * does not distinguish the keypad from the main keyboard, does not return * keys shifted with Alt, and does not even return the ESC key when * pressed. * * We want both the functionality of ReadConsole and the functionality of * ReadConsoleInput. But Microsoft didn't seem to think of that. * * * The solution, in the original code * ================================== * * The original 3.4.1 distribution tries to get proper keyboard translation * by passing keyboard events to the ToAscii function. This works, to some * extent -- it takes the shift key into account, and it processes dead * keys properly. But it doesn't take non-US keyboards into account. It * appears that ToAscii is meant for windowed applications, and does not * have enough information to do its job properly in a console application. * * * The Finnish keyboard patch * ========================== * * This patch adds the "subkeyvalue" option to the defaults.nh file. The * user can then add OPTIONS=sukeyvalue:171/92, for instance, to replace * the 171 character with 92, which is \. This works, once properly * configured, but places too much burden on the user. It also bars the * use of the substituted characters in naming objects or monsters. * * * The solution presented here * =========================== * * The best way I could find to combine the functionality of ReadConsole * with that of ReadConsoleInput is simple in concept. First, call * PeekConsoleInput to get the first event. If it represents a key press, * call ReadConsole to retrieve the key. Otherwise, pop it off the queue * with ReadConsoleInput and, if it's a mouse click, return it as such. * * But the Devil, as they say, is in the details. The problem is in * recognizing an event that ReadConsole will return as a key. We don't * want to call ReadConsole unless we know that it will immediately return: * if it blocks, the mouse and the Alt sequences will cease to function * until it returns. * * Separating process_keystroke into two functions, one for commands and a * new one, process_keystroke2, for answering prompts, makes the job a lot * easier. process_keystroke2 doesn't have to worry about mouse events or * Alt sequences, and so the consequences are minor if ReadConsole blocks. * process_keystroke, OTOH, never needs to return a non-ASCII character * that was read from ReadConsole; it returns bytes with the high bit set * only in response to an Alt sequence. * * So in process_keystroke, before calling ReadConsole, a bogus key event * is pushed on the queue. This event causes ReadConsole to return, even * if there was no other character available. Because the bogus key has * the eighth bit set, it is filtered out. This is not done in * process_keystroke2, because that would render dead keys unusable. * * A separate process_keystroke2 can also process the numeric keypad in a * way that makes sense for prompts: just return the corresponding symbol, * and pay no mind to number_pad or the num lock key. * * The recognition of Alt sequences is modified, to support the use of * characters generated with the AltGr key. A keystroke is an Alt sequence * if an Alt key is seen that can't be an AltGr (since an AltGr sequence * could be a character, and in some layouts it could even be an ASCII * character). This recognition is different on NT-based and 95-based * Windows: * * * On NT-based Windows, AltGr signals as right Alt and left Ctrl * together. So an Alt sequence is recognized if either Alt key is * pressed and if right Alt and left Ctrl are not both present. This * is true even if the keyboard in use does not have an AltGr key, and * uses right Alt for AltGr. * * * On 95-based Windows, with a keyboard that lacks the AltGr key, the * right Alt key is used instead. But it still signals as right Alt, * without left Ctrl. There is no way for the application to know * whether right Alt is Alt or AltGr, and so it is always assumed * to be AltGr. This means that Alt sequences must be formed with * left Alt. * * So the patch processes keystrokes as follows: * * * If the scan and virtual key codes are both 0, it's the bogus key, * and we ignore it. * * * Keys on the numeric keypad are processed for commands as in the * unpatched Nethack, and for prompts by returning the ASCII * character, even if the num lock is off. * * * Alt sequences are processed for commands as in the unpatched * Nethack, and ignored for prompts. * * * Control codes are returned as received, because ReadConsole will * not return the ESC key. * * * Other key-down events are passed to ReadConsole. The use of * ReadConsole is different for commands than for prompts: * * o For commands, the bogus key is pushed onto the queue before * ReadConsole is called. On return, non-ASCII characters are * filtered, so they are not mistaken for Alt sequences; this also * filters the bogus key. * * o For prompts, the bogus key is not used, because that would * interfere with dead keys. Eight bit characters may be returned, * and are coded in the configured code page. * * * Possible improvements * ===================== * * Some possible improvements remain: * * * Integrate the existing Finnish keyboard patch, for use with non- * QWERTY layouts such as the German QWERTZ keyboard or Dvorak. * * * Fix the keyboard glitches in the graphical version. Namely, dead * keys don't work, and input comes in as ISO-8859-1 but is displayed * as code page 437 if IBMgraphics is set on startup. * * * Transform incoming text to ISO-8859-1, for full compatibility with * the graphical version. * * * After pushing the bogus key and calling ReadConsole, check to see * if we got the bogus key; if so, and an Alt is pressed, process the * event as an Alt sequence. * */ static char where_to_get_source[] = "http://www.nethack.org/"; static char author[] = "Ray Chason"; #include "hack.h" #include "wintty.h" #include "win32api.h" extern HANDLE hConIn; extern INPUT_RECORD ir; char dllname[512]; char *shortdllname; int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, BOOLEAN_P numberpad, int portdebug)); static INPUT_RECORD bogus_key; int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { char dlltmpname[512]; char *tmp = dlltmpname, *tmp2; *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0'; (void) strcpy(dllname, tmp); tmp2 = strrchr(dllname, '\\'); if (tmp2) { tmp2++; shortdllname = tmp2; } /* A bogus key that will be filtered when received, to keep ReadConsole * from blocking */ bogus_key.EventType = KEY_EVENT; bogus_key.Event.KeyEvent.bKeyDown = 1; bogus_key.Event.KeyEvent.wRepeatCount = 1; bogus_key.Event.KeyEvent.wVirtualKeyCode = 0; bogus_key.Event.KeyEvent.wVirtualScanCode = 0; bogus_key.Event.KeyEvent.uChar.AsciiChar = (uchar) 0x80; bogus_key.Event.KeyEvent.dwControlKeyState = 0; return TRUE; } /* * Keyboard translation tables. * (Adopted from the MSDOS port) */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) #define isnumkeypad(x) \ (KEYPADLO <= (x) && (x) <= 0x51 && (x) != 0x4A && (x) != 0x4E) /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ static const struct pad { uchar normal, shift, cntrl; } keypad[PADKEYS] = { { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { '+', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[PADKEYS] = { { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '+', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }; #define inmap(x, vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2') /* Use process_keystroke for key commands, process_keystroke2 for prompts */ /* int FDECL(process_keystroke, (INPUT_RECORD *ir, boolean *valid, int * portdebug)); */ int FDECL(process_keystroke2, (HANDLE, INPUT_RECORD *ir, boolean *valid)); static int FDECL(is_altseq, (unsigned long shiftstate)); static int is_altseq(shiftstate) unsigned long shiftstate; { /* We need to distinguish the Alt keys from the AltGr key. * On NT-based Windows, AltGr signals as right Alt and left Ctrl together; * on 95-based Windows, AltGr signals as right Alt only. * So on NT, we signal Alt if either Alt is pressed and left Ctrl is not, * and on 95, we signal Alt for left Alt only. */ switch (shiftstate & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED)) { case LEFT_ALT_PRESSED: case LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED: return 1; case RIGHT_ALT_PRESSED: case RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED: return (GetVersion() & 0x80000000) == 0; default: return 0; } } int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int metaflags = 0, k = 0; int keycode, vk; unsigned char ch, pre_ch, mk = 0; unsigned short int scan; unsigned long shiftstate; int altseq = 0; const struct pad *kpad; DWORD count; shiftstate = 0L; ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); shiftstate = ir->Event.KeyEvent.dwControlKeyState; if (scan == 0 && vk == 0) { /* It's the bogus_key */ ReadConsoleInput(hConIn, ir, 1, &count); *valid = FALSE; return 0; } if (is_altseq(shiftstate)) { if (ch || inmap(keycode, vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || (iskeypad(scan)) || (altseq > 0)) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan)) { ReadConsoleInput(hConIn, ir, 1, &count); kpad = numberpad ? numpad : keypad; if (shiftstate & SHIFT_PRESSED) { ch = kpad[scan - KEYPADLO].shift; } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ch = kpad[scan - KEYPADLO].cntrl; } else { ch = kpad[scan - KEYPADLO].normal; } } else if (altseq > 0) { /* ALT sequence */ ReadConsoleInput(hConIn, ir, 1, &count); if (vk == 0xBF) ch = M('?'); else ch = M(tolower(keycode)); } else if (ch < 32 && !isnumkeypad(scan)) { /* Control code; ReadConsole seems to filter some of these, * including ESC */ ReadConsoleInput(hConIn, ir, 1, &count); } /* Attempt to work better with international keyboards. */ else { CHAR ch2; DWORD written; /* The bogus_key guarantees that ReadConsole will return, * and does not itself do anything */ WriteConsoleInput(hConIn, &bogus_key, 1, &written); ReadConsole(hConIn, &ch2, 1, &count, NULL); /* Prevent high characters from being interpreted as alt * sequences; also filter the bogus_key */ if (ch2 & 0x80) *valid = FALSE; else ch = ch2; if (ch == 0) *valid = FALSE; } if (ch == '\r') ch = '\n'; #ifdef PORT_DEBUG if (portdebug) { char buf[BUFSZ]; Sprintf(buf, "PORTDEBUG: ch=%u, scan=%u, vk=%d, pre=%d, " "shiftstate=0x%X (ESC to end)\n", ch, scan, vk, pre_ch, shiftstate); fprintf(stdout, "\n%s", buf); } #endif return ch; } int process_keystroke2(hConIn, ir, valid) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; { /* Use these values for the numeric keypad */ static const char keypad_nums[] = "789-456+1230."; unsigned char ch; int vk; unsigned short int scan; unsigned long shiftstate; int altseq; DWORD count; ch = ir->Event.KeyEvent.uChar.AsciiChar; vk = ir->Event.KeyEvent.wVirtualKeyCode; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; if (scan == 0 && vk == 0) { /* It's the bogus_key */ ReadConsoleInput(hConIn, ir, 1, &count); *valid = FALSE; return 0; } altseq = is_altseq(shiftstate); if (ch || (iskeypad(scan)) || altseq) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan) && !altseq) { ReadConsoleInput(hConIn, ir, 1, &count); ch = keypad_nums[scan - KEYPADLO]; } else if (ch < 32 && !isnumkeypad(scan)) { /* Control code; ReadConsole seems to filter some of these, * including ESC */ ReadConsoleInput(hConIn, ir, 1, &count); } /* Attempt to work better with international keyboards. */ else { CHAR ch2; ReadConsole(hConIn, &ch2, 1, &count, NULL); ch = ch2 & 0xFF; if (ch == 0) *valid = FALSE; } if (ch == '\r') ch = '\n'; return ch; } int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad, mode, mod, cc) HANDLE hConIn; INPUT_RECORD *ir; DWORD *count; int *mod; boolean numpad; coord *cc; { #if defined(SAFERHANGUP) DWORD dwWait; #endif int ch; boolean valid = 0, done = 0; while (!done) { *count = 0; dwWait = WaitForSingleObject(hConIn, INFINITE); #if defined(SAFERHANGUP) if (dwWait == WAIT_FAILED) return '\033'; #endif PeekConsoleInput(hConIn, ir, 1, count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { ch = process_keystroke2(hConIn, ir, &valid); done = valid; } else ReadConsoleInput(hConIn, ir, 1, count); } else { ch = 0; if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, #ifdef PORTDEBUG 1); #else 0); #endif if (valid) return ch; } else { ReadConsoleInput(hConIn, ir, 1, count); if (ir->EventType == MOUSE_EVENT) { if ((ir->Event.MouseEvent.dwEventFlags == 0) && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) { cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1; cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1; if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON) *mod = CLICK_1; else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; #if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif return 0; } } #if 0 /* We ignore these types of console events */ else if (ir->EventType == FOCUS_EVENT) { } else if (ir->EventType == MENU_EVENT) { } #endif } } else done = 1; } } *mod = 0; return ch; } int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir) HANDLE hConIn; INPUT_RECORD *ir; { int done = 0; /* true = "stop searching" */ int retval; /* true = "we had a match" */ DWORD count; unsigned short int scan; unsigned char ch; unsigned long shiftstate; int altseq = 0, keycode, vk; done = 0; retval = 0; while (!done) { count = 0; PeekConsoleInput(hConIn, ir, 1, &count); if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); if (is_altseq(shiftstate)) { if (ch || inmap(keycode, vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || iskeypad(scan) || altseq) { done = 1; /* Stop looking */ retval = 1; /* Found what we sought */ } else { /* Strange Key event; let's purge it to avoid trouble */ ReadConsoleInput(hConIn, ir, 1, &count); } } else if ((ir->EventType == MOUSE_EVENT && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) { done = 1; retval = 1; } else /* Discard it, it's an insignificant event */ ReadConsoleInput(hConIn, ir, 1, &count); } else /* There are no events in console event queue */ { done = 1; /* Stop looking */ retval = 0; } } return retval; } int __declspec(dllexport) __stdcall SourceWhere(buf) char **buf; { if (!buf) return 0; *buf = where_to_get_source; return 1; } int __declspec(dllexport) __stdcall SourceAuthor(buf) char **buf; { if (!buf) return 0; *buf = author; return 1; } int __declspec(dllexport) __stdcall KeyHandlerName(buf, full) char **buf; int full; { if (!buf) return 0; if (full) *buf = dllname; else *buf = shortdllname; return 1; } nethack-3.6.0/sys/winnt/nhsetup.bat0000775000076400007660000001406312541713002016272 0ustar paxedpaxed@REM NetHack 3.6 nhsetup.bat $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.33 $ */ @REM Copyright (c) NetHack PC Development Team 1993-2015 @REM NetHack may be freely redistributed. See license for details. @REM Win32 setup batch file, see Install.nt for details @REM @echo off pushd %~dp0 set WIN32PATH=..\..\win\win32 set BUILDPATH=..\..\build set BINPATH=..\..\binary set VCDir= :studiocheck @REM Set fallbacks here for 32-bit VS2010 SET REGTREE=HKLM\Software\Microsoft\VCExpress\12.0\Setup\VC SET MSVCVERSION=2010 @REM if we're in a 64-bit cmd prompt, gotta include Wow6432Node echo Checking for 64-bit environment... if "%ProgramFiles%" NEQ "%ProgramFiles(x86)%" SET REGTREE=HKLM\Software\Wow6432Node\Microsoft\VCExpress\12.0\Setup\VC @REM i can see your house from here... or at least your VC++ folder echo Checking version of VC++ installed... echo Checking for VC2013 Express... for /f "usebackq skip=2 tokens=1-2*" %%a IN (`reg query %REGTREE% /v ProductDir`) do @set VCDir="%%c" if not defined VCDir goto :othereditions if not exist %VCDir% goto :othereditions set MSVCVERSION=2013 goto :fallback :othereditions @REM TODO: teach ourselves to detect full versions of Studio, which are under a different registry hive echo VC2013 Express not found; dropping back. :fallback echo Using VS%MSVCVERSION%. set SRCPATH=%WIN32PATH%\vs%MSVCVERSION% :nxtcheck echo Checking to see if directories are set up properly... if not exist ..\..\include\hack.h goto :err_dir if not exist ..\..\src\hack.c goto :err_dir if not exist ..\..\dat\wizard.des goto :err_dir if not exist ..\..\util\makedefs.c goto :err_dir if not exist ..\..\sys\winnt\winnt.c goto :err_dir echo Directories look ok. :do_tty if NOT exist %BINPATH%\*.* mkdir %BINPATH% if NOT exist %BINPATH%\license copy ..\..\dat\license %BINPATH%\license >nul echo Copying Microsoft Makefile - Makefile.msc to ..\..\src\Makefile... if NOT exist ..\..\src\Makefile goto :domsc copy ..\..\src\Makefile ..\..\src\Makefile-orig >nul echo Your existing echo ..\..\src\Makefile echo has been renamed to echo ..\..\src\Makefile-orig :domsc copy Makefile.msc ..\..\src\Makefile >nul echo Microsoft Makefile copied ok. echo Copying MinGW Makefile - Makefile.gcc to ..\..\src\Makefile.gcc... if NOT exist ..\..\src\Makefile.gcc goto :dogcc copy ..\..\src\Makefile.gcc ..\..\src\Makefile.gcc-orig >nul echo Your existing echo ..\..\src\Makefile.gcc echo has been renamed to echo ..\..\src\Makefile.gcc-orig :dogcc copy Makefile.gcc ..\..\src\Makefile.gcc >nul echo MinGW Makefile copied ok. :do_win if not exist %SRCPATH%\nethack.sln goto :err_win echo. if exist %BUILDPATH%\*.* goto projectcopy echo Creating %BUILDPATH% directory... mkdir %BUILDPATH% :projectcopy @REM Visual Studio Express solution file if NOT exist %SRCPATH%\nethack.sln goto skipsoln echo Copying %SRCPATH%\nethack.sln to ..\..\nethack.sln... copy %SRCPATH%\nethack.sln ..\.. >nul :skipsoln if NOT exist %BINPATH%\*.* echo Creating %BINPATH% directory... if NOT exist %BINPATH%\*.* mkdir %BINPATH% if NOT exist %BINPATH%\license copy ..\..\dat\license %BINPATH%\license >nul echo Copying Visual C project files to %BUILDPATH% directory... copy %WIN32PATH%\dgnstuff.mak %BUILDPATH% >nul copy %WIN32PATH%\levstuff.mak %BUILDPATH% >nul copy %WIN32PATH%\tiles.mak %BUILDPATH% >nul @REM Visual C++ 201X Express project files :vcexpress if NOT exist %SRCPATH%\makedefs.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\tile2bmp.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\tilemap.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\uudecode.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\NetHackW.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\NetHack.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\dgncomp.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\dgnstuff.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\dlb_main.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\levcomp.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\levstuff.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\recover.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\tiles.vcxproj goto skipvcexpress if NOT exist %SRCPATH%\nhdefkey.vcxproj goto skipvcexpress copy %SRCPATH%\makedefs.vcxproj %BUILDPATH% >nul copy %SRCPATH%\tile2bmp.vcxproj %BUILDPATH% >nul copy %SRCPATH%\tilemap.vcxproj %BUILDPATH% >nul copy %SRCPATH%\uudecode.vcxproj %BUILDPATH% >nul copy %SRCPATH%\NetHackW.vcxproj %BUILDPATH% >nul copy %SRCPATH%\NetHack.vcxproj %BUILDPATH% >nul copy %SRCPATH%\dgncomp.vcxproj %BUILDPATH% >nul copy %SRCPATH%\dgnstuff.vcxproj %BUILDPATH% >nul copy %SRCPATH%\dlb_main.vcxproj %BUILDPATH% >nul copy %SRCPATH%\levcomp.vcxproj %BUILDPATH% >nul copy %SRCPATH%\levstuff.vcxproj %BUILDPATH% >nul copy %SRCPATH%\recover.vcxproj %BUILDPATH% >nul copy %SRCPATH%\tiles.vcxproj %BUILDPATH% >nul copy %SRCPATH%\nhdefkey.vcxproj %BUILDPATH% >nul echo LIBRARY nhdefkey >%BUILDPATH%\nhdefkey64.def echo LIBRARY nhdefkey >%BUILDPATH%\nhdefkey.def echo EXPORTS >>%BUILDPATH%\nhdefkey.def echo ProcessKeystroke >>%BUILDPATH%\nhdefkey.def echo NHkbhit >>%BUILDPATH%\nhdefkey.def echo CheckInput >>%BUILDPATH%\nhdefkey.def echo SourceWhere >>%BUILDPATH%\nhdefkey.def echo SourceAuthor >>%BUILDPATH%\nhdefkey.def echo KeyHandlerName >>%BUILDPATH%\nhdefkey.def echo Done copying files. :skipvcexpress goto :done :err_win echo Some of the files needed to build graphical NetHack echo for Windows are not in the expected places. echo Check "Install.nt" for a list of the steps required echo to build NetHack. goto :fini :err_data echo A required file ..\..\dat\data.bas seems to be missing. echo Check "Files." in the root directory for your NetHack distribution echo and make sure that all required files exist. goto :fini :err_dir echo Your directories are not set up properly, please re-read the echo documentation and sys/winnt/Install.nt. goto :fini :done echo done! echo. echo Proceed with the next step documented in Install.nt echo. :fini :end set _pause=N for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set _pause=Y if "%_pause%"=="Y" pause set _pause= popd nethack-3.6.0/sys/winnt/ntsound.c0000664000076400007660000000144012536476415015764 0ustar paxedpaxed/* NetHack 3.6 ntsound.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * ntsound.c - Windows NT NetHack sound support * *Edit History: * Initial Creation 93/12/11 * */ #include "hack.h" #include "win32api.h" #include #ifdef USER_SOUNDS void play_usersound(filename, volume) const char *filename; int volume; { /* pline("play_usersound: %s (%d).", filename, volume); */ (void) sndPlaySound(filename, SND_ASYNC | SND_NODEFAULT); } #endif /*USER_SOUNDS*/ /* ntsound.c */ nethack-3.6.0/sys/winnt/nttty.c0000664000076400007660000011401312536476415015455 0ustar paxedpaxed/* NetHack 3.6 nttty.c $NHDT-Date: 1431737067 2015/05/16 00:44:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (Windows NT) version */ /* * Initial Creation M. Allison 1993/01/31 * Switch to low level console output routines M. Allison 2003/10/01 * Restrict cursor movement until input pending M. Lehotay 2003/10/02 * Call Unicode version of output API on NT R. Chason 2005/10/28 * */ #ifdef WIN32 #define NEED_VARARGS /* Uses ... */ #include "hack.h" #include "wintty.h" #include #include #include "win32api.h" void FDECL(cmov, (int, int)); void FDECL(nocmov, (int, int)); int FDECL(process_keystroke, (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug)); /* * The following WIN32 Console API routines are used in this file. * * CreateFile * GetConsoleScreenBufferInfo * GetStdHandle * SetConsoleCursorPosition * SetConsoleTextAttribute * SetConsoleCtrlHandler * PeekConsoleInput * ReadConsoleInput * WriteConsoleOutputCharacter * FillConsoleOutputAttribute * GetConsoleOutputCP */ /* Win32 Console handles for input and output */ HANDLE hConIn; HANDLE hConOut; /* Win32 Screen buffer,coordinate,console I/O information */ CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi; COORD ntcoord; INPUT_RECORD ir; /* Flag for whether NetHack was launched via the GUI, not the command line. * The reason we care at all, is so that we can get * a final RETURN at the end of the game when launched from the GUI * to prevent the scoreboard (or panic message :-|) from vanishing * immediately after it is displayed, yet not bother when started * from the command line. */ int GUILaunched; extern int redirect_stdout; static BOOL FDECL(CtrlHandler, (DWORD)); /* Flag for whether unicode is supported */ static boolean has_unicode; #ifdef PORT_DEBUG static boolean display_cursor_info = FALSE; #endif extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ /* dynamic keystroke handling .DLL support */ typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *, BOOLEAN_P, int); typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *); typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P, int, int *, coord *); typedef int(__stdcall *SOURCEWHERE)(char **); typedef int(__stdcall *SOURCEAUTHOR)(char **); typedef int(__stdcall *KEYHANDLERNAME)(char **, int); HANDLE hLibrary; PROCESS_KEYSTROKE pProcessKeystroke; NHKBHIT pNHkbhit; CHECKINPUT pCheckInput; SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; #ifdef CHANGE_COLOR static void NDECL(adjust_palette); static int FDECL(match_color_name, (const char *)); typedef HWND(WINAPI *GETCONSOLEWINDOW)(); static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); static boolean altered_palette; static COLORREF UserDefinedColors[CLR_MAX]; static COLORREF NetHackColors[CLR_MAX] = { 0x00000000, 0x00c80000, 0x0000c850, 0x00b4b432, 0x000000d2, 0x00800080, 0x000064b4, 0x00c0c0c0, 0x00646464, 0x00f06464, 0x0000ff00, 0x00ffff00, 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff }; static COLORREF DefaultColors[CLR_MAX] = { 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00, 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff }; #endif #ifndef CLR_MAX #define CLR_MAX 16 #endif int ttycolors[CLR_MAX]; #ifdef TEXTCOLOR static void NDECL(init_ttycolor); #endif static void NDECL(really_move_cursor); #define MAX_OVERRIDES 256 unsigned char key_overrides[MAX_OVERRIDES]; static char nullstr[] = ""; char erase_char, kill_char; #define DEFTEXTCOLOR ttycolors[7] static WORD background = 0; static WORD foreground = (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); static WORD attr = (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); static DWORD ccount, acount; static COORD cursor = { 0, 0 }; /* * Called after returning from ! or ^Z */ void gettty() { #ifndef TEXTCOLOR int k; #endif erase_char = '\b'; kill_char = 21; /* cntl-U */ iflags.cbreak = TRUE; #ifdef TEXTCOLOR init_ttycolor(); #else for (k = 0; k < CLR_MAX; ++k) ttycolors[k] = 7; #endif } /* reset terminal to original state */ void settty(s) const char *s; { cmov(ttyDisplay->curx, ttyDisplay->cury); end_screen(); if (s) raw_print(s); } /* called by init_nhwindows() and resume_nhwindows() */ void setftty() { #ifdef CHANGE_COLOR if (altered_palette) adjust_palette(); #endif start_screen(); has_unicode = ((GetVersion() & 0x80000000) == 0); } void tty_startup(wid, hgt) int *wid, *hgt; { int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; if (twid > 80) twid = 80; *wid = twid; *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; set_option_mod_status("mouse_support", SET_IN_GAME); } void tty_number_pad(state) int state; { } void tty_start_screen() { if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */ } void tty_end_screen() { clear_screen(); really_move_cursor(); if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { DWORD ccnt; COORD newcoord; newcoord.X = 0; newcoord.Y = 0; FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter( hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); } FlushConsoleInputBuffer(hConIn); } static BOOL CtrlHandler(ctrltype) DWORD ctrltype; { switch (ctrltype) { /* case CTRL_C_EVENT: */ case CTRL_BREAK_EVENT: clear_screen(); case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: getreturn_enabled = FALSE; #ifndef NOSAVEONHANGUP hangup(0); #endif #if defined(SAFERHANGUP) CloseHandle(hConIn); /* trigger WAIT_FAILED */ return TRUE; #endif default: return FALSE; } } /* called by init_tty in wintty.c for WIN32 port only */ void nttty_open(mode) int mode; { HANDLE hStdOut; DWORD cmode; long mask; try : /* The following lines of code were suggested by * Bob Landau of Microsoft WIN32 Developer support, * as the only current means of determining whether * we were launched from the command prompt, or from * the NT program manager. M. Allison */ hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdOut) { GetConsoleScreenBufferInfo(hStdOut, &origcsbi); GUILaunched = ((origcsbi.dwCursorPosition.X == 0) && (origcsbi.dwCursorPosition.Y == 0)); if ((origcsbi.dwSize.X <= 0) || (origcsbi.dwSize.Y <= 0)) GUILaunched = 0; } else if (mode) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); if (!hStdOut && !hStdIn) { /* Bool rval; */ AllocConsole(); AttachConsole(GetCurrentProcessId()); /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */ freopen("CON", "w", stdout); freopen("CON", "r", stdin); } mode = 0; goto try ; } else return; load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() */ nt_kbhit = nttty_kbhit; /* Obtain handles for the standard Console I/O devices */ hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); #if 0 hConIn = CreateFile("CONIN$", GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ |FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); hConOut = CreateFile("CONOUT$", GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ |FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0); #endif GetConsoleMode(hConIn, &cmode); #ifdef NO_MOUSE_ALLOWED mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT; #else mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT; #endif /* Turn OFF the settings specified in the mask */ cmode &= ~mask; #ifndef NO_MOUSE_ALLOWED cmode |= ENABLE_MOUSE_INPUT; #endif SetConsoleMode(hConIn, cmode); if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) { /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } get_scr_size(); cursor.X = cursor.Y = 0; really_move_cursor(); } int process_keystroke(ir, valid, numberpad, portdebug) INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug); /* check for override */ if (ch && ch < MAX_OVERRIDES && key_overrides[ch]) ch = key_overrides[ch]; return ch; } int nttty_kbhit() { return pNHkbhit(hConIn, &ir); } void get_scr_size() { GetConsoleScreenBufferInfo(hConOut, &csbi); LI = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1); CO = csbi.srWindow.Right - (csbi.srWindow.Left + 1); if ((LI < 25) || (CO < 80)) { COORD newcoord; LI = 25; CO = 80; newcoord.Y = LI; newcoord.X = CO; SetConsoleScreenBufferSize(hConOut, newcoord); } } int tgetch() { int mod; coord cc; DWORD count; really_move_cursor(); return (program_state.done_hup) ? '\033' : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc); } int ntposkey(x, y, mod) int *x, *y, *mod; { int ch; coord cc; DWORD count; really_move_cursor(); ch = (program_state.done_hup) ? '\033' : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc); if (!ch) { *x = cc.x; *y = cc.y; } return ch; } static void really_move_cursor() { #ifdef PORT_DEBUG char oldtitle[BUFSZ], newtitle[BUFSZ]; if (display_cursor_info && wizard) { oldtitle[0] = '\0'; if (GetConsoleTitle(oldtitle, BUFSZ)) { oldtitle[39] = '\0'; } Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle, ttyDisplay->curx, ttyDisplay->cury, cursor.X, cursor.Y); (void) SetConsoleTitle(newtitle); } #endif if (ttyDisplay) { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; } SetConsoleCursorPosition(hConOut, cursor); } void cmov(x, y) register int x, y; { ttyDisplay->cury = y; ttyDisplay->curx = x; cursor.X = x; cursor.Y = y; } void nocmov(x, y) int x, y; { cursor.X = x; cursor.Y = y; ttyDisplay->curx = x; ttyDisplay->cury = y; } void xputc_core(ch) char ch; { switch (ch) { case '\n': cursor.Y++; /* fall through */ case '\r': cursor.X = 1; break; case '\b': cursor.X--; break; default: WriteConsoleOutputAttribute(hConOut, &attr, 1, cursor, &acount); if (has_unicode) { /* Avoid bug in ANSI API on WinNT */ WCHAR c2[2]; int rc; rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2); WriteConsoleOutputCharacterW(hConOut, c2, rc, cursor, &ccount); } else { WriteConsoleOutputCharacterA(hConOut, &ch, 1, cursor, &ccount); } cursor.X++; } } void xputc(ch) char ch; { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; xputc_core(ch); } void xputs(s) const char *s; { int k; int slen = strlen(s); if (ttyDisplay) { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; } if (s) { for (k = 0; k < slen && s[k]; ++k) xputc_core(s[k]); } } /* * Overrides wintty.c function of the same name * for win32. It is used for glyphs only, not text. */ void g_putch(in_ch) int in_ch; { /* CP437 to Unicode mapping according to the Unicode Consortium */ static const WCHAR cp437[] = { 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; unsigned char ch = (unsigned char) in_ch; cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; WriteConsoleOutputAttribute(hConOut, &attr, 1, cursor, &acount); if (has_unicode) WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, cursor, &ccount); else WriteConsoleOutputCharacterA(hConOut, &ch, 1, cursor, &ccount); } void cl_end() { int cx; cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; cx = CO - cursor.X; FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, cursor, &acount); FillConsoleOutputCharacter(hConOut, ' ', cx, cursor, &ccount); tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } void raw_clear_screen() { if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { DWORD ccnt; COORD newcoord; newcoord.X = 0; newcoord.Y = 0; FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter( hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); } } void clear_screen() { raw_clear_screen(); home(); } void home() { cursor.X = cursor.Y = 0; ttyDisplay->curx = ttyDisplay->cury = 0; } void backsp() { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; xputc_core('\b'); } void cl_eos() { int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { DWORD ccnt; COORD newcoord; newcoord.X = ttyDisplay->curx; newcoord.Y = ttyDisplay->cury; FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); FillConsoleOutputCharacter(hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); } tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } void tty_nhbell() { if (flags.silent) return; Beep(8000, 500); } volatile int junk; /* prevent optimizer from eliminating loop below */ void tty_delay_output() { /* delay 50 ms - uses ANSI C clock() function now */ clock_t goal; int k; goal = 50 + clock(); while (goal > clock()) { k = junk; /* Do nothing */ } } #ifdef TEXTCOLOR /* * CLR_BLACK 0 * CLR_RED 1 * CLR_GREEN 2 * CLR_BROWN 3 low-intensity yellow * CLR_BLUE 4 * CLR_MAGENTA 5 * CLR_CYAN 6 * CLR_GRAY 7 low-intensity white * NO_COLOR 8 * CLR_ORANGE 9 * CLR_BRIGHT_GREEN 10 * CLR_YELLOW 11 * CLR_BRIGHT_BLUE 12 * CLR_BRIGHT_MAGENTA 13 * CLR_BRIGHT_CYAN 14 * CLR_WHITE 15 * CLR_MAX 16 * BRIGHT 8 */ static void init_ttycolor() { ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY; /* fix by Quietust */ ttycolors[CLR_RED] = FOREGROUND_RED; ttycolors[CLR_GREEN] = FOREGROUND_GREEN; ttycolors[CLR_BROWN] = FOREGROUND_GREEN | FOREGROUND_RED; ttycolors[CLR_BLUE] = FOREGROUND_BLUE; ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED; ttycolors[CLR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE; ttycolors[CLR_GRAY] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; ttycolors[BRIGHT] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; ttycolors[CLR_ORANGE] = FOREGROUND_RED | FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY; ttycolors[CLR_YELLOW] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; ttycolors[CLR_WHITE] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; } #endif /* TEXTCOLOR */ int has_color(int color) { #ifdef TEXTCOLOR return 1; #else if (color == CLR_BLACK) return 1; else if (color == CLR_WHITE) return 1; else return 0; #endif } void term_start_attr(int attrib) { switch (attrib) { case ATR_INVERSE: if (iflags.wc_inverse) { /* Suggestion by Lee Berger */ if ((foreground & (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)) == (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)) foreground &= ~(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); background = (BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN); break; } /*FALLTHRU*/ case ATR_ULINE: case ATR_BLINK: case ATR_BOLD: foreground |= FOREGROUND_INTENSITY; break; default: foreground &= ~FOREGROUND_INTENSITY; break; } attr = (foreground | background); } void term_end_attr(int attrib) { switch (attrib) { case ATR_INVERSE: if ((foreground & (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)) == 0) foreground |= (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); background = 0; break; case ATR_ULINE: case ATR_BLINK: case ATR_BOLD: foreground &= ~FOREGROUND_INTENSITY; break; } attr = (foreground | background); } void term_end_raw_bold(void) { term_end_attr(ATR_BOLD); } void term_start_raw_bold(void) { term_start_attr(ATR_BOLD); } void term_start_color(int color) { #ifdef TEXTCOLOR if (color >= 0 && color < CLR_MAX) { foreground = (background != 0 && (color == CLR_GRAY || color == CLR_WHITE)) ? ttycolors[0] : ttycolors[color]; } #else foreground = DEFTEXTCOLOR; #endif attr = (foreground | background); } void term_end_color(void) { #ifdef TEXTCOLOR foreground = DEFTEXTCOLOR; #endif attr = (foreground | background); } void standoutbeg() { term_start_attr(ATR_BOLD); } void standoutend() { term_end_attr(ATR_BOLD); } #ifndef NO_MOUSE_ALLOWED void toggle_mouse_support() { DWORD cmode; GetConsoleMode(hConIn, &cmode); if (iflags.wc_mouse_support) cmode |= ENABLE_MOUSE_INPUT; else cmode &= ~ENABLE_MOUSE_INPUT; SetConsoleMode(hConIn, cmode); } #endif /* handle tty options updates here */ void nttty_preference_update(pref) const char *pref; { if (stricmp(pref, "mouse_support") == 0) { #ifndef NO_MOUSE_ALLOWED toggle_mouse_support(); #endif } return; } #ifdef PORT_DEBUG void win32con_debug_keystrokes() { DWORD count; boolean valid = 0; int ch; xputs("\n"); while (!valid || ch != 27) { nocmov(ttyDisplay->curx, ttyDisplay->cury); ReadConsoleInput(hConIn, &ir, 1, &count); if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) ch = process_keystroke(&ir, &valid, iflags.num_pad, 1); } (void) doredraw(); } void win32con_handler_info() { char *buf; int ci; if (!pSourceAuthor && !pSourceWhere) pline("Keyboard handler source info and author unavailable."); else { if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) { xputs("\n"); xputs("Keystroke handler loaded: \n "); xputs(buf); } if (pSourceAuthor && pSourceAuthor(&buf)) { xputs("\n"); xputs("Keystroke handler Author: \n "); xputs(buf); } if (pSourceWhere && pSourceWhere(&buf)) { xputs("\n"); xputs("Keystroke handler source code available at:\n "); xputs(buf); } xputs("\nPress any key to resume."); ci = nhgetch(); (void) doredraw(); } } void win32con_toggle_cursor_info() { display_cursor_info = !display_cursor_info; } #endif void map_subkeyvalue(op) register char *op; { char digits[] = "0123456789"; int length, i, idx, val; char *kp; idx = -1; val = -1; kp = index(op, '/'); if (kp) { *kp = '\0'; kp++; length = strlen(kp); if (length < 1 || length > 3) return; for (i = 0; i < length; i++) if (!index(digits, kp[i])) return; val = atoi(kp); length = strlen(op); if (length < 1 || length > 3) return; for (i = 0; i < length; i++) if (!index(digits, op[i])) return; idx = atoi(op); } if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1) return; key_overrides[idx] = val; } void load_keyboard_handler() { char suffx[] = ".dll"; char *truncspot; #define MAX_DLLNAME 25 char kh[MAX_ALTKEYHANDLER]; if (iflags.altkeyhandler[0]) { if (hLibrary) { /* already one loaded apparently */ FreeLibrary(hLibrary); hLibrary = (HANDLE) 0; pNHkbhit = (NHKBHIT) 0; pCheckInput = (CHECKINPUT) 0; pSourceWhere = (SOURCEWHERE) 0; pSourceAuthor = (SOURCEAUTHOR) 0; pKeyHandlerName = (KEYHANDLERNAME) 0; pProcessKeystroke = (PROCESS_KEYSTROKE) 0; } if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0) *truncspot = '\0'; (void) strncpy(kh, iflags.altkeyhandler, (MAX_ALTKEYHANDLER - sizeof suffx) - 1); kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0'; Strcat(kh, suffx); Strcpy(iflags.altkeyhandler, kh); hLibrary = LoadLibrary(kh); if (hLibrary) { pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress( hLibrary, TEXT("ProcessKeystroke")); pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit")); pCheckInput = (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput")); pSourceWhere = (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere")); pSourceAuthor = (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor")); pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress( hLibrary, TEXT("KeyHandlerName")); } } if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) { if (hLibrary) { FreeLibrary(hLibrary); hLibrary = (HANDLE) 0; pNHkbhit = (NHKBHIT) 0; pCheckInput = (CHECKINPUT) 0; pSourceWhere = (SOURCEWHERE) 0; pSourceAuthor = (SOURCEAUTHOR) 0; pKeyHandlerName = (KEYHANDLERNAME) 0; pProcessKeystroke = (PROCESS_KEYSTROKE) 0; } (void) strncpy(kh, "nhdefkey.dll", (MAX_ALTKEYHANDLER - sizeof suffx) - 1); kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0'; Strcpy(iflags.altkeyhandler, kh); hLibrary = LoadLibrary(kh); if (hLibrary) { pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress( hLibrary, TEXT("ProcessKeystroke")); pCheckInput = (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput")); pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit")); pSourceWhere = (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere")); pSourceAuthor = (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor")); pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress( hLibrary, TEXT("KeyHandlerName")); } } if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) { if (!hLibrary) raw_printf("\nNetHack was unable to load keystroke handler.\n"); else { FreeLibrary(hLibrary); hLibrary = (HANDLE) 0; raw_printf("\nNetHack keystroke handler is invalid.\n"); } exit(EXIT_FAILURE); } } /* this is used as a printf() replacement when the window * system isn't initialized yet */ void msmsg VA_DECL(const char *, fmt) { char buf[ROWNO * COLNO]; /* worst case scenario */ VA_START(fmt); VA_INIT(fmt, const char *); Vsprintf(buf, fmt, VA_ARGS); if (redirect_stdout) fprintf(stdout, "%s", buf); else { xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, cursor.X + 1, cursor.Y); } VA_END(); return; } /* fatal error */ /*VARARGS1*/ void nttty_error VA_DECL(const char *, s) { char buf[BUFSZ]; VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); buf[0] = '\n'; (void) vsprintf(&buf[1], s, VA_ARGS); msmsg(buf); really_move_cursor(); VA_END(); exit(EXIT_FAILURE); } void synch_cursor() { really_move_cursor(); } #ifdef CHANGE_COLOR void tty_change_color(color_number, rgb, reverse) int color_number, reverse; long rgb; { /* Map NetHack color index to NT Console palette index */ int idx, win32_color_number[] = { 0, /* CLR_BLACK 0 */ 4, /* CLR_RED 1 */ 2, /* CLR_GREEN 2 */ 6, /* CLR_BROWN 3 */ 1, /* CLR_BLUE 4 */ 5, /* CLR_MAGENTA 5 */ 3, /* CLR_CYAN 6 */ 7, /* CLR_GRAY 7 */ 8, /* NO_COLOR 8 */ 12, /* CLR_ORANGE 9 */ 10, /* CLR_BRIGHT_GREEN 10 */ 14, /* CLR_YELLOW 11 */ 9, /* CLR_BRIGHT_BLUE 12 */ 13, /* CLR_BRIGHT_MAGENTA 13 */ 11, /* CLR_BRIGHT_CYAN 14 */ 15 /* CLR_WHITE 15 */ }; int k; if (color_number < 0) { /* indicates OPTIONS=palette with no value */ /* copy the NetHack palette into UserDefinedColors */ for (k = 0; k < CLR_MAX; k++) UserDefinedColors[k] = NetHackColors[k]; } else if (color_number >= 0 && color_number < CLR_MAX) { if (!altered_palette) { /* make sure a full suite is available */ for (k = 0; k < CLR_MAX; k++) UserDefinedColors[k] = DefaultColors[k]; } idx = win32_color_number[color_number]; UserDefinedColors[idx] = rgb; } altered_palette = TRUE; } char * tty_get_color_string() { return ""; } int match_color_name(c) const char *c; { const struct others { int idx; const char *colorname; } othernames[] = { { CLR_MAGENTA, "purple" }, { CLR_BRIGHT_MAGENTA, "bright purple" }, { NO_COLOR, "dark gray" }, { NO_COLOR, "dark grey" }, { CLR_GRAY, "grey" }, }; int cnt; for (cnt = 0; cnt < CLR_MAX; ++cnt) { if (!strcmpi(c, c_obj_colors[cnt])) return cnt; } for (cnt = 0; cnt < SIZE(othernames); ++cnt) { if (!strcmpi(c, othernames[cnt].colorname)) return othernames[cnt].idx; } return -1; } /* * Returns 0 if badoption syntax */ int alternative_palette(op) char *op; { /* * palette:color-R-G-B * OPTIONS=palette:green-4-3-1, palette:0-0-0-0 */ int fieldcnt, color_number, rgb, red, green, blue; char *fields[4], *cp; if (!op) { change_color(-1, 0, 0); /* indicates palette option with no value meaning "load an entire hard-coded NetHack palette." */ return 1; } cp = fields[0] = op; for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) { cp = index(cp, '-'); if (!cp) return 0; fields[fieldcnt] = cp; cp++; } for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) { *(fields[fieldcnt]) = '\0'; ++fields[fieldcnt]; } rgb = 0; for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) { if (fieldcnt == 0 && isalpha(*(fields[0]))) { color_number = match_color_name(fields[0]); if (color_number == -1) return 0; } else { int dcount = 0, cval = 0; cp = fields[fieldcnt]; if (*cp == '\\' && index("0123456789xXoO", cp[1])) { const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; cp++; if (*cp == 'x' || *cp == 'X') for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) cval = (int) ((cval * 16) + (dp - hex) / 2); else if (*cp == 'o' || *cp == 'O') for (++cp; (index("01234567", *cp)) && (dcount++ < 3); cp++) cval = (cval * 8) + (*cp - '0'); else return 0; } else { for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3); cp++) cval = (cval * 10) + (*cp - '0'); } switch (fieldcnt) { case 0: color_number = cval; break; case 1: red = cval; break; case 2: green = cval; break; case 3: blue = cval; break; } } } rgb = RGB(red, green, blue); if (color_number >= 0 && color_number < CLR_MAX) change_color(color_number, rgb, 0); return 1; } /* * This uses an undocumented method to set console attributes * at runtime including console palette * * VOID WINAPI SetConsolePalette(COLORREF palette[16]) * * Author: James Brown at www.catch22.net * * Set palette of current console. * Palette should be of the form: * * COLORREF DefaultColors[CLR_MAX] = * { * 0x00000000, 0x00800000, 0x00008000, 0x00808000, * 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0, * 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00, * 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff * }; */ #pragma pack(push, 1) /* * Structure to send console via WM_SETCONSOLEINFO */ typedef struct _CONSOLE_INFO { ULONG Length; COORD ScreenBufferSize; COORD WindowSize; ULONG WindowPosX; ULONG WindowPosY; COORD FontSize; ULONG FontFamily; ULONG FontWeight; WCHAR FaceName[32]; ULONG CursorSize; ULONG FullScreen; ULONG QuickEdit; ULONG AutoPosition; ULONG InsertMode; USHORT ScreenColors; USHORT PopupColors; ULONG HistoryNoDup; ULONG HistoryBufferSize; ULONG NumberOfHistoryBuffers; COLORREF ColorTable[16]; ULONG CodePage; HWND Hwnd; WCHAR ConsoleTitle[0x100]; } CONSOLE_INFO; #pragma pack(pop) BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci); static void GetConsoleSizeInfo(CONSOLE_INFO *pci); VOID WINAPI SetConsolePalette(COLORREF crPalette[16]); void adjust_palette(VOID_ARGS) { SetConsolePalette(UserDefinedColors); altered_palette = 0; } /* /* only in Win2k+ (use FindWindow for NT4) */ /* HWND WINAPI GetConsoleWindow(); */ /* Undocumented console message */ #define WM_SETCONSOLEINFO (WM_USER + 201) VOID WINAPI SetConsolePalette(COLORREF palette[16]) { CONSOLE_INFO ci = { sizeof(ci) }; int i; HWND hwndConsole = GetConsoleHandle(); /* get current size/position settings rather than using defaults.. */ GetConsoleSizeInfo(&ci); /* set these to zero to keep current settings */ ci.FontSize.X = 0; /* def = 8 */ ci.FontSize.Y = 0; /* def = 12 */ ci.FontFamily = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */ ci.FontWeight = 0; /* 0x400; */ /* lstrcpyW(ci.FaceName, L"Terminal"); */ ci.FaceName[0] = L'\0'; ci.CursorSize = 25; ci.FullScreen = FALSE; ci.QuickEdit = TRUE; ci.AutoPosition = 0x10000; ci.InsertMode = TRUE; ci.ScreenColors = MAKEWORD(0x7, 0x0); ci.PopupColors = MAKEWORD(0x5, 0xf); ci.HistoryNoDup = FALSE; ci.HistoryBufferSize = 50; ci.NumberOfHistoryBuffers = 4; // colour table for (i = 0; i < 16; i++) ci.ColorTable[i] = palette[i]; ci.CodePage = GetConsoleOutputCP(); ci.Hwnd = hwndConsole; lstrcpyW(ci.ConsoleTitle, L""); SetConsoleInfo(hwndConsole, &ci); } /* * Wrapper around WM_SETCONSOLEINFO. We need to create the * necessary section (file-mapping) object in the context of the * process which owns the console, before posting the message */ BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci) { DWORD dwConsoleOwnerPid; HANDLE hProcess; HANDLE hSection, hDupSection; PVOID ptrView = 0; HANDLE hThread; /* * Open the process which "owns" the console */ GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid); hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid); /* * Create a SECTION object backed by page-file, then map a view of * this section into the owner process so we can write the contents * of the CONSOLE_INFO buffer into it */ hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, pci->Length, 0); /* * Copy our console structure into the section-object */ ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, pci->Length); memcpy(ptrView, pci, pci->Length); UnmapViewOfFile(ptrView); /* * Map the memory into owner process */ DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0, FALSE, DUPLICATE_SAME_ACCESS); /* Send console window the "update" message */ SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0); /* * clean up */ hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE) CloseHandle, hDupSection, 0, 0); CloseHandle(hThread); CloseHandle(hSection); CloseHandle(hProcess); return TRUE; } /* * Fill the CONSOLE_INFO structure with information * about the current console window */ static void GetConsoleSizeInfo(CONSOLE_INFO *pci) { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hConsoleOut, &csbi); pci->ScreenBufferSize = csbi.dwSize; pci->WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1; pci->WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; pci->WindowPosX = csbi.srWindow.Left; pci->WindowPosY = csbi.srWindow.Top; } static HWND GetConsoleHandle(void) { HMODULE hMod = GetModuleHandle("kernel32.dll"); GETCONSOLEWINDOW pfnGetConsoleWindow = (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow"); if (pfnGetConsoleWindow) return pfnGetConsoleWindow(); else return GetConsoleHwnd(); } static HWND GetConsoleHwnd(void) { int iterations = 0; HWND hwndFound = 0; char OldTitle[1024], NewTitle[1024], TestTitle[1024]; /* Get current window title */ GetConsoleTitle(OldTitle, sizeof OldTitle); (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(), GetCurrentProcessId()); SetConsoleTitle(NewTitle); GetConsoleTitle(TestTitle, sizeof TestTitle); while (strcmp(TestTitle, NewTitle) != 0) { iterations++; /* sleep(0); */ GetConsoleTitle(TestTitle, sizeof TestTitle); } hwndFound = FindWindow(NULL, NewTitle); SetConsoleTitle(OldTitle); /* printf("%d iterations\n", iterations); */ return hwndFound; } #endif /*CHANGE_COLOR*/ #endif /* WIN32 */ nethack-3.6.0/sys/winnt/porthelp0000664000076400007660000003217512536476415015717 0ustar paxedpaxed Microsoft Windows specific help file for NetHack 3.6 Copyright (c) NetHack PC Development Team 1993-2002. NetHack may be freely distributed. See license for details. (Last Revision: March 16, 2003) This file details specifics for NetHack built for Windows 95, 98, NT, Me, 2000, and XP. Users of really early 16-bit Windows versions should use the MSDOS NetHack. Please note that "NetHack for Windows - Graphical Interface" requires an installation of Internet Explorer 4 or an installation of version 4.71 of the common controls. See the following internet page: http://www.nethack.org/v340/ports/download-win.html#cc for more information. If the game runs for you, you are not affected. New players should be sure to read GuideBook.txt which contains essential information about playing NetHack. It can be found in the same directory as your NetHack executable. The NetHack for Windows port supports some additional or enhanced commands as well as some defaults.nh file options specific to configuration choices used during the building of NetHack for Windows. Listed below are those commands and defaults.nh file options. Some options are applicable only to the "Graphical Interface." These are discussed separately in their own section. Contents 1. ALT Key Combinations 2. Boolean options - Option that you can toggle on or off 3. Graphical Interface - Options you can assign a value to 4. Graphical Interface - Additional/Enhanced Commands 5. Graphical Interface - Menus 6. Numeric Keypad (for number_pad mode) 1. ALT Key Combinations ---------------------------------------------- The non-graphical (tty) interface always operates in "NetHack mode", while the "NetHack for Windows - Graphical Interface" lets you toggle the mode. In non-NetHack mode, all ALT-key combinations are sent to the Windows itself, rather than to NetHack. While playing in NetHack mode you can press the ALT key in combination with another key to execute an extended command as an alternative method to pressing a # key sequence. The available commands are: Alt-2 #twoweapon - toggle two-weapon combat (unavailable if number_pad mode is set) Alt-a #adjust - adjust inventory letters. Alt-c #chat - talk to someone or something. Alt-d #dip - dip an object into something. Alt-e #enhance - enhance your skill with a weapon. Alt-f #force - force a lock. Alt-i #invoke - invoke an object's powers. Alt-j #jump - jump to a location. Alt-l #loot - loot a box on the floor. Alt-m #monster - use a monster's special ability. Alt-n #name - name an item or type of object. Alt-o #offer - offer a sacrifice to the gods. Alt-p #pray - pray to the gods for help. Alt-q #quit - quit the game. (Same as #quit) Alt-r #rub - rub a lamp. Alt-s #sit - sit down. Alt-t #turn - turn undead. Alt-u #untrap - untrap something. Alt-v #version - list compile time options for this version of NetHack. Alt-w #wipe - wipe off your face. Alt-? #? - display list of extended menu commands 2. Boolean Options (Options that can be toggled on or off) ---------------------------------------------------------- Listed here are any options not discussed in the main help, options which may be slightly different from the main help file, and options which may need a slightly more explanatory note: color Use color when displaying non-tiled maps. Tiled maps (available in the graphical port) are always rendered in color. Default: [TRUE] hilite_pet Using tiled graphics, displays a small heart symbol next to your pet. Using ascii graphics, the pet is hilited in a white background. Default: [TRUE] IBMgraphics Use IBM extended characters for the dungeon Default: [TRUE] msg_window When ^P is pressed, it shows menu in a full window. Available only in the non-graphical (tty) version. Default: [FALSE] toptenwin Write top ten list to a window, as opposed to stdout. Default in tty interface: [FALSE] Default in graphical interface: [TRUE] (and cannot be changed) 3. Options that you assign a value to (Graphical Interface only) ---------------------------------------------------------------- "NetHack for Windows - Graphical Interface" recognizes the following additional options, which the non-graphical (tty) version will silently ignore. These are options that specify attributes of various windows. The windows that you can tailor include menu windows (such as the inventory list), text windows (such as "It is written in the book of ..." screens), the message window (where events of the game are displayed), the status window (where your character name and attributes are displayed), and the map window (where the map is drawn). Window Alignment options: align_message Specifies at which side of the NetHack screen the message window is aligned. This option can be used to align the window to "top" or "bottom". Default: [TOP] align_status Specifies at which side of the NetHack screen the status window is aligned. This option can be used to align the window to "top" or "bottom". Default: [BOTTOM] Map Window options: map_mode Specifies which map mode to use. The following map modes are available: tiles (display things on the map with colored tiles), ascii4x6, ascii6x8, ascii8x8, ascii16x8, ascii7x12, ascii8x12, ascii16x12, ascii12x16, ascii10x18 (which use that size font to display things on the map), or fit_to_screen (an ascii mode which forces things to fit on a single screen). Default: [tiles] scroll_margin Specifies the number of map cells from the edge of the map window where scrolling will take place. Default: [5] tile_file An alternative file containing bitmap to use for tiles. This file should be a .bmp file and should be organized as 40 rectangular tiles wide. It is beyond the scope of this document to describe the exact contents of each tile in the .bmp, which must match the object lists used when building NetHack. tile_height Used with tile_file to specify the height of each tile in pixels. This option may only be specified in the defaults.nh config file. Default: [16] tile_width Used with tile_file to specify the width of each tile in pixels. This option may only be specified in the defaults.nh config file. Default: [16] Other Window options: windowcolors Specifies the colors for various windows This option may only be specified in the defaults.nh config file and has the following format: window-type foreground/background Notes: - Both foreground and background colors are required, and a slash must separate them. - "window-type" is either "message" or "status" (Short forms are: "msg" or "sts"). - "foreground" and "background" may be specified as a color name (such as "blue"), or by a six digit hexadecimal RGB color value (such as "#8F8F8F") - The following color names are available: black, red, green, brown, blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue, brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, lime, olive, navy, teal, aqua. In addition, you can use the following names to refer to default Windows settings: activeborder, activecaption, appworkspace, background, btnface, btnshadow, btntext, captiontext, graytext, highlight, highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar, window, windowframe, windowtext. Example: OPTIONS=windowcolors:sts #00FF80/blue msg menutext/menu font_menu Specifies the name of the menu font. font_message Specifies the name of the message font. font_status Specifies the name of the status font. font_text Specifies the name of the text font. font_size_menu Specifies the size of the menu font. font_size_message Specifies the size of the message font. font_size_status Specifies the size of the status font. font_size_text Specifies the size of the text font. Miscellaneous options: vary_msgcount Number of lines to display in message window. 4. NetHack for Windows - Graphical Interface, Additional/Enhanced Commands ------------------------------------------------------------------------- The following function keys are active in the "NetHack for Windows - Graphical Interface": F4 Toggle level overview mode on/off This key will toggle the map between a view that is mapped to fit exactly to the window, and the view that shows the various symbols in their normal size. This is useful for getting an idea of where you are in a level. F5 Toggle tiled display on/off. This key switches between the tiled and the traditional ASCII display. This is equivalent to using the "map_mode" option. F10 Activate menu bar. This key will activate the menu bar, allowing you to select between the menus: File, Map, Window Settings, and Help. 5. Graphical Port Menus ----------------------- File Save - Allows you to save and exit the game Quit - Allows you to quit the game Map - Provides for selection of map mode. Equivalent to using the map_mode option. Window Settings - Changes your logged-on user's settings for NetHack. In 3.5.0, only one setting is available: NetHack mode, which can be checked or unchecked. NetHack mode allows you to use the ALT key for game key commands [see list above]. You can use F10 to access the menu bar while in NetHack mode. You can also clear your logged-on user's settings for NetHack. Settings in this window are saved in your logged-on user's registry. Help - Provides help about various portions of NetHack. 6. Numeric Keypad (for "OPTION=number_pad" mode) ------------------------------------------------ The numeric keypad and surrounding characters act as macros for different commands in NetHack. The Num Lock should be toggled to "on" to make the most of these keys: Key Normal Shift-Key ---------- ---------- ------------- 1, 2, 3, 4 Move In Run In 6, 7, 8, 9 Direction Direction 0 (Ins) Inventory Categorized Inventory . (Del) Wait Turn : - Look Here + Spell List P - Put on an accessory - m - Move Previous Only Message NetHack for Windows - tty Interface Specific Behavior: ------------------------------------------------------ In the non-graphical (tty) interface, when you use the Ctrl key with a directional key (1, 2, 3, 4, 6, 7, 8, 9) it means "go in specified direction until you hit a wall or run into something interesting." NetHack for Windows - Graphical Interface Specific Behavior: ------------------------------------------------------------ It is possible to scroll or pan the map in a specific direction: Ctrl-Shift-Left (4) Scroll (Pan) map left Ctrl-Shift-Right (6) Scroll (Pan) map right Ctrl-Shift-Up (8) Scroll (Pan) map up Ctrl-Shift-Down (2) Scroll (Pan) map down Ctrl-Shift-Home (7) Scroll (Pan) map left to leftmost corner Ctrl-Shift-End (1) Scroll (Pan) map left to rightmost corner Ctrl-Shift-PgUp (9) Scroll (Pan) map left to uppermost corner Ctrl-Shift-PgDn (3) Scroll (Pan) map left to lowermost corner nethack-3.6.0/sys/winnt/stubs.c0000664000076400007660000000367312536476415015444 0ustar paxedpaxed#include "hack.h" #ifdef GUISTUB #ifdef TTYSTUB #error You can't compile this with both GUISTUB and TTYSTUB defined. #endif int GUILaunched; struct window_procs mswin_procs = { "guistubs" }; void mswin_destroy_reg() { return; } /* MINGW32 has trouble with both a main() and WinMain() * so we move main for the MINGW tty version into this stub * so that it is out of sight for the gui linkage. */ #ifdef __MINGW32__ extern char default_window_sys[]; int main(argc, argv) int argc; char *argv[]; { boolean resuming; sys_early_init(); Strcpy(default_window_sys, "tty"); resuming = pcmain(argc, argv); moveloop(resuming); nethack_exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif #endif /* GUISTUB */ /* =============================================== */ #ifdef TTYSTUB #include "hack.h" int GUILaunched; struct window_procs tty_procs = { "ttystubs" }; void win_tty_init(dir) int dir; { return; } void nttty_open(mode) int mode; { return; } void xputc(ch) char ch; { return; } void xputs(s) const char *s; { return; } void raw_clear_screen() { return; } void clear_screen() { return; } void backsp() { return; } int has_color(int color) { return 1; } #ifndef NO_MOUSE_ALLOWED void toggle_mouse_support() { return; } #endif #ifdef PORT_DEBUG void win32con_debug_keystrokes() { return; } void win32con_handler_info() { return; } #endif void map_subkeyvalue(op) register char *op; { return; } void load_keyboard_handler() { return; } /* this is used as a printf() replacement when the window * system isn't initialized yet */ void msmsg VA_DECL(const char *, fmt) { VA_START(fmt); VA_INIT(fmt, const char *); VA_END(); return; } /*VARARGS1*/ void nttty_error VA_DECL(const char *, s) { VA_START(s); VA_INIT(s, const char *); VA_END(); return; } void synch_cursor() { return; } void more() { return; } #endif /* TTYSTUBS */ nethack-3.6.0/sys/winnt/sysconf0000664000076400007660000000476412536476415015551 0ustar paxedpaxed# # NetHack 3.6 sysconf $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # # Sample sysconf file. # The sysconf file is only used if NetHack is compiled with SYSCF defined. # This file uses the same syntax as nethack.cf. # Which users can use WIZARD (debugging) mode (the -D flag). # A value of * allows anyone to enter debugging mode. WIZARDS=* # Users allowed to use the ! (shell escape) command or to suspend the game. # Uses the same syntax as the WIZARDS option above. #SHELLERS= # Show debugging information originating from these source files. # Use '*' for all, or list source files separated by spaces. # Only available if game has been compiled with DEBUG. #DEBUGFILES=* # Limit the number of simultaneous games (see also nethack.sh). #MAXPLAYERS=10 # If not null, added to string "To get local support, " in the support # information help. #SUPPORT=call Izchak at extension 42. # Uncomment the next line to disable the SEDUCE option. #SEDUCE=0 # Record (high score) file options. # CAUTION: changing these after people have started playing games can # lead to lost high scores! # Maximum entries for one person. #PERSMAX=10 # Maximum entries in the record file. #ENTRYMAX=100 # Minimum points to get an entry. #POINTSMIN=1 # Determine identity of "person" in the score file with name (0) or # numeric (1) user id. #PERS_IS_UID=1 # Maximum number of score file entries to use for random statue names #MAX_STATUENAME_RANK=10 # *** LOCATIONS *** # IMPORTANT: If you change any of these locations, the directories they # point at must exist. NetHack will not create them for you. # # HACKDIR is the default location for everything. # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file so # setting HACKDIR below to override that is # not usually necessary or recommended. #HACKDIR=c:\games\nethack # # The location that users can adjust their config file startup options #CONFIGDIR=c:\games\nethack # # The location that level files in progress are stored (default=HACKDIR, writeable) #LEVELDIR=c:\nethack\levels # # The location where saved games are kept (default=HACKDIR, writeable) #SAVEDIR=c:\nethack\save # # The location that bones files are kept (default=HACKDIR, writeable) #BONESDIR=c:\nethack\save # # The location that file synchronization locks are stored (default=HACKDIR, writeable) #LOCKDIR=c:\nethack\levels # # The location that a record of game aborts and self-diagnosed game problems # is kept (default=HACKDIR, writeable) #TROUBLEDIR=c:\nethack\trouble nethack-3.6.0/sys/winnt/win32api.h0000664000076400007660000000137212536476415015737 0ustar paxedpaxed/* NetHack 3.6 win32api.h $NHDT-Date: 1432516197 2015/05/25 01:09:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack PC Development Team 1996 */ /* NetHack may be freely redistributed. See license for details. */ /* * This header file is used to clear up some discrepencies with Visual C * header files & NetHack before including windows.h, so all NetHack * files should include "win32api.h" rather than . */ #if defined(_MSC_VER) #undef strcmpi #undef min #undef max #pragma warning(disable : 4142) /* Warning, Benign redefinition of type */ #pragma pack(8) #endif #define WIN32_LEAN_AND_MEAN #include #include #if defined(_MSC_VER) #pragma pack() #endif /*win32api.h*/ nethack-3.6.0/sys/winnt/winnt.c0000664000076400007660000001761712536476415015446 0ustar paxedpaxed/* NetHack 3.6 winnt.c $NHDT-Date: 1431737068 2015/05/16 00:44:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* * WIN32 system functions. * * Initial Creation: Michael Allison - January 31/93 * */ #define NEED_VARARGS #include "hack.h" #include #ifndef __BORLANDC__ #include #endif #include #include "win32api.h" #include "wintty.h" #ifdef WIN32 /* * The following WIN32 API routines are used in this file. * * GetDiskFreeSpace * GetVolumeInformation * GetUserName * FindFirstFile * FindNextFile * FindClose * */ /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. * For the tty port it is tty_kbhit() [from nttty.c] * For the win32 port it is win32_kbhit() [from winmain.c] * It is initialized to point to def_kbhit [in here] for safety. */ int def_kbhit(void); int (*nt_kbhit)() = def_kbhit; char switchar() { /* Could not locate a WIN32 API call for this- MJA */ return '-'; } long freediskspace(path) char *path; { char tmppath[4]; DWORD SectorsPerCluster = 0; DWORD BytesPerSector = 0; DWORD FreeClusters = 0; DWORD TotalClusters = 0; tmppath[0] = *path; tmppath[1] = ':'; tmppath[2] = '\\'; tmppath[3] = '\0'; GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector, &FreeClusters, &TotalClusters); return (long) (SectorsPerCluster * BytesPerSector * FreeClusters); } /* * Functions to get filenames using wildcards */ int findfirst(path) char *path; { if (ffhandle) { FindClose(ffhandle); ffhandle = (HANDLE) 0; } ffhandle = FindFirstFile(path, &ffd); return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1; } int findnext() { return FindNextFile(ffhandle, &ffd) ? 1 : 0; } char * foundfile_buffer() { return &ffd.cFileName[0]; } long filesize(file) char *file; { if (findfirst(file)) { return ((long) ffd.nFileSizeLow); } else return -1L; } /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { char *ptr; char drive; if ((ptr = index(str, ':')) != (char *) 0) { drive = toupper(*(ptr - 1)); _chdrive((drive - 'A') + 1); } } static int max_filename() { DWORD maxflen; int status = 0; status = GetVolumeInformation((LPTSTR) 0, (LPTSTR) 0, 0, (LPDWORD) 0, &maxflen, (LPDWORD) 0, (LPTSTR) 0, 0); if (status) return maxflen; else return 0; } int def_kbhit() { return 0; } /* * Strip out troublesome file system characters. */ void nt_regularize(s) /* normalize file name */ register char *s; { register unsigned char *lp; for (lp = s; *lp; lp++) if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/' || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|' || *lp == ':' || (*lp > 127)) *lp = '_'; } /* * This is used in nhlan.c to implement some of the LAN_FEATURES. */ char * get_username(lan_username_size) int *lan_username_size; { static TCHAR username_buffer[BUFSZ]; unsigned int status; DWORD i = BUFSZ - 1; /* i gets updated with actual size */ status = GetUserName(username_buffer, &i); if (status) username_buffer[i] = '\0'; else Strcpy(username_buffer, "NetHack"); if (lan_username_size) *lan_username_size = strlen(username_buffer); return username_buffer; } #if 0 char *getxxx() { char szFullPath[MAX_PATH] = ""; HMODULE hInst = NULL; /* NULL gets the filename of this module */ GetModuleFileName(hInst, szFullPath, sizeof(szFullPath)); return &szFullPath[0]; } #endif /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *, s) { char buf[BUFSZ]; VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); if (!strncmpi(windowprocs.name, "tty", 3)) { buf[0] = '\n'; (void) vsprintf(&buf[1], s, VA_ARGS); Strcat(buf, "\n"); msmsg(buf); } else { (void) vsprintf(buf, s, VA_ARGS); Strcat(buf, "\n"); raw_printf(buf); } VA_END(); exit(EXIT_FAILURE); } void Delay(int ms) { (void) Sleep(ms); } extern void NDECL(backsp); void win32_abort() { if (wizard) { int c, ci, ct; if (!iflags.window_inited) c = 'n'; ct = 0; msmsg("Execute debug breakpoint wizard?"); while ((ci = nhgetch()) != '\n') { if (ct > 0) { backsp(); /* \b is visible on NT */ (void) putchar(' '); backsp(); ct = 0; c = 'n'; } if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { ct = 1; c = ci; msmsg("%c", c); } } if (c == 'y') DebugBreak(); } abort(); } static char interjection_buf[INTERJECTION_TYPES][1024]; static int interjection[INTERJECTION_TYPES]; void interject_assistance(num, interjection_type, ptr1, ptr2) int num; int interjection_type; genericptr_t ptr1; genericptr_t ptr2; { switch (num) { case 1: { char *panicmsg = (char *) ptr1; char *datadir = (char *) ptr2; char *tempdir = nh_getenv("TEMP"); interjection_type = INTERJECT_PANIC; interjection[INTERJECT_PANIC] = 1; /* * ptr1 = the panic message about to be delivered. * ptr2 = the directory prefix of the dungeon file * that failed to open. * Check to see if datadir matches tempdir or a * common windows temp location. If it does, inform * the user that they are probably trying to run the * game from within their unzip utility, so the required * files really don't exist at the location. Instruct * them to unpack them first. */ if (panicmsg && datadir) { if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15) || strstri(datadir, "TEMP") || (tempdir && strstri(datadir, tempdir))) { (void) strncpy( interjection_buf[INTERJECT_PANIC], "\nOne common cause of this error is attempting to " "execute\n" "the game by double-clicking on it while it is " "displayed\n" "inside an unzip utility.\n\n" "You have to unzip the contents of the zip file into a\n" "folder on your system, and then run \"NetHack.exe\" or " "\n" "\"NetHackW.exe\" from there.\n\n" "If that is not the situation, you are encouraged to\n" "report the error as shown above.\n\n", 1023); } } } break; } } void interject(interjection_type) int interjection_type; { if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES) msmsg(interjection_buf[interjection_type]); } #ifdef RUNTIME_PORT_ID /* * _M_IX86 is Defined for x86 processors. This is not defined for x64 * processors. * _M_X64 is Defined for x64 processors. * _M_IA64 is Defined for Itanium Processor Family 64-bit processors. * _WIN64 is Defined for applications for Win64. */ #ifndef _M_IX86 #ifdef _M_X64 #define TARGET_PORT "(x64) " #endif #ifdef _M_IA64 #define TARGET_PORT "(IA64) " #endif #endif #ifndef TARGET_PORT #define TARGET_PORT "(x86) " #endif void append_port_id(buf) char *buf; { char *portstr = TARGET_PORT; Sprintf(eos(buf), " %s", portstr); } #endif /* RUNTIME_PORT_ID */ #endif /* WIN32 */ /*winnt.c*/ nethack-3.6.0/util/dgn_comp.l0000664000076400007660000001036612631241231015056 0ustar paxedpaxed%{ /* NetHack 3.6 dgn_comp.l $NHDT-Date: 1449385184 2015/12/06 06:59:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #define DGN_COMP #include "config.h" #include "dgn_comp.h" #include "dgn_file.h" /* * Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #else /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ /* most recent flex allows suppressing yyunput() altogether when not needed */ #define YY_NO_UNPUT #endif #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) /* older flex wants this */ #define YY_MALLOC_DECL genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t, size_t)); /* newer flex assumes so needs this in case it's been suppressed */ YY_MALLOC_DECL #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); /* this doesn't always get put in dgn_comp.h * (esp. when using older versions of bison) */ extern YYSTYPE yylval; int nh_line_number = 1; %} %% DUNGEON return(A_DUNGEON); up { yylval.i=1; return(UP_OR_DOWN); } down { yylval.i=0; return(UP_OR_DOWN); } ENTRY return(ENTRY); stair return(STAIR); no_up return(NO_UP); no_down return(NO_DOWN); portal return(PORTAL); PROTOFILE return(PROTOFILE); DESCRIPTION return(DESCRIPTION); LEVELDESC return(LEVELDESC); ALIGNMENT return(ALIGNMENT); LEVALIGN return(LEVALIGN); town { yylval.i=TOWN ; return(DESCRIPTOR); } hellish { yylval.i=HELLISH ; return(DESCRIPTOR); } mazelike { yylval.i=MAZELIKE ; return(DESCRIPTOR); } roguelike { yylval.i=ROGUELIKE ; return(DESCRIPTOR); } unaligned { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } noalign { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } lawful { yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); } neutral { yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); } chaotic { yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); } BRANCH return(BRANCH); CHAINBRANCH return(CHBRANCH); LEVEL return(LEVEL); RNDLEVEL return(RNDLEVEL); CHAINLEVEL return(CHLEVEL); RNDCHLEVEL return(RNDCHLEVEL); [-0-9]+ { yylval.i=atoi(yytext); return(INTEGER); } \"[^"]*\" { yytext[yyleng - 1] = '\0'; /* discard the trailing \" */ yylval.str = dupstr(yytext + 1); /* skip the first \" */ return STRING; } ^#.*\n { nh_line_number++; } \r?\n { nh_line_number++; } [ \t]+ ; /* skip trailing tabs & spaces */ . { return yytext[0]; } %% /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } /*dgn_comp.l*/ nethack-3.6.0/util/dgn_comp.y0000664000076400007660000003726612536476415015125 0ustar paxedpaxed%{ /* NetHack 3.6 dgn_comp.y $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Dungeon Compiler code */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive in its non-standard locale. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #include "config.h" #include "date.h" #include "dgn_file.h" void FDECL(yyerror, (const char *)); void FDECL(yywarning, (const char *)); int NDECL(yylex); int NDECL(yyparse); int FDECL(getchain, (char *)); int NDECL(check_dungeon); int NDECL(check_branch); int NDECL(check_level); void NDECL(init_dungeon); void NDECL(init_branch); void NDECL(init_level); void NDECL(output_dgn); #define Free(ptr) free((genericptr_t)ptr) #ifdef AMIGA # undef printf #ifndef LATTICE # define memset(addr,val,len) setmem(addr,len,val) #endif #endif #define ERR (-1) static struct couple couple; static struct tmpdungeon tmpdungeon[MAXDUNGEON]; static struct tmplevel tmplevel[LEV_LIMIT]; static struct tmpbranch tmpbranch[BRANCH_LIMIT]; static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1; extern int fatal_error; extern const char *fname; extern FILE *yyin, *yyout; /* from dgn_lex.c */ %} %union { int i; char* str; } %token INTEGER %token A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL %token UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC %token ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL %token STRING %type optional_int direction branch_type bones_tag %start file %% file : /* nothing */ | dungeons { output_dgn(); } ; dungeons : dungeon | dungeons dungeon ; dungeon : dungeonline | dungeondesc | branches | levels ; dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int { init_dungeon(); Strcpy(tmpdungeon[n_dgns].name, $3); tmpdungeon[n_dgns].boneschar = (char)$4; tmpdungeon[n_dgns].lev.base = couple.base; tmpdungeon[n_dgns].lev.rand = couple.rand; tmpdungeon[n_dgns].chance = $6; Free($3); } ; optional_int : /* nothing */ { $$ = 0; } | INTEGER { $$ = $1; } ; dungeondesc : entry | descriptions | prototype ; entry : ENTRY ':' INTEGER { tmpdungeon[n_dgns].entry_lev = $3; } ; descriptions : desc ; desc : DESCRIPTION ':' DESCRIPTOR { if($3 <= TOWN || $3 >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmpdungeon[n_dgns].flags |= $3 ; } | ALIGNMENT ':' DESCRIPTOR { if($3 && $3 < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmpdungeon[n_dgns].flags |= $3 ; } ; prototype : PROTOFILE ':' STRING { Strcpy(tmpdungeon[n_dgns].protoname, $3); Free($3); } ; levels : level1 | level2 | levdesc | chlevel1 | chlevel2 ; level1 : LEVEL ':' STRING bones_tag '@' acouple { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmpdungeon[n_dgns].levels++; Free($3); } | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = $7; tmpdungeon[n_dgns].levels++; Free($3); } ; level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $7; tmpdungeon[n_dgns].levels++; Free($3); } | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $7; tmplevel[n_levs].rndlevs = $8; tmpdungeon[n_dgns].levels++; Free($3); } ; levdesc : LEVELDESC ':' DESCRIPTOR { if($3 >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmplevel[n_levs].flags |= $3 ; } | LEVALIGN ':' DESCRIPTOR { if($3 && $3 < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmplevel[n_levs].flags |= $3 ; } ; chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = $8; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } ; chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $8; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $8; tmplevel[n_levs].rndlevs = $9; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } ; branches : branch | chbranch ; branch : BRANCH ':' STRING '@' acouple branch_type direction { init_branch(); Strcpy(tmpbranch[n_brs].name, $3); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = $6; tmpbranch[n_brs].up = $7; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free($3); } ; chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction { init_branch(); Strcpy(tmpbranch[n_brs].name, $3); tmpbranch[n_brs].chain = getchain($4); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = $7; tmpbranch[n_brs].up = $8; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free($3); Free($4); } ; branch_type : /* nothing */ { $$ = TBR_STAIR; /* two way stair */ } | STAIR { $$ = TBR_STAIR; /* two way stair */ } | NO_UP { $$ = TBR_NO_UP; /* no up staircase */ } | NO_DOWN { $$ = TBR_NO_DOWN; /* no down staircase */ } | PORTAL { $$ = TBR_PORTAL; /* portal connection */ } ; direction : /* nothing */ { $$ = 0; /* defaults to down */ } | UP_OR_DOWN { $$ = $1; } ; bones_tag : STRING { char *p = $1; if (strlen(p) != 1) { if (strcmp(p, "none") != 0) yyerror("Bones marker must be a single char, or \"none\"!"); *p = '\0'; } $$ = *p; Free(p); } ; /* * acouple rules: * * (base, range) where: * * base is either a positive or negative integer with a value * less than or equal to MAXLEVEL. * base > 0 indicates the base level. * base < 0 indicates reverse index (-1 == lowest level) * * range is the random component. * if range is zero, there is no random component. * if range is -1 the dungeon loader will randomize between * the base and the end of the dungeon. * during dungeon load, range is always *added* to the base, * therefore range + base(converted) must not exceed MAXLEVEL. */ acouple : '(' INTEGER ',' INTEGER ')' { if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { yyerror("Abs base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else if ($4 < -1 || (($2 < 0) ? (MAXLEVEL + $2 + $4 + 1) > MAXLEVEL : ($2 + $4) > MAXLEVEL)) { yyerror("Abs range out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = $2; couple.rand = $4; } } ; /* * rcouple rules: * * (base, range) where: * * base is either a positive or negative integer with a value * less than or equal to MAXLEVEL. * base > 0 indicates a forward index. * base < 0 indicates a reverse index. * base == 0 indicates on the parent level. * * range is the random component. * if range is zero, there is no random component. * during dungeon load, range is always *added* to the base, * range + base(converted) may be very large. The dungeon * loader will then correct to "between here and the top/bottom". * * There is no practical way of specifying "between here and the * nth / nth last level". */ rcouple : '(' INTEGER ',' INTEGER ')' { if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { yyerror("Rel base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = $2; couple.rand = $4; } } ; %% void init_dungeon() { if(++n_dgns > MAXDUNGEON) { (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n", MAXDUNGEON); (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n"); exit(EXIT_FAILURE); } in_dungeon = 1; tmpdungeon[n_dgns].lev.base = 0; tmpdungeon[n_dgns].lev.rand = 0; tmpdungeon[n_dgns].chance = 100; Strcpy(tmpdungeon[n_dgns].name, ""); Strcpy(tmpdungeon[n_dgns].protoname, ""); tmpdungeon[n_dgns].flags = 0; tmpdungeon[n_dgns].levels = 0; tmpdungeon[n_dgns].branches = 0; tmpdungeon[n_dgns].entry_lev = 0; } void init_level() { if(++n_levs > LEV_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmplevel[n_levs].lev.base = 0; tmplevel[n_levs].lev.rand = 0; tmplevel[n_levs].chance = 100; tmplevel[n_levs].rndlevs = 0; tmplevel[n_levs].flags = 0; Strcpy(tmplevel[n_levs].name, ""); tmplevel[n_levs].chain = -1; } void init_branch() { if(++n_brs > BRANCH_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmpbranch[n_brs].lev.base = 0; tmpbranch[n_brs].lev.rand = 0; Strcpy(tmpbranch[n_brs].name, ""); tmpbranch[n_brs].chain = -1; } int getchain(s) char *s; { int i; if(strlen(s)) { for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++) if(!strcmp(tmplevel[i].name, s)) return i; yyerror("Can't locate the specified chain level."); return(-2); } return(-1); } /* * Consistancy checking routines: * * - A dungeon must have a unique name. * - A dungeon must have a originating "branch" command * (except, of course, for the first dungeon). * - A dungeon must have a proper depth (at least (1, 0)). */ int check_dungeon() { int i; for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) { yyerror("Duplicate dungeon name."); return(0); } if(n_dgns) for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) { if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break; if(i >= n_brs - tmpdungeon[n_dgns].branches) { yyerror("Dungeon cannot be reached."); return(0); } } if(tmpdungeon[n_dgns].lev.base <= 0 || tmpdungeon[n_dgns].lev.rand < 0) { yyerror("Invalid dungeon depth specified."); return(0); } return(1); /* OK */ } /* * - A level must have a unique level name. * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_level() { int i; if(!in_dungeon) { yyerror("Level defined outside of dungeon."); return(0); } for(i = 0; i < n_levs; i++) if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) { yyerror("Duplicate level name."); return(0); } if(tmplevel[i].chain == -2) { yyerror("Invaild level chain reference."); return(0); } else if(tmplevel[i].chain != -1) { /* there is a chain */ /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */ if(tmplevel[tmplevel[i].chain].chance != 100) { yyerror("Level cannot chain from a probabilistic level."); return(0); } else if(tmplevel[i].chain == n_levs) { yyerror("A level cannot chain to itself!"); return(0); } } return(1); /* OK */ } /* * - A branch may not branch backwards - to avoid branch loops. * - A branch name must be unique. * (ie. You can only have one entry point to each dungeon). * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_branch() { int i; if(!in_dungeon) { yyerror("Branch defined outside of dungeon."); return(0); } for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) { yyerror("Reverse branching not allowed."); return(0); } if(tmpbranch[i].chain == -2) { yyerror("Invaild branch chain reference."); return(0); } else if(tmpbranch[i].chain != -1) { /* it is chained */ if(tmplevel[tmpbranch[i].chain].chance != 100) { yyerror("Branch cannot chain from a probabilistic level."); return(0); } } return(1); /* OK */ } /* * Output the dungon definition into a file. * * The file will have the following format: * * [ nethack version ID ] * [ number of dungeons ] * [ first dungeon struct ] * [ levels for the first dungeon ] * ... * [ branches for the first dungeon ] * ... * [ second dungeon struct ] * ... */ void output_dgn() { int nd, cl = 0, nl = 0, cb = 0, nb = 0; static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3 }; if(++n_dgns <= 0) { yyerror("FATAL - no dungeons were defined."); exit(EXIT_FAILURE); } if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) { yyerror("FATAL - output failure."); exit(EXIT_FAILURE); } (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout); for (nd = 0; nd < n_dgns; nd++) { (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), 1, yyout); nl += tmpdungeon[nd].levels; for(; cl < nl; cl++) (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), 1, yyout); nb += tmpdungeon[nd].branches; for(; cb < nb; cb++) (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), 1, yyout); } /* apparently necessary for Think C 5.x, otherwise harmless */ (void) fflush(yyout); } /*dgn_comp.y*/ nethack-3.6.0/util/dgn_main.c0000664000076400007660000001224012536476415015046 0ustar paxedpaxed/* NetHack 3.6 dgn_main.c $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the main function for the parser * and some useful functions needed by yacc */ #include "config.h" #include "dlb.h" /* Macintosh-specific code */ #if defined(__APPLE__) && defined(__MACH__) /* MacOS X has Unix-style files and processes */ #undef MAC #endif #ifdef MAC #if defined(__SC__) || defined(__MRC__) #define MPWTOOL #include #else /* put dungeon file in library location */ #define PREFIX ":lib:" #endif #endif #ifndef MPWTOOL #define SpinCursor(x) #endif #define MAX_ERRORS 25 extern int NDECL(yyparse); extern int nh_line_number; const char *fname = "(stdin)"; int fatal_error = 0; int FDECL(main, (int, char **)); void FDECL(yyerror, (const char *)); void FDECL(yywarning, (const char *)); int NDECL(yywrap); void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); #ifdef AZTEC_36 FILE *FDECL(freopen, (char *, char *, FILE *)); #endif #define Fprintf (void) fprintf #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif int main(argc, argv) int argc; char **argv; { char infile[64], outfile[64], basename[64]; FILE *fin, *fout; int i, len; boolean errors_encountered = FALSE; #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) char *mark; static char *mac_argv[] = { "dgn_comp", /* dummy argv[0] */ ":dat:dungeon.pdf" }; argc = SIZE(mac_argv); argv = mac_argv; #endif Strcpy(infile, "(stdin)"); fin = stdin; Strcpy(outfile, "(stdout)"); fout = stdout; if (argc == 1) { /* Read standard input */ init_yyin(fin); init_yyout(fout); (void) yyparse(); if (fatal_error > 0) errors_encountered = TRUE; } else { /* Otherwise every argument is a filename */ for (i = 1; i < argc; i++) { fname = strcpy(infile, argv[i]); /* the input file had better be a .pdf file */ len = strlen(fname) - 4; /* length excluding suffix */ if (len < 0 || strncmp(".pdf", fname + len, 4)) { Fprintf(stderr, "Error - file name \"%s\" in wrong format.\n", fname); errors_encountered = TRUE; continue; } /* build output file name */ #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) /* extract basename from path to infile */ mark = strrchr(infile, ':'); strcpy(basename, mark ? mark + 1 : infile); mark = strchr(basename, '.'); if (mark) *mark = '\0'; #else /* Use the whole name - strip off the last 3 or 4 chars. */ #ifdef VMS /* avoid possible interaction with logical name */ len++; /* retain "." as trailing punctuation */ #endif (void) strncpy(basename, infile, len); basename[len] = '\0'; #endif outfile[0] = '\0'; #ifdef PREFIX (void) strcat(outfile, PREFIX); #endif (void) strcat(outfile, basename); fin = freopen(infile, "r", stdin); if (!fin) { Fprintf(stderr, "Can't open %s for input.\n", infile); perror(infile); errors_encountered = TRUE; continue; } fout = freopen(outfile, WRBMODE, stdout); if (!fout) { Fprintf(stderr, "Can't open %s for output.\n", outfile); perror(outfile); errors_encountered = TRUE; continue; } init_yyin(fin); init_yyout(fout); (void) yyparse(); nh_line_number = 1; if (fatal_error > 0) { errors_encountered = TRUE; fatal_error = 0; } } } if (fout && fclose(fout) < 0) { Fprintf(stderr, "Can't finish output file."); perror(outfile); errors_encountered = TRUE; } exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS); /*NOTREACHED*/ return 0; } /* * Each time the parser detects an error, it uses this function. * Here we take count of the errors. To continue farther than * MAX_ERRORS wouldn't be reasonable. */ void yyerror(s) const char *s; { (void) fprintf(stderr, "%s : line %d : %s\n", fname, nh_line_number, s); if (++fatal_error > MAX_ERRORS) { (void) fprintf(stderr, "Too many errors, good bye!\n"); exit(EXIT_FAILURE); } } /* * Just display a warning (that is : a non fatal error) */ void yywarning(s) const char *s; { (void) fprintf(stderr, "%s : line %d : WARNING : %s\n", fname, nh_line_number, s); } int yywrap() { SpinCursor(3); /* Don't know if this is a good place to put it ? Is it called for our grammar ? Often enough ? Too often ? -- h+ */ return 1; } /*dgn_main.c*/ nethack-3.6.0/util/dlb_main.c0000664000076400007660000003643012536476415015046 0ustar paxedpaxed/* NetHack 3.6 dlb_main.c $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* data librarian; only useful if you are making the library version, DLBLIB */ #include "config.h" #include "dlb.h" #if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C) #include #endif #if defined(__DJGPP__) #include #endif static void FDECL(grow_ld, (libdir **, int *, int)); static void FDECL(xexit, (int)); #ifdef DLB #ifdef DLBLIB #define DLB_DIRECTORY "Directory" /* name of lib directory */ #define LIBLISTFILE "dlb.lst" /* default list file */ /* library functions (from dlb.c) */ extern boolean FDECL(open_library, (const char *, library *)); extern void FDECL(close_library, (library *)); char *FDECL(eos, (char *)); /* also used by dlb.c */ FILE *FDECL(fopen_datafile, (const char *, const char *)); static void FDECL(Write, (int, char *, long)); static void NDECL(usage); static void NDECL(verbose_help); static void FDECL(write_dlb_directory, (int, int, libdir *, long, long, long)); static char default_progname[] = "dlb"; static char *progname = default_progname; /* fixed library and list file names - can be overridden if necessary */ static const char *library_file = DLBFILE; static const char *list_file = LIBLISTFILE; #ifdef AMIGA static char origdir[255] = ""; #endif #ifndef O_BINARY #define O_BINARY 0 #endif #define DLB_FILES_ALLOC 200 /* initial # of files we'll handle; can grow */ #define DLB_VERS 1 /* version of dlb file we will write */ /* * How the file is encoded within the library. Don't use a space * because (at least) the SunOS 4.1.3 C library will eat the white * space instead of preserving it like the man page says it should. */ #define ENC_NORMAL 'n' /* normal: not compressed in any way */ /* * If you know tar, you have a small clue how to use this (note: - does * NOT mean stdin/stdout). * * dlb COMMANDoptions arg... files... * commands: * dlb x extract all files * dlb c build the archive * dlb t list the archive * options: * v verbose * f file specify archive file (default DLBFILE) * I file specify file for list of files (default LIBLISTFILE) * C dir chdir to dir (used ONCE, not like tar's -C) */ static void usage() { (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname); (void) printf(" default library is %s\n", library_file); (void) printf(" default list file is %s\n", list_file); xexit(EXIT_FAILURE); } static void verbose_help() { static const char *long_help[] = { "", "dlb COMMANDoptions args... files...", " commands:", " dlb ? print this text", " dlb h ditto", " dlb x extract all files", " dlb c create the archive", " dlb t list table of contents", " options:", " v verbose operation", " f file specify archive file name", " I file specify file for list of file names", " C dir change directory before processing any files", "", (char *) 0 }; const char **str; for (str = long_help; *str; str++) (void) printf("%s\n", *str); usage(); } static void Write(out, buf, len) int out; char *buf; long len; { #if defined(MSDOS) && !defined(__DJGPP__) unsigned short slen; if (len > 65534) { printf("%d Length specified for write() too large for 16 bit env.", len); xexit(EXIT_FAILURE); } slen = (unsigned short) len; if (write(out, buf, slen) != slen) { #else if (write(out, buf, len) != len) { #endif printf("Write Error in '%s'\n", library_file); xexit(EXIT_FAILURE); } } char * eos(s) char *s; { while (*s) s++; return s; } /* open_library(dlb.c) needs this (which normally comes from src/files.c) */ FILE * fopen_datafile(filename, mode) const char *filename, *mode; { return fopen(filename, mode); } #endif /* DLBLIB */ #endif /* DLB */ int main(argc, argv) int argc; char **argv; { #ifdef DLB #ifdef DLBLIB int i, r; int ap = 2; /* argument pointer */ int cp; /* command pointer */ int iseen = 0, fseen = 0, verbose = 0; /* flags */ char action = ' '; library lib; if (argc > 0 && argv[0] && *argv[0]) progname = argv[0]; #ifdef VMS progname = vms_basename(progname); #endif if (argc < 2) { usage(); /* doesn't return */ } for (cp = 0; argv[1][cp]; cp++) { switch (argv[1][cp]) { default: usage(); /* doesn't return */ case '-': /* silently ignore */ break; case '?': case 'h': verbose_help(); break; case 'I': if (ap == argc) usage(); list_file = argv[ap++]; if (iseen) printf("Warning: multiple I options. Previous ignored.\n"); iseen = 1; break; case 'f': if (ap == argc) usage(); library_file = argv[ap++]; if (fseen) printf("Warning: multiple f options. Previous ignored.\n"); fseen = 1; break; case 'C': if (ap == argc) usage(); #ifdef AMIGA if (!getcwd(origdir, sizeof(origdir))) { printf("Can't get current directory.\n"); xexit(EXIT_FAILURE); } #endif if (chdir(argv[ap++])) { printf("Can't chdir to %s\n", argv[--ap]); xexit(EXIT_FAILURE); } break; case 'v': verbose = 1; break; case 't': case 'c': case 'x': if (action != ' ') { printf("Only one of t,x,c may be specified.\n"); usage(); } action = argv[1][cp]; break; } } if (argv[ap] && iseen) { printf("Too many arguments.\n"); xexit(EXIT_FAILURE); } switch (action) { default: printf("Internal error - action.\n"); xexit(EXIT_FAILURE); break; case 't': /* list archive */ if (!open_library(library_file, &lib)) { printf("Can't open dlb file\n"); xexit(EXIT_FAILURE); } for (i = 0; i < lib.nentries; i++) { if (verbose) printf("%-14s %6ld %6ld\n", lib.dir[i].fname, lib.dir[i].foffset, lib.dir[i].fsize); else printf("%s\n", lib.dir[i].fname); } if (verbose) printf("Revision:%ld File count:%ld String size:%ld\n", lib.rev, lib.nentries, lib.strsize); close_library(&lib); xexit(EXIT_SUCCESS); case 'x': { /* extract archive contents */ int f, n; long remainder, total_read; char buf[BUFSIZ]; if (!open_library(library_file, &lib)) { printf("Can't open dlb file\n"); xexit(EXIT_FAILURE); } for (i = 0; i < lib.nentries; i++) { if (argv[ap]) { /* if files are listed, see if current is wanted */ int c; for (c = ap; c < argc; c++) if (!FILENAME_CMP(lib.dir[i].fname, argv[c])) break; if (c == argc) continue; /* skip */ } else if (!FILENAME_CMP(lib.dir[i].fname, DLB_DIRECTORY)) { /* * Don't extract the directory unless the user * specifically asks for it. * * Perhaps we should never extract the directory??? */ continue; } fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET); f = open(lib.dir[i].fname, O_WRONLY | O_TRUNC | O_BINARY | O_CREAT, 0640); if (f < 0) { printf("Can't create '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); } /* read chunks from library and write them out */ total_read = 0; do { remainder = lib.dir[i].fsize - total_read; if (remainder > (long) sizeof(buf)) r = (int) sizeof(buf); else r = remainder; n = fread(buf, 1, r, lib.fdata); if (n != r) { printf("Read Error in '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); } if (write(f, buf, n) != n) { printf("Write Error in '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); } total_read += n; } while (total_read != lib.dir[i].fsize); (void) close(f); if (verbose) printf("x %s\n", lib.dir[i].fname); } close_library(&lib); xexit(EXIT_SUCCESS); } case 'c': /* create archive */ { libdir *ld = 0; int ldlimit = 0; char buf[BUFSIZ]; int fd, out, nfiles = 0; long dir_size, slen, flen, fsiz; boolean rewrite_directory = FALSE; /* * Get names from either/both an argv list and a file * list. This does not do any duplicate checking */ grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC); /* get file name in argv list */ if (argv[ap]) { for (; ap < argc; ap++, nfiles++) { if (nfiles == ldlimit) grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5); ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1); Strcpy(ld[nfiles].fname, argv[ap]); } } if (iseen) { /* want to do a list file */ FILE *list = fopen(list_file, "r"); if (!list) { printf("Can't open %s\n", list_file); xexit(EXIT_FAILURE); } /* get file names, one per line */ for (; fgets(buf, sizeof(buf), list); nfiles++) { if (nfiles == ldlimit) grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5); *(eos(buf) - 1) = '\0'; /* strip newline */ ld[nfiles].fname = (char *) alloc(strlen(buf) + 1); Strcpy(ld[nfiles].fname, buf); } fclose(list); } if (nfiles == 0) { printf("No files to archive\n"); xexit(EXIT_FAILURE); } /* * Get file sizes and name string length. Don't include * the directory information yet. */ for (i = 0, slen = 0, flen = 0; i < nfiles; i++) { fd = open(ld[i].fname, O_RDONLY | O_BINARY, 0); if (fd < 0) { printf("Can't open %s\n", ld[i].fname); xexit(EXIT_FAILURE); } ld[i].fsize = lseek(fd, 0, SEEK_END); ld[i].foffset = flen; slen += strlen(ld[i].fname); /* don't add null (yet) */ flen += ld[i].fsize; close(fd); } /* open output file */ out = open(library_file, O_RDWR | O_TRUNC | O_BINARY | O_CREAT, FCMASK); if (out < 0) { printf("Can't open %s for output\n", library_file); xexit(EXIT_FAILURE); } /* caculate directory size */ dir_size = 40 /* header line (see below) */ + ((nfiles + 1) * 11) /* handling+file offset+SP+newline */ + slen + strlen(DLB_DIRECTORY); /* file names */ /* write directory */ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen); flen = 0L; /* write each file */ for (i = 0; i < nfiles; i++) { fd = open(ld[i].fname, O_RDONLY | O_BINARY, 0); if (fd < 0) { printf("Can't open input file '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); } if (verbose) printf("%s\n", ld[i].fname); fsiz = 0L; while ((r = read(fd, buf, sizeof buf)) != 0) { if (r == -1) { printf("Read Error in '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); } if (write(out, buf, r) != r) { printf("Write Error in '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); } fsiz += r; } (void) close(fd); if (fsiz != ld[i].fsize) rewrite_directory = TRUE; /* in case directory rewrite is needed */ ld[i].fsize = fsiz; ld[i].foffset = flen; flen += fsiz; } if (rewrite_directory) { if (verbose) printf("(rewriting dlb directory info)\n"); (void) lseek(out, 0, SEEK_SET); /* rewind */ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen); } for (i = 0; i < nfiles; i++) free((genericptr_t) ld[i].fname), ld[i].fname = 0; free((genericptr_t) ld), ldlimit = 0; (void) close(out); xexit(EXIT_SUCCESS); } } #endif /* DLBLIB */ #endif /* DLB */ xexit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #ifdef DLB #ifdef DLBLIB static void grow_ld(ld_p, ldlimit_p, alloc_incr) libdir **ld_p; int *ldlimit_p; int alloc_incr; { static libdir zerolibdir; int i = 0, newlimit = *ldlimit_p + alloc_incr; libdir *newld = (libdir *) alloc(newlimit * sizeof *newld); if (*ld_p) { for (; i < *ldlimit_p; ++i) newld[i] = (*ld_p)[i]; free((genericptr_t) *ld_p); } *ld_p = newld, *ldlimit_p = newlimit; for (; i < *ldlimit_p; ++i) (*ld_p)[i] = zerolibdir; } static void write_dlb_directory(out, nfiles, ld, slen, dir_size, flen) int out, nfiles; libdir *ld; long slen, dir_size, flen; { char buf[BUFSIZ]; int i; sprintf(buf, "%3ld %8ld %8ld %8ld %8ld\n", (long) DLB_VERS, /* version of dlb file */ (long) nfiles + 1, /* # of entries (includes directory) */ /* string length + room for nulls */ (long) slen + strlen(DLB_DIRECTORY) + nfiles + 1, (long) dir_size, /* start of first file */ (long) flen + dir_size); /* total file size */ Write(out, buf, strlen(buf)); /* write each file entry */ #define ENTRY_FORMAT "%c%s %8ld\n" sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, DLB_DIRECTORY, (long) 0); Write(out, buf, strlen(buf)); for (i = 0; i < nfiles; i++) { sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, /* encoding */ ld[i].fname, /* name */ ld[i].foffset + dir_size); /* offset */ Write(out, buf, strlen(buf)); } } #endif /* DLBLIB */ #endif /* DLB */ static void xexit(retcd) int retcd; { #ifdef DLB #ifdef AMIGA if (origdir[0]) chdir(origdir); #endif #endif exit(retcd); } #ifdef AMIGA #include "date.h" const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif /*dlb_main.c*/ nethack-3.6.0/util/lev_comp.l0000664000076400007660000003650512631241231015077 0ustar paxedpaxed%{ /* NetHack 3.6 lev_comp.l $NHDT-Date: 1449385191 2015/12/06 06:59:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #define LEV_LEX_C #include "hack.h" #include "lev_comp.h" #include "sp_lev.h" /* Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #else /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ /* most recent flex allows suppressing yyunput() altogether when not needed */ #define YY_NO_UNPUT #endif #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) /* older flex wants this */ #define YY_MALLOC_DECL genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t, size_t)); /* newer flex assumes so needs this in case it's been suppressed */ YY_MALLOC_DECL #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); long NDECL(handle_varstring_check); long FDECL(corefunc_str_check, (char *, long)); extern void VDECL(lc_error, (const char *, ...)); extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int)); extern struct lc_vardefs *variable_definitions; extern long FDECL(method_defined, (char *, long, long *)); void FDECL(savetoken, (char *)); void NDECL(newline); void FDECL(advancepos, (char *)); /* * This doesn't always get put in lev_comp.h * (esp. when using older versions of bison). */ extern YYSTYPE yylval; int nh_line_number = 1; int token_start_pos = 0; char curr_token[512]; static char map[4096]; static int map_cnt = 0; FILE *orig_yyin = NULL; #define ST_RET(x) do { savetoken(yytext); return x; } while (0); #define ST_RETF(y, x) do { savetoken(yytext); y; return x; } while (0); %} %e 2000 %p 5000 %n 700 %s MAPC %% ENDMAP { savetoken(yytext); BEGIN(INITIAL); yylval.map = (char *) alloc(map_cnt + 1); (void) strncpy(yylval.map, map, map_cnt); yylval.map[map_cnt] = 0; map_cnt = 0; return MAP_ID; } [-|}{+xABCISHKPLWTF\\#. 0123456789]*\r?\n { int len = yyleng; savetoken(yytext); /* convert \r\n to \n */ if (len >= 2 && yytext[len - 2] == '\r') len -= 1; (void) strncpy(map + map_cnt, yytext, len); map_cnt += len; map[map_cnt - 1] = '\n'; map[map_cnt] = '\0'; newline(); } ^[ \t]*#.*\n { savetoken(yytext); newline(); } MESSAGE ST_RET(MESSAGE_ID); NOMAP ST_RET(NOMAP_ID); MAZE ST_RET(MAZE_ID); LEVEL ST_RET(LEVEL_ID); INIT_MAP ST_RET(LEV_INIT_ID); mazegrid ST_RET(MAZE_GRID_ID); solidfill ST_RET(SOLID_FILL_ID); mines ST_RET(MINES_ID); rogue ST_RET(ROGUELEV_ID); FLAGS ST_RET(FLAGS_ID); GEOMETRY ST_RET(GEOMETRY_ID); ^MAP\r?\n { savetoken(yytext); BEGIN(MAPC); newline(); } obj(ect)? ST_RET(object_ID); OBJECT ST_RET(OBJECT_ID); CONTAINER ST_RET(COBJECT_ID); MONSTER ST_RET(MONSTER_ID); monster ST_RET(monster_ID); TRAP ST_RET(TRAP_ID); DOOR ST_RET(DOOR_ID); ROOMDOOR ST_RET(ROOMDOOR_ID); DRAWBRIDGE ST_RET(DRAWBRIDGE_ID); MAZEWALK ST_RET(MAZEWALK_ID); WALLIFY ST_RET(WALLIFY_ID); REGION ST_RET(REGION_ID); ALTAR ST_RET(ALTAR_ID); LADDER ST_RET(LADDER_ID); STAIR ST_RET(STAIR_ID); PORTAL ST_RET(PORTAL_ID); TELEPORT_REGION ST_RET(TELEPRT_ID); BRANCH ST_RET(BRANCH_ID); FOUNTAIN ST_RET(FOUNTAIN_ID); SINK ST_RET(SINK_ID); POOL ST_RET(POOL_ID); NON_DIGGABLE ST_RET(NON_DIGGABLE_ID); NON_PASSWALL ST_RET(NON_PASSWALL_ID); IF ST_RET(IF_ID); ELSE ST_RET(ELSE_ID); EXIT ST_RET(EXIT_ID); ROOM ST_RET(ROOM_ID); SUBROOM ST_RET(SUBROOM_ID); RANDOM_CORRIDORS ST_RET(RAND_CORRIDOR_ID); CORRIDOR ST_RET(CORRIDOR_ID); TERRAIN ST_RET(TERRAIN_ID); terrain ST_RET(terrain_ID); REPLACE_TERRAIN ST_RET(REPLACE_TERRAIN_ID); GOLD ST_RET(GOLD_ID); GRAVE ST_RET(GRAVE_ID); ENGRAVING ST_RET(ENGRAVING_ID); MINERALIZE ST_RET(MINERALIZE_ID); (NAME|name) ST_RET(NAME_ID); FOR ST_RET(FOR_ID); TO ST_RET(TO_ID); LOOP ST_RET(LOOP_ID); SWITCH ST_RET(SWITCH_ID); CASE ST_RET(CASE_ID); BREAK ST_RET(BREAK_ID); DEFAULT ST_RET(DEFAULT_ID); FUNCTION ST_RET(FUNCTION_ID); SHUFFLE ST_RET(SHUFFLE_ID); montype ST_RET(MONTYPE_ID); selection ST_RET(selection_ID); rect ST_RET(rect_ID); fillrect ST_RET(fillrect_ID); line ST_RET(line_ID); randline ST_RET(randline_ID); grow ST_RET(grow_ID); floodfill ST_RET(flood_ID); rndcoord ST_RET(rndcoord_ID); circle ST_RET(circle_ID); ellipse ST_RET(ellipse_ID); filter ST_RET(filter_ID); gradient ST_RET(gradient_ID); complement ST_RET(complement_ID); radial { savetoken(yytext); yylval.i=SEL_GRADIENT_RADIAL; return GRADIENT_TYPE; } square { savetoken(yytext); yylval.i=SEL_GRADIENT_SQUARE; return GRADIENT_TYPE; } dry { savetoken(yytext); yylval.i=DRY; return HUMIDITY_TYPE; } wet { savetoken(yytext); yylval.i=WET; return HUMIDITY_TYPE; } hot { savetoken(yytext); yylval.i=HOT; return HUMIDITY_TYPE; } solid { savetoken(yytext); yylval.i=SOLID; return HUMIDITY_TYPE; } any { savetoken(yytext); yylval.i=ANY_LOC; return HUMIDITY_TYPE; } levregion ST_RET(LEV); quantity ST_RET(QUANTITY_ID); buried ST_RET(BURIED_ID); eroded ST_RET(ERODED_ID); erodeproof ST_RET(ERODEPROOF_ID); trapped { savetoken(yytext); yylval.i=1; return TRAPPED_STATE; } not_trapped { savetoken(yytext); yylval.i=0; return TRAPPED_STATE; } recharged ST_RET(RECHARGED_ID); invisible ST_RET(INVIS_ID); greased ST_RET(GREASED_ID); female ST_RET(FEMALE_ID); cancelled ST_RET(CANCELLED_ID); revived ST_RET(REVIVED_ID); avenge ST_RET(AVENGE_ID); fleeing ST_RET(FLEEING_ID); blinded ST_RET(BLINDED_ID); paralyzed ST_RET(PARALYZED_ID); stunned ST_RET(STUNNED_ID); confused ST_RET(CONFUSED_ID); seen_traps ST_RET(SEENTRAPS_ID); all ST_RET(ALL_ID); horizontal ST_RETF((yylval.i=1), HORIZ_OR_VERT); vertical { savetoken(yytext); yylval.i=2; return HORIZ_OR_VERT; } open { savetoken(yytext); yylval.i=D_ISOPEN; return DOOR_STATE; } closed { savetoken(yytext); yylval.i=D_CLOSED; return DOOR_STATE; } locked { savetoken(yytext); yylval.i=D_LOCKED; return DOOR_STATE; } nodoor { savetoken(yytext); yylval.i=D_NODOOR; return DOOR_STATE; } broken { savetoken(yytext); yylval.i=D_BROKEN; return DOOR_STATE; } secret { savetoken(yytext); yylval.i=D_SECRET; return DOOR_STATE; } north { savetoken(yytext); yylval.i=W_NORTH; return DIRECTION; } east { savetoken(yytext); yylval.i=W_EAST; return DIRECTION; } south { savetoken(yytext); yylval.i=W_SOUTH; return DIRECTION; } west { savetoken(yytext); yylval.i=W_WEST; return DIRECTION; } random { savetoken(yytext); yylval.i = -1; return RANDOM_TYPE; } random\[ { savetoken(yytext); yylval.i = -1; return RANDOM_TYPE_BRACKET; } none { savetoken(yytext); yylval.i = -2; return NONE; } align ST_RET(A_REGISTER); left { savetoken(yytext); yylval.i=1; return LEFT_OR_RIGHT; } half-left { savetoken(yytext); yylval.i=2; return LEFT_OR_RIGHT; } center { savetoken(yytext); yylval.i=3; return CENTER; } half-right { savetoken(yytext); yylval.i=4; return LEFT_OR_RIGHT; } right { savetoken(yytext); yylval.i=5; return LEFT_OR_RIGHT; } top { savetoken(yytext); yylval.i=1; return TOP_OR_BOT; } bottom { savetoken(yytext); yylval.i=5; return TOP_OR_BOT; } lit { savetoken(yytext); yylval.i=1; return LIGHT_STATE; } unlit { savetoken(yytext); yylval.i=0; return LIGHT_STATE; } filled { savetoken(yytext); yylval.i=1; return FILLING; } unfilled { savetoken(yytext); yylval.i=0; return FILLING; } regular { savetoken(yytext); yylval.i=0; return IRREGULAR; } irregular { savetoken(yytext); yylval.i=1; return IRREGULAR; } unjoined { savetoken(yytext); yylval.i=1; return JOINED; } joined { savetoken(yytext); yylval.i=0; return JOINED; } limited { savetoken(yytext); yylval.i=1; return LIMITED; } unlimited { savetoken(yytext); yylval.i=0; return LIMITED; } noalign { savetoken(yytext); yylval.i= AM_NONE; return ALIGNMENT; } law { savetoken(yytext); yylval.i= AM_LAWFUL; return ALIGNMENT; } neutral { savetoken(yytext); yylval.i= AM_NEUTRAL; return ALIGNMENT; } chaos { savetoken(yytext); yylval.i= AM_CHAOTIC; return ALIGNMENT; } coaligned { savetoken(yytext); yylval.i= AM_SPLEV_CO; return ALIGNMENT; } noncoaligned { savetoken(yytext); yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; } peaceful { savetoken(yytext); yylval.i=1; return MON_ATTITUDE; } hostile { savetoken(yytext); yylval.i=0; return MON_ATTITUDE; } asleep { savetoken(yytext); yylval.i=1; return MON_ALERTNESS; } awake { savetoken(yytext); yylval.i=0; return MON_ALERTNESS; } m_feature { savetoken(yytext); yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; } m_monster { savetoken(yytext); yylval.i= M_AP_MONSTER; return MON_APPEARANCE; } m_object { savetoken(yytext); yylval.i= M_AP_OBJECT; return MON_APPEARANCE; } sanctum { savetoken(yytext); yylval.i=2; return ALTAR_TYPE; } shrine { savetoken(yytext); yylval.i=1; return ALTAR_TYPE; } altar { savetoken(yytext); yylval.i=0; return ALTAR_TYPE; } up { savetoken(yytext); yylval.i=1; return UP_OR_DOWN; } down { savetoken(yytext); yylval.i=0; return UP_OR_DOWN; } false { savetoken(yytext); yylval.i=0; return BOOLEAN; } true { savetoken(yytext); yylval.i=1; return BOOLEAN; } dust { savetoken(yytext); yylval.i=DUST; return ENGRAVING_TYPE; } engrave { savetoken(yytext); yylval.i=ENGRAVE; return ENGRAVING_TYPE; } burn { savetoken(yytext); yylval.i=BURN; return ENGRAVING_TYPE; } mark { savetoken(yytext); yylval.i=MARK; return ENGRAVING_TYPE; } blood { savetoken(yytext); yylval.i=ENGR_BLOOD; return ENGRAVING_TYPE; } blessed { savetoken(yytext); yylval.i=1; return CURSE_TYPE; } uncursed { savetoken(yytext); yylval.i=2; return CURSE_TYPE; } cursed { savetoken(yytext); yylval.i=3; return CURSE_TYPE; } noteleport { savetoken(yytext); yylval.i=NOTELEPORT; return FLAG_TYPE; } hardfloor { savetoken(yytext); yylval.i=HARDFLOOR; return FLAG_TYPE; } nommap { savetoken(yytext); yylval.i=NOMMAP; return FLAG_TYPE; } arboreal { savetoken(yytext); yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */ shortsighted { savetoken(yytext); yylval.i=SHORTSIGHTED; return FLAG_TYPE; } mazelevel { savetoken(yytext); yylval.i=MAZELEVEL; return FLAG_TYPE; } premapped { savetoken(yytext); yylval.i=PREMAPPED; return FLAG_TYPE; } shroud { savetoken(yytext); yylval.i=SHROUD; return FLAG_TYPE; } graveyard { savetoken(yytext); yylval.i=GRAVEYARD; return FLAG_TYPE; } icedpools { savetoken(yytext); yylval.i=ICEDPOOLS; return FLAG_TYPE; } solidify { savetoken(yytext); yylval.i=SOLIDIFY; return FLAG_TYPE; } corrmaze { savetoken(yytext); yylval.i=CORRMAZE; return FLAG_TYPE; } inaccessibles { savetoken(yytext); yylval.i=CHECK_INACCESSIBLES; return FLAG_TYPE; } [0-9]+d[0-9]+ { char *p = index(yytext, 'd'); savetoken(yytext); if (p) { *p++ = '\0'; yylval.dice.num = atoi(yytext); yylval.dice.die = atoi(p); } else { yylval.dice.num = yylval.dice.die = 1; } return DICE; } \[\ *[0-9]+\%\ *\] { savetoken(yytext); yylval.i = atoi(yytext + 1); if (yylval.i < 0 || yylval.i > 100) lc_error("Unexpected percentile '%li%%'", yylval.i); return PERCENT; } -[0-9]+ { savetoken(yytext); yylval.i=atoi(yytext); return MINUS_INTEGER; } \+[0-9]+ { savetoken(yytext); yylval.i=atoi(yytext); return PLUS_INTEGER; } [0-9]+\% { savetoken(yytext); yylval.i = atoi(yytext); if (yylval.i < 0 || yylval.i > 100) lc_error("Unexpected percentile '%li%%'", yylval.i); return SPERCENT; } [0-9]+ { savetoken(yytext); yylval.i=atoi(yytext); return INTEGER; } \"[^"]*\" { savetoken(yytext); yytext[yyleng - 1] = '\0'; /* discard the trailing \" */ yylval.map = dupstr(yytext + 1); /* skip the first \" */ return STRING; } \$[a-zA-Z_]+ { savetoken(yytext); return handle_varstring_check(); } "==" { savetoken(yytext); yylval.i = SPO_JE; return COMPARE_TYPE; } "!=" { savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; } "<>" { savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; } "<=" { savetoken(yytext); yylval.i = SPO_JLE; return COMPARE_TYPE; } ">=" { savetoken(yytext); yylval.i = SPO_JGE; return COMPARE_TYPE; } "<" { savetoken(yytext); yylval.i = SPO_JL; return COMPARE_TYPE; } ">" { savetoken(yytext); yylval.i = SPO_JG; return COMPARE_TYPE; } \r?\n { newline(); } [ \t]+ { advancepos(yytext); } '\\.' { savetoken(yytext); yylval.i = yytext[2]; return CHAR; } '.' { savetoken(yytext); yylval.i = yytext[1]; return CHAR; } [-_a-zA-Z0-9]+ ST_RET(UNKNOWN_TYPE); . { savetoken(yytext); return yytext[0]; } %% #ifdef AMIGA long * alloc(n) unsigned n; { return (long *) malloc(n); } #endif /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; if (!orig_yyin) orig_yyin = yyin; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } long handle_varstring_check() { struct lc_vardefs *vd; yylval.map = dupstr(yytext); if ((vd = vardef_defined(variable_definitions, yytext, 1)) != 0) { long l = vd->var_type; int a = ((l & SPOVAR_ARRAY) == SPOVAR_ARRAY); l &= ~SPOVAR_ARRAY; if (l == SPOVAR_INT) return (a ? VARSTRING_INT_ARRAY : VARSTRING_INT); if (l == SPOVAR_STRING) return (a ? VARSTRING_STRING_ARRAY : VARSTRING_STRING); if (l == SPOVAR_VARIABLE) return (a ? VARSTRING_VAR_ARRAY : VARSTRING_VAR); if (l == SPOVAR_COORD) return (a ? VARSTRING_COORD_ARRAY : VARSTRING_COORD); if (l == SPOVAR_REGION) return (a ? VARSTRING_REGION_ARRAY : VARSTRING_REGION); if (l == SPOVAR_MAPCHAR) return (a ? VARSTRING_MAPCHAR_ARRAY : VARSTRING_MAPCHAR); if (l == SPOVAR_MONST) return (a ? VARSTRING_MONST_ARRAY : VARSTRING_MONST); if (l == SPOVAR_OBJ) return (a ? VARSTRING_OBJ_ARRAY : VARSTRING_OBJ); if (l == SPOVAR_SEL) return (a ? VARSTRING_SEL_ARRAY : VARSTRING_SEL); } return VARSTRING; } void newline() { nh_line_number++; token_start_pos = 0; (void) memset((genericptr_t) curr_token, 0, 512); } void savetoken(s) char *s; { Sprintf(curr_token, "%s", s); advancepos(s); } void advancepos(s) char *s; { token_start_pos += strlen(s); } /*lev_comp.l*/ nethack-3.6.0/util/lev_comp.y0000664000076400007660000020164412624044164015122 0ustar paxedpaxed%{ /* NetHack 3.6 lev_comp.y $NHDT-Date: 1448074095 2015/11/21 02:48:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Level Compiler code * It may handle special mazes & special room-levels */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) */ #include "hack.h" #include "sp_lev.h" #define ERR (-1) /* many types of things are put in chars for transference to NetHack. * since some systems will use signed chars, limit everybody to the * same number for portability. */ #define MAX_OF_TYPE 128 #define MAX_NESTED_IFS 20 #define MAX_SWITCH_CASES 20 #define New(type) \ (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type)) #define NewTab(type, size) (type **) alloc(sizeof(type *) * size) #define Free(ptr) free((genericptr_t)ptr) extern void VDECL(lc_error, (const char *, ...)); extern void VDECL(lc_warning, (const char *, ...)); extern void FDECL(yyerror, (const char *)); extern void FDECL(yywarning, (const char *)); extern int NDECL(yylex); int NDECL(yyparse); extern int FDECL(get_floor_type, (CHAR_P)); extern int FDECL(get_room_type, (char *)); extern int FDECL(get_trap_type, (char *)); extern int FDECL(get_monster_id, (char *,CHAR_P)); extern int FDECL(get_object_id, (char *,CHAR_P)); extern boolean FDECL(check_monster_char, (CHAR_P)); extern boolean FDECL(check_object_char, (CHAR_P)); extern char FDECL(what_map_char, (CHAR_P)); extern void FDECL(scan_map, (char *, sp_lev *)); extern void FDECL(add_opcode, (sp_lev *, int, genericptr_t)); extern genericptr_t FDECL(get_last_opcode_data1, (sp_lev *, int)); extern genericptr_t FDECL(get_last_opcode_data2, (sp_lev *, int,int)); extern boolean FDECL(check_subrooms, (sp_lev *)); extern boolean FDECL(write_level_file, (char *,sp_lev *)); extern struct opvar *FDECL(set_opvar_int, (struct opvar *, long)); extern void VDECL(add_opvars, (sp_lev *, const char *, ...)); extern void FDECL(start_level_def, (sp_lev * *, char *)); extern struct lc_funcdefs *FDECL(funcdef_new,(long,char *)); extern void FDECL(funcdef_free_all,(struct lc_funcdefs *)); extern struct lc_funcdefs *FDECL(funcdef_defined,(struct lc_funcdefs *,char *, int)); extern char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *)); extern char *FDECL(decode_parm_str, (char *)); extern struct lc_vardefs *FDECL(vardef_new,(long,char *)); extern void FDECL(vardef_free_all,(struct lc_vardefs *)); extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int)); extern void NDECL(break_stmt_start); extern void FDECL(break_stmt_end, (sp_lev *)); extern void FDECL(break_stmt_new, (sp_lev *, long)); extern void FDECL(splev_add_from, (sp_lev *, sp_lev *)); extern void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long)); extern void FDECL(vardef_used, (struct lc_vardefs *, char *)); extern struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *, char *, long)); extern int FDECL(reverse_jmp_opcode, (int)); struct coord { long x; long y; }; struct forloopdef { char *varname; long jmp_point; }; static struct forloopdef forloop_list[MAX_NESTED_IFS]; static short n_forloops = 0; sp_lev *splev = NULL; static struct opvar *if_list[MAX_NESTED_IFS]; static short n_if_list = 0; unsigned int max_x_map, max_y_map; int obj_containment = 0; int in_container_obj = 0; /* integer value is possibly an inconstant value (eg. dice notation or a variable) */ int is_inconstant_number = 0; int in_switch_statement = 0; static struct opvar *switch_check_jump = NULL; static struct opvar *switch_default_case = NULL; static struct opvar *switch_case_list[MAX_SWITCH_CASES]; static long switch_case_value[MAX_SWITCH_CASES]; int n_switch_case_list = 0; int allow_break_statements = 0; struct lc_breakdef *break_list = NULL; extern struct lc_vardefs *variable_definitions; struct lc_vardefs *function_tmp_var_defs = NULL; extern struct lc_funcdefs *function_definitions; struct lc_funcdefs *curr_function = NULL; struct lc_funcdefs_parm * curr_function_param = NULL; int in_function_definition = 0; sp_lev *function_splev_backup = NULL; extern int fatal_error; extern int got_errors; extern int line_number; extern const char *fname; extern char curr_token[512]; %} %union { long i; char* map; struct { long room; long wall; long door; } corpos; struct { long area; long x1; long y1; long x2; long y2; } lregn; struct { long x; long y; } crd; struct { long ter; long lit; } terr; struct { long height; long width; } sze; struct { long die; long num; } dice; struct { long cfunc; char *varstr; } meth; } %token CHAR INTEGER BOOLEAN PERCENT SPERCENT %token MINUS_INTEGER PLUS_INTEGER %token MAZE_GRID_ID SOLID_FILL_ID MINES_ID ROGUELEV_ID %token MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID %token OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID %token object_ID monster_ID terrain_ID %token MAZEWALK_ID WALLIFY_ID REGION_ID FILLING IRREGULAR JOINED %token ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID %token PORTAL_ID TELEPRT_ID BRANCH_ID LEV MINERALIZE_ID %token CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE %token RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE %token DIRECTION RANDOM_TYPE RANDOM_TYPE_BRACKET A_REGISTER %token ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN %token SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS %token MON_APPEARANCE ROOMDOOR_ID IF_ID ELSE_ID %token TERRAIN_ID HORIZ_OR_VERT REPLACE_TERRAIN_ID %token EXIT_ID SHUFFLE_ID %token QUANTITY_ID BURIED_ID LOOP_ID %token FOR_ID TO_ID %token SWITCH_ID CASE_ID BREAK_ID DEFAULT_ID %token ERODED_ID TRAPPED_STATE RECHARGED_ID INVIS_ID GREASED_ID %token FEMALE_ID CANCELLED_ID REVIVED_ID AVENGE_ID FLEEING_ID BLINDED_ID %token PARALYZED_ID STUNNED_ID CONFUSED_ID SEENTRAPS_ID ALL_ID %token MONTYPE_ID %token GRAVE_ID ERODEPROOF_ID %token FUNCTION_ID %token MSG_OUTPUT_TYPE %token COMPARE_TYPE %token UNKNOWN_TYPE %token rect_ID fillrect_ID line_ID randline_ID grow_ID selection_ID flood_ID %token rndcoord_ID circle_ID ellipse_ID filter_ID complement_ID %token gradient_ID GRADIENT_TYPE LIMITED HUMIDITY_TYPE %token ',' ':' '(' ')' '[' ']' '{' '}' %token STRING MAP_ID %token NQSTRING VARSTRING %token CFUNC CFUNC_INT CFUNC_STR CFUNC_COORD CFUNC_REGION %token VARSTRING_INT VARSTRING_INT_ARRAY %token VARSTRING_STRING VARSTRING_STRING_ARRAY %token VARSTRING_VAR VARSTRING_VAR_ARRAY %token VARSTRING_COORD VARSTRING_COORD_ARRAY %token VARSTRING_REGION VARSTRING_REGION_ARRAY %token VARSTRING_MAPCHAR VARSTRING_MAPCHAR_ARRAY %token VARSTRING_MONST VARSTRING_MONST_ARRAY %token VARSTRING_OBJ VARSTRING_OBJ_ARRAY %token VARSTRING_SEL VARSTRING_SEL_ARRAY %token METHOD_INT METHOD_INT_ARRAY %token METHOD_STRING METHOD_STRING_ARRAY %token METHOD_VAR METHOD_VAR_ARRAY %token METHOD_COORD METHOD_COORD_ARRAY %token METHOD_REGION METHOD_REGION_ARRAY %token METHOD_MAPCHAR METHOD_MAPCHAR_ARRAY %token METHOD_MONST METHOD_MONST_ARRAY %token METHOD_OBJ METHOD_OBJ_ARRAY %token METHOD_SEL METHOD_SEL_ARRAY %token DICE %type h_justif v_justif trap_name room_type door_state light_state %type alignment altar_type a_register roomfill door_pos %type alignment_prfx %type door_wall walled secret %type dir_list teleprt_detail %type object_infos object_info monster_infos monster_info %type levstatements stmt_block region_detail_end %type engraving_type flag_list roomregionflag roomregionflags optroomregionflags %type humidity_flags %type comparestmt encodecoord encoderegion mapchar %type seen_trap_mask %type encodemonster encodeobj encodeobj_list %type integer_list string_list encodecoord_list encoderegion_list mapchar_list encodemonster_list %type opt_percent opt_fillchar %type all_integers %type ter_selection ter_selection_x %type func_param_type %type objectid monsterid terrainid %type opt_coord_or_var opt_limited %type mazefiller %type level_def %type any_var any_var_array any_var_or_arr any_var_or_unk %type func_call_params_list func_call_param_list %type func_call_param_part %type corr_spec %type region lev_region %type room_pos subroom_pos room_align %type room_size %type terrain_type %left '+' '-' %left '*' '/' '%' %start file %% file : /* nothing */ | levels ; levels : level | level levels ; level : level_def flags levstatements { if (fatal_error > 0) { (void) fprintf(stderr, "%s: %d errors detected for level \"%s\". No output created!\n", fname, fatal_error, $1); fatal_error = 0; got_errors++; } else if (!got_errors) { if (!write_level_file($1, splev)) { lc_error("Can't write output file for '%s'!", $1); exit(EXIT_FAILURE); } } Free($1); Free(splev); splev = NULL; vardef_free_all(variable_definitions); variable_definitions = NULL; } ; level_def : LEVEL_ID ':' STRING { start_level_def(&splev, $3); $$ = $3; } | MAZE_ID ':' STRING ',' mazefiller { start_level_def(&splev, $3); if ($5 == -1) { add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_MAZEGRID,HWALL,0,0, 0,0,0,0, SPO_INITLEVEL)); } else { long bg = what_map_char((char) $5); add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_SOLIDFILL, bg, 0,0, 0,0,0,0, SPO_INITLEVEL)); } add_opvars(splev, "io", VA_PASS2(MAZELEVEL, SPO_LEVEL_FLAGS)); max_x_map = COLNO-1; max_y_map = ROWNO; $$ = $3; } ; mazefiller : RANDOM_TYPE { $$ = -1; } | CHAR { $$ = what_map_char((char) $1); } ; lev_init : LEV_INIT_ID ':' SOLID_FILL_ID ',' terrain_type { long filling = $5.ter; if (filling == INVALID_TYPE || filling >= MAX_TYPE) lc_error("INIT_MAP: Invalid fill char type."); add_opvars(splev, "iiiiiiiio", LVLINIT_SOLIDFILL,filling,0,(long)$5.lit, 0,0,0,0, SPO_INITLEVEL); max_x_map = COLNO-1; max_y_map = ROWNO; } | LEV_INIT_ID ':' MAZE_GRID_ID ',' CHAR { long filling = what_map_char((char) $5); if (filling == INVALID_TYPE || filling >= MAX_TYPE) lc_error("INIT_MAP: Invalid fill char type."); add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_MAZEGRID,filling,0,0, 0,0,0,0, SPO_INITLEVEL)); max_x_map = COLNO-1; max_y_map = ROWNO; } | LEV_INIT_ID ':' ROGUELEV_ID { add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_ROGUE,0,0,0, 0,0,0,0, SPO_INITLEVEL)); } | LEV_INIT_ID ':' MINES_ID ',' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled opt_fillchar { long fg = what_map_char((char) $5); long bg = what_map_char((char) $7); long smoothed = $9; long joined = $11; long lit = $13; long walled = $15; long filling = $16; if (fg == INVALID_TYPE || fg >= MAX_TYPE) lc_error("INIT_MAP: Invalid foreground type."); if (bg == INVALID_TYPE || bg >= MAX_TYPE) lc_error("INIT_MAP: Invalid background type."); if (joined && fg != CORR && fg != ROOM) lc_error("INIT_MAP: Invalid foreground type for joined map."); if (filling == INVALID_TYPE) lc_error("INIT_MAP: Invalid fill char type."); add_opvars(splev, "iiiiiiiio", VA_PASS9(LVLINIT_MINES,filling,walled,lit, joined,smoothed,bg,fg, SPO_INITLEVEL)); max_x_map = COLNO-1; max_y_map = ROWNO; } ; opt_limited : /* nothing */ { $$ = 0; } | ',' LIMITED { $$ = $2; } ; opt_coord_or_var : /* nothing */ { add_opvars(splev, "o", VA_PASS1(SPO_COPY)); $$ = 0; } | ',' coord_or_var { $$ = 1; } ; opt_fillchar : /* nothing */ { $$ = -1; } | ',' CHAR { $$ = what_map_char((char) $2); } ; walled : BOOLEAN | RANDOM_TYPE ; flags : /* nothing */ { add_opvars(splev, "io", VA_PASS2(0, SPO_LEVEL_FLAGS)); } | FLAGS_ID ':' flag_list { add_opvars(splev, "io", VA_PASS2($3, SPO_LEVEL_FLAGS)); } ; flag_list : FLAG_TYPE ',' flag_list { $$ = ($1 | $3); } | FLAG_TYPE { $$ = $1; } ; levstatements : /* nothing */ { $$ = 0; } | levstatement levstatements { $$ = 1 + $2; } ; stmt_block : '{' levstatements '}' { $$ = $2; } ; levstatement : message | lev_init | altar_detail | grave_detail | branch_region | corridor | variable_define | shuffle_detail | diggable_detail | door_detail | drawbridge_detail | engraving_detail | mineralize | fountain_detail | gold_detail | switchstatement | forstatement | loopstatement | ifstatement | chancestatement | exitstatement | breakstatement | function_define | function_call | ladder_detail | map_definition | mazewalk_detail | monster_detail | object_detail | passwall_detail | pool_detail | portal_region | random_corridors | region_detail | room_def | subroom_def | sink_detail | terrain_detail | replace_terrain_detail | stair_detail | stair_region | teleprt_region | trap_detail | wallify_detail ; any_var_array : VARSTRING_INT_ARRAY | VARSTRING_STRING_ARRAY | VARSTRING_VAR_ARRAY | VARSTRING_COORD_ARRAY | VARSTRING_REGION_ARRAY | VARSTRING_MAPCHAR_ARRAY | VARSTRING_MONST_ARRAY | VARSTRING_OBJ_ARRAY | VARSTRING_SEL_ARRAY ; any_var : VARSTRING_INT | VARSTRING_STRING | VARSTRING_VAR | VARSTRING_COORD | VARSTRING_REGION | VARSTRING_MAPCHAR | VARSTRING_MONST | VARSTRING_OBJ | VARSTRING_SEL ; any_var_or_arr : any_var_array | any_var | VARSTRING ; any_var_or_unk : VARSTRING | any_var ; shuffle_detail : SHUFFLE_ID ':' any_var_array { struct lc_vardefs *vd; if ((vd = vardef_defined(variable_definitions, $3, 1))) { if (!(vd->var_type & SPOVAR_ARRAY)) lc_error("Trying to shuffle non-array variable '%s'", $3); } else lc_error("Trying to shuffle undefined variable '%s'", $3); add_opvars(splev, "so", VA_PASS2($3, SPO_SHUFFLE_ARRAY)); Free($3); } ; variable_define : any_var_or_arr '=' math_expr_var { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_INT); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' selection_ID ':' ter_selection { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_SEL); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' string_expr { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_STRING); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' terrainid ':' mapchar_or_var { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' monsterid ':' monster_or_var { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MONST); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' objectid ':' object_or_var { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_OBJ); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' coord_or_var { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_COORD); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' region_or_var { variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_REGION); add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' '{' integer_list '}' { long n_items = $4; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_INT|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' '{' encodecoord_list '}' { long n_items = $4; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_COORD|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' '{' encoderegion_list '}' { long n_items = $4; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_REGION|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' terrainid ':' '{' mapchar_list '}' { long n_items = $6; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' monsterid ':' '{' encodemonster_list '}' { long n_items = $6; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MONST|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' objectid ':' '{' encodeobj_list '}' { long n_items = $6; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_OBJ|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } | any_var_or_arr '=' '{' string_list '}' { long n_items = $4; variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_STRING|SPOVAR_ARRAY); add_opvars(splev, "iso", VA_PASS3(n_items, $1, SPO_VAR_INIT)); Free($1); } ; encodeobj_list : encodeobj { add_opvars(splev, "O", VA_PASS1($1)); $$ = 1; } | encodeobj_list ',' encodeobj { add_opvars(splev, "O", VA_PASS1($3)); $$ = 1 + $1; } ; encodemonster_list : encodemonster { add_opvars(splev, "M", VA_PASS1($1)); $$ = 1; } | encodemonster_list ',' encodemonster { add_opvars(splev, "M", VA_PASS1($3)); $$ = 1 + $1; } ; mapchar_list : mapchar { add_opvars(splev, "m", VA_PASS1($1)); $$ = 1; } | mapchar_list ',' mapchar { add_opvars(splev, "m", VA_PASS1($3)); $$ = 1 + $1; } ; encoderegion_list : encoderegion { $$ = 1; } | encoderegion_list ',' encoderegion { $$ = 1 + $1; } ; encodecoord_list : encodecoord { add_opvars(splev, "c", VA_PASS1($1)); $$ = 1; } | encodecoord_list ',' encodecoord { add_opvars(splev, "c", VA_PASS1($3)); $$ = 1 + $1; } ; integer_list : math_expr_var { $$ = 1; } | integer_list ',' math_expr_var { $$ = 1 + $1; } ; string_list : string_expr { $$ = 1; } | string_list ',' string_expr { $$ = 1 + $1; } ; function_define : FUNCTION_ID NQSTRING '(' { struct lc_funcdefs *funcdef; if (in_function_definition) lc_error("Recursively defined functions not allowed (function %s).", $2); in_function_definition++; if (funcdef_defined(function_definitions, $2, 1)) lc_error("Function '%s' already defined once.", $2); funcdef = funcdef_new(-1, $2); funcdef->next = function_definitions; function_definitions = funcdef; function_splev_backup = splev; splev = &(funcdef->code); Free($2); curr_function = funcdef; function_tmp_var_defs = variable_definitions; variable_definitions = NULL; } func_params_list ')' { /* nothing */ } stmt_block { add_opvars(splev, "io", VA_PASS2(0, SPO_RETURN)); splev = function_splev_backup; in_function_definition--; curr_function = NULL; vardef_free_all(variable_definitions); variable_definitions = function_tmp_var_defs; } ; function_call : NQSTRING '(' func_call_params_list ')' { struct lc_funcdefs *tmpfunc; tmpfunc = funcdef_defined(function_definitions, $1, 1); if (tmpfunc) { long l; long nparams = strlen( $3 ); char *fparamstr = funcdef_paramtypes(tmpfunc); if (strcmp($3, fparamstr)) { char *tmps = strdup(decode_parm_str(fparamstr)); lc_error("Function '%s' requires params '%s', got '%s' instead.", $1, tmps, decode_parm_str($3)); Free(tmps); } Free(fparamstr); Free($3); if (!(tmpfunc->n_called)) { /* we haven't called the function yet, so insert it in the code */ struct opvar *jmp = New(struct opvar); set_opvar_int(jmp, splev->n_opcodes+1); add_opcode(splev, SPO_PUSH, jmp); add_opcode(splev, SPO_JMP, NULL); /* we must jump past it first, then CALL it, due to RETURN. */ tmpfunc->addr = splev->n_opcodes; { /* init function parameter variables */ struct lc_funcdefs_parm *tfp = tmpfunc->params; while (tfp) { add_opvars(splev, "iso", VA_PASS3(0, tfp->name, SPO_VAR_INIT)); tfp = tfp->next; } } splev_add_from(splev, &(tmpfunc->code)); set_opvar_int(jmp, splev->n_opcodes - jmp->vardata.l); } l = tmpfunc->addr - splev->n_opcodes - 2; add_opvars(splev, "iio", VA_PASS3(nparams, l, SPO_CALL)); tmpfunc->n_called++; } else { lc_error("Function '%s' not defined.", $1); } Free($1); } ; exitstatement : EXIT_ID { add_opcode(splev, SPO_EXIT, NULL); } ; opt_percent : /* nothing */ { $$ = 100; } | PERCENT { $$ = $1; } ; comparestmt : PERCENT { /* val > rn2(100) */ add_opvars(splev, "iio", VA_PASS3((long)$1, 100, SPO_RN2)); $$ = SPO_JG; } | '[' math_expr_var COMPARE_TYPE math_expr_var ']' { $$ = $3; } | '[' math_expr_var ']' { /* boolean, explicit foo != 0 */ add_opvars(splev, "i", VA_PASS1(0)); $$ = SPO_JNE; } ; switchstatement : SWITCH_ID { is_inconstant_number = 0; } '[' integer_or_var ']' { struct opvar *chkjmp; if (in_switch_statement > 0) lc_error("Cannot nest switch-statements."); in_switch_statement++; n_switch_case_list = 0; switch_default_case = NULL; if (!is_inconstant_number) add_opvars(splev, "o", VA_PASS1(SPO_RN2)); is_inconstant_number = 0; chkjmp = New(struct opvar); set_opvar_int(chkjmp, splev->n_opcodes+1); switch_check_jump = chkjmp; add_opcode(splev, SPO_PUSH, chkjmp); add_opcode(splev, SPO_JMP, NULL); break_stmt_start(); } '{' switchcases '}' { struct opvar *endjump = New(struct opvar); int i; set_opvar_int(endjump, splev->n_opcodes+1); add_opcode(splev, SPO_PUSH, endjump); add_opcode(splev, SPO_JMP, NULL); set_opvar_int(switch_check_jump, splev->n_opcodes - switch_check_jump->vardata.l); for (i = 0; i < n_switch_case_list; i++) { add_opvars(splev, "oio", VA_PASS3(SPO_COPY, switch_case_value[i], SPO_CMP)); set_opvar_int(switch_case_list[i], switch_case_list[i]->vardata.l - splev->n_opcodes-1); add_opcode(splev, SPO_PUSH, switch_case_list[i]); add_opcode(splev, SPO_JE, NULL); } if (switch_default_case) { set_opvar_int(switch_default_case, switch_default_case->vardata.l - splev->n_opcodes-1); add_opcode(splev, SPO_PUSH, switch_default_case); add_opcode(splev, SPO_JMP, NULL); } set_opvar_int(endjump, splev->n_opcodes - endjump->vardata.l); break_stmt_end(splev); add_opcode(splev, SPO_POP, NULL); /* get rid of the value in stack */ in_switch_statement--; } ; switchcases : /* nothing */ | switchcase switchcases ; switchcase : CASE_ID all_integers ':' { if (n_switch_case_list < MAX_SWITCH_CASES) { struct opvar *tmppush = New(struct opvar); set_opvar_int(tmppush, splev->n_opcodes); switch_case_value[n_switch_case_list] = $2; switch_case_list[n_switch_case_list++] = tmppush; } else lc_error("Too many cases in a switch."); } levstatements { } | DEFAULT_ID ':' { struct opvar *tmppush = New(struct opvar); if (switch_default_case) lc_error("Switch default case already used."); set_opvar_int(tmppush, splev->n_opcodes); switch_default_case = tmppush; } levstatements { } ; breakstatement : BREAK_ID { if (!allow_break_statements) lc_error("Cannot use BREAK outside a statement block."); else { break_stmt_new(splev, splev->n_opcodes); } } ; for_to_span : '.' '.' | TO_ID ; forstmt_start : FOR_ID any_var_or_unk '=' math_expr_var for_to_span math_expr_var { char buf[256], buf2[256]; if (n_forloops >= MAX_NESTED_IFS) { lc_error("FOR: Too deeply nested loops."); n_forloops = MAX_NESTED_IFS - 1; } /* first, define a variable for the for-loop end value */ snprintf(buf, 255, "%s end", $2); /* the value of which is already in stack (the 2nd math_expr) */ add_opvars(splev, "iso", VA_PASS3(0, buf, SPO_VAR_INIT)); variable_definitions = add_vardef_type(variable_definitions, $2, SPOVAR_INT); /* define the for-loop variable. value is in stack (1st math_expr) */ add_opvars(splev, "iso", VA_PASS3(0, $2, SPO_VAR_INIT)); /* calculate value for the loop "step" variable */ snprintf(buf2, 255, "%s step", $2); /* end - start */ add_opvars(splev, "vvo", VA_PASS3(buf, $2, SPO_MATH_SUB)); /* sign of that */ add_opvars(splev, "o", VA_PASS1(SPO_MATH_SIGN)); /* save the sign into the step var */ add_opvars(splev, "iso", VA_PASS3(0, buf2, SPO_VAR_INIT)); forloop_list[n_forloops].varname = strdup($2); forloop_list[n_forloops].jmp_point = splev->n_opcodes; n_forloops++; Free($2); } ; forstatement : forstmt_start { /* nothing */ break_stmt_start(); } stmt_block { char buf[256], buf2[256]; n_forloops--; snprintf(buf, 255, "%s step", forloop_list[n_forloops].varname); snprintf(buf2, 255, "%s end", forloop_list[n_forloops].varname); /* compare for-loop var to end value */ add_opvars(splev, "vvo", VA_PASS3(forloop_list[n_forloops].varname, buf2, SPO_CMP)); /* var + step */ add_opvars(splev, "vvo", VA_PASS3(buf, forloop_list[n_forloops].varname, SPO_MATH_ADD)); /* for-loop var = (for-loop var + step) */ add_opvars(splev, "iso", VA_PASS3(0, forloop_list[n_forloops].varname, SPO_VAR_INIT)); /* jump back if compared values were not equal */ add_opvars(splev, "io", VA_PASS2( forloop_list[n_forloops].jmp_point - splev->n_opcodes - 1, SPO_JNE)); Free(forloop_list[n_forloops].varname); break_stmt_end(splev); } ; loopstatement : LOOP_ID '[' integer_or_var ']' { struct opvar *tmppush = New(struct opvar); if (n_if_list >= MAX_NESTED_IFS) { lc_error("LOOP: Too deeply nested conditionals."); n_if_list = MAX_NESTED_IFS - 1; } set_opvar_int(tmppush, splev->n_opcodes); if_list[n_if_list++] = tmppush; add_opvars(splev, "o", VA_PASS1(SPO_DEC)); break_stmt_start(); } stmt_block { struct opvar *tmppush; add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 0, SPO_CMP)); tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, tmppush->vardata.l - splev->n_opcodes-1); add_opcode(splev, SPO_PUSH, tmppush); add_opcode(splev, SPO_JG, NULL); add_opcode(splev, SPO_POP, NULL); /* get rid of the count value in stack */ break_stmt_end(splev); } ; chancestatement : comparestmt ':' { struct opvar *tmppush2 = New(struct opvar); if (n_if_list >= MAX_NESTED_IFS) { lc_error("IF: Too deeply nested conditionals."); n_if_list = MAX_NESTED_IFS - 1; } add_opcode(splev, SPO_CMP, NULL); set_opvar_int(tmppush2, splev->n_opcodes+1); if_list[n_if_list++] = tmppush2; add_opcode(splev, SPO_PUSH, tmppush2); add_opcode(splev, reverse_jmp_opcode( $1 ), NULL); } levstatement { if (n_if_list > 0) { struct opvar *tmppush; tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); } else lc_error("IF: Huh?! No start address?"); } ; ifstatement : IF_ID comparestmt { struct opvar *tmppush2 = New(struct opvar); if (n_if_list >= MAX_NESTED_IFS) { lc_error("IF: Too deeply nested conditionals."); n_if_list = MAX_NESTED_IFS - 1; } add_opcode(splev, SPO_CMP, NULL); set_opvar_int(tmppush2, splev->n_opcodes+1); if_list[n_if_list++] = tmppush2; add_opcode(splev, SPO_PUSH, tmppush2); add_opcode(splev, reverse_jmp_opcode( $2 ), NULL); } if_ending { /* do nothing */ } ; if_ending : stmt_block { if (n_if_list > 0) { struct opvar *tmppush; tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); } else lc_error("IF: Huh?! No start address?"); } | stmt_block { if (n_if_list > 0) { struct opvar *tmppush = New(struct opvar); struct opvar *tmppush2; set_opvar_int(tmppush, splev->n_opcodes+1); add_opcode(splev, SPO_PUSH, tmppush); add_opcode(splev, SPO_JMP, NULL); tmppush2 = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush2, splev->n_opcodes - tmppush2->vardata.l); if_list[n_if_list++] = tmppush; } else lc_error("IF: Huh?! No else-part address?"); } ELSE_ID stmt_block { if (n_if_list > 0) { struct opvar *tmppush; tmppush = (struct opvar *) if_list[--n_if_list]; set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); } else lc_error("IF: Huh?! No end address?"); } ; message : MESSAGE_ID ':' string_expr { add_opvars(splev, "o", VA_PASS1(SPO_MESSAGE)); } ; random_corridors: RAND_CORRIDOR_ID { add_opvars(splev, "iiiiiio", VA_PASS7(-1, 0, -1, -1, -1, -1, SPO_CORRIDOR)); } | RAND_CORRIDOR_ID ':' all_integers { add_opvars(splev, "iiiiiio", VA_PASS7(-1, $3, -1, -1, -1, -1, SPO_CORRIDOR)); } | RAND_CORRIDOR_ID ':' RANDOM_TYPE { add_opvars(splev, "iiiiiio", VA_PASS7(-1, -1, -1, -1, -1, -1, SPO_CORRIDOR)); } ; corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec { add_opvars(splev, "iiiiiio", VA_PASS7($3.room, $3.door, $3.wall, $5.room, $5.door, $5.wall, SPO_CORRIDOR)); } | CORRIDOR_ID ':' corr_spec ',' all_integers { add_opvars(splev, "iiiiiio", VA_PASS7($3.room, $3.door, $3.wall, -1, -1, (long)$5, SPO_CORRIDOR)); } ; corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' { $$.room = $2; $$.wall = $4; $$.door = $6; } ; room_begin : room_type opt_percent ',' light_state { if (($2 < 100) && ($1 == OROOM)) lc_error("Only typed rooms can have a chance."); else { add_opvars(splev, "iii", VA_PASS3((long)$1, (long)$2, (long)$4)); } } ; subroom_def : SUBROOM_ID ':' room_begin ',' subroom_pos ',' room_size optroomregionflags { long rflags = $8; if (rflags == -1) rflags = (1 << 0); add_opvars(splev, "iiiiiiio", VA_PASS8(rflags, ERR, ERR, $5.x, $5.y, $7.width, $7.height, SPO_SUBROOM)); break_stmt_start(); } stmt_block { break_stmt_end(splev); add_opcode(splev, SPO_ENDROOM, NULL); } ; room_def : ROOM_ID ':' room_begin ',' room_pos ',' room_align ',' room_size optroomregionflags { long rflags = $8; if (rflags == -1) rflags = (1 << 0); add_opvars(splev, "iiiiiiio", VA_PASS8(rflags, $7.x, $7.y, $5.x, $5.y, $9.width, $9.height, SPO_ROOM)); break_stmt_start(); } stmt_block { break_stmt_end(splev); add_opcode(splev, SPO_ENDROOM, NULL); } ; roomfill : /* nothing */ { $$ = 1; } | ',' BOOLEAN { $$ = $2; } ; room_pos : '(' INTEGER ',' INTEGER ')' { if ( $2 < 1 || $2 > 5 || $4 < 1 || $4 > 5 ) { lc_error("Room positions should be between 1-5: (%li,%li)!", $2, $4); } else { $$.x = $2; $$.y = $4; } } | RANDOM_TYPE { $$.x = $$.y = ERR; } ; subroom_pos : '(' INTEGER ',' INTEGER ')' { if ( $2 < 0 || $4 < 0) { lc_error("Invalid subroom position (%li,%li)!", $2, $4); } else { $$.x = $2; $$.y = $4; } } | RANDOM_TYPE { $$.x = $$.y = ERR; } ; room_align : '(' h_justif ',' v_justif ')' { $$.x = $2; $$.y = $4; } | RANDOM_TYPE { $$.x = $$.y = ERR; } ; room_size : '(' INTEGER ',' INTEGER ')' { $$.width = $2; $$.height = $4; } | RANDOM_TYPE { $$.height = $$.width = ERR; } ; door_detail : ROOMDOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos { /* ERR means random here */ if ($7 == ERR && $9 != ERR) { lc_error("If the door wall is random, so must be its pos!"); } else { add_opvars(splev, "iiiio", VA_PASS5((long)$9, (long)$5, (long)$3, (long)$7, SPO_ROOM_DOOR)); } } | DOOR_ID ':' door_state ',' ter_selection { add_opvars(splev, "io", VA_PASS2((long)$3, SPO_DOOR)); } ; secret : BOOLEAN | RANDOM_TYPE ; door_wall : dir_list | RANDOM_TYPE ; dir_list : DIRECTION { $$ = $1; } | DIRECTION '|' dir_list { $$ = ($1 | $3); } ; door_pos : INTEGER | RANDOM_TYPE ; map_definition : NOMAP_ID { add_opvars(splev, "ciisiio", VA_PASS7(0, 0, 1, (char *)0, 0, 0, SPO_MAP)); max_x_map = COLNO-1; max_y_map = ROWNO; } | GEOMETRY_ID ':' h_justif ',' v_justif roomfill MAP_ID { add_opvars(splev, "cii", VA_PASS3(SP_COORD_PACK(($3),($5)), 1, (long)$6)); scan_map($7, splev); Free($7); } | GEOMETRY_ID ':' coord_or_var roomfill MAP_ID { add_opvars(splev, "ii", VA_PASS2(2, (long)$4)); scan_map($5, splev); Free($5); } ; h_justif : LEFT_OR_RIGHT | CENTER ; v_justif : TOP_OR_BOT | CENTER ; monster_detail : MONSTER_ID ':' monster_desc { add_opvars(splev, "io", VA_PASS2(0, SPO_MONSTER)); } | MONSTER_ID ':' monster_desc { add_opvars(splev, "io", VA_PASS2(1, SPO_MONSTER)); in_container_obj++; break_stmt_start(); } stmt_block { break_stmt_end(splev); in_container_obj--; add_opvars(splev, "o", VA_PASS1(SPO_END_MONINVENT)); } ; monster_desc : monster_or_var ',' coord_or_var monster_infos { /* nothing */ } ; monster_infos : /* nothing */ { struct opvar *stopit = New(struct opvar); set_opvar_int(stopit, SP_M_V_END); add_opcode(splev, SPO_PUSH, stopit); $$ = 0x0000; } | monster_infos ',' monster_info { if (( $1 & $3 )) lc_error("MONSTER extra info defined twice."); $$ = ( $1 | $3 ); } ; monster_info : string_expr { add_opvars(splev, "i", VA_PASS1(SP_M_V_NAME)); $$ = 0x0001; } | MON_ATTITUDE { add_opvars(splev, "ii", VA_PASS2((long)$1, SP_M_V_PEACEFUL)); $$ = 0x0002; } | MON_ALERTNESS { add_opvars(splev, "ii", VA_PASS2((long)$1, SP_M_V_ASLEEP)); $$ = 0x0004; } | alignment_prfx { add_opvars(splev, "ii", VA_PASS2((long)$1, SP_M_V_ALIGN)); $$ = 0x0008; } | MON_APPEARANCE string_expr { add_opvars(splev, "ii", VA_PASS2((long)$1, SP_M_V_APPEAR)); $$ = 0x0010; } | FEMALE_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_FEMALE)); $$ = 0x0020; } | INVIS_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_INVIS)); $$ = 0x0040; } | CANCELLED_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CANCELLED)); $$ = 0x0080; } | REVIVED_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_REVIVED)); $$ = 0x0100; } | AVENGE_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_AVENGE)); $$ = 0x0200; } | FLEEING_ID ':' integer_or_var { add_opvars(splev, "i", VA_PASS1(SP_M_V_FLEEING)); $$ = 0x0400; } | BLINDED_ID ':' integer_or_var { add_opvars(splev, "i", VA_PASS1(SP_M_V_BLINDED)); $$ = 0x0800; } | PARALYZED_ID ':' integer_or_var { add_opvars(splev, "i", VA_PASS1(SP_M_V_PARALYZED)); $$ = 0x1000; } | STUNNED_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_STUNNED)); $$ = 0x2000; } | CONFUSED_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CONFUSED)); $$ = 0x4000; } | SEENTRAPS_ID ':' seen_trap_mask { add_opvars(splev, "ii", VA_PASS2((long)$3, SP_M_V_SEENTRAPS)); $$ = 0x8000; } ; seen_trap_mask : STRING { int token = get_trap_type($1); if (token == ERR || token == 0) lc_error("Unknown trap type '%s'!", $1); Free($1); $$ = (1L << (token - 1)); } | ALL_ID { $$ = (long) ~0; } | STRING '|' seen_trap_mask { int token = get_trap_type($1); if (token == ERR || token == 0) lc_error("Unknown trap type '%s'!", $1); if ((1L << (token - 1)) & $3) lc_error("Monster seen_traps, trap '%s' listed twice.", $1); Free($1); $$ = ((1L << (token - 1)) | $3); } ; object_detail : OBJECT_ID ':' object_desc { long cnt = 0; if (in_container_obj) cnt |= SP_OBJ_CONTENT; add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT)); } | COBJECT_ID ':' object_desc { long cnt = SP_OBJ_CONTAINER; if (in_container_obj) cnt |= SP_OBJ_CONTENT; add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT)); in_container_obj++; break_stmt_start(); } stmt_block { break_stmt_end(splev); in_container_obj--; add_opcode(splev, SPO_POP_CONTAINER, NULL); } ; object_desc : object_or_var object_infos { if (( $2 & 0x4000) && in_container_obj) lc_error("Object cannot have a coord when contained."); else if (!( $2 & 0x4000) && !in_container_obj) lc_error("Object needs a coord when not contained."); } ; object_infos : /* nothing */ { struct opvar *stopit = New(struct opvar); set_opvar_int(stopit, SP_O_V_END); add_opcode(splev, SPO_PUSH, stopit); $$ = 0x00; } | object_infos ',' object_info { if (( $1 & $3 )) lc_error("OBJECT extra info '%s' defined twice.", curr_token); $$ = ( $1 | $3 ); } ; object_info : CURSE_TYPE { add_opvars(splev, "ii", VA_PASS2((long)$1, SP_O_V_CURSE)); $$ = 0x0001; } | MONTYPE_ID ':' monster_or_var { add_opvars(splev, "i", VA_PASS1(SP_O_V_CORPSENM)); $$ = 0x0002; } | all_ints_push { add_opvars(splev, "i", VA_PASS1(SP_O_V_SPE)); $$ = 0x0004; } | NAME_ID ':' string_expr { add_opvars(splev, "i", VA_PASS1(SP_O_V_NAME)); $$ = 0x0008; } | QUANTITY_ID ':' integer_or_var { add_opvars(splev, "i", VA_PASS1(SP_O_V_QUAN)); $$ = 0x0010; } | BURIED_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BURIED)); $$ = 0x0020; } | LIGHT_STATE { add_opvars(splev, "ii", VA_PASS2((long)$1, SP_O_V_LIT)); $$ = 0x0040; } | ERODED_ID ':' integer_or_var { add_opvars(splev, "i", VA_PASS1(SP_O_V_ERODED)); $$ = 0x0080; } | ERODEPROOF_ID { add_opvars(splev, "ii", VA_PASS2(-1, SP_O_V_ERODED)); $$ = 0x0080; } | DOOR_STATE { if ($1 == D_LOCKED) { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_LOCKED)); $$ = 0x0100; } else if ($1 == D_BROKEN) { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BROKEN)); $$ = 0x0200; } else lc_error("DOOR state can only be locked or broken."); } | TRAPPED_STATE { add_opvars(splev, "ii", VA_PASS2($1, SP_O_V_TRAPPED)); $$ = 0x0400; } | RECHARGED_ID ':' integer_or_var { add_opvars(splev, "i", VA_PASS1(SP_O_V_RECHARGED)); $$ = 0x0800; } | INVIS_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_INVIS)); $$ = 0x1000; } | GREASED_ID { add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_GREASED)); $$ = 0x2000; } | coord_or_var { add_opvars(splev, "i", VA_PASS1(SP_O_V_COORD)); $$ = 0x4000; } ; trap_detail : TRAP_ID ':' trap_name ',' coord_or_var { add_opvars(splev, "io", VA_PASS2((long)$3, SPO_TRAP)); } ; drawbridge_detail: DRAWBRIDGE_ID ':' coord_or_var ',' DIRECTION ',' door_state { long dir, state = 0; /* convert dir from a DIRECTION to a DB_DIR */ dir = $5; switch (dir) { case W_NORTH: dir = DB_NORTH; break; case W_SOUTH: dir = DB_SOUTH; break; case W_EAST: dir = DB_EAST; break; case W_WEST: dir = DB_WEST; break; default: lc_error("Invalid drawbridge direction."); break; } if ( $7 == D_ISOPEN ) state = 1; else if ( $7 == D_CLOSED ) state = 0; else if ( $7 == -1 ) state = -1; else lc_error("A drawbridge can only be open, closed or random!"); add_opvars(splev, "iio", VA_PASS3(state, dir, SPO_DRAWBRIDGE)); } ; mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION { add_opvars(splev, "iiio", VA_PASS4((long)$5, 1, 0, SPO_MAZEWALK)); } | MAZEWALK_ID ':' coord_or_var ',' DIRECTION ',' BOOLEAN opt_fillchar { add_opvars(splev, "iiio", VA_PASS4((long)$5, (long)$7, (long)$8, SPO_MAZEWALK)); } ; wallify_detail : WALLIFY_ID { add_opvars(splev, "rio", VA_PASS3(SP_REGION_PACK(-1,-1,-1,-1), 0, SPO_WALLIFY)); } | WALLIFY_ID ':' ter_selection { add_opvars(splev, "io", VA_PASS2(1, SPO_WALLIFY)); } ; ladder_detail : LADDER_ID ':' coord_or_var ',' UP_OR_DOWN { add_opvars(splev, "io", VA_PASS2((long)$5, SPO_LADDER)); } ; stair_detail : STAIR_ID ':' coord_or_var ',' UP_OR_DOWN { add_opvars(splev, "io", VA_PASS2((long)$5, SPO_STAIR)); } ; stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN { add_opvars(splev, "iiiii iiiii iiso", VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, $5.x1, $5.y1, $5.x2, $5.y2, $5.area, (long)(($7) ? LR_UPSTAIR : LR_DOWNSTAIR), 0, (char *)0, SPO_LEVREGION)); } ; portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' STRING { add_opvars(splev, "iiiii iiiii iiso", VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, $5.x1, $5.y1, $5.x2, $5.y2, $5.area, LR_PORTAL, 0, $7, SPO_LEVREGION)); Free($7); } ; teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail { long rtyp = 0; switch($6) { case -1: rtyp = LR_TELE; break; case 0: rtyp = LR_DOWNTELE; break; case 1: rtyp = LR_UPTELE; break; } add_opvars(splev, "iiiii iiiii iiso", VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, $5.x1, $5.y1, $5.x2, $5.y2, $5.area, rtyp, 0, (char *)0, SPO_LEVREGION)); } ; branch_region : BRANCH_ID ':' lev_region ',' lev_region { add_opvars(splev, "iiiii iiiii iiso", VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, $5.x1, $5.y1, $5.x2, $5.y2, $5.area, (long)LR_BRANCH, 0, (char *)0, SPO_LEVREGION)); } ; teleprt_detail : /* empty */ { $$ = -1; } | ',' UP_OR_DOWN { $$ = $2; } ; fountain_detail : FOUNTAIN_ID ':' ter_selection { add_opvars(splev, "o", VA_PASS1(SPO_FOUNTAIN)); } ; sink_detail : SINK_ID ':' ter_selection { add_opvars(splev, "o", VA_PASS1(SPO_SINK)); } ; pool_detail : POOL_ID ':' ter_selection { add_opvars(splev, "o", VA_PASS1(SPO_POOL)); } ; terrain_type : CHAR { $$.lit = -2; $$.ter = what_map_char((char) $1); } | '(' CHAR ',' light_state ')' { $$.lit = $4; $$.ter = what_map_char((char) $2); } ; replace_terrain_detail : REPLACE_TERRAIN_ID ':' region_or_var ',' mapchar_or_var ',' mapchar_or_var ',' SPERCENT { add_opvars(splev, "io", VA_PASS2($9, SPO_REPLACETERRAIN)); } ; terrain_detail : TERRAIN_ID ':' ter_selection ',' mapchar_or_var { add_opvars(splev, "o", VA_PASS1(SPO_TERRAIN)); } ; diggable_detail : NON_DIGGABLE_ID ':' region_or_var { add_opvars(splev, "o", VA_PASS1(SPO_NON_DIGGABLE)); } ; passwall_detail : NON_PASSWALL_ID ':' region_or_var { add_opvars(splev, "o", VA_PASS1(SPO_NON_PASSWALL)); } ; region_detail : REGION_ID ':' region_or_var ',' light_state ',' room_type optroomregionflags { long irr; long rt = $7; long rflags = $8; if (rflags == -1) rflags = (1 << 0); if (!(rflags & 1)) rt += MAXRTYPE+1; irr = ((rflags & 2) != 0); add_opvars(splev, "iiio", VA_PASS4((long)$5, rt, rflags, SPO_REGION)); $$ = (irr || (rflags & 1) || rt != OROOM); break_stmt_start(); } region_detail_end { break_stmt_end(splev); if ( $9 ) { add_opcode(splev, SPO_ENDROOM, NULL); } else if ( $10 ) lc_error("Cannot use lev statements in non-permanent REGION"); } ; region_detail_end : /* nothing */ { $$ = 0; } | stmt_block { $$ = $1; } ; altar_detail : ALTAR_ID ':' coord_or_var ',' alignment ',' altar_type { add_opvars(splev, "iio", VA_PASS3((long)$7, (long)$5, SPO_ALTAR)); } ; grave_detail : GRAVE_ID ':' coord_or_var ',' string_expr { add_opvars(splev, "io", VA_PASS2(2, SPO_GRAVE)); } | GRAVE_ID ':' coord_or_var ',' RANDOM_TYPE { add_opvars(splev, "sio", VA_PASS3((char *)0, 1, SPO_GRAVE)); } | GRAVE_ID ':' coord_or_var { add_opvars(splev, "sio", VA_PASS3((char *)0, 0, SPO_GRAVE)); } ; gold_detail : GOLD_ID ':' math_expr_var ',' coord_or_var { add_opvars(splev, "o", VA_PASS1(SPO_GOLD)); } ; engraving_detail: ENGRAVING_ID ':' coord_or_var ',' engraving_type ',' string_expr { add_opvars(splev, "io", VA_PASS2((long)$5, SPO_ENGRAVING)); } ; mineralize : MINERALIZE_ID ':' integer_or_var ',' integer_or_var ',' integer_or_var ',' integer_or_var { add_opvars(splev, "o", VA_PASS1(SPO_MINERALIZE)); } | MINERALIZE_ID { add_opvars(splev, "iiiio", VA_PASS5(-1L, -1L, -1L, -1L, SPO_MINERALIZE)); } ; trap_name : STRING { int token = get_trap_type($1); if (token == ERR) lc_error("Unknown trap type '%s'!", $1); $$ = token; Free($1); } | RANDOM_TYPE ; room_type : STRING { int token = get_room_type($1); if (token == ERR) { lc_warning("Unknown room type \"%s\"! Making ordinary room...", $1); $$ = OROOM; } else $$ = token; Free($1); } | RANDOM_TYPE ; optroomregionflags : /* empty */ { $$ = -1; } | ',' roomregionflags { $$ = $2; } ; roomregionflags : roomregionflag { $$ = $1; } | roomregionflag ',' roomregionflags { $$ = $1 | $3; } ; /* 0 is the "default" here */ roomregionflag : FILLING { $$ = ($1 << 0); } | IRREGULAR { $$ = ($1 << 1); } | JOINED { $$ = ($1 << 2); } ; door_state : DOOR_STATE | RANDOM_TYPE ; light_state : LIGHT_STATE | RANDOM_TYPE ; alignment : ALIGNMENT | a_register | RANDOM_TYPE { $$ = - MAX_REGISTERS - 1; } ; alignment_prfx : ALIGNMENT | a_register | A_REGISTER ':' RANDOM_TYPE { $$ = - MAX_REGISTERS - 1; } ; altar_type : ALTAR_TYPE | RANDOM_TYPE ; a_register : A_REGISTER '[' INTEGER ']' { if ( $3 >= 3 ) lc_error("Register Index overflow!"); else $$ = - $3 - 1; } ; string_or_var : STRING { add_opvars(splev, "s", VA_PASS1($1)); Free($1); } | VARSTRING_STRING { check_vardef_type(variable_definitions, $1, SPOVAR_STRING); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | VARSTRING_STRING_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_STRING|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } ; integer_or_var : math_expr_var { /* nothing */ } ; coord_or_var : encodecoord { add_opvars(splev, "c", VA_PASS1($1)); } | rndcoord_ID '(' ter_selection ')' { add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDCOORD)); } | VARSTRING_COORD { check_vardef_type(variable_definitions, $1, SPOVAR_COORD); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | VARSTRING_COORD_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_COORD|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } ; encodecoord : '(' INTEGER ',' INTEGER ')' { if ($2 < 0 || $4 < 0 || $2 >= COLNO || $4 >= ROWNO) lc_error("Coordinates (%li,%li) out of map range!", $2, $4); $$ = SP_COORD_PACK($2, $4); } | RANDOM_TYPE { $$ = SP_COORD_PACK_RANDOM(0); } | RANDOM_TYPE_BRACKET humidity_flags ']' { $$ = SP_COORD_PACK_RANDOM( $2 ); } ; humidity_flags : HUMIDITY_TYPE { $$ = $1; } | HUMIDITY_TYPE ',' humidity_flags { if (($1 & $3)) lc_warning("Humidity flag used twice."); $$ = ($1 | $3); } ; region_or_var : encoderegion { /* nothing */ } | VARSTRING_REGION { check_vardef_type(variable_definitions, $1, SPOVAR_REGION); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | VARSTRING_REGION_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_REGION|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } ; encoderegion : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' { long r = SP_REGION_PACK($2, $4, $6, $8); if ( $2 > $6 || $4 > $8 ) lc_error("Region start > end: (%li,%li,%li,%li)!", $2, $4, $6, $8); add_opvars(splev, "r", VA_PASS1(r)); $$ = r; } ; mapchar_or_var : mapchar { add_opvars(splev, "m", VA_PASS1($1)); } | VARSTRING_MAPCHAR { check_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | VARSTRING_MAPCHAR_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } ; mapchar : CHAR { if (what_map_char((char) $1) != INVALID_TYPE) $$ = SP_MAPCHAR_PACK(what_map_char((char) $1), -2); else { lc_error("Unknown map char type '%c'!", $1); $$ = SP_MAPCHAR_PACK(STONE, -2); } } | '(' CHAR ',' light_state ')' { if (what_map_char((char) $2) != INVALID_TYPE) $$ = SP_MAPCHAR_PACK(what_map_char((char) $2), $4); else { lc_error("Unknown map char type '%c'!", $2); $$ = SP_MAPCHAR_PACK(STONE, $4); } } ; monster_or_var : encodemonster { add_opvars(splev, "M", VA_PASS1($1)); } | VARSTRING_MONST { check_vardef_type(variable_definitions, $1, SPOVAR_MONST); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | VARSTRING_MONST_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_MONST|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } ; encodemonster : STRING { long m = get_monster_id($1, (char)0); if (m == ERR) { lc_error("Unknown monster \"%s\"!", $1); $$ = -1; } else $$ = SP_MONST_PACK(m, def_monsyms[(int)mons[m].mlet].sym); Free($1); } | CHAR { if (check_monster_char((char) $1)) $$ = SP_MONST_PACK(-1, $1); else { lc_error("Unknown monster class '%c'!", $1); $$ = -1; } } | '(' CHAR ',' STRING ')' { long m = get_monster_id($4, (char) $2); if (m == ERR) { lc_error("Unknown monster ('%c', \"%s\")!", $2, $4); $$ = -1; } else $$ = SP_MONST_PACK(m, $2); Free($4); } | RANDOM_TYPE { $$ = -1; } ; object_or_var : encodeobj { add_opvars(splev, "O", VA_PASS1($1)); } | VARSTRING_OBJ { check_vardef_type(variable_definitions, $1, SPOVAR_OBJ); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | VARSTRING_OBJ_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_OBJ|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } ; encodeobj : STRING { long m = get_object_id($1, (char)0); if (m == ERR) { lc_error("Unknown object \"%s\"!", $1); $$ = -1; } else $$ = SP_OBJ_PACK(m, 1); /* obj class != 0 to force generation of a specific item */ Free($1); } | CHAR { if (check_object_char((char) $1)) $$ = SP_OBJ_PACK(-1, $1); else { lc_error("Unknown object class '%c'!", $1); $$ = -1; } } | '(' CHAR ',' STRING ')' { long m = get_object_id($4, (char) $2); if (m == ERR) { lc_error("Unknown object ('%c', \"%s\")!", $2, $4); $$ = -1; } else $$ = SP_OBJ_PACK(m, $2); Free($4); } | RANDOM_TYPE { $$ = -1; } ; string_expr : string_or_var { } | string_expr '.' string_or_var { add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD)); } ; math_expr_var : INTEGER { add_opvars(splev, "i", VA_PASS1($1)); } | dice { is_inconstant_number = 1; } | '(' MINUS_INTEGER ')' { add_opvars(splev, "i", VA_PASS1($2)); } | VARSTRING_INT { check_vardef_type(variable_definitions, $1, SPOVAR_INT); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); is_inconstant_number = 1; } | VARSTRING_INT_ARRAY '[' math_expr_var ']' { check_vardef_type(variable_definitions, $1, SPOVAR_INT|SPOVAR_ARRAY); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); is_inconstant_number = 1; } | math_expr_var '+' math_expr_var { add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD)); } | math_expr_var '-' math_expr_var { add_opvars(splev, "o", VA_PASS1(SPO_MATH_SUB)); } | math_expr_var '*' math_expr_var { add_opvars(splev, "o", VA_PASS1(SPO_MATH_MUL)); } | math_expr_var '/' math_expr_var { add_opvars(splev, "o", VA_PASS1(SPO_MATH_DIV)); } | math_expr_var '%' math_expr_var { add_opvars(splev, "o", VA_PASS1(SPO_MATH_MOD)); } | '(' math_expr_var ')' { } ; func_param_type : CFUNC_INT { if (!strcmp("int", $1) || !strcmp("integer", $1)) { $$ = (int)'i'; } else lc_error("Unknown function parameter type '%s'", $1); } | CFUNC_STR { if (!strcmp("str", $1) || !strcmp("string", $1)) { $$ = (int)'s'; } else lc_error("Unknown function parameter type '%s'", $1); } ; func_param_part : any_var_or_arr ':' func_param_type { struct lc_funcdefs_parm *tmp = New(struct lc_funcdefs_parm); if (!curr_function) { lc_error("Function parameters outside function definition."); } else if (!tmp) { lc_error("Could not alloc function params."); } else { long vt; tmp->name = strdup($1); tmp->parmtype = (char) $3; tmp->next = curr_function->params; curr_function->params = tmp; curr_function->n_params++; switch (tmp->parmtype) { case 'i': vt = SPOVAR_INT; break; case 's': vt = SPOVAR_STRING; break; default: lc_error("Unknown func param conversion."); break; } variable_definitions = add_vardef_type( variable_definitions, $1, vt); } Free($1); } ; func_param_list : func_param_part | func_param_list ',' func_param_part ; func_params_list : /* nothing */ | func_param_list ; func_call_param_part : math_expr_var { $$ = (int)'i'; } | string_expr { $$ = (int)'s'; } ; func_call_param_list : func_call_param_part { char tmpbuf[2]; tmpbuf[0] = (char) $1; tmpbuf[1] = '\0'; $$ = strdup(tmpbuf); } | func_call_param_list ',' func_call_param_part { long len = strlen( $1 ); char *tmp = (char *)alloc(len + 2); sprintf(tmp, "%c%s", (char) $3, $1 ); Free( $1 ); $$ = tmp; } ; func_call_params_list : /* nothing */ { $$ = strdup(""); } | func_call_param_list { char *tmp = strdup( $1 ); Free( $1 ); $$ = tmp; } ; ter_selection_x : coord_or_var { add_opvars(splev, "o", VA_PASS1(SPO_SEL_POINT)); } | rect_ID region_or_var { add_opvars(splev, "o", VA_PASS1(SPO_SEL_RECT)); } | fillrect_ID region_or_var { add_opvars(splev, "o", VA_PASS1(SPO_SEL_FILLRECT)); } | line_ID coord_or_var ',' coord_or_var { add_opvars(splev, "o", VA_PASS1(SPO_SEL_LINE)); } | randline_ID coord_or_var ',' coord_or_var ',' math_expr_var { /* randline (x1,y1),(x2,y2), roughness */ add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDLINE)); } | grow_ID '(' ter_selection ')' { add_opvars(splev, "io", VA_PASS2(W_ANY, SPO_SEL_GROW)); } | grow_ID '(' dir_list ',' ter_selection ')' { add_opvars(splev, "io", VA_PASS2($3, SPO_SEL_GROW)); } | filter_ID '(' SPERCENT ',' ter_selection ')' { add_opvars(splev, "iio", VA_PASS3($3, SPOFILTER_PERCENT, SPO_SEL_FILTER)); } | filter_ID '(' ter_selection ',' ter_selection ')' { add_opvars(splev, "io", VA_PASS2(SPOFILTER_SELECTION, SPO_SEL_FILTER)); } | filter_ID '(' mapchar_or_var ',' ter_selection ')' { add_opvars(splev, "io", VA_PASS2(SPOFILTER_MAPCHAR, SPO_SEL_FILTER)); } | flood_ID coord_or_var { add_opvars(splev, "o", VA_PASS1(SPO_SEL_FLOOD)); } | circle_ID '(' coord_or_var ',' math_expr_var ')' { add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 1, SPO_SEL_ELLIPSE)); } | circle_ID '(' coord_or_var ',' math_expr_var ',' FILLING ')' { add_opvars(splev, "oio", VA_PASS3(SPO_COPY, $7, SPO_SEL_ELLIPSE)); } | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ')' { add_opvars(splev, "io", VA_PASS2(1, SPO_SEL_ELLIPSE)); } | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ',' FILLING ')' { add_opvars(splev, "io", VA_PASS2($9, SPO_SEL_ELLIPSE)); } | gradient_ID '(' GRADIENT_TYPE ',' '(' math_expr_var '-' math_expr_var opt_limited ')' ',' coord_or_var opt_coord_or_var ')' { add_opvars(splev, "iio", VA_PASS3($9, $3, SPO_SEL_GRADIENT)); } | complement_ID ter_selection_x { add_opvars(splev, "o", VA_PASS1(SPO_SEL_COMPLEMENT)); } | VARSTRING_SEL { check_vardef_type(variable_definitions, $1, SPOVAR_SEL); vardef_used(variable_definitions, $1); add_opvars(splev, "v", VA_PASS1($1)); Free($1); } | '(' ter_selection ')' { /* nothing */ } ; ter_selection : ter_selection_x { /* nothing */ } | ter_selection_x '&' ter_selection { add_opvars(splev, "o", VA_PASS1(SPO_SEL_ADD)); } ; dice : DICE { add_opvars(splev, "iio", VA_PASS3($1.num, $1.die, SPO_DICE)); } ; all_integers : MINUS_INTEGER | PLUS_INTEGER | INTEGER ; all_ints_push : MINUS_INTEGER { add_opvars(splev, "i", VA_PASS1($1)); } | PLUS_INTEGER { add_opvars(splev, "i", VA_PASS1($1)); } | INTEGER { add_opvars(splev, "i", VA_PASS1($1)); } | dice { /* nothing */ } ; objectid : object_ID | OBJECT_ID ; monsterid : monster_ID | MONSTER_ID ; terrainid : terrain_ID | TERRAIN_ID ; engraving_type : ENGRAVING_TYPE | RANDOM_TYPE ; lev_region : region { $$ = $1; } | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' { if ($3 <= 0 || $3 >= COLNO) lc_error("Region (%li,%li,%li,%li) out of level range (x1)!", $3, $5, $7, $9); else if ($5 < 0 || $5 >= ROWNO) lc_error("Region (%li,%li,%li,%li) out of level range (y1)!", $3, $5, $7, $9); else if ($7 <= 0 || $7 >= COLNO) lc_error("Region (%li,%li,%li,%li) out of level range (x2)!", $3, $5, $7, $9); else if ($9 < 0 || $9 >= ROWNO) lc_error("Region (%li,%li,%li,%li) out of level range (y2)!", $3, $5, $7, $9); $$.x1 = $3; $$.y1 = $5; $$.x2 = $7; $$.y2 = $9; $$.area = 1; } ; region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' { /* This series of if statements is a hack for MSC 5.1. It seems that its tiny little brain cannot compile if these are all one big if statement. */ if ($2 < 0 || $2 > (int)max_x_map) lc_error("Region (%li,%li,%li,%li) out of map range (x1)!", $2, $4, $6, $8); else if ($4 < 0 || $4 > (int)max_y_map) lc_error("Region (%li,%li,%li,%li) out of map range (y1)!", $2, $4, $6, $8); else if ($6 < 0 || $6 > (int)max_x_map) lc_error("Region (%li,%li,%li,%li) out of map range (x2)!", $2, $4, $6, $8); else if ($8 < 0 || $8 > (int)max_y_map) lc_error("Region (%li,%li,%li,%li) out of map range (y2)!", $2, $4, $6, $8); $$.area = 0; $$.x1 = $2; $$.y1 = $4; $$.x2 = $6; $$.y2 = $8; } ; %% /*lev_comp.y*/ nethack-3.6.0/util/lev_main.c0000664000076400007660000011434312624044164015061 0ustar paxedpaxed/* NetHack 3.6 lev_main.c $NHDT-Date: 1448074107 2015/11/21 02:48:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.43 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the main function for the parser * and some useful functions needed by yacc */ #define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) and for MPW (macconf.h) */ #define NEED_VARARGS #include "hack.h" #include "date.h" #include "sp_lev.h" #ifdef STRICT_REF_DEF #include "tcap.h" #endif #include #ifdef MAC #if defined(__SC__) || defined(__MRC__) #define MPWTOOL #define PREFIX ":dungeon:" /* place output files here */ #include #else #if !defined(__MACH__) #define PREFIX ":lib:" /* place output files here */ #endif #endif #endif #ifdef WIN_CE #define PREFIX "\\nethack\\dat\\" #endif #ifndef MPWTOOL #define SpinCursor(x) #endif #if defined(AMIGA) && defined(DLB) #define PREFIX "NH:slib/" #endif #ifndef O_WRONLY #include #endif #ifndef O_CREAT /* some older BSD systems do not define O_CREAT in \ */ #include #endif #ifndef O_BINARY /* used for micros, no-op for others */ #define O_BINARY 0 #endif #if defined(MICRO) || defined(WIN32) #define OMASK FCMASK #else #define OMASK 0644 #endif #define ERR (-1) #define NewTab(type, size) (type **) alloc(sizeof(type *) * size) #define Free(ptr) \ if (ptr) \ free((genericptr_t)(ptr)) /* write() returns a signed value but its size argument is unsigned; types might be int and unsigned or ssize_t and size_t; casting to long should be safe for all permutations (even if size_t is bigger, since the values involved won't be too big for long) */ #define Write(fd, item, size) \ if ((long) write(fd, (genericptr_t)(item), size) != (long) (size)) \ return FALSE; #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif #define MAX_ERRORS 25 extern int NDECL(yyparse); extern void FDECL(init_yyin, (FILE *)); extern void FDECL(init_yyout, (FILE *)); int FDECL(main, (int, char **)); void FDECL(yyerror, (const char *)); void FDECL(yywarning, (const char *)); int NDECL(yywrap); int FDECL(get_floor_type, (CHAR_P)); int FDECL(get_room_type, (char *)); int FDECL(get_trap_type, (char *)); int FDECL(get_monster_id, (char *, CHAR_P)); int FDECL(get_object_id, (char *, CHAR_P)); boolean FDECL(check_monster_char, (CHAR_P)); boolean FDECL(check_object_char, (CHAR_P)); char FDECL(what_map_char, (CHAR_P)); void FDECL(scan_map, (char *, sp_lev *)); boolean NDECL(check_subrooms); boolean FDECL(write_level_file, (char *, sp_lev *)); struct lc_funcdefs *FDECL(funcdef_new, (long, char *)); void FDECL(funcdef_free_all, (struct lc_funcdefs *)); struct lc_funcdefs *FDECL(funcdef_defined, (struct lc_funcdefs *, char *, int)); struct lc_vardefs *FDECL(vardef_new, (long, char *)); void FDECL(vardef_free_all, (struct lc_vardefs *)); struct lc_vardefs *FDECL(vardef_defined, (struct lc_vardefs *, char *, int)); void FDECL(splev_add_from, (sp_lev *, sp_lev *)); extern void NDECL(monst_init); extern void NDECL(objects_init); extern void NDECL(decl_init); void FDECL(add_opcode, (sp_lev *, int, genericptr_t)); static boolean FDECL(write_common_data, (int)); static boolean FDECL(write_maze, (int, sp_lev *)); static void NDECL(init_obj_classes); static int FDECL(case_insensitive_comp, (const char *, const char *)); void VDECL(lc_pline, (const char *, ...)); void VDECL(lc_error, (const char *, ...)); void VDECL(lc_warning, (const char *, ...)); char *FDECL(decode_parm_chr, (CHAR_P)); char *FDECL(decode_parm_str, (char *)); struct opvar *FDECL(set_opvar_int, (struct opvar *, long)); struct opvar *FDECL(set_opvar_coord, (struct opvar *, long)); struct opvar *FDECL(set_opvar_region, (struct opvar *, long)); struct opvar *FDECL(set_opvar_mapchar, (struct opvar *, long)); struct opvar *FDECL(set_opvar_monst, (struct opvar *, long)); struct opvar *FDECL(set_opvar_obj, (struct opvar *, long)); struct opvar *FDECL(set_opvar_str, (struct opvar *, const char *)); struct opvar *FDECL(set_opvar_var, (struct opvar *, const char *)); void VDECL(add_opvars, (sp_lev *, const char *, ...)); void NDECL(break_stmt_start); void FDECL(break_stmt_end, (sp_lev *)); void FDECL(break_stmt_new, (sp_lev *, long)); char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *)); const char *FDECL(spovar2str, (long)); void FDECL(vardef_used, (struct lc_vardefs *, char *)); void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long)); struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *, char *, long)); int FDECL(reverse_jmp_opcode, (int)); struct opvar *FDECL(opvar_clone, (struct opvar *)); void FDECL(start_level_def, (sp_lev **, char *)); static struct { const char *name; int type; } trap_types[] = { { "arrow", ARROW_TRAP }, { "dart", DART_TRAP }, { "falling rock", ROCKTRAP }, { "board", SQKY_BOARD }, { "bear", BEAR_TRAP }, { "land mine", LANDMINE }, { "rolling boulder", ROLLING_BOULDER_TRAP }, { "sleep gas", SLP_GAS_TRAP }, { "rust", RUST_TRAP }, { "fire", FIRE_TRAP }, { "pit", PIT }, { "spiked pit", SPIKED_PIT }, { "hole", HOLE }, { "trap door", TRAPDOOR }, { "teleport", TELEP_TRAP }, { "level teleport", LEVEL_TELEP }, { "magic portal", MAGIC_PORTAL }, { "web", WEB }, { "statue", STATUE_TRAP }, { "magic", MAGIC_TRAP }, { "anti magic", ANTI_MAGIC }, { "polymorph", POLY_TRAP }, { "vibrating square", VIBRATING_SQUARE }, { 0, 0 } }; static struct { const char *name; int type; } room_types[] = { /* for historical reasons, room types are not contiguous numbers */ /* (type 1 is skipped) */ { "ordinary", OROOM }, { "throne", COURT }, { "swamp", SWAMP }, { "vault", VAULT }, { "beehive", BEEHIVE }, { "morgue", MORGUE }, { "barracks", BARRACKS }, { "zoo", ZOO }, { "delphi", DELPHI }, { "temple", TEMPLE }, { "anthole", ANTHOLE }, { "cocknest", COCKNEST }, { "leprehall", LEPREHALL }, { "shop", SHOPBASE }, { "armor shop", ARMORSHOP }, { "scroll shop", SCROLLSHOP }, { "potion shop", POTIONSHOP }, { "weapon shop", WEAPONSHOP }, { "food shop", FOODSHOP }, { "ring shop", RINGSHOP }, { "wand shop", WANDSHOP }, { "tool shop", TOOLSHOP }, { "book shop", BOOKSHOP }, { "health food shop", FODDERSHOP }, { "candle shop", CANDLESHOP }, { 0, 0 } }; const char *fname = "(stdin)"; int fatal_error = 0; int got_errors = 0; int be_verbose = 0; int fname_counter = 1; #ifdef FLEX23_BUG /* Flex 2.3 bug work around; not needed for 2.3.6 or later */ int yy_more_len = 0; #endif extern unsigned int max_x_map, max_y_map; extern int nh_line_number; extern int token_start_pos; extern char curr_token[512]; struct lc_vardefs *variable_definitions = NULL; struct lc_funcdefs *function_definitions = NULL; extern int allow_break_statements; extern struct lc_breakdef *break_list; int main(argc, argv) int argc; char **argv; { FILE *fin; int i; boolean errors_encountered = FALSE; #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) static char *mac_argv[] = { "lev_comp", /* dummy argv[0] */ ":dat:Arch.des", ":dat:Barb.des", ":dat:Caveman.des", ":dat:Healer.des", ":dat:Knight.des", ":dat:Monk.des", ":dat:Priest.des", ":dat:Ranger.des", ":dat:Rogue.des", ":dat:Samurai.des", ":dat:Tourist.des", ":dat:Valkyrie.des", ":dat:Wizard.des", ":dat:bigroom.des", ":dat:castle.des", ":dat:endgame.des", ":dat:gehennom.des", ":dat:knox.des", ":dat:medusa.des", ":dat:mines.des", ":dat:oracle.des", ":dat:sokoban.des", ":dat:tower.des", ":dat:yendor.des" }; argc = SIZE(mac_argv); argv = mac_argv; #endif /* Note: these initializers don't do anything except guarantee that * we're linked properly. */ monst_init(); objects_init(); decl_init(); /* this one does something... */ init_obj_classes(); init_yyout(stdout); if (argc == 1) { /* Read standard input */ init_yyin(stdin); (void) yyparse(); if (fatal_error > 0) { errors_encountered = TRUE; } } else { /* Otherwise every argument is a filename */ for (i = 1; i < argc; i++) { fname = argv[i]; if (!strcmp(fname, "-v")) { be_verbose++; continue; } fin = freopen(fname, "r", stdin); if (!fin) { lc_pline("Can't open \"%s\" for input.\n", fname); perror(fname); errors_encountered = TRUE; } else { fname_counter = 1; init_yyin(fin); (void) yyparse(); nh_line_number = 1; if (fatal_error > 0 || got_errors > 0) { errors_encountered = TRUE; fatal_error = 0; } } } } exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS); /*NOTREACHED*/ return 0; } /* * Each time the parser detects an error, it uses this function. * Here we take count of the errors. To continue farther than * MAX_ERRORS wouldn't be reasonable. * Assume that explicit calls from lev_comp.y have the 1st letter * capitalized, to allow printing of the line containing the start of * the current declaration, instead of the beginning of the next declaration. */ void yyerror(s) const char *s; { char *e = ((char *) s + strlen(s) - 1); (void) fprintf(stderr, "%s: line %d, pos %d: %s", fname, nh_line_number, token_start_pos - (int) strlen(curr_token), s); if (*e != '.' && *e != '!') (void) fprintf(stderr, " at \"%s\"", curr_token); (void) fprintf(stderr, "\n"); if (++fatal_error > MAX_ERRORS) { (void) fprintf(stderr, "Too many errors, good bye!\n"); exit(EXIT_FAILURE); } } /* * Just display a warning (that is : a non fatal error) */ void yywarning(s) const char *s; { (void) fprintf(stderr, "%s: line %d : WARNING : %s\n", fname, nh_line_number, s); } /* * Stub needed for lex interface. */ int yywrap() { return 1; } /* * lc_pline(): lev_comp version of pline(), stripped down version of * core's pline(), with convoluted handling for variadic arguments to * support , , and neither of the above. * * Using state for message/warning/error mode simplifies calling interface. */ #define LC_PLINE_MESSAGE 0 #define LC_PLINE_WARNING 1 #define LC_PLINE_ERROR 2 static int lc_pline_mode = LC_PLINE_MESSAGE; #if defined(USE_STDARG) || defined(USE_VARARGS) static void FDECL(lc_vpline, (const char *, va_list)); void lc_pline VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, char *); lc_vpline(line, VA_ARGS); VA_END(); } #ifdef USE_STDARG static void lc_vpline(const char *line, va_list the_args) #else static void lc_vpline(line, the_args) const char *line; va_list the_args; #endif #else /* USE_STDARG | USE_VARARG */ #define lc_vpline lc_pline void lc_pline VA_DECL(const char *, line) #endif /* USE_STDARG | USE_VARARG */ { /* opening brace for lc_vpline, nested block for USE_OLDARGS lc_pline */ char pbuf[3 * BUFSZ]; static char nomsg[] = "(no message)"; /* Do NOT use VA_START and VA_END in here... see above */ if (!line || !*line) line = nomsg; /* shouldn't happen */ if (index(line, '%')) { Vsprintf(pbuf, line, VA_ARGS); pbuf[BUFSZ - 1] = '\0'; /* truncate if long */ line = pbuf; } switch (lc_pline_mode) { case LC_PLINE_ERROR: yyerror(line); break; case LC_PLINE_WARNING: yywarning(line); break; default: (void) fprintf(stderr, "%s\n", line); break; } lc_pline_mode = LC_PLINE_MESSAGE; /* reset to default */ return; #if !(defined(USE_STDARG) || defined(USE_VARARGS)) VA_END(); /* closing brace ofr USE_OLDARGS's nested block */ #endif } /*VARARGS1*/ void lc_error VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, const char *); lc_pline_mode = LC_PLINE_ERROR; lc_vpline(line, VA_ARGS); VA_END(); return; } /*VARARGS1*/ void lc_warning VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, const char *); lc_pline_mode = LC_PLINE_WARNING; lc_vpline(line, VA_ARGS); VA_END(); return; } char * decode_parm_chr(chr) char chr; { static char buf[32]; switch (chr) { default: Strcpy(buf, "unknown"); break; case 'i': Strcpy(buf, "int"); break; case 'r': Strcpy(buf, "region"); break; case 's': Strcpy(buf, "str"); break; case 'O': Strcpy(buf, "obj"); break; case 'c': Strcpy(buf, "coord"); break; case ' ': Strcpy(buf, "nothing"); break; case 'm': Strcpy(buf, "mapchar"); break; case 'M': Strcpy(buf, "monster"); break; } return buf; } char * decode_parm_str(str) char *str; { static char tmpbuf[1024]; char *p = str; tmpbuf[0] = '\0'; if (str) { for (; *p; p++) { Strcat(tmpbuf, decode_parm_chr(*p)); if (*(p + 1)) Strcat(tmpbuf, ", "); } } return tmpbuf; } struct opvar * set_opvar_int(ov, val) struct opvar *ov; long val; { if (ov) { ov->spovartyp = SPOVAR_INT; ov->vardata.l = val; } return ov; } struct opvar * set_opvar_coord(ov, val) struct opvar *ov; long val; { if (ov) { ov->spovartyp = SPOVAR_COORD; ov->vardata.l = val; } return ov; } struct opvar * set_opvar_region(ov, val) struct opvar *ov; long val; { if (ov) { ov->spovartyp = SPOVAR_REGION; ov->vardata.l = val; } return ov; } struct opvar * set_opvar_mapchar(ov, val) struct opvar *ov; long val; { if (ov) { ov->spovartyp = SPOVAR_MAPCHAR; ov->vardata.l = val; } return ov; } struct opvar * set_opvar_monst(ov, val) struct opvar *ov; long val; { if (ov) { ov->spovartyp = SPOVAR_MONST; ov->vardata.l = val; } return ov; } struct opvar * set_opvar_obj(ov, val) struct opvar *ov; long val; { if (ov) { ov->spovartyp = SPOVAR_OBJ; ov->vardata.l = val; } return ov; } struct opvar * set_opvar_str(ov, val) struct opvar *ov; const char *val; { if (ov) { ov->spovartyp = SPOVAR_STRING; ov->vardata.str = (val) ? strdup(val) : NULL; } return ov; } struct opvar * set_opvar_var(ov, val) struct opvar *ov; const char *val; { if (ov) { ov->spovartyp = SPOVAR_VARIABLE; ov->vardata.str = (val) ? strdup(val) : NULL; } return ov; } #define New(type) \ (type *) memset((genericptr_t) alloc(sizeof(type)), 0, sizeof(type)) #if defined(USE_STDARG) || defined(USE_VARARGS) static void FDECL(vadd_opvars, (sp_lev *, const char *, va_list)); void add_opvars VA_DECL2(sp_lev *, sp, const char *, fmt) { VA_START(fmt); VA_INIT(fmt, char *); vadd_opvars(sp, fmt, VA_ARGS); VA_END(); } #ifdef USE_STDARG static void vadd_opvars(sp_lev *sp, const char *fmt, va_list the_args) { #else static void vadd_opvars(sp, fmt, the_args) sp_lev *sp; const char *fmt; va_list the_args; { #endif #else /* USE_STDARG | USE_VARARG */ #define vadd_opvars add_opvars void add_opvars VA_DECL2(sp_lev *, sp, const char *, fmt) #endif /* USE_STDARG | USE_VARARG */ const char *p, *lp; long la; /* Do NOT use VA_START and VA_END in here... see above */ for (p = fmt; *p != '\0'; p++) { switch (*p) { case ' ': break; case 'i': /* integer */ { struct opvar *ov = New(struct opvar); set_opvar_int(ov, VA_NEXT(la, long) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'c': /* coordinate */ { struct opvar *ov = New(struct opvar); set_opvar_coord(ov, VA_NEXT(la, long) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'r': /* region */ { struct opvar *ov = New(struct opvar); set_opvar_region(ov, VA_NEXT(la, long) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'm': /* mapchar */ { struct opvar *ov = New(struct opvar); set_opvar_mapchar(ov, VA_NEXT(la, long) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'M': /* monster */ { struct opvar *ov = New(struct opvar); set_opvar_monst(ov, VA_NEXT(la, long) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'O': /* object */ { struct opvar *ov = New(struct opvar); set_opvar_obj(ov, VA_NEXT(la, long) ); add_opcode(sp, SPO_PUSH, ov); break; } case 's': /* string */ { struct opvar *ov = New(struct opvar); set_opvar_str(ov, VA_NEXT(lp, const char *) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'v': /* variable */ { struct opvar *ov = New(struct opvar); set_opvar_var(ov, VA_NEXT(lp, const char *) ); add_opcode(sp, SPO_PUSH, ov); break; } case 'o': /* opcode */ { long i = VA_NEXT(la, int); if (i < 0 || i >= MAX_SP_OPCODES) lc_pline("add_opvars: unknown opcode '%ld'.", i); add_opcode(sp, i, NULL); break; } default: lc_pline("add_opvars: illegal format character '%c'.", *p); break; } } return; } void break_stmt_start() { allow_break_statements++; } void break_stmt_end(splev) sp_lev *splev; { struct lc_breakdef *tmp = break_list; struct lc_breakdef *prv = NULL; while (tmp) { if (tmp->break_depth == allow_break_statements) { struct lc_breakdef *nxt = tmp->next; set_opvar_int(tmp->breakpoint, splev->n_opcodes - tmp->breakpoint->vardata.l - 1); tmp->next = NULL; Free(tmp); if (!prv) break_list = NULL; else prv->next = nxt; tmp = nxt; } else { prv = tmp; tmp = tmp->next; } } allow_break_statements--; } void break_stmt_new(splev, i) sp_lev *splev; long i; { struct lc_breakdef *tmp = New(struct lc_breakdef); tmp->breakpoint = New(struct opvar); tmp->break_depth = allow_break_statements; tmp->next = break_list; break_list = tmp; set_opvar_int(tmp->breakpoint, i); add_opcode(splev, SPO_PUSH, tmp->breakpoint); add_opcode(splev, SPO_JMP, NULL); } struct lc_funcdefs * funcdef_new(addr, name) long addr; char *name; { struct lc_funcdefs *f = New(struct lc_funcdefs); if (!f) { lc_error("Could not alloc function definition for '%s'.", name); return NULL; } f->next = NULL; f->addr = addr; f->name = strdup(name); f->n_called = 0; f->n_params = 0; f->params = NULL; f->code.opcodes = NULL; f->code.n_opcodes = 0; return f; } void funcdef_free_all(fchain) struct lc_funcdefs *fchain; { struct lc_funcdefs *tmp = fchain; struct lc_funcdefs *nxt; struct lc_funcdefs_parm *tmpparam; while (tmp) { nxt = tmp->next; Free(tmp->name); while (tmp->params) { tmpparam = tmp->params->next; Free(tmp->params->name); tmp->params = tmpparam; } /* FIXME: free tmp->code */ Free(tmp); tmp = nxt; } } char * funcdef_paramtypes(f) struct lc_funcdefs *f; { int i = 0; struct lc_funcdefs_parm *fp = f->params; char *tmp = (char *) alloc((f->n_params) + 1); if (!tmp) return NULL; while (fp) { tmp[i++] = fp->parmtype; fp = fp->next; } tmp[i] = '\0'; return tmp; } struct lc_funcdefs * funcdef_defined(f, name, casesense) struct lc_funcdefs *f; char *name; int casesense; { while (f) { if (casesense) { if (!strcmp(name, f->name)) return f; } else { if (!case_insensitive_comp(name, f->name)) return f; } f = f->next; } return NULL; } struct lc_vardefs * vardef_new(typ, name) long typ; char *name; { struct lc_vardefs *f = New(struct lc_vardefs); if (!f) { lc_error("Could not alloc variable definition for '%s'.", name); return NULL; } f->next = NULL; f->var_type = typ; f->name = strdup(name); f->n_used = 0; return f; } void vardef_free_all(fchain) struct lc_vardefs *fchain; { struct lc_vardefs *tmp = fchain; struct lc_vardefs *nxt; while (tmp) { if (be_verbose && (tmp->n_used == 0)) lc_warning("Unused variable '%s'", tmp->name); nxt = tmp->next; Free(tmp->name); Free(tmp); tmp = nxt; } } struct lc_vardefs * vardef_defined(f, name, casesense) struct lc_vardefs *f; char *name; int casesense; { while (f) { if (casesense) { if (!strcmp(name, f->name)) return f; } else { if (!case_insensitive_comp(name, f->name)) return f; } f = f->next; } return NULL; } const char * spovar2str(spovar) long spovar; { static int togl = 0; static char buf[2][128]; const char *n = NULL; int is_array = (spovar & SPOVAR_ARRAY); spovar &= ~SPOVAR_ARRAY; switch (spovar) { default: lc_error("spovar2str(%ld)", spovar); break; case SPOVAR_INT: n = "integer"; break; case SPOVAR_STRING: n = "string"; break; case SPOVAR_VARIABLE: n = "variable"; break; case SPOVAR_COORD: n = "coordinate"; break; case SPOVAR_REGION: n = "region"; break; case SPOVAR_MAPCHAR: n = "mapchar"; break; case SPOVAR_MONST: n = "monster"; break; case SPOVAR_OBJ: n = "object"; break; } togl = ((togl + 1) % 2); snprintf(buf[togl], 127, "%s%s", n, (is_array ? " array" : "")); return buf[togl]; } void vardef_used(vd, varname) struct lc_vardefs *vd; char *varname; { struct lc_vardefs *tmp; if ((tmp = vardef_defined(vd, varname, 1)) != 0) tmp->n_used++; } void check_vardef_type(vd, varname, vartype) struct lc_vardefs *vd; char *varname; long vartype; { struct lc_vardefs *tmp; if ((tmp = vardef_defined(vd, varname, 1)) != 0) { if (tmp->var_type != vartype) lc_error("Trying to use variable '%s' as %s, when it is %s.", varname, spovar2str(vartype), spovar2str(tmp->var_type)); } else lc_error("Variable '%s' not defined.", varname); } struct lc_vardefs * add_vardef_type(vd, varname, vartype) struct lc_vardefs *vd; char *varname; long vartype; { struct lc_vardefs *tmp; if ((tmp = vardef_defined(vd, varname, 1)) != 0) { if (tmp->var_type != vartype) lc_error("Trying to redefine variable '%s' as %s, when it is %s.", varname, spovar2str(vartype), spovar2str(tmp->var_type)); } else { tmp = vardef_new(vartype, varname); tmp->next = vd; return tmp; } return vd; } int reverse_jmp_opcode(opcode) int opcode; { switch (opcode) { case SPO_JE: return SPO_JNE; case SPO_JNE: return SPO_JE; case SPO_JL: return SPO_JGE; case SPO_JG: return SPO_JLE; case SPO_JLE: return SPO_JG; case SPO_JGE: return SPO_JL; default: lc_error("Cannot reverse comparison jmp opcode %d.", opcode); return SPO_NULL; } } /* basically copied from src/sp_lev.c */ struct opvar * opvar_clone(ov) struct opvar *ov; { if (ov) { struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar)); if (!tmpov) { /* lint suppression */ /*NOTREACHED*/ #if 0 /* not possible; alloc() never returns Null */ panic("could not alloc opvar struct"); /*NOTREACHED*/ #endif return (struct opvar *) 0; } switch (ov->spovartyp) { case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: { tmpov->spovartyp = ov->spovartyp; tmpov->vardata.l = ov->vardata.l; } break; case SPOVAR_VARIABLE: case SPOVAR_STRING: { int len = strlen(ov->vardata.str); tmpov->spovartyp = ov->spovartyp; tmpov->vardata.str = (char *) alloc(len + 1); (void) memcpy((genericptr_t) tmpov->vardata.str, (genericptr_t) ov->vardata.str, len); tmpov->vardata.str[len] = '\0'; } break; default: { lc_error("Unknown opvar_clone value type (%d)!", ov->spovartyp); } /* default */ } /* switch */ return tmpov; } return (struct opvar *) 0; } void splev_add_from(splev, from_splev) sp_lev *splev; sp_lev *from_splev; { int i; if (splev && from_splev) for (i = 0; i < from_splev->n_opcodes; i++) add_opcode(splev, from_splev->opcodes[i].opcode, opvar_clone(from_splev->opcodes[i].opdat)); } void start_level_def(splev, ldfname) sp_lev **splev; char *ldfname; { struct lc_funcdefs *f; if (index(ldfname, '.')) lc_error("Invalid dot ('.') in level name '%s'.", ldfname); if ((int) strlen(ldfname) > 14) lc_error("Level names limited to 14 characters ('%s').", ldfname); f = function_definitions; while (f) { f->n_called = 0; f = f->next; } *splev = (sp_lev *) alloc(sizeof(sp_lev)); (*splev)->n_opcodes = 0; (*splev)->opcodes = NULL; vardef_free_all(variable_definitions); variable_definitions = NULL; } /* * Find the type of floor, knowing its char representation. */ int get_floor_type(c) char c; { int val; SpinCursor(3); val = what_map_char(c); if (val == INVALID_TYPE) { val = ERR; yywarning("Invalid fill character in MAZE declaration"); } return val; } /* * Find the type of a room in the table, knowing its name. */ int get_room_type(s) char *s; { register int i; SpinCursor(3); for (i = 0; room_types[i].name; i++) if (!strcmp(s, room_types[i].name)) return ((int) room_types[i].type); return ERR; } /* * Find the type of a trap in the table, knowing its name. */ int get_trap_type(s) char *s; { register int i; SpinCursor(3); for (i = 0; trap_types[i].name; i++) if (!strcmp(s, trap_types[i].name)) return trap_types[i].type; return ERR; } /* * Find the index of a monster in the table, knowing its name. */ int get_monster_id(s, c) char *s; char c; { register int i, class; SpinCursor(3); class = c ? def_char_to_monclass(c) : 0; if (class == MAXMCLASSES) return ERR; for (i = LOW_PM; i < NUMMONS; i++) if (!class || class == mons[i].mlet) if (!strcmp(s, mons[i].mname)) return i; /* didn't find it; lets try case insensitive search */ for (i = LOW_PM; i < NUMMONS; i++) if (!class || class == mons[i].mlet) if (!case_insensitive_comp(s, mons[i].mname)) { if (be_verbose) lc_warning("Monster type \"%s\" matches \"%s\".", s, mons[i].mname); return i; } return ERR; } /* * Find the index of an object in the table, knowing its name. */ int get_object_id(s, c) char *s; char c; /* class */ { int i, class; const char *objname; SpinCursor(3); class = (c > 0) ? def_char_to_objclass(c) : 0; if (class == MAXOCLASSES) return ERR; for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) { if (class && objects[i].oc_class != class) break; objname = obj_descr[i].oc_name; if (objname && !strcmp(s, objname)) return i; } for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) { if (class && objects[i].oc_class != class) break; objname = obj_descr[i].oc_name; if (objname && !case_insensitive_comp(s, objname)) { if (be_verbose) lc_warning("Object type \"%s\" matches \"%s\".", s, objname); return i; } } return ERR; } static void init_obj_classes() { int i, class, prev_class; prev_class = -1; for (i = 0; i < NUM_OBJECTS; i++) { class = objects[i].oc_class; if (class != prev_class) { bases[class] = i; prev_class = class; } } } /* * Is the character 'c' a valid monster class ? */ boolean check_monster_char(c) char c; { return (def_char_to_monclass(c) != MAXMCLASSES); } /* * Is the character 'c' a valid object class ? */ boolean check_object_char(c) char c; { return (def_char_to_objclass(c) != MAXOCLASSES); } /* * Convert .des map letter into floor type. */ char what_map_char(c) char c; { SpinCursor(3); switch (c) { case ' ': return (STONE); case '#': return (CORR); case '.': return (ROOM); case '-': return (HWALL); case '|': return (VWALL); case '+': return (DOOR); case 'A': return (AIR); case 'B': return (CROSSWALL); /* hack: boundary location */ case 'C': return (CLOUD); case 'S': return (SDOOR); case 'H': return (SCORR); case '{': return (FOUNTAIN); case '\\': return (THRONE); case 'K': return (SINK); case '}': return (MOAT); case 'P': return (POOL); case 'L': return (LAVAPOOL); case 'I': return (ICE); case 'W': return (WATER); case 'T': return (TREE); case 'F': return (IRONBARS); /* Fe = iron */ case 'x': return (MAX_TYPE); /* "see-through" */ } return (INVALID_TYPE); } void add_opcode(sp, opc, dat) sp_lev *sp; int opc; genericptr_t dat; { long nop = sp->n_opcodes; _opcode *tmp; if ((opc < 0) || (opc >= MAX_SP_OPCODES)) lc_error("Unknown opcode '%d'", opc); tmp = (_opcode *) alloc(sizeof(_opcode) * (nop + 1)); if (!tmp) { /* lint suppression */ /*NOTREACHED*/ #if 0 /* not possible; alloc() never returns Null */ lc_error("Could not alloc opcode space"); #endif return; } if (sp->opcodes && nop) { (void) memcpy(tmp, sp->opcodes, sizeof(_opcode) * nop); free(sp->opcodes); } sp->opcodes = tmp; sp->opcodes[nop].opcode = opc; sp->opcodes[nop].opdat = dat; sp->n_opcodes++; } /* * Yep! LEX gives us the map in a raw mode. * Just analyze it here. */ void scan_map(map, sp) char *map; sp_lev *sp; { register int i, len; register char *s1, *s2; int max_len = 0; int max_hig = 0; char *tmpmap[ROWNO]; int dx, dy; char *mbuf; /* First, strip out digits 0-9 (line numbering) */ for (s1 = s2 = map; *s1; s1++) if (*s1 < '0' || *s1 > '9') *s2++ = *s1; *s2 = '\0'; /* Second, find the max width of the map */ s1 = map; while (s1 && *s1) { s2 = index(s1, '\n'); if (s2) { len = (int) (s2 - s1); s1 = s2 + 1; } else { len = (int) strlen(s1); s1 = (char *) 0; } if (len > max_len) max_len = len; } /* Then parse it now */ while (map && *map) { tmpmap[max_hig] = (char *) alloc(max_len); s1 = index(map, '\n'); if (s1) { len = (int) (s1 - map); s1++; } else { len = (int) strlen(map); s1 = map + len; } for (i = 0; i < len; i++) if ((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) { lc_warning("Invalid character '%c' @ (%d, %d) - replacing " "with stone", map[i], max_hig, i); tmpmap[max_hig][i] = STONE; } while (i < max_len) tmpmap[max_hig][i++] = STONE; map = s1; max_hig++; } /* Memorize boundaries */ max_x_map = max_len - 1; max_y_map = max_hig - 1; if (max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) { lc_error("Map too large at (%d x %d), max is (%d x %d)", max_len, max_hig, MAP_X_LIM, MAP_Y_LIM); } mbuf = (char *) alloc(((max_hig - 1) * max_len) + (max_len - 1) + 2); for (dy = 0; dy < max_hig; dy++) for (dx = 0; dx < max_len; dx++) mbuf[(dy * max_len) + dx] = (tmpmap[dy][dx] + 1); mbuf[((max_hig - 1) * max_len) + (max_len - 1) + 1] = '\0'; add_opvars(sp, "siio", VA_PASS4(mbuf, max_hig, max_len, SPO_MAP)); for (dy = 0; dy < max_hig; dy++) Free(tmpmap[dy]); Free(mbuf); } /* * Output some info common to all special levels. */ static boolean write_common_data(fd) int fd; { static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3 }; Write(fd, &version_data, sizeof version_data); return TRUE; } /* * Here we write the sp_lev structure in the specified file (fd). * Also, we have to free the memory allocated via alloc(). */ static boolean write_maze(fd, maze) int fd; sp_lev *maze; { int i; if (!write_common_data(fd)) return FALSE; Write(fd, &(maze->n_opcodes), sizeof(maze->n_opcodes)); for (i = 0; i < maze->n_opcodes; i++) { _opcode tmpo = maze->opcodes[i]; Write(fd, &(tmpo.opcode), sizeof(tmpo.opcode)); if (tmpo.opcode < SPO_NULL || tmpo.opcode >= MAX_SP_OPCODES) panic("write_maze: unknown opcode (%d).", tmpo.opcode); if (tmpo.opcode == SPO_PUSH) { genericptr_t opdat = tmpo.opdat; if (opdat) { struct opvar *ov = (struct opvar *) opdat; int size; Write(fd, &(ov->spovartyp), sizeof(ov->spovartyp)); switch (ov->spovartyp) { case SPOVAR_NULL: break; case SPOVAR_COORD: case SPOVAR_REGION: case SPOVAR_MAPCHAR: case SPOVAR_MONST: case SPOVAR_OBJ: case SPOVAR_INT: Write(fd, &(ov->vardata.l), sizeof(ov->vardata.l)); break; case SPOVAR_VARIABLE: case SPOVAR_STRING: if (ov->vardata.str) size = strlen(ov->vardata.str); else size = 0; Write(fd, &size, sizeof(size)); if (size) { Write(fd, ov->vardata.str, size); Free(ov->vardata.str); } break; default: panic("write_maze: unknown data type (%d).", ov->spovartyp); } } else panic("write_maze: PUSH with no data."); } else { /* sanity check */ genericptr_t opdat = tmpo.opdat; if (opdat) panic("write_maze: opcode (%d) has data.", tmpo.opcode); } Free(tmpo.opdat); } /* clear the struct for next user */ Free(maze->opcodes); maze->opcodes = NULL; /*(void) memset((genericptr_t) &maze->init_lev, 0, sizeof * maze->init_lev);*/ return TRUE; } /* * Open and write maze or rooms file, based on which pointer is non-null. * Return TRUE on success, FALSE on failure. */ boolean write_level_file(filename, lvl) char *filename; sp_lev *lvl; { int fout; char lbuf[60]; lbuf[0] = '\0'; #ifdef PREFIX Strcat(lbuf, PREFIX); #endif Strcat(lbuf, filename); Strcat(lbuf, LEV_EXT); #if defined(MAC) && (defined(__SC__) || defined(__MRC__)) fout = open(lbuf, O_WRONLY | O_CREAT | O_BINARY); #else fout = open(lbuf, O_WRONLY | O_CREAT | O_BINARY, OMASK); #endif if (fout < 0) return FALSE; if (!lvl) panic("write_level_file"); if (be_verbose) fprintf(stdout, "File: '%s', opcodes: %ld\n", lbuf, lvl->n_opcodes); if (!write_maze(fout, lvl)) return FALSE; (void) close(fout); return TRUE; } static int case_insensitive_comp(s1, s2) const char *s1; const char *s2; { uchar u1, u2; for (;; s1++, s2++) { u1 = (uchar) *s1; if (isupper(u1)) u1 = tolower(u1); u2 = (uchar) *s2; if (isupper(u2)) u2 = tolower(u2); if (u1 == '\0' || u1 != u2) break; } return u1 - u2; } #ifdef STRICT_REF_DEF /* * Any globals declared in hack.h and descendents which aren't defined * in the modules linked into lev_comp should be defined here. These * definitions can be dummies: their sizes shouldn't matter as long as * as their types are correct; actual values are irrelevant. */ #define ARBITRARY_SIZE 1 /* attrib.c */ struct attribs attrmax, attrmin; /* files.c */ const char *configfile; char lock[ARBITRARY_SIZE]; char SAVEF[ARBITRARY_SIZE]; #ifdef MICRO char SAVEP[ARBITRARY_SIZE]; #endif /* termcap.c */ struct tc_lcl_data tc_lcl_data; #ifdef TEXTCOLOR #ifdef TOS const char *hilites[CLR_MAX]; #else char NEARDATA *hilites[CLR_MAX]; #endif #endif /* trap.c */ const char *traps[TRAPNUM]; /* window.c */ #ifdef HANGUPHANDLING volatile #endif struct window_procs windowprocs; /* xxxtty.c */ #ifdef DEFINE_OSPEED short ospeed; #endif #endif /* STRICT_REF_DEF */ /*lev_main.c*/ nethack-3.6.0/util/makedefs.c0000664000076400007660000024344612620070666015057 0ustar paxedpaxed/* NetHack 3.6 makedefs.c $NHDT-Date: 1447062431 2015/11/09 09:47:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.105 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) Dean Luick, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #define MAKEDEFS_C /* use to conditionally include file sections */ #include "config.h" #ifdef MONITOR_HEAP #undef free /* makedefs doesn't use the alloc and free in src/alloc.c */ #endif #include "permonst.h" #include "objclass.h" #include "monsym.h" #include "artilist.h" #include "dungeon.h" #include "obj.h" #include "monst.h" #include "you.h" #include "context.h" #include "flag.h" #include "dlb.h" /* version information */ #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #include #ifdef MAC #if defined(__SC__) || defined(__MRC__) /* MPW compilers */ #define MPWTOOL #include #include #else /* MAC without MPWTOOL */ #define MACsansMPWTOOL #endif #endif /* MAC */ #ifndef MPWTOOL #define SpinCursor(x) #endif #define Fprintf (void) fprintf #define Fclose (void) fclose #define Unlink (void) unlink #if !defined(AMIGA) || defined(AZTEC_C) #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */ #endif #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN) static const char SCCS_Id[] = "@(#)makedefs.c\t3.5\t2004/02/01"; #endif /* names of files to be generated */ #define DATE_FILE "date.h" #define MONST_FILE "pm.h" #define ONAME_FILE "onames.h" #ifndef OPTIONS_FILE #define OPTIONS_FILE "options" #endif #define ORACLE_FILE "oracles" #define DATA_FILE "data" #define RUMOR_FILE "rumors" #define DGN_I_FILE "dungeon.def" #define DGN_O_FILE "dungeon.pdf" #define MON_STR_C "monstr.c" #define QTXT_I_FILE "quest.txt" #define QTXT_O_FILE "quest.dat" #define VIS_TAB_H "vis_tab.h" #define VIS_TAB_C "vis_tab.c" /* locations for those files */ #ifdef AMIGA #define FILE_PREFIX #define INCLUDE_TEMPLATE "NH:include/t.%s" #define SOURCE_TEMPLATE "NH:src/%s" #define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */ #define DATA_TEMPLATE "NH:slib/%s" #define DATA_IN_TEMPLATE "NH:dat/%s" #else /* not AMIGA */ #if defined(MAC) && !defined(__MACH__) /* MacOS 9 or earlier */ #define INCLUDE_TEMPLATE ":include:%s" #define SOURCE_TEMPLATE ":src:%s" #define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ #if __SC__ || __MRC__ #define DATA_TEMPLATE ":Dungeon:%s" #else #define DATA_TEMPLATE ":lib:%s" #endif /* __SC__ || __MRC__ */ #define DATA_IN_TEMPLATE ":dat:%s" #else /* neither AMIGA nor MAC */ #ifdef OS2 #define INCLUDE_TEMPLATE "..\\include\\%s" #define SOURCE_TEMPLATE "..\\src\\%s" #define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */ #define DATA_TEMPLATE "..\\dat\\%s" #define DATA_IN_TEMPLATE "..\\dat\\%s" #else /* not AMIGA, MAC, or OS2 */ #define INCLUDE_TEMPLATE "../include/%s" #define SOURCE_TEMPLATE "../src/%s" #define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */ #define DATA_TEMPLATE "../dat/%s" #define DATA_IN_TEMPLATE "../dat/%s" #endif /* else !OS2 */ #endif /* else !MAC */ #endif /* else !AMIGA */ static const char *Dont_Edit_Code = "/* This source file is generated by 'makedefs'. Do not edit. */\n", *Dont_Edit_Data = "#\tThis data file is generated by 'makedefs'. Do not edit. \n"; static struct version_info version; /* definitions used for vision tables */ #define TEST_WIDTH COLNO #define TEST_HEIGHT ROWNO #define BLOCK_WIDTH (TEST_WIDTH + 10) #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */ #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT) #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH) /* Use this as an out-of-bound value in the close table. */ #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */ #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #ifdef VISION_TABLES static char xclear[MAX_ROW][MAX_COL]; #endif /*-end of vision defs-*/ static char filename[600]; #ifdef FILE_PREFIX /* if defined, a first argument not starting with - is * taken as a text string to be prepended to any * output filename generated */ char *file_prefix = ""; #endif #ifdef MACsansMPWTOOL int FDECL(main, (void)); #else int FDECL(main, (int, char **)); #endif void FDECL(do_makedefs, (char *)); void NDECL(do_objs); void NDECL(do_data); void NDECL(do_dungeon); void NDECL(do_date); void NDECL(do_options); void NDECL(do_monstr); void NDECL(do_permonst); void NDECL(do_questtxt); void NDECL(do_rumors); void NDECL(do_oracles); void NDECL(do_vision); extern void NDECL(monst_init); /* monst.c */ extern void NDECL(objects_init); /* objects.c */ static void NDECL(make_version); static char *FDECL(version_string, (char *, const char *)); static char *FDECL(version_id_string, (char *, const char *)); static char *FDECL(bannerc_string, (char *, const char *)); static char *FDECL(xcrypt, (const char *)); static unsigned long FDECL(read_rumors_file, (const char *, int *, long *, unsigned long)); static void FDECL(do_rnd_access_file, (const char *)); static boolean FDECL(d_filter, (char *)); static boolean FDECL(h_filter, (char *)); static boolean FDECL(ranged_attk, (struct permonst *)); static int FDECL(mstrength, (struct permonst *)); static void NDECL(build_savebones_compat_string); static void FDECL(do_ext_makedefs, (int, char **)); static void NDECL(windowing_sanity); static boolean FDECL(qt_comment, (char *)); static boolean FDECL(qt_control, (char *)); static int FDECL(get_hdr, (char *)); static boolean FDECL(new_id, (char *)); static boolean FDECL(known_msg, (int, int)); static void FDECL(new_msg, (char *, int, int)); static char *FDECL(valid_qt_summary, (char *, BOOLEAN_P)); static void FDECL(do_qt_control, (char *)); static void FDECL(do_qt_text, (char *)); static void NDECL(adjust_qt_hdrs); static void NDECL(put_qt_hdrs); #ifdef VISION_TABLES static void NDECL(H_close_gen); static void NDECL(H_far_gen); static void NDECL(C_close_gen); static void NDECL(C_far_gen); static int FDECL(clear_path, (int, int, int, int)); #endif static char *FDECL(fgetline, (FILE*)); static char *FDECL(tmpdup, (const char *)); static char *FDECL(limit, (char *, int)); static char *FDECL(eos, (char *)); /* input, output, tmp */ static FILE *ifp, *ofp, *tfp; #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif #ifdef MACsansMPWTOOL int main(void) { const char *def_options = "odemvpqrshz"; char buf[100]; int len; printf("Enter options to run: [%s] ", def_options); fflush(stdout); fgets(buf, 100, stdin); len = strlen(buf); if (len <= 1) Strcpy(buf, def_options); else buf[len - 1] = 0; /* remove return */ if (buf[0] == '-' && buf[1] == '-') { #if 0 split up buf into words do_ext_makedefs(fakeargc, fakeargv); #else printf("extended makedefs not implemented for Mac OS9\n"); exit(EXIT_FAILURE); #endif } do_makedefs(buf); exit(EXIT_SUCCESS); return 0; } #else /* ! MAC */ int main(argc, argv) int argc; char *argv[]; { if ((argc != 2) #ifdef FILE_PREFIX && (argc != 3) #endif && !(argv[1][0] == '-' && argv[1][1] == '-')) { Fprintf(stderr, "Bad arg count (%d).\n", argc - 1); (void) fflush(stderr); return 1; } #ifdef FILE_PREFIX if (argc >= 2 && argv[1][0] != '-') { file_prefix = argv[1]; argc--; argv++; } #endif if (argv[1][0] == '-' && argv[1][1] == '-') { do_ext_makedefs(argc, argv); } else { do_makedefs(&argv[1][1]); } exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif static void link_sanity_check() { /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); } void do_makedefs(options) char *options; { boolean more_than_one; link_sanity_check(); /* construct the current version number */ make_version(); more_than_one = strlen(options) > 1; while (*options) { if (more_than_one) Fprintf(stderr, "makedefs -%c\n", *options); switch (*options) { case 'o': case 'O': do_objs(); break; case 'd': case 'D': do_data(); break; case 'e': case 'E': do_dungeon(); break; case 'm': case 'M': do_monstr(); break; case 'v': case 'V': do_date(); do_options(); break; case 'p': case 'P': do_permonst(); break; case 'q': case 'Q': do_questtxt(); break; case 'r': case 'R': do_rumors(); break; case 's': case 'S': do_rnd_access_file(EPITAPHFILE); do_rnd_access_file(ENGRAVEFILE); do_rnd_access_file(BOGUSMONFILE); break; case 'h': case 'H': do_oracles(); break; case 'z': case 'Z': do_vision(); break; default: Fprintf(stderr, "Unknown option '%c'.\n", *options); (void) fflush(stderr); exit(EXIT_FAILURE); } options++; } if (more_than_one) Fprintf(stderr, "Completed.\n"); /* feedback */ } static char namebuf[1000]; static char * name_file(template, tag) char *template; char *tag; { Sprintf(namebuf, template, tag); return namebuf; } static void delete_file(template, tag) char *template; char *tag; { char *name = name_file(template, tag); Unlink(name); } static FILE * getfp(template, tag, mode) char *template; char *tag; char *mode; { char *name = name_file(template, tag); FILE *rv = fopen(name, mode); if (!rv) { Fprintf(stderr, "Can't open '%s'.\n", name); exit(EXIT_FAILURE); } return rv; } static boolean debug = FALSE; static FILE *inputfp; static FILE *outputfp; struct grep_var { const char *name; int is_defined; /* 0 undef; 1 defined */ }; /* struct grep_var grep_vars[] and TODO_* constants in include file: */ #include "mdgrep.h" static void NDECL(do_grep); static void NDECL(do_grep_showvars); static struct grep_var *FDECL(grepsearch, (char *)); static int grep_trace = 0; static void do_ext_makedefs(int argc, char **argv) { int todo = 0; link_sanity_check(); argc--; argv++; /* skip program name */ while (argc) { if (argv[0][0] != '-') break; if (argv[0][1] != '-') { Fprintf(stderr, "Can't mix - and -- options.\n"); exit(EXIT_FAILURE); } #define IS_OPTION(str) if (!strcmp(&argv[0][2], str)) #define CONTINUE \ argv++, argc--; \ continue #define CONSUME \ argv++, argc--; \ if (argc == 0) { \ Fprintf(stderr, "missing option\n"); \ exit(EXIT_FAILURE); \ } IS_OPTION("svs") { /* short version string for packaging - note * no \n */ char buf[100]; char delim[10]; argv++; /* not CONSUME */ delim[0] = '\0'; if (argv[0]) strcpy(delim, argv[0]); Fprintf(stdout, "%s", version_string(buf, delim)); exit(EXIT_SUCCESS); } IS_OPTION("debug") { debug = TRUE; CONTINUE; } IS_OPTION("make") { CONSUME; do_makedefs(argv[0]); exit(EXIT_SUCCESS); } IS_OPTION("input") { CONSUME; if (!strcmp(argv[0], "-")) { inputfp = stdin; } else { inputfp = fopen(argv[0], RDTMODE); if (!inputfp) { Fprintf(stderr, "Can't open '%s'.\n", argv[0]); exit(EXIT_FAILURE); } } CONTINUE; } IS_OPTION("output") { CONSUME; if (!strcmp(argv[0], "-")) { outputfp = stdout; } else { outputfp = fopen(argv[0], WRTMODE); if (!outputfp) { Fprintf(stderr, "Can't open '%s'.\n", argv[0]); exit(EXIT_FAILURE); } } CONTINUE; } IS_OPTION("grep") { if (todo) { Fprintf(stderr, "Can't do grep and something else.\n"); exit(EXIT_FAILURE); } todo = TODO_GREP; CONTINUE; } IS_OPTION("grep-showvars") { do_grep_showvars(); exit(EXIT_SUCCESS); } IS_OPTION("grep-trace") { grep_trace = 1; CONTINUE; } IS_OPTION("grep-define") { struct grep_var *p; CONSUME; p = grepsearch(argv[0]); if (p) { p->is_defined = 1; } else { Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]); exit(EXIT_FAILURE); } CONTINUE; } IS_OPTION("grep-undef") { struct grep_var *p; CONSUME; p = grepsearch(argv[0]); if (p) { p->is_defined = 0; } else { Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]); exit(EXIT_FAILURE); } CONTINUE; } #ifdef notyet IS_OPTION("help") { } #endif #undef IS_OPTION Fprintf(stderr, "Unknown option '%s'.\n", argv[0]); exit(EXIT_FAILURE); } if (argc) { Fprintf(stderr, "unexpected argument '%s'.\n", argv[0]); exit(EXIT_FAILURE); } switch (todo) { default: Fprintf(stderr, "Confused about what to do?\n"); exit(EXIT_FAILURE); case 0: Fprintf(stderr, "Nothing to do?\n"); exit(EXIT_FAILURE); case TODO_GREP: do_grep(); break; } } /* Filtering syntax: Any line NOT starting with a caret is either suppressed or passed through unchanged depending on the current conditional state. The default conditional state is printing on. Conditionals may be nested. makedefs will exit with a EXIT_FAILURE if any errors are detected; as many errors as possible are detected before giving up. Unknown identifiers are treated as TRUE and also as an error to allow processing to continue past the unknown identifier (note that "#undef" is different than unknown). Any line starting with a caret is a control line; as in C, zero or more spaces may be embedded in the line almost anywhere; the caret MUST be in column 1. (XXX for the moment, no white space is allowed after the caret because existing lines in the docs look like that) Control lines: ^^ a line starting with a (single) literal caret ^# a comment - the line is ignored ^?ID if defined(ID) ^!ID if !defined(ID) ^: else ^. endif */ #define GREP_MAGIC '^' #define GREP_STACK_SIZE 100 #ifdef notyet static int grep_rewrite = 0; /* need to (possibly) rewrite lines */ #endif static int grep_writing = 1; /* need to copy lines to output */ static int grep_errors = 0; static int grep_sp = 0; #define ST_LD(old, opp) (!!(old) | (!!(opp) << 1)) #define ST_OLD(v) ((v) &1) #define ST_OPP(v) !!((v) &2) #define ST_ELSE 4 static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) }; static int grep_lineno = 0; static void do_grep_showvars() { int x; for (x = 0; x < SIZE(grep_vars) - 1; x++) { printf("%d\t%s\n", grep_vars[x].is_defined, grep_vars[x].name); } } static struct grep_var * grepsearch(name) char *name; { /* XXX make into binary search */ int x = 0; while (x < SIZE(grep_vars) - 1) { if (!strcmp(grep_vars[x].name, name)) return &grep_vars[x]; x++; } return 0; } static int grep_check_id(id) char *id; { struct grep_var *rv; while (*id && isspace(*id)) id++; if (!*id) { Fprintf(stderr, "missing identifier in line %d", grep_lineno); grep_errors++; return 0; } rv = grepsearch(id); if (rv) { if (grep_trace) { Fprintf(outputfp, "ID %d %s\n", rv->is_defined, id); } return rv->is_defined; } if (grep_trace) { Fprintf(outputfp, "ID U %s\n", id); } Fprintf(stderr, "unknown identifier '%s' in line %d.\n", id, grep_lineno); grep_errors++; return 2; /* So new features can be checked before makedefs * is rebuilt. */ } static void grep_show_wstack(tag) char *tag; { int x; if (!grep_trace) return; Fprintf(outputfp, "%s w=%d sp=%d\t", tag, grep_writing, grep_sp); for (x = grep_sp; x >= 0 && x > grep_sp - 6; x--) { Fprintf(outputfp, "[%d]=%d ", x, grep_stack[x]); } Fprintf(outputfp, "\n"); } static char * do_grep_control(buf) char *buf; { int isif = 1; char *buf0 = buf; #if 1 if (isspace(buf[0])) return &buf[-1]; /* XXX see docs above */ #else while (buf[0] && isspace(buf[0])) buf++; #endif switch (buf[0]) { case '#': /* comment */ break; case '.': /* end of if level */ if (grep_sp == 0) { Fprintf(stderr, "unmatched ^. (endif) at line %d.\n", grep_lineno); grep_errors++; } else { grep_writing = ST_OLD(grep_stack[grep_sp--]); grep_show_wstack("pop"); } break; case '!': /* if not ID */ isif = 0; /* FALLTHROUGH */ case '?': /* if ID */ if (grep_sp == GREP_STACK_SIZE - 2) { Fprintf(stderr, "stack overflow at line %d.", grep_lineno); exit(EXIT_FAILURE); } if (grep_writing) { isif = grep_check_id(&buf[1]) ? isif : !isif; grep_stack[++grep_sp] = ST_LD(grep_writing, !isif); grep_writing = isif; } else { grep_stack[++grep_sp] = ST_LD(0, 0); /* grep_writing = 0; */ } grep_show_wstack("push"); break; case ':': /* else */ if (ST_ELSE & grep_stack[grep_sp]) { Fprintf(stderr, "multiple : for same conditional at line %d.\n", grep_lineno); grep_errors++; } grep_writing = ST_OPP(grep_stack[grep_sp]); grep_stack[grep_sp] |= ST_ELSE; break; #if defined(notyet) case '(': /* start of expression */ #endif case GREP_MAGIC: /* ^^ -> ^ */ return buf0; default: { char str[10]; if (isprint(buf[0])) { str[0] = buf[0]; str[1] = '\0'; } else { sprintf(str, "0x%02x", buf[0]); } Fprintf(stderr, "unknown control ^%s at line %d.\n", str, grep_lineno); grep_errors++; } break; } return NULL; } #ifdef notyet static void do_grep_rewrite(buf) char *buf; { /* no language features use this yet */ return; } #endif static void grep0(FILE *, FILE *); static void do_grep() { if (!inputfp) { Fprintf(stderr, "--grep requires --input\n"); } if (!outputfp) { Fprintf(stderr, "--grep requires --output\n"); } if (!inputfp || !outputfp) { exit(EXIT_FAILURE); } grep0(inputfp, outputfp); } static void grep0(inputfp0, outputfp0) FILE *inputfp0; FILE *outputfp0; { char buf[16384]; /* looong, just in case */ while (!feof(inputfp0) && !ferror(inputfp0)) { char *tmp; char *buf1; if (fgets(buf, sizeof(buf), inputfp0) == 0) break; if ((tmp = strchr(buf, '\n'))) *tmp = '\0'; grep_lineno++; if (grep_trace) { Fprintf(outputfp0, "%04d %c >%s\n", grep_lineno, grep_writing ? ' ' : '#', buf); } if (buf[0] == GREP_MAGIC) { buf1 = do_grep_control(&buf[1]); if (!buf1) continue; } else { buf1 = buf; } #ifdef notyet if (grep_rewrite) do_grep_rewrite(buf1); #endif if (grep_writing) Fprintf(outputfp0, "%s\n", buf1); } if (ferror(inputfp0)) { Fprintf(stderr, "read error!\n"); exit(EXIT_FAILURE); } if (ferror(outputfp0)) { Fprintf(stderr, "write error!\n"); exit(EXIT_FAILURE); } fclose(inputfp0); fclose(outputfp0); if (grep_sp) { Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp, grep_sp == 1 ? "" : "s"); grep_errors++; } if (grep_errors) { Fprintf(stderr, "%d error%s detected.\n", grep_errors, grep_errors == 1 ? "" : "s"); exit(EXIT_FAILURE); } } /* trivial text encryption routine which can't be broken with `tr' */ static char * xcrypt(str) const char *str; { /* duplicated in src/hacklib.c */ static char buf[BUFSZ]; register const char *p; register char *q; register int bitmask; for (bitmask = 1, p = str, q = buf; *p; q++) { *q = *p++; if (*q & (32 | 64)) *q ^= bitmask; if ((bitmask <<= 1) >= 32) bitmask = 1; } *q = '\0'; return buf; } #define PAD_RUMORS_TO 60 /* common code for do_rumors(). Return 0 on error. */ static unsigned long read_rumors_file(file_ext, rumor_count, rumor_size, old_rumor_offset) const char *file_ext; int *rumor_count; long *rumor_size; unsigned long old_rumor_offset; { char infile[600]; char *line; unsigned long rumor_offset; Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, file_ext); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); return 0L; } /* copy the rumors */ while ((line = fgetline(ifp)) != 0) { #ifdef PAD_RUMORS_TO /* rumor selection is accomplished by seeking to a random position in the file, advancing to newline, and taking the next line; therefore, rumors which follow long-line rumors are most likely to be chosen and rumors which follow short-line rumors are least likely to be chosen; we ameliorate the latter by padding the shortest lines, increasing the chance of the random seek landing in them */ int len = (int) strlen(line); if (len <= PAD_RUMORS_TO) { char *base = index(line, '\n'); /* this is only safe because fgetline() overallocates */ while (len++ < PAD_RUMORS_TO) { *base++ = '_'; } *base++ = '\n'; *base = '\0'; } #endif (*rumor_count)++; #if 0 /*[if we forced binary output, this would be sufficient]*/ *rumor_size += strlen(line); /* includes newline */ #endif (void) fputs(xcrypt(line), tfp); free(line); } /* record the current position; next rumors section will start here */ rumor_offset = (unsigned long) ftell(tfp); Fclose(ifp); /* all done with rumors.file_ext */ /* the calculated value for *_rumor_count assumes that a single-byte line terminator is in use; for platforms which use two byte CR+LF, we need to override that value [it's much simpler to do so unconditionally, rendering the loop's accumulation above obsolete] */ *rumor_size = (long) (rumor_offset - old_rumor_offset); return rumor_offset; } void do_rnd_access_file(fname) const char *fname; { char *line; Sprintf(filename, DATA_IN_TEMPLATE, fname); Strcat(filename, ".txt"); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, fname); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Data); tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); grep0(ifp, tfp); ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); while ((line = fgetline(ifp)) != 0) { if (line[0] != '#' && line[0] != '\n') (void) fputs(xcrypt(line), ofp); free(line); } Fclose(ifp); Fclose(ofp); delete_file(DATA_TEMPLATE, "grep.tmp"); return; } void do_rumors() { char *line; static const char rumors_header[] = "%s%04d,%06ld,%06lx;%04d,%06ld,%06lx;0,0,%06lx\n"; char tempfile[600]; int true_rumor_count, false_rumor_count; long true_rumor_size, false_rumor_size; unsigned long true_rumor_offset, false_rumor_offset, eof_offset; Sprintf(tempfile, DATA_TEMPLATE, "rumors.tmp"); filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { perror(tempfile); Fclose(ofp); exit(EXIT_FAILURE); } true_rumor_count = false_rumor_count = 0; true_rumor_size = false_rumor_size = 0L; true_rumor_offset = false_rumor_offset = eof_offset = 0L; /* output a dummy header record; we'll replace it in final output */ Fprintf(tfp, rumors_header, Dont_Edit_Data, true_rumor_count, true_rumor_size, true_rumor_offset, false_rumor_count, false_rumor_size, false_rumor_offset, eof_offset); /* record the current position; true rumors will start here */ true_rumor_offset = ftell(tfp); false_rumor_offset = read_rumors_file( ".tru", &true_rumor_count, &true_rumor_size, true_rumor_offset); if (!false_rumor_offset) goto rumors_failure; eof_offset = read_rumors_file(".fal", &false_rumor_count, &false_rumor_size, false_rumor_offset); if (!eof_offset) goto rumors_failure; /* get ready to transfer the contents of temp file to output file */ line = malloc(256); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) { perror(line); free(line); goto rumors_failure; } free(line); /* output the header record */ Fprintf(ofp, rumors_header, Dont_Edit_Data, true_rumor_count, true_rumor_size, true_rumor_offset, false_rumor_count, false_rumor_size, false_rumor_offset, eof_offset); /* skip the temp file's dummy header */ if (!(line = fgetline(tfp))) { /* "Don't Edit" */ perror(tempfile); goto rumors_failure; } free(line); if (!(line = fgetline(tfp))) { /* count,size,offset */ perror(tempfile); goto rumors_failure; } free(line); /* copy the rest of the temp file into the final output file */ while ((line = fgetline(tfp)) != 0) { (void) fputs(line, ofp); free(line); } /* all done; delete temp file */ Fclose(tfp); Unlink(tempfile); Fclose(ofp); return; rumors_failure: Fclose(ofp); Unlink(filename); /* kill empty or incomplete output file */ Fclose(tfp); Unlink(tempfile); /* and temporary file */ exit(EXIT_FAILURE); } /* * Use this to explicitly mask out features during version checks. * * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features * that the port/plaform which wrote the savefile was capable of * dealing with. Don't reject a savefile just because the port * reading the savefile doesn't match on all/some of them. * The actual compression features used to produce the savefile are * recorded in the savefile_info structure immediately following the * version_info, and that is what needs to be checked against the * feature set of the port that is reading the savefile back in. * That check is done in src/restore.c now. * */ #define IGNORED_FEATURES \ (0L | (1L << 19) /* SCORE_ON_BOTL */ \ | (1L << 27) /* ZEROCOMP */ \ | (1L << 28) /* RLECOMP */ \ ) static void make_version() { register int i; /* * integer version number */ version.incarnation = ((unsigned long) VERSION_MAJOR << 24) | ((unsigned long) VERSION_MINOR << 16) | ((unsigned long) PATCHLEVEL << 8) | ((unsigned long) EDITLEVEL); /* * encoded feature list * Note: if any of these magic numbers are changed or reassigned, * EDITLEVEL in patchlevel.h should be incremented at the same time. * The actual values have no special meaning, and the category * groupings are just for convenience. */ version.feature_set = (unsigned long) (0L /* levels and/or topology (0..4) */ /* monsters (5..9) */ #ifdef MAIL | (1L << 6) #endif /* objects (10..14) */ /* flag bits and/or other global variables (15..26) */ #ifdef TEXTCOLOR | (1L << 17) #endif #ifdef INSURANCE | (1L << 18) #endif #ifdef SCORE_ON_BOTL | (1L << 19) #endif /* data format (27..31) * External compression methods such as COMPRESS and ZLIB_COMP * do not affect the contents and are thus excluded from here */ #ifdef ZEROCOMP | (1L << 27) #endif #ifdef RLECOMP | (1L << 28) #endif ); /* * Value used for object & monster sanity check. * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0) */ for (i = 1; artifact_names[i]; i++) continue; version.entity_count = (unsigned long) (i - 1); for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) continue; version.entity_count = (version.entity_count << 12) | (unsigned long) i; for (i = 0; mons[i].mlet; i++) continue; version.entity_count = (version.entity_count << 12) | (unsigned long) i; /* * Value used for compiler (word size/field alignment/padding) check. */ version.struct_sizes1 = (((unsigned long) sizeof(struct context_info) << 24) | ((unsigned long) sizeof(struct obj) << 17) | ((unsigned long) sizeof(struct monst) << 10) | ((unsigned long) sizeof(struct you))); version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10) | /* free bits in here */ #ifdef SYSFLAGS ((unsigned long) sizeof(struct sysflag))); #else ((unsigned long) 0L)); #endif return; } static char * version_string(outbuf, delim) char *outbuf; const char *delim; { Sprintf(outbuf, "%d%s%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR, delim, PATCHLEVEL); #ifdef BETA Sprintf(eos(outbuf), "-%d", EDITLEVEL); #endif return outbuf; } static char * version_id_string(outbuf, build_date) char *outbuf; const char *build_date; { char subbuf[64], versbuf[64]; subbuf[0] = '\0'; #ifdef PORT_SUB_ID subbuf[0] = ' '; Strcpy(&subbuf[1], PORT_SUB_ID); #endif #ifdef BETA Strcat(subbuf, " Beta"); #endif Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.", PORT_ID, subbuf, version_string(versbuf, "."), build_date); return outbuf; } static char * bannerc_string(outbuf, build_date) char *outbuf; const char *build_date; { char subbuf[64], versbuf[64]; subbuf[0] = '\0'; #ifdef PORT_SUB_ID subbuf[0] = ' '; Strcpy(&subbuf[1], PORT_SUB_ID); #endif #ifdef BETA Strcat(subbuf, " Beta"); #endif Sprintf(outbuf, " Version %s %s%s, built %s.", version_string(versbuf, "."), PORT_ID, subbuf, &build_date[4]); #if 0 Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)", PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR, &build_date[4]); #endif return outbuf; } void do_date() { #ifdef KR1ED long clocktim = 0; #else time_t clocktim = 0; #endif char *c, cbuf[60], buf[BUFSZ]; const char *ul_sfx; /* before creating date.h, make sure that xxx_GRAPHICS and DEFAULT_WINDOW_SYS have been set up in a viable fashion */ windowing_sanity(); filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } /* NB: We've moved on from SCCS, but this way this line * won't get clobbered when downstream projects import * this file into something more modern. */ Fprintf(ofp, "%s", Dont_Edit_Code); (void) time(&clocktim); Strcpy(cbuf, ctime(&clocktim)); for (c = cbuf; *c; c++) if (*c == '\n') break; *c = '\0'; /* strip off the '\n' */ Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf); Fprintf(ofp, "#define BUILD_TIME (%ldL)\n", (long) clocktim); Fprintf(ofp, "\n"); #ifdef NHSTDC ul_sfx = "UL"; #else ul_sfx = "L"; #endif Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation, ul_sfx); Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set, ul_sfx); #ifdef IGNORED_FEATURES Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n", (unsigned long) IGNORED_FEATURES, ul_sfx); #endif Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count, ul_sfx); Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1, ul_sfx); Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2, ul_sfx); Fprintf(ofp, "\n"); Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", version_string(buf, ".")); Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n", version_id_string(buf, cbuf)); Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n", bannerc_string(buf, cbuf)); Fprintf(ofp, "\n"); #ifdef AMIGA { struct tm *tm = localtime((time_t *) &clocktim); Fprintf(ofp, "#define AMIGA_VERSION_STRING "); Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900); } #endif Fclose(ofp); return; } static char save_bones_compat_buf[BUFSZ]; static void build_savebones_compat_string() { #ifdef VERSION_COMPATIBILITY unsigned long uver = VERSION_COMPATIBILITY; #endif Strcpy(save_bones_compat_buf, "save and bones files accepted from version"); #ifdef VERSION_COMPATIBILITY Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d", ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16), ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #else Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #endif } static const char *build_opts[] = { #ifdef AMIGA_WBENCH "Amiga WorkBench support", #endif #ifdef ANSI_DEFAULT "ANSI default terminal", #endif #ifdef TEXTCOLOR "color", #endif #ifdef COM_COMPL "command line completion", #endif #ifdef LIFE "Conway's Game of Life", #endif #ifdef COMPRESS "data file compression", #endif #ifdef ZLIB_COMP "ZLIB data file compression", #endif #ifdef DLB "data librarian", #endif #ifdef MFLOPPY "floppy drive support", #endif #ifdef INSURANCE "insurance files for recovering from crashes", #endif #ifdef HOLD_LOCKFILE_OPEN "exclusive lock on level 0 file", #endif #ifdef LOGFILE "log file", #endif #ifdef MAIL "mail daemon", #endif #ifdef GNUDOS "MSDOS protected mode", #endif #ifdef NEWS "news file", #endif #ifdef OVERLAY #ifdef MOVERLAY "MOVE overlays", #else #ifdef VROOMM "VROOMM overlays", #else "overlays", #endif #endif #endif #ifdef SELECTSAVED "restore saved games via menu", #endif #ifdef SCORE_ON_BOTL "score on status line", #endif #ifdef CLIPPING "screen clipping", #endif #ifdef NO_TERMS #ifdef MAC "screen control via mactty", #endif #ifdef SCREEN_BIOS "screen control via BIOS", #endif #ifdef SCREEN_DJGPPFAST "screen control via DJGPP fast", #endif #ifdef SCREEN_VGA "screen control via VGA graphics", #endif #ifdef WIN32CON "screen control via WIN32 console I/O", #endif #endif #ifdef SHELL "shell command", #endif #ifdef SUSPEND "suspend command", #endif #ifdef TERMINFO "terminal info library", #else #if defined(TERMLIB) \ || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS)) "terminal capability library", #endif #endif #ifdef TIMED_DELAY "timed wait for display effects", #endif #ifdef USER_SOUNDS "user sounds", #endif #ifdef PREFIXES_IN_USE "variable playground", #endif #ifdef VISION_TABLES "vision tables", #endif #ifdef ZEROCOMP "zero-compressed save files", #endif #ifdef RLECOMP "run-length compression of map in save files", #endif #ifdef SYSCF "system configuration at run-time", #endif save_bones_compat_buf, "and basic NetHack features" }; struct win_info { const char *id, /* DEFAULT_WINDOW_SYS string */ *name; /* description, often same as id */ }; static struct win_info window_opts[] = { #ifdef TTY_GRAPHICS { "tty", "traditional tty-based graphics" }, #endif #ifdef X11_GRAPHICS { "X11", "X11" }, #endif #ifdef QT_GRAPHICS { "Qt", "Qt" }, #endif #ifdef GNOME_GRAPHICS { "Gnome", "Gnome" }, #endif #ifdef MAC { "mac", "Mac" }, #endif #ifdef AMIGA_INTUITION { "amii", "Amiga Intuition" }, #endif #ifdef GEM_GRAPHICS { "Gem", "Gem" }, #endif #ifdef MSWIN_GRAPHICS { "mswin", "mswin" }, #endif #ifdef BEOS_GRAPHICS { "BeOS", "BeOS InterfaceKit" }, #endif { 0, 0 } }; static void windowing_sanity() { #ifndef DEFAULT_WINDOW_SYS /* pre-standard compilers didn't support #error; wait til run-time */ Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n"); exit(EXIT_FAILURE); /*NOTREACHED*/ /* put in a dummy value so that do_options() will compile and makedefs will build, otherwise the message above won't ever get delivered */ #define DEFAULT_WINDOW_SYS "" #else /*DEFAULT_WINDOW_SYS*/ if (!window_opts[0].id) { Fprintf(stderr, "Configuration error: no windowing systems " "(TTY_GRAPHICS, &c) enabled.\n"); exit(EXIT_FAILURE); } { int i; for (i = 0; window_opts[i].id; ++i) if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS)) break; if (!window_opts[i] .id) { /* went through whole list without a match */ Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n", DEFAULT_WINDOW_SYS); Fprintf(stderr, " does not match any enabled windowing system (%s%s).\n", window_opts[0].id, window_opts[1].id ? ", &c" : ""); exit(EXIT_FAILURE); } } #endif /*DEFAULT_WINDOW_SYS*/ } void do_options() { static const char indent[] = " "; const char *str, *sep; char *word, buf[BUFSZ]; int i, length, winsyscnt; windowing_sanity(); filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } build_savebones_compat_string(); Fprintf(ofp, #ifdef BETA "\n NetHack version %d.%d.%d [beta]\n", #else "\n NetHack version %d.%d.%d\n", #endif VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); Fprintf(ofp, "\nOptions compiled into this edition:\n"); length = COLNO + 1; /* force 1st item onto new line */ for (i = 0; i < SIZE(build_opts); i++) { str = strcpy(buf, build_opts[i]); while (*str) { word = index(str, ' '); if (word) *word = '\0'; if (length + strlen(str) > COLNO - 5) Fprintf(ofp, "\n%s", indent), length = strlen(indent); else Fprintf(ofp, " "), length++; Fprintf(ofp, "%s", str), length += strlen(str); str += strlen(str) + (word ? 1 : 0); } Fprintf(ofp, (i < SIZE(build_opts) - 1) ? "," : "."), length++; } winsyscnt = SIZE(window_opts) - 1; Fprintf(ofp, "\n\nSupported windowing system%s:\n", (winsyscnt > 1) ? "s" : ""); length = COLNO + 1; /* force 1st item onto new line */ for (i = 0; i < winsyscnt; i++) { str = window_opts[i].name; if (length + strlen(str) > COLNO - 5) Fprintf(ofp, "\n%s", indent), length = strlen(indent); else Fprintf(ofp, " "), length++; Fprintf(ofp, "%s", str), length += strlen(str); sep = (winsyscnt == 1) ? "." : (winsyscnt == 2) ? ((i == 0) ? " and" : "") : (i < winsyscnt - 2) ? "," : ((i == winsyscnt - 2) ? ", and" : ""); Fprintf(ofp, "%s", sep), length += strlen(sep); } if (winsyscnt > 1) Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS); Fprintf(ofp, "\n\n"); Fclose(ofp); return; } /* routine to decide whether to discard something from data.base */ static boolean d_filter(line) char *line; { if (*line == '#') return TRUE; /* ignore comment lines */ return FALSE; } /* * New format (v3.1) of 'data' file which allows much faster lookups [pr] "do not edit" first record is a comment line 01234567 hexadecimal formatted offset to text area name-a first name of interest 123,4 offset to name's text, and number of lines for it name-b next name of interest name-c multiple names which share same description also 456,7 share a single offset,count line . sentinel to mark end of names 789,0 dummy record containing offset, count of EOF text-a 4 lines of descriptive text for name-a text-a at file position 0x01234567L + 123L text-a text-a text-b/text-c 7 lines of text for names-b and -c text-b/text-c at fseek(0x01234567L + 456L) ... * */ void do_data() { char infile[60], tempfile[60]; boolean ok; long txt_offset; int entry_cnt, line_cnt; char *line; Sprintf(tempfile, DATA_TEMPLATE, "database.tmp"); filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE); Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE); #ifdef SHORT_FILENAMES Strcat(infile, ".bas"); #else Strcat(infile, ".base"); #endif if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */ perror(infile); exit(EXIT_FAILURE); } if (!(ofp = fopen(filename, WRTMODE))) { /* data */ perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* output a dummy header record; we'll rewind and overwrite it later */ Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L); entry_cnt = line_cnt = 0; /* read through the input file and split it into two sections */ while ((line = fgetline(ifp)) != 0) { if (d_filter(line)) { free(line); continue; } if (*line > ' ') { /* got an entry name */ /* first finish previous entry */ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0; /* output the entry name */ (void) fputs(line, ofp); entry_cnt++; /* update number of entries */ } else if (entry_cnt) { /* got some descriptive text */ /* update previous entry with current text offset */ if (!line_cnt) Fprintf(ofp, "%ld,", ftell(tfp)); /* save the text line in the scratch file */ (void) fputs(line, tfp); line_cnt++; /* update line counter */ } free(line); } /* output an end marker and then record the current position */ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt); Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0); txt_offset = ftell(ofp); Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ line = malloc(256); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; free(line); /* copy all lines of text from the scratch file into the output file */ while ((line = fgetline(tfp)) != 0) { (void) fputs(line, ofp); free(line); } /* finished with scratch file */ Fclose(tfp); Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ line = malloc(256); Sprintf(line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { Sprintf(line, "header rewrite of \"%s\"", filename); ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, (unsigned long) txt_offset) >= 0); } if (!ok) { dead_data: perror(line); /* report the problem */ free(line); /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } free(line); /* all done */ Fclose(ofp); return; } /* routine to decide whether to discard something from oracles.txt */ static boolean h_filter(line) char *line; { static boolean skip = FALSE; char *tag; SpinCursor(3); if (*line == '#') return TRUE; /* ignore comment lines */ tag = malloc(strlen(line)); if (sscanf(line, "----- %s", tag) == 1) { skip = FALSE; } else if (skip && !strncmp(line, "-----", 5)) skip = FALSE; free(tag); return skip; } static const char *special_oracle[] = { "\"...it is rather disconcerting to be confronted with the", "following theorem from [Baker, Gill, and Solovay, 1975].", "", "Theorem 7.18 There exist recursive languages A and B such that", " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "", "This provides impressive evidence that the techniques that are", "currently available will not suffice for proving that P != NP or " " ", "that P == NP.\" [Garey and Johnson, p. 185.]" }; /* The oracle file consists of a "do not edit" comment, a decimal count N and set of N+1 hexadecimal fseek offsets, followed by N multiple-line records, separated by "---" lines. The first oracle is a special case. The input data contains just those multi-line records, separated by "-----" lines. */ void do_oracles() { char infile[60], tempfile[60]; boolean in_oracle, ok; long fpos; unsigned long txt_offset, offset; int oracle_cnt; register int i; char *line; Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp"); filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE); Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE); Strcat(infile, ".txt"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); exit(EXIT_FAILURE); } if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* output a dummy header record; we'll rewind and overwrite it later */ Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0); /* handle special oracle; it must come first */ (void) fputs("---\n", tfp); offset = (unsigned long) ftell(tfp); Fprintf(ofp, "%05lx\n", offset); /* start pos of special oracle */ for (i = 0; i < SIZE(special_oracle); i++) { (void) fputs(xcrypt(special_oracle[i]), tfp); (void) fputc('\n', tfp); } SpinCursor(3); oracle_cnt = 1; (void) fputs("---\n", tfp); offset = (unsigned long) ftell(tfp); Fprintf(ofp, "%05lx\n", offset); /* start pos of first oracle */ in_oracle = FALSE; while ((line = fgetline(ifp)) != 0) { SpinCursor(3); if (h_filter(line)) { free(line); continue; } if (!strncmp(line, "-----", 5)) { if (!in_oracle) { free(line); continue; } in_oracle = FALSE; oracle_cnt++; (void) fputs("---\n", tfp); offset = (unsigned long) ftell(tfp); Fprintf(ofp, "%05lx\n", offset); /* start pos of this oracle */ } else { in_oracle = TRUE; (void) fputs(xcrypt(line), tfp); } free(line); } if (in_oracle) { /* need to terminate last oracle */ oracle_cnt++; (void) fputs("---\n", tfp); offset = (unsigned long) ftell(tfp); Fprintf(ofp, "%05lx\n", offset); /* eof position */ } /* record the current position */ txt_offset = (unsigned long) ftell(ofp); Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ line = malloc(256); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; free(line); /* copy all lines of text from the scratch file into the output file */ while ((line = fgetline(tfp)) != 0) { (void) fputs(line, ofp); free(line); } /* finished with scratch file */ Fclose(tfp); Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ line = malloc(256); Sprintf(line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { Sprintf(line, "header rewrite of \"%s\"", filename); ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >= 0); } if (ok) { Sprintf(line, "data rewrite of \"%s\"", filename); for (i = 0; i <= oracle_cnt; i++) { #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */ if (!(ok = (fflush(ofp) == 0))) break; #endif if (!(ok = (fpos = ftell(ofp)) >= 0)) break; if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break; if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break; #ifdef MAC #ifdef __MWERKS__ /* MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL (ANSI C Libraries) needs this rewind or else the fprintf stops working. This may also be true for CW11, but has never been checked. */ rewind(ofp); #endif #endif if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break; offset += txt_offset; if (!(ok = (fprintf(ofp, "%05lx\n", offset) >= 0))) break; } } if (!ok) { dead_data: perror(line); /* report the problem */ free(line); /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } free(line); /* all done */ Fclose(ofp); return; } void do_dungeon() { int rcnt = 0; char *line; Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Data); tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); grep0(ifp, tfp); ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); while ((line = fgetline(ifp)) != 0) { SpinCursor(3); rcnt++; if (line[0] == '#') { free(line); continue; /* discard comments */ } (void) fputs(line, ofp); free(line); } Fclose(ifp); Fclose(ofp); delete_file(DATA_TEMPLATE, "grep.tmp"); return; } static boolean ranged_attk(ptr) /* returns TRUE if monster can attack at range */ register struct permonst *ptr; { register int i, j; register int atk_mask = (1 << AT_BREA) | (1 << AT_SPIT) | (1 << AT_GAZE); for (i = 0; i < NATTK; i++) { if ((j = ptr->mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1 << j))) return TRUE; } return FALSE; } /* This routine is designed to return an integer value which represents * an approximation of monster strength. It uses a similar method of * determination as "experience()" to arrive at the strength. */ static int mstrength(ptr) struct permonst *ptr; { int i, tmp2, n, tmp = ptr->mlevel; if (tmp > 49) /* special fixed hp monster */ tmp = 2 * (tmp - 6) / 4; /* For creation in groups */ n = (!!(ptr->geno & G_SGROUP)); n += (!!(ptr->geno & G_LGROUP)) << 1; /* For ranged attacks */ if (ranged_attk(ptr)) n++; /* For higher ac values */ n += (ptr->ac < 4); n += (ptr->ac < 0); /* For very fast monsters */ n += (ptr->mmove >= 18); /* For each attack and "special" attack */ for (i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].aatyp; n += (tmp2 > 0); n += (tmp2 == AT_MAGC); n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG)); } /* For each "special" damage type */ for (i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].adtyp; if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST) || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE)) n += 2; else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS); n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23); } /* Leprechauns are special cases. They have many hit dice so they can hit and are hard to kill, but they don't really do much damage. */ if (!strcmp(ptr->mname, "leprechaun")) n -= 2; /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */ if (n == 0) tmp--; else if (n >= 6) tmp += (n / 2); else tmp += (n / 3 + 1); return (tmp >= 0) ? tmp : 0; } void do_monstr() { register struct permonst *ptr; register int i, j; /* * create the source file, "monstr.c" */ filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Code); Fprintf(ofp, "#include \"config.h\"\n"); Fprintf(ofp, "\nconst int monstr[] = {\n"); for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) { SpinCursor(3); i = mstrength(ptr); Fprintf(ofp, "%2d,%c", i, (++j & 15) ? ' ' : '\n'); } /* might want to insert a final 0 entry here instead of just newline */ Fprintf(ofp, "%s};\n", (j & 15) ? "\n" : ""); Fprintf(ofp, "\nvoid NDECL(monstr_init);\n"); Fprintf(ofp, "\nvoid\n"); Fprintf(ofp, "monstr_init()\n"); Fprintf(ofp, "{\n"); Fprintf(ofp, " return;\n"); Fprintf(ofp, "}\n"); Fprintf(ofp, "\n/*monstr.c*/\n"); Fclose(ofp); return; } void do_permonst() { int i; char *c, *nam; filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Code); Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n"); if (strcmp(mons[0].mname, "playermon") != 0) Fprintf(ofp, "\n#define\tPM_PLAYERMON\t(-1)"); for (i = 0; mons[i].mlet; i++) { SpinCursor(3); Fprintf(ofp, "\n#define\tPM_"); if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4)) Fprintf(ofp, "HUMAN_"); for (nam = c = tmpdup(mons[i].mname); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char) ('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; Fprintf(ofp, "%s\t%d", nam, i); } Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i); Fprintf(ofp, "\n#endif /* PM_H */\n"); Fclose(ofp); return; } /* Start of Quest text file processing. */ #include "qtext.h" static struct qthdr qt_hdr; static struct msghdr msg_hdr[N_HDR]; static struct qtmsg *curr_msg; static int qt_line; static boolean in_msg; #define NO_MSG 1 /* strlen of a null line returned by fgets() */ static boolean qt_comment(s) char *s; { if (s[0] == '#') return TRUE; return (boolean) (!in_msg && strlen(s) == NO_MSG); } static boolean qt_control(s) char *s; { return (boolean) (s[0] == '%' && (s[1] == 'C' || s[1] == 'E')); } static int get_hdr(code) char *code; { int i; for (i = 0; i < qt_hdr.n_hdr; i++) if (!strncmp(code, qt_hdr.id[i], LEN_HDR)) return ++i; return 0; } static boolean new_id(code) char *code; { if (qt_hdr.n_hdr >= N_HDR) { Fprintf(stderr, OUT_OF_HEADERS, qt_line); return FALSE; } strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR); msg_hdr[qt_hdr.n_hdr].n_msg = 0; qt_hdr.offset[qt_hdr.n_hdr++] = 0L; return TRUE; } static boolean known_msg(num, id) int num, id; { int i; for (i = 0; i < msg_hdr[num].n_msg; i++) if (msg_hdr[num].qt_msg[i].msgnum == id) return TRUE; return FALSE; } static void new_msg(s, num, id) char *s; int num, id; { struct qtmsg *qt_msg; if (msg_hdr[num].n_msg >= N_MSG) { Fprintf(stderr, OUT_OF_MESSAGES, qt_line); } else { qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]); qt_msg->msgnum = id; qt_msg->delivery = s[2]; qt_msg->offset = qt_msg->size = qt_msg->summary_size = 0L; curr_msg = qt_msg; } } /* check %E record for "[summary text]" that nethack can stuff into the message history buffer when delivering text via window instead of pline */ static char * valid_qt_summary(s, parsing) char *s; /* end record: "%E" optionally followed by " [summary]" */ boolean parsing; /* curr_msg is valid iff this is True */ { static char summary[BUFSZ]; char *p; if (*s != '%' || *(s + 1) != 'E') return (char *) 0; if ((p = index(s, '[')) == 0) return (char *) 0; /* note: opening '[' and closing ']' will be retained in the output; anything after ']' will be discarded by putting a newline there */ Strcpy(summary, p); /* have an opening bracket; summary[] holds it and all text that follows */ p = eos(summary); /* find closing bracket */ while (p > summary && *(p - 1) != ']') --p; if (p == summary) { /* we backed up all the way to the start without finding a bracket */ if (parsing) /* malformed summary */ Fprintf(stderr, MAL_SUM, qt_line); } else if (p == summary + 1) { ; /* ignore empty [] */ } else { /* got something */ /* p points one spot past ']', usually to '\n'; we need to include the \n as part of the size */ if (parsing) { /* during the writing pass we won't be able to recheck delivery, so any useless summary for a pline mode message has to be carried along to the output file */ if (curr_msg->delivery == 'p') Fprintf(stderr, DUMB_SUM, qt_line); /* +1 is for terminating newline */ curr_msg->summary_size = (long) (p - summary) + 1L; } else { /* caller is writing rather than just parsing; force newline after the closing bracket */ Strcpy(p, "\n"); } return summary; } return (char *) 0; } static void do_qt_control(s) char *s; { char code[BUFSZ]; int num, id = 0; if (!index(s, '\n')) Fprintf(stderr, CTRL_TRUNC, qt_line); switch (s[1]) { case 'C': if (in_msg) { Fprintf(stderr, CREC_IN_MSG, qt_line); break; } else { in_msg = TRUE; if (sscanf(&s[4], "%s %5d", code, &id) != 2) { Fprintf(stderr, UNREC_CREC, qt_line); break; } num = get_hdr(code); if (!num && !new_id(code)) break; num = get_hdr(code) - 1; if (known_msg(num, id)) Fprintf(stderr, DUP_MSG, qt_line); else new_msg(s, num, id); } break; case 'E': if (!in_msg) { Fprintf(stderr, END_NOT_IN_MSG, qt_line); } else { /* sets curr_msg->summary_size if applicable */ (void) valid_qt_summary(s, TRUE); in_msg = FALSE; } break; default: Fprintf(stderr, UNREC_CREC, qt_line); break; } } static void do_qt_text(s) char *s; { if (!in_msg) { Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line); } else if (!index(s, '\n')) { Fprintf(stderr, TEXT_TRUNC, qt_line); } curr_msg->size += strlen(s); return; } static void adjust_qt_hdrs() { int i, j; long count = 0L, hdr_offset = sizeof(int) + (sizeof(char) * LEN_HDR + sizeof(long)) * qt_hdr.n_hdr; for (i = 0; i < qt_hdr.n_hdr; i++) { qt_hdr.offset[i] = hdr_offset; hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg; } for (i = 0; i < qt_hdr.n_hdr; i++) for (j = 0; j < msg_hdr[i].n_msg; j++) { msg_hdr[i].qt_msg[j].offset = hdr_offset + count; count += msg_hdr[i].qt_msg[j].size + msg_hdr[i].qt_msg[j].summary_size; } return; } static void put_qt_hdrs() { int i; /* * The main header record. */ if (debug) Fprintf(stderr, "%ld: header info.\n", ftell(ofp)); (void) fwrite((genericptr_t) & (qt_hdr.n_hdr), sizeof(int), 1, ofp); (void) fwrite((genericptr_t) & (qt_hdr.id[0][0]), sizeof(char) * LEN_HDR, qt_hdr.n_hdr, ofp); (void) fwrite((genericptr_t) & (qt_hdr.offset[0]), sizeof(long), qt_hdr.n_hdr, ofp); if (debug) { for (i = 0; i < qt_hdr.n_hdr; i++) Fprintf(stderr, "%s @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]); Fprintf(stderr, "\n"); } /* * The individual class headers. */ for (i = 0; i < qt_hdr.n_hdr; i++) { if (debug) Fprintf(stderr, "%ld: %s header info.\n", ftell(ofp), qt_hdr.id[i]); (void) fwrite((genericptr_t) & (msg_hdr[i].n_msg), sizeof(int), 1, ofp); (void) fwrite((genericptr_t) & (msg_hdr[i].qt_msg[0]), sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp); if (debug) { int j; for (j = 0; j < msg_hdr[i].n_msg; j++) { Fprintf(stderr, "msg %d @ %ld (%ld)", msg_hdr[i].qt_msg[j].msgnum, msg_hdr[i].qt_msg[j].offset, msg_hdr[i].qt_msg[j].size); if (msg_hdr[i].qt_msg[j].summary_size) Fprintf(stderr, " [%ld]", msg_hdr[i].qt_msg[j].summary_size); Fprintf(stderr, "\n"); } } } } void do_questtxt() { char *line; Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE); if (!(ofp = fopen(filename, WRBMODE))) { perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } qt_hdr.n_hdr = 0; qt_line = 0; in_msg = FALSE; while ((line = fgetline(ifp)) != 0) { SpinCursor(3); qt_line++; if (qt_control(line)) do_qt_control(line); else if (qt_comment(line)) { free(line); continue; } else do_qt_text(line); free(line); } (void) rewind(ifp); in_msg = FALSE; adjust_qt_hdrs(); put_qt_hdrs(); while ((line = fgetline(ifp)) != 0) { if (qt_control(line)) { char *summary_p = 0; in_msg = (line[1] == 'C'); if (!in_msg) summary_p = valid_qt_summary(line, FALSE); /* don't write anything unless we've got a summary */ if (!summary_p) { free(line); continue; } /* we have summary text; replace raw %E record with it */ Strcpy(line, summary_p); /* (guaranteed to fit) */ } else if (qt_comment(line)) { free(line); continue; } if (debug) Fprintf(stderr, "%ld: %s", ftell(stdout), line); (void) fputs(xcrypt(line), ofp); free(line); } Fclose(ifp); Fclose(ofp); return; } static char temp[32]; static char *limit(name, pref) /* limit a name to 30 characters length */ char *name; int pref; { (void) strncpy(temp, name, pref ? 26 : 30); temp[pref ? 26 : 30] = 0; return temp; } void do_objs() { int i, sum = 0; char *c, *objnam; int nspell = 0; int prefix = 0; char class = '\0'; boolean sumerr = FALSE; filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Code); Fprintf(ofp, "#ifndef ONAMES_H\n#define ONAMES_H\n\n"); for (i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) { SpinCursor(3); objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */ if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue; /* make sure probabilities add up to 1000 */ if (objects[i].oc_class != class) { if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } class = objects[i].oc_class; sum = 0; } for (c = objnam; *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char) ('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; switch (class) { case WAND_CLASS: Fprintf(ofp, "#define\tWAN_"); prefix = 1; break; case RING_CLASS: Fprintf(ofp, "#define\tRIN_"); prefix = 1; break; case POTION_CLASS: Fprintf(ofp, "#define\tPOT_"); prefix = 1; break; case SPBOOK_CLASS: Fprintf(ofp, "#define\tSPE_"); prefix = 1; nspell++; break; case SCROLL_CLASS: Fprintf(ofp, "#define\tSCR_"); prefix = 1; break; case AMULET_CLASS: /* avoid trouble with stupid C preprocessors */ Fprintf(ofp, "#define\t"); if (objects[i].oc_material == PLASTIC) { Fprintf(ofp, "FAKE_AMULET_OF_YENDOR\t%d\n", i); prefix = -1; break; } break; case GEM_CLASS: /* avoid trouble with stupid C preprocessors */ if (objects[i].oc_material == GLASS) { Fprintf(ofp, "/* #define\t%s\t%d */\n", objnam, i); prefix = -1; break; } default: Fprintf(ofp, "#define\t"); } if (prefix >= 0) Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i); prefix = 0; sum += objects[i].oc_prob; } /* check last set of probabilities */ if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } Fprintf(ofp, "#define\tLAST_GEM\t(JADE)\n"); Fprintf(ofp, "#define\tMAXSPELL\t%d\n", nspell + 1); Fprintf(ofp, "#define\tNUM_OBJECTS\t%d\n", i); Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n"); for (i = 1; artifact_names[i]; i++) { SpinCursor(3); for (c = objnam = tmpdup(artifact_names[i]); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char) ('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; if (!strncmp(objnam, "THE_", 4)) objnam += 4; /* fudge _platinum_ YENDORIAN EXPRESS CARD */ if (!strncmp(objnam, "PLATINUM_", 9)) objnam += 9; Fprintf(ofp, "#define\tART_%s\t%d\n", limit(objnam, 1), i); } Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i - 1); Fprintf(ofp, "\n#endif /* ONAMES_H */\n"); Fclose(ofp); if (sumerr) exit(EXIT_FAILURE); return; } /* Read one line from input, up to and including the next newline * character. Returns a pointer to the heap-allocated string, or a * null pointer if no characters were read. */ static char * fgetline(fd) FILE *fd; { static const int inc = 256; int len = inc; char *c = malloc(len), *ret; for (;;) { ret = fgets(c + len - inc, inc, fd); if (!ret) { free(c); c = NULL; break; } else if (index(c, '\n')) { /* normal case: we have a full line */ break; } len += inc; c = realloc(c, len); } return c; } static char * tmpdup(str) const char *str; { static char buf[128]; if (!str) return (char *) 0; (void) strncpy(buf, str, 127); return buf; } static char * eos(str) char *str; { while (*str) str++; return str; } /* * macro used to control vision algorithms: * VISION_TABLES => generate tables */ void do_vision() { #ifdef VISION_TABLES int i, j; /* Everything is clear. xclear may be malloc'ed. * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH) */ for (i = 0; i < MAX_ROW; i++) for (j = 0; j < MAX_COL; j++) if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH) xclear[i][j] = '\000'; else xclear[i][j] = '\001'; #endif /* VISION_TABLES */ SpinCursor(3); /* * create the include file, "vis_tab.h" */ filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Code); Fprintf(ofp, "#ifdef VISION_TABLES\n"); #ifdef VISION_TABLES H_close_gen(); H_far_gen(); #endif /* VISION_TABLES */ Fprintf(ofp, "\n#endif /* VISION_TABLES */\n"); Fclose(ofp); SpinCursor(3); /* * create the source file, "vis_tab.c" */ filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H); Unlink(filename); exit(EXIT_FAILURE); } Fprintf(ofp, "%s", Dont_Edit_Code); Fprintf(ofp, "#include \"config.h\"\n"); Fprintf(ofp, "#ifdef VISION_TABLES\n"); Fprintf(ofp, "#include \"vis_tab.h\"\n"); SpinCursor(3); #ifdef VISION_TABLES C_close_gen(); C_far_gen(); Fprintf(ofp, "\nvoid vis_tab_init() { return; }\n"); #endif /* VISION_TABLES */ SpinCursor(3); Fprintf(ofp, "\n#endif /* VISION_TABLES */\n"); Fprintf(ofp, "\n/*vis_tab.c*/\n"); Fclose(ofp); return; } #ifdef VISION_TABLES /*-------------- vision tables --------------*\ * * Generate the close and far tables. This is done by setting up a * fake dungeon and moving our source to different positions relative * to a block and finding the first/last visible position. The fake * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT * by BLOCK_WIDTH) is blocked. Then we move the source around relative * to the corner of the block. For each new position of the source * we check positions on rows "kittycorner" from the source. We check * positions until they are either in sight or out of sight (depends on * which table we are generating). The picture below shows the setup * for the generation of the close table. The generation of the far * table would switch the quadrants of the '@' and the "Check rows * here". * * * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * ............................... * ............................... * .........@..................... * ............................... * * Table generation figure (close_table). The 'X's are blocked points. * The 'B' is a special blocked point. The '@' is the source. The ','s * are the target area. The '.' are just open areas. * * * Example usage of close_table[][][]. * * The table is as follows: * * dy = |row of '@' - row of 'B'| - 1 * dx = |col of '@' - col of 'B'| * * The first indices are the deltas from the source '@' and the block 'B'. * You must check for the value inside the abs value bars being zero. If * so then the block is on the same row and you don't need to do a table * lookup. The last value: * * dcy = |row of block - row to be checked| * * Is the value of the first visible spot on the check row from the * block column. So * * first visible col = close_table[dy][dx][dcy] + col of 'B' * \*-------------- vision tables --------------*/ static void H_close_gen() { Fprintf(ofp, "\n/* Close */\n"); Fprintf(ofp, "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n", TEST_HEIGHT - 1); Fprintf(ofp, "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n", TEST_WIDTH); Fprintf(ofp, "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n", TEST_HEIGHT); Fprintf(ofp, "typedef struct {\n"); Fprintf(ofp, " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n"); Fprintf(ofp, "} close2d;\n"); Fprintf(ofp, "extern close2d close_table[CLOSE_MAX_SB_DY];\n"); return; } static void H_far_gen() { Fprintf(ofp, "\n/* Far */\n"); Fprintf(ofp, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n", TEST_HEIGHT); Fprintf(ofp, "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n", TEST_WIDTH - 1); Fprintf(ofp, "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n", TEST_HEIGHT - 1); Fprintf(ofp, "typedef struct {\n"); Fprintf(ofp, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n"); Fprintf(ofp, "} far2d;\n"); Fprintf(ofp, "extern far2d far_table[FAR_MAX_SB_DY];\n"); return; } static void C_close_gen() { int i, dx, dy; int src_row, src_col; /* source */ int block_row, block_col; /* block */ int this_row; int no_more; const char *delim; block_row = BLOCK_HEIGHT - 1; block_col = BLOCK_WIDTH - 1; Fprintf(ofp, "\n#ifndef FAR_TABLE_ONLY\n"); Fprintf(ofp, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n"); #ifndef no_vision_progress Fprintf(stderr, "\nclose:"); #endif for (dy = 1; dy < TEST_HEIGHT; dy++) { src_row = block_row + dy; Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy); #ifndef no_vision_progress Fprintf(stderr, " %2d", dy), (void) fflush(stderr); #endif for (dx = 0; dx < TEST_WIDTH; dx++) { src_col = block_col - dx; Fprintf(ofp, " /*%2d*/ {", dx); no_more = 0; for (this_row = 0; this_row < TEST_HEIGHT; this_row++) { delim = (this_row < TEST_HEIGHT - 1) ? "," : ""; if (no_more) { Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim); continue; } SpinCursor(3); /* Find the first column that we can see. */ for (i = block_col + 1; i < MAX_COL; i++) { if (clear_path(src_row, src_col, block_row - this_row, i)) break; } if (i == MAX_COL) no_more = 1; Fprintf(ofp, "%2d%s", i - block_col, delim); } Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); } Fprintf(ofp, " }},\n"); } Fprintf(ofp, "}; /* close_table[] */\n"); /* closing brace for table */ Fprintf(ofp, "#endif /* !FAR_TABLE_ONLY */\n"); #ifndef no_vision_progress Fprintf(stderr, "\n"); #endif return; } static void C_far_gen() { int i, dx, dy; int src_row, src_col; /* source */ int block_row, block_col; /* block */ int this_row; const char *delim; block_row = BLOCK_HEIGHT - 1; block_col = BLOCK_WIDTH - 1; Fprintf(ofp, "\n#ifndef CLOSE_TABLE_ONLY\n"); Fprintf(ofp, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n"); #ifndef no_vision_progress Fprintf(stderr, "\n_far_:"); #endif for (dy = 0; dy < TEST_HEIGHT; dy++) { src_row = block_row - dy; Fprintf(ofp, "/* DY = %2d */\n {{\n", dy); #ifndef no_vision_progress Fprintf(stderr, " %2d", dy), (void) fflush(stderr); #endif for (dx = 1; dx < TEST_WIDTH; dx++) { src_col = block_col + dx; Fprintf(ofp, " /*%2d(-1)*/ {", dx); for (this_row = block_row + 1; this_row < block_row + TEST_HEIGHT; this_row++) { delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : ""; SpinCursor(3); /* Find first col that we can see. */ for (i = 0; i <= block_col; i++) { if (clear_path(src_row, src_col, this_row, i)) break; } if (block_col - i < 0) Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim); else Fprintf(ofp, "%2d%s", block_col - i, delim); } Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); } Fprintf(ofp, " }},\n"); } Fprintf(ofp, "}; /* far_table[] */\n"); /* closing brace for table */ Fprintf(ofp, "#endif /* !CLOSE_TABLE_ONLY */\n"); #ifndef no_vision_progress Fprintf(stderr, "\n"); #endif return; } /* * "Draw" a line from the hero to the given location. Stop if we hit a * wall. * * Generalized integer Bresenham's algorithm (fast line drawing) for * all quadrants. From _Procedural Elements for Computer Graphics_, by * David F. Rogers. McGraw-Hill, 1985. * * I have tried a little bit of optimization by pulling compares out of * the inner loops. * * NOTE: This had better *not* be called from a position on the * same row as the hero. */ static int clear_path(you_row, you_col, y2, x2) int you_row, you_col, y2, x2; { int dx, dy, s1, s2; register int i, error, x, y, dxs, dys; x = you_col; y = you_row; dx = abs(x2 - you_col); dy = abs(y2 - you_row); s1 = sign(x2 - you_col); s2 = sign(y2 - you_row); if (s1 == 0) { /* same column */ if (s2 == 1) { /* below (larger y2 value) */ for (i = you_row + 1; i < y2; i++) if (!xclear[i][you_col]) return 0; } else { /* above (smaller y2 value) */ for (i = y2 + 1; i < you_row; i++) if (!xclear[i][you_col]) return 0; } return 1; } /* * Lines at 0 and 90 degrees have been weeded out. */ if (dy > dx) { error = dx; dx = dy; dy = error; /* swap the values */ dxs = dx << 1; /* save the shifted values */ dys = dy << 1; error = dys - dx; /* NOTE: error is used as a temporary above */ for (i = 0; i < dx; i++) { if (!xclear[y][x]) return 0; /* plot point */ while (error >= 0) { x += s1; error -= dxs; } y += s2; error += dys; } } else { dxs = dx << 1; /* save the shifted values */ dys = dy << 1; error = dys - dx; for (i = 0; i < dx; i++) { if (!xclear[y][x]) return 0; /* plot point */ while (error >= 0) { y += s2; error -= dxs; } x += s1; error += dys; } } return 1; } #endif /* VISION_TABLES */ #ifdef STRICT_REF_DEF NEARDATA struct flag flags; #ifdef ATTRIB_H struct attribs attrmax, attrmin; #endif #endif /* STRICT_REF_DEF */ /*makedefs.c*/ nethack-3.6.0/util/mdgrep.h0000664000076400007660000002147312536476415014565 0ustar paxedpaxed/* * NetHack 3.6 mdgrep.h $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ * Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008 * NetHack may be freely redistributed. See license for details. * * This file generated by mdgrep.pl version 1.7. * DO NOT EDIT! Your changes will be lost. */ static struct grep_var grep_vars[] = { { "0", 0 }, { "1", 1 }, #if defined(ALLDOCS) { "ALLDOCS", 1 }, #else { "ALLDOCS", 0 }, #endif #if defined(AMIGA) { "AMIGA", 1 }, #else { "AMIGA", 0 }, #endif #if defined(AMII_GRAPHICS) { "AMII_GRAPHICS", 1 }, #else { "AMII_GRAPHICS", 0 }, #endif #if defined(ASCIIGRAPH) { "ASCIIGRAPH", 1 }, #else { "ASCIIGRAPH", 0 }, #endif #if defined(BETA) { "BETA", 1 }, #else { "BETA", 0 }, #endif #if defined(BSD_JOB_CONTROL) { "BSD_JOB_CONTROL", 1 }, #else { "BSD_JOB_CONTROL", 0 }, #endif #if defined(CLIPPING) { "CLIPPING", 1 }, #else { "CLIPPING", 0 }, #endif #if defined(COMPRESS) { "COMPRESS", 1 }, #else { "COMPRESS", 0 }, #endif #if defined(DLB) { "DLB", 1 }, #else { "DLB", 0 }, #endif { "FALSE", 0 }, #if defined(GEM_GRAPHICS) { "GEM_GRAPHICS", 1 }, #else { "GEM_GRAPHICS", 0 }, #endif #if defined(GNOME_GRAPHICS) { "GNOME_GRAPHICS", 1 }, #else { "GNOME_GRAPHICS", 0 }, #endif #if defined(HANGUPHANDLING) { "HANGUPHANDLING", 1 }, #else { "HANGUPHANDLING", 0 }, #endif #if defined(INSURANCE) { "INSURANCE", 1 }, #else { "INSURANCE", 0 }, #endif #if defined(LIFE) { "LIFE", 1 }, #else { "LIFE", 0 }, #endif #if defined(MAC) { "MAC", 1 }, #else { "MAC", 0 }, #endif #if defined(MAC_GRAPHICS) { "MAC_GRAPHICS", 1 }, #else { "MAC_GRAPHICS", 0 }, #endif #if defined(MAIL) { "MAIL", 1 }, #else { "MAIL", 0 }, #endif #if defined(MFLOPPY) { "MFLOPPY", 1 }, #else { "MFLOPPY", 0 }, #endif #if defined(MSDOS) { "MSDOS", 1 }, #else { "MSDOS", 0 }, #endif #if defined(MSWIN_GRAPHICS) { "MSWIN_GRAPHICS", 1 }, #else { "MSWIN_GRAPHICS", 0 }, #endif #if defined(NOCWD_ASSUMPTIONS) { "NOCWD_ASSUMPTIONS", 1 }, #else { "NOCWD_ASSUMPTIONS", 0 }, #endif #if defined(NOSAVEONHANGUP) { "NOSAVEONHANGUP", 1 }, #else { "NOSAVEONHANGUP", 0 }, #endif #if defined(OS2) { "OS2", 1 }, #else { "OS2", 0 }, #endif #if defined(POSIX_JOB_CONTROL) { "POSIX_JOB_CONTROL", 1 }, #else { "POSIX_JOB_CONTROL", 0 }, #endif #if defined(QT_GRAPHICS) { "QT_GRAPHICS", 1 }, #else { "QT_GRAPHICS", 0 }, #endif #if defined(RANDOM) { "RANDOM", 1 }, #else { "RANDOM", 0 }, #endif #if defined(SAFERHANGUP) { "SAFERHANGUP", 1 }, #else { "SAFERHANGUP", 0 }, #endif #if defined(SECURE) { "SECURE", 1 }, #else { "SECURE", 0 }, #endif #if defined(SHELL) { "SHELL", 1 }, #else { "SHELL", 0 }, #endif #if defined(SUSPEND) { "SUSPEND", 1 }, #else { "SUSPEND", 0 }, #endif #if defined(TEXTCOLOR) { "TEXTCOLOR", 1 }, #else { "TEXTCOLOR", 0 }, #endif #if defined(TOS) { "TOS", 1 }, #else { "TOS", 0 }, #endif { "TRUE", 1 }, #if defined(TTY_GRAPHICS) { "TTY_GRAPHICS", 1 }, #else { "TTY_GRAPHICS", 0 }, #endif #if defined(UNICODE_DRAWING) { "UNICODE_DRAWING", 1 }, #else { "UNICODE_DRAWING", 0 }, #endif #if defined(UNICODE_PLAYERTEXT) { "UNICODE_PLAYERTEXT", 1 }, #else { "UNICODE_PLAYERTEXT", 0 }, #endif #if defined(UNICODE_WIDEWINPORT) { "UNICODE_WIDEWINPORT", 1 }, #else { "UNICODE_WIDEWINPORT", 0 }, #endif #if defined(UNIX) { "UNIX", 1 }, #else { "UNIX", 0 }, #endif #if defined(USER_SOUNDS) { "USER_SOUNDS", 1 }, #else { "USER_SOUNDS", 0 }, #endif #if defined(USE_TILES) { "USE_TILES", 1 }, #else { "USE_TILES", 0 }, #endif #if defined(VAR_PLAYGROUND) { "VAR_PLAYGROUND", 1 }, #else { "VAR_PLAYGROUND", 0 }, #endif #if defined(VMS) { "VMS", 1 }, #else { "VMS", 0 }, #endif #if defined(WIN32) { "WIN32", 1 }, #else { "WIN32", 0 }, #endif #if defined(WIN32_PLATFORM_HPCPRO) { "WIN32_PLATFORM_HPCPRO", 1 }, #else { "WIN32_PLATFORM_HPCPRO", 0 }, #endif #if defined(WIN32_PLATFORM_WFSP) { "WIN32_PLATFORM_WFSP", 1 }, #else { "WIN32_PLATFORM_WFSP", 0 }, #endif #if defined(WINNT) { "WINNT", 1 }, #else { "WINNT", 0 }, #endif #if defined(WIN_CE) { "WIN_CE", 1 }, #else { "WIN_CE", 0 }, #endif #if defined(WIN_CE_POCKETPC) { "WIN_CE_POCKETPC", 1 }, #else { "WIN_CE_POCKETPC", 0 }, #endif #if defined(WIN_CE_PS2xx) { "WIN_CE_PS2xx", 1 }, #else { "WIN_CE_PS2xx", 0 }, #endif #if defined(WIN_CE_SMARTPHONE) { "WIN_CE_SMARTPHONE", 1 }, #else { "WIN_CE_SMARTPHONE", 0 }, #endif { "WIZARD", 1 }, #if defined(X11_GRAPHICS) { "X11_GRAPHICS", 1 }, #else { "X11_GRAPHICS", 0 }, #endif #if defined(ZEROCOMP) { "ZEROCOMP", 1 }, #else { "ZEROCOMP", 0 }, #endif #if defined(ZLIB_COMP) { "ZLIB_COMP", 1 }, #else { "ZLIB_COMP", 0 }, #endif #if defined(__BEOS__) { "__BEOS__", 1 }, #else { "__BEOS__", 0 }, #endif { 0, 0 } }; /* Command ids */ #define TODO_GREP 1 /* End of file */ nethack-3.6.0/util/mdgrep.pl0000664000076400007660000000711112536476415014742 0ustar paxedpaxed#!perl # NetHack 3.6 mdgrep.pl $NHDT-Date: 1423877528 2015/02/14 01:32:08 $ $NHDT-Branch$:$NHDT-Revision: 1.7 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. # MAKEDEFS: @commands = qw/grep/; # GREP: # Operating Systems: @os = qw/WIN32 MSDOS VMS UNIX TOS AMIGA MAC WINNT __BEOS__ WIN_CE OS2 WIN_CE_SMARTPHONE WIN_CE_POCKETPC WIN_CE_PS2xx WIN32_PLATFORM_HPCPRO WIN32_PLATFORM_WFSP/; # Window Systems: @win = qw/TTY_GRAPHICS MAC_GRAPHICS AMII_GRAPHICS MSWIN_GRAPHICS X11_GRAPHICS QT_GRAPHICS GNOME_GRAPHICS GEM_GRAPHICS/; # Game Features: @feature = qw/ZEROCOMP USE_TILES ASCIIGRAPH CLIPPING TEXTCOLOR COMPRESS ZLIB_COMP RANDOM SECURE USER_SOUNDS SAFERHANGUP MFLOPPY NOCWD_ASSUMPTIONS VAR_PLAYGROUND DLB SHELL SUSPEND NOSAVEONHANGUP HANGUPHANDLING BSD_JOB_CONTROL MAIL POSIX_JOB_CONTROL INSURANCE UNICODE_DRAWING UNICODE_WIDEWINPORT UNICODE_PLAYERTEXT /; # Miscellaneous @misc = qw/BETA/; # Meta @meta = qw/ALLDOCS/; # convention: use --grep-define ALLDOCS to notate # items that are conditionally available # JUNK: # MICRO BSD __GNUC__ NHSTDC TERMLIB __linux__ LINUX WIN32CON NO_TERMS # ULTRIX_PROTO TERMINFO _DCC DISPMAP OPT_DISPMAP TARGET_API_MAC_CARBON # NOTTYGRAPHICS SYSV ULTRIX MAKEDEFS LEV_LEX_C __STDC__ # BITCOUNT TILE_X COLORS_IN_USE CHDIR KR1ED # apollo __APPLE__ AIX_31 PC9800 __MACH__ _GNU_SOURCE __EMX__ DGUX # __MWERKS__ __MRC__ __BORLANDC__ LINT THINK_C __SC__ AZTEC_C __FreeBSD__ # USE_PROTOTYPES __DJGPP__ macintosh POSIX_TYPES SUNOS4 _MSC_VER __OpenBSD__ # GCC_WARN VOIDYYPUT FLEX_SCANNER FLEXHACK_SCANNER WIERD_LEX # NeXT __osf__ SVR4 _AIX32 _BULL_SOURCE AUX __sgi GNUDOS # TIMED_DELAY DEF_MAILREADER DEF_PAGER NO_SIGNAL PC_LOCKING LATTICE __GO32__ # msleep NO_FILE_LINKS bsdi HPUX AMIFLUSH SYSFLAGS # OVERLAY USE_TRAMPOLI USE_OVLx SPEC_LEV DGN_COMP # SCREEN_BIOS SCREEN_DJGPPFAST SCREEN_VGA SCREEN_8514 # EXEPATH NOTSTDC SELECTSAVED NOTPARMDECL # constants @const_true = qw/1 TRUE/; @const_false = qw/0 FALSE/; $outfile = "mdgrep.h"; sub start_file { ($rev) = ('$NHDT-Revision: 1.7 $') =~ m/: (.*) .$/; my $date = '$NHDT-Date: 1423877529 2015/02/14 01:32:09 $'; my $branch = '$NHDT-Branch$'; my $revision = '$NHDT-Revision: 1.7 $'; open(OUT, ">$outfile") || die "open $outfile: $!"; # NB: Date and Revision below will be modified when mdgrep.h is written to # git - this is correct (but it means you must commit changes to mdgrep.pl # before generating mdgrep.h and committing that file). print OUT < #endif #ifdef WIN32 #include #include "win32api.h" #endif #ifdef VMS extern int FDECL(vms_creat, (const char *, unsigned)); extern int FDECL(vms_open, (const char *, int, unsigned)); #endif /* VMS */ int FDECL(restore_savefile, (char *)); void FDECL(set_levelfile_name, (int)); int FDECL(open_levelfile, (int)); int NDECL(create_savefile); void FDECL(copy_bytes, (int, int)); #ifndef WIN_CE #define Fprintf (void) fprintf #else #define Fprintf (void) nhce_message static void nhce_message(FILE *, const char *, ...); #endif #define Close (void) close #ifdef UNIX #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ #else #ifdef VMS #define SAVESIZE (PL_NSIZ + 22) /* [.save]player.e;1 */ #else #ifdef WIN32 #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ #else #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ #endif #endif #endif #if defined(EXEPATH) char *FDECL(exepath, (char *)); #endif #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif char savename[SAVESIZE]; /* holds relative path of save file from playground */ int main(argc, argv) int argc; char *argv[]; { int argno; const char *dir = (char *) 0; #ifdef AMIGA char *startdir = (char *) 0; #endif if (!dir) dir = getenv("NETHACKDIR"); if (!dir) dir = getenv("HACKDIR"); #if defined(EXEPATH) if (!dir) dir = exepath(argv[0]); #endif if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) { Fprintf(stderr, "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]); #if defined(WIN32) || defined(MSDOS) if (dir) { Fprintf( stderr, "\t(Unless you override it with -d, recover will look \n"); Fprintf(stderr, "\t in the %s directory on your system)\n", dir); } #endif exit(EXIT_FAILURE); } argno = 1; if (!strncmp(argv[argno], "-d", 2)) { dir = argv[argno] + 2; if (*dir == '=' || *dir == ':') dir++; if (!*dir && argc > argno) { argno++; dir = argv[argno]; } if (!*dir) { Fprintf(stderr, "%s: flag -d must be followed by a directory name.\n", argv[0]); exit(EXIT_FAILURE); } argno++; } #if defined(SECURE) && !defined(VMS) if (dir #ifdef HACKDIR && strcmp(dir, HACKDIR) #endif ) { (void) setgid(getgid()); (void) setuid(getuid()); } #endif /* SECURE && !VMS */ #ifdef HACKDIR if (!dir) dir = HACKDIR; #endif #ifdef AMIGA startdir = getcwd(0, 255); #endif if (dir && chdir((char *) dir) < 0) { Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir); exit(EXIT_FAILURE); } while (argc > argno) { if (restore_savefile(argv[argno]) == 0) Fprintf(stderr, "recovered \"%s\" to %s\n", argv[argno], savename); argno++; } #ifdef AMIGA if (startdir) (void) chdir(startdir); #endif exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static char lock[256]; void set_levelfile_name(lev) int lev; { char *tf; tf = rindex(lock, '.'); if (!tf) tf = lock + strlen(lock); (void) sprintf(tf, ".%d", lev); #ifdef VMS (void) strcat(tf, ";1"); #endif } int open_levelfile(lev) int lev; { int fd; set_levelfile_name(lev); #if defined(MICRO) || defined(WIN32) || defined(MSDOS) fd = open(lock, O_RDONLY | O_BINARY); #else fd = open(lock, O_RDONLY, 0); #endif return fd; } int create_savefile() { int fd; #if defined(MICRO) || defined(WIN32) || defined(MSDOS) fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); #else fd = creat(savename, FCMASK); #endif return fd; } void copy_bytes(ifd, ofd) int ifd, ofd; { char buf[BUFSIZ]; int nfrom, nto; do { nfrom = read(ifd, buf, BUFSIZ); nto = write(ofd, buf, nfrom); if (nto != nfrom) { Fprintf(stderr, "file copy failed!\n"); exit(EXIT_FAILURE); } } while (nfrom == BUFSIZ); } int restore_savefile(basename) char *basename; { int gfd, lfd, sfd; int lev, savelev, hpid, pltmpsiz; xchar levc; struct version_info version_data; struct savefile_info sfi; char plbuf[PL_NSIZ]; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created * savefile info * player name * and game state */ (void) strcpy(lock, basename); gfd = open_levelfile(0); if (gfd < 0) { #if defined(WIN32) && !defined(WIN_CE) if (errno == EACCES) { Fprintf( stderr, "\nThere are files from a game in progress under your name."); Fprintf(stderr, "\nThe files are locked or inaccessible."); Fprintf(stderr, "\nPerhaps the other game is still running?\n"); } else Fprintf(stderr, "\nTrouble accessing level 0 (errno = %d).\n", errno); #endif Fprintf(stderr, "Cannot open level 0 for %s.\n", basename); return (-1); } if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { Fprintf( stderr, "%s\n%s%s%s\n", "Checkpoint data incompletely written or subsequently clobbered;", "recovery for \"", basename, "\" impossible."); Close(gfd); return (-1); } if (read(gfd, (genericptr_t) &savelev, sizeof(savelev)) != sizeof(savelev)) { Fprintf(stderr, "Checkpointing was not in effect for %s -- recovery " "impossible.\n", basename); Close(gfd); return (-1); } if ((read(gfd, (genericptr_t) savename, sizeof savename) != sizeof savename) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) || (read(gfd, (genericptr_t) &plbuf, pltmpsiz) != pltmpsiz)) { Fprintf(stderr, "Error reading %s -- can't recover.\n", lock); Close(gfd); return (-1); } /* save file should contain: * version info * savefile info * player name * current level (including pets) * (non-level-based) game state * other levels */ sfd = create_savefile(); if (sfd < 0) { Fprintf(stderr, "Cannot create savefile %s.\n", savename); Close(gfd); return (-1); } lfd = open_levelfile(savelev); if (lfd < 0) { Fprintf(stderr, "Cannot open level of save for %s.\n", basename); Close(gfd); Close(sfd); return (-1); } if (write(sfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) { Fprintf(stderr, "Error writing %s; recovery failed.\n", savename); Close(gfd); Close(sfd); return (-1); } if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) { Fprintf(stderr, "Error writing %s; recovery failed (savefile_info).\n", savename); Close(gfd); Close(sfd); return (-1); } if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) { Fprintf(stderr, "Error writing %s; recovery failed (player name size).\n", savename); Close(gfd); Close(sfd); return (-1); } if (write(sfd, (genericptr_t) &plbuf, pltmpsiz) != pltmpsiz) { Fprintf(stderr, "Error writing %s; recovery failed (player name).\n", savename); Close(gfd); Close(sfd); return (-1); } copy_bytes(lfd, sfd); Close(lfd); (void) unlink(lock); copy_bytes(gfd, sfd); Close(gfd); set_levelfile_name(0); (void) unlink(lock); for (lev = 1; lev < 256; lev++) { /* level numbers are kept in xchars in save.c, so the * maximum level number (for the endlevel) must be < 256 */ if (lev != savelev) { lfd = open_levelfile(lev); if (lfd >= 0) { /* any or all of these may not exist */ levc = (xchar) lev; write(sfd, (genericptr_t) &levc, sizeof(levc)); copy_bytes(lfd, sfd); Close(lfd); (void) unlink(lock); } } } Close(sfd); #if 0 /* OBSOLETE, HackWB is no longer in use */ #ifdef AMIGA /* we need to create an icon for the saved game * or HackWB won't notice the file. */ { char iconfile[FILENAME]; int in, out; (void) sprintf(iconfile, "%s.info", savename); in = open("NetHack:default.icon", O_RDONLY); out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT); if(in > -1 && out > -1){ copy_bytes(in,out); } if(in > -1)close(in); if(out > -1)close(out); } #endif #endif return (0); } #ifdef EXEPATH #ifdef __DJGPP__ #define PATH_SEPARATOR '/' #else #define PATH_SEPARATOR '\\' #endif #define EXEPATHBUFSZ 256 char exepathbuf[EXEPATHBUFSZ]; char * exepath(str) char *str; { char *tmp, *tmp2; int bsize; if (!str) return (char *) 0; bsize = EXEPATHBUFSZ; tmp = exepathbuf; #if !defined(WIN32) strcpy(tmp, str); #else #if defined(WIN_CE) { TCHAR wbuf[EXEPATHBUFSZ]; GetModuleFileName((HANDLE) 0, wbuf, EXEPATHBUFSZ); NH_W2A(wbuf, tmp, bsize); } #else *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; #endif #endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; return tmp; } #endif /* EXEPATH */ #ifdef AMIGA #include "date.h" const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif #ifdef WIN_CE void nhce_message(FILE *f, const char *str, ...) { va_list ap; TCHAR wbuf[NHSTR_BUFSIZE]; char buf[NHSTR_BUFSIZE]; va_start(ap, str); vsprintf(buf, str, ap); va_end(ap); MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"), MB_OK); } #endif /*recover.c*/ nethack-3.6.0/win/Qt/Info.plist0000664000076400007660000000124012504242744015267 0ustar paxedpaxed CFBundleGetInfoHTML http://www.nethack.org CFBundleGetInfoString Copyright (C) 1985-2003 Stichting Mathematisch Centrum CFBundleIconFile nethack.icns CFBundleIdentifier org.nethack.qt CFBundlePackageType APPL CFBundleShortVersionString 3.5.0 CFBundleSignature NHak nethack-3.6.0/win/Qt/Install.Qt0000664000076400007660000001021312536476415015244 0ustar paxedpaxedInstalling NetHack with a Qt or KDE interface --------------------------------------------- $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ This document describes the installation of NetHack with a Qt interface on UNIX/X11 or Mac OS X. This code should also work with Qt/Windows, but support for that is not currently official. You can download Qt from http://www.trolltech.com. You need Qt 2.0 or later to use this code. To use this code on UNIX (not Mac OS X): 1. follow the directions for the UNIX installation (in ../../sys/unix) to create the Makefiles. 2. ../../include/config.h define QT_GRAPHICS (search for it). You can comment out TTY_GRAPHICS if you want to, or leave it in to support both interfaces (in which case be sure you have the right curses libraries etc. required for that interface). 3. ../../src/Makefile ensure your QTDIR environment variable was set correctly when you installed Qt - $QTDIR/include/qwidget.h should exist, for example. ensure CXX and LINK are set to the compiler and linker you need for compiling and linking C++ software (e.g., set both to g++). add $(WINQTSRC), $(WINQTOBJ), and $(WINQTLIB) to WINSRC, WINOBJ, and WINLIB respectively, and compile. This will give you an executable supporting both Qt and tty windowing. 4. ../../Makefile (the top-level makefile) Just change the VARDATND setting to contain the files "x11tiles", "rip.xpm", and "nhsplash.xpm": VARDATND = x11tiles rip.xpm nhsplash.xpm 5. Follow all the instructions in ../../sys/unix/Install.unx for the remainder of the installation process. 6. Consider adding the lines below to your .nethackrc, as they are likely to give the best interface for this window port: OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt If you are using KDE, you may want to also try the KDE version. It just uses the KDE menubar and follows other KDE conventions - there is no extra functionality. To do so: 1. Ensure that you have KDE 2.x libraries on your system (in 1999 KDE 1.x was the norm) 2. ../../src/Makefile Add $(KDECXXFLAGS) to the CXXFLAGS definition, $(KDELFLAGS) to the LFLAGS definition and $(WINKDELIB) to WINLIB. 3. Some additional files here - knh-mini.xpm, knh.xpm, and knethack.lnk are useful if you want to install "knethack" in the KDE games directory. If you are using Qtopia, you can compile NetHack for that environment with the following additional steps: 1. First be sure that you can build a simple Qtopia application, such as the examples that ship with Qtopia. Do not attempt something as challenging to compile as NetHack before you can already build a Qtopia application for your target device. 2. If you are cross-compiling (eg. targetting an ARM-based handheld), be sure to follow the steps for cross-compiling in the Makefile.src and Makefile.utl files. 3. To CXXFLAGS in Makefile.src, add: -DQWS -I$(QPEDIR)/include -fno-rtti -fno-exceptions 4. Rather than -lqt in WINQTLIB, have: -L$(QPEDIR)/lib -lqpe -lqte 5. After building, use the "mkipks" program that ships with Qtopia to package the result into an ipk file. To use this code on Mac OS X: 1. follow the directions for the UNIX installation (in ../../sys/unix) to create the Makefiles. 2. quite a number of changes are required to the Makefiles. They are slowly being made 'official', but for now they are all in the patch nethack-macosx-qt.patch: cd ../.. patch -p0 < win/Qt/nethack-macosx-qt.patch 3. Follow all the instructions in ../../sys/unix/Install.unx for the remainder of the installation process (basically run "make install"). 4. Consider adding the lines below to a file called "NetHack Defaults", in your "Library/Preferences" folder, as they are likely to give the best interface for this window port: OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt nethack-3.6.0/win/Qt/knethack.lnk0000664000076400007660000000067112467321052015622 0ustar paxedpaxed# KDE Config File # Call this file knethack.kdelnk or knethack.desktop [KDE Desktop Entry] Name=Nethack Name[fr]=Nethack Name[hu]=Nethack Name[no]=Nethack Name[sk]=Nethack Name[cs]=Nethack Name[hr]=Nethack Name[pt]=Nethack Name[pt_BR]=Nethack Icon=knh.xpm Exec=knethack -caption "%c" %i %m Type=Application DocPath=knethack/index.html Comment=The classic Unix role-playing game - fight monsters and seek the Amulet of Yendor for your god! nethack-3.6.0/win/Qt/knh-mini.xpm0000664000076400007660000000103612467321052015560 0ustar paxedpaxed/* XPM */ static char *noname[] = { /* width height ncolors chars_per_pixel */ "16 16 7 1", /* colors */ " c #000000", ". c #DCDCDC", "X c #008080", "o c #A0A0A0", "O c None", "+ c #FFFFFF", "@ c #C3C3C3", /* pixels */ "OOOOOOOOOOOOOOOO", "OOO+O+++@@@O@OOO", "O+O+++++@@@@@O.O", "O+o+XXXXX X @ . ", "O+o+XXXX X X@ . ", "OO +XXXXX X @ O ", "OOO+XXXX X X@ OO", "OOO+XXXXX X @ OO", "OOO+XXXX X X@ OO", "OOOO+XXXX X@ OO", "OOOO+XXX X . OO", "OOO+O+XXX . . OO", "OO+++ +X . ... O", "O+++. O+. .... ", "OO+. OOOOOO.. O", "OOOOOOOOOOOOOOOO" }; nethack-3.6.0/win/Qt/knh.xpm0000664000076400007660000000420212467321052014624 0ustar paxedpaxed/* XPM */ static char *noname[] = { /* width height ncolors chars_per_pixel */ "40 40 20 1", /* colors */ " c #000000", ". c #0000C0", "X c #FFC0FF", "o c #FFC0C0", "O c #DCDCDC", "+ c #C0C0FF", "@ c #008080", "# c #A0A0A0", "$ c None", "% c #000080", "& c #585858", "* c #800080", "= c #FFFFFF", "- c #FFFFC0", "; c #00C0C0", ": c #C0FFFF", "> c #C0FFC0", ", c #C3C3C3", "< c #FFDCA8", "1 c #0000FF", /* pixels */ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$=$$$$$$=,==<,=<,$$$$$$,$$$$$$$$$", "$$$$$$$$==$$$=====,=<>,<><$$$<>$$$$$$$$$", "$$$$$$$$===$====,==>,=<,<,,$,,<$$$$$$$$$", "$$$==$$$==========<=<,><,><<><,$$$,<$$$$", "$$$====$========,==,,=<>,<,>,<,$<><,$$$$", "$$$====$==========<=<,,<<><,<><$,,<>$$$$", "$$$$#&&&==$#$#$#@#$&@#&&@&&&&,, && $$", "$$$;#@&@==;#;#;#$;&#@&@$&@&@$>< &@ $$", "$$$====&==###1##.##@&#&@&&$&&<, <>O< $$", "$$$====&==$;##;##;&#@&@$&@&@&>, O<,> $$", "$$$==&@&==#1#;##.##@&#&@&$@$&,< ,< $$", "$$$$ ==###1#;##.#@$&&&@&&@-, $ $$", "$$$$$ =X;#;###&;#&@#&@$&@$&,< $$ $$$", "$$$$$$ ==#$+@+1##@#&@&$@&&&@<> $$$$$$", "$$$$$$$$=X;#1#$#@##@&#@&&&@$&<, $$$$$$", "$$$$$$$$==##;#;##1$#@&$@$&&@&>< $$$$$$", "$$$$$$$$=X;###1#@##@&#@&&@$&&O, $$$$$$", "$$$$$$$$==#1#;##;#.#@&&$@&@&@<> $$$$$$", "$$$$$$$$$==###;#*;#&@#&@&&$&O< $$$$$$$", "$$$$$$$$$==;#1,$;#&#@$@&$@&@<, $$$$$$$", "$$$$$$$$$$=X####.##@&#&&@&& ><, $$$$$$", "$$$$$$====@&=O##@#;&@#&&,< <,>< $$$$$", "$$$$$===#$== ==$1#&#&@&O> ,<$#,,> $$$$", "$$$$===#;#== ==$#;&@#O, >,#;&<,< $$$$", "$$$==$#;*@O< ====Oo,> <,&$#@&O, $$$", "$$$==;$#&&<, $===<,< < $$", "$$$==##;&O>, $$==,> $$ ,<&&#$@o, $$", "$$$===X=O,< $$$$$$$$$$$$$>OO,Oo> $$$", "$$$$====,< $$$$$$$$$$$$$$,<,>,<, $$$$", "$$$$$===<> $$$$$$$$$$$$$$$$><,<> $$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" }; nethack-3.6.0/win/Qt/nhicns.uu0000664000076400007660000020617312467321052015166 0ustar paxedpaxedbegin 640 nethack.icns M:6-N2`Q@J)8&,C9"%T(S\SO(+&"I1U5GU$0G?,X7MN@<8,PHAF6'^#<[QQ MAGV\RH#]O6L;&?(7'HHZA>IGJ@,80BYS#/&F3HGUOQI?&@W3&QH6!Q@E< MIW'&QES&QJ*5A,8$X6K&QJF'Q@6/QD3&QNR'Q@!A@<8`@)'&H,8`=H'&`@\5 M?87&"+:'[L:%;X"46H3&"<@-O(T^9W*9K<6`Q@W:KS'&PS.!&2M[-[+%XH#& M"A<311$U*!X1#!^G@L8*"RP0%@L1%@L9"Q:!Q@RO%A0?&A@-#F11'`T*@,8- M'2D-QL8<%0HC%1HC$0J`QA!^9KT1$@X-'33&-<8Q#L;&;('&"5(-(<;&)L;& MAWB$Q@0*.\;&-8?&!5W&1,;&"8?&`#.!Q@!AD<:@Q@!N@<8"#A5CA<8(M*+> MQGM_FJ=5A,8)QPS'H39E@:6\S(#&#=:D+L;#?8X8*G\VO,K@@,8*%A-!$$%# M'1`-'J."Q@H+'Q`6"PX5"A,*%8'&#*L6$QD:&`T-1S8:#`J`Q@T8(0W&QAP4 M"AH3%2$1"H#&$']BO0X1#@T;+L8UQB\-QL9F@<8)/0T?QL8=QL:#=(3&!`HM MQL8AA\8%4\9"QL8)A\8`*H'&`$*1QG,X;6L```$(____________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M_____________________TE#3B,```$(```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````&EL,S(```;C@<8`R9S&`*F]Q@#%G<8`O(;&`]+JXKR0Q@*] MQ]:"Q@;LCVEW>7?#CL8$SH)_>[2`Q@B!9G^9F:BI<,R,QA&]G)B84,;'QH]Z MAI"0G:^RH,N,QA'AF-[-'B!;;V%WD*":K*R^QZN+QA*D=]OYG:7*97)R>Y.D MI[+&R=.KA\8`NX#&$N^;P[2ZPF)G MKD@8Q;%A:F-E.9"4N+_'UN+&OX+&%2&^V4XH(I'&_D2*/SI)*RDA*$"2CL*' MQA6\BY1U5%AC>$GN+4I624-(7%XV6Z;/A\85K:[.'EMP9XF2;X)^9U9SBYF^ MGJI+S(?&%[.1R#5A6'R*?"_/=V]/MKG(OYR^Q']KQX3&&,BXFWUB86-NBH2- M6JAN4=7R,D;W`?=^!QAMOK^]2@<8;QR$0%<;KF4?&6%MRS,2'E7AV:5EH;,;&Q8*U MVH+&`I$71(#&#T@_3&5EI-A[?(YF4]'&4L&`Q@*-I9:!Q@*U(:6!Q@Y1S,9M M@\!I<65AUL;&;WZ!Q@*>BF&!Q@#)A<8&YV^;:,!'=(#&`7N,@L8"RV'3B\8# M=I/&88'&`4VMD\8#PW?&:('&`7>1DL8$P&O&QE>!Q@&BGY+&`,F$Q@*_'F*$PQ8S&$1)QAXH^QL?& M."UW@(>3I:>!#\@,"T@.#@I[,0H)&A^%QA@7"A(<$`T.%A@9 M'"*'#!A1(3(F%P\*##@?A,89#`D9$!=&-$`>'!L?%Q41$VT:$PH6&@L,%"6# MQAL/"AH++\;&O"(`6E8#&""1?@**BL*THQ8S&$1!DH:`]QL?&+R.& MF8^AN+F#;HS&$0DHU==6);X45R69IYNQK\#)(8O&$BT>K^RDJLD=&7$K<:NK MM<;)TB^'Q@"B@,82"9?`E;V]&F%R@']!K[N_R=;=$H'&',5`.AO&%,?)QD48 M,!ZPHAAA2ETECV.\O\G5W,:,@L85$`D)#1@1=<;VSR4;$0\3$A`2-9!'PH?& M%0D0$1@8&R`/%<\/$PL4"PL,#1(@D;'10)#`D+"Q,6 M#1>^A\86"A5`%@P*#A8<#K<+"S@.#@IB(@H)&1Z%QA@2"A(;#PP.%1@9&1>! M"Q@^'"4@%P\*"R,8A,89#`D8#Q8\+34>&Q@7%A$0$DL9$@H6%PL*$2"#QAL/ M"AD++L;&N2`?%AH9"0T0'QD4&R$A%Q\/1B/9@<8;*R(="\;&Q,;&$!H3#0D/ M%2\3&QP9(B\<$QX)%X'&&\(1#@[&XB$BQ@P9&PD)&!,C-#PW%PS&QK,9#PF" MQ@*0$!:`Q@\V'`H\/0D)$!L7,2O/Q@J!@,8"00DE@<8"L1E_@<8."L7&0!T) M$"HY1-/&Q@D*@<8"C`Y+@<8`"X7&!N`A"1.X"R^`Q@$)0H+&`KL_THO&`PD- MQAF!Q@$C49/&`PD)QBN!Q@$)$9+&!`HFQL9(@<8!"0J2Q@`)A,8"L@DH>8E)"DG8=WS)3&![W/>YF9 MCO'0@<8.IGJ'?H:.D9Z=H*NL@;#4DL8;R]6LJ)&18'?+QM#&KW9QF'.&AIF: MJ+"CN;"7SI'&'-VVZ32?IJ5D)20U/*)O77F1@9"2I)JFKK&^P)/*D,8=R,:I MN5WGO_6!G2NRB&-I:6MX@9&AH+"MM\+(R9;+D<8;VAXBW^%28B(C\N)FYNRJXYO>I-\G92QN]C8?J2%Q@=9TRMU M?6I8HH#&'=)U9GAJ>C&$C(S%I9:=CHRC>;"A:864FJ*[W^&*C83&!G]^W6]X M#EJ#QAR'=WQV<(5WTL>AAJ*,LHZ(9:&+9'I[B9F_TNI\A8/&"L5O;GD8$&+& MQM6I@,8;)3(:='+PP::+C8QXBGJ*6YYR<9)R7@<8%OX.,O73%@\8#"Q@*-G[V%Q@*^@823Q@9< MP8S&)G,8"C]O#@,8!1+J"Q@/!>>R$G,8!R8:!Q@"V@\8# MBY?"LIS&`;*5B,8">+G6G<8`88G&`JV?@)W&`-R)Q@*8@,^JQ@'2T>O&@\8` MX:S&`/VLQ@%GR*S&`)RMQ@!KK<8`NZS&`*B+Q@7-=U]?:*^9Q@!VB<8(=@D/ M%3D5-`Q]F,8%KW)^R,;]@L8+OPDL+%YO@&H@1`S#@):37RI;E,8'M@Q1AX=\[K"!Q@Z%(Q-O>G^`DI24HZ):'-&2QAO* M"Q->@(!;6[7&SL:.%R\*<'IZAY*8I9RNIA/-D<86C8(Z-DA7;AHG M'A%R@8>6DIZEJ[:Z++F0QAW(QA8-)N"\\W6-,+4^/BEG/3!RAY69I:6MNL+% M7JB1QAS%"2-<;,3$F*?&(3\@8W!P+(>2DJ*KKL#`Q--3W(S&`+V!QAPB"C%= M4ZZ8P-$:0&4V<'![*6R4J*>TNL/&R]1ZL(3&"-JS;:^QQC$[FX#&'<,*)3/L MSX'`QAD^:"MP<'N#:S>DJ+*]Q\7.W.*0Q(/&)5@P/Y<9Q@D/)LW&T[HK"6P. M#JO(RB!(/7!F%T9B6HXCL[2WQ,;*@,8`EX/&&;97%D\/"0P8$J9^41/&(3UF M057.#A@S%#4V@10%CIA%N,#3B\8@)!<3"1,6#T4.$!%!*37O#"@:%!X;%!$1 M$`P4%!^U=J?+C,8?"1`)$306.RLX(S42#BG]*PT*$!<+"0H*)S,,"1A9)VJ- MQB`7&`X[0A<;)R@M&Q$))#0I(!\*%PX)"@D,1Q<1,!`9'\&,QB$/"Q5-+!82 M$!`.%A,B"SBW$1`)%AX)"PD,&3@@"PT-%AO-BL8BJPD,$1,9$0H+"0L:%A,1 M##"V"0H452#A<29#07 M40L,'`L.#0H)"AVXAL8G#@D)&!4-$!BQLW@Q/AT7'!@4%A@D"18152@/%AX3 M#A(2%A01"0D9?(7&!PT)#1H<#`R'@,8=S1M%*"0=#AD>&0D0%`\S*@\L#ALT M'AP7%0X)"2!)A,8&'1<**1T+#8/&`D,C'(`5%BT)"A$7(SX0%1@^&AX5(R,B M$0T?"AY,@\8*NBX8'`P/,<;&OUN`QAL1#Q$6#`D)#!<5%ST8.#$3#2P2<"LG M&Q@1%@D9A,8?5AL8#PL4QLN?02#-W!$4&A0*"0D-%14;'2PS*Q\8)0^`Q@:A M*!L5*`H9A,8?2'XI#V;&QKUM-A%5"A)#-PX2"0T;%QT[230T4\8E##6!Q@6V M,1,)#L.#Q@-N%1`E@L87MB`4#;H_6AT/"0D4&ADG5$`RL,;'"@F;@L8#CQD* M$(/&`WD_#RR#Q@Q^$!K&X%`8$`H*%QPF@%N!Q@()#%"#Q@.^%`VS@\8";!"0 MA,8`.X#&"3=2+PH-%B0A.#&"Q@())GF$Q@2'%Q)XN8'&`0L=BL8(CQ\+"5B[ M$0D3@L8"8"*FA<8"M%5UD\8&"0I$QB`4R(+&`LLWOI[&!48*$\8[(X/&`H8U MCYW&!GH)#&3&/82#Q@()"UF=Q@8*#&_&QBJV@L8#R`D)*9S&`ET)NH#&`42Z M@L8#NPP)%YS&`1H>@<8`M8/&`R`*"J*ZK,8` MIHO&!(U*4Q@>T"T>BHI'>HH'& M#GL>$W^%E9JFGZ>PL549T9+&&\4*$$J:FD53M,;9QH07*0ITA86BF["YJ;VN M$\V1QAS7A@D82JZ)S8^!E+%C&2,=$7J6E*J;K+&ROL,ILY#&'F,HML%!T<$X`0!PT4$QZY(Q@NK"0D6&143 M"Q89(1V`&A<8%Q8-*1H-%Q)'+!&QB<."0D8%0P/%K2R M<24T'1<:&!$6&!X)%1%`'0\6&Q(.$A(4$0\)"1ASA<8'#0D,&AL,#(.`QAW. M&CLD'QT.&1H8"1`4#R0A#R(-%BL:&!42#0D)&T&$Q@88%PHA'`L-@\8<0B$< M%!44*`D*$1<:-`\3%R\5&A4A'1T1#!<*&T6#Q@JZ)!<<#`XHQL:Z3H#&&P\. M$!8+"0D,%A47,AT&A(-NC9$'`X) M"1(9&!\^,"JOQL<+"9B"Q@..&0H/@\8#=S4.(H/&#'8/%\;@/1<."@H5'".` M18'&`@D,3X/&`\43#;&#Q@)F$)V$Q@`U@,8)-#TF"@T6(A\O)8+&`@D==H3& M!(,5$'2R@<8!"QJ*Q@B"'0L)5;D0"1&"Q@)<&J*%Q@*S26N3Q@8)"D+&'1/( M@L8"R2&]GL8%-`H3QBT?@\8"@B&*G<8&=@D,8<8O?X/&`@D+6)W&!@H,9\;& M*K6"Q@/("0DEG,8"4PG`@,8!0KF"Q@.Z"PD6G,8!%!Z!Q@"U@\8#'`D*H9S& M`2!O&:#AM:P``"0C_ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M__________]I=#,R``!9E`````#_QHK&`LSWXOK&`O'^]/K&`_[^^-?YQ@/P M\^_=^<8$R-3-N(!^#8F&<6AM:GMTCZK)RLS6P,81VJG!MI&*@8*(G+S:QL;^ M_O3$B<8+T]/SY*9^;F5E9VEX@(80C9"0J)NFD8E^:R<_CO,82U]/`?IYY?W^#?WAK:W*L\>.JU(G&(GZ5FX9K7V)F?H.+A921 MF9^FHJB6B'].:1XHG& M)&N"D8)_=&5H@H*&A)"9D)V8DI21FJ>KG:6=H**@EGZ*FK#%Q]2YQA*[X,!_ M@82EF9>2E9F2?H/DZ83DB<8F:YRGA9:0;G%^>X2#A)6)DI"1E)29IJB:GZ&> MJZ^RG9>"BZR^U8Z]MRBI"' M@(%[?H=_A(Z(D(^)GIFEFIJ=HJ:JK:RMM9*`A9ZISLO)ML84Q:_SS:O$Q9R0 MD)F0E9")TM%`;97'A\8GF.O)=WV%BH*3=GZ+AI"&D)"-F9B9F9N:J*BMH:NP MK:NTNJ%T=Z_-W[;&%=J;O_/-KD)LL9F5D)F0IK&M]HY1W>'Z&AHF`C)"8D9Z:H*BH@+`+MJNPM<*WMXAUG\#GM,8*V>'5 M?NGNLVX0:(^`F3N@H:"OW3\>.#+-T\U;1$3-QL:>ZX9U9F-O=827CWJ&BX:& MD)"9D)&:DIJ>FJ:PLZNSL*^VMKO#J'2/N,2SQDO_2IC)-GYV2F::F M?M?10SHO*E%243\O1&9MM8[Q?F]T9FAM?81]C):.@)"0EIZ0DIJAFINDHZ6O MJZZUK;:]O[RVKI*1J<'3L<9,T.3&R*;4Z,-X,G&LPJJHN'BBA(:.)B(B(1\G M030V2GI\]()K>&]=:'%X<8N8D(&1BY.8EI::H*&BI:*HK*NNLK.RO,&^O\6M MEI6GR]>PQDW)XL;'HJ[QU*X[.:+GOKW6<'=LU>!`'B`A&25+,3A$1&ONB&=W M=U)D:&YI@8Z.A8V)D)2:GIB>IJJAI+"MK;*MN*^YO\'#R,BQFXNRW<>OQ@#5 M@,9*SICE[JB2.ENOP?SY1,/^_?JA+3=!+U(88W1/0V#:AV!Q=E9?:6AL=WV% MB8B/CYZ:I9*GH*BAI;"RL+6MMK>VO,+'SCYRAFYJ?@*L5IK:RMK2ZP,?"Q\?)Q\[.U->\C:6\S:;&`>;1 MAL8CQ[F_[>VD?Y"5C410]UN-!K>75G9FAD:5EP@G(A?'AK MA)^0FIN:H:*BJZJNM*ZTNKV\Q\+'RL_&UM37U,Z9D:;&`LS:AX?&#\>7Q_#0 MA8>!6GE$ZXHXHLN`J`^TOLG"V,UL>G=>9FEF;FE?@G(D?GUQ>HJ*C:*?H*&K MLZNOL+2XP+N[Q,+'RL_-U]'7U=?.KI?&QZ/&`\G52[F&QB+(KZ7BYZ^-ASU4 M99)C.URIFZ>LM\G&QM7!;G9T6&9I:&QP6()R)7Z`>GQ]?XF>GJ"AL;"NL+*V MN[ZZO\3"Q\K*S=31U]C7X,V&!U5T*CDYVQN-&`Q@JQ;7%R5V=I:6AO6X%R`75_@(`B?'J%CY:< MH;&KK["UM[NZNL'&PLC)Q\S1U-;:VM_@O8VMU\>0Q@O+R-#/KI^WP\;%Q,F` MQ@;)P+2P)1?-A\82N['J\KZ,/1U$QN.OB^RX>0H:FLJ["R@+H4N[S"P\[(RL*RPL;JYNL7#PLC. MQ=')T='7V(#@!>7EQ9'"T(W&$\_:M8)Q8%E`1H.LI7N"Q\;>U?.R@!``;X+& M`>/;@<9%S)[2[^M:1$0>4DH8&"RQMLF0D8&#F:>VPK>VN;JYP\?(R,?.T5I8W&5\N$54`^ M/C]`6*3`I8F`PL;([?.(%Q`0;,;&Y\S&P%/*QK3&QJ"XX?-L1$0>#G`B$`Y: MM]/&TL;+67!SQN1"PX)B2.&Q8U@X[&R,)726UR<&%I8SD^D)&D9&0D86.H;BZNL'#P\+(SBL=EV1#(R-1]<61\N9VG4S7GQ*>*54V&.A`S)1$/"\Z)AU[ M)RM&2\;++B-&='IR.6([-2E6,S9.42DV)BHL,RPX-3B1D8F)FY:)DJNXR\7" MQM38HL9.W8`:;9^-I[H5E7VB+:E(L*&`Q*"8@)R$F*!X:<7%I@'$Q M9?3^L!`.#A@>'A@7*CY==G-L*B@H-2,A(S8D,50Q,41&2#8J*BEE.C8YPM3+ MJL;&R[:GQE7,U*N;T[MS>^G9?&E.87U::TYT9T193U-B7&Q:43UG/2@Q:7%Q MC?[)*C(A'%DI,1T8-%U[=F4K)S$\.CT]1CU,7DQ38&5J6CPI*#@[:4[2MEF( MQL;GV*?&5=3@LZW#N)*FIH"49GM.=6Q<7%59GD=NO?Y66@FM-O6RE27=@6F)96%1:65IF;'&*A)F6FX!E0T=MBYK: MJZZ384QB8$](6&9V=EI$5U=F<&%Q87-D:W%OEF5>9=!\GD5I:%I<6U=F869?9E=Y=8:$HIV/>E\_:7%= MV)>GEVE6>VMG25IG?75:1E9==&]N=76#;'U^)LKVIP,BAH)B/E[BTDX]? M2&=.E\1XOZ3&6,"KP[.6MV?(J3GH^& M9#E(*^;&NU)$*'9B55UN971R9E)=57J1Q\W/VBI,9:MGNYI:B>AW.6M,"X9C0J7V563%%14TA13%!EB(5\=81W M;(B+)QI5M.STP&E(EHM6:F]]?7)64%"-R-#4T]3*S\G4V.+EKZF"CJVNO\F]Q\2N@6U06%AKH,9@R+*APK"SGHUW;JG+S,J&:%A87F!H7F-H M9V5E>&AV?(V.AY5[B7]R3CTO,EG'RXF*=&-Z=G-\;%%D9&&%A7U^AXR0GZBY MSL&\OX*"HZZIC*"OM\&YPLO$NZAG65YMT,;&RYW&7\3*VL6VG))S8YJWPZ)S M9%I=8F-E7&1E865NGU^@82)?XR)F8*"IJ2HG8NPL+?%R<'*QL&9CG19JJR!JIO&8\G&T-C= MQK:>E7AFCZ.FC6QD7%YA8F%<9&-A9&]P?W6"@X=_AH*-F(U\=VU$)BH^GHFD M>G%QA8)C=G9H8V]G8V5]@']_?75D'N;H*B?B:^NL<7*P,O'R+"HA5J- MCF^=QL>9QF/0R=W5SK"QIYB'?'Y_6W1N;F-@6%Y87V5C:&-I;GIZ?7>)B(E_ M?WV%FX:4BVDO*2MWTXR%;8:)8G9Y=&YI8V!DA9*0D8=L9&%H9V%G=YFAE96K ML*R[QLC'R]#)PJ1X9D]YE;_)FL9BS^+;PIREI(.*?7Y[8FMI6F-;6&-:76I@ M9&1J9'-X@(&%B(*&C(B1=I^@BF]E+SU0W<*%:XM[76=V?7]L8V!@8YJCIYN$ M@GIXBGAJ;7!_I9.>M+"LNL:^R&5E8G166%)B95I9969F;G%U>GN!?7>!?':0C8>1A'V#<'A)6&53U82'I9N- MA'60HHER8&!C;'V)FY6"E:[$H)BBBW5UBXN?H[BPM<"^VM//U];)N65EBI.8 MQA;#OL/2PL*LDW!PA'YS7R6 MEF1X>82:1+B7BKOGTK9\H9RJGH)_@F2`>A:&BIRZN+"GIIZ1?G6+CY.;K;^N MMLO!Q(#4!\*DB)QCQLB\E,9IOHB?H)VHI:2?A8)W?IV7DJVBO+F^R-'2T-+-PZUF?J1TRY+&:LO-W]',TMS1 MIY!S;G!U7V-[85U96HBDO:^SL;6=;&5N:69K;79^?(R*?81]A8V+2WF"BH^) M:W^9R,S<'5A9WAB6UQ:L[[,@,91RKRIBW-G M:'!IY*,FHEP::[-RCE7AY=WN'A8>1CI.:G*&MJ[K)TMK2R,6= M?*FONY#&%+AQ1WJ]BU\O:WAH<7QT:%]=6%EGHH?&4-BM'2&=(%Z MBV4\CHN$A(UM;;#6T;V\KYJ8EINEG)R=BJ2*KYNTH7V7FJR[K*"%:75R?HJ/ MB)23C)2?GKJUQ]?,V^+`HWB,B<'&QXW&$[AI1RB=BXMD='1M<7QW9RQ16&5D MBL9.RXM9;'IR$?WEW>+;"UK.GP:B.J::PFYR>BIR*DK"5 MH8&7DY:[JIR3<6=Q=81U=(&-AJR2BKNKG,?&T^2_QI&<;J+&RHW&$[Q9A'R$ MA9[IDFEY='AT.`X]679MB\9-SJ1R975Y9G)X>W=_(FV;?HB1=&^NR+[+L)^M MM(V'G9.G=XV*D\"-HWV'=ZB'Q]B(J4HIR-QYS,T]'D MY+INE,:*C<83S'&FTX%BH\]W:W)Z>EX2#D16>'2-QDS(CV5R=GIU>'U(&OBIN0HHA]BW9J88J1I8Z7@')C>7E]F$8#P]$5F6$A,8! MR=B%QDN_1EUU8Z1C:>+BW*/ M;'1GG^0?HV@I+"SRNS(R-ZS5U2-C<82R;)J;(R! M;71Z'QVB7)I7EY_EJYS>8!MA)6!=7%P:7E]@H&`BI"E MH;+=S>CPXI1'=H[&"KY^;H:!='AX4CH1@`\#155Q('& M3IQ0/"LI/E8[6W=U>W:1N^3=Z\"OJ9^LHH.`DX.>B(.">HJ`BW]R=WEN8&!9 M'-[?("%DIJBQB>'U]>W-L M+X(/`T!76=:`QES)Y,W@WKV';G*VRL;&R'Y97S8I.2]B>'QT=W6>PM+4Z<*M MI9ZJLX-_EX*6CGB,?(%^>XAK=VIG66189X*7;&U\?7_'QL;'R+:8?75\?'J` M@96;K<'EU=OMPI"Z2\Z-Q@ZL?7IN.R$1$!`/#PY29(^!QD+9W=+%U:6(6%)@ MX<;&TU%?6F%B7F5U=7=J7XJ>R,+,V7B*<69Q=V9F M5%)36&F`:G!Q=UC)A,82R:YW;GU\@9B;J;K2\_/DI%`VK(W&"-,L%Q`5*A(8 M$(`/`EE>RX#&@.M`UYR'D(%-5TAKRL:^4EI&6%U71%YE97"/P(O`N-C)Q,>< MJXB"F7U]G'Q]<7N*8V%G6UA@55-D5%M>86%F>(1Q7KN'Q@_9EWUX?X2-HJ[" MX^K41S9NCL8,QS517D!&0"D.#A-J9H7&,+1T>F4_4%$]0IV74T]84UAF1%%E M869]AX2MHN"XOKZIDX-^A(%U?GM\>&EX9EM77UR`4PQA7&"UY8M29VEG7H/2 MB,8/UK>!MH<6QQ[BYC)1[?XMY@8Y[B'%K:&!?5%=39%QG M8J;$RL.36FIB8WJ?O8?&#\C$OL"!=XV)AY7*SW5SSVF-Q@NO;TTB31T?#P\F M8I:(QB'"IF)"/STU-SE$2E-ALK1B9F!@@(^1G9^\N=ZYKYE^@'R`@'P:>XU] M:6I78UE866-L9X+`QL;(O'Q33F2/OJKH@7^'B:C$M:]4.MB,Q@NW M;%443Q<3#P\_9K6)QC'%FG5#/CP]/T)*6XO$QVMK8&)[@8*/I:ZUW+.IGFY] M?'R!>GF#AGIG9UE=75Q=:'6$JH+&!Y%*2%ZMV["[BL8,T;ZDA8.$D:['N"(I MU8S&"[]C;!!)'1`0%5AWS8O&+K-,041)24)-GJ)>F]B8F!98&!B>X>K@\8(G$Q+5L/GOY/'B\8,R9N#?X"8O:TN M'\;&NXK&"LU>C!8S+Q`0+&RFC,8(S&Q.45)11%.G@,8AG7EH8&5M:W*MDZV\ MSJR==V:#>H)\0-R>65B@F`"H8O$CL8*OGUZ?9"K9Z^Y$+R* MQ@C"OEM1+!,9=WF/Q@6^4E`^6]*"QA?'RSL[[!BVUH?7ML:6MR M>&6!8`&$P(?&"--89W)6A7)RR(_&";1V=7J+HX1N$*Z+Q@?`A%X^'3-]J)#& M`]);4J6#QAS*I7%C85-B87*EK[>QBV9E>'-S>7AQ:6EE8%-*UXG&!H]E>U=: M8'61Q@O.:W9T?8MU6(F7>\N(Q@?%H(B#06.5PI#&`\BYN,*#QAS'PK9E7V-C M:W:7J[FLGFY=>'AY<&QB9E%*/TUYR(G&!M1?A)EN9Y*1Q@O'O8-X='UO;V=L M?,>)Q@6PS\B/>LJ=QAG(IF]E:&AVG*2RJ*1U8Z*KJ+!F55)(2DA1LXK&!LQN MD92@@YZ2Q@G'MY1M=69J8&2UBL8%R>;GE)/3G<89R,&>@7%L<(>3HJ6B>F:[ MP<#'8E),2T]/5<>+Q@5XB)2SB+"3Q@C(LIQ];F5RBFV`CZ.A?W&`Q@C%7U%/4%)3=\B+Q@6"<9F\AL"5Q@7,EXQ\E+6,Q@+- MF+*CQA3,RZQB>'REJX2*Q,;&N%]-6%)25M*,Q@614YW+ALJJQ@'8TJ;&$=:- M:G*SU*A_P<;&LV1R;E]EMHW&!9I3E1RHW&!6ENBKVLDM7&$+JXO:^\I8MUO\;&JFYB9VK"C<8' MOV5[G\&KC,?2QA+$LJ^_RZ.C=W)ZPL;&J6)B57/?C,8'R:-EB[G"K(?3Q@FX M>KOCRH:"9V>)@,8$JD]A&GV-Q@C/96N>MK:SB,'2Q@B+H>;OK6%A4J"!Q@2Q M42LL;XW&"+%D?IZVSZ2(P='&")V0TO&O>E-NMX+&!,.`('*,C<8(F&2$M^K/ MM(:_T<8'8:GSQ69EI\Z$Q@.M++J,C<8(E&J#M_/9P9>ZT,8(T&JOY(A5N,+' MA,8#VC+%E8W&"'9ED,[NX:Z2O,_&!]_!;[2_:;+%AL8#S5/&Q(S&";Z*6WZD MV;F6BL#/Q@;4P9##F(/,B,8"@,;-C,8)HZE;;H2[FWN$Q,_&!<+!MM!_K8G& M`*Z-Q@G'BK1N>8*VF72/T,8%PKC(TXG-B<8`S(W&",F#D:*WM/"_G-'&!9R^ MI=I]TIK&",EYB;BSO-N\OM'&!,"GI**/F\8(S'B%KJ6EXZZXT<8$MHVACQ@61JM+?DOS&`8/$ M^\8"NE2G^L8#Q;EOV?K&`].)GLKZQ@*Y;;K[Q@*F@L#[Q@&.E_O&`M-OF/K& M`\B[<\2GQ@7DM\O+Q@*K9+VBQ@[6H4]*/S0U.C0Z.$IVG\3&Q@/#DI+3 MG\83Q:AU3ADA"0D+%1H*"14S4VB,I,W$Q@/9<[_'G<86P99J#0D*(`X,#Q4P M$`T,#!P*0&6AI;[#Q@*79<.&RT;$`PSI]/` MQA'96!8.%1@;&1DA;\/&QOW]\L.)Q@NH*`D*$!\?,%IC9V^`>A!^@("8BI6' MA&]6)!L5$`Q%M;_&$8D5.1D:%C`4%1PC+WK6[//*O8G&(7N*%0\8'$U<86Z# M='I[AGZ`?8J"E962DHR&:2D:%"LAA-R\QA+5.PPD-T=A:&EA4SLB,&OPX)#. MB<8B:W'UXA(&'CX^$@8&,EY>5G9.2>6=*,A8H/["[QA+('@T> M5U>'@(5]=&95.T3RXG;?B<8D4FU5)A(81&%T=7IW@8B!C8J'@X"(EIV3FI:8 MFI*'8#$5#UN+T;G&$J@5#1Y;59"'AH&$AX1E5]OE;MJ)QB9&C(DI$@\B3F]P M>79WAGR"@(>$A8B6GI*4FI:CI*Z1830A$$&OO,>WQ@B%"@D/($J*A(:!AP:` MFYW.:)FXB,8G9NK1*!@6%!EC;'1[<7E_>X"%>Y"*EY*2E)J>HJ2CI*J"4B45 M*X_`R;;&%+80"0D-4JYO@("'@(2`?,3%/Q=.Q(?&)V;JEQP<&2D=#4]O?7J! M>H"'?H>'D9&2DIB8I)JCI:2CJ[1]-$$2B-FVQA7520T)"AJ M*!!<+D^W@<8!R]6`QAEFZEH<%AXZ*P\,3G-U>GI\>WZ`AXZ3DI28F("E"ZNC MI:JUKK%T'A$XX+3&"M;@R2,)"0H-#S==@(<[E)F4J=ID*%-%R]++>FQLR\;& M5.I0'"L/*B,9$ALW>GUZ>H"!AX>)DH^2E)*8I:BCJ*6HJZNTN*`N%@V)L\9+ MV]S'C`T)"0P,-$I-@8>7EWG3SVI;24%B9&)<2VR#@JU+\$\7)Q(T(1P9.1HY MF*YPI9*9GC(S,S$K-$I05F6(//(]%"$8.D$J($$8&T1Q@GV'CHB0DI65 MF9F;H*.CI:FMJ;.XM;F_EUDO7IK3L,9-PN'&QF`3"0L+$2E>U;2QT6]\@M7; M/2@M*APD1SU)8&PJ["X6&QTT7T,S.AX5&EAX?8>+BI21E)>@FIVEI:2HJ*^H MLKJWO\3$I6I+4*["K\8`TX#&2L0T"@D-"A8J2BY>.EY2?FIVEIZ:KIZNLKK:^PL7(R\-Y M*1FDQ+/&,+`-"0H/"AHC9^K1;/#]\]J@@)25E&`HI<:U61.V'RA")B(N9VAJ M3Q\M,@TT@8>)DHF`E!6:GJ6DJZ>CJ[2OMKVYQ,/+P\6(&QNUM,8P.0P)"1L. M0%%OOFS=_]O8'%!-2U+Q&?L\8DQ"()"0PK#CI<=FRP_JZFKJ[2UPKW"PL3# MQL70U+))$V_,IL8!Y="'QB.2"@D)*U$70U%L=?._,>',EYB8I*:_EI7$$AH: M*&)G-C0B:6^!<")L4SP9(5F1DY*:FYNCHJBMJ*NTM+>^OL+%RL#2T-30PU@N MD*7&`LS6A8?&#[T>#`D2/4X<5D)LY'\MC;Z`F`^IM\BZQ[D7&QPF8F=8(AM3 M@G`D=7-A.1DQ6(V8F9JBJ:.FJ*NQM;2UO;[#Q<;%U,K4T=2]D$!EQ:/&`[_0 M2;>'QB%U%PD)'EU(12YEG%PU3)9ZDIZNQ,;&T+`9'QTH8F=D-AU$@G`<=7MT M7ST^,%26F9JFIZ6EJ:NTM;2XP+[#Q<3(S\R`U`7R)H828<>(^:IZ.FI:NNLK2TN<*^Q,3#RW2#@5$J,6*2H:.DI:FTK[2UM[Z_QT:`@X-^6R=8 MEJ6FI:JTL;2\NK[$QL#+Q,O+U-.`W`7DY+Q44\2-QA//U:1M9%M./T064T0K M4L3&U!$)#8`/`&^"Q@'TX4>8.#AXYD%BZ9J[6SJ[&TL;G"@,,'Q_;DP_,#`X/RM8>408&Y;&7`D)"A`/#VG&QN"_QH9&RL:7QL9A M#0D)56QL*`XI&A`.;:K0QLW&R!L<(1\Q9V4I9G!@+$AP-1=<>QX46(-W7XZ. M?UP;?+6P@+0)N+B\P\/%R\;^4PPD)1XX9UL9 M,'!5%#5P&A0G6Q44*W8E*HZ.C(ID,GBPM+2UNKF]P\7%W<;)R(?&`,"-QD^4 M9F-&-!04'Q]J6Q(0%!-1#`L*"A4/#S?"QG`KKB<6I[`6:<:^41();&Q-3%0G M-#0H0C)(T\QQ*`H<'QHM9DH5'F4^$C--%108-Q84'$L7'X".#I*#66Z`L+2] MOKN]Q-#%TYO&7\&XLHYT1"<5($4I"@X0$`D/#@L*&1`/&)['/0]V'1%TEQ0U MQL:8)CR9;%]+73LC/3]$02F^QB(0"A88%AQ?,10422,4+"05%!(7%Q04'A0< MCHZ%?IB/>5J*K\/!O<#.UZ+&/-QW%0T0#0D*"0\*#P\-#1H2#P\[PQ@.&A01 M%6L4&+F_PE&_Q&E<>%4[&B9#0$,V4I85%PL7%A0/1Q04$Q>`%`,2%A01@Q0$ M&8Z+7SN`F`=Y-9JSOKS)X:7&-3@,%A,,"@D-"A`1%Q,7$PX1#XT1$!`1$@X7 M%!%:B:=9(SM69\O*/2@46499.A'PP+"2\Z"Q$:'@\0"@H)"0L)"X`)%!<3*",,"@P1%BDC M&!**40V&A`2)"DO*BPG+B@R.!PA0A(3 M%`D+%B@V?-I<>HPZ3&.'X^"@P/#!,E%HA]/S0U$B$9(1XD&B4>'1P;(B\3 M.2`/%`\)"B(F&=,N)QXE$1`C(!`)#1,8#0T,#(()&@L)"@D3%VE$#0\C&AP3 M%PL*&Q`7&AL:?+(GLZ3&/(P-"0H)$1@?%GQ]/3(V%!4@&!(4%Q03$1H4&!04 M&1T-$1L*"182%>&2 M$181#0D)"PL,"0H,"PP4%AD6%QD6%Q41$!82#PX7/UV/-PD*"0D,$@T@+D]4 M*3=1120<'!L9'D!M5DYM;4,;$1`.#@P+#PD3"@H,-S0:'Y"83)*"@L*#0T;'2,Q/%I;6#F`%!\83UU31#!,03`.#A`.$`T- M"PD*#`H*#`P?+A\9('FWNYG&`44*@@E<$!88'!H;$1@1#0T+"0T/"PP0#@X1 M$18='!L:&1L;&!85'!(5%B@4#@PNVGT*#PL)"A(:'!PQ6EM;6A0/#A!?;4XR M(#,X)Q<7#!$-#0X+"@H)"PP*"A='&18@3TESF,8`NH()5!,6$1D9%QP1%!06 M"@D1$102%1@@&1P?'!86&AP<&QL<&!48%1D3&!8R$`P9,K81%@P/%1$7%!`: M/%M;6C,<%Q`T;4`9#A<:#Q$<&!$+$`\-#@L,"0J!"04,#10@*TJ8QD)I"0H* M"0D,$Q47&1H4&10-#!(,#A<=)26"2Q@+`"@J!"1`+$A<4$!@7#@P/%`P4$Z.XR(#&1<>L@UTJ-CTO-28P'AH8 M'!\;&1@8$C4:%A<7-CD:"@D*"A00#Q(0*#U@21,/%1(3%!L?*!\5$1$>&A,/ M%QH8%!X2$1)J:HO)#&%;0+"@D+"0D.&!P3#!P;#0P2#PP6 M,(AH9&Q81+1@8%AD_.A<+"0D+$1,/$Q$/&$M' M(!,?%!,/%B(I'!(0$R$A'1`6'AX6'A83'1(7'`H/"PDB1A46)'MQEI#&%*P1 M#`H+"PD-("@1#!L9"PP,"@X8AX?&&-!]*"4P/BHI)AQ4#,K&A,H)"(:'1@-"P\9&Q-/A,8!N]"$QA#%N1\3 M'!\8&!H0%A<8$147"H`).`H,#0X3$!<6%!@B1#LK)A82%B$J&C,8'QX1"@\O M'!HA2S8?020;)!\;%B$8$A8O#R<)4D()#QH?=X[&$9I2-!L8&AL>&QP/"PX/ M&B,3>8+&!,V/95>RA,8.HR4.$1(/%A(3%!87#1(1@0DX"@L/#Q46&147$AM! M/S`I&!DA/T8M/!46&Q0+#"T>&15T4$[+!\=&QT8$R(,.0D7%PL3.L)PRXS&"(<^'!H<&QL."X$/`PTG&L^` MQAO)XX$D-D,3#4VPRL;&R&8D'0X1%1,:'1P9&`\-@0DA"PH.$1$0%AL5&A89 M/#\C*ALD0#U9+C80$AD7"PLI(Q(18H#&%\?$J&UE33$G'QL:%AD/-@DE(0D+ M2ZP9RHW&!G\<'1L0$1&!#P,+$29=@<8;V-JGME-2&0HG2N#&QM,J&0\-$1$8 M&AH=%2`.#8()(`H,#A86%1L3%QDB/",F,BLL0AU.+SX3(R,A$1(D'PP-#(7& M$KZ16S$<'!L7$A@*)0D)"E@L%)B-Q@?3)A`/%1<2&(`/`PP7'+6`QH#J#,[G&N!\8@`HO#AD@%Q08&PL6#@T)#`D)#PT8&A(;$Q89*BPD-#HS M.%$I)2/,#$Z*QDQ+R,.#`T,1%-*1E90 M&Q87#14-#@H*"1$4&QH9&AL6'2,R/4XW.S`P.T9)05FCQ,J_9!$-#`D++K:' MQ@_(P[:C.1\:%0\*"0D1/\I5C<8+JFQ((485%PX.$A9JB,89NYY7,R&1$/#@Y4P,)&-UE9(AL9$@T3#X`*%0L-$AP<&QL:&QHA05=-2%9) M5D`J;:""Q@)L#@J`"0$8FXK&#-&X;#H9%0\+"1,2$KZ,Q@6]7VL/1AN`#P(J M.L2+QBZD(B(>%`P1"RFCQL9*)U=:-1XA%PP5#PD*"0D+$!L<&1P>&R`Q25E; M2%M05#A,G8/&`G@2"X`)`0I*C,8-NG,P&Q,-"0T-$:/&N\6)Q@K*68L5,2D0 M$!8OBXS&",QC'`P.$AH.@H#&"VDF3EI1'",?"AH1"H`)$@P0&1T9'B4A,5)2 M5EM:6TE'QQPA(W&"&X)"0H)"0H2M]'&!S,)"0P;/:+.A,8#J"JT MA(W&`V`)"PJ`"0$+L=#&"+\8"@D;.J_"QX3&`]DQQ)*-Q@-$"0L*@`D!#++/ MQ@?9020*"C*BQ(;&`\U2QL.,Q@F8%PL*"0D*"A:[S\8&KB)Q@"JCL8"(BH,@`D"#"!FT,8$7AT9 M'Q**Q@#,CL8'&BL-#@P-#F[1Q@5O)$02'\V;Q@&2L9J]'&!'T]6$I= MF\8(RCPB&4)$"QFLT<8$E$\C3;>;Q@C'/QM,'$`E%KG1Q@.7,IF!G<8'D"A3 M.D-<,LC1Q@.M:\2TG<8'H3=023!9>/RXOC:73Q@+4R\2>Q@6#BT!(JMS4Q@'$RY[&!(ZDQ->.U<8`Q)_& M!-2YQ,6BU<8`UI_&!Z9<2GQ@7QA:[EED,"0H7#0P/$R,0#0P+%0HR4J*@N\/&`I12O9S&&KR)#`L)"0X5 M%Q48'C`9%Q43)A`.#`DKA['!R,'&`9^%G,8::PH)&PL.&1\C&A0F*B(B%!0N M'1D3#Q$*'IG3PL8)8XCV4@)"0H6'AD7+3Q-97E_ M@("*A6L\+AL;*!<0"RF9T\#&$=E"%`P4&!H9&!I9O,;&]O;BPHG&"Y,="0H0 M'1TE5F%E>("%$)29F;"DKI*$?TX?&Q40##>TO\81>Q$C%QD5*A,5&B`N9L_E MY+2_B<8A8',2#A@;2UA>E)F,E)RHJJ*IG)9H(!H4(2!RW+S&$LPQ M#!PC06EO;FE6,QPI7.+3A\Z)QB)+528>$QY;7WN$C(J;F:*FI)*6FJ2OK:JN MGIM]:$0H%",_K+O&$K,8#1U/3I.4EH^#;UDV-^+4<=N)QB0Y2$4A$!<^8(*# MA8>3H9.FH)2>FJ.OLJ&LH:*EG8IC+!0/6'[.N<82D!`,'6!,EJ*@FY^BEV50 MS])IT8G&)CEN>"`1#QM-?WR$@X.2 MB:2@JYN;H:BLKK.QM+F"2B03'WN^R;;&%)@/"0D-0)MEF9FBF9V9BJVJ-1=' MQ(?&)USC@QL;&2$8#4A_CX63A9F/E**?FIJPL("Y"[NQN;O`O+EO&Q$NX+3&"M??QB`)"0H-#B93@*([ MIZ:GFL[`5J>=U]K7OL_/U\;&0>-(&R$.(2`9$A&QP95&5<-"`:&1=.@H^DHJN1K:>O MIJN`N1"ZK+N[NL#$R,O3U\IU)Q6J MIV!6N,:[LQ.8'2,X(1XL969H21PH)@TEBX^1FY&GIYZFJ[FTN[6ON+VOP,/` MRLG7R?L;&&2PC(5]8&"%59FB!<@DF&B4-AIZI MG)NC@*\5JKNSN[B]O\C#R,C)R<[+T]>V01%9S*;&`=_0A\8CDPH)"29*%CI0 MS\[DHRW3NZZPL+&YP9*2Q!$9&21?8RXK(&AQ@7(B=$PP&"!5FYV;IJ>GKZZN MNJZXO;[`Q<3(RL_&UM/7T\50)WNEQ@++JX&'Q@^\&@L)$3!3&8I/S^!U*HBJ M@+`/N,')NL>X%AL<(E]E5!\:4H)R)(!T7S(8*E2;HZ2FLKBOMK2XN[^]OL3# MR,K,RM?.U]37O)8X4,6CQ@.^F42YA\8ATN\G& MQM&K&!X<(5]E8C,;/H)R)8!_=EPZ-RM;H*6FM[6RN;>[O;Z]P,;$R1E+3#O+W!R8#&!K(3%(@@',R'QA*3 M#@D)$G:R-!J5U;Z1V'QIC;'.@,8+>!HI(A]D969F)R9K@'(0?H!_?W>!@DLI M*%R:K;&ON;F`O1.^P,3%R\C)RL_3T-?=W-W?QS0GKY#&"]ZMH6E'146I<7Z> MW8#&!G4)$!X/#J*'QA*[&0H*"0VUSS1ZXK]UIXVM4W'#@,8N:1$6%R%D96=J M5AD_N\"_ MN[R]O,#(@,D'R\_7T]??X\V!Q@+$1QZ-QE>P:3HU*RLP-2!!8B<7&HG&2`D) M"A`.#FS&QN"\QF]!R<:5QL9>#`D)G\_/5@\;'A$/M:/3QL[&RAD;'QPI96,D M9')?(D=R-!==?QL45H*`79"0A5,7?<"\@+T)O[_"R"YSQL?#50T<(1PP95@7+G)4$C!R&A0B6A44)GDG*9"0CHE>*G&\O;V_ MP+_"R!O+W&Q,+#RM3(TIO&7\6_N)%T0B4:&S0?"@X0#PD/ M#@L*&!`.%J+'-0]S&A%WE1,VQL:0(3>WS[^MP9%"/:*E6"6\QA\0"Q46%1A= M*A041B`4(AT5%!(6%A,4&10:D)"&@I>0=$^5M\G&Q,?0UZ+&0]QV$@P0#0D* M"0\*#@\-#1D2#@XYQA,-&A,1%6D3%KB]P4.MQ\"TT*F&)4JDHZ0Y2Y(4%@P6 M%1(/1A04$A<3%!,1%100@!,'%!,4%Y"-73>`EP=W+YVVP\+.W*7&3"T,%1,, M"0D-"A`0%1$7$PX0#I<0#Q`0$@T3$Q!6?IE&'215R->T.58BLZ:SCQQ5E8>%Q<0 M"AH?$"$8$A2`$`@4$0X4#@X6"Q"!$PM6&A06P].TC,;&M%.GQB%O"0L0"0X, M"0D*&!,8$1,+%!<6&189&!@;&142%0P-#`P.@!L3-_:X#A(0#A44#A<>#0H4 M&PX@$@Z!#!@+#`H/"AP9#`D1#!$2$Q0<&,2D&5W&QN#1I\95,0D*#@\,"@P) M$!460B46$1(B'Q\@(2@N-1DV$S<5$!%B@5"PP/$`L?$1D7834;.\:4.K^GQCT_"@D+$0L)"Q80 M(QLP,AL.$B,=*"DD'B8G(CD2)R,2%A0*#!@;),+,)Q\9%0P+"2DW"Q`9'0\/ M"@H)"0L)"X`)%!00'1H+"0P1$QT<&!0I&AH>K#H=KJ?&'5\-"0L1"PL,%R%@ M'"%A(4%103$!D3&!04&!@-$1<*"1(0$]-]6A`0#`T0%PH*$Q4< M#A`,"PD*"0N`"1@*#0H+)BD3'1T3(A<-"@H-#1@9&!@Q&1R#I,8`1H`)-`T- M$1<4-6,_,247%A19J<%@H) M#`D+#Q4,)3Y&.AH;+"D;%Q83#PP/6UEB2$@]%!`0#`X-#!0)"PH/$!T:'!W$ MQL;%G,9@:`P)"0H+#Q0.%!4/#!<1%A$+"0D+"@L)"@L+#!,6&!87&!87$Q$0 M%A(/#14X3W@L"0H)"0P2#!PH/D`A+3XW(AP<&AD=,4U$0$A(*Q80$`X-"PL- M"1`*"@LC(A<9C95)CIS&`$"`"0X*"P\3#Q06$@P9%181"PF`"BD+"0L,"PL4 M&!@7&!<6&142%!<2#PL/%2EV-S(*"0H*$`P;(#4])S=$/"2`&PT<*#]$/3)% M0B84$!`.#8`+#`D/"@D*'A\8&F)I'WN;Q@&Q#H`)&PL*#A`6&!L:#R`9%0P, M"0L,#`D+#`P*#!8=&!J`%QP:%Q88%Q,3#1H-#!(WL1@*"PH-#!L=("LR1$5" M*8`4'Q@[1CXY)SDQ*@X.#PX/#0T+"0H+"@H+#!DC&A<==;:ZF<8!*0J""4D0 M%1<;&AL0%A`-#`H)#`X+#`\-#1`0%AL:&AD8&1D8%A4;$1,6&Q,.#"W.7`H. M"PD*$AH;&BI$145#$@\.$#](/B8<*"X>%Q8,$(`-#PL*"@D+"PH*$RX5%AM) M07"8Q@"T@@E2$A40&1D7'!`3%!8*"1`0$Q(3%QL8&AP;%A89&QP:&1L7%1@5 M&!,7%"8.#!@FH1$6#`X5$1<4$!@M145#+1L7$"U(+!0,%!8/$1P8$0L0#PT- M"PR#"04+#!,=(D.8QB!A"0H*"0D,$Q47&1D3&10-"Q$,#A48&1LF*2HY+R`A M&AN`&AX8&A@;&R,7%!47)A@1%19_%2$."0H*%@T0#AE(2D@\@!T"&"(6@`H; M#`D)$!H9"PX0$`\,%`P*#`D)"@D801\<(\9C?I3&`X<5"0J`"6(.%189&A<0 M%PL+$1$,(2\I*B0B'APK,CDO*B@?'!D;&1@:&B`6%Q(7(AT5$QHI%AT+"0D* M%PL0#A5(2&(X#A,9'!P8$1`0"PD)"QD7$A`.%18/%@H.#@D*"@D-(@\/&D(G M*\F2Q@+))PJ""0`/@!4K%A(.#@H2#1`.8(>EH)Z=H7(F)BDS.#$H'!P9&!@; M&!L8%Q<2+!L5%A8G*1F`"0(*%@V`$"D\14\P#0X0$Q87&QD<&!$1#!@6$Q`3 M%A42&@T.$0L0#`D*#@D9'1P='[62Q@*_"@J!"1`+$1<4$!@6#0L/$PL2$J"T MR8#&'&A`6&QL6&A42%Q$3 M%@H-"@D9,Q$5'7IGDY#&%*D0#`H+"PH,'B00"QH9"PP+"@T7@X?&$M%V)R0J M-"$F(Q4B&Q4=%Q,1%AB`&0(Z*Q&`"30+#A02$A$/$B(B)1DB$A,.%A\A&`\. M$!<@+!&!<.%AP=(AL+(A@@+QH9&!`7(`X2(@PI#`QA*1$<((/& MRHW&!+,5%`P2@`H+'S,=$QL9#PL,$QLAB\9-S9.\).C<83RB(D'1\0"@DL+!L='18+"Q80'C:-QA&]4Q,< M'QT8'A`2%1D3%A$=$0Z`"3<*#1`4#@T3%!4>.BL>(!(5$1D=%2`A*B4<"1H5 M%QP7(AX;(1X9&2(:%Q@B#A09#Q8)(1T-&QD7M(S&$\><."0F&1(?("`9'1<, M"PX6&1%)A,8!NM&$QA#%N!H3&AP8%Q%1`6'2$8*14:&Q$*#R2`&A@Z*!XW(!H@'AL5'!<1$R,-'0D\)PD.%Q=R MC<82P)@]*1@8%QH=&AD/"PT.%QL3<(+&!,Y\4E*OA,8.H1X-$!(/%1$3%!87 M#1(0@0DX"@L/#A05&147$1HS-"4A&!0?,S8A-!05&10+#",9&!)S:U9)(BPU M'QP:&QH7&1@1'PDI$0D)#Q8TCL81OF`J&1D7&AP4$0T-#@X2'1*G@<8(TYXX M+"==:(C$@<8.?QX3#0\/%!,7%Q@6#0\+@`D\"@H-$0\2%AD5&A(8-#0A(AD: M+#=()#`1$1<5"PH@&Q40=Z.8BG5^;#LU)QX<&QL7$QH+(PD2$@L0,<-OS(S& M"(,U&QH;&QH."X$.`PT?&-"`QAO(WFX>+2H2#$:RR<;&QV`=&0P0$1(7'1L9 M%PX-@0DA"PH.$1`0%AH4&148,3`>(1D?-S!0(RP/$!86"PL?'A(078#&%\?( MHV5<12TD'AH:%18.(@D;&0D+0:P7S8W&!GH;'1H0$!.!#@,+$!U3@<8;UQ@0"0P) M$Q8H/"L@$Q`8$1$*#`D)#!`8&QD5%Q@;'S$S,38\+1L=&"(J/SU%L.%R@!`# M#`L5Q(C&#]2C/B(=&A$/#0D)"A,^QLZ,Q@S'B%M>-3*C,\+"XE M)BDW-S%"G,3*OUL0#0P)"BNUA\8/R,*UHC`>&!0/"@D)$#W.3XW&"ZEM1B1# M%!8-#1(29(C&&;N<4RL@&!<;%@X.#`ZN2PL+"0D,0M:)Q@W"L((?&A0/#`H*'$4> MT8S&"[-I319*%P\.#QH8FHG&&,238A8=&!8/#@T-4\#%/"M$1!T8%Q$-$0Z` M"A4+#1`;&QD;&AH9'#<_.#1!-T$Q)&6>@L8":0T+@`D!$Y>*Q@S0M<&!4/ M"PD/$1*WC,8+O%UF#D,?#@X/(C;$B\8NIAL=&!(-$`HHH<;&0B)!1"D;'!4, M$@T)"@D)"Q`;'!@<'1D=)SQ"131%/$`R2)Z#Q@)W$`R`"0$*18S&#;EK+!L3 M#0D,#!"8QKK%B<8*S%B,$RLD#@\4*8>,Q@C,4!D+#A$6#8"`Q@MC(SQ$/AH? M'`H6#PJ`"1(+#QD=&1TB'25`/4!%1$4W/&FOA,8"@1$-@0D!(,6,Q@S(;S`: M$0D+#!"&PX;`B<8*U&BQ-2&-Q@;?00D.&!88@<88W#PB/D,>'!X, M&`\*"0H)#!$9'1TC(B,]1(!%!$1%/W[*A<8(K0H)"0P)"1O`CL8*MQL6#PP- M#AZJ#K.*Q@C#O%5((A$0'#2/Q@6Z"1$K',2"QA?,(B)%/R$B&QH*"PD)"Q,4 M&QXK,RPB,3>!10%IOX?&!]()"@D="@D@D,8)E24:$`L/$1L.I(O&![]I2BL; M$QB=D,8#Q"L0?X/&"'2(>'B,S,SP\)A77B<8& M4PD)'`X*-)'&"[XL'1,1"PX,8HT_GHC&!\6213X5&%3`D<8"L["]@\8)Q[R5 M/44Z+"$4"8`*`A,G#X`>"1L?'!L4$14-/,B)Q@;%"0H@&0E;D<8+Q;)'(",5 M'@\Q/%S!B<8%E1@7$QVPG<8'P&XX/"\9$PF`"@<-(1-Q9GZ4-(`-`PH+"9:* MQ@;*&`D>'0EZD\8(IV0O*3(F/C^HBL8%M0D)%DK,G<89R*)W6RX;%0H*"0H* M)!ZIHK/"*PD*"PD)#[V+Q@4O"1T4"864Q@>@>EE".%=VQ(K&!=$1##J)R9_& M%KZ-5$4J#0L*"@DE)\TL8(1A,)"0LJ#1!X@<8$ ML3\3(G*-Q@B5"0L)"@D)%;K1Q@AZ#PH)"@T80Z."Q@3$?QIR@XW&"&\)"0H) M"0H1MM'&!RH)"0L8-9_-A,8#K"J]@XW&`U\)"@J`"0$+L=#&"+T7"@D6*;'! MQX3&`]DPQ9&-Q@,_"0H*@`D!#++/Q@?9/1H*"BB=Q8;&`\Q-QL.,Q@*0%@N` M"0,*"A6ZS\8&H1H8"0MEQ8C&`GS&S8S&`D\2"X`)`PH)+<+/Q@5='Q(-#:6) MQ@"LCL8"'AP,@`D"#!]CT,8$2Q82%Q**Q@#,CL8'&2$-#`L,#6K1Q@5E&2<. M'=Q@6<.R0D@Y73Q@+7N<2>Q@6"B3<] MH]34Q@&SSY[&!9"GK c #661B18", " , c #78443A", " < c #721110", " 1 c #61332A", " 2 c #7C231D", " 3 c #533226", " 4 c #978A8D", " 5 c #AF0A0A", " 6 c #841111", " 7 c #783226", " 8 c #B80D0C", " 9 c #981514", " 0 c #DDDACE", " q c #881918", " w c #B0A5B9", " e c #74352F", " r c #CCA799", " t c #ADA8AC", " y c #9B9897", " u c #651413", " i c #712C22", " p c #710C0B", " a c #8E1817", " s c #861B19", " d c #E4100C", " f c #9B1010", " g c #B49795", " h c #EB0909", " j c #3E302B", " k c #8F5D53", " l c #9E0909", " z c #701717", " x c #D1CBCF", " c c #846E69", " v c #9987A2", " b c #291413", " n c #281212", " m c #691110", " M c #BA0A0A", " N c #DED4D5", " B c #71291B", " V c #918E90", " C c #721F1C", " Z c #664231", " A c #7D1313", " S c #C2B5C0", " D c #6B332C", " F c #D40909", " G c #66625F", " H c #460A0B", " J c #446CCF", " K c #CB0A0A", " L c #BB100E", " P c #867A85", " I c #C64529", " U c #273FA2", " Y c #B70A0A", " T c #A19AA6", " R c #811B1A", " E c #441916", " W c #A50C0C", " Q c #521110", " ! c #C2BDC3", " ~ c #580C0C", " ^ c #0E0E0F", " / c #481210", " ( c #751818", " ) c #E0DCDD", " _ c #C90C0B", " ' c #B5B2C0", " ] c #A898B0", " [ c #722522", " { c #8F1B17", " } c #78201E", " | c #8D1515", ". c #7C1918", ".. c #831615", ".X c #E20909", ".o c #950909", ".O c #7D100F", ".+ c #9D7E7A", ".@ c #792C22", ".# c #878382", ".$ c #BC897E", ".% c #2C2622", ".& c #D7D4D7", ".* c #F30909", ".= c #693D33", ".- c #CDCBD7", ".; c #510C0B", ".: c #0E0B0B", ".> c #ABA3AF", "., c #AE1914", ".< c #6B1414", ".1 c #CB0909", ".2 c #5B513C", ".3 c #65463C", ".4 c #1E2856", ".5 c #6A0909", ".6 c #8A3425", ".7 c #381913", ".8 c #930D0D", ".9 c #D5D099", ".0 c #774E3D", ".q c #403F35", ".w c #3F231D", ".e c #7B0909", ".r c #211110", ".t c #655A56", ".y c #171010", ".u c #BC6F59", ".i c #AB0A0A", ".p c #51423F", ".a c #931110", ".s c #D2C4AD", ".d c #7E6F7F", ".f c #7B1616", ".g c #BC1914", ".h c #602519", ".j c #DAD5C2", ".k c #B7AAA3", ".l c #9C231C", ".z c #67382D", ".x c #D90909", ".c c #BAB4BD", ".v c #A48997", ".b c #D2C4C4", ".n c #AF2B1E", ".m c #EBEAE3", ".M c #A30F0F", ".N c #7D1C1B", ".B c #841918", ".V c #931313", ".C c #8B1615", ".Z c #1A0D0C", ".A c #640909", ".S c #635A43", ".D c #C07D63", ".F c #8B0B0B", ".G c #651817", ".H c #C20909", ".J c #591715", ".K c #A21111", ".L c #9C3122", ".P c #6A241F", ".I c #9E0D0D", ".U c #775B53", ".Y c #A11513", ".T c #C7C3C9", ".R c #280D0C", ".E c #720909", ".W c #8D4941", ".Q c #5B5655", ".! c #8B1111", ".~ c #A54427", ".^ c #E1E0DF", "./ c #8D4037", ".( c #A11B16", ".) c #727072", "._ c #7C0C0C", ".` c #310E0E", ".' c #621110", ".] c #5A1212", ".[ c #B30A0A", ".{ c #532318", ".} c #521F17", ".| c #792623", "X c #A7A29F", "X. c #B6ABBB", "XX c #7D1F1D", "Xo c #908099", "XO c #7B1B1B", "X+ c #90878F", "X@ c #C5B698", "X# c #E90A0A", "X$ c #100F0E", "X% c #A50909", "X& c #580909", "X* c #2A1717", "X= c #65503D", "X- c #3D0C0C", "X; c #B00E0D", "X: c #807B7F", "X> c #7A1D1D", "X, c #781D1B", "X< c #5A0F0E", "X1 c #EF0909", "X2 c #696765", "X3 c #605B45", "X4 c #CD130F", "X5 c #D20A0A", "X6 c #4C0A0A", "X7 c #533E2B", "X8 c #850A0A", "X9 c #3C59B3", "X0 c #C00C0C", "Xq c #C70909", "Xw c #971915", "Xe c #7E1A1A", "Xr c #7E7580", "Xt c #5E0C0B", "Xy c #5D0A0A", "Xu c #520909", "Xi c #8B2520", "Xp c #C85C48", "Xa c #CEC5CB", "Xs c #6C2A1F", "Xd c #642B21", "Xf c #9B1212", "Xg c #706A68", "Xh c #841919", "Xj c #A7999E", "Xk c #69201C", "Xl c #E7E0E0", "Xz c #9C6F65", "Xx c #C3B9C0", "Xc c #826D48", "Xv c #AFADA9", "Xb c #8A2B22", "Xn c #741413", "Xm c #9A929B", "XM c #CBB5B4", "XN c #8F5341", "XB c #783C31", "XV c #73211F", "XC c #911515", "XZ c #630D0C", "XA c #881616", "XS c #E5E4E1", "XD c #6E1B1A", "XF c #DC0A09", "XG c #741616", "XH c #8E7F85", "XJ c #591B19", "XK c #8A201B", "XL c #BE0909", "XP c #4E1A18", "XI c #FEFDF6", "XU c #6A0C0C", /* pixels */ " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXI.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXIXIXI.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXIXIXI.$Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.s N.D.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ).S.~.~.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.c kXp N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g I.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.~ & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ;.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xp.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X ; r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ; & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XzXp N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g.~.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXMXMXM r &XMXM N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.~ & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl rXp : :X#.X h hX#.X :.X.X.X.x.x :Xp.u &.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XN.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b & :X#X1.*.* : dX5.x F _ K.,.nX0 _X5 _ FXFX4X4.x.xXp.D r N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xp.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.s :X# hX1 h.XX5 8 L.LXw 9 9Xh q.|XB 2 qXCXC |.VXi.6X; # _ _.x.X :.D r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X Xp r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXpX#.*.* :X4 _X;.KXhXh.=.| X X.< i 1 1 1.P i.G u.<.=.zX>XhXh.V | #X;.n KX4Xp rXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ; & `Xl r.$XpXpXpXp.$.$XM N ` ` ` ` ` ` ` `XIXI 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXpX#.*X1.*X5.,.6 2XhXO z D.=.3.3 GX2.).d.dXrXrXrXo P PXrXg.3 , DXk zXO [ , {.KX0 _ KXp rXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ;XpX0 8 # | a. RXhXe qXf.L.u rXl ` ` `XIXIXI @.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0 & :.*.*X#X0.K R.=XDXd.=.t GX2X2.).d P P P P PXoXoXoXo ] ] v ] vX+.# V.d.U.3.P.NXhXC.VX0X0 _.DXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXpXF.!.~ { XXD.< > D u.'.XOXCXK.L _ : &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0.uXFX0XCXD.~.L.U P P PX+ P P.d.U.3Xd -XJ.f ; @ 0 0.+ g ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.SXcXcXN.6.|X,.'XJ.Q G G G P PXo PXrXo vXo v v v ] vX+Xo vXo v ] ] ] ] wXmXm T.>XmXm c.U 1.z q.KX0 +Xp.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X@ IX# 8.! [XrXB kXj v v vXoXoXo v vXoX+.U D , @.j @ c.m.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` eX7XcXcXzXb.V f.8 pXd.t.d.d.d.) P.d P P ]Xo PXo vXo vX+ v vXo v v ] wXmXm TXm T.> w w ' w.d.W C RXC #X0 I rXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+X0 h.* 8 f { k.3Xz.b v vXo v v v v v vXoXo.k g @.s c.s r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.WXz.mXS.j i.N aXC.V 6.O.6.d.d.)Xr P P.dXr PXo P PXoXoX+ PX+ vXm ]XmXmXmXm T T w.>.> w.>.> wX..> c ,XGXh.K 8.n &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X@.NX0.*.*Xq $ $Xp.sXzXzXoXoXo v vXoXo vXoXo P.s @X@.q o (./XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.WXz.mXS.D .X>.NXh qXb 2.o.8 ,.).dXo P P P v PXoXoX+ PXo vX+ vXm VXmXm Xm ] ] ].> w T.>.> w.> w.> tX..c wXz e i , #.g &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.jXMXi 8.*.*X5 $.,.p.yXs.uXo v vXoXo v vXo ].kX3 O.yX2.U 3 A ;XM ` ` ` ` ` ` `.-XS ` ` ` ` `.WXz.mXSXbX> <.fX, }.= 7 |.M.oXC.0Xr.)Xr P P PXo PX: PXHXoX+ v V V XmXm ] ] ] w w w w wX. TX. w wX. S.cX..cXj c C |.K.g &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ).^ 0.b.| W.*.* + 5.F.yX$ 3.~ k v v v v v T .%.j 0.4 J.4.4X9 U.d.-.-XS.- * J J J J.- ` ` `.W ;.m.j.P X iXdXZ > i [.NXhXf.! { A.U P PXo P P PXoX+Xo vXoX+X+XmXm VXmXmXm ]Xm ] T wX. w.>X. w wX. tX.X.X..c SXx t c [XhX; 8.u N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS 0 ` `.bXiX0X1.*.x 8X0X-.% k.~.n.WXo v v ] ] ].) 4XI.- J J J J U U U U U U UX9 U U J J JX9 * w ,.W @X@Xd.< [.|.< Q.=.P zX>.N s ,XC.8.l kXoXr P vXoXo v X+X+ VXmXm ]XmXmXmXm ] T T T w.>.>.>.>X. t tX. ' S S.c.c.c.c !.+ iXh 9 8.DXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.m ` ` `.bXbX;X1.*XF.I.[.Z.% j.~ & @ 0Xm ] N !.d &X9X9.- `Xl.Q O.4.4.4.4 O O O O.Q.4 U U U * J.= i @.u ( mXnX>X>.'.p G.t.z C D.=.| a.V.oXb cXoXo PX+X+X+ vXmXmXmXmXm ] wXm T T.> w.>.>.>X..> tX..c t.c.c !.c S !.T.T.T.TXj k. ./.n &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0 ` ` ` ` `.bXi L.*.*.X.I lXtX* j B.D.s gXIXIXI J.Q 0XIXIXIXIXIX+.4.4 U U.p.4.Q.% O.q.)X2X9 J J /.G 0.uX, - 1XnX, iXP.QX2X2X2.3 D X.NXeXA s.C.6 cX+X+X+ w v ]Xm V ] wXm T T w wX. w wX.X. tX.X.X..cX..c.T !.T.TXa.-.T.-Xa ! c [.K.g r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi M.X.*X#X;.!.i l =.w.~.$.m @ ` J.-XIXIXI @ 0 0 gXoXo ] .) j.4Xo.- ` `.>X9.]XnX@Xb.N - G.=.P DXkXJX2X2X2XgXg G.= CX>.= 7.V W.6.dX+X+XmX+XmXmX+ Xm T T TX. w w.>X..>X..> tX..c SXv S ! !Xx !Xa.T.T.-.T.TXa.c kXO.M :XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi 8 h.* h.[XD <.i./.3Xp.uXl ' J *XIXIXI.sX3X@.sXo v ] T T .U./.b ` ` `.^.J }.U i.P - G GXd z.N.<.pX2X2XgXg.).).) G.3 [.N a f |./ P vXmXm V VXm ] T T ] T T T w.>.> wX.X.X.X.X..c.c !XaX.Xx ! ! !XaXaXaXaXaXa.&.& S.WXA.KXpXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi.,.X.*.*X0 eXVX;.,.UXp & J J J `XI @.s.q.+ @.s ] ] ] T wX. 4 e.$ ` ` ` zXD D DXVXJ G G GXdXGXV 3.QX2XgXg.).).).).).) ,.PXe.@ 7.I.WX+Xm ] Xm TXm TXm.>.>.>.> T.>X.X. tX. tX..c.c S.T ! !.T !.T.TXa.TXa.-Xa x.&.& xXj.W a #.u ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.m ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` xXi M h.*.* _.W.UXOX%./ ;.W J J J @ @X@.%Xg @.jXj ] ] ] ].>X. w ! ) g.W N.bX6Xn.f . (Xk G GX2X2 1.z DXJXgXg.).).).).).).)XrXr.U.S D R f.Y.WX+XmXm ]Xm T T T T T.>.>.> t w.c t tX..c S.c.c ! % ! !.T.T x x !Xa.& x.&.&.&.&.&.k.WXi ; & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.9.q y ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXiX;XFX1 h K.6Xo ,.OX U.6 J JXl 0.t j O.+.s c ] ] ] ]X.X. ! ` ` ` NXlXM.G zX>X> .XJ G GX2X2 GXD. XD.pXg.).).).).).).)XrXrX:X:Xg ,.|XhXi.@.W.v ] T TXm T w.>X..>.> w w tX..c.c S.c.c.c ! ! !.T.T.T xXaXa x.&Xa x.& x.&.& ) ).c.U a IXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM.k.9.qX$ t ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi.( F.*.* F.LXHXo y ^.4.L.dX9Xx.q.q.4.% c g k.v ] w.cX. x ` ` ` ` `.k Q .XVXV C.{ G GX2X2X2 G > C 3.t.).).).).).).)XrXrX:X:X:X:X:.U.U e.C 9.WXm T T TX..>.>.>X. wX.X.X. S.c.c.c.cXx.T.T !.T.T.TXa.T.-.- x.& x.&.& ).& ) ) ).&.v 2Xf.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` `XS.jX@X X .c ` ` ` ` ` ` ` ` ` ` ` ` ` ` r.g.H./X@.qX$ O.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXh 8X#.*.*X5.l P.4 J O ^.h rXI 0 ' *X+ @ 0.+ c.W gX.X. x ` ` ` ` `.+.'XV D D [.J GX2X2X2X2Xg GXd D -.).).).).).)XrXrX:X:X:X:X:.#.#.#Xr , }.CXb kXm T.>.>.>.>.> w wX..c !X..c.c.c.c.T ! !.TXa.T.T.T.T x x x.& x.&.& ).& ) ) ).^ !Xz |., & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` `.m 0.s.kX cXcX3X3X3X3Xv r.D.$.+.kXS ` ` ` ` ` rX5.xX5 = O.yX$X$X: ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` rXh 8XFX#.*.XX;X2 J J U ^.+ @ @ 0.t.+.s.+ 4 ] kXz.v ! ` ` ` ` ` cX6Xn.f .XGXJ GX2X2X2XgXg.).t X.<.p.).).).)Xg.)XrX:X:X:X:.3Xg.#.#.#.#.#.U.U.@Xw ;Xm.> w.> t w tX..cX..c.c.c %Xx.T !.T.-Xa !.- x.TXa x x x.& x ) ) ) ) )XSXSXS.&Xx kXfXp.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` `.m.jX@ cXcXcX3X3X3.p.q.2.q.. I ;.~Xi.@ ,XM ` ` ` NX4X1.* FXPX$X$X$X$ O ` ` ` ` ` ` ` ` `Xl N ` ` ` ` ` ` ` r |.,X5 h.* h.l J J J J.4.2 =.p.4 O O O.% wX.X. %XMXz g ` ` ` `.0 < XXOX,XnXP GX2X2X2XgXg.).).U.PX7 G.).).) =.w.)X:X:X:.q o j.#.#.#.#X+X+ V c ,..XwXzXjX.X. S '.cX.X..c.cX..cXx !.T.TXa.T.T.TXa x x.- x.&.& )XS.m.m ` ` ` ` ` ` ` `XM./.K.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` `.j.+ c.2.q.q j j j j.q.q.q.h ; &.u.~ #Xh RX> r ` `Xp h.*.*.oXZ.yX$X$X$X$.T ` ` `Xl k.^ ` `.D j.^ ` ` ` g ` ` `.k q 8.xX#.* d J J J J.4 ^ ^ BXs O ^ O ^X9X..k.& ` ` N ` ` x `XJ.] }XV C C =X2X2X2.Q.w G.).).) 3 i -.).).Q oX*.w.)X:.3.r o b G.#.#Xr.tX+ V V VXH k.U { k T S.cX..c.c.c.c.cXxXx.c !.TXa.T.T x xXa x )XS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` `.+.% O O O.y.y.y O O O.%.% |.D &.D.(.K.VXC R.f g rXq.x.1 MX8X6 QX$X$X$X$ y ` ` ` g o.Q ` x E n.Q ` ` r E.# ` ` ` r q 8X5 hX1 J J J.4X9X9 U ^ 1.~.4 ^.y.4 * 2.3.^ ` ` ` !.:X: HXt i [ [XD 1X2X2 G.w oX*.t.)X2X* QX>.3.) oX* o n.w.Q b b o n.%X:.p o o.# V V V V V y c.6 {XzX..c.c.c.c S !XxXxXx !.T.TXa.T x.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` `.T.c.c.c yX:.).pX$X$X$ OX*Xb ; ; :.i W.MXf.YX;Xq M.M fXUXyXuXu q QX$X$X$.% ! ` `.W.Z.r y.D n n.Z t ` 1 b n.T ` ` `.$ a.,Xq & * J U J U U J U O.4.~ U U UX9.pXP.p.^ `.^.%.:.r HX<.f. .NXn.7.QX2.q b o bX*.t j.r o =X7 = nX* o n nX* bX* o n b.w n o o.t V V V VXm y y yXH c.6XzX..c.cXa !.T !.T !Xa x.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` `.^ y.pX$.r._.M.a.FX%XL K.1 L.a M.xX;.!X6X-X- H R zX-X$.y.Z.p ` x.7.Z.ZX* j.r n.ZX* g o b.r j ` ` ` `Xz.L.jXI.- J.4 J J J U U O O.4.6 U U U U.q.7.U `.+ oXJ o H < (Xn ..'.`X*.Q o b o n bX* b b o n.J Q nX* o.r.r b b o b n o bX* o b.q V V VXg.w V y y y y 4 kXiXz.c ! ! !Xx.T x.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` `.z.F $.. R.! W $XF F.F $ K.[ f Q Q.J Q.G z.f <.` o.ZX$ y.v.r.Z.r.y.y.r n.y.Z.7 n b.r.r.t.$.$ rXz.~ 2XK.~.QX9 J.- @.s.q.4.4 ^ UX9 UX9X9 U.4X*.U E EXJ /.' XXV [XV.<.` b b b b o n b b n b o b nXJ.w b b.r.rX* n o n.r o b o o bX* VX+.pX* o.t y y y y T TX .+XN.u S.T xXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` `Xz M.[ f.C.C K +.MXA.F.oX#.*.1X8 u u -. EXk.{XP.{.{ - (XJ >._.]XPX.SXV u./Xc.(.O.].h.JXy.`.R /.h B B.h.uXI.m./.n.nXK.7.}.Z.RXU.i l f {.l.' ~.'.B.f X zXtX- HX-XuXuX6X&X&X6XyXuX&.AX6X&XuX mXu.]XV 3 -X7 1 j = 3XP 1 =Xd =.6X= DXf a.3.~XG.aXw.h.!X&Xu.R.}.h B.~.h 0.mX7 I.n.LXK.h /X-X6XuX& j.q.pX6.A.' XXD }XO.; / ~X&X6.AX&.E.E ~.E.A ~.E.A.5.5.A < < <.hXs.hXU.o l M.M.K {._ B 3.! z.J /XkXP.}XD E.}.k.=.} C.U ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` `Xl.V m 8.* WXh 6 W W.8 ~ >.J j.D.9.h.~.~X7 OXG z Q.]XPXV 3XJ =.P j.P 1 - 1.PXd 3.N ,.|...6./.K #.I.!.F.E.e HX-.h B B.h.z @.%.n.n.n.L B.}X<. >XkXJ.3 jX6.AXU q.f X <.;X- Q ~Xy.E.E.5.eXU.E.eXUX8.EXt.E.5 p (.< 6 Z.~., K., LX0 8.M |._Xd 7X;., W.O.G.<.}XP E - E -Xk.}.^ ` ` N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` 7 I $.* _.VX;.FX;.VXi.| u.v &.D.~.6.6X7 O /XDXb.J E = C =.PXJXkXdXX - -XJ.PXJ.PXK D.! R.=Xb 9 f.V.Y.8.o.e H.}.h B B.7.m.%XK { 2XK B.{ /.! 6 [ iXA mX&.5Xt AXn (XZ ~ ~Xt.;.;.5.e.E.e.e.EX8.o.F 5.o 5X%X% l (.,.u.u.~.g.H +.,.l.(.(Xw.8XKXw M $.[.aXb.!.'XP EXJXDXPXP.k N cX>Xx ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` `.j.~ $ YXq.[.o l.a #XhXKXXXC.u.9.D I.h 7.q O o Q. } Q -.]XJ.].J z u.]XPXXy.EXU uXnXG C p.' Q QXt.;.E.eX8 YXq _.x +.x.x.1 K FX;X5 K _ : I IX4.g.n.g.n.YXw.LXK p.8 K M M $X0 $.i 7.h.X-.`.R.r j cX@.sX@ qX8.o.E.A.'.eX8XU < A.fXU QX7X=X3X3.2 D R.N 7 e e 7XXXhXh q a.K.MX; 8X4.D.D.u.u.DXcXcXc ;.L., #.M.!.8 MX; LX;X0.L F.HX0X5Xq +X0 8.@XkXJXJ - }XP.b ` ` `.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` rXL.1.X +.XX#.H 8 f f.V 6 p.] R 9 # LX0.( z.<.G Q.]X&XZ.A.A.A.AX&XyXZ.A.AXyXUXZ p.E p A aXGXh..XAXAXh. . |Xh q 9.KXf.! z i <.'.;.R.:X$X*.q 3X@XNXK.o.e.E.5.E.EX8.F AXZ uX> } DX=X3 D i.= Z.SX=.=.|X>X>X>X>X>X>X>.|X=.SXc.0.6./XcXcXc.~.,.( # 9.M.O lX; W Y.[ _Xq.1X0.g K.HXqXq.g.~.~ A. .}.}.+ g.U.PXB ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` `.b.g FXF F F +.x W.[.[.M f 9...fXh.N RXOX<.|XkXD (.'XZXU ~X& ~.A ~XZXt.AXZ.AXU.AXZ.5.A p.f.fX>. Xe X. XwXA | qXe s.f.fXeXh.(.| 6.V |.F B.`.R.R.R b.z.u.sXw.EX8XU.EX8.!.FXZ XX>X>X> [ D.=.=.SX3X3.SX=.6XC.V | | |Xh.|.SX3.S.2.3Xd 1.2.3 Z eXf.I W $.a fX8 #.M M $X0 MXq.H K _.1 KX5Xq _X0.H.l 7 u - E -XX.}.^ `.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` I _ F.X.X F.H.[.oX% $.K..Xf q.NXeXeXO.N.'.<.P m ~.'XZXZXuX&XZXZX.N RXV D.SX3X3X3X3.S { W.M.M $ f.6XcXcXc , 7XiXK 7XB.zXs z z. .! W.a.a.IX; 8X; W.[ MX0XqXL K _ _ F KX5 +.g.~XNXw. -.}.+.W.l.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` &XL l FX1.X + F.M.Y.C.V mXh qXh z mX>.'.f u u.JXGXuXZX& Q Q.' u u.]X<.J.G -Xk.G.PXD CXD ..fXG.fXhX,.NX> X R.N. .Xw a |XCXhXCXD q A A.BXn.{ 7 /X6 ~XD / 3 &.j 6 9 ( W.[.a | 6 6XGXO.V.MXf s 7.SX3X3X3.S.3XV.NXh | f #./XcXc.L.,.( _.Y.lXw.M l.! . C (.!.!.F f.K.MX0X;X; 8.[X0.[.HXF.1 F + +.x.x + _Xq { u [XJXbXiXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` `.$.xXLX0XqX5.H.H.H 5 $.V. .< zXhXh R..} 7XD f 6.Y.B EXz.9XwXiXb L.x hX5XL.[.f.. W f.K $.M./XcXc.UXcX3.=X>X>X>X> R qXb.6.K M $ M 5.[ WX%.i l.8 qXe XXG.F._.K.a f f #.M _., _X; K _X0.H F FX5.x F K ; ;.6 s.l.} e `XMXp.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` `.$ _ F.1X0.H +.X h FXL f |.fXG XXh R. XG m z.'XyX&.'.]X<.G ~XJ.z.=XB 7 DXs 7 i -Xk.h = 1 ZX=X=.= D D D [XVX> .Xh.NX>Xh.N aXe {XeXV {.CXh 9Xf.{.}XbXiXA..Xf.C.N.P -.(XbXw _.x.xXF Y M. | K fXCX; 9.(XcXcXcXzXc.~ WXf.YXh.NX>X,X>XAXf.K f f 9.iX%X%X%X%.a sXA.fXn.e. .I |.( a.M #.( #.H 8.nX0Xq KX5X5X5 +XF.g :X4 _X; XXJ e.P.n.P N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` NX5X#XF FXq.x F.X + +XL.KXCXh.<.<.G.< 2XX A aXe a.N.N q RXeXhXC.N q /.} e.NXA | a.C | [.= eXi #Xq.x.HXFX;XL..XC $ #.V.K L #./ ;XcXcXc.g $X; 8X; _XfXCXC. }XVXkXsXdXkXnXn A.8.8.BXA A A.O.O...KXKXC 6.VXK 9.IX0.( # W.[.g L +.x.xXF +XF.x :.~.Y.fXb.lXVXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` `.$XqX%.x F.[X5XLX&X6.`._ qXhXn.<.; mX>X,XnXZ pXU.< uX& ~.G Q.J N ` ` ` ` ` ` ` ` ` ` ` `Xl gXN CXd.= D } i.z C.=.= [XX.NXG |XO ..| RXCXh s.NXC.` = eXw | a.Y.Y qXX.S.=.,., _ F.H.1 FXFXf 9Xf.MX0XCXfX0 f.Y.nXNXc.L.gX0 9.( L.VXf 8.K |XwXKXi.6.,.Y 8 f.aX,.PXV. A.O._ a.BXK s f a { {.VXf.(.(.KX0.,., # MX5 _ FX5.X :.u I.g 8.B iXV.b.$.L.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` k <.;.RX8 $.x.F.5 H.RX-.|.| XXZ p <.N X u.5XUX6XtX& ~ ~XD ~.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.$ e uX>XV D.=.3 i } e.| zXnXi.P X...NX> a.C u.` CXC aXhXhXhXh { eX= D RXF.x hXqXLXLX0X;Xf 9Xf 9.V.V $.M f.(.L.n.6.6.,.lXb.l L 9.MX0.(Xw.@.L 7.(X; # LX;.(.(XiXs.z C.O < s 7Xi..XwXiXK f.V.(XK a.M.(.L., M L.~X4 +.XX4XFXF.XX4.g.IXKXDXbXb.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` k m.;.R.R f.I.F.F.F.A.e [ e [.< pX,. X,XG u.`.:.; ~ ~.G -XV ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXz.JXJ -.|X> C i [ [ 2 ZXkXhXn |.NXn.C.7 /XhXe.BXCXh.NXh.@.U.U 7 9 F.HXqXF.[X;.MXLX5.K a a # #.VX;.(Xb.L.n./.6.l.LXb {.VX;Xf.V.Y 9XX.l eXwXwXi L.,.l.l.l.@ iXd.< p i.@.B R i e R R {.|XA #.Y {XbXK LX;.L.L LX5 IX4.x d.u.D I + A.l.|Xs.+ ` ` `Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` `.+.J.. 6._.! AX8X8 YX#.X 7.= iXOXnX>X, X.<.`.:.:X-.J ~ .XyXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.v e z u zX>.| DX= [.N ..f qXG 6.J.Z.<. Xf A..XA 9XX e Z.@.,.x 8XLX; FX; $ fX;Xf 8 aXhXA.MXA.V.n./.0.W./.6Xb.lX0XC.C.M.. 2.l L q.(XV i ZX=.~.6.(XK.6 7XK 2Xk.G uX> } i.|X>..XK 2 2.NXA {Xb {.Y.K f.l./X4X0.L.gXF :Xp : dX#.X M a.P.6 NXx k.z ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` N i.L I :XK.|.'X8.H +.(.= DXk XX>X>X>.G.R.:.:.: E Q.' } ~XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM k u u C i }X>X>XG }.f.O u.Z EXe.fXn. .! 6Xe.6 6.Y F.1.1.1 + $XLX; +Xf 9 |X;X0 a A 9 |.C {XB ,XB.6.n.6XKXf 9 |.K # 2XX {.C } D.P 1.z.6Xi.YX% {XbXw 6 2 C.JXD.@ i 2.N } i }X>Xh s s.| RXh a |XiXb.M 8.g.~X0X4 IX4.*X1 I :.XX; s 1 E > EXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` `.s ;.~.6 D [ R < z i [ C }XG XX>X>.J.:.:.:X$.: EXP.P.' i ` ` ` ` ` ` ` ` ` ` ` `XM N ` ` ` ` ` ` ` ` ` ` ` ` ` ` 3.`.].'X> CX>XGXGXD >.r.R.f z A.B 6._ 9. .I.*.X h.1.HXLXF.[ $ $X0 8.V | f qXCXG |.K., s.6.~XBXBXb.L s.C.Y #XA aXi iXK {.zXXXn >XkXD 6 l Y Y q 7.NXD X C.hX=.S i }.=.3 [X, R [ 2X>.N RXC 2 2 |.YXf.Y ; MX;.n : h IXp IX1.X _XX>XD >.R.:.:X$X$X$.:XP.} 1 uXz ` ` ` ` ` ` ` ` ` N.DXp.~Xi.uXM ` ` ` ` ` ` ` ` ` ` ` g =.w.Z.r.R.`.R.;.. /X$ oXnXnXG.f.f._ p 6 #.1.*.x.* h.HXL.[Xq W.MXfX; | qXAXeXC |XhXA.MXh s./ ,XB 7XB.,XhXh.( [XB.0.0 7.6 , > u.].hXJ z.I.F Y.8 i B...B < mXH g.+ cX:.0 i i.=X= DX>.NXX.N sX>XOXhXhXK.(.KXf.L.n.x d I.*.*.*X1.X.I E E i ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` `.+.=.@.N. .N.N.NX> .X-.`.: ^X$X$.:X$X$.:X- = - Q N ` ` ` ` ` ` `XS 0Xp d & d I.l 6 p <.U ! ` ` ` ` ` ` ` c = - - /.R.r.R.7 n o >X> X.N XX,.f <.E.I.H.H F.XXq hX0.H.i.H fXf a 8 L.Y.f.N f 9 R R 9 aXhXBXN.6 2.@Xi. .| 2./ , Z.UX=Xs.z - ~ m ~.J.G .N RXeXh 9Xi.YX;.g I h d : :.* h K.J.W.&.+XP.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` `XM.W.NX>X>XD.J.`.r O ^X$X$X$X$.:X$.:.: QXd u k ` ` ` ` ` ` `.m 0.j &X@.j : ;.n..X&.J =X7 c.^ ` ` ` `.^ =XJ.GX< ~XZ.'. -.O.[.IXq K.H.xXL.x.1X5 MX% $X;Xh 9XA 9XC ..f.V.CXe q.(.6XB.@ {.| 7 7Xb i i Z DXG.0.0Xd Z.h Q.}X7.{.{.G m 6Xn.PXsXn p.O.E ~.b ` ` ` ` ` ` ` ` ` ` ` ` % g.+.U.= [.NX>.N R.N.YXf 9., MX4 :.*.*.*X#.H ; 3 E o.v ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` `.^.%.y.yX$ ^ OX* OX$ OX$X$X$.:X$.:.y.J -.]XM ` ` ` ` `.m.m.m.mXS.sXzXBXi {XCXe / BX7.wXZ DXM ` ` `.k.}.}.' H ~X&Xy.<.; E.{ -.G u u z . { K.I.C L + 8X#Xq _.1XLXq.I f $XA q RXAXf.N.f A.Y a. .|.6 i.| 2.6 1 Z 1 , 1.2.z.{.h.3.{ 3 3 ZX7.2.2.2X= 1.h.G >XD.. 6 p pXt ..b ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXM 4 k D }Xh.NXh a |.K #.,XLXF d h.X F / E o = ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` `.T.% j.p G.Q.q 4.%.qX$.%.:.:.:X$.R.P.J.W ` ` ` ` ` ` ` ` ` ` ` ` g./ D , k -.w jX7X7 /X-X-.p.+.k.U.{.J HX& ~.;X& m u E EX7X= Z 1Xd X A 6.8.B.YX5.K dXF 8.H MXL _.I.a.! R.NXhXh.. z (. XhXOXX 7XB.=.=XB Z.3.2.S 3 - e.{.{ 1 =X7 3.S.2X3X3Xv `XS 4Xd QXX> X a.! f 8X; +XFXF FX<.7 EXM ` `.& ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` `.bXg GX:.Q.q.t j.%.y j.:X$.:X$.`.h.< % ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g 3 j jX7 j j.7.7.%.w.w.w QX-.; /.;Xt.< k.U =.2 Z.SX3X3Xd ..B.aXA $.[.Y.K.XX;X5XL Y.i.H.!.8 9XO.NXe {XnXO.N aXCXOX,XK i e.=.0.2 1.2 1 3 1 3X7.PX=.2 [ Z.SX3Xv ` ` ` ` NXz.J ~XUXZXt.A.E.eXw.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXz.@ }X> {.. f.OX8XLXq.x.H.O.JXM x.p.3 ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ).#.) V.% O.%.Q.y.y.yX$.:X$ b E.' k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv.t j j.w.w.7.7.wX*.7X- / /X6 ~.' g ` %.3.3 Z.SX3X3X=Xh.C.K.V.aX%.I.(X5 LX#.X M.i.i.I 6 < 6.NXO.N R.NXOX> (.NX> a a C.=XcX7X7 ZX=.2.3X7.2X7.S i .X= c x ` ` ` ` ` ` `.kXJX6 HX6.A.5X%.1XL.LXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.k.WX>.NXe.C 6X%.I M.1Xq K.~X* n o N ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` `Xv G x.qX$X$ G OX$X$X$X$ ^ =XJ.P.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx 1 /.w j.w E / HX- /X6Xt.' g ` ` `.+.= [ ZX3.S.S i CXV C. X% $XwX;X;XLX#.i.[X% l._Xy < 9X>XO.N qX> X.N a.N.N 2Xs.3.S.SX3.2X7X3X7.SX3 Z [.|.0Xj ` ` ` ` ` ` ` ` ` N.J / H HX&.5.X h.x 5.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM k iXeXO.K 6.8 YXq 8.8.Z.r.r r ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` x.Q `.)X$.:.q.%X$X$X$X$ b D u.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.2 E.;.;.; Q Q.w /.;XD g ` ` ` ` `.W } i.SX3.SX= zXV.P.P.!.i {Xw #.i + + MX% l.[XZXZ.NXhX>X>Xh R [ [XK.| i.3.S.2.S.2X3X3.SX3X3 Z.= }XzXv ` ` ` ` ` ` ` ` ` ` ` `XB.]X< ~Xu.e F.x.*XqX8.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N kX> } X 6 W l W.[XU.y.r g ` ` yXM ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` `XSXg ! t.q.q.%.q.yX$X$ O - i ,XS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ kXuXu.; QXP.w Q >.b ` ` ` ` ` `Xl.WX>.|X=.S.S =.G C.P.B 8XKXw # 5XL.H.H Y.o.O p.'.NXhX> XX>.|.| [.|.@X=.SX3X3X3X3X3.SX3X3X3.0.$Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXy.5.5.E.e.8 l.i lX8 g ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` %.U.N. Xn.O.F.I $._ Q.nXMX X$.+ ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` !X `.Q.#.q.%.%X$ ^.'X>Xs.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.vXuXuXP j = >.b ` ` ` ` ` ` ` `Xl.WX> }.0X3.S ZXd [.|X,. 2.[ W.HXL 5Xq.F } m uX,.N 2 [ D.=.= D [ iXB ZX=X3X3X3X3X3X3 cXv ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X&Xy.E.E u =X8.E.E.A.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g 7 i X.O <.F $ f 6.C =X$X= ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv ` c c.p j c ^ n s. .v ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b ,.w Q ,.b ` ` ` ` ` ` ` ` ` `XlXz [ D.S.S.2 3 1.z 1 C C W.[.i Y Y 5.C 7 -.'X> } C.| [ }XX }XV D.=.=.=.3X=.2 3 3 /.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` kX&.E.eXU =X<.5Xy.P ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.+ DX, iXn A.O.F.a ~ ~XP.+ 4 cXB r ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.v k.W.W.n.7.G.BXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM ,.3X3X3X=.zX7Xs z.O.o 5X% M.i.i.YXNXd ~X> } }X>X>XD C.P - -.G Q / HX-.7X6X6 k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NX&.AX8.o.~ B.E.A k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` % kX=.@ R Z.fXV.P < D 1 ZX3 c ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g.xX#XF _.Y.N.WXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.$XB.3.3.= i > z.O l 5.o 5X;X% W.6 BXt k g.$.$.kXxXM.3XuXuX6 H HX6X6X6Xu e.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` e.E.o l.6.n M.e.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.+ i.S e.zX3.zX3X3.S c ) ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NX0.*.*.KXXXzXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` r.+XBXVXV >.< p._.F.o # l l.CXB.]XM ` ` ` ` `.b -XuXuX6X6XuXuXuXu.J.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xy.e {.l YX%.e.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.k.# k.S.S c cXv ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$X5 9./.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXM r./.'.5X8._ 8 l.i l 2 6 g ` ` ` ` ` k -X6Xu ~.;XuXuXu.J.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM ~.{X=.n.1X%.eXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl./X&.e.E l M FXL.Y.e.+ ` ` ` ` `.|XdX,.'XD.J u u k N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X7X7 Z.~X4 5.oXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XB.5.F 5XF.*.X f.o.W ` ` ` ` ` DXD D > D >XD.PXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.w.hXKXpX4 Y.o.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ;.i.i.1X#.xXF $.o.G ` ` ` ` `.= } Z z Z DXDXVXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X .w u. .~X0Xq l k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$.i Y.[Xq + + 8.a.E , ` ` ` ` `.2 [X=Xd.3.S ZXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 1XU p B.6 L Y.iXb ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.k ;.[Xq.1.iX;.i._ p.e.E.+ ` ` ` ` `.p.=.SX7.P.z ,Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.kX&.EX8.iX0Xq YX%. .b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X e l.1.XXF.H.C.f.FXU.AXy , ` ` ` ` ` `.pXP i 3.y.yXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.GXy.E l.i M.[Xq 5X8.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` k 2.Y.X hX1Xq.8 1 mXt QXd g ` ` ` ` ` ` `.).p n o.% O ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz.A p.F l.i M + Y lX8Xz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+ 6 YX5.*X1 5.F m.{ Q.U.k ` ` ` ` ` ` ` ` `.cX:X$.p.).p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXu.A.5 l Y.xX1 +.H 5X8.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 1 l.1.*.xX; >.}.UX XS ` ` ` ` ` ` ` ` ` ` ` ` tX$X:.c.p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXy.5 p.o Y.*.*.x.1XL l > ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl k.<.iXL.X.i 3X7Xx ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X$ y ` G ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz /.A p.[X5X#X1.XXLX%.o [ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.gX0 B.i F.[.GX3.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.q.c `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$ lX8 ~.5X8.oXL.x.i.iX8X8.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.D IX0., + F._.t.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` y.c ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xi 8 IXtX&.E.E lX%.F.E.A e ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xp., :X4 :X5.!.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.B.6.l.IXF.8.[.*.*X0 q.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz.g I.~ d.gXX N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.|./ 6 8 :.V.g.D d.g ; ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.D.~.n ; ;.l k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXB 7.V.,.u |.~ d.X., k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXN.0.(XNXB.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `./X, aXN.gXA./ ;.g.Y g ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXi 1.s.D N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.k 1XiXN ; 7 ,XcXcXBXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T.sXz.s 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` y.q ,.0XcXd {.L.0XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv.s.j.sXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X .p [Xb.6.w.$.D r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.&.s.^.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.# y.+./ 7 k.k.sXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.s ` x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` VXa.#.s.s.m V.s ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.&XS V.s.s `X .s ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.c.j 0 `Xv 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X ) ` `.^ y ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.TXv ` ` `.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xg ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `" }; nethack-3.6.0/win/Qt/qpe-nethack.control0000664000076400007660000000067112504242744017130 0ustar paxedpaxedFiles: bin/nethack pics/NetHack.png apps/Games/nethack.desktop games/lib/nethackdir/[a-r]* games/lib/nethackdir/[t-z]* games/lib/nethackdir/save games/lib/nethackdir/s*.* games/lib/nethackdir/[A-Z0-9]* Priority: optional Section: qpe/games Maintainer: Warwick Allison Architecture: arm Version: 3.5.0-1 Depends: qpe-base ($QPE_VERSION) Description: NetHack - The Dungeon Game Graphical version of NetHack for Qtopia nethack-3.6.0/win/Qt/qt_clust.cpp0000664000076400007660000000721412536476415015701 0ustar paxedpaxed/* NetHack 3.6 qt_clust.cpp $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "qt_clust.h" static void include(QRect& r, const QRect& rect) { if (rect.left()r.right()) { r.setRight(rect.right()); } if (rect.top()r.bottom()) { r.setBottom(rect.bottom()); } } /* A Clusterizer groups rectangles (QRects) into non-overlapping rectangles by a merging heuristic. */ Clusterizer::Clusterizer(int maxclusters) : cluster(new QRect[maxclusters]), count(0), max(maxclusters) { } Clusterizer::~Clusterizer() { delete [] cluster; } void Clusterizer::clear() { count=0; } void Clusterizer::add(int x, int y) { add(QRect(x,y,1,1)); } void Clusterizer::add(int x, int y, int w, int h) { add(QRect(x,y,w,h)); } void Clusterizer::add(const QRect& rect) { QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2); //assert(rect.width()>0 && rect.height()>0); int cursor; for (cursor=0; cursor=0) { include(cluster[cheapest],rect); return; } if (count < max) { cluster[count++]=rect; return; } // Do cheapest of: // add to closest cluster // do cheapest cluster merge, add to new cluster lowestcost=9999999; cheapest=-1; for (cursor=0; cursor=0) { include(cluster[cheapestmerge1],cluster[cheapestmerge2]); cluster[cheapestmerge2]=cluster[count--]; } else { // if (!cheapest) debugRectangles(rect); include(cluster[cheapest],rect); } // NB: clusters do not intersect (or intersection will // overwrite). This is a result of the above algorithm, // given the assumption that (x,y) are ordered topleft // to bottomright. } const QRect& Clusterizer::operator[](int i) { return cluster[i]; } nethack-3.6.0/win/Qt/qt_win.cpp0000664000076400007660000037256412536476415015361 0ustar paxedpaxed// NetHack 3.6 qt_win.cpp $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ // Copyright (c) Warwick Allison, 1999. // NetHack may be freely redistributed. See license for details. // Qt Binding for NetHack 3.4 // // Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no) // // Contributors: // Michael Hohmuth // - Userid control // Svante Gerhard // - .nethackrc tile and font size settings // Dirk Schoenberger // - KDE support // - SlashEm support // and many others for bug reports. // // Unfortunately, this doesn't use Qt as well as I would like, // primarily because NetHack is fundamentally a getkey-type program // rather than being event driven (hence the ugly key and click buffer) // and also because this is my first major application of Qt. // // The problem of NetHack's getkey requirement is solved by intercepting // key events by overiding QApplicion::notify(...), and putting them in // a buffer. Mouse clicks on the map window are treated with a similar // buffer. When the NetHack engine calls for a key, one is taken from // the buffer, or if that is empty, QApplication::enter_loop() is called. // Whenever keys or clicks go into the buffer, QApplication::exit_loop() // is called. // // Another problem is that some NetHack players are decade-long players who // demand complete keyboard control (while Qt and X11 conspire to make this // difficult by having widget-based focus rather than application based - // a good thing in general). This problem is solved by again using the key // event buffer. // // Out of all this hackery comes a silver lining however, as macros for // the super-expert and menus for the ultra-newbie are also made possible // by the key event buffer. // extern "C" { // This includes all the definitions we need from the NetHack main // engine. We pretend MSC is a STDC compiler, because C++ is close // enough, and we undefine NetHack macros which conflict with Qt // identifiers. #define alloc hide_alloc // avoid treading on STL symbol #define lock hide_lock // avoid treading on STL symbol #ifdef _MSC_VER #define NHSTDC #endif #include "hack.h" #include "func_tab.h" #include "dlb.h" #include "patchlevel.h" #include "tile2x11.h" #undef Invisible #undef Warning #undef red #undef green #undef blue #undef Black #undef curs #undef TRUE #undef FALSE #undef min #undef max #undef alloc #undef lock #undef yn } #include "qt_win.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include #include #include "qt_clust.h" #include "qt_xpms.h" #include #ifdef Q_WS_MACX # include #else # include #endif #ifdef _WS_X11_ // For userid control #include #endif // Some distributors released Qt 2.1.0beta4 #if QT_VERSION < 220 # define nh_WX11BypassWM 0x01000000 #else # define nh_WX11BypassWM WX11BypassWM #endif #ifdef USER_SOUNDS # if QT_VERSION < 220 # undef USER_SOUNDS # else # include # endif #endif #ifdef USER_SOUNDS extern "C" void play_sound_for_message(const char* str); #endif #ifdef SAFERHANGUP #include #endif // Warwick prefers it this way... #define QT_CHOOSE_RACE_FIRST static const char nh_attribution[] = "
NetHack" "
by the NetHack DevTeam
"; static QString aboutMsg() { QString msg; msg.sprintf( "Qt NetHack is a version of NetHack built\n" #ifdef KDE "using KDE and the Qt GUI toolkit.\n" #else "using the Qt GUI toolkit.\n" #endif "This is version %d.%d.%d\n\n" "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n" #ifdef KDE "KDE:\n http://www.kde.org\n" #endif "Qt:\n http://www.troll.no", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); return msg; } static void centerOnMain( QWidget* w ) { QWidget* m = qApp->mainWidget(); if (!m) m = qApp->desktop(); QPoint p = m->mapToGlobal(QPoint(0,0)); w->move( p.x() + m->width()/2 - w->width()/2, p.y() + m->height()/2 - w->height()/2 ); } NetHackQtLineEdit::NetHackQtLineEdit() : QLineEdit(0) { } NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) : QLineEdit(parent,name) { } void NetHackQtLineEdit::fakeEvent(int key, int ascii, int state) { QKeyEvent fake(QEvent::KeyPress,key,ascii,state); keyPressEvent(&fake); } extern "C" { /* Used by tile/font-size patch below and in ../../src/files.c */ char *qt_tilewidth=NULL; char *qt_tileheight=NULL; char *qt_fontsize=NULL; #if defined(QWS) int qt_compact_mode = 1; #else int qt_compact_mode = 0; #endif extern const char *enc_stat[]; /* from botl.c */ extern const char *hu_stat[]; /* from eat.c */ extern int total_tiles_used; // from tile.c extern short glyph2tile[]; // from tile.c } static int tilefile_tile_W=16; static int tilefile_tile_H=16; #define TILEWMIN 1 #define TILEHMIN 1 /* XPM */ static const char * nh_icon[] = { "40 40 6 1", " s None c none", ". c #ffffff", "X c #dadab6", "o c #6c91b6", "O c #476c6c", "+ c #000000", " ", " ", " ", " . .X..XX.XX X ", " .. .....X.XXXXXX XX ", " ... ....X..XX.XXXXX XXX ", " .. ..........X.XXXXXXXXXXX XX ", " .... ........X..XX.XXXXXXXXX XXXX ", " .... ..........X.XXXXXXXXXXX XXXX ", " ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", " ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", " ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", " ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", " ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", " ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", " +++..ooooooOooOOoOOOOOOOXX+++ + ", " ++..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..oooooOooOOoOOOOOOXX+++ ", " ..oooooooOoOOOOOOOOXX+++ ", " ..ooooOooOOoOOOOOXX+++ ", " ..ooooooOoOOOOOOOXX++++ ", " ..o..oooOooOOoOOOOXX+XX+++ ", " ...o..oooooOoOOOOOXX++XXX++ ", " ....OO..ooOooOOoOOXX+++XXXX++ ", " ...oo..+..oooOoOOOXX++XXooXXX++ ", " ...ooo..++..OooOOoXX+++XXooOXXX+ ", " ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", " ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", " ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", " .....XXX++++ XXXXXXX++ ", " ....XX++++ XXXXXXX+ ", " ...XX+++ XXXXX++ ", " ", " ", " ", " "}; /* XPM */ static const char * nh_icon_small[] = { /* width height ncolors chars_per_pixel */ "16 16 16 1", /* colors */ " c #587070", ". c #D1D5C9", "X c #8B8C84", "o c #2A2A28", "O c #9AABA9", "+ c #6A8FB2", "@ c #C4CAC4", "# c #B6BEB6", "$ c None", "% c #54564E", "& c #476C6C", "* c #ADB2AB", "= c #ABABA2", "- c #5E8295", "; c #8B988F", ": c #E8EAE7", /* pixels */ "$$$$$$$$$$$$$$$$", "$$$.$#::.#==*$$$", "$.*:::::....#*=$", "$@#:..@#*==#;XX;", "$@O:+++- &&; X%X", "$#%.+++- &&;% oX", "$$o.++-- &&;%%X$", "$$$:++-- &&;%%$$", "$$$.O++- &&=o $$", "$$$=:++- & XoX$$", "$$*:@O-- ;%Xo$$", "$*:O#$+--;oOOX $", "$:+ =o::=oo=-;%X", "$::.%o$*;X;##@%$", "$$@# ;$$$$$=*;X$", "$$$$$$$$$$$$$$$$" }; /* XPM */ static const char * map_xpm[] = { "12 13 4 1", ". c None", " c #000000000000", "X c #0000B6DAFFFF", "o c #69A69248B6DA", " .", " XXXXX ooo ", " XoooX o ", " XoooX o o ", " XoooX ooo ", " XXoXX o ", " oooooXXX ", " oo o oooX ", " o XooX ", " oooo XooX ", " o o XXXX ", " ", ". "}; /* XPM */ static const char * msg_xpm[] = { "12 13 4 1", ". c None", " c #FFFFFFFFFFFF", "X c #69A69248B6DA", "o c #000000000000", " .", " XXX XXX X o", " o", " XXXXX XX o", " o", " XX XXXXX o", " o", " XXXXXX o", " o", " XX XXX XX o", " o", " o", ".ooooooooooo"}; /* XPM */ static const char * stat_xpm[] = { "12 13 5 1", " c None", ". c #FFFF00000000", "X c #000000000000", "o c #FFFFFFFF0000", "O c #69A6FFFF0000", " ", " ", "... ", "...X ", "...X ... ", "oooX oooX", "oooXooo oooX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", " XXXXXXXXXXX"}; /* XPM */ static const char * info_xpm[] = { "12 13 4 1", " c None", ". c #00000000FFFF", "X c #FFFFFFFFFFFF", "o c #000000000000", " ... ", " ....... ", " ...XXX... ", " .........o ", "...XXXX.... ", "....XXX....o", "....XXX....o", "....XXX....o", " ...XXX...oo", " ..XXXXX..o ", " .......oo ", " o...ooo ", " ooo "}; /* XPM */ static const char * again_xpm[] = { "12 13 2 1", " c None", ". c #000000000000", " .. ", " .. ", " ..... ", " ....... ", "... .. .. ", ".. .. .. ", ".. ..", ".. ..", ".. ..", " .. .. ", " .......... ", " ...... ", " "}; /* XPM */ static const char * kick_xpm[] = { "12 13 3 1", " c None", ". c #000000000000", "X c #FFFF6DB60000", " ", " ", " . . . ", " ... . . ", " ... . ", " ... . ", " ... ", "XXX ... ", "XXX. ... ", "XXX. ... ", "XXX. .. ", " ... ", " "}; /* XPM */ static const char * throw_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " ", " ", " ", " ", ".... X ", "....X X ", "....X XXXXXX", "....X X ", " XXXX X ", " ", " ", " ", " "}; /* XPM */ static const char * fire_xpm[] = { "12 13 5 1", " c None", ". c #B6DA45140000", "X c #FFFFB6DA9658", "o c #000000000000", "O c #FFFF6DB60000", " . ", " X. ", " X . ", " X .o ", " X . o ", " X .o o ", "OOOOOOOOoooo", " X .o o ", " X . o o ", " X .o ", " X. o ", " . o ", " o "}; /* XPM */ static const char * get_xpm[] = { "12 13 3 1", " c None", ". c #000000000000", "X c #FFFF6DB60000", " ", " . ", " ... ", " . . . ", " . ", " . ", " ", " XXXXX ", " XXXXX. ", " XXXXX. ", " XXXXX. ", " ..... ", " "}; /* XPM */ static const char * drop_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " ", " ..... ", " .....X ", " .....X ", " .....X ", " XXXXX ", " ", " X ", " X ", " X X X ", " XXX ", " X ", " "}; /* XPM */ static const char * eat_xpm[] = { "12 13 4 1", " c None", ". c #000000000000", "X c #FFFFB6DA9658", "o c #FFFF6DB60000", " .X. .. ", " .X. .. ", " .X. .. ", " .X. .. ", " ... .. ", " .. .. ", " .. .. ", " oo oo ", " oo oo ", " oo oo ", " oo oo ", " oo oo ", " oo oo "}; /* XPM */ static const char * rest_xpm[] = { "12 13 2 1", " c None", ". c #000000000000", " ..... ", " . ", " . ", " . ....", " ..... . ", " . ", " ....", " ", " .... ", " . ", " . ", " .... ", " "}; /* XPM */ static const char * cast_a_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " . ", " . ", " .. ", " .. ", " .. . ", " .. . ", " ...... ", " .. .. XX ", " .. X X ", " .. X X ", " .. XXXX ", " . X X ", " . X X "}; /* XPM */ static const char * cast_b_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " . ", " . ", " .. ", " .. ", " .. . ", " .. . ", " ...... ", " .. .. XXX ", " .. X X ", " .. XXX ", " .. X X ", " . X X ", " . XXX "}; /* XPM */ static const char * cast_c_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " . ", " . ", " .. ", " .. ", " .. . ", " .. . ", " ...... ", " .. .. XX ", " .. X X ", " .. X ", " .. X ", " . X X ", " . XX "}; NetHackQtSettings::NetHackQtSettings(int w, int h) : tilewidth(TILEWMIN,64,1,this), tileheight(TILEHMIN,64,1,this), widthlbl(&tilewidth,"&Width:",this), heightlbl(&tileheight,"&Height:",this), whichsize("&Zoomed",this), fontsize(this), normal("times"), #ifdef WS_WIN normalfixed("courier new"), #else normalfixed("fixed"), #endif large("times"), theglyphs(0) { int default_fontsize; if (w<=300) { // ~240x320 default_fontsize=4; tilewidth.setValue(8); tileheight.setValue(12); } else if (w<=700) { // ~640x480 default_fontsize=3; tilewidth.setValue(8); tileheight.setValue(14); } else if (w<=900) { // ~800x600 default_fontsize=3; tilewidth.setValue(10); tileheight.setValue(17); } else if (w<=1100) { // ~1024x768 default_fontsize=2; tilewidth.setValue(12); tileheight.setValue(22); } else if (w<=1200) { // ~1152x900 default_fontsize=1; tilewidth.setValue(14); tileheight.setValue(26); } else { // ~1280x1024 and larger default_fontsize=0; tilewidth.setValue(16); tileheight.setValue(30); } // Tile/font sizes read from .nethackrc if (qt_tilewidth != NULL) { tilewidth.setValue(atoi(qt_tilewidth)); free(qt_tilewidth); } if (qt_tileheight != NULL) { tileheight.setValue(atoi(qt_tileheight)); free(qt_tileheight); } if (qt_fontsize != NULL) { switch (tolower(qt_fontsize[0])) { case 'h': default_fontsize = 0; break; case 'l': default_fontsize = 1; break; case 'm': default_fontsize = 2; break; case 's': default_fontsize = 3; break; case 't': default_fontsize = 4; break; } free(qt_fontsize); } theglyphs=new NetHackQtGlyphs(); resizeTiles(); connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool))); fontsize.insertItem("Huge"); fontsize.insertItem("Large"); fontsize.insertItem("Medium"); fontsize.insertItem("Small"); fontsize.insertItem("Tiny"); fontsize.setCurrentItem(default_fontsize); connect(&fontsize,SIGNAL(activated(int)),this,SIGNAL(fontChanged())); QGridLayout* grid = new QGridLayout(this, 5, 2, 8); grid->addMultiCellWidget(&whichsize, 0, 0, 0, 1); grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0); grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0); QLabel* flabel=new QLabel(&fontsize, "&Font:",this); grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1); QPushButton* dismiss=new QPushButton("Dismiss",this); dismiss->setDefault(TRUE); grid->addMultiCellWidget(dismiss, 4, 4, 0, 1); grid->setRowStretch(4,0); grid->setColStretch(1,1); grid->setColStretch(2,2); grid->activate(); connect(dismiss,SIGNAL(clicked()),this,SLOT(accept())); resize(150,140); } NetHackQtGlyphs& NetHackQtSettings::glyphs() { return *theglyphs; } void NetHackQtSettings::resizeTiles() { int w = tilewidth.value(); int h = tileheight.value(); theglyphs->setSize(w,h); emit tilesChanged(); } void NetHackQtSettings::toggleGlyphSize() { whichsize.toggle(); } void NetHackQtSettings::setGlyphSize(bool which) { QSize n = QSize(tilewidth.value(),tileheight.value()); if ( othersize.isValid() ) { tilewidth.blockSignals(TRUE); tileheight.blockSignals(TRUE); tilewidth.setValue(othersize.width()); tileheight.setValue(othersize.height()); tileheight.blockSignals(FALSE); tilewidth.blockSignals(FALSE); resizeTiles(); } othersize = n; } const QFont& NetHackQtSettings::normalFont() { static int size[]={ 18, 14, 12, 10, 8 }; normal.setPointSize(size[fontsize.currentItem()]); return normal; } const QFont& NetHackQtSettings::normalFixedFont() { static int size[]={ 18, 14, 13, 10, 8 }; normalfixed.setPointSize(size[fontsize.currentItem()]); return normalfixed; } const QFont& NetHackQtSettings::largeFont() { static int size[]={ 24, 18, 14, 12, 10 }; large.setPointSize(size[fontsize.currentItem()]); return large; } bool NetHackQtSettings::ynInMessages() { return !qt_compact_mode; } NetHackQtSettings* qt_settings; NetHackQtKeyBuffer::NetHackQtKeyBuffer() : in(0), out(0) { } bool NetHackQtKeyBuffer::Empty() const { return in==out; } bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; } void NetHackQtKeyBuffer::Put(int k, int a, int state) { if ( Full() ) return; // Safety key[in]=k; ascii[in]=a; in=(in+1)%maxkey; } void NetHackQtKeyBuffer::Put(char a) { Put(0,a,0); } void NetHackQtKeyBuffer::Put(const char* str) { while (*str) Put(*str++); } int NetHackQtKeyBuffer::GetKey() { if ( Empty() ) return 0; int r=TopKey(); out=(out+1)%maxkey; return r; } int NetHackQtKeyBuffer::GetAscii() { if ( Empty() ) return 0; // Safety int r=TopAscii(); out=(out+1)%maxkey; return r; } int NetHackQtKeyBuffer::GetState() { if ( Empty() ) return 0; int r=TopState(); out=(out+1)%maxkey; return r; } int NetHackQtKeyBuffer::TopKey() const { if ( Empty() ) return 0; return key[out]; } int NetHackQtKeyBuffer::TopAscii() const { if ( Empty() ) return 0; return ascii[out]; } int NetHackQtKeyBuffer::TopState() const { if ( Empty() ) return 0; return state[out]; } NetHackQtClickBuffer::NetHackQtClickBuffer() : in(0), out(0) { } bool NetHackQtClickBuffer::Empty() const { return in==out; } bool NetHackQtClickBuffer::Full() const { return (in+1)%maxclick==out; } void NetHackQtClickBuffer::Put(int x, int y, int mod) { click[in].x=x; click[in].y=y; click[in].mod=mod; in=(in+1)%maxclick; } int NetHackQtClickBuffer::NextX() const { return click[out].x; } int NetHackQtClickBuffer::NextY() const { return click[out].y; } int NetHackQtClickBuffer::NextMod() const { return click[out].mod; } void NetHackQtClickBuffer::Get() { out=(out+1)%maxclick; } class NhPSListViewItem : public QListViewItem { public: NhPSListViewItem( QListView* parent, const QString& name ) : QListViewItem(parent, name) { } void setGlyph(int g) { NetHackQtGlyphs& glyphs = qt_settings->glyphs(); int gw = glyphs.width(); int gh = glyphs.height(); QPixmap pm(gw,gh); QPainter p(&pm); glyphs.drawGlyph(p, g, 0, 0); p.end(); setPixmap(0,pm); setHeight(QMAX(pm.height()+1,height())); } void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment ) { if ( isSelectable() ) { QListViewItem::paintCell( p, cg, column, width, alignment ); } else { QColorGroup disabled( cg.foreground().light(), cg.button().light(), cg.light(), cg.dark(), cg.mid(), gray, cg.base() ); QListViewItem::paintCell( p, disabled, column, width, alignment ); } } }; class NhPSListViewRole : public NhPSListViewItem { public: NhPSListViewRole( QListView* parent, int id ) : NhPSListViewItem(parent, #ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better QString(QChar(roles[id].name.m[0])).lower()+QString(roles[id].name.m+1) #else roles[id].name.m #endif ) { setGlyph(monnum_to_glyph(roles[id].malenum)); } }; class NhPSListViewRace : public NhPSListViewItem { public: NhPSListViewRace( QListView* parent, int id ) : NhPSListViewItem(parent, #ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better QString(QChar(races[id].noun[0])).upper()+QString(races[id].noun+1) #else QString(QChar(races[id].noun[0])+QString(races[id].noun+1)) #endif ) { setGlyph(monnum_to_glyph(races[id].malenum)); } }; class NhPSListView : public QListView { public: NhPSListView( QWidget* parent ) : QListView(parent) { setSorting(-1); // order is identity header()->setClickEnabled(FALSE); } QSizePolicy sizePolicy() const { return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); } QSize minimumSizeHint() const { return sizeHint(); } QSize sizeHint() const { QListView::sizeHint(); QSize sz = header()->sizeHint(); int h=0; QListViewItem* c=firstChild(); while (c) h+=c->height(),c = c->nextSibling(); sz += QSize(frameWidth()*2, h+frameWidth()*2); return sz; } int selectedItemNumber() const { int i=0; QListViewItem* c = firstChild(); while (c) { if (c == selectedItem()) { return i; } i++; c = c->nextSibling(); } return -1; } void setSelectedItemNumber(int i) { QListViewItem* c=firstChild(); while (i--) c = c->nextSibling(); c->setSelected(TRUE); } }; NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : QDialog(qApp->mainWidget(),"plsel",TRUE), keysource(ks), fully_specified_role(TRUE) { /* 0 1 2 + Name ------------------------------------+ 0 | | + ---- ------------------------------------+ + Role ---+ + Race ---+ + Gender ------+ | | | | | * Male | 1 | | | | | * Female | | | | | +--------------+ | | | | | | | | + Alignment ---+ 2 | | | | | * Male | | | | | | * Female | | | | | +--------------+ 3 | | | | ...stretch... | | | | 4 | | | | [ Play ] 5 | | | | [ Quit ] +---------+ +---------+ */ int marg=4; QGridLayout *l = new QGridLayout(this,6,3,marg,marg); QButtonGroup* namebox = new QButtonGroup(1,Horizontal,"Name",this); QLineEdit* name = new QLineEdit(namebox); name->setMaxLength(sizeof(plname)-1); if ( strncmp(plname,"player",6) && strncmp(plname,"games",5) ) name->setText(plname); connect(name, SIGNAL(textChanged(const QString&)), this, SLOT(selectName(const QString&)) ); name->setFocus(); QButtonGroup* genderbox = new QButtonGroup("Sex",this); QButtonGroup* alignbox = new QButtonGroup("Alignment",this); QVBoxLayout* vbgb = new QVBoxLayout(genderbox,3,1); vbgb->setAutoAdd(TRUE); vbgb->addSpacing(fontMetrics().height()*3/4); QVBoxLayout* vbab = new QVBoxLayout(alignbox,3,1); vbab->setAutoAdd(TRUE); vbab->addSpacing(fontMetrics().height()); QLabel* logo = new QLabel(nh_attribution, this); l->addMultiCellWidget( namebox, 0,0,0,2 ); #ifdef QT_CHOOSE_RACE_FIRST race = new NhPSListView(this); role = new NhPSListView(this); l->addMultiCellWidget( race, 1,5,0,0 ); l->addMultiCellWidget( role, 1,5,1,1 ); #else role = new NhPSListView(this); race = new NhPSListView(this); l->addMultiCellWidget( role, 1,5,0,0 ); l->addMultiCellWidget( race, 1,5,1,1 ); #endif role->addColumn("Role"); race->addColumn("Race"); l->addWidget( genderbox, 1, 2 ); l->addWidget( alignbox, 2, 2 ); l->addWidget( logo, 3, 2, AlignCenter ); l->setRowStretch( 3, 5 ); int i; int nrole; for (nrole=0; roles[nrole].name.m; nrole++) ; for (i=nrole-1; i>=0; i--) { // XXX QListView unsorted goes in rev. new NhPSListViewRole( role, i ); } connect( role, SIGNAL(selectionChanged()), this, SLOT(selectRole()) ); int nrace; for (nrace=0; races[nrace].noun; nrace++) ; for (i=nrace-1; i>=0; i--) { new NhPSListViewRace( race, i ); } connect( race, SIGNAL(selectionChanged()), this, SLOT(selectRace()) ); gender = new QRadioButton*[ROLE_GENDERS]; for (i=0; iaddWidget( ok, 4, 2 ); ok->setDefault(TRUE); connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); QPushButton* cancel = new QPushButton("Quit",this); l->addWidget( cancel, 5, 2 ); connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); // Randomize race and role, unless specified in config int ro = flags.initrole; if (ro == ROLE_NONE || ro == ROLE_RANDOM) { ro = rn2(nrole); if (flags.initrole != ROLE_RANDOM) { fully_specified_role = FALSE; } } int ra = flags.initrace; if (ra == ROLE_NONE || ra == ROLE_RANDOM) { ra = rn2(nrace); if (flags.initrace != ROLE_RANDOM) { fully_specified_role = FALSE; } } // make sure we have a valid combination, honoring // the users request if possible. bool choose_race_first; #ifdef QT_CHOOSE_RACE_FIRST choose_race_first = TRUE; if (flags.initrole >= 0 && flags.initrace < 0) { choose_race_first = FALSE; } #else choose_race_first = FALSE; if (flags.initrace >= 0 && flags.initrole < 0) { choose_race_first = TRUE; } #endif while (!validrace(ro,ra)) { if (choose_race_first) { ro = rn2(nrole); if (flags.initrole != ROLE_RANDOM) { fully_specified_role = FALSE; } } else { ra = rn2(nrace); if (flags.initrace != ROLE_RANDOM) { fully_specified_role = FALSE; } } } int g = flags.initgend; if (g == -1) { g = rn2(ROLE_GENDERS); fully_specified_role = FALSE; } while (!validgend(ro,ra,g)) { g = rn2(ROLE_GENDERS); } gender[g]->setChecked(TRUE); selectGender(g); int a = flags.initalign; if (a == -1) { a = rn2(ROLE_ALIGNS); fully_specified_role = FALSE; } while (!validalign(ro,ra,a)) { a = rn2(ROLE_ALIGNS); } alignment[a]->setChecked(TRUE); selectAlignment(a); QListViewItem* li; li = role->firstChild(); while (ro--) li=li->nextSibling(); role->setSelected(li,TRUE); li = race->firstChild(); while (ra--) li=li->nextSibling(); race->setSelected(li,TRUE); flags.initrace = race->selectedItemNumber(); flags.initrole = role->selectedItemNumber(); } void NetHackQtPlayerSelector::selectName(const QString& n) { strncpy(plname,n.latin1(),sizeof(plname)-1); } void NetHackQtPlayerSelector::selectRole() { int ra = race->selectedItemNumber(); int ro = role->selectedItemNumber(); if (ra == -1 || ro == -1) return; #ifdef QT_CHOOSE_RACE_FIRST selectRace(); #else QListViewItem* i=role->currentItem(); QListViewItem* valid=0; int j; NhPSListViewItem* item; item = (NhPSListViewItem*)role->firstChild(); for (j=0; roles[j].name.m; j++) { bool v = validrace(j,ra); item->setSelectable(TRUE); if ( !valid && v ) valid = item; item=(NhPSListViewItem*)item->nextSibling(); } if ( !validrace(role->selectedItemNumber(),ra) ) i = valid; role->setSelected(i,TRUE); item = (NhPSListViewItem*)role->firstChild(); for (j=0; roles[j].name.m; j++) { bool v = validrace(j,ra); item->setSelectable(v); item->repaint(); item=(NhPSListViewItem*)item->nextSibling(); } #endif flags.initrole = role->selectedItemNumber(); setupOthers(); } void NetHackQtPlayerSelector::selectRace() { int ra = race->selectedItemNumber(); int ro = role->selectedItemNumber(); if (ra == -1 || ro == -1) return; #ifndef QT_CHOOSE_RACE_FIRST selectRole(); #else QListViewItem* i=race->currentItem(); QListViewItem* valid=0; int j; NhPSListViewItem* item; item = (NhPSListViewItem*)race->firstChild(); for (j=0; races[j].noun; j++) { bool v = validrace(ro,j); item->setSelectable(TRUE); if ( !valid && v ) valid = item; item=(NhPSListViewItem*)item->nextSibling(); } if ( !validrace(ro,race->selectedItemNumber()) ) i = valid; race->setSelected(i,TRUE); item = (NhPSListViewItem*)race->firstChild(); for (j=0; races[j].noun; j++) { bool v = validrace(ro,j); item->setSelectable(v); item->repaint(); item=(NhPSListViewItem*)item->nextSibling(); } #endif flags.initrace = race->selectedItemNumber(); setupOthers(); } void NetHackQtPlayerSelector::setupOthers() { int ro = role->selectedItemNumber(); int ra = race->selectedItemNumber(); int valid=-1; int c=0; int j; for (j=0; jisChecked() ) c = j; gender[j]->setEnabled(v); if ( valid<0 && v ) valid = j; } if ( !validgend(ro,ra,c) ) c = valid; int k; for (k=0; ksetChecked(c==k); } selectGender(c); valid=-1; for (j=0; jisChecked() ) c = j; alignment[j]->setEnabled(v); if ( valid<0 && v ) valid = j; } if ( !validalign(ro,ra,c) ) c = valid; for (k=0; ksetChecked(c==k); } selectAlignment(c); } void NetHackQtPlayerSelector::selectGender(int i) { flags.initgend = i; } void NetHackQtPlayerSelector::selectAlignment(int i) { flags.initalign = i; } void NetHackQtPlayerSelector::done(int i) { setResult(i); qApp->exit_loop(); } void NetHackQtPlayerSelector::Quit() { done(R_Quit); qApp->exit_loop(); } void NetHackQtPlayerSelector::Random() { done(R_Rand); qApp->exit_loop(); } bool NetHackQtPlayerSelector::Choose() { if (fully_specified_role) return TRUE; #if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). if ( qt_compact_mode ) { showMaximized(); } else #endif { adjustSize(); centerOnMain(this); } if ( exec() ) { return TRUE; } else { return FALSE; } } NetHackQtStringRequestor::NetHackQtStringRequestor(NetHackQtKeyBuffer& ks, const char* p, const char* cancelstr) : QDialog(qApp->mainWidget(),"string",FALSE), prompt(p,this,"prompt"), input(this,"input"), keysource(ks) { cancel=new QPushButton(cancelstr,this); connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); okay=new QPushButton("Okay",this); connect(okay,SIGNAL(clicked()),this,SLOT(accept())); connect(&input,SIGNAL(returnPressed()),this,SLOT(accept())); okay->setDefault(TRUE); setFocusPolicy(StrongFocus); } void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) { const int margin=5; const int gutter=5; int h=(height()-margin*2-gutter); if (strlen(prompt.text()) > 16) { h/=3; prompt.setGeometry(margin,margin,width()-margin*2,h); input.setGeometry(width()*1/5,margin+h+gutter, (width()-margin-2-gutter)*4/5,h); } else { h/=2; prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h); input.setGeometry(prompt.geometry().right()+gutter,margin, (width()-margin-2-gutter)*3/5,h); } cancel->setGeometry(margin,input.geometry().bottom()+gutter, (width()-margin*2-gutter)/2,h); okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(), cancel->width(),h); } void NetHackQtStringRequestor::SetDefault(const char* d) { input.setText(d); } bool NetHackQtStringRequestor::Get(char* buffer, int maxchar) { input.setMaxLength(maxchar); if (strlen(prompt.text()) > 16) { resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6); } else { resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4); } centerOnMain(this); show(); input.setFocus(); setResult(-1); while (result()==-1) { // Put keys in buffer (eg. from macros, from out-of-focus input) if (!keysource.Empty()) { while (!keysource.Empty()) { int key=keysource.TopKey(); int ascii=keysource.TopAscii(); int state=keysource.GetState(); if (ascii=='\r' || ascii=='\n') { // CR or LF in buffer causes confirmation strcpy(buffer,input.text()); return TRUE; } else if (ascii=='\033') { return FALSE; } else { input.fakeEvent(key,ascii,state); } } } qApp->enter_loop(); } // XXX Get rid of extra keys, since we couldn't get focus! while (!keysource.Empty()) keysource.GetKey(); if (result()) { strcpy(buffer,input.text()); return TRUE; } else { return FALSE; } } void NetHackQtStringRequestor::done(int i) { setResult(i); qApp->exit_loop(); } NetHackQtWindow::NetHackQtWindow() { } NetHackQtWindow::~NetHackQtWindow() { } // XXX Use "expected ..." for now, abort or default later. // void NetHackQtWindow::Clear() { puts("unexpected Clear"); } void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); } bool NetHackQtWindow::Destroy() { return TRUE; } void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); } void NetHackQtWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr"); } void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); } void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel) { puts("unexpected AddMenu"); } void NetHackQtWindow::EndMenu(const char* prompt) { puts("unexpected EndMenu"); } int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; } void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); } void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); } //void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); } void NetHackQtWindow::UseRIP(int how, time_t when) { puts("unexpected UseRIP"); } // XXX Hmmm... crash after saving bones file if Map window is // XXX deleted. Strange bug somewhere. bool NetHackQtMapWindow::Destroy() { return FALSE; } NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : clicksink(click_sink), change(10), rogue_font(0) { viewport.addChild(this); setBackgroundColor(black); viewport.setBackgroundColor(black); pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); cursor.setX(0); cursor.setY(0); Clear(); connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); connect(&viewport, SIGNAL(contentsMoving(int,int)), this, SLOT(moveMessages(int,int))); updateTiles(); //setFocusPolicy(StrongFocus); #ifdef SAFERHANGUP QTimer* deadman = new QTimer(this); connect(deadman, SIGNAL(timeout()), SLOT(timeout())); deadman->start(2000); // deadman timer every 2 seconds #endif } #ifdef SAFERHANGUP // The "deadman" timer is received by this slot void NetHackQtMapWindow::timeout() {} #endif void NetHackQtMapWindow::moveMessages(int x, int y) { QRect u = messages_rect; messages_rect.moveTopLeft(QPoint(x,y)); u |= messages_rect; update(u); } void NetHackQtMapWindow::clearMessages() { messages = ""; update(messages_rect); messages_rect = QRect(); } void NetHackQtMapWindow::putMessage(int attr, const char* text) { if ( !messages.isEmpty() ) messages += "\n"; messages += text; QFontMetrics fm = fontMetrics(); messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); update(messages_rect); } void NetHackQtMapWindow::updateTiles() { NetHackQtGlyphs& glyphs = qt_settings->glyphs(); int gw = glyphs.width(); int gh = glyphs.height(); // Be exactly the size we want to be - full map... resize(COLNO*gw,ROWNO*gh); viewport.verticalScrollBar()->setSteps(gh,gh); viewport.horizontalScrollBar()->setSteps(gw,gw); /* viewport.setMaximumSize( gw*COLNO + viewport.verticalScrollBar()->width(), gh*ROWNO + viewport.horizontalScrollBar()->height() ); */ viewport.updateScrollBars(); change.clear(); change.add(0,0,COLNO,ROWNO); delete rogue_font; rogue_font = 0; Display(FALSE); emit resized(); } NetHackQtMapWindow::~NetHackQtMapWindow() { // Remove from viewport porthole, since that is a destructible member. viewport.removeChild(this); recreate(0,0,QPoint(0,0)); } QWidget* NetHackQtMapWindow::Widget() { return &viewport; } void NetHackQtMapWindow::Scroll(int dx, int dy) { if (viewport.horizontalScrollBar()->isVisible()) { while (dx<0) { viewport.horizontalScrollBar()->subtractPage(); dx++; } while (dx>0) { viewport.horizontalScrollBar()->addPage(); dx--; } } if (viewport.verticalScrollBar()->isVisible()) { while (dy<0) { viewport.verticalScrollBar()->subtractPage(); dy++; } while (dy>0) { viewport.verticalScrollBar()->addPage(); dy--; } } } void NetHackQtMapWindow::Clear() { unsigned short stone=cmap_to_glyph(S_stone); for (int j=0; jexit_loop(); } void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event) { clicksink.Put( event->pos().x()/qt_settings->glyphs().width(), event->pos().y()/qt_settings->glyphs().height(), event->button()==LeftButton ? CLICK_1 : CLICK_2 ); qApp->exit_loop(); } #ifdef TEXTCOLOR static const QPen& nhcolor_to_pen(int c) { static QPen* pen=0; if ( !pen ) { pen = new QPen[17]; pen[0] = QColor(24,24,24); // "black" on black pen[1] = Qt::red; pen[2] = QColor(0,191,0); pen[3] = QColor(127,127,0); pen[4] = Qt::blue; pen[5] = Qt::magenta; pen[6] = Qt::cyan; pen[7] = Qt::gray; pen[8] = Qt::white; // no color pen[9] = QColor(255,127,0); pen[10] = QColor(127,255,127); pen[11] = Qt::yellow; pen[12] = QColor(127,127,255); pen[13] = QColor(255,127,255); pen[14] = QColor(127,255,255); pen[15] = Qt::white; pen[16] = QColor(24,24,24); // "black" on black } return pen[c]; } #endif void NetHackQtMapWindow::paintEvent(QPaintEvent* event) { QRect area=event->rect(); QRect garea; garea.setCoords( QMAX(0,area.left()/qt_settings->glyphs().width()), QMAX(0,area.top()/qt_settings->glyphs().height()), QMIN(COLNO-1,area.right()/qt_settings->glyphs().width()), QMIN(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) ); QPainter painter; painter.begin(this); if (Is_rogue_level(&u.uz) || iflags.wc_ascii_map) { // You enter a VERY primitive world! painter.setClipRect( event->rect() ); // (normally we don't clip) painter.fillRect( event->rect(), black ); if ( !rogue_font ) { // Find font... int pts = 5; QString fontfamily = iflags.wc_font_map ? iflags.wc_font_map : "Courier"; bool bold = FALSE; if ( fontfamily.right(5).lower() == "-bold" ) { fontfamily.truncate(fontfamily.length()-5); bold = TRUE; } while ( pts < 32 ) { QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); painter.setFont(QFont(fontfamily, pts)); QFontMetrics fm = painter.fontMetrics(); if ( fm.width("M") > qt_settings->glyphs().width() ) break; if ( fm.height() > qt_settings->glyphs().height() ) break; pts++; } rogue_font = new QFont(fontfamily,pts-1); } painter.setFont(*rogue_font); for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); uchar ch; int color, och; unsigned special; painter.setPen( green ); /* map glyph to character and color */ (void)mapglyph(g, &och, &color, &special, i, j); ch = (uchar)och; #ifdef TEXTCOLOR painter.setPen( nhcolor_to_pen(color) ); #endif painter.drawText( i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height(), qt_settings->glyphs().width(), qt_settings->glyphs().height(), AlignCenter, (const char*)&ch, 1 ); if (glyph_is_pet(g) #ifdef TEXTCOLOR && ::iflags.hilite_pet #endif ) { painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); } } } painter.setFont(font()); } else { for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); qt_settings->glyphs().drawCell(painter, g, i, j); if (glyph_is_pet(g) #ifdef TEXTCOLOR && ::iflags.hilite_pet #endif ) { painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); } } } } if (garea.contains(cursor)) { if (Is_rogue_level(&u.uz)) { #ifdef TEXTCOLOR painter.setPen( white ); #else painter.setPen( green ); // REALLY primitive #endif } else { int hp100; if (u.mtimedone) { hp100=u.mhmax ? u.mh*100/u.mhmax : 100; } else { hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; } if (hp100 > 75) painter.setPen(white); else if (hp100 > 50) painter.setPen(yellow); else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange else if (hp100 > 10) painter.setPen(red); else painter.setPen(magenta); } painter.drawRect( cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), qt_settings->glyphs().width(),qt_settings->glyphs().height()); } if (area.intersects(messages_rect)) { painter.setPen(black); painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); painter.setPen(white); painter.drawText(viewport.contentsX(),viewport.contentsY(), viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); } painter.end(); } void NetHackQtMapWindow::Display(bool block) { for (int i=0; iglyphs().width(), ch.y()*qt_settings->glyphs().height(), ch.width()*qt_settings->glyphs().width(), ch.height()*qt_settings->glyphs().height(), FALSE ); } change.clear(); if (block) { yn_function("Press a key when done viewing",0,'\0'); } } void NetHackQtMapWindow::CursorTo(int x,int y) { Changed(cursor.x(),cursor.y()); cursor.setX(x); cursor.setY(y); Changed(cursor.x(),cursor.y()); } void NetHackQtMapWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr in MapWindow"); } void NetHackQtMapWindow::ClipAround(int x,int y) { // Convert to pixel of center of tile x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; // Then ensure that pixel is visible viewport.center(x,y,0.45,0.45); } void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph) { Glyph(x,y)=glyph; Changed(x,y); } //void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2) //{ // TODO: composed graphics //} void NetHackQtMapWindow::Changed(int x, int y) { change.add(x,y); } class NetHackQtScrollText : public QTableView { struct UData { UData() : text(0), attr(0) { } ~UData() { if (text) free(text); } char* text; int attr; }; public: int uncleared; NetHackQtScrollText(int maxlength) : uncleared(0), maxitems(maxlength), first(0), count(0), item_cycle(maxlength) { setNumCols(1); setCellWidth(200); setCellHeight(fontMetrics().height()); setBackgroundColor(white); setTableFlags(Tbl_vScrollBar |Tbl_autoHScrollBar |Tbl_clipCellPainting |Tbl_smoothScrolling); } ~NetHackQtScrollText() { } void Scroll(int dx, int dy) { setXOffset(xOffset()+dx*viewWidth()); setYOffset(yOffset()+dy*viewHeight()); } void insertItem(int attr, const char* text) { setTopCell(count); setAutoUpdate(FALSE); int i; if (count cellWidth()) { // Get wider. setCellWidth(w); } setTopCell(count); setAutoUpdate(TRUE); if (viewHeight() >= totalHeight()-cellHeight()) { repaint(); } else { scroll(0,cellHeight()); } } virtual void setFont(const QFont& font) { QTableView::setFont(font); setCellHeight(fontMetrics().height()); } protected: UData& item(int i) { return item_cycle[(first+i)%maxitems]; } const int maxitems; int first, count; QArray item_cycle; int datumWidth(const UData& uitem) { if (uitem.text) { int width=fontMetrics().width(uitem.text)+3; if (uitem.attr) { // XXX Too expensive to do properly, because // XXX we have to set the font of the widget // XXX just to get the font metrics information! // XXX Could hold a fake widget for that // XXX purpose, but this hack is less ugly. width+=width/10; } return width; } else { return 0; } } virtual void setupPainter(QPainter *p) { // XXX This shouldn't be needed - we set the bg in the constructor. p->setBackgroundColor(white); } virtual void paintCell(QPainter *p, int row, int col) { bool sel=FALSE; UData& uitem=item(row); if (!sel && row < count-uncleared) { p->setPen(darkGray); } else { p->setPen(black); } if (uitem.attr) { // XXX only bold QFont bold(font().family(),font().pointSize(),QFont::Bold); p->setFont(bold); } p->drawText(3, 0, cellWidth(), cellHeight(), AlignLeft|AlignVCenter, uitem.text); if (uitem.attr) { p->setFont(font()); } } }; NetHackQtMessageWindow::NetHackQtMessageWindow() : list(new NetHackQtScrollText(::iflags.msg_history)) { ::iflags.window_inited = 1; map = 0; connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont())); updateFont(); } NetHackQtMessageWindow::~NetHackQtMessageWindow() { ::iflags.window_inited = 0; delete list; } QWidget* NetHackQtMessageWindow::Widget() { return list; } void NetHackQtMessageWindow::setMap(NetHackQtMapWindow* m) { map = m; updateFont(); } void NetHackQtMessageWindow::updateFont() { list->setFont(qt_settings->normalFont()); if ( map ) map->setFont(qt_settings->normalFont()); } void NetHackQtMessageWindow::Scroll(int dx, int dy) { list->Scroll(dx,dy); } void NetHackQtMessageWindow::Clear() { if ( map ) map->clearMessages(); if (list->uncleared) { list->uncleared=0; changed=TRUE; Display(FALSE); } } void NetHackQtMessageWindow::Display(bool block) { if (changed) { list->repaint(); changed=FALSE; } } void NetHackQtMessageWindow::PutStr(int attr, const char* text) { #ifdef USER_SOUNDS play_sound_for_message(text); #endif changed=TRUE; list->uncleared++; list->insertItem(attr,text); // Force scrollbar to bottom // XXX list->setTopItem(list->count()); if ( map ) map->putMessage(attr, text); } NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) : QWidget(parent), low_is_good(FALSE), prev_value(-123), turn_count(-1), label(new QLabel(l,this)), icon(0) { initHighlight(); } NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) : QWidget(parent), low_is_good(FALSE), prev_value(-123), turn_count(-1), label(new QLabel(l,this)), icon(new QLabel(this)) { setIcon(i); initHighlight(); } void NetHackQtLabelledIcon::initHighlight() { const QPalette& pal=palette(); const QColorGroup& pa=pal.normal(); //QColorGroup good(white,darkGreen,pa.light(),pa.dark(),pa.mid(),white,pa.base()); QColorGroup good(black,green,pa.light(),pa.dark(),pa.mid(),black,pa.base()); QColorGroup bad(white,red,pa.light(),pa.dark(),pa.mid(),white,pa.base()); hl_good=pal.copy(); hl_good.setNormal(good); hl_good.setActive(good); hl_bad=pal.copy(); hl_bad.setNormal(bad); hl_bad.setActive(bad); } void NetHackQtLabelledIcon::setLabel(const char* t, bool lower) { if (!label) { label=new QLabel(this); label->setFont(font()); resizeEvent(0); } if (0!=strcmp(label->text(),t)) { label->setText(t); highlight(lower==low_is_good ? hl_good : hl_bad); } } void NetHackQtLabelledIcon::setLabel(const char* t, long v, long cv, const char* tail) { char buf[BUFSZ]; if (v==NoNum) { Sprintf(buf,"%s%s",t,tail); } else { Sprintf(buf,"%s%ld%s",t,v,tail); } setLabel(buf,cvsetPixmap(i); else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); } icon->resize(i.width(),i.height()); } void NetHackQtLabelledIcon::setFont(const QFont& f) { QWidget::setFont(f); if (label) label->setFont(f); } void NetHackQtLabelledIcon::show() { #if QT_VERSION >= 300 if (isHidden()) #else if (!isVisible()) #endif highlight(hl_bad); QWidget::show(); } void NetHackQtLabelledIcon::highlightWhenChanging() { turn_count=0; } void NetHackQtLabelledIcon::lowIsGood() { low_is_good=TRUE; } void NetHackQtLabelledIcon::dissipateHighlight() { if (turn_count>0) { turn_count--; if (!turn_count) unhighlight(); } } void NetHackQtLabelledIcon::highlight(const QPalette& hl) { if (label) { // Surely it is?! if (turn_count>=0) { label->setPalette(hl); turn_count=4; // `4' includes this turn, so dissipates after // 3 more keypresses. } else { label->setPalette(palette()); } } } void NetHackQtLabelledIcon::unhighlight() { if (label) { // Surely it is?! label->setPalette(palette()); } } void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*) { setAlignments(); //int labw=label ? label->fontMetrics().width(label->text()) : 0; int labh=label ? label->fontMetrics().height() : 0; int icoh=icon ? icon->height() : 0; int h=icoh+labh; int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2); int laby=icoy+icoh; if (icon) { icon->setGeometry(0,icoy,width(),icoh); } if (label) { label->setGeometry(0,laby,width(),labh); } } void NetHackQtLabelledIcon::setAlignments() { if (label) label->setAlignment(AlignHCenter|AlignVCenter); if (icon) icon->setAlignment(AlignHCenter|AlignVCenter); } static void tryload(QPixmap& pm, const char* fn) { if (!pm.load(fn)) { QString msg; msg.sprintf("Cannot load \"%s\"", fn); QMessageBox::warning(0, "IO Error", msg); } } NetHackQtStatusWindow::NetHackQtStatusWindow() : // Notes: // Alignment needs -2 init value, because -1 is an alignment. // Armor Class is an schar, so 256 is out of range. // Blank value is 0 and should never change. name(this,"(name)"), dlevel(this,"(dlevel)"), str(this,"STR"), dex(this,"DEX"), con(this,"CON"), intel(this,"INT"), wis(this,"WIS"), cha(this,"CHA"), gold(this,"Gold"), hp(this,"Hit Points"), power(this,"Power"), ac(this,"Armour Class"), level(this,"Level"), exp(this,"Experience"), align(this,"Alignment"), time(this,"Time"), score(this,"Score"), hunger(this,""), confused(this,"Confused"), sick_fp(this,"Sick"), sick_il(this,"Ill"), blind(this,"Blind"), stunned(this,"Stunned"), hallu(this,"Hallu"), encumber(this,""), hline1(this), hline2(this), hline3(this), first_set(TRUE) { p_str = QPixmap(str_xpm); p_str = QPixmap(str_xpm); p_dex = QPixmap(dex_xpm); p_con = QPixmap(cns_xpm); p_int = QPixmap(int_xpm); p_wis = QPixmap(wis_xpm); p_cha = QPixmap(cha_xpm); p_chaotic = QPixmap(chaotic_xpm); p_neutral = QPixmap(neutral_xpm); p_lawful = QPixmap(lawful_xpm); p_satiated = QPixmap(satiated_xpm); p_hungry = QPixmap(hungry_xpm); p_confused = QPixmap(confused_xpm); p_sick_fp = QPixmap(sick_fp_xpm); p_sick_il = QPixmap(sick_il_xpm); p_blind = QPixmap(blind_xpm); p_stunned = QPixmap(stunned_xpm); p_hallu = QPixmap(hallu_xpm); p_encumber[0] = QPixmap(slt_enc_xpm); p_encumber[1] = QPixmap(mod_enc_xpm); p_encumber[2] = QPixmap(hvy_enc_xpm); p_encumber[3] = QPixmap(ext_enc_xpm); p_encumber[4] = QPixmap(ovr_enc_xpm); str.setIcon(p_str); dex.setIcon(p_dex); con.setIcon(p_con); intel.setIcon(p_int); wis.setIcon(p_wis); cha.setIcon(p_cha); align.setIcon(p_neutral); hunger.setIcon(p_hungry); confused.setIcon(p_confused); sick_fp.setIcon(p_sick_fp); sick_il.setIcon(p_sick_il); blind.setIcon(p_blind); stunned.setIcon(p_stunned); hallu.setIcon(p_hallu); encumber.setIcon(p_encumber[0]); hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken); hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken); hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken); hline1.setLineWidth(1); hline2.setLineWidth(1); hline3.setLineWidth(1); connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); doUpdate(); } void NetHackQtStatusWindow::doUpdate() { const QFont& large=qt_settings->largeFont(); name.setFont(large); dlevel.setFont(large); const QFont& normal=qt_settings->normalFont(); str.setFont(normal); dex.setFont(normal); con.setFont(normal); intel.setFont(normal); wis.setFont(normal); cha.setFont(normal); gold.setFont(normal); hp.setFont(normal); power.setFont(normal); ac.setFont(normal); level.setFont(normal); exp.setFont(normal); align.setFont(normal); time.setFont(normal); score.setFont(normal); hunger.setFont(normal); confused.setFont(normal); sick_fp.setFont(normal); sick_il.setFont(normal); blind.setFont(normal); stunned.setFont(normal); hallu.setFont(normal); encumber.setFont(normal); updateStats(); } QWidget* NetHackQtStatusWindow::Widget() { return this; } void NetHackQtStatusWindow::Clear() { } void NetHackQtStatusWindow::Display(bool block) { } void NetHackQtStatusWindow::CursorTo(int,int y) { cursy=y; } void NetHackQtStatusWindow::PutStr(int attr, const char* text) { // do a complete update when line 0 is done (as per X11 fancy status) if (cursy==0) updateStats(); } void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) { const float SP_name=0.13; // the (large) const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large) const float SP_atr1=0.25; // STR DEX CON INT WIS CHA const float SP_hln1=0.02; // --- const float SP_atr2=0.09; // Au HP PW AC LVL EXP const float SP_hln2=0.02; // --- const float SP_time=0.09; // time score const float SP_hln3=0.02; // --- const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc. int h=height(); int x=0,y=0; int iw; // Width of an item across line int lh; // Height of a line of values lh=int(h*SP_name); name.setGeometry(0,0,width(),lh); y+=lh; lh=int(h*SP_dlev); dlevel.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_hln1); hline1.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_atr1); iw=width()/6; str.setGeometry(x,y,iw,lh); x+=iw; dex.setGeometry(x,y,iw,lh); x+=iw; con.setGeometry(x,y,iw,lh); x+=iw; intel.setGeometry(x,y,iw,lh); x+=iw; wis.setGeometry(x,y,iw,lh); x+=iw; cha.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_hln2); hline2.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_atr2); iw=width()/6; gold.setGeometry(x,y,iw,lh); x+=iw; hp.setGeometry(x,y,iw,lh); x+=iw; power.setGeometry(x,y,iw,lh); x+=iw; ac.setGeometry(x,y,iw,lh); x+=iw; level.setGeometry(x,y,iw,lh); x+=iw; exp.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_hln3); hline3.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_time); iw=width()/3; x+=iw/2; time.setGeometry(x,y,iw,lh); x+=iw; score.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_stat); iw=width()/9; align.setGeometry(x,y,iw,lh); x+=iw; hunger.setGeometry(x,y,iw,lh); x+=iw; confused.setGeometry(x,y,iw,lh); x+=iw; sick_fp.setGeometry(x,y,iw,lh); x+=iw; sick_il.setGeometry(x,y,iw,lh); x+=iw; blind.setGeometry(x,y,iw,lh); x+=iw; stunned.setGeometry(x,y,iw,lh); x+=iw; hallu.setGeometry(x,y,iw,lh); x+=iw; encumber.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; } /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all * kinds of funny values being displayed. */ void NetHackQtStatusWindow::nullOut() { } void NetHackQtStatusWindow::fadeHighlighting() { name.dissipateHighlight(); dlevel.dissipateHighlight(); str.dissipateHighlight(); dex.dissipateHighlight(); con.dissipateHighlight(); intel.dissipateHighlight(); wis.dissipateHighlight(); cha.dissipateHighlight(); gold.dissipateHighlight(); hp.dissipateHighlight(); power.dissipateHighlight(); ac.dissipateHighlight(); level.dissipateHighlight(); exp.dissipateHighlight(); align.dissipateHighlight(); time.dissipateHighlight(); score.dissipateHighlight(); hunger.dissipateHighlight(); confused.dissipateHighlight(); sick_fp.dissipateHighlight(); sick_il.dissipateHighlight(); blind.dissipateHighlight(); stunned.dissipateHighlight(); hallu.dissipateHighlight(); encumber.dissipateHighlight(); } /* * Update the displayed status. The current code in botl.c updates * two lines of information. Both lines are always updated one after * the other. So only do our update when we update the second line. * * Information on the first line: * name, attributes, alignment, score * * Information on the second line: * dlvl, gold, hp, power, ac, {level & exp or HD **} * status (hunger, conf, halu, stun, sick, blind), time, encumbrance * * [**] HD is shown instead of level and exp if mtimedone is non-zero. */ void NetHackQtStatusWindow::updateStats() { if (!parentWidget()) return; char buf[BUFSZ]; if (cursy != 0) return; /* do a complete update when line 0 is done */ if (ACURR(A_STR) > 118) { Sprintf(buf,"STR:%d",ACURR(A_STR)-100); } else if (ACURR(A_STR)==118) { Sprintf(buf,"STR:18/**"); } else if(ACURR(A_STR) > 18) { Sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18); } else { Sprintf(buf,"STR:%d",ACURR(A_STR)); } str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR)); dex.setLabel("DEX:",(long)ACURR(A_DEX)); con.setLabel("CON:",(long)ACURR(A_CON)); intel.setLabel("INT:",(long)ACURR(A_INT)); wis.setLabel("WIS:",(long)ACURR(A_WIS)); cha.setLabel("CHA:",(long)ACURR(A_CHA)); const char* hung=hu_stat[u.uhs]; if (hung[0]==' ') { hunger.hide(); } else { hunger.setIcon(u.uhs ? p_hungry : p_satiated); hunger.setLabel(hung); hunger.show(); } if (Confusion) confused.show(); else confused.hide(); if (Sick) { if (u.usick_type & SICK_VOMITABLE) { sick_fp.show(); } else { sick_fp.hide(); } if (u.usick_type & SICK_NONVOMITABLE) { sick_il.show(); } else { sick_il.hide(); } } else { sick_fp.hide(); sick_il.hide(); } if (Blind) blind.show(); else blind.hide(); if (Stunned) stunned.show(); else stunned.hide(); if (Hallucination) hallu.show(); else hallu.hide(); const char* enc=enc_stat[near_capacity()]; if (enc[0]==' ' || !enc[0]) { encumber.hide(); } else { encumber.setIcon(p_encumber[near_capacity()-1]); encumber.setLabel(enc); encumber.show(); } Strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a'; Strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; Strcpy(mname, mons[u.umonnum].mname); while(mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k-1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') { mname[k] += 'A' - 'a'; } k++; } Strcat(buf, mname); } else { Strcat(buf, rank_of(u.ulevel, pl_character[0], ::flags.female)); } name.setLabel(buf,NetHackQtLabelledIcon::NoNum,u.ulevel); if (describe_level(buf)) { dlevel.setLabel(buf,(bool)TRUE); } else { Sprintf(buf, "%s, level ", dungeons[u.uz.dnum].dname); dlevel.setLabel(buf,(long)depth(&u.uz)); } gold.setLabel("Au:", money_cnt(invent)); if (u.mtimedone) { // You're a monster! Sprintf(buf, "/%d", u.mhmax); hp.setLabel("HP:",u.mh > 0 ? u.mh : 0,buf); level.setLabel("HD:",(long)mons[u.umonnum].mlevel); } else { // You're normal. Sprintf(buf, "/%d", u.uhpmax); hp.setLabel("HP:",u.uhp > 0 ? u.uhp : 0,buf); level.setLabel("Level:",(long)u.ulevel); } Sprintf(buf, "/%d", u.uenmax); power.setLabel("Pow:",u.uen,buf); ac.setLabel("AC:",(long)u.uac); if (::flags.showexp) { exp.setLabel("Exp:",(long)u.uexp); } else { exp.setLabel(""); } if (u.ualign.type==A_CHAOTIC) { align.setIcon(p_chaotic); align.setLabel("Chaotic"); } else if (u.ualign.type==A_NEUTRAL) { align.setIcon(p_neutral); align.setLabel("Neutral"); } else { align.setIcon(p_lawful); align.setLabel("Lawful"); } if (::flags.time) time.setLabel("Time:",(long)moves); else time.setLabel(""); #ifdef SCORE_ON_BOTL if (::flags.showscore) { score.setLabel("Score:",(long)botl_score()); } else #endif { score.setLabel(""); } if (first_set) { first_set=FALSE; name.highlightWhenChanging(); dlevel.highlightWhenChanging(); str.highlightWhenChanging(); dex.highlightWhenChanging(); con.highlightWhenChanging(); intel.highlightWhenChanging(); wis.highlightWhenChanging(); cha.highlightWhenChanging(); gold.highlightWhenChanging(); hp.highlightWhenChanging(); power.highlightWhenChanging(); ac.highlightWhenChanging(); ac.lowIsGood(); level.highlightWhenChanging(); exp.highlightWhenChanging(); align.highlightWhenChanging(); //time.highlightWhenChanging(); score.highlightWhenChanging(); hunger.highlightWhenChanging(); confused.highlightWhenChanging(); sick_fp.highlightWhenChanging(); sick_il.highlightWhenChanging(); blind.highlightWhenChanging(); stunned.highlightWhenChanging(); hallu.highlightWhenChanging(); encumber.highlightWhenChanging(); } } /* * Turn off hilighted status values after a certain amount of turns. */ void NetHackQtStatusWindow::checkTurnEvents() { } NetHackQtMenuDialog::NetHackQtMenuDialog() : QDialog(qApp->mainWidget(),0,FALSE) { } void NetHackQtMenuDialog::resizeEvent(QResizeEvent*) { emit Resized(); } void NetHackQtMenuDialog::Accept() { accept(); } void NetHackQtMenuDialog::Reject() { reject(); } void NetHackQtMenuDialog::SetResult(int r) { setResult(r); } void NetHackQtMenuDialog::done(int i) { setResult(i); qApp->exit_loop(); } // Table view columns: // // [pick-count] [accel] [glyph] [string] // // Maybe accel should be near string. We'll see. // pick-count normally blank. // double-clicking or click-on-count gives pop-up entry // string is green when selected // NetHackQtMenuWindow::NetHackQtMenuWindow(NetHackQtKeyBuffer& ks) : QTableView(), keysource(ks), dialog(new NetHackQtMenuDialog()), prompt(0), pressed(-1) { setNumCols(4); setCellHeight(QMAX(qt_settings->glyphs().height()+1,fontMetrics().height())); setBackgroundColor(lightGray); setFrameStyle(Panel|Sunken); setLineWidth(2); ok=new QPushButton("Ok",dialog); connect(ok,SIGNAL(clicked()),dialog,SLOT(accept())); cancel=new QPushButton("Cancel",dialog); connect(cancel,SIGNAL(clicked()),dialog,SLOT(reject())); all=new QPushButton("All",dialog); connect(all,SIGNAL(clicked()),this,SLOT(All())); none=new QPushButton("None",dialog); connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone())); invert=new QPushButton("Invert",dialog); connect(invert,SIGNAL(clicked()),this,SLOT(Invert())); search=new QPushButton("Search",dialog); connect(search,SIGNAL(clicked()),this,SLOT(Search())); QPoint pos(0,ok->height()); recreate(dialog,0,pos); prompt.recreate(dialog,0,pos); setBackgroundColor(lightGray); connect(dialog,SIGNAL(Resized()),this,SLOT(Layout())); setTableFlags(Tbl_autoHScrollBar|Tbl_autoVScrollBar |Tbl_smoothScrolling|Tbl_clipCellPainting); setFocusPolicy(StrongFocus); } NetHackQtMenuWindow::~NetHackQtMenuWindow() { // Remove from dialog before we destruct it recreate(0,0,QPoint(0,0)); delete dialog; } void NetHackQtMenuWindow::focusInEvent(QFocusEvent *) { // Don't repaint at all, since nothing is using the focus colour } void NetHackQtMenuWindow::focusOutEvent(QFocusEvent *) { // Don't repaint at all, since nothing is using the focus colour } int NetHackQtMenuWindow::cellWidth(int col) { switch (col) { case 0: return fontMetrics().width("All "); break; case 1: return fontMetrics().width(" m "); break; case 2: return qt_settings->glyphs().width(); break; case 3: return str_width; } impossible("Extra column (#%d) in MenuWindow",col); return 0; } QWidget* NetHackQtMenuWindow::Widget() { return dialog; } void NetHackQtMenuWindow::StartMenu() { setNumRows((itemcount=0)); str_width=200; str_fixed=FALSE; next_accel=0; has_glyphs=FALSE; } NetHackQtMenuWindow::MenuItem::MenuItem() : str(0) { } NetHackQtMenuWindow::MenuItem::~MenuItem() { if (str) free((void*)str); } #define STR_MARGIN 4 void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel) { if (!ch && identifier->a_void!=0) { // Supply a keyboard accelerator. Limited supply. static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; if (accel[next_accel]) { ch=accel[next_accel++]; } } if ((int)item.size() < itemcount+1) { item.resize(itemcount*4+10); } item[itemcount].glyph=glyph; item[itemcount].identifier=*identifier; item[itemcount].ch=ch; item[itemcount].attr=attr; item[itemcount].str=strdup(str); item[itemcount].selected=presel; item[itemcount].count=-1; ++itemcount; str_fixed=str_fixed || strstr(str," "); if (glyph!=NO_GLYPH) has_glyphs=TRUE; } void NetHackQtMenuWindow::EndMenu(const char* p) { prompt.setText(p ? p : ""); } void NetHackQtMenuWindow::Layout() { int butw=totalWidth()/6; // 6 buttons int buth=fontMetrics().height()+8; // 8 for spacing & mitres int prompth=(prompt.text().isNull() ? 0 : buth); prompt.setGeometry(6,buth,dialog->width()-6,prompth); int h=dialog->height()-buth-prompth; setGeometry(0,buth+prompth, dialog->width(), h); // Below, we take care to use up full width int x=0; ok->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/5; cancel->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/4; all->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/3; none->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/2; invert->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/1; search->setGeometry(x,0,butw,buth); } int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) { setFont(str_fixed ? qt_settings->normalFixedFont() : qt_settings->normalFont()); for (int i=0; iglyphs().height()+1,fontMetrics().height())); setNumRows(itemcount); int buth=fontMetrics().height()+8; // 8 for spacing & mitres how=h; ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE); cancel->setEnabled(TRUE); all->setEnabled(how==PICK_ANY); none->setEnabled(how==PICK_ANY); invert->setEnabled(how==PICK_ANY); search->setEnabled(how!=PICK_NONE); dialog->SetResult(-1); // 20 allows for scrollbar or spacing // 4 for frame borders int mh = QApplication::desktop()->height()*3/5; if ( qt_compact_mode && totalHeight() > mh ) { // big, so make it fill dialog->showMaximized(); } else { dialog->resize(totalWidth()+20, QMIN(totalHeight(), mh)+buth+4+(prompt.text().isNull() ? 0 : buth)); if ( dialog->width() > QApplication::desktop()->width() ) dialog->resize(QApplication::desktop()->width(),dialog->height()+16); centerOnMain(dialog); dialog->show(); } setFocus(); while (dialog->result()<0) { // changed the defaults below to the values in wintype.h 000119 - azy if (!keysource.Empty()) { char k=keysource.GetAscii(); k=map_menu_cmd(k); /* added 000119 - azy */ if (k=='\033') dialog->Reject(); else if (k=='\r' || k=='\n' || k==' ') dialog->Accept(); else if (k==MENU_SEARCH) Search(); else if (k==MENU_SELECT_ALL) All(); else if (k==MENU_INVERT_ALL) Invert(); else if (k==MENU_UNSELECT_ALL) ChooseNone(); else { for (int i=0; iresult()<0) qApp->enter_loop(); } //if ( (nhid != WIN_INVEN || !flags.perm_invent) ) // doesn't work yet { dialog->hide(); } int result=dialog->result(); // Consume ^M (which QDialog steals for default button) while (!keysource.Empty() && (keysource.TopAscii()=='\n' || keysource.TopAscii()=='\r')) keysource.GetAscii(); *menu_list=0; if (how==PICK_NONE) return result==0 ? -1 : 0; if (result>0) { if (how==PICK_ONE) { int i; for (i=0; istate()&ShiftButton)) { if (event->key()==Key_Prior) { setYOffset(yOffset()-viewHeight()); } else if (event->key()==Key_Next) { setYOffset(yOffset()+viewHeight()); } else { event->ignore(); } } else { event->ignore(); } } void NetHackQtMenuWindow::All() { for (int i=0; iAccept(); } } } void NetHackQtMenuWindow::paintCell(QPainter* painter, int row, int col) { // [pick-count] [accel] [glyph] [string] MenuItem& i = item[row]; painter->setPen(black); painter->setFont(font()); if (i.selected) { painter->setPen(darkGreen); } switch (col) { case 0: if ( i.ch || i.attr!=ATR_INVERSE ) { QString text; if ( i.selected && i.count == -1 ) { if ( i.str[0]>='0' && i.str[0]<='9' ) text = "All"; else text = "*"; } else if ( i.count<0 ) { text = "-"; } else { text.sprintf("%d",i.count); } painter->drawText(0,0,cellWidth(col),cellHeight(), AlignHCenter|AlignVCenter,text); } break; case 1: if ((signed char)i.ch >= 0) { char text[2]={i.ch,0}; painter->drawText(0,0,cellWidth(col),cellHeight(), AlignHCenter|AlignVCenter,text); } break; case 2: if (i.glyph!=NO_GLYPH) { // Centered in height int y=(cellHeight()-qt_settings->glyphs().height())/2; if (y<0) y=0; qt_settings->glyphs().drawGlyph(*painter, i.glyph, 0, y); } break; case 3: // XXX should qt_settings have ALL the various fonts QFont newfont=font(); if (i.attr) { switch(i.attr) { case ATR_ULINE: newfont.setUnderline(TRUE); break; case ATR_BOLD: painter->setPen(red); break; case ATR_BLINK: newfont.setItalic(TRUE); break; case ATR_INVERSE: newfont=qt_settings->largeFont(); newfont.setWeight(QFont::Bold); if (i.selected) { painter->setPen(blue); } else { painter->setPen(darkBlue); } } } painter->setFont(newfont); painter->drawText(STR_MARGIN,0,cellWidth(col),cellHeight(), AlignLeft|AlignVCenter,i.str); } } void NetHackQtMenuWindow::mousePressEvent(QMouseEvent* event) { int col=findCol(event->pos().x()); int row=findRow(event->pos().y()); if (col<0 || row<0 || !item[row].Selectable()) return; if (how!=PICK_NONE) { if (col==0) { // Changing count. NetHackQtStringRequestor requestor(keysource,"Count:"); char buf[BUFSZ]; if (item[row].count>0) Sprintf(buf,"%d", item[row].count); else Strcpy(buf, ""); requestor.SetDefault(buf); if (requestor.Get(buf)) { item[row].count=atoi(buf); if (item[row].count==0) { item[row].count=-1; if (item[row].selected) ToggleSelect(row); } else { if (!item[row].selected) ToggleSelect(row); } updateCell(row,0); } } else { pressed=row; was_sel=item[row].selected; ToggleSelect(row); updateCell(row,0); } } } void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event) { if (pressed>=0) { int p=pressed; pressed=-1; updateCell(p,3); } } void NetHackQtMenuWindow::mouseMoveEvent(QMouseEvent* event) { if (pressed>=0) { int col=findCol(event->pos().x()); int row=findRow(event->pos().y()); if (row>=0 && col>=0) { if (pressed!=row) { // reset to initial state if (item[pressed].selected!=was_sel) ToggleSelect(pressed); } else { // reset to new state if (item[pressed].selected==was_sel) ToggleSelect(pressed); } } } } class NetHackQtTextListBox : public QListBox { public: NetHackQtTextListBox(QWidget* parent) : QListBox(parent) { } int TotalWidth() { doLayout(); return contentsWidth(); } int TotalHeight() { doLayout(); return contentsHeight(); } virtual void setFont(const QFont &font) { QListBox::setFont(font); } void keyPressEvent(QKeyEvent* e) { QListBox::keyPressEvent(e); } }; QPixmap* NetHackQtRIP::pixmap=0; NetHackQtRIP::NetHackQtRIP(QWidget* parent) : QWidget(parent) { if (!pixmap) { pixmap=new QPixmap; tryload(*pixmap, "rip.xpm"); } riplines=0; resize(pixmap->width(),pixmap->height()); setFont(QFont("times",12)); // XXX may need to be configurable } void NetHackQtRIP::setLines(char** l, int n) { line=l; riplines=n; } QSize NetHackQtRIP::sizeHint() const { return pixmap->size(); } void NetHackQtRIP::paintEvent(QPaintEvent* event) { if ( riplines ) { int pix_x=(width()-pixmap->width())/2; int pix_y=(height()-pixmap->height())/2; // XXX positions based on RIP image int rip_text_x=pix_x+156; int rip_text_y=pix_y+67; int rip_text_h=94/riplines; QPainter painter; painter.begin(this); painter.drawPixmap(pix_x,pix_y,*pixmap); for (int i=0; imainWidget(),0,FALSE), keysource(ks), use_rip(FALSE), str_fixed(FALSE), ok("Dismiss",this), search("Search",this), lines(new NetHackQtTextListBox(this)), rip(this) { ok.setDefault(TRUE); connect(&ok,SIGNAL(clicked()),this,SLOT(accept())); connect(&search,SIGNAL(clicked()),this,SLOT(Search())); connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); QVBoxLayout* vb = new QVBoxLayout(this); vb->addWidget(&rip); QHBoxLayout* hb = new QHBoxLayout(vb); hb->addWidget(&ok); hb->addWidget(&search); vb->addWidget(lines); } void NetHackQtTextWindow::doUpdate() { update(); } NetHackQtTextWindow::~NetHackQtTextWindow() { } QWidget* NetHackQtTextWindow::Widget() { return this; } bool NetHackQtTextWindow::Destroy() { return !isVisible(); } void NetHackQtTextWindow::UseRIP(int how, time_t when) { // Code from X11 windowport #define STONE_LINE_LEN 16 /* # chars that fit on one line */ #define NAME_LINE 0 /* line # for player name */ #define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ #define YEAR_LINE 6 /* line # for year */ static char** rip_line=0; if (!rip_line) { rip_line=new char*[YEAR_LINE+1]; for (int i=0; i STONE_LINE_LEN) { for(i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if(dpx[i] == ' ') i0 = i; if(!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; strcpy(rip_line[line], dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; } else dpx= &dpx[i0+1]; } /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(rip_line[YEAR_LINE], "%4ld", year); rip.setLines(rip_line,YEAR_LINE+1); use_rip=TRUE; } void NetHackQtTextWindow::Clear() { lines->clear(); use_rip=FALSE; str_fixed=FALSE; } void NetHackQtTextWindow::Display(bool block) { if (str_fixed) { lines->setFont(qt_settings->normalFixedFont()); } else { lines->setFont(qt_settings->normalFont()); } int h=0; if (use_rip) { h+=rip.height(); ok.hide(); search.hide(); rip.show(); } else { h+=ok.height()*2; ok.show(); search.show(); rip.hide(); } int mh = QApplication::desktop()->height()*3/5; if ( qt_compact_mode && (lines->TotalHeight() > mh || use_rip) ) { // big, so make it fill showMaximized(); } else { resize(QMAX(use_rip ? rip.width() : 200, lines->TotalWidth()+24), QMIN(mh, lines->TotalHeight()+h)); centerOnMain(this); show(); } if (block) { setResult(-1); while (result()==-1) { qApp->enter_loop(); if (result()==-1 && !keysource.Empty()) { char k=keysource.GetAscii(); if (k=='\033' || k==' ' || k=='\r' || k=='\n') { accept(); } else if (k=='/') { Search(); } } } } } void NetHackQtTextWindow::PutStr(int attr, const char* text) { str_fixed=str_fixed || strstr(text," "); lines->insertItem(text); } void NetHackQtTextWindow::done(int i) { setResult(i+1000); hide(); qApp->exit_loop(); } void NetHackQtTextWindow::keyPressEvent(QKeyEvent* e) { if ( e->ascii() != '\r' && e->ascii() != '\n' && e->ascii() != '\033' ) lines->keyPressEvent(e); else QDialog::keyPressEvent(e); } void NetHackQtTextWindow::Search() { NetHackQtStringRequestor requestor(keysource,"Search for:"); static char line[256]=""; requestor.SetDefault(line); if (requestor.Get(line)) { int current=lines->currentItem(); for (uint i=1; icount(); i++) { int lnum=(i+current)%lines->count(); QString str=lines->text(lnum); if (str.contains(line)) { lines->setCurrentItem(lnum); lines->centerCurrentItem(); return; } } lines->setCurrentItem(-1); } } NetHackQtDelay::NetHackQtDelay(int ms) : msec(ms) { } void NetHackQtDelay::wait() { startTimer(msec); qApp->enter_loop(); } void NetHackQtDelay::timerEvent(QTimerEvent* timer) { qApp->exit_loop(); killTimers(); } NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) : QWidget(parent) { } void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe) { short int glyph; if (nhobj) glyph=obj_to_glyph(nhobj); else if (canbe) glyph=cmap_to_glyph(S_room); else glyph=cmap_to_glyph(S_stone); qt_settings->glyphs().drawCell(painter,glyph,x,y); } void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) { // 012 // //0 WhB //1 s"w //2 gCg //3 =A= //4 T //5 S QPainter painter; painter.begin(this); // Blanks drawWorn(painter,0,0,4,FALSE); drawWorn(painter,0,0,5,FALSE); drawWorn(painter,0,2,4,FALSE); drawWorn(painter,0,2,5,FALSE); drawWorn(painter,uarm,1,3); // Armour drawWorn(painter,uarmc,1,2); // Cloak drawWorn(painter,uarmh,1,0); // Helmet drawWorn(painter,uarms,0,1); // Shield drawWorn(painter,uarmg,0,2); // Gloves - repeated drawWorn(painter,uarmg,2,2); // Gloves - repeated drawWorn(painter,uarmf,1,5); // Shoes (feet) drawWorn(painter,uarmu,1,4); // Undershirt drawWorn(painter,uleft,0,3); // RingL drawWorn(painter,uright,2,3); // RingR drawWorn(painter,uwep,2,1); // Weapon drawWorn(painter,uswapwep,0,0); // Secondary weapon drawWorn(painter,uamul,1,1); // Amulet drawWorn(painter,ublindf,2,0); // Blindfold painter.end(); } class SmallToolButton : public QToolButton { public: SmallToolButton(const QPixmap & pm, const QString &textLabel, const QString& grouptext, QObject * receiver, const char* slot, QToolBar * parent) : QToolButton(pm, textLabel, #if QT_VERSION < 210 QString::null, #else grouptext, #endif receiver, slot, parent) { } QSize sizeHint() const { // get just a couple more pixels for the map return QToolButton::sizeHint()-QSize(0,2); } }; NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : message(0), map(0), status(0), invusage(0), keysink(ks), dirkey(0) { QToolBar* toolbar = new QToolBar(this); #if QT_VERSION >= 210 setToolBarsMovable(FALSE); toolbar->setHorizontalStretchable(TRUE); toolbar->setVerticalStretchable(TRUE); #endif addToolBar(toolbar); menubar = menuBar(); setCaption("Qt NetHack"); if ( qt_compact_mode ) setIcon(QPixmap(nh_icon_small)); else setIcon(QPixmap(nh_icon)); QPopupMenu* game=new QPopupMenu; QPopupMenu* apparel=new QPopupMenu; QPopupMenu* act1=new QPopupMenu; QPopupMenu* act2 = qt_compact_mode ? new QPopupMenu : act1; QPopupMenu* magic=new QPopupMenu; QPopupMenu* info=new QPopupMenu; QPopupMenu *help; #ifdef KDE help = kapp->getHelpMenu( TRUE, "" ); help->insertSeparator(); #else help = qt_compact_mode ? info : new QPopupMenu; #endif enum { OnDesktop=1, OnHandhelds=2 }; struct Macro { QPopupMenu* menu; const char* name; const char* action; int flags; } item[] = { { game, 0, 0, 3}, { game, "Version\tv", "v", 3}, { game, "Compilation\tAlt+V", "\366", 3}, { game, "History\tShift+V", "V", 3}, { game, "Redraw\tCtrl+R", "\022", 0}, // useless { game, "Options\tShift+O", "O", 3}, { game, "Explore mode\tShift+X", "X", 3}, { game, 0, 0, 3}, { game, "Save\tSy", "Sy", 3}, { game, "Quit\tAlt+Q", "\361", 3}, { apparel, "Apparel off\tShift+A", "A", 2}, { apparel, "Remove many\tShift+A", "A", 1}, { apparel, 0, 0, 3}, { apparel, "Wield weapon\tw", "w", 3}, { apparel, "Exchange weapons\tx", "x", 3}, { apparel, "Two weapon combat\t#two", "#tw", 3}, { apparel, "Load quiver\tShift+Q", "Q", 3}, { apparel, 0, 0, 3}, { apparel, "Wear armour\tShift+W", "W", 3}, { apparel, "Take off armour\tShift+T", "T", 3}, { apparel, 0, 0, 3}, { apparel, "Put on non-armour\tShift+P", "P", 3}, { apparel, "Remove non-armour\tShift+R", "R", 3}, { act1, "Again\tCtrl+A", "\001", 2}, { act1, 0, 0, 3}, { act1, "Apply\ta?", "a?", 3}, { act1, "Chat\tAlt+C", "\343", 3}, { act1, "Close door\tc", "c", 3}, { act1, "Down\t>", ">", 3}, { act1, "Drop many\tShift+D", "D", 2}, { act1, "Drop\td?", "d?", 2}, { act1, "Eat\te?", "e?", 2}, { act1, "Engrave\tShift+E", "E", 3}, { act1, "Fight\tShift+F", "F", 3}, { act1, "Fire from quiver\tf", "f", 2}, { act1, "Force\tAlt+F", "\346", 3}, { act1, "Get\t,", ",", 2}, { act1, "Jump\tAlt+J", "\352", 3}, { act2, "Kick\tCtrl+D", "\004", 2}, { act2, "Loot\tAlt+L", "\354", 3}, { act2, "Open door\to", "o", 3}, { act2, "Pay\tp", "p", 3}, { act2, "Rest\t.", ".", 2}, { act2, "Ride\t#ri", "#ri", 3}, { act2, "Search\ts", "s", 3}, { act2, "Sit\tAlt+S", "\363", 3}, { act2, "Throw\tt", "t", 2}, { act2, "Untrap\t#u", "#u", 3}, { act2, "Up\t<", "<", 3}, { act2, "Wipe face\tAlt+W", "\367", 3}, { magic, "Quaff potion\tq?", "q?", 3}, { magic, "Read scroll/book\tr?", "r?", 3}, { magic, "Zap wand\tz?", "z?", 3}, { magic, "Zap spell\tShift+Z", "Z", 3}, { magic, "Dip\tAlt+D", "\344", 3}, { magic, "Rub\tAlt+R", "\362", 3}, { magic, "Invoke\tAlt+I", "\351", 3}, { magic, 0, 0, 3}, { magic, "Offer\tAlt+O", "\357", 3}, { magic, "Pray\tAlt+P", "\360", 3}, { magic, 0, 0, 3}, { magic, "Teleport\tCtrl+T", "\024", 3}, { magic, "Monster action\tAlt+M", "\355", 3}, { magic, "Turn undead\tAlt+T", "\364", 3}, { help, "Help\t?", "?", 3}, { help, 0, 0, 3}, { help, "What is here\t:", ":", 3}, { help, "What is there\t;", ";", 3}, { help, "What is...\t/y", "/y", 2}, { help, 0, 0, 1}, { info, "Inventory\ti", "i", 3}, #ifdef SLASHEM { info, "Angbandish inventory\t*", "*", 3}, #endif { info, "Conduct\t#co", "#co", 3}, { info, "Discoveries\t\\", "\\", 3}, { info, "List/reorder spells\t+", "+", 3}, { info, "Adjust letters\tAlt+A", "\341", 2}, { info, 0, 0, 3}, { info, "Name object\tAlt+N", "\356y?", 3}, { info, "Name object type\tAlt+N", "\356n?", 3}, { info, "Name creature\tShift+C", "C", 3}, { info, 0, 0, 3}, { info, "Qualifications\tAlt+E", "\345", 3}, { 0, 0, 0, 0 } }; int i; int count=0; for (i=0; item[i].menu; i++) if (item[i].name) count++; macro=new const char* [count]; game->insertItem("Qt settings...",1000); help->insertItem("About Qt NetHack...",2000); //help->insertItem("NetHack Guidebook...",3000); help->insertSeparator(); count=0; for (i=0; item[i].menu; i++) { if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) { if (item[i].name) { QString name = item[i].name; if ( qt_compact_mode ) // accelerators aren't name.replace(QRegExp("\t.*"),""); item[i].menu->insertItem(name,count); macro[count++]=item[i].action; } else { item[i].menu->insertSeparator(); } } } menubar->insertItem("Game",game); menubar->insertItem("Gear",apparel); if ( qt_compact_mode ) { menubar->insertItem("A-J",act1); menubar->insertItem("K-Z",act2); menubar->insertItem("Magic",magic); menubar->insertItem(QPixmap(info_xpm),info); menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap())); menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages())); menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus())); } else { menubar->insertItem("Action",act1); menubar->insertItem("Magic",magic); menubar->insertItem("Info",info); menubar->insertSeparator(); menubar->insertItem("Help",help); } QSignalMapper* sm = new QSignalMapper(this); connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&))); QToolButton* tb; tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "\001" ); tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "," ); tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "\004" ); tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "t" ); tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "f" ); tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "D" ); tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "e" ); tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "." ); tb = new SmallToolButton( QPixmap(cast_a_xpm),"Cast A","Magic", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "Za" ); tb = new SmallToolButton( QPixmap(cast_b_xpm),"Cast B","Magic", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "Zb" ); tb = new SmallToolButton( QPixmap(cast_c_xpm),"Cast C","Magic", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "Zc" ); if ( !qt_compact_mode ) { QWidget* filler = new QWidget(toolbar); filler->setBackgroundMode(PaletteButton); toolbar->setStretchableWidget(filler); } connect(menubar,SIGNAL(activated(int)),this,SLOT(doMenuItem(int))); #ifdef KDE setMenu (menubar); #endif int x=0,y=0; int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame int h=QApplication::desktop()->height()-50; int maxwn; int maxhn; if (qt_tilewidth != NULL) { maxwn = atoi(qt_tilewidth) * COLNO + 10; } else { maxwn = 1400; } if (qt_tileheight != NULL) { maxhn = atoi(qt_tileheight) * ROWNO * 6/4; } else { maxhn = 1024; } // Be exactly the size we want to be - full map... if (w>maxwn) { x+=(w-maxwn)/2; w=maxwn; // Doesn't need to be any wider } if (h>maxhn) { y+=(h-maxhn)/2; h=maxhn; // Doesn't need to be any taller } setGeometry(x,y,w,h); if ( qt_compact_mode ) { stack = new QWidgetStack(this); setCentralWidget(stack); } else { setCentralWidget(new QWidget(this)); invusage = new NetHackQtInvUsageWindow(centralWidget()); } } void NetHackQtMainWindow::zoomMap() { qt_settings->toggleGlyphSize(); } void NetHackQtMainWindow::raiseMap() { if ( stack->id(stack->visibleWidget()) == 0 ) { zoomMap(); } else { stack->raiseWidget(0); } } void NetHackQtMainWindow::raiseMessages() { stack->raiseWidget(1); } void NetHackQtMainWindow::raiseStatus() { stack->raiseWidget(2); } class NetHackMimeSourceFactory : public QMimeSourceFactory { public: const QMimeSource* data(const QString& abs_name) const { const QMimeSource* r = 0; if ( (NetHackMimeSourceFactory*)this == QMimeSourceFactory::defaultFactory() ) r = QMimeSourceFactory::data(abs_name); else r = QMimeSourceFactory::defaultFactory()->data(abs_name); if ( !r ) { int sl = abs_name.length(); do { sl = abs_name.findRev('/',sl-1); QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name; int dot = name.findRev('.'); if ( dot >= 0 ) name = name.left(dot); if ( name == "map" ) r = new QImageDrag(QImage(map_xpm)); else if ( name == "msg" ) r = new QImageDrag(QImage(msg_xpm)); else if ( name == "stat" ) r = new QImageDrag(QImage(stat_xpm)); } while (!r && sl>0); } return r; } }; void NetHackQtMainWindow::doMenuItem(int id) { switch (id) { case 1000: centerOnMain(qt_settings); qt_settings->show(); break; case 2000: QMessageBox::about(this, "About Qt NetHack", aboutMsg()); break; case 3000: { QDialog dlg(this,0,TRUE); (new QVBoxLayout(&dlg))->setAutoAdd(TRUE); QTextBrowser browser(&dlg); NetHackMimeSourceFactory ms; browser.setMimeSourceFactory(&ms); browser.setSource(QDir::currentDirPath()+"/Guidebook.html"); if ( qt_compact_mode ) dlg.showMaximized(); dlg.exec(); } break; default: if ( id >= 0 ) doKeys(macro[id]); } } void NetHackQtMainWindow::doKeys(const QString& k) { keysink.Put(k); qApp->exit_loop(); } void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) { message=window; ShowIfReady(); } void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow* window) { map=window; ShowIfReady(); connect(map,SIGNAL(resized()),this,SLOT(layout())); } void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) { status=window; ShowIfReady(); } void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window) { if (window==status) { status=0; ShowIfReady(); } else if (window==map) { map=0; ShowIfReady(); } else if (window==message) { message=0; ShowIfReady(); } } void NetHackQtMainWindow::updateInventory() { if ( invusage ) invusage->repaint(FALSE); } void NetHackQtMainWindow::fadeHighlighting() { if (status) { status->fadeHighlighting(); } } void NetHackQtMainWindow::layout() { if ( qt_compact_mode ) return; if (message && map && status) { QSize maxs=map->Widget()->maximumSize(); int maph=QMIN(height()*2/3,maxs.height()); QWidget* c = centralWidget(); int h=c->height(); int toph=h-maph; int iuw=3*qt_settings->glyphs().width(); int topw=(c->width()-iuw)/2; message->Widget()->setGeometry(0,0,topw,toph); invusage->setGeometry(topw,0,iuw,toph); status->Widget()->setGeometry(topw+iuw,0,topw,toph); map->Widget()->setGeometry(QMAX(0,(c->width()-maxs.width())/2), toph,c->width(),maph); } } void NetHackQtMainWindow::resizeEvent(QResizeEvent*) { layout(); #ifdef KDE updateRects(); #endif } void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event) { if ( dirkey ) { doKeys(QString(QChar(dirkey))); if ( !event->isAutoRepeat() ) dirkey = 0; } } void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) { // Global key controls // For desktop, arrow keys scroll map, since we don't want players // to think that's the way to move. For handhelds, the normal way is to // click-to-travel, so we allow the cursor keys for fine movements. // 321 // 4 0 // 567 if ( event->isAutoRepeat() && event->key() >= Key_Left && event->key() <= Key_Down ) return; const char* d = Cmd.dirchars; switch (event->key()) { case Key_Up: if ( dirkey == d[0] ) dirkey = d[1]; else if ( dirkey == d[4] ) dirkey = d[3]; else dirkey = d[2]; break; case Key_Down: if ( dirkey == d[0] ) dirkey = d[7]; else if ( dirkey == d[4] ) dirkey = d[5]; else dirkey = d[6]; break; case Key_Left: if ( dirkey == d[2] ) dirkey = d[1]; else if ( dirkey == d[6] ) dirkey = d[7]; else dirkey = d[0]; break; case Key_Right: if ( dirkey == d[2] ) dirkey = d[3]; else if ( dirkey == d[6] ) dirkey = d[5]; else dirkey = d[4]; break; case Key_Prior: dirkey = 0; if (message) message->Scroll(0,-1); break; case Key_Next: dirkey = 0; if (message) message->Scroll(0,+1); break; case Key_Space: if ( flags.rest_on_space ) { event->ignore(); return; } case Key_Enter: if ( map ) map->clickCursor(); break; default: dirkey = 0; event->ignore(); } } void NetHackQtMainWindow::closeEvent(QCloseEvent* e) { if ( program_state.something_worth_saving ) { switch ( QMessageBox::information( this, "NetHack", "This will end your NetHack session", "&Save", "&Cancel", 0, 1 ) ) { case 0: // See dosave() function if (dosave0()) { u.uhp = -1; NetHackQtBind::qt_exit_nhwindows(0); terminate(EXIT_SUCCESS); } break; case 1: break; // ignore the event } } else { e->accept(); } } void NetHackQtMainWindow::ShowIfReady() { if (message && map && status) { QPoint pos(0,0); QWidget* p = qt_compact_mode ? stack : centralWidget(); message->Widget()->recreate(p,0,pos); map->Widget()->recreate(p,0,pos); status->Widget()->recreate(p,0,pos); if ( qt_compact_mode ) { message->setMap(map); stack->addWidget(map->Widget(), 0); stack->addWidget(message->Widget(), 1); stack->addWidget(status->Widget(), 2); raiseMap(); } else { layout(); } showMaximized(); } else if (isVisible()) { hide(); } } NetHackQtYnDialog::NetHackQtYnDialog(NetHackQtKeyBuffer& keysrc,const char* q,const char* ch,char df) : QDialog(qApp->mainWidget(),0,FALSE), question(q), choices(ch), def(df), keysource(keysrc) { setCaption("NetHack: Question"); } char NetHackQtYnDialog::Exec() { QString ch(choices); int ch_per_line=6; QString qlabel; QString enable; if ( qt_compact_mode && !choices ) { // expand choices from prompt // ##### why isn't choices set properly??? const char* c=question; while ( *c && *c != '[' ) c++; qlabel = QString(question).left(c-question); if ( *c ) { c++; if ( *c == '-' ) ch.append(*c++); char from=0; while ( *c && *c != ']' && *c != ' ' ) { if ( *c == '-' ) { from = c[-1]; } else if ( from ) { for (char f=from+1; f<=*c; f++) ch.append(f); from = 0; } else { ch.append(*c); from = 0; } c++; } if ( *c == ' ' ) { while ( *c && *c != ']' ) { if ( *c == '*' || *c == '?' ) ch.append(*c); c++; } } } if ( strstr(question, "what direction") ) { // We replace this regardless, since sometimes you get choices. const char* d = Cmd.dirchars; enable=ch; ch=""; ch.append(d[1]); ch.append(d[2]); ch.append(d[3]); ch.append(d[0]); ch.append('.'); ch.append(d[4]); ch.append(d[7]); ch.append(d[6]); ch.append(d[5]); ch.append(d[8]); ch.append(d[9]); ch_per_line = 3; def = ' '; } else { // Hmm... they'll have to use a virtual keyboard } } else { qlabel = question; } if (!ch.isNull()) { QVBoxLayout vb(this); vb.setAutoAdd(TRUE); bool bigq = qlabel.length()>40; if ( bigq ) { QLabel* q = new QLabel(qlabel,this); q->setAlignment(AlignLeft|WordBreak); q->setMargin(4); } QButtonGroup group(ch_per_line, Horizontal, bigq ? QString::null : qlabel, this); int nchoices=ch.length(); bool allow_count=ch.contains('#'); const int margin=8; const int gutter=8; const int extra=fontMetrics().height(); // Extra for group int x=margin, y=extra+margin; int butsize=fontMetrics().height()*2+5; QPushButton* button; for (int i=0; isetEnabled(FALSE); } button->setFixedSize(butsize,butsize); // Square if (ch[i]==def) button->setDefault(TRUE); if (i%10==9) { // last in row x=margin; y+=butsize+gutter; } else { x+=butsize+gutter; } } connect(&group,SIGNAL(clicked(int)),this,SLOT(doneItem(int))); QLabel* lb=0; QLineEdit* le=0; if (allow_count) { QHBox *hb = new QHBox(this); lb=new QLabel("Count: ",hb); le=new QLineEdit(hb); } adjustSize(); centerOnMain(this); show(); char choice=0; char ch_esc=0; for (uint i=0; i= 1000 ) { choice = ch[result() - 1000].latin1(); } if ( !choice ) qApp->enter_loop(); } hide(); if (allow_count && !le->text().isEmpty()) { yn_number=atoi(le->text()); choice='#'; } return choice; } else { QLabel label(qlabel,this); QPushButton cancel("Dismiss",this); label.setFrameStyle(QFrame::Box|QFrame::Sunken); label.setAlignment(AlignCenter); label.resize(fontMetrics().width(qlabel)+60,30+fontMetrics().height()); cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8); connect(&cancel,SIGNAL(clicked()),this,SLOT(reject())); centerOnMain(this); setResult(-1); show(); while (result()<0 && keysource.Empty()) { qApp->enter_loop(); } hide(); if (keysource.Empty()) { return '\033'; } else { return keysource.GetAscii(); } } } void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) { // Don't want QDialog's Return/Esc behaviour event->ignore(); } void NetHackQtYnDialog::doneItem(int i) { done(i+1000); } void NetHackQtYnDialog::done(int i) { setResult(i); qApp->exit_loop(); } NetHackQtGlyphs::NetHackQtGlyphs() { const char* tile_file = "nhtiles.bmp"; if ( iflags.wc_tile_file ) tile_file = iflags.wc_tile_file; if (!img.load(tile_file)) { tile_file = "x11tiles"; if (!img.load(tile_file)) { QString msg; msg.sprintf("Cannot load x11tiles or nhtiles.bmp"); QMessageBox::warning(0, "IO Error", msg); } else { tiles_per_row = TILES_PER_ROW; if (img.width()%tiles_per_row) { impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)", tile_file, img.width(), tiles_per_row); } } } else { tiles_per_row = 40; } if ( iflags.wc_tile_width ) tilefile_tile_W = iflags.wc_tile_width; else tilefile_tile_W = img.width() / tiles_per_row; if ( iflags.wc_tile_height ) tilefile_tile_H = iflags.wc_tile_height; else tilefile_tile_H = tilefile_tile_W; setSize(tilefile_tile_W, tilefile_tile_H); } void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y) { int tile = glyph2tile[glyph]; int px = (tile%tiles_per_row)*width(); int py = tile/tiles_per_row*height(); painter.drawPixmap( x, y, pm, px,py, width(),height() ); } void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly) { drawGlyph(painter,glyph,cellx*width(),celly*height()); } void NetHackQtGlyphs::setSize(int w, int h) { if ( size == QSize(w,h) ) return; bool was1 = size == pm1.size(); size = QSize(w,h); if (!w || !h) return; // Still not decided if ( size == pm1.size() ) { pm = pm1; return; } if ( size == pm2.size() ) { pm = pm2; return; } if (w==tilefile_tile_W && h==tilefile_tile_H) { pm.convertFromImage(img); } else { QApplication::setOverrideCursor( Qt::waitCursor ); QImage scaled = img.smoothScale( w*img.width()/tilefile_tile_W, h*img.height()/tilefile_tile_H ); pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither); QApplication::restoreOverrideCursor(); } (was1 ? pm2 : pm1) = pm; } ////////////////////////////////////////////////////////////// // // The ugly C binding classes... // ////////////////////////////////////////////////////////////// NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer& ks) : actual(0), keysource(ks) { } QWidget* NetHackQtMenuOrTextWindow::Widget() { if (!actual) impossible("Widget called before we know if Menu or Text"); return actual->Widget(); } // Text void NetHackQtMenuOrTextWindow::Clear() { if (!actual) impossible("Clear called before we know if Menu or Text"); actual->Clear(); } void NetHackQtMenuOrTextWindow::Display(bool block) { if (!actual) impossible("Display called before we know if Menu or Text"); actual->Display(block); } bool NetHackQtMenuOrTextWindow::Destroy() { if (!actual) impossible("Destroy called before we know if Menu or Text"); return actual->Destroy(); } void NetHackQtMenuOrTextWindow::PutStr(int attr, const char* text) { if (!actual) actual=new NetHackQtTextWindow(keysource); actual->PutStr(attr,text); } // Menu void NetHackQtMenuOrTextWindow::StartMenu() { if (!actual) actual=new NetHackQtMenuWindow(keysource); actual->StartMenu(); } void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel) { if (!actual) impossible("AddMenu called before we know if Menu or Text"); actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel); } void NetHackQtMenuOrTextWindow::EndMenu(const char* prompt) { if (!actual) impossible("EndMenu called before we know if Menu or Text"); actual->EndMenu(prompt); } int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { if (!actual) impossible("SelectMenu called before we know if Menu or Text"); return actual->SelectMenu(how,menu_list); } // XXX Should be from Options // // XXX Hmm. Tricky part is that perhaps some macros should only be active // XXX when a key is about to be gotten. For example, the user could // XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for // XXX other purposes. Maybe just too bad. // struct { int key; int state; const char* macro; } key_macro[]={ { Qt::Key_F1, 0, "n100." }, // Rest (x100) { Qt::Key_F2, 0, "n20s" }, // Search (x20) { Qt::Key_F3, 0, "o8o4o6o2o8o4o6o2o8o4o6o2" }, // Open all doors (x3) { Qt::Key_Tab, 0, "\001" }, { 0, 0, 0 } }; NetHackQtBind::NetHackQtBind(int& argc, char** argv) : #ifdef KDE KApplication(argc,argv) #elif defined(QWS) // not quite the right condition QPEApplication(argc,argv) #else QApplication(argc,argv) #endif { QPixmap pm("nhsplash.xpm"); if ( iflags.wc_splash_screen && !pm.isNull() ) { QVBox *vb = new QVBox(0,0, WStyle_Customize | WStyle_NoBorder | nh_WX11BypassWM | WStyle_StaysOnTop ); splash = vb; QLabel *lsplash = new QLabel(vb); lsplash->setAlignment(AlignCenter); lsplash->setPixmap(pm); QLabel* capt = new QLabel("Loading...",vb); capt->setAlignment(AlignCenter); if ( pm.mask() ) { lsplash->setFixedSize(pm.size()); lsplash->setMask(*pm.mask()); } splash->move((QApplication::desktop()->width()-pm.width())/2, (QApplication::desktop()->height()-pm.height())/2); //splash->setGeometry(0,0,100,100); if ( qt_compact_mode ) { splash->showMaximized(); } else { vb->setFrameStyle(QFrame::WinPanel|QFrame::Raised); vb->setMargin(10); splash->adjustSize(); splash->show(); } // force content refresh outside event loop splash->repaint(FALSE); lsplash->repaint(FALSE); capt->repaint(FALSE); qApp->flushX(); } else { splash = 0; } main = new NetHackQtMainWindow(keybuffer); #if defined(QWS) // not quite the right condition showMainWidget(main); #else setMainWidget(main); #endif qt_settings=new NetHackQtSettings(main->width(),main->height()); } void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv) { #ifdef UNIX // Userid control // // Michael Hohmuth ... // // As the game runs setuid games, it must seteuid(getuid()) before // calling XOpenDisplay(), and reset the euid afterwards. // Otherwise, it can't read the $HOME/.Xauthority file and whines about // not being able to open the X display (if a magic-cookie // authorization mechanism is being used). uid_t gamesuid=geteuid(); seteuid(getuid()); #endif QApplication::setColorSpec(ManyColor); instance=new NetHackQtBind(*argc,argv); #ifdef UNIX seteuid(gamesuid); #endif #ifdef _WS_WIN_ // This nethack engine feature should be moved into windowport API nt_kbhit = NetHackQtBind::qt_kbhit; #endif } int NetHackQtBind::qt_kbhit() { return !keybuffer.Empty(); } static bool have_asked = FALSE; void NetHackQtBind::qt_player_selection() { if ( !have_asked ) qt_askname(); } NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : QDialog(qApp->mainWidget(),"sgsel",TRUE) { QVBoxLayout *vbl = new QVBoxLayout(this,6); QHBox* hb; QLabel* logo = new QLabel(this); vbl->addWidget(logo); logo->setAlignment(AlignCenter); logo->setPixmap(QPixmap("nhsplash.xpm")); QLabel* attr = new QLabel("by the NetHack DevTeam",this); attr->setAlignment(AlignCenter); vbl->addWidget(attr); vbl->addStretch(2); /* QLabel* logo = new QLabel(hb); hb = new QHBox(this); vbl->addWidget(hb, AlignCenter); logo->setPixmap(QPixmap(nh_icon)); logo->setAlignment(AlignRight|AlignVCenter); new QLabel(nh_attribution,hb); */ hb = new QHBox(this); vbl->addWidget(hb, AlignCenter); QPushButton* q = new QPushButton("Quit",hb); connect(q, SIGNAL(clicked()), this, SLOT(reject())); QPushButton* c = new QPushButton("New Game",hb); connect(c, SIGNAL(clicked()), this, SLOT(accept())); c->setDefault(TRUE); QButtonGroup* bg = new QButtonGroup(3, Horizontal, "Saved Characters",this); vbl->addWidget(bg); connect(bg, SIGNAL(clicked(int)), this, SLOT(done(int))); for (int i=0; saved[i]; i++) { QPushButton* b = new QPushButton(saved[i],bg); bg->insert(b, i+2); } } int NetHackQtSavedGameSelector::choose() { #if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). if ( qt_compact_mode ) showMaximized(); #endif return exec()-2; } void NetHackQtBind::qt_askname() { have_asked = TRUE; // We do it all here, and nothing in askname char** saved = get_saved_games(); int ch = -1; if ( saved && *saved ) { if ( splash ) splash->hide(); NetHackQtSavedGameSelector sgsel((const char**)saved); ch = sgsel.choose(); if ( ch >= 0 ) strcpy(plname,saved[ch]); } free_saved_games(saved); switch (ch) { case -1: if ( splash ) splash->hide(); if (NetHackQtPlayerSelector(keybuffer).Choose()) return; case -2: break; default: return; } // Quit clearlocks(); qt_exit_nhwindows(0); terminate(0); } void NetHackQtBind::qt_get_nh_event() { } #if defined(QWS) // Kludge to access lastWindowClosed() signal. class TApp : public QApplication { public: TApp(int& c, char**v) : QApplication(c,v) {} void lwc() { emit lastWindowClosed(); } }; #endif void NetHackQtBind::qt_exit_nhwindows(const char *) { #if defined(QWS) // Avoids bug in SHARP SL5500 ((TApp*)qApp)->lwc(); qApp->quit(); #endif delete instance; // ie. qApp } void NetHackQtBind::qt_suspend_nhwindows(const char *) { } void NetHackQtBind::qt_resume_nhwindows() { } static QArray id_to_window; winid NetHackQtBind::qt_create_nhwindow(int type) { winid id; for (id = 0; id < (winid) id_to_window.size(); id++) { if ( !id_to_window[id] ) break; } if ( id == (winid) id_to_window.size() ) id_to_window.resize(id+1); NetHackQtWindow* window=0; switch (type) { case NHW_MAP: { NetHackQtMapWindow* w=new NetHackQtMapWindow(clickbuffer); main->AddMapWindow(w); window=w; } break; case NHW_MESSAGE: { NetHackQtMessageWindow* w=new NetHackQtMessageWindow; main->AddMessageWindow(w); window=w; } break; case NHW_STATUS: { NetHackQtStatusWindow* w=new NetHackQtStatusWindow; main->AddStatusWindow(w); window=w; } break; case NHW_MENU: window=new NetHackQtMenuOrTextWindow(keybuffer); break; case NHW_TEXT: window=new NetHackQtTextWindow(keybuffer); } window->nhid = id; // Note: use of isHidden does not work with Qt 2.1 if ( splash #if QT_VERSION >= 300 && !main->isHidden() #else && main->isVisible() #endif ) { delete splash; splash = 0; } id_to_window[id] = window; return id; } void NetHackQtBind::qt_clear_nhwindow(winid wid) { NetHackQtWindow* window=id_to_window[wid]; window->Clear(); } void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block) { NetHackQtWindow* window=id_to_window[wid]; window->Display(block); } void NetHackQtBind::qt_destroy_nhwindow(winid wid) { NetHackQtWindow* window=id_to_window[wid]; main->RemoveWindow(window); if (window->Destroy()) delete window; id_to_window[wid] = 0; } void NetHackQtBind::qt_curs(winid wid, int x, int y) { NetHackQtWindow* window=id_to_window[wid]; window->CursorTo(x,y); } void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text) { NetHackQtWindow* window=id_to_window[wid]; window->PutStr(attr,text); } void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist) { NetHackQtTextWindow* window=new NetHackQtTextWindow(keybuffer); bool complain = FALSE; #ifdef DLB { dlb *f; char buf[BUFSZ]; char *cr; window->Clear(); f = dlb_fopen(filename, "r"); if (!f) { complain = must_exist; } else { while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; #ifdef MSDOS if ((cr = index(buf, '\r')) != 0) *cr = 0; #endif if (index(buf, '\t') != 0) (void) tabexpand(buf); window->PutStr(ATR_NONE, buf); } window->Display(FALSE); (void) dlb_fclose(f); } } #else QFile file(filename); if (file.open(IO_ReadOnly)) { char line[128]; while (file.readLine(line,127) >= 0) { line[strlen(line)-1]=0;// remove newline window->PutStr(ATR_NONE,line); } window->Display(FALSE); } else { complain = must_exist; } #endif if (complain) { QString message; message.sprintf("File not found: %s\n",filename); QMessageBox::message("File Error", (const char*)message, "Ignore"); } } void NetHackQtBind::qt_start_menu(winid wid) { NetHackQtWindow* window=id_to_window[wid]; window->StartMenu(); } void NetHackQtBind::qt_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr, const char *str, BOOLEAN_P presel) { NetHackQtWindow* window=id_to_window[wid]; window->AddMenu(glyph, identifier, ch, gch, attr, str, presel); } void NetHackQtBind::qt_end_menu(winid wid, const char *prompt) { NetHackQtWindow* window=id_to_window[wid]; window->EndMenu(prompt); } int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list) { NetHackQtWindow* window=id_to_window[wid]; return window->SelectMenu(how,menu_list); } void NetHackQtBind::qt_update_inventory() { if (main) main->updateInventory(); /* doesn't work yet if (program_state.something_worth_saving && flags.perm_invent) display_inventory(NULL, FALSE); */ } void NetHackQtBind::qt_mark_synch() { } void NetHackQtBind::qt_wait_synch() { } void NetHackQtBind::qt_cliparound(int x, int y) { // XXXNH - winid should be a parameter! qt_cliparound_window(WIN_MAP,x,y); } void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y) { NetHackQtWindow* window=id_to_window[wid]; window->ClipAround(x,y); } void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph, int bkglyph) { NetHackQtWindow* window=id_to_window[wid]; window->PrintGlyph(x,y,glyph); } //void NetHackQtBind::qt_print_glyph_compose(winid wid,XCHAR_P x,XCHAR_P y,int glyph1, int glyph2) //{ //NetHackQtWindow* window=id_to_window[wid]; //window->PrintGlyphCompose(x,y,glyph1,glyph2); //} void NetHackQtBind::qt_raw_print(const char *str) { puts(str); } void NetHackQtBind::qt_raw_print_bold(const char *str) { puts(str); } int NetHackQtBind::qt_nhgetch() { if (main) main->fadeHighlighting(); // Process events until a key arrives. // while (keybuffer.Empty() #ifdef SAFERHANGUP && !program_state.done_hup #endif ) { qApp->enter_loop(); } #ifdef SAFERHANGUP if (program_state.done_hup && keybuffer.Empty()) return '\033'; #endif return keybuffer.GetAscii(); } int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod) { if (main) main->fadeHighlighting(); // Process events until a key or map-click arrives. // while (keybuffer.Empty() && clickbuffer.Empty() #ifdef SAFERHANGUP && !program_state.done_hup #endif ) { qApp->enter_loop(); } #ifdef SAFERHANGUP if (program_state.done_hup && keybuffer.Empty()) return '\033'; #endif if (!keybuffer.Empty()) { return keybuffer.GetAscii(); } else { *x=clickbuffer.NextX(); *y=clickbuffer.NextY(); *mod=clickbuffer.NextMod(); clickbuffer.Get(); return 0; } } void NetHackQtBind::qt_nhbell() { QApplication::beep(); } int NetHackQtBind::qt_doprev_message() { // Don't need it - uses scrollbar // XXX but could make this a shortcut return 0; } char NetHackQtBind::qt_yn_function(const char *question, const char *choices, CHAR_P def) { if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { // Similar to X11 windowport `slow' feature. char message[BUFSZ]; char yn_esc_map='\033'; if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { // anything beyond is hidden *cb = '\0'; } (void)strncpy(message, question, QBUFSZ-1); message[QBUFSZ-1] = '\0'; Sprintf(eos(message), " [%s]", choicebuf); if (def) Sprintf(eos(message), " (%c)", def); Strcat(message, " "); // escape maps to 'q' or 'n' or default, in that order yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); } #ifdef USE_POPUPS // Improve some special-cases (DIRKS 08/02/23) if (strcmp (choices,"ynq") == 0) { switch (QMessageBox::information (qApp->mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2)) { case 0: return 'y'; case 1: return 'n'; case 2: return 'q'; } } if (strcmp (choices,"yn") == 0) { switch (QMessageBox::information(qApp->mainWidget(),"NetHack",question,"&Yes", "&No",0,1)) { case 0: return 'y'; case 1: return 'n'; } } #endif NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); int result=-1; while (result<0) { char ch=NetHackQtBind::qt_nhgetch(); if (ch=='\033') { result=yn_esc_map; } else if (choices && !index(choices,ch)) { if (def && (ch==' ' || ch=='\r' || ch=='\n')) { result=def; } else { NetHackQtBind::qt_nhbell(); // and try again... } } else { result=ch; } } NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); return result; } else { NetHackQtYnDialog dialog(keybuffer,question,choices,def); return dialog.Exec(); } } void NetHackQtBind::qt_getlin(const char *prompt, char *line) { NetHackQtStringRequestor requestor(keybuffer,prompt); if (!requestor.Get(line)) { line[0]=0; } } NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks) : QDialog(qApp->mainWidget(), "ext-cmd", FALSE), keysource(ks) { int marg=4; QVBoxLayout *l = new QVBoxLayout(this,marg,marg); QPushButton* can = new QPushButton("Cancel", this); can->setDefault(TRUE); can->setMinimumSize(can->sizeHint()); l->addWidget(can); QButtonGroup *group=new QButtonGroup("",0); QGroupBox *grid=new QGroupBox("Extended commands",this); l->addWidget(grid); int i; int butw=50; QFontMetrics fm = fontMetrics(); for (i=0; extcmdlist[i].ef_txt; i++) { butw = QMAX(butw,30+fm.width(extcmdlist[i].ef_txt)); } int ncols=4; int nrows=(i+ncols-1)/ncols; QVBoxLayout* bl = new QVBoxLayout(grid,marg); bl->addSpacing(fm.height()); QGridLayout* gl = new QGridLayout(nrows,ncols,marg); bl->addLayout(gl); for (i=0; extcmdlist[i].ef_txt; i++) { QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid); pb->setMinimumSize(butw,pb->sizeHint().height()); group->insert(pb); gl->addWidget(pb,i/ncols,i%ncols); } connect(group,SIGNAL(clicked(int)),this,SLOT(done(int))); bl->activate(); l->activate(); resize(1,1); connect(can,SIGNAL(clicked()),this,SLOT(cancel())); } void NetHackQtExtCmdRequestor::cancel() { setResult(-1); qApp->exit_loop(); } void NetHackQtExtCmdRequestor::done(int i) { setResult(i); qApp->exit_loop(); } int NetHackQtExtCmdRequestor::get() { const int none = -10; char str[32]; int cursor=0; resize(1,1); // pack centerOnMain(this); show(); setResult(none); while (result()==none) { while (result()==none && !keysource.Empty()) { char k=keysource.GetAscii(); if (k=='\r' || k=='\n' || k==' ' || k=='\033') { setResult(-1); } else { str[cursor++] = k; int r=-1; for (int i=0; extcmdlist[i].ef_txt; i++) { if (qstrnicmp(str, extcmdlist[i].ef_txt, cursor)==0) { if ( r == -1 ) r = i; else r = -2; } } if ( r == -1 ) { // no match! QApplication::beep(); cursor=0; } else if ( r != -2 ) { // only one match setResult(r); } } } if (result()==none) qApp->enter_loop(); } hide(); return result(); } int NetHackQtBind::qt_get_ext_cmd() { NetHackQtExtCmdRequestor requestor(keybuffer); return requestor.get(); } void NetHackQtBind::qt_number_pad(int) { // Ignore. } void NetHackQtBind::qt_delay_output() { NetHackQtDelay delay(15); delay.wait(); } void NetHackQtBind::qt_start_screen() { // Ignore. } void NetHackQtBind::qt_end_screen() { // Ignore. } void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) { NetHackQtWindow* window=id_to_window[wid]; window->UseRIP(how, when); } bool NetHackQtBind::notify(QObject *receiver, QEvent *event) { // Ignore Alt-key navigation to menubar, it's annoying when you // use Alt-Direction to move around. if ( main && event->type()==QEvent::KeyRelease && main==receiver && ((QKeyEvent*)event)->key() == Key_Alt ) return TRUE; bool result=QApplication::notify(receiver,event); #ifdef SAFERHANGUP if (program_state.done_hup) { keybuffer.Put('\033'); qApp->exit_loop(); return TRUE; } #endif if (event->type()==QEvent::KeyPress) { QKeyEvent* key_event=(QKeyEvent*)event; if (!key_event->isAccepted()) { const int k=key_event->key(); bool macro=FALSE; for (int i=0; !macro && key_macro[i].key; i++) { if (key_macro[i].key==k && ((key_macro[i].state&key_event->state())==key_macro[i].state)) { keybuffer.Put(key_macro[i].macro); macro=TRUE; } } char ch=key_event->ascii(); if ( !ch && (key_event->state() & Qt::ControlButton) ) { // On Mac, it aint-ncessarily-control if ( k>=Qt::Key_A && k<=Qt::Key_Z ) ch = k - Qt::Key_A + 1; } if (!macro && ch) { bool alt = (key_event->state()&AltButton) || (k >= Key_0 && k <= Key_9 && (key_event->state()&ControlButton)); keybuffer.Put(key_event->key(),ch + (alt ? 128 : 0), key_event->state()); key_event->accept(); result=TRUE; } if (ch || macro) { qApp->exit_loop(); } } } return result; } NetHackQtBind* NetHackQtBind::instance=0; NetHackQtKeyBuffer NetHackQtBind::keybuffer; NetHackQtClickBuffer NetHackQtBind::clickbuffer; NetHackQtMainWindow* NetHackQtBind::main=0; QWidget* NetHackQtBind::splash=0; extern "C" struct window_procs Qt_procs; struct window_procs Qt_procs = { "Qt", WC_COLOR|WC_HILITE_PET| WC_ASCII_MAP|WC_TILED_MAP| WC_FONT_MAP|WC_TILE_FILE|WC_TILE_WIDTH|WC_TILE_HEIGHT| WC_PLAYER_SELECTION|WC_SPLASH_SCREEN, 0L, NetHackQtBind::qt_init_nhwindows, NetHackQtBind::qt_player_selection, NetHackQtBind::qt_askname, NetHackQtBind::qt_get_nh_event, NetHackQtBind::qt_exit_nhwindows, NetHackQtBind::qt_suspend_nhwindows, NetHackQtBind::qt_resume_nhwindows, NetHackQtBind::qt_create_nhwindow, NetHackQtBind::qt_clear_nhwindow, NetHackQtBind::qt_display_nhwindow, NetHackQtBind::qt_destroy_nhwindow, NetHackQtBind::qt_curs, NetHackQtBind::qt_putstr, genl_putmixed, NetHackQtBind::qt_display_file, NetHackQtBind::qt_start_menu, NetHackQtBind::qt_add_menu, NetHackQtBind::qt_end_menu, NetHackQtBind::qt_select_menu, genl_message_menu, /* no need for X-specific handling */ NetHackQtBind::qt_update_inventory, NetHackQtBind::qt_mark_synch, NetHackQtBind::qt_wait_synch, #ifdef CLIPPING NetHackQtBind::qt_cliparound, #endif #ifdef POSITIONBAR donull, #endif NetHackQtBind::qt_print_glyph, //NetHackQtBind::qt_print_glyph_compose, NetHackQtBind::qt_raw_print, NetHackQtBind::qt_raw_print_bold, NetHackQtBind::qt_nhgetch, NetHackQtBind::qt_nh_poskey, NetHackQtBind::qt_nhbell, NetHackQtBind::qt_doprev_message, NetHackQtBind::qt_yn_function, NetHackQtBind::qt_getlin, NetHackQtBind::qt_get_ext_cmd, NetHackQtBind::qt_number_pad, NetHackQtBind::qt_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif /* other defs that really should go away (they're tty specific) */ NetHackQtBind::qt_start_screen, NetHackQtBind::qt_end_screen, #ifdef GRAPHIC_TOMBSTONE NetHackQtBind::qt_outrip, #else genl_outrip, #endif genl_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, # ifdef STATUS_HILITES genl_status_threshold, # endif #endif }; extern "C" void play_usersound(const char* filename, int volume) { #ifdef USER_SOUNDS #ifndef QT_NO_SOUND QSound::play(filename); #endif #endif } #include "qt_win.moc" #ifndef KDE #include "qt_kde0.moc" #endif #if QT_VERSION >= 300 #include "qttableview.moc" #endif nethack-3.6.0/win/Qt/qttableview.cpp0000664000076400007660000016311712504447330016364 0ustar paxedpaxed/********************************************************************** ** $NHDT-Branch$:$NHDT-Revision$ $NHDT-Date$ ** $Id: qttableview.cpp,v 1.2 2002/03/09 03:13:15 jwalz Exp $ ** ** Implementation of QtTableView class ** ** Created : 941115 ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file contains a class moved out of the Qt GUI Toolkit API. It ** may be used, distributed and modified without limitation. ** **********************************************************************/ #include "qttableview.h" #if QT_VERSION >= 300 #ifndef QT_NO_QTTABLEVIEW #include #include #include #include enum ScrollBarDirtyFlags { verGeometry = 0x01, verSteps = 0x02, verRange = 0x04, verValue = 0x08, horGeometry = 0x10, horSteps = 0x20, horRange = 0x40, horValue = 0x80, verMask = 0x0F, horMask = 0xF0 }; #define HSBEXT horizontalScrollBar()->sizeHint().height() #define VSBEXT verticalScrollBar()->sizeHint().width() class QCornerSquare : public QWidget // internal class { public: QCornerSquare( QWidget *, const char* = 0 ); void paintEvent( QPaintEvent * ); }; QCornerSquare::QCornerSquare( QWidget *parent, const char *name ) : QWidget( parent, name ) { } void QCornerSquare::paintEvent( QPaintEvent * ) { } // NOT REVISED /*! \class QtTableView qttableview.h \brief The QtTableView class provides an abstract base for tables. \obsolete A table view consists of a number of abstract cells organized in rows and columns, and a visible part called a view. The cells are identified with a row index and a column index. The top-left cell is in row 0, column 0. The behavior of the widget can be finely tuned using setTableFlags(); a typical subclass will consist of little more than a call to setTableFlags(), some table content manipulation and an implementation of paintCell(). Subclasses that need cells with variable width or height must reimplement cellHeight() and/or cellWidth(). Use updateTableSize() to tell QtTableView when the width or height has changed. When you read this documentation, it is important to understand the distinctions among the four pixel coordinate systems involved. \list 1 \i The \e cell coordinates. (0,0) is the top-left corner of a cell. Cell coordinates are used by functions such as paintCell(). \i The \e table coordinates. (0,0) is the top-left corner of the cell at row 0 and column 0. These coordinates are absolute; that is, they are independent of what part of the table is visible at the moment. They are used by functions such as setXOffset() or maxYOffset(). \i The \e widget coordinates. (0,0) is the top-left corner of the widget, \e including the frame. They are used by functions such as repaint(). \i The \e view coordinates. (0,0) is the top-left corner of the view, \e excluding the frame. This is the least-used coordinate system; it is used by functions such as viewWidth(). \endlist It is rather unfortunate that we have to use four different coordinate systems, but there was no alternative to provide a flexible and powerful base class. Note: The row,column indices are always given in that order, i.e., first the vertical (row), then the horizontal (column). This is the opposite order of all pixel operations, which take first the horizontal (x) and then the vertical (y). \warning the functions setNumRows(), setNumCols(), setCellHeight(), setCellWidth(), setTableFlags() and clearTableFlags() may cause virtual functions such as cellWidth() and cellHeight() to be called, even if autoUpdate() is FALSE. This may cause errors if relevant state variables are not initialized. \warning Experience has shown that use of this widget tends to cause more bugs than expected and our analysis indicates that the widget's very flexibility is the problem. If QScrollView or QListBox can easily be made to do the job you need, we recommend subclassing those widgets rather than QtTableView. In addition, QScrollView makes it easy to have child widgets inside tables, which QtTableView doesn't support at all. \sa QScrollView \link guibooks.html#fowler GUI Design Handbook: Table\endlink */ /*! Constructs a table view. The \a parent, \a name and \f arguments are passed to the QFrame constructor. The \link setTableFlags() table flags\endlink are all cleared (set to 0). Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll bars and \c Tbl_clipCellPainting to get safe clipping. The \link setCellHeight() cell height\endlink and \link setCellWidth() cell width\endlink are set to 0. Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed; see QFrame::setFrameStyle(). Note that the \a f argument is \e not \link setTableFlags() table flags \endlink but rather \link QWidget::QWidget() widget flags. \endlink */ QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f ) : QFrame( parent, name, f ) { nRows = nCols = 0; // zero rows/cols xCellOffs = yCellOffs = 0; // zero offset xCellDelta = yCellDelta = 0; // zero cell offset xOffs = yOffs = 0; // zero total pixel offset cellH = cellW = 0; // user defined cell size tFlags = 0; vScrollBar = hScrollBar = 0; // no scroll bars cornerSquare = 0; sbDirty = 0; eraseInPaint = FALSE; verSliding = FALSE; verSnappingOff = FALSE; horSliding = FALSE; horSnappingOff = FALSE; coveringCornerSquare = FALSE; inSbUpdate = FALSE; } /*! Destroys the table view. */ QtTableView::~QtTableView() { delete vScrollBar; delete hScrollBar; delete cornerSquare; } /*! \internal Reimplements QWidget::setBackgroundColor() for binary compatibility. \sa setPalette() */ void QtTableView::setBackgroundColor( const QColor &c ) { QWidget::setBackgroundColor( c ); } /*!\reimp */ void QtTableView::setPalette( const QPalette &p ) { QWidget::setPalette( p ); } /*!\reimp */ void QtTableView::show() { showOrHideScrollBars(); QWidget::show(); } /*! \overload void QtTableView::repaint( bool erase ) Repaints the entire view. */ /*! Repaints the table view directly by calling paintEvent() directly unless updates are disabled. Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a (x,y) are in \e widget coordinates. If \a w is negative, it is replaced with width() - x. If \a h is negative, it is replaced with height() - y. Doing a repaint() usually is faster than doing an update(), but calling update() many times in a row will generate a single paint event. At present, QtTableView is the only widget that reimplements \link QWidget::repaint() repaint()\endlink. It does this because by clearing and then repainting one cell at at time, it can make the screen flicker less than it would otherwise. */ void QtTableView::repaint( int x, int y, int w, int h, bool erase ) { if ( !isVisible() || testWState(WState_BlockUpdates) ) return; if ( w < 0 ) w = width() - x; if ( h < 0 ) h = height() - y; QRect r( x, y, w, h ); if ( r.isEmpty() ) return; // nothing to do QPaintEvent e( r ); if ( erase && backgroundMode() != NoBackground ) eraseInPaint = TRUE; // erase when painting paintEvent( &e ); eraseInPaint = FALSE; } /*! \overload void QtTableView::repaint( const QRect &r, bool erase ) Replaints rectangle \a r. If \a erase is TRUE draws the background using the palette's background. */ /*! \fn int QtTableView::numRows() const Returns the number of rows in the table. \sa numCols(), setNumRows() */ /*! Sets the number of rows of the table to \a rows (must be non-negative). Does not change topCell(). The table repaints itself automatically if autoUpdate() is set. \sa numCols(), setNumCols(), numRows() */ void QtTableView::setNumRows( int rows ) { if ( rows < 0 ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.", name( "unnamed" ), rows ); #endif return; } if ( nRows == rows ) return; if ( autoUpdate() && isVisible() ) { int oldLastVisible = lastRowVisible(); int oldTopCell = topCell(); nRows = rows; if ( autoUpdate() && isVisible() && ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) ) repaint( oldTopCell != topCell() ); } else { // Be more careful - if destructing, bad things might happen. nRows = rows; } updateScrollBars( verRange ); updateFrameSize(); } /*! \fn int QtTableView::numCols() const Returns the number of columns in the table. \sa numRows(), setNumCols() */ /*! Sets the number of columns of the table to \a cols (must be non-negative). Does not change leftCell(). The table repaints itself automatically if autoUpdate() is set. \sa numCols(), numRows(), setNumRows() */ void QtTableView::setNumCols( int cols ) { if ( cols < 0 ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.", name( "unnamed" ), cols ); #endif return; } if ( nCols == cols ) return; int oldCols = nCols; nCols = cols; if ( autoUpdate() && isVisible() ) { int maxCol = lastColVisible(); if ( maxCol >= oldCols || maxCol >= nCols ) repaint(); } updateScrollBars( horRange ); updateFrameSize(); } /*! \fn int QtTableView::topCell() const Returns the index of the first row in the table that is visible in the view. The index of the first row is 0. \sa leftCell(), setTopCell() */ /*! Scrolls the table so that \a row becomes the top row. The index of the very first row is 0. \sa setYOffset(), setTopLeftCell(), setLeftCell() */ void QtTableView::setTopCell( int row ) { setTopLeftCell( row, -1 ); return; } /*! \fn int QtTableView::leftCell() const Returns the index of the first column in the table that is visible in the view. The index of the very leftmost column is 0. \sa topCell(), setLeftCell() */ /*! Scrolls the table so that \a col becomes the leftmost column. The index of the leftmost column is 0. \sa setXOffset(), setTopLeftCell(), setTopCell() */ void QtTableView::setLeftCell( int col ) { setTopLeftCell( -1, col ); return; } /*! Scrolls the table so that the cell at row \a row and colum \a col becomes the top-left cell in the view. The cell at the extreme top left of the table is at position (0,0). \sa setLeftCell(), setTopCell(), setOffset() */ void QtTableView::setTopLeftCell( int row, int col ) { int newX = xOffs; int newY = yOffs; if ( col >= 0 ) { if ( cellW ) { newX = col*cellW; if ( newX > maxXOffset() ) newX = maxXOffset(); } else { newX = 0; while ( col ) newX += cellWidth( --col ); // optimize using current! ### } } if ( row >= 0 ) { if ( cellH ) { newY = row*cellH; if ( newY > maxYOffset() ) newY = maxYOffset(); } else { newY = 0; while ( row ) newY += cellHeight( --row ); // optimize using current! ### } } setOffset( newX, newY ); } /*! \fn int QtTableView::xOffset() const Returns the x coordinate in \e table coordinates of the pixel that is currently on the left edge of the view. \sa setXOffset(), yOffset(), leftCell() */ /*! Scrolls the table so that \a x becomes the leftmost pixel in the view. The \a x parameter is in \e table coordinates. The interaction with \link setTableFlags() Tbl_snapToHGrid \endlink is tricky. \sa xOffset(), setYOffset(), setOffset(), setLeftCell() */ void QtTableView::setXOffset( int x ) { setOffset( x, yOffset() ); } /*! \fn int QtTableView::yOffset() const Returns the y coordinate in \e table coordinates of the pixel that is currently on the top edge of the view. \sa setYOffset(), xOffset(), topCell() */ /*! Scrolls the table so that \a y becomes the top pixel in the view. The \a y parameter is in \e table coordinates. The interaction with \link setTableFlags() Tbl_snapToVGrid \endlink is tricky. \sa yOffset(), setXOffset(), setOffset(), setTopCell() */ void QtTableView::setYOffset( int y ) { setOffset( xOffset(), y ); } /*! Scrolls the table so that \a (x,y) becomes the top-left pixel in the view. Parameters \a (x,y) are in \e table coordinates. The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink is tricky. If \a updateScrBars is TRUE, the scroll bars are updated. \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell() */ void QtTableView::setOffset( int x, int y, bool updateScrBars ) { if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) && (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) && (x == xOffs && y == yOffs) ) return; if ( x < 0 ) x = 0; if ( y < 0 ) y = 0; if ( cellW ) { if ( x > maxXOffset() ) x = maxXOffset(); xCellOffs = x / cellW; if ( !testTableFlags(Tbl_snapToHGrid) ) { xCellDelta = (short)(x % cellW); } else { x = xCellOffs*cellW; xCellDelta = 0; } } else { int xn=0, xcd=0, col = 0; while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) { xn += xcd; col++; } xCellOffs = col; if ( testTableFlags(Tbl_snapToHGrid) ) { xCellDelta = 0; x = xn; } else { xCellDelta = (short)(x-xn); } } if ( cellH ) { if ( y > maxYOffset() ) y = maxYOffset(); yCellOffs = y / cellH; if ( !testTableFlags(Tbl_snapToVGrid) ) { yCellDelta = (short)(y % cellH); } else { y = yCellOffs*cellH; yCellDelta = 0; } } else { int yn=0, yrd=0, row=0; while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) { yn += yrd; row++; } yCellOffs = row; if ( testTableFlags(Tbl_snapToVGrid) ) { yCellDelta = 0; y = yn; } else { yCellDelta = (short)(y-yn); } } int dx = (x - xOffs); int dy = (y - yOffs); xOffs = x; yOffs = y; if ( autoUpdate() && isVisible() ) scroll( dx, dy ); if ( updateScrBars ) updateScrollBars( verValue | horValue ); } /*! \overload int QtTableView::cellWidth() const Returns the column width in pixels. Returns 0 if the columns have variable widths. \sa setCellWidth(), cellHeight() */ /*! Returns the width of column \a col in pixels. This function is virtual and must be reimplemented by subclasses that have variable cell widths. Note that if the total table width changes, updateTableSize() must be called. \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize() */ int QtTableView::cellWidth( int ) { return cellW; } /*! Sets the width in pixels of the table cells to \a cellWidth. Setting it to 0 means that the column width is variable. When set to 0 (this is the default) QtTableView calls the virtual function cellWidth() to get the width. \sa cellWidth(), setCellHeight(), totalWidth(), numCols() */ void QtTableView::setCellWidth( int cellWidth ) { if ( cellW == cellWidth ) return; #if defined(QT_CHECK_RANGE) if ( cellWidth < 0 || cellWidth > SHRT_MAX ) { qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)", name( "unnamed" ), cellWidth ); return; } #endif cellW = (short)cellWidth; updateScrollBars( horSteps | horRange ); if ( autoUpdate() && isVisible() ) repaint(); } /*! \overload int QtTableView::cellHeight() const Returns the row height, in pixels. Returns 0 if the rows have variable heights. \sa setCellHeight(), cellWidth() */ /*! Returns the height of row \a row in pixels. This function is virtual and must be reimplemented by subclasses that have variable cell heights. Note that if the total table height changes, updateTableSize() must be called. \sa setCellHeight(), cellWidth(), totalHeight() */ int QtTableView::cellHeight( int ) { return cellH; } /*! Sets the height in pixels of the table cells to \a cellHeight. Setting it to 0 means that the row height is variable. When set to 0 (this is the default), QtTableView calls the virtual function cellHeight() to get the height. \sa cellHeight(), setCellWidth(), totalHeight(), numRows() */ void QtTableView::setCellHeight( int cellHeight ) { if ( cellH == cellHeight ) return; #if defined(QT_CHECK_RANGE) if ( cellHeight < 0 || cellHeight > SHRT_MAX ) { qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)", name( "unnamed" ), cellHeight ); return; } #endif cellH = (short)cellHeight; if ( autoUpdate() && isVisible() ) repaint(); updateScrollBars( verSteps | verRange ); } /*! Returns the total width of the table in pixels. This function is virtual and should be reimplemented by subclasses that have variable cell widths and a non-trivial cellWidth() function, or a large number of columns in the table. The default implementation may be slow for very wide tables. \sa cellWidth(), totalHeight() */ int QtTableView::totalWidth() { if ( cellW ) { return cellW*nCols; } else { int tw = 0; for( int i = 0 ; i < nCols ; i++ ) tw += cellWidth( i ); return tw; } } /*! Returns the total height of the table in pixels. This function is virtual and should be reimplemented by subclasses that have variable cell heights and a non-trivial cellHeight() function, or a large number of rows in the table. The default implementation may be slow for very tall tables. \sa cellHeight(), totalWidth() */ int QtTableView::totalHeight() { if ( cellH ) { return cellH*nRows; } else { int th = 0; for( int i = 0 ; i < nRows ; i++ ) th += cellHeight( i ); return th; } } /*! \fn uint QtTableView::tableFlags() const Returns the union of the table flags that are currently set. \sa setTableFlags(), clearTableFlags(), testTableFlags() */ /*! \fn bool QtTableView::testTableFlags( uint f ) const Returns TRUE if any of the table flags in \a f are currently set, otherwise FALSE. \sa setTableFlags(), clearTableFlags(), tableFlags() */ /*! Sets the table flags to \a f. If a flag setting changes the appearance of the table, the table is repainted if - and only if - autoUpdate() is TRUE. The table flags are mostly single bits, though there are some multibit flags for convenience. Here is a complete list:
Tbl_vScrollBar
- The table has a vertical scroll bar.
Tbl_hScrollBar
- The table has a horizontal scroll bar.
Tbl_autoVScrollBar
- The table has a vertical scroll bar if - and only if - the table is taller than the view.
Tbl_autoHScrollBar
The table has a horizontal scroll bar if - and only if - the table is wider than the view.
Tbl_autoScrollBars
- The union of the previous two flags.
Tbl_clipCellPainting
- The table uses QPainter::setClipRect() to make sure that paintCell() will not draw outside the cell boundaries.
Tbl_cutCellsV
- The table will never show part of a cell at the bottom of the table; if there is not space for all of a cell, the space is left blank.
Tbl_cutCellsH
- The table will never show part of a cell at the right side of the table; if there is not space for all of a cell, the space is left blank.
Tbl_cutCells
- The union of the previous two flags.
Tbl_scrollLastHCell
- When the user scrolls horizontally, let him/her scroll the last cell left until it is at the left edge of the view. If this flag is not set, the user can only scroll to the point where the last cell is completely visible.
Tbl_scrollLastVCell
- When the user scrolls vertically, let him/her scroll the last cell up until it is at the top edge of the view. If this flag is not set, the user can only scroll to the point where the last cell is completely visible.
Tbl_scrollLastCell
- The union of the previous two flags.
Tbl_smoothHScrolling
- The table scrolls as smoothly as possible when the user scrolls horizontally. When this flag is not set, scrolling is done one cell at a time.
Tbl_smoothVScrolling
- The table scrolls as smoothly as possible when scrolling vertically. When this flag is not set, scrolling is done one cell at a time.
Tbl_smoothScrolling
- The union of the previous two flags.
Tbl_snapToHGrid
- Except when the user is actually scrolling, the leftmost column shown snaps to the leftmost edge of the view.
Tbl_snapToVGrid
- Except when the user is actually scrolling, the top row snaps to the top edge of the view.
Tbl_snapToGrid
- The union of the previous two flags.
You can specify more than one flag at a time using bitwise OR. Example: \code setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars ); \endcode \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and Tbl_cutCellsV) may cause painting problems when scrollbars are enabled. Do not combine cutCells and scrollbars. \sa clearTableFlags(), testTableFlags(), tableFlags() */ void QtTableView::setTableFlags( uint f ) { f = (f ^ tFlags) & f; // clear flags already set tFlags |= f; bool updateOn = autoUpdate(); setAutoUpdate( FALSE ); uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; if ( f & Tbl_vScrollBar ) { setVerScrollBar( TRUE ); } if ( f & Tbl_hScrollBar ) { setHorScrollBar( TRUE ); } if ( f & Tbl_autoVScrollBar ) { updateScrollBars( verRange ); } if ( f & Tbl_autoHScrollBar ) { updateScrollBars( horRange ); } if ( f & Tbl_scrollLastHCell ) { updateScrollBars( horRange ); } if ( f & Tbl_scrollLastVCell ) { updateScrollBars( verRange ); } if ( f & Tbl_snapToHGrid ) { updateScrollBars( horRange ); } if ( f & Tbl_snapToVGrid ) { updateScrollBars( verRange ); } if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll? (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) { snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping (f & Tbl_snapToVGrid) != 0 ); repaintMask |= Tbl_snapToGrid; // repaint table } } if ( updateOn ) { setAutoUpdate( TRUE ); updateScrollBars(); if ( isVisible() && (f & repaintMask) ) repaint(); } } /*! Clears the \link setTableFlags() table flags\endlink that are set in \a f. Example (clears a single flag): \code clearTableFlags( Tbl_snapToGrid ); \endcode The default argument clears all flags. \sa setTableFlags(), testTableFlags(), tableFlags() */ void QtTableView::clearTableFlags( uint f ) { f = (f ^ ~tFlags) & f; // clear flags that are already 0 tFlags &= ~f; bool updateOn = autoUpdate(); setAutoUpdate( FALSE ); uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; if ( f & Tbl_vScrollBar ) { setVerScrollBar( FALSE ); } if ( f & Tbl_hScrollBar ) { setHorScrollBar( FALSE ); } if ( f & Tbl_scrollLastHCell ) { int maxX = maxXOffset(); if ( xOffs > maxX ) { setOffset( maxX, yOffs ); repaintMask |= Tbl_scrollLastHCell; } updateScrollBars( horRange ); } if ( f & Tbl_scrollLastVCell ) { int maxY = maxYOffset(); if ( yOffs > maxY ) { setOffset( xOffs, maxY ); repaintMask |= Tbl_scrollLastVCell; } updateScrollBars( verRange ); } if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll? (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) { snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping (f & Tbl_smoothVScrolling) != 0 ); repaintMask |= Tbl_smoothScrolling; // repaint table } } if ( f & Tbl_snapToHGrid ) { updateScrollBars( horRange ); } if ( f & Tbl_snapToVGrid ) { updateScrollBars( verRange ); } if ( updateOn ) { setAutoUpdate( TRUE ); updateScrollBars(); // returns immediately if nothing to do if ( isVisible() && (f & repaintMask) ) repaint(); } } /*! \fn bool QtTableView::autoUpdate() const Returns TRUE if the view updates itself automatically whenever it is changed in some way. \sa setAutoUpdate() */ /*! Sets the auto-update option of the table view to \a enable. If \a enable is TRUE (this is the default), the view updates itself automatically whenever it has changed in some way (for example, when a \link setTableFlags() flag\endlink is changed). If \a enable is FALSE, the view does NOT repaint itself or update its internal state variables when it is changed. This can be useful to avoid flicker during large changes and is singularly useless otherwise. Disable auto-update, do the changes, re-enable auto-update and call repaint(). \warning Do not leave the view in this state for a long time (i.e., between events). If, for example, the user interacts with the view when auto-update is off, strange things can happen. Setting auto-update to TRUE does not repaint the view; you must call repaint() to do this. \sa autoUpdate(), repaint() */ void QtTableView::setAutoUpdate( bool enable ) { if ( isUpdatesEnabled() == enable ) return; setUpdatesEnabled( enable ); if ( enable ) { showOrHideScrollBars(); updateScrollBars(); } } /*! Repaints the cell at row \a row, column \a col if it is inside the view. If \a erase is TRUE, the relevant part of the view is cleared to the background color/pixmap before the contents are repainted. \sa isVisible() */ void QtTableView::updateCell( int row, int col, bool erase ) { int xPos, yPos; if ( !colXPos( col, &xPos ) ) return; if ( !rowYPos( row, &yPos ) ) return; QRect uR = QRect( xPos, yPos, cellW ? cellW : cellWidth(col), cellH ? cellH : cellHeight(row) ); repaint( uR.intersect(viewRect()), erase ); } /*! \fn QRect QtTableView::cellUpdateRect() const This function should be called only from the paintCell() function in subclasses. It returns the portion of a cell that actually needs to be updated in \e cell coordinates. This is useful only for non-trivial paintCell(). */ /*! Returns the rectangle that is the actual table, excluding any frame, in \e widget coordinates. */ QRect QtTableView::viewRect() const { return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() ); } /*! Returns the index of the last (bottom) row in the view. The index of the first row is 0. If no rows are visible it returns -1. This can happen if the view is too small for the first row and Tbl_cutCellsV is set. \sa lastColVisible() */ int QtTableView::lastRowVisible() const { int cellMaxY; int row = findRawRow( maxViewY(), &cellMaxY ); if ( row == -1 || row >= nRows ) { // maxViewY() past end? row = nRows - 1; // yes: return last row } else { if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) { if ( row == yCellOffs ) // cut by right margin? return -1; // yes, nothing in the view else row = row - 1; // cut by margin, one back } } return row; } /*! Returns the index of the last (right) column in the view. The index of the first column is 0. If no columns are visible it returns -1. This can happen if the view is too narrow for the first column and Tbl_cutCellsH is set. \sa lastRowVisible() */ int QtTableView::lastColVisible() const { int cellMaxX; int col = findRawCol( maxViewX(), &cellMaxX ); if ( col == -1 || col >= nCols ) { // maxViewX() past end? col = nCols - 1; // yes: return last col } else { if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) { if ( col == xCellOffs ) // cut by bottom margin? return -1; // yes, nothing in the view else col = col - 1; // cell by margin, one back } } return col; } /*! Returns TRUE if \a row is at least partially visible. \sa colIsVisible() */ bool QtTableView::rowIsVisible( int row ) const { return rowYPos( row, 0 ); } /*! Returns TRUE if \a col is at least partially visible. \sa rowIsVisible() */ bool QtTableView::colIsVisible( int col ) const { return colXPos( col, 0 ); } /*! \internal Called when both scroll bars are active at the same time. Covers the bottom left corner between the two scroll bars with an empty widget. */ void QtTableView::coverCornerSquare( bool enable ) { coveringCornerSquare = enable; if ( !cornerSquare && enable ) { cornerSquare = new QCornerSquare( this ); Q_CHECK_PTR( cornerSquare ); cornerSquare->setGeometry( maxViewX() + frameWidth() + 1, maxViewY() + frameWidth() + 1, VSBEXT, HSBEXT); } if ( autoUpdate() && cornerSquare ) { if ( enable ) cornerSquare->show(); else cornerSquare->hide(); } } /*! \internal Scroll the view to a position such that: If \a horizontal is TRUE, the leftmost column shown fits snugly with the left edge of the view. If \a vertical is TRUE, the top row shown fits snugly with the top of the view. You can achieve the same effect automatically by setting any of the \link setTableFlags() Tbl_snapTo*Grid \endlink table flags. */ void QtTableView::snapToGrid( bool horizontal, bool vertical ) { int newXCell = -1; int newYCell = -1; if ( horizontal && xCellDelta != 0 ) { int w = cellW ? cellW : cellWidth( xCellOffs ); if ( xCellDelta >= w/2 ) newXCell = xCellOffs + 1; else newXCell = xCellOffs; } if ( vertical && yCellDelta != 0 ) { int h = cellH ? cellH : cellHeight( yCellOffs ); if ( yCellDelta >= h/2 ) newYCell = yCellOffs + 1; else newYCell = yCellOffs; } setTopLeftCell( newYCell, newXCell ); //row,column } /*! \internal This internal slot is connected to the horizontal scroll bar's QScrollBar::valueChanged() signal. Moves the table horizontally to offset \a val without updating the scroll bar. */ void QtTableView::horSbValue( int val ) { if ( horSliding ) { horSliding = FALSE; if ( horSnappingOff ) { horSnappingOff = FALSE; tFlags |= Tbl_snapToHGrid; } } setOffset( val, yOffs, FALSE ); } /*! \internal This internal slot is connected to the horizontal scroll bar's QScrollBar::sliderMoved() signal. Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set. */ void QtTableView::horSbSliding( int val ) { if ( testTableFlags(Tbl_snapToHGrid) && testTableFlags(Tbl_smoothHScrolling) ) { tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding setOffset( val, yOffs, FALSE ); tFlags |= Tbl_snapToHGrid; // turn on snapping again } else { setOffset( val, yOffs, FALSE ); } } /*! \internal This internal slot is connected to the horizontal scroll bar's QScrollBar::sliderReleased() signal. */ void QtTableView::horSbSlidingDone( ) { if ( testTableFlags(Tbl_snapToHGrid) && testTableFlags(Tbl_smoothHScrolling) ) snapToGrid( TRUE, FALSE ); } /*! \internal This internal slot is connected to the vertical scroll bar's QScrollBar::valueChanged() signal. Moves the table vertically to offset \a val without updating the scroll bar. */ void QtTableView::verSbValue( int val ) { if ( verSliding ) { verSliding = FALSE; if ( verSnappingOff ) { verSnappingOff = FALSE; tFlags |= Tbl_snapToVGrid; } } setOffset( xOffs, val, FALSE ); } /*! \internal This internal slot is connected to the vertical scroll bar's QScrollBar::sliderMoved() signal. Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set. */ void QtTableView::verSbSliding( int val ) { if ( testTableFlags(Tbl_snapToVGrid) && testTableFlags(Tbl_smoothVScrolling) ) { tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding setOffset( xOffs, val, FALSE ); tFlags |= Tbl_snapToVGrid; // turn on snapping again } else { setOffset( xOffs, val, FALSE ); } } /*! \internal This internal slot is connected to the vertical scroll bar's QScrollBar::sliderReleased() signal. */ void QtTableView::verSbSlidingDone( ) { if ( testTableFlags(Tbl_snapToVGrid) && testTableFlags(Tbl_smoothVScrolling) ) snapToGrid( FALSE, TRUE ); } /*! This virtual function is called before painting of table cells is started. It can be reimplemented by subclasses that want to to set up the painter in a special way and that do not want to do so for each cell. */ void QtTableView::setupPainter( QPainter * ) { } /*! \fn void QtTableView::paintCell( QPainter *p, int row, int col ) This pure virtual function is called to paint the single cell at \a (row,col) using \a p, which is open when paintCell() is called and must remain open. The coordinate system is \link QPainter::translate() translated \endlink so that the origin is at the top-left corner of the cell to be painted, i.e. \e cell coordinates. Do not scale or shear the coordinate system (or if you do, restore the transformation matrix before you return). The painter is not clipped by default and for maximum efficiency. For safety, call setTableFlags(Tbl_clipCellPainting) to enable clipping. \sa paintEvent(), setTableFlags() */ /*! Handles paint events, \a e, for the table view. Calls paintCell() for the cells that needs to be repainted. */ void QtTableView::paintEvent( QPaintEvent *e ) { QRect updateR = e->rect(); // update rectangle if ( sbDirty ) { bool e = eraseInPaint; updateScrollBars(); eraseInPaint = e; } QPainter paint( this ); if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ? drawFrame( &paint ); if ( updateR.left() < frameWidth() ) //### updateR.setLeft( frameWidth() ); if ( updateR.top() < frameWidth() ) updateR.setTop( frameWidth() ); } int maxWX = maxViewX(); int maxWY = maxViewY(); if ( updateR.right() > maxWX ) updateR.setRight( maxWX ); if ( updateR.bottom() > maxWY ) updateR.setBottom( maxWY ); setupPainter( &paint ); // prepare for painting table int firstRow = findRow( updateR.y() ); int firstCol = findCol( updateR.x() ); int xStart, yStart; if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) { paint.eraseRect( updateR ); // erase area outside cells but in view return; } int maxX = updateR.right(); int maxY = updateR.bottom(); int row = firstRow; int col; int yPos = yStart; int xPos = maxX+1; // in case the while() is empty int nextX; int nextY; QRect winR = viewRect(); QRect cellR; QRect cellUR; #ifndef QT_NO_TRANSFORMATIONS QWMatrix matrix; #endif while ( yPos <= maxY && row < nRows ) { nextY = yPos + (cellH ? cellH : cellHeight( row )); if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) ) break; col = firstCol; xPos = xStart; while ( xPos <= maxX && col < nCols ) { nextX = xPos + (cellW ? cellW : cellWidth( col )); if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) ) break; cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col), cellH ? cellH : cellHeight(row) ); cellUR = cellR.intersect( updateR ); if ( cellUR.isValid() ) { cellUpdateR = cellUR; cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates if ( eraseInPaint ) paint.eraseRect( cellUR ); #ifndef QT_NO_TRANSFORMATIONS matrix.translate( xPos, yPos ); paint.setWorldMatrix( matrix ); if ( testTableFlags(Tbl_clipCellPainting) || frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt paint.setClipRect( cellUR ); paintCell( &paint, row, col ); paint.setClipping( FALSE ); } else { paintCell( &paint, row, col ); } matrix.reset(); paint.setWorldMatrix( matrix ); #else paint.translate( xPos, yPos ); if ( testTableFlags(Tbl_clipCellPainting) || frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt paint.setClipRect( cellUR ); paintCell( &paint, row, col ); paint.setClipping( FALSE ); } else { paintCell( &paint, row, col ); } paint.translate( -xPos, -yPos ); #endif } col++; xPos = nextX; } row++; yPos = nextY; } // while painting we have to erase any areas in the view that // are not covered by cells but are covered by the paint event // rectangle these must be erased. We know that xPos is the last // x pixel updated + 1 and that yPos is the last y pixel updated + 1. // Note that this needs to be done regardless whether we do // eraseInPaint or not. Reason: a subclass may implement // flicker-freeness and encourage the use of repaint(FALSE). // The subclass, however, cannot draw all pixels, just those // inside the cells. So QtTableView is reponsible for all pixels // outside the cells. QRect viewR = viewRect(); const QColorGroup g = colorGroup(); if ( xPos <= maxX ) { QRect r = viewR; r.setLeft( xPos ); r.setBottom( yPossetCursor( arrowCursor ); #endif sb->resize( sb->sizeHint() ); // height is irrelevant Q_CHECK_PTR(sb); sb->setTracking( FALSE ); sb->setFocusPolicy( NoFocus ); connect( sb, SIGNAL(valueChanged(int)), SLOT(verSbValue(int))); connect( sb, SIGNAL(sliderMoved(int)), SLOT(verSbSliding(int))); connect( sb, SIGNAL(sliderReleased()), SLOT(verSbSlidingDone())); sb->hide(); that->vScrollBar = sb; return sb; } return vScrollBar; } /*! Returns a pointer to the horizontal scroll bar mainly so you can connect() to its signals. Note that the scroll bar works in pixel values; use findCol() to translate to cell numbers. */ QScrollBar *QtTableView::horizontalScrollBar() const { QtTableView *that = (QtTableView*)this; // semantic const if ( !hScrollBar ) { QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that ); #ifndef QT_NO_CURSOR sb->setCursor( arrowCursor ); #endif sb->resize( sb->sizeHint() ); // width is irrelevant sb->setFocusPolicy( NoFocus ); Q_CHECK_PTR(sb); sb->setTracking( FALSE ); connect( sb, SIGNAL(valueChanged(int)), SLOT(horSbValue(int))); connect( sb, SIGNAL(sliderMoved(int)), SLOT(horSbSliding(int))); connect( sb, SIGNAL(sliderReleased()), SLOT(horSbSlidingDone())); sb->hide(); that->hScrollBar = sb; return sb; } return hScrollBar; } /*! Enables or disables the horizontal scroll bar, as required by setAutoUpdate() and the \link setTableFlags() table flags\endlink. */ void QtTableView::setHorScrollBar( bool on, bool update ) { if ( on ) { tFlags |= Tbl_hScrollBar; horizontalScrollBar(); // created if ( update ) updateScrollBars( horMask | verMask ); else sbDirty = sbDirty | (horMask | verMask); if ( testTableFlags( Tbl_vScrollBar ) ) coverCornerSquare( TRUE ); if ( autoUpdate() ) sbDirty = sbDirty | horMask; } else { tFlags &= ~Tbl_hScrollBar; if ( !hScrollBar ) return; coverCornerSquare( FALSE ); bool hideScrollBar = autoUpdate() && hScrollBar->isVisible(); if ( hideScrollBar ) hScrollBar->hide(); if ( update ) updateScrollBars( verMask ); else sbDirty = sbDirty | verMask; if ( hideScrollBar && isVisible() ) repaint( hScrollBar->x(), hScrollBar->y(), width() - hScrollBar->x(), hScrollBar->height() ); } if ( update ) updateFrameSize(); } /*! Enables or disables the vertical scroll bar, as required by setAutoUpdate() and the \link setTableFlags() table flags\endlink. */ void QtTableView::setVerScrollBar( bool on, bool update ) { if ( on ) { tFlags |= Tbl_vScrollBar; verticalScrollBar(); // created if ( update ) updateScrollBars( verMask | horMask ); else sbDirty = sbDirty | (horMask | verMask); if ( testTableFlags( Tbl_hScrollBar ) ) coverCornerSquare( TRUE ); if ( autoUpdate() ) sbDirty = sbDirty | verMask; } else { tFlags &= ~Tbl_vScrollBar; if ( !vScrollBar ) return; coverCornerSquare( FALSE ); bool hideScrollBar = autoUpdate() && vScrollBar->isVisible(); if ( hideScrollBar ) vScrollBar->hide(); if ( update ) updateScrollBars( horMask ); else sbDirty = sbDirty | horMask; if ( hideScrollBar && isVisible() ) repaint( vScrollBar->x(), vScrollBar->y(), vScrollBar->width(), height() - vScrollBar->y() ); } if ( update ) updateFrameSize(); } int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY, bool goOutsideView ) const { int r = -1; if ( nRows == 0 ) return r; if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) { if ( yPos < minViewY() ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::findRawRow: (%s) internal error: " "yPos < minViewY() && goOutsideView " "not supported. (%d,%d)", name( "unnamed" ), yPos, yOffs ); #endif return -1; } if ( cellH ) { // uniform cell height r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top if ( cellMaxY ) *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1; if ( cellMinY ) *cellMinY = r*cellH + minViewY() - yCellDelta; r += yCellOffs; // absolute cell index } else { // variable cell height QtTableView *tw = (QtTableView *)this; r = yCellOffs; int h = minViewY() - yCellDelta; //##arnt3 int oldH = h; Q_ASSERT( r < nRows ); while ( r < nRows ) { oldH = h; h += tw->cellHeight( r ); // Start of next cell if ( yPos < h ) break; r++; } if ( cellMaxY ) *cellMaxY = h - 1; if ( cellMinY ) *cellMinY = oldH; } } return r; } int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX , bool goOutsideView ) const { int c = -1; if ( nCols == 0 ) return c; if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) { if ( xPos < minViewX() ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::findRawCol: (%s) internal error: " "xPos < minViewX() && goOutsideView " "not supported. (%d,%d)", name( "unnamed" ), xPos, xOffs ); #endif return -1; } if ( cellW ) { // uniform cell width c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left if ( cellMaxX ) *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1; if ( cellMinX ) *cellMinX = c*cellW + minViewX() - xCellDelta; c += xCellOffs; // absolute cell index } else { // variable cell width QtTableView *tw = (QtTableView *)this; c = xCellOffs; int w = minViewX() - xCellDelta; //##arnt3 int oldW = w; Q_ASSERT( c < nCols ); while ( c < nCols ) { oldW = w; w += tw->cellWidth( c ); // Start of next cell if ( xPos < w ) break; c++; } if ( cellMaxX ) *cellMaxX = w - 1; if ( cellMinX ) *cellMinX = oldW; } } return c; } /*! Returns the index of the row at position \a yPos, where \a yPos is in \e widget coordinates. Returns -1 if \a yPos is outside the valid range. \sa findCol(), rowYPos() */ int QtTableView::findRow( int yPos ) const { int cellMaxY; int row = findRawRow( yPos, &cellMaxY ); if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) row = - 1; // cell cut by bottom margin if ( row >= nRows ) row = -1; return row; } /*! Returns the index of the column at position \a xPos, where \a xPos is in \e widget coordinates. Returns -1 if \a xPos is outside the valid range. \sa findRow(), colXPos() */ int QtTableView::findCol( int xPos ) const { int cellMaxX; int col = findRawCol( xPos, &cellMaxX ); if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) col = - 1; // cell cut by right margin if ( col >= nCols ) col = -1; return col; } /*! Computes the position in the widget of row \a row. Returns TRUE and stores the result in \a *yPos (in \e widget coordinates) if the row is visible. Returns FALSE and does not modify \a *yPos if \a row is invisible or invalid. \sa colXPos(), findRow() */ bool QtTableView::rowYPos( int row, int *yPos ) const { int y; if ( row >= yCellOffs ) { if ( cellH ) { int lastVisible = lastRowVisible(); if ( row > lastVisible || lastVisible == -1 ) return FALSE; y = (row - yCellOffs)*cellH + minViewY() - yCellDelta; } else { //##arnt3 y = minViewY() - yCellDelta; // y of leftmost cell in view int r = yCellOffs; QtTableView *tw = (QtTableView *)this; int maxY = maxViewY(); while ( r < row && y <= maxY ) y += tw->cellHeight( r++ ); if ( y > maxY ) return FALSE; } } else { return FALSE; } if ( yPos ) *yPos = y; return TRUE; } /*! Computes the position in the widget of column \a col. Returns TRUE and stores the result in \a *xPos (in \e widget coordinates) if the column is visible. Returns FALSE and does not modify \a *xPos if \a col is invisible or invalid. \sa rowYPos(), findCol() */ bool QtTableView::colXPos( int col, int *xPos ) const { int x; if ( col >= xCellOffs ) { if ( cellW ) { int lastVisible = lastColVisible(); if ( col > lastVisible || lastVisible == -1 ) return FALSE; x = (col - xCellOffs)*cellW + minViewX() - xCellDelta; } else { //##arnt3 x = minViewX() - xCellDelta; // x of uppermost cell in view int c = xCellOffs; QtTableView *tw = (QtTableView *)this; int maxX = maxViewX(); while ( c < col && x <= maxX ) x += tw->cellWidth( c++ ); if ( x > maxX ) return FALSE; } } else { return FALSE; } if ( xPos ) *xPos = x; return TRUE; } /*! Moves the visible area of the table right by \a xPixels and down by \a yPixels pixels. Both may be negative. \warning You might find that QScrollView offers a higher-level of functionality than using QtTableView and this function. This function is \e not the same as QWidget::scroll(); in particular, the signs of \a xPixels and \a yPixels have the reverse semantics. \sa setXOffset(), setYOffset(), setOffset(), setTopCell(), setLeftCell() */ void QtTableView::scroll( int xPixels, int yPixels ) { QWidget::scroll( -xPixels, -yPixels, contentsRect() ); } /*! Returns the leftmost pixel of the table view in \e view coordinates. This excludes the frame and any header. \sa maxViewY(), viewWidth(), contentsRect() */ int QtTableView::minViewX() const { return frameWidth(); } /*! Returns the top pixel of the table view in \e view coordinates. This excludes the frame and any header. \sa maxViewX(), viewHeight(), contentsRect() */ int QtTableView::minViewY() const { return frameWidth(); } /*! Returns the rightmost pixel of the table view in \e view coordinates. This excludes the frame and any scroll bar, but includes blank pixels to the right of the visible table data. \sa maxViewY(), viewWidth(), contentsRect() */ int QtTableView::maxViewX() const { return width() - 1 - frameWidth() - (tFlags & Tbl_vScrollBar ? VSBEXT : 0); } /*! Returns the bottom pixel of the table view in \e view coordinates. This excludes the frame and any scroll bar, but includes blank pixels below the visible table data. \sa maxViewX(), viewHeight(), contentsRect() */ int QtTableView::maxViewY() const { return height() - 1 - frameWidth() - (tFlags & Tbl_hScrollBar ? HSBEXT : 0); } /*! Returns the width of the table view, as such, in \e view coordinates. This does not include any header, scroll bar or frame, but it does include background pixels to the right of the table data. \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect() */ int QtTableView::viewWidth() const { return maxViewX() - minViewX() + 1; } /*! Returns the height of the table view, as such, in \e view coordinates. This does not include any header, scroll bar or frame, but it does include background pixels below the table data. \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect() */ int QtTableView::viewHeight() const { return maxViewY() - minViewY() + 1; } void QtTableView::doAutoScrollBars() { int viewW = width() - frameWidth() - minViewX(); int viewH = height() - frameWidth() - minViewY(); bool vScrollOn = testTableFlags(Tbl_vScrollBar); bool hScrollOn = testTableFlags(Tbl_hScrollBar); int w = 0; int h = 0; int i; if ( testTableFlags(Tbl_autoHScrollBar) ) { if ( cellW ) { w = cellW*nCols; } else { i = 0; while ( i < nCols && w <= viewW ) w += cellWidth( i++ ); } if ( w > viewW ) hScrollOn = TRUE; else hScrollOn = FALSE; } if ( testTableFlags(Tbl_autoVScrollBar) ) { if ( cellH ) { h = cellH*nRows; } else { i = 0; while ( i < nRows && h <= viewH ) h += cellHeight( i++ ); } if ( h > viewH ) vScrollOn = TRUE; else vScrollOn = FALSE; } if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn ) if ( w > viewW - VSBEXT ) hScrollOn = TRUE; if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn ) if ( h > viewH - HSBEXT ) vScrollOn = TRUE; setHorScrollBar( hScrollOn, FALSE ); setVerScrollBar( vScrollOn, FALSE ); updateFrameSize(); } /*! \fn void QtTableView::updateScrollBars() Updates the scroll bars' contents and presence to match the table's state. Generally, you should not need to call this. \sa setTableFlags() */ /*! Updates the scroll bars' contents and presence to match the table's state \c or \a f. \sa setTableFlags() */ void QtTableView::updateScrollBars( uint f ) { sbDirty = sbDirty | f; if ( inSbUpdate ) return; inSbUpdate = TRUE; if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) || testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) ) // if range change and auto doAutoScrollBars(); // turn scroll bars on/off if needed if ( !autoUpdate() ) { inSbUpdate = FALSE; return; } if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) && !testTableFlags( Tbl_vScrollBar ) ) { setYOffset( 0 ); } if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) && !testTableFlags( Tbl_hScrollBar ) ) { setXOffset( 0 ); } if ( !isVisible() ) { inSbUpdate = FALSE; return; } if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) { if ( sbDirty & horGeometry ) hScrollBar->setGeometry( 0,height() - HSBEXT, viewWidth() + frameWidth()*2, HSBEXT); if ( sbDirty & horSteps ) { if ( cellW ) hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() ); else hScrollBar->setSteps( 16, viewWidth() ); } if ( sbDirty & horRange ) hScrollBar->setRange( 0, maxXOffset() ); if ( sbDirty & horValue ) hScrollBar->setValue( xOffs ); // show scrollbar only when it has a sane geometry if ( !hScrollBar->isVisible() ) hScrollBar->show(); } if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) { if ( sbDirty & verGeometry ) vScrollBar->setGeometry( width() - VSBEXT, 0, VSBEXT, viewHeight() + frameWidth()*2 ); if ( sbDirty & verSteps ) { if ( cellH ) vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() ); else vScrollBar->setSteps( 16, viewHeight() ); // fttb! ### } if ( sbDirty & verRange ) vScrollBar->setRange( 0, maxYOffset() ); if ( sbDirty & verValue ) vScrollBar->setValue( yOffs ); // show scrollbar only when it has a sane geometry if ( !vScrollBar->isVisible() ) vScrollBar->show(); } if ( coveringCornerSquare && ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) ) cornerSquare->move( maxViewX() + frameWidth() + 1, maxViewY() + frameWidth() + 1 ); sbDirty = 0; inSbUpdate = FALSE; } void QtTableView::updateFrameSize() { int rw = width() - ( testTableFlags(Tbl_vScrollBar) ? VSBEXT : 0 ); int rh = height() - ( testTableFlags(Tbl_hScrollBar) ? HSBEXT : 0 ); if ( rw < 0 ) rw = 0; if ( rh < 0 ) rh = 0; if ( autoUpdate() ) { int fh = frameRect().height(); int fw = frameRect().width(); setFrameRect( QRect(0,0,rw,rh) ); if ( rw != fw ) update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh ); if ( rh != fh ) update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 ); } } /*! Returns the maximum horizontal offset within the table of the view's left edge in \e table coordinates. This is used mainly to set the horizontal scroll bar's range. \sa maxColOffset(), maxYOffset(), totalWidth() */ int QtTableView::maxXOffset() { int tw = totalWidth(); int maxOffs; if ( testTableFlags(Tbl_scrollLastHCell) ) { if ( nCols != 1) maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) ); else maxOffs = tw - viewWidth(); } else { if ( testTableFlags(Tbl_snapToHGrid) ) { if ( cellW ) { maxOffs = tw - (viewWidth()/cellW)*cellW; } else { int goal = tw - viewWidth(); int pos = tw; int nextCol = nCols - 1; int nextCellWidth = cellWidth( nextCol ); while( nextCol > 0 && pos > goal + nextCellWidth ) { pos -= nextCellWidth; nextCellWidth = cellWidth( --nextCol ); } if ( goal + nextCellWidth == pos ) maxOffs = goal; else if ( goal < pos ) maxOffs = pos; else maxOffs = 0; } } else { maxOffs = tw - viewWidth(); } } return maxOffs > 0 ? maxOffs : 0; } /*! Returns the maximum vertical offset within the table of the view's top edge in \e table coordinates. This is used mainly to set the vertical scroll bar's range. \sa maxRowOffset(), maxXOffset(), totalHeight() */ int QtTableView::maxYOffset() { int th = totalHeight(); int maxOffs; if ( testTableFlags(Tbl_scrollLastVCell) ) { if ( nRows != 1) maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) ); else maxOffs = th - viewHeight(); } else { if ( testTableFlags(Tbl_snapToVGrid) ) { if ( cellH ) { maxOffs = th - (viewHeight()/cellH)*cellH; } else { int goal = th - viewHeight(); int pos = th; int nextRow = nRows - 1; int nextCellHeight = cellHeight( nextRow ); while( nextRow > 0 && pos > goal + nextCellHeight ) { pos -= nextCellHeight; nextCellHeight = cellHeight( --nextRow ); } if ( goal + nextCellHeight == pos ) maxOffs = goal; else if ( goal < pos ) maxOffs = pos; else maxOffs = 0; } } else { maxOffs = th - viewHeight(); } } return maxOffs > 0 ? maxOffs : 0; } /*! Returns the index of the last column, which may be at the left edge of the view. Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag, this may or may not be the last column. \sa maxXOffset(), maxRowOffset() */ int QtTableView::maxColOffset() { int mx = maxXOffset(); if ( cellW ) return mx/cellW; else { int xcd=0, col=0; while ( col < nCols && mx > (xcd=cellWidth(col)) ) { mx -= xcd; col++; } return col; } } /*! Returns the index of the last row, which may be at the top edge of the view. Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag, this may or may not be the last row. \sa maxYOffset(), maxColOffset() */ int QtTableView::maxRowOffset() { int my = maxYOffset(); if ( cellH ) return my/cellH; else { int ycd=0, row=0; while ( row < nRows && my > (ycd=cellHeight(row)) ) { my -= ycd; row++; } return row; } } void QtTableView::showOrHideScrollBars() { if ( !autoUpdate() ) return; if ( vScrollBar ) { if ( testTableFlags(Tbl_vScrollBar) ) { if ( !vScrollBar->isVisible() ) sbDirty = sbDirty | verMask; } else { if ( vScrollBar->isVisible() ) vScrollBar->hide(); } } if ( hScrollBar ) { if ( testTableFlags(Tbl_hScrollBar) ) { if ( !hScrollBar->isVisible() ) sbDirty = sbDirty | horMask; } else { if ( hScrollBar->isVisible() ) hScrollBar->hide(); } } if ( cornerSquare ) { if ( testTableFlags(Tbl_hScrollBar) && testTableFlags(Tbl_vScrollBar) ) { if ( !cornerSquare->isVisible() ) cornerSquare->show(); } else { if ( cornerSquare->isVisible() ) cornerSquare->hide(); } } } /*! Updates the scroll bars and internal state. Call this function when the table view's total size is changed; typically because the result of cellHeight() or cellWidth() have changed. This function does not repaint the widget. */ void QtTableView::updateTableSize() { bool updateOn = autoUpdate(); setAutoUpdate( FALSE ); int xofs = xOffset(); xOffs++; //so that setOffset will not return immediately setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly setAutoUpdate(updateOn); updateScrollBars( horSteps | horRange | verSteps | verRange ); showOrHideScrollBars(); } #endif #endif nethack-3.6.0/win/Qt/tileedit.cpp0000664000076400007660000002245312536476415015650 0ustar paxedpaxed/* NetHack 3.6 tileedit.cpp $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ /* Build this little utility program if you want to use it to edit the tile files. Move tileedit.cpp and tileedit.h to ../../util, add the 3 lines below to the Makefile there and "make tileedit". tileedit: tileedit.cpp $(TEXT_IO) moc -o tileedit.moc tileedit.h $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt */ #include "tileedit.h" #include #include #include #include #include #include #include #include #include extern "C" { #include "config.h" #include "tile.h" extern const char *FDECL(tilename, (int, int)); } #define TILES_ACROSS 20 TilePickerTab::TilePickerTab(const char* basename, int i, QWidget* parent) : QWidget(parent) { id = i; filename = basename; filename += ".txt"; num = 0; int index = 0; for (int real=0; real<2; real++) { if ( real ) { image.create( TILES_ACROSS*TILE_X, ((num+TILES_ACROSS-1)/TILES_ACROSS)*TILE_Y, 32 ); } if ( !fopen_text_file(filename.latin1(), RDTMODE) ) { // XXX handle better exit(1); } pixel p[TILE_Y][TILE_X]; while ( read_text_tile(p) ) { if ( real ) { int ox = (index%TILES_ACROSS)*TILE_X; int oy = (index/TILES_ACROSS)*TILE_Y; for ( int y=0; yx()-e->x()%TILE_X; int oy = e->y()-e->y()%TILE_Y; QImage subimage = image.copy(ox,oy,TILE_X,TILE_Y); if ( e->button() == RightButton ) { setCurrent(subimage); } else { last_pick = ox/TILE_X + oy/TILE_Y*TILES_ACROSS; } emit pick(subimage); emit pickName(tilename(id, last_pick)); } void TilePickerTab::setCurrent(const QImage& i) { int ox = last_pick%TILES_ACROSS * TILE_X; int oy = last_pick/TILES_ACROSS * TILE_Y; bitBlt( &image, ox, oy, &i ); bitBlt( &pixmap, ox, oy, &i ); repaint( ox, oy, TILE_X, TILE_Y, FALSE ); } QSize TilePickerTab::sizeHint() const { return pixmap.size(); } void TilePickerTab::paintEvent( QPaintEvent* ) { QPainter p(this); p.drawPixmap(0,0,pixmap); } static struct { const char* name; TilePickerTab* tab; } tileset[] = { { "monsters", 0 }, { "objects", 0 }, { "other", 0 }, { 0 } }; TilePicker::TilePicker(QWidget* parent) : QTabWidget(parent) { for (int i=0; tileset[i].name; i++) { QString tabname = tileset[i].name; tabname[0] = tabname[0].upper(); tileset[i].tab = new TilePickerTab(tileset[i].name,i+1,this); addTab( tileset[i].tab, tabname ); connect( tileset[i].tab, SIGNAL(pick(const QImage&)), this, SIGNAL(pick(const QImage&)) ); connect( tileset[i].tab, SIGNAL(pickName(const QString&)), this, SIGNAL(pickName(const QString&)) ); } } void TilePicker::setCurrent(const QImage& i) { ((TilePickerTab*)currentPage())->setCurrent(i); } void TilePicker::save() { for (int i=0; tileset[i].tab; i++) { tileset[i].tab->save(); } } TrivialTileEditor::TrivialTileEditor( QWidget* parent ) : QWidget(parent) { } const QImage& TrivialTileEditor::image() const { return img; } void TrivialTileEditor::setColor( QRgb rgb ) { pen = rgb; for (penpixel = 0; penpixelrect(); QPoint tl = imagePoint(r.topLeft()); QPoint br = imagePoint(r.bottomRight()); r = QRect(tl,br).intersect(img.rect()); QPainter painter(this); for (int y=r.top(); y<=r.bottom(); y++) { for (int x=r.left(); x<=r.right(); x++) { paintPoint(painter,QPoint(x,y)); } } } void TrivialTileEditor::paintPoint(QPainter& painter, QPoint p) { QPoint p1 = screenPoint(p); QPoint p2 = screenPoint(p+QPoint(1,1)); QColor c = img.color(img.scanLine(p.y())[p.x()]); painter.fillRect(QRect(p1,p2-QPoint(1,1)), c); } void TrivialTileEditor::mousePressEvent(QMouseEvent* e) { QPoint p = imagePoint(e->pos()); if ( !img.rect().contains(p) ) return; uchar& pixel = img.scanLine(p.y())[p.x()]; if ( e->button() == LeftButton ) { pixel = penpixel; QPainter painter(this); paintPoint(painter,p); } else if ( e->button() == RightButton ) { emit pick( img.color(pixel) ); } else if ( e->button() == MidButton ) { QPainter painter(this); if ( pixel != penpixel ) fill(painter,p,pixel); } } void TrivialTileEditor::fill(QPainter& painter, QPoint p, uchar from) { if ( img.rect().contains(p) ) { uchar& pixel = img.scanLine(p.y())[p.x()]; if ( pixel == from ) { pixel = penpixel; paintPoint(painter,p); fill(painter, p+QPoint(-1,0), from); fill(painter, p+QPoint(+1,0), from); fill(painter, p+QPoint(0,-1), from); fill(painter, p+QPoint(0,+1), from); } } } void TrivialTileEditor::mouseReleaseEvent(QMouseEvent* e) { emit edited(image()); } void TrivialTileEditor::mouseMoveEvent(QMouseEvent* e) { QPoint p = imagePoint(e->pos()); if ( !img.rect().contains(p) ) return; uchar& pixel = img.scanLine(p.y())[p.x()]; pixel = penpixel; QPainter painter(this); paintPoint(painter,p); } QPoint TrivialTileEditor::imagePoint(QPoint p) const { return QPoint(p.x()*TILE_X/width(), p.y()*TILE_Y/height()); } QPoint TrivialTileEditor::screenPoint(QPoint p) const { return QPoint(p.x()*width()/TILE_X, p.y()*height()/TILE_Y); } QSizePolicy TrivialTileEditor::sizePolicy() const { return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding, TRUE ); } QSize TrivialTileEditor::sizeHint() const { return sizeForWidth(-1); } QSize TrivialTileEditor::sizeForWidth(int w) const { if ( w < 0 ) return QSize(TILE_X*32,TILE_Y*32); else return QSize(w,w*TILE_Y/TILE_X); } TilePalette::TilePalette( QWidget* parent ) : QWidget(parent) { num = 0; rgb = 0; } TilePalette::~TilePalette() { delete rgb; } void TilePalette::setFromImage( const QImage& i ) { num = i.numColors(); rgb = new QRgb[num]; memcpy(rgb, i.colorTable(), num*sizeof(QRgb)); repaint(FALSE); } void TilePalette::setColor(QRgb c) { for (int i=0; ix()*num/width(); emit pick(rgb[c]); } TileEditor::TileEditor(QWidget* parent) : QVBox(parent), editor(this), palette(this) { connect( &palette, SIGNAL(pick(QRgb)), &editor, SLOT(setColor(QRgb)) ); connect( &editor, SIGNAL(pick(QRgb)), &palette, SLOT(setColor(QRgb)) ); connect( &editor, SIGNAL(edited(const QImage&)), this, SIGNAL(edited(const QImage&)) ); } void TileEditor::edit(const QImage& i) { editor.setImage(i); palette.setFromImage(i); } const QImage& TileEditor::image() const { return editor.image(); } class Main : public QMainWindow { public: Main() : central(this), editor(¢ral), picker(¢ral) { QPopupMenu* file = new QPopupMenu(menuBar()); file->insertItem("&Save", &picker, SLOT(save()), CTRL+Key_S); file->insertSeparator(); file->insertItem("&Exit", qApp, SLOT(quit()), CTRL+Key_Q); menuBar()->insertItem("&File", file); connect( &picker, SIGNAL(pick(const QImage&)), &editor, SLOT(edit(const QImage&)) ); connect( &picker, SIGNAL(pickName(const QString&)), statusBar(), SLOT(message(const QString&)) ); connect( &editor, SIGNAL(edited(const QImage&)), &picker, SLOT(setCurrent(const QImage&)) ); setCentralWidget(¢ral); } private: QHBox central; TileEditor editor; TilePicker picker; }; main(int argc, char** argv) { QApplication app(argc,argv); Main m; app.setMainWidget(&m); m.show(); return app.exec(); } #include "tileedit.moc" nethack-3.6.0/win/Qt/tileedit.h0000664000076400007660000000523712536476415015316 0ustar paxedpaxed/* NetHack 3.6 tileedit.h $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QNHTILEEDIT_H #define QNHTILEEDIT_H #include #include #include #include class TilePickerTab : public QWidget { Q_OBJECT public: TilePickerTab(const char *basename, int id, QWidget *parent); bool save(); int numTiles(); signals: void pick(const QImage &); void pickName(const QString &); public slots: void setCurrent(const QImage &); protected: void paintEvent(QPaintEvent *); QSize sizeHint() const; void mousePressEvent(QMouseEvent *); private: QString filename; int id; int last_pick; int num; QPixmap pixmap; QImage image; }; class TilePicker : public QTabWidget { Q_OBJECT public: TilePicker(QWidget *parent); void setTile(int tilenum, const QImage &); signals: void pick(const QImage &); void pickName(const QString &); public slots: void setCurrent(const QImage &); void save(); }; class TrivialTileEditor : public QWidget { Q_OBJECT public: TrivialTileEditor(QWidget *parent); const QImage &image() const; signals: void edited(const QImage &); void pick(QRgb); public slots: void setColor(QRgb); void setImage(const QImage &); protected: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); void mouseMoveEvent(QMouseEvent *); QSize sizeHint() const; QSize sizeForWidth(int) const; QSizePolicy sizePolicy() const; private: void fill(QPainter &painter, QPoint p, uchar from); QImage img; QColor pen; int penpixel; void paintPoint(QPainter &painter, QPoint p); QPoint screenPoint(QPoint) const; QPoint imagePoint(QPoint) const; }; class TilePalette : public QWidget { Q_OBJECT public: TilePalette(QWidget *parent); ~TilePalette(); void setFromImage(const QImage &); protected: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *); QSize sizeHint() const; QSizePolicy sizePolicy() const; signals: void pick(QRgb); public slots: void setColor(QRgb); private: int num; QRgb *rgb; }; class TileEditor : public QVBox { Q_OBJECT public: TileEditor(QWidget *parent); const QImage &image() const; signals: void edited(const QImage &); public slots: void edit(const QImage &); private: TrivialTileEditor editor; TilePalette palette; }; #endif nethack-3.6.0/win/X11/Install.X110000664000076400007660000002416012536476415015224 0ustar paxedpaxed$NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ This document describes the installation of NetHack with an X11 interface. There are no explicit UNIX dependencies in this code, but we have only tested it under UNIX, using X11R4, X11R5, or X11R6. We have two reports that the code also works under DesqView/X on MS-DOS with djgpp, but you will have to add dependencies for the X code to that makefile before you can use it. Other X11R4+ platforms may work as well, with some tweaking likely. Follow WIN* in sys/unix/Makefile.src for compilation hints. (If you try to compile it with X11R3 or earlier, you will get many errors, starting with complaints about XtPointer not being declared. If you get around the compilation problems, you will still need a recent library of Athena Widgets to link against. Once compiled, you can probably run it under an R3 X server, though.) The reason this uses the Athena widget set is that the Athena widgets come free from MIT (like X11). Unfortunately, the companies that resell X11 (value subtracted er, added software; yea, yea, that's the ticket) usually discourage its use by either omitting the set or putting it on the "unsupported" portion of their tape. If you do not have the Athena widgets, you may obtain them via anonymous ftp from ftp.x.org. To use this code, define X11_GRAPHICS in include/config.h. (You can comment out TTY_GRAPHICS or change DEFAULT_WINDOW_SYS if you want to, but there's little reason to do so. The X11 version almost requires a config file for full effect, so you can just as well set windowtype there; also, you or someone else might just possibly be stuck in a situation where you can't use the X version -- over a non-blindingly-fast modem, say.) You may also want to define USE_XPM or GRAPHIC_TOMBSTONE as discussed below. In src/Makefile, add $(WINX11SRC), $(WINX11OBJ), and $(WINX11LIB) to WINSRC, WINOBJ, and WINLIB respectively, and compile. This will give you an executable supporting both X11 and tty windowing. If you want to use the optional tiles (multicolored pictures instead of a replacement font), you will need to have the win/share files and change the VARDATND setting in the top Makefile to contain the tile files before you do your 'make all'. If you get a linker error referring to `substitute_tiles' then most likely you have overlooked the WINSRC, WINOBJ, WINLIB step above. Alternatively, you are building with more than one non-tty interface specified but haven't followed the direction in src/Makefile to remove all but one instance of tile.o from the WINxxxOBJ values used for WINOBJ. When using tiles, you have the option of defining USE_XPM in config.h. This causes NetHack to use the XPM file format for the "x11tiles" file rather than a custom format. Since the XPM format can be processed by existing tools such as PBMPlus and XV, you can modify the tiles to suit your environment. However, you need to make sure the number of tiles in each row of the image remains the same (currently 40), as the code depends on this to calculate the size of each tile. For example, you may magnify them for display on high-resolution screens using the following command: xpmtoppm x11tiles | pnmscale -xscale 1 -yscale 1.6875 | pnmdepth 255 | ppmquant 100 | ppmtoxpm >x11tiles_big.xpm To use XPM, you must have the free XPM libraries installed in your system. Official xpm releases can be found by ftp on: ftp.x.org (198.4.202.8) contrib/libraries (Boston, USA) avahi.inria.fr (138.96.12.1) pub/xpm (Sophia Antipolis, France) If you do choose to define USE_XPM, be sure to add "-lXpm" to WINX11LIB in src/Makefile. If you define USE_XPM in config.h, you may also define GRAPHIC_TOMBSTONE which causes the closing tombstone to be displayed from the image file specified by the "tombstone" X resource (rip.xpm by default). In this case, make sure the top Makefile VARDATND also contains rip.xpm. Whether or not you install tile support, you can provide support for special graphics symbols via alternate fonts. (The fonts and tiles cannot be used at the same time, but the same executable handles both.) The two included X11 fonts use the general NetHack map area remapping to represent object/dungeon/trap/effect characters (see win/X11/nethack.rc and the Guidebook) as monocolored symbols and monsters as monocolored letters. For instance, a ruby potion will show up as a potion symbol in red. It's easier to see the difference between fonts and tiles than to describe it. :-) Unless you are the only one using your executable and you already know which you prefer, we suggest installing the optional files for both possibilities and letting each person decide for themselves. To use the included fonts, you will need to install one or both of them and then use the symbol mappings found in nethack.rc. The fonts are found in nh10.bdf and ibm.bdf. You first need to convert the bdf files to whatever form your X11 server recognizes (usually using a command called bdftosnf for R4 servers or bdftopcf for R5 servers). Then run mkfontdir on the directory containing your font files (you might want to copy them to HACKDIR, from the top Makefile, after you've done "make install"). If these commands aren't familiar, talk to your local X11 guru and read the man pages. nethack.sh automatically adds HACKDIR to your font search path. If you (assuming you are a system administrator) can install the fonts in your standard X11 font directory the relevent lines in nethack.sh can be removed. Alternatively, all persons playing nethack must add that "xset fp+" command to their .xinitrc file, or whatever file they execute when starting X11. See the note below for the alternative installation procedure for Sun's OpenWindows. If your X11 include files and libraries are not installed in a standard place (i.e. /usr/include/X11 and /usr/lib respectively) you will need to prepend an appropriate -I parameter to CFLAGS and a -L parameter to LFLAGS, setting to the place to find the include and library files for X11. Finally, to ensure NetHack's windows look the way they were intended to look, make sure the top Makefile VARDATND also contains NetHack.ad. If it does, running nethack will automatically take the appropriate steps to cause this file to be used to initialize NetHack's X11 resources. Three icon suggestions to the window manager are supported: nh72, nh56, and nh32. Data for them comes from the source files nh72icon, nh56icon, and nh32icon; they are compiled into the program via #includes in winX.c. Selection between them is controlled by the "icon" resource in NetHack.ad; the default is nh72. Sorry, an Imakefile is not included. Unlike many X11 programs, X11 support is only a small, optional, part of nethack, and the Makefile is needed for systems that don't use X11. Notes for Sun's OpenWindows: 1. For OpenWindows 3.0 (NOT 2.x), define OPENWINBUG in include/unixconf.h. The library bug from SunOS 4.1.x is fixed in Solaris 2.x (or when proper Sun patches have been applied to 4.1.x), so it is also unnecessary there. (Defining it when unnecessary causes the same problem being avoided when it is necessary. :-) 2. In addition to the changes suggested by the comments in src/Makefile, -- for OpenWindows 2.x and 3.0 (NOT 3.1) (i.e., versions for SunOS 4.x), add -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib to LFLAGS, and -lm to WINX11LIB in src/Makefile. -- for OpenWindows 3.1 (i.e., versions for Solaris 2.x), add -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib -L/usr/ccs/lib -R/usr/openwin/lib to LFLAGS, and -lsocket -lnsl -lm to WINX11LIB in src/Makefile. (Naturally, if your OpenWindows is installed elsewhere, adapt the openwin paths.) This will allow you to create a game executable. 3. Run the fonts through convertfont and run bldfamily on the directory. Now you must let your X server know where to find the fonts. For a personal installation, the simplest thing is to include the directory of the fonts in the environment variable FONTPATH, as set in your .profile or .login before starting the server. For a multi-user installation, you have the various "xset fp+" options outlined above for standard X. 4. Something must still be done with the NetHack.ad file -- all three of the possibilities mentioned for standard X11 should work. Notes for AIX 3.2: 1. AIX 3.2 includes the Athena Widget Toolkit library (and other things) under the /usr/lpp/X11/Xamples tree, so you will have to add -L/usr/lpp/X11/Xamples/lib to LFLAGS. If you can't find libXaw.a on your first build, go into /usr/lib/X11/Xamples, read the README file, and build the library. Notes for XFree86 - (on linux and BSD386 platforms) 1. Edit src/Makefile for linux/BSD386. Even though you use the Open Look Window manager, do not define OPENWINBUG. Use the standard X11 object and library options. 2. Follow the standard installation directions defined above. File Description --------- --------------------------------------------------------------- nethack.rc - A sample configuration file for fonts nh10 and ibm. nh10.bdf - A modified version of the 10x20 standard font. ibm.bdf - A modified version of one of the ibm (8x14) nethack font. Must be used in conjunction with NetHack.ad or nethack.rc. nh32icon - A 32x32 icon bitmap for use with window managers. nh56icon - A 56x56 icon bitmap for use with window managers. nh72icon - A 72x72 icon bitmap for use with window managers. nh_icon.xpm - A color icon for use with window managers. NetHack.ad - A sample .Xdefaults for a color screen. ../../include/Window.h ../../include/WindowP.h Window.c - A bare-bones widget that has 16 colors and a drawing canvas. ../../include/winX.h - Defines for the X window-port. win*.c - Code for the X window-port dialogs.c - A better dialog widget. Original code (modified slightly by Dean Luick) distributed under the X copyright by Tim Theisen. This is from his Ghostview program (which is under the GNU public license, v2 or higher). pet_mark.xbm - A pet indicator bitmap for tiles. pilemark.xbm - Item pile indicator for tiles. rip.xpm - A graphical tombstone. tile2x11.c - Converts win/share tiles for X11 use. nethack-3.6.0/win/X11/NetHack.ad0000664000076400007660000001646112536476415015153 0ustar paxedpaxed! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ ! The display_file, tombstone, and menu windows are all formatted assuming ! a fixed width font. Text windows may or may not be formatted as above. ! The rip window applies if the GRAPHIC_TOMBSTONE option is turned on, and ! requires a 12 pixel font for correct appearance. ! NetHack*font: variable NetHack*display_file*font: fixed NetHack*tombstone*font: fixed NetHack*text*rip*font: -*-times-medium-r-*-*-12-*-*-*-*-*-*-* NetHack*menu*font: fixed NetHack*text*font: fixed NetHack*map*font: nh10 ! tile_file names a file containing full-color tiles for the map. ! If you use a 100dpi (or greater) monitor you may wish to double the ! tile size so you can see the figures. If NetHack was compiled to ! use XPM (USE_XPM in config.h), the tile_file is a standard XPM file. ! Otherwise, it is a custom format. double_tile_size only applies to ! the custom format - to enlarge an XPM file, use processing tools ! such as XV or preferably PBMplus. ! NetHack.tile_file: x11tiles !NetHack.double_tile_size: True ! ! The annotation of pets. !NetHack.pet_mark_bitmap: pet_mark.xbm !NetHack.pet_mark_color: Red ! The annotation of item piles. !NetHack.pilemark_bitmap: pilemark.xbm !NetHack.pilemark_color: Green ! Tombstone ! The image file !NetHack.tombstone: rip.xpm ! Text starts at (tombtext_x, tombtext_y) and subsequent lines ! are displaced by (tombtext_dx, tombtext_dy) pixels. If you !NetHack.tombtext_x: 155 !NetHack.tombtext_y: 78 !NetHack.tombtext_dx: 0 !NetHack.tombtext_dy: 13 ! The color to use for the text on the hero's tombstone NetHack*rip*foreground: black ! Translation tables. There are currently several actions in nethack, but ! the only one you should be using is "input()", which, with no parameters, ! uses XLookupString to translate your keypress into a command. You ! can optionally give it parameters to change the behavior, see the example ! below. Note that you have to specify the translations in every appropriate ! window. NetHack*message*translations: : input() ! ! Example extra translations for the map window. ! !NetHack*map*translations: #override \ ! !Left: input(h) \n\ ! !Right: input(l) \n\ ! !Up: input(k) \n\ ! !Down: input(j) ! ! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the ! default. Some window managers may not support the larger icon sizes. ! It is not guaranteed that the window manager will honor the icon selection. !NetHack*icon: nh56 ! ! If True, the default, a popup for single character prompts such as y/n ! questions is _not_ used. NetHack*slow: True ! The number of lines the message window will show without scrolling. !NetHack*message_lines: 12 ! ! If True, the message window has a line that seperates old and new messages. !NetHack*message_line: True ! ! If True, force keyboard to attach to popup windows. Some window managers ! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm). NetHack ! has a lot of popups and is almost unplayable without some kind of autofocus. !NetHack*autofocus: True ! ! Specify the number of rows and columns of the map window. The default ! is the standard 80x21 window. Note: this _does_not_ change nethack's ! level size, only what you see of it. !NetHack*map*rows: 21 !NetHack*map*columns: 80 ! Parts of the fancy status display. ! NetHack*status_condition.borderWidth: 0 NetHack*status_info*borderWidth: 0 ! Sample color screen entries. ! NetHack*nethack.background: wheat NetHack*map*yellow: gold NetHack*map*brown: tan NetHack*map*gray: grey85 NetHack*map*foreground: wheat NetHack*map*background: grey40 NetHack*fancy_status.skipAdjust: True NetHack*fancy_status.background: wheat NetHack*status_info*foreground: Sienna NetHack*status_info*background: wheat NetHack*status_info.background: wheat NetHack*status_attributes*foreground: black NetHack*status_attributes*background: white NetHack*status_condition*foreground: red NetHack*status_condition*background: wheat NetHack*Scrollbar*foreground: Sienna NetHack*Scrollbar*background: wheat NetHack*status_info*showGrip: False NetHack*status_attributes*showGrip: False NetHack*player_selection*random.borderColor: blue NetHack*player_selection*random.borderWidth: 2 NetHack*player_selection*random.foreground: blue NetHack*player_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*player_selection*quit.borderColor: blue NetHack*player_selection*quit.foreground: blue NetHack*player_selection*Command.borderColor: red NetHack*player_selection*Command.foreground: red NetHack*player_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*race_selection*random.borderColor: blue NetHack*race_selection*random.borderWidth: 2 NetHack*race_selection*random.foreground: blue NetHack*race_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*race_selection*quit.borderColor: blue NetHack*race_selection*quit.foreground: blue NetHack*race_selection*Command.borderColor: red NetHack*race_selection*Command.foreground: red NetHack*race_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*gender_selection*random.borderColor: blue NetHack*gender_selection*random.borderWidth: 2 NetHack*gender_selection*random.foreground: blue NetHack*gender_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*gender_selection*quit.borderColor: blue NetHack*gender_selection*quit.foreground: blue NetHack*gender_selection*Command.borderColor: red NetHack*gender_selection*Command.foreground: red NetHack*gender_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*alignment_selection*random.borderColor: blue NetHack*alignment_selection*random.borderWidth: 2 NetHack*alignment_selection*random.foreground: blue NetHack*alignment_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*alignment_selection*quit.borderColor: blue NetHack*alignment_selection*quit.foreground: blue NetHack*alignment_selection*Command.borderColor: red NetHack*alignment_selection*Command.foreground: red NetHack*alignment_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*extended_commands*dismiss.borderColor: blue NetHack*extended_commands*dismiss.foreground: blue NetHack*extended_commands*help.borderColor: blue NetHack*extended_commands*help.foreground: blue NetHack*extended_commands*Command.borderColor: red NetHack*extended_commands*Command.foreground: red NetHack*extended_commands*help.accelerators: #override\n\ :?: set() notify() unset() NetHack*extended_commands*dismiss.accelerators: #override\n\ Escape: set() notify() unset() ! ! ! The following are the default 15 colors that the nethack map uses. ! If they don't look good on your screen, change them. ! ! The foreground color is used as "no color". ! !NetHack*map*black: black !NetHack*map*red: red !NetHack*map*green: pale green !NetHack*map*brown: brown !NetHack*map*blue: blue !NetHack*map*magenta: magenta !NetHack*map*cyan: light cyan !NetHack*map*gray: gray !NetHack*map*orange: orange !NetHack*map*bright_green: green !NetHack*map*yellow: yellow !NetHack*map*bright_blue: royal blue !NetHack*map*bright_magenta: violet !NetHack*map*bright_cyan: cyan !NetHack*map*white: white nethack-3.6.0/win/X11/Window.c0000664000076400007660000001357212536476415014743 0ustar paxedpaxed/* NetHack 3.6 Window.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Data structures and support routines for the Window widget. This is a * drawing canvas with 16 colors and one font. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #ifdef MSDOS /* from compiler */ #define SHORT_FILENAMES #endif #ifdef SHORT_FILENAMES #include #else #include #endif #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "xwindowp.h" #include "config.h" #include "lint.h" static XtResource resources[] = { #define offset(field) XtOffset(WindowWidget, window.field) /* {name, class, type, size, offset, default_type, default_addr}, */ { nhStr(XtNrows), nhStr(XtCRows), XtRDimension, sizeof(Dimension), offset(rows), XtRImmediate, (XtPointer) 21 }, { nhStr(XtNcolumns), nhStr(XtCColumns), XtRDimension, sizeof(Dimension), offset(columns), XtRImmediate, (XtPointer) 80 }, { nhStr(XtNforeground), XtCForeground, XtRPixel, sizeof(Pixel), offset(foreground), XtRString, (XtPointer) XtDefaultForeground }, { nhStr(XtNblack), XtCColor, XtRPixel, sizeof(Pixel), offset(black), XtRString, (XtPointer) "black" }, { nhStr(XtNred), XtCColor, XtRPixel, sizeof(Pixel), offset(red), XtRString, (XtPointer) "red" }, { nhStr(XtNgreen), XtCColor, XtRPixel, sizeof(Pixel), offset(green), XtRString, (XtPointer) "pale green" }, { nhStr(XtNbrown), XtCColor, XtRPixel, sizeof(Pixel), offset(brown), XtRString, (XtPointer) "brown" }, { nhStr(XtNblue), XtCColor, XtRPixel, sizeof(Pixel), offset(blue), XtRString, (XtPointer) "blue" }, { nhStr(XtNmagenta), XtCColor, XtRPixel, sizeof(Pixel), offset(magenta), XtRString, (XtPointer) "magenta" }, { nhStr(XtNcyan), XtCColor, XtRPixel, sizeof(Pixel), offset(cyan), XtRString, (XtPointer) "light cyan" }, { nhStr(XtNgray), XtCColor, XtRPixel, sizeof(Pixel), offset(gray), XtRString, (XtPointer) "gray" }, { nhStr(XtNorange), XtCColor, XtRPixel, sizeof(Pixel), offset(orange), XtRString, (XtPointer) "orange" }, { nhStr(XtNbright_green), XtCColor, XtRPixel, sizeof(Pixel), offset(bright_green), XtRString, (XtPointer) "green" }, { nhStr(XtNyellow), XtCColor, XtRPixel, sizeof(Pixel), offset(yellow), XtRString, (XtPointer) "yellow" }, { nhStr(XtNbright_blue), XtCColor, XtRPixel, sizeof(Pixel), offset(bright_blue), XtRString, (XtPointer) "royal blue" }, { nhStr(XtNbright_magenta), XtCColor, XtRPixel, sizeof(Pixel), offset(bright_magenta), XtRString, (XtPointer) "violet" }, { nhStr(XtNbright_cyan), XtCColor, XtRPixel, sizeof(Pixel), offset(bright_cyan), XtRString, (XtPointer) "cyan" }, { nhStr(XtNwhite), XtCColor, XtRPixel, sizeof(Pixel), offset(white), XtRString, (XtPointer) "white" }, { nhStr(XtNfont), XtCFont, XtRFontStruct, sizeof(XFontStruct *), offset(font), XtRString, (XtPointer) XtDefaultFont }, { nhStr(XtNexposeCallback), XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(expose_callback), XtRCallback, (char *) 0 }, { nhStr(XtNcallback), XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(input_callback), XtRCallback, (char *) 0 }, { nhStr(XtNresizeCallback), XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(resize_callback), XtRCallback, (char *) 0 }, #undef offset }; /* ARGSUSED */ static void no_op(w, event, params, num_params) Widget w; /* unused */ XEvent *event; /* unused */ String *params; /* unused */ Cardinal *num_params; /* unused */ { nhUse(w); nhUse(event); nhUse(params); nhUse(num_params); return; } static XtActionsRec actions[] = { { nhStr("no-op"), no_op }, }; static char translations[] = ": input() \ "; /* ARGSUSED */ static void Redisplay(w, event, region) Widget w; XEvent *event; Region region; /* unused */ { nhUse(region); /* This isn't correct - we need to call the callback with region. */ XtCallCallbacks(w, XtNexposeCallback, (caddr_t) event); } /* ARGSUSED */ static void Resize(w) Widget w; { XtCallCallbacks(w, XtNresizeCallback, (caddr_t) 0); } WindowClassRec windowClassRec = { { /* core fields */ /* superclass */ (WidgetClass) &widgetClassRec, /* class_name */ nhStr("Window"), /* widget_size */ sizeof(WindowRec), /* class_initialize */ 0, /* class_part_initialize */ 0, /* class_inited */ FALSE, /* initialize */ 0, /* initialize_hook */ 0, /* realize */ XtInheritRealize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ 0, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ 0, /* set_values_hook */ 0, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ 0, /* accept_focus */ 0, /* version */ XtVersion, /* callback_private */ 0, /* tm_table */ translations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ 0 }, { /* window fields */ /* empty */ 0 } }; WidgetClass windowWidgetClass = (WidgetClass) &windowClassRec; Font WindowFont(w) Widget w; { return ((WindowWidget) w)->window.font->fid; } XFontStruct * WindowFontStruct(w) Widget w; { return ((WindowWidget) w)->window.font; } nethack-3.6.0/win/X11/dialogs.c0000664000076400007660000003061712536476415015115 0ustar paxedpaxed/* * Copyright 1991 University of Wisconsin-Madison * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Wisconsin-Madison not * be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. The University of * Wisconsin-Madison makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE *FOR * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Tim Theisen Department of Computer Sciences * tim@cs.wisc.edu University of Wisconsin-Madison * uwvax!tim 1210 West Dayton Street * (608)262-0438 Madison, WI 53706 * * * Modified 12/91 by Dean Luick. Tim graciously donated this piece of code * from his program ghostview, an X11 front end for ghostscript. * * + Make the cancel button optional. * + Put an #ifdef SPECIAL_CMAP around code to fix a colormap bug. * We don't need it here. * + Add the function positionpopup() from another part of ghostview * to this code. * * Modified 2/93, Various. * + Added workaround for SYSV include problem. * + Changed the default width response text widget to be as wide as the * window itself. Suggestion from David E. Wexelblat, dwex@goblin.org. * * Modified 5/2015, anonymous. * + Include nethack's lint.h to get nhStr() macro. * + Use nhStr() on string literals (or macros from * that hide string literals) to cast away implicit 'const' in order * to suppress "warning: assignment discards qualifers from pointer * target type" issued by 'gcc -Wwrite-strings' as used by nethack. * (For this file, always the second parameter to XtSetArg().) * * $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "config.h" /* #define for const for non __STDC__ compilers */ #include "lint.h" /* for nethack's nhStr() macro */ /* ":" added to both translations below to allow limited redefining of * keysyms before testing for keysym values -- dlc */ static const char okay_accelerators[] = "#override\n\ :Return: set() notify() unset()\n"; static const char cancel_accelerators[] = "#override\n\ :Escape: set() notify() unset()\n\ :[: set() notify() unset()\n"; /* for keyboards w/o an ESC */ /* Create a dialog widget. It is just a form widget with * a label prompt * a text response * an okay button * an optional cancel button */ Widget CreateDialog(parent, name, okay_callback, cancel_callback) Widget parent; String name; XtCallbackProc okay_callback; XtCallbackProc cancel_callback; { Widget form, prompt, response, okay, cancel; Arg args[20]; Cardinal num_args; num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], nhStr(XtNbackground), white); num_args++; } #endif form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args); num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], nhStr(XtNforeground), black); num_args++; XtSetArg(args[num_args], nhStr(XtNbackground), white); num_args++; } #endif XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; XtSetArg(args[num_args], nhStr(XtNborderWidth), 0); num_args++; prompt = XtCreateManagedWidget("prompt", labelWidgetClass, form, args, num_args); num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], nhStr(XtNforeground), black); num_args++; XtSetArg(args[num_args], nhStr(XtNbackground), white); num_args++; } #endif XtSetArg(args[num_args], nhStr(XtNfromVert), prompt); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; XtSetArg(args[num_args], nhStr(XtNeditType), XawtextEdit); num_args++; XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++; XtSetArg(args[num_args], nhStr(XtNstring), ""); num_args++; response = XtCreateManagedWidget("response", asciiTextWidgetClass, form, args, num_args); num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], nhStr(XtNforeground), black); num_args++; XtSetArg(args[num_args], nhStr(XtNbackground), white); num_args++; } #endif XtSetArg(args[num_args], nhStr(XtNfromVert), response); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; XtSetArg(args[num_args], nhStr(XtNaccelerators), XtParseAcceleratorTable(okay_accelerators)); num_args++; okay = XtCreateManagedWidget("okay", commandWidgetClass, form, args, num_args); XtAddCallback(okay, XtNcallback, okay_callback, form); /* Only create cancel button if there is a callback for it. */ if (cancel_callback) { num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], nhStr(XtNforeground), black); num_args++; XtSetArg(args[num_args], nhStr(XtNbackground), white); num_args++; } #endif XtSetArg(args[num_args], nhStr(XtNfromVert), response); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), okay); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; XtSetArg(args[num_args], nhStr(XtNaccelerators), XtParseAcceleratorTable(cancel_accelerators)); num_args++; cancel = XtCreateManagedWidget("cancel", commandWidgetClass, form, args, num_args); XtAddCallback(cancel, XtNcallback, cancel_callback, form); XtInstallAccelerators(response, cancel); } XtInstallAccelerators(response, okay); XtSetKeyboardFocus(form, response); return form; } #if 0 /* get the prompt from the dialog box. Used a startup time to * save away the initial prompt */ String GetDialogPrompt(w) Widget w; { Arg args[1]; Widget label; String s; label = XtNameToWidget(w, "prompt"); XtSetArg(args[0], nhStr(XtNlabel), &s); XtGetValues(label, args, ONE); return XtNewString(s); } #endif /* set the prompt. This is used to put error information in the prompt */ void SetDialogPrompt(w, newprompt) Widget w; String newprompt; { Arg args[1]; Widget label; label = XtNameToWidget(w, "prompt"); XtSetArg(args[0], nhStr(XtNlabel), newprompt); XtSetValues(label, args, ONE); } /* get what the user typed; caller must free the response */ String GetDialogResponse(w) Widget w; { Arg args[1]; Widget response; String s; response = XtNameToWidget(w, "response"); XtSetArg(args[0], nhStr(XtNstring), &s); XtGetValues(response, args, ONE); return XtNewString(s); } #define max(a, b) (((a) > (b)) ? (a) : (b)) /* set the default reponse */ void SetDialogResponse(w, s) Widget w; String s; { Arg args[4]; Widget response; XFontStruct *font; Dimension width, nwidth, leftMargin, rightMargin; response = XtNameToWidget(w, "response"); XtSetArg(args[0], nhStr(XtNfont), &font); XtSetArg(args[1], nhStr(XtNleftMargin), &leftMargin); XtSetArg(args[2], nhStr(XtNrightMargin), &rightMargin); XtSetArg(args[3], nhStr(XtNwidth), &width); XtGetValues(response, args, FOUR); /* width includes margins as per Xaw documentation */ nwidth = (font->max_bounds.width * strlen(s)) + leftMargin + rightMargin; if (nwidth < width) nwidth = width; XtSetArg(args[0], nhStr(XtNstring), s); XtSetArg(args[1], nhStr(XtNwidth), nwidth); XtSetValues(response, args, TWO); XawTextSetInsertionPoint(response, strlen(s)); } #if 0 /* clear the response */ void ClearDialogResponse(w) Widget w; { Arg args[2]; Widget response; response = XtNameToWidget(w, "response"); XtSetArg(args[0], nhStr(XtNstring), ""); XtSetArg(args[1], nhStr(XtNwidth), 100); XtSetValues(response, args, TWO); } #endif /* Not a part of the original dialogs.c from ghostview --------------------- */ /* position popup window under the cursor */ void positionpopup(w, bottom) Widget w; boolean bottom; /* position y on bottom? */ { Arg args[3]; Cardinal num_args; Dimension width, height, b_width; int x, y, max_x, max_y; Window root, child; XSizeHints *hints; int dummyx, dummyy; unsigned int dummymask; extern Widget toplevel; /* following line deals with a race condition w/brain-damaged WM's -dlc */ XtUnrealizeWidget(w); XQueryPointer(XtDisplay(toplevel), XtWindow(toplevel), &root, &child, &x, &y, &dummyx, &dummyy, &dummymask); num_args = 0; XtSetArg(args[num_args], XtNwidth, &width); num_args++; XtSetArg(args[num_args], XtNheight, &height); num_args++; XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++; XtGetValues(w, args, num_args); /* position so that the cursor is center,center or center,bottom */ width += 2 * b_width; x -= ((Position) width / 2); if (x < 0) x = 0; if (x > (max_x = (Position)(XtScreen(w)->width - width))) x = max_x; if (bottom) { y -= (height + b_width - 1); height += 2 * b_width; } else { height += 2 * b_width; y -= ((Position) height / 2); } if (y < 0) y = 0; if (y > (max_y = (Position)(XtScreen(w)->height - height))) y = max_y; num_args = 0; XtSetArg(args[num_args], XtNx, x); num_args++; XtSetArg(args[num_args], XtNy, y); num_args++; XtSetValues(w, args, num_args); /* Some older window managers ignore XtN{x,y}; hint the same values */ /* The {x,y} are not used by newer window managers; older ones need them */ XtRealizeWidget(w); hints = XAllocSizeHints(); hints->flags = USPosition; hints->x = x; hints->y = y; XSetWMNormalHints(XtDisplay(w), XtWindow(w), hints); XFree(hints); } nethack-3.6.0/win/X11/ibm.bdf0000664000076400007660000011420612467321052014535 0ustar paxedpaxedSTARTFONT 2.1 COMMENT (null) FONT -Misc-Fixed-Medium-R-Normal-IBMPC-14-120-75-75-C-80-ISO8859-1 SIZE 13 78 78 FONTBOUNDINGBOX 8 14 0 -3 STARTPROPERTIES 19 FONTNAME_REGISTRY "" FOUNDRY "Misc" FAMILY_NAME "Fixed" WEIGHT_NAME "Medium" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "IBMPC" PIXEL_SIZE 14 POINT_SIZE 120 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 80 CHARSET_REGISTRY "ISO8859" CHARSET_ENCODING "1" DEFAULT_CHAR 0 FONT_DESCENT 3 FONT_ASCENT 11 COPYRIGHT "Public domain font. Share and enjoy." ENDPROPERTIES CHARS 256 STARTCHAR C000 ENCODING 0 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C001 ENCODING 1 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 8100 a500 8100 8100 bd00 9900 8100 7e00 0000 0000 0000 ENDCHAR STARTCHAR C002 ENCODING 2 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 ff00 db00 ff00 ff00 c300 e700 ff00 7e00 0000 0000 0000 ENDCHAR STARTCHAR C003 ENCODING 3 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 6c00 ee00 fe00 fe00 fe00 7c00 3800 1000 0000 0000 0000 ENDCHAR STARTCHAR C004 ENCODING 4 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1000 3800 7c00 fe00 7c00 3800 1000 0000 0000 0000 0000 ENDCHAR STARTCHAR C005 ENCODING 5 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1000 3800 1000 6c00 ee00 6c00 1000 3800 0000 0000 0000 ENDCHAR STARTCHAR C006 ENCODING 6 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1000 3800 7c00 7c00 fe00 fe00 6c00 1000 3800 0000 0000 0000 ENDCHAR STARTCHAR C007 ENCODING 7 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 1800 3c00 3c00 1800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C010 ENCODING 8 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 ff00 e700 c300 c300 e700 ff00 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C011 ENCODING 9 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1800 3c00 6600 6600 3c00 1800 0000 0000 0000 0000 ENDCHAR STARTCHAR C012 ENCODING 10 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 e700 c300 9900 9900 c300 e700 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C013 ENCODING 11 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1e00 0e00 1e00 3600 7800 cc00 cc00 cc00 7800 0000 0000 0000 ENDCHAR STARTCHAR C014 ENCODING 12 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 6600 6600 6600 3c00 1800 7e00 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR C015 ENCODING 13 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1e00 1a00 1e00 1800 1800 1800 7800 f800 7000 0000 0000 0000 ENDCHAR STARTCHAR C016 ENCODING 14 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3e00 3600 3e00 3600 3600 7600 f600 6600 0e00 1e00 0c00 0000 0000 ENDCHAR STARTCHAR C017 ENCODING 15 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1800 db00 7e00 3c00 6600 6600 3c00 7e00 db00 1800 0000 0000 0000 ENDCHAR STARTCHAR C020 ENCODING 16 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 8000 e000 f000 fc00 fe00 fc00 f000 e000 8000 0000 0000 0000 ENDCHAR STARTCHAR C021 ENCODING 17 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0200 0e00 3e00 7e00 fe00 7e00 3e00 0e00 0200 0000 0000 0000 ENDCHAR STARTCHAR C022 ENCODING 18 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 7e00 1800 1800 1800 7e00 3c00 1800 0000 0000 0000 ENDCHAR STARTCHAR C023 ENCODING 19 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6600 6600 6600 6600 6600 6600 0000 6600 6600 0000 0000 0000 ENDCHAR STARTCHAR C024 ENCODING 20 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7f00 db00 db00 db00 7b00 1b00 1b00 1b00 1b00 0000 0000 0000 ENDCHAR STARTCHAR C025 ENCODING 21 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 7c00 c600 c600 6000 7c00 f600 de00 7c00 0c00 c600 c600 7c00 0000 ENDCHAR STARTCHAR C026 ENCODING 22 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 fe00 fe00 fe00 0000 0000 0000 ENDCHAR STARTCHAR C027 ENCODING 23 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 7e00 1800 1800 7e00 3c00 1800 7e00 0000 0000 0000 ENDCHAR STARTCHAR C030 ENCODING 24 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 7e00 1800 1800 1800 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR C031 ENCODING 25 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 1800 1800 1800 1800 1800 7e00 3c00 1800 0000 0000 0000 ENDCHAR STARTCHAR C032 ENCODING 26 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0c00 0e00 ff00 0e00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C033 ENCODING 27 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 3000 7000 fe00 7000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C034 ENCODING 28 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c000 c000 c000 fe00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C035 ENCODING 29 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 2400 6600 ff00 6600 2400 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C036 ENCODING 30 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1000 3800 3800 3800 7c00 7c00 fe00 fe00 0000 0000 0000 0000 ENDCHAR STARTCHAR C037 ENCODING 31 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 fe00 7c00 7c00 7c00 3800 3800 1000 0000 0000 0000 0000 ENDCHAR STARTCHAR C040 ENCODING 32 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ! ENCODING 33 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 3c00 3c00 1800 1800 0000 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR " ENCODING 34 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3600 3600 3600 1400 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR # ENCODING 35 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6c00 6c00 6c00 fe00 6c00 6c00 fe00 6c00 6c00 0000 0000 0000 ENDCHAR STARTCHAR $ ENCODING 36 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1800 1800 7c00 c600 c000 7800 3c00 0600 c600 7c00 1800 1800 0000 ENDCHAR STARTCHAR % ENCODING 37 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 6200 6600 0c00 1800 3000 6600 c600 0000 0000 0000 ENDCHAR STARTCHAR & ENCODING 38 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 3800 3800 7600 f600 ce00 cc00 7600 0000 0000 0000 ENDCHAR STARTCHAR ' ENCODING 39 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0c00 0c00 0c00 1800 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ( ENCODING 40 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 3000 3000 3000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR ) ENCODING 41 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3000 1800 0c00 0c00 0c00 0c00 0c00 1800 3000 0000 0000 0000 ENDCHAR STARTCHAR * ENCODING 42 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 6c00 3800 fe00 3800 6c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR + ENCODING 43 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1800 1800 7e00 1800 1800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR , ENCODING 44 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 0c00 1800 0000 0000 ENDCHAR STARTCHAR - ENCODING 45 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 fe00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR . ENCODING 46 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR / ENCODING 47 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0200 0600 0c00 1800 3000 6000 c000 8000 0000 0000 0000 ENDCHAR STARTCHAR 0 ENCODING 48 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 ce00 de00 f600 e600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 1 ENCODING 49 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 7800 1800 1800 1800 1800 1800 1800 7e00 0000 0000 0000 ENDCHAR STARTCHAR 2 ENCODING 50 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 0c00 1800 3000 6000 c600 fe00 0000 0000 0000 ENDCHAR STARTCHAR 3 ENCODING 51 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 0600 0600 3c00 0600 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 4 ENCODING 52 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1c00 3c00 6c00 cc00 fe00 0c00 0c00 0c00 0000 0000 0000 ENDCHAR STARTCHAR 5 ENCODING 53 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c000 c000 c000 fc00 0600 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 6 ENCODING 54 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c000 c000 fc00 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 7 ENCODING 55 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c600 0c00 1800 3000 3000 3000 3000 3000 0000 0000 0000 ENDCHAR STARTCHAR 8 ENCODING 56 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 7c00 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 9 ENCODING 57 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 7e00 0600 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR : ENCODING 58 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 0000 0c00 0c00 0000 0000 0000 0000 ENDCHAR STARTCHAR ; ENCODING 59 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 0000 0c00 0c00 0c00 1800 0000 0000 ENDCHAR STARTCHAR < ENCODING 60 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 c000 6000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR = ENCODING 61 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 0000 fe00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR > ENCODING 62 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6000 3000 1800 0c00 0600 0c00 1800 3000 6000 0000 0000 0000 ENDCHAR STARTCHAR ? ENCODING 63 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 0c00 1800 1800 0000 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR @ ENCODING 64 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 de00 de00 de00 dc00 c000 7e00 0000 0000 0000 ENDCHAR STARTCHAR A ENCODING 65 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 c600 c600 c600 fe00 c600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR B ENCODING 66 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fc00 6600 6600 6600 7c00 6600 6600 6600 fc00 0000 0000 0000 ENDCHAR STARTCHAR C ENCODING 67 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 6600 c000 c000 c000 c000 c000 6600 3c00 0000 0000 0000 ENDCHAR STARTCHAR D ENCODING 68 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 f800 6c00 6600 6600 6600 6600 6600 6c00 f800 0000 0000 0000 ENDCHAR STARTCHAR E ENCODING 69 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 6600 6000 6000 7c00 6000 6000 6600 fe00 0000 0000 0000 ENDCHAR STARTCHAR F ENCODING 70 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 6600 6000 6000 7c00 6000 6000 6000 f000 0000 0000 0000 ENDCHAR STARTCHAR G ENCODING 71 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c000 c000 ce00 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR H ENCODING 72 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 c600 c600 fe00 c600 c600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR I ENCODING 73 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 1800 1800 1800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR J ENCODING 74 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 1800 1800 1800 1800 1800 d800 d800 7000 0000 0000 0000 ENDCHAR STARTCHAR K ENCODING 75 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 cc00 d800 f000 f000 d800 cc00 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR L ENCODING 76 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 f000 6000 6000 6000 6000 6000 6200 6600 fe00 0000 0000 0000 ENDCHAR STARTCHAR M ENCODING 77 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 ee00 fe00 d600 d600 d600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR N ENCODING 78 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 e600 e600 f600 de00 ce00 ce00 c600 0000 0000 0000 ENDCHAR STARTCHAR O ENCODING 79 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR P ENCODING 80 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fc00 6600 6600 6600 7c00 6000 6000 6000 f000 0000 0000 0000 ENDCHAR STARTCHAR Q ENCODING 81 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 c600 c600 c600 d600 7c00 0600 0000 0000 ENDCHAR STARTCHAR R ENCODING 82 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fc00 6600 6600 6600 7c00 7800 6c00 6600 e600 0000 0000 0000 ENDCHAR STARTCHAR S ENCODING 83 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c000 6000 3800 0c00 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR T ENCODING 84 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 5a00 1800 1800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR U ENCODING 85 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 c600 c600 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR V ENCODING 86 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 c600 c600 c600 c600 6c00 3800 1000 0000 0000 0000 ENDCHAR STARTCHAR W ENCODING 87 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 d600 d600 d600 fe00 ee00 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR X ENCODING 88 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 6c00 3800 3800 3800 6c00 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR Y ENCODING 89 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6600 6600 6600 6600 3c00 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR Z ENCODING 90 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c600 8c00 1800 3000 6000 c200 c600 fe00 0000 0000 0000 ENDCHAR STARTCHAR [ ENCODING 91 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 6000 6000 6000 6000 6000 6000 6000 7c00 0000 0000 0000 ENDCHAR STARTCHAR \ ENCODING 92 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 8000 c000 6000 3000 1800 0c00 0600 0200 0000 0000 0000 ENDCHAR STARTCHAR ] ENCODING 93 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7c00 0000 0000 0000 ENDCHAR STARTCHAR ^ ENCODING 94 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1000 3800 6c00 c600 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR _ ENCODING 95 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ff00 0000 ENDCHAR STARTCHAR ` ENCODING 96 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1800 1800 1800 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR a ENCODING 97 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR b ENCODING 98 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 6000 6000 7c00 6600 6600 6600 6600 fc00 0000 0000 0000 ENDCHAR STARTCHAR c ENCODING 99 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 c000 c000 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR d ENCODING 100 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1c00 0c00 0c00 7c00 cc00 cc00 cc00 cc00 7e00 0000 0000 0000 ENDCHAR STARTCHAR e ENCODING 101 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 fe00 c000 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR f ENCODING 102 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1c00 3600 3000 3000 fc00 3000 3000 3000 7800 0000 0000 0000 ENDCHAR STARTCHAR g ENCODING 103 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7600 ce00 c600 c600 7e00 0600 c600 7c00 0000 ENDCHAR STARTCHAR h ENCODING 104 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 6000 6000 6c00 7600 6600 6600 6600 e600 0000 0000 0000 ENDCHAR STARTCHAR i ENCODING 105 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 1800 0000 3800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR j ENCODING 106 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 0c00 0000 1c00 0c00 0c00 0c00 0c00 cc00 cc00 7800 0000 ENDCHAR STARTCHAR k ENCODING 107 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 6000 6000 6600 6c00 7800 6c00 6600 e600 0000 0000 0000 ENDCHAR STARTCHAR l ENCODING 108 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 1800 1800 1800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR m ENCODING 109 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 6c00 fe00 d600 d600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR n ENCODING 110 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 dc00 6600 6600 6600 6600 6600 0000 0000 0000 ENDCHAR STARTCHAR o ENCODING 111 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR p ENCODING 112 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 dc00 6600 6600 6600 7c00 6000 6000 f000 0000 ENDCHAR STARTCHAR q ENCODING 113 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7600 cc00 cc00 cc00 7c00 0c00 0c00 1e00 0000 ENDCHAR STARTCHAR r ENCODING 114 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 dc00 6600 6000 6000 6000 f000 0000 0000 0000 ENDCHAR STARTCHAR s ENCODING 115 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 7000 1c00 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR t ENCODING 116 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3000 3000 3000 fc00 3000 3000 3000 3600 1c00 0000 0000 0000 ENDCHAR STARTCHAR u ENCODING 117 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 cc00 cc00 cc00 cc00 cc00 7600 0000 0000 0000 ENDCHAR STARTCHAR v ENCODING 118 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 c600 c600 6c00 3800 1000 0000 0000 0000 ENDCHAR STARTCHAR w ENCODING 119 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 c600 d600 d600 fe00 6c00 0000 0000 0000 ENDCHAR STARTCHAR x ENCODING 120 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 6c00 3800 3800 6c00 c600 0000 0000 0000 ENDCHAR STARTCHAR y ENCODING 121 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 c600 c600 ce00 7600 0600 c600 7c00 0000 ENDCHAR STARTCHAR z ENCODING 122 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 8c00 1800 3000 6200 fe00 0000 0000 0000 ENDCHAR STARTCHAR { ENCODING 123 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0e00 1800 1800 1800 7000 1800 1800 1800 0e00 0000 0000 0000 ENDCHAR STARTCHAR | ENCODING 124 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 1800 1800 1800 0000 1800 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR } ENCODING 125 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7000 1800 1800 1800 0e00 1800 1800 1800 7000 0000 0000 0000 ENDCHAR STARTCHAR ~ ENCODING 126 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7600 dc00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C177 ENCODING 127 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1000 3800 3800 6c00 6c00 fe00 0000 0000 0000 0000 ENDCHAR STARTCHAR vwall ENCODING 128 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR hwall ENCODING 129 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 ff00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR tlcorn ENCODING 130 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR trcorn ENCODING 131 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 f800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR blcorn ENCODING 132 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1f00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR brcorn ENCODING 133 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 f800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR crwall ENCODING 134 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 ff00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR tuwall ENCODING 135 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 ff00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR tdwall ENCODING 136 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 ff00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR tlwall ENCODING 137 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 18 18 18 18 18 18 18 f8 18 18 18 18 18 18 ENDCHAR STARTCHAR trwall ENCODING 138 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 18 18 18 18 18 18 18 1f 18 18 18 18 18 18 ENDCHAR STARTCHAR ndoor ENCODING 139 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR vodoor ENCODING 140 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 0000 0000 0000 7e00 0000 0000 0000 1800 1800 1800 ENDCHAR STARTCHAR hodoor ENCODING 141 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 1800 1800 9900 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR vcdoor ENCODING 142 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 1800 7e00 7e00 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR hcdoor ENCODING 143 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 1800 7e00 7e00 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR room ENCODING 144 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR dark corr ENCODING 145 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1100 4400 1100 4400 1100 4400 1100 4400 1100 4400 1100 4400 1100 4400 ENDCHAR STARTCHAR lit corr ENCODING 146 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 5500 aa00 5500 aa00 5500 aa00 5500 aa00 5500 aa00 5500 aa00 5500 aa00 ENDCHAR STARTCHAR upstair ENCODING 147 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 c000 6000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR dnstair ENCODING 148 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6000 3000 1800 0c00 0600 0c00 1800 3000 6000 0000 0000 0000 ENDCHAR STARTCHAR trap ENCODING 149 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1000 3800 6c00 c600 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR web ENCODING 150 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0100 0f00 3c00 c600 c200 6f00 3a00 3200 7300 5700 8c00 db00 7f00 2500 ENDCHAR STARTCHAR pool ENCODING 151 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 7700 0000 ee00 bb00 0000 7700 dd00 0000 bb00 ee00 0000 dd00 7700 0000 ENDCHAR STARTCHAR fountain ENCODING 152 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1400 0000 3400 4a00 4900 8a00 2800 0200 5900 1800 3c00 3c00 ff00 ff00 ENDCHAR STARTCHAR sink ENCODING 153 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 2400 2400 7e00 2400 2400 7e00 2400 2400 0000 0000 0000 ENDCHAR STARTCHAR throne ENCODING 154 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0400 0400 0400 0400 3c00 1400 3c00 2400 2400 ff00 ff00 ENDCHAR STARTCHAR upladder ENCODING 155 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 c000 6000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR dnladder ENCODING 156 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6000 3000 1800 0c00 0600 0c00 1800 3000 6000 0000 0000 0000 ENDCHAR STARTCHAR dbvwall ENCODING 157 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 3c00 7e00 7e00 3c00 3c00 3c00 3c00 3c00 3c00 7e00 7e00 3c00 1800 ENDCHAR STARTCHAR dbhwall ENCODING 158 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 2400 7e00 ff00 7e00 2400 0000 0000 0000 0000 ENDCHAR STARTCHAR ice ENCODING 159 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 2400 1800 1800 2400 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR lava ENCODING 160 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0200 4000 2000 2000 0400 1000 9500 5500 5500 5e00 ff00 ff00 ENDCHAR STARTCHAR vbeam ENCODING 161 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1000 1c00 0800 1000 2000 4000 3000 1800 0400 0800 1000 2000 7000 1000 ENDCHAR STARTCHAR hbeam ENCODING 162 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 4000 6000 d100 0a00 0400 0000 0000 0000 0000 ENDCHAR STARTCHAR lslant ENCODING 163 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 8000 6000 2000 2000 2000 1000 1000 0800 0c00 0200 0200 0200 0200 0100 ENDCHAR STARTCHAR rslant ENCODING 164 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0100 0100 0200 0200 0400 0400 0400 1800 2000 2000 4000 4000 4000 8000 ENDCHAR STARTCHAR dig beam ENCODING 165 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 5500 0a00 1400 2800 5000 a000 4100 8200 0500 0a00 1400 2800 5000 aa00 ENDCHAR STARTCHAR camera flash ENCODING 166 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c800 4b00 0200 2000 0400 d800 1b00 2000 4400 5200 0a00 0000 ENDCHAR STARTCHAR boom open left ENCODING 167 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 2000 1000 0800 0400 0200 0400 0800 1000 2000 0000 0000 0000 ENDCHAR STARTCHAR boom open right ENCODING 168 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0200 0400 0800 1000 2000 1000 0800 0400 0200 0000 0000 0000 ENDCHAR STARTCHAR magic shield 1 ENCODING 169 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 5000 1200 4200 0800 1000 3a00 1000 4400 5000 2c00 0400 2800 ENDCHAR STARTCHAR magic shield 2 ENCODING 170 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 3600 a800 5a00 da00 8400 f400 d500 3a00 d700 a500 fd00 6f00 3800 3600 ENDCHAR STARTCHAR magic sheild 3 ENCODING 171 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1c00 4300 0000 0800 2200 0000 4000 0800 0200 9a00 cc00 2200 0000 ENDCHAR STARTCHAR magic shield 4 ENCODING 172 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 6000 1000 6c00 5200 4000 1b00 4600 6b00 cd00 a200 a800 5600 3400 0000 ENDCHAR STARTCHAR sw top left ENCODING 173 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0300 0400 0400 0800 0800 1000 1000 ENDCHAR STARTCHAR sw top center ENCODING 174 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 3c00 c300 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR sw top right ENCODING 175 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 c000 2000 2000 1000 1000 0800 0800 ENDCHAR STARTCHAR sw middle left ENCODING 176 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1000 1000 2000 2000 2000 2000 2000 4000 2000 2000 2000 2000 1000 1000 ENDCHAR STARTCHAR sw middle right ENCODING 177 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0800 0800 0400 0400 0400 0400 0400 0200 0400 0400 0400 0400 0800 0800 ENDCHAR STARTCHAR sw bottom left ENCODING 178 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1000 1000 0800 0800 0400 0400 0300 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR sw bottom center ENCODING 179 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 c300 3c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR sw bottom right ENCODING 180 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0800 0800 1000 1000 2000 2000 c000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR explosion1 ENCODING 181 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0100 0e00 3100 ce00 3100 4600 9800 6700 9800 2300 4c00 9300 2400 ENDCHAR STARTCHAR explosion2 ENCODING 182 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 ff00 0000 ff00 0000 ff00 0000 fe00 0100 fe00 0100 fe00 0100 7c00 ENDCHAR STARTCHAR explosion3 ENCODING 183 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 1800 e600 1900 c400 3300 cd00 3200 8900 6400 9200 4900 ENDCHAR STARTCHAR explosion4 ENCODING 184 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 4900 5600 a500 aa00 4a00 5500 5500 5500 5500 5500 4a00 aa00 a500 5600 ENDCHAR STARTCHAR explosion5 ENCODING 185 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 8300 7c00 8300 7c00 8200 3900 4500 5500 4500 3900 8200 7c00 8300 7c00 ENDCHAR STARTCHAR explosion6 ENCODING 186 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2500 d400 4a00 aa00 a500 5500 5500 5500 5500 5500 a500 aa00 4a00 d400 ENDCHAR STARTCHAR explosion7 ENCODING 187 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 4900 2400 9300 4c00 2300 9800 6700 b800 4e00 3100 ce00 3100 0e00 0100 ENDCHAR STARTCHAR explosion8 ENCODING 188 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 8300 7c00 0100 fe00 0100 fe00 0100 fe00 0000 ff00 0000 ff00 0000 ff00 ENDCHAR STARTCHAR explosion9 ENCODING 189 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2500 4900 9200 6400 8900 3200 cc00 3b00 e400 1900 e600 1800 e000 0000 ENDCHAR STARTCHAR C276 ENCODING 190 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 f800 1800 f800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C203 ENCODING 191 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3000 7800 cc00 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR C204 ENCODING 192 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 cc00 cc00 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR C207 ENCODING 193 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 7c00 c600 c000 c000 c600 7c00 1800 6c00 3800 0000 ENDCHAR STARTCHAR C210 ENCODING 194 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3000 7800 cc00 0000 7c00 c600 fe00 c000 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR C303 ENCODING 195 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1f00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR C201 ENCODING 196 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 0000 c600 c600 c600 c600 ce00 7600 0000 0000 0000 ENDCHAR STARTCHAR C206 ENCODING 197 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3800 6c00 3800 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR C200 ENCODING 198 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 6600 c000 c000 c000 c600 6600 3c00 1800 cc00 3800 0000 ENDCHAR STARTCHAR C264 ENCODING 199 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 f800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR C333 ENCODING 200 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C334 ENCODING 201 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C335 ENCODING 202 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 ENDCHAR STARTCHAR C336 ENCODING 203 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 ENDCHAR STARTCHAR C337 ENCODING 204 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 ff00 ff00 ff00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C272 ENCODING 205 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 ENDCHAR STARTCHAR C273 ENCODING 206 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 0600 f600 3600 3600 3600 3600 3600 3600 ENDCHAR STARTCHAR C236 ENCODING 207 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 fc00 c600 fc00 c000 cc00 de00 cc00 cc00 cc00 c600 0000 0000 0000 ENDCHAR STARTCHAR amulet ENCODING 208 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3c00 4200 4200 4200 2200 2200 1c00 3e00 3e00 3e00 1c00 0000 0000 ENDCHAR STARTCHAR food ENCODING 209 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 7c00 7c00 3800 1000 1000 1000 7c00 0000 ENDCHAR STARTCHAR weapon ENCODING 210 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2000 3000 2800 2800 2800 2800 2800 2800 3800 fe00 3000 3000 3000 3000 ENDCHAR STARTCHAR tool ENCODING 211 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 3c00 4200 4200 7e00 7e00 7e00 7e00 0000 0000 ENDCHAR STARTCHAR ball ENCODING 212 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1c00 3e00 3e00 7e00 ad00 7600 ENDCHAR STARTCHAR chain ENCODING 213 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6600 9900 6600 ENDCHAR STARTCHAR rock ENCODING 214 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3c00 6600 5200 8500 d200 a900 a000 4500 9300 bf00 6a00 fe00 7f00 ENDCHAR STARTCHAR armor ENCODING 215 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 6c00 5400 6c00 5400 2800 1000 0000 0000 ENDCHAR STARTCHAR potion ENCODING 216 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 1800 1800 1800 1800 3c00 6e00 7a00 5e00 7600 3c00 0000 ENDCHAR STARTCHAR scroll ENCODING 217 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 ff00 7e00 2a00 5400 2a00 5400 2a00 7e00 ff00 7e00 0000 ENDCHAR STARTCHAR wand ENCODING 218 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2200 2400 1500 0200 0800 0800 1000 1000 1000 2000 2000 2000 4000 0000 ENDCHAR STARTCHAR ring ENCODING 219 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 4200 2400 8300 3800 4500 4400 4400 3900 8200 2900 4800 0000 0000 ENDCHAR STARTCHAR gem ENCODING 220 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 7c00 c600 4400 3800 1000 0000 ENDCHAR STARTCHAR gold ENCODING 221 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 5400 5400 a500 a900 8a00 0000 6000 be00 fb00 df00 3800 ENDCHAR STARTCHAR venom ENCODING 222 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 2400 4400 5800 2000 0000 0000 0000 ENDCHAR STARTCHAR spbook ENCODING 223 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 7c00 4600 6600 4600 4600 4600 6600 4600 7e00 7e00 0000 ENDCHAR STARTCHAR C262 ENCODING 224 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP dd00 7700 dd00 7700 dd00 7700 dd00 7700 dd00 7700 dd00 7700 dd00 7700 ENDCHAR STARTCHAR C341 ENCODING 225 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 7800 cc00 d800 fc00 c600 e600 dc00 c000 c000 0000 ENDCHAR STARTCHAR C342 ENCODING 226 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 6600 6200 6000 6000 6000 6000 6000 6000 0000 0000 0000 ENDCHAR STARTCHAR C343 ENCODING 227 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 6c00 6c00 6c00 6c00 6c00 0000 0000 0000 ENDCHAR STARTCHAR C344 ENCODING 228 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c600 6200 3000 1800 3000 6200 c600 fe00 0000 0000 0000 ENDCHAR STARTCHAR C345 ENCODING 229 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7e00 d800 cc00 cc00 cc00 7800 0000 0000 0000 ENDCHAR STARTCHAR C346 ENCODING 230 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 6600 6600 6600 6600 7c00 6000 c000 8000 0000 0000 ENDCHAR STARTCHAR C347 ENCODING 231 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7600 dc00 1800 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR C350 ENCODING 232 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 3800 6c00 c600 c600 c600 6c00 3800 fe00 0000 0000 0000 ENDCHAR STARTCHAR C351 ENCODING 233 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 c600 c600 fe00 c600 c600 6c00 3800 0000 0000 0000 ENDCHAR STARTCHAR C352 ENCODING 234 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 c600 c600 c600 6c00 6c00 6c00 ee00 0000 0000 0000 ENDCHAR STARTCHAR C353 ENCODING 235 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3e00 6000 3000 3c00 6600 c600 c600 cc00 7800 0000 0000 0000 ENDCHAR STARTCHAR C354 ENCODING 236 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7e00 db00 db00 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C355 ENCODING 237 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0600 0c00 7c00 de00 f600 e600 7c00 6000 c000 0000 0000 0000 ENDCHAR STARTCHAR C356 ENCODING 238 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1c00 3000 6000 6000 7c00 6000 6000 3000 1c00 0000 0000 0000 ENDCHAR STARTCHAR C357 ENCODING 239 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 c600 c600 c600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR C360 ENCODING 240 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 0000 fe00 0000 fe00 0000 0000 0000 0000 ENDCHAR STARTCHAR C361 ENCODING 241 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1800 1800 7e00 1800 1800 0000 7e00 0000 0000 0000 ENDCHAR STARTCHAR C362 ENCODING 242 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3000 1800 0c00 0600 0c00 1800 3000 0000 7e00 0000 0000 0000 ENDCHAR STARTCHAR C363 ENCODING 243 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 3000 1800 0c00 0000 7e00 0000 0000 0000 ENDCHAR STARTCHAR C364 ENCODING 244 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0c00 1e00 1a00 1800 1800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR C365 ENCODING 245 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1800 1800 5800 7800 3000 0000 0000 ENDCHAR STARTCHAR C366 ENCODING 246 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 0000 7e00 0000 1800 1800 0000 0000 0000 0000 ENDCHAR STARTCHAR C225 ENCODING 247 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3000 1800 0c00 0000 7c00 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR C370 ENCODING 248 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7800 cc00 cc00 7800 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C371 ENCODING 249 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C372 ENCODING 250 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C373 ENCODING 251 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1f00 1800 1800 1800 1800 d800 7800 3800 1800 0000 0000 ENDCHAR STARTCHAR C374 ENCODING 252 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 d800 6c00 6c00 6c00 6c00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C375 ENCODING 253 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 7000 d800 3000 6000 f800 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C376 ENCODING 254 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 7e00 7e00 7e00 7e00 7e00 7e00 0000 0000 0000 0000 ENDCHAR STARTCHAR C377 ENCODING 255 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR ENDFONT nethack-3.6.0/win/X11/nethack.rc0000664000076400007660000000505012536476415015263 0ustar paxedpaxed# # Nethack configuration file. # $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # # Naming this file $(HOME)/.nethackrc (for UNIX) or setting the environment # variable NETHACKOPTIONS to point to its full path name elsewhere tells # NetHack to use X11 windowing and fonts (provided the executable was # compiled with that ability). # # OPTIONS=windowtype:x11,toptenwin,hilite_pet OPTIONS=confirm,male,fixinv,noautopickup,safe_pet,sortpack,tombstone OPTIONS=verbose,news,fruit:pineapple OPTIONS=dogname:Dhairrhuwyth OPTIONS=catname:Ghisteslwchlohm # # The graphics symbols mappings below are for NetHack 3.4. NetHack 3.6 # uses a new scheme, but this file has not been updated. # # There are 17 object symbols and various graphics symbols. # The descriptions of these symbols can be found in dat/opthelp. # # # Font: nh10 (10x20) # #OBJECTS= 180 183 188 192 181 184 182 189 190 196 \ # 191 194 193 187 185 186 195 # #DUNGEON= 032 025 018 013 012 014 011 015 023 024 \ # 022 021 128 129 130 131 132 035 035 133 \ # 134 135 136 137 145 146 144 124 143 142 \ # 141 140 149 150 031 031 147 148 031 161 \ # 140 # #TRAPS= 138 138 138 138 138 138 138 138 138 138 \ # 138 138 138 138 138 139 138 138 138 138 \ # 138 138 # #EFFECTS= 151 152 153 154 155 156 157 158 \ # 159 160 161 162 \ # 163 164 165 166 167 168 169 170 \ # 171 172 173 174 175 176 177 178 179 # # # Font: ibm (8x14) # #OBJECTS= 207 210 215 219 208 211 209 216 217 223 \ # 218 221 220 214 212 213 222 # #DUNGEON= 032 128 129 130 131 132 133 134 135 136 \ # 137 138 139 045 124 142 143 035 035 144 \ # 145 146 147 148 155 156 227 124 154 153 \ # 152 151 159 160 200 200 157 158 250 170 \ # 151 # #TRAPS= 149 149 149 149 149 149 149 149 149 149 \ # 149 149 149 149 149 150 149 149 149 149 \ # 149 149 # #EFFECTS= 161 162 163 164 165 166 167 168 \ # 169 170 171 172 \ # 173 174 175 176 177 178 179 180 \ # 181 182 183 184 185 186 187 188 189 # # # Font: a "standard" font like 6x13 # Note that this version is unlikely to work on a tty on a Unix system because # many of these characters are also control characters. # #DUNGEON = 032 025 018 013 012 014 011 015 023 024 \ # 022 021 031 045 124 043 043 035 035 031 \ # 035 001 060 062 060 062 019 124 092 035 \ # 123 125 031 125 046 046 035 035 046 127 \ # 125 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 002 094 094 094 094 \ # 094 094 # #EFFECTS= 124 045 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 124 124 092 045 047 \ # 047 064 092 064 064 064 092 064 047 nethack-3.6.0/win/X11/nh10.bdf0000664000076400007660000013461112467321052014536 0ustar paxedpaxedSTARTFONT 2.1 COMMENT Nethack 10x20 font. Based on the font 10x20. FONT nh10 SIZE 20 75 75 FONTBOUNDINGBOX 10 20 0 -5 STARTPROPERTIES 19 FONTNAME_REGISTRY "" FOUNDRY "Misc" FAMILY_NAME "Fixed" WEIGHT_NAME "Medium" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "NetHack" PIXEL_SIZE 20 POINT_SIZE 200 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 100 CHARSET_REGISTRY "ISO8859" CHARSET_ENCODING "1" DEFAULT_CHAR 0 FONT_DESCENT 5 FONT_ASCENT 15 COPYRIGHT "Copyright 1989-1991 Network Computing Devices, Inc." ENDPROPERTIES CHARS 256 STARTCHAR C000 ENCODING 0 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C001 ENCODING 1 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0c00 1e00 3f00 7f80 7f80 3f00 1e00 0c00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C002 ENCODING 2 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 ENDCHAR STARTCHAR C003 ENCODING 3 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 6600 6600 6600 7e00 6600 6600 6600 0000 1f80 0600 0600 0600 0600 0600 0000 0000 ENDCHAR STARTCHAR C004 ENCODING 4 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 7c00 6000 6000 7800 6000 6000 6000 0f80 0c00 0c00 0f00 0c00 0c00 0c00 0000 0000 ENDCHAR STARTCHAR C005 ENCODING 5 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 3c00 6600 6000 6000 6600 3c00 0000 1f00 1980 1980 1f00 1e00 1b00 1980 0000 0000 ENDCHAR STARTCHAR C006 ENCODING 6 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 3000 3000 3000 3000 3000 3e00 0000 0f80 0c00 0c00 0f00 0c00 0c00 0c00 0000 0000 ENDCHAR STARTCHAR C007 ENCODING 7 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 3300 3300 1e00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C010 ENCODING 8 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 7f80 0c00 0c00 0000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C011 ENCODING 9 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 6600 7600 7e00 7e00 6e00 6600 0000 0c00 0c00 0c00 0c00 0c00 0c00 0f80 0000 0000 ENDCHAR STARTCHAR C012 ENCODING 10 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 6600 6600 6600 3c00 3c00 1800 1800 0000 1f80 0600 0600 0600 0600 0600 0000 0000 ENDCHAR STARTCHAR C013 ENCODING 11 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 fc00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C014 ENCODING 12 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 fc00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C015 ENCODING 13 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0fc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C016 ENCODING 14 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0fc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C017 ENCODING 15 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ffc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C020 ENCODING 16 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C021 ENCODING 17 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C022 ENCODING 18 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C023 ENCODING 19 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C024 ENCODING 20 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 ENDCHAR STARTCHAR C025 ENCODING 21 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0fc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C026 ENCODING 22 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 fc00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C027 ENCODING 23 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C030 ENCODING 24 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C031 ENCODING 25 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C032 ENCODING 26 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 01c0 0700 1c00 7000 1c00 0700 01c0 0000 0000 7fc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C033 ENCODING 27 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 7000 1c00 0700 01c0 0700 1c00 7000 0000 0000 7fc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C034 ENCODING 28 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0080 3f80 5b00 1b00 1b00 1b00 1b00 3300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C035 ENCODING 29 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0180 0300 7fc0 0600 0c00 7fc0 1800 3000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C036 ENCODING 30 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f00 1980 1980 1800 1800 1800 7e00 1800 1800 1800 7c00 56c0 7380 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C037 ENCODING 31 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR space ENCODING 32 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ! ENCODING 33 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR " ENCODING 34 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 3300 1200 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR # ENCODING 35 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0d80 0d80 0d80 3fc0 1b00 1b00 1b00 7f80 3600 3600 3600 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR $ ENCODING 36 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 3f00 6d80 6c00 6c00 6c00 3f00 0d80 0d80 0d80 6d80 3f00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR % ENCODING 37 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 3980 6d80 6f00 3b00 0600 0600 0c00 0c00 1b80 1ec0 36c0 3380 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR & ENCODING 38 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1c00 3600 3600 3600 3c00 1800 3800 6c00 66c0 6380 6300 7780 3cc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ' ENCODING 39 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f00 0e00 1800 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ( ENCODING 40 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0c00 1800 1800 1800 1800 1800 0c00 0c00 0600 0300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ) ENCODING 41 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0c00 0600 0600 0600 0600 0600 0c00 0c00 1800 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR * ENCODING 42 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3300 3300 1e00 7f80 1e00 3300 3300 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR + ENCODING 43 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0c00 0c00 0c00 7f80 0c00 0c00 0c00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR , ENCODING 44 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0e00 0e00 1800 0000 0000 0000 0000 ENDCHAR STARTCHAR - ENCODING 45 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 7f80 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR . ENCODING 46 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0e00 0e00 0e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR / ENCODING 47 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0180 0180 0300 0300 0600 0600 0c00 0c00 1800 1800 3000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 0 ENCODING 48 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 3300 6180 6180 6180 6180 6180 3300 3300 1e00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 1 ENCODING 49 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1c00 3c00 6c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 2 ENCODING 50 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 0180 0180 0300 0e00 1800 3000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 3 ENCODING 51 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 0180 0300 0e00 0300 0180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 4 ENCODING 52 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0100 0300 0700 0f00 1b00 3300 6300 6300 7f80 0300 0300 0300 0300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 5 ENCODING 53 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 6000 6000 6000 6000 6e00 7300 0180 0180 0180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 6 ENCODING 54 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6100 6000 6000 6e00 7300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 7 ENCODING 55 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0180 0180 0300 0300 0600 0600 0c00 0c00 1800 1800 3000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 8 ENCODING 56 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 3300 1e00 3300 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 9 ENCODING 57 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 6180 3380 1d80 0180 0180 2180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR : ENCODING 58 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0e00 0e00 0000 0000 0000 0000 0e00 0e00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ; ENCODING 59 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0e00 0e00 0000 0000 0000 0000 0e00 0e00 1c00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR < ENCODING 60 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0100 0300 0600 0c00 1800 3000 6000 3000 1800 0c00 0600 0300 0100 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR = ENCODING 61 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 7f80 0000 0000 0000 0000 7f80 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR > ENCODING 62 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 2000 3000 1800 0c00 0600 0300 0180 0300 0600 0c00 1800 3000 2000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ? ENCODING 63 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 0300 0600 0c00 0c00 0c00 0000 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR @ ENCODING 64 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6780 6f80 6d80 6d80 6d80 6f00 6600 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR A ENCODING 65 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 3300 6180 6180 6180 7f80 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR B ENCODING 66 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7c00 6600 6300 6300 6300 6600 7e00 6300 6180 6180 6180 6300 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C ENCODING 67 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 6000 6000 6000 6000 6000 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR D ENCODING 68 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 6180 6180 6180 6180 6180 6300 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR E ENCODING 69 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 6000 6000 6000 6000 6000 7e00 6000 6000 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR F ENCODING 70 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 6000 6000 6000 6000 6000 7e00 6000 6000 6000 6000 6000 6000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR G ENCODING 71 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 6000 6780 6180 6180 6180 6180 3380 1e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR H ENCODING 72 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 6180 6180 7f80 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR I ENCODING 73 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR J ENCODING 74 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f80 0180 0180 0180 0180 0180 0180 0180 0180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR K ENCODING 75 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6300 6300 6600 6600 7c00 6600 6600 6300 6300 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR L ENCODING 76 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6000 6000 6000 6000 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR M ENCODING 77 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 7380 7380 7f80 6d80 6d80 6d80 6d80 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR N ENCODING 78 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 7180 7180 7980 7980 6d80 6d80 6780 6780 6380 6380 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR O ENCODING 79 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR P ENCODING 80 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 6300 7e00 6000 6000 6000 6000 6000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Q ENCODING 81 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 6180 6180 6180 6180 6d80 6780 3300 1f00 0180 0000 0000 0000 0000 ENDCHAR STARTCHAR R ENCODING 82 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 6300 7e00 6600 6300 6300 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR S ENCODING 83 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 3000 1e00 0300 0180 0180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR T ENCODING 84 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR U ENCODING 85 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR V ENCODING 86 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 3300 3300 3300 1e00 1e00 1e00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR W ENCODING 87 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 6180 6d80 6d80 6d80 6d80 7380 7380 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR X ENCODING 88 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 3300 3300 1e00 1e00 0c00 1e00 1e00 3300 3300 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Y ENCODING 89 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 3300 3300 1e00 1e00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Z ENCODING 90 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0180 0180 0300 0600 0600 0c00 1800 1800 3000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR [ ENCODING 91 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3f00 3000 3000 3000 3000 3000 3000 3000 3000 3000 3000 3000 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR \ ENCODING 92 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 3000 3000 1800 1800 0c00 0c00 0600 0600 0300 0300 0180 0180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ] ENCODING 93 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3f00 0300 0300 0300 0300 0300 0300 0300 0300 0300 0300 0300 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ^ ENCODING 94 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 6180 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR _ ENCODING 95 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 7fc0 0000 0000 0000 0000 ENDCHAR STARTCHAR ` ENCODING 96 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3c00 1c00 0600 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR a ENCODING 97 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 3180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR b ENCODING 98 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6e00 7300 6180 6180 6180 6180 7300 6e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR c ENCODING 99 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 3180 6000 6000 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR d ENCODING 100 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0180 0180 0180 0180 0180 1d80 3380 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR e ENCODING 101 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR f ENCODING 102 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f00 1980 1980 1800 1800 1800 1800 7e00 1800 1800 1800 1800 1800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR g ENCODING 103 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3e80 6380 6300 6300 6300 3e00 6000 3f00 6180 6180 6180 3f00 0000 ENDCHAR STARTCHAR h ENCODING 104 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6e00 7300 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR i ENCODING 105 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR j ENCODING 106 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0180 0180 0000 0780 0180 0180 0180 0180 0180 0180 0180 3180 3180 3180 1f00 0000 ENDCHAR STARTCHAR k ENCODING 107 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6300 6600 6c00 7800 7c00 6600 6300 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR l ENCODING 108 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR m ENCODING 109 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 5b00 7f80 6d80 6d80 6d80 6d80 6d80 6d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR n ENCODING 110 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6e00 7300 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR o ENCODING 111 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR p ENCODING 112 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6e00 7300 6180 6180 6180 6180 7300 6e00 6000 6000 6000 6000 0000 ENDCHAR STARTCHAR q ENCODING 113 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1d80 3380 6180 6180 6180 6180 3380 1d80 0180 0180 0180 0180 0000 ENDCHAR STARTCHAR r ENCODING 114 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6f00 3980 3000 3000 3000 3000 3000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR s ENCODING 115 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3f00 6180 6000 3f00 0180 0180 6180 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR t ENCODING 116 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 1800 1800 1800 7e00 1800 1800 1800 1800 1800 1980 0f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR u ENCODING 117 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR v ENCODING 118 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 3300 3300 1e00 1e00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR w ENCODING 119 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 6180 6d80 6d80 6d80 7f80 3300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR x ENCODING 120 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 3300 1e00 0c00 0c00 1e00 3300 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR y ENCODING 121 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0180 6180 3300 1e00 0000 ENDCHAR STARTCHAR z ENCODING 122 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3f80 0180 0300 0600 0c00 1800 3000 3f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR { ENCODING 123 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0780 0c00 0c00 0c00 0c00 0c00 7800 0c00 0c00 0c00 0c00 0c00 0780 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR bar ENCODING 124 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR } ENCODING 125 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7800 0c00 0c00 0c00 0c00 0c00 0780 0c00 0c00 0c00 0c00 0c00 7800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ~ ENCODING 126 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3980 6d80 6700 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C177 ENCODING 127 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR doorway ENCODING 128 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1e00 1200 1200 1e00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR vodoor ENCODING 129 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 7f80 7f80 0000 0000 0000 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR codoor ENCODING 130 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0c00 0c00 0c00 8c40 8c40 0c00 0c00 0c00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR vcdoor ENCODING 131 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 3300 2100 2100 2100 2100 2100 2100 3300 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR hcdoor ENCODING 132 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 7f80 4080 8040 8040 4080 7f80 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR room ENCODING 133 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR dark corridor ENCODING 134 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 ENDCHAR STARTCHAR lit corridor ENCODING 135 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 ENDCHAR STARTCHAR upstair ENCODING 136 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0100 0200 0400 0800 1000 2000 1000 0800 0400 0200 0100 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR dnstair ENCODING 137 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 2000 1000 0800 0400 0200 0100 0200 0400 0800 1000 2000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR trap ENCODING 138 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 ffc0 c0c0 e1c0 b340 9e40 8c40 9e40 b340 e1c0 c0c0 ffc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR web ENCODING 139 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4980 f900 4f00 c9c0 9940 9300 f240 9e40 9340 32c0 a640 fcc0 2f80 2580 e4c0 ec80 7f80 4bc0 4940 c900 ENDCHAR STARTCHAR pool ENCODING 140 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP b6c0 0000 2480 db40 0000 9240 6d80 0000 4900 b6c0 0000 2480 db40 0000 9240 6d80 0000 4900 b6c0 0000 ENDCHAR STARTCHAR fountain ENCODING 141 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 1000 0a00 4200 0c00 3000 0280 6800 0100 4800 2900 4800 0900 9c00 1400 ff80 ff80 ff80 ENDCHAR STARTCHAR sink ENCODING 142 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2100 2100 2100 2100 1e00 1e00 1200 ENDCHAR STARTCHAR throne ENCODING 143 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0100 0100 0100 0100 0100 1f00 0900 0900 3f00 2100 2100 ffc0 ENDCHAR STARTCHAR altar ENCODING 144 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 7f80 7f80 3300 3300 3300 3300 ENDCHAR STARTCHAR up ladder ENCODING 145 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 9000 f000 9000 9000 f000 9100 9380 f540 9100 9100 f100 9100 9100 f000 9000 9000 f000 9000 9000 f000 ENDCHAR STARTCHAR down ladder ENCODING 146 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 9000 f000 9000 9000 f000 9100 9100 f100 9100 9100 f540 9380 9100 f000 9000 9000 f000 9000 9000 f000 ENDCHAR STARTCHAR dbvwall ENCODING 147 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR dbhwall ENCODING 148 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3f00 3f00 ffc0 ffc0 3f00 3f00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ice ENCODING 149 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1200 0c00 0c00 1200 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR lava ENCODING 150 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 8800 0480 0080 3700 1300 9900 0940 4140 0840 2900 8900 a840 4540 ffc0 ffc0 ffc0 ENDCHAR STARTCHAR vbeam ENCODING 151 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 0800 0e00 0400 0800 1000 2000 1000 0800 0800 0800 0800 0400 0200 0400 0800 1000 3000 0800 0800 ENDCHAR STARTCHAR hbeam ENCODING 152 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 2000 3000 e8c0 0500 0200 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR lslant ENCODING 153 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 8000 4000 4000 4000 3000 0800 0800 0800 0800 0800 0800 0400 0400 0200 0200 0200 0200 0200 0180 0040 ENDCHAR STARTCHAR rslant ENCODING 154 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0040 0080 0080 0080 0080 0080 0300 0400 0400 0400 0800 0800 1000 2000 4000 4000 4000 4000 4000 8000 ENDCHAR STARTCHAR dig beam ENCODING 155 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 8040 4080 2100 1200 0c00 0c00 1200 2100 4080 8040 8040 4080 2100 1200 0c00 0c00 1200 2100 4080 8040 ENDCHAR STARTCHAR camera flash ENCODING 156 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4200 0600 6400 0100 0940 4840 0400 2100 1e00 5ec0 1e80 1e00 2500 5440 2000 0d80 2840 c000 9280 0040 ENDCHAR STARTCHAR boomerang left ENCODING 157 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3000 2800 1400 0a00 0500 0300 0500 0a00 1400 2800 3000 0000 0000 0000 0000 ENDCHAR STARTCHAR boomerang right ENCODING 158 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0300 0500 0a00 1400 2800 3000 2800 1400 0a00 0500 0300 0000 0000 0000 0000 ENDCHAR STARTCHAR shield 1 ENCODING 159 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0200 76c0 fa40 8a00 4680 f900 ea00 e7c0 ddc0 5480 3100 b300 e8c0 4cc0 6c00 6300 4480 a180 1400 0780 ENDCHAR STARTCHAR shield 2 ENCODING 160 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 6100 b340 0040 08c0 77c0 d240 b980 8380 a100 2700 4c40 31c0 bf40 c200 ca00 3380 4180 1b80 0780 ENDCHAR STARTCHAR shield 3 ENCODING 161 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP d000 0600 5e80 4e80 4c80 2000 2800 3e80 5f80 e640 5080 47c0 8380 c880 a940 9840 0dc0 1300 6080 3200 ENDCHAR STARTCHAR shield 4 ENCODING 162 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4200 d480 95c0 1c40 3c80 9b80 2d80 5280 5900 5400 6500 0680 2780 9c80 af80 2180 6080 2340 4580 3100 ENDCHAR STARTCHAR swallow top left ENCODING 163 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00c0 0100 0100 0100 0200 0200 0200 0400 0400 0400 ENDCHAR STARTCHAR swallow top center ENCODING 164 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1e00 6180 8040 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR swallow top right ENCODING 165 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 c000 2000 2000 2000 1000 1000 1000 0800 0800 0800 ENDCHAR STARTCHAR swallow mid left ENCODING 166 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0400 0400 0400 0800 0800 0800 1000 1000 1000 1000 1000 1000 1000 1000 0800 0800 0800 0400 0400 0400 ENDCHAR STARTCHAR swallow mid right ENCODING 167 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 0800 0800 0400 0400 0400 0200 0200 0200 0200 0200 0200 0200 0200 0400 0400 0400 0800 0800 0800 ENDCHAR STARTCHAR swallow bot left ENCODING 168 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0400 0400 0400 0200 0200 0200 0100 0100 0100 00c0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR swallow bot center ENCODING 169 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 8040 6180 1e00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR swallow bot right ENCODING 170 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 0800 0800 1000 1000 1000 2000 2000 2000 c000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR explosion 1 ENCODING 171 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 01c0 0e00 31c0 ce00 31c0 c600 18c0 6700 98c0 2300 ccc0 3300 4c40 9380 2440 4980 b640 2880 5300 ENDCHAR STARTCHAR explosion 2 ENCODING 172 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f780 ENDCHAR STARTCHAR explosion 3 ENCODING 173 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 c000 3800 c600 3980 c640 3180 8c40 7300 8cc0 6200 9980 6640 1900 e480 1240 c900 3680 8a40 6500 ENDCHAR STARTCHAR explosion 4 ENCODING 174 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP a4c0 2900 4a40 5480 a500 aa40 aa80 aa80 aa80 5540 aa80 aa80 aa80 aa40 a500 5480 4a40 2900 a4c0 5300 ENDCHAR STARTCHAR explosion 5 ENCODING 175 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0840 f780 0840 7700 8880 7740 8880 b680 aa80 5540 aa80 b680 8880 7740 8880 7700 0840 f780 0840 f780 ENDCHAR STARTCHAR explosion 6 ENCODING 176 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 9280 4a40 2940 9540 5280 2a80 aa80 aa80 aa80 5540 aa80 aa80 aa80 2a80 5280 9540 2940 4a40 9280 6500 ENDCHAR STARTCHAR explosion 7 ENCODING 177 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 2880 b640 4980 2440 9380 4c40 3300 ccc0 2300 98c0 6700 18c0 c600 31c0 ce00 31c0 0e00 01c0 0000 0000 ENDCHAR STARTCHAR explosion 8 ENCODING 178 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 0000 ENDCHAR STARTCHAR explosion 9 ENCODING 179 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 8a40 3680 c900 1240 e480 1900 6640 9980 6200 8cc0 7300 8c40 3180 c640 3980 c600 3800 c000 0000 0000 ENDCHAR STARTCHAR illegal object ENCODING 180 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 3b80 4640 4440 4c40 3b80 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR amulet ENCODING 181 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 1e00 2100 2100 2100 1100 1100 0e00 1f00 1f00 0e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR food ENCODING 182 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 3f00 3f00 3f00 1e00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 ENDCHAR STARTCHAR weapon ENCODING 183 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1000 1800 1400 1200 1200 1200 1200 1200 1200 1200 7f80 1c00 1c00 1c00 1c00 1c00 0000 0000 ENDCHAR STARTCHAR tool ENCODING 184 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1e00 2100 2100 3f00 3f00 3f00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ball ENCODING 185 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0e00 1f00 1f00 1f00 eac0 5780 ENDCHAR STARTCHAR chain ENCODING 186 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6d80 9240 6d80 ENDCHAR STARTCHAR rock ENCODING 187 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e00 3100 2900 4280 6900 5480 5000 2280 4980 5f80 3500 ff40 bfc0 ENDCHAR STARTCHAR armor ENCODING 188 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 2e80 3f80 2a80 3580 2a80 3580 2a80 1500 0a00 0400 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR potion ENCODING 189 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 1e00 0c00 0c00 0c00 0c00 1e00 3700 3d00 2f00 3b00 1e00 0000 0000 0000 ENDCHAR STARTCHAR scroll ENCODING 190 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3f00 7f80 3f00 2a00 1500 2a00 1500 2a00 3f00 7f80 3f00 0000 0000 0000 0000 ENDCHAR STARTCHAR wand ENCODING 191 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1100 1500 1240 0a80 0100 0400 0400 0800 0800 0800 1000 1000 1000 2000 0000 0000 0000 0000 ENDCHAR STARTCHAR ring ENCODING 192 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 2900 1200 4180 1c00 2280 2200 2200 1c80 4100 1480 2400 0000 0000 0000 0000 ENDCHAR STARTCHAR gem ENCODING 193 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 3e00 6300 2200 1c00 0800 0000 0000 ENDCHAR STARTCHAR gold ENCODING 194 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 2a00 2a00 5280 5480 4500 0000 3000 5f00 7d80 6f80 1c00 ENDCHAR STARTCHAR venom ENCODING 195 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0c00 1200 2200 2c00 1000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR spbook ENCODING 196 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3e00 2300 3300 2300 2300 2300 3300 2300 3f00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Aring ENCODING 197 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1200 1200 0c00 0c00 1e00 3300 6180 6180 7f80 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR AE ENCODING 198 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f80 1e00 3600 3600 6600 6600 7f80 6600 6600 6600 6600 6600 6780 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ccedilla ENCODING 199 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 6000 6000 6000 6000 6000 6180 3300 1e00 0c00 0400 1200 0c00 0000 ENDCHAR STARTCHAR Egrave ENCODING 200 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Eacute ENCODING 201 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ecircumflex ENCODING 202 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Edieresis ENCODING 203 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Igrave ENCODING 204 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Iacute ENCODING 205 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Icircumflex ENCODING 206 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Idieresis ENCODING 207 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Eth ENCODING 208 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 f980 6180 6180 6180 6180 6300 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ntilde ENCODING 209 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 4180 6180 7180 7980 7d80 6f80 6780 6380 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ograve ENCODING 210 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Oacute ENCODING 211 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ocircumflex ENCODING 212 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Otilde ENCODING 213 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Odieresis ENCODING 214 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR multiply ENCODING 215 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 2080 3180 1b00 0e00 0e00 1b00 3180 2080 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Oslash ENCODING 216 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0080 1f80 3300 6380 6580 6580 6980 6980 7180 3300 7e00 4000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ugrave ENCODING 217 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Uacute ENCODING 218 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0000 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ucircumflex ENCODING 219 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 6180 6180 6180 6180 6180 6180 6180 3380 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Udieresis ENCODING 220 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Yacute ENCODING 221 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0000 4080 6180 3300 1e00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Thorn ENCODING 222 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 3c00 1800 1f00 1980 1980 1980 1f00 1800 1800 1800 3c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR germandbls ENCODING 223 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 1c00 3e00 7300 6300 6300 6600 6c00 6600 6300 6100 6300 6e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR agave ENCODING 224 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR aacute ENCODING 225 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR acircumflex ENCODING 226 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR atilde ENCODING 227 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR adieresis ENCODING 228 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR aring ENCODING 229 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0c00 1200 1200 0c00 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ae ENCODING 230 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3b00 4d80 0d80 0f00 3c00 6c00 6c80 3700 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ccedilla ENCODING 231 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 3180 6000 6000 6000 6000 3180 1f00 0c00 0400 1200 0c00 0000 ENDCHAR STARTCHAR egrave ENCODING 232 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR eacute ENCODING 233 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ecircumflex ENCODING 234 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR edieresis ENCODING 235 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR igrave ENCODING 236 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR iacute ENCODING 237 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR icircumflex ENCODING 238 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR idieresis ENCODING 239 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR eth ENCODING 240 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 4400 6c00 3800 3800 6c00 4600 1f00 3380 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ntilde ENCODING 241 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 0000 6e00 7300 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ograve ENCODING 242 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR oacute ENCODING 243 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ocircumflex ENCODING 244 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR otilde ENCODING 245 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR odieresis ENCODING 246 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR divide ENCODING 247 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 0000 7f80 7f80 0000 0000 0c00 0c00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR oslash ENCODING 248 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e80 3380 6380 6780 6d80 7980 3300 7e00 4000 0000 0000 0000 0000 ENDCHAR STARTCHAR ugrave ENCODING 249 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR uacute ENCODING 250 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ucircumflex ENCODING 251 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR udieresis ENCODING 252 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR yacute ENCODING 253 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 0000 6180 6180 6180 6180 6180 3380 1d80 0180 6180 3300 1e00 0000 ENDCHAR STARTCHAR thorn ENCODING 254 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3800 1e00 1b00 1b00 1e00 1800 1800 3800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ydieresis ENCODING 255 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 0000 6180 6180 6180 6180 6180 3380 1d80 0180 6180 3300 1e00 0000 ENDCHAR ENDFONT nethack-3.6.0/win/X11/nh32icon0000664000076400007660000000224112616043300014643 0ustar paxedpaxed/* NetHack 3.6 nh32icon $NHDT-Date: 1446457887 2015/11/02 09:51:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 1993,1995,2015 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ /* 32x32 X11 icon for NetHack. */ #define nh32icon_width 32 #define nh32icon_height 32 static unsigned char nh32icon_bits[] = { 0xff, 0x7f, 0xfe, 0xff, 0x01, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x40, 0x82, 0x21, 0x25, 0xc0, 0x83, 0x61, 0x25, 0x80, 0x81, 0xe1, 0x3d, 0x80, 0x81, 0xa1, 0x25, 0x80, 0x81, 0x21, 0x25, 0x80, 0x81, 0x01, 0x00, 0xe0, 0x87, 0x71, 0x08, 0x90, 0x89, 0x81, 0x08, 0x80, 0x81, 0x61, 0x38, 0x80, 0x81, 0x81, 0x48, 0x80, 0x81, 0x71, 0x32, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1, 0x02, 0x00, 0x84, 0x41, 0x32, 0x67, 0x80, 0x41, 0xf3, 0x7f, 0x80, 0xc1, 0xf1, 0x7f, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xb1, 0x68, 0x84, 0x81, 0x71, 0x77, 0x80, 0x81, 0x71, 0x77, 0x80, 0x81, 0xb1, 0x68, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xf1, 0x7f, 0x84, 0x81, 0xe1, 0x3f, 0x80, 0x81, 0xc1, 0x1f, 0x80, 0x81, 0x81, 0x0f, 0x80, 0x81, 0x01, 0x07, 0x00, 0x81, 0x01, 0xc0, 0x03, 0x80, 0xff, 0x7f, 0xfe, 0xff}; nethack-3.6.0/win/X11/nh56icon0000664000076400007660000000541312616043300014655 0ustar paxedpaxed/* NetHack 3.6 nh56icon $NHDT-Date: 1446457887 2015/11/02 09:51:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) 1993,1995,2015 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* 56x56 X11 icon for NetHack. */ #define nh56icon_width 56 #define nh56icon_height 56 static unsigned char nh56icon_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x30, 0x38, 0x18, 0x00, 0xc0, 0x03, 0x00, 0x78, 0x28, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x6c, 0x3e, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x55, 0x3f, 0x00, 0xc0, 0x23, 0x22, 0xfc, 0xc7, 0x7f, 0x88, 0xc8, 0x43, 0x10, 0xfc, 0xd7, 0x7f, 0x10, 0xc4, 0x03, 0x07, 0xfe, 0xc7, 0xff, 0xc0, 0xc1, 0x83, 0x0d, 0xfe, 0xd7, 0xff, 0x60, 0xc3, 0xa3, 0x28, 0xfe, 0xc7, 0xff, 0x28, 0xca, 0x83, 0x0d, 0xfe, 0xd7, 0xff, 0x60, 0xc3, 0x03, 0x07, 0xfe, 0xc7, 0xff, 0xc0, 0xc1, 0x43, 0x10, 0xfc, 0xd7, 0x7f, 0x10, 0xc4, 0x23, 0x22, 0xfc, 0xc7, 0x7f, 0x88, 0xc8, 0x03, 0x00, 0xf8, 0x55, 0x3f, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x44, 0x3e, 0x00, 0xc0, 0x03, 0x00, 0x78, 0x54, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0x30, 0x6c, 0x18, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x6c, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x40, 0xc0, 0xc3, 0x10, 0x21, 0x38, 0x88, 0x20, 0xc0, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x20, 0xc0, 0x43, 0x11, 0x21, 0x38, 0x80, 0x20, 0xc0, 0x43, 0x12, 0x3f, 0x38, 0x70, 0xe0, 0xc1, 0x43, 0x12, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x14, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x88, 0x2c, 0xc2, 0x43, 0x10, 0x21, 0x38, 0x70, 0xcc, 0xc1, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0x7c, 0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0xee, 0x02, 0x00, 0xd0, 0xfb, 0xff, 0xff, 0xd6, 0xfe, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0xaa, 0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0x54, 0x02, 0x00, 0xd0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; nethack-3.6.0/win/X11/nh72icon0000664000076400007660000001050112616043300014645 0ustar paxedpaxed/* NetHack 3.6 nh72icon $NHDT-Date: 1446457888 2015/11/02 09:51:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) 1993 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* 72x72 X11 icon for NetHack. */ #define nh72icon_width 72 #define nh72icon_height 72 static unsigned char nh72icon_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0xe0, 0x07, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0xe0, 0x07, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x07, 0x3e, 0xc8, 0x07, 0x00, 0xf8, 0x13, 0x7c, 0xe0, 0x07, 0x22, 0x08, 0xfc, 0xc1, 0x0f, 0x10, 0x44, 0xe0, 0x07, 0x36, 0x08, 0x00, 0x7f, 0x00, 0x10, 0x6c, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x87, 0xff, 0x08, 0x10, 0x00, 0x10, 0x10, 0xff, 0xe1, 0xc7, 0xff, 0x09, 0x38, 0x10, 0x38, 0x90, 0xff, 0xe3, 0x47, 0x1c, 0x09, 0x78, 0x38, 0x3c, 0x90, 0x38, 0xe2, 0x07, 0x1c, 0x08, 0xfc, 0x39, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0xbb, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0xbb, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0x39, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x78, 0x38, 0x3c, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x38, 0x38, 0x38, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x10, 0x38, 0x10, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x28, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x08, 0x18, 0x00, 0x28, 0x00, 0x10, 0x10, 0xe0, 0x07, 0x08, 0x30, 0x00, 0x38, 0x00, 0x18, 0x10, 0xe0, 0x07, 0x00, 0x60, 0x00, 0x28, 0x00, 0x0c, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x00, 0x38, 0x00, 0x06, 0x00, 0xe0, 0x07, 0x00, 0x80, 0x01, 0x28, 0x00, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x03, 0x38, 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x06, 0x6c, 0xc0, 0x00, 0x10, 0xe0, 0x07, 0x08, 0x00, 0x0c, 0x44, 0x60, 0x00, 0x92, 0xe0, 0x07, 0x49, 0x00, 0x18, 0x7c, 0x30, 0x00, 0x6c, 0xe0, 0x07, 0x36, 0x00, 0x30, 0x00, 0x18, 0x00, 0x44, 0xe0, 0x07, 0x22, 0x00, 0x60, 0x00, 0x0c, 0x00, 0x83, 0xe1, 0x87, 0xc1, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x44, 0xe0, 0x07, 0x22, 0x00, 0x80, 0x01, 0x03, 0x00, 0x6c, 0xe0, 0x07, 0x36, 0x00, 0x00, 0x83, 0x01, 0x00, 0x92, 0xe0, 0x07, 0x49, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x10, 0xe0, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; nethack-3.6.0/win/X11/nh_icon.xpm0000664000076400007660000000356212467321052015456 0ustar paxedpaxed/* XPM */ static char * nh_icon[] = { "40 40 6 1", " s None c none", ". c #ffffff", "X c #dadab6", "o c #6c91b6", "O c #476c6c", "+ c #000000", " ", " ", " ", " . .X..XX.XX X ", " .. .....X.XXXXXX XX ", " ... ....X..XX.XXXXX XXX ", " .. ..........X.XXXXXXXXXXX XX ", " .... ........X..XX.XXXXXXXXX XXXX ", " .... ..........X.XXXXXXXXXXX XXXX ", " ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", " ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", " ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", " ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", " ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", " ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", " +++..ooooooOooOOoOOOOOOOXX+++ + ", " ++..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..oooooOooOOoOOOOOOXX+++ ", " ..oooooooOoOOOOOOOOXX+++ ", " ..ooooOooOOoOOOOOXX+++ ", " ..ooooooOoOOOOOOOXX++++ ", " ..o..oooOooOOoOOOOXX+XX+++ ", " ...o..oooooOoOOOOOXX++XXX++ ", " ....OO..ooOooOOoOOXX+++XXXX++ ", " ...oo..+..oooOoOOOXX++XXooXXX++ ", " ...ooo..++..OooOOoXX+++XXooOXXX+ ", " ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", " ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", " ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", " .....XXX++++ XXXXXXX++ ", " ....XX++++ XXXXXXX+ ", " ...XX+++ XXXXX++ ", " ", " ", " ", " "}; nethack-3.6.0/win/X11/pet_mark.xbm0000664000076400007660000000045012467321052015616 0ustar paxedpaxed#define pet_mark_width 16 #define pet_mark_height 16 static unsigned char pet_mark_bits[] = { 0x00, 0x00, 0x6c, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nethack-3.6.0/win/X11/pilemark.xbm0000664000076400007660000000045112536476415015634 0ustar paxedpaxed#define pilemark_width 16 #define pilemark_height 16 static unsigned char pilemark_bits[] = { 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; nethack-3.6.0/win/X11/rip.xpm0000664000076400007660000024054212467321052014634 0ustar paxedpaxed/* XPM */ static char *rip_xpm[] = { /* width height ncolors chars_per_pixel */ "400 200 90 1", /* colors */ " c #36362E", ". c #414146", "X c #2F2F31", "o c #353523", "O c #034702", "+ c #152E0A", "@ c #30311E", "# c #29292B", "$ c #233511", "% c #22221A", "& c #A6A6A2", "* c #3A3A38", "= c #75746B", "- c #191A14", "; c #7F7E78", ": c #12120D", "> c #1F2713", ", c #16330A", "< c #033E01", "1 c #181816", "2 c #033A01", "3 c #043802", "4 c #161614", "5 c #46464D", "6 c #242425", "7 c #0C0C0A", "8 c #15150C", "9 c #454545", "0 c #4B4B37", "q c #1F300F", "w c #1F2E0F", "e c #3F3F3F", "r c #3D3D3D", "t c #1B1B15", "y c #1A2E0D", "u c #888783", "i c #2D2D2D", "p c #292929", "a c #807F7B", "s c #272F13", "d c #313134", "f c #4D4D56", "g c #18180E", "h c #B4B4B1", "j c #989892", "k c #252621", "l c #90908A", "z c #1C1C18", "x c #83827D", "c c #6D6C64", "v c #20201F", "b c #797873", "n c #2C2C2E", "m c #42424A", "M c #434341", "N c #1F1F17", "B c #273B22", "V c #2E2E1F", "C c #7E7D74", "Z c #8B8B84", "A c #1D1D18", "S c #85857E", "D c #4B4B4F", "F c #CECECC", "G c #034301", "H c #034101", "J c #272728", "K c #043302", "L c #353539", "P c #282B15", "I c #5A5B50", "U c #24241B", "Y c #C0C0BE", "T c #30302A", "R c #5E5E61", "E c #1F330F", "W c #DFDFDC", "Q c #8C8C87", "! c #043C01", "~ c #053602", "^ c #38383B", "/ c #053002", "( c #343437", ") c #44444A", "_ c #52525B", "` c #132909", "' c #060603", "] c #292922", "[ c #424237", "{ c #3B3B3A", /* pixels */ "'''''''''''''''''7777777v7''''''''''''''''''''v''k'7777777777777777:7:7:7:7::::::4::4:444444444411111z1zzzzzzvddvvvvvvvvvvv6J#JJJJJ6JJ66JJJJJJ####nnnnXXdL^^^fRLLLLL^^^^^rrr.rm..mmmmmm5m....c_m__.mm.m.mmm.m.mm.mmm.m_).mmmm)_Df555555D5D5D5D5DDDDDfffff_____________cR______c_______c_____R_R_R______R__uffDDDDDDDDDR5D5D5D5D5D5D55R55D55555555555555Ra555555555)5)))))))))))))))))))5)5))5)5)5)))))))5))55555", "'''''''''''''''''''776777'7''''''''''''''''''7'7kv7'7777777777777:77:7:::::::::::::4:44:44444411111111zzzdzzvzvvzvvvvvvvv66JJ##66JJJ6J6JJ6JJJ#####nnnXXXdL^^^^^^LL^^^r^.R^.^.Rmmmm55m5m55m..m_mm)))mmmmmmm))55)mm.m.mm9mmmmmm)555fffff5fffffDDDDfDffffff_______________R_c_cR_____R__cR_______R__R_R_____fRDfDfDD5DD555D5D5555555555R555555D5555555555555555555)))))))))mmmmmmmm))))))))))))))))))))))))))))))))", "''''''''v''''''''77'7777777v''''''''''''''7'7'77'77777777777:7:7:7::7:7::e:::#.:4:44:4:444444X41111zzz1v1vzvzvzvvvzvvvv666J####JJ6#66J6JJJJ#####nnnnXXXXdL^^m^^^^L^^^.RfRm^m.mmm5m555555mmmmm)mm)))))))))5555555mmm_cmmm_)))))5fff5fffffff_ffffffff_b__________________cbRR__c_RR___________R__________ffff5DD5D5D55DD5555555555555555555555555555555555)5_5)))))))mmmmmm9m9m9mmmmmmmmmmmmmmmmmmmm))))))))))))))", "''''''''''''''''v''7777777vv('''''''''''''7'77'77777777777:7:7:::7:7:::::#7474::4:4:44444n9n491111z11v1v1vzvdvvvvvvvv6666######JJJ6J6JJJJJ#J###n#nnXnXXdLL^^^^^^^^^^.^f...f..mmm55555f5_mmmmm)))))))55))55ff5ff55m)m))mR_)))555f5bffff_R_fff________R___________R_____bR____________________________ffffDf5fDDD5f5D55555555555R5555555555555)5)5c))))))))5_)))))mmm).mm)_m.mm)))))m.m.m.m.m9__.).).m.mmmmmm)))))", "''''''''''''''''v'777777777''''''''''''7'7'77'777777777:7:7:7:7:747474:::4:4:4744:44444444411111z11v11v1v1vvvzvvvvv666JJ#######6J6JJJJJJJ#J####nnnnXXXXd(L^mLm^m^.^^.^.^.^m..mmm55555mmmmmm))))555555555D5fff5ff55))))))_D555555fffffffffff_f______________R__R_____R___R_c_R__R__________________Rfff5f5DD5D55D555555555555555D5D5555))))))))))_5))))))))))mmmmm))m5mmm)mm.m555))m.........9.9..m.m.m.m9mmmmmmm", "''''''''''7''7''''v'777777777''''''''''7'777777777777:7:7::7:747474::474:474:444:444:444444111111v11v1v1vvvvv6vvv66J6#6._###^#JJ6JJJJJJJJ#####nnnnXnXdddLLLf^Lm^m^m^^......m^.mm5m5555m)_))))55555555555ff5fff5RfD555_l55555555fff_ffff__ffffff___________________R_________c__________f_fff_f_f_RfffDfDDf5D5D5555555555)55mRD5fRf5555)))5_)))))5)))))))m)))m).m555555)mmmm555555mm........._..m..._.....__m9m9m", "''''''''''''''7'7'c'7'77777'777777777'7'77'77777777:67:7:7:::::::474::4:4:44:4:4447n4444441111dv11v1v1vvv666666#6##J###__.6##66#6JJJJ#######nnnnnXXXXXdddLL^^mLm^m^m.m^m^.^m....mmmmmmm5))555_55555555Dfffffff5f5f=555Rm55555555fffffffff_f_ff_f_______R___________________________f_f_ff_fffffffff5f5f5D5D555555555))))5_DDf5f55f5f555)mm)mmmmmmmmmmm555555)))5555555mm)555555555m....................m..9.m.mm", "'''''''''''''''v'''7''7'7777777776777{v7777777777:777JJ::74747474:47444474:44444444n4444411)1d5vvvvvv66666666#66666####nR^666#JJ##J##J######nnnnnXnXdddLdLL^LLLm^mm^m^m.^..m^..mmmmmm5)))5555D55D5D5D5ffffffRff5ffb5f5555555DD5f5fffffff_fff_ff__ff______________R________b_R____f_fff_RfffffffffR5ffDD5D5D5555555)555555=5f55555555555)m9_mm)m9mmc.m5555f5555_5f_5f55mmm55mmmm555m......................mmmmm))", "''''''''''''''''v''''''777777767777777777777777:77:::J:74J.::4:4:444744444447444444n444111191zvvvvv6v6vvvvvv6v6666666######J#JJ##J##J####ennnnnXXXXdddd5LLLL^m^mmLm^mmm^m^m..m.Rmmm5m5)55555555D55DDDD5f_fffb55f5f5f5f55555D5D5=5f5ffffff_f_f_ff_f____________cc____________bRbfffff_fffffffffDf5ff55DD5D5Rc5555))))555f5f5m555mmm5f5555mm_.mmmm.mmm)55f555555555_5m55mm5mmmmmmm555mm...mm..e.e.e......mmmmmm555", "'''''''''''''''''''''''''77777^6477777777777r:77::7:7:::::#74:47447444.4#4444444444441111111z16vvvvvv1vvvvvvvv6v6666666JJJJ#6###J#####n#nnnnnXnXXXXdd(ddLLLLLmLm^m^m^m^.......m5mm5m5)5555555D5DDDD5f5ffffffff5f5fffRfD555D5D5ff5ff5fffff___ff_f__f____R___________c_____f_ff_ff_fffffffffffDDfDfDDDf55D5555555))55555f555mmmmmmmmm5cf55mm.mm)mm...m5555mm55_5555m5m55m55mm....mmm5m5mmmmm..._e.f.f.e.mm55555555", "''''''''''''v'''''''''7'77777'67774777777::::::::::::4:444:44:44444444#44444444444111111111zdvvv1v1v1vvvvvv6v6666666##J6#J^#########n#nnn#nnnXXXXdddddLLLLLLLLm^mmLm^mm^m...m.mm)))5)555555D55DD5fDDDfff_ffff5f5f5fffff5DDDDf5f5fffffff____f________________R__________f_fff_bRfffRfffDffDDRRf5DD5D55D5555555))55555f5a55mmmm.....mmm555m.mmmmmm..m55m_5mmmmm5mmm5mmmm_mmm..rer.mmmmm5m5m5m........e..m5_5mc55__", "''''''''''''('''''''''''77777777447:7::7:74:474744:4:44:4447444444#44444444114114111111111v1dvvvvv1vvv1vv6d6v6v6666666#J###########n#nnnnnnXnXXXdddd(((LLL^L^Lm^mLm^m^.mm..m.mm))5)555555c55DD5DDRf5fffff_fffff555ffffff5f5D5fDffDffffff_____fb___________R_________f_fbf_ffff____RfDfDfDDDfD5fDD5f5D55555_)5_R555f5555mm..........mm555m.mmmm...m5_mmmmmmmmmm55mmmmmmm..r.r..^.e_f.mmm5mmmmmmm.mm..mm5mm.m_m...", "N''''''''''''''''''''''777777747474474_::474:4444#47444444444444444444111111111X1111111v111vvv6vv1vv16vvvv566v6666##J#J#########n.n#nnnnnXnX._Xdddd()L(LLL^^^^^m^m^m^m...mm.mm))))555555D5fDD5fDf5=ffffRR_ff555f5fffffffffDfDDfDfffRf_f_f__f__bf___Ra__R________R____fff_f_f_______fffDDfDDD5DR55D555555555555f5f55mmmm_m..e....e...mm555mmm.mmmm55mmmmm..fR5mmm5mm..^.^r.^.^.rrr.re.emmmmmmmmmmmmmmmm_m.ee.r.ee", "'''''''N''''N'''''''''7'7747447474474444J44744744n_4444444444444444111111111111115111v11v1v1vv66vvvvvvLvvv6v66666666JJ#J####.##n#nnnnnnnXnXXdXd.e_xalLLLL^^LmLm^m^m^mblabbbmm)))55555555D5D5ff=Rffbff____ff5ff5555fff_fffffRDfffffff_f________b__________R_________fff__f__________ffffDDD5DD5555555D_5))5555f55mmmmm....r..e.Rr..^..mm55mmmmmmm5mmm....r.mmmmmmmm..^.^.^.^.^.^.^.^.^.^r....mmmmmmmmmm..r.r.r.e.", "'''''''v'''NL'''''7'7''7'777774474744447447444444441441411444444441111111v11v11v1d1v111v11vvvv666vvvvvv6v666v6666#6###J######nnnnnnnnnXnX._e=&hY&&jjh^L^^^^^^mLmmfmmmRFYYFWW&lRc555555DDafffffffffff____ff5f55f5f5ffRf__ffffffDffffR__f____________R__c__________ff_f__________ff__f_fD5D5f555D5555555_5)5fff5_5mm....r...r.....r...rmmm_5m5mm5mmm.r.^.^.^.mmmmm_f.f^^r^R.^^.^.^.^rrr^..^.^..........^er.^.^.^.^", "''''''''''''N''''''''77'777774747444#m444447474444441111111111111111111v11Rv11v111v11v1v1v1v166666vvvv6v66v66666#6##J###.##nnnnnnnnXnXXDRjYYhYh&j&&jj^^^^^.^.LmmmRmmmRWFYYFWFWWWhjRR5D55Rff_____ff___fffff5f5f5f5fmff__f__ffDffffR_bR_________________c_______f_f_ff________f_fffff_ffff5f555555555))5))55555f5m....r..r.r.^.^.^.r.^..m__mm5mmmmm....^.^^.^mmmmmmm^L.^.^.^^.^^r^^.^.^.^^^.^.^m^.^^.^rr.^.Rr.r.ee", "'''''''''''''''''7'77'7777777744444447444444444444411v111111111v1v1v1v11v111v1v1vv15v1v1v1vv66666vvvv6v6v66666J6J#J#J#####nn#n.nnnXne=&&hYYhh&&l&h&jQL^^^^^.^fmmmmmmmbFFFYYFWWWFYhYFl=fRfff__________fff5ff5f5f5f5fff_____f_ffffRR_f___________R__R___RR_______fffff______fffffR_ffffff5fffDD5555))))))555f555mm...r..^m^...r..RRm..r.mm_mmmmm....^.f.^.^..m.mmm^.^^^^^^^r^^r.^.^^.^^.f.^^r^.^.^r^^.^.Rrrfe^.^rr", "'''v'''''''''''7'7'7vv7'7777777744744444444444441111v11v11v1v1v11v1111v1v1vv11v1v11v1v1v1vv1666666L6v6v6666666#JJJJ####._nn__nnn.rR&YYhY&hYh&jlQjh&Qarn^^^.Lm^.mmmmmmbWWFYFYWWWYYhhFFYY&bff_______ffff5fff5fff5f5f5f___f___f_ff__R____cR_______c______a____f_ff_fff_____ffff5f5ff55fffffff5ff5f55cc))m)555555_m...em^..bf.r^.rr..^.^.^mm5mmm...^..mm^.m^m^m^mLm^m^^.^r^.^^^.^^^^r^^.^^^^^.^.^.^.^.rfr^.^rr^.^.^r", "'''''''''''''''''77'7{77777777474744744111144444411v11111111111vv1v1v1v1v1v1vv1v1vv1v1vvv1v6v66666m66666666^#6#6########nn..nnXRbhhhhYYYhhh&&hjuQhjQbee^.^.^.^mfmmmmmbFFWFYYFWWWhYYhFFWWY&R____ffffffffffff5f5fff5fff___R_____f__R________R__R______a_____f_f____ff_____ff5f55f55D5fffff5555ff5fm_mmmm5555555mmme.r..^.frrf.^..^.r.^...mmmm..^..m.^m.^m.^mmm^mmL^^fL^^^^^.^^^^^.^^r^^.^r^^^^^^^^^^^r^^^.^.^^^r^.", "''*'''''N'''''7'7'777777777774777474441111144444n111v1v11v1v1v11vv1v1vv1vv1vv1vvvv1vvvv1vvvv66666666v666666#6#6##J####nn#nnnXDlhh&h&hhYh&&j&h&&Qj&&ubr5r^.^.f.mmmmmmmQWWFWYYhWWWhhhYhYFWWFY&uR_fbffffRf=5fDfffDf5fff______u__R_f_________________________f_f__________ffRff5fR5555555f5f555mm55f5)mmmm555f5f_mm..r.^.^.^.^.^.^.^.^ff.^^.m.m^.^^m^mm.^mLm^m^^m^Lm^^R^^^^^^^^^^^^^^.^^^^^^.^.^.^.rf^.^^.r^^^^^.^r^", "''v'''''v''7'7'777vk77r77:74774474747441v11v4444111v111v1dd111v11vv1v1vvdvvv1vv1vvvv1vvvvvvv66#66v66666666#6########nn#nnnnDjhhhh&YFWYYYhjulljjjjh&jQr)dr^m^....mmmmmjWWWWYYYYWWFhYY&hhhFWWYhhaRbffffRfRffffDfDffDfff___________________R___________bR_f______________ff5f5555D555555555m5m5mm5f5mm..m55mmm5_5m.^.^.RR.r.^.^.^fr^.^rff.^.^.^.^.^^f^^m^^mLmfmLmLLL^L^^^^^^^^^^^^^^^^.^^.^^^^^^^^^^^^^^^^^^.^^^^r^", "'''''''v''7'777'77{777777477J4747474411111v1v11111v11v1111111v11v1vv1vv5mv1vvvvvvv1vvvvvvvvv66#6666666666#6#J#J#####n#nn.f&FFhhhh&hWFWWYY&lQQxl&YYYYQM9drm^.m^..mmmmmbWWWFFYFYhWYhYFYhhYhWWWWYFWRRfffRffffffffffDfff_________f_f_______RR___________________R____f_ffff5f55f5D5555555m5m))mmmm5555mmmmm5m55_5m.^.r.rmRr^.^^.^^.^.rrfDf^.^^^.^m^LmRm^^^f^^LLLLLLL^LL^LLLLL^L^^^^^f^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", "'''''v'''7777777k77k7:7::7474747474744L_mL1d#ddvv11161v1v1dd1vdv1vv1vdvvvvvvv1vvdLvvvvvvvvb666#6666666#######^.###nnnnncjYYYYFhYY&FFFWFYjj&lQj&&Yhu_^^9re.......mmm55f_lFhYhYhjFYYYFFYhFYFWWWWWFF&R_ff_fffffDfffffDff___R______________Rc___c__R_____R_R_______ffffff5f55f55D555555)5)))mmm.m.m5555)5555m5mm5m^.r.^^.^.^^.^^.^^.^^.^r^^^^.L^mL^mL^L^mLRmL^^^^LLLLLLL^^^^L^LD^^^^R^^^^^^^^^^^^f^^^^^^^^^^^^^^^^^^", "''''''''7'77777777777:7:7477474746mu&&h&hj&jQb_Lvvvv1161v1v1v1v1v1vvvv1vvvvvvvvvvvvvvvvv6v6v6##66666#6#6#6######n#n#nnRYFYYhYFYYFhhFWWF&l&&j&hhh&fv6#M9r.^.^...mm_m5m566duhhY&&hYYYWFFhFFFWWWWWWWWFx_fffffffffffffffff___R_R__________R_____________bR________fffff5f55DD5D555555)))))mm).m...mmmm555m5m55mm_mr.^^.^.^r^.r^.^.^^r^^fr^r^^^^^Lm^LLm^^^LbL^^LLLLLLLLLLLLLLLLLDLL^^L^^^^^^^^^^^^D^^^^^^^^^^^^^^^^^^", "'''''7'77777777777:7::::474474#5bhYYYYhhhh&&j&jlu_dvvv1611v1v1vvvvv1vvvvvvvvvvvvvvv6vvLLv6vL66##6#6#6##########n#nnnrjYYFWFYYhFFhYhYYY&auj&j&YYYmz666XM.r.....m.m_55c5Xnvd&hYhhFhYFhFYYhFYFWWWWWWYWFYR_fffffffffffff_f___R_RR____cRR________f__f__________f_Rffff5f5D5f55D555555))))mm.m.........mmmmmmmmmmm.^fr.^^.^^.^^^^^^^.^^.DD^r^^^^^^m^mL^LL^^^L^^^^LLLLLLLLLL(LLLLLLLLLL^L^^^^^^^^^^^L^^^^^^^^^LLLLLLLLL", "'''7''777777777::::4:44744744^jhFFYYYhFYYYhhhh&&jQu_L66161vv1vv1v1vvvvvvvvvvvvv6v6vv6v66666L#####6#6#########nnnnnnbhFYFYFWFFYYFFhhh&juaj&&hhFFjJv#pkJe.r.....mma_5_R5Lv66uhYhFYFFYYYFhYhFWWWWWWFYhWYFQf_f_f_ffffffff____R___R______cR_____________R_____ffffff5DD5D5D5555R55555_))m).m..........f....m^....^..^^.^^.^^^.^.^.^^^^^^^^^^^^^L.^^mLm^^^LLm^^LLLLLL5L(((((((((LLLLLLL^LLLD^^^^L^LL^5LLLLLLL^LLLLLLLL", "''7'77'7777:7:J::44#14444444uFhYFFFFYFhFFYYhY&Ql&ujua_66vvvvvvv6L6vvvvvvvv6v66vv6v6v6v6v66666#d######6#fm##nn#nnn.xFFYYFFFFYhFFFFFFhjbbj&&&YYYYh#v#kvp*e.&YFYYhhj55555m6vvjFFhYFFFYWFYYFFYFYFWWWWYYhhFW&=f_ff_f_f_fR______bRb___________R_ff______R____fff_ffff5D5D5555555__5))5))mmm........fe.r.r.rrr.^.^^.^^.^^.^^^.^^^f^^^r^^^^^^^^^L^^Lm^LmL^mLLLLL^LLLLdd5d(d(d(d(((((LLLRLLL^LLLLLLLL^LLLLLLLLLLLLLLL((((", "'7'7'7777:7::7:744444m1111#uWFFWWWFWFFhYFYYYYhj&jQjQQuRLvvv6v6v666666v6v6vv6vv6v6v6v66666666#n###6########nn#nn#.YYYFYFFFWYFhhFFFYWYlaQQ&lYFWhYF)6piiTpmRhYhFFYhhcR5D5Rk#^FWFYFFYFhWFYhWWWYYFWWWWYYYYFFFhR_f_f_f_f__f___R__R_RR__R___________R__R_____f_ffffcf55D555555555D5)5))))mm........e..r.e.^..^.^.^.^.^^.^^^.^^^^^^^^^^^^^^^^^LLfLL^^LmLLmLLLLfLLLLdLd((((((((((d((((((RLLLLLLLLLLLLLLLLLLLLL(((((((((((", "'7'7777777::74:444444m_dv_&YFYYWWFWFWYFFFYYYhhhj&&j&ajabfv6v666666666666L66v66666666666666###n##########nn#nnnnfYFYFYFFFFFYFFhhFYFFY&j&jj&FWWhhFbL]TJp#)&YYhhYFhhj55ffD^djFhhYYYYYhWFYYFWWFYhYYWWYFYYFWFFhu__f_f_f________RRR_R_________f______R______ffffff55D555555555))))5)))mm.m......e.eee.^.fer^.^.^.^^r^.LrfD^^r^^^^^^^^^^^^^L^LLLLL^fmLL^LL^LLRLLLLdmdddddd9RXddd((((((((((LLLLLLLLLLL((((((((((((((((99", "77'77777:7::4744414444114hFFWWWWWWFWFFFFFYFYYhYjjl&j&juub_6LLL6#6###666666v66v6v6v6666666####d########nn#nnnnnRYFFFFFFFFFFhYFYh&&YF&hh&h&&hhYhYYYhcR)ca&hYFYhYhhhYYlRR=lhFF&hFhYhWYFWYhFWWWFhhYhFFFYhYWFWYFuR__fb_f_f___RR_R_R_R________f___R______f_fffff5f5D555555_))))))))))mm)5mm...e..r.r.^.eR.^.^.^r^f^.^^^^^^^^^^^^^^^^^f^^LLLLLLLLLmLLLmLmLmLLLLLddLc()dddddddd(dddd()((((((((((((((((((((95((((((d(dd(d", "77777777::47444411144444aFFWWFWWFWWWFWFWYFYFFY&&&h&Q&&uaaRf6###6######6#6^66666666666666###dd#######n_nnnnnnnuhYYFFFWWFYh&h&FFF&&hh&YFh&&&hhYFhhYYFYYYFYYFFYhFFYYhhjjhFFYhhuYWYYhWWWWWYWWWWWFFYYYYFYYYYWFFFFu___________b_RR_R_R_____fRf__________fffff5f5f5555555)5))c_5))))55)))55mmm..r.r.^.rrr.^.^.^.^.^r^^r^r^^^^^^^^^^^^LLLLLLLL(LL^^LmLLLLLLLLLLLdddddddddddddddddd(dd9((((((((((((((((((((((d(dddddddddd", "777k77:7:744744n1114441RYWWFWWWWWFWWFWWFFFYhFF&&&hh&juabaaRL6#6#########m####666666666#6##dnnn##^m#n#nnnnnnnaFYYFFFFFYh&YYYhhFFY&&jhFYFYhhhhFWFYhYYFFYYYYYFFYhYYh&ja&hhFhhlQhhhYYWWWWFYWWWWWWWYYYYWYFhYYFFFYFuR____________RR_R_R____f_ff_a________fff5f55555555))))))_)mmm)5555555555mmr.rf.r.^.^r^.^r^^^^r^^^RR^^^^^^^^^^^LL^LLL(R(()5LLmLLLLmLLLLLLLdddddddddddddddddddddddR9d(9(d((((((((((d(d(ddd(ddddddddd", "7U76::7:4:44444n1v44444&WWFWFWWWWWWWWWFWFWFYYYh&Yhhh&buaubbRL66#########^##n##.6J6JJ^^##ndnn###n##nnnnnnXnXuFFFFFh&hFF&hYYFF&hhFYj&YhFFYFFYYWFFFhhYFFFFhhhYYFYYYhxba&Yhhh&jhYYFYYFWWWWYWWWWWWWYYYFWFYYYhFFWFYYQR_________RRR_R_RRb__fff__________R_ff555R55555)))))mm))m.)))55555555555mm..r.^.fr.^.^^.^.^^^.^^^^^^^^^^^L^LL^LLL((((d((d(LLL^mLLLLddddddddddddd9XXXXXXdddddddd9_(ddddd9d(ddddddddddddddddddddddX", "77::::4:444n4444v11444^FFWWWWWWWWWWWWFWWFYFFYYYh&&hhQuuQabbb_6#########6#####mRn######mRmn#_###nnnnnnnXnndRFhh&&&h&&hhhYFYYYhj&&&j&&hFYFWFFFYYWWYYFFFFYhYYhhFYY&jaujYhWY&&hhFFFFYYFWWFFWWWWWWWYFFYFWFYYhhFFYhhYQ_________R_R_R_R______ff______fffbfff5f55555)))))m.m.m..9_mm55f5555mmm_mmm^.r.^f^^^^r^^^^^.^^^^^^^^^^D^^LLLLLL(((((((d(ddLLLLLLLLddddddddddXXXXdXXXXdXXXXdXddddddddd(d(ddd(d(d(ddddddddddddXXXXX", "7:::4:444441111v11v411bFWWWWWWWWWWWWWFWWFFFYFhYYh&&&QuluuaRbbL6#####66#6#L6#J#mnnndndndd#f_m#nn#nnnmmnnXdaFhhh&&h&YYhYYYFYhYhhhlQ&hhYFYhFYFYYhFFFhFFFFFYYWYhYF&jaua&h&YhhhYhFWFFWYYWWFFWWWWWWWYFFYYFFFWFYhYYYhFY______R___RR_R_R_R__________ffffff5f5555555))))mm.c_....mm)5555m5m5_cmm5m..^.^.^.r.^^.^^^^^^^^^^RfL^L^LLLLLL((((((ddddddddLLLddddddnddndndndXXXXXXXXXXXXXXXXdXdddddddddddddddddddddddddXXcdXdXdX", ":647444441111v1mv1v11XFFWWWWWWWWWWFWWWWWFFFYYYYhhh&lujjjuaQRbR########6#6##6#JJ##n#n#####m####nnnnnnndd(5&Yh&&&&&&hYYhYYYh&hh&&l;xxxjjQajlullahFWYYFFFFhYW&jljbbau&&&&ljjxlQjjj&&&jjFYYWWWWFYYYFWFYYYYYYFYWWFYFF&___________R__R__________ffff5f55555f555_)))m.m.m.......mmm5555mmmm_mmmm.^ff.^r^^L.^^^f^^^^^D^^^L^LLLLD5LL((((((dddddddddLdLdddndnddndndcdXXXXXXXXXXXXXXXdXXXXXdXdddddd9(ddddddddddddXXddXXXXXX", "4:44444411v1v1v1v1v1v.YWFWWWWWWWWWWWWFWWYWFYFYFYYh&&jujuQQbbRbf########6#6#^###J#^#########nnnndndndmLLm&&&&&YYhh&h&&&hh&hh&&&&css@so$@$s@$@$@sZWWhFYhhhhWc$o$ocujhh&hb@@@@$oooo$oo$@@ChWWWYFWFFFWFYYFWFWWWWWYFFWl____________R_________f_ff55fmf555555555))mmm...........mm55mmmm_mmmmmmm.rrr^r^.^^^r^^^^^^^^LLL^LLLLLLL((((((dddddddddXdddddnddnmndXmXmmnXXXXXXXXXX.cXXXXXXdXXXXXXddddddddddddddXXXXXXXXXXXXXX", "44n44#nd1111v111vvvv1fFFWWWWWWWWWWWWWWWFWYYYFFhh&&h&Q&uQubuRbb_#####6#6##J###J#J.#######n#nnnndnnnddLLmQhYh&hYWFY&hhhhhFYFY&&&&Iossoossssssssss$0FFFYh&hhFcosss=jhFWFYCo0ssssssssssssso0&FWFFFYYFFFYYWWWWWWWFYYWWF=________b____________ffff5f555555555)))_.)........e_e...mm5mmm._m.mmmm..f^.^.^^f^^^^^^^^^LLL^LLLLLLL((((((9dddddddd9_dXdndnddnd_dnmnXnnXnXnXnXnXnXnXXXXXXXXXXdXdXXdXXddddddXdXXX9dXXXXXXXXXXX", "44n11111v1v1d16v1v1vv_FYWWWWWWWWWWWWWFWYFFFFWFj&&hhhuuQQaaabRbRmd#######6##########n#nnnnnnnnXnddddLLLc&hhYY&FFWF&hhYYhFWWh&&&hI000000000000000ss0FYYWYY&h00000Z&hWWWY=000000000000000os0YFYFFhYYYYFYWWWWWWWYFWFFFh_____________ff_ff_ffff55f_f555555_))))9m.......e.efee..mmmmmm.._...mm.^_.^^^^^^^^^^^RDLL^^LLLLLL((((5(((dd(ddddXXXXXXXXdndnndnXmmnXnXXnXnnnnnnnXXX_XXXXXXXXXXXXMdXXXXX9XXXXXXdX_XXMXXXXXXnXi", "44111111mv1161v161vv1cYYWWWWWWWWWWWWFWWWFFYFFh&h&h&h&jQQQbuRbbbd######6###########n#nnnnnnnXndddnddLLf&&hhh&FFWFY&&&YYhYFFh&h&&I00000I0c0c0I00000@lYYFWFhY0000oj&hYFWWI0000II==ICC==0000scFWFFhYYYFYYWWWWWWWWYFWWWW&_RR____f_fffffffff5f55f5555555555_))).m......e.e.e.e.e.mm5mam..f.mmm....^..^r^^^R^^^LLLL5LLLLL(((((((d(ddd99ddXdXXXXXXnmdnnXnXnnn.nXnnXnnnnXnXnnniMiXnXXXXXXXX9MXXXXXXXXdXdXXXXXXXXXXXiXiXnn", "#44111vdn1vv1v16161vvRFFWWWWWWWWWWWWWWWWYFFYF&h&&&&hhuulaaabRbRm###6##########._#nnnnnnnnndndddXdLLLL&&&hh&YWFFhhhhhhhhhYFhhhhl00000jjj&j&hYYj00000jhh&&YY00000ljhhhWFc0000jFFhYFWWWj0000oWWWWYYFYYFFFWWWFWWWFFFFFFWa___ffffffffff55f55f_f555555555)))).)........e.reeer..e.mmmmm.....m.^.^^.^^.L^^^^^^LL^LL(L((((((((((d(ddddddXXXXXXXXnXnmnXnnXnnnnnXnnXninnnnniinnnnnnXXnXXXXXXXXXXXXXXXXMXXX_XXXXXXiXinnnnMi", "#44111111v1v1vvvv1v1vRYFFFWWWWWWWWFFFFFWFYFFF&h&&YhhhubQuabcbcb_L6##########nn##nnnnnnXnXXXddLdLLLLLR&hY&&&&hYhYYYYhYhhhYFhhjjZ00000CZjh&h&YFF00000ljl&h&l0000oZjYhhYYZ0000jYFFFFWWWW0000oWWWFYYFFFYWWWWFFFYFYFYYFWW&_ff_ffffffff5ff55f_R55555555))))).m......e.r.r.r.^.r^.mmmmm......mmm^.m^.^^^^D^^^LLLL(5(((((((((d(ddddd9ddX9XXXXXnXXXnnnnXnmXnnXnnnnnnnnnnnnenniXnXnniXXnXnXXXXXXXXXXXXXXXXXXXXiiXnnnniXnni", "444411v1v1v161611v16vfhWFWFWWWWWWWFFFWFFFYhFFY&hhhjhjlbbuabRbcbRn########n.#n#nnnnnnnXXdddLLLLLL_^Lmu&hYYh&hhhhhYhh&hYh&YFY&j&j00000cCZ&h&YFFC00000CCj&hjl00000ShY&&jYC0000&FFFYFWWW&00000WWWYYFFYFYFWWWWYWFFYWFYFFFWbfffffffffmf5f55f55R5_D55)))))m.).._cRm..e.r.^.^.r^..b.mmm.m.^m..^mmm^Rm^^^^^^^LLLLLL(5(((((((ddddd9dddddddXXXXXXXnXn.nXnnm.#nnnnnnnnnnnnnnnnnnnn_iinnnnXXXXnXnXXXXXXXXXXXiXiXinniinXinnnnn", "7441111v1v16161v61v1v#&FFFFFFFFFWWFWWWYYFFYhhYY&j&&h&uuRbbbbbRbR########n#_nnnnnnX.XXdddLLLLLLLLRmLbQ&&h&h&&hhh&lhhFY&&j&hYjllj0000000c0II=c000000cCx&&&Sj0000o&&Y&jhY=0000I=cC==Cj=00000=WWWYhFFFWFWWWWFFYFWWYFYYYWFYffffR_f5ff5f5f55555555))))))m9m._..._.e.r.r.r.^.^.^.^mm..m.m^.^..m^mm_^.^^^RLLLLLL((9R((((d(d(dddddddXdddXXXXXXnXnXnXnnnn#nnnnnnnnnnnnnnnnninnnnninniXninXiXXXnMiXiiXiXiXiXnniXninnnnnnnnn", "4:441v1v1v1616v1v11v1vjYYYFWFFWYYFFWFFYFYYYYhYF&j&&jQu&ubaRbRbc_######n#nnnnnnnXXddXd(LLLLLL^LLLLL_aj&hh&&&h&&&alh&&hh&jjhlalj&00000o0o0000o000000jjj&lxS&00000&h&hYhhc000000000000o00000YWWWFYFFFFWFWWWFYhFFWFFFYYYWWcfffffffmf555_R5555)5)))))m.)........e..e.^.^rrrr^r^m.mf_m...^.^^L.^mmffL^LDL^LL(((((d(d(ddddddddddXXXXdXXXXXnXnnninnnnnnnnnnnnnnn#########nniiinnniiiinnnnnnnn_innnnnnnniiininnnnnniiiiin", ":44111111vvvvv161vv1vdbYFWYFFFFWYFFYYYFFYYYYhhFjj&au&Qjuacbcbc=5#####n#nnnnninXd(d(LL5LLLL^^LLLLL^RQ&&hhhhh&&&juj&QjjjQauQaajjl00000000000000000IjjjjljZh&00000YhhFWFY=00000000000000000&WWWWYFWFFFFYWWWYhYFFWWFFWFYWWjffffff5f55f5D5555)5))))))_).......e...^.r.R^.^.^.^.^.mmmmm^^.^^^.Lm^^.^L^LLL(5(((((d(ddddddddddXdXXXXXXXXXnXnnnXnnnnnnXXnnnnn#n#n#nnnnnnni##n#inne_nnnniXniXniMiiiXii_Mninnnnnnn#p_#n#n#n", "4444411v1v1v11v11v1dvvXhYYFFYFYFFWWYFYYYYYYY&hYjj&ujjjjjaabRbcb^.^###nnnnnninXXdLLL(LLLLLLLLLLLLLmbuul&h&&h&&lujull&&jbaaljQ&jC0000000000000000C&h&ljlhYFj00000FYFWWWW=00000000000000IZFYYWWWWWFFYYYFFWWWYhYWFWWWFWFWFY_f5_f55f555555555)))))).)..........ee.e.^.r.^r^.^^^mm.m.m..^^.^^.^m^m^^^LLLL(9(((d(ddddddddddX9XdXXXXXXXnXnnnXinnnnnXddXXXnnn#in##########ne#nniniiinniiiiiiiiiinnnnniinnnni_p#in#i#i#n#n", "4444411nv1v1111v1v1dvzvChYYYhFYYYYYFYYYYhhhhhhhjQ&jjjjQauRbcbcc^n##nn#nnninnXd(LLdddddLLLLLLLLdLdRbajhhYYY&uualjQ&hYY&uauu&j&S=00000CZ=000000YYhhY&jFFFWYh00000FFFWWWWC0000CZ&ZCjZZZFFWYFFWFWYWYYYFYFFWWWYYYFWFFWWFWWFhbRfR5f55f5fDDD555))))m.).......e.ee..r.^.^rr^.r^r^.^m^.m^m^m^.^m^mm^m^^^LLL((((d(dddddddddXXXX9ddXXXXXiXnnnninnnnnXXdddddXnnn##############i#ne#iiinnnnnennnnnnnnnnii_in#enpi#i#pi###i#i#", "44444411111161v1v1vvvvvn&&hhFYYFYFhYYYYY&Y&hhYhxQjljjullabRbRbRdnnnn#nnnnnXXddLLdddddddLLLLLdLLL5bcbjh&h&&aabj&&hYWFWFjQujhh&xc00000&hYc000o0SFhYFhhWWWFYF00000WWWFWFW00000&YF&&hh&FWWYhYhhhhWFWFYWFWYWWWWYYYFWWFFWWFFhQf55ff5f_R5f5ffD555)))m..9......e..rr.^.rr.^.^^.^^..mm^.^m^m^m^m^mL^L^^LLL(((((ddddddddXXXXdXdddddXXXnnninXnnnnnnndddddddXXnn####i##i##i###e#nn_pniii_einnnnniiii#n##p##i##_rp###########", "4444411111v1111v1v1v1vv(ZhhFYYYYFFFhhhYYhh&hF&&&jlQa&ulabRbcbc_nXnnnnnnXnXnXdLLLdddd(ddLLdLLLLLLfbRbj&&&jucRa&&hFWFWFFhhhYFYjZI00000&jYFI000soZYhFYhYWFWFh00000WWFFFWWC0000hYhj&j&hWWWWYFYFYYFYWWFWWFFFWWWFYFWWFWYYFhYhhR5f55fffffffff5f55555)m......e.e.^..rr.^.^r^^f^^^.^m^m^^^^m^mm^m^^^^^^LLL((((dd9dddd9XXXdXXddddddddXniMnnnnnninnXdddddddXXnn####p##p##########pi#n##Iiininn#n#n#ni#i#i###prp###eepip#p##", "44m411111v41v1v1616vvvvv{jhhhhhYYYhF&hh&hh&hjj&jj&QQluabRbcbRbdnXnn_nnnXXXXd(LLdd(ddddLdLLdLLLLLfRbajj&jQbbu&&hFWFWFFFFFFFYYj;c00000hhhhh0000o0lhhFFYWWWFY00000WWWFFWW00000hY&ljjhhWWWWWFWY&&YhWWFWWWYYFWWWFFFFWFYYhYFYFbfffffff5_5555f5f5R_f5)m..e.e.e.r.^er.^.^rr^.^^r.^m.^^.^^m^m^^mLL^LRLLL(((dddddddXXX9XXXXXddddd(((dXXnMnnnnnn#nXdddddXdddnn#####rr###p########i#een#nnnXXXnn#n#ir######ip#p#p#p###p#####", "11n1111v14v1v1vv161vvvvvv*&&&&hh&hhh&h&h&h&hhQlljhbQabbbcbcc=f#nnnnnnXXXXXXdLLdddddd((dLdLLLLLL^_cbujuuQubaljhhFFFFWFFFFWWWYucI00000hhhh&&0000s@ZYFYFFWWWj00000FWWWFFWC0000hY&Zj&YYWWWWWF&&&&hYWWWWWWWYFFWWFFFWFFYhhYFYF&Rfff5f55555555f5555555mm...r.er.r_^.^.^r^.^^r^.^mmLm^L^^^^mff5^^^L5LL(((d(dddddXXXXXXXXXXXddd(d(d(dXXnnnnXXXXXdXXXdndXXdnn###p####p####pi##i###i#nnn.XXXXnn###pfni###pppppppppppppppprr", "111111v41v1v1v1vvvvvvv6vvv9&&&hhh&&h&&&hh&&&&bjj&jbbbbRbRbRbRXnnnnXXXXXXXXdLLLLddd((((LLLLL5^^^RRbbuQuQjuaj&&YFFFFWFFFFFYFFhacc0000IhhhhYhj0000@@hFhWWWWFh00000YWWFWFWI0000&&ljl&hYWWWWFhjj&hYYWWWWWWWFFFYFYYhYh&hYYYYYYWfff5f555)))m)5mm5m5m5555mm.ee.^effrrr^rr.^.f.^mm^^^^L^^^^m^^^^^LLLLLL((ddddddXXXXMXXXXXXdd)d(d(dddddX_inXdXddddndXnddndXXn##pppppppp#p##p##p#####nnXXXXXnncen#pi#fppppppppppppppppppppp", "1z11v111v1v1v1vv1vvvvvvv6kJ0&j&h&&&&hjjh&&&j&j&xxbaabRbcbRbcmnnnXnXiXXXXXX(LLL(dd((((((LLLL^^^^Rbabu&h&jujQhFFFFFFFWFFFFYFFj;Ic0000IhhYh&&jj0000sohYWWWFh&00000hFWWFFWC0000ZSCjhFYFWWWFh&&lYFhYWWWWWWWWYFYhWhj&&hFFFYFFYYbff5)5)))).)..m...mm55mm5mm..^.rer^.^.^.^..^.m^m^m^^^^^^5Lm^.^^^LL(5((((dddXXXXXXXXXXXnXdddLddXXndddd.ddddXXXXmdddnnddndnn#pppppppppppr##########neXXXXnXnnnnn##iipJJJJJJJJJJJJJJJJJJJJ", "z1z11v1v1v1vvvvvvvvvv6v666669ljj&&&j&&&&jZ&Z&Qjaxuubbccccbcmnn.nnX.MXXXXdd(^5L(((((((LLL^^^^^^Dbxauj&Y&QbauYWFFWFFFFFFFYYYYQcc=0000IhY&&jj&jC0000olYWWFh&&0000=YYWWFFF=0000Z=lhYWWFWWWhjl&&WWYYYWWWWWWWFYY&&QjhhhYFFFYYYhR_5_5))cm.9......_..m.mmmmmm.rrrrre^r^r^mf^fm^mL^^L^LLLL^^mL^^^L^LL5(((dddXdXXXXXXXdXXX.Xd(ddnnnnnXXXdXXXnnnnXXXXdXmnddXmnn#pppJppppppppp#p#p####nXdXdnXnnXdXnnnn##JpJJJJJJJ{{JpJpJpJpJ", "z1v1v1v1v1vv1v1vvvv6vv6v6vk6kD;ZjS&hjjjlj&jQljabac=bRbRbccmnnXnXXXXXXXddddL^5L(((((LLLL^^^^^^r^luu&hhh&ubauYFFFFFFFFFYYFYY&=RClZj&j&YYhhj&&&&jjjZS&YFYh&&YZj&j&YhYWWYW&hZjC=lYYFWWWWWWjZjhWWWYhFFWWWWWWYh&&QlYFYhFYWFYYYhxff5)))_mm.......e....mmm5mm...^.rr^.^^m^fffm^^^^^L^L^LLLL^Lm^^^^^LL(dddXXXXXXXiXnXd.XXdddXXnnnnnnn#nXnnnnn##nnnndnndnndnXXn#JJrJJJppppiRpppprp##nXXXXXnXXXnnn.nn#pJJJJJJJJJJJJJJJJJJJJ", "zzzv1vvv1vv16vvvvvvv6v666666k**blj&llZjjljlljxuauaccbcbRRm#XnXXXXXdddddd(LDDL((((((LL^^^^^^^r^c&&&&&&h&ubQjhFFFFFFFFYFYYYYQRcC&YFFFhFFY&Y&&YYYFYYhhhhhjYFWFhhYYFhhYWWWFhYY&jhFFFWWWWWF=jhWWWWFYYYFWWWWWY&&hjhWFYYYYWYYYFhj55m).).9........ee....mmmmm.^.^.^^r^^.^.r.^^^^L^LLLLLLLLL.L^^^^L^^L(ddXXdXXXiXM_idddd)dddnn#n#n#####n########nnnnnnnndnXnXn##prJJJJJJpJppppprp#nX._XnXXmnnrnneXnnJJJ6JJJJJJJJDJJJJJJJJ", "v1v1v1v1vvvvvvvvvvv6v6v6k66666JJ9;xxlCuSSxax;abaccbcccc_mnnXXXXXdXddddd(L^^LL(((LLL^^^^^^^Dr^.R&hhYhh&hQQ&j&FFFFFFFFYFFFYhuRSZhYYFYYYFY&hhYYhhYYY&hj&&&FFWWWFFYFFYYWWWYYWh&YFYYYWWWWFZlYWWWWWFYFYYWWFFh&&hYhhWWFYYYFYhYhYh55)m9.mmm.....ee.e....mmmm...^..^r^^^.^m^m^.^LLLLLLLLLLL5LLLm^^^LL((ddXXXXXXiiiindd(ddXXn#n#n######################n#nnnXnnn#pJJJpJpJJJpJJpppp#nnXXnnnnn#n#nn#nn##JJJJ##pJ66J]J666666*", "zvzvvvvvvddvvvv6v6666D66k66JkJ6{##{I;;;x=auabccc=cccb_LnnXXXXXddddddd((L^r^^L(LLL*^^^^^DD{r^r^a&&YFF&h&jhh&hhFFFFFFFFFYFY&bS&jhYFYYWYFFYhYYFFFYYh&jjhhhWWFWWWFYFWYhFWFFWWhYWYWFYFWWWhlhWWWWWWWFhhYFW&QjhYYFYYWFWWYYFYYYFFYfm5)m))....e.e..r.e......m.^..^r^.^r^.^m^.L^LLLLL((()_((5LLLLL^L^^L(dddd9XiiinnnXXdXXXn##############ppppppJJ#####^###nnd#####JJJJJJJpJJJJJJJ##nnnnnXXn########nn##Jp###rJJ6666J]6J]6J", "zvv1vXvvvvdvvvvvL66JJrJJJJ]6J6J#nnnn^RRb=b==cc=c=RR5dnXnXXXXXdXdddd(LL^^^.^^LLL*L^^^^^^^r^rr^mj&hhYYh&&jhYh&hYFFFFWFFFFYh&bjj&FYFYYFWYFYYWYWWWWWhZS&Y&FWWWWWWWhFFFYYWWWFFFWWYFYYWWWh&hWWWWWWWWFYFYWhuahWFYFFFYWWWFFFYYhFFY5c55))m...e_feefr.r.re^.^.....m^.^.^.^.^m^^LLL(((((d(((d(dLLLLL^LLLL((dddXXXnii_Xdddnnn########p#pppppppJJJ#JJJJ6J^JJ#nn#nJ#ppJJJJJJJJJJp{JpJ##nnnnnnnn#######r#n######rr###JJJ666k666", "vvvvvvvv66vv6v6666######J{DJJJ##nnnnXXnnLm.f__mmdXXnXnXXXXXddddddd(L5^^r^^^^L^L^^^^^^^r^rrrr.R&YYhYFYY&j&hhh&hYFWFWFFFFh&lujjhYYFYYWWhFYhFWWWWWYjZj&YYWWWWWWWWYFWWFYWWWFWWWWYYYYWWh&hWWWWWWWWWWYWF&QbjWWFYWWFFYWWWWYFYYYhY555555)..e.ee.eerr^rrrrr.^...^m.ff^.^^^mL^LLL((d(d(dddddd(dmLdddLLLLLL(dddX.XXXXXXdnX###p#ppppppppppJJJJJpJJJJJJJJJJJ##d###JJJJJJJJJJJJJJJJ###nnnnnn###JJ6JJJJJJ##n##nn##rr##JJ66666k6", "vvvvvvv6666666666###nnen##JJJp#nnnnXXXnnnXddX_.nnnnXnXnXXXXddd d(d(L^^^f^^^L^^^^^^^^{r^r^rrf^^hFFYFFFYh&FFjf#f^R5Rf_v))eDLXJ900I0000I0I00000c0IPoo0 0IIcI0=0c0000II0IcIc0Ic0sIIocIIIc cR_=;c=IDf.(nX(D_=5__D_aFWWWWWYYhYYY_55m555m..e.e..r.^.^.^^^^^.^^..^.^.^m^m^^^LLd(d(dddddddddddLddddXXdddd(dddddXdXXXXXn#cpppppppppJJJJJJpJJJJJJJJJJ^JJJ6##nn#f####JJJJJpJpJJp#####nnnn###JJ66666666JJJJ#J#######JJJJJJJJJ", "vvvvvv6v6666########n#nn#n#rDinnnnXXdnnnXXdXXdnnnXnXXXXXXXdddddd(((L^ff^^^^^^^=^^^{^r^rrer.f..&hFFFhYYh&YW&77'''''''''''''''''''778788888787787''''''''''77878788777888888777'7''''''''''''''''''''''''''''''5YWWWWWWYYhYh5mmmmmm)m.eb..r.^r^^^r^f^^^^.L^m^.^mL^^^^LL(ddddddddddXdXdXXddXnXXXnXXddddXXXnXnnnn#J^JJJJJJJJJJpJJJJJJJJJJJJJJJJ6J6J6#n#n.#nnn#####n######nn#nnb###J6J666v6v6v666666JJ###############", "vvvv666666###6#######nnnnnnnennnXnXdXnnnnXddXXdXXXnXnXXXdddd d((d(LL^^^R^^L^^^D^{{rrrrrrrrrrD.YhYFF&&hllYFjbuxx=aac=bZbZSCbaSa;;C=C=SxxSxZSCZSZQQullllSljlZSSSSuSZS=lSSbSZxljjulQllQuQaQujQQaQQalQQjuQcQQlujlfYWWWWWWWYYYY_...e..mm..r^..^.^r^^^^D^^^^L^^^Lm^^^Lm^L((ddddddddXdXdXXXdXXnXXnXnnnnnnnnnnn#n#n##JJJJJJJ{JJJJJJJJJJJJJ]J666666J6J6J6##nnnnn#nnnrnnnnnnnnnnnnn####JJ666v6k6kvkvvv6666J#######JJJJ6JJJ", "666666J####6#666#J####nnXXXnnenXndXdXXXnXXd(dddddXXXXXXdddddd(d(((L^^r.^^^^^^^^{r^r^rf^.r.r.e.&&&YY&&jua&FluuaaabaaSxQZu;bbaS;aSxaxSuxlul;xZlSlulSSQQjjZllSxxuuZZuuSjlSSujlljllQQjlZQljujljuQQQllQQujjljjlljjIYYWWWWWWWWYYfrre...mm.^f.r^.^^^^^^^^^^^^^^^^^^^^L^LLLddddddddXXXXXXXXXXXXXnXnnnnnn######J###JJJJJJJJJJJJJJJJJJJ]J66J6J6JJJ]666J6J6J6##^nn#n#n#n#nnn#########6666DLD 6vvvvvvkvkvv66J6J6JJJ6JJJ66666", "66J6J####J#6666J66J6J#nnnnXXXXXXXXddddXXXXddd(d(mdddXdddd d(d( (((^^^.^^^^^^^{r^rr^rrrrrrrr.rm&&hh&h&laajhRbbbbaQ;QSuQZQb;a;;xxxaaxxSalZxxZllaxZQuSujQjlZlSlSSuuuSZjjjQljQQlQQQlljQQlQujlQjuQQllljjjjjjjjjlQQ)YWWWWWWWWWWFD.r......e.^rrr^^^^^^^^xLLL^Lf^^LLLL^5LLddddddXXXXXXXXXXXXiXnXnnnnnin###ppJJJJJJJJJJ6J666J6J66J*666J6J6J6J6**666J66666666Jr#Jr#######J###J#J#JJJ^6v6Lvkvvkvv6vvv(vvvv6v6666666L66vvvvv", "JJ#####J6666J6#6JJ#JJ#rrnXXXXnXXXXdddm.XiXXdd((L((ddd(dddddd((((((^r.^^^^^^^{^r^r^.^r.r.r..r..hhYYh&&&bbj&RbbbauaxxauZZS;bQbaxxxaaxxSaZlxaZxSxxlxuuQlxSxxSSxSxSSuSujljljllljljjjuZQQQjjjQjjjQQQQQQjljjjQjlllQ9FFWWWWWWWWWW_rr.^.rf_.^r^^^^^^^^^^LLLLLLL5LLLLLLLLLddddXXXXXXXXXXXiXiXXiiininin####pJJJJJJJ{J6J6{6J]6J6]6J**J6J6J6J6]6666666kR]6666J66666J6JJJJJ6J6666JJ^666D66vk6vvvvvvvvvvvvvvvvvvv6v66v6vvvvvvv", "##n###JJJ6J6JJ6#JJJp#pr#nnnXdddddddLddXXXXXXXdd(LLLL((( d( (d(((LL^^^.^^^^^^r^rrre^.rrr.r.r..fYhh&h&&&abQ&RbbbuxxSaxuZxab;;bxaxxxxaaxual;lluuaauuuljljuSuxxuSSulZuujjjlluululQuZjZjjjjlluQjjQlQlljjjjuQQllllQ9YFWWWWWWWWWW_r^...r.f..^^^^^^^^LLLL(((((L(LLLd(dLLdddXXXXXXXXiXiXiXiiiiiinni#n#p#ppJJJJJJJ66JD**{666666666666J6]6]666***kJk6k66666666666666R6666666k6666*6D66k6vv66vvvvvvvvvvvvvvvdvvvvvvvvvv%R vv", "r####JJJ6^^J#J#J#p#pp#Di#nnnXd((((d(dddXXXXXdd((LL^^L^LL(d((((9DL^r.^R^^^^r{rr^rrrerr.r.r...ebhY&&h&&&u_u&RQauuaSauuSQuba;baxxxxxaa;lQSuauxuuxaSuQlQjllljjSxQxSjuuujjjQZSZuuZuuujljQQQjjlljjlQQuQjjjQljjljQlQ9YWFWWWWWWWWWRr.^.^.^.^r^^^^^^LLLL(L((((((((dmdddLddXXXXXXXiXiXiMiiiiiinnnii#i###ppJJJJJ66J6Jk666666666666J6J66666666**66666666k6k6k6k6k6k*k6k6k6kv6v6 DUv(Dk6v6vkvv6vvvvvvvv vvvvvNvvvvvvvNvv9Nvvv", "nn###JJJpppJpJpppppiperiiiiinnXXXX(d(dddXdddddd((LLL^^^^5LLLL^^^^^.^r^^^{^^^r^e^.^.r.r.e.e.._c&&&&&hYY&RuhcuuabaQxaxxQxbu;axSxxxa;;lauuaa;xuxxxlululluSluxuQxuuSSuujZllSuuuZujQljjjljjljllljjjjljjjjllljlllQQ9YYFWWWWWWWWWRRfm^..^..^^^^^LLLL((((((d(dd(dddddd(dXXXXXXiXiiiiiiiinnniiiii##p#n#JJJJ6JkJJJJJ666666kkk6*k6k6k6]666666666k6k6k6k6k6k6k6k66*(*6k6v6v6kkv6vvkvk66vvvvvk9vv9vAvAdcvAAvNvvNvNvNvvAv vAvA", "nnn##pJJppppppp##i##ireiiiiiiiiXXXXdddXddXMddd((dd(((L^^5*L^^^Dr.r^^^^r^r^rrrrr.rr.re.r......c&&&&&hFF&u&&RabaxaQubxQu;aub;xxxxuaalZQaaaaaxSuSxlZluulluxSxSSuZSuuSulZuSuSuuujQllujlQQQQuQQQllQjjjujjQljllllll9YYYYWWWWWWWWme^.^.^.^^.L^LLL((((((((d(ddddddddd(dXXXXiXiiiiiiinnniiii#nnXninnnnn#JJ6JJ#####JJk6JJJJJJJ666666666k6kk6k66666k6k6kRk6k6k6kkv6 6vkkvkvvvkvkvvvv6vvvvvvvv vAvAAvAdAdAAvAvAvAvAvAvAAvAvA", "Xnnn#pDpppp#pipi#riiiiiiiiiiXXMXT_XXddd ddd (99d(((((L^r^^^^^r^.r^r^^^^r^rrrrrrrr.re.e.e....mb&&&&h&hYj&hYbuabaxuuaxuxCub;xxxuxaauull;axZaxuuxxxljuujjxSuuuQxuuuQuSuZQuuQQZllQjjQuuuuuuuQjljjljuQQjljQlljljllDFFYYWWWWWWWWR.^^^^^m^.^^L((((((((( ddddd(ddXdXdXXXiXiiiiiinniiiin####nXdXdXXXn#n#JJ6J#######J6J6JJJJJ{6k6k6k6k6*66666k6k6666v6666v6v6v6v6v6kvv6vvvkvvvvvvvvvvvvvvAvzvAvAvAATXAAAAAAAAzvzvAAzvAAAAA", "Xnnp#ppipipi#iiiiiiiiiiiiXXXXXXXXdX dddd(d(d(((d9(((((^^r^r^.r.^^r^^DD{rr^rrr.r.r.e.e....M..mQ&&&YFYFY&&YY_uaaau;Z;Sxbbaa;aaxxaa;lu;Qa;QlluaaaxalZxjuxuSSuuuuSuuuuZQuuQuQQuujjljuZuQuZuQljQjlQQllQQQjQQQlQlll9FYYWWWWWWWWFDLL^^^^^^^R^L(((((ddddddd ddXdXXXXXXXiiiiinniii######i#iinXXXXXnnXnn#r#J###JJJJ##JJJJJJ#r^J66k66666*k6k6k66JJJJJ6J6666666kvkkvvvkvvvvvvvvvvvvvvvvvvNvvAvzAAAAAzzAzzzzzvzzvzzAAvzAAvz9z", "enipiDipiiiiiiiiiiiiiiXXXMXXXXXdd ddd (d d((( (((((I((L^^.^rr^^r^^^r^^r^rre^.rrreee.e.....9m5Rh&&&YYYhhYhh_bab;aSaua;b;Cbaaa;ZZQZxaa;;ZlQQuulQuljuuuxuuuSuuxuxuuuuuuZQQQQQQuuQQlZuuljjjjljjjjQuQQjlllllluQQQQcWWWWWWWWWWWWRLLLLLL^^^^((((d( (d(dddddXdXXXXXXXXinecniee##rrei#i#nXnXXXnXnnnne.nn#####J666J###JJ6JJ##JJ6J6k6k6k66k66*66JJJ#JJJJJJJ66666vvvkvvvvvvvvvvvvvvvvvv9AvAAAAzvzvzzzzzzzzzzzzzzzzzzzzzzzzzz", "XnpiiTiiiiiiiieiiieXXXTXXMX Xd ddd9I(d(((((((((*(*(LL*LL^L^r^.^^^rr^rRDrrrr.re.....e..M.9.)))uh&&hYhYYFhhh_bbxuxxQab;bbb;;;;Q;;CS;;aaZxaxaSaauujQljSuuuxuuxuSSSuuZuZuQuQQQlllQulljjjjjlQjjjljuQlQujlQlljj&jjjeWWWWWWWWWWWWbL(((LL(LLL(dd(ddddd dddXdXXXXXXTXiiiin#i##iri###p#iinXXXnnnnn######nnnn#J66666JJ##JJJJ#JJJJJJ66J6k6k6kk66JJ#J#J6J6JJJJJJ6*6kvvRvv vvvv%vvvNvNvNvA9AvAAzzzzzzzzzzzzzzzzzzzzzzzXzzzzzzz", "iiiiiiiiiTiiieeTXXXTXXXdXMM_ d(ddd((((((9( ((*((LL*L*L^*^^^^^^^r^r^rrrrerr.rr.eeee......)9))5ch&&hFYYYh&h&RaubaSSab;bbb;;abxux;uZu;xaal;xSuSxxulSjxuuSSuxSxuQQjZQuuQuuQlllllQujQjjjjlQQlQlllQQuQlQjjj&ljjjjllRWWWWWWWWWWWW=(d(dd(_d(dd(dddddddXdXdXXXTXXiXiiiinii#i#ipr##i##nnXXXnn#######pJJ##rr#{J66v6k666J##{{#JrJJJJJJJ666kk6v66{JJJJ666666JJ6JJJ66vv%vv(vvvvvvvAvvvAvAAXAAzzzzzzzzzzz1z1z1z1z11zztztztzzzzz", "iiTiiTiiiXTXiXXXXXXXdTdX dd ddd ((d(( (*(*L*LL*L*L**^**5^^^^^r^rr^rrrrre.re.e.e.....9.99))95cuhhh&h&hh&hY&Raxxbbb;;bbauubaSuQluSlxaxxaaaxSuuSxQQlSxxxuuQllQjjljSSQuuQQuQQQQuQQljjjjljjQQlQQuQQuQQQQQQlljjjjjlrWWWWWWWWWWWWfdd(ddddddddd ddddddMdXXXXdXXTXiiiiii##ip#p#nnnnnnXnn#n#ppJ##pJJJ6J6JJ6J6*k6kvkv66JJJJJ#JJJJJJJ{J66kv6vk666JJJJ66666J6J66666JJ6v6v9vvNvAAvvAAAvzAAAzzzXzzz1z11z1z1111z1tzt1t1tttzzzzzz", "iiiiiiXiXXXTXXXXXX Xdd d(ddd( (( (( (L((*LLLL***L*^^*^*D*D{{r^r^rrrrrr.ree.e.e....M..b9)9)555u&hhh&hhYYFhjRbbabab;bbxu;xZZQuQZxuQaxaaaaxSuuuSxljlZaSlxxluQlljljxuuuuQuQuQQQQlQZujjljjlQljllQQQQQQulllQjjljjlQDWWWWWWWWWWWW_dddd dddddddXXdTXXMXXXTXXMXXiiiiiii#i#p#pnnXn.XXXXn#ppJJJJp#JJJJ6k6k6*6k6vkv6v6v6JJ#JJJ6JJJJJ66666kvkvkvk6666J6666J6J6666v6v666666vvvvvvvzvAAAAzzzzzzztz1z1zt111-1t1--1-111I11iz1zvzv", "iiTXiXXMIeXdd X X dd ddd ( (((((((*LL*L*L*9*^*^^^*^*^^{^{^{^rrrrrrrr.ree.e.e...M..99)m)_55555uhh&hYYYYYh&Qcbbbbb;bbauaSQZu;uC;lQuuxaS;axSuuuuxxujuajQlSljjljjlZuSuSQQQlQQQuQQQQQQlZjjluuQlQQQQQQQQQQuQQjjjllQIFFWWWWWWWWWWRcdXdXX XXXXXXXXXdXMXXXXXiXeiiiiii##ipppiinXnXnnn#n#JJJJJJJJJJJ6k66*66 kvkv6kvvk666JJJ666JJ6JJJ6k6kv6kvvvvvv666D6666J6^6vvvvdvvv666v6vvvAAAAAzzzzzzzz1t1tt11-1--111111111--11--TzzzvXv", "iXXXXTXXXdXXd(ddddddd (d((((((((*(L*9L**L*D^*^*^{{{{{{{{{{rrrrrrrD.eeee.e....M.9.9)9)95959D55&h&hhhYYYh&&QbaaSxxaabuauabCaa;;SSSu;x;xaaxxuuuuuxxaSQlljQjQljllljuuQQuullQQlllQlQQllujjlQuQuQQQuuQljjlQljjjQjuj6WYFWWWFWWWWW9XXXXXXXXXXXTXTXTXiXXTXXiXieiiiii#pippppnnXnn####p#JpJJJ]R]6JJJJk6k6k6k66vk6vkvv66^#JJJ66666JJ666vkvvvkvkvkvv66vk666666vvNvvNvvvvvv6v6vvvvvzzzzzzzz1tti1-1---114---------1111111zzvzvz", "XXTXX XTIX d9(( ((( ((d (9( L*(*(*L*IRL*^**^{{{{{^r{{^r^rrrrrrreeeee..e...M..9.99)9))595D5D5DYYh&&&&&&&&&abuxxxxbQx;SC;a;Ca;;uuulxaZaaaaSuuuuSxxZlQlllljlQxxSuSQlllQQQuQQlllllQllQQjjljjjjQuljjjljjjlQjjjlljlDWYWFFYFWFFWWbXXXTXXXTXiiXiiiiiXiiiiXiiiiiiXiii#pp#nnnnXn#pJJJJJJ]J]JJ6J6k6Jk666k6kvkvk(v66vk66JJJJ66J6J66666kvvkvkvvvvvvvvv66666666vvvAAvAIvvvvv6vv(vvzzzzzzz1ttt1---1111--44444444444g----1zzzzzz", "TXdTdXddddd d(((( ((((((*_IL*(*L***^^^*^{{{{{{{{{r^rrrrrrrrrreeeeee.ee..M..9)99)))95595D9D_D5WF&h&&&&&h&&abaxa;bbauub;bbC;alQQllQ;l;aa;xSxxxxSxSZQZljZulxxSuuuQuQQQulQlQllluujjuQQQZuuujjljujllQljjjjjQjjjjQlcWFWYhjhFFFFWcXXiXiiiiiieiiiiiiiiiXiiXXddd9ddXnnninXXXnXn#pJJJJ]JJJkD*k6]6kk*k6k66k6vkvvkvk666JJJ6JJJ666666k6vvkvvvvvvvvvvvvv666v6vvAAAAvAzvzAzvvvvvvvzvzzzz1ttt1--i14-1g444g4g4g4g4g4g4414111z1vzz", "XdTd d d ddM( ((((( ( L(*(*L**L*^*^*^{{{{^{r{^rrrrrrrrrrrreeee.e.e....M.M9)55)55D5DDDD5DDDDDDFWY&h&h&&&&&aaaxabauQuZZZQZb;bZuuSQSQaaaaxxaSxxxaxuxuuQluulluuSlQSuuuQujljuQujjlQujjjQlljjQljluQlljjQllQjjjjjlQQRWWY&jhhYYYYYRXiiiiiiiiiiiiiiiiXieiXiXdd.XXeXXXXXnXnnnnnnnpJkJ]6Jk6Jk6]J6k66k66J666k6vkvvvvkv66JJJJJJ6J66kvv6kvvvvvUvvv%vvvv6666vvvAvAAvzAAvXvAvvvvvv1vz1z1tt111-11p-44444g444g4g4444444-1-11z1v111", "X dddddddd( (( (( (L(*(*L***^****^{{{{^{{r{rrrrrrrrrrreeer.r.ee.e..MM..99)D_DDDDDDDDDDDDDDDRDFFFh&&hh&hhh=axabbaaZuSuxQalQbCZQQZux;aaxaaxxZuxaaaQluuuuuQjSxulQSxuuQujQlQuullQjllQQljjjjuQlluQljuljjQjjluQuQujuWWhjjhFWWWWW_iiiiiiiiiiiiiiniiXXXXXXdXXiiiiinnnnnn#pp##nnpJJJJ6kJkk6k66J66kk66666666kvkvkv666JJJ6J6JJ666v66v6kvvUvv vvv%vvvv66vvAAAAAXAvAXvzvvvvvvvzzzztt111--4--4g4g4g444g484g484gg441111z1z1z14", "ddX d d ( (9((( LL*(*L***L*^*^{^{{{{{r{rrrrrrrrrDDeeeeeee.ee.e...M..99.9)5D_DDDfDDDfDffffffDDFYFh&&h&hYFYRaaabbabbZ;aa;ub;;;blZQZC;axxxxxaZQllaSjljlluSQluSxSuQlSSSuQlulQjjjuujluljjjjjjjjuuQuuujjllQjQllllQjRWY&u&YFWWWWW=niiiiiiip#pp#iXXXXdddXXn#p##ppp##pp##JJJpp##JJJJJJ66k6k6k66k6vvkkkkk6vvvkvvvk6*J666666J6666k6k6kvvvvvvvvvNvvvvv6v6vvvAAzzAvzzAvvvvzvvzvzz1z1---111-44g444g4gg48484884844411111zzz1114", "d d d( d(( (( (*(*L****^**^{{{^IR{{{{rDrrrrrreeeeeeeee.e.ee.e.M.M.999))55D5DDD5DfffffRDffff_cFhY&&hhh&&YFRabbubbbCx;ZubCCbbxSxZlSu;;xxSaxxalujQulllQllljjjjlQljjlSuuujjQljuQQQuuuuljjjjjuQlllllQjjjjjujlljlQj9Yj&j&hYWWWWWRi##ppppppippinXXXXnini#ppippppppppJJpJ6JJp##pJ#pJJ6k6kkk6kkkvk6vkvvvvkvkvvvk(6J666666DDJ6666v6vvvvvv%d vvvvvvvvvvvvvvAvzzz1vzzzvvvvzvzvzzz1t--1-zt1-14444484:48484848441111izz1111148", "ddd( (d ((((*L*(****9*^*{{{{{{rr^rrrrrrrrrreeeeeeee.efeMeR.M.M.M.9.)55DDD55955DDDfffDfff____cFYY&hY&h&&&hRabubbbbbuSCb;bbu;CuaQxuu;;xxaSxauluQjljljZlQjjlQQjjjllZuuSuulljuQQQQQuuljjljlZQQlllQQlQujjjlQljllljTjjl&YFFYYWWWRripipipppppp#nXnnnpDpppppppppJJJJJ]JkJkpprDr#pJpJJk6k6kvkv6vkvvvvkvkkvvvvvvv66666vv666k666kvvvvvvv%vAvvvvvvvvvvvv6vvvXzAzzzzzvzvzvzv1vzvzzzzzzzzzzzzz1t11444888848848441111i111n44448", "d ( d( (( L *(**L*^*{{{{{{{{r{r{rrrrrrrereeeeeee.e.eMM..Mf..M9999)955DD5DD9D9D5DDDfff_f_ff_faFYY&YYh&hhhhRbbQbbbbbu;CQZuxuQxQSQaQu;;xSxSxSuuxZlQlllljQQjjjQxxxluxuxuSQjjQljjuuuQuuZljjZuulQluuQQuljjjQQQQlllj{j&&hFWFFFWYYrpppppppppppi#nnppp{{{]p]JJJJ]J]J]66*6kJJJp*JJJ66J6kkvkvk(kvkvvk%RvvvvvkkvUvv66666v6666666 v6vvvvvvvAvvv6v66666vvvv6vvAAzzvzvzzzvzvzvvzvzvzvvzzzzzzz1zzzti4g44444:8484441114444448:884", "(d (( ((*(*L**L***{{{{{{rrrrrrrrrrrrrereeeee.e.Me.M.M.MMf99M9.9.95DDDDDD5D55D5DDDDfR__f_____QFFh&YYh&YFFYfaubb;bCZbCQuxuZQCCZSZalQa;xxxxuZlSlSSjSuuQluljQZjuSSllllQjljjjljQjuuZQZuQjjljjQlQQjjQjljQj&uQQllQQlMYhhFFWWWFhYYR]pppp]pp]JJ]#nnJJ]J]JJJJJkJkJ]6*6]kkkkkJJJk6k6k6k6vkvkvv vvvUvvv v 9kvvvvvvk66L66666666669vvvv%v%vNvvvvv66v(vvvvvvvvvvzvzzvzvzvzv1v1v1v1z111zz111111111zi14444884444441114484488848:8", "( (( (( *9(*L***^{{{D{rrrrrrrrrDDeeeeeeeee.eMMMfRM.M.M.99M9)99)9D_DDDDD5DD9DD9DDDffff_______aFh&&YYYhYWWFRxxS;bbZxbQSSxxC;;CluQSZQQlaxxalQSllauQuljllljQulxuuululjlljljlljQQQuQQullljlQluQjjjjjjuujjjQujlQQulRFhFFFWFWWFYYIpp{*pJ]J{]JpnnpJ]J]JJ]JkJ]6]6k**k6k666k6k(6T* IivvvvTvkvvvUvvvv(IvUvvvUvvUvvv6k66666vvvv666vvvvAvvvvvv66(vv6vvvvvvzvvvzvzvzvzvzzzv1v1vz11111144444111111111114444g-D4411448488:8k8::8", " (( L(*L(I9****{{{{D{rrrDrrrreeeeeeeeee.eMMM..MMMMMM.9999999)99)5DfDDD5DDDDDDDDDDfffR_______uFhh&hYYhYWFW_SxbuSbSSaZub;;;;;aZZlSxaaxu;a;QZllaxujZllZluuulSuZSQQljuQuQuQZjjjQjuZujjjjjljQQllQuuQZZuuljluulQuljbFFFWFFWWWWFFf]J]JJJJJ*JJ#nnp6666k66kkkk6k6kk6k6kkUvkv MD9I99*Uv9j&RTT*] vv%vvvvvvvvvvvvvv%vvvvv66vvvv96v(vvAvAvvvvvvv vvvvvvvvzvzvvvzv1vzvz1vvzv1v111144444g4g4g4414111111144844]-441444]8]::::8::", "(( ((* (******{{{{{rrrrrereeeeeeeeeD.eMM.M..MMM.9.999999)9)99595DRDDDDD9DD9DDDDDDfDfIff_____jFY&&hYYhFFWFcSuSCZZaZCZCxC;;bxaZZulQQ;allQQQllQxauQlaxxSaxxSSZuSZljjxuuQjllQjjjjllljjjQjZuZQQQuQjjlQQQZljjjjjjljRFFFFFFFFWFWWR]J]J]JkJ]Jp#n#p]kkk6kkkkk6k6kkkkvkvvkXII9D9ID9Mpvv&&hu {{r r%v%%v%%vN v%%%%vvv%vvvvvvvvv(vv6vvvvvvv(vvvvvAvvvvvvvvvvvzvzzzzz1zv1111v1z1444g4g848488444444444411444414441444J8:::8::::", "( L* L**L****{{{rrrrrrreeeeeeeeDMeMDMM.M.M99M_9999999)999)95595DDfDDDDDDDDDDDIDffIffDfIf___f&FY&&&hhYhFFFRSuu;ZuxaSS;ubC;;bCQQlSuZ;;ZlZlQaxZaSZSQxSSxSxxSuuuSjljZuSSlQQjjljSQZljjuuuuuZuuZuuuQZQQQQQQjjjjuQlj WWWWFWFWWFFWS]6666kkk6JJ###J6k6kk6k6 (kvkvvkvkvU9=IDIM0ID[ v%v&j&&r9[D[MrpTvNvvAvXNvvAvANNvAvvvvvvvAMdvvvvvvvvvvvAAzzzzzzvvzvzzvzvzzzzz1zz1v1zz1114gg84g:488848:g4848484411414144144448]:::*::::*", " L (L*9*****{{{rrrreDeeeeeeeeMMMD.MMM.M99.M_9M99999)995=95959D9DDfDDD9DDDDDDDfDDDfDfDRfD_f__jFY&&hYYYYhFYR=;u;aZZ;xQZSu;;;C;CuluQZZZQZQxxxSaSxSuuaSuSxxuuuSuxjllZuSSSSuZljjjjuuljjQZQZQZullZQuuQuQQQjjjjjjuQZDWWWWWFFFWWWWR6kkk]6]6kkJ###Jkkkkkvkvkk9vvvkvvv9xbIRIID9D TekvNTljlc{[* 9D*** vNNXNNvNAvNvAXAAAAvvvvvvvvvvvvdvvvzzzzzzzttzzzzvzzzzzvzvzz1111z1v1z444g4:4884884:8::88888:484414444444448]]k:::::::::", "L*L* *9****{{{rrrrreDeeeeMMMMeMMMM.MMMM9_M9999999999595_D9D9DD9DfDDDDDDDDDDDDDIDIfDIDDDDD_ffjFFY&&hh&YYhYRb=ub;x;a;xaxSabbb;;CuuQaaaQxxSZxSxxxaxQuSuSSuxuSuSjulllSSuuuZuljQjjjQlZQQuZQlQZljjlQjjjjjljjjjjjjuQIWWWWWWFFFFWW=kk6k6k6kk6JJpJk(kvvkvvvvUUvUvvvT=&=IRI9DI909D*NMMkIDk%kTM[9D[9 9kAvTvAAvAAAAANANAvvvvvvvAAvAvdMvAMtttttt---tz(ztppTiznD=bXJv1z1z11148:88488488:8848k8:8::::8444141p14888:::::::::::::", "( *9******{{{rrrrreeMeeeMMeM.MM.MMM.9999M_99999959595I99D9D9D9DDffDDDDDDDDbIDfDDDDDDDDDDDDDf&FFYY&&hY&YYhI=bSb;aZaSZZuZab;b;;CxQQQaaxaxalaxxxxaaSaSxSSxuSSSxllxSlZuSuZuuljlQlljjulluQQlQulljjjjjlQlQQQljjljuQIWWWWWWWWFFWWRkkkkkkkkkkRpJ6kUvkvvUvUvvvvvvvTu&bRRIcf0RDDDIM9]]9DI9I;cMM[0De[* AAAvAAAvNAvAAAAAAvvvvvAvAAvAAzzT-ttttt--k 9MTTTT]]R&&jbMTTTv11144848488::8:::88k8::::::8::884444g484:::::::878787::", "********{{{{rrrreeeeeMMMMM.MMMMM999999999=9)59599D9D95DD9DDDDDDDffDDDDDDDDcDDDDDDDDDDDDDDDDRhYhhYh&hhh&hlRbbbb;;x;SSbaCbCbb;b;CZuSSSuaZuuaaxxxxSSSuSSxSxxuajlSSQjZlQuQuZuQlljZjSlQluuZjjjjjuujjjjjjQQlllQjlZQRWWWWWFWWWWFWbkkkvkvvkv(kJ6kvvUvvUvvv%v%%vNTl&bRRIRIIDI[IDIDI* 9IDclQM[MIeD09 M9*TAAAAAAATAAAAzzTvAvvvzzzzzzzz--------T9cRVk]Tp]]p9SQjlDT T4Tz14888:*8:8:8:g::::::8:8:::::84444848::::::::787878787", "*(*****{{{{rrrreeeeeReMMDMMM9M999M99999999)I99D9D9D9D9D9DD9D9DDD_DDDDDDIDDRDDDDDDDDcDDDDDDDDj&&&&&&&hYh&&IbSu;abaZxbbbbbCb;b;;CxQlQuSZuuul;axxSuSSSxSuSSxSjljuljjlljSluQZZZjlQuuZjulujjujjlQjjuuQZjQullllZjjQkWWWYYYYYWWWWRkvvkvkkvkv6J9vUvvv%vv%vTNXNNix&lcRIRIcDII9D0DID9DM0DDDDDDMrIDDMp[9[*TAAAAAAAAzzzzzzAAAzAzzztzti-------gDabRTi% *]]] ah&SM]]k% iA8::88888:8:::]k8:8:::::8:8:::88::8:::::::87888%8o7:U", "******{{{{rrrreeReMeDMMMfMM9M99M9999999)_I)9D959D9D9DD9DD9DDDDDIf_IDDDDDDDDDDDDDDDD9D99D999D&&&&&&h&hYYhQcuaaSxbbxbbCbC;bbC;;;;aQZZllSuZlu;u;aaxxxSSxxxlljlQllljlljSuQQZQQSjQQjlZlQjjjjuullljlluQulZZQlllQjlZDWWYYYYYYYFWWcvkvUvUvUvUk6*vvv%v%XNNNvANAX=&hcRcIIRIRD0000D0D0D[DIII0I[M[I90{ *[DMkzzzzzzzzzztttttzzet-----4[4-g4g4IaSSc p]i ]g%RD[A%A] kTTkNt88:::::::8: k8:::8::::88:8::::8::::V9@9oNUVDCjjjU%", "*****{{{{rrrreeeDeeMMMMM9M999999999995999959D9DD9D9DD9DDDIIDDDDfD_DDDDDDDDDDDDDD9D9D9D9D9D9)&Y&jh&hhhhYhbcCuSuZbZSb;;bCS;bbb;;C;;lQQluuZlQQSaaaxxuxuSxQjlZuuulSSQllSSuZQZuulQZuZjjjjQjuuuZlZZjllQujlZZQllQlQZIWWYYFWFYYYFWlv v%vvvvvv66vT %vNNNvAAMTAzIhhaRIRRIIcIIsoo$oo0ID0ooID0o@[[MIDM {MM[Mtttttttttttttt-------4g-g4-g4g4U=;uc* *TT]T* p]VTiI=u]p ]kpT-::8:8:8:::8::::::::::::::::::::tT9c=M]kT%T=hY&&]T", "****{{{{rrrrreMeMeMMMMM9M99M9999999999D9D9D9D9D9DDDD9DDDDDDDDDDDIfDRDDDDD9D0D99DD9D9D99c9999&&j&hhYhjhhhubCaxxxux;C;;C;bb;Qx;;a;;aZulSuQZuxlSaa;uSaauuuQQluQZuSSlSxSuZZuuuSlljjulZZQlluuuuuZZujlZQujjjZulQlulRWWYFWFWFFYYYRUvv%%%v%%vk6%%vANvAAAAAAAzz&YjRcRIIIfRc0oo000oo00Mo0IIoo$s@oo0[9[*D * ttttttttt---------g-g-g4gg4ggkcllbT* T]kpTT*]]k 9cIkUkpk]T]-8::::::::::::::::::::::::::::: Rbx= kU]T]TI&hYh]]", "***{{{{r{rrreMeMDMMMMM9M9999999999599D99D9D9D9DD9D9DDDDDDDDDDDDDffDDDD0D9D9D9DD9DD9D9D99999)h&h&&&hljhYYxxSSuSbbbb;a;;abSbZSb;a;;xlllSuuuSxlulZZQuxSuulllllZuxSSSSuuuuuuuuullQQluZuulZjQlluZQZuuulZlQjljZZQjj*WWYFYFYFFYFYbv%v%vN%Nvv6vANTAATAAAzzzt-IYYaIIccIIIIc000I000o0I0oo0Io0000oo[D9D[M [e%--tpT----t------]-g4g4gg4g4:cl&&DT *TTUT]TpU T T]%iN]T]T]]-]-U::::::::88788o788o878878:8 b;;cTkkUkpU[&jZSIkU", "*{{{{rrrreeeeeMeMMMMM9M9999999999D9D99D9D9DDDDD0DDDD0DDDDDDDIDDDIfDD0DDD9D9I5D9DD9D9D999999RY&h&Yhuxhh&Y=axSZbb=ubbaabCbb;bxC;;aaCSaluaZlaxxxSSSxSuSuullllxxxxxSuuZuuuuSuSjljZjuuZuuljlljuZQQQujjSujjljjlujjj9WWYYYhhYYhYYRUvNNNvvvvvkNAAAAAAAAttttttlFhIDIDRRIIDIIoso0oo0IIIooIIo0000oo00I[ TT*9*]t-t--t-----g4g-g4gggg4g8g8I&lj=T * ]ps ]TTUT ( TvN]TkpT%k]]TT:87887887878788878:88788>[xSlS ]]kTT]N]U]V]IR[", "*{{{r{[rrr[DeMeMMMMM9M999999I99D99999D9D9DD0D9DDDIDDDDD0DDDDDDDDDDDDD9D999D5D9DDDD9D9999999cY&&hY&au&j&&u=ab;bbbubaaC;;aCbCb;S;C;;xSxlSaZQxxxxxxuulQllxSlaSSSxxSuuuuuSQljlllZjuluZuSQZuZuuZQQZulljjjjujlulQljIFFFhFYYhhYhhIvvvNAANv vAAAAAztttttt--TFFlRIIIIRIIIIcoo0o0o0000o0000o@sooo00D*T *[ 9U--------]-4--g4gg4g48g8R8]hY&&9TT* *Tossss@s okosss@s %]Tk TV7878787878787878787788789SljuIT]kkT]]]%]TTpC&I", "{{r{r[rr[eeD[eMMMMMMM99999999999D9DDD9D0DDIDDDDDDDDDDDDDDDIDDDDDDfRDDD9D9D9D5DD9D9D9999M9MMR&&jhhjbxba&&=b==bbbbabbaaa;;;bbbC;;;bC;ZlllxZQlxxxxuZulllQuQxSSxQZxxSSuSxQjjjlluQlQuuuSjjQuZQQQZZQuQuuuulQQllllZQMFYYYYFYYYYYYIzvvNvNvvvvAAAztttTtt-----cFYlII_DIIcRIIIo0I0oo0I00oo000o000o000I*[{M T9[4-g-g-g--gggggg4gg8g88*88DY&Yu TT*** Vs@ooPs@TVs@]@ssssso]Tk TTV78787878787878787887878=bbSckT]kUTT]TA%]]Tk[p", "{r{[rrereeeMeMMMM9DR9M999999999D99D0D9DDDRDD0DD0DDDI0DD0DDDDDDDDDDDDDDDD9DDD9D95955999MMMMMRj&jhhju=_=lu_S;bb=CbbZbaa;;a;bbC;;bCb;;;CaluQlSuu;x;lllQljSxaxlQSZxxxllZjuuuQjjSZljuuZulQluQQQuZuQulQuZZZllZjjjlZIFFYhFFFFYhFYcvvvvvvvvvMzttttttt-------=hhbccIIcDIDIIco0IIo00900oo0I0o0000IMIr[MM[Mr0Dgggg-g-ggg-g4]gg8g8488888jY&hI[]TV* *Ps@oPP@] @@VPs@ooPo T]k]kUV8787878787878787878787IIRxuM]UT-%TVTTNp]Tk-T]", "r{rrr[re[eMDMMMMMM9M999999IR9D99D9D9D0DD9DDDDDDDD0DDD9=_DDDD9D9D9D9D9D99D99999999959MMMMMMMR&&&hj&&ubRc=DCx==;bbbxbx;;C;;CbQSuSuS;;;C;SZZQSQZZQlSlll;SSZQllllxSSlllQuSQQlQlxZuuuZujQjuSZQuuuSulQQZuuujlljjlQQ_FYhYFFYFFFFYIvvvv%vNvTtTtttt--{----g-glhYccI_RDDI9[DIo0000oo00[ooo00o00II0ID[M[{*M 99kg-g4g-g4g4ggg848g888888]Fhhh9**TT *[Us@s@ssoT s@]so@os@@V]%NNAT]87878787878>87888788VcR;xRPNUTt%]s@ss@T]stV@", "[r[erreeeeIDMMMM9MM9M99999999D9D0DD9DDD0DD0D9D0D9D999D99D0D9D9DD9D9DD9D59D999999599MMMMMeeecj&FYhh&j=R=bM==xubCb=Sbxa;;a;baQuQuu;xbCC;a;;;;xQlQQZ;;alQuSxlQljZllZuujljjxlSuZljSuuuQuSuSuZZulZZZQuZZuujQllljQjDWFhhFFFYYYFhRvvvNAAttTt-Vt---tg--ggg-U&YYIDIIcIID [I0I00II00 [0o0oo0o00IIID0M9[*[*T[ g]ggg4ggggg]8g8g8888888R&hYh T*[]TT]o@ooo@oV ooV@o@@@@sV]N-NUtTN88888888887888787887[cS&&Dk-]UtTVs@@@sT@stos", "rrrr[e[eMMM[MMMMM999999999D90D9ID9D0D9I_D0D9D9D999D9D0D99999D999D9D9999995999999999MMMReMee;j&h&h&&ucbuuI==bbbbbbxb;a;babb;alaaSQQQC;;aaxaa;uuQlZxllZuulQllZllZuSZjllQlxSxlljSuuSjjuQuSZuuuuljululuZZlQZlljQjIWYhYYYYYYYYhcNNAztttttt------g-g]-g4gg&&jRIIRIRcIDIIII0IIII0 MI00[[[o0I90D[D9[M[D**[MT]]g4ggggggg*8g888888888=YhF; [TTT T] so@oo@@V @oVosPPo@g%gz]k]]]:78787878788888I8>7Pxl&hj U]U]NUUsoPPs@V@oV@", "r[e[eeMeM[MMMMMM9MM99999990DR99ID9IDDDDD9D9D999II09999999DI90999959999I9999)999999MMeeDeeee;uxl&h&lbbub;_;=a=bbb=Sb;aCaaCbCbZQZSxSSZlQQuQQQZQZaSuZlSZZjlllQSQlQZSQluxSSSSjQlSSlulullSuuQQQuSujjjZuQZQlZlljljQgYhYYhYhYWWFhbTAttttt--------g-gggggggk&l&RRIRI*M[[D90T00II0[MIII9[*[M0DID9ID[IM[[I **[]4ggggg48g888g888888:8:cjYYZ*[kk]T%N[os0o@@ o@ Vo@VPoVNk%]TTTV]P878878888>88888:888&h&&;%t]%kNTo@s@s@V@s]@s", "eeeee[eM[MMMMMM9M9909I99D9D99D9D9RD9D9D9D9909999959I999999M9999II99999.9999999M9MMeeee[r[rDQlQlQj&lcbucc9a=b=b=bbub;aC;axCaxZZSuZQQaaxaSuQSxxuZuxxxQ;xx;;lSSQZluullSSQSZZuxSulljQZjlluQllZZuZjlZSZZQZQQZZuQluIYYYhYhYFWWWYbAtt-----g[g]*]ggg-gg4gg8 jj&IIIID T U]T]]UNTTk%%t]]%k]k]oTo* [* r[{ *[4-g4g4g8g8gg88888888888cZh&S ]TN%ktU [oo[os@o @@oV@oo] U Tk ]kkk88888>8788788888880h&hj=Vkt]UN]VsPso@oVsPU@", "e[e[eM[MMMMMMMMM9M9999990990D9IID0D0DD0D90D9D999999M9909MMMMMMM9999MMMMMMMMMMMMDeeee[eeer[r&h&&j&&u=abcc9b=bb=;b=ab;;Caa;xCSZx;SZlZuaaaxSluZZQuxlSaSxxxaZlZaaxuSZuZlSxuZuSZuljlujxjSSullZuuZljllZZQZSlQluuujZMFYFYYhhYFWWF=*Ntt-tg--g-g-gg-gggggg8gT&jhcIRID TTTTT ]TTTT]]]T]]]]]kUUNNNztk]M0D{t--ggg8g8g8888888 :888UlSj&cTT{] N ToV [0oo@@oooVV]]TTUTT U] ]U87878>88888888888-IYhh&=]]tTT-UosP@@soos@Ps", "ee[MMMMMMMMMMM990999IM9D9D9D9D999D9DI9D9I5999D099999DMMMMMMMMMM99MMeMMMMeeeeeeeMDMrereeeeerjh&hhh&u=cRcjf=b=bSbCCb=b;b;aCS;uZuCCuQ;uZlZQQQ;;CaC;;;axa;;x;axxxQluZlSuZxxxllllluSljxSZuQQuSuSujllljuZuuljQllSSl[WWWFhhYhYhYFa *%-gV-g-gg]ggggg8g888g8 j&&ccRcI TTTTTTTT]TTV]T]]V]]Vp]]]]kkk]kU M9I --gggg--88g8888888888glSh&RV {T%]]kVT]TVoT[ TVTT ]ViV ]kTT NN]T]g888888888888gg8ggRhhhYlVkTV]%UU@@P@@@os@PV", "M[MM[M[MM[MMM90M999M990990D0D0D9D9DMI9D9I9D9D99999MIDMMMMMMMMMMMMMeeeeeeeeMeeMeeer[r[re[eerh&&YFFhQbcRQ&Rb==C;SS;=ba;C;CSZZuZCbCbxxSSQQCC;axaa;;;axxa;;;xx;a;QZxljSZZllSZlZjZZZZZZuZSuuuSSuQlZlllSSuSjlljjSSjRWWWWFhYhhYFFa[ *U--g-g-gggg4ggg88g98gM&jjIIRIR T TTTVTT]TT]T]]T]]]]]]]]Uk]UUUVD{0DA--]]9[U]VDujkt]8 88g48&&&h=] [kggg888:88:8:g8:g:gg4gtANU]kUtk]]V88888888888gggggg-0hhhh;VTU]]NTVPPoPVVoooUU", "M[M[MMMMMMMMMM999M9099D99D99DDDD9D99999D99D99999999MMD0MM[MMMMMMMee[ee[e[rr{eree[rr{{rrre[9YY&YFFhjQuu&&I=b=SxSSCbb;aabba;;xSbCb;aCbxuSCCa;;;;;xxxxa;xxSxxuSaxxSSulZjlZQSSxxSSuSSSuSSSuxluuZluQjZjjxljZQljSQjIWWWWFFFFFYFWl[[* Ugggggg9ggg8g888k g8Ujj&RDIcI TT TT T T] T]T]]T]]]T]]]kk]]]kkkTMIDD ]DcMV]kVN9&j T]T%gg-gg;&h&=]]kkg4gg8g:8888:888:8::8:::8:::::UTUUV88888888gggg]gg--9h&&hSV]%U]%VUUNUV]V]VUVU", "M[MMMMM[MMMM0M9M90999909909D99999IID9D9999MR999999999MMMMeeeMeMMM[Drr[r{{{{{[r[rr{r[{[{[{r*YYYhYFYjQjl&Yc=ab;Sbaa=bbbCbabCxZxbbCauaZSa;CbC;;;a;xaxSxxSxxxuZux;aaaSlllZxSSSxSuuuuuSSxlllSujQlZllQjuuQuZSjjlSxl FWWFFFFWFFFWj{ [ -g-gg-0gggg888g8888gl&&cRRIR T T TTTTT TT]TV]]V]]]]]V]kkUkUU [*IDoRc[VTT]]g]I[ T%]-%4g-gSSjjR]%]]gg4g48g4888g8888:88::88:::8::UUA]]888888ggg--gggggg0&&&jZ]U]7:7::g7:g:gtNN]]", "MM[M[MMMM0M9M9099990999D059D0D99DMMM99M9990999D9ID99MMMDD[[ee[eDer[r[r{[{[**{*{{r{[{{{9r***YYhhYFFjQ&&FhR=Sx=;CCaSSC;aC;aSuuuuZa;u;SCbbCCCa;;aSaxaa;;;xxxSuuSSx;aualSSSuSuuuZuuuuuuuSjujjjlZQQlljulQZZZljlluSTYFFWFYFFFWWWj[[[[MTggggggg8g88g8888888llj=ccRI T TTTTTVTpT]T]T]Vp]]]]U]]]k][[0D=C*T%]TUVAkNcj[Tog]kgggccC&=V]T g4gg8ggg8g8888:88:888:8:88:8:Nk]kV88888P8ggggggkggg[j&jjZVAN:78778787:787:7:", "M0DIMM[MMMM0MM9M909999099D99990990DM90MM0DMM90DMMMMM9MMM[eee[eee[r{r{{********[{[{{{r{[***[FY&jhFY&&jYF&c=bS=uSbu==b=ZSbbaZSaSZZuZxuu;bbub;;;xxS;;llSZlxSSSSx;lQluSxuZuuuuuuuSxxSuuSSllulljujZljjjlullQZuQluS[YYFWFFWFWWWhS[*M[[ Ngggggggg8888888888jl&cccII* TT TTTTTVTT TT]]T]]]]V]]kk]k]UT[D{0boUT%]]U]]TU]k]TTT]]]g8cbbZl T]]-gggg4g84884888:88:88::88:8:8t]k]T888PoUgggg-ggggg8Pjj&jjUUUg7878787878787::", "IMM[MM0MMMMM90M90990999D9090MMMM[MM[MMM[MIMMM[[M[M[MMMM[Me[ee[e[r{[**[*0** [ ****{{[****** hh&&&FhYhhFFjR==babx;xxCbabbCZSS;xS;SubbZZZ;CbCCCbC;SxxZQQuQ;SuuxaSZZZaSuZSSuuuSSSSSSxSuxlljZjllululjlZuZQjQQuluSZTYhhFFWWWWWhla] *[Tgggggg88g888888gggjj&=cRI9 * * TTTTTTTTV]TVTVi]]T]]]V]k]k]M0D[IkVUT]sssVU@PUT]tVTUg]g[SZjj[*TT-g4gg-gg8ggg88g8888888888:8888V8VTg888UgggggggggUggojjlZZ N%N878787878878878", "[M[M[DMMM0M0MM9MMMM909909MMMMM[M[M[e[[e[e[R[[e[[[[e[[9eeeeeeer[**[*** *** * ******* * *[ *[&hhhhYYYhFYF&c====;;;CauuCCbbbbxbbb;ZSCZZxCb;;b;SSaauZC;;;ClZax;ZaSQQ;SSaaSSSSxxxxxxSxaSZQllllSSjllllluuulQZlujZjl YhhhYWWWWhQjl ]V M[ggggg88g8888ggggg-lj&b=IID T TT T TTTTTT]T]]TVT]]V]]]]]UT[90M ]kVVPsP@sPs%PsssTU%kkUDjlQj*[ g-g4gg4gg488gggg88888:8:88888:]%%UgggggggggUggggPggP&jl=S*tNP787878787878787", "M[M0M[[M0MMMM0M0M0MM999MM[D[[[[e[[[[e[[[[[[[{[r[{[{{[[[90r[[r9**[* [** 0 ** [ [ * * * *IjhhYhYYYhFFYZbb===;=CxCSbbbbbb;CC;bCbbbbZCxZ;;auSQubCCC;;aa;uQZxZSlxaSZxaxaaxxxxaxalZxxjluZSjjSuujxlZjlZuQjuZZujuQ]FFhhhYFWW&Zhj** [ [[ ggggggggggg-g--- ;Cj=cR[I* ToT T oT TVT]]]]T]]]]k]]]]90D* ]]%]Usss@osVUs@sso]UV][ljjjD[[T-gggg-ggggg4gg:8g8g88888888888UkgTggggggggggggggggPgZSCCZIg%]888878888788788", "M[MM[MM0DMM0M[DMMMMMMM0M[[[[[e[[[9r[[r[{[{[{[*[*[*[[***[*[**M0[*[** * * * * D[c&jj&YhhhYYYYuCbb======xbbS;a;bbbC;;;;;CCbbbQZuCC;C;aaa;aaxaxCZSSu;;aSxaSx;a;axaxxxaxllZSuuSlQulSlljllZjZulllQQQQjlDFFYYhYhWW&lFj[[[[ [*Uggggg-t---g-gU]gUcSZb=IDc * * * T TT VTVTTTV]]T]V]]]]kV[{ 0[TV]oo@@sPPsVP@@s@UV]UVDSZjjI [Tg---g-g4ggggg8gg8g88g888888888V]t@ggggggggggggggggggSljjj0UNV78788787887887:", "[M[M[M[M0M[MMM0IM0MM0[[[[e[[[[[r[[[{[[{[*[*[*[******0** I[* [ [[* [ 0* [ [ 0Icj&&j&Y&&Yhhh=bb;;bbb==bCabC;Zbbuabb;;;CbbC;C;;;CCbCCbCCC;xxaCSSuCa;xa;lCxxx;xxx;xSxuSSuZuSQjxxljlZlZlllullZjlllSZZcYYYYhYhhW&&F& * [oNNttgtgggggggggggbulCcRII[* [ o T o TVTT]TT]VV]]]]UV]U] [* N%TTPsosoVPVUsPPPV]]]V[jj&l0 ]]tgtg-ggggggg4gg488g88888888888kV%]gggggggggggggggggg=jjl&cNNU888788878788788", "[[M[[[[[[M[M0M9[MMM[e[e[[[[[{[*[[[D*[*[*[*[ **[0[ [[[[ [ [ * * * * I&&j&&hhhhh&&Zbbbb;bb=S;SSSbS=bCSSxCbCZSxaCbC;;;CCaSSZlQu;xxa;Cal;C;Z;ZaSSSxx;;xxuSxZxuuQuQxSxSuluSlZZZQSjllQZllxuZgYYYYYYhhY&YWjUUN%T * ToVggggggggggggggZjQ;cRI0 T TTTTTTTTTVTTT]V]]]]]]]][D[MTUUoTo@o@VVVU@PPo]]]]V%[&ljjI UTtgttgt---g--ggggggg8g8g8888888]]]Pg>ggggggg>gg>gg>gsjjjjjRtUP878887888878888", "[[0I[M[M[[MMM[M[[[[[[[[*[*[*[*[**00[* [ [ *[ [ [* [ * *[ [0 [ [ R&jj&&YYhYY&habbbbb===bSSa;;abbb=b=bbbbCxxxaabC;uuSxa;uxC;;uCx;lx;allCxSSSuSaSSSxSSuuxSxQlSxxxlZluulZjSuZjlZlZjxSSl%YYhhhhhh&hFWjUUUNV[[*@]Tggggggg>gggggVSllCcc99* [* TToTT@TTVTVTVTVT]]TV]V]]][[MD[V]kUNUVVU]U%VVU]]VVV%V &&ljI]* UN-gtgtgg-ggggggggggggg8g88888V]k]gggwgwg>ggg>gg>gg>I&&llc>TV888788878888787", "[[[[[[[[[M[[[[[[e[[[*[*[*[*[[ [ [*[ [ [ [ [ [ [ [ [ *0 o o o o o [c&j&&hYFYYh&&R==b=====SSSxxS=bbbbCbbbC;;CCCbbCbuS;SZSZbC;aCQCxx;CClx;xSSSxxSxSxxxxSClZxSaSZa;lSZlxuxSSxxSllljZSSSlZth&hhhYhhjYWW&UU%Uk[M[TVVVggg>gggggg>ggljl;Ic0I[ [ TTTTo T]TVT]]TV]T]]]]][[0[*T888888888888888888-VT@l&ZjM[ *UtgNgtgttggg-gggggggggggg88g88T]UP>g>ggggggPgg>gg>ggclSCcIU]N888888888888888", "[[{[[[[[[[[[[[[[[[[*[ [ [ [ [ [ [ [ [ [ [ [o [ o o o [o o o o o o Cjj&&j&YYYYh&0====abbbx=b;Cb====bbCbbbbCb;bC;bbCCZZZZZZx;Cu;;a;a;CZ;;SSSa;;xxaSxxxx;llxZ;x;SlZlluZZSxxxuZQllSZjZSZlThhhhhhYhjhWWjPUUUV[[ VVTNg>Pgggg>gggg>=jlcc9II[* oToT TVTTVTVTTTV]V]]]]U[M[M[P88888888888888888888]V;lZS[ okttgttgtgtg-ggg-ggg-ggg8ggggggU]TUUg>gPgPgPg>gPg>gPgoc==cIPVt888888888888888", "*[[[*[[[D0*[*[ [*[*[ [ [ [o[ [ [ [ [ [[[ [ [ o o o o oo[o o o o o o[ o ooo*b&jjj&j&&&Yh&_c==CbbbSxS;bbx==b=bbCbbbCbC;;;Cb;xSZx;;aZCC;Cxxaaa;ClS;aSxS;CxaxSxxaxxuQxSx;SQllllQluSuSuZZjlllZllxQZ]hhhhhYh&jFFFjUUUUV*[[TVVNPggg>g>gg>g>gZSb=0cRI[ [[ T T TTTTTTVTTVVT]V]VV]VT[[ [V88888888888888888888]VSZl=0[ T@tNNgtgttgtgtg-g-gggggggggg8ggU]V%PPgPgPg>gPg>gPg>g>oc=S=R%%N888888888888888", "[ [ [[*[[*[ [ [ [ [o[o [o [o[ [o o o oo o[oo o o o o oo o o o ooooooT ooTo oobjjh&hhhh&jjC[==bbCCCbS=SSCSS=====bbbbbbb=bCbbCuS;xu;CaCxZCSxC;Sua;xxaC;SC;C;x;S;xCCSlx;;luZlSS;llluuulllZZZllZ;lQZ]FFYYYYhlhFWWjVUUUV[[[ VkVVPN>g>gPg>g>gcCcIcRIIM o oToTVToTTV]TV]T]]]V]T9o[*Vggggg8g888888888888NVVSjScI[*oTtNgNNgNgNgtgtg-gggggggggggggg] UVVg>gPgPgPgPgPgPgPg[=CS=c>gV888888888888888", " [ [ [ [ [ [ [ [ [o[ [o[o[o[o o[o o[o[o o[o[o oo o o o o[ o o o o oTo To oooToToToQ&&j&&&&hhScc bbb=Cb;=bSb=xSab=bSS==uaSS;;CSS;uaZCSS;ZbC;CC;CuSSSZ;;;auCuSC;C;xaSxa;ClZ;;ZS;Z;SlZllZZllllZxZllu;;lZVFWFFFYQlFWWWjUPUU] [ Nggo]VP>g>PgPgPg>ISCcccII0 [ * o o oT T oTT VTTVVTV]VV]V]V[9M[Vgg8g8g8ggggg8g888888]V=lZxI*[ Vg>tNgNgNgtNgtttgggttggggggggggoUTVPgPgPgPgPgPgPgPgPs==C=Io]V@88888888888888", " [o[o[o[ [o[o[o[o[o o[o o o [o[o o o o [oooo oo oo o oooo o o o o o o o oooTooTooooTox&j&jj&j&lcRbrbx==CbbC==bC;xCC;b;axSC;;;SxS;SxSSSSuSZZZaSZxuZZZbbC;;ZSxZxZxCC;;xSSxaaaQ;aZxxxxSlZZZlZllZlZZllZCxlZZ*YFWFF&lhFWFWjVUUPV[0 ggtVoVUgPgPgPggPgClj;cIII* [ * T o T TVTTVTT]V]TVpVTV]*II[Tggggggggg8ggggggggg8P]ClSCc [TNtNgN>gNg>gNgNgttgtggggggggggg]%VVNPgPgPgPgPgPgPgPPgC=cCC0V]V88888888888888", "[o[o[ [ [o[ [ [ [o[o[o o[ o[ooo[ o[o[o ooo o o oo ooo o o ooo ooooooooo*o ooooooVooooQh&&&jjjl==ajIb==C=b=;=;C=;C;aCaCabbCSSZ;bbx;SS;CC;bbbbbxSuSxxZb;aaCZZx;auCC;;;;xSS;xCZSCuau;ZZZxZZ;;ZZlllSlSxx;SaZVYFFWYl&YWFWWjPU]]][[ g>NoU]V@gPgPgPPg@CjjlRc=I[[[ [ [ o o TTo oTV VTVTVTVVV]T 0[0[Pggggggggggggggg8gggg@VcjZZc[ [ N>gNNgNNgNtNgNg>gtggtgtgggggggU]UVgPgPPgPPPgPPPP@PgPZZCCZDVVV88888888888888", " [o[ [o[o[o[o[o[o[o [o o[oo oo o oo ooo o o ooo oo o o o oooooo ooo o o o o[oooToVoVToTo[j&hh&jjjuaSj&9=c;=bC;;====xSCb;xCbbbbSSS;bCCub=bbCCCbbxZCuCSC;ZCCCC;SZZSaZCCC;;;xSxS;CSZ;lxxQZlS;xlxxClllZZSZSCSSlZ hYWFjjYFFWFFjVUPUoT otgNV%PPVPgPgPgPP>cljScIRI0[ [ [oo T oToTTT oTVTVTVVTV]TVVTD0e[Vgggggggggggggggggggg@VISS=C[ [ >NNNg>Ng>Ngg>gNggNg>gggtgtgtggUVVoPPPPPPgPgPgPgPgPPgcZZCSIVTVgggggggggggg8g", "[ [[[[ [ [o[o[ [ o ooo[o[o[o[[o o o[o o o o o[o o oooooo oo@oooTo[ ooToo TooooTooToo@j&j&h&jjuSjjlDcC=;x;xa===bCCx;C;bbC;xx=;b;uSb=Cx=bC=xSSSS;ZZSCZZ;ubSuuZZxCS;C;;;xxxCx;;QSCSlZSxuS;ZSSCSZCClZZZSSllSVhh&&jhFWFFWFjP]VU][ og>googV@gPPPgPPg>cllC0ccc[ [ [ o o ToToToTVTVTTVVTVTV 90D[@gggggggggggggggggggg@oI=ccCToo NNg>NNgNNg>NNgNgNgNggNg>gtgtgtUoT]PgPogPPgPPPPgPPgPsIZZSSIVVV8g8gggggggg8gg", " [o[o o[o[o[o o[oo[oo[o ooooooooo o oooo o oo ooo oooooo ooToooVoo@o ooooooooTooooTo@T@j&&jjjjlxuh&jIc=abC======CCCxbbbCabSSSCbxbbSSCCCS=bbSx;SCCbZCbbuxSCCSCZZCC;CC;xax;x;xCCZSCSZZSxlSSxSlCxSCC;SZ;ZZZlZ]&lSjhFWWFFFFYP]P]@ 0oN>N@oNPVPgPgPgPPg0lZcIcII0 [o [ oTo ToTVTVTVToVTTVV]V I00 @tg>gg>gg>gg>gg>ggggg@VIC=c=V]VV%NNNN>N>gNgNg>Ng>gNgNgNgg>g>ggVo]VPNPPPgPPgPgPgPgPgPICCCZc@Vogggggggggggggg", "[ [o[ [o[ [o[o[[ o oo o o o o o oo o oo o o ooooToooo@oooVoVo@oo@T@TVoVoooToVo@@@V&jj&jj&jZajjZI=CCC=bc===bCaCxxCCbCa==CCb=bC;==bCb=x=CSCSZCxbbCbSZSubSCZCCCbbC;x;C;;x;xCQZCCSlZZZZZZS;ZZllZZZSSZCCCS jjul&hYFFFFW&P]V]o[0ot>tooNo@gPgPPPgP@IcIc0ccIM[ [[ o o o o oToToTTVTVTT@TVTVo DM[ @>gg>gg>gg>gg>gggwg>gPV0=Cc=o oN>N>NNNNN>Ng>NgNg>gNgNg>gNgg>gTo @NPNPgP@PgPgPPgPPPo0C=CCCVV@gggggggggggggg", " [o[o[ [o[o [o[oo[ooo o[oo o o oo o oo[o o o oo ooooooooT@T@oo@oVT@@@@ooToV o@T@oV@[jjjljjlu;au&&cCCC==Cc=cCxxC==C;CCb=;;=b===Cbbb=b=b=bb=SxCbb=bCCx=;CbbZSbbb;bC;;x;C;;xSaCZZCxZZSZZZZSSSSZSZZSlSxC;;Z[jljjj&hYYYFFF@P]PUV[ >N>VVg@VPPgPgPgPgIIcCII0D[ [[o o o o oToT@ToTVTVTVTVT 00[ ogg>ggPg>ggPggPg>gg>g@V0cZC=[[[o%N>NN>gPgNN>gN>N>gNg>gNgNg>gNgoTooPNPPPNPgPPPgPPgPgP0CSCC=ooVggg`ggg`ggg`gg", "o[ o[o[ o[o[[o[0o ooo[o oooo oo oo o o o oo oo o oooooooVoVo@o@oVoVo@Vo@oV@@@@o@oooVV@oV&jjjjlbcal&&jRCCc=;=bCaaCCb==;;x==b=======b===b===b=b=Z==bbCCbx;CbCbCZxCbCbbb;aC;CCC;xx;SZZZSZxZZZZZZSxSSZZZSZ;CClSMQj&hhh&&hhYFhVVVVV[[oN>NVPNPPPgPPPgPPPcSZ=I0II0 [ o ToTo ToToTo VooTVVoVT@I0D[@og>gPggPg>gPggPgg>gN@T0ClCC[[*oNPNPgPNNNPgPN>NNgN>N>g>g>Ng>gNV oT@PgPNPPPgPgPPgPgPP0CSZ=C@T@g>ggg>ggg>gggg", " o[ o [o o o [o oooo o o [oo oo o0o o oo oo oooooVT@oVo@oVoV@T@@@oVoVVT@@V@V@VV@@@VIj&&jju=bj&&&Scb==;b=bc=;xx;bc========Cb===b=bb=bbb=CSSSCSbbb=bSSCCCbC;;SbbbCC;;aCbC;CCCCCSCCZCxZSZSZZSCCSSC;lZSCSZS l&&hYYYh&YhF&@VV]V[ [>NP@oPVPNPPPgPgPgcZZ=III0*o[[o[o [ [o o oo @ToVToTToTo]oVT0I0 o@>gPggPgPgPgPggPgPg>Po SCC=[ [ PNNNPgPNNgPgNNgPNg>gNPgPgN>gNgPVooVUPNPNPPPPPPgPP@Pg0=S==CoPPgg>g>gg>gg>g>g", " o[oo[o[ o o[o[[o o o o o oooo[ o0[ ooooo oo oo oo[oToVooo@oTVo@Vo@@@T@VVVV@@@T@@V@T@VV@@DjljQj;=Sj&j&Q==b=c=cccC;c================b===b=b=xx;Cbb=;Cb=xSxSb;;=ZC;bCbCCbbCCCCCCbCbCCSCZbxZSZZZSS;;;ZCx;CxSZZSZt&hhjhYhhh&&YYVVVPVo0oPPN@VNP@PgPgPPPgPIZZCI0IR0[ [ [ o[ o o oo oT oTooToTVoTV@TVVT0D0 o@PgPgPgPgPggPgPgPg>N@@@=C=C0[o NPNPNNNPNPNNPNPgPNPgPgNNgPgN>NVVo]VPNPPgPNPgPgPPPP@Ps=CCCC[VVogg>gg>gPgg>gg", " oo oooo o [ oo o[o ooo o ooooooooo ooo oo [o o oo@ oVoV@@@T@oVV@@@@@@@To@@@@@@VVVVoV@IjjjZ;bx&hhhhxcccccb=C;b=====================b===CbCx===SSS;CbSbS=;bCSbCbCCCCbbbbbbbCbbSbCuZuCCCxSSxCx;;;SuCx;SS;xxSVhhh&hYYhhh&Fh@VVVV[ oPPP@@PPPVPPPgPPPP0SSCcIIc0[[o[ o[ o [o oo o oToToVToToVToVVo00Doo@NPgPgPgPgPPgPgPgPgP@Vo====0 oP%PNPNPNPgPNNPgPNgNNgPgPNgPgPgVo VVNPNPPgoP@PNP@NPPPPII=ccoVVV>gPgPgggPg>gP", "o[ o[ o0 ooo o[o ooo o o ooooooooooooo o ooooooooooooVoVo@o@VVV@T@V@TV@@@@@VVVVV@V@V@VIjja=cC&hYYYh=c==cc==CbCc==c=====b===b===;b==CCb;======bC;SSSCCxSbbbCCS;bbbbbb;CbCbbbCCSxSSZCCbCCSS;;;;CaSZSZZZ;C;;x hhhhYYhhYhhFh@VVVP[[ PNPo@N@@NPPgPPPgP0=SCIcIII[o [o[o[ o o o o oooTooToToTooVo@TVVe00 0ogPPgPPgPgPgPPgPPgP>@oo====0[o P%NPNPNPNNPgPNNPgPPgPNPgPN>NNNoV@ooNPgPgPPNPgPgogPgP@II=cI >V@>gPggPgPgPg>g", " oooooo oooo ooo oo o oo oooo oooooo ooooooo ooooToVT@V@oVoVoVVoo@@@@@@@VVVVVVV@V@VVVVVVVcllcRbZhhYhYYC===ccc=cC======c=====b==bc;aSC;a;==bbbb====CSS=;SCSC=b=S;C=CbCC=C=SCbbCbbCSZxS=CbbSSCCS;C;a;SZSSS;xSxxc&hhhhYhhh&hF&@@VPV[o[PPPo@P@@PNPPgPgPg0cSCcIII0 [o o o o oo oo oToTooVoVooToVT@VT0D[ [@PPgPPgPPPgPPgPPgPPgP@@ccc=0 [oUPNPNPNPNPNPNPgPNNNPgPgPgPgPgPt@oVoPPPgPgPgPPgPPPgPPPIc==c0@VPgPgPgPgPgPgPg", " o o o o o o o o o o o o oooo oTooooToo ooToToo@oo@o@Vo@VV@VV@T@VV VVV@V@V@VVVVVVVVVVVcl=I=SjYhYYhYCc=ccc=ccc=cc==c===c====c=;;=bC===b==b==bCb===CCSS;=SbCCCb=C=bbb==b;b=b=C=xZSSbCb=CSS;C;x;SZSS;xSxSxxSS j&hhhhhhh&&hj@VV@@o@oNP%ooPVPPNPNPPgPPIcC=cIcII[o[o[ o[o oo o ooooToToTVoTVoTVV00[0[ogPPPgPPPgPPgPPgPPgPPPoIIIcI [ooUPPNPNPNPNPNPNPNPPNPNPNPgPNP>NoVVogPgPPgPPgPPgPgPPgP0ccc=IP@VPgPgPgPgPgPg>", "o ooo o o ooooooo o o oo[ooooo0ooooooToooooTooooVoV@@T@T@VV@@T@@VVVV@o@VVVVVVV@@VVVVVVVVP=ScRblhhYhhYhR=c===c==cbccc=c==cc==c=====C=======bbb=b=bbCxCCSSSCSCCbb=b=C=b=bb=Z=CbCC;xCCS=;Cb=SSCxS;SZS;SCSSSCS;SCI&&&&hh&h&&&ll@@@@@o [PPP@VN@VNPg@PgPPg0=C=IIII0 o o[o oo o oo o oTooooo@T@oo@oV[[o[ @PPgPPgPgPPgPPgPPgPPg@@0I00Io[ooUP%PNPNPNPNPNPNPgPgPgPNPNPgPNPoVVoPNoPgoPgPgPPgPgPP0IcIIc0o@VgPgPgPgPgPgPP", " o[o oo0 oo o o oooooo oooooooTooTooo@[o@TVooToT@oT@o@@@@@@T@@VVVV@VVVV@@@@VVVVVVVVVVVVVoI=IcC&&hh&hhY=c=ccccc=cbc==c=cc=c=====c=C======bb=bCCbbb==;bCSC;bS=CbS===SS=b=b=;==bCSSSSxCbCCSSSCxZCCSZSS;CSS=C=C=b &&j&&&hh&&lCc@@@V@[ooPPP@VP@@PNPPNPPgPo=CCIIII0[o[o[oo[oo o oo ooooooooooToo@oTVV@ [o [@PNPPgPPPgPPgPPgPPgPPPo0III0o PP%PPPPPPPPNPPNPPPNPPPgPNPPNPNV@V@gPPgPPPgPPPPgPPgPP0I=III@@@PgPPPgPPPgP>N", "ooooo oo[o[oooooo o oooooooooooooo@o[@oVooo@To0VoV@@T@V [@@@VVVo@VV@@@VoVVVVVVVVVVVVPVVVVIIR;Sh&h&&hhYc===cccc=cCccccbcc====c===c=x=======bbbbbb===bbC==S=x=S=;==CbxSS==C=;C=CSSSCCSCCSSSCSSSSCbCSCSSS=CbC=CbI&&jhhhh&hYZ=C@@@@P[o[PNPNPgPPPPPgPPPPPo==cIIII0[oo[o[ooo o o o ooo oo ooToooVoT@@@V0[0[oPPPgPPPgPPgPPPgPPPPgPP@0cIIIoo0oPUPPUPNPNPPPNPPNPNPPNPPPNPgPPNP@PoPgPPgPgPgPPPPgPPgPo00cI0o@@PPgPgPPgPPgPg", " o o ooo ooooo ooooooooooooToTooVoooVo@oVoVoooTVo@ o@V@@@VVVVV@VV@VoVVVoVVVVVVVVVPVVVVPVV[I=S&&&&h&&Yhccc=cccc=cc=ccC=bc=b====c==b=c============b=bCC;CCx=C==Cx===CCxCS=bbSCCCCSSCCCCSS=SCCCS=SSCS=C===CbbC=CIh&&jhYhhh&Sj&P@>>P>PwPwPP>PP>>PwPPsgwso==III0I0o[oo oo[ o[o oooo ooooo@ooo@oo@@@V@V0[[[[P>PPPgPPPPPPgPPPPgPPN@@0cII0@oVoPPPUPUPPPNPNPPPPPPNPPNPNPPPNPPPVoPPPPPPPgPPPgPgPPgPP0I0II0PP@PgPPPgPPgPP>P", "s@s@s@ssssPPs@sPs@sP@PPPPPPPPPPPPPPPPPPPPPPPPPsPPPPPPPPPPPPsPPPPPPPPPPPPPsPsPsPsPPPsPPPsPIcbljjh&&&&hhcccccccccc=cb=Cccb=cc=c===c===c=======bb=b===CCS=S=CC===b;===CCS;CCb=CCCxCSCC=CCCSCSC;CbSC====CCb=bbbC=[&&&&j&Y&hj&h&w``+``g``sw>swwPw>PgswPswoIcc0II0Ioo [o[ooooooooo oooooooooooVo@oo@@o@o[[[oswswPsPwPP>PPPgPPPPgPgg@ssPggggggNggggw>gwgw>ggwwgwggwggggwgPP@o@oPwPgsPPPgPPPPPPPPP@00I00@P@PPggPgPgPggg>", "PsPPsPs@P@PsPPPPPs@sPsPsPPsPsPssPPsPPP@PsPs@sPPPPPsPPsPsPs@sPPsPsPPsPsPs@sP@sPPPsPsPPPPPP=SQljl&h&hhhhIcccccccccc=ccccCCccc==cccCCc=====c====b====C==C=;CCCC==C;====;CSC=C=SS=CSCCbbbCCCC=CCCS=C==b=b=b===C=bP&&&&ljj&&hYFY+y,,+,+````+```g`y````g`w$00I0I0I00o[oooo[o oo ooooooooooo@ooVoooo@oV@o0[00wPwPwwPggg>gggwggggwggwg>gwg`>`wwywqwwwywyw`yyw``yyywyyww`yyygyy>yg`gww>ggPgPPPgPgPPPoossPPgPggPgPgPgPgPPN", "PPsPPPPPsPsPPsPsPPPPs@PPPPPPPPPPsPPssPsP@PPPPsPsPsPPs@Ps@sPP@sPPPPPsPPPPPPPPPsPPP@sPsPsPsujl&ZZlh&hhhhIcccccccccccbCCCcccc=cccccbC=Ccc============c=CC==C==b==cC===CSCS==b=CSCSCCCCS=CSSCb=C=====b=C=b==CCCC=Nh&jjZCCjh&&&j,,++,`,+++,+,``++,`y`+,++`,E,E$@ooooo[oooooooooooo ooooooo@ooo@@@@o@@o@[o@@>gwgg>gw>gwgw>gwgwg>gwgggwyqyyw`>``wy``w+yywyyyywgygy+yyyyyyy`>``yygw`y`wgwwggwwwgwgywwwgPgPgPPgPgPgPgPgg>", "PsPPPPsPPPPPs@sP@s@sPPsPsPsPsPPsP@sVs@sPssssPPPPPPPPPPPPss@sssPsssPsPPPsPsPsPPPssPPPPPPPs&h&lZZjjh&hhhIccRccccccccc=cccccc==bC==Cc=bc=cc=cc=======c==C===C;=c==C==;==CC===b=C=CCCCC=;CCb=bCCxb=========CC====0YYhjSSSj&&jh&,,,++,+,```,+`+,,+```,++,+,,+,,+,,+,$y+[ooo[ooooooooooooo@ooo@@oo@osg>>>`>wgwgwgwg>gwgwggwg>gwgwgwEEyyyyyyyyy>w`wyyyy>`w`yyyyyq,yyy+yy+yyyyyw`w`w`ygw`y`w`ygyyyw``ywwg`wwgwwPgPPgPgP>", "PPPsPsP@ss@sPsP@sssPPPPPPPPPPPPPsPsPsPs@s@s@sPsPPPPsPsPPPPPPPs@s@s@sPssPsPsPPPPPPPsPPsPs0&&hjjllZjh&h&IcIccRccccccc==cccbCbc=cccccbcc=c=cc===cc=c=CCc=c=C=C=c====cCS=======c;CCC==C======CCC=;SSCCC==b==cSCCCUYFhjZCjhh&&Yj,,,,,+++,,,++``,,++`+,`+`,,++,++`++``+,+,y,++qoooooooooooo@ooo>>>N>>>g>g>>g>gPgPgPgw>wgwgPgwgwwwq,Eyyq,wyywyyyyqyyyyyyyy>`w,yy`wyyyyyyyyy,y`wyyy`wyyyy`>`wyy``y`>y`y`wy`gy`wwwgwwgwg>", "sPPPPPsPPss@s@sssPs@sssssPsPsPsPsPsPsPsPsPsPss@ssssPsPsssPsPsPsPsPsPsPPPsPs@ssss@sPss@sso&h&h&lZZj&&h&Icc=cIccIccI=c=======c===b==cc=c=cc=c=c=c=ccCcC==CC=C=C=c=c=C=cCC=====c====bCC=======CCCc=============CohYhjSZ&&&j&Yj,,,,,,,,,+,+,,+,,``+++,,`,+,`,+,,``,,+`+`+++,,,+ywy,oooo@s>>>>>>g>>>>w>sg>>>wg>>wgwgwgPgwgwwwww,EE,qywyqywyyqyEyyyyyyEyq,wyyw,wyyyyyyyyyyyywyy,ywyyyyyw`yyw`wwwyywyww`wywywygw`w`w`wy", "sPssPsPPsPPssPsPPsPPsP@s@ssPsPs@sP@sP@sPsPsPPsPsPPsPsPsPPsP@sP@sPs@s@s@s@s@sPPPssPsPPsPsI&&&&&jZZjjh&hIc=cccIccccc=cccccccc=c===ccccccccccc=cc==cc==bc======cbcb=cb=====ccc==c=C=C=C=CCC==CbbC==c===CC===CCCC0Yh&Sjjj&&&j&&,,,,,,,,+,,,,,,,,,,,,,,++````,,,+,,+,``,`+,`,`,`,```y+++y>>>>>>P>>>>>>g>w>gPgswgw>gPgwwwwEEwqyqwqyqwyEE,EEyE,qyyqywyq,EyE,wyyyy,Ey,Eyyyyyyyyyyyyyyyyyyyww`y>+y`w+yy`wyyyy`w`wy`ww`>`w", "sPs@s@sPs@sPs@Ps@s@s@PsPsPPsPsPsPsPsPsPsPsPs@s@s@s@s@s@s@s@ss@sPsPsPsPssPsPsPssPPPPPs@ss0&&&&h&jZljl&lIccccccccIc==ccc==ccc==ccccccccc=ccc=cccc=ccc=====c==c=c=Ccc=cc==cc==ccc=CC====CCC=C=C====CC;CCCC;CCC==oYhjZhhjj&&j&l,,,,O,,,+,+,,,!,,,,,,+++,,,,,,+,,,++++,+,,+,+,+`++`++++````gy>Pg>>w>>PwPgwPw>wgPg>w>wEwqqEEEEEEEyqEEwwyEEEywwyqEywyE,EEyyq,qyEEE,Eyqyyyywyyyw,Eyyyyygyyyywyyw`yyyyyyyyyyyyyw`ywyyywgy", "PsPsPs@s@s@s@ss@sssss@ss@s@sPsPPsPsPsPsPsPsPsssssPs@ss@ss@s@ss@s@s@s@s@ssssPssPsssssssss0&j&&&&jZSjZlZIcI==cc===ccccc=cc===ccccccccccccccccccc=cccc==c==C=cC=cc=====c==c=c=c==cC==C=c===CCCC=CCCCCC====CC=c== hjS&hhhj&&h&j,,,,,y,,,,,,,,,,,,,,,,,,,,,,,,!,,,,+`+,,,++,,,+,`,++++++,++g,`+,``PgPwgPPPgP>>PwP>swq$$E$EEEEEEwqEEEEEEEEEEEEEE,qEEEE,wwEEE,qyyEEE,EyqEywyqyyyyyyyyE,wyyyyyyqwyyyyyq,y,wyyyyw`wyyy`wy", "sPsPPsssssPsss@s@s@@s@s@s@ss@s@s@s@s@ssssssssPsPsPssPssPsssss@s@s@ss@ss@s@s@s@s@s@s@s@s@0&&&j&hjlSZZS=IcI==cc==ccccc=c=cc=cccIccccccccccccccccccccc==cccCcb==ccc=Cc==c=ccccccccC====CC==CcC=CCC==CCCCCCCcc=c=0&CZhYhhh&&&&&,,,,,+,,,,,,,,,,,,,H,,,H,,,,,,,,,```,,,`+`,,+,+``+,+,+++,`,+`,y``y`w``Psgws>w>PgwwwwE$wwq$EEEEEEEEEEEEEEqEqywqEEEyEEEEEyE,EqwEE,E,EEEyyqyEqyEqyEEyEyEyyEywyEyyyywyyywyEyyqyyyyw`ywwyy", "ssssssPsPssPsPssssssssss@s@s@ss@ss@ss@s@s@s@s@s@s@ssPsPsPPsPsssssssPssPsPsss@s@s@s@s@ss@0&&j&j&jSCZjZcIcIcccccc=ccccccccIccIccccccccccccccccccccccccC==c=cC=cccccCcccc==ccccc=c====C==ccc=c===c=C===CC===cc==[==jhhhhhj&h&j,,,,,,,,,,,,,,,,,OE++,,+,,,,,,,,,,`,+,,,+``,,,+`+,``,,`,,,`++,,```y``y`y`y>PgPss$$$$$$$$E$E$EEEEEEEEEEEEEEEEEEEEEEEEEEEEqwEEEEqqwEEyEEEEEyywyEE,qE,EywEyE,EyywyqyE,wyq,qyyqqqEywwy`w>", "s@s@s@s@s@PsPsPsPPPPPPPssssssssssPssPsss@s@s@s@ss@s@@s@@s@@s@s@s@s@ssssssPsssssssssssss$IZj&j&j&ZZZjjIIcI=IcIcccccIIcIcIccIccccccIccIcccccIc==cccc==c==c====ccccc=cc=ccCccccccc===cccccc=ccCc==c===c====c=c==ocC&&&&hh&ll&&O,$O,,,,,,O,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,`+,+,``+,++,`+,+y`+`y`y`y`+y`w`y$$$$$qs$E$$E$$$sE$$E$qq$EEE$EwEEEEEEEEEEqEEEEyEEEEqyEEEEEqwyEEqywqyEEEyw,qwywwyEyyyEEw,wywyq,yyEyywwwy", "s@s@s@s@s@s@@s@@s@s@s@s@s@sssPsPsssssssssssssssssssssssssss@s@s@s@s@@s@@@s@@s@s@s@s@@s$$IccSSCl&CI=CZIIIcccccccIcIcccccIcIccIcIcccccccIccICcccc=c===c=c=ccccccccc=cccc=ccccccc=====ccc=cccc=====C===c==cC===cocj&&j&&hhjjj&$,,E,OE,,,E,,,,,,,,,OE,,,,,H++,,,,,,H+`,,,,,,+,+,,,,,,,,,,`+,++`+y`++`y+`y++````y`w$$$$$$$$$E$E$$E$$$$Eq$$Ewwqwq$EEqEEEEEEEqEEEqqEqEEEEEEwwqyEEEEEEEEEEyEywywE,EqqyyywqE,qEEEyywqyywy", "s@s@ss@s@s@ss@s@sssssssssss@ssss@Ps@sPsPsssssssss@s@s@s@ss@s@s@s@G~G!!H~H!!H!HH!!~!!GH!O!GGGOOOOOOOOOOO,!!!O!G!O,O$$OBBBBB0000000IcIIccIcccIcc=c=c=cc=cccc=cccIc=cccccc==ccccc====ccccccccC=Cc=c==C=C===c====@=&&&&&&&h&Zlj$O$O,$,,,,,,,,EO,,,,E,O,,,,,,,,,!,,,,,,`,,,,,,,,,++`,+,,++,,,+`,+,+,+++`y``y`yyy+w```+$$$$$$$$s$$$$$$$$$$$$$qsqqqE$E$E$E$qwwEE$EEEEEEEEEqEwwEEEEEEEqwyqwwEEEEEEEEqEEEEEEwwyyyyEEEEy>w", "sssss@s@s@s@s@ss@s@@s@@s@@s@s@@s@s@s@s@s@sPsG!!,!!!/~!OGO!HGG!!G!!!!!H!!!!!GOG!G!!!~~~HOH,!,!,!,O,G,!,!!!,!,~,!HG!OOOOOOOOOOOOOH!~~~!,~,$OBBBBB0IIccccccc=cIccccc==ccccccccccc==c=cc=c======cccc===c=cccc===c[=jh&&j&&&&&&j,$,$,,,O$,O$O$,,,,,,O$,,,,,+,,,,,,,,,,,,+,,,H,,,,,,+,,,,,,++,,++,,+,,,y++,y`y+++``yy`yy`yy$$$sE$$$$$$$$$$$$$s$$$$$$$$$$EEE$$Eq$E$E$E$E$EEwwqEEEEEEEEEqEEEEqwEEEEywqEqqqEyEwwEEEEyw>yE", "@s@s@s@s@$@s@$@s@s@s@s@s@ss@sEE!/!HHHGH/~O!OOGH!O~/~~~!,OOOH!HG!!H,OOOGOOOOO,!~+//`/K+~`//!!!!!!!~!OG~~~!!////H!!~,O,OGO,O!~~,~!,H,!~!~~/`,OOOOGOOO$OBBI0IcccIccc=IcIcccccccIcc===cc====cIc=c=====Icc=ccccc==oSj&h&&j&&&&&j$O,$O,,E,,$,,,,,,,,,E,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,,,+,+y`,++y`,,+y`+yy,`y`+yyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$E$$$E$E$E$$E$$$$qEEE$E$$EEqEEwwwwwqEEEEEEEEEEEEqEEEEqEEqwww", "ssssssssss@$$s$s$O,G!G!GO~`~HOO!!!!OG!H!!!!,~!HGOOOOGGOOGOO,OGGG!!GO,O!G,O!HGG!HHOOG!!H!!33!3!!!!!~!!!H!~!~3!H!,!!!O!,~~/~//~~~!GO!~~~////!O,G,!~!O!,OOOG!~$$B0I0ccccIccI=cc=cc=cccccccccccIccccc==cccIcI====0Slj&&&&&&&&j&$,$O$$OE,,,,,,,,,O$,,,,,,,,,OE,,O$OE,,,,,,,,,,,,+,,,,,,,++,,,++,,,,,,,,,`,,,y`y`yy,+`yy+y+y+y+yy,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$E$$$$$E$q$EEq$EEE$EEEEEEEEqEEEqqEEEEqEEEEEwwwqEqwqw", "s$ssO$OOO,GHOOO!!OOO!HH~/OG!!~~~~!!!!~!GOGH!HGGOOG!HOOOOOG!!!!!!!!~~!!!GG!!GOO!!~HHHHHGGGGOGH!~!,H!!!!,!G!~~~/~~!!!~~~~~/~~~~~!~~~!G!!!~//`/~!OG!~,~!~~/+~K,OOOOOO$$B00cIcccccc=IcIccIc=IccccIcccccccIcc=cccc0ZZZjjZjj&&&&&$O,$,,E,$O,$O,,,,$,$O,,,,,$O$,,,E,,EO,EO,,,,,,,,,,,,,,,,,,,+,,,+,,++,,,yy,,,,,,,,,+yy`,`y,y`,yy`yyyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$Esw$$$qw$E$$$$$qqEwwE$E$EEqwqEqqEEEEEEqqqqE", ",,,,,,y,,y,```yy,,y,,+y,,,,,,,,,,,,+,,,,,,,,,,,,,,,+,,,y,yy,,,y,y,y,+y,yy,yy`yyyyyy$$$$$$$$$$$$$$$$$$$$$$$sq$$$$$$$$$$ws$$$$$$q$$$E$$$w$$$EEqE$wqEE$ww$EEqwEEEEE", "OOH!/~~~!OHHG,OOOOOOG,!OOOOOOOOOOOOOOOOH!~~////~~~H,GOOG`yyy`y`yy+y+`y++``y+y+``y++`>`y`yy`yy+y,yyy`>+y+y+y+`y,,,,,,,,,y,y,,,,,,y+,,y,,yy+,y,y,yyyyyyyy`>yyyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$sqs$$$$$$$$q$$$wq$$sq$q$$w$wq", "~~HOOOOOOOOOOOOGH!,~~!!!OOOOOGHHH`yyyyy`y+y`yy,y+yy`yy`y`y`+++yy`+y+y`y+y`+y``+y``+y``+y+y`yy`y`y,y`+y,+,+,,y,y,+,yyyyy,y,y,,y+y,+yyyyyyyyyyyyEyw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ws$$$$$$$$q$$$$qsq$q", "OH!!OOOOGHOOOO!HHGOOOOOOH,!~~!GOOOOOOOOOOOH!HGOOH!!!!!!!!H!!!~!~!~!!!!~~K/~!!!H~/~//~!!GOOOGOOOH!~~3HHOOOOOGGH!~//~~~//~!HGHHH!!!!!!~~!!!HH!3KK~!!3~!OGOH!~!~!,!~H33~~~!,//~!~/!G~~~,!`,!OOO,O0cCCSZCCZSZCSlZCZCZZCCZCZCCZl$wyyyyyyyy`yyy`yyy+`>+`yyyy`yy,yy,`y+`y`y+y``yg,+y`y+y+y+``y,`y`y+y+y`y+y+y`yy,,,E,,y+y+,,y,y,yy,E,yy,yyyyyyyyyyyy>qy$$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$q$$$$$$$$$$$qs$$$$qsws$$sqsqs$$$$", "!!~!!OOHO,!!G,~~!!OOOOOOOOOOOOOGOOOOOOOOOOOOOOOOGH!!H!HO!HH!!~~~!!!!3~~K~K33~~~~///~~!!!!HG`yyyy`yyyyy``y`+y```yyy+y``y`++y``gy+yyyygyyy+y,y,,yy,y,,,y,y,yy,yy,yyyyy,yy>yyyywyw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$$$$$q$$", "K///`/`////~~H!!H!!HGOOOOOOOOOO!~~~!!GOOGHHH,G!~~~H!HGGGHG!HH!!3~~~!!!!!!!!!~!~~~~~~~~/~~HH!3!HGGOOOH`y`yyy`y`yyyyyy`y,y`>+y`yg``yyy+y`yy`yy`yyy`>`yy`yyyyyyyyyy+gy`y,,y+y`yy,yy+,E,E,E,y,yyy,y,y,yyyyEyyyyyyyy>ywwww$$$$qs$$$$$$$$$$$$$$$$$$$$q$$$$$$$$s$$$$ws$$$ws$$$$$$$$$$", "33~K~~K~3y>yy>`>y>yyyyyy,yyyy,yyyyy``y`y`y`yy``yy`yyyyyyyyy+y,yyy,y+y+y+y,yyyy`y`y`ygyyyyyyy,yy,y,y,y,yyyyyyEy,yyyyyEEyyEyyy>ywqqq$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Esq$$$w$$$$$$$$", "OOGHGGOOGHH!HOOOOOOOOOOOGOOOH!HGHHH!HGOOO!~~~~~!~!OOOHHH!,3!!!!~~3!!GOGOOH3/~~33!!!!GOOGH!~~~///K~3K~~~~!GO!!`yyyyygyy>gyyyyyyyyyy,yyyyy>yyyyyyyy`yyy+y``y+y+y`yy+yy+yyy+yy+y``yyyyyyy,y`yyy`yyyy,yyyyyE,y,E,E,EyyEyyE`yyEyEywyEywywwww$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ws$s$$$$$$", "GHyy>`wyyyy>`yy`yyyyyyy,yyyyy`y,yy+yyyyyyyyy,yy,yyyyyyyyyyy,yyy`yyyyyy`>`yy`yyyyyyyyyyyyyyyyyyyyyyEyy,E,E,EyyE,EyyEyyyEEyqyw>yqw>qE$B$$$$$$$$$$$$$sq$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$$", "OOOOOG<<ywyyyyyy>`>yyyyyyyyyyyyyyyyy,yyy,yyy,yyyyyyyyyyy``>,yyy,yyyyy,yyyyyyyyyyyy,yyyyyyyyyyyyyy>`>ygyyyyyyEyyE,EyEyqyyEyyyyqwywwwEwwwwwE$$$$$$$$$$$$$$$$$q$$$$$$$$$$ws$$$$$$$$$$$$$$$", "H!<222~333yyyyyyyyyyyyyyyyyyyyyyyyyyyyy>`>yyyyyyEyEwyywywwyEwwywyqwww>Eqwwq$$$$$$$$$$$$$$$sw$$$$$$$$$$$$$$$$$$sqsws$", "2322!HOOOOOH!ywyyEyy>yyyyyyyyEy>yyyyyyyy,E,Ey>`yyyyyyy,y>`wyyyyyyyy,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyEyyyyyy>ywywyEyyEEEyqqyqyqywEqEywqw>wwwwqw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$$$", "OOOOOGH!!23!wyyy>wyy>>EyEyyyyEE,EyyEyyyEyyyyyyyyyyyy`yyyyyyyyyyyyyyyyyE,yyyyyyyyy>yyyyyyyyyyyyyyyyyyyyyyyywywyyyywyyyyyyyEyEyEEqEEEwwwqwqEwwwwww$>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$", "HH<yyEyyE,y>`wyyyyyyEyyqyyqyEqyqyw>yqywywyyqqq>wwqywEEEEqEEEywqEEwwwwww>www>$sw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "GGGHHHHHHyqyywyyEqyyEEyyyyyEEyyyEyEyyEEyyyEyyyyEyy,yyEyyyy>yyy+>yyyyyyyyqyyyy>yEyEwyyqyyyqyyqyyyyqywywqwywyywywywywyEqyEqwEqwwEqww$q>qsqwqPqs$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "OOOOOGHGOOOGHGHHyqyw>ywqywyqyywyqywywyyyEyE,qEyyEyyyyyEyyyyE,EE,yyyyyyyyyyyyyyyyyywyy>ywy>`wyEywyywEyyqyywwqEywqyqyqwqqqwwwq>wwqqwwqEqwwEEwqqqqwwwww>wsqs$$$$$$$$$$$$$$$$$$$$$$$$$$$$sq", "OOOOOOOGHHGOOOOOOOOOOOOOOOOGHH!2~K~3332<22<<ywyywyyqywyyyEyyEqEyyEEyEywyyEy>y>>yEEEqyEEqywyEyy>y>yyywyyEyqy>yEEqywqEywywqywqwywyqwww>wwwwwwwww>wwqwqw$E$w$Esw$qsw$qsws$$$$$$$$$$$$$$$$$$$$$$$$$$$", "KK~2HGGGOOOHOOOOOHH!!!HOOOOOOOH>yyyyyq,EyyyyqEEyEyEyEyyyyyyEyEyEyywyyEyEyyEywyqEEyEEyEywyqqywwywwywwqqqwwwyqqywqwqwwww>qqwqqqwEEEqEqE$wwq$>wswsws$s$$$$$$$$$$$$$$$$$$$$$ws", "~22wwwwwwwqwwwwwEwwwwEwwEqwwqwwqww$E$w$Esqsq$Esqs>qwsw$$$$$B$$$$$$$$$$$$$$$", "~22wEyEEEEEEEqywwyqywyEEEyqyqEEwyqEEyqEEywEyqEEEyEEyEEEyqyEwqyqyEyqqywqEEwwyqEwyEEqqqw>>yEw>wqww>w>wqw>Ewqwwwww$wswwwww>w$>sEs$$w$$qswssws$$$$$$$$$$$$$$$$$$$", "wwwqEEEEwwwwwqwwwwwwwwq>wEqwwqwqwwsqwwwwws$sqswwwEsw$sw$sw$qw$wsw$$$$$$$$$$$$$$$$", "GOOOOOOGOGGGHH!232!22wwwEEEqqqqqw>w>wqqwwEEqEEEEqEqqEEqqqEqqEwwwwEEwqEEEEEEEwqEqEqEwwwqqqwwqwwwwqEqwwwEqqEwqE$wwsw$wswq$ws>swqwsq$sws$$q$swsws$swswswsq$$$$$$$$$$$$$", "OOOOOOOOHH!33qEEqqwwywwy>>yqEqqwqqEqEEEEEEEEEqEEEqEqwwwEwwEEEqwwqEwwwwEqEEqEqEEwwqqwwqEwEwwEwqq$qwwq$Eww$wwEsw$wswwsqswsqswsqs$$$s$sw$sqsqsqs>$sw$$$$$$$$$", "OOOGHHwEEwwwqEEwwqEEEEqEEwqww$Ew>wwwwsE$wwwsws>sww$wsws$wsqs>w$ws>$wswqwssw$qsw$$w$swswsq$$$$$$", "sws$sws$s$qs$swswEswswsw$$$s", "HHGGGGGOOGGHHHHGOOOOOGOHHs$qs$q$wswwswswswsqs$qq$swswswsswsswsqsws$$ws$$qwssw$s", "OOOOOOOOOHHHHHGHH<<$wssE", "OOOOOOOGOOOOOOOOOOGOOOOH<<2!$sq$s$$$swsqsswsw$swsqsqsw$sqwsqsqsws$sq$sw$w$", "OOOOOOOOOOOOOOOOOOOOOH22!<q$$$E$$$w$$$$q$$$q$$E$ws$q$sqs$$sE$q$$ss$sws$$$$s$sqsww$sEswsEsqswsqswPwsws$qsqsqsws>sqsq>sws>$s$sq", "OOOOOOOOOOOOOOOOGH!<<<<swsswswswsqsqsqswswsq", "OOOOOOOOOOOOGH$ws$sqsqswswsqsqsws", "OOOOOOOOOOOGGGOOOOOOOH<<$s$$$q$$$s$$$$$wsq$q$Eswsw$qsw$$$$$sw$sq$$qsqsqsw$s$s$wPws$q$$ssEs$$q$$Eswswsw$$w$ws$qsqwsw$$swsq$$wsqsq" }; nethack-3.6.0/win/X11/tile2x11.c0000664000076400007660000001446212536476415015044 0ustar paxedpaxed/* $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ /* * Convert the given input files into an output file that is expected * by nethack. * * Assumptions: * + Two dimensional byte arrays are in row order and are not padded * between rows (x11_colormap[][]). */ #include "hack.h" /* for MAX_GLYPH */ #include "tile.h" #include "tile2x11.h" /* x11 output file header structure */ #define OUTNAME "x11tiles" /* output file name */ /* #define PRINT_COLORMAP */ /* define to print the colormap */ x11_header header; unsigned char tile_bytes[TILE_X * TILE_Y * (MAX_GLYPH + TILES_PER_ROW)]; unsigned char *curr_tb = tile_bytes; unsigned char x11_colormap[MAXCOLORMAPSIZE][3]; /* Look up the given pixel and return its colormap index. */ static unsigned char pix_to_colormap(pix) pixel pix; { unsigned i; for (i = 0; i < header.ncolors; i++) { if (pix.r == ColorMap[CM_RED][i] && pix.g == ColorMap[CM_GREEN][i] && pix.b == ColorMap[CM_BLUE][i]) break; } if (i == header.ncolors) { Fprintf(stderr, "can't find color: [%u,%u,%u]\n", pix.r, pix.g, pix.b); exit(1); } return (unsigned char) (i & 0xFF); } /* Convert the tiles in the file to our format of bytes. */ static unsigned long convert_tiles(tb_ptr, total) unsigned char **tb_ptr; /* pointer to a tile byte pointer */ unsigned long total; /* total tiles so far */ { unsigned char *tb = *tb_ptr; unsigned long count = 0; pixel tile[TILE_Y][TILE_X]; int x, y; while (read_text_tile(tile)) { count++; total++; for (y = 0; y < TILE_Y; y++) { for (x = 0; x < TILE_X; x++) tb[x] = pix_to_colormap(tile[y][x]); tb += TILE_X * header.per_row; } /* repoint at the upper-left corner of the next tile */ *tb_ptr += TILE_X; if (header.per_row == 1 || (total % header.per_row) == 0) *tb_ptr += TILE_X * (TILE_Y - 1) * header.per_row; tb = *tb_ptr; } return count; } /* Merge the current text colormap (ColorMap) with ours (x11_colormap). */ static void merge_text_colormap() { unsigned i, j; for (i = 0; i < (unsigned) colorsinmap; i++) { for (j = 0; j < header.ncolors; j++) if (x11_colormap[j][CM_RED] == ColorMap[CM_RED][i] && x11_colormap[j][CM_GREEN] == ColorMap[CM_GREEN][i] && x11_colormap[j][CM_BLUE] == ColorMap[CM_BLUE][i]) break; if (j >= MAXCOLORMAPSIZE) { Fprintf(stderr, "colormap overflow\n"); exit(1); } if (j == header.ncolors) { /* couldn't find it */ #ifdef PRINT_COLORMAP printf("color %2d: %3d %3d %3d\n", header.ncolors, ColorMap[CM_RED][i], ColorMap[CM_GREEN][i], ColorMap[CM_BLUE][i]); #endif x11_colormap[j][CM_RED] = ColorMap[CM_RED][i]; x11_colormap[j][CM_GREEN] = ColorMap[CM_GREEN][i]; x11_colormap[j][CM_BLUE] = ColorMap[CM_BLUE][i]; header.ncolors++; } } } /* Open the given file, read & merge the colormap, convert the tiles. */ static void process_file(fname) char *fname; { unsigned long count; if (!fopen_text_file(fname, RDTMODE)) { Fprintf(stderr, "can't open file \"%s\"\n", fname); exit(1); } merge_text_colormap(); count = convert_tiles(&curr_tb, header.ntiles); Fprintf(stderr, "%s: %lu tiles\n", fname, count); header.ntiles += count; fclose_text_file(); } #ifdef USE_XPM static int xpm_write(fp) FILE *fp; { int i, j, n; if (header.ncolors > 64) { Fprintf(stderr, "Sorry, only configured for up to 64 colors\n"); exit(1); /* All you need to do is add more char per color - below */ } Fprintf(fp, "/* XPM */\n"); Fprintf(fp, "static char* nhtiles[] = {\n"); Fprintf(fp, "\"%lu %lu %lu %d\",\n", header.tile_width * header.per_row, (header.tile_height * header.ntiles) / header.per_row, header.ncolors, 1 /* char per color */); for (i = 0; i < header.ncolors; i++) Fprintf(fp, "\"%c c #%02x%02x%02x\",\n", i + '0', /* just one char per color */ x11_colormap[i][0], x11_colormap[i][1], x11_colormap[i][2]); n = 0; for (i = 0; i < (header.tile_height * header.ntiles) / header.per_row; i++) { Fprintf(fp, "\""); for (j = 0; j < header.tile_width * header.per_row; j++) { /* just one char per color */ fputc(tile_bytes[n++] + '0', fp); } Fprintf(fp, "\",\n"); } return fprintf(fp, "};\n") >= 0; } #endif /* USE_XPM */ int main(argc, argv) int argc; char **argv; { FILE *fp; int i; header.version = 2; /* version 1 had no per_row field */ header.ncolors = 0; header.tile_width = TILE_X; header.tile_height = TILE_Y; header.ntiles = 0; /* updated as we read in files */ header.per_row = TILES_PER_ROW; if (argc == 1) { Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]); exit(1); } fp = fopen(OUTNAME, "w"); if (!fp) { Fprintf(stderr, "can't open output file\n"); exit(1); } /* don't leave garbage at end of partial row */ (void) memset((genericptr_t) tile_bytes, 0, sizeof(tile_bytes)); for (i = 1; i < argc; i++) process_file(argv[i]); Fprintf(stderr, "Total tiles: %ld\n", header.ntiles); /* round size up to the end of the row */ if ((header.ntiles % header.per_row) != 0) { header.ntiles += header.per_row - (header.ntiles % header.per_row); } #ifdef USE_XPM if (xpm_write(fp) == 0) { Fprintf(stderr, "can't write XPM file\n"); exit(1); } #else if (fwrite((char *) &header, sizeof(x11_header), 1, fp) == 0) { Fprintf(stderr, "can't open output header\n"); exit(1); } if (fwrite((char *) x11_colormap, 1, header.ncolors * 3, fp) == 0) { Fprintf(stderr, "can't write output colormap\n"); exit(1); } if (fwrite((char *) tile_bytes, 1, (int) header.ntiles * header.tile_width * header.tile_height, fp) == 0) { Fprintf(stderr, "can't write tile bytes\n"); exit(1); } #endif fclose(fp); return 0; } nethack-3.6.0/win/X11/winX.c0000664000076400007660000020402512536476415014414 0ustar paxedpaxed/* NetHack 3.6 winX.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * "Main" file for the X window-port. This contains most of the interface * routines. Please see doc/window.doc for an description of the window * interface. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #ifdef MSDOS /* from compiler */ #define SHORT_FILENAMES #endif #include #include #include #include #include #include #include #include #include #include #include /* for color support */ #ifdef SHORT_FILENAMES #include #else #include #endif #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #ifdef SHORT_FILENAMES #undef SHORT_FILENAMES /* hack.h will reset via global.h if necessary */ #endif #include "hack.h" #include "winX.h" #include "dlb.h" #ifndef NO_SIGNAL #include #endif /* Should be defined in but you never know */ #ifndef XtSpecificationRelease #define XtSpecificationRelease 0 #endif /* * Icons. */ #include "../win/X11/nh72icon" #include "../win/X11/nh56icon" #include "../win/X11/nh32icon" static struct icon_info { const char *name; unsigned char *bits; unsigned width, height; } icon_data[] = { { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height }, { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height }, { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height }, { (const char *) 0, (unsigned char *) 0, 0, 0 } }; /* * Private global variables (shared among the window port files). */ struct xwindow window_list[MAX_WINDOWS]; AppResources appResources; void FDECL((*input_func), (Widget, XEvent *, String *, Cardinal *)); int click_x, click_y, click_button; /* Click position on a map window */ /* (filled by set_button_values()). */ int updated_inventory; #if !defined(NO_SIGNAL) && defined(SAFERHANGUP) #if XtSpecificationRelease >= 6 #define X11_HANGUP_SIGNAL static XtSignalId X11_sig_id; #endif #endif /* this is only needed until X11_status_* routines are written */ extern NEARDATA winid WIN_STATUS; /* Interface definition, for windows.c */ struct window_procs X11_procs = { "X11", WC_COLOR | WC_HILITE_PET | WC_TILED_MAP, 0L, X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow, X11_clear_nhwindow, X11_display_nhwindow, X11_destroy_nhwindow, X11_curs, X11_putstr, genl_putmixed, X11_display_file, X11_start_menu, X11_add_menu, X11_end_menu, X11_select_menu, genl_message_menu, /* no need for X-specific handling */ X11_update_inventory, X11_mark_synch, X11_wait_synch, #ifdef CLIPPING X11_cliparound, #endif #ifdef POSITIONBAR donull, #endif X11_print_glyph, X11_raw_print, X11_raw_print_bold, X11_nhgetch, X11_nh_poskey, X11_nhbell, X11_doprev_message, X11_yn_function, X11_getlin, X11_get_ext_cmd, X11_number_pad, X11_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif /* other defs that really should go away (they're tty specific) */ X11_start_screen, X11_end_screen, #ifdef GRAPHIC_TOMBSTONE X11_outrip, #else genl_outrip, #endif X11_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif genl_can_suspend_no, /* XXX may not always be correct */ }; /* * Local functions. */ static void FDECL(dismiss_file, (Widget, XEvent *, String *, Cardinal *)); static void FDECL(delete_file, (Widget, XEvent *, String *, Cardinal *)); static void FDECL(yn_key, (Widget, XEvent *, String *, Cardinal *)); static void FDECL(yn_delete, (Widget, XEvent *, String *, Cardinal *)); static void FDECL(askname_delete, (Widget, XEvent *, String *, Cardinal *)); static void FDECL(getline_delete, (Widget, XEvent *, String *, Cardinal *)); static void FDECL(X11_hangup, (Widget, XEvent *, String *, Cardinal *)); static int FDECL(input_event, (int)); static void FDECL(win_visible, (Widget, XtPointer, XEvent *, Boolean *)); static void NDECL(init_standard_windows); #ifdef X11_HANGUP_SIGNAL static void FDECL(X11_sig, (int)); static void FDECL(X11_sig_cb, (XtPointer, XtSignalId *)); #endif /* * Local variables. */ static boolean x_inited = FALSE; /* TRUE if window system is set up. */ static winid message_win = WIN_ERR, /* These are the winids of the */ map_win = WIN_ERR, /* message, map, and status */ status_win = WIN_ERR; /* windows, when they are created */ /* in init_windows(). */ static Pixmap icon_pixmap = None; /* Pixmap for icon. */ /* * Find the window structure that corresponds to the given widget. Note * that this is not the popup widget, nor the viewport, but the child. */ struct xwindow * find_widget(w) Widget w; { int windex; struct xwindow *wp; /* Search to find the corresponding window. Look at the main widget, */ /* popup, the parent of the main widget, then parent of the widget. */ for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++) if (wp->type != NHW_NONE && (wp->w == w || wp->popup == w || (wp->w && (XtParent(wp->w)) == w) || (wp->popup == XtParent(w)))) break; if (windex == MAX_WINDOWS) panic("find_widget: can't match widget"); return wp; } /* * Find a free window slot for use. */ static winid find_free_window() { int windex; struct xwindow *wp; for (windex = 0, wp = &window_list[0]; windex < MAX_WINDOWS; windex++, wp++) if (wp->type == NHW_NONE) break; if (windex == MAX_WINDOWS) panic("find_free_window: no free windows!"); return (winid) windex; } /* * Color conversion. The default X11 color converters don't try very * hard to find matching colors in PseudoColor visuals. If they can't * allocate the exact color, they puke and give you something stupid. * This is an attempt to find some close readonly cell and use it. */ XtConvertArgRec const nhcolorConvertArgs[] = { { XtWidgetBaseOffset, (XtPointer) XtOffset(Widget, core.screen), sizeof(Screen *) }, { XtWidgetBaseOffset, (XtPointer) XtOffset(Widget, core.colormap), sizeof(Colormap) } }; #define done(type, value) \ { \ if (toVal->addr != 0) { \ if (toVal->size < sizeof(type)) { \ toVal->size = sizeof(type); \ return False; \ } \ *(type *)(toVal->addr) = (value); \ } else { \ static type static_val; \ static_val = (value); \ toVal->addr = (genericptr_t) &static_val; \ } \ toVal->size = sizeof(type); \ return True; \ } /* * Find a color that approximates the color named in "str". The "str" color * may be a color name ("red") or number ("#7f0000"). If str == NULL, then * "color" is assumed to contain the RGB color wanted. * The approximate color found is returned in color as well. * Return True if something close was found. */ Boolean nhApproxColor(screen, colormap, str, color) Screen *screen; /* screen to use */ Colormap colormap; /* the colormap to use */ char *str; /* color name */ XColor *color; /* the X color structure; changed only if successful */ { int ncells; long cdiff = 16777216; /* 2^24; hopefully our map is smaller */ XColor tmp; static XColor *table = 0; register int i, j; register long tdiff; /* if the screen doesn't have a big colormap, don't waste our time */ /* or if it's huge, and _some_ match should have been possible */ if ((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096) return False; if (str != (char *) 0) { if (!XParseColor(DisplayOfScreen(screen), colormap, str, &tmp)) return False; } else { tmp = *color; tmp.flags = 7; /* force to use all 3 of RGB */ } if (!table) { table = (XColor *) XtCalloc(ncells, sizeof(XColor)); for (i = 0; i < ncells; i++) table[i].pixel = i; XQueryColors(DisplayOfScreen(screen), colormap, table, ncells); } /* go thru cells and look for the one with smallest diff */ /* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */ /* a more knowledgeable color person might improve this -dlc */ try_again: for (i = 0; i < ncells; i++) { if (table[i].flags == tmp.flags) { j = (int) table[i].red - (int) tmp.red; if (j < 0) j = -j; tdiff = j; j = (int) table[i].green - (int) tmp.green; if (j < 0) j = -j; tdiff += j; j = (int) table[i].blue - (int) tmp.blue; if (j < 0) j = -j; tdiff += j; if (tdiff < cdiff) { cdiff = tdiff; tmp.pixel = i; /* table[i].pixel == i */ } } } if (cdiff == 16777216) return False; /* nothing found?! */ /* * Found something. Return it and mark this color as used to avoid * reuse. Reuse causes major contrast problems :-) */ *color = table[tmp.pixel]; table[tmp.pixel].flags = 0; /* try to alloc the color, so no one else can change it */ if (!XAllocColor(DisplayOfScreen(screen), colormap, color)) { cdiff = 16777216; goto try_again; } return True; } Boolean nhCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret) Display *dpy; XrmValuePtr args; Cardinal *num_args; XrmValuePtr fromVal; XrmValuePtr toVal; XtPointer *closure_ret; { String str = (String) fromVal->addr; XColor screenColor; XColor exactColor; Screen *screen; XtAppContext app = XtDisplayToApplicationContext(dpy); Colormap colormap; Status status; String params[1]; Cardinal num_params = 1; if (*num_args != 2) { XtAppWarningMsg( app, "wrongParameters", "cvtStringToPixel", "XtToolkitError", "String to pixel conversion needs screen and colormap arguments", (String *) 0, (Cardinal *) 0); return False; } screen = *((Screen **) args[0].addr); colormap = *((Colormap *) args[1].addr); /* If Xt colors, use the Xt routine and hope for the best */ #if (XtSpecificationRelease >= 5) if ((strcmpi(str, XtDefaultBackground) == 0) || (strcmpi(str, XtDefaultForeground) == 0)) { return XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret); } #else if (strcmpi(str, XtDefaultBackground) == 0) { *closure_ret = (char *) False; done(Pixel, WhitePixelOfScreen(screen)); } if (strcmpi(str, XtDefaultForeground) == 0) { *closure_ret = (char *) False; done(Pixel, BlackPixelOfScreen(screen)); } #endif status = XAllocNamedColor(DisplayOfScreen(screen), colormap, (char *) str, &screenColor, &exactColor); if (status == 0) { String msg, type; /* some versions of XAllocNamedColor don't allow #xxyyzz names */ if (str[0] == '#' && XParseColor(DisplayOfScreen(screen), colormap, str, &exactColor) && XAllocColor(DisplayOfScreen(screen), colormap, &exactColor)) { *closure_ret = (char *) True; done(Pixel, exactColor.pixel); } params[0] = str; /* Server returns a specific error code but Xlib discards it. Ugh */ if (XLookupColor(DisplayOfScreen(screen), colormap, (char *) str, &exactColor, &screenColor)) { /* try to find another color that will do */ if (nhApproxColor(screen, colormap, (char *) str, &screenColor)) { *closure_ret = (char *) True; done(Pixel, screenColor.pixel); } type = nhStr("noColormap"); msg = nhStr("Cannot allocate colormap entry for \"%s\""); } else { /* some versions of XLookupColor also don't allow #xxyyzz names */ if (str[0] == '#' && (nhApproxColor(screen, colormap, (char *) str, &screenColor))) { *closure_ret = (char *) True; done(Pixel, screenColor.pixel); } type = nhStr("badValue"); msg = nhStr("Color name \"%s\" is not defined"); } XtAppWarningMsg(app, type, "cvtStringToPixel", "XtToolkitError", msg, params, &num_params); *closure_ret = False; return False; } else { *closure_ret = (char *) True; done(Pixel, screenColor.pixel); } } /* ARGSUSED */ static void nhFreePixel(app, toVal, closure, args, num_args) XtAppContext app; XrmValuePtr toVal; XtPointer closure; XrmValuePtr args; Cardinal *num_args; { Screen *screen; Colormap colormap; if (*num_args != 2) { XtAppWarningMsg( app, "wrongParameters", "freePixel", "XtToolkitError", "Freeing a pixel requires screen and colormap arguments", (String *) 0, (Cardinal *) 0); return; } screen = *((Screen **) args[0].addr); colormap = *((Colormap *) args[1].addr); if (closure) { XFreeColors(DisplayOfScreen(screen), colormap, (unsigned long *) toVal->addr, 1, (unsigned long) 0); } } /* [ALI] Utility function to ask Xaw for font height, since the previous * assumption of ascent + descent is not always valid. */ Dimension nhFontHeight(w) Widget w; #ifdef _XawTextSink_h { Widget sink; XawTextPosition pos = 0; int resWidth, resHeight; Arg args[1]; XtSetArg(args[0], XtNtextSink, &sink); XtGetValues(w, args, 1); XawTextSinkFindPosition(sink, pos, 0, 0, 0, &pos, &resWidth, &resHeight); return resHeight; } #else { XFontStruct *fs; Arg args[1]; XtSetArg(args[0], XtNfont, &fs); XtGetValues(w, args, 1); /* Assume font height is ascent + descent. */ return = fs->ascent + fs->descent; } #endif /* Global Functions ======================================================== */ void X11_raw_print(str) const char *str; { (void) puts(str); } void X11_raw_print_bold(str) const char *str; { (void) puts(str); } void X11_curs(window, x, y) winid window; int x, y; { check_winid(window); if (x < 0 || x >= COLNO) { impossible("curs: bad x value [%d]", x); x = 0; } if (y < 0 || y >= ROWNO) { impossible("curs: bad y value [%d]", y); y = 0; } window_list[window].cursx = x; window_list[window].cursy = y; } void X11_putstr(window, attr, str) winid window; int attr; const char *str; { winid new_win; struct xwindow *wp; check_winid(window); wp = &window_list[window]; switch (wp->type) { case NHW_MESSAGE: (void) strncpy(toplines, str, TBUFSZ); /* for Norep(). */ toplines[TBUFSZ - 1] = 0; append_message(wp, str); break; case NHW_STATUS: adjust_status(wp, str); break; case NHW_MAP: impossible("putstr: called on map window \"%s\"", str); break; case NHW_MENU: if (wp->menu_information->is_menu) { impossible("putstr: called on a menu window, \"%s\" discarded", str); break; } /* * Change this menu window into a text window by creating a * new text window, then copying it to this winid. */ new_win = X11_create_nhwindow(NHW_TEXT); X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ /* fall though to add text */ case NHW_TEXT: add_to_text_window(wp, attr, str); break; default: impossible("putstr: unknown window type [%d] \"%s\"", wp->type, str); } } /* We do event processing as a callback, so this is a null routine. */ void X11_get_nh_event() { return; } int X11_nhgetch() { return input_event(EXIT_ON_KEY_PRESS); } int X11_nh_poskey(x, y, mod) int *x, *y, *mod; { int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS); if (val == 0) { /* user clicked on a map window */ *x = click_x; *y = click_y; *mod = click_button; } return val; } winid X11_create_nhwindow(type) int type; { winid window; struct xwindow *wp; if (!x_inited) panic("create_nhwindow: windows not initialized"); #ifdef X11_HANGUP_SIGNAL /* set up our own signal handlers on the first call. Can't do this in * X11_init_nhwindows because unixmain sets its handler after calling * all the init routines. */ if (X11_sig_id == 0) { X11_sig_id = XtAppAddSignal(app_context, X11_sig_cb, (XtPointer) 0); #ifdef SA_RESTART { struct sigaction sact; (void) memset((char *) &sact, 0, sizeof(struct sigaction)); sact.sa_handler = (SIG_RET_TYPE) X11_sig; (void) sigaction(SIGHUP, &sact, (struct sigaction *) 0); #ifdef SIGXCPU (void) sigaction(SIGXCPU, &sact, (struct sigaction *) 0); #endif } #else (void) signal(SIGHUP, (SIG_RET_TYPE) X11_sig); #ifdef SIGXCPU (void) signal(SIGXCPU, (SIG_RET_TYPE) X11_sig); #endif #endif } #endif /* * We have already created the standard message, map, and status * windows in the window init routine. The first window of that * type to be created becomes the standard. * * A better way to do this would be to say that init_nhwindows() * has already defined these three windows. */ if (type == NHW_MAP && map_win != WIN_ERR) { window = map_win; map_win = WIN_ERR; return window; } if (type == NHW_MESSAGE && message_win != WIN_ERR) { window = message_win; message_win = WIN_ERR; return window; } if (type == NHW_STATUS && status_win != WIN_ERR) { window = status_win; status_win = WIN_ERR; return window; } window = find_free_window(); wp = &window_list[window]; /* The create routines will set type, popup, w, and Win_info. */ wp->prevx = wp->prevy = wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->keep_window = FALSE; switch (type) { case NHW_MAP: create_map_window(wp, TRUE, (Widget) 0); break; case NHW_MESSAGE: create_message_window(wp, TRUE, (Widget) 0); break; case NHW_STATUS: create_status_window(wp, TRUE, (Widget) 0); break; case NHW_MENU: create_menu_window(wp); break; case NHW_TEXT: create_text_window(wp); break; default: panic("create_nhwindow: unknown type [%d]", type); break; } return window; } void X11_clear_nhwindow(window) winid window; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; switch (wp->type) { case NHW_MAP: clear_map_window(wp); break; case NHW_TEXT: clear_text_window(wp); break; case NHW_STATUS: case NHW_MENU: case NHW_MESSAGE: /* do nothing for these window types */ break; default: panic("clear_nhwindow: unknown window type [%d]", wp->type); break; } } void X11_display_nhwindow(window, blocking) winid window; boolean blocking; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; switch (wp->type) { case NHW_MAP: if (wp->popup) nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w); display_map_window(wp); /* flush map */ /* * We need to flush the message window here due to the way the tty * port is set up. To flush a window, you need to call this * routine. However, the tty port _pauses_ with a --more-- if we * do a display_nhwindow(WIN_MESSAGE, FALSE). Thus, we can't call * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we * get a --more-- after every line. * * Perhaps the window document should mention that when the map * is flushed, everything on the three main windows should be * flushed. Note: we don't need to flush the status window * because we don't buffer changes. */ if (WIN_MESSAGE != WIN_ERR) display_message_window(&window_list[WIN_MESSAGE]); if (blocking) (void) x_event(EXIT_ON_KEY_OR_BUTTON_PRESS); break; case NHW_MESSAGE: if (wp->popup) nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w); display_message_window(wp); /* flush messages */ break; case NHW_STATUS: if (wp->popup) nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w); break; /* no flushing necessary */ case NHW_MENU: { int n; menu_item *selected; /* pop up menu */ n = X11_select_menu(window, PICK_NONE, &selected); if (n) { impossible("perminvent: %d selected??", n); free((genericptr_t) selected); } break; } case NHW_TEXT: display_text_window(wp, blocking); /* pop up text window */ break; default: panic("display_nhwindow: unknown window type [%d]", wp->type); break; } } void X11_destroy_nhwindow(window) winid window; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; /* * "Zap" known windows, but don't destroy them. We need to keep the * toplevel widget popped up so that later windows (e.g. tombstone) * are visible on DECWindow systems. This is due to the virtual * roots that the DECWindow wm creates. */ if (window == WIN_MESSAGE) { wp->keep_window = TRUE; WIN_MESSAGE = WIN_ERR; iflags.window_inited = 0; } else if (window == WIN_MAP) { wp->keep_window = TRUE; WIN_MAP = WIN_ERR; } else if (window == WIN_STATUS) { wp->keep_window = TRUE; WIN_STATUS = WIN_ERR; } else if (window == WIN_INVEN) { /* don't need to keep this one */ WIN_INVEN = WIN_ERR; } switch (wp->type) { case NHW_MAP: destroy_map_window(wp); break; case NHW_MENU: destroy_menu_window(wp); break; case NHW_TEXT: destroy_text_window(wp); break; case NHW_STATUS: destroy_status_window(wp); break; case NHW_MESSAGE: destroy_message_window(wp); break; default: panic("destroy_nhwindow: unknown window type [%d]", wp->type); break; } } void X11_update_inventory() { if (x_inited && window_list[WIN_INVEN].menu_information->is_up) { updated_inventory = 1; /* hack to avoid mapping&raising window */ (void) display_inventory((char *) 0, FALSE); updated_inventory = 0; } } /* The current implementation has all of the saved lines on the screen. */ int X11_doprev_message() { return 0; } void X11_nhbell() { /* We can't use XBell until toplevel has been initialized. */ if (x_inited) XBell(XtDisplay(toplevel), 0); /* else print ^G ?? */ } void X11_mark_synch() { if (x_inited) { /* * The window document is unclear about the status of text * that has been pline()d but not displayed w/display_nhwindow(). * Both the main and tty code assume that a pline() followed * by mark_synch() results in the text being seen, even if * display_nhwindow() wasn't called. Duplicate this behavior. */ if (WIN_MESSAGE != WIN_ERR) display_message_window(&window_list[WIN_MESSAGE]); XSync(XtDisplay(toplevel), False); } } void X11_wait_synch() { if (x_inited) XFlush(XtDisplay(toplevel)); } /* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */ void X11_resume_nhwindows() { return; } /* ARGSUSED */ void X11_suspend_nhwindows(str) const char *str; { nhUse(str); return; } /* Under X, we don't need to initialize the number pad. */ /* ARGSUSED */ void X11_number_pad(state) /* called from options.c */ int state; { nhUse(state); return; } void X11_start_screen() { return; } /* called from setftty() in unixtty.c */ void X11_end_screen() { return; } /* called from settty() in unixtty.c */ #ifdef GRAPHIC_TOMBSTONE void X11_outrip(window, how, when) winid window; int how; time_t when; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; if (wp->type == NHW_TEXT) { wp->text_information->is_rip = TRUE; } else { panic("ripout on non-text window (window type [%d])", wp->type); } calculate_rip_text(how, when); } #endif /* init and exit nhwindows ------------------------------------------------- */ XtAppContext app_context; /* context of application */ Widget toplevel = (Widget) 0; /* toplevel widget */ Atom wm_delete_window; /* pop down windows */ static XtActionsRec actions[] = { { nhStr("dismiss_file"), dismiss_file }, /* file viewing widget */ { nhStr("delete_file"), delete_file }, /* file delete-window */ { nhStr("dismiss_text"), dismiss_text }, /* text widget button action */ { nhStr("delete_text"), delete_text }, /* text widget delete action */ { nhStr("key_dismiss_text"), key_dismiss_text }, /* text widget key action */ #ifdef GRAPHIC_TOMBSTONE { nhStr("rip_dismiss_text"), rip_dismiss_text }, /* rip in text widget */ #endif { nhStr("menu_key"), menu_key }, /* menu accelerators */ { nhStr("yn_key"), yn_key }, /* yn accelerators */ { nhStr("yn_delete"), yn_delete }, /* yn delete-window */ { nhStr("askname_delete"), askname_delete }, /* askname delete-window */ { nhStr("getline_delete"), getline_delete }, /* getline delete-window */ { nhStr("menu_delete"), menu_delete }, /* menu delete-window */ { nhStr("ec_key"), ec_key }, /* extended commands */ { nhStr("ec_delete"), ec_delete }, /* ext-com menu delete */ { nhStr("ps_key"), ps_key }, /* player selection */ { nhStr("race_key"), race_key }, /* race selection */ { nhStr("gend_key"), gend_key }, /* gender selection */ { nhStr("algn_key"), algn_key }, /* alignment selection */ { nhStr("X11_hangup"), X11_hangup }, /* delete of top-level */ { nhStr("input"), map_input }, /* key input */ { nhStr("scroll"), nh_keyscroll }, /* scrolling by keys */ }; static XtResource resources[] = { { nhStr("slow"), nhStr("Slow"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, slow), XtRString, nhStr("True") }, { nhStr("autofocus"), nhStr("AutoFocus"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, autofocus), XtRString, nhStr("False") }, { nhStr("message_line"), nhStr("Message_line"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, message_line), XtRString, nhStr("False") }, { nhStr("double_tile_size"), nhStr("Double_tile_size"), XtRBoolean, sizeof(Boolean), XtOffset(AppResources *, double_tile_size), XtRString, nhStr("False") }, { nhStr("tile_file"), nhStr("Tile_file"), XtRString, sizeof(String), XtOffset(AppResources *, tile_file), XtRString, nhStr("x11tiles") }, { nhStr("icon"), nhStr("Icon"), XtRString, sizeof(String), XtOffset(AppResources *, icon), XtRString, nhStr("nh72") }, { nhStr("message_lines"), nhStr("Message_lines"), XtRInt, sizeof(int), XtOffset(AppResources *, message_lines), XtRString, nhStr("12") }, { nhStr("pet_mark_bitmap"), nhStr("Pet_mark_bitmap"), XtRString, sizeof(String), XtOffset(AppResources *, pet_mark_bitmap), XtRString, nhStr("pet_mark.xbm") }, { nhStr("pet_mark_color"), nhStr("Pet_mark_color"), XtRPixel, sizeof(XtRPixel), XtOffset(AppResources *, pet_mark_color), XtRString, nhStr("Red") }, { nhStr("pilemark_bitmap"), nhStr("Pilemark_bitmap"), XtRString, sizeof(String), XtOffset(AppResources *, pilemark_bitmap), XtRString, nhStr("pilemark.xbm") }, { nhStr("pilemark_color"), nhStr("Pilemark_color"), XtRPixel, sizeof(XtRPixel), XtOffset(AppResources *, pilemark_color), XtRString, nhStr("Green") }, #ifdef GRAPHIC_TOMBSTONE { nhStr("tombstone"), "Tombstone", XtRString, sizeof(String), XtOffset(AppResources *, tombstone), XtRString, "rip.xpm" }, { nhStr("tombtext_x"), "Tombtext_x", XtRInt, sizeof(int), XtOffset(AppResources *, tombtext_x), XtRString, "155" }, { nhStr("tombtext_y"), "Tombtext_y", XtRInt, sizeof(int), XtOffset(AppResources *, tombtext_y), XtRString, "78" }, { nhStr("tombtext_dx"), "Tombtext_dx", XtRInt, sizeof(int), XtOffset(AppResources *, tombtext_dx), XtRString, "0" }, { nhStr("tombtext_dy"), "Tombtext_dy", XtRInt, sizeof(int), XtOffset(AppResources *, tombtext_dy), XtRString, "13" }, #endif }; void X11_init_nhwindows(argcp, argv) int *argcp; char **argv; { int i; Cardinal num_args; Arg args[4]; uid_t savuid; /* Init windows to nothing. */ for (i = 0; i < MAX_WINDOWS; i++) window_list[i].type = NHW_NONE; /* add another option that can be set */ set_wc_option_mod_status(WC_TILED_MAP, SET_IN_GAME); /* * setuid hack: make sure that if nethack is setuid, to use real uid * when opening X11 connections, in case the user is using xauth, since * the "games" or whatever user probably doesn't have permission to open * a window on the user's display. This code is harmless if the binary * is not installed setuid. See include/system.h on compilation failures. */ savuid = geteuid(); (void) seteuid(getuid()); XSetIOErrorHandler((XIOErrorHandler) hangup); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; toplevel = XtAppInitialize(&app_context, "NetHack", /* application class */ (XrmOptionDescList) 0, 0, /* options list */ argcp, (String *) argv, /* command line args */ (String *) 0, /* fallback resources */ (ArgList) args, num_args); XtOverrideTranslations( toplevel, XtParseTranslationTable("WM_PROTOCOLS: X11_hangup()")); /* We don't need to realize the top level widget. */ #ifdef TEXTCOLOR /* add new color converter to deal with overused colormaps */ XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel, (XtConvertArgList) nhcolorConvertArgs, XtNumber(nhcolorConvertArgs), XtCacheByDisplay, nhFreePixel); #endif /* TEXTCOLOR */ /* Register the actions mentioned in "actions". */ XtAppAddActions(app_context, actions, XtNumber(actions)); /* Get application-wide resources */ XtGetApplicationResources(toplevel, (XtPointer) &appResources, resources, XtNumber(resources), (ArgList) 0, ZERO); /* Initialize other things. */ init_standard_windows(); /* Give the window manager an icon to use; toplevel must be realized. */ if (appResources.icon && *appResources.icon) { struct icon_info *ip; for (ip = icon_data; ip->name; ip++) if (!strcmp(appResources.icon, ip->name)) { icon_pixmap = XCreateBitmapFromData( XtDisplay(toplevel), XtWindow(toplevel), (genericptr_t) ip->bits, ip->width, ip->height); if (icon_pixmap != None) { XWMHints hints; (void) memset((genericptr_t) &hints, 0, sizeof(XWMHints)); hints.flags = IconPixmapHint; hints.icon_pixmap = icon_pixmap; XSetWMHints(XtDisplay(toplevel), XtWindow(toplevel), &hints); } break; } } /* end of setuid hack: reset uid back to the "games" uid */ (void) seteuid(savuid); x_inited = TRUE; /* X is now initialized */ /* Display the startup banner in the message window. */ for (i = 1; i <= 4 + 2; ++i) /* (values beyond 4 yield blank lines) */ X11_putstr(WIN_MESSAGE, 0, copyright_banner_line(i)); } /* * All done. */ /* ARGSUSED */ void X11_exit_nhwindows(dummy) const char *dummy; { extern Pixmap tile_pixmap; /* from winmap.c */ nhUse(dummy); /* explicitly free the icon and tile pixmaps */ if (icon_pixmap != None) { XFreePixmap(XtDisplay(toplevel), icon_pixmap); icon_pixmap = None; } if (tile_pixmap != None) { XFreePixmap(XtDisplay(toplevel), tile_pixmap); tile_pixmap = None; } if (WIN_INVEN != WIN_ERR) X11_destroy_nhwindow(WIN_INVEN); if (WIN_STATUS != WIN_ERR) X11_destroy_nhwindow(WIN_STATUS); if (WIN_MAP != WIN_ERR) X11_destroy_nhwindow(WIN_MAP); if (WIN_MESSAGE != WIN_ERR) X11_destroy_nhwindow(WIN_MESSAGE); } #ifdef X11_HANGUP_SIGNAL static void X11_sig(sig) /* Unix signal handler */ int sig; { XtNoticeSignal(X11_sig_id); hangup(sig); } static void X11_sig_cb(not_used, id) XtPointer not_used; XtSignalId *id; { XEvent event; XClientMessageEvent *mesg; nhUse(not_used); nhUse(id); /* Set up a fake message to the event handler. */ mesg = (XClientMessageEvent *) &event; mesg->type = ClientMessage; mesg->message_type = XA_STRING; mesg->format = 8; XSendEvent(XtDisplay(window_list[WIN_MAP].w), XtWindow(window_list[WIN_MAP].w), False, NoEventMask, (XEvent *) mesg); } #endif /* delay_output ------------------------------------------------------------ */ /* * Timeout callback for delay_output(). Send a fake message to the map * window. */ /* ARGSUSED */ static void d_timeout(client_data, id) XtPointer client_data; XtIntervalId *id; { XEvent event; XClientMessageEvent *mesg; nhUse(client_data); nhUse(id); /* Set up a fake message to the event handler. */ mesg = (XClientMessageEvent *) &event; mesg->type = ClientMessage; mesg->message_type = XA_STRING; mesg->format = 8; XSendEvent(XtDisplay(window_list[WIN_MAP].w), XtWindow(window_list[WIN_MAP].w), False, NoEventMask, (XEvent *) mesg); } /* * Delay for 50ms. This is not implemented asynch. Maybe later. * Start the timeout, then wait in the event loop. The timeout * function will send an event to the map window which will be waiting * for a sent event. */ void X11_delay_output() { if (!x_inited) return; (void) XtAppAddTimeOut(app_context, 30L, d_timeout, (XtPointer) 0); /* The timeout function will enable the event loop exit. */ (void) x_event(EXIT_ON_SENT_EVENT); } /* X11_hangup -------------------------------------------------------------- */ /* ARGSUSED */ static void X11_hangup(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(w); nhUse(event); nhUse(params); nhUse(num_params); hangup(1); /* 1 is commonly SIGHUP, but ignored anyway */ exit_x_event = TRUE; } /* askname ----------------------------------------------------------------- */ /* ARGSUSED */ static void askname_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(event); nhUse(params); nhUse(num_params); nh_XtPopdown(w); (void) strcpy(plname, "Mumbles"); /* give them a name... ;-) */ exit_x_event = TRUE; } /* Callback for askname dialog widget. */ /* ARGSUSED */ static void askname_done(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { int len; char *s; Widget dialog = (Widget) client_data; nhUse(w); nhUse(call_data); s = (char *) GetDialogResponse(dialog); len = (int) strlen(s); if (len == 0) { X11_nhbell(); return; } /* Truncate name if necessary */ if (len >= (int) sizeof(plname) - 1) len = (int) sizeof(plname) - 1; (void) strncpy(plname, s, len); plname[len] = '\0'; XtFree(s); nh_XtPopdown(XtParent(dialog)); exit_x_event = TRUE; } void X11_askname() { Widget popup, dialog; Arg args[1]; XtSetArg(args[0], XtNallowShellResize, True); popup = XtCreatePopupShell("askname", transientShellWidgetClass, toplevel, args, ONE); XtOverrideTranslations( popup, XtParseTranslationTable("WM_PROTOCOLS: askname_delete()")); dialog = CreateDialog(popup, nhStr("dialog"), askname_done, (XtCallbackProc) 0); SetDialogPrompt(dialog, nhStr("What is your name?")); /* set prompt */ SetDialogResponse(dialog, nhStr("")); /* set default answer */ XtRealizeWidget(popup); positionpopup(popup, TRUE); /* center,bottom */ nh_XtPopup(popup, (int) XtGrabExclusive, dialog); /* The callback will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); } /* getline ----------------------------------------------------------------- */ /* This uses Tim Theisen's dialog widget set (from GhostView). */ static Widget getline_popup, getline_dialog; #define CANCEL_STR "\033" static char *getline_input; /* Callback for getline dialog widget. */ /* ARGSUSED */ static void done_button(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { int len; char *s; Widget dialog = (Widget) client_data; nhUse(w); nhUse(call_data); s = (char *) GetDialogResponse(dialog); len = strlen(s); /* Truncate input if necessary */ if (len >= BUFSZ) len = BUFSZ - 1; (void) strncpy(getline_input, s, len); getline_input[len] = '\0'; XtFree(s); nh_XtPopdown(XtParent(dialog)); exit_x_event = TRUE; } /* ARGSUSED */ static void getline_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(event); nhUse(params); nhUse(num_params); Strcpy(getline_input, CANCEL_STR); nh_XtPopdown(w); exit_x_event = TRUE; } /* Callback for getline dialog widget. */ /* ARGSUSED */ static void abort_button(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget dialog = (Widget) client_data; nhUse(w); nhUse(call_data); Strcpy(getline_input, CANCEL_STR); nh_XtPopdown(XtParent(dialog)); exit_x_event = TRUE; } void X11_getlin(question, input) const char *question; char *input; { static boolean need_to_init = True; getline_input = input; flush_screen(1); if (need_to_init) { Arg args[1]; need_to_init = False; XtSetArg(args[0], XtNallowShellResize, True); getline_popup = XtCreatePopupShell( "getline", transientShellWidgetClass, toplevel, args, ONE); XtOverrideTranslations( getline_popup, XtParseTranslationTable( "WM_PROTOCOLS: getline_delete()")); getline_dialog = CreateDialog(getline_popup, nhStr("dialog"), done_button, abort_button); XtRealizeWidget(getline_popup); XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup), &wm_delete_window, 1); } SetDialogPrompt(getline_dialog, (String) question); /* set prompt */ SetDialogResponse(getline_dialog, nhStr("")); /* set default answer */ positionpopup(getline_popup, TRUE); /* center,bottom */ nh_XtPopup(getline_popup, (int) XtGrabExclusive, getline_dialog); /* The callback will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); } /* Display file ------------------------------------------------------------ */ static const char display_translations[] = "#override\n\ q: dismiss_file()\n\ Escape: dismiss_file()\n\ : dismiss_file()"; /* WM_DELETE_WINDOW callback for file dismissal. */ /*ARGSUSED*/ static void delete_file(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(event); nhUse(params); nhUse(num_params); nh_XtPopdown(w); XtDestroyWidget(w); } /* Callback for file dismissal. */ /*ARGSUSED*/ static void dismiss_file(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { Widget popup = XtParent(w); nhUse(event); nhUse(params); nhUse(num_params); nh_XtPopdown(popup); XtDestroyWidget(popup); } void X11_display_file(str, complain) const char *str; boolean complain; { dlb *fp; Arg args[12]; Cardinal num_args; Widget popup, dispfile; Position top_margin, bottom_margin, left_margin, right_margin; XFontStruct *fs; int new_width, new_height; #define LLEN 128 char line[LLEN]; int num_lines; char *textlines; int charcount; /* Use the port-independent file opener to see if the file exists. */ fp = dlb_fopen(str, RDTMODE); if (!fp) { if (complain) pline("Cannot open %s. Sorry.", str); return; /* it doesn't exist, ignore */ } /* * Count the number of lines and characters in the file. */ num_lines = 0; charcount = 1; while (dlb_fgets(line, LLEN, fp)) { num_lines++; charcount += strlen(line); } (void) dlb_fclose(fp); /* Ignore empty files */ if (num_lines == 0) return; /* If over the max window size, truncate the window size to the max */ if (num_lines >= DISPLAY_FILE_SIZE) num_lines = DISPLAY_FILE_SIZE; /* * Re-open the file and read the data into a buffer. Cannot use * the XawAsciiFile type of widget, because that is not DLB-aware. */ textlines = (char *) alloc((unsigned int) charcount); textlines[0] = '\0'; fp = dlb_fopen(str, RDTMODE); while (dlb_fgets(line, LLEN, fp)) { (void) strcat(textlines, line); } (void) dlb_fclose(fp); num_args = 0; XtSetArg(args[num_args], nhStr(XtNtitle), str); num_args++; popup = XtCreatePopupShell("display_file", topLevelShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations( popup, XtParseTranslationTable("WM_PROTOCOLS: delete_file()")); num_args = 0; XtSetArg(args[num_args], nhStr(XtNscrollHorizontal), XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], nhStr(XtNscrollVertical), XawtextScrollAlways); num_args++; XtSetArg(args[num_args], nhStr(XtNtype), XawAsciiString); num_args++; XtSetArg(args[num_args], nhStr(XtNstring), textlines); num_args++; XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); num_args++; XtSetArg(args[num_args], nhStr(XtNtranslations), XtParseTranslationTable(display_translations)); num_args++; dispfile = XtCreateManagedWidget("text", /* name */ asciiTextWidgetClass, popup, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* Get font and border information. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfont), &fs); num_args++; XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin); num_args++; XtGetValues(dispfile, args, num_args); /* * The data files are currently set up assuming an 80 char wide window * and a fixed width font. Soo.. */ new_height = num_lines * nhFontHeight(dispfile) + top_margin + bottom_margin; new_width = 80 * fs->max_bounds.width + left_margin + right_margin; /* Set the new width and height. */ num_args = 0; XtSetArg(args[num_args], XtNwidth, new_width); num_args++; XtSetArg(args[num_args], XtNheight, new_height); num_args++; XtSetValues(dispfile, args, num_args); nh_XtPopup(popup, (int) XtGrabNone, (Widget) 0); free(textlines); } /* yn_function ------------------------------------------------------------- */ /* (not threaded) */ static const char *yn_quitchars = " \n\r"; static const char *yn_choices; /* string of acceptable input */ static char yn_def; static char yn_return; /* return value */ static char yn_esc_map; /* ESC maps to this char. */ static Widget yn_popup; /* popup for the yn fuction (created once) */ static Widget yn_label; /* label for yn function (created once) */ static boolean yn_getting_num; /* TRUE if accepting digits */ static boolean yn_preserve_case; /* default is to force yn to lower case */ static int yn_ndigits; /* digit count */ static long yn_val; /* accumulated value */ static const char yn_translations[] = "#override\n\ : yn_key()"; /* * Convert the given key event into a character. If the key maps to * more than one character only the first is returned. If there is * no conversion (i.e. just the CTRL key hit) a NUL is returned. */ char key_event_to_char(key) XKeyEvent *key; { char keystring[MAX_KEY_STRING]; int nbytes; boolean meta = !!(key->state & Mod1Mask); nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *) 0, (XComposeStatus *) 0); /* Modifier keys return a zero lengh string when pressed. */ if (nbytes == 0) return '\0'; return (char) (((int) keystring[0]) + (meta ? 0x80 : 0)); } /* * Called when we get a WM_DELETE_WINDOW event on a yn window. */ /* ARGSUSED */ static void yn_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(w); nhUse(event); nhUse(params); nhUse(num_params); yn_getting_num = FALSE; /* Only use yn_esc_map if we have choices. Otherwise, return ESC. */ yn_return = yn_choices ? yn_esc_map : '\033'; exit_x_event = TRUE; /* exit our event handler */ } /* * Called when we get a key press event on a yn window. */ /* ARGSUSED */ static void yn_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch; if (appResources.slow && !input_func) map_input(w, event, params, num_params); ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char or modifier event */ /* no bell */ return; } if (!yn_choices) { /* accept any input */ yn_return = ch; } else { if (!yn_preserve_case) ch = lowc(ch); /* move to lower case */ if (ch == '\033') { yn_getting_num = FALSE; yn_return = yn_esc_map; } else if (index(yn_quitchars, ch)) { yn_return = yn_def; } else if (index(yn_choices, ch)) { if (ch == '#') { if (yn_getting_num) { /* don't select again */ X11_nhbell(); return; } yn_getting_num = TRUE; yn_ndigits = 0; yn_val = 0; return; /* wait for more input */ } yn_return = ch; if (ch != 'y') yn_getting_num = FALSE; } else { if (yn_getting_num) { if (digit(ch)) { yn_ndigits++; yn_val = (yn_val * 10) + (long) (ch - '0'); return; /* wait for more input */ } if (yn_ndigits && (ch == '\b' || ch == 127 /*DEL*/)) { yn_ndigits--; yn_val = yn_val / 10; return; /* wait for more input */ } } X11_nhbell(); /* no match */ return; } if (yn_getting_num) { yn_return = '#'; if (yn_val < 0) yn_val = 0; yn_number = yn_val; /* assign global */ } } exit_x_event = TRUE; /* exit our event handler */ } char X11_yn_function(ques, choices, def) const char *ques; const char *choices; char def; { static Boolean need_to_init = True; char buf[BUFSZ]; Arg args[4]; Cardinal num_args; yn_choices = choices; /* set up globals for callback to use */ yn_def = def; yn_preserve_case = !choices; /* preserve when arbitrary response allowed */ /* * This is sort of a kludge. There are quite a few places in the main * nethack code where a pline containing information is followed by a * call to yn_function(). There is no flush of the message window * (it is implicit in the tty window port), so the line never shows * up for us! Solution: do our own flush. */ if (WIN_MESSAGE != WIN_ERR) display_message_window(&window_list[WIN_MESSAGE]); if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); /* anything beyond is hidden */ /* default when choices are present is to force yn answer to lowercase unless one or more choices are explicitly uppercase; check this before stripping the hidden choices */ for (cb = choicebuf; *cb; ++cb) if ('A' <= *cb && *cb <= 'Z') { yn_preserve_case = TRUE; break; } if ((cb = index(choicebuf, '\033')) != 0) *cb = '\0'; /* ques [choices] (def) */ if ((int) (1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= BUFSZ) panic("X11_yn_function: question too long"); (void) strncpy(buf, ques, QBUFSZ - 1); buf[QBUFSZ - 1] = '\0'; Sprintf(eos(buf), " [%s]", choicebuf); if (def) Sprintf(eos(buf), " (%c)", def); Strcat(buf, " "); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { if ((int) (1 + strlen(ques) + 1) >= BUFSZ) panic("X11_yn_function: question too long"); Strcpy(buf, ques); Strcat(buf, " "); } if (!appResources.slow && need_to_init) { need_to_init = False; XtSetArg(args[0], XtNallowShellResize, True); yn_popup = XtCreatePopupShell("query", transientShellWidgetClass, toplevel, args, ONE); XtOverrideTranslations( yn_popup, XtParseTranslationTable("WM_PROTOCOLS: yn_delete()")); num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(yn_translations)); num_args++; yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, yn_popup, args, num_args); XtRealizeWidget(yn_popup); XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup), &wm_delete_window, 1); } if (appResources.slow) input_func = yn_key; num_args = 0; XtSetArg(args[num_args], XtNlabel, buf); num_args++; XtSetValues(yn_label, args, num_args); if (!appResources.slow) { /* * Due to some kind of weird bug in the X11R4 and X11R5 shell, we * need to set the label twice to get the size to change. */ num_args = 0; XtSetArg(args[num_args], XtNlabel, buf); num_args++; XtSetValues(yn_label, args, num_args); positionpopup(yn_popup, TRUE); nh_XtPopup(yn_popup, (int) XtGrabExclusive, yn_label); } yn_getting_num = FALSE; (void) x_event(EXIT_ON_EXIT); if (appResources.slow) { input_func = 0; num_args = 0; XtSetArg(args[num_args], XtNlabel, " "); num_args++; XtSetValues(yn_label, args, num_args); } else { nh_XtPopdown(yn_popup); /* this removes the event grab */ } return yn_return; } /*ARGSUSED*/ void X11_preference_update(pref) const char *pref; { if (!strcmp(pref, "tiled_map")) { if (WIN_MAP != WIN_ERR) display_map_window(&window_list[WIN_MAP]); } } /* End global functions ==================================================== */ /* * Before we wait for input via nhgetch() and nh_poskey(), we need to * do some pre-processing. */ static int input_event(exit_condition) int exit_condition; { if (WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */ check_turn_events(); if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */ check_cursor_visibility(&window_list[WIN_MAP]); if (WIN_MESSAGE != WIN_ERR) /* reset pause line */ set_last_pause(&window_list[WIN_MESSAGE]); return x_event(exit_condition); } /*ARGSUSED*/ void msgkey(w, data, event) Widget w; XtPointer data; XEvent *event; { Cardinal num = 0; nhUse(w); nhUse(data); map_input(window_list[WIN_MAP].w, event, (String *) 0, &num); } /*ARGSUSED*/ static void win_visible(w, data, event, flag) /* only called for autofocus */ Widget w; XtPointer data; /* client_data not used */ XEvent *event; Boolean *flag; /* continue_to_dispatch flag not used */ { XVisibilityEvent *vis_event = (XVisibilityEvent *) event; nhUse(data); nhUse(flag); if (vis_event->state != VisibilityFullyObscured) { /* one-time operation; cancel ourself */ XtRemoveEventHandler(toplevel, VisibilityChangeMask, False, win_visible, (XtPointer) 0); /* grab initial input focus */ XSetInputFocus(XtDisplay(w), XtWindow(w), RevertToNone, CurrentTime); } } /* * Set up the playing console. This has three major parts: the * message window, the map, and the status window. */ static void init_standard_windows() { Widget form, message_viewport, map_viewport, status; Arg args[8]; Cardinal num_args; Dimension message_vp_width, map_vp_width, status_width, max_width; int map_vp_hd, status_hd; struct xwindow *wp; num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; form = XtCreateManagedWidget("nethack", panedWidgetClass, toplevel, args, num_args); XtAddEventHandler(form, KeyPressMask, False, (XtEventHandler) msgkey, (XtPointer) 0); if (appResources.autofocus) XtAddEventHandler(toplevel, VisibilityChangeMask, False, win_visible, (XtPointer) 0); /* * Create message window. */ WIN_MESSAGE = message_win = find_free_window(); wp = &window_list[message_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->popup = (Widget) 0; create_message_window(wp, FALSE, form); message_viewport = XtParent(wp->w); /* Tell the form that contains it that resizes are OK. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetValues(message_viewport, args, num_args); if (appResources.slow) { num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(yn_translations)); num_args++; yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, form, args, num_args); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), message_viewport); num_args++; XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; XtSetArg(args[num_args], nhStr(XtNlabel), " "); num_args++; XtSetValues(yn_label, args, num_args); } /* * Create the map window & viewport and chain the viewport beneath the * message_viewport. */ map_win = find_free_window(); wp = &window_list[map_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->popup = (Widget) 0; create_map_window(wp, FALSE, form); map_viewport = XtParent(wp->w); /* Chain beneath message_viewport or yn window. */ num_args = 0; if (appResources.slow) { XtSetArg(args[num_args], nhStr(XtNfromVert), yn_label); num_args++; } else { XtSetArg(args[num_args], nhStr(XtNfromVert), message_viewport); num_args++; } XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++; XtSetValues(map_viewport, args, num_args); /* Create the status window, with the form as it's parent. */ status_win = find_free_window(); wp = &window_list[status_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->popup = (Widget) 0; create_status_window(wp, FALSE, form); status = wp->w; /* * Chain the status window beneath the viewport. Mark the left and right * edges so that they stay a fixed distance from the left edge of the * parent, as well as the top and bottom edges so that they stay a fixed * distance from the bottom of the parent. We do this so that the status * will never expand or contract. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), map_viewport); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainBottom); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++; XtSetValues(status, args, num_args); /* * Realize the popup so that the status widget knows it's size. * * If we unset MappedWhenManaged then the DECwindow driver doesn't * attach the nethack toplevel to the highest virtual root window. * So don't do it. */ /* XtSetMappedWhenManaged(toplevel, False); */ XtRealizeWidget(toplevel); wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False); XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel), &wm_delete_window, 1); /* * Resize to at most full-screen. */ { #define TITLEBAR_SPACE 18 /* Leave SOME screen for window decorations */ int screen_width = WidthOfScreen(XtScreen(wp->w)); int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE; Dimension form_width, form_height; XtSetArg(args[0], XtNwidth, &form_width); XtSetArg(args[1], XtNheight, &form_height); XtGetValues(toplevel, args, TWO); if (form_width > screen_width || form_height > screen_height) { XtSetArg(args[0], XtNwidth, min(form_width, screen_width)); XtSetArg(args[1], XtNheight, min(form_height, screen_height)); XtSetValues(toplevel, args, TWO); XMoveWindow(XtDisplay(toplevel), XtWindow(toplevel), 0, TITLEBAR_SPACE); } #undef TITLEBAR_SPACE } post_process_tiles(); /* after toplevel is realized */ /* * Now get the default widths of the windows. */ XtSetArg(args[0], nhStr(XtNwidth), &message_vp_width); XtGetValues(message_viewport, args, ONE); XtSetArg(args[0], nhStr(XtNwidth), &map_vp_width); XtSetArg(args[1], nhStr(XtNhorizDistance), &map_vp_hd); XtGetValues(map_viewport, args, TWO); XtSetArg(args[0], nhStr(XtNwidth), &status_width); XtSetArg(args[1], nhStr(XtNhorizDistance), &status_hd); XtGetValues(status, args, TWO); /* * Adjust positions and sizes. The message viewport widens out to the * widest width. Both the map and status are centered by adjusting * their horizDistance. */ if (map_vp_width < status_width || map_vp_width < message_vp_width) { if (status_width > message_vp_width) { XtSetArg(args[0], nhStr(XtNwidth), status_width); XtSetValues(message_viewport, args, ONE); max_width = status_width; } else { max_width = message_vp_width; } XtSetArg(args[0], nhStr(XtNhorizDistance), map_vp_hd + ((int) (max_width - map_vp_width) / 2)); XtSetValues(map_viewport, args, ONE); } else { /* map is widest */ XtSetArg(args[0], nhStr(XtNwidth), map_vp_width); XtSetValues(message_viewport, args, ONE); } /* * Clear all data values on the fancy status widget so that the values * used for spacing don't appear. This needs to be called some time * after the fancy status widget is realized (above, with the game popup), * but before it is popped up. */ null_out_status(); /* * Set the map size to its standard size. As with the message window * above, the map window needs to be set to its constrained size until * its parent (the viewport widget) was realized. * * Move the message window's slider to the bottom. */ set_map_size(&window_list[map_win], COLNO, ROWNO); set_message_slider(&window_list[message_win]); /* attempt to catch fatal X11 errors before the program quits */ (void) XtAppSetErrorHandler(app_context, (XtErrorHandler) hangup); /* We can now print to the message window. */ iflags.window_inited = 1; } void nh_XtPopup(w, g, childwid) Widget w; /* widget */ int g; /* type of grab */ Widget childwid; /* child to recieve focus (can be None) */ { XtPopup(w, (XtGrabKind) g); XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1); if (appResources.autofocus) XtSetKeyboardFocus(toplevel, childwid); } void nh_XtPopdown(w) Widget w; { XtPopdown(w); if (appResources.autofocus) XtSetKeyboardFocus(toplevel, None); } void win_X11_init(dir) int dir; { if (dir != WININIT) return; #ifdef OPENWINBUG /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these * two routines will not be found when linking. An apparently correct * executable is produced, along with nasty messages and a failure code * returned to make. The routines are in the static libXmu.a and * libXmu.sa.4.0, but not in libXmu.so.4.0. Rather than fiddle with * static linking, we do this. */ if (rn2(2) > 2) { /* i.e., FALSE that an optimizer probably can't find */ get_wmShellWidgetClass(); get_applicationShellWidgetClass(); } #endif return; } /* Callback * Scroll a viewport, using standard NH 1,2,3,4,6,7,8,9 directions. */ /*ARGSUSED*/ void nh_keyscroll(viewport, event, params, num_params) Widget viewport; XEvent *event; String *params; Cardinal *num_params; { Arg arg[2]; Widget horiz_sb, vert_sb; float top, shown; Boolean do_call; int direction; Cardinal in_nparams = (num_params ? *num_params : 0); nhUse(event); if (in_nparams != 1) return; /* bad translation */ direction = atoi(params[0]); horiz_sb = XtNameToWidget(viewport, "*horizontal"); vert_sb = XtNameToWidget(viewport, "*vertical"); if (!horiz_sb && !vert_sb) { /* Perhaps the widget enclosing this has scrollbars (could use while) */ Widget parent = XtParent(viewport); if (parent) { horiz_sb = XtNameToWidget(parent, "horizontal"); vert_sb = XtNameToWidget(parent, "vertical"); } } #define H_DELTA 0.25 /* distance of horiz shift */ /* vert shift is half of curr distance */ /* The V_DELTA is 1/2 the value of shown. */ if (horiz_sb) { XtSetArg(arg[0], nhStr(XtNshown), &shown); XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top); XtGetValues(horiz_sb, arg, TWO); do_call = True; switch (direction) { case 1: case 4: case 7: top -= H_DELTA; if (top < 0.0) top = 0.0; break; case 3: case 6: case 9: top += H_DELTA; if (top + shown > 1.0) top = 1.0 - shown; break; default: do_call = False; } if (do_call) { XtCallCallbacks(horiz_sb, XtNjumpProc, &top); } } if (vert_sb) { XtSetArg(arg[0], nhStr(XtNshown), &shown); XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top); XtGetValues(vert_sb, arg, TWO); do_call = True; switch (direction) { case 7: case 8: case 9: top -= shown / 2.0; if (top < 0.0) top = 0; break; case 1: case 2: case 3: top += shown / 2.0; if (top + shown > 1.0) top = 1.0 - shown; break; default: do_call = False; } if (do_call) { XtCallCallbacks(vert_sb, XtNjumpProc, &top); } } } /*winX.c*/ nethack-3.6.0/win/X11/winmap.c0000664000076400007660000015366412623162643014766 0ustar paxedpaxed/* NetHack 3.6 winmap.c $NHDT-Date: 1447844616 2015/11/18 11:03:36 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains: * + global functions print_glyph() and cliparound() * + the map window routines * + the char and pointer input routines * * Notes: * + We don't really have a good way to get the compiled ROWNO and * COLNO as defaults. They are hardwired to the current "correct" * values in the Window widget. I am _not_ in favor of including * some nethack include file for Window.c. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "xwindow.h" /* map widget declarations */ #include "hack.h" #include "dlb.h" #include "winX.h" #ifdef USE_XPM #include #endif /* from tile.c */ extern short glyph2tile[]; extern int total_tiles_used; /* Define these if you really want a lot of junk on your screen. */ /* #define VERBOSE */ /* print various info & events as they happen */ /* #define VERBOSE_UPDATE */ /* print screen update bounds */ /* #define VERBOSE_INPUT */ /* print input events */ #define USE_WHITE /* almost always use white as a tile cursor border */ static boolean FDECL(init_tiles, (struct xwindow *)); static void FDECL(set_button_values, (Widget, int, int, unsigned)); static void FDECL(map_check_size_change, (struct xwindow *)); static void FDECL(map_update, (struct xwindow *, int, int, int, int, BOOLEAN_P)); static void FDECL(init_text, (struct xwindow *)); static void FDECL(map_exposed, (Widget, XtPointer, XtPointer)); static void FDECL(set_gc, (Widget, Font, const char *, Pixel, GC *, GC *)); static void FDECL(get_text_gc, (struct xwindow *, Font)); static void FDECL(get_char_info, (struct xwindow *)); static void FDECL(display_cursor, (struct xwindow *)); /* Global functions ======================================================= */ void X11_print_glyph(window, x, y, glyph, bkglyph) winid window; xchar x, y; int glyph; int bkglyph UNUSED; { struct map_info_t *map_info; boolean update_bbox = FALSE; check_winid(window); if (window_list[window].type != NHW_MAP) { impossible("print_glyph: can (currently) only print to map windows"); return; } map_info = window_list[window].map_information; /* update both the tile and text backing stores */ { unsigned short *t_ptr = &map_info->tile_map.glyphs[y][x].glyph; if (*t_ptr != glyph) { *t_ptr = glyph; if (map_info->is_tile) update_bbox = TRUE; } } { uchar ch; register unsigned char *ch_ptr; int color, och; unsigned special; #ifdef TEXTCOLOR register unsigned char *co_ptr; #endif /* map glyph to character and color */ (void) mapglyph(glyph, &och, &color, &special, x, y); ch = (uchar) och; if (special != map_info->tile_map.glyphs[y][x].special) { map_info->tile_map.glyphs[y][x].special = special; update_bbox = TRUE; } /* Only update if we need to. */ ch_ptr = &map_info->text_map.text[y][x]; #ifdef TEXTCOLOR co_ptr = &map_info->text_map.colors[y][x]; if (*ch_ptr != ch || *co_ptr != color) #else if (*ch_ptr != ch) #endif { *ch_ptr = ch; #ifdef TEXTCOLOR if ((special & MG_PET) && iflags.hilite_pet) color += CLR_MAX; if ((special & MG_OBJPILE) && iflags.hilite_pile) *co_ptr = color; #endif if (!map_info->is_tile) update_bbox = TRUE; } } if (update_bbox) { /* update row bbox */ if ((uchar) x < map_info->t_start[y]) map_info->t_start[y] = x; if ((uchar) x > map_info->t_stop[y]) map_info->t_stop[y] = x; } } #ifdef CLIPPING /* * The is the tty clip call. Since X can resize at any time, we can't depend * on this being defined. */ /*ARGSUSED*/ void X11_cliparound(x, y) int x, y; { } #endif /* CLIPPING */ /* End global functions =================================================== */ #include "tile2x11.h" /* * We're expecting to never read more than one tile file per session. * If this is false, then we can make an array of this information, * or just keep it on a per-window basis. */ Pixmap tile_pixmap = None; static int tile_width; static int tile_height; static int tile_count; static XImage *tile_image = 0; /* * This structure is used for small bitmaps that are used for annotating * tiles. For example, a "heart" annotates pets. */ struct tile_annotation { Pixmap bitmap; Pixel foreground; unsigned int width, height; int hotx, hoty; /* not currently used */ }; static struct tile_annotation pet_annotation; static struct tile_annotation pile_annotation; static void init_annotation(annotation, filename, colorpixel) struct tile_annotation *annotation; char *filename; Pixel colorpixel; { Display *dpy = XtDisplay(toplevel); if (0 != XReadBitmapFile(dpy, XtWindow(toplevel), filename, &annotation->width, &annotation->height, &annotation->bitmap, &annotation->hotx, &annotation->hoty)) { char buf[BUFSZ]; Sprintf(buf, "Failed to load %s", filename); X11_raw_print(buf); } annotation->foreground = colorpixel; } /* * Put the tile image on the server. * * We can't send the image to the server until the top level * is realized. When the tile file is first processed, the top * level is not realized. This routine is called after we * realize the top level, but before we start resizing the * map viewport. */ void post_process_tiles() { Display *dpy = XtDisplay(toplevel); unsigned int width, height; if (tile_image == 0) return; /* no tiles */ height = tile_image->height; width = tile_image->width; tile_pixmap = XCreatePixmap(dpy, XtWindow(toplevel), width, height, DefaultDepth(dpy, DefaultScreen(dpy))); XPutImage(dpy, tile_pixmap, DefaultGC(dpy, DefaultScreen(dpy)), tile_image, 0, 0, 0, 0, /* src, dest top left */ width, height); XDestroyImage(tile_image); /* data bytes free'd also */ tile_image = 0; init_annotation(&pet_annotation, appResources.pet_mark_bitmap, appResources.pet_mark_color); init_annotation(&pile_annotation, appResources.pilemark_bitmap, appResources.pilemark_color); } /* * Open and read the tile file. Return TRUE if there were no problems. * Return FALSE otherwise. */ static boolean init_tiles(wp) struct xwindow *wp; { #ifdef USE_XPM XpmAttributes attributes; int errorcode; #else FILE *fp = (FILE *) 0; x11_header header; unsigned char *cp, *colormap = (unsigned char *) 0; unsigned char *tb, *tile_bytes = (unsigned char *) 0; int size; XColor *colors = (XColor *) 0; unsigned i; int x, y; int bitmap_pad; int ddepth; #endif char buf[BUFSZ]; Display *dpy = XtDisplay(toplevel); Screen *screen = DefaultScreenOfDisplay(dpy); struct map_info_t *map_info = (struct map_info_t *) 0; struct tile_map_info_t *tile_info = (struct tile_map_info_t *) 0; unsigned int image_height = 0, image_width = 0; boolean result = TRUE; XGCValues values; XtGCMask mask; /* already have tile information */ if (tile_pixmap != None) goto tiledone; map_info = wp->map_information; tile_info = &map_info->tile_map; (void) memset((genericptr_t) tile_info, 0, sizeof(struct tile_map_info_t)); /* no tile file name, no tile information */ if (!appResources.tile_file[0]) { result = FALSE; goto tiledone; } #ifdef USE_XPM attributes.valuemask = XpmCloseness; attributes.closeness = 25000; errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image, 0, &attributes); if (errorcode == XpmColorFailed) { Sprintf(buf, "Insufficient colors available to load %s.", appResources.tile_file); X11_raw_print(buf); X11_raw_print("Try closing other colorful applications and restart."); X11_raw_print("Attempting to load with inferior colors."); attributes.closeness = 50000; errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image, 0, &attributes); } if (errorcode != XpmSuccess) { if (errorcode == XpmColorFailed) { Sprintf(buf, "Insufficient colors available to load %s.", appResources.tile_file); X11_raw_print(buf); } else { Sprintf(buf, "Failed to load %s: %s", appResources.tile_file, XpmGetErrorString(errorcode)); X11_raw_print(buf); } result = FALSE; X11_raw_print("Switching to text-based mode."); goto tiledone; } /* assume a fixed number of tiles per row */ if (tile_image->width % TILES_PER_ROW != 0 || tile_image->width <= TILES_PER_ROW) { Sprintf(buf, "%s is not a multiple of %d (number of tiles/row) pixels wide", appResources.tile_file, TILES_PER_ROW); X11_raw_print(buf); XDestroyImage(tile_image); tile_image = 0; result = FALSE; goto tiledone; } /* infer tile dimensions from image size and TILES_PER_ROW */ image_width = tile_image->width; image_height = tile_image->height; tile_count = total_tiles_used; if ((tile_count % TILES_PER_ROW) != 0) { tile_count += TILES_PER_ROW - (tile_count % TILES_PER_ROW); } tile_width = image_width / TILES_PER_ROW; tile_height = image_height / (tile_count / TILES_PER_ROW); #else /* !USE_XPM */ /* any less than 16 colours makes tiles useless */ ddepth = DefaultDepthOfScreen(screen); if (ddepth < 4) { X11_raw_print("need a screen depth of at least 4"); result = FALSE; goto tiledone; } fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE); if (!fp) { X11_raw_print("can't open tile file"); result = FALSE; goto tiledone; } if ((int) fread((char *) &header, sizeof(header), 1, fp) != 1) { X11_raw_print("read of header failed"); result = FALSE; goto tiledone; } if (header.version != 2) { Sprintf(buf, "Wrong tile file version, expected 2, got %lu", header.version); X11_raw_print(buf); result = FALSE; goto tiledone; } #ifdef VERBOSE fprintf(stderr, "\ X11 tile file:\n version %ld\n ncolors %ld\n \ tile width %ld\n tile height %ld\n per row %ld\n \ ntiles %ld\n", header.version, header.ncolors, header.tile_width, header.tile_height, header.per_row, header.ntiles); #endif size = 3 * header.ncolors; colormap = (unsigned char *) alloc((unsigned) size); if ((int) fread((char *) colormap, 1, size, fp) != size) { X11_raw_print("read of colormap failed"); result = FALSE; goto tiledone; } colors = (XColor *) alloc(sizeof(XColor) * (unsigned) header.ncolors); for (i = 0; i < header.ncolors; i++) { cp = colormap + (3 * i); colors[i].red = cp[0] * 256; colors[i].green = cp[1] * 256; colors[i].blue = cp[2] * 256; colors[i].flags = 0; colors[i].pixel = 0; if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i]) && !nhApproxColor(screen, DefaultColormapOfScreen(screen), (char *) 0, &colors[i])) { Sprintf(buf, "%dth out of %ld color allocation failed", i, header.ncolors); X11_raw_print(buf); result = FALSE; goto tiledone; } } size = header.tile_height * header.tile_width; /* * This alloc() and the one below require 32-bit ints, since tile_bytes * is currently ~200k and alloc() takes an int */ tile_count = header.ntiles; if ((tile_count % header.per_row) != 0) { tile_count += header.per_row - (tile_count % header.per_row); } tile_bytes = (unsigned char *) alloc((unsigned) tile_count * size); if ((int) fread((char *) tile_bytes, size, tile_count, fp) != tile_count) { X11_raw_print("read of tile bytes failed"); result = FALSE; goto tiledone; } if (header.ntiles < (unsigned) total_tiles_used) { Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu", total_tiles_used, header.ntiles); X11_raw_print(buf); result = FALSE; goto tiledone; } if (appResources.double_tile_size) { tile_width = 2 * header.tile_width; tile_height = 2 * header.tile_height; } else { tile_width = header.tile_width; tile_height = header.tile_height; } image_height = tile_height * tile_count / header.per_row; image_width = tile_width * header.per_row; /* calculate bitmap_pad */ if (ddepth > 16) bitmap_pad = 32; else if (ddepth > 8) bitmap_pad = 16; else bitmap_pad = 8; tile_image = XCreateImage(dpy, DefaultVisualOfScreen(screen), ddepth, /* depth */ ZPixmap, /* format */ 0, /* offset */ (char *) 0, /* data */ image_width, /* width */ image_height, /* height */ bitmap_pad, /* bit pad */ 0); /* bytes_per_line */ if (!tile_image) impossible("init_tiles: insufficient memory to create image"); /* now we know the physical memory requirements, we can allocate space */ tile_image->data = (char *) alloc((unsigned) tile_image->bytes_per_line * image_height); if (appResources.double_tile_size) { unsigned long *expanded_row = (unsigned long *) alloc(sizeof(unsigned long) * image_width); tb = tile_bytes; for (y = 0; y < (int) image_height; y++) { for (x = 0; x < (int) image_width / 2; x++) expanded_row[2 * x] = expanded_row[(2 * x) + 1] = colors[*tb++].pixel; for (x = 0; x < (int) image_width; x++) XPutPixel(tile_image, x, y, expanded_row[x]); y++; /* duplicate row */ for (x = 0; x < (int) image_width; x++) XPutPixel(tile_image, x, y, expanded_row[x]); } free((genericptr_t) expanded_row); } else { for (tb = tile_bytes, y = 0; y < (int) image_height; y++) for (x = 0; x < (int) image_width; x++, tb++) XPutPixel(tile_image, x, y, colors[*tb].pixel); } #endif /* ?USE_XPM */ /* fake an inverted tile by drawing a border around the edges */ #ifdef USE_WHITE /* use white or black as the border */ mask = GCFunction | GCForeground | GCGraphicsExposures; values.graphics_exposures = False; values.foreground = WhitePixelOfScreen(screen); values.function = GXcopy; tile_info->white_gc = XtGetGC(wp->w, mask, &values); values.graphics_exposures = False; values.foreground = BlackPixelOfScreen(screen); values.function = GXcopy; tile_info->black_gc = XtGetGC(wp->w, mask, &values); #else /* * Use xor so we don't have to check for special colors. Xor white * against the upper left pixel of the corridor so that we have a * white rectangle when in a corridor. */ mask = GCFunction | GCForeground | GCGraphicsExposures; values.graphics_exposures = False; values.foreground = WhitePixelOfScreen(screen) ^ XGetPixel(tile_image, 0, tile_height * glyph2tile[cmap_to_glyph(S_corr)]); values.function = GXxor; tile_info->white_gc = XtGetGC(wp->w, mask, &values); mask = GCFunction | GCGraphicsExposures; values.function = GXCopy; values.graphics_exposures = False; tile_info->black_gc = XtGetGC(wp->w, mask, &values); #endif /* USE_WHITE */ tiledone: #ifndef USE_XPM if (fp) (void) fclose(fp); if (colormap) free((genericptr_t) colormap); if (tile_bytes) free((genericptr_t) tile_bytes); if (colors) free((genericptr_t) colors); #endif if (result) { /* succeeded */ tile_info->square_height = tile_height; tile_info->square_width = tile_width; tile_info->square_ascent = 0; tile_info->square_lbearing = 0; tile_info->image_width = image_width; tile_info->image_height = image_height; } return result; } /* * Make sure the map's cursor is always visible. */ void check_cursor_visibility(wp) struct xwindow *wp; { Arg arg[2]; Widget viewport, horiz_sb, vert_sb; float top, shown, cursor_middle; Boolean do_call, adjusted = False; #ifdef VERBOSE char *s; #endif viewport = XtParent(wp->w); horiz_sb = XtNameToWidget(viewport, "horizontal"); vert_sb = XtNameToWidget(viewport, "vertical"); /* All values are relative to currently visible area */ #define V_BORDER 0.25 /* if this far from vert edge, shift */ #define H_BORDER 0.25 /* if this from from horiz edge, shift */ #define H_DELTA 0.25 /* distance of horiz shift */ #define V_DELTA 0.25 /* distance of vert shift */ if (horiz_sb) { XtSetArg(arg[0], XtNshown, &shown); XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top); XtGetValues(horiz_sb, arg, TWO); /* [ALI] Don't assume map widget is the same size as actual map */ if (wp->map_information->is_tile) cursor_middle = wp->map_information->tile_map.square_width; else cursor_middle = wp->map_information->text_map.square_width; cursor_middle = (wp->cursx + 0.5) * cursor_middle / wp->pixel_width; do_call = True; #ifdef VERBOSE if (cursor_middle < top) { s = " outside left"; } else if (cursor_middle < top + shown * H_BORDER) { s = " close to left"; } else if (cursor_middle > (top + shown)) { s = " outside right"; } else if (cursor_middle > (top + shown - shown * H_BORDER)) { s = " close to right"; } else { s = ""; } printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s); #endif if (cursor_middle < top) { top = cursor_middle - shown * H_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle < top + shown * H_BORDER) { top -= shown * H_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle > (top + shown)) { top = cursor_middle - shown * H_DELTA; if (top < 0.0) top = 0.0; if (top + shown > 1.0) top = 1.0 - shown; } else if (cursor_middle > (top + shown - shown * H_BORDER)) { top += shown * H_DELTA; if (top + shown > 1.0) top = 1.0 - shown; } else { do_call = False; } if (do_call) { XtCallCallbacks(horiz_sb, XtNjumpProc, &top); adjusted = True; } } if (vert_sb) { XtSetArg(arg[0], XtNshown, &shown); XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top); XtGetValues(vert_sb, arg, TWO); if (wp->map_information->is_tile) cursor_middle = wp->map_information->tile_map.square_height; else cursor_middle = wp->map_information->text_map.square_height; cursor_middle = (wp->cursy + 0.5) * cursor_middle / wp->pixel_height; do_call = True; #ifdef VERBOSE if (cursor_middle < top) { s = " above top"; } else if (cursor_middle < top + shown * V_BORDER) { s = " close to top"; } else if (cursor_middle > (top + shown)) { s = " below bottom"; } else if (cursor_middle > (top + shown - shown * V_BORDER)) { s = " close to bottom"; } else { s = ""; } printf("%sVert: shown = %3.2f, top = %3.2f%s", horiz_sb ? "; " : "", shown, top, s); #endif if (cursor_middle < top) { top = cursor_middle - shown * V_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle < top + shown * V_BORDER) { top -= shown * V_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle > (top + shown)) { top = cursor_middle - shown * V_DELTA; if (top < 0.0) top = 0.0; if (top + shown > 1.0) top = 1.0 - shown; } else if (cursor_middle > (top + shown - shown * V_BORDER)) { top += shown * V_DELTA; if (top + shown > 1.0) top = 1.0 - shown; } else { do_call = False; } if (do_call) { XtCallCallbacks(vert_sb, XtNjumpProc, &top); adjusted = True; } } /* make sure cursor is displayed during dowhatis.. */ if (adjusted) display_cursor(wp); #ifdef VERBOSE if (horiz_sb || vert_sb) printf("\n"); #endif } /* * Check to see if the viewport has grown smaller. If so, then we want to * make * sure that the cursor is still on the screen. We do this to keep the cursor * on the screen when the user resizes the nethack window. */ static void map_check_size_change(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; Arg arg[2]; Dimension new_width, new_height; Widget viewport; viewport = XtParent(wp->w); XtSetArg(arg[0], XtNwidth, &new_width); XtSetArg(arg[1], XtNheight, &new_height); XtGetValues(viewport, arg, TWO); /* Only do cursor check if new size is smaller. */ if (new_width < map_info->viewport_width || new_height < map_info->viewport_height) { /* [ALI] If the viewport was larger than the map (and so the map * widget was contrained to be larger than the actual map) then we * may be able to shrink the map widget as the viewport shrinks. */ if (map_info->is_tile) { wp->pixel_width = map_info->tile_map.square_width * COLNO; wp->pixel_height = map_info->tile_map.square_height * ROWNO; } else { wp->pixel_width = map_info->text_map.square_width * COLNO; wp->pixel_height = map_info->text_map.square_height * ROWNO; } if (wp->pixel_width < new_width) wp->pixel_width = new_width; if (wp->pixel_height < new_height) wp->pixel_height = new_height; XtSetArg(arg[0], XtNwidth, wp->pixel_width); XtSetArg(arg[1], XtNheight, wp->pixel_height); XtSetValues(wp->w, arg, TWO); check_cursor_visibility(wp); } map_info->viewport_width = new_width; map_info->viewport_height = new_height; /* [ALI] These may have changed if the user has re-sized the viewport */ XtSetArg(arg[0], XtNwidth, &wp->pixel_width); XtSetArg(arg[1], XtNheight, &wp->pixel_height); XtGetValues(wp->w, arg, TWO); } /* * Fill in parameters "regular" and "inverse" with newly created GCs. * Using the given background pixel and the foreground pixel optained * by querying the widget with the resource name. */ static void set_gc(w, font, resource_name, bgpixel, regular, inverse) Widget w; Font font; const char *resource_name; Pixel bgpixel; GC *regular, *inverse; { XGCValues values; XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont; Pixel curpixel; Arg arg[1]; XtSetArg(arg[0], (char *) resource_name, &curpixel); XtGetValues(w, arg, ONE); values.foreground = curpixel; values.background = bgpixel; values.function = GXcopy; values.font = font; *regular = XtGetGC(w, mask, &values); values.foreground = bgpixel; values.background = curpixel; values.function = GXcopy; values.font = font; *inverse = XtGetGC(w, mask, &values); } /* * Create the GC's for each color. * * I'm not sure if it is a good idea to have a GC for each color (and * inverse). It might be faster to just modify the foreground and * background colors on the current GC as needed. */ static void get_text_gc(wp, font) struct xwindow *wp; Font font; { struct map_info_t *map_info = wp->map_information; Pixel bgpixel; Arg arg[1]; /* Get background pixel. */ XtSetArg(arg[0], XtNbackground, &bgpixel); XtGetValues(wp->w, arg, ONE); #ifdef TEXTCOLOR #define set_color_gc(nh_color, resource_name) \ set_gc(wp->w, font, resource_name, bgpixel, \ &map_info->text_map.color_gcs[nh_color], \ &map_info->text_map.inv_color_gcs[nh_color]); set_color_gc(CLR_BLACK, XtNblack); set_color_gc(CLR_RED, XtNred); set_color_gc(CLR_GREEN, XtNgreen); set_color_gc(CLR_BROWN, XtNbrown); set_color_gc(CLR_BLUE, XtNblue); set_color_gc(CLR_MAGENTA, XtNmagenta); set_color_gc(CLR_CYAN, XtNcyan); set_color_gc(CLR_GRAY, XtNgray); set_color_gc(NO_COLOR, XtNforeground); set_color_gc(CLR_ORANGE, XtNorange); set_color_gc(CLR_BRIGHT_GREEN, XtNbright_green); set_color_gc(CLR_YELLOW, XtNyellow); set_color_gc(CLR_BRIGHT_BLUE, XtNbright_blue); set_color_gc(CLR_BRIGHT_MAGENTA, XtNbright_magenta); set_color_gc(CLR_BRIGHT_CYAN, XtNbright_cyan); set_color_gc(CLR_WHITE, XtNwhite); #else set_gc(wp->w, font, XtNforeground, bgpixel, &map_info->text_map.copy_gc, &map_info->text_map.inv_copy_gc); #endif } /* * Display the cursor on the map window. */ static void display_cursor(wp) struct xwindow *wp; { /* Redisplay the cursor location inverted. */ map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE); } /* * Check if there are any changed characters. If so, then plaster them on * the screen. */ void display_map_window(wp) struct xwindow *wp; { register int row; struct map_info_t *map_info = wp->map_information; if ((Is_rogue_level(&u.uz) ? map_info->is_tile : (map_info->is_tile != iflags.wc_tiled_map)) && map_info->tile_map.image_width) { /* changed map display mode, re-display the full map */ (void) memset((genericptr_t) map_info->t_start, (char) 0, sizeof(map_info->t_start)); (void) memset((genericptr_t) map_info->t_stop, (char) (COLNO - 1), sizeof(map_info->t_stop)); map_info->is_tile = iflags.wc_tiled_map && !Is_rogue_level(&u.uz); XClearWindow(XtDisplay(wp->w), XtWindow(wp->w)); set_map_size(wp, COLNO, ROWNO); check_cursor_visibility(wp); } else if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) { register unsigned int x = wp->prevx, y = wp->prevy; /* * Previous cursor position is not the same as the current * cursor position, update the old cursor position. */ if (x < map_info->t_start[y]) map_info->t_start[y] = x; if (x > map_info->t_stop[y]) map_info->t_stop[y] = x; } for (row = 0; row < ROWNO; row++) { if (map_info->t_start[row] <= map_info->t_stop[row]) { map_update(wp, row, row, (int) map_info->t_start[row], (int) map_info->t_stop[row], FALSE); map_info->t_start[row] = COLNO - 1; map_info->t_stop[row] = 0; } } display_cursor(wp); wp->prevx = wp->cursx; /* adjust old cursor position */ wp->prevy = wp->cursy; } /* * Set all map tiles to S_stone */ static void map_all_stone(map_info) struct map_info_t *map_info; { int x, y; unsigned short stone = cmap_to_glyph(S_stone); for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { map_info->tile_map.glyphs[y][x].glyph = stone; map_info->tile_map.glyphs[y][x].special = 0; } } /* * Fill the saved screen characters with the "clear" tile or character. * * Flush out everything by resetting the "new" bounds and calling * display_map_window(). */ void clear_map_window(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; /* update both tile and text backing store, then update */ map_all_stone(map_info); (void) memset((genericptr_t) map_info->text_map.text, ' ', sizeof(map_info->text_map.text)); #ifdef TEXTCOLOR (void) memset((genericptr_t) map_info->text_map.colors, NO_COLOR, sizeof(map_info->text_map.colors)); #endif /* force a full update */ (void) memset((genericptr_t) map_info->t_start, (char) 0, sizeof(map_info->t_start)); (void) memset((genericptr_t) map_info->t_stop, (char) COLNO - 1, sizeof(map_info->t_stop)); display_map_window(wp); } /* * Retreive the font associated with the map window and save attributes * that are used when updating it. */ static void get_char_info(wp) struct xwindow *wp; { XFontStruct *fs; struct map_info_t *map_info = wp->map_information; struct text_map_info_t *text_map = &map_info->text_map; fs = WindowFontStruct(wp->w); text_map->square_width = fs->max_bounds.width; text_map->square_height = fs->max_bounds.ascent + fs->max_bounds.descent; text_map->square_ascent = fs->max_bounds.ascent; text_map->square_lbearing = -fs->min_bounds.lbearing; #ifdef VERBOSE printf("Font information:\n"); printf("fid = %ld, direction = %d\n", fs->fid, fs->direction); printf("first = %d, last = %d\n", fs->min_char_or_byte2, fs->max_char_or_byte2); printf("all chars exist? %s\n", fs->all_chars_exist ? "yes" : "no"); printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n", fs->min_bounds.lbearing, fs->min_bounds.rbearing, fs->min_bounds.width, fs->min_bounds.ascent, fs->min_bounds.descent, fs->min_bounds.attributes); printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n", fs->max_bounds.lbearing, fs->max_bounds.rbearing, fs->max_bounds.width, fs->max_bounds.ascent, fs->max_bounds.descent, fs->max_bounds.attributes); printf("per_char = 0x%lx\n", (unsigned long) fs->per_char); printf("Text: (max) width = %d, height = %d\n", text_map->square_width, text_map->square_height); #endif if (fs->min_bounds.width != fs->max_bounds.width) X11_raw_print("Warning: map font is not monospaced!"); } /* * keyhit buffer */ #define INBUF_SIZE 64 int inbuf[INBUF_SIZE]; int incount = 0; int inptr = 0; /* points to valid data */ /* * Keyboard and button event handler for map window. */ void map_input(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XKeyEvent *key; XButtonEvent *button; boolean meta = FALSE; int i, nbytes; Cardinal in_nparams = (num_params ? *num_params : 0); char c; char keystring[MAX_KEY_STRING]; switch (event->type) { case ButtonPress: button = (XButtonEvent *) event; #ifdef VERBOSE_INPUT printf("button press\n"); #endif if (in_nparams > 0 && (nbytes = strlen(params[0])) < MAX_KEY_STRING) { Strcpy(keystring, params[0]); key = (XKeyEvent *) event; /* just in case */ goto key_events; } if (w != window_list[WIN_MAP].w) { #ifdef VERBOSE_INPUT printf("map_input called from wrong window\n"); #endif X11_nhbell(); return; } set_button_values(w, button->x, button->y, button->button); break; case KeyPress: #ifdef VERBOSE_INPUT printf("key: "); #endif if (appResources.slow && input_func) { (*input_func)(w, event, params, num_params); break; } /* * Don't use key_event_to_char() because we want to be able * to allow keys mapped to multiple characters. */ key = (XKeyEvent *) event; if (in_nparams > 0 && (nbytes = strlen(params[0])) < MAX_KEY_STRING) { Strcpy(keystring, params[0]); } else { /* * Assume that mod1 is really the meta key. */ meta = !!(key->state & Mod1Mask); nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *) 0, (XComposeStatus *) 0); } key_events: /* Modifier keys return a zero length string when pressed. */ if (nbytes) { #ifdef VERBOSE_INPUT printf("\""); #endif for (i = 0; i < nbytes; i++) { c = keystring[i]; if (incount < INBUF_SIZE) { inbuf[(inptr + incount) % INBUF_SIZE] = ((int) c) + (meta ? 0x80 : 0); incount++; } else { X11_nhbell(); } #ifdef VERBOSE_INPUT if (meta) /* meta will print as M */ (void) putchar('M'); if (c < ' ') { /* ctrl will print as ^ */ (void) putchar('^'); c += '@'; } (void) putchar(c); #endif } #ifdef VERBOSE_INPUT printf("\" [%d bytes]\n", nbytes); #endif } break; default: impossible("unexpected X event, type = %d\n", (int) event->type); break; } } static void set_button_values(w, x, y, button) Widget w; int x; int y; unsigned int button; { struct xwindow *wp; struct map_info_t *map_info; wp = find_widget(w); map_info = wp->map_information; if (map_info->is_tile) { click_x = x / map_info->tile_map.square_width; click_y = y / map_info->tile_map.square_height; } else { click_x = x / map_info->text_map.square_width; click_y = y / map_info->text_map.square_height; } /* The values can be out of range if the map window has been resized to be larger than the max size. */ if (click_x >= COLNO) click_x = COLNO - 1; if (click_y >= ROWNO) click_y = ROWNO - 1; /* Map all buttons but the first to the second click */ click_button = (button == Button1) ? CLICK_1 : CLICK_2; } /* * Map window expose callback. */ /*ARGSUSED*/ static void map_exposed(w, client_data, widget_data) Widget w; XtPointer client_data; /* unused */ XtPointer widget_data; /* expose event from Window widget */ { int x, y; struct xwindow *wp; struct map_info_t *map_info; unsigned width, height; int start_row, stop_row, start_col, stop_col; XExposeEvent *event = (XExposeEvent *) widget_data; int t_height, t_width; /* tile/text height & width */ nhUse(client_data); if (!XtIsRealized(w) || event->count > 0) return; wp = find_widget(w); map_info = wp->map_information; if (wp->keep_window && !map_info) return; /* * The map is sent an expose event when the viewport resizes. Make sure * that the cursor is still in the viewport after the resize. */ map_check_size_change(wp); if (event) { /* called from button-event */ x = event->x; y = event->y; width = event->width; height = event->height; } else { x = 0; y = 0; width = wp->pixel_width; height = wp->pixel_height; } /* * Convert pixels into INCLUSIVE text rows and columns. */ if (map_info->is_tile) { t_height = map_info->tile_map.square_height; t_width = map_info->tile_map.square_width; } else { t_height = map_info->text_map.square_height; t_width = map_info->text_map.square_width; } start_row = y / t_height; stop_row = ((y + height) / t_height) + ((((y + height) % t_height) == 0) ? 0 : 1) - 1; start_col = x / t_width; stop_col = ((x + width) / t_width) + ((((x + width) % t_width) == 0) ? 0 : 1) - 1; #ifdef VERBOSE printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n", x, y, width, height); printf("chars %d x %d, rows %d to %d, columns %d to %d\n", t_height, t_width, start_row, stop_row, start_col, stop_col); #endif /* Out of range values are possible if the map window is resized to be bigger than the largest expected value. */ if (stop_row >= ROWNO) stop_row = ROWNO - 1; if (stop_col >= COLNO) stop_col = COLNO - 1; map_update(wp, start_row, stop_row, start_col, stop_col, FALSE); display_cursor(wp); /* make sure cursor shows up */ } /* * Do the actual work of the putting characters onto our X window. This * is called from the expose event routine, the display window (flush) * routine, and the display cursor routine. The later involves inverting * the foreground and background colors, which are also inverted when the * position's color is above CLR_MAX. * * This works for rectangular regions (this includes one line rectangles). * The start and stop columns are *inclusive*. */ static void map_update(wp, start_row, stop_row, start_col, stop_col, inverted) struct xwindow *wp; int start_row, stop_row, start_col, stop_col; boolean inverted; { int win_start_row, win_start_col; struct map_info_t *map_info = wp->map_information; int row; register int count; if (start_row < 0 || stop_row >= ROWNO) { impossible("map_update: bad row range %d-%d\n", start_row, stop_row); return; } if (start_col < 0 || stop_col >= COLNO) { impossible("map_update: bad col range %d-%d\n", start_col, stop_col); return; } #ifdef VERBOSE_UPDATE printf("update: [0x%x] %d %d %d %d\n", (int) wp->w, start_row, stop_row, start_col, stop_col); #endif win_start_row = start_row; win_start_col = start_col; if (map_info->is_tile) { struct tile_map_info_t *tile_map = &map_info->tile_map; int cur_col; Display *dpy = XtDisplay(wp->w); Screen *screen = DefaultScreenOfDisplay(dpy); for (row = start_row; row <= stop_row; row++) { for (cur_col = start_col; cur_col <= stop_col; cur_col++) { int glyph = tile_map->glyphs[row][cur_col].glyph; int tile = glyph2tile[glyph]; int src_x, src_y; int dest_x = cur_col * tile_map->square_width; int dest_y = row * tile_map->square_height; src_x = (tile % TILES_PER_ROW) * tile_width; src_y = (tile / TILES_PER_ROW) * tile_height; XCopyArea(dpy, tile_pixmap, XtWindow(wp->w), tile_map->black_gc, /* no grapics_expose */ src_x, src_y, tile_width, tile_height, dest_x, dest_y); if (glyph_is_pet(glyph) && iflags.hilite_pet) { /* draw pet annotation (a heart) */ XSetForeground(dpy, tile_map->black_gc, pet_annotation.foreground); XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y); XSetClipMask(dpy, tile_map->black_gc, pet_annotation.bitmap); XCopyPlane(dpy, pet_annotation.bitmap, XtWindow(wp->w), tile_map->black_gc, 0, 0, pet_annotation.width, pet_annotation.height, dest_x, dest_y, 1); XSetClipOrigin(dpy, tile_map->black_gc, 0, 0); XSetClipMask(dpy, tile_map->black_gc, None); XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen)); } if ((tile_map->glyphs[row][cur_col].special & MG_OBJPILE)) { /* draw object pile annotation (a plus sign) */ XSetForeground(dpy, tile_map->black_gc, pile_annotation.foreground); XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y); XSetClipMask(dpy, tile_map->black_gc, pile_annotation.bitmap); XCopyPlane(dpy, pile_annotation.bitmap, XtWindow(wp->w), tile_map->black_gc, 0, 0, pile_annotation.width, pile_annotation.height, dest_x, dest_y, 1); XSetClipOrigin(dpy, tile_map->black_gc, 0, 0); XSetClipMask(dpy, tile_map->black_gc, None); XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen)); } } } if (inverted) { XDrawRectangle(XtDisplay(wp->w), XtWindow(wp->w), #ifdef USE_WHITE /* kludge for white square... */ (tile_map->glyphs[start_row][start_col].glyph == cmap_to_glyph(S_ice)) ? tile_map->black_gc : tile_map->white_gc, #else tile_map->white_gc, #endif start_col * tile_map->square_width, start_row * tile_map->square_height, tile_map->square_width - 1, tile_map->square_height - 1); } } else { struct text_map_info_t *text_map = &map_info->text_map; #ifdef TEXTCOLOR if (iflags.use_color) { register char *c_ptr; char *t_ptr; int cur_col, color, win_ystart; boolean cur_inv; for (row = start_row; row <= stop_row; row++) { win_ystart = text_map->square_ascent + (row * text_map->square_height); t_ptr = (char *) &(text_map->text[row][start_col]); c_ptr = (char *) &(text_map->colors[row][start_col]); cur_col = start_col; while (cur_col <= stop_col) { color = *c_ptr++; cur_inv = inverted; count = 1; while ((cur_col + count) <= stop_col && *c_ptr == color) { count++; c_ptr++; } if (color >= CLR_MAX) { color -= CLR_MAX; cur_inv = !cur_inv; } XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w), cur_inv ? text_map->inv_color_gcs[color] : text_map->color_gcs[color], text_map->square_lbearing + (text_map->square_width * cur_col), win_ystart, t_ptr, count); /* move text pointer and column count */ t_ptr += count; cur_col += count; } /* col loop */ } /* row loop */ } else #endif /* TEXTCOLOR */ { int win_row, win_xstart; /* We always start at the same x window position and have the same character count. */ win_xstart = text_map->square_lbearing + (win_start_col * text_map->square_width); count = stop_col - start_col + 1; for (row = start_row, win_row = win_start_row; row <= stop_row; row++, win_row++) { XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w), inverted ? text_map->inv_copy_gc : text_map->copy_gc, win_xstart, text_map->square_ascent + (win_row * text_map->square_height), (char *) &(text_map->text[row][start_col]), count); } } } } /* Adjust the number of rows and columns on the given map window */ void set_map_size(wp, cols, rows) struct xwindow *wp; Dimension cols, rows; { Arg args[4]; Cardinal num_args; if (wp->map_information->is_tile) { wp->pixel_width = wp->map_information->tile_map.square_width * cols; wp->pixel_height = wp->map_information->tile_map.square_height * rows; } else { wp->pixel_width = wp->map_information->text_map.square_width * cols; wp->pixel_height = wp->map_information->text_map.square_height * rows; } num_args = 0; XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } static void init_text(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; struct text_map_info_t *text_map = &map_info->text_map; (void) memset((genericptr_t) text_map->text, ' ', sizeof(text_map->text)); #ifdef TEXTCOLOR (void) memset((genericptr_t) text_map->colors, NO_COLOR, sizeof(text_map->colors)); #endif get_char_info(wp); get_text_gc(wp, WindowFont(wp->w)); } static char map_translations[] = "#override\n\ Left: scroll(4)\n\ Right: scroll(6)\n\ Up: scroll(8)\n\ Down: scroll(2)\n\ : input() \ "; /* * The map window creation routine. */ void create_map_window(wp, create_popup, parent) struct xwindow *wp; boolean create_popup; /* parent is a popup shell that we create */ Widget parent; { struct map_info_t *map_info; /* map info pointer */ Widget map, viewport; Arg args[16]; Cardinal num_args; Dimension rows, columns; #if 0 int screen_width, screen_height; #endif wp->type = NHW_MAP; if (create_popup) { /* * Create a popup that accepts key and button events. */ num_args = 0; XtSetArg(args[num_args], XtNinput, False); num_args++; wp->popup = parent = XtCreatePopupShell("nethack", topLevelShellWidgetClass, toplevel, args, num_args); /* * If we're here, then this is an auxiliary map window. If we're * cancelled via a delete window message, we should just pop down. */ } num_args = 0; XtSetArg(args[num_args], XtNallowHoriz, True); num_args++; XtSetArg(args[num_args], XtNallowVert, True); num_args++; #if 0 XtSetArg(args[num_args], XtNforceBars, True); num_args++; #endif XtSetArg(args[num_args], XtNuseBottom, True); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(map_translations)); num_args++; viewport = XtCreateManagedWidget("map_viewport", /* name */ viewportWidgetClass, /* from Window.h */ parent, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* * Create a map window. We need to set the width and height to some * value when we create it. We will change it to the value we want * later */ num_args = 0; XtSetArg(args[num_args], XtNwidth, 100); num_args++; XtSetArg(args[num_args], XtNheight, 100); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(map_translations)); num_args++; wp->w = map = XtCreateManagedWidget( "map", /* name */ windowWidgetClass, /* widget class from Window.h */ viewport, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0); map_info = wp->map_information = (struct map_info_t *) alloc(sizeof(struct map_info_t)); map_info->viewport_width = map_info->viewport_height = 0; /* reset the "new entry" indicators */ (void) memset((genericptr_t) map_info->t_start, (char) COLNO, sizeof(map_info->t_start)); (void) memset((genericptr_t) map_info->t_stop, (char) 0, sizeof(map_info->t_stop)); /* we probably want to restrict this to the 1st map window only */ map_info->is_tile = (init_tiles(wp) && iflags.wc_tiled_map); init_text(wp); /* * Initially, set the map widget to be the size specified by the * widget rows and columns resources. We need to do this to * correctly set the viewport window size. After the viewport is * realized, then the map can resize to its normal size. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNrows), &rows); num_args++; XtSetArg(args[num_args], nhStr(XtNcolumns), &columns); num_args++; XtGetValues(wp->w, args, num_args); /* Don't bother with windows larger than ROWNOxCOLNO. */ if (columns > COLNO) columns = COLNO; if (rows > ROWNO) rows = ROWNO; set_map_size(wp, columns, rows); /* * If we have created our own popup, then realize it so that the * viewport is also realized. Then resize the map window. */ if (create_popup) { XtRealizeWidget(wp->popup); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); set_map_size(wp, COLNO, ROWNO); } map_all_stone(map_info); } /* * Destroy this map window. */ void destroy_map_window(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; if (wp->popup) nh_XtPopdown(wp->popup); if (map_info) { struct text_map_info_t *text_map = &map_info->text_map; /* Free allocated GCs. */ #ifdef TEXTCOLOR int i; for (i = 0; i < CLR_MAX; i++) { XtReleaseGC(wp->w, text_map->color_gcs[i]); XtReleaseGC(wp->w, text_map->inv_color_gcs[i]); } #else XtReleaseGC(wp->w, text_map->copy_gc); XtReleaseGC(wp->w, text_map->inv_copy_gc); #endif /* Free malloc'ed space. */ free((genericptr_t) map_info); wp->map_information = 0; } /* Destroy map widget. */ if (wp->popup && !wp->keep_window) XtDestroyWidget(wp->popup), wp->popup = (Widget) 0; if (wp->keep_window) XtRemoveCallback(wp->w, XtNexposeCallback, map_exposed, (XtPointer) 0); else wp->type = NHW_NONE; /* allow re-use */ } boolean exit_x_event; /* exit condition for the event loop */ #if 0 /*******/ void pkey(k) int k; { printf("key = '%s%c'\n", (k < 32) ? "^" : "", (k < 32) ? '@' + k : k); } #endif /***0***/ /* * Main X event loop. Here we accept and dispatch X events. We only exit * under certain circumstances. */ int x_event(exit_condition) int exit_condition; { XEvent event; int retval = 0; boolean keep_going = TRUE; /* Hold globals so function is re-entrant */ boolean hold_exit_x_event = exit_x_event; click_button = NO_CLICK; /* reset click exit condition */ exit_x_event = FALSE; /* reset callback exit condition */ /* * Loop until we get a sent event, callback exit, or are accepting key * press and button press events and we receive one. */ if ((exit_condition == EXIT_ON_KEY_PRESS || exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount) goto try_test; do { XtAppNextEvent(app_context, &event); XtDispatchEvent(&event); /* See if we can exit. */ try_test: switch (exit_condition) { case EXIT_ON_SENT_EVENT: { XAnyEvent *any = (XAnyEvent *) &event; if (any->send_event) { retval = 0; keep_going = FALSE; } break; } case EXIT_ON_EXIT: if (exit_x_event) { incount = 0; retval = 0; keep_going = FALSE; } break; case EXIT_ON_KEY_PRESS: if (incount != 0) { /* get first pressed key */ --incount; retval = inbuf[inptr]; inptr = (inptr + 1) % INBUF_SIZE; /* pkey(retval); */ keep_going = FALSE; } else if (program_state.done_hup) { retval = '\033'; inptr = (inptr + 1) % INBUF_SIZE; keep_going = FALSE; } break; case EXIT_ON_KEY_OR_BUTTON_PRESS: if (incount != 0 || click_button != NO_CLICK) { if (click_button != NO_CLICK) { /* button press */ /* click values are already set */ retval = 0; } else { /* key press */ /* get first pressed key */ --incount; retval = inbuf[inptr]; inptr = (inptr + 1) % INBUF_SIZE; /* pkey(retval); */ } keep_going = FALSE; } else if (program_state.done_hup) { retval = '\033'; inptr = (inptr + 1) % INBUF_SIZE; keep_going = FALSE; } break; default: panic("x_event: unknown exit condition %d", exit_condition); break; } } while (keep_going); /* Restore globals */ exit_x_event = hold_exit_x_event; return retval; } /*winmap.c*/ nethack-3.6.0/win/X11/winmenu.c0000664000076400007660000011406612536476415015156 0ustar paxedpaxed/* NetHack 3.6 winmenu.c $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * File for creating menus. * * + Global functions: start_menu, add_menu, end_menu, select_menu */ /*#define USE_FWF*/ /* use FWF's list widget */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #include #ifdef USE_FWF #include #else #include #endif #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "winX.h" #include static void FDECL(menu_select, (Widget, XtPointer, XtPointer)); static void FDECL(invert_line, (struct xwindow *, x11_menu_item *, int, long)); static void FDECL(menu_ok, (Widget, XtPointer, XtPointer)); static void FDECL(menu_cancel, (Widget, XtPointer, XtPointer)); static void FDECL(menu_all, (Widget, XtPointer, XtPointer)); static void FDECL(menu_none, (Widget, XtPointer, XtPointer)); static void FDECL(menu_invert, (Widget, XtPointer, XtPointer)); static void FDECL(menu_search, (Widget, XtPointer, XtPointer)); static void FDECL(select_all, (struct xwindow *)); static void FDECL(select_none, (struct xwindow *)); static void FDECL(select_match, (struct xwindow *, char *)); static void FDECL(invert_all, (struct xwindow *)); static void FDECL(invert_match, (struct xwindow *, char *)); static void FDECL(menu_popdown, (struct xwindow *)); #ifdef USE_FWF static void FDECL(sync_selected, (struct menu_info_t *, int, int *)); #endif static void FDECL(move_menu, (struct menu *, struct menu *)); static void FDECL(free_menu, (struct menu *)); static void FDECL(reset_menu_to_default, (struct menu *)); static void FDECL(clear_old_menu, (struct xwindow *)); static char *FDECL(copy_of, (const char *)); #define reset_menu_count(mi) ((mi)->counting = FALSE, (mi)->menu_count = 0L) static const char menu_translations[] = "#override\n\ Left: scroll(4)\n\ Right: scroll(6)\n\ Up: scroll(8)\n\ Down: scroll(2)\n\ : menu_key()"; /* * Menu callback. */ /* ARGSUSED */ static void menu_select(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { struct xwindow *wp; struct menu_info_t *menu_info; #ifdef USE_FWF XfwfMultiListReturnStruct *lrs = (XfwfMultiListReturnStruct *) call_data; #else XawListReturnStruct *lrs = (XawListReturnStruct *) call_data; int i; x11_menu_item *curr; #endif long how_many; nhUse(client_data); wp = find_widget(w); menu_info = wp->menu_information; how_many = menu_info->counting ? menu_info->menu_count : -1L; reset_menu_count(menu_info); #ifdef USE_FWF /* if we've reached here, we've found our selected item */ switch (lrs->action) { case XfwfMultiListActionNothing: pline("menu_select: nothing action?"); break; case XfwfMultiListActionStatus: pline("menu_select: status action?"); break; case XfwfMultiListActionHighlight: case XfwfMultiListActionUnhighlight: sync_selected(menu_info, lrs->num_selected, lrs->selected_items); break; } #else for (i = 0, curr = menu_info->curr_menu.base; i < lrs->list_index; i++) { if (!curr) panic("menu_select: out of menu items!"); curr = curr->next; } XawListUnhighlight(w); /* unhilight item */ /* if the menu is not active or don't have an identifier, try again */ if (!menu_info->is_active || curr->identifier.a_void == 0) { X11_nhbell(); return; } /* if we've reached here, we've found our selected item */ curr->selected = !curr->selected; if (curr->selected) { curr->str[2] = (how_many != -1L) ? '#' : '+'; curr->pick_count = how_many; } else { curr->str[2] = '-'; curr->pick_count = -1L; } XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True); #endif if (menu_info->how == PICK_ONE) menu_popdown(wp); } /* * Called when menu window is deleted. */ /* ARGSUSED */ void menu_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(event); nhUse(params); nhUse(num_params); menu_cancel((Widget) None, (XtPointer) find_widget(w), (XtPointer) 0); } /* * Invert the count'th line (curr) in the given window. */ /*ARGSUSED*/ static void invert_line(wp, curr, which, how_many) struct xwindow *wp; x11_menu_item *curr; int which; long how_many; { #ifndef USE_FWF nhUse(which); #endif reset_menu_count(wp->menu_information); curr->selected = !curr->selected; if (curr->selected) { #ifdef USE_FWF XfwfMultiListHighlightItem((XfwfMultiListWidget) wp->w, which); #else curr->str[2] = (how_many != -1) ? '#' : '+'; #endif curr->pick_count = how_many; } else { #ifdef USE_FWF XfwfMultiListUnhighlightItem((XfwfMultiListWidget) wp->w, which); #else curr->str[2] = '-'; #endif curr->pick_count = -1L; } } /* * Called when we get a key press event on a menu window. */ /* ARGSUSED */ void menu_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { struct menu_info_t *menu_info; x11_menu_item *curr; struct xwindow *wp; char ch; int count; boolean selected_something; nhUse(params); nhUse(num_params); wp = find_widget(w); menu_info = wp->menu_information; ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } if (menu_info->is_active) { /* waiting for input */ /* first check for an explicit selector match, so that it won't be overridden if it happens to duplicate a mapped menu command (':' to look inside a container vs ':' to select via search string) */ for (curr = menu_info->curr_menu.base; curr; curr = curr->next) if (curr->identifier.a_void != 0 && curr->selector == ch) goto make_selection; ch = map_menu_cmd(ch); if (ch == '\033') { /* quit */ if (menu_info->counting) { /* when there's a count in progress, ESC discards it rather than dismissing the whole menu */ reset_menu_count(menu_info); return; } select_none(wp); } else if (ch == '\n' || ch == '\r') { ; /* accept */ } else if (isdigit(ch)) { /* special case: '0' is also the default ball class */ if (ch == '0' && !menu_info->counting && index(menu_info->curr_menu.gacc, ch)) goto group_accel; menu_info->menu_count *= 10L; menu_info->menu_count += (long) (ch - '0'); if (menu_info->menu_count != 0L) /* ignore leading zeros */ menu_info->counting = TRUE; return; } else if (ch == MENU_SEARCH) { /* search */ if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { char buf[BUFSZ + 2], tmpbuf[BUFSZ]; X11_getlin("Search for:", tmpbuf); if (!*tmpbuf || *tmpbuf == '\033') return; /* convert "string" into "*string*" for use with pmatch() */ Sprintf(buf, "*%s*", tmpbuf); if (menu_info->how == PICK_ANY) { invert_match(wp, buf); return; } else { select_match(wp, buf); } } else { X11_nhbell(); return; } } else if (ch == MENU_SELECT_ALL) { /* select all */ if (menu_info->how == PICK_ANY) select_all(wp); else X11_nhbell(); return; } else if (ch == MENU_UNSELECT_ALL) { /* unselect all */ if (menu_info->how == PICK_ANY) select_none(wp); else X11_nhbell(); return; } else if (ch == MENU_INVERT_ALL) { /* invert all */ if (menu_info->how == PICK_ANY) invert_all(wp); else X11_nhbell(); return; } else if (index(menu_info->curr_menu.gacc, ch)) { group_accel: /* matched a group accelerator */ if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { for (count = 0, curr = menu_info->curr_menu.base; curr; curr = curr->next, count++) { if (curr->identifier.a_void != 0 && curr->gselector == ch) { invert_line(wp, curr, count, -1L); /* for PICK_ONE, a group accelerator will only be included in gacc[] if it matches exactly one entry, so this must be it... */ if (menu_info->how == PICK_ONE) goto menu_done; /* pop down */ } } #ifndef USE_FWF XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True); #endif } else X11_nhbell(); return; } else { make_selection: selected_something = FALSE; for (count = 0, curr = menu_info->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0 && curr->selector == ch) break; if (curr) { invert_line(wp, curr, count, menu_info->counting ? menu_info->menu_count : -1L); #ifndef USE_FWF XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True); #endif selected_something = curr->selected; } else { X11_nhbell(); /* no match */ } if (!(selected_something && menu_info->how == PICK_ONE)) return; /* keep going */ } /* pop down */ } else { /* permanent inventory window */ if (ch != '\033') { X11_nhbell(); return; } /* pop down on ESC */ } menu_done: menu_popdown(wp); } /* ARGSUSED */ static void menu_ok(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; nhUse(w); nhUse(call_data); menu_popdown(wp); } /* ARGSUSED */ static void menu_cancel(w, client_data, call_data) Widget w; /* don't use - may be None */ XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; nhUse(w); nhUse(call_data); if (wp->menu_information->is_active) { select_none(wp); wp->menu_information->cancelled = TRUE; } menu_popdown(wp); } /* ARGSUSED */ static void menu_all(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(call_data); select_all((struct xwindow *) client_data); } /* ARGSUSED */ static void menu_none(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(call_data); select_none((struct xwindow *) client_data); } /* ARGSUSED */ static void menu_invert(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(call_data); invert_all((struct xwindow *) client_data); } /* ARGSUSED */ static void menu_search(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; struct menu_info_t *menu_info = wp->menu_information; char buf[BUFSZ + 2], tmpbuf[BUFSZ]; nhUse(w); nhUse(call_data); X11_getlin("Search for:", tmpbuf); if (!*tmpbuf || *tmpbuf == '\033') return; /* convert "string" into "*string*" for use with pmatch() */ Sprintf(buf, "*%s*", tmpbuf); if (menu_info->how == PICK_ANY) invert_match(wp, buf); else select_match(wp, buf); if (menu_info->how == PICK_ONE) menu_popdown(wp); } static void select_all(wp) struct xwindow *wp; { x11_menu_item *curr; int count; boolean changed = FALSE; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0) if (!curr->selected) { invert_line(wp, curr, count, -1L); changed = TRUE; } #ifndef USE_FWF if (changed) XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void select_none(wp) struct xwindow *wp; { x11_menu_item *curr; int count; boolean changed = FALSE; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0) if (curr->selected) { invert_line(wp, curr, count, -1L); changed = TRUE; } #ifndef USE_FWF if (changed) XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void invert_all(wp) struct xwindow *wp; { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0) invert_line(wp, curr, count, -1L); #ifndef USE_FWF XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void invert_match(wp, match) struct xwindow *wp; char *match; /* wildcard pattern for pmatch() */ { x11_menu_item *curr; int count; boolean changed = FALSE; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0 && pmatchi(match, curr->str)) { invert_line(wp, curr, count, -1L); changed = TRUE; } #ifndef USE_FWF if (changed) XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void select_match(wp, match) struct xwindow *wp; char *match; /* wildcard pattern for pmatch() */ { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0 && pmatchi(match, curr->str)) { if (!curr->selected) { invert_line(wp, curr, count, -1L); #ifndef USE_FWF XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } return; } /* no match */ X11_nhbell(); } static void menu_popdown(wp) struct xwindow *wp; { nh_XtPopdown(wp->popup); /* remove the event grab */ if (wp->menu_information->is_active) exit_x_event = TRUE; /* exit our event handler */ wp->menu_information->is_up = FALSE; /* menu is down */ } #ifdef USE_FWF /* * Make sure our idea of selected matches the FWF Multilist's idea of what * is currently selected. The MultiList's selected list can change without * notifying us if one or more items are selected and then another is * selected (not toggled). Then the items that were selected are deselected * but we are not notified. */ static void sync_selected(menu_info, num_selected, items) struct menu_info_t *menu_info; int num_selected; int *items; { int i, j, *ip; x11_menu_item *curr; Boolean found; for (i = 0, curr = menu_info->curr_menu.base; curr; i++, curr = curr->next) { found = False; for (j = 0, ip = items; j < num_selected; j++, ip++) if (*ip == i) { found = True; break; } #if 0 if (curr->selected && !found) printf("sync: deselecting %s\n", curr->str); else if (!curr->selected && found) printf("sync: selecting %s\n", curr->str); #endif curr->selected = found ? TRUE : FALSE; } } #endif /* USE_FWF */ /* Global functions ======================================================== */ void X11_start_menu(window) winid window; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; if (wp->menu_information->is_menu) { /* make sure we'ere starting with a clean slate */ free_menu(&wp->menu_information->new_menu); } else { wp->menu_information->is_menu = TRUE; } } /*ARGSUSED*/ void X11_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; int glyph; /* unused (for now) */ const anything *identifier; char ch; char gch; /* group accelerator (0 = no group) */ int attr; const char *str; boolean preselected; { x11_menu_item *item; struct menu_info_t *menu_info; nhUse(glyph); nhUse(preselected); /*FIXME*/ check_winid(window); menu_info = window_list[window].menu_information; if (!menu_info->is_menu) { impossible("add_menu: called before start_menu"); return; } item = (x11_menu_item *) alloc((unsigned) sizeof(x11_menu_item)); item->next = (x11_menu_item *) 0; item->identifier = *identifier; item->attr = attr; /* item->selected = preselected; */ item->selected = FALSE; item->pick_count = -1L; if (identifier->a_void) { char buf[4 + BUFSZ]; int len = strlen(str); if (!ch) { /* Supply a keyboard accelerator. Only the first 52 get one. */ if (menu_info->new_menu.curr_selector) { ch = menu_info->new_menu.curr_selector++; if (ch == 'z') menu_info->new_menu.curr_selector = 'A'; else if (ch == 'Z') menu_info->new_menu.curr_selector = 0; /* out */ } } if (len >= BUFSZ) { /* We *think* everything's coming in off at most BUFSZ bufs... */ impossible("Menu item too long (%d).", len); len = BUFSZ - 1; } Sprintf(buf, "%c - ", ch ? ch : ' '); (void) strncpy(buf + 4, str, len); buf[4 + len] = '\0'; item->str = copy_of(buf); } else { /* no keyboard accelerator */ item->str = copy_of(str); ch = 0; } item->selector = ch; item->gselector = gch; if (menu_info->new_menu.last) { menu_info->new_menu.last->next = item; } else { menu_info->new_menu.base = item; } menu_info->new_menu.last = item; menu_info->new_menu.count++; } void X11_end_menu(window, query) winid window; const char *query; { struct menu_info_t *menu_info; check_winid(window); menu_info = window_list[window].menu_information; if (!menu_info->is_menu) { impossible("end_menu: called before start_menu"); return; } menu_info->new_menu.query = copy_of(query); } int X11_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { x11_menu_item *curr; struct xwindow *wp; struct menu_info_t *menu_info; Arg args[10]; Cardinal num_args; String *ptr; int retval; Dimension v_pixel_width, v_pixel_height; boolean labeled; Widget viewport_widget, form, label, ok, cancel, all, none, invert, search; Boolean sens; #ifdef USE_FWF Boolean *boolp; #endif char gacc[QBUFSZ], *ap; *menu_list = (menu_item *) 0; check_winid(window); wp = &window_list[window]; menu_info = wp->menu_information; if (!menu_info->is_menu) { impossible("select_menu: called before start_menu"); return 0; } menu_info->how = (short) how; /* collect group accelerators; for PICK_NONE, they're ignored; for PICK_ONE, only those which match exactly one entry will be accepted; for PICK_ANY, those which match any entry are okay */ gacc[0] = '\0'; if (menu_info->how != PICK_NONE) { int i, n, gcnt[128]; #define GSELIDX(c) ((c) &127) /* guard against `signed char' */ for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0; for (n = 0, curr = menu_info->new_menu.base; curr; curr = curr->next) if (curr->gselector && curr->gselector != curr->selector) { ++n; ++gcnt[GSELIDX(curr->gselector)]; } if (n > 0) /* at least one group accelerator found */ for (ap = gacc, curr = menu_info->new_menu.base; curr; curr = curr->next) if (curr->gselector && !index(gacc, curr->gselector) && (menu_info->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { *ap++ = curr->gselector; *ap = '\0'; /* re-terminate for index() */ } } menu_info->new_menu.gacc = copy_of(gacc); reset_menu_count(menu_info); /* * Create a string and sensitive list for the new menu. */ menu_info->new_menu.list_pointer = ptr = (String *) alloc( (unsigned) (sizeof(String) * (menu_info->new_menu.count + 1))); for (curr = menu_info->new_menu.base; curr; ptr++, curr = curr->next) *ptr = (String) curr->str; *ptr = 0; /* terminate list with null */ #ifdef USE_FWF menu_info->new_menu.sensitive = boolp = (Boolean *) alloc( (unsigned) (sizeof(Boolean) * (menu_info->new_menu.count))); for (curr = menu_info->new_menu.base; curr; boolp++, curr = curr->next) *boolp = (curr->identifier.a_void != 0); #else menu_info->new_menu.sensitive = (Boolean *) 0; #endif labeled = (menu_info->new_menu.query && *(menu_info->new_menu.query)) ? TRUE : FALSE; /* * Menus don't appear to size components correctly, except * when first created. For 3.2.0 release, just recreate * each time. */ if (menu_info->valid_widgets && (window != WIN_INVEN || !flags.perm_invent)) { XtDestroyWidget(wp->popup); menu_info->valid_widgets = FALSE; menu_info->is_up = FALSE; } if (!menu_info->valid_widgets) { Dimension row_spacing; num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; wp->popup = XtCreatePopupShell(window == WIN_INVEN ? "inventory" : "menu", how == PICK_NONE ? topLevelShellWidgetClass : transientShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations( wp->popup, XtParseTranslationTable("WM_PROTOCOLS: menu_delete()")); num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(menu_translations)); num_args++; form = XtCreateManagedWidget("mform", formWidgetClass, wp->popup, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; if (labeled) label = XtCreateManagedWidget(menu_info->new_menu.query, labelWidgetClass, form, args, num_args); else label = NULL; /* * Create ok, cancel, all, none, invert, and search buttons.. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; ok = XtCreateManagedWidget("OK", commandWidgetClass, form, args, num_args); XtAddCallback(ok, XtNcallback, menu_ok, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), ok); num_args++; XtSetArg(args[num_args], nhStr(XtNsensitive), how != PICK_NONE); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; cancel = XtCreateManagedWidget("cancel", commandWidgetClass, form, args, num_args); XtAddCallback(cancel, XtNcallback, menu_cancel, (XtPointer) wp); sens = (how == PICK_ANY); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), cancel); num_args++; XtSetArg(args[num_args], nhStr(XtNsensitive), sens); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; all = XtCreateManagedWidget("all", commandWidgetClass, form, args, num_args); XtAddCallback(all, XtNcallback, menu_all, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), all); num_args++; XtSetArg(args[num_args], nhStr(XtNsensitive), sens); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; none = XtCreateManagedWidget("none", commandWidgetClass, form, args, num_args); XtAddCallback(none, XtNcallback, menu_none, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), none); num_args++; XtSetArg(args[num_args], nhStr(XtNsensitive), sens); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; invert = XtCreateManagedWidget("invert", commandWidgetClass, form, args, num_args); XtAddCallback(invert, XtNcallback, menu_invert, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), invert); num_args++; XtSetArg(args[num_args], nhStr(XtNsensitive), how != PICK_NONE); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; search = XtCreateManagedWidget("search", commandWidgetClass, form, args, num_args); XtAddCallback(search, XtNcallback, menu_search, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], nhStr(XtNallowVert), True); num_args++; XtSetArg(args[num_args], nhStr(XtNallowHoriz), False); num_args++; XtSetArg(args[num_args], nhStr(XtNuseBottom), True); num_args++; XtSetArg(args[num_args], nhStr(XtNuseRight), True); num_args++; /* XtSetArg(args[num_args], nhStr(XtNforceBars), True); num_args++; */ XtSetArg(args[num_args], nhStr(XtNfromVert), all); num_args++; XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; viewport_widget = XtCreateManagedWidget( "menu_viewport", /* name */ viewportWidgetClass, form, /* parent widget */ args, num_args); /* values, and number of values */ /* make new menu the current menu */ move_menu(&menu_info->new_menu, &menu_info->curr_menu); num_args = 0; XtSetArg(args[num_args], nhStr(XtNforceColumns), True); num_args++; XtSetArg(args[num_args], nhStr(XtNcolumnSpacing), 1); num_args++; XtSetArg(args[num_args], nhStr(XtNdefaultColumns), 1); num_args++; XtSetArg(args[num_args], nhStr(XtNlist), menu_info->curr_menu.list_pointer); num_args++; #ifdef USE_FWF XtSetArg(args[num_args], nhStr(XtNsensitiveArray), menu_info->curr_menu.sensitive); num_args++; XtSetArg(args[num_args], nhStr(XtNmaxSelectable), menu_info->curr_menu.count); num_args++; #endif wp->w = XtCreateManagedWidget("menu_list", /* name */ #ifdef USE_FWF xfwfMultiListWidgetClass, #else listWidgetClass, #endif viewport_widget, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ XtAddCallback(wp->w, XtNcallback, menu_select, (XtPointer) 0); /* Get the font and margin information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &menu_info->fs); num_args++; XtSetArg(args[num_args], XtNinternalHeight, &menu_info->internal_height); num_args++; XtSetArg(args[num_args], XtNinternalWidth, &menu_info->internal_width); num_args++; XtSetArg(args[num_args], nhStr(XtNrowSpacing), &row_spacing); num_args++; XtGetValues(wp->w, args, num_args); /* font height is ascent + descent */ menu_info->line_height = menu_info->fs->max_bounds.ascent + menu_info->fs->max_bounds.descent + row_spacing; menu_info->valid_widgets = TRUE; num_args = 0; XtSetArg(args[num_args], XtNwidth, &v_pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, &v_pixel_height); num_args++; XtGetValues(wp->w, args, num_args); } else { Dimension len; viewport_widget = XtParent(wp->w); /* get the longest string on new menu */ v_pixel_width = 0; for (ptr = menu_info->new_menu.list_pointer; *ptr; ptr++) { len = XTextWidth(menu_info->fs, *ptr, strlen(*ptr)); if (len > v_pixel_width) v_pixel_width = len; } /* add viewport internal border */ v_pixel_width += 2 * menu_info->internal_width; v_pixel_height = (2 * menu_info->internal_height) + (menu_info->new_menu.count * menu_info->line_height); /* make new menu the current menu */ move_menu(&menu_info->new_menu, &menu_info->curr_menu); #ifdef USE_FWF XfwfMultiListSetNewData((XfwfMultiListWidget) wp->w, menu_info->curr_menu.list_pointer, 0, 0, TRUE, menu_info->curr_menu.sensitive); #else XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, TRUE); #endif } /* if viewport will be bigger than the screen, limit its height */ num_args = 0; XtSetArg(args[num_args], XtNwidth, &v_pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, &v_pixel_height); num_args++; XtGetValues(wp->w, args, num_args); if ((Dimension) XtScreen(wp->w)->height * 5 / 6 < v_pixel_height) { /* scrollbar is 14 pixels wide. Widen the form to accommodate it. */ v_pixel_width += 14; /* shrink to fit vertically */ v_pixel_height = XtScreen(wp->w)->height * 5 / 6; num_args = 0; XtSetArg(args[num_args], XtNwidth, v_pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, v_pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } XtRealizeWidget(wp->popup); /* need to realize before we position */ /* if menu is not up, position it */ if (!menu_info->is_up) positionpopup(wp->popup, FALSE); menu_info->is_up = TRUE; if (window == WIN_INVEN && how == PICK_NONE) { /* cant use nh_XtPopup() because it may try to grab the focus */ XtPopup(wp->popup, (int) XtGrabNone); if (!updated_inventory) XMapRaised(XtDisplay(wp->popup), XtWindow(wp->popup)); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); retval = 0; } else { menu_info->is_active = TRUE; /* waiting for user response */ menu_info->cancelled = FALSE; nh_XtPopup(wp->popup, (int) XtGrabExclusive, wp->w); (void) x_event(EXIT_ON_EXIT); menu_info->is_active = FALSE; if (menu_info->cancelled) return -1; retval = 0; for (curr = menu_info->curr_menu.base; curr; curr = curr->next) if (curr->selected) retval++; if (retval) { menu_item *mi; *menu_list = mi = (menu_item *) alloc(retval * sizeof(menu_item)); for (curr = menu_info->curr_menu.base; curr; curr = curr->next) if (curr->selected) { mi->item = curr->identifier; mi->count = curr->pick_count; mi++; } } } return retval; } /* End global functions ==================================================== */ /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in tty/wintty.c. */ static char * copy_of(s) const char *s; { if (!s) s = ""; return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); } static void move_menu(src_menu, dest_menu) struct menu *src_menu, *dest_menu; { free_menu(dest_menu); /* toss old menu */ *dest_menu = *src_menu; /* make new menu current */ /* leave no dangling ptrs */ reset_menu_to_default(src_menu); } static void free_menu(mp) struct menu *mp; { while (mp->base) { mp->last = mp->base; mp->base = mp->base->next; free((genericptr_t) mp->last->str); free((genericptr_t) mp->last); } if (mp->query) free((genericptr_t) mp->query); if (mp->gacc) free((genericptr_t) mp->gacc); if (mp->list_pointer) free((genericptr_t) mp->list_pointer); if (mp->sensitive) free((genericptr_t) mp->sensitive); reset_menu_to_default(mp); } static void reset_menu_to_default(mp) struct menu *mp; { mp->base = mp->last = (x11_menu_item *) 0; mp->query = (const char *) 0; mp->gacc = (const char *) 0; mp->count = 0; mp->list_pointer = (String *) 0; mp->sensitive = (Boolean *) 0; mp->curr_selector = 'a'; /* first accelerator */ } static void clear_old_menu(wp) struct xwindow *wp; { struct menu_info_t *menu_info = wp->menu_information; free_menu(&menu_info->curr_menu); free_menu(&menu_info->new_menu); if (menu_info->valid_widgets) { nh_XtPopdown(wp->popup); menu_info->is_up = FALSE; XtDestroyWidget(wp->popup); menu_info->valid_widgets = FALSE; wp->w = wp->popup = (Widget) 0; } } void create_menu_window(wp) struct xwindow *wp; { wp->type = NHW_MENU; wp->menu_information = (struct menu_info_t *) alloc(sizeof(struct menu_info_t)); (void) memset((genericptr_t) wp->menu_information, '\0', sizeof(struct menu_info_t)); reset_menu_to_default(&wp->menu_information->curr_menu); reset_menu_to_default(&wp->menu_information->new_menu); reset_menu_count(wp->menu_information); wp->w = wp->popup = (Widget) 0; } void destroy_menu_window(wp) struct xwindow *wp; { clear_old_menu(wp); /* this will also destroy the widgets */ free((genericptr_t) wp->menu_information); wp->menu_information = (struct menu_info_t *) 0; wp->type = NHW_NONE; /* allow re-use */ } /*winmenu.c*/ nethack-3.6.0/win/X11/winmesg.c0000664000076400007660000004502712536476415015145 0ustar paxedpaxed/* NetHack 3.6 winmesg.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Message window routines. * * Global functions: * create_message_window() * destroy_message_window() * display_message_window() * append_message() */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "xwindow.h" /* Window widget declarations */ #include "hack.h" #include "winX.h" static struct line_element *FDECL(get_previous, (struct line_element *)); static void FDECL(set_circle_buf, (struct mesg_info_t *, int)); static char *FDECL(split, (char *, XFontStruct *, DIMENSION_P)); static void FDECL(add_line, (struct mesg_info_t *, const char *)); static void FDECL(redraw_message_window, (struct xwindow *)); static void FDECL(mesg_check_size_change, (struct xwindow *)); static void FDECL(mesg_exposed, (Widget, XtPointer, XtPointer)); static void FDECL(get_gc, (Widget, struct mesg_info_t *)); static void FDECL(mesg_resized, (Widget, XtPointer, XtPointer)); static char mesg_translations[] = "#override\n\ : input() \ "; /* Move the message window's vertical scrollbar's slider to the bottom. */ void set_message_slider(wp) struct xwindow *wp; { Widget scrollbar; float top; scrollbar = XtNameToWidget(XtParent(wp->w), "vertical"); if (scrollbar) { top = 1.0; XtCallCallbacks(scrollbar, XtNjumpProc, &top); } } void create_message_window(wp, create_popup, parent) struct xwindow *wp; /* window pointer */ boolean create_popup; Widget parent; { Arg args[8]; Cardinal num_args; Widget viewport; struct mesg_info_t *mesg_info; wp->type = NHW_MESSAGE; wp->mesg_information = mesg_info = (struct mesg_info_t *) alloc(sizeof(struct mesg_info_t)); mesg_info->fs = 0; mesg_info->num_lines = 0; mesg_info->head = mesg_info->line_here = mesg_info->last_pause = mesg_info->last_pause_head = (struct line_element *) 0; mesg_info->dirty = False; mesg_info->viewport_width = mesg_info->viewport_height = 0; if (iflags.msg_history < (unsigned) appResources.message_lines) iflags.msg_history = (unsigned) appResources.message_lines; if (iflags.msg_history > MAX_HISTORY) /* a sanity check */ iflags.msg_history = MAX_HISTORY; set_circle_buf(mesg_info, (int) iflags.msg_history); /* Create a popup that becomes the parent. */ if (create_popup) { num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; wp->popup = parent = XtCreatePopupShell("message_popup", topLevelShellWidgetClass, toplevel, args, num_args); /* * If we're here, then this is an auxiliary message window. If we're * cancelled via a delete window message, we should just pop down. */ } /* * Create the viewport. We only want the vertical scroll bar ever to be * visible. If we allow the horizontal scrollbar to be visible it will * always be visible, due to the stupid way the Athena viewport operates. */ num_args = 0; XtSetArg(args[num_args], XtNallowVert, True); num_args++; viewport = XtCreateManagedWidget( "mesg_viewport", /* name */ viewportWidgetClass, /* widget class from Window.h */ parent, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* * Create a message window. We will change the width and height once * we know what font we are using. */ num_args = 0; if (!create_popup) { XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(mesg_translations)); num_args++; } wp->w = XtCreateManagedWidget( "message", /* name */ windowWidgetClass, /* widget class from Window.h */ viewport, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ XtAddCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer) 0); /* * Now adjust the height and width of the message window so that it * is appResources.message_lines high and DEFAULT_MESSAGE_WIDTH wide. */ /* Get the font information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &mesg_info->fs); num_args++; XtGetValues(wp->w, args, num_args); /* Save character information for fast use later. */ mesg_info->char_width = mesg_info->fs->max_bounds.width; mesg_info->char_height = mesg_info->fs->max_bounds.ascent + mesg_info->fs->max_bounds.descent; mesg_info->char_ascent = mesg_info->fs->max_bounds.ascent; mesg_info->char_lbearing = -mesg_info->fs->min_bounds.lbearing; get_gc(wp->w, mesg_info); wp->pixel_height = ((int) iflags.msg_history) * mesg_info->char_height; /* If a variable spaced font, only use 2/3 of the default size */ if (mesg_info->fs->min_bounds.width != mesg_info->fs->max_bounds.width) { wp->pixel_width = ((2 * DEFAULT_MESSAGE_WIDTH) / 3) * mesg_info->fs->max_bounds.width; } else wp->pixel_width = (DEFAULT_MESSAGE_WIDTH * mesg_info->fs->max_bounds.width); /* Set the new width and height. */ num_args = 0; XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); /* make sure viewport height makes sense before realizing it */ num_args = 0; mesg_info->viewport_height = appResources.message_lines * mesg_info->char_height; XtSetArg(args[num_args], XtNheight, mesg_info->viewport_height); num_args++; XtSetValues(viewport, args, num_args); XtAddCallback(wp->w, XtNresizeCallback, mesg_resized, (XtPointer) 0); /* * If we have created our own popup, then realize it so that the * viewport is also realized. */ if (create_popup) { XtRealizeWidget(wp->popup); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); } } void destroy_message_window(wp) struct xwindow *wp; { if (wp->popup) { nh_XtPopdown(wp->popup); if (!wp->keep_window) XtDestroyWidget(wp->popup), wp->popup = (Widget) 0; } if (wp->mesg_information) { set_circle_buf(wp->mesg_information, 0); /* free buffer list */ free((genericptr_t) wp->mesg_information), wp->mesg_information = 0; } if (wp->keep_window) XtRemoveCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer) 0); else wp->type = NHW_NONE; } /* Redraw message window if new lines have been added. */ void display_message_window(wp) struct xwindow *wp; { if (wp->mesg_information->dirty) redraw_message_window(wp); } /* * Append a line of text to the message window. Split the line if the * rendering of the text is too long for the window. */ void append_message(wp, str) struct xwindow *wp; const char *str; { char *mark, *remainder, buf[BUFSZ]; if (!str) return; Strcpy(buf, str); /* we might mark it up */ remainder = buf; do { mark = remainder; remainder = split(mark, wp->mesg_information->fs, wp->pixel_width); add_line(wp->mesg_information, mark); } while (remainder); } /* private functions ======================================================= */ /* * Return the element in the circular linked list just before the given * element. */ static struct line_element * get_previous(mark) struct line_element *mark; { struct line_element *curr; if (!mark) return (struct line_element *) 0; for (curr = mark; curr->next != mark; curr = curr->next) ; return curr; } /* * Set the information buffer size to count lines. We do this by creating * a circular linked list of elements, each of which represents a line of * text. New buffers are created as needed, old ones are freed if they * are no longer used. */ static void set_circle_buf(mesg_info, count) struct mesg_info_t *mesg_info; int count; { int i; struct line_element *tail, *curr, *head; if (count < 0) panic("set_circle_buf: bad count [= %d]", count); if (count == mesg_info->num_lines) return; /* no change in size */ if (count < mesg_info->num_lines) { /* * Toss num_lines - count line entries from our circular list. * * We lose lines from the front (top) of the list. We _know_ * the list is non_empty. */ tail = get_previous(mesg_info->head); for (i = mesg_info->num_lines - count; i > 0; i--) { curr = mesg_info->head; mesg_info->head = curr->next; if (curr->line) free((genericptr_t) curr->line); free((genericptr_t) curr); } if (count == 0) { /* make sure we don't have a dangling pointer */ mesg_info->head = (struct line_element *) 0; } else { tail->next = mesg_info->head; /* link the tail to the head */ } } else { /* * Add count - num_lines blank lines to the head of the list. * * Create a separate list, keeping track of the tail. */ for (head = tail = 0, i = 0; i < count - mesg_info->num_lines; i++) { curr = (struct line_element *) alloc(sizeof(struct line_element)); curr->line = 0; curr->buf_length = 0; curr->str_length = 0; if (tail) { tail->next = curr; tail = curr; } else { head = tail = curr; } } /* * Complete the circle by making the new tail point to the old head * and the old tail point to the new head. If our line count was * zero, then make the new list circular. */ if (mesg_info->num_lines) { curr = get_previous(mesg_info->head); /* get end of old list */ tail->next = mesg_info->head; /* new tail -> old head */ curr->next = head; /* old tail -> new head */ } else { tail->next = head; } mesg_info->head = head; } mesg_info->num_lines = count; /* Erase the line on a resize. */ mesg_info->last_pause = (struct line_element *) 0; } /* * Make sure the given string is shorter than the given pixel width. If * not, back up from the end by words until we find a place to split. */ static char * split(s, fs, pixel_width) char *s; XFontStruct *fs; /* Font for the window. */ Dimension pixel_width; { char save, *end, *remainder; save = '\0'; remainder = 0; end = eos(s); /* point to null at end of string */ /* assume that if end == s, XXXXXX returns 0) */ while ((Dimension) XTextWidth(fs, s, (int) strlen(s)) > pixel_width) { *end-- = save; while (*end != ' ') { if (end == s) panic("split: eos!"); --end; } save = *end; *end = '\0'; remainder = end + 1; } return remainder; } /* * Add a line of text to the window. The first line in the curcular list * becomes the last. So all we have to do is copy the new line over the * old one. If the line buffer is too small, then allocate a new, larger * one. */ static void add_line(mesg_info, s) struct mesg_info_t *mesg_info; const char *s; { register struct line_element *curr = mesg_info->head; register int new_line_length = strlen(s); if (new_line_length + 1 > curr->buf_length) { if (curr->line) free(curr->line); /* free old line */ curr->buf_length = new_line_length + 1; curr->line = (char *) alloc((unsigned) curr->buf_length); } Strcpy(curr->line, s); /* copy info */ curr->str_length = new_line_length; /* save string length */ mesg_info->head = mesg_info->head->next; /* move head to next line */ mesg_info->dirty = True; /* we have undrawn lines */ } /* * Save a position in the text buffer so we can draw a line to seperate * text from the last time this function was called. * * Save the head position, since it is the line "after" the last displayed * line in the message window. The window redraw routine will draw a * line above this saved pointer. */ void set_last_pause(wp) struct xwindow *wp; { register struct mesg_info_t *mesg_info = wp->mesg_information; #ifdef ERASE_LINE /* * If we've erased the pause line and haven't added any new lines, * don't try to erase the line again. */ if (!mesg_info->last_pause && mesg_info->last_pause_head == mesg_info->head) return; if (mesg_info->last_pause == mesg_info->head) { /* No new messages in last turn. Redraw window to erase line. */ mesg_info->last_pause = (struct line_element *) 0; mesg_info->last_pause_head = mesg_info->head; redraw_message_window(wp); } else { #endif mesg_info->last_pause = mesg_info->head; #ifdef ERASE_LINE } #endif } static void redraw_message_window(wp) struct xwindow *wp; { struct mesg_info_t *mesg_info = wp->mesg_information; register struct line_element *curr; register int row, y_base; /* * Do this the cheap and easy way. Clear the window and just redraw * the whole thing. * * This could be done more effecently with one call to XDrawText() instead * of many calls to XDrawString(). Maybe later. * * Only need to clear if window has new text. */ if (mesg_info->dirty) { XClearWindow(XtDisplay(wp->w), XtWindow(wp->w)); mesg_info->line_here = mesg_info->last_pause; } /* For now, just update the whole shootn' match. */ for (y_base = row = 0, curr = mesg_info->head; row < mesg_info->num_lines; row++, y_base += mesg_info->char_height, curr = curr->next) { XDrawString(XtDisplay(wp->w), XtWindow(wp->w), mesg_info->gc, mesg_info->char_lbearing, mesg_info->char_ascent + y_base, curr->line, curr->str_length); /* * This draws a line at the _top_ of the line of text pointed to by * mesg_info->last_pause. */ if (appResources.message_line && curr == mesg_info->line_here) { XDrawLine(XtDisplay(wp->w), XtWindow(wp->w), mesg_info->gc, 0, y_base, wp->pixel_width, y_base); } } mesg_info->dirty = False; } /* * Check the size of the viewport. If it has shrunk, then we want to * move the vertical slider to the bottom. */ static void mesg_check_size_change(wp) struct xwindow *wp; { struct mesg_info_t *mesg_info = wp->mesg_information; Arg arg[2]; Dimension new_width, new_height; Widget viewport; viewport = XtParent(wp->w); XtSetArg(arg[0], XtNwidth, &new_width); XtSetArg(arg[1], XtNheight, &new_height); XtGetValues(viewport, arg, TWO); /* Only move slider to bottom if new size is smaller. */ if (new_width < mesg_info->viewport_width || new_height < mesg_info->viewport_height) { set_message_slider(wp); } mesg_info->viewport_width = new_width; mesg_info->viewport_height = new_height; } /* Event handler for message window expose events. */ /*ARGSUSED*/ static void mesg_exposed(w, client_data, widget_data) Widget w; XtPointer client_data; /* unused */ XtPointer widget_data; /* expose event from Window widget */ { XExposeEvent *event = (XExposeEvent *) widget_data; nhUse(client_data); if (XtIsRealized(w) && event->count == 0) { struct xwindow *wp; Display *dpy; Window win; XEvent evt; /* * Drain all pending expose events for the message window; * we'll redraw the whole thing at once. */ dpy = XtDisplay(w); win = XtWindow(w); while (XCheckTypedWindowEvent(dpy, win, Expose, &evt)) continue; wp = find_widget(w); if (wp->keep_window && !wp->mesg_information) return; mesg_check_size_change(wp); redraw_message_window(wp); } } static void get_gc(w, mesg_info) Widget w; struct mesg_info_t *mesg_info; { XGCValues values; XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont; Pixel fgpixel, bgpixel; Arg arg[2]; XtSetArg(arg[0], XtNforeground, &fgpixel); XtSetArg(arg[1], XtNbackground, &bgpixel); XtGetValues(w, arg, TWO); values.foreground = fgpixel; values.background = bgpixel; values.function = GXcopy; values.font = WindowFont(w); mesg_info->gc = XtGetGC(w, mask, &values); } /* * Handle resizes on a message window. Correct saved pixel height and width. * Adjust circle buffer to accomidate the new size. * * Problem: If the resize decreases the width of the window such that * some lines are now longer than the window, they will be cut off by * X itself. All new lines will be split to the new size, but the ends * of the old ones will not be seen again unless the window is lengthened. * I don't deal with this problem because it isn't worth the trouble. */ /* ARGSUSED */ static void mesg_resized(w, client_data, call_data) Widget w; XtPointer call_data, client_data; { Arg args[4]; Cardinal num_args; Dimension pixel_width, pixel_height; struct xwindow *wp; #ifdef VERBOSE int old_lines; old_lines = wp->mesg_information->num_lines; ; #endif nhUse(call_data); nhUse(client_data); num_args = 0; XtSetArg(args[num_args], XtNwidth, &pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, &pixel_height); num_args++; XtGetValues(w, args, num_args); wp = find_widget(w); wp->pixel_width = pixel_width; wp->pixel_height = pixel_height; set_circle_buf(wp->mesg_information, (int) pixel_height / wp->mesg_information->char_height); #ifdef VERBOSE printf("Message resize. Pixel: width = %d, height = %d; Lines: old = " "%d, new = %d\n", pixel_width, pixel_height, old_lines, wp->mesg_information->num_lines); #endif } /*winmesg.c*/ nethack-3.6.0/win/X11/winmisc.c0000664000076400007660000007303412536476415015144 0ustar paxedpaxed/* NetHack 3.6 winmisc.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Misc. popup windows: player selection and extended commands. * * + Global functions: player_selection() and get_ext_cmd(). */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include /* for index() */ #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "func_tab.h" #include "winX.h" static Widget extended_command_popup = 0; static Widget extended_command_form; static Widget *extended_commands = 0; static int extended_command_selected; /* index of the selected command; */ static int ps_selected; /* index of selected role */ #define PS_RANDOM (-50) #define PS_QUIT (-75) static const char ps_randchars[] = "*@"; static const char ps_quitchars[] = "\033qQ"; #define EC_NCHARS 32 static boolean ec_active = FALSE; static int ec_nchars = 0; static char ec_chars[EC_NCHARS]; static Time ec_time; static const char extended_command_translations[] = "#override\n\ : ec_key()"; static const char player_select_translations[] = "#override\n\ : ps_key()"; static const char race_select_translations[] = "#override\n\ : race_key()"; static const char gend_select_translations[] = "#override\n\ : gend_key()"; static const char algn_select_translations[] = "#override\n\ : algn_key()"; static void FDECL(popup_delete, (Widget, XEvent *, String *, Cardinal *)); static void NDECL(ec_dismiss); static Widget FDECL(make_menu, (const char *, const char *, const char *, const char *, XtCallbackProc, const char *, XtCallbackProc, int, const char **, Widget **, XtCallbackProc, Widget *)); static void NDECL(init_extended_commands_popup); static void FDECL(ps_quit, (Widget, XtPointer, XtPointer)); static void FDECL(ps_random, (Widget, XtPointer, XtPointer)); static void FDECL(ps_select, (Widget, XtPointer, XtPointer)); /* Player Selection -------------------------------------------------------- */ /* ARGSUSED */ static void ps_quit(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(client_data); nhUse(call_data); ps_selected = PS_QUIT; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ static void ps_random(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(client_data); nhUse(call_data); ps_selected = PS_RANDOM; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ static void ps_select(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(call_data); ps_selected = (int) client_data; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ void ps_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; char rolechars[QBUFSZ]; int i; nhUse(w); nhUse(params); nhUse(num_params); (void) memset(rolechars, '\0', sizeof rolechars); /* for index() */ for (i = 0; roles[i].name.m; ++i) { ch = lowc(*roles[i].name.m); /* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f); */ /* this supports at most two roles with the same first letter */ if (index(rolechars, ch)) ch = highc(ch); rolechars[i] = ch; } ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(rolechars, ch); if (!mark) mark = index(rolechars, lowc(ch)); if (!mark) mark = index(rolechars, highc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such class */ return; } } else ps_selected = (int) (mark - rolechars); exit_x_event = TRUE; } /* ARGSUSED */ void race_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; char racechars[QBUFSZ]; int i; nhUse(w); nhUse(params); nhUse(num_params); (void) memset(racechars, '\0', sizeof racechars); /* for index() */ for (i = 0; races[i].noun; ++i) { ch = lowc(*races[i].noun); /* this supports at most two races with the same first letter */ if (index(racechars, ch)) ch = highc(ch); racechars[i] = ch; } ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(racechars, ch); if (!mark) mark = index(racechars, lowc(ch)); if (!mark) mark = index(racechars, highc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such race */ return; } } else ps_selected = (int) (mark - racechars); exit_x_event = TRUE; } /* ARGSUSED */ void gend_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; static char gendchars[] = "mf"; nhUse(w); nhUse(params); nhUse(num_params); ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(gendchars, ch); if (!mark) mark = index(gendchars, lowc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such gender */ return; } } else ps_selected = (int) (mark - gendchars); exit_x_event = TRUE; } /* ARGSUSED */ void algn_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; static char algnchars[] = "LNC"; nhUse(w); nhUse(params); nhUse(num_params); ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(algnchars, ch); if (!mark) mark = index(algnchars, highc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such alignment */ return; } } else ps_selected = (int) (mark - algnchars); exit_x_event = TRUE; } /* Global functions ========================================================= */ void X11_player_selection() { int num_roles, num_races, num_gends, num_algns, i, availcount, availindex; Widget popup, player_form; const char **choices; char qbuf[QBUFSZ], plbuf[QBUFSZ]; /* avoid unnecessary prompts further down */ rigid_role_checks(); (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (flags.initrole < 0) { if (flags.initrole == ROLE_RANDOM || flags.randomall) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); break; } /* select a role */ for (num_roles = 0; roles[num_roles].name.m; ++num_roles) continue; choices = (const char **) alloc(sizeof(char *) * num_roles); for (;;) { availcount = 0; for (i = 0; i < num_roles; i++) { choices[i] = 0; if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { choices[i] = roles[i].name.m; if (flags.initgend >= 0 && flags.female && roles[i].name.f) choices[i] = roles[i].name.f; ++availcount; } } if (availcount > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else if (flags.initgend >= 0) flags.initgend = -1; else if (flags.initrace >= 0) flags.initrace = -1; else panic("no available ROLE+race+gender+alignment combinations"); } Sprintf(qbuf, "Choose your %s Role", s_suffix(plbuf)); popup = make_menu("player_selection", qbuf, player_select_translations, "quit", ps_quit, "random", ps_random, num_roles, choices, (Widget **) 0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int) XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; if (ps_selected == PS_QUIT || program_state.done_hup) { clearlocks(); X11_exit_nhwindows((char *) 0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initrole = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_roles) { panic("player_selection: bad role select value %d", ps_selected); } else { flags.initrole = ps_selected; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (!validrace(flags.initrole, flags.initrace)) { if (flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); break; } /* select a race */ for (num_races = 0; races[num_races].noun; ++num_races) continue; choices = (const char **) alloc(sizeof(char *) * num_races); for (;;) { availcount = availindex = 0; for (i = 0; i < num_races; i++) { choices[i] = 0; if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { choices[i] = races[i].noun; ++availcount; availindex = i; /* used iff only one */ } } if (availcount > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else if (flags.initgend >= 0) flags.initgend = -1; else panic("no available role+RACE+gender+alignment combinations"); } if (availcount == 1) { flags.initrace = availindex; free((genericptr_t) choices), choices = 0; } else { Sprintf(qbuf, "Pick your %s race", s_suffix(plbuf)); popup = make_menu("race_selection", qbuf, race_select_translations, "quit", ps_quit, "random", ps_random, num_races, choices, (Widget **) 0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int) XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; if (ps_selected == PS_QUIT || program_state.done_hup) { clearlocks(); X11_exit_nhwindows((char *) 0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initrace = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_races) { panic("player_selection: bad race select value %d", ps_selected); } else { flags.initrace = ps_selected; } } /* more than one race choice available */ } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (!validgend(flags.initrole, flags.initrace, flags.initgend)) { if (flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); break; } /* select a gender */ num_gends = 2; /* genders[2] isn't allowed */ choices = (const char **) alloc(sizeof(char *) * num_gends); for (;;) { availcount = availindex = 0; for (i = 0; i < num_gends; i++) { choices[i] = 0; if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { choices[i] = genders[i].adj; ++availcount; availindex = i; /* used iff only one */ } } if (availcount > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else panic("no available role+race+GENDER+alignment combinations"); } if (availcount == 1) { flags.initgend = availindex; free((genericptr_t) choices), choices = 0; } else { Sprintf(qbuf, "Your %s gender?", s_suffix(plbuf)); popup = make_menu("gender_selection", qbuf, gend_select_translations, "quit", ps_quit, "random", ps_random, num_gends, choices, (Widget **) 0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int) XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; if (ps_selected == PS_QUIT || program_state.done_hup) { clearlocks(); X11_exit_nhwindows((char *) 0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initgend = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_gends) { panic("player_selection: bad gender select value %d", ps_selected); } else { flags.initgend = ps_selected; } } /* more than one gender choice available */ } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (!validalign(flags.initrole, flags.initrace, flags.initalign)) { if (flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); break; } /* select an alignment */ num_algns = 3; /* aligns[3] isn't allowed */ choices = (const char **) alloc(sizeof(char *) * num_algns); for (;;) { availcount = availindex = 0; for (i = 0; i < num_algns; i++) { choices[i] = 0; if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { choices[i] = aligns[i].adj; ++availcount; availindex = i; /* used iff only one */ } } if (availcount > 0) break; else panic("no available role+race+gender+ALIGNMENT combinations"); } if (availcount == 1) { flags.initalign = availindex; free((genericptr_t) choices), choices = 0; } else { Sprintf(qbuf, "Your %s alignment?", s_suffix(plbuf)); popup = make_menu("alignment_selection", qbuf, algn_select_translations, "quit", ps_quit, "random", ps_random, num_algns, choices, (Widget **) 0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int) XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t) choices), choices = 0; if (ps_selected == PS_QUIT || program_state.done_hup) { clearlocks(); X11_exit_nhwindows((char *) 0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initalign = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_algns) { panic("player_selection: bad alignment select value %d", ps_selected); } else { flags.initalign = ps_selected; } } /* more than one alignment choice available */ } } int X11_get_ext_cmd() { static Boolean initialized = False; if (!initialized) { init_extended_commands_popup(); initialized = True; } extended_command_selected = -1; /* reset selected value */ positionpopup(extended_command_popup, FALSE); /* center on cursor */ nh_XtPopup(extended_command_popup, (int) XtGrabExclusive, extended_command_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); return extended_command_selected; } /* End global functions ===================================================== */ /* Extended Command -------------------------------------------------------- */ /* ARGSUSED */ static void extend_select(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { int selected = (int) client_data; nhUse(w); nhUse(call_data); if (extended_command_selected != selected) { /* visibly deselect old one */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); /* select new one */ swap_fg_bg(extended_commands[selected]); extended_command_selected = selected; } nh_XtPopdown(extended_command_popup); /* reset colors while popped down */ swap_fg_bg(extended_commands[extended_command_selected]); ec_active = FALSE; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ static void extend_dismiss(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(client_data); nhUse(call_data); ec_dismiss(); } /* ARGSUSED */ static void extend_help(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { nhUse(w); nhUse(client_data); nhUse(call_data); /* We might need to make it known that we already have one listed. */ (void) doextlist(); } /* ARGSUSED */ void ec_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { if (w == extended_command_popup) { ec_dismiss(); } else { popup_delete(w, event, params, num_params); } } /* ARGSUSED */ static void popup_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nhUse(event); nhUse(params); nhUse(num_params); ps_selected = PS_QUIT; nh_XtPopdown(w); exit_x_event = TRUE; /* leave event loop */ } static void ec_dismiss() { /* unselect while still visible */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); extended_command_selected = -1; /* dismiss */ nh_XtPopdown(extended_command_popup); ec_active = FALSE; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ void ec_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch; int i; XKeyEvent *xkey = (XKeyEvent *) event; nhUse(w); nhUse(params); nhUse(num_params); ch = key_event_to_char(xkey); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } else if (index("\033\n\r", ch)) { if (ch == '\033') { /* unselect while still visible */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); extended_command_selected = -1; /* dismiss */ } nh_XtPopdown(extended_command_popup); /* unselect while invisible */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); exit_x_event = TRUE; /* leave event loop */ ec_active = FALSE; return; } /* too much time has elapsed */ if ((xkey->time - ec_time) > 500) ec_active = FALSE; if (!ec_active) { ec_nchars = 0; ec_active = TRUE; } ec_time = xkey->time; ec_chars[ec_nchars++] = ch; if (ec_nchars >= EC_NCHARS) ec_nchars = EC_NCHARS - 1; /* don't overflow */ for (i = 0; extcmdlist[i].ef_txt; i++) { if (extcmdlist[i].ef_txt[0] == '?') continue; if (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)) { if (extended_command_selected != i) { /* I should use set() and unset() actions, but how do */ /* I send the an action to the widget? */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); extended_command_selected = i; swap_fg_bg(extended_commands[extended_command_selected]); } break; } } } /* * Use our own home-brewed version menu because simpleMenu is designed to * be used from a menubox. */ static void init_extended_commands_popup() { int i, num_commands; const char **command_list; /* count commands */ for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++) ; /* do nothing */ /* If the last entry is "help", don't use it. */ if (strcmp(extcmdlist[num_commands - 1].ef_txt, "?") == 0) --num_commands; command_list = (const char **) alloc((unsigned) num_commands * sizeof(char *)); for (i = 0; i < num_commands; i++) command_list[i] = extcmdlist[i].ef_txt; extended_command_popup = make_menu("extended_commands", "Extended Commands", extended_command_translations, "dismiss", extend_dismiss, "help", extend_help, num_commands, command_list, &extended_commands, extend_select, &extended_command_form); free((char *) command_list); } /* ------------------------------------------------------------------------- */ /* * Create a popup widget of the following form: * * popup_label * ----------- ------------ * |left_name| |right_name| * ----------- ------------ * ------------------------ * | name1 | * ------------------------ * ------------------------ * | name2 | * ------------------------ * . * . * ------------------------ * | nameN | * ------------------------ */ static Widget make_menu(popup_name, popup_label, popup_translations, left_name, left_callback, right_name, right_callback, num_names, widget_names, command_widgets, name_callback, formp) const char *popup_name; const char *popup_label; const char *popup_translations; const char *left_name; XtCallbackProc left_callback; const char *right_name; XtCallbackProc right_callback; int num_names; const char **widget_names; /* return array of command widgets */ Widget **command_widgets; XtCallbackProc name_callback; Widget *formp; /* return */ { Widget popup, form, label, above, left, right; Widget *commands, *curr; int i; Arg args[8]; Cardinal num_args; Dimension width, max_width; int distance, skip; commands = (Widget *) alloc((unsigned) num_names * sizeof(Widget)); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; popup = XtCreatePopupShell(popup_name, transientShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations( popup, XtParseTranslationTable("WM_PROTOCOLS: ec_delete()")); num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(popup_translations)); num_args++; *formp = form = XtCreateManagedWidget("menuform", formWidgetClass, popup, args, num_args); /* Get the default distance between objects in the form widget. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNdefaultDistance), &distance); num_args++; XtGetValues(form, args, num_args); /* * Create the label. */ num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; label = XtCreateManagedWidget(popup_label, labelWidgetClass, form, args, num_args); /* * Create the left button. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; /* XtSetArg(args[num_args], nhStr(XtNshapeStyle), XmuShapeRoundedRectangle); num_args++; */ left = XtCreateManagedWidget(left_name, commandWidgetClass, form, args, num_args); XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0); skip = 3 * distance; /* triple the spacing */ if (!skip) skip = 3; /* * Create right button. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; XtSetArg(args[num_args], nhStr(XtNfromVert), label); num_args++; /* XtSetArg(args[num_args], nhStr(XtNshapeStyle), XmuShapeRoundedRectangle); num_args++; */ right = XtCreateManagedWidget(right_name, commandWidgetClass, form, args, num_args); XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0); XtInstallAccelerators(form, left); XtInstallAccelerators(form, right); /* * Create and place the command widgets. */ for (i = 0, above = left, curr = commands; i < num_names; i++) { if (!widget_names[i]) continue; num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), above); num_args++; if (above == left) { /* if first, we are farther apart */ XtSetArg(args[num_args], nhStr(XtNvertDistance), skip); num_args++; } *curr = XtCreateManagedWidget(widget_names[i], commandWidgetClass, form, args, num_args); XtAddCallback(*curr, XtNcallback, name_callback, (XtPointer) i); above = *curr++; } /* * Now find the largest width. Start with the width dismiss + help * buttons, since they are adjacent. */ XtSetArg(args[0], XtNwidth, &max_width); XtGetValues(left, args, ONE); XtSetArg(args[0], XtNwidth, &width); XtGetValues(right, args, ONE); max_width = max_width + width + distance; /* Next, the title. */ XtSetArg(args[0], XtNwidth, &width); XtGetValues(label, args, ONE); if (width > max_width) max_width = width; /* Finally, the commands. */ for (i = 0, curr = commands; i < num_names; i++) { if (!widget_names[i]) continue; XtSetArg(args[0], XtNwidth, &width); XtGetValues(*curr, args, ONE); if (width > max_width) max_width = width; curr++; } /* * Finally, set all of the single line widgets to the largest width. */ XtSetArg(args[0], XtNwidth, max_width); XtSetValues(label, args, ONE); for (i = 0, curr = commands; i < num_names; i++) { if (!widget_names[i]) continue; XtSetArg(args[0], XtNwidth, max_width); XtSetValues(*curr, args, ONE); curr++; } if (command_widgets) *command_widgets = commands; else free((char *) commands); XtRealizeWidget(popup); XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1); return popup; } nethack-3.6.0/win/X11/winstat.c0000664000076400007660000007666712536476415015203 0ustar paxedpaxed/* NetHack 3.6 winstat.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Status window routines. This file supports both the "traditional" * tty status display and a "fancy" status display. A tty status is * made if a popup window is requested, otherewise a fancy status is * made. This code assumes that only one fancy status will ever be made. * Currently, only one status window (of any type) is _ever_ made. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "winX.h" extern const char *hu_stat[]; /* from eat.c */ extern const char *enc_stat[]; /* from botl.c */ static void FDECL(update_fancy_status, (struct xwindow *)); static Widget FDECL(create_fancy_status, (Widget, Widget)); static void FDECL(destroy_fancy_status, (struct xwindow *)); void create_status_window(wp, create_popup, parent) struct xwindow *wp; /* window pointer */ boolean create_popup; Widget parent; { XFontStruct *fs; Arg args[8]; Cardinal num_args; Position top_margin, bottom_margin, left_margin, right_margin; wp->type = NHW_STATUS; if (!create_popup) { /* * If we are not creating a popup, then we must be the "main" status * window. */ if (!parent) panic("create_status_window: no parent for fancy status"); wp->status_information = 0; wp->w = create_fancy_status(parent, (Widget) 0); return; } wp->status_information = (struct status_info_t *) alloc(sizeof(struct status_info_t)); init_text_buffer(&wp->status_information->text); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, False); num_args++; XtSetArg(args[num_args], XtNinput, False); num_args++; wp->popup = parent = XtCreatePopupShell( "status_popup", topLevelShellWidgetClass, toplevel, args, num_args); /* * If we're here, then this is an auxiliary status window. If we're * cancelled via a delete window message, we should just pop down. */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); num_args++; XtSetArg(args[num_args], nhStr(XtNscrollHorizontal), XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], nhStr(XtNscrollVertical), XawtextScrollWhenNeeded); num_args++; wp->w = XtCreateManagedWidget("status", /* name */ asciiTextWidgetClass, parent, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* * Adjust the height and width of the message window so that it * is two lines high and COLNO of the widest characters wide. */ /* Get the font and margin information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &fs); num_args++; XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin); num_args++; XtGetValues(wp->w, args, num_args); wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin; wp->pixel_width = COLNO * fs->max_bounds.width + left_margin + right_margin; /* Set the new width and height. */ num_args = 0; XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } void destroy_status_window(wp) struct xwindow *wp; { /* If status_information is defined, then it a "text" status window. */ if (wp->status_information) { if (wp->popup) { nh_XtPopdown(wp->popup); if (!wp->keep_window) XtDestroyWidget(wp->popup), wp->popup = (Widget) 0; } free((genericptr_t) wp->status_information); wp->status_information = 0; } else { destroy_fancy_status(wp); } if (!wp->keep_window) wp->type = NHW_NONE; } /* * This assumes several things: * + Status has only 2 lines * + That both lines are updated in succession in line order. * + We didn't set stringInPlace on the widget. */ void adjust_status(wp, str) struct xwindow *wp; const char *str; { Arg args[2]; Cardinal num_args; if (!wp->status_information) { update_fancy_status(wp); return; } if (wp->cursy == 0) { clear_text_buffer(&wp->status_information->text); append_text_buffer(&wp->status_information->text, str, FALSE); return; } append_text_buffer(&wp->status_information->text, str, FALSE); /* Set new buffer as text. */ num_args = 0; XtSetArg(args[num_args], XtNstring, wp->status_information->text.text); num_args++; XtSetValues(wp->w, args, num_args); } /* Fancy Status * -------------------------------------------------------------*/ static int hilight_time = 1; /* number of turns to hilight a changed value */ struct X_status_value { /* we have to cast away 'const' when assigning new names */ const char *name; /* text name */ int type; /* status type */ Widget w; /* widget of name/value pair */ long last_value; /* value displayed */ int turn_count; /* last time the value changed */ boolean set; /* if hilighed */ boolean after_init; /* don't hilight on first change (init) */ }; /* valid type values */ #define SV_VALUE 0 /* displays a label:value pair */ #define SV_LABEL 1 /* displays a changable label */ #define SV_NAME 2 /* displays an unchangeable name */ static void FDECL(hilight_label, (Widget)); static void FDECL(update_val, (struct X_status_value *, long)); static const char *FDECL(width_string, (int)); static void FDECL(create_widget, (Widget, struct X_status_value *, int)); static void FDECL(get_widths, (struct X_status_value *, int *, int *)); static void FDECL(set_widths, (struct X_status_value *, int, int)); static Widget FDECL(init_column, (const char *, Widget, Widget, Widget, int *)); static Widget FDECL(init_info_form, (Widget, Widget, Widget)); /* * Form entry storage indices. */ #define F_STR 0 #define F_DEX 1 #define F_CON 2 #define F_INT 3 #define F_WIS 4 #define F_CHA 5 #define F_NAME 6 #define F_DLEVEL 7 #define F_GOLD 8 #define F_HP 9 #define F_MAXHP 10 #define F_POWER 11 #define F_MAXPOWER 12 #define F_AC 13 #define F_LEVEL 14 #define F_EXP 15 #define F_ALIGN 16 #define F_TIME 17 #define F_SCORE 18 #define F_HUNGER 19 #define F_CONFUSED 20 #define F_SICK 21 #define F_BLIND 22 #define F_STUNNED 23 #define F_HALLU 24 #define F_ENCUMBER 25 #define NUM_STATS 26 /* * Notes: * + Alignment needs a different init value, because -1 is an alignment. * + Armor Class is an schar, so 256 is out of range. * + Blank value is 0 and should never change. */ static struct X_status_value shown_stats[NUM_STATS] = { { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/ { "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/ { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */ { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */ { "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/ { "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Armor Class", SV_VALUE, (Widget) 0, 256, 0, FALSE, FALSE }, { "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/ { "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE }, { "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/ { "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/ { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* sick */ { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*encumbr*/ }; /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all * kinds of funny values being displayed. */ void null_out_status() { int i; struct X_status_value *sv; Arg args[1]; for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) { switch (sv->type) { case SV_VALUE: set_value(sv->w, ""); break; case SV_LABEL: case SV_NAME: XtSetArg(args[0], XtNlabel, ""); XtSetValues(sv->w, args, ONE); break; default: impossible("null_out_status: unknown type %d\n", sv->type); break; } } } /* This is almost an exact duplicate of hilight_value() */ static void hilight_label(w) Widget w; /* label widget */ { Arg args[2]; Pixel fg, bg; XtSetArg(args[0], XtNforeground, &fg); XtSetArg(args[1], XtNbackground, &bg); XtGetValues(w, args, TWO); XtSetArg(args[0], XtNforeground, bg); XtSetArg(args[1], XtNbackground, fg); XtSetValues(w, args, TWO); } static void update_val(attr_rec, new_value) struct X_status_value *attr_rec; long new_value; { char buf[BUFSZ]; Arg args[4]; if (attr_rec->type == SV_LABEL) { if (attr_rec == &shown_stats[F_NAME]) { Strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A' - 'a'; Strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; Strcpy(mname, mons[u.umonnum].mname); while (mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k - 1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') mname[k] += 'A' - 'a'; k++; } Strcat(buf, mname); } else Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); } else if (attr_rec == &shown_stats[F_DLEVEL]) { if (!describe_level(buf)) { Strcpy(buf, dungeons[u.uz.dnum].dname); Sprintf(eos(buf), ", level %d", depth(&u.uz)); } } else { impossible("update_val: unknown label type \"%s\"", attr_rec->name); return; } if (strcmp(buf, attr_rec->name) == 0) return; /* same */ /* Set the label. 'name' field is const for most entries; we need to cast away that const for this assignment */ Strcpy((char *) attr_rec->name, buf); XtSetArg(args[0], XtNlabel, buf); XtSetValues(attr_rec->w, args, ONE); } else if (attr_rec->type == SV_NAME) { if (attr_rec->last_value == new_value) return; /* no change */ attr_rec->last_value = new_value; /* special cases: hunger, encumbrance, sickness */ if (attr_rec == &shown_stats[F_HUNGER]) { XtSetArg(args[0], XtNlabel, hu_stat[new_value]); } else if (attr_rec == &shown_stats[F_ENCUMBER]) { XtSetArg(args[0], XtNlabel, enc_stat[new_value]); } else if (attr_rec == &shown_stats[F_SICK]) { buf[0] = 0; if (Sick) { if (u.usick_type & SICK_VOMITABLE) Strcat(buf, "FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) { if (u.usick_type & SICK_VOMITABLE) Strcat(buf, " "); Strcat(buf, "Ill"); } } XtSetArg(args[0], XtNlabel, buf); } else if (new_value) { XtSetArg(args[0], XtNlabel, attr_rec->name); } else { XtSetArg(args[0], XtNlabel, ""); } XtSetValues(attr_rec->w, args, ONE); } else { /* a value pair */ boolean force_update = FALSE; /* special case: time can be enabled & disabled */ if (attr_rec == &shown_stats[F_TIME]) { static boolean flagtime = TRUE; if (flags.time && !flagtime) { set_name(attr_rec->w, shown_stats[F_TIME].name); force_update = TRUE; flagtime = flags.time; } else if (!flags.time && flagtime) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagtime = flags.time; } if (!flagtime) return; } /* special case: exp can be enabled & disabled */ else if (attr_rec == &shown_stats[F_EXP]) { static boolean flagexp = TRUE; if (flags.showexp && !flagexp) { set_name(attr_rec->w, shown_stats[F_EXP].name); force_update = TRUE; flagexp = flags.showexp; } else if (!flags.showexp && flagexp) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagexp = flags.showexp; } if (!flagexp) return; } /* special case: score can be enabled & disabled */ else if (attr_rec == &shown_stats[F_SCORE]) { static boolean flagscore = TRUE; #ifdef SCORE_ON_BOTL if (flags.showscore && !flagscore) { set_name(attr_rec->w, shown_stats[F_SCORE].name); force_update = TRUE; flagscore = flags.showscore; } else if (!flags.showscore && flagscore) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagscore = flags.showscore; } if (!flagscore) return; #else if (flagscore) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagscore = FALSE; } return; #endif } /* special case: when polymorphed, show "HD", disable exp */ else if (attr_rec == &shown_stats[F_LEVEL]) { static boolean lev_was_poly = FALSE; if (u.mtimedone && !lev_was_poly) { force_update = TRUE; set_name(attr_rec->w, "HD"); lev_was_poly = TRUE; } else if (!u.mtimedone && lev_was_poly) { force_update = TRUE; set_name(attr_rec->w, shown_stats[F_LEVEL].name); lev_was_poly = FALSE; } } else if (attr_rec == &shown_stats[F_EXP]) { static boolean exp_was_poly = FALSE; if (u.mtimedone && !exp_was_poly) { force_update = TRUE; set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); exp_was_poly = TRUE; } else if (!u.mtimedone && exp_was_poly) { force_update = TRUE; set_name(attr_rec->w, shown_stats[F_EXP].name); exp_was_poly = FALSE; } if (u.mtimedone) return; /* no display for exp when poly */ } if (attr_rec->last_value == new_value && !force_update) /* same */ return; attr_rec->last_value = new_value; /* Special cases: strength, alignment and "clear". */ if (attr_rec == &shown_stats[F_STR]) { if (new_value > 18) { if (new_value > 118) Sprintf(buf, "%ld", new_value - 100); else if (new_value < 118) Sprintf(buf, "18/%02ld", new_value - 18); else Strcpy(buf, "18/**"); } else { Sprintf(buf, "%ld", new_value); } } else if (attr_rec == &shown_stats[F_ALIGN]) { Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful"); } else { Sprintf(buf, "%ld", new_value); } set_value(attr_rec->w, buf); } /* * Now hilight the changed information. Names, time and score don't * hilight. If first time, don't hilight. If already lit, don't do * it again. */ if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) { if (attr_rec->after_init) { if (!attr_rec->set) { if (attr_rec->type == SV_LABEL) hilight_label(attr_rec->w); else hilight_value(attr_rec->w); attr_rec->set = TRUE; } attr_rec->turn_count = 0; } else { attr_rec->after_init = TRUE; } } } /* * Update the displayed status. The current code in botl.c updates * two lines of information. Both lines are always updated one after * the other. So only do our update when we update the second line. * * Information on the first line: * name, attributes, alignment, score * * Information on the second line: * dlvl, gold, hp, power, ac, {level & exp or HD **} * status (hunger, conf, halu, stun, sick, blind), time, encumbrance * * [**] HD is shown instead of level and exp if mtimedone is non-zero. */ static void update_fancy_status(wp) struct xwindow *wp; { struct X_status_value *sv; long val; int i; if (wp->cursy != 0) return; /* do a complete update when line 0 is done */ for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) { switch (i) { case F_STR: val = (long) ACURR(A_STR); break; case F_DEX: val = (long) ACURR(A_DEX); break; case F_CON: val = (long) ACURR(A_CON); break; case F_INT: val = (long) ACURR(A_INT); break; case F_WIS: val = (long) ACURR(A_WIS); break; case F_CHA: val = (long) ACURR(A_CHA); break; /* * Label stats. With the exceptions of hunger, encumbrance, sick * these are either on or off. Pleae leave the ternary operators * the way they are. I want to specify 0 or 1, not a boolean. */ case F_HUNGER: val = (long) u.uhs; break; case F_CONFUSED: val = (long) Confusion ? 1L : 0L; break; case F_SICK: val = (long) Sick ? (long) u.usick_type : 0L; break; case F_BLIND: val = (long) Blind ? 1L : 0L; break; case F_STUNNED: val = (long) Stunned ? 1L : 0L; break; case F_HALLU: val = (long) Hallucination ? 1L : 0L; break; case F_ENCUMBER: val = (long) near_capacity(); break; case F_NAME: val = (long) 0L; break; /* special */ case F_DLEVEL: val = (long) 0L; break; /* special */ case F_GOLD: val = money_cnt(invent); break; case F_HP: val = (long) (u.mtimedone ? (u.mh > 0 ? u.mh : 0) : (u.uhp > 0 ? u.uhp : 0)); break; case F_MAXHP: val = (long) (u.mtimedone ? u.mhmax : u.uhpmax); break; case F_POWER: val = (long) u.uen; break; case F_MAXPOWER: val = (long) u.uenmax; break; case F_AC: val = (long) u.uac; break; case F_LEVEL: val = (long) (u.mtimedone ? mons[u.umonnum].mlevel : u.ulevel); break; case F_EXP: val = flags.showexp ? u.uexp : 0L; break; case F_ALIGN: val = (long) u.ualign.type; break; case F_TIME: val = flags.time ? (long) moves : 0L; break; #ifdef SCORE_ON_BOTL case F_SCORE: val = flags.showscore ? botl_score() : 0L; break; #else case F_SCORE: val = 0L; break; #endif default: { /* * There is a possible infinite loop that occurs with: * * impossible->pline->flush_screen->bot->bot{1,2}-> * putstr->adjust_status->update_other->impossible * * Break out with this. */ static boolean active = FALSE; if (!active) { active = TRUE; impossible("update_other: unknown shown value"); active = FALSE; } val = 0; break; } } update_val(sv, val); } } /* * Turn off hilighted status values after a certain amount of turns. */ void check_turn_events() { int i; struct X_status_value *sv; for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) { if (!sv->set) continue; if (sv->turn_count++ >= hilight_time) { if (sv->type == SV_LABEL) hilight_label(sv->w); else hilight_value(sv->w); sv->set = FALSE; } } } /* Initialize alternate status ============================================= */ /* Return a string for the initial width. */ static const char * width_string(sv_index) int sv_index; { switch (sv_index) { case F_STR: return "018/**"; case F_DEX: case F_CON: case F_INT: case F_WIS: case F_CHA: return "088"; /* all but str never get bigger */ case F_HUNGER: return shown_stats[F_HUNGER].name; case F_CONFUSED: return shown_stats[F_CONFUSED].name; case F_SICK: return shown_stats[F_SICK].name; case F_BLIND: return shown_stats[F_BLIND].name; case F_STUNNED: return shown_stats[F_STUNNED].name; case F_HALLU: return shown_stats[F_HALLU].name; case F_ENCUMBER: return shown_stats[F_ENCUMBER].name; case F_NAME: case F_DLEVEL: return ""; case F_HP: case F_MAXHP: return "9999"; case F_POWER: case F_MAXPOWER: return "999"; case F_AC: return "-99"; case F_LEVEL: return "99"; case F_GOLD: case F_EXP: return "4294967295"; /* max ulong */ case F_ALIGN: return "Neutral"; case F_TIME: return "4294967295"; /* max ulong */ case F_SCORE: return "4294967295"; /* max ulong */ } impossible("width_string: unknown index %d\n", sv_index); return ""; } static void create_widget(parent, sv, sv_index) Widget parent; struct X_status_value *sv; int sv_index; { Arg args[4]; Cardinal num_args; switch (sv->type) { case SV_VALUE: sv->w = create_value(parent, sv->name); set_value(sv->w, width_string(sv_index)); break; case SV_LABEL: /* Labels get their own buffer. */ sv->name = (char *) alloc(BUFSZ); /* we need to cast away 'const' when assigning a value */ *(char *) (sv->name) = '\0'; num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; sv->w = XtCreateManagedWidget(sv_index == F_NAME ? "name" : "dlevel", labelWidgetClass, parent, args, num_args); break; case SV_NAME: num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent, args, num_args); break; default: panic("create_widget: unknown type %d", sv->type); } } /* * Get current width of value. width2p is only valid for SV_LABEL types. */ static void get_widths(sv, width1p, width2p) struct X_status_value *sv; int *width1p, *width2p; { Arg args[1]; Dimension width; switch (sv->type) { case SV_VALUE: *width1p = get_name_width(sv->w); *width2p = get_value_width(sv->w); break; case SV_LABEL: case SV_NAME: XtSetArg(args[0], XtNwidth, &width); XtGetValues(sv->w, args, ONE); *width1p = width; *width2p = 0; break; default: panic("get_widths: unknown type %d", sv->type); } } static void set_widths(sv, width1, width2) struct X_status_value *sv; int width1, width2; { Arg args[1]; switch (sv->type) { case SV_VALUE: set_name_width(sv->w, width1); set_value_width(sv->w, width2); break; case SV_LABEL: case SV_NAME: XtSetArg(args[0], XtNwidth, (width1 + width2)); XtSetValues(sv->w, args, ONE); break; default: panic("set_widths: unknown type %d", sv->type); } } static Widget init_column(name, parent, top, left, col_indices) const char *name; Widget parent, top, left; int *col_indices; { Widget form; Arg args[4]; Cardinal num_args; int max_width1, width1, max_width2, width2; int *ip; struct X_status_value *sv; num_args = 0; if (top != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } if (left != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args); max_width1 = max_width2 = 0; for (ip = col_indices; *ip >= 0; ip++) { sv = &shown_stats[*ip]; create_widget(form, sv, *ip); /* will set init width */ if (ip != col_indices) { /* not first */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), shown_stats[*(ip - 1)].w); num_args++; XtSetValues(sv->w, args, num_args); } get_widths(sv, &width1, &width2); if (width1 > max_width1) max_width1 = width1; if (width2 > max_width2) max_width2 = width2; } for (ip = col_indices; *ip >= 0; ip++) { set_widths(&shown_stats[*ip], max_width1, max_width2); } /* There is room behind the end marker for the two widths. */ *++ip = max_width1; *++ip = max_width2; return form; } /* * These are the orders of the displayed columns. Change to suit. The -1 * indicates the end of the column. The two numbers after that are used * to store widths that are calculated at run-time. */ static int attrib_indices[] = { F_STR, F_DEX, F_CON, F_INT, F_WIS, F_CHA, -1, 0, 0 }; static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND, F_STUNNED, F_HALLU, F_ENCUMBER, -1, 0, 0 }; static int col2_indices[] = { F_MAXHP, F_ALIGN, F_TIME, F_EXP, F_MAXPOWER, -1, 0, 0 }; static int col1_indices[] = { F_HP, F_AC, F_GOLD, F_LEVEL, F_POWER, F_SCORE, -1, 0, 0 }; /* * Produce a form that looks like the following: * * name * dlevel * col1_indices[0] col2_indices[0] * col1_indices[1] col2_indices[1] * . . * . . * col1_indices[n] col2_indices[n] */ static Widget init_info_form(parent, top, left) Widget parent, top, left; { Widget form, col1; struct X_status_value *sv_name, *sv_dlevel; Arg args[6]; Cardinal num_args; int total_width, *ip; num_args = 0; if (top != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } if (left != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromHoriz), left); num_args++; } XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; form = XtCreateManagedWidget("status_info", formWidgetClass, parent, args, num_args); /* top of form */ sv_name = &shown_stats[F_NAME]; create_widget(form, sv_name, F_NAME); /* second */ sv_dlevel = &shown_stats[F_DLEVEL]; create_widget(form, sv_dlevel, F_DLEVEL); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), sv_name->w); num_args++; XtSetValues(sv_dlevel->w, args, num_args); /* two columns beneath */ col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0, col1_indices); (void) init_column("name_col2", form, sv_dlevel->w, col1, col2_indices); /* Add calculated widths. */ for (ip = col1_indices; *ip >= 0; ip++) ; /* skip to end */ total_width = *++ip; total_width += *++ip; for (ip = col2_indices; *ip >= 0; ip++) ; /* skip to end */ total_width += *++ip; total_width += *++ip; XtSetArg(args[0], XtNwidth, total_width); XtSetValues(sv_name->w, args, ONE); XtSetArg(args[0], XtNwidth, total_width); XtSetValues(sv_dlevel->w, args, ONE); return form; } /* * Create the layout for the fancy status. Return a form widget that * contains everything. */ static Widget create_fancy_status(parent, top) Widget parent, top; { Widget form; /* The form that surrounds everything. */ Widget w; Arg args[8]; Cardinal num_args; num_args = 0; if (top != (Widget) 0) { XtSetArg(args[num_args], nhStr(XtNfromVert), top); num_args++; } XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++; form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent, args, num_args); w = init_info_form(form, (Widget) 0, (Widget) 0); w = init_column("status_attributes", form, (Widget) 0, w, attrib_indices); (void) init_column("status_condition", form, (Widget) 0, w, status_indices); return form; } static void destroy_fancy_status(wp) struct xwindow *wp; { int i; struct X_status_value *sv; if (!wp->keep_window) XtDestroyWidget(wp->w), wp->w = (Widget) 0; for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) if (sv->type == SV_LABEL) { free((genericptr_t) sv->name); sv->name = 0; } } /*winstat.c*/ nethack-3.6.0/win/X11/wintext.c0000664000076400007660000004202212536476415015166 0ustar paxedpaxed/* NetHack 3.6 wintext.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * File for dealing with text windows. * * + No global functions. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "winX.h" #include "xwindow.h" #ifdef GRAPHIC_TOMBSTONE #include #endif #define TRANSIENT_TEXT /* text window is a transient window (no positioning) \ */ static const char text_translations[] = "#override\n\ : dismiss_text()\n\ : key_dismiss_text()"; #ifdef GRAPHIC_TOMBSTONE static const char rip_translations[] = "#override\n\ : rip_dismiss_text()\n\ : rip_dismiss_text()"; static Widget FDECL(create_ripout_widget, (Widget)); #endif /*ARGSUSED*/ void delete_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { struct xwindow *wp; struct text_info_t *text_info; nhUse(event); nhUse(params); nhUse(num_params); wp = find_widget(w); text_info = wp->text_information; nh_XtPopdown(wp->popup); if (text_info->blocked) { exit_x_event = TRUE; } else if (text_info->destroy_on_ack) { destroy_text_window(wp); } } /* * Callback used for all text windows. The window is poped down on any key * or button down event. It is destroyed if the main nethack code is done * with it. */ /*ARGSUSED*/ void dismiss_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { struct xwindow *wp; struct text_info_t *text_info; nhUse(event); nhUse(params); nhUse(num_params); wp = find_widget(w); text_info = wp->text_information; nh_XtPopdown(wp->popup); if (text_info->blocked) { exit_x_event = TRUE; } else if (text_info->destroy_on_ack) { destroy_text_window(wp); } } /* Dismiss when a non-modifier key pressed. */ void key_dismiss_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch = key_event_to_char((XKeyEvent *) event); if (ch) dismiss_text(w, event, params, num_params); } #ifdef GRAPHIC_TOMBSTONE /* Dismiss from clicking on rip image. */ void rip_dismiss_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { dismiss_text(XtParent(w), event, params, num_params); } #endif /* ARGSUSED */ void add_to_text_window(wp, attr, str) struct xwindow *wp; int attr; /* currently unused */ const char *str; { struct text_info_t *text_info = wp->text_information; int width; nhUse(attr); append_text_buffer(&text_info->text, str, FALSE); /* Calculate text width and save longest line */ width = XTextWidth(text_info->fs, str, (int) strlen(str)); if (width > text_info->max_width) text_info->max_width = width; } void display_text_window(wp, blocking) struct xwindow *wp; boolean blocking; { struct text_info_t *text_info; Arg args[8]; Cardinal num_args; Dimension width, height, font_height; int nlines; text_info = wp->text_information; width = text_info->max_width + text_info->extra_width; text_info->blocked = blocking; text_info->destroy_on_ack = FALSE; font_height = nhFontHeight(wp->w); /* * Calculate the number of lines to use. First, find the number of * lines that would fit on the screen. Next, remove four of these * lines to give room for a possible window manager titlebar (some * wm's put a titlebar on transient windows). Make sure we have * _some_ lines. Finally, use the number of lines in the text if * there are fewer than the max. */ nlines = (XtScreen(wp->w)->height - text_info->extra_height) / font_height; nlines -= 4; if (nlines > text_info->text.num_lines) nlines = text_info->text.num_lines; if (nlines <= 0) nlines = 1; height = nlines * font_height + text_info->extra_height; num_args = 0; if (nlines < text_info->text.num_lines) { /* add on width of scrollbar. Really should look this up, * but can't until the window is realized. Chicken-and-egg problem. */ width += 20; } #ifdef GRAPHIC_TOMBSTONE if (text_info->is_rip) { Widget rip = create_ripout_widget(XtParent(wp->w)); XtSetArg(args[num_args], XtNfromVert, rip); num_args++; } #endif if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */ /* Back off some amount - we really need to back off the scrollbar */ /* width plus some extra. */ width = XtScreen(wp->w)->width - 20; } XtSetArg(args[num_args], XtNstring, text_info->text.text); num_args++; XtSetArg(args[num_args], XtNwidth, width); num_args++; XtSetArg(args[num_args], XtNheight, height); num_args++; XtSetValues(wp->w, args, num_args); #ifdef TRANSIENT_TEXT XtRealizeWidget(wp->popup); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); positionpopup(wp->popup, FALSE); #endif nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w); /* Kludge alert. Scrollbars are not sized correctly by the Text widget */ /* if added before the window is displayed, so do it afterward. */ num_args = 0; if (nlines < text_info->text.num_lines) { /* add vert scrollbar */ XtSetArg(args[num_args], nhStr(XtNscrollVertical), XawtextScrollAlways); num_args++; } if (width >= (Dimension)(XtScreen(wp->w)->width - 20)) { /* too wide */ XtSetArg(args[num_args], nhStr(XtNscrollHorizontal), XawtextScrollAlways); num_args++; } if (num_args) XtSetValues(wp->w, args, num_args); /* We want the user to acknowlege. */ if (blocking) { (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(wp->popup); } } void create_text_window(wp) struct xwindow *wp; { struct text_info_t *text_info; Arg args[8]; Cardinal num_args; Position top_margin, bottom_margin, left_margin, right_margin; Widget form; wp->type = NHW_TEXT; wp->text_information = text_info = (struct text_info_t *) alloc(sizeof(struct text_info_t)); init_text_buffer(&text_info->text); text_info->max_width = 0; text_info->extra_width = 0; text_info->extra_height = 0; text_info->blocked = FALSE; text_info->destroy_on_ack = TRUE; /* Ok to destroy before display */ #ifdef GRAPHIC_TOMBSTONE text_info->is_rip = FALSE; #endif num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(text_translations)); num_args++; #ifdef TRANSIENT_TEXT wp->popup = XtCreatePopupShell("text", transientShellWidgetClass, toplevel, args, num_args); #else wp->popup = XtCreatePopupShell("text", topLevelShellWidgetClass, toplevel, args, num_args); #endif XtOverrideTranslations( wp->popup, XtParseTranslationTable("WM_PROTOCOLS: delete_text()")); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; form = XtCreateManagedWidget("form", formWidgetClass, wp->popup, args, num_args); num_args = 0; XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False); num_args++; XtSetArg(args[num_args], XtNresize, XawtextResizeBoth); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(text_translations)); num_args++; wp->w = XtCreateManagedWidget(killer.name[0] && WIN_MAP == WIN_ERR ? "tombstone" : "text_text", /* name */ asciiTextWidgetClass, form, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* Get the font and margin information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &text_info->fs); num_args++; XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin); num_args++; XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin); num_args++; XtGetValues(wp->w, args, num_args); text_info->extra_width = left_margin + right_margin; text_info->extra_height = top_margin + bottom_margin; } void destroy_text_window(wp) struct xwindow *wp; { /* Don't need to pop down, this only called from dismiss_text(). */ struct text_info_t *text_info = wp->text_information; /* * If the text window was blocked, then the user has already ACK'ed * it and we are free to really destroy the window. Otherwise, don't * destroy until the user dismisses the window via a key or button * press. */ if (text_info->blocked || text_info->destroy_on_ack) { XtDestroyWidget(wp->popup); free_text_buffer(&text_info->text); free((genericptr_t) text_info), wp->text_information = 0; wp->type = NHW_NONE; /* allow reuse */ } else { text_info->destroy_on_ack = TRUE; /* destroy on next ACK */ } } void clear_text_window(wp) struct xwindow *wp; { clear_text_buffer(&wp->text_information->text); } /* text buffer routines ---------------------------------------------------- */ /* Append a line to the text buffer. */ void append_text_buffer(tb, str, concat) struct text_buffer *tb; const char *str; boolean concat; { char *copy; int length; if (!tb->text) panic("append_text_buffer: null text buffer"); if (str) { length = strlen(str); } else { length = 0; } if (length + tb->text_last + 1 >= tb->text_size) { /* we need to go to a bigger buffer! */ #ifdef VERBOSE printf( "append_text_buffer: text buffer growing from %d to %d bytes\n", tb->text_size, 2 * tb->text_size); #endif copy = (char *) alloc((unsigned) tb->text_size * 2); (void) memcpy(copy, tb->text, tb->text_last); free(tb->text); tb->text = copy; tb->text_size *= 2; } if (tb->num_lines) { /* not first --- append a newline */ char appchar = '\n'; if (concat && !index("!.?'\")", tb->text[tb->text_last - 1])) { appchar = ' '; tb->num_lines--; /* offset increment at end of function */ } *(tb->text + tb->text_last) = appchar; tb->text_last++; } if (str) { (void) memcpy((tb->text + tb->text_last), str, length + 1); if (length) { /* Remove all newlines. Otherwise we have a confused line count. */ copy = (tb->text + tb->text_last); while ((copy = index(copy, '\n')) != (char *) 0) *copy = ' '; } tb->text_last += length; } tb->text[tb->text_last] = '\0'; tb->num_lines++; } /* Initialize text buffer. */ void init_text_buffer(tb) struct text_buffer *tb; { tb->text = (char *) alloc(START_SIZE); tb->text[0] = '\0'; tb->text_size = START_SIZE; tb->text_last = 0; tb->num_lines = 0; } /* Empty the text buffer */ void clear_text_buffer(tb) struct text_buffer *tb; { tb->text_last = 0; tb->text[0] = '\0'; tb->num_lines = 0; } /* Free up allocated memory. */ void free_text_buffer(tb) struct text_buffer *tb; { free(tb->text); tb->text = (char *) 0; tb->text_size = 0; tb->text_last = 0; tb->num_lines = 0; } #ifdef GRAPHIC_TOMBSTONE static void FDECL(rip_exposed, (Widget, XtPointer, XtPointer)); static XImage *rip_image = 0; #define STONE_LINE_LEN 16 /* # chars that fit on one line */ #define NAME_LINE 0 /* line # for player name */ #define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ #define YEAR_LINE 6 /* line # for year */ static char rip_line[YEAR_LINE + 1][STONE_LINE_LEN + 1]; void calculate_rip_text(int how, time_t when) { /* Follows same algorithm as genl_outrip() */ char buf[BUFSZ]; char *dpx; int line; long year; /* Put name on stone */ Sprintf(rip_line[NAME_LINE], "%s", plname); /* Put $ on stone */ Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money); /* Put together death description */ formatkiller(buf, sizeof buf, how); /* Put death type on stone */ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { register int i, i0; char tmpchar; if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if (dpx[i] == ' ') i0 = i; if (!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; strcpy(rip_line[line], dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx = &dpx[i0]; } else dpx = &dpx[i0 + 1]; } /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(rip_line[YEAR_LINE], "%4ld", year); } /* * RIP image expose callback. */ /*ARGSUSED*/ static void rip_exposed(w, client_data, widget_data) Widget w; XtPointer client_data; /* unused */ XtPointer widget_data; /* expose event from Window widget */ { XExposeEvent *event = (XExposeEvent *) widget_data; Display *dpy = XtDisplay(w); Arg args[8]; XGCValues values; XtGCMask mask; GC gc; static Pixmap rip_pixmap = None; int i, x, y; if (!XtIsRealized(w) || event->count > 0) return; if (rip_pixmap == None && rip_image) { rip_pixmap = XCreatePixmap(dpy, XtWindow(w), rip_image->width, rip_image->height, DefaultDepth(dpy, DefaultScreen(dpy))); XPutImage(dpy, rip_pixmap, DefaultGC(dpy, DefaultScreen(dpy)), rip_image, 0, 0, 0, 0, /* src, dest top left */ rip_image->width, rip_image->height); XDestroyImage(rip_image); /* data bytes free'd also */ } mask = GCFunction | GCForeground | GCGraphicsExposures | GCFont; values.graphics_exposures = False; XtSetArg(args[0], XtNforeground, &values.foreground); XtGetValues(w, args, 1); values.function = GXcopy; values.font = WindowFont(w); gc = XtGetGC(w, mask, &values); if (rip_pixmap != None) { XCopyArea(dpy, rip_pixmap, XtWindow(w), gc, event->x, event->y, event->width, event->height, event->x, event->y); } x = appResources.tombtext_x; y = appResources.tombtext_y; for (i = 0; i <= YEAR_LINE; i++) { int len = strlen(rip_line[i]); XFontStruct *font = WindowFontStruct(w); int width = XTextWidth(font, rip_line[i], len); XDrawString(dpy, XtWindow(w), gc, x - width / 2, y, rip_line[i], len); x += appResources.tombtext_dx; y += appResources.tombtext_dy; } XtReleaseGC(w, gc); } /* * The ripout window creation routine. */ static Widget create_ripout_widget(Widget parent) { Widget imageport; Arg args[16]; Cardinal num_args; static int rip_width, rip_height; if (!rip_image) { XpmAttributes attributes; int errorcode; attributes.valuemask = XpmCloseness; attributes.closeness = 65535; /* Try anything */ errorcode = XpmReadFileToImage(XtDisplay(parent), appResources.tombstone, &rip_image, 0, &attributes); if (errorcode != XpmSuccess) { char buf[BUFSZ]; Sprintf(buf, "Failed to load %s: %s", appResources.tombstone, XpmGetErrorString(errorcode)); X11_raw_print(buf); } rip_width = rip_image->width; rip_height = rip_image->height; } num_args = 0; XtSetArg(args[num_args], XtNwidth, rip_width); num_args++; XtSetArg(args[num_args], XtNheight, rip_height); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(rip_translations)); num_args++; imageport = XtCreateManagedWidget("rip", windowWidgetClass, parent, args, num_args); XtAddCallback(imageport, XtNexposeCallback, rip_exposed, (XtPointer) 0); return imageport; } #endif /* GRAPHIC_TOMBSTONE */ /*wintext.c*/ nethack-3.6.0/win/X11/winval.c0000664000076400007660000000754512536476415014777 0ustar paxedpaxed/* NetHack 3.6 winval.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Routines that define a name-value label widget pair that fit inside a * form widget. */ #include #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #ifdef PRESERVE_NO_SYSV #ifdef SYSV #undef SYSV #endif #undef PRESERVE_NO_SYSV #endif #include "hack.h" /* #define for const for non __STDC__ compilers */ #include "winX.h" #define WNAME "name" #define WVALUE "value" Widget create_value(parent, name_value) Widget parent; const char *name_value; { Widget form, name; Arg args[8]; Cardinal num_args; num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], nhStr(XtNdefaultDistance), 0); num_args++; form = XtCreateManagedWidget(name_value, formWidgetClass, parent, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNjustify, XtJustifyRight); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNlabel, name_value); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; name = XtCreateManagedWidget(WNAME, labelWidgetClass, form, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNjustify, XtJustifyRight); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), name); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; (void) XtCreateManagedWidget(WVALUE, labelWidgetClass, form, args, num_args); return form; } void set_name(w, new_label) Widget w; const char *new_label; { Arg args[1]; Widget name; name = XtNameToWidget(w, WNAME); XtSetArg(args[0], XtNlabel, new_label); XtSetValues(name, args, ONE); } void set_name_width(w, new_width) Widget w; int new_width; { Arg args[1]; Widget name; name = XtNameToWidget(w, WNAME); XtSetArg(args[0], XtNwidth, new_width); XtSetValues(name, args, ONE); } int get_name_width(w) Widget w; { Arg args[1]; Dimension width; Widget name; name = XtNameToWidget(w, WNAME); XtSetArg(args[0], XtNwidth, &width); XtGetValues(name, args, ONE); return (int) width; } void set_value(w, new_value) Widget w; const char *new_value; { Arg args[1]; Widget val; val = XtNameToWidget(w, WVALUE); XtSetArg(args[0], XtNlabel, new_value); XtSetValues(val, args, ONE); } void set_value_width(w, new_width) Widget w; int new_width; { Arg args[1]; Widget val; val = XtNameToWidget(w, WVALUE); XtSetArg(args[0], XtNwidth, new_width); XtSetValues(val, args, ONE); } int get_value_width(w) Widget w; { Arg args[1]; Widget val; Dimension width; val = XtNameToWidget(w, WVALUE); XtSetArg(args[0], XtNwidth, &width); XtGetValues(val, args, ONE); return (int) width; } /* Swap foreground and background colors (this is the best I can do with */ /* a label widget, unless I can get some init hook in there). */ void hilight_value(w) Widget w; { swap_fg_bg(XtNameToWidget(w, WVALUE)); } /* Swap the foreground and background colors of the given widget */ void swap_fg_bg(w) Widget w; { Arg args[2]; Pixel fg, bg; XtSetArg(args[0], XtNforeground, &fg); XtSetArg(args[1], XtNbackground, &bg); XtGetValues(w, args, TWO); XtSetArg(args[0], XtNforeground, bg); XtSetArg(args[1], XtNbackground, fg); XtSetValues(w, args, TWO); } nethack-3.6.0/win/chain/wc_chainin.c0000664000076400007660000002632212536476415016304 0ustar paxedpaxed/* NetHack 3.6 wc_chainin.c $NHDT-Date: 1433806610 2015/06/08 23:36:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ /* -chainin is an internal processor that changes the flow from window_procs * to chain_procs. */ #include "hack.h" struct chainin_data { struct chain_procs *nprocs; void *ndata; int linknum; }; /* Normally, a processor gets this information from the first parm of each * call, but here we are keeping the original API, so that parm doesn't exist, * so we use this instead. */ static struct chainin_data *cibase; void * chainin_procs_chain(cmd, n, me, nextprocs, nextdata) int cmd; int n; void *me; void *nextprocs; void *nextdata; { switch (cmd) { case WINCHAIN_ALLOC: { struct chainin_data *tdp = calloc(1, sizeof(struct chainin_data)); tdp->linknum = n; cibase = tdp; return tdp; } case WINCHAIN_INIT: { struct chainin_data *tdp = me; tdp->nprocs = nextprocs; tdp->ndata = nextdata; return tdp; } default: raw_printf("chainin_procs_chain: bad cmd\n"); exit(EXIT_FAILURE); } } /* XXX if we don't need this, take it out of the table */ void chainin_procs_init(dir) int dir UNUSED; { } /*** *** winprocs ***/ void chainin_init_nhwindows(argcp, argv) int *argcp; char **argv; { (*cibase->nprocs->win_init_nhwindows)(cibase->ndata, argcp, argv); } void chainin_player_selection() { (*cibase->nprocs->win_player_selection)(cibase->ndata); } void chainin_askname() { (*cibase->nprocs->win_askname)(cibase->ndata); } void chainin_get_nh_event() { (*cibase->nprocs->win_get_nh_event)(cibase->ndata); } void chainin_exit_nhwindows(str) const char *str; { (*cibase->nprocs->win_exit_nhwindows)(cibase->ndata, str); } void chainin_suspend_nhwindows(str) const char *str; { (*cibase->nprocs->win_suspend_nhwindows)(cibase->ndata, str); } void chainin_resume_nhwindows() { (*cibase->nprocs->win_resume_nhwindows)(cibase->ndata); } winid chainin_create_nhwindow(type) int type; { winid rv; rv = (*cibase->nprocs->win_create_nhwindow)(cibase->ndata, type); return rv; } void chainin_clear_nhwindow(window) winid window; { (*cibase->nprocs->win_clear_nhwindow)(cibase->ndata, window); } void chainin_display_nhwindow(window, blocking) winid window; BOOLEAN_P blocking; { (*cibase->nprocs->win_display_nhwindow)(cibase->ndata, window, blocking); } void chainin_destroy_nhwindow(window) winid window; { (*cibase->nprocs->win_destroy_nhwindow)(cibase->ndata, window); } void chainin_curs(window, x, y) winid window; int x; int y; { (*cibase->nprocs->win_curs)(cibase->ndata, window, x, y); } void chainin_putstr(window, attr, str) winid window; int attr; const char *str; { (*cibase->nprocs->win_putstr)(cibase->ndata, window, attr, str); } void chainin_putmixed(window, attr, str) winid window; int attr; const char *str; { (*cibase->nprocs->win_putmixed)(cibase->ndata, window, attr, str); } void chainin_display_file(fname, complain) const char *fname; boolean complain; { (*cibase->nprocs->win_display_file)(cibase->ndata, fname, complain); } void chainin_start_menu(window) winid window; { (*cibase->nprocs->win_start_menu)(cibase->ndata, window); } void chainin_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; /* window to use, must be of type NHW_MENU */ int glyph; /* glyph to display with item (unused) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like tty_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { (*cibase->nprocs->win_add_menu)(cibase->ndata, window, glyph, identifier, ch, gch, attr, str, preselected); } void chainin_end_menu(window, prompt) winid window; const char *prompt; { (*cibase->nprocs->win_end_menu)(cibase->ndata, window, prompt); } int chainin_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { int rv; rv = (*cibase->nprocs->win_select_menu)(cibase->ndata, window, how, (void *) menu_list); return rv; } char chainin_message_menu(let, how, mesg) char let; int how; const char *mesg; { char rv; rv = (*cibase->nprocs->win_message_menu)(cibase->ndata, let, how, mesg); return rv; } void chainin_update_inventory() { (*cibase->nprocs->win_update_inventory)(cibase->ndata); } void chainin_mark_synch() { (*cibase->nprocs->win_mark_synch)(cibase->ndata); } void chainin_wait_synch() { (*cibase->nprocs->win_wait_synch)(cibase->ndata); } #ifdef CLIPPING void chainin_cliparound(x, y) int x; int y; { (*cibase->nprocs->win_cliparound)(cibase->ndata, x, y); } #endif #ifdef POSITIONBAR void chainin_update_positionbar(posbar) char *posbar; { (*cibase->nprocs->win_update_positionbar)(cibase->ndata, posbar); } #endif /* XXX can we decode the glyph in a meaningful way? */ void chainin_print_glyph(window, x, y, glyph, bkglyph) winid window; xchar x, y; int glyph, bkglyph; { (*cibase->nprocs->win_print_glyph)(cibase->ndata, window, x, y, glyph, bkglyph); } void chainin_raw_print(str) const char *str; { (*cibase->nprocs->win_raw_print)(cibase->ndata, str); } void chainin_raw_print_bold(str) const char *str; { (*cibase->nprocs->win_raw_print_bold)(cibase->ndata, str); } int chainin_nhgetch() { int rv; rv = (*cibase->nprocs->win_nhgetch)(cibase->ndata); return rv; } int chainin_nh_poskey(x, y, mod) int *x; int *y; int *mod; { int rv; rv = (*cibase->nprocs->win_nh_poskey)(cibase->ndata, x, y, mod); return rv; } void chainin_nhbell() { (*cibase->nprocs->win_nhbell)(cibase->ndata); } int chainin_doprev_message() { int rv; rv = (*cibase->nprocs->win_doprev_message)(cibase->ndata); return rv; } char chainin_yn_function(query, resp, def) const char *query, *resp; char def; { int rv; rv = (*cibase->nprocs->win_yn_function)(cibase->ndata, query, resp, def); return rv; } void chainin_getlin(query, bufp) const char *query; char *bufp; { (*cibase->nprocs->win_getlin)(cibase->ndata, query, bufp); } int chainin_get_ext_cmd() { int rv; rv = (*cibase->nprocs->win_get_ext_cmd)(cibase->ndata); return rv; } void chainin_number_pad(state) int state; { (*cibase->nprocs->win_number_pad)(cibase->ndata, state); } void chainin_delay_output() { (*cibase->nprocs->win_delay_output)(cibase->ndata); } #ifdef CHANGE_COLOR void chainin_change_color(color, value, reverse) int color; long value; int reverse; { (*cibase->nprocs->win_change_color)(cibase->ndata, color, value, reverse); } #ifdef MAC void chainin_change_background(bw) int bw; { (*cibase->nprocs->win_change_background)(cibase->ndata, bw); } short chainin_set_font_name(window, font) winid window; char *font; { short rv; rv = (*cibase->nprocs->win_set_font_name)(cibase->ndata, window, font); return rv; } #endif char * trace_get_color_string() { char *rv; rv = (*cibase->nprocs->win_get_color_string)(cibase->ndata); return rv; } #endif /* other defs that really should go away (they're tty specific) */ void chainin_start_screen() { (*cibase->nprocs->win_start_screen)(cibase->ndata); } void chainin_end_screen() { (*cibase->nprocs->win_end_screen)(cibase->ndata); } void chainin_outrip(tmpwin, how, when) winid tmpwin; int how; time_t when; { (*cibase->nprocs->win_outrip)(cibase->ndata, tmpwin, how, when); } void chainin_preference_update(pref) const char *pref; { (*cibase->nprocs->win_preference_update)(cibase->ndata, pref); } char * chainin_getmsghistory(init) boolean init; { char *rv; rv = (*cibase->nprocs->win_getmsghistory)(cibase->ndata, init); return rv; } void chainin_putmsghistory(msg, is_restoring) const char *msg; boolean is_restoring; { (*cibase->nprocs->win_putmsghistory)(cibase->ndata, msg, is_restoring); } #ifdef STATUS_VIA_WINDOWPORT void chainin_status_init() { (*cibase->nprocs->win_status_init)(cibase->ndata); } void chainin_status_finish() { (*cibase->nprocs->win_status_finish)(cibase->ndata); } void chainin_status_enablefield(fieldidx, nm, fmt, enable) int fieldidx; const char *nm; const char *fmt; boolean enable; { (*cibase->nprocs->win_status_enablefield)(cibase->ndata, fieldidx, nm, fmt, enable); } void chainin_status_update(idx, ptr, chg, percent) int idx, chg, percent; genericptr_t ptr; { (*cibase->nprocs->win_status_update)(cibase->ndata, idx, ptr, chg, percent); } #ifdef STATUS_HILITES void chainin_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over) int fldidx, thresholdtype; int behavior, under, over; anything threshold; { (*cibase->nprocs->win_status_threshold)(cibase->ndata, fldidx, thresholdtype, threshold, behavior, under, over); } #endif #endif boolean chainin_can_suspend() { boolean rv; rv = (*cibase->nprocs->win_can_suspend)(cibase->ndata); return rv; } struct window_procs chainin_procs = { "-chainin", 0, /* wincap */ 0, /* wincap2 */ /* XXX problem - the above need to come from the real window port, possibly modified. May need to do something to call an additional init fn later or if this is the only place like this the choose_windows fn can do the fixup (but not if the value can be modified by the stack?) TBD */ chainin_init_nhwindows, chainin_player_selection, chainin_askname, chainin_get_nh_event, chainin_exit_nhwindows, chainin_suspend_nhwindows, chainin_resume_nhwindows, chainin_create_nhwindow, chainin_clear_nhwindow, chainin_display_nhwindow, chainin_destroy_nhwindow, chainin_curs, chainin_putstr, chainin_putmixed, chainin_display_file, chainin_start_menu, chainin_add_menu, chainin_end_menu, chainin_select_menu, chainin_message_menu, chainin_update_inventory, chainin_mark_synch, chainin_wait_synch, #ifdef CLIPPING chainin_cliparound, #endif #ifdef POSITIONBAR chainin_update_positionbar, #endif chainin_print_glyph, chainin_raw_print, chainin_raw_print_bold, chainin_nhgetch, chainin_nh_poskey, chainin_nhbell, chainin_doprev_message, chainin_yn_function, chainin_getlin, chainin_get_ext_cmd, chainin_number_pad, chainin_delay_output, #ifdef CHANGE_COLOR chainin_change_color, #ifdef MAC chainin_change_background, chainin_set_font_name, #endif chainin_get_color_string, #endif chainin_start_screen, chainin_end_screen, chainin_outrip, chainin_preference_update, chainin_getmsghistory, chainin_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT chainin_status_init, chainin_status_finish, chainin_status_enablefield, chainin_status_update, #ifdef STATUS_HILITES chainin_status_threshold, #endif #endif chainin_can_suspend, }; nethack-3.6.0/win/chain/wc_chainout.c0000664000076400007660000003107712536476415016510 0ustar paxedpaxed/* NetHack 3.6 wc_chainout.c $NHDT-Date: 1433806611 2015/06/08 23:36:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ /* -chainout is an internal processor that changes the flow from chain_procs * back to window_procs. */ #include "hack.h" struct chainout_data { struct window_procs *nprocs; #if 0 void *ndata; #endif int linknum; }; void * chainout_procs_chain(cmd, n, me, nextprocs, nextdata) int cmd; int n; void *me; void *nextprocs; void *nextdata UNUSED; { switch (cmd) { case WINCHAIN_ALLOC: { struct chainout_data *tdp = calloc(1, sizeof(struct chainout_data)); tdp->linknum = n; return tdp; } case WINCHAIN_INIT: { struct chainout_data *tdp = me; tdp->nprocs = nextprocs; return tdp; } default: raw_printf("chainout_procs_chain: bad cmd\n"); exit(EXIT_FAILURE); } } /* XXX if we don't need this, take it out of the table */ void chainout_procs_init(dir) int dir UNUSED; { } /*** *** winprocs ***/ void chainout_init_nhwindows(vp, argcp, argv) void *vp; int *argcp; char **argv; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_init_nhwindows)(argcp, argv); } void chainout_player_selection(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_player_selection)(); } void chainout_askname(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_askname)(); } void chainout_get_nh_event(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_get_nh_event)(); } void chainout_exit_nhwindows(vp, str) void *vp; const char *str; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_exit_nhwindows)(str); } void chainout_suspend_nhwindows(vp, str) void *vp; const char *str; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_suspend_nhwindows)(str); } void chainout_resume_nhwindows(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_resume_nhwindows)(); } winid chainout_create_nhwindow(vp, type) void *vp; int type; { struct chainout_data *tdp = vp; winid rv; rv = (*tdp->nprocs->win_create_nhwindow)(type); return rv; } void chainout_clear_nhwindow(vp, window) void *vp; winid window; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_clear_nhwindow)(window); } void chainout_display_nhwindow(vp, window, blocking) void *vp; winid window; BOOLEAN_P blocking; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_display_nhwindow)(window, blocking); } void chainout_destroy_nhwindow(vp, window) void *vp; winid window; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_destroy_nhwindow)(window); } void chainout_curs(vp, window, x, y) void *vp; winid window; int x; int y; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_curs)(window, x, y); } void chainout_putstr(vp, window, attr, str) void *vp; winid window; int attr; const char *str; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_putstr)(window, attr, str); } void chainout_putmixed(vp, window, attr, str) void *vp; winid window; int attr; const char *str; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_putmixed)(window, attr, str); } void chainout_display_file(vp, fname, complain) void *vp; const char *fname; boolean complain; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_display_file)(fname, complain); } void chainout_start_menu(vp, window) void *vp; winid window; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_start_menu)(window); } void chainout_add_menu(vp, window, glyph, identifier, ch, gch, attr, str, preselected) void *vp; winid window; /* window to use, must be of type NHW_MENU */ int glyph; /* glyph to display with item (unused) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like tty_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { struct chainout_data *tdp = vp; (*tdp->nprocs->win_add_menu)(window, glyph, identifier, ch, gch, attr, str, preselected); } void chainout_end_menu(vp, window, prompt) void *vp; winid window; const char *prompt; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_end_menu)(window, prompt); } int chainout_select_menu(vp, window, how, menu_list) void *vp; winid window; int how; menu_item **menu_list; { struct chainout_data *tdp = vp; int rv; rv = (*tdp->nprocs->win_select_menu)(window, how, (void *) menu_list); return rv; } char chainout_message_menu(vp, let, how, mesg) void *vp; char let; int how; const char *mesg; { struct chainout_data *tdp = vp; char rv; rv = (*tdp->nprocs->win_message_menu)(let, how, mesg); return rv; } void chainout_update_inventory(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_update_inventory)(); } void chainout_mark_synch(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_mark_synch)(); } void chainout_wait_synch(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_wait_synch)(); } #ifdef CLIPPING void chainout_cliparound(vp, x, y) void *vp; int x; int y; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_cliparound)(x, y); } #endif #ifdef POSITIONBAR void chainout_update_positionbar(vp, posbar) void *vp; char *posbar; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_update_positionbar)(posbar); } #endif void chainout_print_glyph(vp, window, x, y, glyph, bkglyph) void *vp; winid window; xchar x, y; int glyph, bkglyph; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_print_glyph)(window, x, y, glyph, bkglyph); } void chainout_raw_print(vp, str) void *vp; const char *str; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_raw_print)(str); } void chainout_raw_print_bold(vp, str) void *vp; const char *str; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_raw_print_bold)(str); } int chainout_nhgetch(vp) void *vp; { struct chainout_data *tdp = vp; int rv; rv = (*tdp->nprocs->win_nhgetch)(); return rv; } int chainout_nh_poskey(vp, x, y, mod) void *vp; int *x; int *y; int *mod; { struct chainout_data *tdp = vp; int rv; rv = (*tdp->nprocs->win_nh_poskey)(x, y, mod); return rv; } void chainout_nhbell(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_nhbell)(); } int chainout_doprev_message(vp) void *vp; { struct chainout_data *tdp = vp; int rv; rv = (*tdp->nprocs->win_doprev_message)(); return rv; } char chainout_yn_function(vp, query, resp, def) void *vp; const char *query, *resp; char def; { struct chainout_data *tdp = vp; int rv; rv = (*tdp->nprocs->win_yn_function)(query, resp, def); return rv; } void chainout_getlin(vp, query, bufp) void *vp; const char *query; char *bufp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_getlin)(query, bufp); } int chainout_get_ext_cmd(vp) void *vp; { struct chainout_data *tdp = vp; int rv; rv = (*tdp->nprocs->win_get_ext_cmd)(); return rv; } void chainout_number_pad(vp, state) void *vp; int state; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_number_pad)(state); } void chainout_delay_output(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_delay_output)(); } #ifdef CHANGE_COLOR void chainout_change_color(vp, color, value, reverse) void *vp; int color; long value; int reverse; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_change_color)(color, value, reverse); } #ifdef MAC void chainout_change_background(vp, bw) void *vp; int bw; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_change_background)(bw); } short chainout_set_font_name(vp, window, font) void *vp; winid window; char *font; { struct chainout_data *tdp = vp; short rv; rv = (*tdp->nprocs->win_set_font_name)(window, font); return rv; } #endif char * trace_get_color_string(vp) void *vp; { struct chainout_data *tdp = vp; char *rv; rv = (*tdp->nprocs->win_get_color_string)(); return rv; } #endif /* other defs that really should go away (they're tty specific) */ void chainout_start_screen(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_start_screen)(); } void chainout_end_screen(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_end_screen)(); } void chainout_outrip(vp, tmpwin, how, when) void *vp; winid tmpwin; int how; time_t when; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_outrip)(tmpwin, how, when); } void chainout_preference_update(vp, pref) void *vp; const char *pref; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_preference_update)(pref); } char * chainout_getmsghistory(vp, init) void *vp; boolean init; { struct chainout_data *tdp = vp; char *rv; rv = (*tdp->nprocs->win_getmsghistory)(init); return rv; } void chainout_putmsghistory(vp, msg, is_restoring) void *vp; const char *msg; boolean is_restoring; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_putmsghistory)(msg, is_restoring); } #ifdef STATUS_VIA_WINDOWPORT void chainout_status_init(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_status_init)(); } void chainout_status_finish(vp) void *vp; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_status_finish)(); } void chainout_status_enablefield(vp, fieldidx, nm, fmt, enable) void *vp; int fieldidx; const char *nm; const char *fmt; boolean enable; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_status_enablefield)(fieldidx, nm, fmt, enable); } void chainout_status_update(vp, idx, ptr, chg, percent) void *vp; int idx, chg, percent; genericptr_t ptr; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_status_update)(idx, ptr, chg, percent); } #ifdef STATUS_HILITES void chainout_status_threshold(vp, fldidx, thresholdtype, threshold, behavior, under, over) void *vp; int fldidx, thresholdtype; int behavior, under, over; anything threshold; { struct chainout_data *tdp = vp; (*tdp->nprocs->win_status_threshold)(fldidx, thresholdtype, threshold, behavior, under, over); } #endif #endif boolean chainout_can_suspend(vp) void *vp; { struct chainout_data *tdp = vp; boolean rv; rv = (*tdp->nprocs->win_can_suspend)(); return rv; } struct chain_procs chainout_procs = { "-chainout", 0, /* wincap */ 0, /* wincap2 */ /* XXX problem - the above need to come from the real window port, possibly modified. May need to do something to call an additional init fn later or if this is the only place like this the choose_windows fn can do the fixup (but not if the value can be modified by the stack?) TBD */ chainout_init_nhwindows, chainout_player_selection, chainout_askname, chainout_get_nh_event, chainout_exit_nhwindows, chainout_suspend_nhwindows, chainout_resume_nhwindows, chainout_create_nhwindow, chainout_clear_nhwindow, chainout_display_nhwindow, chainout_destroy_nhwindow, chainout_curs, chainout_putstr, chainout_putmixed, chainout_display_file, chainout_start_menu, chainout_add_menu, chainout_end_menu, chainout_select_menu, chainout_message_menu, chainout_update_inventory, chainout_mark_synch, chainout_wait_synch, #ifdef CLIPPING chainout_cliparound, #endif #ifdef POSITIONBAR chainout_update_positionbar, #endif chainout_print_glyph, chainout_raw_print, chainout_raw_print_bold, chainout_nhgetch, chainout_nh_poskey, chainout_nhbell, chainout_doprev_message, chainout_yn_function, chainout_getlin, chainout_get_ext_cmd, chainout_number_pad, chainout_delay_output, #ifdef CHANGE_COLOR chainout_change_color, #ifdef MAC chainout_change_background, chainout_set_font_name, #endif chainout_get_color_string, #endif chainout_start_screen, chainout_end_screen, chainout_outrip, chainout_preference_update, chainout_getmsghistory, chainout_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT chainout_status_init, chainout_status_finish, chainout_status_enablefield, chainout_status_update, #ifdef STATUS_HILITES chainout_status_threshold, #endif #endif chainout_can_suspend, }; nethack-3.6.0/win/chain/wc_trace.c0000664000076400007660000006173412536476415015777 0ustar paxedpaxed/* NetHack 3.6 wc_trace.c $NHDT-Date: 1433806611 2015/06/08 23:36:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "wintty.h" #include "func_tab.h" #include #include FILE *wc_tracelogf; /* Should be static, but it's just too useful to have * access to this logfile from arbitrary other files. */ static unsigned int indent_level; /* Some winfuncs call other winfuncs, so * we need to support nesting. */ static char indentdata[10] = " "; #define ISCALE 1 #if 1 #define INDENT \ &indentdata[((indent_level * ISCALE) < (sizeof(indentdata))) \ ? ((sizeof(indentdata) - 1) - (indent_level * ISCALE)) \ : 0] #else /* for debugging this file */ #define INDENT \ ({ \ static char buf[50]; \ sprintf(buf, "[%s:%d %d]\t", __func__, __LINE__, indent_level); \ buf; \ }) #endif #define PRE indent_level++ #define POST indent_level-- struct trace_data { struct chain_procs *nprocs; void *ndata; int linknum; }; void * trace_procs_chain(cmd, n, me, nextprocs, nextdata) int cmd; int n; void *me; void *nextprocs; void *nextdata; { switch (cmd) { case WINCHAIN_ALLOC: { struct trace_data *tdp = calloc(1, sizeof(struct trace_data)); tdp->linknum = n; return tdp; } case WINCHAIN_INIT: { struct trace_data *tdp = me; tdp->nprocs = nextprocs; tdp->ndata = nextdata; return tdp; } default: raw_printf("trace_procs_chain: bad cmd\n"); exit(EXIT_FAILURE); } } void trace_procs_init(dir) int dir; { char fname[200]; /* processors shouldn't need this test, but just in case */ if (dir != WININIT) return; sprintf(fname, "%s/tlog.%d", HACKDIR, getpid()); wc_tracelogf = fopen(fname, "w"); if (wc_tracelogf == NULL) { fprintf(stderr, "Can't open trace log file %s: %s\n", fname, strerror(errno)); exit(EXIT_FAILURE); } setvbuf(wc_tracelogf, (char *) NULL, _IONBF, 0); fprintf(wc_tracelogf, "Trace log started for pid %d\n", getpid()); indent_level = 0; } /*** *** winprocs ***/ void trace_init_nhwindows(vp, argcp, argv) void *vp; int *argcp; char **argv; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sinit_nhwindows(%d,*)\n", INDENT, *argcp); PRE; (*tdp->nprocs->win_init_nhwindows)(tdp->ndata, argcp, argv); POST; } void trace_player_selection(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%splayer_selection()\n", INDENT); PRE; (*tdp->nprocs->win_player_selection)(tdp->ndata); POST; } void trace_askname(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%saskname()\n", INDENT); PRE; (*tdp->nprocs->win_askname)(tdp->ndata); POST; } void trace_get_nh_event(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sget_nh_event()\n", INDENT); PRE; (*tdp->nprocs->win_get_nh_event)(tdp->ndata); POST; } void trace_exit_nhwindows(vp, str) void *vp; const char *str; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sexit_nhwindows(%s)\n", INDENT, str); PRE; (*tdp->nprocs->win_exit_nhwindows)(tdp->ndata, str); POST; } void trace_suspend_nhwindows(vp, str) void *vp; const char *str; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%ssuspend_nhwindows(%s)\n", INDENT, str); PRE; (*tdp->nprocs->win_suspend_nhwindows)(tdp->ndata, str); POST; } void trace_resume_nhwindows(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sresume_nhwindows()\n", INDENT); PRE; (*tdp->nprocs->win_resume_nhwindows)(tdp->ndata); POST; } static const char * NHWname(type) int type; { switch (type) { case NHW_MESSAGE: return "MESSAGE"; case NHW_STATUS: return "STATUS"; case NHW_MAP: return "MAP"; case NHW_MENU: return "MENU"; case NHW_TEXT: return "TEXT"; case NHW_BASE: return "BASE"; default: { static char b[20]; sprintf(b, "(%d)", type); return b; } } } winid trace_create_nhwindow(vp, type) void *vp; int type; { struct trace_data *tdp = vp; const char *typestring = NHWname(type); winid rv; fprintf(wc_tracelogf, "%screate_nhwindow(%s)\n", INDENT, typestring); PRE; rv = (*tdp->nprocs->win_create_nhwindow)(tdp->ndata, type); POST; fprintf(wc_tracelogf, "%s=> %d\n", INDENT, rv); return rv; } void trace_clear_nhwindow(vp, window) void *vp; winid window; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sclear_nhwindow(%d)\n", INDENT, window); PRE; (*tdp->nprocs->win_clear_nhwindow)(tdp->ndata, window); POST; } void trace_display_nhwindow(vp, window, blocking) void *vp; winid window; BOOLEAN_P blocking; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sdisplay_nhwindow(%d, %d)\n", INDENT, window, blocking); PRE; (*tdp->nprocs->win_display_nhwindow)(tdp->ndata, window, blocking); POST; } void trace_destroy_nhwindow(vp, window) void *vp; winid window; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sdestroy_nhwindow(%d)\n", INDENT, window); PRE; (*tdp->nprocs->win_destroy_nhwindow)(tdp->ndata, window); POST; } void trace_curs(vp, window, x, y) void *vp; winid window; int x; int y; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%scurs(%d, %d, %d)\n", INDENT, window, x, y); PRE; (*tdp->nprocs->win_curs)(tdp->ndata, window, x, y); POST; } void trace_putstr(vp, window, attr, str) void *vp; winid window; int attr; const char *str; { struct trace_data *tdp = vp; if (str) { fprintf(wc_tracelogf, "%sputstr(%d, %d, '%s'(%d))\n", INDENT, window, attr, str, (int) strlen(str)); } else { fprintf(wc_tracelogf, "%sputstr(%d, %d, NULL)\n", INDENT, window, attr); } PRE; (*tdp->nprocs->win_putstr)(tdp->ndata, window, attr, str); POST; } void trace_putmixed(vp, window, attr, str) void *vp; winid window; int attr; const char *str; { struct trace_data *tdp = vp; if (str) { fprintf(wc_tracelogf, "%sputmixed(%d, %d, '%s'(%d))\n", INDENT, window, attr, str, (int) strlen(str)); } else { fprintf(wc_tracelogf, "%sputmixed(%d, %d, NULL)\n", INDENT, window, attr); } PRE; (*tdp->nprocs->win_putmixed)(tdp->ndata, window, attr, str); POST; } void trace_display_file(vp, fname, complain) void *vp; const char *fname; boolean complain; { struct trace_data *tdp = vp; if (fname) { fprintf(wc_tracelogf, "%sdisplay_file('%s'(%d), %d)\n", INDENT, fname, (int) strlen(fname), complain); } else { fprintf(wc_tracelogf, "%sdisplay_file(NULL, %d)\n", INDENT, complain); } PRE; (*tdp->nprocs->win_display_file)(tdp->ndata, fname, complain); POST; } void trace_start_menu(vp, window) void *vp; winid window; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sstart_menu(%d)\n", INDENT, window); PRE; (*tdp->nprocs->win_start_menu)(tdp->ndata, window); POST; } void trace_add_menu(vp, window, glyph, identifier, ch, gch, attr, str, preselected) void *vp; winid window; /* window to use, must be of type NHW_MENU */ int glyph; /* glyph to display with item (unused) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like tty_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { struct trace_data *tdp = vp; char buf_ch[10]; char buf_gch[10]; if (isprint(ch)) { sprintf(buf_ch, "'%c'(%d)", ch, ch); } else { sprintf(buf_ch, "(%d)", ch); } if (isprint(gch)) { sprintf(buf_gch, "'%c'(%d)", gch, gch); } else { sprintf(buf_gch, "(%d)", gch); } if (str) { fprintf(wc_tracelogf, "%sadd_menu(%d, %d, %p, %s, %s, %d, '%s'(%d), %d)\n", INDENT, window, glyph, (void *) identifier, buf_ch, buf_gch, attr, str, (int) strlen(str), preselected); } else { fprintf(wc_tracelogf, "%sadd_menu(%d, %d, %p, %s, %s, %d, NULL, %d)\n", INDENT, window, glyph, (void *) identifier, buf_ch, buf_gch, attr, preselected); } PRE; (*tdp->nprocs->win_add_menu)(tdp->ndata, window, glyph, identifier, ch, gch, attr, str, preselected); POST; } void trace_end_menu(vp, window, prompt) void *vp; winid window; const char *prompt; { struct trace_data *tdp = vp; if (prompt) { fprintf(wc_tracelogf, "%send_menu(%d, '%s'(%d))\n", INDENT, window, prompt, (int) strlen(prompt)); } else { fprintf(wc_tracelogf, "%send_menu(%d, NULL)\n", INDENT, window); } PRE; (*tdp->nprocs->win_end_menu)(tdp->ndata, window, prompt); POST; } int trace_select_menu(vp, window, how, menu_list) void *vp; winid window; int how; menu_item **menu_list; { struct trace_data *tdp = vp; int rv; fprintf(wc_tracelogf, "%sselect_menu(%d, %d, %p)\n", INDENT, window, how, (void *) menu_list); PRE; rv = (*tdp->nprocs->win_select_menu)(tdp->ndata, window, how, (void *) menu_list); POST; fprintf(wc_tracelogf, "%s=> %d\n", INDENT, rv); return rv; } char trace_message_menu(vp, let, how, mesg) void *vp; char let; int how; const char *mesg; { struct trace_data *tdp = vp; char buf_let[10]; char rv; if (isprint(let)) { sprintf(buf_let, "'%c'(%d)", let, let); } else { sprintf(buf_let, "(%d)", let); } if (mesg) { fprintf(wc_tracelogf, "%smessage_menu(%s, %d, '%s'(%d))\n", INDENT, buf_let, how, mesg, (int) strlen(mesg)); } else { fprintf(wc_tracelogf, "%smessage_menu(%s, %d, NULL)\n", INDENT, buf_let, how); } PRE; rv = (*tdp->nprocs->win_message_menu)(tdp->ndata, let, how, mesg); POST; if (isprint(rv)) { sprintf(buf_let, "'%c'(%d)", rv, rv); } else { sprintf(buf_let, "(%d)", rv); } fprintf(wc_tracelogf, "%s=> %s\n", INDENT, buf_let); return rv; } void trace_update_inventory(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%supdate_inventory()\n", INDENT); PRE; (*tdp->nprocs->win_update_inventory)(tdp->ndata); POST; } void trace_mark_synch(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%smark_synch()\n", INDENT); PRE; (*tdp->nprocs->win_mark_synch)(tdp->ndata); POST; } void trace_wait_synch(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%swait_synch()\n", INDENT); PRE; (*tdp->nprocs->win_wait_synch)(tdp->ndata); POST; } #ifdef CLIPPING void trace_cliparound(vp, x, y) void *vp; int x; int y; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%scliparound(%d, %d)\n", INDENT, x, y); PRE; (*tdp->nprocs->win_cliparound)(tdp->ndata, x, y); POST; } #endif #ifdef POSITIONBAR void trace_update_positionbar(vp, posbar) void *vp; char *posbar; { struct trace_data *tdp = vp; if (posbar) { fprintf(wc_tracelogf, "%supdate_positionbar('%s'(%d))\n", INDENT, posbar, (int) strlen(posbar)); } else { fprintf(wc_tracelogf, "%supdate_positionbar(NULL)\n"); } PRE; (*tdp->nprocs->win_update_positionbar)(tdp->ndata, posbar); POST; } #endif /* XXX can we decode the glyph in a meaningful way? see mapglyph()? genl_putmixed? */ void trace_print_glyph(vp, window, x, y, glyph, bkglyph) void *vp; winid window; xchar x, y; int glyph, bkglyph; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sprint_glyph(%d, %d, %d, %d, %d)\n", INDENT, window, x, y, glyph, bkglyph); PRE; (*tdp->nprocs->win_print_glyph)(tdp->ndata, window, x, y, glyph, bkglyph); POST; } void trace_raw_print(vp, str) void *vp; const char *str; { struct trace_data *tdp = vp; if (str) { fprintf(wc_tracelogf, "%sraw_print('%s'(%d))\n", INDENT, str, (int) strlen(str)); } else { fprintf(wc_tracelogf, "%sraw_print(NULL)\n", INDENT); } PRE; (*tdp->nprocs->win_raw_print)(tdp->ndata, str); POST; } void trace_raw_print_bold(vp, str) void *vp; const char *str; { struct trace_data *tdp = vp; if (str) { fprintf(wc_tracelogf, "%sraw_print_bold('%s'(%d))\n", INDENT, str, (int) strlen(str)); } else { fprintf(wc_tracelogf, "%sraw_print_bold(NULL)\n", INDENT); } PRE; (*tdp->nprocs->win_raw_print_bold)(tdp->ndata, str); POST; } int trace_nhgetch(vp) void *vp; { struct trace_data *tdp = vp; int rv; char buf[10]; fprintf(wc_tracelogf, "%snhgetch()\n", INDENT); PRE; rv = (*tdp->nprocs->win_nhgetch)(tdp->ndata); POST; if (rv > 0 && rv < 256 && isprint(rv)) { sprintf(buf, "'%c'(%d)", rv, rv); } else { sprintf(buf, "(%d)", rv); } fprintf(wc_tracelogf, "%s=> %s\n", INDENT, buf); return rv; } int trace_nh_poskey(vp, x, y, mod) void *vp; int *x; int *y; int *mod; { struct trace_data *tdp = vp; int rv; char buf[10]; fprintf(wc_tracelogf, "%snh_poskey(%d, %d, %d)\n", INDENT, *x, *y, *mod); PRE; rv = (*tdp->nprocs->win_nh_poskey)(tdp->ndata, x, y, mod); POST; if (rv > 0 && rv < 256 && isprint(rv)) { sprintf(buf, "'%c'(%d)", rv, rv); } else { sprintf(buf, "(%d)", rv); } fprintf(wc_tracelogf, "%s=> %s (%d, %d, %d)\n", INDENT, buf, *x, *y, *mod); return rv; } void trace_nhbell(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%snhbell()\n", INDENT); PRE; (*tdp->nprocs->win_nhbell)(tdp->ndata); POST; } int trace_doprev_message(vp) void *vp; { struct trace_data *tdp = vp; int rv; fprintf(wc_tracelogf, "%sdoprev_message()\n", INDENT); PRE; rv = (*tdp->nprocs->win_doprev_message)(tdp->ndata); POST; fprintf(wc_tracelogf, "%s=> %d\n", INDENT, rv); return rv; } char trace_yn_function(vp, query, resp, def) void *vp; const char *query, *resp; char def; { struct trace_data *tdp = vp; char rv; char buf[10]; if (query) { fprintf(wc_tracelogf, "%syn_function('%s'(%d), ", INDENT, query, (int) strlen(query)); } else { fprintf(wc_tracelogf, "%syn_function(NULL, ", INDENT); } if (resp) { fprintf(wc_tracelogf, "'%s'(%d), ", resp, (int) strlen(resp)); } else { fprintf(wc_tracelogf, "NULL, "); } if (isprint(def)) { sprintf(buf, "'%c'(%d)", def, def); } else { sprintf(buf, "(%d)", def); } fprintf(wc_tracelogf, "%s)\n", buf); PRE; rv = (*tdp->nprocs->win_yn_function)(tdp->ndata, query, resp, def); POST; if (isprint(rv)) { sprintf(buf, "'%c'(%d)", rv, rv); } else { sprintf(buf, "(%d)", rv); } fprintf(wc_tracelogf, "%s=> %s\n", INDENT, buf); return rv; } void trace_getlin(vp, query, bufp) void *vp; const char *query; char *bufp; { struct trace_data *tdp = vp; if (query) { fprintf(wc_tracelogf, "%sgetlin('%s'(%d), ", INDENT, query, (int) strlen(query)); } else { fprintf(wc_tracelogf, "%sgetlin(NULL, ", INDENT); } if (bufp) { fprintf(wc_tracelogf, "%p)\n", bufp); } else { fprintf(wc_tracelogf, "NULL)\n"); } PRE; (*tdp->nprocs->win_getlin)(tdp->ndata, query, bufp); POST; } int trace_get_ext_cmd(vp) void *vp; { struct trace_data *tdp = vp; int rv; int ecl_size; /* this is ugly, but the size isn't exposed */ const struct ext_func_tab *efp; for (efp = extcmdlist; efp->ef_txt; efp++) ecl_size++; fprintf(wc_tracelogf, "%sget_ext_cmd()\n", INDENT); PRE; rv = (*tdp->nprocs->win_get_ext_cmd)(tdp->ndata); POST; if (rv < 0 || rv >= ecl_size) { fprintf(wc_tracelogf, "%s=> (%d)\n", INDENT, rv); } else { fprintf(wc_tracelogf, "%s=> %d/%s\n", INDENT, rv, extcmdlist[rv].ef_txt); } return rv; } void trace_number_pad(vp, state) void *vp; int state; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%snumber_pad(%d)\n", INDENT, state); PRE; (*tdp->nprocs->win_number_pad)(tdp->ndata, state); POST; } void trace_delay_output(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sdelay_output()\n", INDENT); PRE; (*tdp->nprocs->win_delay_output)(tdp->ndata); POST; } #ifdef CHANGE_COLOR void trace_change_color(vp, color, value, reverse) void *vp; int color; long value; int reverse; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%schange_color(%d, $%lx, %d)\n", INDENT, color, value, reverse); PRE; (*tdp->nprocs->win_change_color)(tdp->ndata, color, value, reverse); POST; } #ifdef MAC void trace_change_background(vp, bw) void *vp; int bw; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%schange_background(%d)\n", INDENT, bw); PRE; (*tdp->nprocs->win_change_background)(tdp->ndata, bw); POST; } short trace_set_font_name(vp, window, font) void *vp; winid window; char *font; { struct trace_data *tdp = vp; short rv; if (font) { fprintf(wc_tracelogf, "%sset_font_name(%d, '%s'(%d))\n", INDENT, window, font, (int) (strlen(font))); } else { fprintf(wc_tracelogf, "%sset_font_name(%d, NULL)\n", INDENT, window); } PRE; rv = (*tdp->nprocs->win_set_font_name)(tdp->ndata, window, font); POST; fprintf(wc_tracelogf, "%s=> %d\n", INDENT, rv); return rv; } #endif char * trace_get_color_string(vp) void *vp; { struct trace_data *tdp = vp; char *rv; fprintf(wc_tracelogf, "%sget_color_string()\n"); PRE; rv = (*tdp->nprocs->win_get_color_string)(tdp->ndata); POST; if (rv) { fprintf(wc_tracelogf, "%s=> '%s'(%d)\n", INDENT, rv, (int) strlen(rv)); } else { fprintf(wc_tracelogf, "%s=> NULL\n"); } return rv; } #endif /* other defs that really should go away (they're tty specific) */ void trace_start_screen(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sstart_screen()\n", INDENT); PRE; (*tdp->nprocs->win_start_screen)(tdp->ndata); POST; } void trace_end_screen(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%send_screen()\n", INDENT); PRE; (*tdp->nprocs->win_end_screen)(tdp->ndata); POST; } void trace_outrip(vp, tmpwin, how, when) void *vp; winid tmpwin; int how; time_t when; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%soutrip(%d, %d, %ld)\n", INDENT, (int) tmpwin, how, (long) when); PRE; (*tdp->nprocs->win_outrip)(tdp->ndata, tmpwin, how, when); POST; } void trace_preference_update(vp, pref) void *vp; const char *pref; { struct trace_data *tdp = vp; if (pref) { fprintf(wc_tracelogf, "%spreference_update('%s'(%d))\n", INDENT, pref, (int) strlen(pref)); } else { fprintf(wc_tracelogf, "%spreference_update(NULL)\n", INDENT); } PRE; (*tdp->nprocs->win_preference_update)(tdp->ndata, pref); POST; } char * trace_getmsghistory(vp, init) void *vp; boolean init; { struct trace_data *tdp = vp; char *rv; fprintf(wc_tracelogf, "%sgetmsghistory(%d)\n", INDENT, init); PRE; rv = (*tdp->nprocs->win_getmsghistory)(tdp->ndata, init); POST; if (rv) { fprintf(wc_tracelogf, "%s=> '%s'(%d)\n", INDENT, rv, (int) strlen(rv)); } else { fprintf(wc_tracelogf, "%s=> NULL\n", INDENT); } return rv; } void trace_putmsghistory(vp, msg, is_restoring) void *vp; const char *msg; boolean is_restoring; { struct trace_data *tdp = vp; if (msg) { fprintf(wc_tracelogf, "%sputmsghistory('%s'(%d), %d)\n", INDENT, msg, (int) strlen(msg), is_restoring); } else { fprintf(wc_tracelogf, "%sputmghistory(NULL, %d)\n", INDENT, is_restoring); } PRE; (*tdp->nprocs->win_putmsghistory)(tdp->ndata, msg, is_restoring); POST; } #ifdef STATUS_VIA_WINDOWPORT void trace_status_init(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sstatus_init()\n", INDENT); PRE; (*tdp->nprocs->win_status_init)(tdp->ndata); POST; } void trace_status_finish(vp) void *vp; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sstatus_finish()\n", INDENT); PRE; (*tdp->nprocs->win_status_finish)(tdp->ndata); POST; } void trace_status_enablefield(vp, fieldidx, nm, fmt, enable) void *vp; int fieldidx; const char *nm; const char *fmt; boolean enable; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sstatus_enablefield(%d, ", INDENT, fieldidx); if (nm) { fprintf(wc_tracelogf, "'%s'(%d), ", nm, (int) strlen(nm)); } else { fprintf(wc_tracelogf, "NULL, "); } if (fmt) { fprintf(wc_tracelogf, "'%s'(%d), ", fmt, (int) strlen(fmt)); } else { fprintf(wc_tracelogf, "NULL, "); } fprintf(wc_tracelogf, "%d)\n", enable); PRE; (*tdp->nprocs->win_status_enablefield)(tdp->ndata, fieldidx, nm, fmt, enable); POST; } void trace_status_update(vp, idx, ptr, chg, percent) void *vp; int idx, chg, percent; genericptr_t ptr; { struct trace_data *tdp = vp; fprintf(wc_tracelogf, "%sstatus_update(%d, %p, %d, %d)\n", INDENT, idx, ptr, chg, percent); PRE; (*tdp->nprocs->win_status_update)(tdp->ndata, idx, ptr, chg, percent); POST; } #ifdef STATUS_HILITES void trace_status_threshold(vp, fldidx, thresholdtype, threshold, behavior, under, over) void *vp; int fldidx, thresholdtype; int behavior, under, over; anything threshold; { struct trace_data *tdp = vp; /* XXX how do we print an anything? We don't. */ fprintf(wc_tracelogf, "%sstatus_threshold(%d, %d, -, %d, %d, %d)\n", INDENT, fldidx, thresholdtype, behavior, under, over); PRE; (*tdp->nprocs->win_status_threshold)(tdp->ndata, fldidx, thresholdtype, threshold, behavior, under, over); POST; } #endif #endif boolean trace_can_suspend(vp) void *vp; { struct trace_data *tdp = vp; boolean rv; fprintf(wc_tracelogf, "%scan_suspend()\n", INDENT); PRE; rv = (*tdp->nprocs->win_can_suspend)(tdp->ndata); POST; fprintf(wc_tracelogf, "%s=> %d\n", INDENT, rv); return rv; } struct chain_procs trace_procs = { "+trace", 0, /* wincap */ 0, /* wincap2 */ /* XXX problem - the above need to come from the real window port, possibly modified. May need to do something to call an additional init fn later or if this is the only place like this the choose_windows fn can do the fixup (but not if the value can be modified by the stack?) TBD */ trace_init_nhwindows, trace_player_selection, trace_askname, trace_get_nh_event, trace_exit_nhwindows, trace_suspend_nhwindows, trace_resume_nhwindows, trace_create_nhwindow, trace_clear_nhwindow, trace_display_nhwindow, trace_destroy_nhwindow, trace_curs, trace_putstr, trace_putmixed, trace_display_file, trace_start_menu, trace_add_menu, trace_end_menu, trace_select_menu, trace_message_menu, trace_update_inventory, trace_mark_synch, trace_wait_synch, #ifdef CLIPPING trace_cliparound, #endif #ifdef POSITIONBAR trace_update_positionbar, #endif trace_print_glyph, trace_raw_print, trace_raw_print_bold, trace_nhgetch, trace_nh_poskey, trace_nhbell, trace_doprev_message, trace_yn_function, trace_getlin, trace_get_ext_cmd, trace_number_pad, trace_delay_output, #ifdef CHANGE_COLOR trace_change_color, #ifdef MAC trace_change_background, trace_set_font_name, #endif trace_get_color_string, #endif trace_start_screen, trace_end_screen, trace_outrip, trace_preference_update, trace_getmsghistory, trace_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT trace_status_init, trace_status_finish, trace_status_enablefield, trace_status_update, #ifdef STATUS_HILITES trace_status_threshold, #endif #endif trace_can_suspend, }; nethack-3.6.0/win/gem/Install.gem0000664000076400007660000000210712536476415015617 0ustar paxedpaxed$NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ Hi, This is nethack3.5.0 for Atari Gem and tty Windowing System. It is by far not complete or perfect. (My english too :-)) You need at least 2Meg free RAM, 16 colors and 3 Meg free Disk space. In fact it works also with monochrome, but you have to create a nh2.img (and title2.img) on your own. Atari windowport changes from 3.3.0: added a ASCII-Mode in GEM -> F2 the cursor is switchable -> F3 added inventory/menu search -> : removed the redraw problem removed almost all flicker (except with NOVA-Card :-() placed the GEM-dialogues more pleasent tty corner windows (i.e. inv) display now correct in a vt52-win greyed out old messages placed the GEM-windows more convient ... Feel free to contact me about Issues and Errors. e-mail: gaston@cs.tu-berlin.de You use this program at your own risk, I can't guarantee it will work or do you no harm. Look at the nethack licence too. As you may have noticed the look and feel is from Warwick Allisons nethack3.1.3d Gem Version and I have used E_Gem2.2.0 from Christian Grunenberg. Marvin nethack-3.6.0/win/gem/bitmfile.c0000664000076400007660000002454412536476415015467 0ustar paxedpaxed/****************************\ * Bitmap mit Farbtabelle als * * Graphik-Datei speichern * * Autor: Gabriel Schmidt * * (c) 1992 by MAXON-Computer * * Modifiziert von Sebastian * * Bieber, Dez. 1994 * * -> Programmcode * \****************************/ /* * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $ */ #include #include #include #include #include #include "bitmfile.h" /* --- (X) IMG-Implementation ----------------- */ #define IMG_COMPRESSED typedef struct { UWORD img_version; UWORD img_headlen; UWORD img_nplanes; UWORD img_patlen; UWORD img_pixw; UWORD img_pixh; UWORD img_w; UWORD img_h; } IMG_HEADER; typedef enum { NONE, SOLID0, SOLID1, PATRUN, BITSTR } IMG_MODE; typedef UBYTE IMG_SOLID; typedef enum { RGB = 0, CMY = 1, Pantone = 2 } XIMG_COLMODEL; typedef struct { ULONG img_ximg; XIMG_COLMODEL img_colmodel; } XIMG_HEADER; typedef struct RGB XIMG_RGB; int bitmap_to_img(FILE_TYP typ, int ww, int wh, unsigned int pixw, unsigned int pixh, unsigned int planes, unsigned int colors, const char *filename, void (*get_color)(unsigned int colind, struct RGB *rgb), void (*get_pixel)(int x, int y, unsigned int *colind)) { int file, error, cnt; IMG_HEADER header; XIMG_HEADER xheader; XIMG_RGB xrgb; IMG_MODE mode; UBYTE *line_buf, *write_buf; register UBYTE *startpnt, *bufpnt; unsigned int colind, line_len, line, bit; register unsigned int byte; register UBYTE count; /* fill in (X) IMG-Header */ header.img_version = 1; header.img_headlen = (UWORD) sizeof(header) / 2; if (typ == XIMG) header.img_headlen += (UWORD)(sizeof(xheader) + colors * sizeof(xrgb)) / 2; header.img_nplanes = planes; header.img_patlen = 2; header.img_pixw = pixw; header.img_pixh = pixh; header.img_w = ww; header.img_h = wh; xheader.img_ximg = XIMG_MAGIC; xheader.img_colmodel = RGB; /* calculate linelength, allocate buffer. */ line_len = (ww + 7) / 8; line_buf = malloc((size_t) planes * line_len); if (line_buf == NULL) return (ENOMEM); /* Worst case: the bufferd line could grow to max. 3 times the length */ /* of the original! */ write_buf = malloc((size_t) 3 * line_len); if (write_buf == NULL) { free(line_buf); return (ENOMEM); }; /* open file */ file = open(filename, O_WRONLY | O_CREAT | O_TRUNC); if (file < 0) { error = errno; free(line_buf); free(write_buf); return (error); }; /* write Header */ if (write(file, &header, sizeof(header)) != sizeof(header) || (typ == XIMG && write(file, &xheader, sizeof(xheader)) != sizeof(xheader))) { error = errno; close(file); free(line_buf); free(write_buf); return (error); }; /* save the colortable if possible */ if (typ == XIMG) for (cnt = 0; cnt < colors; cnt++) { get_color(cnt, &xrgb); if (write(file, &xrgb, sizeof(xrgb)) != sizeof(xrgb)) { error = errno; close(file); free(line_buf); free(write_buf); return (error); }; }; /* And now line by line ... */ for (line = 0; line < wh; line++) { /* get pixel, split it up and */ /* store it as planes in buffer */ for (byte = 0; byte < line_len; byte++) { for (cnt = 0; cnt < planes; cnt++) line_buf[cnt * line_len + byte] = 0x00; for (bit = 0; bit < 8; bit++) { if (8 * byte + bit < ww) get_pixel(8 * byte + bit, line, &colind); for (cnt = 0; cnt < planes; cnt++) { line_buf[cnt * line_len + byte] <<= 1; line_buf[cnt * line_len + byte] |= colind & 0x01; colind >>= 1; }; }; }; /* compress bitstrings in buffer */ /* and write it to file */ for (cnt = 0; cnt < planes; cnt++) { /* Bitstringpointer to start of plane */ startpnt = &line_buf[cnt * line_len]; bufpnt = write_buf; while (startpnt < &line_buf[(cnt + 1) * line_len]) { /*********************************************/ /* Which _new_ compression-mode "fits" the */ /* the current byte? */ /* Note: the compressing modes get choosen */ /* "positive". The non compressing BITSTR- */ /* mode is choosen only if nothing else */ /* "fits" ... */ /*********************************************/ switch (*startpnt) { case 0x00: mode = SOLID0; break; case 0xFF: mode = SOLID1; break; default: if (startpnt < &line_buf[(cnt + 1) * line_len - 3] && *(startpnt) == *(startpnt + 2) && *(startpnt + 1) == *(startpnt + 3)) mode = PATRUN; else mode = BITSTR; }; /************************************************/ /* The mode is choosen, now work with it. */ /* The compressing modi stay current as long as */ /* possible. */ /************************************************/ count = 0; switch (mode) { case SOLID0: while ((startpnt < &line_buf[(cnt + 1) * line_len]) && (*(startpnt) == 0x00) && (count < 0x7F)) { startpnt++; count++; }; *(bufpnt++) = count; break; case SOLID1: while ((startpnt < &line_buf[(cnt + 1) * line_len]) && (*(startpnt) == 0xFF) && (count < 0x7F)) { startpnt++; count++; }; *(bufpnt++) = 0x80 | count; break; case PATRUN: *(bufpnt++) = 0x00; startpnt += 2; count = 1; while (startpnt < &line_buf[(cnt + 1) * line_len - 1] && *(startpnt) == *(startpnt - 2) && *(startpnt + 1) == *(startpnt - 1) && (count < 0xFF)) { count++; startpnt += 2; }; *(bufpnt++) = count; *(bufpnt++) = *(startpnt - 2); *(bufpnt++) = *(startpnt - 1); break; /************************************************/ /* The while Condition is ment as follows: */ /* */ /* while ( NOT(2-Byte-Solidrun possible) && */ /* NOT(6-Byte-Patternrun possible) && */ /* count < 0xFF * && */ /* still Bytes remaining ) */ /* */ /* As soon as a _compressing_ alternative shows */ /* up, BITSTR gets cancelled! */ /************************************************/ case BITSTR: *(bufpnt++) = 0x80; while (!(((startpnt + count) < &line_buf[(cnt + 1) * line_len - 1]) && (((*(startpnt + count) == 0xFF) && (*(startpnt + count + 1) == 0xFF)) || ((*(startpnt + count) == 0x00) && (*(startpnt + count + 1) == 0x00)))) && !(((startpnt + count) < &line_buf[(cnt + 1) * line_len - 5]) && (*(startpnt + count) == *(startpnt + count + 2)) && (*(startpnt + count + 1) == *(startpnt + count + 3)) && (*(startpnt + count) == *(startpnt + count + 4)) && (*(startpnt + count + 1) == *(startpnt + count + 5))) && (count < 0xFF) && ((startpnt + count) < &line_buf[(cnt + 1) * line_len])) count++; *(bufpnt++) = count; for (; count > 0; count--) *(bufpnt++) = *(startpnt++); break; }; }; if (write(file, write_buf, bufpnt - write_buf) != (bufpnt - write_buf)) { error = errno; close(file); free(line_buf); free(write_buf); return (error); }; }; }; /*close file, free buffer. */ close(file); free(line_buf); free(write_buf); return (0); } /*---filetype-dispatcher--------------------*/ const char * get_file_ext(FILE_TYP typ) { switch (typ) { case IMG: case XIMG: return ("IMG"); default: return (""); }; } int bitmap_to_file(FILE_TYP typ, int ww, int wh, unsigned int pwx, unsigned int pwy, unsigned int planes, unsigned int colors, const char *filename, void (*get_color)(unsigned int colind, struct RGB *rgb), void (*get_pixel)(int x, int y, unsigned int *colind)) { switch (typ) { case IMG: case XIMG: return (bitmap_to_img(typ, ww, wh, pwx, pwy, planes, colors, filename, get_color, get_pixel)); default: return (-1); }; } nethack-3.6.0/win/gem/gem_rsc.uu0000664000076400007660000003351212467321052015502 0ustar paxedpaxedbegin 777 GEM_RSC.RSC M $29@^Z$B(/N@^Z #0)&@^Z)]X Y0 , !8 @ "@. M "!.151(04-+ "!'86UE "!(97)E "!4:&5R90 @271E;0 @07!P M87)E; @36%G:6, ("!!8F]U="!.971H86-K+BXN "TM+2TM+2TM+2TM+2TM M+2TM+2TM+2T ("!$97-K($%C8V5S2 Q(" ("!$97-K($%C8V5S2 R(" ("!$97-K($%C8V5S2 S(" ("!$97-K($%C8V5S2 T M(" ("!$97-K($%C8V5S2 U(" ("!$97-K($%C8V5S2 V(" M("!(96QP+BXN(" @(" @(" @/P @(%=H870@:7,N+BX@(" @(" O " @0V]M M;6%N9"!H96QP+BXN("8 +2TM+2TM+2TM+2TM+2TM+2TM+2TM " @3W!T:6]N M" @ M(" @( 5L " @16YG00 M+2TM M+2TM+2TM+2TM+2TM " @3&]O:R!A=" @(" [ " @4V5A " @2G5M<" @(" @( 5J " @ M0VAA=" @(" @( 5C " @1FEG:'0@(" @("!& " @4VAO=R!A;&P@(" @("!I M " @4VAO=R!K:6YD(" @("!) " @1&ES8V]V97)I97,@("!< "TM+2TM+2TM M+2TM+2TM+2TM+2T ("!%870@(" @(" @(" @(&4 ("!$2 @(" @(" @(&$ ("!5 @($9I;&P@<75I=F5R(" @ M(" @40 @($9I2 @(% ("!296UO M=F4@86-C97-S;W)Y(%( ("!7;W)N(')I;F=S(" @(" @(#T ("!7;W)N(&%M M=6QE=" @(" @("( ("!,:7-T('-P96QL@ @($-A'#P)'$< X#@0/YS^"!P' . X$#_=_@@?GF @ !@)__^8"0 F D 59@) "8"0!5F D )@) 168"0 MF D%!9@$@ $X!($5, 2 3 "0%9P D "8 $@5. D G $A3@ D)P $DX M F< $. G ' #SP\\ \\//@/ M___X#___^ ____@/ #X#U55^ \ /@/557X#P ^ ]55?@/ #X#U55^ > M ?@'U57P!X !\ /55_ #P /@ ?47X #P#\ ?5^ #P_ ??@ #_P ?X M #\ < '0 !V\ =P 4 !@ "$8 /__ M "\ 0 !W$ >1 'D@ % 8 A& #__P @ $ >: 'HP !Z0 M P & 0 __\ "0 ! 'V0 !]L ?E , !@ "$8 /__ ( "@ M!^H ?O '^P # 8 A& #__P % P @ ("0 " H P & 0 M __\ "0 ! ("P "$$ AW , !@ "$8 /__ #8 -@ "(, B% M (A@ # 8 A$ #__@ " $ B' (B0 "(H P & (1 __X M @ ! (BP "(T B. , !@ "$0 /_^ ( 0 "(\ B1 (D@ # M 8 A$ #__@ " $ B3 (E0 ")8 P & (1 __X @ ! ( MEP ")D B: , !@ "$0 /_^ ( 0 ")L B= (G@ # 8 A$ M #__@ " $ B? (H0 "*( P & (1 __X @ ! (HP "*4 M BF , !@ "$0 /_^ ( 0 "*< BN (KP % 8 A& #__P ' M $ BP (M0 "+8 !0 & (1@ __\ !0 ! (MP "- C1 , M!@ "$P, /__ !D 0 "-( C= (Z # 8 I!Y #__P + L CJ M ([0 ".X P & (0> $ P ! ([P "0H D+ , !@ "$0$ M /__ !L 0 "^H D: &URD 4 !( @ \Z M .N@ "1$0 !P " ( ! " +0 (__\ 0 * !D M : 9 H @ " !0 1 : ,! $ P ) !D M " ,@,! 3_____ " - "0,! 7_____ " M /0 ) !@,! ;_____ " 0P / !@,! ?_____ M " 20 5 !P,! C_____ " 4 < !@,! G_ M____ " 5@ B "0,! +_____ " 7P K !P,! M "P!< !D P$ 40 3 !0 # 3 !0 /\1 " M%@ ( W_____ !P 9@ %@ ! [_____ !P ( >0 M $ %@ ! ______ !P D ( %@ ! !#_____ !P MI0 , %@ ! !'_____ !P N@ 0 %@ ! !+_____ !P M SP 4 %@ ! !/_____ !P Y 8 %@ ! O_____ !P M ^0 < %@ ! !\ %0 > !0 /\1 + %0 * !;_____ M !P !#@ %0 ! !?_____ !P !(@ $ %0 ! !C_ M____ !P !-@ ( %0 ! !G_____ !P ( !2@ , %0 ! M !K_____ !P !8 0 %0 ! !O_____ !P != 4 M%0 ! !S_____ !P ( !B 8 %0 ! !W_____ !P !G@ M < %0 ! ![_____ !P ( !L@ @ %0 ! !3_____ !P ! MR D %0 ! "X ( M !0 /\1 1 % . "'_____ !P M !W % ! "+_____ !P ![P $ % ! "/_____ !P M " @ ( % ! "3_____ !P "%0 , % ! "7_____ M !P "* 0 % ! ";_____ !P ".P 4 % ! "?_ M____ !P "3@ 8 % ! "C_____ !P ( "80 < % ! M "G_____ !P "=@ @ % ! "K_____ !P "B0 D M% ! "O_____ !P ( "G H % ! "S_____ !P "L0 M L % ! "W_____ !P "Q P % ! !______ !P " MUP T % ! #L +P Z !0 /\1 7 $ , ##_____ !P M "Z@ $ ! #'_____ !P ( "^0 $ $ ! #+_____ !P M #"@ ( $ ! #/_____ !P #&0 , $ ! #3_____ M !P #* 0 $ ! #7_____ !P #-P 4 $ ! #;_ M____ !P #1@ 8 $ ! #?_____ !P #50 < $ ! M #C_____ !P #9 @ $ ! #G_____ !P #

$P / #W_____ !P # MH $P ! #[_____ !P #L@ $ $P ! #______ !P M #Q ( $P ! $#_____ !P ( #U@ , $P ! $'_____ !P M #Z@ 0 $P ! $+_____ !P #_ 4 $P ! $/_____ M !P $#@ 8 $P ! $3_____ !P $( < $P ! $7_ M____ !P $,@ @ $P ! $;_____ !P $1 D $P ! M $?_____ !P $5@ H $P ! $C_____ !P $: L M$P ! $G_____ !P ( $>@ P $P ! $K_____ !P $C@ M T $P ! #O_____ !P $H X $P ! %P 3 !; !0 /\1 M D %@ 0 $W_____ !P $L@ %@ ! $[_____ !P M $QP $ %@ ! $______ !P $W ( %@ ! %#_____ !P M $\0 , %@ ! %'_____ !P %!@ 0 %@ ! %+_____ M !P %&P 4 %@ ! %/_____ !P ( %, 8 %@ ! %3_ M____ !P %1P < %@ ! %7_____ !P %7 @ %@ ! M %;_____ !P %<0 D %@ ! %?_____ !P %A@ H M%@ ! %C_____ !P ( %FP L %@ ! %G_____ !P %L@ M P %@ ! %K_____ !P %QP T %@ ! %O_____ !P % MW X %@ ! $O_____ !P %\0 \ %@ ! H 70!H !0 M /\1 M $@ , %[_____ !P &!@ $@ ! %______ !P M ( &%P $ $@ ! &#_____ !P &*@ ( $@ ! &'_____ M !P &.P , $@ ! &+_____ !P &3 0 $@ ! &/_ M____ !P &70 4 $@ ! &3_____ !P &;@ 8 $@ ! M &7_____ !P &?P < $@ ! &;_____ !P &D @ M$@ ! &?_____ !P &H0 D $@ ! &C_____ !P &L@ M H $@ ! %S_____ !P ( &PP L $@ !__\ 0 ! !0 1 M 4 3P " #_____"Q0 8 $1>0 @ "__\ 0 ! !0 M $1 " $ H 5 #_____ !D ( $A 1 , @ !__\ 0 *"Q0 M 0 (1 # $ +@ * +_____ !H,!P &U I @$ P8! 4 P $ M !0 /\1 0 !" #0 ' 3_____ !\ 2(@ "" !0 % +_ M____ !P &V #" 4 !P ! ;_____ !P( &X / $ %0 ! M ?_____ !P &]@ / , '@ ! C_____ !P '%0 / 0 M$0 ! G_____ !P ')P / 8 & ! K_____ !4 /N@ ! M# <$(@ ! #_____ !4 ( /U@ !" @ (0 !__\ 0 ""Q0 0 /X1 M> ! ( 3P@6 +_____$QH,!P 'DP " !4 " ! #_____ !@ ( M ) ( @ &3@ 4__\ 0 ["Q0 0 (1> ! $ + ) +_____ !4( M /\@ " $ " ! #< P U !0 $1>0 " , * @# 4 ! $ M !H,!0 'I0 !" @ ! /_____!1D $1 0 ! < M!@ & !H,!0 'IP $" @ ! 7_____!1D $1 0 ! M D " ( !H,!0 'J0 '" @ ! ?_____!1D $1 M 0 ! L "@ * !H,!0 'JP *" @ ! G_____!1D $1 M 0 ! T # , !H,!0 'K0 -" @ ! O_____!1D $1 M 0 ! \ #@ . !H,!0 'KP 0" @ ! W_____!1D M $1 0 ! !$ $ 0 !H,!0 'L0 3" @ ! ______!1D M $1 0 ! !, $@ 2 !H,!0 'LP 6" @ ! !'_____ M!1D $1 0 ! !4 % 4 !H,!0 'M0 9" @ ! !/_ M____!1D $1 0 ! !< %@ 6 !H,!0 'MP <" @ ! M !7_____!1D $1 0 ! !D & 8 !H,!0 'N0 ?" M @ ! !?_____!1D $1 0 ! !L &@ : !H,!0 'NP B M" @ ! !G_____!1D $1 0 ! !T ' < !H,!0 ' MO0 E" @ ! !O_____!1D $1 0 ! !\ '@ > !H,!0 M 'OP ! ( @ ! !W_____!1D $1 0 ! "$ ( @ !H, M!0 'P0 $ ( @ ! !______!1D $1 0 ! ", (@ B M !H,!0 'PP ' ( @ ! "'_____!1D $1 0 ! "4 M) D !H,!0 'Q0 * ( @ ! "/_____!1D $1 0 ! M "< )@ F !H,!0 'QP - ( @ ! "7_____!1D $1 M 0 ! "D * H !H,!0 'R0 0 ( @ ! "?_____!1D $1 M 0 ! "L *@ J !H,!0 'RP 3 ( @ ! "G_____!1D $1 M 0 ! "T + L !H,!0 'S0 6 ( @ ! "O_____!1D M $1 0 ! "\ +@ N !H,!0 'SP 9 ( @ ! "W_____!1D M $1 0 ! #$ , P !H,!0 'T0 < ( @ ! "______ M!1D $1 0 ! #, ,@ R !H,!0 'TP ? ( @ ! #'_ M____!1D $1 0 ! #4 - T !H,!0 'U0 B ( @ ! M #/_____!1D $1 0 ! ( -@ V !H,!0 'UP E ( M @ ! #7_____!1D $1 0 ! #H . Y !0 $1>0 # M , %@ # #G_____ !X(" 0#@ ! $ "P ! #?_____ !H,!P ' MYP - $ !P ! #O_____ !X(" 0*@ # < # ! #_____ !H,)0 M '_0 1 < !@ !__\ 0 $"Q0( 0 (1> ! $ .P ' +_____ !4( M 01@ " $ -P ! /_____ !X(" 08@ " , -P ! 3_____ M$QH$!0 (>0 # 4 " ! #_____ !H,)P (@ P 4 " !__\ M 0 9"Q0 0 1> ( 0 # & +_____ !L 0 6> % @ ! M /_____ !L ! 6> " ( @ ! 3_____ !L P 6> *" ( M @ ! 7_____ !L @ 6> % 4 @ ! < !@ & !8,!0 0?@ " M 0 @ ! 7_____!1D $1 0 ! D " ( !8,!0 0 MF@ % 0 @ ! ?_____!1D $1 0 ! L "@ * !8,!0 M 0M@ ( 0 @ ! G_____!1D $1 0 ! T # , !8, M!0 0T@ "" ( @ ! O_____!1D $1 0 ! \ #@ . M !8,!0 0[@ %" ( @ ! W_____!1D $1 0 ! !$ M$ 0 !8,!0 1"@ (" ( @ ! ______!1D $1 0 ! M !, $@ 2 !8,!0 1)@ " $ @ ! !'_____!1D $1 M 0 ! !4 % 4 !8,!0 10@ % $ @ ! !/_____!1D $1 M 0 ! !< %@ 6 !8,!0 17@ ( $ @ ! !7_____!1D $1 M 0 ! !D & 8 !8,!0 1>@ '! 4 !0P !?_____!1D M $1 ! 0P &@ : !8,!0 1E@ ' !0P !G_____!1D M( $1 ! 0P __\ 0 $ !0 1 ! 4 3P # +_____ M !L, 0 0 6>0 @ ! /_____"Q0( $1>0 $ @ ! 3_ M____ !L, 0 @ 6>0 ( @ ! #_____ !@ ( + " 30 # M__\ 0 $"Q0 0 (1>0 ! $ + @4 +_____ !4( 1L@ ! M+ ! /_____"AX " 1S@ . !( $ ! 3_____ !8,!P 1Z@ A M !( "0@! #_____ !8 ( 2!@ " $ * @,__\ 0 !"Q0 $1 M<@ # , " " #_____ !H,)P )# !" !@ !__\ 0 ! !0 0 @ M /\1>0 " , !@ # #_____ !\ ( 21 P # 29@ '#X G !QN N end nethack-3.6.0/win/gem/gem_rso.uu0000664000076400007660000000234212467321052015513 0ustar paxedpaxedbegin 777 GEM_RSC.RSO M4E-/2 1( @ " ! !#__P __\ M M '___^!____@ M #__P #__P M M /_ '___^!____@ :1F]1)Y2KX@ M (\TJP "!$U%3E4 P'1$]!0D]55 '@9$3U%5250 __\ 0 #"E-4 M05154TQ)3D4 $*1U)!0E-405154P#__P " ,&34%05TE. !DU!4$)/ M6 0E-05!#55)33U( __\ P #!4%"3U54 "$9,64%"3U54 !!T]+ M04)/550 ,+3D542$%#2TE-1S __\ ! #!4Q)3D53 "$9,64Q)3D53 M !!5%,24Y% ""4Q)3D533$E35 #__P % ,(64Y#2$])0T4 +1DQ9 M64Y#2$])0T4 $(64Y04D]-4%0 ()4T]-14-(05)3 # UE.,0 -0-9 M3DX #<'04Y90TA!4@ . A#2$]314Y#2 .@5#3U5.5 .P193D]+ /__ M 8 P=,24Y%1T54 "D9,64Q)3D5'150 $(3$=04D]-4%0 ('3$=2 M15!,60 P-13$< 0$3$=/2P#__P ' ,)1$E214-424]. #$9,641) M4D5#5$E/3@ !01$25(Q 5!$1)4CD !<'1$E21$]73@ &05$25)54 #_ M_P ( ,&35-'5TE. !!55035-' ""D=204)-4T=724X ,%1$Y-4T< M 0(35-'3$E.15, __\ "0 #!TY!345'150 *1DQ93D%-14=%5 @90 M3$Y!344 0.3D542$%#2U!)0U154D4 __\ "@ #!5!!1T52 "$9,65!! @1T52 !!E%004=%4@#__P + ,&3DA)0T]. /____\ end nethack-3.6.0/win/gem/gr_rect.c0000664000076400007660000001410312536476415015307 0ustar paxedpaxed/* NetHack 3.6 gr_rect.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ */ /* Copyright (c) Christian Bressler, 2001 */ /* NetHack may be freely redistributed. See license for details. */ /* This is an almost exact copy of qt_clust.cpp */ /* gr_rect.c */ #include #include #include #include "gr_rect.h" dirty_rect * new_dirty_rect(int size) { dirty_rect *new = NULL; if (size > 0) { new = (dirty_rect *) calloc(1L, sizeof(dirty_rect)); if (new) { new->rects = (GRECT *) calloc((long) size, sizeof(GRECT)); if (new->rects == NULL) { free(new); return (NULL); } new->max = size; } } return (new); } void delete_dirty_rect(dirty_rect *this) { if (this == NULL) return; if (this->rects) free(this->rects); /* In case the Pointer is reused wrongly */ this->rects = NULL; this->max = 0; this->used = 0; free(this); } static int gc_inside(GRECT *frame, GRECT *test); static int gc_touch(GRECT *frame, GRECT *test); static void gc_combine(GRECT *frame, GRECT *test); static long gc_area(GRECT *area); int add_dirty_rect(dirty_rect *dr, GRECT *area) { int cursor; long lowestcost = 9999999L; int cheapest = -1; int cheapestmerge1 = -1; int cheapestmerge2 = -1; int merge1; int merge2; for (cursor = 0; cursor < dr->used; cursor++) { if (gc_inside(&dr->rects[cursor], area)) { /* Wholly contained already. */ return (TRUE); } } for (cursor = 0; cursor < dr->used; cursor++) { if (gc_touch(&dr->rects[cursor], area)) { GRECT larger = dr->rects[cursor]; long cost; gc_combine(&larger, area); cost = gc_area(&larger) - gc_area(&dr->rects[cursor]); if (cost < lowestcost) { int bad = FALSE, c; for (c = 0; c < dr->used && !bad; c++) { bad = gc_touch(&dr->rects[c], &larger) && c != cursor; } if (!bad) { cheapest = cursor; lowestcost = cost; } } } } if (cheapest >= 0) { gc_combine(&dr->rects[cheapest], area); return (TRUE); } if (dr->used < dr->max) { dr->rects[dr->used++] = *area; return (TRUE); } // Do cheapest of: // add to closest cluster // do cheapest cluster merge, add to new cluster lowestcost = 9999999L; cheapest = -1; for (cursor = 0; cursor < dr->used; cursor++) { GRECT larger = dr->rects[cursor]; long cost; gc_combine(&larger, area); cost = gc_area(&larger) - gc_area(&dr->rects[cursor]); if (cost < lowestcost) { int bad = FALSE, c; for (c = 0; c < dr->used && !bad; c++) { bad = gc_touch(&dr->rects[c], &larger) && c != cursor; } if (!bad) { cheapest = cursor; lowestcost = cost; } } } // XXX could make an heuristic guess as to whether we // XXX need to bother looking for a cheap merge. for (merge1 = 0; merge1 < dr->used; merge1++) { for (merge2 = 0; merge2 < dr->used; merge2++) { if (merge1 != merge2) { GRECT larger = dr->rects[merge1]; long cost; gc_combine(&larger, &dr->rects[merge2]); cost = gc_area(&larger) - gc_area(&dr->rects[merge1]) - gc_area(&dr->rects[merge2]); if (cost < lowestcost) { int bad = FALSE, c; for (c = 0; c < dr->used && !bad; c++) { bad = gc_touch(&dr->rects[c], &larger) && c != cursor; } if (!bad) { cheapestmerge1 = merge1; cheapestmerge2 = merge2; lowestcost = cost; } } } } } if (cheapestmerge1 >= 0) { gc_combine(&dr->rects[cheapestmerge1], &dr->rects[cheapestmerge2]); dr->rects[cheapestmerge2] = dr->rects[dr->used - 1]; dr->rects[dr->used - 1] = *area; } else { gc_combine(&dr->rects[cheapest], area); } // NB: clusters do not intersect (or intersection will // overwrite). This is a result of the above algorithm, // given the assumption that (x,y) are ordered topleft // to bottomright. return (TRUE); } int get_dirty_rect(dirty_rect *dr, GRECT *area) { if (dr == NULL || area == NULL || dr->rects == NULL || dr->used <= 0 || dr->max <= 0) return (FALSE); *area = dr->rects[--dr->used]; return (TRUE); } int clear_dirty_rect(dirty_rect *dr) { if (dr) dr->used = 0; return (TRUE); } int resize_dirty_rect(dirty_rect *dr, int new_size) { return (FALSE); } static int gc_inside(GRECT *frame, GRECT *test) { if (frame && test && frame->g_x <= test->g_x && frame->g_y <= test->g_y && frame->g_x + frame->g_w >= test->g_x + test->g_w && frame->g_y + frame->g_h >= test->g_y + test->g_h) return (TRUE); return (FALSE); } static int gc_touch(GRECT *frame, GRECT *test) { GRECT tmp = { test->g_x - 1, test->g_y - 1, test->g_w + 2, test->g_h + 2 }; return (rc_intersect(frame, &tmp)); } static void gc_combine(GRECT *frame, GRECT *test) { if (!frame || !test) return; if (frame->g_x > test->g_x) { frame->g_w += frame->g_x - test->g_x; frame->g_x = test->g_x; } if (frame->g_y > test->g_y) { frame->g_h += frame->g_y - test->g_y; frame->g_y = test->g_y; } if (frame->g_x + frame->g_w < test->g_x + test->g_w) frame->g_w = test->g_x + test->g_w - frame->g_x; if (frame->g_y + frame->g_h < test->g_y + test->g_h) frame->g_h = test->g_y + test->g_h - frame->g_y; } static long gc_area(GRECT *area) { return ((long) area->g_h * (long) area->g_w); } nethack-3.6.0/win/gem/gr_rect.h0000664000076400007660000000103412536476415015313 0ustar paxedpaxed/* gr_rect.h */ /* * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $ */ #include /********** structs **********/ typedef struct { GRECT *rects; int max, used; } dirty_rect; /********* functions ************/ dirty_rect *new_dirty_rect(int size); void delete_dirty_rect(dirty_rect *this); int add_dirty_rect(dirty_rect *dr, GRECT *area); int get_dirty_rect(dirty_rect *dr, GRECT *area); int clear_dirty_rect(dirty_rect *dr); int resize_dirty_rect(dirty_rect *dr, int new_size); nethack-3.6.0/win/gem/load_img.c0000664000076400007660000002217112536476415015441 0ustar paxedpaxed/* * $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ */ #define __TCC_COMPAT__ #include #include #include #include #include #include #include #include #include "load_img.h" #ifndef FALSE #define FALSE 0 #define TRUE !FALSE #endif /* VDI <-> Device palette order conversion matrixes: */ /* Four-plane vdi-device */ int vdi2dev4[] = { 0, 15, 1, 2, 4, 6, 3, 5, 7, 8, 9, 10, 12, 14, 11, 13 }; /* Two-plane vdi-device */ int vdi2dev2[] = { 0, 3, 1, 2 }; void get_colors(int handle, short *palette, int col) { int i, idx; /* get current color palette */ for (i = 0; i < col; i++) { /* device->vdi->device palette order */ switch (planes) { case 1: idx = i; break; case 2: idx = vdi2dev2[i]; break; case 4: idx = vdi2dev4[i]; break; default: if (i < 16) idx = vdi2dev4[i]; else idx = i == 255 ? 1 : i; } vq_color(handle, i, 0, (int *) palette + idx * 3); } } void img_set_colors(int handle, short *palette, int col) { int i, idx, end; /* set color palette */ end = min(1 << col, 1 << planes); for (i = 0; i < end; i++) { switch (planes) { /* MAR -- war col 10.01.2001 */ case 1: idx = i; break; case 2: idx = vdi2dev2[i]; break; case 4: idx = vdi2dev4[i]; break; default: if (i < 16) idx = vdi2dev4[i]; else idx = i == 255 ? 1 : i; } vs_color(handle, i, (int *) palette + idx * 3); } } int convert(MFDB *image, long size) { int plane, mplanes; char *line_addr, *buf_addr, *new_addr, *new1_addr, *image_addr, *screen_addr; MFDB dev_form, tmp; long new_size; /* convert size from words to bytes */ size <<= 1; /* memory for the device raster */ new_size = size * (long) planes; if ((new_addr = (char *) calloc(1, new_size)) == NULL) return (FALSE); /* initialize MFDBs */ tmp = *image; tmp.fd_nplanes = planes; tmp.fd_addr = new_addr; tmp.fd_stand = 1; /* standard format */ dev_form = tmp; screen_addr = new_addr; dev_form.fd_stand = 0; /* device format */ image_addr = (char *) image->fd_addr; /* initialize some variables and zero temp. line buffer */ mplanes = min(image->fd_nplanes, planes); /* convert image */ line_addr = image_addr; buf_addr = screen_addr; if (mplanes > 1) { /* cut/pad color planes into temp buf */ for (plane = 0; plane < mplanes; plane++) { memcpy(buf_addr, line_addr, size); line_addr += size; buf_addr += size; } } else { /* fill temp line bitplanes with a b&w line */ for (plane = 0; plane < planes; plane++) { memcpy(buf_addr, line_addr, size); buf_addr += size; } } free(image->fd_addr); /* convert image line in temp into current device raster format */ if ((new1_addr = (char *) calloc(1, new_size)) == NULL) return (FALSE); dev_form.fd_addr = new1_addr; vr_trnfm(x_handle, &tmp, &dev_form); free(new_addr); /* change image description */ image->fd_stand = 0; /* device format */ image->fd_addr = new1_addr; image->fd_nplanes = planes; return (TRUE); } int transform_img(MFDB *image) { /* return FALSE if transform_img fails */ int success; long size; if (!image->fd_addr) return (FALSE); size = (long) ((long) image->fd_wdwidth * (long) image->fd_h); success = convert( image, size); /* Use vr_trfm(), which needs quite a lot memory. */ if (success) return (TRUE); /* else show_error(ERR_ALLOC); */ return (FALSE); } /* Loads & depacks IMG (0 if succeded, else error). */ /* Bitplanes are one after another in address IMG_HEADER.addr. */ int depack_img(char *name, IMG_header *pic) { int b, line, plane, width, word_aligned, opcode, patt_len, pal_size, byte_repeat, patt_repeat, scan_repeat, error = FALSE; char *pattern, *to, *endline, *puffer, sol_pat; long size; FILE *fp; if ((fp = fopen(name, "rb")) == NULL) return (ERR_FILE); setvbuf(fp, NULL, _IOLBF, BUFSIZ); /* read header info (bw & ximg) into image structure */ fread((char *) &(pic->version), 2, 8 + 3, fp); /* only 2-256 color imgs */ if (pic->planes < 1 || pic->planes > 8) { error = ERR_COLOR; goto end_depack; } /* if XIMG, read info */ if (pic->magic == XIMG && pic->paltype == 0) { pal_size = (1 << pic->planes) * 3 * 2; if ((pic->palette = (short *) calloc(1, pal_size))) { fread((char *) pic->palette, 1, pal_size, fp); } } else { pic->palette = NULL; } /* width in bytes word aliged */ word_aligned = (pic->img_w + 15) >> 4; word_aligned <<= 1; /* width byte aligned */ width = (pic->img_w + 7) >> 3; /* allocate memory for the picture */ free(pic->addr); size = (long) ((long) word_aligned * (long) pic->img_h * (long) pic->planes); /*MAR*/ /* check for header validity & malloc long... */ if (pic->length > 7 && pic->planes < 33 && pic->img_w > 0 && pic->img_h > 0) { if (!(pic->addr = (char *) calloc(1, size))) { error = ERR_ALLOC; goto end_depack; } } else { error = ERR_HEADER; goto end_depack; } patt_len = pic->pat_len; /* jump over the header and possible (XIMG) info */ fseek(fp, (long) pic->length * 2L, SEEK_SET); for (line = 0, to = pic->addr; line < pic->img_h; line += scan_repeat) { /* depack whole img */ for (plane = 0, scan_repeat = 1; plane < pic->planes; plane++) { /* depack one scan line */ puffer = to = pic->addr + (long) (line + plane * pic->img_h) * (long) word_aligned; endline = puffer + width; do { /* depack one line in one bitplane */ switch ((opcode = fgetc(fp))) { case 0: /* pattern or scan repeat */ if ((patt_repeat = fgetc(fp))) { /* repeat a pattern */ fread(to, patt_len, 1, fp); pattern = to; to += patt_len; while (--patt_repeat) { /* copy pattern */ memcpy(to, pattern, patt_len); to += patt_len; } } else { /* repeat a line */ if (fgetc(fp) == 0xFF) scan_repeat = fgetc(fp); else { error = ERR_DEPACK; goto end_depack; } } break; case 0x80: /* Literal */ byte_repeat = fgetc(fp); fread(to, byte_repeat, 1, fp); to += byte_repeat; break; default: /* Solid run */ byte_repeat = opcode & 0x7F; sol_pat = opcode & 0x80 ? 0xFF : 0x00; while (byte_repeat--) *to++ = sol_pat; } } while (to < endline); if (to == endline) { /* ensure that lines aren't repeated past the end of the img */ if (line + scan_repeat > pic->img_h) scan_repeat = pic->img_h - line; /* copy line to image buffer */ if (scan_repeat > 1) { /* calculate address of a current line in a current * bitplane */ /* to=pic->addr+(long)(line+1+plane*pic->img_h)*(long)word_aligned;*/ for (b = scan_repeat - 1; b; --b) { memcpy(to, puffer, width); to += word_aligned; } } } else { error = ERR_DEPACK; goto end_depack; } } } end_depack: fclose(fp); return (error); } int half_img(MFDB *s, MFDB *d) { int pxy[8], i, j; MFDB tmp; mfdb(&tmp, NULL, s->fd_w / 2, s->fd_h, s->fd_stand, s->fd_nplanes); tmp.fd_w = s->fd_w / 2; tmp.fd_addr = calloc(1, mfdb_size(&tmp)); if (!tmp.fd_addr) return (FALSE); pxy[1] = pxy[5] = 0; pxy[3] = pxy[7] = s->fd_h - 1; for (i = 0; i < s->fd_w / 2; i++) { pxy[0] = pxy[2] = 2 * i; pxy[4] = pxy[6] = i; vro_cpyfm(x_handle, S_ONLY, pxy, s, &tmp); } pxy[0] = pxy[4] = 0; pxy[2] = pxy[6] = s->fd_w / 2 - 1; for (j = 0; j < s->fd_h / 2; j++) { pxy[1] = pxy[3] = 2 * j; pxy[5] = pxy[7] = j; vro_cpyfm(x_handle, S_ONLY, pxy, &tmp, d); } free(tmp.fd_addr); return (TRUE); } nethack-3.6.0/win/gem/tile2img.c0000664000076400007660000001036212536476415015401 0ustar paxedpaxed/* NetHack 3.6 tile2img.c $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 94/01/11 * Marvin was here Marvin 97/01/11 * */ /* #include */ #include "hack.h" #include "tile.h" #include "bitmfile.h" /* #define COLORS_IN_USE MAXCOLORMAPSIZE /* 256 colors */ #define COLORS_IN_USE 16 /* 16 colors */ extern char *FDECL(tilename, (int, int)); static void FDECL(build_ximgtile, (pixel(*) [TILE_X])); void get_color(unsigned int colind, struct RGB *rgb); void get_pixel(int x, int y, unsigned int *colind); #if COLORS_IN_USE == 16 #define MAX_X 320 /* 2 per byte, 4 bits per pixel */ #else #define MAX_X 640 #endif #define MAX_Y 1200 FILE *tibfile2; pixel tilepixels[TILE_Y][TILE_X]; char *tilefiles[] = { "..\\win\\share\\monsters.txt", "..\\win\\share\\objects.txt", "..\\win\\share\\other.txt" }; unsigned int **Bild_daten; int num_colors = 0; int tilecount; int max_tiles_in_row = 40; int tiles_in_row; int filenum; int initflag; int yoffset, xoffset; char bmpname[128]; FILE *fp; int main(argc, argv) int argc; char *argv[]; { int i; if (argc != 2) { Fprintf(stderr, "usage: tile2img outfile.img\n"); exit(EXIT_FAILURE); } else strcpy(bmpname, argv[1]); #ifdef OBSOLETE bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); if (bmpfile2 == (FILE *) 0) { Fprintf(stderr, "Unable to open output file %s\n", NETHACK_PACKED_TILEFILE); exit(EXIT_FAILURE); } #endif tilecount = 0; xoffset = yoffset = 0; initflag = 0; filenum = 0; fp = fopen(bmpname, "wb"); if (!fp) { printf("Error creating tile file %s, aborting.\n", bmpname); exit(1); } fclose(fp); Bild_daten = (unsigned int **) malloc(MAX_Y * sizeof(unsigned int *)); for (i = 0; i < MAX_Y; i++) Bild_daten[i] = (unsigned int *) malloc(MAX_X * sizeof(unsigned int)); while (filenum < 3) { if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { Fprintf(stderr, "usage: tile2img (from the util directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); exit(EXIT_FAILURE); } while (read_text_tile(tilepixels)) { build_ximgtile(tilepixels); tilecount++; xoffset += TILE_X; if (xoffset >= MAX_X) { yoffset += TILE_Y; xoffset = 0; } } (void) fclose_text_file(); ++filenum; } Fprintf(stderr, "Total of %d tiles in memory.\n", tilecount); bitmap_to_file(XIMG, MAX_X, (tilecount / 20 + 1) * 16, 372, 372, 4, 16, bmpname, get_color, get_pixel); Fprintf(stderr, "Total of %d tiles written to %s.\n", tilecount, bmpname); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } void get_color(unsigned int colind, struct RGB *rgb) { rgb->r = (1000L * (long) ColorMap[CM_RED][colind]) / 0xFF; rgb->g = (1000L * (long) ColorMap[CM_GREEN][colind]) / 0xFF; rgb->b = (1000L * (long) ColorMap[CM_BLUE][colind]) / 0xFF; } void get_pixel(int x, int y, unsigned int *colind) { *colind = Bild_daten[y][x]; } static void build_ximgtile(pixels) pixel (*pixels)[TILE_X]; { int cur_x, cur_y, cur_color; int x, y; for (cur_y = 0; cur_y < TILE_Y; cur_y++) { for (cur_x = 0; cur_x < TILE_X; cur_x++) { for (cur_color = 0; cur_color < num_colors; cur_color++) { if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r && ColorMap[CM_GREEN][cur_color] == pixels[cur_y][cur_x].g && ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b) break; } if (cur_color >= num_colors) Fprintf(stderr, "color not in colormap!\n"); y = cur_y + yoffset; x = cur_x + xoffset; Bild_daten[y][x] = cur_color; } } } nethack-3.6.0/win/gem/title.uu0000664000076400007660000006325012467321052015206 0ustar paxedpaxedbegin 777 title.img M $ .P $ $!= %T 4 R%A)34< /H ^@#Z /H &K ^@ /H ^@ M #Z /H #Z LH#Z &K CT"R@$: :L!JP+* 1H CT /H M :L (] 1H -; UL"R@/H LH"/0 _PDH*"BH!H ) ?_@'_^_ M___'A( /_#_\!__X _P#__P?__P!B@HAH )_@ ?X ! X!( / \ #^ ' M__ /\ /@ /A@>!@ ?@#_^____'@X 0W_@?^ /_\ __ ?_X!__P 8H!X ( M?\ '_Q___X.#@ ^/\ _P ?_@ ?P ?_ #_\'AX (?]_W_U___[N#@!"O]^_W M_?_O_\?S^?_?[_\_A@> "& P!@,8 #& X !V( .&!@8 8 P '@.$8# # ,' M* > "#_@ _X/__^#@X /C_ /\ #_X ?_ #_@ ?^!X> "* O^@+H "Z X / MJ!?H%_Z +_^8#>Z O_0"AP> "& P P8, #& X /S# ,, & 8 #@ Q&!P P& M!R@'@ @_X '\!___@X. #X?@!^ _\ ?_X _X '_ >'@ B@+_T%] N@. M#[0O]"_^@%__8 +N@;_T!8<'@ @P, &&# Q@. #\PP## !@& !P &Q@X , M# "- O_H7T "Z X /M"_T+_Z 7_Z (Z" M_^@7AP6 "O@ ,!X!A_P /X#@!#\/XP_@8!_ P \8/^&#_\!@B !P8 ? M #@#@ !N@O_07X<%@!U\ # ? 8?L/_S^ M?P'X_#\,/P, /@<'_#&#_&!_X 8%@ H0 ' '@ X X ', \ #P #@6 M!/P '^ &!8 *' ?]P#]Y___NX. $+?O!^\!_^X!_A_@_OP_W^ &A8 <[__0 M%_Z%]#_\NG\!^+0O]"_] "_Y!APN@O^@7X<%@!T\ # / 8?L?__^_X/__#\, M/P, /@8/_CN#^&#_P 8%@ H0 # '@ X X 0, \ #P #@ !X H ^ _ MP 8%@!T< !_[ /WGP .[@/X'M^\'[P'_[@/YX^K^^#^_P :%@!SO_] +_H7T M0 .Z@(('M"_T+_T +_H)XBZ"_Z"_AP6 "#P , \!A^Q_@X 2@__\/PP_ P ^ M!A__/X/PP/^ !@6 '1@ , > ?_#A^ /@P#P / . ?X#@#P #^ !@6 M'1P '_L _>??_+M^_OBW[P?O ?_N _?Y[O[P?[^ !H6 '.?_T O^A?1?_+M^ M@OBT+_0O_0 O^A?Y+H+_0+^'!8 ??_SI^_O\W[P?O ?_N ^_^[O[P_W\'A8 ?_[A^ /^P#P / ' !__#@#P /X'!8 <'X ?^X#]Y]__N'[^ M_[?O!^\!^_<'W_]N_O#^_@>%@!OG_] +_H7T7_^Y_H+_M"_T+_T*%_1?_VZ" M_H*(!8 ??__A^_O_W[P?O _OW M!]__KO[Q_OX'A8 ;Y__0!?Z%]%__^?Z"__0O]"_Z"A?T7_^N@OT"B 6 '#_ M, ?!A^Q___Q_@__\/PP_!@X?#/_A_X/V!_P'!8 <&\ < !X!__^'X __ / M \ < /^'. / !_ <%@!P?P!_]P/WGW__X?O[_]^\'[P/[]P>_X<[^\_W\ M!X6 &^?_T 7^A?1?__O^@O_T+_0O^@H7]+__SH+Z!8@%@!P_P# 'P8?L?@ \ M>8/P?#\,/P8>'QS_@'^#_ _\!P6 '!O ' > > #QX /!P#P / ' #^ M;@#P _P'!8 <'\ ?_<#]Y]X /'C^\'?O!^\#\_<'OX!N_O?[_ >%@!OG_] % M_H7T7____H+_]"_T+_H2%^2__^Z"] N(!8 ?> QP_O '[P?O _7W#W\ 'O[W^_@'A8 ;Y__0 OZ%]%____Z" M__0O]"_Z%1?I?__^@O0+B 6 '#_ , /!A^Q^ 1AH_ ,/_P_!A\?F?X #X/X M'_ '!8 -&\ , !X!X !& \ . # \ ! > ?@ . . '\ <%@!P?P!_^P/WG MW@ $8-[P!^ '[P/U]X]^ [^[_?P!X6 &^?_T +^A?1?___^@O_T( 0O^A47 MZ7___H+H%X@%@!P_P# #X8?L?@ 88/P#!_X/PP?#YG^ >#\#_P!P6 #1O M #@ > > !@ / #@ P/ 0#@'X !@# #_ '!8 <'\ ?_N#]Y]X &#^\ ?_ M_^\']?N/?@ &_M_O\ >%@!OG_] "_H7T7____H+_]!_X+_05"^E___Z"T"^( M!8 ?> ! GO '___O!_7[CWP M O[?[^ 'A8 ;Y__0 OZ%]%____Z"__0 "_T%0OI?__^@M OB 6 '#_ , 'A MA^Q^ !Z_ , _##\/F?P 8/@?\ '!8 (&\ & !X!X$@ 'P X &#P , M X!\!( "'\ '!8 ('\ ?_V#]Y]X#@!&6\ ?__^\'[?N/? _C_?P >%@!OG M_] !?H7T7____H+_] +_0M"^E___Z"(%^(!8 >!( !\ . !@\ #@. > 2 C^ !P6 "!_ 'O]P_>?> M X 1_O '___O!^[[GW@ /__OX 'A8 ;Y__2@7Z%]%____Z"__0 "_T+HO1 M?__^@ "_B 6 &W_ ,X#QA^Q^! !F_ , !_##^'\?@ 8 !_P@%@ @[P M, '@'@2 ? #@ 8/ X!P'@$@ %_" 6 "#_ 'O^P_>?> X 0YO '__^O!^[] MWW@ /__?PB%@!O'_]* OH7T7_O__H+_] +_0NA=%___Z 7^(@ $.!(& M&L S@/&'['X, '#\ P #\8/X?S^ !@ '_"( !#@2 "#O P > >!( ! M\ . !@\ #@' ^ 2 7\(!8 (/\ >_[#]Y]X#@!"^\ ?__^\/[OW>^ __]_ M"(6 &\?_TH"^A?1?\__^@O_T OZ"Z%TO___H !?XB (!^ !_\ SP/F' M['X\ &+\ P?^'\8?X?S^ !@ /^"( "'X #@ A[P . '@'@2 ? #@ 8/ M !X!P/@$@ '^" 6 &W_ 'G^X_>?>" ]O '__^O#][]WO@ /_^_@B%@!J' M_]) OH7T7\O__H+_]!_X+^A>A=+___Z HF 3.$@!O\ #/ P88,8?P << M#+_\,!AAAC, & 8 #@ )Y7@. 3^$@ 'X'8 "!_X#@ $,!( 5_ >?X#\ M!\ X "Z =@!^ /P/P> X($@ )__@.%@!4$ !) @(0$0#@ (( !" $( A MA!(#@ * 02 G@!@X @;X . #-@888,?\P ;\ ## ,,!AAAC, &! M@8 %@ -UP " 7^$@ & 'X ##\ @!H0?____? 'C_ _ ? ^ P@ 'X ?@ M#\#\'@."!H #?\ A( 6_G $B! A 1 R @@ $( 0@"$"$$@. H&!!H # M<#__@ %?A * &3-@888,/PP 8, #K ,82 M 7 @@ (# ( !( . %@.( !X_P/P'__@ /X !6 'H _ ?AX#@ /^?X &@ (/ M (2 %OSX !(@0(0$/P@ (( !" $( A 0A(#@ ."0( &@ (,_X2 '/X #,P M888, P ?, #+ -L!A@PS, &#X, '@ ' @ '@@ 55555^^"& 4 $@!8' M! >'\#\!__X ". =@!F /P'X> X #_C^ !X !P(2 %OF, !(00(0$ @ M (( !" $( A 0A(#@ ."(( '@ &_A( <_ ,S QA@P C !XP ,, SP-,## M,P 8-@P > 3" < #@ (=O"& 1 $@!8& @ >'^#\!_]X "> ?@!R ; M@'X> X #_C^ !X !,(2 %OL& !(0((0$ @ (( !" $(!" 0A(#@ ."(( ' M@ $OA( 6_ '_\_@_A_P)#___T__\/_T_\O_#\X. X/P?X> ?" < #@ (- M_"($@!P& __>[^[]]_;[__ZN__?O]N_=OW[>___^_M_?AX !\(2 '/L'_]+H M+H7T O__H+_]"_T+]"_0M+___Z"T%^(A( 6Z '_\_@_A_P'[___@__\?_R_ M^?_#\X. X/P?X> >" 8 #@!P)_?_ X X!\ #__X __ /\ _ /P# ___^ M , ?AX !X 2 '!(#_][O[OWW__O__O[_]Z_W;]:_?M[___[^W]^'@ '@A8 5 M!@ 2"""$! ?H "" 0@!" 0@$(2 X #@A! !X !'X& #*JJJH !__/X/Z?\ M/X. "L?__'_\__?_P_.#@ .#\'^'@ $P@ & !( ;^?_ X X!\ #__X __ / M\ _ /P# ___^ , ?AX !, & 'U5557D%_][O[MWW^!O__KK_]Z_W+]B_?M[_ M__[^W]^'@ $PA8 5C@ 2"""$!#@8 "" 0@!" 0@$(2 X #@A! !X& 5\$ M@ <#__/\/[?\A( *@__]/_X_\/_!\X. X/X/X: L7\!8 ;<__ \ 8!\ ?C M__X __ /\ _ !P! ___^ . /AH "Q?R 2"#@!S\B__>]];-]T?C__[^__;O M]>_?AW]>___^_N_OAH "Q?R%@ C\ !($$(0$0 . "H( !" $(!" 01(#@ ." M"" &@ (__X !! 2 " ?_]_R?C_Q_@X *@__]O_T_X7_A\X. \/X/X2 !/P) M__X%@!L'_\#P!@'P'_O__@#_\ _P#X $#___X X ^$@ 3\"?_^@ %[@X < M_G?_VO=V]???^__^_O_V;_;OOOA?7O___K[O[X2 !/P)__Z%@ CX !($$(0$ M0 . "H( !" $("!X01(#@ .""" $@ $#@P6 "(__^_X_E_Q_@X *S___/_^_ MZQ_I]X. YOX/X. H"?@P6 &XO_P/@& ? ?___^ /_P#_ /@ 0/___@#@ M#X. H"?@X !/X2 &X__UOO6[???___^LO_T[_1OM.>76O___N;O[X. H"? M@X6 "'0 $@(0A 1 X *@@ $( 0@( >!$@. X((( . 7^$ 8 !?X6 !?/_ M#^?]A( *Q__\/_T_?VS1\X. \/\'X> ?X!@!5____^>__ ^ (!\!____X M__ /\ \#@ = ___^ / 'AX !_H !'X. '/Y__][Z^IWV7____KK_]^_V[R"3 M+U[___Z^]_>'@ '^A8 ;A__2^@J%]%____Z"__0O]"^@ %2___^@O07B( ! M 8: !O/_G__\?X. "OO__+__?W:.>_.#@ .C_!^'@ 'X@ $!A( 1.__ _ (! M\!____X __ /\ \#@ = ___^ / 'AX !^( !#X2 &S__WOUJA???___^AO_W M;_2O*7&%7O___M[W]X> ?B%@!O'_]+]"H7T7____H+_]"_T+Z 5+___Z" M]!>(@ $'AH %\_\OK_R'@ 5__/]]](6 X/^'X> :" 0>$@!&[_\#\ @'P M'____@#_\ _P#P2"@ 3^ /@'AX !H( !!X2 &[__WOW:U?=?___^@O_TK_ :"%@!O'_]+]"H7T7____H+_]"_T+Z( )+___Z"^A>( M@ $'B( #G\_]A( *B___/_]_>?WW]X. ^?^#X: F@ @ $'A( 1F__ _@(! M\!____X __ /\ \$@H $_@#X X: F@ @ $'A( ;G__2_NJU]E____[V__3O M]*\G_@B:___^FOO[AH ": "%@!OG_]+^BH7T7____H+_]"_TKZ/\ )K___Z" M^@N(@ $#AH &]_^7__Q_@X %V___?_Z#@ +L]X2 OX/A( $[4 ( ! X2 M$=O_P/X! ? ?___^ /_P#_ /!( &?__^ /@#A( $[4 ( ! X2 &]__VO[M MA???___^IO_TK_4O0@/SF7___H+[^X2 !.U "%@!OG_]+^A87T7____H;_ M]"_U+T(#X)E___Z"^@N(@ (!^ . '#_ ,_'GU^_^ !O_ -?PW_[__^_? M ?_S3X '@ (!^ . "!O / > >!( *\ / \ _ @< . _ #@ > @'X M X ('\ >\)LMY%X#@!'"\ :O!B]2_!&K< @O&[@ >%@!OG_]+^@P7T7___ M_L+_]"_T+T+\$*E___Z"_0N( 8 !X . '#_ /_#5G^]^ !@_ ,/P[_U__Z M__ ??S3X ' 8 !X . "!O / > >!( *\ / \ _\ @< . _ !@ %@!OG_]+_0 7T M7____M[_]*_T+V+_T*E___Z"_06(!8 %@!OG_]+_0 7T7__]_NK_]"_T M;T+_TDE___Z"_06(!8 %@!OG_]+_H 7T7__]_IK_]&_U;T+_T4M___Z" M_H6(!8 @O""P >%@!OG_]+_H 7U7__Y_J;_]._U+M7_ZDE___Z"_H*(!8 % M@!OG_]+_T 7W7__Y_H[_]B_V+L7_[%:___Z2_H*(!8 %@!SG_]+_T 7T M7__U_O;_]:_U;HW_[-2___:2_T%_AP6 '#_ -_ V[^[^ XAB_ /OPS_K_ 8 M?O@ ">_P]> '!8 6&\ \ !X!X " \ / X!\ 0. . _ 8 <%@!P? MP!KP&17E7@ $(/;P!&\'+M7P#]6X "2\$M@!X6 '.?_TO_0%?1?__7^]O_T M;_4NU?_N5;__]H+_07^'!8 9S_#[ MX <%@!8;P #P '@'@ ( #P \ #@'P 8 X #\ !@!P6 '!_ $O +5>1> M P@MO 'KP?N[? *IM@ ++P16 'A8 O]^[E_^JF MW__FDO]!?X<%@!P_P#?P'=?O_@ V89/P##\,/R_@&O_X !G'\'7P!P6 %AO M / > > !@ / #P , ^ "!@#@ /P # '!8 <'\ :\ HMY%X '&#N\ ?O M!^W;X TJ6 NO JL >%@!SG_]+_Z@WT7__=_N[_]^_W[=O_[2I?_^::_ZB_ MAP6 '#_ /_ /M^U^ .9AP_ ,/PP^#^ ,?WP .?_P?_ '!8 6&\ \ !X!X M & \ / @#X (' . _ , <%@!P?P!+P!$WFW@ \8+[P!^\'Z_O@!ZK< M !""\""P!X6 '.?_TO_T3?;?_SW^OO_W[_?K^__WJM__UH+_H+^'!8 => /S@_W /]P_W^^ 'Z^P ,.+P(+@' MA8 <[__6__5=]U_\_?[_?^_W[_?[__ > #@ ' P > # 0# M@ /P !@'!8 <'\ 2\ *EY]X#_.#_< _[#__]X ?M] !@WO 96 >%@!SO_]+_ M^J7WWP/]_O]_[_OO__W_]^WW_V[>_]!?AP6 '/O /_ &!^S__ ?C ? __S__ M_^ , ! !X $!( #\ 8!P6 M'+O $O #_>=0__WA_[ < 0 /> 'U?@ X/[P$=@'A8 '@ X$!@0& \ !@2 _ ' <%@!S[P!KP ?WG MS__]X?X /\ _P# #_;^ <#N\!3 #-K__?WWS__]_?X/@X. "\#_[_;^ M =[N_]1?AP6 ' / ,_ #!^PP ?G__ _P#_?\ __\'^8Z/P'_P'!8 < \ M\ !X > !\ #_ /]_P ' " / # <%@!P#P![P ?WG___]X@'P /\ M_W_ ?=__\+>\ @L!X> "MK__?WW___]^@&'@ G!]W__WM[_Z"^'!8 < \ _ M\ ,'[ #__\?^ '_@?__P '_< #'@_ ;/ <%@!P#P #P '@ !X!_X ?^! M___ , 8 \ ,!P6 ' / $O !_>?___G@'_@!_X'__\ &S__AO[P#.P' MAX )TO_]_??___G@B( )_AN__[[^_^QOAP6 ' ? ,_ !A^P ?__@'_@!_\'_ M_^ _SX#CX/P#_X'!8 "-[__OWW__P'BH ( MX<__?O[_]"^'!8 <#X _\ &'[ ___^ __ /_X___X '_O_\?@_ .W@<%@!P/ M@ #P '@ /_X#_\ __C___@ ?^P !X \ &!P6 ' ^ $O _>?_@__@/_P# M_^/__^ !_['\'O[P!38'AX 'TO_^_??_@XR !_'\_O[_]#>'!8 &#X S\ #' MA( 2X#__!\ /P ?^?__\#\ Q^!P6 ' ^ / > ?__@/_\'P _ ! M_YX#^ #P 8'!8 <#X >\ !][_!__^ __P? #\ '_G@/Y_O 'E@>'@ ?6 M__]][_!_C( '_@/Y_O_WEX<'@ 0W\ #'A( #X'_@!H ) _^/__\!\ 9?!PB M"O > /___@?^ &@ D#_X__\ !P <'!X +&O ?>P/___@?^ &@ D#_X__ M]_]P [<'AX &VO__?>P/CX %]_]_^[>'!X %,_ 9_R#@ +A\ B "!_'___! M\ :O!PB !/ <"#@ +A\ B "!_'_^ < #!P> !1[P #W @X "X? (@ @? MQ__@_W #6P>'@ 7>__^]PY" !>#_?_M;AP> !3/P '_@@X !@ F " 'C__CY M\ 8/!PB !/ <"#@ & "8 ( >/_^ P ,'!X %'O .<"#@ & "8 ( >/_ M^ >P _L'AX %WO__N=^1@ 0'O_O[AP> "#/P #_@___ #(& !O ?\ 8O@ 8( M@ ?P ?@___ #(& !O 0$ #@ 8'@ @>\ 'X/__P R!@ ;P$% #VX &AX $ MWO__QY* !/!?^]N'!X '8? #^'_^ V !Q_ ?_ &!X &"( &< /X?_X#8 ' M'\!_@ !@ 8'@ <_< /X?_X#8 ''\!_@ /]@ :'@ *_?Y6 X_[_8<'@ 9@ M\ /X?\0@8 $^ P'@ 8(@ 40 _A_Q"!@ 3X & !@> !C^0 _A_Q"!@ 3X M!_V !H> K^?EH "]_V'!X &8'@ !^/ #X & ?_X?P? !@J P?CP ^ !@'_ M^ !P 8'@ 8_X 'X\ /@ 8!__@/_< &AX "O^>6@ */_8<'@ 7!_ 'XA& M!0_\#\/ !@J @?B$8 %#_P , &!X %?^ !^(1@ 4/_ #^P :'@ )_XY: M O#^AP> !<_P . $H $_@#[P 8(@ 00 . $H $_@ P 8'@ 5^$ #@!* M!/X /L &AX "?A^7@ $^AP: P&_^!6 ! < ?^ &!X " ?@5@ 0' $!@!@> M O'X%8 $!P!'8 :&@ +^\9B L=_A@: P/W_A>!@ '@!@> @?^%X "^" & M!H # P?_@!6 M @?^!P: ! ('_X 5@ ('_@>&@ +Z/YB OX?A@: ! X/_\ 6@8 !\ 8'@ ,/ M_\ 6@8 !P 8'@ ,/_\ 6@8 !P :&@ 'QFH !SX8'@ (/_A> @_P!@> @_^ M%X "#_ &!X "#_X7@ (/\ :H!X "'^ 7@ (#^ 8'@ (?X!> @/X!@> A_@ M%X " _@&J > 3\9@ %\!@> 3\9@ %\!@> 3\9@ %\!J@'@ %\&8 !'@8' M@ %\&8 !'@8'@ %\&8 !'@:H!X !X!F 0,&!X !X!F 0,&!X !X!F 0,& MJ"@H'8 !. JH*"@<@ (!_@JH"X "'X #@ (#P!8+@ '\!( " \ %@ '\$ N M > $@ (#P 6 ?P$@ (#_PJ+@ +\?X. OP_E@N A^ X "#/ 6"H " _P$ M@ (/\ 2 @'^$ J @/@!( "#_ $@ (#_P2 P/_@ F+@ +\?X. O /E@N M A_ X "&?@6"H "!_P$@ (?^ 6 ?P0"H "!^ $@ (?^ 2 P?_@ . P?_ M@ F+@ +\/X. N 'E@J P?^0 . A/X%@J @_@!( "'_@%@ '\!8 !_ H* M@ $(!8 "'_@$@ ,'_X #@ ,'_X )BX "X;^#@ +@!Y8*@ ('_@2 B?\%@J M A_@!( "/_P$@ (!_@6 ?P*"H !& 6 C_\!( #!_^ X #!_^ "8N >&$ M@ + Y8*@ (/_ 2 B_\%@J A_P!( "/_P$@ (!_@2 @'^"@J 1 %@ (_ M_ 2 P?_@ . P?_@ F+@ 'SA( "P .%@ $SA8 !,XH*@ (/_ 2 C_\!8 ! M9 6 :@*"H "/_@$@ (__ 2 P??@ . @'>"@J C?@!( "/_P$@ ,'WX # M@ ,'WX )BX !^X2 L #A8 !=X6 ;N*"H "'_P$@ (YG 6 2 %@ $@"@J M C_X!( ".9P$@ (#WP2 @'>"@J B?P!( "/_P$@ ,#WX #@ ,'WX )BX ! M^X2 L #E@J AZ\!( "/_P%@ $@!8 !( H*@ (^N 2 C_\!( " ]\$@ (! MW@H*@ (O\ 2 C_\!( " ]\$@ ,'WX )BX !^X2 L9CE@J AUO 2 AB(!8 !> 6 7@*"H "/K@$@ (?^ 2 @&&!( " M 88*"H "+_ $@ (7> 2 @&'!( #/X?@"8N ?N$@ +O]X6 8>%@ &'B@J M A_\!( "*!06"H "/_@$@ (O] 6 ?P%@ '\"@J BO0!( "+_0%@ '^!( # M/__P"8N ?N$@ +7ZY8*@ ([W 2 @O0!( # P. X $ 08 < @*@ (_^ 2 M @PP!( # P. !( #? !P" J @PP!( "## %@ '\!( $/OWP< B+@ '[A( " M_#^*@ /X_'^)"H ".]P$@ (($ 2 ! >'P#@#@ -^#_@("H "/#@$@ (/\ 2 M! >'@#@#@ -\#_@("H "## $@ (/\ 6 "7@ . /_W_^ B*@ +\.XR ;^# M@ /X_'^)"H "/#P$@ (,, 2 "@__X/P 0$#_X("H "/_ $@ (/\ 2 ! O_ M@/P$@ (/_@@*@ (+T 2 @_P!X '_ ._O__@B+@ 'SBH #^_^?@X "^'B* M"H 6/_\/_ !^ !^ '__]_@ '@#__@@*@!8_\P_\ '__X'X 8 W^ M 8 _^" J "@PS#_P ?__@?@$@ @-_@ ?\/_@B+@ 'S@X $_@?@?X. M _@ #X. _@!#XD*@ T__[_^ #__X?\ _@P* !#\!__\("H 6/^.__@ ' M___G_ ,_\'_P . /_P@*@ H'X[_^ ?__^?\!( "!_\#@ /^#_\(BX ! MXX. !/@'X!^#@ /S_P>#@ /X @^)"H !/X,!@ @"__]O_ ?X,"@ 1_P___ M" J %C@'__\ !O__;_P &/_!_\ & !_\("X ) ___ ;__V_\!( "!_\# M@ ,\!_\(BX !YX. !/D#P)^#@ /C_P>#@ /@ >)"H !#X. "8 #?_[__ M^X,"A @)@!__?_\ #Z___^ #_\___" F %P/_^#__@ ^__?_\ #8_@'^ #/X /_ M" F $0,8 #__@ ^__?_\ # '^ X #% /_"(N "/@____P0 (/@X #V_X! M@X #S_0#B0F %P'G'__[@ ??^__\ 'Z___X '_\__^" F %P?_X!_[@ _? M^__\ ' _$'X '/X '^" F $088X!_[@ _?^__\ # $'X X #% '^"(N M". ?___P( 0/@X #P_Q!@X #S_0!B0F %P/P'__Q@ >O=?_X '#/^/@ ![ M]_G\" F %P__X _Q@ ^O]?_X ' ''W@ '; .?\" F %PP/X _Q@ ^O]?_X M # 'W@ &8]^?\"(N #N /___QT N/___YPQQ]@X #W_?GB0F %P_\/__@ M _7<__X 8_W_'X C /'\" F %P__P _@ _7\__X ' #'_X 'C /_\ M" J %@/ #^ #]?S__@ !__@?_@ > __P(BX (P ____'H#X^$@ +L?X0! MB@F 0^#@!/ _7\__P "'_/\ #D//\" F %P__^@_ _7\__P #@ M#'_\ ##@/_\" J %D "#\ #]?S__ ./@?_P ,!W__P(BX (^@____'H M#X^#@ +[[(6 ?>*"8 7",?_'^ , ##\ +___P 'R__P("8 +#__[ M[^ #\ #_\ #@ D(?_P '@__P("8 7!_@#[^ #\ #_\ , ?_P (5 M__P(BX "^^^)@ /[SW^$@ 'UB@J %L__#^ "/'#^ +___@ (1__@( M"8 +#__C_^ #R/'_^ $@ A_^ @'_^ @)@! #3@ __ MG^/ ?O_^ #@H '^ _/_^ @'@!H@ 8_Z__CP 7[__@ #_'_X # MX/_X' <'@!,&' 8P __@ 7[__@ # '_X X #%/_X"(N !^O__#__Z!>% M@ +\?X2 !/3___>'!X -. '___[_ ]__X ."@ ?X #\__X" > &B M #_C_^_P #O?_^ /\/_@ /@?_C\!P> $P<\ " #_^ #O?_^ , M/_@#@ ,4?_@(BX 'X__QC__$(X6 OP_A( $]'__(X<'@ 0X /@X &^ , M/__ X* !_@ 'S__@(!X :( ?^O___@ /#__P !_P_^ _!_^_P' M!X 9!_P < /_X /#__P !P _^ @Q_^ B+@ ?K_^!'_\/#A8 "_#^$ M@ 3\?_PGAP> &3 #__\]_X !O[^\ '__[@ '__S@(!X :( ?^/S MW_@ ._O[P #_X?N _P_/_P'!X 9#_P 0 /SP ._O[P\ #@ ?O^ M @ _. B+@ ?C_^!'_\6'A8 "_A^$@ 3\/_@?AP> &3 #__\]WX ?[^\ M ?__S@( '__B (!X :( __WSW_@ )_O[P #_\/. @ !_X>/_ '!X 9 M#_P P 'SP@ )_O[S_ " //_@ !@ >( B+@ ?]_^H7_]F'AH !#X2 !/X? MX!^'!X 9, ?__YV)@ '[?YQ40 "__^)P0 __^( @'@!H@ '_\?G?^ _ MM_G ! ?_PX@! /_PX__ <&@!H(#_P1@ 'YQV /[?YVKP % ../P # . M( B+@ ?Q_^=G_\/+AH !#X6 P_@/X<&@ !_X /^_\"PN " !#'^ !@ !@F+@ +Z?X. @/ AH !AX6 X?!^X<&@!D/ M__P#___X 0 _[_P#!$ +__\& $ #___"0: &P& ___+@?_ '_O_ 0!_ M_\0 0!__\$__ <(@!<#_ .!F< ?^_\'/O % !&?_ ' 0F+@ C\O_N_ M_@/ ?X6 <>%@ /!P:.'!H 9!\ !?__\ -$ ?\_\$ %___ @#___PD& M@ T!P ?__T0'_P!_S_P X +?__H " ___PO_T'!X :/__Z 0&MP!_S_P M/_\ ( __^ P @ $'BX (_1____X#P'^%@ 'KA8 #\, #AP> "#?\!___ M ")$!( %0 " !_\$@ 4/_^" 0<'@ @P ?__P ?^ 2 #A_X@ ?_ !_X __ MX/__!P> 7@%@ (]N 2 ";__@ ?__@ . L [!Y^ D ZAP> DSD!( " M 8(&@ & !8 &0 /@ "$!P> 4 %@ (^?@2 S_\@ . "#_\0 /@'_^!P: M P'S& 2 CY^!( )\\^ !\\_ X "7WH'AX "_.>6@ +1QX<'@ *Q* 6 M 0($@ ,-,( #@ ,-,$ #@ (@0 <'@ *MS 2 C_^!( #/_R X #/_Q X " M<<8'!X "[]P$@ (__@2 ">RW@ >RWP . ENN!X> OWOEH "\<>'!X " M4" $@ (GY 2 P(@@ . T(@0 2 40'!X "3]P$@ (X' 2 S_<@ . S_< M0 . G_^!P> N_-@ +X'YD'@ &P M!8 ", P$@ ."@( #@ /"@$ #@ )@!@<'@ *O_ 2 B_T!( #/_R X #/_Q M X "?_X'!H # >_\!( "+_0$@ E__X $__\ #@ )__@>?@ *__8<'@ ,1 M! P#@ 0,, #@!( '@ L 0 . !# D X%!X ##O@, X )>]X X '_B M X #/_Q X $/]P #@4'@ ,N^ P#@ ][W@#@ #__X $__\ #@ 0OW . M!8> ?Z8@ '?AP> "ACP#A@ &?D _@#@ P /@4'@ H' M" X8 &?^X/X X " 8 #@ )\/@2 !!X< #X%!X 5!P@.& !__^#^ ?_^ M !?#_P X $'A0 /@6(@ $/D( "_#^$@ +^'X<'@!0, ]\ &#R ?X !# MR8'\ +'X@2 !!@,!'X%!X * _ /? "?_?G^ . !P&!_ >!X$@ 0?_ 1^ M!0> %0/P#WP ___Y_@ #PW@?P 7@?\ . !!?\!'X%DX "_#^$@ +X'XT' M@!P&( ?^ (!D _\ "@P/\ +%8@/P ,/ S^!0> ' ' !_X !?_O[_P M :C _P 'U^ _ _\#/X%!X < < '_@ '___O_ /K\#_ !?7_S\ M"]P,_@63@ +^OX2 OU_C0: !0'__ __ X 5@ _\ @0 !_^ +CQ _X . M< _\!0: !P'V( __ ^#@!/\ _!P__^ #\/$_X __ _\!0> ' 8CC_\ M#_]___P !^__[_X #?P___@ 6@#_P%F8 "_#^$@ +'XX<&@!T#__P?_P " M !/^ $ 0'_@ D P'_ #_ /_ 4&@ <##R ?_P /@X 3^ ?X ?__@ ( M'_Q/_ __\/_ 4'@!P&(]__ W__[_X !_O__O^ ]____\ #'XP_\!9^ M L?CAP: '0?__!__ $ @(?X 0# /^ "8& /\ #P!_\!0: !P8#P!__ M !^#@!/X #_P#__^ #P?^._\ '__Y_\!0> # /#__\ 'O]_?_@ /X. #?X M/W____P !A_@ #^ !_ 2 C_X!0: !PP __@!^#@ /P '^#@ G^ 'X/X'_\ M .#@ 'X!0> 0>#@!B '_Z___ ?W__G_X ?_?___P \ #__@%GX "P!^' M!H =#_P"#__@$>(G#\ !X P?P C_@0?P % */_H%!H '"$ "#__@'X. M#\ ?7____P ?C@ ?_P X. ?H%!X !0X. &. .W=OWP !X?_\__ !]P!^_ M_ #T O_^@6?@ +0'X<&@!T/]@,/^> 3\ ^?X #@ '!_ #_^'!_ \ \? M_@4'@ ;P P_YX!^#@ /@ '^#@ G\ '_X ?_\ >#@ '^!0> ',G___G@#>_W M;^ ??__O_P ?< ?O_P !_ /__X%GX "\#^'!H =#_,#C_@ ?"/W^ > # M@?P !__CX?P / /'_X%!H ' ? #C_@ #X. #^ ?_OO__P ?_@#__P !X. M ?X%!H = < ?G_P !_ /__X%GX "\#^'!H = M#_&#C_@ ? /C_ &? #D_@ 0?_C@_@ _ /W_@%!H ' ? #C_@ #X. #_ M/^____@ ?_@#__@ !X. ?@%!H ' /\ 0__D/^ !_^.#^ T \?X 4& M@!T/L /_\ /X ?_\ ?X '_^ _^ /_^ 'W___X 4&@!T/CS__\ /_Q__ M\ /@ ?W^ _P!__^ 'T __X 6?@ +P?X<'@!8P&(!X 6,#^/ M\ !P..'\ __,/^ !_^./^ . P,_P 4&@!T., /_\ ?X ?_\ /\ /_ M^ /^ /_^ #/___P 4&@!T.#\/_\ ?_Q__\ /P __^ /P!__^ # /_ MP 6?@ '#B > !# ?__ #@ \#A^ #_CG^ #_C_^ #@ .#_< %!X <, /_ M\ >, __X #. /_X . /_X /__]P 4'@! /X__P !X____@ , '__@ M X #'__@ X #@_W !9^ <>(!X $, /]\ . %0./P /^/_X /^/_X M "@___? M#C___\ #@ ,?_^ #@ D?_^ '#^< %GX !QX@'@ 00!_G X 5!__ ? MX__ _X__ !P_' !0> '! '^< #Y__\ #@'_\ #@#_\ #__ M\< %!X 0#__YP /_O_P (!__P . "1__P '!_[ M\< "&'\\ /#\< /#_< '#\\ %!X <'_OQP /__SP /__Q MP /__]P /__SP 4'@!P/__' ?^_/ ___' ___W !P_/ M!9^ <>(!X <$<)QP (8?SP \/QP \/YP ' __\< !_[\\ #__\< M #__^< '#\\ %GX !QX@'@!SYP!A #P_' #P_# #P_# ! MP_& !0> ' ' &$ #__\< #__\, #__\, #__\8 %!X &!H 6 8$ " ?\?\ _]_^ _]_ M^ . U\:X 8'@!5_/'@ '?&_ -7:O@ -7:O@#@ -;"N &J : ! &! M!^ #@ .G!7 #@ .I%3 #@ .I%3 #@ ,& . &!H " 8$$@! !_Q_P #_W_P M #_W_P X #_A_@!@> %7\X$ 5\:\ U=J\ U=J\ . _X?X :H M #_ B@H**@/@ '@#H " > (#X !X Z @_@" ^ > .@ (/^ B>@ +P!X@. M@ (!\ . 3X*@ (#P @.@ (!\ Z C_ " Z @'P X " ? )@ (_\ B>@ + M#X@.@ (!\ . 7 *@ (/P @.@ (!\ Z G_ " Z @'P X "#_@)@ )_X B> M@ * 'X@.@ ("X . 6 *@ %_"0Z @+@#H$)#H " ^ #@ (?^ F!@ '@")X! M@ $?B B R 0 . C^@ X !8 6 ?P$@ %^"0Z C^@"8 !_ . @'^"0B M R 0 . C_@ X "'_@(@ ,!_^ (F8 ! X. _X 'X@(@ -@ & #@8 !P . M 6 $@ ,'_X #@0D.@8 !P B !P?_@ ?\)"( #8 !@ X& < #@ (?^ B M P'_P B8@ CX '____X /X@(@ AP & '_P . 6 $@ ,.+\ #@8 !@ @- M@ ,!_\ (@ @.+\ /_@ @(@ AP & '_P . A_X"( # __ "(J 7^- M@ CP #____Q^/X@(@ H__N /_X !@X +_@ $/_@ !_X (#8 # __@ M"( ($/_@ #_X ("( (/X;@ #_^ -@ ,#_\ (B( "O@:.@ C@ !____Q_ M/X@(@ A__^ ?_\ B "!?NX >N " J !B ?_\ B "!?NX ^N M" B "G\#X !__P .$!X # __ "(B _P#WXV ". '____/\_B B "#__ MP !__P"( (/__P !U8 ("H &0 !__P"( (/__P #U8 ("( */@' M '__ 8. ?X'@ ,#_\ (B( #^ &_C8 (P /___\_S^("( "#_\#@ @. M ' '__P. ""@ \ >N " V P__\ . A;1 X (+__P #ZX ("( ! M# 2 P__\ 2 0$#@ ('_P. P/_P B(@ +P (B _X6T8. ",?_#____/\_ MB B @__ X (# P !XQX#@ AQ2G '_@ @-@ ,/__ #@ )_^@. "'XQ M\ _^ " B 0@$@ ,/__ #@ ( #O< /_ :8@ @'_X____S_/X@(@ (((0. P0 ( . #PA$ M8 N !P #_[#__@8(@ (&<@. P?_X . #W>\8 O__P #_[#__@8( M@ ('W@. P?_X . #W>\8 !_^ #P_#__@:(@ +^_@X (!_^/ M___\_S^("( ""#$#@ ,"'$ #@ ]'B?P8 ;1X\ _\[__X&"( "!_X#@ ,# MX\ #@ ]X>?P8 ;>'\ _\[__X&"( "!\X#@ ,#X\ #@ =X>?P8 .' X % M __[__X&CH !XX2 #?A____^ X ( M 'X /X #@X ,_@ ( !@X .OX #\#__@#'_G__ M #^#@ ' !HF #Q____X ?@!___P/P/__^(6 \ X@(@ 4&9@& (2 $=@% MG_G__@XX_X'_ !Y\ ?^ !@B "P>> 8 #P _]@'@X ,_@X _ '_ '[^ ?^ M!@B !0>> 8 A( -V /P'_^ # 8 $ ___P84#B F &/ _^ ?__C_P #_-!_^>@// M ?^ __X _ <(@ L____X .0 )__ 'X. "_Y[X ?_X#__@#\!PB %3____@ MY__G_\ ? /__@'\,/__@(. ?P'B( (P/ ____D "># 8 $ ___@84#B B M&7 '__PG! Y_\ #Y_\?_]X;SV'_@!_^,/X'"( %0_P?__"$@ + 'X2 "M_X M '__@/_^-_X'"( !#X. $?!O__;_P!\ ___@>PP__^ @X !_@>(@ +P (. M _P /X,!@ 0#__^AA8 #^ WB B &? #__@GBBY_\ #YO\?_\X;CF'_@!/\ M./X'"( %@?@/_^"$@ + 'X2 "L_X '__@//\/_X'"( !#X. %>!O__;_P!\ M ___@>1Q__^ \____@>(@ +P (. _P /X,!@ 4#__^Q]X2 _P /X@'@!H! M\ G_P ,1##_@ .?SQ__GCP \?^ _YX_P<)@ 3P!_\ A( "@!^$@ J?_ #_ M_X#C_G__!PB !0__W_\ A( (@!\ ___@<>#@ * XX,'B( "\ "#@ /\ #^# M 8 % ___X>>$@ /\ '^(!X : _@!V_\ #((P_X !FX!__^ P8,'B( "^ &#@ /\ #^# 8 % ___^>^$@ /^ '^(!X : _P#^_X M#1%P_X #^?\?\8P^ ?'_ #^?_X'"( %? /C_@"$@ * 'X. "_&-_@'__P ! M_G_^!PB !7__Y_X A( (@!\ __Q@<># 8 $ ?___@>(@ +\ X. _P /X,! M@ 4#___SYX2 _X ?X@'@!H#_ /__@ . +#_@ /_]Q_P #ZD\?P 'P_[@<( M@ 5\ ^/^ (2 H ?@X +\ '^ /_\ '\/^X'"( %?__C_@"$@!" 'X '__ ! M]UO__ !___N!XB OP#@X #_ _@X "@ >#@ 'WA( #_@ _B B !@__P_X M X,"@ Y@!__@ #7^__@ /Z_[@<'@ 4#R!'__@. C__ X -!__@ #0 __@ M _Z_[@<'@!H#R '__@ #@#__ ?___@ 8!__@ ___[@>)@ 'O@X #_ _ MB( !SX2 _P /X@)@!@XP_P ____@ 8 ?_X '___X '^/\P'!X % \ X M__P#@ (__@. #0?_X $ /_X /^/\P'!X : \_'__P X(__@ '___X $ M /_X /__\P'B8 !QX. _P /XV _P /X@)@!@8X_@ ]___@ 8 ?_P # MMW_X #^O\ '!X % X 8__@#@ (__@. #0?_P ,'_X ?^O\ '!X : X_G M__@ Z(__@ '___P $>/_X ?__\ 'B8 !YX. _P@/XV _@ /X@(@!@/ MQ__P /?_YP #,'YX ![-^. #_C\("( 8" #_\ '#^< !##^> P M?C@ !_X_" F %SC_\ #OC^< !/_^> !\_C@ !___"(V _P\/XV _@ M/X@(@!@/S__P /__YP ,'YX ![M^> #_]\("( 8" #_\ '#^< !_ M_^> X?G@ #__?" F %S#_\ #GC^< !__^> !\_G@ #___"(V _P< M/XV _ 'X@(@!D/___ /__YP ,'XX !7A^> '_Q^ !PF &&#_P M'#^< !__^. +Y?G@ '_\?@ <)@!A@_\ YX_G ?__C@ "__YX !__ M_X 'C8 #_!P_C8 #X ?B B "#___P '___ X # P#@ X (<'XP !?_I\ ' M"8 "\#\#@!,\!P ___X !W/^, !__Z? !PF &/ _ ?__\ /__^ M ?W_C ?___P >-@ /@/ >-@ . >("( (?\_\ ?\_\#@ ,# . #@ A@ M'@ /__+P <)@ + ' . $S ' #___@ ?Y_X /__R\ '"8 4P!P !_S M_P ___X '^?^ "#@ ' !XV ^ \!XT"@ $#B B "'_'_ '_'_ X # M#@#@ X '8 X %__T0@(@ ,!P!P#@!)P!P _X_X /^?^ /__]$("( 5 M < < ?\?\ /^/^ #_G_@ #@PB-@ /@?@>,@ 3\ !B!V W__\ @= 4@ -___ ('8 #?__P")V X #X@ end nethack-3.6.0/win/gem/wingem.c0000664000076400007660000010660512536476415015161 0ustar paxedpaxed/* NetHack 3.6 wingem.c $NHDT-Date: 1433806613 2015/06/08 23:36:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* Copyright (c) Christian Bressler, 1999 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "func_tab.h" #include "dlb.h" #include #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef GEM_GRAPHICS #include "wingem.h" static char nullstr[] = "", winpanicstr[] = "Bad window id %d"; static int curr_status_line; static char *FDECL(copy_of, (const char *)); static void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ extern int mar_set_tile_mode(int); extern void mar_set_font(int, const char *, int); extern void mar_set_margin(int); extern void mar_set_msg_visible(int); extern void mar_set_status_align(int); extern void mar_set_msg_align(int); extern void mar_set_tilefile(char *); extern void mar_set_tilex(int); extern void mar_set_tiley(int); extern short glyph2tile[MAX_GLYPH]; /* from tile.c */ extern void mar_display_nhwindow(winid); /* from wingem1.c */ void Gem_outrip(winid, int, time_t); void Gem_preference_update(const char *); /* Interface definition, for windows.c */ struct window_procs Gem_procs = { "Gem", WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_FONTSIZ_MAP | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT | WC_ASCII_MAP, 0L, Gem_init_nhwindows, Gem_player_selection, Gem_askname, Gem_get_nh_event, Gem_exit_nhwindows, Gem_suspend_nhwindows, Gem_resume_nhwindows, Gem_create_nhwindow, Gem_clear_nhwindow, Gem_display_nhwindow, Gem_destroy_nhwindow, Gem_curs, Gem_putstr, genl_putmixed, Gem_display_file, Gem_start_menu, Gem_add_menu, Gem_end_menu, Gem_select_menu, genl_message_menu, Gem_update_inventory, Gem_mark_synch, Gem_wait_synch, #ifdef CLIPPING Gem_cliparound, #endif #ifdef POSITIONBAR Gem_update_positionbar, #endif Gem_print_glyph, Gem_raw_print, Gem_raw_print_bold, Gem_nhgetch, Gem_nh_poskey, Gem_nhbell, Gem_doprev_message, Gem_yn_function, Gem_getlin, Gem_get_ext_cmd, Gem_number_pad, Gem_delay_output, #ifdef CHANGE_COLOR /* the Mac uses a palette device */ Gem_change_color, #ifdef MAC Gem_change_background, Gem_set_font_name, #endif Gem_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ Gem_start_screen, Gem_end_screen, Gem_outrip, Gem_preference_update, genl_getmsghistory, genl_putmsghistory #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif genl_can_suspend_no, }; #ifdef MAC void * Gem_change_background(dummy) int dummy; { } short * Gem_set_font_name(foo, bar) winid foo; char *bar; { } #endif /*************************** Proceduren *************************************/ int mar_hp_query(void) { if (Upolyd) return (u.mh ? u.mhmax / u.mh : -1); return (u.uhp ? u.uhpmax / u.uhp : -1); } int mar_iflags_numpad() { return (iflags.num_pad ? 1 : 0); } int mar_get_msg_history() { return (iflags.msg_history); } int mar_get_msg_visible() { return (iflags.wc_vary_msgcount); } /* clean up and quit */ static void bail(mesg) const char *mesg; { clearlocks(); Gem_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } /*$$$*/ #define DEF_CLIPAROUND_MARGIN -1 #ifndef TILE_X #define TILE_X 16 #endif #define TILE_Y 16 #define TILES_PER_LINE 20 #define NHFONT_DEFAULT_SIZE 10 #define NHFONT_SIZE_MIN 3 #define NHFONT_SIZE_MAX 20 /*$$$*/ /*ARGSUSED*/ void Gem_init_nhwindows(argcp, argv) int *argcp; char **argv; { argv = argv, argcp = argcp; colors_changed = TRUE; set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE, DISP_IN_GAME); set_wc_option_mod_status( WC_HILITE_PET | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_MAP | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_MAP | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, SET_IN_GAME); if (iflags.wc_align_message == 0) iflags.wc_align_message = ALIGN_TOP; if (iflags.wc_align_status == 0) iflags.wc_align_status = ALIGN_BOTTOM; if (iflags.wc_scroll_margin == 0) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; if (iflags.wc_tile_width == 0) iflags.wc_tile_width = TILE_X; if (iflags.wc_tile_height == 0) iflags.wc_tile_height = TILE_Y; if (iflags.wc_tile_file && *iflags.wc_tile_file) mar_set_tilefile(iflags.wc_tile_file); if (iflags.wc_vary_msgcount == 0) iflags.wc_vary_msgcount = 3; mar_set_tile_mode( !iflags.wc_ascii_map); /* MAR -- 17.Mar 2002 True is tiles */ mar_set_tilex(iflags.wc_tile_width); mar_set_tiley(iflags.wc_tile_height); mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM); mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM); if (mar_gem_init() == 0) { bail((char *) 0); /*NOTREACHED*/ } iflags.window_inited = TRUE; CO = 80; /* MAR -- whatsoever */ LI = 25; add_menu_cmd_alias(' ', MENU_NEXT_PAGE); mar_set_no_glyph(NO_GLYPH); } void Gem_player_selection() { int i, k, n; char pick4u = 'n', pbuf[QBUFSZ], lastch = 0, currch; winid win; anything any; menu_item *selected = NULL; /* avoid unnecessary prompts further down */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { /* pick4u = yn_function("Shall I pick a character for you? * [ynq]",ynqchars,'n');*/ pick4u = yn_function(build_plselection_prompt( pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign), ynqchars, 'n'); if (pick4u == 'q') { give_up: /* Just quit */ if (selected) free((genericptr_t) selected); bail((char *) 0); /*NOTREACHED*/ return; } } /* Select a role, if necessary */ if (flags.initrole < 0) { /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { mar_add_message("Incompatible role!"); mar_display_nhwindow(WIN_MESSAGE); flags.initrole = randrole(); } } else { /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ currch = lowc(roles[i].name.m[0]); if (currch == lastch) currch = highc(currch); add_menu(win, roles[i].malenum, &any, currch, 0, ATR_NONE, an(roles[i].name.m), MENU_UNSELECTED); lastch = currch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole() + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); end_menu(win, "Pick a role"); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { mar_add_message("Incompatible race!"); mar_display_nhwindow(WIN_MESSAGE); flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", roles[flags.initrole].name.m); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { mar_add_message("Incompatible gender!"); mar_display_nhwindow(WIN_MESSAGE); flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s %s", races[flags.initrace].adj, roles[flags.initrole].name.m); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { mar_add_message("Incompatible alignment!"); mar_display_nhwindow(WIN_MESSAGE); flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s %s %s", genders[flags.initgend].adj, races[flags.initrace].adj, (flags.initgend && roles[flags.initrole].name.f) ? roles[flags.initrole].name.f : roles[flags.initrole].name.m); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ return; } /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting pl_character. * Always called after init_nhwindows() and before display_gamewindows(). */ void Gem_askname() { strncpy(plname, mar_ask_name(), PL_NSIZ); } void Gem_get_nh_event() { } void Gem_suspend_nhwindows(str) const char *str; { const char *foo; foo = str; /* MAR -- And the compiler whines no more ... */ } void Gem_resume_nhwindows() { } void Gem_end_screen() { } void Gem_start_screen() { } extern void mar_exit_nhwindows(void); extern boolean run_from_desktop; void Gem_exit_nhwindows(str) const char *str; { if (str) Gem_raw_print(str); mar_exit_nhwindows(); if (iflags.toptenwin) run_from_desktop = FALSE; iflags.window_inited = 0; } winid Gem_create_nhwindow(type) int type; { winid newid; switch (type) { case NHW_MESSAGE: if (iflags.msg_history < 20) iflags.msg_history = 20; else if (iflags.msg_history > 60) iflags.msg_history = 60; break; case NHW_STATUS: case NHW_MAP: case NHW_MENU: case NHW_TEXT: break; default: panic("Tried to create window type %d\n", (int) type); return WIN_ERR; } newid = mar_create_window(type); if (newid == MAXWIN) { panic("No window slots!"); /* NOTREACHED */ } return newid; } void Gem_nhbell() { if (flags.silent) return; putchar('\007'); fflush(stdout); } extern void mar_clear_map(void); void Gem_clear_nhwindow(window) winid window; { if (window == WIN_ERR) panic(winpanicstr, window); switch (mar_hol_win_type(window)) { case NHW_MESSAGE: mar_clear_messagewin(); break; case NHW_MAP: mar_clear_map(); break; case NHW_STATUS: case NHW_MENU: case NHW_TEXT: break; } } extern void mar_more(void); /*ARGSUSED*/ void Gem_display_nhwindow(window, blocking) winid window; boolean blocking; { if (window == WIN_ERR) panic(winpanicstr, window); mar_display_nhwindow(window); switch (mar_hol_win_type(window)) { case NHW_MESSAGE: if (blocking) mar_more(); break; case NHW_MAP: if (blocking) Gem_display_nhwindow(WIN_MESSAGE, TRUE); break; case NHW_STATUS: case NHW_TEXT: case NHW_MENU: default: break; } } void Gem_destroy_nhwindow(window) winid window; { if (window == WIN_ERR) /* MAR -- test existence */ panic(winpanicstr, window); mar_destroy_nhwindow(window); } extern void mar_curs(int, int); /* mar_curs is only for map */ void Gem_curs(window, x, y) winid window; register int x, y; { if (window == WIN_ERR) /* MAR -- test existence */ panic(winpanicstr, window); if (window == WIN_MAP) mar_curs(x - 1, y); /*$$$*/ else if (window == WIN_STATUS) curr_status_line = y; } extern void mar_add_status_str(const char *, int); extern void mar_putstr_text(winid, int, const char *); void Gem_putstr(window, attr, str) winid window; int attr; const char *str; { int win_type; if (window == WIN_ERR) { Gem_raw_print(str); return; } if (str == (const char *) 0) return; switch ((win_type = mar_hol_win_type(window))) { case NHW_MESSAGE: mar_add_message(str); break; case NHW_STATUS: mar_status_dirty(); mar_add_status_str(str, curr_status_line); if (curr_status_line) mar_display_nhwindow(WIN_STATUS); break; case NHW_MAP: if (strcmp(str, ".")) Gem_putstr(WIN_MESSAGE, 0, str); else mar_map_curs_weiter(); mar_display_nhwindow(WIN_MESSAGE); mar_display_nhwindow(WIN_STATUS); break; case NHW_MENU: mar_change_menu_2_text(window); /* Fallthru */ case NHW_TEXT: mar_putstr_text(window, attr, str); break; } /* endswitch win_type */ } void Gem_display_file(fname, complain) const char *fname; boolean complain; { dlb *f; char buf[BUFSZ]; char *cr; f = dlb_fopen(fname, "r"); if (!f) { if (complain) pline("Cannot open \"%s\".", fname); } else { winid datawin; datawin = Gem_create_nhwindow(NHW_TEXT); while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; if (index(buf, '\t') != 0) (void) tabexpand(buf); Gem_putstr(datawin, 0, buf); } (void) dlb_fclose(f); Gem_display_nhwindow(datawin, FALSE); Gem_destroy_nhwindow(datawin); } } /*ARGSUSED*/ /* * Add a menu item to the beginning of the menu list. This list is reversed * later. */ void Gem_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; /* window to use, must be of type NHW_MENU */ int glyph; /* glyph to display with item (unused) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like Gem_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { Gem_menu_item *G_item; const char *newstr; char buf[QBUFSZ]; if (str == (const char *) 0) return; if (window == WIN_ERR) /* MAR -- test existence */ panic(winpanicstr, window); if (identifier->a_void) Sprintf(buf, "%c - %s", ch ? ch : '?', str); else Sprintf(buf, "%s", str); newstr = buf; G_item = (Gem_menu_item *) alloc(sizeof(Gem_menu_item)); G_item->Gmi_identifier = (long) identifier->a_void; G_item->Gmi_glyph = glyph != NO_GLYPH ? glyph2tile[glyph] : NO_GLYPH; G_item->Gmi_count = -1L; G_item->Gmi_selected = preselected ? 1 : 0; G_item->Gmi_accelerator = ch; G_item->Gmi_groupacc = gch; G_item->Gmi_attr = attr; G_item->Gmi_str = copy_of(newstr); mar_add_menu(window, G_item); } /* * End a menu in this window, window must a type NHW_MENU. * We assign the keyboard accelerators as needed. */ void Gem_end_menu(window, prompt) winid window; /* menu to use */ const char *prompt; /* prompt to for menu */ { if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU) panic(winpanicstr, window); /* Reverse the list so that items are in correct order. */ mar_reverse_menu(); /* Put the prompt at the beginning of the menu. */ mar_set_menu_title(prompt); mar_set_accelerators(); } int Gem_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { Gem_menu_item *Gmit; menu_item *mi; int n; if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU) panic(winpanicstr, window); *menu_list = (menu_item *) 0; mar_set_menu_type(how); Gem_display_nhwindow(window, TRUE); for (n = 0, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next) if (Gmit->Gmi_selected) n++; if (n > 0) { *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); for (mi = *menu_list, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next) if (Gmit->Gmi_selected) { mi->item = (anything)(genericptr_t) Gmit->Gmi_identifier; mi->count = Gmit->Gmi_count; mi++; } } return n; } void Gem_update_inventory() { } void Gem_mark_synch() { mar_display_nhwindow(WIN_MESSAGE); mar_display_nhwindow(WIN_MAP); mar_display_nhwindow(WIN_STATUS); } void Gem_wait_synch() { mar_display_nhwindow(WIN_MESSAGE); mar_display_nhwindow(WIN_MAP); mar_display_nhwindow(WIN_STATUS); } #ifdef CLIPPING extern void mar_cliparound(void); void Gem_cliparound(x, y) int x, y; { mar_curs(x - 1, y); mar_cliparound(); } #endif /* CLIPPING */ /* * Gem_print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void mar_print_gl_char(winid, xchar, xchar, int); extern int mar_set_rogue(int); extern void mar_add_pet_sign(winid, int, int); void Gem_print_glyph(window, x, y, glyph, bkglyph) winid window; xchar x, y; int glyph, bkglyph; { /* Move the cursor. */ Gem_curs(window, x, y); mar_set_rogue(Is_rogue_level(&u.uz) ? TRUE : FALSE); x--; /* MAR -- because x ranges from 1 to COLNO */ if (mar_set_tile_mode(-1)) { mar_print_glyph(window, x, y, glyph2tile[glyph], glyph2tile[bkglyph]); if ( #ifdef TEXTCOLOR iflags.hilite_pet && #endif glyph_is_pet(glyph)) mar_add_pet_sign(window, x, y); } else mar_print_gl_char(window, x, y, glyph); } void mar_print_char(winid, xchar, xchar, char, int); void mar_print_gl_char(window, x, y, glyph) winid window; xchar x, y; int glyph; { int ch; int color; unsigned special; /* map glyph to character and color */ (void) mapglyph(glyph, &ch, &color, &special, x, y); #ifdef TEXTCOLOR /* Turn off color if rogue level. */ if (Is_rogue_level(&u.uz)) color = NO_COLOR; #endif /* TEXTCOLOR */ mar_print_char(window, x, y, ch, color); } extern void mar_raw_print(const char *); extern void mar_raw_print_bold(const char *); void Gem_raw_print(str) const char *str; { if (str && *str) { if (iflags.window_inited) mar_raw_print(str); else printf("%s\n", str); } } void Gem_raw_print_bold(str) const char *str; { if (str && *str) { if (iflags.window_inited) mar_raw_print_bold(str); else printf("%s\n", str); } } extern void mar_update_value(void); /* wingem1.c */ int Gem_nhgetch() { int i; mar_update_value(); i = tgetch(); if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ return i; } /* Get a extended command in windowport specific way. returns index of the ext_cmd or -1. called after '#'. It's a menu with all the possibilities. */ int Gem_get_ext_cmd() { winid wind; int i, count, what, too_much = FALSE; menu_item *selected = NULL; anything any; char accelerator = 0, tmp_acc = 0; const char *ptr; wind = Gem_create_nhwindow(NHW_MENU); Gem_start_menu(wind); for (i = 0; (ptr = extcmdlist[i].ef_txt); i++) { any.a_int = i; accelerator = *ptr; if (tmp_acc == accelerator) { if (too_much) accelerator = '&'; /* MAR -- poor choice, anyone? */ else accelerator += 'A' - 'a'; too_much = TRUE; } else too_much = FALSE; tmp_acc = *ptr; Gem_add_menu(wind, NO_GLYPH, &any, accelerator, 0, ATR_NONE, ptr, FALSE); } Gem_end_menu(wind, "What extended command?"); count = Gem_select_menu(wind, PICK_ONE, &selected); what = count ? selected->item.a_int : -1; if (selected) free(selected); Gem_destroy_nhwindow(wind); return (what); } void Gem_number_pad(state) int state; { state = state; } void win_Gem_init() { } #ifdef POSITIONBAR void Gem_update_positionbar(posbar) char *posbar; { } #endif /** Gem_outrip **/ void mar_set_text_to_rip(winid); char **rip_line = 0; void Gem_outrip(w, how, when) winid w; int how; time_t when; { /* Code from X11 windowport */ #define STONE_LINE_LEN 15 /* # chars that fit on one line */ #define NAME_LINE 0 /* line # for player name */ #define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ #define YEAR_LINE 6 /* line # for year */ char buf[BUFSZ]; char *dpx; int line; long year; if (!rip_line) { int i; rip_line = (char **) malloc((YEAR_LINE + 1) * sizeof(char *)); for (i = 0; i < YEAR_LINE + 1; i++) { rip_line[i] = (char *) malloc((STONE_LINE_LEN + 1) * sizeof(char)); } } /* Follows same algorithm as genl_outrip() */ /* Put name on stone */ Sprintf(rip_line[NAME_LINE], "%s", plname); /* Put $ on stone */ Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money); /* Put together death description */ formatkiller(buf, sizeof buf, how); /* Put death type on stone */ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { register int i, i0; char tmpchar; if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if (dpx[i] == ' ') i0 = i; if (!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; strcpy(rip_line[line], dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx = &dpx[i0]; } else dpx = &dpx[i0 + 1]; } /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(rip_line[YEAR_LINE], "%4ld", year); mar_set_text_to_rip(w); for (line = 0; line < 13; line++) putstr(w, 0, ""); } void mar_get_font(type, p_fname, psize) int type; char **p_fname; int *psize; { switch (type) { case NHW_MESSAGE: *p_fname = iflags.wc_font_message; *psize = iflags.wc_fontsiz_message; break; case NHW_MAP: *p_fname = iflags.wc_font_map; *psize = iflags.wc_fontsiz_map; break; case NHW_STATUS: *p_fname = iflags.wc_font_status; *psize = iflags.wc_fontsiz_status; break; case NHW_MENU: *p_fname = iflags.wc_font_menu; *psize = iflags.wc_fontsiz_menu; break; case NHW_TEXT: *p_fname = iflags.wc_font_text; *psize = iflags.wc_fontsiz_text; break; default: break; } } void Gem_preference_update(pref) const char *pref; { if (stricmp(pref, "font_message") == 0 || stricmp(pref, "font_size_message") == 0) { if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_MESSAGE, iflags.wc_font_message, iflags.wc_fontsiz_message); return; } if (stricmp(pref, "font_map") == 0 || stricmp(pref, "font_size_map") == 0) { if (iflags.wc_fontsiz_map < NHFONT_SIZE_MIN || iflags.wc_fontsiz_map > NHFONT_SIZE_MAX) iflags.wc_fontsiz_map = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_MAP, iflags.wc_font_map, iflags.wc_fontsiz_map); return; } if (stricmp(pref, "font_status") == 0 || stricmp(pref, "font_size_status") == 0) { if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_STATUS, iflags.wc_font_status, iflags.wc_fontsiz_status); return; } if (stricmp(pref, "font_menu") == 0 || stricmp(pref, "font_size_menu") == 0) { if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_MENU, iflags.wc_font_menu, iflags.wc_fontsiz_menu); return; } if (stricmp(pref, "font_text") == 0 || stricmp(pref, "font_size_text") == 0) { if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_TEXT, iflags.wc_font_text, iflags.wc_fontsiz_text); return; } if (stricmp(pref, "scroll_margin") == 0) { mar_set_margin(iflags.wc_scroll_margin); Gem_cliparound(u.ux, u.uy); return; } if (stricmp(pref, "ascii_map") == 0) { mar_set_tile_mode(!iflags.wc_ascii_map); doredraw(); return; } if (stricmp(pref, "hilite_pet") == 0) { /* MAR -- works without doing something here. */ return; } if (stricmp(pref, "align_message") == 0) { mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM); return; } if (stricmp(pref, "align_status") == 0) { mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM); return; } if (stricmp(pref, "vary_msgcount") == 0) { mar_set_msg_visible(iflags.wc_vary_msgcount); return; } } /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in X11/winmenu.c. */ static char * copy_of(s) const char *s; { if (!s) s = nullstr; return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); } #endif /* GEM_GRAPHICS \ \ /*wingem.c*/ nethack-3.6.0/win/gem/wingem1.c0000664000076400007660000030237412536476415015243 0ustar paxedpaxed/* NetHack 3.6 wingem1.c $NHDT-Date: 1433806613 2015/06/08 23:36:53 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Christian Bressler 1999 */ /* NetHack may be freely redistributed. See license for details. */ #define __TCC_COMPAT__ #include #include #include #include #include #include #include #include "gem_rsc.h" #include "load_img.h" #include "gr_rect.h" #define genericptr_t void * typedef signed char schar; #include "wintype.h" #undef genericptr_t #define NDECL(f) f(void) #define FDECL(f, p) f p #define CHAR_P char #define SCHAR_P schar #define UCHAR_P uchar #define XCHAR_P xchar #define SHORT_P short #define BOOLEAN_P boolean #define ALIGNTYP_P aligntyp typedef signed char xchar; #include "wingem.h" #undef CHAR_P #undef SCHAR_P #undef UCHAR_P #undef XCHAR_P #undef SHORT_P #undef BOOLEAN_P #undef ALIGNTYP_P #undef NDECL #undef FDECL static char nullstr[] = "", md[] = "NetHack 3.6.0", strCancel[] = "Cancel", strOk[] = "Ok", strText[] = "Text"; extern winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN; #define MAXWIN 20 #define ROWNO 21 #define COLNO 80 #define MSGLEN 100 #define MAP_GADGETS \ NAME | MOVER | CLOSER | FULLER | LFARROW | RTARROW | UPARROW | DNARROW \ | VSLIDE | HSLIDE | SIZER | SMALLER #define DIALOG_MODE AUTO_DIAL | MODAL | NO_ICONIFY /* * Keyboard translation tables. */ #define C(c) (0x1f & (c)) #define M(c) (0x80 | (c)) #define KEYPADLO 0x61 #define KEYPADHI 0x71 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { { C('['), 'Q', C('[') }, /* UNDO */ { '?', '/', '?' }, /* HELP */ { '(', 'a', '(' }, /* ( */ { ')', 'w', ')' }, /* ) */ { '/', '/', '/' }, /* / */ { C('p'), '$', C('p') }, /* * */ { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'h', 'H', C('h') }, /* 4 */ { '.', '.', '.' }, { 'l', 'L', C('l') }, /* 6 */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[PADKEYS] = { { C('['), 'Q', C('[') }, /* UNDO */ { '?', '/', '?' }, /* HELP */ { '(', 'a', '(' }, /* ( */ { ')', 'w', ')' }, /* ) */ { '/', '/', '/' }, /* / */ { C('p'), '$', C('p') }, /* * */ { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { '4', M('4'), '4' }, /* 4 */ { '.', '.', '.' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }; #define TBUFSZ 300 #define BUFSZ 256 extern int yn_number; /* from decl.c */ extern char toplines[TBUFSZ]; /* from decl.c */ extern char mapped_menu_cmds[]; /* from options.c */ extern int mar_iflags_numpad(void); /* from wingem.c */ extern void Gem_raw_print(const char *); /* from wingem.c */ extern int mar_hp_query(void); /* from wingem.c */ extern int mar_get_msg_history(void); /* from wingem.c */ extern int mar_get_msg_visible(void); /* from wingem.c */ extern void mar_get_font(int, char **, int *); /* from wingem.c */ extern int vdi2dev4[]; /* from load_img.c */ void recalc_msg_win(GRECT *); void recalc_status_win(GRECT *); void calc_std_winplace(int, GRECT *); int (*v_mtext)(int, int, int, char *); static int no_glyph; /* the int indicating there is no glyph */ IMG_header tile_image, titel_image, rip_image; MFDB Tile_bilder, Map_bild, Titel_bild, Rip_bild, Black_bild, Pet_Mark, FontCol_Bild; static int Tile_width = 16, Tile_heigth = 16, Tiles_per_line = 20; char *Tilefile = NULL; /* pet_mark Design by Warwick Allison warwick@troll.no */ static int pet_mark_data[] = { 0x0000, 0x3600, 0x7F00, 0x7F00, 0x3E00, 0x1C00, 0x0800 }; static short *normal_palette = NULL; static struct gw { WIN *gw_window; int gw_type, gw_dirty; GRECT gw_place; } Gem_nhwindow[MAXWIN]; typedef struct { int id; int size; int cw, ch; int prop; } NHGEM_FONT; /*struct gemmapdata {*/ GRECT dirty_map_area = { COLNO - 1, ROWNO, 0, 0 }; int map_cursx = 0, map_cursy = 0, curs_col = WHITE; int draw_cursor = TRUE, scroll_margin = -1; NHGEM_FONT map_font; SCROLL scroll_map; char **map_glyphs = NULL; dirty_rect *dr_map; /*};*/ /*struct gemstatusdata{*/ char **status_line; int Anz_status_lines, status_w, status_align = FALSE; NHGEM_FONT status_font; dirty_rect *dr_stat; /*};*/ /*struct gemmessagedata{*/ int mar_message_pause = TRUE; int mar_esc_pressed = FALSE; int messages_pro_zug = 0; char **message_line; int *message_age; int msg_pos = 0, msg_max = 0, msg_anz = 0, msg_width = 0, msg_vis = 3, msg_align = TRUE; NHGEM_FONT msg_font; dirty_rect *dr_msg; /*};*/ /*struct geminvdata {*/ SCROLL scroll_menu; Gem_menu_item *invent_list; int Anz_inv_lines = 0, Inv_breite = 16; NHGEM_FONT menu_font; int Inv_how; /*};*/ /*struct gemtextdata{*/ char **text_lines; int Anz_text_lines = 0, text_width; NHGEM_FONT text_font; int use_rip = FALSE; extern char **rip_line; /*};*/ static OBJECT *zz_oblist[NHICON + 1]; MITEM scroll_keys[] = { /* menu, key, state, mode, msg */ { FAIL, key(CTRLLEFT, 0), K_CTRL, PAGE_LEFT, FAIL }, { FAIL, key(CTRLRIGHT, 0), K_CTRL, PAGE_RIGHT, FAIL }, { FAIL, key(SCANUP, 0), K_SHIFT, PAGE_UP, FAIL }, { FAIL, key(SCANDOWN, 0), K_SHIFT, PAGE_DOWN, FAIL }, { FAIL, key(SCANLEFT, 0), 0, LINE_LEFT, FAIL }, { FAIL, key(SCANRIGHT, 0), 0, LINE_RIGHT, FAIL }, { FAIL, key(SCANUP, 0), 0, LINE_UP, FAIL }, { FAIL, key(SCANDOWN, 0), 0, LINE_DOWN, FAIL }, { FAIL, key(SCANLEFT, 0), K_SHIFT, LINE_START, FAIL }, { FAIL, key(SCANRIGHT, 0), K_SHIFT, LINE_END, FAIL }, { FAIL, key(SCANUP, 0), K_CTRL, WIN_START, FAIL }, { FAIL, key(SCANDOWN, 0), K_CTRL, WIN_END, FAIL }, { FAIL, key(SCANHOME, 0), K_SHIFT, WIN_END, FAIL }, { FAIL, key(SCANHOME, 0), 0, WIN_START, FAIL } }; #define SCROLL_KEYS 14 static DIAINFO *Inv_dialog; #define null_free(ptr) free(ptr), (ptr) = NULL #define test_free(ptr) \ if (ptr) \ null_free(ptr) static char *Menu_title = NULL; void mar_display_nhwindow(winid); void mar_check_hilight_status(void) { } /* to be filled :-) */ static char *mar_copy_of(const char *); extern void panic(const char *, ...); void * m_alloc(size_t amt) { void *ptr; ptr = malloc(amt); if (!ptr) panic("Memory allocation failure; cannot get %lu bytes", amt); return (ptr); } void mar_clear_messagewin(void) { int i, *ptr = message_age; if (WIN_MESSAGE == WIN_ERR) return; for (i = msg_anz; --i >= 0; ptr++) { if (*ptr) Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; *ptr = FALSE; } mar_message_pause = FALSE; mar_display_nhwindow(WIN_MESSAGE); } void clipbrd_save(void *data, int cnt, boolean append, boolean is_inv) { char path[MAX_PATH], *text, *crlf = "\r\n"; long handle; int i; if (data && cnt > 0 && scrp_path(path, "scrap.txt") && (handle = append ? Fopen(path, 1) : Fcreate(path, 0)) > 0) { if (append) Fseek(0L, (int) handle, SEEK_END); if (is_inv) { Gem_menu_item *it = (Gem_menu_item *) data; for (; it; it = it->Gmi_next) { text = it->Gmi_str; Fwrite((int) handle, strlen(text), text); Fwrite((int) handle, 2L, crlf); } } else { for (i = 0; i < cnt; i++) { text = ((char **) data)[i] + 1; Fwrite((int) handle, strlen(text), text); Fwrite((int) handle, 2L, crlf); } } Fclose((int) handle); scrp_changed(SCF_TEXT, 0x2e545854l); /* .TXT */ } } void move_win(WIN *z_win) { GRECT frame = desk; v_set_mode(MD_XOR); v_set_line(BLACK, 1, 1, 0, 0); frame.g_w <<= 1, frame.g_h <<= 1; if (graf_rt_dragbox(FALSE, &z_win->curr, &frame, &z_win->curr.g_x, &z_win->curr.g_y, NULL)) window_size(z_win, &z_win->curr); else window_top(z_win); } void message_handler(int x, int y) { switch (objc_find(zz_oblist[MSGWIN], ROOT, MAX_DEPTH, x, y)) { case UPMSG: if (msg_pos > msg_vis - 1) { msg_pos--; Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; mar_display_nhwindow(WIN_MESSAGE); } Event_Timer(50, 0, TRUE); break; case DNMSG: if (msg_pos < msg_max) { msg_pos++; Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; mar_display_nhwindow(WIN_MESSAGE); } Event_Timer(50, 0, TRUE); break; case GRABMSGWIN: default: move_win(Gem_nhwindow[WIN_MESSAGE].gw_window); break; case -1: break; } } int mar_ob_mapcenter(OBJECT *p_obj) { WIN *p_w = WIN_MAP != WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL; if (p_obj && p_w) { p_obj->ob_x = p_w->work.g_x + p_w->work.g_w / 2 - p_obj->ob_width / 2; p_obj->ob_y = p_w->work.g_y + p_w->work.g_h / 2 - p_obj->ob_height / 2; return (DIA_LASTPOS); } return (DIA_CENTERED); } /****************************** set_no_glyph * *************************************/ void mar_set_no_glyph(ng) int ng; { no_glyph = ng; } void mar_set_tilefile(name) char *name; { Tilefile = name; } void mar_set_tilex(value) int value; { Min(&value, 32); Max(&value, 1); Tile_width = value; } void mar_set_tiley(value) int value; { Min(&value, 32); Max(&value, 1); Tile_heigth = value; } /****************************** userdef_draw * *************************************/ void rearrange_windows(void); void mar_set_status_align(int sa) { if (status_align != sa) { status_align = sa; rearrange_windows(); } } void mar_set_msg_align(int ma) { if (msg_align != ma) { msg_align = ma; rearrange_windows(); } } void mar_set_msg_visible(int mv) { if (mv != msg_vis) { Max(&mv, 1); Min(&mv, min(msg_anz, 20)); Min(&mv, desk.g_h / msg_font.ch / 2); msg_vis = mv; rearrange_windows(); } } /* size<0 cellheight; size>0 points */ void mar_set_fontbyid(int type, int id, int size) { int chardim[4]; if (id <= 0) id = ibm_font_id; if ((size > -3 && size < 3) || size < -20 || size > 20) size = -ibm_font; /* MAR -- 17.Mar 2002 For now allow FNT_PROP only with NHW_TEXT */ if (type != NHW_TEXT && (FontInfo(id)->type & (FNT_PROP | FNT_ASCII))) id = ibm_font_id; switch (type) { case NHW_MESSAGE: if (msg_font.size == -size && msg_font.id == id) break; msg_font.size = -size; msg_font.id = id; msg_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); v_set_text(msg_font.id, msg_font.size, BLACK, 0, 0, chardim); msg_font.ch = chardim[3] ? chardim[3] : 1; msg_font.cw = chardim[2] ? chardim[2] : 1; msg_width = min(max_w / msg_font.cw - 3, MSGLEN); rearrange_windows(); break; case NHW_MAP: if (map_font.size != -size || map_font.id != id) { MFDB mtmp; map_font.size = -size; map_font.id = id; map_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); v_set_text(map_font.id, map_font.size, BLACK, 0, 0, chardim); map_font.ch = chardim[3] ? chardim[3] : 1; map_font.cw = chardim[2] ? chardim[2] : 1; mfdb(&mtmp, NULL, (COLNO - 1) * map_font.cw, ROWNO * map_font.ch, 0, planes); if (mfdb_size(&mtmp) > mfdb_size(&FontCol_Bild) && mfdb_size(&mtmp) > mfdb_size(&Map_bild)) { FontCol_Bild.fd_addr = Map_bild.fd_addr = (int *) realloc(Map_bild.fd_addr, mfdb_size(&mtmp)); if (!Map_bild.fd_addr) /* FIXME -- Not really neccessary since the former space is still valid */ panic("Not enough Space for the map."); } mfdb(&FontCol_Bild, FontCol_Bild.fd_addr, (COLNO - 1) * map_font.cw, ROWNO * map_font.ch, 0, planes); rearrange_windows(); } break; case NHW_STATUS: if (status_font.size == -size && status_font.id == id) break; status_font.size = -size; status_font.id = id; status_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); v_set_text(status_font.id, status_font.size, BLACK, 0, 0, chardim); status_font.ch = chardim[3] ? chardim[3] : 1; status_font.cw = chardim[2] ? chardim[2] : 1; rearrange_windows(); break; case NHW_MENU: if (menu_font.size == -size && menu_font.id == id) break; menu_font.size = -size; menu_font.id = id; menu_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); v_set_text(menu_font.id, menu_font.size, BLACK, 0, 0, chardim); menu_font.ch = chardim[3] ? chardim[3] : 1; menu_font.cw = chardim[2] ? chardim[2] : 1; break; case NHW_TEXT: if (text_font.size == -size && text_font.id == id) break; text_font.size = -size; text_font.id = id; text_font.prop = FontInfo(id)->type & (FNT_PROP | FNT_ASCII); v_set_text(text_font.id, text_font.size, BLACK, 0, 0, chardim); text_font.ch = chardim[3] ? chardim[3] : 1; text_font.cw = chardim[2] ? chardim[2] : 1; break; default: break; } } void mar_set_font(int type, const char *font_name, int size) { int id = 0; /* MAR -- 17.Mar 2002 usual Gem behavior, use the Font-ID */ if (font_name && *font_name) { id = atoi(font_name); if (id <= 0) { int i, tid; char name[32]; for (i = fonts_loaded; --i >= 0;) { tid = vqt_name(x_handle, i, name); if (!stricmp(name, font_name)) { id = tid; break; } } } } mar_set_fontbyid(type, id, size); } void rearrange_windows(void) { GRECT area; int todo = TRUE; if (WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window) { scroll_map.px_hline = mar_set_tile_mode(FAIL) ? Tile_width : map_font.cw; scroll_map.px_vline = mar_set_tile_mode(FAIL) ? Tile_heigth : map_font.ch; if (todo) { calc_std_winplace(FAIL, &area); todo = FALSE; } calc_std_winplace(NHW_MAP, &area); Gem_nhwindow[WIN_MAP].gw_window->max.g_w = area.g_w; Gem_nhwindow[WIN_MAP].gw_window->max.g_h = area.g_h; Gem_nhwindow[WIN_MAP].gw_window->max.g_w = area.g_w; window_reinit(Gem_nhwindow[WIN_MAP].gw_window, md, md, NULL, FALSE, FALSE); { int buf[8]; buf[3] = K_CTRL; buf[4] = C('L'); AvSendMsg(ap_id, AV_SENDKEY, buf); } } if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) { if (todo) { calc_std_winplace(FAIL, &area); todo = FALSE; } calc_std_winplace(NHW_MESSAGE, &area); Gem_nhwindow[WIN_MESSAGE].gw_window->min_h = area.g_h; window_size(Gem_nhwindow[WIN_MESSAGE].gw_window, &area); redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window, NULL); } if (WIN_STATUS != WIN_ERR && Gem_nhwindow[WIN_STATUS].gw_window) { if (todo) { calc_std_winplace(FAIL, &area); todo = FALSE; } calc_std_winplace(NHW_STATUS, &area); Gem_nhwindow[WIN_STATUS].gw_window->min_h = area.g_h; window_size(Gem_nhwindow[WIN_STATUS].gw_window, &area); redraw_window(Gem_nhwindow[WIN_STATUS].gw_window, NULL); } } void my_color_area(GRECT *area, int col) { int pxy[4]; v_set_fill(col, 1, IP_SOLID, 0); rc_grect_to_array(area, pxy); v_bar(x_handle, pxy); } void my_clear_area(GRECT *area) { my_color_area(area, WHITE); } int mar_set_tile_mode(int); static void win_draw_map(int first, WIN *win, GRECT *area) { int pla[8], w = area->g_w - 1, h = area->g_h - 1; int i, x, y; GRECT back = *area; first = first; if (!mar_set_tile_mode(FAIL)) { int start = (area->g_x - win->work.g_x) / map_font.cw + scroll_map.hpos; int stop = (area->g_x + area->g_w + map_font.cw - 1 - win->work.g_x) / map_font.cw + scroll_map.hpos; int starty = (area->g_y - win->work.g_y) / map_font.ch + scroll_map.vpos; int stopy = min((area->g_y + area->g_h + map_font.ch - 1 - win->work.g_y) / map_font.ch + scroll_map.vpos, ROWNO); char tmp; v_set_text(map_font.id, map_font.size, WHITE, 0, 0, NULL); v_set_mode(MD_TRANS); x = win->work.g_x - scroll_map.px_hpos + start * map_font.cw; y = win->work.g_y - scroll_map.px_vpos + starty * map_font.ch; pla[2] = pla[0] = scroll_map.px_hpos + area->g_x - win->work.g_x; pla[3] = pla[1] = starty * map_font.ch; pla[2] += w; pla[3] += map_font.ch - 1; pla[6] = pla[4] = area->g_x; /* x_wert to */ pla[7] = pla[5] = y; /* y_wert to */ pla[6] += w; pla[7] += map_font.ch - 1; back.g_h = map_font.ch; for (i = starty; i < stopy; i++, y += map_font.ch, pla[1] += map_font.ch, pla[3] += map_font.ch, pla[5] += map_font.ch, pla[7] += map_font.ch) { back.g_y = y; my_color_area(&back, BLACK); tmp = map_glyphs[i][stop]; map_glyphs[i][stop] = 0; (*v_mtext)(x_handle, x, y, &map_glyphs[i][start]); map_glyphs[i][stop] = tmp; vro_cpyfm(x_handle, S_OR_D, pla, &FontCol_Bild, screen); } } else { v_set_mode(MD_REPLACE); pla[2] = pla[0] = scroll_map.px_hpos + area->g_x - win->work.g_x; pla[3] = pla[1] = scroll_map.px_vpos + area->g_y - win->work.g_y; pla[2] += w; pla[3] += h; pla[6] = pla[4] = area->g_x; /* x_wert to */ pla[7] = pla[5] = area->g_y; /* y_wert to */ pla[6] += w; pla[7] += h; vro_cpyfm(x_handle, S_ONLY, pla, &Map_bild, screen); } if (draw_cursor) { v_set_line(curs_col, 1, 1, 0, 0); pla[0] = pla[2] = win->work.g_x + scroll_map.px_hline * (map_cursx - scroll_map.hpos); pla[1] = pla[3] = win->work.g_y + scroll_map.px_vline * (map_cursy - scroll_map.vpos); pla[2] += scroll_map.px_hline - 1; pla[3] += scroll_map.px_vline - 1; v_rect(pla[0], pla[1], pla[2], pla[3]); } } static int draw_titel(PARMBLK *pb) { static int pla[8]; GRECT work = *(GRECT *) &pb->pb_x; if (rc_intersect((GRECT *) &pb->pb_xc, &work)) { pla[0] = pla[1] = 0; pla[2] = pb->pb_w - 1; pla[3] = pb->pb_h - 1; pla[6] = pla[4] = pb->pb_x; /* x_wert to */ pla[7] = pla[5] = pb->pb_y; /* y_wert to */ pla[6] += pb->pb_w - 1; pla[7] += pb->pb_h - 1; vro_cpyfm(x_handle, S_ONLY, pla, &Titel_bild, screen); } return (0); } static int draw_lines(PARMBLK *pb) { GRECT area = *(GRECT *) &pb->pb_x; if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { char **ptr; int x = pb->pb_x, y = pb->pb_y, start_line = (area.g_y - y); v_set_mode((text_font.cw & 7) == 0 && text_font.prop == 0 ? MD_REPLACE : MD_TRANS); /* void v_set_text(int font,int height,int color,int effect,int * rotate,int out[4]) */ v_set_text(text_font.id, text_font.size, BLACK, 0, 0, NULL); start_line /= text_font.ch; y += start_line * text_font.ch; x -= (int) scroll_menu.px_hpos; ptr = &text_lines[start_line += scroll_menu.vpos]; start_line = min((area.g_y - y + area.g_h + text_font.ch - 1) / text_font.ch, Anz_text_lines - start_line); area.g_h = text_font.ch; Vsync(); /* x=(x+7) & ~7;*/ for (; --start_line >= 0; y += text_font.ch) { area.g_y = y; my_clear_area(&area); if (**ptr - 1) { v_set_text(FAIL, 0, BLUE, 0x01, 0, NULL); (*v_mtext)(x_handle, x, y, (*ptr++) + 1); v_set_text(FAIL, 0, BLACK, 0x00, 0, NULL); } else (*v_mtext)(x_handle, x, y, (*ptr++) + 1); } } return (0); } static int draw_rip(PARMBLK *pb) { GRECT area = *(GRECT *) &pb->pb_x; if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { char **ptr; int x = pb->pb_x, y = pb->pb_y, start_line = (area.g_y - y), chardim[4], pla[8], i; v_set_mode(MD_REPLACE); /* void v_set_text(int font,int height,int color,int effect,int * rotate,int out[4]) */ v_set_text(text_font.id, text_font.size, BLACK, 0, 0, chardim); start_line /= text_font.ch; y += start_line * text_font.ch; x -= scroll_menu.px_hpos; ptr = &text_lines[start_line += scroll_menu.vpos]; start_line = min((area.g_y - y + area.g_h + text_font.ch - 1) / text_font.ch, Anz_text_lines - start_line); area.g_h = text_font.ch; Vsync(); x = (x + 7) & ~7; for (; --start_line >= 0; y += text_font.ch) { area.g_y = y; my_clear_area(&area); if (**ptr - 1) { v_set_text(FAIL, 0, BLUE, 0x01, 0, NULL); (*v_mtext)(x_handle, x, y, (*ptr++) + 1); v_set_text(FAIL, 0, BLACK, 0x00, 0, NULL); } else (*v_mtext)(x_handle, x, y, (*ptr++) + 1); } pla[0] = pla[1] = 0; pla[2] = min(pb->pb_w - 1, Rip_bild.fd_w - 1); pla[3] = min(pb->pb_h - 1, Rip_bild.fd_h - 1); pla[6] = pla[4] = pb->pb_x + (pb->pb_w - Rip_bild.fd_w) / 2; /* x_wert to */ pla[7] = pla[5] = pb->pb_y; /* y_wert to */ pla[6] += pla[2]; pla[7] += pla[3]; vro_cpyfm(x_handle, S_ONLY, pla, &Rip_bild, screen); v_set_mode(MD_TRANS); vst_alignment(x_handle, 1, 5, &i, &i); pla[5] += 64; for (i = 0; i < 7; i++, pla[5] += chardim[3]) { v_set_text(text_font.id, (i == 0 || i == 6) ? text_font.size : 12, WHITE, 1, 0, chardim); (*v_mtext)(x_handle, pla[4] + 157, pla[5], rip_line[i]); v_set_text(text_font.id, (i == 0 || i == 6) ? text_font.size : 12, BLACK, 0, 0, chardim); (*v_mtext)(x_handle, pla[4] + 157, pla[5], rip_line[i]); } vst_alignment(x_handle, 0, 5, &i, &i); } return (0); } static int draw_msgline(PARMBLK *pb) { GRECT area = *(GRECT *) &pb->pb_x; if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { int x = pb->pb_x, y = pb->pb_y + (msg_vis - 1) * msg_font.ch, foo, i; char **ptr = &message_line[msg_pos], tmp; int startx, stopx, starty, stopy; x = (x + 7) & ~7; /* Byte alignment speeds output up */ v_set_mode(MD_REPLACE); /* void v_set_text(int font,int height,int color,int effect,int * rotate,int out[4]) */ v_set_text(msg_font.id, msg_font.size, FAIL, FAIL, 0, NULL); vst_alignment(x_handle, 0, 5, &foo, &foo); stopy = min(msg_pos, msg_vis); /* Vsync();*/ startx = (area.g_x - x) / msg_font.cw - 1; /* MAR 06.02.2001 -- because italic covers the next char */ Max(&startx, 0); stopx = (area.g_x + area.g_w + msg_font.cw - x - 1) / msg_font.cw; x += startx * msg_font.cw; for (i = 0; i < stopy; i++, y -= msg_font.ch, ptr--) { if (message_age[msg_pos - i]) v_set_text(FAIL, 0, BLACK, 0, 0, NULL); else v_set_text(FAIL, 0, LBLACK, 4, 0, NULL); tmp = (*ptr)[stopx]; (*ptr)[stopx] = 0; (*v_mtext)(x_handle, x, y, &(*ptr)[startx]); (*ptr)[stopx] = tmp; } } return (0); } static int draw_status(PARMBLK *pb) { GRECT area = *(GRECT *) &pb->pb_x; area.g_x += 2 * status_font.cw - 2; area.g_w -= 2 * status_font.cw - 2; if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { int x = pb->pb_x, y = pb->pb_y, startx, stopx, starty, stopy, i; char tmp; /* void v_set_text(int font,int height,int color,int effect,int * rotate,int out[4]) */ v_set_mode(MD_REPLACE); v_set_text(status_font.id, status_font.size, BLACK, 0, 0, NULL); x = (x + 2 * status_font.cw + 6) & ~7; startx = (area.g_x - x) / status_font.cw; starty = (area.g_y - y) / status_font.ch; stopx = (area.g_x + area.g_w + status_font.ch - 1 - x) / status_font.cw; stopy = (area.g_y + area.g_h + status_font.ch - 1 - y) / status_font.ch; Max(&startx, 0); /* MAR -- Hmm, area.g_x could end up 1 below x */ Max(&stopx, 0); x += startx * status_font.cw; y += starty * status_font.ch; /* Vsync();*/ area.g_h = status_font.ch; for (i = starty; i < min(2, stopy); i++, area.g_y += status_font.ch, y += status_font.ch) { my_clear_area(&area); tmp = status_line[i][stopx]; status_line[i][stopx] = 0; (*v_mtext)(x_handle, x, y, &status_line[i][startx]); status_line[i][stopx] = tmp; } } return (0); } static int draw_inventory(PARMBLK *pb) { GRECT area = *(GRECT *) &pb->pb_x; if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { int gl, i, x = pb->pb_x, y = pb->pb_y, start_line = area.g_y - y; Gem_menu_item *it; v_set_mode(MD_REPLACE); v_set_text(menu_font.id, menu_font.size, BLACK, 0, 0, NULL); start_line /= menu_font.ch; y += start_line * menu_font.ch; x -= scroll_menu.px_hpos; start_line += scroll_menu.vpos; for (it = invent_list, i = start_line; --i >= 0 && it; it = it->Gmi_next) ; i = min((area.g_y - y + area.g_h + menu_font.ch - 1) / menu_font.ch, Anz_inv_lines - start_line); Vsync(); area.g_h = menu_font.ch; for (; (--i >= 0) && it; it = it->Gmi_next, y += menu_font.ch) { if (it->Gmi_attr) v_set_text(FAIL, FALSE, BLUE, 1, FAIL, NULL); /* Bold */ else v_set_text(FAIL, FALSE, BLACK, 0, FAIL, NULL); area.g_y = y; my_clear_area(&area); if ((gl = it->Gmi_glyph) != no_glyph) { int pla[8], h = min(menu_font.ch, Tile_heigth) - 1; pla[0] = pla[2] = (gl % Tiles_per_line) * Tile_width; /* x_wert from */ pla[1] = pla[3] = (gl / Tiles_per_line) * Tile_heigth; /* y_wert from */ pla[4] = pla[6] = x; /* x_wert to */ pla[5] = pla[7] = y; /* y_wert to */ pla[2] += Tile_width - 1; pla[3] += h; pla[6] += Tile_heigth - 1; pla[7] += h; vro_cpyfm(x_handle, S_ONLY, pla, &Tile_bilder, screen); } if (it->Gmi_identifier) it->Gmi_str[2] = it->Gmi_selected ? (it->Gmi_count == -1L ? '+' : '#') : '-'; (*v_mtext)(x_handle, (x + 23) & ~7, y, it->Gmi_str); } } return (0); } static int draw_prompt(PARMBLK *pb) { GRECT area = *(GRECT *) &pb->pb_x; if (rc_intersect((GRECT *) &pb->pb_xc, &area)) { char **ptr = (char **) pb->pb_parm; int x = pb->pb_x, y = pb->pb_y, chardim[4]; /* void v_set_text(int font,int height,int color,int effect,int * rotate,int out[4]) */ v_set_mode(MD_TRANS); v_set_text(ibm_font_id, ibm_font, WHITE, 0, 0, chardim); Vsync(); if (planes < 4) { int pxy[4]; v_set_fill(BLACK, 2, 4, 0); rc_grect_to_array(&area, pxy); v_bar(x_handle, pxy); } else my_color_area(&area, LWHITE); (*v_mtext)(x_handle, x, y, *(ptr++)); if (*ptr) (*v_mtext)(x_handle, x, y + chardim[3], *ptr); } return (0); } static USERBLK ub_lines = { draw_lines, 0L }, ub_msg = { draw_msgline, 0L }, ub_inventory = { draw_inventory, 0L }, ub_titel = { draw_titel, 0L }, ub_status = { draw_status, 0L }, ub_prompt = { draw_prompt, 0L }; /**************************** rsc_funktionen *****************************/ void my_close_dialog(DIAINFO *dialog, boolean shrink_box) { close_dialog(dialog, shrink_box); Event_Timer(0, 0, TRUE); } void mar_get_rsc_tree(obj_number, z_ob_obj) int obj_number; OBJECT **z_ob_obj; { rsrc_gaddr(R_TREE, obj_number, z_ob_obj); fix_objects(*z_ob_obj, SCALING, 0, 0); } void mar_clear_map(void); void img_error(errnumber) int errnumber; { char buf[BUFSZ]; switch (errnumber) { case ERR_HEADER: sprintf(buf, "%s", "[1][ Image Header | corrupt. ][ Oops ]"); break; case ERR_ALLOC: sprintf(buf, "%s", "[1][ Not enough | memory for | an image. ][ Oops ]"); break; case ERR_FILE: sprintf(buf, "%s", "[1][ The Image-file | is not available ][ Oops ]"); break; case ERR_DEPACK: sprintf(buf, "%s", "[1][ The Image-file | is corrupt ][ Oops ]"); break; case ERR_COLOR: sprintf(buf, "%s", "[1][ Number of colors | not supported ][ Oops ]"); break; default: sprintf(buf, "[1][ img_error | strange error | number: %i ][ Hmm ]", errnumber); break; } form_alert(1, buf); } void mar_change_button_char(OBJECT *z_ob, int nr, char ch) { *ob_get_text(z_ob, nr, 0) = ch; ob_set_hotkey(z_ob, nr, ch); } void mar_set_dir_keys() { static int mi_numpad = FAIL; char mcmd[] = "bjnh.lyku", npcmd[] = "123456789", *p_cmd; if (mi_numpad != mar_iflags_numpad()) { OBJECT *z_ob = zz_oblist[DIRECTION]; int i; mi_numpad = mar_iflags_numpad(); ob_set_hotkey(z_ob, DIRDOWN, '>'); ob_set_hotkey(z_ob, DIRUP, '<'); p_cmd = mi_numpad ? npcmd : mcmd; for (i = 0; i < 9; i++) mar_change_button_char(z_ob, DIR1 + 2 * i, p_cmd[i]); } } extern int total_tiles_used; /* tile.c */ int mar_gem_init() { int i, bild_fehler = FALSE, fsize; char *fname; static MITEM wish_workaround = { FAIL, key(0, 'J'), K_CTRL, W_CYCLE, FAIL }; OBJECT *z_ob; if ((i = open_rsc("gem_rsc.rsc", NULL, md, md, md, 0, 0, 0)) <= 0) { graf_mouse(M_OFF, NULL); if (i < 0) form_alert(1, "[3][| Fatal Error | File: GEM_RSC.RSC | not " "found. ][ grumble ]"); else form_alert(1, "[3][| Fatal Error | GEM initialisation | failed. " "][ a pity ]"); return (0); } if (planes < 1 || planes > 8) { form_alert( 1, "[3][ Color-depth | not supported, | try 2-256 colors. ][ Ok ]"); return (0); } MouseBee(); /* MAR -- 17.Mar 2002 NVDI 3.0 or better uses v_ftext */ v_mtext = speedo == 3 ? &v_ftext : &v_gtext; for (i = 0; i < NHICON; i++) mar_get_rsc_tree(i, &zz_oblist[i]); z_ob = zz_oblist[ABOUT]; ob_hide(z_ob, OKABOUT, TRUE); ob_draw_dialog(z_ob, 0, 0, 0, 0); mar_get_font(NHW_MESSAGE, &fname, &fsize); mar_set_font(NHW_MESSAGE, fname, fsize); mar_get_font(NHW_MAP, &fname, &fsize); mar_set_font(NHW_MAP, fname, fsize); mar_get_font(NHW_STATUS, &fname, &fsize); mar_set_font(NHW_STATUS, fname, fsize); mar_get_font(NHW_MENU, &fname, &fsize); mar_set_font(NHW_MENU, fname, fsize); mar_get_font(NHW_TEXT, &fname, &fsize); mar_set_font(NHW_TEXT, fname, fsize); msg_anz = mar_get_msg_history(); mar_set_msg_visible(mar_get_msg_visible()); msg_width = min(max_w / msg_font.cw - 3, MSGLEN); if (max_w / status_font.cw < COLNO - 1) mar_set_fontbyid(NHW_STATUS, small_font_id, -small_font); status_w = min(max_w / status_font.cw - 3, MSGLEN); if (planes > 0 && planes < 9) { normal_palette = (short *) m_alloc(3 * colors * sizeof(short)); get_colors(x_handle, normal_palette, colors); } loadimg: bild_fehler = depack_img(Tilefile ? Tilefile : (planes >= 4) ? "NH16.IMG" : "NH2.IMG", &tile_image); if (bild_fehler) { z_ob = zz_oblist[ABOUT]; ob_undraw_dialog(z_ob, 0, 0, 0, 0); ob_hide(z_ob, OKABOUT, FALSE); img_error(bild_fehler); return (0); } if (tile_image.img_w % Tile_width || tile_image.img_h % Tile_heigth) { Tilefile = NULL; Tile_width = Tile_heigth = 16; printf("size didn't match.\n"); goto loadimg; } if ((tile_image.img_w / Tile_width) * (tile_image.img_h / Tile_heigth) < total_tiles_used) { Tilefile = NULL; Tile_width = Tile_heigth = 16; printf("Too few Tiles in Image.\n"); goto loadimg; } Tiles_per_line = tile_image.img_w / Tile_width; if (planes >= 4) { if (tile_image.planes > 1) img_set_colors(x_handle, tile_image.palette, tile_image.planes); #if 0 else{ int mypalette[]={}; img_set_colors(x_handle, mypalette, 4); } #endif } mfdb(&Tile_bilder, (int *) tile_image.addr, tile_image.img_w, tile_image.img_h, 1, tile_image.planes); transform_img(&Tile_bilder); mfdb(&Map_bild, NULL, (COLNO - 1) * Tile_width, ROWNO * Tile_heigth, 0, planes); mfdb(&FontCol_Bild, NULL, (COLNO - 1) * map_font.cw, ROWNO * map_font.ch, 0, planes); Map_bild.fd_addr = (int *) m_alloc(mfdb_size(&Map_bild) > mfdb_size(&FontCol_Bild) ? mfdb_size(&Map_bild) : mfdb_size(&FontCol_Bild)); FontCol_Bild.fd_addr = Map_bild.fd_addr; mfdb(&Pet_Mark, pet_mark_data, 8, 7, 1, 1); vr_trnfm(x_handle, &Pet_Mark, &Pet_Mark); mfdb(&Black_bild, NULL, 16, 32, 1, 1); /* MAR -- 17.Mar 2002 that should cover the biggest map-font */ Black_bild.fd_addr = (int *) m_alloc(mfdb_size(&Black_bild)); memset(Black_bild.fd_addr, 255, mfdb_size(&Black_bild)); vr_trnfm(x_handle, &Black_bild, &Black_bild); for (i = 0; i < MAXWIN; i++) { Gem_nhwindow[i].gw_window = NULL; Gem_nhwindow[i].gw_type = 0; Gem_nhwindow[i].gw_dirty = TRUE; } memset(&scroll_menu, 0, sizeof(scroll_menu)); scroll_menu.scroll = AUTO_SCROLL; scroll_menu.obj = LINESLIST; scroll_menu.px_hline = menu_font.cw; scroll_menu.px_vline = menu_font.ch; scroll_menu.hscroll = scroll_menu.vscroll = 1; scroll_menu.tbar_d = 2 * gr_ch - 2; mar_set_dir_keys(); memset(&scroll_map, 0, sizeof(scroll_map)); scroll_map.scroll = AUTO_SCROLL; scroll_map.obj = ROOT; scroll_map.px_hline = mar_set_tile_mode(FAIL) ? Tile_width : map_font.cw; scroll_map.px_vline = mar_set_tile_mode(FAIL) ? Tile_heigth : map_font.ch; scroll_map.hsize = COLNO - 1; scroll_map.vsize = ROWNO; scroll_map.hpage = 8; scroll_map.vpage = 8; scroll_map.hscroll = 1; scroll_map.vscroll = 1; /* dial_options( round, niceline, standard, return_default, background, nonselectable, always_keys, toMouse, clipboard, hz); */ dial_options(TRUE, TRUE, FALSE, RETURN_DEFAULT, AES_BACK, TRUE, KEY_ALWAYS, FALSE, TRUE, 3); /* dial_colors( dial_pattern, dial_color, dial_frame, hotkey, alert, cycle_button, check_box, radio_button, arrow, cycle_backgrnd, check_backgrnd, radio_backgrnd, arrow_backgrnd, edit_3d, draw_3d) */ if (planes < 4) dial_colors(4, BLACK, WHITE, RED, RED, WHITE, BLACK, BLACK, BLACK, FAIL, FAIL, FAIL, FAIL, TRUE, TRUE); else dial_colors(7, LWHITE, BLACK, RED, RED, BLACK, BLACK, BLACK, BLACK, WHITE, WHITE, WHITE, WHITE, TRUE, TRUE); /* void MenuItems(MITEM *close,MITEM *closeall,MITEM *cycle,MITEM *invcycle, MITEM *globcycle,MITEM *full,MITEM *bottom,MITEM *iconify,MITEM *iconify_all, MITEM *menu,int menu_cnt) */ /* Ctrl-W ist normaly bound to cycle */ MenuItems(NULL, NULL, &wish_workaround, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); menu_install(zz_oblist[MENU], TRUE); z_ob = zz_oblist[ABOUT]; ob_undraw_dialog(z_ob, 0, 0, 0, 0); ob_hide(z_ob, OKABOUT, FALSE); return (1); } /************************* mar_exit_nhwindows *******************************/ void mar_exit_nhwindows() { int i; for (i = MAXWIN; --i >= 0;) if (Gem_nhwindow[i].gw_type) mar_destroy_nhwindow(i); if (normal_palette) { img_set_colors(x_handle, normal_palette, tile_image.planes); null_free(normal_palette); } test_free(tile_image.palette); test_free(tile_image.addr); test_free(titel_image.palette); test_free(titel_image.addr); } /************************* mar_curs *******************************/ void mar_curs(x, y) int x, y; { Min(&dirty_map_area.g_x, x); Min(&dirty_map_area.g_y, y); Max(&dirty_map_area.g_w, x); Max(&dirty_map_area.g_h, y); Min(&dirty_map_area.g_x, map_cursx); Min(&dirty_map_area.g_y, map_cursy); Max(&dirty_map_area.g_w, map_cursx); Max(&dirty_map_area.g_h, map_cursy); map_cursx = x; map_cursy = y; if (WIN_MAP != WIN_ERR) Gem_nhwindow[WIN_MAP].gw_dirty = TRUE; } void mar_cliparound(void); void mar_map_curs_weiter(void) { static int once = TRUE; if (once) { redraw_window(Gem_nhwindow[WIN_STATUS].gw_window, NULL); redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window, NULL); once = FALSE; } mar_curs(map_cursx + 1, map_cursy); mar_cliparound(); } /************************* about *******************************/ void mar_about() { xdialog(zz_oblist[ABOUT], md, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE); Event_Timer(0, 0, TRUE); } /************************* ask_name *******************************/ char * mar_ask_name() { OBJECT *z_ob = zz_oblist[NAMEGET]; int bild_fehler; char who_are_you[] = "Who are you? "; bild_fehler = depack_img(planes < 4 ? "TITLE2.IMG" : "TITLE.IMG", &titel_image); if (bild_fehler) { /* MAR -- this isn't lethal */ ob_set_text(z_ob, NETHACKPICTURE, "missing title.img."); } else { mfdb(&Titel_bild, (int *) titel_image.addr, titel_image.img_w, titel_image.img_h, 1, titel_image.planes); transform_img(&Titel_bild); z_ob[NETHACKPICTURE].ob_type = G_USERDEF; z_ob[NETHACKPICTURE].ob_spec.userblk = &ub_titel; } ob_clear_edit(z_ob); xdialog(z_ob, who_are_you, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE); Event_Timer(0, 0, TRUE); test_free(titel_image.palette); test_free(titel_image.addr); test_free(Titel_bild.fd_addr); return (ob_get_text(z_ob, PLNAME, 0)); } /************************* more *******************************/ void send_key(int key) { int buf[8]; buf[3] = 0; /* No Shift/Ctrl/Alt */ buf[4] = key; AvSendMsg(ap_id, AV_SENDKEY, buf); } void send_return() { send_key(key(SCANRET, 0)); } int K_Init(xev, availiable) XEVENT *xev; int availiable; { xev = xev; return (MU_KEYBD & availiable); } int KM_Init(xev, availiable) XEVENT *xev; int availiable; { xev = xev; return ((MU_KEYBD | MU_MESAG) & availiable); } int M_Init(xev, availiable) XEVENT *xev; int availiable; { xev = xev; return (MU_MESAG & availiable); } #define More_Init K_Init int More_Handler(xev) XEVENT *xev; { int ev = xev->ev_mwich; if (ev & MU_KEYBD) { char ch = (char) (xev->ev_mkreturn & 0x00FF); DIAINFO *dinf; WIN *w; switch (ch) { case '\033': /* no more more more */ case ' ': if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) && dinf->di_tree == zz_oblist[PAGER]) { if (ch == '\033') mar_esc_pressed = TRUE; send_return(); break; } /* Fall thru */ default: ev &= ~MU_KEYBD; /* unknown key */ break; } } return (ev); } void mar_more() { if (!mar_esc_pressed) { OBJECT *z_ob = zz_oblist[PAGER]; WIN *p_w; Event_Handler(More_Init, More_Handler); dial_colors(7, RED, BLACK, RED, RED, BLACK, BLACK, BLACK, BLACK, WHITE, WHITE, WHITE, WHITE, TRUE, TRUE); if (WIN_MESSAGE != WIN_ERR && (p_w = Gem_nhwindow[WIN_MESSAGE].gw_window)) { z_ob->ob_x = p_w->work.g_x; z_ob->ob_y = p_w->curr.g_y + p_w->curr.g_h + gr_ch; } xdialog(z_ob, NULL, NULL, NULL, DIA_LASTPOS, FALSE, DIALOG_MODE); Event_Timer(0, 0, TRUE); Event_Handler(NULL, NULL); if (planes < 4) dial_colors(4, BLACK, WHITE, RED, RED, WHITE, BLACK, BLACK, BLACK, FAIL, FAIL, FAIL, FAIL, TRUE, TRUE); else dial_colors(7, LWHITE, BLACK, RED, RED, BLACK, BLACK, BLACK, BLACK, WHITE, WHITE, WHITE, WHITE, TRUE, TRUE); } } /************************* Gem_start_menu *******************************/ void Gem_start_menu(win) winid win; { win = win; if (invent_list) { Gem_menu_item *curr, *next; for (curr = invent_list; curr; curr = next) { next = curr->Gmi_next; free(curr->Gmi_str); free(curr); } } invent_list = NULL; Anz_inv_lines = 0; Inv_breite = 16; } /************************* mar_add_menu *******************************/ void mar_add_menu(win, item) winid win; Gem_menu_item *item; { win = win; item->Gmi_next = invent_list; invent_list = item; Anz_inv_lines++; } void mar_reverse_menu() { Gem_menu_item *next, *head = 0, *curr = invent_list; while (curr) { next = curr->Gmi_next; curr->Gmi_next = head; head = curr; curr = next; } invent_list = head; } void mar_set_accelerators() { char ch = 'a'; Gem_menu_item *curr; for (curr = invent_list; curr; curr = curr->Gmi_next) { int extent[8]; v_set_text(menu_font.id, menu_font.size, BLACK, 0, 0, NULL); vqt_extent(x_handle, curr->Gmi_str, extent); Max(&Inv_breite, extent[4] + Tile_width + menu_font.cw); if (ch && curr->Gmi_accelerator == 0 && curr->Gmi_identifier) { curr->Gmi_accelerator = ch; curr->Gmi_str[0] = ch; if (ch == 'z') ch = 'A'; else if (ch == 'Z') ch = 0; else ch++; } } } Gem_menu_item * mar_hol_inv() { return (invent_list); } /************************* mar_putstr_text *********************/ void mar_raw_print(const char *); void mar_set_text_to_rip(winid w) { use_rip = TRUE; } void mar_putstr_text(winid window, int attr, const char *str) { static int zeilen_frei = 0; int breite; char *ptr; window = window; if (!text_lines) { text_lines = (char **) m_alloc(12 * sizeof(char *)); zeilen_frei = 12; } if (!zeilen_frei) { text_lines = (char **) realloc(text_lines, (Anz_text_lines + 12) * sizeof(char *)); zeilen_frei = 12; } if (!text_lines) { mar_raw_print("No room for Text"); return; } if (str) breite = strlen(str); Min(&breite, 80); ptr = text_lines[Anz_text_lines] = (char *) m_alloc(breite * sizeof(char) + 2); *ptr = (char) (attr + 1); /* avoid 0 */ strncpy(ptr + 1, str, breite); ptr[breite + 1] = 0; Anz_text_lines++; zeilen_frei--; } int mar_set_inv_win(Anzahl, Breite) int Anzahl, Breite; { OBJECT *z_ob = zz_oblist[LINES]; int retval = WIN_DIAL | MODAL | NO_ICONIFY; scroll_menu.hsize = 0; scroll_menu.vpage = (desk.g_h - 3 * gr_ch) / scroll_menu.px_vline; if (Anzahl > scroll_menu.vpage) { retval |= WD_VSLIDER; if (Breite > max_w - 3 * scroll_menu.px_hline) { retval |= WD_HSLIDER; scroll_menu.hpage = (max_w - 3 * scroll_menu.px_hline) / scroll_menu.px_hline; scroll_menu.hpos = 0; scroll_menu.hsize = Breite / scroll_menu.px_hline; scroll_menu.vpage = (desk.g_h - 4 * gr_ch - 1) / scroll_menu.px_vline; } Anzahl = scroll_menu.vpage; } else { if (Breite > max_w - scroll_menu.px_hline) { retval |= WD_HSLIDER; scroll_menu.hpage = (max_w - scroll_menu.px_hline) / scroll_menu.px_hline; scroll_menu.hpos = 0; scroll_menu.hsize = Breite / scroll_menu.px_hline; scroll_menu.vpage = (desk.g_h - 4 * gr_ch - 1) / scroll_menu.px_vline; if (Anzahl > scroll_menu.vpage) { retval |= WD_VSLIDER; Anzahl = scroll_menu.vpage; } } scroll_menu.vpage = Anzahl; } if ((scroll_menu.hmax = scroll_menu.hsize - scroll_menu.hpage) < 0) scroll_menu.hmax = 0; if ((scroll_menu.vmax = scroll_menu.vsize - scroll_menu.vpage) < 0) scroll_menu.vmax = 0; /* left/right/up 2 pixel border down 2gr_ch toolbar */ z_ob[ROOT].ob_width = z_ob[LINESLIST].ob_width = Breite; z_ob[ROOT].ob_height = z_ob[QLINE].ob_y = z_ob[LINESLIST].ob_height = scroll_menu.px_vline * Anzahl; z_ob[QLINE].ob_y += gr_ch / 2; z_ob[ROOT].ob_width += 4; z_ob[ROOT].ob_height += 2 * gr_ch + 2; return (retval); } /************************* mar_status_dirty *******************************/ void mar_status_dirty() { int ccol; ccol = mar_hp_query(); if (ccol < 2) curs_col = WHITE; /* 50-100% : 0 */ else if (ccol < 3) curs_col = YELLOW; /* 33-50% : 6 */ else if (ccol < 5) curs_col = LYELLOW; /* 20-33% : 14*/ else if (ccol < 10) curs_col = RED; /* 10-20% : 2 */ else curs_col = MAGENTA; /* <10% : 7*/ } /************************* mar_add_message *******************************/ void mar_add_message(str) const char *str; { int i, mesg_hist = mar_get_msg_history(); char *tmp, *rest, buf[TBUFSZ]; if (WIN_MESSAGE == WIN_ERR) return; if (!mar_message_pause) { mar_message_pause = TRUE; messages_pro_zug = 0; msg_pos = msg_max; } if (msg_max > mesg_hist - 2) { msg_max = mesg_hist - 2; msg_pos--; if (msg_pos < 0) msg_pos = 0; tmp = message_line[0]; for (i = 0; i < mesg_hist - 1; i++) { message_line[i] = message_line[i + 1]; message_age[i] = message_age[i + 1]; } message_line[mesg_hist - 1] = tmp; } strcpy(toplines, str); messages_pro_zug++; msg_max++; if ((int) strlen(toplines) >= msg_width) { int pos = msg_width; tmp = toplines + msg_width; while (*tmp != ' ' && pos >= 0) { tmp--; pos--; } if (pos <= 0) pos = msg_width; /* Mar -- Oops, what a word :-) */ message_age[msg_max] = TRUE; strncpy(message_line[msg_max], toplines, pos); message_line[msg_max][pos] = 0; rest = strcpy(buf, toplines + pos); } else { message_age[msg_max] = TRUE; strncpy(message_line[msg_max], toplines, msg_width); rest = 0; } Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; if (messages_pro_zug >= mesg_hist) { /* MAR -- Greater then should never happen */ messages_pro_zug = mesg_hist; mar_display_nhwindow(WIN_MESSAGE); } if (rest) mar_add_message(rest); } /************************* mar_add_status_str *******************************/ void mar_add_status_str(str, line) const char *str; int line; { int i, last_diff = -1; GRECT area = { 0, line * status_font.ch, status_font.cw, status_font.ch }; for (i = 0; (i < status_w - 2) && str[i]; i++) if (str[i] != status_line[line][i]) { if (last_diff == -1) area.g_x = i * status_font.cw; else area.g_w += status_font.cw; last_diff = i; status_line[line][i] = str[i]; } else if (last_diff >= 0) { add_dirty_rect(dr_stat, &area); last_diff = -1; area.g_w = status_font.cw; } for (; i < status_w - 1; i++) { if (status_line[line][i]) { if (last_diff == -1) area.g_x = i * status_font.cw; else area.g_w += status_font.cw; last_diff = i; } status_line[line][i] = 0; } if (last_diff >= 0) add_dirty_rect(dr_stat, &area); } /************************* mar_set_menu_title *******************************/ void mar_set_menu_title(str) const char *str; { test_free(Menu_title); /* just in case */ Menu_title = mar_copy_of(str ? str : nullstr); } /************************* mar_set_menu_type *******************************/ void mar_set_menu_type(how) int how; { Inv_how = how; } /************************* Inventory Utils *******************************/ void set_all_on_page(start, page) int start, page; { Gem_menu_item *curr; if (start < 0 || page < 0) return; for (curr = invent_list; start-- && curr; curr = curr->Gmi_next) ; for (; page-- && curr; curr = curr->Gmi_next) if (curr->Gmi_identifier && !curr->Gmi_selected) curr->Gmi_selected = TRUE; } void unset_all_on_page(start, page) int start, page; { Gem_menu_item *curr; if (start < 0 || page < 0) return; for (curr = invent_list; start-- && curr; curr = curr->Gmi_next) ; for (; page-- && curr; curr = curr->Gmi_next) if (curr->Gmi_identifier && curr->Gmi_selected) { curr->Gmi_selected = FALSE; curr->Gmi_count = -1L; } } void invert_all_on_page(start, page, acc) int start, page; char acc; { Gem_menu_item *curr; if (start < 0 || page < 0) return; for (curr = invent_list; start-- && curr; curr = curr->Gmi_next) ; for (; page-- && curr; curr = curr->Gmi_next) if (curr->Gmi_identifier && (acc == 0 || curr->Gmi_groupacc == acc)) { if (curr->Gmi_selected) { curr->Gmi_selected = FALSE; curr->Gmi_count = -1L; } else curr->Gmi_selected = TRUE; } } /************************* Inv_Handler and Inv_Init * *******************************/ int scroll_top_dialog(char ch) { WIN *w; DIAINFO *dinf; if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) && dinf->di_tree == zz_oblist[LINES]) { switch (ch) { case ' ': if (scroll_menu.vpos == scroll_menu.vmax) { send_return(); break; } /* Fall thru */ case MENU_NEXT_PAGE: scroll_window(w, PAGE_DOWN, NULL); break; case MENU_PREVIOUS_PAGE: scroll_window(w, PAGE_UP, NULL); break; case MENU_FIRST_PAGE: scroll_window(w, WIN_START, NULL); break; case MENU_LAST_PAGE: scroll_window(w, WIN_END, NULL); break; default: return (FALSE); } return (TRUE); } return (FALSE); } #define Text_Init KM_Init int Text_Handler(xev) XEVENT *xev; { int ev = xev->ev_mwich; if (ev & MU_MESAG) { int *buf = xev->ev_mmgpbuf, y_wo, i; if (*buf == FONT_CHANGED) { if (buf[3] >= 0) { mar_set_fontbyid(NHW_TEXT, buf[4], buf[5]); FontAck(buf[1], 1); } } } if (ev & MU_KEYBD) { char ch = (char) (xev->ev_mkreturn & 0x00FF); if (!scroll_top_dialog(ch)) switch (ch) { case '\033': send_return(); /* just closes the textwin */ break; case C('c'): clipbrd_save(text_lines, Anz_text_lines, xev->ev_mmokstate & K_SHIFT, FALSE); break; default: ev &= ~MU_KEYBD; /* unknown key */ break; } } return (ev); } #define Inv_Init KM_Init static long count = 0; int Inv_Handler(xev) XEVENT *xev; { int ev = xev->ev_mwich; Gem_menu_item *it; GRECT area; OBJECT *z_ob = zz_oblist[LINES]; ob_pos(z_ob, LINESLIST, &area); if (ev & MU_MESAG) { int *buf = xev->ev_mmgpbuf, y_wo, i; if (*buf == FONT_CHANGED) { if (buf[3] >= 0) { mar_set_fontbyid(NHW_MENU, buf[4], buf[5]); FontAck(buf[1], 1); } } else if (*buf == OBJC_CHANGED && buf[3] == LINESLIST) { ob_undostate(z_ob, LINESLIST, SELECTED); mouse(NULL, &y_wo); y_wo = (y_wo - area.g_y) / menu_font.ch + scroll_menu.vpos; for (it = invent_list, i = 0; i < y_wo && it; it = it->Gmi_next, i++) ; if (it->Gmi_identifier) { it->Gmi_selected = !it->Gmi_selected; it->Gmi_count = count == 0L ? -1L : count; count = 0L; if (Inv_how != PICK_ANY) { /*my_close_dialog(Inv_dialog,TRUE);*/ send_return(); } else { area.g_x = (area.g_x + 23 + 2 * menu_font.cw) & ~7; area.g_w = menu_font.cw; area.g_h = menu_font.ch; area.g_y += (y_wo - scroll_menu.vpos) * menu_font.ch; ob_draw_chg(Inv_dialog, LINESLIST, &area, FAIL); } /* how != PICK_ANY */ } /* identifier */ } else /* LINESLIST changed */ ev &= ~MU_MESAG; /* unknown message not used */ } /* MU_MESAG */ if (ev & MU_KEYBD) { char ch = (char) (xev->ev_mkreturn & 0x00FF); if (!scroll_top_dialog(ch)) { switch (ch) { case '0': /* special 0 is also groupaccelerator for balls */ if (count <= 0) goto find_acc; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (Inv_how == PICK_NONE) goto find_acc; count = (count * 10L) + (long) (ch - '0'); break; case '\033': /* cancel - from counting or loop */ if (count > 0L) count = 0L; else { unset_all_on_page(0, (int) scroll_menu.vsize); my_close_dialog(Inv_dialog, TRUE); return (ev); } break; case '\0': /* finished (commit) */ case '\n': case '\r': break; case MENU_SELECT_PAGE: if (Inv_how == PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) set_all_on_page((int) scroll_menu.vpos, scroll_menu.vpage); break; case MENU_SELECT_ALL: if (Inv_how == PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) set_all_on_page(0, (int) scroll_menu.vsize); break; case MENU_UNSELECT_PAGE: unset_all_on_page((int) scroll_menu.vpos, scroll_menu.vpage); break; case MENU_UNSELECT_ALL: unset_all_on_page(0, (int) scroll_menu.vsize); break; case MENU_INVERT_PAGE: if (Inv_how == PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) invert_all_on_page((int) scroll_menu.vpos, scroll_menu.vpage, 0); break; case MENU_INVERT_ALL: if (Inv_how == PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) invert_all_on_page(0, (int) scroll_menu.vsize, 0); break; case MENU_SEARCH: if (Inv_how != PICK_NONE) { char buf[BUFSZ]; Gem_getlin("Search for:", buf); if (!*buf || buf[0] == '\033') break; for (it = invent_list; it; it = it->Gmi_next) { if (it->Gmi_identifier && strstr(it->Gmi_str, buf)) { it->Gmi_selected = TRUE; if (Inv_how != PICK_ANY) { my_close_dialog(Inv_dialog, FALSE); break; } } } } break; case C('c'): clipbrd_save(invent_list, Anz_inv_lines, xev->ev_mmokstate & K_SHIFT, TRUE); break; default: find_acc: if (Inv_how == PICK_NONE) my_close_dialog(Inv_dialog, TRUE); else for (it = invent_list; it; it = it->Gmi_next) { if (it->Gmi_identifier && (it->Gmi_accelerator == ch || it->Gmi_groupacc == ch)) { it->Gmi_selected = !it->Gmi_selected; it->Gmi_count = count == 0L ? -1L : count; count = 0L; if (Inv_how != PICK_ANY) my_close_dialog(Inv_dialog, TRUE); } } break; } /* end switch(ch) */ if (Inv_how == PICK_ANY) { area.g_x = (area.g_x + 23 + 2 * menu_font.cw) & ~7; area.g_w = menu_font.cw; ob_draw_chg(Inv_dialog, LINESLIST, &area, FAIL); } } /* !scroll_Inv_dialog */ } /* MU_KEYBD */ if (Inv_how == PICK_ANY) { ob_set_text(Inv_dialog->di_tree, QLINE, strCancel); for (it = invent_list; it; it = it->Gmi_next) if (it->Gmi_identifier && it->Gmi_selected) { ob_set_text(Inv_dialog->di_tree, QLINE, strOk); break; } ob_draw_chg(Inv_dialog, QLINE, NULL, FAIL); } return (ev); } /************************* draw_window *******************************/ static void mar_draw_window(first, win, area) int first; WIN *win; GRECT *area; { OBJECT *obj = (OBJECT *) win->para; if (obj) { if (first) { obj->ob_x = win->work.g_x; obj->ob_y = win->work.g_y; } if (area == NULL) area = &(win->work); objc_draw(obj, ROOT, MAX_DEPTH, area->g_x, area->g_y, area->g_w, area->g_h); } } /************************* mar_display_nhwindow * *******************************/ void redraw_winwork(WIN *w, GRECT *area) { area->g_x += w->work.g_x; area->g_y += w->work.g_y; redraw_window(w, area); } void mar_menu_set_slider(WIN *p_win) { if (p_win) { SCROLL *sc = p_win->scroll; if (!sc) return; if (p_win->gadgets & HSLIDE) { long hsize = 1000l; if (sc->hsize > 0 && sc->hpage > 0) { hsize *= sc->hpage; hsize /= sc->hsize; } window_slider(p_win, HOR_SLIDER, 0, (int) hsize); } if (p_win->gadgets & VSLIDE) { long vsize = 1000l; if (sc->vsize > 0 && sc->vpage > 0) { vsize *= sc->vpage; vsize /= sc->vsize; } window_slider(p_win, VERT_SLIDER, 0, (int) vsize); } } } void recalc_msg_win(GRECT *area) { OBJECT *z_ob; z_ob = zz_oblist[MSGWIN]; z_ob[MSGLINES].ob_spec.userblk = &ub_msg; z_ob[MSGLINES].ob_width = z_ob[ROOT].ob_width = (msg_width + 3) * msg_font.cw; z_ob[MSGLINES].ob_width -= z_ob[UPMSG].ob_width; z_ob[ROOT].ob_height = z_ob[GRABMSGWIN].ob_height = z_ob[MSGLINES].ob_height = msg_vis * msg_font.ch; z_ob[DNMSG].ob_y = z_ob[GRABMSGWIN].ob_height - z_ob[DNMSG].ob_height; window_border(0, 0, 0, z_ob->ob_width, z_ob->ob_height, area); } void recalc_status_win(GRECT *area) { OBJECT *z_ob; z_ob = zz_oblist[STATUSLINE]; z_ob[ROOT].ob_type = G_USERDEF; z_ob[ROOT].ob_spec.userblk = &ub_status; z_ob[ROOT].ob_width = (status_w + 2) * status_font.cw; z_ob[ROOT].ob_height = z_ob[GRABSTATUS].ob_height = 2 * status_font.ch; z_ob[GRABSTATUS].ob_width = 2 * status_font.cw - 2; window_border(0, 0, 0, z_ob->ob_width, z_ob->ob_height, area); } void calc_std_winplace(int which, GRECT *place) { static int todo = TRUE; static GRECT me, ma, st; if (todo || which < 0) { OBJECT *z_ob; int map_h_off, foo; /* First the messagewin */ recalc_msg_win(&me); /* Now the map */ wind_calc(WC_BORDER, MAP_GADGETS, 0, 0, scroll_map.px_hline * (COLNO - 1), scroll_map.px_vline * ROWNO, &foo, &foo, &foo, &map_h_off); map_h_off -= scroll_map.px_vline * ROWNO; window_border(MAP_GADGETS, 0, 0, scroll_map.px_hline * (COLNO - 1), scroll_map.px_vline * ROWNO, &ma); /* Next the statuswin */ recalc_status_win(&st); /* And last but not least a final test */ ma.g_h = map_h_off + scroll_map.px_vline * ROWNO; while (me.g_h + ma.g_h + st.g_h >= desk.g_h) ma.g_h -= scroll_map.px_vline; /* stack the windows */ ma.g_y = me.g_y = st.g_y = desk.g_y; if (status_align) { ma.g_y += st.g_h; if (msg_align) { st.g_y += me.g_h; ma.g_y += me.g_h; } else { me.g_y += st.g_h + ma.g_h; } } else { if (msg_align) { ma.g_y += me.g_h; } else { me.g_y += ma.g_h; } st.g_y += me.g_h + ma.g_h; } if (which) todo = FALSE; } switch (which) { case NHW_MESSAGE: *place = me; break; case NHW_MAP: *place = ma; break; case NHW_STATUS: *place = st; break; default: break; } } void mar_display_nhwindow(wind) winid wind; { DIAINFO *dlg_info; OBJECT *z_ob; int d_exit = W_ABANDON, i, breite, mar_di_mode, tmp_magx = magx; GRECT g_mapmax, area; char *tmp_button; struct gw *p_Gw; if (wind == WIN_ERR) return; p_Gw = &Gem_nhwindow[wind]; switch (p_Gw->gw_type) { case NHW_TEXT: if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); z_ob = zz_oblist[LINES]; scroll_menu.vsize = Anz_text_lines; scroll_menu.vpos = 0; if (use_rip) { if (!depack_img(planes < 4 ? "RIP2.IMG" : "RIP.IMG", &rip_image)) { mfdb(&Rip_bild, (int *) rip_image.addr, rip_image.img_w, rip_image.img_h, 1, rip_image.planes); transform_img(&Rip_bild); } ub_lines.ub_code = draw_rip; } else ub_lines.ub_code = draw_lines; z_ob[LINESLIST].ob_spec.userblk = &ub_lines; breite = 16; v_set_text(text_font.id, text_font.size, BLACK, 0, 0, NULL); for (i = 0; i < Anz_text_lines; i++) { int eout[8]; vqt_extent(x_handle, text_lines[i], eout); Max(&breite, eout[4]); } scroll_menu.px_vline = text_font.ch; scroll_menu.px_hline = text_font.cw; mar_di_mode = mar_set_inv_win(Anz_text_lines, breite); tmp_button = ob_get_text(z_ob, QLINE, 0); ob_set_text(z_ob, QLINE, strOk); ob_undoflag(z_ob, LINESLIST, TOUCHEXIT); Event_Handler(Text_Init, Text_Handler); if ((dlg_info = open_dialog(z_ob, strText, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL)) != NULL) { WIN *ptr_win = dlg_info->di_win; ptr_win->scroll = &scroll_menu; mar_menu_set_slider(ptr_win); WindowItems(ptr_win, SCROLL_KEYS, scroll_keys); if ((d_exit = X_Form_Do(NULL)) != W_ABANDON) { my_close_dialog(dlg_info, FALSE); if (d_exit != W_CLOSED) ob_undostate(z_ob, d_exit & NO_CLICK, SELECTED); } } Event_Handler(NULL, NULL); ob_set_text(z_ob, QLINE, tmp_button); break; case NHW_MENU: if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); z_ob = zz_oblist[LINES]; scroll_menu.vsize = Anz_inv_lines; scroll_menu.vpos = 0; z_ob[LINESLIST].ob_spec.userblk = &ub_inventory; if ((Menu_title) && (wind != WIN_INVEN)) /* because I sets no Menu_title */ Max(&Inv_breite, gr_cw * strlen(Menu_title) + 16); scroll_menu.px_vline = menu_font.ch; scroll_menu.px_hline = menu_font.cw; mar_di_mode = mar_set_inv_win(Anz_inv_lines, Inv_breite, NHW_MENU); tmp_button = ob_get_text(z_ob, QLINE, 0); ob_set_text(z_ob, QLINE, Inv_how != PICK_NONE ? strCancel : strOk); ob_doflag(z_ob, LINESLIST, TOUCHEXIT); Event_Handler(Inv_Init, Inv_Handler); if ((Inv_dialog = open_dialog(z_ob, (wind == WIN_INVEN) ? "Inventory" : (Menu_title ? Menu_title : "Staun"), NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL)) != NULL) { WIN *ptr_win = Inv_dialog->di_win; ptr_win->scroll = &scroll_menu; mar_menu_set_slider(ptr_win); WindowItems(ptr_win, SCROLL_KEYS, scroll_keys); do { int y_wo, x_wo, ru_w = 1, ru_h = 1; GRECT oarea; Gem_menu_item *it; d_exit = X_Form_Do(NULL); if ((d_exit & NO_CLICK) == LINESLIST) { ob_pos(z_ob, LINESLIST, &oarea); if (mouse(&x_wo, &y_wo) && Inv_how == PICK_ANY) { graf_rt_rubberbox(FALSE, x_wo, y_wo, FAIL, FAIL, &oarea, &ru_w, &ru_h, NULL); invert_all_on_page( (int) ((y_wo - oarea.g_y) / menu_font.ch + scroll_menu.vpos), (ru_h + menu_font.ch - 1) / menu_font.ch, 0); } else { for (it = invent_list, i = 0; i < ((y_wo - oarea.g_y) / menu_font.ch + scroll_menu.vpos) && it; it = it->Gmi_next, i++) ; if (it && it->Gmi_identifier) { it->Gmi_selected = !it->Gmi_selected; it->Gmi_count = count == 0L ? -1L : count; count = 0L; if (Inv_how != PICK_ANY) break; } /* identifier */ } oarea.g_x = (oarea.g_x + 23 + 2 * menu_font.cw) & ~7; oarea.g_y = y_wo - (y_wo - oarea.g_y) % menu_font.ch; oarea.g_w = menu_font.cw; oarea.g_h = ((ru_h + menu_font.ch - 1) / menu_font.ch) * menu_font.ch; ob_draw_chg(Inv_dialog, LINESLIST, &oarea, FAIL); } if (Inv_how == PICK_ANY) { ob_set_text(Inv_dialog->di_tree, QLINE, strCancel); for (it = invent_list; it; it = it->Gmi_next) if (it->Gmi_identifier && it->Gmi_selected) { ob_set_text(Inv_dialog->di_tree, QLINE, strOk); break; } ob_draw_chg(Inv_dialog, QLINE, NULL, FAIL); } } while ((d_exit & NO_CLICK) == LINESLIST); if (d_exit != W_ABANDON) { my_close_dialog(Inv_dialog, FALSE); if (d_exit != W_CLOSED) ob_undostate(z_ob, d_exit & NO_CLICK, SELECTED); } } Event_Handler(NULL, NULL); ob_set_text(z_ob, QLINE, tmp_button); break; case NHW_MAP: if (p_Gw->gw_window == NULL) { calc_std_winplace(NHW_MAP, &p_Gw->gw_place); window_border(MAP_GADGETS, 0, 0, Tile_width * (COLNO - 1), Tile_heigth * ROWNO, &g_mapmax); p_Gw->gw_window = open_window( md, md, NULL, zz_oblist[NHICON], MAP_GADGETS, TRUE, 128, 128, &g_mapmax, &p_Gw->gw_place, &scroll_map, win_draw_map, NULL, XM_TOP | XM_BOTTOM | XM_SIZE); WindowItems(p_Gw->gw_window, SCROLL_KEYS - 1, scroll_keys); /* ClrHome centers on u */ mar_clear_map(); } if (p_Gw->gw_dirty) { area.g_x = p_Gw->gw_window->work.g_x + scroll_map.px_hline * (dirty_map_area.g_x - scroll_map.hpos); area.g_y = p_Gw->gw_window->work.g_y + scroll_map.px_vline * (dirty_map_area.g_y - scroll_map.vpos); area.g_w = (dirty_map_area.g_w - dirty_map_area.g_x + 1) * scroll_map.px_hline; area.g_h = (dirty_map_area.g_h - dirty_map_area.g_y + 1) * scroll_map.px_vline; redraw_window(p_Gw->gw_window, &area); dirty_map_area.g_x = COLNO - 1; dirty_map_area.g_y = ROWNO; dirty_map_area.g_w = dirty_map_area.g_h = 0; } break; case NHW_MESSAGE: if (p_Gw->gw_window == NULL) { calc_std_winplace(NHW_MESSAGE, &p_Gw->gw_place); z_ob = zz_oblist[MSGWIN]; magx = 0; /* MAR -- Fake E_GEM to remove Backdropper */ p_Gw->gw_window = open_window( NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP | XM_BOTTOM | XM_SIZE); magx = tmp_magx; window_size(p_Gw->gw_window, &p_Gw->gw_window->curr); p_Gw->gw_dirty = TRUE; } if (p_Gw->gw_dirty) { ob_pos(zz_oblist[MSGWIN], MSGLINES, &area); while (messages_pro_zug > 3) { messages_pro_zug -= 3; msg_pos += 3; redraw_window(p_Gw->gw_window, &area); mar_more(); } msg_pos += messages_pro_zug; messages_pro_zug = 0; if (msg_pos > msg_max) msg_pos = msg_max; redraw_window(p_Gw->gw_window, &area); mar_message_pause = FALSE; } break; case NHW_STATUS: if (p_Gw->gw_window == NULL) { z_ob = zz_oblist[STATUSLINE]; calc_std_winplace(NHW_STATUS, &p_Gw->gw_place); magx = 0; /* MAR -- Fake E_GEM to remove Backdropper */ p_Gw->gw_window = open_window( NULL, NULL, NULL, NULL, 0, FALSE, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP | XM_BOTTOM | XM_SIZE); magx = tmp_magx; /* Because 2*status_font.ch is smaller then e_gem expects the * minimum win_height */ p_Gw->gw_window->min_h = z_ob[ROOT].ob_height; window_size(p_Gw->gw_window, &p_Gw->gw_place); p_Gw->gw_dirty = TRUE; add_dirty_rect(dr_stat, &p_Gw->gw_place); } while (get_dirty_rect(dr_stat, &area)) { area.g_x = (area.g_x + p_Gw->gw_window->work.g_x + 2 * status_font.cw + 6) & ~7; area.g_y += p_Gw->gw_window->work.g_y; redraw_window(p_Gw->gw_window, &area); } break; default: if (p_Gw->gw_dirty) redraw_window(p_Gw->gw_window, NULL); } p_Gw->gw_dirty = FALSE; } /************************* create_window *******************************/ int mar_hol_win_type(window) winid window; { return (Gem_nhwindow[window].gw_type); } winid mar_create_window(type) int type; { winid newid; static char name[] = "Gem"; int i; struct gw *p_Gw = &Gem_nhwindow[0]; for (newid = 0; p_Gw->gw_type && newid < MAXWIN; newid++, p_Gw++) ; switch (type) { case NHW_MESSAGE: message_line = (char **) m_alloc(msg_anz * sizeof(char *)); message_age = (int *) m_alloc(msg_anz * sizeof(int)); for (i = 0; i < msg_anz; i++) { message_age[i] = FALSE; message_line[i] = (char *) m_alloc((MSGLEN + 1) * sizeof(char)); *message_line[i] = 0; } dr_msg = new_dirty_rect(10); if (!dr_msg) panic("Memory allocation failure (dr_msg)"); break; case NHW_STATUS: status_line = (char **) m_alloc(2 * sizeof(char *)); for (i = 0; i < 2; i++) { status_line[i] = (char *) m_alloc(status_w * sizeof(char)); memset(status_line[i], 0, status_w); } dr_stat = new_dirty_rect(10); if (!dr_stat) panic("Memory allocation failure (dr_stat)"); break; case NHW_MAP: map_glyphs = (char **) m_alloc((long) ROWNO * sizeof(char *)); for (i = 0; i < ROWNO; i++) { map_glyphs[i] = (char *) m_alloc((long) COLNO * sizeof(char)); *map_glyphs[i] = map_glyphs[i][COLNO - 1] = 0; } dr_map = new_dirty_rect(10); if (!dr_map) panic("Memory allocation failure (dr_map)"); mar_clear_map(); break; case NHW_MENU: case NHW_TEXT: /* They are no more treated as dialog */ break; default: p_Gw->gw_window = open_window( "Sonst", name, NULL, NULL, NAME | MOVER | CLOSER, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, NULL, NULL, XM_TOP | XM_BOTTOM | XM_SIZE); break; } p_Gw->gw_type = type; return (newid); } void mar_change_menu_2_text(win) winid win; { Gem_nhwindow[win].gw_type = NHW_TEXT; } /************************* mar_clear_map *******************************/ void mar_clear_map() { int pla[8]; int x, y; pla[0] = pla[1] = pla[4] = pla[5] = 0; pla[2] = pla[6] = scroll_map.px_hline * (COLNO - 1) - 1; pla[3] = pla[7] = scroll_map.px_vline * ROWNO - 1; for (y = 0; y < ROWNO; y++) for (x = 0; x < COLNO - 1; x++) map_glyphs[y][x] = ' '; vro_cpyfm(x_handle, ALL_BLACK, pla, &Tile_bilder, &Map_bild); /* MAR -- 17.Mar 2002 Hmm, what if FontCol_Bild is bigger? */ if (WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window) redraw_window(Gem_nhwindow[WIN_MAP].gw_window, NULL); } /************************* destroy_window *******************************/ void mar_destroy_nhwindow(window) winid window; { int i; switch (Gem_nhwindow[window].gw_type) { case NHW_TEXT: for (i = 0; i < Anz_text_lines; i++) free(text_lines[i]); null_free(text_lines); Anz_text_lines = 0; use_rip = FALSE; break; case NHW_MENU: Gem_start_menu(window); /* delete invent_list */ test_free(Menu_title); break; case 0: /* No window available, probably an error message? */ break; default: close_window(Gem_nhwindow[window].gw_window, 0); break; } Gem_nhwindow[window].gw_window = NULL; Gem_nhwindow[window].gw_type = 0; Gem_nhwindow[window].gw_dirty = FALSE; if (window == WIN_MAP) { for (i = 0; i < ROWNO; i++) { free(map_glyphs[i]); } null_free(map_glyphs); WIN_MAP = WIN_ERR; } if (window == WIN_STATUS) { for (i = 0; i < 2; i++) free(status_line[i]); null_free(status_line); WIN_STATUS = WIN_ERR; } if (window == WIN_MESSAGE) { for (i = 0; i < msg_anz; i++) free(message_line[i]); null_free(message_line); null_free(message_age); WIN_MESSAGE = WIN_ERR; } if (window == WIN_INVEN) WIN_INVEN = WIN_ERR; } /************************* nh_poskey *******************************/ void mar_set_margin(int m) { Max(&m, 0); Min(&m, min(ROWNO, COLNO)); /* MAR 16.Mar 2002 -- the larger the less sense */ scroll_margin = m; } void mar_cliparound() { if (WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window) { int breite = scroll_margin > 0 ? scroll_margin : max(scroll_map.hpage / 4, 1), hoehe = scroll_margin > 0 ? scroll_margin : max(scroll_map.vpage / 4, 1), adjust_needed; adjust_needed = FALSE; if ((map_cursx < scroll_map.hpos + breite) || (map_cursx >= scroll_map.hpos + scroll_map.hpage - breite)) { scroll_map.hpos = map_cursx - scroll_map.hpage / 2; adjust_needed = TRUE; } if ((map_cursy < scroll_map.vpos + hoehe) || (map_cursy >= scroll_map.vpos + scroll_map.vpage - hoehe)) { scroll_map.vpos = map_cursy - scroll_map.vpage / 2; adjust_needed = TRUE; } if (adjust_needed) scroll_window(Gem_nhwindow[WIN_MAP].gw_window, WIN_SCROLL, NULL); } } void mar_update_value() { if (WIN_MESSAGE != WIN_ERR) { mar_message_pause = FALSE; mar_esc_pressed = FALSE; mar_display_nhwindow(WIN_MESSAGE); } if (WIN_MAP != WIN_ERR) mar_cliparound(); if (WIN_STATUS != WIN_ERR) { mar_check_hilight_status(); mar_display_nhwindow(WIN_STATUS); } } int Main_Init(xev, availiable) XEVENT *xev; int availiable; { xev->ev_mb1mask = xev->ev_mb1state = 1; xev->ev_mb1clicks = xev->ev_mb2clicks = xev->ev_mb2mask = xev->ev_mb2state = 2; return ((MU_KEYBD | MU_BUTTON1 | MU_BUTTON2 | MU_MESAG) & availiable); } /* * return a key, or 0, in which case a mouse button was pressed * mouse events should be returned as character postitions in the map window. */ /*ARGSUSED*/ int mar_nh_poskey(x, y, mod) int *x, *y, *mod; { static XEVENT xev; int retval, ev; xev.ev_mflags = Main_Init(&xev, 0xFFFF); ev = Event_Multi(&xev); retval = FAIL; if (ev & MU_KEYBD) { char ch = xev.ev_mkreturn & 0x00FF; char scan = (xev.ev_mkreturn & 0xff00) >> 8; int shift = xev.ev_mmokstate; const struct pad *kpad; /* Translate keypad keys */ if (iskeypad(scan)) { kpad = mar_iflags_numpad() == 1 ? numpad : keypad; if (shift & K_SHIFT) ch = kpad[scan - KEYPADLO].shift; else if (shift & K_CTRL) { if (scan >= 0x67 && scan <= 0x6f && scan != 0x6b) { send_key(kpad[scan - KEYPADLO].normal); ch = 'g'; } else { ch = kpad[scan - KEYPADLO].cntrl; } } else ch = kpad[scan - KEYPADLO].normal; } if (scan == SCANHOME) mar_cliparound(); else if (scan == SCANF1) retval = 'h'; else if (scan == SCANF2) { mar_set_tile_mode(!mar_set_tile_mode(FAIL)); retval = C('l'); /* trigger full-redraw */ } else if (scan == SCANF3) { draw_cursor = !draw_cursor; mar_curs(map_cursx, map_cursy); mar_display_nhwindow(WIN_MAP); } else if (scan == SCANF4) { /* Font-Selector */ if (!CallFontSelector(0, FAIL, FAIL, FAIL, FAIL)) { xalert(1, 1, X_ICN_ALERT, NULL, SYS_MODAL, BUTTONS_RIGHT, TRUE, "Hello", "Fontselector not available!", NULL); } } else if (!ch && shift & K_CTRL && scan == -57) { /* MAR -- nothing ignore Ctrl-Alt-Clr/Home == MagiC's restore * screen */ } else { if (!ch) ch = (char) M(tolower(scan_2_ascii(xev.ev_mkreturn, shift))); if (((int) ch) == -128) ch = '\033'; retval = ch; } } if (ev & MU_BUTTON1 || ev & MU_BUTTON2) { int ex = xev.ev_mmox, ey = xev.ev_mmoy; WIN *akt_win = window_find(ex, ey); if (WIN_MAP != WIN_ERR && akt_win == Gem_nhwindow[WIN_MAP].gw_window) { *x = max(min((ex - akt_win->work.g_x) / scroll_map.px_hline + scroll_map.hpos, COLNO - 1), 0) + 1; *y = max(min((ey - akt_win->work.g_y) / scroll_map.px_vline + scroll_map.vpos, ROWNO), 0); *mod = xev.ev_mmobutton; retval = 0; } else if (WIN_STATUS != WIN_ERR && akt_win == Gem_nhwindow[WIN_STATUS].gw_window) { move_win(akt_win); } else if (WIN_MESSAGE != WIN_ERR && akt_win == Gem_nhwindow[WIN_MESSAGE].gw_window) { message_handler(ex, ey); } } if (ev & MU_MESAG) { int *buf = xev.ev_mmgpbuf; char *str; OBJECT *z_ob = zz_oblist[MENU]; switch (*buf) { case MN_SELECTED: menu_tnormal(z_ob, buf[3], TRUE); /* unselect menu header */ str = ob_get_text(z_ob, buf[4], 0); str += strlen(str) - 2; switch (*str) { case ' ': /* just that command */ retval = str[1]; break; case '\005': /* Alt command */ case '\007': retval = M(str[1]); break; case '^': /* Ctrl command */ retval = C(str[1]); break; case 'f': /* Func Key */ switch (str[1]) { case '1': retval = 'h'; break; case '2': mar_set_tile_mode(!mar_set_tile_mode(FAIL)); retval = C('l'); /* trigger full-redraw */ break; case '3': draw_cursor = !draw_cursor; mar_curs(map_cursx, map_cursy); mar_display_nhwindow(WIN_MAP); break; default: } break; default: mar_about(); break; } break; /* MN_SELECTED */ case WM_CLOSED: WindowHandler(W_ICONIFYALL, NULL, NULL); break; case AP_TERM: retval = 'S'; break; case FONT_CHANGED: if (buf[3] >= 0) { if (buf[3] == Gem_nhwindow[WIN_MESSAGE].gw_window->handle) { mar_set_fontbyid(NHW_MESSAGE, buf[4], buf[5]); mar_display_nhwindow(WIN_MESSAGE); } else if (buf[3] == Gem_nhwindow[WIN_MAP].gw_window->handle) { mar_set_fontbyid(NHW_MAP, buf[4], buf[5]); mar_display_nhwindow(WIN_MAP); } else if (buf[3] == Gem_nhwindow[WIN_STATUS].gw_window->handle) { mar_set_fontbyid(NHW_STATUS, buf[4], buf[5]); mar_display_nhwindow(WIN_STATUS); } FontAck(buf[1], 1); } break; default: break; } } /* MU_MESAG */ if (retval == FAIL) retval = mar_nh_poskey(x, y, mod); return (retval); } int Gem_nh_poskey(x, y, mod) int *x, *y, *mod; { mar_update_value(); return (mar_nh_poskey(x, y, mod)); } void Gem_delay_output() { Event_Timer(50, 0, FALSE); /* wait 50ms */ } int Gem_doprev_message() { if (msg_pos > 2) { msg_pos--; if (WIN_MESSAGE != WIN_ERR) Gem_nhwindow[WIN_MESSAGE].gw_dirty = TRUE; mar_display_nhwindow(WIN_MESSAGE); } return (0); } /************************* print_glyph *******************************/ int mar_set_rogue(int); int mar_set_tile_mode(tiles) int tiles; { static int tile_mode = TRUE; static GRECT prev; WIN *z_w = WIN_MAP != WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL; if (tiles < 0) return (tile_mode); else if (!z_w) tile_mode = tiles; else if (tile_mode == tiles || (mar_set_rogue(FAIL) && tiles)) return (FAIL); else { GRECT tmp; tile_mode = tiles; scroll_map.px_hline = tiles ? Tile_width : map_font.cw; scroll_map.px_vline = tiles ? Tile_heigth : map_font.ch; window_border(MAP_GADGETS, 0, 0, scroll_map.px_hline * (COLNO - 1), scroll_map.px_vline * ROWNO, &tmp); z_w->max.g_w = tmp.g_w; z_w->max.g_h = tmp.g_h; if (tiles) z_w->curr = prev; else prev = z_w->curr; window_reinit(z_w, md, md, NULL, FALSE, FALSE); } return (FAIL); } int mar_set_rogue(what) int what; { static int rogue = FALSE, prev_mode = TRUE; if (what < 0) return (rogue); if (what != rogue) { rogue = what; if (rogue) { prev_mode = mar_set_tile_mode(FAIL); mar_set_tile_mode(FALSE); } else mar_set_tile_mode(prev_mode); } return (FAIL); } void mar_add_pet_sign(window, x, y) winid window; int x, y; { if (window != WIN_ERR && window == WIN_MAP) { static int pla[8] = { 0, 0, 7, 7, 0, 0, 0, 0 }, colindex[2] = { RED, WHITE }; pla[4] = pla[6] = scroll_map.px_hline * x; pla[5] = pla[7] = scroll_map.px_vline * y; pla[6] += 7; pla[7] += 6; vrt_cpyfm(x_handle, MD_TRANS, pla, &Pet_Mark, &Map_bild, colindex); } } void mar_print_glyph(window, x, y, gl, bkgl) winid window; int x, y, gl, bkgl; { if (window != WIN_ERR && window == WIN_MAP) { static int pla[8]; pla[2] = pla[0] = (gl % Tiles_per_line) * Tile_width; pla[3] = pla[1] = (gl / Tiles_per_line) * Tile_heigth; pla[2] += Tile_width - 1; pla[3] += Tile_heigth - 1; pla[6] = pla[4] = Tile_width * x; /* x_wert to */ pla[7] = pla[5] = Tile_heigth * y; /* y_wert to */ pla[6] += Tile_width - 1; pla[7] += Tile_heigth - 1; vro_cpyfm(x_handle, gl != -1 ? S_ONLY : ALL_BLACK, pla, &Tile_bilder, &Map_bild); } } void mar_print_char(window, x, y, ch, col) winid window; int x, y; char ch; int col; { if (window != WIN_ERR && window == WIN_MAP) { static int gem_color[16] = { 9, 2, 11, 10, 4, 7, 8, 15, 0, 14, 3, 6, 5, 13, 15, 0 }; int pla[8], colindex[2]; map_glyphs[y][x] = ch; pla[0] = pla[1] = 0; pla[2] = map_font.cw - 1; pla[3] = map_font.ch - 1; pla[6] = pla[4] = map_font.cw * x; pla[7] = pla[5] = map_font.ch * y; pla[6] += map_font.cw - 1; pla[7] += map_font.ch - 1; colindex[0] = gem_color[col]; colindex[1] = WHITE; vrt_cpyfm(x_handle, MD_REPLACE, pla, &Black_bild, &FontCol_Bild, colindex); } } /************************* getlin *******************************/ void Gem_getlin(ques, input) const char *ques; char *input; { OBJECT *z_ob = zz_oblist[LINEGET]; int d_exit, length; char *pr[2], *tmp; if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); z_ob[LGPROMPT].ob_type = G_USERDEF; z_ob[LGPROMPT].ob_spec.userblk = &ub_prompt; z_ob[LGPROMPT].ob_height = 2 * gr_ch; length = z_ob[LGPROMPT].ob_width / gr_cw; if (strlen(ques) > length) { tmp = ques + length; while (*tmp != ' ' && tmp >= ques) { tmp--; } if (tmp <= ques) tmp = ques + length; /* Mar -- Oops, what a word :-) */ pr[0] = ques; *tmp = 0; pr[1] = ++tmp; } else { pr[0] = ques; pr[1] = NULL; } ub_prompt.ub_parm = (long) pr; ob_clear_edit(z_ob); d_exit = xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE); Event_Timer(0, 0, TRUE); if (d_exit == W_CLOSED || d_exit == W_ABANDON || (d_exit & NO_CLICK) == QLG) { *input = '\033'; input[1] = 0; } else strncpy(input, ob_get_text(z_ob, LGREPLY, 0), length); } /************************* ask_direction *******************************/ #define Dia_Init K_Init int Dia_Handler(xev) XEVENT *xev; { int ev = xev->ev_mwich; char ch = (char) (xev->ev_mkreturn & 0x00FF); if (ev & MU_KEYBD) { WIN *w; DIAINFO *dinf; switch (ch) { case 's': send_key((int) (mar_iflags_numpad() ? '5' : '.')); break; case '.': send_key('5'); /* MAR -- '.' is a button if numpad isn't set */ break; case '\033': /*ESC*/ if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) && dinf->di_tree == zz_oblist[DIRECTION]) { my_close_dialog(dinf, FALSE); break; } /* Fall thru */ default: ev &= ~MU_KEYBD; /* let the dialog handle it */ break; } } return (ev); } int mar_ask_direction() { int d_exit; OBJECT *z_ob = zz_oblist[DIRECTION]; Event_Handler(Dia_Init, Dia_Handler); mar_set_dir_keys(); d_exit = xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE); Event_Timer(0, 0, TRUE); Event_Handler(NULL, NULL); if (d_exit == W_CLOSED || d_exit == W_ABANDON) return ('\033'); if ((d_exit & NO_CLICK) == DIRDOWN) return ('>'); if ((d_exit & NO_CLICK) == DIRUP) return ('<'); if ((d_exit & NO_CLICK) == (DIR1 + 8)) /* 5 or . */ return ('.'); return (*ob_get_text(z_ob, d_exit & NO_CLICK, 0)); } /************************* yn_function *******************************/ #define any_init M_Init static int any_handler(xev) XEVENT *xev; { int ev = xev->ev_mwich; if (ev & MU_MESAG) { int *buf = xev->ev_mmgpbuf; if (*buf == OBJC_EDITED) my_close_dialog(*(DIAINFO **) &buf[4], FALSE); else ev &= ~MU_MESAG; } return (ev); } int send_yn_esc(char ch) { static char esc_char = 0; if (ch < 0) { if (esc_char) { send_key((int) esc_char); return (TRUE); } return (FALSE); } else esc_char = ch; return (TRUE); } #define single_init K_Init static int single_handler(xev) XEVENT *xev; { int ev = xev->ev_mwich; if (ev & MU_KEYBD) { char ch = (char) xev->ev_mkreturn & 0x00FF; WIN *w; DIAINFO *dinf; switch (ch) { case ' ': send_return(); break; case '\033': if ((w = get_top_window()) && (dinf = (DIAINFO *) w->dialog) && dinf->di_tree == zz_oblist[YNCHOICE]) { if (!send_yn_esc(FAIL)) my_close_dialog(dinf, FALSE); break; } /* Fall thru */ default: ev &= ~MU_MESAG; } } return (ev); } char Gem_yn_function(query, resp, def) const char *query, *resp; char def; { OBJECT *z_ob = zz_oblist[YNCHOICE]; int d_exit, i, len; long anzahl; char *tmp; const char *ptr; if (WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); /* if query for direction the special dialog */ if (strstr(query, "irect")) return (mar_ask_direction()); len = min(strlen(query), (max_w - 8 * gr_cw) / gr_cw); z_ob[ROOT].ob_width = (len + 8) * gr_cw; z_ob[YNPROMPT].ob_width = gr_cw * len + 8; tmp = ob_get_text(z_ob, YNPROMPT, 0); ob_set_text(z_ob, YNPROMPT, mar_copy_of(query)); if (resp) { /* single inputs */ ob_hide(z_ob, SOMECHARS, FALSE); ob_hide(z_ob, ANYCHAR, TRUE); if (strchr(resp, 'q')) send_yn_esc('q'); else if (strchr(resp, 'n')) send_yn_esc('n'); else send_yn_esc( def); /* strictly def should be returned, but in trad. I it's 0 */ if (strchr(resp, '#')) { /* count possible */ ob_hide(z_ob, YNOK, FALSE); ob_hide(z_ob, COUNT, FALSE); } else { /* no count */ ob_hide(z_ob, YNOK, TRUE); ob_hide(z_ob, COUNT, TRUE); } if ((anzahl = (long) strchr(resp, '\033'))) { anzahl -= (long) resp; } else { anzahl = strlen(resp); } for (i = 0, ptr = resp; i < 2 * anzahl; i += 2, ptr++) { ob_hide(z_ob, YN1 + i, FALSE); mar_change_button_char(z_ob, YN1 + i, *ptr); ob_undoflag(z_ob, YN1 + i, DEFAULT); if (*ptr == def) ob_doflag(z_ob, YN1 + i, DEFAULT); } z_ob[SOMECHARS].ob_width = z_ob[YN1 + i].ob_x + 8; z_ob[SOMECHARS].ob_height = z_ob[YN1 + i].ob_y + gr_ch + gr_ch / 2; Max((int *) &z_ob[ROOT].ob_width, z_ob[SOMECHARS].ob_width + 4 * gr_cw); z_ob[ROOT].ob_height = z_ob[SOMECHARS].ob_height + 4 * gr_ch; if (strchr(resp, '#')) z_ob[ROOT].ob_height = z_ob[YNOK].ob_y + 2 * gr_ch; for (i += YN1; i < (YNN + 1); i += 2) { ob_hide(z_ob, i, TRUE); } Event_Handler(single_init, single_handler); } else { /* any input */ ob_hide(z_ob, SOMECHARS, TRUE); ob_hide(z_ob, ANYCHAR, FALSE); ob_hide(z_ob, YNOK, TRUE); ob_hide(z_ob, COUNT, TRUE); z_ob[ANYCHAR].ob_height = 2 * gr_ch; z_ob[CHOSENCH].ob_y = z_ob[CHOSENCH + 1].ob_y = gr_ch / 2; z_ob[ROOT].ob_width = max(z_ob[YNPROMPT].ob_width + z_ob[YNPROMPT].ob_x, z_ob[ANYCHAR].ob_width + z_ob[ANYCHAR].ob_x) + 2 * gr_cw; z_ob[ROOT].ob_height = z_ob[ANYCHAR].ob_height + z_ob[ANYCHAR].ob_y + gr_ch / 2; *ob_get_text(z_ob, CHOSENCH, 0) = '?'; Event_Handler(any_init, any_handler); } d_exit = xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE); Event_Timer(0, 0, TRUE); Event_Handler(NULL, NULL); /* display of count is missing (through the core too) */ free(ob_get_text(z_ob, YNPROMPT, 0)); ob_set_text(z_ob, YNPROMPT, tmp); if (resp && (d_exit == W_CLOSED || d_exit == W_ABANDON)) return ('\033'); if ((d_exit & NO_CLICK) == YNOK) { yn_number = atol(ob_get_text(z_ob, COUNT, 0)); return ('#'); } if (!resp) return (*ob_get_text(z_ob, CHOSENCH, 0)); return (*ob_get_text(z_ob, d_exit & NO_CLICK, 0)); } /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in X11/winmenu.c. */ static char * mar_copy_of(s) const char *s; { if (!s) s = nullstr; return strcpy((char *) m_alloc((unsigned) (strlen(s) + 1)), s); } const char *strRP = "raw_print", *strRPB = "raw_print_bold"; void mar_raw_print(str) const char *str; { xalert(1, FAIL, X_ICN_INFO, NULL, APPL_MODAL, BUTTONS_CENTERED, TRUE, strRP, str, NULL); } void mar_raw_print_bold(str) const char *str; { char buf[BUFSZ]; sprintf(buf, "!%s", str); xalert(1, FAIL, X_ICN_INFO, NULL, APPL_MODAL, BUTTONS_CENTERED, TRUE, strRPB, buf, NULL); } /*wingem1.c*/ nethack-3.6.0/win/gem/xpm2img.c0000664000076400007660000001256212536476415015254 0ustar paxedpaxed/* NetHack 3.6 xpm2img.c $NHDT-Date: 1432512809 2015/05/25 00:13:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Christian Bressler 2002 */ /* NetHack may be freely redistributed. See license for details. */ /* This is mainly a reworked tile2bmp.c + xpm2iff.c -- Marvin */ #include #include #include #include "bitmfile.h" #define TRUE 1 #define FALSE 0 void get_color(unsigned int colind, struct RGB *rgb); void get_pixel(int x, int y, unsigned int *colind); char *xpmgetline(); unsigned int **Bild_daten; /* translation table from xpm characters to RGB and colormap slots */ struct Ttable { char flag; struct RGB col; int slot; /* output colortable index */ } ttable[256]; struct RGB *ColorMap; int num_colors = 0; int width = 0, height = 0; int initflag; FILE *fp; int main(argc, argv) int argc; char *argv[]; { int i; int row, col, planeno; int farben, planes; if (argc != 3) { fprintf(stderr, "usage: tile2img infile.xpm outfile.img\n"); exit(EXIT_FAILURE); } initflag = 0; fp = fopen(argv[2], "wb"); if (!fp) { printf("Error creating IMG-file %s, aborting.\n", argv[2]); exit(EXIT_FAILURE); } fclose(fp); if (fopen_xpm_file(argv[1], "r") != TRUE) { printf("Error reading xpm-file %s, aborting.\n", argv[1]); exit(EXIT_FAILURE); } Bild_daten = (unsigned int **) malloc((long) height * sizeof(unsigned int *)); for (i = 0; i < height; i++) Bild_daten[i] = (unsigned int *) malloc((long) width * sizeof(unsigned int)); for (row = 0; row < height; row++) { char *xb = xpmgetline(); int plane_offset; if (xb == 0) { printf("Error to few lines in xpm-file %s, aborting.\n", argv[1]); exit(EXIT_FAILURE); } for (col = 0; col < width; col++) { int color = xb[col]; if (!ttable[color].flag) fprintf(stderr, "Bad image data\n"); Bild_daten[row][col] = ttable[color].slot; } } if (num_colors > 256) { fprintf(stderr, "ERROR: zuviele Farben\n"); exit(EXIT_FAILURE); } else if (num_colors > 16) { farben = 256; planes = 8; } else if (num_colors > 2) { farben = 16; planes = 4; } else { farben = 2; planes = 1; } bitmap_to_file(XIMG, width, height, 372, 372, planes, farben, argv[2], get_color, get_pixel); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } void get_color(unsigned int colind, struct RGB *rgb) { rgb->r = (1000L * (long) ColorMap[colind].r) / 0xFF; rgb->g = (1000L * (long) ColorMap[colind].g) / 0xFF; rgb->b = (1000L * (long) ColorMap[colind].b) / 0xFF; } void get_pixel(int x, int y, unsigned int *colind) { *colind = Bild_daten[y][x]; } FILE *xpmfh = 0; char initbuf[200]; char *xpmbuf = initbuf; /* version 1. Reads the raw xpm file, NOT the compiled version. This is * not a particularly good idea but I don't have time to do the right thing * at this point, even if I was absolutely sure what that was. */ fopen_xpm_file(const char *fn, const char *mode) { int temp; char *xb; if (strcmp(mode, "r")) return FALSE; /* no choice now */ if (xpmfh) return FALSE; /* one file at a time */ xpmfh = fopen(fn, mode); if (!xpmfh) return FALSE; /* I'm hard to please */ /* read the header */ xb = xpmgetline(); if (xb == 0) return FALSE; if (4 != sscanf(xb, "%d %d %d %d", &width, &height, &num_colors, &temp)) return FALSE; /* bad header */ /* replace the original buffer with one big enough for * the real data */ /* XXX */ xpmbuf = malloc(width * 2); if (!xpmbuf) { fprintf(stderr, "ERROR: Can't allocate line buffer\n"); exit(1); } if (temp != 1) return FALSE; /* limitation of this code */ { /* read the colormap and translation table */ int ccount = -1; ColorMap = (struct RGB *) malloc((long) num_colors * sizeof(struct RGB)); while (ccount++ < (num_colors - 1)) { char index; int r, g, b; xb = xpmgetline(); if (xb == 0) return FALSE; if (4 != sscanf(xb, "%c c #%2x%2x%2x", &index, &r, &g, &b)) { fprintf(stderr, "Bad color entry: %s\n", xb); return FALSE; } ttable[index].flag = 1; /* this color is valid */ ttable[index].col.r = r; ttable[index].col.g = g; ttable[index].col.b = b; ttable[index].slot = ccount; ColorMap[ccount].r = r; ColorMap[ccount].g = g; ColorMap[ccount].b = b; } } return TRUE; } /* This deserves better. Don't read it too closely - you'll get ill. */ #define bufsz 2048 char buf[bufsz]; char * xpmgetline() { char *bp; do { if (fgets(buf, bufsz, xpmfh) == 0) return 0; } while (buf[0] != '"'); /* strip off the trailing <",> if any */ for (bp = buf; *bp; bp++) ; bp--; while (isspace(*bp)) bp--; if (*bp == ',') bp--; if (*bp == '"') bp--; bp++; *bp = '\0'; return &buf[1]; } nethack-3.6.0/win/gnome/README0000664000076400007660000000331312467321052014721 0ustar paxedpaxedThis directory contains the windowing code written for GnomeHack. The NetHack devteam is in the process of making it part of the normal distribution. It should be noted that this is still work in progress and that there are still problems with this code. So use at your own risk. Of course any contributions, especially bug fixes, are more than welcome! These files are based on the files from GnomeHack 1.0.5 by Erik Andersen. Some files have been renamed to fit into 8.3 name constraints (yuk!). These are: GnomeHack.h gnomeprv.h GnomeHackAskStringDialog.c gnaskstr.c GnomeHackAskStringDialog.h gnaskstr.h GnomeHackBind.c gnbind.c GnomeHackBind.h gnbind.h GnomeHackGlyph.c gnglyph.c GnomeHackGlyph.h gnglyph.h GnomeHackMainWindow.c gnmain.c GnomeHackMainWindow.h gnmain.h GnomeHackMapWindow.c gnmap.c GnomeHackMapWindow.h gnmap.h GnomeHackMenuWindow.c gnmenu.c GnomeHackMenuWindow.h gnmenu.h GnomeHackMessageWindow.c gnmesg.c GnomeHackMessageWindow.h gnmesg.h GnomeHackPlayerSelDialog.c gnplayer.c GnomeHackPlayerSelDialog.h gnplayer.h GnomeHackSettings.c gnopts.c GnomeHackSettings.h gnopts.h GnomeHackSignals.c gnsignal.c GnomeHackSignals.h gnsignal.h GnomeHackStatusWindow.c gnstatus.c GnomeHackStatusWindow.h gnstatus.h GnomeHackTextWindow.c gntext.c GnomeHackTextWindow.h gntext.h GnomeHackYesNoDialog.c gnyesno.c GnomeHackYesNoDialog.h gnyesno.h Other files have been removed because we don't or can't use them (yet). Makefile.am Makefile.in gnomehack.desktop gnomehack.desktop.in NetHack currently doesn't use autoconf, so the setup for that has not made the translation. Note: All loss in style, elegance, and readability is entirely our fault and not Erik's. nethack-3.6.0/win/gnome/gn_xpms.h0000664000076400007660000014007512536476415015707 0ustar paxedpaxed/* NetHack 3.6 gn_xpms.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ /* These XPMs are the artwork of Warwick Allison * . They have been borrowed from * the most excellent NetHackQt, until such time as * we can come up with something better. * * More information about NetHackQt can be had from: * http://www.troll.no/~warwick/nethack/ */ /* clang-format off */ /* XPM */ static char *blind_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 5 1", /* colors */ " c #000000", ". c None", "X c #909090", "o c #606060", "O c #303030", /* pixels */ "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "....ooooooooooooooooooooooooooooooooX...", ".... o...", ".... o...", ".... o...", ".... o...", "......o ..o ......", "......X O..X O......", "....... o... o......", ".......o ....o .......", "........O X.....O X.......", ".........O X.......O X........", "..........o OX.........o OX.........", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................" }; /* XPM */ static char *cha_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c None", "@ c #B0B0B0", "# c #F82C24", "$ c #F89E6C", "% c #FF0000", "& c #909090", "* c #FFFFFF", "= c #CEAA90", "- c #DADAB6", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++=#%#=+=#%% ++++++++++++++", "++++++++++++++ %O%%%#%$$%o%=++++++++++++", "+++++++++++++# +#%%o%%o%%%%% +++++++++++", "+++++++++++ %%%%%%%%%%%%%%%%o#=+++++++++", "+++++++++ o%%%%%%%%%%%%%%%%%%%%# +++++++", "++++++ #%%%%%%o%%%o%%o%%o%o%%%%%o%o +++", "++=#%%o%%%#= =*+**O*+**O*+- = =%%%%#@+++", "++++ %=++*+*+**O****O****O*O*O*OO%=+++++", "+++++.%=OO+*O*OO****+****+*O*+O&%=@+++++", "++++++=%=*OO+**O**O*O**O*O*OO+$%=+++++++", "+++++++#% +*OOOO****+****@O+*#%=++++++++", "++++++++#%#*+**+O+OO+O+OOO*O#o#+++++++++", "+++++++++o% O**+****O****O*#%%=+++++++++", "+++++++++ %%#O*O****+****+ %o#++++++++++", "++++++++++o%% XO*O**O*O**#%%%+++++++++++", "++++++++++ %%%o%$-**+**$%%%%=+++++++++++", "+++++++++++o%%$X$%%%%%%#= o#++++++++++++", "++++++++++@ %%%o#O$$+$$$%%%=++++++++++++", "++++++++++++#o%%%%%%%%o%%%=@++++++++++++", "+++++++++++++ %%%%%%%%%%o=++++++++++++++", "+++++++++++++++= & & @++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static char *chaotic_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 9 1", /* colors */ " c #000000", ". c #5C7A7A", "X c None", "o c #B0B0B0", "O c #909090", "+ c #788C8C", "@ c #606060", "# c #FFFFFF", "$ c #303030", /* pixels */ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX@$ @XXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXX$$+#X$ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXXX@$#o @XXXXXXXXX", "XXXXXXXXXXXXXXXXXX$XX OXXXXXXXX", "XXXXXXXXXXXXXXXXX@ # $@$ $XXXXXXXX", "XXXXXXXXXXXXXXXXX@.+ $XXXO @XXXXXXX", "XXXXXXXXXXXXXXXXX O@ XXXXX@ @XXXXXXX", "XXXXXXXXXXXXXXXXX @O $XXXXX@$ @XXXXXXX", "XXXXXXXXXXXXXXXXX O+ @XXXXO++ @XXXXXXX", "XXXXXXXXXXXXXXXXX @+ $@OXO$#$ XXXXXXXX", "XXXXXXXXXXXXXXXXX O@ $ @$Xo $XXXXXXXX", "XXXXXXXXXXXXXXXXX +O $X##+ $XXXXXXXXX", "XXXXXXXXXXXXXXXXX +@ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXX oO $XXXXXXXXXXX", "XXXXXXXXO@@@@@ +# $XXXXXXXXXXXX", "XXXXXXO +o########$ $@XXXXXXXXX", "XXXXXX +#+.$XXXXXXXX", "XXXXXX @O @XXXXXXX", "XXXXXX$ $@ $@@$ @XXXXXXX", "XXXXXXX@@@@XXXXXX + @XXXX@$ OXXXXXXX", "XXXXXXXXXXXXXXXX@ # @XXXXXXX@@OXXXXXXXX", "XXXXXXXXXXXXXXXX@.+ @XXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX$O@ XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX @O XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX #$ @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # OXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@.X XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX ++ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @+ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX O@ @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX +O @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX$ OXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX@@OXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ static char *cns_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #F85848", "X c #949E9E", "o c #F8B090", "O c #E00028", "+ c #7C3400", "@ c None", "# c #B0B0B0", "$ c #F82C24", "% c #F89E6C", "& c #FF0000", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #C80050", "> c #CEAA90", ", c #303030", "< c #FFB691", /* pixels */ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@.oo.o$ ;@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@>.o.%%O,@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@$oo.o. ,@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@.oo$oo+ =@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@..o&oo$ ,@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@#.o.oo. =@.$%@@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o..oo& O.%ooo@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.&%o.$oo%O++;@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.+$%$o.@@@@@@@@@@@", "@@@@@@@@@@@@@.oo++o%$$ ,@@$.oo@@@@@@@@@@", "@@@@@@@@@@@@>.oo+Oo$o%.@@$oo..-@@@@@@@@@", "@@@@@@@@@@@@..o%;.o&%.$..o%O ++>@@@@@@@@", "@@@@@@@@@@@@>.$O:%o.O::::O* $oooo@@@@@@@", "@@@@@@@@@@@@::::::$$:OO&OO::oo%.;=@@@@@@", "@@@@@@@@@@@.::::::::O&&&&&O::++ ,@@@@@@", "@@@@@@@@@@>:::O&&OO&&&&&&&&:: ;@@@@@", "@@@@@@@@@@=::O&&&&&O:O&&&&&O: ,=@@@@@@@", "@@@@@@@@@@:::&&&&&&&&:&&&&&O: ;@@@@@@@@", "@@@@@@@@@@::O&&&&&&&&:&O&&&O:, ;@@@@@@@@", "@@@@@@@@@@::O&&&&O&O&OO&O&&O:+ ;@@@@@@@@", "@@@@@@@@@@::&&&O&&&&&O:&&&&O:, @@@@@@@@", "@@@@@@@@@@::O&&&&&O&&&:O&O&::+ @@@@@@@@", "@@@@@@@@@@::O&&O&&&&O&OO&&&:: @@@@@@@@", "@@@@@@@@@@=::O&&&&O&&&O:&&&:: @@@@@@@@", "@@@@@@@@@@.:::O&&O&&&&&:&OO:: @@@@@@@@", "@@@@@@@@@@@:::::&&&&O&O:&&O:, @@@@@@@@", "@@@@@@@@@@.>:::::O&&&&&:&&::+ ;@@@@@@@@", "@@@@@@@@@@>.<::::O&&O&O:&&:: @@@@@@@@@", "@@@@@@@@@@@.o%,:::O&&&O:&O:, @@@@@@@@@", "@@@@@@@@@@@$o. :::OO&OO&::, ;@@@@@@@@@", "@@@@@@@@@@@&o%+ ,::O&OO&O:: =@@@@@@@@@", "@@@@@@@@@@@.oo+ :::OO::: ,@@@@@@@@@@", "@@@@@@@@@@@..oO +::::: =@@@@@@@@@@", "@@@@@@@@@@@@.<.+ ,+, ,@@@@@@@@@@@", "@@@@@@@@@@@@Oo<+ @X, ,@@@@@@@@@@@@", "@@@@@@@@@@@@.%o$ @@@@@;, ;@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o., =@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" }; /* XPM */ static char *confused_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO", "OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO", "OOOOOOOOOOO+=.=====.=++++===OO==+O=+OOOO", "OOOOOOOOOOO=+===.+=o==o===+&OoO======OOO", "OOOOOOOO+O+====OO+=o&&&&Oo==o&oO+==+=.O.", "OOOO+.+=+O==+&&o=oooOo&o&ooo=&oooO==O=+=", "OOOOOOOO++O===oo=oo&=&o&&oo=o==&o+==++==", "OOOOOOOO=o.=O====o&OO&o&oo&o&&oo=======O", "OOOOOOOo===+=O=O=ooO=ooooOOo=o&O=====OOO", "OOOOOOOOO+==+=======O=oo====O=o=O===+OOO", "OOOOOOOOO.=#=X=+====O========O======OOOO", "OOOOOOO.#Xo++.=#%====O==========OO==+OOO", "OOOOOO+Xo#+#+.#=.==X====+====O=+=+==+OOO", "OOOOO.+.+O===##.#=X.====oX##===o+OO.OOOO", "OOOOO#+####O#O##o.#+==#X#O#+...=OOo=+OOO", "OOOO++#o+#+X++++#.#O.#+#X.#+X+==+OO=oOOO", "OOOO#+.+..X+.##X++#++#..+XX#+##+..OOOOOO", "OOOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOO", "OOOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOO", "OOOOO#+#+.+++#++.+++##+X###+X+X##+**OOOO", "OOOOO#..#OO#+.##o###.+..++.+#X+#+#* @OOO", "OOOOO+#.#O+#+#O.+++.###+##++###+.#* $OOO", "OOOOOOXX+#+#+#o..X##++#+..##.#+### *OOO", "OOOOOOOX#.#X+#+#+#+.#+..+####%XX%% OOO", "OOOOOOOO.%%X.#+#+#.++#+#+#+.X++=.% *OOO", "OOOOOOOOO.* *##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX=.+++#X $OOO", "OOOOOOOOOOOO.* %%X..#X%=.####%X* $OOO", "OOOOOOOOOOOOOO.$ *XX%%%=.#X%###=* OOOO", "OOOOOOOOOOOOOOOOOO+%%%=%%#.+.#=* @OOOO", "OOOOOOOOOOOOOOOOOOo=%%%==X##X%* OOOOO", "OOOOOOOOOOOOOOOOOOO+X%%%%X=%* @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X *@OOOOOO", "OOOOOOOOOOOOOOOOOOOO=%%%X* *$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%= .OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%% OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO" }; /* XPM */ static char *dex_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #B64700", "* c #909090", "= c #606060", "- c #CEAA90", "; c #DADAB6", ": c #303030", "> c #F86800", ", c #FFB691", "< c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "###############-%-######################", "##############-%X<-#####################", "#########-<<-#-%XX+==###################", "#########%,X< :<,X%@ :##################", "#########-XX%: @;X%+ *#################", "##########<,X& :<<%+: :#################", "######->+#-%%%: <,XX@ #################", "######%X%@ <,,& @XXX+ :++-#############", "######-: +XX+ #########", "#####+%%@@,X%<,XXXXXXX<:@XXX<: =########", "####$%XX< <,<,XX& ########", "#####$%<%X@%XXXX<%XX< =#######", "#######<;X%XXXXX<<,XXXXXX%,XXXXXXXXX%@ #######", "##########- c #788C8C", ", c #606060", "< c #406868", "1 c #C80050", "2 c #FFFFFF", "3 c #FFFF00", "4 c #00B6FF", "5 c #CEAA90", "6 c #DADAB6", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$353333335*$$$$$$$$$$$$$$$", "$$$$$$$$$$$$*33333333#7@3335$$$$$$$$$$$$", "$$$$$$$$$65333333333@7777#333*$$$$$$$$$$", "$$$$$$$$$3333333333377777733333===%$$$$$", "$$$$$$$533333333333#7777777333%=====$$$$", "$$$$$$ #3333333333o>7777773330======%$$$", "$$$$5---O#33333o3944077777333*=======$$$", "$$$$-----O333333>4444.77333330======%$$$", "$$$ ---O--;3333344444443333333:====5$$$$", "$$$ O-----733333444444433333333 ==035$$$", "$$$3--O--O333333>44444>33333333333333$$$", "$$533---O33333333944493333#333333333356$", "$$33867733333o33333:o333333o3333333333$$", "$532+2233333#333333333333oooo3#3333333%$", "6522222+33333333333333333oooooo33o3333*$", "$+22+22263333333o3333333ooooooo333333356", "662222+2533333333333333#ooooooo33333333$", "$32+22223333o3#33333o333ooooooo3#333333%", "$33222233333333333#333333ooooo333333333$", "$33368333333333333330626*oooo#333333o33%", "%333335== 33oo333333222223#333333333333$", "$3333=====:ooooo333+22+2263333333.>o333%", "$5333=====oooooo33322222223333339444935$", "$*33 ====>ooooooo3362+222633333.44444>3$", "$%330====:ooooooo333222+23333334444444$$", "$$333177 =oooXoo#333*626333333;4444444$$", "$$53##777&3oooo3333333333333#--,444449$$", "$$$3;77777#3o333333333333333O---94449$$$", "$$%*@77777#33333333333333337O----O:o3$$$", "$$$5777777333 333333333333;---O-O73$$$$", "$$$$#7777730====#:.,33333333------3$$$$$", "$$$$$577333=====qqqq<0333333#O---35$$$$$", "$$$$$%53335====qqqqqq.33o333337735$$$$$$", "$$$$$$$533 ====qqqqqqq3333333333%$$$$$$$", "$$$$$$$$%33====qqqqqqq333333333%$$$$$$$$", "$$$$$$$$$$50===qqqqqq,3333333:$$$$$$$$$$", "$$$$$$$$$%6%5503,qqq<333#335%$$$$$$$$$$$", "$$$$$$$$$$$$$%$*53,03335o$%%$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$" }; /* XPM */ static char *hungry_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 15 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO========OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO=============OOOOOOOOOOOOO", "OO;XX;@OOOOO================OOOOOOOO;XOO", "OO;%-;$OOOO==================OOOOOOO;XOO", "OO;-%;$OOO========@$#@========OOOOO+;;$O", "OO;%-;$OO=======- -*======*OOOO.;;$O", "OO;-%;$O======* @====.$$&=====@OOO.;;$O", "OO;X%;$O====== -========*@=====*.OO+;;$O", "OO;;;X$o====* -==========@======$OO;;;$O", "OO+;;-+o====- =============o====#@O+;;$O", "OOO;%$O===== @=============&====*$O;;;$O", "OOO+%OO====@ ==============&=====-OO;;$O", "OOo;-Oo====$ ==============o&==== OO;;$O", "OOO+%OO====@ ==============&===== O+;;#O", "OOO;-Oo====$-==============&&==== O+;;-O", "OOO;;+O=====$*============&&====* OO;;%+", "OOO;;$o=====$.============&&====X-OO;;$O", "OOO;;$O======*.===&======&&=====-$=O;;$O", "OOO;;$Oo=====.==========&&=====* @O+;;$O", "OOO;;$OO=======oo=====&&&======$-OOO;;$O", "OOO;;$OOo=======&o&&&&&&======$ @OOO;;$O", "OOO;;$OOOO========&=&========* $OOOO;;$O", "OO+;;$OOOOo=================* -OOOOO#;$O", "OOO;;$OOOOO=*==============@ -=OOOOO;;$O", "OOO;;$OOOOOOO+*==========*- $OOOOOOO;;$O", "OOOX-$OOOOOOOO@X@*====*#- -.OOOOOOOOX-$O", "OOOOOOOOOOOOOO=*@$- -$.=OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO=O==O=O=OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *hvy_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO", "OOOOOOOOOOOo==============X*OOOOOOOOOOOO", "OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO", "OOOOOOOOOO&============X===% $OOOOOOOOOO", "OOOOOOOOOoo===*%====***%===%* OOOOOOOOOO", "OOOOOOOOOoO==% %===* %==X* @OOOOOOOOO", "OOOOOOOOO&===% *==% X==**===% $OOOOOOOOO", "OOOOOOOOoo===% %==% ===% ===X OOOOOOOOO", "OOOOOOOOoO==== *== *==== *==X* @OOOOOOOO", "OOOOOOOO&===== %== %==== %===% $OOOOOOOO", "OOOOOOOoo===== *== *==== *===%* OOOOOOOO", "OOOOOOOoO===== %==% ===* ====X* @OOOOOOO", "OOOOOOO&===X== *==% X==**=====% $OOOOOOO", "OOOOOOoo===== *==* %=====X OOOOOOO", "OOOOOOoO=====*%%X===*%*X======%* @OOOOOO", "OOOOOOo====================X===* $OOOOOO", "OOOOOOO=%X%XXXX%XXXXXXXXX%X=%X% OOOOOO", "OOOOOOO.=********************** OOOOOO", "OOOOOOOOO OOOOOO", "OOOOOOOOO. @OOOOOO", "OOOOOOOOOOOoOOoOoOoOoOoOoOOoOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *int_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOO+#.X.##@#OOOOOOOOOOOOOOOOOO", "OOOOOOOO+##@X#O++.#+#.##OOOOOOOOOOOOOOOO", "OOOOOO+#Xo++#X#%#+##o#O#.#+OOOOOOOOOOOOO", "OOOOO.Xo#+#++##+.XX#..+.+..XOOOOOOOOOOOO", "OOOO++.+O.+O##+#.X###..OX#.+X+OOOOOOOOOO", "OOOO#+####O#O##o##+###X#+#+.#..OOOOOOOOO", "OOO.+#o+#+X++++#.#O+#+#X.#+X++X+OOOOOOOO", "OOO.+.+..X+.##X++#++#..+XX#+#X+..OOOOOOO", "OOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOOO", "OOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOOO", "OOOO#+#+.+++#++.+++##+X###+X+X##+&&OOOOO", "OOOO#..#OO#+.##o###.+..++.+#X+#+#& @OOOO", "OOOO.#.#O+#+#O.+++.###+##++###+.# $OOOO", "OOOOOXX+#+#+#o..X##++#+..##.#+### &OOOO", "OOOOOOX#.#X+#+#+#+.#+..+####XX%X% OOOO", "OOOOOOO.%%X.#+#+#.++#+#+#+.%++*+% &OOOO", "OOOOOOOO@& &##+#+.O####.+XXX%%%#% $OOOO", "OOOOOOOOOO. %X.+.#+++XXX*.+++#% $OOOO", "OOOOOOOOOOO@& %%X..#XXX.####%%& $OOOO", "OOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOOO", "OOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOOO", "OOOOOOOOOOOOOOOOOO*%%%*.X##XX& OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%X*%& @OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%% &@OOOOOOO", "OOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+%%%* .OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+*%%% OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO" }; /* XPM */ static char *lawful_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 10 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #606060", "$ c #FFFFFF", "% c #303030", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOo$$$$$$oOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO$$o$$o$$$$$OOOOOOOOOO", "OOOOOOOOOOOOOOOOOOo$$$$$$$o$$ooOOOOOOOOO", "OOOOOOOOOOOOOOOOOO$o$$$o$$$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$$+ .o$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$+%OOOO$o$$$oOOOOOOO", "OOOOOOOOOOOOOOOOO$$o$X@OOOOo$$$ooOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$%OOOOOo$$$..OOOOOOO", "OOOOOOOOOOOOOOOOO$$$$@OOOOo$$oo##OOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$ooOoo$$$o OOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$o$$$$o#%OOOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$o$$$$$o@%OOOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$$o$o.%OOOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$o$$oo@#%OOOOOOOOOOO", "OOOOOOOOoooooo$$$$$$$$$$$% %OOOOOOOOOOOO", "OOOOOOO$$$$$$$$$$$$o$$o$$$$$$$oOOOOOOOOO", "OOOOOO$$$$$$$$$o$$$$$$$$$$$$o$$oOOOOOOOO", "OOOOOO$$o$ooooo##+o$$+##@oo$$$$$oOOOOOOO", "OOOOOOo$$#% %#$$$+%##%%#ooo$O#OOOOOOO", "OOOOOOOo@##OOOOO+$$$##OOOO#%%##%@OOOOOOO", "OOOOOOOOOOOOOOOOo$$$##OOOOOOO##@OOOOOOOO", "OOOOOOOOOOOOOOOOo$$o##OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+$$$o OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$o$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o%@OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$o##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$# @OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO.#@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *mod_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOo&&&&&&&&&oXOOOOOOOOOOOOOOO", "OOOOOOOOOOOO+&=========X%@OOOOOOOOOOOOOO", "OOOOOOOOOOOOO&=====X====% @OOOOOOOOOOOOO", "OOOOOOOOOOOOoO==X=======X* OOOOOOOOOOOOO", "OOOOOOOOOOOO&====*%*%*===* $OOOOOOOOOOOO", "OOOOOOOOOOO+&===X ===% *OOOOOOOOOOOO", "OOOOOOOOOOOoO===**=======X* OOOOOOOOOOOO", "OOOOOOOOOOO&===% %=======X% $OOOOOOOOOOO", "OOOOOOOOOOO&===% %*%%=====% *OOOOOOOOOOO", "OOOOOOOOOOoO===* ====X* OOOOOOOOOOO", "OOOOOOOOOO&=========* X===X% $OOOOOOOOOO", "OOOOOOOOO+&=========% *====% *OOOOOOOOOO", "OOOOOOOOOoO===% %=== %====%* OOOOOOOOOO", "OOOOOOOOO&====* *==X===% $OOOOOOOOO", "OOOOOOOOO&======*%*%X=======% *OOOOOOOOO", "OOOOOOOOOo==X===============% OOOOOOOOO", "OOOOOOOOO=XXXXXXXXXX%X%X%X%%% $OOOOOOOO", "OOOOOOOOOO=%**************** $OOOOOOOO", "OOOOOOOOOOO$ $OOOOOOOO", "OOOOOOOOOOOO* *OOOOOOOOO", "OOOOOOOOOOOOOoOOoOoOoOoOoOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *neutral_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #00B6FF", "= c #303030", "- c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO.------.OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO-+O&o.-----OOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+-&o--------.OOOOOOOOO", "OOOOOOOOOOOOOOOOOO-oo----------+OOOOOOOO", "OOOOOOOOOOOOOOOOO+-&--% #-------OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-X=OOO.-----+OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-%#OOOO.-----OOOOOOO", "OOOOOOOOOOOOOOOOO--O-=OOOOO+---X#OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-XOOOO+OO--=$OOOOOOO", "OOOOOOOOOOOOOOOOO-OO--++OO-&--- OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-----+oo--%=OOOOOOOO", "OOOOOOOOOOOOOOOOO--O--+o&&o--%=OOOOOOOOO", "OOOOOOOOOOOOOOOOO-oo*-------%=OOOOOOOOOO", "OOOOOOOOOOOOOOOOO-oO------%%=OOOOOOOOOOO", "OOOOOOOO+.+-+.---O&------= =OOOOOOOOOOOO", "OOOOOO+-oo&&&&&&&&------------.OOOOOOOOO", "OOOOOO---------------X-----O&Oo-OOOOOOOO", "OOOOOO---------%=%---%%=%----OO-.OOOOOOO", "OOOOOO---== =%---%=%%===----%XOOOOOOO", "OOOOOOO-#$%OOOOOO-+-%$OOOO%===%=@OOOOOOO", "OOOOOOOOOOOOOOOO.-&-=%OOOOOOO%%#OOOOOOOO", "OOOOOOOOOOOOOOOo-O+-%$OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%%OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-=$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--o-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+-&- .OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-Oo- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO%%OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-o-%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO---%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--% #OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOX$@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *ovr_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOoO+=+OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOo=#===+OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo=.OO@X=OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo#OO* #X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+=.XX+=#* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO+=O=.=OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO#.=+OO@ $OOOOOOOOOOOOOO", "OOOOOOOOOooooooooo&O.#+#XooooOOOOOOOOOOO", "OOOOOOOOO&OOoOoOoOOOOOOOOOoO%@OOOOOOOOOO", "OOOOOOOOoO==================X*@OOOOOOOOO", "OOOOOOOO&===================X% @OOOOOOOO", "OOOOOOOO&==%*%*%*%*%*%*%*%*==% *OOOOOOOO", "OOOOOOOoO==%*%%*%%*%%*%*%*%==X* OOOOOOOO", "OOOOOOO&======================* $OOOOOOO", "OOOOOO+&=== ===% *OOOOOOO", "OOOOOOoO======================X* OOOOOOO", "OOOOOO&=======================X% $OOOOOO", "OOOOOOo========================% *OOOOOO", "OOOOOoO===*%X=====%%======%%===X* OOOOOO", "OOOOO&==% %==% *==== %==* $OOOOO", "OOOOO&== *==**== **% *=X% %%* ==% *OOOOO", "OOOOoO==%%==* =* ===% == %=== %=X* OOOOO", "OOOO&=======% =**===% %X %X==* =X% $OOOO", "OOOO&======% %= %==== %% ====* ==% *OOOO", "OOOoO=====% *== *==== %* ====% ==X* OOOO", "OOO&====XX *===**===% X% X=== *===* $OOO", "OO+&====X *====* ===% == *=== %===% *OOO", "OOoO===% %*%*== *** %==% %** ====X* OOO", "OO&====% ==X *====* %====X% $OO", "OO&================================% *OO", "OOo===X============================% OO", "OO=XXXXXXXXXXXX%XXXX%X%X%XXXXX%X%X%% $O", "OOO=%****************************** $O", "OOOO$ $O", "OOOOO* *OO", "OOOOOOOOOOoOOoOOoOOoOOoOOoOOoOOoOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *satiated_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #914700", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #406868", "> c #FFFFFF", ", c #CEAA90", "< c #DADAB6", "1 c #303030", "2 c #FFB691", "3 c #6C91B6", "4 c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "################<<<<<<<<################", "##############<<<<<<<<<<$#$$$###########", "############<<<<<<<<<<$:31:3:###########", "###########<<<<<<%42<<#:3:133-##########", "##########<<<<<%<<;;=o$131:33;##########", "#########<<<<<<,1 ::31:33;,#########", "########<<<<<<, =<<<<.13:133;<=########", "########<<<%2, 1<<<<<<#333:33;<,=#######", "#######<<<3-=<33;<<@o######", "#######O<<<<<,#<<<<<<<<.3:<3-;<, =######", "########<<<<2<<<<<<<<<>#31<33o<11#######", "########O<<<<44<>O>>>>>#3:<3.;- =#######", "##########<<<4<<<<><><<$3:<331 ;<#######", "##########<<<<<<<%2<<<<$3:<33 1#########", "###########O,<<<<<<<<<<#31<331##########", "#############.<<<<<<<<<$3:133;##########", "##############=;=,<<<<,o 1;;=##########", "###############<=;1 1;=##############", "#################<# c #B64700", ", c #909090", "< c #788C8C", "1 c #606060", "2 c #406868", "3 c #FFFFFF", "4 c #CEAA90", "5 c #DADAB6", "6 c #303030", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "****************************************", "*************#333333333#****************", "***********##33333#333333#**************", "**********#33333#33333#33*==************", "*********#33##33-;-3#3333399************", "********#33#33#3-@ 33333#33=.***********", "********#3*#33-;;;;;-33333#99***********", "*******#3*3333-;;;;@ 33#333#9=**********", "*******#333#33#3-;-33#*##33399**********", "******#3#3333333-@-#333#9933*9=*********", "******#333#33#3333333#333*9999=*********", "******#333333333#3#33333333*999*********", "******#3#33#33333333#33#3333#9=*********", "******#333334>&&:&&>::44,3#33#9*********", "******#33*::&41OOO6:4O 0::4433=*********", "******#3:>,0:O0O1O+O:OXO,O+2+OOo4<+1104:>:#*********", "******.&:1OOO,14X2O48:O80,440:,*********", "******4::>OOO%8-X4O4%O,84+O0X&>=********", "******.::>,O 99*X+<$,+.o*1O4&0:*********", "******>:0&4O5qq9#10OO3qq9,+X:1:*********", "****=>,,::,O4qq9X+O>O-qq9O2X0,>*********", "******4:>OOOO48882OOOO+4OOO07*4*********", "******4*,4OO+OXX3O5************", "*********=0%,OO,>:>>O +1OO4*************", "**********=%+OO:::1:::6+:7**************", "***********7&OO:O+O,O1OO+1**************", "***********40OO,O4:OOO11O<5*************", "**********=4 +O1O2+O2+O0O***************", "************72O+1+21-OOO%5**************", "************0%1OOOO+O+174***************", "*************%%O,OO1407-=***************", "**************-$>%0%:74*****************", "****************54044*=*****************", "*****************=*=********************" }; /* XPM */ static char *sick_il_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #FF0000", "* c #914700", "= c #B64700", "- c #909090", "; c #606060", ": c #FFFFFF", "> c #CEAA90", ", c #DADAB6", "< c #F86800", "1 c #FFB691", "2 c #6C91B6", "3 c #F88C48", "4 c #0000FF", /* pixels */ "########################################", "#############O:::::::::O################", "###########OO:::::O::::::O##############", "##########O:::::O:::::O::#$$############", "#########O::OO::%&%:O:::::22############", "########O::O::O:%o :::::O::$.###########", "########O:#O::%&&&&&%:::::O22###########", "#######O:#::::%&&&&o ::O:::O2$##########", "#######O:::O::O:%&%::O#OO:::22##########", "######O:O:::::::%o%O:::O22::#2$#########", "######O:::O::O:::::::O:::#2222$#########", "######O:::::::::O:O::::::::#222#########", "######O:O::O::::::::O::O::::O2$#########", "######O:::::>=@@=**=**>>-:O::O2#########", "######O::#**@3>%* ;=>=3;<@>>::$#########", "######O:** >=>XXXX1X >>+>%*%*;O#########", "######O3@*,X%XXXXXXX>X%XX >*=*O#########", "######.@@3XXXXXXXXXXXXXXX>X>3*-#########", "######>***>X% >XXXXX3XXXXXX%>*=>########", "######.***> 22#XXX<%X22#XXX@+;#########", "######=*3@X>O442OXX==%XX11111O1+%X111XX%<#>#########", "######.,;XXXXXX1O1X%3XXXXX%+3###########", "########3=XXXXXX:XXXXXXXXX+<>$##########", "########>+XXXXXX%-3->XXXX%+<############", "#########%3XXXXXX>- -%XXX%<%$###########", "#########$############", "##########+%XXXXXXXXXXXX%+<#############", "##########%3XXX>=****3XX%<%#############", "##########>+XXX**=3-*@3>3+##############", "###########<%XX >XX%X;%X3+##############", "###########%3XX>XX++XXXX<%$#############", "##########$>+XXXXXXXXXXX<###############", "############<%XXXXXXXXX3+###############", "###########$%+XXXXXXXX%<>###############", "#############++XXXXXX%<%$###############", "#############$%<<3333<%#################", "#################%3>>$##################", "#################$#$####################" }; /* XPM */ static char *slt_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO&&&&&&&X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo======X*OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOoO======X**OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO&====X===% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoo==%* %==%* OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoO=% % =X* @OOOOOOOOOOOOO", "OOOOOOOOOOOOO&==**==% %=% $OOOOOOOOOOOOO", "OOOOOOOOOOOOoo==%%==* %=X OOOOOOOOOOOOO", "OOOOOOOOOOOOoO=====* X==X* @OOOOOOOOOOOO", "OOOOOOOOOOOO&=====* %====% $OOOOOOOOOOOO", "OOOOOOOOOOOoo==== X=====%* OOOOOOOOOOOO", "OOOOOOOOOOOo+===* *%*%%==X* @OOOOOOOOOOO", "OOOOOOOOOOO&==== %===% $OOOOOOOOOOO", "OOOOOOOOOOO&==============% OOOOOOOOOOO", "OOOOOOOOOOO==============X% @OOOOOOOOOO", "OOOOOOOOOOO+%%%%%%%%%%%%%% $OOOOOOOOOO", "OOOOOOOOOOOOO% $OOOOOOOOOO", "OOOOOOOOOOOOO@ @OOOOOOOOOO", "OOOOOOOOOOOOOO@$$$$$$$$$$$$$@OOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *str_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 17 1", /* colors */ " c #000000", ". c #F8B090", "X c #5C7A7A", "o c #F87A24", "O c #7C3400", "+ c None", "@ c #B0B0B0", "# c #F89E6C", "$ c #B64700", "% c #909090", "& c #606060", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #F86800", ": c #FFB691", "> c #F88C48", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++++++*>*>#++++++++++++++++", "++++++++++++++++*#o>..*#o*++++++++++++++", "+++++++++++++++o#.#>.....o++++++++++++++", "+++++++++++++++;>;#.o.>..#$X++++++++++++", "+++++++++++++++o#>.o.>:...o %++++++++++", "++++++++++++++o##>>#o##>..#O -++++++++++", "++++++++++++++>#.oo#>..>...O ++++++++++", "++++++++++++++*o##.>>;o#...o ++++++++++", "+++++++++++++++*;o#........>- &+++++++++", "+++++++++++++++++#>>;o......O -+++++++++", "+++++++++++++++++@+@+o>.....$ +++++++++", "+++++++++++++++++++++*;.#...>- %++++++++", "++++++++++++++++++++++;>o....$ &++++++++", "++++++++++++++++++++++#>>....>- %+++++++", "+++++++++++++++++++++++;#>....; -+++++++", "+++++++++++++++++++++++o#>....>O %++++++", "+++++++++++++++++++++++*>o.....; -++++++", "+++++++++++++#>**+++++++;#.....>O %+++++", "+o#+++++++*o;>>>>o#+++++o##.....; -+++++", "+:#o*++++oo#..*..*>;*+++#>#.....>O %++++", "+:=#o#+*;>.:==:....#;*++@o.......; &++++", "+::..>;o#.=::::......o*++;.......>O ++++", "+.....#o.:.=:.........o#+;........$ ++++", "+......#o..:...........#o;>.......o &+++", "+........#..............*>o......:o- +++", "+..................#o>#...#o.......O +++", "+...............>o>#.......#>......O &++", "+..................................o -++", "+..................................> ++", "+..................................> ++", "+.................................#$ &+", "+................................>$ &+", "+..#>$o>#..............#>;>>>oOOO- ++", "+...#O OOOOO$>>>>>>>$OO %++", "+...o -&&++++", "+..#O -&&%++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static char *stunned_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOO&$OOOO@OOO@@OO@OOOOOOOOOOOOO", "OOOOOOOOOOO@& $OO@&&$$@ O@$$OOOOOOOOOOOO", "OOOOOOOOOOOO$$ @@@$ &&OOO@$OOOOOOOOOOOO", "OOOOOOOOOOOOO@@&$$$$&O$OO$O &@O@OOOOOOOO", "OOOOOO@@@@@@OO@$$O$&$@@OO& &&$O&OOOOOOO", "OOOOOO&&&& & $ &&@$ &O@$& &&&$ & $OOOOOO", "OOOOOO$&OO &&&$ $$ $& $$&$&&&OOOOOOO", "OOOOOO@@O@$ &+ # &O$$ $$&O@OOOOO", "OOOOOOOO@X%$ %& %% & && $$@@@@OOOO", "OOOOOOO+$$@+ &%%%&%& & &@OOO&&OOO", "OOOOOO.Xo%+ &&%%%%%&& & OO@$&&OOO", "OOOOO++ $$&&$ && %&%%& &O@&$&OOOO", "OOOOO####$ X&&& && &%& & &&OOOO", "OOOO++#.+## $&# %& & & &$ OOOO", "OOOO#+++.@&%&& &#&%& & $ @OOOOOO", "OOOO##....#+$#@%#& $%$&@&$$% & X##$@OOOO", "OOOO.+#+.+@#+#+$&$X#%&%.+& %&#++.$&OOOOO", "OOOOO#+#+.+++#$$%&++&X+X#&#+&+&##+ &OOOO", "OOOOO#..#OO#+@%#o##X.@..++.+$&+#+#& @OOO", "OOOOO+#.#O+#+#O@++@$$##+##++###+.#& $OOO", "OOOOOOXX+#+#+#o.@%&$++#+..##.#+### &OOO", "OOOOOOOX#.#X+#+#+##&#+..+####%XX%% OOO", "OOOOOOOO+%%X.#+#+#.++#+#+#+.X++*.% &OOO", "OOOOOOOOO@& &##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX*.+++#X $OOO", "OOOOOOOOOOOO@& %%X..#X%#.####%X& $OOO", "OOOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOO", "OOOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOO", "OOOOOOOOOOOOOOOOOOO*%%%**X##X%& OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X*X& @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X &@OOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%* @OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%& OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO" }; /* XPM */ static char *wis_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c None", "O c #B0B0B0", "+ c #909090", "@ c #788C8C", "# c #606060", "$ c #406868", "% c #FFFFFF", "& c #303030", "* c #6C91B6", "= c #0000FF", /* pixels */ "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooo+#& &#oooooooooooooooooooo", "oooooooooooo+& #oooooooooooooooooo", "ooooooooooo+ &====&& &ooooooooooooooooo", "oooooooooo+ &==& ===%& +ooooooooooooooo", "ooooooooo+&%=== ===%%o&&oooooooooooooo", "oooooooo.&%%===& ===%o& #+ooooooooooo", "oooo&###&&%%*=======$#&ooo#& #+oooooooo", "ooooo###o+&X$=====& #oo##oooo+######oooo", "oooooooooooo######@oo##ooooooooooooooooo", "oooooooooooooOoOoOo##ooooooooooooooooooo", "ooooooooooooooooo+#+ooo+&#oooooooooooooo", "ooooooooooooooooooooooo#oooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; /* XPM */ static char *nothing_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c None", "O c #B0B0B0", "+ c #909090", "@ c #788C8C", "# c #606060", "$ c #406868", "% c #FFFFFF", "& c #303030", "* c #6C91B6", "= c #0000FF", /* pixels */ "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; /* clang-format on */ nethack-3.6.0/win/gnome/gnaskstr.c0000664000076400007660000000305512536476415016057 0ustar paxedpaxed/* NetHack 3.6 gnaskstr.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnaskstr.h" #include "gnmain.h" #include static void ghack_ask_string_callback(gchar *string, gpointer data) { char **user_text = (char **) data; g_assert(user_text != NULL); *user_text = string; /* note - value must be g_free'd */ } int ghack_ask_string_dialog(const char *szMessageStr, const char *szDefaultStr, const char *szTitleStr, char *buffer) { int i; GtkWidget *dialog; gchar *user_text = NULL; dialog = gnome_request_dialog(FALSE, szMessageStr, szDefaultStr, 0, ghack_ask_string_callback, &user_text, NULL); g_assert(dialog != NULL); gtk_window_set_title(GTK_WINDOW(dialog), szTitleStr); gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(ghack_get_main_window())); i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); /* Quit */ if (i != 0 || user_text == NULL) { if (user_text) g_free(user_text); return -1; } if (*user_text == 0) { g_free(user_text); return -1; } g_assert(strlen(user_text) > 0); strcpy(buffer, user_text); g_free(user_text); return 0; } nethack-3.6.0/win/gnome/gnaskstr.h0000664000076400007660000000103512536476415016060 0ustar paxedpaxed/* NetHack 3.6 gnaskstr.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackAskStringDialog_h #define GnomeHackAskStringDialog_h int ghack_ask_string_dialog(const char *szMessageStr, const char *szDefaultStr, const char *szTitleStr, char *buffer); #endif /* GnomeHackAskStringDialog_h */ nethack-3.6.0/win/gnome/gnbind.c0000664000076400007660000012026612536476415015470 0ustar paxedpaxed/* NetHack 3.6 gnbind.c $NHDT-Date: 1433806614 2015/06/08 23:36:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ /* * This file implements the interface between the window port specific * code in the Gnome port and the rest of the nethack game engine. */ #include "gnbind.h" #include "gnmain.h" #include "gnmenu.h" #include "gnaskstr.h" #include "gnyesno.h" GNHWinData gnome_windowlist[MAXWINDOWS]; winid WIN_WORN = WIN_ERR; extern void tty_raw_print(const char *); extern void tty_raw_print_bold(const char *); /* this is only needed until gnome_status_* routines are written */ extern NEARDATA winid WIN_STATUS; /* Interface definition, for windows.c */ struct window_procs Gnome_procs = { "Gnome", WC_COLOR | WC_HILITE_PET | WC_INVERSE, 0L, gnome_init_nhwindows, gnome_player_selection, gnome_askname, gnome_get_nh_event, gnome_exit_nhwindows, gnome_suspend_nhwindows, gnome_resume_nhwindows, gnome_create_nhwindow, gnome_clear_nhwindow, gnome_display_nhwindow, gnome_destroy_nhwindow, gnome_curs, gnome_putstr, genl_putmixed, gnome_display_file, gnome_start_menu, gnome_add_menu, gnome_end_menu, gnome_select_menu, genl_message_menu, /* no need for X-specific handling */ gnome_update_inventory, gnome_mark_synch, gnome_wait_synch, #ifdef CLIPPING gnome_cliparound, #endif #ifdef POSITIONBAR donull, #endif gnome_print_glyph, gnome_raw_print, gnome_raw_print_bold, gnome_nhgetch, gnome_nh_poskey, gnome_nhbell, gnome_doprev_message, gnome_yn_function, gnome_getlin, gnome_get_ext_cmd, gnome_number_pad, gnome_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif /* other defs that really should go away (they're tty specific) */ gnome_start_screen, gnome_end_screen, gnome_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, #ifdef STATUS_HILITES genl_status_threshold, #endif #endif genl_can_suspend_yes, }; /* init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean */ void gnome_init_nhwindows(int *argc, char **argv) { /* Main window */ ghack_init_main_window(*argc, argv); ghack_init_signals(); #ifdef HACKDIR // if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm")) if (ghack_init_glyphs(HACKDIR "/x11tiles")) g_error("ERROR: Could not initialize glyphs.\n"); #else #error HACKDIR is not defined! #endif // gnome/gtk is not reentrant set_option_mod_status("ignintr", DISP_IN_GAME); flags.ignintr = TRUE; iflags.window_inited = TRUE; /* gnome-specific window creation */ WIN_WORN = gnome_create_nhwindow(NHW_WORN); } /* Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. */ void gnome_player_selection() { int n, i, sel; const char **choices; int *pickmap; /* prevent an unnecessary prompt */ rigid_role_checks(); if (!flags.randomall && flags.initrole < 0) { /* select a role */ for (n = 0; roles[n].name.m; n++) continue; choices = (const char **) alloc(sizeof(char *) * (n + 1)); pickmap = (int *) alloc(sizeof(int) * (n + 1)); for (;;) { for (n = 0, i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { if (flags.initgend >= 0 && flags.female && roles[i].name.f) choices[n] = roles[i].name.f; else choices[n] = roles[i].name.m; pickmap[n++] = i; } } if (n > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else if (flags.initgend >= 0) flags.initgend = -1; else if (flags.initrace >= 0) flags.initrace = -1; else panic("no available ROLE+race+gender+alignment combinations"); } choices[n] = (const char *) 0; if (n > 1) sel = ghack_player_sel_dialog( choices, _("Player selection"), _("Choose one of the following roles:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gtk_exit(0); } free(choices); free(pickmap); } else if (flags.initrole < 0) sel = ROLE_RANDOM; else sel = flags.initrole; if (sel == ROLE_RANDOM) { /* Random role */ sel = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (sel < 0) sel = randrole(); } flags.initrole = sel; /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { if (flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) flags.initrace = randrace(flags.initrole); } else { /* Count the number of valid races */ n = 0; /* number valid */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) n++; } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) n++; } } choices = (const char **) alloc(sizeof(char *) * (n + 1)); pickmap = (int *) alloc(sizeof(int) * (n + 1)); for (n = 0, i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { choices[n] = races[i].noun; pickmap[n++] = i; } } choices[n] = (const char *) 0; /* Permit the user to pick, if there is more than one */ if (n > 1) sel = ghack_player_sel_dialog( choices, _("Race selection"), _("Choose one of the following races:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gtk_exit(0); } flags.initrace = sel; free(choices); free(pickmap); } if (flags.initrace == ROLE_RANDOM) { /* Random role */ sel = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (sel < 0) sel = randrace(flags.initrole); flags.initrace = sel; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { if (flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) flags.initgend = randgend(flags.initrole, flags.initrace); } else { /* Count the number of valid genders */ n = 0; /* number valid */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) n++; } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) n++; } } choices = (const char **) alloc(sizeof(char *) * (n + 1)); pickmap = (int *) alloc(sizeof(int) * (n + 1)); for (n = 0, i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { choices[n] = genders[i].adj; pickmap[n++] = i; } } choices[n] = (const char *) 0; /* Permit the user to pick, if there is more than one */ if (n > 1) sel = ghack_player_sel_dialog( choices, _("Gender selection"), _("Choose one of the following genders:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gtk_exit(0); } flags.initgend = sel; free(choices); free(pickmap); } if (flags.initgend == ROLE_RANDOM) { /* Random gender */ sel = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (sel < 0) sel = randgend(flags.initrole, flags.initrace); flags.initgend = sel; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { if (flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) flags.initalign = randalign(flags.initrole, flags.initrace); } else { /* Count the number of valid alignments */ n = 0; /* number valid */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) n++; } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) if (validalign(flags.initrole, flags.initrace, i)) n++; } choices = (const char **) alloc(sizeof(char *) * (n + 1)); pickmap = (int *) alloc(sizeof(int) * (n + 1)); for (n = 0, i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { choices[n] = aligns[i].adj; pickmap[n++] = i; } } choices[n] = (const char *) 0; /* Permit the user to pick, if there is more than one */ if (n > 1) sel = ghack_player_sel_dialog( choices, _("Alignment selection"), _("Choose one of the following alignments:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gtk_exit(0); } flags.initalign = sel; free(choices); free(pickmap); } if (flags.initalign == ROLE_RANDOM) { sel = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (sel < 0) sel = randalign(flags.initrole, flags.initrace); flags.initalign = sel; } } } /* Ask the user for a player name. */ void gnome_askname() { int ret; g_message("Asking name...."); /* Ask for a name and stuff the response into plname, a nethack global */ ret = ghack_ask_string_dialog("What is your name?", "gandalf", "GnomeHack", plname); /* Quit if they want to quit... */ if (ret == -1) { clearlocks(); gtk_exit(0); } } /* Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. */ void gnome_get_nh_event() { /* We handle our own events. */ return; } /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ void gnome_exit_nhwindows(const char *str) { /* gtk cannot do this without exiting the program, do nothing */ } /* Prepare the window to be suspended. */ void gnome_suspend_nhwindows(const char *str) { /* I don't think we need to do anything here... */ return; } /* Restore the windows after being suspended. */ void gnome_resume_nhwindows() { /* Do Nothing. Un-necessary since the GUI will refresh itself. */ return; } /* Create a window of type "type" which can be NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) */ winid gnome_create_nhwindow(int type) { winid i = 0; /* Return the next available winid */ for (i = 0; i < MAXWINDOWS; i++) if (gnome_windowlist[i].win == NULL) break; if (i == MAXWINDOWS) g_error("ERROR: No windows available...\n"); gnome_create_nhwindow_by_id(type, i); return i; } void gnome_create_nhwindow_by_id(int type, winid i) { switch (type) { case NHW_MAP: { gnome_windowlist[i].win = ghack_init_map_window(); gnome_windowlist[i].type = NHW_MAP; ghack_main_window_add_map_window(gnome_windowlist[i].win); break; } case NHW_MESSAGE: { gnome_windowlist[i].win = ghack_init_message_window(); gnome_windowlist[i].type = NHW_MESSAGE; ghack_main_window_add_message_window(gnome_windowlist[i].win); break; } case NHW_STATUS: { gnome_windowlist[i].win = ghack_init_status_window(); gnome_windowlist[i].type = NHW_STATUS; ghack_main_window_add_status_window(gnome_windowlist[i].win); break; } case NHW_WORN: { gnome_windowlist[i].win = ghack_init_worn_window(); gnome_windowlist[i].type = NHW_WORN; ghack_main_window_add_worn_window(gnome_windowlist[i].win); break; } case NHW_MENU: { gnome_windowlist[i].type = NHW_MENU; gnome_windowlist[i].win = ghack_init_menu_window(); break; } case NHW_TEXT: { gnome_windowlist[i].win = ghack_init_text_window(); gnome_windowlist[i].type = NHW_TEXT; break; } } } /* This widget is being destroyed before its time-- * clear its entry from the windowlist. */ void gnome_delete_nhwindow_by_reference(GtkWidget *menuWin) { int i; for (i = 0; i < MAXWINDOWS; i++) { if (gnome_windowlist[i].win == menuWin) { gnome_windowlist[i].win = NULL; gnome_windowlist[i].type = 0; break; } } } /* Clear the given window, when asked to. */ void gnome_clear_nhwindow(winid wid) { if (gnome_windowlist[wid].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_CLEAR]); } } /* -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. */ void gnome_display_nhwindow(winid wid, BOOLEAN_P block) { if (gnome_windowlist[wid].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_DISPLAY], block); if (block && (gnome_windowlist[wid].type == NHW_MAP)) (void) gnome_nhgetch(); } } /* Destroy will dismiss the window if the window has not * already been dismissed. */ void gnome_destroy_nhwindow(winid wid) { if ((wid == WIN_MAP) || (wid == WIN_MESSAGE) || (wid == WIN_STATUS)) { /* no thanks, I'll do these myself */ return; } if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_widget_destroy(gnome_windowlist[wid].win); gnome_windowlist[wid].win = NULL; gnome_windowlist[wid].type = 0; } } /* Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. */ void gnome_curs(winid wid, int x, int y) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_CURS], x, y); } } /* putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. */ void gnome_putstr(winid wid, int attr, const char *text) { if ((wid >= 0) && (wid < MAXWINDOWS) && (gnome_windowlist[wid].win != NULL)) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_PUTSTR], (guint) attr, text); } } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void gnome_display_file(const char *filename, BOOLEAN_P must_exist) { /* Strange -- for some reason it makes us create a new text window * instead of reusing any existing ones -- perhaps we can work out * some way to reuse stuff -- but for now just make and destroy new * ones each time */ dlb *f; f = dlb_fopen(filename, "r"); if (!f) { if (must_exist) { GtkWidget *box; char message[90]; sprintf(message, "Warning! Could not find file: %s\n", filename); box = gnome_message_box_new(_(message), GNOME_MESSAGE_BOX_ERROR, GNOME_STOCK_BUTTON_OK, NULL); gnome_dialog_set_default(GNOME_DIALOG(box), 0); gnome_dialog_set_parent(GNOME_DIALOG(box), GTK_WINDOW(ghack_get_main_window())); gtk_window_set_modal(GTK_WINDOW(box), TRUE); gtk_widget_show(box); } } else { GtkWidget *txtwin, *gless, *frametxt; #define LLEN 128 char line[LLEN], *textlines; int num_lines, charcount; txtwin = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL); gtk_widget_set_usize(GTK_WIDGET(txtwin), 500, 400); gtk_window_set_policy(GTK_WINDOW(txtwin), TRUE, TRUE, FALSE); gtk_window_set_title(GTK_WINDOW(txtwin), "Text Window"); gnome_dialog_set_default(GNOME_DIALOG(txtwin), 0); gtk_window_set_modal(GTK_WINDOW(txtwin), TRUE); frametxt = gtk_frame_new(""); gtk_widget_show(frametxt); /* * Count the number of lines and characters in the file. */ num_lines = 0; charcount = 1; while (dlb_fgets(line, LLEN, f)) { num_lines++; charcount += strlen(line); } (void) dlb_fclose(f); /* Ignore empty files */ if (num_lines == 0) return; /* * Re-open the file and read the data into a buffer. */ textlines = (char *) alloc((unsigned int) charcount); textlines[0] = '\0'; f = dlb_fopen(filename, RDTMODE); while (dlb_fgets(line, LLEN, f)) { (void) strcat(textlines, line); } (void) dlb_fclose(f); gless = gnome_less_new(); gnome_less_show_string(GNOME_LESS(gless), textlines); gtk_container_add(GTK_CONTAINER(frametxt), gless); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(txtwin)->vbox), frametxt, TRUE, TRUE, 0); gtk_widget_show_all(txtwin); gtk_window_set_modal(GTK_WINDOW(txtwin), TRUE); gnome_dialog_set_parent(GNOME_DIALOG(txtwin), GTK_WINDOW(ghack_get_main_window())); gnome_dialog_run_and_close(GNOME_DIALOG(txtwin)); free(textlines); } } /* Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. */ void gnome_start_menu(winid wid) { if (wid != -1) { if (gnome_windowlist[wid].win == NULL && gnome_windowlist[wid].type != 0) { gnome_create_nhwindow_by_id(gnome_windowlist[wid].type, wid); } gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_START_MENU]); } } /* add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. */ void gnome_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { GHackMenuItem item; item.glyph = glyph; item.identifier = identifier; item.accelerator = accelerator; item.group_accel = group_accel; item.attr = attr; item.str = str; item.presel = presel; if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_ADD_MENU], &item); } } /* end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean */ void gnome_end_menu(winid wid, const char *prompt) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_END_MENU], prompt); } } /* int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_N, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. */ int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected) { int nReturned = -1; if (wid != -1 && gnome_windowlist[wid].win != NULL && gnome_windowlist[wid].type == NHW_MENU) { nReturned = ghack_menu_window_select_menu(gnome_windowlist[wid].win, selected, how); } return nReturned; } /* -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. */ void gnome_update_inventory() { ghack_main_window_update_inventory(); } /* mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment */ void gnome_mark_synch() { /* Do nothing */ } /* wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). */ void gnome_wait_synch() { /* Do nothing */ } /* cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. */ void gnome_cliparound(int x, int y) { /* FIXME!!! winid should be a parameter!!! * Call a function that Does The Right Thing(tm). */ gnome_cliparound_proper(WIN_MAP, x, y); } void gnome_cliparound_proper(winid wid, int x, int y) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_CLIPAROUND], (guint) x, (guint) y); } } /* print_glyph(window, x, y, glyph, bkglyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). */ void gnome_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { GdkImlibImage *im; im = ghack_image_from_glyph(glyph, FALSE); gtk_signal_emit(GTK_OBJECT(gnome_windowlist[wid].win), ghack_signals[GHSIG_PRINT_GLYPH], (guint) x, (guint) y, im, NULL); } } /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). */ void gnome_raw_print(const char *str) { tty_raw_print(str); } /* raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). */ void gnome_raw_print_bold(const char *str) { tty_raw_print_bold(str); } /* int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero. */ int gnome_nhgetch() { int key; GList *theFirst; gtk_signal_emit(GTK_OBJECT(gnome_windowlist[WIN_STATUS].win), ghack_signals[GHSIG_FADE_HIGHLIGHT]); g_askingQuestion = 1; /* Process events until a key press event arrives. */ while (g_numKeys == 0) { if (program_state.done_hup) return '\033'; gtk_main_iteration(); } theFirst = g_list_first(g_keyBuffer); g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst); key = GPOINTER_TO_INT(theFirst->data); g_list_free_1(theFirst); g_numKeys--; g_askingQuestion = 0; return (key); } /* int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 -- mouse click type 1 CLICK_2 -- mouse click type 2 The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. */ int gnome_nh_poskey(int *x, int *y, int *mod) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[WIN_STATUS].win), ghack_signals[GHSIG_FADE_HIGHLIGHT]); g_askingQuestion = 0; /* Process events until a key or map-click arrives. */ while (g_numKeys == 0 && g_numClicks == 0) { if (program_state.done_hup) return '\033'; gtk_main_iteration(); } if (g_numKeys > 0) { int key; GList *theFirst; theFirst = g_list_first(g_keyBuffer); g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst); key = GPOINTER_TO_INT(theFirst->data); g_list_free_1(theFirst); g_numKeys--; return (key); } else { GHClick *click; GList *theFirst; theFirst = g_list_first(g_clickBuffer); g_clickBuffer = g_list_remove_link(g_clickBuffer, theFirst); click = (GHClick *) theFirst->data; *x = click->x; *y = click->y; *mod = click->mod; g_free(click); g_list_free_1(theFirst); g_numClicks--; return (0); } } /* nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void gnome_nhbell() { /* FIXME!!! Play a cool GNOME sound instead */ gdk_beep(); } /* doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int gnome_doprev_message() { /* Do Nothing. They can read old messages using the scrollbar. */ return 0; } /* char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. */ char gnome_yn_function(const char *question, const char *choices, CHAR_P def) { int ch; int result = -1; char message[BUFSZ]; char yn_esc_map = '\033'; GtkWidget *mainWnd = ghack_get_main_window(); if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } (void) strncpy(message, question, QBUFSZ - 1); message[QBUFSZ - 1] = '\0'; sprintf(eos(message), " [%s]", choicebuf); if (def) sprintf(eos(message), " (%c)", def); Strcat(message, " "); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); } gnome_putstr(WIN_MESSAGE, ATR_BOLD, message); if (mainWnd != NULL && choices && !index(choices, ch)) { return (ghack_yes_no_dialog(question, choices, def)); } /* Only here if main window is not present */ while (result < 0) { ch = gnome_nhgetch(); if (ch == '\033') { result = yn_esc_map; } else if (choices && !index(choices, ch)) { /* FYI: ch==-115 is for KP_ENTER */ if (def && (ch == ' ' || ch == '\r' || ch == '\n' || ch == -115)) { result = def; } else { gnome_nhbell(); /* and try again... */ } } else { result = ch; } } return result; } /* getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. */ void gnome_getlin(const char *question, char *input) { int ret; ret = ghack_ask_string_dialog(question, "", "nethack", input); if (ret == -1) input[0] = 0; } /* int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. */ int gnome_get_ext_cmd() { return ghack_menu_ext_cmd(); } /* number_pad(state) -- Initialize the number pad to the given state. */ void gnome_number_pad(int state) { /* Do Nothing */ } /* delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. */ void gnome_delay_output() { if (gnome_windowlist[WIN_MESSAGE].win != NULL) { gtk_signal_emit(GTK_OBJECT(gnome_windowlist[WIN_MESSAGE].win), ghack_signals[GHSIG_DELAY], (guint) 50); } } /* start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. */ void gnome_start_screen() { /* Do Nothing */ } /* end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). */ void gnome_end_screen() { /* Do Nothing */ } /* outrip(winid, int, when) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. */ void gnome_outrip(winid wid, int how, time_t when) { /* Follows roughly the same algorithm as genl_outrip() */ char buf[BUFSZ]; char ripString[BUFSZ] = "\0"; long year; /* Put name on stone */ Sprintf(buf, "%s\n", plname); Strcat(ripString, buf); /* Put $ on stone */ Sprintf(buf, "%ld Au\n", done_money); Strcat(ripString, buf); /* Put together death description */ formatkiller(buf, sizeof buf, how); /* Put death type on stone */ Strcat(ripString, buf); Strcat(ripString, "\n"); /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(buf, "%4ld\n", year); Strcat(ripString, buf); ghack_text_window_rip_string(ripString); } nethack-3.6.0/win/gnome/gnbind.h0000664000076400007660000000600112610522241015441 0ustar paxedpaxed/* NetHack 3.6 gnbind.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackBind_h #define GnomeHackBind_h /* * This header files defines the interface between the window port specific * code in the Gnome port and the rest of the nethack game engine. */ #include #include #include "gnomeprv.h" #include "gnmain.h" #include "gnmap.h" #include "gnmenu.h" #include "gnplayer.h" #include "gnsignal.h" #include "gnstatus.h" #include "gntext.h" #include "gnmesg.h" #include "gnyesno.h" #include "gnglyph.h" #include "gnworn.h" /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif typedef struct gnome_nhwindow_data { GtkWidget *win; int type; } GNHWinData; /* Some prototypes */ void gnome_init_nhwindows(int *argc, char **argv); void gnome_player_selection(void); void gnome_askname(void); void gnome_get_nh_event(void); void gnome_exit_nhwindows(const char *); void gnome_suspend_nhwindows(const char *); void gnome_resume_nhwindows(void); winid gnome_create_nhwindow(int type); void gnome_create_nhwindow_by_id(int type, winid i); void gnome_clear_nhwindow(winid wid); void gnome_display_nhwindow(winid wid, BOOLEAN_P block); void gnome_destroy_nhwindow(winid wid); void gnome_curs(winid wid, int x, int y); void gnome_putstr(winid wid, int attr, const char *text); void gnome_display_file(const char *filename, BOOLEAN_P must_exist); void gnome_start_menu(winid wid); void gnome_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel); void gnome_end_menu(winid wid, const char *prompt); int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected); /* No need for message_menu -- we'll use genl_message_menu instead */ void gnome_update_inventory(void); void gnome_mark_synch(void); void gnome_wait_synch(void); void gnome_cliparound(int x, int y); /* The following function does the right thing. The nethack * gnome_cliparound (which lacks the winid) simply calls this function. */ void gnome_cliparound_proper(winid wid, int x, int y); void gnome_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph); void gnome_raw_print(const char *str); void gnome_raw_print_bold(const char *str); int gnome_nhgetch(void); int gnome_nh_poskey(int *x, int *y, int *mod); void gnome_nhbell(void); int gnome_doprev_message(void); char gnome_yn_function(const char *question, const char *choices, CHAR_P def); void gnome_getlin(const char *question, char *input); int gnome_get_ext_cmd(void); void gnome_number_pad(int state); void gnome_delay_output(void); void gnome_start_screen(void); void gnome_end_screen(void); void gnome_outrip(winid wid, int how, time_t when); void gnome_delete_nhwindow_by_reference(GtkWidget *menuWin); #endif /* GnomeHackBind_h */ nethack-3.6.0/win/gnome/gnglyph.c0000664000076400007660000001447112536476415015677 0ustar paxedpaxed/* NetHack 3.6 gnglyph.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnglyph.h" #include "tile2x11.h" /* from tile.c */ extern int total_tiles_used; static GHackGlyphs ghack_glyphs; static GdkImlibImage **ghack_tiles = NULL; /* NAME: * ghack_init_glyphs(char* xpm_file) * * ARGUMENTS: * char *xpm_file -- The name of the image file. * May be any image format imlib recognizes. * Does not have to be XPM. * * RETURNS: * TRUE upon successful loading of the glyphs. * FALSE upon failure. * * PURPOSE: * Constructor for the Glyph object. Well, really each glyph * object is a collection of glyphs, or tiles. This constructor * takes a single argument: the name of the image file that contains * the tile images. * * NOTES: * The glyphs (tiles) must be in the image in a certain way: the * glyphs must be stacked such that the resultant image is * TILE_X * TILES_PER_ROW wide, and * TILE_Y * (number of glyphs) / TILES_PER_ROW high (rounded up). * In this sense, TILE_X == TILE_Y, and can be any reasonable integer * say, 16 <= TILE_X <= 64. Because the glyph number is tightly * coupled to the Nethack object it represents, the order of the * glyphs in the image is imporant: Glyph 1 is at the top of the * image, while Glyph N (the last glyph) is at the bottom. * * What's the difference between a glyph and a tile? Well, a * tile is just an image. A glyph is a tile that knows its * place in line. * * This initializer relies heavily on gdk_imlib. Thanks, Rasterman. */ int ghack_init_glyphs(const char *xpmFile) { ghack_glyphs.im = gdk_imlib_load_image((char *) xpmFile); if (!ghack_glyphs.im) { g_error("Couldn't load required xpmFile!"); return -1; } gdk_imlib_render(ghack_glyphs.im, ghack_glyphs.im->rgb_width, ghack_glyphs.im->rgb_height); if ((ghack_glyphs.im->rgb_width % TILES_PER_ROW) != 0 || ghack_glyphs.im->rgb_width <= TILES_PER_ROW) { g_error( "%s is not a multiple of %d (number of tiles/row) pixels wide", xpmFile, TILES_PER_ROW); return -1; } ghack_glyphs.count = total_tiles_used; if ((ghack_glyphs.count % TILES_PER_ROW) != 0) { ghack_glyphs.count += TILES_PER_ROW - (ghack_glyphs.count % TILES_PER_ROW); } ghack_glyphs.width = ghack_glyphs.im->rgb_width / TILES_PER_ROW; ghack_glyphs.height = ghack_glyphs.im->rgb_height / (ghack_glyphs.count / TILES_PER_ROW); /* Assume the tiles are organized in rows of TILES_PER_ROW */ ghack_tiles = g_new0(GdkImlibImage *, ghack_glyphs.count); return (ghack_tiles == NULL) ? -1 : 0; } void ghack_free_glyphs() { int i; for (i = 0; i < ghack_glyphs.count; i++) gdk_imlib_destroy_image(ghack_tiles[i]); g_free(ghack_tiles); gdk_imlib_destroy_image(ghack_glyphs.im); ghack_glyphs.im = NULL; } /* NAME: * ghack_glyph_count( ) * * ARGUMENTS: * None. * * RETURNS: * int -- The number of glyphs in this object. * * PURPOSE: * Simply reports the number of glyphs in this object. */ int ghack_glyph_count() { return ghack_glyphs.count; } /* NAME: * ghack_glyph_height() * * ARGUMENTS: * None * * RETURNS: * int -- The glyph height. * * PURPOSE: * Returns the standard glyph height. */ int ghack_glyph_height() { return ghack_glyphs.height; } /* NAME: * ghack_glyph_width() * * ARGUMENTS: * None * * RETURNS: * int -- The glyph width. * * PURPOSE: * Returns the standard glyph width. */ int ghack_glyph_width() { return ghack_glyphs.width; } /* NAME: * ghack_image_from_glyph( int glyph, gboolean force) * * ARGUMENTS: * int glyph -- The glyph number. * gboolean force -- force it to re-render. * * RETURNS: * GdkImlibImage* -- The glyph image, as a GdkImlibImage. * * PURPOSE: * Decodes the glyph into an image suitable for manipulation */ GdkImlibImage * ghack_image_from_glyph(int glyph, gboolean force) { int tile = glyph2tile[glyph]; if (tile >= ghack_glyphs.count || tile < 0) { g_warning( "Aiiee! I've was asked for a tile outside the allowed range!\n" "Email this to other-gnomehack@lists.debian.org"); g_warning("Max tile: %d Tile asked for: %d", ghack_glyphs.count, tile); return NULL; } if (ghack_glyphs.im == NULL) { g_warning("Aiiee! I've been asked to clone from a null image.\n" "Email this to other-gnomehack@lists.debian.org"); g_warning("making image from tile %d, force=%s\n", tile, (force == TRUE) ? "TRUE" : "FALSE"); } if (force == TRUE) { g_warning("Aiiee! I've been asked to force rendering.\n" "Email this to other-gnomehack@lists.debian.org"); g_warning("making image from tile %d, force=%s\n", tile, (force == TRUE) ? "TRUE" : "FALSE"); } if (!ghack_tiles[tile] || force) { int src_x, src_y; #if 0 fprintf( stderr, "crop_and_clone: glyph=%d, tile=%d, ptr=%p, x=%d, y=%d, w=%d, h=%d\n", glyph, tile, (void*)&(ghack_tiles[tile]), 0, tile * ghack_glyphs.width, ghack_glyphs.height, ghack_glyphs.width); #endif if (ghack_glyphs.im->pixmap == NULL) g_warning("Aiiee! ghack_glyphs.im->pixmap==NULL!!!!\n"); src_x = (tile % TILES_PER_ROW) * ghack_glyphs.width; src_y = (tile / TILES_PER_ROW) * ghack_glyphs.height; ghack_tiles[tile] = gdk_imlib_crop_and_clone_image( ghack_glyphs.im, src_x, src_y, ghack_glyphs.width, ghack_glyphs.height); } if (ghack_tiles[tile] && (!ghack_tiles[tile]->pixmap || force)) { if (gdk_imlib_render(ghack_tiles[tile], ghack_tiles[tile]->rgb_width, ghack_tiles[tile]->rgb_height) == 0) { g_error("GLYPH: couldn't create tile # %d", tile); } if (!ghack_tiles[tile]->pixmap) g_error("Strange, tile # %d didn't get rendered???", tile); } return ghack_tiles[tile]; } nethack-3.6.0/win/gnome/gnglyph.h0000664000076400007660000000213012536476415015671 0ustar paxedpaxed/* NetHack 3.6 gnglyph.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackGlyph_h #define GnomeHackGlyph_h #include "config.h" #include "global.h" /* the prototypes in system headers contain useless argument names that trigger spurious warnings if gcc's `-Wshadow' option is used */ #undef index #define index _hide_index_ #define time _hide_time_ #include #include #undef index #define index strchr #undef time extern short glyph2tile[]; /* From tile.c */ typedef struct { GdkImlibImage *im; int count; int width; int height; } GHackGlyphs; extern int ghack_init_glyphs(const char *); extern void ghack_free_glyphs(void); extern void ghack_dispose_glyphs(void); extern int ghack_glyph_count(void); extern GdkImlibImage *ghack_image_from_glyph(int, gboolean); extern int ghack_glyph_height(void); extern int ghack_glyph_width(void); #endif /* GnomeHackGlyph_h */ nethack-3.6.0/win/gnome/gnmain.c0000664000076400007660000006323112536476415015476 0ustar paxedpaxed/* NetHack 3.6 gnmain.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnmain.h" #include "gnsignal.h" #include "gnbind.h" #include "gnopts.h" #include #include #include #include #include #include #include "hack.h" #include "date.h" static GtkWidget *mainWindow = NULL; static GtkWidget *about = NULL; static GtkWidget *hBoxFirstRow; static GtkWidget *vBoxMain; int restarted = 0; int os_x = 0, os_y = 0, os_w = 0, os_h = 0; static GnomeClient *session_id; static void ghack_quit_game(GtkWidget *widget, int button) { gtk_widget_hide(widget); if (button == 0) { gnome_exit_nhwindows(0); gtk_object_unref(GTK_OBJECT(session_id)); clearlocks(); gtk_exit(0); } } static void ghack_quit_game_cb(GtkWidget *widget, gpointer data) { GtkWidget *box; box = gnome_message_box_new( _("Do you really want to quit?"), GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); gnome_dialog_set_default(GNOME_DIALOG(box), 1); gnome_dialog_set_parent(GNOME_DIALOG(box), GTK_WINDOW(ghack_get_main_window())); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 1, 'n', 0); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'y', 0); gtk_window_set_modal(GTK_WINDOW(box), TRUE); gtk_signal_connect(GTK_OBJECT(box), "clicked", (GtkSignalFunc) ghack_quit_game, NULL); gtk_widget_show(box); } static void ghack_save_game(GtkWidget *widget, int button) { gtk_widget_hide(widget); if (button == 0) { if (dosave0()) { /* make sure they see the Saving message */ display_nhwindow(WIN_MESSAGE, TRUE); gnome_exit_nhwindows("Be seeing you..."); clearlocks(); gtk_exit(0); } else (void) doredraw(); } } void ghack_save_game_cb(GtkWidget *widget, gpointer data) { GtkWidget *box; box = gnome_message_box_new( _("Quit and save the current game?"), GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); gnome_dialog_set_default(GNOME_DIALOG(box), 1); gnome_dialog_set_parent(GNOME_DIALOG(box), GTK_WINDOW(ghack_get_main_window())); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 1, 'n', 0); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'y', 0); gtk_window_set_modal(GTK_WINDOW(box), TRUE); gtk_signal_connect(GTK_OBJECT(box), "clicked", (GtkSignalFunc) ghack_save_game, NULL); gtk_widget_show(box); } static void ghack_new_game(GtkWidget *widget, int button) { if (button == 0) { g_message("This feature is not yet implemented. Sorry."); } } static void ghack_new_game_cb(GtkWidget *widget, gpointer data) { GtkWidget *box; box = gnome_message_box_new( _("Start a new game?"), GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); gnome_dialog_set_default(GNOME_DIALOG(box), 1); gnome_dialog_set_parent(GNOME_DIALOG(box), GTK_WINDOW(ghack_get_main_window())); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 1, 'n', 0); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'y', 0); gtk_window_set_modal(GTK_WINDOW(box), TRUE); gtk_signal_connect(GTK_OBJECT(box), "clicked", (GtkSignalFunc) ghack_new_game, NULL); gtk_widget_show(box); } static void about_destroy_callback(void) { about = NULL; } static void ghack_about_cb(GtkWidget *widget, gpointer data) { char buf[BUFSZ] = "\0"; char buf1[BUFSZ] = "\0"; const gchar *authors[] = { "Erik Andersen", "Anthony Taylor", "Jeff Garzik", "The Nethack Dev Team", NULL }; if (about) { gdk_window_raise(about->window); return; } getversionstring(buf); #if 0 /* XXX this needs further re-write to use DEVTEAM_EMAIL, DEVTEAM_URL, * sysopt.support, etc. I'm not doing it now because I can't test * it yet. (keni) */ /* out of date first cut: */ ! len = strlen(buf); ! char *str1 = _("\nSend comments and bug reports to:\n"); ! len += strlen(str1); ! len += sysopt.email; ! char *str2 = _("\nThis game is free software. See License for details."); ! len += strlen(str2); ! str = (char*)alloc(len+1); ! strcat(buf, str1); ! strcat(buf, sysopt.email); ! strcat(buf, str2); free(str) below #else strcat(buf1, VERSION_STRING); strcat(buf, _("\nSend comments and bug reports to: nethack-bugs@nethack.org\n" "This game is free software. See License for details.")); #endif about = gnome_about_new(_("Nethack"), buf1, "Copyright (C) 1985-2002 Mike Stephenson", (const char **) authors, buf, NULL); gtk_signal_connect(GTK_OBJECT(about), "destroy", (GtkSignalFunc) about_destroy_callback, NULL); gtk_widget_show(about); } static void ghack_settings_cb(GtkWidget *widget, gpointer data) { ghack_settings_dialog(); } static void ghack_accelerator_selected(GtkWidget *widget, gpointer data) { GdkEventKey event; int key = GPOINTER_TO_INT(data); /* g_message("An accelerator for \"%c\" was selected", key); */ /* stuff a key directly into the keybuffer */ event.state = 0; event.keyval = key; ghack_handle_key_press(NULL, &event, NULL); } #ifndef M #ifndef NHSTDC #define M(c) (0x80 | (c)) #else #define M(c) ((c) -128) #endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif GnomeUIInfo game_tree[] = { { GNOME_APP_UI_ITEM, N_("_Change Settings..."), N_("Change Game Settings"), ghack_settings_cb, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, 0, 0, NULL }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Version"), NULL, ghack_accelerator_selected, GINT_TO_POINTER('v'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'v', 0 }, { GNOME_APP_UI_ITEM, N_("History..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER('V'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'V', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Compilation..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER(M('v')), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'v', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Options..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER('O'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF, 'O', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Explore Mode..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER('X'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'X', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_NEW_GAME_ITEM(ghack_new_game_cb, NULL), GNOMEUIINFO_MENU_SAVE_ITEM(ghack_save_game_cb, NULL), { GNOME_APP_UI_ITEM, N_("Exit"), NULL, ghack_quit_game_cb, GINT_TO_POINTER(M('Q')), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'Q', GDK_MOD1_MASK }, GNOMEUIINFO_END }; GnomeUIInfo edit_menu[] = { { GNOME_APP_UI_ITEM, N_("Inventory"), N_("Edit/View your Inventory"), ghack_accelerator_selected, GINT_TO_POINTER('i'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i', 0 }, { GNOME_APP_UI_ITEM, N_("Discoveries"), N_("Edit/View your Discoveries"), ghack_accelerator_selected, GINT_TO_POINTER('\\'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '\\', 0 }, { GNOME_APP_UI_ITEM, N_("List/reorder your spells"), N_("List/reorder your spells"), ghack_accelerator_selected, GINT_TO_POINTER('x'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'x', 0 }, { GNOME_APP_UI_ITEM, N_("Adjust letters"), N_("Adjust letter for items in your Inventory"), ghack_accelerator_selected, GINT_TO_POINTER(M('a')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a', GDK_MOD1_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Name object"), N_("Assign a name to an object"), ghack_accelerator_selected, GINT_TO_POINTER(M('n')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'n', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Name creature"), N_("Assign a name to a creature"), ghack_accelerator_selected, GINT_TO_POINTER('C'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'C', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Qualifications"), N_("Edit your Qualifications"), ghack_accelerator_selected, GINT_TO_POINTER(M('e')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e', GDK_MOD1_MASK }, GNOMEUIINFO_END }; GnomeUIInfo apparel_menu[] = { { GNOME_APP_UI_ITEM, N_("Wield Weapon"), N_("Select a weapon to fight with"), ghack_accelerator_selected, GINT_TO_POINTER('w'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w', 0 }, { GNOME_APP_UI_ITEM, N_("Remove Apparel..."), N_("Remove apparel dialog bog"), ghack_accelerator_selected, GINT_TO_POINTER('A'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'A', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Wear Armor"), N_("Put on armor"), ghack_accelerator_selected, GINT_TO_POINTER('W'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'W', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Take off Armor"), N_("Take off armor you are wearing"), ghack_accelerator_selected, GINT_TO_POINTER('T'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'T', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Put on non-armor"), N_("Put on non-armor apparel"), ghack_accelerator_selected, GINT_TO_POINTER('P'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'P', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Remove non-armor"), N_("Remove non-armor apparel you are wearing"), ghack_accelerator_selected, GINT_TO_POINTER('R'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R', GDK_SHIFT_MASK }, GNOMEUIINFO_END }; GnomeUIInfo action_menu[] = { { GNOME_APP_UI_ITEM, N_("Get"), N_("Pick up things at the current location"), ghack_accelerator_selected, GINT_TO_POINTER(','), NULL, GNOME_APP_PIXMAP_NONE, NULL, ',', 0 }, { GNOME_APP_UI_ITEM, N_("Loot"), N_("loot a box on the floor"), ghack_accelerator_selected, GINT_TO_POINTER(M('l')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'l', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Sit"), N_("sit down"), ghack_accelerator_selected, GINT_TO_POINTER(M('s')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Force"), N_("force a lock"), ghack_accelerator_selected, GINT_TO_POINTER(M('f')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'f', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Kick"), N_("kick something (usually a door)"), ghack_accelerator_selected, GINT_TO_POINTER(C('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd', GDK_CONTROL_MASK }, { GNOME_APP_UI_ITEM, N_("Jump"), N_("jump to another location"), ghack_accelerator_selected, GINT_TO_POINTER(M('j')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'j', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Ride"), N_("Ride (or stop riding) a monster"), doride, GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Wipe face"), N_("wipe off your face"), ghack_accelerator_selected, GINT_TO_POINTER(M('w')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Throw/Shoot"), N_("throw or shoot a weapon"), ghack_accelerator_selected, GINT_TO_POINTER('t'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't', 0 }, { GNOME_APP_UI_ITEM, N_("Quiver/Ready"), N_("ready or quiver some ammunition"), ghack_accelerator_selected, GINT_TO_POINTER('Q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Q', GDK_SHIFT_MASK, }, { GNOME_APP_UI_ITEM, N_("Open Door"), N_("open a door"), ghack_accelerator_selected, GINT_TO_POINTER('o'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o', 0 }, { GNOME_APP_UI_ITEM, N_("Close Door"), N_("open a door"), ghack_accelerator_selected, GINT_TO_POINTER('c'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c', 0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Drop"), N_("drop an object"), ghack_accelerator_selected, GINT_TO_POINTER('d'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd', 0 }, { GNOME_APP_UI_ITEM, N_("Drop Many"), N_("drop selected types of objects"), ghack_accelerator_selected, GINT_TO_POINTER('D'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'D', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Eat"), N_("eat something"), ghack_accelerator_selected, GINT_TO_POINTER('e'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e', 0 }, { GNOME_APP_UI_ITEM, N_("Engrave"), N_("write a message in the dust on the floor"), ghack_accelerator_selected, GINT_TO_POINTER('E'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'E', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Apply"), N_("apply or use a tool (pick-axe, key, camera, etc.)"), ghack_accelerator_selected, GINT_TO_POINTER('a'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a', 0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Up"), N_("go up the stairs"), ghack_accelerator_selected, GINT_TO_POINTER('<'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '<', 0 }, { GNOME_APP_UI_ITEM, N_("Down"), N_("go down the stairs"), ghack_accelerator_selected, GINT_TO_POINTER('>'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '>', 0 }, { GNOME_APP_UI_ITEM, N_("Rest"), N_("wait for a moment"), ghack_accelerator_selected, GINT_TO_POINTER('.'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '.', 0 }, { GNOME_APP_UI_ITEM, N_("Search"), N_("search for secret doors, hidden traps and monsters"), ghack_accelerator_selected, GINT_TO_POINTER('s'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's', 0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Chat"), N_("talk to someone"), ghack_accelerator_selected, GINT_TO_POINTER(M('c')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Pay"), N_("pay your bill to the shopkeeper"), ghack_accelerator_selected, GINT_TO_POINTER('p'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p', 0 }, GNOMEUIINFO_END }; GnomeUIInfo magic_menu[] = { { GNOME_APP_UI_ITEM, N_("Quaff potion"), N_("drink a potion"), ghack_accelerator_selected, GINT_TO_POINTER('q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'q', 0 }, { GNOME_APP_UI_ITEM, N_("Read Book/Scroll"), N_("read a spell book or a scroll"), ghack_accelerator_selected, GINT_TO_POINTER('r'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r', 0 }, { GNOME_APP_UI_ITEM, N_("Zap Wand"), N_("zap a wand"), ghack_accelerator_selected, GINT_TO_POINTER('z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'z', 0 }, { GNOME_APP_UI_ITEM, N_("Zap Spell"), N_("cast a spell"), ghack_accelerator_selected, GINT_TO_POINTER('Z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Z', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Dip"), N_("dip an object into something"), ghack_accelerator_selected, GINT_TO_POINTER(M('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Rub"), N_("Rub something (i.e. a lamp)"), ghack_accelerator_selected, GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Invoke"), N_("invoke an object's special powers"), ghack_accelerator_selected, GINT_TO_POINTER(M('i')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i', GDK_MOD1_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Offer"), N_("offer a sacrifice to the gods"), ghack_accelerator_selected, GINT_TO_POINTER(M('o')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Pray"), N_("pray to the gods for help"), ghack_accelerator_selected, GINT_TO_POINTER(M('p')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p', GDK_MOD1_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Teleport"), N_("teleport (if you can)"), ghack_accelerator_selected, GINT_TO_POINTER(C('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't', GDK_CONTROL_MASK }, { GNOME_APP_UI_ITEM, N_("Monster Action"), N_("use a monster's special ability"), ghack_accelerator_selected, GINT_TO_POINTER(M('m')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'm', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Turn Undead"), N_("turn undead"), ghack_accelerator_selected, GINT_TO_POINTER(M('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't', GDK_MOD1_MASK }, GNOMEUIINFO_END }; GnomeUIInfo help_menu[] = { { GNOME_APP_UI_ITEM, N_("About..."), N_("About GnomeHack"), ghack_about_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 0, 0, NULL }, { GNOME_APP_UI_ITEM, N_("Help"), NULL, ghack_accelerator_selected, GINT_TO_POINTER('?'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, '?', 0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("What is here"), N_("Check what items occupy the current location"), ghack_accelerator_selected, GINT_TO_POINTER(':'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, ':', 0 }, { GNOME_APP_UI_ITEM, N_("What is that"), N_("Identify an object"), ghack_accelerator_selected, GINT_TO_POINTER(';'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, ';', 0 }, { GNOME_APP_UI_ITEM, N_("Identify a map symbol"), N_("Identify a map symbol"), ghack_accelerator_selected, GINT_TO_POINTER('/'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, '/', 0 }, GNOMEUIINFO_END }; GnomeUIInfo mainmenu[] = { GNOMEUIINFO_MENU_GAME_TREE(game_tree), GNOMEUIINFO_MENU_EDIT_TREE(edit_menu), { GNOME_APP_UI_SUBTREE, N_("Apparel"), NULL, apparel_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, { GNOME_APP_UI_SUBTREE, N_("Action"), NULL, action_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, { GNOME_APP_UI_SUBTREE, N_("Magic"), NULL, magic_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, GNOMEUIINFO_MENU_HELP_TREE(help_menu), GNOMEUIINFO_END }; static void ghack_main_window_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { /* First, turn off the key press propogation. We've got the * key, but we don't wan't the underlying Gtk widgets to get it, * since they do the wrong thing with the arrow keys (shift focus)... */ gtk_signal_emit_stop_by_name(GTK_OBJECT(mainWindow), "key_press_event"); /* stuff the key event into the keybuffer */ ghack_handle_key_press(widget, event, data); } /* parsing args */ void parse_args(int argc, char *argv[]) { gint ch; struct option options[] = { /* Default args */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; gchar *id = NULL; /* initialize getopt */ optarg = NULL; optind = 0; optopt = 0; while ((ch = getopt_long(argc, argv, "hv", options, NULL)) != EOF) { switch (ch) { case 'h': g_print( _("%s: A gnomified 'Hello World' program\n\n" "Usage: %s [--help] [--version]\n\n" "Options:\n" " --help display this help and exit\n" " --version output version information and exit\n"), argv[0], argv[0]); exit(0); break; case 'v': g_print(_("NetHack %s.\n"), VERSION_STRING); exit(0); break; case ':': case '?': g_print(_("Options error\n")); exit(0); break; } } /* SM stuff */ session_id = gnome_client_new(); #if 0 session_id = gnome_client_new ( /* callback to save the state and parameter for it */ save_state, argv[0], /* callback to die and parameter for it */ NULL, NULL, /* id from the previous session if restarted, NULL otherwise */ id); #endif /* set the program name */ gnome_client_set_program(session_id, argv[0]); g_free(id); return; } /* * [ALI] Gnome installs its own handler(s) for SIGBUS, SIGFPE and SIGSEGV. * These handlers will fork and exec a helper program. When that helper * comes to initialize GTK+, it may fail if setuid/setgid. We solve this * by dropping privileges before passing the signal along the chain. * Note: We don't need to either drop or mask the saved ID since this * will be reset when the child process performs the execve() anyway. */ static struct { int signum; void (*handler)(int); } ghack_chain[] = { { SIGBUS }, { SIGFPE }, { SIGSEGV }, { SIGILL } /* Not currently handled by Gnome */ }; static void ghack_sig_handler(int signum) { int i; uid_t uid, euid; gid_t gid, egid; uid = getuid(); euid = geteuid(); gid = getgid(); egid = getegid(); if (gid != egid) setgid(gid); if (uid != euid) setuid(uid); for (i = SIZE(ghack_chain) - 1; i >= 0; i--) if (ghack_chain[i].signum == signum) { ghack_chain[i].handler(signum); break; } if (i < 0) impossible("Unhandled ghack signal"); if (uid != euid) setuid(euid); if (gid != egid) setgid(egid); } /* initialize gnome and fir up the main window */ void ghack_init_main_window(int argc, char **argv) { int i; struct timeval tv; uid_t uid, euid; /* It seems that the authors of gnome_score_init() drop group * priveledges. We need group priveledges, so until we change the * way we save games to do things the gnome way(???), this stays * commented out. (after hours of frusteration...) * -Erik */ /* gnome_score_init("gnomehack"); */ gettimeofday(&tv, NULL); srand(tv.tv_usec); uid = getuid(); euid = geteuid(); if (uid != euid) setuid(uid); hide_privileges(TRUE); /* XXX gnome_init must print nethack options for --help, but does not */ gnome_init("nethack", VERSION_STRING, argc, argv); hide_privileges(FALSE); parse_args(argc, argv); /* Initialize the i18n stuff (not that gnomehack supperts it yet...) */ #if 0 textdomain (PACKAGE); #endif gdk_imlib_init(); /* Main window */ mainWindow = gnome_app_new((char *) "nethack", (char *) N_("Nethack for Gnome")); gtk_widget_realize(mainWindow); if (restarted) { gtk_widget_set_uposition(mainWindow, os_x, os_y); gtk_widget_set_usize(mainWindow, os_w, os_h); } gtk_window_set_default_size(GTK_WINDOW(mainWindow), 800, 600); gtk_window_set_policy(GTK_WINDOW(mainWindow), FALSE, TRUE, TRUE); gnome_app_create_menus(GNOME_APP(mainWindow), mainmenu); gtk_signal_connect(GTK_OBJECT(mainWindow), "key_press_event", GTK_SIGNAL_FUNC(ghack_main_window_key_press), NULL); gtk_signal_connect(GTK_OBJECT(mainWindow), "delete_event", GTK_SIGNAL_FUNC(ghack_quit_game_cb), NULL); /* Put some stuff into our main window */ vBoxMain = gtk_vbox_new(FALSE, 0); hBoxFirstRow = gtk_hbox_new(FALSE, 0); /* pack Boxes into other boxes to produce the right structure */ gtk_box_pack_start(GTK_BOX(vBoxMain), hBoxFirstRow, FALSE, TRUE, 0); /* pack vBoxMain which contains all our widgets into the main window. */ gnome_app_set_contents(GNOME_APP(mainWindow), vBoxMain); /* DONT show the main window yet, due to a Gtk bug that causes it * to not refresh the window when adding widgets after the window * has already been shown */ if (uid != euid) setuid(euid); for (i = 0; i < SIZE(ghack_chain); i++) ghack_chain[i].handler = signal(ghack_chain[i].signum, ghack_sig_handler); } void ghack_main_window_add_map_window(GtkWidget *win) { GtkWidget *vBox; vBox = gtk_vbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(vBox), win, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(vBoxMain), vBox, TRUE, TRUE, 2); gtk_widget_show_all(vBox); /* Ok, now show the main window -- now that we have added in * all the windows (relys on nethack displaying the map window last * (This is an ugly kludge, BTW) */ gtk_widget_show_all(mainWindow); } void ghack_main_window_add_message_window(GtkWidget *win) { gtk_box_pack_start(GTK_BOX(hBoxFirstRow), win, TRUE, TRUE, 2); gtk_widget_show_all(win); } void ghack_main_window_add_status_window(GtkWidget *win) { gtk_box_pack_start(GTK_BOX(hBoxFirstRow), win, FALSE, TRUE, 2); gtk_widget_show_all(win); } void ghack_main_window_add_worn_window(GtkWidget *win) { gtk_box_pack_end(GTK_BOX(hBoxFirstRow), win, FALSE, TRUE, 2); gtk_widget_show_all(win); } void ghack_main_window_add_text_window(GtkWidget *win) { g_warning("Fixme!!! AddTextWindow is not yet implemented"); } void ghack_main_window_remove_window(GtkWidget *win) { g_warning("Fixme!!! RemoveWindow is not yet implemented"); } void ghack_main_window_update_inventory() { /* For now, do very little. Eventually we may allow the inv. window to stay active. When we do this, we'll need to implement this... g_warning("Fixme!!! updateInventory is not yet implemented"); */ gnome_display_nhwindow(WIN_WORN, FALSE); } GtkWidget * ghack_get_main_window() { return (GTK_WIDGET(mainWindow)); } nethack-3.6.0/win/gnome/gnmain.h0000664000076400007660000000162012536476415015475 0ustar paxedpaxed/* NetHack 3.6 gnmain.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMainWindow_h #define GnomeHackMainWindow_h #include #include void ghack_init_main_window(int argc, char **argv); void ghack_main_window_add_map_window(GtkWidget *win); void ghack_main_window_add_message_window(GtkWidget *win); void ghack_main_window_add_status_window(GtkWidget *win); void ghack_main_window_add_text_window(GtkWidget *); void ghack_main_window_add_worn_window(GtkWidget *win); void ghack_main_window_remove_window(GtkWidget *); void ghack_main_window_update_inventory(); void ghack_save_game_cb(GtkWidget *widget, gpointer data); GtkWidget *ghack_get_main_window(); #endif /* GnomeHackMainWindow_h */ nethack-3.6.0/win/gnome/gnmap.c0000664000076400007660000004416612536476415015335 0ustar paxedpaxed/* NetHack 3.6 gnmap.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #include "gnmap.h" #include "gnglyph.h" #include "gnsignal.h" #include "hack.h" #ifndef ROWNO #define ROWNO 21 #define COLNO 80 #endif /* globals static to this file go here */ struct { GnomeCanvas *canvas; GnomeCanvasImage *map[(ROWNO + 1) * COLNO]; GnomeCanvasImage *overlay[(ROWNO + 1) * COLNO]; double zoom; GtkWidget *frame; } ghack_map; static GdkImlibImage *background; static GdkImlibImage *petmark; static GnomeCanvasGroup *myCanvasGroup; /* static function declarations -- local to this file go here */ void ghack_map_cursor_to(GtkWidget *win, int x, int y, gpointer data); void ghack_map_putstr(GtkWidget *win, int attr, const char *text, gpointer data); void ghack_map_print_glyph(GtkObject *win, guint x, guint y, GdkImlibImage *im, gpointer data); void ghack_map_clear(GtkWidget *win, gpointer data); static void ghack_map_display(GtkWidget *win, boolean block, gpointer data); static void ghack_map_cliparound(GtkWidget *win, int x, int y, gpointer data); static void ghack_map_window_zoom(GtkAdjustment *adj, gpointer data); /* The following XPM is the artwork of Warwick Allison * . It has been borrowed from * the most excellent NetHackQt, until such time as * we can come up with something better. * * More information about NetHackQt can be had from: * http://www.troll.no/~warwick/nethack/ */ /* XPM */ static char *pet_mark_xpm[] = { /* width height ncolors chars_per_pixel */ "8 7 2 1", /* colors */ ". c None", " c #FF0000", /* pixels */ "........", ".. . .", ". ", ". ", ".. .", "... ..", ".... ..." }; /* NAME: * ghack_init_map_window( ) * * ARGUMENTS: * NONE * * RETURNS: * GtkWidget* * * PURPOSE: * Create the basic map necessities. Create a canvas; * give it a background. Attach all the right signals * to all the right places. Generally prepare the map * to behave properly. */ GtkWidget * ghack_init_map_window() { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *table; GtkWidget *frame; GtkWidget *w; GtkWidget *hSeparator; GtkAdjustment *adj; GnomeCanvasImage *bg; double width, height, x, y; int i; width = COLNO * ghack_glyph_width(); height = ROWNO * ghack_glyph_height(); vbox = gtk_vbox_new(FALSE, 4); gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); gtk_widget_show(vbox); /* Add in a horiz seperator */ hSeparator = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), hSeparator, FALSE, FALSE, 2); gtk_widget_show(hSeparator); hbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); /* Create the Zoom spinbutton. */ ghack_map.zoom = 1.0; w = gtk_label_new("Zoom:"); gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 0); gtk_widget_show(w); adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.00, 0.5, 3.00, 0.05, 0.50, 0.50)); w = gtk_spin_button_new(adj, 0.5, 2); gtk_widget_set_usize(w, 50, 0); gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 0); gtk_widget_show(w); /* Canvas and scrollbars */ gtk_widget_push_visual(gdk_imlib_get_visual()); gtk_widget_push_colormap(gdk_imlib_get_colormap()); ghack_map.canvas = GNOME_CANVAS(gnome_canvas_new()); // gtk_widget_push_visual(gdk_rgb_get_visual()); // gtk_widget_push_colormap(gdk_rgb_get_cmap()); // ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new_aa()); gtk_widget_pop_colormap(); gtk_widget_pop_visual(); gtk_widget_show(GTK_WIDGET(ghack_map.canvas)); table = gtk_table_new(2, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 4); gtk_table_set_col_spacings(GTK_TABLE(table), 4); gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); gtk_widget_show(table); frame = gtk_frame_new(NULL); ghack_map.frame = frame; gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); gtk_widget_show(frame); gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(ghack_map.canvas)); gnome_canvas_set_scroll_region(GNOME_CANVAS(ghack_map.canvas), 0, 0, width + 2 * ghack_glyph_width(), height + 2 * ghack_glyph_height()); gnome_canvas_set_pixels_per_unit(GNOME_CANVAS(ghack_map.canvas), 1.0); w = gtk_hscrollbar_new(GTK_LAYOUT(ghack_map.canvas)->hadjustment); gtk_table_attach(GTK_TABLE(table), w, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 0, 0); gtk_widget_show(w); w = gtk_vscrollbar_new(GTK_LAYOUT(ghack_map.canvas)->vadjustment); gtk_table_attach(GTK_TABLE(table), w, 1, 2, 0, 1, GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); gtk_widget_show(w); myCanvasGroup = GNOME_CANVAS_GROUP(gnome_canvas_item_new( gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), gnome_canvas_group_get_type(), "x", 0.0, "y", 0.0, NULL)); /* Tile the map background with a pretty image */ background = gdk_imlib_load_image((char *) "mapbg.xpm"); if (background == NULL) { g_warning( "Bummer! Failed to load the map background image (mapbg.xpm)!"); } else { gdk_imlib_render(background, background->rgb_width, background->rgb_height); /* Tile the map background */ for (y = 0; y < height + background->rgb_height; y += background->rgb_height) { for (x = 0; x < width + background->rgb_width; x += background->rgb_width) { bg = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, "y", (double) y, "width", (double) background->rgb_width, "height", (double) background->rgb_height, "image", background, "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER, NULL)); gnome_canvas_item_lower_to_bottom(GNOME_CANVAS_ITEM(bg)); } } } /* ghack_map.map is an array of canvas images. Each cell of * the array will contain one tile. Here, we create the * space for the cells and then create the cells for easy * access later. */ for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { for (x = 0; x < width; x += ghack_glyph_width()) { ghack_map.map[i++] = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, "y", (double) y, "width", (double) ghack_glyph_width(), "height", (double) ghack_glyph_height(), "anchor", GTK_ANCHOR_NORTH_WEST, NULL)); } } /* Set up the pet mark image */ petmark = gdk_imlib_create_image_from_xpm_data(pet_mark_xpm); if (petmark == NULL) { g_warning("Bummer! Failed to load the pet_mark image!"); } else { gdk_imlib_render(petmark, petmark->rgb_width, petmark->rgb_height); /* ghack_map.overlay is an array of canvas images used to * overlay tile images... */ for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { for (x = 0; x < width; x += ghack_glyph_width()) { ghack_map.overlay[i] = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, "y", (double) y, "width", (double) petmark->rgb_width, "height", (double) petmark->rgb_height, "image", petmark, "anchor", GTK_ANCHOR_NORTH_WEST, NULL)); gnome_canvas_item_lower_to_bottom( GNOME_CANVAS_ITEM(ghack_map.overlay[i++])); } } } /* Resize the canvas when the spinbutton changes */ gtk_signal_connect(GTK_OBJECT(adj), "value_changed", (GtkSignalFunc) ghack_map_window_zoom, ghack_map.canvas); /* Game signals */ gtk_signal_connect(GTK_OBJECT(vbox), "ghack_curs", GTK_SIGNAL_FUNC(ghack_map_cursor_to), NULL); gtk_signal_connect(GTK_OBJECT(vbox), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_map_putstr), NULL); gtk_signal_connect(GTK_OBJECT(vbox), "ghack_print_glyph", GTK_SIGNAL_FUNC(ghack_map_print_glyph), NULL); gtk_signal_connect(GTK_OBJECT(vbox), "ghack_clear", GTK_SIGNAL_FUNC(ghack_map_clear), NULL); gtk_signal_connect(GTK_OBJECT(vbox), "ghack_display", GTK_SIGNAL_FUNC(ghack_map_display), NULL); gtk_signal_connect(GTK_OBJECT(vbox), "ghack_cliparound", GTK_SIGNAL_FUNC(ghack_map_cliparound), NULL); gtk_signal_connect(GTK_OBJECT(ghack_map.canvas), "button_press_event", GTK_SIGNAL_FUNC(ghack_handle_button_press), NULL); gtk_signal_connect(GTK_OBJECT(ghack_map.canvas), "gnome_delay_output", GTK_SIGNAL_FUNC(ghack_delay), NULL); return GTK_WIDGET(vbox); } /* NAME: * ghack_map_window_zoom * * ARGUMENTS: * double zoom -- The zoom factor * * RETURNS: * Nothing. * * PURPOSE: * Zoom the map image in and out. This should allow the user to * dynamically scale the map. Ideally, the background should * *NOT* scale, but this may be impractical. */ static void ghack_map_window_zoom(GtkAdjustment *adj, gpointer data) { if (adj->value > 3.0) adj->value = 3.0; if (adj->value < 0.5) adj->value = 0.5; ghack_map.zoom = adj->value; gnome_canvas_set_pixels_per_unit(data, adj->value); } void ghack_map_cursor_to(GtkWidget *win, int x, int y, gpointer data) { GnomeCanvasGroup *group; static GnomeCanvasRE *cursor = NULL; double x1, y1, x2, y2; float hp; guint r, g, b; x1 = x * ghack_glyph_width() - 1; y1 = y * ghack_glyph_height() - 1; x2 = x1 + ghack_glyph_width() + 2; y2 = y1 + ghack_glyph_height() + 2; hp = u.mtimedone ? (u.mhmax ? (float) u.mh / u.mhmax : 1) : (u.uhpmax ? (float) u.uhp / u.uhpmax : 1); r = 255; g = (hp >= 0.75) ? 255 : (hp >= 0.25 ? 255 * 2 * (hp - 0.25) : 0); b = (hp >= 0.75) ? 255 * 4 * (hp - 0.75) : (hp >= 0.25 ? 0 : 255 * 4 * (0.25 - hp)); group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)); if (!cursor) { cursor = GNOME_CANVAS_RE(gnome_canvas_item_new( group, gnome_canvas_rect_get_type(), "width_units", 1.0, NULL)); } gnome_canvas_item_set(GNOME_CANVAS_ITEM(cursor), "outline_color_rgba", GNOME_CANVAS_COLOR(r, g, b), "x1", x1, "y1", y1, "x2", x2, "y2", y2, NULL); gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(cursor)); gnome_canvas_item_show(GNOME_CANVAS_ITEM(cursor)); } void ghack_map_putstr(GtkWidget *win, int attr, const char *text, gpointer data) { g_warning("Fixme!!! ghack_map_putstr is not implemented"); } /* NAME: * ghack_map_print_glyph( ) * * ARGUMENTS: * XCHAR_P x, y -- The coordinates where which to print the glyph * GdkImlibImage* glyph -- The glyph image to print * * RETURNS: * Nothing. * * PURPOSE: * Draw the glyph-tile at the specified coordinates. */ void ghack_map_print_glyph(GtkObject *win, guint x, guint y, GdkImlibImage *im, gpointer data) { GnomeCanvasGroup *group; int i = y * COLNO + x; int glyph = glyph_at(x, y); GnomeCanvasImage *canvas_image = GNOME_CANVAS_IMAGE(ghack_map.map[i]); group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)); gnome_canvas_item_set(GNOME_CANVAS_ITEM(canvas_image), "image", im, NULL); gnome_canvas_item_show(GNOME_CANVAS_ITEM(canvas_image)); canvas_image = GNOME_CANVAS_IMAGE(ghack_map.overlay[i]); if (x == u.ux && y == u.uy) ghack_map_cliparound(NULL, x, y, NULL); if (glyph_is_pet(glyph) #ifdef TEXTCOLOR && iflags.hilite_pet #endif ) { gnome_canvas_item_raise_to_top(GNOME_CANVAS_ITEM(canvas_image)); gnome_canvas_item_show(GNOME_CANVAS_ITEM(canvas_image)); } else { gnome_canvas_item_hide(GNOME_CANVAS_ITEM(canvas_image)); } } /* NAME: * ghack_map_clear( ) * * ARGUMENTS: * NONE * * RETURNS: * Nothing. * * PURPOSE: * Clear the map by hiding all the map tiles. */ void ghack_map_clear(GtkWidget *win, gpointer data) { int i; for (i = 0; i < ROWNO * COLNO; i++) { if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i])) { gnome_canvas_item_hide(GNOME_CANVAS_ITEM(ghack_map.map[i])); } if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i])) { gnome_canvas_item_hide(GNOME_CANVAS_ITEM(ghack_map.overlay[i])); } } gnome_canvas_update_now(GNOME_CANVAS(ghack_map.canvas)); } void ghack_map_display(GtkWidget *win, boolean block, gpointer data) { gtk_widget_show_all(GTK_WIDGET(win)); } void ghack_map_cliparound(GtkWidget *win, int x, int y, gpointer data) { int map_width, map_height; int to_x, to_y; int cur_x, cur_y; int width, height, half_width, half_height; x *= ghack_glyph_width() * ghack_map.zoom; y *= ghack_glyph_height() * ghack_map.zoom; map_width = COLNO * ghack_glyph_width() * ghack_map.zoom; map_height = ROWNO * ghack_glyph_height() * ghack_map.zoom; gdk_window_get_size(GTK_LAYOUT(ghack_map.canvas)->bin_window, &width, &height); gnome_canvas_get_scroll_offsets(ghack_map.canvas, &cur_x, &cur_y); half_width = width * 0.5; half_height = height * 0.5; if (((x - cur_x) < (width * 0.25)) || ((x - cur_x) > (width * 0.75))) { to_x = ((x - half_width) > 0) ? x - half_width : 0; to_x = ((x + half_width) > map_width) ? map_width - 2 * half_width : to_x; } else { to_x = cur_x; } if (((y - cur_y) < (height * 0.25)) || ((y - cur_y) > (height * 0.75))) { to_y = ((y - half_height) > 0) ? y - half_height : 0; to_y = ((y + half_height) > map_height) ? map_height - 2 * half_height : to_y; } else { to_y = cur_y; } if (to_x != cur_x || to_y != cur_y) gnome_canvas_scroll_to(ghack_map.canvas, to_x, to_y); // gnome_canvas_update_now ( ghack_map.canvas); } void ghack_reinit_map_window() { GnomeCanvasImage *bg; double width, height, x, y; int i; /* ghack_map_clear(NULL, NULL); */ width = COLNO * ghack_glyph_width(); height = ROWNO * ghack_glyph_height(); gnome_canvas_set_scroll_region(GNOME_CANVAS(ghack_map.canvas), 0, 0, width + 2 * ghack_glyph_width(), height + 2 * ghack_glyph_height()); /* remove everything currently in the canvas map */ gtk_object_destroy(GTK_OBJECT(myCanvasGroup)); /* Put some groups back */ myCanvasGroup = GNOME_CANVAS_GROUP(gnome_canvas_item_new( gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), gnome_canvas_group_get_type(), "x", 0.0, "y", 0.0, NULL)); /* Tile the map background with a pretty image */ if (background != NULL) { /* Tile the map background */ for (y = 0; y < height + background->rgb_height; y += background->rgb_height) { for (x = 0; x < width + background->rgb_width; x += background->rgb_width) { bg = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, "y", (double) y, "width", (double) background->rgb_width, "height", (double) background->rgb_height, "image", background, "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER, NULL)); gnome_canvas_item_lower_to_bottom(GNOME_CANVAS_ITEM(bg)); } } } /* ghack_map.map is an array of canvas images. Each cell of * the array will contain one tile. Here, we create the * space for the cells and then create the cells for easy * access later. */ for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { for (x = 0; x < width; x += ghack_glyph_width()) { ghack_map.map[i++] = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, "y", (double) y, "width", (double) ghack_glyph_width(), "height", (double) ghack_glyph_height(), "anchor", GTK_ANCHOR_NORTH_WEST, NULL)); } } if (petmark != NULL) { /* ghack_map.overlay is an array of canvas images used to * overlay tile images... */ for (i = 0, y = 0; y < height; y += ghack_glyph_height()) { for (x = 0; x < width; x += ghack_glyph_width()) { ghack_map.overlay[i] = GNOME_CANVAS_IMAGE(gnome_canvas_item_new( myCanvasGroup, gnome_canvas_image_get_type(), "x", (double) x, "y", (double) y, "width", (double) petmark->rgb_width, "height", (double) petmark->rgb_height, "image", petmark, "anchor", GTK_ANCHOR_NORTH_WEST, NULL)); gnome_canvas_item_lower_to_bottom( GNOME_CANVAS_ITEM(ghack_map.overlay[i++])); } } } ghack_map_cliparound(NULL, u.ux, u.uy, NULL); ghack_map_cursor_to(NULL, u.ux, u.uy, NULL); gnome_canvas_update_now(ghack_map.canvas); doredraw(); } nethack-3.6.0/win/gnome/gnmap.h0000664000076400007660000000077012536476415015333 0ustar paxedpaxed/* NetHack 3.6 gnmap.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMapWindow_h #define GnomeHackMapWindow_h #include #include #include "config.h" #include "global.h" GtkWidget *ghack_init_map_window(void); void ghack_reinit_map_window(void); #endif /* GnomeHackMapWindow_h */ nethack-3.6.0/win/gnome/gnmenu.c0000664000076400007660000006215112536476415015516 0ustar paxedpaxed/* NetHack 3.6 gnmenu.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #include "gnmenu.h" #include "gnmain.h" #include "gnbind.h" #include "func_tab.h" typedef enum { MenuUnknown = 0, MenuText, MenuMenu } MenuWinType; typedef struct { ANY_P identifier; gchar accelerator[BUFSZ]; int itemNumber; int selected; } menuItem; typedef struct { int curItem; int numRows; int charIdx; guint32 lastTime; } extMenu; static GdkColor color_blue = { 0, 0, 0, 0xffff }; static void ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data) { int i, numRows; menuItem *item; MenuWinType isMenu; isMenu = (MenuWinType) GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); if (isMenu == MenuMenu) { GtkWidget *clist; gint selection_mode; clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); g_assert(clist != NULL); numRows = GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(clist), "numRows")); selection_mode = GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(clist), "selection_mode")); for (i = 0; i <= numRows; ++i) { item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i); if (item == NULL) continue; if (!strcmp(item->accelerator, "")) continue; if ((!strcmp(item->accelerator, event->string)) || ((selection_mode == GTK_SELECTION_MULTIPLE) && (event->keyval == ','))) { if (item->selected) { gtk_clist_unselect_row(GTK_CLIST(clist), item->itemNumber, 0); item->selected = FALSE; } else { gtk_clist_select_row(GTK_CLIST(clist), item->itemNumber, 0); if (gtk_clist_row_is_visible(GTK_CLIST(clist), item->itemNumber) != GTK_VISIBILITY_FULL) gtk_clist_moveto(GTK_CLIST(clist), item->itemNumber, 0, 0.5, 0); item->selected = TRUE; } } } } } static void ghack_menu_row_selected(GtkCList *clist, int row, int col, GdkEvent *event) { /* FIXME: Do something */ } void ghack_menu_window_clear(GtkWidget *menuWin, gpointer data) { MenuWinType isMenu; int i, numRows; menuItem *item; isMenu = (MenuWinType) GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); if (isMenu == MenuMenu) { GtkWidget *clist; clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); g_assert(clist != NULL); /* destroy existing menu data, if any */ if (clist) { /* destroy all the row_data we stored in the clist */ numRows = GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(clist), "numRows")); for (i = 0; i < numRows; i++) { item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i); if (item != NULL) { g_free(item); gtk_clist_set_row_data(GTK_CLIST(clist), i, (gpointer) NULL); } } gtk_object_set_data(GTK_OBJECT(clist), "numItems", GINT_TO_POINTER(-1)); gtk_clist_clear(GTK_CLIST(clist)); } } else if (isMenu == MenuText) { GnomeLess *gless; gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless")); g_assert(gless != NULL); gtk_editable_delete_text(GTK_EDITABLE(gless->text), 0, 0); } } void ghack_menu_window_display(GtkWidget *menuWin, gboolean blocking, gpointer data) { // if(blocking) { gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE); gnome_dialog_set_close(GNOME_DIALOG(menuWin), TRUE); gnome_dialog_run_and_close(GNOME_DIALOG(menuWin)); //} // else { // gtk_widget_show(menuWin); //} } gint ghack_menu_hide(GtkWidget *menuWin, GdkEvent *event, gpointer data) { gtk_widget_hide(menuWin); return FALSE; /* FIXME: what is correct result here? */ } void ghack_menu_window_start_menu(GtkWidget *menuWin, gpointer data) { GtkWidget *frame1, *swin, *clist; MenuWinType isMenu; g_assert(menuWin != NULL); g_assert(data == NULL); /* destroy existing menu data, if any */ frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1"); if (frame1) gtk_widget_destroy(frame1); isMenu = MenuMenu; gtk_object_set_data(GTK_OBJECT(menuWin), "isMenu", GINT_TO_POINTER(isMenu)); gtk_widget_set_usize(GTK_WIDGET(menuWin), 500, 400); gtk_window_set_policy(GTK_WINDOW(menuWin), TRUE, TRUE, FALSE); frame1 = gtk_frame_new("Make your selection"); g_assert(frame1 != NULL); gtk_object_set_data(GTK_OBJECT(menuWin), "frame1", frame1); gtk_widget_show(GTK_WIDGET(frame1)); gtk_container_set_border_width(GTK_CONTAINER(frame1), 5); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(menuWin)->vbox), frame1, TRUE, TRUE, 0); swin = gtk_scrolled_window_new(NULL, NULL); g_assert(swin != NULL); gtk_object_set_data(GTK_OBJECT(menuWin), "swin", swin); gtk_widget_show(GTK_WIDGET(swin)); gtk_container_add(GTK_CONTAINER(frame1), swin); clist = gtk_clist_new(4); g_assert(clist != NULL); gtk_object_set_data(GTK_OBJECT(menuWin), "clist", clist); gtk_widget_show(GTK_WIDGET(clist)); gtk_container_add(GTK_CONTAINER(swin), clist); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL); gtk_object_set_data(GTK_OBJECT(clist), "numItems", GINT_TO_POINTER(-1)); } int ghack_menu_window_select_menu(GtkWidget *menuWin, MENU_ITEM_P **_selected, gint how) { gint rc; guint num_sel, i, idx; GtkWidget *clist; GList *cur; MENU_ITEM_P *selected = NULL; menuItem *item; g_assert(_selected != NULL); *_selected = NULL; if (how == PICK_NONE) { gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE); rc = gnome_dialog_run_and_close(GNOME_DIALOG(menuWin)); return (rc == 1 ? -1 : 0); } clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); g_assert(clist != NULL); gtk_object_set_data(GTK_OBJECT(clist), "selection_mode", GINT_TO_POINTER((how == PICK_ANY) ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE)); gtk_clist_set_selection_mode(GTK_CLIST(clist), (how == PICK_ANY) ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); gnome_dialog_close_hides(GNOME_DIALOG(menuWin), TRUE); rc = gnome_dialog_run_and_close(GNOME_DIALOG(menuWin)); if ((rc == 1) || (GTK_CLIST(clist)->selection == NULL)) { return (-1); } num_sel = g_list_length(GTK_CLIST(clist)->selection); if (num_sel < 1) { return (-1); } /* fill in array with selections from clist */ selected = g_new0(MENU_ITEM_P, num_sel); g_assert(selected != NULL); cur = GTK_CLIST(clist)->selection; i = 0; while (cur) { g_assert(i < num_sel); /* grab row number from clist selection list */ idx = GPOINTER_TO_INT(cur->data); item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), idx); selected[i].item = item->identifier; selected[i].count = -1; cur = g_list_next(cur); i++; } *_selected = selected; return ((int) num_sel); } void ghack_menu_window_add_menu(GtkWidget *menuWin, gpointer menu_item, gpointer data) { GHackMenuItem *item; GtkWidget *clist; gchar buf[BUFSZ] = "", accelBuf[BUFSZ] = ""; gchar *pbuf; char *text[4] = { buf, NULL, NULL, NULL }; gint nCurrentRow = -1, numItems = -1; MenuWinType isMenu; GtkStyle *bigStyle = NULL; gboolean item_selectable; GdkImlibImage *image; static gboolean special; g_assert(menu_item != NULL); item = (GHackMenuItem *) menu_item; item_selectable = (item->identifier->a_int == 0) ? FALSE : TRUE; isMenu = (MenuWinType) GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); g_assert(clist != NULL); /* This is a special kludge to make the special hidden help menu item work * as designed */ if (special == TRUE) { special = FALSE; item_selectable = TRUE; } if (!strcmp(item->str, "The NetHack license.")) { special = TRUE; } if (item->str) { /* First, make a new blank entry in the clist */ nCurrentRow = gtk_clist_append(GTK_CLIST(clist), text); if (item->glyph != NO_GLYPH) { image = ghack_image_from_glyph(item->glyph, FALSE); if (image == NULL || image->pixmap == NULL) { g_warning("Bummer -- having to force rendering for glyph %d!", item->glyph); /* wierd -- pixmap is NULL so retry rendering it */ image = ghack_image_from_glyph(item->glyph, TRUE); } if (image == NULL || image->pixmap == NULL) { g_error("Aiiee! glyph is still NULL for item\n\"%s\"", item->str); } else gtk_clist_set_pixmap(GTK_CLIST(clist), nCurrentRow, 1, gdk_imlib_move_image(image), gdk_imlib_move_mask(image)); } if (item->accelerator) { /* FIXME: handle accelerator, */ g_snprintf(accelBuf, sizeof(accelBuf), "%c ", item->accelerator); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); g_snprintf(buf, sizeof(buf), "%s", item->str); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf); } else { if (item->group_accel) { /* FIXME: maybe some day I should try to handle * group accelerators... */ } if (((item->attr == 0) && (item->identifier->a_int != 0)) || (special == TRUE)) { numItems = GPOINTER_TO_INT(gtk_object_get_data( GTK_OBJECT(clist), "numItems")) + 1; /* Ok, now invent a unique accelerator */ if (('a' + numItems) <= 'z') { g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'a' + numItems); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); } else if (('A' + numItems - 26) <= 'Z') { g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'A' + numItems - 26); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); } else { accelBuf[0] = buf[0] = 0; } g_snprintf(buf, sizeof(buf), "%s", item->str); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf); gtk_object_set_data(GTK_OBJECT(clist), "numItems", GINT_TO_POINTER(numItems)); /* This junk is to specially handle the options menu */ pbuf = strstr(buf, " ["); if (pbuf == NULL) { pbuf = strstr(buf, "\t["); } if (pbuf != NULL) { *pbuf = 0; pbuf++; gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 3, pbuf); } } /* FIXME: handle more than 26*2 accelerators (but how? * since I only have so many keys to work with???) else { foo(); } */ else { g_snprintf(buf, sizeof(buf), "%s", item->str); pbuf = strstr(buf, " ["); if (pbuf == NULL) { pbuf = strstr(buf, "\t["); } if (pbuf != NULL) { *pbuf = 0; pbuf++; gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 3, pbuf); } gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 2, buf); } } if (item->attr) { switch (item->attr) { case ATR_ULINE: case ATR_BOLD: case ATR_BLINK: case ATR_INVERSE: bigStyle = gtk_style_copy(GTK_WIDGET(clist)->style); g_assert(bigStyle != NULL); gdk_font_unref(bigStyle->font); bigStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); bigStyle->fg[GTK_STATE_NORMAL] = color_blue; gtk_clist_set_cell_style(GTK_CLIST(clist), nCurrentRow, 2, bigStyle); item_selectable = FALSE; } } g_assert(nCurrentRow >= 0); gtk_clist_set_selectable(GTK_CLIST(clist), nCurrentRow, item_selectable); if (item_selectable == TRUE && item->presel == TRUE) { /* pre-select this item */ gtk_clist_select_row(GTK_CLIST(clist), nCurrentRow, 0); } gtk_object_set_data(GTK_OBJECT(clist), "numRows", GINT_TO_POINTER(nCurrentRow)); /* We have to allocate memory here, since the menu_item currently * lives on the stack, and will otherwise go to the great bit bucket * in the sky as soon as this function exits, which would leave a * pointer to crap in the row_data. Use g_memdup to make a private, * persistant copy of the item identifier. * * We need to arrange to blow away this memory somewhere (like * ghack_menu_destroy and ghack_menu_window_clear for example). * * -Erik */ { menuItem newItem; menuItem *pNewItem; newItem.identifier = *item->identifier; newItem.itemNumber = nCurrentRow; newItem.selected = FALSE; newItem.accelerator[0] = 0; /* only copy 1 char, since accel keys are by definition 1 char */ if (accelBuf[0]) { strncpy(newItem.accelerator, accelBuf, 1); } newItem.accelerator[1] = 0; pNewItem = g_memdup(&newItem, sizeof(menuItem)); gtk_clist_set_row_data(GTK_CLIST(clist), nCurrentRow, (gpointer) pNewItem); } } /* Now adjust the column widths to match the contents */ gtk_clist_columns_autosize(GTK_CLIST(clist)); } void ghack_menu_window_end_menu(GtkWidget *menuWin, gpointer data) { const char *p = (const char *) data; if ((p) && (*p)) { GtkWidget *frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1"); g_assert(frame1 != NULL); gtk_frame_set_label(GTK_FRAME(frame1), p); } } void ghack_menu_window_put_string(GtkWidget *menuWin, int attr, const char *text, gpointer data) { GnomeLess *gless; MenuWinType isMenu; if (text == NULL) return; isMenu = (MenuWinType) GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); if (isMenu == MenuText) { gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless")); g_assert(gless != NULL); g_assert(gless->text != NULL); g_assert(GTK_IS_TEXT(gless->text)); /* Don't bother with attributes yet */ gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, text, -1); gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1); } else if (isMenu == MenuUnknown) { isMenu = MenuText; gtk_object_set_data(GTK_OBJECT(menuWin), "isMenu", GINT_TO_POINTER(isMenu)); gtk_widget_set_usize(GTK_WIDGET(menuWin), 500, 400); gtk_window_set_policy(GTK_WINDOW(menuWin), TRUE, TRUE, FALSE); gless = GNOME_LESS(gnome_less_new()); g_assert(gless != NULL); gtk_object_set_data(GTK_OBJECT(menuWin), "gless", gless); gtk_widget_show(GTK_WIDGET(gless)); gnome_less_show_string(gless, text); gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(menuWin)->vbox), GTK_WIDGET(gless), TRUE, TRUE, 0); } } void ghack_menu_destroy(GtkWidget *menuWin, gpointer data) { MenuWinType isMenu; isMenu = (MenuWinType) GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(menuWin), "isMenu")); if (isMenu == MenuText) { GnomeLess *gless; gless = GNOME_LESS(gtk_object_get_data(GTK_OBJECT(menuWin), "gless")); g_assert(gless != NULL); g_assert(gless->text != NULL); g_assert(GTK_IS_TEXT(gless->text)); gtk_widget_destroy(GTK_WIDGET(gless)); } else if (isMenu == MenuMenu) { GtkWidget *frame1, *swin, *clist; /* destroy existing menu data, if any */ clist = gtk_object_get_data(GTK_OBJECT(menuWin), "clist"); if (clist) { /* destroy all the row_data we stored in the clist */ int i, numRows; menuItem *item; numRows = GPOINTER_TO_INT( gtk_object_get_data(GTK_OBJECT(clist), "numRows")); for (i = 0; i < numRows; i++) { item = (menuItem *) gtk_clist_get_row_data(GTK_CLIST(clist), i); if (item != NULL) { g_free(item); gtk_clist_set_row_data(GTK_CLIST(clist), i, (gpointer) NULL); } } gtk_object_set_data(GTK_OBJECT(clist), "numItems", GINT_TO_POINTER(-1)); gtk_widget_destroy(clist); } swin = gtk_object_get_data(GTK_OBJECT(menuWin), "swin"); if (swin) { gtk_widget_destroy(swin); } frame1 = gtk_object_get_data(GTK_OBJECT(menuWin), "frame1"); if (frame1) { gtk_widget_destroy(frame1); } } gnome_delete_nhwindow_by_reference(menuWin); } GtkWidget * ghack_init_menu_window(void) { GtkWidget *menuWin = NULL; GtkWidget *parent = ghack_get_main_window(); menuWin = gnome_dialog_new("GnomeHack", GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_set_default(GNOME_DIALOG(menuWin), 0); gtk_signal_connect(GTK_OBJECT(menuWin), "destroy", GTK_SIGNAL_FUNC(ghack_menu_destroy), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "delete_event", GTK_SIGNAL_FUNC(ghack_menu_hide), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_clear", GTK_SIGNAL_FUNC(ghack_menu_window_clear), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_display", GTK_SIGNAL_FUNC(ghack_menu_window_display), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_start_menu", GTK_SIGNAL_FUNC(ghack_menu_window_start_menu), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_add_menu", GTK_SIGNAL_FUNC(ghack_menu_window_add_menu), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_end_menu", GTK_SIGNAL_FUNC(ghack_menu_window_end_menu), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_select_menu", GTK_SIGNAL_FUNC(ghack_menu_window_select_menu), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_menu_window_put_string), NULL); gtk_signal_connect(GTK_OBJECT(menuWin), "key_press_event", GTK_SIGNAL_FUNC(ghack_menu_window_key), NULL); /* Center the dialog over parent */ g_assert(parent != NULL); g_assert(menuWin != NULL); g_assert(GTK_IS_WINDOW(parent)); g_assert(GNOME_IS_DIALOG(menuWin)); gnome_dialog_set_parent(GNOME_DIALOG(menuWin), GTK_WINDOW(parent)); return menuWin; } static void ghack_ext_key_hit(GtkWidget *menuWin, GdkEventKey *event, gpointer data) { GtkWidget *clist; extMenu *info = (extMenu *) data; int i; char c = event->string[0]; clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); g_assert(clist != NULL); /* if too long between keystrokes, reset to initial state */ if (event->time - info->lastTime > 500) goto init_state; /* see if current item continue to match */ if (info->charIdx > 0) { if (extcmdlist[info->curItem].ef_txt[info->charIdx] == c) { ++info->charIdx; goto found; } } /* see if the prefix matches a later command in the list */ if (info->curItem >= 0) { for (i = info->curItem + 1; i < info->numRows; ++i) { if (!strncmp(extcmdlist[info->curItem].ef_txt, extcmdlist[i].ef_txt, info->charIdx)) { if (extcmdlist[i].ef_txt[info->charIdx] == c) { ++info->charIdx; info->curItem = i; goto found; } } } } init_state: /* reset to initial state, look for matching 1st character */ for (i = 0; i < info->numRows; ++i) { if (extcmdlist[i].ef_txt[0] == c) { info->charIdx = 1; info->curItem = i; goto found; } } /* no match: leave prior, if any selection in place */ return; found: info->lastTime = event->time; gtk_clist_select_row(GTK_CLIST(clist), info->curItem, 0); if (gtk_clist_row_is_visible(GTK_CLIST(clist), info->curItem) != GTK_VISIBILITY_FULL) gtk_clist_moveto(GTK_CLIST(clist), info->curItem, 0, 0.5, 0); } int ghack_menu_ext_cmd(void) { int n; GtkWidget *dialog; GtkWidget *swin; GtkWidget *frame1; GtkWidget *clist; extMenu info; dialog = gnome_dialog_new("Extended Commands", GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", GTK_SIGNAL_FUNC(ghack_ext_key_hit), &info); frame1 = gtk_frame_new("Make your selection"); gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); gtk_widget_show(frame1); gtk_container_border_width(GTK_CONTAINER(frame1), 3); swin = gtk_scrolled_window_new(NULL, NULL); clist = gtk_clist_new(2); gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist); gtk_widget_set_usize(clist, 500, 400); gtk_container_add(GTK_CONTAINER(swin), clist); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL); gtk_container_add(GTK_CONTAINER(frame1), swin); gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); /* Add the extended commands into the list here... */ for (n = 0; extcmdlist[n].ef_txt; ++n) { const char *text[3] = { extcmdlist[n].ef_txt, extcmdlist[n].ef_desc, NULL }; gtk_clist_insert(GTK_CLIST(clist), n, (char **) text); } /* fill in starting info fields */ info.curItem = -1; info.numRows = n; info.charIdx = 0; info.lastTime = 0; gtk_clist_columns_autosize(GTK_CLIST(clist)); gtk_widget_show_all(swin); /* Center the dialog over over parent */ gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(ghack_get_main_window())); /* Run the dialog -- returning whichever button was pressed */ n = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); /* Quit on button 2 or error */ return (n != 0) ? -1 : info.curItem; } nethack-3.6.0/win/gnome/gnmenu.h0000664000076400007660000000152212536476415015516 0ustar paxedpaxed/* NetHack 3.6 gnmenu.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMenuWindow_h #define GnomeHackMenuWindow_h #include #include "config.h" #include "global.h" #include "gnomeprv.h" GtkWidget *ghack_init_menu_window(void); struct _GHackMenuItem { int glyph; const ANY_P *identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; const char *str; BOOLEAN_P presel; }; typedef struct _GHackMenuItem GHackMenuItem; int ghack_menu_window_select_menu(GtkWidget *menuWin, MENU_ITEM_P **_selected, gint how); int ghack_menu_ext_cmd(void); #endif /* GnomeHackMenuWindow_h */ nethack-3.6.0/win/gnome/gnmesg.c0000664000076400007660000000561212536476415015504 0ustar paxedpaxed/* NetHack 3.6 gnmesg.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnmesg.h" #include "gnsignal.h" /* Pick an arbitrary number of chars such as 80 col X 40 rows text = 3200 * chars */ #define nCharsBeforeDeletingStuff 3200 /* Message Window widgets */ GtkWidget *MW_table; GtkWidget *MW_text; GtkWidget *MW_scrollbar; void ghack_message_window_clear(GtkWidget *widget, gpointer data) { /* Seems nethack calls this after every move -- we don't want * to really clear the window at all though. Ignore the request */ gint len; len = gtk_text_get_length(GTK_TEXT(MW_text)); if (len < nCharsBeforeDeletingStuff) return; gtk_text_freeze(GTK_TEXT(MW_text)); gtk_text_set_point(GTK_TEXT(MW_text), 0); gtk_text_forward_delete(GTK_TEXT(MW_text), len - ((guint)(nCharsBeforeDeletingStuff * 0.5))); gtk_text_set_point(GTK_TEXT(MW_text), (guint)(nCharsBeforeDeletingStuff * 0.5)); gtk_text_thaw(GTK_TEXT(MW_text)); } void ghack_message_window_destroy(GtkWidget *win, gpointer data) { } void ghack_message_window_display(GtkWidget *widget, boolean block, gpointer data) { } void ghack_message_window_put_string(GtkWidget *widget, int attr, const char *text, gpointer data) { if (text == NULL) return; /* Don't bother with attributes yet */ gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, text, -1); gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, "\n", -1); } void ghack_message_window_use_RIP(int how) { } void ghack_message_window_scroll(int dx, int dy) { } GtkWidget * ghack_init_message_window(void) { MW_table = gtk_table_new(2, 1, FALSE); gtk_table_set_row_spacing(GTK_TABLE(MW_table), 0, 2); MW_text = gtk_text_new(NULL, NULL); gtk_text_set_editable(GTK_TEXT(MW_text), FALSE); gtk_text_set_word_wrap(GTK_TEXT(MW_text), TRUE); gtk_table_attach(GTK_TABLE(MW_table), MW_text, 0, 1, 0, 1, (GTK_EXPAND | GTK_FILL), (GTK_EXPAND | GTK_FILL), 0, 0); MW_scrollbar = gtk_vscrollbar_new(GTK_TEXT(MW_text)->vadj); gtk_table_attach(GTK_TABLE(MW_table), MW_scrollbar, 1, 2, 0, 1, GTK_FILL, (GTK_EXPAND | GTK_FILL), 0, 0); gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_message_window_put_string), NULL); gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_clear", GTK_SIGNAL_FUNC(ghack_message_window_clear), NULL); gtk_signal_connect(GTK_OBJECT(MW_table), "gnome_delay_output", GTK_SIGNAL_FUNC(ghack_delay), NULL); gtk_widget_show_all(MW_table); return GTK_WIDGET(MW_table); } nethack-3.6.0/win/gnome/gnmesg.h0000664000076400007660000000171212536476415015506 0ustar paxedpaxed/* NetHack 3.6 gnmesg.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMessageWindow_h #define GnomeHackMessageWindow_h #include #include "config.h" GtkWidget *ghack_init_message_window(/* GnomeHackKeyBuffer g_keybuffer, GnomeHackClickBuffer g_clickbuffer */); void ghack_message_window_clear(GtkWidget *widget, gpointer data); void ghack_message_window_destroy(); void ghack_message_window_display(GtkWidget *widget, boolean block, gpointer data); void ghack_message_window_put_string(GtkWidget *widget, int attr, const char *text, gpointer data); void ghack_message_window_use_RIP(int how); void ghack_message_window_scroll(int dx, int dy); #endif /* GnomeHackMessageWindow_h */ nethack-3.6.0/win/gnome/gnomeprv.h0000664000076400007660000000070212536476415016061 0ustar paxedpaxed/* NetHack 3.6 gnomeprv.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHack_h #define GnomeHack_h /* These are the base nethack include files */ #include "hack.h" #include "dlb.h" #include "patchlevel.h" #include "winGnome.h" #endif /* GnomeHack_h */ nethack-3.6.0/win/gnome/gnopts.c0000664000076400007660000000727712536476415015547 0ustar paxedpaxed/* NetHack 3.6 gnopts.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnopts.h" #include "gnglyph.h" #include "gnmain.h" #include "gnmap.h" #include #include #include "hack.h" static gint tileset; static GtkWidget *clist; const char *tilesets[] = { "Traditional (16x16)", "Big (32x32)", 0 }; static void opt_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data) { int i; for (i = 0; tilesets[i] != 0; ++i) { if (tilesets[i][0] == toupper(event->keyval)) { tileset = i; gtk_clist_select_row(GTK_CLIST(clist), i, 0); } } } static void opt_sel_row_selected(GtkCList *cList, int row, int col, GdkEvent *event) { tileset = row; } void ghack_settings_dialog() { int i; static GtkWidget *dialog; static GtkWidget *swin; static GtkWidget *frame1; dialog = gnome_dialog_new(_("GnomeHack Settings"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", GTK_SIGNAL_FUNC(opt_sel_key_hit), tilesets); frame1 = gtk_frame_new(_("Choose one of the following tilesets:")); gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); gtk_widget_show(frame1); gtk_container_border_width(GTK_CONTAINER(frame1), 3); swin = gtk_scrolled_window_new(NULL, NULL); clist = gtk_clist_new(2); gtk_clist_column_titles_hide(GTK_CLIST(clist)); gtk_widget_set_usize(GTK_WIDGET(clist), 100, 180); gtk_container_add(GTK_CONTAINER(swin), clist); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(opt_sel_row_selected), NULL); gtk_container_add(GTK_CONTAINER(frame1), swin); gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); /* Add the tilesets into the list here... */ for (i = 0; tilesets[i]; i++) { gchar accelBuf[BUFSZ]; const char *text[3] = { accelBuf, tilesets[i], NULL }; sprintf(accelBuf, "%c ", tolower(tilesets[i][0])); gtk_clist_insert(GTK_CLIST(clist), i, (char **) text); } gtk_clist_columns_autosize(GTK_CLIST(clist)); gtk_widget_show_all(swin); /* Center the dialog over over parent */ gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(ghack_get_main_window())); /* Run the dialog -- returning whichever button was pressed */ i = gnome_dialog_run(GNOME_DIALOG(dialog)); gnome_dialog_close(GNOME_DIALOG(dialog)); /* They hit Quit or error */ if (i != 0) { return; } switch (tileset) { case 0: /* They selected traditional */ ghack_free_glyphs(); if (ghack_init_glyphs(HACKDIR "/x11tiles")) g_error("ERROR: Could not initialize glyphs.\n"); ghack_reinit_map_window(); break; case 1: ghack_free_glyphs(); if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm")) g_error("ERROR: Could not initialize glyphs.\n"); ghack_reinit_map_window(); /* They selected big */ break; default: /* This shouldn't happen */ g_warning("This shouldn't happen\n"); } } nethack-3.6.0/win/gnome/gnopts.h0000664000076400007660000000057112536476415015542 0ustar paxedpaxed/* NetHack 3.6 gnopts.h $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackSettings_h #define GnomeHackSettings_h void ghack_settings_dialog(void); #endif /* GnomeHackSettings.h */ nethack-3.6.0/win/gnome/gnplayer.c0000664000076400007660000000653012536476415016045 0ustar paxedpaxed/* NetHack 3.6 gnplayer.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include "gnplayer.h" #include "gnmain.h" #include "hack.h" static gint role_number; static GtkWidget *clist; static void player_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data) { const char **roles = data; int i; for (i = 0; roles[i] != 0; ++i) { if (tolower(roles[i][0]) == tolower(event->keyval)) { role_number = i; gtk_clist_select_row(GTK_CLIST(clist), i, 0); if (gtk_clist_row_is_visible(GTK_CLIST(clist), i) != GTK_VISIBILITY_FULL) gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0.5, 0); } } } static void player_sel_row_selected(GtkCList *clist, int row, int col, GdkEvent *event) { role_number = row; } int ghack_player_sel_dialog(const char **choices, const gchar *title, const gchar *prompt) { int i; static GtkWidget *dialog; static GtkWidget *swin; static GtkWidget *frame1; dialog = gnome_dialog_new(title, GNOME_STOCK_BUTTON_OK, _("Random"), GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", GTK_SIGNAL_FUNC(player_sel_key_hit), choices); frame1 = gtk_frame_new(prompt); gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); gtk_widget_show(frame1); gtk_container_border_width(GTK_CONTAINER(frame1), 3); swin = gtk_scrolled_window_new(NULL, NULL); clist = gtk_clist_new(2); gtk_clist_column_titles_hide(GTK_CLIST(clist)); gtk_widget_set_usize(GTK_WIDGET(clist), 100, 180); gtk_container_add(GTK_CONTAINER(swin), clist); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(player_sel_row_selected), NULL); gtk_container_add(GTK_CONTAINER(frame1), swin); gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); /* Add the roles into the list here... */ for (i = 0; choices[i]; i++) { gchar accelBuf[BUFSZ]; const char *text[3] = { accelBuf, choices[i], NULL }; sprintf(accelBuf, "%c ", tolower(choices[i][0])); gtk_clist_insert(GTK_CLIST(clist), i, (char **) text); } gtk_clist_columns_autosize(GTK_CLIST(clist)); gtk_widget_show_all(swin); /* Center the dialog over over parent */ gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(ghack_get_main_window())); /* Run the dialog -- returning whichever button was pressed */ i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); /* Quit on button 2 or error */ if (i < 0 || i > 1) { return (ROLE_NONE); } /* Random is button 1*/ if (i == 1) { return (ROLE_RANDOM); } return (role_number); } nethack-3.6.0/win/gnome/gnplayer.h0000664000076400007660000000067012536476415016051 0ustar paxedpaxed/* NetHack 3.6 gnplayer.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackPlayerSelDialog_h #define GnomeHackPlayerSelDialog_h int ghack_player_sel_dialog(const char **, const gchar *, const gchar *); #endif /* GnomeHackPlayerSelDialog_h */ nethack-3.6.0/win/gnome/gnsignal.c0000664000076400007660000002620112536476415016023 0ustar paxedpaxed/* NetHack 3.6 gnsignal.c $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #include "gnsignal.h" #include "gnmain.h" #include GList *g_keyBuffer; GList *g_clickBuffer; int g_numKeys = 0; int g_numClicks = 0; int g_askingQuestion = 0; static int s_done = FALSE; /* * ghack_init_signals * * Create some signals and attach them to the GtkWidget class. * These are the signals: * * ghack_curs : NONE:INT,INT * INT 1 = x * INT 2 = y * * ghack_putstr : NONE:INT,POINTER * INT = attribute * POINTER = char* string to print * * ghack_print_glyph : NONE:INT,INT,POINTER * INT 1 = x * INT 2 = y * INT 3 = GtkPixmap* to rendered glyph * * ghack_clear : NONE:NONE * * ghack_display : NONE:BOOL * BOOL = blocking flag * * ghack_start_menu : NONE:NONE * * ghack_add_menu : NONE:POINTER * POINTER = GHackMenuItem* * * ghack_end_menu : NONE:POINTER * POINTER = char* to closing string * * ghack_select_menu : NONE:POINTER,INT,POINTER * POINTER = int pointer-- filled with number * of selected items on return * INT = number of items selected * POINTER = structure to fill * * ghack_cliparound : NONE:INT,INT * INT 1 = x * INT 2 = y */ void ghack_init_signals(void) { ghack_signals[GHSIG_CURS] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_curs", GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); ghack_signals[GHSIG_PUTSTR] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_putstr", GTK_RUN_FIRST, gtk_marshal_NONE__INT_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_POINTER); ghack_signals[GHSIG_PRINT_GLYPH] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_print_glyph", GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT_POINTER, GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER); ghack_signals[GHSIG_CLEAR] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_clear", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); ghack_signals[GHSIG_DISPLAY] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_display", GTK_RUN_FIRST, gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1, GTK_TYPE_BOOL); ghack_signals[GHSIG_START_MENU] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_start_menu", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); ghack_signals[GHSIG_ADD_MENU] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_add_menu", GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); ghack_signals[GHSIG_END_MENU] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_end_menu", GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); ghack_signals[GHSIG_SELECT_MENU] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_select_menu", GTK_RUN_FIRST, gtk_marshal_NONE__POINTER_INT_POINTER, GTK_TYPE_NONE, 3, GTK_TYPE_POINTER, GTK_TYPE_INT, GTK_TYPE_POINTER); ghack_signals[GHSIG_CLIPAROUND] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_cliparound", GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); ghack_signals[GHSIG_FADE_HIGHLIGHT] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "ghack_fade_highlight", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); ghack_signals[GHSIG_DELAY] = gtk_object_class_user_signal_new( gtk_type_class(gtk_widget_get_type()), "gnome_delay_output", GTK_RUN_FIRST, gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT); } /* For want of a better place, I'm putting the delay output stuff here * -Erik */ static gint timeout_callback(gpointer data) { s_done = TRUE; return FALSE; } void ghack_delay(GtkWidget *win, int numMillisecs, gpointer data) { s_done = FALSE; gtk_timeout_add((unsigned int) numMillisecs, timeout_callback, NULL); while (s_done == FALSE) gtk_main_iteration(); } void ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) { GHClick *click; double x1, y1; if (event->type != GDK_BUTTON_PRESS) return; gnome_canvas_window_to_world(GNOME_CANVAS(widget), event->x, event->y, &x1, &y1); /* g_message("I got a click at %f,%f with button %d \n", x1, y1, event->button); */ /* We allocate storage here, so we need to remember if (g_numClicks>0) * to blow this away when closing the app using something like * while (g_clickBuffer) * { * g_free((GHClick)g_clickBuffer->data); * g_clickBuffer = g_clickBuffer->next; * } * g_list_free( g_clickBuffer ); * */ click = g_new(GHClick, 1); click->x = (int) x1 / ghack_glyph_width(); click->y = (int) y1 / ghack_glyph_height(); click->mod = (event->button == 1) ? CLICK_1 : CLICK_2; g_clickBuffer = g_list_prepend(g_clickBuffer, click); /* Could use g_list_length(), but it is stupid and just * traverses the list while counting, so we'll just do * the counting ourselves in advance. */ g_numClicks++; } #ifndef M #ifndef NHSTDC #define M(c) (0x80 | (c)) #else #define M(c) ((c) -128) #endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif void ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { static int was_pound = 0; int key = 0; int ctl = GDK_CONTROL_MASK; int alt = GDK_MOD1_MASK; /* Turn this on to debug key events */ #if 0 g_message("I got a \"%s\" key (%d) %s%s", gdk_keyval_name (event->keyval), event->keyval, (event->state&ctl)? "+CONTROL":"", (event->state&alt)? "+ALT":""); #endif switch (event->keyval) { /* special keys to do stuff with */ /* Set up the direction keys */ /* First handle the arrow keys -- these always mean move */ case GDK_Right: case GDK_rightarrow: key = Cmd.move_E; break; case GDK_Left: case GDK_leftarrow: key = Cmd.move_W; break; case GDK_Up: case GDK_uparrow: key = Cmd.move_N; break; case GDK_Down: case GDK_downarrow: key = Cmd.move_S; break; case GDK_Home: key = Cmd.move_NW; break; case GDK_End: key = Cmd.move_SW; break; case GDK_Page_Down: key = Cmd.move_SE; break; case GDK_Page_Up: key = Cmd.move_NE; break; case ' ': key = '.'; break; /* Now, handle the numberpad (move or numbers) */ case GDK_KP_Right: case GDK_KP_6: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_6; else key = '6'; break; case GDK_KP_Left: case GDK_KP_4: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_4; else key = '4'; break; case GDK_KP_Up: case GDK_KP_8: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_8; else key = '8'; break; case GDK_KP_Down: case GDK_KP_2: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_2; else key = '2'; break; /* Move Top-Left */ case GDK_KP_Home: case GDK_KP_7: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_7; else key = '7'; break; case GDK_KP_Page_Up: case GDK_KP_9: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_9; else key = '9'; break; case GDK_KP_End: case GDK_KP_1: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_1; else key = '1'; break; case GDK_KP_Page_Down: case GDK_KP_3: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_3; else key = '3'; break; case GDK_KP_5: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_5; else key = '5'; break; case GDK_KP_Delete: case GDK_KP_Decimal: key = '.'; break; /* can't just ignore "#", it's a core feature */ case GDK_numbersign: key = '#'; break; /* We will probably want to do something with these later... */ case GDK_KP_Begin: case GDK_KP_F1: case GDK_F1: case GDK_KP_F2: case GDK_F2: case GDK_KP_F3: case GDK_F3: case GDK_KP_F4: case GDK_F4: case GDK_F5: case GDK_F6: case GDK_F7: case GDK_F8: case GDK_F9: case GDK_F10: case GDK_F11: case GDK_F12: break; /* various keys to ignore */ case GDK_KP_Insert: case GDK_Insert: case GDK_Delete: case GDK_Print: case GDK_BackSpace: case GDK_Pause: case GDK_Scroll_Lock: case GDK_Shift_Lock: case GDK_Num_Lock: case GDK_Caps_Lock: case GDK_Control_L: case GDK_Control_R: case GDK_Shift_L: case GDK_Shift_R: case GDK_Alt_L: case GDK_Alt_R: case GDK_Meta_L: case GDK_Meta_R: case GDK_Mode_switch: case GDK_Multi_key: return; default: key = event->keyval; break; } if ((event->state & alt) || was_pound) { key = M(event->keyval); } else if (event->state & ctl) { key = C(event->keyval); } if (was_pound) { was_pound = 0; } /* Ok, here is where we do clever stuff to overide the default * game behavior */ if (g_askingQuestion == 0) { if (key == 'S' || key == M('S') || key == C('S')) { ghack_save_game_cb(NULL, NULL); return; } } g_keyBuffer = g_list_prepend(g_keyBuffer, GINT_TO_POINTER(key)); g_numKeys++; } nethack-3.6.0/win/gnome/gnsignal.h0000664000076400007660000000241312536476415016027 0ustar paxedpaxed/* NetHack 3.6 gnsignal.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackSignals_h #define GnomeHackSignals_h #include #include #include "gnomeprv.h" #include "gnglyph.h" /* The list of custom signals */ enum { GHSIG_CURS, GHSIG_PUTSTR, GHSIG_PRINT_GLYPH, GHSIG_CLEAR, GHSIG_DISPLAY, GHSIG_START_MENU, GHSIG_ADD_MENU, GHSIG_END_MENU, GHSIG_SELECT_MENU, GHSIG_CLIPAROUND, GHSIG_FADE_HIGHLIGHT, GHSIG_DELAY, GHSIG_LAST_SIG }; guint ghack_signals[GHSIG_LAST_SIG]; extern void ghack_init_signals(void); void ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data); void ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data); typedef struct { int x, y, mod; } GHClick; extern GList *g_keyBuffer; extern GList *g_clickBuffer; extern int g_numKeys; extern int g_numClicks; extern int g_askingQuestion; void ghack_delay(GtkWidget *win, int numMillisecs, gpointer data); #endif /* GnomeHackSignals_h */ nethack-3.6.0/win/gnome/gnstatus.c0000664000076400007660000010311712536476415016073 0ustar paxedpaxed/* NetHack 3.6 gnstatus.c $NHDT-Date: 1432512806 2015/05/25 00:13:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnstatus.h" #include "gnsignal.h" #include "gn_xpms.h" #include "gnomeprv.h" extern const char *hu_stat[]; /* from eat.c */ extern const char *enc_stat[]; /* from botl.c */ void ghack_status_window_update_stats(); void ghack_status_window_clear(GtkWidget *win, gpointer data); void ghack_status_window_destroy(GtkWidget *win, gpointer data); void ghack_status_window_display(GtkWidget *win, boolean block, gpointer data); void ghack_status_window_cursor_to(GtkWidget *win, int x, int y, gpointer data); void ghack_status_window_put_string(GtkWidget *win, int attr, const char *text, gpointer data); static void ghack_fade_highlighting(); static void ghack_highlight_widget(GtkWidget *widget, GtkStyle *oldStyle, GtkStyle *newStyle); /* some junk to handle when to fade the highlighting */ #define NUM_TURNS_HIGHLIGHTED 3 static GList *s_HighLightList; typedef struct { GtkWidget *widget; GtkStyle *oldStyle; int nTurnsLeft; } Highlight; /* Ok, now for a LONG list of widgets... */ static GtkWidget *statTable = NULL; static GtkWidget *titleLabel = NULL; static GtkWidget *dgnLevelLabel = NULL; static GtkWidget *strPix = NULL; static GtkWidget *strLabel = NULL; static GtkWidget *dexPix = NULL; static GtkWidget *dexLabel = NULL; static GtkWidget *intPix = NULL; static GtkWidget *intLabel = NULL; static GtkWidget *wisPix = NULL; static GtkWidget *wisLabel = NULL; static GtkWidget *conPix = NULL; static GtkWidget *conLabel = NULL; static GtkWidget *chaPix = NULL; static GtkWidget *chaLabel = NULL; static GtkWidget *goldLabel = NULL; static GtkWidget *hpLabel = NULL; static GtkWidget *powLabel = NULL; static GtkWidget *acLabel = NULL; static GtkWidget *levlLabel = NULL; static GtkWidget *expLabel = NULL; static GtkWidget *timeLabel = NULL; static GtkWidget *scoreLabel = NULL; static GtkWidget *alignPix = NULL; static GtkWidget *alignLabel = NULL; static GtkWidget *hungerPix = NULL; static GtkWidget *hungerLabel = NULL; static GtkWidget *sickPix = NULL; static GtkWidget *sickLabel = NULL; static GtkWidget *blindPix = NULL; static GtkWidget *blindLabel = NULL; static GtkWidget *stunPix = NULL; static GtkWidget *stunLabel = NULL; static GtkWidget *halluPix = NULL; static GtkWidget *halluLabel = NULL; static GtkWidget *confuPix = NULL; static GtkWidget *confuLabel = NULL; static GtkWidget *encumbPix = NULL; static GtkWidget *encumbLabel = NULL; static GtkStyle *normalStyle = NULL; static GtkStyle *bigStyle = NULL; static GtkStyle *redStyle = NULL; static GtkStyle *greenStyle = NULL; static GtkStyle *bigRedStyle = NULL; static GtkStyle *bigGreenStyle = NULL; /* Pure red */ static GdkColor color_red = { 0, 0xff00, 0, 0 }; /* ForestGreen (looks better than just pure green) */ static GdkColor color_green = { 0, 0x2200, 0x8b00, 0x2200 }; static int lastDepth; static int lastStr; static int lastInt; static int lastWis; static int lastDex; static int lastCon; static int lastCha; static long lastAu; static int lastHP; static int lastMHP; static int lastLevel; static int lastPOW; static int lastMPOW; static int lastAC; static int lastExp; static aligntyp lastAlignment; static unsigned lastHungr; static long lastConf; static long lastBlind; static long lastStun; static long lastHalu; static long lastSick; static int lastEncumb; void ghack_status_window_clear(GtkWidget *win, gpointer data) { /* Don't think we need this at all */ } void ghack_status_window_destroy(GtkWidget *win, gpointer data) { while (s_HighLightList) { g_free((Highlight *) s_HighLightList->data); s_HighLightList = s_HighLightList->next; } g_list_free(s_HighLightList); } void ghack_status_window_display(GtkWidget *win, boolean block, gpointer data) { gtk_widget_show_all(GTK_WIDGET(win)); } void ghack_status_window_cursor_to(GtkWidget *win, int x, int y, gpointer data) { /* Don't think we need this at all */ } void ghack_status_window_put_string(GtkWidget *win, int attr, const char *text, gpointer data) { ghack_status_window_update_stats(); } GtkWidget * ghack_init_status_window() { GtkWidget *horizSep0, *horizSep1, *horizSep2, *horizSep3; GtkWidget *statsHBox, *strVBox, *dexVBox, *intVBox, *statHBox; GtkWidget *wisVBox, *conVBox, *chaVBox; GtkWidget *alignVBox, *hungerVBox, *sickVBox, *blindVBox; GtkWidget *stunVBox, *halluVBox, *confuVBox, *encumbVBox; /* Set up a (ridiculous) initial state */ lastDepth = 9999; lastStr = 9999; lastInt = 9999; lastWis = 9999; lastDex = 9999; lastCon = 9999; lastCha = 9999; lastAu = 9999; lastHP = 9999; lastMHP = 9999; lastLevel = 9999; lastPOW = 9999; lastMPOW = 9999; lastAC = 9999; lastExp = 9999; lastAlignment = A_NEUTRAL; /* start off guessing neutral */ lastHungr = 9999; lastConf = 9999; lastBlind = 9999; lastStun = 9999; lastHalu = 9999; lastSick = 9999; lastEncumb = 9999; statTable = gtk_table_new(10, 8, FALSE); gtk_table_set_row_spacings(GTK_TABLE(statTable), 1); gtk_table_set_col_spacings(GTK_TABLE(statTable), 1); /* Begin the first row of the table -- the title */ titleLabel = gtk_label_new(_("GnomeHack!")); gtk_table_attach(GTK_TABLE(statTable), titleLabel, 0, 8, 0, 1, GTK_FILL, 0, 0, 0); if (!normalStyle) normalStyle = gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(titleLabel))); /* Set up some styles to draw stuff with */ if (!redStyle) { g_assert(greenStyle == NULL); g_assert(bigStyle == NULL); g_assert(bigRedStyle == NULL); g_assert(bigGreenStyle == NULL); greenStyle = gtk_style_copy(normalStyle); redStyle = gtk_style_copy(normalStyle); bigRedStyle = gtk_style_copy(normalStyle); bigGreenStyle = gtk_style_copy(normalStyle); bigStyle = gtk_style_copy(normalStyle); greenStyle->fg[GTK_STATE_NORMAL] = color_green; redStyle->fg[GTK_STATE_NORMAL] = color_red; bigRedStyle->fg[GTK_STATE_NORMAL] = color_red; bigGreenStyle->fg[GTK_STATE_NORMAL] = color_green; gdk_font_unref(bigRedStyle->font); gdk_font_unref(bigGreenStyle->font); bigRedStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); bigGreenStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); gdk_font_unref(bigStyle->font); bigStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); } gtk_widget_set_style(GTK_WIDGET(titleLabel), bigStyle); /* Begin the second row */ dgnLevelLabel = gtk_label_new(_("Nethack for Gnome")); gtk_table_attach(GTK_TABLE(statTable), dgnLevelLabel, 0, 8, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_set_style(GTK_WIDGET(dgnLevelLabel), bigStyle); /* Begin the third row */ horizSep0 = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(statTable), horizSep0, 0, 8, 2, 3, GTK_FILL, GTK_FILL, 0, 0); /* Begin the fourth row */ statsHBox = gtk_hbox_new(TRUE, 0); strVBox = gtk_vbox_new(FALSE, 0); strPix = gnome_pixmap_new_from_xpm_d(str_xpm); strLabel = gtk_label_new("STR: "); gtk_box_pack_start(GTK_BOX(strVBox), strPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(strVBox), strLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(strVBox), TRUE, TRUE, 2); dexVBox = gtk_vbox_new(FALSE, 0); dexPix = gnome_pixmap_new_from_xpm_d(dex_xpm); dexLabel = gtk_label_new("DEX: "); gtk_box_pack_start(GTK_BOX(dexVBox), dexPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(dexVBox), dexLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(dexVBox), TRUE, TRUE, 2); conVBox = gtk_vbox_new(FALSE, 0); conPix = gnome_pixmap_new_from_xpm_d(cns_xpm); conLabel = gtk_label_new("CON: "); gtk_box_pack_start(GTK_BOX(conVBox), conPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(conVBox), conLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(conVBox), TRUE, TRUE, 2); intVBox = gtk_vbox_new(FALSE, 0); intPix = gnome_pixmap_new_from_xpm_d(int_xpm); intLabel = gtk_label_new("INT: "); gtk_box_pack_start(GTK_BOX(intVBox), intPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(intVBox), intLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(intVBox), TRUE, TRUE, 2); wisVBox = gtk_vbox_new(FALSE, 0); wisPix = gnome_pixmap_new_from_xpm_d(wis_xpm); wisLabel = gtk_label_new("WIS: "); gtk_box_pack_start(GTK_BOX(wisVBox), wisPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(wisVBox), wisLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(wisVBox), TRUE, TRUE, 2); chaVBox = gtk_vbox_new(FALSE, 0); chaPix = gnome_pixmap_new_from_xpm_d(cha_xpm); chaLabel = gtk_label_new("CHA: "); gtk_box_pack_start(GTK_BOX(chaVBox), chaPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(chaVBox), chaLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statsHBox), GTK_WIDGET(chaVBox), TRUE, TRUE, 2); gtk_table_attach(GTK_TABLE(statTable), GTK_WIDGET(statsHBox), 0, 8, 3, 4, GTK_FILL, 0, 0, 0); /* Begin the fifth row */ horizSep1 = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(statTable), horizSep1, 0, 8, 4, 5, GTK_FILL, GTK_FILL, 0, 0); /* Begin the sixth row */ hpLabel = gtk_label_new("HP: "); gtk_table_attach(GTK_TABLE(statTable), hpLabel, 0, 1, 5, 6, GTK_FILL, 0, 0, 0); acLabel = gtk_label_new("AC: "); gtk_table_attach(GTK_TABLE(statTable), acLabel, 2, 3, 5, 6, GTK_FILL, 0, 0, 0); powLabel = gtk_label_new("Power: "); gtk_table_attach(GTK_TABLE(statTable), powLabel, 4, 5, 5, 6, GTK_FILL, 0, 0, 0); goldLabel = gtk_label_new("Au: "); gtk_table_attach(GTK_TABLE(statTable), goldLabel, 6, 7, 5, 6, GTK_FILL, 0, 0, 0); /* Begin the seventh row */ horizSep2 = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(statTable), horizSep2, 0, 8, 6, 7, GTK_FILL, GTK_FILL, 0, 0); /* Begin the eigth row */ levlLabel = gtk_label_new("Level: "); gtk_table_attach(GTK_TABLE(statTable), levlLabel, 0, 1, 7, 8, GTK_FILL, 0, 0, 0); expLabel = gtk_label_new("Exp: "); gtk_table_attach(GTK_TABLE(statTable), expLabel, 2, 3, 7, 8, GTK_FILL, 0, 0, 0); timeLabel = gtk_label_new("Time: "); gtk_table_attach(GTK_TABLE(statTable), timeLabel, 4, 5, 7, 8, GTK_FILL, 0, 0, 0); scoreLabel = gtk_label_new("Score: "); gtk_table_attach(GTK_TABLE(statTable), scoreLabel, 6, 7, 7, 8, GTK_FILL, 0, 0, 0); /* Begin the ninth row */ horizSep3 = gtk_hseparator_new(); gtk_table_attach(GTK_TABLE(statTable), horizSep3, 0, 8, 8, 9, GTK_FILL, GTK_FILL, 0, 0); /* Begin the tenth and last row */ statHBox = gtk_hbox_new(FALSE, 0); alignVBox = gtk_vbox_new(FALSE, 0); alignPix = gnome_pixmap_new_from_xpm_d(neutral_xpm); alignLabel = gtk_label_new("Neutral"); gtk_box_pack_start(GTK_BOX(alignVBox), alignPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(alignVBox), alignLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(alignVBox), TRUE, FALSE, 2); hungerVBox = gtk_vbox_new(FALSE, 0); hungerPix = gnome_pixmap_new_from_xpm_d(hungry_xpm); hungerLabel = gtk_label_new("Hungry"); gtk_box_pack_start(GTK_BOX(hungerVBox), hungerPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(hungerVBox), hungerLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(hungerVBox), TRUE, FALSE, 2); sickVBox = gtk_vbox_new(FALSE, 0); sickPix = gnome_pixmap_new_from_xpm_d(sick_fp_xpm); sickLabel = gtk_label_new("FoodPois"); gtk_box_pack_start(GTK_BOX(sickVBox), sickPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(sickVBox), sickLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(sickVBox), TRUE, FALSE, 2); blindVBox = gtk_vbox_new(FALSE, 0); blindPix = gnome_pixmap_new_from_xpm_d(blind_xpm); blindLabel = gtk_label_new("Blind"); gtk_box_pack_start(GTK_BOX(blindVBox), blindPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(blindVBox), blindLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(blindVBox), TRUE, FALSE, 2); stunVBox = gtk_vbox_new(FALSE, 0); stunPix = gnome_pixmap_new_from_xpm_d(stunned_xpm); stunLabel = gtk_label_new("Stun"); gtk_box_pack_start(GTK_BOX(stunVBox), stunPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(stunVBox), stunLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(stunVBox), TRUE, FALSE, 2); confuVBox = gtk_vbox_new(FALSE, 0); confuPix = gnome_pixmap_new_from_xpm_d(confused_xpm); confuLabel = gtk_label_new("Confused"); gtk_box_pack_start(GTK_BOX(confuVBox), confuPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(confuVBox), confuLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(confuVBox), TRUE, FALSE, 2); halluVBox = gtk_vbox_new(FALSE, 0); halluPix = gnome_pixmap_new_from_xpm_d(hallu_xpm); halluLabel = gtk_label_new("Hallu"); gtk_box_pack_start(GTK_BOX(halluVBox), halluPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(halluVBox), halluLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(halluVBox), TRUE, FALSE, 2); encumbVBox = gtk_vbox_new(FALSE, 0); encumbPix = gnome_pixmap_new_from_xpm_d(slt_enc_xpm); encumbLabel = gtk_label_new("Burdened"); gtk_box_pack_start(GTK_BOX(encumbVBox), encumbPix, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(encumbVBox), encumbLabel, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(statHBox), GTK_WIDGET(encumbVBox), TRUE, FALSE, 2); gtk_table_attach(GTK_TABLE(statTable), GTK_WIDGET(statHBox), 0, 8, 9, 10, GTK_FILL, GTK_FILL, 0, 0); /* Set up the necessary signals */ gtk_signal_connect(GTK_OBJECT(statTable), "ghack_fade_highlight", GTK_SIGNAL_FUNC(ghack_fade_highlighting), NULL); gtk_signal_connect(GTK_OBJECT(statTable), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_status_window_put_string), NULL); gtk_signal_connect(GTK_OBJECT(statTable), "ghack_clear", GTK_SIGNAL_FUNC(ghack_status_window_clear), NULL); gtk_signal_connect(GTK_OBJECT(statTable), "ghack_curs", GTK_SIGNAL_FUNC(ghack_status_window_cursor_to), NULL); gtk_signal_connect(GTK_OBJECT(statTable), "gnome_delay_output", GTK_SIGNAL_FUNC(ghack_delay), NULL); /* Lastly, show the status window and everything in it */ gtk_widget_show_all(statTable); return GTK_WIDGET(statTable); } void ghack_status_window_update_stats() { char buf[BUFSZ]; gchar *buf1; const char *hung; const char *enc; static int firstTime = TRUE; long umoney; /* First, fill in the player name and the dungeon level */ strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A' - 'a'; strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; strcpy(mname, mons[u.umonnum].mname); while (mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k - 1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') { mname[k] += 'A' - 'a'; } k++; } strcat(buf, mname); } else { strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); } gtk_label_get(GTK_LABEL(titleLabel), &buf1); if (strcmp(buf1, buf) != 0 && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(titleLabel, bigStyle, bigGreenStyle); } gtk_label_set(GTK_LABEL(titleLabel), buf); if (In_endgame(&u.uz)) { strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane" : "End Game")); } else { sprintf(buf, "%s, level %d", dungeons[u.uz.dnum].dname, depth(&u.uz)); } if (lastDepth > depth(&u.uz) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dgnLevelLabel, bigStyle, bigRedStyle); } else if (lastDepth < depth(&u.uz) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dgnLevelLabel, bigStyle, bigGreenStyle); } lastDepth = depth(&u.uz); gtk_label_set(GTK_LABEL(dgnLevelLabel), buf); /* Next, fill in the player's stats */ if (ACURR(A_STR) > 118) { sprintf(buf, "STR:%d", ACURR(A_STR) - 100); } else if (ACURR(A_STR) == 118) { sprintf(buf, "STR:18/**"); } else if (ACURR(A_STR) > 18) { sprintf(buf, "STR:18/%02d", ACURR(A_STR) - 18); } else { sprintf(buf, "STR:%d", ACURR(A_STR)); } if (lastStr < ACURR(A_STR) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(strLabel, normalStyle, greenStyle); } else if (lastStr > ACURR(A_STR) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(strLabel, normalStyle, redStyle); } lastStr = ACURR(A_STR); gtk_label_set(GTK_LABEL(strLabel), buf); sprintf(buf, "INT:%d", ACURR(A_INT)); if (lastInt < ACURR(A_INT) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(intLabel, normalStyle, greenStyle); } else if (lastInt > ACURR(A_INT) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(intLabel, normalStyle, redStyle); } lastInt = ACURR(A_INT); gtk_label_set(GTK_LABEL(intLabel), buf); sprintf(buf, "WIS:%d", ACURR(A_WIS)); if (lastWis < ACURR(A_WIS) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(wisLabel, normalStyle, greenStyle); } else if (lastWis > ACURR(A_WIS) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(wisLabel, normalStyle, redStyle); } lastWis = ACURR(A_WIS); gtk_label_set(GTK_LABEL(wisLabel), buf); sprintf(buf, "DEX:%d", ACURR(A_DEX)); if (lastDex < ACURR(A_DEX) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dexLabel, normalStyle, greenStyle); } else if (lastDex > ACURR(A_DEX) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(dexLabel, normalStyle, redStyle); } lastDex = ACURR(A_DEX); gtk_label_set(GTK_LABEL(dexLabel), buf); sprintf(buf, "CON:%d", ACURR(A_CON)); if (lastCon < ACURR(A_CON) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(conLabel, normalStyle, greenStyle); } else if (lastCon > ACURR(A_CON) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(conLabel, normalStyle, redStyle); } lastCon = ACURR(A_CON); gtk_label_set(GTK_LABEL(conLabel), buf); sprintf(buf, "CHA:%d", ACURR(A_CHA)); if (lastCha < ACURR(A_CHA) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(chaLabel, normalStyle, greenStyle); } else if (lastCha > ACURR(A_CHA) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(chaLabel, normalStyle, redStyle); } lastCha = ACURR(A_CHA); gtk_label_set(GTK_LABEL(chaLabel), buf); /* Now do the non-pixmaped stats (gold and such) */ umoney = money_cnt(invent); sprintf(buf, "Au:%ld", umoney); if (lastAu < umoney && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(goldLabel, normalStyle, greenStyle); } else if (lastAu > umoney && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(goldLabel, normalStyle, redStyle); } lastAu = umoney; gtk_label_set(GTK_LABEL(goldLabel), buf); if (u.mtimedone) { /* special case: when polymorphed, show "HD", disable exp */ sprintf(buf, "HP:%d/%d", ((u.mh > 0) ? u.mh : 0), u.mhmax); if ((lastHP < u.mh || lastMHP < u.mhmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, greenStyle); } else if ((lastHP > u.mh || lastMHP > u.mhmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, redStyle); } lastHP = u.mh; lastMHP = u.mhmax; } else { sprintf(buf, "HP:%d/%d", ((u.uhp > 0) ? u.uhp : 0), u.uhpmax); if ((lastHP < u.uhp || lastMHP < u.uhpmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, greenStyle); } else if ((lastHP > u.uhp || lastMHP > u.uhpmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hpLabel, normalStyle, redStyle); } lastHP = u.uhp; lastMHP = u.uhpmax; } gtk_label_set(GTK_LABEL(hpLabel), buf); if (u.mtimedone) { /* special case: when polymorphed, show "HD", disable exp */ sprintf(buf, "HD:%d", mons[u.umonnum].mlevel); if (lastLevel < mons[u.umonnum].mlevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, greenStyle); } else if (lastLevel > mons[u.umonnum].mlevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, redStyle); } lastLevel = mons[u.umonnum].mlevel; } else { sprintf(buf, "Level:%d", u.ulevel); if (lastLevel < u.ulevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, greenStyle); } else if (lastLevel > u.ulevel && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(levlLabel, normalStyle, redStyle); } lastLevel = u.ulevel; } gtk_label_set(GTK_LABEL(levlLabel), buf); sprintf(buf, "Power:%d/%d", u.uen, u.uenmax); if ((lastPOW < u.uen || lastMPOW < u.uenmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(powLabel, normalStyle, greenStyle); } if ((lastPOW > u.uen || lastMPOW > u.uenmax) && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(powLabel, normalStyle, redStyle); } lastPOW = u.uen; lastMPOW = u.uenmax; gtk_label_set(GTK_LABEL(powLabel), buf); sprintf(buf, "AC:%d", u.uac); if (lastAC > u.uac && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(acLabel, normalStyle, greenStyle); } else if (lastAC < u.uac && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(acLabel, normalStyle, redStyle); } lastAC = u.uac; gtk_label_set(GTK_LABEL(acLabel), buf); if (flags.showexp) { sprintf(buf, "Exp:%ld", u.uexp); if (lastExp < u.uexp && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(expLabel, normalStyle, greenStyle); } else if (lastExp > u.uexp && firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(expLabel, normalStyle, redStyle); } lastExp = u.uexp; gtk_label_set(GTK_LABEL(expLabel), buf); } else { gtk_label_set(GTK_LABEL(expLabel), ""); } if (flags.time) { sprintf(buf, "Time:%ld", moves); gtk_label_set(GTK_LABEL(timeLabel), buf); } else gtk_label_set(GTK_LABEL(timeLabel), ""); #ifdef SCORE_ON_BOTL if (flags.showscore) { sprintf(buf, "Score:%ld", botl_score()); gtk_label_set(GTK_LABEL(scoreLabel), buf); } else gtk_label_set(GTK_LABEL(scoreLabel), ""); #else { gtk_label_set(GTK_LABEL(scoreLabel), ""); } #endif /* See if their alignment has changed */ if (lastAlignment != u.ualign.type) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(alignLabel, normalStyle, redStyle); } lastAlignment = u.ualign.type; /* looks like their alignment has changed -- change out the icon */ if (u.ualign.type == A_CHAOTIC) { gtk_label_set(GTK_LABEL(alignLabel), "Chaotic"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), chaotic_xpm); } else if (u.ualign.type == A_NEUTRAL) { gtk_label_set(GTK_LABEL(alignLabel), "Neutral"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), neutral_xpm); } else { gtk_label_set(GTK_LABEL(alignLabel), "Lawful"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(alignPix), lawful_xpm); } } hung = hu_stat[u.uhs]; if (lastHungr != u.uhs) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(hungerLabel, normalStyle, redStyle); } lastHungr = u.uhs; if (hung[0] == ' ') { gtk_label_set(GTK_LABEL(hungerLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), nothing_xpm); } else if (u.uhs == 0 /* SATIATED */) { gtk_label_set(GTK_LABEL(hungerLabel), hung); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), satiated_xpm); } else { gtk_label_set(GTK_LABEL(hungerLabel), hung); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(hungerPix), hungry_xpm); } } if (lastConf != Confusion) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(confuLabel, normalStyle, redStyle); } lastConf = Confusion; if (Confusion) { gtk_label_set(GTK_LABEL(confuLabel), "Confused"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(confuPix), confused_xpm); } else { gtk_label_set(GTK_LABEL(confuLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(confuPix), nothing_xpm); } } if (lastBlind != Blind) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(blindLabel, normalStyle, redStyle); } lastBlind = Blind; if (Blind) { gtk_label_set(GTK_LABEL(blindLabel), "Blind"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(blindPix), blind_xpm); } else { gtk_label_set(GTK_LABEL(blindLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(blindPix), nothing_xpm); } } if (lastStun != Stunned) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(stunLabel, normalStyle, redStyle); } lastStun = Stunned; if (Stunned) { gtk_label_set(GTK_LABEL(stunLabel), "Stun"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(stunPix), stunned_xpm); } else { gtk_label_set(GTK_LABEL(stunLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(stunPix), nothing_xpm); } } if (lastHalu != Hallucination) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(halluLabel, normalStyle, redStyle); } lastHalu = Hallucination; if (Hallucination) { gtk_label_set(GTK_LABEL(halluLabel), "Hallu"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(halluPix), hallu_xpm); } else { gtk_label_set(GTK_LABEL(halluLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(halluPix), nothing_xpm); } } if (lastSick != Sick) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(sickLabel, normalStyle, redStyle); } lastSick = Sick; if (Sick) { if (u.usick_type & SICK_VOMITABLE) { gtk_label_set(GTK_LABEL(sickLabel), "FoodPois"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_fp_xpm); } else if (u.usick_type & SICK_NONVOMITABLE) { gtk_label_set(GTK_LABEL(sickLabel), "Ill"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_il_xpm); } else { gtk_label_set(GTK_LABEL(sickLabel), "FoodPois"); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), sick_fp_xpm); } } else { gtk_label_set(GTK_LABEL(sickLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(sickPix), nothing_xpm); } } enc = enc_stat[near_capacity()]; if (lastEncumb != near_capacity()) { if (firstTime == FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget(encumbLabel, normalStyle, redStyle); } lastEncumb = near_capacity(); switch (lastEncumb) { case 0: gtk_label_set(GTK_LABEL(encumbLabel), " "); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), nothing_xpm); break; case 1: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), slt_enc_xpm); break; case 2: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), mod_enc_xpm); break; case 3: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), hvy_enc_xpm); break; case 4: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), ext_enc_xpm); break; case 5: gtk_label_set(GTK_LABEL(encumbLabel), enc); gnome_pixmap_load_xpm_d(GNOME_PIXMAP(encumbPix), ovr_enc_xpm); } } firstTime = FALSE; } static void ghack_fade_highlighting() { GList *item; Highlight *highlt; /* Remove any items from the queue if their time is up */ for (item = g_list_first(s_HighLightList); item;) { highlt = (Highlight *) item->data; if (highlt) { if (highlt->nTurnsLeft <= 0) { gtk_widget_set_style(GTK_WIDGET(highlt->widget), highlt->oldStyle); s_HighLightList = g_list_remove_link(s_HighLightList, item); g_free(highlt); g_list_free_1(item); item = g_list_first(s_HighLightList); continue; } else (highlt->nTurnsLeft)--; } if (item) item = item->next; else break; } } /* Widget changed, so add it to the highlighing list */ static void ghack_highlight_widget(GtkWidget *widget, GtkStyle *oldStyle, GtkStyle *newStyle) { Highlight *highlt; GList *item; /* Check if this widget is already in the queue. If so then * remove it, so we will only have the new entry in the queue */ for (item = g_list_first(s_HighLightList); item;) { highlt = (Highlight *) item->data; if (highlt) { if (highlt->widget == widget) { s_HighLightList = g_list_remove_link(s_HighLightList, item); g_free(highlt); g_list_free_1(item); break; } } if (item) item = item->next; else break; } /* Ok, now highlight this widget and add it into the fade * highlighting queue */ highlt = g_new(Highlight, 1); highlt->nTurnsLeft = NUM_TURNS_HIGHLIGHTED; highlt->oldStyle = oldStyle; highlt->widget = widget; s_HighLightList = g_list_prepend(s_HighLightList, highlt); gtk_widget_set_style(GTK_WIDGET(widget), newStyle); } nethack-3.6.0/win/gnome/gnstatus.h0000664000076400007660000000071012536476415016073 0ustar paxedpaxed/* NetHack 3.6 gnstatus.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackStatusWindow_h #define GnomeHackStatusWindow_h #include #include "config.h" #include "global.h" GtkWidget *ghack_init_status_window(); #endif /* GnomeHackStatusWindow_h */ nethack-3.6.0/win/gnome/gntext.c0000664000076400007660000001132312536476415015531 0ustar paxedpaxed/* NetHack 3.6 gntext.c $NHDT-Date: 1432512804 2015/05/25 00:13:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gntext.h" #include "gnmain.h" #include /* include the standard RIP window (win/X11/rip.xpm) */ #include "gn_rip.h" /* dimensions of the pixmap */ #define RIP_IMAGE_WIDTH 400 #define RIP_IMAGE_HEIGHT 200 /* dimensions and location of area where we can draw text on the pixmap */ #define RIP_DRAW_WIDTH 84 #define RIP_DRAW_HEIGHT 89 #define RIP_DRAW_X 114 #define RIP_DRAW_Y 69 /* Text Window widgets */ GtkWidget *RIP = NULL; GtkWidget *RIPlabel = NULL; GtkWidget *TW_window = NULL; GnomeLess *gless; static int showRIP = 0; void ghack_text_window_clear(GtkWidget *widget, gpointer data) { g_assert(gless != NULL); gtk_editable_delete_text(GTK_EDITABLE(gless->text), 0, 0); } void ghack_text_window_destroy() { TW_window = NULL; } void ghack_text_window_display(GtkWidget *widget, boolean block, gpointer data) { if (showRIP == 1) { gtk_widget_show(GTK_WIDGET(RIP)); gtk_window_set_title(GTK_WINDOW(TW_window), "Rest In Peace"); } gtk_signal_connect(GTK_OBJECT(TW_window), "destroy", (GtkSignalFunc) ghack_text_window_destroy, NULL); if (block) gnome_dialog_run(GNOME_DIALOG(TW_window)); else gnome_dialog_run_and_close(GNOME_DIALOG(TW_window)); if (showRIP == 1) { showRIP = 0; gtk_widget_hide(GTK_WIDGET(RIP)); gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window"); } } void ghack_text_window_put_string(GtkWidget *widget, int attr, const char *text, gpointer data) { if (text == NULL) return; /* Don't bother with attributes yet */ gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, text, -1); gtk_text_insert(GTK_TEXT(gless->text), NULL, NULL, NULL, "\n", -1); } GtkWidget * ghack_init_text_window() { GtkWidget *pixmap; if (TW_window) return (GTK_WIDGET(TW_window)); TW_window = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL); gtk_window_set_default_size(GTK_WINDOW(TW_window), 500, 400); gtk_window_set_policy(GTK_WINDOW(TW_window), TRUE, TRUE, FALSE); gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window"); /* create GNOME pixmap object */ pixmap = gnome_pixmap_new_from_xpm_d(rip_xpm); g_assert(pixmap != NULL); gtk_widget_show(GTK_WIDGET(pixmap)); /* create label with our "death message", sized to fit into the * tombstone */ RIPlabel = gtk_label_new("RIP"); g_assert(RIPlabel != NULL); /* gtk_label_set_justify is broken? */ gtk_label_set_justify(GTK_LABEL(RIPlabel), GTK_JUSTIFY_CENTER); gtk_label_set_line_wrap(GTK_LABEL(RIPlabel), TRUE); gtk_widget_set_usize(RIPlabel, RIP_DRAW_WIDTH, RIP_DRAW_HEIGHT); gtk_widget_show(RIPlabel); /* create a fixed sized widget for the RIP pixmap */ RIP = gtk_fixed_new(); g_assert(RIP != NULL); gtk_widget_set_usize(RIP, RIP_IMAGE_WIDTH, RIP_IMAGE_HEIGHT); gtk_fixed_put(GTK_FIXED(RIP), pixmap, 0, 0); gtk_fixed_put(GTK_FIXED(RIP), RIPlabel, RIP_DRAW_X, RIP_DRAW_Y); gtk_widget_show(RIP); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), RIP, TRUE, TRUE, 0); /* create a gnome Less widget for the text stuff */ gless = GNOME_LESS(gnome_less_new()); g_assert(gless != NULL); gtk_widget_show(GTK_WIDGET(gless)); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), GTK_WIDGET(gless), TRUE, TRUE, 0); /* Hook up some signals */ gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_text_window_put_string), NULL); gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_clear", GTK_SIGNAL_FUNC(ghack_text_window_clear), NULL); gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_display", GTK_SIGNAL_FUNC(ghack_text_window_display), NULL); /* Center the dialog over over parent */ gnome_dialog_set_parent(GNOME_DIALOG(TW_window), GTK_WINDOW(ghack_get_main_window())); gtk_window_set_modal(GTK_WINDOW(TW_window), TRUE); gtk_widget_show_all(TW_window); gtk_widget_hide(GTK_WIDGET(RIP)); gnome_dialog_close_hides(GNOME_DIALOG(TW_window), TRUE); return GTK_WIDGET(TW_window); } void ghack_text_window_rip_string(const char *string) { /* This is called to specify that the next message window will * be a RIP window, which will include this text */ showRIP = 1; gtk_label_set(GTK_LABEL(RIPlabel), string); } nethack-3.6.0/win/gnome/gntext.h0000664000076400007660000000151512536476415015540 0ustar paxedpaxed/* NetHack 3.6 gntext.h $NHDT-Date: 1432512805 2015/05/25 00:13:25 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackTextWindow_h #define GnomeHackTextWindow_h #include #include "config.h" #include "global.h" GtkWidget *ghack_init_text_window(); void ghack_text_window_clear(GtkWidget *widget, gpointer data); void ghack_text_window_destroy(); void ghack_text_window_display(GtkWidget *widget, boolean block, gpointer data); void ghack_text_window_put_string(GtkWidget *widget, int attr, const char *text, gpointer data); void ghack_text_window_rip_string(const char *ripString); #endif /* GnomeHackTextWindow_h */ nethack-3.6.0/win/gnome/gnworn.c0000664000076400007660000000660112536476415015535 0ustar paxedpaxed/* NetHack 3.6 gnworn.c 2009/05/06 10:58:06 1.3 */ /* * $NHDT-Date: 1432512804 2015/05/25 00:13:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2002, Dylan Alex Simon */ /* NetHack may be freely redistributed. See license for details. */ #include "gnworn.h" #include "gnglyph.h" #include "gnsignal.h" #include "gnomeprv.h" #define WORN_WIDTH 3 #define WORN_HEIGHT 6 #define WORN_OBJECT_LIST /* struct obj *[WORN_HEIGHT][WORN_WIDTH] = */ \ { \ { \ uquiver, uarmh, u.twoweap ? NULL : uswapwep \ } \ , { u.twoweap ? uswapwep : NULL, ublindf, uwep }, \ { uleft, uamul, uright }, { uarms, uarmc, uarmg }, \ { uarmu, uarm, uskin }, \ { \ uball, uarmf, uchain \ } \ } static GtkWidget *worn_contents[WORN_HEIGHT][WORN_WIDTH]; static struct obj *last_worn_objects[WORN_HEIGHT][WORN_WIDTH]; GdkImlibImage *image_of_worn_object(struct obj *o); void ghack_worn_display(GtkWidget *win, boolean block, gpointer data); GtkWidget * ghack_init_worn_window() { GtkWidget *top; GtkWidget *table; GtkWidget *tablealign; GtkWidget *label; int i, j; top = gtk_vbox_new(FALSE, 2); table = gtk_table_new(WORN_HEIGHT, WORN_WIDTH, TRUE); for (i = 0; i < WORN_HEIGHT; i++) { for (j = 0; j < WORN_WIDTH; j++) { worn_contents[i][j] = gnome_pixmap_new_from_imlib(image_of_worn_object(NULL)); last_worn_objects[i][j] = NULL; /* a pointer that will never be */ gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(worn_contents[i][j]), j, j + 1, i, i + 1, 0, 0, 0, 0); } } tablealign = gtk_alignment_new(0.5, 0.0, 0.0, 1.0); gtk_box_pack_start(GTK_BOX(top), tablealign, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(tablealign), table); label = gtk_label_new("Equipment"); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(top), label, FALSE, FALSE, 0); gtk_signal_connect(GTK_OBJECT(top), "ghack_display", GTK_SIGNAL_FUNC(ghack_worn_display), NULL); return top; } GdkImlibImage * image_of_worn_object(struct obj *o) { int glyph; GdkImlibImage *im; if (o) glyph = obj_to_glyph(o); else glyph = cmap_to_glyph(S_stone); im = ghack_image_from_glyph(glyph, FALSE); return im; } void ghack_worn_display(GtkWidget *win, boolean block, gpointer data) { int i, j; struct obj *worn_objects[WORN_HEIGHT][WORN_WIDTH] = WORN_OBJECT_LIST; for (i = 0; i < WORN_HEIGHT; i++) { for (j = 0; j < WORN_WIDTH; j++) { if (worn_objects[i][j] != last_worn_objects[i][j]) { last_worn_objects[i][j] = worn_objects[i][j]; gnome_pixmap_load_imlib( GNOME_PIXMAP(worn_contents[i][j]), image_of_worn_object(worn_objects[i][j])); } } } } nethack-3.6.0/win/gnome/gnworn.h0000664000076400007660000000071712536476415015544 0ustar paxedpaxed/* NetHack 3.6 gnworn.h 2009/05/06 10:58:06 1.3 */ /* * $NHDT-Date: 1432512804 2015/05/25 00:13:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 2002 by Dylan Alex Simon */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackWornWindow_h #define GnomeHackWornWindow_h #include #include "config.h" #include "global.h" GtkWidget *ghack_init_worn_window(); #endif /* GnomeHackWornWindow_h */ nethack-3.6.0/win/gnome/gnyesno.c0000664000076400007660000000471212536476415015706 0ustar paxedpaxed/* NetHack 3.6 gnyesno.c $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnbind.h" #include "gnyesno.h" int ghack_yes_no_dialog(const char *question, const char *choices, int def) { int i = 0, ret; gchar button_name[BUFSZ]; GtkWidget *box; GtkWidget *mainWnd = NULL; box = gnome_message_box_new(question, GNOME_MESSAGE_BOX_QUESTION, NULL); /* add buttons for each choice */ if (!strcmp(GNOME_STOCK_BUTTON_OK, choices)) { gnome_dialog_append_button(GNOME_DIALOG(box), GNOME_STOCK_BUTTON_OK); gnome_dialog_set_default(GNOME_DIALOG(box), 0); gnome_dialog_set_accelerator(GNOME_DIALOG(box), 0, 'o', 0); #if 0 g_print("Setting accelerator '%c' for button %d\n", 'o', 0); #endif } else { for (; choices[i] != '\0'; i++) { if (choices[i] == 'y') { sprintf(button_name, GNOME_STOCK_BUTTON_YES); } else if (choices[i] == 'n') { sprintf(button_name, GNOME_STOCK_BUTTON_NO); } else if (choices[i] == 'q') { sprintf(button_name, "Quit"); } else { sprintf(button_name, "%c", choices[i]); } if (def == choices[i]) gnome_dialog_set_default(GNOME_DIALOG(box), i); gnome_dialog_append_button(GNOME_DIALOG(box), button_name); gnome_dialog_set_accelerator(GNOME_DIALOG(box), i, choices[i], 0); #if 0 g_print("Setting accelerator '%c' for button %d\n", choices[i], i); #endif } } #if 0 /* Perhaps add in a quit game button, like this... */ gnome_dialog_append_button ( GNOME_DIALOG(box), GNOME_STOCK_BUTTON_CLOSE); gnome_dialog_set_accelerator( GNOME_DIALOG(box), i, choices[i], 0); g_print("Setting accelerator '%c' for button %d\n", 'Q', i); #endif gnome_dialog_set_close(GNOME_DIALOG(box), TRUE); mainWnd = ghack_get_main_window(); gtk_window_set_modal(GTK_WINDOW(box), TRUE); gtk_window_set_title(GTK_WINDOW(box), "GnomeHack"); if (mainWnd != NULL) { gnome_dialog_set_parent(GNOME_DIALOG(box), GTK_WINDOW(mainWnd)); } ret = gnome_dialog_run_and_close(GNOME_DIALOG(box)); #if 0 g_print("You selected button %d\n", ret); #endif if (ret == -1) return ('\033'); else return (choices[ret]); } nethack-3.6.0/win/gnome/gnyesno.h0000664000076400007660000000067012536476415015712 0ustar paxedpaxed/* NetHack 3.6 gnyesno.h $NHDT-Date: 1432512807 2015/05/25 00:13:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackYesNoDialog_h #define GnomeHackYesNoDialog_h int ghack_yes_no_dialog(const char *szQuestionStr, const char *szChoicesStr, int nDefault); #endif nethack-3.6.0/win/gnome/mapbg.xpm0000664000076400007660000005462512467321052015671 0ustar paxedpaxed/* XPM */ static char * mapbg_xpm[] = { "96 96 254 2", " c None", ". c #BC6C33", "+ c #AC6324", "@ c #B46B2B", "# c #B47734", "$ c #AC6B2C", "% c #B46C3D", "& c #BC7945", "* c #A4774B", "= c #B48643", "- c #AC7F40", "; c #AC773A", "> c #C49054", ", c #C48044", "' c #B4642C", ") c #B45E21", "! c #BC642B", "~ c #BD723E", "{ c #C4884E", "] c #C48F4B", "^ c #C49753", "/ c #CC9052", "( c #CC7234", "_ c #B4804F", ": c #C4985D", "< c #946232", "[ c #AC6431", "} c #C46637", "| c #945222", "1 c #8C5435", "2 c #844C29", "3 c #945836", "4 c #AC653D", "5 c #A45E2B", "6 c #AC5E2A", "7 c #A44D21", "8 c #A45823", "9 c #A4592C", "0 c #B46C34", "a c #B46536", "b c #AC7240", "c c #AC7231", "d c #944C1B", "e c #8C5223", "f c #945722", "g c #AC6B34", "h c #944C24", "i c #9C5222", "j c #B47234", "k c #C4783B", "l c #BC7833", "m c #BC7F3B", "n c #BC8044", "o c #BC783C", "p c #A46332", "q c #9C6331", "r c #B4773C", "s c #B4723D", "t c #A46B33", "u c #B48043", "v c #CC814C", "w c #B46422", "x c #C47946", "y c #C48743", "z c #BC6D3D", "A c #BC6536", "B c #94522E", "C c #A4643E", "D c #B45E2F", "E c #A45223", "F c #9C4C1B", "G c #B47845", "H c #C4804D", "I c #9C5723", "J c #AC5E35", "K c #A45935", "L c #9B5E29", "M c #BE7234", "N c #BC8744", "O c #AC5924", "P c #A45E35", "Q c #9C582C", "R c #AC501F", "S c #9C5935", "T c #8C4D28", "U c #643D21", "V c #845437", "W c #B47E31", "X c #844126", "Y c #B45823", "Z c #954627", "` c #9C4C24", " . c #7C4124", ".. c #B4592D", "+. c #9C5E37", "@. c #945644", "#. c #AC6C3E", "$. c #8C4627", "%. c #9C643E", "&. c #744021", "*. c #A4723C", "=. c #844628", "-. c #743819", ";. c #844019", ">. c #944D2D", ",. c #A4512C", "'. c #B45227", "). c #C4622A", "!. c #9C522E", "~. c #7C3A1A", "{. c #BC5E24", "]. c #CC8243", "^. c #9C664C", "/. c #AC5934", "(. c #9C4E2E", "_. c #7C4B29", ":. c #8C532C", "<. c #A46423", "[. c #7C422C", "}. c #743214", "|. c #AC592C", "1. c #8C4224", "2. c #C47F3C", "3. c #8C421C", "4. c #8C410F", "5. c #8C5D3E", "6. c #8C5B32", "7. c #88461A", "8. c #663626", "9. c #AC6B4C", "0. c #94411A", "a. c #845C30", "b. c #744B20", "c. c #7C4D34", "d. c #CC874A", "e. c #D49053", "f. c #C46C32", "g. c #BC814D", "h. c #CC7842", "i. c #A45A44", "j. c #8C4B1A", "k. c #843204", "l. c #945E37", "m. c #7C564C", "n. c #74422C", "o. c #95461B", "p. c #AC7747", "q. c #745634", "r. c #94572C", "s. c #7C4621", "t. c #CC7A54", "u. c #B47654", "v. c #BC5E2C", "w. c #B49056", "x. c #C4915C", "y. c #B4874E", "z. c #BC884D", "A. c #A46C45", "B. c #D48749", "C. c #BC5A30", "D. c #CCA06C", "E. c #BCA26C", "F. c #BC8F54", "G. c #BC895C", "H. c #BC8F4C", "I. c #BC995E", "J. c #C46D3D", "K. c #D4985A", "L. c #C4562C", "M. c #843A16", "N. c #C49F63", "O. c #BC9652", "P. c #B48F4C", "Q. c #CC915C", "R. c #BC5824", "S. c #B49A60", "T. c #CC9F60", "U. c #DC995F", "V. c #AC8A54", "W. c #B4875F", "X. c #C4885C", "Y. c #BC905E", "Z. c #CC975B", "`. c #D4A167", " + c #7C5334", ".+ c #9C6B39", "++ c #845323", "@+ c #B46D4C", "#+ c #A46B3C", "$+ c #CC9864", "%+ c #8C4E34", "&+ c #743A24", "*+ c #6C3D2E", "=+ c #C45E30", "-+ c #AC7E52", ";+ c #9C6C47", ">+ c #6C3C1B", ",+ c #CC8954", "'+ c #542810", ")+ c #7C5E3C", "!+ c #84532C", "~+ c #946C45", "{+ c #946340", "]+ c #BCA870", "^+ c #B49E5C", "/+ c #C47E5C", "(+ c #AC8E44", "_+ c #8C633A", ":+ c #C4A86C", "<+ c #CCA76E", "[+ c #CCA961", "}+ c #7A462D", "|+ c #8C6644", "1+ c #744623", "2+ c #A47248", "3+ c #94624C", "4+ c #845E3C", "5+ c #7C5329", "6+ c #9C7249", "7+ c #844D34", "8+ c #6C4C30", "9+ c #A46E54", "0+ c #A4624C", "a+ c #6C3E24", "b+ c #5C3224", "c+ c #D4A66C", "d+ c #744B30", "e+ c #BC926C", "f+ c #AC7954", "g+ c #AC522C", "h+ c #6C4526", "i+ c #A47A54", "j+ c #BC6644", "k+ c #BC6E4C", "l+ c #A48650", "m+ c #AC825C", "n+ c #CC6A34", "o+ c #9C7E5C", "p+ c #7C623C", "q+ c #5C3A2C", "r+ c #644A34", "s+ c #4C3624", "t+ c #844B1B", "u+ c #7C4018", "v+ c #D49A68", "w+ c #7C4B1C", "x+ c #742E04", "y+ c #CC8157", "z+ c #745A44", "A+ c #B46644", "B+ c #643614", "C+ c #C4A65C", "D+ c #843A04", "E+ c #6C2E14", ". + @ # @ $ % & * = - ; > , ' . ) ! ~ { ] ^ ] / ( ' , _ : < [ } [ | 1 2 3 4 5 ! 6 7 8 ' 8 9 0 a b c d | [ 0 % e 8 f 5 ~ g h i % & % 5 a ' 8 ' a < j k l m { n o . ! 6 . 0 % p p q g r s 0 @ 0 . ", "j + $ # @ t g s u > u c { v @ ! w ' ~ x y y m u . ) z r > f 5 A [ B 3 2 B C 6 @ D E E 8 F i 6 0 g G 0 o H , j d I I [ & % i f [ . @ . 6 J K 2 3 L $ . M o N # j D ' O % [ 0 p P L g & l 0 0 . % ", "4 Q 5 % j $ @ g u / G t M k ' R 9 9 J A . M p 3 . O ! M { L 3 4 [ Q S T B Q 6 ' 6 6 J a a 9 9 a c & 0 ~ ~ z 0 L 5 8 5 [ [ d 8 & M . x i B 3 U V 3 4 . l & N m W 6 6 8 % [ g 8 5 q % & o j [ [ 0 ", "3 X h [ 0 0 0 0 ~ n j p 0 z Y 7 T Z ` Y ! ' Q .a ..! . , t +.@.#.[ C S S 9 [ . D a J a z J 8 % , o + 8 8 [ @ ' J 9 Q 6 5 5 [ x P [ 4 $.1 %.&.V S p ~ o b *.; c 9 6 5 % [ [ 5 p p b & o 0 $ [ 6 ", "=.-.;.9 a . j j . 0 [ @ z . Y O >.h ,.'.).! !.~.P D {.! ].& ^.T & & s % 4 [ A . 4 /.` Z (.d Q , H #.8 E 8 [ [ [ a 9 /.% z 0 . ~ _.1 :.T S C S | < <.M 0 | 2 T >.Q Q | [ 5 [ p 0 0 % # s j % 5 !.", "[.}.~.!.' 0 @ @ . 6 O 0 ~ a D Y P K |.... . K 1.8 D {.! 2.y b Q o x % % a 6 . A ,.` 3.1.1.4.i ~ & 5 i d 8 J 9 [ A J |.D a D a a 5.3 .;.h 8 a I 6.f $ g 7.}.1.$.T T T +.Q 0 g 0 % % 0 0 0 % 5 h ", "_.8.;.E 6 ' ' @ ' O 8 ' @ . a ..+ D 9 9 0 o ~ p 6 ' ! . , n 0 . 0 o [ A a |.a 6 ` 3.Z (.>.$.I 0 #.e h d !.J I C a D E F F 7 |.D 9.>.>.Z 0.9 a 8 a.b.Q [ =.;.!.K 2 T 7.S 5 #.[ 0 g [ g g % g J Q ", "c.-.;.8 D ) @ w . ' w [ a ~ ~ Y O O 9 S c d.e.d.f.A . H g.# @ h.$ ~ [ % z |.. 6 /.Z ` i.Z d [ o %.j.S P 4 % Q p E 8 O 7 F Z E /.O k.a a 9 & #.l.m.n.B C j.T 5 ) :.:.2 q p % [ [ [ [ [ [ [ 4 p Q ", "o.F i I 9 [ 0 0 ' 6 8 6 # n o 0 @ ) L W d.].0 [ + @ M k m ; $ @ $ 0 j 0 0 0 0 a c g G p.q f p s ' 0 d !.Q h & M Y '.7 E 7 7 7 R [ @ ) |.[ 4 3 b.q.b.2 L % g P r.j.I 6 a a 6 + [ [ p [ [ g & & I ", "I d d E 0 ~ 0 6 ' O E 8 j n m . ( j # N 2.@ O !.@ @ ! M r # # M # m n , & r % s m r & o p I [ [ $ @ 7.Q P Q o j f.. O 8 F 7 O ..6 ' ' ..a a q 2 _.s.;.j.F o.o.j.I 5 p O 8 O @ M [ 0 0 g 0 o ~ L ", "[ 9 F 9 z t.. O ' ) O w r n , ~ A % u.n o w |.|.a ' D ' o o n ~ j l , N n r G _ u 0 #.a |.[ 0 # n r | 9 P 8 0 [ l o o % g [ D 6 7 O ..Y a A 4 p C #.s ' O 6 D a g % 0 a [ 6 [ 0 @ , k o o n o c ", "[ [ [ ' a . a |.8 O Y 0 o ~ . v./.r.S #.z . D D 5 6 ..! s & o ~ # o m r u _ w.x.y.p.[ J 6 % y z.] n p g a 6 @ [ # m y { m ~ @ @ 9 |.D ' A ~ % [ A.G x ~ ' ! 0 z 0 0 0 % . 0 [ [ [ o o $ M # 0 o ", "g s ~ 0 0 a ' ' O ' ~ B.{ o ' C./.$.;.B ' A R ` Z ,...A . o & ~ y m N N ] : : D.E.F.G.g.G _ H.I.y N s % 0 a z M r u m & o o m m & & ~ ~ l j 0 <.t s G j $ 0 # j % [ 8 [ 0 % . ~ @ o o 0 r j # y ", "o o l s o & , x 0 J.B.e.K., . L.a >.M.d 6 ! E 3.M.o...! . & n r 2.y n { > : : F.I.I.N.: y.F.O.P.n o a ' D 6 ' 0 $ c % o & o o m & G # j # r c [ q p L I I L <.p . ' [ 0 o % 0 % o k o o o o o , ", "k n o o & { / Q., l ~ , { m ! R.D !.h 6 . . ) P 7.i ..w M m { n m n N z.z.z.y.= y.z.I.S.w.I.x.g.o ' 6 Y R O 8 [ [ a [ a z o r # s j j j @ 0 . 0 ~ . 0 0 0 0 0 o ! . o H o [ [ a g 6 [ s 0 g g g ", "@ o o r c u > T.U.H # n ] n J.).D 6 0 k ( M ~ & +.[ D w l y / g.{ { { { N z.] > y z.w.w.V.W.X.& ~ 6 Y R Y ! ' 0 ~ a E 7 9 0 m n o k k k . ' D } D D A z z ' [ A 6 ' 0 0 p L [ x a I [ & & & s g ", "I E D ! 0 s z.F.T.H.o o h.d., c j m / Y.Z.`.n t ' ' $ , y y N m m y y ] { z.n N n { ; > H.r / z.~ p E O D 6 ' . @ 5 i d F 5 g r [ j o 0 g % 0 [ ' 6 5 p I 4.4.o.o.d e U +c.6..+[ i j d.# m { p ", "0 5 i O a g.Q.F.T.^ N o & ].n @ # m { b p.Q.N c ! a M , / { m m W m N z.z.n N y n { ; z.] u ] r 0 + 8 ..a D w @ @ ' 8 d T r.g r @ 0 g [ <.[ [ p 5 5 [ p Q Q 5 z 6 p :.b.V _.l.p s 5 0 m @ # { G ", "H ~ [ a & H g._ > Z.: ] z.] , o . o ~ f Q H H j . . x y d., 2.o y N z.z.z.N n & { { ; z.> u { s 0 a D 6 v.a ' w Y O >. .&.2 q $ g 0 [ 5 5 [ [ [ 0 [ | 7.>.Q 9 h !.P ++2 5.=.4 @ C | Q P Q 5 0 k ", "H , s % @+#.#+#+#.z.$+N.: Z.H k 0 a a E 9 & x ~ z k x , , l M k y ] > ^ > G.n m { N u ] ^ { y s k . a |.6 ! ' + {.|.%+&+*+V p l [ $ @ [ $ 0 0 p % S 7.$.B C Q T ;.3 T 2 @.%+a @ +.T $.>.K 9 [ k ", "n & q B +.+.S p :.#+y.Y.w.H.{ , J.a a /.a z a o x k , o ~ . . f.# n ] : Z.: > { o n u > ^ { n o ~ J.a 9 6 0 . @ =+O T 8.8.1 [ 0 $ 0 s j % % g 0 +.Q S !.B h h f ~.4 t %.3 3 4 6 r.T X $.i.J a k ", "~ % B e ^.%.e T 3 q * -+_ u H / x a a a A 0 [ & , { , n l M f.. . o z.> : : ] H o n N F.z.n o J.~ a [ [ 0 % M M w |.Z }.-.T L O j ~ o 0 $ [ [ % p 5 9 K i j.j.| 4.% G p 1 S B r.| T X Z K a [ . ", "' % +.l.* ;+2 2 ;+%.q s b b u x.x % 0 . 0 M j n N z.y n o o f.! ).. & z.F.> z.n n n z.H.z.n 0 . a [ [ b & r g j @ 0 [ >.` K a ' 0 r o % [ 5 5 g $ p 8 9 a ~ o # D @ o #+T @.>+1 K 5 5 [ % ~ z J ", "E a +.1 ;+;+6.A.* %.+.@+% p #+= #.g 0 0 M , r y u N N n o k . {.R.v.0 u G.F.{ z.,+y > H.H.G ' ' @ [ g n z.# $ <.<.0 a |.E a A 0 <.0 x o g L 8 [ <.% 0 8 8 @ k m B.M o g V 1 '+)+h Q @ j M 0 J o.", "_..+^.!+6.l.l.l.~+;+6.V {+:.:.A.r.e q G F.N.]+]+^+I.^ K.d.' 6 z @ M % a /+{ y.H.(+T.^ u ,+2.a ' [ <.t y.x.y.b t L $ @ ' [ 0 # g j j r % [ I p g [ 0 O Y ) w 2.y l j $ @ 5 I P i I <.0 0 0 0 5 e ", ":.%.< :.1 {+l.3 ~+;+_+6.l.!+s.5.3 T q g.> > :+<+:+: H.y ].. ) A + ' 6 9 [ G z.> P.[+^ N { d.0 . . @ s g.z.n 0 @ j o o 0 @ M r # $ j o #.[ <.g #.j . 6 . . 0 , y j l k , g 8 p 5 [ g a z % a 5 i ", "A.%.%.+.l.C #+%.{+~+{+{+5.}+n.}+3 6.#.H { z.> T.<+Z.n o , ~ ! a w ' D 9 !.[ n ] O.<+N.= ] y o l M . o o & s 0 . n n o 0 $ j r # $ j s 0 #.s s # g [ 9 0 z 5 g #+2.o , ,+d.H & 0 s % a a a [ J 5 ", "b S %.C +.^.9.A.5.{+~+^.|+1+*+n.c.1 #.H x o H ,+> { n s x k . . . ! A A O a v y I.[+N.N H.y m 2.h.l l & o r ~ o & m r g g s o G j g b G G r r & r #.[ % 4 | S q o 5 <.~ , d.o $ z a 6 a a /.4 a ", "#.3 +.%.r.+.2+b 5.5.3+;+5.c.n.n.8.T #.~ 0 z x & % & & o x M . z ! D A A D o d.d.: T.: H.z.] y ] 2.m n n z.N N n m G r # r r m r n g c g.{ G j o H r [ #.9 7.e q [ | [ $ g o o o % a [ J [ [ a a ", "C p %.C {+l.;+;+{+4+3+;+l.%+2 .2 Q @+z J 6 K Q [ M & & , s 0 l ~ ' a ' ' o , n F.F.> H.m N N m N N u y.z.H.z.N n n n n z.n G o , s r G.F.r # & o & [ g L j.Q p o 5 0 [ 0 , o x M . s g % % % a ", "C A.#+A.A.;+5.1 ~+5.{+;+^.S +.Q #.g ~ x 6 h $.=.. [ [ r g.o # , , H o 0 j o m N = N { N u u m r N N N n _ u = = & u u _ N _ n r & & n z.z.n o # x x j o o $ o r ].L + [ 0 d.g g 0 n , n u n % p ", "q p.2+A.* ;+5+1+6+a.< A.#+#+~ g v ' . h.a $. .7+. + I #.{ { m / H e.{ k d.y N ] N N ] / n n y m N { { { G G u _ r b r u = u G r ~ g.{ u y.z.n @ 0 0 0 o 2.y ].m , + , o s , 0 & @ , { N , y o 5 ", "k @ j j . H & 6.a.6+a.6+;+s ~ [ 2.j C C !.j.b.8+[ K j.l r H.N.P.= z.K.N Z.; N > r z.H.N ] r t o u u n n u u u V.<.G I p ;.g g u = V.H.u { # o g $ g G z.z.m m , N = = ] # y m # W <.o ~ ; t r t ", ". + $ [ ' ~ & .+l.;+l.2+9+#.~ a n q 1 2 T &.1+q.C [ % { y T.^ I.> z./ o e.r n z.# u N N { u # l u u m r r r p.u s % [ J I 5 r { z.u > u { r r 0 j ~ b g t #.o d.H.y N K.y { o r n g k o g.N { j ", "D 9 + + O ' % b S 0+@.9+C C 4 z A.}+a+b+V &._.7+e p { { { c+F.<+Z.N n $ y 0 ~ % j $ r y n # ~ 0 u m n G r s G n & $ % 5 4 j.t n F.G.] g.{ r n 0 d.n p $.X I # 2.y n u y g 0 0 , 2.' . % & { e.. ", "..|.6 a D D a j S @.2 3+1 5.S #.S [.d+U l.T +.B e b X.g.> D.F.N.x.z.r 6 M D ' |.0 [ o , r j ~ $ r n g.& & r r & s p % P % j.<.p.> z.z._ / n n o y & S ~.~.Q j m / H H v 5 I |.x M ' A /.5 s x a ", "C./.9 9 D v.' . %.7+a+c.d+c.2 q !.1 3+2 #+9 % S u.Z.G.y.e+x.z.f+> { & [ . ....... 0 , v % . ~ ' [ b & n & s ~ s t #.& G & b _ g.z._ z.g./ g.{ H m g Q X >.s { y 5 L p , [ a [ x . ! A |.4.Q z {.", "..g+d 0.7 ..' z %.c.U }+h+5+s.l.$.%+3 h ' ' z g G.$+-+_ Y.* f+r._ H & w D O ..D A z ~ o j % 0 a I [ s G r s b s G x.H X.G X.G.z.G.= G.z.x.z.> > z.u #.C b H > N <.| d % % h.~ ~ . } v./.~.d D v.", "..|.d ;.F ..D . C T _.c.[.B $.P }+ .%+K z ' s _ z.i+-+i+_ 2+;+e t r z [ 6 |.|.A 6 a D [ 0 ~ 0 [ E [ s g.G G r u > : z._ p.G.F.P.Y.F.F.F.: y.> Z.Z.> g.n g.> ] > U.,+o , [ ~ a ! f.{...J 3.| D ! ", "v.J.p h /.A A J.i.B B @.=.i.(.j+a.c.@.k+t.~ A.l+F..+e+m+W.f+;+:.P s % ' D a a z ..D 8 I ~ & 0 a /.@+x z.z.= y.z.x.y.p.A.b y.I.N.: Y.N.: : y.F.N.x.F.N y ] ] : T.r n n , 5 5 [ ' M ! /.k+B 4 . n+", "] u 6 R ! A z g.I #.=.%+l.%+J a B T p [ & C k+g.u ; g.e+o+p+ +3 {+q #.[ 6 . o g [ H [ n { > N j D 6 a & { : I.w._ _ !+_.+.9.Y.N.]+S.I.F.Z.u n n u u - H.Z.N # y I l o u j j m l l l + $ K.] u : ", "z.m @ ' f.~ ~ g.& & :.1 @.S % a %.+.C % @+[ u.& u b _ m+~+)+_+^.#+#.% @ [ . & c s d.g.> ] { z.N ~ z s u G.x.O.F.G -+c.&.1 ^.y.I.]+S.N.G.> n n N ] = ; W Z.] u n @ n o m n m , $ l 2.j k e.{ N Z.", "n , j . k o n > { G e T 3 C H a P 0+J % [ [ % & n G _ f+|+4+2+f+p 4 % a ' ~ , s & % { { F.N z.z., n & n z.z.F.y.s 9+b.U c.@._ O.S.I.N.G.H.n { { N ] H.= H.y m y , , s j g j & . j M . M & [ 5 r ", "n o j . o y z.T.,+_ r.:.:.#.,+a 3 K !.4 8 a % x u G u.A._+|+9+#.4 #.z a [ ~ x % G f u u > ^ z.N N u u g.z.z.g.G p 3 8+q+*+V p.] w.I.T.z.G.z.{ { u ] Z.> z.= r #.~ ].r g <.<.~ o ~ x k z A O i a ", "& o j @ , N ] : K.{ p.#+p #.H g Q P Q a 6 ~ ~ H _ g.& _ p.-+p.#+% % @+0 0 % & #.& | G y.Z.> H.y.> z.u u g.g.G b i 2 r+s+8.7+#+r -+F.T.F.> g.{ g.> ] = u y.g.t t++ & & , r g j 0 o ~ z z z J D z ", "0 o o o n & _ G.x.> { _ G g.H & #.s % s z H H & W.u.g.X.G.e+g.A.i.3 p % % 0 ~ z ~ #.g.> > y.u n Z.> u G r r s #.S 2 +}+n.3 C c u z.Z.> > g.{ & > N y.u p.u #.| g ~ r n H & & 0 r b g a a 6 ' a ", "g o x o @+p +.@+= G.> { ,+{ g.{ g.g., o H v H #.6.1 %.u.-+i+2+l.:.u+!+#.s g M x % & G g.g.G ; u { z.{ n s % g 0 S 2 %.l.Q @+r G G u { G.> _ n G N u > > u p.u.g & G ; r u r u s F.= n & 0 . a a ", "g o n % 9 $.>.0+z.> Z.Q.v+,+n ,+z.n n 0 , & u.I 8+&.1 A.* i+;++.5.&.++b r [ @ ~ % /+5 G g.g.n G c r { H & [ [ p 3 2 C t a ].{ u g.G z.z.: r _ & > u G.x.z._ b r.b n z.> N b G r P.- u n o ~ M 0 ", ";.P 9 ~ #.u+7.6.t u F.y.g.o k m . . a ~ I ~ j p ++s.w+;+{+< _ ;+7+l.2 _ 4 s ' M c c # & s g 0 k @ o u u r g 8 |.2 &.t+b P.w.y.r ; { z.H.; z.o s t ; z.: F.z.n ; # m r t #.c r & u H.; y o ~ ~ Q ", "h T x+K & | r.r.% & y.u s s z s a 9 p [ g & n <.l.>+&.b 2+%.p.f+V 1 3 #.% g % o m u n & & % $ [ p 0 r r n g 9 6 +.e Q u F.P.N r n n ; = u { r s ; r y.x.y.N u # u N o c s s G g.] Z.= ] % a J T ", "X S 3.j.9 K 4 Q A s s % % a 4 +.+.e Q r.G & d.g b 7.:.p.G p.b p.6.6.4 [ x % > z.z.{ { { y n o % $ j r u g.r [ a 3 Q 4 & _ y.n % p.n u g.; ; s H , n z.{ z.g.n o o , n s r & G H = F.= H 9 7 (.T ", "~.P S 3.0.i a K J.~ & & u.@+^.l.l.1 3 e #.G { & u.r.C #.p.H G c .+t % J y+u.T.y.G.g.F.] { r & H ~ o G , ,+& [ [ T K % G ; - & g #.#.s g.s #.s ,+y 2.{ H r b & r #.& o s r o & n z.] z.{ 9 /.,.(.", "S 1.M.,.|./.a a a u.n g.@++.c.8+V {+6.l.< G { / G +.p q #.{ r s u m % % x g.Y.l+X.#.#.u n g [ k+o ~ g & { & [ [ S a k+x p.G & 4 #.r.3 #.& & @+s r s & r 5 | Q p 9 #.s s o n G H H.F.z.n E ,.Z Z ", "4 ` ` |.A ~ z J P #.s r t e q+s+c.~+5.q l.g.g.K.{ % t % s b 4 s r , 0 n H : : w./+r.7.+.; #.[ . s [ I [ & G p 4 S 4 k+n G u g.% 3 t+T Q u.#.#.t C p g % | 4.7.T >.C s r n N n z.F.z.z.G 7 ..Z >.", "J a J.D |.J.~ E 4 C #.o z +.d+r+!+;+%.%.p.g.g.Q.K.X.r G s +.Q %.a o b > : T.T.: ~ Q u+=.P @+~ f.s [ i <.& & @+r | !.[ s G u & @+2 s.:.B #.p #+t 3 !.C a S h B :.$.P G n ] z.N F.Z.x.^ { [ } ..a ", "D R D D O a 6 h (.h i ' a 4 5.z+6.%.A..+G.z.g.u z.K.G #.%.r.r.T 6 ~ n Z.N.F.> { . [ >.X T J . f.H g 8 #.y+H g.H 3 i 9 % ; p.b [ 6.s.=.T #.#.#+l.=.X 3 4 [ +.Q 3 $.C g.{ ^ ^ H.F.x.F.: 2.8 v.R [ ", "E a D 8 8 6 5 I 5+5+!+B [ ~ C 5+#+* L u.#.s p #.0 [ #.3 +.1 1 =.p u.r Z./ n G H % 5 B 2 T L 0 ! $ l W m { n s o p.b g G ~ #.P +.l.w+w+f .+G r L 1+s.f K [ 6 9 o a P g & m m g.z.u m { , 0 O D ..", "R |.O E 8 ' [ [ ++!+1 Q ..a [ {+G -+r.#+4 #+p g 8 5 C e 1 2 2 =.q r #.Q.{ r #.z.% p q L +.#.~ . j 2.m 2.{ { n l b p.n H g 5 +.#.b T j.+.% 0 0 @ 2 T S 5 [ 6 I 4 a 6 0 x & r n g.m u m G @ [ a |.", "D D O O D 0 z ~ Q S K /...D % & _ f+f +.p #.p +.| +.C 2 2 2 5.2 p s g e.{ # c H & % #.b t #.4 ` K % m o g.H g.# p.s s % #.p S S K S J 4 x a [ D r.r.q [ % a i 5 a 6 0 o g [ #.#.o # 0 0 0 z . 6 ", "A ..J D J J z ~ J P J a A ! z g.2+A.e P % @+C r.T l.A.7+2 7++.:.p G g / , n & H /+& u ] / Q.@+1.9 ~ ,+g.G z.,+y & p.#.g g 4 9 T 1.P @+/.~ 4 D 9 +.r.P [ o ~ I 8 a [ a 0 [ 5 P [ 0 g 0 g z , , [ ", "v.O D 4 (.` /.a [ S 3 J . a #.A.l.C Q 5 k+s A.:.=.3 ^.s._.2 3 r.I ~ 0 m o , o s +.B e t z.Q.u.$.1.[ & <.j.r.G # s g.g.r #.[ P !.2 %.#.B C S P 4 P 9 p [ , & 5 8 [ p [ 0 [ [ a a ~ ' [ @ ~ v x 0 ", "v./.D P Z h K 7 P r.T p s ~ q :.6.#+C 9 z C C :._.1 l.s.2 :.q !.Q ~ [ o k , ~ [ C B e L g.`.v+G @+H / #.t+Q & , s & n o r s [ d !+!+1 < 3 7.j.C [ /.[ g H , [ I S I p [ [ % z z % [ 0 z ~ k k 0 ", "! |.P S X B J ` /.K S C z & q _.:.#+% |.4 Q +.V T 7+1 2 3 S [ 5 9 [ Q ~ H v % [ +.r.3 r.+._ : z.g.n y u I p ~ ' g o o r n , a d 2 s.2 b 3 T ;.C D J [ g H H [ 9 T T f [ g . % [ [ 5 ' o . 0 . . ", "' E !.T u+S 4 h g+/.K J z z S . .C & D a >.S 7+%+2 1 2 +.p [ 5 i (.4.~ v x [ 0 +.C 9.+.3 b H.H.,+N ] / G x x 8 8 l Z./ m o ~ 6 :.T T 9.$.+.K A+/.|.[ g , ,+g 5 2 2 +.g % o 0 8 I | [ k % ) A k ", "O O 8 Z h K p p <.+.r.B Q q :.&.&+S @+#.9 B S {+I f r.T 2 l.l.e ;.q 9 x x k ~ 9 q.B+1 0+S C s / 2.N ^ C+O.; [ v.Y 0 M ,+m n [ ' I I 5 % 4 t r r [ [ 0 0 , n { ; R O @ p.; #.p 9 7.Q #.% a O O z ", "i 9 9 i !.L S r.< 3 >.:.Q +.:. .}+3 4 4 6 Q Q +.$ Q L 3 1 :.r.e | p 5 ~ 0 s [ 5 5.s.c.^.0+r.p n H m u H.z.j @ J.+ [ t r r n o k [ i S 4 #.s r # j 0 o 0 , o n n . ' <.p p r.!.Q Q P [ 4 % [ !.9 ", "2 B P J 9 S :.c._.2 =.%+P #.4 @.T >.P 4 J 5 P %.[ % C 3 2 B l.T 9 [ [ . 6 z [ #._.>+'+c.{+_.Q #.,+# j m N r o , e./ ] u = n n s [ 3.3.P u.g.n N o c o 0 ~ g n { , 0 [ a [ B $.2 d Q Q Q C C B T ", "&.1 P [ 6 3 2 1+c.V %+3 4 @+P >.%+%+B J [ K 9 P a P +.B 2 :.%.%.a [ z . 9 % r.C i.@.>+ +|+2 >.6 r M j ~ x d.z.N > Z.T.z.^ > / n J ;.u+Q u.{ { N G 0 % 0 0 5 0 n m j . a ..!.T u+7.5 4 r.>.1 2 =.", "h+7++.J +.r.c.d+_.!+1 C #.o % S T =.>.S K Q Q J 4 7.X 1 1 2 C H ~ % x z 5 [ T B 0+3 V 1+4+l.B a <.0 z ' . , y r - N Z.= H.z./ z.& S | #.G n z.u N j o 0 o O [ [ N , % E ` !.S :.I % @+Q 2 _.n.n.", "n.7+3 3 r.B !+V b.++3 +.j o 0 S =.2 T B >.>.(.K $.T _.&._.A.& ~ b s % & g #.L q d 2 1 a+u+%.I % 6 M ~ w [ o , r n { > n u u N z.,+G s G g.y.z.z.n r r 0 . 8 8 I o d.& |.i J 4 S 6 g p B 1 2 n.a+", "=.=.7+V 6.1 1 r.l.{+S +.5 p r.;.c.7+7+2 T >.>.(. .1 +U _._ ,+6 l.C L s s & g.X.s #.#.C Q p g $ . J.. @ [ . ~ . 0 o o n n z.z.> > , n z.n z.> z.n r r [ 0 O 6 E + o , G & n % I [ [ !.T :.7+}+}+", "$.=._. +V 6.3 9 !+1 %+%+r.C S %+_.7+7+[.=.B (.T 1 n.h+5+|+p.o @ ++l.s.t #.& X.Q.N g.x y+k+0 ,+W A ' @ 0 0 + D ) O [ [ x 0 u ; u y N N u - z.F._ u r o [ ' ' . . E [ r N { y 0 R % 4 p r.B =. .7+", "2 s.7+1 &+1 .:._.1+1+2 1 %+7+1.5+2 X $.[.n._.3 >.Q i [ M g #.p 2 e :.l.f #.[ a g p #.% 0 % z . $ m 8 x |.v.' w *.$ # @ j l p f + , k s d f z.n u ; o # $ o l 2.m $ <.j x o [ L @ j % [ h $.P 1.", "1 2 2 %+ .S T :._._._.2 7+2 %+@.6.T %+X [.n. .T B K 8 6 [ 0 #.p 2 2 !+e T #+Q 9 t p g % [ ' a 5 r.<.I . /.a 6 w p #.~ M z ~ [ 9 $ r g.g f t n z., u m , c , # 2.2.l j s s [ <.[ $ j s % | >.K >.", "S T T T $.%.3 T c.c.2 _.}+=.1 +.+.S B }+n.h+s.1.!.Q 6 |.' o #.p 2 1 :.2 2 #.3 | r.p #.a 9 [ [ I &.2 <.' a A J [ d Q J z z z A+a g s { #.C _ b G.m & r { $ y g 0 j o o g <.[ s o $ & r & 4 L p S ", "p Q S >.>.C P | 2 2 V 2 2 2 3 C P 4 S 2 h+1+7+Z 3 ` |.D J.~ [ p 1 3 :.5+2 2++.T :.p @+[ 9 J [ f 8.>+t + . a 9 P 0.` F |.a D a D I #.& A.G _ *.n n s s n 0 , g @ t s s #.p g r o s & s o & g [ g ", "a [ J K S S 4 r.%+1 3 3 3 S %.C 9 a J %+&.2 S /.+.>.E D } z K S B 3 :._._.A.1 2 3 #.& a 9 9 C r.b+>+#.5 0 J Q B 0 a 8 a z . . a 4.P L #+f+b G g.x g x % & & , m 0 o s [ p #.t <.#.G $ s m % g p ", "5 P 4 P Q T +.Q S P P 4 4 #.p 9 B K D i T S J A+#.0+E D A ..4 q S S 3 2 s.%.7+2 1 +.@+a /.[ #.l.8.1+#.8 6 !.>.2 6 i D+| I F + 8 E #.L #.p.t n & & P & 5 o s H n o s % C p q q f @+#.g r r s b p ", "8 9 P J S M.+.S P [ % 4 [ 4 J Q j.Q ..'.|.D a j+l.u.9 D D E s +.J C p 3 2 3 2 %+2 >.K a a #.4 l.>+1 P O ,.Z r.w+S Q -.r.p L & . z a [ G G ; o j a i a Q 5 p o G M j $ p S r.3 %.t #.s m s b & S ", "9 i 4 4 0+u+%.%.' % . [ 6 |.9 Q w+(.7 L.=+A A ) >+p.J D |.` G T 4 % 4 +.2 1 [.1 3 :.!.a % 4 l.s.&.q 9 /.,.$.r.++T =.E+2 @.T #.% } F % G & { s @ P ` K I d p [ % l M g q | 2 r.A.+.t G n t #.u.B ", "t r.J @+P B 9 ' a [ J |.J p B ;.T Q [ D v.. . + ; l w . 4 T #+e t #+6.!+!+:.f P K S r.S 0 % S &+s.f P Q ` Q 5 Q <.+ | <.0 5 7.l.P I 8 ' . @ 0 % a Q i i ` [ % I 6 & P #.| >+3 S !+p q c b - C C ", "t r.P A+q p % A % [ [ 9 6 P S =.T Q a D A M k m m 2.@ f.P T #+q 4 [ r.T 3 S P [ K S S #.% 4 B }+e L +.Q ` 9 P 6 # l j k o g t+| P !.8 D ' 6 J [ [ 8 9 5 5 5 6 I i 0 g r q u+r.@.6.p p 0 b & #.a ", "#+q J 4 P #+% a [ J O 8 9 !.>.2 ` 9 /...! k ].].y / M M 5 T #.[ z |.K =.C K A+z P S +.4 [ !.>.7+3 3 | ` ` 8 6 a j o l l 0 s p C 9 ` 7 ,.|.8 9 |.K 9 5 a @+6 i 9 i @ j o t j.:.e ++S 9 P p g [ A ", "q C J P p % % |.' [ 6 9 !.| >.T ,.9 |.|.' . k 2.N 2.k k P T 4 g z J p ;.C B 4 A+[ 5 +.P 8 ` >.V T T h (.8 |.D z y 2.o k $ o g I ,.` 7 ,.9 g+9 |.|.[ [ a z [ i 9 I [ [ 0 L T r.:.1 +.S Q +.q P A+", ":.+.J P #.g.% a a a [ P 9 Q !.S |./.|.|.D z M ~ r o h.k [ Q C [ s p #+s.3 s.3 +.5 #.4 9 O 6 3 7+[.T Q |.6 a A A #.o 2.B., d.~ L ,.,.,.K /.K g+/.8 a 6 9 4 4 Q Q Q 9 d h h T 1 V 5+6.1 2 _._.++3 ", ":.C A+4 s & ~ a a p P P K K 9 |.,.,.,.|.D a ' a [ @ f.k #.C [ [ s #+%.b.c.h+_.:.| C 4 6 J a !.&.X T K 5 6 a [ 9 f p [ ~ k y+o a 9 K K K K 9 9 |.6 a |.i 9 [ 9 | Z $.0.0.Z >.%+s.b.++e &.h+U h+_.", "1 #.k+#.s r #.z Q Q B r.K 9 O ..8 !.E 9 O |.Y Y a O . . b b b g #.#+l._.d+&.&.2 | 9 4 J ..D B &.$.B I i 5 g p T Q 4 8 [ 8 [ I [ 9 K 9 Q Q Q 9 [ ' [ [ 6 9 S Q h h !.(.` h >.=.s.++l.+.s.c.U 8+c.", "_.4 @+[ s b a x S T :.S P 6 D v.J K |.|.|...g+'.A O v.. #._ G r a C B }+[.}+ .7+I +.p D D |.3 V B S I d 5 G 4 2 7.C 5 a a ' i % 8 9 Q :.| I p ' . 6 A ~ P I Q B p 6 [ E F d t+w+t+h K .1+b+*+}+", "r.q S f q r z.- !.i Q L g ' ! ).O A O z [ 4.+ ' #.I z ..a K r.#+| T 2 i.[ i [ L h i 7 J I f | Q ` 5 + 0 @ c b f e $ c m j H r #.Q I f [ Q Q 0+T r.q t % [ 6 |...p t m y r L T ;.t+:.r.p u+&.h+q.", "< A.b p g u _ - #.p 5 6 0 . . ! 6 |.d 6 % 6 . O 5 d 9 9 J Q Q q [ S %+C P E [ f T P 9 9 h p +.S 6 6 5 j j j & g o , j $ I g G v #+#.f 5 [ #.g u+f p n r @ [ a a g 0 r o c [ Q T 7.T K a Q | e 6.", "#+G g._ p.u N u f+#.p 6 A . . @ @ [ g % % a A A [ K Q r.r.;.p @+~ C r.S K 8 9 B u+Q ,.` ;.l.I h 8 6 6 2.v # o s . z 0 o o & p | f G & s s s G [ r # 2.<.l l , 0 & n o j c #.p h $.3.` /.a 4 a C ", "f+g.z.n u u y.z.u r a v.A M o # o o , & a . a } z x G p.< u+4 t.~ p r.S 9 ,.Q T ;.P /.8 7.q +.B 8 ' ' , ,+o z g D 8 E 0 x o 5 T D+u.,+].o 0 l { ,+0 @ I k o n p g & o g j ~ #.5 3 1.h F /.J x ~ ", "n u G G u n z.] y.n o . f.k 2.m o j s 0 a % ....a x x.x.G.f % j+0 Q r.S 9 6 9 h T P /.J Q q Q K ' J.[ [ o ~ . ' ,.,.|.6 a 6 4 z r.[ % 0 o l $ n s 5 0 8 o I Q e d [ #.g o n & ~ 2+Q q h p [ & o ", "& r b c u n N n N , x M ~ k 2.m j M ~ s [ ` 8 |.z % & z.Z.% z /.0 I S S /.z a Q B 9 g+a Q 5 B K D z I I g #.5 F d (.a [ % [ a a #.Q I 5 z o j y & p [ 6 ~ !.B T j.[ 0 g x & ~ , g.p.G #.g c o j ", "~ @ j r m G o o m m # j 2.d.2.@ @ 2.& v % 7.6 ~ x + 0 s v & a a a Q +.P J ~ ' g J J '.A 6 % [ z 9 [ h T #.P F 4.K S 9 d 6 J % D C Q % 0 [ M & { / & 0 0 ~ 0 [ +.9 @+[ g x o $ o r & G g.#.o o c ", ". @ j n , r 0 0 x l # # y K.].. M ~ <.y+H 5 & x 2.0 ].x ].z O ' a B P S O ~ . g 5 ..R ..O % a A z 4 u+7.A.+.` E :.p u.9 P 8 A+a 9 9 v ~ [ s % % N ] B.B.k z g g 4 s J [ & M [ o + 0 0 & 0 & l @ "}; nethack-3.6.0/win/macosx/NetHackGuidebook.applescript0000664000076400007660000000061612623253702021647 0ustar paxedpaxed#!/usr/bin/osascript # NetHack 3.6.0 NetHackGuidebook.applescript $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2011 # NetHack may be freely redistributed. See license for details. # Display the Guidebook from the GUI. tell application "Finder" open location "file:///Library/Nethack/doc/NetHackGuidebook.pdf" delay 5 end tell nethack-3.6.0/win/macosx/NetHackRecover.applescript0000664000076400007660000000173012623253702021342 0ustar paxedpaxed#!/usr/bin/osascript # NetHack 3.6 NetHackRecover.applescript $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009 # NetHack may be freely redistributed. See license for details. set canceled to false try display dialog "Welcome to the NetHack recover program. Please make sure NetHack is not running before continuing. Ready?" with title "NetHackRecover" on error number -128 set canceled to true end try if not canceled then set hpath to the path to me set mpath to the POSIX path of hpath considering case --set lastpos to offset of "/nethackdir" in mpath --set lastpos to lastpos + (length of "/nethackdir") --set rawpath to (get text 1 through lastpos of mpath) & "/recover.pl" --set safepath to the quoted form of rawpath set safepath to the quoted form of "/Library/Nethack/nethackdir/recover.pl" end considering do shell script safepath display dialog result with title "NetHackRecover Output" end if nethack-3.6.0/win/macosx/NetHackTerm.applescript0000664000076400007660000000704412623253702020650 0ustar paxedpaxed#!/usr/bin/osascript # NetHack 3.6.0 NetHackTerm.applescript $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2011 # NetHack may be freely redistributed. See license for details. # Run the terminal port from the GUI. # BUGS: # We close any terminal windows with no processes in them, even if they # don't belong to us because we can't really tell which ones do belong to us. # Shouldn't be serious since anyone using this is unlikely to be using Terminal # for anything else. set debug to false set needshutdown to false tell application "Terminal" # see if we're going to have to shut it down at the end because we started it up if it is not running then set needshutdown to true end if activate #open new window and run NetHack in it do script with command "clear;sleep 1;/usr/local/bin/nethack;echo '(press RETURN to exit)';awk '{exit}';exit" set nhresult to result -- class is tab set nhresrec to result as record set nhreslist to result as list set nhwin to item 4 of nhreslist set custom title of nhwin to "NH" #set title displays custom title of nhresult to true set title displays device name of nhresult to false set title displays shell path of nhresult to false set title displays window size of nhresult to false set title displays file name of nhresult to false #set idnum to id of nhresult set xxx to class of nhresrec get class of nhresrec -- record get length of nhresrec -- 4 set nhwinname to name of nhwin set nhtab to selected tab of nhwin get processes of nhtab # main loop - wait for all nethack processes to exit set hit to true set nhname to "nethack" as text delay 4 repeat while hit set hit to false delay 0.5 # don't blow up if the window has gone away try set procs to get processes of nhtab on error number -1728 exit repeat end try repeat with pname in procs if debug then display alert "PNAME=" & pname & "=" & nhname & "=" end if # XXX this test is odd, but more obvious tests fail if pname starts with nhname then #display alert "HIT" -- dangerous - infinite loop set hit to true end if # yes, this is scary. if pname starts with ("awk" as text) then set hit to true end if end repeat end repeat if debug then display alert "DONE" end if # window may have already closed or dropped its last process (error -1728) try close window nhwinname on error errText number errNum if errNum = -1728 then if debug then display alert "close failed (expected)" end if else -- unexpected error - show it display alert "close failed: " & errText & " errnum=" & errNum end if end try end tell # Close all the windows that don't have any live processes in them. tell application "Terminal" set wc to count windows set pending to {} if debug then display alert "COUNT is " & wc end if repeat with win in windows if debug then display alert "WIN: " & (name of win) & " TABS: " & (count of tabs of win) & " PROCS: " & (count of processes of item 1 of tabs of win) end if set pcount to count of processes of item 1 of tabs of win if pcount is 0 then copy win to the end of pending set wc to wc - 1 end if end repeat end tell if debug then display alert "LATE COUNT is " & wc end if repeat with win in pending try close win end try end repeat # If we started Terminal.app and the user doesn't have anything else running, # shut it down. if needshutdown and (wc is 0) then if debug then display alert "trying shutdown" end if tell application "Terminal" quit end tell end if nethack-3.6.0/win/macosx/recover.pl0000775000076400007660000000233712623253702016240 0ustar paxedpaxed#!/usr/bin/perl # NetHack 3.6 recover.pl $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009 # NetHack may be freely redistributed. See license for details. # Wrapper for 3.4.3 recover to be called from Applescript to reset the Qt # package after it locks up due to a bug in suspend handling. # find the right place ($playground = $0) =~ s!/recover.pl$!!; if(! -d $playground){ print "Cannot find playground $playground."; exit 0 } if(! -f "$playground/castle.lev" && ! -f "$playground/nhdat"){ print "Failed to find playground $playground."; exit 0 } print "Playground is $playground.\n"; chdir $playground or do { print "Can't get to playground.\n"; exit 0 }; if(-e 'perm_lock'){ print "Attempting to remove perm_lock.\n"; $try_perm = 1; unlink 'perm_lock'; } else { print "Did not find perm_lock (this is OK).\n"; } if(-e 'perm_lock'){ print "Failed to remove perm_lock: $!\n"; exit 0 } if($try_perm){ print "Removed perm_lock.\n"; } # run recover, but only if there is something that looks promising $recover = "./recover"; $recover = "/usr/local/bin/recover" unless(-e $recover); $uid = $<; foreach ( <$uid*.0> ){ system ("$recover -d . $_"); } print "Done.\n"; exit 0 nethack-3.6.0/win/share/gifread.c0000664000076400007660000004530712536476415015627 0ustar paxedpaxed/* GIF reading routines based on those in pbmplus:ppm/giftoppm.c, bearing * following copyright notice: */ /* +-------------------------------------------------------------------+ */ /* | Copyright 1990, David Koblas. | */ /* | Permission to use, copy, modify, and distribute this software | */ /* | and its documentation for any purpose and without fee is hereby | */ /* | granted, provided that the above copyright notice appear in all | */ /* | copies and that both that copyright notice and this permission | */ /* | notice appear in supporting documentation. This software is | */ /* | provided "as is" without express or implied warranty. | */ /* +-------------------------------------------------------------------+ */ /* * $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ */ #include "config.h" #include "tile.h" #ifndef MONITOR_HEAP extern long *FDECL(alloc, (unsigned int)); #endif #define PPM_ASSIGN(p, red, grn, blu) \ do { \ (p).r = (red); \ (p).g = (grn); \ (p).b = (blu); \ } while (0) #define MAX_LWZ_BITS 12 #define INTERLACE 0x40 #define LOCALCOLORMAP 0x80 #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define ReadOK(file, buffer, len) \ (fread((genericptr_t) buffer, (int) len, 1, file) != 0) #define LM_to_uint(a, b) (((b) << 8) | (a)) struct gifscreen { int Width; int Height; int Colors; int ColorResolution; int Background; int AspectRatio; int Interlace; } GifScreen; struct { int transparent; int delayTime; int inputFlag; int disposal; } Gif89 = { -1, -1, -1, 0 }; int ZeroDataBlock = FALSE; static FILE *gif_file; static int tiles_across, tiles_down, curr_tiles_across, curr_tiles_down; static pixel **image; static unsigned char input_code_size; static int FDECL(GetDataBlock, (FILE * fd, unsigned char *buf)); static void FDECL(DoExtension, (FILE * fd, int label)); static boolean FDECL(ReadColorMap, (FILE * fd, int number)); static void FDECL(read_header, (FILE * fd)); static int FDECL(GetCode, (FILE * fd, int code_size, int flag)); static int FDECL(LWZReadByte, (FILE * fd, int flag, int input_code_size)); static void FDECL(ReadInterleavedImage, (FILE * fd, int len, int height)); static void FDECL(ReadTileStrip, (FILE * fd, int len)); /* These should be in gif.h, but there isn't one. */ boolean FDECL(fopen_gif_file, (const char *, const char *)); boolean FDECL(read_gif_tile, (pixel(*) [TILE_X])); int NDECL(fclose_gif_file); static int GetDataBlock(fd, buf) FILE *fd; unsigned char *buf; { unsigned char count; if (!ReadOK(fd, &count, 1)) { Fprintf(stderr, "error in getting DataBlock size\n"); return -1; } ZeroDataBlock = (count == 0); if ((count != 0) && (!ReadOK(fd, buf, count))) { Fprintf(stderr, "error in reading DataBlock\n"); return -1; } return count; } static void DoExtension(fd, label) FILE *fd; int label; { static char buf[256]; char *str; switch (label) { case 0x01: /* Plain Text Extension */ str = "Plain Text Extension"; #ifdef notdef if (GetDataBlock(fd, (unsigned char *) buf) == 0) ; lpos = LM_to_uint(buf[0], buf[1]); tpos = LM_to_uint(buf[2], buf[3]); width = LM_to_uint(buf[4], buf[5]); height = LM_to_uint(buf[6], buf[7]); cellw = buf[8]; cellh = buf[9]; foreground = buf[10]; background = buf[11]; while (GetDataBlock(fd, (unsigned char *) buf) != 0) { PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v], cmap[CM_GREEN][v], cmap[CM_BLUE][v]); ++index; } return; #else break; #endif case 0xff: /* Application Extension */ str = "Application Extension"; break; case 0xfe: /* Comment Extension */ str = "Comment Extension"; while (GetDataBlock(fd, (unsigned char *) buf) != 0) { Fprintf(stderr, "gif comment: %s\n", buf); } return; case 0xf9: /* Graphic Control Extension */ str = "Graphic Control Extension"; (void) GetDataBlock(fd, (unsigned char *) buf); Gif89.disposal = (buf[0] >> 2) & 0x7; Gif89.inputFlag = (buf[0] >> 1) & 0x1; Gif89.delayTime = LM_to_uint(buf[1], buf[2]); if ((buf[0] & 0x1) != 0) Gif89.transparent = buf[3]; while (GetDataBlock(fd, (unsigned char *) buf) != 0) ; return; default: str = buf; Sprintf(buf, "UNKNOWN (0x%02x)", label); break; } Fprintf(stderr, "got a '%s' extension\n", str); while (GetDataBlock(fd, (unsigned char *) buf) != 0) ; } static boolean ReadColorMap(fd, number) FILE *fd; int number; { int i; unsigned char rgb[3]; for (i = 0; i < number; ++i) { if (!ReadOK(fd, rgb, sizeof(rgb))) { return (FALSE); } ColorMap[CM_RED][i] = rgb[0]; ColorMap[CM_GREEN][i] = rgb[1]; ColorMap[CM_BLUE][i] = rgb[2]; } colorsinmap = number; return TRUE; } /* * Read gif header, including colormaps. We expect only one image per * file, so if that image has a local colormap, overwrite the global one. */ static void read_header(fd) FILE *fd; { unsigned char buf[16]; unsigned char c; char version[4]; if (!ReadOK(fd, buf, 6)) { Fprintf(stderr, "error reading magic number\n"); exit(EXIT_FAILURE); } if (strncmp((genericptr_t) buf, "GIF", 3) != 0) { Fprintf(stderr, "not a GIF file\n"); exit(EXIT_FAILURE); } (void) strncpy(version, (char *) buf + 3, 3); version[3] = '\0'; if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { Fprintf(stderr, "bad version number, not '87a' or '89a'\n"); exit(EXIT_FAILURE); } if (!ReadOK(fd, buf, 7)) { Fprintf(stderr, "failed to read screen descriptor\n"); exit(EXIT_FAILURE); } GifScreen.Width = LM_to_uint(buf[0], buf[1]); GifScreen.Height = LM_to_uint(buf[2], buf[3]); GifScreen.Colors = 2 << (buf[4] & 0x07); GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1); GifScreen.Background = buf[5]; GifScreen.AspectRatio = buf[6]; if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ if (!ReadColorMap(fd, GifScreen.Colors)) { Fprintf(stderr, "error reading global colormap\n"); exit(EXIT_FAILURE); } } if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) { Fprintf(stderr, "warning - non-square pixels\n"); } for (;;) { if (!ReadOK(fd, &c, 1)) { Fprintf(stderr, "EOF / read error on image data\n"); exit(EXIT_FAILURE); } if (c == ';') { /* GIF terminator */ return; } if (c == '!') { /* Extension */ if (!ReadOK(fd, &c, 1)) { Fprintf(stderr, "EOF / read error on extension function code\n"); exit(EXIT_FAILURE); } DoExtension(fd, (int) c); continue; } if (c != ',') { /* Not a valid start character */ Fprintf(stderr, "bogus character 0x%02x, ignoring\n", (int) c); continue; } if (!ReadOK(fd, buf, 9)) { Fprintf(stderr, "couldn't read left/top/width/height\n"); exit(EXIT_FAILURE); } if (BitSet(buf[8], LOCALCOLORMAP)) { /* replace global color map with local */ GifScreen.Colors = 1 << ((buf[8] & 0x07) + 1); if (!ReadColorMap(fd, GifScreen.Colors)) { Fprintf(stderr, "error reading local colormap\n"); exit(EXIT_FAILURE); } } if (GifScreen.Width != LM_to_uint(buf[4], buf[5])) { Fprintf(stderr, "warning: widths don't match\n"); GifScreen.Width = LM_to_uint(buf[4], buf[5]); } if (GifScreen.Height != LM_to_uint(buf[6], buf[7])) { Fprintf(stderr, "warning: heights don't match\n"); GifScreen.Height = LM_to_uint(buf[6], buf[7]); } GifScreen.Interlace = BitSet(buf[8], INTERLACE); return; } } static int GetCode(fd, code_size, flag) FILE *fd; int code_size; int flag; { static unsigned char buf[280]; static int curbit, lastbit, done, last_byte; int i, j, ret; unsigned char count; if (flag) { curbit = 0; lastbit = 0; done = FALSE; return 0; } if ((curbit + code_size) >= lastbit) { if (done) { if (curbit >= lastbit) Fprintf(stderr, "ran off the end of my bits\n"); return -1; } buf[0] = buf[last_byte - 2]; buf[1] = buf[last_byte - 1]; if ((count = GetDataBlock(fd, &buf[2])) == 0) done = TRUE; last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2 + count) * 8; } ret = 0; for (i = curbit, j = 0; j < code_size; ++i, ++j) ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j; curbit += code_size; return ret; } static int LWZReadByte(fd, flag, input_code_size) FILE *fd; int flag; int input_code_size; { static int fresh = FALSE; int code, incode; static int code_size, set_code_size; static int max_code, max_code_size; static int firstcode, oldcode; static int clear_code, end_code; static int table[2][(1 << MAX_LWZ_BITS)]; static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp; register int i; if (flag) { set_code_size = input_code_size; code_size = set_code_size + 1; clear_code = 1 << set_code_size; end_code = clear_code + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; (void) GetCode(fd, 0, TRUE); fresh = TRUE; for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1 << MAX_LWZ_BITS); ++i) table[0][i] = table[1][0] = 0; sp = stack; return 0; } else if (fresh) { fresh = FALSE; do { firstcode = oldcode = GetCode(fd, code_size, FALSE); } while (firstcode == clear_code); return firstcode; } if (sp > stack) return *--sp; while ((code = GetCode(fd, code_size, FALSE)) >= 0) { if (code == clear_code) { for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1 << MAX_LWZ_BITS); ++i) table[0][i] = table[1][i] = 0; code_size = set_code_size + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; sp = stack; firstcode = oldcode = GetCode(fd, code_size, FALSE); return firstcode; } else if (code == end_code) { int count; unsigned char buf[260]; if (ZeroDataBlock) return -2; while ((count = GetDataBlock(fd, buf)) > 0) ; if (count != 0) Fprintf(stderr, "missing EOD in data stream (common occurrence)\n"); return -2; } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if (code == table[0][code]) { Fprintf(stderr, "circular table entry BIG ERROR\n"); exit(EXIT_FAILURE); } code = table[0][code]; } *sp++ = firstcode = table[1][code]; if ((code = max_code) < (1 << MAX_LWZ_BITS)) { table[0][code] = oldcode; table[1][code] = firstcode; ++max_code; if ((max_code >= max_code_size) && (max_code_size < (1 << MAX_LWZ_BITS))) { max_code_size *= 2; ++code_size; } } oldcode = incode; if (sp > stack) return *--sp; } return code; } static void ReadInterleavedImage(fd, len, height) FILE *fd; int len, height; { int v; int xpos = 0, ypos = 0, pass = 0; while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) { PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v], ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]); ++xpos; if (xpos == len) { xpos = 0; switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { ++pass; switch (pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } if (ypos >= height) break; } fini: if (LWZReadByte(fd, FALSE, (int) input_code_size) >= 0) Fprintf(stderr, "too much input data, ignoring extra...\n"); } static void ReadTileStrip(fd, len) FILE *fd; int len; { int v; int xpos = 0, ypos = 0; while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) { PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v], ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]); ++xpos; if (xpos == len) { xpos = 0; ++ypos; } if (ypos >= TILE_Y) break; } } boolean fopen_gif_file(filename, type) const char *filename; const char *type; { int i; if (strcmp(type, RDBMODE)) { Fprintf(stderr, "using reading routine for non-reading?\n"); return FALSE; } gif_file = fopen(filename, type); if (gif_file == (FILE *) 0) { Fprintf(stderr, "cannot open gif file %s\n", filename); return FALSE; } read_header(gif_file); if (GifScreen.Width % TILE_X) { Fprintf(stderr, "error: width %d not divisible by %d\n", GifScreen.Width, TILE_X); exit(EXIT_FAILURE); } tiles_across = GifScreen.Width / TILE_X; curr_tiles_across = 0; if (GifScreen.Height % TILE_Y) { Fprintf(stderr, "error: height %d not divisible by %d\n", GifScreen.Height, TILE_Y); /* exit(EXIT_FAILURE) */; } tiles_down = GifScreen.Height / TILE_Y; curr_tiles_down = 0; if (GifScreen.Interlace) { /* sigh -- hope this doesn't happen on micros */ image = (pixel **) alloc(GifScreen.Height * sizeof(pixel *)); for (i = 0; i < GifScreen.Height; i++) { image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel)); } } else { image = (pixel **) alloc(TILE_Y * sizeof(pixel *)); for (i = 0; i < TILE_Y; i++) { image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel)); } } /* ** Initialize the Compression routines */ if (!ReadOK(gif_file, &input_code_size, 1)) { Fprintf(stderr, "EOF / read error on image data\n"); exit(EXIT_FAILURE); } if (LWZReadByte(gif_file, TRUE, (int) input_code_size) < 0) { Fprintf(stderr, "error reading image\n"); exit(EXIT_FAILURE); } /* read first section */ if (GifScreen.Interlace) { ReadInterleavedImage(gif_file, GifScreen.Width, GifScreen.Height); } else { ReadTileStrip(gif_file, GifScreen.Width); } return TRUE; } /* Read a tile. Returns FALSE when there are no more tiles */ boolean read_gif_tile(pixels) pixel (*pixels)[TILE_X]; { int i, j; if (curr_tiles_down >= tiles_down) return FALSE; if (curr_tiles_across == tiles_across) { curr_tiles_across = 0; curr_tiles_down++; if (curr_tiles_down >= tiles_down) return FALSE; if (!GifScreen.Interlace) ReadTileStrip(gif_file, GifScreen.Width); } if (GifScreen.Interlace) { for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { pixels[j][i] = image[curr_tiles_down * TILE_Y + j][curr_tiles_across * TILE_X + i]; } } } else { for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { pixels[j][i] = image[j][curr_tiles_across * TILE_X + i]; } } } curr_tiles_across++; /* check for "filler" tile */ for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X && i < 4; i += 2) { if (pixels[j][i].r != ColorMap[CM_RED][0] || pixels[j][i].g != ColorMap[CM_GREEN][0] || pixels[j][i].b != ColorMap[CM_BLUE][0] || pixels[j][i + 1].r != ColorMap[CM_RED][1] || pixels[j][i + 1].g != ColorMap[CM_GREEN][1] || pixels[j][i + 1].b != ColorMap[CM_BLUE][1]) return TRUE; } } return FALSE; } int fclose_gif_file() { int i; if (GifScreen.Interlace) { for (i = 0; i < GifScreen.Height; i++) { free((genericptr_t) image[i]); } free((genericptr_t) image); } else { for (i = 0; i < TILE_Y; i++) { free((genericptr_t) image[i]); } free((genericptr_t) image); } return (fclose(gif_file)); } #ifndef AMIGA static char *std_args[] = { "tilemap", /* dummy argv[0] */ "monsters.gif", "monsters.txt", "objects.gif", "objects.txt", "other.gif", "other.txt" }; int main(argc, argv) int argc; char *argv[]; { pixel pixels[TILE_Y][TILE_X]; if (argc == 1) { argc = SIZE(std_args); argv = std_args; } else if (argc != 3) { Fprintf(stderr, "usage: gif2txt giffile txtfile\n"); exit(EXIT_FAILURE); } while (argc > 1) { if (!fopen_gif_file(argv[1], RDBMODE)) exit(EXIT_FAILURE); init_colormap(); if (!fopen_text_file(argv[2], WRTMODE)) { (void) fclose_gif_file(); exit(EXIT_FAILURE); } while (read_gif_tile(pixels)) (void) write_text_tile(pixels); (void) fclose_gif_file(); (void) fclose_text_file(); argc -= 2; argv += 2; } exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif nethack-3.6.0/win/share/monsters.txt0000664000076400007660000037776512541713002016473 0ustar paxedpaxed. = (71, 108, 108) A = (0, 0, 0) B = (0, 182, 255) C = (255, 108, 0) D = (255, 0, 0) E = (0, 0, 255) F = (0, 145, 0) G = (108, 255, 0) H = (255, 255, 0) I = (255, 0, 255) J = (145, 71, 0) K = (204, 79, 0) L = (255, 182, 145) M = (237, 237, 237) N = (255, 255, 255) O = (215, 215, 215) P = (108, 145, 182) Q = (18, 18, 18) R = (54, 54, 54) S = (73, 73, 73) T = (82, 82, 82) U = (205,205,205) V = (104, 104, 104) W = (131, 131, 131) X = (140, 140, 140) Y = (149, 149, 149) Z = (195, 195, 195) 0 = (100, 100, 100) 1 = (72, 108, 108) # tile 0 (giant ant) { ................ ................ ................ ................ ................ ................ ................ .......JAJKKA... .....JAAAKJJJA.. .....AKJJAJJAA.. ...KKAJJJAAA.... ..BJJAAAAAJJA... ..JBJAJAJAA..... .....AJA.JA..... ......JA.JA..... ................ } # tile 1 (killer bee) { ................ ................ .PPP.....PP..... PPPPP...PBPP.... PBPPP..PBPPP.... .PPBP.PPLPLL.... ...PP.PLLALHAH.. ...AKKKLAHAAHH.. BBJJJJJJJAHHAA.. ABJBBJJJJAHAHH.. .JJABJAJ.J.HH... .......J.J...... ................ ...AAAAAAAAAAA.. .....AAAAAA..... ................ } # tile 2 (soldier ant) { ................ ................ ................ ................ ................ ................ ................ .......JAJKKA... .....JAAAKJJJA.. .....AKJJAJJAA.. .JJKKAJJJAAA.... JBJJJAAAAAJJA... JJJBJAJAJAA..... JAAJJAJA.JA..... ..JJAAJA.JA..... ................ } # tile 3 (fire ant) { ................ ................ ................ ................ ................ ................ ................ .......DACCCA... .....DAAACDDDA.. .....ACDDADDAA.. ...CCADDDAAA.... ..GDDAAAAADDA... ..DGDADADAA..... .....ADA.DA..... ......DA.DA..... ................ } # tile 4 (giant beetle) { ................ ................ ................ ................ ................ ................ ......KKDKK..... ....KACLCJJD.... ...KCLCJJDDDK... ...DCCJDADDAD... ...ADJDDDDDDD... ...BAKDDAADKAA.. ...ABAKDDK...... ......AA.AA..... ................ ................ } # tile 5 (queen bee) { ................ .PPP.....PP..... PPPPP...PPPP.... PPPPP..PPBPP.... PBPPP..PBPPP.... .PPBP.PPLPLL.... ...PP.PLLALHAH.. ...AKKKLAHAAHH.. BBJJJJJJJAHHAAH. ABJBBJJJJAHAHHH. .JJABJAJ.JHHHAA. ...J...J.JAAAHH. ..JJ..JJ.J.HHAH. ..JAAAJAAJ..HH.. .....AAAAAA..... ................ } # tile 6 (acid blob) { ................ ................ ................ .....KDDA....... ...DDKDDKA...... .DDDIIIDJDA..... D.IIOOIIDAIA.... .DKNNNODIDA..IA. IDJNANOJDDJA.... ADIDNOIDIDDDA... ...JDIKIADKIA... .IA.IDID.JDA.... ...I.DDA....DA.. .........IA..... ..IA............ ................ } # tile 7 (quivering blob) { ................ ................ .....PPPP....... .........P...... .P.OOOPPE..AAA.. P.OPBBBPOEAEAA.. P.PBNNNP.OEAAEA. P.PNNNNNPOEEAEA. POPNAANNEO.OAEA. .OPNAANNE..OAAA. .OPBNNNEPP.OEAA. BPOPEEEBBPO.EEA. BBBPBBBBBBPPPPA. ..BBBBBBBBBBPA.. ................ ................ } # tile 8 (gelatinous cube) { ................ ................ ................ ................ ................ .......LLL...... .....LLLLLLLL... ...LLLLLLLLLD... ...CLLLLLLLDDA.. ...CGGCLLLDDDAA. ...CAGCGGDDDDAAA ...CCCCAGDDDAAAA .....CCCCDDAAAA. .......CCDAAA... ................ ................ } # tile 9 (chickatrice) { ................ ................ ................ ................ .......OO....... ......HAOO...... .....HHOOH.HHA.. ........OOHOA... ........OOFA.... ........FGGFA... ........AGFGAA.. ...........GA... .......F..FFA... .......AFFAA.... ........AA...... ................ } # tile 10 (cockatrice) { ................ ...D.DD......... ....DD.......... ....NL..AA...... ..HHAN.AAA...... .HH.NO..AAAA.... ...AOOLFFFAA.... ...OOLKGGFFAA... ...AOAGGFGFFAA.. .......GFFGFAA.. .........FGGAA.. .....FA...FFA... ....FA....FFA... ....FA..FFFA.... .....FFFFA...... ................ } # tile 11 (pyrolisk) { ................ ...D.DD......... ....DD.......... ....NB..AA...... ..HHAN.AAA...... .HH.NB..AAAA.... ...APBBJJJAA.... ...PPPKDDKJAA... ...APADDKDKJAA.. .......DJKDJAA.. .........JDDAA.. .....JA...JJA... ....JA....JJA... ....KA..KKKA.... .....JKKKA...... ................ } # tile 12 (jackal) { ................ ................ ................ ................ ...O..O......... ...O.OO...O..... ..OOOO.....O.... ..IOIOO....O.A.. .OLLOOOL...O.A.. DOOOAOOOOOOOAA.. ..AAOOOOOOOOAA.. ....OJOOOOOLAA.. ....OJOLKALKAA.. ...OOAOAAAOAA... .....OO..OOA.... ................ } # tile 13 (fox) { ................ ................ ................ ................ ................ ................ ................ ................ ....C........... ....C........... ..CCAC...CCC.... ..ACCCCCCACCC... ...AACCCC.ACC... ....ACAAC..AA... ...AC.ACA....... ................ } # tile 14 (coyote) { ................ ................ ................ ...K..K......... ...K.KK......KKK ..KKKK......KKKA ..NCNK.KKKKKAAA. .KCCKKKKKKKKK... KKCKAKKKKKKKK... DKKKAKAKKKKAK... ..AAKAAKAAAAK... ....AKAKAAAAK... ...AKKAKA.AKK... .....AKK........ ................ ................ } # tile 15 (werejackal) { ................ ................ ................ ................ ...O..O......... ...O.OO...O..... ..OOOO.....O.... ..IOIOO....O.A.. .OLLOOOL...O.A.. DOOOALLOOOOOAA.. ..AALLLLOOOOAA.. ....LJLLLOOLAA.. ....LJLLKALKAA.. ..LLLALAAAOAA... ...L.LL..OOA.... ......L......... } # tile 16 (little dog) { ................ ................ ................ ................ ...J..J......... ...J.JJ...K..... ..JJJJ.....K.... ..NJNKK....K.A.. .JJJCKK....K.A.. .PJJAKCKKCKKAA.. .DDAACKKCKKKAA.. ....KJKJCJKJAA.. ....KJKJJAJJAA.. ...KKAKAAAKAA... .....KK...KA.... ................ } # tile 17 (dingo) { ................ ................ ................ .............C.. ...C..C.......C. ...C.CC.......CA ..CCCCK.......CA ..ACACCKCCCCCCAA ..LLCCCKCCCLCCCA .KCCACKCLLLLACCA ..AACAACLLAAACCA ....ACACAAAAAACA ....CCACAAA..CCA .....ACCA....... ................ ................ } # tile 18 (dog) { ................ ................ ................ ...J..J.....K... ...J.JJ......K.. ..JJJJ.......K.. ..NJNKK......K.A .JJJCKKKK....K.A .PJCAKCKKKKCKKAA .DDAACKKKKCKKKAA ..AAKJKKJJCJKJAA ....KJKKJJJAJJAA ....KAKJAAAAKJA. ...KKAKAAAAAKAA. .....KKAA...KA.. ................ } # tile 19 (large dog) { ................ ................ ...J..J.....K... ...J.JJ......K.. ..JJJJ.......K.. ..NJNKKK.....K.A .JJJCKKKKK..JK.A .PJCAKCKKKKCKKAA .DDAACKKKKCKKKAA ..AAKJKKJJCJKJAA ...JKJKKJJJAJJAA ....KAKJAAAAKJA. ....KAKJAAAAKJA. ...KKAKAAAAAKAA. .....KKAA...KA.. ................ } # tile 20 (wolf) { ................ ................ ................ ...P..P.....P... ...P.PP......P.. ..PPPP.......P.. ..N.NPP......P.A .P..PPPPP....P.A PP.PAPPPPPPPPPAA DPPPAPPPPPPPPPAA ..AAP.PP..P.P.AA ....P.PP...A.PAA ....PAP.AAAAP.A. ...PPAPAAAAAPAA. .....PPAA..PPA.. ................ } # tile 21 (werewolf) { ................ ................ ................ ...P..P.....P... ...P.PP......P.. ..PPPP.......P.. ..N.NPP......P.A .P..PPPPP....P.A PP.PAPPPPPPPPPAA DPPPALPPPPPPPPAA ..AALLPL..P.P.AA ....L.LL...A.PAA ....LAL.AAAAP.A. ..LLLALAAAAAPPA. ...L.LLAA..PP... .....LL......... } # tile 22 (winter wolf cub) { ................ ................ ................ ................ ...N..N......... ...N.NB...N..... ..NNNN.....N.... ..DNDNB....N.A.. ..NNNNB....N.A.. .NNNNNNNNNNNAA.. .DNBBNNNNNNBAA.. ....NNNNNNNBAA.. ....NNNBBANBAA.. ...NBANAAANAA... .....NB..NBA.... ................ } # tile 23 (warg) { ................ ...P..P....PP... ...P.PP......P.. ..PPPP.......P.A ..N.NPP......P.A .P..PPPPP....P.A PPPPDPPPPPPPPPAA DPPNDPPPPPPPPPAA ..DDDPPPPPPPPPAA PNDNP.PPPPPPPPAA .PPPPAPPPPAPP.A. ...PAAPPAAAAPPAA ...PAAP.AAAAP.A. .PPPAAPAAAAAPAA. ....PPPAA.PPPA.. ................ } # tile 24 (winter wolf) { ................ ................ ................ ...N..N.....N... ...N.NN......N.. ..NNNN.......N.. ..DODNN......N.A .NOONNNNN....N.A NNONANNNNNNNNNAA DNNBANNNNNNNNNAA ..AANNNNNNNBNNAA ....NBNNNBBANNAA ....NANBAAAANBA. ...NNANAAAAANAA. .....NNAA..NNA.. ................ } # tile 25 (hell hound pup) { ................ ................ ................ ................ ...C..C......... ...C.CC...C..... ..CCCC.....C.... ..DCDCC....C.A.. .CCCCCC....C.A.. .PCCACCCCCCCAA.. .CHAACCCCCCCAA.. CHC.CCCCCCCCAA.. .D..CCCCCACCAA.. ...CCACAAACAA... .....CC...CA.... ................ } # tile 26 (hell hound) { ................ ...C..C....CC... ...C.CC......C.. ..CCCC.......C.A ..DJDCC......C.A .CCCCCCCC....C.A CCCCDCCCCCCCCCAA .CHC.CCCCCCCCCAA CHC..CCCCCCCCCAA .D..CCCCCCCCCCAA ...CCACCCCACC.A. ...CAACCAAAACCAA ...CAAC.AAAAC.A. .CCCAACAAAAACAA. ....CCCAA.CCCA.. ................ } # tile 27 (Cerberus) { ................ ..J..J.......... ..JJJJ.J..J..... .NJNJ..J.JJ..... JJJJKAJJJJ....J. PJJJJANJNKK...J. DJKJAJJJKJJK..J. ..AAJPJKAJKJKJJ. ..JJJDDAJKJJJJJA ..JJJAAJJJJJJJJA .JKKKJJJKJJKJJAA .JJAAKJJKJJJKJAA JJAAAAJJAAAAJJA. JAAAAAJAAAAAJAA. .....JJAA...JA.. ................ } # tile 28 (gas spore) { ................ ................ ................ .....PFGGFP..... ....PGFFFFFP.... ...PFFFFFGGFP... ...FFGGFFGGFF... ...GFGGFFFFFG... ...GFFFFFFFFG... ...FFFFGGFFFF... ...PGGFGGFGGP... ....PGFFFFGP.... .....PFGGFP..... ................ ................ ................ } # tile 29 (floating eye) { ................ ................ ......ONNNO..... ....PNNNNNNNP... ....NNNNNNNNN... ...ONNBBBBNNNO.. ...NNBBEEBBNNN.. ...NNBEAAEBNNN.. ...ONBEAAEBNNO.. ....NBBEEBBNN... ....PNBBBBNNPAA. ......ONNNOAAAA. ......AAAAAAAAA. .......AAAAAAA.. ................ ................ } # tile 30 (freezing sphere) { ................ ................ ......PBBBP..... ....PBBBBBBBP... ....BBBBBBBBB... ...PBPPPBBBBBP.. ...BBNNBBPPPBB.. ...BBANPBNNBBB.. ...PBBPPBANPBP.. ....BBBBBBPPB... ....PBBBBBBBPAA. ......PBBBPAAAA. ......AAAAAAAAA. .......AAAAAAA.. ................ ................ } # tile 31 (flaming sphere) { ................ ....C...H....... ....C....O...C.. ...C..H.CC...C.. ...C..C.CC..CC.. ...DCA.DDC.ACC.. .AHCDCADDCAADC.. .AACDCDDDDDADD.. ..ACDDDJJJDDDD.. ..ADDCAKDDACDD.. ...ADAKDDCDAD... ...ADADHCHCAD... ....DADDDCDAD... .....DADDDAD.... ......JJJJJ..... ................ } # tile 32 (shocking sphere) { ................ .....PPPPPP..... ...PPIAAADAPP... ..PAAAIAAADDAP.. ..PHAAAPBOAAAP.. .PAHHAPBBBOAAAP. .PHAAAPBBBBAHHP. .PAAAAPPBBBAAAP. .PAAAIAPPPAAAIP. .PIIIAAAAAAIIAP. ..PIAANAAPAAAIP. ..PIAANAAAPAAP.. ...PANANAPAPAP.. ....PPAIAPAPP... ......PPPPP..... ................ } # tile 33 (beholder) { ....OA..OA...... ..OA.DADA.OA.OA. ...DA.DADADADD.. ..OADDOOOODDADO. ...DDHOAAOHDDA.. ...JDHOAAOHDDJ.. ...DDDOOOODDDD.. ...DDDDDDDDDDD.. ...JDAOAAAOADJ.. ....DDAAOAADD... ....PDDDDDDDPAA. ......JDDDJAAAA. ......AAAAAAAAA. .......AAAAAAA.. ................ ................ } # tile 34 (kitten) { ................ ................ ................ ................ ................ ................ ...........K.... ............C... ....C.C.....L.A. ...CCCCJ....C.A. ...NCNCJCCLCL.A. ...CCCCJCCLCCAA. ....IACCLLCCCAA. .....CACCJCCJA.. ......CCA..CA... ................ } # tile 35 (housecat) { ................ ................ ................ ................ ................ ...........K.... ............C... ...C.C......L.A. ..CCCCJ.....C.A. .CNCNCJCLCLCL.A. .CCCCCJCLCLCCAA. ..CICJCCLCLCLAA. ...AACCLCLCCCAA. ...CCACCJJCCJA.. .....CCA...CA... ................ } # tile 36 (jaguar) { ................ ................ ................ ................ ..C..C......C... ..CC.CJ......C.A .CCCCCJ......C.A .GCGCCJCAACCJC.A .CCCCCJCCCCCCCAA .CDDDJCAACCAJCAA ..CCACCAJCCAACAA ....CACCJJJCCJA. ....CACAAAAACJA. ...CKACAAAAACAA. .....CCAA...CA.. ................ } # tile 37 (lynx) { ................ ................ ................ ................ O....O.......... AC.CCA.......... .CCCA........CA. .GCGCOAKKKKK.LA. .CKCCAJCCCCCKA.. LLDDLLACLLLCCAA. ..CC.AACLLLCCAA. .......CAAAACAA. ....CACAAAACCA.. ................ ................ ................ } # tile 38 (panther) { ................ ................ ............AA.. ..............A. ..............A. .A...A........A. .EA.AE........A. .AAAAAEAAAAAAA.. .AAAAAEAAAAAAA.. .HAHAA.AAAAAAAA. .AAAA.AAAAAEAAA. .AAA..AAAAAEAAA. .....AA....AAA.. ..AAAA..AAAA.... ................ ................ } # tile 39 (large cat) { ................ ................ ................ ................ ............K... .............C.. ...C.C.......L.A ..CCCCJ......C.A .CNCNCJCLCCLCL.A .CCCCCJCLCCLCCAA ..CDCJCCLCCLCLAA ...AACCLCCLCCCAA ....CACCJJJCCJA. ...CKALAAAAACAA. .....CCAA...CA.. ................ } # tile 40 (tiger) { ................ ................ ................ ................ ..C..C......C... .CCJCC.......C.A .CAACCJ......A.A .GAGCCJACACAJC.A .CCCCCACACACACAA .ODOCACCACACACAA .OCOACCJACACACAA ....CACJAJAJCAA. ....AACAAAAAAJA. ...CKACAAAAACAA. .....CCAA..CCA.. ................ } # tile 41 (gremlin) { ................ ................ ................ GGGA....AGGG.... .GGGFAAAGGG..... ..FFFFFFFF...... ...NDFFDNA...... ...GNFFNGA...... ...GFFFFGA..AA.. ...AGFFFAFAAAAA. ..GFAGFAFFFAAAA. .GFGFAAFFAFAAAA. .GF.GFAGAAFAAAA. ....FFAGFAA.AA.. ...GFA.FGA...... ................ } # tile 42 (gargoyle) { ................ ................ ...PAPPPPAP..... ..PA......AP.... ..P.DD..DDAP.... ....PD..DPA..... ....P....PA..AA. ....AP...A.AAAAA ...P.AP.A...AAAA ..P.P.AA..A.AAAA ..PA.P.APAA.AAAA ..PA.P....A.AA.. .....P....AAAA.. .....P.AP.AA.... ....PFA.FPA..... ................ } # tile 43 (winged gargoyle) { ...K......K..... ...KJ....KJ..... ..KJAPPPPAJJ.... ..KJ......AJ.... ..KJDD..DDAJ.... .KJAPD..DPAJJ... .KJAP....PAAJAA. KJA.AP...A.AJJAA J..P.AP.A...AJAA ..P.P.AA..A.AAAA ..PA.P.APAA.AAAA ..PA.P....A.AA.. .....P....AAAA.. .....P.AP.AA.... ....PFA.FPA..... ................ } # tile 44 (hobbit) { ................ ................ ................ ................ ......JJA....... .....JJJJA...... ....JLFLFJ...... ....JLLLLJ...... ....JKLLKJJ.AA.. ...CLLLLLLCAAA.. ..CLALLLLALCA... ..LLAJJKJALLA... ...L.LKJLALAA... .....LLALLA.A... ....LLL.LLL..... ................ } # tile 45 (dwarf) { ................ ................ ................ ................ ......B......... .....BEE........ ....BBEEE....... ....BLLLE....... .....OLO...AAA.. ...BBOOOEEAAAA.. ...BABOEAEAAAA.. ....LBBELAAAA... ....EBAEEAA..... ....BEAEB.A..... ................ ................ } # tile 46 (bugbear) { ................ ................ ......K......... .K..KKK......... .KKKKKK......... KADKADKKK....... KKKKKKKJKK...... KAPAPAKJJKJ..... KAAAAAKKJKJJ.... .KKKKKJKAKKJ.... ..KAJJCAKKKJ.AA. ..KK.KKKKKJJAA.. ...C..KJAKJAA... .....CCAAKJA.... ........CCA..... ................ } # tile 47 (dwarf lord) { ................ ................ ................ ................ ......B......... .....BEE........ ....HHHHH....... ....BLLLE....... ....BOLOE..AAA.. ...BBOOOEEAAAA.. ...BABOEAEAAAA.. ....LBBELAAAA... ....EBAEEAA..... ....BEAEB.A..... ................ ................ } # tile 48 (dwarf king) { ................ ................ ................ ................ ....H.C.H....... ....HCHCH....... ....HHHHH....... ....BLLLE...A... .....OLO...AAAA. ...EBOOOEEAAAA.. ...BABOEAEAAAA.. ....LBBELAAAA... ....EBAEEAA..... ....BEAEB.A..... ................ ................ } # tile 49 (mind flayer) { ................ .......IIIIC.... .....IIIIIIC.... ....IIIIIIIC.... ...IGIIIIGC..... ...IIGINGIC..... ....IIIIIC...... ....IAIAIF...... ....IAIAIF...... ....IAIAIFI..... .....FIFIFIC.AA. ....CBIBBF.CAAA. ...IIIBBFFACAAA. ......BBFCAAAA.. ......CFFCAA.... ....IIC.IIA..... } # tile 50 (master mind flayer) { ................ .......IIIIC.... .....IIIIIIC.... ....IIIIIIIC.... ...IGIIIIGC..... ...IIGINGIC..... .EEEIIIIICEEEE.. ..EEIAIAIEEEE... ...EIAIAIEEE.... ....IAIAIEEE.... ....EFIFIEEE.AA. ....CBIBBEEEAAA. ...IIIBBEEEEAAA. ....EEBEEEEAAA.. ...EEECEEEAA.... ....IIC.IIA..... } # tile 51 (manes) { ................ ................ ....PP.......... ...PPPP......... ..PAPAP......... ..PPPPP.PPP.P... ..P..PPPP....... ..P..PPPPP...P.. ..PPPPP.PPP..... ..P.P.P.PP.P.... .P...P.PPPP..... .P....PPP.PP.... ..P....P.P.P.P.. ........P....... ................ ................ } # tile 52 (homunculus) { ................ ................ ................ ................ ................ ................ ................ ......JJJ....... ......LLC....... ......LLC....... .....BBPPPAA.... ....L.BPPACAA... ......BAPAAAA... .....LLALCA..... ................ ................ } # tile 53 (imp) { ................ ................ ................ ................ ................ ................ ................ .....O.D.O...... .....OCDDO...... ......CDD....... .....GGFFFAA.... ....C.GFFADAA... ......GAFAAAA... .....CDADDA..... ................ ................ } # tile 54 (lemure) { ................ ................ ....PP.......... ...PPPP......... ..PAPAP....P.... ..PPPPP..PP.P... ..P..PPPPPPPP... ..P..PPPPPPP.... ..PPPPPPPPP..... ....PPPPPPPP.... ..PPPPPPPPPP.... ...PPPPPPPPPP... ..P.P..PPPP.PP.. ........P.PP.... ................ ................ } # tile 55 (quasit) { ................ ................ ................ ................ ................ ................ .....O.D.O...... .....OCDDOD..... ......CDD.D..... .....GGFFFAA.... ....C.GFFAAADA.. ....C.GFFJJDA... ......GAFAAAA... .....CDADDA..... ................ ................ } # tile 56 (tengu) { ................ .......PP....... ......PPPP...... .....DPPNP...... ....DDDPPP...... ....DDPPPP...... ....D..PPA...... .....PIAAIP.AAA. ....PPPIIPPPAAA. ....PAPPPPAPAAA. ....PAHHHHAPAAA. ....LAPPPPALAAA. ......PPPPAAAA.. ......PPPPAA.A.. .....LLA.LLA.... ................ } # tile 57 (blue jelly) { ................ ................ ................ .......E........ ......OBE....... ...BE.OBEBOE.... ..OBEOBBEOBBE... ..OBEOBBEOBBE... ..BBBGGBGGBEEE.. ..BBBAGBAGEEEEA. ..BBBBBBEBEEEEAA ...BBBBBBBEEEAAA ....BBBBBEEEAAA. ......BBBEEAA... ................ ................ } # tile 58 (spotted jelly) { ................ ................ ................ .......E........ ......OBE....... ...BE.OCEBOE.... ..OCEOCCEOBCE... ..OCEOBCEOCBD... ..BBBHHBHHBEDD.. ..CCBAHBAHEEEEA. ..BBCBBBEBEEDEAA ...BBBCBBBEEDAAA ....BCCCBEEDAAA. ......CCBEEAA... ................ ................ } # tile 59 (ochre jelly) { ................ ................ ................ .......D........ ......LCD....... ...CD.LCDCLD.... ..LCDLCCDLCCD... ..LCDLCCDLCCD... ..CCCGGCGGCDDD.. ..CCCAGCAGDDDDA. ..CCCCCCDCDDDDAA ...CCCCCCCDDDAAA ....CCCCCDDDAAA. ......CCCDDAA... ................ ................ } # tile 60 (kobold) { ................ ................ ................ ................ ...N...N........ ...NBPBN........ ...BABAB........ ....BBPA..A..... ...BBABPA.AA.A.. ..BPBBBBPAAAAA.. ..BAPBPAPAAAAA.. ....PBPAAAAAA... ....BABAAAA..... ...BBABBA....... ................ ................ } # tile 61 (large kobold) { ................ ................ ................ ...N...N........ ...NBPBN........ ...BABAB........ ....BBPA..A..... ...BBABPA.AA.... ..BPBBBBPAAA.A.. ..BAPBPAPAAAAA.. ..BAPBPAPAAAAA.. ....PBPAAAAAA... ....BABAAAA..... ...BBABBA....... ................ ................ } # tile 62 (kobold lord) { ................ ................ ................ ...N...N........ ...NCCCN........ ...CABAC........ ...CBBPC..A..... ..CCBABCC.AA.... ..CCBBBCCAAA.A.. ..BCCBCCPAAAAA.. ..BACBCAPAAAAA.. ....BBBAAAAAA... ....BABAAAA..... ...BBABBA....... ................ ................ } # tile 63 (kobold shaman) { ................ ................ ................ ...N...N........ ...NHHHN........ ...HABAH........ ...HBBPH..A..... ..HHBABHH.AA.... .HHHBBBHHHAA.A.. .HBHHBHHPHAAAA.. ..BAHBHAPAAAAA.. ....BBBAAAAAA... ....BABAAAA..... ...BBABBA....... ................ ................ } # tile 64 (leprechaun) { ................ ................ ................ ................ ......G......... ......F....K.... .....GFF..KLK... ....GFFFF..K.... .....KLKA.GLAA.. ...FGFJFFFAKA.A. ...GAGFFAAAK.AA. ....LKHKKJAKAA.. ....GFAGKJAKA... ...GFAA.GFAK.... ................ ................ } # tile 65 (small mimic) { ................ ................ ................ ................ ......POP....... ......NNO....... ......NNO....... .......OA....... .....NNNNN..AA.. ....OONNNOO.AA.. ....NANOOANAAA.. ......NAOAAAA... ......NAOAA.A... .....NN.OOA..... ................ ................ } # tile 66 (large mimic) { ................ ................ ................ ......LLOA...... ......NNOA...... ......NNOA...... ......ONOA...... .....NNNNO..AAA. ....OONNNOO.AAA. ...NOANNNAOOAAA. ...NAONONOANAAA. .....NO.NOAAAA.. .....NO.NOAA.A.. ....NNO.NOOA.... ................ ................ } # tile 67 (giant mimic) { ................ ......NNO....... .....NNNNOA..... .....NNNNOA..... .....NNNNOA..... .....ONNNOA..... ..PONNOOONOOPAAA .PONONNNNOONOPAA .ONOANNNNOAONOAA .NNOANNNNOAOOOAA ...AANNONNAAAAAA ....PNO.NNPAAAAA ....ONO.NNOAA..A ....NNO.NNOAA..A ...NNNO.NNOOA... ................ } # tile 68 (wood nymph) { ................ ................ ...OH........... ..OHHL.......... ..OHLL.......... ..HHLA.......... .OHLLFKKKKLA.... .HKFLFKKKKA..... OHKJFKKJJK.A.... HKKLJJGKAAAAAAA. .JJAJGDKJAAAAA.. ..JA.KKJJAAAA... ...J.KKKKJAA.... ....JKKKKKJA.... ....KJKJKJKJ.... ................ } # tile 69 (water nymph) { ................ ................ ...OH........... ..OHHL.......... ..OHLL.......... ..HHLA.......... .OHLLJBBBBLA.... .HBJLJBBBBA..... OHBPJBBPPB.A.... HBBLPPNBAAAAAAA. .PPAPNDB.AAAAA.. ..PA.BBPPAAAA... ...P.BBBBPAA.... ....PBBBBBPA.... ....BPBPBPBP.... ................ } # tile 70 (mountain nymph) { ................ ................ ...OH........... ..OHHL.......... ..OHLL.......... ..HHLA.......... .OHLLCOOOOLA.... .HOCLCOOOOA..... OHOLCOOLLO.A.... HOOKLLIOAAAAAAA. .LLALIBOKAAAAA.. ..LA.OOLLAAAA... ...L.OOOOLAA.... ....LOOOOOLA.... ....OLOLOLOL.... ................ } # tile 71 (goblin) { ................ ................ ................ ....LK.......... ...CJA.......... ..KJA........... .JJA.IIK...AA... .IK.IGIGIJAA.... J.ICKIIIJK...... ...IIJJJK.A..... ....KICJAAAAA... ....ICKKJA...... ....IKAIJA...... ...IKAA.IK...... ................ ................ } # tile 72 (hobgoblin) { ................ .....LK......... ....CKA......... ...CJA.......... ..KJA........... .JJA.IIK...AA... .IK.IHIHIJAA.... J.ICKIIIJK...... ...IIJJJK.A..... ....KICCAAAAA... ....IIIIJA...... ....ICKKJA...... ....IKAIJA...... ...IKAA.IK...... ................ ................ } # tile 73 (orc) { ................ ................ ................ .....OA......... ....NOPA........ ....LPLA........ .....P.A........ ..KCCAKKKA.AA... ..BPCKJ.P.AAA... ..BAGGFAAPNO.... ..BAJJPNOAAA.... ....BNOJAAAAAA.. ...BJACPAAAA.... ..BPPABPPA...... ................ ................ } # tile 74 (hill orc) { ................ ................ ................ .....OA......... ....NOPA........ ....LKLA........ .....K.A........ ..KGGAFFKA.AA... ..JKGFF.K.AAA... ..JAHHFAAKNO.... ..JAGFFNOAAA.... ....GNNFAAAAAA.. ...GGAGFAAAA.... ..KJJAKJJA...... ................ ................ } # tile 75 (Mordor orc) { ................ ................ ................ .....OA......... ....NOPA........ ....LPLA........ .....P.A........ ..KIIAIIKA.AA... ..BPIDD.P.AAA... ..BAGGFAAP.O.... ..BAIDDNOAAA.... ....BNOJAAAAAA.. ...BIAIPAAAA.... ..BPPABPPA...... ................ ................ } # tile 76 (Uruk-hai) { ................ ................ .....OA......... ....NOPA........ ....LPLA........ .....P.A........ ..IIIAIIIA...... ..BPIKI.BAAAA... ..BIG.PPPPAAA... .NBAD.PDDPAA.... ..BNNJPDDPAA.... ....INPPPPAAAA.. ...BIAK.AAAA.... ..BPPABPPA...... ................ ................ } # tile 77 (orc shaman) { ................ ................ .....OA......... ....NOPA........ ....LPLA........ .....P.A........ ..CCCACCCA...... ..BPCKC.BAAAA... ..BCGGFJBAAAA... ..BAJJCJBAAA.... ..BAJJCJBAAA.... ....CACJAAAAAA.. ...BCACPAAAA.... ..BPPABPPA...... ................ ................ } # tile 78 (orc-captain) { ................ ................ .....OA......... ...NNOOPA....... ....LPLA........ ...IPPPA........ ..DIIPADDA.AA... ..BPIAD.P.AAA... ..BAGGFAAP.O.... ..BAGGFAAP.O.... ..BAJJPNOAAA.... ....BNOJAAAAAA.. ...BDAIPAAAA.... ..BPPABPPA...... ................ ................ } # tile 79 (rock piercer) { .JKKKKKKKKJAAA.. ..JJGKGKJJAAAA.. ...JKKKJJAAAA... ...JJKKJJAAAA... ....JKKJAAAA.... ....JJKJ.AAA.... ....JJKJ.AAA.... ....JJJJ..A..... .....JJ...A..... .....JJ...A..... .....JJ......... .....JJ......... .....J.......... .....J.......... ................ ................ } # tile 80 (iron piercer) { .BPPPPPPPP.AAA.. ..BBDPDP..AAAA.. ...BPPP..AAAA... ...PBPP..AAAA... ....BPP.AAAA.... ....BBP.AAAA.... ....PBP.AAAA.... ....PBP...A..... .....BP...A..... .....BP...A..... .....BP......... .....BP......... .....B.......... .....P.......... ................ ................ } # tile 81 (glass piercer) { .NBBBBBBBBPAAA.. ..NNDBDBPPAAAA.. ...NBBBPPAAAA... ...PNBBPPAAAA... ....NBBPAAAA.... ....NNBPAAAA.... ....PNBPAAAA.... ....PNBP..A..... .....NB...A..... .....NB...A..... .....NB......... .....NB......... .....N.......... .....P.......... ................ ................ } # tile 82 (rothe) { ................ ...........K.... ............K... ............K... .......JJJKKJ... .....JKKKKKKK... ..AAAKKKKKKKK... .AAAAAKKKKKKKA.. AAKKAAKKKKKAKA.. .KEKKAKKKJAAKA.. .KKKJAKKAJAAK... ..KJAAAKAAA..... ..AAKA.KA....... ..A..A.K........ ................ ................ } # tile 83 (mumak) { ................ ...........P.... .PP.........P... PPP...PPPPP.P... PPPPPPPPP.PP.... PPPPBPPBBP.PP... PPPBPPPPPP.PP... .PDPPDDPP.PPP... ..BPPDDP.PPPPA.. ..PPPPPPPPPPPA.. ..PPPPO..PAPPA.. .OOPPOOAPPAPPA.. OOPPOOAAPPA..... .PPPAPA.PP...... PPPA............ .AA............. } # tile 84 (leocrotta) { ................ ..A..A.......... ..AOOA....J..... ..AOOAA....J.... .APOAFA....J.... .APOAAA.JJJJ.... .AOPAAJKKKKKJ... .AOAAKJJKKJKJA.. ...JKKKKKJAKKA.. ...JKJKKJAAKKA.. ..JKJAKKAAPAPA.. ..KKAAKKAAPAPA.. .PAPAAPAPA...... .PAPA.PAPA...... ................ ................ } # tile 85 (wumpus) { ................ ............B... .............B.. .......BBBBB.B.. ....BBBPPBBBB... ...BOOBBBPBBBB.. ...OOBBBBBPBBB.. ..DABBAABBPBBBA. .BOOBBDABEBBEBAA .BOBBBBBBEBEBBAA .BBBBBBBEBBABBAA .EBBBBBEABBABBAA ..EEEEEAABBA.... .....BBA.BB..... ................ ................ } # tile 86 (titanothere) { ................ ................ ................ ..........PPP.P. .......PPPPPPPAP .....PPPPPPPPP.A ..P.P.PPPPPPPP.A ..PPP.PPPPPPPPPA ..PPPP.PPPPPPPPA .PPPPP.PPPPPPP.. .PPEPP.PPPP.PPA. PBPPP.PPP.AAPPA. PPPP.AAPPAA..... .PP.PPAPPA...... ................ ................ } # tile 87 (baluchitherium) { ................ ................ ................ ..........PPP.P. .......PPPPPPPAP .....PPPPPPPPP.A ..P.P.PPPPPPPP.A ..PPP.PPPPPPPPPA ..PPPP.PPPPPPPPA BPPPPP.PPPPPPP.. B.PEPP.PPPP.PPA. PB.PP.PPP.AAPPA. PPPP.AAPPAA..... .PP.PPAPPA...... ................ ................ } # tile 88 (mastodon) { ................ ................ ................ ................ ................ ..O...O......... .N..POP.P....... N..PNPPPPP...... O.PNPPPPPP.PP... O.POPEPPP.PPPPP. .OPOPOP..PPPPPAP ..PPOPP.PPPPPPAA ..PPAAAPPPPAPPA. ..P...APPAAAPPA. .......PPA...... ................ } # tile 89 (sewer rat) { ................ ................ ................ ................ ................ ................ ................ ..K..K.JKKKK.... ..KKKKJKKJKKK... ..JAKAKJJJKKKJ.. ..GKGKJKAKKAKKA. .KKJJJJKAKAAKKA. .PJJAAKKAJAJKA.. ..AA.KKA..JKA... .........JJA.... ................ } # tile 90 (giant rat) { ................ ................ ................ ................ ................ ................ ..K..K.JKKKKK... ..KKKKJKKKJKKK.. ..JAKAKJKJJKKKJ. ..GAGAKJKJJKKKK. ..AKAKJKKAKKAKKA .KKJJJJKAJKAAKKA .PJJAAKKAJJAJKA. ..AA.KKAA..JKA.. ..........JJA... ................ } # tile 91 (rabid rat) { ................ ................ ................ ................ ................ ................ ..K..K.JKKKKK... ..KKKKJKKKJKKK.. ..JAKAKJKJJKKKJ. ..GAGAKJKJJKKKK. ..AKAKJKKAKKAKKA .KKJOOOKAJKAAKKA .PJOOAKKAJJAJKA. ..AOOOKAA..JKA.. .OOOOOOOO.JJA... ................ } # tile 92 (wererat) { ................ ................ ................ ................ ................ ................ ..K..K.JKKKKK... ..KKKKJKKKJKKK.. ..LLLLKJKJJKKKJ. ..FLFLLJKJJKKKK. ..LLLLJKKAKKAKKA .KKJJJJKAJKAAKKA .PJJAAKKAJJAJKA. ..AA.KKAA..JKA.. ..........JJA... ................ } # tile 93 (rock mole) { ................ ................ ................ ................ ................ ................ ................ .......AAAAA.... ...AAAAAAAAAA... ..AAAAAAAAAAAA.. ..JAJAAAAAAAAAA. .AAAAAAAAAAAAAA. AN.NAAAAAAAAAAA. A...AAAA...AAA.. AN.NAA.AA...AA.. .AAAA........... } # tile 94 (woodchuck) { ................ ................ ................ ................ ................ ................ .......KJA...... ......NKKNA..... ......KNOJA..... ......KNOJA..... .....KKKKKJA.... ....JJKLLJJJAA.. ......KLLJAAAAA. ......KJJJAAAA.. .....JJAAJJAA... ................ } # tile 95 (cave spider) { ................ ................ ................ ................ ................ ........PA...... .......PA....... ......PAPBBA.... ...PA.APBPPPA... ...ABBPPAPPAA.PA ...GPPPPAAAPPPAA ...PPGPAAPPAAAA. ..D.PAPAPAAPPA.. ....D.PAAPA.APA. .....PAA.APA.... ................ } # tile 96 (centipede) { ................ ................ ......PBPP...... ....BBPAAA...... ..PPBAAA........ .PAPBBBPPPP..... ..PAAPPBBBA..... ....PAAPAPBPP... ......AABBPP.... ......BB.PPAP... ....PBBPPAP.A... ...GPPPAP.AP.... ...PPGPAAP...... ..B.PAA......... ...B............ ................ } # tile 97 (giant spider) { ................ ................ ................ ................ ................ ........JA...... .......JA....... ......JAJKKA.... ...JA.AJKJJJA... ...AKKJJAJJAA.JA ...GJJJJAAAJJJAA ...JJGJAAJJAAAA. ..D.JAJAJAAJJA.. ....D.JAAJA.AJA. .....JAA.AJA.... ................ } # tile 98 (scorpion) { ................ ................ .......JKJKJAA.. ......JA.JKJKKA. .......KA...JJJA ......JA....KKJA ...........JJJKA .......AJKKAJJA. .....AAJKJJJAA.. ...AKKJJAJJAA... ...GJJJJAAAJJJA. ...JJGJAAJJAAAJ. ..D.JAJAJAAJJA.. ....D.JAAJA.JAA. .......JAAJA.... ................ } # tile 99 (lurker above) { .AAAAAAAAAAAAAAA ...AAGFAAGFAAA.. ...AAAAAAAAAAA.. ....AODODODOA... ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ } # tile 100 (trapper) { ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ................ ....AODODODOA... ...AAAAAAAAAAA.. ...AAGFAAGFAAA.. .AAAAAAAAAAAAAAA } # tile 101 (pony) { ................ ................ .....JJ......... ....KKKJ........ ...KKEKJ........ ..KKJKKJ........ ..JJAKKJAA...... ...AKKKJA....... ...KKKKKKKJ..... ...KKKKKKKJJAAA. ...KJKJJJJJAJA.. ...JAJAAAAJAA... ...JAJAAJAJA.... ...L.JAALAJ..... .....LA...L..... ................ } # tile 102 (white unicorn) { ................ ..HP............ ..PHO.NN........ ...PHNNB........ ...ONENB........ ..ONNNNB........ ..NOANNBAA...... ...AONNBA....... ...ONNNONNN..... ..NONNNNONNOAAA. ..N.ONONNONAOA.. ..OAANAAAAOAA... ...LAOAAOAOA.... .....OAALAO..... .....LA...L..... ................ } # tile 103 (gray unicorn) { ................ ..HP............ ..PHO.PP........ ...PHPPN........ ....PGPN........ ...PPPPN........ ..PPAPPNAA...... ...APPPNA....... ....PPP.PPP..... ..P.PPPP.PP.AAA. ..P..P.PP.PA.A.. ..PAAPAAAA.AA... ...LA.AA.A.A.... ......AALA...... .....LA...L..... ................ } # tile 104 (black unicorn) { ................ ..HP............ ..PHO.AA........ ...PHAAJ........ ...AADAJ........ ..AAAAAJ........ ..AAPAAJPP...... ...PAAAJP....... ...AAAAAAAA..... ..AAAAAAAAAAPPP. ..A.AAAAAAAPAP.. ..APPAPPAPAPP... ...LPAPPAPAP.... .....APPLPA..... .....LP...L..... ................ } # tile 105 (horse) { ................ ................ .....JJ......... ....KKKJ........ ..KKKEKJ........ .KKKJKKJAA...... .JJJAKKJAA...... ...AKKKJA....... ...KKKKKKKKJA... ..KKKKKKKKKKJA.. ..KJJKJJJJJKAJA. ..JAAJAAAAAJAJA. ..JAAJAAAJAJAA.. ..LA.JAA.L.JA... .....LA....L.... ................ } # tile 106 (warhorse) { ................ .....JJJ........ ...KKKKJJ....... .KKKKEKJJ....... KKKKKKKJJAA..... JKKKJKKJJAA..... .JJJAKKJJAA..... ...AKKKJJA...... ...KKKKKKKKKJA.. ..KKKKKKKKKKKJA. ..KKJKKJKKJKKJJA ..KJAKJAKJAKJAJA ..KJAKJAKJAKJA.. ..LC.KJALC.KJ... .....LC....LC... ................ } # tile 107 (fog cloud) { .......P........ ....P..P........ .....P.P...P.... ...P.......P.... ..P..P.P.P...... ....PP.PP.P.P... .P..APAPPP..P... ...P.PPPP.PP.... ......PPPPP.P.P. ...P.PPPPP..P... ....P..P.PP.P... .P...P.P...PPP.. ..P.P....PP..... .......P....P... ..P..P.P..P..... ................ } # tile 108 (dust vortex) { ................ ................ ....K..KKKK..... ...K..KKJJJK.... ..K..KJJJJ..K... .KJ.KJJ.JKK..K.. .KJJKJ.JJJJK.... .KJJJJ....JJK... .KKJ.J...J.JKK.. ..KJJ....JJJJK.. ...KJJJJ.JKJJK.. .K..KKJ.JJK.JK.. ..K..JJJJK..K... ...KJJJKK..K.... ....KKKK..K..... ................ } # tile 109 (ice vortex) { ................ ................ ....N..NNNN..... ...N..NNOOON.... ..N..NOOOO..N... .NO.NOO.ONN..N.. .NOONO.OOOON.... .NOOOO....OON... .NNO.O...O.ONN.. ..NOO....OOOON.. ...NOOOO.ONOON.. .N..NNO.OON.ON.. ..N..OOOON..N... ...NOOONN..N.... ....NNNN..N..... ................ } # tile 110 (energy vortex) { ................ ................ ....E..EEEE..... ...E..EEAAAE.... ..E..EAAAA..E... .EA.EAAAAIE..E.. .EAAIAAAAAAE.... .EAAAAAAAAAAE... .EEAAAAAAAAAEE.. ..EAAAAAAAAAAE.. ...EAAAAAAIAAE.. .E..EIAAAAE.AE.. ..E..AAAAE..E... ...EAAAEE..E.... ....EEEE..E..... ................ } # tile 111 (steam vortex) { ................ ................ ....P..PPPP..... ...P..PPBBBP.... ..P..PBBBB..P... .PB.PBBPBPP..P.. .PBBPBPBBBBP.... .PBBBBP.PPBBP... .PPBPB...BPBPP.. ..PBBPP.PBBBBP.. ...PBBBBPBPBBP.. .P..PPBPBBP.BP.. ..P..BBBBP..P... ...PBBBPP..P.... ....PPPP..P..... ................ } # tile 112 (fire vortex) { ................ ................ ....D..DDDD..... ...D..DDCCCD.... ..D..DCCCC..D... .DC.DCCHCDD..D.. .DCCDCHCCCCD.... .DCCCCHHHHCCD... .DDCHCHHHCHCDD.. ..DCCHHHHCCCCD.. ...DCCCCHCDCCD.. .D..DDCHCCD.CD.. ..D..CCCCD..D... ...DCCCDD..D.... ....DDDD..D..... ................ } # tile 113 (baby long worm) { ................ ................ ................ ................ ......CLC....... ......LLL....... .....GGAGG.A.... .....GGAGGAAA... ......LLLAAA.C.. ......LLLAA.CC.. ......CLLCCCCA.. .......LLLCCA... ........CLL..... ................ ................ ................ } # tile 114 (baby purple worm) { ................ ................ ................ .......I........ ......III....... ......III....... .....GGAGG.A.... .....GGAGGAAA... ......IIIAAA.D.. ......IIIAA.DD.. ......IIIDDDDA.. .......IIIDDA... ........III..... ................ ................ ................ } # tile 115 (long worm) { ................ ................ .....CLC........ ....CLLLC....... ....LLLLL....... ...GGGLGGGAA.... ...GAGLGAGAAA... ...GGGLGGGAAA... ....LLLLLAAACC.. ....LLLLLAACCC.. ....CLLLLCCCCA.. .....LLLLLCCA... ......CLLLL..... ................ ................ ................ } # tile 116 (purple worm) { ................ ................ .....DID........ ....DIIID....... ....IIIII....... ...GGGIGGGAA.... ...GAGIGAGAAA... ...GGGIGGGAAA... ....IIIIIAAADD.. ....IIIIIAADDD.. ....DIIIIDDDDA.. .....IIIIIDDA... ......DIIII..... ................ ................ ................ } # tile 117 (grid bug) { ................ ................ ................ ................ ..D....NHCN..D.. .D.D..NHDNCNDED. D.D.D.NNHCND.DED .D...D.NNHDND... .DDD..ENNG.D.DE. ..DDDDEEEEGD..DE D.....DEHEE.D... .D.......H...... ................ ................ ................ ................ } # tile 118 (xan) { ................ ................ ..........GG.... ...HHH...GOGG... .....HH..GGGG... ...HHHHH.GGG.... .......GG...AAA. .....GOGGHHAAAA. ....GOGG..HHAAA. NNNGOGG.AAHHHA.. NANGGGG.AAHAH... NNNGGNNNAAAAAA.. ..GGGNANAA.AAA.. .GGGANNNAA.A.A.. ..G..AAAAAA..... ......AA.AA..... } # tile 119 (yellow light) { ................ ......NA........ ......HA........ ..NA.NHNA.NA.... ...LALHLALA..... ....NHHHNA...... ..NLHHHHHLNA.... NHHHHHHHHHHHNA.. ..NLHHHHHLNA.... ....NHHHNA...... ...LALHLALA..... ..NA.NNNA.NA.... ......HA........ ......NA........ ................ ................ } # tile 120 (black light) { ................ ......AA........ ......AA........ ..AA.AAAA.AA.... ...AAAAAAAA..... ....AAAAAA...... ..AAAAAAAAAA.... AAAAAAAAAAAAAA.. ..AAAAAAAAAA.... ....AAAAAA...... ...AAAAAAAA..... ..AA.AAAA.AA.... ......AA........ ......AA........ ................ ................ } # tile 121 (zruty) { ................ ......FFGF...... ....OOFGFFFF.... ...AOFGFOOKFF... ...FFGFAOAJKKF.. ..FFFFFFJAAJKK.. ..ODOFFJAJJKKJA. ..DDDDJAJJKJJAA. ..JODOAJJJAJJAAA .KKJAJJJKJAJJAAA .KKAAJKKKKJAAAAA ...AJJKKKKJJAAAA ...KJJAAAAKJAAA. ..JKJJJAAJJJJ... ................ ................ } # tile 122 (couatl) { ................ ................ ........I....I.. ....KKAIII..III. ...NAOJAKI.IIIII ...KKJAJJKKK..II ...KKAAIJJJJJ..I ...FAA.I...KJ..I ..FAFA..AAAKJAA. .......AAAJJAAA. ......AKKJJAAA.. ......KJAAAAAJA. .....JJAA...JA.. ......JJJJJJA... ................ ................ } # tile 123 (Aleax) { ................ ......BBBB..I... ..I..BF...B..... ....BF.HHA.B.... ...BF.HHHHA.B.I. ...BF.LFLFA.FB.. .I.BF.LLLLA.FB.. ...BF.ALLA.FB... ..BF.LLAALL.ABA. .BF.LLLLLLLLAFB. .BF.LALLLLALAFB. .BF.LAJJKJALAFB. ..BF..LJJLAAABA. ...BF.LLALAABA.. ..BF.LLAALLAFB.. ................ } # tile 124 (Angel) { ................ ................ ......HHHH...... ................ .......CC....... ......CLLC..AA.. ......PLLP....A. ......NPPPA.A... .....BBLLPPAAA.. .....NNLLPPAAA.. ......BNNPAAAA.. ......BNNPAAAA.. .....BNNNPAA.A.. .....BNNNNPA.... ....BNNNNNNP.... ................ } # tile 125 (ki-rin) { ................ ................ ..LP............ ..PLO.C.C....... ...PLCCD........ ...KCIKD........ ..KCCCCD........ ..CKACCDA....... ...ACCCCCC...A.. ...KCCCKCCKAA... ..CAKCKCKCAKA... ..CAAKAKAKA..... ...L.KALAK...... .....LA..L...... ................ ................ } # tile 126 (Archon) { ................ ......OOOO...... .....OOOOOO..... .....OJLLJO..... .....OLLLLO..... ....OOJLLJOO.... ......AJJA...... .....AAAAAAA.... ....AAAAAAAAA... ...OAAOAAAJLJ... ..OOAOAAAACJC... ....LAAAACCJCC.. .....AAAAAJJJ... ....AAAAAAAA.... ................ ................ } # tile 127 (bat) { ................ ................ ................ ................ ...JJJCACJJJ.... ..JJAAHJHAAJJ... ..JA...JA..AJ... ................ ................ ......AAAA...... ....AAAAAAAA.... ...AAA.AA.AAA... .......AA....... ................ ................ ................ } # tile 128 (giant bat) { ................ ................ ................ ...JK.J.J.JK.... ..KJJJCACJJKJ... .JJJAAHJHAAJJK.. .KJA...JA..AJJ.. ..JA.......AJ... ................ .....AAAAAA..... ...AAAAAAAAAA... ..AAAA.AA.AAAA.. .......AA....... ................ ................ ................ } # tile 129 (raven) { ..AAAA...AAA.... .AAAAAA.AAA..... AAAAAAAAAAA.AA.. A...AAAAAAAAAAA. ......AAAAAAAAA. .....AAAA.....AA .....ADA.......A .....PA......... .....P.......... .........P.P.P.. ........P.P.P.P. .......P.P.P.... ........P.P.P... ...........P.... ................ ................ } # tile 130 (vampire bat) { ................ ................ ................ ...AA.A.A.AA.... ..AAAAAAAAAAA... .AAAA.DAD.AAAA.. .AAA...A...AAA.. ..A.........A... ................ .....AAAAAA..... ...AAAAAAAAAA... ..AAAA.AA.AAAA.. .......AA....... ................ ................ ................ } # tile 131 (plains centaur) { ................ ...KKA.......... ...LLAA......... .AAKKAA......... .LLAALLA........ LALLLLALA....... LALLLKALA.A..... ..LKLKAAAAA..... ..KLKJKJJKAA.... .KJKJKJKJAKAAAA. .KAKJJJJKJAAA.A. .KAAKAAAAKAA.... ..CAKAAJAKA..... ....KAAKAK...... ....CA...C...... ................ } # tile 132 (forest centaur) { ................ ................ ................ ...KKA.......... LA.LLAALA....... LAALLAALA....... .LLAALLA........ ..LLLLA.A....... ..LKLKAAAAA..... ..KLKJKJJKAA.... .KJKJKJKJAKA.A.. .KAKJJJJKJAAAA.. .KAAKAAJAKA..... ..C.KAAKAK...... ....CA...C...... ................ } # tile 133 (mountain centaur) { ................ ................ ...KKA.......... ...LLAA......... ..AKKAA......... .LJJJJLA........ LAJKKJALA.A..... LAKKKKALAAA..... ..JJJJKJJKAA.... .KJJJKJKJAKAAAA. .KAKJJJJKJAAA.A. .KAAKAAAAKAA.... ..CAKAAJAKA..... ....KAAKAK...... ....CA...C...... ................ } # tile 134 (baby gray dragon) { ................ ................ ................ .....BBBA....... ....NPNPPA...... ...BPPPPPA...... ..CHHPABPA.AAA.. .CHCDA.BPAAAAAA. ..D..BPPAAAAAAA. ....BBPPPPPAAAA. ...BOOPPPPPPAAA. ..BPOBPPPPPPPAA. ..BPPBPPOBPAPPA. ..BPABP.ABPAPPA. .....BPAA..PPAA. ...........PAA.. } # tile 135 (baby silver dragon) { ................ ................ ................ .....PPPA....... ....OBOBBA...... ...PBBBBBA...... ..CHHBAPBA.AAA.. .CHCDA.PBAAAAAA. ..D..PBBAAAAAAA. ....PPBBBBBAAAA. ...PNNBBBBBBAAA. ..PBNPBBBBBBBAA. ..PBBPBBNPBABBA. ..PBAPB.APBABBA. .....PBAA..BBAA. ...........BAA.. } # tile 136 (baby shimmering dragon) { .I.............. ...BBBBBBB.I.... ..BF.FFF.FB...I. .BF..BBBA.FB.... BF..NPNPPAFB.I.. BF.BPPPPPA.B.... B.CHHPABPAFBAAI. BCHCDA.BPAAFBAA. B.D..BPPAAAAFBA. B...BBPPPPPAAFB. BF.BOOPPPPPPAAAB BFBPOBPPPPPPPAFB BFBPPBPPOBPAPPFB B.BPABP.ABPAPPFB B....BPAA..PPAAB .B.........PAAB. } # tile 137 (baby red dragon) { ................ ................ ................ .....IIIA....... ....NDNDDA...... ...IDDDDDA...... ..CHHDAIDA.AAA.. .CHCDA.IDAAAAAA. ..D..IDDAAAAAAA. ....IIDDDDDAAAA. ...IHHDDDDDDAAA. ..IDHIDDDDDDDAA. ..IDDIDDHIDADDA. ..IDAID.AIDADDA. .....IDAA..DDAA. ...........DAA.. } # tile 138 (baby white dragon) { ................ ................ ................ .....NNNA....... ....IOIOOA...... ...NOOOOOA...... ..CHHOANOA.AAA.. .CHCDA.NOAAAAAA. ..D..NOOAAAAAAA. ....NNOOOOOAAAA. ...NOOOOOOOOAAA. ..NOONOOOOOOOAA. ..NOONOOONOAOOA. ..NOANO.ANOAOOA. .....NOAA..OOAA. ...........OAA.. } # tile 139 (baby orange dragon) { ................ ................ ................ .....LLLA....... ....NCNCCA...... ...LCCCCCA...... ..CHHCALCA.AAA.. .CHCDA.LCAAAAAA. ..D..LCCAAAAAAA. ....LLCCCCCAAAA. ...LOOCCCCCCAAA. ..LCOLCCCCCCCAA. ..LCCLCCOLCACCA. ..LCALC.ALCACCA. .....LCAA..CCAA. ...........CAA.. } # tile 140 (baby black dragon) { ................ ................ ................ .....AAA........ ....NANAA....... ...AAAAAA....... ..CHHA.AA..PPP.. .CHCD..AA.PPPPP. ..D..AAAPPP.PPP. ....AAAAAAAPPPP. ...AAAAAAAAAPPP. ..AAAAAAAAAAAPP. ..AAAAAAAAAPAAP. ..AAPAA.PAAPAAP. .....AAP...AAPP. ...........APP.. } # tile 141 (baby blue dragon) { ................ ................ ................ .....BBBA....... ....NENEEA...... ...BEEEEEA...... ..CHHEABEA.AAA.. CCHCDA.BEAAAAAA. ..D..BEEAAAAAAA. ....BBEEEEEAAAA. ...BOOEEEEEEAAA. ..BEOBEEEEEEEAA. ..BEEBEEOBEAEEA. ..BEABE.ABEAEEA. .....BEAA..EEAA. ...........EAA.. } # tile 142 (baby green dragon) { ................ ................ ................ .....GGGA....... ....NFNFFA...... ...GFFFFFA...... ..CHHFAGFA.AAA.. .CHCDA.GFAAAAAA. ..D..GFFAAAAAAA. ....GGFFFFFAAAA. ...GOOFFFFFFAAA. ..GFOGFFFFFFFAA. ..GFFGFFOGFAFFA. ..GFAGF.AGFAFFA. .....GFAA..FFAA. ...........FAA.. } # tile 143 (baby yellow dragon) { ................ ................ ................ .....NNNA....... ....DHDHHA...... ...NHHHHHA...... ..CHHHANHA.AAA.. .CHCDA.NHAAAAAA. ..D..NHHAAAAAAA. ....NNHHHHHAAAA. ...NOOHHHHHHAAA. ..NHONHHHHHHHAA. ..NHHNHHONHAHHA. ..NHANH.ANHAHHA. .....NHAA..HHAA. ...........HAA.. } # tile 144 (gray dragon) { ......BBBPA..... .....NPNPPPA.... ....BPPPPPPA.... ..DCHHP..PPA.... CHCHCD..BPPA.... HD.D...BPPA..... ......OBPAAAAAA. ....BOBPAAAAAAAA ..BOOBPA.PP.AAA. .BOOOBPPPPPP.AA. .BOOOBPPPPPPPAA. PPOOBBPPPPPPPPA. BP.OBPPOOPP.P.A. BPAABP.AAPPAPPA. ....BPAA...PP.A. ........PPPP.A.. } # tile 145 (silver dragon) { ......PPPBA..... .....OBOBBBA.... ....PBBBBBBA.... ..DCHHB..BBA.... CHCHCD..PBBA.... HD.D...PBBA..... ......NPBAAAAAA. ....PNPBAAAAAAAA ..PNNPBA.BB.AAA. .PNNNPBBBBBB.AA. .PNNNPBBBBBBBAA. BBNNPPBBBBBBBBA. PB.NPBBNNBB.B.A. PBAAPB.AABBABBA. ....PBAA...BB.A. ........BBBB.A.. } # tile 146 (shimmering dragon) { .I.BF.BBBPAFB... ..BF.NPNPPPAFB.I .BF.BPPPPPPAFB.. .BDCHHP..PPAFBI. CBCHCD..BPPAFB.. HDBB...BPPA.B..I ..BF..OBPAAAABA. .BF.BOBPAAAAAFBA BFBOOBPA.PP.AAFB .BOOOBPPPPPP.AFB .BOOOBPPPPPPPAFB PPOOBBPPPPPPPPFB BP.OBPPOOPP.P.FB BPAABP.AAPPAPPFB ....BPAA...PP.AB ........PPPP.AB. } # tile 147 (red dragon) { ......IIIDA..... .....NDNDDDA.... ....IDDDDDDA.... ..DCHHD..DDA.... CHCHCD..IDDA.... HD.D...IDDA..... ......HIDAAAAAA. ....IHIDAAAAAAAA ..IHHIDAJDDJAAA. .IHHHIDDDDDDJAA. .IHHHIDDDDDDDAA. DDHHIIDDDDDDDDA. ID.HIDDHHDDJDJA. IDAAID.AADDADDA. ....IDAAJJJDDJA. ........DDDDJA.. } # tile 148 (white dragon) { ......NNNOA..... .....IOIOOOA.... ....NOOOOOOA.... ..DCHHO..OOA.... CHCHCD..NOOA.... HD.D...NOOA..... ......ONOAAAAAA. ....NONOAAAAAAAA ..NOONOA.OO.AAA. .NOOONOOOOOOJAA. .NOOONOOOOOOOAA. OOOONNOOOOOOOOA. NO.ONOOOOOO.OJA. NOAANO.AAOOAOOA. ....NOAA...OOJA. ........OOOOJA.. } # tile 149 (orange dragon) { ......LLLCA..... .....NCNCCCA.... ....LCCCCCCA.... ..DCHHC..CCA.... CHCHCD..LCCA.... HD.D...LCCA..... ......OLCAAAAAA. ....LOLCAAAAAAAA ..LOOLCA.CCKAAA. .LOOOLCCCCCCJAA. .LOOOLCCCCCCCAA. CCOOLLCCCCCCCCA. LC.OLCCOOCCKCJA. LCAALC.AACCACCA. ....LCAA.KKCCJA. ........CCCCJA.. } # tile 150 (black dragon) { ......AAAA...... .....NANAAA..... ....AAAAAAA..... ..DCHHA..AA..... CHCHCD..AAA..... HD.D...AAA...... ......AAA..PPPP. ....AAAAPPPPPPPP ..AAAAAAAAA.PPP. .AAAAAAAAAAAAPP. .AAAAAAAAAAAAPP. AAAAAAAAAAAAAAP. AA.AAAAAAAA.AAP. AAPPAA.PPAAPAAP. ....AAPP...AAAP. ........AAAAA... } # tile 151 (blue dragon) { ......BBBEA..... .....NENEEEA.... ....BEEEEEEA.... ..DCHHE..EEA.... CHCHCD..BEEA.... HD.D...BEEA..... ......OBEAAAAAA. ....BOBEAAAAAAAA ..BOOBEA.EE.AAA. .BOOOBEEEEEEJAA. .BOOOBEEEEEEEAA. EEOOBBEEEEEEEEA. BE.OBEEOOEE.EJA. BEAABE.AAEEAEEA. ....BEAA...EEJA. ...P....EEEEJA.. } # tile 152 (green dragon) { ......GGGFA..... .....NFNFFFA.... ....GFFFFFFA.... ..DCHHF..FFA.... CHCHCD..GFFA.... HD.D...GFFA..... ......OGFAAAAAA. ....GOGFAAAAAAAA ..GOOGFA.FF.AAA. .GOOOGFFFFFFJAA. .GOOOGFFFFFFFAA. FFOOGGFFFFFFFFA. GF.OGFFOOFF.FJA. GFAAGF.AAFFAFFA. ....GFAA...FFJA. ........FFFFJA.. } # tile 153 (yellow dragon) { ......NNNHA..... .....DHDHHHA.... ....NHHHHHHA.... ..DCHHH..HHA.... CHCHCD..NHHA.... HD.D...NHHA..... ......ONHAAAAAA. ....NONHAAAAAAAA ..NOONHAJHHJAAA. .NOOONHHHHHHJAA. .NOOONHHHHHHHAA. HHOONNHHHHHHHHA. NH.ONHHOOHHJHJA. NHAANH.AAHHAHHA. ....NHAAJJJHHJA. ........HHHHJA.. } # tile 154 (stalker) { ................ .......PPP...... ......P.P.P..... .....PPPPPP..... .....PP..PPP.... ....PPPPPP.P.... ....P.PPPP.P.... ....P.PPP..P.... ....P..PP..P.... ....P.PPPP.P.... ....P.P..P.P.... ....P.P..P.P.... ......P..P...... ......P..P...... .....PP..PP..... ................ } # tile 155 (air elemental) { ................ ...P.PPP..P..... ..P.PAPA.P...... P..PPPPPP..P.... .P.PPAAPPP...P.. ..PPPAAP.P.P.... ..PAPAAPAP...... P.PAPPP.AP.P.AA. ..PA.PP.AP.AAAA. ..PAPPPPAPAAAA.. ..PAP.APAPAAAA.. ..PAP.APAPAAAAA. ....P.APAAAAAAA. ..P.P.APPAAAAAA. ...PP.APPPA..... ................ } # tile 156 (fire elemental) { ................ .H..LDDD........ ...LDADAC.H..... H..DDDDDD..H.H.. ..LDDAADDD...... ..DDDAADCD.H.... ..DADAACAD...... H.DADDDCAD...AA. ..DACDDCAD.AAAA. ..DADDDDADAAAA.. ..DADCADADAAAA.. H.DADCADADAAAAA. ....DCADAAAAAAA. .H.LDCADDAAAAAA. ..LDDCADDDA..... ................ } # tile 157 (earth elemental) { ..F............. ....CKKK..F..... ...CKAKAJ....F.. ...KKKKKK....... ..CKKAAKKK.F..F. .FKKKAAKJK...... ..KAKAAJAK..F... ..KAKJJJAK...AA. F.KAJKKJAK.AAAA. ..KAKKKKAKAAAA.. ..KAKJAKAKAAAA.. ..KAKJAKAKAAAAA. ....KJAKAAAAAAA. .F.CKJAKKAAAAAA. ..CKKJAKKKA..... ................ } # tile 158 (water elemental) { ................ ....PBBB..E..... .E.PBABAE...E... ...BBBBBB....... ..PBBAABBB.E..E. E.BBBAABEB...... ..BABAABEB.E.... ..BABBBBEB...AA. ..BAPBBEAB.AAAA. E.BABBBBABAAAA.. ..BABEABABAAAA.. ..BABEABABAAAAA. ....BEABAAAAAAA. .E.PBEABBAAAAAA. ..PBBEABBBA..... ................ } # tile 159 (lichen) { ................ ................ ...FFF...FFF.... ..FCFFFFFCCFA... .FCOOFFFCOFFFA.. .FCOOFFFCFFFFA.. ..FFFFFFFFFFA... ...AFFFCCFFFA... ...FFFFCOFFAA... ..FCCFFCOFCFA... ..FCOFFCFFOCFA.. ..FFCFFFCFFFFA.. ...FFFAAFFFFFA.. .....AA.AAAAA... ................ ................ } # tile 160 (brown mold) { ................ ................ ...JJJ...JJJ.... ..JKJJJJJKKJA... .JKCCJJJKCJJJA.. .JKCCJJJKJJJJA.. ..JJJJJJJJJJA... ...AJJJKKJJJA... ...JJJJKCJJAA... ..JKKJJKCJKJA... ..JKCJJKJJCKJA.. ..JJKJJJKJJJJA.. ...JJJAAJJJJJA.. .....AA.AAAAA... ................ ................ } # tile 161 (yellow mold) { ................ ................ ...HHH...HHH.... ..HHHHHHHNHHA... .HHNNOHHNNOHHA.. .HHNNOOHHOOHHA.. ..HHOOHHHHHHA... ...AHHHHHHHHA... ...HHHHNNOHAA... ..HHHHHNNOHHA... ..HNNOHHHONOHA.. ..HHOHHHHHOOHA.. ...HHHAAHHHHHA.. .....AA.AAAAA... ................ ................ } # tile 162 (green mold) { ................ ................ ...FFF...FFF.... ..FGFFFFFGGFA... .FGOOFFFGOFFFA.. .FGOOFFFGFFFFA.. ..FFFFFFFFFFA... ...AFFFGGFFFA... ...FFFFGOFFAA... ..FGGFFGOFGFA... ..FGOFFGFFOGFA.. ..FFGFFFGFFFFA.. ...FFFAAFFFFFA.. .....AA.AAAAA... ................ ................ } # tile 163 (red mold) { ................ ................ ...DDD...DDD.... ..DCDDDDDCCDA... .DLLCDDDCLDDDA.. .DCCCDDDCDDDDA.. ..DDDDDDDDDDA... ...ADDDCCDDDA... ...DDDDCLDDAA... ..DCCDDCLDCDA... ..DCLDDCDDLCDA.. ..DDCDDDCDDDDA.. ...DDDAADDDDDA.. .....AA.AAAAA... ................ ................ } # tile 164 (shrieker) { ................ ................ ................ ................ .....GGGGFF..... ...GGGGIGIDFF... .GGGIIGGGIIFFFF. GIIGIIGGGGGGGDDF GIIGGGGIIGIIGIDF GGGGIGGIIGIIGGFF ..GGGGGGGGGGG... ......FFF..AAAAA ....AGGGFFAAAAAA ...AGGGGGGFAAAA. ...AAAAAAAAAA... ................ } # tile 165 (violet fungus) { ................ ................ ...III...III.... ..ILIIIIILLIA... .IOOLIIILOIIIA.. .ILLLIIILIIIIA.. ..IIIIIIIIIIA... ...AIIILLIIIA... ...IIIILOIIAA... ..ILLIILOILIA... ..ILOIILIIOLIA.. ..IILIIILIIIIA.. ...IIIAAIIIIIA.. .....AA.AAAAA... ................ ................ } # tile 166 (gnome) { ................ ................ ................ .....DF......... ......G......... .....GFF........ ....GGFFF....... ....GLLLF....... .....OLO...AAA.. ...FGOOOFFAAAA.. ...GAGOFAFAAAA.. ....LKNKFAAAA... ....FGAFFAA..... ....GFAFG.A..... ................ ................ } # tile 167 (gnome lord) { ................ ................ ......D......... ......G......... ......G......... .....GFF........ ....HHHHH....... ....GLLLF.....A. .....OLO...AAA.. ...FGOOOFFAAAA.. ...GAGOFAFAAAA.. ....LKNKFAAAA... ....FGAFFAA..... ....GFAFG.A..... ................ ................ } # tile 168 (gnomish wizard) { ................ ................ ................ ................ ......G......... .....GFF........ ....GGFFF....... ....GLLLF....... ...FFOLOFF.AAA.. ...GFOOOFFAAAA.. ...FAGOFAFAAAA.. ...GLKNKFFAAA... ...FFGFFFFA..... ...GFFFFGFA..... ................ ................ } # tile 169 (gnome king) { ................ ................ ................ ................ ....H.C.H....... ....HCHCH....... ....HHHHH....... ....GLLLF...A... .....OLO...AAAA. ...FGOOOFFAAAA.. ...GAGOFAFAAAA.. ....LKNKFAAAA... ....FGAFFAA..... ....GFAFG.A..... ................ ................ } # tile 170 (giant) { ......JJJJAA.... ....JJJJJJJJA... ....JJLLLLJJA... ....JFFLLFFJA... ....JLLLLLLJA... ....ALLAALLAAA.. .....ALLLLJAAAA. ..CCLLJJJJLLCCAA .CLLLCCKCKCLLLCA .LLLKLKCKCLKLLLA .LLAALLCCLLAALLA .LLAAJJJKKJAALLA .CLC.JJJJJKKCLAA ..LL.CLJACLJLLAA .....CLJACLJAAAA ...LLLLJ.CLLLKAA } # tile 171 (stone giant) { ......JJJJAA.... ....JJJJJJJJA... ....JJLLLLJJA... ....JFFLLFFJA... ....JLLLLLLJA... ....ALLAALLAAA.. .....ALLLLJAAAA. ..CCLLJJJJLLCCAA .CLLLCCKCKCLLLCA .LLLAAKCKCLKLLLA .LLPPPACCLLAALLA .LLPPPPAKKJAALLA .CLCPPPAJJKKCLAA ..LLPPALACLJLLAA .....ALJACLJAAAA ...LLLLJ.CLLLKAA } # tile 172 (hill giant) { ......JJJJAA.... ....JJJJJJJJA... ....JJLLLLJJA... ....JFFLLFFJA... ....JLLLLLLJA... ....ALLAALLAAA.. .....ALLLLJAAAA. ...JJKJJJJJJJAA. ..LJJCCKCKCJJLA. ..JLKKKCKCKKLJA. ..LAAKKCCKJAALAA ..LAAJJJKKJAALAA ..LC.JJJJJKKCLAA ..LL.CLJACLJLLAA .....CLJACLJAAAA ...LLLLJ.LLLLKAA } # tile 173 (fire giant) { ....PPDDDDAA.... ....PDDDDDDDA... ...PPDLLLLDDA... ...PDPFLLFFDA... ...PPPLLLLLDA... ....PLLAALLAAA.. ...PPALLLLJAAAA. ...JPDJJJJJJJAA. ..LDDHDKCKCJJLA. ..JLHDDCKCKKLJA. ..LAHDHCCKJAALAA JLAADDHJKKJAALAA JJLJDHHJJJKKCLAA ..LLJJJJACLJLLAA .....CLJACLJAAAA ...LLLLJ.LLLLKAA } # tile 174 (frost giant) { .....KJJJJAA.... ....KJJJJJJJA... ....JJLLLLJJA... ....JEELLEEJA... ....JLLLLLLJA... ....AKJJJJJAAA.. .....KJAAJJAAAA. ....KKJJJJAJAAAA ...KJKJJJJAJJAAA ..KJKKJJJJJKJJAA ..KAAJKJJAJAAJAA ..JAAJKKAKJAAJAA ..LC.JJJJJKKCLAA ..LL.CJJAJLJLLAA .....CLJACLJAAAA ...LLLLJ.CLLLKAA } # tile 175 (ettin) { ....NN..ONOP.... ..NNOOPNNOOPP... ..NPP..NPP..P... ..ALPPLALPPLA... ..APPPPAPPPPA... ..APAAPAPAAPAA.. ..APPPPAPPPPAAA. ..BIIIIJJJIIIBAA .BPPPIIIIIIPPPBA .PPPFPIIIIPFPPPA .PPAAPIIIIPAAPPA .PPAAIIIIIIAAPPA .BPB.IIFFIIABPAA ..PP.BPAABPAPPAA .....BPAABPAAAAA ...PPPPA.BPPPFAA } # tile 176 (storm giant) { ......JJJJAA.... ....JJJJJJJJA... ....JJLLLLJJA... ....JFFLLFFJA... ....JLLLLLLJA... ....ALLAALLAAH.. .....ALLLLJAHAA. ...JJKJJJJJHHAA. ..LJJCCKCKHHLAA. ..JLKKKCKHHHHHH. ..LAAKKCCKJAHHAA ..LAAJJJKKJHHALA ..LC.JJJJJKHAAAA ..LL.CLJACHAAAAA .....CLJACCJAAAA ...LLLLJ.LLLLKAA } # tile 177 (titan) { .....AAAAAAA.... ....AALLLLAAA... ....A..LL..AA... ....ALLLLLLAA... ....ALLAALLAAA.. .....ALLLLJAAAA. ..CCJJJJJJJJCCA. .CLLLCCKCKCLLLCA .LLLKJKCKCJKLLLA .LLAAJJCCJJAALLA .LLAAJJCCJJAALLA .LLAAJJJKKJAALLA .CLC.JJJJJKKCLAA ..LL.CLJACLJLLAA .....CLJACLJAAAA ...LLLLJ.CLLLKAA } # tile 178 (minotaur) { ................ .O..........O... .OOOJJJJJJOOO... ..OOJJKJJJOO.... ...JGAKJGAJA.... ...JJJKJJJJA.... ....JJKJJJAAA... ....JKKKJAAAA... ..CLJAJAKALCAA.A .CLLJJJJJALLCAAA .LLCLAAAALCLLAA. .LAACLLLLCAALAA. .LL.JJJJJJJLLAAA .LL.JJJJJJJLLAAA ....CLCACLCAAAAA ..LLLLL.LLLLLAA. } # tile 179 (jabberwock) { ................ ...DP........... ....DP.ADOO..... ..DAIDADIPAD.... ...DIAPIPA...... ...DBDDDA....... ..IBBDADDA..AA.. .DDDDAODDIAAAA.. ..OAOA.DDAIAAA.. ..IOAODDAAADDAA. ..DDDADDDDAIDA.. ...AAADDIDIDDD.. ....IDDAIDDDDA.. ....IDAAIDAA.... ...IDAA..ID..... ................ } # tile 180 (vorpal jabberwock) { ................ ...GP........... ....GP.AGOO..... ..GAFGAGFPAG.... ...GFAPFPA...... ...GHGGGA....... ..FHHGAGGA..AA.. .GGGGAOGGFAAAA.. ..OAOA.GGAFAAA.. ..FOAOGGAAAGGAA. ..GGGAGGGGAFGA.. ...AAAGGFGFGGG.. ....FGGAFGGGGA.. ....FGAAFGAA.... ...FGAA..FG..... ................ } # tile 181 (Keystone Kop) { ................ ....AA.......... ...AAAA......... ...AOAA...C..... ..AAAAAA..C..... ...LLLL...C..... ....LL....C..... ...AAAA.AAA..... ..AAAAAAAAC.P... .AA.AAAAA.PPPP.. ..AAAAAA.PPPPPP. ....AAAAPPPAPP.. .A.AAAAAAPAAA... AAAAA.PAAAAA.... ..AA....AA...... ................ } # tile 182 (Kop Sergeant) { ................ ....AA.......... ...AOOA......... ...AOOA...C..... ..AAAAAA..C..... ...LLLL...C..... ....LL....C..... ...AAAA.AAA..... ..AAAAAAAAC.P... .AA.AAAAA.CPPP.. ..AAAAAA.PPPPPP. ....AAAAPPPAPP.. .A.AAAAAAPAAA... AAAAA.PAAAAA.... ..AA....AA...... ................ } # tile 183 (Kop Lieutenant) { ................ ....AA.......... ...AOOA...C..... ...AOOA...C..... ..AAAAAA..C..... ...LLLL...C..... ....LL....C..... ..OAAAO.AAA..... .OAAAAA.AAC.P... .AA.AAAAA.CPPP.. ..AAAAAA.PPPPPP. ....AAAAPPPAPP.. .A.AAAAAAPAAA... AAAAA.PAAAAA.... ..AA....AA...... ................ } # tile 184 (Kop Kaptain) { ................ ....AA....C..... ...AHHA...C..... ...AHHA...C..... ..AAAAAA..C..... ...LLLL...C..... ....LL....C..... .HHAAAAHHAA..... .AAAAHAAAACCC... .AA.AHAAA.CPPP.. ..AAAHAA.PCPPPP. ....AAAAPPPAPP.. .A.AAAAAAPAAA... AAAAA.PAAAAA.... ..AA....AA...... ................ } # tile 185 (lich) { ................ ................ ...OOO.......... ..AOAOO......... ..OOOOO......... ..OO.O.......... .....PPP........ ...OOPPP....AAA. ..O.PPPPPA..AAA. .O...PPPP.AAAAA. ....O.PPPAAAA.A. ......PPPAAA.A.. .....OPAP.A..... ...OOOA.OA...... ......OOO....... ................ } # tile 186 (demilich) { ................ ................ ...OOO.......... ..AOAOO......... ..OOOOO......... ..OO.O.......... .....PPP........ ...OOPPP....AAA. ..O.PPPPPA..AAA. .O...PPPP.AAAAA. ....L.PPPAAAA.A. ......LPPAAA.A.. .....LLAL.A..... ...LLLA.LA...... ......LLL....... ................ } # tile 187 (master lich) { ...H............ ...HCH.H........ ...HHHCH........ ..AOAOHH........ ..OOOOO......... ..OO.O.......... .....PPP........ ...PPPPP....AAA. ..PPPPPPPA..AAA. .O..PPPPP.AAAAA. ....OPPPPAAAA.A. ......PPPAAA.A.. .....OPAP.A..... ...OOOA.OA...... ......OOO....... ................ } # tile 188 (arch-lich) { ................ ................ ...OOO.......... ..DODOO......... ..OOOOO......... H.OO.O.......... A....PPP........ A..OOPPP....AAA. .AO.PPPPPA..AAA. .O...PPPP.AAAAA. .A..O.PPPAAAA.A. ..A...PPPAAA.A.. ..A..OPAP.A..... ..AOOOA.OA...... ......OOO....... ................ } # tile 189 (kobold mummy) { ................ ................ ................ ...N...N........ ...NONONO....... ...OAOAO.OP..... ....ONN...A..... ...ONODNA.AA.... ..OLONNONAAA.A.. ..NALONANAAAAA.. ..NAOLOAOAAAAA.. ....NOLAAAAAA... ....NANAAAA..... ...OOANOA....... ................ ................ } # tile 190 (gnome mummy) { ................ ................ ................ ................ ......G......... .....GGFO....... ....GGFFOOP..... ....GDODF....... .....ONO...AAA.. ...NONOONOAAAA.. ...OANLOAOAAAA.. ....NNOLOAAAA... ....NOANDAA..... ....NOAOO.A..... ................ ................ } # tile 191 (orc mummy) { ................ ................ ................ .....OA......... ....NOOP........ ....DODPOP...... ....OOOA........ ..OOOOOOOA.AA... ..OOOOOOO.AAA... ..OAOOOAACCC.... ..OAOOOCCAAA.... ....OCCOAAAAAA.. ...CCAOOAAAA.... ..OOOAOOOA...... ................ ................ } # tile 192 (dwarf mummy) { ................ ................ ................ ................ ......B......... .....BBEO....... ....BBEEEOP..... ....BDODE....... .....ONO...AAA.. ...NONOONOAAAA.. ...OANLOAOAAAA.. ....NNOLOAAAA... ....NOANDAA..... ....NOAOO.A..... ................ ................ } # tile 193 (elf mummy) { ................ ................ .........O...... .......OOOP..... ......OOOOP..... ......OEOEAP.... ......OOOOA..... ......AOOA....A. ......OAAO..AAA. .....OOOOOOAAAA. ....OALOOLAOAAA. ....OADOOOAOAA.. ......OOAOAA.A.. .....OOA.OOA.... ................ ................ } # tile 194 (human mummy) { ................ ................ ...ONNO......... ...NNNNOP....... ..PANAN.OPP..... ..PNNNN......... ..ONOONNP....... .ONLNNOOO....... .NJNOOOOO..AAA.. .OJOOOODN.AAAA.. .NJOLNOAOAAAAAA. .OCNO.NKNAAAAA.. .N.OO.OLAAAAAAA. ...OOAOOAAA..... ..NNN.NNNA...... ................ } # tile 195 (ettin mummy) { .....NN..ONOO... ...NNOOONNOOOO.. ...NOOOONOOOOOO. ...OFOFOLOFOFO.O ...OOOOOLOOOOO.P ...NOOOOLNNOOOA. ...ONOOOLOOOOAAA ..OOOONNNNNNNOAA .ONNNNNNOONOOOOA .ONODNNOOOOOOOOA .NNAAONNONOAAOOA .NOAAONOONLAAOOA .OOO.ONOONOOOOAA ..OO.NNOANOLOOAA .....NOOANOOAAAA ...OOOOO.OOOOKAA } # tile 196 (giant mummy) { ......ONOOAA.... ....ONNNOOOOA... ....NNOOOOOOO... ....NFFOOFFOOP.. ....NONOOOOOAOP. ....AONOOOOAAAP. .....ANOOODAAAA. ..OOOONOOONNNOAA .ONNNNNOOOOOOOOA .ONODNNLOOOOOOOA .NNAAONOLNOAAOOA .NOAAONOONLAAOOA .OOO.ONOONOOOOAA ..OO.NNOANOLOOAA .....NOOANOOAAAA ...OOOOO.OOOOKAA } # tile 197 (red naga hatchling) { ................ ................ ................ ................ ....K........... ...KLK.......... ...LLLA......... ...ALAA......... ...LALA......... ...LLLA......... ...LLLAA........ ...LDLAA........ ...IDDAAAAADA... ...IDDDAAADDA... ....IIDDDDDA.... ................ } # tile 198 (black naga hatchling) { ................ ................ ................ ................ ....K........... ...KLK.......... ...LLLA......... ...ALAA......... ...LALA......... ...LLLA......... ...LLLA......... ...LALAA........ ...AAAPA..PAA... ...AAAAPPPAAA... ....AAAAAAAA.... ................ } # tile 199 (golden naga hatchling) { ................ ................ ................ ................ ....K........... ...KLK.......... ...LLLA......... ...ALAA......... ...LALA......... ...LLLA......... ...LLLAA........ ...LHLAA........ ...NHHAAAAAHA... ...NHHHAAAHHA... ....NNHHHHHA.... ................ } # tile 200 (guardian naga hatchling) { ................ ................ ................ ................ ....K........... ...KLK.......... ...LLLA......... ...ALAA......... ...LALA......... ...LLLA......... ...LLLAA........ ...LFLAA........ ...GFFAAAAAFA... ...GFFFAAAFFA... ....GGFFFFFA.... ................ } # tile 201 (red naga) { ................ ....KK.......... ...KLLK......... ...LLLLA........ ...ALLAA........ ...LAALA........ ...LLLLA........ ...LLLDA..AA.... ...LDLDA.AAAA... ...IDDDAAAIIA... ...IDDDAIDDDIDA. ...IDDDIDDDDDDDA ...IDDDDDDAA.DDA ....DDDDDA..DDA. .....DDAA..DDA.. ..........DA.... } # tile 202 (black naga) { ................ ....KK.......... ...KLLK......... ...LLLLA........ ...ALLAA........ ...LAALA........ ...LLLLA........ ...LLLAA........ ...LALAA..PPP... ...AAAAPPPAAP... ...AAAAPAAAAAAP. ...AAAAAAAAAAAAP ...AAAAAAAPP.AAP ....AAAAAP..AAP. .....AAPP..AAP.. ..........AP.... } # tile 203 (golden naga) { ................ ....KK.......... ...KLLK......... ...LLLLA........ ...ALLAA........ ...LAALA........ ...LLLLA........ ...LLLHA..AA.... ...LHLHA.AAAA... ...NHHHAAANNA... ...NHHHANHHHNHA. ...NHHHNHHHHHHHA ...NHHHHHHAA.HHA ....HHHHHA..HHA. .....HHAA..HHA.. ..........HA.... } # tile 204 (guardian naga) { ................ ....KK.......... ...KLLK......... ...LLLLA........ ...ALLAA........ ..CLAALC........ ..LLLLLL........ ..CLLCLC..AA.... ...CLLCA.AAAA... ...GLFCAAAGGA... ...GFFFAAFFFGFA. ...GFFFGFFFFFFFA ...GFFFFFFAA.FFA ....FFFFFA..FFA. .....FFAA..FFA.. ..........FA.... } # tile 205 (ogre) { ................ ................ ....CLLLC....... ..LCKKLKKCL..... ...LAALAALJA.... ...CLLLLLCJA.... ....CAAACJAAA... ....LDDDLAAAA... ..CLJLLLKALCAA.A .CLLAJJJJALLCAAA .LLCLAAAALCLLAA. .LAACLLLLCAALAA. .LC.HHHBHHACLAAA .LL.JJJJJJALLAAA ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } # tile 206 (ogre lord) { ................ ................ ....CLLLC....... ..LCKKLKKCL..... ...LAALAALJA.... ...CLLLLLCJA.... ....CLLLCJAAA... ....LAAALAAAA... ..JKJLLLKAKJAA.A .CLKAJJJJAKLCAAA .LLJKAAAAKJLLAA. .LAAJKKKKJAALAA. .LC.HHHBHHACLAAA .LL.JJJJJJALLAAA ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } # tile 207 (ogre king) { ...H..C..H...... ...HDCHCDH...... ...HHHHHHH...... ..LCKKLKKCL..... ...LAALAALJA.... ...CLLLLLCJA.... ....CLLLCJAAA... ....LAAALAAAA... ..JKJLLLKAKJAA.A .CJKAJJJJAKJCAAA .LJJKAAAAKJJLAA. .LAAJKKKKJAALAA. .LC.HHHBHHACLAAA .LL.JJJJJJALLAAA ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } # tile 208 (gray ooze) { ................ ................ ................ .....PBPA....... ...PBBBPBA...... ..BBNNBPPBAA.... .BBNNPPPBBPAAA.. PBBBPPPBPBBAAA.. BBBPBPPPPPBPAAA. BBPBPPPPPPPBAAA. PBPPBPPPBBPPAAA. .PBBPPPBAAPPPAA. ...PBBBAAAKPPJ.. ........ACPPAK.. .........KCCCJ.. ................ } # tile 209 (brown pudding) { ................ ................ ................ ................ ............J... ....JKKJJJ..JJ.. ...KKKCJJJJJ.... ..KKNNJNNJJJ.... ..KJANJANJJJA... ..KKJJJJJCJJAA.. ..JKJJCJJJJJAA.. ...JJJJJJJJAAA.. ....JJJJJJAAA... .....AAAAAAA.... ................ ................ } # tile 210 (green slime) { ................ ................ ................ ................ ................ ................ ............G... .....G......G..G .G....G..G.NGN.G ..NG.NGGNGGGGGGG ..GGNGGNGGGFGGF. GGNGGGGGGGGGFF.G .NGGGGGFGFG..... NGGGGFGGFG.G..GF NGGFGGF..GF..... ..GGF..GGF..G... } # tile 211 (black pudding) { ........A....... ........AA...... .....AAA........ ....AAAAA....... ....CACAA....... ....DADAA....... ....AAAAA....... ....AAAAA....... ....AAAAA....... .....AAAAA...... .....AAAAA...... ......AAAAA..... ......AAAAAA.... .......AAAAAA.A. ........AAAAAAAA ..........AAAA.. } # tile 212 (quantum mechanic) { ................ ......LLLL...... ...FGGCLCGGF.... ...GNNGLGNNGL... B.BGANGGGANGL... B.BFGGCLCGGFL... BIB..CLLLCCL.... BILN.LLAALLAAAA. BILNN.LLLLJAAAA. BIB.NNJJJJNAAA.. BIB.BNNNONNNAA.. .B...NNNONNLAA.. .....NBEBENA.A.. .....NBEBENN.... ....NAAEBAANN... ................ } # tile 213 (rust monster) { ................ ....EEEE........ ...EEHEHE....... ...EEEAEE....... ...EEPAPE....... ...EPEAEP...E... ....EEEE.AAEE... ....EEEEEAAEEE.. ...EEEEEEEAEAEE. ..EEEEEEAAAAE... ..EEAEEEEAEEEA.. ..AAEEEEEEEEEAA. ....AEEEEEEEAAA. .....EEEEEAA..A. ......AAAA...... ................ } # tile 214 (disenchanter) { ................ ....PPPP........ ...PPDPDP....... ...PPPAPP....... ...PPOAOP....... ...POPAPO...P... ....PPPP.AAPP... ....PPPPPAAPPP.. ...PPPPPPPAPAPP. ..PPPPPPAAAAP... ..PPAPPPPAPPPA.. ..AAPPPPPPPPPAA. ....APPPPPPPAAA. .....PPPPPAA..A. ......AAAA...... ................ } # tile 215 (garter snake) { ................ ................ ................ ....KKA......... ...NAOKA........ ...KKAKA........ ...KKAKA....KA.. ....APKAP..KAPP. .....PKAPP.KAP.. .....KAAP..KAP.. ....KAAP..KAAP.. ....KAAPPKAAP... ....KAAKKAAP.... .....KAAAAP..... ................ ................ } # tile 216 (snake) { ................ ................ ................ ....KKA......... ...NAOJA........ ...KKJAJ........ ...KKAAJ....KK.. ...FAAKJ...KJAA. ..FAFAKJAA.KJA.. .....KJAA..KJA.. ....KJAA..KJJA.. ....KJAAAKJJA... ....KJJJJJJA.... .....KJJJJA..... ................ ................ } # tile 217 (water moccasin) { ................ ................ ................ ....AAA......... ...AAAAA...AA... ...OAOAAA.AA.... ...AAA.AA.AA.... ...DA..AA.AA.... ..D.D.AAA..AA... .....AAA...AA... .....AAA...AA... ....AAA...AAA... ....AAAAAAAA.... ....AAAAAAA..... .....AAAAA...... ................ } # tile 218 (python) { ................ ................ ................ ...KKKA.....JJ.. ...GAGJA...JJJ.. ..JKKJAJ..KJJ... ..KKKAJJ..KJJ.AA ..KKAAKJA.KKJAA. .....AKJAA.KJAA. ....JKJAA..KJJA. ...JJJAA..KJJJA. ...JJJAAAKJJJA.. ...JJJJJJJJJAA.. ....JJJJJJJAA... .....JJJJJAA.... ................ } # tile 219 (pit viper) { ................ ................ ................ ....AAA......... ...AAAAA...AAA.. ...OAAAAA.AA.AA. ...AA..AA.AA.AA. ...D...AA.AA..A. ......AAA..AA.A. ......AA...AA... .....AAA...AA... .....AA...AAA... .....AA..AAA.... .....AAAAAA..... ......AAAA...... ................ } # tile 220 (cobra) { ................ ................ ................ ....AAA......... ...AAAAAA....... ..PA..AAAA...... ..A..AAAAA..AA.. ..D..AAAAA....A. ......AAA.....A. ......AA..AAAA.. .....AA..AA..... ....AA...AA..... ....AA....AAAA.. ....AAA......AA. .....AAAAAAAAA.. ................ } # tile 221 (troll) { ................ ..AAAAAA........ AAAANANA........ .AAKKKJJA....... AAAKAAAKA....... AKAKAAAKAA...... KJJAKKKAJKA..... KJAJAAAJJJA..... KJAJKKJJKJA..... .KJJAFGFJJAAAA.. ..KJA.PFJAAAA... ...AFAGFAAAAAA.. ...GFAGP.AA.AA.. ..KJJAKJAA.AA... ..KJA..KA....... ................ } # tile 222 (ice troll) { ................ ..OONOOO........ NONOAOAOO....... .NOKKKJJO....... NOJKAAAKOO...... OKJKAAAKAO...... KJJAKKKAJKA..... KJAJAAAJJJA..... KJAJKKJJKJA..... .KJJAEBEJJAAAA.. ..KJA.PEJAAAA... ...AEABEAAAAAA.. ...BEABP.AA.AA.. ..KJJAKJAA.AA... ..KJA..KA....... ................ } # tile 223 (rock troll) { ................ ...AAAAA........ .AAANANAAAA..... .AAKKKJJAA...... AAAKAAAKAAAA.... AKAKAAAKAAA..... KJJAKKKAJKAA.... KJAJAAAJJJA..... KJAPAKJJKJA..... PKJPPAGFJJAAAA.. PPPPPAFFJAAAA... .PPPAAGFAAAAAA.. ...AFAGF.AA.AA.. ..KJJAKJAA.AA... ..KJA..KA....... ................ } # tile 224 (water troll) { ................ ...AAAAA........ ..AANANAA....... .AAKKKJJAA...... .AAKAAAKAA...... .KAKAAAKAA...... KJJAKKKAJKA..... KJAJAAAJJJA..... KJAJKKJJKJA..... .KJJAEBEJJAAAA.. ..KJA.PEJAAAA... ...AEABEAAAAAA.. ...BEABP.AA.AA.. ..KJJAKJAA.AA... ..KJA..KA....... ................ } # tile 225 (Olog-hai) { ...PPPPP........ ..PPAAAPP....... ..PANANAP....... ..PAAAAAP....... .PPAAAAAPP...... PPPAAAAAPPP..... AAPPAAAPPAA..... AAAPPPPPAAA..... AAAPPPPPAAA..... .AAAAPPPAAAPPP.. PONNNNNNAACPP... ...APAPPAPPPPP.. ...PPAPP.PP.PP.. ..AAAAAAAP.PP... ..AAA.AAA....... ................ } # tile 226 (umber hulk) { ................ ...AAAAA........ ..AAAAAAA....... .ADADADADA...... .AAAAAAAAA.A.... .AAAOAOAAA.AA... .A.AOAOA.AAA.... .A.AAAAAPAA..... .AAAAAAAP....... .A.AAAAA.PPPPPP. ...AA.AA.PPPPP.. ...AA.AAPPPPPPP. ...AAPAAPPPP.... ..AAAPAAAPP..... .AAAP..AAP...... ................ } # tile 227 (vampire) { ................ ................ .....AAA........ ....AAOAA....... .ADDAGAGADA..... ..ADALLOAD...... .AAAAAAAAA...... ..AAAAAAAA...... ...AAAAAAA...... ..ADAAAAAAPPPPP. ..ADDAAAAAPPPP.. ..AAAAAAAAPPP... .....AAPAAPP.... ....AAP..AP..... ................ ................ } # tile 228 (vampire lord) { ................ .....AAAA....... .N..AAOOAA...... .NDDAGAAGADA.... .NADALLLOAD..... AAAAAAAAAAA..... AAAAAAAAAAA..... .AAAAAAAAAA..... .NAAAAAAAAA..... .N.AAAAAAAAPPPPP .NADAAAAAAAPPPPP .NADDAAAAAAPPPP. .NAAAAAAAAAPPP.. .N...AAAPAAPP... .N..AAPP..AP.... ................ } # tile 229 (vampire mage) { ................ ................ .....AAA........ ....AAOAA....... .ADDAGAGADA..... ..ADALLOAD...... .AAAA.A.AA...... ..AAAACAAA...... ...AAADAAA...... ..ADAAAAAAPPPPP. ..ADDAAAAAPPPP.. ..AAAAAAAAPPP... .....AAPAAPP.... ....AAP..AP..... ................ ................ } # tile 230 (Vlad the Impaler) { ................ ..N..AAAA....... ADNDAAOOAADDDA.. .ANDAGAAGADDA... ..NDALLLOADA.... ..NAAAAAAAAAAAAA .HHHDAAAAADDDDDA HEHEHJAAAADDDAA. LLLLLJAAAADDAAPP .LLLJAAAAADDAPPP ..NJDAAAAADAPPPP .ANDDAAAAAAAPPPP .ANAAAAAAAAPPPP. ..N..AAAPAAPPP.. ..N.AAPP..AP.... ................ } # tile 231 (barrow wight) { ................ ................ ...LLO.......... ..DLDLO......... ..LLLLO......... ..LJL..P........ ..OOO.PP...AAAA. ..POO.PP.AAAAAA. .LPOO.PP.PAAAA.. .JJOO.PP.PAAAA.. .J.O..PL.PPAAA.. .J.O.PPPPPPAAA.. .J...PPPPPPPAA.. .J..LLPPPPPPA... .J.....LLAA..... ................ } # tile 232 (wraith) { ................ ................ ...PPPPP........ ...PAAPPP....... ....PAAPP....... ....PAAPP....... ..PP.PPP.P...... .OLAPPP.PP...... ..AAPPPPAP..AAA. ..PPPPPOLPAAAAA. ...A.PPAAAAPPA.. .....PPAPPPPA... ......PPPPA..... ................ ................ ................ } # tile 233 (Nazgul) { ................ ................ ...PPPPP........ ...PAAPPP....... ....PAAPP....... ....PAAPP....... ..PP.PPP.P...... .OLAPPP.PP...... .OPAPPPPAP..AAA. ..PAPPPPAP..AAA. ..PA.PPPLP..AAA. ..PP.PPOLPAAAAA. ...AAPPOAAAPPA.. .....PPAPPPPA... ......PPPPA..... ................ } # tile 234 (xorn) { ................ ................ ................ ...OB.OP.BP..... ...BBBBPPPP..... ...B............ ...DDBB.BDDA.A.. ...DDBB.PDDAAAA. ...B.......AAAA. ...BOB.BPP.AAAA. ...BBB.PPP.AAAA. ...B.......AAA.. ...BOBBPPBPAA... ...BO.BP.PPA.... ................ ................ } # tile 235 (monkey) { ................ ................ ................ ................ ................ .......KKA...... ......KLLJA..... ......KLLJA..... .......KJA...... .....KKKKKJAA... ....KJKLLJJJAA.. ....LAKLLJALAA.. ......KJJJAAAA.. ......JAAJAAA... .....JJA.JJA.... ................ } # tile 236 (ape) { ................ ................ ......KKKJ...... .....JJJJJJ..... ....KCELECJJ.AA. ....KLLLLCAJAAAA ...KKCLACCAJJAAA ..KKKKCCCAJKJJAA ..KKAKJAAJJAJJAA ..KAAKJJJJJAAJAA ..LC.KJJJJJKCLAA ..LL.CJJAKLJLLAA .....CLJACLJAAAA ...LLLLJACLLLKA. ................ ................ } # tile 237 (owlbear) { ................ ....K.....K..... ....CK...KK..... ....CKKKKKK..... ...KOOOKOOOK.... ...KOOOKOOOKA..A ...KOOAJAOOKAAAA ..CKCJJHJJKAKAAA .CKKKCKLKKAJJKAA .KJJJJCKKJJJJJAA .KJJJPAKJPJJJJAA ..KJJJAKJJJJJAAA ...JJPAKJPJJAAA. ...JAAJAJAAJAA.. ...PJPJAJPJPA... ................ } # tile 238 (yeti) { ................ ....BNNN........ ...BNANAP....... ..BNNNNNNP...... ..NNNADANN...... ..NNNNNNPN...... ..N.NNBPPNP..... ..N.NNNNANP..AA. ..NNBNNNPN.AAAA. ....NNNNP.KAAA.. ....NN.NPAKKAA.. ....NB.NPAACKAA. ....NNANPAAKKJA. ...BNNANNPAACKA. ..BNNA..NNA..... ................ } # tile 239 (carnivorous ape) { ................ ................ ......KKKJ...... .....JJJJJJ..... ....KCELECJJ.AA. ....KLLLLCAJAAAA ...KKCAAACAJJAAA ..KKKCDDDCAKJJAA ..KKAKCCCAJAJJAA ..KAAKJAAJJAAJAA ..LC.AJJJJJKCLAA ..LLDDAJAKLJLLAA ...DDALJACLJAAAA ..DDALLJACLLLKA. ................ ................ } # tile 240 (sasquatch) { ................ ....CCCCC....... ...CGAJGAJ...... ..CKKKKJJJ...... ..CKKAAAKJJ..... .CKKKAAAKKJ..... .CKJKKKKKKKJ.... .CKAJJJJJAKJ.... .CKAJKKKJAKJ.AA. .CKJAJKJACKJAAAA .CKJAJJJACKJAAA. ..J.AJAKKAJAAAAA ...CKJAKKJAAAAA. .KCKJJACKJKJAA.. .CJJJKACKJJKA... ................ } # tile 241 (kobold zombie) { ................ ................ ................ ...N...N........ ...NGFBN........ ...GABAB........ ....GBFA..A..... ...GBABFA.AA.... ..GFBBBIKAAA.A.. ..BAFBFFEAAAAA.. ..BAFBFFAAAAAA.. ....FBFAAAAAA... ....BABAAAA..... ...BBABBA....... ................ ................ } # tile 242 (gnome zombie) { ................ ................ ................ ................ ......G......... .....GFF........ ....GGFFF....... ....GDFDF....... .....PFP...AAA.. ...FGFPFEGAAAA.. ..GAAGFFFAGAAA.. ....AKNKFAAAA... ....FGAFFAA..... ....GFAFG.A..... ................ ................ } # tile 243 (orc zombie) { ................ ................ ................ .....OA......... ....NOPA........ ....GPGA........ .....PFA........ ..KCCAKKKA.AA... .BBPCKJ.BBAAA... BB.AGGFAABBA.... B..AJJPAAABA.... ....BAPPPAAAAA.. ...BJAAEPAAA.... ..BPPAAAPP...... ................ ................ } # tile 244 (dwarf zombie) { ................ ................ ................ ................ ......B......... .....BEE........ ....BBEEE....... ....BFFFE....... .....PFP...AAA.. ...BBPPPEEAAAA.. ..FBABPEAEAAAA.. ..F.EBBEFAAAA... ....EBAEEAA..... ....BEAEB.A..... ................ ................ } # tile 245 (elf zombie) { ................ ................ .........G...... .......GGF...... ......GGGGA..... ......FEFEA..... ......FFFFA..... ......AFDA....A. ......GAAG..AAA. ....FFGGGFFFAAA. ...FAAAGFAAAFAA. .....AGGGFAAAA.. ......GFAFAA.A.. .....KDA.FKA.... ................ ................ } # tile 246 (human zombie) { ......AAA....... .....FFGAA...... .....AGAFA...... .....FFGFA...... ....FKF..JJ..... ....JJJFJKJ..... ...FJ.KJJAKJ.... ..FK..KFJFFJ.... ..G...KKJG...... .....BP.BPAAAAA. .....FPAPFAAAA.. .....BFABFAAAA.. .....PFABPAA.... .....BFABFA..... ....GGAGGA...... ................ } # tile 247 (ettin zombie) { ....NN..ONOP.... ..NNOOPNNOOPP... ..NFF..NFF..P... ..ADFFDADFFDA... ..AFFFFAFFFFA... ..AFAAFAFAAFAA.. ..AFFFFAFFFFAAA. ..GIIIIJJJIIIGAA .GFFFIIIIIIFFFGA .GFFFFIIIIFFFFFA .FFAAFIIIIFAAFFA .FFAAIIIIIIAAFFA .FFF.IIFFIIAGFAA ..FF.GFAAGFAFFAA .....GFAAGFAAAAA ...FFFFA.GFFFFAA } # tile 248 (ghoul) { ......AAA....... .....OOOAA...... .....DODOA...... .....OOOOA...... ....PPOOOPP..... ....PPPPPPP..... ...PP.PPPAPP.... ..PP..PPPOOP.... ..O...PPPO...... .....PP.PPAAAAA. .....PPAPPAAAA.. .....PPAPPAAAA.. .....PPAPPAA.... .....PPAPPA..... ....OOAOOA...... ................ } # tile 249 (giant zombie) { ......JJJJAA.... ....JJJJJJJJA... ....JJFFFFJJA... ....JDDFFDDJA... ....JFFFFFFJA... ....AFFAAFFAAA.. .....AFFFFJAAAA. ..GGFFJJJJFFGGAA .GFFFGGFFFFFFFCA .FFFKFFFFFFKFFFA FFFAAFFFFFFAAFFA FFAA.JJJKKJAAFFA FFA..JJJJJKAGFAA .....GFAGFFAFFAA ....GFFAGFFAAAAA ...GFFAAGFFFAAAA } # tile 250 (skeleton) { ................ ................ ...OOO.......... ..AOAOO......... ..OOOOO......... ..OO.O.......... ......O......... ....OOOOO...AAA. ...OA.OOOA..AAA. ..OA.OAAO.AAAAA. ....OA.OOOAAA.A. ......OOOAAA.A.. .....O.AO.A..... ...OOOA.OA...... ......OOO....... ................ } # tile 251 (straw golem) { ......LJ........ ......LJHJ...... ....HJLJH...A... ....AAAAAL.....A ....DAADAL.A.AA. ....LJHJL..AAAA. ....LLHJLHHCHHL. ...HHLJL.AJLJL.A .HHJJLLLLAAA.AA. ..JL..LALHAAAAAA .LL..CJLHJHAAAAA .....HJLAHJHAAA. .....HJAACALHAAA ....CJLAAJHALHA. ....HALA.AHAAL.. ..........L..... } # tile 252 (paper golem) { ................ .......OA....... .....NNNOA...... .....ONNNOA..... ......ONNOA..... .......NOA...... ..NNOA.NOA...... ..NONOAOAONNOA.. ..OAOANNOAOOOA.. ......NNNOAAAAA. ......ONOAAAAAA. .......OOAAAAAA. .....NOAAOAAAAA. .....NOA..NOAA.. ....OOA...OOA... ................ } # tile 253 (rope golem) { ................ ................ ......OOO....... .....O...O...... .....O...O...AA. .OO...O..O..A..A O..O...LL..OO..A ...O...LOOO.AOA. ....OOOOOAAAAO.. .......OO..AA.A. .......LO.AA...A ......O..OOAA..A ....OO..A..O.A.. ...O..AA...O.A.. ...O.A....OAA... ....OA.......... } # tile 254 (gold golem) { ................ ......HNH....... ......DND...N... ......HNH...JC.. ......HNH...NC.. ...HHHAAAAHANC.. ..HNJNHNHNJNAC.A ..HHHHHHHHHHHA.A .NCACCCCCCCCA..A .HH.AAAAAAAAA.AA .NH.ANC.AHNC.AAA .NJ.AHC.AHHC.AAA ..H.ANC.AHNC.AAA ....HJC.AHJC.AA. H...HNC.AHNC.A.H ..H............. } # tile 255 (leather golem) { ......KKKK...... .....KHKHJ...... ....KAKKJJA..... ...KKAJJJJAJ.... ..KKJJAJAAKJJ... .KKKJJAAKKKJJJ.. ..KKJJJAKKJJJJ.. ...KKJJJA.AAA.A. ....AAAA.KJAAAA. ....KJAAAKKAAAAA ...KJJAA.KJJAAA. ...KKJA..KKJAAA. ..KKJJJAKKJJJAA. ..KKKJJAKKKJJA.. ...KJJA..KJJA... ....KA....KA.... } # tile 256 (wood golem) { ................ ......KCKJ...... ......HCHJ..C... ......KCKJ..CK.. ......KCKJ..CKJ. ...KKKAAAAKACKJ. ..KCCCCCCCCCAKJA ..KKKKKKKKKKKAJA .CJAJJJJJJJJA..A .CKJAAAAAAAAA.AA .CKJACKJAKCKJAAA .CKJACKJAKCKJAAA ..KJACKJAKCKJAAA ....KCKJAKCKJAA. ....KCKJAKCKJA.. ................ } # tile 257 (flesh golem) { ................ ................ ...D..DDC....... .....DLDDL...... ..DD..LLLLC.D... ...CDL.LLLLADL.. ..CLDLA.CLLA.LL. ..LLLAA.LLCA..L. .CLLAA.CLLAA..CA .LLA..CLLALLAAAA ..LA.CLCAALCAAAA ...A..LLCACLCAAA ....LLALLAALLAAA ..CLLLAAAADLLA.. ..LLDDD..DDDDD.. ................ } # tile 258 (clay golem) { ................ ................ ................ ....LCCCCK...... ...LKKKKKKK..... ...CKAKKAKK..... ...CKAKKAKK..... .LCKKKKKKKKLC... CKKJKKKKKKCKKJ.. KKKJKKJJKKJKKJAA .JJAKKJAKKAJJAAA ..AKKKJAKKKAAAAA ..CKKKKKKKKKAAAA ..CKKKAACKKKAA.. ..CKKKA.CKKKAA.. ................ } # tile 259 (stone golem) { ................ ................ ................ ....BBBPP....... ...BBPPPPP...... ...BHAPHAP...... ...PPPPPPP...... .BBPPPPPP.BPA... BPPPP....PPPPAA. BPP.BPPPP.PPPAAA .PP.BP.PP.PPPAAA ...BPP.PPPAAAAAA ..BPPPAPPPAAAAA. ..PPPPAPPPPAAA.. ...PPAA.PPPA.... ................ } # tile 260 (glass golem) { ................ .....BBBBBBA.... .....BPNPPPA.... .....BNPPPNA.... .....NPPPNPA.... .....BPPNPPA.... .......BA...BA.. .BNBBABPBA.BPNA. .NPPNABPNBBANPBA .....BPNPPPAABAA .....BNPPPAAAAAA ......BPPNAAAAAA ....BNABNABPAAA. ...BNPA...BNAAA. ..BNPA....NPAA.. ...BA.....BPA... } # tile 261 (iron golem) { ................ ......PBP....... ......HBH...B... ......PBP...JP.. ......PBP...BP.. ...PPPAAAAPABP.. ..PBJBBBBBJBAP.A ..PPPPPPPPPPPA.A .B.A........A..A .BP.AAAAAAAAA.AA .BP.ABP.APBP.AAA .BJ.ABP.APBP.AAA ..P.ABP.APBP.AAA ....PJP.APJP.AA. ....PBP.APBP.A.. ................ } # tile 262 (human) { ................ ................ .......JJA...... ......JJJJA..... ......ELELA..... ......LLLLA..... ......ALLA...... .....CLAALC.AAA. ....CLLLLLLCAAA. ....LACLLCALAAA. ....LAJJKJALAAA. ......JJJKAAAA.. ......JJAJAA.A.. .....KLA.LKA.... ................ ................ } # tile 263 (wererat) { ................ ................ .......JJA...... ......JJJJA..... ......GJGJA..... ......LLLLA..... ......ALLA...... .....CLAALC.AAA. ....CLLLLLLCAAA. ....LACLLCALAAA. ....LAJJKJALAAA. ......JJJKAAAA.. ......JJAJAA.A.. .....KLA.LKA.... ................ ................ } # tile 264 (werejackal) { ................ ................ .......JJA...... ......JJJJA..... ......IPIPA..... ......LLLLA..... ......ALLA...... .....CLAALC.AAA. ....CLLLLLLCAAA. ....LACLLCALAAA. ....LAJJKJALAAA. ......JJJKAAAA.. ......JJAJAA.A.. .....KLA.LKA.... ................ ................ } # tile 265 (werewolf) { ................ ................ ......JJA....... .....JJJJA...... .....NJNJA...... .....LLLLA...... .....ALLA....... ....CLAALC.AAA.. ...CLLLLLLCAAA.. ...LACLLCALAAA.. ...LAJJKJALAAA.. .....JJJKAAAA... .....JJAJAA.A... ....KLA.LKA..... ................ ................ } # tile 266 (elf) { ................ .........G...... .......GGF...... ......GGGGA..... ......LELEA..... ......LLLLA..... ......ALLA....A. ......GAAG..AAA. .....LGGGFLAAAA. ....LAAGFAALAAA. ....LAGGGFALAA.. ......GFAFAA.A.. ......GFAFAA.A.. .....KLA.LKA.... ................ ................ } # tile 267 (Woodland-elf) { ................ ................ .........K...... .......KKJ...... ......KKKKA..... ......LELEA..... ......LLLLA..... ......ALLA....A. ......KAAK..AAA. .....LKKKJLAAAA. ....LAPPJAALAAA. ..KKLKKKKJALAA.. ......PPAJAA.A.. .....KLA.LKA.... ................ ................ } # tile 268 (Green-elf) { ................ ................ .........G...... .......GGF...... ......GGGGA..... ......LELEA..... ......LLLLA..... ......ALLA....A. ......GAAG..AAA. .....LGGGFLAAAA. ....LAAGFAALAAA. ....LAGGGFALAA.. ......GFAFAA.A.. .....KLA.LKA.... ................ ................ } # tile 269 (Grey-elf) { ................ ................ .........P...... .......PP....... ......PPPPA..... ......LELEA..... ......LLLLA..... ......ALLA....A. ......PAAP..AAA. .....LPPP.LAAAA. ....LAAP.AALAAA. ....LAPPP.ALAA.. ......P.A.AA.A.. .....KLA.LKA.... ................ ................ } # tile 270 (elf-lord) { ................ ................ ........II...... .......HGF...... ......HGGGA..... ......LELEA..... ......LLLLA..... ......ALLA....A. ......HAAH..AAA. .....LHHHFLAAAA. ....LAAIIAALAAA. ....LAHGGFALAA.. ......HFAFAA.A.. .....KLA.LKA.... ................ ................ } # tile 271 (Elvenking) { ................ ................ ......H..H...... ......HCHH...... ......HHHHA..... ......LELEA..... ......LLLLA..... .....IALLAI...A. ....IIIAAIDIAAA. .....LIIGDLAAAAA ....LADIFDALAAAA ....LAIIGDALAAA. .....IIFAFDAAA.. ...IIKLAILKDI... ................ ................ } # tile 272 (doppelganger) { ................ ......CCCC..I... ..I..CD...C..... ....CD.HHA.C.... ...CD.HHHHA.C.I. ...CD.LFLFA.DC.. .I.CD.LLLLA.DC.. ...CD.ALLA.DC... ..CD.LLAALL.ACA. .CD.LLLLLLLLADC. .CD.LALLLLALADC. .CD.LAJJKJALADC. ..CD..LJJLAAACA. ...CD.LLALAACA.. ..CD.LLAALLADC.. ................ } # tile 273 (shopkeeper) { ................ ................ ......AAAA...... .....AAAAAA..... ......JLJL...... ......LLLL...... ......ALLA...... .....EBAABEA.AA. ....EBBBBBBEAAA. ....BAEBBEABAAA. ....LAGFFFALAAA. ......GFAFAAAA.. ......GFAFAA.A.. .....JJA.JJA.... ................ ................ } # tile 274 (guard) { ................ .....BBPPPAA.... ....BNPPPPPPA... ....BPPBPPPPA... ....BAABPAAPA... ....BCLBPCLPA... ....AKCPPCJAAA.. ....BKJJJJAPAAAA ...BPKJAAJAPPAAA ..BPPKJJJJAPPPAA ..PPABKJJAPPAPPA ..PPABPKAPPPAPPA ..LC.BPPPPPPCLAA ..LL.BPPABPPLLAA .....BPPABPPAAAA ....BPPP.BPPPAAA } # tile 275 (prisoner) { ................ ................ .......NOA...... .......LLA...... .......LLA...... .......NOA...... ......NOONA..... .....NOOOONA.... ....NANOOOANAA.. ....PANOOOAPAAA. ....LANOOOALAAA. ......NOOOAAAA.. ......NAANAAA... ......PAAPAA.... .....LLA.LLA.... ................ } # tile 276 (Oracle) { ................ ................ .......NN....... LLL...GLLG...LLL ..L..NLLLLN..L.. ...L.NLAALN.L... ....LNLLLLNL.... .....LNLLNL..AA. .....NBBEEN.AAAA ......BBEEAAAAAA .LLA..BBBEAAALL. .LLLLBBBEBELLLLA ..LLCLBLLELLCLAA ...CLLLLLLLCLAA. ....LELLLLELAA.. ................ } # tile 277 (aligned priest) { ................ INI............. III..KCCK....... .J..KCCCCK...... .J..CAAKCC...... .LC.CAAACC...... CLLC.CAACJKC.... CJLACCCCJKCCC... .JAACCJJCKCCCK.. .JKCCCJCCJCCK.AA .J..CCJCCLJCAAAA .J..CCJCLLCAAAA. .J..KCJCCCJAAAA. .J.ACCJCCCJAAA.. .JACCCJJCCCAA... ................ } # tile 278 (high priest) { .INI............ IIIII.KCCK...... .IHI.KCAACK..... ..H..CGAGAC..... ..LC.CAAAAC..... .CLLC.CAACJCK... .CHLACCCCJCCCK.. ..HAACCJJCCCCCK. ..HCCCCJCCJCCC.A ..H..CCJCCLJCAAA ..H..CCJCLLCAAAA ..H..KCJCCCJAAAA ..H..KCJCCCJAAAA ..H.ACCJCCCJAAA. ..HACCCJJCCCAA.. ................ } # tile 279 (soldier) { .....J.......... .....JAAA....... .....ALLLA...... .....LLLLC...... .....JLLC....... .....JF..F...... ....FJFFFFF..A.. ....FJFFFAF.A... ....FLFFFFFAAA.. ....FJFFAAAAAAA. .....LFAFFAAAA.. .....FFAF.AAAA.. ......FAF.AA.... .....FFAFFA..... .....JJ.JJ...... ................ } # tile 280 (sergeant) { .....J.......... .....JFFF....... ....FFFFFF...... .....LLLLC...... .....JLLC....... .....JF..G...... ....FJFFFFF..A.. ....FJFFFAF.A... ....FLFFFFFAAA.. ....FJFFAAAAAAA. .....LFAFFAAAA.. .....FFAF.AAAA.. ......FAF.AA.... .....FFAFFA..... .....AA.AA...... ................ } # tile 281 (nurse) { ................ .......NO....... ......NDDO...... ......NNOOA..... .....DBLBLD..... .....CLLLLDC.... .....DALLACD.... .....CNAAODCAAA. .....NNNOOLAAAA. ....LANNDOALAAA. ....LANNOOALAAA. ......NNOOAAAA.. ......NNAOAA.A.. .....LLA.LLA.... ................ ................ } # tile 282 (lieutenant) { ................ .......FFF...... .....FFFFFF..... ......LLLL...... .......LLCA..... .....GF.FGA..... ....FFFFFFFF.... ....FAFFFFAFAAA. ....FAFFFFAFAAAA ....FAFFFFAFAAA. ....LFFAFFJLJA.. .....FFAFFJJJA.. ......FAF.AA.... .....FFAFFA..... .....AA.AA...... ................ } # tile 283 (captain) { ................ ......FHHF...... .....FFFFFF..... ......LLLL...... .......LLCA..... .....HF.FHF..... ....FFFFFFFFAA.. ....FAFFIFAFAAAA ....FAFFFFAFAAA. ....FAFFFFAFAAA. ....LFFAFFJLJA.. .....FFAFFJJJA.. ......FAF.JJJA.. .....FFAFFJJJA.. .....AA.AAAAA... ................ } # tile 284 (watchman) { ................ ......PPP....... ....PPPPPP...... .....LLLLC...... ......LLC....... .....PP..P...... ....PPPPPPP..... ....PAPPHAPPA... ....PAPPPANNAAA. ....PJPPAPNNAAA. ....JLPAPPAAAA.. .....JPAP.AAAA.. ......PAP.AA.... .....PPAPPA..... ....JJJ.JJJ..... ................ } # tile 285 (watch captain) { ......PPP....... .....PHHHP...... ....PPPPPPP..... .....LLLLC...... ......LLC....... .....HP..H...... ....PPPPPPP..... ....PAPPHAPPA... ....PAPPPANNAAA. ....PJPPAPNNAAA. ....JLPAPPAAAA.. .....JPAP.AAAA.. .....JPAP.AA.... .....PPAPPA..... ....JJJ.JJJ..... ................ } # tile 286 (Medusa) { ................ ..GA...GA....... ...FA.FA..GA.... ....FJFFFF...... ..FAFLLFA....A.. .GAFLLLLA..A..A. ....JLLKA.A.A.A. ...KBLLBKAAAAA.. ..KIIBBIIIAAA.A. ..IIIKKILLIAAA.. ..KIILLIALIAA... ...KIALKAAIAA... ...IKAAKIIAAA... ...IIKKIIIAA.... ..IIKIKIKIA..... ................ } # tile 287 (Wizard of Yendor) { .EEE.......EEE.. EFFAE..E..EAFFE. EAAAE.EEE.EAAAE. EAAAEEEAEEEAAAE. EEAAEEDADEEAAEE. .EEEEAAAAAEEEE.. ..EEEEAAAEEEE... ..EEEEEEEEEE.... ...EEEEEEEE..... ...EEEEEEEE....A ....EEEEEE...AAA ....EEEEEEAAAAAA ...EEEEEEEEAAAAA ..EEEEEEEEEAAAAA .EEEEEEEEEEEAAA. EEEEEEEEEEEEEEA. } # tile 288 (Croesus) { ....H..H..H..... ....HCHEHCH..... ....HHHHHHH..... ....ALLLLLA..... ....LLALALL..... .....LLLLL...... ....HLLDLLH..... ...HIALLLAIH.A.A ...HIHAAAHIHAAAA ..IIIEHHHIIIIAAA ..IIIIEHIIIIIAA. ..ILLIHHHILLIAAA ...LIIKHIIILAAAA ..GIIIKJIIIIGAA. .GIIIKJJKKIIIGG. ................ } # tile 289 (Charon) { ................ .......J........ ......JJJ....... ....JJJAJJJ..... ....JJDADJJ..... ...JJAAAAAJJ.... ...JJJAAAJJJ.... ..JJJJJJJJJJ.... .JJJJJJJJJJJJ... JJJJJJJJJJJJJJ.A .OO.JJJJJJ.OOAAA ....JJJJJJAAAAAA ...JJJJJJJJAAAAA ..JJJJJJJJJAAAAA .JJJJJJJJJJJAAA. JJJJJJJJJJJJJJA. } # tile 290 (ghost) { ................ ................ ...NNN.......... ..NANANN........ .NNNNNNNNN...... .NNPAAPNNNNN.... .NNAAAANNNOONO.. .NNAAAANONNNPNNO .NNPAAPNONNOOOP. .NNNNNNONOPNPPO. .NNONNOPNNOPOOP. .NOPNNOOOPPOOP.. .OOOPOPPOPPP.PP. .PP.PPOPPP...P.. .O...P....P..... ........P....... } # tile 291 (shade) { ................ ................ ................ ................ ................ ................ ................ ................ ........AAAAAAA. ....AAAAAAAA.... ..AAAAAAAAAAAA.. AAAAAAAAAAAAAAA. ..AAAAAAAAAAAAAA .AAAAAAAAAAAAA.. AAAA.AAAAJA..... ................ } # tile 292 (water demon) { ................ ................ ................ ................ ..EE.....EE..... .E.EE...EE.E.... ....EEEEE....... ....EBEBE..A.... ...EEEEEEEAAAA.. ..EEE...EEEAA.A. ..EEEEEEEEEAAA.. ..EEAEEEAEEAAA.. ...AAEEEAAAAA... ....EEAEEAA..... ....EEAEEA...... ................ } # tile 293 (succubus) { DD.OHHD......... DDOHHDGD........ DDOHDDDDD....... DDHHDDDA........ DHHHDJADDDD..... .HHJJDDDJDDD.... OHDDCDCDDJDD.... HHHCDDCDLJ.DD... HHHCDLJJJAADDA.. HHHDJJDDDAADAA.. HHHHDDAADAAAA... HHHH.DKJDDAA.... H.H..DDAADDAA... ..H..DDAA.DAA... ....DDAA..DDAA.. ...DDJA...DDDA.. } # tile 294 (horned devil) { ................ ................ ..O.......O..... ..OO.....OO..... ...LOCDCOL...... ...CDDDDDC...... ...DAADAADA..D.. ...DDDDDDDA.D... ..CCDDFDDCCAD.A. ..CDKDDDKCDADA.. ..CDAKKKACDAAAA. ..DDADDDADDAAAA. ....CDDDKAAAAA.. ...CDDADDKAA.... ..CDDAA.DDK..... ................ } # tile 295 (incubus) { DD.OHHD......... DDOHHDGD........ DDOHDDDDD....... DDHHDDDA........ DDDHDJADDDD..... DDDJDDDDDDDD.... .DDDDDCDD.DDD... .DDCDDDKK..DD... ..DDKKDDDAADDA.. ...DDDDDDAAAAA.. ....DDDDDDDDDA.. ....DDJDJJAAAAAA ....JDJJADKAA... ....DDKAADDKA... ...DDKAA..DDAA.. ..DDKAA...DDDA.. } # tile 296 (erinys) { ..GA...GA....... ...FA.FA..GA.... ....FJFFFF...... ..FAFLLFA....... .GAFDLDLA..A.A.. ....LLLEA.A.A.A. ...EBLLBEAAAA.A. ..EBBBBBBBAAAA.. ..BBBEBBLLBAA.A. ..EBBLLBALBAAA.. ...EBALBAABAA... ...BEAABBBAAA... ...BBBBBBBAAA... ...BBBBBBBAA.... ..BBEBEBEBA..... ................ } # tile 297 (barbed devil) { ................ ................ ..O.......O..... ..OO.....OO..... .O.LOCDCOL.O.... ...CDDDDDC....DD ...DAADAADA..D.D ...DDDDDDDA.D... ..CCDDFDDCCAD.A. ..CDKDDDKCDADA.. .C.DAKKKACDKAAA. ..DDADDDADDAAAA. ....CDDDKAAAAA.. .K.CDDADDKAAK... .CCDDAA.DDKK.... ................ } # tile 298 (marilith) { .D..HHH.....D... DD.HHHHHA...DD.. .DCHDDDHHAAD..A. ..HDBDBDHDDAAAA. .CHKDDDKHAAADD.. CDDDKKKDHDDDDFF. D..CDDCDKAAFFFAA D.KDDKDDDDDDFAA. D.DKDDKDKAFDFAA. ..D.GDDFAAFDFFAA .D.GGFFFAAAFFFFA ...GFFFFFAAAFFFA ..FGFFFFFFAFFFFA ..FGFFFFFFFFFFA. ..FGFFFFFFFFFA.. ....GFFFFFFAA... } # tile 299 (vrock) { ................ ......OPP.O..... ......PPPP...... .....CPPDP...... ....CCCPPP...... ....CCPPPP...... ....C..PPA...... .....DDAADD.AAA. ....DDDDDDDDAAA. ....DADDDDADAAA. ....DADDDDADAAA. ....DADDDDADAAA. ......DAADAAAA.. ......DAADAA.A.. .....DDA.DDA.... ................ } # tile 300 (hezrou) { ................ ................ ....GGGFF....... ..NGFFNNFFF..... .DFFFDDNFF.F.... .GFFFDNFF.FFFAA. .AFAFFFFFFFFFFAA .GFFFF.FFF.FGFAA .GAAAFF..LFGFFAA ..FFFF.FFLFGFFFA ..LLA.FLLLJJG.FA .LLAFFLLFJJGFFFA ..LAFLLLAAGF.FAA .....L.LAGFFFFAA ...........FFFA. ................ } # tile 301 (bone devil) { ................ ................ ..O.......O..... ..OO.....OO..O.. ...LNLOLOL....O. ...LOOOOOL....O. ...NAAOAAOA..O.. ...NOOOOOOA.O... ..NOOOFOOOOAO.A. ..OOKNOOKOOALA.. ..OOANOOAOOAKAA. ..LLANOOALLAAAA. ....NOOOLAAAAA.. ...NOOAOOLAA.... ..NOOAA.OOL..... ................ } # tile 302 (ice devil) { ................ ................ ..N.......N..... ..NN.....NN..... ...PBPNPNP..BNB. ...PNNNNNP..N.N. ...BAANAANA...N. ...BNNNNNNA.BNB. ..BNNNFNNNNAN.A. ..NNKBNNKNNABA.. ..NNABNNANNA.AA. ..PPABNNAPPAAAA. ....BNNNPAAAAA.. ...BNNANNPAA.... ..BNNAA.NNP..... ................ } # tile 303 (nalfeshnee) { ................ ................ ......BB...BB... ..KKKKKBB.BB.... .KADKADKKKB..... .KKKKKKKDKK..... .OKDKOKKDDKD.... .OKDKOKKKDKDD... .KAAAKKDKAKKD... ..KKKDDLAKKKD.A. ...KK.KKKKKDDA.. ....L..KDAKDAA.. ......LLAAKDA... .........LLA.... ................ ................ } # tile 304 (pit fiend) { ................ .K.O.......O.K.. .K.OO.....OO.KJ. KJJ.LOCDCOL.KJJ. KJJJKDDDDDKKJJJ. KJJCKDNDNDKCJJJA JJCCKDDDDDJCCJJA JJCCCKDIDJDCCJJA JACCDDKJJDDCDAJA JACCKDDDDDKCDAJA ...CDKDDDKCDDAAA ....DKDDDKCDAAAA .....CDDDKAAAA.. ....CDDADDKA.... ...CDDAA.DDK.... ................ } # tile 305 (sandestin) { .....CCCCC..I... .I..CD....C..... ...CD.DDD..C..I. ..CD.DDDDD..C... ..CD.DNDNDA.DC.. I.CD.DDDDDA.DC.. ..CD.ADDDA.DC..A .CD.DDAAADD.DCAA CD.DDDDDDDDDADCA CD.DADDDDDADADCA CD.DADDDDDADADCA CD.DADDDDDADADC. .CD..DDJDDAADCA. ..CD.DDADDADCA.. .CD.DDAADDDADC.. ................ } # tile 306 (balrog) { ................ .K..O.....O..K.. .KJ.O.....O.KJ.. KJJLOOCDCOOLJJJ. JJJDDDDDDDDDDKJ. JCCDDDNDNDDDCCJA CCDKDDDDDDDJCCCA CDDKKKDIDJJDCCDA CDDKDDKJJDDDCDDA CCDKDDDDDDDKCDDA JCCDKKDDDKKCDDDA JJCDKKDDDKKCDDJA JJ..CCDDDKKAAJJA J..CDDDADDDKAAJA ..CDDDAA.DDDK.AA ................ } # tile 307 (Juiblex) { ................ DD.........DD... NDC.KKKKJ.CND... .CCKCCCKKCCAA... ..KCCCCKCCJAA... ..KCCCCCK.JJAA.. ..KCCFCCK..JAA.. ..FKCFCCKK.JAAA. .FKKFCCKFK..JAA. .FKCFCCFKFK.JAA. .FCFCCKFCFK.JAA. FKCFCFCFCKK.JAA. CKFCCFCCKKFKJJA. CCKKCFCKFFKKKKA. .CCCCCCCCCCCKA.. ................ } # tile 308 (Yeenoghu) { ....B.HHP....... ....BPPPP....... ...BPLCPPH...... .KBPPCCPPH...... .PPPPPPP.H...... .PP...P.PH...... ....BPPPPPAAA... ..BPPPPPPPPAAAA. .BP.PPPPPAPPAAAA .B...BPP.AAPAAAA .B...BPP.AAPAAA. .....BPPAAAAA.A. ....BP.PPAA...A. ...BP.AAPPA..A.. ...BPAA.PPA..... ................ } # tile 309 (Orcus) { ................ .K..O.....O..K.. KJJO..BBB..O.KJ. KJJLOBPPPPOLKJJ. JKJJ.PGPGP.JJKJA JJKJKPPPPPJJKJJJ JBPPB.BPPABBPPJJ PJJPP.BPPAPPJJPA PJBPPP.AAPPPPJPA .JBP.PPPP.P.PJAA .JBPPPP.PPPPPJAA ..PPP.PPP.PPPAAA ...P.PPPPPPP.P.A ...BPPPAPPPPAAPA ...OOPPAOOPPAGA. ................ } # tile 310 (Geryon) { .K...........K.. .K....JJJ....KJ. KJJ..JJJJJ..KJJ. KJJJKLLLLLKKJJJ. KJJJKLBLBLKJJJJA JJJJKLLLLLJJJJJA JJALLKLLLJLLAJJA JA.LLLKJJLLLAAJA ...LJLLLLLKLAAAA ...LCKLLLKCLAFGF ...LLGLLFALLFFFA .....GFFFAAAFFAA ....GGGGFFAAFFAA ....GFFFFFAAFGFA ....FGGGFFFFFFFA .....FFFFFFFFFA. } # tile 311 (Dispater) { ................ ......OJJO...... ......JJJJA..... ......BLBLA..... ......LLLLA..... ......ALLA...... .....CKAAKK.AAA. ....CKKKKKKKAAA. ....KACKKJAKAAA. ....KACKKJAKAAJA ....KACKKJAKAAJA ....LACKKJJLAJA. ......CKAJAJJA.. ......CKAPAAAA.. .....PPA.PPA.... ................ } # tile 312 (Baalzebub) { ......F...F..... .......F.F...... ......BFFFB..... .....BPPFBPP.... .....PPPFPPP.... ......PPFPP..... .....CAFFFAK.... ....CKKAFAKKKAA. ....CAKJFAKAKAA. ....FACJDAJAFAA. ....FACKJJJAFAA. ....FACKKKJAFAA. ......CKKKJAAA.. ......CKAKJA.A.. .....FFA..FF.... ................ } # tile 313 (Asmodeus) { ................ ......OJJO...... ......JJJJA..... ......BLBLA..... ......LLLLA..... ......ALLA...... .....CKAAKK.AAA. ....CKKKKKKKAAA. ...KKCKKKKJKKAA. ...KKAKKKJAKKAJA ...KA.CKKJAAKAJA ...LA.CKKJJALJA. ......CKAJAJJA.. ......CKAPAAAA.. .....PPA.PPA.... ................ } # tile 314 (Demogorgon) { ...KKK..KKK..... ..KBKBK.BKBK.... ..KDKKK.KKDK.... ..DKKFA.GKKD.... ....GFAAGFAAA... ...GFFFJFFFA.AAA ..GFAGFFFAFFAAAA .GJFAGJFJAFFFAA. .GFAAGFFFAAFJA.. .GJA.GFJFAAFFAA. .GFA.GFFFA.FJAA. .GJA.GJFJA.FFAA. .GFAGFAAFFAFFA.. ..GAGJAAJFAFAA.. ..GAGFAFFFAFA... ................ } # tile 315 (Death) { .BBBB....JJJ.... .BPPPP.JJJJ..... .C....JJJJJ..... .C....JAAAJ..... .C...JADADAJ.AAA OOJ..JAAAAAJAAA. OOOJJJAAAAAJJJA. OOJJJJAAAAJOOJJA .CJJJJAAAJOOOOJA .C.JJAAAAJAOAAJA .C..JAAAAJAOAAJA .C..JAAAAAJOAJAA .C..JAAAAAJJJAAA .C.JAAAAAAAJJAA. .CJJAAAAAAAAJJA. ACJAAAAAAAAAAAJ. } # tile 316 (Pestilence) { F........JJJ.... ..F....JJJJ..... B...F.JJJJJ..... ...B..JAAAJ..... .F...JADADAJ.... ...F.JAAAAAJ.AA. .B..JFAAAAFJAA.. ...FJJAFABJJAA.. ..F.JFFBAJJJAAA. ....FAFFJJJJAAA. ....JABAJJJJAAA. ...FJFFJJJJJJAA. ...JJBFJJJJJJAA. ...JAABFBJJJJAA. ..JJFBFAFFAJJJA. .JJAAFAFAAAAAAJ. } # tile 317 (Famine) { .........JJJ.... .......JJJ...... K.....JJJJJ..... K.....JAAAJ..... K....JADADAJ.... K....JAAAAAJ...A K.....JAAAJJ..AA OOJJJJJJAAJAJ.AA K...JJJAAJJAJAAA K.....JAJJJOJAA. K.....JAOOOAAA.. K.....JAJJAAA... K.....JAJJAA.... K.....JAAJAA.... K...JJAAAJJAA... K..JJAAAAAJJJA.. } # tile 318 (mail daemon) { ...OP.BEEE.PO... ...OOEBEEEEOOD.. ..DLOBEEEEOOLDD. .DDDLDDDDDDLDDD. .CCDDDNDDNDDDCC. CCDKDDDDDDDDJCCC CDDKKDDIIDDJJCCD CDDK.KDAADJJECDD CCDKEEKKKJEEKCDD .CCDK.EEEE..CDDD .CCDAE.EENNNCDD. .DDDAEEEENDNDDD. ....BBEEENNNNN.. ...BEEEAANNNNNA. ..CDDDAAA.DDDK.. ................ } # tile 319 (djinni) { .LL..NNN..LL.... ..L..NGNA.L..... ..LAALLLAALA.... ..LAAKKKAALA.... ...LCKKKCLA..... ....LCKCLA...... ....LICLIA..A... ....IIIIEA.AA..A ....EIEEIA.AAAAA ....IEFEAAAAAAAA .....DEAIAAAAA.. .....IGIFAAAA... .......FEDAAA... .......I.GEA.A.. .........IFED... ................ } # tile 320 (jellyfish) { ................ .....PBPA....... ...PBBBPBA...... ..BBNNBPPBAA.... .BBNNPPPBBPAA... PBBBPPPBPBBAAA.. BBBPBPPPPPBPAAA. BBPBPPPPPPPBAAA. PBPPBPPPPEPEEE.. .PBBPPPEPEPPEE.. .PEPBBEEPEEPEE.. .PEEEPEEPEEPE... ..PEEPE..PE.P... ..P.EP.EEP..P... ..PEE.P.E..E.... .P..E.P..E...... } # tile 321 (piranha) { ................ ................ ................ ................ ................ ....OPP......... .....OPP........ ..O..PPAP.....E. ..POPPPPPA...EEE ..PPPPP.PPA.E... ...PP..PPPAAAEE. ..E.PPPPPPPPPE.. ..E...PPPPPAA.E. .....E..PPAE.... .....E..P....... ....E..E...E.... } # tile 322 (shark) { ................ ................ ................ ...............P ........P.....PP ....E..PP....PP. ...E...PPA..PPP. ..EEEEPPPA.PPPPP .E.EEPPP.PPPPPPE ...EP.P.PPPPPEEE ..PPPPPPPPPPEEE. .APPPPPPPPEEEE.E PPPPPPP..EE..... NDPPAPEPPP.E..EE PDNPPEE..EE..... .PPPE..EEE..E... } # tile 323 (giant eel) { ................ ................ ................ ....AAA......... ...AAOAA...AAA.. ..AAAAAAA.AA.AA. ..AAAA.AA.AA.AA. ...AA..AA.AA..A. ......AAA..AA.A. ......AA...AA... .....AAA.E.AA.E. ...E.AAEE.AAAE.. ...E.AAEEAAAEE.. ..E..AAAAAAE.E.. ...EE.AAAAE.E... ..E...EE.E...E.. } # tile 324 (electric eel) { ................ ................ ................ ....AAA......... ...AAOAA........ ..AAAAAAA....... ..AAAA.AA....... ...AA..AA...DD.. ......AAA..DD... ......AA...DD... .....AAA.E.DD.E. ...E.AAEE.DD.E.. ...E.AAEEDD.EE.. ..E..AAADDDE.E.. ...EE.AAADE.E... ..E...EE.E...E.. } # tile 325 (kraken) { ................ ................ ..FF..FF........ ..DDFDDF........ ..FFFFF.....GG.. ..NCNFF......GFA ..CC.FF.....EGFA ....GFAA.GFAEGFE ...GFFAGFFFFAGFE ...GFAAFFAGFAEEE ..GFFAGFFAGFEEE. EEGFFAGFFAEEEE.E .EGFFAGFFEE..... EEGFFEEEEE.E..EE EEEEEEE..EE..... ..EEE..EEE..E... } # tile 326 (newt) { ................ ................ ................ ................ ................ ......JKKJ...... .....CLCCLLC.... ....LAAAACCLCA.. .......LCCLLLCA. ....LCCCLLLAALA. ....CALLLLAAAA.. ...LLLLCLAAA.... ...LLAAALLA..... ................ ................ ................ } # tile 327 (gecko) { ................ ................ ...........LLP.. ..........LLOOA. ......PO.LLOOOA. ......OOALOOOA.. .......LLOOOA... ...POALOOOAA.... ...OOLOOOOOOA... ....ALOOOAOPA... ...DOOOOA.AA.... ...OOOAOOA...... ...OODAOPA...... ..F.AA.AA....... ................ ................ } # tile 328 (iguana) { ................ ................ ................ ................ ................ ....GPGPGGPF.... ..GPAAAAFFGPF... .GPAA.PFFGPPPAA. ......FGGPPFPPAA .PFGGGGPPPFAAPPA .FGPAPPPPFAAAAA. .GPPPPFPFAAA.A.. .PPFFAFPPAA..... D.AAAAAAPPA..... ................ ................ } # tile 329 (baby crocodile) { ................ ................ ................ ................ ................ .....FFOFOFA.... ....FOGFGGOFF... ....GAAAAFOGFA.. ...FAA.GFOGGGFA. ...GFOOOGGGFAGA. ...FGAGGGGFAAA.. ..FGGGGFGFAA.... ..GGDFAFGGA..... ...D............ ................ ................ } # tile 330 (lizard) { ................ ................ ................ ................ ................ ................ ....FFFFGFJ..... ..FFAAAJJGFJ.... ......JGFFJFAA.. ...JGGGFFJAAFA.. ..JFAFFFJAAAA... ..FFFFJJAAA..... .JFAAAAFAA...... .D.............. ................ ................ } # tile 331 (chameleon) { ................ ................ ................ .....GGGG....... ...GGGGGGGG..... ...GGFFFFGGFA... ..GPAAAGFFGGFA.. .GPAA.PFFGGGGAA. ...GGGGGGGGFGGAA .PGGBBGGGGFAAGGA .FGGABGGGFAAAAA. .GGGGGFGFAAA.A.. .DGFFAFGGAA..... D.AAAAAAGGA..... .DD............. ................ } # tile 332 (crocodile) { ................ ................ ................ ................ ....FFOFOOFA.... ...FOGFGFGOFFA.. ..FGAAAAFFOGFFA. .FFAA.GFFOGGGGFA ......FOOGGGGGGA .G.OOOOGGGGFAGGA .FOGAGGGGGFAAAA. FGGGGGFGGFAA.... GGDDFAFGGGA..... GDDFAAAAGGA..... .DF............. ................ } # tile 333 (salamander) { ................ ................ ................ ......CCC....... ....CCCCCCC..... ...CCDDDDCCDA... ....AAAADDCCDA.. ......KDDCCCCAA. ..LLLCCCCCCDCCAA .KLCCCLLLCDAACCA .DCEECLKKDAAAAA. DCCAECDKDAAA.A.. CCCCCCDCCAA..... .DAADAAACCA..... ..ACCA.......... ...AAA.......... } # tile 334 (long worm tail) { ........ILLLL... ......IILLAA.... .....ILLAA...... .....ILA........ .....ILA........ ......LLA...II.. .......LLIIILLLL ........ILLAAA.L ...IIIILLALL.... .ILLLLLAA..LL... ILLAAAA.....LA.. ILA.........LA.. LLA........LLA.. LILA......LLA... .LLLIIIILLLA.... ...LLLLLAAA..... } # tile 335 (archeologist) { ................ ................ ......KJ.J...... ......KJJJ...... ....KCKKKJJJ.... ......LELEA..... ......LLLLA..... ......ALLA...... .....CKAAKJ.AAA. ....CKKKJJJJAAA. ....KACKJJAJAAA. ....LACJKJALAAA. ......CJJKAAAA.. .....KCJAJJA.A.. .....CJJ.JKJ.... ................ } # tile 336 (barbarian) { ................ ................ .......HHA...... ......HHHHA..... ......LFLFA..... ......LLLLA..... ......ALLA...... .....LLAALL.AAA. ....LLLLLLLLAAA. ....LALLLLALAAA. ....LAALLAALAAA. ....LAJJKJALAAA. ......LJJLAAAA.. ......LLALAA.A.. .....LLA.LLA.... ................ } # tile 337 (caveman) { ................ ................ .......JJA...... ......JJJJA..... .....JFLFLJ..... .....JLLLLJ..... .....JJDDJA..... ....LLAJJALLAAA. ...LLLLAALLLLAA. ...LLALLLLALLAA. ....LACKKJALAAA. ......CKKJAAAA.. ......LA.LAA.A.. .....LLA.LLA.... ................ ................ } # tile 338 (cavewoman) { ................ ................ .......JJA...... ......JJJJA..... .....JFLFLJ..... .....JLLLLJ..... .....JLDDLAJ.... ....LJALLAJLAAA. ...LLJCAAJJLLAA. ...LLACKKJALLAA. ....LACKKJALAAA. ......CKKJAAAA.. ......LA.LAA.A.. .....LLA.LLA.... ................ ................ } # tile 339 (healer) { ................ .......NN....... ......NDDO...... ......NNNN...... ......ELEP...... ......LLLP...... .......LLP...... ......O..PA.AAA. .....NNOOPPAAAA. ....OOONOPPPAA.. ....LANOOPALAA.. ......NOOPAAAA.. .....NOOOPAA.A.. ....NOOOOOPA.... ................ ................ } # tile 340 (knight) { ................ ................ .......BPA...... ......BPPPA..... ......PEEPA..... ......PLLPA..... ......ALLAA..... .....BBAABB.AAA. ....BPPPPPPPAAA. ....PABPPPAPAAA. ....LA.PP.ALAAA. ......BP.PAAAA.. ......BPAPAA.A.. .....PPA.PPA.... ................ ................ } # tile 341 (monk) { ................ ................ .......CCC...... ......JCJJJA.... ......CAAAJA.... ......CAAAJA.... ......CKLKCAAAA. .....CDDDDDDAAAA ....CDDLALDDDAAA ....DALLALLADAA. ....DDDDCDDDDAA. .....AACCCDAAAA. .....CDCCCDDA.A. ....CCCCCCCDD... ................ ................ } # tile 342 (priest) { ................ ................ ......JLLJ...... ......JLLJA..... ......LLLLA..... ......ALLJA..... ......IJJIAAAA.. .....ODDDDDAAAA. ....IDNDDDDDAAA. ...NLNNNDDALAA.. ......NDDDAAAA.. ......DIIDAAAA.. .....DDIIDDA.A.. ....DIIIIIDD.... ................ ................ } # tile 343 (priestess) { ................ .......JJ....... ......JJJJ...... ......JLLJA..... ......JLLJJ..... .....JJLLJJ..... .....JEJJEJAAA.. .....ODEEDDAAAA. ....IDINDDDDAAA. ....L.NNNDALAA.. ......INDDAAAA.. ......INDDAAAA.. .....DDIIDDA.A.. ....DIIIIIDD.... ................ ................ } # tile 344 (ranger) { ................ ................ ........CJA..... .......CJJJA.... .......JEEJA.... .......JLLJA.... .......ALLAA.... ......GGAAGG.AAA .....BPFFFFPPAAA .....PAGFFFAPAAA .....LA.FF.ALAAA .......BP.PAAAA. .......BPAPAA.A. ......PPA.PPA... ................ ................ } # tile 345 (rogue) { ................ ................ ................ .....OA...OA.... .....OOIDPPA.... ......IDDDA..... ......LKLKA..... ......LLLLA..... ......ALLA...... ......BAABAA..A. .....KEBBEJAAAA. ....KAAEEAAKAA.. ....LAJJHJALAA.. ......KKJKAAAA.. .....KKA.KKA.... ................ } # tile 346 (samurai) { ................ ................ .........AA..... .......AAA...... ......AAAAA..... .....ALFLFA..... .....ALLLLA..... ......ALLA...... ....IIIAAIIIAAA. ....LDIIIIDLAAA. ....LABBBBALAAA. ....LABBBBALAAA. ......IDDDAAAA.. ......IDADAA.A.. .....IIA.IIA.... ................ } # tile 347 (tourist) { ................ ................ ......JKJJA..... ......KJJJA..... ...JJJJJJJJJJ... ......LFLFAA.... ......LLLLA..... ......ALLA...... .....HGAAGH.AAA. ....LLGHHGLLAAA. ....LAHGHGALAAA. ....LAHHGHALAAA. ......JJJKAAAA.. ......LLALAA.A.. .....LLA.LLA.... ................ } # tile 348 (valkyrie) { ................ ................ ......LHHL...... .....HHHHHL..... ....LHELELH..... ....HHLLLLH..... ...HHHALLA...... ...HJKJAAKJJAAA. ..HHLJJKKJJLAAA. ..H.LACKJCALAAA. ....LAAKKAALAAA. ......KKJKAAAA.. ......KJAJAA.A.. .....KLA.LKA.... ................ ................ } # tile 349 (wizard) { ................ .........BP..... .......BBPE..... ......BPPEA..... ......BAAEA..... ......BAAEA..... ......PLLE...... ......PAAEA.AAA. .....BBPBEEAAAA. ....PPPBEEEEAA.. ....LABPPEALAA.. ......BPPEAAAA.. .....BPPPEAA.A.. .....BPPPPEA.... ....BPPPPPPE.... ................ } # tile 350 (Lord Carnarvon) { .......JJ....... ......KJJJ...... ....KCKKKJJJ.... ......LELEA..... ......LLLLA..... ......ALLA...... .....CIAAIK.AAA. ....CKKIIKKKAAA. ...KKCKKHKJKKAA. ...KKAKHKJAKKAA. ...KAIHKKJIAKA.. ...LAICKKJIALA.. .....ICKAJIAAA.. ......CKAPAAAA.. .....PPA.PPA.... ................ } # tile 351 (Pelias) { ................ .......JJ....... ......KKKJ...... ......LELEA..... ......LLLLA..... ......ALLA...... .....CKAAKK.AAA. ....CKKKKKKKAAA. ...KKCKKKKJKKAA. ...KKAKKKKAKKAA. ...KA.CKKJAAKA.. ...LA.CKAJAALA.. ......CKAJAAAA.. ......CKAPAAAA.. .....PPA.PPA.... ................ } # tile 352 (Shaman Karnov) { ................ .......JJA...... ......JJJJA..... .....JFLFLJ..... .....JLLLLJ..... .....JJDDJA..... ....LHAJJAHLAA.. ...LLLHAAHLLLAA. ...LLLLHHLLLLAA. ...LLALHHLALLAA. ...LLALLLLALLAA. ....LACKKJALAAA. ......CKKJAAAA.. ......LA.LAA.A.. .....LLA.LLA.... ................ } # tile 353 (Earendil) { .........G...... ....B..GGF..B... ...BB.GGGGABB... ..BPBPLELEABPB.. ..BBBPLLLLABBB.. ..PBPPALLAPPP... ...PPBGAAGBBB... ...BBLGGGFLBBB.. ..BBLAAGFAALBB.. ...BLAGGGFALB... ......GFAF...... ......L..L.AAA.. ......AAAAAAAA.. ....AAAAAAAA.... .....AAAAAA..... ................ } # tile 354 (Elwing) { .........G...... ....B..GGF..B... ...BB.GGGGABB... ..BPBHLELEHBPB.. ..BBBHLLLLHBBB.. ..PBHHALLAHHP... ...PHHGAAGHHB... ...BBLGGGFLBBB.. ..BBLAAGFAALBB.. ...BLAGGGFALB... ......GFAF...... ......L..L.AAA.. ......AAAAAAAA.. ....AAAAAAAA.... .....AAAAAA..... ................ } # tile 355 (Hippocrates) { ................ ....LLLCCD...... ...LLCCDDA...... ...LAAAADA...... ...LBABADA...... ...LAAAADA...... ...CCLLDD.B..... ....CKKDDFBFAAA. ..LLLCLDDDBFAAA. .CCCCLDDDFBAAA.. .LALLCCDDFBDAA.. ...LCCCCDABFAA.. ...LCCCCDABAAA.. ..LLCCCCDAA.AA.. .LCCCCCCCDA..... ................ } # tile 356 (King Arthur) { ................ ................ ......OHHA...... .....OHHHHA..... .....HBLBHA..... .....HLLLHA..... .....ALLLAA..... ....BBAAABB.AAA. ...BPPPPPPPPAAA. ...PABPPPPACPAA. ..NNNNNNNNNCLCA. .....BPP.PACAA.. .....BPAPPAA.A.. .....BPAPPAA.A.. ....PPAA.PPA.... ................ } # tile 357 (Grand Master) { ................ .......LL....... ......LLLL...... ......LLLL...... ..LC.CALLAC..... .CLLC.CAACCCC... .CJLACCCCCCCCC.. ..JAACCCCCCCCCC. ..JCCCCCCCCCCC.A ..J..PPPPPLCCAAA ..J..CCCCLLCAAAA ..J..CCCCCCCAAAA ..J..CCCCCCCAAAA ..J.ACCCCCCCAAA. ..JACCCCCCCCAA.. ................ } # tile 358 (Arch Priest) { ..N............. .NNN..JLLJ...... ..N...JLLJ...... ..N...LLLL...... ..LC.CALLAC..... .CLLC.CAACJDK... .CHLACCCCJCCDK.. ..HAACCJJCCCCDK. ..HCCCCJCCJCCC.A ..H..DCJCCLJCAAA ..H..DCJCLLCAAAA ..H..KCJCCDJAAAA ..H..KCJCCDJAAAA ..H.ACCJCCDJAAA. ..HACCCJJCCCAA.. ................ } # tile 359 (Orion) { ................ ................ .......CJA...... ......CJJJA..... ......JEEJA..... ......JLLJA..... ......ALLAA..... .....GGAAGG..... ....BGFFFFFP.... ....BPFFFFPPAAA. ....PAGFFFAPAAA. ....LANNNNALAAA. ......BP.PAAAAA. ......BP.PAAAA.. ......BPAPAA.A.. .....PPA.PPA.... } # tile 360 (Master of Thieves) { ................ ...H.....H...... ...HHIDKHH...... ....IDDDD....... ....LLLLLA...... ....LBLBLA...... ....LLLLLA...... .....LLLA....... ....B.AABAA..... ...KEBBBEJAAA... ..KAEEEEEAJAAA.. ..LAJJHHJALAAA.. ....JKKKJAAAAA.. ....KJAJKAAAA... ...JJA..JJA..... ................ } # tile 361 (Lord Sato) { .....AAA........ .....AAA........ ...AAAAAAA...... ..AALLLLLAA..... ..ALFFLFFLA..... ..ALLLLLLLA..... ...AALLLA....... IIIIIAAAIIIIAAA. LLDIIIIIIDLLAAA. LLABBBBBBALLAAA. LLABBBBBBALLAAA. LLABBBBBBALLAAA. ...IIDDDDAAAAAA. ...IIAAIDAAA..A. ..IIIA.IIIAA.... ................ } # tile 362 (Twoflower) { ................ ................ ......JKJJA..... ......KJJJA..... ....JJJJJJJJ.... .....NNLNNA..... ....NALNALNA.... .....NNANNAA.... .....AAAAAA.AAA. ....LLHGHGLLAAA. ....LAGGGGALAAA. ....LAHGHGALAAA. ......JJJKAAAA.. ......JJAKAA.A.. .....LLA.LLA.... ................ } # tile 363 (Norn) { ................ ................ ......NNN....... .....NNNNN...... .....NELELN..... ....NNLLLLN..... ...NNNALLA...... ...NJKJAAKJJAAA. ..NNLJJKKJJLAAA. ..N.LACKJCALAAA. ....LAKKKKALAAA. ......KKJKAAAA.. ......KJAJAA.A.. .....KLA.LKA.... ................ ................ } # tile 364 (Neferet the Green) { ................ ................ ......GGG....... .....GFFFG...... ....GFEFEG...... ....GFFFFEG..... .N.GPEFFFEE..... .I..BBEAAEA.AA.. .I.BBPPBBEEAAAA. .IGBPPPPPEEEAA.. .I.PP.EPEAAGAA.. .I...BPPPAAAAA.. .N...BPPPEAA.A.. ....BPPPPPEA.... ...BPPPPPPPE.... ................ } # tile 365 (Minion of Huhetotl) { ...OP......PO... ...OODDDDDDOOD.. ..DLOOCDDCOOLDD. .DDDLDDDDDDLDDD. .CCDDDNDDNDDDCC. CCDKDDDDDDDDJCCC CDDKKDDIIDDJJCCD CDDKKKDAADJJDCDD CCDKDDKKKJDDKCDD .CCDKKDDDDKKCDDD .CCDADKDDKDACDD. .DDDADDDDDDADDD. ....CCDDDDKKAA.. ...CDDDAADDDKAA. ..CDDDAAA.DDDK.. ................ } # tile 366 (Thoth Amon) { ................ ......OJJO...... ......JJJJA..... ......BLBLA..... ......LLLLA..... ......ALLA...... .....BPAAPP.AAA. ....BPPPPPPPAAA. ...PPBPPPPJPPAA. ...PPAPPP.APPA.A ...PA.BPP.AAPA.A ...LA.BPP..AL.A. ......BPA.A..A.. ......BPAPAAAA.. .....PPA.PPA.... ................ } # tile 367 (Chromatic Dragon) { ......GGGFA..... .....NFNFEEA.... ....GFFFEECA.... ..DCHHF..CCA.... CHCHCD..BCCA.... HD.D...BFFA..... ......OBFAAAAAA. ....HOGFAAAAAAAA ..HOOIEA.EF.AAA. .HOOOIEEEEFFJAA. .HOOOIEEFFFDDAA. HBOOIIEFFFDDCCA. HB.OIEFOODD.CJA. HBAAGE.AADDACCA. ....GFAA...CCJA. ........FFFFJA.. } # tile 368 (Goblin King) { ................ ................ .H..H...H....... CLC.HCHCH....... CLC.HHHHH....... .H..IIIII....... .HK.IHIHI.I..... .HICKIIIJKK..... .H.IIJJJK.AA.... .H..JICJJAAAAA.. .H..IIIIJAAAAA.. ....JIIJJAA..... ....IJKJJA...... ...IKAA.IK...... ................ ................ } # tile 369 (Cyclops) { ................ ....LLLLL....... ...CLLLLLC...... ...LBABNNL...... ...LBBBNNLJA.... ...CLNNNLCJA.... ....LLLLLJAAA... ....LAALLAAAA... ..JKJLLLKAKJAA.A .CLKAJJJJAKLCAAA .LLJKAAAAKJLLAA. .LAAJKKKKJAALAA. .LC.GGGHGGACLAAA .LL.JJJJJJALLAAA ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } # tile 370 (Ixoth) { ....O......O.... ....O......O.... ...LOOCDDCOOL... ...DDDDDDDDDDD.. .CCDDDGDDGDDDCC. CCDKDDDDDDDDJCCC CDDKKKDIIDJJDCCD CDDKDDKJJJDDDCDD CCDKDDDDDDDDKCDD .CCDKKDDDDKKCDDD .CCDADKDDKDACDD. .DDDADDDDDDADDD. ....CCDDDDKKAA.. ...CDDDAADDDKAA. ..CDDDAAA.DDDK.. ................ } # tile 371 (Master Kaen) { ................ .......KKA...... ......KJJKA..... ..KKA.KAAKA.KKA. .KAAKAKDDKAKAAKA .KOOJKKOOKKKOOJA .KJJJJJJJJJKJJJA ..KJJJJJJJJJJJA. ....KJJJJJJJA... ......KJJJAAAAAA .....KJJJJKAAAAA .....KJJJJJAAAAA ....KJJJJJJKAAA. ...KJJJJJJJJKAA. ...KJJJJJJJJJA.. ................ } # tile 372 (Nalzok) { ....O......O.... ....O......O.... ...LOOCDDCOOL... ...DDDDDDDDDDD.. .CCDDDBDDBDDDCC. CCDKDDDDDDDDJCCC CDDKKKDIIDJJDCCD CDDKDDKJJJDDDCDD CCDKDDDDDDDDKCDD .CCDKKDDDDKKCDDD .CCDADKDDKDACDD. .DDDADDDDDDADDD. ....CCDDDDKKAA.. ...CDDDAADDDKAA. ..CDDDAAA.DDDK.. ................ } # tile 373 (Scorpius) { .....JLJLJAA.... ....JA.JCJCKAA.. ....AJ.....JJJA. ....LA......LCKA .JAKJA......JJJA ..JJA......ALCJA .......ALLAJCJKA ....JJALCCAAJJA. .JJALLAJCJJJAA.. JA.LCCAJAJJAAAA. ..JACJJJAAACCJAA GGJJJJJAACCAAAJA .JJGGAJACAAJJAAA D.JJAAJAACA.JAA. ...D...JAAJA.JJ. ........JA.JA... } # tile 374 (Master Assassin) { ................ ................ ................ .......AA....... ......AAAA...... .....ABLBLA..... .....AAAAAA..... ......AAAA...... .....AAAAAA..PP. ....AAAAAAAAPPP. ....AAAAAAAAPPP. ....LAAAAAALPPP. ......AAAAAPPP.. ......AAAAAP.P.. .....AAA.AAA.... ................ } # tile 375 (Ashikaga Takauji) { ................ ................ ......AA........ .......AAA...... ......AAAAA..... .....ALFLFA..... .....ALLLLA..... ......ALLA...... ....IIIAAIIIAAA. ....LDIIIIDLAAA. ....LAIIIIALAAA. ....LALHHLALAAA. ......IIIIAAAA.. ......IIAIAA.A.. .....IIA.IIA.... ................ } # tile 376 (Lord Surtur) { ....PPDDDDAA.... ....PDDDDDDDA... ...PPDLLLLDDA... ...PDPFLLFFDA... ...PPPLLLLLDA... ....PLLAALLAAA.. ...PPALLLLBAAAA. ...PPDBBBBBBBAA. ..BDDHDPBPPPPPA. ..PPHDDPBPPPPPA. ..LAHDHPBPPAALAA JLAADDHBBBBAALAA JJLJDHHPBPPPCLAA ..LLJBPPABPPLLAA .....BPPABPPAAAA ...LLLLJ.BLLLKAA } # tile 377 (Dark One) { ................ ......AAA....... .....AAAAA...... .....ADADA...... .....AAAAA...... ....AAAAAAA..... ....AAAAAAA..... ...AAAAAAAAA.... ...AAAAAAAAA.... ..AAAAAAAAAAA... ..AAAAAAAAAAA... ...AAAAAAAAA.... ...AAAAAAAAAA... ..AAAAAAAAAAAA.. AAAAAAAAAAAAAAAA ................ } # tile 378 (student) { ................ ................ .....GGFGG...... .......G........ ......NDND...... ...DDDDDDDD..... ......LELEA..... ......LLLLA..... ......ALLA...... .....CKAAKJ.AAA. ....CKKKJJJJAAA. ....KACKJJAJAAA. ....LACJKJALAAA. .....KCJAJJA.A.. .....CJJ.JKJ.... ................ } # tile 379 (chieftain) { ................ ................ .......HHA...... ......HHHHA..... ......LFLFA..... ......LLLLA..... .....HALLAH..... ....LLHAAHLLAAA. ....LLLIILLLAAA. ....LALIILALAAA. ....LAALLAALAAA. ....LAJJKJALAAA. ......LJJLAAAA.. ......LLALAA.A.. .....LLA.LLA.... ................ } # tile 380 (neanderthal) { ................ ................ ................ ......JJJJ...... .....JJJJJJ..... .....JFLFLJ..... .....JLLLLJ..... .....JJDDJA..... ....JJAJJAJJ.AA. ...JLLJAAJLLJAA. ...LLALJJLALLAA. ....LALCCLALAAA. ......LA.LAA.A.. .....LLA.LLA.... ................ ................ } # tile 381 (High-elf) { .........G...... .......GGF...... ......GGGGA..... ......LILIA..... ......LLLLA..... ......ALLA...... ......GAAG..AA.. .....LGGGFLAAAA. ....LAAGFAALAAA. ....LA.GFAALAA.. ....LA.GFAALAA.. ....LAGGGFAL.A.. ......GFAFAA.A.. ......GFAFAA.... ......GFAFAA.... .....KLA.LKA.... } # tile 382 (attendant) { ................ ................ ................ ......JJJ....... .....JLLLJ...... ......BLB....... .....CLLLD...... .....CCKKDA.AAA. .....LLCLDDAAAA. ....CCCLDDDDAA.. ....LALCCDALAA.. ......LCCDAAAA.. .....LCCCDAA.A.. ....LCCCCCDA.... ................ ................ } # tile 383 (page) { ................ ................ .......BPA...... ......BPPPA..... ......PEEPA..... ......PLLPA..... .......LLAA..... ......BAABA.AAA. .....BPPPPPAAAA. ....PABPPPAPAAA. ....LA.PP.ALAAA. ......BP.PAAAA.. ......LLALAA.A.. .....LLA.LLA.... ................ ................ } # tile 384 (abbot) { ................ ................ ................ ................ ................ ......KLK....... ......LLL....... ....CCLLLJJ..... ....KCKLKKJAAA.. ....CDDDDDDAAAA. ...CDDLALDDDAAA. ...DALLALLADAA.. ...DDDDCDDDDAA.. ....AACCCDAAAA.. ....CDCCCDDA.A.. ...CCCCCCCDD.... } # tile 385 (acolyte) { ................ ................ ................ ......JJJJ...... ......JLLJA..... ......LLLLA..... ......ALLJA..... ......CJJCAAAA.. .....LDDDDDAAAA. ....CDCCDDDDAAA. ....L.LCCDALAA.. ......LCCDAAAA.. ......LCCDAAAA.. .....LDCCDDA.A.. ....LCCCCCDD.... ................ } # tile 386 (hunter) { ................ ................ ................ ....J..CJA...... ...J..CJJJA..... ...J..JEEJA..... ..J...JLLJA..... ..J...ALLAA..... ..J..GGAAGG.AAA. ..LPBPFFFFPPAAA. ..J..AGFFFAPAAA. ..J....FF.ALAAA. ...J..BP.PAAAA.. ...J..BPAPAA.A.. ....JPPA.PPA.... ................ } # tile 387 (thug) { ................ ................ ................ .......ID....... ......IDDDA..... ......LKLKA..... ......LLLLA..... ......ALLA...... .....KKAAKKA..A. ....KKJKKJJKAAA. ....KAAJJAAKAA.. ....LAJJJJALAA.. ......KKJKAAAA.. ......KAAKAAAA.. .....KKA.KKA.... ................ } # tile 388 (ninja) { ................ ................ .........AA..... .......AAA...... ......AAAAA..... .....AFLFLA..... .....AAAAAA..... ......AAAA...... ....AAAAAAAA.PP. ....AAAAAAAAPPP. ....AAAAAAAAPPP. ....LAAAAAALPPP. ......AAAAAPPP.. ......AAAAAP.P.. .....AAA.AAA.... ................ } # tile 389 (roshi) { ................ ................ ................ .......AAAAA.... ......AAAAA..... .....ALFLFA..... .....ALLLLA..... ......ALLA...... ....PPPAAPPPAAA. ....L.PPPP.LAAA. ....LAOOOOALAAA. ....LAOOOOALAAA. ......P...AAAA.. ......P.A.AA.A.. .....PPA.PPA.... ................ } # tile 390 (guide) { ................ ................ ......JKJJA..... ......KJJJA..... ....JJJJJJJJ.... ......LFLFAA.... ......LLLLA..... ......ALLA...... .....HHAAHH.AAA. ....LLHHHHLLAAA. ....LAHHHHALAAA. ....LAHHHHALAAA. ......JJJKAAAA.. ......JJAKAA.A.. .....LLA.LLA.... ................ } # tile 391 (warrior) { .....O....O..... .....NO..ON..... ......NPPN...... .....PPPPPP..... .....PELELP..... ....HHLLLLH..... ...HHHALLA...... ...HJKJAAKJJAAA. ..HHLJJKKJJLAAA. ..H.LACKJCALAAA. ....LAAKKAALAAA. ......KKJKAAAA.. ......KJAJAA.A.. ......KJAJAA.A.. .....KLA.LKA.... ................ } # tile 392 (apprentice) { ................ ................ ................ ......JJJ....... .....JLLLJ...... ......GLG....... .....BLLLE...... .....BBEEEA.AAA. .....BBPBEEAAAA. ....PPPBEEEEAA.. ....LABPPEALAA.. ......BPPEAAAA.. .....BPPPEAA.A.. .....BPPPPEA.... ....BPPPPPPE.... ................ } # tile 393 (invisible monster) { ................ ................ .....NNNN....... ....NNNNNN...... ...NNAAAANN..... ...NNA...NNA.... ....AA...NNA.... ........NNAA.... .......NNAA..... ......NNAA...... ......NNA....... .......AA....... ......NN........ ......NNA....... .......AA....... ................ } nethack-3.6.0/win/share/objects.txt0000664000076400007660000046060412577716300016250 0ustar paxedpaxed. = (71, 108, 108) A = (0, 0, 0) B = (0, 182, 255) C = (255, 108, 0) D = (255, 0, 0) E = (0, 0, 255) F = (0, 145, 0) G = (108, 255, 0) H = (255, 255, 0) I = (255, 0, 255) J = (145, 71, 0) K = (204, 79, 0) L = (255, 182, 145) M = (237, 237, 237) N = (255, 255, 255) O = (215, 215, 215) P = (108, 145, 182) Q = (18, 18, 18) R = (54, 54, 54) S = (73, 73, 73) T = (82, 82, 82) U = (205,205,205) V = (104, 104, 104) W = (131, 131, 131) X = (140, 140, 140) Y = (149, 149, 149) Z = (195, 195, 195) 0 = (100, 100, 100) 1 = (72, 108, 108) # tile 0 (strange object) { ................ ...CJKKKCJKKKC.. .CKJKKCKJKKCJJK. .KJKKKKJKKKKJJJ. CJKKKCJKKKCJJJJ. CJKKKCJKKKCJJAJ. CCCCCHHCCCCJAJJ. AADDAAAADDAAJJJ. CCCCCHHCCCCJJJJ. CJJJHJJHJJJJJJJ. CJKKKHHKKKCJJJJA CJKKKHHKKKCJJJJA CJKKKCJKKKCJJJAA CJCCCCJCCCCJJAA. CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } # tile 1 (arrow) { ................ ..........PP.... .........PBPO... .........BPOBL.. .........POBLA.. ........JPAAA... .......JKA...... ......JKA....... .....JKA........ ....JKA......... ...JKA.......... .OOCA........... .ONNA........... .NNOA........... ..AAA........... ................ } # tile 2 (runed arrow / elven arrow) { ................ ..........FF.... .........FGFO... .........GFOGH.. .........FOGHA.. ........JFAAA... .......JKA...... ......JKA....... .....JKA........ ....JKA......... ...JKA.......... .OOCA........... .ONNA........... .NNOA........... ..AAA........... ................ } # tile 3 (crude arrow / orcish arrow) { ................ ..........PP.... .........PBPO... .........BPOBL.. .........POBLA.. ........JKAAA... .......JKA...... ......JKA....... .....JKA........ ....JKA......... ...JKA.......... .OJCA........... .ONAA........... .NNOA........... ..AAA........... ................ } # tile 4 (silver arrow) { ................ ..........DP.... .........DBDO... .........BDOBD.. .........DOBDA.. ........PPAAA... .......PPA...... ......PPA....... .....PPA........ ....PPA......... ...PPA.......... .OPPA........... .OPPA........... .NNOA........... ..AAA........... ................ } # tile 5 (bamboo arrow / ya) { ................ ..........BP.... .........BBPO... ........BBPOBL.. .........POBLA.. ........CJBLA... .......CJA.A.... ......CJA....... .....CJA........ ....CJA......... ...CJA.......... ..CJA........... OCJA............ ONA............. NNPA............ .AA............. } # tile 6 (crossbow bolt) { ................ ................ ................ ...N............ ..AON........... ...AOK.......... ....AJK......... .....AJK........ ......AJK....... .......AJK...... ........AJK..... .........AJK.... ..........AJJ... ...........AA... ................ ................ } # tile 7 (dart) { ................ ................ ................ ................ ................ ...........OOO.. .....CLCL.OBBA.. .NNNCJDJDCBAAA.. .AAAAJDJDAOBB... .....AAAA..OOO.. ...........AAA.. ................ ................ ................ ................ ................ } # tile 8 (throwing star / shuriken) { ................ ................ ................ ................ .....PN......... .....NAPNNP..... .....NNNNANA.... .....PNNNPAA.... ....N.NNNN...... ....PNNPANA..... .....AAANPA..... .........AA..... ................ ................ ................ ................ } # tile 9 (boomerang) { ................ ................ ....KK.......... ....KHKA........ .....KHKA....... ......KKKA...... .......KKKA..... ........KDKA.... ........JDKA.... .......JKDJA.... ......JKDJA..... .....JHDJA...... ....JHDJA....... .....KJA........ ................ ................ } # tile 10 (spear) { ................ ..............N. .............NO. ............NOA. ...........NOAA. ..........KJAA.. .........KJAA... ........KJLA.... .......KJAAJA... ......KJAAKJA... .....KJAA.CJA... ....KJAA..LA.... ...KJAA......... ..KJAA.......... ..JAA........... ................ } # tile 11 (runed spear / elven spear) { ................ ..............N. .............NO. ............NOA. ...........NOAA. ..........KJAA.. .........KJAA... ........KJLA.... .......KJAAFA... ......KJAAFFA... .....KJAA.GFA... ....KJAA..HA.... ...KJAA......... ..KJAA.......... ..JAA........... ................ } # tile 12 (crude spear / orcish spear) { ................ ..............N. .............NO. ............NOA. ...........KJAA. ..........KJAA.. .........LJAA... ........KJLA.... .......KJAAJA... ......KJAKKJA... .....KJAA.CJA... ....KJAA..LA.... ...KJAA......... ..KJAA.......... ..JAA........... ................ } # tile 13 (stout spear / dwarvish spear) { ................ ................ .............N.. ............NO.. ...........NOA.. ..........NOAA.. .........KJAA... ........KJAA.... .......KJLA..... ......KJAAJA.... .....KJAACJA.... ....KJAA.LA..... ...KJAA......... ..JJAA.......... ................ ................ } # tile 14 (silver spear) { ................ ..............OA .............OA. ............PA.. ...........PA... ..........PA.... .........PA..... ........PA...... .......BA....... ......BA........ .....PA......... ....PA.......... ...PA........... ..OA............ .OA............. ................ } # tile 15 (throwing spear / javelin) { ................ ..............OA .............OA. ............IA.. ...........IA... ..........IA.... .........IA..... ........IA...... .......LA....... ......LA........ .....IA......... ....IA.......... ...IA........... ..OA............ .OA............. ................ } # tile 16 (trident) { ................ ...PA........... ....PA.......... ..PA.PA......... PA.PA.PA........ .PA.PAPA........ ..PA.PPA........ ...PPPPA........ .......PA....... ........PA...... .........PA..... ..........PKA... ..........JPKA.. ...........JPKA. ............JA.. ................ } # tile 17 (dagger) { ................ ................ ................ ................ ................ .........N...... ........NOA..... .......NOAA..... ....OONOAA...... .....KOOA....... ....KJAOA....... ...KJAAAA....... ...AAA.......... ................ ................ ................ } # tile 18 (runed dagger / elven dagger) { ................ ................ ................ ................ ................ .........N...... ........NOA..... .......NOAA..... ....OONOAA...... .....KOOA....... ....KFAOA....... ...KFAAAA....... ...AAA.......... ................ ................ ................ } # tile 19 (crude dagger / orcish dagger) { ................ ................ ................ ................ ................ .........N...... ........NOA..... .......NOAA..... ....O.NOAA...... .....COAA....... ....KJAOA....... ...KJAAAA....... ...AAA.......... ................ ................ ................ } # tile 20 (silver dagger) { ................ ................ ................ ................ ................ .........N...... ........NPA..... .......NPAA..... ....BBNPAA...... .....KPPA....... ....KJAPA....... ...KJAAAA....... ...AAA.......... ................ ................ ................ } # tile 21 (athame) { ................ ................ .............P.. ............NPA. ...........PPA.. ..........NOAA.. .........PPA.... ........NOAA.... ......PPPA...... ....PONOPA...... .....KPBA....... ....KJAOA....... ...KJA.......... ....A........... ................ ................ } # tile 22 (scalpel) { ................ ................ ................ ................ ....NA.......... ....ONA......... .....PBA........ .......PA....... ........PA...... .........PA..... ..........PA.... ................ ................ ................ ................ ................ } # tile 23 (knife) { ................ ................ ................ ................ ................ .........N...... ........NOA..... .......NOAA..... ......NOAA...... .....KLAA....... ....KLAA........ ...KLAA......... ...AAA.......... ................ ................ ................ } # tile 24 (stiletto) { ................ ................ ................ ................ ................ ...........OA... ..........OA.... ........POA..... .......POA...... ......OOA....... ...OPNOA........ ....KJAA........ ...KJAOP........ ..KJAA.......... ..AAA........... ................ } # tile 25 (worm tooth) { ................ ................ ................ ................ ................ ................ ................ ......O......... ......NA........ ......NOA....... ......POA....... .......OA....... ................ ................ ................ ................ } # tile 26 (crysknife) { ................ ................ ................ ................ ................ ..........NOA... .........PPAA... ........NOAA.... ......PPPA...... ....PONOPA...... .....KPBA....... ....KJAOA....... ...KJA.......... ....A........... ................ ................ } # tile 27 (axe) { ................ .....OPA........ ....OPPPA....... ...OPPPPPA...... ...KPKPPPA...... ....KPPPA....... .....KAA........ ......KA........ .......CA....... ........CA...... .........CA..... ..........CA.... ...........CA... ................ ................ ................ } # tile 28 (double-headed axe / battle-axe) { ................ ................ ....OPPA........ ....OPPPA....... ...KPPPPA....... .OPPKPPPA....... .OPPPKAA........ .PPPPAKA........ ..PPPA.CA....... ...AA...CA...... .........CA..... ..........CA.... ...........CA... ................ ................ ................ } # tile 29 (short sword) { ................ ................ ................ ................ ....N........... ...AON.......... ....AON......... .....AON........ ......AONAPO.... .......AOOK..... ......APOAJK.... ......AAAAAJK... ..........AAJ... ...........AA... ................ ................ } # tile 30 (runed short sword / elven short sword) { ................ ................ ................ ................ ....N........... ...AON.......... ....AON......... .....AON........ ......AONAPO.... .......AOO...... ......APOFG..... ......AAAAFG.... ..........AFG... ...........AA... ................ ................ } # tile 31 (crude short sword / orcish short sword) { ................ ................ ................ ................ ....N........... ...AON.......... ....AON......... .....AON........ .....AAONAPO.... .......AOOK..... ......APOBJK.... ......AAAABJK... ..........ABJ... ...........AA... ................ ................ } # tile 32 (broad short sword / dwarvish short sword) { ................ ................ ................ ................ ....N........... ...AON.......... ....AON......... .....AONP....... .....AAONAPO.... .......AOO...... ......APOJJ..... ......AAAAJJ.... ..........AA.... ................ ................ ................ } # tile 33 (curved sword / scimitar) { ................ ................ ................ .AN............. .APN............ ..AOO........... ..AANO.......... ...APNO......... ....APNN........ .....AAONPO..... .......APOA..... ......APOJKJ.... ........AAJKJ... ..........AA.... ................ ................ } # tile 34 (silver saber) { ................ ................ ................ ................ ...........NA... ..........POPA.. .........PNOPA.. ........PNNPA... ....PPANNOPA.... .....OOOAA...... .....JJOPA...... ...KJJAAA....... ....AA.......... ................ ................ ................ } # tile 35 (broadsword) { ................ ................ ...N............ ..ANN........... ..AONN.......... ...AONN......... ....AONN........ .....AONN....... ......AONNPO.... .......AOOK..... ......APOAJK.... ......AAAAAJK... ..........AAJ... ...........AA... ................ ................ } # tile 36 (runed broadsword / elven broadsword) { ................ ................ ...N............ ..ANN........... ..AONN.......... ...AONN......... ....AONN........ .....AONN....... ......AONNPO.... .......AOOG..... ......APOFFG.... ......AAAAAFG... ..........AAJ... ...........AA... ................ ................ } # tile 37 (long sword) { ................ .............O.. ............OPA. ...........OPAA. ..........NPAA.. .........NPAA... ........NPAA.... .......NPAA..... ......NOAA...... .....NOAA....... ..OPNOAA........ ...KJAA......... ..KJAOP......... .NDAA........... .AAA............ ................ } # tile 38 (two-handed sword) { ..............N. .............NO. ............NOA. ...........NOAA. ..........NOAA.. .........NOAA... ........NOAA.... .......NNAA..... ....OPNNAA...... .....KIIA....... ....KJAOP....... ...KJAAAA....... ..KJAA.......... .NDAA........... .AAA............ ................ } # tile 39 (samurai sword / katana) { ................ ..............N. .............ON. ............PNA. ............NPA. ...........OOA.. ..........ONAA.. .........ONPA... ........NNPA.... .....OPNOAA..... .....AOPA....... ....JKJOPA...... ...JKJAA........ ..JJAA.......... ..AA............ ................ } # tile 40 (long samurai sword / tsurugi) { ................ ................ ..............N. .............NP. ............NOA. ...........OOA.. ..........ONA... .........ONA.... ........NNA..... .....OPNOA...... .....AOPA....... ....JKJOPA...... ...JKJAA........ ..JJAA.......... ..AA............ ................ } # tile 41 (runed broadsword / runesword) { ................ .............A.. ............AAP. ...........AAPP. ..........AAPP.. .........AAPP... ........AAPP.... .......AAPP..... ......AAPP...... .....AAPP....... ..OPAAPP........ ...NNPP......... ..NNPOP......... .NNPP........... .PPP............ ................ } # tile 42 (vulgar polearm / partisan) { ................ .............PO. ............PNP. ...........ONPA. ..........ONOAA. ..........NOAA.. .........KJAA... ........KJAA.... .......KJAA..... ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .JJAA........... JJAA............ } # tile 43 (hilted polearm / ranseur) { ................ .............PN. ............PNP. ...........PNOA. .......POPPNOAA. .......OAONOA... .......AAKOOP... ........KJAAOA.. .......KJAAOPA.. ......KJAA.AA... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .JJAA........... JJAA............ } # tile 44 (forked polearm / spetum) { ................ .............PN. ............PNP. ........PO.PNOA. ........OPANOAA. ........AONOA... ........AKOOPOA. ........KJAAOPA. .......KJAAAAA.. ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .JJAA........... JJAA............ } # tile 45 (single-edged polearm / glaive) { .............KA. ............KNOA ...........KNNPA ..........KNNPA. .........KNNPA.. ........KNNPA... .......KJAAA.... ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .KJAA........... KJAA............ JAA............. AA.............. } # tile 46 (lance) { PA.............. .PA............. ..BA............ ...OA........... ....OA.......... .....NA......... ......NA........ ......PNA....... .......PNA...... ........BNA..... .........ONA.... ..........NNOOOA ..........OONOA. ..........OOONOA ..........OA.ONO ..............ON } # tile 47 (angled poleaxe / halberd) { ................ .........OOOA... .........PPPKK.. .........PPKKOO. ..........KJPPPA .........KJAPPPA ........KJA.AAA. .......KJA...... ......KJA....... .....KJA........ ....KJAA........ ...KJAA......... ..KJAA.......... .KJAA........... JJAA............ JAA............. } # tile 48 (long poleaxe / bardiche) { .............NA. ............POPA ...........PNOPA ..........PNNPA. .........NNOPA.. ........KOAA.... .......KJAA..... ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .KJAA........... JJAA............ JAA............. ................ } # tile 49 (pole cleaver / voulge) { .............NA. ............NNOA ...........NNNPA ..........NNNPA. .........NNOPA.. ........KOAA.... .......KJAA..... ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .KJAA........... KJAA............ JAA............. AA.............. } # tile 50 (broad pick / dwarvish mattock) { ................ ................ ......ONOA...... ........PNOA.... .........NONA... ........KJAANA.. .......KJA...NA. ......KJA....... .....KJA........ ....KJA......... ...KJA.......... ..KJA........... .KJA............ ................ ................ ................ } # tile 51 (pole sickle / fauchard) { ..........NNN... .........NPPPN.. .........NPAAPN. .........NPA.ANA ..........NA..AA .........NPA.... ........KJA..... .......KJA...... ......KJA....... .....KJA........ ....KJA......... ...KJA.......... ..KJA........... .KJA............ KJA............. .A.............. } # tile 52 (pruning hook / guisarme) { .............NA. ............POPA ......PNNP.PNOPA ......NAANPNNPA. .......A.NNOPA.. ........KOAA.... .......KJAA..... ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .KJAA........... KJAA............ JAA............. AA.............. } # tile 53 (hooked polearm / bill-guisarme) { .............PN. ............PNA. ............POPA ......PNNP.PNOPA ......NAANPNNPA. .......A.NNOPA.. ........KOAA.... .......KJAA..... ......KJAA...... .....KKJA....... .....KJA........ ...ONJA......... ..ONOAA......... .PNOAA.......... PNPAA........... OPAA............ } # tile 54 (pronged polearm / lucern hammer) { .........NP..... .........PNP.... .........APPPK.. ..........APKPPO ...........KPPPO ..........KAPPPP .........KJAPPPA ........KJA.AAA. .......KJAA..... ......KJAA...... .....KJAA....... ....KJAA........ ...KJAA......... ..KJAA.......... .JJAA........... JJAA............ } # tile 55 (beaked polearm / bec de corbin) { ................ ................ ......PN........ .....PNPA....... ...KPPPAA....... AOPPKPAA........ .OPPPKA......... .PPPPAKA........ ..PPPA.CA....... ...AA...CA...... .........CA..... ..........CA.... ...........CA... ................ ................ ................ } # tile 56 (mace) { ................ ................ ................ .........BAB.... ........B.O.PA.. ........AO.B.A.. ........B.B.PA.. ........AP.PAA.. .......KJAAAA... ......KJA....... .....KJA........ ....KJA......... ...KJA.......... ..KJA........... ...A............ ................ } # tile 57 (morning star) { ................ ................ ................ ..........BAB... .........B.O.PA. .........AO.B.A. ...PP....B.B.PA. ..PAAP...AP.PAA. ..PAAP..PPAAAA.. ..PA.APPAA...... ..PA..AA........ ...KA........... ....KA.......... .....KA......... ......KA........ ................ } # tile 58 (war hammer) { ..........O..... .........PPOA... .........APPKK.. ..........AKKOO. ..........KJAPPO .........KJAAAPA ........KJA..AA. .......KJA...... ......KJA....... .....KJA........ ....KJA......... ...KJA.......... ..KJA........... .KJA............ .JA............. ................ } # tile 59 (club) { ................ ................ ................ ..........KK.... ........JCKKA... .......KKKKKA... ......JKKKKJA... ......KKKCKAA... .....JCKKKAA.... ....JKKKJAA..... ...JKKJAA....... ...KJAA......... ..KJA........... .KJA............ .JA............. ................ } # tile 60 (rubber hose) { ................ ................ ................ ................ .......FGF...... .....FGAAAGF.... ....GAA...AAA... ....GA.......... .....GA......... ......FGA....... ........GA...... ........FA...... .......GA....... ...GGGFA........ ....AAA......... ................ } # tile 61 (staff / quarterstaff) { ................ .............JK. ............JCJA ...........JKJA. ..........JCJAA. .........JCJAA.. ........JKJAA... .......JKJAA.... .......KJAA..... ......KJAA...... .....JJAA....... ....KJAA........ ...JJAA......... ..KJAA.......... .JJAA........... ..A............. } # tile 62 (thonged club / aklys) { ................ ................ ................ ................ ................ ........KJJJ.... ........KJJAA... .......KJJAA.... .......KJAA..... ......KJAA...... .....KJAA....... .....KAA........ ....KAA......... .....A.......... ................ ................ } # tile 63 (flail) { ................ ............KJ.. ...........KJA.. ..........KJA... .........KJA.... ........KJA..... .......KJA...... ......KJA....... .....KJA........ ....PA.......... ...KJA.......... ...KA........... ..KJA........... .JKA............ ..JA............ ................ } # tile 64 (bullwhip) { ................ ................ .......KKKKKK... .....KKAAAAAAKA. ....KAA......KA. ...KA.......KA.. ...KA.......JA.. ...KA........JA. ....KKKKKK...... .....AAAAAKA.... .P........KA.... .APP......KA.... ...APK...KA..... .....AKKKA...... ......AAA....... ................ } # tile 65 (bow) { ................ .....K.......... .....KP......... .....PK......... .....PKJ........ .....P.KJ....... .....P..K....... .....O..L....... .....P..O....... .....P..J..AA... .....P.KJ..A.... .....PKJ..AA.... .....PK..AA..... .....KPAAA...... .....KAA........ ................ } # tile 66 (runed bow / elven bow) { .....K.......... .....KP......... .....PK......... .....PKJ........ .....P.KJ....... .....P..K....... .....P..KJ...... .....P..JL...... .....O..JJ...... .....P..JL...... .....P..J..AA... .....P.KJ..A.... .....PKJ..AA.... .....PK..AA..... .....KPAAA...... .....KAA........ } # tile 67 (crude bow / orcish bow) { ................ ................ ....KKP......... .....PK......... .....PKJ........ .....P.KJ....... .....P..K....... .....O..L....... .....P..O...A... .....P..J..AA... .....P.KJ..A.... .....PKJ..AA.... .....PK.AAA..... ....KKPAA....... ................ ................ } # tile 68 (long bow / yumi) { .....L.......... .....LP......... .....PL......... .....PLO........ .....P.LO....... .....P..L....... .....P..LO...... .....P..OL...... .....P..OO...... .....P..OL...... .....P..O..AA... .....P.LO..A.... .....PLO..AA.... .....PL..AA..... .....LPAAA...... .....LAA........ } # tile 69 (sling) { ................ ................ ................ ................ ................ ................ ......JJJJ...... .....JAAAAJK.... ....JA.....KK... ..........JAKA.. ......JJKKAKKA.. ....JJAAAKKJJA.. ...JAA...AAAA... ................ ................ ................ } # tile 70 (crossbow) { ................ ................ ................ .......CJJ...... .......DJJ...... .....DKJJJK..... ...DKJJJJJJJK... ..DJ...DJJ..JK.. ....P..CJJ.P.... .....P.CJJP..... ......PCJPAAAA.. .......PPA.AAAA. .......CJJAA..A. .......OAOA..... ........OA...... ................ } # tile 71 (leather hat / elven leather helm) { ................ ................ ................ ................ ................ ................ .....JKKJ....... ....JCKKKJ...... ...JCKKJJJA..... ...JKKJJJJA..... ...JAJJAAJA..... ...JAJJA.JA..... ...JA.A.JA...... ....JA.JA....... ................ ................ } # tile 72 (iron skull cap / orcish helm) { ................ ................ ................ ................ ................ ................ .....PBBP....... ....PNBBBPA..... ...PNBBPPPA..... ...PBBPPPPA..... ...JAPPAAJA..... ...JAPPA.JA..... ...JA.A.JA...... ....JA.JA....... ................ ................ } # tile 73 (hard hat / dwarvish iron helm) { ................ ................ ................ ................ ................ .....PPP........ ....PBBPPA...... ...PBNPPPPA..... ...PNPPPPPA..... ...PPPPPPPA..... ...PAPPAAPA..... ...JAPPA.JA..... ...JA.A.JA...... ....JA.JA....... ................ ................ } # tile 74 (fedora) { ................ ................ ................ ................ ................ ......AAAA...... .....AAAAAA..... ...AA.AAAAA..... ...AAA.AAA.A.... ....AAA...AAA... ....K.AAAAAA.... ...KA...KA...... ....KA..KA...... .......KA....... ................ ................ } # tile 75 (conical hat / cornuthaum) { ................ .......E........ .......E........ .......B........ ......EBE....... ......EBE....A.. ......PBE....A.. .....EBBEE..AA.. .....EBBPE.AAA.. .....PNBPEAAA... ....EBNBBEEAA... ....ENNBBPEAA... ...EBBBBPEAEA... ...EE..A.AEE.... ....EEEEEEE..... ................ } # tile 76 (conical hat / dunce cap) { ................ .......E........ .......E........ .......B........ ......EBE....... ......EBE....A.. ......PBE....A.. .....EBBEE..AA.. .....EBBPE.AAA.. .....PNBPEAAA... ....EBNBBEEAA... ....ENNBBPEAA... ...EBBBBPEAEA... ...EE..A.AEE.... ....EEEEEEE..... ................ } # tile 77 (dented pot) { ................ ................ ................ ............JJ.. ...........JJ... ..........JJ.... .........JJ...AA .....BPPP.J..AA. ....BAAA..P.AA.. ....BPA..P.AA... ....BBPPP..AA... ....BPPP...AA... .....BBPPPAAA... ......AAAAAA.... ................ ................ } # tile 78 (plumed helmet / helmet) { .......DID...... ......DIBI...... ......IBIB...... ......DIB....... .......I........ ......PIP....... .....PNIPPA..... ....PNBPPPPA.... ....PBPPPPPA.... ....PPPPPPPA.... ....PAPPAAPA.... ....JAPPA.JA.... .......AA..A.... ................ ................ ................ } # tile 79 (etched helmet / helm of brilliance) { ................ ................ ................ ................ ................ ......PPP....... .....PNBPPA..... .....NBPPP.A.... ....P.P.P.PA.... ....PPPPPPPA.... ....PAPPAAPA.... ....JAPPA.JA.... .......AA..A.... ................ ................ ................ } # tile 80 (crested helmet / helm of opposite alignment) { ................ ................ ................ ................ ......HHH....... .....HHH........ .....HH..PA..... ....PPH..PPA.... ....PPP.PPPA.... ....PPPPPPPA.... ....PAPPAAPA.... ....JAPPA.JA.... .......AA..A.... ................ ................ ................ } # tile 81 (visored helmet / helm of telepathy) { ................ ................ ................ ................ ................ ......PPP....... .....PNNPPA..... ....PNNPPPPA.... ....PBBBBBPA.... ....PPPPPPPA.... ....PAAAAAPA.... ....JBPPPPJA.... ......PPAAAA.... .......AA....... ................ ................ } # tile 82 (gray dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.N..P...P.OAOA .N.N.P...P..OAOA ..ANP...P...OA.A ...N...P...POA.. ...N..P...P.OA.. ....NP...P.OAA.. ...N.N..P.OAOA.. ..NNNANP.OAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 83 (silver dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOBOO.O. .N.NOBNOOBNOBAOA .N.NBNOOBNOBBAOA ..ANNOOBNOBBBA.A ...NOOBNOBBNBA.. ...NOBNOBBNBBA.. ....NNOBBNBBAA.. ...N.NBBNBBAOA.. ..NNNANNBBAOOOA. .NNNBA.NBAAOOOOA ..NBAA......OOA. ................ ................ } # tile 84 (shimmering dragon scale mail) { ................ ................ ...B.BBBOOO.O... .B.BBBBBOOOOO.O. .B.BEEFFGGHHOAOA .B.BEFFGGHHCOACA ..ABFFGGHHCDOA.A ...BFGGHHCDDOA.. ...BGGHHCDDKOA.. ....BHHCDDKOAA.. ...B.BCDDKOAOA.. ..BBBABDKOAOOCA. .BBBOA.BBAAOOOCA ..BOAA......KCA. ................ ................ } # tile 85 (red dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NDDIDDDIDOAOA .N.NDIDDDIDDOAOA ..ANIDDDIDDDOA.A ...NDDDIDDDIOA.. ...NDDIDDDIDOA.. ....NIDDDIDOAA.. ...N.NDDIDOAOA.. ..NNNANIDOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 86 (white dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NOONOOONOOAOA .N.NONOOONOOOAOA ..ANNOOONOOOOA.A ...NOOONOOONOA.. ...NOONOOONOOA.. ....NNOOONOOAA.. ...N.NOONOOAOA.. ..NNNANNOOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 87 (orange dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NCCLCCCLCOAOA .N.NCLCCCLCCOAOA ..ANLCCCLCCCOA.A ...NCCCLCCCLOA.. ...NCCLCCCLCOA.. ....NLCCCLCOAA.. ...N.NCCLCOAOA.. ..NNNANLCOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 88 (black dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NAA.AAA.AOAOA .N.NA.AAA.AAOAOA ..AN.AAA.AAAOA.A ...NAAA.AAA.OA.. ...NAA.AAA.AOA.. ....N.AAA.AOAA.. ...N.NAA.AOAOA.. ..NNNAN.AOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 89 (blue dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NEEBEEEBEOAOA .N.NEBEEEBEEOAOA ..ANBEEEBEEEOA.A ...NEEEBEEEBOA.. ...NEEBEEEBEOA.. ....NBEEEBEOAA.. ...N.NEEBEOAOA.. ..NNNANBEOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 90 (green dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NFFGFFFGFOAOA .N.NFGFFFGFFOAOA ..ANGFFFGFFFOA.A ...NFFFGFFFGOA.. ...NFFGFFFGFOA.. ....NGFFFGFOAA.. ...N.NFFGFOAOA.. ..NNNANGFOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 91 (yellow dragon scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NHHNHHHNHOAOA .N.NHNHHHNHHOAOA ..ANNHHHNHHHOA.A ...NHHHNHHHNOA.. ...NHHNHHHNHOA.. ....NNHHHNHOAA.. ...N.NHHNHOAOA.. ..NNNANNHOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 92 (gray dragon scales) { ................ ................ ................ ........P....... .......PPP...... ....P.PPPPA..... ...PPP.PPAAP.... ..PPPPAPAAPPA... ...PPAAPPAPAA... ....AAPPAAAA.... .......AAPA..... .......PPAA..... ........AA...... ................ ................ ................ } # tile 93 (silver dragon scales) { ................ ................ ................ ........N....... .......NNN...... ....N.NNNNA..... ...NNN.NNAAN.... ..NNNNANAANNA... ...NNAANNANAA... ....AANNAAAA.... .......AANA..... .......NNAA..... ........AA...... ................ ................ ................ } # tile 94 (shimmering dragon scales) { ................ ................ ................ ........P....... .......PPP...... ....E.PPFPA..... ...EBB.FFAAH.... ..EBBPAFAAHDA... ...EBAAGGADAA... ....AAGGAAAA.... .......AADA..... .......GHAA..... ........AA...... ................ ................ ................ } # tile 95 (red dragon scales) { ................ ................ ................ ........D....... .......DDD...... ....D.DDDDA..... ...DDD.DDAAD.... ..DDDDADAADDA... ...DDAADDADAA... ....AADDAAAA.... .......AADA..... .......DDAA..... ........AA...... ................ ................ ................ } # tile 96 (white dragon scales) { ................ ................ ................ ........O....... .......OOO...... ....O.OOOOA..... ...OOO.OOAAO.... ..OOOOAOAAOOA... ...OOAAOOAOAA... ....AAOOAAAA.... .......AAOA..... .......OOAA..... ........AA...... ................ ................ ................ } # tile 97 (orange dragon scales) { ................ ................ ................ ........C....... .......CCC...... ....C.CCCCA..... ...CCC.CCAAC.... ..CCCCACAACCA... ...CCAACCACAA... ....AACCAAAA.... .......AACA..... .......CCAA..... ........AA...... ................ ................ ................ } # tile 98 (black dragon scales) { ................ ................ ................ ........A....... .......AAA...... ....A.AAAAP..... ...AAA.AAPAA.... ..AAAAPAPAAAP... ...AAPAAAPAPP... ....PAAAPAPP.... .......PAAP..... .......AAPP..... ........PP...... ................ ................ ................ } # tile 99 (blue dragon scales) { ................ ................ ................ ........E....... .......EEE...... ....E.EEEEA..... ...EEE.EEAAE.... ..EEEEAEAAEEA... ...EEAAEEAEAA... ....AAEEAAAA.... .......AAEA..... .......EEAA..... ........AA...... ................ ................ ................ } # tile 100 (green dragon scales) { ................ ................ ................ ........F....... .......FFF...... ....F.FFFFA..... ...FFF.FFAAF.... ..FFFFAFAAFFA... ...FFAAFFAFAA... ....AAFFAAAA.... .......AAFA..... .......FFAA..... ........AA...... ................ ................ ................ } # tile 101 (yellow dragon scales) { ................ ................ ................ ........H....... .......HHH...... ....H.HHHHA..... ...HHH.HHAAH.... ..HHHHAHAAHHA... ...HHAAHHAHAA... ....AAHHAAAA.... .......AAHA..... .......HHAA..... ........AA...... ................ ................ ................ } # tile 102 (plate mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NNNNNOOOOOAOA .N.NNNNONOOOOAOA ..ANNNOONNOOOA.A ...NNNOONNOOOA.. ...NNNNONOOOOA.. ....NNNNOOOOAA.. ...N.NNNOOOAOA.. ..NNNANNOOAOOOA. .NNNOA.NOAAOOOOA ..NOAA......OOA. ................ ................ } # tile 103 (crystal plate mail) { ................ ................ ...N.NNNBBB.B... .N.NNNNNBBBBB.B. .N.NNNNNBBBBBABA .N.NNNNBNBBBBABA ..ANNNBBNNBBBA.A ...NNNBBNNBBBA.. ...NNNNBNBBBBA.. ....NNNNBBBBAA.. ...N.NNNBBBABA.. ..NNNANNBBABBBA. .NNNBA.NBAABBBBA ..NBAA......BBA. ................ ................ } # tile 104 (bronze plate mail) { ................ ................ ...L.LLLCCC.C... .L.LLLLLCCCCC.C. .L.LLLLLCCCCCACA .L.LLLLCLCCCCACA ..ALLLCCLLCCCA.A ...LLLCCLLCCCA.. ...LLLLCLCCCCA.. ....LLLLCCCCAA.. ...L.LLLCCCACA.. ..LLLALLCCACCCA. .LLLCA.LCAACCCCA ..LCAA......CCA. ................ ................ } # tile 105 (splint mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .J.NPPPP....OAJA .N.NKKKKJJJJOAOA ..ANPPPP....OA.A ...NKKKKJJJJOA.. ...NPPPP....OA.. ....NKKKJJJOAA.. ...N.NPP..OAOA.. ..NPNANKJOAOPOA. .NPJOA.NOAAOJPOA ..NOAA......OOA. ................ ................ } # tile 106 (banded mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .P.NPNPPPPOPOAPA .N.N........OAOA ..ANPNPPPPOPOA.A ...N........OA.. ...NPNPPPPOPOA.. ....N......OAA.. ...N.NPNOPOAOA.. ..NPNAN..OAOPOA. .NP.OA.NOAAO.POA ..NOAA......OOA. ................ ................ } # tile 107 (dwarvish mithril-coat) { ................ ................ ...NNNNNOOOOO... .N.NANANAPAPO.O. .N.NNANAPAPAOAOA .N.NANANAPAPOAOA ..ANNANAPAPAOA.A ...NANANAPAPOA.. ...NNANAPAPAOA.. ....NNANAPAOAA.. ...N.NNAPAOAOA.. ..NPNANNAOAO.OA. .NPNOA.NOAAOO.OA ..NOAA......OOA. ................ ................ } # tile 108 (elven mithril-coat) { ................ ...N.N.NO.O.O... ...NNNNNOOOOO... .N.NANANAOAOO.O. .N.ONANAPAPAOAOA .N.NANANAPAPOAOA ..AONANAPAPAOA.A ...NANANAPAPOA.. ...ONANAPAPAOA.. ....ONANAPAOAA.. ...N.ONAPAOAOA.. ..NPNAONAOAO.OA. .NPNOA.OOAAOO.OA ..NOAA......OOA. ................ ................ } # tile 109 (chain mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .N.NPAPA.A.AOAOA .N.NAPAPA.A.OAOA ..ANPAPA.A.AOA.A ...NAPAPA.A.OA.. ...NPAPA.A.AOA.. ....NPAPA.AOAA.. ...N.NPA.AOAOA.. ..NPNANPAOAO.OA. .NPNOA.NOAAOO.OA ..NOAA......OOA. ................ ................ } # tile 110 (crude chain mail / orcish chain mail) { ................ ................ ...K.KKKJJJ.J... .K.KKKKKJJJJJ.J. .K.KPAPA.A.AJAJA .K.KAPAPA.A.JAJA ..AKPAPA.A.AJA.A ...KAPAPA.A.JA.. ...KPAPA.A.AJA.. ....KPAPA.AJAA.. ...K.KPA.AJAJA.. ..KKKAKPAJAJJJA. .KKKJA.KJAAJJJJA ..KJAA......JJA. ................ ................ } # tile 111 (scale mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .P.NPAPAA.A.OA.A .N.NAPPP...AOAOA ..ANPAPAA.A.OA.A ...NPPAP.A..OA.. ...NPAPAA.A.OA.. ....NPPP...OAA.. ...N.NPAA.OAOA.. ..NPNANP.OAO.OA. .NPPOA.NOAAO..OA ..NOAA......OOA. ................ ................ } # tile 112 (studded leather armor) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .K.NKKKKJJJJOAKA .K.NKNKNOJOJOAKA ..ANKKKKJJJJOA.A ...NKNKNOJOJOA.. ...NKKKKJJJJOA.. ....NKNKJOJOAA.. ...N.NKKJJOAOA.. ..NKKANKJOAOKKA. .NKKJA.NOAAOKKKA ..KJAA......KKA. ................ ................ } # tile 113 (ring mail) { ................ ................ ...N.NNNOOO.O... .N.NNNNNOOOOO.O. .P.NPAAP.AA.OA.A .N.NABPAA.PAOAOA ..ANAPBAAP.AOA.A ...NPAAP.AA.OA.. ...NAPBAAP.AOA.. ....NBPAA.POAA.. ...N.NAP.AOAOA.. ..NPNANAAOAO.OA. .NPBOA.NOAAOP.OA ..NOAA......OOA. ................ ................ } # tile 114 (crude ring mail / orcish ring mail) { ................ ................ ...K.KKKJJJ.J... .K.KKKKKJJJJJ.J. .B.KPAAP.AA.JAPA .K.KABPAA.PAJAJA ..AKAPBAAP.AJA.A ...KPAAP.AA.JA.. ...KAPBAAP.AJA.. ....KBPAA.PJAA.. ...K.KAP.AJAJA.. ..KPKAKAAJAJ.JA. .KPBJA.KJAAJP.JA ..KJAA......JJA. ................ ................ } # tile 115 (leather armor) { ................ ................ ...N.NNNOOO.O... .K.NNNNNOOOOO.J. .K.NKKKKJJJJOAJA .K.NKKKJKJJJOAJA ..ANKKJJKKJJOA.A ...NKKJJKKJJOA.. ...NKKKJKJJJOA.. ....NKKKJJJOAA.. ...K.NKKJJOAJA.. ..KKKANKJOAJJJA. .KKKJA.NOAAJJJJA ..KJAA......JJA. ................ ................ } # tile 116 (leather jacket) { ................ ................ ................ ................ ......KA.JA..... ....KKKKJJJJA... ...KKKKKJLJJJA.. ..KKKKKKJJJJJJA. ...KAKKKJLJAJAA. .....KKKJJJA.A.. .....KKKJLJA.... .....KKKJJJA.... ......AAAAAA.... ................ ................ ................ } # tile 117 (Hawaiian shirt) { ................ ................ ................ ....C.....C..... ...GCGGGGGCH.... ..GGHCGGGCHHH... .HHHJHCCCHJHHH.. ..HHJHHCHHJHHAA. ....GHHCGGHAAA.. ....HHHCGGHA.... ....GGHCHHHA.... ....GGHCHGGA.... ....HHHCHHHA.... .....AAAAAAA.... ................ ................ } # tile 118 (T-shirt) { ................ ................ ................ ....P.....P..... ...NPOOOOOPN.... ..NNNPOOOPNNN... .NNNONPPPNONNN.. ..NNONNNNNONNAA. ....NDODODNAAA.. ....NNNNNNNA.... ....NDODODNA.... ....NNNNNNNA.... ....NNNNNNNA.... .....AAAAAAA.... ................ ................ } # tile 119 (mummy wrapping) { ................ ................ ................ ................ ................ ................ .............O.. .......N..N..O.. ....O.ONO.NNAN.. .....NONO.ANNO.. O...ONOOODNNOAA. .OOODNNONNNAOOA. ..A.NNOOAOAAOAA. ...OODOOAAOOOA.. ..N.AAN.NA.OO... ................ } # tile 120 (faded pall / elven cloak) { ................ ................ ................ ....OFF..FO..... .....OFFFOAA.... ......OFOAA..... .....OGAGFA..... ....OGOAOFFA.... ...OGOAAGFFFA... ..OGOGAAOFFFFA.. ..OOGAAFFOFFFA.. ..OGOAAFFGFFFA.. ...OGAFFFFGFA... ....AAAAAAAA.... ................ ................ } # tile 121 (coarse mantelet / orcish cloak) { ................ ................ ................ ....CJK.KKC..... .....CJKKCAA.... ......CKCAA..... .....CCACKA..... ....CCCACKKA.... ...CCCAACKKKA... ..CCCCAACKKKKA.. ..CCCAAJJCKKKA.. ..CCCAAJJCKKKA.. ...CCAJJJJCKA... ....AAAAAAAA.... ................ ................ } # tile 122 (hooded cloak / dwarvish cloak) { ................ ................ ................ ......BBP....... .....BBBBP...... ....BPAAAPP..... .....BPAPPAA.... ......BPPAA..... .....BBABPA..... ....BBBABPPA.... ...BBBAABPPPA... ..BBBBA..BPPPA.. ...BBA....BPA... ....AAAAAAAA.... ................ ................ } # tile 123 (slippery cloak / oilskin cloak) { ................ ................ ................ ....JAA.AAJ..... .....JAAAJAA.... ......JAJAA..... .....JJAJAA..... ....JJJAJAAA.... ...JJJAAJAAAA... ..JJJJAAJAAAAA.. ..JJJAAAAJAAAA.. ..JJJAAAAJAAAA.. ...JJAAAAAJAA... ....AAAAAAAA.... ................ ................ } # tile 124 (robe) { ................ ......CCC....... .....CAAAKA..... ....CCAJJKKA.... .....CAJJKAA.... .....CCJKKAA.... ....CCCAKKKA.... ....CCCCAKKAA... ...CCCCCCAKKA... ...CCCCCCAKKA... ...CCCCCCCAKA... ...CCCCCCCAKA... ...CCCCCCCAKA... ...CCCCCCCAKA... ...ACCCCCCAAA... ....AAAAAAAA.... } # tile 125 (apron / alchemy smock) { ................ ................ .....NO..NO..... .....NAO.NAO.... .....NAO.NAOA... .....NNNNNAOA... .....NNNNNOOA... .....NNNNNOOA... ....ONNNNNOAA... ....ONNNNNNAA... ....NNNNNNNAA... ....NNNNNNNAA... ....NNNNNNNAA... ....NNNNNNNAA... .....NNNNNAA.... ......AAAAA..... } # tile 126 (leather cloak) { ................ ................ ................ ....KJJ.JJK..... .....KJJJKAA.... ......KJKAA..... .....KKAKJA..... ....KKKAKJJA.... ...KKKAAKJJJA... ..KKKKAAKJJJJA.. ..KKKAAJJKJJJA.. ..KKKAAJJKJJJA.. ...KKAJJJJKJA... ....AAAAAAAA.... ................ ................ } # tile 127 (tattered cape / cloak of protection) { ................ ................ ................ .........PO..... ...OOOPPPOAA.... ......OPOAA..... .....OOAOPA..... ....OOOAOPPA.... ...OOOAAOPPPA... ..OOOOAAOPPPPA.. ..OOOAAPPOPPA... ...OOAAPPOPA.... ..OOOA..APOPA... ...AA....AAA.... ................ ................ } # tile 128 (opera cloak / cloak of invisibility) { ................ ......NNN....... .....NAAAO...... ....NNAAAOOA.... .....NAAAOA..... .....NNAOOAA.... ....NNNAOOOAA... ...NNNNNAOOOAA.. ..NNNNNNNAOOOAA. ..NNNNNNNAOOOOA. .NNNNNNNNNAOOOA. .NNNNNNNNNAOOOA. .NNNNNNNNNNAOOA. .NNNNNNNNNNAOOA. ..AANNNNNNAOOAA. ....AAAAAAAAAA.. } # tile 129 (ornamental cope / cloak of magic resistance) { ................ ................ ................ ....AAA..AA..... .....AAAAAPP.... ......AAAPP..... .....AAAAAP..... ....AAAAAAAP.... ...AAAAAAAAAP... ...AAAAAAAAAPP.. ..AAAAAAAAAAAP.. ..AAAAAAAAAAAP.. ..AAAAAAAAAAAP.. ..AAAAAAAAAAAP.. ..AAAAAAAAAAAP.. ...PPPPPPPPPPP.. } # tile 130 (piece of cloth / cloak of displacement) { ................ ................ ........P....... .......PPPA..... ......PPPBPAA... .....PBPBPPPAA.. ....PPPBPPPPBAA. ...PPPBPPBPBPPAA ..PBPBPPPPBPPPPA .PPPBPPPPBPBPPPA .PPBPBPPBPPPBPAA ..BPPPPBPPPPPAA. ...PPPBPBPPPAA.. ....PBPPPBPAA... .....PPPPPAA.... .......PPAA..... } # tile 131 (small shield) { ................ ................ ................ ................ ................ ...C.CJJ.J...... ...CCKKJJJA..... ...CKKKJJJA..... ...CKKJJJJA..... ...CKKJJJJA..... ....CKKJJAA..... .....CKJAA...... ......CAA....... .......A........ ................ ................ } # tile 132 (blue and green shield / elven shield) { ................ ................ ................ ................ ...N.NNNN.N..... ...NNNGFNNNA.... ...NGGGFFFNA.... ...NGGFFFFNA.... ...NGGFFFFNA.... ...NGGFFFFNA.... ....NGGFFNAA.... .....NGFNAA..... ......NNAA...... .......AA....... ................ ................ } # tile 133 (white-handed shield / Uruk-hai shield) { ................ ...K.KKKJJJ.J... ...KKKKKJJJJJ... ...KPPPP....JA.. ...KPPPNOO..JA.. ...KPPPNOOO.JA.. ...KPNPNOOO.JA.. ...KPNNNOOO.JA.. ...KPPNNOO..JA.. ...KPPPNO...JA.. ....KPPNO..JAA.. .....KPP..JAA... ......KP.JAA.... .......KJAA..... ................ ................ } # tile 134 (red-eyed shield / orcish shield) { ................ ................ ...K.KKKJJJ.J... ...KKKKKJJJJJ... ...KPPPP....JA.. ...KPPDDDD..JA.. ...KPDDAADD.JA.. ...KPDDAADD.JA.. ...KPPDDDD..JA.. ....KPPP...JAA.. .....KPP..JAA... ......KP.JAA.... .......KJAA..... ........AA...... ................ ................ } # tile 135 (large shield) { ................ ...N.NNNOOO.O... ...NNNNNOOOOO... ...NPPPPP...OA.. ...NPPP.....OA.. ...NPPP.....OA.. ...NPPPPP...OA.. ...NPPP.....OA.. ...NPPP.....OA.. ...NPPPPP...OA.. ....NPP....OAA.. .....NP...OAA... ......NPPOAA.... .......NOAA..... ........AA...... ................ } # tile 136 (large round shield / dwarvish roundshield) { ................ ................ ................ ................ .....BBBP....... ....BKKKKP...... ...BKKKKKJP..... ...BKKKJJJPA.... ...BKKJJJJPA.... ...BKKJJJJPA.... ....PJJJJPAA.... .....PPPPAA..... ......AAAA...... ................ ................ ................ } # tile 137 (polished silver shield / shield of reflection) { ................ ................ ...N.NNNOOO.O... ...NNNNNOOOOO... ...NPPPPPPPPOA.. ...NPNNPPPPPOA.. ...NPNNPPPPPOA.. ...NPPPPPPPPOA.. ...NPPPPPPPPOA.. ....NPPPPPPOAA.. .....NPPPPOAA... ......NPPOAA.... .......NOAA..... ........AA...... ................ ................ } # tile 138 (old gloves / leather gloves) { ................ ................ .......KJ....... ....KJ.KJ.KJ.... ....KJAJJAKJ.... ..KJ.JJAJJAJJ... ..KJAJJAJJAJJA.. ...JJAJKJJKJJA.. ....JKJJJJJJJA.. ...KAJJJJJJJJA.. ...KJJJJJJJJJJA. ....JJJJJJJJJJA. .....AAAJJJJJAA. ........AJJJAA.. .........AAA.... ................ } # tile 139 (padded gloves / gauntlets of fumbling) { ................ ................ .......KJ....... ....KJ.KJ.KJ.... ....KJAJJAKJ.... ..KJ.KJAKJAKJ... ..KJAJKAKJAKJA.. ...KJAJKKJKKJA.. ....KKJJKJJKJA.. ...KAJKKKKKKJA.. ...KKKKKKKKKJJA. ....JJJJJKKKKJA. .....AAAJJKKKAA. ........AJJKAA.. .........AAA.... ................ } # tile 140 (riding gloves / gauntlets of power) { ................ ................ ................ ....KKJJA....... ...KJJJJJA...... ..KJJJJJJJA..... ..KJJJJJJJA..... ...JJJJJJJJA.... ....JKJJJJJJA... ...KAJJJJJJJA... ...KJJJJJJJJJA.. ....JJJJJJJJJJA. .....AAAJJJJJAA. ........AJJJAA.. .........AAA.... ................ } # tile 141 (fencing gloves / gauntlets of dexterity) { ................ ................ .......NO....... ....NO.NO.NO.... ....NOAOOANO.... ..NO.OOAOOAOO... ..NOAOOAOOAOOA.. ...OOAONOONOOA.. ....ONOOOOOOOA.. ...NAOOOOOOOOA.. ...NOOOOOOOOOOA. ....OOOOOOOOOOA. .....AAAOOOOOAA. ........AOOOAA.. .........AAA.... ................ } # tile 142 (walking shoes / low boots) { ................ ................ ................ ................ ................ ................ ................ ................ ........KJKKJ... ...CKLKLKJJKJA.. ..CKKLKLKJKKJA.. ..KKKKKKKKKKJA.. ..JJJJJJJJJJJA.. ...AAAAAAAAAAA.. ................ ................ } # tile 143 (hard shoes / iron shoes) { ................ ................ ................ ................ ................ ................ ........PPBBP... ........PNPPPA.. ........PPPP.A.. ...OPNPN.PPP.A.. ..OPPPPNP....A.. ..PPPPPPPPPP.A.. ...P.........A.. ...AAAAAAAAAAA.. ................ ................ } # tile 144 (jackboots / high boots) { .......CCKKKK... ......CKAAAAJJ.. ......KKKKKKKJA. .......JKKKKKJA. .......KJKKKKJA. ........JKKKKA.. ........JKKKKA.. ........JKKKKA.. ........KJKKJA.. ...CKLKLKJJKJA.. ..CKKLKLKJKKJA.. ..KKKKKKKKKKJA.. ..JJJJJJJJJJJA.. ...AAAAAAAAAAA.. ................ ................ } # tile 145 (combat boots / speed boots) { ................ ................ .......GGFFFF... ......GFAAAA.... ......FFFFFFF.A. ........FFFFF.A. .......K.FFFF.A. .........FFFFA.. ........F.FF.A.. ...GFLFLF..F.A.. ..GFFLFLF.FF.A.. ..FFFFFFFFFF.A.. ..J..........A.. ...AAAAAAAAAAA.. ................ ................ } # tile 146 (jungle boots / water walking boots) { ................ ................ .......GGGGGG... ......GFAAAAJJ.. ......FFFFFFFJA. .......GFFFFFJA. .......KGFFFFJA. ........GFFFFA.. ........FGFFJA.. ...GFLFLFGGFJA.. ..GFFLFLFGFFJA.. ..FFFFFFFFFFJA.. ..JJJJJJJJJJJA.. ...AAAAAAAAAAA.. ................ ................ } # tile 147 (hiking boots / jumping boots) { ................ ................ ................ ................ ........CCKKKJA. .......CAAAAKJA. .......KJKKKKJA. ........JKKKKA.. ........KJKKJA.. ...CKLKLKJJKJA.. ..CKKLKLKJKKJA.. ..KKKKKKKKKKJA.. ..JJJJJJJJJJJA.. ...AAAAAAAAAAA.. ................ ................ } # tile 148 (mud boots / elven boots) { ................ ................ .......CCKKKK... ......CKAAAAJJ.. ......KKKKKKKJA. .......JKKKKKJA. .......KJKKKKJA. ........JKKKKA.. ........KJKKJA.. ...CKLKLKJJKJA.. ..CKKLKLKJKKJA.. ..KKKKKKKKKKJA.. ..JJJJJJJJJJJA.. ...AAAAAAAAAAA.. ................ ................ } # tile 149 (buckled boots / kicking boots) { ................ ................ .......CCKKKK... ......CKAAAAJJ.. ......KKKKKKKJA. .......JKKKKKJA. .......CJKKKKJA. ......HOOKKKCA.. ...CKHKKHCCCCA.. ..CKKLOHCCCCJA.. .CKKKKKKKJKKJA.. .CKKKKKKKKKKJA.. ..JJJJJJJJJJJA.. ...AAAAAAAAAAA.. ................ ................ } # tile 150 (riding boots / fumble boots) { ................ ................ .......LLLLLL... ......LAAAAAAL.. ......LAAAAAALP. .......LLLLLLAP. .......AAAAAAAP. ........AAAAAP.. ........AAAAAP.. ...AALALAAAAAP.. ..AAALALAAAAAP.. ..AAAAAAAAAAAP.. ...AAAAAAAAAAP.. ...PPPPPPPPPPP.. ................ ................ } # tile 151 (snow boots / levitation boots) { ................ ................ .......NNLLLL... ......NOAAAALL.. ......OOOOOOOLA. .......LOOOOOLA. .......LLOOOOLA. ........LOOOOA.. ........OLOOLA.. ...NOAOAOLLOLA.. ..NOOAOAOLOOOLA. .OOOOOOOOOOOOOA. .OOOOOOOOOOOOOA. ..LALALALALALAA. ...A.A.A.A.A.A.. ................ } # tile 152 (wooden / adornment) { ................ ................ ................ ................ ................ ................ .....KCCKJ...... ....KJAAAKJ..... ....CA...AKA.... ....CA....KA.... ....JKA..KJA.... .....JKKKJAA.... ......AAAAA..... ................ ................ ................ } # tile 153 (granite / gain strength) { ................ ................ ................ ................ ................ .....PPPPP...... ....PBPBPPP..... ...PPPAAAPBP.... ...PBAAAAAPPA... ...PPAA...PPA... ...BPPA..PPBA... ....PPPPPBPAA... .....PBPPPAA.... ......AAAAA..... ................ ................ } # tile 154 (opal / gain constitution) { ................ ................ ................ ................ ......OIO....... .....OIOBOA..... .....OOOBOA..... .....COGOCA..... ....HHAAAHNA.... ....HAA...HA.... ....NHA..HNA.... .....HNHNHAA.... ......AAAAA..... ................ ................ ................ } # tile 155 (clay / increase accuracy) { ................ ................ ................ ................ ................ .....LLLLL...... ....LCCCCLL..... ...LCCAAALLC.... ...LCAAAAALCA... ...LCAA...LCA... ...LCCA..LLCA... ....LLLLLCCAA... .....CCCCCAA.... ......AAAAA..... ................ ................ } # tile 156 (coral / increase damage) { ................ ................ ................ ................ ................ ................ .....OOOOO...... ....OOAAAOO..... ....OAA...NA.... ....OA....OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 157 (black onyx / protection) { ................ ................ ................ ................ .....ANAAA...... .....AAAAA...... ......AAA....... .....OLLLNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 158 (moonstone / regeneration) { ................ ................ ................ ................ ......OBO....... .....OBOOOA..... .....OOOOOA..... .....CCCCCA..... ....HHAAAHNA.... ....HAA...HA.... ....NHA..HNA.... .....HNHNHAA.... ......AAAAA..... ................ ................ ................ } # tile 159 (tiger eye / searching) { ................ ................ ................ ................ .....KCACKA..... .....CCACCA..... .....ACCCA...... .....OCOCNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 160 (jade / stealth) { ................ ................ ................ ................ ......NFF....... .....FFFFFA..... .....FFFFFA..... .....OLLLNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 161 (bronze / sustain ability) { ................ ................ ................ ................ ................ ................ .....CHCCC...... ....CHAAACC..... ....CAA..ACA.... ....CA....CA.... ....CCA..CCA.... .....CCCCCAA.... ......AAAAA..... ................ ................ ................ } # tile 162 (agate / levitation) { ................ ................ ................ ................ .....PNOOPA..... .....OIOIOA..... .....AOIOA...... .....LHHHLA..... ....LHAAAHLA.... ....HAA...HA.... ....LHA..HLA.... .....LHHHLAA.... ......AAAAA..... ................ ................ ................ } # tile 163 (topaz / hunger) { ................ ................ ................ ................ .....PNBBPA..... .....BOOOBA..... .....ABBBA...... .....OLLLNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 164 (sapphire / aggravate monster) { ................ ................ ................ ................ ......NEE....... .....EEEEFA..... .....AEEFA...... .....OFEFNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 165 (ruby / conflict) { ................ ................ ................ ................ .....JLDDJA..... .....DDDDDA..... .....ADDDA...... .....OLLLNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 166 (diamond / warning) { ................ ................ ................ ................ .....PNNNPA..... .....NNNNBA..... .....ANNBA...... .....PPPPPA..... ....PPAAAPPA.... ....PAA...PA.... ....PPA..PPA.... .....PPPPPAA.... ......AAAAA..... ................ ................ ................ } # tile 167 (pearl / poison resistance) { ................ ................ ................ ......NNN....... .....NONNNA..... .....NNNNNA..... .....ANNNA...... .....LHHHLA..... ....LHAAAHLA.... ....HAA...HA.... ....LHA..HLA.... .....LHHHLAA.... ......AAAAA..... ................ ................ ................ } # tile 168 (iron / fire resistance) { ................ ................ ................ ................ ................ ................ .....PPPPP...... ....PPAAAPP..... ....PA....PA.... ....PA....PA.... ....PPA..PPA.... .....PPPPPAA.... ......AAAAA..... ................ ................ ................ } # tile 169 (brass / cold resistance) { ................ ................ ................ ................ ................ ................ .....HHHCC...... ....HCAAACC..... ....HAA...CA.... ....CA....HA.... ....CCA..HCA.... .....CCCHCAA.... ......AAAAA..... ................ ................ ................ } # tile 170 (copper / shock resistance) { ................ ................ ................ ................ ................ ................ .....CCCCC...... ....CCAAACC..... ....CAA..ACA.... ....CA....CA.... ....CCA..CCA.... .....CCCCCAA.... ......AAAAA..... ................ ................ ................ } # tile 171 (twisted / free action) { ................ ................ ................ ................ ................ ................ .....APPBP...... ....PPAAAAP..... ....PAA..APA.... ....PA....BA.... ....BPA..APA.... .....APBPPAA.... ......AAAAA..... ................ ................ ................ } # tile 172 (steel / slow digestion) { ................ ................ ................ ................ ................ ................ .....PBBPP...... ....PBAAAPP..... ....PAA..APA.... ....PA....PA.... ....PPA..PPA.... .....PPPPPAA.... ......AAAAA..... ................ ................ ................ } # tile 173 (silver / teleportation) { ................ ................ ................ ................ ................ ................ .....PNBPP...... ....PBAAAPP..... ....BAA..APA.... ....BA....PA.... ....PPA..PPA.... .....PPPBPAA.... ......AAAAA..... ................ ................ ................ } # tile 174 (gold / teleport control) { ................ ................ ................ ................ ................ ................ .....LHHHL...... ....LHAAAHL..... ....HAA..AHA.... ....HA....HA.... ....LHA..HLA.... .....LHHHLAA.... ......AAAAA..... ................ ................ ................ } # tile 175 (ivory / polymorph) { ................ ................ ................ ................ ................ ................ .....OOONO...... ....OOAAAOO..... ....NAA..ANA.... ....OA....OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 176 (emerald / polymorph control) { ................ ................ ................ ................ .....PGFFPA..... .....FGFFFA..... .....AFFFA...... .....OCECNA..... ....OOAAAONA.... ....OAA...OA.... ....NOA..ONA.... .....ONONOAA.... ......AAAAA..... ................ ................ ................ } # tile 177 (wire / invisibility) { ................ ................ ................ ................ ................ ................ .....PPPPP...... ....PPAAAPP..... ....PAA...PA.... ....PA.....PA... ....PA.....PA... ....PAAPPPPA.... .....PPPAAA..... ......AA........ ................ ................ } # tile 178 (engagement / see invisible) { ................ ................ ................ ................ .....PNNNPA..... .....NNNNNA..... .....ANNNA...... .....LHHHLA..... ....LHAAAHLA.... ....HAA...HA.... ....LHA..HLA.... .....LHHHLAA.... ......AAAAA..... ................ ................ ................ } # tile 179 (shiny / protection from shape changers) { ................ ................ ................ ................ ................ ................ .....NNNNN...... ....NNAAANN..... ....NA....NA.... ....NA....NA.... ....NNA..NNA.... .....NNNNNAA.... ......AAAAA..... ................ ................ ................ } # tile 180 (circular / amulet of ESP) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......ACCCA..... ......CKKKKA.... ......CKKKKA.... .......KKKAA.... .......AAAA..... ................ ................ } # tile 181 (spherical / amulet of life saving) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......AKKKAA.... ......KHCCKAA... ......KCCCKAA... ......AKKKAA.... .......AAAA..... ................ ................ } # tile 182 (oval / amulet of strangulation) { ................ ......LLLLLLAA.. .....LAA....LAA. ....LAA......LAA ....LAA......LAA ....LAA......LAA ....LAA......LAA .....LAA....LAA. ......LAAA.LAA.. ......ACCCCA.... ......CKKKKKA... ......CKKKKKA... ......AKKKKA.... .......AAAA..... ................ ................ } # tile 183 (triangular / amulet of restful sleep) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......ALCLAA.... .......CKKA..... ......CKKKKA.... .....CKKKKKKA... .......AAAAAA... ................ ................ } # tile 184 (pyramidal / amulet versus poison) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......ALCLAA.... .......CCKAA.... ......CCCKKA.... .....CCCKKKKA... ....CCKJJJJKKA.. ....KJJJJJJJJA.. .......AAAAAAA.. } # tile 185 (square / amulet of change) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......ALALAA.... ......CCCCCA.... ......CKKKKA.... ......CKKKKA.... ......CKKKKA.... .......AAAAA.... ................ } # tile 186 (concave / amulet of unchanging) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......AJJKAA.... ......JJJCKAA... .....JJJKKCCA... .....JJKKCLCA... ......JJCLCAA... .......KCCAA.... ........AAA..... } # tile 187 (hexagonal / amulet of reflection) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LA..LAA... ......ACCCAA.... ......CKKKKAA... .....CKKKKKKA... ......KKKKKAA... .......KKKAA.... ........AAA..... ................ } # tile 188 (octagonal / amulet of magical breathing) { ................ ......LLLLLAA... .....LAA...LAA.. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. ....LAA.....LAA. .....LAA...LAA.. ......LAA.LAA... ......ACCCAA.... ......CKKKKAA... .....CKKKKKKA... .....CKKKKKKA... ......KKKKKAA... .......KKKAA.... ........AAA..... } # tile 189 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor) { ................ ......HHHHHAA... .....HAA...HAA.. ....HAA.....HAA. ....HAA.....HAA. ....HAA.....HAA. ....HAA.....HAA. .....HAA...HAA.. ......HAA.HAA... ......AHCCAA.... ......BCDDPAA... ......BCDDPAA... ......ABPPAA.... .......AAAA..... ................ ................ } # tile 190 (Amulet of Yendor / Amulet of Yendor) { ................ ......HHHHHAA... .....HAA...HAA.. ....HAA.....HAA. ....HAA.....HAA. ....HAA.....HAA. ....HAA.....HAA. .....HAA...HAA.. ......HAA.HAA... ......AHCCAA.... ......BCDDPAA... ......BCDDPAA... ......ABPPAA.... .......AAAA..... ................ ................ } # tile 191 (large box) { ................ ................ ................ ................ ....CCCCCCCCCCJ. ...CKKKKCKKKCJJ. ..CKJJKCJJJCJJJ. .CJJJKCJJJCJJJJ. CCCCCCCCCCCJJJJ. CJJJJJJJJJJJJJJA CJKKKCJKKKCJJJJA CJKKKHHKKKCJJJJA CJKKKCJKKKCJJJAA CJCCCCJCCCCJJAA. CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } # tile 192 (chest) { ................ ................ ................ ...CJKKKCJKKKC.. .CKJKKCKJKKCJJK. .KJKKKKJKKKKJJJ. CJKKKCJKKKCJJJJ. CJKKKCJKKKCJJJJ. CCCCCHHCCCCJJJJ. CJJJHJJHJJJJJJJ. CJKKKHHKKKCJJJJA CJKKKHHKKKCJJJJA CJKKKCJKKKCJJJAA CJCCCCJCCCCJJAA. CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } # tile 193 (ice box) { ................ ................ ................ ................ ....NNNNNNNNNNN. ...NPBBBBBBBBNP. ..NPPBBBBBBBNPP. .NPPPBBBBBBNPPP. NNNNNNNNNNNPPPP. NBBBBBBBBBBPPPPA NNNNBBBBBBBPPPPA NBBBBBBBBBBPPPPA NNBBBBBBBBBPPPAA NBBBBBBBBBBPPAA. NBBBBBBBBBBPAA.. .AAAAAAAAAAAA... } # tile 194 (bag / sack) { ................ ................ ................ ....CJKKKKJ..... .....CJKKJAA.... ....OOOOOAA..... ...O.OKKKJA..... ....COKKKKJA.... ...CCCKKKKKJA... ..CCCKKKKKKJJA.. ..CCCKKKKKKJJA.. ..CCKKKKKKJJJA.. ...CKKKKJJJJA... ....AAAAAAAA.... ................ ................ } # tile 195 (bag / oilskin sack) { ................ ................ ................ ....CJKKKKJ..... .....CJKKJAA.... ....OOOOOAA..... ...O.OKKKJA..... ....COKKKKJA.... ...CCCKKKKKJA... ..CCCKKKKKKJJA.. ..CCCKKKKKKJJA.. ..CCKKKKKKJJJA.. ...CKKKKJJJJA... ....AAAAAAAA.... ................ ................ } # tile 196 (bag / bag of holding) { ................ ................ ................ ....CJKKKKJ..... .....CJKKJAA.... ....OOOOOAA..... ...O.OKKKJA..... ....COKKKKJA.... ...CCCKKKKKJA... ..CCCKKKKKKJJA.. ..CCCKKKKKKJJA.. ..CCKKKKKKJJJA.. ...CKKKKJJJJA... ....AAAAAAAA.... ................ ................ } # tile 197 (bag / bag of tricks) { ................ ................ ................ ....CJKKKKJ..... .....CJKKJAA.... ....OOOOOAA..... ...O.OKKKJA..... ....COKKKKJA.... ...CCCKKKKKJA... ..CCCKKKKKKJJA.. ..CCCKKKKKKJJA.. ..CCKKKKKKJJJA.. ...CKKKKJJJJA... ....AAAAAAAA.... ................ ................ } # tile 198 (key / skeleton key) { ................ ................ ................ ................ ................ ................ ..OO............ .O.AOOOOOOOOOO.. .OA.OAAAAOAOAOA. .OA.OA...OA.AOA. ..OO.A....A...A. ...AA........... ................ ................ ................ ................ } # tile 199 (lock pick) { ................ ................ ................ ................ ................ ................ ................ .BBBPPPPP....... .BPPPPPPPPPPPA.. .BPPAAAAAAAAAAA. .BPPA........... ..AAA........... ................ ................ ................ ................ } # tile 200 (credit card) { ................ ................ ................ ................ ................ ..PPPPPPPPPPPP.. .PPPDDDDPCCCPPP. .PPDDDDPCCCCCPPA .PPDDDDPCCCCCPPA .PPDDDDPCCCCCPPA .PPPDDDDPCCCPPPA ..PPPPPPPPPPPPAA ...AAAAAAAAAAAA. ................ ................ ................ } # tile 201 (candle / tallow candle) { ................ ................ ................ ...NNAAA........ .....NPOA....... .....PNNOA...... .....OOONOA..... ......OOONOA.... .......OOONOA... ........OOONOA.. .........OOONOA. ..........OOOPA. ...........OPA.. ............A... ................ ................ } # tile 202 (candle / wax candle) { ................ ................ ................ ...NNAAA........ .....NPOA....... .....PNNOA...... .....OOONOA..... ......OOONOA.... .......OOONOA... ........OOONOA.. .........OOONOA. ..........OOOPA. ...........OPA.. ............A... ................ ................ } # tile 203 (brass lantern) { ................ ................ ......CCC....... .....C.AAC...... .....CA..CA..... .....LHHHLA..... ....LNNHNNLA.... ....HNNHNNHA.... ....HNNHNNHA.... ....HNNHNNHA.... ....LHHHHHLA.... .....LHHHLA..... .....LHHHLA..... ....LHHHHHL..... .....AAAAAAA.... ................ } # tile 204 (lamp / oil lamp) { ................ ................ ................ ................ ................ ................ ................ ........HA...... .LHC..LNLLLA.... ...HHHNHHHHHHH.. ....CLHHHHHLCHA. .....ACLHLCCAAA. ......LHHHLAA... ......AAAAAA.... ................ ................ } # tile 205 (lamp / magic lamp) { ................ ................ ................ ................ ................ ................ ................ ........HA...... .LHC..LNLLLA.... ...HHHNHHHHHHH.. ....CLHHHHHLCHA. .....ACLHLCCAAA. ......LHHHLAA... ......AAAAAA.... ................ ................ } # tile 206 (expensive camera) { ................ ................ ................ ................ ................ ......AAA....... ...A.AAAAAAAAA.. ..AAAAAAAAABBA.. ..AAAAPPPAABBA.. ..AAAPPBPPAAAAP. ..AAAPBBBPAAAAP. ..AAAPPBPPAAAAP. ..AAAAPPPAAAAAP. ..AAAAAAAAAAAAP. ...PPPPPPPPPPPP. ................ } # tile 207 (looking glass / mirror) { ................ ................ ....BBBBA....... ...BPPPPBA...... ..BPPPPPPBA..... ..BPPPPPPPBA.... ..BPPPPPPPBA.... ..BPPPPPPPBA.... ...BPPPPPPBA.... ....BPPPPBBA.... .....BBBBBBBA... ..........BBBA.. ...........BBBA. ............BBA. ................ ................ } # tile 208 (glass orb / crystal ball) { ................ ................ ................ ................ ................ .....BBBB....... ....BNBBBB...... ....BBBBBB...... ....BBBBBB.AA... ....BBBBBBAAAA.. ....CBBBBJAAA... ...CKKKKKJJA.... ....KKKKJJA..... ................ ................ ................ } # tile 209 (lenses) { ................ ................ ................ ................ ................ ................ .....PP.....P... ....P..PA..P.PA. ...P..AA..P.AA.. ..PNBAA.NBPAA... ..NAABPNAABAA... ..BA.PABA.PAA... ...BPAA.BPAA.... ................ ................ ................ } # tile 210 (blindfold) { ................ ................ ................ ................ ................ ....OOOOOOOO.... ...OOOOOOOOOO... ...OOOOOOOOOOA.. ..OAOOOAAOOOAOA. ..OAAAAAAAAAAOA. ...OOA.......OA. .....OA.....OA.. .....OA.....OA.. ......OOA..OA... ................ ................ } # tile 211 (towel) { ................ ................ ................ ........PPPPPPP. ........OOOOOOO. ........OOOOOOO. ...OOOOOOBOOOOO. ..OOOOOOOPPOOOA. ..OOOOOOOPPOOOA. ..OOOOOOOPPPOA.. .OOOOOOOPPPPPA.. .OOOOOOOAAAAA... .PPPPPPPA....... ................ ................ ................ } # tile 212 (saddle) { ................ ................ ................ ....JJA...JJA... ....JKJJJJKJA... .....JCCKKJA.... .....JKKKKJA.... ......JKKJA..... .......JJAA..... .......JAA.A.... .......PA..A.... ......PAPAA..... ......PPPA...... .......AAA...... ................ ................ } # tile 213 (leash) { ................ ................ .......KKJ...... ......JJJJA..... .....JAAAAA..... ....KAA......... ....JA.......... ....JA.......... .....JJJJ....... ......AAAJ...... .........AJ..... ...PPPPP..KA.... ..PPAAAPPKAA.... ...PPPPPAAA..... .....AAAA....... ................ } # tile 214 (stethoscope) { ................ ................ ...PN...NP...... ..PAA....APA.... ..PA......PA.... ...PA....PA..... ...PA....PA..... ....PA..PA...... ....PA..PAPPP... .....PPPA.JJPA.. .....PJPA.JPPA.. ......JA..JAAA.. ......JA.JJA.... .......JJJA..... ........AAA..... ................ } # tile 215 (tinning kit) { ................ ................ .....POOOOOOOOP. ....PPOOOOOOOPP. ...PPPAAAAAAPPP. ..OOOOOOOOOOPPPA ..OOOOBBBOOOPPPA ..OOOBPPP.OOPPAA ..OOOBPBP.OOPAA. ..OOOOBP..OOAA.. ...AAOOOP.AAA... .....BOOP.A..... .....BPPP.A..... .....ABP.A...... ......AAA....... ................ } # tile 216 (tin opener) { ................ ................ ........BA...... ........BPA..... ......P.BPPA.... ......PABPPA.... ......BPPPAA.... .......BPAA..... .......KJA...... .......KJA...... .......KJA...... .......KJA...... .......KJA...... .......KJA...... ........AA...... ................ } # tile 217 (can of grease) { ................ ................ ................ ................ ................ ................ ................ .....BPPPP...... ....BAAAAAP..... ....BPAAAP.A.... ....BBPPP..AA... ....BBPPP..AAA.. ....BBPPP..AA... .....BPPP.AA.... .......AAAA..... ................ } # tile 218 (figurine) { ................ ................ ................ ........JJ...... .......KCJJ..... .......KKJJ..... ....CK.CJ....... ....JJCKJ.CJ.... .....JCKJJJJAA.. ......CKAA.AAAA. ....KCKKAAAAAA.. ...JCCKKAJJAA... ...JKKKKJJJJA... ....JJKKJJJAA... .....JJJJJAA.... ................ } # tile 219 (magic marker) { ................ ................ ................ ................ ................ ..........B..... .........BIE.... ........BIEAA... .......BIEAA.... ......BIEAA..... .....BIEAA...... ....NNEAA....... ....NNAA........ .....AA......... ................ ................ } # tile 220 (land mine) { ................ ................ ................ ................ ................ ................ ................ .......A........ .....FFAFF...... ....F.AAA.FA.... ....FGFFFFFAA... .....GFFFFAA.... ......AAAA...... ................ ................ ................ } # tile 221 (beartrap) { ................ ................ ................ .....PO.OP...... ....PA...AP..... ....PPO.OPPA.... ....PA...APA.... ....PPOAOPPAA... ....PAAAAAPAA... ....PAA...PAA... ....PPA..PPA.... .....PPPPPAA.... ......PPPAA..... ................ ................ ................ } # tile 222 (whistle / tin whistle) { ................ ................ ................ ................ ................ ................ ................ ..BBABBBBBBB.... .BPPPPPPPPPPA... .PPPPPPAAAAAA... .PPPPPPA........ ..PPPPAA........ ...AAAA......... ................ ................ ................ } # tile 223 (whistle / magic whistle) { ................ ................ ................ ................ ................ ................ ................ ..BBABBBBBBB.... .BPPPPPPPPPPA... .PPPPPPAAAAAA... .PPPPPPA........ ..PPPPAA........ ...AAAA......... ................ ................ ................ } # tile 224 (flute / wooden flute) { ................ ................ ............J... ...........AJ... ..........KJA... .........KJA.... ........KJA..... .......JJA...... ......KJA....... .....JJA........ ....KJA......... ...JJA.......... ..KJA........... .JJA............ ..A............. ................ } # tile 225 (flute / magic flute) { ................ ................ ............J... ...........AJ... ..........KJA... .........KJA.... ........JJA..... .......JJA...... ......KJA....... .....JJA........ ....KJA......... ...JJA.......... ..KJA........... .JJA............ ..A............. ................ } # tile 226 (horn / tooled horn) { ................ ................ ...........N.... ..........NOO... .........NOO.... .......NNOOP.... ....NNPOOOO..... ...NKKNPOOP.A... ..NKJAANPO.AAA.. ..NKAAANPPAAA... ..NKJAJNPAAA.... ...NKKNPAAA..... ....NNPAAA...... ....AAA......... ................ ................ } # tile 227 (horn / frost horn) { ................ ................ ...........N.... ..........NOO... .........NOO.... .......NNOOP.... ....NNPOOOO..... ...NKKNPOOP.A... ..NKJAANPO.AAA.. ..NKAAANPPAAA... ..NKJAJNPAAA.... ...NKKNPAAA..... ....NNPAAA...... ....AAA......... ................ ................ } # tile 228 (horn / fire horn) { ................ ................ ...........N.... ..........NOO... .........NOO.... .......NNOOP.... ....NNPOOOO..... ...NKKNPOOP.A... ..NKJAANPO.AAA.. ..NKAAANPPAAA... ..NKJAJNPAAA.... ...NKKNPAAA..... ....NNPAAA...... ....AAA......... ................ ................ } # tile 229 (horn / horn of plenty) { ................ ................ ...........N.... ..........NOO... .........NOO.... .......NNOOP.... ....NNPOOOO..... ...NKKNPOOP.A... ..NKJAANPO.AAA.. ..NKAAANPPAAA... ..NKJAJNPAAA.... ...NKKNPAAA..... ....NNPAAA...... ....AAA......... ................ ................ } # tile 230 (harp / wooden harp) { ................ ................ ................ ................ ..KKK......KKK.. ..KAKPPPPPPKAKA. ...AKA.....KA.A. ...KPPPPPPPPK... ...KA.......KA.. ...KPPPPPPPPKA.. ...KA.......KA.. ....KPPPPPPK.A.. .....KKKKKK.A... ......AAAAAA.... ................ ................ } # tile 231 (harp / magic harp) { ................ ................ ................ ................ ..KKK......KKK.. ..KAKPPPPPPKAKA. ...AKA.....KA.A. ...KPPPPPPPPK... ...KA.......KA.. ...KPPPPPPPPKA.. ...KA.......KA.. ....KPPPPPPK.A.. .....KKKKKK.A... ......AAAAAA.... ................ ................ } # tile 232 (bell) { ................ .......KA....... ......KAKA...... .......KA....... ......LCKA...... .....LCCCKA..... .....LCCCKA..... .....LCCCKAA.... ....CLCCCKCA.... ...CLLCCCKLKA... ...CCLLLLLCKA... ....CCCCCCKAA... .....AAKKAAA.... .......AAA...... ................ ................ } # tile 233 (bugle) { ................ ................ ................ ................ ..L............. .KCL............ .KCCL........LL. .KCCCLCCCCCCCLA. .KCCKAAKKKKKAACA .KCKAAJCAAACJAA. ..KAA..JCCCJAA.. ...A....AAAAA... ................ ................ ................ ................ } # tile 234 (drum / leather drum) { ................ ................ ................ ................ .....POOOOP..... ....OOOOOOOO.... ...OOOOOOOOOO... ...LOOOOOOOOLAA. ...LKOOOOOOJLAAA ...KKLKKKKLJJAAA ...JKLKKKKLJJAA. ....JKKKKKKJAA.. .....JJJJJJAA... ......AAAAAA.... ................ ................ } # tile 235 (drum / drum of earthquake) { ................ ................ ................ ................ .....POOOOP..... ....OOOOOOOO.... ...OOOOOOOOOO... ...LOOOOOOOOLAA. ...LKOOOOOOJLAA. ...KKLKKKKLJJAA. ...JKLKKKKLJJAA. ....JKKKKKKJAA.. .....JJJJJJAA... ......AAAAAA.... ................ ................ } # tile 236 (pick-axe) { ................ ................ ................ ......BBA....... .....BPPBA...... ......PPPBA..... .......KPPPA.... ......KJA.PPA... .....KJA...PA... ....KJA......... ...KJA.......... ..KJA........... .KJA............ ..A............. ................ ................ } # tile 237 (iron hook / grappling hook) { .............N.. ..............P. ...........NPAPA .............PAA .......OOEPPPPA. .....OOAAAAAAAPA ....OAA.......PA ....OA.......NA. ....OA.......... .....OOAA....... .......OOOA..... ..........OA.... ..........OA.... .OA.......OA.... ..OOA..OOOA..... ....OOOAA....... } # tile 238 (unicorn horn) { ................ ................ ................ ..H............. ...LA........... ...LHLA......... ....HLHAA....... .....LHLHA...... ......HLHLAA.... ......LLHLHHA... .......HHLHDA... ........LHDDA... ........HDDA.... .........AA..... ................ ................ } # tile 239 (candelabrum / Candelabrum of Invocation) { .......N........ .......D........ .......D...N.... ...N...D...D.... ...D...D...D.... ...D..HDH..D.... ..HDH..H..HDH... ...H...H..AH.... ...OHHHHHHHO.A.. ......OHOAA.A... .......H..AAA..A ......OHOAAAAAA. .....OHHHHA..A.. ......HHHAA..... ................ ................ } # tile 240 (silver bell / Bell of Opening) { ................ .......OA....... ......OAOA...... .......OA....... ......NOPA...... .....NOOOPA..... .....NOOOPA..... .....NOOOPAA.... ....ONOOOPOA.... ...ONNOOOPNPA... ...OONNNNNOPA... ....OOOOOOPAA... .....AAPPAAA.... .......AAA...... ................ ................ } # tile 241 (tripe ration) { ................ ................ ................ ................ ................ ................ ................ .....OOOO....... ....DODDDOO..... ...ODODOOODA.... ...OOOOODDDA.... ....DODOOOOA.... .....ODOODAA.... ......AAAAA..... ................ ................ } # tile 242 (corpse) { ................ .....D.DPLN..... ...NO.DDLNOA.... ..POOAD..OONN... .ONONN.DLNNNN... .NPANDCCCNAAAA.. ..AADCCCCAAD.... ..DDDCCCDADDDD.. ..D.NCDCCN.D.... .PNNNOAADNNPNN.. .ONPON.DD.NONOA. ...PNNA.D.PNAAA. ...LNAA.D.NPA... ....AA.....AA... ................ ................ } # tile 243 (egg) { ................ ................ ................ ................ ................ ....PONOP....... ....ONNNO....... ...PNNNNNP...... ...ONNNNNO.AAA.. ...NNNNNNOAAAA.. ...ONNNNOOAAAA.. ...PONNOOPAAA... ....POOOPAAA.... ................ ................ ................ } # tile 244 (meatball) { ................ ................ ................ ................ ................ ................ ................ .....KKCK....... ....KCDJDJ...... ....CDJDJJAAA... ....DCDJAJAAA... ....KDDJJJAAA... .....JJAJAAA.... ................ ................ ................ } # tile 245 (meat stick) { ................ ................ ................ ...........CD... ..........CDAA.. .........LDAA... .......DLKAA.... ......LCKAA..... .....LCKAA...... ....LLKAA....... ...DCKAA........ ...CKAA......... ....AA.......... ................ ................ ................ } # tile 246 (huge chunk of meat) { ................ ................ .....KDKK....... ...KKJJJJKD..... ..KCCKKCJJJK.... ..KCKKCJJJJKA... .KKKKJJJDDJJKAA. .KKKJJJJJJJJKAAA .KCKDJJJDJJJJAAA .KKJDJJDJJAJAAAA .KKKKJJDKKDJJAAA .DKDJJJKKKKAJAA. DKKKKAJJAJDAJJA. KKKKKKKKKJJJAJA. ................ ................ } # tile 247 (meat ring) { ................ ................ ................ ................ ................ ................ .....OOOA....... ....OAA.OOA..... ....OAA...OA.... .....OAA...OA... .....OAA...OA... .....OA....OA... ....OAAA..OAA... .....OOOOOAA.... ......AAAAA..... ................ } # tile 248 (glob of gray ooze) { ................ ................ ................ ................ ................ ................ .....PPPPPP..... .....PPPPPPP.... ...PPPPPPPP..... ....PPPPPPPP.... ..PPPPPPPPPP.... ...PPPPPPPPPP... ..P.PPPPPPP.PA.. ..PPPPA.P.PPA... ...AAA.AAAAA.... ................ } # tile 249 (glob of brown pudding) { ................ ................ ................ ................ ................ ................ .....JJJJJJ..... .....JJJJJJJ.... ...JJJJJJJJ..... ....JJJJJJJJ.... ..JJJJJJJJJJ.... ...JJJJJJJJJJ... ..J.JJJJJJJ.JA.. ..JJJJA.J.JJA... ...AAA.AAAAA.... ................ } # tile 250 (glob of green slime) { ................ ................ ................ ................ ................ ................ .....FFFFFF..... .....FFFFFFF.... ...FFFFFFFF..... ....FFFFFFFF.... ..FFFFFFFFFF.... ...FFFFFFFFFF... ..F.FFFFFFF.FA.. ..FFFFA.F.FFA... ...AAA.AAAAA.... ................ } # tile 251 (glob of black pudding) { ................ ................ ................ ................ ................ ................ .....AAAAAA..... .....ADAAAAA.... ...AAAAADAA..... ....AAAAADAA.... ..AAAAAAAAAA.... ...AAADAAAAAA... ..A.AAAAAAD.AA.. ..AAAAA.A.AAA... ...AAA.AAAAA.... ................ } # tile 252 (kelp frond) { ....FA.......... ....FFA......... .....FFA........ .......FFA...... ........FA...... ........FFA..... ........FFA..... ........FFA..... .......FFA...... .......FFA...... ......FFA....... .....FFFA....... .....FFA........ .....FFFA....... .....FFFFA...... ......FFFFA..... } # tile 253 (eucalyptus leaf) { ................ ................ ................ .......L........ .......LA....... .......LH....... ......GOHA...... ......GOOA...... .....GOOA....... .....GOHA....... .....OOA........ ....OHA......... ....OA.......... ...OA........... ................ ................ } # tile 254 (apple) { ................ ................ ................ ....FF.......... ......F......... ....CCFFCC...... ...CLLKCDDK..... ...CLDDDCDKA.... ...CDDDDDDKAA... ...DDDDDDDKAA... ...DDDDDDKKAA... ....DDKDKKAA.... .....KAAKAA..... ................ ................ ................ } # tile 255 (orange) { ................ ................ ....FFF......... .......FGG...... .....CCFCCD..... ....CGGCCCCD.... ...DCCCCCCCDA... ...CCCCCCCCDKA.. ...CCCCCCCDDKA.. ...DCCCCCDDKJA.. ....DCCCDDKKAA.. .....DDDDKKAA... ......AKKJAA.... .......AAAA..... ................ ................ } # tile 256 (pear) { ................ ................ ................ .........FFCC... ........FGCF.... .......FGGGFAA.. .....FFGHGFAA... ...FGHHHGFFAA... ..FGHHGGGFFA.... ..FHHGGGGFFA.... ..FHHGGGGF.A.... ...FGGGGF.AA.... ....FFF..AA..... .....AAAAA...... ................ ................ } # tile 257 (melon) { ................ ................ ................ ................ ......FFFF...... ....FGGGGGF..... ...FGGGGGGGFA... ...GGGGGGGGFAA.. ..FGGGGGGGGFAA.. ..FGGGGGGGGFAA.. ..FGGGGGGGGAA... ..FGGKAGGGFAA... ...FKAGGGFAA.... .....FFFAAA..... ......AAA....... ................ } # tile 258 (banana) { ................ ................ ............J... ............HA.. ............HH.. ...........HOHA. ...........HOHA. ..........HOHHA. ..........HOHJA. .........HOHHAA. ........HOHHJA.. ......HHOHHJAA.. ..JHOOOOHHJAA... ....HHHHJAAA.... .....AAAAA...... ................ } # tile 259 (carrot) { ................ ..........F..F.. ..........GFGAA. ..........FFA... ..........GFFF.. .......CCGFAA... ......CCCCA..... ......DCCC...... .....CCDCA...... ....CCCCAA...... ....DCAAA....... ...CCAA......... ..CDAA.......... ..CAA........... ...A............ ................ } # tile 260 (sprig of wolfsbane) { ................ ................ ................ ...........HH... ..........H..H.. ...HHHF...FAA... ..H.AAAF.FA..A.. ..HAA...FA...... ...A...FFA...... ......FFAA...... .....FFAA....... ...FFFAA........ ....AAA......... ................ ................ ................ } # tile 261 (clove of garlic) { ................ ................ ................ ................ ................ .....O.......... ....OOOAA....... ....OOOOAA...... ....HOOOOAA..... ....HHOOOOAA.... .....HHHOOOAA... .......HOOOAA... ........AAAA.... ................ ................ ................ } # tile 262 (slime mold) { ................ ................ ................ ...........J.... ........FGJF.... ......FFGGGF.... ....FGGGGGGFA... ...FGGGGGCGCA... ...GGGGGGGCCA... ..FGGGGCGCCKA... ..FGGCGGCCKJA... ...CGGCCCKJA.... ....CCCKJAAA.... .....AAAAA...... ................ ................ } # tile 263 (lump of royal jelly) { ................ ................ ................ ................ ................ ................ ................ ................ .....OH......... ....ONHHAAA..... ...ONOHHHAAA.... ..HOOOOHHHHA.... ....HOOHHAAA.... ......AAAAA..... ................ ................ } # tile 264 (cream pie) { ................ ................ ................ ................ ................ ................ ................ ....OOOOOOOO.... ...OONNNNOONOA.. ..KNONOOONNNNJA. ...KKKKKKKKJJAA. ....JJJJJJJJAA.. ......AAAAAAA... ................ ................ ................ } # tile 265 (candy bar) { ................ ................ ................ ................ ........IA...... .......BIIA..... ......IBBIIA.... .....NIIBBAA.... ....NNNIIAA..... ...NNCNNAA...... ..IINNNAA....... .IIIINAA........ ..IIIAA......... ...IAA.......... ....A........... ................ } # tile 266 (fortune cookie) { ................ ................ ................ ................ ................ ................ ................ .....LL......... ....LLLLLL...... ...LLLLLLLL..... ...LLLKJJKAA.... ...LLLLLJAA..... ....LLLLAA...... .....AAAA....... ................ ................ } # tile 267 (pancake) { ................ ................ ................ .....OOOOOO..... ....OOOOOOOO.... ....OOOOKOOOO... ...OOKOOOOOOOA.. ..OOOOOOOKOOOA.. ..OOOOOOOOOOOA.. ..OOKOOOOOOOOA.. ..OOOOOOOKOOAA.. ...OOOKOOOOOAA.. ....OOOOOOOAA... .....AAAAAAA.... ................ ................ } # tile 268 (lembas wafer) { ................ ................ ................ ................ .......OO....... ......OOLOO..... .....OOLOOLOO... ....OOLOOLOOLOO. ...OOLOOLOOLOOA. ..OOLOOLOOLOOA.. ...AOOLOOLOOA... .....AOOLOOA.... .......AOOA..... .........A...... ................ ................ } # tile 269 (cram ration) { ................ ...JKA.......... ...PBA.......... ...PBA.......... ...PBPA......... ...BBPAKKKKKA... ...BBPKKKKKKKA.. ...OPKKKKKKKA... ...OKKKKKKKJJA.. ...BPKLLOKJJJA.. ...PKLOLOLKJJA.. ...AKOLOLLKJAA.. ....KLOLLOKAA... ....KKKKKKKA.... .....AAAAAA..... ................ } # tile 270 (food ration) { ...JJA.......... ...BPA.......... ...BPA.......... ..BBBPA......... ..BBBPAKKKKKKKA. .BBBBPKKKKKKKKKA .BOOPKKKKKKKKKA. .BOOKKKKKKKKKJJA .BOOPKLLLLOKJJJA .BPPKLOLLLOLKJJA ..PAKOLOOOLLKJJA .PPPKLOLLLOLKJJA ...AKOLOOOLLKJAA ....KLOLLLLOKAA. ....KKKKKKKKKA.. .....AAAAAAAA... } # tile 271 (K-ration) { ................ ................ ...JJA.......... ...BPA.......... ..BBBPA......... ..BBBPKKKKKKKA.. ..OOPKKKKKKKKKA. ..OOKKKKKKKKKJA. ..OOPKLLLLOKJJA. ..PPKLLELEOLKJA. ..PAKOLEELLLKJA. ..PPKLLEELOLKJA. ...AKOLELELLKJA. ....KLLLLLLOKAA. ....KKKKKKKKKA.. .....AAAAAAAA... } # tile 272 (C-ration) { ................ ................ ...JJA.......... ...BPA.......... ..BBBPA......... ..BBBPA......... ..OOPKKKKKKKKA.. ..OOKKKKKKKKKJA. ..OOPKLLLLOKJJA. ..PPKLOEEEOLKJA. ..PAKOLEOOLLKJA. ..PPKLOELLOLKJA. ...AKOLEEELLKJA. ....KLOLLLLOKAA. ....KKKKKKKKKA.. .....AAAAAAAA... } # tile 273 (tin) { ................ ................ ................ ................ .....BBBB....... ....BPPPPP.A.... ....BPBBP.AAA... ....OBPP..AAAA.. ....OOOP..AAAA.. ....OOOP..AAA... ....BOOP..AA.... ....BBPP..A..... .....BPP.A...... ......AAA....... ................ ................ } # tile 274 (ruby / gain ability) { ................ ................ ................ .....LJA........ .....KJA........ ....ODDDA....... .....CDA........ ....CDDDA....... ...CNCDDDA.AA... ...CDDDDDAAAA... ...CDDDDDAA..... ....CDDDAA...... .....AAAA....... ................ ................ ................ } # tile 275 (pink / restore ability) { ................ ................ ................ .....LJA........ .....KJA........ ....OIIIA....... .....LIA........ ....LIIIA....... ...LNLIIIA.AA... ...LIIIIIAAAA... ...LIIIIIAA..... ....LIIIAA...... .....AAAA....... ................ ................ ................ } # tile 276 (orange / confusion) { ................ ................ ................ .....LJA........ .....KJA........ ....OCCCA....... .....KCA........ ....KCCCA....... ...KNKCCCA.AA... ...KCCCCCAAAA... ...KCCCCCAA..... ....KCCCAA...... .....AAAA....... ................ ................ ................ } # tile 277 (yellow / blindness) { ................ ................ ................ .....LJA........ .....KJA........ ....OHHHA....... .....OHA........ ....OHHHA....... ...ONOHHHA.AA... ...OHHHHHAAAA... ...OHHHHHAA..... ....OHHHAA...... .....AAAA....... ................ ................ ................ } # tile 278 (emerald / paralysis) { ................ ................ ................ .....LJA........ .....KJA........ ....OFFFA....... .....GFA........ ....GFFFA....... ...GNGFFFA.AA... ...GFFFFFAAAA... ...GFFFFFAA..... ....GFFFAA...... .....AAAA....... ................ ................ ................ } # tile 279 (dark green / speed) { ................ ................ ................ .....LJA........ .....KJA........ ....OFF.A....... .....F.A........ ....F.F.A....... ...FNF.F.A.AA... ...FF.F..AAAA... ...F.F...AA..... ....F.F.AA...... .....AAAA....... ................ ................ ................ } # tile 280 (cyan / levitation) { ................ ................ ................ .....LJA........ .....KJA........ ....BBBEA....... .....BEA........ ....BBBEA....... ...BNBBEEA.AA... ...BBBBEEAAAA... ...BBBBEEAA..... ....BBEEAA...... .....AAAA....... ................ ................ ................ } # tile 281 (sky blue / hallucination) { ................ ................ ................ .....LJA........ .....KJA........ ....NBBBA....... .....NBA........ ....NBBBA....... ...NBBBBBA.AA... ...NBBBBBAAAA... ...NBBBBBAA..... ....NBBBAA...... .....AAAA....... ................ ................ ................ } # tile 282 (brilliant blue / invisibility) { ................ ................ ................ .....LJA........ .....KJA........ ....OEEEA....... .....BEA........ ....BEEEA....... ...BNBEEEA.AA... ...BEEEEEAAAA... ...BEEEEEAA..... ....BEEEAA...... .....AAAA....... ................ ................ ................ } # tile 283 (magenta / see invisible) { ................ ................ ................ .....LJA........ .....KJA........ ....DIIDA....... .....DIA........ ....DIIDA....... ...DLDIIDA.AA... ...DIIIIDAAAA... ...DDIIDDAA..... ....DDDDAA...... .....AAAA....... ................ ................ ................ } # tile 284 (purple-red / healing) { ................ ................ ................ .....LJA........ .....KJA........ ....OEDEA....... .....DEA........ ....DEDEA....... ...DNDEDEA.AA... ...DDEDEEAAAA... ...DEDEDEAA..... ....DEDEAA...... .....AAAA....... ................ ................ ................ } # tile 285 (puce / extra healing) { ................ ................ ................ .....LJA........ .....KJA........ ....OKKJA....... .....IKA........ ....IKDJA....... ...INDKJJA.AA... ...IKKDJJAAAA... ...DKDKJJAA..... ....DKKJAA...... .....AAAA....... ................ ................ ................ } # tile 286 (milky / gain level) { ................ ................ ................ .....LJA........ .....KJA........ ....OOOOA....... .....NOA........ ....NOOOA....... ...NOOOOOA.AA... ...NOOOOOAAAA... ...NOOOOOAA..... ....NOOOAA...... .....AAAA....... ................ ................ ................ } # tile 287 (swirly / enlightenment) { ................ ................ ................ .....LJA........ .....KJA........ ....NOOOA....... .....NOA........ ....NOIIA....... ...NOIIOOA.AA... ...IIOOOIAAAA... ...NOOIIOAA..... ....IIOOAA...... .....AAAA....... ................ ................ ................ } # tile 288 (bubbly / monster detection) { ................ ................ ................ .....LJA........ .....KJA........ ....OFFFA....... .....NFA........ ....FFFNA....... ...NFNFFFA.AA... ...FFFFFNAAAA... ...FNFFFFAA..... ....FFNFAA...... .....AAAA....... ................ ................ ................ } # tile 289 (smoky / object detection) { ................ ................ ................ .....LJA........ .....KJA........ ....OPPPA....... .....OPA........ ....OPPPA....... ...ONPPPPA.AA... ...OPPPPPAAAA... ...OPPPPPAA..... ....OPPPAA...... .....AAAA....... ................ ................ ................ } # tile 290 (cloudy / gain energy) { ................ ................ ................ .....LJA........ .....KJA........ ....OEEEA....... .....BPA........ ....BEEPA....... ...BEPPPEA.AA... ...BEEPEEAAAA... ...BEPPPPAA..... ....BPEEAA...... .....AAAA....... ................ ................ ................ } # tile 291 (effervescent / sleeping) { ................ ................ ................ .....LJA........ .....KJA........ ....OEEOA....... .....NNA........ ....OFNNA....... ...BFNNFOA.AA... ...OFNFFOAAAA... ...BFFFNEAA..... ....BNFFAA...... .....AAAA....... ................ ................ ................ } # tile 292 (black / full healing) { ................ ................ ................ .....LJ......... .....KJ......... ....AAAA........ .....AA......... ....AAAA........ ...ANAAAA.PPP... ...AAAAAAPPPP... ...AAAAAAPP..... ...AAAAAAP...... ....AAAAP....... ................ ................ ................ } # tile 293 (golden / polymorph) { ................ ................ ................ .....LJA........ .....KJA........ ....LHHHA....... .....LHA........ ....LHHCA....... ...LNLHHCA.AA... ...LHHHHCAAAA... ...LHHHCCAA..... ....LCCCAA...... .....AAAA....... ................ ................ ................ } # tile 294 (brown / booze) { ................ ................ ................ .....GFA........ .....FFA........ ....CJJJA....... .....KJA........ ....KJJJA....... ...KCKJJJA.AA... ...KJJJJJAAAA... ...KJJJJJAA..... ....KJJJAA...... .....AAAA....... ................ ................ ................ } # tile 295 (fizzy / sickness) { ................ ................ ................ .....LJA........ .....KJA........ ....OEEOA....... .....OOA........ ....OEOOA....... ...BEOOEOA.AA... ...OEOEEOAAAA... ...BEEEOEAA..... ....BOEEAA...... .....AAAA....... ................ ................ ................ } # tile 296 (dark / fruit juice) { ................ ................ ................ .....LJ......... .....KJ......... ....AAAA........ .....AA......... ....AJJA........ ...ANJJJA.PPP... ...AJJAAAPPPP... ...AJAAAAPP..... ...AAAAAAP...... ....AAAAP....... ................ ................ ................ } # tile 297 (white / acid) { ................ ................ ................ .....LJA........ .....KJA........ ....NNNNA....... .....NNA........ ....NNNNA....... ...NPNNNNA.AA... ...NNNNNNAAAA... ...NNNNNNAA..... ....NNNNAA...... .....AAAA....... ................ ................ ................ } # tile 298 (murky / oil) { ................ ................ ................ .....LJ......... .....KJ......... ....AAAA........ .....AA......... ....AFJA........ ...ANJFJA.PPP... ...AJFAFAPPPP... ...AFAFAAPP..... ...AAFAFAP...... ....AAAAP....... ................ ................ ................ } # tile 299 (clear / water) { ................ ................ ................ .....LJA........ .....KJA........ ....BPPPA....... .....BPA........ ....BPPPA....... ...BPPPPPA.AA... ...BEEEEEAAAA... ...BEEEEEAA..... ....BEEEAA...... .....AAAA....... ................ ................ ................ } # tile 300 (ZELGO MER / enchant armor) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 301 (JUYED AWK YACC / destroy armor) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 302 (NR 9 / confuse monster) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 303 (XIXAXA XOXAXA XUXAXA / scare monster) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 304 (PRATYAVAYAH / remove curse) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 305 (DAIYEN FOOELS / enchant weapon) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 306 (LEP GEX VEN ZEA / create monster) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 307 (PRIRUTSENIE / taming) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 308 (ELBIB YLOH / genocide) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 309 (VERR YED HORRE / light) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 310 (VENZAR BORGAVVE / teleportation) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 311 (THARR / gold detection) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 312 (YUM YUM / food detection) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 313 (KERNOD WEL / identify) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 314 (ELAM EBOW / magic mapping) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 315 (DUAM XNAHT / amnesia) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 316 (ANDOVA BEGARIN / fire) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 317 (KIRJE / earth) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 318 (VE FORBRYDERNE / punishment) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 319 (HACKEM MUCHE / charging) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 320 (VELOX NEB / stinking cloud) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 321 (FOOBIE BLETCH) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 322 (TEMOV) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 323 (GARVEN DEH) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 324 (READ ME) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 325 (ETAOIN SHRDLU) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 326 (LOREM IPSUM) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 327 (FNORD) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 328 (KO BATE) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 329 (ABRA KA DABRA) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 330 (ASHPD SODALG) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 331 (ZLORFIK) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 332 (GNIK SISI VLE) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 333 (HAPAX LEGOMENON) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 334 (EIRIS SAZUN IDISI) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 335 (PHOL ENDE WODAN) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 336 (GHOTI) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 337 (MAPIRO MAHAMA DIROMAT) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 338 (VAS CORP BET MANI) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 339 (XOR OTA) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 340 (STRC PRST SKRZ KRK) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....NJNJAO.A... .....LLLLLLPA... .....LLJLJLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 341 (stamped / mail) { ................ ................ ................ ................ ................ ................ .OOOOOOOOOEEO... .OOOOOOOOOEEO... .OOOOOOOOOOOOA.. .OOOJLJJLJOOOA.. .OOOOOOOOOOOOA.. .OOOJJLJOOOOOA.. .OOOOOOOOOOOOA.. ...AAAAAAAAAAA.. ................ ................ } # tile 342 (unlabeled / blank paper) { ................ ................ ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAPA... .....LLLLLLPA... .....LLLLLLPA... .....LLLLLLPA... .....LLLLLLPA... ....POOOOOPKA... ...DOOOOOOKDJ... ....POOOOOPJAA.. .....AAAAAAAA... ................ ................ } # tile 343 (parchment / dig) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCOAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 344 (vellum / magic missile) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCOAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 345 (ragged / fireball) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKJJA.. .KKKKKKKKKCJAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JOOOOOJA.... ......OOJJAA.... ................ } # tile 346 (dog eared / cone of cold) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKO..... ...KKHHKKKJOC... ..JKKKHHKKJOOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCOAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 347 (mottled / sleep) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCLAA.. .JOOKKKKKKOJA... ..JJLLOKKCOAA... ....JJJOLLJA.... .......JJJAA.... ................ } # tile 348 (stained / finger of death) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHCJJJJ... ...KKHHKKCJJC... ..JJJJCHKJJJLA.. ..KJCJJHHKKCLAA. .JKJJCCCKKKOJA.. .KKKJJJJKKCOAA.. .JOOKJJKKKOJA... ..JJOLOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 349 (cloth / light) { ................ ................ ................ ....EPPP........ ....PPPEPP...... ...EPPHHHPEPP... ...PPHHPPHPPE... ..EPPPHHPPPPOA.. ..PPHPPHHEPEOAA. .EPPPHHHPPPOPA.. .PPPEPPPPPEOAA.. .POOPPPEPPOPA... ..PPOOOPPEOAA... ....PPPOOOPA.... .......PPPAA.... ................ } # tile 350 (leathery / detect monsters) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCOAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 351 (white / healing) { ................ ................ ................ ....PNNP........ ....NNNNNP...... ...PNNAAANNNP... ...NNAANNANNN... ..PNNNAANNNNOA.. ..NNANNAANNNOAA. .PNNNAAANNNONA.. .NNNNNNNNNNOAA.. .NOONNNNNNONA... ..PNOOONNNOAA... ....PNNOOONA.... .......PNNAA.... ................ } # tile 352 (pink / knock) { ................ ................ ................ ....DIID........ ....IIIIID...... ...DIIHHHIIID... ...IIHHIIHIIC... ..DIIIHHIIIIOA.. ..IIHIIHHIICOAA. .DIIIHHHIIIOIA.. .IIIIIIIIICOAA.. .IOOIIIIIIOIA... ..IIOOOIICOAA... ....IIIOOOIA.... .......IIIAA.... ................ } # tile 353 (red / force bolt) { ................ ................ ................ ....KDDK........ ....DDDDDK...... ...KDDHHHDDDK... ...DDHHDDHDDC... ..KDDDHHDDDDOA.. ..DDHDDHHDDCOAA. .KDDDHHHDDDODA.. .DDDDDDDDDCOAA.. .DOODDDDDDODA... ..DDOOODDCOAA... ....DDDOOODA.... .......DDDAA.... ................ } # tile 354 (orange / confuse monster) { ................ ................ ................ ....KCCK........ ....CCCCCK...... ...KCCAAACCCK... ...CCAACCACCL... ..KCCCAACCCCOA.. ..CCACCAACCLOAA. .KCCCAAACCCOCA.. .CCCCCCCCCLOAA.. .COOCCCCCCOCA... ..CCOOOCCLOAA... ....CCCOOOCA.... .......CCCAA.... ................ } # tile 355 (yellow / cure blindness) { ................ ................ ................ ....OHHO........ ....HHHHHO...... ...OHHAAAHHHO... ...HHAAHHAHHL... ..OHHHAAHHHHOA.. ..HHAHHAAHHLOAA. .OHHHAAAHHHOHA.. .HHHHHHHHHLOAA.. .HOOHHHHHHOHA... ..HHOOOHHLOAA... ....HHHOOOHA.... .......HHHAA.... ................ } # tile 356 (velvet / drain life) { ................ ................ ................ ....IIII........ ....IEEEEE...... ...IEENNNEEEE... ...IENNEENEEB... ..IEEENNEEEIOA.. ..EENEENNEIBOAA. .IEEENNNEEIOEA.. .EEEEEEEEIBOAA.. .EOOEEEEIIOEA... ..EEOOOIIBOAA... ....EEEOOOEA.... .......EEEAA.... ................ } # tile 357 (light green / slow monster) { ................ ................ ................ ....FGGF........ ....GGGGGF...... ...FGG...GGGF... ...GG..GG.GGH... ..FGGG..GGGGOA.. ..GG.GG..GGHOAA. .FGGG...GGGOGA.. .GGGGGGGGGHOAA.. .GOOGGGGGGOGA... ..GGOOOGGHOAA... ....GGGOOOGA.... .......GGGAA.... ................ } # tile 358 (dark green / wizard lock) { ................ ................ ................ ....FFFF........ ....FFFFFF...... ...FFFHHHFFFF... ...FFHHFFHFFG... ..FFFFHHFFFFOA.. ..FFHFFHHFFGOAA. .FFFFHHHFFFOFA.. .FFFFFFFFFGOAA.. .FOOFFFFFFOFA... ..FFOOOFFGOAA... ....FFFOOOFA.... .......FFFAA.... ................ } # tile 359 (turquoise / create monster) { ................ ................ ................ ....FBBF........ ....BBBBBF...... ...FBBGGGBBBF... ...BBGGBBGBBB... ..FBBBGGBBBBOA.. ..BBGBBGGBBBOAA. .FBBBGGGBBBOBA.. .BBBBBBBBBBOAA.. .FOOBBBBBBOBA... ..BBOOOBBBOAA... ....FBBOOOBA.... .......FBBAA.... ................ } # tile 360 (cyan / detect food) { ................ ................ ................ ....BBBB........ ....BBBBBB...... ...BBBGGGBBBB... ...BBGGBBGBBB... ..BBBBGGBBBBOA.. ..BBGBBGGBBBOAA. .BBBBGGGBBBOBA.. .BBBBBBBBBBOAA.. .BOOBBBBBBOBA... ..BBOOOBBBOAA... ....BBBOOOBA.... .......BBBAA.... ................ } # tile 361 (light blue / cause fear) { ................ ................ ................ ....EBBE........ ....BBBBBE...... ...EBBAAABBBE... ...BBAABBABBB... ..EBBBAABBBBOA.. ..BBABBAABBBOAA. .EBBBAAABBBOBA.. .BBBBBBBBBBOAA.. .BOOBBBBBBOBA... ..BBOOOBBBOAA... ....BBBOOOBA.... .......BBBAA.... ................ } # tile 362 (dark blue / clairvoyance) { ................ ................ ................ ....EEEE........ ....EEEEEE...... ...EEEHHHEEEE... ...EEHHEEHEEB... ..EEEEHHEEEEOA.. ..EEHEEHHEEBOAA. .EEEEHHHEEEOEA.. .EEEEEEEEEBOAA.. .EOOEEEEEEOEA... ..EEOOOEEBOAA... ....EEEOOOEA.... .......EEEAA.... ................ } # tile 363 (indigo / cure sickness) { ................ ................ ................ ....EEEE........ ....EEEEEE...... ...EEEIIIEEEE... ...EEIIEEIEEB... ..EEEEIIEEEEOA.. ..EEIEEIIEEBOAA. .EEEEIIIEEEOEA.. .EEEEEEEEEBOAA.. .EOOEEEEEEOEA... ..EEOOOEEBOAA... ....EEEOOOEA.... .......EEEAA.... ................ } # tile 364 (magenta / charm monster) { ................ ................ ................ ....KIIK........ ....IIIIIK...... ...KIIEEEIIIK... ...IIEEIIEIIC... ..KIIIEEIIIIOA.. ..IIEIIEEIICOAA. .KIIIEEEIIIOIA.. .IIIIIIIIICOAA.. .IOOIIIIIIOIA... ..IIOOOIICOAA... ....IIIOOOIA.... .......IIIAA.... ................ } # tile 365 (purple / haste self) { ................ ................ ................ ....EDED........ ....DEDEDE...... ...DEDHHHDED.... ...EDHHEDHDEC... ..EDEDHHEDEDOA.. ..DEHEDHHEDCOAA. .DEDEHHHEDEOIA.. .EDEDEDEDECOAA.. .DOOEDEDEDOIA... ..IIOOOEDCOAA... ....IIIOOOIA.... .......IIIAA.... ................ } # tile 366 (violet / detect unseen) { ................ ................ ................ ....JBIJ........ ....BIBIBJ...... ...JIBAAABIBJ... ...IBAAIBABIC... ..JBIBAAIBIBOA.. ..BIAIBAAIBCOAA. .JIBIAAAIBIOIA.. .IBIBIBIBICOAA.. .IOOIBIBIBOIA... ..IIOOOIBCOAA... ....IIIOOOIA.... .......IIIAA.... ................ } # tile 367 (tan / levitation) { ................ ................ ................ ....JCKJ........ ....CKCKCJ...... ...JKCHHHCKCJ... ...KCHHKCHCKC... ..JCKCHHKCKCOA.. ..CKHKCHHKCCOAA. .JKCKHHHKCKOKA.. .KCKCKCKCKCOAA.. .JOOKCKCKCOKA... ..KKOOOKCCOAA... ....KKKOOOKA.... .......KKKAA.... ................ } # tile 368 (plaid / extra healing) { ................ ................ ................ ....JEEJ........ ....DEEDDJ...... ...JDFHHHFFDJ... ...DDHHDDHFDC... ..JDDEHHDEEDOA.. ..EDHEEHHEECOAA. .JFDDHHHDFFOEA.. .FFDDFFDDFCOAA.. .JOODEEDDEODA... ..EDOOODDCOAA... ....EFDOOOFA.... .......EFDAA.... ................ } # tile 369 (light brown / restore ability) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCOAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 370 (dark brown / invisibility) { ................ ................ ................ ....JJJJ........ ....JJJJJJ...... ...JJJHHHJJJJ... ...JJHHJJHJJK... ..JJJJHHJJJJOA.. ..JJHJJHHJJKOAA. .JJJJHHHJJJOJA.. .JJJJJJJJJKOAA.. .JOOJJJJJJOJA... ..JJOOOJJKOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 371 (gray / detect treasure) { ................ ................ ................ ....PPPP........ ....PPPPPP...... ...PPPAAAPPPP... ...PPAAPPAPPB... ..PPPPAAPPPPOA.. ..PPAPPAAPPBOAA. .PPPPAAAPPPOPA.. .PPPPPPPPPBOAA.. .POOPPPPPPOPA... ..PPOOOPPBOAA... ....PPPOOOPA.... .......PPPAA.... ................ } # tile 372 (wrinkled / remove curse) { ................ ................ ................ ....JKKJ........ ....KKKKK....... ....KKAAAKKKJ... ...KKAAKKAKKK... ..JKKKAAKKKKOA.. ..KKAKKAAKKKOAA. .JKKKAAAKKKOKA.. .KKKKKKKKKLOAA.. .KOOLKKKKKOKA..K ..JKOOKKKKOAA... ....JKLOOOKA.... ......JJKKAA.... ................ } # tile 373 (dusty / magic mapping) { ................ ................ ..K.......KA.... ..KAJKKJ........ ....KKKKKJ..K... .KAJKKHHHKKKJ.KA ...KKHHKKHKKC... ..JKAKHHKKAKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOJA.. .KKKKKKKKKCOAA.. AJOOKKKKAKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .KAKA..JJJAA.... ................ } # tile 374 (bronze / identify) { ................ ................ ................ ....KCCK........ ....CCCCCK...... ...KCCHHHCCCK... ...CCHHCCHCCC... ..KCCCHHCCCCOA.. ..CCHCCHHCCCOAA. .KCCCHHHCCCOCA.. .CCCCCCCCCCOAA.. .KOOCCCCCCOCA... ..CCOOOCCCOAA... ....CCCOOOCA.... .......CCCAA.... ................ } # tile 375 (copper / turn undead) { ................ ................ ................ ....JKKJ........ ....KCKCKJ...... ...JCKHHHKCKJ... ...CKHHCKHKCC... ..JKCKHHCKCKOA.. ..KCHCKHHCKCOAA. .JCKCHHHCKCOJA.. .CKCKCKCKCCOAA.. .JOOCKCKCKOJA... ..CJOOOCKCOAA... ....JCJOOOJA.... .......JCJAA.... ................ } # tile 376 (silver / polymorph) { ................ ................ ................ ....PPPP........ ....PPPPPP...... ...PPPNNNPPPP... ...PPNNPPNPPB... ..PPPPNNPPPPOA.. ..PPNPPNNPPBOAA. .PPPPNNNPPPOPA.. .PPPPPPPPPBOAA.. .POOPPPPPPOPA... ..PPOOOPPBOAA... ....PPPOOOPA.... .......PPPAA.... ................ } # tile 377 (gold / teleport away) { ................ ................ ................ ....LHHL........ ....HHHHHL...... ...LHHCCCHHHL... ...HHCCHHCHHN... ..LHHHCCHHHHOA.. ..HHCHHCCHHNOAA. .LHHHCCCHHHOHA.. .HHHHHHHHHNOAA.. .LOOHHHHHHOHA... ..HHOOOHHNOAA... ....HHHOOOHA.... .......HHHAA.... ................ } # tile 378 (glittering / create familiar) { ................ ................ ......N......... ...NPPPP..N..... ....PPPPPP...N.. ...PPPHHHPPPP... ..NPPHHPPHPPB... ..PPPPHHPPPPON.. .NPPHPPHHPPBOAA. .PPPPHHHPPPOPA.. NPPPPPPPPPBONA.. .POONPPPPPOPA... ..PPOONPPBOAA... ...N.PPOOOPA.... .......PPPAN.... .......N........ } # tile 379 (shining / cancellation) { ....N........... .......N........ ..N............. ....PNPP........ ....PNNNPP...... ...PNNAAAPPPP... ...PNAAPPAPPB... ..PNNPAAPPPPOA.. ..PNAPPAAPPBOAA. .PNPPAAAPPPOPA.. .PPPPPPPPPBOAA.. .POOPPPPPPOPA... ..PPOOOPPBOAA... ....PPPOOOPA.... .......PPPAA.... ................ } # tile 380 (dull / protection) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKCCCKKKJ... ...KKCCKKCKKJ... ..JKKKCCKKKKPA.. ..KKCKKCCKKJPAA. .JKKKCCCKKKPJA.. .KKKKKKKKKJPAA.. .JPPKKKKKKPJA... ..JJPPPKKJPAA... ....JJJPPPJA.... .......JJJAA.... ................ } # tile 381 (thin / jumping) { ................ ................ ................ ................ .....JKJ........ ....JKKKKKJ..... ....KKHHHKKKK... ...JKHHKKHKKOA.. ...KKKHHKKKKOAA. ..JKHKKHHKKCJA.. ..KKKHHHKKKOAA.. .JOCKKKKKKCJA... ..JJOOCKKKOAA... ....JJJOCOJA.... .......JJJAA.... ................ } # tile 382 (thick / stone to flesh) { ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKHHHKKKJ... ...KKHHKKHKKC... ..JKKKHHKKKKOA.. ..KKHKKHHKKCOAA. .JKKKHHHKKKOLA.. .KKKKKKKKKCOJA.. .JOOKKKKKKOLA... .JLLOOOKKCOJA... ..JJLLLOOOLAA... ....JJJLLLJA.... .......JJJAA.... ................ } # tile 383 (plain / blank paper) { ................ ................ ................ ....JKKJ........ ....KKKKKJ...... ...JKKKKKKKKJ... ...KKKKKKKKKC... ..JKKKKKKKKKOA.. ..KKKKKKKKKCOAA. .JKKKKKKKKKOJA.. .KKKKKKKKKCOAA.. .JOOKKKKKKOJA... ..JJOOOKKCOAA... ....JJJOOOJA.... .......JJJAA.... ................ } # tile 384 (paperback / novel) { ................ ................ ................ ....EEEE........ ....EEEEEE...... ...EEEEEEEEEE... ...EEEEEEEEEB... ..EEEEEEEEEEOA.. ..EEEEEEEEEBOAA. .EEEEEEEEEEOEA.. .EEEEEEEEEBOAA.. .EOOEEEEEEOEA... ..EEOOOEEBOAA... ....EEEOOOEA.... .......EEEAA.... ................ } # tile 385 (papyrus / Book of the Dead) { ................ ................ ................ ....AAAA........ ....AAAAAA...... ...AAAOOOAAAA... ...AAOAOOOAAA... ..AAAAOOAOAAO... ..AAAOAOOAAAO... .AAAAOOOAAAOA... .AAAAAAAAAAO.... .AOOAAAAAAOA.... ..AAOOOAAAO..... ....AAAOOOA..... .......AAA...... ................ } # tile 386 (glass / light) { ................ ................ ............N... ...........NB... ..........NBAA.. .........NBAA... ........NBAA.... .......NBAA..... ......NBAA...... .....NBAA....... ....NBAA........ ...NBAA......... ...BAF.......... ................ ................ ................ } # tile 387 (balsa / secret door detection) { ................ ................ ................ ...........OK... ..........OKAA.. .........LKAA... ........LKAA.... .......LKAA..... ......LKAA...... .....LKAA....... ....OKAA........ ...OKAA......... ....AA.......... ................ ................ ................ } # tile 388 (crystal / enlightenment) { ................ ................ ................ ...........N.... ..........NB.... .........NBA.... ........NBA..... .......NBA...... ......NBA....... .....NBA........ ....NBA......... ....BA.......... ................ ................ ................ ................ } # tile 389 (maple / create monster) { ................ ................ ................ ...........NO... ..........KJAA.. .........KJAA... ........KJAA.... .......KJAA..... ......KJAA...... .....KJAA....... ....KJAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 390 (pine / wishing) { ................ ................ ................ ...........NO... ..........LLAA.. .........LLAA... ........LLAA.... .......LLAA..... ......LLAA...... .....LLAA....... ....LLAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 391 (oak / nothing) { ................ ................ ...........N.... ..........NNO... .........JKOAA.. ........JJJAA... .......JJKAA.... ......JKJAA..... .....JJJAA...... ....JJKAA....... ...OKJAA........ ..NNOAA......... ...NAA.......... ................ ................ ................ } # tile 392 (ebony / striking) { ................ ................ ................ ...........NO... ..........AJAA.. .........AJAA... ........AJAA.... .......AJAA..... ......AJAA...... .....AJAA....... ....AJAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 393 (marble / make invisible) { ................ ................ ................ ...........NO... ..........IOAA.. .........NIAA... ........NNAA.... .......IIAA..... ......NNAA...... .....INAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 394 (tin / slow monster) { ................ ................ ................ ...........NO... ..........PPAA.. .........PPAA... ........PPAA.... .......PPAA..... ......PPAA...... .....PPAA....... ....PPAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 395 (brass / speed monster) { ................ ................ ................ ...........NO... ..........HCAA.. .........HCAA... ........HCAA.... .......HCAA..... ......HCAA...... .....HCAA....... ....HCAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 396 (copper / undead turning) { ................ ................ ................ ...........NO... ..........CCAA.. .........CCAA... ........CCAA.... .......CCAA..... ......CCAA...... .....CCAA....... ....CCAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 397 (silver / polymorph) { ................ ................ ................ ...........NO... ..........NPAA.. .........NPAA... ........NPAA.... .......NPAA..... ......NPAA...... .....NPAA....... ....NPAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 398 (platinum / cancellation) { ................ ................ ................ ...........NO... ..........NOAA.. .........NBAA... ........NBAA.... .......NBAA..... ......NBAA...... .....NBAA....... ....NOAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 399 (iridium / teleportation) { ................ ................ ................ ...........NO... ..........NOAA.. .........PIAA... ........PIAA.... .......PIAA..... ......PIAA...... .....PIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 400 (zinc / opening) { ................ ................ ................ ...........NO... ..........LPAA.. .........LPAA... ........LPAA.... .......LPAA..... ......LPAA...... .....LPAA....... ....LPAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 401 (aluminum / locking) { ................ ................ ................ ...........NO... ..........PPAA.. .........BPAA... ........PPAA.... .......BPAA..... ......PPAA...... .....BPAA....... ....PPAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 402 (uranium / probing) { ................ ................ ................ ..........PNO... .........PPPAA.. ........HHPAA... .......HAHAA.... ......PAHAA..... .....PPPAA...... ....PPPAA....... ...PPPAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 403 (iron / digging) { ................ ................ ................ ...........KJ... ..........KPAA.. .........PPAA... ........PPAA.... .......PPAA..... ......PPAA...... .....PPAA....... ....KPAA........ ...KJAA......... ....AA.......... ................ ................ ................ } # tile 404 (steel / magic missile) { ................ ................ ................ ...........KP... ..........OPAA.. .........OPAA... ........OPAA.... .......OPAA..... ......PPAA...... .....PPAA....... ....KPAA........ ...KKAA......... ....AA.......... ................ ................ ................ } # tile 405 (hexagonal / fire) { ................ ................ ................ ..........PN.... .........PN.AA.. ........PN.AA... .......PN.AA.... ......PN.AA..... .....PN.AA...... ....PN.AA....... ...PN.AA........ ...N.AA......... ....AA.......... ................ ................ ................ } # tile 406 (short / cold) { ................ ................ ................ ................ ................ .........NO..... ........NO...... .......DIAA..... ......DIAA...... .....DIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 407 (runed / sleep) { ................ ................ ................ ...........NO... ..........NOAA.. .........DIAA... ........AIAA.... .......DIAA..... ......AIAA...... .....DIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 408 (long / death) { ................ .............NO. ............NN.. ...........DI... ..........DIAA.. .........DIAA... ........DIAA.... .......DIAA..... ......DIAA...... .....DIAA....... ....DIAA........ ...NIAA......... ..NOAA.......... ................ ................ ................ } # tile 409 (curved / lightning) { ................ .......NO....... .......NOA...... .......CIA...... .......DIA...... .......DIA...... ......JIKA...... ......KIJA...... ......DIAA...... .....DIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 410 (forked) { ................ ................ .........N...... ........N..NO... .......D..NOAA.. .......D.DIAA.O. .......DDIAA.OA. .......DIIIIIA.. ......DIAAAAA... .....DIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 411 (spiked) { ................ ................ ................ ..........NNO... ..........DIO... .........DIAP... ........DIAA.... .......DIAA..... ......DIAA...... .....DIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 412 (jeweled) { ................ ................ ..........NNB... ..........NBB... ..........BBBA.. .........DIAA... ........DIAA.... .......DIAA..... ......DIAA...... .....DIAA....... ....NIAA........ ...NOAA......... ....AA.......... ................ ................ ................ } # tile 413 (gold piece) { ................ ................ ................ ................ .JKKKJ.JJ....... JKCKKKJKKKJ..... KCKKKJKAAAKA.... KKKKKJAHALKAA... KKKKJKHLLHAHA... .KKJJKLHCALA.... .AAAJKLALHCAHA.. ...AAKAHAH...... ....AAAALAHA.HA. ......HA........ .........HA..... ...........HA... } # tile 414 (white / dilithium crystal) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....ONOOO...... ....ONOOOBO..... ...NNNONONBB.... ....ONOOOBOAA... .....ONOBOAAAA.. ......OOOAAA.... .......OAA...... ................ ................ } # tile 415 (white / diamond) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....ONOOO...... ....ONOOOBO..... ...NNNONONBB.... ....ONOOOBOAA... .....ONOBOAAAA.. ......OOOAAA.... .......OAA...... ................ ................ } # tile 416 (red / ruby) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....DNDDD...... ....DNDDDKD..... ...DNDDKDKKK.... ....DCDDDKDAA... .....DCDKDAAAA.. ......DDDAAA.... .......DAA...... ................ ................ } # tile 417 (orange / jacinth) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....CNCCC...... ....CNCCCKC..... ...CNCCKCKKK.... ....CLCCCKCAA... .....CLCKCAAAA.. ......CCCAAA.... .......CAA...... ................ ................ } # tile 418 (blue / sapphire) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....BNBBB...... ....BNBBBEB..... ...NNNBEBEEE.... ....BNBBBEBAA... .....BNBEBAAAA.. ......BBBAAA.... .......BAA...... ................ ................ } # tile 419 (black / black opal) { ................ ................ ................ ................ ................ ................ ................ .....AAAAA...... ....ANAAAAA..... ...ANAAAAAAA.... ...AAAAAAAAAP... ....AAAAAAAPPP.. ......AAAPPP.... ................ ................ ................ } # tile 420 (green / emerald) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....FGFFF...... ....FGFFFFF..... ...GGFGFGFFF.... ....FGFFFFFAA... .....FGFFFAAAA.. ......FGFAAA.... .......FAA...... ................ ................ } # tile 421 (green / turquoise) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....FGFFF...... ....FGFFFFF..... ...GGFGFGFFF.... ....FGFFFFFAA... .....FGFFFAAAA.. ......FGFAAA.... .......FAA...... ................ ................ } # tile 422 (yellow / citrine) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....HNHHH...... ....HNHHHCH..... ...HNHHCHCCC.... ....HLHHHCHAA... .....HLHCHAAAA.. ......HHHAAA.... .......HAA...... ................ ................ } # tile 423 (green / aquamarine) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....FGFFF...... ....FGFFFFF..... ...GGFGFGFFF.... ....FGFFFFFAA... .....FGFFFAAAA.. ......FGFAAA.... .......FAA...... ................ ................ } # tile 424 (yellowish brown / amber) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....KCKKK...... ....KCKKKJK..... ...CCCKJKJJJ.... ....KCKKKJKAA... .....KCKJKAAAA.. ......KKKAAA.... .......KAA...... ................ ................ } # tile 425 (yellowish brown / topaz) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....KCKKK...... ....KCKKKJK..... ...CCCKJKJJJ.... ....KCKKKJKAA... .....KCKJKAAAA.. ......KKKAAA.... .......KAA...... ................ ................ } # tile 426 (black / jet) { ................ ................ ................ ................ ................ ................ ................ .....AAAAA...... ....ANAAAAA..... ...ANAAAAAAA.... ...AAAAAAAAAP... ....AAAAAAAPPP.. ......AAAPPP.... ................ ................ ................ } # tile 427 (white / opal) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....ONOOO...... ....ONOOOBO..... ...NNNONONBB.... ....ONOOOBOAA... .....ONOBOAAAA.. ......OOOAAA.... .......OAA...... ................ ................ } # tile 428 (yellow / chrysoberyl) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....HNHHH...... ....HNHHHCH..... ...HNHHCHCCC.... ....HLHHHCHAA... .....HLHCHAAAA.. ......HHHAAA.... .......HAA...... ................ ................ } # tile 429 (red / garnet) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....DNDDD...... ....DNDDDKD..... ...DNDDKDKKK.... ....DCDDDKDAA... .....DCDKDAAAA.. ......DDDAAA.... .......DAA...... ................ ................ } # tile 430 (violet / amethyst) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....INIII...... ....INIIIEI..... ...NNNININEI.... ....INIIIEIAA... .....INIEIAAAA.. ......IIIAAA.... .......IAA...... ................ ................ } # tile 431 (red / jasper) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....DNDDD...... ....DNDDDKD..... ...DNDDKDKKK.... ....DCDDDKDAA... .....DCDKDAAAA.. ......DDDAAA.... .......DAA...... ................ ................ } # tile 432 (violet / fluorite) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....INIII...... ....INIIIEI..... ...NNNININEI.... ....INIIIEIAA... .....INIEIAAAA.. ......IIIAAA.... .......IAA...... ................ ................ } # tile 433 (black / obsidian) { ................ ................ ................ ................ ................ ................ ................ .....AAAAA...... ....ANAAAAA..... ...ANAAAAAAA.... ...AAAAAAAAAP... ....AAAAAAAPPP.. ......AAAPPP.... ................ ................ ................ } # tile 434 (orange / agate) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....CNCCC...... ....CNCCCKC..... ...CNCCKCKKK.... ....CLCCCKCAA... .....CLCKCAAAA.. ......CCCAAA.... .......CAA...... ................ ................ } # tile 435 (green / jade) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....FGFFF...... ....FGFFFFF..... ...GGFGFGFFF.... ....FGFFFFFAA... .....FGFFFAAAA.. ......FGFAAA.... .......FAA...... ................ ................ } # tile 436 (white / worthless piece of white glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....ONOOO...... ....ONOOOBO..... ...NNNONONBB.... ....ONOOOBOAA... .....ONOBOAAAA.. ......OOOAAA.... .......OAA...... ................ ................ } # tile 437 (blue / worthless piece of blue glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....BNBBB...... ....BNBBBEB..... ...NNNBEBEEE.... ....BNBBBEBAA... .....BNBEBAAAA.. ......BBBAAA.... .......BAA...... ................ ................ } # tile 438 (red / worthless piece of red glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....DNDDD...... ....DNDDDKD..... ...DNDDKDKKK.... ....DCDDDKDAA... .....DCDKDAAAA.. ......DDDAAA.... .......DAA...... ................ ................ } # tile 439 (yellowish brown / worthless piece of yellowish brown glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....KCKKK...... ....KCKKKJK..... ...CCCKJKJJJ.... ....KCKKKJKAA... .....KCKJKAAAA.. ......KKKAAA.... .......KAA...... ................ ................ } # tile 440 (orange / worthless piece of orange glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....CNCCC...... ....CNCCCKC..... ...CNCCKCKKK.... ....CLCCCKCAA... .....CLCKCAAAA.. ......CCCAAA.... .......CAA...... ................ ................ } # tile 441 (yellow / worthless piece of yellow glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....HNHHH...... ....HNHHHCH..... ...HNHHCHCCC.... ....HLHHHCHAA... .....HLHCHAAAA.. ......HHHAAA.... .......HAA...... ................ ................ } # tile 442 (black / worthless piece of black glass) { ................ ................ ................ ................ ................ ................ ................ .....AAAAA...... ....ANAAAAA..... ...ANAAAAAAA.... ...AAAAAAAAAP... ....AAAAAAAPPP.. ......AAAPPP.... ................ ................ ................ } # tile 443 (green / worthless piece of green glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....FGFFF...... ....FGFFFFF..... ...GGFGFGFFF.... ....FGFFFFFAA... .....FGFFFAAAA.. ......FGFAAA.... .......FAA...... ................ ................ } # tile 444 (violet / worthless piece of violet glass) { ................ ................ ................ ................ .......P........ ..P....P....P... ...P.......P.... .....INIII...... ....INIIIEI..... ...NNNININEI.... ....INIIIEIAA... .....INIEIAAAA.. ......IIIAAA.... .......IAA...... ................ ................ } # tile 445 (gray / luckstone) { ................ ................ ................ ................ ................ ................ ................ .....PPPPP...... ....PNPPPPP..... ...PNPPPPPPPA... ..PPPPPPPPPPPAA. ..PPPPPPPPPPPAAA ...PPPPPPPPPAAA. ................ ................ ................ } # tile 446 (gray / loadstone) { ................ ................ ................ ................ ................ ................ ................ .....PPPPP...... ....PNPPPPP..... ...PNPPPPPPPA... ..PPPPPPPPPPPAA. ..PPPPPPPPPPPAAA ...PPPPPPPPPAAA. ................ ................ ................ } # tile 447 (gray / touchstone) { ................ ................ ................ ................ ................ ................ ................ .....PPPPP...... ....PNPPPPP..... ...PNPPPPPPPA... ..PPPPPPPPPPPAA. ..PPPPPPPPPPPAAA ...PPPPPPPPPAAA. ................ ................ ................ } # tile 448 (gray / flint) { ................ ................ ................ ................ ................ ................ ................ .....PPPPP...... ....PNPPPPP..... ...PNPPPPPPPA... ..PPPPPPPPPPPAA. ..PPPPPPPPPPPAAA ...PPPPPPPPPAAA. ................ ................ ................ } # tile 449 (rock) { ................ ................ ................ ................ ................ ................ ................ ......KKK....... .....KLCKK...... .....KCCKJA..... .....KKKKJA..... ......KJJAA..... .......AAA...... ................ ................ ................ } # tile 450 (boulder) { ................ ................ ......KKKJ...... ....KKKKKKJJ.... ...KCCKKKKKJJ... ...KCKKKCKKKJA.. ..KKKKKKKJKKJJA. ..KKKKKKKKKKJJAA ..KJKKKCKKKKJJAA ..KKKKKKJKKKJJAA ...KKKKKKKKKJAAA ...JJKKKKKJJJAA. ....JJJJJJJJAA.. ......JJJJAAA... ................ ................ } # tile 451 (statue) { ................ ........JJ...... .......KCJJ..... .......KKJJ..... ....CK.CKJ...... ....JJCKKJ.CJ... .....JCKJJJJJ... .....JCKJJJ.AA.. ......CKJ...AAA. ......CKJAAAAAAA ....KCKKJAAAAAA. ...JCCKKJAJJAA.. ...JKKKKJJJJJA.. ....JJKKKJJJAA.. .....JJJJJJAA... ................ } # tile 452 (heavy iron ball) { ................ ................ ................ ................ ................ ................ ................ ......PPP....... .....POBPP...... .....PBBP.A..... .....PPPP.A..... ......P..AA..... .......AAA...... ................ ................ ................ } # tile 453 (iron chain) { ................ ................ ................ ................ ................ ................ .PP.PP.PP....... P.AP.AP.APP..... .PPAPPAPPPAP.... ..AA.AA.APAPA... ..........PA.... .........PAP.... .........PAPP.P. ..........P.APAP ...........PP.PA ............AA.. } # tile 454 (splash of venom / blinding venom) { ................ ................ ................ ................ ................ ................ ................ .......HHHH..... .....HHAAAAHH... ....HAAAAAAAH... ....HAAAAAAAH... ....HAAAAHHH.... .....HHHH....... ................ ................ ................ } # tile 455 (splash of venom / acid venom) { ................ ................ ................ ................ ................ ................ ................ .......HHHH..... .....HHGGGGHH... ....HGGGGGGGH... ....HGGGGGGGH... ....HGGGGHHH.... .....HHHH....... ................ ................ ................ } nethack-3.6.0/win/share/other.txt0000664000076400007660000023034712541713002015722 0ustar paxedpaxed. = (71, 108, 108) A = (0, 0, 0) B = (0, 182, 255) C = (255, 108, 0) D = (255, 0, 0) E = (0, 0, 255) F = (0, 145, 0) G = (108, 255, 0) H = (255, 255, 0) I = (255, 0, 255) J = (145, 71, 0) K = (204, 79, 0) L = (255, 182, 145) M = (237, 237, 237) N = (255, 255, 255) O = (215, 215, 215) P = (108, 145, 182) Q = (18, 18, 18) R = (54, 54, 54) S = (73, 73, 73) T = (82, 82, 82) U = (205,205,205) V = (104, 104, 104) W = (131, 131, 131) X = (140, 140, 140) Y = (149, 149, 149) Z = (195, 195, 195) 0 = (100, 100, 100) 1 = (72, 108, 108) # tile 0 (dark part of a room) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 1 (wall) { ANNOA1PPPPP1NNOA AOOOA1P1PP11OOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA AOOOA11PPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PP1P1OP1A ANNOA1PPPPP1NNOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA AOOOA11P1P11OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 2 (wall) { AAANOOAAAAANOOAA OOONOOA1OOONOOA1 POO111A1POO111A1 1111111111111111 PP111PPPPP111PPP PPNOOPPPPPNOOPPP OONOOA1OOONOOA1O OO111A1POO111A1P 1111111111111111 PP1OPPPP1OPPP1OP PP1PPPPP1PPPP1PP 1111111111111111 1OPPPP1OPPPP1OPP 1PPPPP1PPPPP1PPP 1111111111111111 AAAAAAAAAAAAAAAA } # tile 3 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 APP111111111PPP1 AOOOAAAAAAAAOOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 4 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 APP111111111PPP1 AOOOAAAAAAAAOOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 5 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 PP1OPPPP1OPPP1OP PP1PPPPP1PPPP1PP 1111111111111111 1OPPPP1OPPPP1OPP 1PPPPP1PPPPP1PPP 1111111111111111 AAAAAAAAAAAAAAAA } # tile 6 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 PP1OPPPP1OPPP1OP PP1PPPPP1PPPP1PP 1111111111111111 1OPPPP1OPPPP1OPP 1PPPPP1PPPPP1PPP 1111111111111111 AAAAAAAAAAAAAAAA } # tile 7 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 APP111111111PPP1 AOOOAAAAAAAAOOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 8 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 PP1OPPPP1OPPP1OP PP1PPPPP1PPPP1PP 1111111111111111 1OPPPP1OPPPP1OPP 1PPPPP1PPPPP1PPP 1111111111111111 AAAAAAAAAAAAAAAA } # tile 9 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 APP111111111PPP1 AOOOAAAAAAAAOOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 10 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 APP111111111PPP1 AOOOAAAAAAAAOOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 11 (wall) { AAANNNNOOOOOOAAA NNNNAA11PPPPO111 OOONA11PPPBBO111 OOOOOOOOOOOOO111 OOOPPPPPPPPPP111 OOOPPPPPPPPPP111 OOPPPPPPPPPPPP11 OPPPPPPPPPPPPPP1 1111111111111111 APP111111111PPP1 AOOOAAAAAAAAOOOA AOOOA1PPPPP1OOOA AOOOA1PPPPP1OOOA A1AAA11PPPP11A1A A111A11PPPP1111A AOPPA11PPPP1OP1A } # tile 12 (doorway) { AAAAAAAAAAAAAAAA AA............AA A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A AA............AA AAAAAAAAAAAAAAAA } # tile 13 (open door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAJJ.JJJJJJJJJAA AJKJJKJJKJJJJJJA AAAAAAAAAAAAAAAA A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A A..............A AAAAAAAAAAAAAAAA } # tile 14 (open door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AK............AA ACK............A APJ............A A.J............A A.J............A A.J............A AJJ............A APJ............A A.J............A A.J............A A.J............A AK.............A AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 15 (closed door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AACCKKKKKKKKJJAA ACKJJJJJJJJJJKJA APJJPKJJKJJJJJJA A.PP.PPPPP.BPPJA A.........BPP.JA A.JJ.JJJJJPAPAJA AJJJJKJJJJ.P.AJA APKJPKJJJJJAAAJA A.PP.PPPPPP..PJA A.............JA A.JJ.JJJJJJJJJJA AJKJJKJJKJJJJJJA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 16 (closed door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AACCKKKKKKKKJJAA ACKJJJJJJJJJJKJA APJJPKJJKJJJJJJA A.PP.PPPPP.BPPJA A.........BPP.JA A.JJ.JJJJJPAPAJA AJJJJKJJJJ.P.AJA APKJPKJJJJJAAAJA A.PP.PPPPPP..PJA A.............JA A.JJ.JJJJJJJJJJA AJKJJKJJKJJJJJJA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 17 (iron bars) { ................ ................ .......BB....... ....BB.BP.BP.... .BB.BP.BP.PP.BP. .BP.BP.BP.PP.PP. .BP.BP.BP.PP.PP. .BP.BP.BP.PPAPP. .BP.BP.BPAPPAPP. .BP.BPABPAPPAPP. .BPABPABPAPPAPPA .BPABPABPAPPAPPA .BPABPABPAPPAPPA .BPABPABPAPPAPPA .BP.BP.BP.PP.PP. ................ } # tile 18 (tree) { ................ .....FFFFFF..... ...FFFFFFFFFF... ..FFFFFFFFFFFF.. ..FFFFFFFFFFFF.. ..FFFFJFFFJFFF.. ...FFFFJFJFFF... ....FFJJJJFF.... .......KJJ.AAAA. .......KJ.AAAAAA .......JJ.AAAAAA .......KJ.AAAAA. .......KJAAA.... ......KJJJAA.... ...JJJJ.J.JJJA.. ................ } # tile 19 (floor of a room) { ................ ................ ................ ................ ................ ................ ................ .......PP....... .......PP....... ................ ................ ................ ................ ................ ................ ................ } # tile 20 (dark part of a room) { .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. .A.A.A.A.A.A.A.A A.A.A.APP.A.A.A. .A.A.A.PPA.A.A.A A.A.A.A.A.A.A.A. .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. .A.A.A.A.A.A.A.A A.A.A.A.A.A.A.A. } # tile 21 (corridor) { ................ ................ ................ ................ ................ ................ .......PP....... ......P..P...... ......P..P...... .......PP....... ................ ................ ................ ................ ................ ................ } # tile 22 (lit corridor) { ................ ................ ................ ................ ................ ................ .......PP....... ......PPPP...... ......PPPP...... .......PP....... ................ ................ ................ ................ ................ ................ } # tile 23 (staircase up) { AAAAAAAAAAAAAA.A AADJJJJJJJJJDA.A AACDDJKNKKDDCA.A AAAAAANNNAAAA..A AAADJNNNNNJDA..A AAACNOONONNCA..A AAAAAAOONAAA...A AAAAKDOOOKJA...A AAAACKPONKCA...A AAAAAAOPOAA....A AAAAAKPPPJA....A AAAAACKJJKA....A AAAAAAAAAAAA...A AAAAAAAAAAAAA..A AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } # tile 24 (staircase down) { AAAAAAAAAAAAAA.A AADJJJJJJJJJDA.A AACDDJNNNKDDCA.A AAAAAANNNAAAA..A AAADJJNONJJDA..A AAACDDONNKDCA..A AAAAAAONOAAA...A AAAAPOOONONA...A AAAACPOOOPCA...A AAAAAANPNAA....A AAAAAKKOJJA....A AAAAACKJJKA....A AAAAAAAAAAAA...A AAAAAAAAAAAAA..A AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } # tile 25 (ladder up) { ADAAAAAAAAAAAD.A AADAAAANAAAADA.A AACCCCNNNCCCCA.A AADAANANANAAD..A AAADAAANAAADA..A AAACDDDNDDDCA..A AAADAAAOAAAD...A AAAAKAAOAAJA...A AAAACKKOKKCA...A AAAADAAPAAD....A AAAAAKJPJJA....A AAAAADAAAKA....A AAAAAAAAAAAA...A AAAAAAAAAAAAA..A AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } # tile 26 (ladder down) { ADAAAAAAAAAAAD.A AADAAAANAAAADA.A AACCCCCNCCCCCA.A AADAAAANAAAAD..A AAADAAANAAADA..A AAACDDDNDDDCA..A AAADAAAOAAAD...A AAAAKAAOAAJA...A AAAACOKOKOCA...A AAAADAOOOAD....A AAAAAKJOJJA....A AAAAADAAAKA....A AAAAAAAAAAAA...A AAAAAAAAAAAAA..A AAAAAAAAAAAAAA.A AAAAAAAAAAAAAAAA } # tile 27 (altar) { ................ ................ ................ ................ ................ ................ ................ ................ ................ ...PDPDPDPDP.... ..PPPDPDDDPPP... ...BBPPPDPP.AA.. ...BPPPPPP..A... ..PP.......PP... ...AAAAAAAAAAA.. ................ } # tile 28 (grave) { ................ ................ .....ONOPP...... ...ONPPPPPP..... ..OPPPPPPPPP.... .OPPPPPPPPPPP... .OPAAPPAPAAPP... .OPAPAPAPAPAPAA. .OPAAPPAPAAPPAAA .OPAPAPAPAPPPAAA .OPAPAPAPAPPPAAA .OPPPPPPPPPPPAAA .OPPPPPPPFPPPAA. .OPPF..PPF.PPA.. FFFFFFFFFFFFFFF. ................ } # tile 29 (opulent throne) { ................ .....HHHHH...... ....HCCCDDH..... ....HCCEDDH..... ....HCEEEDH..... ....HCCEDDH..... ....HCCEDDH..AA. .....HCDDHAAAAA. ..CCOHCDDHOCCAAA .HHHDHHHHHCHHHAA .H.HODDDCCOHAHAA ...HHHHHHHHHAAA. ...HALAAALAHAA.. ..HA.AAAAAAAH... ................ ................ } # tile 30 (sink) { ................ ................ ................ ....P....P...... ..NPPPPPPPPN.... .NO.P.PP.P.ON... .NOB..PP..BON... .NOBBBPPBBBONAA. .NOBBBBBBBBONAAA .NOOOOOOOOOONAAA ..NNNNNNNNNNAAAA .....OOOOAAAAAAA .....OOOOAAAAA.. ....OOOOOOA..... ................ ................ } # tile 31 (fountain) { ....E....E...... ..EEEE..EEE..... ..E...EEE.EE.... ...E.EEEE.E..... ..E..EEOE.EE.A.. .EE.EENOE.E.EAA. .E..E.NO.E.EAAA. ...PPPNOPPPAAA.. ..PEEENOEEEPAA.. .OEENNNOOOEEPA.. .NOEEEEEEEEONAA. .PNOOOOOOOONPAA. ..PNNNNNNNNPAAA. ...PPPPPPPPAAA.. ....AAAAAAAAA... ................ } # tile 32 (water) { ..........NNN... .EEEE....NE.EN.. ....EE.EEE...... .....EEE........ .NN......EE..... E.EN....E.EE..EE ...EN.E....E..E. ....EE......EE.. ................ N..EE...EEEE.... NNE..E.E...EE..N .E....E.NN..EEN. .......NEEEE.... ..EEE..E...EEE.. .E..EE...E..EEE. EE....EEE.....EE } # tile 33 (ice) { NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNN..NNNNNNN NNNNNN.NN.NNNNNN NNNNNN.NN.NNNNNN NNNNNNN..NNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN } # tile 34 (molten lava) { DDDDDDCDDDDDDDDD DDDDDCDKDDDDDDDD DDCCDDKDDDDCCCDD DCJJKDDDDDCKJJKD DCJDKDDDDDCJKDKD DDKKDDDDDDCJDKKD DDDDDDDCDDDKKKDD DDDCDDDDDDDDDDDD DDDDJDCDDDDCDDDD DDDDDDDDDDCJKDDD DDDDDDDDDDDKDDDC DDDDCCDDDDDDDDDD DDDCJJKDDDDDDDDD CDDCJDKDDDDDDJDD DDDDKKDDDDCDDDDD DDDDDDDDDDDKDDDD } # tile 35 (lowered drawbridge) { EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJKAAA EJKKKKKKKKKKKJAA EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA } # tile 36 (lowered drawbridge) { EEEEEEEEEEEEEEEE JEJKJEJKJEJKJEJK KJKKKJKKKJKKKJKK KJKAKJKAKJKAKJKA KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKAKJKAKJKAKJKA KJKKKJKKKKKKKJKK JAJKJAJKJAJKJAJK AAAAAAAAAAAAAAAA AAAEAAAEAAAEAAAE } # tile 37 (raised drawbridge) { ................ ..JKJ.JKJ.JKJ... .JKKKJKKKJKKKJ.. .JKAKJKAKJKAKJA. .JKKKJKKKJKKKJA. .JKKKJKKKJKKKJA. .JKKKJKKKJKKKJA. .JKKKJKKKJKKKJA. .JKKKJKKKJKKKJA. .JKKKJKKKJKKKJA. .JKKKJKKKJKKKJA. .JKAKJKAKJKAKJA. .JKKKJKKKKKKKJA. ..JKJAJKJAJKJAA. ...AAA.AAA.AAA.. ................ } # tile 38 (raised drawbridge) { ................ ..JJJJJJJJJJJ... .JKKKKKKKKKKKJ.. .KKAKKKKKKKAKKA. .JKKKKKKKKKKKJA. ..JJJJJJJJJJJAA. .JKKKKKKKKKKKJ.. .KKAKKKKKKKAKKA. .JKKKKKKKKKKKJA. ..JJJJJJJJJJKAA. .JKKKKKKKKKKKJ.. .KKAKKKKKKKAKKA. .JKKKKKKKKKKKJA. ..JJJJJJJJJJJAA. ...AAAAAAAAAAA.. ................ } # tile 39 (air) { BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB } # tile 40 (cloud) { BBBBBBBBBBBBBBBB BBBBBNNNNNNNBBBB BBBNNNNNNNNNNBBB BBNNNNNNNNNONNBB BBNNNNNNNNNNNNNB BNNNNNNNNNNNNONB NNNONNNNNNNNONNN NNNNNNNNNNOONNNN NNNNNNNNNNNNNONN NNOONNNNNNNOONNO NNNNNOOOOONNNNOO BONNNNNNNNNNOOOB BBOOONNNNOOOOOOB BBBOOOOOOOOOOBBB BBBBBBOOOOBBBBBB BBBBBBBBBBBBBBBB } # tile 41 (water) { EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE } # tile 42 (arrow trap) { ................ .....DDDDD...... ....DDCACDD..... ...DCCAAACCD.... ...CCAAAAACDA... ..DCCHHAHHCDDA.. ..DCHHNANHHCDA.. ..DCHNNANNHCDA.. ..DCHNNANNHCDA.. ..DCCHAAAHCCDA.. ...CCAAAAACCAA.. ...DCAAAAACDA... ....DAACAADAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 43 (dart trap) { ................ .....DDDDD...... ....DDCACDD..... ...DCCCACCCD.... ...CCCHAHCCDA... ..DCCHAAAHCDD... ..DCHHAAAHHCDA.. ..DCHNAAANHCDA.. ..DCHNNANNHCDA.. ..DCCAAAAACDDA.. ...CCAACAACDAA.. ...DCACACACDA... ....DDCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 44 (falling rock trap) { ................ .....DDDDD...... ....DDAACDD..... ...DCCCCCCCD.... ...CCCAAHCCDA... ..DCCHHHHHCDDA.. ..DCHHAAHHHCDA.. ..DCHHHHHHHCDA.. ..DCHHAAHHHCDA.. ..DCHAHAAHHCDA.. ...CCAAAAHCCAA.. ...DCCAAHCCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 45 (squeaky board) { ................ .....DDDDD...... ....DDCCCDD..... ...DCCCCCCCD.... ...CCCHHHCCDA... ..DCCHHNHHCDDA.. ..DAAAAAAAAADA.. ..DAAAAAAAAADA.. ..DAAAAAAAAADA.. ..DAAAAAAAAADA.. ...CCHHNHHCCAA.. ...DCCHHHCCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 46 (bear trap) { ................ .....DDDDD...... ....DDCCCDD..... ...DAAPCPAAD.... ...DAHHHHHADA... ..DDAAPNPAACD... ..DCANNNNNACDA.. ..DCAAPNPAACDA.. ..DCANNNNNACDA.. ..DDAHHHHHACDA.. ...DAACHCAADAA.. ...DCAAAAACDA... ....DDAAADDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 47 (land mine) { ................ .....DDDDD...... ....DDCCCDD..... ...DCCCCCCCD.... ...CCCHHHCCDA... ..DCCHHAHHCDDA.. ..DCHHAAAHHCDA.. ..DCAAAAAAACDA.. ..DCAAAAAAACDA.. ..DCHHNNNHHCDA.. ...CCHHNHHCCAA.. ...DCCHHHCCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 48 (rolling boulder trap) { ................ .....DDDDD...... ....DDCCCDD..... ...DCCCCCCCD.... ...CCCHHHCCDA... ..DCCAAAAHCDDA.. ..DCAAHAAAHCDA.. ..DCAHAAAAHCDA.. ..DCAAAAAAHCDA.. ..DCAAAAAAHCDA.. ...CCAAAAHCCAA.. ...DCCHHHCCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 49 (sleeping gas trap) { ................ .....DDDDD...... ....DDCCCDD..... ...DCCHHHCCD.... ...CAAAAAAACA... ..DCAANNAAACDA.. ..DCHNNAAAHCDA.. ..DCHNAAANHCDA.. ..DCHAAANHHCDA.. ..DCAAAHHHACDA.. ...CAAAAAAACAA.. ...DCCHHHCCDA... ....DDCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 50 (rust trap) { ................ .....DDDDD...... ....DDCCCDD..... ...DCCCCCCCD.... ...CCCHHHCCDA... ..DCCAAAAACDDA.. ..DCAAEEEAACDA.. ..DCAEEEEEACDA.. ..DCAEEEEEACDA.. ..DCAAEEEAACDA.. ...CCAAAAACCAA.. ...DCCHHHCCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 51 (fire trap) { ................ .....DDDDD...... ....DDCCCDD..... ...DCCAAACCD.... ...CCAADAACDA... ..DCAADDAAADDA.. ..DCAADDDAACDA.. ..DCADCHCDACDA.. ..DCADHNHDACDA.. ..DCAAHNHAACDA.. ...CCAANAACCAA.. ...DCCAAACCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 52 (pit) { AAAAAAAAAAAAAAAA A.AAAAAAAAAAAABA A..AAAAAAAAAABBA A...AAAAAAAABBBA A...A......ABBBA A...A......ABBBA A...A......ABBBA A...A......ABBBA A...A......ABBBA A...A......ABBBA A...A......ABBBA A...AAAAAAAABBBA A...PPPPPPPPPBBA A..PPPPPPPPPPPBA A.PPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } # tile 53 (spiked pit) { AAAAAAAAAAAAAAAA A.AAAAAAAAAAAABA A..AAAAAAAAAABBA A...AAAAAAAABBBA A...A......ABBBA A...A.N.N..ABBBA A...A......ABBBA A...A..N.N.ABBBA A...A......ABBBA A...A.N.N..ABBBA A...A......ABBBA A...AAAAAAAABBBA A...PPPPPPPPPBBA A..PPPPPPPPPPPBA A.PPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } # tile 54 (hole) { ................ ......AAAA...... .....AAAAAAB.... ....AAAAAAABB... ...AAAAAAAAABBB. ...AAAAAAAAAABB. ...AAAAAAAAAABB. ...AAAAAAAAAABB. ...AAAAAAAAAABB. ....AAAAAAAAABB. .....AAAAAAAABB. .....AAAAAAABB.. ......AAAAAB.... ................ ................ ................ } # tile 55 (trap door) { AAAAAAAAAAAAAAAA A.AAAAAAAAAAAABA A..AAAAAAAAAABBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...AAAAAAAABBBA A...PPPPPPPPPBBA A..PPPPPPPPPPPBA A.PPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } # tile 56 (teleportation trap) { ................ .....DDDDD...... ....DDCACDD..... ...DCCAAACCD.... ...DCAAAAACCA... ..DDCHHAHHCCD... ..DCOHAAAHOCDA.. ..DCHOAAAOHCDA.. ..DCHOAAAOHCDA.. ..DDCHHAHHCCDA.. ...DCAAAAACCAA.. ...DCCAAACCDA... ....DDCACDDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 57 (level teleporter) { ................ .....DDADD...... ....DDAAADD..... ...DCAAAAADD.... ...DCCCACCCCA... ..DDCHAAAHCCD... ..DCOAAOAAOCDA.. ..DCHAOOOAHCDA.. ..DCHAAOAAHCDA.. ..DDCHAAAHCCDA.. ...DCCCACCCCAA.. ...DCAAAAACDA... ....DDAAADDAA... .....DDADDAA.... ......AAAAA..... ................ } # tile 58 (magic portal) { ................ .....DDDDD...... ....DDCACDD..... ...DCCAAACCD.... ...DCAAAAACCA... ..DDCHHAHHHAD... ..DDCHOAOAACDA.. ..DDOAAAAAOCDA.. ..DDAAOAOOCCDA.. ..DAHHHAHHCCDA.. ...DCAAAAACCAA.. ...DCCAAACCDA... ....DDCACDDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 59 (web) { OAOA.OA...O....O .O.NNNN.NOA..OOA OON.NO.NA..OOA.. .N..OO.N.NOA.... .N.O...NOA...... ONO.O.NA........ .ONNNNA......... ..O.NA.......... .OA.OA.......... .OONA........... OA.OA........... ..OA............ ..OA............ .OA............. .OA............. OA.............. } # tile 60 (statue trap) { ................ .....DDDDD...... ....DDCAADD..... ...DCCAJJACD.... ...CCAKCJJADA... ..DAAAKKJJADDA.. ..ACKACKJAAADA.. ..AJJCKKJACJAA.. ..DAJCKJJJJJAA.. ..DAJCKJJJAADA.. ...CACKJAACCAA.. ...DACKJACCDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 61 (magic trap) { ................ .....DDDDD...... ....DDCCCDA..... ...DCCCCCCAD.... ...CCCHHHAADA... ..DCAHHNHAADDA.. ..DCAANNAAACDA.. ..DCAAAAAAACDA.. ..DCAAANNAACDA.. ..DCAANNNHACDA.. ...CAAHNHHCCAA.. ...DACHHHCCDA... ....ACCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 62 (anti-magic field) { ................ ......DDDDD..... .....ADCCCDD.... ....DACCCCCCD... ...ADAAHHHCCC... ..ADDAAHNHHACD.. ..ADCAAANNAACD.. ..ADCAAAAAAACD.. ..ADCAANNAAACD.. ..ADCAHNNNAACD.. ..AACCHHNHAAC... ...ADCCHHHCAD... ...AADCCCCCA.... ....AADDDDD..... .....AAAAA...... ................ } # tile 63 (polymorph trap) { ................ .....DDDDD...... ....DDCCCDD..... ...DCAAAPCCD.... ...CCAAPHCCDA... ..DCCAPAAHCDDA.. ..DCHPNAAHHCDA.. ..DCHNPAPNHCDA.. ..DCHNAANPHCDA.. ..DCHHAAPAHCDA.. ...CCHHPAACCAA.. ...DCCPAAACDA... ....DCCCCCDAA... .....DDDDDAA.... ......AAAAA..... ................ } # tile 64 (vibrating square) { ................ ................ ......H.H....... ...H.H.H.H.H.... ....H.H.H.H..... ...H.H.H.H.H.... ....H.H.H.H..... ...H.H.H.H.H.... ...H.H.H.H.H.... ....H.H.H.H..... ...H.H.H.H.H.... ....H.H.H.H..... ...H.H.H.H.H.... ......H.H....... ................ ................ } # tile 65 (wall) { .......NN....... ......NN........ .....NN......... ......NN........ .......NN....... ........NN...... .........NN..... ........NN...... .......NN....... ......NN........ .....NN......... ......NN........ .......NN....... ........NN...... .........NN..... ........NN...... } # tile 66 (wall) { ................ ................ ................ ................ ................ ..N.......N..... .NNN.....NNN.... NN.NN...NN.NN... N...NN.NN...NN.N .....NNN.....NNN ......N.......N. ................ ................ ................ ................ ................ } # tile 67 (wall) { NNNNN........... ....N........... ....N........... ....N........... ....N........... ....N........... ....N........... ....N........... ....NNNNNNNNN... ............N... ............N... ............N... ............N... ............N... ............N... ............NNNN } # tile 68 (wall) { ............NNNN ............N... ............N... ............N... ............N... ............N... ............N... ....NNNNNNNNN... ....N........... ....N........... ....N........... ....N........... ....N........... ....N........... ....N........... NNNNN........... } # tile 69 (cmap 69) { ....AAAA........ ..A....AA..AA... .AA.AAA......AA. .AA.A....A..AA.. ..A....A.A.A.AA. .A..AAA.A....AA. .A.AA.....A.AA.. ...AA....AA..... .A.A...A...A.A.. ...A......AA.AA. .A.AAA.AAAA.A.A. .AA..AA.......A. ..A...AA..A..AA. ..AAAAA..AAAAA.. ....AA....AAA... ................ } # tile 70 (cmap 70) { ................ .....NNNNNN..... ...NNNNNNNNNN... ..NNNNNNNNNNNN.. ..NNNNNNNNNNNN.. .NNNNNNNNNNNNNN. .NNNNNNNNNNNNNN. .NNNNNNNNNNNNNN. .NNNNNNNNNNNNNN. .NNNNNNNNNNNNNN. .NNNNNNNNNNNNNN. ..NNNNNNNNNNNN.. ..NNNNNNNNNNNN.. ...NNNNNNNNNN... .....NNNNNN..... ................ } # tile 71 (cmap 71) { ................ ................ ....KK.......... ....KHKA........ .....KHKA....... ......KKKA...... .......KKKA..... ........KDKA.... ........JDKA.... .......JKDJA.... ......JKDJA..... .....JHDJA...... ....JHDJA....... .....KJA........ ................ ................ } # tile 72 (cmap 72) { ................ ................ .........JK..... ........JDHJ.... .......JDHJA.... ......JDKJA..... .....JDKJA...... .....KDJA....... .....KDKA....... ......KKKA...... .......KKKA..... ........KHKA.... .........KHKA... ..........KKA... ................ ................ } # tile 73 (cmap 73) { ................ .....I....I..... ....I......I.... ...I........I... ..I...IIII...I.. .I............I. ....I..II..I.... ....I.IIII.I.... ....I.IIII.I.... ....I..II..I.... .I............I. ..I...IIII...I.. ...I........I... ....I......I.... .....I....I..... ................ } # tile 74 (cmap 74) { ................ .CCCCCCCCCCCCCCC .C.............. .C.CCCCCCCCCCCC. .C.C..........C. .C.C.CCCCCCCC.C. .C.C.C......C.C. .C.C.C.CCCC.C.C. .C.C.C.CC.C.C.C. .C.C.C....C.C.C. .C.C.CCCCCC.C.C. .C.C........C.C. .C.CCCCCCCCCC.C. .C............C. .CCCCCCCCCCCCCC. ................ } # tile 75 (cmap 75) { .......HH....... .......HH....... ....HH.HH.HH.... ...H...HH...H... ..H.H......H.H.. ..H..H....H..H.. ......H..H...... HHHH...HH...HHHH HHHH...HH...HHHH ......H..H...... ..H..H....H..H.. ..H.H......H.H.. ...H...HH...H... ....HH.HH.HH.... .......HH....... .......HH....... } # tile 76 (cmap 76) { ................ ......NNNNN..... ........N....... ...NNNN.N.NNN... ...N..N.N.N.N... .N.NNNN.N.N.N... .N......N.NNN.N. .NNNNNNNN.....N. .N.....NNNNNNNN. .N.NNN.N......N. ...N.N.N.NNNN.N. ...N.N.N.N..N... ...NNN.N.NNNN... .......N........ .....NNNNN...... ................ } # tile 77 (poison cloud) { BBBBBBBBBBBBBBBB BBBBBFFFFFFFBBBB BBBFFFFFFFFFFBBB BBFFFFFFFFFGFFBB BBFFFFFFFFFFFFFB BFFFFFFFFFFFFGFB FFFGFFFFFFFFGFFF FFFFFFFFFFGGFFFF FFFFFFFFFFFFFGFF FFGGFFFFFFFGGFFG FFFFFGGGGGFFFFGG BGFFFFFFFFFFGGGB BBGGGFFFFGGGGGGB BBBGGGGGGGGGGBBB BBBBBBGGGGBBBBBB BBBBBBBBBBBBBBBB } # tile 78 (valid position) { ................ ................ .....GGGG....... ....GGGGGG...... ...GGFFFFGG..... ...GGF...GGF.... ....FF...GGF.... ........GGFF.... .......GGFF..... ......GGFF...... ......GGF....... .......FF....... ......GG........ ......GGF....... .......FF....... ................ } # tile 79 (cmap 79) { AAAAAAADDDDDDAAA AAAAADDDDDDDDDDD AAAADDDDDDDDDDDD AAADDDDDDCCDDDDD AAADDDCCCCCCDDDD AADDDDCCCCCDDDDD AADDDCCCCCDDDDDD AADDDCCCCDDDDD.. AADDDCCCDDDD.... AADDDCCCDDDD.... AADDDDDDDDD..... AAADDDDDDD...... AAADDDDDDD...... AAAADDDDDD...... AAAADDDDDD...... AAAADDDDDD...... } # tile 80 (cmap 80) { AAAAAAAAAAAAAAAA DDAAAAAAAAAAAAAA DDDDAAAAAAAAAADD DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDD DDDDDDDCCCCCCDDD .DDDDDDDDCCCCCDD ...DDDDDDDDDDDDD ....DDDDDDDDDDDD ......DDDDDDDD.. .......DDDD..... ................ ................ ................ ................ } # tile 81 (cmap 81) { AAAAAAAAAAAAAAAA AAADDDDDAAAAAAAA DDDDDDDDDDDAAAAA DDDDDDDDDDDDAAAA DDDDDCCCDDDDDAAA DDDDDCCCCDDDDDAA DDDDDCCCCDDDDDDA DDDDDCCCCCDDDDDD DDDDDDCCCCCDDDDD DDDDDDDCCCCDDDDD ...DDDDDCCCDDDDD ...DDDDDDCCDDDDD ....DDDDDDDDDDDD ....DDDDDDDDDDDD ....DDDDDDDDDDDD ....DDDDDDDDDDDA } # tile 82 (cmap 82) { AAAADDDDDD...... AAAADDDDDDD..... AAAADDDDDDD..... AAAADDDDDDDD.... AAAADDCCCDDD.... AAADDDDCCDDD.... AADDDDCCCDDD.... AADDDDCCCDDD.... AADDDDCDDDDD.... ADDDDDDDDDD..... ADDDDDDDDD...... DDDDDDDDD....... DDDDDDDD........ DDDDDDD......... DDDDDDD......... DDCCDDD......... } # tile 83 (cmap 83) { ....DDDDDDDDDDDA ....DDDDDDDDDDDA ....DDDDDDDDDDAA ....DDDDDDDDDDAA ...DDDDDDDDDDDAA ..DDDCCDDDDDDAAA ..DDDCCDDDDDDAAA ..DDDCCDDDDDAAAA ..DDDCCDDDDDAAAA ..DDDDDDDDDDAAAA ...DDDDDDDDDAAAA ...DDDDDDDDDAAAA ....DDDDDDDDDAAA .....DDDDDDDDAAA ......DDDDDDDDAA .......DDDDDDDAA } # tile 84 (cmap 84) { DDDCDDD......... DDDCDDD......... ADDCDDD......... ADDDDDDD........ ADDDDDDDDDDDD... AADDDDDDDDDDDDDD AADDDDDDDDDDDDDD AAADDDDDDDDCDDDD AAAAADDDDDDCCCCD AAAAAAADDDDDCCCD AAAAAAAAADDDDCCC AAAAAAAAAADDDDCC AAAAAAAAAAADDDDD AAAAAAAAAAADDDDD AAAAAAAAAAAADDDD AAAAAAAAAAAAAADD } # tile 85 (cmap 85) { ................ ................ ................ ................ .............DDD ............DDDD D...........DDDD DD..........DDDC DDD.........DDDC DDDD........DDDC DDDDDD....DDDDDC DDDDDDDDDDDDDDDC DDDDDDDDDDDDDDDC DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDAA } # tile 86 (cmap 86) { ......DDDDDDDDAA ......DDDDDDDDDA .....DDDDDDDDDDA ....DDDDDDDDDDDA DDDDDDDDDDDDDDDA DDDDDDDDDDDDDDDA CCCDDDDDDDDDDDAA CCCCDDDDDDDDDDAA CCCDDDDDDDDDDDAA CCDDDDDDDDDDDAAA CCDDDDDDAAAAAAAA CDDDDDAAAAAAAAAA CDDDDAAAAAAAAAAA DDDDAAAAAAAAAAAA DDAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 87 (explosion dark 0) { ................ ................ .............AAA ......A...AAAAAA .........AAAAAAA .........AAAAAA. ........AAAA...A ...AAA.AAAA...AA .A...AAAAAA.AAAA .....AAAAAA.AAAA ....AAAAAAA.AAAA ........AA..AA.. ....AAAAAAAAAA.. ...AAAA..AAA.... ..AAAA..AAAA.... ..AAA..AAAAA.... } # tile 88 (explosion dark 1) { ................ ................ A........AAAAAA. AAAAAA.AAAAAAAA. AAAAAA.....AAAAA ...AAA.AAAAAAAAA AAAAAA.AAAAAAAAA AAAAAA.AAAAAAAA. AA...........A.. ..AAA.A.....AAAA .A.A.A...A...AAA .PPA...AA.....AA .A.....A....AAAA .....A..A...PAAA ........A.A.APAA .PA...APAAAAAAAA } # tile 89 (explosion dark 2) { ................ ................ ................ ........A...A... AAAAA........... AAAAAA...A..A... AAAAAAA......... ......AAAA...... AAAAA..AAAA..... ..AAAAAAAAAA.... AA.AA....AAA.... AA.AAAAA.AAA.... AAPAA.AAAAAA.A.. AAA.....AAAA.... AA.A..A.AAAA.... A.AA..A.AAAAA... } # tile 90 (explosion dark 3) { ..AAA.A.AAA..... ..AAA.AAAAA.AP.. ...AA.AA.......A ...AAAAAA....PP. ..AAA.AA..A..PAP .AAA...A....P.AP .AAA.AAA.A..P..P .AAA.AAA...AAAAP .AAA.AAA....PAAA .AAA..AA....PPAA ..AAA..AA...PAAP ...AAA...AP.PPPP ....AAA...P..P.A .....AA.....AAA. ..A.A...AAP...PA ....A.........PA } # tile 91 (explosion dark 4) { APAAA..PPAPAAAAA .APA..A.AAAPAAA. AAP.PAA..AAAAAA. PAPPPAAA..AAPA.. AAAPPAAAAPAAP..A AAPP.PPPAAAAA..A AAPAAAAAAAAAAA.. APPAAAAAAAAAAA.. AAAAAAAAAAAAPAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAA.AA AAAAAAAAAAA.HH.. } # tile 92 (explosion dark 5) { ..AAA.A.A.AAAA.. ..AAAAA.A.AAAA.. ..AAAAA.A.AAAA.. P.AAAAA...AAAA.. P.AAPAPAA.AAAA.. P...P..A..AAA... ...AP..AAAAAA... .PAAPAAAAAAAA... AAP...PAAAAA.... ..AA.PPAA.A...A. A...PP.......... .AAAAPPAA...A... ..AA.PP.AAA..... A......AAAAA.... AAA...AAAAAAA... ....PPAAAAAAAA.. } # tile 93 (explosion dark 6) { ....A.......A..P ....A.......AA.. .A..AA...P..A.A. ...AAA.A..P..AAP ...AAAA..AAP..A. ...AAAA....P...A ...AAAA..A..A..A ...AAAAA.AAA.... ...AAAAA..AA.... ....AAAAAAAAA... .....AAAAAAAAAAA ...A..AAAAAAAAAA ........AA.AAAAA ...A........AAAA ................ ................ } # tile 94 (explosion dark 7) { PPPAAAAAPAAA.A.. AAPPAAPPPPA.A... PPPPPPPPPPA..APP .PPAA.AA.APAA... ..AAAA.A..AAAPAA APPAPAP.A.A.PAA. A..PPAAA.......P AA.......A...... PAPA.AAAAAAAAAAP AA.APAAAA......A AAA.A.PP...AAAAA AAAAAA.A..AAAAAA AAAAAAAAAAAAAAAA AAAA..........AA ................ ................ } # tile 95 (explosion dark 8) { ....P..AAAAAAA.. ..A..A.AA.A.AA.. PP..A..AA.A.AA.. ...AAA.AA.A.AA.. .AAAAA.AAA..AA.. ..PAA..AAA.AAA.. .AAA..AAA..AAA.. .A.AA.AAAAAAAA.. AA.AAAAAA.AAAA.. ...AAAAAAAAAAA.. .AAAAAAAA.AAA... AAAAAAAA........ AAAAAA....A..... AAA...A......... ................ ................ } # tile 96 (explosion noxious 0) { ................ ................ .............FFF ......F...FFFFFF .........FFFFFFF .........FFFFFF. ........FFFF...F ...FFF.FFFF...FF .F...FFFFFF.FFFF .....FFFFFF.FFFF ....FFFFFFF.FFFF ........FF..FF.. ....FFFFFFFFFF.. ...FFFF..FFF.... ..FFFF..FFFF.... ..FFF..FFFFF.... } # tile 97 (explosion noxious 1) { ................ ................ F........FFFFFF. FFFFFF.FFFFFFFF. FFFFFF.....FFFFF ...FFF.FFFFFFFFF FFFFFF.FFFFFFFFF FFFFFF.FFFFFFFF. FF...........F.. ..FFF.F.....FFFF .H.F.F...F...FFF .GGF...FF.....FF .H.....F....FFFF .....F..F...GFFF ........F.F.FGFF .GH...HGHHFFFFFF } # tile 98 (explosion noxious 2) { ................ ................ ................ ........F...F... FFFFF........... FFFFFF...F..F... FFFFFFF......... ......FFFF...... FFFFF..FFFF..... ..FFFFFFFFFF.... FF.FF....FFF.... FF.FFFFF.FFF.... FFGFF.FFFFFF.F.. FFF.....FFFF.... FF.F..F.FFFF.... F.FF..F.FFFFF... } # tile 99 (explosion noxious 3) { ..FFF.F.FFF..... ..FFF.FFFFF.FG.. ...FF.FF.......F ...FFFFFF....GG. ..FFF.FF..F..GFG .FFF...F....G.FG .FFF.FFF.H..G..G .FFF.FFF...FFFFG .FFF.FFF....GFHH .FFF..FF....GGHH ..FFF..FF...GHHG ...FFF...FG.GGGG ....FFF...G..G.H .....FF.....HHF. ..F.F...FHG...GH ....F.........GH } # tile 100 (explosion noxious 4) { FGHFF..GGFGHFFFF .HGH..F.FFHGFHF. HFG.GHF..HHHFFH. GFGGGHHH..HHGF.. HHHGGHHHHGHHG..F HHGG.GGGHHHHF..F HHGHHHHHHHHHHF.. HGGHHHHHHHHHHH.. HHHHHHNNNNHHGHNH GHHHHHHHNHHHHHNH GHHGHGNNNNHHHHGF GGNHNHNNNNHHHGGF HHHHNHNNNHHHGGGG HGGNGHNNNHHHGGGF HHHHNHNHN.GGG.GF GGGGNHHHGGG.HH.. } # tile 101 (explosion noxious 5) { ..FFF.F.F.FFFF.. ..FFFFF.F.FFFF.. ..FFFFF.F.FFFF.. G.FFFFF...FFFF.. G.FFGFGFF.FFFF.. G...G.GF..FFF... ...FG..FFFFFF... .GFFFFFFFFFFF... FFG...GFFFFF.... ..FF.GGFF.F...F. F...GG.......... .FFFFGGFF...F... ..HF.GG.FFF..... H......FFFFF.... HFH...FFFFFFF... ....GGFFFFFFFF.. } # tile 102 (explosion noxious 6) { ....F.......H..G ....F.......FH.. .F..FF...G..F.H. ...FFF.F..G..FFG ...FFFF..FFG..F. ...FFFF....G...F ...FFFF..F..H..F ...FFFFF.FFF.... ...FFFFF..FF.... ....FFFFFFFFF... .....FFFHFFFFFFF ...F..FFFFFFFFFF ........FF.FFFFF ...F........FFFF ................ ................ } # tile 103 (explosion noxious 7) { GGGHHHHHGHHH.H.. HHGGHHGGGGH.F... GGGGGGGGGGF..FGG .GGHF.FF.HGFF... ..HHHH.F..FFHGHF HGGFGFG.H.H.GFF. F..GGFFH.......G HF.......F...... GHGF.FFFFFFFFFFG HF.HGHFFF......F FFF.F.GG...FFFFF FFFFFF.F..FFFFFF FFFFFFFFFFFFFFFF FFFF..........FF ................ ................ } # tile 104 (explosion noxious 8) { ....G..FFFFFFF.. ..F..F.FF.F.FF.. GG..F..FF.F.FF.. ...FFF.FF.F.FF.. .FFFFF.FFF..FF.. ..GFF..FFF.FFF.. .FFF..FFF..FFF.. .F.FF.FFFFFFFF.. FF.FFFFFF.FFFF.. ...FFFFFFFFFFF.. .FFFFFFFF.FFF... FFFFFFFF........ FFFFFF....F..... FFF...F......... ................ ................ } # tile 105 (explosion muddy 0) { ................ ................ .............JJJ ......J...JJJJJJ .........JJJJJJJ .........JJJJJJK ........JJJJKKKJ ...JJJ.JJJJKKKJJ .J...JJJJJJKJJJJ .....JJJJJJKJJJJ ....JJJJJJJKJJJJ .......KJJKKJJKK ....JJJJJJJJJJKK ...JJJJKKJJJKKKK ..JJJJKKJJJJKKKK ..JJJKKJJJJJKKKK } # tile 106 (explosion muddy 1) { ................ ................ J........JJJJJJ. JJJJJJKJJJJJJJJ. JJJJJJKKKKKJJJJJ KKKJJJKJJJJJJJJJ JJJJJJKJJJJJJJJJ JJJJJJKJJJJJJJJK JJKKKKKKKKKKKJKK KKJJJKJKKKKKJJJJ KLKJKJKKKJKKKJJJ KCCJKKKJJKKKKKJJ KLKKKKKJKKKKJJJJ KKKKKJKKJKKKCJJJ KKKKKKKKJKJKJCJJ KCLKKKLCLLJJJJJJ } # tile 107 (explosion muddy 2) { ................ ................ ................ ........J...J... JJJJJ........... JJJJJJ...J..J... JJJJJJJ......... KKKKKKJJJJ...... JJJJJKKJJJJ..... KKJJJJJJJJJJ.... JJKJJKKKKJJJ.... JJKJJJJJKJJJ.... JJCJJKJJJJJJ.J.. JJJKKKKKJJJJ.... JJKJKKJKJJJJ.... JKJJKKJKJJJJJ... } # tile 108 (explosion muddy 3) { ..JJJKJKJJJKKKKK ..JJJKJJJJJKJCKK ...JJKJJKKKKKKKJ ...JJJJJJKKKKCCK ..JJJKJJKKJKKCJC .JJJKKKJKKKKCKJC .JJJKJJJKLKKCKKC .JJJKJJJKKKJJJJC .JJJKJJJKKKKCJLL .JJJKKJJKKKKCCLL ..JJJKKJJKKKCLLC ...JJJKKKJCKCCCC ....JJJKKKCKKCKL .....JJKKKKKLLJK ..J.JKKKJLCKKKCL ....JKKKKKKKKKCL } # tile 109 (explosion muddy 4) { JCLJJKKCCJCLJJJJ KLCLKKJKJJLCJLJK LJCKCLJKKLLLJJLK CJCCCLLLKKLLCJKK LLLCCLLLLCLLCKKJ LLCCKCCCLLLLJKKJ LLCLLLLLLLLLLJKK LCCLLLLLLLLLLLKK LLLLLLCCCCLLCLCL CLLLLLLLCLLLLLCL CLLCLCCCCCLLLLCJ CCCLCLCCCCLLLCCJ LLLLCLCCCLLLCCCC LCCCCLCCCLLLCCCJ LLLLCLCLCKCCCKCJ CCCCCLLLCCCKLLKK } # tile 110 (explosion muddy 5) { KKJJJKJKJKJJJJ.. KKJJJJJKJKJJJJ.. KKJJJJJKJKJJJJ.. CKJJJJJKKKJJJJ.. CKJJCJCJJKJJJJ.. CKKKCKKJKKJJJ... KKKJCKKJJJJJJ... KCJJCJJJJJJJJ... JJCKKKCJJJJJ.... KKJJKCCJJKJ...J. JKKKCCKKKK...... KJJJJCCJJK..J... KKLJKCCKJJJ..... LKKKKKKJJJJJ.... LJLKKKJJJJJJJ... KKKKCCJJJJJJJJ.. } # tile 111 (explosion muddy 6) { ....JKKKKKKKLKKC ....JKKKKKKKJLKK .J..JJKKKCKKJKLK ...JJJKJKKCKKJJC ...JJJJKKJJCKKJK ...JJJJKKKKCKKKJ ...JJJJKKJKKLKKJ ...JJJJJKJJJKKKK ...JJJJJKKJJKKKK ....JJJJJJJJJKKK .....JJJLJJJJJJJ ...J..JJJJJJJJJJ ........JJ.JJJJJ ...J........JJJJ ................ ................ } # tile 112 (explosion muddy 7) { CCCLLLLLCLLLKLKK LLCCLLCCCCLKJKKK CCCCCCCCCCJKKJCC KCCLJKJJKLCJJKKK KKLLLLKJKKJJLCLJ LCCJCJCKLKLKCJJK JKKCCJJLKKKKKKKC LJKKKKKKKJKKKKKK CLCJKJJJJJJJJJJC LJKLCLJJJKKKKKKJ JJJKJKCCKKKJJJJJ JJJJJJKJKKJJJJJJ JJJJJJJJJJJJJJJJ JJJJ..........JJ ................ ................ } # tile 113 (explosion muddy 8) { KKKKCKKJJJJJJJ.. KKJKKJKJJKJKJJ.. CCKKJKKJJKJKJJ.. KKKJJJKJJKJKJJ.. KJJJJJKJJJKKJJ.. KKCJJKKJJJKJJJ.. KJJJKKJJJKKJJJ.. KJKJJKJJJJJJJJ.. JJKJJJJJJKJJJJ.. KKKJJJJJJJJJJJ.. KJJJJJJJJ.JJJ... JJJJJJJJ........ JJJJJJ....J..... JJJ...J......... ................ ................ } # tile 114 (explosion wet 0) { ................ ................ .............EEE ......E...EEEEEE .........EEEEEEE .........EEEEEEP ........EEEEPPPE ...EEE.EEEEPPPEE .E...EEEEEEPEEEE .....EEEEEEPEEEE ....EEEEEEEPEEEE .......PEEPPEEPP ....EEEEEEEEEEPP ...EEEEPPEEEPPPP ..EEEEPPEEEEPPPP ..EEEPPEEEEEPPPP } # tile 115 (explosion wet 1) { ................ ................ E........EEEEEE. EEEEEEPEEEEEEEE. EEEEEEPPPPPEEEEE PPPEEEPEEEEEEEEE EEEEEEPEEEEEEEEE EEEEEEPEEEEEEEEP EEPPPPPPPPPPPEPP PPEEEPEPPPPPEEEE PNPEPEPPPEPPPEEE PBBEPPPEEPPPPPEE PNPPPPPEPPPPEEEE PPPPPEPPEPPPBEEE PPPPPPPPEPEPEBEE PBNPPPNBEEEEEEEE } # tile 116 (explosion wet 2) { ................ ................ ................ ........E...E... EEEEE........... EEEEEE...E..E... EEEEEEE......... PPPPPPEEEE...... EEEEEPPEEEE..... PPEEEEEEEEEE.... EEPEEPPPPEEE.... EEPEEEEEPEEE.... EEBEEPEEEEEE.E.. EEEPPPPPEEEE.... EEPEPPEPEEEE.... EPEEPPEPEEEEE... } # tile 117 (explosion wet 3) { ..EEEPEPEEEPPPPP ..EEEPEEEEEPEBPP ...EEPEEPPPPPPPE ...EEEEEEPPPPBBP ..EEEPEEPPEPPBEB .EEEPPPEPPPPBPEB .EEEPEEEPNPPBPPB .EEEPEEEPPPEEEEB .EEEPEEEPPPPBEEE .EEEPPEEPPPPBBEE ..EEEPPEEPPPBEEB ...EEEPPPEBPBBBB ....EEEPPPBPPBPN .....EEPPPPPNNEP ..E.EPPPENBPPPBE ....EPPPPPPPPPBE } # tile 118 (explosion wet 4) { EBNEEPPBBEBNEEEE PNBNPPEPEEEBENEP NEBPBEEPPEEEEENP BEBBBEEEPPEEBEPP EEEBBEEEEBEEBPPE EEBBPBBBEEEEEPPE EEBEEEEEEEEEEEPP EBBEEEEEEEEEEEPP EEEEEEEEEEEEBEEE BEEEEEEEEEEEEEEE BEEBEBEEEEEEEEBE BBEEEEEEEEEEEBBE EEEEEEEEEEEEBBBB EBBEBEEEEEEEBBBE EEEEEEEEEPBBBPBE BBBBEEEEBBBPNNPP } # tile 119 (explosion wet 5) { PPEEEPEPEPEEEE.. PPEEEEEPEPEEEE.. PPEEEEEPEPEEEE.. BPEEEEEPPPEEEE.. BPEEBEBEEPEEEE.. BPPPBPPEPPEEE... PPPEBPPEEEEEE... PBEEBEEEEEEEE... EEBPPPBEEEEE.... PPEEPBBEEPE...E. EPPPBBPPPP...... PEEEEBBEEP..E... PPNEPBBPEEE..... NPPPPPPEEEEE.... NENPPPEEEEEEE... PPPPBBEEEEEEEE.. } # tile 120 (explosion wet 6) { ....EPPPPPPPNPPB ....EPPPPPPPENPP .E..EEPPPBPPEPNP ...EEEPEPPBPPEEB ...EEEEPPEEBPPEP ...EEEEPPPPBPPPE ...EEEEPPEPPNPPE ...EEEEEPEEEPPPP ...EEEEEPPEEPPPP ....EEEEEEEEEPPP .....EEENEEEEEEE ...E..EEEEEEEEEE ........EE.EEEEE ...E........EEEE ................ ................ } # tile 121 (explosion wet 7) { BBBEEEEEBEEEPEPP EEBBEEBBBBEPEPPP BBBBBBBBBBEPPEBB PBBEEPEEPNBEEPPP PPEEEEPEPPEENBNE NBBEBEBPNPNPBEEP EPPBBEENPPPPPPPB NEPPPPPPPEPPPPPP BNBEPEEEEEEEEEEB NEPNBNEEEPPPPPPE EEEPEPBBPPPEEEEE EEEEEEPEPPEEEEEE EEEEEEEEEEEEEEEE EEEE..........EE ................ ................ } # tile 122 (explosion wet 8) { PPPPBPPEEEEEEE.. PPEPPEPEEPEPEE.. BBPPEPPEEPEPEE.. PPPEEEPEEPEPEE.. PEEEEEPEEEPPEE.. PPBEEPPEEEPEEE.. PEEEPPEEEPPEEE.. PEPEEPEEEEEEEE.. EEPEEEEEEPEEEE.. PPPEEEEEEEEEEE.. PEEEEEEEE.EEE... EEEEEEEE........ EEEEEE....E..... EEE...E......... ................ ................ } # tile 123 (explosion magical 0) { ................ ................ .............EEE ......E...EEEEEE .........EEEEEEE .........EEEEEEC ........EEEEIIIE ...EEE.EEEEIIIEE .E...EEEEEEIEEEE .....EEEEEEIEEEE ....EEEEEEEIEEEE .......IEEIIEEII ....EEEEEEEEEEII ...EEEEIIEEEIIII ..EEEEIIEEEEIIII ..EEEIIEEEEEIIII } # tile 124 (explosion magical 1) { ................ ................ E........EEEEEE. EEEEEEIEEEEEEEE. EEEEEEIIIIIEEEEE IIIEEEIEEEEEEEEE EEEEEEIEEEEEEEEE EEEEEEIEEEEEEEEI EEIIIIIIIIIIIEII IIEEEIEIIIIIEEEE IHIEIEIIIEIIIEEE ILLEIIIEEIIIIIEE IHIIIIIEIIIIEEEE IIIIIEIIEIIILEEE IIIIIIIIEIEIELEE ILHIIIHLHHEEEEEE } # tile 125 (explosion magical 2) { ................ ................ ................ ........E...E... EEEEE........... EEEEEE...E..E... EEEEEEE......... IIIIIIEEEE...... EEEEEIIEEEE..... IIEEEEEEEEEE.... EEIEEIIIIEEE.... EEIEEEEEIEEE.... EELEEIEEEEEE.E.. EEEIIIIIEEEE.... EEIEIIEIEEEE.... EIEEIIEIEEEEE... } # tile 126 (explosion magical 3) { ..EEEIEIEEEIIIII ..EEEIEEEEEIEIII ...EEIEEIIIIIIIE ...EEEEEEIIIIIII ..EEEIEEIIEIIIEI .EEEIIIEIIIIIIEI .EEEIEEEINIIIIII .EEEIEEEIIIEEEEI .EEEIEEEIIIIIENN .EEEIIEEIIIIIINN ..EEEIIEEIIIINNI ...EEEIIIEIIIIII ....EEEIIIIIIIIN .....EEIIIIINNEI ..E.EIIIENIIIIIN ....EIIIIIIIIIIN } # tile 127 (explosion magical 4) { EINEEIIIIEINEEEE ININIIEIEENIENEI NEIIINEIINNNEENI IEIIINNNIINNIEII NNNIINNNNINNIIIE NNIIIIIINNNNEIIE NNINNNNNNNNNNEII NIINNNNNNNNNNNII NNNNNNNNNNNNINNN INNNNNNNNNNNNNNN INNININNNNNNNNIE IINNNNNNNNNNNIIE NNNNNNNNNNNNIIII NIININNNNNNNIIIE NNNNNNNNNIIIIIIE IIIINNNNIIIINNII } # tile 128 (explosion magical 5) { IIEEEIEIEIEEEE.. IIEEEEEIEIEEEE.. IIEEEEEIEIEEEE.. IIEEEEEIIIEEEE.. IIEEIEIEEIEEEE.. IIIIIIIEIIEEE... IIIEIIIEEEEEE... IIEEIEEEEEEEE... EEIIIIIEEEEE.... IIEEIIIEEIE...E. EIIIIIIIII...... IEEEEIIEEI..E... IINEIIIIEEE..... NIIIIIIEEEEE.... NENIIIEEEEEEE... IIIIIIEEEEEEEE.. } # tile 129 (explosion magical 6) { ....EIIIIIIIHIII ....EIIIIIIIEHII .E..EEIIIIIIEIHI ...EEEIEIIIIIEEI ...EEEEIIEEIIIEI ...EEEEIIIIIIIIE ...EEEEIIEIIHIIE ...EEEEEIEEEIIII ...EEEEEIIEEIIII ....EEEEEEEEEIII .....EEEHEEEEEEE ...E..EEEEEEEEEE ........EE.EEEEE ...E........EEEE ................ ................ } # tile 130 (explosion magical 7) { IIINNNNNINNNINII NNIINNIIIINIEIII IIIIIIIIIIEIIEII IIINEIEEINIEEIII IINNNNIEIIEENINE NIIEIEIININIIEEI EIIIIEENIIIIIIII NEIIIIIIIEIIIIII INIEIEEEEEEEEEEI NEININEEEIIIIIIE EEEIEIIIIIIEEEEE EEEEEEIEIIEEEEEE EEEEEEEEEEEEEEEE EEEE..........EE ................ ................ } # tile 131 (explosion magical 8) { IIIIIIIEEEEEEE.. IIEIIEIEEIEIEE.. IIIIEIIEEIEIEE.. IIIEEEIEEIEIEE.. IEEEEEIEEEIIEE.. IIIEEIIEEEIEEE.. IEEEIIEEEIIEEE.. IEIEEIEEEEEEEE.. EEIEEEEEEIEEEE.. IIIEEEEEEEEEEE.. IEEEEEEEE.EEE... EEEEEEEE........ EEEEEE....E..... EEE...E......... ................ ................ } # tile 132 (explosion fiery 0) { ................ ................ .............DDD ......D...DDDDDD .........DDDDDDD .........DDDDDDC ........DDDDCCCD ...DDD.DDDDCCCDD .D...DDDDDDCDDDD .....DDDDDDCDDDD ....DDDDDDDCDDDD .......CDDCCDDCC ....DDDDDDDDDDCC ...DDDDCCDDDCCCC ..DDDDCCDDDDCCCC ..DDDCCDDDDDCCCC } # tile 133 (explosion fiery 1) { ................ ................ D........DDDDDD. DDDDDDCDDDDDDDD. DDDDDDCCCCCDDDDD CCCDDDCDDDDDDDDD DDDDDDCDDDDDDDDD DDDDDDCDDDDDDDDC DDCCCCCCCCCCCDCC CCDDDCDCCCCCDDDD CHCDCDCCCDCCCDDD CLLDCCCDDCCCCCDD CHCCCCCDCCCCDDDD CCCCCDCCDCCCLDDD CCCCCCCCDCDCDLDD CLHCCCHLHHDDDDDD } # tile 134 (explosion fiery 2) { ................ ................ ................ ........D...D... DDDDD........... DDDDDD...D..D... DDDDDDD......... CCCCCCDDDD...... DDDDDCCDDDD..... CCDDDDDDDDDD.... DDCDDCCCCDDD.... DDCDDDDDCDDD.... DDLDDCDDDDDD.D.. DDDCCCCCDDDD.... DDCDCCDCDDDD.... DCDDCCDCDDDDD... } # tile 135 (explosion fiery 3) { ..DDDCDCDDDCCCCC ..DDDCDDDDDCDLCC ...DDCDDCCCCCCCD ...DDDDDDCCCCLLC ..DDDCDDCCDCCLDL .DDDCCCDCCCCLCDL .DDDCDDDCHCCLCCL .DDDCDDDCCCDDDDL .DDDCDDDCCCCLDHH .DDDCCDDCCCCLLHH ..DDDCCDDCCCLHHL ...DDDCCCDLCLLLL ....DDDCCCLCCLCH .....DDCCCCCHHDC ..D.DCCCDHLCCCLH ....DCCCCCCCCCLH } # tile 136 (explosion fiery 4) { DLHDDCCLLDLHDDDD CHLHCCDCDDHLDHDC HDLCLHDCCHHHDDHC LDLLLHHHCCHHLDCC HHHLLHHHHLHHLCCD HHLLCLLLHHHHDCCD HHLHHHHHHHHHHDCC HLLHHHHHHHHHHHCC HHHHHHNNNNHHLHNH LHHHHHHHNHHHHHNH LHHLHLNNNNHHHHLD LLNHNHNNNNHHHLLD HHHHNHNNNHHHLLLL HLLNLHNNNHHHLLLD HHHHNHNHNCLLLCLD LLLLNHHHLLLCHHCC } # tile 137 (explosion fiery 5) { CCDDDCDCDCDDDD.. CCDDDDDCDCDDDD.. CCDDDDDCDCDDDD.. LCDDDDDCCCDDDD.. LCDDLDLDDCDDDD.. LCCCLCCDCCDDD... CCCDLCCDDDDDD... CLDDLDDDDDDDD... DDLCCCLDDDDD.... CCDDCLLDDCD...D. DCCCLLCCCC...... CDDDDLLDDC..D... CCHDCLLCDDD..... HCCCCCCDDDDD.... HDHCCCDDDDDDD... CCCCLLDDDDDDDD.. } # tile 138 (explosion fiery 6) { ....DCCCCCCCHCCL ....DCCCCCCCDHCC .D..DDCCCLCCDCHC ...DDDCDCCLCCDDL ...DDDDCCDDLCCDC ...DDDDCCCCLCCCD ...DDDDCCDCCHCCD ...DDDDDCDDDCCCC ...DDDDDCCDDCCCC ....DDDDDDDDDCCC .....DDDHDDDDDDD ...D..DDDDDDDDDD ........DD.DDDDD ...D........DDDD ................ ................ } # tile 139 (explosion fiery 7) { LLLHHHHHLHHHCHCC HHLLHHLLLLHCDCCC LLLLLLLLLLDCCDLL CLLHDCDDCHLDDCCC CCHHHHCDCCDDHLHD HLLDLDLCHCHCLDDC DCCLLDDHCCCCCCCL HDCCCCCCCDCCCCCC LHLDCDDDDDDDDDDL HDCHLHDDDCCCCCCD DDDCDCLLCCCDDDDD DDDDDDCDCCDDDDDD DDDDDDDDDDDDDDDD DDDD..........DD ................ ................ } # tile 140 (explosion fiery 8) { CCCCLCCDDDDDDD.. CCDCCDCDDCDCDD.. LLCCDCCDDCDCDD.. CCCDDDCDDCDCDD.. CDDDDDCDDDCCDD.. CCLDDCCDDDCDDD.. CDDDCCDDDCCDDD.. CDCDDCDDDDDDDD.. DDCDDDDDDCDDDD.. CCCDDDDDDDDDDD.. CDDDDDDDD.DDD... DDDDDDDD........ DDDDDD....D..... DDD...D......... ................ ................ } # tile 141 (explosion frosty 0) { ................ ................ .............EEE .....NE...EEEEEE ..N...N..ENBEEEE .N.N.N...EEEEEEP ....N...EEEEPPPE ...NEN.NEEEPPPEE .EN..ENEEEEPNBEE ...N.EEEEEEPEEEE ....EENBEEEPEEEE .......PEEPPEEPP ....EEEEEEEEEEPP ...EEEEPPEEEPPPP ..EEEEPPNBEEPPPP ..EEEPPEEEEEPPPP } # tile 142 (explosion frosty 1) { ................ ................ E........EEEEEE. ENBEENPEEEENBEE. EEEEEENPNPNEEEEE PPBEEEPENEEEEEEE EEEEEENNNNNEEEEE EEEEEEPENEEENBEP EEPPPPNPNPNPPPPP PPEEENEPPPPNEEEE PNPEPEPPPEPPPEEE PBBEPPPEEPPNBPEE PNPPPPPEPPPPEEEE PPPPPEPPEPPPBEEE PPPPPPPPEPEPEBEE PBNPPPNBNNEEEEEE } # tile 143 (explosion frosty 2) { ................ ................ ................ ........E...E... EEEEE........... EEEEEE...E..N... EEEEEEEN..NN.... PPPPPPENEN...... EEEEEPPENEN.N... PPEEEEEEEEEN.N.. EEPEEPPPPNNE.N.. EEPEEEEENEEE.... EEBEEPEEEEEE.E.. EEEPPPPPEEEE.... EEPEPPEPEEEE.... EPEEPPEPEEEEE... } # tile 144 (explosion frosty 3) { ..EEEPEPEEEPPPPP ..EEEPEEEEEPEBPP ...EEPEEPPPPPPPE ...ENENEEPPPPBBP ..EEENEEPPEPPBEB .EEENENEPPPPBPEB .EEEPEEEPNPPBPPB .EEEPEEEPPPEEEEB .EEEPEEEPPPPBENN .EEEPPEEPPPPBBNN ..EEEPNEEPPPBNNB ...EENNNPEBPBBBB ....EENPPPBPPBPN .....EEPPPPPNNEP ..E.EPPPENBPPPBN ....EPPPPPPPPPBN } # tile 145 (explosion frosty 4) { EBNEEPPBBEBNEEEE PNBNPPEPEENBENEP NEBPBNEPPNNNEENP BEBBBNNNPPNNBEPP NNNBBNNNNBNNBPPE NNBBPBBBNNNNEPPE NNBNNNNNNNNNNEPP NBBNNNNNNNNNNNPP NNNNNNNNNNNNBNNN BNNNNNNNNNNNNNNN BNNBNBNNNNNNNNBE BBNNNNNNNNNNNBBE NNNNNNNNNNNNBBBB NBBNBNNNNNNNBBBE NNNNNNNNNPBBBPBE BBBBNNNNBBBPNNPP } # tile 146 (explosion frosty 5) { PPEEEPEPEPEEEE.. PPEEEEEPEPEEEE.. PPEEEEEPEPEEEE.. BPEEEEEPPPEEEE.. BPEEBEBEEPEEEE.. BPPPBPPEPPEEE... PPPEBPPENEEEN... PBEEBEEEENENE... EEBPPPBNNNNNNN.. PPEEPBBEENEN..E. EPPPBBPPNP..N... PEEEEBBEEP..E... PPNEPBBPEEE..... NPPPPPPEEEEE.... NENPPPEEEEEEE... PPPPBBEEEEEEEE.. } # tile 147 (explosion frosty 6) { ....EPPPPPPPNPPB ....EPPPPPPPENPP .E..EEPPPBPPEPNP ...EEEPEPPBPPEEB ...EENEPPEEBPPEP ...NEEENPPPBPPPE ..NENPNPNEPPNPPE ...NNENNPEEEPPPP .N.PEEEPPNEEPPPP ...NNENNEEEEEPPP ..N.NPNENEEEEEEE ...N..ENEEEEEEEE .....N..EE.EEEEE ...E........EEEE ................ ................ } # tile 148 (explosion frosty 7) { BBBNNNNNBNNNPNPP NNBBNNBBBBNPEPPP BBBBBBBBBBEPPEBB PBBNEPEEPNBEEPPP PPNNNNPEPPEENBNE NBBEBEBPNPNPBEEP EPPBBEENPPPPPPPB NEPPPPPPPEPPPPPP BNBEPEEEEEEEEEEB NEPNBNEEEPNENPPE EEEPEPBBPPPNEEEE EEEEEEPEPNNNNNEE EEEEEEEEEEENEEEE EEEE......N.N.EE ................ ................ } # tile 149 (explosion frosty 8) { PPPPBPPEEEEEEE.. PPEPPEPEEPEPEE.. BBPPEPPEEPEPNEN. PPPEEEPEEPEPEN.. PEEEEEPEEEPPNEN. PPBEEPNENEPEEE.. PEEEPPENEPPEEE.. PEPEENNNNNEEEE.. EEPEEEENEPEEEE.. PPPEEENENEEEEE.. PEEEEEEEE.EEE... EEEEEEEE........ EEEEEE....EN.... EEE...E...N.N... ...........N.... ................ } # tile 150 (zap 0 0) { .......II....... ......IIII...... ......IIII...... .......II....... .......II....... ......IIII...... ......IIII...... .......II....... .......II....... ......IIII...... ......IIII...... .......II....... .......II....... ......IIII...... ......IIII...... .......II....... } # tile 151 (zap 0 1) { ................ ................ ................ ................ ................ ................ .II..II..II..II. IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII .II..II..II..II. ................ ................ ................ ................ ................ ................ } # tile 152 (zap 0 2) { III............. IIII............ IIII............ .IIII........... ...IIII......... ....IIII........ ....IIII........ .....IIII....... .......IIII..... ........IIII.... ........IIII.... .........IIII... ...........IIII. ............IIII ............IIII .............III } # tile 153 (zap 0 3) { .............III ............IIII ............IIII ...........IIII. .........IIII... ........IIII.... ........IIII.... .......IIII..... .....IIII....... ....IIII........ ....IIII........ ...IIII......... .IIII........... IIII............ IIII............ III............. } # tile 154 (zap 1 0) { .......CC....... ......CCCC...... ......CCCC...... .......CC....... .......CC....... ......CCCC...... ......CCCC...... .......CC....... .......CC....... ......CCCC...... ......CCCC...... .......CC....... .......CC....... ......CCCC...... ......CCCC...... .......CC....... } # tile 155 (zap 1 1) { ................ ................ ................ ................ ................ ................ .CC..CC..CC..CC. CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC .CC..CC..CC..CC. ................ ................ ................ ................ ................ ................ } # tile 156 (zap 1 2) { CCC............. CCCC............ CCCC............ .CCCC........... ...CCCC......... ....CCCC........ ....CCCC........ .....CCCC....... .......CCCC..... ........CCCC.... ........CCCC.... .........CCCC... ...........CCCC. ............CCCC ............CCCC .............CCC } # tile 157 (zap 1 3) { .............CCC ............CCCC ............CCCC ...........CCCC. .........CCCC... ........CCCC.... ........CCCC.... .......CCCC..... .....CCCC....... ....CCCC........ ....CCCC........ ...CCCC......... .CCCC........... CCCC............ CCCC............ CCC............. } # tile 158 (zap 2 0) { .......NN....... ......NNNN...... ......NNNN...... .......NN....... .......NN....... ......NNNN...... ......NNNN...... .......NN....... .......NN....... ......NNNN...... ......NNNN...... .......NN....... .......NN....... ......NNNN...... ......NNNN...... .......NN....... } # tile 159 (zap 2 1) { ................ ................ ................ ................ ................ ................ .NN..NN..NN..NN. NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN .NN..NN..NN..NN. ................ ................ ................ ................ ................ ................ } # tile 160 (zap 2 2) { NNN............. NNNN............ NNNN............ .NNNN........... ...NNNN......... ....NNNN........ ....NNNN........ .....NNNN....... .......NNNN..... ........NNNN.... ........NNNN.... .........NNNN... ...........NNNN. ............NNNN ............NNNN .............NNN } # tile 161 (zap 2 3) { .............NNN ............NNNN ............NNNN ...........NNNN. .........NNNN... ........NNNN.... ........NNNN.... .......NNNN..... .....NNNN....... ....NNNN........ ....NNNN........ ...NNNN......... .NNNN........... NNNN............ NNNN............ NNN............. } # tile 162 (zap 3 0) { .......BB....... ......BBBB...... ......BBBB...... .......BB....... .......BB....... ......BBBB...... ......BBBB...... .......BB....... .......BB....... ......BBBB...... ......BBBB...... .......BB....... .......BB....... ......BBBB...... ......BBBB...... .......BB....... } # tile 163 (zap 3 1) { ................ ................ ................ ................ ................ ................ .BB..BB..BB..BB. BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB .BB..BB..BB..BB. ................ ................ ................ ................ ................ ................ } # tile 164 (zap 3 2) { BBB............. BBBB............ BBBB............ .BBBB........... ...BBBB......... ....BBBB........ ....BBBB........ .....BBBB....... .......BBBB..... ........BBBB.... ........BBBB.... .........BBBB... ...........BBBB. ............BBBB ............BBBB .............BBB } # tile 165 (zap 3 3) { .............BBB ............BBBB ............BBBB ...........BBBB. .........BBBB... ........BBBB.... ........BBBB.... .......BBBB..... .....BBBB....... ....BBBB........ ....BBBB........ ...BBBB......... .BBBB........... BBBB............ BBBB............ BBB............. } # tile 166 (zap 4 0) { .......AA....... ......AAAA...... ......AAAA...... .......AA....... .......AA....... ......AAAA...... ......AAAA...... .......AA....... .......AA....... ......AAAA...... ......AAAA...... .......AA....... .......AA....... ......AAAA...... ......AAAA...... .......AA....... } # tile 167 (zap 4 1) { ................ ................ ................ ................ ................ ................ .AA..AA..AA..AA. AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA .AA..AA..AA..AA. ................ ................ ................ ................ ................ ................ } # tile 168 (zap 4 2) { AAA............. AAAA............ AAAA............ .AAAA........... ...AAAA......... ....AAAA........ ....AAAA........ .....AAAA....... .......AAAA..... ........AAAA.... ........AAAA.... .........AAAA... ...........AAAA. ............AAAA ............AAAA .............AAA } # tile 169 (zap 4 3) { .............AAA ............AAAA ............AAAA ...........AAAA. .........AAAA... ........AAAA.... ........AAAA.... .......AAAA..... .....AAAA....... ....AAAA........ ....AAAA........ ...AAAA......... .AAAA........... AAAA............ AAAA............ AAA............. } # tile 170 (zap 5 0) { .......NN....... ......NNNN...... ......NNNN...... .......NN....... .......NN....... ......NNNN...... ......NNNN...... .......NN....... .......NN....... ......NNNN...... ......NNNN...... .......NN....... .......NN....... ......NNNN...... ......NNNN...... .......NN....... } # tile 171 (zap 5 1) { ................ ................ ................ ................ ................ ................ .NN..NN..NN..NN. NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN .NN..NN..NN..NN. ................ ................ ................ ................ ................ ................ } # tile 172 (zap 5 2) { NNN............. NNNN............ NNNN............ .NNNN........... ...NNNN......... ....NNNN........ ....NNNN........ .....NNNN....... .......NNNN..... ........NNNN.... ........NNNN.... .........NNNN... ...........NNNN. ............NNNN ............NNNN .............NNN } # tile 173 (zap 5 3) { .............NNN ............NNNN ............NNNN ...........NNNN. .........NNNN... ........NNNN.... ........NNNN.... .......NNNN..... .....NNNN....... ....NNNN........ ....NNNN........ ...NNNN......... .NNNN........... NNNN............ NNNN............ NNN............. } # tile 174 (zap 6 0) { .......FF....... ......FFFF...... ......FFFF...... .......FF....... .......FF....... ......FFFF...... ......FFFF...... .......FF....... .......FF....... ......FFFF...... ......FFFF...... .......FF....... .......FF....... ......FFFF...... ......FFFF...... .......FF....... } # tile 175 (zap 6 1) { ................ ................ ................ ................ ................ ................ .FF..FF..FF..FF. FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF .FF..FF..FF..FF. ................ ................ ................ ................ ................ ................ } # tile 176 (zap 6 2) { FFF............. FFFF............ FFFF............ .FFFF........... ...FFFF......... ....FFFF........ ....FFFF........ .....FFFF....... .......FFFF..... ........FFFF.... ........FFFF.... .........FFFF... ...........FFFF. ............FFFF ............FFFF .............FFF } # tile 177 (zap 6 3) { .............FFF ............FFFF ............FFFF ...........FFFF. .........FFFF... ........FFFF.... ........FFFF.... .......FFFF..... .....FFFF....... ....FFFF........ ....FFFF........ ...FFFF......... .FFFF........... FFFF............ FFFF............ FFF............. } # tile 178 (zap 7 0) { .......GG....... ......GGGG...... ......GGGG...... .......GG....... .......GG....... ......GGGG...... ......GGGG...... .......GG....... .......GG....... ......GGGG...... ......GGGG...... .......GG....... .......GG....... ......GGGG...... ......GGGG...... .......GG....... } # tile 179 (zap 7 1) { ................ ................ ................ ................ ................ ................ .GG..GG..GG..GG. GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG .GG..GG..GG..GG. ................ ................ ................ ................ ................ ................ } # tile 180 (zap 7 2) { GGG............. GGGG............ GGGG............ .GGGG........... ...GGGG......... ....GGGG........ ....GGGG........ .....GGGG....... .......GGGG..... ........GGGG.... ........GGGG.... .........GGGG... ...........GGGG. ............GGGG ............GGGG .............GGG } # tile 181 (zap 7 3) { .............GGG ............GGGG ............GGGG ...........GGGG. .........GGGG... ........GGGG.... ........GGGG.... .......GGGG..... .....GGGG....... ....GGGG........ ....GGGG........ ...GGGG......... .GGGG........... GGGG............ GGGG............ GGG............. } # tile 182 (warning 0) { ................ ................ .....OOOO....... ....OOOOOO...... ...OOAAAAOO..... ...OOA...OOA.... ....AA...OOA.... ........OOAA.... .......OOAA..... ......OOAA...... ......OOA....... .......AA....... ......OO........ ......OOA....... .......AA....... ................ } # tile 183 (warning 1) { ................ ................ .....OCOC....... ....OCOCOC...... ...OCAAAAOC..... ...COA...COA.... ....AA...OCA.... ........OCAA.... .......OCAA..... ......OCAA...... ......COA....... .......AA....... ......CO........ ......OCA....... .......AA....... ................ } # tile 184 (warning 2) { ................ ................ .....CCCC....... ....CCCCCC...... ...CCAAAACC..... ...CCA...CCA.... ....AA...CCA.... ........CCAA.... .......CCAA..... ......CCAA...... ......CCA....... .......AA....... ......CC........ ......CCA....... .......AA....... ................ } # tile 185 (warning 3) { ................ ................ .....DDDD....... ....DDDDDD...... ...DDAAAADD..... ...DDA...DDA.... ....AA...DDA.... ........DDAA.... .......DDAA..... ......DDAA...... ......DDA....... .......AA....... ......DD........ ......DDA....... .......AA....... ................ } # tile 186 (warning 4) { ................ ................ .....IIII....... ....IIIIII...... ...IIAAAAII..... ...IIA...IIA.... ....AA...IIA.... ........IIAA.... .......IIAA..... ......IIAA...... ......IIA....... .......AA....... ......II........ ......IIA....... .......AA....... ................ } # tile 187 (warning 5) { ................ ................ .....IEIE....... ....IEIEIE...... ...IEAAAAIE..... ...EIA...EIA.... ....AA...IEA.... ........IEAA.... .......IEAA..... ......IEAA...... ......EIA....... .......AA....... ......EI........ ......IEA....... .......AA....... ................ } # tile 188 (sub mine walls 0) { AJJKKKACJAAJJJAA AJKKKACLJJAJJJJA AJKKACLCKJJAJJJA AAKACLCKJJJJAAAA AAACLLKKJJJJJJAA AACLLKKKAAJJJJJA ACKKKKKACJAJJJJA AKKKKKACLJJAJJJA AAKKKACLKJJJAJAA AAKKACLKKJJJJJAA AACCCKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AAKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 189 (sub mine walls 1) { AJAAAAAAJJAAAJAA JJJAAAJJJJJAAAAJ JJJACJAJJJACCJAJ AAACLJJAJACCLJJA AACLCKJJACCLCKJJ ACKCKKJJJCKCKKJA CJKKKKJJCKCKJJAC KJJKCJJCKKKJJJCK KJKKKJJKJKJJJJKK JJJKCJKKJKJJJCKJ JJJJJJKJKKJJJKKJ JJJJJKJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 190 (sub mine walls 2) { AAAAAAKCCKKJAAAA AAAAKKCLCJKJJAAA AAKKKCLCKJJJKKAA AKKKCLCKJJJJJJKA AKKCLLKKJJJJJJJA AKCLLKKKAAJJJJJJ ACKKKKKACJAJJJJJ AKKKKKACLJJAAJJJ AAKKKCLLKJJJAJAJ AAKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AAKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 191 (sub mine walls 3) { AAAAAAKCCKKJAAAA AAAAKKCLCJKJJAAA AAKKKCLCKJJJKKAA AKKCCLCKJJJJJJKA KKCCLLKKJJJJJJJA KKCLKKKKAAJJJJJA KCLKKKKACJAJJJJA CKKKKKACLJJAAJJA KAKKKCLLKJJJAJAA AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 192 (sub mine walls 4) { AKKKAAKKKKAAJJJA AKKAAKCCCJJJAAJA AKKAALLJJJACCJAA AKAACLJJJACCLJJA AAACCKJJACLLCKJJ AAACLKJJJCKCKKJA AACLKKJJCKCKJJAC AAKKCJJCKKKJJJCK ACKKKJJKJKJJJJKK ACKKCJKKJKJJJCKJ AKKKJJKJKKJJJKKJ ACKJJKJJJJJJJJJJ AKJJJJJJJJJJJJJJ AKJJJJJJJJJJJJJJ AJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 193 (sub mine walls 5) { AKKAAAKKAAAAJJJA AKAAKKLCKAAAAAJA AAKKCLCJJACCAJJA AKKCLJJJACCCLAJA AKCKKKJACCCLCAAA ACKKKKJACCKCKKAA CJKKKKACCKCKJJAA KJJKCJJCKKKJJJAA KJKKKJJKJKJJJJJA JJJKCJKKJKJJJJJA JJJJJJKJKKJJJJJA JJJJJKJJJJJJJJJA JJJJJJJJJJJJJJJA JJJJJJJJJJJJJJJA JJJJJJJJJJJJJJJA AAAAAAAAAAAAAAAA } # tile 194 (sub mine walls 6) { AAAAAAKCCKKJAAAA AAAAKCCLCJKJJAAA AAKKCCLCKJJJKKAA AKKKCLCKJJJJJJKA KKKCLKKKJJJJJJJA KKCLKKKKAAJJJJJJ KCKLKKKACJAJJJJJ CKKKKKACLJJAAJJJ KAKKKCLLKJJJAJAJ AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 195 (sub mine walls 7) { AKKAAAKKKKAAJJJA AKAAKKLCCJJJAAJA AAKKCLCJJJACCJAA AKKCLJJJJACCLJJA AKCLCKJJACCLCKJJ ACKCKKJJJCKCKKJA CJKKKKJJCKCKJJAC KJJKCJJCKKKJJJCK KJKKKJJKJKJJJJKK JJJKCJKKJKJJJCKJ JJJJJJKJKKJJJKKJ JJJJJKJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 196 (sub mine walls 8) { AAAAAAKCCKKJAAAA AAAAKCCLCJKJJAAA AAKKKCLCKJJJKKAA AKKKCLCKJJJJJJKA KKCCLLKKJJJJJJJA KKCLLKKKAAJJJJJJ KCLLKKKACJAJJJJJ CKLKKKACLJJAAJJJ KAKKKCLLKJJJAJAJ AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 197 (sub mine walls 9) { AKKAACKCCKKJAJJA AKACKKKLLJKJJAJA AAKKKCCCKJJJKKAA AKKKCCLKJJJJJJKA AKKCLLKKJJJJJJJA AKCLLKKKAAJJJJJJ ACLKKKKACJAJJJJJ AKKKKKACLJJAAJJJ AAKKKCLLKJJJAJAJ AAKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AAKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 198 (sub mine walls 10) { AKKAACKCCKKJAJJA AKACKKCLCJKJJAJA AAKKCCLCKJJJKKAA AKKCLLCKJJJJJJKA KKCCLLKKJJJJJJJA KCKLLKKKAAJJJJJA CCKKKKKACJAJJJJA CKKKKKACLJJAAJJA KAKKKCLLKJJJAJAA AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 199 (sub gehennom walls 0) { ALLDAJ11111JLLDA ADDDAJ1J11JJDDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA ADDDAJJ1111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ11J1JD1JA ALLDAJ11111JLLDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA ADDDAJJ1J1JJDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 200 (sub gehennom walls 1) { AAALDDAAAAALDDAA DDDLDDAJDDDLDDAJ 1DDJJJAJ1DDJJJAJ JJJJJJJJJJJJJJJJ 11JJJ11111JJJ111 11LDD11111LDD111 DDLDDAJDDDLDDAJD DDJJJAJ1DDJJJAJ1 JJJJJJJJJJJJJJJJ 11JD1111JD111JD1 11J11111J1111J11 JJJJJJJJJJJJJJJJ JD1111JD1111JD11 J11111J11111J111 JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 201 (sub gehennom walls 2) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ A11JJJJJJJJJ111J ADDDAAAAAAAADDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 202 (sub gehennom walls 3) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ A11JJJJJJJJJ111J ADDDAAAAAAAADDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 203 (sub gehennom walls 4) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ 11JD1111JD111JD1 11J11111J1111J11 JJJJJJJJJJJJJJJJ JD1111JD1111JD11 J11111J11111J111 JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 204 (sub gehennom walls 5) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ 11JD1111JD111JD1 11J11111J1111J11 JJJJJJJJJJJJJJJJ JD1111JD1111JD11 J11111J11111J111 JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 205 (sub gehennom walls 6) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ A11JJJJJJJJJ111J ADDDAAAAAAAADDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 206 (sub gehennom walls 7) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ 11JD1111JD111JD1 11J11111J1111J11 JJJJJJJJJJJJJJJJ JD1111JD1111JD11 J11111J11111J111 JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 207 (sub gehennom walls 8) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ A11JJJJJJJJJ111J ADDDAAAAAAAADDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 208 (sub gehennom walls 9) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ A11JJJJJJJJJ111J ADDDAAAAAAAADDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 209 (sub gehennom walls 10) { AAALLLLDDDDDDAAA LLLLAAJJ1111DJJJ DDDLAJJ111CCDJJJ DDDDDDDDDDDDDJJJ DDD1111111111JJJ DDD1111111111JJJ DD111111111111JJ D11111111111111J JJJJJJJJJJJJJJJJ A11JJJJJJJJJ111J ADDDAAAAAAAADDDA ADDDAJ11111JDDDA ADDDAJ11111JDDDA AJAAAJJ1111JJAJA AJJJAJJ1111JJJJA AD11AJJ1111JD1JA } # tile 210 (sub knox walls 0) { AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AJJJACLCKJJAJJJA AAAAALCKJJJAAAAA AAJAAAKKJJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 211 (sub knox walls 1) { AJAAAJAAAJAAAJAA JJJAAAJAJJJAAAJA JJJACJAAJJJACJAA AAACLJJAJJACLJJA AACLCKJJAACLCKJJ AAACKKJAAAACKKJA AJAAAJAAAJAAAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 212 (sub knox walls 2) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 213 (sub knox walls 3) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 214 (sub knox walls 4) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AACCCAKJJAJJJAKA AJACAJAJAJAJAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 215 (sub knox walls 5) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AACCCAKJJAJJJAKA AJACAJAJAJAJAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 216 (sub knox walls 6) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 217 (sub knox walls 7) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AACCCAKJJAJJJAKA AJACAJAJAJAJAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 218 (sub knox walls 8) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 219 (sub knox walls 9) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 220 (sub knox walls 10) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 221 (sub sokoban walls 0) { ANNBA1EEEEE1NNBA ABBBA1E1EE11BBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA ABBBA11EEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EE1E1BE1A ANNBA1EEEEE1NNBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA ABBBA11E1E11BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } # tile 222 (sub sokoban walls 1) { AAANBBAAAAANBBAA BBBNBBA1BBBNBBA1 EBB111A1EBB111A1 1111111111111111 EE111EEEEE111EEE EENBBEEEEENBBEEE BBNBBA1BBBNBBA1B BB111A1EBB111A1E 1111111111111111 EE1BEEEE1BEEE1BE EE1EEEEE1EEEE1EE 1111111111111111 1BEEEE1BEEEE1BEE 1EEEEE1EEEEE1EEE 1111111111111111 AAAAAAAAAAAAAAAA } # tile 223 (sub sokoban walls 2) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 AEE111111111EEE1 ABBBAAAAAAAABBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } # tile 224 (sub sokoban walls 3) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 AEE111111111EEE1 ABBBAAAAAAAABBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } # tile 225 (sub sokoban walls 4) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 EE1BEEEE1BEEE1BE EE1EEEEE1EEEE1EE 1111111111111111 1BEEEE1BEEEE1BEE 1EEEEE1EEEEE1EEE 1111111111111111 AAAAAAAAAAAAAAAA } # tile 226 (sub sokoban walls 5) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 EE1BEEEE1BEEE1BE EE1EEEEE1EEEE1EE 1111111111111111 1BEEEE1BEEEE1BEE 1EEEEE1EEEEE1EEE 1111111111111111 AAAAAAAAAAAAAAAA } # tile 227 (sub sokoban walls 6) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 AEE111111111EEE1 ABBBAAAAAAAABBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } # tile 228 (sub sokoban walls 7) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 EE1BEEEE1BEEE1BE EE1EEEEE1EEEE1EE 1111111111111111 1BEEEE1BEEEE1BEE 1EEEEE1EEEEE1EEE 1111111111111111 AAAAAAAAAAAAAAAA } # tile 229 (sub sokoban walls 8) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 AEE111111111EEE1 ABBBAAAAAAAABBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } # tile 230 (sub sokoban walls 9) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 AEE111111111EEE1 ABBBAAAAAAAABBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } # tile 231 (sub sokoban walls 10) { AAANNNNBBBBBBAAA NNNNAA11EEEEB111 BBBNA11EEENNB111 BBBBBBBBBBBBB111 BBBEEEEEEEEEE111 BBBEEEEEEEEEE111 BBEEEEEEEEEEEE11 BEEEEEEEEEEEEEE1 1111111111111111 AEE111111111EEE1 ABBBAAAAAAAABBBA ABBBA1EEEEE1BBBA ABBBA1EEEEE1BBBA A1AAA11EEEE11A1A A111A11EEEE1111A ABEEA11EEEE1BE1A } nethack-3.6.0/win/share/ppmwrite.c0000664000076400007660000000751512536476415016074 0ustar paxedpaxed/* NetHack 3.6 ppmwrite.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ /* this produces a raw ppm file, with a 15-character header of * "P6 3-digit-width 3-digit-height 255\n" */ #include "config.h" #include "tile.h" #ifndef MONITOR_HEAP extern long *FDECL(alloc, (unsigned int)); #endif FILE *ppm_file; struct ppmscreen { int Width; int Height; } PpmScreen; static int tiles_across, tiles_down, curr_tiles_across; static pixel **image; static void NDECL(write_header); static void NDECL(WriteTileStrip); static void write_header() { (void) fprintf(ppm_file, "P6 %03d %03d 255\n", PpmScreen.Width, PpmScreen.Height); } static void WriteTileStrip() { int i, j; for (j = 0; j < TILE_Y; j++) { for (i = 0; i < PpmScreen.Width; i++) { (void) fputc((char) image[j][i].r, ppm_file); (void) fputc((char) image[j][i].g, ppm_file); (void) fputc((char) image[j][i].b, ppm_file); } } } boolean fopen_ppm_file(filename, type) const char *filename; const char *type; { int i; if (strcmp(type, WRBMODE)) { Fprintf(stderr, "using writing routine for non-writing?\n"); return FALSE; } ppm_file = fopen(filename, type); if (ppm_file == (FILE *) 0) { Fprintf(stderr, "cannot open ppm file %s\n", filename); return FALSE; } if (!colorsinmainmap) { Fprintf(stderr, "no colormap set yet\n"); return FALSE; } tiles_across = 20; curr_tiles_across = 0; PpmScreen.Width = 20 * TILE_X; tiles_down = 0; PpmScreen.Height = 0; /* will be rewritten later */ write_header(); image = (pixel **) alloc(TILE_Y * sizeof(pixel *)); for (i = 0; i < TILE_Y; i++) { image[i] = (pixel *) alloc(PpmScreen.Width * sizeof(pixel)); } return TRUE; } boolean write_ppm_tile(pixels) pixel (*pixels)[TILE_X]; { int i, j; for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { image[j][curr_tiles_across * TILE_X + i] = pixels[j][i]; } } curr_tiles_across++; if (curr_tiles_across == tiles_across) { WriteTileStrip(); curr_tiles_across = 0; tiles_down++; } return TRUE; } int fclose_ppm_file() { int i, j; if (curr_tiles_across) { /* partial row */ /* fill with checkerboard, for lack of a better idea */ for (j = 0; j < TILE_Y; j++) { for (i = curr_tiles_across * TILE_X; i < PpmScreen.Width; i += 2) { image[j][i].r = MainColorMap[CM_RED][0]; image[j][i].g = MainColorMap[CM_GREEN][0]; image[j][i].b = MainColorMap[CM_BLUE][0]; image[j][i + 1].r = MainColorMap[CM_RED][1]; image[j][i + 1].g = MainColorMap[CM_GREEN][1]; image[j][i + 1].b = MainColorMap[CM_BLUE][1]; } } WriteTileStrip(); curr_tiles_across = 0; tiles_down++; } for (i = 0; i < TILE_Y; i++) { free((genericptr_t) image[i]); } free((genericptr_t) image); PpmScreen.Height = tiles_down * TILE_Y; rewind(ppm_file); write_header(); /* update size */ return (fclose(ppm_file)); } int main(argc, argv) int argc; char *argv[]; { pixel pixels[TILE_Y][TILE_X]; if (argc != 3) { Fprintf(stderr, "usage: txt2ppm txtfile ppmfile\n"); exit(EXIT_FAILURE); } if (!fopen_text_file(argv[1], RDTMODE)) exit(EXIT_FAILURE); init_colormap(); if (!fopen_ppm_file(argv[2], WRBMODE)) { (void) fclose_text_file(); exit(EXIT_FAILURE); } while (read_text_tile(pixels)) (void) write_ppm_tile(pixels); (void) fclose_text_file(); (void) fclose_ppm_file(); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } nethack-3.6.0/win/share/renumtiles.pl0000664000076400007660000000341512536476415016600 0ustar paxedpaxed#!/bin/perl # # $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # sub bail($); use Getopt::Std; # TODO: switch to Getopt::Long so we can parse normal arguments too $Getopt::Std::STANDARD_HELP_VERSION = TRUE; $main::VERSION = 1.0; my %commands = ( 'd' => 'debug mode; parse objects.txt to stdout instead of updating', ); getopts(join('', keys(%commands))); my $debug = (defined($opt_d) && $opt_d == 1); my $tilecount = 0; my $outfile = $debug ? "-" : "objects.txt"; my $infile = $debug ? "objects.txt" : "objects.bak"; unless ($debug) { if (-e "$infile") { die "something didn't clean up objects.bak from last time; stopping\n"; } rename($outfile,$infile) or die "couldn't move objects.txt to objects.bak; stopping\n"; } open(INFILE, "<$infile") or bail("couldn't open $infile; bailing"); open(OUTFILE, ">$outfile") or bail("couldn't open $outfile; bailing"); while (my $line = ) { if (my ($tiletext) = $line =~ /^# tile \d+ (.*)/) { $line = "# tile $tilecount $tiletext\n"; $tilecount++; } print OUTFILE $line; } close(INFILE); close(OUTFILE); unless ($debug) { unlink $infile; } exit; sub main::HELP_MESSAGE() { print <<"STARTHELP"; Usage: renumtiles.pl [OPTIONS] STARTHELP foreach $cmd (keys(%commands)) { printf("%10s %s\n", '-'.$cmd, $commands{$cmd}); } print <<"ENDHELP"; \t--help display this help message and exit \t--version display version and exit ENDHELP exit; } sub main::VERSION_MESSAGE() { my ($objglob, $optpackage, $ver, $switches) = @_; print <<"STARTHELP"; renumtiles $ver -- tile-renumbering utility for NetHack STARTHELP } sub bail($) { unless ($debug) { unlink $outfile; rename ($infile,$outfile); } shift; die "$_\n"; } nethack-3.6.0/win/share/thintile.c0000664000076400007660000000622212536476415016037 0ustar paxedpaxed/* NetHack 3.6 thintile.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) NetHack Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* Create a set of overview tiles by eliminating even pixels in original */ #include "config.h" #include "tile.h" #ifdef __GO32__ #include #endif static char pixels[TILE_Y][TILE_X]; static char *tilefiles[] = { "../win/share/monsters.txt", "../win/share/objects.txt", "../win/share/other.txt" }; static char *thinfiles[] = { "../win/share/monthin.txt", "../win/share/objthin.txt", "../win/share/oththin.txt" }; static FILE *infile, *outfile; static int tilecount; static int tilecount_per_file; static int filenum; static char comment[BUFSZ]; static void copy_colormap() { int r, g, b; char c[2]; while (fscanf(infile, "%[A-Za-z0-9] = (%d, %d, %d) ", c, &r, &g, &b) == 4) { Fprintf(outfile, "%c = (%d, %d, %d)\n", c[0], r, g, b); } } static boolean read_txttile() { int i, j; char buf[BUFSZ]; char buf2[BUFSZ]; char c[2]; if (fscanf(infile, "# %s %d (%[^)])", buf2, &i, buf) <= 0) return FALSE; Sprintf(comment, "# tile %d (%s)", i, buf); /* look for non-whitespace at each stage */ if (fscanf(infile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '{') { Fprintf(stderr, "didn't find expected '{'\n"); return FALSE; } for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { if (fscanf(infile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } pixels[j][i] = c[0]; } } if (fscanf(infile, "%1s ", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '}') { Fprintf(stderr, "didn't find expected '}'\n"); return FALSE; } return TRUE; } static void write_thintile() { int i, j; Fprintf(outfile, "%s\n", comment); Fprintf(outfile, "{\n"); for (j = 0; j < TILE_Y; j++) { Fprintf(outfile, " "); for (i = 0; i < TILE_X; i += 2) { (void) fputc(pixels[j][i], outfile); } Fprintf(outfile, "\n"); } Fprintf(outfile, "}\n"); } int main(argc, argv) int argc; char *argv[]; { while (filenum < 3) { tilecount_per_file = 0; infile = fopen(tilefiles[filenum], RDTMODE); outfile = fopen(thinfiles[filenum], WRTMODE); copy_colormap(); while (read_txttile()) { write_thintile(); tilecount_per_file++; tilecount++; } fclose(outfile); fclose(infile); printf("%d tiles processed from %s\n", tilecount_per_file, tilefiles[filenum]); ++filenum; } printf("Grand total of %d tiles processed.\n", tilecount); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } /*thintile.c*/ nethack-3.6.0/win/share/tile.doc0000664000076400007660000001304512536476415015500 0ustar paxedpaxedNetHack 3.6 tile.doc $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ Window ports can optionally make use of the tiles (pictures for NetHack symbols) found in this directory. They are distributed in a text format with routines to help in converting them to a system's preferred format and using them there. The original tiles were provided by Warwick Allison. The tile distribution format for monsters.txt, objects.txt, and other.txt starts with a palette header like: A = (0, 0, 0) ... P = (254, 254, 254) and then each tile has an entry like: # tile 292 (comment identifying tile) { AAAAGHPAAAAACDAA AAAFGDEMLOCNAAAA ... } Each port can convert these .txt files to whatever format it wants the game executable to use, probably providing only one merged output file. See the tilemap.c discussion at the bottom for more hints on adding tiles. Shared code provided for conversion utilities: tile.h contains shared declarations. tiletext.c defines the external variables from tile.h and supplies the external routines for reading and writing the defined text format. Each conversion utility is expected to use tiletext.c and provide code of its own for reading and/or writing another format. The important global variables implement a colormap shared between tiletext.c and the other half of utilities. As an example of conversion utilities, we provide txt2ppm (tiletext.c + ppmwrite.c) and gif2txt (tiletext.c + gifread.c). (Sorry, we're not paying Unisys patent royalties for the right to provide you with a gifwrite.c, which would necessarily use the LZW compression algorithm they claim.) The text I/O routines are: boolean fopen_text_file(const char *filename, const char *type); select file for subsequent tile I/O "type" a la fopen returns FALSE if file not opened, otherwise reads/writes header (including colormap) and sets up to decode/encode tiles int fclose_text_file(); close file boolean read_text_tile(pixel[TILE_Y][TILE_X]); returns FALSE if no next tile in current file otherwise TRUE and insert the tile in the provided array boolean write_text_tile(pixel[TILE_Y][TILE_X]); writes tile There are two additional shared routines provided for writers: void init_colormap(); initialize the output colormap from the input one must be called before opening output file as colormap is part of header void merge_colormap(); merge the current input colormap into the output one Due to the amount of state being kept, only one text or gif file can be open at a time. If you are combining multiple files into one other-format file with a single common colormap, you may need to open each source file and merge their colormaps into a common colormap before processing any tiles. Although there are expected to be only 16 colors in the distribution tiles, conversion programs should be prepared to accept up to MAXCOLORMAPSIZE colors and map them to a smaller number if their port requires it. Expected sequence for editing tiles: edit foo.txt -or- run txt2ppm foo.txt foo.ppm convert ppm to gif, either via ppmtogif from pbmplus/netpbm or stripping the first 15 bytes of foo.ppm (containing the size of the image) and feeding the rest to any raw-24bit- image-reading program edit tiles with gif-editing program run gif2txt foo.gif foo.txt When converted to ppm, monsters.ppm, objects.ppm, and other.ppm are: each a single ppm format (rgb triples with header) 20 tiles across, however many down (need "blank" tile to fill in extras on last row -- currently alternating pixels in first and second colors) allows looking at tiles en masse for comparison or whatever The gif reading routines accept further variations so long as the gif is n*TILE_X pixels across. The gif I/O routines are: boolean fopen_gif_file(const char *filename, const char *type); select file for subsequent tile I/O "type" a la fopen returns FALSE if file not opened, otherwise reads gif header (including colormap) and sets up to decode tiles int fclose_gif_file(); tear down decode mechanism close file boolean read_gif_tile(pixel[TILE_Y][TILE_X]); returns FALSE if no next tile in current file (including when any remaining tiles are "blank"), otherwise TRUE and insert the tile in the provided array Array provided by shared code for NetHack use, by compiling and running tilemap.c to form tile.c: short glyph2tile[MAXGLYPH]; maps glyph number to tile number for display purposes, assuming (non-blank) tiles are numbered sequentially through monsters/objects/other tilemap.c (shudder) accounts for things disappearing due to compilation options -- there should be a tile for everything appearing under any supported option, but under some options some tiles won't be referenced. Therefore, tilemap.c has the knowledge to provide the comments for gif2txt and is compiled with GIF2TXT to link in there, along with the various strings for things that are compiled in (monst.o etc.). If you add monsters/objects/other things to NetHack and need to add tiles to go with them, just add an entry in the right place in the appropriate .txt file, and one to tilemap.c if the new item is conditionally compiled. While the "comment identifying tile" in the .txt file must be correct, the number of the tile need not be, and can just be a duplicate of the tile on either side (or any other integer, for that matter). In an official release, the tiles in a .txt file will be numbered consecutively so that you may cross-reference with a graphics format, but the conversion code does not care about the numbering. (In fact, running txt2ppm, ppmtogif, and gif2txt gives you a consecutively numbered version of the .txt file.) nethack-3.6.0/win/share/tile.h0000664000076400007660000000212612536476415015160 0ustar paxedpaxed/* NetHack 3.6 tile.h $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ typedef unsigned char pixval; typedef struct pixel_s { pixval r, g, b; } pixel; #define MAXCOLORMAPSIZE 256 #define CM_RED 0 #define CM_GREEN 1 #define CM_BLUE 2 /* shared between reader and writer */ extern pixval ColorMap[3][MAXCOLORMAPSIZE]; extern int colorsinmap; /* writer's accumulated colormap */ extern pixval MainColorMap[3][MAXCOLORMAPSIZE]; extern int colorsinmainmap; #include "dlb.h" /* for MODEs */ /* size of tiles */ #ifndef TILE_X #define TILE_X 16 #endif #ifndef TILE_Y #define TILE_Y 16 #endif #define Fprintf (void) fprintf extern boolean FDECL(fopen_text_file, (const char *, const char *)); extern boolean FDECL(read_text_tile, (pixel(*) [TILE_X])); extern boolean FDECL(write_text_tile, (pixel(*) [TILE_X])); extern int NDECL(fclose_text_file); extern void NDECL(init_colormap); extern void NDECL(merge_colormap); #if defined(MICRO) || defined(WIN32) #undef exit #if !defined(MSDOS) && !defined(WIN32) extern void FDECL(exit, (int)); #endif #endif nethack-3.6.0/win/share/tile2bmp.c0000664000076400007660000002174712536476415015746 0ustar paxedpaxed/* NetHack 3.6 tile2bmp.c $NHDT-Date: 1431192770 2015/05/09 17:32:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 1994/01/11 * 256 colour bmp and statue support M.Allison 2015/04/19 * */ /* #pragma warning(4103:disable) */ #include "hack.h" #include "tile.h" #ifndef __GNUC__ #include "win32api.h" #endif #if (TILE_X == 32) #define COLORS_IN_USE 256 #else /*#define COLORS_IN_USE 16 */ /* 16 colors */ #define COLORS_IN_USE 256 /* 256 colors */ #endif #define BITCOUNT 8 extern char *FDECL(tilename, (int, int)); #define MAGICTILENO (340 + 440 + 231 + 340) #if BITCOUNT == 4 #define MAX_X 320 /* 2 per byte, 4 bits per pixel */ #define MAX_Y 480 #else #if (TILE_X == 32) #define MAX_X (32 * 40) #define MAX_Y ((MAGICTILENO * 32) / 40) * 2 #else #define MAX_X (16 * 40) #define MAX_Y ((MAGICTILENO * 16) / 40) * 2 #endif #endif /* GCC fix by Paolo Bonzini 1999/03/28 */ #ifdef __GNUC__ #define PACK __attribute__((packed)) #else #define PACK #endif static short leshort(short x) { #ifdef __BIG_ENDIAN__ return ((x & 0xff) << 8) | ((x >> 8) & 0xff); #else return x; #endif } static long lelong(long x) { #ifdef __BIG_ENDIAN__ return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff); #else return x; #endif } #ifdef __GNUC__ typedef struct tagBMIH { unsigned long biSize; long biWidth; long biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long biCompression; unsigned long biSizeImage; long biXPelsPerMeter; long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; } PACK BITMAPINFOHEADER; typedef struct tagBMFH { unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; } PACK BITMAPFILEHEADER; typedef struct tagRGBQ { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } PACK RGBQUAD; #define UINT unsigned int #define DWORD unsigned long #define LONG long #define WORD unsigned short #define BI_RGB 0L #define BI_RLE8 1L #define BI_RLE4 2L #define BI_BITFIELDS 3L #endif /* __GNUC__ */ #pragma pack(1) struct tagBMP { BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; #if BITCOUNT == 4 #define RGBQUAD_COUNT 16 RGBQUAD bmaColors[RGBQUAD_COUNT]; #else #if (TILE_X == 32) #define RGBQUAD_COUNT 256 #else /*#define RGBQUAD_COUNT 16 */ #define RGBQUAD_COUNT 256 #endif RGBQUAD bmaColors[RGBQUAD_COUNT]; #endif #if (COLORS_IN_USE == 16) uchar packtile[MAX_Y][MAX_X]; #else uchar packtile[MAX_Y][MAX_X]; /* uchar packtile[TILE_Y][TILE_X]; */ #endif } PACK bmp; #pragma pack() #define BMPFILESIZE (sizeof(struct tagBMP)) FILE *tibfile2; pixel tilepixels[TILE_Y][TILE_X]; static void FDECL(build_bmfh, (BITMAPFILEHEADER *)); static void FDECL(build_bmih, (BITMAPINFOHEADER *)); static void FDECL(build_bmptile, (pixel(*) [TILE_X])); char *tilefiles[] = { #if (TILE_X == 32) "../win/share/mon32.txt", "../win/share/obj32.txt", "../win/share/oth32.txt", #else "../win/share/monsters.txt", "../win/share/objects.txt", "../win/share/other.txt", #endif }; int num_colors = 0; int tilecount; int max_tiles_in_row = 40; int tiles_in_row; int filenum; int initflag; int pass; int yoffset, xoffset; char bmpname[128]; FILE *fp; int main(argc, argv) int argc; char *argv[]; { int i, j; if (argc != 2) { Fprintf(stderr, "usage: %s outfile.bmp\n", argv[0]); exit(EXIT_FAILURE); } else strcpy(bmpname, argv[1]); #ifdef OBSOLETE bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); if (bmpfile2 == (FILE *) 0) { Fprintf(stderr, "Unable to open output file %s\n", NETHACK_PACKED_TILEFILE); exit(EXIT_FAILURE); } #endif tilecount = 0; xoffset = yoffset = 0; initflag = 0; filenum = 0; pass = 0; fp = fopen(bmpname, "wb"); if (!fp) { printf("Error creating tile file %s, aborting.\n", bmpname); exit(1); } while (pass < 4) { filenum = pass % (sizeof(tilefiles) / sizeof(char *)); if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { Fprintf(stderr, "usage: tile2bmp (from the util directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); exit(EXIT_FAILURE); } if (!initflag) { build_bmfh(&bmp.bmfh); build_bmih(&bmp.bmih); for (i = 0; i < MAX_Y; ++i) for (j = 0; j < MAX_X; ++j) bmp.packtile[i][j] = (uchar) 0; for (i = 0; i < num_colors; i++) { bmp.bmaColors[i].rgbRed = ColorMap[CM_RED][i]; bmp.bmaColors[i].rgbGreen = ColorMap[CM_GREEN][i]; bmp.bmaColors[i].rgbBlue = ColorMap[CM_BLUE][i]; bmp.bmaColors[i].rgbReserved = 0; } initflag = 1; } /* printf("Colormap initialized\n"); */ while (read_text_tile(tilepixels)) { build_bmptile(tilepixels); tilecount++; #if BITCOUNT == 4 xoffset += (TILE_X / 2); #else xoffset += TILE_X; #endif if (xoffset >= MAX_X) { yoffset += TILE_Y; xoffset = 0; } } (void) fclose_text_file(); ++pass; } fwrite(&bmp, sizeof(bmp), 1, fp); fclose(fp); Fprintf(stderr, "Total of %d tiles written to %s.\n", tilecount, bmpname); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static void build_bmfh(pbmfh) BITMAPFILEHEADER *pbmfh; { pbmfh->bfType = leshort(0x4D42); pbmfh->bfSize = lelong(BMPFILESIZE); pbmfh->bfReserved1 = (UINT) 0; pbmfh->bfReserved2 = (UINT) 0; pbmfh->bfOffBits = lelong(sizeof(bmp.bmfh) + sizeof(bmp.bmih) + (RGBQUAD_COUNT * sizeof(RGBQUAD))); } static void build_bmih(pbmih) BITMAPINFOHEADER *pbmih; { WORD cClrBits; int w, h; pbmih->biSize = lelong(sizeof(bmp.bmih)); #if BITCOUNT == 4 pbmih->biWidth = lelong(w = MAX_X * 2); #else pbmih->biWidth = lelong(w = MAX_X); #endif pbmih->biHeight = lelong(h = MAX_Y); pbmih->biPlanes = leshort(1); #if BITCOUNT == 4 pbmih->biBitCount = leshort(4); cClrBits = 4; #else pbmih->biBitCount = leshort(8); cClrBits = 8; #endif if (cClrBits == 1) cClrBits = 1; else if (cClrBits <= 4) cClrBits = 4; else if (cClrBits <= 8) cClrBits = 8; else if (cClrBits <= 16) cClrBits = 16; else if (cClrBits <= 24) cClrBits = 24; else cClrBits = 32; pbmih->biCompression = lelong(BI_RGB); pbmih->biXPelsPerMeter = lelong(0); pbmih->biYPelsPerMeter = lelong(0); #if (TILE_X == 32) if (cClrBits < 24) pbmih->biClrUsed = lelong(1 << cClrBits); #else pbmih->biClrUsed = lelong(RGBQUAD_COUNT); #endif #if (TILE_X == 16) /* pbmih->biSizeImage = lelong(0); */ pbmih->biSizeImage = lelong(((w * cClrBits + 31) & ~31) / 8 * h); #else pbmih->biSizeImage = lelong(((w * cClrBits + 31) & ~31) / 8 * h); #endif pbmih->biClrImportant = (DWORD) 0; } static int graymappings[] = { /* . A B C D E F G H I J K L M N O P */ 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14 }; static void build_bmptile(pixels) pixel (*pixels)[TILE_X]; { int cur_x, cur_y, cur_color, apply_color; int x, y; for (cur_y = 0; cur_y < TILE_Y; cur_y++) { for (cur_x = 0; cur_x < TILE_X; cur_x++) { for (cur_color = 0; cur_color < num_colors; cur_color++) { if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r && ColorMap[CM_GREEN][cur_color] == pixels[cur_y][cur_x].g && ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b) break; } if (cur_color >= num_colors) Fprintf(stderr, "color not in colormap!\n"); y = (MAX_Y - 1) - (cur_y + yoffset); apply_color = cur_color; if (pass == 3) { /* map to shades of gray */ if (cur_color > (SIZE(graymappings) - 1)) Fprintf(stderr, "Gray mapping issue %d %d.\n", cur_color, SIZE(graymappings) - 1); else apply_color = graymappings[cur_color]; } #if BITCOUNT == 4 x = (cur_x / 2) + xoffset; bmp.packtile[y][x] = cur_x % 2 ? (uchar)(bmp.packtile[y][x] | cur_color) : (uchar)(cur_color << 4); #else x = cur_x + xoffset; bmp.packtile[y][x] = (uchar) apply_color; #endif } } } nethack-3.6.0/win/share/tilemap.c0000664000076400007660000003701612621027147015644 0ustar paxedpaxed/* NetHack 3.6 tilemap.c $NHDT-Date: 1447306925 2015/11/12 05:42:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* NetHack may be freely redistributed. See license for details. */ /* * This source file is compiled twice: * once without TILETEXT defined to make tilemap.{o,obj}, * then again with it defined to produce tiletxt.{o,obj}. */ #include "hack.h" const char *FDECL(tilename, (int, int)); void NDECL(init_tilemap); void FDECL(process_substitutions, (FILE *)); #if defined(MICRO) || defined(WIN32) #undef exit #if !defined(MSDOS) && !defined(WIN32) extern void FDECL(exit, (int)); #endif #endif #if defined(WIN32) #define STATUES_LOOK_LIKE_MONSTERS #endif #define MON_GLYPH 1 #define OBJ_GLYPH 2 #define OTH_GLYPH 3 /* fortunately unnecessary */ #define EXTRA_SCROLL_DESCR_COUNT ((SCR_BLANK_PAPER - SCR_STINKING_CLOUD) - 1) /* note that the ifdefs here should be the opposite sense from monst.c/ * objects.c/rm.h */ struct conditionals { int sequence, predecessor; const char *name; } conditionals[] = { #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_HELL_HOUND, "Cerberus" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_SHOCKING_SPHERE, "beholder" }, { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" }, { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" }, { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" }, { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" }, #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_CROESUS, "Charon" }, #endif #ifndef MAIL { MON_GLYPH, PM_FAMINE, "mail daemon" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_SHAMAN_KARNOV, "Earendil" }, { MON_GLYPH, PM_SHAMAN_KARNOV, "Elwing" }, /* commented out in monst.c at present */ { MON_GLYPH, PM_CHROMATIC_DRAGON, "Goblin King" }, { MON_GLYPH, PM_NEANDERTHAL, "High-elf" }, /* objects commented out in objects.c at present */ { OBJ_GLYPH, SILVER_DRAGON_SCALE_MAIL, "shimmering dragon scale mail" }, { OBJ_GLYPH, SILVER_DRAGON_SCALES, "shimmering dragon scales" }, /* allow slime mold to look like slice of pizza, since we * don't know what a slime mold should look like when renamed anyway */ #ifndef MAIL { OBJ_GLYPH, SCR_STINKING_CLOUD + EXTRA_SCROLL_DESCR_COUNT, "stamped / mail" }, #endif { 0, 0, 0 } }; /* * Some entries in glyph2tile[] should be substituted for on various levels. * The tiles used for the substitute entries will follow the usual ones in * other.til in the order given here, which should have every substitution * for the same set of tiles grouped together. You will have to change * more code in process_substitutions()/substitute_tiles() if the sets * overlap in the future. */ struct substitute { int first_glyph, last_glyph; const char *sub_name; /* for explanations */ const char *level_test; } substitutes[] = { { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "mine walls", "In_mines(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "gehennom walls", "In_hell(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "knox walls", "Is_knox(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "sokoban walls", "In_sokoban(plev)" } }; #ifdef TILETEXT /* * entry is the position of the tile within the monsters/objects/other set */ const char * tilename(set, entry) int set, entry; { int i, j, condnum, tilenum; static char buf[BUFSZ]; /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); (void) def_char_to_objclass(']'); condnum = tilenum = 0; for (i = 0; i < NUMMONS; i++) { if (set == MON_GLYPH && tilenum == entry) return mons[i].mname; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { if (set == MON_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } if (set == MON_GLYPH && tilenum == entry) return "invisible monster"; tilenum = 0; /* set-relative number */ for (i = 0; i < NUM_OBJECTS; i++) { /* prefer to give the description - that's all the tile's * appearance should reveal */ if (set == OBJ_GLYPH && tilenum == entry) { if (!obj_descr[i].oc_descr) return obj_descr[i].oc_name; if (!obj_descr[i].oc_name) return obj_descr[i].oc_descr; Sprintf(buf, "%s / %s", obj_descr[i].oc_descr, obj_descr[i].oc_name); return buf; } tilenum++; while (conditionals[condnum].sequence == OBJ_GLYPH && conditionals[condnum].predecessor == i) { if (set == OBJ_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } tilenum = 0; /* set-relative number */ for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { if (set == OTH_GLYPH && tilenum == entry) { if (*defsyms[i].explanation) { return defsyms[i].explanation; } else { Sprintf(buf, "cmap %d", tilenum); return buf; } } tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == i) { if (set == OTH_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } /* explosions */ tilenum = MAXPCHARS - MAXEXPCHARS; i = entry - tilenum; if (i < (MAXEXPCHARS * EXPL_MAX)) { if (set == OTH_GLYPH) { static const char *explosion_types[] = { /* hack.h */ "dark", "noxious", "muddy", "wet", "magical", "fiery", "frosty" }; Sprintf(buf, "explosion %s %d", explosion_types[i / MAXEXPCHARS], i % MAXEXPCHARS); return buf; } } tilenum += (MAXEXPCHARS * EXPL_MAX); i = entry - tilenum; if (i < (NUM_ZAP << 2)) { if (set == OTH_GLYPH) { Sprintf(buf, "zap %d %d", i / 4, i % 4); return buf; } } tilenum += (NUM_ZAP << 2); i = entry - tilenum; if (i < WARNCOUNT) { if (set == OTH_GLYPH) { Sprintf(buf, "warning %d", i); return buf; } } tilenum += WARNCOUNT; for (i = 0; i < SIZE(substitutes); i++) { j = entry - tilenum; if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) { if (set == OTH_GLYPH) { Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j); return buf; } } tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } Sprintf(buf, "unknown %d %d", set, entry); return buf; } #else /* TILETEXT */ #define TILE_FILE "tile.c" #ifdef AMIGA #define SOURCE_TEMPLATE "NH:src/%s" #else #ifdef MAC #define SOURCE_TEMPLATE ":src:%s" #else #define SOURCE_TEMPLATE "../src/%s" #endif #endif short tilemap[MAX_GLYPH]; #ifdef STATUES_LOOK_LIKE_MONSTERS int lastmontile, lastobjtile, lastothtile, laststatuetile; #else int lastmontile, lastobjtile, lastothtile; #endif /* Number of tiles for invisible monsters */ #define NUM_INVIS_TILES 1 /* * set up array to map glyph numbers to tile numbers * * assumes tiles are numbered sequentially through monsters/objects/other, * with entries for all supported compilation options * * "other" contains cmap and zaps (the swallow sets are a repeated portion * of cmap), as well as the "flash" glyphs for the new warning system * introduced in 3.3.1. */ void init_tilemap() { int i, j, condnum, tilenum; int corpsetile, swallowbase; for (i = 0; i < MAX_GLYPH; i++) { tilemap[i] = -1; } corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE; swallowbase = NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl; /* add number compiled out */ for (i = 0; conditionals[i].sequence; i++) { switch (conditionals[i].sequence) { case MON_GLYPH: corpsetile++; swallowbase++; break; case OBJ_GLYPH: if (conditionals[i].predecessor < CORPSE) corpsetile++; swallowbase++; break; case OTH_GLYPH: if (conditionals[i].predecessor < S_sw_tl) swallowbase++; break; } } condnum = tilenum = 0; for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_MON_OFF + i] = tilenum; tilemap[GLYPH_PET_OFF + i] = tilenum; tilemap[GLYPH_DETECT_OFF + i] = tilenum; tilemap[GLYPH_RIDDEN_OFF + i] = tilenum; tilemap[GLYPH_BODY_OFF + i] = corpsetile; j = GLYPH_SWALLOW_OFF + 8 * i; tilemap[j] = swallowbase; tilemap[j + 1] = swallowbase + 1; tilemap[j + 2] = swallowbase + 2; tilemap[j + 3] = swallowbase + 3; tilemap[j + 4] = swallowbase + 4; tilemap[j + 5] = swallowbase + 5; tilemap[j + 6] = swallowbase + 6; tilemap[j + 7] = swallowbase + 7; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } tilemap[GLYPH_INVISIBLE] = tilenum++; lastmontile = tilenum - 1; for (i = 0; i < NUM_OBJECTS; i++) { tilemap[GLYPH_OBJ_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OBJ_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } lastobjtile = tilenum - 1; for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { tilemap[GLYPH_CMAP_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) { tilemap[GLYPH_EXPLODE_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXPCHARS)) { condnum++; tilenum++; } } for (i = 0; i < NUM_ZAP << 2; i++) { tilemap[GLYPH_ZAP_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXEXPCHARS)) { condnum++; tilenum++; } } for (i = 0; i < WARNCOUNT; i++) { tilemap[GLYPH_WARNING_OFF + i] = tilenum; tilenum++; } #ifndef STATUES_LOOK_LIKE_MONSTERS /* statue patch: statues still use the same glyph as in vanilla */ for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_STATUE_OFF + i] = tilemap[GLYPH_OBJ_OFF + STATUE]; } #endif lastothtile = tilenum - 1; #ifdef STATUES_LOOK_LIKE_MONSTERS /* skip over the substitutes to get to the grayscale statues */ for (i = 0; i < SIZE(substitutes); i++) { tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* statue patch: statues look more like the monster */ condnum = 0; /* doing monsters again, so reset */ for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_STATUE_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } laststatuetile = tilenum - 1; #endif } const char *prolog[] = { "", "", "void", "substitute_tiles(plev)", "d_level *plev;", "{", "\tint i;", "" }; const char *epilog[] = { "}" }; /* write out the substitutions in an easily-used form. */ void process_substitutions(ofp) FILE *ofp; { int i, j, k, span, start; fprintf(ofp, "\n\n"); j = 0; /* unnecessary */ span = -1; for (i = 0; i < SIZE(substitutes); i++) { if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { j = i; span++; fprintf(ofp, "short std_tiles%d[] = { ", span); for (k = substitutes[i].first_glyph; k < substitutes[i].last_glyph; k++) fprintf(ofp, "%d, ", tilemap[k]); fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); } } for (i = 0; i < SIZE(prolog); i++) { fprintf(ofp, "%s\n", prolog[i]); } j = -1; span = -1; start = lastothtile + 1; for (i = 0; i < SIZE(substitutes); i++) { if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { if (i != 0) { /* finish previous span */ fprintf(ofp, "\t} else {\n"); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[j].first_glyph, substitutes[j].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, substitutes[j].first_glyph); fprintf(ofp, "\t}\n\n"); } j = i; span++; } if (i != j) fprintf(ofp, "\t} else "); fprintf(ofp, "\tif (%s) {\n", substitutes[i].level_test); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[i].first_glyph, substitutes[i].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = %d + i - %d;\n", start, substitutes[i].first_glyph); start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* finish last span */ fprintf(ofp, "\t} else {\n"); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[j].first_glyph, substitutes[j].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, substitutes[j].first_glyph); fprintf(ofp, "\t}\n\n"); for (i = 0; i < SIZE(epilog); i++) { fprintf(ofp, "%s\n", epilog[i]); } fprintf(ofp, "\nint total_tiles_used = %d;\n", start); lastothtile = start - 1; } int main() { register int i; char filename[30]; FILE *ofp; init_tilemap(); /* * create the source file, "tile.c" */ Sprintf(filename, SOURCE_TEMPLATE, TILE_FILE); if (!(ofp = fopen(filename, "w"))) { perror(filename); exit(EXIT_FAILURE); } fprintf(ofp, "/* This file is automatically generated. Do not edit. */\n"); fprintf(ofp, "\n#include \"hack.h\"\n\n"); fprintf(ofp, "short glyph2tile[MAX_GLYPH] = {\n"); for (i = 0; i < MAX_GLYPH; i++) { fprintf(ofp, "%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n'); } fprintf(ofp, "%s};\n", (i % 12) ? "\n" : ""); process_substitutions(ofp); fprintf(ofp, "\n#define MAXMONTILE %d\n", lastmontile); fprintf(ofp, "#define MAXOBJTILE %d\n", lastobjtile); fprintf(ofp, "#define MAXOTHTILE %d\n", lastothtile); fprintf(ofp, "\n/*tile.c*/\n"); fclose(ofp); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif /* TILETEXT */ nethack-3.6.0/win/share/tiletext.c0000664000076400007660000002166112536476415016065 0ustar paxedpaxed/* NetHack 3.6 tiletext.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "tile.h" pixval ColorMap[3][MAXCOLORMAPSIZE]; int colorsinmap; pixval MainColorMap[3][MAXCOLORMAPSIZE]; int colorsinmainmap; static short color_index[MAXCOLORMAPSIZE]; static int num_colors; static char charcolors[MAXCOLORMAPSIZE]; static int placeholder_init = 0; static pixel placeholder[TILE_Y][TILE_X]; static FILE *tile_file; static int tile_set, tile_set_indx; #if (TILE_X == 8) static const char *text_sets[] = { "monthin.txt", "objthin.txt", "oththin.txt" }; #else static const char *text_sets[] = { "monsters.txt", "objects.txt", "other.txt" }; #endif extern const char *FDECL(tilename, (int, int)); static void FDECL(read_text_colormap, (FILE *)); static boolean FDECL(write_text_colormap, (FILE *)); static boolean FDECL(read_txttile, (FILE *, pixel (*)[TILE_X])); static void FDECL(write_txttile, (FILE *, pixel (*)[TILE_X])); /* Ugh. DICE doesn't like %[A-Z], so we have to spell it out... */ #define FORMAT_STRING \ "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \ "(%d, %d, %d) " static void read_text_colormap(txtfile) FILE *txtfile; { int i, r, g, b; char c[2]; for (i = 0; i < MAXCOLORMAPSIZE; i++) color_index[i] = -1; num_colors = 0; while (fscanf(txtfile, FORMAT_STRING, c, &r, &g, &b) == 4) { color_index[(int) c[0]] = num_colors; ColorMap[CM_RED][num_colors] = r; ColorMap[CM_GREEN][num_colors] = g; ColorMap[CM_BLUE][num_colors] = b; num_colors++; } colorsinmap = num_colors; } #undef FORMAT_STRING static boolean write_text_colormap(txtfile) FILE *txtfile; { int i; char c; num_colors = colorsinmainmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); return FALSE; } for (i = 0; i < num_colors; i++) { if (i < 26) c = 'A' + i; else if (i < 52) c = 'a' + i - 26; else c = '0' + i - 52; charcolors[i] = c; Fprintf( txtfile, "%c = (%d, %d, %d)\n", c, (int) MainColorMap[CM_RED][i], (int) MainColorMap[CM_GREEN][i], (int) MainColorMap[CM_BLUE][i]); } return TRUE; } static boolean read_txttile(txtfile, pixels) FILE *txtfile; pixel (*pixels)[TILE_X]; { int ph, i, j, k; char buf[BUFSZ], ttype[BUFSZ]; const char *p; char c[2]; if (fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf) <= 0) return FALSE; ph = strcmp(ttype, "placeholder") == 0; if (!ph && strcmp(ttype, "tile") != 0) Fprintf(stderr, "Keyword \"%s\" unexpected for entry %d\n", ttype, i); if (tile_set != 0) { /* check tile name, but not relative number, which will * change when tiles are added */ p = tilename(tile_set, tile_set_indx); if (p && strcmp(p, buf)) { Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n", tile_set_indx, i, text_sets[tile_set - 1]); Fprintf(stderr, "\tfound '%s' while expecting '%s'\n", buf, p); } } tile_set_indx++; /* look for non-whitespace at each stage */ if (fscanf(txtfile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '{') { Fprintf(stderr, "didn't find expected '{'\n"); return FALSE; } for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { if (fscanf(txtfile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } k = color_index[(int) c[0]]; if (k == -1) Fprintf(stderr, "color %c not in colormap!\n", c[0]); else { pixels[j][i].r = ColorMap[CM_RED][k]; pixels[j][i].g = ColorMap[CM_GREEN][k]; pixels[j][i].b = ColorMap[CM_BLUE][k]; } } } if (ph) { /* remember it for later */ memcpy(placeholder, pixels, sizeof(placeholder)); } if (fscanf(txtfile, "%1s ", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '}') { Fprintf(stderr, "didn't find expected '}'\n"); return FALSE; } #ifdef _DCC /* DICE again... it doesn't seem to eat whitespace after the } like * it should, so we have to do so manually. */ while ((*c = fgetc(txtfile)) != EOF && isspace(*c)) ; ungetc(*c, txtfile); #endif return TRUE; } static void write_txttile(txtfile, pixels) FILE *txtfile; pixel (*pixels)[TILE_X]; { const char *p; const char *type; int i, j, k; if (memcmp(placeholder, pixels, sizeof(placeholder)) == 0) type = "placeholder"; else type = "tile"; if (tile_set == 0) Fprintf(txtfile, "# %s %d (unknown)\n", type, tile_set_indx); else { p = tilename(tile_set, tile_set_indx); if (p) Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p); else Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx); } tile_set_indx++; Fprintf(txtfile, "{\n"); for (j = 0; j < TILE_Y; j++) { Fprintf(txtfile, " "); for (i = 0; i < TILE_X; i++) { for (k = 0; k < num_colors; k++) { if (ColorMap[CM_RED][k] == pixels[j][i].r && ColorMap[CM_GREEN][k] == pixels[j][i].g && ColorMap[CM_BLUE][k] == pixels[j][i].b) break; } if (k >= num_colors) Fprintf(stderr, "color not in colormap!\n"); (void) fputc(charcolors[k], txtfile); } Fprintf(txtfile, "\n"); } Fprintf(txtfile, "}\n"); } /* initialize main colormap from globally accessed ColorMap */ void init_colormap() { int i; colorsinmainmap = colorsinmap; for (i = 0; i < colorsinmap; i++) { MainColorMap[CM_RED][i] = ColorMap[CM_RED][i]; MainColorMap[CM_GREEN][i] = ColorMap[CM_GREEN][i]; MainColorMap[CM_BLUE][i] = ColorMap[CM_BLUE][i]; } } /* merge new colors from ColorMap into MainColorMap */ void merge_colormap() { int i, j; for (i = 0; i < colorsinmap; i++) { for (j = 0; j < colorsinmainmap; j++) { if (MainColorMap[CM_RED][j] == ColorMap[CM_RED][i] && MainColorMap[CM_GREEN][j] == ColorMap[CM_GREEN][i] && MainColorMap[CM_BLUE][j] == ColorMap[CM_BLUE][i]) break; } if (j >= colorsinmainmap) { /* new color */ if (colorsinmainmap >= MAXCOLORMAPSIZE) { Fprintf(stderr, "Too many colors to merge -- excess ignored.\n"); } j = colorsinmainmap; MainColorMap[CM_RED][j] = ColorMap[CM_RED][i]; MainColorMap[CM_GREEN][j] = ColorMap[CM_GREEN][i]; MainColorMap[CM_BLUE][j] = ColorMap[CM_BLUE][i]; colorsinmainmap++; } } } boolean fopen_text_file(filename, type) const char *filename; const char *type; { const char *p; int i; if (tile_file != (FILE *) 0) { Fprintf(stderr, "can only open one text file at at time\n"); return FALSE; } tile_file = fopen(filename, type); if (tile_file == (FILE *) 0) { Fprintf(stderr, "cannot open text file %s\n", filename); return FALSE; } p = rindex(filename, '/'); if (p) p++; else p = filename; tile_set = 0; for (i = 0; i < SIZE(text_sets); i++) { if (!strcmp(p, text_sets[i])) tile_set = i + 1; } tile_set_indx = 0; if (!strcmp(type, RDTMODE)) { /* Fill placeholder with noise */ if (!placeholder_init) { placeholder_init++; for (i = 0; i < (int) sizeof placeholder; i++) ((char *) placeholder)[i] = i % 256; } read_text_colormap(tile_file); if (!colorsinmainmap) init_colormap(); else merge_colormap(); return TRUE; } else if (!strcmp(type, WRTMODE)) { if (!colorsinmainmap) { Fprintf(stderr, "no colormap set yet\n"); return FALSE; } return (write_text_colormap(tile_file)); } else { Fprintf(stderr, "bad mode (%s) for fopen_text_file\n", type); return FALSE; } } boolean read_text_tile(pixels) pixel (*pixels)[TILE_X]; { return (read_txttile(tile_file, pixels)); } boolean write_text_tile(pixels) pixel (*pixels)[TILE_X]; { write_txttile(tile_file, pixels); return TRUE; } int fclose_text_file() { int ret; ret = fclose(tile_file); tile_file = (FILE *) 0; return ret; } nethack-3.6.0/win/tty/getline.c0000664000076400007660000002052412536476415015365 0ustar paxedpaxed/* NetHack 3.6 getline.c $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef TTY_GRAPHICS #if !defined(MAC) #define NEWAUTOCOMP #endif #include "wintty.h" #include "func_tab.h" char morc = 0; /* tell the outside world what char you chose */ STATIC_DCL boolean FDECL(ext_cmd_getlin_hook, (char *)); typedef boolean FDECL((*getlin_hook_proc), (char *)); STATIC_DCL void FDECL(hooked_tty_getlin, (const char *, char *, getlin_hook_proc)); extern int NDECL(extcmd_via_menu); /* cmd.c */ extern char erase_char, kill_char; /* from appropriate tty.c file */ /* * Read a line closed with '\n' into the array char bufp[BUFSZ]. * (The '\n' is not stored. The string is closed with a '\0'.) * Reading can be interrupted by an escape ('\033') - now the * resulting string is "\033". */ void tty_getlin(query, bufp) const char *query; register char *bufp; { hooked_tty_getlin(query, bufp, (getlin_hook_proc) 0); } STATIC_OVL void hooked_tty_getlin(query, bufp, hook) const char *query; register char *bufp; getlin_hook_proc hook; { register char *obufp = bufp; register int c; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; ttyDisplay->toplin = 3; /* special prompt state */ ttyDisplay->inread++; pline("%s ", query); *obufp = 0; for (;;) { (void) fflush(stdout); Strcat(strcat(strcpy(toplines, query), " "), obufp); c = pgetchar(); if (c == '\033' || c == EOF) { if (c == '\033' && obufp[0] != '\0') { obufp[0] = '\0'; bufp = obufp; tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(query); addtopl(" "); addtopl(obufp); } else { obufp[0] = '\033'; obufp[1] = '\0'; break; } } if (ttyDisplay->intr) { ttyDisplay->intr--; *bufp = 0; } if (c == '\020') { /* ctrl-P */ if (iflags.prevmsg_window != 's') { int sav = ttyDisplay->inread; ttyDisplay->inread = 0; (void) tty_doprev_message(); ttyDisplay->inread = sav; tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(query); addtopl(" "); *bufp = 0; addtopl(obufp); } else { if (!doprev) (void) tty_doprev_message(); /* need two initially */ (void) tty_doprev_message(); doprev = 1; continue; } } else if (doprev && iflags.prevmsg_window == 's') { tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; doprev = 0; addtopl(query); addtopl(" "); *bufp = 0; addtopl(obufp); } if (c == erase_char || c == '\b') { if (bufp != obufp) { #ifdef NEWAUTOCOMP char *i; #endif /* NEWAUTOCOMP */ bufp--; #ifndef NEWAUTOCOMP putsyms("\b \b"); /* putsym converts \b */ #else /* NEWAUTOCOMP */ putsyms("\b"); for (i = bufp; *i; ++i) putsyms(" "); for (; i > bufp; --i) putsyms("\b"); *bufp = 0; #endif /* NEWAUTOCOMP */ } else tty_nhbell(); #if defined(apollo) } else if (c == '\n' || c == '\r') { #else } else if (c == '\n') { #endif #ifndef NEWAUTOCOMP *bufp = 0; #endif /* not NEWAUTOCOMP */ break; } else if (' ' <= (unsigned char) c && c != '\177' && (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)) { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ #ifdef NEWAUTOCOMP char *i = eos(bufp); #endif /* NEWAUTOCOMP */ *bufp = c; bufp[1] = 0; putsyms(bufp); bufp++; if (hook && (*hook)(obufp)) { putsyms(bufp); #ifndef NEWAUTOCOMP bufp = eos(bufp); #else /* NEWAUTOCOMP */ /* pointer and cursor left where they were */ for (i = bufp; *i; ++i) putsyms("\b"); } else if (i > bufp) { char *s = i; /* erase rest of prior guess */ for (; i > bufp; --i) putsyms(" "); for (; s > bufp; --s) putsyms("\b"); #endif /* NEWAUTOCOMP */ } } else if (c == kill_char || c == '\177') { /* Robert Viduya */ /* this test last - @ might be the kill_char */ #ifndef NEWAUTOCOMP while (bufp != obufp) { bufp--; putsyms("\b \b"); } #else /* NEWAUTOCOMP */ for (; *bufp; ++bufp) putsyms(" "); for (; bufp != obufp; --bufp) putsyms("\b \b"); *bufp = 0; #endif /* NEWAUTOCOMP */ } else tty_nhbell(); } ttyDisplay->toplin = 2; /* nonempty, no --More-- required */ ttyDisplay->inread--; clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */ } void xwaitforspace(s) register const char *s; /* chars allowed besides return */ { register int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n'; morc = 0; while ( #ifdef HANGUPHANDLING !program_state.done_hup && #endif (c = tty_nhgetch()) != EOF) { if (c == '\n') break; if (iflags.cbreak) { if (c == '\033') { if (ttyDisplay) ttyDisplay->dismiss_more = 1; morc = '\033'; break; } if ((s && index(s, c)) || c == x) { morc = (char) c; break; } tty_nhbell(); } } } /* * Implement extended command completion by using this hook into * tty_getlin. Check the characters already typed, if they uniquely * identify an extended command, expand the string to the whole * command. * * Return TRUE if we've extended the string at base. Otherwise return FALSE. * Assumptions: * * + we don't change the characters that are already in base * + base has enough room to hold our string */ STATIC_OVL boolean ext_cmd_getlin_hook(base) char *base; { int oindex, com_index; com_index = -1; for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0; oindex++) { if (!strncmpi(base, extcmdlist[oindex].ef_txt, strlen(base))) { if (com_index == -1) /* no matches yet */ com_index = oindex; else /* more than 1 match */ return FALSE; } } if (com_index >= 0) { Strcpy(base, extcmdlist[com_index].ef_txt); return TRUE; } return FALSE; /* didn't match anything */ } /* * Read in an extended command, doing command line completion. We * stop when we have found enough characters to make a unique command. */ int tty_get_ext_cmd() { int i; char buf[BUFSZ]; if (iflags.extmenu) return extcmd_via_menu(); /* maybe a runtime option? */ /* hooked_tty_getlin("#", buf, flags.cmd_comp ? ext_cmd_getlin_hook : * (getlin_hook_proc) 0); */ hooked_tty_getlin("#", buf, in_doagain ? (getlin_hook_proc) 0 : ext_cmd_getlin_hook); (void) mungspaces(buf); if (buf[0] == 0 || buf[0] == '\033') return -1; for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++) if (!strcmpi(buf, extcmdlist[i].ef_txt)) break; if (!in_doagain) { int j; for (j = 0; buf[j]; j++) savech(buf[j]); savech('\n'); } if (extcmdlist[i].ef_txt == (char *) 0) { pline("%s: unknown extended command.", buf); i = -1; } return i; } #endif /* TTY_GRAPHICS */ /*getline.c*/ nethack-3.6.0/win/tty/termcap.c0000664000076400007660000010033612620611342015351 0ustar paxedpaxed/* NetHack 3.6 termcap.c $NHDT-Date: 1447234979 2015/11/11 09:42:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.23 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #if defined(TTY_GRAPHICS) && !defined(NO_TERMS) #include "wintty.h" #include "tcap.h" #ifdef MICROPORT_286_BUG #define Tgetstr(key) (tgetstr(key, tbuf)) #else #define Tgetstr(key) (tgetstr(key, &tbufptr)) #endif /* MICROPORT_286_BUG **/ static char *FDECL(s_atr2str, (int)); static char *FDECL(e_atr2str, (int)); void FDECL(cmov, (int, int)); void FDECL(nocmov, (int, int)); #if defined(TEXTCOLOR) && defined(TERMLIB) #if !defined(UNIX) || !defined(TERMINFO) #ifndef TOS static void FDECL(analyze_seq, (char *, int *, int *)); #endif #endif static void NDECL(init_hilite); static void NDECL(kill_hilite); #endif /* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE, ul_hack */ struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0, 0, 0, 0, FALSE }; STATIC_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE; STATIC_VAR char *VS, *VE; STATIC_VAR char *ME; STATIC_VAR char *MR; #if 0 STATIC_VAR char *MB, *MH; STATIC_VAR char *MD; /* may already be in use below */ #endif #ifdef TERMLIB boolean dynamic_HIHE = FALSE; #ifdef TEXTCOLOR STATIC_VAR char *MD; #endif STATIC_VAR int SG; STATIC_OVL char PC = '\0'; STATIC_VAR char tbuf[512]; #endif /*TERMLIB*/ #ifdef TEXTCOLOR #ifdef TOS const char *hilites[CLR_MAX]; /* terminal escapes for the various colors */ #else char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */ #endif #endif static char *KS = (char *) 0, *KE = (char *) 0; /* keypad sequences */ static char nullstr[] = ""; #if defined(ASCIIGRAPH) && !defined(NO_TERMS) extern boolean HE_resets_AS; #endif #ifndef TERMLIB STATIC_VAR char tgotobuf[20]; #ifdef TOS #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + ' ', x + ' '), tgotobuf) #else #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y + 1, x + 1), tgotobuf) #endif #endif /* TERMLIB */ void tty_startup(wid, hgt) int *wid, *hgt; { register int i; #ifdef TERMLIB register const char *term; register char *tptr; char *tbufptr, *pc; #ifdef VMS term = verify_termcap(); if (!term) #endif term = getenv("TERM"); #if defined(TOS) && defined(__GNUC__) if (!term) term = "builtin"; /* library has a default */ #endif if (!term) #endif #ifndef ANSI_DEFAULT error("Can't get TERM."); #else #ifdef TOS { CO = 80; LI = 25; TI = VS = VE = TE = nullstr; HO = "\033H"; CE = "\033K"; /* the VT52 termcap */ UP = "\033A"; nh_CM = "\033Y%c%c"; /* used with function tgoto() */ nh_ND = "\033C"; XD = "\033B"; BC = "\033D"; SO = "\033p"; SE = "\033q"; /* HI and HE will be updated in init_hilite if we're using color */ nh_HI = "\033p"; nh_HE = "\033q"; *wid = CO; *hgt = LI; CL = "\033E"; /* last thing set */ return; } #else /* TOS */ { #ifdef MICRO get_scr_size(); #ifdef CLIPPING if (CO < COLNO || LI < ROWNO + 3) setclipped(); #endif #endif HO = "\033[H"; /* nh_CD = "\033[J"; */ CE = "\033[K"; /* the ANSI termcap */ #ifndef TERMLIB nh_CM = "\033[%d;%dH"; #else nh_CM = "\033[%i%d;%dH"; #endif UP = "\033[A"; nh_ND = "\033[C"; XD = "\033[B"; #ifdef MICRO /* backspaces are non-destructive */ BC = "\b"; #else BC = "\033[D"; #endif nh_HI = SO = "\033[1m"; nh_US = "\033[4m"; MR = "\033[7m"; TI = nh_HE = ME = SE = nh_UE = "\033[0m"; /* strictly, SE should be 2, and nh_UE should be 24, but we can't trust all ANSI emulators to be that complete. -3. */ #ifndef MICRO AS = "\016"; AE = "\017"; #endif TE = VS = VE = nullstr; #ifdef TEXTCOLOR for (i = 0; i < CLR_MAX / 2; i++) if (i != CLR_BLACK) { hilites[i | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm")); Sprintf(hilites[i | BRIGHT], "\033[1;3%dm", i); if (i != CLR_GRAY) #ifdef MICRO if (i == CLR_BLUE) hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT]; else #endif { hilites[i] = (char *) alloc(sizeof("\033[0;3%dm")); Sprintf(hilites[i], "\033[0;3%dm", i); } } #endif *wid = CO; *hgt = LI; CL = "\033[2J"; /* last thing set */ return; } #endif /* TOS */ #endif /* ANSI_DEFAULT */ #ifdef TERMLIB tptr = (char *) alloc(1024); tbufptr = tbuf; if (!strncmp(term, "5620", 4)) flags.null = FALSE; /* this should be a termcap flag */ if (tgetent(tptr, term) < 1) { char buf[BUFSZ]; (void) strncpy(buf, term, (BUFSZ - 1) - (sizeof("Unknown terminal type: . "))); buf[BUFSZ - 1] = '\0'; error("Unknown terminal type: %s.", term); } if ((pc = Tgetstr("pc")) != 0) PC = *pc; if (!(BC = Tgetstr("le"))) /* both termcap and terminfo use le */ #ifdef TERMINFO error("Terminal must backspace."); #else if (!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */ #ifndef MINIMAL_TERM if (!tgetflag("bs")) error("Terminal must backspace."); #endif BC = tbufptr; tbufptr += 2; *BC = '\b'; } #endif #ifdef MINIMAL_TERM HO = (char *) 0; #else HO = Tgetstr("ho"); #endif /* * LI and CO are set in ioctl.c via a TIOCGWINSZ if available. If * the kernel has values for either we should use them rather than * the values from TERMCAP ... */ #ifndef MICRO if (!CO) CO = tgetnum("co"); if (!LI) LI = tgetnum("li"); #else #if defined(TOS) && defined(__GNUC__) if (!strcmp(term, "builtin")) { get_scr_size(); } else #endif { CO = tgetnum("co"); LI = tgetnum("li"); if (!LI || !CO) /* if we don't override it */ get_scr_size(); } #endif /* ?MICRO */ #ifdef CLIPPING if (CO < COLNO || LI < ROWNO + 3) setclipped(); #endif nh_ND = Tgetstr("nd"); if (tgetflag("os")) error("NetHack can't have OS."); if (tgetflag("ul")) ul_hack = TRUE; CE = Tgetstr("ce"); UP = Tgetstr("up"); /* It seems that xd is no longer supported, and we should use a linefeed instead; unfortunately this requires resetting CRMOD, and many output routines will have to be modified slightly. Let's leave that till the next release. */ XD = Tgetstr("xd"); /* not: XD = Tgetstr("do"); */ if (!(nh_CM = Tgetstr("cm"))) { if (!UP && !HO) error("NetHack needs CM or UP or HO."); tty_raw_print("Playing NetHack on terminals without CM is suspect."); tty_wait_synch(); } SO = Tgetstr("so"); SE = Tgetstr("se"); nh_US = Tgetstr("us"); nh_UE = Tgetstr("ue"); SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */ if (!SO || !SE || (SG > 0)) SO = SE = nh_US = nh_UE = nullstr; TI = Tgetstr("ti"); TE = Tgetstr("te"); VS = VE = nullstr; #ifdef TERMINFO VS = Tgetstr("eA"); /* enable graphics */ #endif KS = Tgetstr("ks"); /* keypad start (special mode) */ KE = Tgetstr("ke"); /* keypad end (ordinary mode [ie, digits]) */ MR = Tgetstr("mr"); /* reverse */ #if 0 MB = Tgetstr("mb"); /* blink */ MD = Tgetstr("md"); /* boldface */ MH = Tgetstr("mh"); /* dim */ #endif ME = Tgetstr("me"); /* turn off all attributes */ if (!ME || (SE == nullstr)) ME = SE; /* default to SE value */ /* Get rid of padding numbers for nh_HI and nh_HE. Hope they * aren't really needed!!! nh_HI and nh_HE are outputted to the * pager as a string - so how can you send it NULs??? * -jsb */ for (i = 0; digit(SO[i]); ++i) continue; nh_HI = dupstr(&SO[i]); for (i = 0; digit(ME[i]); ++i) continue; nh_HE = dupstr(&ME[i]); dynamic_HIHE = TRUE; AS = Tgetstr("as"); AE = Tgetstr("ae"); nh_CD = Tgetstr("cd"); #ifdef TEXTCOLOR MD = Tgetstr("md"); #endif #ifdef TEXTCOLOR #if defined(TOS) && defined(__GNUC__) if (!strcmp(term, "builtin") || !strcmp(term, "tw52") || !strcmp(term, "st52")) { init_hilite(); } #else init_hilite(); #endif #endif *wid = CO; *hgt = LI; if (!(CL = Tgetstr("cl"))) /* last thing set */ error("NetHack needs CL."); if ((int) (tbufptr - tbuf) > (int) (sizeof tbuf)) error("TERMCAP entry too big...\n"); free((genericptr_t) tptr); #endif /* TERMLIB */ } /* note: at present, this routine is not part of the formal window interface */ /* deallocate resources prior to final termination */ void tty_shutdown() { /* we only attempt to clean up a few individual termcap variables */ #ifdef TERMLIB #ifdef TEXTCOLOR kill_hilite(); #endif if (dynamic_HIHE) { free((genericptr_t) nh_HI), nh_HI = (char *) 0; free((genericptr_t) nh_HE), nh_HE = (char *) 0; dynamic_HIHE = FALSE; } #endif return; } void tty_number_pad(state) int state; { switch (state) { case -1: /* activate keypad mode (escape sequences) */ if (KS && *KS) xputs(KS); break; case 1: /* activate numeric mode for keypad (digits) */ if (KE && *KE) xputs(KE); break; case 0: /* don't need to do anything--leave terminal as-is */ default: break; } } #ifdef TERMLIB extern void NDECL((*decgraphics_mode_callback)); /* defined in drawing.c */ static void NDECL(tty_decgraphics_termcap_fixup); /* We call this routine whenever DECgraphics mode is enabled, even if it has been previously set, in case the user manages to reset the fonts. The actual termcap fixup only needs to be done once, but we can't call xputs() from the option setting or graphics assigning routines, so this is a convenient hook. */ static void tty_decgraphics_termcap_fixup() { static char ctrlN[] = "\016"; static char ctrlO[] = "\017"; static char appMode[] = "\033="; static char numMode[] = "\033>"; /* these values are missing from some termcaps */ if (!AS) AS = ctrlN; /* ^N (shift-out [graphics font]) */ if (!AE) AE = ctrlO; /* ^O (shift-in [regular font]) */ if (!KS) KS = appMode; /* ESC= (application keypad mode) */ if (!KE) KE = numMode; /* ESC> (numeric keypad mode) */ /* * Select the line-drawing character set as the alternate font. * Do not select NA ASCII as the primary font since people may * reasonably be using the UK character set. */ if (SYMHANDLING(H_DEC)) xputs("\033)0"); #ifdef PC9800 init_hilite(); #endif #if defined(ASCIIGRAPH) && !defined(NO_TERMS) /* some termcaps suffer from the bizarre notion that resetting video attributes should also reset the chosen character set */ { const char *nh_he = nh_HE, *ae = AE; int he_limit, ae_length; if (digit(*ae)) { /* skip over delay prefix, if any */ do ++ae; while (digit(*ae)); if (*ae == '.') { ++ae; if (digit(*ae)) ++ae; } if (*ae == '*') ++ae; } /* can't use nethack's case-insensitive strstri() here, and some old systems don't have strstr(), so use brute force substring search */ ae_length = strlen(ae), he_limit = strlen(nh_he); while (he_limit >= ae_length) { if (strncmp(nh_he, ae, ae_length) == 0) { HE_resets_AS = TRUE; break; } ++nh_he, --he_limit; } } #endif } #endif /* TERMLIB */ #if defined(ASCIIGRAPH) && defined(PC9800) extern void NDECL((*ibmgraphics_mode_callback)); /* defined in drawing.c */ #endif #ifdef PC9800 extern void NDECL((*ascgraphics_mode_callback)); /* defined in drawing.c */ static void NDECL(tty_ascgraphics_hilite_fixup); static void tty_ascgraphics_hilite_fixup() { register int c; for (c = 0; c < CLR_MAX / 2; c++) if (c != CLR_BLACK) { hilites[c | BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm")); Sprintf(hilites[c | BRIGHT], "\033[1;3%dm", c); if (c != CLR_GRAY) { hilites[c] = (char *) alloc(sizeof("\033[0;3%dm")); Sprintf(hilites[c], "\033[0;3%dm", c); } } } #endif /* PC9800 */ void tty_start_screen() { xputs(TI); xputs(VS); #ifdef PC9800 if (!SYMHANDLING(H_IBM)) tty_ascgraphics_hilite_fixup(); /* set up callback in case option is not set yet but toggled later */ ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup; #ifdef ASCIIGRAPH if (SYMHANDLING(H_IBM)) init_hilite(); /* set up callback in case option is not set yet but toggled later */ ibmgraphics_mode_callback = init_hilite; #endif #endif /* PC9800 */ #ifdef TERMLIB if (SYMHANDLING(H_DEC)) tty_decgraphics_termcap_fixup(); /* set up callback in case option is not set yet but toggled later */ decgraphics_mode_callback = tty_decgraphics_termcap_fixup; #endif if (Cmd.num_pad) tty_number_pad(1); /* make keypad send digits */ } void tty_end_screen() { clear_screen(); xputs(VE); xputs(TE); } /* Cursor movements */ /* Note to overlay tinkerers. The placement of this overlay controls the location of the function xputc(). This function is not currently in trampoli.[ch] files for what is deemed to be performance reasons. If this define is moved and or xputc() is taken out of the ROOT overlay, then action must be taken in trampoli.[ch]. */ void nocmov(x, y) int x, y; { if ((int) ttyDisplay->cury > y) { if (UP) { while ((int) ttyDisplay->cury > y) { /* Go up. */ xputs(UP); ttyDisplay->cury--; } } else if (nh_CM) { cmov(x, y); } else if (HO) { home(); tty_curs(BASE_WINDOW, x + 1, y); } /* else impossible("..."); */ } else if ((int) ttyDisplay->cury < y) { if (XD) { while ((int) ttyDisplay->cury < y) { xputs(XD); ttyDisplay->cury++; } } else if (nh_CM) { cmov(x, y); } else { while ((int) ttyDisplay->cury < y) { xputc('\n'); ttyDisplay->curx = 0; ttyDisplay->cury++; } } } if ((int) ttyDisplay->curx < x) { /* Go to the right. */ if (!nh_ND) { cmov(x, y); } else { /* bah */ /* should instead print what is there already */ while ((int) ttyDisplay->curx < x) { xputs(nh_ND); ttyDisplay->curx++; } } } else if ((int) ttyDisplay->curx > x) { while ((int) ttyDisplay->curx > x) { /* Go to the left. */ xputs(BC); ttyDisplay->curx--; } } } void cmov(x, y) register int x, y; { xputs(tgoto(nh_CM, x, y)); ttyDisplay->cury = y; ttyDisplay->curx = x; } /* See note above. xputc() is a special function. */ void xputc(c) #if defined(apollo) int c; #else char c; #endif { (void) putchar(c); } void xputs(s) const char *s; { #ifndef TERMLIB (void) fputs(s, stdout); #else #if defined(NHSTDC) || defined(ULTRIX_PROTO) tputs(s, 1, (int (*) ()) xputc); #else tputs(s, 1, xputc); #endif #endif } void cl_end() { if (CE) { xputs(CE); } else { /* no-CE fix - free after Harold Rynes */ register int cx = ttyDisplay->curx + 1; /* this looks terrible, especially on a slow terminal but is better than nothing */ while (cx < CO) { xputc(' '); cx++; } tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } } void clear_screen() { /* note: if CL is null, then termcap initialization failed, so don't attempt screen-oriented I/O during final cleanup. */ if (CL) { xputs(CL); home(); } } void home() { if (HO) xputs(HO); else if (nh_CM) xputs(tgoto(nh_CM, 0, 0)); else tty_curs(BASE_WINDOW, 1, 0); /* using UP ... */ ttyDisplay->curx = ttyDisplay->cury = 0; } void standoutbeg() { if (SO) xputs(SO); } void standoutend() { if (SE) xputs(SE); } #if 0 /* if you need one of these, uncomment it (here and in extern.h) */ void revbeg() { if (MR) xputs(MR); } void boldbeg() { if (MD) xputs(MD); } void blinkbeg() { if (MB) xputs(MB); } void dimbeg() { /* not in most termcap entries */ if (MH) xputs(MH); } void m_end() { if (ME) xputs(ME); } #endif /*0*/ void backsp() { xputs(BC); } void tty_nhbell() { if (flags.silent) return; (void) putchar('\007'); /* curx does not change */ (void) fflush(stdout); } #ifdef ASCIIGRAPH void graph_on() { if (AS) xputs(AS); } void graph_off() { if (AE) xputs(AE); } #endif #if !defined(MICRO) #ifdef VMS static const short tmspc10[] = { /* from termcap */ 0, 2000, 1333, 909, 743, 666, 333, 166, 83, 55, 50, 41, 27, 20, 13, 10, 5 }; #else static const short tmspc10[] = { /* from termcap */ 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5 }; #endif #endif /* delay 50 ms */ void tty_delay_output() { #if defined(MICRO) register int i; #endif #ifdef TIMED_DELAY if (flags.nap) { (void) fflush(stdout); msleep(50); /* sleep for 50 milliseconds */ return; } #endif #if defined(MICRO) /* simulate the delay with "cursor here" */ for (i = 0; i < 3; i++) { cmov(ttyDisplay->curx, ttyDisplay->cury); (void) fflush(stdout); } #else /* MICRO */ /* BUG: if the padding character is visible, as it is on the 5620 then this looks terrible. */ if (flags.null) { #ifdef TERMINFO /* cbosgd!cbcephus!pds for SYS V R2 */ #ifdef NHSTDC tputs("$<50>", 1, (int (*) ()) xputc); #else tputs("$<50>", 1, xputc); #endif #else #if defined(NHSTDC) || defined(ULTRIX_PROTO) tputs("50", 1, (int (*) ()) xputc); #else tputs("50", 1, xputc); #endif #endif } else if (ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) { /* delay by sending cm(here) an appropriate number of times */ register int cmlen = strlen(tgoto(nh_CM, ttyDisplay->curx, ttyDisplay->cury)); register int i = 500 + tmspc10[ospeed] / 2; while (i > 0) { cmov((int) ttyDisplay->curx, (int) ttyDisplay->cury); i -= cmlen * tmspc10[ospeed]; } } #endif /* MICRO */ } /* must only be called with curx = 1 */ void cl_eos() /* free after Robert Viduya */ { if (nh_CD) { xputs(nh_CD); } else { register int cy = ttyDisplay->cury + 1; while (cy <= LI - 2) { cl_end(); xputc('\n'); cy++; } cl_end(); tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } } #if defined(TEXTCOLOR) && defined(TERMLIB) #if defined(UNIX) && defined(TERMINFO) /* * Sets up color highlighting, using terminfo(4) escape sequences. * * Having never seen a terminfo system without curses, we assume this * inclusion is safe. On systems with color terminfo, it should define * the 8 COLOR_FOOs, and avoid us having to guess whether this particular * terminfo uses BGR or RGB for its indexes. * * If we don't get the definitions, then guess. Original color terminfos * used BGR for the original Sf (setf, Standard foreground) codes, but * there was a near-total lack of user documentation, so some subsequent * terminfos, such as early Linux ncurses and SCO UNIX, used RGB. Possibly * as a result of the confusion, AF (setaf, ANSI Foreground) codes were * introduced, but this caused yet more confusion. Later Linux ncurses * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4 * standard. We could switch the colors around when using Sf with ncurses, * which would help things on later ncurses and hurt things on early ncurses. * We'll try just preferring AF and hoping it always agrees with COLOR_FOO, * and falling back to Sf if AF isn't defined. * * In any case, treat black specially so we don't try to display black * characters on the assumed black background. */ /* `curses' is aptly named; various versions don't like these macros used elsewhere within nethack; fortunately they're not needed beyond this point, so we don't need to worry about reconstructing them after the header file inclusion. */ #undef delay_output #undef TRUE #undef FALSE #define m_move curses_m_move /* Some curses.h decl m_move(), not used here \ */ #include #if !defined(LINUX) && !defined(__FreeBSD__) && !defined(NOTPARMDECL) extern char *tparm(); #endif #ifndef COLOR_BLACK /* trust include file */ #ifndef _M_UNIX /* guess BGR */ #define COLOR_BLACK 0 #define COLOR_BLUE 1 #define COLOR_GREEN 2 #define COLOR_CYAN 3 #define COLOR_RED 4 #define COLOR_MAGENTA 5 #define COLOR_YELLOW 6 #define COLOR_WHITE 7 #else /* guess RGB */ #define COLOR_BLACK 0 #define COLOR_RED 1 #define COLOR_GREEN 2 #define COLOR_YELLOW 3 #define COLOR_BLUE 4 #define COLOR_MAGENTA 5 #define COLOR_CYAN 6 #define COLOR_WHITE 7 #endif #endif /* Mapping data for the six terminfo colors that resolve to pairs of nethack * colors. Black and white are handled specially. */ const struct { int ti_color, nh_color, nh_bright_color; } ti_map[6] = { { COLOR_RED, CLR_RED, CLR_ORANGE }, { COLOR_GREEN, CLR_GREEN, CLR_BRIGHT_GREEN }, { COLOR_YELLOW, CLR_BROWN, CLR_YELLOW }, { COLOR_BLUE, CLR_BLUE, CLR_BRIGHT_BLUE }, { COLOR_MAGENTA, CLR_MAGENTA, CLR_BRIGHT_MAGENTA }, { COLOR_CYAN, CLR_CYAN, CLR_BRIGHT_CYAN } }; static char nilstring[] = ""; static void init_hilite() { register int c; char *setf, *scratch; int md_len; if (tgetnum("Co") < 8 || (MD == NULL) || (strlen(MD) == 0) || ((setf = tgetstr("AF", (char **) 0)) == (char *) 0 && (setf = tgetstr("Sf", (char **) 0)) == (char *) 0)) { /* Fallback when colors not available * It's arbitrary to collapse all colors except gray * together, but that's what the previous code did. */ hilites[CLR_BLACK] = nh_HI; hilites[CLR_RED] = nh_HI; hilites[CLR_GREEN] = nh_HI; hilites[CLR_BROWN] = nh_HI; hilites[CLR_BLUE] = nh_HI; hilites[CLR_MAGENTA] = nh_HI; hilites[CLR_CYAN] = nh_HI; hilites[CLR_GRAY] = nilstring; hilites[NO_COLOR] = nilstring; hilites[CLR_ORANGE] = nh_HI; hilites[CLR_BRIGHT_GREEN] = nh_HI; hilites[CLR_YELLOW] = nh_HI; hilites[CLR_BRIGHT_BLUE] = nh_HI; hilites[CLR_BRIGHT_MAGENTA] = nh_HI; hilites[CLR_BRIGHT_CYAN] = nh_HI; hilites[CLR_WHITE] = nh_HI; return; } md_len = strlen(MD); c = 6; while (c--) { char *work; scratch = tparm(setf, ti_map[c].ti_color); work = (char *) alloc(strlen(scratch) + md_len + 1); Strcpy(work, MD); hilites[ti_map[c].nh_bright_color] = work; work += md_len; Strcpy(work, scratch); hilites[ti_map[c].nh_color] = work; } scratch = tparm(setf, COLOR_WHITE); hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1); Strcpy(hilites[CLR_WHITE], MD); Strcat(hilites[CLR_WHITE], scratch); hilites[CLR_GRAY] = nilstring; hilites[NO_COLOR] = nilstring; if (iflags.wc2_darkgray) { /* On many terminals, esp. those using classic PC CGA/EGA/VGA * textmode, specifying "hilight" and "black" simultaneously * produces a dark shade of gray that is visible against a * black background. We can use it to represent black objects. */ scratch = tparm(setf, COLOR_BLACK); hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + md_len + 1); Strcpy(hilites[CLR_BLACK], MD); Strcat(hilites[CLR_BLACK], scratch); } else { /* But it's concievable that hilighted black-on-black could * still be invisible on many others. We substitute blue for * black. */ hilites[CLR_BLACK] = hilites[CLR_BLUE]; } } static void kill_hilite() { /* if colors weren't available, no freeing needed */ if (hilites[CLR_BLACK] == nh_HI) return; if (hilites[CLR_BLACK] != hilites[CLR_BLUE]) free(hilites[CLR_BLACK]); /* CLR_BLUE overlaps CLR_BRIGHT_BLUE, do not free */ /* CLR_GREEN overlaps CLR_BRIGHT_GREEN, do not free */ /* CLR_CYAN overlaps CLR_BRIGHT_CYAN, do not free */ /* CLR_RED overlaps CLR_ORANGE, do not free */ /* CLR_MAGENTA overlaps CLR_BRIGHT_MAGENTA, do not free */ /* CLR_BROWN overlaps CLR_YELLOW, do not free */ /* CLR_GRAY is static 'nilstring', do not free */ /* NO_COLOR is static 'nilstring', do not free */ free(hilites[CLR_BRIGHT_BLUE]); free(hilites[CLR_BRIGHT_GREEN]); free(hilites[CLR_BRIGHT_CYAN]); free(hilites[CLR_YELLOW]); free(hilites[CLR_ORANGE]); free(hilites[CLR_BRIGHT_MAGENTA]); free(hilites[CLR_WHITE]); } #else /* UNIX && TERMINFO */ #ifndef TOS /* find the foreground and background colors set by nh_HI or nh_HE */ static void analyze_seq(str, fg, bg) char *str; int *fg, *bg; { register int c, code; int len; #ifdef MICRO *fg = CLR_GRAY; *bg = CLR_BLACK; #else *fg = *bg = NO_COLOR; #endif c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */ len = strlen(str) - 1; /* length excluding attrib suffix */ if ((c != 1 && (str[0] != '\033' || str[1] != '[')) || (len - c) < 1 || str[len] != 'm') return; while (c < len) { if ((code = atoi(&str[c])) == 0) { /* reset */ /* this also catches errors */ #ifdef MICRO *fg = CLR_GRAY; *bg = CLR_BLACK; #else *fg = *bg = NO_COLOR; #endif } else if (code == 1) { /* bold */ *fg |= BRIGHT; #if 0 /* I doubt we'll ever resort to using blinking characters, unless we want a pulsing glow for something. But, in case we do... -3. */ } else if (code == 5) { /* blinking */ *fg |= BLINK; } else if (code == 25) { /* stop blinking */ *fg &= ~BLINK; #endif } else if (code == 7 || code == 27) { /* reverse */ code = *fg & ~BRIGHT; *fg = *bg | (*fg & BRIGHT); *bg = code; } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */ *fg = code - 30; } else if (code >= 40 && code <= 47) { /* hi_background RGB */ *bg = code - 40; } while (digit(str[++c])) ; c++; } } #endif /* * Sets up highlighting sequences, using ANSI escape sequences (highlight code * found in print.c). The nh_HI and nh_HE sequences (usually from SO) are * scanned to find foreground and background colors. */ static void init_hilite() { register int c; #ifdef TOS extern unsigned long tos_numcolors; /* in tos.c */ static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0"; if (tos_numcolors <= 2) { return; } /* Under TOS, the "bright" and "dim" colors are reversed. Moreover, * on the Falcon the dim colors are *really* dim; so we make most * of the colors the bright versions, with a few exceptions where * the dim ones look OK. */ hilites[0] = NOCOL; for (c = 1; c < SIZE(hilites); c++) { char *foo; foo = (char *) alloc(sizeof("\033b0")); if (tos_numcolors > 4) Sprintf(foo, "\033b%c", (c & ~BRIGHT) + '0'); else Strcpy(foo, "\033b0"); hilites[c] = foo; } if (tos_numcolors == 4) { TI = "\033b0\033c3\033E\033e"; TE = "\033b3\033c0\033J"; nh_HE = COLHE; hilites[CLR_GREEN] = hilites[CLR_GREEN | BRIGHT] = "\033b2"; hilites[CLR_RED] = hilites[CLR_RED | BRIGHT] = "\033b1"; } else { sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN ^ BRIGHT) + '0'); sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN ^ BRIGHT) + '0'); TI = "\033b0\033c\017\033E\033e"; TE = "\033b\017\033c0\033J"; nh_HE = COLHE; hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL; hilites[NO_COLOR] = hilites[CLR_GRAY]; } #else /* TOS */ int backg, foreg, hi_backg, hi_foreg; for (c = 0; c < SIZE(hilites); c++) hilites[c] = nh_HI; hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *) 0; analyze_seq(nh_HI, &hi_foreg, &hi_backg); analyze_seq(nh_HE, &foreg, &backg); for (c = 0; c < SIZE(hilites); c++) /* avoid invisibility */ if ((backg & ~BRIGHT) != c) { #ifdef MICRO if (c == CLR_BLUE) continue; #endif if (c == foreg) hilites[c] = (char *) 0; else if (c != hi_foreg || backg != hi_backg) { hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm")); Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT)); if ((c | BRIGHT) != (foreg | BRIGHT)) Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT); if (backg != CLR_BLACK) Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT); Strcat(hilites[c], "m"); } } #ifdef MICRO /* brighten low-visibility colors */ hilites[CLR_BLUE] = hilites[CLR_BLUE | BRIGHT]; #endif #endif /* TOS */ } static void kill_hilite() { #ifndef TOS register int c; for (c = 0; c < CLR_MAX / 2; c++) { if (hilites[c | BRIGHT] == hilites[c]) hilites[c | BRIGHT] = 0; if (hilites[c] && (hilites[c] != nh_HI)) free((genericptr_t) hilites[c]), hilites[c] = 0; if (hilites[c | BRIGHT] && (hilites[c | BRIGHT] != nh_HI)) free((genericptr_t) hilites[c | BRIGHT]), hilites[c | BRIGHT] = 0; } #endif return; } #endif /* UNIX */ #endif /* TEXTCOLOR */ static char nulstr[] = ""; static char * s_atr2str(n) int n; { switch (n) { case ATR_ULINE: if (nh_US) return nh_US; case ATR_BOLD: case ATR_BLINK: #if defined(TERMLIB) && defined(TEXTCOLOR) if (MD) return MD; #endif return nh_HI; case ATR_INVERSE: return MR; } return nulstr; } static char * e_atr2str(n) int n; { switch (n) { case ATR_ULINE: if (nh_UE) return nh_UE; case ATR_BOLD: case ATR_BLINK: return nh_HE; case ATR_INVERSE: return ME; } return nulstr; } void term_start_attr(attr) int attr; { if (attr) { xputs(s_atr2str(attr)); } } void term_end_attr(attr) int attr; { if (attr) { xputs(e_atr2str(attr)); } } void term_start_raw_bold() { xputs(nh_HI); } void term_end_raw_bold() { xputs(nh_HE); } #ifdef TEXTCOLOR void term_end_color() { xputs(nh_HE); } void term_start_color(color) int color; { xputs(hilites[color]); } int has_color(color) int color; { #ifdef X11_GRAPHICS /* XXX has_color() should be added to windowprocs */ if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "X11")) return TRUE; #endif #ifdef GEM_GRAPHICS /* XXX has_color() should be added to windowprocs */ if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "Gem")) return TRUE; #endif #ifdef QT_GRAPHICS /* XXX has_color() should be added to windowprocs */ if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "Qt")) return TRUE; #endif #ifdef AMII_GRAPHICS /* hilites[] not used */ return iflags.use_color; #endif return hilites[color] != (char *) 0; } #endif /* TEXTCOLOR */ #endif /* TTY_GRAPHICS */ /*termcap.c*/ nethack-3.6.0/win/tty/topl.c0000664000076400007660000005114712536476415014721 0ustar paxedpaxed/* NetHack 3.6 topl.c $NHDT-Date: 1431192777 2015/05/09 17:32:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef TTY_GRAPHICS #include "tcap.h" #include "wintty.h" #include #ifndef C /* this matches src/cmd.c */ #define C(c) (0x1f & (c)) #endif STATIC_DCL void FDECL(redotoplin, (const char *)); STATIC_DCL void FDECL(topl_putsym, (CHAR_P)); STATIC_DCL void NDECL(remember_topl); STATIC_DCL void FDECL(removetopl, (int)); STATIC_DCL void FDECL(msghistory_snapshot, (BOOLEAN_P)); STATIC_DCL void FDECL(free_msghistory_snapshot, (BOOLEAN_P)); int tty_doprev_message() { register struct WinDesc *cw = wins[WIN_MESSAGE]; winid prevmsg_win; int i; if ((iflags.prevmsg_window != 's') && !ttyDisplay->inread) { /* not single */ if (iflags.prevmsg_window == 'f') { /* full */ prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); cw->maxcol = cw->maxrow; i = cw->maxcol; do { if (cw->data[i] && strcmp(cw->data[i], "")) putstr(prevmsg_win, 0, cw->data[i]); i = (i + 1) % cw->rows; } while (i != cw->maxcol); putstr(prevmsg_win, 0, toplines); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); } else if (iflags.prevmsg_window == 'c') { /* combination */ do { morc = 0; if (cw->maxcol == cw->maxrow) { ttyDisplay->dismiss_more = C('p'); /* allowed at --More-- */ redotoplin(toplines); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } else if (cw->maxcol == (cw->maxrow - 1)) { ttyDisplay->dismiss_more = C('p'); /* allowed at --More-- */ redotoplin(cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } else { prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); cw->maxcol = cw->maxrow; i = cw->maxcol; do { if (cw->data[i] && strcmp(cw->data[i], "")) putstr(prevmsg_win, 0, cw->data[i]); i = (i + 1) % cw->rows; } while (i != cw->maxcol); putstr(prevmsg_win, 0, toplines); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); } } while (morc == C('p')); ttyDisplay->dismiss_more = 0; } else { /* reversed */ morc = 0; prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); putstr(prevmsg_win, 0, toplines); cw->maxcol = cw->maxrow - 1; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; do { putstr(prevmsg_win, 0, cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } while (cw->maxcol != cw->maxrow); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); cw->maxcol = cw->maxrow; ttyDisplay->dismiss_more = 0; } } else if (iflags.prevmsg_window == 's') { /* single */ ttyDisplay->dismiss_more = C('p'); /* allowed at --More-- */ do { morc = 0; if (cw->maxcol == cw->maxrow) redotoplin(toplines); else if (cw->data[cw->maxcol]) redotoplin(cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows - 1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } while (morc == C('p')); ttyDisplay->dismiss_more = 0; } return 0; } STATIC_OVL void redotoplin(str) const char *str; { int otoplin = ttyDisplay->toplin; home(); if (*str & 0x80) { /* kludge for the / command, the only time we ever want a */ /* graphics character on the top line */ g_putch((int) *str++); ttyDisplay->curx++; } end_glyphout(); /* in case message printed during graphics output */ putsyms(str); cl_end(); ttyDisplay->toplin = 1; if (ttyDisplay->cury && otoplin != 3) more(); } STATIC_OVL void remember_topl() { register struct WinDesc *cw = wins[WIN_MESSAGE]; int idx = cw->maxrow; unsigned len = strlen(toplines) + 1; if ((cw->flags & WIN_LOCKHISTORY) || !*toplines) return; if (len > (unsigned) cw->datlen[idx]) { if (cw->data[idx]) free(cw->data[idx]); len += (8 - (len & 7)); /* pad up to next multiple of 8 */ cw->data[idx] = (char *) alloc(len); cw->datlen[idx] = (short) len; } Strcpy(cw->data[idx], toplines); *toplines = '\0'; cw->maxcol = cw->maxrow = (idx + 1) % cw->rows; } void addtopl(s) const char *s; { register struct WinDesc *cw = wins[WIN_MESSAGE]; tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); putsyms(s); cl_end(); ttyDisplay->toplin = 1; } void more() { struct WinDesc *cw = wins[WIN_MESSAGE]; /* avoid recursion -- only happens from interrupts */ if (ttyDisplay->inmore++) return; if (ttyDisplay->toplin) { tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); if (cw->curx >= CO - 8) topl_putsym('\n'); } if (flags.standout) standoutbeg(); putsyms(defmorestr); if (flags.standout) standoutend(); xwaitforspace("\033 "); if (morc == '\033') cw->flags |= WIN_STOP; if (ttyDisplay->toplin && cw->cury) { docorner(1, cw->cury + 1); cw->curx = cw->cury = 0; home(); } else if (morc == '\033') { cw->curx = cw->cury = 0; home(); cl_end(); } ttyDisplay->toplin = 0; ttyDisplay->inmore = 0; } void update_topl(bp) register const char *bp; { register char *tl, *otl; register int n0; int notdied = 1; struct WinDesc *cw = wins[WIN_MESSAGE]; /* If there is room on the line, print message on same line */ /* But messages like "You die..." deserve their own line */ n0 = strlen(bp); if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) && cw->cury == 0 && n0 + (int) strlen(toplines) + 3 < CO - 8 && /* room for --More-- */ (notdied = strncmp(bp, "You die", 7))) { Strcat(toplines, " "); Strcat(toplines, bp); cw->curx += 2; if (!(cw->flags & WIN_STOP)) addtopl(bp); return; } else if (!(cw->flags & WIN_STOP)) { if (ttyDisplay->toplin == 1) more(); else if (cw->cury) { /* for when flags.toplin == 2 && cury > 1 */ docorner(1, cw->cury + 1); /* reset cury = 0 if redraw screen */ cw->curx = cw->cury = 0; /* from home--cls() & docorner(1,n) */ } } remember_topl(); (void) strncpy(toplines, bp, TBUFSZ); toplines[TBUFSZ - 1] = 0; for (tl = toplines; n0 >= CO;) { otl = tl; for (tl += CO - 1; tl != otl && !isspace(*tl); --tl) ; if (tl == otl) { /* Eek! A huge token. Try splitting after it. */ tl = index(otl, ' '); if (!tl) break; /* No choice but to spit it out whole. */ } *tl++ = '\n'; n0 = strlen(tl); } if (!notdied) cw->flags &= ~WIN_STOP; if (!(cw->flags & WIN_STOP)) redotoplin(toplines); } STATIC_OVL void topl_putsym(c) char c; { register struct WinDesc *cw = wins[WIN_MESSAGE]; if (cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant"); switch (c) { case '\b': if (ttyDisplay->curx == 0 && ttyDisplay->cury > 0) tty_curs(BASE_WINDOW, CO, (int) ttyDisplay->cury - 1); backsp(); ttyDisplay->curx--; cw->curx = ttyDisplay->curx; return; case '\n': cl_end(); ttyDisplay->curx = 0; ttyDisplay->cury++; cw->cury = ttyDisplay->cury; #ifdef WIN32CON (void) putchar(c); #endif break; default: if (ttyDisplay->curx == CO - 1) topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */ #ifdef WIN32CON (void) putchar(c); #endif ttyDisplay->curx++; } cw->curx = ttyDisplay->curx; if (cw->curx == 0) cl_end(); #ifndef WIN32CON (void) putchar(c); #endif } void putsyms(str) const char *str; { while (*str) topl_putsym(*str++); } STATIC_OVL void removetopl(n) register int n; { /* assume addtopl() has been done, so ttyDisplay->toplin is already set */ while (n-- > 0) putsyms("\b \b"); } extern char erase_char; /* from xxxtty.c; don't need kill_char */ char tty_yn_function(query, resp, def) const char *query, *resp; char def; /* * Generic yes/no function. 'def' is the default (returned by space or * return; 'esc' returns 'q', or 'n', or the default, depending on * what's in the string. The 'query' string is printed before the user * is asked about the string. * If resp is NULL, any single character is accepted and returned. * If not-NULL, only characters in it are allowed (exceptions: the * quitchars are always allowed, and if it contains '#' then digits * are allowed); if it includes an , anything beyond that won't * be shown in the prompt to the user but will be acceptable as input. */ { register char q; char rtmp[40]; boolean digit_ok, allow_num, preserve_case = FALSE; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; char prompt[BUFSZ]; if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; ttyDisplay->toplin = 3; /* special prompt state */ ttyDisplay->inread++; if (resp) { char *rb, respbuf[QBUFSZ]; allow_num = (index(resp, '#') != 0); Strcpy(respbuf, resp); /* normally we force lowercase, but if any uppercase letters are present in the allowed response, preserve case; check this before stripping the hidden choices */ for (rb = respbuf; *rb; ++rb) if ('A' <= *rb && *rb <= 'Z') { preserve_case = TRUE; break; } /* any acceptable responses that follow aren't displayed */ if ((rb = index(respbuf, '\033')) != 0) *rb = '\0'; (void) strncpy(prompt, query, QBUFSZ - 1); prompt[QBUFSZ - 1] = '\0'; Sprintf(eos(prompt), " [%s]", respbuf); if (def) Sprintf(eos(prompt), " (%c)", def); /* not pline("%s ", prompt); trailing space is wanted here in case of reprompt */ Strcat(prompt, " "); pline("%s", prompt); } else { /* no restriction on allowed response, so always preserve case */ /* preserve_case = TRUE; -- moot since we're jumping to the end */ pline("%s ", query); q = readchar(); goto clean_up; } do { /* loop until we get valid input */ q = readchar(); if (!preserve_case) q = lowc(q); if (q == '\020') { /* ctrl-P */ if (iflags.prevmsg_window != 's') { int sav = ttyDisplay->inread; ttyDisplay->inread = 0; (void) tty_doprev_message(); ttyDisplay->inread = sav; tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(prompt); } else { if (!doprev) (void) tty_doprev_message(); /* need two initially */ (void) tty_doprev_message(); doprev = 1; } q = '\0'; /* force another loop iteration */ continue; } else if (doprev) { /* BUG[?]: this probably ought to check whether the character which has just been read is an acceptable response; if so, skip the reprompt and use it. */ tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; doprev = 0; addtopl(prompt); q = '\0'; /* force another loop iteration */ continue; } digit_ok = allow_num && digit(q); if (q == '\033') { if (index(resp, 'q')) q = 'q'; else if (index(resp, 'n')) q = 'n'; else q = def; break; } else if (index(quitchars, q)) { q = def; break; } if (!index(resp, q) && !digit_ok) { tty_nhbell(); q = (char) 0; } else if (q == '#' || digit_ok) { char z, digit_string[2]; int n_len = 0; long value = 0; addtopl("#"), n_len++; digit_string[1] = '\0'; if (q != '#') { digit_string[0] = q; addtopl(digit_string), n_len++; value = q - '0'; q = '#'; } do { /* loop until we get a non-digit */ z = readchar(); if (!preserve_case) z = lowc(z); if (digit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; addtopl(digit_string), n_len++; } else if (z == 'y' || index(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ } else if (z == erase_char || z == '\b') { if (n_len <= 1) { value = -1; break; } else { value /= 10; removetopl(1), n_len--; } } else { value = -1; /* abort */ tty_nhbell(); break; } } while (z != '\n'); if (value > 0) yn_number = value; else if (value == 0) q = 'n'; /* 0 => "no" */ else { /* remove number from top line, then try again */ removetopl(n_len), n_len = 0; q = '\0'; } } } while (!q); if (q != '#') { Sprintf(rtmp, "%c", q); addtopl(rtmp); } clean_up: ttyDisplay->inread--; ttyDisplay->toplin = 2; if (ttyDisplay->intr) ttyDisplay->intr--; if (wins[WIN_MESSAGE]->cury) tty_clear_nhwindow(WIN_MESSAGE); return q; } /* shared by tty_getmsghistory() and tty_putmsghistory() */ static char **snapshot_mesgs = 0; /* collect currently available message history data into a sequential array; optionally, purge that data from the active circular buffer set as we go */ STATIC_OVL void msghistory_snapshot(purge) boolean purge; /* clear message history buffer as we copy it */ { char *mesg; int i, inidx, outidx; struct WinDesc *cw; /* paranoia (too early or too late panic save attempt?) */ if (WIN_MESSAGE == WIN_ERR || !wins[WIN_MESSAGE]) return; cw = wins[WIN_MESSAGE]; /* flush toplines[], moving most recent message to history */ remember_topl(); /* for a passive snapshot, we just copy pointers, so can't allow further history updating to take place because that could clobber them */ if (!purge) cw->flags |= WIN_LOCKHISTORY; snapshot_mesgs = (char **) alloc((cw->rows + 1) * sizeof(char *)); outidx = 0; inidx = cw->maxrow; for (i = 0; i < cw->rows; ++i) { snapshot_mesgs[i] = (char *) 0; mesg = cw->data[inidx]; if (mesg && *mesg) { snapshot_mesgs[outidx++] = mesg; if (purge) { /* we're taking this pointer away; subsequest history updates will eventually allocate a new one to replace it */ cw->data[inidx] = (char *) 0; cw->datlen[inidx] = 0; } } inidx = (inidx + 1) % cw->rows; } snapshot_mesgs[cw->rows] = (char *) 0; /* sentinel */ /* for a destructive snapshot, history is now completely empty */ if (purge) cw->maxcol = cw->maxrow = 0; } /* release memory allocated to message history snapshot */ STATIC_OVL void free_msghistory_snapshot(purged) boolean purged; /* True: took history's pointers, False: just cloned them */ { if (snapshot_mesgs) { /* snapshot pointers are no longer in use */ if (purged) { int i; for (i = 0; snapshot_mesgs[i]; ++i) free((genericptr_t) snapshot_mesgs[i]); } free((genericptr_t) snapshot_mesgs), snapshot_mesgs = (char **) 0; /* history can resume being updated at will now... */ if (!purged) wins[WIN_MESSAGE]->flags &= ~WIN_LOCKHISTORY; } } /* * This is called by the core save routines. * Each time we are called, we return one string from the * message history starting with the oldest message first. * When none are left, we return a final null string. * * History is collected at the time of the first call. * Any new messages issued after that point will not be * included among the output of the subsequent calls. */ char * tty_getmsghistory(init) boolean init; { static int nxtidx; char *nextmesg; char *result = 0; if (init) { msghistory_snapshot(FALSE); nxtidx = 0; } if (snapshot_mesgs) { nextmesg = snapshot_mesgs[nxtidx++]; if (nextmesg) { result = (char *) nextmesg; } else { free_msghistory_snapshot(FALSE); } } return result; } /* * This is called by the core savefile restore routines. * Each time we are called, we stuff the string into our message * history recall buffer. The core will send the oldest message * first (actually it sends them in the order they exist in the * save file, but that is supposed to be the oldest first). * These messages get pushed behind any which have been issued * since this session with the program has been started, since * they come from a previous session and logically precede * anything (like "Restoring save file...") that's happened now. * * Called with a null pointer to finish up restoration. * * It's also called by the quest pager code when a block message * has a one-line summary specified. We put that line directly * message history for ^P recall without having displayed it. */ void tty_putmsghistory(msg, restoring_msghist) const char *msg; boolean restoring_msghist; { static boolean initd = FALSE; int idx; if (restoring_msghist && !initd) { /* we're restoring history from the previous session, but new messages have already been issued this session ("Restoring...", for instance); collect current history (ie, those new messages), and also clear it out so that nothing will be present when the restored ones are being put into place */ msghistory_snapshot(TRUE); initd = TRUE; } if (msg) { /* move most recent message to history, make this become most recent */ remember_topl(); Strcpy(toplines, msg); } else if (snapshot_mesgs) { /* done putting arbitrary messages in; put the snapshot ones back */ for (idx = 0; snapshot_mesgs[idx]; ++idx) { remember_topl(); Strcpy(toplines, snapshot_mesgs[idx]); } /* now release the snapshot */ free_msghistory_snapshot(TRUE); initd = FALSE; /* reset */ } } #endif /* TTY_GRAPHICS */ /*topl.c*/ nethack-3.6.0/win/tty/wintty.c0000664000076400007660000034325012627562712015275 0ustar paxedpaxed/* NetHack 3.6 wintty.c $NHDT-Date: 1449052583 2015/12/02 10:36:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ /* * Neither a standard out nor character-based control codes should be * part of the "tty look" windowing implementation. * h+ 930227 */ /* It's still not clear I've caught all the cases for H2344. #undef this * to back out the changes. */ #define H2344_BROKEN #include "hack.h" #ifdef TTY_GRAPHICS #include "dlb.h" #ifdef MAC #define MICRO /* The Mac is a MICRO only for this file, not in general! */ #ifdef THINK_C extern void msmsg(const char *, ...); #endif #endif #ifndef NO_TERMS #include "tcap.h" #endif #include "wintty.h" #ifdef CLIPPING /* might want SIGWINCH */ #if defined(BSD) || defined(ULTRIX) || defined(AIX_31) \ || defined(_BULL_SOURCE) #include #endif #endif extern char mapped_menu_cmds[]; /* from options.c */ /* this is only needed until tty_status_* routines are written */ extern NEARDATA winid WIN_STATUS; /* Interface definition, for windows.c */ struct window_procs tty_procs = { "tty", #ifdef MSDOS WC_TILED_MAP | WC_ASCII_MAP | #endif #if defined(WIN32CON) WC_MOUSE_SUPPORT | #endif WC_COLOR | WC_HILITE_PET | WC_INVERSE | WC_EIGHT_BIT_IN, #if defined(SELECTSAVED) WC2_SELECTSAVED | #endif WC2_DARKGRAY, tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, tty_exit_nhwindows, tty_suspend_nhwindows, tty_resume_nhwindows, tty_create_nhwindow, tty_clear_nhwindow, tty_display_nhwindow, tty_destroy_nhwindow, tty_curs, tty_putstr, genl_putmixed, tty_display_file, tty_start_menu, tty_add_menu, tty_end_menu, tty_select_menu, tty_message_menu, tty_update_inventory, tty_mark_synch, tty_wait_synch, #ifdef CLIPPING tty_cliparound, #endif #ifdef POSITIONBAR tty_update_positionbar, #endif tty_print_glyph, tty_raw_print, tty_raw_print_bold, tty_nhgetch, tty_nh_poskey, tty_nhbell, tty_doprev_message, tty_yn_function, tty_getlin, tty_get_ext_cmd, tty_number_pad, tty_delay_output, #ifdef CHANGE_COLOR /* the Mac uses a palette device */ tty_change_color, #ifdef MAC tty_change_background, set_tty_font_name, #endif tty_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ tty_start_screen, tty_end_screen, genl_outrip, #if defined(WIN32) nttty_preference_update, #else genl_preference_update, #endif tty_getmsghistory, tty_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT tty_status_init, genl_status_finish, genl_status_enablefield, tty_status_update, #ifdef STATUS_HILITES tty_status_threshold, #endif #endif genl_can_suspend_yes, }; static int maxwin = 0; /* number of windows in use */ winid BASE_WINDOW; struct WinDesc *wins[MAXWIN]; struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ extern void FDECL(cmov, (int, int)); /* from termcap.c */ extern void FDECL(nocmov, (int, int)); /* from termcap.c */ #if defined(UNIX) || defined(VMS) static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ #endif static char winpanicstr[] = "Bad window id %d"; char defmorestr[] = "--More--"; #ifdef CLIPPING #if defined(USE_TILES) && defined(MSDOS) boolean clipping = FALSE; /* clipping on? */ int clipx = 0, clipxmax = 0; #else static boolean clipping = FALSE; /* clipping on? */ static int clipx = 0, clipxmax = 0; #endif static int clipy = 0, clipymax = 0; #endif /* CLIPPING */ #if defined(USE_TILES) && defined(MSDOS) extern void FDECL(adjust_cursor_flags, (struct WinDesc *)); #endif #if defined(ASCIIGRAPH) && !defined(NO_TERMS) boolean GFlag = FALSE; boolean HE_resets_AS; /* see termcap.c */ #endif #if defined(MICRO) || defined(WIN32CON) static const char to_continue[] = "to continue"; #define getret() getreturn(to_continue) #else STATIC_DCL void NDECL(getret); #endif STATIC_DCL void FDECL(erase_menu_or_text, (winid, struct WinDesc *, BOOLEAN_P)); STATIC_DCL void FDECL(free_window_info, (struct WinDesc *, BOOLEAN_P)); STATIC_DCL void FDECL(dmore, (struct WinDesc *, const char *)); STATIC_DCL void FDECL(set_item_state, (winid, int, tty_menu_item *)); STATIC_DCL void FDECL(set_all_on_page, (winid, tty_menu_item *, tty_menu_item *)); STATIC_DCL void FDECL(unset_all_on_page, (winid, tty_menu_item *, tty_menu_item *)); STATIC_DCL void FDECL(invert_all_on_page, (winid, tty_menu_item *, tty_menu_item *, CHAR_P)); STATIC_DCL void FDECL(invert_all, (winid, tty_menu_item *, tty_menu_item *, CHAR_P)); STATIC_DCL void FDECL(process_menu_window, (winid, struct WinDesc *)); STATIC_DCL void FDECL(process_text_window, (winid, struct WinDesc *)); STATIC_DCL tty_menu_item *FDECL(reverse, (tty_menu_item *)); STATIC_DCL const char *FDECL(compress_str, (const char *)); STATIC_DCL void FDECL(tty_putsym, (winid, int, int, CHAR_P)); STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ STATIC_DCL void FDECL(setup_rolemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); /* * A string containing all the default commands -- to add to a list * of acceptable inputs. */ static const char default_menu_cmds[] = { MENU_FIRST_PAGE, MENU_LAST_PAGE, MENU_NEXT_PAGE, MENU_PREVIOUS_PAGE, MENU_SELECT_ALL, MENU_UNSELECT_ALL, MENU_INVERT_ALL, MENU_SELECT_PAGE, MENU_UNSELECT_PAGE, MENU_INVERT_PAGE, MENU_SEARCH, 0 /* null terminator */ }; /* clean up and quit */ STATIC_OVL void bail(mesg) const char *mesg; { clearlocks(); tty_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } #if defined(SIGWINCH) && defined(CLIPPING) STATIC_OVL void winch() { int oldLI = LI, oldCO = CO, i; register struct WinDesc *cw; #ifdef WINCHAIN { #define WINCH_MESSAGE "(SIGWINCH)" if (wc_tracelogf) (void) write(fileno(wc_tracelogf), WINCH_MESSAGE, strlen(WINCH_MESSAGE)); #undef WINCH_MESSAGE } #endif getwindowsz(); /* For long running events such as multi-page menus and * display_file(), we note the signal's occurance and * hope the code there decides to handle the situation * and reset the flag. There will be race conditions * when handling this - code handlers so it doesn't matter. */ #ifdef notyet winch_seen = TRUE; #endif if ((oldLI != LI || oldCO != CO) && ttyDisplay) { ttyDisplay->rows = LI; ttyDisplay->cols = CO; cw = wins[BASE_WINDOW]; cw->rows = ttyDisplay->rows; cw->cols = ttyDisplay->cols; if (iflags.window_inited) { cw = wins[WIN_MESSAGE]; cw->curx = cw->cury = 0; tty_destroy_nhwindow(WIN_STATUS); WIN_STATUS = tty_create_nhwindow(NHW_STATUS); if (u.ux) { #ifdef CLIPPING if (CO < COLNO || LI < ROWNO + 3) { setclipped(); tty_cliparound(u.ux, u.uy); } else { clipping = FALSE; clipx = clipy = 0; } #endif i = ttyDisplay->toplin; ttyDisplay->toplin = 0; docrt(); bot(); ttyDisplay->toplin = i; flush_screen(1); if (i) { addtopl(toplines); } else for (i = WIN_INVEN; i < MAXWIN; i++) if (wins[i] && wins[i]->active) { /* cop-out */ addtopl("Press Return to continue: "); break; } (void) fflush(stdout); if (i < 2) flush_screen(1); } } } } #endif /*ARGSUSED*/ void tty_init_nhwindows(argcp, argv) int *argcp UNUSED; char **argv UNUSED; { int wid, hgt, i; /* * Remember tty modes, to be restored on exit. * * gettty() must be called before tty_startup() * due to ordering of LI/CO settings * tty_startup() must be called before initoptions() * due to ordering of graphics settings */ #if defined(UNIX) || defined(VMS) setbuf(stdout, obuf); #endif gettty(); /* to port dependant tty setup */ tty_startup(&wid, &hgt); setftty(); /* calls start_screen */ /* set up tty descriptor */ ttyDisplay = (struct DisplayDesc *) alloc(sizeof(struct DisplayDesc)); ttyDisplay->toplin = 0; ttyDisplay->rows = hgt; ttyDisplay->cols = wid; ttyDisplay->curx = ttyDisplay->cury = 0; ttyDisplay->inmore = ttyDisplay->inread = ttyDisplay->intr = 0; ttyDisplay->dismiss_more = 0; #ifdef TEXTCOLOR ttyDisplay->color = NO_COLOR; #endif ttyDisplay->attrs = 0; /* set up the default windows */ BASE_WINDOW = tty_create_nhwindow(NHW_BASE); wins[BASE_WINDOW]->active = 1; ttyDisplay->lastwin = WIN_ERR; #if defined(SIGWINCH) && defined(CLIPPING) && !defined(NO_SIGNAL) (void) signal(SIGWINCH, winch); #endif /* add one a space forward menu command alias */ add_menu_cmd_alias(' ', MENU_NEXT_PAGE); tty_clear_nhwindow(BASE_WINDOW); tty_putstr(BASE_WINDOW, 0, ""); for (i = 1; i <= 4; ++i) tty_putstr(BASE_WINDOW, 0, copyright_banner_line(i)); tty_putstr(BASE_WINDOW, 0, ""); tty_display_nhwindow(BASE_WINDOW, FALSE); } /* try to reduce clutter in the code below... */ #define ROLE flags.initrole #define RACE flags.initrace #define GEND flags.initgend #define ALGN flags.initalign void tty_player_selection() { int i, k, n, choice, nextpick; boolean getconfirmation; char pick4u = 'n'; char pbuf[QBUFSZ], plbuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; if (flags.randomall) { if (ROLE == ROLE_NONE) ROLE = ROLE_RANDOM; if (RACE == ROLE_NONE) RACE = ROLE_RANDOM; if (GEND == ROLE_NONE) GEND = ROLE_RANDOM; if (ALGN == ROLE_NONE) ALGN = ROLE_RANDOM; } /* prevent an unnecessary prompt */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (ROLE == ROLE_NONE || RACE == ROLE_NONE || GEND == ROLE_NONE || ALGN == ROLE_NONE) { int echoline; char *prompt = build_plselection_prompt(pbuf, QBUFSZ, ROLE, RACE, GEND, ALGN); /* this prompt string ends in "[ynaq]?": y - game picks role,&c then asks player to confirm; n - player manually chooses via menu selections; a - like 'y', but skips confirmation and starts game; q - quit */ tty_putstr(BASE_WINDOW, 0, ""); echoline = wins[BASE_WINDOW]->cury; tty_putstr(BASE_WINDOW, 0, prompt); do { pick4u = lowc(readchar()); if (index(quitchars, pick4u)) pick4u = 'y'; } while (!index(ynaqchars, pick4u)); if ((int) strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ tty_putsym(BASE_WINDOW, (int) strlen(prompt) + 1, echoline, pick4u); tty_putstr(BASE_WINDOW, 0, ""); } else /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ tty_clear_nhwindow(BASE_WINDOW); if (pick4u != 'y' && pick4u != 'a' && pick4u != 'n') goto give_up; } makepicks: nextpick = RS_ROLE; do { if (nextpick == RS_ROLE) { nextpick = RS_RACE; /* Select a role, if necessary; we'll try to be compatible with pre-selected race/gender/alignment, but may not succeed. */ if (ROLE < 0) { /* Process the choice */ if (pick4u == 'y' || pick4u == 'a' || ROLE == ROLE_RANDOM) { /* Pick a random role */ k = pick_role(RACE, GEND, ALGN, PICK_RANDOM); if (k < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); k = randrole(); } } else { /* Prompt for a role */ tty_clear_nhwindow(BASE_WINDOW); role_selection_prolog(RS_ROLE, BASE_WINDOW); win = create_nhwindow(NHW_MENU); start_menu(win); /* populate the menu with role choices */ setup_rolemenu(win, TRUE, RACE, GEND, ALGN); /* add miscellaneous menu entries */ role_menu_extra(ROLE_RANDOM, win); any.a_int = 0; /* separator, not a choice */ add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "", MENU_UNSELECTED); role_menu_extra(RS_RACE, win); role_menu_extra(RS_GENDER, win); role_menu_extra(RS_ALGNMNT, win); if (gotrolefilter()) role_menu_extra(RS_filter, win); role_menu_extra(ROLE_NONE, win); /* quit */ Strcpy(pbuf, "Pick a role or profession"); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); if (choice == ROLE_NONE) { goto give_up; /* Selected quit */ } else if (choice == RS_menu_arg(RS_ALGNMNT)) { ALGN = k = ROLE_NONE; nextpick = RS_ALGNMNT; } else if (choice == RS_menu_arg(RS_GENDER)) { GEND = k = ROLE_NONE; nextpick = RS_GENDER; } else if (choice == RS_menu_arg(RS_RACE)) { RACE = k = ROLE_NONE; nextpick = RS_RACE; } else if (choice == RS_menu_arg(RS_filter)) { ROLE = k = ROLE_NONE; (void) reset_role_filtering(); nextpick = RS_ROLE; } else if (choice == ROLE_RANDOM) { k = pick_role(RACE, GEND, ALGN, PICK_RANDOM); if (k < 0) k = randrole(); } else { k = choice - 1; } } ROLE = k; } /* needed role */ } /* picking role */ if (nextpick == RS_RACE) { nextpick = (ROLE < 0) ? RS_ROLE : RS_GENDER; /* Select a race, if necessary; force compatibility with role, try for compatibility with pre-selected gender/alignment. */ if (RACE < 0 || !validrace(ROLE, RACE)) { /* no race yet, or pre-selected race not valid */ if (pick4u == 'y' || pick4u == 'a' || RACE == ROLE_RANDOM) { k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM); if (k < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); k = randrace(ROLE); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) if (ok_race(ROLE, i, GEND, ALGN)) { n++; k = i; } if (n == 0) { for (i = 0; races[i].noun; i++) if (validrace(ROLE, i)) { n++; k = i; } } /* Permit the user to pick, if there is more than one */ if (n > 1) { tty_clear_nhwindow(BASE_WINDOW); role_selection_prolog(RS_RACE, BASE_WINDOW); win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ /* populate the menu with role choices */ setup_racemenu(win, TRUE, ROLE, GEND, ALGN); /* add miscellaneous menu entries */ role_menu_extra(ROLE_RANDOM, win); any.a_int = 0; /* separator, not a choice */ add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "", MENU_UNSELECTED); role_menu_extra(RS_ROLE, win); role_menu_extra(RS_GENDER, win); role_menu_extra(RS_ALGNMNT, win); if (gotrolefilter()) role_menu_extra(RS_filter, win); role_menu_extra(ROLE_NONE, win); /* quit */ Strcpy(pbuf, "Pick a race or species"); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); if (choice == ROLE_NONE) { goto give_up; /* Selected quit */ } else if (choice == RS_menu_arg(RS_ALGNMNT)) { ALGN = k = ROLE_NONE; nextpick = RS_ALGNMNT; } else if (choice == RS_menu_arg(RS_GENDER)) { GEND = k = ROLE_NONE; nextpick = RS_GENDER; } else if (choice == RS_menu_arg(RS_ROLE)) { ROLE = k = ROLE_NONE; nextpick = RS_ROLE; } else if (choice == RS_menu_arg(RS_filter)) { RACE = k = ROLE_NONE; if (reset_role_filtering()) nextpick = RS_ROLE; else nextpick = RS_RACE; } else if (choice == ROLE_RANDOM) { k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM); if (k < 0) k = randrace(ROLE); } else { k = choice - 1; } } } RACE = k; } /* needed race */ } /* picking race */ if (nextpick == RS_GENDER) { nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE : RS_ALGNMNT; /* Select a gender, if necessary; force compatibility with role/race, try for compatibility with pre-selected alignment. */ if (GEND < 0 || !validgend(ROLE, RACE, GEND)) { /* no gender yet, or pre-selected gender not valid */ if (pick4u == 'y' || pick4u == 'a' || GEND == ROLE_RANDOM) { k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM); if (k < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); k = randgend(ROLE, RACE); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(ROLE, RACE, i, ALGN)) { n++; k = i; } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) if (validgend(ROLE, RACE, i)) { n++; k = i; } } /* Permit the user to pick, if there is more than one */ if (n > 1) { tty_clear_nhwindow(BASE_WINDOW); role_selection_prolog(RS_GENDER, BASE_WINDOW); win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ /* populate the menu with gender choices */ setup_gendmenu(win, TRUE, ROLE, RACE, ALGN); /* add miscellaneous menu entries */ role_menu_extra(ROLE_RANDOM, win); any.a_int = 0; /* separator, not a choice */ add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "", MENU_UNSELECTED); role_menu_extra(RS_ROLE, win); role_menu_extra(RS_RACE, win); role_menu_extra(RS_ALGNMNT, win); if (gotrolefilter()) role_menu_extra(RS_filter, win); role_menu_extra(ROLE_NONE, win); /* quit */ Strcpy(pbuf, "Pick a gender or sex"); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); if (choice == ROLE_NONE) { goto give_up; /* Selected quit */ } else if (choice == RS_menu_arg(RS_ALGNMNT)) { ALGN = k = ROLE_NONE; nextpick = RS_ALGNMNT; } else if (choice == RS_menu_arg(RS_RACE)) { RACE = k = ROLE_NONE; nextpick = RS_RACE; } else if (choice == RS_menu_arg(RS_ROLE)) { ROLE = k = ROLE_NONE; nextpick = RS_ROLE; } else if (choice == RS_menu_arg(RS_filter)) { GEND = k = ROLE_NONE; if (reset_role_filtering()) nextpick = RS_ROLE; else nextpick = RS_GENDER; } else if (choice == ROLE_RANDOM) { k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM); if (k < 0) k = randgend(ROLE, RACE); } else { k = choice - 1; } } } GEND = k; } /* needed gender */ } /* picking gender */ if (nextpick == RS_ALGNMNT) { nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE : RS_GENDER; /* Select an alignment, if necessary; force compatibility with role/race/gender. */ if (ALGN < 0 || !validalign(ROLE, RACE, ALGN)) { /* no alignment yet, or pre-selected alignment not valid */ if (pick4u == 'y' || pick4u == 'a' || ALGN == ROLE_RANDOM) { k = pick_align(ROLE, RACE, GEND, PICK_RANDOM); if (k < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); k = randalign(ROLE, RACE); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(ROLE, RACE, GEND, i)) { n++; k = i; } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) if (validalign(ROLE, RACE, i)) { n++; k = i; } } /* Permit the user to pick, if there is more than one */ if (n > 1) { tty_clear_nhwindow(BASE_WINDOW); role_selection_prolog(RS_ALGNMNT, BASE_WINDOW); win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ setup_algnmenu(win, TRUE, ROLE, RACE, GEND); role_menu_extra(ROLE_RANDOM, win); any.a_int = 0; /* separator, not a choice */ add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "", MENU_UNSELECTED); role_menu_extra(RS_ROLE, win); role_menu_extra(RS_RACE, win); role_menu_extra(RS_GENDER, win); if (gotrolefilter()) role_menu_extra(RS_filter, win); role_menu_extra(ROLE_NONE, win); /* quit */ Strcpy(pbuf, "Pick an alignment or creed"); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); if (choice == ROLE_NONE) { goto give_up; /* Selected quit */ } else if (choice == RS_menu_arg(RS_GENDER)) { GEND = k = ROLE_NONE; nextpick = RS_GENDER; } else if (choice == RS_menu_arg(RS_RACE)) { RACE = k = ROLE_NONE; nextpick = RS_RACE; } else if (choice == RS_menu_arg(RS_ROLE)) { ROLE = k = ROLE_NONE; nextpick = RS_ROLE; } else if (choice == RS_menu_arg(RS_filter)) { ALGN = k = ROLE_NONE; if (reset_role_filtering()) nextpick = RS_ROLE; else nextpick = RS_ALGNMNT; } else if (choice == ROLE_RANDOM) { k = pick_align(ROLE, RACE, GEND, PICK_RANDOM); if (k < 0) k = randalign(ROLE, RACE); } else { k = choice - 1; } } } ALGN = k; } /* needed alignment */ } /* picking alignment */ } while (ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0); /* * Role, race, &c have now been determined; * ask for confirmation and maybe go back to choose all over again. * * Uses ynaq for familiarity, although 'a' is usually a * superset of 'y' but here is an alternate form of 'n'. * Menu layout: * title: Is this ok? [ynaq] * blank: * text: $name, $alignment $gender $race $role * blank: * menu: y + yes; play * n - no; pick again * maybe: a - no; rename hero * q - quit * (end) */ getconfirmation = (pick4u != 'a' && !flags.randomall); while (getconfirmation) { tty_clear_nhwindow(BASE_WINDOW); role_selection_prolog(ROLE_NONE, BASE_WINDOW); win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ any.a_int = 0; if (!roles[ROLE].name.f && (roles[ROLE].allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)) Sprintf(plbuf, " %s", genders[GEND].adj); else *plbuf = '\0'; /* omit redundant gender */ Sprintf(pbuf, "%s, %s%s %s %s", plname, aligns[ALGN].adj, plbuf, races[RACE].adj, (GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f : roles[ROLE].name.m); add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, pbuf, MENU_UNSELECTED); /* blank separator */ any.a_int = 0; add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "", MENU_UNSELECTED); /* [ynaq] menu choices */ any.a_int = 1; add_menu(win, NO_GLYPH, &any, 'y', 0, ATR_NONE, "Yes; start game", MENU_SELECTED); any.a_int = 2; add_menu(win, NO_GLYPH, &any, 'n', 0, ATR_NONE, "No; choose role again", MENU_UNSELECTED); if (iflags.renameallowed) { any.a_int = 3; add_menu(win, NO_GLYPH, &any, 'a', 0, ATR_NONE, "Not yet; choose another name", MENU_UNSELECTED); } any.a_int = -1; add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Is this ok? [yn%sq]", iflags.renameallowed ? "a" : ""); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); /* [pick-one menus with a preselected entry behave oddly...] */ choice = (n > 0) ? selected[n - 1].item.a_int : (n == 0) ? 1 : -1; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); switch (choice) { default: /* 'q' or ESC */ goto give_up; /* quit */ break; case 3: { /* 'a' */ /* * TODO: what, if anything, should be done if the name is * changed to or from "wizard" after port-specific startup * code has set flags.debug based on the original name? */ int saveROLE, saveRACE, saveGEND, saveALGN; iflags.renameinprogress = TRUE; /* plnamesuffix() can change any or all of ROLE, RACE, GEND, ALGN; we'll override that and honor only the name */ saveROLE = ROLE, saveRACE = RACE, saveGEND = GEND, saveALGN = ALGN; *plname = '\0'; plnamesuffix(); /* calls askname() when plname[] is empty */ ROLE = saveROLE, RACE = saveRACE, GEND = saveGEND, ALGN = saveALGN; break; /* getconfirmation is still True */ } case 2: /* 'n' */ /* start fresh, but bypass "shall I pick everything for you?" step; any partial role selection via config file, command line, or name suffix is discarded this time */ pick4u = 'n'; ROLE = RACE = GEND = ALGN = ROLE_NONE; goto makepicks; break; case 1: /* 'y' or Space or Return/Enter */ /* success; drop out through end of function */ getconfirmation = FALSE; break; } } /* Success! */ tty_display_nhwindow(BASE_WINDOW, FALSE); return; give_up: /* Quit */ if (selected) free((genericptr_t) selected); /* [obsolete] */ bail((char *) 0); /*NOTREACHED*/ return; } STATIC_OVL boolean reset_role_filtering() { winid win; anything any; int i, n; menu_item *selected = 0; win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* no extra blank line preceding this entry; end_menu supplies one */ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "Unacceptable roles", MENU_UNSELECTED); setup_rolemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "Unacceptable races", MENU_UNSELECTED); setup_racemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "Unacceptable genders", MENU_UNSELECTED); setup_gendmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "Uncceptable alignments", MENU_UNSELECTED); setup_algnmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); end_menu(win, "Pick all that apply"); n = select_menu(win, PICK_ANY, &selected); if (n > 0) { clearrolefilter(); for (i = 0; i < n; i++) setrolefilter(selected[i].item.a_string); ROLE = RACE = GEND = ALGN = ROLE_NONE; } if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); return (n > 0) ? TRUE : FALSE; } #undef ROLE #undef RACE #undef GEND #undef ALGN /* add entries a-Archeologist, b-Barbarian, &c to menu being built in 'win' */ STATIC_OVL void setup_rolemenu(win, filtering, race, gend, algn) winid win; boolean filtering; /* True => exclude filtered roles; False => filter reset */ int race, gend, algn; /* all ROLE_NONE for !filtering case */ { anything any; int i; boolean role_ok; char thisch, lastch = '\0', rolenamebuf[50]; any = zeroany; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { role_ok = ok_role(i, race, gend, algn); if (filtering && !role_ok) continue; if (filtering) any.a_int = i + 1; else any.a_string = roles[i].name.m; thisch = lowc(*roles[i].name.m); if (thisch == lastch) thisch = highc(thisch); Strcpy(rolenamebuf, roles[i].name.m); if (roles[i].name.f) { /* role has distinct name for female (C,P) */ if (gend == 1) { /* female already chosen; replace male name */ Strcpy(rolenamebuf, roles[i].name.f); } else if (gend < 0) { /* not chosen yet; append slash+female name */ Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } } /* !filtering implies reset_role_filtering() where we want to mark this role as preseleted if current filter excludes it */ add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), (!filtering && !role_ok) ? MENU_SELECTED : MENU_UNSELECTED); lastch = thisch; } } STATIC_OVL void setup_racemenu(win, filtering, role, gend, algn) winid win; boolean filtering; int role, gend, algn; { anything any; boolean race_ok; int i; char this_ch; any = zeroany; for (i = 0; races[i].noun; i++) { race_ok = ok_race(role, i, gend, algn); if (filtering && !race_ok) continue; if (filtering) any.a_int = i + 1; else any.a_string = races[i].noun; this_ch = *races[i].noun; /* filtering: picking race, so choose by first letter, with capital letter as unseen accelerator; !filtering: resetting filter rather than picking, choose by capital letter since lowercase role letters will be present */ add_menu(win, NO_GLYPH, &any, filtering ? this_ch : highc(this_ch), filtering ? highc(this_ch) : 0, ATR_NONE, races[i].noun, (!filtering && !race_ok) ? MENU_SELECTED : MENU_UNSELECTED); } } STATIC_DCL void setup_gendmenu(win, filtering, role, race, algn) winid win; boolean filtering; int role, race, algn; { anything any; boolean gend_ok; int i; char this_ch; any = zeroany; for (i = 0; i < ROLE_GENDERS; i++) { gend_ok = ok_gend(role, race, i, algn); if (filtering && !gend_ok) continue; if (filtering) any.a_int = i + 1; else any.a_string = genders[i].adj; this_ch = *genders[i].adj; /* (see setup_racemenu for explanation of selector letters and setup_rolemenu for preselection) */ add_menu(win, NO_GLYPH, &any, filtering ? this_ch : highc(this_ch), filtering ? highc(this_ch) : 0, ATR_NONE, genders[i].adj, (!filtering && !gend_ok) ? MENU_SELECTED : MENU_UNSELECTED); } } STATIC_DCL void setup_algnmenu(win, filtering, role, race, gend) winid win; boolean filtering; int role, race, gend; { anything any; boolean algn_ok; int i; char this_ch; any = zeroany; for (i = 0; i < ROLE_ALIGNS; i++) { algn_ok = ok_align(role, race, gend, i); if (filtering && !algn_ok) continue; if (filtering) any.a_int = i + 1; else any.a_string = aligns[i].adj; this_ch = *aligns[i].adj; /* (see setup_racemenu for explanation of selector letters and setup_rolemenu for preselection) */ add_menu(win, NO_GLYPH, &any, filtering ? this_ch : highc(this_ch), filtering ? highc(this_ch) : 0, ATR_NONE, aligns[i].adj, (!filtering && !algn_ok) ? MENU_SELECTED : MENU_UNSELECTED); } } /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting the role, etc. * Always called after init_nhwindows() and before display_gamewindows(). */ void tty_askname() { static const char who_are_you[] = "Who are you? "; register int c, ct, tryct = 0; #ifdef SELECTSAVED if (iflags.wc2_selectsaved && !iflags.renameinprogress) switch (restore_menu(BASE_WINDOW)) { case -1: bail("Until next time then..."); /* quit */ /*NOTREACHED*/ case 0: break; /* no game chosen; start new game */ case 1: return; /* plname[] has been set */ } #endif /* SELECTSAVED */ tty_putstr(BASE_WINDOW, 0, ""); do { if (++tryct > 1) { if (tryct > 10) bail("Giving up after 10 tries.\n"); tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury - 1); tty_putstr(BASE_WINDOW, 0, "Enter a name for your character..."); /* erase previous prompt (in case of ESC after partial response) */ tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury), cl_end(); } tty_putstr(BASE_WINDOW, 0, who_are_you); tty_curs(BASE_WINDOW, (int) (sizeof who_are_you), wins[BASE_WINDOW]->cury - 1); ct = 0; while ((c = tty_nhgetch()) != '\n') { if (c == EOF) c = '\033'; if (c == '\033') { ct = 0; break; } /* continue outer loop */ #if defined(WIN32CON) if (c == '\003') bail("^C abort.\n"); #endif /* some people get confused when their erase char is not ^H */ if (c == '\b' || c == '\177') { if (ct) { ct--; #ifdef WIN32CON ttyDisplay->curx--; #endif #if defined(MICRO) || defined(WIN32CON) #if defined(WIN32CON) || defined(MSDOS) backsp(); /* \b is visible on NT */ (void) putchar(' '); backsp(); #else msmsg("\b \b"); #endif #else (void) putchar('\b'); (void) putchar(' '); (void) putchar('\b'); #endif } continue; } #if defined(UNIX) || defined(VMS) if (c != '-' && c != '@') if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && /* reject leading digit but allow digits elsewhere (avoids ambiguity when character name gets appended to uid to construct save file name) */ !(c >= '0' && c <= '9' && ct > 0)) c = '_'; #endif if (ct < (int) (sizeof plname) - 1) { #if defined(MICRO) #if defined(MSDOS) if (iflags.grmode) { (void) putchar(c); } else #endif msmsg("%c", c); #else (void) putchar(c); #endif plname[ct++] = c; #ifdef WIN32CON ttyDisplay->curx++; #endif } } plname[ct] = 0; } while (ct == 0); /* move to next line to simulate echo of user's */ tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury + 1); /* since we let user pick an arbitrary name now, he/she can pick another one during role selection */ iflags.renameallowed = TRUE; } void tty_get_nh_event() { return; } #if !defined(MICRO) && !defined(WIN32CON) STATIC_OVL void getret() { xputs("\n"); if (flags.standout) standoutbeg(); xputs("Hit "); xputs(iflags.cbreak ? "space" : "return"); xputs(" to continue: "); if (flags.standout) standoutend(); xwaitforspace(" "); } #endif void tty_suspend_nhwindows(str) const char *str; { settty(str); /* calls end_screen, perhaps raw_print */ if (!str) tty_raw_print(""); /* calls fflush(stdout) */ } void tty_resume_nhwindows() { gettty(); setftty(); /* calls start_screen */ docrt(); } void tty_exit_nhwindows(str) const char *str; { winid i; tty_suspend_nhwindows(str); /* * Disable windows to avoid calls to window routines. */ free_pickinv_cache(); /* reset its state as well as tear down window */ for (i = 0; i < MAXWIN; i++) { if (i == BASE_WINDOW) continue; /* handle wins[BASE_WINDOW] last */ if (wins[i]) { #ifdef FREE_ALL_MEMORY free_window_info(wins[i], TRUE); free((genericptr_t) wins[i]); #endif wins[i] = (struct WinDesc *) 0; } } WIN_MAP = WIN_MESSAGE = WIN_INVEN = WIN_ERR; /* these are all gone now */ #ifndef STATUS_VIA_WINDOWPORT WIN_STATUS = WIN_ERR; #endif #ifdef FREE_ALL_MEMORY if (BASE_WINDOW != WIN_ERR && wins[BASE_WINDOW]) { free_window_info(wins[BASE_WINDOW], TRUE); free((genericptr_t) wins[BASE_WINDOW]); wins[BASE_WINDOW] = (struct WinDesc *) 0; BASE_WINDOW = WIN_ERR; } free((genericptr_t) ttyDisplay); ttyDisplay = (struct DisplayDesc *) 0; #endif #ifndef NO_TERMS /*(until this gets added to the window interface)*/ tty_shutdown(); /* cleanup termcap/terminfo/whatever */ #endif iflags.window_inited = 0; } winid tty_create_nhwindow(type) int type; { struct WinDesc *newwin; int i; int newid; if (maxwin == MAXWIN) return WIN_ERR; newwin = (struct WinDesc *) alloc(sizeof(struct WinDesc)); newwin->type = type; newwin->flags = 0; newwin->active = FALSE; newwin->curx = newwin->cury = 0; newwin->morestr = 0; newwin->mlist = (tty_menu_item *) 0; newwin->plist = (tty_menu_item **) 0; newwin->npages = newwin->plist_size = newwin->nitems = newwin->how = 0; switch (type) { case NHW_BASE: /* base window, used for absolute movement on the screen */ newwin->offx = newwin->offy = 0; newwin->rows = ttyDisplay->rows; newwin->cols = ttyDisplay->cols; newwin->maxrow = newwin->maxcol = 0; break; case NHW_MESSAGE: /* message window, 1 line long, very wide, top of screen */ newwin->offx = newwin->offy = 0; /* sanity check */ if (iflags.msg_history < 20) iflags.msg_history = 20; else if (iflags.msg_history > 60) iflags.msg_history = 60; newwin->maxrow = newwin->rows = iflags.msg_history; newwin->maxcol = newwin->cols = 0; break; case NHW_STATUS: /* status window, 2 lines long, full width, bottom of screen */ newwin->offx = 0; #if defined(USE_TILES) && defined(MSDOS) if (iflags.grmode) { newwin->offy = ttyDisplay->rows - 2; } else #endif newwin->offy = min((int) ttyDisplay->rows - 2, ROWNO + 1); newwin->rows = newwin->maxrow = 2; newwin->cols = newwin->maxcol = ttyDisplay->cols; break; case NHW_MAP: /* map window, ROWNO lines long, full width, below message window */ newwin->offx = 0; newwin->offy = 1; newwin->rows = ROWNO; newwin->cols = COLNO; newwin->maxrow = 0; /* no buffering done -- let gbuf do it */ newwin->maxcol = 0; break; case NHW_MENU: case NHW_TEXT: /* inventory/menu window, variable length, full width, top of screen */ /* help window, the same, different semantics for display, etc */ newwin->offx = newwin->offy = 0; newwin->rows = 0; newwin->cols = ttyDisplay->cols; newwin->maxrow = newwin->maxcol = 0; break; default: panic("Tried to create window type %d\n", (int) type); return WIN_ERR; } for (newid = 0; newid < MAXWIN; newid++) { if (wins[newid] == 0) { wins[newid] = newwin; break; } } if (newid == MAXWIN) { panic("No window slots!"); return WIN_ERR; } if (newwin->maxrow) { newwin->data = (char **) alloc(sizeof(char *) * (unsigned) newwin->maxrow); newwin->datlen = (short *) alloc(sizeof(short) * (unsigned) newwin->maxrow); if (newwin->maxcol) { /* WIN_STATUS */ for (i = 0; i < newwin->maxrow; i++) { newwin->data[i] = (char *) alloc((unsigned) newwin->maxcol); newwin->datlen[i] = (short) newwin->maxcol; } } else { for (i = 0; i < newwin->maxrow; i++) { newwin->data[i] = (char *) 0; newwin->datlen[i] = 0; } } if (newwin->type == NHW_MESSAGE) newwin->maxrow = 0; } else { newwin->data = (char **) 0; newwin->datlen = (short *) 0; } return newid; } STATIC_OVL void erase_menu_or_text(window, cw, clear) winid window; struct WinDesc *cw; boolean clear; { if (cw->offx == 0) if (cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else if (clear) clear_screen(); else docrt(); else docorner((int) cw->offx, cw->maxrow + 1); } STATIC_OVL void free_window_info(cw, free_data) struct WinDesc *cw; boolean free_data; { int i; if (cw->data) { if (cw == wins[WIN_MESSAGE] && cw->rows > cw->maxrow) cw->maxrow = cw->rows; /* topl data */ for (i = 0; i < cw->maxrow; i++) if (cw->data[i]) { free((genericptr_t) cw->data[i]); cw->data[i] = (char *) 0; if (cw->datlen) cw->datlen[i] = 0; } if (free_data) { free((genericptr_t) cw->data); cw->data = (char **) 0; if (cw->datlen) free((genericptr_t) cw->datlen); cw->datlen = (short *) 0; cw->rows = 0; } } cw->maxrow = cw->maxcol = 0; if (cw->mlist) { tty_menu_item *temp; while ((temp = cw->mlist) != 0) { cw->mlist = cw->mlist->next; if (temp->str) free((genericptr_t) temp->str); free((genericptr_t) temp); } } if (cw->plist) { free((genericptr_t) cw->plist); cw->plist = 0; } cw->plist_size = cw->npages = cw->nitems = cw->how = 0; if (cw->morestr) { free((genericptr_t) cw->morestr); cw->morestr = 0; } } void tty_clear_nhwindow(window) winid window; { register struct WinDesc *cw = 0; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); ttyDisplay->lastwin = window; switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) { home(); cl_end(); if (cw->cury) docorner(1, cw->cury + 1); ttyDisplay->toplin = 0; } break; case NHW_STATUS: tty_curs(window, 1, 0); cl_end(); tty_curs(window, 1, 1); cl_end(); break; case NHW_MAP: /* cheap -- clear the whole thing and tell nethack to redraw botl */ context.botlx = 1; /* fall into ... */ case NHW_BASE: clear_screen(); break; case NHW_MENU: case NHW_TEXT: if (cw->active) erase_menu_or_text(window, cw, TRUE); free_window_info(cw, FALSE); break; } cw->curx = cw->cury = 0; } boolean toggle_menu_curr(window, curr, lineno, in_view, counting, count) winid window; tty_menu_item *curr; int lineno; boolean in_view, counting; long count; { if (curr->selected) { if (counting && count > 0) { curr->count = count; if (in_view) set_item_state(window, lineno, curr); return TRUE; } else { /* change state */ curr->selected = FALSE; curr->count = -1L; if (in_view) set_item_state(window, lineno, curr); return TRUE; } } else { /* !selected */ if (counting && count > 0) { curr->count = count; curr->selected = TRUE; if (in_view) set_item_state(window, lineno, curr); return TRUE; } else if (!counting) { curr->selected = TRUE; if (in_view) set_item_state(window, lineno, curr); return TRUE; } /* do nothing counting&&count==0 */ } return FALSE; } STATIC_OVL void dmore(cw, s) register struct WinDesc *cw; const char *s; /* valid responses */ { const char *prompt = cw->morestr ? cw->morestr : defmorestr; int offset = (cw->type == NHW_TEXT) ? 1 : 2; tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + offset, (int) ttyDisplay->cury); if (flags.standout) standoutbeg(); xputs(prompt); ttyDisplay->curx += strlen(prompt); if (flags.standout) standoutend(); xwaitforspace(s); } STATIC_OVL void set_item_state(window, lineno, item) winid window; int lineno; tty_menu_item *item; { char ch = item->selected ? (item->count == -1L ? '+' : '#') : '-'; tty_curs(window, 4, lineno); term_start_attr(item->attr); (void) putchar(ch); ttyDisplay->curx++; term_end_attr(item->attr); } STATIC_OVL void set_all_on_page(window, page_start, page_end) winid window; tty_menu_item *page_start, *page_end; { tty_menu_item *curr; int n; for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (curr->identifier.a_void && !curr->selected) { curr->selected = TRUE; set_item_state(window, n, curr); } } STATIC_OVL void unset_all_on_page(window, page_start, page_end) winid window; tty_menu_item *page_start, *page_end; { tty_menu_item *curr; int n; for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (curr->identifier.a_void && curr->selected) { curr->selected = FALSE; curr->count = -1L; set_item_state(window, n, curr); } } STATIC_OVL void invert_all_on_page(window, page_start, page_end, acc) winid window; tty_menu_item *page_start, *page_end; char acc; /* group accelerator, 0 => all */ { tty_menu_item *curr; int n; for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (curr->identifier.a_void && (acc == 0 || curr->gselector == acc)) { if (curr->selected) { curr->selected = FALSE; curr->count = -1L; } else curr->selected = TRUE; set_item_state(window, n, curr); } } /* * Invert all entries that match the give group accelerator (or all if zero). */ STATIC_OVL void invert_all(window, page_start, page_end, acc) winid window; tty_menu_item *page_start, *page_end; char acc; /* group accelerator, 0 => all */ { tty_menu_item *curr; boolean on_curr_page; struct WinDesc *cw = wins[window]; invert_all_on_page(window, page_start, page_end, acc); /* invert the rest */ for (on_curr_page = FALSE, curr = cw->mlist; curr; curr = curr->next) { if (curr == page_start) on_curr_page = TRUE; else if (curr == page_end) on_curr_page = FALSE; if (!on_curr_page && curr->identifier.a_void && (acc == 0 || curr->gselector == acc)) { if (curr->selected) { curr->selected = FALSE; curr->count = -1; } else curr->selected = TRUE; } } } STATIC_OVL void process_menu_window(window, cw) winid window; struct WinDesc *cw; { tty_menu_item *page_start, *page_end, *curr; long count; int n, curr_page, page_lines, resp_len; boolean finished, counting, reset_count; char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ], *msave, *morestr, really_morc; #define MENU_EXPLICIT_CHOICE 0x7f /* pseudo menu manipulation char */ curr_page = page_lines = 0; page_start = page_end = 0; msave = cw->morestr; /* save the morestr */ cw->morestr = morestr = (char *) alloc((unsigned) QBUFSZ); counting = FALSE; count = 0L; reset_count = TRUE; finished = FALSE; /* collect group accelerators; for PICK_NONE, they're ignored; for PICK_ONE, only those which match exactly one entry will be accepted; for PICK_ANY, those which match any entry are okay */ gacc[0] = '\0'; if (cw->how != PICK_NONE) { int i, gcnt[128]; #define GSELIDX(c) (c & 127) /* guard against `signed char' */ for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0; for (n = 0, curr = cw->mlist; curr; curr = curr->next) if (curr->gselector && curr->gselector != curr->selector) { ++n; ++gcnt[GSELIDX(curr->gselector)]; } if (n > 0) /* at least one group accelerator found */ for (rp = gacc, curr = cw->mlist; curr; curr = curr->next) if (curr->gselector && curr->gselector != curr->selector && !index(gacc, curr->gselector) && (cw->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { *rp++ = curr->gselector; *rp = '\0'; /* re-terminate for index() */ } } resp_len = 0; /* lint suppression */ /* loop until finished */ while (!finished) { if (reset_count) { counting = FALSE; count = 0; } else reset_count = TRUE; if (!page_start) { /* new page to be displayed */ if (curr_page < 0 || (cw->npages > 0 && curr_page >= cw->npages)) panic("bad menu screen page #%d", curr_page); /* clear screen */ if (!cw->offx) { /* if not corner, do clearscreen */ if (cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else clear_screen(); } rp = resp; if (cw->npages > 0) { /* collect accelerators */ page_start = cw->plist[curr_page]; page_end = cw->plist[curr_page + 1]; for (page_lines = 0, curr = page_start; curr != page_end; page_lines++, curr = curr->next) { int color = NO_COLOR, attr = ATR_NONE; boolean menucolr = FALSE; if (curr->selector) *rp++ = curr->selector; tty_curs(window, 1, page_lines); if (cw->offx) cl_end(); (void) putchar(' '); ++ttyDisplay->curx; /* * Don't use xputs() because (1) under unix it calls * tputstr() which will interpret a '*' as some kind * of padding information and (2) it calls xputc to * actually output the character. We're faster doing * this. */ if (iflags.use_menu_color && (menucolr = get_menu_coloring(curr->str, &color, &attr))) { term_start_attr(attr); #ifdef TEXTCOLOR if (color != NO_COLOR) term_start_color(color); #endif } else term_start_attr(curr->attr); for (n = 0, cp = curr->str; #ifndef WIN32CON *cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols; cp++, n++) #else *cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols; cp++, n++, ttyDisplay->curx++) #endif if (n == 2 && curr->identifier.a_void != 0 && curr->selected) { if (curr->count == -1L) (void) putchar('+'); /* all selected */ else (void) putchar('#'); /* count selected */ } else (void) putchar(*cp); if (iflags.use_menu_color && menucolr) { #ifdef TEXTCOLOR if (color != NO_COLOR) term_end_color(); #endif term_end_attr(attr); } else term_end_attr(curr->attr); } } else { page_start = 0; page_end = 0; page_lines = 0; } *rp = 0; /* remember how many explicit menu choices there are */ resp_len = (int) strlen(resp); /* corner window - clear extra lines from last page */ if (cw->offx) { for (n = page_lines + 1; n < cw->maxrow; n++) { tty_curs(window, 1, n); cl_end(); } } /* set extra chars.. */ Strcat(resp, default_menu_cmds); Strcat(resp, "0123456789\033\n\r"); /* counts, quit */ Strcat(resp, gacc); /* group accelerators */ Strcat(resp, mapped_menu_cmds); if (cw->npages > 1) Sprintf(cw->morestr, "(%d of %d)", curr_page + 1, (int) cw->npages); else if (msave) Strcpy(cw->morestr, msave); else Strcpy(cw->morestr, defmorestr); tty_curs(window, 1, page_lines); cl_end(); dmore(cw, resp); } else { /* just put the cursor back... */ tty_curs(window, (int) strlen(cw->morestr) + 2, page_lines); xwaitforspace(resp); } really_morc = morc; /* (only used with MENU_EXPLICIT_CHOICE */ if ((rp = index(resp, morc)) != 0 && rp < resp + resp_len) /* explicit menu selection; don't override it if it also happens to match a mapped menu command (such as ':' to look inside a container vs ':' to search) */ morc = MENU_EXPLICIT_CHOICE; else morc = map_menu_cmd(morc); switch (morc) { case '0': /* special case: '0' is also the default ball class */ if (!counting && index(gacc, morc)) goto group_accel; /* fall through to count the zero */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': count = (count * 10L) + (long) (morc - '0'); /* * It is debatable whether we should allow 0 to * start a count. There is no difference if the * item is selected. If not selected, then * "0b" could mean: * * count starting zero: "zero b's" * ignore starting zero: "select b" * * At present I don't know which is better. */ if (count != 0L) { /* ignore leading zeros */ counting = TRUE; reset_count = FALSE; } break; case '\033': /* cancel - from counting or loop */ if (!counting) { /* deselect everything */ for (curr = cw->mlist; curr; curr = curr->next) { curr->selected = FALSE; curr->count = -1L; } cw->flags |= WIN_CANCELLED; finished = TRUE; } /* else only stop count */ break; case '\0': /* finished (commit) */ case '\n': case '\r': /* only finished if we are actually picking something */ if (cw->how != PICK_NONE) { finished = TRUE; break; } /* else fall through */ case MENU_NEXT_PAGE: if (cw->npages > 0 && curr_page != cw->npages - 1) { curr_page++; page_start = 0; } else finished = TRUE; /* questionable behavior */ break; case MENU_PREVIOUS_PAGE: if (cw->npages > 0 && curr_page != 0) { --curr_page; page_start = 0; } break; case MENU_FIRST_PAGE: if (cw->npages > 0 && curr_page != 0) { page_start = 0; curr_page = 0; } break; case MENU_LAST_PAGE: if (cw->npages > 0 && curr_page != cw->npages - 1) { page_start = 0; curr_page = cw->npages - 1; } break; case MENU_SELECT_PAGE: if (cw->how == PICK_ANY) set_all_on_page(window, page_start, page_end); break; case MENU_UNSELECT_PAGE: unset_all_on_page(window, page_start, page_end); break; case MENU_INVERT_PAGE: if (cw->how == PICK_ANY) invert_all_on_page(window, page_start, page_end, 0); break; case MENU_SELECT_ALL: if (cw->how == PICK_ANY) { set_all_on_page(window, page_start, page_end); /* set the rest */ for (curr = cw->mlist; curr; curr = curr->next) if (curr->identifier.a_void && !curr->selected) curr->selected = TRUE; } break; case MENU_UNSELECT_ALL: unset_all_on_page(window, page_start, page_end); /* unset the rest */ for (curr = cw->mlist; curr; curr = curr->next) if (curr->identifier.a_void && curr->selected) { curr->selected = FALSE; curr->count = -1; } break; case MENU_INVERT_ALL: if (cw->how == PICK_ANY) invert_all(window, page_start, page_end, 0); break; case MENU_SEARCH: if (cw->how == PICK_NONE) { tty_nhbell(); break; } else { char searchbuf[BUFSZ + 2], tmpbuf[BUFSZ]; boolean on_curr_page = FALSE; int lineno = 0; tty_getlin("Search for:", tmpbuf); if (!tmpbuf[0] || tmpbuf[0] == '\033') break; Sprintf(searchbuf, "*%s*", tmpbuf); for (curr = cw->mlist; curr; curr = curr->next) { if (on_curr_page) lineno++; if (curr == page_start) on_curr_page = TRUE; else if (curr == page_end) on_curr_page = FALSE; if (curr->identifier.a_void && pmatchi(searchbuf, curr->str)) { toggle_menu_curr(window, curr, lineno, on_curr_page, counting, count); if (cw->how == PICK_ONE) { finished = TRUE; break; } } } } break; case MENU_EXPLICIT_CHOICE: morc = really_morc; /*FALLTHRU*/ default: if (cw->how == PICK_NONE || !index(resp, morc)) { /* unacceptable input received */ tty_nhbell(); break; } else if (index(gacc, morc)) { group_accel: /* group accelerator; for the PICK_ONE case, we know that it matches exactly one item in order to be in gacc[] */ invert_all(window, page_start, page_end, morc); if (cw->how == PICK_ONE) finished = TRUE; break; } /* find, toggle, and possibly update */ for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (morc == curr->selector) { toggle_menu_curr(window, curr, n, TRUE, counting, count); if (cw->how == PICK_ONE) finished = TRUE; break; /* from `for' loop */ } break; } } /* while */ cw->morestr = msave; free((genericptr_t) morestr); } STATIC_OVL void process_text_window(window, cw) winid window; struct WinDesc *cw; { int i, n, attr; register char *cp; for (n = 0, i = 0; i < cw->maxrow; i++) { if (!cw->offx && (n + cw->offy == ttyDisplay->rows - 1)) { tty_curs(window, 1, n); cl_end(); dmore(cw, quitchars); if (morc == '\033') { cw->flags |= WIN_CANCELLED; break; } if (cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else clear_screen(); n = 0; } tty_curs(window, 1, n++); #ifdef H2344_BROKEN cl_end(); #else if (cw->offx) cl_end(); #endif if (cw->data[i]) { attr = cw->data[i][0] - 1; if (cw->offx) { (void) putchar(' '); ++ttyDisplay->curx; } term_start_attr(attr); for (cp = &cw->data[i][1]; #ifndef WIN32CON *cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols; cp++) #else *cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols; cp++, ttyDisplay->curx++) #endif (void) putchar(*cp); term_end_attr(attr); } } if (i == cw->maxrow) { #ifdef H2344_BROKEN if (cw->type == NHW_TEXT) { tty_curs(BASE_WINDOW, 1, (int) ttyDisplay->cury + 1); cl_eos(); } #endif tty_curs(BASE_WINDOW, (int) cw->offx + 1, (cw->type == NHW_TEXT) ? (int) ttyDisplay->rows - 1 : n); cl_end(); dmore(cw, quitchars); if (morc == '\033') cw->flags |= WIN_CANCELLED; } } /*ARGSUSED*/ void tty_display_nhwindow(window, blocking) winid window; boolean blocking; /* with ttys, all windows are blocking */ { register struct WinDesc *cw = 0; short s_maxcol; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); if (cw->flags & WIN_CANCELLED) return; ttyDisplay->lastwin = window; ttyDisplay->rawprint = 0; switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin == 1) { more(); ttyDisplay->toplin = 1; /* more resets this */ tty_clear_nhwindow(window); } else ttyDisplay->toplin = 0; cw->curx = cw->cury = 0; if (!cw->active) iflags.window_inited = TRUE; break; case NHW_MAP: end_glyphout(); if (blocking) { if (!ttyDisplay->toplin) ttyDisplay->toplin = 1; tty_display_nhwindow(WIN_MESSAGE, TRUE); return; } case NHW_BASE: (void) fflush(stdout); break; case NHW_TEXT: cw->maxcol = ttyDisplay->cols; /* force full-screen mode */ /*FALLTHRU*/ case NHW_MENU: cw->active = 1; /* cw->maxcol is a long, but its value is constrained to be <= ttyDisplay->cols, so is sure to fit within a short */ s_maxcol = (short) cw->maxcol; #ifdef H2344_BROKEN cw->offx = (cw->type == NHW_TEXT) ? 0 : min(min(82, ttyDisplay->cols / 2), ttyDisplay->cols - s_maxcol - 1); #else /* avoid converting to uchar before calculations are finished */ cw->offx = (uchar) max((int) 10, (int) (ttyDisplay->cols - s_maxcol - 1)); #endif if (cw->offx < 0) cw->offx = 0; if (cw->type == NHW_MENU) cw->offy = 0; if (ttyDisplay->toplin == 1) tty_display_nhwindow(WIN_MESSAGE, TRUE); #ifdef H2344_BROKEN if (cw->maxrow >= (int) ttyDisplay->rows) #else if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) #endif { cw->offx = 0; if (cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else clear_screen(); ttyDisplay->toplin = 0; } else { if (WIN_MESSAGE != WIN_ERR) tty_clear_nhwindow(WIN_MESSAGE); } if (cw->data || !cw->maxrow) process_text_window(window, cw); else process_menu_window(window, cw); break; } cw->active = 1; } void tty_dismiss_nhwindow(window) winid window; { register struct WinDesc *cw = 0; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) tty_display_nhwindow(WIN_MESSAGE, TRUE); /*FALLTHRU*/ case NHW_STATUS: case NHW_BASE: case NHW_MAP: /* * these should only get dismissed when the game is going away * or suspending */ tty_curs(BASE_WINDOW, 1, (int) ttyDisplay->rows - 1); cw->active = 0; break; case NHW_MENU: case NHW_TEXT: if (cw->active) { if (iflags.window_inited) { /* otherwise dismissing the text endwin after other windows * are dismissed tries to redraw the map and panics. since * the whole reason for dismissing the other windows was to * leave the ending window on the screen, we don't want to * erase it anyway. */ erase_menu_or_text(window, cw, FALSE); } cw->active = 0; } break; } cw->flags = 0; } void tty_destroy_nhwindow(window) winid window; { register struct WinDesc *cw = 0; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); if (cw->active) tty_dismiss_nhwindow(window); if (cw->type == NHW_MESSAGE) iflags.window_inited = 0; if (cw->type == NHW_MAP) clear_screen(); free_window_info(cw, TRUE); free((genericptr_t) cw); wins[window] = 0; } void tty_curs(window, x, y) winid window; register int x, y; /* not xchar: perhaps xchar is unsigned and curx-x would be unsigned as well */ { struct WinDesc *cw = 0; int cx = ttyDisplay->curx; int cy = ttyDisplay->cury; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); ttyDisplay->lastwin = window; #if defined(USE_TILES) && defined(MSDOS) adjust_cursor_flags(cw); #endif cw->curx = --x; /* column 0 is never used */ cw->cury = y; #ifdef DEBUG if (x < 0 || y < 0 || y >= cw->rows || x > cw->cols) { const char *s = "[unknown type]"; switch (cw->type) { case NHW_MESSAGE: s = "[topl window]"; break; case NHW_STATUS: s = "[status window]"; break; case NHW_MAP: s = "[map window]"; break; case NHW_MENU: s = "[corner window]"; break; case NHW_TEXT: s = "[text window]"; break; case NHW_BASE: s = "[base window]"; break; } debugpline4("bad curs positioning win %d %s (%d,%d)", window, s, x, y); return; } #endif x += cw->offx; y += cw->offy; #ifdef CLIPPING if (clipping && window == WIN_MAP) { x -= clipx; y -= clipy; } #endif if (y == cy && x == cx) return; if (cw->type == NHW_MAP) end_glyphout(); #ifndef NO_TERMS if (!nh_ND && (cx != x || x <= 3)) { /* Extremely primitive */ cmov(x, y); /* bunker!wtm */ return; } #endif if ((cy -= y) < 0) cy = -cy; if ((cx -= x) < 0) cx = -cx; if (cy <= 3 && cx <= 3) { nocmov(x, y); #ifndef NO_TERMS } else if ((x <= 3 && cy <= 3) || (!nh_CM && x < cx)) { (void) putchar('\r'); ttyDisplay->curx = 0; nocmov(x, y); } else if (!nh_CM) { nocmov(x, y); #endif } else cmov(x, y); ttyDisplay->curx = x; ttyDisplay->cury = y; } STATIC_OVL void tty_putsym(window, x, y, ch) winid window; int x, y; char ch; { register struct WinDesc *cw = 0; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); switch (cw->type) { case NHW_STATUS: case NHW_MAP: case NHW_BASE: tty_curs(window, x, y); (void) putchar(ch); ttyDisplay->curx++; cw->curx++; break; case NHW_MESSAGE: case NHW_MENU: case NHW_TEXT: impossible("Can't putsym to window type %d", cw->type); break; } } STATIC_OVL const char * compress_str(str) const char *str; { static char cbuf[BUFSZ]; /* compress in case line too long */ if ((int) strlen(str) >= CO) { register const char *bp0 = str; register char *bp1 = cbuf; do { #ifdef CLIPPING if (*bp0 != ' ' || bp0[1] != ' ') #else if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ') #endif *bp1++ = *bp0; } while (*bp0++); } else return str; return cbuf; } void tty_putstr(window, attr, str) winid window; int attr; const char *str; { register struct WinDesc *cw = 0; register char *ob; register const char *nb; register long i, j, n0; /* Assume there's a real problem if the window is missing -- * probably a panic message */ if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) { tty_raw_print(str); return; } if (str == (const char *) 0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; if (cw->type != NHW_MESSAGE) str = compress_str(str); ttyDisplay->lastwin = window; switch (cw->type) { case NHW_MESSAGE: /* really do this later */ #if defined(USER_SOUNDS) && defined(WIN32CON) play_sound_for_message(str); #endif update_topl(str); break; case NHW_STATUS: ob = &cw->data[cw->cury][j = cw->curx]; if (context.botlx) *ob = 0; if (!cw->cury && (int) strlen(str) >= CO) { /* the characters before "St:" are unnecessary */ nb = index(str, ':'); if (nb && nb > str + 2) str = nb - 2; } nb = str; for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { if (*ob || context.botlx) { /* last char printed may be in middle of line */ tty_curs(WIN_STATUS, i, cw->cury); cl_end(); } break; } if (*ob != *nb) tty_putsym(WIN_STATUS, i, cw->cury, *nb); if (*ob) ob++; } (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ #ifdef STATUS_VIA_WINDOWPORT if (!iflags.use_status_hilites) { #endif cw->cury = (cw->cury + 1) % 2; cw->curx = 0; #ifdef STATUS_VIA_WINDOWPORT } #endif break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); term_start_attr(attr); while (*str && (int) ttyDisplay->curx < (int) ttyDisplay->cols - 1) { (void) putchar(*str); str++; ttyDisplay->curx++; } cw->curx = 0; cw->cury++; term_end_attr(attr); break; case NHW_BASE: tty_curs(window, cw->curx + 1, cw->cury); term_start_attr(attr); while (*str) { if ((int) ttyDisplay->curx >= (int) ttyDisplay->cols - 1) { cw->curx = 0; cw->cury++; tty_curs(window, cw->curx + 1, cw->cury); } (void) putchar(*str); str++; ttyDisplay->curx++; } cw->curx = 0; cw->cury++; term_end_attr(attr); break; case NHW_MENU: case NHW_TEXT: #ifdef H2344_BROKEN if (cw->type == NHW_TEXT && (cw->cury + cw->offy) == ttyDisplay->rows - 1) #else if (cw->type == NHW_TEXT && cw->cury == ttyDisplay->rows - 1) #endif { /* not a menu, so save memory and output 1 page at a time */ cw->maxcol = ttyDisplay->cols; /* force full-screen mode */ tty_display_nhwindow(window, TRUE); for (i = 0; i < cw->maxrow; i++) if (cw->data[i]) { free((genericptr_t) cw->data[i]); cw->data[i] = 0; } cw->maxrow = cw->cury = 0; } /* always grows one at a time, but alloc 12 at a time */ if (cw->cury >= cw->rows) { char **tmp; cw->rows += 12; tmp = (char **) alloc(sizeof(char *) * (unsigned) cw->rows); for (i = 0; i < cw->maxrow; i++) tmp[i] = cw->data[i]; if (cw->data) free((genericptr_t) cw->data); cw->data = tmp; for (i = cw->maxrow; i < cw->rows; i++) cw->data[i] = 0; } if (cw->data[cw->cury]) free((genericptr_t) cw->data[cw->cury]); n0 = strlen(str) + 1; ob = cw->data[cw->cury] = (char *) alloc((unsigned) n0 + 1); *ob++ = (char) (attr + 1); /* avoid nuls, for convenience */ Strcpy(ob, str); if (n0 > cw->maxcol) cw->maxcol = n0; if (++cw->cury > cw->maxrow) cw->maxrow = cw->cury; if (n0 > CO) { /* attempt to break the line */ for (i = CO - 1; i && str[i] != ' ' && str[i] != '\n';) i--; if (i) { cw->data[cw->cury - 1][++i] = '\0'; tty_putstr(window, attr, &str[i]); } } break; } } void tty_display_file(fname, complain) const char *fname; boolean complain; { #ifdef DEF_PAGER /* this implies that UNIX is defined */ { /* use external pager; this may give security problems */ register int fd = open(fname, 0); if (fd < 0) { if (complain) pline("Cannot open %s.", fname); else docrt(); return; } if (child(1)) { /* Now that child() does a setuid(getuid()) and a chdir(), we may not be able to open file fname anymore, so make it stdin. */ (void) close(0); if (dup(fd)) { if (complain) raw_printf("Cannot open %s as stdin.", fname); } else { (void) execlp(catmore, "page", (char *) 0); if (complain) raw_printf("Cannot exec %s.", catmore); } if (complain) sleep(10); /* want to wait_synch() but stdin is gone */ terminate(EXIT_FAILURE); } (void) close(fd); #ifdef notyet winch_seen = 0; #endif } #else /* DEF_PAGER */ { dlb *f; char buf[BUFSZ]; char *cr; tty_clear_nhwindow(WIN_MESSAGE); f = dlb_fopen(fname, "r"); if (!f) { if (complain) { home(); tty_mark_synch(); tty_raw_print(""); perror(fname); tty_wait_synch(); pline("Cannot open \"%s\".", fname); } else if (u.ux) docrt(); } else { winid datawin = tty_create_nhwindow(NHW_TEXT); boolean empty = TRUE; if (complain #ifndef NO_TERMS && nh_CD #endif ) { /* attempt to scroll text below map window if there's room */ wins[datawin]->offy = wins[WIN_STATUS]->offy + 3; if ((int) wins[datawin]->offy + 12 > (int) ttyDisplay->rows) wins[datawin]->offy = 0; } while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; #ifdef MSDOS if ((cr = index(buf, '\r')) != 0) *cr = 0; #endif if (index(buf, '\t') != 0) (void) tabexpand(buf); empty = FALSE; tty_putstr(datawin, 0, buf); if (wins[datawin]->flags & WIN_CANCELLED) break; } if (!empty) tty_display_nhwindow(datawin, FALSE); tty_destroy_nhwindow(datawin); (void) dlb_fclose(f); } } #endif /* DEF_PAGER */ } void tty_start_menu(window) winid window; { tty_clear_nhwindow(window); return; } /*ARGSUSED*/ /* * Add a menu item to the beginning of the menu list. This list is reversed * later. */ void tty_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; /* window to use, must be of type NHW_MENU */ int glyph UNUSED; /* glyph to display with item (not used) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like tty_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { register struct WinDesc *cw = 0; tty_menu_item *item; const char *newstr; char buf[4 + BUFSZ]; if (str == (const char *) 0) return; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) panic(winpanicstr, window); cw->nitems++; if (identifier->a_void) { int len = strlen(str); if (len >= BUFSZ) { /* We *think* everything's coming in off at most BUFSZ bufs... */ impossible("Menu item too long (%d).", len); len = BUFSZ - 1; } Sprintf(buf, "%c - ", ch ? ch : '?'); (void) strncpy(buf + 4, str, len); buf[4 + len] = '\0'; newstr = buf; } else newstr = str; item = (tty_menu_item *) alloc(sizeof(tty_menu_item)); item->identifier = *identifier; item->count = -1L; item->selected = preselected; item->selector = ch; item->gselector = gch; item->attr = attr; item->str = dupstr(newstr ? newstr : ""); item->next = cw->mlist; cw->mlist = item; } /* Invert the given list, can handle NULL as an input. */ STATIC_OVL tty_menu_item * reverse(curr) tty_menu_item *curr; { tty_menu_item *next, *head = 0; while (curr) { next = curr->next; curr->next = head; head = curr; curr = next; } return head; } /* * End a menu in this window, window must a type NHW_MENU. This routine * processes the string list. We calculate the # of pages, then assign * keyboard accelerators as needed. Finally we decide on the width and * height of the window. */ void tty_end_menu(window, prompt) winid window; /* menu to use */ const char *prompt; /* prompt to for menu */ { struct WinDesc *cw = 0; tty_menu_item *curr; short len; int lmax, n; char menu_ch; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) panic(winpanicstr, window); /* Reverse the list so that items are in correct order. */ cw->mlist = reverse(cw->mlist); /* Put the prompt at the beginning of the menu. */ if (prompt) { anything any; any = zeroany; /* not selectable */ tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED); } /* XXX another magic number? 52 */ lmax = min(52, (int) ttyDisplay->rows - 1); /* # lines per page */ cw->npages = (cw->nitems + (lmax - 1)) / lmax; /* # of pages */ /* make sure page list is large enough */ if (cw->plist_size < cw->npages + 1 /*need 1 slot beyond last*/) { if (cw->plist) free((genericptr_t) cw->plist); cw->plist_size = cw->npages + 1; cw->plist = (tty_menu_item **) alloc(cw->plist_size * sizeof(tty_menu_item *)); } cw->cols = 0; /* cols is set when the win is initialized... (why?) */ menu_ch = '?'; /* lint suppression */ for (n = 0, curr = cw->mlist; curr; n++, curr = curr->next) { /* set page boundaries and character accelerators */ if ((n % lmax) == 0) { menu_ch = 'a'; cw->plist[n / lmax] = curr; } if (curr->identifier.a_void && !curr->selector) { curr->str[0] = curr->selector = menu_ch; if (menu_ch++ == 'z') menu_ch = 'A'; } /* cut off any lines that are too long */ len = strlen(curr->str) + 2; /* extra space at beg & end */ if (len > (int) ttyDisplay->cols) { curr->str[ttyDisplay->cols - 2] = 0; len = ttyDisplay->cols; } if (len > cw->cols) cw->cols = len; } cw->plist[cw->npages] = 0; /* plist terminator */ /* * If greater than 1 page, morestr is "(x of y) " otherwise, "(end) " */ if (cw->npages > 1) { char buf[QBUFSZ]; /* produce the largest demo string */ Sprintf(buf, "(%ld of %ld) ", cw->npages, cw->npages); len = strlen(buf); cw->morestr = dupstr(""); } else { cw->morestr = dupstr("(end) "); len = strlen(cw->morestr); } if (len > (int) ttyDisplay->cols) { /* truncate the prompt if it's too long for the screen */ if (cw->npages <= 1) /* only str in single page case */ cw->morestr[ttyDisplay->cols] = 0; len = ttyDisplay->cols; } if (len > cw->cols) cw->cols = len; cw->maxcol = cw->cols; /* * The number of lines in the first page plus the morestr will be the * maximum size of the window. */ if (cw->npages > 1) cw->maxrow = cw->rows = lmax + 1; else cw->maxrow = cw->rows = cw->nitems + 1; } int tty_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { register struct WinDesc *cw = 0; tty_menu_item *curr; menu_item *mi; int n, cancelled; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) panic(winpanicstr, window); *menu_list = (menu_item *) 0; cw->how = (short) how; morc = 0; tty_display_nhwindow(window, TRUE); cancelled = !!(cw->flags & WIN_CANCELLED); tty_dismiss_nhwindow(window); /* does not destroy window data */ if (cancelled) { n = -1; } else { for (n = 0, curr = cw->mlist; curr; curr = curr->next) if (curr->selected) n++; } if (n > 0) { *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); for (mi = *menu_list, curr = cw->mlist; curr; curr = curr->next) if (curr->selected) { mi->item = curr->identifier; mi->count = curr->count; mi++; } } return n; } /* special hack for treating top line --More-- as a one item menu */ char tty_message_menu(let, how, mesg) char let; int how; const char *mesg; { /* "menu" without selection; use ordinary pline, no more() */ if (how == PICK_NONE) { pline("%s", mesg); return 0; } ttyDisplay->dismiss_more = let; morc = 0; /* barebones pline(); since we're only supposed to be called after response to a prompt, we'll assume that the display is up to date */ tty_putstr(WIN_MESSAGE, 0, mesg); /* if `mesg' didn't wrap (triggering --More--), force --More-- now */ if (ttyDisplay->toplin == 1) { more(); ttyDisplay->toplin = 1; /* more resets this */ tty_clear_nhwindow(WIN_MESSAGE); } /* normally means skip further messages, but in this case it means cancel the current prompt; any other messages should continue to be output normally */ wins[WIN_MESSAGE]->flags &= ~WIN_CANCELLED; ttyDisplay->dismiss_more = 0; return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0'; } void tty_update_inventory() { return; } void tty_mark_synch() { (void) fflush(stdout); } void tty_wait_synch() { /* we just need to make sure all windows are synch'd */ if (!ttyDisplay || ttyDisplay->rawprint) { getret(); if (ttyDisplay) ttyDisplay->rawprint = 0; } else { tty_display_nhwindow(WIN_MAP, FALSE); if (ttyDisplay->inmore) { addtopl("--More--"); (void) fflush(stdout); } else if (ttyDisplay->inread > program_state.gameover) { /* this can only happen if we were reading and got interrupted */ ttyDisplay->toplin = 3; /* do this twice; 1st time gets the Quit? message again */ (void) tty_doprev_message(); (void) tty_doprev_message(); ttyDisplay->intr++; (void) fflush(stdout); } } } void docorner(xmin, ymax) register int xmin, ymax; { register int y; register struct WinDesc *cw = wins[WIN_MAP]; if (u.uswallow) { /* Can be done more efficiently */ swallowed(1); return; } #if defined(SIGWINCH) && defined(CLIPPING) if (ymax > LI) ymax = LI; /* can happen if window gets smaller */ #endif for (y = 0; y < ymax; y++) { tty_curs(BASE_WINDOW, xmin, y); /* move cursor */ cl_end(); /* clear to end of line */ #ifdef CLIPPING if (y < (int) cw->offy || y + clipy > ROWNO) continue; /* only refresh board */ #if defined(USE_TILES) && defined(MSDOS) if (iflags.tile_view) row_refresh((xmin / 2) + clipx - ((int) cw->offx / 2), COLNO - 1, y + clipy - (int) cw->offy); else #endif row_refresh(xmin + clipx - (int) cw->offx, COLNO - 1, y + clipy - (int) cw->offy); #else if (y < cw->offy || y > ROWNO) continue; /* only refresh board */ row_refresh(xmin - (int) cw->offx, COLNO - 1, y - (int) cw->offy); #endif } end_glyphout(); if (ymax >= (int) wins[WIN_STATUS]->offy) { /* we have wrecked the bottom line */ context.botlx = 1; bot(); } } void end_glyphout() { #if defined(ASCIIGRAPH) && !defined(NO_TERMS) if (GFlag) { GFlag = FALSE; graph_off(); } #endif #ifdef TEXTCOLOR if (ttyDisplay->color != NO_COLOR) { term_end_color(); ttyDisplay->color = NO_COLOR; } #endif } #ifndef WIN32 void g_putch(in_ch) int in_ch; { register char ch = (char) in_ch; #if defined(ASCIIGRAPH) && !defined(NO_TERMS) if (SYMHANDLING(H_IBM) || iflags.eight_bit_tty) { /* IBM-compatible displays don't need other stuff */ (void) putchar(ch); } else if (ch & 0x80) { if (!GFlag || HE_resets_AS) { graph_on(); GFlag = TRUE; } (void) putchar((ch ^ 0x80)); /* Strip 8th bit */ } else { if (GFlag) { graph_off(); GFlag = FALSE; } (void) putchar(ch); } #else (void) putchar(ch); #endif /* ASCIIGRAPH && !NO_TERMS */ return; } #endif /* !WIN32 */ #ifdef CLIPPING void setclipped() { clipping = TRUE; clipx = clipy = 0; clipxmax = CO; clipymax = LI - 3; } void tty_cliparound(x, y) int x, y; { extern boolean restoring; int oldx = clipx, oldy = clipy; if (!clipping) return; if (x < clipx + 5) { clipx = max(0, x - 20); clipxmax = clipx + CO; } else if (x > clipxmax - 5) { clipxmax = min(COLNO, clipxmax + 20); clipx = clipxmax - CO; } if (y < clipy + 2) { clipy = max(0, y - (clipymax - clipy) / 2); clipymax = clipy + (LI - 3); } else if (y > clipymax - 2) { clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2); clipy = clipymax - (LI - 3); } if (clipx != oldx || clipy != oldy) { if (on_level(&u.uz0, &u.uz) && !restoring) (void) doredraw(); } } #endif /* CLIPPING */ /* * tty_print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void tty_print_glyph(window, x, y, glyph, bkglyph) winid window; xchar x, y; int glyph; int bkglyph UNUSED; { int ch; boolean reverse_on = FALSE; int color; unsigned special; #ifdef CLIPPING if (clipping) { if (x <= clipx || y < clipy || x >= clipxmax || y >= clipymax) return; } #endif /* map glyph to character and color */ (void) mapglyph(glyph, &ch, &color, &special, x, y); /* Move the cursor. */ tty_curs(window, x, y); #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ (void) putchar((char) ' '); backsp(); } #endif #ifdef TEXTCOLOR if (color != ttyDisplay->color) { if (ttyDisplay->color != NO_COLOR) term_end_color(); ttyDisplay->color = color; if (color != NO_COLOR) term_start_color(color); } #endif /* TEXTCOLOR */ /* must be after color check; term_end_color may turn off inverse too */ if (((special & MG_PET) && iflags.hilite_pet) || ((special & MG_OBJPILE) && iflags.hilite_pile) || ((special & MG_DETECT) && iflags.use_inverse)) { term_start_attr(ATR_INVERSE); reverse_on = TRUE; } #if defined(USE_TILES) && defined(MSDOS) if (iflags.grmode && iflags.tile_view) xputg(glyph, ch, special); else #endif g_putch(ch); /* print the character */ if (reverse_on) { term_end_attr(ATR_INVERSE); #ifdef TEXTCOLOR /* turn off color as well, ATR_INVERSE may have done this already */ if (ttyDisplay->color != NO_COLOR) { term_end_color(); ttyDisplay->color = NO_COLOR; } #endif } wins[window]->curx++; /* one character over */ ttyDisplay->curx++; /* the real cursor moved too */ } void tty_raw_print(str) const char *str; { if (ttyDisplay) ttyDisplay->rawprint++; #if defined(MICRO) || defined(WIN32CON) msmsg("%s\n", str); #else puts(str); (void) fflush(stdout); #endif } void tty_raw_print_bold(str) const char *str; { if (ttyDisplay) ttyDisplay->rawprint++; term_start_raw_bold(); #if defined(MICRO) || defined(WIN32CON) msmsg("%s", str); #else (void) fputs(str, stdout); #endif term_end_raw_bold(); #if defined(MICRO) || defined(WIN32CON) msmsg("\n"); #else puts(""); (void) fflush(stdout); #endif } int tty_nhgetch() { int i; #ifdef UNIX /* kludge alert: Some Unix variants return funny values if getc() * is called, interrupted, and then called again. There * is non-reentrant code in the internal _filbuf() routine, called by * getc(). */ static volatile int nesting = 0; char nestbuf; #endif (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be * available yet. Such problems will probably be fatal before we get * here, but validate those pointers just in case... */ if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) wins[WIN_MESSAGE]->flags &= ~WIN_STOP; #ifdef UNIX i = (++nesting == 1) ? tgetch() : (read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1) ? (int) nestbuf : EOF; --nesting; #else i = tgetch(); #endif if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ else if (i == EOF) i = '\033'; /* same for EOF */ if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; return i; } /* * return a key, or 0, in which case a mouse button was pressed * mouse events should be returned as character postitions in the map window. * Since normal tty's don't have mice, just return a key. */ /*ARGSUSED*/ int tty_nh_poskey(x, y, mod) int *x, *y, *mod; { #if defined(WIN32CON) int i; (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be * available yet. Such problems will probably be fatal before we get * here, but validate those pointers just in case... */ if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) wins[WIN_MESSAGE]->flags &= ~WIN_STOP; i = ntposkey(x, y, mod); if (!i && mod && (*mod == 0 || *mod == EOF)) i = '\033'; /* map NUL or EOF to ESC, nethack doesn't expect either */ if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; return i; #else /* !WIN32CON */ nhUse(x); nhUse(y); nhUse(mod); return tty_nhgetch(); #endif /* ?WIN32CON */ } void win_tty_init(dir) int dir; { if (dir != WININIT) return; #if defined(WIN32CON) if (!strncmpi(windowprocs.name, "tty", 3)) nttty_open(0); #endif return; } #ifdef POSITIONBAR void tty_update_positionbar(posbar) char *posbar; { #ifdef MSDOS video_update_positionbar(posbar); #endif } #endif #ifdef STATUS_VIA_WINDOWPORT /* * The following data structures come from the genl_ routines in * src/windows.c and as such are considered to be on the window-port * "side" of things, rather than the NetHack-core "side" of things. */ extern const char *status_fieldnm[MAXBLSTATS]; extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; #ifdef STATUS_HILITES typedef struct hilite_data_struct { int thresholdtype; anything threshold; int behavior; int under; int over; } hilite_data_t; static hilite_data_t tty_status_hilites[MAXBLSTATS]; static int tty_status_colors[MAXBLSTATS]; struct color_option { int color; int attr_bits; }; static void FDECL(start_color_option, (struct color_option)); static void FDECL(end_color_option, (struct color_option)); static void FDECL(apply_color_option, (struct color_option, const char *)); static void FDECL(add_colored_text, (const char *, char *)); #endif void tty_status_init() { int i; /* let genl_status_init do most of the initialization */ genl_status_init(); for (i = 0; i < MAXBLSTATS; ++i) { #ifdef STATUS_HILITES tty_status_colors[i] = NO_COLOR; /* no color */ tty_status_hilites[i].thresholdtype = 0; tty_status_hilites[i].behavior = BL_TH_NONE; tty_status_hilites[i].under = BL_HILITE_NONE; tty_status_hilites[i].over = BL_HILITE_NONE; #endif /* STATUS_HILITES */ } } /* * *_status_update() * -- update the value of a status field. * -- the fldindex identifies which field is changing and * is an integer index value from botl.h * -- fldindex could be any one of the following from botl.h: * BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, * BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, * BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, * BL_LEVELDESC, BL_EXP, BL_CONDITION * -- fldindex could also be BL_FLUSH (-1), which is not really * a field index, but is a special trigger to tell the * windowport that it should redisplay all its status fields, * even if no changes have been presented to it. * -- ptr is usually a "char *", unless fldindex is BL_CONDITION. * If fldindex is BL_CONDITION, then ptr is a long value with * any or none of the following bits set (from botl.h): * BL_MASK_BLIND 0x00000001L * BL_MASK_CONF 0x00000002L * BL_MASK_FOODPOIS 0x00000004L * BL_MASK_ILL 0x00000008L * BL_MASK_HALLU 0x00000010L * BL_MASK_STUNNED 0x00000020L * BL_MASK_SLIMED 0x00000040L * -- The value passed for BL_GOLD includes a leading * symbol for GOLD "$:nnn". If the window port needs to use * the textual gold amount without the leading "$:" the port * will have to add 2 to the passed "ptr" for the BL_GOLD case. */ void tty_status_update(fldidx, ptr, chg, percent) int fldidx, chg, percent; genericptr_t ptr; { long cond, *condptr = (long *) ptr; register int i; char *text = (char *) ptr; /* Mapping BL attributes to tty attributes * BL_HILITE_NONE -1 + 3 = 2 (statusattr[2]) * BL_HILITE_INVERSE -2 + 3 = 1 (statusattr[1]) * BL_HILITE_BOLD -3 + 3 = 0 (statusattr[0]) */ int statusattr[] = { ATR_BOLD, ATR_INVERSE, ATR_NONE }; int attridx = 0; long value = -1L; static boolean beenhere = FALSE; enum statusfields fieldorder[2][15] = { { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH }, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; if (fldidx != BL_FLUSH) { if (!status_activefields[fldidx]) return; switch (fldidx) { case BL_CONDITION: cond = *condptr; *status_vals[fldidx] = '\0'; if (cond & BL_MASK_BLIND) Strcat(status_vals[fldidx], " Blind"); if (cond & BL_MASK_CONF) Strcat(status_vals[fldidx], " Conf"); if (cond & BL_MASK_FOODPOIS) Strcat(status_vals[fldidx], " FoodPois"); if (cond & BL_MASK_ILL) Strcat(status_vals[fldidx], " Ill"); if (cond & BL_MASK_STUNNED) Strcat(status_vals[fldidx], " Stun"); if (cond & BL_MASK_HALLU) Strcat(status_vals[fldidx], " Hallu"); if (cond & BL_MASK_SLIMED) Strcat(status_vals[fldidx], " Slime"); value = cond; break; default: value = atol(text); Sprintf(status_vals[fldidx], status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s", text); break; } #ifdef STATUS_HILITES switch (tty_status_hilites[fldidx].behavior) { case BL_TH_NONE: tty_status_colors[fldidx] = NO_COLOR; break; case BL_TH_UPDOWN: if (chg > 0) tty_status_colors[fldidx] = tty_status_hilites[fldidx].over; else if (chg < 0) tty_status_colors[fldidx] = tty_status_hilites[fldidx].under; else tty_status_colors[fldidx] = NO_COLOR; break; case BL_TH_VAL_PERCENTAGE: { int pct_th = 0; if (tty_status_hilites[fldidx].thresholdtype != ANY_INT) { impossible( "tty_status_update: unsupported percentage threshold type %d", tty_status_hilites[fldidx].thresholdtype); } else { pct_th = tty_status_hilites[fldidx].threshold.a_int; tty_status_colors[fldidx] = (percent >= pct_th) ? tty_status_hilites[fldidx].over : tty_status_hilites[fldidx].under; } break; } case BL_TH_VAL_ABSOLUTE: { int c = NO_COLOR; int o = tty_status_hilites[fldidx].over; int u = tty_status_hilites[fldidx].under; anything *t = &tty_status_hilites[fldidx].threshold; switch (tty_status_hilites[fldidx].thresholdtype) { case ANY_LONG: c = (value >= t->a_long) ? o : u; break; case ANY_INT: c = (value >= t->a_int) ? o : u; break; case ANY_UINT: c = ((unsigned long) value >= t->a_uint) ? o : u; break; case ANY_ULONG: c = ((unsigned long) value >= t->a_ulong) ? o : u; break; case ANY_MASK32: c = (value & t->a_ulong) ? o : u; break; default: impossible( "tty_status_update: unsupported absolute threshold type %d\n", tty_status_hilites[fldidx].thresholdtype); break; } tty_status_colors[fldidx] = c; break; } /* case */ } /* switch */ #endif /* STATUS_HILITES */ } /* For now, this version copied from the genl_ version currently * updates everything on the display, everytime */ if (!beenhere || !iflags.use_status_hilites) { char newbot1[MAXCO], newbot2[MAXCO]; newbot1[0] = '\0'; for (i = 0; fieldorder[0][i] >= 0; ++i) { int idx1 = fieldorder[0][i]; if (status_activefields[idx1]) Strcat(newbot1, status_vals[idx1]); } newbot2[0] = '\0'; for (i = 0; fieldorder[1][i] >= 0; ++i) { int idx2 = fieldorder[1][i]; if (status_activefields[idx2]) Strcat(newbot2, status_vals[idx2]); } curs(WIN_STATUS, 1, 0); putstr(WIN_STATUS, 0, newbot1); curs(WIN_STATUS, 1, 1); putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */ beenhere = TRUE; return; } curs(WIN_STATUS, 1, 0); for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) { int fldidx1 = fieldorder[0][i]; if (status_activefields[fldidx1]) { if (tty_status_colors[fldidx1] < 0 && tty_status_colors[fldidx1] >= -3) { /* attribute, not a color */ attridx = tty_status_colors[fldidx1] + 3; term_start_attr(statusattr[attridx]); putstr(WIN_STATUS, 0, status_vals[fldidx1]); term_end_attr(statusattr[attridx]); #ifdef TEXTCOLOR } else if (tty_status_colors[fldidx1] != CLR_MAX) { if (tty_status_colors[fldidx1] != NO_COLOR) term_start_color(tty_status_colors[fldidx1]); putstr(WIN_STATUS, 0, status_vals[fldidx1]); if (tty_status_colors[fldidx1] != NO_COLOR) term_end_color(); #endif } else putstr(WIN_STATUS, 0, status_vals[fldidx1]); } } curs(WIN_STATUS, 1, 1); for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) { int fldidx2 = fieldorder[1][i]; if (status_activefields[fldidx2]) { if (tty_status_colors[fldidx2] < 0 && tty_status_colors[fldidx2] >= -3) { /* attribute, not a color */ attridx = tty_status_colors[fldidx2] + 3; term_start_attr(statusattr[attridx]); putstr(WIN_STATUS, 0, status_vals[fldidx2]); term_end_attr(statusattr[attridx]); #ifdef TEXTCOLOR } else if (tty_status_colors[fldidx2] != CLR_MAX) { if (tty_status_colors[fldidx2] != NO_COLOR) term_start_color(tty_status_colors[fldidx2]); if (fldidx2 == BL_GOLD) { /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, status_vals[fldidx2]); } else { putstr(WIN_STATUS, 0, status_vals[fldidx2]); } if (tty_status_colors[fldidx2] != NO_COLOR) term_end_color(); #endif } else putstr(WIN_STATUS, 0, status_vals[fldidx2]); } } return; } #ifdef STATUS_HILITES /* * status_threshold(int fldidx, int threshholdtype, anything threshold, * int behavior, int under, int over) * * -- called when a hiliting preference is added, changed, or * removed. * -- the fldindex identifies which field is having its hiliting * preference set. It is an integer index value from botl.h * -- fldindex could be any one of the following from botl.h: * BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, * BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, * BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, * BL_LEVELDESC, BL_EXP, BL_CONDITION * -- datatype is P_INT, P_UINT, P_LONG, or P_MASK. * -- threshold is an "anything" union which can contain the * datatype value. * -- behavior is used to define how threshold is used and can * be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE, * or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above * or below the threshold. BL_TH_VAL_PERCENTAGE treats the * threshold value as a precentage of the maximum possible * value. BL_TH_VAL_ABSOLUTE means that the threshold is an * actual value. BL_TH_UPDOWN means that threshold is not * used, and the two below/above hilite values indicate how * to display something going down (under) or rising (over). * -- under is the hilite attribute used if value is below the * threshold. The attribute can be BL_HILITE_NONE, * BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one * of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, * CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, * CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, * CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). * -- over is the hilite attribute used if value is at or above * the threshold. The attribute can be BL_HILITE_NONE, * BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one * of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, * CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, * CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, * CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). */ void tty_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over) int fldidx, thresholdtype; int behavior, under, over; anything threshold; { tty_status_hilites[fldidx].thresholdtype = thresholdtype; tty_status_hilites[fldidx].threshold = threshold; tty_status_hilites[fldidx].behavior = behavior; tty_status_hilites[fldidx].under = under; tty_status_hilites[fldidx].over = over; return; } #endif /* STATUS_HILITES */ #endif /*STATUS_VIA_WINDOWPORT*/ #endif /* TTY_GRAPHICS */ /*wintty.c*/ nethack-3.6.0/win/win32/dgnstuff.mak0000664000076400007660000000265612536476415016234 0ustar paxedpaxed# $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Set all of these or none of them. # # bison and flex are the ones found in GnuWin32, which # is probably the easiest set of these tools to find # on Windows. # #YACC = bison.exe -y #LEX = flex.exe #YTABC = y.tab.c #YTABH = y.tab.h #LEXYYC = lex.yy.c default: all all: tools ..\util\dgn_yacc.c ..\util\dgn_lex.c rebuild: clean all clean: -del ..\util\dgn_lex.c -del ..\util\dgn_yacc.c -del ..\include\dgn_comp.h tools: !IFDEF YACC @echo Yacc-alike set to $(YACC) @echo YTABC set to $(YTABC) @echo YTABH set to $(YTABH) !ENDIF !IFDEF LEX @echo Lex-alike set to $(LEX) @echo LEXYYC set to $(LEXYYC) !ENDIF #========================================== # Dungeon Compiler Stuff #========================================== ..\util\dgn_yacc.c ..\include\dgn_comp.h : ..\util\dgn_comp.y !IF "$(YACC)"=="" @echo Using pre-built dgn_yacc.c and dgn_comp.h @copy ..\sys\share\dgn_yacc.c ..\util\dgn_yacc.c @copy ..\sys\share\dgn_comp.h ..\include\dgn_comp.h !ELSE chdir ..\util $(YACC) -d dgn_comp.y copy $(YTABC) $@ copy $(YTABH) ..\include\dgn_comp.h @del $(YTABC) @del $(YTABH) chdir ..\build !ENDIF ..\util\dgn_lex.c: ..\util\dgn_comp.l !IF "$(LEX)"=="" @echo Using pre-built dgn_lex.c @copy ..\sys\share\dgn_lex.c $@ !ELSE chdir ..\util $(LEX) dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir ..\build !ENDIF nethack-3.6.0/win/win32/levstuff.mak0000664000076400007660000000275212536476415016247 0ustar paxedpaxed# $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ # Set all of these or none of them. # # bison and flex are the ones found in GnuWin32, which # is probably the easiest set of these tools to find # on Windows. # #YACC = bison.exe -y #LEX = flex.exe #YTABC = y.tab.c #YTABH = y.tab.h #LEXYYC = lex.yy.c default: all all: tools ..\util\lev_yacc.c ..\util\lev_lex.c rebuild: clean all clean: -del ..\util\lev_lex.c -del ..\util\lev_yacc.c -del ..\include\lev_comp.h tools: !IFDEF YACC @echo Yacc-alike set to $(YACC) @echo YTABC set to $(YTABC) @echo YTABH set to $(YTABH) !ENDIF !IFDEF LEX @echo Lex-alike set to $(LEX) @echo LEXYYC set to $(LEXYYC) !ENDIF #========================================== # Level Compiler Stuff #========================================== ..\util\lev_yacc.c ..\include\lev_comp.h: ..\util\lev_comp.y !IFNDEF YACC @echo Using pre-built lev_yacc.c and lev_comp.h @copy ..\sys\share\lev_yacc.c ..\util\lev_yacc.c @copy ..\sys\share\lev_comp.h ..\include\lev_comp.h !ELSE @echo Generating lev_yacc.c and lev_comp.h chdir ..\util $(YACC) -d lev_comp.y copy $(YTABC) $@ copy $(YTABH) ..\include\lev_comp.h @del $(YTABC) @del $(YTABH) chdir ..\build !ENDIF ..\util\lev_lex.c: ..\util\lev_comp.l !IFNDEF LEX @echo Using pre-built lev_lex.c @copy ..\sys\share\lev_lex.c $@ !ELSE @echo Generating lev_lex.c chdir ..\util $(LEX) lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir ..\build !ENDIF nethack-3.6.0/win/win32/mhaskyn.c0000664000076400007660000000076412536476415015536 0ustar paxedpaxed/* NetHack 3.6 mhaskyn.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhaskyn.h" int mswin_yes_no_dialog(const char *question, const char *choices, int def) { UNREFERENCED_PARAMETER(question); UNREFERENCED_PARAMETER(choices); UNREFERENCED_PARAMETER(def); return '\032'; } nethack-3.6.0/win/win32/mhaskyn.h0000664000076400007660000000062712536476415015541 0ustar paxedpaxed/* NetHack 3.6 mhaskyn.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINAskYesNO_h #define MSWINAskYesNO_h #include "winMS.h" int mswin_yes_no_dialog(const char *question, const char *choices, int def); #endif /* MSWINAskYesNO_h */ nethack-3.6.0/win/win32/mhdlg.c0000664000076400007660000006722212610522241015137 0ustar paxedpaxed/* NetHack 3.6 mhdlg.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* various dialog boxes are defined here */ #include "winMS.h" #include "hack.h" #include "func_tab.h" #include "resource.h" #include "mhdlg.h" /*---------------------------------------------------------------*/ /* data for getlin dialog */ struct getlin_data { const char *question; char *result; size_t result_size; }; INT_PTR CALLBACK GetlinDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_getlin_window(const char *question, char *result, size_t result_size) { INT_PTR ret; struct getlin_data data; /* initilize dialog data */ ZeroMemory(&data, sizeof(data)); data.question = question; data.result = result; data.result_size = result_size; /* create modal dialog window */ ret = DialogBoxParam(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_GETLIN), GetNHApp()->hMainWnd, GetlinDlgProc, (LPARAM) &data); if (ret == -1) panic("Cannot create getlin window"); return (int) ret; } INT_PTR CALLBACK GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct getlin_data *data; RECT main_rt, dlg_rt; SIZE dlg_sz; TCHAR wbuf[BUFSZ]; HDC WindowDC; HWND ControlHWND; SIZE WindowExtents; SIZE ViewPortExtents; RECT ControlRect; RECT ClientRect; LONG Division; LONG ButtonOffset; switch (message) { case WM_INITDIALOG: data = (struct getlin_data *) lParam; SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf))); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* center dialog in the main window */ GetWindowRect(hWnd, &dlg_rt); GetWindowRect(GetNHApp()->hMainWnd, &main_rt); WindowDC = GetWindowDC(hWnd); if (!GetWindowExtEx(WindowDC, &WindowExtents) || !GetViewportExtEx(WindowDC, &ViewPortExtents) || !GetTextExtentPoint32(GetWindowDC(hWnd), wbuf, _tcslen(wbuf), &dlg_sz)) { dlg_sz.cx = 0; } else { /* I think we need to do the following scaling */ dlg_sz.cx *= ViewPortExtents.cx; dlg_sz.cx /= WindowExtents.cx; /* Add the size of the various items in the caption bar */ dlg_sz.cx += GetSystemMetrics(SM_CXSIZE) + 2 * (GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME)); } if (dlg_sz.cx < dlg_rt.right - dlg_rt.left) dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); /* set focus and size of the edit control */ ControlHWND = GetDlgItem(hWnd, IDC_GETLIN_EDIT); SetFocus(ControlHWND); GetClientRect(hWnd, &ClientRect); GetWindowRect(ControlHWND, &ControlRect); MoveWindow(ControlHWND, 0, 0, ClientRect.right - ClientRect.left, ControlRect.bottom - ControlRect.top, TRUE); ButtonOffset = ControlRect.bottom - ControlRect.top; /* Now get the OK and CANCEL buttons */ ControlHWND = GetDlgItem(hWnd, IDOK); GetWindowRect(ControlHWND, &ControlRect); Division = ((ClientRect.right - ClientRect.left) - 2 * (ControlRect.right - ControlRect.left)) / 3; MoveWindow(ControlHWND, Division, ButtonOffset, ControlRect.right - ControlRect.left, ControlRect.bottom - ControlRect.top, TRUE); ControlHWND = GetDlgItem(hWnd, IDCANCEL); MoveWindow(ControlHWND, Division * 2 + ControlRect.right - ControlRect.left, ButtonOffset, ControlRect.right - ControlRect.left, ControlRect.bottom - ControlRect.top, TRUE); /* tell windows that we've set the focus */ return FALSE; break; case WM_COMMAND: { TCHAR wbuf[BUFSZ]; switch (LOWORD(wParam)) { /* OK button was pressed */ case IDOK: data = (struct getlin_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA); SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, (WPARAM) sizeof(wbuf), (LPARAM) wbuf); NH_W2A(wbuf, data->result, data->result_size); /* Fall through. */ /* cancel button was pressed */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; } } break; } /* end switch (message) */ return FALSE; } /*---------------------------------------------------------------*/ /* dialog data for the list of extended commands */ struct extcmd_data { int *selection; }; INT_PTR CALLBACK ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_ext_cmd_window(int *selection) { INT_PTR ret; struct extcmd_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); *selection = -1; data.selection = selection; /* create modal dialog window */ ret = DialogBoxParam(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_EXTCMD), GetNHApp()->hMainWnd, ExtCmdDlgProc, (LPARAM) &data); if (ret == -1) panic("Cannot create extcmd window"); return (int) ret; } INT_PTR CALLBACK ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct extcmd_data *data; RECT main_rt, dlg_rt; SIZE dlg_sz; int i; TCHAR wbuf[255]; switch (message) { case WM_INITDIALOG: data = (struct extcmd_data *) lParam; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); /* fill combobox with extended commands */ for (i = 0; extcmdlist[i].ef_txt; i++) { SendDlgItemMessage( hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(extcmdlist[i].ef_txt, wbuf, sizeof(wbuf))); } /* set focus to the list control */ SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct extcmd_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (LOWORD(wParam)) { /* OK button ws clicked */ case IDOK: *data->selection = (int) SendDlgItemMessage( hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); if (*data->selection == LB_ERR) *data->selection = -1; /* Fall through. */ /* CANCEL button ws clicked */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; /* list control events */ case IDC_EXTCMD_LIST: switch (HIWORD(wParam)) { case LBN_DBLCLK: /* double click within the list wParam The low-order word is the list box identifier. The high-order word is the notification message. lParam Handle to the list box */ *data->selection = (int) SendMessage( (HWND) lParam, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); if (*data->selection == LB_ERR) *data->selection = -1; EndDialog(hWnd, IDOK); return TRUE; } break; } } return FALSE; } /*---------------------------------------------------------------*/ /* player selector dialog data */ struct plsel_data { int *selection; }; INT_PTR CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); static void plselInitDialog(HWND hWnd); static void plselAdjustLists(HWND hWnd, int changed_opt); static int plselFinalSelection(HWND hWnd, int *selection); int mswin_player_selection_window(int *selection) { INT_PTR ret; struct plsel_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); data.selection = selection; /* create modal dialog */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR), GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM) &data); if (ret == -1) panic("Cannot create getlin window"); return (int) ret; } INT_PTR CALLBACK PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct plsel_data *data; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: data = (struct plsel_data *) lParam; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); /* init dialog */ plselInitDialog(hWnd); /* set focus on the role checkbox (random) field */ SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (LOWORD(wParam)) { /* OK button was clicked */ case IDOK: if (plselFinalSelection(hWnd, data->selection)) { EndDialog(hWnd, wParam); } else { NHMessageBox( hWnd, TEXT("Cannot match this role. Try something else."), MB_ICONSTOP | MB_OK); } return TRUE; /* CANCEL button was clicked */ case IDCANCEL: *data->selection = -1; EndDialog(hWnd, wParam); return TRUE; /* following are events from dialog controls: "random" checkboxes send BN_CLICKED messages; role/race/... combo-boxes send CBN_SELENDOK if something was selected; */ case IDC_PLSEL_ROLE_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { /* enable corresponding list window if "random" checkbox was "unchecked" */ EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_RACE_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_GENDER_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_ALIGN_RANDOM: if (HIWORD(wParam) == BN_CLICKED) { EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_UNCHECKED); } break; case IDC_PLSEL_ROLE_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { /* filter out invalid options if the selection was made */ plselAdjustLists(hWnd, LOWORD(wParam)); } break; case IDC_PLSEL_RACE_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { plselAdjustLists(hWnd, LOWORD(wParam)); } break; case IDC_PLSEL_GENDER_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { plselAdjustLists(hWnd, LOWORD(wParam)); } break; case IDC_PLSEL_ALIGN_LIST: if (HIWORD(wParam) == CBN_SELENDOK) { plselAdjustLists(hWnd, LOWORD(wParam)); } break; } break; } return FALSE; } void setComboBoxValue(HWND hWnd, int combo_box, int value) { int index_max = (int) SendDlgItemMessage(hWnd, combo_box, CB_GETCOUNT, 0, 0); int index; int value_to_set = LB_ERR; for (index = 0; index < index_max; index++) { if (SendDlgItemMessage(hWnd, combo_box, CB_GETITEMDATA, (WPARAM) index, 0) == value) { value_to_set = index; break; } } SendDlgItemMessage(hWnd, combo_box, CB_SETCURSEL, (WPARAM) value_to_set, 0); } /* initialize player selector dialog */ void plselInitDialog(HWND hWnd) { TCHAR wbuf[BUFSZ]; /* set player name */ SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf))); /* check flags for consistency */ if (flags.initrole >= 0) { if (flags.initrace >= 0 && !validrace(flags.initrole, flags.initrace)) { flags.initrace = ROLE_NONE; } if (flags.initgend >= 0 && !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = ROLE_NONE; } if (flags.initalign >= 0 && !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = ROLE_NONE; } } /* populate select boxes */ plselAdjustLists(hWnd, -1); /* intialize roles list */ if (flags.initrole < 0 || !ok_role(flags.initrole, ROLE_NONE, ROLE_NONE, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ROLE_LIST, flags.initrole); } /* intialize races list */ if (flags.initrace < 0 || !ok_race(flags.initrole, flags.initrace, ROLE_NONE, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_RACE_LIST, flags.initrace); } /* intialize genders list */ if (flags.initgend < 0 || !ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_GENDER_LIST, flags.initgend); } /* intialize alignments list */ if (flags.initalign < 0 || !ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign)) { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ALIGN_LIST, flags.initalign); } } /* adjust role/race/alignment/gender list - filter out invalid combinations changed_sel points to the list where selection occurred (-1 if unknown) */ void plselAdjustLists(HWND hWnd, int changed_sel) { HWND control_role, control_race, control_gender, control_align; int initrole, initrace, initgend, initalign; int i; LRESULT ind; int valid_opt; TCHAR wbuf[255]; /* get control handles */ control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST); control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST); control_gender = GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST); control_align = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST); /* get current selections */ ind = SendMessage(control_role, CB_GETCURSEL, 0, 0); initrole = (ind == LB_ERR) ? flags.initrole : (int) SendMessage(control_role, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_race, CB_GETCURSEL, 0, 0); initrace = (ind == LB_ERR) ? flags.initrace : (int) SendMessage(control_race, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0); initgend = (ind == LB_ERR) ? flags.initgend : (int) SendMessage(control_gender, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_align, CB_GETCURSEL, 0, 0); initalign = (ind == LB_ERR) ? flags.initalign : (int) SendMessage(control_align, CB_GETITEMDATA, ind, 0); /* intialize roles list */ if (changed_sel == -1) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_role, CB_RESETCONTENT, 0, 0); for (i = 0; roles[i].name.m; i++) { if (initgend >= 0 && flags.female && roles[i].name.f) ind = SendMessage( control_role, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(roles[i].name.f, wbuf, sizeof(wbuf))); else ind = SendMessage( control_role, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(roles[i].name.m, wbuf, sizeof(wbuf))); SendMessage(control_role, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initrole) { SendMessage(control_role, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected role if it is still valid */ if (!valid_opt) { initrole = ROLE_NONE; initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_role, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } /* trigger change of the races list */ changed_sel = IDC_PLSEL_ROLE_LIST; } /* intialize races list */ if (changed_sel == IDC_PLSEL_ROLE_LIST) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_race, CB_RESETCONTENT, 0, 0); for (i = 0; races[i].noun; i++) if (ok_race(initrole, i, ROLE_NONE, ROLE_NONE)) { ind = SendMessage( control_race, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(races[i].noun, wbuf, sizeof(wbuf))); SendMessage(control_race, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initrace) { SendMessage(control_race, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected race if it is still valid */ if (!valid_opt) { initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_race, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } /* trigger change of the genders list */ changed_sel = IDC_PLSEL_RACE_LIST; } /* intialize genders list */ if (changed_sel == IDC_PLSEL_RACE_LIST) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_gender, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(initrole, initrace, i, ROLE_NONE)) { ind = SendMessage( control_gender, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(genders[i].adj, wbuf, sizeof(wbuf))); SendMessage(control_gender, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initgend) { SendMessage(control_gender, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected gender if it is still valid */ if (!valid_opt) { initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_gender, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } /* trigger change of the alignments list */ changed_sel = IDC_PLSEL_GENDER_LIST; } /* intialize alignments list */ if (changed_sel == IDC_PLSEL_GENDER_LIST) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_align, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(initrole, initrace, initgend, i)) { ind = SendMessage( control_align, CB_ADDSTRING, (WPARAM) 0, (LPARAM) NH_A2W(aligns[i].adj, wbuf, sizeof(wbuf))); SendMessage(control_align, CB_SETITEMDATA, (WPARAM) ind, (LPARAM) i); if (i == initalign) { SendMessage(control_align, CB_SETCURSEL, (WPARAM) ind, (LPARAM) 0); valid_opt = 1; } } /* set selection to the previously selected alignment if it is still valid */ if (!valid_opt) { initalign = ROLE_NONE; SendMessage(control_align, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); } } } /* player made up his mind - get final selection here */ int plselFinalSelection(HWND hWnd, int *selection) { LRESULT ind; UNREFERENCED_PARAMETER(selection); /* get current selections */ if (SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initrole = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETCURSEL, 0, 0); flags.initrole = (ind == LB_ERR) ? ROLE_RANDOM : (int) SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETITEMDATA, ind, 0); } if (SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initrace = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETCURSEL, 0, 0); flags.initrace = (ind == LB_ERR) ? ROLE_RANDOM : (int) SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETITEMDATA, ind, 0); } if (SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initgend = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETCURSEL, 0, 0); flags.initgend = (ind == LB_ERR) ? ROLE_RANDOM : (int) SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETITEMDATA, ind, 0); } if (SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_RANDOM, BM_GETCHECK, 0, 0) == BST_CHECKED) { flags.initalign = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETCURSEL, 0, 0); flags.initalign = (ind == LB_ERR) ? ROLE_RANDOM : (int) SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETITEMDATA, ind, 0); } /* check the role */ if (flags.initrole == ROLE_RANDOM) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { NHMessageBox(hWnd, TEXT("Incompatible role!"), MB_ICONSTOP | MB_OK); return FALSE; } } /* Select a race, if necessary */ /* force compatibility with role */ if (flags.initrace == ROLE_RANDOM || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (flags.initrace == ROLE_RANDOM) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); } if (flags.initrace < 0) { NHMessageBox(hWnd, TEXT("Incompatible race!"), MB_ICONSTOP | MB_OK); return FALSE; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (flags.initgend == ROLE_RANDOM) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); } if (flags.initgend < 0) { NHMessageBox(hWnd, TEXT("Incompatible gender!"), MB_ICONSTOP | MB_OK); return FALSE; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (flags.initalign == ROLE_RANDOM) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); } else { NHMessageBox(hWnd, TEXT("Incompatible alignment!"), MB_ICONSTOP | MB_OK); return FALSE; } } return TRUE; } nethack-3.6.0/win/win32/mhdlg.h0000664000076400007660000000107212536476415015155 0ustar paxedpaxed/* NetHack 3.6 mhdlg.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINDlgWindow_h #define MSWINDlgWindow_h #include "winMS.h" #include "config.h" #include "global.h" int mswin_getlin_window(const char *question, char *result, size_t result_size); int mswin_ext_cmd_window(int *selection); int mswin_player_selection_window(int *selection); #endif /* MSWINDlgWindow_h */ nethack-3.6.0/win/win32/mhfont.c0000664000076400007660000002215712536476415015357 0ustar paxedpaxed/* NetHack 3.6 mhfont.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.23 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management and such */ #include "mhfont.h" #define MAXFONTS 64 /* font table - 64 fonts ought to be enough */ static struct font_table_entry { int code; HFONT hFont; } font_table[MAXFONTS]; static int font_table_size = 0; HFONT version_splash_font; #define NHFONT_CODE(win, attr) (((attr & 0xFF) << 8) | (win_type & 0xFF)) static void __cdecl font_table_cleanup(void); void mswin_init_splashfonts(HWND hWnd) { HDC hdc = GetDC(hWnd); LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); lgfnt.lfHeight = -80; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_BOLD; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = ANSI_CHARSET; // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W("Times New Roman", lgfnt.lfFaceName, LF_FACESIZE); version_splash_font = CreateFontIndirect(&lgfnt); ReleaseDC(hWnd, hdc); } void mswin_destroy_splashfonts() { DeleteObject(version_splash_font); } /* create font based on window type, charater attributes and window device context */ HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) { HFONT fnt = NULL; LOGFONT lgfnt; int font_size; int font_index; static BOOL once = FALSE; if (!once) { once = TRUE; atexit(font_table_cleanup); } ZeroMemory(&lgfnt, sizeof(lgfnt)); /* try find font in the table */ for (font_index = 0; font_index < font_table_size; font_index++) if (NHFONT_CODE(win_type, attr) == font_table[font_index].code) break; if (!replace && font_index < font_table_size) return font_table[font_index].hFont; switch (win_type) { case NHW_STATUS: font_size = (attr == ATR_BOLD) ? iflags.wc_fontsiz_status + 1 : iflags.wc_fontsiz_status; lgfnt.lfHeight = -font_size * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_status && *iflags.wc_font_status) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_status, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family } break; case NHW_MENU: lgfnt.lfHeight = -iflags.wc_fontsiz_menu * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option lgfnt.lfUnderline = (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_menu && *iflags.wc_font_menu) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_menu, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family } break; case NHW_MESSAGE: font_size = (attr == ATR_INVERSE) ? iflags.wc_fontsiz_message + 1 : iflags.wc_fontsiz_message; lgfnt.lfHeight = -font_size * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option lgfnt.lfUnderline = (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_message && *iflags.wc_font_message) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = VARIABLE_PITCH; // pitch and family } break; case NHW_TEXT: lgfnt.lfHeight = -iflags.wc_fontsiz_text * GetDeviceCaps(hdc, LOGPIXELSY) / 72; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = (attr == ATR_BOLD || attr == ATR_INVERSE) ? FW_BOLD : FW_NORMAL; // font weight lgfnt.lfItalic = (attr == ATR_BLINK) ? TRUE : FALSE; // italic attribute option lgfnt.lfUnderline = (attr == ATR_ULINE) ? TRUE : FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_text && *iflags.wc_font_text) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_text, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family } break; } fnt = CreateFontIndirect(&lgfnt); /* add font to the table */ if (font_index == font_table_size) { if (font_table_size >= MAXFONTS) panic("font table overflow!"); font_table_size++; } else { DeleteObject(font_table[font_index].hFont); } font_table[font_index].code = NHFONT_CODE(win_type, attr); font_table[font_index].hFont = fnt; return fnt; } UINT mswin_charset() { CHARSETINFO cis; if (SYMHANDLING(H_IBM)) if (TranslateCharsetInfo((DWORD *) GetOEMCP(), &cis, TCI_SRCCODEPAGE)) return cis.ciCharset; else return OEM_CHARSET; else if (TranslateCharsetInfo((DWORD *) GetACP(), &cis, TCI_SRCCODEPAGE)) return cis.ciCharset; else return ANSI_CHARSET; } void __cdecl font_table_cleanup(void) { int i; for (i = 0; i < font_table_size; i++) { DeleteObject(font_table[i].hFont); } font_table_size = 0; } nethack-3.6.0/win/win32/mhfont.h0000664000076400007660000000101612536476415015353 0ustar paxedpaxed/* NetHack 3.6 mhfont.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management functions */ #ifndef MSWINFont_h #define MSWINFont_h #include "winMS.h" HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); void mswin_init_splashfonts(HWND hWnd); void mswin_destroy_splashfonts(void); UINT mswin_charset(void); #endif /* MSWINFont_h */ nethack-3.6.0/win/win32/mhinput.c0000664000076400007660000000527412536476415015551 0ustar paxedpaxed/* NetHack 3.6 mhinput.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhinput.h" /* nethack input queue functions */ #define NH_INPUT_BUFFER_SIZE 64 /* as it stands right now we need only one slot since events are processed almost the same time as they occur but I like large round numbers */ static MSNHEvent nhi_input_buffer[NH_INPUT_BUFFER_SIZE]; static int nhi_init_input = 0; static int nhi_read_pos = 0; static int nhi_write_pos = 0; /* initialize input queue */ void mswin_nh_input_init(void) { if (!nhi_init_input) { nhi_init_input = 1; ZeroMemory(nhi_input_buffer, sizeof(nhi_input_buffer)); nhi_read_pos = 0; nhi_write_pos = 0; } } /* check for input */ int mswin_have_input() { return #ifdef SAFERHANGUP /* we always have input (ESC) if hangup was requested */ program_state.done_hup || #endif (nhi_read_pos != nhi_write_pos); } /* add event to the queue */ void mswin_input_push(PMSNHEvent event) { int new_write_pos; if (!nhi_init_input) mswin_nh_input_init(); new_write_pos = (nhi_write_pos + 1) % NH_INPUT_BUFFER_SIZE; if (new_write_pos != nhi_read_pos) { memcpy(nhi_input_buffer + nhi_write_pos, event, sizeof(*event)); nhi_write_pos = new_write_pos; } } /* get event from the queue and delete it */ PMSNHEvent mswin_input_pop() { PMSNHEvent retval; #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.kbd.ch = '\033'; return &hangup_event; } #endif if (!nhi_init_input) mswin_nh_input_init(); if (nhi_read_pos != nhi_write_pos) { retval = &nhi_input_buffer[nhi_read_pos]; nhi_read_pos = (nhi_read_pos + 1) % NH_INPUT_BUFFER_SIZE; } else { retval = NULL; } return retval; } /* get event from the queue but leave it there */ PMSNHEvent mswin_input_peek() { PMSNHEvent retval; #ifdef SAFERHANGUP /* always return ESC when hangup was requested */ if (program_state.done_hup) { static MSNHEvent hangup_event; hangup_event.type = NHEVENT_CHAR; hangup_event.kbd.ch = '\033'; return &hangup_event; } #endif if (!nhi_init_input) mswin_nh_input_init(); if (nhi_read_pos != nhi_write_pos) { retval = &nhi_input_buffer[nhi_read_pos]; } else { retval = NULL; } return retval; } nethack-3.6.0/win/win32/mhinput.h0000664000076400007660000000242512536476415015551 0ustar paxedpaxed/* NetHack 3.6 mhinput.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINInput_h #define MSWINInput_h /* nethack input queue - store/extract input events */ #include "winMS.h" #define NHEVENT_CHAR 1 #define NHEVENT_MOUSE 2 typedef struct mswin_event { int type; union { struct { int ch; } kbd; struct { int mod; int x, y; } ms; }; } MSNHEvent, *PMSNHEvent; #define NHEVENT_KBD(c) \ { \ MSNHEvent e; \ e.type = NHEVENT_CHAR; \ e.kbd.ch = (c); \ mswin_input_push(&e); \ } #define NHEVENT_MS(_mod, _x, _y) \ { \ MSNHEvent e; \ e.type = NHEVENT_MOUSE; \ e.ms.mod = (_mod); \ e.ms.x = (_x); \ e.ms.y = (_y); \ mswin_input_push(&e); \ } void mswin_nh_input_init(void); int mswin_have_input(void); void mswin_input_push(PMSNHEvent event); PMSNHEvent mswin_input_pop(void); PMSNHEvent mswin_input_peek(void); #endif /* MSWINInput_h */ nethack-3.6.0/win/win32/mhmain.c0000664000076400007660000011164612536476415015337 0ustar paxedpaxed/* NetHack 3.6 mhmain.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "date.h" #include "patchlevel.h" #include "resource.h" #include "mhmsg.h" #include "mhinput.h" #include "mhmain.h" #include "mhmenu.h" #include "mhstatus.h" #include "mhmsgwnd.h" #include "mhmap.h" typedef struct mswin_nethack_main_window { int mapAcsiiModeSave; } NHMainWindow, *PNHMainWindow; extern winid WIN_STATUS; static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; extern void mswin_display_splash_window(BOOL); LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void register_main_window_class(void); static int menuid2mapmode(int menuid); static int mapmode2menuid(int map_mode); static void nhlock_windows(BOOL lock); static char *nh_compose_ascii_screenshot(); // returns strdup() created pointer - callee assumes the ownership HWND mswin_init_main_window() { static int run_once = 0; HWND ret; WINDOWPLACEMENT wp; /* register window class */ if (!run_once) { LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); register_main_window_class(); run_once = 1; } /* create the main window */ ret = CreateWindow(szMainWindowClass, /* registered class name */ szTitle, /* window name */ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */ CW_USEDEFAULT, /* horizontal position of window */ CW_USEDEFAULT, /* vertical position of window */ CW_USEDEFAULT, /* window width */ CW_USEDEFAULT, /* window height */ NULL, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL /* window-creation data */ ); if (!ret) panic("Cannot create main window"); if (GetNHApp()->regMainMinX != CW_USEDEFAULT) { wp.length = sizeof(wp); wp.showCmd = GetNHApp()->regMainShowState; wp.ptMinPosition.x = GetNHApp()->regMainMinX; wp.ptMinPosition.y = GetNHApp()->regMainMinY; wp.ptMaxPosition.x = GetNHApp()->regMainMaxX; wp.ptMaxPosition.y = GetNHApp()->regMainMaxY; wp.rcNormalPosition.left = GetNHApp()->regMainLeft; wp.rcNormalPosition.top = GetNHApp()->regMainTop; wp.rcNormalPosition.right = GetNHApp()->regMainRight; wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom; SetWindowPlacement(ret, &wp); } else ShowWindow(ret, SW_SHOWDEFAULT); UpdateWindow(ret); return ret; } void register_main_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC) MainWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR) IDI_NETHACKW); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = (TCHAR *) IDC_NETHACKW; wcex.lpszClassName = szMainWindowClass; RegisterClass(&wcex); } /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ enum KEY_INDEXES { KEY_NW, KEY_N, KEY_NE, KEY_MINUS, KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS, KEY_SW, KEY_S, KEY_SE, KEY_INV, KEY_WAITLOOK, KEY_LAST }; static const unsigned char /* normal, shift, control */ keypad[KEY_LAST][3] = { { 'y', 'Y', C('y') }, /* 7 */ { 'k', 'K', C('k') }, /* 8 */ { 'u', 'U', C('u') }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { 'h', 'H', C('h') }, /* 4 */ { 'g', 'G', 'g' }, /* 5 */ { 'l', 'L', C('l') }, /* 6 */ { '+', 'P', C('p') }, /* + */ { 'b', 'B', C('b') }, /* 1 */ { 'j', 'J', C('j') }, /* 2 */ { 'n', 'N', C('n') }, /* 3 */ { 'i', 'I', C('i') }, /* Ins */ { '.', ':', ':' } /* Del */ }, numpad[KEY_LAST][3] = { { '7', M('7'), '7' }, /* 7 */ { '8', M('8'), '8' }, /* 8 */ { '9', M('9'), '9' }, /* 9 */ { 'm', C('p'), C('p') }, /* - */ { '4', M('4'), '4' }, /* 4 */ { '5', M('5'), '5' }, /* 5 */ { '6', M('6'), '6' }, /* 6 */ { '+', 'P', C('p') }, /* + */ { '1', M('1'), '1' }, /* 1 */ { '2', M('2'), '2' }, /* 2 */ { '3', M('3'), '3' }, /* 3 */ { '0', M('0'), '0' }, /* Ins */ { '.', ':', ':' } /* Del */ }; #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0) #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0]) #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1]) #define KEYTABLE(x) \ (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x)) static const char *extendedlist = "acdefijlmnopqrstuvw?2"; #define SCANLO 0x02 static const char scanmap[] = { /* ... */ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '?' /* ... */ }; /* // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. */ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMainWindow data; switch (message) { case WM_CREATE: /* set window data */ data = (PNHMainWindow) malloc(sizeof(NHMainWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHMainWindow)); data->mapAcsiiModeSave = MAP_MODE_ASCII12x16; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* update menu items */ CheckMenuItem( GetMenu(hWnd), IDM_SETTING_LOCKWINDOWS, MF_BYCOMMAND | (GetNHApp()->bWindowsLocked ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(GetMenu(hWnd), IDM_SETTING_AUTOLAYOUT, GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED); /* store handle to the mane menu in the application record */ GetNHApp()->hMainWnd = hWnd; break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_KEYDOWN: { data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* translate arrow keys into nethack commands */ switch (wParam) { case VK_LEFT: if (STATEON(VK_CONTROL)) { /* scroll map window one line left */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_W)); } return 0; case VK_RIGHT: if (STATEON(VK_CONTROL)) { /* scroll map window one line right */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_E)); } return 0; case VK_UP: if (STATEON(VK_CONTROL)) { /* scroll map window one line up */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_N)); } return 0; case VK_DOWN: if (STATEON(VK_CONTROL)) { /* scroll map window one line down */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_S)); } return 0; case VK_HOME: if (STATEON(VK_CONTROL)) { /* scroll map window to upper left corner */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL); SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_NW)); } return 0; case VK_END: if (STATEON(VK_CONTROL)) { /* scroll map window to lower right corner */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM) NULL); SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_SW)); } return 0; case VK_PRIOR: if (STATEON(VK_CONTROL)) { /* scroll map window one page up */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_NE)); } return 0; case VK_NEXT: if (STATEON(VK_CONTROL)) { /* scroll map window one page down */ SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM) NULL); } else { NHEVENT_KBD(KEYTABLE(KEY_SE)); } return 0; case VK_DECIMAL: case VK_DELETE: NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK)); return 0; case VK_INSERT: NHEVENT_KBD(KEYTABLE(KEY_INV)); return 0; case VK_SUBTRACT: NHEVENT_KBD(KEYTABLE(KEY_MINUS)); return 0; case VK_ADD: NHEVENT_KBD(KEYTABLE(KEY_PLUS)); return 0; case VK_CLEAR: /* This is the '5' key */ NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING)); return 0; case VK_F4: if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? data->mapAcsiiModeSave : MAP_MODE_TILES); } else { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN); } return 0; case VK_F5: if (IS_MAP_ASCII(iflags.wc_map_mode)) { if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN); } else { mswin_select_map_mode(MAP_MODE_TILES); } } else { if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN); } else { mswin_select_map_mode(data->mapAcsiiModeSave); } } return 0; default: { WORD c; BYTE kbd_state[256]; c = 0; ZeroMemory(kbd_state, sizeof(kbd_state)); GetKeyboardState(kbd_state); if (ToAscii(wParam, (lParam >> 16) & 0xFF, kbd_state, &c, 0)) { NHEVENT_KBD(c & 0xFF); return 0; } else { return 1; } } } /* end switch */ } break; case WM_SYSCHAR: /* Alt-char pressed */ { /* If not nethackmode, don't handle Alt-keys here. If no Alt-key pressed it can never be an extended command */ if (GetNHApp()->regNetHackMode && ((lParam & 1 << 29) != 0)) { unsigned char c = (unsigned char) (wParam & 0xFF); unsigned char scancode = (lParam >> 16) & 0xFF; if (index(extendedlist, tolower(c)) != 0) { NHEVENT_KBD(M(tolower(c))); } else if (scancode == (SCANLO + SIZE(scanmap)) - 1) { NHEVENT_KBD(M('?')); } return 0; } return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_COMMAND: /* process commands - menu commands mostly */ if (onWMCommand(hWnd, wParam, lParam)) return DefWindowProc(hWnd, message, wParam, lParam); else return 0; case WM_MOVE: case WM_SIZE: { WINDOWPLACEMENT wp; mswin_layout_main_window(NULL); wp.length = sizeof(wp); if (GetWindowPlacement(hWnd, &wp)) { GetNHApp()->regMainShowState = (wp.showCmd == SW_SHOWMAXIMIZED ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); GetNHApp()->regMainMinX = wp.ptMinPosition.x; GetNHApp()->regMainMinY = wp.ptMinPosition.y; GetNHApp()->regMainMaxX = wp.ptMaxPosition.x; GetNHApp()->regMainMaxY = wp.ptMaxPosition.y; GetNHApp()->regMainLeft = wp.rcNormalPosition.left; GetNHApp()->regMainTop = wp.rcNormalPosition.top; GetNHApp()->regMainRight = wp.rcNormalPosition.right; GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom; } break; } case WM_SETFOCUS: /* if there is a menu window out there - transfer input focus to it */ if (IsWindow(GetNHApp()->hPopupWnd)) { SetFocus(GetNHApp()->hPopupWnd); } break; case WM_CLOSE: { /* exit gracefully */ if (program_state.gameover) { /* assume the user really meant this, as the game is already * over... */ /* to make sure we still save bones, just set stop printing flag */ program_state.stopprint++; NHEVENT_KBD( '\033'); /* and send keyboard input as if user pressed ESC */ /* additional code for this is done in menu and rip windows */ } else if (!program_state.something_worth_saving) { /* User exited before the game started, e.g. during splash display */ /* Just get out. */ bail((char *) 0); } else { /* prompt user for action */ switch (NHMessageBox(hWnd, TEXT("Save?"), MB_YESNOCANCEL | MB_ICONQUESTION)) { case IDYES: #ifdef SAFERHANGUP /* destroy popup window - it has its own loop and we need to return control to NetHack core at this point */ if (IsWindow(GetNHApp()->hPopupWnd)) SendMessage(GetNHApp()->hPopupWnd, WM_COMMAND, IDCANCEL, 0); /* tell NetHack core that "hangup" is requested */ hangup(1); #else NHEVENT_KBD('y'); dosave(); #endif break; case IDNO: NHEVENT_KBD('q'); done(QUIT); break; case IDCANCEL: break; } } } return 0; case WM_DESTROY: /* apparently we never get here TODO: work on exit routines - need to send WM_QUIT somehow */ /* clean up */ free((PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA)); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); // PostQuitMessage(0); exit(1); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(hWnd); UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); switch (wParam) { /* new window was just added */ case MSNH_MSG_ADDWND: { PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd) lParam; HWND child; if (GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP) mswin_select_map_mode(iflags.wc_map_mode); child = GetNHApp()->windowlist[msg_param->wid].win; } break; } } /* adjust windows to fit main window layout --------------------------- | Status | +-------------------------+ | | | | | MAP | | | | | +-------------------------+ | Messages | --------------------------- */ void mswin_layout_main_window(HWND changed_child) { winid i; RECT client_rt, wnd_rect; POINT status_org; SIZE status_size; POINT msg_org; SIZE msg_size; POINT map_org; SIZE map_size; SIZE menu_size; HWND wnd_status, wnd_msg; PNHMainWindow data; if (GetNHApp()->bAutoLayout) { GetClientRect(GetNHApp()->hMainWnd, &client_rt); data = (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd, GWLP_USERDATA); /* get sizes of child windows */ wnd_status = mswin_hwnd_from_winid(WIN_STATUS); if (IsWindow(wnd_status)) { mswin_status_window_size(wnd_status, &status_size); } else { status_size.cx = status_size.cy = 0; } wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE); if (IsWindow(wnd_msg)) { mswin_message_window_size(wnd_msg, &msg_size); } else { msg_size.cx = msg_size.cy = 0; } /* find all menu windows and calculate the size */ menu_size.cx = menu_size.cy = 0; for (i = 0; i < MAXWINDOWS; i++) { SIZE tmp_size; if (GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead && GetNHApp()->windowlist[i].type == NHW_MENU) { mswin_menu_window_size(GetNHApp()->windowlist[i].win, &tmp_size); menu_size.cx = max(menu_size.cx, tmp_size.cx); menu_size.cy = max(menu_size.cy, tmp_size.cy); } } /* set window positions */ SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom); switch (iflags.wc_align_status) { case ALIGN_LEFT: status_size.cx = (wnd_rect.right - wnd_rect.left) / 4; status_size.cy = (wnd_rect.bottom - wnd_rect.top); // that won't look good status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.left += status_size.cx; break; case ALIGN_RIGHT: status_size.cx = (wnd_rect.right - wnd_rect.left) / 4; status_size.cy = (wnd_rect.bottom - wnd_rect.top); // that won't look good status_org.x = wnd_rect.right - status_size.cx; status_org.y = wnd_rect.top; wnd_rect.right -= status_size.cx; break; case ALIGN_TOP: status_size.cx = (wnd_rect.right - wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.top += status_size.cy; break; case ALIGN_BOTTOM: default: status_size.cx = (wnd_rect.right - wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.bottom - status_size.cy; wnd_rect.bottom -= status_size.cy; break; } switch (iflags.wc_align_message) { case ALIGN_LEFT: msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4; msg_size.cy = (wnd_rect.bottom - wnd_rect.top); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; wnd_rect.left += msg_size.cx; break; case ALIGN_RIGHT: msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4; msg_size.cy = (wnd_rect.bottom - wnd_rect.top); msg_org.x = wnd_rect.right - msg_size.cx; msg_org.y = wnd_rect.top; wnd_rect.right -= msg_size.cx; break; case ALIGN_TOP: msg_size.cx = (wnd_rect.right - wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; wnd_rect.top += msg_size.cy; break; case ALIGN_BOTTOM: default: msg_size.cx = (wnd_rect.right - wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.bottom - msg_size.cy; wnd_rect.bottom -= msg_size.cy; break; } /* map window */ map_org.x = wnd_rect.left; map_org.y = wnd_rect.top; map_size.cx = wnd_rect.right - wnd_rect.left; map_size.cy = wnd_rect.bottom - wnd_rect.top; GetNHApp()->rtStatusWindow.left = status_org.x; GetNHApp()->rtStatusWindow.top = status_org.y; GetNHApp()->rtStatusWindow.right = status_org.x + status_size.cx; GetNHApp()->rtStatusWindow.bottom = status_org.y + status_size.cy; GetNHApp()->rtTextWindow.left = map_org.x; GetNHApp()->rtTextWindow.top = map_org.y; GetNHApp()->rtTextWindow.right = map_org.x + (wnd_rect.right - wnd_rect.left); GetNHApp()->rtTextWindow.bottom = map_org.y + map_size.cy; GetNHApp()->rtMapWindow.left = map_org.x; GetNHApp()->rtMapWindow.top = map_org.y; GetNHApp()->rtMapWindow.right = map_org.x + map_size.cx; GetNHApp()->rtMapWindow.bottom = map_org.y + map_size.cy; GetNHApp()->rtMsgWindow.left = msg_org.x; GetNHApp()->rtMsgWindow.top = msg_org.y; GetNHApp()->rtMsgWindow.right = msg_org.x + msg_size.cx; GetNHApp()->rtMsgWindow.bottom = msg_org.y + msg_size.cy; /* map_width/4 < menu_width < map_width*2/3 */ GetNHApp()->rtMenuWindow.left = GetNHApp()->rtMapWindow.right - min(map_size.cx * 2 / 3, max(map_size.cx / 4, menu_size.cx)); GetNHApp()->rtMenuWindow.top = GetNHApp()->rtMapWindow.top; GetNHApp()->rtMenuWindow.right = GetNHApp()->rtMapWindow.right; GetNHApp()->rtMenuWindow.bottom = GetNHApp()->rtMapWindow.bottom; GetNHApp()->rtInvenWindow.left = GetNHApp()->rtMenuWindow.left; GetNHApp()->rtInvenWindow.top = GetNHApp()->rtMenuWindow.top; GetNHApp()->rtInvenWindow.right = GetNHApp()->rtMenuWindow.right; GetNHApp()->rtInvenWindow.bottom = GetNHApp()->rtMenuWindow.bottom; /* adjust map window size only if perm_invent is set */ if (flags.perm_invent) GetNHApp()->rtMapWindow.right = GetNHApp()->rtMenuWindow.left; } /* go through the windows list and adjust sizes */ for (i = 0; i < MAXWINDOWS; i++) { if (GetNHApp()->windowlist[i].win && !GetNHApp()->windowlist[i].dead) { RECT rt; /* kludge - inventory window should have its own type (same as menu-text as a matter of fact) */ if (flags.perm_invent && i == WIN_INVEN) mswin_get_window_placement(NHW_INVEN, &rt); else mswin_get_window_placement(GetNHApp()->windowlist[i].type, &rt); MoveWindow(GetNHApp()->windowlist[i].win, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, TRUE); } } if (IsWindow(changed_child)) SetForegroundWindow(changed_child); } LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PNHMainWindow data; UNREFERENCED_PARAMETER(lParam); data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: mswin_display_splash_window(TRUE); break; case IDM_EXIT: done2(); break; case IDM_SAVE: if (!program_state.gameover && !program_state.done_hup) dosave(); else MessageBeep(0); break; case IDM_MAP_TILES: case IDM_MAP_ASCII4X6: case IDM_MAP_ASCII6X8: case IDM_MAP_ASCII8X8: case IDM_MAP_ASCII16X8: case IDM_MAP_ASCII7X12: case IDM_MAP_ASCII8X12: case IDM_MAP_ASCII12X16: case IDM_MAP_ASCII16X12: case IDM_MAP_ASCII10X18: mswin_select_map_mode(menuid2mapmode(wmId)); break; case IDM_MAP_FIT_TO_SCREEN: if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? data->mapAcsiiModeSave : MAP_MODE_TILES); } else { mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode) ? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN); } break; case IDM_SETTING_SCREEN_TO_CLIPBOARD: { char *p; size_t len; HANDLE hglbCopy; char *p_copy; p = nh_compose_ascii_screenshot(); if (!p) return 0; len = strlen(p); if (!OpenClipboard(hWnd)) { NHMessageBox(hWnd, TEXT("Cannot open clipboard"), MB_OK | MB_ICONERROR); return 0; } EmptyClipboard(); hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(char)); if (hglbCopy == NULL) { CloseClipboard(); return FALSE; } p_copy = (char *) GlobalLock(hglbCopy); strncpy(p_copy, p, len); p_copy[len] = 0; // null character GlobalUnlock(hglbCopy); SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy); CloseClipboard(); free(p); } break; case IDM_SETTING_SCREEN_TO_FILE: { OPENFILENAME ofn; TCHAR filename[1024]; TCHAR whackdir[MAX_PATH]; FILE *pFile; char *text; wchar_t *wtext; int tlen = 0; ZeroMemory(filename, sizeof(filename)); ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.hInstance = GetNHApp()->hApp; ofn.lpstrFilter = TEXT("Text Files (*.txt)\x0*.txt\x0") TEXT("All Files (*.*)\x0*.*\x0") TEXT("\x0\x0"); ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 1; ofn.lpstrFile = filename; ofn.nMaxFile = SIZE(filename); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NH_A2W(hackdir, whackdir, MAX_PATH); ofn.lpstrTitle = NULL; ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = TEXT("txt"); ofn.lCustData = 0; ofn.lpfnHook = 0; ofn.lpTemplateName = 0; if (!GetSaveFileName(&ofn)) return FALSE; text = nh_compose_ascii_screenshot(); if (!text) return FALSE; pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8")); if (!pFile) { TCHAR buf[4096]; _stprintf(buf, TEXT("Cannot open %s for writing!"), filename); NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR); free(text); return FALSE; } tlen = strlen(text); wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t)); if (!wtext) panic("out of memory"); MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen); fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile); fclose(pFile); free(text); free(wtext); } break; case IDM_NHMODE: { GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1; mswin_menu_check_intf_mode(); break; } case IDM_CLEARSETTINGS: { mswin_destroy_reg(); /* Notify the user that windows settings will not be saved this time. */ NHMessageBox(GetNHApp()->hMainWnd, TEXT("Your Windows Settings will not be stored when you " "exit this time."), MB_OK | MB_ICONINFORMATION); break; } case IDM_SETTING_AUTOLAYOUT: GetNHApp()->bAutoLayout = !GetNHApp()->bAutoLayout; mswin_layout_main_window(NULL); /* Update menu item check-mark */ CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_AUTOLAYOUT, GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED); break; case IDM_SETTING_LOCKWINDOWS: nhlock_windows(!GetNHApp()->bWindowsLocked); break; case IDM_HELP_LONG: display_file(HELP, TRUE); break; case IDM_HELP_COMMANDS: display_file(SHELP, TRUE); break; case IDM_HELP_HISTORY: (void) dohistory(); break; case IDM_HELP_INFO_CHAR: (void) dowhatis(); break; case IDM_HELP_INFO_KEY: (void) dowhatdoes(); break; case IDM_HELP_OPTIONS: option_help(); break; case IDM_HELP_OPTIONS_LONG: display_file(OPTIONFILE, TRUE); break; case IDM_HELP_EXTCMD: (void) doextlist(); break; case IDM_HELP_LICENSE: display_file(LICENSE, TRUE); break; case IDM_HELP_PORTHELP: display_file(PORT_HELP, TRUE); break; default: return 1; } return 0; } // Mesage handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; RECT main_rt, dlg_rt; SIZE dlg_sz; UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: getversionstring(buf); SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, sizeof(wbuf))); SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT, NH_A2W(COPYRIGHT_BANNER_A "\n" COPYRIGHT_BANNER_B "\n" COPYRIGHT_BANNER_C "\n" COPYRIGHT_BANNER_D, wbuf, BUFSZ)); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hDlg, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow(hDlg, (main_rt.left + main_rt.right - dlg_sz.cx) / 2, (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx, dlg_sz.cy, TRUE); return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } void mswin_menu_check_intf_mode() { HMENU hMenu = GetMenu(GetNHApp()->hMainWnd); if (GetNHApp()->regNetHackMode) CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED); else CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED); } void mswin_select_map_mode(int mode) { PNHMainWindow data; winid map_id; map_id = WIN_MAP; data = (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd, GWLP_USERDATA); /* override for Rogue level */ if (Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode)) return; /* set map mode menu mark */ if (IS_MAP_ASCII(mode)) { CheckMenuRadioItem( GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18, mapmode2menuid(IS_MAP_FIT_TO_SCREEN(mode) ? data->mapAcsiiModeSave : mode), MF_BYCOMMAND); } else { CheckMenuRadioItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18, mapmode2menuid(MAP_MODE_TILES), MF_BYCOMMAND); } /* set fit-to-screen mode mark */ CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_FIT_TO_SCREEN, MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode) ? MF_CHECKED : MF_UNCHECKED)); if (IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { data->mapAcsiiModeSave = iflags.wc_map_mode; } iflags.wc_map_mode = mode; /* ** first, check if WIN_MAP has been inialized. ** If not - attempt to retrieve it by type, then check it again */ if (map_id == WIN_ERR) map_id = mswin_winid_from_type(NHW_MAP); if (map_id != WIN_ERR) mswin_map_mode(mswin_hwnd_from_winid(map_id), mode); } static struct t_menu2mapmode { int menuID; int mapMode; } _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES }, { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 }, { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 }, { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 }, { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 }, { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 }, { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 }, { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 }, { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 }, { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 }, { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN }, { -1, -1 } }; int menuid2mapmode(int menuid) { struct t_menu2mapmode *p; for (p = _menu2mapmode; p->mapMode != -1; p++) if (p->menuID == menuid) return p->mapMode; return -1; } int mapmode2menuid(int map_mode) { struct t_menu2mapmode *p; for (p = _menu2mapmode; p->mapMode != -1; p++) if (p->mapMode == map_mode) return p->menuID; return -1; } void nhlock_windows(BOOL lock) { int i; /* go through the windows list and adjust sizes */ for (i = 0; i < MAXWINDOWS; i++) { if (IsWindow(GetNHApp()->windowlist[i].win) && !GetNHApp()->windowlist[i].dead) { DWORD style; style = GetWindowLong(GetNHApp()->windowlist[i].win, GWL_STYLE); if (lock) style &= ~WS_CAPTION; else style |= WS_CAPTION; SetWindowLong(GetNHApp()->windowlist[i].win, GWL_STYLE, style); SetWindowPos(GetNHApp()->windowlist[i].win, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); } } /* update menu */ GetNHApp()->bWindowsLocked = lock; CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_LOCKWINDOWS, MF_BYCOMMAND | (lock ? MF_CHECKED : MF_UNCHECKED)); } // returns strdup() created pointer - callee assumes the ownership #define TEXT_BUFFER_SIZE 4096 char * nh_compose_ascii_screenshot() { char *retval; PMSNHMsgGetText text; retval = (char *) malloc(3 * TEXT_BUFFER_SIZE); text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); text->max_size = TEXT_BUFFER_SIZE - 1; /* make sure we always have 0 at the end of the buffer */ ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); strcpy(retval, text->buffer); ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); strcat(retval, text->buffer); ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); strcat(retval, text->buffer); free(text); return retval; } nethack-3.6.0/win/win32/mhmain.h0000664000076400007660000000103712536476415015334 0ustar paxedpaxed/* NetHack 3.6 mhmain.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMainWindow_h #define MSWINMainWindow_h /* this is a main appliation window */ #include "winMS.h" HWND mswin_init_main_window(void); void mswin_layout_main_window(HWND changed_child); void mswin_select_map_mode(int map_mode); void mswin_menu_check_intf_mode(void); #endif /* MSWINMainWindow_h */ nethack-3.6.0/win/win32/mhmap.c0000664000076400007660000010401012542155117015141 0ustar paxedpaxed/* NetHack 3.6 mhmap.c $NHDT-Date: 1435002695 2015/06/22 19:51:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.56 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhmap.h" #include "mhmsg.h" #include "mhinput.h" #include "mhfont.h" #include "patchlevel.h" #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 extern short glyph2tile[]; #define TILEBMP_X(ntile) ((ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X) #define TILEBMP_Y(ntile) ((ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y) /* map window data */ typedef struct mswin_nethack_map_window { int map[COLNO][ROWNO]; /* glyph map */ int bkmap[COLNO][ROWNO]; /* backround glyph map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */ int xPos, yPos; /* scroll position */ int xPageSize, yPageSize; /* scroll page size */ int xCur, yCur; /* position of the cursor */ int xScrTile, yScrTile; /* size of display tile */ POINT map_orig; /* map origin point */ HFONT hMapFont; /* font for ASCII mode */ } NHMapWindow, *PNHMapWindow; static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass"); LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM); static void register_map_window_class(void); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif HWND mswin_init_map_window() { static int run_once = 0; HWND ret; RECT rt; if (!run_once) { register_map_window_class(); run_once = 1; } /* get window position */ if (GetNHApp()->bAutoLayout) { SetRect(&rt, 0, 0, 0, 0); } else { mswin_get_window_placement(NHW_MAP, &rt); } /* create map window object */ ret = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS | WS_SIZEBOX, /* window style */ rt.left, /* horizontal position of window */ rt.top, /* vertical position of window */ rt.right - rt.left, /* window width */ rt.bottom - rt.top, /* window height */ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ if (!ret) { panic("Cannot create map window"); } /* Set window caption */ SetWindowText(ret, "Map"); return ret; } void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw) { PNHMapWindow data; RECT client_rt; SCROLLINFO si; SIZE wnd_size; LOGFONT lgfnt; /* check arguments */ if (!IsWindow(hWnd) || !lpsz || lpsz->cx <= 0 || lpsz->cy <= 0) return; /* calculate window size */ GetClientRect(hWnd, &client_rt); wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; /* set new screen tile size */ data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); data->xScrTile = max(1, (data->bFitToScreenMode ? wnd_size.cx : lpsz->cx) / COLNO); data->yScrTile = max(1, (data->bFitToScreenMode ? wnd_size.cy : lpsz->cy) / ROWNO); /* set map origin point */ data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile * COLNO) / 2); data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile * ROWNO) / 2); data->map_orig.x -= data->map_orig.x % data->xScrTile; data->map_orig.y -= data->map_orig.y % data->yScrTile; /* adjust horizontal scroll bar */ if (data->bFitToScreenMode) data->xPageSize = COLNO + 1; /* disable scroll bar */ else data->xPageSize = wnd_size.cx / data->xScrTile; if (data->xPageSize >= COLNO) { data->xPos = 0; GetNHApp()->bNoHScroll = TRUE; } else { GetNHApp()->bNoHScroll = FALSE; data->xPos = max( 0, min(COLNO - data->xPageSize + 1, u.ux - data->xPageSize / 2)); } si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = COLNO; si.nPage = data->xPageSize; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); /* adjust vertical scroll bar */ if (data->bFitToScreenMode) data->yPageSize = ROWNO + 1; /* disable scroll bar */ else data->yPageSize = wnd_size.cy / data->yScrTile; if (data->yPageSize >= ROWNO) { data->yPos = 0; GetNHApp()->bNoVScroll = TRUE; } else { GetNHApp()->bNoVScroll = FALSE; data->yPos = max( 0, min(ROWNO - data->yPageSize + 1, u.uy - data->yPageSize / 2)); } si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = ROWNO; si.nPage = data->yPageSize; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); /* create font */ if (data->hMapFont) DeleteObject(data->hMapFont); ZeroMemory(&lgfnt, sizeof(lgfnt)); lgfnt.lfHeight = -data->yScrTile; // height of font lgfnt.lfWidth = -data->xScrTile; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if (iflags.wc_font_map && *iflags.wc_font_map) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); } data->hMapFont = CreateFontIndirect(&lgfnt); mswin_cliparound(data->xCur, data->yCur); if (redraw) InvalidateRect(hWnd, NULL, TRUE); } /* set map mode */ int mswin_map_mode(HWND hWnd, int mode) { PNHMapWindow data; int oldMode; SIZE mapSize; data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (mode == data->mapMode) return mode; oldMode = data->mapMode; data->mapMode = mode; switch (data->mapMode) { case MAP_MODE_ASCII4x6: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 4 * COLNO; mapSize.cy = 6 * ROWNO; break; case MAP_MODE_ASCII6x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 6 * COLNO; mapSize.cy = 8 * ROWNO; break; case MAP_MODE_ASCII8x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8 * COLNO; mapSize.cy = 8 * ROWNO; break; case MAP_MODE_ASCII16x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16 * COLNO; mapSize.cy = 8 * ROWNO; break; case MAP_MODE_ASCII7x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 7 * COLNO; mapSize.cy = 12 * ROWNO; break; case MAP_MODE_ASCII8x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8 * COLNO; mapSize.cy = 12 * ROWNO; break; case MAP_MODE_ASCII16x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16 * COLNO; mapSize.cy = 12 * ROWNO; break; case MAP_MODE_ASCII12x16: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 12 * COLNO; mapSize.cy = 16 * ROWNO; break; case MAP_MODE_ASCII10x18: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 10 * COLNO; mapSize.cy = 18 * ROWNO; break; case MAP_MODE_ASCII_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = TRUE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = FALSE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES: default: data->bAsciiMode = FALSE; data->bFitToScreenMode = FALSE; mapSize.cx = GetNHApp()->mapTile_X * COLNO; mapSize.cy = GetNHApp()->mapTile_Y * ROWNO; break; } mswin_map_stretch(hWnd, &mapSize, TRUE); mswin_update_inventory(); /* for perm_invent to hide/show tiles */ return oldMode; } /* register window class for map window */ void register_map_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); /* window class */ wcex.style = CS_NOCLOSE | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC) MapWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */ wcex.lpszMenuName = NULL; wcex.lpszClassName = szNHMapWindowClass; if (!RegisterClass(&wcex)) { panic("cannot register Map window class"); } } /* map window procedure */ LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { case WM_CREATE: onCreate(hWnd, wParam, lParam); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: /* transfer focus back to the main window */ SetFocus(GetNHApp()->hMainWnd); break; case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_SIZE: { RECT rt; SIZE size; if (data->bFitToScreenMode) { size.cx = LOWORD(lParam); size.cy = HIWORD(lParam); } else { /* mapping factor is unchaged we just need to adjust scroll bars */ size.cx = data->xScrTile * COLNO; size.cy = data->yScrTile * ROWNO; } mswin_map_stretch(hWnd, &size, TRUE); /* update window placement */ GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_MAP, &rt); } break; case WM_MOVE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_MAP, &rt); } return FALSE; case WM_LBUTTONDOWN: NHEVENT_MS(CLICK_1, max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) / data->xScrTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) / data->yScrTile))); return 0; case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: NHEVENT_MS(CLICK_2, max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) / data->xScrTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) / data->yScrTile))); return 0; case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } /* on WM_COMMAND */ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; RECT rt; data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; if ((data->map[msg_data->x][msg_data->y] != msg_data->glyph) || (data->bkmap[msg_data->x][msg_data->y] != msg_data->bkglyph)) { data->map[msg_data->x][msg_data->y] = msg_data->glyph; data->bkmap[msg_data->x][msg_data->y] = msg_data->bkglyph; /* invalidate the update area. Erase backround if there is nothing to paint or we are in text mode */ nhcoord2display(data, msg_data->x, msg_data->y, &rt); InvalidateRect(hWnd, &rt, (((msg_data->glyph == NO_GLYPH) && (msg_data->bkglyph == NO_GLYPH)) || data->bAsciiMode || Is_rogue_level(&u.uz))); } } break; case MSNH_MSG_CLIPAROUND: { PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround) lParam; int x, y; BOOL scroll_x, scroll_y; int mcam = iflags.wc_scroll_margin; /* calculate if you should clip around */ scroll_x = !GetNHApp()->bNoHScroll && (msg_data->x < (data->xPos + mcam) || msg_data->x > (data->xPos + data->xPageSize - mcam)); scroll_y = !GetNHApp()->bNoVScroll && (msg_data->y < (data->yPos + mcam) || msg_data->y > (data->yPos + data->yPageSize - mcam)); mcam += iflags.wc_scroll_amount - 1; /* get page size and center horizontally on x-position */ if (scroll_x) { if (data->xPageSize <= 2 * mcam) { x = max(0, min(COLNO, msg_data->x - data->xPageSize / 2)); } else if (msg_data->x < data->xPos + data->xPageSize / 2) { x = max(0, min(COLNO, msg_data->x - mcam)); } else { x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam)); } SendMessage(hWnd, WM_HSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, x), (LPARAM) NULL); } /* get page size and center vertically on y-position */ if (scroll_y) { if (data->yPageSize <= 2 * mcam) { y = max(0, min(ROWNO, msg_data->y - data->yPageSize / 2)); } else if (msg_data->y < data->yPos + data->yPageSize / 2) { y = max(0, min(ROWNO, msg_data->y - mcam)); } else { y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam)); } SendMessage(hWnd, WM_VSCROLL, (WPARAM) MAKELONG(SB_THUMBTRACK, y), (LPARAM) NULL); } } break; case MSNH_MSG_CLEAR_WINDOW: { int i, j; for (i = 0; i < COLNO; i++) for (j = 0; j < ROWNO; j++) { data->map[i][j] = NO_GLYPH; data->bkmap[i][j] = NO_GLYPH; } InvalidateRect(hWnd, NULL, TRUE); } break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam; HDC hdc; RECT rt; /* move focus rectangle at the cursor postion */ hdc = GetDC(hWnd); nhcoord2display(data, data->xCur, data->yCur, &rt); if (data->bAsciiMode) { PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } data->xCur = msg_data->x; data->yCur = msg_data->y; nhcoord2display(data, data->xCur, data->yCur, &rt); if (data->bAsciiMode) { PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } ReleaseDC(hWnd, hdc); } break; case MSNH_MSG_GETTEXT: { PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; size_t index; int col, row; int color; unsigned special; int mgch; index = 0; for (row = 0; row < ROWNO; row++) { for (col = 0; col < COLNO; col++) { if (index >= msg_data->max_size) break; if (data->map[col][row] == NO_GLYPH) { mgch = ' '; } else { (void) mapglyph(data->map[col][row], &mgch, &color, &special, col, row); } msg_data->buffer[index] = mgch; index++; } if (index >= msg_data->max_size - 1) break; msg_data->buffer[index++] = '\r'; msg_data->buffer[index++] = '\n'; } } break; } /* end switch(wParam) */ } /* on WM_CREATE */ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; int i, j; UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); /* set window data */ data = (PNHMapWindow) malloc(sizeof(NHMapWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); for (i = 0; i < COLNO; i++) for (j = 0; j < ROWNO; j++) { data->map[i][j] = NO_GLYPH; data->bkmap[i][j] = NO_GLYPH; } data->bAsciiMode = FALSE; data->xScrTile = GetNHApp()->mapTile_X; data->yScrTile = GetNHApp()->mapTile_Y; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); } /* on WM_PAINT */ void onPaint(HWND hWnd) { PNHMapWindow data; PAINTSTRUCT ps; HDC hDC; HDC tileDC; HGDIOBJ saveBmp; RECT paint_rt; int i, j; /* get window data */ data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); hDC = BeginPaint(hWnd, &ps); /* calculate paint rectangle */ if (!IsRectEmpty(&ps.rcPaint)) { /* calculate paint rectangle */ paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x) / data->xScrTile, 0); paint_rt.top = max( data->yPos + (ps.rcPaint.top - data->map_orig.y) / data->yScrTile, 0); paint_rt.right = min( data->xPos + (ps.rcPaint.right - data->map_orig.x) / data->xScrTile + 1, COLNO); paint_rt.bottom = min( data->yPos + (ps.rcPaint.bottom - data->map_orig.y) / data->yScrTile + 1, ROWNO); if (data->bAsciiMode || Is_rogue_level(&u.uz)) { /* You enter a VERY primitive world! */ HGDIOBJ oldFont; oldFont = SelectObject(hDC, data->hMapFont); SetBkMode(hDC, TRANSPARENT); /* draw the map */ for (i = paint_rt.left; i < paint_rt.right; i++) for (j = paint_rt.top; j < paint_rt.bottom; j++) if (data->map[i][j] >= 0) { char ch; TCHAR wch; RECT glyph_rect; int color; unsigned special; int mgch; HBRUSH back_brush; COLORREF OldFg; nhcoord2display(data, i, j, &glyph_rect); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) nhglyph2charcolor(data->map[i][j], &ch, &color); OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); #else /* rely on NetHack core helper routine */ (void) mapglyph(data->map[i][j], &mgch, &color, &special, i, j); ch = (char) mgch; if (((special & MG_PET) && iflags.hilite_pet) || ((special & MG_DETECT) && iflags.use_inverse)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); FillRect(hDC, &glyph_rect, back_brush); DeleteObject(back_brush); switch (color) { case CLR_GRAY: case CLR_WHITE: OldFg = SetTextColor( hDC, nhcolor_to_RGB(CLR_BLACK)); break; default: OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); } } else { OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); } #endif DrawText(hDC, NH_A2W(&ch, &wch, 1), 1, &glyph_rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX); SetTextColor(hDC, OldFg); } SelectObject(hDC, oldFont); } else { short ntile; int t_x, t_y; int glyph, bkglyph; RECT glyph_rect; int layer; #ifdef USE_PILEMARK int color; unsigned special; int mgch; #endif /* prepare tiles DC for mapping */ tileDC = CreateCompatibleDC(hDC); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); /* draw the map */ for (i = paint_rt.left; i < paint_rt.right; i++) for (j = paint_rt.top; j < paint_rt.bottom; j++) { layer = 0; glyph = data->map[i][j]; bkglyph = data->bkmap[i][j]; if (bkglyph != NO_GLYPH) { ntile = glyph2tile[bkglyph]; t_x = TILEBMP_X(ntile); t_y = TILEBMP_Y(ntile); nhcoord2display(data, i, j, &glyph_rect); StretchBlt(hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); layer ++; } if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { ntile = glyph2tile[glyph]; t_x = TILEBMP_X(ntile); t_y = TILEBMP_Y(ntile); nhcoord2display(data, i, j, &glyph_rect); if (layer > 0) { (*GetNHApp()->lpfnTransparentBlt)( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, TILE_BK_COLOR); } else { StretchBlt(hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); } layer ++; } #ifdef USE_PILEMARK /* rely on NetHack core helper routine */ (void) mapglyph(data->map[i][j], &mgch, &color, &special, i, j); if ((glyph != NO_GLYPH) && (special & MG_PET) #else if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) #endif && iflags.wc_hilite_pet) { /* apply pet mark transparently over pet image */ HDC hdcPetMark; HBITMAP bmPetMarkOld; /* this is DC for petmark bitmap */ hdcPetMark = CreateCompatibleDC(hDC); bmPetMarkOld = SelectObject( hdcPetMark, GetNHApp()->bmpPetMark); (*GetNHApp()->lpfnTransparentBlt)( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, hdcPetMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR); SelectObject(hdcPetMark, bmPetMarkOld); DeleteDC(hdcPetMark); } #ifdef USE_PILEMARK if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) && iflags.hilite_pile) { /* apply pilemark transparently over other image */ HDC hdcPileMark; HBITMAP bmPileMarkOld; /* this is DC for pilemark bitmap */ hdcPileMark = CreateCompatibleDC(hDC); bmPileMarkOld = SelectObject( hdcPileMark, GetNHApp()->bmpPileMark); (*GetNHApp()->lpfnTransparentBlt)( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, hdcPileMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR); SelectObject(hdcPileMark, bmPileMarkOld); DeleteDC(hdcPileMark); } #endif } SelectObject(tileDC, saveBmp); DeleteDC(tileDC); } /* draw focus rect */ nhcoord2display(data, data->xCur, data->yCur, &paint_rt); if (data->bAsciiMode) { PatBlt(hDC, paint_rt.left, paint_rt.top, paint_rt.right - paint_rt.left, paint_rt.bottom - paint_rt.top, DSTINVERT); } else { DrawFocusRect(hDC, &paint_rt); } } EndPaint(hWnd, &ps); } /* on WM_VSCROLL */ void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int yNewPos; int yDelta; UNREFERENCED_PARAMETER(lParam); /* get window data */ data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (LOWORD(wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: yNewPos = data->yPos - data->yPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: yNewPos = data->yPos + data->yPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: yNewPos = data->yPos - 1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: yNewPos = data->yPos + 1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: yNewPos = HIWORD(wParam); break; default: yNewPos = data->yPos; } yNewPos = max(0, min(ROWNO - data->yPageSize + 1, yNewPos)); if (yNewPos == data->yPos) return; yDelta = yNewPos - data->yPos; data->yPos = yNewPos; ScrollWindowEx(hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } /* on WM_HSCROLL */ void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int xNewPos; int xDelta; UNREFERENCED_PARAMETER(lParam); /* get window data */ data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (LOWORD(wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: xNewPos = data->xPos - data->xPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: xNewPos = data->xPos + data->xPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: xNewPos = data->xPos - 1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: xNewPos = data->xPos + 1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: xNewPos = HIWORD(wParam); break; default: xNewPos = data->xPos; } xNewPos = max(0, min(COLNO - data->xPageSize + 1, xNewPos)); if (xNewPos == data->xPos) return; xDelta = xNewPos - data->xPos; data->xPos = xNewPos; ScrollWindowEx(hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } /* map nethack map coordinates to the screen location */ void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut) { lpOut->left = (x - data->xPos) * data->xScrTile + data->map_orig.x; lpOut->top = (y - data->yPos) * data->yScrTile + data->map_orig.y; lpOut->right = lpOut->left + data->xScrTile; lpOut->bottom = lpOut->top + data->yScrTile; } #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) /* map glyph to character/color combination */ void nhglyph2charcolor(short g, uchar *ch, int *color) { int offset; #ifdef TEXTCOLOR #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR #define obj_color(n) \ *color = iflags.use_color ? objects[n].oc_color : NO_COLOR #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define warn_color(n) \ *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR #else /* no text color */ #define zap_color(n) #define cmap_color(n) #define obj_color(n) #define mon_color(n) #define pet_color(c) #define warn_color(c) *color = CLR_WHITE; #endif if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */ *ch = showsyms[offset + SYM_OFF_W]; warn_color(offset); } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ /* see swallow_to_glyph() in display.c */ *ch = (uchar) showsyms[(S_sw_tl + (offset & 0x7)) + SYM_OFF_P]; mon_color(offset >> 3); } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ /* see zapdir_to_glyph() in display.c */ *ch = showsyms[(S_vbeam + (offset & 0x3)) + SYM_OFF_P]; zap_color((offset >> 2)); } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ *ch = showsyms[offset + SYM_OFF_P]; cmap_color(offset); } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */ *ch = showsyms[(int) objects[offset].oc_class + SYM_OFF_O]; obj_color(offset); } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ *ch = showsyms[(int) objects[CORPSE].oc_class + SYM_OFF_O]; mon_color(offset); } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */ *ch = showsyms[(int) mons[offset].mlet + SYM_OFF_M]; pet_color(offset); } else { /* a monster */ *ch = showsyms[(int) mons[g].mlet + SYM_OFF_M]; mon_color(g); } // end of wintty code } #endif /* map nethack color to RGB */ COLORREF nhcolor_to_RGB(int c) { switch (c) { case CLR_BLACK: return RGB(0x55, 0x55, 0x55); case CLR_RED: return RGB(0xFF, 0x00, 0x00); case CLR_GREEN: return RGB(0x00, 0x80, 0x00); case CLR_BROWN: return RGB(0xA5, 0x2A, 0x2A); case CLR_BLUE: return RGB(0x00, 0x00, 0xFF); case CLR_MAGENTA: return RGB(0xFF, 0x00, 0xFF); case CLR_CYAN: return RGB(0x00, 0xFF, 0xFF); case CLR_GRAY: return RGB(0xC0, 0xC0, 0xC0); case NO_COLOR: return RGB(0xFF, 0xFF, 0xFF); case CLR_ORANGE: return RGB(0xFF, 0xA5, 0x00); case CLR_BRIGHT_GREEN: return RGB(0x00, 0xFF, 0x00); case CLR_YELLOW: return RGB(0xFF, 0xFF, 0x00); case CLR_BRIGHT_BLUE: return RGB(0x00, 0xC0, 0xFF); case CLR_BRIGHT_MAGENTA: return RGB(0xFF, 0x80, 0xFF); case CLR_BRIGHT_CYAN: return RGB(0x80, 0xFF, 0xFF); /* something close to aquamarine */ case CLR_WHITE: return RGB(0xFF, 0xFF, 0xFF); default: return RGB(0x00, 0x00, 0x00); /* black */ } } nethack-3.6.0/win/win32/mhmap.h0000664000076400007660000000121712536476415015165 0ustar paxedpaxed/* NetHack 3.6 mhmap.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMapWindow_h #define MSWINMapWindow_h #include "winMS.h" #include "config.h" #include "global.h" COLORREF nhcolor_to_RGB(int c); HWND mswin_init_map_window(void); void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 #endif /* MSWINMapWindow_h */ nethack-3.6.0/win/win32/mhmenu.c0000664000076400007660000016072312541713002015335 0ustar paxedpaxed/* NetHack 3.6 mhmenu.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.48 $ */ /* Copyright (c) Alex Kompel, 2002 */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "resource.h" #include "mhmenu.h" #include "mhmain.h" #include "mhmsg.h" #include "mhfont.h" #include "mhdlg.h" #define MENU_MARGIN 0 #define NHMENU_STR_SIZE BUFSZ #define MIN_TABSTOP_SIZE 0 #define NUMTABS 15 #define TAB_SEPARATION 10 /* pixels between each tab stop */ #define DEFAULT_COLOR_BG_TEXT COLOR_WINDOW #define DEFAULT_COLOR_FG_TEXT COLOR_WINDOWTEXT #define DEFAULT_COLOR_BG_MENU COLOR_WINDOW #define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT typedef struct mswin_menu_item { int glyph; ANY_P identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; char str[NHMENU_STR_SIZE]; BOOLEAN_P presel; int count; BOOL has_focus; } NHMenuItem, *PNHMenuItem; typedef struct mswin_nethack_menu_window { int type; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */ int how; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */ union { struct menu_list { int size; /* number of items in items[] */ int allocated; /* number of allocated slots in items[] */ PNHMenuItem items; /* menu items */ char gacc[QBUFSZ]; /* group accelerators */ BOOL counting; /* counting flag */ char prompt[QBUFSZ]; /* menu prompt */ int tab_stop_size[NUMTABS]; /* tabstops to align option values */ int menu_cx; /* menu width */ } menu; struct menu_text { TCHAR *text; SIZE text_box_size; } text; }; int result; int done; HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; BOOL is_active; } NHMenuWindow, *PNHMenuWindow; extern short glyph2tile[]; static WNDPROC wndProcListViewOrig = NULL; static WNDPROC editControlWndProc = NULL; #define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj != NULL) #define NHMENU_IS_SELECTED(item) ((item).count != 0) #define NHMENU_HAS_GLYPH(item) ((item).glyph != NO_GLYPH) INT_PTR CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutMenu(HWND hwnd); static void SetMenuType(HWND hwnd, int type); static void SetMenuListType(HWND hwnd, int now); static HWND GetMenuControl(HWND hwnd); static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count); static void reset_menu_count(HWND hwndList, PNHMenuWindow data); static BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch); /*-----------------------------------------------------------------------------*/ HWND mswin_init_menu_window(int type) { HWND ret; RECT rt; /* get window position */ if (GetNHApp()->bAutoLayout) { SetRect(&rt, 0, 0, 0, 0); } else { mswin_get_window_placement(NHW_MENU, &rt); } /* create menu window object */ ret = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_MENU), GetNHApp()->hMainWnd, MenuWndProc); if (!ret) { panic("Cannot create menu window"); } /* move it in the predefined position */ if (!GetNHApp()->bAutoLayout) { MoveWindow(ret, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, TRUE); } /* Set window caption */ SetWindowText(ret, "Menu/Text"); if (!GetNHApp()->bWindowsLocked) { DWORD style; style = GetWindowLong(ret, GWL_STYLE); style |= WS_CAPTION; SetWindowLong(ret, GWL_STYLE, style); SetWindowPos(ret, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); } SetMenuType(ret, type); return ret; } /*-----------------------------------------------------------------------------*/ int mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, BOOL activate) { PNHMenuWindow data; int ret_val; MENU_ITEM_P *selected = NULL; int i; char *ap; assert(_selected != NULL); *_selected = NULL; ret_val = -1; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* force activate for certain menu types */ if (data->type == MENU_TYPE_MENU && (how == PICK_ONE || how == PICK_ANY)) { activate = TRUE; } data->is_active = activate; /* set menu type */ SetMenuListType(hWnd, how); /* Ok, now give items a unique accelerators */ if (data->type == MENU_TYPE_MENU) { char next_char = 'a'; data->menu.gacc[0] = '\0'; ap = data->menu.gacc; for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].accelerator != 0) { next_char = (char) (data->menu.items[i].accelerator + 1); } else if (NHMENU_IS_SELECTABLE(data->menu.items[i])) { if ((next_char >= 'a' && next_char <= 'z') || (next_char >= 'A' && next_char <= 'Z')) { data->menu.items[i].accelerator = next_char; } else { if (next_char > 'z') next_char = 'A'; else if (next_char > 'Z') break; data->menu.items[i].accelerator = next_char; } next_char++; } } /* collect group accelerators */ for (i = 0; i < data->menu.size; i++) { if (data->how != PICK_NONE) { if (data->menu.items[i].group_accel && !strchr(data->menu.gacc, data->menu.items[i].group_accel)) { *ap++ = data->menu.items[i].group_accel; *ap = '\x0'; } } } reset_menu_count(NULL, data); } LayoutMenu(hWnd); // show dialog buttons if (activate) { mswin_popup_display(hWnd, &data->done); } else { SetFocus(GetNHApp()->hMainWnd); mswin_layout_main_window(hWnd); } /* get the result */ if (data->result != -1) { if (how == PICK_NONE) { if (data->result >= 0) ret_val = 0; else ret_val = -1; } else if (how == PICK_ONE || how == PICK_ANY) { /* count selected items */ ret_val = 0; for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i])) { ret_val++; } } if (ret_val > 0) { int sel_ind; selected = (MENU_ITEM_P *) malloc(ret_val * sizeof(MENU_ITEM_P)); if (!selected) panic("out of memory"); sel_ind = 0; for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i])) { selected[sel_ind].item = data->menu.items[i].identifier; selected[sel_ind].count = data->menu.items[i].count; sel_ind++; } } ret_val = sel_ind; *_selected = selected; } } } if (activate) { data->is_active = FALSE; LayoutMenu(hWnd); // hide dialog buttons mswin_popup_destroy(hWnd); } return ret_val; } /*-----------------------------------------------------------------------------*/ INT_PTR CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; HWND control; HDC hdc; TCHAR title[MAX_LOADSTRING]; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { case WM_INITDIALOG: data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; data->how = PICK_NONE; data->result = 0; data->done = 0; data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL)); data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); data->is_active = FALSE; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* set font for the text cotrol */ control = GetDlgItem(hWnd, IDC_MENU_TEXT); hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM) 0); ReleaseDC(control, hdc); /* subclass edit control */ editControlWndProc = (WNDPROC) GetWindowLongPtr(control, GWLP_WNDPROC); SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) NHMenuTextWndProc); /* Even though the dialog has no caption, you can still set the title which shows on Alt-Tab */ LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING); SetWindowText(hWnd, title); /* set focus to text control for now */ SetFocus(control); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: { RECT rt; LayoutMenu(hWnd); GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) mswin_update_window_placement(NHW_INVEN, &rt); else mswin_update_window_placement(NHW_MENU, &rt); } return FALSE; case WM_MOVE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) mswin_update_window_placement(NHW_INVEN, &rt); else mswin_update_window_placement(NHW_MENU, &rt); } return FALSE; case WM_CLOSE: if (program_state.gameover) { data->result = -1; data->done = 1; program_state.stopprint++; return TRUE; } else return FALSE; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: if (data->type == MENU_TYPE_MENU && (data->how == PICK_ONE || data->how == PICK_ANY) && data->menu.counting) { HWND list; int i; /* reset counter if counting is in progress */ list = GetMenuControl(hWnd); i = ListView_GetNextItem(list, -1, LVNI_FOCUSED); if (i >= 0) { SelectMenuItem(list, data, i, 0); } return TRUE; } else { data->result = -1; data->done = 1; } return TRUE; case IDOK: data->done = 1; data->result = 0; return TRUE; } } break; case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR) lParam; switch (LOWORD(wParam)) { case IDC_MENU_LIST: { if (!data || data->type != MENU_TYPE_MENU) break; switch (lpnmhdr->code) { case LVN_ITEMACTIVATE: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if (data->how == PICK_ONE) { if (lpnmlv->iItem >= 0 && lpnmlv->iItem < data->menu.size && NHMENU_IS_SELECTABLE( data->menu.items[lpnmlv->iItem])) { SelectMenuItem(lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1); data->done = 1; data->result = 0; return TRUE; } } } break; case NM_CLICK: { LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW) lParam; if (lpnmitem->iItem == -1) return 0; if (data->how == PICK_ANY) { SelectMenuItem( lpnmitem->hdr.hwndFrom, data, lpnmitem->iItem, NHMENU_IS_SELECTED(data->menu.items[lpnmitem->iItem]) ? 0 : -1); } } break; case LVN_ITEMCHANGED: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if (lpnmlv->iItem == -1) return 0; if (!(lpnmlv->uChanged & LVIF_STATE)) return 0; if (data->how == PICK_ONE || data->how == PICK_ANY) { data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); } /* update count for single-selection menu (follow the listview * selection) */ if (data->how == PICK_ONE) { if (lpnmlv->uNewState & LVIS_SELECTED) { SelectMenuItem(lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1); } } /* check item focus */ if (data->how == PICK_ONE || data->how == PICK_ANY) { data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); } } break; case NM_KILLFOCUS: reset_menu_count(lpnmhdr->hwndFrom, data); break; } } break; } } break; case WM_SETFOCUS: if (hWnd != GetNHApp()->hPopupWnd) { SetFocus(GetNHApp()->hMainWnd); } else { if (IsWindow(GetMenuControl(hWnd))) SetFocus(GetMenuControl(hWnd)); } return FALSE; case WM_MEASUREITEM: if (wParam == IDC_MENU_LIST) return onMeasureItem(hWnd, wParam, lParam); else return FALSE; case WM_DRAWITEM: if (wParam == IDC_MENU_LIST) return onDrawItem(hWnd, wParam, lParam); else return FALSE; case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if (hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT)) { SetBkColor(hdcEdit, text_bg_brush ? text_bg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_BG_TEXT)); SetTextColor(hdcEdit, text_fg_brush ? text_fg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_FG_TEXT)); return (INT_PTR)(text_bg_brush ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT)); } } return FALSE; case WM_DESTROY: if (data) { DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); if (data->type == MENU_TYPE_TEXT) { if (data->text.text) free(data->text.text); } free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); } return TRUE; } return FALSE; } /*-----------------------------------------------------------------------------*/ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; HWND text_view; TCHAR wbuf[BUFSZ]; size_t text_size; RECT text_rt; HGDIOBJ saveFont; HDC hdc; if (data->type != MENU_TYPE_TEXT) SetMenuType(hWnd, MENU_TYPE_TEXT); if (!data->text.text) { text_size = strlen(msg_data->text) + 4; data->text.text = (TCHAR *) malloc(text_size * sizeof(data->text.text[0])); ZeroMemory(data->text.text, text_size * sizeof(data->text.text[0])); } else { text_size = _tcslen(data->text.text) + strlen(msg_data->text) + 4; data->text.text = (TCHAR *) realloc( data->text.text, text_size * sizeof(data->text.text[0])); } if (!data->text.text) break; _tcscat(data->text.text, NH_A2W(msg_data->text, wbuf, BUFSZ)); _tcscat(data->text.text, TEXT("\r\n")); text_view = GetDlgItem(hWnd, IDC_MENU_TEXT); if (!text_view) panic("cannot get text view window"); SetWindowText(text_view, data->text.text); /* calculate dimensions of the added line of text */ hdc = GetDC(text_view); saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE)); SetRect(&text_rt, 0, 0, 0, 0); DrawText(hdc, msg_data->text, strlen(msg_data->text), &text_rt, DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE); data->text.text_box_size.cx = max(text_rt.right - text_rt.left, data->text.text_box_size.cx); data->text.text_box_size.cy += text_rt.bottom - text_rt.top; SelectObject(hdc, saveFont); ReleaseDC(text_view, hdc); } break; case MSNH_MSG_STARTMENU: { int i; if (data->type != MENU_TYPE_MENU) SetMenuType(hWnd, MENU_TYPE_MENU); if (data->menu.items) free(data->menu.items); data->how = PICK_NONE; data->menu.items = NULL; data->menu.size = 0; data->menu.allocated = 0; data->done = 0; data->result = 0; for (i = 0; i < NUMTABS; ++i) data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE; } break; case MSNH_MSG_ADDMENU: { PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu) lParam; char *p, *p1; int new_item; HDC hDC; int column; HFONT saveFont; LONG menuitemwidth = 0; TEXTMETRIC tm; if (data->type != MENU_TYPE_MENU) break; if (strlen(msg_data->str) == 0) break; if (data->menu.size == data->menu.allocated) { data->menu.allocated += 10; data->menu.items = (PNHMenuItem) realloc( data->menu.items, data->menu.allocated * sizeof(NHMenuItem)); } new_item = data->menu.size; ZeroMemory(&data->menu.items[new_item], sizeof(data->menu.items[new_item])); data->menu.items[new_item].glyph = msg_data->glyph; data->menu.items[new_item].identifier = *msg_data->identifier; data->menu.items[new_item].accelerator = msg_data->accelerator; data->menu.items[new_item].group_accel = msg_data->group_accel; data->menu.items[new_item].attr = msg_data->attr; strncpy(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE); data->menu.items[new_item].presel = msg_data->presel; /* calculate tabstop size */ hDC = GetDC(hWnd); saveFont = SelectObject( hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE)); GetTextMetrics(hDC, &tm); p1 = data->menu.items[new_item].str; p = strchr(data->menu.items[new_item].str, '\t'); column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT drawRect; SetRect(&drawRect, 0, 0, 1, 1); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE); data->menu.tab_stop_size[column] = max(data->menu.tab_stop_size[column], drawRect.right - drawRect.left); menuitemwidth += data->menu.tab_stop_size[column]; if (p != NULL) *p = '\t'; else /* last string so, */ break; /* add the separation only when not the last item */ /* in the last item, we break out of the loop, in the statement * just above */ menuitemwidth += TAB_SEPARATION; ++column; p1 = p + 1; p = strchr(p1, '\t'); } SelectObject(hDC, saveFont); ReleaseDC(hWnd, hDC); /* calculate new menu width */ data->menu.menu_cx = max(data->menu.menu_cx, 2 * TILE_X + menuitemwidth + (tm.tmAveCharWidth + tm.tmOverhang) * 12); /* increment size */ data->menu.size++; } break; case MSNH_MSG_ENDMENU: { PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu) lParam; if (msg_data->text) { strncpy(data->menu.prompt, msg_data->text, sizeof(data->menu.prompt) - 1); } else { ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt)); } } break; } } /*-----------------------------------------------------------------------------*/ void LayoutMenu(HWND hWnd) { PNHMenuWindow data; HWND menu_ok; HWND menu_cancel; RECT clrt, rt; POINT pt_elem, pt_ok, pt_cancel; SIZE sz_elem, sz_ok, sz_cancel; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); menu_ok = GetDlgItem(hWnd, IDOK); menu_cancel = GetDlgItem(hWnd, IDCANCEL); /* get window coordinates */ GetClientRect(hWnd, &clrt); // OK button if (data->is_active) { GetWindowRect(menu_ok, &rt); if (data->type == MENU_TYPE_TEXT || (data->type == MENU_TYPE_MENU && data->how == PICK_NONE)) { sz_ok.cx = (clrt.right - clrt.left) - 2 * MENU_MARGIN; } else { sz_ok.cx = (clrt.right - clrt.left) / 2 - 2 * MENU_MARGIN; } sz_ok.cy = rt.bottom - rt.top; pt_ok.x = clrt.left + MENU_MARGIN; pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy; ShowWindow(menu_ok, SW_SHOW); MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE); } else { sz_ok.cx = sz_ok.cy = 0; pt_ok.x = pt_ok.y = 0; ShowWindow(menu_ok, SW_HIDE); } // CANCEL button if (data->is_active && !(data->type == MENU_TYPE_TEXT || (data->type == MENU_TYPE_MENU && data->how == PICK_NONE))) { GetWindowRect(menu_ok, &rt); sz_cancel.cx = (clrt.right - clrt.left) / 2 - 2 * MENU_MARGIN; pt_cancel.x = (clrt.left + clrt.right) / 2 + MENU_MARGIN; sz_cancel.cy = rt.bottom - rt.top; pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy; ShowWindow(menu_cancel, SW_SHOW); MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE); } else { sz_cancel.cx = sz_cancel.cy = 0; pt_cancel.x = pt_cancel.y = 0; ShowWindow(menu_cancel, SW_HIDE); } // main menu control pt_elem.x = clrt.left + MENU_MARGIN; pt_elem.y = clrt.top + MENU_MARGIN; sz_elem.cx = (clrt.right - clrt.left) - 2 * MENU_MARGIN; if (data->is_active) { sz_elem.cy = (clrt.bottom - clrt.top) - max(sz_ok.cy, sz_cancel.cy) - 3 * MENU_MARGIN; } else { sz_elem.cy = (clrt.bottom - clrt.top) - 2 * MENU_MARGIN; } if (data->type == MENU_TYPE_MENU) { ListView_SetColumnWidth( GetMenuControl(hWnd), 0, max(clrt.right - clrt.left - GetSystemMetrics(SM_CXVSCROLL), data->menu.menu_cx)); } MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE); } /*-----------------------------------------------------------------------------*/ void SetMenuType(HWND hWnd, int type) { PNHMenuWindow data; HWND list, text; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); data->type = type; text = GetDlgItem(hWnd, IDC_MENU_TEXT); list = GetDlgItem(hWnd, IDC_MENU_LIST); if (data->type == MENU_TYPE_TEXT) { ShowWindow(list, SW_HIDE); EnableWindow(list, FALSE); EnableWindow(text, TRUE); ShowWindow(text, SW_SHOW); if (data->is_active) SetFocus(text); } else { ShowWindow(text, SW_HIDE); EnableWindow(text, FALSE); EnableWindow(list, TRUE); ShowWindow(list, SW_SHOW); if (data->is_active) SetFocus(list); } LayoutMenu(hWnd); } /*-----------------------------------------------------------------------------*/ void SetMenuListType(HWND hWnd, int how) { PNHMenuWindow data; RECT rt; DWORD dwStyles; char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; int nItem; int i; HWND control; LVCOLUMN lvcol; LRESULT fnt; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data->type != MENU_TYPE_MENU) return; data->how = how; switch (how) { case PICK_NONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ANY: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY"); }; if (strlen(data->menu.prompt) == 0) { dwStyles |= LVS_NOCOLUMNHEADER; } GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt); DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST)); control = CreateWindow(WC_LISTVIEW, NULL, dwStyles, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hWnd, (HMENU) IDC_MENU_LIST, GetNHApp()->hApp, NULL); if (!control) panic("cannot create menu control"); /* install the hook for the control window procedure */ wndProcListViewOrig = (WNDPROC) GetWindowLongPtr(control, GWLP_WNDPROC); SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) NHMenuListWndProc); /* set control colors */ ListView_SetBkColor(control, menu_bg_brush ? menu_bg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_BG_MENU)); ListView_SetTextBkColor( control, menu_bg_brush ? menu_bg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_BG_MENU)); ListView_SetTextColor( control, menu_fg_brush ? menu_fg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_FG_MENU)); /* set control font */ fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM) 0, (LPARAM) 0); SendMessage(control, WM_SETFONT, (WPARAM) fnt, (LPARAM) 0); /* add column to the list view */ ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN); lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); /* add items to the list view */ for (i = 0; i < data->menu.size; i++) { LVITEM lvitem; ZeroMemory(&lvitem, sizeof(lvitem)); sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str); lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; lvitem.iItem = i; lvitem.iSubItem = 0; lvitem.state = data->menu.items[i].presel ? LVIS_SELECTED : 0; lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ); lvitem.lParam = (LPARAM) &data->menu.items[i]; nItem = (int) SendMessage(control, LB_ADDSTRING, (WPARAM) 0, (LPARAM) buf); if (ListView_InsertItem(control, &lvitem) == -1) { panic("cannot insert menu item"); } } if (data->is_active) SetFocus(control); } /*-----------------------------------------------------------------------------*/ HWND GetMenuControl(HWND hWnd) { PNHMenuWindow data; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data->type == MENU_TYPE_TEXT) { return GetDlgItem(hWnd, IDC_MENU_TEXT); } else { return GetDlgItem(hWnd, IDC_MENU_LIST); } } /*-----------------------------------------------------------------------------*/ BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMEASUREITEMSTRUCT lpmis; TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; RECT list_rect; int i; UNREFERENCED_PARAMETER(wParam); lpmis = (LPMEASUREITEMSTRUCT) lParam; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); GetClientRect(GetMenuControl(hWnd), &list_rect); hdc = GetDC(GetMenuControl(hWnd)); saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE)); GetTextMetrics(hdc, &tm); /* Set the height of the list box items to max height of the individual * items */ for (i = 0; i < data->menu.size; i++) { if (NHMENU_HAS_GLYPH(data->menu.items[i]) && !IS_MAP_ASCII(iflags.wc_map_mode)) { lpmis->itemHeight = max(lpmis->itemHeight, (UINT) max(tm.tmHeight, GetNHApp()->mapTile_Y) + 2); } else { lpmis->itemHeight = max(lpmis->itemHeight, (UINT) max(tm.tmHeight, TILE_Y) + 2); } } /* set width to the window width */ lpmis->itemWidth = list_rect.right - list_rect.left; SelectObject(hdc, saveFont); ReleaseDC(GetMenuControl(hWnd), hdc); return TRUE; } /*-----------------------------------------------------------------------------*/ BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPDRAWITEMSTRUCT lpdis; PNHMenuItem item; PNHMenuWindow data; TEXTMETRIC tm; HGDIOBJ saveFont; HDC tileDC; short ntile; int t_x, t_y; int x, y; TCHAR wbuf[BUFSZ]; RECT drawRect; COLORREF OldBg, OldFg, NewBg; char *p, *p1; int column; int spacing = 0; int color = NO_COLOR, attr; boolean menucolr = FALSE; UNREFERENCED_PARAMETER(wParam); lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ if (lpdis->itemID == -1) return FALSE; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); item = &data->menu.items[lpdis->itemID]; tileDC = CreateCompatibleDC(lpdis->hDC); saveFont = SelectObject( lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE)); NewBg = menu_bg_brush ? menu_bg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MENU); OldBg = SetBkColor(lpdis->hDC, NewBg); OldFg = SetTextColor(lpdis->hDC, menu_fg_brush ? menu_fg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MENU)); GetTextMetrics(lpdis->hDC, &tm); spacing = tm.tmAveCharWidth; /* set initial offset */ x = lpdis->rcItem.left + 1; /* print check mark and letter */ if (NHMENU_IS_SELECTABLE(*item)) { char buf[2]; if (data->how != PICK_NONE) { HGDIOBJ saveBrush; HBRUSH hbrCheckMark; switch (item->count) { case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break; case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break; default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break; } y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; SetBrushOrgEx(lpdis->hDC, x, y, NULL); saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY); SelectObject(lpdis->hDC, saveBrush); DeleteObject(hbrCheckMark); } x += TILE_X + spacing; if (item->accelerator != 0) { buf[0] = item->accelerator; buf[1] = '\x0'; if (iflags.use_menu_color && (menucolr = get_menu_coloring(item->str, &color, &attr))) { /* TODO: use attr too */ if (color != NO_COLOR) SetTextColor(lpdis->hDC, nhcolor_to_RGB(color)); } SetRect(&drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } x += tm.tmAveCharWidth + tm.tmOverhang + spacing; } else { x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 2 * spacing; } /* print glyph if present */ if (NHMENU_HAS_GLYPH(*item)) { if (!IS_MAP_ASCII(iflags.wc_map_mode)) { HGDIOBJ saveBmp; saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); ntile = glyph2tile[item->glyph]; t_x = (ntile % GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_X; t_y = (ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y; y = (lpdis->rcItem.bottom + lpdis->rcItem.top - GetNHApp()->mapTile_Y) / 2; if (GetNHApp()->bmpMapTiles == GetNHApp()->bmpTiles) { /* using original nethack tiles - apply image transparently */ (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, TILE_X, TILE_Y, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR); } else { /* using custom tiles - simple blt */ BitBlt(lpdis->hDC, x, y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, tileDC, t_x, t_y, SRCCOPY); } SelectObject(tileDC, saveBmp); x += GetNHApp()->mapTile_X; } else { const char *sel_ind; switch (item->count) { case -1: sel_ind = "+"; break; case 0: sel_ind = "-"; break; default: sel_ind = "#"; break; } SetRect(&drawRect, x, lpdis->rcItem.top, min(x + tm.tmAveCharWidth, lpdis->rcItem.right), lpdis->rcItem.bottom); DrawText(lpdis->hDC, NH_A2W(sel_ind, wbuf, BUFSZ), 1, &drawRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); x += tm.tmAveCharWidth; } } else { /* no glyph - need to adjust so help window won't look to cramped */ x += TILE_X; } x += spacing; /* draw item text */ p1 = item->str; p = strchr(item->str, '\t'); column = 0; SetRect(&drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right), lpdis->rcItem.bottom); for (;;) { TCHAR wbuf[BUFSZ]; if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(lpdis->hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); if (p != NULL) *p = '\t'; else /* last string so, */ break; p1 = p + 1; p = strchr(p1, '\t'); drawRect.left = drawRect.right + TAB_SEPARATION; ++column; drawRect.right = min(drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right); } /* draw focused item */ if (item->has_focus || (NHMENU_IS_SELECTABLE(*item) && data->menu.items[lpdis->itemID].count != -1)) { RECT client_rt; GetClientRect(lpdis->hwndItem, &client_rt); client_rt.right = min(client_rt.right, lpdis->rcItem.right); if (NHMENU_IS_SELECTABLE(*item) && data->menu.items[lpdis->itemID].count != 0 && item->glyph != NO_GLYPH) { if (data->menu.items[lpdis->itemID].count == -1) { _stprintf(wbuf, TEXT("Count: All")); } else { _stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count); } SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE)); /* calculate text rectangle */ SetRect(&drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); /* erase text rectangle */ drawRect.left = max(client_rt.left + 1, client_rt.right - (drawRect.right - drawRect.left) - 10); drawRect.right = client_rt.right - 1; drawRect.top = lpdis->rcItem.top; drawRect.bottom = lpdis->rcItem.bottom; FillRect(lpdis->hDC, &drawRect, menu_bg_brush ? menu_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MENU)); /* draw text */ DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } } if (item->has_focus) { /* draw focus rect */ RECT client_rt; GetClientRect(lpdis->hwndItem, &client_rt); SetRect(&drawRect, client_rt.left, lpdis->rcItem.top, client_rt.left + ListView_GetColumnWidth(lpdis->hwndItem, 0), lpdis->rcItem.bottom); DrawFocusRect(lpdis->hDC, &drawRect); } SetTextColor(lpdis->hDC, OldFg); SetBkColor(lpdis->hDC, OldBg); SelectObject(lpdis->hDC, saveFont); DeleteDC(tileDC); return TRUE; } /*-----------------------------------------------------------------------------*/ BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch) { int i = 0; PNHMenuWindow data; int curIndex, topIndex, pageSize; boolean is_accelerator = FALSE; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (ch) { case MENU_FIRST_PAGE: i = 0; ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_LAST_PAGE: i = max(0, data->menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_NEXT_PAGE: topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ i = min(curIndex + pageSize, data->menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_PREVIOUS_PAGE: topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus up one page */ i = max(curIndex - pageSize, 0); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos up one page */ i = max(topIndex - pageSize, 0); ListView_EnsureVisible(hwndList, i, FALSE); break; case MENU_SELECT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { SelectMenuItem(hwndList, data, i, -1); } return -2; } break; case MENU_UNSELECT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { SelectMenuItem(hwndList, data, i, 0); } return -2; } break; case MENU_INVERT_ALL: if (data->how == PICK_ANY) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { SelectMenuItem(hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } return -2; } break; case MENU_SELECT_PAGE: if (data->how == PICK_ANY) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); to = min(data->menu.size, from + pageSize); for (i = from; i < to; i++) { SelectMenuItem(hwndList, data, i, -1); } return -2; } break; case MENU_UNSELECT_PAGE: if (data->how == PICK_ANY) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); to = min(data->menu.size, from + pageSize); for (i = from; i < to; i++) { SelectMenuItem(hwndList, data, i, 0); } return -2; } break; case MENU_INVERT_PAGE: if (data->how == PICK_ANY) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); from = max(0, topIndex); to = min(data->menu.size, from + pageSize); for (i = from; i < to; i++) { SelectMenuItem(hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } return -2; } break; case MENU_SEARCH: if (data->how == PICK_ANY || data->how == PICK_ONE) { char buf[BUFSZ]; reset_menu_count(hwndList, data); if (mswin_getlin_window("Search for:", buf, BUFSZ) == IDCANCEL) { strcpy(buf, "\033"); } if (data->is_active) SetFocus(hwndList); // set focus back to the list control if (!*buf || *buf == '\033') return -2; for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && strstr(data->menu.items[i].str, buf)) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); break; } } } } else { mswin_nhbell(); } return -2; case ' ': { if (GetNHApp()->regNetHackMode) { /* NetHack mode: Scroll down one page, ends menu when on last page. */ SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hwndList, SB_VERT, &si); if ((si.nPos + (int) si.nPage) > (si.nMax - si.nMin)) { /* We're at the bottom: dismiss. */ data->done = 1; data->result = 0; return -2; } /* We're not at the bottom: page down. */ topIndex = ListView_GetTopIndex(hwndList); pageSize = ListView_GetCountPerPage(hwndList); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ i = min(curIndex + pageSize, data->menu.size - 1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ i = min(topIndex + (2 * pageSize - 1), data->menu.size - 1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; } else { /* Windows mode: ends menu for PICK_ONE/PICK_NONE select item for PICK_ANY */ if (data->how == PICK_ONE || data->how == PICK_NONE) { data->done = 1; data->result = 0; return -2; } else if (data->how == PICK_ANY) { i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if (i >= 0) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } } } } break; default: if (strchr(data->menu.gacc, ch) && !(ch == '0' && data->menu.counting)) { /* matched a group accelerator */ if (data->how == PICK_ANY || data->how == PICK_ONE) { reset_menu_count(hwndList, data); for (i = 0; i < data->menu.size; i++) { if (NHMENU_IS_SELECTABLE(data->menu.items[i]) && data->menu.items[i].group_accel == ch) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); data->result = 0; data->done = 1; return -2; } } } return -2; } else { mswin_nhbell(); return -2; } } if (isdigit(ch)) { int count; i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if (i >= 0) { count = data->menu.items[i].count; if (count == -1) count = 0; count *= 10L; count += (int) (ch - '0'); if (count != 0) /* ignore leading zeros */ { data->menu.counting = TRUE; data->menu.items[i].count = min(100000, count); ListView_RedrawItems(hwndList, i, i); /* update count mark */ } } return -2; } is_accelerator = FALSE; for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].accelerator == ch) { is_accelerator = TRUE; break; } } if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || is_accelerator) { if (data->how == PICK_ANY || data->how == PICK_ONE) { for (i = 0; i < data->menu.size; i++) { if (data->menu.items[i].accelerator == ch) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i]) ? 0 : -1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; } else if (data->how == PICK_ONE) { SelectMenuItem(hwndList, data, i, -1); data->result = 0; data->done = 1; return -2; } } } } } break; } reset_menu_count(hwndList, data); return -1; } /*-----------------------------------------------------------------------------*/ void mswin_menu_window_size(HWND hWnd, LPSIZE sz) { HWND control; PNHMenuWindow data; RECT rt, wrt; int extra_cx; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data) { control = GetMenuControl(hWnd); /* get the control size */ GetClientRect(control, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; /* calculate "extra" space around the control */ GetWindowRect(hWnd, &wrt); extra_cx = (wrt.right - wrt.left) - sz->cx; if (data->type == MENU_TYPE_MENU) { sz->cx = data->menu.menu_cx + GetSystemMetrics(SM_CXVSCROLL); } else { /* Use the width of the text box */ sz->cx = data->text.text_box_size.cx + 2 * GetSystemMetrics(SM_CXVSCROLL); } sz->cx += extra_cx; } else { /* uninitilized window */ GetClientRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; } } /*-----------------------------------------------------------------------------*/ void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count) { int i; if (item < 0 || item >= data->menu.size) return; if (data->how == PICK_ONE && count != 0) { for (i = 0; i < data->menu.size; i++) if (item != i && data->menu.items[i].count != 0) { data->menu.items[i].count = 0; ListView_RedrawItems(hwndList, i, i); }; } data->menu.items[item].count = count; ListView_RedrawItems(hwndList, item, item); reset_menu_count(hwndList, data); } /*-----------------------------------------------------------------------------*/ void reset_menu_count(HWND hwndList, PNHMenuWindow data) { int i; data->menu.counting = FALSE; if (IsWindow(hwndList)) { i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED); if (i >= 0) ListView_RedrawItems(hwndList, i, i); } } /*-----------------------------------------------------------------------------*/ /* List window Proc */ LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bUpdateFocusItem; /* we will redraw focused item whenever horizontal scrolling occurs since "Count: XXX" indicator is garbled by scrolling */ bUpdateFocusItem = FALSE; switch (message) { case WM_KEYDOWN: if (wParam == VK_LEFT || wParam == VK_RIGHT) bUpdateFocusItem = TRUE; break; case WM_CHAR: /* filter keyboard input for the control */ if (wParam > 0 && wParam < 256 && onListChar(GetParent(hWnd), hWnd, (char) wParam) == -2) { return 0; } else { return 1; } break; case WM_SIZE: case WM_HSCROLL: bUpdateFocusItem = TRUE; break; case WM_SETFOCUS: if (GetParent(hWnd) != GetNHApp()->hPopupWnd) { SetFocus(GetNHApp()->hMainWnd); } return FALSE; } /* update focused item */ if (bUpdateFocusItem) { int i; RECT rt; /* invalidate the focus rectangle */ i = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); if (i != -1) { ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS); InvalidateRect(hWnd, &rt, TRUE); } } /* call ListView control window proc */ if (wndProcListViewOrig) return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam); else return 0; } /*-----------------------------------------------------------------------------*/ /* Text control window proc - implements scrolling without a cursor */ LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; RECT rc; switch (message) { case WM_ERASEBKGND: hDC = (HDC) wParam; GetClientRect(hWnd, &rc); FillRect(hDC, &rc, text_bg_brush ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT)); return 0; case WM_KEYDOWN: switch (wParam) { /* close on space in Windows mode page down on space in NetHack mode */ case VK_SPACE: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hWnd, SB_VERT, &si); /* If nethackmode and not at the end of the list */ if (GetNHApp()->regNetHackMode && (si.nPos + (int) si.nPage) <= (si.nMax - si.nMin)) SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); else PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; } case VK_NEXT: SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); return 0; case VK_PRIOR: SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0); return 0; case VK_UP: SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0); return 0; case VK_DOWN: SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0); return 0; } break; case WM_CHAR: switch(wParam) { case MENU_FIRST_PAGE: SendMessage(hWnd, EM_SCROLL, SB_TOP, 0); return 0; case MENU_LAST_PAGE: SendMessage(hWnd, EM_SCROLL, SB_BOTTOM, 0); return 0; case MENU_NEXT_PAGE: SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); return 0; case MENU_PREVIOUS_PAGE: SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0); return 0; } break; /* edit control needs to know nothing of its focus */ case WM_SETFOCUS: HideCaret(hWnd); return 0; } if (editControlWndProc) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } /*-----------------------------------------------------------------------------*/ nethack-3.6.0/win/win32/mhmenu.h0000664000076400007660000000125312536476415015354 0ustar paxedpaxed/* NetHack 3.6 mhmenu.h $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMenuWindow_h #define MSWINMenuWindow_h #include "winMS.h" #include "config.h" #include "global.h" #define MENU_TYPE_TEXT 1 #define MENU_TYPE_MENU 2 extern COLORREF nhcolor_to_RGB(int c); HWND mswin_init_menu_window(int type); int mswin_menu_window_select_menu(HWND hwnd, int how, MENU_ITEM_P **selected, BOOL activate); void mswin_menu_window_size(HWND hwnd, LPSIZE sz); #endif /* MSWINTextWindow_h */ nethack-3.6.0/win/win32/mhmsg.h0000664000076400007660000000356612541713002015165 0ustar paxedpaxed/* NetHack 3.6 mhmsg.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MHNethackMessages_H #define MHNethackMessages_H /* nethack messages */ #define WM_MSNH_COMMAND (WM_APP + 1) #define MSNH_MSG_ADDWND 100 #define MSNH_MSG_PUTSTR 101 #define MSNH_MSG_PRINT_GLYPH 102 #define MSNH_MSG_CLEAR_WINDOW 103 #define MSNH_MSG_CLIPAROUND 104 #define MSNH_MSG_STARTMENU 105 #define MSNH_MSG_ADDMENU 106 #define MSNH_MSG_CURSOR 107 #define MSNH_MSG_ENDMENU 108 #define MSNH_MSG_DIED 109 #define MSNH_MSG_CARET 110 #define MSNH_MSG_GETTEXT 111 #define MSNH_MSG_UPDATE_STATUS 112 typedef struct mswin_nhmsg_add_wnd { winid wid; } MSNHMsgAddWnd, *PMSNHMsgAddWnd; typedef struct mswin_nhmsg_putstr { int attr; const char *text; int append; } MSNHMsgPutstr, *PMSNHMsgPutstr; typedef struct mswin_nhmsg_print_glyph { XCHAR_P x; XCHAR_P y; int glyph; int bkglyph; } MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph; typedef struct mswin_nhmsg_cliparound { int x; int y; } MSNHMsgClipAround, *PMSNHMsgClipAround; typedef struct mswin_nhmsg_add_menu { int glyph; const ANY_P *identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; const char *str; BOOLEAN_P presel; } MSNHMsgAddMenu, *PMSNHMsgAddMenu; typedef struct mswin_nhmsg_cursor { int x; int y; } MSNHMsgCursor, *PMSNHMsgCursor; typedef struct mswin_nhmsg_end_menu { const char *text; } MSNHMsgEndMenu, *PMSNHMsgEndMenu; typedef struct mswin_nhmsg_get_text { size_t max_size; char buffer[]; } MSNHMsgGetText, *PMSNHMsgGetText; typedef struct mswin_nhmsg_update_status { int n_fields; const char **vals; boolean *activefields; int *colors; } MSNHMsgUpdateStatus, *PMSNHMsgUpdateStatus; #endif nethack-3.6.0/win/win32/mhmsgwnd.c0000664000076400007660000006432212570751460015702 0ustar paxedpaxed/* NetHack 3.6 mhmsgwnd.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmsgwnd.h" #include "mhmsg.h" #include "mhfont.h" #define MSG_WRAP_TEXT #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2) #define MAX_MSG_LINES 128 #define MSG_LINES (int) min(iflags.msg_history, MAX_MSG_LINES) #define MAXWINDOWTEXT TBUFSZ #define DEFAULT_COLOR_BG_MSG COLOR_WINDOW #define DEFAULT_COLOR_FG_MSG COLOR_WINDOWTEXT #define MORE "--More--" struct window_line { int attr; char text[MAXWINDOWTEXT + 1]; }; typedef struct mswin_nethack_message_window { size_t max_text; struct window_line window_text[MAX_MSG_LINES]; int lines_last_turn; /* lines added during the last turn */ int lines_not_seen; /* lines not yet seen by user after last turn or --More-- */ int nevermore; /* We want no more --More-- prompts */ int xChar; /* horizontal scrolling unit */ int yChar; /* vertical scrolling unit */ int xUpper; /* average width of uppercase letters */ int xPos; /* current horizontal scrolling position */ int yPos; /* current vertical scrolling position */ int xMax; /* maximum horizontal scrolling position */ int yMax; /* maximum vertical scrolling position */ int xPage; /* page size of horizontal scroll bar */ } NHMessageWindow, *PNHMessageWindow; static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass"); LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM); static void register_message_window_class(void); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifndef MSG_WRAP_TEXT static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #endif static COLORREF setMsgTextColor(HDC hdc, int gray); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static BOOL can_append_text(HWND hWnd, int attr, const char *text); /* check if text can be appended to the last line without wrapping */ static BOOL more_prompt_check(HWND hWnd); /* check if "--more--" prompt needs to be displayed */ #ifdef USER_SOUNDS extern void play_sound_for_message(const char *str); #endif HWND mswin_init_message_window() { static int run_once = 0; HWND ret; DWORD style; RECT rt; if (!run_once) { register_message_window_class(); run_once = 1; } /* get window position */ if (GetNHApp()->bAutoLayout) { SetRect(&rt, 0, 0, 0, 0); } else { mswin_get_window_placement(NHW_MESSAGE, &rt); } #ifdef MSG_WRAP_TEXT style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_SIZEBOX; #else style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL | WS_SIZEBOX; #endif ret = CreateWindowEx( WS_EX_CLIENTEDGE, szMessageWindowClass, /* registered class name */ NULL, /* window name */ style, /* window style */ rt.left, /* horizontal position of window */ rt.top, /* vertical position of window */ rt.right - rt.left, /* window width */ rt.bottom - rt.top, /* window height */ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ if (!ret) panic("Cannot create message window"); /* Set window caption */ SetWindowText(ret, "Messages"); return ret; } void register_message_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC) NHMessageWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = message_bg_brush ? message_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MSG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szMessageWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: onCreate(hWnd, wParam, lParam); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; #ifndef MSG_WRAP_TEXT case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; #endif case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_DESTROY: { PNHMessageWindow data; data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); } break; case WM_SIZE: { SCROLLINFO si; int xNewSize; int yNewSize; PNHMessageWindow data; RECT rt; data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); xNewSize = LOWORD(lParam); yNewSize = HIWORD(lParam); if (xNewSize > 0 || yNewSize > 0) { #ifndef MSG_WRAP_TEXT data->xPage = xNewSize / data->xChar; data->xMax = max(0, (int) (1 + data->max_text - data->xPage)); data->xPos = min(data->xPos, data->xMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = data->max_text; si.nPage = data->xPage; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); #endif data->yMax = MSG_LINES - 1; data->yPos = min(data->yPos, data->yMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = MSG_VISIBLE_LINES; si.nMax = data->yMax + MSG_VISIBLE_LINES - 1; si.nPage = MSG_VISIBLE_LINES; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } /* update NetHack internal window position */ GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_MESSAGE, &rt); /* redraw window - it does not handle incremental resizing too well */ InvalidateRect(hWnd, NULL, TRUE); } break; case WM_MOVE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_MESSAGE, &rt); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; SCROLLINFO si; char *p; if (msg_data->append == 1) { /* Forcibly append to line, even if we pass the edge */ strncat(data->window_text[MSG_LINES - 1].text, msg_data->text, MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES - 1].text)); } else if (msg_data->append < 0) { /* remove that many chars */ int len = strlen(data->window_text[MSG_LINES - 1].text); int newend = max(len + msg_data->append, 0); data->window_text[MSG_LINES - 1].text[newend] = '\0'; } else { if (can_append_text(hWnd, msg_data->attr, msg_data->text)) { strncat(data->window_text[MSG_LINES - 1].text, " ", MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES - 1].text)); strncat(data->window_text[MSG_LINES - 1].text, msg_data->text, MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES - 1].text)); } else { /* check for "--more--" */ if (!data->nevermore && more_prompt_check(hWnd)) { int okkey = 0; int chop; // @@@ Ok respnses /* append more prompt and inticate the update */ strncat( data->window_text[MSG_LINES - 1].text, MORE, MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES - 1].text)); InvalidateRect(hWnd, NULL, TRUE); /* get the input */ while (!okkey) { int c = mswin_nhgetch(); switch (c) { /* space or enter */ case ' ': case '\015': okkey = 1; break; /* ESC */ case '\033': data->nevermore = 1; okkey = 1; break; default: break; } } /* erase the "--more--" prompt */ chop = strlen(data->window_text[MSG_LINES - 1].text) - strlen(MORE); data->window_text[MSG_LINES - 1].text[chop] = '\0'; data->lines_not_seen = 0; } /* check if the string is empty */ for (p = data->window_text[MSG_LINES - 1].text; *p && isspace(*p); p++) ; if (*p) { /* last string is not empty - scroll up */ memmove(&data->window_text[0], &data->window_text[1], (MSG_LINES - 1) * sizeof(data->window_text[0])); } /* append new text to the end of the array */ data->window_text[MSG_LINES - 1].attr = msg_data->attr; strncpy(data->window_text[MSG_LINES - 1].text, msg_data->text, MAXWINDOWTEXT); data->lines_not_seen++; data->lines_last_turn++; } } /* reset V-scroll position to display new text */ data->yPos = data->yMax; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); /* update window content */ InvalidateRect(hWnd, NULL, TRUE); #ifdef USER_SOUNDS if (!GetNHApp()->bNoSounds) play_sound_for_message(msg_data->text); #endif } break; case MSNH_MSG_CLEAR_WINDOW: { data->lines_last_turn = 0; data->lines_not_seen = 0; data->nevermore = 0; break; } case MSNH_MSG_CARET: /* Create or destroy a caret */ if (*(int *) lParam) CreateCaret(hWnd, NULL, 0, data->yChar); else { DestroyCaret(); /* this means we just did something interactive in this window, so we don't need a --More-- for the lines above. */ data->lines_not_seen = 0; } break; case MSNH_MSG_GETTEXT: { PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; int i; size_t buflen; buflen = 0; for (i = 0; i < MSG_LINES; i++) if (*data->window_text[i].text) { strncpy(&msg_data->buffer[buflen], data->window_text[i].text, msg_data->max_size - buflen); buflen += strlen(data->window_text[i].text); if (buflen >= msg_data->max_size) break; strncpy(&msg_data->buffer[buflen], "\r\n", msg_data->max_size - buflen); buflen += 2; if (buflen > msg_data->max_size) break; } } break; } /* switch( wParam ) */ } void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int yInc; UNREFERENCED_PARAMETER(lParam); /* get window data */ data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_POS; GetScrollInfo(hWnd, SB_VERT, &si); switch (LOWORD(wParam)) { // User clicked the shaft above the scroll box. case SB_PAGEUP: yInc = -(int) si.nPage; break; // User clicked the shaft below the scroll box. case SB_PAGEDOWN: yInc = si.nPage; break; // User clicked the top arrow. case SB_LINEUP: yInc = -1; break; // User clicked the bottom arrow. case SB_LINEDOWN: yInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: yInc = HIWORD(wParam) - data->yPos; break; default: yInc = 0; } // If applying the vertical scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. UpdateWindow // sends the WM_PAINT message. if (yInc = max(MSG_VISIBLE_LINES - data->yPos, min(yInc, data->yMax - data->yPos))) { data->yPos += yInc; /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); */ InvalidateRect(hWnd, NULL, TRUE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); UpdateWindow(hWnd); } } #ifndef MSG_WRAP_TEXT void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int xInc; /* get window data */ data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE; GetScrollInfo(hWnd, SB_HORZ, &si); switch (LOWORD(wParam)) { // User clicked shaft left of the scroll box. case SB_PAGEUP: xInc = -(int) si.nPage; break; // User clicked shaft right of the scroll box. case SB_PAGEDOWN: xInc = si.nPage; break; // User clicked the left arrow. case SB_LINEUP: xInc = -1; break; // User clicked the right arrow. case SB_LINEDOWN: xInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: xInc = HIWORD(wParam) - data->xPos; break; default: xInc = 0; } // If applying the horizontal scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. if (xInc = max(-data->xPos, min(xInc, data->xMax - data->xPos))) { data->xPos += xInc; ScrollWindowEx(hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); UpdateWindow(hWnd); } } #endif // MSG_WRAP_TEXT COLORREF setMsgTextColor(HDC hdc, int gray) { COLORREF fg, color1, color2; if (gray) { if (message_bg_brush) { color1 = message_bg_color; color2 = message_fg_color; } else { color1 = (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MSG); color2 = (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MSG); } /* Make a "gray" color by taking the average of the individual R,G,B components of two colors. Thanks to Jonathan del Strother */ fg = RGB((GetRValue(color1) + GetRValue(color2)) / 2, (GetGValue(color1) + GetGValue(color2)) / 2, (GetBValue(color1) + GetBValue(color2)) / 2); } else { fg = message_fg_brush ? message_fg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_MSG); } return SetTextColor(hdc, fg); } void onPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; PNHMessageWindow data; RECT client_rt, draw_rt; int FirstLine, LastLine; int i, x, y; HGDIOBJ oldFont; TCHAR wbuf[MAXWINDOWTEXT + 2]; size_t wlen; COLORREF OldBg, OldFg; hdc = BeginPaint(hWnd, &ps); OldBg = SetBkColor( hdc, message_bg_brush ? message_bg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_MSG)); OldFg = setMsgTextColor(hdc, 0); data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); GetClientRect(hWnd, &client_rt); if (!IsRectEmpty(&ps.rcPaint)) { FirstLine = max( 0, data->yPos - (client_rt.bottom - ps.rcPaint.top) / data->yChar + 1); LastLine = min(MSG_LINES - 1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar); y = min(ps.rcPaint.bottom, client_rt.bottom); for (i = LastLine; i >= FirstLine; i--) { x = data->xChar * (2 - data->xPos); draw_rt.left = x; draw_rt.right = client_rt.right; draw_rt.top = y - data->yChar; draw_rt.bottom = y; oldFont = SelectObject( hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE)); /* convert to UNICODE */ NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf)); wlen = _tcslen(wbuf); setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn)); #ifdef MSG_WRAP_TEXT /* Find out how large the bounding rectangle of the text is */ DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); /* move that rectangle up, so that the bottom remains at the same * height */ draw_rt.top = y - (draw_rt.bottom - draw_rt.top); draw_rt.bottom = y; /* Now really draw it */ DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK); /* Find out the cursor (caret) position */ if (i == MSG_LINES - 1) { int nnum, numfit; SIZE size; TCHAR *nbuf; int nlen; nbuf = wbuf; nlen = wlen; while (nlen) { /* Get the number of characters that fit on the line */ GetTextExtentExPoint(hdc, nbuf, nlen, draw_rt.right - draw_rt.left, &numfit, NULL, &size); /* Search back to a space */ nnum = numfit; if (numfit < nlen) { while (nnum > 0 && nbuf[nnum] != ' ') nnum--; /* If no space found, break wherever */ if (nnum == 0) nnum = numfit; } nbuf += nnum; nlen -= nnum; if (*nbuf == ' ') { nbuf++; nlen--; } } /* The last size is the size of the last line. Set the caret there. This will fail automatically if we don't own the caret (i.e., when not in a question.) */ SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar); } #else DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX); SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar); #endif SelectObject(hdc, oldFont); y -= draw_rt.bottom - draw_rt.top; } } SetTextColor(hdc, OldFg); SetBkColor(hdc, OldBg); EndPaint(hWnd, &ps); } void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SIZE dummy; UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); /* set window data */ data = (PNHMessageWindow) malloc(sizeof(NHMessageWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHMessageWindow)); data->max_text = MAXWINDOWTEXT; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* re-calculate window size (+ font size) */ mswin_message_window_size(hWnd, &dummy); } void mswin_message_window_size(HWND hWnd, LPSIZE sz) { HDC hdc; HGDIOBJ saveFont; TEXTMETRIC tm; PNHMessageWindow data; RECT rt, client_rt; data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (!data) return; /* -- Calculate the font size -- */ /* Get the handle to the client area's device context. */ hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); /* Extract font dimensions from the text metrics. */ GetTextMetrics(hdc, &tm); data->xChar = tm.tmAveCharWidth; data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar / 2; data->yChar = tm.tmHeight + tm.tmExternalLeading; data->xPage = 1; /* Free the device context. */ SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); /* -- calculate window size -- */ GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; /* set size to accomodate MSG_VISIBLE_LINES and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); sz->cy = sz->cy - (client_rt.bottom - client_rt.top) + data->yChar * MSG_VISIBLE_LINES; } /* check if text can be appended to the last line without wrapping */ BOOL can_append_text(HWND hWnd, int attr, const char *text) { PNHMessageWindow data; char tmptext[MAXWINDOWTEXT + 1]; HDC hdc; HGDIOBJ saveFont; RECT draw_rt; BOOL retval = FALSE; data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* cannot append if lines_not_seen is 0 (beginning of the new turn */ if (data->lines_not_seen == 0) return FALSE; /* cannot append text with different attrbutes */ if (data->window_text[MSG_LINES - 1].attr != attr) return FALSE; /* check if the maximum string langth will be exceeded */ if (strlen(data->window_text[MSG_LINES - 1].text) + 2 + /* space characters */ strlen(text) + strlen(MORE) >= MAXWINDOWTEXT) return FALSE; /* check if the text is goinf to fin into a single line */ strcpy(tmptext, data->window_text[MSG_LINES - 1].text); strcat(tmptext, " "); strcat(tmptext, text); strcat(tmptext, MORE); hdc = GetDC(hWnd); saveFont = SelectObject( hdc, mswin_get_font(NHW_MESSAGE, data->window_text[MSG_LINES - 1].attr, hdc, FALSE)); GetClientRect(hWnd, &draw_rt); draw_rt.bottom = draw_rt.top; /* we only need width for the DrawText */ DrawText(hdc, tmptext, strlen(tmptext), &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); /* we will check against 1.5 of the font size in order to determine if the text is single-line or not - just to be on the safe size */ retval = (draw_rt.bottom - draw_rt.top) < (data->yChar + data->yChar / 2); /* free device context */ SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); return retval; } /* check if "--more--" prompt needs to be displayed basically, check if the lines not seen are going to find in the message window */ BOOL more_prompt_check(HWND hWnd) { PNHMessageWindow data; HDC hdc; HGDIOBJ saveFont; RECT client_rt, draw_rt; int i; int remaining_height; char tmptext[MAXWINDOWTEXT + 1]; data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data->lines_not_seen == 0) return FALSE; /* don't bother checking - nothig to "more" */ if (data->lines_not_seen >= MSG_LINES) return TRUE; /* history size exceeded - always more */ GetClientRect(hWnd, &client_rt); remaining_height = client_rt.bottom - client_rt.top; hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); for (i = 0; i < data->lines_not_seen; i++) { /* we only need width for the DrawText */ SetRect(&draw_rt, client_rt.left, client_rt.top, client_rt.right, client_rt.top); SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[MSG_LINES - i - 1].attr, hdc, FALSE)); strcpy(tmptext, data->window_text[MSG_LINES - i - 1].text); if (i == 0) strcat(tmptext, MORE); remaining_height -= DrawText(hdc, tmptext, strlen(tmptext), &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); if (remaining_height <= 0) break; } /* free device context */ SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); return (remaining_height <= 0); /* TRUE if lines_not_seen take more that window height */ } nethack-3.6.0/win/win32/mhmsgwnd.h0000664000076400007660000000073612536476415015714 0ustar paxedpaxed/* NetHack 3.6 mhmsgwnd.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMessageWindow_h #define MSWINMessageWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_message_window(void); void mswin_message_window_size(HWND hWnd, LPSIZE sz); #endif /* MSWINMessageWindow_h */ nethack-3.6.0/win/win32/mhrip.c0000664000076400007660000002067112536476415015202 0ustar paxedpaxed/* NetHack 3.6 mhrip.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhrip.h" #include "mhmsg.h" #include "mhfont.h" #define RIP_WIDTH 400 #define RIP_HEIGHT 200 #define RIP_GRAVE_HEIGHT 120 #define RIP_GRAVE_WIDTH 115 #define RIP_GRAVE_X 90 #define RIP_GRAVE_Y 60 #define RIP_OFFSET_X 10 #define RIP_OFFSET_Y 10 PNHWinApp GetNHApp(void); typedef struct mswin_nethack_text_window { HANDLE rip_bmp; TCHAR *window_text; TCHAR *rip_text; } NHRIPWindow, *PNHRIPWindow; INT_PTR CALLBACK NHRIPWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); HWND mswin_init_RIP_window() { HWND ret; PNHRIPWindow data; ret = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHRIP), GetNHApp()->hMainWnd, NHRIPWndProc); if (!ret) panic("Cannot create rip window"); data = (PNHRIPWindow) malloc(sizeof(NHRIPWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHRIPWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); return ret; } void mswin_display_RIP_window(HWND hWnd) { MSG msg; RECT rt; PNHRIPWindow data; HWND mapWnd; RECT riprt; RECT clientrect; RECT textrect; HDC hdc; HFONT OldFont; data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); GetNHApp()->hPopupWnd = hWnd; mapWnd = mswin_hwnd_from_winid(WIN_MAP); if (!IsWindow(mapWnd)) mapWnd = GetNHApp()->hMainWnd; GetWindowRect(mapWnd, &rt); GetWindowRect(hWnd, &riprt); GetClientRect(hWnd, &clientrect); textrect = clientrect; textrect.top += RIP_OFFSET_Y; textrect.left += RIP_OFFSET_X; textrect.right -= RIP_OFFSET_X; if (data->window_text) { hdc = GetDC(hWnd); OldFont = SelectObject(hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); DrawText(hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); SelectObject(hdc, OldFont); ReleaseDC(hWnd, hdc); } if (textrect.right - textrect.left > RIP_WIDTH) clientrect.right = textrect.right + RIP_OFFSET_X - clientrect.right; else clientrect.right = textrect.left + 2 * RIP_OFFSET_X + RIP_WIDTH - clientrect.right; clientrect.bottom = textrect.bottom + RIP_HEIGHT + RIP_OFFSET_Y - clientrect.bottom; GetWindowRect(GetDlgItem(hWnd, IDOK), &textrect); textrect.right -= textrect.left; textrect.bottom -= textrect.top; clientrect.bottom += textrect.bottom + RIP_OFFSET_Y; riprt.right -= riprt.left; riprt.bottom -= riprt.top; riprt.right += clientrect.right; riprt.bottom += clientrect.bottom; rt.left += (rt.right - rt.left - riprt.right) / 2; rt.top += (rt.bottom - rt.top - riprt.bottom) / 2; MoveWindow(hWnd, rt.left, rt.top, riprt.right, riprt.bottom, TRUE); GetClientRect(hWnd, &clientrect); MoveWindow(GetDlgItem(hWnd, IDOK), (clientrect.right - clientrect.left - textrect.right) / 2, clientrect.bottom - textrect.bottom - RIP_OFFSET_Y, textrect.right, textrect.bottom, TRUE); ShowWindow(hWnd, SW_SHOW); while (IsWindow(hWnd) && GetMessage(&msg, NULL, 0, 0) != 0) { if (!IsDialogMessage(hWnd, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } GetNHApp()->hPopupWnd = NULL; } INT_PTR CALLBACK NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PNHRIPWindow data; data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { case WM_INITDIALOG: /* set text control font */ hdc = GetDC(hWnd); SendMessage(hWnd, WM_SETFONT, (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(hWnd, hdc); SetFocus(GetDlgItem(hWnd, IDOK)); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: { int bitmap_offset; RECT clientrect; RECT textrect; HDC hdcBitmap; HANDLE OldBitmap; PAINTSTRUCT ps; HFONT OldFont; hdc = BeginPaint(hWnd, &ps); OldFont = SelectObject(hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); hdcBitmap = CreateCompatibleDC(hdc); SetBkMode(hdc, TRANSPARENT); GetClientRect(hWnd, &clientrect); textrect = clientrect; textrect.top += RIP_OFFSET_Y; textrect.left += RIP_OFFSET_X; textrect.right -= RIP_OFFSET_X; if (data->window_text) { DrawText(hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); DrawText(hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX); } OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpRip); SetBkMode(hdc, OPAQUE); bitmap_offset = (textrect.right - textrect.left - RIP_WIDTH) / 2; BitBlt(hdc, textrect.left + bitmap_offset, textrect.bottom, RIP_WIDTH, RIP_HEIGHT, hdcBitmap, 0, 0, SRCCOPY); SetBkMode(hdc, TRANSPARENT); if (data->rip_text) { textrect.left += RIP_GRAVE_X + bitmap_offset; textrect.top = textrect.bottom + RIP_GRAVE_Y; textrect.right = textrect.left + RIP_GRAVE_WIDTH; textrect.bottom = textrect.top + RIP_GRAVE_HEIGHT; DrawText(hdc, data->rip_text, strlen(data->rip_text), &textrect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_WORDBREAK); } SelectObject(hdcBitmap, OldBitmap); SelectObject(hdc, OldFont); DeleteDC(hdcBitmap); EndPaint(hWnd, &ps); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if (GetNHApp()->hMainWnd == hWnd) GetNHApp()->hMainWnd = NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); return TRUE; } break; case WM_CLOSE: /* if we get this here, we saved the bones so we can just force a quit */ mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if (GetNHApp()->hMainWnd == hWnd) GetNHApp()->hMainWnd = NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); program_state.stopprint++; return TRUE; case WM_DESTROY: if (data) { if (data->window_text) free(data->window_text); if (data->rip_text) free(data->rip_text); if (data->rip_bmp != NULL) DeleteObject(data->rip_bmp); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); } break; } return FALSE; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHRIPWindow data; static int InRipText = 1; data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; TCHAR wbuf[BUFSZ]; size_t text_size; if (!data->window_text) { text_size = strlen(msg_data->text) + 4; data->window_text = (TCHAR *) malloc(text_size * sizeof(data->window_text[0])); ZeroMemory(data->window_text, text_size * sizeof(data->window_text[0])); } else { text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4; data->window_text = (TCHAR *) realloc( data->window_text, text_size * sizeof(data->window_text[0])); } if (!data->window_text) break; _tcscat(data->window_text, NH_A2W(msg_data->text, wbuf, BUFSZ)); _tcscat(data->window_text, TEXT("\r\n")); break; } case MSNH_MSG_DIED: { data->rip_text = data->window_text; data->window_text = NULL; break; } } } void mswin_finish_rip_text(winid wid) { SendMessage(mswin_hwnd_from_winid(wid), WM_MSNH_COMMAND, MSNH_MSG_DIED, 0); } nethack-3.6.0/win/win32/mhrip.h0000664000076400007660000000074712536476415015211 0ustar paxedpaxed/* NetHack 3.6 mhrip.h $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINRIPWindow_h #define MSWINRIPWindow_h #include "winMS.h" #include "config.h" #include "global.h" void mswin_finish_rip_text(winid wid); HWND mswin_init_RIP_window(void); void mswin_display_RIP_window(HWND hwnd); #endif /* MSWINRIPWindow_h */ nethack-3.6.0/win/win32/mhsplash.c0000664000076400007660000001750712541713002015664 0ustar paxedpaxed/* NetHack 3.6 mhsplash.c $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhsplash.h" #include "mhmsg.h" #include "mhfont.h" #include "date.h" #include "patchlevel.h" #include "dlb.h" #define LLEN 128 PNHWinApp GetNHApp(void); INT_PTR CALLBACK NHSplashWndProc(HWND, UINT, WPARAM, LPARAM); #define SPLASH_WIDTH 440 #define SPLASH_HEIGHT 322 #define SPLASH_VERSION_X 290 #define SPLASH_VERSION_Y 10 #define SPLASH_OFFSET_X 10 #define SPLASH_OFFSET_Y 10 extern HFONT version_splash_font; void mswin_display_splash_window(BOOL show_ver) { MSG msg; int left, top; RECT splashrt; RECT clientrt; RECT controlrt; HWND hWnd; int buttop; int strsize = 0; int bufsize = BUFSZ; char *buf = malloc(bufsize); if (buf == NULL) panic("out of memory"); buf[0] = '\0'; hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), GetNHApp()->hMainWnd, NHSplashWndProc); if (!hWnd) panic("Cannot create Splash window"); mswin_init_splashfonts(hWnd); GetNHApp()->hPopupWnd = hWnd; /* Get control size */ GetWindowRect(GetDlgItem(hWnd, IDOK), &controlrt); controlrt.right -= controlrt.left; controlrt.bottom -= controlrt.top; /* Get current client area */ GetClientRect(hWnd, &clientrt); /* Get window size */ GetWindowRect(hWnd, &splashrt); splashrt.right -= splashrt.left; splashrt.bottom -= splashrt.top; /* Get difference between requested client area and current value */ splashrt.right += SPLASH_WIDTH + SPLASH_OFFSET_X * 2 - clientrt.right; splashrt.bottom += SPLASH_HEIGHT + controlrt.bottom + SPLASH_OFFSET_Y * 3 - clientrt.bottom; /* Place the window centered */ /* On the screen, not on the parent window */ left = (GetSystemMetrics(SM_CXSCREEN) - splashrt.right) / 2; top = (GetSystemMetrics(SM_CYSCREEN) - splashrt.bottom) / 2; MoveWindow(hWnd, left, top, splashrt.right, splashrt.bottom, TRUE); /* Place the OK control */ GetClientRect(hWnd, &clientrt); MoveWindow(GetDlgItem(hWnd, IDOK), (clientrt.right - clientrt.left - controlrt.right) / 2, clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y, controlrt.right, controlrt.bottom, TRUE); buttop = clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y; /* Place the text control */ GetWindowRect(GetDlgItem(hWnd, IDC_EXTRAINFO), &controlrt); controlrt.right -= controlrt.left; controlrt.bottom -= controlrt.top; GetClientRect(hWnd, &clientrt); MoveWindow(GetDlgItem(hWnd, IDC_EXTRAINFO), clientrt.left + SPLASH_OFFSET_X, buttop - controlrt.bottom - SPLASH_OFFSET_Y, clientrt.right - 2 * SPLASH_OFFSET_X, controlrt.bottom, TRUE); /* Fill the text control */ Sprintf(buf, "%s\r\n%s\r\n%s\r\n%s\r\n\r\n", COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C, COPYRIGHT_BANNER_D); strsize = strlen(buf); if (show_ver) { /* Show complete version information */ dlb *f; getversionstring(buf + strsize); strcat(buf, "\r\n\r\n"); strsize = strlen(buf); /* Add compile options */ f = dlb_fopen(OPTIONS_USED, RDTMODE); if (f) { char line[LLEN + 1]; while (dlb_fgets(line, LLEN, f)) { size_t len; len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\r'; line[len] = '\n'; line[len + 1] = '\0'; len++; } if (strsize + (int) len + 1 > bufsize) { bufsize += BUFSZ; buf = realloc(buf, bufsize); if (buf == NULL) panic("out of memory"); } strcat(buf, line); strsize += len; } (void) dlb_fclose(f); } } else { /* Show news, if any */ if (iflags.news) { FILE *nf; iflags.news = 0; /* prevent newgame() from re-displaying news */ nf = fopen(NEWS, "r"); if (nf != NULL) { char line[LLEN + 1]; while (fgets(line, LLEN, nf)) { size_t len; len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\r'; line[len] = '\n'; line[len + 1] = '\0'; len++; } if (strsize + (int) len + 1 > bufsize) { bufsize += BUFSZ; buf = realloc(buf, bufsize); if (buf == NULL) panic("out of memory"); } strcat(buf, line); strsize += len; } (void) fclose(nf); } else { strcat(buf, "No news."); } } } SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), buf); free(buf); ShowWindow(hWnd, SW_SHOW); while (IsWindow(hWnd) && GetMessage(&msg, NULL, 0, 0) != 0) { if (!IsDialogMessage(hWnd, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } GetNHApp()->hPopupWnd = NULL; mswin_destroy_splashfonts(); } INT_PTR CALLBACK NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: /* set text control font */ hdc = GetDC(hWnd); SendMessage(hWnd, WM_SETFONT, (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(hWnd, hdc); SetFocus(GetDlgItem(hWnd, IDOK)); return FALSE; case WM_PAINT: { char VersionString[BUFSZ]; RECT rt; HDC hdcBitmap; HANDLE OldBitmap; HANDLE OldFont; PAINTSTRUCT ps; hdc = BeginPaint(hWnd, &ps); /* Show splash graphic */ hdcBitmap = CreateCompatibleDC(hdc); SetBkMode(hdc, OPAQUE); OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpSplash); (*GetNHApp()->lpfnTransparentBlt)(hdc, SPLASH_OFFSET_X, SPLASH_OFFSET_Y, SPLASH_WIDTH, SPLASH_HEIGHT, hdcBitmap, 0, 0, SPLASH_WIDTH, SPLASH_HEIGHT, TILE_BK_COLOR); SelectObject(hdcBitmap, OldBitmap); DeleteDC(hdcBitmap); SetBkMode(hdc, TRANSPARENT); /* Print version number */ SetTextColor(hdc, RGB(0, 0, 0)); rt.right = rt.left = SPLASH_VERSION_X; rt.bottom = rt.top = SPLASH_VERSION_Y; Sprintf(VersionString, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); OldFont = SelectObject(hdc, version_splash_font); DrawText(hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); DrawText(hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX); EndPaint(hWnd, &ps); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if (GetNHApp()->hMainWnd == hWnd) GetNHApp()->hMainWnd = NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); return TRUE; } break; } return FALSE; } nethack-3.6.0/win/win32/mhsplash.h0000664000076400007660000000061612536476415015704 0ustar paxedpaxed/* Copyright (C) 2002 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ #ifndef MSWINSplashWindow_h #define MSWINSplashWindow_h #include "winMS.h" #include "config.h" #include "global.h" void mswin_display_splash_window(BOOL); #endif /* MSWINSplashWindow_h */ nethack-3.6.0/win/win32/mhstatus.c0000664000076400007660000002662712536476415015742 0ustar paxedpaxed/* NetHack 3.6 mhstatus.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhstatus.h" #include "mhmsg.h" #include "mhfont.h" #define NHSW_LINES 2 #define MAXWINDOWTEXT BUFSZ extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */ typedef struct mswin_nethack_status_window { int index; char window_text[NHSW_LINES][MAXWINDOWTEXT + 1]; int n_fields; const char **vals; boolean *activefields; int *colors; } NHStatusWindow, *PNHStatusWindow; #ifdef STATUS_VIA_WINDOWPORT static int fieldorder1[] = { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, -1 }; static int fieldorder2[] = { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, -1 }; static int *fieldorders[] = { fieldorder1, fieldorder2, NULL }; #endif /* STATUS_VIA_WINDOWPORT */ static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass"); LRESULT CALLBACK StatusWndProc(HWND, UINT, WPARAM, LPARAM); static void register_status_window_class(void); static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam); #define DEFAULT_COLOR_BG_STATUS COLOR_WINDOW #define DEFAULT_COLOR_FG_STATUS COLOR_WINDOWTEXT HWND mswin_init_status_window() { static int run_once = 0; HWND ret; NHStatusWindow *data; RECT rt; if (!run_once) { register_status_window_class(); run_once = 1; } /* get window position */ if (GetNHApp()->bAutoLayout) { SetRect(&rt, 0, 0, 0, 0); } else { mswin_get_window_placement(NHW_STATUS, &rt); } /* create status window object */ ret = CreateWindow(szStatusWindowClass, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_SIZEBOX, rt.left, /* horizontal position of window */ rt.top, /* vertical position of window */ rt.right - rt.left, /* window width */ rt.bottom - rt.top, /* window height */ GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL); if (!ret) panic("Cannot create status window"); /* Set window caption */ SetWindowText(ret, "Status"); /* create window data */ data = (PNHStatusWindow) malloc(sizeof(NHStatusWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHStatusWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); return ret; } void register_status_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC) StatusWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = status_bg_brush ? status_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_STATUS); wcex.lpszMenuName = NULL; wcex.lpszClassName = szStatusWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHStatusWindow data; data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { case WM_MSNH_COMMAND: { switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; strncpy(data->window_text[data->index], msg_data->text, MAXWINDOWTEXT); data->index = (data->index + 1) % NHSW_LINES; InvalidateRect(hWnd, NULL, TRUE); } break; case MSNH_MSG_CLEAR_WINDOW: { data->index = 0; ZeroMemory(data->window_text, sizeof(data->window_text)); InvalidateRect(hWnd, NULL, TRUE); } break; case MSNH_MSG_GETTEXT: { PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; #ifdef STATUS_VIA_WINDOWPORT int **fop; int *f; msg_data->buffer[0] = '\0'; if (data->n_fields > 0) { for (fop = fieldorders; *fop; fop++) { for (f = *fop; *f != -1; f++) { if (data->activefields[*f]) strncat(msg_data->buffer, data->vals[*f], msg_data->max_size - strlen(msg_data->buffer)); } strncat(msg_data->buffer, "\r\n", msg_data->max_size - strlen(msg_data->buffer)); } } #else /* STATUS_VIA_WINDOWPORT */ strncpy(msg_data->buffer, data->window_text[0], msg_data->max_size); strncat(msg_data->buffer, "\r\n", msg_data->max_size - strlen(msg_data->buffer)); strncat(msg_data->buffer, data->window_text[1], msg_data->max_size - strlen(msg_data->buffer)); #endif /* STATUS_VIA_WINDOWPORT */ } break; case MSNH_MSG_UPDATE_STATUS: { PMSNHMsgUpdateStatus msg_data = (PMSNHMsgUpdateStatus) lParam; data->n_fields = msg_data->n_fields; data->vals = msg_data->vals; data->activefields = msg_data->activefields; data->colors = msg_data->colors; InvalidateRect(hWnd, NULL, TRUE); } break; } /* end switch( wParam ) { */ } break; case WM_PAINT: return onWMPaint(hWnd, wParam, lParam); case WM_SIZE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_STATUS, &rt); } return FALSE; case WM_MOVE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_STATUS, &rt); } return FALSE; case WM_DESTROY: free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } #ifdef STATUS_VIA_WINDOWPORT static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) { int *f; int **fop; SIZE sz; HGDIOBJ oldFont, normalFont, boldFont; TCHAR wbuf[BUFSZ]; COLORREF OldBg, OldFg, Bg, Fg; RECT rt; PAINTSTRUCT ps; HDC hdc; PNHStatusWindow data; data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); normalFont = mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE); boldFont = mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, FALSE); oldFont = SelectObject(hdc, normalFont); Bg = status_bg_brush ? status_bg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_STATUS); OldBg = SetBkColor(hdc, Bg); Fg = status_fg_brush ? status_fg_color : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_STATUS); OldFg = SetTextColor(hdc, Fg); for (fop = fieldorders; *fop; fop++) { LONG left = rt.left; LONG cy = 0; int vlen; for (f = *fop; *f != -1; f++) { if (((*f) >= data->n_fields) || (!data->activefields[*f])) continue; vlen = strlen(data->vals[*f]); NH_A2W(data->vals[*f], wbuf, SIZE(wbuf)); if (!iflags.use_status_hilites) { SelectObject(hdc, normalFont); SetBkColor(hdc, Bg); SetTextColor(hdc, Fg); } else if (data->colors[*f] == CLR_MAX || data->colors[*f] == BL_HILITE_NONE) { SelectObject(hdc, normalFont); SetBkColor(hdc, Bg); SetTextColor(hdc, Fg); } else if (data->colors[*f] > 0) { SelectObject(hdc, normalFont); SetBkColor(hdc, Bg); SetTextColor(hdc, nhcolor_to_RGB(data->colors[*f])); } else if (data->colors[*f] == BL_HILITE_INVERSE) { SelectObject(hdc, normalFont); SetBkColor(hdc, Fg); SetTextColor(hdc, Bg); } else if (data->colors[*f] == BL_HILITE_BOLD) { SelectObject(hdc, boldFont); SetBkColor(hdc, Bg); SetTextColor(hdc, Fg); } else { SelectObject(hdc, normalFont); SetBkColor(hdc, Bg); SetTextColor(hdc, Fg); } GetTextExtentPoint32(hdc, wbuf, vlen, &sz); DrawText(hdc, wbuf, vlen, &rt, DT_LEFT); rt.left += sz.cx; cy = max(cy, sz.cy); } rt.left = left; rt.top += cy; } SelectObject(hdc, oldFont); SetTextColor(hdc, OldFg); SetBkColor(hdc, OldBg); EndPaint(hWnd, &ps); return 0; } #else static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) { int i; SIZE sz; HGDIOBJ oldFont; TCHAR wbuf[BUFSZ]; COLORREF OldBg, OldFg; RECT rt; PAINTSTRUCT ps; HDC hdc; PNHStatusWindow data; data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); oldFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); OldBg = SetBkColor(hdc, status_bg_brush ? status_bg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_BG_STATUS)); OldFg = SetTextColor(hdc, status_fg_brush ? status_fg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_FG_STATUS)); for (i = 0; i < NHSW_LINES; i++) { int wlen = strlen(data->window_text[i]); NH_A2W(data->window_text[i], wbuf, SIZE(wbuf)); GetTextExtentPoint32(hdc, wbuf, wlen, &sz); DrawText(hdc, wbuf, wlen, &rt, DT_LEFT | DT_END_ELLIPSIS); rt.top += sz.cy; } SelectObject(hdc, oldFont); SetTextColor(hdc, OldFg); SetBkColor(hdc, OldBg); EndPaint(hWnd, &ps); return 0; } #endif /*STATUS_VIA_WINDOWPORT*/ void mswin_status_window_size(HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHStatusWindow data; RECT rt; SIZE text_sz; GetClientRect(hWnd, &rt); data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data) { hdc = GetDC(hWnd); saveFont = SelectObject( hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); GetTextExtentPoint32(hdc, _T("W"), 1, &text_sz); GetTextMetrics(hdc, &tm); rt.bottom = rt.top + text_sz.cy * NHSW_LINES; SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); } AdjustWindowRect(&rt, GetWindowLong(hWnd, GWL_STYLE), FALSE); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; } nethack-3.6.0/win/win32/mhstatus.h0000664000076400007660000000073212536476415015734 0ustar paxedpaxed/* NetHack 3.6 mhstatus.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINStatusWindow_h #define MSWINStatusWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_status_window(void); void mswin_status_window_size(HWND hWnd, LPSIZE sz); #endif /* MSWINStatusWindow_h */ nethack-3.6.0/win/win32/mhtext.c0000664000076400007660000002374112536476415015375 0ustar paxedpaxed/* NetHack 3.6 mhtext.c $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhtext.h" #include "mhmsg.h" #include "mhfont.h" PNHWinApp GetNHApp(void); typedef struct mswin_nethack_text_window { TCHAR *window_text; } NHTextWindow, *PNHTextWindow; static WNDPROC editControlWndProc = 0; #define DEFAULT_COLOR_BG_TEXT COLOR_WINDOW #define DEFAULT_COLOR_FG_TEXT COLOR_WINDOWTEXT INT_PTR CALLBACK NHTextWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHEditHookWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutText(HWND hwnd); HWND mswin_init_text_window() { HWND ret; PNHTextWindow data; RECT rt; /* get window position */ if (GetNHApp()->bAutoLayout) { SetRect(&rt, 0, 0, 0, 0); } else { mswin_get_window_placement(NHW_TEXT, &rt); } /* create text widnow object */ ret = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHTEXT), GetNHApp()->hMainWnd, NHTextWndProc); if (!ret) panic("Cannot create text window"); /* move it in the predefined position */ if (!GetNHApp()->bAutoLayout) { MoveWindow(ret, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, TRUE); } /* Set window caption */ SetWindowText(ret, "Text"); if (!GetNHApp()->bWindowsLocked) { DWORD style; style = GetWindowLong(ret, GWL_STYLE); style |= WS_CAPTION; SetWindowLong(ret, GWL_STYLE, style); SetWindowPos(ret, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); } /* create and set window data */ data = (PNHTextWindow) malloc(sizeof(NHTextWindow)); if (!data) panic("out of memory"); ZeroMemory(data, sizeof(NHTextWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); return ret; } void mswin_display_text_window(HWND hWnd) { PNHTextWindow data; data = (PNHTextWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); if (data && data->window_text) { HWND control; control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); SendMessage(control, EM_FMTLINES, 1, 0); SetWindowText(control, data->window_text); } mswin_popup_display(hWnd, NULL); mswin_popup_destroy(hWnd); } INT_PTR CALLBACK NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HWND control; HDC hdc; PNHTextWindow data; TCHAR title[MAX_LOADSTRING]; data = (PNHTextWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { case WM_INITDIALOG: /* set text control font */ control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); if (!control) { panic("cannot get text view window"); } hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(control, hdc); /* subclass edit control */ editControlWndProc = (WNDPROC) GetWindowLongPtr(control, GWLP_WNDPROC); SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) NHEditHookWndProc); SetFocus(control); /* Even though the dialog has no caption, you can still set the title which shows on Alt-Tab */ LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING); SetWindowText(hWnd, title); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_TEXT, &rt); LayoutText(hWnd); } return FALSE; case WM_MOVE: { RECT rt; GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); mswin_update_window_placement(NHW_TEXT, &rt); } return FALSE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if (GetNHApp()->hMainWnd == hWnd) GetNHApp()->hMainWnd = NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); return TRUE; } break; case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if (hwndEdit == GetDlgItem(hWnd, IDC_TEXT_CONTROL)) { SetBkColor(hdcEdit, text_bg_brush ? text_bg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_BG_TEXT)); SetTextColor(hdcEdit, text_fg_brush ? text_fg_color : (COLORREF) GetSysColor( DEFAULT_COLOR_FG_TEXT)); return (INT_PTR)(text_bg_brush ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT)); } } return FALSE; case WM_DESTROY: if (data) { if (data->window_text) free(data->window_text); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); } break; } return FALSE; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHTextWindow data; data = (PNHTextWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; TCHAR wbuf[BUFSZ]; size_t text_size; if (!data->window_text) { text_size = strlen(msg_data->text) + 4; data->window_text = (TCHAR *) malloc(text_size * sizeof(data->window_text[0])); ZeroMemory(data->window_text, text_size * sizeof(data->window_text[0])); } else { text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4; data->window_text = (TCHAR *) realloc( data->window_text, text_size * sizeof(data->window_text[0])); } if (!data->window_text) break; _tcscat(data->window_text, NH_A2W(msg_data->text, wbuf, BUFSZ)); _tcscat(data->window_text, TEXT("\r\n")); break; } } } void LayoutText(HWND hWnd) { HWND btn_ok; HWND text; RECT clrt, rt; POINT pt_elem, pt_ok; SIZE sz_elem, sz_ok; text = GetDlgItem(hWnd, IDC_TEXT_CONTROL); btn_ok = GetDlgItem(hWnd, IDOK); /* get window coordinates */ GetClientRect(hWnd, &clrt); /* set window placements */ GetWindowRect(btn_ok, &rt); sz_ok.cx = clrt.right - clrt.left; sz_ok.cy = rt.bottom - rt.top; pt_ok.x = clrt.left; pt_ok.y = clrt.bottom - sz_ok.cy; pt_elem.x = clrt.left; pt_elem.y = clrt.top; sz_elem.cx = clrt.right - clrt.left; sz_elem.cy = pt_ok.y; MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE); MoveWindow(btn_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE); } /* Edit box hook */ LRESULT CALLBACK NHEditHookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; RECT rc; switch (message) { case WM_ERASEBKGND: hDC = (HDC) wParam; GetClientRect(hWnd, &rc); FillRect(hDC, &rc, text_bg_brush ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT)); return 1; case WM_KEYDOWN: switch (wParam) { /* close on space in Windows mode page down on space in NetHack mode */ case VK_SPACE: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hWnd, SB_VERT, &si); /* If nethackmode and not at the end of the list */ if (GetNHApp()->regNetHackMode && (si.nPos + (int) si.nPage) <= (si.nMax - si.nMin)) SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); else PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; } case VK_NEXT: SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); return 0; case VK_PRIOR: SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0); return 0; case VK_UP: SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0); return 0; case VK_DOWN: SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0); return 0; } break; case WM_CHAR: switch(wParam) { case MENU_FIRST_PAGE: SendMessage(hWnd, EM_SCROLL, SB_TOP, 0); return 0; case MENU_LAST_PAGE: SendMessage(hWnd, EM_SCROLL, SB_BOTTOM, 0); return 0; case MENU_NEXT_PAGE: SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); return 0; case MENU_PREVIOUS_PAGE: SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0); return 0; } break; /* edit control needs to know nothing of focus. We will take care of it * for it */ case WM_SETFOCUS: HideCaret(hWnd); return 0; } if (editControlWndProc) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } nethack-3.6.0/win/win32/mhtext.h0000664000076400007660000000070512536476415015375 0ustar paxedpaxed/* NetHack 3.6 mhtext.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINTextWindow_h #define MSWINTextWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_text_window(void); void mswin_display_text_window(HWND hwnd); #endif /* MSWINTextWindow_h */ nethack-3.6.0/win/win32/mnsel.uu0000664000076400007660000000031012467321052015361 0ustar paxedpaxedbegin 600 mnsel.bmp M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(` M`````````````````/___P```````````#_\```W_```,_P``"7\```F_``` D)WP``">\```_W```/^P``#_T```__```/_P````````````` ` end nethack-3.6.0/win/win32/mnselcnt.uu0000664000076400007660000000031312467321052016071 0ustar paxedpaxedbegin 600 mnselcnt.bmp M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(` M`````````````````/___P```````````#_\```__```.]P``#`,```[W``` D.]P``#O<```[W```,`P``#O<```__```/_P````````````` ` end nethack-3.6.0/win/win32/mnunsel.uu0000664000076400007660000000031212467321052015726 0ustar paxedpaxedbegin 600 mnunsel.bmp M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(` M`````````````````/___P```````````#_\```__```/_P``#_\```__``` D/_P``#_\```__```/_P``#_\```__```/_P````````````` ` end nethack-3.6.0/win/win32/mswproc.c0000664000076400007660000031562112631241231015535 0ustar paxedpaxed/* NetHack 3.6 mswproc.c $NHDT-Date: 1449116670 2015/12/03 04:24:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.94 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* * This file implements the interface between the window port specific * code in the mswin port and the rest of the nethack game engine. */ #include "hack.h" #include "dlb.h" #include "func_tab.h" /* for extended commands */ #include "winMS.h" #include #include "mhmap.h" #include "mhstatus.h" #include "mhtext.h" #include "mhmsgwnd.h" #include "mhmenu.h" #include "mhsplash.h" #include "mhmsg.h" #include "mhinput.h" #include "mhaskyn.h" #include "mhdlg.h" #include "mhrip.h" #include "mhmain.h" #include "mhfont.h" #include "resource.h" #define LLEN 128 #define NHTRACE_LOG "nhtrace.log" #ifdef DEBUG # ifdef _DEBUG static FILE* _s_debugfp = NULL; extern void logDebug(const char *fmt, ...); # endif #else void logDebug(const char *fmt, ...) { } #endif static void mswin_main_loop(void); static BOOL initMapTiles(void); static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr, COLORREF *colorptr); static void prompt_for_player_selection(void); #define TOTAL_BRUSHES 10 HBRUSH brush_table[TOTAL_BRUSHES]; int max_brush = 0; HBRUSH menu_bg_brush = NULL; HBRUSH menu_fg_brush = NULL; HBRUSH text_bg_brush = NULL; HBRUSH text_fg_brush = NULL; HBRUSH status_bg_brush = NULL; HBRUSH status_fg_brush = NULL; HBRUSH message_bg_brush = NULL; HBRUSH message_fg_brush = NULL; COLORREF menu_bg_color = RGB(0, 0, 0); COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF text_bg_color = RGB(0, 0, 0); COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF status_bg_color = RGB(0, 0, 0); COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF message_bg_color = RGB(0, 0, 0); COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF); /* Interface definition, for windows.c */ struct window_procs mswin_procs = { "MSWIN", WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN | WC_POPUP_DIALOG, 0L, mswin_init_nhwindows, mswin_player_selection, mswin_askname, mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows, mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow, mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr, genl_putmixed, mswin_display_file, mswin_start_menu, mswin_add_menu, mswin_end_menu, mswin_select_menu, genl_message_menu, /* no need for X-specific handling */ mswin_update_inventory, mswin_mark_synch, mswin_wait_synch, #ifdef CLIPPING mswin_cliparound, #endif #ifdef POSITIONBAR donull, #endif mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch, mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function, mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ mswin, mswin_change_background, #endif /* other defs that really should go away (they're tty specific) */ mswin_start_screen, mswin_end_screen, mswin_outrip, mswin_preference_update, mswin_getmsghistory, mswin_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT mswin_status_init, mswin_status_finish, mswin_status_enablefield, mswin_status_update, #ifdef STATUS_HILITES mswin_status_threshold, #endif #endif genl_can_suspend_yes, }; /* init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean */ void mswin_init_nhwindows(int *argc, char **argv) { UNREFERENCED_PARAMETER(argc); UNREFERENCED_PARAMETER(argv); #ifdef DEBUG # ifdef _DEBUG if (showdebug(NHTRACE_LOG) && !_s_debugfp) { /* truncate trace file */ _s_debugfp = fopen(NHTRACE_LOG, "w"); } # endif #endif logDebug("mswin_init_nhwindows()\n"); mswin_nh_input_init(); /* set it to WIN_ERR so we can detect attempts to use this ID before it is inialized */ WIN_MAP = WIN_ERR; /* Read Windows settings from the reqistry */ /* First set safe defaults */ GetNHApp()->regMainMinX = CW_USEDEFAULT; mswin_read_reg(); /* Create the main window */ GetNHApp()->hMainWnd = mswin_init_main_window(); if (!GetNHApp()->hMainWnd) { panic("Cannot create main window"); } /* Set menu check mark for interface mode */ mswin_menu_check_intf_mode(); /* check default values */ if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; if (iflags.wc_align_message == 0) iflags.wc_align_message = ALIGN_TOP; if (iflags.wc_align_status == 0) iflags.wc_align_status = ALIGN_BOTTOM; if (iflags.wc_scroll_margin == 0) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; if (iflags.wc_scroll_amount == 0) iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT; if (iflags.wc_tile_width == 0) iflags.wc_tile_width = TILE_X; if (iflags.wc_tile_height == 0) iflags.wc_tile_height = TILE_Y; if (iflags.wc_vary_msgcount == 0) iflags.wc_vary_msgcount = 4; /* force tabs in menus */ iflags.menu_tab_sep = 1; /* force toptenwin to be true. toptenwin is the option that decides * whether to * write output to a window or stdout. stdout doesn't make sense on * Windows * non-console applications */ iflags.toptenwin = 1; set_option_mod_status("toptenwin", SET_IN_FILE); set_option_mod_status("perm_invent", SET_IN_FILE); /* initialize map tiles bitmap */ initMapTiles(); /* set tile-related options to readonly */ set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE, DISP_IN_GAME); /* set font-related options to change in the game */ set_wc_option_mod_status( WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, SET_IN_GAME); mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush, &menu_fg_color); mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush, &message_fg_color); mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush, &status_fg_color); mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush, &text_fg_color); mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush, &menu_bg_color); mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush, &message_bg_color); mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush, &status_bg_color); mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush, &text_bg_color); if (iflags.wc_splash_screen) mswin_display_splash_window(FALSE); iflags.window_inited = TRUE; } /* Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. */ void mswin_player_selection(void) { int nRole; logDebug("mswin_player_selection()\n"); if (iflags.wc_player_selection == VIA_DIALOG) { /* pick player type randomly (use pre-selected * role/race/gender/alignment) */ if (flags.randomall) { if (flags.initrole < 0) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { raw_print("Incompatible role!"); flags.initrole = randrole(); } } if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { raw_print("Incompatible race!"); flags.initrace = randrace(flags.initrole); } } if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { raw_print("Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { raw_print("Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } } else { /* select a role */ if (mswin_player_selection_window(&nRole) == IDCANCEL) { bail(0); } } } else { /* iflags.wc_player_selection == VIA_PROMPTS */ prompt_for_player_selection(); } } void prompt_for_player_selection(void) { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; DWORD box_result; logDebug("prompt_for_player_selection()\n"); /* prevent an unnecessary prompt */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { /* int echoline; */ char *prompt = build_plselection_prompt( pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* tty_putstr(BASE_WINDOW, 0, ""); */ /* echoline = wins[BASE_WINDOW]->cury; */ box_result = NHMessageBox(NULL, prompt, MB_YESNOCANCEL | MB_DEFBUTTON1 | MB_ICONQUESTION); pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033'; /* tty_putstr(BASE_WINDOW, 0, prompt); */ do { /* pick4u = lowc(readchar()); */ if (index(quitchars, pick4u)) pick4u = 'y'; } while (!index(ynqchars, pick4u)); if ((int) strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, * pick4u); */ /* tty_putstr(BASE_WINDOW, 0, ""); */ } else /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ /* tty_clear_nhwindow(BASE_WINDOW) */; if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); bail((char *) 0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { char rolenamebuf[QBUFSZ]; /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */ flags.initrole = randrole(); } } else { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */ /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole() + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */ flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */ flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */ flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any = zeroany; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i + 1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM) + 1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace) + 1; add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i + 1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ /* tty_display_nhwindow(BASE_WINDOW, FALSE); */ } /* Ask the user for a player name. */ void mswin_askname(void) { logDebug("mswin_askname()\n"); if (mswin_getlin_window("Who are you?", plname, PL_NSIZ) == IDCANCEL) { bail("bye-bye"); /* not reached */ } } /* Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. */ void mswin_get_nh_event(void) { MSG msg; logDebug("mswin_get_nh_event()\n"); while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return; } /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ void mswin_exit_nhwindows(const char *str) { logDebug("mswin_exit_nhwindows(%s)\n", str); /* Write Window settings to the registry */ mswin_write_reg(); while (max_brush) DeleteObject(brush_table[--max_brush]); } /* Prepare the window to be suspended. */ void mswin_suspend_nhwindows(const char *str) { logDebug("mswin_suspend_nhwindows(%s)\n", str); return; } /* Restore the windows after being suspended. */ void mswin_resume_nhwindows() { logDebug("mswin_resume_nhwindows()\n"); return; } /* Create a window of type "type" which can be NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) */ winid mswin_create_nhwindow(int type) { winid i = 0; MSNHMsgAddWnd data; logDebug("mswin_create_nhwindow(%d)\n", type); /* Return the next available winid */ for (i = 1; i < MAXWINDOWS; i++) if (GetNHApp()->windowlist[i].win == NULL && !GetNHApp()->windowlist[i].dead) break; if (i == MAXWINDOWS) panic("ERROR: No windows available...\n"); switch (type) { case NHW_MAP: { GetNHApp()->windowlist[i].win = mswin_init_map_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MESSAGE: { GetNHApp()->windowlist[i].win = mswin_init_message_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_STATUS: { GetNHApp()->windowlist[i].win = mswin_init_status_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MENU: { GetNHApp()->windowlist[i].win = NULL; // will create later GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 1; break; } case NHW_TEXT: { GetNHApp()->windowlist[i].win = mswin_init_text_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } } ZeroMemory(&data, sizeof(data)); data.wid = i; SendMessage(GetNHApp()->hMainWnd, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ADDWND, (LPARAM) &data); return i; } /* Clear the given window, when asked to. */ void mswin_clear_nhwindow(winid wid) { logDebug("mswin_clear_nhwindow(%d)\n", wid); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { if (Is_rogue_level(&u.uz)) mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode); } SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CLEAR_WINDOW, (LPARAM) NULL); } } /* -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. */ void mswin_display_nhwindow(winid wid, BOOLEAN_P block) { logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block); if (GetNHApp()->windowlist[wid].win != NULL) { ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW); mswin_layout_main_window(GetNHApp()->windowlist[wid].win); if (GetNHApp()->windowlist[wid].type == NHW_MENU) { MENU_ITEM_P *p; mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p, TRUE); } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) { mswin_display_text_window(GetNHApp()->windowlist[wid].win); } if (GetNHApp()->windowlist[wid].type == NHW_RIP) { mswin_display_RIP_window(GetNHApp()->windowlist[wid].win); } else { if (!block) { UpdateWindow(GetNHApp()->windowlist[wid].win); } else { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { (void) mswin_nhgetch(); } } } SetFocus(GetNHApp()->hMainWnd); } } HWND mswin_hwnd_from_winid(winid wid) { if (wid >= 0 && wid < MAXWINDOWS) { return GetNHApp()->windowlist[wid].win; } else { return NULL; } } winid mswin_winid_from_handle(HWND hWnd) { winid i = 0; for (i = 1; i < MAXWINDOWS; i++) if (GetNHApp()->windowlist[i].win == hWnd) return i; return -1; } winid mswin_winid_from_type(int type) { winid i = 0; for (i = 1; i < MAXWINDOWS; i++) if (GetNHApp()->windowlist[i].type == type) return i; return -1; } void mswin_window_mark_dead(winid wid) { if (wid >= 0 && wid < MAXWINDOWS) { GetNHApp()->windowlist[wid].win = NULL; GetNHApp()->windowlist[wid].dead = 1; } } /* Destroy will dismiss the window if the window has not * already been dismissed. */ void mswin_destroy_nhwindow(winid wid) { logDebug("mswin_destroy_nhwindow(%d)\n", wid); if ((GetNHApp()->windowlist[wid].type == NHW_MAP) || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) { /* main windows is going to take care of those */ return; } if (wid != -1) { if (!GetNHApp()->windowlist[wid].dead && GetNHApp()->windowlist[wid].win != NULL) DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = NULL; GetNHApp()->windowlist[wid].type = 0; GetNHApp()->windowlist[wid].dead = 0; } } /* Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. */ void mswin_curs(winid wid, int x, int y) { logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgCursor data; data.x = x; data.y = y; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CURSOR, (LPARAM) &data); } } /* putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. */ void mswin_putstr(winid wid, int attr, const char *text) { logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text); mswin_putstr_ex(wid, attr, text, 0); } void mswin_putstr_ex(winid wid, int attr, const char *text, int app) { if ((wid >= 0) && (wid < MAXWINDOWS)) { if (GetNHApp()->windowlist[wid].win == NULL && GetNHApp()->windowlist[wid].type == NHW_MENU) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT); GetNHApp()->windowlist[wid].dead = 0; } if (GetNHApp()->windowlist[wid].win != NULL) { MSNHMsgPutstr data; ZeroMemory(&data, sizeof(data)); data.attr = attr; data.text = text; data.append = app; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_PUTSTR, (LPARAM) &data); } /* yield a bit so it gets done immediately */ mswin_get_nh_event(); } else { // build text to display later in message box GetNHApp()->saved_text = realloc(GetNHApp()->saved_text, strlen(text) + strlen(GetNHApp()->saved_text) + 1); strcat(GetNHApp()->saved_text, text); } } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void mswin_display_file(const char *filename, BOOLEAN_P must_exist) { dlb *f; TCHAR wbuf[BUFSZ]; logDebug("mswin_display_file(%s, %d)\n", filename, must_exist); f = dlb_fopen(filename, RDTMODE); if (!f) { if (must_exist) { TCHAR message[90]; _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf))); NHMessageBox(GetNHApp()->hMainWnd, message, MB_OK | MB_ICONEXCLAMATION); } } else { winid text; char line[LLEN]; text = mswin_create_nhwindow(NHW_TEXT); while (dlb_fgets(line, LLEN, f)) { size_t len; len = strlen(line); if (line[len - 1] == '\n') line[len - 1] = '\x0'; mswin_putstr(text, ATR_NONE, line); } (void) dlb_fclose(f); mswin_display_nhwindow(text, 1); mswin_destroy_nhwindow(text); } } /* Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. */ void mswin_start_menu(winid wid) { logDebug("mswin_start_menu(%d)\n", wid); if ((wid >= 0) && (wid < MAXWINDOWS)) { if (GetNHApp()->windowlist[wid].win == NULL && GetNHApp()->windowlist[wid].type == NHW_MENU) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU); GetNHApp()->windowlist[wid].dead = 0; } if (GetNHApp()->windowlist[wid].win != NULL) { SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_STARTMENU, (LPARAM) NULL); } } } /* add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. */ void mswin_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph, identifier, (char) accelerator, (char) group_accel, attr, str, presel); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgAddMenu data; ZeroMemory(&data, sizeof(data)); data.glyph = glyph; data.identifier = identifier; data.accelerator = accelerator; data.group_accel = group_accel; data.attr = attr; data.str = str; data.presel = presel; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data); } } /* end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean */ void mswin_end_menu(winid wid, const char *prompt) { logDebug("mswin_end_menu(%d, %s)\n", wid, prompt); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgEndMenu data; ZeroMemory(&data, sizeof(data)); data.text = prompt; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_ENDMENU, (LPARAM) &data); } } /* int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_N, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. */ int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) { int nReturned = -1; logDebug("mswin_select_menu(%d, %d)\n", wid, how); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW); nReturned = mswin_menu_window_select_menu( GetNHApp()->windowlist[wid].win, how, selected, !(flags.perm_invent && wid == WIN_INVEN && how == PICK_NONE) /* don't activate inventory window if perm_invent is on */ ); } return nReturned; } /* -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. */ void mswin_update_inventory() { logDebug("mswin_update_inventory()\n"); if (flags.perm_invent && program_state.something_worth_saving && iflags.window_inited && WIN_INVEN != WIN_ERR) display_inventory(NULL, FALSE); } /* mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment */ void mswin_mark_synch() { logDebug("mswin_mark_synch()\n"); } /* wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). */ void mswin_wait_synch() { logDebug("mswin_wait_synch()\n"); } /* cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. */ void mswin_cliparound(int x, int y) { winid wid = WIN_MAP; logDebug("mswin_cliparound(%d, %d)\n", x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgClipAround data; data.x = x; data.y = y; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CLIPAROUND, (LPARAM) &data); } } /* print_glyph(window, x, y, glyph, bkglyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). -- bkglyph is a background glyph for potential use by some graphical or tiled environments to allow the depiction to fall against a background consistent with the grid around x,y. */ void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) { logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgPrintGlyph data; ZeroMemory(&data, sizeof(data)); data.x = x; data.y = y; data.glyph = glyph; data.bkglyph = bkglyph; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data); } } /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). */ void mswin_raw_print(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print(%s)\n", str); if (str && *str) { extern int redirect_stdout; if (!redirect_stdout) NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), MB_ICONINFORMATION | MB_OK); else fprintf(stdout, "%s", str); } } /* raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). */ void mswin_raw_print_bold(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print_bold(%s)\n", str); if (str && *str) NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), MB_ICONINFORMATION | MB_OK); } /* int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero. */ int mswin_nhgetch() { PMSNHEvent event; int key = 0; logDebug("mswin_nhgetch()\n"); while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR) mswin_main_loop(); key = event->kbd.ch; return (key); } /* int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 -- mouse click type 1 CLICK_2 -- mouse click type 2 The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. */ int mswin_nh_poskey(int *x, int *y, int *mod) { PMSNHEvent event; int key; logDebug("mswin_nh_poskey()\n"); while ((event = mswin_input_pop()) == NULL) mswin_main_loop(); if (event->type == NHEVENT_MOUSE) { *mod = event->ms.mod; *x = event->ms.x; *y = event->ms.y; key = 0; } else { key = event->kbd.ch; } return (key); } /* nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void mswin_nhbell() { logDebug("mswin_nhbell()\n"); } /* doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int mswin_doprev_message() { logDebug("mswin_doprev_message()\n"); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL); return 0; } /* char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. */ char mswin_yn_function(const char *question, const char *choices, CHAR_P def) { char ch; char yn_esc_map = '\033'; char message[BUFSZ]; char res_ch[2]; int createcaret; boolean digit_ok, allow_num; logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def); if (WIN_MESSAGE == WIN_ERR && choices == ynchars) { char *text = realloc(strdup(GetNHApp()->saved_text), strlen(question) + strlen(GetNHApp()->saved_text) + 1); DWORD box_result; strcat(text, question); box_result = NHMessageBox(NULL, NH_W2A(text, message, sizeof(message)), MB_ICONQUESTION | MB_YESNOCANCEL | ((def == 'y') ? MB_DEFBUTTON1 : (def == 'n') ? MB_DEFBUTTON2 : MB_DEFBUTTON3)); free(text); GetNHApp()->saved_text = strdup(""); return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033'; } if (choices) { char *cb, choicebuf[QBUFSZ]; allow_num = (index(choices, '#') != 0); Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } (void) strncpy(message, question, QBUFSZ - 1); message[QBUFSZ - 1] = '\0'; sprintf(eos(message), " [%s]", choicebuf); if (def) sprintf(eos(message), " (%c)", def); Strcat(message, " "); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); Strcat(message, " "); } createcaret = 1; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); mswin_clear_nhwindow(WIN_MESSAGE); mswin_putstr(WIN_MESSAGE, ATR_BOLD, message); /* Only here if main window is not present */ ch = 0; do { ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); ch = mswin_nhgetch(); HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); if (choices) ch = lowc(ch); else break; /* If choices is NULL, all possible inputs are accepted and returned. */ digit_ok = allow_num && digit(ch); if (ch == '\033') { if (index(choices, 'q')) ch = 'q'; else if (index(choices, 'n')) ch = 'n'; else ch = def; break; } else if (index(quitchars, ch)) { ch = def; break; } else if (!index(choices, ch) && !digit_ok) { mswin_nhbell(); ch = (char) 0; /* and try again... */ } else if (ch == '#' || digit_ok) { char z, digit_string[2]; int n_len = 0; long value = 0; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1); n_len++; digit_string[1] = '\0'; if (ch != '#') { digit_string[0] = ch; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++; value = ch - '0'; ch = '#'; } do { /* loop until we get a non-digit */ z = lowc(readchar()); if (digit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++; } else if (z == 'y' || index(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ } else if (z == '\b') { if (n_len <= 1) { value = -1; break; } else { value /= 10; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -1); n_len--; } } else { value = -1; /* abort */ mswin_nhbell(); break; } } while (z != '\n'); if (value > 0) yn_number = value; else if (value == 0) ch = 'n'; /* 0 => "no" */ else { /* remove number from top line, then try again */ mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len); n_len = 0; ch = (char) 0; } } } while (!ch); createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); /* display selection in the message window */ if (isprint(ch) && ch != '#') { res_ch[0] = ch; res_ch[1] = '\x0'; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1); } return ch; } /* getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. */ void mswin_getlin(const char *question, char *input) { logDebug("mswin_getlin(%s, %p)\n", question, input); if (!iflags.wc_popup_dialog) { char c; int len; int done; int createcaret; createcaret = 1; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); mswin_clear_nhwindow(WIN_MESSAGE); mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0); mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1); input[0] = '\0'; len = 0; ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); done = FALSE; while (!done) { c = mswin_nhgetch(); switch (c) { case VK_ESCAPE: strcpy(input, "\033"); done = TRUE; break; case '\n': case '\r': case -115: done = TRUE; break; default: if (input[0]) mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len); if (c == VK_BACK) { if (len > 0) len--; input[len] = '\0'; } else { input[len++] = c; input[len] = '\0'; } mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1); break; } } HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); } else { if (mswin_getlin_window(question, input, BUFSZ) == IDCANCEL) { strcpy(input, "\033"); } } } /* int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. */ int mswin_get_ext_cmd() { int ret; logDebug("mswin_get_ext_cmd()\n"); if (!iflags.wc_popup_dialog) { char c; char cmd[BUFSZ]; int i, len; int createcaret; createcaret = 1; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); cmd[0] = '\0'; i = -2; mswin_clear_nhwindow(WIN_MESSAGE); mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0); len = 0; ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); while (i == -2) { int oindex, com_index; c = mswin_nhgetch(); switch (c) { case VK_ESCAPE: i = -1; break; case '\n': case '\r': case -115: for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++) if (!strcmpi(cmd, extcmdlist[i].ef_txt)) break; if (extcmdlist[i].ef_txt == (char *) 0) { pline("%s: unknown extended command.", cmd); i = -1; } break; default: if (cmd[0]) mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, -(int) strlen(cmd)); if (c == VK_BACK) { if (len > 0) len--; cmd[len] = '\0'; } else { cmd[len++] = c; cmd[len] = '\0'; /* Find a command with this prefix in extcmdlist */ com_index = -1; for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0; oindex++) { if (!strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) { if (com_index == -1) /* no matches yet */ com_index = oindex; else com_index = -2; /* two matches, don't complete */ } } if (com_index >= 0) { Strcpy(cmd, extcmdlist[com_index].ef_txt); } } mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1); break; } } HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); return i; } else { if (mswin_ext_cmd_window(&ret) == IDCANCEL) return -1; else return ret; } } /* number_pad(state) -- Initialize the number pad to the given state. */ void mswin_number_pad(int state) { /* Do Nothing */ logDebug("mswin_number_pad(%d)\n", state); } /* delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. */ void mswin_delay_output() { logDebug("mswin_delay_output()\n"); Sleep(50); } void mswin_change_color() { logDebug("mswin_change_color()\n"); } char * mswin_get_color_string() { logDebug("mswin_get_color_string()\n"); return (""); } /* start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. */ void mswin_start_screen() { /* Do Nothing */ logDebug("mswin_start_screen()\n"); } /* end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). */ void mswin_end_screen() { /* Do Nothing */ logDebug("mswin_end_screen()\n"); } /* outrip(winid, int, when) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. */ #define STONE_LINE_LEN 16 void mswin_outrip(winid wid, int how, time_t when) { char buf[BUFSZ]; long year; logDebug("mswin_outrip(%d, %d, %ld)\n", wid, how, (long) when); if ((wid >= 0) && (wid < MAXWINDOWS)) { DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = mswin_init_RIP_window(); GetNHApp()->windowlist[wid].type = NHW_RIP; GetNHApp()->windowlist[wid].dead = 0; } /* Put name on stone */ Sprintf(buf, "%s", plname); buf[STONE_LINE_LEN] = 0; putstr(wid, 0, buf); /* Put $ on stone */ Sprintf(buf, "%ld Au", done_money); buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ putstr(wid, 0, buf); /* Put together death description */ formatkiller(buf, sizeof buf, how); /* Put death type on stone */ putstr(wid, 0, buf); /* Put year on stone */ year = yyyymmdd(when) / 10000L; Sprintf(buf, "%4ld", year); putstr(wid, 0, buf); mswin_finish_rip_text(wid); } /* handle options updates here */ void mswin_preference_update(const char *pref) { HDC hdc; int i; if (stricmp(pref, "font_menu") == 0 || stricmp(pref, "font_size_menu") == 0) { if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if (stricmp(pref, "font_status") == 0 || stricmp(pref, "font_size_status") == 0) { if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); for (i = 1; i < MAXWINDOWS; i++) { if (GetNHApp()->windowlist[i].type == NHW_STATUS && GetNHApp()->windowlist[i].win != NULL) { InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE); } } mswin_layout_main_window(NULL); return; } if (stricmp(pref, "font_message") == 0 || stricmp(pref, "font_size_message") == 0) { if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE); mswin_layout_main_window(NULL); return; } if (stricmp(pref, "font_text") == 0 || stricmp(pref, "font_size_text") == 0) { if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if (stricmp(pref, "scroll_amount") == 0) { mswin_cliparound(u.ux, u.uy); return; } if (stricmp(pref, "scroll_margin") == 0) { mswin_cliparound(u.ux, u.uy); return; } if (stricmp(pref, "map_mode") == 0) { mswin_select_map_mode(iflags.wc_map_mode); return; } if (stricmp(pref, "hilite_pet") == 0) { InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE); return; } if (stricmp(pref, "align_message") == 0 || stricmp(pref, "align_status") == 0) { mswin_layout_main_window(NULL); return; } if (stricmp(pref, "vary_msgcount") == 0) { InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE); mswin_layout_main_window(NULL); return; } } #define TEXT_BUFFER_SIZE 4096 char * mswin_getmsghistory(BOOLEAN_P init) { static PMSNHMsgGetText text = 0; static char *next_message = 0; if (init) { text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); text->max_size = TEXT_BUFFER_SIZE - 1; /* make sure we always have 0 at the end of the buffer */ ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); next_message = text->buffer; } if (!(next_message && next_message[0])) { free(text); next_message = 0; return (char *) 0; } else { char *retval = next_message; char *p; next_message = p = strchr(next_message, '\n'); if (next_message) next_message++; if (p) while (p >= retval && isspace(*p)) *p-- = (char) 0; /* delete trailing whitespace */ return retval; } } void mswin_putmsghistory(const char *msg, BOOLEAN_P restoring) { BOOL save_sound_opt; UNREFERENCED_PARAMETER(restoring); if (!msg) return; /* end of message history restore */ save_sound_opt = GetNHApp()->bNoSounds; GetNHApp()->bNoSounds = TRUE; /* disable sounds while restoring message history */ mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, msg, 0); clear_nhwindow(WIN_MESSAGE); /* it is in fact end-of-turn indication so each message will print on the new line */ GetNHApp()->bNoSounds = save_sound_opt; /* restore sounds option */ } void mswin_main_loop() { MSG msg; while (!mswin_have_input() && GetMessage(&msg, NULL, 0, 0) != 0) { if (GetNHApp()->regNetHackMode || !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /* clean up and quit */ void bail(const char *mesg) { clearlocks(); mswin_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } BOOL initMapTiles(void) { HBITMAP hBmp; BITMAP bm; TCHAR wbuf[MAX_PATH]; int tl_num; SIZE map_size; extern int total_tiles_used; /* no file - no tile */ if (!(iflags.wc_tile_file && *iflags.wc_tile_file)) return TRUE; /* load bitmap */ hBmp = LoadImage(GetNHApp()->hApp, NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); if (hBmp == NULL) { raw_print( "Cannot load tiles from the file. Reverting back to default."); return FALSE; } /* calculate tile dimensions */ GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bm); if (bm.bmWidth % iflags.wc_tile_width || bm.bmHeight % iflags.wc_tile_height) { DeleteObject(hBmp); raw_print("Tiles bitmap does not match tile_width and tile_height " "options. Reverting back to default."); return FALSE; } tl_num = (bm.bmWidth / iflags.wc_tile_width) * (bm.bmHeight / iflags.wc_tile_height); if (tl_num < total_tiles_used) { DeleteObject(hBmp); raw_print("Number of tiles in the bitmap is less than required by " "the game. Reverting back to default."); return FALSE; } /* set the tile information */ if (GetNHApp()->bmpMapTiles != GetNHApp()->bmpTiles) { DeleteObject(GetNHApp()->bmpMapTiles); } GetNHApp()->bmpMapTiles = hBmp; GetNHApp()->mapTile_X = iflags.wc_tile_width; GetNHApp()->mapTile_Y = iflags.wc_tile_height; GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width; map_size.cx = GetNHApp()->mapTile_X * COLNO; map_size.cy = GetNHApp()->mapTile_Y * ROWNO; mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE); return TRUE; } void mswin_popup_display(HWND hWnd, int *done_indicator) { MSG msg; HWND hChild; HMENU hMenu; int mi_count; int i; /* activate the menu window */ GetNHApp()->hPopupWnd = hWnd; mswin_layout_main_window(hWnd); /* disable game windows */ for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT)) { if (hChild != hWnd) EnableWindow(hChild, FALSE); } /* disable menu */ hMenu = GetMenu(GetNHApp()->hMainWnd); mi_count = GetMenuItemCount(hMenu); for (i = 0; i < mi_count; i++) { EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_GRAYED); } DrawMenuBar(GetNHApp()->hMainWnd); /* bring menu window on top */ SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); SetFocus(hWnd); /* go into message loop */ while (IsWindow(hWnd) && (done_indicator == NULL || !*done_indicator) && GetMessage(&msg, NULL, 0, 0) != 0) { if (!IsDialogMessage(hWnd, &msg)) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } void mswin_popup_destroy(HWND hWnd) { HWND hChild; HMENU hMenu; int mi_count; int i; /* enable game windows */ for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT)) { if (hChild != hWnd) { EnableWindow(hChild, TRUE); } } /* enable menu */ hMenu = GetMenu(GetNHApp()->hMainWnd); mi_count = GetMenuItemCount(hMenu); for (i = 0; i < mi_count; i++) { EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_ENABLED); } DrawMenuBar(GetNHApp()->hMainWnd); ShowWindow(hWnd, SW_HIDE); GetNHApp()->hPopupWnd = NULL; mswin_layout_main_window(hWnd); SetFocus(GetNHApp()->hMainWnd); } #ifdef DEBUG # ifdef _DEBUG #include void logDebug(const char *fmt, ...) { va_list args; if (!showdebug(NHTRACE_LOG) || !_s_debugfp) return; va_start(args, fmt); vfprintf(_s_debugfp, fmt, args); va_end(args); fflush(_s_debugfp); } # endif #endif /* Reading and writing settings from the registry. */ #define CATEGORYKEY "Software" #define COMPANYKEY "NetHack" #define PRODUCTKEY "NetHack 3.6.0" #define SETTINGSKEY "Settings" #define MAINSHOWSTATEKEY "MainShowState" #define MAINMINXKEY "MainMinX" #define MAINMINYKEY "MainMinY" #define MAINMAXXKEY "MainMaxX" #define MAINMAXYKEY "MainMaxY" #define MAINLEFTKEY "MainLeft" #define MAINRIGHTKEY "MainRight" #define MAINTOPKEY "MainTop" #define MAINBOTTOMKEY "MainBottom" #define MAINAUTOLAYOUT "AutoLayout" #define MAPLEFT "MapLeft" #define MAPRIGHT "MapRight" #define MAPTOP "MapTop" #define MAPBOTTOM "MapBottom" #define MSGLEFT "MsgLeft" #define MSGRIGHT "MsgRight" #define MSGTOP "MsgTop" #define MSGBOTTOM "MsgBottom" #define STATUSLEFT "StatusLeft" #define STATUSRIGHT "StatusRight" #define STATUSTOP "StatusTop" #define STATUSBOTTOM "StatusBottom" #define MENULEFT "MenuLeft" #define MENURIGHT "MenuRight" #define MENUTOP "MenuTop" #define MENUBOTTOM "MenuBottom" #define TEXTLEFT "TextLeft" #define TEXTRIGHT "TextRight" #define TEXTTOP "TextTop" #define TEXTBOTTOM "TextBottom" #define INVENTLEFT "InventLeft" #define INVENTRIGHT "InventRight" #define INVENTTOP "InventTop" #define INVENTBOTTOM "InventBottom" /* #define all the subkeys here */ #define INTFKEY "Interface" void mswin_read_reg() { HKEY key; DWORD size; DWORD safe_buf; char keystring[MAX_PATH]; sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY); /* Set the defaults here. The very first time the app is started, nothing is read from the registry, so these defaults apply. */ GetNHApp()->saveRegistrySettings = 1; /* Normally, we always save */ GetNHApp()->regNetHackMode = 0; if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key) != ERROR_SUCCESS) return; size = sizeof(DWORD); #define NHGETREG_DWORD(name, val) \ RegQueryValueEx(key, (name), 0, NULL, (unsigned char *)(&safe_buf), \ &size); \ (val) = safe_buf; /* read the keys here */ NHGETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode); /* read window placement */ NHGETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState); NHGETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX); NHGETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY); NHGETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX); NHGETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY); NHGETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft); NHGETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight); NHGETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop); NHGETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom); NHGETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout); NHGETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left); NHGETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right); NHGETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top); NHGETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom); NHGETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left); NHGETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right); NHGETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top); NHGETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom); NHGETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left); NHGETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right); NHGETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top); NHGETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom); NHGETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left); NHGETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right); NHGETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top); NHGETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom); NHGETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left); NHGETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right); NHGETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top); NHGETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom); NHGETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left); NHGETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right); NHGETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top); NHGETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom); #undef NHGETREG_DWORD RegCloseKey(key); /* check the data for validity */ if (IsRectEmpty(&GetNHApp()->rtMapWindow) || IsRectEmpty(&GetNHApp()->rtMsgWindow) || IsRectEmpty(&GetNHApp()->rtStatusWindow) || IsRectEmpty(&GetNHApp()->rtMenuWindow) || IsRectEmpty(&GetNHApp()->rtTextWindow) || IsRectEmpty(&GetNHApp()->rtInvenWindow)) { GetNHApp()->bAutoLayout = TRUE; } } void mswin_write_reg() { HKEY key; DWORD disposition; if (GetNHApp()->saveRegistrySettings) { char keystring[MAX_PATH]; DWORD safe_buf; sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY); if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key) != ERROR_SUCCESS) { RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &disposition); } #define NHSETREG_DWORD(name, val) \ RegSetValueEx(key, (name), 0, REG_DWORD, \ (unsigned char *)((safe_buf = (val)), &safe_buf), \ sizeof(DWORD)); /* Write the keys here */ NHSETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode); /* Main window placement */ NHSETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState); NHSETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX); NHSETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY); NHSETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX); NHSETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY); NHSETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft); NHSETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight); NHSETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop); NHSETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom); NHSETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout); NHSETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left); NHSETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right); NHSETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top); NHSETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom); NHSETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left); NHSETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right); NHSETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top); NHSETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom); NHSETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left); NHSETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right); NHSETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top); NHSETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom); NHSETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left); NHSETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right); NHSETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top); NHSETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom); NHSETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left); NHSETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right); NHSETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top); NHSETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom); NHSETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left); NHSETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right); NHSETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top); NHSETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom); #undef NHSETREG_DWORD RegCloseKey(key); } } void mswin_destroy_reg() { char keystring[MAX_PATH]; HKEY key; DWORD nrsubkeys; /* Delete keys one by one, as NT does not delete trees */ sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY); RegDeleteKey(HKEY_CURRENT_USER, keystring); sprintf(keystring, "%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY); RegDeleteKey(HKEY_CURRENT_USER, keystring); /* The company key will also contain information about newer versions of nethack (e.g. a subkey called NetHack 4.0), so only delete that if it's empty now. */ sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY); /* If we cannot open it, we probably cannot delete it either... Just go on and see what happens. */ RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key); nrsubkeys = 0; RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); RegCloseKey(key); if (nrsubkeys == 0) RegDeleteKey(HKEY_CURRENT_USER, keystring); /* Prevent saving on exit */ GetNHApp()->saveRegistrySettings = 0; } typedef struct ctv { const char *colorstring; COLORREF colorvalue; } color_table_value; /* * The color list here is a combination of: * NetHack colors. (See mhmap.c) * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 ) */ static color_table_value color_table[] = { /* NetHack colors */ { "black", RGB(0x55, 0x55, 0x55) }, { "red", RGB(0xFF, 0x00, 0x00) }, { "green", RGB(0x00, 0x80, 0x00) }, { "brown", RGB(0xA5, 0x2A, 0x2A) }, { "blue", RGB(0x00, 0x00, 0xFF) }, { "magenta", RGB(0xFF, 0x00, 0xFF) }, { "cyan", RGB(0x00, 0xFF, 0xFF) }, { "orange", RGB(0xFF, 0xA5, 0x00) }, { "brightgreen", RGB(0x00, 0xFF, 0x00) }, { "yellow", RGB(0xFF, 0xFF, 0x00) }, { "brightblue", RGB(0x00, 0xC0, 0xFF) }, { "brightmagenta", RGB(0xFF, 0x80, 0xFF) }, { "brightcyan", RGB(0x80, 0xFF, 0xFF) }, { "white", RGB(0xFF, 0xFF, 0xFF) }, /* Remaining HTML colors */ { "trueblack", RGB(0x00, 0x00, 0x00) }, { "gray", RGB(0x80, 0x80, 0x80) }, { "grey", RGB(0x80, 0x80, 0x80) }, { "purple", RGB(0x80, 0x00, 0x80) }, { "silver", RGB(0xC0, 0xC0, 0xC0) }, { "maroon", RGB(0x80, 0x00, 0x00) }, { "fuchsia", RGB(0xFF, 0x00, 0xFF) }, /* = NetHack magenta */ { "lime", RGB(0x00, 0xFF, 0x00) }, /* = NetHack bright green */ { "olive", RGB(0x80, 0x80, 0x00) }, { "navy", RGB(0x00, 0x00, 0x80) }, { "teal", RGB(0x00, 0x80, 0x80) }, { "aqua", RGB(0x00, 0xFF, 0xFF) }, /* = NetHack cyan */ { "", RGB(0x00, 0x00, 0x00) }, }; typedef struct ctbv { char *colorstring; int syscolorvalue; } color_table_brush_value; static color_table_brush_value color_table_brush[] = { { "activeborder", COLOR_ACTIVEBORDER }, { "activecaption", COLOR_ACTIVECAPTION }, { "appworkspace", COLOR_APPWORKSPACE }, { "background", COLOR_BACKGROUND }, { "btnface", COLOR_BTNFACE }, { "btnshadow", COLOR_BTNSHADOW }, { "btntext", COLOR_BTNTEXT }, { "captiontext", COLOR_CAPTIONTEXT }, { "graytext", COLOR_GRAYTEXT }, { "greytext", COLOR_GRAYTEXT }, { "highlight", COLOR_HIGHLIGHT }, { "highlighttext", COLOR_HIGHLIGHTTEXT }, { "inactiveborder", COLOR_INACTIVEBORDER }, { "inactivecaption", COLOR_INACTIVECAPTION }, { "menu", COLOR_MENU }, { "menutext", COLOR_MENUTEXT }, { "scrollbar", COLOR_SCROLLBAR }, { "window", COLOR_WINDOW }, { "windowframe", COLOR_WINDOWFRAME }, { "windowtext", COLOR_WINDOWTEXT }, { "", -1 }, }; static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr, COLORREF *colorptr) { color_table_value *ctv_ptr = color_table; color_table_brush_value *ctbv_ptr = color_table_brush; int red_value, blue_value, green_value; static char *hexadecimals = "0123456789abcdef"; if (colorstring == NULL) return; if (*colorstring == '#') { if (strlen(++colorstring) != 6) return; red_value = (int) (index(hexadecimals, tolower(*colorstring++)) - hexadecimals); red_value *= 16; red_value += (int) (index(hexadecimals, tolower(*colorstring++)) - hexadecimals); green_value = (int) (index(hexadecimals, tolower(*colorstring++)) - hexadecimals); green_value *= 16; green_value += (int) (index(hexadecimals, tolower(*colorstring++)) - hexadecimals); blue_value = (int) (index(hexadecimals, tolower(*colorstring++)) - hexadecimals); blue_value *= 16; blue_value += (int) (index(hexadecimals, tolower(*colorstring++)) - hexadecimals); *colorptr = RGB(red_value, green_value, blue_value); } else { while (*ctv_ptr->colorstring && stricmp(ctv_ptr->colorstring, colorstring)) ++ctv_ptr; if (*ctv_ptr->colorstring) { *colorptr = ctv_ptr->colorvalue; } else { while (*ctbv_ptr->colorstring && stricmp(ctbv_ptr->colorstring, colorstring)) ++ctbv_ptr; if (*ctbv_ptr->colorstring) { *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue); *colorptr = GetSysColor(ctbv_ptr->syscolorvalue); } } } if (max_brush > TOTAL_BRUSHES) panic("Too many colors!"); *brushptr = CreateSolidBrush(*colorptr); brush_table[max_brush++] = *brushptr; } void mswin_get_window_placement(int type, LPRECT rt) { switch (type) { case NHW_MAP: *rt = GetNHApp()->rtMapWindow; break; case NHW_MESSAGE: *rt = GetNHApp()->rtMsgWindow; break; case NHW_STATUS: *rt = GetNHApp()->rtStatusWindow; break; case NHW_MENU: *rt = GetNHApp()->rtMenuWindow; break; case NHW_TEXT: *rt = GetNHApp()->rtTextWindow; break; case NHW_INVEN: *rt = GetNHApp()->rtInvenWindow; break; default: SetRect(rt, 0, 0, 0, 0); break; } } void mswin_update_window_placement(int type, LPRECT rt) { LPRECT rt_conf = NULL; switch (type) { case NHW_MAP: rt_conf = &GetNHApp()->rtMapWindow; break; case NHW_MESSAGE: rt_conf = &GetNHApp()->rtMsgWindow; break; case NHW_STATUS: rt_conf = &GetNHApp()->rtStatusWindow; break; case NHW_MENU: rt_conf = &GetNHApp()->rtMenuWindow; break; case NHW_TEXT: rt_conf = &GetNHApp()->rtTextWindow; break; case NHW_INVEN: rt_conf = &GetNHApp()->rtInvenWindow; break; } if (rt_conf && !IsRectEmpty(rt) && !EqualRect(rt_conf, rt)) { *rt_conf = *rt; } } int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) { TCHAR title[MAX_LOADSTRING]; LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING); return MessageBox(hWnd, text, title, type); } #ifdef STATUS_VIA_WINDOWPORT static const char *_status_fieldnm[MAXBLSTATS]; static const char *_status_fieldfmt[MAXBLSTATS]; static char *_status_vals[MAXBLSTATS]; static int _status_colors[MAXBLSTATS]; static boolean _status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; #ifdef STATUS_HILITES typedef struct hilite_data_struct { int thresholdtype; anything threshold; int behavior; int under; int over; } hilite_data_t; static hilite_data_t _status_hilites[MAXBLSTATS]; #endif /* STATUS_HILITES */ /* status_init() -- core calls this to notify the window port that a status display is required. The window port should perform the necessary initialization in here, allocate memory, etc. */ void mswin_status_init(void) { int i; logDebug("mswin_status_init()\n"); for (i = 0; i < MAXBLSTATS; ++i) { _status_vals[i] = (char *) alloc(BUFSZ); *_status_vals[i] = '\0'; _status_activefields[i] = FALSE; _status_fieldfmt[i] = (const char *) 0; _status_colors[i] = CLR_MAX; /* no color */ #ifdef STATUS_HILITES _status_hilites[i].thresholdtype = 0; _status_hilites[i].behavior = BL_TH_NONE; _status_hilites[i].under = BL_HILITE_NONE; _status_hilites[i].over = BL_HILITE_NONE; #endif /* STATUS_HILITES */ } /* Use a window for the genl version; backward port compatibility */ WIN_STATUS = create_nhwindow(NHW_STATUS); display_nhwindow(WIN_STATUS, FALSE); } /* status_finish() -- called when it is time for the window port to tear down the status display and free allocated memory, etc. */ void mswin_status_finish(void) { /* tear down routine */ int i; logDebug("mswin_status_finish()\n"); /* free alloc'd memory here */ for (i = 0; i < MAXBLSTATS; ++i) { if (_status_vals[i]) free((genericptr_t) _status_vals[i]); _status_vals[i] = (char *) 0; } } /* status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable) -- notifies the window port which fields it is authorized to display. -- This may be called at any time, and is used to disable as well as enable fields, depending on the value of the final argument (TRUE = enable). -- fldindex could be one of the following from botl.h: BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION -- There are MAXBLSTATS status fields (from botl.h) */ void mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, boolean enable) { logDebug("mswin_status_enablefield(%d, %s, %s, %d)\n", fieldidx, nm, fmt, (int) enable); _status_fieldfmt[fieldidx] = fmt; _status_fieldnm[fieldidx] = nm; _status_activefields[fieldidx] = enable; } #ifdef STATUS_HILITES /* status_threshold(int fldidx, int threshholdtype, anything threshold, int behavior, int under, int over) -- called when a hiliting preference is added, changed, or removed. -- the fldindex identifies which field is having its hiliting preference set. It is an integer index value from botl.h -- fldindex could be any one of the following from botl.h: BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION -- datatype is P_INT, P_UINT, P_LONG, or P_MASK. -- threshold is an "anything" union which can contain the datatype value. -- behavior is used to define how threshold is used and can be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE, or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above or below the threshold. BL_TH_VAL_PERCENTAGE treats the threshold value as a precentage of the maximum possible value. BL_TH_VAL_ABSOLUTE means that the threshold is an actual value. BL_TH_UPDOWN means that threshold is not used, and the two below/above hilite values indicate how to display something going down (under) or rising (over). -- under is the hilite attribute used if value is below the threshold. The attribute can be BL_HILITE_NONE, BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). -- over is the hilite attribute used if value is at or above the threshold. The attribute can be BL_HILITE_NONE, BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). */ void mswin_status_threshold(int fldidx, int thresholdtype, anything threshold, int behavior, int under, int over) { logDebug("mswin_status_threshold(%d, %d, %d, %d, %d)\n", fldidx, thresholdtype, behavior, under, over); assert(fldidx >= 0 && fldidx < MAXBLSTATS); _status_hilites[fldidx].thresholdtype = thresholdtype; _status_hilites[fldidx].threshold = threshold; _status_hilites[fldidx].behavior = behavior; _status_hilites[fldidx].under = under; _status_hilites[fldidx].over = over; } #endif /* STATUS_HILITES */ /* status_update(int fldindex, genericptr_t ptr, int chg, int percentage) -- update the value of a status field. -- the fldindex identifies which field is changing and is an integer index value from botl.h -- fldindex could be any one of the following from botl.h: BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION -- fldindex could also be BL_FLUSH (-1), which is not really a field index, but is a special trigger to tell the windowport that it should redisplay all its status fields, even if no changes have been presented to it. -- ptr is usually a "char *", unless fldindex is BL_CONDITION. If fldindex is BL_CONDITION, then ptr is a long value with any or none of the following bits set (from botl.h): BL_MASK_BLIND 0x00000001L BL_MASK_CONF 0x00000002L BL_MASK_FOODPOIS 0x00000004L BL_MASK_ILL 0x00000008L BL_MASK_HALLU 0x00000010L BL_MASK_STUNNED 0x00000020L BL_MASK_SLIMED 0x00000040L -- The value passed for BL_GOLD includes a leading symbol for GOLD "$:nnn". If the window port needs to use the textual gold amount without the leading "$:" the port will have to add 2 to the passed "ptr" for the BL_GOLD case. */ void mswin_status_update(int idx, genericptr_t ptr, int chg, int percent) { long cond, *condptr = (long *) ptr; char *text = (char *) ptr; MSNHMsgUpdateStatus update_cmd_data; int ocolor, ochar; unsigned ospecial; long value = -1; logDebug("mswin_status_update(%d, %p, %d, %d)\n", idx, ptr, chg, percent); if (idx != BL_FLUSH) { if (!_status_activefields[idx]) return; switch (idx) { case BL_CONDITION: { cond = *condptr; *_status_vals[idx] = '\0'; if (cond & BL_MASK_BLIND) Strcat(_status_vals[idx], " Blind"); if (cond & BL_MASK_CONF) Strcat(_status_vals[idx], " Conf"); if (cond & BL_MASK_FOODPOIS) Strcat(_status_vals[idx], " FoodPois"); if (cond & BL_MASK_ILL) Strcat(_status_vals[idx], " Ill"); if (cond & BL_MASK_STUNNED) Strcat(_status_vals[idx], " Stun"); if (cond & BL_MASK_HALLU) Strcat(_status_vals[idx], " Hallu"); if (cond & BL_MASK_SLIMED) Strcat(_status_vals[idx], " Slime"); value = cond; } break; case BL_GOLD: { char buf[BUFSZ]; char *p; ZeroMemory(buf, sizeof(buf)); mapglyph(objnum_to_glyph(GOLD_PIECE), &ochar, &ocolor, &ospecial, 0, 0); buf[0] = ochar; p = strchr(text, ':'); if (p) { strncpy(buf + 1, p, sizeof(buf) - 2); value = atol(p + 1); } else { buf[1] = ':'; strncpy(buf + 2, text, sizeof(buf) - 2); value = atol(text); } Sprintf(_status_vals[idx], _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s", buf); } break; default: { value = atol(text); Sprintf(_status_vals[idx], _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s", text); } break; } } #ifdef STATUS_HILITES switch (_status_hilites[idx].behavior) { case BL_TH_NONE: { _status_colors[idx] = CLR_MAX; } break; case BL_TH_UPDOWN: { if (chg > 0) _status_colors[idx] = _status_hilites[idx].over; else if (chg < 0) _status_colors[idx] = _status_hilites[idx].under; else _status_colors[idx] = CLR_MAX; } break; case BL_TH_VAL_PERCENTAGE: { int pct_th = 0; if (_status_hilites[idx].thresholdtype != ANY_INT) { impossible("mswin_status_update: unsupported percentage " "threshold type %d", _status_hilites[idx].thresholdtype); break; } pct_th = _status_hilites[idx].threshold.a_int; _status_colors[idx] = (percent >= pct_th) ? _status_hilites[idx].over : _status_hilites[idx].under; } break; case BL_TH_VAL_ABSOLUTE: { int c = CLR_MAX; int o = _status_hilites[idx].over; int u = _status_hilites[idx].under; anything *t = &_status_hilites[idx].threshold; switch (_status_hilites[idx].thresholdtype) { case ANY_LONG: c = (value >= t->a_long) ? o : u; break; case ANY_INT: c = (value >= t->a_int) ? o : u; break; case ANY_UINT: c = ((unsigned long) value >= t->a_uint) ? o : u; break; case ANY_ULONG: c = ((unsigned long) value >= t->a_ulong) ? o : u; break; case ANY_MASK32: c = (value & t->a_ulong) ? o : u; break; default: impossible("mswin_status_update: unsupported absolute threshold " "type %d\n", _status_hilites[idx].thresholdtype); break; } _status_colors[idx] = c; } break; } #endif /* STATUS_HILITES */ /* send command to status window */ ZeroMemory(&update_cmd_data, sizeof(update_cmd_data)); update_cmd_data.n_fields = MAXBLSTATS; update_cmd_data.vals = _status_vals; update_cmd_data.activefields = _status_activefields; update_cmd_data.colors = _status_colors; SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_UPDATE_STATUS, (LPARAM) &update_cmd_data); } #endif /*STATUS_VIA_WINDOWPORT*/ nethack-3.6.0/win/win32/petmark.uu0000664000076400007660000000056012467321052015715 0ustar paxedpaxedbegin 600 petmark.bmp M0DWV`````````'8````H````$````!`````!``0``````(`````````````` M````````````;&Q'````_P```````("``(````"``(``@(```,#`P`#`W,`` M\,JF``0$!``("`@`#`P,`!$1$0`6%A8`'!P<```````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````````$````` 5````$1````````$1$0```````!`0 ` end nethack-3.6.0/win/win32/pilemark.uu0000664000076400007660000000056112541713002016050 0ustar paxedpaxedbegin 600 pilemark.bmp M0DWV`````````'8````H````$````!`````!``0``````(`````3"P``$PL` M`!`````0````;&Q'````_P```````("``(````"``(``@(```,#`P`#`W,`` M\,JF``0$!``("`@`#`P,`!$1$0`6%A8`'!P<```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````'````````<'````````!P````````=W=P 5````````<`````````!P```````` ` end nethack-3.6.0/win/win32/resource.h0000664000076400007660000001007512541713002015672 0ustar paxedpaxed//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by winhack.rc // #define IDC_MYICON 2 #define IDD_WINHACK_DIALOG 102 #define IDD_ABOUTBOX 103 #define IDS_APP_TITLE 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDS_HELLO 106 #define IDI_NETHACKW 107 #define IDC_NETHACKW 109 #define IDS_APP_TITLE_SHORT 110 #define IDR_MAINFRAME 128 #define IDB_TILES 129 #define IDD_TEXT 130 #define IDD_NHTEXT 130 #define IDD_MENU 132 #define IDB_MENU_SEL 133 #define IDB_MENU_UNSEL 134 #define IDD_COMMANDS 136 #define IDD_GETLIN 138 #define IDD_EXTCMD 139 #define IDD_PLAYER_SELECTOR 141 #define IDB_PETMARK 143 #define IDB_MENU_SEL_COUNT 144 #define IDD_NHRIP 145 #define IDB_SPLASH 146 #define IDB_RIP 147 #define IDD_SPLASH 148 #define IDB_PILEMARK 149 #define IDC_TEXT_VIEW 1000 #define IDC_TEXT_CONTROL 1000 #define IDC_CMD_MOVE_NW 1001 #define IDC_CMD_MOVE_N 1002 #define IDC_MENU_LIST 1003 #define IDC_CMD_MOVE_NE 1003 #define IDC_MENU_TEXT 1004 #define IDC_CMD_MOVE_W 1004 #define IDC_CMD_MOVE_SELF 1005 #define IDC_CMD_MOVE_E 1006 #define IDC_CMD_MOVE_SW 1007 #define IDC_CMD_MOVE_S 1008 #define IDC_CMD_MOVE_SE 1009 #define IDC_CMD_MOVE_UP 1010 #define IDC_CMD_MOVE_DOWN 1011 #define IDC_CMD_5 1012 #define IDC_CMD_A 1013 #define IDC_CMD_B 1014 #define IDC_CMD_C 1015 #define IDC_CMD_D 1016 #define IDC_CMD_E 1017 #define IDC_CMD_F 1018 #define IDC_CMD_G 1019 #define IDC_CMD_H 1020 #define IDC_CMD_I 1021 #define IDC_CMD_J 1022 #define IDC_CMD_K 1023 #define IDC_CMD_L 1024 #define IDC_CMD_M 1025 #define IDC_CMD_N 1026 #define IDC_CMD_O 1027 #define IDC_CMD_P 1028 #define IDC_CMD_Q 1029 #define IDC_CMD_R 1030 #define IDC_CMD_S 1031 #define IDC_CMD_T 1032 #define IDC_CMD_U 1033 #define IDC_CMD_V 1034 #define IDC_CMD_W 1035 #define IDC_CMD_X 1036 #define IDC_CMD_Y 1037 #define IDC_CMD_Z 1038 #define IDC_CMD_AA 1039 #define IDC_CMD_BB 1040 #define IDC_CMD_CC 1041 #define IDC_CMD_DD 1042 #define IDC_CMD_EE 1043 #define IDC_CMD_FF 1044 #define IDC_CMD_GG 1045 #define IDC_CMD_HH 1046 #define IDC_CMD_II 1047 #define IDC_CMD_JJ 1048 #define IDC_CMD_KK 1049 #define IDC_CMD_LL 1050 #define IDC_CMD_MM 1051 #define IDC_CMD_NN 1052 #define IDC_CMD_OO 1053 #define IDC_CMD_PP 1054 #define IDC_CMD_QQ 1055 #define IDC_CMD_RR 1056 #define IDC_CMD_SS 1057 #define IDC_CMD_TT 1058 #define IDC_CMD_UU 1059 #define IDC_CMD_VV 1060 #define IDC_CMD_WW 1061 #define IDC_CMD_XX 1062 #define IDC_CMD_YY 1063 #define IDC_CMD_ZZ 1064 #define IDC_CMD_FIRST 1100 #define IDC_CMD_LAST 1300 #define IDC_GETLIN_EDIT 1309 #define IDC_EXTCMD_LIST 1310 #define IDC_PLSEL_NAME 1314 #define IDC_PLSEL_ROLE_RANDOM 1315 #define IDC_PLSEL_RACE_RANDOM 1318 #define IDC_PLSEL_GENDER_RANDOM 1319 #define IDC_PLSEL_ALIGN_RANDOM 1320 #define IDC_PLSEL_ROLE_LIST 1323 #define IDC_PLSEL_RACE_LIST 1324 #define IDC_PLSEL_ALIGN_LIST 1325 #define IDC_PLSEL_GENDER_LIST 1326 #define IDC_ABOUT_VERSION 1327 #define IDC_ABOUT_COPYRIGHT 1328 #define IDC_EXTRAINFO 1331 #define IDM_SAVE 32771 #define IDM_HELP_LONG 32772 #define IDM_HELP_COMMANDS 32773 #define IDM_HELP_HISTORY 32774 #define IDM_HELP_INFO_CHAR 32775 #define IDM_HELP_INFO_KEY 32776 #define IDM_HELP_OPTIONS 32777 #define IDM_HELP_OPTIONS_LONG 32778 #define IDM_HELP_EXTCMD 32779 #define IDM_HELP_LICENSE 32780 #define IDM_HELP_PORTHELP 32781 #define IDM_MAP_TILES 32782 #define IDM_MAP_ASCII4X6 32783 #define IDM_MAP_ASCII6X8 32784 #define IDM_MAP_ASCII8X8 32785 #define IDM_MAP_ASCII16X8 32786 #define IDM_MAP_ASCII7X12 32787 #define IDM_MAP_ASCII8X12 32788 #define IDM_MAP_ASCII16X12 32789 #define IDM_MAP_ASCII12X16 32790 #define IDM_MAP_ASCII10X18 32791 #define IDM_MAP_FIT_TO_SCREEN 32792 #define IDM_NHMODE 32794 #define IDM_CLEARSETTINGS 32795 #define IDM_SETTING_AUTOLAYOUT 32796 #define IDM_SETTING_LOCKWINDOWS 32797 #define IDM_SETTING_SCREEN_TO_CLIPBOARD 32798 #define IDM_SETTING_SCREEN_TO_FILE 32799 #define IDC_STATIC -1 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 145 #define _APS_NEXT_COMMAND_VALUE 32800 #define _APS_NEXT_CONTROL_VALUE 1332 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif nethack-3.6.0/win/win32/rip.uu0000664000076400007660000033216412467321052015054 0ustar paxedpaxedbegin 600 rip.bmp M0DVV/`$``````#8$```H````D`$``,@````!``@``````(`X`0`2"P``$@L` M```!`````0``+C8V`$9!00`Q+R\`(S4U``)'`P`*+A4`'C$P`"LI*0`1-2,` M&B(B`**FI@`X.CH`:W1U`!0:&0!X?G\`#1(2`!,G'P`*,Q8``3X#`!88&``! M.@,``C@$`!06%@!-1D8`)20D``H,#``,%14`145%`#=+2P`/,!\`#RX?`#\_ M/P`]/3T`%1L;``TN&@"#AX@`+2TM`"DI*0![?X``$R\G`#0Q,0!634T`#A@8 M`+&TM`"2F)@`(28E`(J0D``8'!P`?8*#`&1L;0`?("``8FP`)"GZ=`+"8 MJ``I1<8`559;`,"RM0!(7,@`#@\0`%EOO`!_E\\`5B@>`#4_0`!_;WX`04F- M`')P<@#5U-X`SVQ$`*FMKP"B/R<`?HF\`-?+S0#V_?X`XO+T`.#@YP#.VMT` MX^KK`+-9/`"BAYD`)T2E`$AM@@#___\`,4)F`,3$T@!C?<``+#-K````0``` M`(````"@````P````.````#_``!`````0$```$"```!`H```0,```$#@``!` M_P``@````(!```"`@```@*```(#```"`X```@/\``*````"@0```H(```*"@ M``"@P```H.```*#_``#`````P$```,"```#`H```P,```,#@``#`_P``X``` M`.!```#@@```X*```.#```#@X```X/\``/\```#_0```_X```/^@``#_P``` M_^```/__`$````!``$``0`"``$``H`!``,``0`#@`$``_P!`0```0$!``$!` M@`!`0*``0$#``$!`X`!`0/\`0(```$"`0`!`@(``0("@`$"`P`!`@.``0(#_ M`$"@``!`H$``0*"``$"@H`!`H,``0*#@`$"@_P!`P```0,!``$#`@`!`P*`` M0,#``$#`X`!`P/\`0.```$#@0`!`X(``0."@`$#@P`!`X.``0.#_`$#_``!` M_T``0/^``$#_H`!`_\``0/_@`$#__P"`````@`!``(``@`"``*``@`#``(`` MX`"``/\`@$```(!`0`"`0(``@$"@`(!`P`"`0.``@$#_`("```"`@$``@("` M`("`H`"`@,``@(#@`("`_P"`H```@*!``("@@`"`H*``@*#``("@X`"`H/\` M@,```(#`0`"`P(``@,"@`(#`P`"`P.``@,#_`(#@``"`X$``@."``(#@H`"` MX,``@.#@`(#@_P"`_P``@/]``(#_@`"`_Z``@/_``(#_X`"`__\`P````,`` M0`#``(``P`"@`,``P`#``.``P`#_`,!```#`0$``P$"``,!`H`#`0,``P$#@ M`,!`_P#`@```P(!``,"`@`#`@*``P(#``,"`X`#`@/\`P*```,"@0`#`H(`` MP*"@`,"@P`#`H.``P*#_`,#```#`P$``P,"``,#`H`#`P,``P,#@`,#`_P#` MX```P.!``,#@@`#`X*``P.#``,#@X`#`X/\`P/\``,#_0`#`_X``P/^@```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````(:(0`````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````&`X)```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````)`DA*Q8````6"1`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```0"AHN"0``$"$*"0`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````!@*#P\)`!8* M#Q4)```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````DH```````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````$!T/#P,)"2(S+@D````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````6"AH)```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````D&`D"'P\/+`H""@\:"0`````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````D/(@D````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!`*(AL*%1L/+A$=&P\H```````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````"1H;"0()```````````````````````````````````````````````` M````````````````````````````````````````````````````&"(L#PH# M&QL:#@H5%0(````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````A(ALK+A\) M```````````````````````````````````````````````````````````` M```````````````````````````````````````0'AH/'@H5#QLB%2(;#A`8 M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````"1L;#P\/&Q8````````````` M```````````````````````````````````````````````````````````` M`````````````````````````!@."B(*"A,<'!T;&P\/'A`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````)#RP;-BPB(1@````````````````````````` M```````````````````````````````````````````````````````````` M````````````%!T*'1,3!@4"!@H:&S85&``````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````DB#QLL#P\;"0`````````````````````````````````````` M```````````````````````````````````````````````````````````8 M'@HA$0<&`CD""@HF%0HG```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````"1L/ M&PH5+#4G```````````````````````````````````````````````````` M`````````````````````````````````````````````!8*+A$"*@8<$0($ M!@8.$Q4)```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````"+AHF$QL/&@X)```` M```````````````````````````````````````````````````````````` M````````````````````````````````$`H*(0(<#A,.!`<%.08."@X)```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````DP$P8"%1LF#S`H```````````````` M```````````````````````````````````````````````````````````` M```````````````````0'A41!`83'`8"!@X<$1P<%0H6```````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````@HJ`BH<(QP<$PH)```````````````````````````` M```````````````````````````````````````````````````````````` M`````!8.)0<%!`8@!@0&*AP@!!<5"A8````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```)"B,<`@8&!@(.%0D````````````````````````````````````````` M```````````````````````````````````````````````````D`@($!0T& M!@82!1$C(Q<2!B4=&``````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````!`3(P8@(Q,< M!`8<)Q@````````````````````````````````````````````````````` M`````````````````````````````````````"@*$P("!`@2(Q,$!B`@&1D7 M$QP````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````%AP&$@8<(!(7!`8*"A`````` M```````````````````````````````````````````````````````````` M````````````````````````)PH M'PX)````````````````````````````````%AX?%2"@(6```````````````````` M````````````````````````````(1L"%@P,#0@+"!D9$AD+%P0,!`(0```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````%@X3!@@+%QD9&1D%"`@"#!`-'!4*"0D) M)```````````"1H/`Q`4"2$.$1@````````````````````````````````` M```````````````)'0X'!PT$"!<+&1D+"Q(+"P@$*A8````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````%`DJ'`8%"QD2&0L+!`@%!P<-`@T"'1X)```````````4 M*QX""18)$!@)"1`````````````````````````````````````````````` M`!@)*Q,"#`@(!`4("`L+%PL("`(<"0`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````)`D*"AP$"Q<9&1D("P(-"`4'#`("!A$6`````````!`A#@('!P(4&!8* M"A8```````````````````````````````````````````````D5%0(,#0@( M"`L2%Q(+(`@$!A,)```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````%AX*!@8@ M$AD7&0L2"`0%!`T,#`P-`@()`````````"@"!P81`A80`@H;(20````````` M````````````````````````````````````&`H;#@<,#`8(!@L("PL+"P@" M'0D````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````&!@)"B8J!A(+"Q<(%P8+ M"`<%#`0%$Q,6````````(0X"$0X1`@("$1,*"0`````````````````````` M````````````````````````%B$*!@P(#`@%"!(%"P8(!"HF"0`````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````!0)*`DE%1(+$@@+$@L7"P0&"`(.!B0` M`````!8)$0(1`@("$0(1*AX)```````````````````````````````````` M````````````%`D"#0((!0<&!1(+"P4$!@D8```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````$!,>(`07"R`+"QD2"PL(!08\&````````"@A!A$A M!P(1$1$"'"$)```````````````````````````````````````````````` M%A$&!PT'!!$&"!(+!@8"%@`````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````4(1$&!`L$"Q<+&1<+!@0,!`D4```````8`AP"`@8"!A$"#00&%148 M```````````````````````````````````````````````8'@H"#`4$!B`7 M"PL&(PXD```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````!@*%0X% M#`@+"Q(9&1D+!00&`A8``````!0"`@(<`@("`@<"#1P;&Q`````````````` M``````````````````````````````````D:(@('`@83(Q<+!@@E)18````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````8"2$))``````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````4(145`@<,#00+&0L9(`@% M"!,<%```````%`(&`@("!0("!`P"!@H*(10````````````````````````` M````````````````````"0\/`@D-!B4C(`L(%Q4*$``````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````$`(?&S`)$!`````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````6%A`0"2$5$P8%#`T(!0L($AD+!@0%"AT8```````8 M`@8$#00-#`4"#`(-!B8*(1@4```````````````````````````````````` M```````)&P\"!P(1(R`2%P@$&Q46```````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````````"03 M"B,3!A$*"A8````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!`*#Q45"AP"#`((!PP$"Q<+"P8(`@05'A```````!0J'`("#`P)!PP) M#`P'`A$*"A```````````````````````````````````````````!8/&@(" M"0(<"R`+!`85&@D````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````D`@HC&0L$(Q4F"0D" M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````8"0<6"14:&Q4> M!@P,"`@%"`@7!`4(!`8$`A4*$```````)`X3#0P6#`P,#0P,%!0,!Q45(18` M````````````````````````````````````````&!H5`@<"$082"P@(!1L* M"0`````````````````````````````````````````````````````````` M````````````%`DA`@D6%A08$`D8$"<6%``````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````"<*(R`@&1<+!@83&@HA)``````````` M```````````````````````````````````````````````````````````` M````````````````````````````$`D6``D*"A,A!B$&`@8-`@0(`@@$%P0+ M"!<"$08"%1\)%@D0&!`)&B("#`P0#!00#`T,#`P,`AP=(1`8```````````` M```````````````````````````0$R8"!0@$!@8+!0@",!X6```````````` M````````````````````````````````````````````````````````%@D" M'2X*#AX.(1$"$Q,K"@H)&!88```````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````"0H2&1D9$@L$!08<'A4G```````````````````````` M```````````````````````````````````````````````````````````` M`````````````!@*&AX1!A,<'!$"!PT,!`@(!0@("!<("P42"`0"!@(>)@H> M)1T>(AHS&PX'#`P-#`T,$!8'%A0,"1P5"A`````````````````````````` M```````````````A!@4,"!<&!A(2"P0E$Q`````````````````````````` M`````````````````````````````````````````!`*(AX3'`XJ(1P.$0X1 M'`X3*Q,5"A`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```))B,2(!<2"P4$#0(3%0D````````````````````````````````````` M```````````````````````````````````````````````````````````8 M$14;,!P"$0(A$08"!PT"#`@($@4(!`L$"P@&!@('#`83"C`*%14*&@\5(10' M"10,$!0,#!0,#0<,!@\*$``````````````````````````````````````8 M"0(%!P4("`0&(`0+`AXI&``````````````````````````````````````` M````````````````````````&`D)$0H;$P(,`@<"!A$&`A$H$0X1$P\N%@`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````8``D>'BH<(08& M!P<-"`83`A8````````````````````````````````````````````````` M`````````!08&````!00"1```````````````````!08$"@*$P8.$1$.$0(" M`A$�@-!@@7"`07"`4+"`4<`@T'!P4&!@8&`@8&`@('`@P-!P<-#!86!PD0 M%`<)'!,)%`````````````````````````````````````(>`A8,!P@$(!P" M#`T''"H4```````````````````````````````````````````````````` M```````4%@DH"@H3$2H""`0"!`@"`@<"`@81`@(.'A,)%``````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````"1X)%BD3#@("$1,)&!`$!`8=#A0` M````````````````````````````````````````````````````````"1X< M`A`4"0(*"A8`````````````````"0H=#@8&`@(.#A$"`A$"`@("!`0("`@( M"P@2"P8+!`8"!PT$!`(%!P0%`@@-!`($`@("`@("`A$"`B@"!PT-$0,)```` M````````````````````````````````%@X&#`P(#0@"`@T'#`<"`A0````` M`````````````````````````````````````````````````````!`#%1X. M!AP&!P<"#0($!00,#`P'`AT*'BL&$PH)```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````)`D."@()$QX=$0D)#A88%`T%`B8*$1@````````````` M````````````````````````````````````````&`DA"A,""0T'!AL5`A@` M````````````)`D3"B8<#0(&$1$1(0<"`@(&`@0"#00+!@L&"P4+"P0"`@4' M`@4"`@4"`@('`@4"!@T&!A$&$08"$0X1$0()`@DA%0X)%``````````````` M````````````````%`D1$0T,"`<(#`('`@P,#`T'"1@````````````````` M```````````````````````````````````````D(14/$P8"!PT"!00(!`@( M#0P0"0D"*QX=#@<.'@D````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`!@""B(;(0D.`QX)"0D)$`$8#`0%`BH=$1`4```````````````````````` M```````````````````````4%A@"$QX1#0P'"0()`@X*$184`````````!0) M"A43!@8"'"$1#A$1`@<&`@8$`@4$%P@+"Q(+"P@+"`4$`@P-!P4$!`(&`@8" M`@(1`@<"`A$A'!$.$0X1#A$.$0XK%1X)$!80)``````````````````````` M```0'Q4"%@<-"`P"!P(("`T'#!$*$0`````````````````````````````` M`````````````````````!@0%@(='`8&!P0%#`0%"P@%#08$`@(6$0(6$!@8 M%!06```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````*`H>"@\N`Q$. M`@D)*!0!&!0D%@<%/!,5"A`````````````````````````````````````` M`````````!`*%1P1`@P,$`<-"0T'!P85"A@`````````)PHE$P8-!!$<$1$" M`@T"#0($!04(!P4$"Q(%"P42"P8(!`@""`T$#0(%!P4"`@(&`@4"!@(&$0X1 M(1$1(1$1#@X1#A$.*R$3)@H)``````````````````````````DN%0<,"`P, M"`T("`4$"P@-!@HG```````````````````````````````````````````` M````````"0H.$08$!P(-"`@'"`@$!0<((!4;`PDK$Q@````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````"&BL."AHB`A`)`B@)&!80)!@0 M"0($$1H;"0`````````````````````````````````````````````D(2(: M#@P,#`D,#0P'"1`,`@H5`A@````````"+BH"!`81$0X.#@('`@0'`@(%$@8% M$@4&"P@+"R`+"P@&"`@'!P4$!0((`@@%!@(&!P0"!!$A$1$.$0X1#@X1$0(. M#B@1'"85%2$)"1@`````````````````````&!,=`@P,#`((!`4+$A<("P@& M%0(`````````````````````````````````````````````````"0DA%1X& M`@4""`0(!@L%"`@-$`8E'Q4>#@H*%@`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````DB$R$1#@X0`10)"0D0)`$8)`$0`@("'A,)&``` M````````````````````````````````````````%A$5*P('#10)#`P)$`T0 M#10'!RH>(1``````$`D&!@<"#APA$1$1!P((`@T'!`0(!00&$@4+"Q(+"!<( M"PL(`@T,!P($!`(%!`<"!P(&!P8%`@<1(1$A#A$1$0X1$Q$1$2$1#@(&$QX= M"18D$````````````````!00`A$,#0<4#`P,"PL9"QD$""H*"0`````````` M`````````````````````````````````!@0%@D>$Q$&!@4'"`0%"`8("P8' M%A0-'B8)%B@=&QX8```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````*!43*Q4.`A@!$`X8$!@4`10D%A0)!PT"'!4)```````````````` M`````````````````````````!8*"AP-$`D"`@<)%`P,$!0'"0P'"`X>`Q8` M`"03'@("!!$1$0X1#@8"!0<"`@0%"P@+!!<+"!(9%PL2"P0%!`4'#`<(!04" M#00"!04$!0(%!`($!P8"`A$1(0X.$1$"`A$"$0(<#@(&!A,"$0,)```````` M````````"1X.#`<0#`D,!P42&1<9%PL&!@D6```````````````````````` M````````````````````"0HK'"H"!0<&"`4,!1(+"P4("`P8`1`*%0D`&`D) M"20````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````````D."BD3 M(A$4$`$)(0D4&!@0&!8D&`('"0<&"@(````````````````````````````` M``````````D)`A\5`@D,#0D0"0T'"10-%`T4#10,!R8P*!04*!,*!@<"`A$. M$0X1`@0"!04'"`@%$@8%$@47$A<9"P8+"`L("`P'!08$`@0(`@4$`@<"!`@$ M!0<%`@0"`A$1#A$.`A$A`@()$0X1$0('!0(3"B$)"0`````````````H&@(, M%A06#`P,#`L9"QD+!B4.%@`````````````````````````````````````` M)`D)"0D1"B4*@<,%`<,"0P-"`8+ M(!(&%1T8````````````````````````````````````&!8)"AL*'"H&`@4" M"`0-"`@+!`L7"PL%(!P")!`)"BX0```````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````D/#QX.'1X.$0D1(0()%B0)"188%!@D%!0" M`@8*'A8``````````````````````````````!@='@(1(0()$0D)`A80%!`) M#1`)"0P,#!8,#0P,!P(<$Q,""0("$1$1#@X1`@0%!`4(!1<(%P47!1D7!!D+ M$@42!1((!P4$!`($#00"!0T$`@(%!`0%!`(%!@0"`A$.'"$"`A$"`@("`@D1 M$081#@X'!08.#A,*'1``````"0H3$Q$0#`P-!PP,#`0,"`8E$P()`A@````` M``````````````````````````````D*&AX.!BH&`@4$#00%"`P2%PL9"Q(( M!`(P&PH.`@(""0`````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````8$1\5$PX.#@XA*`X.*!`)$`())"0!`1@!"0T$`A4*%@`````` M````````````````"100$!00"28*`A`)"0(""0()$!8-"0(1"0<-"106!Q80 M#`<-!"H3$0T'*!$A`@X1(0("!0<%!0<$"!(7!`02"PL&"P4+"P@+!`4$"`4% M#00"!00$"`(%!`8%`@0'!`0&!@(&$081$0X&(0("`@("`@D"`B$1`@("#A$A M$14N(1`6)PDA%0H<#0P-!PT,#0P,#`4''!,K%@`````````````````````` M````````$`DH"1`)"0H5$P0'#`0-!`<("`8""Q<+$@L+"`4,`ALQ&R$H#A@` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````&`(* M$0D)*`(A$1$A'AX)`@D8$!`6`18!%`$0!P('*@X)%``````````)$`D)"1@) M$`(**@(&`@81`@8)!P()$0(,%`T)`@X3"B83`@T'#0P,#`<-#`P-!P4)%`D" M$1$1`@('`@0$!0@$#00%$@L+&0L9"PL+$@L%$A<(!0@'!`0$!0@$!0@"!PT" M!`0%`@4"!@(&$0(J`A$"`A$1`@<-$0("!P("`@D"/`(1`A$.#A,*"2@5"A,. M#0('`@P'"`<(!PT,!!,F(1@4```````````````````````4$!8)$!8)"AL* M$QP"!B$&`@4"!00%%P42"P@2"QD+&00,"1`"%0HH&"@="0`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````!8>"B$4&!06)!86"0DH M"10)$`$6)!@0&"06`1@-`@T'`@H)````````"1HB&AH/#QHB%1X1!@0"!`8$ M!PP"`@()"0<0`@H"$`DH(0H"$`T'!Q8,#0<,!P@-#`D-!PD-!P(,#0<%!04+ M!!<(!@L+%P07&1<2%PL%"PL+!`@$!`4%`@4'!00%`@4%"`@%!@@'`@8'`@0" M!`0"`@("$0X1`A$"`@<'`@()!PD"`A$1`B$1$2L1(1$.`@<"#`@""`4,!0P- M#`(5%0X4`````````````````````````!@*(A\*'0XJ*@8&!@((!`8(!`4( M!1($"PL7&0L7$@L(#`P0%`D""10`&`DD```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````4$14*`B04%!@4)!@0%A@D&!@6)`$4`0$4 M`204&`<-!PT&%0(````````)"@\/,C(S-C,;,!,.!@0%!@0%"00"*!`-`@8= M"@D````"+B$'"0P-#!`,#`T,!Q`,#`<'`@T"#`@""`<"!!<+"`4$%Q(+"PL9 M"PL2"PL2!0@%"PL7!`@$#00%!`0'!`<&!`4$`@4&`@8'!0('!A$'`@('!@(" M(1$"#0T"'`<-!PD'`@(H$1$"`A$1#0P'#`(-`@@(`@@'#`<-*@H*&``````` M````````````&`()`@D)"1\;%1X3$P<'`@0-!`(%"`8(!!<$!!<2&0L2&1D+ M$@T0"186`A`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````)"$*)1P%!P("!PT6#!`)$!0D&"04&!`!&`$8%!@D#`T'!P(3 M`A@``````!88"1$B-"P/%28;&Q4@'"`$!0<,#0<"`A$.%0H"``````D*#@P, M`@('#0T'!PT,#0P-`@4'"`<"`@<-`@T'!P0+!`4+"Q<2"Q<+%QD7$@L+$@@& M"`0-!@0%!`4%`@4(#04(`@@$!A(&!@(&!`4"!@(&!@4"`@81!@($$1P"`@(" M`@D"!PT""0<"#0('"`(%!P8'`@<'"`T(!P(>$1`````````8"180&!`4%!`) M"AH>$PX<(1P"!0(&!P(%!08+!`82!0L+"Q(2$AD9&1D9$@8@$0(0!PD3"0`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````````!`3 M'AP&`@(%"`4$`@0-`@P-&!`4&!0D`184)!`D)!84"0(-!Q$5"A8````````` M%@X/,S4E(",5&R`2'`0%!P@-!!,N'P()"0``````&`(3#@T'#0<'%`T4$!0' M#1`4#`("!04%!`($#0T(!0P$"P8+"PL9&1(9"Q(7"`8+"PL$%P0%$@L&!`0" M`@4$!`0"!04%`@0"!@X&!@<&`@0$`@($`AP"*@(.$R$"!`(-!PP,!P<-!P(, M!`4$"`@"`@((!0@"!`T.$R$8````````"14B&PH>'0X.(0(<$RH&!@0&`@<$ M!P(%!`0$`@@%!00C(`L@&2`2&1D9&0L%!!,;&AT)(1LG```````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````&`DG"1XP$08$!`($`@0- M!`($`@<6#!06`18D)`$8%!@8`1`,`@<"#2(5"0``````````&!T/&Q4C(R8F M$A(@'`8�<-#@H*%@``````````&!T>`@<""186$!@4&!80#0D-!P0"!P($ M#00-!`<'#0@("PL+$@L+%QD7"PL$"PL2!0@&!0@+!@L%!0<%!`@%#00"!`0% M!`8)1,<'`8E'QT0%``4 M%A@````````````6*R8""180%!`4$!84$`P(!PD4%@P,`@@%`@0(#0P(!P4$ M$A<9&2`9$@L2"Q<+!0L$"`@&$@42!`8-!`T$!00'!00%!@@"!@X"!A$"!@0& M"`4&"!<$`@81'`X&!A$&`@<-!PT'#0<%"`0("PL&`@(&!`((!0T$$PH>'BL3 M#AX.`@8.!@X1'`8%!@(%`@@$`@0"!`0"#00&$@42!@82%PL9(R,@&1D@&1D+ M"`@-"0T&`A@6)!08%``````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````"0HF$R41`@8-!`('!0T"!P<-`@4"!0($#00-"10!)!06)!@0 M#1`"!`T&`A0``````````````!@)*`(0(14;%0(""0`````````````````` M```)"0(0%A`-!P("!P<%`@(%#0<8)`T,`@0,"`8%!P4%!`4("Q(9&0L9%PL( M$@L2"Q(%"PL+"`@%!`@%!`4'#0@&"!(%!`8@'`8&!@(&!@4$`A(%!`8(!@(& M`@8$!`(-!`T'#0<"#00(%P@%"P4$`@<%#0($!P(.$PXJ`@8A'`("!`4"!0(" M`@0-!P4$!00%!`4(!00(!1P7!`@2!B`9&1(E(R,9&1D2"P(-!PD'"1$)```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````````````D. M)B4@!B`&`@(""`((!`0"!0('!`<(!0<%`@0,&"04&`$4`0T0#0<"#`("*!0` M```````````````````)"AH*%@`````````````````````D"0D0"0<4!PT( M!00&!`T$#0<'`A08%`<(`@4""`0'"`4$"`(2"Q<2&1<+"PL7"Q<("`L&"P8+ M!@(%!@4%!`T$!00+!0($'`8&$0("!`82!`(%"`0+!00$!@($!P4%`@($#0<" M`@T$!0@%$@L$!`(&`@0'"`(%`@(1$00%!P(1'`8"!P@"!P4"!0(%!`8(`@(" M!`8$!08&!@0($B`<&1D@$B,E("`9"PL%!PP)#0P"$PD````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````0"AL&!AP@$A("!@T$ M!0@&"PL$!@("!@('`@4"`@T"$!8D$!@D%`D'"0P"!P8>"0`````````````` M`````!@0"1@0```````````````8&!`6&`D*#A$-#`(-!`($#0("!0P$`@@- M!`T4"0(%!P@"#`4'!`(%`@8%!@07$A(7$@L+$@8+!1(+!`4$"`0+$A(%!`@& M!`4$"`8&'`X"'`8&!@8%"`0%!@@2!0@$!0(%!`($`@8"`@(1!@8"!`@($@8& M!00%!P("#`<(`@(&`@<"!0("#0($!0($!00$`@0""`8$!00%!`L+"Q(@%Q(+ M(R`@&1D2("`@"QD+!081`@<"#`X*`@`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````!`="@(%!A(&"`4$`@P'"`L9&2`&`A$" M!P4(!P4'!00,#10!%`$)#`P,#0<,`A,)```````````````````````````` M`````````````!`*(AX1!`8&!`((!`("`@("!0($`@4-!`((!PT4%`<"!0@" M!00%"`0&`@81!@8+$AD(!@L("PL2"!<(!`4%!@L%!@4""`@(`@0%(!$A$08< M*CD"!@0+!`4$#`8(!0($!@L$!0@"`@<"$2$&'`8&$@(&`CD"!`(&!0T'`@4$ M`@('!0@$!00%!`4-!`<%!P8%"!(%!`@%!AP7%P87!@8+%Q(@(R`9&1D2%Q(+ M!`4$*AH/%1,"!PD8```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````$!,3`@0(#`P""`0("`4$!0L7"P81!@($`@<-!00"`@($ M"18D%@P'`@T'#0P"*A``````````````````````````````````````$`D" M*`H;,"H""`<"!`T"!0(&$1$$!`T(`@0$!00%!Q80#00(!@@'!`T$!@4$(1$. M'`87$A<+"P87$@4+!`4+$@0($@0$!00&!@0%!002!AP"!B$#A8````` M````````````````````````"0H*$R$&!@($!0("!A$&`@<&`@8-!00&`@<$ M!0(%!`0%!`4-#`D-!`8$`@@"!`T%!00"!@X1!@(+&1(7&0L2"`L+$@07"`8$ M!`4&"`8+!`4$"`4&!"`&!@87$@8&!@4&"P4$"PL&!@@"!@8'!@02"Q<2"P02 M$@4&!00&`@0-!0P"!00"!`((`@0&!04$!04&!`4$"!<$PX< M`@(&`@("`@0"!@0"`@8"!00$`@P(`@0"!`8""`T%!`<%!@@0%@<1`@@%!`4+ M!00%#08A$087$@0+$A<+"PL2$@L2!@@%$@42"`8+(`L$!A<&$RH)``````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````8%@(E(!(+"Q(9&1<+"PL&!`0(!`4(`@@$!0($!P<$#`P'#0<$#0<- M!PP'#0P'%@<-!PT,!PT'#0<-#0<'`@T"`@T$`@T"!`4'`@4$#00%`@4"!`4% M!`<"!`4$!@@(!00$!`<$"`@""`((`@<"#0<,#`((!PT1)AL;'`@(!P4$$@4( M!08(!`4-!P($!1(%"`0&$0X<#@X1$0X"`@(%!`4%!`L%!A$3'!,&%P0%!1(+ M!@0$"`L("`(%!P4'!`@(!`@+!0L&"R`2"`L2"PL&"PL7$@L+"Q(+"Q(+$AD7 M"Q<$!`(-`@("!`8$$Q,0%A`6$!8````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````&`<@ M(!(7"Q<2&1(+!`@+!1(%$@0(`@0(!`T%!04"`@@-#0('`@@,%@P'#`T'#`P' M#0<,`@P6#`P'%`(,#`T$#`P%!P<-!`T(`@<"!`4"!`4&"`(%!@@%!P0%"`8$ M!0T$!04%!`4$!0('!@T'%A`4%`D1'1L/%24%#0(,#04("`<(#`T-!P0%`@@% M!`("`@X1#A$1$2$.'`8%$@@(%P0(!083$RLZ#AP&`@07!@8"!@('!0<$#0P" M!`4%!`4(!00+!!<$"`L%$@4+"PL+$@L2%QD7"Q<+"Q<@!B`&"P0"#0<'`A,@ M!@8:+@D````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````!PC(`L9&0L9"Q<+ M"P@$"P@(!@4(!@4"!`("!`(%!`<'#0('`@P,!PT'#`P)#`P,#`<,!PP'#0P- M#`T'`@P-!P<(#0((!P0$!04"!`4$#00"!`0%!`(%!0($!0@$!08&$@L$!0P% M!PT0!Q04`0D6#1T5#QLF!@@'"`<,!`@%"`T,#`0-!P4$`@('!@(1#A$1#@X1 M(1$A!`@(!1(&"P4&!#H<'!,3$08"!@('$1P1!@("#04"!`4(!`@%!!(+!!<( M%P@7"!(+"PL@"PL7"Q<2"Q(+$AD2!!P&#@0"#`4$#1`"'@XA'!4*$``````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````0'14C"PL7"Q(+"PL@"P4+!1(+"`0( M`@0-!00$!04""`T$!PT$`@(,#`T-#`P,!P(,%@P"#`P,!PP$#`T,#`(,#`(( M"`(-!0('!`@"!`($!04%"`<-!`0$!`@"!`4$!`8(!@4$"`0""106$!80!Q`1 M(Q45*@4("`4,#0@-!`@%"`<"!`(%`@0"!A$1`B$"#@X"$0X1'`(%"`0""`@& M!`4"`@X.$1$"#@("`@8"#@(1`@0(!`@(!`@%!`0("`87$@L2""`+%PL7$@L+ M$@L@"PL7"Q(7"P47`CD'`@("`@("#2$5`@(>(188```````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````!@"#A42"!(9%QD2&0L+!`@+"`8%!`4("`<"!0((!A($ M"P8%!PT,#`T'!PP'!PT,#`@'#`P,`@@-#`T,#`(,#`<(#`<""`0'"`(%#00% M!0<%!P0%!@4%!@47!@@&"`("!0('"`T,$!0!%"0)"0(*%1P&!B`$!P@,#`<, M!P@-"`<-#`@-!`0"$1$.`@(&/`(1`@X<(0("`@0"#`4"!0($`@4$$0(H#@X1 M`@8"(3H<$PX&(`8%%P8+!@L"#`L%!`L%"P0+"PL2"PL+!A<2"PL+"Q(@!@8& M!`<""0T.'283(08'`B@D&`D````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````))B4@"PL2%PL7&1<+$@4$!00(`@<"#0@$%Q(+"Q<+!`@"!`('`@T4 M#`T,#`<-#`T"#`<,#`<,!PT'#`<-#`0-"`T$`@4(`@0$!00""`0%!`((!`0( M!`0(!`4,#00'!PP4$!8!&!8)`A$.$145'`($#`T(!P4'"`@-"`0(`@P'#`(& M`@8A$0X1`@(%`@(1$1$1`@(%!P4$`@4$`@4-!`(&!@X1.A,<'`8<$SHK'!P$ M$@0$"`0%"`@(!!(+"!(7"R`7%PL2!1(7"PL7"Q(7"QP&.00%#0<'`@H5"@X. M`@XJ%@`````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````!@)'14& M%P@($@L$$A<+%PL2#00%"`@,`@@$%R`2("`@%Q(%!0<%#`<"$`P,#`P'#`@, M#0T,!0P(#`P-#`@"#`T'!0<%!P((!0T&"`8(`@8("`4"#0<%"`4$#0<"#`T4 M%!80"1`"#AX5%14F(P($"`@(#`<,#`@-#`<(#04(#`4'`@(1#A$1`A$$`@4% M!`8"!@8"!0((`@0(!@@7!!<$"PL&(R43'B4F)1X3$QP3$P8<%PL7!`4$!@@7 M"`07!`@2$@82%PL+"QD+$A<+"Q("!P(-`@("!0("%0HA$!0)'@H8```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````"00$Q4&"P@7"Q<("`@2 M"`4%!`4%`@<%$A<$"R`5&B8<$0()#`<)#`T,#0(,#0P,`@P4!PP,#0<-!PP' M#`P,!P@,!`4$`@4$!`@-!`4($@8(`@<$`@4'!PP,#`T0%!0D`0<.'1L/&P\; M)@8%"`0,#0<,#0P%#`P,"`4'"`<$#0P"(1$.'`X.'`4+"`82!!((!!<2!1(7 M$@L+"Q(+"`L+"PL7(",E$R8P)1P>$RL<(P87!`8("P@7!`L7$A<+"!<$%PL+ M"Q(+%Q!@T,#0<("`4-"0<'#`@-#`@(#0@' M`@P-`A$)"0<"!P8+%PL+$@L9"PL9"PL+$@L+!0L7$@L+&0L+&1D9!@8C'",1 M.AP3(`87!@0%!`@(!0L+"R`+%PL+(`L&!`L%"`4'#0<-"0D'!P(J"0(P)A,3 M$``````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````D;+",7"`L+%PL$"`8(!A("!00%!08<)AL5)B`"!`("*!`4!PP'"`44 M!PP'#0T6!PT,`@T,`@T4#`<'#`<%#00(!`((#`4-`@4(!!<%!`4(!`P%!Q80 M"0<)$"<:#Q4;/28E!@T'$!08%`T$!PP'%@T'#`P'#0(,`@@-!`<'#`<,!PP, M#`0("`4+%Q(7&2`+&0L9"QD2$@L$"Q<2"PL@%R`@("`7$@8@(!(%!`0&(`<- M!`42%Q(%"Q(+$A<+"`0-!`(,`A8)!P(,!PP-`@X0)`D)"0D4```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````&!T*!@8$ M!@L2!0@("P0+!0@"!`('!"45&R8C(`('`A$)%A86#`("!PT0#0(,!PT,!P(( M!P('#`<"#0@"!P($`@<%#`@$`@0'"P@%!`8%!`4("`P,%@P)#`D4"2(Q#B4E M'`8(!Q8,"100"`4(`@<)!PP,#0@'"`P-!`T"#`T-#`P-"1`-#`4,"`07"!(( M"Q(7$@L2%PL+%Q(%"P8(%R`2(R,@$@L$%Q(&!A(%%P8$!0T("`L+"PL$%P07 M"`@&!@<)#`('!PP-'`X&`@<&'0D````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````"2$"("`+"QD+"P0%"`@& M!`4&!@0"'@H;)B4C`@8&$0(8!Q`"!`0-$`D"`@('`@('#0('!@4"`@T'`@(, M`@<%`@($#0(1!@8%$@@+"`0%"`@-!Q0'`@<-!`D"&P\A`@0%!`($!`4'%@P, M!@0-`@8$`@<,!PP-!`('"`((!PP0#0P,#`P'"`<-"`@,"`4("`@(!0L(!`@% M"P0(!0@&(Q,3'"`%"Q(+"PL$%P0$!@0%!`8$%PL$%P@%!@8$"`<)#`<-!PT- M%`(5&@H3!A,5"0`````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````!8*"@8%`@L9&00%"`0%$@@%"`<'#0()#B8; M+@8&!B`"`A8-#00-`@P)!P0"`@T)`@<)`@(1`@T"$00"!P<%`@("!@4$!@8& M$@0%"`8&"`@,!`P,%@P"!`('`A$:#R@$%P8&$@8"`@<'`@0,`@8"!P()"0D, M"`((!04$#0@-%!8'#`(,!P@(#`@%!P4,!P@"!PP(#`(("`<,!0('`@@&'"`@ M!@L$!0L@(`4(!00(!`("!@L&$A<$!0<'"`T)#`<-"18'`@('`A\3*"@5"@(8 M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````&!4:!@P,"!D+"P0""`@%"!(%#`4'!Q8"$QL5!QP<.1$)$`0- M!Q8,"0T"#1$)!P<"#0D'`@("`@("`@("`@0"'`8"!`($PH*(0`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````8)A4C"R`+!@@$!`@9$A<(!0P$!@L9"Q<(!`4,!PT) M#`P'`@4'#`(,!PT)#`T$#0(,!P(-"0P)#0<"#0<-`@(,!P<)#0T'#0(,"104 M$!`0#`($`@<(!P(<&S0R-AL"$!0)%!@D$!`!#0D6%`T4$!@4%A0)%`P,#`0% M!P0,!P<)$!0)%!`-$!06#!0)#`P6%!0,"100%`T'#0P)"0<'#0@,!PP"#`D4 M%A`0$!0)!PD0#`<"!Q0-%34;'1,"`@8#"0$D`2$*(1$5"0`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!@)#A,2"PL+!0T%"`L9$@@"!0@(""`9&1((!PT'#0<-!PT$!PT'#0P6 M$!0,$!`"`A80#1`6%"04%A`,%A`0%`T4%A`0&!0,!PP'#`D,#0('#0<%`@<) M`A4V,C(L%0D!`10!%!@!%A0)"2<)&!84&"08$!80#`<-!PT'#0(%#`D6)!84 M%A`6#"00%A`4$!80%A0D%!8'#!8'%!0-$`T0!Q8'%!0-$!0)%!8)%!81`A84 M"18,"0D?,2PQ#Q4E`@(8`0$!"14>'!X)```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````)*@8% M!`0%!`($!@L7"P4$"`@(&1D+"P4-!PT'#0<""`4$#0@($!04&!`6`A$1#0$4 M`100%B06`1`8&!08%!`6`1@4%A$&$1PJ$00$`@0"!`('!@(3-C(S+"X>"18D M&!@)&`DG"2"A,)`18D%B08%!`6%"04 M"0D6"100%`D.$R8E%283'`8&!@8@#@XO+0,/+#$/#@D))PD8+R\W+R\O-S(0D)%`T."@H*"A\5"AH*"@H3*B4F M%2(/&QH?$0D0&``````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````"0H?'@(6&!0,"`8(!@@%!`L7$@L2%P@+"PL+ M!@@'#!0'%`T'!`4'#!@6)!0)"2$:(@DD%"04$!88%!@0&!`='@T8%!8)$!`) M"1`)$1,@'!LL#QL#-R\#+0,M`S'PH#'B$0"1X*%0H;"@HB"A,J$Q,N&Q\/#P\/#P\:(@H" M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````4*`D) M`B@)"0D8%A@)+@H=(204$`T$!`4%"`0+"P@+%P@+!@L2%PL%!`T-%`T0#`T" M#104`104%@X1"0H*`@$6$`DA`A`6$`$8(14*"106"2$"%`$!`0<1*@0@%34S M,0,M)RTM+2\M+S$QP&'1H/#QH;(@\:#P\V+"LG"1@````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````"<5'PH*'PH#'BD.`B$) M"1`4%A8)!08E'!,@!@@&$@@($@4&$B`2$@@2#`<,%`T4!`4'%!`8)!@)%0H6 M&`DA$`$)$PH>`@$8%"@3*!`"$!@H'@,8`20)"B4&"`8C(Q4#`RTO+2DO-R\# M+R<)"2$J+R\O+S$RH&!A,*&QH/ M(@\:#QH/#P\;(AH/#P\Q#P\B'QL/"A@````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````)'0D)%A06&!`8)!@4$!`8%@D)"0T$)145)2`$!00%"`0" M*@H*%2`7&1<2"P@-!PT)%`$4%!@""@D````),!$)#@D)"B$-"0X.$``)"AP. M#A@!)`D."B`($@L9"QD@+2T#`S(1`)(R,+&0L9 M"`(,%`$0&"08)`D*"0````D*$QP*"1@)$R8A+@H0`"0)'1X)`0$""AX&!`L9 M&1D9&2,#`RTM+2DG%@D8`@8"!Q@6&!08+P,:+A\:#@D"'PH)$"$>)Q`'#`<" M#0<"!0("$2D.#BL1"0D1#AT.`PX1`@0"#BD.#A$)%!8)#ATK'`()#`D0`BL> M'1XI#@X="@H#'@H3$Q,<(083'14/&B(5(AH;&@\B&B(;#R(/#P\/#P\/#P\/ M#P\;(AH/#QLG"0D8$`D8$!@4```````````````0&`D=&PH6```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````%B$;+`\5)@X1 M'!$1$0(H$0DG$0(H`@(C'",,"X;'R(;&B(:(ALB&AL:(AH/&AL:#P\:#QH/&@\/+`\L#S4T#R(: M&AH:#P\/"A``````````````"0HJ!AP5"A8````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````%@HB&QL/)@H>$Q,K$Q$.$0() M*!$"!B,E(R,<'`81$QL*&```&`H5)1D7&1<@#1@!`10D`0D)```````````` M````%@HB"@D`````````)`(1)@8$$A(9&1D9$@8.+2TM+2DM(0X3#A,.)PD" M"0D0`A4/&@H:#QL:"AT>&`$!`0$0`@('#0T"`@4-`@X3#@XK#@XK$QX.`PXJ M!P'0,=$0<)$1X*'AT*'@H*"@,>#A$$`@8J,"X:#QH; M&AHB&QH:'QH;&B(;&B(:#P\/#P\/#P\/#P\/#P\/,0\/+#4S-C,V,S0/#B$) M(2@"(2@""0D""B43(R4K$``````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````%@DG%0\;%145%0H>$PX.#@X<(0XF&PH>'B4= M"A4*$0D`````%A$*(Q<9&1('"0D0%B06'0X6```````````````D$`D6```` M`````!0)'@H<"`L7&1D7$AD&!BD#+2DO"0(=#RP/-1HI#ATB)AT*%1L*'A,E M"A\;)Q`!`0$!`183`@<,!`0$#`0-$2D.#AT.'2L.#BDJ!@(%"2$.`Q,.$PX. M#A,K'0,3'AX##@(.`QT=`QX='A,3'"$&!@8@'0H5'QL:'RX?(A4:(AL;'P\B M&AH/&P\/#QH/#P\/#R(/#P\L#P\L#S4T-0\T#S0U,0\/#P\U+#$L&R(5$P8< M(R4F$18````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````G"2#BL.#ATK$Q$"!0<.*0,3*2L#*1X#'0,='AT#'1T. M'1X#'@H>'0X&`@($!A,3'0H?+A\:'PH;&A45(AL:&@\:%1HB&QH;&B(:&R(: M#P\;&@\/#P\/#P\/+`\/+`\U+`\T-2PS#S0S-C$N)2H$'#`<"0D8```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````%@H;&Q4>"@H*'PD`````````````````````````%`HF!B`@)1L5 M(0$6$0H*%@````````````````````````````DK%08'"Q<+&1D+$@8J`R$O M*2<0#`(J%30U&RX?*2D##S$L'BD3$PH5#QHB&@D!`0$!`0$6"@('!P(&!P8" M#0X.#@X.#@XK$PX.#0("!@X=#BL3*1,.$RD3`Q,#`Q,>`QT*`QX=*1,.!@<( M!08A'A4?'Q4:'QLN&@H?(AH?&ALB#R(;&@\:(AH/#P\/#P\/&@\/#P\/#P\T M#P\Q#S$/,3$/-BPU,30U-BP/%1,"AXG)S\"$RD#&AL. M(0(G"2@=&PH3"@H:'R(:%0\:$0$!`106$!$*!@T'!0("!`('#A,K$PX3$PX. M`@<$!P(A*RL=*PX#'BD.'@,3'AT>*0,=*QX3#AP.*@(%!`8<'0H?"AL*(AH; M'Q\5(A4B&ALB&A\;&B(B&ALB&AL/&@\/#P\/#P\L#QH/#S4/+`\L-2P/,RP/ M-3$/,RP/&AX<(!PC%28)```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````!@)'0\;%2@="B$0```````````````````` M````````"0H3!@42&1D+&1(2!@,3#AP5'S<&'`,M`S$U&A$H"1`.'143'14: M"AH*+AHB#QLG`0$!"0H/#Q4&!PT"!P4-!`T.#@XI*RD.#@($!0("*`XI#A,I M'1,.'2LI$RD#*1X='A,J(1P"!`4"!!$3,`HN&BX?"@H:(A\;&Q\5'QHN&A\; M&@\:#QL:#QL/(@\;#P\/#S$/#P\/#P\T#RPQ#P\/,34Q#S8T,S0Q&BL&!B,5 M'P()"10````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````)%34;'AT>&`````````````````````````````D.%08( M"!D+&1D+%P81'1$%`@H=*0XJ+2T#-38/*0()`AX5#QX>'PH?(A\5'QHB&@X) M"0(A&S0S#QP,!P4$`@0"`A$.#@X.*PX"!P($#0(.'BL=*PX>#@,3*Q,#$PHI M$RL=#A$&!`@%!`81$PH?&@H?%0H5"AL?&A\:(AHN&A\5&Q\/'R(:#Q\:(AH; M&@\/&@\:#R(/#P\/#P\/#P\/#S,/#S,Q+#4/#Q4>#AP&(`H*$``````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`!0G+BP*)Q8``````````````````````````!@""A4&$A<+&1D9"P8&#AP& M!@0<(SHJ*0,M+0,Q,RP;"1`.#S8;(@H?%1H5&@HB&QLB'QLB"B83#P\:`@T% M!P(%#0<%#@X3#A,.`@("!@("#@X.*2L3*2LI'@XI$PX=*1,A#A$&!`0&"`8< M$PH*"A4N"@H?"A\*'Q45+A\;"A\?&R(:'Q4:&QH;#P\;(AH/#R(/#P\/#P\T M#P\/#S$U+`\Q+`\T#P\/&C`3*AP3)1,0%A8````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````)`@D0```` M````````````````````````"1T3!@42&1D9$A<&!@<%"P8&$R4F'2T#+0,G M-S,R-AL""1XS-"P:'Q4?"@H?'Q4?&AH;"A,5,`D"`A$'!P<'!@("!`<.*PXK M$2$'!00""1$.#AX.$P,.'0X=#@,=`Q$A`@8Y`@(%"`83'3`?&A\?"A\*&BX* M%1\;'R(5%1\*&QH:&B(;(@HB'QH:#QH/#P\;&@\B#QH/#P\/#QH/#P\/#S4Q M-@\/+C`*AX3$`$8)PT$`@(A`@8-`B$.#@X1`@4'!P(A#@XI M#@X.$PX>`RL.$PX.!@T(#0<&!`8&$P,*'PH5"@H5%0H*"A\*(@H:'Q4B"AH? M(A4B%14:(AH;(ALB#P\/#QH/#P\;#P\/#P\/#P\/#S4L#P\/#PH3!@0&(R,3 M"@D````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````!@"'14< M"PL2&1(9"P0%!`4(!`81)3XP+#$B`P,#&@\R,C4/$RLN&QL:"C@*%1\N"@H* M"@H3!A,*(1`8%B<*`@P%'!$"!PT"$2D<`@($"`(%*!$.*Q,.'2LI#A,I$R$A M`@8$`@0$!081'1X="@H*"@H*"A\?+A\5"AH*'PH*(AH;"AL5&B(:(AH:&Q\: M&AL/#P\:#P\/&AH/#P\/#P\/#P\Q#P\/&Q4J!@0&(!XF"0D0```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````"1X3!A(9%QD9&1(%!`@% M"`(6"08E%0\S#RDM+0\R,C(R,RP;#RPN%0H*%2(5'Q4?%0,1`B<>'QLA`1@> M"@,"#`(5"@8$`@<.#A$"`@(%`@<.#@X3#BL.'0X<#@($`@('!@8+"`83*1X* M`PH*'0H5"AT*"@H:"A\N"AL*&AL:+A\:(AHN%14B%2(5(@\B#QH:#R(;&AHB M#P\:#P\/+`\/#P\L#QT.!@82(Q4""0D8```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````&`()``````````D.%08(!1D+&1D+"P<%!`@$"0<"(QX;-C(/ M#BT#(C0S,C(R-C0U+!H*'2D*.`,?'0H=#@())PX*&R$0"1\B+0D,!P\;'`4' M#2$.!@<%`@(-`@X>#@XI$PX.$0("`@4'!@($!`42#A,#"@H=%0H*'PH*"A\5 M'PH*%0H?"@H5(A\:(A4?'QH?#QH*&AHB&AL:+B(/#P\B#QL/#P\/#P\Q#P\: M(A\=!@@$("`C'0D````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````6 M"B(1`````!`G"C``A08 M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````!@*+`H)````"0H3 M'`4+%QD9"P42"PT)$`D1("8/,RPN"ALV-`\*'@HI+0,Q+`,U,2L""2<))R!@('(",C)AH*&``````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````8&S(L(0D)'A4J$@L2&1D9"Q(%#!0"#A,&(",3"@H? M,`H*&A\5`RL>&BPB`RDM+2TM-R\W-R\M+RTO-RDO+R\O+0,M`RTI*0H*'`(3 M#S85!@T'!@("#`4'`@("`@0'!0(%`AP$!@0&'!,=$QX*'PH='1\*'14="@,* M'Q4*"AH*%0H*%0H5(@H5'PHB'QL?&RX:(A4B%1\;&AL:&B(:&P\?&QH;"AX" M!@4&("`3"@HH&!`4```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!8B,C,/&R(3(009&1<9$@0%"`"A\*'0H*'PH>'0H*"@H*"@H?"@H? M"A\*&@H?%1H?&A\:'QHB&AH*&Q\/(B(/#QL:#QL*`RH"!0@+$B8]%1$""0`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````&`H/-30L M&@8("QD9&0L7"P<"%!04!AP<$PH?'PH5.!\*"A\*'RX=$0H;"B,!T*'PH="@,*"AT*"A4?&PH.$1$A$0X.$0("$QT*`A`8"0D8"1@D M%B$*&A\)%@D8```4$1P3+#8L(P<%"`<"!0<$$0(&!P4+!`4$!@X3`PX#`PH# M'0H=`QXI"AT=`S@*"@H*"@H5"@H5'Q4?'PH5(A45'R(:'Q\:+AH;'R(5(AH/ M&QLB%1\5'A,"!087(!,F%28)%@D````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````"143!A<+&1D9"PL+!B,5%1,<$QX*"AT* M"@HX'0H?"@H*'0HB&P\5*PD)"04$$Q4""0D8````````````&`DA"0`````` M`!@&$QXL,@\5'`((`@4$#0(&!`((!`@&!@X=#AT='AT='0H="AT*"AT>*0H= M"@H*.`H>"@H*"@H*'Q4:'Q\5'R(:%1\5%2(5'QL:&BX:#P\B&@H<#A$<#@@+ M!B8/%2$H"1@````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````))@(("QD9"Q<2!!($)0\;,`H3'PH*"@HX"@H*"@H*"@H= M"A4/,P\;#A$"`@83"@D`````````````````````````````%`8<'BPR,Q4E M`@4"!00%!`8"!`@%!AP.*Q,="@H='@,="AT#"AT#'0,*"@H*'0H5"@H*"A4* M'PH*'PH?&Q\;&@H*'QL?&QHB'Q4B"A\;"A4*$P($!0(&("4C%1L>&``````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``D3(!<9%QD+"`L"*@X<$Q4;%0HX"C@*'PH?"AT*'0H=`QX5+A4L#Q4>"AL5 M*!00```````````````````````````````8$2HP#S0U#PH&`@0(`@@%!`@$ M`@8I'0X='@,=$P,3`QT#"@H='AT*'0,='AT*'PH="@H?'PH*%0H*%0H*%1\N M&B(:%1\:"AH5'QH*'0X.!@(%!@02'"`F%0H""1@````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````@HC(`L+!0@" M*A,'AX*)@8"!04(!`P"`B$.'1,I'BDI'2D= M"AT=%1T=`QT?"@H*"@H*"@H*,!\*'Q4?%0H*"@H?'Q\*'PH:+AHB&B(/(AT> M$Q$&`@07"`L2(Q4;&A$""1@````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````H&R,2(!((`@0"'B$1$PH*"@HX M"AT*'0,='0H3'1,K'`('!@\S#S,L"@\S#R$````````````````````````` M``````````<"`AP1#A,3!@@$"`4$!1$"$1TK`P,3$P,>$P,="A4?"@H>"@H* M.`HX"C`?'1T*"@H*'Q4B"@H?%0H5%0H*"@H?%0H;"A\=*08"!0<(!A(&("`C M"AL*%@`````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````"<5"B,7"Q<�(&!CDJ$P,=*1T*$P,3$QX.!@X" M!0(-`@83,S(U+`\=)AH/`@`````````````````````````````````4$1,Z M$QP'0H?"AT*"A\="AT="AT="AT*"@H;"AH*&A4? M(@H*"@X&*@("`@0%!`87"Q(E&Q4.!R<8```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````$`H5 M,"`7!!P&!`T""`T,#`T'#`<,#00(`@8&!A,C$R8N#S8L,S(T#Q,3"@D````` M````````````````````````````%@H5$R8E&0L7"`0$!P0$(0(.#A$.#A,I M$S@='1,#'1X#"@H*'AT="AT#"@H5"A\*'Q4?&A\*"@H?"@H*'2L3!@('"`4$ M"`8&(",C("45%2@````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````$0,5(QP<(R`&%P4$ M!04"`@0"`@0%!`8$!AXP%1X)%!`A%38V,C(S%1TH&``````````````````` M```````````````8%0\5(R`9"QD+%P8$!0(1!@("`@8A#@X.#@XK*1X=*1T= M'AT="AT*"@H*.`H?"AT*'1T>`Q,>'1,.#A$"!`8%!`4&"P87("`F%28)$`D6 M)``````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````!@*%24F,`85#R85)24C)2,C)3`F,!4: M"@()!P(G`@```"0)#C0R,BPI"10````````````````````````````````` M`!@)#ALE$AD9&0L9&0L$!`8"!P0"#0`Q,I"@,*"AT*"AT* M'0,=`QP<#AP"$0("`@(J!@4(!0L+"Q(@(QL/%0(H"20````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````8`AL;)0H3)PH;"B8>$R,C)1P3)AX*%1L*$``````````` M```)+B(/&R@````````````````````````````````````````)"B4C$B`9 M&1D9(!<2!`4""`4(`@0"`B$"`@X1$PX3`RD3*1TK#A,3*1,>$PX1`@("`@T$ M#`4(!!PA!!(&&2`@(R,E"AH*&``````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````4 M&`(3,"8>`@D4&`D6$!`4)!00%!`)%A8)"18````````````````6"0D6```` M```````````````````````````````````````6$`DF)2,@&0L+&2`@"PL& M"P8%"`4&`@8"!0("!@("!@("`@4'`@T%`@(A`@8'!00%"`4(!`8%(!P@%PLC M"ALP"1`)%A`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````"0.'A,;&R<````` M```````````````````````````````````````````````````````````` M````````````````````````````%@D)`A4C&1D9(!D9&0L+"P0%!`8"!`4$ M!`($`@("$08$!0<%"`<$!0<<`@0(!0@2"PL9&1DE,"8"%`<)"0D8```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````)`DH`AXP)1H*"0`````````````````` M```````````````````````````````````````````````````````````` M```````````````````)"B,&)1(9&1(+&1D+%PL7"Q<2!0@%"`0%!`(&`@0% M"`@&!0@(!@0&!!<2&2`7(R4@'",>'@D````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````!@),!43)285(1`````````````````````````````````` M```````````````````````````````````````````````````````````` M`````"00%@(5%24@&1D2&1D9&2`9"Q<9$A(+"PL&(!(2"Q(9"PL9&2`+%R`9 M%P0@$Q,F%0H6%!80```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M"0H3$R8A"0D8```````````````````````````````````````````````` M````````````````````````````````````````````````````````&"@) M"0(5&QLC)1(@$AD7&0L9&1D+&1(2&0L9$AD9&2`E(R,5%14"#1`'$`DH"1`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````!81"B4E$PT````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````$`H:%2,@!A<2 M!1(C(R`2(Q(C(!(C(!(2$@@2("`3$R4F+@D````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````8$!@)$PHE%0H)```````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````%A`8$``4%!`6'AH5&Q45)B85 M)AH5&PH,%``4"100"1`6```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````!`*%1,C)A43"1@````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````!0)(0DG`@DA"0(H)PDG"20````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````D M$1\;'B,J'B<````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````&"`A08```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````"0>"B45)@(````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````8"0H5'A4>%@`````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````````!00 M%@D3)3`F(1````````````````````````````````$!`0`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````!`0$!`0$!```` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````)PH Debug Win32 Debug x64 Release Win32 Release x64 {CEC5D360-8804-454F-8591-002184C23499} NetHackW Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\Release\ .\Release\ .\Release\ .\Release\ false false .\Debug\ .\Debug\ .\Debug\ .\Debug\ true true NDEBUG;%(PreprocessorDefinitions) true true Win32 .\Release/NetHackW.tlb /Gs /Oi- %(AdditionalOptions) Disabled OnlyExplicitInline Speed true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/NetHackW.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x0409 /MAPINFO:EXPORTS %(AdditionalOptions) comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\Release/NetHackW.pdb true .\Release/NetHackW.map Windows false MachineX86 true .\Release/NetHackW.bsc Install exe copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh NDEBUG;%(PreprocessorDefinitions) true true .\Release/NetHackW.tlb /Gs /Oi- %(AdditionalOptions) Disabled OnlyExplicitInline Speed true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/NetHackW.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x0409 /MAPINFO:EXPORTS %(AdditionalOptions) comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\Release/NetHackW.pdb true .\Release/NetHackW.map Windows false true .\Release/NetHackW.bsc Install exe copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh _DEBUG;%(PreprocessorDefinitions) true true Win32 .\Debug/NetHackW.tlb Disabled ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/NetHackW.pch .\Debug/ .\Debug/ .\Debug/ Level3 true EditAndContinue _DEBUG;%(PreprocessorDefinitions) 0x0409 comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\Debug/NetHackW.pdb Windows false MachineX86 true .\Debug/NetHackW.bsc Install exe if NOT exist ..\binary\*.* mkdir ..\binary copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary copy ..\dat\symbols ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh _DEBUG;%(PreprocessorDefinitions) true true .\Debug/NetHackW.tlb Disabled ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/NetHackW.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x0409 comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\Debug/NetHackW.pdb Windows false true .\Debug/NetHackW.bsc Install exe if NOT exist ..\binary\*.* mkdir ..\binary copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary copy ..\dat\symbols ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) ..\win\win32;%(AdditionalIncludeDirectories) ..\win\win32;%(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) ..\win\win32;%(AdditionalIncludeDirectories) ..\win\win32;%(AdditionalIncludeDirectories) {8a3f81c7-2968-49a8-86bf-2669412ad7de} false {0303a585-3f83-4bb7-af6b-1e12c8fb54ac} false {9dd9c52e-e8c9-4533-bd22-83c055c0aaba} false {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false {93f10526-209e-41d7-bbea-775787876895} false {55946465-fc65-47b3-bb48-742c7694c0d6} false {63f9b82b-f589-4082-abe5-d4f0682050ab} false nethack-3.6.0/win/win32/vs2010/dgncomp.vcxproj0000664000076400007660000005342112536476415017715 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {8A3F81C7-2968-49A8-86BF-2669412AD7DE} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\..\util\ .\..\util\ .\Debug\ .\Debug\ false false .\..\util/dgncomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dgncomp.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/dgncomp.pdb Console false MachineX86 true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build .\..\util/dgncomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dgncomp.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/dgncomp.pdb Console false true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build .\..\util/dgncomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/dgncomp.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\..\util/dgncomp.pdb Console false MachineX86 true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build .\..\util/dgncomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/dgncomp.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\..\util/dgncomp.pdb Console false true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {b9e02f2c-8851-442b-bf2a-3581802b78d4} false nethack-3.6.0/win/win32/vs2010/dgnstuff.vcxproj0000664000076400007660000002236612536476415020112 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {B9E02F2C-8851-442B-BF2A-3581802B78D4} MakeFileProj Makefile false Makefile false Makefile false Makefile false <_ProjectFileVersion>10.0.30319.1 .\dgnstuff___Win32_Debug\ .\dgnstuff___Win32_Debug\ .\Debug\ .\Debug\ nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" /a nmake /f "dgnstuff.mak" /a ..\util\dgncomp.exe ..\util\dgncomp.exe $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) .\Release\ .\Release\ .\Release\ .\Release\ nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" /a nmake /f "dgnstuff.mak" /a ..\util\dgncomp.exe ..\util\dgncomp.exe $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2010/dlb_main.vcxproj0000664000076400007660000005333712536476415020041 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\..\util\ .\..\util\ .\Debug\ .\Debug\ false false .\Release/dlb_main.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dlb_main.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/dlb_main.pdb Console false MachineX86 true .\Release/dlb_main.bsc Packaging via DLB echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary .\Release/dlb_main.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dlb_main.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/dlb_main.pdb Console false true .\Release/dlb_main.bsc Packaging via DLB echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary .\Debug/dlb_main.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/dlb_main.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/dlb_main.pdb Console false MachineX86 true .\Debug/dlb_main.bsc Packaging via dlb echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary .\Debug/dlb_main.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/dlb_main.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/dlb_main.pdb Console false true .\Debug/dlb_main.bsc Packaging via dlb echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {8a3f81c7-2968-49a8-86bf-2669412ad7de} false {9dd9c52e-e8c9-4533-bd22-83c055c0aaba} false {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2010/levcomp.vcxproj0000664000076400007660000007166712536476415017747 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\..\util\ .\..\util\ .\Debug\ .\Debug\ false false .\..\util/levcomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;YY_NO_UNISTD_H;%(PreprocessorDefinitions) true MultiThreaded true .\Release/levcomp.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/levcomp.pdb Console false MachineX86 true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build .\..\util/levcomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;YY_NO_UNISTD_H;%(PreprocessorDefinitions) true MultiThreaded true .\Release/levcomp.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/levcomp.pdb Console false true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build .\..\util/levcomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;YY_NO_UNISTD_H;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/levcomp.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\..\util/levcomp.pdb Console false MachineX86 true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build .\..\util/levcomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;YY_NO_UNISTD_H;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/levcomp.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\..\util/levcomp.pdb Console false true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {ff144dfb-83a5-4d26-a598-715a2b354782} false nethack-3.6.0/win/win32/vs2010/levstuff.vcxproj0000664000076400007660000002242412536476415020123 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {FF144DFB-83A5-4D26-A598-715A2B354782} MakeFileProj Makefile false Makefile false Makefile false Makefile false <_ProjectFileVersion>10.0.30319.1 .\Release\ .\Release\ .\Release\ .\Release\ nmake /f "levstuff.mak" nmake /f "levstuff.mak" nmake /f "levstuff.mak" /a nmake /f "levstuff.mak" /a ..\util\lev_lex.c ..\util\lev_lex.c $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) .\levstuff___Win32_Debug0\ .\levstuff___Win32_Debug0\ .\levstuff___Win32_Debug0\ .\levstuff___Win32_Debug0\ nmake /f "levstuff.mak" nmake /f "levstuff.mak" nmake /f "levstuff.mak" /a nmake /f "levstuff.mak" /a ..\util\lev_lex.c ..\util\lev_lex.c $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2010/makedefs.vcxproj0000664000076400007660000005014212536476415020042 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {BA3DD34C-04B7-40D0-B373-9329AA9E8945} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\..\util\ .\..\util\ .\Debug\ .\Debug\ false false .\..\util/makedefs.tlb MaxSpeed OnlyExplicitInline .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/makedefs.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\..\util/makedefs.pdb Console false MachineX86 true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c .\..\util/makedefs.tlb MaxSpeed OnlyExplicitInline .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/makedefs.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\..\util/makedefs.pdb Console false true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c .\..\util/makedefs.tlb Disabled .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/makedefs.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\..\util/makedefs.pdb Console false MachineX86 true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c .\..\util/makedefs.tlb Disabled .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/makedefs.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\..\util/makedefs.pdb Console false true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2010/recover.vcxproj0000664000076400007660000003626212536476415017737 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\ .\Debug\ true true .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\Debug/recover.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/recover.pch .\Debug/ .\Debug/ .\Debug/ Level3 true EditAndContinue _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/recover.pdb Console false MachineX86 true .\Debug/recover.bsc install exe copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt .\Debug/recover.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/recover.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/recover.pdb Console false true .\Debug/recover.bsc install exe copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt .\Release/recover.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/recover.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/recover.pdb Console false MachineX86 true .\Release/recover.bsc copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt .\Release/recover.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/recover.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/recover.pdb Console false true .\Release/recover.bsc copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {0303a585-3f83-4bb7-af6b-1e12c8fb54ac} false {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2010/tile2bmp.vcxproj0000664000076400007660000005211112536476415017777 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {642BC75D-ABAF-403E-8224-7C725FD4CB42} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\ .\Debug\ true true .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\Debug/tile2bmp.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/tile2bmp.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/tile2bmp.pdb Console false MachineX86 true .\Debug/tile2bmp.bsc .\Debug/tile2bmp.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/tile2bmp.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/tile2bmp.pdb Console false true .\Debug/tile2bmp.bsc .\Release/tile2bmp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tile2bmp.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tile2bmp.pdb Console false MachineX86 true .\Release/tile2bmp.bsc .\Release/tile2bmp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tile2bmp.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tile2bmp.pdb Console false true .\Release/tile2bmp.bsc %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) PACKED_FILE;%(PreprocessorDefinitions) PACKED_FILE;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) TILETEXT;%(PreprocessorDefinitions) TILETEXT;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) TILETEXT;%(PreprocessorDefinitions) TILETEXT;%(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2010/tilemap.vcxproj0000664000076400007660000004076312536476415017726 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {93F10526-209E-41D7-BBEA-775787876895} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\ .\Debug\ false false .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\Debug/tilemap.tlb Disabled ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/tilemap.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/tilemap.pdb Console false MachineX86 true .\Debug/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build .\Debug/tilemap.tlb Disabled ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/tilemap.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\Debug/tilemap.pdb Console false true .\Debug/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build .\Release/tilemap.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tilemap.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tilemap.pdb Console false MachineX86 true .\Release/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build .\Release/tilemap.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tilemap.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tilemap.pdb Console false true .\Release/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2010/tiles.vcxproj0000664000076400007660000002231412536476415017403 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {55946465-FC65-47B3-BB48-742C7694C0D6} MakeFileProj Makefile false Makefile false Makefile false Makefile false <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\ .\Debug\ nmake /f "tiles.mak" nmake /f "tiles.mak" nmake /f "tiles.mak" /a nmake /f "tiles.mak" /a ..\win\win32\tiles.bmp ..\win\win32\tiles.bmp $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) .\..\util\ .\..\util\ .\Release\ .\Release\ nmake /f "tiles.mak" nmake /f "tiles.mak" nmake /f "tiles.mak" /a nmake /f "tiles.mak" /a ..\win\win32\tiles.bmp ..\win\win32\tiles.bmp $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) {642bc75d-abaf-403e-8224-7c725fd4cb42} false nethack-3.6.0/win/win32/vs2010/uudecode.vcxproj0000664000076400007660000004001612541713002020035 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {63F9B82B-F589-4082-ABE5-D4F0682050AB} Application false MultiByte Application false MultiByte Windows7.1SDK Application false MultiByte Application false MultiByte Windows7.1SDK <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Release\ .\Release\ false false .\Debug\ .\Debug\ true true .\..\util\ .\..\util\ .\Release/uudecode.tlb MaxSpeed OnlyExplicitInline WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true MultiThreaded true .\Release/uudecode.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\Release/uudecode.pdb Console false MachineX86 true .\Release/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary .\Release/uudecode.tlb MaxSpeed OnlyExplicitInline WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true MultiThreaded true .\Release/uudecode.pch .\Release/ .\Release/ .\Release/ Level3 true NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\Release/uudecode.pdb Console false true .\Release/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary .\Debug/uudecode.tlb Disabled WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/uudecode.pch .\Debug/ .\Debug/ .\Debug/ Level3 true EditAndContinue _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\Debug/uudecode.pdb Console false MachineX86 true .\Debug/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary .\Debug/uudecode.tlb Disabled WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/uudecode.pch .\Debug/ .\Debug/ .\Debug/ Level3 true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\Debug/uudecode.pdb Console false true .\Debug/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2013/NetHack.sln0000664000076400007660000003077412536476415016715 0ustar paxedpaxed Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2013 for Windows Desktop VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetHackW", "build\NetHackW.vcxproj", "{CEC5D360-8804-454F-8591-002184C23499}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dgncomp", "build\dgncomp.vcxproj", "{8A3F81C7-2968-49A8-86BF-2669412AD7DE}" ProjectSection(ProjectDependencies) = postProject {642BC75D-ABAF-403E-8224-7C725FD4CB42} = {642BC75D-ABAF-403E-8224-7C725FD4CB42} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dgnstuff", "build\dgnstuff.vcxproj", "{B9E02F2C-8851-442B-BF2A-3581802B78D4}" ProjectSection(ProjectDependencies) = postProject {FF144DFB-83A5-4D26-A598-715A2B354782} = {FF144DFB-83A5-4D26-A598-715A2B354782} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlb_main", "build\dlb_main.vcxproj", "{0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "levcomp", "build\levcomp.vcxproj", "{9DD9C52E-E8C9-4533-BD22-83C055C0AABA}" ProjectSection(ProjectDependencies) = postProject {B9E02F2C-8851-442B-BF2A-3581802B78D4} = {B9E02F2C-8851-442B-BF2A-3581802B78D4} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "levstuff", "build\levstuff.vcxproj", "{FF144DFB-83A5-4D26-A598-715A2B354782}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makedefs", "build\makedefs.vcxproj", "{BA3DD34C-04B7-40D0-B373-9329AA9E8945}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recover", "build\recover.vcxproj", "{2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tile2bmp", "build\tile2bmp.vcxproj", "{642BC75D-ABAF-403E-8224-7C725FD4CB42}" ProjectSection(ProjectDependencies) = postProject {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} = {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tilemap", "build\tilemap.vcxproj", "{93F10526-209E-41D7-BBEA-775787876895}" ProjectSection(ProjectDependencies) = postProject {8A3F81C7-2968-49A8-86BF-2669412AD7DE} = {8A3F81C7-2968-49A8-86BF-2669412AD7DE} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tiles", "build\tiles.vcxproj", "{55946465-FC65-47B3-BB48-742C7694C0D6}" ProjectSection(ProjectDependencies) = postProject {93F10526-209E-41D7-BBEA-775787876895} = {93F10526-209E-41D7-BBEA-775787876895} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uudecode", "build\uudecode.vcxproj", "{63F9B82B-F589-4082-ABE5-D4F0682050AB}" ProjectSection(ProjectDependencies) = postProject {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetHack", "build\NetHack.vcxproj", "{609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}" ProjectSection(ProjectDependencies) = postProject {63F9B82B-F589-4082-ABE5-D4F0682050AB} = {63F9B82B-F589-4082-ABE5-D4F0682050AB} {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} = {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} = {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} {8A3F81C7-2968-49A8-86BF-2669412AD7DE} = {8A3F81C7-2968-49A8-86BF-2669412AD7DE} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nhdefkey", "build\nhdefkey.vcxproj", "{6813477F-64B6-4B97-B230-438D0D233385}" ProjectSection(ProjectDependencies) = postProject {BA3DD34C-04B7-40D0-B373-9329AA9E8945} = {BA3DD34C-04B7-40D0-B373-9329AA9E8945} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CEC5D360-8804-454F-8591-002184C23499}.Debug|Win32.ActiveCfg = Debug|Win32 {CEC5D360-8804-454F-8591-002184C23499}.Debug|Win32.Build.0 = Debug|Win32 {CEC5D360-8804-454F-8591-002184C23499}.Debug|x64.ActiveCfg = Debug|x64 {CEC5D360-8804-454F-8591-002184C23499}.Debug|x64.Build.0 = Debug|x64 {CEC5D360-8804-454F-8591-002184C23499}.Release|Win32.ActiveCfg = Release|Win32 {CEC5D360-8804-454F-8591-002184C23499}.Release|Win32.Build.0 = Release|Win32 {CEC5D360-8804-454F-8591-002184C23499}.Release|x64.ActiveCfg = Release|x64 {CEC5D360-8804-454F-8591-002184C23499}.Release|x64.Build.0 = Release|x64 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|Win32.ActiveCfg = Debug|Win32 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|Win32.Build.0 = Debug|Win32 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|x64.ActiveCfg = Debug|x64 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Debug|x64.Build.0 = Debug|x64 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|Win32.ActiveCfg = Release|Win32 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|Win32.Build.0 = Release|Win32 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|x64.ActiveCfg = Release|x64 {8A3F81C7-2968-49A8-86BF-2669412AD7DE}.Release|x64.Build.0 = Release|x64 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Debug|Win32.ActiveCfg = Debug|Win32 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Debug|Win32.Build.0 = Debug|Win32 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Debug|x64.ActiveCfg = Debug|x64 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Debug|x64.Build.0 = Debug|x64 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Release|Win32.ActiveCfg = Release|Win32 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Release|Win32.Build.0 = Release|Win32 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Release|x64.ActiveCfg = Release|x64 {B9E02F2C-8851-442B-BF2A-3581802B78D4}.Release|x64.Build.0 = Release|x64 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|Win32.ActiveCfg = Debug|Win32 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|Win32.Build.0 = Debug|Win32 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|x64.ActiveCfg = Debug|x64 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Debug|x64.Build.0 = Debug|x64 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|Win32.ActiveCfg = Release|Win32 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|Win32.Build.0 = Release|Win32 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|x64.ActiveCfg = Release|x64 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}.Release|x64.Build.0 = Release|x64 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|Win32.ActiveCfg = Debug|Win32 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|Win32.Build.0 = Debug|Win32 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|x64.ActiveCfg = Debug|x64 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Debug|x64.Build.0 = Debug|x64 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|Win32.ActiveCfg = Release|Win32 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|Win32.Build.0 = Release|Win32 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|x64.ActiveCfg = Release|x64 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA}.Release|x64.Build.0 = Release|x64 {FF144DFB-83A5-4D26-A598-715A2B354782}.Debug|Win32.ActiveCfg = Debug|Win32 {FF144DFB-83A5-4D26-A598-715A2B354782}.Debug|Win32.Build.0 = Debug|Win32 {FF144DFB-83A5-4D26-A598-715A2B354782}.Debug|x64.ActiveCfg = Debug|x64 {FF144DFB-83A5-4D26-A598-715A2B354782}.Debug|x64.Build.0 = Debug|x64 {FF144DFB-83A5-4D26-A598-715A2B354782}.Release|Win32.ActiveCfg = Release|Win32 {FF144DFB-83A5-4D26-A598-715A2B354782}.Release|Win32.Build.0 = Release|Win32 {FF144DFB-83A5-4D26-A598-715A2B354782}.Release|x64.ActiveCfg = Release|x64 {FF144DFB-83A5-4D26-A598-715A2B354782}.Release|x64.Build.0 = Release|x64 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|Win32.ActiveCfg = Debug|Win32 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|Win32.Build.0 = Debug|Win32 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|x64.ActiveCfg = Debug|x64 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Debug|x64.Build.0 = Debug|x64 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|Win32.ActiveCfg = Release|Win32 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|Win32.Build.0 = Release|Win32 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|x64.ActiveCfg = Release|x64 {BA3DD34C-04B7-40D0-B373-9329AA9E8945}.Release|x64.Build.0 = Release|x64 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|Win32.ActiveCfg = Debug|Win32 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|Win32.Build.0 = Debug|Win32 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|x64.ActiveCfg = Debug|x64 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Debug|x64.Build.0 = Debug|x64 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|Win32.ActiveCfg = Release|Win32 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|Win32.Build.0 = Release|Win32 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|x64.ActiveCfg = Release|x64 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E}.Release|x64.Build.0 = Release|x64 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|Win32.ActiveCfg = Debug|Win32 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|Win32.Build.0 = Debug|Win32 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|x64.ActiveCfg = Debug|x64 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Debug|x64.Build.0 = Debug|x64 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|Win32.ActiveCfg = Release|Win32 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|Win32.Build.0 = Release|Win32 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|x64.ActiveCfg = Release|x64 {642BC75D-ABAF-403E-8224-7C725FD4CB42}.Release|x64.Build.0 = Release|x64 {93F10526-209E-41D7-BBEA-775787876895}.Debug|Win32.ActiveCfg = Debug|Win32 {93F10526-209E-41D7-BBEA-775787876895}.Debug|Win32.Build.0 = Debug|Win32 {93F10526-209E-41D7-BBEA-775787876895}.Debug|x64.ActiveCfg = Debug|x64 {93F10526-209E-41D7-BBEA-775787876895}.Debug|x64.Build.0 = Debug|x64 {93F10526-209E-41D7-BBEA-775787876895}.Release|Win32.ActiveCfg = Release|Win32 {93F10526-209E-41D7-BBEA-775787876895}.Release|Win32.Build.0 = Release|Win32 {93F10526-209E-41D7-BBEA-775787876895}.Release|x64.ActiveCfg = Release|x64 {93F10526-209E-41D7-BBEA-775787876895}.Release|x64.Build.0 = Release|x64 {55946465-FC65-47B3-BB48-742C7694C0D6}.Debug|Win32.ActiveCfg = Debug|Win32 {55946465-FC65-47B3-BB48-742C7694C0D6}.Debug|Win32.Build.0 = Debug|Win32 {55946465-FC65-47B3-BB48-742C7694C0D6}.Debug|x64.ActiveCfg = Debug|x64 {55946465-FC65-47B3-BB48-742C7694C0D6}.Debug|x64.Build.0 = Debug|x64 {55946465-FC65-47B3-BB48-742C7694C0D6}.Release|Win32.ActiveCfg = Release|Win32 {55946465-FC65-47B3-BB48-742C7694C0D6}.Release|Win32.Build.0 = Release|Win32 {55946465-FC65-47B3-BB48-742C7694C0D6}.Release|x64.ActiveCfg = Release|x64 {55946465-FC65-47B3-BB48-742C7694C0D6}.Release|x64.Build.0 = Release|x64 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|Win32.ActiveCfg = Debug|Win32 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|Win32.Build.0 = Debug|Win32 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|x64.ActiveCfg = Debug|x64 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Debug|x64.Build.0 = Debug|x64 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|Win32.ActiveCfg = Release|Win32 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|Win32.Build.0 = Release|Win32 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|x64.ActiveCfg = Release|x64 {63F9B82B-F589-4082-ABE5-D4F0682050AB}.Release|x64.Build.0 = Release|x64 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|Win32.ActiveCfg = Debug|Win32 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|Win32.Build.0 = Debug|Win32 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Debug|x64.ActiveCfg = Debug|Win32 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|Win32.ActiveCfg = Release|Win32 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|Win32.Build.0 = Release|Win32 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751}.Release|x64.ActiveCfg = Release|Win32 {6813477F-64B6-4B97-B230-438D0D233385}.Debug|Win32.ActiveCfg = Debug|Win32 {6813477F-64B6-4B97-B230-438D0D233385}.Debug|Win32.Build.0 = Debug|Win32 {6813477F-64B6-4B97-B230-438D0D233385}.Debug|x64.ActiveCfg = Debug|x64 {6813477F-64B6-4B97-B230-438D0D233385}.Debug|x64.Build.0 = Debug|x64 {6813477F-64B6-4B97-B230-438D0D233385}.Release|Win32.ActiveCfg = Release|Win32 {6813477F-64B6-4B97-B230-438D0D233385}.Release|Win32.Build.0 = Release|Win32 {6813477F-64B6-4B97-B230-438D0D233385}.Release|x64.ActiveCfg = Release|x64 {6813477F-64B6-4B97-B230-438D0D233385}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal nethack-3.6.0/win/win32/vs2013/NetHack.vcxproj0000664000076400007660000006555712536476415017623 0ustar paxedpaxed Release Win32 Release x64 Debug Win32 Debug x64 {609BC774-C6F8-4B2B-AA7D-5B3D0EA95751} Win32Proj NetHack Application true v120 MultiByte Application false MultiByte v120 Application false v120 true MultiByte Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\Release\ .\Release\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\Debug\ .\Debug\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true /Gs /Oi- /FS %(AdditionalOptions) Disabled Level3 Default Speed true MaxSpeed true false TILES;MSWIN_GRAPHICS;WIN32;WIN32CON;DLB;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) true MultiThreaded true .\Release/NetHack.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false Console true true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;%(AdditionalDependencies) true true .\Release/NetHack.pdb true .\Release/NetHack.map MachineX86 true true .\Release/NetHack.bsc Install exe copy $(OutDir)NetHack.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh /Gs /Oi- /FS %(AdditionalOptions) Disabled Level3 Default Speed true MaxSpeed true false TILES;MSWIN_GRAPHICS;WIN32;WIN32CON;DLB;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) true MultiThreaded true .\Release/NetHack.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false Console true true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Winmm.lib;%(AdditionalDependencies) true true .\Release/NetHack.pdb true .\Release/NetHack.map true .\Release/NetHack.bsc Install exe copy $(OutDir)NetHack.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh /Gs /Oi- /FS %(AdditionalOptions) Disabled Default Speed true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) TILES;MSWIN_GRAPHICS;NDEBUG;WIN32;WIN32CON;DLB;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true true MultiThreadedDebug true .\Debug/NetHack.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false .\Release/NetHack.pdb true .\Release/NetHack.map Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Winmm.lib;%(AdditionalDependencies) MachineX86 true .\Debug/NetHack.bsc Install exe if NOT exist ..\binary\*.* mkdir ..\binary copy $(OutDir)NetHack.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary copy ..\dat\symbols ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh /Gs /Oi- /FS %(AdditionalOptions) Disabled Default Speed true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) TILES;MSWIN_GRAPHICS;WIN32;WIN32CON;DLB;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true true MultiThreadedDebug true .\Debug/NetHack.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false .\Release/NetHack.pdb true .\Release/NetHack.map Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;%(AdditionalDependencies) /SAFESEH:NO %(AdditionalOptions) true .\Debug/NetHack.bsc Install exe if NOT exist ..\binary\*.* mkdir ..\binary copy $(OutDir)NetHack.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary copy ..\dat\symbols ..\binary if exist tiles.bmp copy tiles.bmp ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh GUISTUB;NDEBUG;WIN32;WIN32CON;DLB;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) GUISTUB;WIN32;WIN32CON;DLB;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) GUISTUB;WIN32;WIN32CON;DLB;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) GUISTUB;WIN32;WIN32CON;DLB;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2013/NetHackW.vcxproj0000664000076400007660000006545612541713002017726 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {CEC5D360-8804-454F-8591-002184C23499} NetHackW Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\Release\ .\Release\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\Debug\ .\Debug\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true NDEBUG;%(PreprocessorDefinitions) true true Win32 .\Release/NetHackW.tlb /Gs /Oi- /FS %(AdditionalOptions) Disabled OnlyExplicitInline Speed true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) TILES;MSWIN_GRAPHICS;WIN32CONNDEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/NetHackW.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false NDEBUG;%(PreprocessorDefinitions) 0x0409 /MAPINFO:EXPORTS %(AdditionalOptions) comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\Release/NetHackW.pdb true .\Release/NetHackW.map Windows false MachineX86 true .\Release/NetHackW.bsc Install exe copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh NDEBUG;%(PreprocessorDefinitions) true true .\Release/NetHackW.tlb /Gs /Oi- /FS %(AdditionalOptions) Disabled OnlyExplicitInline Speed true ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) TILES;MSWIN_GRAPHICS;WIN32CONNDEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/NetHackW.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false NDEBUG;%(PreprocessorDefinitions) 0x0409 /MAPINFO:EXPORTS %(AdditionalOptions) comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\Release/NetHackW.pdb true .\Release/NetHackW.map Windows false true .\Release/NetHackW.bsc Install exe copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh _DEBUG;%(PreprocessorDefinitions) true true Win32 .\Debug/NetHackW.tlb Disabled ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) TILES;MSWIN_GRAPHICS;WIN32CON_DEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/NetHackW.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /Gs /Oi- /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x0409 comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\$(ConfigurationName)\$(ProjectName)\ Windows false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\Debug/NetHackW.bsc Install exe if NOT exist ..\binary\*.* mkdir ..\binary copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary copy ..\dat\symbols ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh _DEBUG;%(PreprocessorDefinitions) true true .\Debug/NetHackW.tlb Disabled ..\win\win32;..\include;..\sys\winnt;..\sys\share;..\win\share;%(AdditionalIncludeDirectories) TILES;MSWIN_GRAPHICS;WIN32CON_DEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/NetHackW.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true ProgramDatabase false /Gs /Oi- /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x0409 comctl32.lib;winmm.lib;%(AdditionalDependencies) true true .\$(ConfigurationName)\$(ProjectName)\ Windows false /SAFESEH:NO %(AdditionalOptions) true .\Debug/NetHackW.bsc Install exe if NOT exist ..\binary\*.* mkdir ..\binary copy $(OutDir)NetHackW.exe ..\binary copy ..\dat\nhdat ..\binary copy ..\dat\license ..\binary copy ..\dat\symbols ..\binary if NOT exist ..\binary\sysconf copy ..\sys\winnt\sysconf ..\binary\sysconf if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh TTYSTUB; _DEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) TTYSTUB;NDEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) TTYSTUB; _DEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) TTYSTUB;NDEBUG;WIN32;_WINDOWS;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) {8a3f81c7-2968-49a8-86bf-2669412ad7de} false {0303a585-3f83-4bb7-af6b-1e12c8fb54ac} false {9dd9c52e-e8c9-4533-bd22-83c055c0aaba} false {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false {93f10526-209e-41d7-bbea-775787876895} false {55946465-fc65-47b3-bb48-742c7694c0d6} false false false true false {63f9b82b-f589-4082-abe5-d4f0682050ab} false nethack-3.6.0/win/win32/vs2013/dgncomp.vcxproj0000664000076400007660000005653412536476415017730 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {8A3F81C7-2968-49A8-86BF-2669412AD7DE} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util/dgncomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dgncomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/dgncomp.pdb Console false MachineX86 true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build .\..\util/dgncomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dgncomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/dgncomp.pdb Console false true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build .\..\util/dgncomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/dgncomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build .\..\util/dgncomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/dgncomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\..\util/dgncomp.bsc dgncomp echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgncomp.exe dungeon.pdf ..\util\dgncomp.exe dungeon.pdf echo chdir ..\build chdir ..\build %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {b9e02f2c-8851-442b-bf2a-3581802b78d4} false nethack-3.6.0/win/win32/vs2013/dgnstuff.vcxproj0000664000076400007660000002265412536476415020115 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {B9E02F2C-8851-442B-BF2A-3581802B78D4} MakeFileProj Makefile false v120 Makefile false v120 Makefile false v120 Makefile false v120 <_ProjectFileVersion>10.0.30319.1 .\dgnstuff___Win32_Debug\ .\dgnstuff___Win32_Debug\ .\Debug\ .\Debug\ nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" /a nmake /f "dgnstuff.mak" /a ..\util\dgncomp.exe ..\util\dgncomp.exe $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) .\Release\ .\Release\ .\Release\ .\Release\ nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" nmake /f "dgnstuff.mak" /a nmake /f "dgnstuff.mak" /a ..\util\dgncomp.exe ..\util\dgncomp.exe $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2013/dlb_main.vcxproj0000664000076400007660000005674012536476415020045 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {0303A585-3F83-4BB7-AF6B-1E12C8FB54AC} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\Release/dlb_main.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dlb_main.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/dlb_main.pdb Console false MachineX86 true .\Release/dlb_main.bsc Packaging via DLB echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo tribute >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary .\Release/dlb_main.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/dlb_main.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/dlb_main.pdb Console false true .\Release/dlb_main.bsc Packaging via DLB echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo tribute >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary .\Debug/dlb_main.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/dlb_main.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\Debug/dlb_main.bsc Packaging via dlb echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo tribute >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary .\Debug/dlb_main.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;DLB;WIN32CON;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/dlb_main.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\Debug/dlb_main.bsc Packaging via dlb echo chdir ..\dat chdir ..\dat chdir echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo tribute >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst ..\util\dlb_main.exe cIf dlb.lst nhdat echo chdir ..\build chdir ..\build echo if NOT exist ..\binary\*.* mkdir ..\binary if NOT exist ..\binary\*.* mkdir ..\binary %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {8a3f81c7-2968-49a8-86bf-2669412ad7de} false {9dd9c52e-e8c9-4533-bd22-83c055c0aaba} false {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2013/levcomp.vcxproj0000664000076400007660000007500012536476415017733 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {9DD9C52E-E8C9-4533-BD22-83C055C0AABA} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util/levcomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;YY_NO_UNISTD_H;%(PreprocessorDefinitions) true MultiThreaded true .\Release/levcomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/levcomp.pdb Console false MachineX86 true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build .\..\util/levcomp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;YY_NO_UNISTD_H;%(PreprocessorDefinitions) true MultiThreaded true .\Release/levcomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\..\util/levcomp.pdb Console false true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build .\..\util/levcomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;YY_NO_UNISTD_H;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/levcomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build .\..\util/levcomp.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;YY_NO_UNISTD_H;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/levcomp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\..\util/levcomp.bsc levcomp echo Building special levels echo chdir ..\dat chdir ..\dat echo arch.des ..\util\levcomp.exe arch.des echo barb.des ..\util\levcomp.exe barb.des echo bigroom.des ..\util\levcomp.exe bigroom.des echo castle.des ..\util\levcomp.exe castle.des echo caveman.des ..\util\levcomp.exe caveman.des echo endgame.des ..\util\levcomp.exe endgame.des echo gehennom.des ..\util\levcomp.exe gehennom.des echo healer.des ..\util\levcomp.exe healer.des echo knight.des ..\util\levcomp.exe knight.des echo knox.des ..\util\levcomp.exe knox.des echo medusa.des ..\util\levcomp.exe medusa.des echo mines.des ..\util\levcomp.exe mines.des echo monk.des ..\util\levcomp.exe monk.des echo oracle.des ..\util\levcomp.exe oracle.des echo priest.des ..\util\levcomp.exe priest.des echo ranger.des ..\util\levcomp.exe ranger.des echo rogue.des ..\util\levcomp.exe rogue.des echo samurai.des ..\util\levcomp.exe samurai.des echo sokoban.des ..\util\levcomp.exe sokoban.des echo tourist.des ..\util\levcomp.exe tourist.des echo tower.des ..\util\levcomp.exe tower.des echo valkyrie.des ..\util\levcomp.exe valkyrie.des echo wizard .des ..\util\levcomp.exe wizard.des echo yendor.des ..\util\levcomp.exe yendor.des echo chdir ..\build chdir ..\build %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {ff144dfb-83a5-4d26-a598-715a2b354782} false nethack-3.6.0/win/win32/vs2013/levstuff.vcxproj0000664000076400007660000002271212536476415020126 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {FF144DFB-83A5-4D26-A598-715A2B354782} MakeFileProj Makefile false v120 Makefile false v120 Makefile false v120 Makefile false v120 <_ProjectFileVersion>10.0.30319.1 .\Release\ .\Release\ .\Release\ .\Release\ nmake /f "levstuff.mak" nmake /f "levstuff.mak" nmake /f "levstuff.mak" /a nmake /f "levstuff.mak" /a ..\util\lev_lex.c ..\util\lev_lex.c $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) .\levstuff___Win32_Debug0\ .\levstuff___Win32_Debug0\ .\levstuff___Win32_Debug0\ .\levstuff___Win32_Debug0\ nmake /f "levstuff.mak" nmake /f "levstuff.mak" nmake /f "levstuff.mak" /a nmake /f "levstuff.mak" /a ..\util\lev_lex.c ..\util\lev_lex.c $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2013/makedefs.vcxproj0000664000076400007660000005316412536476415020054 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {BA3DD34C-04B7-40D0-B373-9329AA9E8945} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util/makedefs.tlb MaxSpeed OnlyExplicitInline .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/makedefs.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\..\util/makedefs.pdb Console false MachineX86 true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c .\..\util/makedefs.tlb MaxSpeed OnlyExplicitInline .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/makedefs.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\..\util/makedefs.pdb Console false true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c .\..\util/makedefs.tlb Disabled .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/makedefs.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c .\..\util/makedefs.tlb Disabled .;..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/makedefs.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\..\util/makedefs.bsc Running makedefs echo chdir ..\util chdir ..\util chdir echo makedefs.exe -v makedefs.exe -v echo makedefs.exe -o makedefs.exe -o echo makedefs.exe -p makedefs.exe -p echo makedefs.exe -m makedefs.exe -m echo makedefs.exe -z makedefs.exe -z echo chdir ..\dat chdir ..\dat chdir echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e echo chdir ..\build chdir ..\build copy ..\win\share\tilemap.c ..\win\share\tiletxt.c %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2013/nhdefkey.vcxproj0000664000076400007660000002337612536476415020074 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {6813477F-64B6-4B97-B230-438D0D233385} Win32Proj nhdefkey DynamicLibrary true v120 NotSet DynamicLibrary true v120 NotSet DynamicLibrary false v120 true NotSet DynamicLibrary false v120 true NotSet true true false false Level3 Disabled WIN32;WIN32CON;_DEBUG;_WINDOWS;_USRDLL;NHDEFKEY_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)..\include;$(ProjectDir)..\sys\winnt;%(AdditionalIncludeDirectories) false Windows true $(ProjectDir)..\build\nhdefkey.def true true copy $(TargetPath) ..\binary & if exist $(TargetDir)$(TargetName).PDB copy $(TargetDir)$(TargetName).PDB ..\binary Level3 Disabled WIN32;WIN32CON;_DEBUG;_WINDOWS;_USRDLL;NHDEFKEY_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)..\include;$(ProjectDir)..\sys\winnt;%(AdditionalIncludeDirectories) false Windows true $(ProjectDir)..\build\nhdefkey64.def copy $(TargetPath) ..\binary & if exist $(TargetDir)$(TargetName).PDB copy $(TargetDir)$(TargetName).PDB ..\binary Level3 MaxSpeed true true WIN32;WIN32CON;NDEBUG;_WINDOWS;_USRDLL;NHDEFKEY_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)..\include;$(ProjectDir)..\sys\winnt;%(AdditionalIncludeDirectories) false Windows true true true $(ProjectDir)..\build\nhdefkey.def true true copy $(TargetPath) ..\binary & if exist $(TargetDir)$(TargetName).PDB copy $(TargetDir)$(TargetName).PDB ..\binary Level3 MaxSpeed true true WIN32;WIN32CON;NDEBUG;_WINDOWS;_USRDLL;NHDEFKEY_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)..\include;$(ProjectDir)..\sys\winnt;%(AdditionalIncludeDirectories) false Windows true true true $(ProjectDir)..\build\nhdefkey64.def copy $(TargetPath) ..\binary & if exist $(TargetDir)$(TargetName).PDB copy $(TargetDir)$(TargetName).PDB ..\binary nethack-3.6.0/win/win32/vs2013/recover.vcxproj0000664000076400007660000004127212536476415017737 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {2F35F228-6733-4FE5-9B46-B3AA10D4BC2E} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\Debug/recover.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/recover.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\Debug/recover.bsc install exe copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt .\Debug/recover.tlb Disabled ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/recover.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\Debug/recover.bsc install exe copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt .\Release/recover.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/recover.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/recover.pdb Console false MachineX86 true .\Release/recover.bsc copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt .\Release/recover.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/recover.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/recover.pdb Console false true .\Release/recover.bsc copy $(OutDir)recover.exe ..\binary if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) {0303a585-3f83-4bb7-af6b-1e12c8fb54ac} false {ba3dd34c-04b7-40d0-b373-9329aa9e8945} false nethack-3.6.0/win/win32/vs2013/tile2bmp.vcxproj0000664000076400007660000005515112536476415020011 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {642BC75D-ABAF-403E-8224-7C725FD4CB42} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\Debug/tile2bmp.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/tile2bmp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true ProgramDatabase false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\Debug/tile2bmp.bsc .\Debug/tile2bmp.tlb Disabled ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/tile2bmp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true ProgramDatabase false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\Debug/tile2bmp.bsc .\Release/tile2bmp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tile2bmp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tile2bmp.pdb Console false MachineX86 true .\Release/tile2bmp.bsc .\Release/tile2bmp.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tile2bmp.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tile2bmp.pdb Console false true .\Release/tile2bmp.bsc %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) PACKED_FILE;%(PreprocessorDefinitions) PACKED_FILE;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) TILETEXT;%(PreprocessorDefinitions) TILETEXT;%(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) TILETEXT;%(PreprocessorDefinitions) TILETEXT;%(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2013/tilemap.vcxproj0000664000076400007660000004402412536476415017723 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {93F10526-209E-41D7-BBEA-775787876895} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\Debug/tilemap.tlb Disabled ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/tilemap.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\Debug/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build .\Debug/tilemap.tlb Disabled ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) _DEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/tilemap.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x1009 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\Debug/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build .\Release/tilemap.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tilemap.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tilemap.pdb Console false MachineX86 true .\Release/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build .\Release/tilemap.tlb MaxSpeed OnlyExplicitInline ..\include;..\sys\winnt\include;..\win\share;%(AdditionalIncludeDirectories) NDEBUG;WIN32;_CONSOLE;WIN32CON;DLB;MSWIN_GRAPHICS;%(PreprocessorDefinitions) true MultiThreaded true .\Release/tilemap.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x1009 true .\Release/tilemap.pdb Console false true .\Release/tilemap.bsc Generating src\tile.c echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) %(PreprocessorDefinitions) nethack-3.6.0/win/win32/vs2013/tiles.vcxproj0000664000076400007660000002260212536476415017406 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {55946465-FC65-47B3-BB48-742C7694C0D6} MakeFileProj Makefile false v120 Makefile false v120 Makefile false v120 Makefile false v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\Debug\ .\Debug\ nmake /f "tiles.mak" nmake /f "tiles.mak" nmake /f "tiles.mak" /a nmake /f "tiles.mak" /a ..\win\win32\tiles.bmp ..\win\win32\tiles.bmp $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) .\..\util\ .\..\util\ .\Release\ .\Release\ nmake /f "tiles.mak" nmake /f "tiles.mak" nmake /f "tiles.mak" /a nmake /f "tiles.mak" /a ..\win\win32\tiles.bmp ..\win\win32\tiles.bmp $(NMakePreprocessorDefinitions) $(NMakePreprocessorDefinitions) $(NMakeIncludeSearchPath) $(NMakeIncludeSearchPath) $(NMakeForcedIncludes) $(NMakeForcedIncludes) $(NMakeAssemblySearchPath) $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) $(NMakeForcedUsingAssemblies) {642bc75d-abaf-403e-8224-7c725fd4cb42} false nethack-3.6.0/win/win32/vs2013/uudecode.vcxproj0000664000076400007660000004236712541713002020053 0ustar paxedpaxed Debug Win32 Debug x64 Release Win32 Release x64 {63F9B82B-F589-4082-ABE5-D4F0682050AB} Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 Application false MultiByte v120 <_ProjectFileVersion>10.0.30319.1 .\..\util\ .\..\util\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ false false .\Debug\$(ProjectName)\ .\Debug\$(ProjectName)\ true true .\..\util\ .\..\util\ .\Release/uudecode.tlb MaxSpeed OnlyExplicitInline WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true MultiThreaded true .\Release/uudecode.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\Release/uudecode.pdb Console false MachineX86 true .\Release/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary .\Release/uudecode.tlb MaxSpeed OnlyExplicitInline WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true MultiThreaded true .\Release/uudecode.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true false /FS %(AdditionalOptions) NDEBUG;%(PreprocessorDefinitions) 0x0409 true .\Release/uudecode.pdb Console false true .\Release/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary .\Debug/uudecode.tlb Disabled WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug .\Debug/uudecode.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\$(ConfigurationName)\$(ProjectName)\ Console false MachineX86 /SAFESEH:NO %(AdditionalOptions) true .\Debug/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary .\Debug/uudecode.tlb Disabled WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug .\Debug/uudecode.pch .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ .\$(ConfigurationName)\$(ProjectName)\ Level3 true EditAndContinue false /FS %(AdditionalOptions) _DEBUG;%(PreprocessorDefinitions) 0x0409 true true .\$(ConfigurationName)\$(ProjectName)\ Console false /SAFESEH:NO %(AdditionalOptions) true .\Debug/uudecode.bsc echo chdir ..\win\win32 chdir ..\win\win32 echo decoding icon (nhico.uu to NetHack.ico) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu echo decoding mnsel (mnsel.uu to mnsel.bmp) ..\..\util\uudecode.exe mnsel.uu echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) ..\..\util\uudecode.exe mnselcnt.uu echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) ..\..\util\uudecode.exe mnunsel.uu echo decoding petmark (petmark.uu to petmark.bmp) ..\..\util\uudecode.exe petmark.uu echo decoding pilemark (pilemark.uu to pilemark.bmp) ..\..\util\uudecode.exe pilemark.uu echo decoding splash (splash.uu to splash.bmp) ..\..\util\uudecode.exe splash.uu echo decoding tombstone (rip.uu to rip.bmp) ..\..\util\uudecode.exe rip.uu chdir ..\..\binary %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) %(PreprocessorDefinitions) nethack-3.6.0/win/win32/winMS.h0000664000076400007660000001636312541713002015106 0ustar paxedpaxed/* NetHack 3.6 winMS.h $NHDT-Date: 1434804346 2015/06/20 12:45:46 $ $NHDT-Branch: win32-x64-working $:$NHDT-Revision: 1.41 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINMS_H #define WINMS_H #ifdef _MSC_VER #if _MSC_VER >= 1400 /* Visual C 8 warning elimination */ #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE #endif #ifndef _SCL_SECURE_NO_DEPRECATE #define _SCL_SECURE_NO_DEPRECATE #endif #ifndef _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE #endif #endif #endif #define WIN32_LEAN_AND_MEAN #include #include #include #include "hack.h" /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif #define NHW_RIP 32 #define NHW_INVEN 33 #ifndef TILE_X #define TILE_X 16 #endif #define TILE_Y 16 #define TILES_PER_LINE 40 /* tile background color */ #define TILE_BK_COLOR RGB(71, 108, 108) /* minimum/maximum font size (in points - 1/72 inch) */ #define NHFONT_DEFAULT_SIZE 9 #define NHFONT_SIZE_MIN 3 #define NHFONT_SIZE_MAX 20 #define MAX_LOADSTRING 100 #define USE_PILEMARK typedef struct mswin_nhwindow_data { HWND win; int type; int dead; } MSNHWinData, *PMSNHWinData; typedef BOOL(WINAPI *LPTRANSPARENTBLT)(HDC, int, int, int, int, HDC, int, int, int, int, UINT); typedef struct mswin_nhwindow_app { HINSTANCE hApp; HWND hMainWnd; HACCEL hAccelTable; HWND hPopupWnd; /* current popup window */ MSNHWinData windowlist[MAXWINDOWS]; HBITMAP bmpTiles; HBITMAP bmpPetMark; #ifdef USE_PILEMARK HBITMAP bmpPileMark; #endif HBITMAP bmpMapTiles; /* custom tiles bitmap */ HBITMAP bmpRip; HBITMAP bmpSplash; int mapTile_X; /* tile width */ int mapTile_Y; /* tile height */ int mapTilesPerLine; /* number of tile per row in the bitmap */ boolean bNoHScroll; /* disable cliparound for horizontal grid (map) */ boolean bNoVScroll; /* disable cliparound for vertical grid (map) */ int mapDisplayModeSave; /* saved map display mode */ char *saved_text; DWORD saveRegistrySettings; /* Flag if we should save this time */ DWORD regNetHackMode; /* NetHack mode means no Windows keys in some places */ LONG regMainMinX; LONG regMainMinY; LONG regMainMaxX; LONG regMainMaxY; LONG regMainLeft; LONG regMainTop; LONG regMainBottom; LONG regMainRight; DWORD regMainShowState; BOOL bAutoLayout; RECT rtMapWindow; RECT rtMsgWindow; RECT rtStatusWindow; RECT rtMenuWindow; RECT rtTextWindow; RECT rtInvenWindow; BOOL bWindowsLocked; /* TRUE if windows are "locked" - no captions */ BOOL bNoSounds; /* disable sounds */ LPTRANSPARENTBLT lpfnTransparentBlt; /* transparent blt function */ } NHWinApp, *PNHWinApp; #define E extern E PNHWinApp GetNHApp(void); E struct window_procs mswin_procs; #undef E /* Some prototypes */ void mswin_init_nhwindows(int *argc, char **argv); void mswin_player_selection(void); void mswin_askname(void); void mswin_get_nh_event(void); void mswin_exit_nhwindows(const char *); void mswin_suspend_nhwindows(const char *); void mswin_resume_nhwindows(void); winid mswin_create_nhwindow(int type); void mswin_clear_nhwindow(winid wid); void mswin_display_nhwindow(winid wid, BOOLEAN_P block); void mswin_destroy_nhwindow(winid wid); void mswin_curs(winid wid, int x, int y); void mswin_putstr(winid wid, int attr, const char *text); void mswin_putstr_ex(winid wid, int attr, const char *text, int); void mswin_display_file(const char *filename, BOOLEAN_P must_exist); void mswin_start_menu(winid wid); void mswin_add_menu(winid wid, int glyph, const ANY_P *identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel); void mswin_end_menu(winid wid, const char *prompt); int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected); void mswin_update_inventory(void); void mswin_mark_synch(void); void mswin_wait_synch(void); void mswin_cliparound(int x, int y); void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); int mswin_nhgetch(void); int mswin_nh_poskey(int *x, int *y, int *mod); void mswin_nhbell(void); int mswin_doprev_message(void); char mswin_yn_function(const char *question, const char *choices, CHAR_P def); void mswin_getlin(const char *question, char *input); int mswin_get_ext_cmd(void); void mswin_number_pad(int state); void mswin_delay_output(void); void mswin_change_color(void); char *mswin_get_color_string(void); void mswin_start_screen(void); void mswin_end_screen(void); void mswin_outrip(winid wid, int how, time_t when); void mswin_preference_update(const char *pref); char *mswin_getmsghistory(BOOLEAN_P init); void mswin_putmsghistory(const char *msg, BOOLEAN_P); #ifdef STATUS_VIA_WINDOWPORT void mswin_status_init(void); void mswin_status_finish(void); void mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, boolean enable); void mswin_status_update(int idx, genericptr_t ptr, int chg, int percent); #ifdef STATUS_HILITES void mswin_status_threshold(int fldidx, int thresholdtype, anything threshold, int behavior, int under, int over); #endif /* STATUS_HILITES */ #endif /*STATUS_VIA_WINDOWPORT*/ /* helper function */ HWND mswin_hwnd_from_winid(winid wid); winid mswin_winid_from_type(int type); winid mswin_winid_from_handle(HWND hWnd); void mswin_window_mark_dead(winid wid); void bail(const char *mesg); void mswin_popup_display(HWND popup, int *done_indicator); void mswin_popup_destroy(HWND popup); void mswin_read_reg(void); void mswin_destroy_reg(void); void mswin_write_reg(void); void mswin_get_window_placement(int type, LPRECT rt); void mswin_update_window_placement(int type, LPRECT rt); int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type); extern HBRUSH menu_bg_brush; extern HBRUSH menu_fg_brush; extern HBRUSH text_bg_brush; extern HBRUSH text_fg_brush; extern HBRUSH status_bg_brush; extern HBRUSH status_fg_brush; extern HBRUSH message_bg_brush; extern HBRUSH message_fg_brush; extern COLORREF menu_bg_color; extern COLORREF menu_fg_color; extern COLORREF text_bg_color; extern COLORREF text_fg_color; extern COLORREF status_bg_color; extern COLORREF status_fg_color; extern COLORREF message_bg_color; extern COLORREF message_fg_color; #define SYSCLR_TO_BRUSH(x) ((HBRUSH)((x) + 1)) /* unicode stuff */ #define NH_CODEPAGE (SYMHANDLING(H_IBM) ? GetOEMCP() : GetACP()) #ifdef _UNICODE #define NH_W2A(w, a, cb) \ (WideCharToMultiByte(NH_CODEPAGE, 0, (w), -1, (a), (cb), NULL, NULL), (a)) #define NH_A2W(a, w, cb) \ (MultiByteToWideChar(NH_CODEPAGE, 0, (a), -1, (w), (cb)), (w)) #else #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb))) #endif /* map mode macros */ #define IS_MAP_FIT_TO_SCREEN(mode) \ ((mode) == MAP_MODE_ASCII_FIT_TO_SCREEN \ || (mode) == MAP_MODE_TILES_FIT_TO_SCREEN) #define IS_MAP_ASCII(mode) \ ((mode) != MAP_MODE_TILES && (mode) != MAP_MODE_TILES_FIT_TO_SCREEN) #endif /* WINMS_H */ nethack-3.6.0/win/win32/winhack.c0000664000076400007660000003033512631271551015473 0ustar paxedpaxed/* NetHack 3.6 winhack.c $NHDT-Date: 1449488876 2015/12/07 11:47:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ // winhack.cpp : Defines the entry point for the application. // #include #include "winMS.h" #include "hack.h" #include "dlb.h" #include "resource.h" #include "mhmain.h" #include "mhmap.h" /* Borland and MinGW redefine "boolean" in shlwapi.h, so just use the little bit we need */ typedef struct _DLLVERSIONINFO { DWORD cbSize; DWORD dwMajorVersion; // Major version DWORD dwMinorVersion; // Minor version DWORD dwBuildNumber; // Build number DWORD dwPlatformID; // DLLVER_PLATFORM_* } DLLVERSIONINFO; // // The caller should always GetProcAddress("DllGetVersion"), not // implicitly link to it. // typedef HRESULT(CALLBACK *DLLGETVERSIONPROC)(DLLVERSIONINFO *); /* end of shlwapi.h */ /* Minimal common control library version Version _WIN_32IE Platform/IE ======= ========= =========== 4.00 0x0200 Microsoft(r) Windows 95/Windows NT 4.0 4.70 0x0300 Microsoft(r) Internet Explorer 3.x 4.71 0x0400 Microsoft(r) Internet Explorer 4.0 4.72 0x0401 Microsoft(r) Internet Explorer 4.01 ...and probably going on infinitely... */ #define MIN_COMCTLMAJOR 4 #define MIN_COMCTLMINOR 71 #define INSTALL_NOTES "http://www.nethack.org/v340/ports/download-win.html#cc" /*#define COMCTL_URL * "http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp"*/ extern void FDECL(nethack_exit, (int)); static TCHAR *_get_cmd_arg(TCHAR *pCmdLine); static HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); BOOL WINAPI _nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, UINT cTransparent); // Global Variables: NHWinApp _nethack_app; #ifdef __BORLANDC__ #define _stricmp(s1, s2) stricmp(s1, s2) #define _strdup(s1) strdup(s1) #endif // Foward declarations of functions included in this code module: extern boolean FDECL(pcmain, (int, char **)); static void __cdecl mswin_moveloop(void *); #define MAX_CMDLINE_PARAM 255 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX InitCtrls; int argc; char *argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR *p; TCHAR wbuf[BUFSZ]; char buf[BUFSZ]; DWORD major, minor; boolean resuming; /* OSVERSIONINFO osvi; */ UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); sys_early_init(); /* ensure that we don't access violate on a panic() */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; /* init applicatio structure */ _nethack_app.hApp = hInstance; _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR) IDC_NETHACKW); _nethack_app.hMainWnd = NULL; _nethack_app.hPopupWnd = NULL; _nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES)); if (_nethack_app.bmpTiles == NULL) panic("cannot load tiles bitmap"); _nethack_app.bmpPetMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK)); if (_nethack_app.bmpPetMark == NULL) panic("cannot load pet mark bitmap"); #ifdef USE_PILEMARK _nethack_app.bmpPileMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PILEMARK)); if (_nethack_app.bmpPileMark == NULL) panic("cannot load pile mark bitmap"); #endif _nethack_app.bmpRip = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_RIP)); if (_nethack_app.bmpRip == NULL) panic("cannot load rip bitmap"); _nethack_app.bmpSplash = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SPLASH)); if (_nethack_app.bmpSplash == NULL) panic("cannot load splash bitmap"); _nethack_app.bmpMapTiles = _nethack_app.bmpTiles; _nethack_app.mapTile_X = TILE_X; _nethack_app.mapTile_Y = TILE_Y; _nethack_app.mapTilesPerLine = TILES_PER_LINE; _nethack_app.bNoHScroll = FALSE; _nethack_app.bNoVScroll = FALSE; _nethack_app.saved_text = strdup(""); _nethack_app.bAutoLayout = TRUE; _nethack_app.bWindowsLocked = TRUE; _nethack_app.bNoSounds = FALSE; #if 0 /* GdiTransparentBlt does not render spash bitmap for whatever reason */ /* use system-provided TransparentBlt for Win2k+ */ ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); if (osvi.dwMajorVersion >= 5) _nethack_app.lpfnTransparentBlt = GdiTransparentBlt; else #endif _nethack_app.lpfnTransparentBlt = _nhapply_image_transparent; // init controls if (FAILED(GetComCtlVersion(&major, &minor))) { char buf[TBUFSZ]; Sprintf(buf, "Cannot load common control library.\n%s\n%s", "For further information, refer to the installation notes at", INSTALL_NOTES); panic(buf); } if (major < MIN_COMCTLMAJOR || (major == MIN_COMCTLMAJOR && minor < MIN_COMCTLMINOR)) { char buf[TBUFSZ]; Sprintf(buf, "Common control library is outdated.\n%s %d.%d\n%s\n%s", "NetHack requires at least version ", MIN_COMCTLMAJOR, MIN_COMCTLMINOR, "For further information, refer to the installation notes at", INSTALL_NOTES); panic(buf); } ZeroMemory(&InitCtrls, sizeof(InitCtrls)); InitCtrls.dwSize = sizeof(InitCtrls); InitCtrls.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&InitCtrls); /* get command line parameters */ p = _get_cmd_arg(GetCommandLine()); p = _get_cmd_arg(NULL); /* skip first paramter - command name */ for (argc = 1; p && argc < MAX_CMDLINE_PARAM; argc++) { len = _tcslen(p); if (len > 0) { argv[argc] = _strdup(NH_W2A(p, buf, BUFSZ)); } else { argv[argc] = ""; } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); if (argc == 2) { TCHAR *savefile = strdup(argv[1]); TCHAR *plname; for (p = savefile; *p && *p != '-'; p++) ; if (*p) { /* we found a '-' */ plname = p + 1; for (p = plname; *p && *p != '.'; p++) ; if (*p) { if (strcmp(p + 1, "NetHack-saved-game") == 0) { *p = '\0'; argv[1] = "-u"; argv[2] = _strdup(plname); argc = 3; } } } free(savefile); } resuming = pcmain(argc, argv); moveloop(resuming); return 0; } PNHWinApp GetNHApp() { return &_nethack_app; } TCHAR * _get_cmd_arg(TCHAR *pCmdLine) { static TCHAR *pArgs = NULL; TCHAR *pRetArg; BOOL bQuoted; if (!pCmdLine && !pArgs) return NULL; if (!pArgs) pArgs = pCmdLine; /* skip whitespace */ for (pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg)) ; if (!*pRetArg) { pArgs = NULL; return NULL; } /* check for quote */ if (*pRetArg == TEXT('"')) { bQuoted = TRUE; pRetArg = CharNext(pRetArg); pArgs = _tcschr(pRetArg, TEXT('"')); } else { /* skip to whitespace */ for (pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs)) ; } if (pArgs && *pArgs) { TCHAR *p; p = pArgs; pArgs = CharNext(pArgs); *p = (TCHAR) 0; } else { pArgs = NULL; } return pRetArg; } /* Get the version of the Common Control library on this machine. Copied from the Microsoft SDK */ HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) { HINSTANCE hComCtl; HRESULT hr = S_OK; DLLGETVERSIONPROC pDllGetVersion; if (IsBadWritePtr(pdwMajor, sizeof(DWORD)) || IsBadWritePtr(pdwMinor, sizeof(DWORD))) return E_INVALIDARG; // load the DLL hComCtl = LoadLibrary(TEXT("comctl32.dll")); if (!hComCtl) return E_FAIL; /* You must get this function explicitly because earlier versions of the DLL don't implement this function. That makes the lack of implementation of the function a version marker in itself. */ pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hComCtl, TEXT("DllGetVersion")); if (pDllGetVersion) { DLLVERSIONINFO dvi; ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); hr = (*pDllGetVersion)(&dvi); if (SUCCEEDED(hr)) { *pdwMajor = dvi.dwMajorVersion; *pdwMinor = dvi.dwMinorVersion; } else { hr = E_FAIL; } } else { /* If GetProcAddress failed, then the DLL is a version previous to the one shipped with IE 3.x. */ *pdwMajor = 4; *pdwMinor = 0; } FreeLibrary(hComCtl); return hr; } /* apply bitmap pointed by sourceDc transparently over bitmap pointed by hDC */ BOOL WINAPI _nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, UINT cTransparent) { /* Don't use TransparentBlt; According to Microsoft, it contains a memory * leak in Window 95/98. */ HDC hdcMem, hdcBack, hdcObject, hdcSave; COLORREF cColor; HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave; HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld; /* Create some DCs to hold temporary data. */ hdcBack = CreateCompatibleDC(hDC); hdcObject = CreateCompatibleDC(hDC); hdcMem = CreateCompatibleDC(hDC); hdcSave = CreateCompatibleDC(hDC); /* this is bitmap for our pet image */ bmSave = CreateCompatibleBitmap(hDC, width, height); /* Monochrome DC */ bmAndBack = CreateBitmap(width, height, 1, 1, NULL); bmAndObject = CreateBitmap(width, height, 1, 1, NULL); /* resulting bitmap */ bmAndMem = CreateCompatibleBitmap(hDC, width, height); /* Each DC must select a bitmap object to store pixel data. */ bmBackOld = SelectObject(hdcBack, bmAndBack); bmObjectOld = SelectObject(hdcObject, bmAndObject); bmMemOld = SelectObject(hdcMem, bmAndMem); bmSaveOld = SelectObject(hdcSave, bmSave); /* copy source image because it is going to be overwritten */ StretchBlt(hdcSave, 0, 0, width, height, sourceDC, s_x, s_y, s_width, s_height, SRCCOPY); /* Set the background color of the source DC to the color. contained in the parts of the bitmap that should be transparent */ cColor = SetBkColor(hdcSave, cTransparent); /* Create the object mask for the bitmap by performing a BitBlt from the source bitmap to a monochrome bitmap. */ BitBlt(hdcObject, 0, 0, width, height, hdcSave, 0, 0, SRCCOPY); /* Set the background color of the source DC back to the original color. */ SetBkColor(hdcSave, cColor); /* Create the inverse of the object mask. */ BitBlt(hdcBack, 0, 0, width, height, hdcObject, 0, 0, NOTSRCCOPY); /* Copy background to the resulting image */ BitBlt(hdcMem, 0, 0, width, height, hDC, x, y, SRCCOPY); /* Mask out the places where the source image will be placed. */ BitBlt(hdcMem, 0, 0, width, height, hdcObject, 0, 0, SRCAND); /* Mask out the transparent colored pixels on the source image. */ BitBlt(hdcSave, 0, 0, width, height, hdcBack, 0, 0, SRCAND); /* XOR the source image with the beckground. */ BitBlt(hdcMem, 0, 0, width, height, hdcSave, 0, 0, SRCPAINT); /* blt resulting image to the screen */ BitBlt(hDC, x, y, width, height, hdcMem, 0, 0, SRCCOPY); /* cleanup */ DeleteObject(SelectObject(hdcBack, bmBackOld)); DeleteObject(SelectObject(hdcObject, bmObjectOld)); DeleteObject(SelectObject(hdcMem, bmMemOld)); DeleteObject(SelectObject(hdcSave, bmSaveOld)); DeleteDC(hdcMem); DeleteDC(hdcBack); DeleteDC(hdcObject); DeleteDC(hdcSave); return TRUE; } nethack-3.6.0/win/win32/winhack.rc0000664000076400007660000002671512541713002015654 0ustar paxedpaxed//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #if defined(__BORLANDC__) LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US #endif #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS #include "resource.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_NETHACKW ICON DISCARDABLE "NETHACK.ICO" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDC_NETHACKW MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Save and Exit", IDM_SAVE MENUITEM SEPARATOR MENUITEM "&Quit", IDM_EXIT END POPUP "&Map" BEGIN MENUITEM "&0 - Use Tiles", IDM_MAP_TILES MENUITEM "&1 - ASCII (4x6)", IDM_MAP_ASCII4X6 MENUITEM "&2 - ASCII (6x8)", IDM_MAP_ASCII6X8 MENUITEM "&3 - ASCII (8x8)", IDM_MAP_ASCII8X8 MENUITEM "&4 - ASCII (16x8)", IDM_MAP_ASCII16X8 MENUITEM "&5 - ASCII (7x12)", IDM_MAP_ASCII7X12 MENUITEM "&6 - ASCII (8x12)", IDM_MAP_ASCII8X12 MENUITEM "&7 - ASCII (16x12)", IDM_MAP_ASCII16X12 MENUITEM "&8 - ASCII (12x16)", IDM_MAP_ASCII12X16 MENUITEM "&9 - ASCII (10x18)", IDM_MAP_ASCII10X18 MENUITEM SEPARATOR MENUITEM "&Fit To Screen ", IDM_MAP_FIT_TO_SCREEN MENUITEM SEPARATOR MENUITEM "&Copy To Clipboard (ASCII)", IDM_SETTING_SCREEN_TO_CLIPBOARD MENUITEM "&Save to File (ASCII)", IDM_SETTING_SCREEN_TO_FILE END POPUP "Windows &Settings" BEGIN MENUITEM "NetHack Mode", IDM_NHMODE MENUITEM SEPARATOR MENUITEM "&Clear All Settings", IDM_CLEARSETTINGS MENUITEM SEPARATOR MENUITEM "Auto &Arrange Windows", IDM_SETTING_AUTOLAYOUT MENUITEM "&Lock Windows", IDM_SETTING_LOCKWINDOWS END POPUP "&Help" BEGIN MENUITEM "&About ...", IDM_ABOUT MENUITEM "&Long description of the game", IDM_HELP_LONG MENUITEM "List of &commands", IDM_HELP_COMMANDS MENUITEM "&History of NetHack", IDM_HELP_HISTORY MENUITEM "&Info on a character", IDM_HELP_INFO_CHAR MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY MENUITEM "List of game &options", IDM_HELP_OPTIONS MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG MENUITEM "List of e&xtended commands", IDM_HELP_EXTCMD MENUITEM "The &NetHack license", IDM_HELP_LICENSE MENUITEM "NetHack for &Windows help", IDM_HELP_PORTHELP END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_NETHACKW ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75 STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN LTEXT "NetHack",IDC_ABOUT_VERSION,10,10,170,15,SS_NOPREFIX LTEXT "Copyright",IDC_ABOUT_COPYRIGHT,10,30,210,40 DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP END IDD_NHTEXT DIALOGEX 0, 0, 172, 178 STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME EXSTYLE WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT FONT 8, "MS Sans Serif", 0, 0 BEGIN EDITTEXT IDC_TEXT_CONTROL,0,0,172,160,ES_MULTILINE | ES_OEMCONVERT | ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP DEFPUSHBUTTON "OK",IDOK,54,163,50,14,BS_FLAT | NOT WS_TABSTOP END IDD_MENU DIALOGEX 0, 0, 187, 153 STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME EXSTYLE WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT FONT 8, "MS Sans Serif", 0, 0 BEGIN LISTBOX IDC_MENU_LIST,10,10,170,55,LBS_SORT EDITTEXT IDC_MENU_TEXT,10,70,170,60,ES_MULTILINE | ES_OEMCONVERT | ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP DEFPUSHBUTTON "OK",IDOK,7,132,50,14,BS_FLAT | NOT WS_TABSTOP PUSHBUTTON "Cancel",IDCANCEL,130,132,50,14,BS_FLAT | NOT WS_TABSTOP END IDD_GETLIN DIALOG DISCARDABLE 0, 0, 131, 29 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,0,15,65,14 PUSHBUTTON "Cancel",IDCANCEL,65,15,65,14 EDITTEXT IDC_GETLIN_EDIT,0,0,130,13,ES_AUTOHSCROLL END IDD_EXTCMD DIALOG DISCARDABLE 0, 0, 137, 117 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Extended Commands" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,80,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,80,24,50,14 LISTBOX IDC_EXTCMD_LIST,7,7,65,103,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END IDD_PLAYER_SELECTOR DIALOG DISCARDABLE 0, 0, 152, 169 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "Play",IDOK,7,148,66,14 PUSHBUTTON "Quit",IDCANCEL,79,148,66,14 LTEXT "Name:",IDC_STATIC,7,8,25,10 EDITTEXT IDC_PLSEL_NAME,40,7,105,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP GROUPBOX "Role",IDC_STATIC,7,21,138,30 CONTROL "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,34,40,10 COMBOBOX IDC_PLSEL_ROLE_LIST,63,33,75,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Race",IDC_STATIC,7,51,138,30 CONTROL "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,63,40,10 COMBOBOX IDC_PLSEL_RACE_LIST,63,62,75,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Gender",IDC_STATIC,7,81,138,30 CONTROL "Random",IDC_PLSEL_GENDER_RANDOM,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,14,93,40,10 COMBOBOX IDC_PLSEL_GENDER_LIST,63,92,75,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Alignment",IDC_STATIC,7,111,138,30 CONTROL "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,123,40,10 COMBOBOX IDC_PLSEL_ALIGN_LIST,63,122,75,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_NHRIP DIALOGEX 0, 0, 281, 209 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Here lies..." FONT 8, "MS Sans Serif", 0, 0 BEGIN DEFPUSHBUTTON "OK",IDOK,82,188,50,14 END IDD_SPLASH DIALOG DISCARDABLE 0, 0, 281, 257 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Welcome to NetHack" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,224,236,50,14 EDITTEXT IDC_EXTRAINFO,7,176,267,52,ES_MULTILINE | ES_READONLY | WS_VSCROLL END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE DISCARDABLE BEGIN "#if defined(__BORLANDC__)\r\n" "LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US\r\n" "#endif\r\n" "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""resource.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // IDB_TILES BITMAP DISCARDABLE "tiles.bmp" IDB_MENU_SEL BITMAP DISCARDABLE "mnsel.bmp" IDB_MENU_UNSEL BITMAP DISCARDABLE "mnunsel.bmp" IDB_PETMARK BITMAP DISCARDABLE "petmark.bmp" IDB_PILEMARK BITMAP DISCARDABLE "pilemark.bmp" IDB_MENU_SEL_COUNT BITMAP DISCARDABLE "mnselcnt.bmp" IDB_RIP BITMAP DISCARDABLE "rip.bmp" IDB_SPLASH BITMAP DISCARDABLE "splash.bmp" ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_NHTEXT, DIALOG BEGIN BOTTOMMARGIN, 177 END IDD_MENU, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 180 TOPMARGIN, 7 BOTTOMMARGIN, 146 END IDD_GETLIN, DIALOG BEGIN BOTTOMMARGIN, 22 END IDD_EXTCMD, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 130 TOPMARGIN, 7 BOTTOMMARGIN, 110 END IDD_PLAYER_SELECTOR, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 145 TOPMARGIN, 7 BOTTOMMARGIN, 162 END IDD_NHRIP, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 274 TOPMARGIN, 7 BOTTOMMARGIN, 202 END IDD_SPLASH, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 274 BOTTOMMARGIN, 250 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,5,0,0 PRODUCTVERSION 3,5,0,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - Graphical Interface\0" VALUE "FileVersion", "3.5.0\0" VALUE "InternalName", "NetHackW\0" VALUE "LegalCopyright", "Copyright (C) 1985 - 2006. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" VALUE "OriginalFilename", "NetHackW.exe\0" VALUE "PrivateBuild", "140606\0" VALUE "ProductName", "NetHack\0" VALUE "ProductVersion", "3.5.0\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "NetHack for Windows - Graphical Interface" IDC_NETHACKW "NETHACKW" IDS_APP_TITLE_SHORT "NetHack for Windows" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED